--- linux-2.6.27.orig/MAINTAINERS +++ linux-2.6.27/MAINTAINERS @@ -360,7 +360,7 @@ ALI1563 I2C DRIVER P: Rudolf Marek M: r.marek@assembler.cz -L: i2c@lm-sensors.org +L: linux-i2c@vger.kernel.org S: Maintained ALPHA PORT @@ -1681,7 +1681,7 @@ P: Jochen Friedrich M: jochen@scram.de L: linuxppc-dev@ozlabs.org -L: i2c@lm-sensors.org +L: linux-i2c@vger.kernel.org S: Maintained FREESCALE SOC FS_ENET DRIVER @@ -1982,7 +1982,7 @@ I2C/SMBUS STUB DRIVER P: Mark M. Hoffman M: mhoffman@lightlink.com -L: i2c@lm-sensors.org +L: linux-i2c@vger.kernel.org S: Maintained I2C SUBSYSTEM @@ -1990,14 +1990,14 @@ M: khali@linux-fr.org P: Ben Dooks (embedded platforms) M: ben-linux@fluff.org -L: i2c@lm-sensors.org +L: linux-i2c@vger.kernel.org T: quilt http://khali.linux-fr.org/devel/linux-2.6/jdelvare-i2c/ S: Maintained I2C-TINY-USB DRIVER P: Till Harbaum M: till@harbaum.org -L: i2c@lm-sensors.org +L: linux-i2c@vger.kernel.org T: http://www.harbaum.org/till/i2c_tiny_usb S: Maintained @@ -3070,7 +3070,7 @@ OPENCORES I2C BUS DRIVER P: Peter Korsgaard M: jacmet@sunsite.dk -L: i2c@lm-sensors.org +L: linux-i2c@vger.kernel.org S: Maintained ORACLE CLUSTER FILESYSTEM 2 (OCFS2) @@ -3144,7 +3144,7 @@ PA SEMI SMBUS DRIVER P: Olof Johansson M: olof@lixom.net -L: i2c@lm-sensors.org +L: linux-i2c@vger.kernel.org S: Maintained PARALLEL PORT SUPPORT @@ -3280,7 +3280,7 @@ PNXxxxx I2C DRIVER P: Vitaly Wool M: vitalywool@gmail.com -L: i2c@lm-sensors.org +L: linux-i2c@vger.kernel.org S: Maintained PPP PROTOCOL DRIVERS AND COMPRESSORS @@ -3725,7 +3725,7 @@ SIS 96X I2C/SMBUS DRIVER P: Mark M. Hoffman M: mhoffman@lightlink.com -L: i2c@lm-sensors.org +L: linux-i2c@vger.kernel.org S: Maintained SIS FRAMEBUFFER DRIVER @@ -4445,7 +4445,7 @@ VIAPRO SMBUS DRIVER P: Jean Delvare M: khali@linux-fr.org -L: i2c@lm-sensors.org +L: linux-i2c@vger.kernel.org S: Maintained VIA VELOCITY NETWORK DRIVER --- linux-2.6.27.orig/Makefile +++ linux-2.6.27/Makefile @@ -1,8 +1,8 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 27 -EXTRAVERSION = -NAME = Rotary Wombat +EXTRAVERSION = .18 +NAME = Trembling Tortoise # *DOCUMENTATION* # To see a list of typical targets execute "make help" @@ -328,19 +328,30 @@ CFLAGS_KERNEL = AFLAGS_KERNEL = +# Prefer linux-backports-modules +ifneq ($(KBUILD_SRC),) +ifneq ($(shell if test -e $(KBUILD_OUTPUT)/ubuntu-build; then echo yes; fi),yes) +UBUNTUINCLUDE := -I/usr/src/linux-headers-lbm-$(KERNELRELEASE) +endif +endif # Use LINUXINCLUDE when you must reference the include/ directory. # Needed to be compatible with the O= option -LINUXINCLUDE := -Iinclude \ +LINUXINCLUDE := $(UBUNTUINCLUDE) -Iinclude \ $(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) \ -I$(srctree)/arch/$(hdr-arch)/include \ -include include/linux/autoconf.h +# UBUNTU: Include our third party driver stuff too +LINUXINCLUDE += -Iubuntu/include \ + $(if $(KBUILD_SRC),-I$(srctree)/ubuntu/include) + KBUILD_CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE) KBUILD_CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ -fno-strict-aliasing -fno-common \ - -Werror-implicit-function-declaration + -Werror-implicit-function-declaration \ + -fno-delete-null-pointer-checks KBUILD_AFLAGS := -D__ASSEMBLY__ # Read KERNELRELEASE from include/config/kernel.release (if it exists) @@ -458,7 +469,7 @@ # Objects we will link into vmlinux / subdirs we need to visit init-y := init/ -drivers-y := drivers/ sound/ firmware/ +drivers-y := drivers/ sound/ firmware/ ubuntu/ net-y := net/ libs-y := lib/ core-y := usr/ @@ -555,6 +566,9 @@ # disable pointer signed / unsigned warnings in gcc 4.0 KBUILD_CFLAGS += $(call cc-option,-Wno-pointer-sign,) +# disable invalid "can't wrap" optimzations for signed / pointers +KBUILD_CFLAGS += $(call cc-option,-fwrapv) + # Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments # But warn user when we do so warn-assign = \ --- linux-2.6.27.orig/crypto/authenc.c +++ linux-2.6.27/crypto/authenc.c @@ -157,16 +157,19 @@ dstp = sg_page(dst); vdst = PageHighMem(dstp) ? NULL : page_address(dstp) + dst->offset; - sg_init_table(cipher, 2); - sg_set_buf(cipher, iv, ivsize); - authenc_chain(cipher, dst, vdst == iv + ivsize); + if (ivsize) { + sg_init_table(cipher, 2); + sg_set_buf(cipher, iv, ivsize); + authenc_chain(cipher, dst, vdst == iv + ivsize); + dst = cipher; + } cryptlen = req->cryptlen + ivsize; - hash = crypto_authenc_hash(req, flags, cipher, cryptlen); + hash = crypto_authenc_hash(req, flags, dst, cryptlen); if (IS_ERR(hash)) return PTR_ERR(hash); - scatterwalk_map_and_copy(hash, cipher, cryptlen, + scatterwalk_map_and_copy(hash, dst, cryptlen, crypto_aead_authsize(authenc), 1); return 0; } @@ -284,11 +287,14 @@ srcp = sg_page(src); vsrc = PageHighMem(srcp) ? NULL : page_address(srcp) + src->offset; - sg_init_table(cipher, 2); - sg_set_buf(cipher, iv, ivsize); - authenc_chain(cipher, src, vsrc == iv + ivsize); + if (ivsize) { + sg_init_table(cipher, 2); + sg_set_buf(cipher, iv, ivsize); + authenc_chain(cipher, src, vsrc == iv + ivsize); + src = cipher; + } - return crypto_authenc_verify(req, cipher, cryptlen + ivsize); + return crypto_authenc_verify(req, src, cryptlen + ivsize); } static int crypto_authenc_decrypt(struct aead_request *req) --- linux-2.6.27.orig/crypto/ccm.c +++ linux-2.6.27/crypto/ccm.c @@ -266,6 +266,8 @@ if (assoclen) { pctx->ilen = format_adata(idata, assoclen); get_data_to_compute(cipher, pctx, req->assoc, req->assoclen); + } else { + pctx->ilen = 0; } /* compute plaintext into mac */ --- linux-2.6.27.orig/crypto/async_tx/async_xor.c +++ linux-2.6.27/crypto/async_tx/async_xor.c @@ -53,10 +53,17 @@ int xor_src_cnt; dma_addr_t dma_dest; - dma_dest = dma_map_page(dma->dev, dest, offset, len, DMA_FROM_DEVICE); - for (i = 0; i < src_cnt; i++) + /* map the dest bidrectional in case it is re-used as a source */ + dma_dest = dma_map_page(dma->dev, dest, offset, len, DMA_BIDIRECTIONAL); + for (i = 0; i < src_cnt; i++) { + /* only map the dest once */ + if (unlikely(src_list[i] == dest)) { + dma_src[i] = dma_dest; + continue; + } dma_src[i] = dma_map_page(dma->dev, src_list[i], offset, len, DMA_TO_DEVICE); + } while (src_cnt) { async_flags = flags; --- linux-2.6.27.orig/Documentation/kernel-parameters.txt +++ linux-2.6.27/Documentation/kernel-parameters.txt @@ -179,6 +179,9 @@ acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT + acpi_no_initrd_override [KNL,ACPI] + Disable loading custom ACPI tables from the initramfs + acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS Format: To spoof as Windows 98: ="Microsoft Windows" @@ -197,6 +200,18 @@ that require a timer override, but don't have HPET + acpi_backlight= [HW,ACPI] + acpi_backlight=vendor + acpi_backlight=video + If set to vendor, prefer vendor specific driver + (e.g. thinkpad_acpi, sony_acpi, etc.) instead + of the ACPI video.ko driver. + + acpi_display_output= [HW,ACPI] + acpi_display_output=vendor + acpi_display_output=video + See above. + acpi.debug_layer= [HW,ACPI] Format: Each bit of the indicates an ACPI debug layer, @@ -232,6 +247,14 @@ Warning: Many of these options can produce a lot of output and make your system unusable. Be very careful. + acpi.power_nocheck= [HW,ACPI] + Format: 1/0 enable/disable the check of power state. + On some bogus BIOS the _PSC object/_STA object of + power resource can't return the correct device power + state. In such case it is unneccessary to check its + power state again in power transition. + 1 : disable the power state check + acpi_pm_good [X86-32,X86-64] Override the pmtimer bug detection: force the kernel to assume that this machine's pmtimer latches its value @@ -283,7 +306,7 @@ Possible values are: isolate - enable device isolation (each device, as far as possible, will get its own protection - domain) + domain) [default] amd_iommu_size= [HW,X86-64] Define the size of the aperture for the AMD IOMMU driver. Possible values are: @@ -2174,6 +2197,13 @@ Format: ,,,,,,,, + tsc= Disable clocksource-must-verify flag for TSC. + Format: + [x86] reliable: mark tsc clocksource as reliable, this + disables clocksource verification at runtime. + Used to enable high-resolution timer mode on older + hardware, and in virtualized environment. + turbografx.map[2|3]= [HW,JOY] TurboGraFX parallel port interface Format: --- linux-2.6.27.orig/Documentation/cciss.txt +++ linux-2.6.27/Documentation/cciss.txt @@ -26,6 +26,8 @@ * SA P410i * SA P411 * SA P812 + * SA P712m + * SA P711m Detecting drive failures: ------------------------- --- linux-2.6.27.orig/Documentation/filesystems/proc.txt +++ linux-2.6.27/Documentation/filesystems/proc.txt @@ -44,6 +44,7 @@ 2.14 /proc//io - Display the IO accounting fields 2.15 /proc//coredump_filter - Core dump filtering settings 2.16 /proc//mountinfo - Information about mounts + 2.17 /proc/sys/fs/epoll - Configuration options for the epoll interface ------------------------------------------------------------------------------ Preface @@ -2471,4 +2472,30 @@ Documentation/filesystems/sharedsubtree.txt +2.17 /proc/sys/fs/epoll - Configuration options for the epoll interface +-------------------------------------------------------- + +This directory contains configuration options for the epoll(7) interface. + +max_user_instances +------------------ + +This is the maximum number of epoll file descriptors that a single user can +have open at a given time. The default value is 128, and should be enough +for normal users. + +max_user_watches +---------------- + +Every epoll file descriptor can store a number of files to be monitored +for event readiness. Each one of these monitored files constitutes a "watch". +This configuration option sets the maximum number of "watches" that are +allowed for each user. +Each "watch" costs roughly 90 bytes on a 32bit kernel, and roughly 160 bytes +on a 64bit one. +The current default value for max_user_watches is the 1/32 of the available +low memory, divided for the "watch" cost in bytes. + + ------------------------------------------------------------------------------ + --- linux-2.6.27.orig/Documentation/filesystems/sysfs-pci.txt +++ linux-2.6.27/Documentation/filesystems/sysfs-pci.txt @@ -9,6 +9,7 @@ | |-- class | |-- config | |-- device + | |-- enable | |-- irq | |-- local_cpus | |-- resource @@ -32,6 +33,7 @@ class PCI class (ascii, ro) config PCI config space (binary, rw) device PCI device (ascii, ro) + enable Whether the device is enabled (ascii, rw) irq IRQ number (ascii, ro) local_cpus nearby CPU mask (cpumask, ro) resource PCI resource host addresses (ascii, ro) @@ -57,10 +59,19 @@ don't support mmapping of certain resources, so be sure to check the return value from any attempted mmap. +The 'enable' file provides a counter that indicates how many times the device +has been enabled. If the 'enable' file currently returns '4', and a '1' is +echoed into it, it will then return '5'. Echoing a '0' into it will decrease +the count. Even when it returns to 0, though, some of the initialisation +may not be reversed. + The 'rom' file is special in that it provides read-only access to the device's ROM file, if available. It's disabled by default, however, so applications should write the string "1" to the file to enable it before attempting a read -call, and disable it following the access by writing "0" to the file. +call, and disable it following the access by writing "0" to the file. Note +that the device must be enabled for a rom read to return data succesfully. +In the event a driver is not bound to the device, it can be enabled using the +'enable' file, documented above. Accessing legacy resources through sysfs ---------------------------------------- --- linux-2.6.27.orig/Documentation/acpi/initramfs-add-dsdt.sh +++ linux-2.6.27/Documentation/acpi/initramfs-add-dsdt.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# Adds a DSDT file to the initrd (if it's an initramfs) +# first argument is the name of archive +# second argument is the name of the file to add +# The file will be copied as /DSDT.aml + +# 20060126: fix "Premature end of file" with some old cpio (Roland Robic) +# 20060205: this time it should really work + +# check the arguments +if [ $# -ne 2 ]; then + program_name=$(basename $0) + echo "\ +$program_name: too few arguments +Usage: $program_name initrd-name.img DSDT-to-add.aml +Adds a DSDT file to an initrd (in initramfs format) + + initrd-name.img: filename of the initrd in initramfs format + DSDT-to-add.aml: filename of the DSDT file to add + " 1>&2 + exit 1 +fi + +# we should check it's an initramfs + +tempcpio=$(mktemp -d) +# cleanup on exit, hangup, interrupt, quit, termination +trap 'rm -rf $tempcpio' 0 1 2 3 15 + +# extract the archive +gunzip -c "$1" > "$tempcpio"/initramfs.cpio || exit 1 + +# copy the DSDT file at the root of the directory so that we can call it "/DSDT.aml" +cp -f "$2" "$tempcpio"/DSDT.aml + +# add the file +cd "$tempcpio" +(echo DSDT.aml | cpio --quiet -H newc -o -A -O "$tempcpio"/initramfs.cpio) || exit 1 +cd "$OLDPWD" + +# re-compress the archive +gzip -c "$tempcpio"/initramfs.cpio > "$1" + --- linux-2.6.27.orig/Documentation/acpi/dsdt-override.txt +++ linux-2.6.27/Documentation/acpi/dsdt-override.txt @@ -1,7 +1,15 @@ -Linux supports a method of overriding the BIOS DSDT: +Linux supports two methods of overriding the BIOS DSDT: CONFIG_ACPI_CUSTOM_DSDT builds the image into the kernel. -When to use this method is described in detail on the +CONFIG_ACPI_CUSTOM_DSDT_INITRD adds the image to the initrd. + +When to use these methods is described in detail on the Linux/ACPI home page: http://www.lesswatts.org/projects/acpi/overridingDSDT.php + +Note that if both options are used, the DSDT supplied +by the INITRD method takes precedence. + +Documentation/initramfs-add-dsdt.sh is provided for convenience +for use with the CONFIG_ACPI_CUSTOM_DSDT_INITRD method. --- linux-2.6.27.orig/Documentation/sound/alsa/ALSA-Configuration.txt +++ linux-2.6.27/Documentation/sound/alsa/ALSA-Configuration.txt @@ -960,9 +960,10 @@ 6stack 6-jack, separate surrounds (default) 3stack 3-stack, shared surrounds laptop 2-channel only (FSC V2060, Samsung M50) - laptop-eapd 2-channel with EAPD (Samsung R65, ASUS A6J) + laptop-eapd 2-channel with EAPD (ASUS A6J) laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100) ultra 2-channel with EAPD (Samsung Ultra tablet PC) + samsung 2-channel with EAPD (Samsung R65) AD1988/AD1988B/AD1989A/AD1989B 6stack 6-jack @@ -1056,7 +1057,9 @@ STAC92HD73* ref Reference board - dell-m6 Dell desktops + dell-m6-amic Dell desktops/laptops with analog mics + dell-m6-dmic Dell desktops/laptops with digital mics + dell-m6 Dell desktops/laptops with both type of mics STAC9872 vaio Setup for VAIO FE550G/SZ110 --- linux-2.6.27.orig/Documentation/networking/README.ipw2200 +++ linux-2.6.27/Documentation/networking/README.ipw2200 @@ -147,7 +147,7 @@ driver. If disabled, the driver will not attempt to scan for and associate to a network until it has been configured with one or more properties for the target network, for example configuring - the network SSID. Default is 1 (auto-associate) + the network SSID. Default is 0 (do not auto-associate) Example: % modprobe ipw2200 associate=0 --- linux-2.6.27.orig/Documentation/i2c/busses/i2c-sis96x +++ linux-2.6.27/Documentation/i2c/busses/i2c-sis96x @@ -42,7 +42,7 @@ chipsets as well: 635, and 635T. If anyone owns a board with those chips AND is willing to risk crashing & burning an otherwise well-behaved kernel in the name of progress... please contact me at or -via the project's mailing list: . Please send bug +via the linux-i2c mailing list: . Please send bug reports and/or success stories as well. --- linux-2.6.27.orig/Documentation/video4linux/CARDLIST.au0828 +++ linux-2.6.27/Documentation/video4linux/CARDLIST.au0828 @@ -1,5 +1,5 @@ 0 -> Unknown board (au0828) - 1 -> Hauppauge HVR950Q (au0828) [2040:7200,2040:7210,2040:7217,2040:721b,2040:721f,2040:7280,0fd9:0008] + 1 -> Hauppauge HVR950Q (au0828) [2040:7200,2040:7210,2040:7217,2040:721b,2040:721e,2040:721f,2040:7280,0fd9:0008] 2 -> Hauppauge HVR850 (au0828) [2040:7240] 3 -> DViCO FusionHDTV USB (au0828) [0fe9:d620] 4 -> Hauppauge HVR950Q rev xxF8 (au0828) [2040:7201,2040:7211,2040:7281] --- linux-2.6.27.orig/arch/Kconfig +++ linux-2.6.27/arch/Kconfig @@ -46,6 +46,9 @@ See Documentation/unaligned-memory-access.txt for more information on the topic of unaligned memory accesses. +config HAVE_SYSCALL_WRAPPERS + bool + config KRETPROBES def_bool y depends on KPROBES && HAVE_KRETPROBES --- linux-2.6.27.orig/arch/alpha/kernel/irq_srm.c +++ linux-2.6.27/arch/alpha/kernel/irq_srm.c @@ -63,6 +63,8 @@ { long i; + if (NR_IRQS <= 16) + return; for (i = 16; i < max; ++i) { if (i < 64 && ((ignore_mask >> i) & 1)) continue; --- linux-2.6.27.orig/arch/alpha/kernel/entry.S +++ linux-2.6.27/arch/alpha/kernel/entry.S @@ -894,9 +894,9 @@ .end sys_getxpid .align 4 - .globl sys_pipe - .ent sys_pipe -sys_pipe: + .globl sys_alpha_pipe + .ent sys_alpha_pipe +sys_alpha_pipe: lda $sp, -16($sp) stq $26, 0($sp) .prologue 0 @@ -914,7 +914,7 @@ stq $1, 80+16($sp) 1: lda $sp, 16($sp) ret -.end sys_pipe +.end sys_alpha_pipe .align 4 .globl sys_execve --- linux-2.6.27.orig/arch/alpha/kernel/systbls.S +++ linux-2.6.27/arch/alpha/kernel/systbls.S @@ -52,7 +52,7 @@ .quad sys_setpgid .quad alpha_ni_syscall /* 40 */ .quad sys_dup - .quad sys_pipe + .quad sys_alpha_pipe .quad osf_set_program_attributes .quad alpha_ni_syscall .quad sys_open /* 45 */ --- linux-2.6.27.orig/arch/mips/kernel/scall32-o32.S +++ linux-2.6.27/arch/mips/kernel/scall32-o32.S @@ -401,7 +401,7 @@ sys sys_uselib 1 sys sys_swapon 2 sys sys_reboot 3 - sys old_readdir 3 + sys sys_old_readdir 3 sys old_mmap 6 /* 4090 */ sys sys_munmap 2 sys sys_truncate 2 --- linux-2.6.27.orig/arch/sh/kernel/syscalls_64.S +++ linux-2.6.27/arch/sh/kernel/syscalls_64.S @@ -109,7 +109,7 @@ .long sys_uselib .long sys_swapon .long sys_reboot - .long old_readdir + .long sys_old_readdir .long old_mmap /* 90 */ .long sys_munmap .long sys_truncate --- linux-2.6.27.orig/arch/sh/kernel/sys_sh32.c +++ linux-2.6.27/arch/sh/kernel/sys_sh32.c @@ -21,7 +21,7 @@ * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way Unix traditionally does this, though. */ -asmlinkage int sys_pipe(unsigned long r4, unsigned long r5, +asmlinkage int sys_sh_pipe(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, struct pt_regs __regs) { --- linux-2.6.27.orig/arch/sh/kernel/syscalls_32.S +++ linux-2.6.27/arch/sh/kernel/syscalls_32.S @@ -58,7 +58,7 @@ .long sys_mkdir .long sys_rmdir /* 40 */ .long sys_dup - .long sys_pipe + .long sys_sh_pipe .long sys_times .long sys_ni_syscall /* old prof syscall holder */ .long sys_brk /* 45 */ @@ -105,7 +105,7 @@ .long sys_uselib .long sys_swapon .long sys_reboot - .long old_readdir + .long sys_old_readdir .long old_mmap /* 90 */ .long sys_munmap .long sys_truncate --- linux-2.6.27.orig/arch/cris/arch-v10/kernel/entry.S +++ linux-2.6.27/arch/cris/arch-v10/kernel/entry.S @@ -691,7 +691,7 @@ .long sys_uselib .long sys_swapon .long sys_reboot - .long old_readdir + .long sys_old_readdir .long old_mmap /* 90 */ .long sys_munmap .long sys_truncate --- linux-2.6.27.orig/arch/cris/arch-v32/kernel/entry.S +++ linux-2.6.27/arch/cris/arch-v32/kernel/entry.S @@ -614,7 +614,7 @@ .long sys_uselib .long sys_swapon .long sys_reboot - .long old_readdir + .long sys_old_readdir .long old_mmap /* 90 */ .long sys_munmap .long sys_truncate --- linux-2.6.27.orig/arch/um/drivers/mconsole_kern.c +++ linux-2.6.27/arch/um/drivers/mconsole_kern.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -785,7 +787,7 @@ /* long to avoid size mismatch warnings from gcc */ long sock; int err; - char file[256]; + char file[UNIX_PATH_MAX]; if (umid_file_name("mconsole", file, sizeof(file))) return -1; --- linux-2.6.27.orig/arch/arm/mm/cache-xsc3l2.c +++ linux-2.6.27/arch/arm/mm/cache-xsc3l2.c @@ -97,7 +97,7 @@ /* * Clean and invalidate partial last cache line. */ - if (end & (CACHE_LINE_SIZE - 1)) { + if (start < end && (end & (CACHE_LINE_SIZE - 1))) { xsc3_l2_clean_pa(end & ~(CACHE_LINE_SIZE - 1)); xsc3_l2_inv_pa(end & ~(CACHE_LINE_SIZE - 1)); end &= ~(CACHE_LINE_SIZE - 1); @@ -106,7 +106,7 @@ /* * Invalidate all full cache lines between 'start' and 'end'. */ - while (start != end) { + while (start < end) { xsc3_l2_inv_pa(start); start += CACHE_LINE_SIZE; } --- linux-2.6.27.orig/arch/arm/mm/cache-feroceon-l2.c +++ linux-2.6.27/arch/arm/mm/cache-feroceon-l2.c @@ -148,7 +148,7 @@ /* * Clean and invalidate partial last cache line. */ - if (end & (CACHE_LINE_SIZE - 1)) { + if (start < end && end & (CACHE_LINE_SIZE - 1)) { l2_clean_inv_pa(end & ~(CACHE_LINE_SIZE - 1)); end &= ~(CACHE_LINE_SIZE - 1); } @@ -156,7 +156,7 @@ /* * Invalidate all full cache lines between 'start' and 'end'. */ - while (start != end) { + while (start < end) { unsigned long range_end = calc_range_end(start, end); l2_inv_pa_range(start, range_end - CACHE_LINE_SIZE); start = range_end; --- linux-2.6.27.orig/arch/arm/kernel/calls.S +++ linux-2.6.27/arch/arm/kernel/calls.S @@ -98,7 +98,7 @@ CALL(sys_uselib) CALL(sys_swapon) CALL(sys_reboot) - CALL(OBSOLETE(old_readdir)) /* used by libc4 */ + CALL(OBSOLETE(sys_old_readdir)) /* used by libc4 */ /* 90 */ CALL(OBSOLETE(old_mmap)) /* used by libc4 */ CALL(sys_munmap) CALL(sys_truncate) --- linux-2.6.27.orig/arch/arm/mach-pxa/spitz.c +++ linux-2.6.27/arch/arm/mach-pxa/spitz.c @@ -548,7 +548,7 @@ static void __init common_init(void) { - init_gpio_reset(SPITZ_GPIO_ON_RESET); + init_gpio_reset(SPITZ_GPIO_ON_RESET, 1); pm_power_off = spitz_poweroff; arm_pm_restart = spitz_restart; --- linux-2.6.27.orig/arch/arm/mach-pxa/tosa.c +++ linux-2.6.27/arch/arm/mach-pxa/tosa.c @@ -781,7 +781,7 @@ gpio_set_wake(MFP_PIN_GPIO1, 1); /* We can't pass to gpio-keys since it will drop the Reset altfunc */ - init_gpio_reset(TOSA_GPIO_ON_RESET); + init_gpio_reset(TOSA_GPIO_ON_RESET, 0); pm_power_off = tosa_poweroff; arm_pm_restart = tosa_restart; --- linux-2.6.27.orig/arch/arm/mach-pxa/reset.c +++ linux-2.6.27/arch/arm/mach-pxa/reset.c @@ -20,7 +20,7 @@ static int reset_gpio = -1; -int init_gpio_reset(int gpio) +int init_gpio_reset(int gpio, int output) { int rc; @@ -30,9 +30,12 @@ goto out; } - rc = gpio_direction_input(gpio); + if (output) + rc = gpio_direction_output(gpio, 0); + else + rc = gpio_direction_input(gpio); if (rc) { - printk(KERN_ERR "Can't configure reset_gpio for input\n"); + printk(KERN_ERR "Can't configure reset_gpio\n"); gpio_free(gpio); goto out; } --- linux-2.6.27.orig/arch/arm/mach-pxa/include/mach/reset.h +++ linux-2.6.27/arch/arm/mach-pxa/include/mach/reset.h @@ -10,9 +10,12 @@ extern unsigned int reset_status; extern void clear_reset_status(unsigned int mask); -/* - * register GPIO as reset generator +/** + * init_gpio_reset() - register GPIO as reset generator + * + * @gpio - gpio nr + * @output - set gpio as out/low instead of input during normal work */ -extern int init_gpio_reset(int gpio); +extern int init_gpio_reset(int gpio, int output); #endif /* __ASM_ARCH_RESET_H */ --- linux-2.6.27.orig/arch/sparc/include/asm/compat.h +++ linux-2.6.27/arch/sparc/include/asm/compat.h @@ -240,4 +240,9 @@ unsigned int __unused2; }; +static inline int is_compat_task(void) +{ + return test_thread_flag(TIF_32BIT); +} + #endif /* _ASM_SPARC64_COMPAT_H */ --- linux-2.6.27.orig/arch/sparc/include/asm/seccomp.h +++ linux-2.6.27/arch/sparc/include/asm/seccomp.h @@ -1,11 +1,5 @@ #ifndef _ASM_SECCOMP_H -#include /* already defines TIF_32BIT */ - -#ifndef TIF_32BIT -#error "unexpected TIF_32BIT on sparc64" -#endif - #include #define __NR_seccomp_read __NR_read --- linux-2.6.27.orig/arch/sparc/include/asm/uaccess_64.h +++ linux-2.6.27/arch/sparc/include/asm/uaccess_64.h @@ -265,8 +265,8 @@ #define strlen_user __strlen_user #define strnlen_user __strnlen_user -#define __copy_to_user_inatomic __copy_to_user -#define __copy_from_user_inatomic __copy_from_user +#define __copy_to_user_inatomic ___copy_to_user +#define __copy_from_user_inatomic ___copy_from_user #endif /* __ASSEMBLY__ */ --- linux-2.6.27.orig/arch/sparc/kernel/entry.S +++ linux-2.6.27/arch/sparc/kernel/entry.S @@ -1142,8 +1142,8 @@ ld [%sp + STACKFRAME_SZ + PT_I0], %o0 .align 4 - .globl sys_pipe -sys_pipe: + .globl sys_sparc_pipe +sys_sparc_pipe: mov %o7, %l5 add %sp, STACKFRAME_SZ, %o0 ! pt_regs *regs arg call sparc_pipe --- linux-2.6.27.orig/arch/sparc/kernel/systbls.S +++ linux-2.6.27/arch/sparc/kernel/systbls.S @@ -24,7 +24,7 @@ /*25*/ .long sys_vmsplice, sys_ptrace, sys_alarm, sys_sigaltstack, sys_pause /*30*/ .long sys_utime, sys_lchown, sys_fchown, sys_access, sys_nice /*35*/ .long sys_chown, sys_sync, sys_kill, sys_newstat, sys_sendfile -/*40*/ .long sys_newlstat, sys_dup, sys_pipe, sys_times, sys_getuid +/*40*/ .long sys_newlstat, sys_dup, sys_sparc_pipe, sys_times, sys_getuid /*45*/ .long sys_umount, sys_setgid16, sys_getgid16, sys_signal, sys_geteuid16 /*50*/ .long sys_getegid16, sys_acct, sys_nis_syscall, sys_getgid, sys_ioctl /*55*/ .long sys_reboot, sys_mmap2, sys_symlink, sys_readlink, sys_execve @@ -56,7 +56,7 @@ /*185*/ .long sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sys_newuname /*190*/ .long sys_init_module, sys_personality, sparc_remap_file_pages, sys_epoll_create, sys_epoll_ctl /*195*/ .long sys_epoll_wait, sys_ioprio_set, sys_getppid, sparc_sigaction, sys_sgetmask -/*200*/ .long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir +/*200*/ .long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_old_readdir /*205*/ .long sys_readahead, sys_socketcall, sys_syslog, sys_lookup_dcookie, sys_fadvise64 /*210*/ .long sys_fadvise64_64, sys_tgkill, sys_waitpid, sys_swapoff, sys_sysinfo /*215*/ .long sys_ipc, sys_sigreturn, sys_clone, sys_ioprio_get, sys_adjtimex --- linux-2.6.27.orig/arch/mn10300/kernel/entry.S +++ linux-2.6.27/arch/mn10300/kernel/entry.S @@ -477,7 +477,7 @@ .long sys_uselib .long sys_swapon .long sys_reboot - .long old_readdir + .long sys_old_readdir .long old_mmap /* 90 */ .long sys_munmap .long sys_truncate --- linux-2.6.27.orig/arch/s390/Kconfig +++ linux-2.6.27/arch/s390/Kconfig @@ -70,6 +70,7 @@ config S390 def_bool y + select HAVE_SYSCALL_WRAPPERS select HAVE_OPROFILE select HAVE_KPROBES select HAVE_KRETPROBES --- linux-2.6.27.orig/arch/s390/kernel/smp.c +++ linux-2.6.27/arch/s390/kernel/smp.c @@ -1117,9 +1117,7 @@ return rc; } -static ssize_t __ref rescan_store(struct sys_device *dev, - struct sysdev_attribute *attr, - const char *buf, +static ssize_t __ref rescan_store(struct sysdev_class *class, const char *buf, size_t count) { int rc; @@ -1127,12 +1125,10 @@ rc = smp_rescan_cpus(); return rc ? rc : count; } -static SYSDEV_ATTR(rescan, 0200, NULL, rescan_store); +static SYSDEV_CLASS_ATTR(rescan, 0200, NULL, rescan_store); #endif /* CONFIG_HOTPLUG_CPU */ -static ssize_t dispatching_show(struct sys_device *dev, - struct sysdev_attribute *attr, - char *buf) +static ssize_t dispatching_show(struct sysdev_class *class, char *buf) { ssize_t count; @@ -1142,9 +1138,8 @@ return count; } -static ssize_t dispatching_store(struct sys_device *dev, - struct sysdev_attribute *attr, - const char *buf, size_t count) +static ssize_t dispatching_store(struct sysdev_class *dev, const char *buf, + size_t count) { int val, rc; char delim; @@ -1166,7 +1161,8 @@ put_online_cpus(); return rc ? rc : count; } -static SYSDEV_ATTR(dispatching, 0644, dispatching_show, dispatching_store); +static SYSDEV_CLASS_ATTR(dispatching, 0644, dispatching_show, + dispatching_store); static int __init topology_init(void) { @@ -1176,13 +1172,11 @@ register_cpu_notifier(&smp_cpu_nb); #ifdef CONFIG_HOTPLUG_CPU - rc = sysfs_create_file(&cpu_sysdev_class.kset.kobj, - &attr_rescan.attr); + rc = sysdev_class_create_file(&cpu_sysdev_class, &attr_rescan); if (rc) return rc; #endif - rc = sysfs_create_file(&cpu_sysdev_class.kset.kobj, - &attr_dispatching.attr); + rc = sysdev_class_create_file(&cpu_sysdev_class, &attr_dispatching); if (rc) return rc; for_each_present_cpu(cpu) { --- linux-2.6.27.orig/arch/s390/kernel/compat_wrapper.S +++ linux-2.6.27/arch/s390/kernel/compat_wrapper.S @@ -549,7 +549,7 @@ .globl sys32_newuname_wrapper sys32_newuname_wrapper: llgtr %r2,%r2 # struct new_utsname * - jg s390x_newuname # branch to system call + jg sys_s390_newuname # branch to system call .globl compat_sys_adjtimex_wrapper compat_sys_adjtimex_wrapper: @@ -617,7 +617,7 @@ .globl sys32_personality_wrapper sys32_personality_wrapper: llgfr %r2,%r2 # unsigned long - jg s390x_personality # branch to system call + jg sys_s390_personality # branch to system call .globl sys32_setfsuid16_wrapper sys32_setfsuid16_wrapper: --- linux-2.6.27.orig/arch/s390/kernel/entry.h +++ linux-2.6.27/arch/s390/kernel/entry.h @@ -30,23 +30,23 @@ struct old_sigaction; struct sel_arg_struct; -long sys_pipe(unsigned long __user *fildes); long sys_mmap2(struct mmap_arg_struct __user *arg); -long old_mmap(struct mmap_arg_struct __user *arg); +long sys_s390_old_mmap(struct mmap_arg_struct __user *arg); long sys_ipc(uint call, int first, unsigned long second, unsigned long third, void __user *ptr); -long s390x_newuname(struct new_utsname __user *name); -long s390x_personality(unsigned long personality); -long s390_fadvise64(int fd, u32 offset_high, u32 offset_low, +long sys_s390_newuname(struct new_utsname __user *name); +long sys_s390_personality(unsigned long personality); +long sys_s390_fadvise64(int fd, u32 offset_high, u32 offset_low, size_t len, int advice); -long s390_fadvise64_64(struct fadvise64_64_args __user *args); -long s390_fallocate(int fd, int mode, loff_t offset, u32 len_high, u32 len_low); +long sys_s390_fadvise64_64(struct fadvise64_64_args __user *args); +long sys_s390_fallocate(int fd, int mode, loff_t offset, u32 len_high, + u32 len_low); long sys_fork(void); long sys_clone(void); long sys_vfork(void); void execve_tail(void); long sys_execve(void); -int sys_sigsuspend(int history0, int history1, old_sigset_t mask); +long sys_sigsuspend(int history0, int history1, old_sigset_t mask); long sys_sigaction(int sig, const struct old_sigaction __user *act, struct old_sigaction __user *oact); long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss); --- linux-2.6.27.orig/arch/s390/kernel/process.c +++ linux-2.6.27/arch/s390/kernel/process.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -257,13 +258,13 @@ return 0; } -asmlinkage long sys_fork(void) +SYSCALL_DEFINE0(fork) { struct pt_regs *regs = task_pt_regs(current); return do_fork(SIGCHLD, regs->gprs[15], regs, 0, NULL, NULL); } -asmlinkage long sys_clone(void) +SYSCALL_DEFINE0(clone) { struct pt_regs *regs = task_pt_regs(current); unsigned long clone_flags; @@ -290,7 +291,7 @@ * do not have enough call-clobbered registers to hold all * the information you need. */ -asmlinkage long sys_vfork(void) +SYSCALL_DEFINE0(vfork) { struct pt_regs *regs = task_pt_regs(current); return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, @@ -310,7 +311,7 @@ /* * sys_execve() executes a new program. */ -asmlinkage long sys_execve(void) +SYSCALL_DEFINE0(execve) { struct pt_regs *regs = task_pt_regs(current); char *filename; --- linux-2.6.27.orig/arch/s390/kernel/topology.c +++ linux-2.6.27/arch/s390/kernel/topology.c @@ -65,18 +65,21 @@ static struct timer_list topology_timer; static void set_topology_timer(void); static DECLARE_WORK(topology_work, topology_work_fn); +/* topology_lock protects the core linked list */ +static DEFINE_SPINLOCK(topology_lock); cpumask_t cpu_core_map[NR_CPUS]; cpumask_t cpu_coregroup_map(unsigned int cpu) { struct core_info *core = &core_info; + unsigned long flags; cpumask_t mask; cpus_clear(mask); if (!machine_has_topology) return cpu_present_map; - mutex_lock(&smp_cpu_state_mutex); + spin_lock_irqsave(&topology_lock, flags); while (core) { if (cpu_isset(cpu, core->mask)) { mask = core->mask; @@ -84,7 +87,7 @@ } core = core->next; } - mutex_unlock(&smp_cpu_state_mutex); + spin_unlock_irqrestore(&topology_lock, flags); if (cpus_empty(mask)) mask = cpumask_of_cpu(cpu); return mask; @@ -133,7 +136,7 @@ union tl_entry *tle, *end; struct core_info *core = &core_info; - mutex_lock(&smp_cpu_state_mutex); + spin_lock_irq(&topology_lock); clear_cores(); tle = info->tle; end = (union tl_entry *)((unsigned long)info + info->length); @@ -157,7 +160,7 @@ } tle = next_tle(tle); } - mutex_unlock(&smp_cpu_state_mutex); + spin_unlock_irq(&topology_lock); } static void topology_update_polarization_simple(void) --- linux-2.6.27.orig/arch/s390/kernel/syscalls.S +++ linux-2.6.27/arch/s390/kernel/syscalls.S @@ -98,7 +98,7 @@ SYSCALL(sys_swapon,sys_swapon,sys32_swapon_wrapper) SYSCALL(sys_reboot,sys_reboot,sys32_reboot_wrapper) SYSCALL(sys_ni_syscall,sys_ni_syscall,old32_readdir_wrapper) /* old readdir syscall */ -SYSCALL(old_mmap,old_mmap,old32_mmap_wrapper) /* 90 */ +SYSCALL(sys_s390_old_mmap,sys_s390_old_mmap,old32_mmap_wrapper) /* 90 */ SYSCALL(sys_munmap,sys_munmap,sys32_munmap_wrapper) SYSCALL(sys_truncate,sys_truncate,sys32_truncate_wrapper) SYSCALL(sys_ftruncate,sys_ftruncate,sys32_ftruncate_wrapper) @@ -130,7 +130,7 @@ SYSCALL(sys_sigreturn,sys_sigreturn,sys32_sigreturn) SYSCALL(sys_clone,sys_clone,sys32_clone) /* 120 */ SYSCALL(sys_setdomainname,sys_setdomainname,sys32_setdomainname_wrapper) -SYSCALL(sys_newuname,s390x_newuname,sys32_newuname_wrapper) +SYSCALL(sys_newuname,sys_s390_newuname,sys32_newuname_wrapper) NI_SYSCALL /* modify_ldt for i386 */ SYSCALL(sys_adjtimex,sys_adjtimex,compat_sys_adjtimex_wrapper) SYSCALL(sys_mprotect,sys_mprotect,sys32_mprotect_wrapper) /* 125 */ @@ -144,7 +144,7 @@ SYSCALL(sys_fchdir,sys_fchdir,sys32_fchdir_wrapper) SYSCALL(sys_bdflush,sys_bdflush,sys32_bdflush_wrapper) SYSCALL(sys_sysfs,sys_sysfs,sys32_sysfs_wrapper) /* 135 */ -SYSCALL(sys_personality,s390x_personality,sys32_personality_wrapper) +SYSCALL(sys_personality,sys_s390_personality,sys32_personality_wrapper) NI_SYSCALL /* for afs_syscall */ SYSCALL(sys_setfsuid16,sys_ni_syscall,sys32_setfsuid16_wrapper) /* old setfsuid16 syscall */ SYSCALL(sys_setfsgid16,sys_ni_syscall,sys32_setfsgid16_wrapper) /* old setfsgid16 syscall */ @@ -261,7 +261,7 @@ SYSCALL(sys_epoll_ctl,sys_epoll_ctl,sys_epoll_ctl_wrapper) /* 250 */ SYSCALL(sys_epoll_wait,sys_epoll_wait,sys_epoll_wait_wrapper) SYSCALL(sys_set_tid_address,sys_set_tid_address,sys32_set_tid_address_wrapper) -SYSCALL(s390_fadvise64,sys_fadvise64_64,sys32_fadvise64_wrapper) +SYSCALL(sys_s390_fadvise64,sys_fadvise64_64,sys32_fadvise64_wrapper) SYSCALL(sys_timer_create,sys_timer_create,sys32_timer_create_wrapper) SYSCALL(sys_timer_settime,sys_timer_settime,sys32_timer_settime_wrapper) /* 255 */ SYSCALL(sys_timer_gettime,sys_timer_gettime,sys32_timer_gettime_wrapper) @@ -272,7 +272,7 @@ SYSCALL(sys_clock_getres,sys_clock_getres,sys32_clock_getres_wrapper) SYSCALL(sys_clock_nanosleep,sys_clock_nanosleep,sys32_clock_nanosleep_wrapper) NI_SYSCALL /* reserved for vserver */ -SYSCALL(s390_fadvise64_64,sys_ni_syscall,sys32_fadvise64_64_wrapper) +SYSCALL(sys_s390_fadvise64_64,sys_ni_syscall,sys32_fadvise64_64_wrapper) SYSCALL(sys_statfs64,sys_statfs64,compat_sys_statfs64_wrapper) SYSCALL(sys_fstatfs64,sys_fstatfs64,compat_sys_fstatfs64_wrapper) SYSCALL(sys_remap_file_pages,sys_remap_file_pages,sys32_remap_file_pages_wrapper) @@ -322,7 +322,7 @@ SYSCALL(sys_getcpu,sys_getcpu,sys_getcpu_wrapper) SYSCALL(sys_epoll_pwait,sys_epoll_pwait,compat_sys_epoll_pwait_wrapper) SYSCALL(sys_utimes,sys_utimes,compat_sys_utimes_wrapper) -SYSCALL(s390_fallocate,sys_fallocate,sys_fallocate_wrapper) +SYSCALL(sys_s390_fallocate,sys_fallocate,sys_fallocate_wrapper) SYSCALL(sys_utimensat,sys_utimensat,compat_sys_utimensat_wrapper) /* 315 */ SYSCALL(sys_signalfd,sys_signalfd,compat_sys_signalfd_wrapper) NI_SYSCALL /* 317 old sys_timer_fd */ --- linux-2.6.27.orig/arch/s390/kernel/signal.c +++ linux-2.6.27/arch/s390/kernel/signal.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -52,8 +53,7 @@ /* * Atomically swap in the new signal mask, and wait for a signal. */ -asmlinkage int -sys_sigsuspend(int history0, int history1, old_sigset_t mask) +SYSCALL_DEFINE3(sigsuspend, int, history0, int, history1, old_sigset_t, mask) { mask &= _BLOCKABLE; spin_lock_irq(¤t->sighand->siglock); @@ -69,9 +69,8 @@ return -ERESTARTNOHAND; } -asmlinkage long -sys_sigaction(int sig, const struct old_sigaction __user *act, - struct old_sigaction __user *oact) +SYSCALL_DEFINE3(sigaction, int, sig, const struct old_sigaction __user *, act, + struct old_sigaction __user *, oact) { struct k_sigaction new_ka, old_ka; int ret; @@ -101,15 +100,13 @@ return ret; } -asmlinkage long -sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) +SYSCALL_DEFINE2(sigaltstack, const stack_t __user *, uss, + stack_t __user *, uoss) { struct pt_regs *regs = task_pt_regs(current); return do_sigaltstack(uss, uoss, regs->gprs[15]); } - - /* Returns non-zero on fault. */ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs) { @@ -163,7 +160,7 @@ return 0; } -asmlinkage long sys_sigreturn(void) +SYSCALL_DEFINE0(sigreturn) { struct pt_regs *regs = task_pt_regs(current); sigframe __user *frame = (sigframe __user *)regs->gprs[15]; @@ -190,7 +187,7 @@ return 0; } -asmlinkage long sys_rt_sigreturn(void) +SYSCALL_DEFINE0(rt_sigreturn) { struct pt_regs *regs = task_pt_regs(current); rt_sigframe __user *frame = (rt_sigframe __user *)regs->gprs[15]; --- linux-2.6.27.orig/arch/s390/kernel/sys_s390.c +++ linux-2.6.27/arch/s390/kernel/sys_s390.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "entry.h" @@ -74,7 +75,7 @@ unsigned long offset; }; -asmlinkage long sys_mmap2(struct mmap_arg_struct __user *arg) +SYSCALL_DEFINE1(mmap2, struct mmap_arg_struct __user *, arg) { struct mmap_arg_struct a; int error = -EFAULT; @@ -86,7 +87,7 @@ return error; } -asmlinkage long old_mmap(struct mmap_arg_struct __user *arg) +SYSCALL_DEFINE1(s390_old_mmap, struct mmap_arg_struct __user *, arg) { struct mmap_arg_struct a; long error = -EFAULT; @@ -127,8 +128,8 @@ * * This is really horribly ugly. */ -asmlinkage long sys_ipc(uint call, int first, unsigned long second, - unsigned long third, void __user *ptr) +SYSCALL_DEFINE5(ipc, uint, call, int, first, unsigned long, second, + unsigned long, third, void __user *, ptr) { struct ipc_kludge tmp; int ret; @@ -194,7 +195,7 @@ } #ifdef CONFIG_64BIT -asmlinkage long s390x_newuname(struct new_utsname __user *name) +SYSCALL_DEFINE1(s390_newuname, struct new_utsname __user *, name) { int ret = sys_newuname(name); @@ -205,7 +206,7 @@ return ret; } -asmlinkage long s390x_personality(unsigned long personality) +SYSCALL_DEFINE1(s390_personality, unsigned long, personality) { int ret; @@ -224,15 +225,13 @@ */ #ifndef CONFIG_64BIT -asmlinkage long -s390_fadvise64(int fd, u32 offset_high, u32 offset_low, size_t len, int advice) +SYSCALL_DEFINE5(s390_fadvise64, int, fd, u32, offset_high, u32, offset_low, + size_t, len, int, advice) { return sys_fadvise64(fd, (u64) offset_high << 32 | offset_low, len, advice); } -#endif - struct fadvise64_64_args { int fd; long long offset; @@ -240,8 +239,7 @@ int advice; }; -asmlinkage long -s390_fadvise64_64(struct fadvise64_64_args __user *args) +SYSCALL_DEFINE1(s390_fadvise64_64, struct fadvise64_64_args __user *, args) { struct fadvise64_64_args a; @@ -250,7 +248,6 @@ return sys_fadvise64_64(a.fd, a.offset, a.len, a.advice); } -#ifndef CONFIG_64BIT /* * This is a wrapper to call sys_fallocate(). For 31 bit s390 the last * 64 bit argument "len" is split into the upper and lower 32 bits. The @@ -263,9 +260,19 @@ * to * %r2: fd, %r3: mode, %r4/%r5: offset, 96(%r15)-103(%r15): len */ -asmlinkage long s390_fallocate(int fd, int mode, loff_t offset, +SYSCALL_DEFINE(s390_fallocate)(int fd, int mode, loff_t offset, u32 len_high, u32 len_low) { return sys_fallocate(fd, mode, offset, ((u64)len_high << 32) | len_low); } +#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS +asmlinkage long SyS_s390_fallocate(long fd, long mode, loff_t offset, + long len_high, long len_low) +{ + return SYSC_s390_fallocate((int) fd, (int) mode, offset, + (u32) len_high, (u32) len_low); +} +SYSCALL_ALIAS(sys_s390_fallocate, SyS_s390_fallocate); +#endif + #endif --- linux-2.6.27.orig/arch/parisc/kernel/traps.c +++ linux-2.6.27/arch/parisc/kernel/traps.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -51,7 +50,7 @@ DEFINE_SPINLOCK(pa_dbit_lock); #endif -void parisc_show_stack(struct task_struct *t, unsigned long *sp, +static void parisc_show_stack(struct task_struct *task, unsigned long *sp, struct pt_regs *regs); static int printbinary(char *buf, unsigned long x, int nbits) @@ -121,18 +120,19 @@ void show_regs(struct pt_regs *regs) { - int i; + int i, user; char *level; unsigned long cr30, cr31; - level = user_mode(regs) ? KERN_DEBUG : KERN_CRIT; + user = user_mode(regs); + level = user ? KERN_DEBUG : KERN_CRIT; print_gr(level, regs); for (i = 0; i < 8; i += 4) PRINTREGS(level, regs->sr, "sr", RFMT, i); - if (user_mode(regs)) + if (user) print_fr(level, regs); cr30 = mfctl(30); @@ -145,14 +145,18 @@ printk("%s CPU: %8d CR30: " RFMT " CR31: " RFMT "\n", level, current_thread_info()->cpu, cr30, cr31); printk("%s ORIG_R28: " RFMT "\n", level, regs->orig_r28); - printk(level); - print_symbol(" IAOQ[0]: %s\n", regs->iaoq[0]); - printk(level); - print_symbol(" IAOQ[1]: %s\n", regs->iaoq[1]); - printk(level); - print_symbol(" RP(r2): %s\n", regs->gr[2]); - parisc_show_stack(current, NULL, regs); + if (user) { + printk("%s IAOQ[0]: " RFMT "\n", level, regs->iaoq[0]); + printk("%s IAOQ[1]: " RFMT "\n", level, regs->iaoq[1]); + printk("%s RP(r2): " RFMT "\n", level, regs->gr[2]); + } else { + printk("%s IAOQ[0]: %pS\n", level, (void *) regs->iaoq[0]); + printk("%s IAOQ[1]: %pS\n", level, (void *) regs->iaoq[1]); + printk("%s RP(r2): %pS\n", level, (void *) regs->gr[2]); + + parisc_show_stack(current, NULL, regs); + } } @@ -173,20 +177,15 @@ break; if (__kernel_text_address(info->ip)) { - printk("%s [<" RFMT ">] ", (i&0x3)==1 ? KERN_CRIT : "", info->ip); -#ifdef CONFIG_KALLSYMS - print_symbol("%s\n", info->ip); -#else - if ((i & 0x03) == 0) - printk("\n"); -#endif + printk(KERN_CRIT " [<" RFMT ">] %pS\n", + info->ip, (void *) info->ip); i++; } } - printk("\n"); + printk(KERN_CRIT "\n"); } -void parisc_show_stack(struct task_struct *task, unsigned long *sp, +static void parisc_show_stack(struct task_struct *task, unsigned long *sp, struct pt_regs *regs) { struct unwind_frame_info info; --- linux-2.6.27.orig/arch/ia64/Kconfig +++ linux-2.6.27/arch/ia64/Kconfig @@ -15,6 +15,7 @@ select ACPI if (!IA64_HP_SIM) select PM if (!IA64_HP_SIM) select ARCH_SUPPORTS_MSI + select HAVE_UNSTABLE_SCHED_CLOCK select HAVE_IDE select HAVE_OPROFILE select HAVE_KPROBES --- linux-2.6.27.orig/arch/ia64/include/asm/unistd.h +++ linux-2.6.27/arch/ia64/include/asm/unistd.h @@ -363,7 +363,7 @@ struct sigaction; long sys_execve(char __user *filename, char __user * __user *argv, char __user * __user *envp, struct pt_regs *regs); -asmlinkage long sys_pipe(void); +asmlinkage long sys_ia64_pipe(void); asmlinkage long sys_rt_sigaction(int sig, const struct sigaction __user *act, struct sigaction __user *oact, --- linux-2.6.27.orig/arch/ia64/sn/kernel/io_acpi_init.c +++ linux-2.6.27/arch/ia64/sn/kernel/io_acpi_init.c @@ -434,7 +434,7 @@ size = pci_resource_len(dev, PCI_ROM_RESOURCE); addr = ioremap(pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE], size); - image_size = pci_get_rom_size(addr, size); + image_size = pci_get_rom_size(dev, addr, size); dev->resource[PCI_ROM_RESOURCE].start = (unsigned long) addr; dev->resource[PCI_ROM_RESOURCE].end = (unsigned long) addr + image_size - 1; --- linux-2.6.27.orig/arch/ia64/sn/kernel/io_init.c +++ linux-2.6.27/arch/ia64/sn/kernel/io_init.c @@ -269,7 +269,7 @@ rom = ioremap(pci_resource_start(dev, PCI_ROM_RESOURCE), size + 1); - image_size = pci_get_rom_size(rom, size + 1); + image_size = pci_get_rom_size(dev, rom, size + 1); dev->resource[PCI_ROM_RESOURCE].end = dev->resource[PCI_ROM_RESOURCE].start + image_size - 1; --- linux-2.6.27.orig/arch/ia64/ia32/ia32_entry.S +++ linux-2.6.27/arch/ia64/ia32/ia32_entry.S @@ -215,7 +215,7 @@ data8 sys_mkdir data8 sys_rmdir /* 40 */ data8 sys_dup - data8 sys32_pipe + data8 sys_ia64_pipe data8 compat_sys_times data8 sys_ni_syscall /* old prof syscall holder */ data8 sys32_brk /* 45 */ --- linux-2.6.27.orig/arch/ia64/kernel/setup.c +++ linux-2.6.27/arch/ia64/kernel/setup.c @@ -549,8 +549,12 @@ #ifdef CONFIG_ACPI /* Initialize the ACPI boot-time table parser */ acpi_table_init(); + early_acpi_boot_init(); # ifdef CONFIG_ACPI_NUMA acpi_numa_init(); +#ifdef CONFIG_ACPI_HOTPLUG_CPU + prefill_possible_map(); +#endif per_cpu_scan_finalize((cpus_weight(early_cpu_possible_map) == 0 ? 32 : cpus_weight(early_cpu_possible_map)), additional_cpus > 0 ? additional_cpus : 0); @@ -841,9 +845,6 @@ setup_per_cpu_areas (void) { /* start_kernel() requires this... */ -#ifdef CONFIG_ACPI_HOTPLUG_CPU - prefill_possible_map(); -#endif } /* --- linux-2.6.27.orig/arch/ia64/kernel/entry.S +++ linux-2.6.27/arch/ia64/kernel/entry.S @@ -1436,7 +1436,7 @@ data8 sys_mkdir // 1055 data8 sys_rmdir data8 sys_dup - data8 sys_pipe + data8 sys_ia64_pipe data8 sys_times data8 ia64_brk // 1060 data8 sys_setgid --- linux-2.6.27.orig/arch/ia64/kernel/acpi.c +++ linux-2.6.27/arch/ia64/kernel/acpi.c @@ -656,6 +656,30 @@ return 0; } +int __init early_acpi_boot_init(void) +{ + int ret; + + /* + * do a partial walk of MADT to determine how many CPUs + * we have including offline CPUs + */ + if (acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) { + printk(KERN_ERR PREFIX "Can't find MADT\n"); + return 0; + } + + ret = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_SAPIC, + acpi_parse_lsapic, NR_CPUS); + if (ret < 1) + printk(KERN_ERR PREFIX + "Error parsing MADT - no LAPIC entries\n"); + + return 0; +} + + + int __init acpi_boot_init(void) { @@ -679,11 +703,6 @@ printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); - if (acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_SAPIC, acpi_parse_lsapic, NR_CPUS) - < 1) - printk(KERN_ERR PREFIX - "Error parsing MADT - no LAPIC entries\n"); - if (acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0) < 0) printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); --- linux-2.6.27.orig/arch/ia64/kernel/sys_ia64.c +++ linux-2.6.27/arch/ia64/kernel/sys_ia64.c @@ -154,7 +154,7 @@ * and r9) as this is faster than doing a copy_to_user(). */ asmlinkage long -sys_pipe (void) +sys_ia64_pipe (void) { struct pt_regs *regs = task_pt_regs(current); int fd[2]; --- linux-2.6.27.orig/arch/sparc64/Kconfig +++ linux-2.6.27/arch/sparc64/Kconfig @@ -15,6 +15,7 @@ select HAVE_FTRACE select HAVE_IDE select HAVE_LMB + select HAVE_SYSCALL_WRAPPERS select HAVE_ARCH_KGDB select USE_GENERIC_SMP_HELPERS if SMP select HAVE_ARCH_TRACEHOOK --- linux-2.6.27.orig/arch/sparc64/lib/user_fixup.c +++ linux-2.6.27/arch/sparc64/lib/user_fixup.c @@ -24,7 +24,7 @@ if (fault_addr < start || fault_addr >= end) { *offset = 0; } else { - *offset = start - fault_addr; + *offset = fault_addr - start; size = end - fault_addr; } return size; --- linux-2.6.27.orig/arch/sparc64/kernel/pci.c +++ linux-2.6.27/arch/sparc64/kernel/pci.c @@ -1017,6 +1017,7 @@ for (i = 0; i <= PCI_ROM_RESOURCE; i++) { struct resource *rp = &pdev->resource[i]; + resource_size_t aligned_end; /* Active? */ if (!rp->flags) @@ -1034,8 +1035,15 @@ continue; } + /* Align the resource end to the next page address. + * PAGE_SIZE intentionally added instead of (PAGE_SIZE - 1), + * because actually we need the address of the next byte + * after rp->end. + */ + aligned_end = (rp->end + PAGE_SIZE) & PAGE_MASK; + if ((rp->start <= user_paddr) && - (user_paddr + user_size) <= (rp->end + 1UL)) + (user_paddr + user_size) <= aligned_end) break; } --- linux-2.6.27.orig/arch/sparc64/kernel/systbls.h +++ linux-2.6.27/arch/sparc64/kernel/systbls.h @@ -16,9 +16,6 @@ void __user *ptr, long fifth); extern asmlinkage long sparc64_newuname(struct new_utsname __user *name); extern asmlinkage long sparc64_personality(unsigned long personality); -extern asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long off); extern asmlinkage long sys64_munmap(unsigned long addr, size_t len); extern asmlinkage unsigned long sys64_mremap(unsigned long addr, unsigned long old_len, --- linux-2.6.27.orig/arch/sparc64/kernel/systbls.S +++ linux-2.6.27/arch/sparc64/kernel/systbls.S @@ -21,12 +21,12 @@ /*0*/ .word sys_restart_syscall, sys32_exit, sys_fork, sys_read, sys_write /*5*/ .word sys32_open, sys_close, sys32_wait4, sys32_creat, sys_link /*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys32_mknod -/*15*/ .word sys_chmod, sys_lchown16, sparc_brk, sys32_perfctr, sys32_lseek +/*15*/ .word sys_chmod, sys_lchown16, sys_sparc_brk, sys32_perfctr, sys32_lseek /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16 /*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause /*30*/ .word compat_sys_utime, sys_lchown, sys_fchown, sys32_access, sys32_nice .word sys_chown, sys_sync, sys32_kill, compat_sys_newstat, sys32_sendfile -/*40*/ .word compat_sys_newlstat, sys_dup, sys_pipe, compat_sys_times, sys_getuid +/*40*/ .word compat_sys_newlstat, sys_dup, sys_sparc_pipe, compat_sys_times, sys_getuid .word sys32_umount, sys_setgid16, sys_getgid16, sys32_signal, sys_geteuid16 /*50*/ .word sys_getegid16, sys_acct, sys_nis_syscall, sys_getgid, compat_sys_ioctl .word sys32_reboot, sys32_mmap2, sys_symlink, sys32_readlink, sys32_execve @@ -55,8 +55,8 @@ /*170*/ .word sys32_lsetxattr, sys32_fsetxattr, sys_getxattr, sys_lgetxattr, compat_sys_getdents .word sys_setsid, sys_fchdir, sys32_fgetxattr, sys_listxattr, sys_llistxattr /*180*/ .word sys32_flistxattr, sys_removexattr, sys_lremovexattr, compat_sys_sigpending, sys_ni_syscall - .word sys32_setpgid, sys32_fremovexattr, sys32_tkill, sys32_exit_group, sparc64_newuname -/*190*/ .word sys32_init_module, sparc64_personality, sys_remap_file_pages, sys32_epoll_create, sys32_epoll_ctl + .word sys32_setpgid, sys32_fremovexattr, sys32_tkill, sys32_exit_group, sys_sparc64_newuname +/*190*/ .word sys32_init_module, sys_sparc64_personality, sys_remap_file_pages, sys32_epoll_create, sys32_epoll_ctl .word sys32_epoll_wait, sys32_ioprio_set, sys_getppid, sys32_sigaction, sys_sgetmask /*200*/ .word sys32_ssetmask, sys_sigsuspend, compat_sys_newlstat, sys_uselib, compat_sys_old_readdir .word sys32_readahead, sys32_socketcall, sys32_syslog, sys32_lookup_dcookie, sys32_fadvise64 @@ -95,18 +95,18 @@ /*0*/ .word sys_restart_syscall, sparc_exit, sys_fork, sys_read, sys_write /*5*/ .word sys_open, sys_close, sys_wait4, sys_creat, sys_link /*10*/ .word sys_unlink, sys_nis_syscall, sys_chdir, sys_chown, sys_mknod -/*15*/ .word sys_chmod, sys_lchown, sparc_brk, sys_perfctr, sys_lseek +/*15*/ .word sys_chmod, sys_lchown, sys_sparc_brk, sys_perfctr, sys_lseek /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid /*25*/ .word sys_vmsplice, sys_ptrace, sys_alarm, sys_sigaltstack, sys_nis_syscall /*30*/ .word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice .word sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_sendfile64 -/*40*/ .word sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall +/*40*/ .word sys_newlstat, sys_dup, sys_sparc_pipe, sys_times, sys_nis_syscall .word sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid /*50*/ .word sys_getegid, sys_acct, sys_memory_ordering, sys_nis_syscall, sys_ioctl .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve /*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_fstat64, sys_getpagesize .word sys_msync, sys_vfork, sys_pread64, sys_pwrite64, sys_nis_syscall -/*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys64_munmap, sys_mprotect +/*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_64_munmap, sys_mprotect .word sys_madvise, sys_vhangup, sys_nis_syscall, sys_mincore, sys_getgroups /*80*/ .word sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall .word sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall @@ -129,8 +129,8 @@ /*170*/ .word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents .word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr /*180*/ .word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_nis_syscall, sys_ni_syscall - .word sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sparc64_newuname -/*190*/ .word sys_init_module, sparc64_personality, sys_remap_file_pages, sys_epoll_create, sys_epoll_ctl + .word sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sys_sparc64_newuname +/*190*/ .word sys_init_module, sys_sparc64_personality, sys_remap_file_pages, sys_epoll_create, sys_epoll_ctl .word sys_epoll_wait, sys_ioprio_set, sys_getppid, sys_nis_syscall, sys_sgetmask /*200*/ .word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall .word sys_readahead, sys_socketcall, sys_syslog, sys_lookup_dcookie, sys_fadvise64 @@ -142,7 +142,7 @@ .word sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep -/*250*/ .word sys64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl +/*250*/ .word sys_64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl .word sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep /*260*/ .word sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun .word sys_timer_delete, sys_timer_create, sys_ni_syscall, sys_io_setup, sys_io_destroy --- linux-2.6.27.orig/arch/sparc64/kernel/trampoline.S +++ linux-2.6.27/arch/sparc64/kernel/trampoline.S @@ -328,6 +328,12 @@ wrpr %g0, 0, %wstate + sethi %hi(prom_entry_lock), %g2 +1: ldstub [%g2 + %lo(prom_entry_lock)], %g1 + membar #StoreLoad | #StoreStore + brnz,pn %g1, 1b + nop + /* As a hack, put &init_thread_union into %g6. * prom_world() loads from here to restore the %asi * register. @@ -337,7 +343,7 @@ sethi %hi(is_sun4v), %o0 lduw [%o0 + %lo(is_sun4v)], %o0 - brz,pt %o0, 1f + brz,pt %o0, 2f nop TRAP_LOAD_TRAP_BLOCK(%g2, %g3) @@ -369,10 +375,10 @@ call %o1 add %sp, (2047 + 128), %o0 - ba,pt %xcc, 2f + ba,pt %xcc, 3f nop -1: sethi %hi(sparc64_ttable_tl0), %o0 +2: sethi %hi(sparc64_ttable_tl0), %o0 set prom_set_trap_table_name, %g2 stx %g2, [%sp + 2047 + 128 + 0x00] mov 1, %g2 @@ -386,7 +392,11 @@ call %o1 add %sp, (2047 + 128), %o0 -2: ldx [%l0], %g6 +3: sethi %hi(prom_entry_lock), %g2 + stb %g0, [%g2 + %lo(prom_entry_lock)] + membar #StoreStore | #StoreLoad + + ldx [%l0], %g6 ldx [%g6 + TI_TASK], %g4 mov 1, %g5 --- linux-2.6.27.orig/arch/sparc64/kernel/sys_sparc.c +++ linux-2.6.27/arch/sparc64/kernel/sys_sparc.c @@ -397,7 +397,7 @@ } } -asmlinkage unsigned long sparc_brk(unsigned long brk) +SYSCALL_DEFINE1(sparc_brk, unsigned long, brk) { /* People could try to be nasty and use ta 0x6d in 32bit programs */ if (test_thread_flag(TIF_32BIT) && brk >= STACK_TOP32) @@ -413,7 +413,7 @@ * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way unix traditionally does this, though. */ -asmlinkage long sparc_pipe(struct pt_regs *regs) +SYSCALL_DEFINE1(sparc_pipe_real, struct pt_regs *, regs) { int fd[2]; int error; @@ -433,8 +433,8 @@ * This is really horribly ugly. */ -asmlinkage long sys_ipc(unsigned int call, int first, unsigned long second, - unsigned long third, void __user *ptr, long fifth) +SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second, + unsigned long, third, void __user *, ptr, long, fifth) { long err; @@ -517,7 +517,7 @@ return err; } -asmlinkage long sparc64_newuname(struct new_utsname __user *name) +SYSCALL_DEFINE1(sparc64_newuname, struct new_utsname __user *, name) { int ret = sys_newuname(name); @@ -528,7 +528,7 @@ return ret; } -asmlinkage long sparc64_personality(unsigned long personality) +SYSCALL_DEFINE1(sparc64_personality, unsigned long, personality) { int ret; @@ -562,9 +562,9 @@ } /* Linux version of mmap */ -asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, unsigned long fd, - unsigned long off) +SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, + unsigned long, prot, unsigned long, flags, unsigned long, fd, + unsigned long, off) { struct file * file = NULL; unsigned long retval = -EBADF; @@ -587,7 +587,7 @@ return retval; } -asmlinkage long sys64_munmap(unsigned long addr, size_t len) +SYSCALL_DEFINE2(64_munmap, unsigned long, addr, size_t, len) { long ret; @@ -604,9 +604,9 @@ unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr); -asmlinkage unsigned long sys64_mremap(unsigned long addr, - unsigned long old_len, unsigned long new_len, - unsigned long flags, unsigned long new_addr) +SYSCALL_DEFINE5(64_mremap, unsigned long, addr, unsigned long, old_len, + unsigned long, new_len, unsigned long, flags, + unsigned long, new_addr) { unsigned long ret = -EINVAL; @@ -669,7 +669,7 @@ extern void check_pending(int signum); -asmlinkage long sys_getdomainname(char __user *name, int len) +SYSCALL_DEFINE2(getdomainname, char __user *, name, int, len) { int nlen, err; @@ -692,11 +692,10 @@ return err; } -asmlinkage long sys_utrap_install(utrap_entry_t type, - utrap_handler_t new_p, - utrap_handler_t new_d, - utrap_handler_t __user *old_p, - utrap_handler_t __user *old_d) +SYSCALL_DEFINE5(utrap_install, utrap_entry_t, type, + utrap_handler_t, new_p, utrap_handler_t, new_d, + utrap_handler_t __user *, old_p, + utrap_handler_t __user *, old_d) { if (type < UT_INSTRUCTION_EXCEPTION || type > UT_TRAP_INSTRUCTION_31) return -EINVAL; @@ -762,11 +761,9 @@ return 0; } -asmlinkage long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - void __user *restorer, - size_t sigsetsize) +SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act, + struct sigaction __user *, oact, void __user *, restorer, + size_t, sigsetsize) { struct k_sigaction new_ka, old_ka; int ret; @@ -806,7 +803,8 @@ reset_pic(); } -asmlinkage long sys_perfctr(int opcode, unsigned long arg0, unsigned long arg1, unsigned long arg2) +SYSCALL_DEFINE4(perfctr, int, opcode, unsigned long, arg0, + unsigned long, arg1, unsigned long, arg2) { int err = 0; --- linux-2.6.27.orig/arch/sparc64/kernel/syscalls.S +++ linux-2.6.27/arch/sparc64/kernel/syscalls.S @@ -20,8 +20,8 @@ add %sp, PTREGS_OFF, %o0 .align 32 -sys_pipe: - ba,pt %xcc, sparc_pipe +sys_sparc_pipe: + ba,pt %xcc, sys_sparc_pipe_real add %sp, PTREGS_OFF, %o0 sys_nis_syscall: ba,pt %xcc, c_sys_nis_syscall --- linux-2.6.27.orig/arch/sparc64/kernel/ptrace.c +++ linux-2.6.27/arch/sparc64/kernel/ptrace.c @@ -1014,7 +1014,7 @@ break; case PTRACE_SETFPREGS64: - ret = copy_regset_to_user(child, view, REGSET_FP, + ret = copy_regset_from_user(child, view, REGSET_FP, 0 * sizeof(u64), 33 * sizeof(u64), fps); --- linux-2.6.27.orig/arch/sparc64/kernel/pci_common.c +++ linux-2.6.27/arch/sparc64/kernel/pci_common.c @@ -368,7 +368,7 @@ const u32 *vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL); if (vdma) { - struct resource *rp = kmalloc(sizeof(*rp), GFP_KERNEL); + struct resource *rp = kzalloc(sizeof(*rp), GFP_KERNEL); if (!rp) { prom_printf("Cannot allocate IOMMU resource.\n"); --- linux-2.6.27.orig/arch/sparc64/kernel/visemul.c +++ linux-2.6.27/arch/sparc64/kernel/visemul.c @@ -131,7 +131,7 @@ #define VIS_OPF_SHIFT 5 #define VIS_OPF_MASK (0x1ff << VIS_OPF_SHIFT) -#define RS1(INSN) (((INSN) >> 24) & 0x1f) +#define RS1(INSN) (((INSN) >> 14) & 0x1f) #define RS2(INSN) (((INSN) >> 0) & 0x1f) #define RD(INSN) (((INSN) >> 25) & 0x1f) @@ -445,7 +445,7 @@ unsigned long i; rs1 = fpd_regval(f, RS1(insn)); - rs2 = fpd_regval(f, RS1(insn)); + rs2 = fpd_regval(f, RS2(insn)); rd = fpd_regaddr(f, RD(insn)); rd_val = *rd; @@ -807,6 +807,8 @@ if (get_user(insn, (u32 __user *) pc)) return -EFAULT; + save_and_clear_fpu(); + opf = (insn & VIS_OPF_MASK) >> VIS_OPF_SHIFT; switch (opf) { default: --- linux-2.6.27.orig/arch/h8300/kernel/syscalls.S +++ linux-2.6.27/arch/h8300/kernel/syscalls.S @@ -103,7 +103,7 @@ .long SYMBOL_NAME(sys_uselib) .long SYMBOL_NAME(sys_swapon) .long SYMBOL_NAME(sys_reboot) - .long SYMBOL_NAME(old_readdir) + .long SYMBOL_NAME(sys_old_readdir) .long SYMBOL_NAME(old_mmap) /* 90 */ .long SYMBOL_NAME(sys_munmap) .long SYMBOL_NAME(sys_truncate) --- linux-2.6.27.orig/arch/x86/Kconfig +++ linux-2.6.27/arch/x86/Kconfig @@ -123,6 +123,9 @@ config ARCH_HAS_CPU_RELAX def_bool y +config ARCH_HAS_DEFAULT_IDLE + def_bool y + config ARCH_HAS_CACHE_LINE_SIZE def_bool y @@ -567,7 +570,7 @@ # need this always selected by IOMMU for the VIA workaround config SWIOTLB - bool + def_bool y if X86_64 help Support for software bounce buffers used on x86-64 systems which don't have a hardware IOMMU (e.g. the current generation @@ -1059,6 +1062,26 @@ low memory. Setting this option will put user-space page table entries in high memory. +config X86_RESERVE_LOW_64K + bool "Reserve low 64K of RAM on AMI/Phoenix BIOSen" + default y + help + Reserve the first 64K of physical RAM on BIOSes that are known + to potentially corrupt that memory range. A numbers of BIOSes are + known to utilize this area during suspend/resume, so it must not + be used by the kernel. + + Set this to N if you are absolutely sure that you trust the BIOS + to get all its memory reservations and usages right. + + If you have doubts about the BIOS (e.g. suspend/resume does not + work or there's kernel crashes after certain hardware hotplug + events) and it's not AMI or Phoenix, then you might want to enable + X86_CHECK_BIOS_CORRUPTION=y to allow the kernel to check typical + corruption patterns. + + Say Y if unsure. + config MATH_EMULATION bool prompt "Math emulation" if X86_32 @@ -1782,6 +1805,8 @@ source "drivers/Kconfig" +source "ubuntu/Kconfig" + source "drivers/firmware/Kconfig" source "fs/Kconfig" --- linux-2.6.27.orig/arch/x86/kvm/vmx.c +++ linux-2.6.27/arch/x86/kvm/vmx.c @@ -898,11 +898,11 @@ int ret = 0; switch (msr_index) { -#ifdef CONFIG_X86_64 case MSR_EFER: vmx_load_host_state(vmx); ret = kvm_set_msr_common(vcpu, msr_index, data); break; +#ifdef CONFIG_X86_64 case MSR_FS_BASE: vmcs_writel(GUEST_FS_BASE, data); break; --- linux-2.6.27.orig/arch/x86/kvm/mmu.c +++ linux-2.6.27/arch/x86/kvm/mmu.c @@ -2055,6 +2055,7 @@ { struct kvm_mmu_page *sp; + spin_lock(&kvm->mmu_lock); list_for_each_entry(sp, &kvm->arch.active_mmu_pages, link) { int i; u64 *pt; @@ -2068,6 +2069,7 @@ if (pt[i] & PT_WRITABLE_MASK) pt[i] &= ~PT_WRITABLE_MASK; } + spin_unlock(&kvm->mmu_lock); } void kvm_mmu_zap_all(struct kvm *kvm) --- linux-2.6.27.orig/arch/x86/kvm/x86.c +++ linux-2.6.27/arch/x86/kvm/x86.c @@ -3582,7 +3582,13 @@ vcpu->arch.cr2 = sregs->cr2; mmu_reset_needed |= vcpu->arch.cr3 != sregs->cr3; - vcpu->arch.cr3 = sregs->cr3; + + down_read(&vcpu->kvm->slots_lock); + if (gfn_to_memslot(vcpu->kvm, sregs->cr3 >> PAGE_SHIFT)) + vcpu->arch.cr3 = sregs->cr3; + else + set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests); + up_read(&vcpu->kvm->slots_lock); kvm_set_cr8(vcpu, sregs->cr8); --- linux-2.6.27.orig/arch/x86/mm/init_64.c +++ linux-2.6.27/arch/x86/mm/init_64.c @@ -446,13 +446,14 @@ return phys_pud_init(pud, addr, end, page_size_mask); } -static void __init find_early_table_space(unsigned long end) +static void __init find_early_table_space(unsigned long end, int use_pse, + int use_gbpages) { unsigned long puds, pmds, ptes, tables, start; puds = (end + PUD_SIZE - 1) >> PUD_SHIFT; tables = round_up(puds * sizeof(pud_t), PAGE_SIZE); - if (direct_gbpages) { + if (use_gbpages) { unsigned long extra; extra = end - ((end>>PUD_SHIFT) << PUD_SHIFT); pmds = (extra + PMD_SIZE - 1) >> PMD_SHIFT; @@ -460,7 +461,7 @@ pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; tables += round_up(pmds * sizeof(pmd_t), PAGE_SIZE); - if (cpu_has_pse) { + if (use_pse) { unsigned long extra; extra = end - ((end>>PMD_SHIFT) << PMD_SHIFT); ptes = (extra + PAGE_SIZE - 1) >> PAGE_SHIFT; @@ -571,6 +572,7 @@ struct map_range mr[NR_RANGE_MR]; int nr_range, i; + int use_pse, use_gbpages; printk(KERN_INFO "init_memory_mapping\n"); @@ -584,9 +586,21 @@ if (!after_bootmem) init_gbpages(); - if (direct_gbpages) +#ifdef CONFIG_DEBUG_PAGEALLOC + /* + * For CONFIG_DEBUG_PAGEALLOC, identity mapping will use small pages. + * This will simplify cpa(), which otherwise needs to support splitting + * large pages into small in interrupt context, etc. + */ + use_pse = use_gbpages = 0; +#else + use_pse = cpu_has_pse; + use_gbpages = direct_gbpages; +#endif + + if (use_gbpages) page_size_mask |= 1 << PG_LEVEL_1G; - if (cpu_has_pse) + if (use_pse) page_size_mask |= 1 << PG_LEVEL_2M; memset(mr, 0, sizeof(mr)); @@ -647,7 +661,7 @@ (mr[i].page_size_mask & (1<> PAGE_SHIFT; int ret; - last_mapped_pfn = init_memory_mapping(start, start + size-1); + last_mapped_pfn = init_memory_mapping(start, start + size); if (last_mapped_pfn > max_pfn_mapped) max_pfn_mapped = last_mapped_pfn; ret = __add_pages(zone, start_pfn, nr_pages); - WARN_ON(1); + WARN_ON_ONCE(ret); return ret; } --- linux-2.6.27.orig/arch/x86/mm/discontig_32.c +++ linux-2.6.27/arch/x86/mm/discontig_32.c @@ -222,6 +222,41 @@ } } +#ifdef CONFIG_HIBERNATION +/** + * resume_map_numa_kva - add KVA mapping to the temporary page tables created + * during resume from hibernation + * @pgd_base - temporary resume page directory + */ +void resume_map_numa_kva(pgd_t *pgd_base) +{ + int node; + + for_each_online_node(node) { + unsigned long start_va, start_pfn, size, pfn; + + start_va = (unsigned long)node_remap_start_vaddr[node]; + start_pfn = node_remap_start_pfn[node]; + size = node_remap_size[node]; + + printk(KERN_DEBUG "%s: node %d\n", __FUNCTION__, node); + + for (pfn = 0; pfn < size; pfn += PTRS_PER_PTE) { + unsigned long vaddr = start_va + (pfn << PAGE_SHIFT); + pgd_t *pgd = pgd_base + pgd_index(vaddr); + pud_t *pud = pud_offset(pgd, vaddr); + pmd_t *pmd = pmd_offset(pud, vaddr); + + set_pmd(pmd, pfn_pmd(start_pfn + pfn, + PAGE_KERNEL_LARGE_EXEC)); + + printk(KERN_DEBUG "%s: %08lx -> pfn %08lx\n", + __FUNCTION__, vaddr, start_pfn + pfn); + } + } +} +#endif + static unsigned long calculate_numa_remap_pages(void) { int nid; --- linux-2.6.27.orig/arch/x86/mm/pat.c +++ linux-2.6.27/arch/x86/mm/pat.c @@ -403,12 +403,16 @@ return 1; } #else +/* This check is needed to avoid cache aliasing when PAT is enabled */ static inline int range_is_allowed(unsigned long pfn, unsigned long size) { u64 from = ((u64)pfn) << PAGE_SHIFT; u64 to = from + size; u64 cursor = from; + if (!pat_enabled) + return 1; + while (cursor < to) { if (!devmem_is_allowed(pfn)) { printk(KERN_INFO --- linux-2.6.27.orig/arch/x86/mm/fault.c +++ linux-2.6.27/arch/x86/mm/fault.c @@ -534,7 +534,7 @@ happen within a race in page table update. In the later case just flush. */ - pgd = pgd_offset(current->mm ?: &init_mm, address); + pgd = pgd_offset(current->active_mm, address); pgd_ref = pgd_offset_k(address); if (pgd_none(*pgd_ref)) return -1; @@ -607,8 +607,6 @@ si_code = SEGV_MAPERR; - if (notify_page_fault(regs)) - return; if (unlikely(kmmio_fault(regs, address))) return; @@ -638,6 +636,9 @@ if (spurious_fault(address, error_code)) return; + /* kprobes don't want to hook the spurious faults. */ + if (notify_page_fault(regs)) + return; /* * Don't take the mm semaphore here. If we fixup a prefetch * fault we could otherwise deadlock. @@ -645,6 +646,9 @@ goto bad_area_nosemaphore; } + /* kprobes don't want to hook the spurious faults. */ + if (notify_page_fault(regs)) + return; #ifdef CONFIG_X86_32 /* It's safe to allow irq's after cr2 has been saved and the vmalloc --- linux-2.6.27.orig/arch/x86/mm/pageattr.c +++ linux-2.6.27/arch/x86/mm/pageattr.c @@ -582,6 +582,36 @@ return 0; } +static int __cpa_process_fault(struct cpa_data *cpa, unsigned long vaddr, + int primary) +{ + /* + * Ignore all non primary paths. + */ + if (!primary) + return 0; + + /* + * Ignore the NULL PTE for kernel identity mapping, as it is expected + * to have holes. + * Also set numpages to '1' indicating that we processed cpa req for + * one virtual address page and its pfn. TBD: numpages can be set based + * on the initial value and the level returned by lookup_address(). + */ + if (within(vaddr, PAGE_OFFSET, + PAGE_OFFSET + (max_pfn_mapped << PAGE_SHIFT))) { + cpa->numpages = 1; + cpa->pfn = __pa(vaddr) >> PAGE_SHIFT; + return 0; + } else { + WARN(1, KERN_WARNING "CPA: called for zero pte. " + "vaddr = %lx cpa->vaddr = %lx\n", vaddr, + cpa->vaddr); + + return -EINVAL; + } +} + static int __change_page_attr(struct cpa_data *cpa, int primary) { unsigned long address = cpa->vaddr; @@ -592,17 +622,11 @@ repeat: kpte = lookup_address(address, &level); if (!kpte) - return 0; + return __cpa_process_fault(cpa, address, primary); old_pte = *kpte; - if (!pte_val(old_pte)) { - if (!primary) - return 0; - WARN(1, KERN_WARNING "CPA: called for zero pte. " - "vaddr = %lx cpa->vaddr = %lx\n", address, - cpa->vaddr); - return -EINVAL; - } + if (!pte_val(old_pte)) + return __cpa_process_fault(cpa, address, primary); if (level == PG_LEVEL_4K) { pte_t new_pte; @@ -676,12 +700,7 @@ * mapping already: */ if (!(within(cpa->vaddr, PAGE_OFFSET, - PAGE_OFFSET + (max_low_pfn_mapped << PAGE_SHIFT)) -#ifdef CONFIG_X86_64 - || within(cpa->vaddr, PAGE_OFFSET + (1UL<<32), - PAGE_OFFSET + (max_pfn_mapped << PAGE_SHIFT)) -#endif - )) { + PAGE_OFFSET + (max_pfn_mapped << PAGE_SHIFT)))) { alias_cpa = *cpa; alias_cpa.vaddr = (unsigned long) __va(cpa->pfn << PAGE_SHIFT); --- linux-2.6.27.orig/arch/x86/mm/init_32.c +++ linux-2.6.27/arch/x86/mm/init_32.c @@ -718,7 +718,7 @@ after_init_bootmem = 1; } -static void __init find_early_table_space(unsigned long end) +static void __init find_early_table_space(unsigned long end, int use_pse) { unsigned long puds, pmds, ptes, tables, start; @@ -728,7 +728,7 @@ pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; tables += PAGE_ALIGN(pmds * sizeof(pmd_t)); - if (cpu_has_pse) { + if (use_pse) { unsigned long extra; extra = end - ((end>>PMD_SHIFT) << PMD_SHIFT); @@ -768,12 +768,22 @@ pgd_t *pgd_base = swapper_pg_dir; unsigned long start_pfn, end_pfn; unsigned long big_page_start; +#ifdef CONFIG_DEBUG_PAGEALLOC + /* + * For CONFIG_DEBUG_PAGEALLOC, identity mapping will use small pages. + * This will simplify cpa(), which otherwise needs to support splitting + * large pages into small in interrupt context, etc. + */ + int use_pse = 0; +#else + int use_pse = cpu_has_pse; +#endif /* * Find space for the kernel direct mapping tables. */ if (!after_init_bootmem) - find_early_table_space(end); + find_early_table_space(end, use_pse); #ifdef CONFIG_X86_PAE set_nx(); @@ -819,7 +829,7 @@ end_pfn = (end>>PMD_SHIFT) << (PMD_SHIFT - PAGE_SHIFT); if (start_pfn < end_pfn) kernel_physical_mapping_init(pgd_base, start_pfn, end_pfn, - cpu_has_pse); + use_pse); /* tail is not big page alignment ? */ start_pfn = end_pfn; --- linux-2.6.27.orig/arch/x86/mm/ioremap.c +++ linux-2.6.27/arch/x86/mm/ioremap.c @@ -595,7 +595,7 @@ */ offset = phys_addr & ~PAGE_MASK; phys_addr &= PAGE_MASK; - size = PAGE_ALIGN(last_addr) - phys_addr; + size = PAGE_ALIGN(last_addr + 1) - phys_addr; /* * Mappings have to fit in the FIX_BTMAP area. --- linux-2.6.27.orig/arch/x86/lib/usercopy_32.c +++ linux-2.6.27/arch/x86/lib/usercopy_32.c @@ -49,7 +49,7 @@ " jmp 2b\n" \ ".previous\n" \ _ASM_EXTABLE(0b,3b) \ - : "=d"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \ + : "=&d"(res), "=&c"(count), "=&a" (__d0), "=&S" (__d1), \ "=&D" (__d2) \ : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \ : "memory"); \ @@ -211,7 +211,7 @@ " .align 4\n" " .long 0b,2b\n" ".previous" - :"=r" (n), "=D" (s), "=a" (res), "=c" (tmp) + :"=&r" (n), "=&D" (s), "=&a" (res), "=&c" (tmp) :"0" (n), "1" (s), "2" (0), "3" (mask) :"cc"); return res & mask; --- linux-2.6.27.orig/arch/x86/lib/usercopy_64.c +++ linux-2.6.27/arch/x86/lib/usercopy_64.c @@ -32,7 +32,7 @@ " jmp 2b\n" \ ".previous\n" \ _ASM_EXTABLE(0b,3b) \ - : "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \ + : "=&r"(res), "=&c"(count), "=&a" (__d0), "=&S" (__d1), \ "=&D" (__d2) \ : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \ : "memory"); \ @@ -86,7 +86,7 @@ ".previous\n" _ASM_EXTABLE(0b,3b) _ASM_EXTABLE(1b,2b) - : [size8] "=c"(size), [dst] "=&D" (__d0) + : [size8] "=&c"(size), [dst] "=&D" (__d0) : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr), [zero] "r" (0UL), [eight] "r" (8UL)); return size; --- linux-2.6.27.orig/arch/x86/pci/i386.c +++ linux-2.6.27/arch/x86/pci/i386.c @@ -128,7 +128,7 @@ pr = pci_find_parent_resource(dev, r); if (!r->start || !pr || request_resource(pr, r) < 0) { - dev_err(&dev->dev, "BAR %d: can't allocate resource\n", idx); + dev_warn(&dev->dev, "BAR %d: can't allocate resource\n", idx); /* * Something is wrong with the region. * Invalidate the resource to prevent @@ -169,7 +169,7 @@ r->flags, disabled, pass); pr = pci_find_parent_resource(dev, r); if (!pr || request_resource(pr, r) < 0) { - dev_err(&dev->dev, "BAR %d: can't allocate resource\n", idx); + dev_warn(&dev->dev, "BAR %d: can't allocate resource\n", idx); /* We'll assign a new address later */ r->end -= r->start; r->start = 0; --- linux-2.6.27.orig/arch/x86/pci/fixup.c +++ linux-2.6.27/arch/x86/pci/fixup.c @@ -496,18 +496,21 @@ pci_siemens_interrupt_controller); /* - * Regular PCI devices have 256 bytes, but AMD Family 10h Opteron ext config - * have 4096 bytes. Even if the device is capable, that doesn't mean we can - * access it. Maybe we don't have a way to generate extended config space - * accesses. So check it + * Regular PCI devices have 256 bytes, but AMD Family 10h/11h CPUs have + * 4096 bytes configuration space for each function of their processor + * configuration space. */ -static void fam10h_pci_cfg_space_size(struct pci_dev *dev) +static void amd_cpu_pci_cfg_space_size(struct pci_dev *dev) { dev->cfg_size = pci_cfg_space_size_ext(dev); } - -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1200, fam10h_pci_cfg_space_size); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1201, fam10h_pci_cfg_space_size); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1202, fam10h_pci_cfg_space_size); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1203, fam10h_pci_cfg_space_size); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1204, fam10h_pci_cfg_space_size); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1200, amd_cpu_pci_cfg_space_size); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1201, amd_cpu_pci_cfg_space_size); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1202, amd_cpu_pci_cfg_space_size); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1203, amd_cpu_pci_cfg_space_size); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1204, amd_cpu_pci_cfg_space_size); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1300, amd_cpu_pci_cfg_space_size); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1301, amd_cpu_pci_cfg_space_size); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1302, amd_cpu_pci_cfg_space_size); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1303, amd_cpu_pci_cfg_space_size); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1304, amd_cpu_pci_cfg_space_size); --- linux-2.6.27.orig/arch/x86/pci/irq.c +++ linux-2.6.27/arch/x86/pci/irq.c @@ -573,6 +573,7 @@ case PCI_DEVICE_ID_INTEL_ICH7_1: case PCI_DEVICE_ID_INTEL_ICH7_30: case PCI_DEVICE_ID_INTEL_ICH7_31: + case PCI_DEVICE_ID_INTEL_TGP_LPC: case PCI_DEVICE_ID_INTEL_ESB2_0: case PCI_DEVICE_ID_INTEL_ICH8_0: case PCI_DEVICE_ID_INTEL_ICH8_1: --- linux-2.6.27.orig/arch/x86/xen/enlighten.c +++ linux-2.6.27/arch/x86/xen/enlighten.c @@ -1413,7 +1413,7 @@ if (HYPERVISOR_xen_version(XENVER_platform_parameters, &pp) == 0) top = pp.virt_start; - reserve_top_address(-top + 2 * PAGE_SIZE); + reserve_top_address(-top); #endif /* CONFIG_X86_32 */ } --- linux-2.6.27.orig/arch/x86/ia32/ia32entry.S +++ linux-2.6.27/arch/x86/ia32/ia32entry.S @@ -424,9 +424,9 @@ orl $TS_COMPAT,TI_status(%r10) testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) jnz ia32_tracesys -ia32_do_syscall: cmpl $(IA32_NR_syscalls-1),%eax - ja int_ret_from_sys_call /* ia32_tracesys has set RAX(%rsp) */ + ja ia32_badsys +ia32_do_call: IA32_ARG_FIXUP call *ia32_sys_call_table(,%rax,8) # xxx: rip relative ia32_sysret: @@ -441,7 +441,9 @@ call syscall_trace_enter LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ RESTORE_REST - jmp ia32_do_syscall + cmpl $(IA32_NR_syscalls-1),%eax + ja int_ret_from_sys_call /* ia32_tracesys has set RAX(%rsp) */ + jmp ia32_do_call END(ia32_syscall) ia32_badsys: --- linux-2.6.27.orig/arch/x86/power/hibernate_32.c +++ linux-2.6.27/arch/x86/power/hibernate_32.c @@ -12,6 +12,7 @@ #include #include #include +#include /* Defined in hibernate_asm_32.S */ extern int restore_image(void); @@ -127,6 +128,9 @@ } } } + + resume_map_numa_kva(pgd_base); + return 0; } --- linux-2.6.27.orig/arch/x86/kernel/rtc.c +++ linux-2.6.27/arch/x86/kernel/rtc.c @@ -223,11 +223,25 @@ static __init int add_rtc_cmos(void) { #ifdef CONFIG_PNP - if (!pnp_platform_devices) - platform_device_register(&rtc_device); -#else + static const char *ids[] __initconst = + { "PNP0b00", "PNP0b01", "PNP0b02", }; + struct pnp_dev *dev; + struct pnp_id *id; + int i; + + pnp_for_each_dev(dev) { + for (id = dev->id; id; id = id->next) { + for (i = 0; i < ARRAY_SIZE(ids); i++) { + if (compare_pnp_id(id, ids[i]) != 0) + return 0; + } + } + } +#endif + platform_device_register(&rtc_device); -#endif /* CONFIG_PNP */ + dev_info(&rtc_device.dev, + "registered platform RTC device (no PNP device found)\n"); return 0; } device_initcall(add_rtc_cmos); --- linux-2.6.27.orig/arch/x86/kernel/alternative.c +++ linux-2.6.27/arch/x86/kernel/alternative.c @@ -410,6 +410,8 @@ void __init alternative_instructions(void) { + unsigned long flags; + /* The patching is not fully atomic, so try to avoid local interruptions that might execute the to be patched code. Other CPUs are not running. */ @@ -418,7 +420,9 @@ stop_mce(); #endif + local_irq_save(flags); apply_alternatives(__alt_instructions, __alt_instructions_end); + local_irq_restore(flags); /* switch to patch-once-at-boottime-only mode and free the * tables in case we know the number of CPUs will never ever @@ -444,11 +448,13 @@ _text, _etext); /* Only switch to UP mode if we don't immediately boot others */ - if (num_possible_cpus() == 1 || setup_max_cpus <= 1) + if (num_present_cpus() == 1 || setup_max_cpus <= 1) alternatives_smp_switch(0); } #endif + local_irq_save(flags); apply_paravirt(__parainstructions, __parainstructions_end); + local_irq_restore(flags); if (smp_alt_once) free_init_pages("SMP alternatives", --- linux-2.6.27.orig/arch/x86/kernel/early-quirks.c +++ linux-2.6.27/arch/x86/kernel/early-quirks.c @@ -95,6 +95,99 @@ } +#if defined(CONFIG_ACPI) && defined(CONFIG_X86_IO_APIC) +static u32 __init ati_ixp4x0_rev(int num, int slot, int func) +{ + u32 d; + u8 b; + + b = read_pci_config_byte(num, slot, func, 0xac); + b &= ~(1<<5); + write_pci_config_byte(num, slot, func, 0xac, b); + + d = read_pci_config(num, slot, func, 0x70); + d |= 1<<8; + write_pci_config(num, slot, func, 0x70, d); + + d = read_pci_config(num, slot, func, 0x8); + d &= 0xff; + return d; +} + +static void __init ati_bugs(int num, int slot, int func) +{ + u32 d; + u8 b; + + if (acpi_use_timer_override) + return; + + d = ati_ixp4x0_rev(num, slot, func); + if (d < 0x82) + acpi_skip_timer_override = 1; + else { + /* check for IRQ0 interrupt swap */ + outb(0x72, 0xcd6); b = inb(0xcd7); + if (!(b & 0x2)) + acpi_skip_timer_override = 1; + } + + if (acpi_skip_timer_override) { + printk(KERN_INFO "SB4X0 revision 0x%x\n", d); + printk(KERN_INFO "Ignoring ACPI timer override.\n"); + printk(KERN_INFO "If you got timer trouble " + "try acpi_use_timer_override\n"); + } +} + +static u32 __init ati_sbx00_rev(int num, int slot, int func) +{ + u32 old, d; + + d = read_pci_config(num, slot, func, 0x70); + old = d; + d &= ~(1<<8); + write_pci_config(num, slot, func, 0x70, d); + d = read_pci_config(num, slot, func, 0x8); + d &= 0xff; + write_pci_config(num, slot, func, 0x70, old); + + return d; +} + +static void __init ati_bugs_contd(int num, int slot, int func) +{ + u32 d, rev; + + if (acpi_use_timer_override) + return; + + rev = ati_sbx00_rev(num, slot, func); + if (rev > 0x13) + return; + + /* check for IRQ0 interrupt swap */ + d = read_pci_config(num, slot, func, 0x64); + if (!(d & (1<<14))) + acpi_skip_timer_override = 1; + + if (acpi_skip_timer_override) { + printk(KERN_INFO "SB600 revision 0x%x\n", rev); + printk(KERN_INFO "Ignoring ACPI timer override.\n"); + printk(KERN_INFO "If you got timer trouble " + "try acpi_use_timer_override\n"); + } +} +#else +static void __init ati_bugs(int num, int slot, int func) +{ +} + +static void __init ati_bugs_contd(int num, int slot, int func) +{ +} +#endif + #define QFLAG_APPLY_ONCE 0x1 #define QFLAG_APPLIED 0x2 #define QFLAG_DONE (QFLAG_APPLY_ONCE|QFLAG_APPLIED) @@ -114,6 +207,10 @@ PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, via_bugs }, { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB, PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, fix_hypertransport_config }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS, + PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs }, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, + PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs_contd }, {} }; --- linux-2.6.27.orig/arch/x86/kernel/setup.c +++ linux-2.6.27/arch/x86/kernel/setup.c @@ -98,6 +98,7 @@ #include #include +#include #include #include @@ -578,6 +579,39 @@ struct x86_quirks *x86_quirks __initdata = &default_x86_quirks; +static int __init dmi_low_memory_corruption(const struct dmi_system_id *d) +{ + printk(KERN_NOTICE + "%s detected: BIOS may corrupt low RAM, working it around.\n", + d->ident); + + e820_update_range(0, 0x10000, E820_RAM, E820_RESERVED); + sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); + + return 0; +} + +/* List of systems that have known low memory corruption BIOS problems */ +static struct dmi_system_id __initdata bad_bios_dmi_table[] = { +#ifdef CONFIG_X86_RESERVE_LOW_64K + { + .callback = dmi_low_memory_corruption, + .ident = "AMI BIOS", + .matches = { + DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), + }, + }, + { + .callback = dmi_low_memory_corruption, + .ident = "Phoenix BIOS", + .matches = { + DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies"), + }, + }, +#endif + {} +}; + /* * Determine if we were loaded by an EFI loader. If so, then we have also been * passed the efi memmap, systab, etc., so we should use these data structures @@ -601,6 +635,9 @@ printk(KERN_INFO "Command line: %s\n", boot_command_line); #endif + /* VMI may relocate the fixmap; do this before touching ioremap area */ + vmi_init(); + early_cpu_init(); early_ioremap_init(); @@ -674,13 +711,8 @@ check_efer(); #endif -#if defined(CONFIG_VMI) && defined(CONFIG_X86_32) - /* - * Must be before kernel pagetables are setup - * or fixmap area is touched. - */ - vmi_init(); -#endif + /* Must be before kernel pagetables are setup */ + vmi_activate(); /* after early param, so could get panic from serial */ reserve_early_setup_data(); @@ -699,6 +731,10 @@ finish_e820_parsing(); + dmi_scan_machine(); + + dmi_check_system(bad_bios_dmi_table); + #ifdef CONFIG_X86_32 probe_roms(); #endif @@ -781,8 +817,6 @@ vsmp_init(); #endif - dmi_scan_machine(); - io_delay_init(); /* @@ -869,6 +903,12 @@ e820_reserve_resources(); e820_mark_nosave_regions(max_low_pfn); + /* + * VMware detection requires dmi to be available, so this + * needs to be done after dmi_scan_machine, for the BP. + */ + init_hypervisor(&boot_cpu_data); + #ifdef CONFIG_X86_32 request_resource(&iomem_resource, &video_ram_resource); #endif @@ -885,3 +925,5 @@ #endif #endif } + + --- linux-2.6.27.orig/arch/x86/kernel/amd_iommu.c +++ linux-2.6.27/arch/x86/kernel/amd_iommu.c @@ -235,7 +235,7 @@ u64 __pte, *pte, *page; bus_addr = PAGE_ALIGN(bus_addr); - phys_addr = PAGE_ALIGN(bus_addr); + phys_addr = PAGE_ALIGN(phys_addr); /* only support 512GB address spaces for now */ if (bus_addr > IOMMU_MAP_SIZE_L3 || !(prot & IOMMU_PROT_MASK)) @@ -487,7 +487,7 @@ continue; p2 = IOMMU_PTE_PAGE(p1[i]); - for (j = 0; j < 512; ++i) { + for (j = 0; j < 512; ++j) { if (!IOMMU_PTE_PRESENT(p2[j])) continue; p3 = IOMMU_PTE_PAGE(p2[j]); --- linux-2.6.27.orig/arch/x86/kernel/hpet.c +++ linux-2.6.27/arch/x86/kernel/hpet.c @@ -283,7 +283,7 @@ * what we wrote hit the chip before we compare it to the * counter. */ - WARN_ON((u32)hpet_readl(HPET_T0_CMP) != cnt); + WARN_ON_ONCE((u32)hpet_readl(HPET_T0_CMP) != cnt); return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; } --- linux-2.6.27.orig/arch/x86/kernel/io_apic_32.c +++ linux-2.6.27/arch/x86/kernel/io_apic_32.c @@ -2314,6 +2314,9 @@ for (i = first_system_vector; i < NR_VECTORS; i++) set_bit(i, used_vectors); + /* Mark FIRST_DEVICE_VECTOR which is assigned to IRQ0 as used. */ + set_bit(FIRST_DEVICE_VECTOR, used_vectors); + enable_IO_APIC(); io_apic_irqs = ~PIC_IRQS; --- linux-2.6.27.orig/arch/x86/kernel/vmi_32.c +++ linux-2.6.27/arch/x86/kernel/vmi_32.c @@ -430,6 +430,16 @@ } /* + * We use the pgd_free hook for releasing the pgd page: + */ +static void vmi_pgd_free(struct mm_struct *mm, pgd_t *pgd) +{ + unsigned long pfn = __pa(pgd) >> PAGE_SHIFT; + + vmi_ops.release_page(pfn, VMI_PAGE_L2); +} + +/* * Helper macros for MMU update flags. We can defer updates until a flush * or page invalidation only if the update is to the current address space * (otherwise, there is no flush). We must check against init_mm, since @@ -881,6 +891,7 @@ if (vmi_ops.release_page) { pv_mmu_ops.release_pte = vmi_release_pte; pv_mmu_ops.release_pmd = vmi_release_pmd; + pv_mmu_ops.pgd_free = vmi_pgd_free; } /* Set linear is needed in all cases */ @@ -960,8 +971,6 @@ void __init vmi_init(void) { - unsigned long flags; - if (!vmi_rom) probe_vmi_rom(); else @@ -973,13 +982,21 @@ reserve_top_address(-vmi_rom->virtual_top); - local_irq_save(flags); - activate_vmi(); - #ifdef CONFIG_X86_IO_APIC /* This is virtual hardware; timer routing is wired correctly */ no_timer_check = 1; #endif +} + +void vmi_activate(void) +{ + unsigned long flags; + + if (!vmi_rom) + return; + + local_irq_save(flags); + activate_vmi(); local_irq_restore(flags & X86_EFLAGS_IF); } --- linux-2.6.27.orig/arch/x86/kernel/apic_32.c +++ linux-2.6.27/arch/x86/kernel/apic_32.c @@ -1115,7 +1115,7 @@ switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: if ((boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model > 1) || - (boot_cpu_data.x86 == 15)) + (boot_cpu_data.x86 >= 15)) break; goto no_apic; case X86_VENDOR_INTEL: --- linux-2.6.27.orig/arch/x86/kernel/amd_iommu_init.c +++ linux-2.6.27/arch/x86/kernel/amd_iommu_init.c @@ -120,7 +120,7 @@ LIST_HEAD(amd_iommu_unity_map); /* a list of required unity mappings we find in ACPI */ unsigned amd_iommu_aperture_order = 26; /* size of aperture in power of 2 */ -int amd_iommu_isolate; /* if 1, device isolation is enabled */ +int amd_iommu_isolate = 1; /* if 1, device isolation is enabled */ LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the system */ @@ -210,7 +210,7 @@ /* Programs the physical address of the device table into the IOMMU hardware */ static void __init iommu_set_device_table(struct amd_iommu *iommu) { - u32 entry; + u64 entry; BUG_ON(iommu->mmio_base == NULL); @@ -407,6 +407,10 @@ memcpy_toio(iommu->mmio_base + MMIO_CMD_BUF_OFFSET, &entry, sizeof(entry)); + /* set head and tail to zero manually */ + writel(0x00, iommu->mmio_base + MMIO_CMD_HEAD_OFFSET); + writel(0x00, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET); + iommu_feature_enable(iommu, CONTROL_CMDBUF_EN); return cmd_buf; @@ -926,7 +930,8 @@ goto free; /* IOMMU rlookup table - find the IOMMU for a specific device */ - amd_iommu_rlookup_table = (void *)__get_free_pages(GFP_KERNEL, + amd_iommu_rlookup_table = (void *)__get_free_pages( + GFP_KERNEL | __GFP_ZERO, get_order(rlookup_table_size)); if (amd_iommu_rlookup_table == NULL) goto free; --- linux-2.6.27.orig/arch/x86/kernel/tsc.c +++ linux-2.6.27/arch/x86/kernel/tsc.c @@ -15,6 +15,7 @@ #include #include #include +#include unsigned int cpu_khz; /* TSC clocks / usec, not used here */ EXPORT_SYMBOL(cpu_khz); @@ -31,6 +32,7 @@ erroneous rdtsc usage on !cpu_has_tsc processors */ static int tsc_disabled = -1; +static int tsc_clocksource_reliable; /* * Scheduler clock - returns current time in nanosec units. */ @@ -98,6 +100,15 @@ __setup("notsc", notsc_setup); +static int __init tsc_setup(char *str) +{ + if (!strcmp(str, "reliable")) + tsc_clocksource_reliable = 1; + return 1; +} + +__setup("tsc=", tsc_setup); + #define MAX_RETRIES 5 #define SMI_TRESHOLD 50000 @@ -189,9 +200,15 @@ { u64 tsc1, tsc2, delta, pm1, pm2, hpet1, hpet2; unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX; - unsigned long flags; + unsigned long flags, tsc_khz; int hpet = is_hpet_enabled(), i; + tsc_khz = get_hypervisor_tsc_freq(); + if (tsc_khz) { + printk(KERN_INFO "TSC: Frequency read from the hypervisor\n"); + return tsc_khz; + } + /* * Run 5 calibration loops to get the lowest frequency value * (the best estimate). We use two different calibration modes @@ -557,24 +574,21 @@ {} }; -/* - * Geode_LX - the OLPC CPU has a possibly a very reliable TSC - */ +static void __init check_system_tsc_reliable(void) +{ #ifdef CONFIG_MGEODE_LX -/* RTSC counts during suspend */ + /* RTSC counts during suspend */ #define RTSC_SUSP 0x100 - -static void __init check_geode_tsc_reliable(void) -{ unsigned long res_low, res_high; rdmsr_safe(MSR_GEODE_BUSCONT_CONF0, &res_low, &res_high); + /* Geode_LX - the OLPC CPU has a possibly a very reliable TSC */ if (res_low & RTSC_SUSP) - clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY; -} -#else -static inline void check_geode_tsc_reliable(void) { } + tsc_clocksource_reliable = 1; #endif + if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) + tsc_clocksource_reliable = 1; +} /* * Make an educated guess if the TSC is trustworthy and synchronized @@ -609,6 +623,8 @@ { clocksource_tsc.mult = clocksource_khz2mult(tsc_khz, clocksource_tsc.shift); + if (tsc_clocksource_reliable) + clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY; /* lower the rating if we already know its unstable: */ if (check_tsc_unstable()) { clocksource_tsc.rating = 0; @@ -639,10 +655,6 @@ cpu_khz = calibrate_cpu(); #endif - lpj = ((u64)tsc_khz * 1000); - do_div(lpj, HZ); - lpj_fine = lpj; - printk("Detected %lu.%03lu MHz processor.\n", (unsigned long)cpu_khz / 1000, (unsigned long)cpu_khz % 1000); @@ -662,6 +674,10 @@ /* now allow native_sched_clock() to use rdtsc */ tsc_disabled = 0; + lpj = ((u64)tsc_khz * 1000); + do_div(lpj, HZ); + lpj_fine = lpj; + use_tsc_delay(); /* Check and install the TSC clocksource */ dmi_check_system(bad_tsc_dmi_table); @@ -669,7 +685,7 @@ if (unsynchronized_tsc()) mark_tsc_unstable("TSCs unsynchronized"); - check_geode_tsc_reliable(); + check_system_tsc_reliable(); init_tsc_clocksource(); } --- linux-2.6.27.orig/arch/x86/kernel/tlb_uv.c +++ linux-2.6.27/arch/x86/kernel/tlb_uv.c @@ -586,7 +586,6 @@ static struct bau_control * __init uv_table_bases_init(int blade, int node) { int i; - int *ip; struct bau_msg_status *msp; struct bau_control *bau_tabp; @@ -603,13 +602,6 @@ bau_cpubits_clear(&msp->seen_by, (int) uv_blade_nr_possible_cpus(blade)); - bau_tabp->watching = - kmalloc_node(sizeof(int) * DEST_NUM_RESOURCES, GFP_KERNEL, node); - BUG_ON(!bau_tabp->watching); - - for (i = 0, ip = bau_tabp->watching; i < DEST_Q_SIZE; i++, ip++) - *ip = 0; - uv_bau_table_bases[blade] = bau_tabp; return bau_tabp; @@ -632,7 +624,6 @@ bcp->bau_msg_head = bau_tablesp->va_queue_first; bcp->va_queue_first = bau_tablesp->va_queue_first; bcp->va_queue_last = bau_tablesp->va_queue_last; - bcp->watching = bau_tablesp->watching; bcp->msg_statuses = bau_tablesp->msg_statuses; bcp->descriptor_base = adp; } --- linux-2.6.27.orig/arch/x86/kernel/head64.c +++ linux-2.6.27/arch/x86/kernel/head64.c @@ -26,7 +26,7 @@ #include /* boot cpu pda */ -static struct x8664_pda _boot_cpu_pda __read_mostly; +static struct x8664_pda _boot_cpu_pda; #ifdef CONFIG_SMP /* @@ -108,11 +108,11 @@ } load_idt((const struct desc_ptr *)&idt_descr); - early_printk("Kernel alive\n"); + //early_printk("Kernel alive\n"); x86_64_init_pda(); - early_printk("Kernel really alive\n"); + //early_printk("Kernel really alive\n"); x86_64_start_reservations(real_mode_data); } --- linux-2.6.27.orig/arch/x86/kernel/reboot.c +++ linux-2.6.27/arch/x86/kernel/reboot.c @@ -169,6 +169,15 @@ DMI_MATCH(DMI_BOARD_NAME, "0KW626"), }, }, + { /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */ + .callback = set_bios_reboot, + .ident = "Dell OptiPlex 330", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"), + DMI_MATCH(DMI_BOARD_NAME, "0KP561"), + }, + }, { /* Handle problems with rebooting on Dell 2400's */ .callback = set_bios_reboot, .ident = "Dell PowerEdge 2400", @@ -185,6 +194,15 @@ DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"), }, }, + { /* Handle problems with rebooting on Dell Dimension 9200 */ + .callback = set_bios_reboot, + .ident = "Dell Dimension 9200", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"), + DMI_MATCH(DMI_BOARD_NAME, "0CT017"), + }, + }, { /* Handle problems with rebooting on HP laptops */ .callback = set_bios_reboot, .ident = "HP Compaq Laptop", --- linux-2.6.27.orig/arch/x86/kernel/smpboot.c +++ linux-2.6.27/arch/x86/kernel/smpboot.c @@ -289,9 +289,7 @@ * fragile that we want to limit the things done here to the * most necessary things. */ -#ifdef CONFIG_VMI vmi_bringup(); -#endif cpu_init(); preempt_disable(); smp_callin(); --- linux-2.6.27.orig/arch/x86/kernel/ptrace.c +++ linux-2.6.27/arch/x86/kernel/ptrace.c @@ -1403,7 +1403,7 @@ #ifdef CONFIG_X86_32 # define IS_IA32 1 #elif defined CONFIG_IA32_EMULATION -# define IS_IA32 test_thread_flag(TIF_IA32) +# define IS_IA32 is_compat_task() #else # define IS_IA32 0 #endif --- linux-2.6.27.orig/arch/x86/kernel/syscall_table_32.S +++ linux-2.6.27/arch/x86/kernel/syscall_table_32.S @@ -88,7 +88,7 @@ .long sys_uselib .long sys_swapon .long sys_reboot - .long old_readdir + .long sys_old_readdir .long old_mmap /* 90 */ .long sys_munmap .long sys_truncate --- linux-2.6.27.orig/arch/x86/kernel/process_64.c +++ linux-2.6.27/arch/x86/kernel/process_64.c @@ -729,12 +729,12 @@ if (!p || p == current || p->state==TASK_RUNNING) return 0; stack = (unsigned long)task_stack_page(p); - if (p->thread.sp < stack || p->thread.sp > stack+THREAD_SIZE) + if (p->thread.sp < stack || p->thread.sp >= stack+THREAD_SIZE) return 0; fp = *(u64 *)(p->thread.sp); do { if (fp < (unsigned long)stack || - fp > (unsigned long)stack+THREAD_SIZE) + fp >= (unsigned long)stack+THREAD_SIZE) return 0; ip = *(u64 *)(fp+8); if (!in_sched_functions(ip)) --- linux-2.6.27.orig/arch/x86/kernel/tsc_sync.c +++ linux-2.6.27/arch/x86/kernel/tsc_sync.c @@ -108,6 +108,12 @@ if (unsynchronized_tsc()) return; + if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) { + printk(KERN_INFO + "Skipping synchronization checks as TSC is reliable.\n"); + return; + } + printk(KERN_INFO "checking TSC synchronization [CPU#%d -> CPU#%d]:", smp_processor_id(), cpu); @@ -161,7 +167,7 @@ { int cpus = 2; - if (unsynchronized_tsc()) + if (unsynchronized_tsc() || boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) return; /* --- linux-2.6.27.orig/arch/x86/kernel/head_64.S +++ linux-2.6.27/arch/x86/kernel/head_64.S @@ -305,7 +305,7 @@ call dump_stack #ifdef CONFIG_KALLSYMS leaq early_idt_ripmsg(%rip),%rdi - movq 8(%rsp),%rsi # get rip again + movq 0(%rsp),%rsi # get rip again call __print_symbol #endif #endif /* EARLY_PRINTK */ --- linux-2.6.27.orig/arch/x86/kernel/acpi/cstate.c +++ linux-2.6.27/arch/x86/kernel/acpi/cstate.c @@ -56,6 +56,7 @@ static short mwait_supported[ACPI_PROCESSOR_MAX_POWER]; #define MWAIT_SUBSTATE_MASK (0xf) +#define MWAIT_CSTATE_MASK (0xf) #define MWAIT_SUBSTATE_SIZE (4) #define CPUID_MWAIT_LEAF (5) @@ -98,7 +99,8 @@ cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx); /* Check whether this particular cx_type (in CST) is supported or not */ - cstate_type = (cx->address >> MWAIT_SUBSTATE_SIZE) + 1; + cstate_type = ((cx->address >> MWAIT_SUBSTATE_SIZE) & + MWAIT_CSTATE_MASK) + 1; edx_part = edx >> (cstate_type * MWAIT_SUBSTATE_SIZE); num_cstate_subtype = edx_part & MWAIT_SUBSTATE_MASK; --- linux-2.6.27.orig/arch/x86/kernel/acpi/boot.c +++ linux-2.6.27/arch/x86/kernel/acpi/boot.c @@ -1593,6 +1593,11 @@ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), }, }, + {} +}; + +/* second table for DMI checks that should run after early-quirks */ +static struct dmi_system_id __initdata acpi_dmi_table_late[] = { /* * HP laptops which use a DSDT reporting as HP/SB400/10000, * which includes some code which overrides all temperature @@ -1721,6 +1726,9 @@ int __init acpi_boot_init(void) { + /* those are executed after early-quirks are executed */ + dmi_check_system(acpi_dmi_table_late); + /* * If acpi_disabled, bail out * One exception: acpi=ht continues far enough to enumerate LAPICs --- linux-2.6.27.orig/arch/x86/kernel/acpi/sleep.c +++ linux-2.6.27/arch/x86/kernel/acpi/sleep.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "realmode/wakeup.h" #include "sleep.h" @@ -98,6 +99,8 @@ header->trampoline_segment = setup_trampoline() >> 4; #ifdef CONFIG_SMP stack_start.sp = temp_stack + 4096; + early_gdt_descr.address = + (unsigned long)get_cpu_gdt_table(smp_processor_id()); #endif initial_code = (unsigned long)wakeup_long64; saved_magic = 0x123456789abcdef0; --- linux-2.6.27.orig/arch/x86/kernel/cpu/hypervisor.c +++ linux-2.6.27/arch/x86/kernel/cpu/hypervisor.c @@ -0,0 +1,57 @@ +/* + * Common hypervisor code + * + * Copyright (C) 2008, VMware, Inc. + * Author : Alok N Kataria + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include + +static inline void __cpuinit +detect_hypervisor_vendor(struct cpuinfo_x86 *c) +{ + if (vmware_platform()) { + c->x86_hyper_vendor = X86_HYPER_VENDOR_VMWARE; + } else { + c->x86_hyper_vendor = X86_HYPER_VENDOR_NONE; + } +} + +unsigned long get_hypervisor_tsc_freq(void) +{ + if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) + return vmware_get_tsc_khz(); + return 0; +} + +static inline void __cpuinit +hypervisor_set_feature_bits(struct cpuinfo_x86 *c) +{ + if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) { + vmware_set_feature_bits(c); + return; + } +} + +void __cpuinit init_hypervisor(struct cpuinfo_x86 *c) +{ + detect_hypervisor_vendor(c); + hypervisor_set_feature_bits(c); +} --- linux-2.6.27.orig/arch/x86/kernel/cpu/common_64.c +++ linux-2.6.27/arch/x86/kernel/cpu/common_64.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "cpu.h" @@ -384,6 +385,7 @@ detect_ht(c); + init_hypervisor(c); /* * On SMP, boot_cpu_data holds the common feature set between * all CPUs; so make sure that we indicate which features are --- linux-2.6.27.orig/arch/x86/kernel/cpu/vmware.c +++ linux-2.6.27/arch/x86/kernel/cpu/vmware.c @@ -0,0 +1,111 @@ +/* + * VMware Detection code. + * + * Copyright (C) 2008, VMware, Inc. + * Author : Alok N Kataria + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include + +#define CPUID_VMWARE_INFO_LEAF 0x40000000 +#define VMWARE_HYPERVISOR_MAGIC 0x564D5868 +#define VMWARE_HYPERVISOR_PORT 0x5658 + +#define VMWARE_PORT_CMD_GETVERSION 10 +#define VMWARE_PORT_CMD_GETHZ 45 + +#define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \ + __asm__("inl (%%dx)" : \ + "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \ + "0"(VMWARE_HYPERVISOR_MAGIC), \ + "1"(VMWARE_PORT_CMD_##cmd), \ + "2"(VMWARE_HYPERVISOR_PORT), "3"(UINT_MAX) : \ + "memory"); + +static inline int __vmware_platform(void) +{ + uint32_t eax, ebx, ecx, edx; + VMWARE_PORT(GETVERSION, eax, ebx, ecx, edx); + return eax != (uint32_t)-1 && ebx == VMWARE_HYPERVISOR_MAGIC; +} + +static unsigned long __vmware_get_tsc_khz(void) +{ + uint64_t tsc_hz; + uint32_t eax, ebx, ecx, edx; + + VMWARE_PORT(GETHZ, eax, ebx, ecx, edx); + + if (ebx == UINT_MAX) + return 0; + tsc_hz = eax | (((uint64_t)ebx) << 32); + do_div(tsc_hz, 1000); + BUG_ON(tsc_hz >> 32); + return tsc_hz; +} + +/* + * While checking the dmi string infomation, just checking the product + * serial key should be enough, as this will always have a VMware + * specific string when running under VMware hypervisor. + */ +int vmware_platform(void) +{ + if (cpu_has_hypervisor) { + unsigned int eax, ebx, ecx, edx; + char hyper_vendor_id[13]; + + cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &ebx, &ecx, &edx); + memcpy(hyper_vendor_id + 0, &ebx, 4); + memcpy(hyper_vendor_id + 4, &ecx, 4); + memcpy(hyper_vendor_id + 8, &edx, 4); + hyper_vendor_id[12] = '\0'; + if (!strcmp(hyper_vendor_id, "VMwareVMware")) + return 1; + } else if (dmi_available && dmi_name_in_serial("VMware") && + __vmware_platform()) + return 1; + + return 0; +} + +unsigned long vmware_get_tsc_khz(void) +{ + BUG_ON(!vmware_platform()); + return __vmware_get_tsc_khz(); +} + +/* + * VMware hypervisor takes care of exporting a reliable TSC to the guest. + * Still, due to timing difference when running on virtual cpus, the TSC can + * be marked as unstable in some cases. For example, the TSC sync check at + * bootup can fail due to a marginal offset between vcpus' TSCs (though the + * TSCs do not drift from each other). Also, the ACPI PM timer clocksource + * is not suitable as a watchdog when running on a hypervisor because the + * kernel may miss a wrap of the counter if the vcpu is descheduled for a + * long time. To skip these checks at runtime we set these capability bits, + * so that the kernel could just trust the hypervisor with providing a + * reliable virtual TSC that is suitable for timekeeping. + */ +void __cpuinit vmware_set_feature_bits(struct cpuinfo_x86 *c) +{ + set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); + set_cpu_cap(c, X86_FEATURE_TSC_RELIABLE); +} --- linux-2.6.27.orig/arch/x86/kernel/cpu/Makefile +++ linux-2.6.27/arch/x86/kernel/cpu/Makefile @@ -4,6 +4,7 @@ obj-y := intel_cacheinfo.o addon_cpuid_features.o obj-y += proc.o feature_names.o +obj-y += vmware.o hypervisor.o obj-$(CONFIG_X86_32) += common.o bugs.o obj-$(CONFIG_X86_64) += common_64.o bugs_64.o --- linux-2.6.27.orig/arch/x86/kernel/cpu/common.c +++ linux-2.6.27/arch/x86/kernel/cpu/common.c @@ -14,6 +14,7 @@ #include #include #include +#include #ifdef CONFIG_X86_LOCAL_APIC #include #include @@ -505,6 +506,7 @@ c->x86, c->x86_model); } + init_hypervisor(c); /* * On SMP, boot_cpu_data holds the common feature set between * all CPUs; so make sure that we indicate which features are --- linux-2.6.27.orig/arch/x86/kernel/cpu/cpufreq/powernow-k8.h +++ linux-2.6.27/arch/x86/kernel/cpu/cpufreq/powernow-k8.h @@ -5,6 +5,19 @@ * http://www.gnu.org/licenses/gpl.html */ + +enum pstate { + HW_PSTATE_INVALID = 0xff, + HW_PSTATE_0 = 0, + HW_PSTATE_1 = 1, + HW_PSTATE_2 = 2, + HW_PSTATE_3 = 3, + HW_PSTATE_4 = 4, + HW_PSTATE_5 = 5, + HW_PSTATE_6 = 6, + HW_PSTATE_7 = 7, +}; + struct powernow_k8_data { unsigned int cpu; @@ -23,7 +36,9 @@ u32 exttype; /* extended interface = 1 */ /* keep track of the current fid / vid or pstate */ - u32 currvid, currfid, currpstate; + u32 currvid; + u32 currfid; + enum pstate currpstate; /* the powernow_table includes all frequency and vid/fid pairings: * fid are the lower 8 bits of the index, vid are the upper 8 bits. --- linux-2.6.27.orig/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c +++ linux-2.6.27/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c @@ -45,6 +45,7 @@ CPU_DOTHAN_A1, CPU_DOTHAN_A2, CPU_DOTHAN_B0, + CPU_DOTHAN_C0, CPU_MP4HT_D0, CPU_MP4HT_E0, }; @@ -54,6 +55,7 @@ [CPU_DOTHAN_A1] = { 6, 13, 1 }, [CPU_DOTHAN_A2] = { 6, 13, 2 }, [CPU_DOTHAN_B0] = { 6, 13, 6 }, + [CPU_DOTHAN_C0] = { 6, 13, 8 }, [CPU_MP4HT_D0] = {15, 3, 4 }, [CPU_MP4HT_E0] = {15, 4, 1 }, }; @@ -196,6 +198,88 @@ }; #undef OP + +#define OPEX(mhz, base, mva, mvb, mvc, mvd) \ +{ \ + .frequency = (mhz) * 1000, \ + .index = (((mhz)/(base)) << 8) | ((mva - 700) / 16) \ +} + +/* Intel Pentium M processor 730 / 1.60 GHz (Sonoma) */ +static struct cpufreq_frequency_table sonoma_1596[] = +{ + OPEX( 798, 133, 988, 988, 988, 988), + OPEX(1064, 133, 1116, 1111, 1084, 1079), + OPEX(1330, 133, 1244, 1233, 1180, 1169), + OPEX(1596, 133, 1356, 1356, 1260, 1260), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Intel Pentium M processor 740 / 1.73 GHz (Sonoma) */ +static struct cpufreq_frequency_table sonoma_1729[] = +{ + OPEX( 798, 133, 988, 988, 988, 988), + OPEX(1064, 133, 1100, 1093, 1068, 1066), + OPEX(1330, 133, 1212, 1198, 1148, 1143), + OPEX(1729, 133, 1356, 1356, 1260, 1260), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Intel Pentium M processor 750 / 1.86 GHz (Sonoma) */ +static struct cpufreq_frequency_table sonoma_1862[] = +{ + OPEX( 798, 133, 988, 988, 988, 988), + OPEX(1064, 133, 1084, 1080, 1068, 1056), + OPEX(1330, 133, 1180, 1172, 1132, 1124), + OPEX(1596, 133, 1276, 1264, 1196, 1192), + OPEX(1862, 133, 1356, 1356, 1260, 1260), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Intel Pentium M processor 760 / 2.00 GHz (Sonoma) */ +static struct cpufreq_frequency_table sonoma_1995[] = +{ + OPEX( 798, 133, 988, 988, 988, 988), + OPEX(1064, 133, 1084, 1070, 1052, 1048), + OPEX(1330, 133, 1164, 1152, 1116, 1109), + OPEX(1596, 133, 1244, 1233, 1180, 1169), + OPEX(1995, 133, 1356, 1356, 1260, 1260), + { .frequency = CPUFREQ_TABLE_END } +}; +/* Intel Pentium M processor 770 / 2.13 GHz (Sonoma) */ +static struct cpufreq_frequency_table sonoma_2128[] = +{ + OPEX( 798, 133, 988, 988, 988, 988), + OPEX(1064, 133, 1068, 1065, 1052, 1042), + OPEX(1330, 133, 1148, 1142, 1100, 1097), + OPEX(1596, 133, 1228, 1218, 1164, 1151), + OPEX(1862, 133, 1308, 1295, 1212, 1206), + OPEX(2128, 133, 1372, 1372, 1260, 1260), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Intel Pentium M processor 780 / 2.26 GHz (Sonoma) */ +static struct cpufreq_frequency_table sonoma_2261[] = +{ + OPEX( 798, 133, 988, 988, 988, 988), + OPEX(1064, 133, 1068, 1064, 1052, 1037), + OPEX(1330, 133, 1148, 1139, 1100, 1087), + OPEX(1596, 133, 1228, 1215, 1148, 1136), + OPEX(1862, 133, 1292, 1291, 1196, 1186), + OPEX(2261, 133, 1404, 1404, 1260, 1260), + { .frequency = CPUFREQ_TABLE_END } +}; + +#undef OPEX + +#define SONOMA(cpuid, max, base, name) \ +{ .cpu_id = cpuid, \ + .model_name = "Intel(R) Pentium(R) M processor " name "GHz", \ + .max_freq = (max)*1000, \ + .op_points = sonoma_##max, \ +} + + #define _BANIAS(cpuid, max, name) \ { .cpu_id = cpuid, \ .model_name = "Intel(R) Pentium(R) M processor " name "MHz", \ @@ -218,6 +302,15 @@ BANIAS(1600), BANIAS(1700), + /* Builtin tables for Dothan C0 CPUs, a.k.a Sonoma */ + SONOMA(&cpu_ids[CPU_DOTHAN_C0], 1596, 133, "1.60"), + SONOMA(&cpu_ids[CPU_DOTHAN_C0], 1729, 133, "1.73"), + SONOMA(&cpu_ids[CPU_DOTHAN_C0], 1862, 133, "1.86"), + SONOMA(&cpu_ids[CPU_DOTHAN_C0], 1995, 133, "2.00"), + SONOMA(&cpu_ids[CPU_DOTHAN_C0], 2128, 133, "2.13"), + SONOMA(&cpu_ids[CPU_DOTHAN_C0], 2261, 133, "2.26"), + + /* NULL model_name is a wildcard */ { &cpu_ids[CPU_DOTHAN_A1], NULL, 0, NULL }, { &cpu_ids[CPU_DOTHAN_A2], NULL, 0, NULL }, --- linux-2.6.27.orig/arch/x86/kernel/cpu/cpufreq/powernow-k8.c +++ linux-2.6.27/arch/x86/kernel/cpu/cpufreq/powernow-k8.c @@ -116,9 +116,20 @@ u32 i = 0; if (cpu_family == CPU_HW_PSTATE) { - rdmsr(MSR_PSTATE_STATUS, lo, hi); - i = lo & HW_PSTATE_MASK; - data->currpstate = i; + if (data->currpstate == HW_PSTATE_INVALID) { + /* read (initial) hw pstate if not yet set */ + rdmsr(MSR_PSTATE_STATUS, lo, hi); + i = lo & HW_PSTATE_MASK; + + /* + * a workaround for family 11h erratum 311 might cause + * an "out-of-range Pstate if the core is in Pstate-0 + */ + if (i >= data->numps) + data->currpstate = HW_PSTATE_0; + else + data->currpstate = i; + } return 0; } do { @@ -1117,6 +1128,7 @@ } data->cpu = pol->cpu; + data->currpstate = HW_PSTATE_INVALID; if (powernow_k8_cpu_init_acpi(data)) { /* --- linux-2.6.27.orig/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c +++ linux-2.6.27/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c @@ -779,6 +779,9 @@ { int ret; + if (acpi_disabled) + return 0; + dprintk("acpi_cpufreq_init\n"); ret = acpi_cpufreq_early_init(); --- linux-2.6.27.orig/arch/x86/kernel/cpu/mtrr/generic.c +++ linux-2.6.27/arch/x86/kernel/cpu/mtrr/generic.c @@ -45,6 +45,33 @@ static int mtrr_show; module_param_named(show, mtrr_show, bool, 0); +/** + * BIOS is expected to clear MtrrFixDramModEn bit, see for example + * "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD + * Opteron Processors" (26094 Rev. 3.30 February 2006), section + * "13.2.1.2 SYSCFG Register": "The MtrrFixDramModEn bit should be set + * to 1 during BIOS initalization of the fixed MTRRs, then cleared to + * 0 for operation." + */ +#define FW_WARN "[Firmware Warn]: " +static inline void k8_check_syscfg_dram_mod_en(void) +{ + u32 lo, hi; + + if (!((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && + (boot_cpu_data.x86 >= 0x0f))) + return; + + rdmsr(MSR_K8_SYSCFG, lo, hi); + if (lo & K8_MTRRFIXRANGE_DRAM_MODIFY) { + printk(KERN_ERR FW_WARN "MTRR: CPU %u: SYSCFG[MtrrFixDramModEn]" + " not cleared by BIOS, clearing this bit\n", + smp_processor_id()); + lo &= ~K8_MTRRFIXRANGE_DRAM_MODIFY; + mtrr_wrmsr(MSR_K8_SYSCFG, lo, hi); + } +} + /* * Returns the effective MTRR type for the region * Error returns: @@ -178,6 +205,8 @@ unsigned int *p = (unsigned int *) frs; int i; + k8_check_syscfg_dram_mod_en(); + rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]); for (i = 0; i < 2; i++) @@ -312,27 +341,10 @@ } /** - * Enable and allow read/write of extended fixed-range MTRR bits on K8 CPUs - * see AMD publication no. 24593, chapter 3.2.1 for more information - */ -static inline void k8_enable_fixed_iorrs(void) -{ - unsigned lo, hi; - - rdmsr(MSR_K8_SYSCFG, lo, hi); - mtrr_wrmsr(MSR_K8_SYSCFG, lo - | K8_MTRRFIXRANGE_DRAM_ENABLE - | K8_MTRRFIXRANGE_DRAM_MODIFY, hi); -} - -/** * set_fixed_range - checks & updates a fixed-range MTRR if it differs from the value it should have * @msr: MSR address of the MTTR which should be checked and updated * @changed: pointer which indicates whether the MTRR needed to be changed * @msrwords: pointer to the MSR values which the MSR should have - * - * If K8 extentions are wanted, update the K8 SYSCFG MSR also. - * See AMD publication no. 24593, chapter 7.8.1, page 233 for more information. */ static void set_fixed_range(int msr, bool *changed, unsigned int *msrwords) { @@ -341,10 +353,6 @@ rdmsr(msr, lo, hi); if (lo != msrwords[0] || hi != msrwords[1]) { - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && - (boot_cpu_data.x86 >= 0x0f && boot_cpu_data.x86 <= 0x11) && - ((msrwords[0] | msrwords[1]) & K8_MTRR_RDMEM_WRMEM_MASK)) - k8_enable_fixed_iorrs(); mtrr_wrmsr(msr, msrwords[0], msrwords[1]); *changed = true; } @@ -428,6 +436,8 @@ bool changed = false; int block=-1, range; + k8_check_syscfg_dram_mod_en(); + while (fixed_range_blocks[++block].ranges) for (range=0; range < fixed_range_blocks[block].ranges; range++) set_fixed_range(fixed_range_blocks[block].base_msr + range, --- linux-2.6.27.orig/arch/m68k/kernel/entry.S +++ linux-2.6.27/arch/m68k/kernel/entry.S @@ -513,7 +513,7 @@ .long sys_uselib .long sys_swapon .long sys_reboot - .long old_readdir + .long sys_old_readdir .long old_mmap /* 90 */ .long sys_munmap .long sys_truncate --- linux-2.6.27.orig/arch/m68k/kernel/ints.c +++ linux-2.6.27/arch/m68k/kernel/ints.c @@ -133,7 +133,7 @@ { int i; - BUG_ON(IRQ_USER + cnt >= NR_IRQS); + BUG_ON(IRQ_USER + cnt > NR_IRQS); m68k_first_user_vec = vec; for (i = 0; i < cnt; i++) irq_controller[IRQ_USER + i] = &user_irq_controller; --- linux-2.6.27.orig/arch/m68knommu/Kconfig +++ linux-2.6.27/arch/m68knommu/Kconfig @@ -14,6 +14,10 @@ bool default n +config NO_DMA + bool + default y + config FPU bool default n --- linux-2.6.27.orig/arch/m68knommu/kernel/syscalltable.S +++ linux-2.6.27/arch/m68knommu/kernel/syscalltable.S @@ -107,7 +107,7 @@ .long sys_uselib .long sys_ni_syscall /* sys_swapon */ .long sys_reboot - .long old_readdir + .long sys_old_readdir .long old_mmap /* 90 */ .long sys_munmap .long sys_truncate --- linux-2.6.27.orig/arch/powerpc/Kconfig +++ linux-2.6.27/arch/powerpc/Kconfig @@ -122,6 +122,7 @@ select HAVE_DMA_ATTRS if PPC64 select USE_GENERIC_SMP_HELPERS if SMP select HAVE_OPROFILE + select HAVE_SYSCALL_WRAPPERS if PPC64 config EARLY_PRINTK bool --- linux-2.6.27.orig/arch/powerpc/mm/pgtable_32.c +++ linux-2.6.27/arch/powerpc/mm/pgtable_32.c @@ -65,8 +65,8 @@ #ifdef HAVE_TLBCAM extern unsigned int tlbcam_index; -extern unsigned long v_mapped_by_tlbcam(unsigned long va); -extern unsigned long p_mapped_by_tlbcam(unsigned long pa); +extern phys_addr_t v_mapped_by_tlbcam(unsigned long va); +extern unsigned long p_mapped_by_tlbcam(phys_addr_t pa); #else /* !HAVE_TLBCAM */ #define v_mapped_by_tlbcam(x) (0UL) #define p_mapped_by_tlbcam(x) (0UL) --- linux-2.6.27.orig/arch/powerpc/mm/slice.c +++ linux-2.6.27/arch/powerpc/mm/slice.c @@ -710,9 +710,18 @@ unsigned long len) { struct slice_mask mask, available; + unsigned int psize = mm->context.user_psize; mask = slice_range_to_mask(addr, len); - available = slice_mask_for_size(mm, mm->context.user_psize); + available = slice_mask_for_size(mm, psize); +#ifdef CONFIG_PPC_64K_PAGES + /* We need to account for 4k slices too */ + if (psize == MMU_PAGE_64K) { + struct slice_mask compat_mask; + compat_mask = slice_mask_for_size(mm, MMU_PAGE_4K); + or_mask(available, compat_mask); + } +#endif #if 0 /* too verbose */ slice_dbg("is_hugepage_only_range(mm=%p, addr=%lx, len=%lx)\n", --- linux-2.6.27.orig/arch/powerpc/mm/hash_utils_64.c +++ linux-2.6.27/arch/powerpc/mm/hash_utils_64.c @@ -381,8 +381,10 @@ printk(KERN_INFO "Huge page(16GB) memory: " "addr = 0x%lX size = 0x%lX pages = %d\n", phys_addr, block_size, expected_pages); - lmb_reserve(phys_addr, block_size * expected_pages); - add_gpage(phys_addr, block_size, expected_pages); + if (phys_addr + (16 * GB) <= lmb_end_of_DRAM()) { + lmb_reserve(phys_addr, block_size * expected_pages); + add_gpage(phys_addr, block_size, expected_pages); + } return 0; } --- linux-2.6.27.orig/arch/powerpc/mm/fsl_booke_mmu.c +++ linux-2.6.27/arch/powerpc/mm/fsl_booke_mmu.c @@ -80,7 +80,7 @@ /* * Return PA for this VA if it is mapped by a CAM, or 0 */ -unsigned long v_mapped_by_tlbcam(unsigned long va) +phys_addr_t v_mapped_by_tlbcam(unsigned long va) { int b; for (b = 0; b < tlbcam_index; ++b) @@ -92,7 +92,7 @@ /* * Return VA for a given PA or 0 if not mapped */ -unsigned long p_mapped_by_tlbcam(unsigned long pa) +unsigned long p_mapped_by_tlbcam(phys_addr_t pa) { int b; for (b = 0; b < tlbcam_index; ++b) --- linux-2.6.27.orig/arch/powerpc/mm/numa.c +++ linux-2.6.27/arch/powerpc/mm/numa.c @@ -89,6 +89,48 @@ return 0; } +/* + * get_active_region_work_fn - A helper function for get_node_active_region + * Returns datax set to the start_pfn and end_pfn if they contain + * the initial value of datax->start_pfn between them + * @start_pfn: start page(inclusive) of region to check + * @end_pfn: end page(exclusive) of region to check + * @datax: comes in with ->start_pfn set to value to search for and + * goes out with active range if it contains it + * Returns 1 if search value is in range else 0 + */ +static int __init get_active_region_work_fn(unsigned long start_pfn, + unsigned long end_pfn, void *datax) +{ + struct node_active_region *data; + data = (struct node_active_region *)datax; + + if (start_pfn <= data->start_pfn && end_pfn > data->start_pfn) { + data->start_pfn = start_pfn; + data->end_pfn = end_pfn; + return 1; + } + return 0; + +} + +/* + * get_node_active_region - Return active region containing start_pfn + * Active range returned is empty if none found. + * @start_pfn: The page to return the region for. + * @node_ar: Returned set to the active region containing start_pfn + */ +static void __init get_node_active_region(unsigned long start_pfn, + struct node_active_region *node_ar) +{ + int nid = early_pfn_to_nid(start_pfn); + + node_ar->nid = nid; + node_ar->start_pfn = start_pfn; + node_ar->end_pfn = start_pfn; + work_with_active_regions(nid, get_active_region_work_fn, node_ar); +} + static void __cpuinit map_cpu_to_node(int cpu, int node) { numa_cpu_lookup_table[cpu] = node; @@ -837,38 +879,53 @@ start_pfn, end_pfn); free_bootmem_with_active_regions(nid, end_pfn); + } - /* Mark reserved regions on this node */ - for (i = 0; i < lmb.reserved.cnt; i++) { - unsigned long physbase = lmb.reserved.region[i].base; - unsigned long size = lmb.reserved.region[i].size; - unsigned long start_paddr = start_pfn << PAGE_SHIFT; - unsigned long end_paddr = end_pfn << PAGE_SHIFT; - - if (early_pfn_to_nid(physbase >> PAGE_SHIFT) != nid && - early_pfn_to_nid((physbase+size-1) >> PAGE_SHIFT) != nid) - continue; - - if (physbase < end_paddr && - (physbase+size) > start_paddr) { - /* overlaps */ - if (physbase < start_paddr) { - size -= start_paddr - physbase; - physbase = start_paddr; - } - - if (size > end_paddr - physbase) - size = end_paddr - physbase; - - dbg("reserve_bootmem %lx %lx\n", physbase, - size); - reserve_bootmem_node(NODE_DATA(nid), physbase, - size, BOOTMEM_DEFAULT); - } + /* Mark reserved regions */ + for (i = 0; i < lmb.reserved.cnt; i++) { + unsigned long physbase = lmb.reserved.region[i].base; + unsigned long size = lmb.reserved.region[i].size; + unsigned long start_pfn = physbase >> PAGE_SHIFT; + unsigned long end_pfn = ((physbase + size) >> PAGE_SHIFT); + struct node_active_region node_ar; + + get_node_active_region(start_pfn, &node_ar); + while (start_pfn < end_pfn && + node_ar.start_pfn < node_ar.end_pfn) { + unsigned long reserve_size = size; + /* + * if reserved region extends past active region + * then trim size to active region + */ + if (end_pfn > node_ar.end_pfn) + reserve_size = (node_ar.end_pfn << PAGE_SHIFT) + - (start_pfn << PAGE_SHIFT); + dbg("reserve_bootmem %lx %lx nid=%d\n", physbase, + reserve_size, node_ar.nid); + reserve_bootmem_node(NODE_DATA(node_ar.nid), physbase, + reserve_size, BOOTMEM_DEFAULT); + /* + * if reserved region is contained in the active region + * then done. + */ + if (end_pfn <= node_ar.end_pfn) + break; + + /* + * reserved region extends past the active region + * get next active region that contains this + * reserved region + */ + start_pfn = node_ar.end_pfn; + physbase = start_pfn << PAGE_SHIFT; + size = size - reserve_size; + get_node_active_region(start_pfn, &node_ar); } - sparse_memory_present_with_active_regions(nid); } + + for_each_online_node(nid) + sparse_memory_present_with_active_regions(nid); } void __init paging_init(void) --- linux-2.6.27.orig/arch/powerpc/lib/rheap.c +++ linux-2.6.27/arch/powerpc/lib/rheap.c @@ -556,6 +556,7 @@ be = blk->start + blk->size; if (s >= bs && e <= be) break; + blk = NULL; } if (blk == NULL) --- linux-2.6.27.orig/arch/powerpc/include/asm/systbl.h +++ linux-2.6.27/arch/powerpc/include/asm/systbl.h @@ -92,7 +92,7 @@ SYSCALL(uselib) SYSCALL(swapon) SYSCALL(reboot) -SYSX(sys_ni_syscall,compat_sys_old_readdir,old_readdir) +SYSX(sys_ni_syscall,compat_sys_old_readdir,sys_old_readdir) SYSCALL_SPU(mmap) SYSCALL_SPU(munmap) SYSCALL_SPU(truncate) --- linux-2.6.27.orig/arch/powerpc/include/asm/compat.h +++ linux-2.6.27/arch/powerpc/include/asm/compat.h @@ -210,5 +210,10 @@ compat_ulong_t __unused6; }; +static inline int is_compat_task(void) +{ + return test_thread_flag(TIF_32BIT); +} + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_COMPAT_H */ --- linux-2.6.27.orig/arch/powerpc/include/asm/seccomp.h +++ linux-2.6.27/arch/powerpc/include/asm/seccomp.h @@ -1,10 +1,6 @@ #ifndef _ASM_POWERPC_SECCOMP_H #define _ASM_POWERPC_SECCOMP_H -#ifdef __KERNEL__ -#include -#endif - #include #define __NR_seccomp_read __NR_read --- linux-2.6.27.orig/arch/powerpc/include/asm/mpic.h +++ linux-2.6.27/arch/powerpc/include/asm/mpic.h @@ -355,6 +355,8 @@ #define MPIC_NO_BIAS 0x00000400 /* Ignore NIRQS as reported by FRR */ #define MPIC_BROKEN_FRR_NIRQS 0x00000800 +/* Destination only supports a single CPU at a time */ +#define MPIC_SINGLE_DEST_CPU 0x00001000 /* MPIC HW modification ID */ #define MPIC_REGSET_MASK 0xf0000000 --- linux-2.6.27.orig/arch/powerpc/sysdev/mpic.c +++ linux-2.6.27/arch/powerpc/sysdev/mpic.c @@ -563,6 +563,51 @@ #endif /* CONFIG_MPIC_U3_HT_IRQS */ +#ifdef CONFIG_SMP +static int irq_choose_cpu(unsigned int virt_irq) +{ + cpumask_t mask = irq_desc[virt_irq].affinity; + int cpuid; + + if (cpus_equal(mask, CPU_MASK_ALL)) { + static int irq_rover; + static DEFINE_SPINLOCK(irq_rover_lock); + unsigned long flags; + + /* Round-robin distribution... */ + do_round_robin: + spin_lock_irqsave(&irq_rover_lock, flags); + + while (!cpu_online(irq_rover)) { + if (++irq_rover >= NR_CPUS) + irq_rover = 0; + } + cpuid = irq_rover; + do { + if (++irq_rover >= NR_CPUS) + irq_rover = 0; + } while (!cpu_online(irq_rover)); + + spin_unlock_irqrestore(&irq_rover_lock, flags); + } else { + cpumask_t tmp; + + cpus_and(tmp, cpu_online_map, mask); + + if (cpus_empty(tmp)) + goto do_round_robin; + + cpuid = first_cpu(tmp); + } + + return cpuid; +} +#else +static int irq_choose_cpu(unsigned int virt_irq) +{ + return hard_smp_processor_id(); +} +#endif #define mpic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) @@ -777,12 +822,18 @@ struct mpic *mpic = mpic_from_irq(irq); unsigned int src = mpic_irq_to_hw(irq); - cpumask_t tmp; + if (mpic->flags & MPIC_SINGLE_DEST_CPU) { + int cpuid = irq_choose_cpu(irq); - cpus_and(tmp, cpumask, cpu_online_map); + mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); + } else { + cpumask_t tmp; - mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), - mpic_physmask(cpus_addr(tmp)[0])); + cpus_and(tmp, cpumask, cpu_online_map); + + mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), + mpic_physmask(cpus_addr(tmp)[0])); + } } static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type) @@ -1220,6 +1271,7 @@ void __init mpic_init(struct mpic *mpic) { int i; + int cpu; BUG_ON(mpic->num_sources == 0); @@ -1262,6 +1314,11 @@ mpic_pasemi_msi_init(mpic); + if (mpic->flags & MPIC_PRIMARY) + cpu = hard_smp_processor_id(); + else + cpu = 0; + for (i = 0; i < mpic->num_sources; i++) { /* start with vector = source number, and masked */ u32 vecpri = MPIC_VECPRI_MASK | i | @@ -1272,8 +1329,7 @@ continue; /* init hw */ mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); - mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), - 1 << hard_smp_processor_id()); + mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu); } /* Init spurious vector */ --- linux-2.6.27.orig/arch/powerpc/configs/linkstation_defconfig +++ linux-2.6.27/arch/powerpc/configs/linkstation_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.27-rc4 -# Thu Aug 21 00:52:05 2008 +# Linux kernel version: 2.6.27 +# Fri Oct 24 00:42:39 2008 # # CONFIG_PPC64 is not set @@ -934,7 +934,7 @@ CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_SERIAL_JSM is not set -CONFIG_SERIAL_OF_PLATFORM=y +# CONFIG_SERIAL_OF_PLATFORM is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -1211,7 +1211,6 @@ # CONFIG_USB_STORAGE_ALAUDA is not set # CONFIG_USB_STORAGE_ONETOUCH is not set # CONFIG_USB_STORAGE_KARMA is not set -# CONFIG_USB_STORAGE_SIERRA is not set # CONFIG_USB_STORAGE_CYPRESS_ATACB is not set # CONFIG_USB_LIBUSUAL is not set --- linux-2.6.27.orig/arch/powerpc/platforms/pseries/smp.c +++ linux-2.6.27/arch/powerpc/platforms/pseries/smp.c @@ -52,8 +52,8 @@ /* - * The primary thread of each non-boot processor is recorded here before - * smp init. + * The Primary thread of each non-boot processor was started from the OF client + * interface by prom_hold_cpus and is spinning on secondary_hold_spinloop. */ static cpumask_t of_spin_map; @@ -191,8 +191,7 @@ static int smp_pSeries_cpu_bootable(unsigned int nr) { /* Special case - we inhibit secondary thread startup - * during boot if the user requests it. Odd-numbered - * cpus are assumed to be secondary threads. + * during boot if the user requests it. */ if (system_state < SYSTEM_RUNNING && cpu_has_feature(CPU_FTR_SMT) && @@ -229,11 +228,7 @@ /* Mark threads which are still spinning in hold loops. */ if (cpu_has_feature(CPU_FTR_SMT)) { for_each_present_cpu(i) { - if (i % 2 == 0) - /* - * Even-numbered logical cpus correspond to - * primary threads. - */ + if (cpu_thread_in_core(i) == 0) cpu_set(i, of_spin_map); } } else { --- linux-2.6.27.orig/arch/powerpc/platforms/pseries/Kconfig +++ linux-2.6.27/arch/powerpc/platforms/pseries/Kconfig @@ -54,7 +54,7 @@ config CMM tristate "Collaborative memory management" - depends on PPC_SMLPAR + depends on PPC_SMLPAR && !CRASH_DUMP default y help Select this option, if you want to enable the kernel interface --- linux-2.6.27.orig/arch/powerpc/platforms/86xx/pic.c +++ linux-2.6.27/arch/powerpc/platforms/86xx/pic.c @@ -44,7 +44,8 @@ mpic = mpic_alloc(np, res.start, MPIC_PRIMARY | MPIC_WANTS_RESET | - MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, + MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | + MPIC_SINGLE_DEST_CPU, 0, 256, " MPIC "); of_node_put(np); BUG_ON(mpic == NULL); --- linux-2.6.27.orig/arch/powerpc/platforms/cell/smp.c +++ linux-2.6.27/arch/powerpc/platforms/cell/smp.c @@ -54,8 +54,8 @@ #endif /* - * The primary thread of each non-boot processor is recorded here before - * smp init. + * The Primary thread of each non-boot processor was started from the OF client + * interface by prom_hold_cpus and is spinning on secondary_hold_spinloop. */ static cpumask_t of_spin_map; @@ -208,11 +208,7 @@ /* Mark threads which are still spinning in hold loops. */ if (cpu_has_feature(CPU_FTR_SMT)) { for_each_present_cpu(i) { - if (i % 2 == 0) - /* - * Even-numbered logical cpus correspond to - * primary threads. - */ + if (cpu_thread_in_core(i) == 0) cpu_set(i, of_spin_map); } } else { --- linux-2.6.27.orig/arch/powerpc/platforms/cell/spufs/file.c +++ linux-2.6.27/arch/powerpc/platforms/cell/spufs/file.c @@ -390,6 +390,9 @@ if (offset >= ps_size) return VM_FAULT_SIGBUS; + if (fatal_signal_pending(current)) + return VM_FAULT_SIGBUS; + /* * Because we release the mmap_sem, the context may be destroyed while * we're in spu_wait. Grab an extra reference so it isn't destroyed --- linux-2.6.27.orig/arch/powerpc/platforms/cell/spufs/inode.c +++ linux-2.6.27/arch/powerpc/platforms/cell/spufs/inode.c @@ -496,6 +496,8 @@ ret = spufs_context_open(dget(dentry), mntget(mnt)); if (ret < 0) { WARN_ON(spufs_rmdir(inode, dentry)); + if (affinity) + mutex_unlock(&gang->aff_mutex); mutex_unlock(&inode->i_mutex); spu_forget(SPUFS_I(dentry->d_inode)->i_ctx); goto out; --- linux-2.6.27.orig/arch/powerpc/platforms/embedded6xx/linkstation.c +++ linux-2.6.27/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -54,6 +55,19 @@ }, }; +static __initdata struct of_device_id of_bus_ids[] = { + { .type = "soc", }, + { .compatible = "simple-bus", }, + {}, +}; + +static int __init declare_of_platform_devices(void) +{ + of_platform_bus_probe(NULL, of_bus_ids, NULL); + return 0; +} +machine_device_initcall(linkstation, declare_of_platform_devices); + static int __init linkstation_add_bridge(struct device_node *dev) { #ifdef CONFIG_PCI --- linux-2.6.27.orig/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ linux-2.6.27/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -78,7 +78,8 @@ mpic = mpic_alloc(np, r.start, MPIC_PRIMARY | MPIC_WANTS_RESET | - MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, + MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | + MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); of_node_put(np); --- linux-2.6.27.orig/arch/powerpc/kernel/signal_32.c +++ linux-2.6.27/arch/powerpc/kernel/signal_32.c @@ -410,7 +410,7 @@ * altivec/spe instructions at some point. */ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, - int sigret) + int sigret, int ctx_has_vsx_region) { unsigned long msr = regs->msr; @@ -451,7 +451,7 @@ * the saved MSR value to indicate that frame->mc_vregs * contains valid data */ - if (current->thread.used_vsr) { + if (current->thread.used_vsr && ctx_has_vsx_region) { __giveup_vsx(current); if (copy_vsx_to_user(&frame->mc_vsregs, current)) return 1; @@ -858,11 +858,11 @@ frame = &rt_sf->uc.uc_mcontext; addr = frame; if (vdso32_rt_sigtramp && current->mm->context.vdso_base) { - if (save_user_regs(regs, frame, 0)) + if (save_user_regs(regs, frame, 0, 1)) goto badframe; regs->link = current->mm->context.vdso_base + vdso32_rt_sigtramp; } else { - if (save_user_regs(regs, frame, __NR_rt_sigreturn)) + if (save_user_regs(regs, frame, __NR_rt_sigreturn, 1)) goto badframe; regs->link = (unsigned long) frame->tramp; } @@ -936,12 +936,13 @@ int ctx_size, int r6, int r7, int r8, struct pt_regs *regs) { unsigned char tmp; + int ctx_has_vsx_region = 0; #ifdef CONFIG_PPC64 unsigned long new_msr = 0; if (new_ctx && - __get_user(new_msr, &new_ctx->uc_mcontext.mc_gregs[PT_MSR])) + get_user(new_msr, &new_ctx->uc_mcontext.mc_gregs[PT_MSR])) return -EFAULT; /* * Check that the context is not smaller than the original @@ -956,16 +957,9 @@ if ((ctx_size < sizeof(struct ucontext)) && (new_msr & MSR_VSX)) return -EINVAL; -#ifdef CONFIG_VSX - /* - * If userspace doesn't provide enough room for VSX data, - * but current thread has used VSX, we don't have anywhere - * to store the full context back into. - */ - if ((ctx_size < sizeof(struct ucontext)) && - (current->thread.used_vsr && old_ctx)) - return -EINVAL; -#endif + /* Does the context have enough room to store VSX data? */ + if (ctx_size >= sizeof(struct ucontext)) + ctx_has_vsx_region = 1; #else /* Context size is for future use. Right now, we only make sure * we are passed something we understand @@ -985,17 +979,17 @@ */ mctx = (struct mcontext __user *) ((unsigned long) &old_ctx->uc_mcontext & ~0xfUL); - if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx)) - || save_user_regs(regs, mctx, 0) + if (!access_ok(VERIFY_WRITE, old_ctx, ctx_size) + || save_user_regs(regs, mctx, 0, ctx_has_vsx_region) || put_sigset_t(&old_ctx->uc_sigmask, ¤t->blocked) || __put_user(to_user_ptr(mctx), &old_ctx->uc_regs)) return -EFAULT; } if (new_ctx == NULL) return 0; - if (!access_ok(VERIFY_READ, new_ctx, sizeof(*new_ctx)) + if (!access_ok(VERIFY_READ, new_ctx, ctx_size) || __get_user(tmp, (u8 __user *) new_ctx) - || __get_user(tmp, (u8 __user *) (new_ctx + 1) - 1)) + || __get_user(tmp, (u8 __user *) new_ctx + ctx_size - 1)) return -EFAULT; /* @@ -1196,11 +1190,11 @@ goto badframe; if (vdso32_sigtramp && current->mm->context.vdso_base) { - if (save_user_regs(regs, &frame->mctx, 0)) + if (save_user_regs(regs, &frame->mctx, 0, 1)) goto badframe; regs->link = current->mm->context.vdso_base + vdso32_sigtramp; } else { - if (save_user_regs(regs, &frame->mctx, __NR_sigreturn)) + if (save_user_regs(regs, &frame->mctx, __NR_sigreturn, 1)) goto badframe; regs->link = (unsigned long) frame->mctx.tramp; } --- linux-2.6.27.orig/arch/powerpc/kernel/cputable.c +++ linux-2.6.27/arch/powerpc/kernel/cputable.c @@ -39,6 +39,7 @@ extern void __setup_cpu_440gx(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_440grx(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_440spe(unsigned long offset, struct cpu_spec* spec); +extern void __setup_cpu_440x5(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_460ex(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_460gt(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_603(unsigned long offset, struct cpu_spec* spec); @@ -1463,6 +1464,8 @@ .cpu_user_features = COMMON_USER_BOOKE, .icache_bsize = 32, .dcache_bsize = 32, + .cpu_setup = __setup_cpu_440x5, + .machine_check = machine_check_440A, .platform = "ppc440", }, { /* 460EX */ --- linux-2.6.27.orig/arch/powerpc/kernel/signal_64.c +++ linux-2.6.27/arch/powerpc/kernel/signal_64.c @@ -74,7 +74,8 @@ */ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, - int signr, sigset_t *set, unsigned long handler) + int signr, sigset_t *set, unsigned long handler, + int ctx_has_vsx_region) { /* When CONFIG_ALTIVEC is set, we _always_ setup v_regs even if the * process never used altivec yet (MSR_VEC is zero in pt_regs of @@ -121,7 +122,7 @@ * then out to userspace. Update v_regs to point after the * VMX data. */ - if (current->thread.used_vsr) { + if (current->thread.used_vsr && ctx_has_vsx_region) { __giveup_vsx(current); v_regs += ELF_NVRREG; err |= copy_vsx_to_user(v_regs, current); @@ -284,9 +285,10 @@ unsigned char tmp; sigset_t set; unsigned long new_msr = 0; + int ctx_has_vsx_region = 0; if (new_ctx && - __get_user(new_msr, &new_ctx->uc_mcontext.gp_regs[PT_MSR])) + get_user(new_msr, &new_ctx->uc_mcontext.gp_regs[PT_MSR])) return -EFAULT; /* * Check that the context is not smaller than the original @@ -301,28 +303,23 @@ if ((ctx_size < sizeof(struct ucontext)) && (new_msr & MSR_VSX)) return -EINVAL; -#ifdef CONFIG_VSX - /* - * If userspace doesn't provide enough room for VSX data, - * but current thread has used VSX, we don't have anywhere - * to store the full context back into. - */ - if ((ctx_size < sizeof(struct ucontext)) && - (current->thread.used_vsr && old_ctx)) - return -EINVAL; -#endif + /* Does the context have enough room to store VSX data? */ + if (ctx_size >= sizeof(struct ucontext)) + ctx_has_vsx_region = 1; + if (old_ctx != NULL) { - if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx)) - || setup_sigcontext(&old_ctx->uc_mcontext, regs, 0, NULL, 0) + if (!access_ok(VERIFY_WRITE, old_ctx, ctx_size) + || setup_sigcontext(&old_ctx->uc_mcontext, regs, 0, NULL, 0, + ctx_has_vsx_region) || __copy_to_user(&old_ctx->uc_sigmask, ¤t->blocked, sizeof(sigset_t))) return -EFAULT; } if (new_ctx == NULL) return 0; - if (!access_ok(VERIFY_READ, new_ctx, sizeof(*new_ctx)) + if (!access_ok(VERIFY_READ, new_ctx, ctx_size) || __get_user(tmp, (u8 __user *) new_ctx) - || __get_user(tmp, (u8 __user *) (new_ctx + 1) - 1)) + || __get_user(tmp, (u8 __user *) new_ctx + ctx_size - 1)) return -EFAULT; /* @@ -425,7 +422,7 @@ &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, signr, NULL, - (unsigned long)ka->sa.sa_handler); + (unsigned long)ka->sa.sa_handler, 1); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); if (err) goto badframe; --- linux-2.6.27.orig/arch/powerpc/kernel/cpu_setup_44x.S +++ linux-2.6.27/arch/powerpc/kernel/cpu_setup_44x.S @@ -35,6 +35,7 @@ _GLOBAL(__setup_cpu_460ex) _GLOBAL(__setup_cpu_460gt) b __init_fpu_44x +_GLOBAL(__setup_cpu_440x5) _GLOBAL(__setup_cpu_440gx) _GLOBAL(__setup_cpu_440spe) b __fixup_440A_mcheck --- linux-2.6.27.orig/mm/mempolicy.c +++ linux-2.6.27/mm/mempolicy.c @@ -1059,10 +1059,9 @@ return copy_to_user(mask, nodes_addr(*nodes), copy) ? -EFAULT : 0; } -asmlinkage long sys_mbind(unsigned long start, unsigned long len, - unsigned long mode, - unsigned long __user *nmask, unsigned long maxnode, - unsigned flags) +SYSCALL_DEFINE6(mbind, unsigned long, start, unsigned long, len, + unsigned long, mode, unsigned long __user *, nmask, + unsigned long, maxnode, unsigned, flags) { nodemask_t nodes; int err; @@ -1082,8 +1081,8 @@ } /* Set the process memory policy */ -asmlinkage long sys_set_mempolicy(int mode, unsigned long __user *nmask, - unsigned long maxnode) +SYSCALL_DEFINE3(set_mempolicy, int, mode, unsigned long __user *, nmask, + unsigned long, maxnode) { int err; nodemask_t nodes; @@ -1101,9 +1100,9 @@ return do_set_mempolicy(mode, flags, &nodes); } -asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode, - const unsigned long __user *old_nodes, - const unsigned long __user *new_nodes) +SYSCALL_DEFINE4(migrate_pages, pid_t, pid, unsigned long, maxnode, + const unsigned long __user *, old_nodes, + const unsigned long __user *, new_nodes) { struct mm_struct *mm; struct task_struct *task; @@ -1171,10 +1170,9 @@ /* Retrieve NUMA policy */ -asmlinkage long sys_get_mempolicy(int __user *policy, - unsigned long __user *nmask, - unsigned long maxnode, - unsigned long addr, unsigned long flags) +SYSCALL_DEFINE5(get_mempolicy, int __user *, policy, + unsigned long __user *, nmask, unsigned long, maxnode, + unsigned long, addr, unsigned long, flags) { int err; int uninitialized_var(pval); --- linux-2.6.27.orig/mm/filemap.c +++ linux-2.6.27/mm/filemap.c @@ -209,7 +209,7 @@ int ret; struct writeback_control wbc = { .sync_mode = sync_mode, - .nr_to_write = mapping->nrpages * 2, + .nr_to_write = LONG_MAX, .range_start = start, .range_end = end, }; @@ -1304,7 +1304,8 @@ goto out; /* skip atime */ size = i_size_read(inode); if (pos < size) { - retval = filemap_write_and_wait(mapping); + retval = filemap_write_and_wait_range(mapping, pos, + pos + iov_length(iov, nr_segs) - 1); if (!retval) { retval = mapping->a_ops->direct_IO(READ, iocb, iov, pos, nr_segs); @@ -1353,7 +1354,7 @@ return 0; } -asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count) +SYSCALL_DEFINE(readahead)(int fd, loff_t offset, size_t count) { ssize_t ret; struct file *file; @@ -1372,6 +1373,13 @@ } return ret; } +#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS +asmlinkage long SyS_readahead(long fd, loff_t offset, long count) +{ + return SYSC_readahead((int) fd, offset, (size_t) count); +} +SYSCALL_ALIAS(sys_readahead, SyS_readahead); +#endif #ifdef CONFIG_MMU /** @@ -1760,12 +1768,12 @@ } EXPORT_SYMBOL(should_remove_suid); -static int __remove_suid(struct dentry *dentry, int kill) +static int __remove_suid(struct path *path, int kill) { struct iattr newattrs; newattrs.ia_valid = ATTR_FORCE | kill; - return notify_change(dentry, &newattrs); + return notify_change(path->dentry, path->mnt, &newattrs); } int file_remove_suid(struct file *file) @@ -1780,7 +1788,7 @@ if (killpriv) error = security_inode_killpriv(dentry); if (!error && killsuid) - error = __remove_suid(dentry, killsuid); + error = __remove_suid(&file->f_path, killsuid); return error; } @@ -2026,7 +2034,7 @@ struct inode *inode = mapping->host; struct page *page; again: - page = __grab_cache_page(mapping, index); + page = grab_cache_page_write_begin(mapping, index, flags); *pagep = page; if (!page) return -ENOMEM; @@ -2110,18 +2118,10 @@ if (count != ocount) *nr_segs = iov_shorten((struct iovec *)iov, *nr_segs, count); - /* - * Unmap all mmappings of the file up-front. - * - * This will cause any pte dirty bits to be propagated into the - * pageframes for the subsequent filemap_write_and_wait(). - */ write_len = iov_length(iov, *nr_segs); end = (pos + write_len - 1) >> PAGE_CACHE_SHIFT; - if (mapping_mapped(mapping)) - unmap_mapping_range(mapping, pos, write_len, 0); - written = filemap_write_and_wait(mapping); + written = filemap_write_and_wait_range(mapping, pos, pos + write_len - 1); if (written) goto out; @@ -2190,19 +2190,24 @@ * Find or create a page at the given pagecache position. Return the locked * page. This function is specifically for buffered writes. */ -struct page *__grab_cache_page(struct address_space *mapping, pgoff_t index) +struct page *grab_cache_page_write_begin(struct address_space *mapping, + pgoff_t index, unsigned flags) { int status; struct page *page; + gfp_t gfp_notmask = 0; + if (flags & AOP_FLAG_NOFS) + gfp_notmask = __GFP_FS; repeat: page = find_lock_page(mapping, index); if (likely(page)) return page; - page = page_cache_alloc(mapping); + page = __page_cache_alloc(mapping_gfp_mask(mapping) & ~gfp_notmask); if (!page) return NULL; - status = add_to_page_cache_lru(page, mapping, index, GFP_KERNEL); + status = add_to_page_cache_lru(page, mapping, index, + GFP_KERNEL & ~gfp_notmask); if (unlikely(status)) { page_cache_release(page); if (status == -EEXIST) @@ -2211,7 +2216,7 @@ } return page; } -EXPORT_SYMBOL(__grab_cache_page); +EXPORT_SYMBOL(grab_cache_page_write_begin); static ssize_t generic_perform_write_2copy(struct file *file, struct iov_iter *i, loff_t pos) @@ -2256,7 +2261,7 @@ break; } - page = __grab_cache_page(mapping, index); + page = grab_cache_page_write_begin(mapping, index, 0); if (!page) { status = -ENOMEM; break; @@ -2507,7 +2512,8 @@ * the file data here, to try to honour O_DIRECT expectations. */ if (unlikely(file->f_flags & O_DIRECT) && written) - status = filemap_write_and_wait(mapping); + status = filemap_write_and_wait_range(mapping, + pos, pos + written - 1); return written ? written : status; } --- linux-2.6.27.orig/mm/page-writeback.c +++ linux-2.6.27/mm/page-writeback.c @@ -872,9 +872,11 @@ int done = 0; struct pagevec pvec; int nr_pages; + pgoff_t uninitialized_var(writeback_index); pgoff_t index; pgoff_t end; /* Inclusive */ - int scanned = 0; + pgoff_t done_index; + int cycled; int range_whole = 0; if (wbc->nonblocking && bdi_write_congested(bdi)) { @@ -884,82 +886,146 @@ pagevec_init(&pvec, 0); if (wbc->range_cyclic) { - index = mapping->writeback_index; /* Start from prev offset */ + writeback_index = mapping->writeback_index; /* prev offset */ + index = writeback_index; + if (index == 0) + cycled = 1; + else + cycled = 0; end = -1; } else { index = wbc->range_start >> PAGE_CACHE_SHIFT; end = wbc->range_end >> PAGE_CACHE_SHIFT; if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) range_whole = 1; - scanned = 1; + cycled = 1; /* ignore range_cyclic tests */ } retry: - while (!done && (index <= end) && - (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, - PAGECACHE_TAG_DIRTY, - min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) { - unsigned i; + done_index = index; + while (!done && (index <= end)) { + int i; + + nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, + PAGECACHE_TAG_DIRTY, + min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1); + if (nr_pages == 0) + break; - scanned = 1; for (i = 0; i < nr_pages; i++) { struct page *page = pvec.pages[i]; /* - * At this point we hold neither mapping->tree_lock nor - * lock on the page itself: the page may be truncated or - * invalidated (changing page->mapping to NULL), or even - * swizzled back from swapper_space to tmpfs file - * mapping + * At this point, the page may be truncated or + * invalidated (changing page->mapping to NULL), or + * even swizzled back from swapper_space to tmpfs file + * mapping. However, page->index will not change + * because we have a reference on the page. */ + if (page->index > end) { + /* + * can't be range_cyclic (1st pass) because + * end == -1 in that case. + */ + done = 1; + break; + } + + done_index = page->index + 1; + lock_page(page); + /* + * Page truncated or invalidated. We can freely skip it + * then, even for data integrity operations: the page + * has disappeared concurrently, so there could be no + * real expectation of this data interity operation + * even if there is now a new, dirty page at the same + * pagecache address. + */ if (unlikely(page->mapping != mapping)) { +continue_unlock: unlock_page(page); continue; } - if (!wbc->range_cyclic && page->index > end) { - done = 1; - unlock_page(page); - continue; + if (!PageDirty(page)) { + /* someone wrote it for us */ + goto continue_unlock; } - if (wbc->sync_mode != WB_SYNC_NONE) - wait_on_page_writeback(page); - - if (PageWriteback(page) || - !clear_page_dirty_for_io(page)) { - unlock_page(page); - continue; + if (PageWriteback(page)) { + if (wbc->sync_mode != WB_SYNC_NONE) + wait_on_page_writeback(page); + else + goto continue_unlock; } + BUG_ON(PageWriteback(page)); + if (!clear_page_dirty_for_io(page)) + goto continue_unlock; + ret = (*writepage)(page, wbc, data); - if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE)) { - unlock_page(page); - ret = 0; + if (unlikely(ret)) { + if (ret == AOP_WRITEPAGE_ACTIVATE) { + unlock_page(page); + ret = 0; + } else { + /* + * done_index is set past this page, + * so media errors will not choke + * background writeout for the entire + * file. This has consequences for + * range_cyclic semantics (ie. it may + * not be suitable for data integrity + * writeout). + */ + done = 1; + break; + } + } + + if (wbc->nr_to_write > 0) { + wbc->nr_to_write--; + if (wbc->nr_to_write == 0 && + wbc->sync_mode == WB_SYNC_NONE) { + /* + * We stop writing back only if we are + * not doing integrity sync. In case of + * integrity sync we have to keep going + * because someone may be concurrently + * dirtying pages, and we might have + * synced a lot of newly appeared dirty + * pages, but have not synced all of the + * old dirty pages. + */ + done = 1; + break; + } } - if (ret || (--(wbc->nr_to_write) <= 0)) - done = 1; + if (wbc->nonblocking && bdi_write_congested(bdi)) { wbc->encountered_congestion = 1; done = 1; + break; } } pagevec_release(&pvec); cond_resched(); } - if (!scanned && !done) { + if (!cycled && !done) { /* + * range_cyclic: * We hit the last page and there is more work to be done: wrap * back to the start of the file */ - scanned = 1; + cycled = 1; index = 0; + end = writeback_index - 1; goto retry; } if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) - mapping->writeback_index = index; + mapping->writeback_index = done_index; if (wbc->range_cont) wbc->range_start = index << PAGE_CACHE_SHIFT; --- linux-2.6.27.orig/mm/madvise.c +++ linux-2.6.27/mm/madvise.c @@ -281,7 +281,7 @@ * -EBADF - map exists, but area maps something that isn't a file. * -EAGAIN - a kernel resource was temporarily unavailable. */ -asmlinkage long sys_madvise(unsigned long start, size_t len_in, int behavior) +SYSCALL_DEFINE3(madvise, unsigned long, start, size_t, len_in, int, behavior) { unsigned long end, tmp; struct vm_area_struct * vma, *prev; --- linux-2.6.27.orig/mm/fremap.c +++ linux-2.6.27/mm/fremap.c @@ -118,8 +118,8 @@ * and the vma's default protection is used. Arbitrary protections * might be implemented in the future. */ -asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size, - unsigned long prot, unsigned long pgoff, unsigned long flags) +SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, + unsigned long, prot, unsigned long, pgoff, unsigned long, flags) { struct mm_struct *mm = current->mm; struct address_space *mapping; --- linux-2.6.27.orig/mm/mprotect.c +++ linux-2.6.27/mm/mprotect.c @@ -219,8 +219,8 @@ return error; } -asmlinkage long -sys_mprotect(unsigned long start, size_t len, unsigned long prot) +SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len, + unsigned long, prot) { unsigned long vm_flags, nstart, end, tmp, reqprot; struct vm_area_struct *vma, *prev; --- linux-2.6.27.orig/mm/mlock.c +++ linux-2.6.27/mm/mlock.c @@ -130,7 +130,7 @@ return error; } -asmlinkage long sys_mlock(unsigned long start, size_t len) +SYSCALL_DEFINE2(mlock, unsigned long, start, size_t, len) { unsigned long locked; unsigned long lock_limit; @@ -156,7 +156,7 @@ return error; } -asmlinkage long sys_munlock(unsigned long start, size_t len) +SYSCALL_DEFINE2(munlock, unsigned long, start, size_t, len) { int ret; @@ -193,7 +193,7 @@ return 0; } -asmlinkage long sys_mlockall(int flags) +SYSCALL_DEFINE1(mlockall, int, flags) { unsigned long lock_limit; int ret = -EINVAL; @@ -219,7 +219,7 @@ return ret; } -asmlinkage long sys_munlockall(void) +SYSCALL_DEFINE0(munlockall) { int ret; --- linux-2.6.27.orig/mm/hugetlb.c +++ linux-2.6.27/mm/hugetlb.c @@ -353,11 +353,26 @@ return 0; } +static void clear_gigantic_page(struct page *page, + unsigned long addr, unsigned long sz) +{ + int i; + struct page *p = page; + + might_sleep(); + for (i = 0; i < sz/PAGE_SIZE; i++, p = mem_map_next(p, page, i)) { + cond_resched(); + clear_user_highpage(p, addr + i * PAGE_SIZE); + } +} static void clear_huge_page(struct page *page, unsigned long addr, unsigned long sz) { int i; + if (unlikely(sz > MAX_ORDER_NR_PAGES)) + return clear_gigantic_page(page, addr, sz); + might_sleep(); for (i = 0; i < sz/PAGE_SIZE; i++) { cond_resched(); @@ -365,12 +380,32 @@ } } +static void copy_gigantic_page(struct page *dst, struct page *src, + unsigned long addr, struct vm_area_struct *vma) +{ + int i; + struct hstate *h = hstate_vma(vma); + struct page *dst_base = dst; + struct page *src_base = src; + might_sleep(); + for (i = 0; i < pages_per_huge_page(h); ) { + cond_resched(); + copy_user_highpage(dst, src, addr + i*PAGE_SIZE, vma); + + i++; + dst = mem_map_next(dst, dst_base, i); + src = mem_map_next(src, src_base, i); + } +} static void copy_huge_page(struct page *dst, struct page *src, unsigned long addr, struct vm_area_struct *vma) { int i; struct hstate *h = hstate_vma(vma); + if (unlikely(pages_per_huge_page(h) > MAX_ORDER_NR_PAGES)) + return copy_gigantic_page(dst, src, addr, vma); + might_sleep(); for (i = 0; i < pages_per_huge_page(h); i++) { cond_resched(); @@ -455,6 +490,8 @@ { int i; + VM_BUG_ON(h->order >= MAX_ORDER); + h->nr_huge_pages--; h->nr_huge_pages_node[page_to_nid(page)]--; for (i = 0; i < pages_per_huge_page(h); i++) { @@ -969,6 +1006,14 @@ return 1; } +static void prep_compound_huge_page(struct page *page, int order) +{ + if (unlikely(order > (MAX_ORDER - 1))) + prep_compound_gigantic_page(page, order); + else + prep_compound_page(page, order); +} + /* Put bootmem huge pages into the standard lists after mem_map is up */ static void __init gather_bootmem_prealloc(void) { @@ -979,7 +1024,7 @@ struct hstate *h = m->hstate; __ClearPageReserved(page); WARN_ON(page_count(page) != 1); - prep_compound_page(page, h->order); + prep_compound_huge_page(page, h->order); prep_new_huge_page(h, page, page_to_nid(page)); } } @@ -1752,6 +1797,7 @@ struct page *page, unsigned long address) { + struct hstate *h = hstate_vma(vma); struct vm_area_struct *iter_vma; struct address_space *mapping; struct prio_tree_iter iter; @@ -1761,7 +1807,7 @@ * vm_pgoff is in PAGE_SIZE units, hence the different calculation * from page cache lookup which is in HPAGE_SIZE units. */ - address = address & huge_page_mask(hstate_vma(vma)); + address = address & huge_page_mask(h); pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + (vma->vm_pgoff >> PAGE_SHIFT); mapping = (struct address_space *)page_private(page); @@ -1780,7 +1826,7 @@ */ if (!is_vma_resv_set(iter_vma, HPAGE_RESV_OWNER)) unmap_hugepage_range(iter_vma, - address, address + HPAGE_SIZE, + address, address + huge_page_size(h), page); } @@ -2103,7 +2149,7 @@ same_page: if (pages) { get_page(page); - pages[i] = page + pfn_offset; + pages[i] = mem_map_offset(page, pfn_offset); } if (vmas) --- linux-2.6.27.orig/mm/fadvise.c +++ linux-2.6.27/mm/fadvise.c @@ -24,7 +24,7 @@ * POSIX_FADV_WILLNEED could set PG_Referenced, and POSIX_FADV_NOREUSE could * deactivate the pages and clear PG_Referenced. */ -asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) +SYSCALL_DEFINE(fadvise64_64)(int fd, loff_t offset, loff_t len, int advice) { struct file *file = fget(fd); struct address_space *mapping; @@ -126,12 +126,26 @@ fput(file); return ret; } +#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS +asmlinkage long SyS_fadvise64_64(long fd, loff_t offset, loff_t len, long advice) +{ + return SYSC_fadvise64_64((int) fd, offset, len, (int) advice); +} +SYSCALL_ALIAS(sys_fadvise64_64, SyS_fadvise64_64); +#endif #ifdef __ARCH_WANT_SYS_FADVISE64 -asmlinkage long sys_fadvise64(int fd, loff_t offset, size_t len, int advice) +SYSCALL_DEFINE(fadvise64)(int fd, loff_t offset, size_t len, int advice) { return sys_fadvise64_64(fd, offset, len, advice); } +#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS +asmlinkage long SyS_fadvise64(long fd, loff_t offset, long len, long advice) +{ + return SYSC_fadvise64((int) fd, offset, (size_t)len, (int)advice); +} +SYSCALL_ALIAS(sys_fadvise64, SyS_fadvise64); +#endif #endif --- linux-2.6.27.orig/mm/swap.c +++ linux-2.6.27/mm/swap.c @@ -244,7 +244,6 @@ put_cpu(); } -#ifdef CONFIG_NUMA static void lru_add_drain_per_cpu(struct work_struct *dummy) { lru_add_drain(); @@ -258,18 +257,6 @@ return schedule_on_each_cpu(lru_add_drain_per_cpu); } -#else - -/* - * Returns 0 for success - */ -int lru_add_drain_all(void) -{ - lru_add_drain(); - return 0; -} -#endif - /* * Batched page_cache_release(). Decrement the reference count on all the * passed pages. If it fell to zero then remove the page from the LRU and --- linux-2.6.27.orig/mm/rmap.c +++ linux-2.6.27/mm/rmap.c @@ -55,7 +55,33 @@ struct kmem_cache *anon_vma_cachep; -/* This must be called under the mmap_sem. */ +/** + * anon_vma_prepare - attach an anon_vma to a memory region + * @vma: the memory region in question + * + * This makes sure the memory mapping described by 'vma' has + * an 'anon_vma' attached to it, so that we can associate the + * anonymous pages mapped into it with that anon_vma. + * + * The common case will be that we already have one, but if + * if not we either need to find an adjacent mapping that we + * can re-use the anon_vma from (very common when the only + * reason for splitting a vma has been mprotect()), or we + * allocate a new one. + * + * Anon-vma allocations are very subtle, because we may have + * optimistically looked up an anon_vma in page_lock_anon_vma() + * and that may actually touch the spinlock even in the newly + * allocated vma (it depends on RCU to make sure that the + * anon_vma isn't actually destroyed). + * + * As a result, we need to do proper anon_vma locking even + * for the new allocation. At the same time, we do not want + * to do any locking for the common case of already having + * an anon_vma. + * + * This must be called with the mmap_sem held for reading. + */ int anon_vma_prepare(struct vm_area_struct *vma) { struct anon_vma *anon_vma = vma->anon_vma; @@ -63,20 +89,17 @@ might_sleep(); if (unlikely(!anon_vma)) { struct mm_struct *mm = vma->vm_mm; - struct anon_vma *allocated, *locked; + struct anon_vma *allocated; anon_vma = find_mergeable_anon_vma(vma); - if (anon_vma) { - allocated = NULL; - locked = anon_vma; - spin_lock(&locked->lock); - } else { + allocated = NULL; + if (!anon_vma) { anon_vma = anon_vma_alloc(); if (unlikely(!anon_vma)) return -ENOMEM; allocated = anon_vma; - locked = NULL; } + spin_lock(&anon_vma->lock); /* page_table_lock to protect against threads */ spin_lock(&mm->page_table_lock); @@ -87,8 +110,7 @@ } spin_unlock(&mm->page_table_lock); - if (locked) - spin_unlock(&locked->lock); + spin_unlock(&anon_vma->lock); if (unlikely(allocated)) anon_vma_free(allocated); } --- linux-2.6.27.orig/mm/nommu.c +++ linux-2.6.27/mm/nommu.c @@ -355,7 +355,7 @@ * to a regular file. in this case, the unmapping will need * to invoke file system routines that need the global lock. */ -asmlinkage unsigned long sys_brk(unsigned long brk) +SYSCALL_DEFINE1(brk, unsigned long, brk) { struct mm_struct *mm = current->mm; @@ -1170,7 +1170,7 @@ } EXPORT_SYMBOL(do_munmap); -asmlinkage long sys_munmap(unsigned long addr, size_t len) +SYSCALL_DEFINE2(munmap, unsigned long, addr, size_t, len) { int ret; struct mm_struct *mm = current->mm; @@ -1261,9 +1261,9 @@ } EXPORT_SYMBOL(do_mremap); -asmlinkage unsigned long sys_mremap(unsigned long addr, - unsigned long old_len, unsigned long new_len, - unsigned long flags, unsigned long new_addr) +SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, + unsigned long, new_len, unsigned long, flags, + unsigned long, new_addr) { unsigned long ret; --- linux-2.6.27.orig/mm/internal.h +++ linux-2.6.27/mm/internal.h @@ -17,6 +17,7 @@ unsigned long floor, unsigned long ceiling); extern void prep_compound_page(struct page *page, unsigned long order); +extern void prep_compound_gigantic_page(struct page *page, unsigned long order); static inline void set_page_count(struct page *page, int v) { @@ -53,6 +54,34 @@ } /* + * Return the mem_map entry representing the 'offset' subpage within + * the maximally aligned gigantic page 'base'. Handle any discontiguity + * in the mem_map at MAX_ORDER_NR_PAGES boundaries. + */ +static inline struct page *mem_map_offset(struct page *base, int offset) +{ + if (unlikely(offset >= MAX_ORDER_NR_PAGES)) + return pfn_to_page(page_to_pfn(base) + offset); + return base + offset; +} + +/* + * Iterator over all subpages withing the maximally aligned gigantic + * page 'base'. Handle any discontiguity in the mem_map. + */ +static inline struct page *mem_map_next(struct page *iter, + struct page *base, int offset) +{ + if (unlikely((offset & (MAX_ORDER_NR_PAGES - 1)) == 0)) { + unsigned long pfn = page_to_pfn(base) + offset; + if (!pfn_valid(pfn)) + return NULL; + return pfn_to_page(pfn); + } + return iter + 1; +} + +/* * FLATMEM and DISCONTIGMEM configurations use alloc_bootmem_node, * so all functions starting at paging_init should be marked __init * in those cases. SPARSEMEM, however, allows for memory hotplug, --- linux-2.6.27.orig/mm/swapfile.c +++ linux-2.6.27/mm/swapfile.c @@ -286,6 +286,8 @@ swap_list.next = p - swap_info; nr_swap_pages++; p->inuse_pages--; + if (p->notify_swap_entry_free_fn) + p->notify_swap_entry_free_fn(offset); } } return count; @@ -1204,7 +1206,7 @@ } #endif -asmlinkage long sys_swapoff(const char __user * specialfile) +SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) { struct swap_info_struct * p = NULL; unsigned short *swap_map; @@ -1448,7 +1450,7 @@ * * The swapon system call */ -asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags) +SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) { struct swap_info_struct * p; char *name = NULL; @@ -1799,6 +1801,23 @@ } /* + * Sets callback for event when swap_map[offset] == 0 + * i.e. page at this swap offset is not longer used. + * + * type: identifies swap file + * fn: callback function + */ +void set_notify_swap_entry_free(unsigned type, void (*fn) (unsigned long)) +{ + struct swap_info_struct *sis; + sis = get_swap_info_struct(type); + BUG_ON(!sis); + sis->notify_swap_entry_free_fn = fn; + return; +} +EXPORT_SYMBOL(set_notify_swap_entry_free); + +/* * swap_lock prevents swap_map being freed. Don't grab an extra * reference on the swaphandle, it doesn't matter if it becomes unused. */ --- linux-2.6.27.orig/mm/mincore.c +++ linux-2.6.27/mm/mincore.c @@ -177,8 +177,8 @@ * mapped * -EAGAIN - A kernel resource was temporarily unavailable. */ -asmlinkage long sys_mincore(unsigned long start, size_t len, - unsigned char __user * vec) +SYSCALL_DEFINE3(mincore, unsigned long, start, size_t, len, + unsigned char __user *, vec) { long retval; unsigned long pages; --- linux-2.6.27.orig/mm/migrate.c +++ linux-2.6.27/mm/migrate.c @@ -979,10 +979,10 @@ * Move a list of pages in the address space of the currently executing * process. */ -asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages, - const void __user * __user *pages, - const int __user *nodes, - int __user *status, int flags) +SYSCALL_DEFINE6(move_pages, pid_t, pid, unsigned long, nr_pages, + const void __user * __user *, pages, + const int __user *, nodes, + int __user *, status, int, flags) { int err = 0; int i; --- linux-2.6.27.orig/mm/page_isolation.c +++ linux-2.6.27/mm/page_isolation.c @@ -130,10 +130,11 @@ if (page && get_pageblock_migratetype(page) != MIGRATE_ISOLATE) break; } - if (pfn < end_pfn) + page = __first_valid_page(start_pfn, end_pfn - start_pfn); + if ((pfn < end_pfn) || !page) return -EBUSY; /* Check all pages are free or Marked as ISOLATED */ - zone = page_zone(pfn_to_page(pfn)); + zone = page_zone(page); spin_lock_irqsave(&zone->lock, flags); ret = __test_page_isolated_in_pageblock(start_pfn, end_pfn); spin_unlock_irqrestore(&zone->lock, flags); --- linux-2.6.27.orig/mm/mmap.c +++ linux-2.6.27/mm/mmap.c @@ -244,7 +244,7 @@ return next; } -asmlinkage unsigned long sys_brk(unsigned long brk) +SYSCALL_DEFINE1(brk, unsigned long, brk) { unsigned long rlim, retval; unsigned long newbrk, oldbrk; @@ -1927,7 +1927,7 @@ EXPORT_SYMBOL(do_munmap); -asmlinkage long sys_munmap(unsigned long addr, size_t len) +SYSCALL_DEFINE2(munmap, unsigned long, addr, size_t, len) { int ret; struct mm_struct *mm = current->mm; --- linux-2.6.27.orig/mm/page_alloc.c +++ linux-2.6.27/mm/page_alloc.c @@ -268,24 +268,39 @@ { int i; int nr_pages = 1 << order; + + set_compound_page_dtor(page, free_compound_page); + set_compound_order(page, order); + __SetPageHead(page); + for (i = 1; i < nr_pages; i++) { + struct page *p = page + i; + + __SetPageTail(p); + p->first_page = page; + } +} + +#ifdef CONFIG_HUGETLBFS +void prep_compound_gigantic_page(struct page *page, unsigned long order) +{ + int i; + int nr_pages = 1 << order; struct page *p = page + 1; set_compound_page_dtor(page, free_compound_page); set_compound_order(page, order); __SetPageHead(page); - for (i = 1; i < nr_pages; i++, p++) { - if (unlikely((i & (MAX_ORDER_NR_PAGES - 1)) == 0)) - p = pfn_to_page(page_to_pfn(page) + i); + for (i = 1; i < nr_pages; i++, p = mem_map_next(p, page, i)) { __SetPageTail(p); p->first_page = page; } } +#endif static void destroy_compound_page(struct page *page, unsigned long order) { int i; int nr_pages = 1 << order; - struct page *p = page + 1; if (unlikely(compound_order(page) != order)) bad_page(page); @@ -293,9 +308,8 @@ if (unlikely(!PageHead(page))) bad_page(page); __ClearPageHead(page); - for (i = 1; i < nr_pages; i++, p++) { - if (unlikely((i & (MAX_ORDER_NR_PAGES - 1)) == 0)) - p = pfn_to_page(page_to_pfn(page) + i); + for (i = 1; i < nr_pages; i++) { + struct page *p = page + i; if (unlikely(!PageTail(p) | (p->first_page != page))) @@ -4210,7 +4224,7 @@ for_each_zone(zone) { u64 tmp; - spin_lock_irqsave(&zone->lru_lock, flags); + spin_lock_irqsave(&zone->lock, flags); tmp = (u64)pages_min * zone->present_pages; do_div(tmp, lowmem_pages); if (is_highmem(zone)) { @@ -4242,7 +4256,7 @@ zone->pages_low = zone->pages_min + (tmp >> 2); zone->pages_high = zone->pages_min + (tmp >> 1); setup_zone_migrate_reserve(zone); - spin_unlock_irqrestore(&zone->lru_lock, flags); + spin_unlock_irqrestore(&zone->lock, flags); } /* update totalreserve_pages */ --- linux-2.6.27.orig/mm/mremap.c +++ linux-2.6.27/mm/mremap.c @@ -418,9 +418,9 @@ return ret; } -asmlinkage unsigned long sys_mremap(unsigned long addr, - unsigned long old_len, unsigned long new_len, - unsigned long flags, unsigned long new_addr) +SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, + unsigned long, new_len, unsigned long, flags, + unsigned long, new_addr) { unsigned long ret; --- linux-2.6.27.orig/mm/msync.c +++ linux-2.6.27/mm/msync.c @@ -28,7 +28,7 @@ * So by _not_ starting I/O in MS_ASYNC we provide complete flexibility to * applications. */ -asmlinkage long sys_msync(unsigned long start, size_t len, int flags) +SYSCALL_DEFINE3(msync, unsigned long, start, size_t, len, int, flags) { unsigned long end; struct mm_struct *mm = current->mm; --- linux-2.6.27.orig/security/commoncap.c +++ linux-2.6.27/security/commoncap.c @@ -279,10 +279,10 @@ struct vfs_cap_data vcaps; struct inode *inode; - if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID) { - bprm_clear_caps(bprm); + bprm_clear_caps(bprm); + + if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID) return 0; - } dentry = dget(bprm->file->f_dentry); inode = dentry->d_inode; @@ -411,8 +411,9 @@ current->egid != current->gid); } -int cap_inode_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags) +int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, const void *value, size_t size, + int flags, struct file *file) { if (!strcmp(name, XATTR_NAME_CAPS)) { if (!capable(CAP_SETFCAP)) @@ -425,7 +426,8 @@ return 0; } -int cap_inode_removexattr(struct dentry *dentry, const char *name) +int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, struct file *file) { if (!strcmp(name, XATTR_NAME_CAPS)) { if (!capable(CAP_SETFCAP)) --- linux-2.6.27.orig/security/Kconfig +++ linux-2.6.27/security/Kconfig @@ -117,6 +117,7 @@ source security/selinux/Kconfig source security/smack/Kconfig +source security/apparmor/Kconfig endmenu --- linux-2.6.27.orig/security/security.c +++ linux-2.6.27/security/security.c @@ -358,72 +358,81 @@ } EXPORT_SYMBOL(security_inode_init_security); -int security_inode_create(struct inode *dir, struct dentry *dentry, int mode) +int security_inode_create(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode) { if (unlikely(IS_PRIVATE(dir))) return 0; - return security_ops->inode_create(dir, dentry, mode); + return security_ops->inode_create(dir, dentry, mnt, mode); } -int security_inode_link(struct dentry *old_dentry, struct inode *dir, - struct dentry *new_dentry) +int security_inode_link(struct dentry *old_dentry, struct vfsmount *old_mnt, + struct inode *dir, struct dentry *new_dentry, + struct vfsmount *new_mnt) { if (unlikely(IS_PRIVATE(old_dentry->d_inode))) return 0; - return security_ops->inode_link(old_dentry, dir, new_dentry); + return security_ops->inode_link(old_dentry, old_mnt, dir, + new_dentry, new_mnt); } -int security_inode_unlink(struct inode *dir, struct dentry *dentry) +int security_inode_unlink(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt) { if (unlikely(IS_PRIVATE(dentry->d_inode))) return 0; - return security_ops->inode_unlink(dir, dentry); + return security_ops->inode_unlink(dir, dentry, mnt); } int security_inode_symlink(struct inode *dir, struct dentry *dentry, - const char *old_name) + struct vfsmount *mnt, const char *old_name) { if (unlikely(IS_PRIVATE(dir))) return 0; - return security_ops->inode_symlink(dir, dentry, old_name); + return security_ops->inode_symlink(dir, dentry, mnt, old_name); } -int security_inode_mkdir(struct inode *dir, struct dentry *dentry, int mode) +int security_inode_mkdir(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode) { if (unlikely(IS_PRIVATE(dir))) return 0; - return security_ops->inode_mkdir(dir, dentry, mode); + return security_ops->inode_mkdir(dir, dentry, mnt, mode); } -int security_inode_rmdir(struct inode *dir, struct dentry *dentry) +int security_inode_rmdir(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt) { if (unlikely(IS_PRIVATE(dentry->d_inode))) return 0; - return security_ops->inode_rmdir(dir, dentry); + return security_ops->inode_rmdir(dir, dentry, mnt); } -int security_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +int security_inode_mknod(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode, dev_t dev) { if (unlikely(IS_PRIVATE(dir))) return 0; - return security_ops->inode_mknod(dir, dentry, mode, dev); + return security_ops->inode_mknod(dir, dentry, mnt, mode, dev); } +EXPORT_SYMBOL_GPL(security_inode_permission); int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) + struct vfsmount *old_mnt, struct inode *new_dir, + struct dentry *new_dentry, struct vfsmount *new_mnt) { if (unlikely(IS_PRIVATE(old_dentry->d_inode) || (new_dentry->d_inode && IS_PRIVATE(new_dentry->d_inode)))) return 0; - return security_ops->inode_rename(old_dir, old_dentry, - new_dir, new_dentry); + return security_ops->inode_rename(old_dir, old_dentry, old_mnt, + new_dir, new_dentry, new_mnt); } -int security_inode_readlink(struct dentry *dentry) +int security_inode_readlink(struct dentry *dentry, struct vfsmount *mnt) { if (unlikely(IS_PRIVATE(dentry->d_inode))) return 0; - return security_ops->inode_readlink(dentry); + return security_ops->inode_readlink(dentry, mnt); } int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd) @@ -440,11 +449,12 @@ return security_ops->inode_permission(inode, mask); } -int security_inode_setattr(struct dentry *dentry, struct iattr *attr) +int security_inode_setattr(struct dentry *dentry, struct vfsmount *mnt, + struct iattr *attr) { if (unlikely(IS_PRIVATE(dentry->d_inode))) return 0; - return security_ops->inode_setattr(dentry, attr); + return security_ops->inode_setattr(dentry, mnt, attr); } EXPORT_SYMBOL_GPL(security_inode_setattr); @@ -462,41 +472,48 @@ security_ops->inode_delete(inode); } -int security_inode_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags) +int security_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, const void *value, size_t size, + int flags, struct file *file) { if (unlikely(IS_PRIVATE(dentry->d_inode))) return 0; - return security_ops->inode_setxattr(dentry, name, value, size, flags); + return security_ops->inode_setxattr(dentry, mnt, name, value, size, + flags, file); } -void security_inode_post_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags) +void security_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, const void *value, + size_t size, int flags) { if (unlikely(IS_PRIVATE(dentry->d_inode))) return; - security_ops->inode_post_setxattr(dentry, name, value, size, flags); + security_ops->inode_post_setxattr(dentry, mnt, name, value, size, + flags); } -int security_inode_getxattr(struct dentry *dentry, const char *name) +int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, struct file *file) { if (unlikely(IS_PRIVATE(dentry->d_inode))) return 0; - return security_ops->inode_getxattr(dentry, name); + return security_ops->inode_getxattr(dentry, mnt, name, file); } -int security_inode_listxattr(struct dentry *dentry) +int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt, + struct file *file) { if (unlikely(IS_PRIVATE(dentry->d_inode))) return 0; - return security_ops->inode_listxattr(dentry); + return security_ops->inode_listxattr(dentry, mnt, file); } -int security_inode_removexattr(struct dentry *dentry, const char *name) +int security_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, struct file *file) { if (unlikely(IS_PRIVATE(dentry->d_inode))) return 0; - return security_ops->inode_removexattr(dentry, name); + return security_ops->inode_removexattr(dentry, mnt, name, file); } int security_inode_need_killpriv(struct dentry *dentry) @@ -599,6 +616,15 @@ return security_ops->dentry_open(file); } +int security_path_permission(struct path *path, int mask) +{ + struct inode *inode = path->dentry->d_inode; + if (unlikely(IS_PRIVATE(inode))) + return 0; + + return security_ops->path_permission(path, mask); +} + int security_task_create(unsigned long clone_flags) { return security_ops->task_create(clone_flags); --- linux-2.6.27.orig/security/device_cgroup.c +++ linux-2.6.27/security/device_cgroup.c @@ -543,6 +543,9 @@ struct dev_cgroup *dev_cgroup; struct dev_whitelist_item *wh; + if (!S_ISBLK(mode) && !S_ISCHR(mode)) + return 0; + rcu_read_lock(); dev_cgroup = task_devcgroup(current); --- linux-2.6.27.orig/security/Makefile +++ linux-2.6.27/security/Makefile @@ -14,5 +14,6 @@ # Must precede capability.o in order to stack properly. obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o -obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o +obj-$(CONFIG_SECURITY_APPARMOR) += commoncap.o apparmor/ + obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o --- linux-2.6.27.orig/security/capability.c +++ linux-2.6.27/security/capability.c @@ -155,52 +155,56 @@ } static int cap_inode_create(struct inode *inode, struct dentry *dentry, - int mask) + struct vfsmount *mnt, int mask) { return 0; } -static int cap_inode_link(struct dentry *old_dentry, struct inode *inode, - struct dentry *new_dentry) +static int cap_inode_link(struct dentry *old_dentry, struct vfsmount *old_mnt, + struct inode *inode, + struct dentry *new_dentry, struct vfsmount *new_mnt) { return 0; } -static int cap_inode_unlink(struct inode *inode, struct dentry *dentry) +static int cap_inode_unlink(struct inode *inode, struct dentry *dentry, + struct vfsmount *mnt) { return 0; } static int cap_inode_symlink(struct inode *inode, struct dentry *dentry, - const char *name) + struct vfsmount *mnt, const char *name) { return 0; } static int cap_inode_mkdir(struct inode *inode, struct dentry *dentry, - int mask) + struct vfsmount *mnt, int mask) { return 0; } -static int cap_inode_rmdir(struct inode *inode, struct dentry *dentry) +static int cap_inode_rmdir(struct inode *inode, struct dentry *dentry, + struct vfsmount *mnt) { return 0; } static int cap_inode_mknod(struct inode *inode, struct dentry *dentry, - int mode, dev_t dev) + struct vfsmount *mnt, int mode, dev_t dev) { return 0; } static int cap_inode_rename(struct inode *old_inode, struct dentry *old_dentry, - struct inode *new_inode, struct dentry *new_dentry) + struct vfsmount *old_mnt, struct inode *new_inode, + struct dentry *new_dentry, struct vfsmount *new_mnt) { return 0; } -static int cap_inode_readlink(struct dentry *dentry) +static int cap_inode_readlink(struct dentry *dentry, struct vfsmount *mnt) { return 0; } @@ -216,7 +220,8 @@ return 0; } -static int cap_inode_setattr(struct dentry *dentry, struct iattr *iattr) +static int cap_inode_setattr(struct dentry *dentry, struct vfsmount *mnt, + struct iattr *iattr) { return 0; } @@ -230,17 +235,20 @@ { } -static void cap_inode_post_setxattr(struct dentry *dentry, const char *name, +static void cap_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, const void *value, size_t size, int flags) { } -static int cap_inode_getxattr(struct dentry *dentry, const char *name) +static int cap_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, struct file *f) { return 0; } -static int cap_inode_listxattr(struct dentry *dentry) +static int cap_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt, + struct file *f) { return 0; } @@ -335,6 +343,11 @@ return 0; } +static int cap_path_permission(struct path *path, int mask) +{ + return security_inode_permission(path->dentry->d_inode, mask); +} + static int cap_task_create(unsigned long clone_flags) { return 0; @@ -889,6 +902,7 @@ set_to_cap_if_null(ops, file_send_sigiotask); set_to_cap_if_null(ops, file_receive); set_to_cap_if_null(ops, dentry_open); + set_to_cap_if_null(ops, path_permission); set_to_cap_if_null(ops, task_create); set_to_cap_if_null(ops, task_alloc_security); set_to_cap_if_null(ops, task_free_security); --- linux-2.6.27.orig/security/keys/keyctl.c +++ linux-2.6.27/security/keys/keyctl.c @@ -54,11 +54,11 @@ * - returns the new key's serial number * - implements add_key() */ -asmlinkage long sys_add_key(const char __user *_type, - const char __user *_description, - const void __user *_payload, - size_t plen, - key_serial_t ringid) +SYSCALL_DEFINE5(add_key, const char __user *, _type, + const char __user *, _description, + const void __user *, _payload, + size_t, plen, + key_serial_t, ringid) { key_ref_t keyring_ref, key_ref; char type[32], *description; @@ -146,10 +146,10 @@ * - if the _callout_info string is empty, it will be rendered as "-" * - implements request_key() */ -asmlinkage long sys_request_key(const char __user *_type, - const char __user *_description, - const char __user *_callout_info, - key_serial_t destringid) +SYSCALL_DEFINE4(request_key, const char __user *, _type, + const char __user *, _description, + const char __user *, _callout_info, + key_serial_t, destringid) { struct key_type *ktype; struct key *key; @@ -270,6 +270,7 @@ /* join the session */ ret = join_session_keyring(name); + kfree(name); error: return ret; @@ -1152,8 +1153,8 @@ /* * the key control system call */ -asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5) +SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, + unsigned long, arg4, unsigned long, arg5) { switch (option) { case KEYCTL_GET_KEYRING_ID: --- linux-2.6.27.orig/security/keys/process_keys.c +++ linux-2.6.27/security/keys/process_keys.c @@ -40,7 +40,7 @@ /* * install user and user session keyrings for a particular UID */ -static int install_user_keyrings(struct task_struct *tsk) +int install_user_keyrings(struct task_struct *tsk) { struct user_struct *user = tsk->user; struct key *uid_keyring, *session_keyring; --- linux-2.6.27.orig/security/keys/internal.h +++ linux-2.6.27/security/keys/internal.h @@ -107,6 +107,7 @@ extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check); +extern int install_user_keyrings(struct task_struct *tsk); extern int install_thread_keyring(struct task_struct *tsk); extern int install_process_keyring(struct task_struct *tsk); --- linux-2.6.27.orig/security/keys/request_key.c +++ linux-2.6.27/security/keys/request_key.c @@ -74,6 +74,10 @@ kenter("{%d},{%d},%s", key->serial, authkey->serial, op); + ret = install_user_keyrings(tsk); + if (ret < 0) + goto error_alloc; + /* allocate a new session keyring */ sprintf(desc, "_req.%u", key->serial); --- linux-2.6.27.orig/security/selinux/hooks.c +++ linux-2.6.27/security/selinux/hooks.c @@ -1811,40 +1811,16 @@ static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid) { - int buflen, rc; - char *buffer, *path, *end; + char *buffer, *path; + int rc = -ENOMEM; - rc = -ENOMEM; buffer = (char *)__get_free_page(GFP_KERNEL); if (!buffer) goto out; - buflen = PAGE_SIZE; - end = buffer+buflen; - *--end = '\0'; - buflen--; - path = end-1; - *path = '/'; - while (table) { - const char *name = table->procname; - size_t namelen = strlen(name); - buflen -= namelen + 1; - if (buflen < 0) - goto out_free; - end -= namelen; - memcpy(end, name, namelen); - *--end = '/'; - path = end; - table = table->parent; - } - buflen -= 4; - if (buflen < 0) - goto out_free; - end -= 4; - memcpy(end, "/sys", 4); - path = end; - rc = security_genfs_sid("proc", path, tclass, sid); -out_free: + path = sysctl_pathname(table, buffer, PAGE_SIZE); + if (path) + rc = security_genfs_sid("proc", path, tclass, sid); free_page((unsigned long)buffer); out: return rc; @@ -2566,64 +2542,79 @@ return 0; } -static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask) +static int selinux_inode_create(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mask) { return may_create(dir, dentry, SECCLASS_FILE); } -static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) +static int selinux_inode_link(struct dentry *old_dentry, + struct vfsmount *old_mnt, + struct inode *dir, + struct dentry *new_dentry, + struct vfsmount *new_mnt) { int rc; - rc = secondary_ops->inode_link(old_dentry, dir, new_dentry); + rc = secondary_ops->inode_link(old_dentry, old_mnt, dir, new_dentry, + new_mnt); if (rc) return rc; return may_link(dir, old_dentry, MAY_LINK); } -static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry) +static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt) { int rc; - rc = secondary_ops->inode_unlink(dir, dentry); + rc = secondary_ops->inode_unlink(dir, dentry, mnt); if (rc) return rc; return may_link(dir, dentry, MAY_UNLINK); } -static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name) +static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, const char *name) { return may_create(dir, dentry, SECCLASS_LNK_FILE); } -static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask) +static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mask) { return may_create(dir, dentry, SECCLASS_DIR); } -static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry) +static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt) { return may_link(dir, dentry, MAY_RMDIR); } -static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode, dev_t dev) { int rc; - rc = secondary_ops->inode_mknod(dir, dentry, mode, dev); + rc = secondary_ops->inode_mknod(dir, dentry, mnt, mode, dev); if (rc) return rc; return may_create(dir, dentry, inode_mode_to_security_class(mode)); } -static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry, - struct inode *new_inode, struct dentry *new_dentry) +static int selinux_inode_rename(struct inode *old_inode, + struct dentry *old_dentry, + struct vfsmount *old_mnt, + struct inode *new_inode, + struct dentry *new_dentry, + struct vfsmount *new_mnt) { return may_rename(old_inode, old_dentry, new_inode, new_dentry); } -static int selinux_inode_readlink(struct dentry *dentry) +static int selinux_inode_readlink(struct dentry *dentry, struct vfsmount *mnt) { return dentry_has_perm(current, NULL, dentry, FILE__READ); } @@ -2655,11 +2646,12 @@ open_file_mask_to_av(inode->i_mode, mask), NULL); } -static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) +static int selinux_inode_setattr(struct dentry *dentry, struct vfsmount *mnt, + struct iattr *iattr) { int rc; - rc = secondary_ops->inode_setattr(dentry, iattr); + rc = secondary_ops->inode_setattr(dentry, mnt, iattr); if (rc) return rc; @@ -2697,8 +2689,9 @@ return dentry_has_perm(current, NULL, dentry, FILE__SETATTR); } -static int selinux_inode_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags) +static int selinux_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, const void *value, + size_t size, int flags, struct file *file) { struct task_security_struct *tsec = current->security; struct inode *inode = dentry->d_inode; @@ -2752,7 +2745,8 @@ &ad); } -static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, +static void selinux_inode_post_setxattr(struct dentry *dentry, + struct vfsmount *mnt, const char *name, const void *value, size_t size, int flags) { @@ -2778,17 +2772,21 @@ return; } -static int selinux_inode_getxattr(struct dentry *dentry, const char *name) +static int selinux_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, struct file *file) { return dentry_has_perm(current, NULL, dentry, FILE__GETATTR); } -static int selinux_inode_listxattr(struct dentry *dentry) +static int selinux_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt, + struct file *file) { return dentry_has_perm(current, NULL, dentry, FILE__GETATTR); } -static int selinux_inode_removexattr(struct dentry *dentry, const char *name) +static int selinux_inode_removexattr(struct dentry *dentry, + struct vfsmount *mnt, const char *name, + struct file *file) { if (strcmp(name, XATTR_NAME_SELINUX)) return selinux_inode_setotherxattr(dentry, name); @@ -4467,6 +4465,7 @@ if (err) return err; err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); + if (err) return err; err = sel_netnode_sid(addrp, family, &node_sid); --- linux-2.6.27.orig/security/smack/smack_lsm.c +++ linux-2.6.27/security/smack/smack_lsm.c @@ -432,8 +432,9 @@ * * Returns 0 if access is permitted, an error code otherwise */ -static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, - struct dentry *new_dentry) +static int smack_inode_link(struct dentry *old_dentry, struct vfsmount *old_mnt, + struct inode *dir, + struct dentry *new_dentry, struct vfsmount *new_mnt) { int rc; char *isp; @@ -453,11 +454,13 @@ * smack_inode_unlink - Smack check on inode deletion * @dir: containing directory object * @dentry: file to unlink + * @mnt: vfsmount of file to unlink * * Returns 0 if current can write the containing directory * and the object, error code otherwise */ -static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) +static int smack_inode_unlink(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt) { struct inode *ip = dentry->d_inode; int rc; @@ -479,11 +482,13 @@ * smack_inode_rmdir - Smack check on directory deletion * @dir: containing directory object * @dentry: directory to unlink + * @mnt: vfsmount @dentry to unlink * * Returns 0 if current can write the containing directory * and the directory, error code otherwise */ -static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) +static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt) { int rc; @@ -504,8 +509,10 @@ * smack_inode_rename - Smack check on rename * @old_inode: the old directory * @old_dentry: unused + * @old_mnt: unused * @new_inode: the new directory * @new_dentry: unused + * @new_mnt: unused * * Read and write access is required on both the old and * new directories. @@ -514,8 +521,10 @@ */ static int smack_inode_rename(struct inode *old_inode, struct dentry *old_dentry, + struct vfsmount *old_mnt, struct inode *new_inode, - struct dentry *new_dentry) + struct dentry *new_dentry, + struct vfsmount *new_mnt) { int rc; char *isp; @@ -559,7 +568,8 @@ * * Returns 0 if access is permitted, an error code otherwise */ -static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) +static int smack_inode_setattr(struct dentry *dentry, struct vfsmount *mnt, + struct iattr *iattr) { /* * Need to allow for clearing the setuid bit. @@ -585,17 +595,20 @@ /** * smack_inode_setxattr - Smack check for setting xattrs * @dentry: the object + * @mnt: unused * @name: name of the attribute * @value: unused * @size: unused * @flags: unused + * @file: unused * * This protects the Smack attribute explicitly. * * Returns 0 if access is permitted, an error code otherwise */ -static int smack_inode_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags) +static int smack_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, const void *value, + size_t size, int flags, struct file *file) { int rc = 0; @@ -605,7 +618,8 @@ if (!capable(CAP_MAC_ADMIN)) rc = -EPERM; } else - rc = cap_inode_setxattr(dentry, name, value, size, flags); + rc = cap_inode_setxattr(dentry, mnt, name, value, size, flags, + file); if (rc == 0) rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE); @@ -616,6 +630,7 @@ /** * smack_inode_post_setxattr - Apply the Smack update approved above * @dentry: object + * @mnt: unused * @name: attribute name * @value: attribute value * @size: attribute size @@ -624,7 +639,8 @@ * Set the pointer in the inode blob to the entry found * in the master label list. */ -static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, +static void smack_inode_post_setxattr(struct dentry *dentry, + struct vfsmount *mnt, const char *name, const void *value, size_t size, int flags) { struct inode_smack *isp; @@ -657,11 +673,14 @@ /* * smack_inode_getxattr - Smack check on getxattr * @dentry: the object + * @mnt: unused * @name: unused + * @file: unused * * Returns 0 if access is permitted, an error code otherwise */ -static int smack_inode_getxattr(struct dentry *dentry, const char *name) +static int smack_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, struct file *file) { return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ); } @@ -669,13 +688,16 @@ /* * smack_inode_removexattr - Smack check on removexattr * @dentry: the object + * @mnt: unused * @name: name of the attribute + * @file: unused * * Removing the Smack attribute requires CAP_MAC_ADMIN * * Returns 0 if access is permitted, an error code otherwise */ -static int smack_inode_removexattr(struct dentry *dentry, const char *name) +static int smack_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, struct file *file) { int rc = 0; @@ -685,7 +707,7 @@ if (!capable(CAP_MAC_ADMIN)) rc = -EPERM; } else - rc = cap_inode_removexattr(dentry, name); + rc = cap_inode_removexattr(dentry, mnt, name, file); if (rc == 0) rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE); --- linux-2.6.27.orig/security/apparmor/module_interface.c +++ linux-2.6.27/security/apparmor/module_interface.c @@ -0,0 +1,967 @@ +/* + * Copyright (C) 1998-2007 Novell/SUSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * AppArmor userspace policy interface + */ + +#include + +#include "apparmor.h" +#include "inline.h" + +/* + * This mutex is used to synchronize profile adds, replacements, and + * removals: we only allow one of these operations at a time. + * We do not use the profile list lock here in order to avoid blocking + * exec during those operations. (Exec involves a profile list lookup + * for named-profile transitions.) + */ +DEFINE_MUTEX(aa_interface_lock); + +/* + * The AppArmor interface treats data as a type byte followed by the + * actual data. The interface has the notion of a a named entry + * which has a name (AA_NAME typecode followed by name string) followed by + * the entries typecode and data. Named types allow for optional + * elements and extensions to be added and tested for without breaking + * backwards compatability. + */ + +enum aa_code { + AA_U8, + AA_U16, + AA_U32, + AA_U64, + AA_NAME, /* same as string except it is items name */ + AA_STRING, + AA_BLOB, + AA_STRUCT, + AA_STRUCTEND, + AA_LIST, + AA_LISTEND, + AA_ARRAY, + AA_ARRAYEND, +}; + +/* + * aa_ext is the read of the buffer containing the serialized profile. The + * data is copied into a kernel buffer in apparmorfs and then handed off to + * the unpack routines. + */ +struct aa_ext { + void *start; + void *end; + void *pos; /* pointer to current position in the buffer */ + u32 version; + char *ns_name; +}; + +static inline int aa_inbounds(struct aa_ext *e, size_t size) +{ + return (size <= e->end - e->pos); +} + +/** + * aa_u16_chunck - test and do bounds checking for a u16 size based chunk + * @e: serialized data read head + * @chunk: start address for chunk of data + * + * return the size of chunk found with the read head at the end of + * the chunk. + */ +static size_t aa_is_u16_chunk(struct aa_ext *e, char **chunk) +{ + void *pos = e->pos; + size_t size = 0; + + if (!aa_inbounds(e, sizeof(u16))) + goto fail; + size = le16_to_cpu(get_unaligned((u16 *)e->pos)); + e->pos += sizeof(u16); + if (!aa_inbounds(e, size)) + goto fail; + *chunk = e->pos; + e->pos += size; + return size; + +fail: + e->pos = pos; + return 0; +} + +static inline int aa_is_X(struct aa_ext *e, enum aa_code code) +{ + if (!aa_inbounds(e, 1)) + return 0; + if (*(u8 *) e->pos != code) + return 0; + e->pos++; + return 1; +} + +/** + * aa_is_nameX - check is the next element is of type X with a name of @name + * @e: serialized data extent information + * @code: type code + * @name: name to match to the serialized element. + * + * check that the next serialized data element is of type X and has a tag + * name @name. If @name is specified then there must be a matching + * name element in the stream. If @name is NULL any name element will be + * skipped and only the typecode will be tested. + * returns 1 on success (both type code and name tests match) and the read + * head is advanced past the headers + * returns %0 if either match failes, the read head does not move + */ +static int aa_is_nameX(struct aa_ext *e, enum aa_code code, const char *name) +{ + void *pos = e->pos; + /* + * Check for presence of a tagname, and if present name size + * AA_NAME tag value is a u16. + */ + if (aa_is_X(e, AA_NAME)) { + char *tag; + size_t size = aa_is_u16_chunk(e, &tag); + /* if a name is specified it must match. otherwise skip tag */ + if (name && (!size || strcmp(name, tag))) + goto fail; + } else if (name) { + /* if a name is specified and there is no name tag fail */ + goto fail; + } + + /* now check if type code matches */ + if (aa_is_X(e, code)) + return 1; + +fail: + e->pos = pos; + return 0; +} + +static int aa_is_u16(struct aa_ext *e, u16 *data, const char *name) +{ + void *pos = e->pos; + if (aa_is_nameX(e, AA_U16, name)) { + if (!aa_inbounds(e, sizeof(u16))) + goto fail; + if (data) + *data = le16_to_cpu(get_unaligned((u16 *)e->pos)); + e->pos += sizeof(u16); + return 1; + } +fail: + e->pos = pos; + return 0; +} + +static int aa_is_u32(struct aa_ext *e, u32 *data, const char *name) +{ + void *pos = e->pos; + if (aa_is_nameX(e, AA_U32, name)) { + if (!aa_inbounds(e, sizeof(u32))) + goto fail; + if (data) + *data = le32_to_cpu(get_unaligned((u32 *)e->pos)); + e->pos += sizeof(u32); + return 1; + } +fail: + e->pos = pos; + return 0; +} + +static int aa_is_u64(struct aa_ext *e, u64 *data, const char *name) +{ + void *pos = e->pos; + if (aa_is_nameX(e, AA_U64, name)) { + if (!aa_inbounds(e, sizeof(u64))) + goto fail; + if (data) + *data = le64_to_cpu(get_unaligned((u64 *)e->pos)); + e->pos += sizeof(u64); + return 1; + } +fail: + e->pos = pos; + return 0; +} + +static size_t aa_is_array(struct aa_ext *e, const char *name) +{ + void *pos = e->pos; + if (aa_is_nameX(e, AA_ARRAY, name)) { + int size; + if (!aa_inbounds(e, sizeof(u16))) + goto fail; + size = (int) le16_to_cpu(get_unaligned((u16 *)e->pos)); + e->pos += sizeof(u16); + return size; + } +fail: + e->pos = pos; + return 0; +} + +static size_t aa_is_blob(struct aa_ext *e, char **blob, const char *name) +{ + void *pos = e->pos; + if (aa_is_nameX(e, AA_BLOB, name)) { + u32 size; + if (!aa_inbounds(e, sizeof(u32))) + goto fail; + size = le32_to_cpu(get_unaligned((u32 *)e->pos)); + e->pos += sizeof(u32); + if (aa_inbounds(e, (size_t) size)) { + * blob = e->pos; + e->pos += size; + return size; + } + } +fail: + e->pos = pos; + return 0; +} + +static int aa_is_dynstring(struct aa_ext *e, char **string, const char *name) +{ + char *src_str; + size_t size = 0; + void *pos = e->pos; + *string = NULL; + if (aa_is_nameX(e, AA_STRING, name) && + (size = aa_is_u16_chunk(e, &src_str))) { + char *str; + if (!(str = kmalloc(size, GFP_KERNEL))) + goto fail; + memcpy(str, src_str, size); + *string = str; + } + + return size; + +fail: + e->pos = pos; + return 0; +} + +/** + * aa_unpack_dfa - unpack a file rule dfa + * @e: serialized data extent information + * + * returns dfa or ERR_PTR + */ +static struct aa_dfa *aa_unpack_dfa(struct aa_ext *e) +{ + char *blob = NULL; + size_t size, error = 0; + struct aa_dfa *dfa = NULL; + + size = aa_is_blob(e, &blob, "aadfa"); + if (size) { + dfa = aa_match_alloc(); + if (dfa) { + /* + * The dfa is aligned with in the blob to 8 bytes + * from the beginning of the stream. + */ + size_t sz = blob - (char *) e->start; + size_t pad = ALIGN(sz, 8) - sz; + error = unpack_dfa(dfa, blob + pad, size - pad); + if (!error) + error = verify_dfa(dfa); + } else { + error = -ENOMEM; + } + + if (error) { + aa_match_free(dfa); + dfa = ERR_PTR(error); + } + } + + return dfa; +} + +static int aa_unpack_exec_table(struct aa_ext *e, struct aa_profile *profile) +{ + void *pos = e->pos; + + /* exec table is optional */ + if (aa_is_nameX(e, AA_STRUCT, "xtable")) { + int i, size; + + size = aa_is_array(e, NULL); + /* currently 4 exec bits and entries 0-3 are reserved iupcx */ + if (size > 16 - 4) + goto fail; + profile->exec_table = kzalloc(sizeof(char *) * size, + GFP_KERNEL); + if (!profile->exec_table) + goto fail; + + for (i = 0; i < size; i++) { + char *tmp; + if (!aa_is_dynstring(e, &tmp, NULL)) + goto fail; + /* note: strings beginning with a : have an embedded + \0 seperating the profile ns name from the profile + name */ + profile->exec_table[i] = tmp; + } + if (!aa_is_nameX(e, AA_ARRAYEND, NULL)) + goto fail; + if (!aa_is_nameX(e, AA_STRUCTEND, NULL)) + goto fail; + profile->exec_table_size = size; + } + return 1; + +fail: + e->pos = pos; + return 0; +} + +int aa_unpack_rlimits(struct aa_ext *e, struct aa_profile *profile) +{ + void *pos = e->pos; + + /* rlimits are optional */ + if (aa_is_nameX(e, AA_STRUCT, "rlimits")) { + int i, size; + u32 tmp = 0; + if (!aa_is_u32(e, &tmp, NULL)) + goto fail; + profile->rlimits.mask = tmp; + + size = aa_is_array(e, NULL); + if (size > RLIM_NLIMITS) + goto fail; + for (i = 0; i < size; i++) { + u64 tmp = 0; + if (!aa_is_u64(e, &tmp, NULL)) + goto fail; + profile->rlimits.limits[i].rlim_max = tmp; + } + if (!aa_is_nameX(e, AA_ARRAYEND, NULL)) + goto fail; + if (!aa_is_nameX(e, AA_STRUCTEND, NULL)) + goto fail; + } + return 1; + +fail: + e->pos = pos; + return 0; +} + +/** + * aa_unpack_profile - unpack a serialized profile + * @e: serialized data extent information + * @sa: audit struct for the operation + */ +static struct aa_profile *aa_unpack_profile(struct aa_ext *e, + struct aa_audit *sa) +{ + struct aa_profile *profile = NULL; + size_t size = 0; + int i, error = -EPROTO; + + profile = alloc_aa_profile(); + if (!profile) + return ERR_PTR(-ENOMEM); + + /* check that we have the right struct being passed */ + if (!aa_is_nameX(e, AA_STRUCT, "profile")) + goto fail; + if (!aa_is_dynstring(e, &profile->name, NULL)) + goto fail; + + /* per profile debug flags (complain, audit) */ + if (!aa_is_nameX(e, AA_STRUCT, "flags")) + goto fail; + if (!aa_is_u32(e, &(profile->flags.hat), NULL)) + goto fail; + if (!aa_is_u32(e, &(profile->flags.complain), NULL)) + goto fail; + if (!aa_is_u32(e, &(profile->flags.audit), NULL)) + goto fail; + if (!aa_is_nameX(e, AA_STRUCTEND, NULL)) + goto fail; + + if (!aa_is_u32(e, &(profile->capabilities.cap[0]), NULL)) + goto fail; + if (!aa_is_u32(e, &(profile->audit_caps.cap[0]), NULL)) + goto fail; + if (!aa_is_u32(e, &(profile->quiet_caps.cap[0]), NULL)) + goto fail; + if (!aa_is_u32(e, &(profile->set_caps.cap[0]), NULL)) + goto fail; + + if (aa_is_nameX(e, AA_STRUCT, "caps64")) { + /* optional upper half of 64 bit caps */ + if (!aa_is_u32(e, &(profile->capabilities.cap[1]), NULL)) + goto fail; + if (!aa_is_u32(e, &(profile->audit_caps.cap[1]), NULL)) + goto fail; + if (!aa_is_u32(e, &(profile->quiet_caps.cap[1]), NULL)) + goto fail; + if (!aa_is_u32(e, &(profile->set_caps.cap[1]), NULL)) + goto fail; + if (!aa_is_nameX(e, AA_STRUCTEND, NULL)) + goto fail; + } + + if (!aa_unpack_rlimits(e, profile)) + goto fail; + + size = aa_is_array(e, "net_allowed_af"); + if (size) { + if (size > AF_MAX) + goto fail; + + for (i = 0; i < size; i++) { + if (!aa_is_u16(e, &profile->network_families[i], NULL)) + goto fail; + if (!aa_is_u16(e, &profile->audit_network[i], NULL)) + goto fail; + if (!aa_is_u16(e, &profile->quiet_network[i], NULL)) + goto fail; + } + if (!aa_is_nameX(e, AA_ARRAYEND, NULL)) + goto fail; + /* allow unix domain and netlink sockets they are handled + * by IPC + */ + } + profile->network_families[AF_UNIX] = 0xffff; + profile->network_families[AF_NETLINK] = 0xffff; + + /* get file rules */ + profile->file_rules = aa_unpack_dfa(e); + if (IS_ERR(profile->file_rules)) { + error = PTR_ERR(profile->file_rules); + profile->file_rules = NULL; + goto fail; + } + + if (!aa_unpack_exec_table(e, profile)) + goto fail; + + if (!aa_is_nameX(e, AA_STRUCTEND, NULL)) + goto fail; + + return profile; + +fail: + sa->name = profile && profile->name ? profile->name : "unknown"; + if (!sa->info) + sa->info = "failed to unpack profile"; + aa_audit_status(NULL, sa); + + if (profile) + free_aa_profile(profile); + + return ERR_PTR(error); +} + +/** + * aa_verify_head - unpack serialized stream header + * @e: serialized data read head + * @operation: operation header is being verified for + * + * returns error or 0 if header is good + */ +static int aa_verify_header(struct aa_ext *e, struct aa_audit *sa) +{ + /* get the interface version */ + if (!aa_is_u32(e, &e->version, "version")) { + sa->info = "invalid profile format"; + aa_audit_status(NULL, sa); + return -EPROTONOSUPPORT; + } + + /* check that the interface version is currently supported */ + if (e->version != 5) { + sa->info = "unsupported interface version"; + aa_audit_status(NULL, sa); + return -EPROTONOSUPPORT; + } + + /* read the namespace if present */ + if (!aa_is_dynstring(e, &e->ns_name, "namespace")) { + e->ns_name = NULL; + } + + return 0; +} + +/** + * aa_add_profile - Unpack and add a new profile to the profile list + * @data: serialized data stream + * @size: size of the serialized data stream + */ +ssize_t aa_add_profile(void *data, size_t size) +{ + struct aa_profile *profile = NULL; + struct aa_namespace *ns = NULL; + struct aa_ext e = { + .start = data, + .end = data + size, + .pos = data, + .ns_name = NULL + }; + ssize_t error; + struct aa_audit sa; + memset(&sa, 0, sizeof(sa)); + sa.operation = "profile_load"; + sa.gfp_mask = GFP_KERNEL; + + error = aa_verify_header(&e, &sa); + if (error) + return error; + + profile = aa_unpack_profile(&e, &sa); + if (IS_ERR(profile)) + return PTR_ERR(profile); + + mutex_lock(&aa_interface_lock); + write_lock(&profile_ns_list_lock); + if (e.ns_name) + ns = __aa_find_namespace(e.ns_name, &profile_ns_list); + else + ns = default_namespace; + if (!ns) { + struct aa_namespace *new_ns; + write_unlock(&profile_ns_list_lock); + new_ns = alloc_aa_namespace(e.ns_name); + if (!new_ns) { + mutex_unlock(&aa_interface_lock); + return -ENOMEM; + } + write_lock(&profile_ns_list_lock); + ns = __aa_find_namespace(e.ns_name, &profile_ns_list); + if (!ns) { + list_add(&new_ns->list, &profile_ns_list); + ns = new_ns; + } else + free_aa_namespace(new_ns); + } + + write_lock(&ns->lock); + if (__aa_find_profile(profile->name, &ns->profiles)) { + /* A profile with this name exists already. */ + write_unlock(&ns->lock); + write_unlock(&profile_ns_list_lock); + sa.name = profile->name; + sa.name2 = ns->name; + sa.info = "failed: profile already loaded"; + aa_audit_status(NULL, &sa); + mutex_unlock(&aa_interface_lock); + aa_put_profile(profile); + return -EEXIST; + } + profile->ns = aa_get_namespace(ns); + ns->profile_count++; + list_add(&profile->list, &ns->profiles); + write_unlock(&ns->lock); + write_unlock(&profile_ns_list_lock); + + sa.name = profile->name; + sa.name2 = ns->name; + aa_audit_status(NULL, &sa); + mutex_unlock(&aa_interface_lock); + return size; +} + +/** + * task_replace - replace a task's profile + * @task: task to replace profile on + * @new_cxt: new aa_task_context to do replacement with + * @new_profile: new profile + */ +static inline void task_replace(struct task_struct *task, + struct aa_task_context *new_cxt, + struct aa_profile *new_profile) +{ + struct aa_task_context *cxt = aa_task_context(task); + + AA_DEBUG("%s: replacing profile for task %d " + "profile=%s (%p)\n", + __FUNCTION__, + cxt->task->pid, + cxt->profile->name, cxt->profile); + + aa_change_task_context(task, new_cxt, new_profile, cxt->cookie, + cxt->previous_profile); +} + +/** + * aa_replace_profile - replace a profile on the profile list + * @udata: serialized data stream + * @size: size of the serialized data stream + * + * unpack and replace a profile on the profile list and uses of that profile + * by any aa_task_context. If the profile does not exist on the profile list + * it is added. Return %0 or error. + */ +ssize_t aa_replace_profile(void *udata, size_t size) +{ + struct aa_profile *old_profile, *new_profile; + struct aa_namespace *ns; + struct aa_task_context *new_cxt; + struct aa_ext e = { + .start = udata, + .end = udata + size, + .pos = udata, + .ns_name = NULL + }; + ssize_t error; + struct aa_audit sa; + memset(&sa, 0, sizeof(sa)); + sa.operation = "profile_replace"; + sa.gfp_mask = GFP_KERNEL; + + error = aa_verify_header(&e, &sa); + if (error) + return error; + + new_profile = aa_unpack_profile(&e, &sa); + if (IS_ERR(new_profile)) + return PTR_ERR(new_profile); + + mutex_lock(&aa_interface_lock); + write_lock(&profile_ns_list_lock); + if (e.ns_name) + ns = __aa_find_namespace(e.ns_name, &profile_ns_list); + else + ns = default_namespace; + if (!ns) { + struct aa_namespace *new_ns; + write_unlock(&profile_ns_list_lock); + new_ns = alloc_aa_namespace(e.ns_name); + if (!new_ns) { + mutex_unlock(&aa_interface_lock); + return -ENOMEM; + } + write_lock(&profile_ns_list_lock); + ns = __aa_find_namespace(e.ns_name, &profile_ns_list); + if (!ns) { + list_add(&new_ns->list, &profile_ns_list); + ns = new_ns; + } else + free_aa_namespace(new_ns); + } + + write_lock(&ns->lock); + old_profile = __aa_find_profile(new_profile->name, &ns->profiles); + if (old_profile) { + lock_profile(old_profile); + old_profile->isstale = 1; + list_del_init(&old_profile->list); + unlock_profile(old_profile); + ns->profile_count--; + } + new_profile->ns = aa_get_namespace(ns); + ns->profile_count++; + /* not don't need an extra ref count to keep new_profile as + * it is protect by the interface mutex */ + list_add(&new_profile->list, &ns->profiles); + write_unlock(&ns->lock); + write_unlock(&profile_ns_list_lock); + + if (!old_profile) { + sa.operation = "profile_load"; + goto out; + } + /* do not fail replacement based off of profile's NPROC rlimit */ + + /* + * Replacement needs to allocate a new aa_task_context for each + * task confined by old_profile. To do this the profile locks + * are only held when the actual switch is done per task. While + * looping to allocate a new aa_task_context the old_task list + * may get shorter if tasks exit/change their profile but will + * not get longer as new task will not use old_profile detecting + * that is stale. + */ + do { + new_cxt = aa_alloc_task_context(GFP_KERNEL | __GFP_NOFAIL); + + lock_both_profiles(old_profile, new_profile); + if (!list_empty(&old_profile->task_contexts)) { + struct task_struct *task = + list_entry(old_profile->task_contexts.next, + struct aa_task_context, list)->task; + task_lock(task); + task_replace(task, new_cxt, new_profile); + task_unlock(task); + aa_set_rlimits(task, new_profile); + new_cxt = NULL; + } + unlock_both_profiles(old_profile, new_profile); + } while (!new_cxt); + aa_free_task_context(new_cxt); + aa_put_profile(old_profile); + +out: + sa.name = new_profile->name; + sa.name2 = ns->name; + aa_audit_status(NULL, &sa); + mutex_unlock(&aa_interface_lock); + return size; +} + +/** + * aa_remove_profile - remove a profile from the system + * @name: name of the profile to remove + * @size: size of the name + * + * remove a profile from the profile list and all aa_task_context references + * to said profile. + * NOTE: removing confinement does not restore rlimits to preconfinemnet values + */ +ssize_t aa_remove_profile(char *name, size_t size) +{ + struct aa_namespace *ns; + struct aa_profile *profile; + struct aa_audit sa; + memset(&sa, 0, sizeof(sa)); + sa.operation = "profile_remove"; + sa.gfp_mask = GFP_KERNEL; + + mutex_lock(&aa_interface_lock); + write_lock(&profile_ns_list_lock); + + if (name[0] == ':') { + char *split = strchr(name + 1, ':'); + if (!split) + goto noent; + *split = 0; + ns = __aa_find_namespace(name + 1, &profile_ns_list); + name = split + 1; + } else { + ns = default_namespace; + } + + if (!ns) + goto noent; + sa.name2 = ns->name; + write_lock(&ns->lock); + profile = __aa_find_profile(name, &ns->profiles); + if (!profile) { + write_unlock(&ns->lock); + goto noent; + } + sa.name = profile->name; + + /* Remove the profile from each task context it is on. */ + lock_profile(profile); + profile->isstale = 1; + aa_unconfine_tasks(profile); + list_del_init(&profile->list); + ns->profile_count--; + unlock_profile(profile); + /* Release the profile itself. */ + write_unlock(&ns->lock); + /* check to see if the namespace has become stale */ + if (ns != default_namespace && ns->profile_count == 0) { + list_del_init(&ns->list); + aa_put_namespace(ns); + } + write_unlock(&profile_ns_list_lock); + + aa_audit_status(NULL, &sa); + mutex_unlock(&aa_interface_lock); + aa_put_profile(profile); + + return size; + +noent: + write_unlock(&profile_ns_list_lock); + sa.info = "failed: profile does not exist"; + aa_audit_status(NULL, &sa); + mutex_unlock(&aa_interface_lock); + return -ENOENT; +} + +/** + * free_aa_namespace_kref - free aa_namespace by kref (see aa_put_namespace) + * @kr: kref callback for freeing of a namespace + */ +void free_aa_namespace_kref(struct kref *kref) +{ + struct aa_namespace *ns=container_of(kref, struct aa_namespace, count); + + free_aa_namespace(ns); +} + +/** + * alloc_aa_namespace - allocate, initialize and return a new namespace + * @name: a preallocated name + * Returns NULL on failure. + */ +struct aa_namespace *alloc_aa_namespace(char *name) +{ + struct aa_namespace *ns; + + ns = kzalloc(sizeof(*ns), GFP_KERNEL); + AA_DEBUG("%s(%p)\n", __FUNCTION__, ns); + if (ns) { + ns->name = name; + INIT_LIST_HEAD(&ns->list); + INIT_LIST_HEAD(&ns->profiles); + kref_init(&ns->count); + rwlock_init(&ns->lock); + + ns->null_complain_profile = alloc_aa_profile(); + if (!ns->null_complain_profile) { + if (!name) + kfree(ns->name); + kfree(ns); + return NULL; + } + ns->null_complain_profile->name = + kstrdup("null-complain-profile", GFP_KERNEL); + if (!ns->null_complain_profile->name) { + free_aa_profile(ns->null_complain_profile); + if (!name) + kfree(ns->name); + kfree(ns); + return NULL; + } + ns->null_complain_profile->flags.complain = 1; + /* null_complain_profile doesn't contribute to ns ref count */ + ns->null_complain_profile->ns = ns; + } + return ns; +} + +/** + * free_aa_namespace - free a profile namespace + * @namespace: the namespace to free + * + * Free a namespace. All references to the namespace must have been put. + * If the namespace was referenced by a profile confining a task, + * free_aa_namespace will be called indirectly (through free_aa_profile) + * from an rcu callback routine, so we must not sleep here. + */ +void free_aa_namespace(struct aa_namespace *ns) +{ + AA_DEBUG("%s(%p)\n", __FUNCTION__, ns); + + if (!ns) + return; + + /* namespace still contains profiles -- invalid */ + if (!list_empty(&ns->profiles)) { + AA_ERROR("%s: internal error, " + "namespace '%s' still contains profiles\n", + __FUNCTION__, + ns->name); + BUG(); + } + if (!list_empty(&ns->list)) { + AA_ERROR("%s: internal error, " + "namespace '%s' still on list\n", + __FUNCTION__, + ns->name); + BUG(); + } + /* null_complain_profile doesn't contribute to ns ref counting */ + ns->null_complain_profile->ns = NULL; + aa_put_profile(ns->null_complain_profile); + kfree(ns->name); + kfree(ns); +} + +/** + * free_aa_profile_kref - free aa_profile by kref (called by aa_put_profile) + * @kr: kref callback for freeing of a profile + */ +void free_aa_profile_kref(struct kref *kref) +{ + struct aa_profile *p=container_of(kref, struct aa_profile, count); + + free_aa_profile(p); +} + +/** + * alloc_aa_profile - allocate, initialize and return a new profile + * Returns NULL on failure. + */ +struct aa_profile *alloc_aa_profile(void) +{ + struct aa_profile *profile; + + profile = kzalloc(sizeof(*profile), GFP_KERNEL); + AA_DEBUG("%s(%p)\n", __FUNCTION__, profile); + if (profile) { + INIT_LIST_HEAD(&profile->list); + kref_init(&profile->count); + INIT_LIST_HEAD(&profile->task_contexts); + spin_lock_init(&profile->lock); + } + return profile; +} + +/** + * free_aa_profile - free a profile + * @profile: the profile to free + * + * Free a profile, its hats and null_profile. All references to the profile, + * its hats and null_profile must have been put. + * + * If the profile was referenced from a task context, free_aa_profile() will + * be called from an rcu callback routine, so we must not sleep here. + */ +void free_aa_profile(struct aa_profile *profile) +{ + AA_DEBUG("%s(%p)\n", __FUNCTION__, profile); + + if (!profile) + return; + + /* profile is still on profile namespace list -- invalid */ + if (!list_empty(&profile->list)) { + AA_ERROR("%s: internal error, " + "profile '%s' still on global list\n", + __FUNCTION__, + profile->name); + BUG(); + } + aa_put_namespace(profile->ns); + + aa_match_free(profile->file_rules); + + if (profile->name) { + AA_DEBUG("%s: %s\n", __FUNCTION__, profile->name); + kfree(profile->name); + } + + kfree(profile); +} + +/** + * aa_unconfine_tasks - remove tasks on a profile's task context list + * @profile: profile to remove tasks from + * + * Assumes that @profile lock is held. + */ +void aa_unconfine_tasks(struct aa_profile *profile) +{ + while (!list_empty(&profile->task_contexts)) { + struct task_struct *task = + list_entry(profile->task_contexts.next, + struct aa_task_context, list)->task; + task_lock(task); + aa_change_task_context(task, NULL, NULL, 0, NULL); + task_unlock(task); + } +} --- linux-2.6.27.orig/security/apparmor/apparmorfs.c +++ linux-2.6.27/security/apparmor/apparmorfs.c @@ -0,0 +1,281 @@ +/* + * Copyright (C) 1998-2007 Novell/SUSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * AppArmor filesystem (part of securityfs) + */ + +#include +#include +#include +#include +#include +#include + +#include "apparmor.h" +#include "inline.h" + +static char *aa_simple_write_to_buffer(const char __user *userbuf, + size_t alloc_size, size_t copy_size, + loff_t *pos, const char *operation) +{ + struct aa_profile *profile; + char *data; + + if (*pos != 0) { + /* only writes from pos 0, that is complete writes */ + data = ERR_PTR(-ESPIPE); + goto out; + } + + /* + * Don't allow confined processes to load/replace/remove profiles. + * No sane person would add rules allowing this to a profile + * but we enforce the restriction anyways. + */ + profile = aa_get_profile(current); + if (profile) { + struct aa_audit sa; + memset(&sa, 0, sizeof(sa)); + sa.operation = operation; + sa.gfp_mask = GFP_KERNEL; + sa.error_code = -EACCES; + data = ERR_PTR(aa_audit_reject(profile, &sa)); + aa_put_profile(profile); + goto out; + } + + data = vmalloc(alloc_size); + if (data == NULL) { + data = ERR_PTR(-ENOMEM); + goto out; + } + + if (copy_from_user(data, userbuf, copy_size)) { + vfree(data); + data = ERR_PTR(-EFAULT); + goto out; + } + +out: + return data; +} + +/* apparmor/profiles */ +extern struct seq_operations apparmorfs_profiles_op; + +static int aa_profiles_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &apparmorfs_profiles_op); +} + + +static int aa_profiles_release(struct inode *inode, struct file *file) +{ + return seq_release(inode, file); +} + +static struct file_operations apparmorfs_profiles_fops = { + .open = aa_profiles_open, + .read = seq_read, + .llseek = seq_lseek, + .release = aa_profiles_release, +}; + +/* apparmor/matching */ +static ssize_t aa_matching_read(struct file *file, char __user *buf, + size_t size, loff_t *ppos) +{ + const char *matching = "pattern=aadfa audit perms=rwxamlk/ user::other"; + + return simple_read_from_buffer(buf, size, ppos, matching, + strlen(matching)); +} + +static struct file_operations apparmorfs_matching_fops = { + .read = aa_matching_read, +}; + +/* apparmor/features */ +static ssize_t aa_features_read(struct file *file, char __user *buf, + size_t size, loff_t *ppos) +{ + const char *features = "file=3.0 capability=2.0 network=1.0 " + "change_hat=1.5 change_profile=1.0 " + "aanamespaces=1.0 rlimit=1.0"; + + return simple_read_from_buffer(buf, size, ppos, features, + strlen(features)); +} + +static struct file_operations apparmorfs_features_fops = { + .read = aa_features_read, +}; + +/* apparmor/.load */ +static ssize_t aa_profile_load(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + char *data; + ssize_t error; + + data = aa_simple_write_to_buffer(buf, size, size, pos, "profile_load"); + + error = PTR_ERR(data); + if (!IS_ERR(data)) { + error = aa_add_profile(data, size); + vfree(data); + } + + return error; +} + + +static struct file_operations apparmorfs_profile_load = { + .write = aa_profile_load +}; + +/* apparmor/.replace */ +static ssize_t aa_profile_replace(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + char *data; + ssize_t error; + + data = aa_simple_write_to_buffer(buf, size, size, pos, + "profile_replace"); + + error = PTR_ERR(data); + if (!IS_ERR(data)) { + error = aa_replace_profile(data, size); + vfree(data); + } + + return error; +} + + +static struct file_operations apparmorfs_profile_replace = { + .write = aa_profile_replace +}; + +/* apparmor/.remove */ +static ssize_t aa_profile_remove(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + char *data; + ssize_t error; + + /* + * aa_remove_profile needs a null terminated string so 1 extra + * byte is allocated and the copied data is null terminated. + */ + data = aa_simple_write_to_buffer(buf, size + 1, size, pos, + "profile_remove"); + + error = PTR_ERR(data); + if (!IS_ERR(data)) { + data[size] = 0; + error = aa_remove_profile(data, size); + vfree(data); + } + + return error; +} + +static struct file_operations apparmorfs_profile_remove = { + .write = aa_profile_remove +}; + +static struct dentry *apparmor_dentry; + +static void aafs_remove(const char *name) +{ + struct dentry *dentry; + + dentry = lookup_one_len(name, apparmor_dentry, strlen(name)); + if (!IS_ERR(dentry)) { + securityfs_remove(dentry); + dput(dentry); + } +} + +static int aafs_create(const char *name, int mask, struct file_operations *fops) +{ + struct dentry *dentry; + + dentry = securityfs_create_file(name, S_IFREG | mask, apparmor_dentry, + NULL, fops); + + return IS_ERR(dentry) ? PTR_ERR(dentry) : 0; +} + +void destroy_apparmorfs(void) +{ + if (apparmor_dentry) { + aafs_remove(".remove"); + aafs_remove(".replace"); + aafs_remove(".load"); + aafs_remove("matching"); + aafs_remove("features"); + aafs_remove("profiles"); + securityfs_remove(apparmor_dentry); + apparmor_dentry = NULL; + } +} + +int create_apparmorfs(void) +{ + int error; + + if (!apparmor_initialized) + return 0; + + if (apparmor_dentry) { + AA_ERROR("%s: AppArmor securityfs already exists\n", + __FUNCTION__); + return -EEXIST; + } + + apparmor_dentry = securityfs_create_dir("apparmor", NULL); + if (IS_ERR(apparmor_dentry)) { + error = PTR_ERR(apparmor_dentry); + apparmor_dentry = NULL; + goto error; + } + error = aafs_create("profiles", 0440, &apparmorfs_profiles_fops); + if (error) + goto error; + error = aafs_create("matching", 0444, &apparmorfs_matching_fops); + if (error) + goto error; + error = aafs_create("features", 0444, &apparmorfs_features_fops); + if (error) + goto error; + error = aafs_create(".load", 0640, &apparmorfs_profile_load); + if (error) + goto error; + error = aafs_create(".replace", 0640, &apparmorfs_profile_replace); + if (error) + goto error; + error = aafs_create(".remove", 0640, &apparmorfs_profile_remove); + if (error) + goto error; + + /* Report that AppArmor fs is enabled */ + info_message("AppArmor Filesystem Enabled"); + return 0; + +error: + destroy_apparmorfs(); + AA_ERROR("Error creating AppArmor securityfs\n"); + apparmor_disable(); + return error; +} + +fs_initcall(create_apparmorfs); + --- linux-2.6.27.orig/security/apparmor/inline.h +++ linux-2.6.27/security/apparmor/inline.h @@ -0,0 +1,250 @@ +/* + * Copyright (C) 1998-2007 Novell/SUSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + */ + +#ifndef __INLINE_H +#define __INLINE_H + +#include + +#include "match.h" + +static inline int mediated_filesystem(struct inode *inode) +{ + return !(inode->i_sb->s_flags & MS_NOUSER); +} + +static inline struct aa_task_context *aa_task_context(struct task_struct *task) +{ + return (struct aa_task_context *) rcu_dereference(task->security); +} + +static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns) +{ + if (ns) + kref_get(&(ns->count)); + + return ns; +} + +static inline void aa_put_namespace(struct aa_namespace *ns) +{ + if (ns) + kref_put(&ns->count, free_aa_namespace_kref); +} + + +static inline struct aa_namespace *aa_find_namespace(const char *name) +{ + struct aa_namespace *ns = NULL; + + read_lock(&profile_ns_list_lock); + ns = aa_get_namespace(__aa_find_namespace(name, &profile_ns_list)); + read_unlock(&profile_ns_list_lock); + + return ns; +} + +/** + * aa_dup_profile - increment refcount on profile @p + * @p: profile + */ +static inline struct aa_profile *aa_dup_profile(struct aa_profile *p) +{ + if (p) + kref_get(&(p->count)); + + return p; +} + +/** + * aa_put_profile - decrement refcount on profile @p + * @p: profile + */ +static inline void aa_put_profile(struct aa_profile *p) +{ + if (p) + kref_put(&p->count, free_aa_profile_kref); +} + +static inline struct aa_profile *aa_get_profile(struct task_struct *task) +{ + struct aa_task_context *cxt; + struct aa_profile *profile = NULL; + + rcu_read_lock(); + cxt = aa_task_context(task); + if (cxt) { + profile = cxt->profile; + aa_dup_profile(profile); + } + rcu_read_unlock(); + + return profile; +} + +static inline struct aa_profile *aa_find_profile(struct aa_namespace *ns, + const char *name) +{ + struct aa_profile *profile = NULL; + + read_lock(&ns->lock); + profile = aa_dup_profile(__aa_find_profile(name, &ns->profiles)); + read_unlock(&ns->lock); + + return profile; +} + +static inline struct aa_task_context *aa_alloc_task_context(gfp_t flags) +{ + struct aa_task_context *cxt; + + cxt = kzalloc(sizeof(*cxt), flags); + if (cxt) { + INIT_LIST_HEAD(&cxt->list); + INIT_RCU_HEAD(&cxt->rcu); + } + + return cxt; +} + +static inline void aa_free_task_context(struct aa_task_context *cxt) +{ + if (cxt) { + aa_put_profile(cxt->profile); + aa_put_profile(cxt->previous_profile); + kfree(cxt); + } +} + +/** + * lock_profile - lock a profile + * @profile: the profile to lock + * + * While the profile is locked, local interrupts are disabled. This also + * gives us RCU reader safety. + */ +static inline void lock_profile_nested(struct aa_profile *profile, + enum aa_lock_class lock_class) +{ + /* + * Lock the profile. + * + * Need to disable interrupts here because this lock is used in + * the task_free_security hook, which may run in RCU context. + */ + if (profile) + spin_lock_irqsave_nested(&profile->lock, profile->int_flags, + lock_class); +} + +static inline void lock_profile(struct aa_profile *profile) +{ + lock_profile_nested(profile, aa_lock_normal); +} + +/** + * unlock_profile - unlock a profile + * @profile: the profile to unlock + */ +static inline void unlock_profile(struct aa_profile *profile) +{ + /* Unlock the profile. */ + if (profile) + spin_unlock_irqrestore(&profile->lock, profile->int_flags); +} + +/** + * lock_both_profiles - lock two profiles in a deadlock-free way + * @profile1: profile to lock (may be NULL) + * @profile2: profile to lock (may be NULL) + * + * The order in which profiles are passed into lock_both_profiles() / + * unlock_both_profiles() does not matter. + * While the profile is locked, local interrupts are disabled. This also + * gives us RCU reader safety. + */ +static inline void lock_both_profiles(struct aa_profile *profile1, + struct aa_profile *profile2) +{ + /* + * Lock the two profiles. + * + * We need to disable interrupts because the profile locks are + * used in the task_free_security hook, which may run in RCU + * context. + * + * Do not nest spin_lock_irqsave()/spin_unlock_irqresore(): + * interrupts only need to be turned off once. + */ + if (!profile1 || profile1 == profile2) { + if (profile2) + spin_lock_irqsave_nested(&profile2->lock, + profile2->int_flags, + aa_lock_normal); + } else if (profile1 > profile2) { + /* profile1 cannot be NULL here. */ + spin_lock_irqsave_nested(&profile1->lock, profile1->int_flags, + aa_lock_normal); + if (profile2) + spin_lock_nested(&profile2->lock, aa_lock_nested); + + } else { + /* profile2 cannot be NULL here. */ + spin_lock_irqsave_nested(&profile2->lock, profile2->int_flags, + aa_lock_normal); + spin_lock_nested(&profile1->lock, aa_lock_nested); + } +} + +/** + * unlock_both_profiles - unlock two profiles in a deadlock-free way + * @profile1: profile to unlock (may be NULL) + * @profile2: profile to unlock (may be NULL) + * + * The order in which profiles are passed into lock_both_profiles() / + * unlock_both_profiles() does not matter. + * While the profile is locked, local interrupts are disabled. This also + * gives us RCU reader safety. + */ +static inline void unlock_both_profiles(struct aa_profile *profile1, + struct aa_profile *profile2) +{ + /* Unlock the two profiles. */ + if (!profile1 || profile1 == profile2) { + if (profile2) + spin_unlock_irqrestore(&profile2->lock, + profile2->int_flags); + } else if (profile1 > profile2) { + /* profile1 cannot be NULL here. */ + if (profile2) + spin_unlock(&profile2->lock); + spin_unlock_irqrestore(&profile1->lock, profile1->int_flags); + } else { + /* profile2 cannot be NULL here. */ + spin_unlock(&profile1->lock); + spin_unlock_irqrestore(&profile2->lock, profile2->int_flags); + } +} + +static inline unsigned int aa_match(struct aa_dfa *dfa, const char *pathname, + int *audit_mask) +{ + if (dfa) + return aa_dfa_match(dfa, pathname, audit_mask); + if (audit_mask) + *audit_mask = 0; + return 0; +} + +static inline int dfa_audit_mask(struct aa_dfa *dfa, unsigned int state) +{ + return ACCEPT_TABLE2(dfa)[state]; +} + +#endif /* __INLINE_H__ */ --- linux-2.6.27.orig/security/apparmor/match.c +++ linux-2.6.27/security/apparmor/match.c @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2007 Novell/SUSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * Regular expression transition table matching + */ + +#include +#include +#include +#include "apparmor.h" +#include "match.h" +#include "inline.h" + +static struct table_header *unpack_table(void *blob, size_t bsize) +{ + struct table_header *table = NULL; + struct table_header th; + size_t tsize; + + if (bsize < sizeof(struct table_header)) + goto out; + + th.td_id = be16_to_cpu(*(u16 *) (blob)); + th.td_flags = be16_to_cpu(*(u16 *) (blob + 2)); + th.td_lolen = be32_to_cpu(*(u32 *) (blob + 8)); + blob += sizeof(struct table_header); + + if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 || + th.td_flags == YYTD_DATA8)) + goto out; + + tsize = table_size(th.td_lolen, th.td_flags); + if (bsize < tsize) + goto out; + + table = kmalloc(tsize, GFP_KERNEL); + if (table) { + *table = th; + if (th.td_flags == YYTD_DATA8) + UNPACK_ARRAY(table->td_data, blob, th.td_lolen, + u8, byte_to_byte); + else if (th.td_flags == YYTD_DATA16) + UNPACK_ARRAY(table->td_data, blob, th.td_lolen, + u16, be16_to_cpu); + else + UNPACK_ARRAY(table->td_data, blob, th.td_lolen, + u32, be32_to_cpu); + } + +out: + return table; +} + +int unpack_dfa(struct aa_dfa *dfa, void *blob, size_t size) +{ + int hsize, i; + int error = -ENOMEM; + + /* get dfa table set header */ + if (size < sizeof(struct table_set_header)) + goto fail; + + if (ntohl(*(u32 *)blob) != YYTH_MAGIC) + goto fail; + + hsize = ntohl(*(u32 *)(blob + 4)); + if (size < hsize) + goto fail; + + blob += hsize; + size -= hsize; + + error = -EPROTO; + while (size > 0) { + struct table_header *table; + table = unpack_table(blob, size); + if (!table) + goto fail; + + switch(table->td_id) { + case YYTD_ID_ACCEPT: + case YYTD_ID_ACCEPT2: + case YYTD_ID_BASE: + dfa->tables[table->td_id - 1] = table; + if (table->td_flags != YYTD_DATA32) + goto fail; + break; + case YYTD_ID_DEF: + case YYTD_ID_NXT: + case YYTD_ID_CHK: + dfa->tables[table->td_id - 1] = table; + if (table->td_flags != YYTD_DATA16) + goto fail; + break; + case YYTD_ID_EC: + dfa->tables[table->td_id - 1] = table; + if (table->td_flags != YYTD_DATA8) + goto fail; + break; + default: + kfree(table); + goto fail; + } + + blob += table_size(table->td_lolen, table->td_flags); + size -= table_size(table->td_lolen, table->td_flags); + } + + return 0; + +fail: + for (i = 0; i < ARRAY_SIZE(dfa->tables); i++) { + if (dfa->tables[i]) { + kfree(dfa->tables[i]); + dfa->tables[i] = NULL; + } + } + return error; +} + +/** + * verify_dfa - verify that all the transitions and states in the dfa tables + * are in bounds. + * @dfa: dfa to test + * + * assumes dfa has gone through the verification done by unpacking + */ +int verify_dfa(struct aa_dfa *dfa) +{ + size_t i, state_count, trans_count; + int error = -EPROTO; + + /* check that required tables exist */ + if (!(dfa->tables[YYTD_ID_ACCEPT - 1] && + dfa->tables[YYTD_ID_ACCEPT2 - 1] && + dfa->tables[YYTD_ID_DEF - 1] && + dfa->tables[YYTD_ID_BASE - 1] && + dfa->tables[YYTD_ID_NXT - 1] && + dfa->tables[YYTD_ID_CHK - 1])) + goto out; + + /* accept.size == default.size == base.size */ + state_count = dfa->tables[YYTD_ID_BASE - 1]->td_lolen; + if (!(state_count == dfa->tables[YYTD_ID_DEF - 1]->td_lolen && + state_count == dfa->tables[YYTD_ID_ACCEPT - 1]->td_lolen && + state_count == dfa->tables[YYTD_ID_ACCEPT2 - 1]->td_lolen)) + goto out; + + /* next.size == chk.size */ + trans_count = dfa->tables[YYTD_ID_NXT - 1]->td_lolen; + if (trans_count != dfa->tables[YYTD_ID_CHK - 1]->td_lolen) + goto out; + + /* if equivalence classes then its table size must be 256 */ + if (dfa->tables[YYTD_ID_EC - 1] && + dfa->tables[YYTD_ID_EC - 1]->td_lolen != 256) + goto out; + + for (i = 0; i < state_count; i++) { + if (DEFAULT_TABLE(dfa)[i] >= state_count) + goto out; + if (BASE_TABLE(dfa)[i] >= trans_count + 256) + goto out; + } + + for (i = 0; i < trans_count ; i++) { + if (NEXT_TABLE(dfa)[i] >= state_count) + goto out; + if (CHECK_TABLE(dfa)[i] >= state_count) + goto out; + } + + /* verify accept permissions */ + for (i = 0; i < state_count; i++) { + int mode = ACCEPT_TABLE(dfa)[i]; + + if (mode & ~AA_VALID_PERM_MASK) + goto out; + if (ACCEPT_TABLE2(dfa)[i] & ~AA_VALID_PERM2_MASK) + goto out; + + /* if any exec modifier is set MAY_EXEC must be set */ + if ((mode & AA_USER_EXEC_TYPE) && !(mode & AA_USER_EXEC)) + goto out; + if ((mode & AA_OTHER_EXEC_TYPE) && !(mode & AA_OTHER_EXEC)) + goto out; + } + + error = 0; +out: + return error; +} + +struct aa_dfa *aa_match_alloc(void) +{ + return kzalloc(sizeof(struct aa_dfa), GFP_KERNEL); +} + +void aa_match_free(struct aa_dfa *dfa) +{ + if (dfa) { + int i; + + for (i = 0; i < ARRAY_SIZE(dfa->tables); i++) + kfree(dfa->tables[i]); + } + kfree(dfa); +} + +/** + * aa_dfa_next_state_len - traverse @dfa to find state @str stops at + * @dfa: the dfa to match @str against + * @start: the state of the dfa to start matching in + * @str: the string of bytes to match against the dfa + * @len: length of the string of bytes to match + * + * aa_dfa_next_state will match @str against the dfa and return the state it + * finished matching in. The final state can be used to look up the accepting + * label, or as the start state of a continuing match. + * + * aa_dfa_next_state could be implement using this function by doing + * return aa_dfa_next_state_len(dfa, start, str, strlen(str)); + * but that would require traversing the string twice and be slightly + * slower. + */ +unsigned int aa_dfa_next_state_len(struct aa_dfa *dfa, unsigned int start, + const char *str, int len) +{ + u16 *def = DEFAULT_TABLE(dfa); + u32 *base = BASE_TABLE(dfa); + u16 *next = NEXT_TABLE(dfa); + u16 *check = CHECK_TABLE(dfa); + unsigned int state = start, pos; + + if (state == 0) + return 0; + + /* current state is , matching character *str */ + if (dfa->tables[YYTD_ID_EC - 1]) { + u8 *equiv = EQUIV_TABLE(dfa); + for (; len; len--) { + pos = base[state] + equiv[(u8)*str++]; + if (check[pos] == state) + state = next[pos]; + else + state = def[state]; + } + } else { + for (; len; len--) { + pos = base[state] + (u8)*str++; + if (check[pos] == state) + state = next[pos]; + else + state = def[state]; + } + } + return state; +} + +/** + * aa_dfa_next_state - traverse @dfa to find state @str stops at + * @dfa: the dfa to match @str against + * @start: the state of the dfa to start matching in + * @str: the null terminated string of bytes to match against the dfa + * + * aa_dfa_next_state will match @str against the dfa and return the state it + * finished matching in. The final state can be used to look up the accepting + * label, or as the start state of a continuing match. + */ +unsigned int aa_dfa_next_state(struct aa_dfa *dfa, unsigned int start, + const char *str) +{ + u16 *def = DEFAULT_TABLE(dfa); + u32 *base = BASE_TABLE(dfa); + u16 *next = NEXT_TABLE(dfa); + u16 *check = CHECK_TABLE(dfa); + unsigned int state = start, pos; + + if (state == 0) + return 0; + + /* current state is , matching character *str */ + if (dfa->tables[YYTD_ID_EC - 1]) { + u8 *equiv = EQUIV_TABLE(dfa); + while (*str) { + pos = base[state] + equiv[(u8)*str++]; + if (check[pos] == state) + state = next[pos]; + else + state = def[state]; + } + } else { + while (*str) { + pos = base[state] + (u8)*str++; + if (check[pos] == state) + state = next[pos]; + else + state = def[state]; + } + } + return state; +} + +/** + * aa_dfa_null_transition - step to next state after null character + * @dfa: the dfa to match against + * @start: the state of the dfa to start matching in + * + * aa_dfa_null_transition transitions to the next state after a null + * character which is not used in standard matching and is only + * used to seperate pairs. + */ +unsigned int aa_dfa_null_transition(struct aa_dfa *dfa, unsigned int start) +{ + return aa_dfa_next_state_len(dfa, start, "", 1); +} + +/** + * aa_dfa_match - find accept perm for @str in @dfa + * @dfa: the dfa to match @str against + * @str: the string to match against the dfa + * @audit_mask: the audit_mask for the final state + * + * aa_dfa_match will match @str and return the accept perms for the + * final state. + */ +unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str, int *audit_mask) +{ + int state = aa_dfa_next_state(dfa, DFA_START, str); + if (audit_mask) + *audit_mask = dfa_audit_mask(dfa, state); + return ACCEPT_TABLE(dfa)[state]; +} + +/** + * aa_match_state - find accept perm and state for @str in @dfa + * @dfa: the dfa to match @str against + * @start: the state to start the match from + * @str: the string to match against the dfa + * @final: the state that the match finished in + * + * aa_match_state will match @str and return the accept perms, and @final + * state, the match occured in. + */ +unsigned int aa_match_state(struct aa_dfa *dfa, unsigned int start, + const char *str, unsigned int *final) +{ + unsigned int state; + if (dfa) { + state = aa_dfa_next_state(dfa, start, str); + if (final) + *final = state; + return ACCEPT_TABLE(dfa)[state]; + } + if (final) + *final = 0; + return 0; +} + --- linux-2.6.27.orig/security/apparmor/apparmor.h +++ linux-2.6.27/security/apparmor/apparmor.h @@ -0,0 +1,403 @@ +/* + * Copyright (C) 1998-2007 Novell/SUSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * AppArmor internal prototypes + */ + +#ifndef __APPARMOR_H +#define __APPARMOR_H + +#include +#include +#include +#include +#include +#include +#include + +/* + * We use MAY_READ, MAY_WRITE, MAY_EXEC, MAY_APPEND and the following flags + * for profile permissions + */ +#define AA_MAY_LINK 0x0010 +#define AA_MAY_LOCK 0x0020 +#define AA_EXEC_MMAP 0x0040 +#define AA_MAY_MOUNT 0x0080 /* no direct audit mapping */ +#define AA_EXEC_UNSAFE 0x0100 +#define AA_EXEC_INHERIT 0x0200 +#define AA_EXEC_MOD_0 0x0400 +#define AA_EXEC_MOD_1 0x0800 +#define AA_EXEC_MOD_2 0x1000 +#define AA_EXEC_MOD_3 0x2000 + +#define AA_BASE_PERMS (MAY_READ | MAY_WRITE | MAY_EXEC | \ + MAY_APPEND | AA_MAY_LINK | \ + AA_MAY_LOCK | AA_EXEC_MMAP | \ + AA_MAY_MOUNT | AA_EXEC_UNSAFE | \ + AA_EXEC_INHERIT | AA_EXEC_MOD_0 | \ + AA_EXEC_MOD_1 | AA_EXEC_MOD_2 | \ + AA_EXEC_MOD_3) + +#define AA_EXEC_MODIFIERS (AA_EXEC_MOD_0 | AA_EXEC_MOD_1 | \ + AA_EXEC_MOD_2 | AA_EXEC_MOD_3) + +#define AA_EXEC_TYPE (AA_EXEC_UNSAFE | AA_EXEC_INHERIT | \ + AA_EXEC_MODIFIERS) + +#define AA_EXEC_UNCONFINED AA_EXEC_MOD_0 +#define AA_EXEC_PROFILE AA_EXEC_MOD_1 +#define AA_EXEC_CHILD (AA_EXEC_MOD_0 | AA_EXEC_MOD_1) +/* remaining exec modes are index into profile name table */ +#define AA_EXEC_INDEX(mode) ((mode & AA_EXEC_MODIFIERS) >> 10) + +#define AA_USER_SHIFT 0 +#define AA_OTHER_SHIFT 14 + +#define AA_USER_PERMS (AA_BASE_PERMS << AA_USER_SHIFT) +#define AA_OTHER_PERMS (AA_BASE_PERMS << AA_OTHER_SHIFT) + +#define AA_FILE_PERMS (AA_USER_PERMS | AA_OTHER_PERMS) + +#define AA_LINK_BITS ((AA_MAY_LINK << AA_USER_SHIFT) | \ + (AA_MAY_LINK << AA_OTHER_SHIFT)) + +#define AA_USER_EXEC (MAY_EXEC << AA_USER_SHIFT) +#define AA_OTHER_EXEC (MAY_EXEC << AA_OTHER_SHIFT) + +#define AA_USER_EXEC_TYPE (AA_EXEC_TYPE << AA_USER_SHIFT) +#define AA_OTHER_EXEC_TYPE (AA_EXEC_TYPE << AA_OTHER_SHIFT) + +#define AA_EXEC_BITS (AA_USER_EXEC | AA_OTHER_EXEC) + +#define ALL_AA_EXEC_UNSAFE ((AA_EXEC_UNSAFE << AA_USER_SHIFT) | \ + (AA_EXEC_UNSAFE << AA_OTHER_SHIFT)) + +#define ALL_AA_EXEC_TYPE (AA_USER_EXEC_TYPE | AA_OTHER_EXEC_TYPE) + +/* overloaded permissions for link pairs */ +#define AA_LINK_SUBSET_TEST 0x0020 + +#define AA_USER_PTRACE 0x10000000 +#define AA_OTHER_PTRACE 0x20000000 +#define AA_PTRACE_PERMS (AA_USER_PTRACE | AA_OTHER_PTRACE) + +/* shared permissions that are not duplicated in user::other */ +#define AA_CHANGE_HAT 0x40000000 +#define AA_CHANGE_PROFILE 0x80000000 + +#define AA_SHARED_PERMS (AA_CHANGE_HAT | AA_CHANGE_PROFILE) + +#define AA_VALID_PERM_MASK (AA_FILE_PERMS | AA_PTRACE_PERMS | \ + AA_SHARED_PERMS) + +/* audit bits for the second accept field */ +#define AUDIT_FILE_MASK 0x1fc07f +#define AUDIT_QUIET_MASK(mask) ((mask >> 7) & AUDIT_FILE_MASK) +#define AA_VALID_PERM2_MASK 0x0fffffff + +#define AA_SECURE_EXEC_NEEDED 1 + +/* Control parameters (0 or 1), settable thru module/boot flags or + * via /sys/kernel/security/apparmor/control */ +extern int apparmor_complain; +extern int apparmor_debug; +extern int apparmor_audit; +extern int apparmor_logsyscall; +extern unsigned int apparmor_path_max; + +#define PROFILE_COMPLAIN(_profile) \ + (apparmor_complain == 1 || ((_profile) && (_profile)->flags.complain)) + +#define APPARMOR_COMPLAIN(_cxt) \ + (apparmor_complain == 1 || \ + ((_cxt) && (_cxt)->profile && (_cxt)->profile->flags.complain)) + +#define PROFILE_AUDIT(_profile) \ + (apparmor_audit == 1 || ((_profile) && (_profile)->flags.audit)) + +#define APPARMOR_AUDIT(_cxt) \ + (apparmor_audit == 1 || \ + ((_cxt) && (_cxt)->profile && (_cxt)->profile->flags.audit)) + +#define PROFILE_IS_HAT(_profile) \ + ((_profile) && (_profile)->flags.hat) + +/* + * DEBUG remains global (no per profile flag) since it is mostly used in sysctl + * which is not related to profile accesses. + */ + +#define AA_DEBUG(fmt, args...) \ + do { \ + if (apparmor_debug) \ + printk(KERN_DEBUG "AppArmor: " fmt, ##args); \ + } while (0) + +#define AA_ERROR(fmt, args...) printk(KERN_ERR "AppArmor: " fmt, ##args) + +/* struct aa_rlimit - rlimits settings for the profile + * @mask: which hard limits to set + * @limits: rlimit values that override task limits + * + * AppArmor rlimits are used to set confined task rlimits. Only the + * limits specified in @mask will be controlled by apparmor. + */ +struct aa_rlimit { + unsigned int mask; + struct rlimit limits[RLIM_NLIMITS]; +}; + +struct aa_profile; + +/* struct aa_namespace - namespace for a set of profiles + * @name: the name of the namespace + * @list: list the namespace is on + * @profiles: list of profile in the namespace + * @profile_count: the number of profiles in the namespace + * @null_complain_profile: special profile used for learning in this namespace + * @count: reference count on the namespace + * @lock: lock for adding/removing profile to the namespace + */ +struct aa_namespace { + char *name; + struct list_head list; + struct list_head profiles; + int profile_count; + struct aa_profile *null_complain_profile; + + struct kref count; + rwlock_t lock; +}; + +/* struct aa_profile - basic confinement data + * @name: the profiles name + * @list: list this profile is on + * @ns: namespace the profile is in + * @file_rules: dfa containing the profiles file rules + * @flags: flags controlling profile behavior + * @isstale: flag indicating if profile is stale + * @set_caps: capabilities that are being set + * @capabilities: capabilities mask + * @audit_caps: caps that are to be audited + * @quiet_caps: caps that should not be audited + * @capabilities: capabilities granted by the process + * @rlimits: rlimits for the profile + * @task_count: how many tasks the profile is attached to + * @count: reference count of the profile + * @task_contexts: list of tasks confined by profile + * @lock: lock for the task_contexts list + * @network_families: basic network permissions + * @audit_network: which network permissions to force audit + * @quiet_network: which network permissions to quiet rejects + * + * The AppArmor profile contains the basic confinement data. Each profile + * has a name, and all nonstale profile are in a profile namespace. + * + * The task_contexts list and the isstale flag are protected by the + * profile lock. + * + * If a task context is moved between two profiles, we first need to grab + * both profile locks. lock_both_profiles() does that in a deadlock-safe + * way. + */ +struct aa_profile { + char *name; + struct list_head list; + struct aa_namespace *ns; + + int exec_table_size; + char **exec_table; + struct aa_dfa *file_rules; + struct { + int hat; + int complain; + int audit; + } flags; + int isstale; + + kernel_cap_t set_caps; + kernel_cap_t capabilities; + kernel_cap_t audit_caps; + kernel_cap_t quiet_caps; + + struct aa_rlimit rlimits; + unsigned int task_count; + + struct kref count; + struct list_head task_contexts; + spinlock_t lock; + unsigned long int_flags; + u16 network_families[AF_MAX]; + u16 audit_network[AF_MAX]; + u16 quiet_network[AF_MAX]; +}; + +extern struct list_head profile_ns_list; +extern rwlock_t profile_ns_list_lock; +extern struct mutex aa_interface_lock; + +/** + * struct aa_task_context - primary label for confined tasks + * @profile: the current profile + * @previous_profile: profile the task may return to + * @cookie: magic value the task must know for returning to @previous_profile + * @list: list this aa_task_context is on + * @task: task that the aa_task_context confines + * @rcu: rcu head used when freeing the aa_task_context + * @caps_logged: caps that have previously generated log entries + * + * Contains the task's current profile (which could change due to + * change_hat). Plus the hat_magic needed during change_hat. + */ +struct aa_task_context { + struct aa_profile *profile; + struct aa_profile *previous_profile; + u64 cookie; + struct list_head list; + struct task_struct *task; + struct rcu_head rcu; + kernel_cap_t caps_logged; +}; + +extern struct aa_namespace *default_namespace; + +/* aa_audit - AppArmor auditing structure + * Structure is populated by access control code and passed to aa_audit which + * provides for a single point of logging. + */ + +struct aa_audit { + const char *operation; + gfp_t gfp_mask; + const char *info; + const char *name; + const char *name2; + const char *name3; + int request_mask, denied_mask, audit_mask; + int rlimit; + struct iattr *iattr; + pid_t task, parent; + int family, type, protocol; + int error_code; +}; + +/* Flags for the permission check functions */ +#define AA_CHECK_FD 1 /* coming from a file descriptor */ +#define AA_CHECK_DIR 2 /* file type is directory */ + +/* lock subtypes so lockdep does not raise false dependencies */ +enum aa_lock_class { + aa_lock_normal, + aa_lock_nested, + aa_lock_task_release +}; + +/* main.c */ +extern int alloc_default_namespace(void); +extern void free_default_namespace(void); +extern int aa_audit_message(struct aa_profile *profile, struct aa_audit *sa, + int type); +void aa_audit_hint(struct aa_profile *profile, struct aa_audit *sa); +void aa_audit_status(struct aa_profile *profile, struct aa_audit *sa); +int aa_audit_reject(struct aa_profile *profile, struct aa_audit *sa); +extern int aa_audit_syscallreject(struct aa_profile *profile, gfp_t gfp, + const char *); +extern int aa_audit(struct aa_profile *profile, struct aa_audit *); + +extern int aa_attr(struct aa_profile *profile, struct dentry *dentry, + struct vfsmount *mnt, struct iattr *iattr); +extern int aa_perm_xattr(struct aa_profile *profile, const char *operation, + struct dentry *dentry, struct vfsmount *mnt, + int mask, int check); +extern int aa_capability(struct aa_task_context *cxt, int cap); +extern int aa_perm(struct aa_profile *profile, const char *operation, + struct dentry *dentry, struct vfsmount *mnt, int mask, + int check); +extern int aa_perm_dir(struct aa_profile *profile, const char *operation, + struct dentry *dentry, struct vfsmount *mnt, + int mask); +extern int aa_perm_path(struct aa_profile *, const char *operation, + const char *name, int mask, uid_t uid); +extern int aa_link(struct aa_profile *profile, + struct dentry *link, struct vfsmount *link_mnt, + struct dentry *target, struct vfsmount *target_mnt); +extern int aa_clone(struct task_struct *task); +extern int aa_register(struct linux_binprm *bprm); +extern void aa_release(struct task_struct *task); +extern int aa_change_hat(const char *id, u64 hat_magic); +extern int aa_change_profile(const char *ns_name, const char *name); +extern struct aa_profile *__aa_replace_profile(struct task_struct *task, + struct aa_profile *profile); +extern struct aa_task_context *lock_task_and_profiles(struct task_struct *task, + struct aa_profile *profile); +extern void unlock_task_and_profiles(struct task_struct *task, + struct aa_task_context *cxt, + struct aa_profile *profile); +extern void aa_change_task_context(struct task_struct *task, + struct aa_task_context *new_cxt, + struct aa_profile *profile, u64 cookie, + struct aa_profile *previous_profile); +extern int aa_may_ptrace(struct aa_task_context *cxt, + struct aa_profile *tracee); +extern int aa_net_perm(struct aa_profile *profile, char *operation, + int family, int type, int protocol); +extern int aa_revalidate_sk(struct sock *sk, char *operation); +extern int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource, + struct rlimit *new_rlim); +extern void aa_set_rlimits(struct task_struct *task, struct aa_profile *profile); + + +/* lsm.c */ +extern int apparmor_initialized; +extern void info_message(const char *str); +extern void apparmor_disable(void); + +/* list.c */ +extern struct aa_namespace *__aa_find_namespace(const char *name, + struct list_head *list); +extern struct aa_profile *__aa_find_profile(const char *name, + struct list_head *list); +extern void aa_profile_ns_list_release(void); + +/* module_interface.c */ +extern ssize_t aa_add_profile(void *, size_t); +extern ssize_t aa_replace_profile(void *, size_t); +extern ssize_t aa_remove_profile(char *, size_t); +extern struct aa_namespace *alloc_aa_namespace(char *name); +extern void free_aa_namespace(struct aa_namespace *ns); +extern void free_aa_namespace_kref(struct kref *kref); +extern struct aa_profile *alloc_aa_profile(void); +extern void free_aa_profile(struct aa_profile *profile); +extern void free_aa_profile_kref(struct kref *kref); +extern void aa_unconfine_tasks(struct aa_profile *profile); + +/* procattr.c */ +extern int aa_getprocattr(struct aa_profile *profile, char **string, + unsigned *len); +extern int aa_setprocattr_changehat(char *args); +extern int aa_setprocattr_changeprofile(char *args); +extern int aa_setprocattr_setprofile(struct task_struct *task, char *args); + +/* apparmorfs.c */ +extern int create_apparmorfs(void); +extern void destroy_apparmorfs(void); + +/* match.c */ +extern struct aa_dfa *aa_match_alloc(void); +extern void aa_match_free(struct aa_dfa *dfa); +extern int unpack_dfa(struct aa_dfa *dfa, void *blob, size_t size); +extern int verify_dfa(struct aa_dfa *dfa); +extern unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str, int *); +extern unsigned int aa_dfa_next_state(struct aa_dfa *dfa, unsigned int start, + const char *str); +extern unsigned int aa_match_state(struct aa_dfa *dfa, unsigned int start, + const char *str, unsigned int *final); +extern unsigned int aa_dfa_null_transition(struct aa_dfa *dfa, + unsigned int start); + +#endif /* __APPARMOR_H */ --- linux-2.6.27.orig/security/apparmor/match.h +++ linux-2.6.27/security/apparmor/match.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2007 Novell/SUSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * AppArmor submodule (match) prototypes + */ + +#ifndef __MATCH_H +#define __MATCH_H + +#define DFA_START 1 + +/** + * The format used for transition tables is based on the GNU flex table + * file format (--tables-file option; see Table File Format in the flex + * info pages and the flex sources for documentation). The magic number + * used in the header is 0x1B5E783D insted of 0xF13C57B1 though, because + * the YY_ID_CHK (check) and YY_ID_DEF (default) tables are used + * slightly differently (see the apparmor-parser package). + */ + +#define YYTH_MAGIC 0x1B5E783D + +struct table_set_header { + u32 th_magic; /* YYTH_MAGIC */ + u32 th_hsize; + u32 th_ssize; + u16 th_flags; + char th_version[]; +}; + +#define YYTD_ID_ACCEPT 1 +#define YYTD_ID_BASE 2 +#define YYTD_ID_CHK 3 +#define YYTD_ID_DEF 4 +#define YYTD_ID_EC 5 +#define YYTD_ID_META 6 +#define YYTD_ID_ACCEPT2 7 +#define YYTD_ID_NXT 8 + + +#define YYTD_DATA8 1 +#define YYTD_DATA16 2 +#define YYTD_DATA32 4 + +struct table_header { + u16 td_id; + u16 td_flags; + u32 td_hilen; + u32 td_lolen; + char td_data[]; +}; + +#define DEFAULT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_DEF - 1]->td_data)) +#define BASE_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_BASE - 1]->td_data)) +#define NEXT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_NXT - 1]->td_data)) +#define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK - 1]->td_data)) +#define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC - 1]->td_data)) +#define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT - 1]->td_data)) +#define ACCEPT_TABLE2(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT2 -1]->td_data)) + +struct aa_dfa { + struct table_header *tables[YYTD_ID_NXT]; +}; + +#define byte_to_byte(X) (X) + +#define UNPACK_ARRAY(TABLE, BLOB, LEN, TYPE, NTOHX) \ + do { \ + typeof(LEN) __i; \ + TYPE *__t = (TYPE *) TABLE; \ + TYPE *__b = (TYPE *) BLOB; \ + for (__i = 0; __i < LEN; __i++) { \ + __t[__i] = NTOHX(__b[__i]); \ + } \ + } while (0) + +static inline size_t table_size(size_t len, size_t el_size) +{ + return ALIGN(sizeof(struct table_header) + len * el_size, 8); +} + +#endif /* __MATCH_H */ --- linux-2.6.27.orig/security/apparmor/Kconfig +++ linux-2.6.27/security/apparmor/Kconfig @@ -0,0 +1,42 @@ +config SECURITY_APPARMOR + bool "AppArmor support" + depends on SECURITY + select AUDIT + help + This enables the AppArmor security module. + Required userspace tools (if they are not included in your + distribution) and further information may be found at + + + If you are unsure how to answer this question, answer N. + +config SECURITY_APPARMOR_BOOTPARAM_VALUE + int "AppArmor boot parameter default value" + depends on SECURITY_APPARMOR + range 0 1 + default 1 + help + This option sets the default value for the kernel parameter + 'apparmor', which allows AppArmor to be enabled or disabled + at boot. If this option is set to 0 (zero), the AppArmor + kernel parameter will default to 0, disabling AppArmor at + bootup. If this option is set to 1 (one), the AppArmor + kernel parameter will default to 1, enabling AppArmor at + bootup. + + If you are unsure how to answer this question, answer 1. + +config SECURITY_APPARMOR_DISABLE + bool "AppArmor runtime disable" + depends on SECURITY_APPARMOR + default n + help + This option enables writing to a apparmorfs node 'disable', which + allows AppArmor to be disabled at runtime prior to the policy load. + AppArmor will then remain disabled until the next boot. + This option is similar to the apparmor.enabled=0 boot parameter, + but is to support runtime disabling of AppArmor, e.g. from + /sbin/init, for portability across platforms where boot + parameters are difficult to employ. + + If you are unsure how to answer this question, answer N. --- linux-2.6.27.orig/security/apparmor/procattr.c +++ linux-2.6.27/security/apparmor/procattr.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) 1998-2007 Novell/SUSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * AppArmor /proc/pid/attr handling + */ + +#include "apparmor.h" +#include "inline.h" + +int aa_getprocattr(struct aa_profile *profile, char **string, unsigned *len) +{ + char *str; + + if (profile) { + const char *mode_str = PROFILE_COMPLAIN(profile) ? + " (complain)" : " (enforce)"; + int mode_len, name_len, ns_len = 0; + + mode_len = strlen(mode_str); + name_len = strlen(profile->name); + if (profile->ns != default_namespace) + ns_len = strlen(profile->ns->name) + 2; + *len = mode_len + ns_len + name_len + 1; + str = kmalloc(*len, GFP_ATOMIC); + if (!str) + return -ENOMEM; + + if (ns_len) { + *str++ = ':'; + memcpy(str, profile->ns->name, ns_len - 2); + str += ns_len - 2; + *str++ = ':'; + } + memcpy(str, profile->name, name_len); + str += name_len; + memcpy(str, mode_str, mode_len); + str += mode_len; + *str++ = '\n'; + str -= *len; + } else { + const char *unconfined_str = "unconfined\n"; + + *len = strlen(unconfined_str); + str = kmalloc(*len, GFP_ATOMIC); + if (!str) + return -ENOMEM; + + memcpy(str, unconfined_str, *len); + } + *string = str; + + return 0; +} + +static char *split_token_from_name(const char *op, char *args, u64 *cookie) +{ + char *name; + + *cookie = simple_strtoull(args, &name, 16); + if ((name == args) || *name != '^') { + AA_ERROR("%s: Invalid input '%s'", op, args); + return ERR_PTR(-EINVAL); + } + + name++; /* skip ^ */ + if (!*name) + name = NULL; + return name; +} + +int aa_setprocattr_changehat(char *args) +{ + char *hat; + u64 cookie; + + hat = split_token_from_name("change_hat", args, &cookie); + if (IS_ERR(hat)) + return PTR_ERR(hat); + + if (!hat && !cookie) { + AA_ERROR("change_hat: Invalid input, NULL hat and NULL magic"); + return -EINVAL; + } + + AA_DEBUG("%s: Magic 0x%llx Hat '%s'\n", + __FUNCTION__, cookie, hat ? hat : NULL); + + return aa_change_hat(hat, cookie); +} + +int aa_setprocattr_changeprofile(char *args) +{ + char *name = args, *ns_name = NULL; + + if (name[0] == ':') { + char *split = strchr(&name[1], ':'); + if (split) { + *split = 0; + ns_name = &name[1]; + name = split + 1; + } + } + + return aa_change_profile(ns_name, name); +} + +int aa_setprocattr_setprofile(struct task_struct *task, char *args) +{ + struct aa_profile *old_profile, *new_profile; + struct aa_namespace *ns; + struct aa_audit sa; + char *name, *ns_name = NULL; + + memset(&sa, 0, sizeof(sa)); + sa.operation = "profile_set"; + sa.gfp_mask = GFP_KERNEL; + sa.task = task->pid; + + AA_DEBUG("%s: current %d\n", + __FUNCTION__, current->pid); + + name = args; + if (args[0] != '/') { + char *split = strchr(args, ':'); + if (split) { + *split = 0; + ns_name = args; + name = split + 1; + } + } + if (ns_name) + ns = aa_find_namespace(ns_name); + else + ns = aa_get_namespace(default_namespace); + if (!ns) { + sa.name = ns_name; + sa.info = "unknown namespace"; + aa_audit_reject(NULL, &sa); + aa_put_namespace(ns); + return -EINVAL; + } + +repeat: + if (strcmp(name, "unconfined") == 0) + new_profile = NULL; + else { + new_profile = aa_find_profile(ns, name); + if (!new_profile) { + sa.name = ns_name; + sa.name2 = name; + sa.info = "unknown profile"; + aa_audit_reject(NULL, &sa); + aa_put_namespace(ns); + return -EINVAL; + } + } + + old_profile = __aa_replace_profile(task, new_profile); + if (IS_ERR(old_profile)) { + int error; + + aa_put_profile(new_profile); + error = PTR_ERR(old_profile); + if (error == -ESTALE) + goto repeat; + aa_put_namespace(ns); + return error; + } + + if (new_profile) { + sa.name = ns_name; + sa.name2 = name; + sa.name3 = old_profile ? old_profile->name : + "unconfined"; + aa_audit_status(NULL, &sa); + } else { + if (old_profile) { + sa.name = "unconfined"; + sa.name2 = old_profile->name; + aa_audit_status(NULL, &sa); + } else { + sa.info = "task is unconfined"; + aa_audit_status(NULL, &sa); + } + } + aa_put_namespace(ns); + aa_put_profile(old_profile); + aa_put_profile(new_profile); + return 0; +} --- linux-2.6.27.orig/security/apparmor/Makefile +++ linux-2.6.27/security/apparmor/Makefile @@ -0,0 +1,18 @@ +# Makefile for AppArmor Linux Security Module +# +obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o + +apparmor-y := main.o list.o procattr.o lsm.o apparmorfs.o \ + module_interface.o match.o + +quiet_cmd_make-caps = GEN $@ +cmd_make-caps = sed -n -e "/CAP_FS_MASK/d" -e "s/^\#define[ \\t]\\+CAP_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\$$/[\\2] = \"\\1\",/p" $< | tr A-Z a-z > $@ + +quiet_cmd_make-af = GEN $@ +cmd_make-af = sed -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "s/^\#define[ \\t]\\+AF_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/[\\2] = \"\\1\",/p" $< | tr A-Z a-z > $@ + +$(obj)/main.o : $(obj)/capability_names.h $(obj)/af_names.h +$(obj)/capability_names.h : $(srctree)/include/linux/capability.h + $(call cmd,make-caps) +$(obj)/af_names.h : $(srctree)/include/linux/socket.h + $(call cmd,make-af) --- linux-2.6.27.orig/security/apparmor/locking.txt +++ linux-2.6.27/security/apparmor/locking.txt @@ -0,0 +1,68 @@ +Locking in AppArmor +=================== + +Lock hierarchy: + + aa_interface_lock + profile_list_lock + aa_profile->lock + task_lock() + + +Which lock protects what? + + /-----------------------+-------------------------------\ + | Variable | Lock | + >-----------------------+-------------------------------< + | profile_list | profile_list_lock | + +-----------------------+-------------------------------+ + | aa_profile | (reference count) | + +-----------------------+-------------------------------+ + | aa_profile-> | aa_profile->lock | + | isstale, | | + | task_contexts | | + +-----------------------+-------------------------------+ + | task_struct->security | read: RCU | + | | write: task_lock() | + +-----------------------+-------------------------------+ + | aa_profile->sub | handle on the profile (list | + | | is never modified) | + \-----------------------+-------------------------------/ + +(Obviously, the list_heads embedded in data structures are always +protected with the lock that also protects the list.) + +When moving a task context from one profile to another, we grab both +profile locks with lock_both_profiles(). This ensures that both locks +are always taken in the same order, and so we won't deadlock. + +Since task_struct->security is RCU protected the aa_task_struct it +references is only guarenteed to exist for the rcu cycle. Where +aa_task_context->profile is needed in blocking operations the +profile's reference count is incremented and the profile reference +is used. + +Profiles on profile_list are never stale: when a profile becomes stale, +it is removed from profile_list at the same time (under profile_list_lock +and aa_profile->lock). + +The aa_interface_lock is taken whenever user-space modifies the profile +list, and can sleep. This ensures that profile loading/replacement/removal +won't race with itself. We release the profile_list_lock as soon as +possible to avoid stalling exec during profile loading/replacement/removal. + +AppArmor uses lock subtyping to avoid false positives from lockdep. The +profile lock is often taken nested, but it is guaranteed to be in a lock +safe order and not the same lock when done, so it is safe. + +A third lock type (aa_lock_task_release) is given to the profile lock +when it is taken in soft irq context during task release (aa_release). +This is to avoid a false positive between the task lock and the profile +lock. In task context the profile lock wraps the task lock with irqs +off, but the kernel takes the task lock with irqs enabled. This won't +result in a deadlock because for a deadlock to occur the kernel must +take dead task A's lock (irqs on), the rcu callback hook freeing +dead task A must be run and AppArmor must be changing the profile on +dead task A. The kernel should not be taking a dead task's task_lock +at the same time the task is being freed by task rcu cleanup other wise +the task would not be out of its quiescent period. --- linux-2.6.27.orig/security/apparmor/list.c +++ linux-2.6.27/security/apparmor/list.c @@ -0,0 +1,174 @@ +/* + * Copyright (C) 1998-2007 Novell/SUSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * AppArmor Profile List Management + */ + +#include +#include "apparmor.h" +#include "inline.h" + +/* list of profile namespaces and lock */ +LIST_HEAD(profile_ns_list); +rwlock_t profile_ns_list_lock = RW_LOCK_UNLOCKED; + +/** + * __aa_find_namespace - look up a profile namespace on the namespace list + * @name: name of namespace to find + * @head: list to search + * + * Returns a pointer to the namespace on the list, or NULL if no namespace + * called @name exists. The caller must hold the profile_ns_list_lock. + */ +struct aa_namespace *__aa_find_namespace(const char *name, + struct list_head *head) +{ + struct aa_namespace *ns; + + list_for_each_entry(ns, head, list) { + if (!strcmp(ns->name, name)) + return ns; + } + + return NULL; +} + +/** + * __aa_find_profile - look up a profile on the profile list + * @name: name of profile to find + * @head: list to search + * + * Returns a pointer to the profile on the list, or NULL if no profile + * called @name exists. The caller must hold the profile_list_lock. + */ +struct aa_profile *__aa_find_profile(const char *name, struct list_head *head) +{ + struct aa_profile *profile; + + list_for_each_entry(profile, head, list) { + if (!strcmp(profile->name, name)) + return profile; + } + + return NULL; +} + +static void aa_profile_list_release(struct list_head *head) +{ + struct aa_profile *profile, *tmp; + list_for_each_entry_safe(profile, tmp, head, list) { + /* Remove the profile from each task context it is on. */ + lock_profile(profile); + profile->isstale = 1; + aa_unconfine_tasks(profile); + list_del_init(&profile->list); + unlock_profile(profile); + aa_put_profile(profile); + } +} + +/** + * aa_profilelist_release - Remove all profiles from profile_list + */ +void aa_profile_ns_list_release(void) +{ + struct aa_namespace *ns, *tmp; + + /* Remove and release all the profiles on namespace profile lists. */ + write_lock(&profile_ns_list_lock); + list_for_each_entry_safe(ns, tmp, &profile_ns_list, list) { + write_lock(&ns->lock); + aa_profile_list_release(&ns->profiles); + list_del_init(&ns->list); + write_unlock(&ns->lock); + aa_put_namespace(ns); + } + write_unlock(&profile_ns_list_lock); +} + + +static struct aa_profile *next_profile(struct aa_profile *profile) +{ + struct aa_profile *next = profile; + struct aa_namespace *ns; + + list_for_each_entry_continue(next, &profile->ns->profiles, list) + return next; + + ns = profile->ns; + read_unlock(&ns->lock); + list_for_each_entry_continue(ns, &profile_ns_list, list) { + read_lock(&ns->lock); + list_for_each_entry(profile, &ns->profiles, list) + return profile; + read_unlock(&ns->lock); + } + return NULL; +} + +static void *p_start(struct seq_file *f, loff_t *pos) +{ + struct aa_namespace *ns; + loff_t l = *pos; + + read_lock(&profile_ns_list_lock); + if (!list_empty(&profile_ns_list)) { + struct aa_profile *profile = NULL; + ns = list_first_entry(&profile_ns_list, typeof(*ns), list); + read_lock(&ns->lock); + if (!list_empty(&ns->profiles)) + profile = list_first_entry(&ns->profiles, + typeof(*profile), list); + else + read_unlock(&ns->lock); + for ( ; profile && l > 0; l--) + profile = next_profile(profile); + return profile; + } + return NULL; +} + +static void *p_next(struct seq_file *f, void *p, loff_t *pos) +{ + struct aa_profile *profile = (struct aa_profile *) p; + + (*pos)++; + profile = next_profile(profile); + + return profile; +} + +static void p_stop(struct seq_file *f, void *p) +{ + struct aa_profile *profile = (struct aa_profile *) p; + + if (profile) + read_unlock(&profile->ns->lock); + read_unlock(&profile_ns_list_lock); +} + +static int seq_show_profile(struct seq_file *f, void *p) +{ + struct aa_profile *profile = (struct aa_profile *)p; + + if (profile->ns == default_namespace) + seq_printf(f, "%s (%s)\n", profile->name, + PROFILE_COMPLAIN(profile) ? "complain" : "enforce"); + else + seq_printf(f, ":%s:%s (%s)\n", profile->ns->name, profile->name, + PROFILE_COMPLAIN(profile) ? "complain" : "enforce"); + return 0; +} + +/* Used in apparmorfs.c */ +struct seq_operations apparmorfs_profiles_op = { + .start = p_start, + .next = p_next, + .stop = p_stop, + .show = seq_show_profile, +}; --- linux-2.6.27.orig/security/apparmor/lsm.c +++ linux-2.6.27/security/apparmor/lsm.c @@ -0,0 +1,1060 @@ +/* + * Copyright (C) 1998-2007 Novell/SUSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * AppArmor LSM interface + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "apparmor.h" +#include "inline.h" + +/* Flag indicating whether initialization completed */ +int apparmor_initialized = 0; + +static int param_set_aabool(const char *val, struct kernel_param *kp); +static int param_get_aabool(char *buffer, struct kernel_param *kp); +#define param_check_aabool(name, p) __param_check(name, p, int) + +static int param_set_aauint(const char *val, struct kernel_param *kp); +static int param_get_aauint(char *buffer, struct kernel_param *kp); +#define param_check_aauint(name, p) __param_check(name, p, int) + +/* Flag values, also controllable via /sys/module/apparmor/parameters + * We define special types as we want to do additional mediation. + * + * Complain mode -- in complain mode access failures result in auditing only + * and task is allowed access. audit events are processed by userspace to + * generate policy. Default is 'enforce' (0). + * Value is also togglable per profile and referenced when global value is + * enforce. + */ +int apparmor_complain = 0; +module_param_named(complain, apparmor_complain, aabool, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(apparmor_complain, "Toggle AppArmor complain mode"); + +/* Debug mode */ +int apparmor_debug = 0; +module_param_named(debug, apparmor_debug, aabool, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(apparmor_debug, "Toggle AppArmor debug mode"); + +/* Audit mode */ +int apparmor_audit = 0; +module_param_named(audit, apparmor_audit, aabool, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(apparmor_audit, "Toggle AppArmor audit mode"); + +/* Syscall logging mode */ +int apparmor_logsyscall = 0; +module_param_named(logsyscall, apparmor_logsyscall, aabool, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(apparmor_logsyscall, "Toggle AppArmor logsyscall mode"); + +/* Maximum pathname length before accesses will start getting rejected */ +unsigned int apparmor_path_max = 2 * PATH_MAX; +module_param_named(path_max, apparmor_path_max, aauint, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(apparmor_path_max, "Maximum pathname length allowed"); + +/* Boot time disable flag */ +#ifdef CONFIG_SECURITY_APPARMOR_DISABLE +#define AA_ENABLED_PERMS 0600 +#else +#define AA_ENABLED_PERMS 0400 +#endif +static int param_set_aa_enabled(const char *val, struct kernel_param *kp); +unsigned int apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE; +module_param_call(enabled, param_set_aa_enabled, param_get_aauint, + &apparmor_enabled, AA_ENABLED_PERMS); +MODULE_PARM_DESC(apparmor_enabled, "Enable/Disable Apparmor on boot"); + +static int __init apparmor_enabled_setup(char *str) +{ + apparmor_enabled = simple_strtol(str, NULL, 0); + return 1; +} +__setup("apparmor=", apparmor_enabled_setup); + +static int param_set_aabool(const char *val, struct kernel_param *kp) +{ + if (aa_task_context(current)) + return -EPERM; + return param_set_bool(val, kp); +} + +static int param_get_aabool(char *buffer, struct kernel_param *kp) +{ + if (aa_task_context(current)) + return -EPERM; + return param_get_bool(buffer, kp); +} + +static int param_set_aauint(const char *val, struct kernel_param *kp) +{ + if (aa_task_context(current)) + return -EPERM; + return param_set_uint(val, kp); +} + +static int param_get_aauint(char *buffer, struct kernel_param *kp) +{ + if (aa_task_context(current)) + return -EPERM; + return param_get_uint(buffer, kp); +} + +/* allow run time disabling of apparmor */ +static int param_set_aa_enabled(const char *val, struct kernel_param *kp) +{ + char *endp; + unsigned long l; + + if (!apparmor_initialized) { + apparmor_enabled = 0; + return 0; + } + + if (aa_task_context(current)) + return -EPERM; + + if (!apparmor_enabled) + return -EINVAL; + + if (!val) + return -EINVAL; + + l = simple_strtoul(val, &endp, 0); + if (endp == val || l != 0) + return -EINVAL; + + apparmor_enabled = 0; + apparmor_disable(); + return 0; +} + +static int aa_reject_syscall(struct task_struct *task, gfp_t flags, + const char *name) +{ + struct aa_profile *profile = aa_get_profile(task); + int error = 0; + + if (profile) { + error = aa_audit_syscallreject(profile, flags, name); + aa_put_profile(profile); + } + + return error; +} + +static int apparmor_ptrace(struct task_struct *tracer, + struct task_struct *tracee) +{ + struct aa_task_context *cxt; + int error = 0; + + /* + * tracer can ptrace tracee when + * - tracer is unconfined + * - tracer & tracee are in the same namespace && + * - tracer is in complain mode + * - tracer and tracee are confined by the same profile + * - tracer profile has CAP_SYS_PTRACE + */ + + rcu_read_lock(); + cxt = aa_task_context(tracer); + if (cxt) { + if (tracer->nsproxy != tracee->nsproxy) { + struct aa_audit sa; + memset(&sa, 0, sizeof(sa)); + sa.operation = "ptrace"; + sa.gfp_mask = GFP_ATOMIC; + sa.parent = tracer->pid; + sa.task = tracee->pid; + sa.info = "different namespaces"; + aa_audit_reject(cxt->profile, &sa); + error = -EPERM; + } else { + struct aa_task_context *tracee_cxt = + aa_task_context(tracee); + + error = aa_may_ptrace(cxt, tracee_cxt ? + tracee_cxt->profile : NULL); + if (error && PROFILE_COMPLAIN(cxt->profile)) { + struct aa_audit sa; + memset(&sa, 0, sizeof(sa)); + sa.operation = "ptrace"; + sa.gfp_mask = GFP_ATOMIC; + sa.parent = tracer->pid; + sa.task = tracee->pid; + aa_audit_hint(cxt->profile, &sa); + } + } + } + rcu_read_unlock(); + + return error; +} + +static int apparmor_ptrace_may_access(struct task_struct *child, + unsigned int mode) +{ + return apparmor_ptrace(current, child); +} + + +static int apparmor_ptrace_traceme(struct task_struct *parent) +{ + return apparmor_ptrace(parent, current); +} + +static int apparmor_capable(struct task_struct *task, int cap) +{ + int error; + struct aa_task_context *cxt; + + /* cap_capable returns 0 on success, else -EPERM */ + error = cap_capable(task, cap); + + rcu_read_lock(); + cxt = aa_task_context(task); + if (cxt && (!error || cap_raised(cxt->profile->set_caps, cap))) + error = aa_capability(cxt, cap); + rcu_read_unlock(); + + return error; +} + +static int apparmor_sysctl(struct ctl_table *table, int op) +{ + struct aa_profile *profile = aa_get_profile(current); + int error = 0; + + if (profile) { + char *buffer, *name; + int mask; + + mask = 0; + if (op & 4) + mask |= MAY_READ; + if (op & 2) + mask |= MAY_WRITE; + + error = -ENOMEM; + buffer = (char*)__get_free_page(GFP_KERNEL); + if (!buffer) + goto out; + name = sysctl_pathname(table, buffer, PAGE_SIZE); + if (name && name - buffer >= 5) { + name -= 5; + memcpy(name, "/proc", 5); + error = aa_perm_path(profile, "sysctl", name, mask, 0); + } + free_page((unsigned long)buffer); + } + +out: + aa_put_profile(profile); + return error; +} + +static int apparmor_bprm_set_security(struct linux_binprm *bprm) +{ + /* handle capability bits with setuid, etc */ + cap_bprm_set_security(bprm); + /* already set based on script name */ + if (bprm->sh_bang) + return 0; + return aa_register(bprm); +} + +static int apparmor_bprm_secureexec(struct linux_binprm *bprm) +{ + int ret = cap_bprm_secureexec(bprm); + + if (!ret && (unsigned long)bprm->security & AA_SECURE_EXEC_NEEDED) { + AA_DEBUG("%s: secureexec required for %s\n", + __FUNCTION__, bprm->filename); + ret = 1; + } + + return ret; +} + +static int apparmor_sb_mount(char *dev_name, struct path *path, char *type, + unsigned long flags, void *data) +{ + return aa_reject_syscall(current, GFP_KERNEL, "mount"); +} + +static int apparmor_umount(struct vfsmount *mnt, int flags) +{ + return aa_reject_syscall(current, GFP_KERNEL, "umount"); +} + +static int apparmor_inode_mkdir(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mask) +{ + struct aa_profile *profile; + int error = 0; + + if (!mnt || !mediated_filesystem(dir)) + goto out; + + profile = aa_get_profile(current); + + if (profile) + error = aa_perm_dir(profile, "inode_mkdir", dentry, mnt, + MAY_WRITE); + + aa_put_profile(profile); + +out: + return error; +} + +static int apparmor_inode_rmdir(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt) +{ + struct aa_profile *profile; + int error = 0; + + if (!mnt || !mediated_filesystem(dir)) + goto out; + + profile = aa_get_profile(current); + + if (profile) + error = aa_perm_dir(profile, "inode_rmdir", dentry, mnt, + MAY_WRITE); + + aa_put_profile(profile); + +out: + return error; +} + +static int aa_permission(const char *operation, struct inode *inode, + struct dentry *dentry, struct vfsmount *mnt, + int mask, int check) +{ + int error = 0; + + if (mnt && mediated_filesystem(inode)) { + struct aa_profile *profile; + + profile = aa_get_profile(current); + if (profile) + error = aa_perm(profile, operation, dentry, mnt, mask, + check); + aa_put_profile(profile); + } + return error; +} + +static inline int aa_mask_permissions(int mask) +{ + if (mask & MAY_APPEND) + mask &= (MAY_READ | MAY_APPEND | MAY_EXEC); + else + mask &= (MAY_READ | MAY_WRITE | MAY_EXEC); + return mask; +} + +static int apparmor_inode_create(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mask) +{ + return aa_permission("inode_create", dir, dentry, mnt, MAY_APPEND, 0); +} + +static int apparmor_inode_link(struct dentry *old_dentry, + struct vfsmount *old_mnt, struct inode *dir, + struct dentry *new_dentry, + struct vfsmount *new_mnt) +{ + int error = 0; + struct aa_profile *profile; + + if (!old_mnt || !new_mnt || !mediated_filesystem(dir)) + goto out; + + profile = aa_get_profile(current); + + if (profile) + error = aa_link(profile, new_dentry, new_mnt, + old_dentry, old_mnt); + + aa_put_profile(profile); + +out: + return error; +} + +static int apparmor_inode_unlink(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt) +{ + int check = 0; + + if (S_ISDIR(dentry->d_inode->i_mode)) + check |= AA_CHECK_DIR; + return aa_permission("inode_unlink", dir, dentry, mnt, MAY_WRITE, + check); +} + +static int apparmor_inode_symlink(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, const char *old_name) +{ + return aa_permission("inode_symlink", dir, dentry, mnt, MAY_WRITE, 0); +} + +static int apparmor_inode_mknod(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode, dev_t dev) +{ + return aa_permission("inode_mknod", dir, dentry, mnt, MAY_WRITE, 0); +} + +static int apparmor_inode_rename(struct inode *old_dir, + struct dentry *old_dentry, + struct vfsmount *old_mnt, + struct inode *new_dir, + struct dentry *new_dentry, + struct vfsmount *new_mnt) +{ + struct aa_profile *profile; + int error = 0; + + if ((!old_mnt && !new_mnt) || !mediated_filesystem(old_dir)) + goto out; + + profile = aa_get_profile(current); + + if (profile) { + struct inode *inode = old_dentry->d_inode; + int check = 0; + + if (inode && S_ISDIR(inode->i_mode)) + check |= AA_CHECK_DIR; + if (old_mnt) + error = aa_perm(profile, "inode_rename", old_dentry, + old_mnt, MAY_READ | MAY_WRITE, check); + + if (!error && new_mnt) { + error = aa_perm(profile, "inode_rename", new_dentry, + new_mnt, MAY_WRITE, check); + } + } + + aa_put_profile(profile); + +out: + return error; +} + +static int apparmor_inode_permission(struct inode *inode, int mask) +{ + return 0; +} + +static int apparmor_inode_setattr(struct dentry *dentry, struct vfsmount *mnt, + struct iattr *iattr) +{ + int error = 0; + + if (!mnt) + goto out; + + if (mediated_filesystem(dentry->d_inode)) { + struct aa_profile *profile; + + profile = aa_get_profile(current); + /* + * Mediate any attempt to change attributes of a file + * (chmod, chown, chgrp, etc) + */ + if (profile) + error = aa_attr(profile, dentry, mnt, iattr); + + aa_put_profile(profile); + } + +out: + return error; +} + +static int aa_xattr_permission(struct dentry *dentry, struct vfsmount *mnt, + const char *operation, int mask, + struct file *file) +{ + int error = 0; + + if (mnt && mediated_filesystem(dentry->d_inode)) { + struct aa_profile *profile = aa_get_profile(current); + int check = file ? AA_CHECK_FD : 0; + + if (profile) + error = aa_perm_xattr(profile, operation, dentry, mnt, + mask, check); + aa_put_profile(profile); + } + + return error; +} + +static int apparmor_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, const void *value, + size_t size, int flags, struct file *file) +{ + int error = cap_inode_setxattr(dentry, mnt, name, value, size, flags, + file); + + if (!error) + error = aa_xattr_permission(dentry, mnt, "xattr set", + MAY_WRITE, file); + return error; +} + +static int apparmor_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, struct file *file) +{ + return aa_xattr_permission(dentry, mnt, "xattr get", MAY_READ, file); +} + +static int apparmor_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt, + struct file *file) +{ + return aa_xattr_permission(dentry, mnt, "xattr list", MAY_READ, file); +} + +static int apparmor_inode_removexattr(struct dentry *dentry, + struct vfsmount *mnt, const char *name, + struct file *file) +{ + return aa_xattr_permission(dentry, mnt, "xattr remove", MAY_WRITE, + file); +} + +static int aa_file_permission(const char *op, struct file *file, int mask) +{ + struct aa_profile *profile; + struct aa_profile *file_profile = (struct aa_profile*)file->f_security; + int error = 0; + + if (!file_profile) + goto out; + + /* + * If this file was opened under a different profile, we + * revalidate the access against the current profile. + */ + profile = aa_get_profile(current); + if (profile && (file_profile != profile || mask & AA_MAY_LOCK)) { + struct dentry *dentry = file->f_dentry; + struct vfsmount *mnt = file->f_vfsmnt; + struct inode *inode = dentry->d_inode; + int check = AA_CHECK_FD; + + /* + * FIXME: We should remember which profiles we revalidated + * against. + */ + if (S_ISDIR(inode->i_mode)) + check |= AA_CHECK_DIR; + error = aa_permission(op, inode, dentry, mnt, mask, check); + } + aa_put_profile(profile); + +out: + return error; +} + +static int apparmor_file_permission(struct file *file, int mask) +{ + return aa_file_permission("file_permission", file, + aa_mask_permissions(mask)); +} + +static inline int apparmor_file_lock (struct file *file, unsigned int cmd) +{ + int mask = AA_MAY_LOCK; + if (cmd == F_WRLCK) + mask |= MAY_WRITE; + return aa_file_permission("file_lock", file, mask); +} + +static int apparmor_file_alloc_security(struct file *file) +{ + struct aa_profile *profile; + + profile = aa_get_profile(current); + if (profile) + file->f_security = profile; + + return 0; +} + +static void apparmor_file_free_security(struct file *file) +{ + struct aa_profile *file_profile = (struct aa_profile*)file->f_security; + + aa_put_profile(file_profile); +} + +static inline int aa_mmap(struct file *file, const char *operation, + unsigned long prot, unsigned long flags) +{ + struct dentry *dentry; + int mask = 0; + + if (!file || !file->f_security) + return 0; + + if (prot & PROT_READ) + mask |= MAY_READ; + /* Private mappings don't require write perms since they don't + * write back to the files */ + if ((prot & PROT_WRITE) && !(flags & MAP_PRIVATE)) + mask |= MAY_WRITE; + if (prot & PROT_EXEC) + mask |= AA_EXEC_MMAP; + + dentry = file->f_dentry; + return aa_permission(operation, dentry->d_inode, dentry, + file->f_vfsmnt, mask, AA_CHECK_FD); +} + +static int apparmor_file_mmap(struct file *file, unsigned long reqprot, + unsigned long prot, unsigned long flags, + unsigned long addr, unsigned long addr_only) +{ + if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO)) { + struct aa_profile *profile = aa_get_profile(current); + if (profile) + /* future control check here */ + return -EACCES; + else + return -EACCES; + aa_put_profile(profile); + } + + return aa_mmap(file, "file_mmap", prot, flags); +} + +static int apparmor_file_mprotect(struct vm_area_struct *vma, + unsigned long reqprot, unsigned long prot) +{ + return aa_mmap(vma->vm_file, "file_mprotect", prot, + !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0); +} + +static int apparmor_path_permission(struct path *path, int mask) +{ + struct inode *inode; + int check = 0; + + if (!path) + return 0; + + inode = path->dentry->d_inode; + + mask = aa_mask_permissions(mask); + if (S_ISDIR(inode->i_mode)) { + check |= AA_CHECK_DIR; + /* allow traverse accesses to directories */ + mask &= ~MAY_EXEC; + if (!mask) + return 0; + } + + return aa_permission("inode_permission", inode, path->dentry, + path->mnt, mask, check); +} + +static int apparmor_task_alloc_security(struct task_struct *task) +{ + return aa_clone(task); +} + +/* + * Called from IRQ context from RCU callback. + */ +static void apparmor_task_free_security(struct task_struct *task) +{ + aa_release(task); +} + +static int apparmor_socket_create(int family, int type, int protocol, int kern) +{ + struct aa_profile *profile; + int error = 0; + + if (kern) + return 0; + + profile = aa_get_profile(current); + if (profile) + error = aa_net_perm(profile, "socket_create", family, + type, protocol); + aa_put_profile(profile); + + return error; +} + +static int apparmor_socket_post_create(struct socket *sock, int family, + int type, int protocol, int kern) +{ + struct sock *sk = sock->sk; + + if (kern) + return 0; + + return aa_revalidate_sk(sk, "socket_post_create"); +} + +static int apparmor_socket_bind(struct socket *sock, + struct sockaddr *address, int addrlen) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(sk, "socket_bind"); +} + +static int apparmor_socket_connect(struct socket *sock, + struct sockaddr *address, int addrlen) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(sk, "socket_connect"); +} + +static int apparmor_socket_listen(struct socket *sock, int backlog) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(sk, "socket_listen"); +} + +static int apparmor_socket_accept(struct socket *sock, struct socket *newsock) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(sk, "socket_accept"); +} + +static int apparmor_socket_sendmsg(struct socket *sock, + struct msghdr *msg, int size) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(sk, "socket_sendmsg"); +} + +static int apparmor_socket_recvmsg(struct socket *sock, + struct msghdr *msg, int size, int flags) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(sk, "socket_recvmsg"); +} + +static int apparmor_socket_getsockname(struct socket *sock) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(sk, "socket_getsockname"); +} + +static int apparmor_socket_getpeername(struct socket *sock) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(sk, "socket_getpeername"); +} + +static int apparmor_socket_getsockopt(struct socket *sock, int level, + int optname) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(sk, "socket_getsockopt"); +} + +static int apparmor_socket_setsockopt(struct socket *sock, int level, + int optname) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(sk, "socket_setsockopt"); +} + +static int apparmor_socket_shutdown(struct socket *sock, int how) +{ + struct sock *sk = sock->sk; + + return aa_revalidate_sk(sk, "socket_shutdown"); +} + +static int apparmor_getprocattr(struct task_struct *task, char *name, + char **value) +{ + unsigned len; + int error; + struct aa_profile *profile; + + /* AppArmor only supports the "current" process attribute */ + if (strcmp(name, "current") != 0) + return -EINVAL; + + /* must be task querying itself or admin */ + if (current != task && !capable(CAP_SYS_ADMIN)) + return -EPERM; + + profile = aa_get_profile(task); + error = aa_getprocattr(profile, value, &len); + aa_put_profile(profile); + if (!error) + error = len; + + return error; +} + +static int apparmor_setprocattr(struct task_struct *task, char *name, + void *value, size_t size) +{ + char *command, *args; + int error; + + if (strcmp(name, "current") != 0 || size == 0 || size >= PAGE_SIZE) + return -EINVAL; + args = value; + args[size] = '\0'; + args = strstrip(args); + command = strsep(&args, " "); + if (!args) + return -EINVAL; + while (isspace(*args)) + args++; + if (!*args) + return -EINVAL; + + if (strcmp(command, "changehat") == 0) { + if (current != task) + return -EACCES; + error = aa_setprocattr_changehat(args); + } else if (strcmp(command, "changeprofile") == 0) { + if (current != task) + return -EACCES; + error = aa_setprocattr_changeprofile(args); + } else if (strcmp(command, "setprofile") == 0) { + struct aa_profile *profile; + + /* Only an unconfined process with admin capabilities + * may change the profile of another task. + */ + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + profile = aa_get_profile(current); + if (profile) { + struct aa_audit sa; + memset(&sa, 0, sizeof(sa)); + sa.operation = "profile_set"; + sa.gfp_mask = GFP_KERNEL; + sa.task = task->pid; + sa.info = "from confined process"; + aa_audit_reject(profile, &sa); + aa_put_profile(profile); + return -EACCES; + } + error = aa_setprocattr_setprofile(task, args); + } else { + struct aa_audit sa; + memset(&sa, 0, sizeof(sa)); + sa.operation = "setprocattr"; + sa.gfp_mask = GFP_KERNEL; + sa.info = "invalid command"; + sa.name = command; + sa.task = task->pid; + aa_audit_reject(NULL, &sa); + return -EINVAL; + } + + if (!error) + error = size; + return error; +} + +static int apparmor_task_setrlimit(unsigned int resource, + struct rlimit *new_rlim) +{ + struct aa_profile *profile; + int error = 0; + + profile = aa_get_profile(current); + if (profile) { + error = aa_task_setrlimit(profile, resource, new_rlim); + } + aa_put_profile(profile); + + return error; +} + +struct security_operations apparmor_ops = { + .ptrace_may_access = apparmor_ptrace_may_access, + .ptrace_traceme = apparmor_ptrace_traceme, + .capget = cap_capget, + .capset_check = cap_capset_check, + .capset_set = cap_capset_set, + .sysctl = apparmor_sysctl, + .capable = apparmor_capable, + .syslog = cap_syslog, + + .bprm_apply_creds = cap_bprm_apply_creds, + .bprm_set_security = apparmor_bprm_set_security, + .bprm_secureexec = apparmor_bprm_secureexec, + + .sb_mount = apparmor_sb_mount, + .sb_umount = apparmor_umount, + + .inode_mkdir = apparmor_inode_mkdir, + .inode_rmdir = apparmor_inode_rmdir, + .inode_create = apparmor_inode_create, + .inode_link = apparmor_inode_link, + .inode_unlink = apparmor_inode_unlink, + .inode_symlink = apparmor_inode_symlink, + .inode_mknod = apparmor_inode_mknod, + .inode_rename = apparmor_inode_rename, + .inode_permission = apparmor_inode_permission, + .inode_setattr = apparmor_inode_setattr, + .inode_setxattr = apparmor_inode_setxattr, + .inode_getxattr = apparmor_inode_getxattr, + .inode_listxattr = apparmor_inode_listxattr, + .inode_removexattr = apparmor_inode_removexattr, + .file_permission = apparmor_file_permission, + .file_alloc_security = apparmor_file_alloc_security, + .file_free_security = apparmor_file_free_security, + .file_mmap = apparmor_file_mmap, + .file_mprotect = apparmor_file_mprotect, + .file_lock = apparmor_file_lock, + + .path_permission = apparmor_path_permission, + + .task_alloc_security = apparmor_task_alloc_security, + .task_free_security = apparmor_task_free_security, + .task_post_setuid = cap_task_post_setuid, + .task_reparent_to_init = cap_task_reparent_to_init, + .task_setrlimit = apparmor_task_setrlimit, + + .getprocattr = apparmor_getprocattr, + .setprocattr = apparmor_setprocattr, + + .socket_create = apparmor_socket_create, + .socket_post_create = apparmor_socket_post_create, + .socket_bind = apparmor_socket_bind, + .socket_connect = apparmor_socket_connect, + .socket_listen = apparmor_socket_listen, + .socket_accept = apparmor_socket_accept, + .socket_sendmsg = apparmor_socket_sendmsg, + .socket_recvmsg = apparmor_socket_recvmsg, + .socket_getsockname = apparmor_socket_getsockname, + .socket_getpeername = apparmor_socket_getpeername, + .socket_getsockopt = apparmor_socket_getsockopt, + .socket_setsockopt = apparmor_socket_setsockopt, + .socket_shutdown = apparmor_socket_shutdown, +}; + +void info_message(const char *str) +{ + struct aa_audit sa; + memset(&sa, 0, sizeof(sa)); + sa.gfp_mask = GFP_KERNEL; + sa.info = str; + printk(KERN_INFO "AppArmor: %s\n", str); + if (audit_enabled) + aa_audit_message(NULL, &sa, AUDIT_APPARMOR_STATUS); +} + +static int __init apparmor_init(void) +{ + int error; + + if (!apparmor_enabled) { + info_message("AppArmor disabled by boottime parameter\n"); + return 0; + } + + if ((error = create_apparmorfs())) { + AA_ERROR("Unable to activate AppArmor filesystem\n"); + goto createfs_out; + } + + if ((error = alloc_default_namespace())){ + AA_ERROR("Unable to allocate default profile namespace\n"); + goto alloc_out; + } + + if ((error = register_security(&apparmor_ops))) { + AA_ERROR("Unable to register AppArmor\n"); + goto register_security_out; + } + + /* Report that AppArmor successfully initialized */ + apparmor_initialized = 1; + if (apparmor_complain) + info_message("AppArmor initialized: complainmode enabled"); + else + info_message("AppArmor initialized"); + + return error; + +register_security_out: + free_default_namespace(); + +alloc_out: + destroy_apparmorfs(); + +createfs_out: + return error; + +} + +security_initcall(apparmor_init); + +void apparmor_disable(void) +{ + /* Remove and release all the profiles on the profile list. */ + mutex_lock(&aa_interface_lock); + aa_profile_ns_list_release(); + + /* FIXME: cleanup profiles references on files */ + free_default_namespace(); + + /* + * Delay for an rcu cycle to make sure that all active task + * context readers have finished, and all profiles have been + * freed by their rcu callbacks. + */ + synchronize_rcu(); + + destroy_apparmorfs(); + mutex_unlock(&aa_interface_lock); + + apparmor_initialized = 0; + + info_message("AppArmor protection removed"); +} + +MODULE_DESCRIPTION("AppArmor process confinement"); +MODULE_AUTHOR("Novell/Immunix, http://bugs.opensuse.org"); +MODULE_LICENSE("GPL"); --- linux-2.6.27.orig/security/apparmor/main.c +++ linux-2.6.27/security/apparmor/main.c @@ -0,0 +1,1690 @@ +/* + * Copyright (C) 2002-2007 Novell/SUSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * AppArmor Core + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "apparmor.h" + +#include "inline.h" + +/* + * Table of capability names: we generate it from capabilities.h. + */ +static const char *capability_names[] = { +#include "capability_names.h" +}; + +struct aa_namespace *default_namespace; + +static int aa_inode_mode(struct inode *inode) +{ + /* if the inode doesn't exist the user is creating it */ + if (!inode || current->fsuid == inode->i_uid) + return AA_USER_SHIFT; + return AA_OTHER_SHIFT; +} + +int alloc_default_namespace(void) +{ + struct aa_namespace *ns; + char *name = kstrdup("default", GFP_KERNEL); + if (!name) + return -ENOMEM; + ns = alloc_aa_namespace(name); + if (!ns) { + kfree(name); + return -ENOMEM; + } + + write_lock(&profile_ns_list_lock); + default_namespace = ns; + aa_get_namespace(ns); + list_add(&ns->list, &profile_ns_list); + write_unlock(&profile_ns_list_lock); + + return 0; +} + +void free_default_namespace(void) +{ + write_lock(&profile_ns_list_lock); + list_del_init(&default_namespace->list); + write_unlock(&profile_ns_list_lock); + aa_put_namespace(default_namespace); + default_namespace = NULL; +} + +static void aa_audit_file_sub_mask(struct audit_buffer *ab, char *buffer, + int mask) +{ + const char unsafex[] = "upcn"; + const char safex[] = "UPCN"; + char *m = buffer; + + if (mask & AA_EXEC_MMAP) + *m++ = 'm'; + if (mask & MAY_READ) + *m++ = 'r'; + if (mask & MAY_WRITE) + *m++ = 'w'; + else if (mask & MAY_APPEND) + *m++ = 'a'; + if (mask & MAY_EXEC) { + int index = AA_EXEC_INDEX(mask); + /* all indexes > 4 are also named transitions */ + if (index > 4) + index = 4; + if (index > 0) { + if (mask & AA_EXEC_UNSAFE) + *m++ = unsafex[index - 1]; + else + *m++ = safex[index - 1]; + } + if (mask & AA_EXEC_INHERIT) + *m++ = 'i'; + *m++ = 'x'; + } + if (mask & AA_MAY_LINK) + *m++ = 'l'; + if (mask & AA_MAY_LOCK) + *m++ = 'k'; + *m++ = '\0'; +} + +static void aa_audit_file_mask(struct audit_buffer *ab, const char *name, + int mask) +{ + char user[10], other[10]; + + aa_audit_file_sub_mask(ab, user, + (mask & AA_USER_PERMS) >> AA_USER_SHIFT); + aa_audit_file_sub_mask(ab, other, + (mask & AA_OTHER_PERMS) >> AA_OTHER_SHIFT); + + audit_log_format(ab, " %s=\"%s::%s\"", name, user, other); +} + +static const char *address_families[] = { +#include "af_names.h" +}; + +static const char *sock_types[] = { + "unknown(0)", + "stream", + "dgram", + "raw", + "rdm", + "seqpacket", + "dccp", + "unknown(7)", + "unknown(8)", + "unknown(9)", + "packet", +}; + +/** + * aa_audit - Log an audit event to the audit subsystem + * @profile: profile to check against + * @sa: audit event + * @audit_cxt: audit context to log message to + * @type: audit event number + */ +static int aa_audit_base(struct aa_profile *profile, struct aa_audit *sa, + struct audit_context *audit_cxt, int type) +{ + struct audit_buffer *ab = NULL; + + ab = audit_log_start(audit_cxt, sa->gfp_mask, type); + + if (!ab) { + AA_ERROR("Unable to log event (%d) to audit subsys\n", + type); + /* don't fail operations in complain mode even if logging + * fails */ + return type == AUDIT_APPARMOR_ALLOWED ? 0 : -ENOMEM; + } + + if (sa->operation) + audit_log_format(ab, "operation=\"%s\"", sa->operation); + + if (sa->info) { + audit_log_format(ab, " info=\"%s\"", sa->info); + if (sa->error_code) + audit_log_format(ab, " error=%d", sa->error_code); + } + + if (sa->request_mask) + aa_audit_file_mask(ab, "requested_mask", sa->request_mask); + + if (sa->denied_mask) + aa_audit_file_mask(ab, "denied_mask", sa->denied_mask); + + if (sa->request_mask) + audit_log_format(ab, " fsuid=%d", current->fsuid); + + if (sa->rlimit) + audit_log_format(ab, " rlimit=%d", sa->rlimit - 1); + + if (sa->iattr) { + struct iattr *iattr = sa->iattr; + + audit_log_format(ab, " attribute=\"%s%s%s%s%s%s%s\"", + iattr->ia_valid & ATTR_MODE ? "mode," : "", + iattr->ia_valid & ATTR_UID ? "uid," : "", + iattr->ia_valid & ATTR_GID ? "gid," : "", + iattr->ia_valid & ATTR_SIZE ? "size," : "", + iattr->ia_valid & (ATTR_ATIME | ATTR_ATIME_SET) ? + "atime," : "", + iattr->ia_valid & (ATTR_MTIME | ATTR_MTIME_SET) ? + "mtime," : "", + iattr->ia_valid & ATTR_CTIME ? "ctime," : ""); + } + + if (sa->task) + audit_log_format(ab, " task=%d", sa->task); + + if (sa->parent) + audit_log_format(ab, " parent=%d", sa->parent); + + if (sa->name) { + audit_log_format(ab, " name="); + audit_log_untrustedstring(ab, sa->name); + } + + if (sa->name2) { + audit_log_format(ab, " name2="); + audit_log_untrustedstring(ab, sa->name2); + } + + if (sa->family || sa->type) { + if (address_families[sa->family]) + audit_log_format(ab, " family=\"%s\"", + address_families[sa->family]); + else + audit_log_format(ab, " family=\"unknown(%d)\"", + sa->family); + + if (sock_types[sa->type]) + audit_log_format(ab, " sock_type=\"%s\"", + sock_types[sa->type]); + else + audit_log_format(ab, " sock_type=\"unknown(%d)\"", + sa->type); + + audit_log_format(ab, " protocol=%d", sa->protocol); + } + + audit_log_format(ab, " pid=%d", current->pid); + + if (profile) { + audit_log_format(ab, " profile="); + audit_log_untrustedstring(ab, profile->name); + + if (profile->ns != default_namespace) { + audit_log_format(ab, " namespace="); + audit_log_untrustedstring(ab, profile->ns->name); + } + } + + audit_log_end(ab); + + return type == AUDIT_APPARMOR_ALLOWED ? 0 : sa->error_code; +} + +/** + * aa_audit_syscallreject - Log a syscall rejection to the audit subsystem + * @profile: profile to check against + * @gfp: memory allocation flags + * @msg: string describing syscall being rejected + */ +int aa_audit_syscallreject(struct aa_profile *profile, gfp_t gfp, + const char *msg) +{ + struct aa_audit sa; + memset(&sa, 0, sizeof(sa)); + sa.operation = "syscall"; + sa.name = msg; + sa.gfp_mask = gfp; + sa.error_code = -EPERM; + + return aa_audit_base(profile, &sa, current->audit_context, + AUDIT_APPARMOR_DENIED); +} + +int aa_audit_message(struct aa_profile *profile, struct aa_audit *sa, + int type) +{ + struct audit_context *audit_cxt; + + audit_cxt = apparmor_logsyscall ? current->audit_context : NULL; + return aa_audit_base(profile, sa, audit_cxt, type); +} + +void aa_audit_hint(struct aa_profile *profile, struct aa_audit *sa) +{ + aa_audit_message(profile, sa, AUDIT_APPARMOR_HINT); +} + +void aa_audit_status(struct aa_profile *profile, struct aa_audit *sa) +{ + aa_audit_message(profile, sa, AUDIT_APPARMOR_STATUS); +} + +int aa_audit_reject(struct aa_profile *profile, struct aa_audit *sa) +{ + return aa_audit_message(profile, sa, AUDIT_APPARMOR_DENIED); +} + +/** + * aa_audit - Log an audit event to the audit subsystem + * @profile: profile to check against + * @sa: audit event + */ +int aa_audit(struct aa_profile *profile, struct aa_audit *sa) +{ + int type = AUDIT_APPARMOR_DENIED; + struct audit_context *audit_cxt; + + if (likely(!sa->error_code)) + type = AUDIT_APPARMOR_AUDIT; + else if (PROFILE_COMPLAIN(profile)) + type = AUDIT_APPARMOR_ALLOWED; + + audit_cxt = apparmor_logsyscall ? current->audit_context : NULL; + return aa_audit_base(profile, sa, audit_cxt, type); +} + +static int aa_audit_file(struct aa_profile *profile, struct aa_audit *sa) +{ + if (likely(!sa->error_code)) { + int mask = sa->audit_mask & AUDIT_FILE_MASK; + + if (unlikely(PROFILE_AUDIT(profile))) + mask |= AUDIT_FILE_MASK; + + if (likely(!(sa->request_mask & mask))) + return 0; + + /* mask off perms that are not being force audited */ + sa->request_mask &= mask | ALL_AA_EXEC_TYPE; + } else { + int mask = AUDIT_QUIET_MASK(sa->audit_mask); + + if (!(sa->denied_mask & ~mask)) + return sa->error_code; + + /* mask off perms whose denial is being silenced */ + if (!PROFILE_COMPLAIN(profile)) + sa->denied_mask &= (~mask) | ALL_AA_EXEC_TYPE; + } + + return aa_audit(profile, sa); +} + +static int aa_audit_caps(struct aa_profile *profile, struct aa_audit *sa, + int cap) +{ + if (likely(!sa->error_code)) { + if (likely(!PROFILE_AUDIT(profile) && + !cap_raised(profile->audit_caps, cap))) + return 0; + } + + /* quieting of capabilities is handled the caps_logged cache */ + return aa_audit(profile, sa); +} + +/** + * aa_file_denied - check for @mask access on a file + * @profile: profile to check against + * @name: pathname of file + * @mask: permission mask requested for file + * @audit_mask: return audit mask for the match + * + * Return %0 on success, or else the permissions in @mask that the + * profile denies. + */ +static int aa_file_denied(struct aa_profile *profile, const char *name, + int mask, int *audit_mask) +{ + return (mask & ~aa_match(profile->file_rules, name, audit_mask)); +} + +/** + * aa_link_denied - check for permission to link a file + * @profile: profile to check against + * @link: pathname of link being created + * @target: pathname of target to be linked to + * @target_mode: UGO shift for target inode + * @request_mask: the permissions subset valid only if link succeeds + * @audit_mask: return the audit_mask for the link permission + * Return %0 on success, or else the permissions that the profile denies. + */ +static int aa_link_denied(struct aa_profile *profile, const char *link, + const char *target, int target_mode, + int *request_mask, int *audit_mask) +{ + unsigned int state; + int l_mode, t_mode, l_x, t_x, denied_mask = 0; + int link_mask = AA_MAY_LINK << target_mode; + + *request_mask = link_mask; + + l_mode = aa_match_state(profile->file_rules, DFA_START, link, &state); + + if (l_mode & link_mask) { + int mode; + /* test to see if target can be paired with link */ + state = aa_dfa_null_transition(profile->file_rules, state); + mode = aa_match_state(profile->file_rules, state, target, + &state); + + if (!(mode & link_mask)) + denied_mask |= link_mask; + + *audit_mask = dfa_audit_mask(profile->file_rules, state); + + /* return if link subset test is not required */ + if (!(mode & (AA_LINK_SUBSET_TEST << target_mode))) + return denied_mask; + } + + /* Do link perm subset test requiring permission on link are a + * subset of the permissions on target. + * If a subset test is required a permission subset test of the + * perms for the link are done against the user::other of the + * target's 'r', 'w', 'x', 'a', 'k', and 'm' permissions. + * + * If the link has 'x', an exact match of all the execute flags + * must match. + */ + denied_mask |= ~l_mode & link_mask; + + t_mode = aa_match(profile->file_rules, target, NULL); + + l_x = l_mode & (ALL_AA_EXEC_TYPE | AA_EXEC_BITS); + t_x = t_mode & (ALL_AA_EXEC_TYPE | AA_EXEC_BITS); + + /* For actual subset test ignore valid-profile-transition flags, + * and link bits + */ + l_mode &= AA_FILE_PERMS & ~AA_LINK_BITS; + t_mode &= AA_FILE_PERMS & ~AA_LINK_BITS; + + *request_mask = l_mode | link_mask; + + if (l_mode) { + int x = l_x | (t_x & ALL_AA_EXEC_UNSAFE); + denied_mask |= l_mode & ~t_mode; + /* mask off x modes not used by link */ + + /* handle exec subset + * - link safe exec issubset of unsafe exec + * - no link x perm is subset of target having x perm + */ + if ((l_mode & AA_USER_EXEC) && + (x & AA_USER_EXEC_TYPE) != (t_x & AA_USER_EXEC_TYPE)) + denied_mask = AA_USER_EXEC | (l_x & AA_USER_EXEC_TYPE); + if ((l_mode & AA_OTHER_EXEC) && + (x & AA_OTHER_EXEC_TYPE) != (t_x & AA_OTHER_EXEC_TYPE)) + denied_mask = AA_OTHER_EXEC | (l_x & AA_OTHER_EXEC_TYPE); + } + + return denied_mask; +} + +/** + * aa_get_name - compute the pathname of a file + * @dentry: dentry of the file + * @mnt: vfsmount of the file + * @buffer: buffer that aa_get_name() allocated + * @check: AA_CHECK_DIR is set if the file is a directory + * + * Returns a pointer to the beginning of the pathname (which usually differs + * from the beginning of the buffer), or an error code. + * + * We need @check to indicate whether the file is a directory or not because + * the file may not yet exist, and so we cannot check the inode's file type. + */ +static char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt, + char **buffer, int check) +{ + char *name; + int is_dir, size = 256; + + is_dir = (check & AA_CHECK_DIR) ? 1 : 0; + + for (;;) { + char *buf = kmalloc(size, GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + name = d_namespace_path(dentry, mnt, buf, size - is_dir); + if (!IS_ERR(name)) { + if (name[0] != '/') { + /* + * This dentry is not connected to the + * namespace root -- reject access. + */ + kfree(buf); + return ERR_PTR(-ENOENT); + } + if (is_dir && name[1] != '\0') { + /* + * Append "/" to the pathname. The root + * directory is a special case; it already + * ends in slash. + */ + buf[size - 2] = '/'; + buf[size - 1] = '\0'; + } + + *buffer = buf; + return name; + } + kfree(buf); + if (PTR_ERR(name) != -ENAMETOOLONG) + return name; + + size <<= 1; + if (size > apparmor_path_max) + return ERR_PTR(-ENAMETOOLONG); + } +} + +static char *new_compound_name(const char *n1, const char *n2) +{ + char *name = kmalloc(strlen(n1) + strlen(n2) + 3, GFP_KERNEL); + if (name) + sprintf(name, "%s//%s", n1, n2); + return name; +} +static inline void aa_put_name_buffer(char *buffer) +{ + kfree(buffer); +} + +/** + * aa_perm_dentry - check if @profile allows @mask for a file + * @profile: profile to check against + * @dentry: dentry of the file + * @mnt: vfsmount o the file + * @sa: audit context + * @mask: requested profile permissions + * @check: kind of check to perform + * + * Returns 0 upon success, or else an error code. + * + * @check indicates the file type, and whether the file was accessed through + * an open file descriptor (AA_CHECK_FD) or not. + */ +static int aa_perm_dentry(struct aa_profile *profile, struct dentry *dentry, + struct vfsmount *mnt, struct aa_audit *sa, int check) +{ + int error; + char *buffer = NULL; + + sa->name = aa_get_name(dentry, mnt, &buffer, check); + sa->request_mask <<= aa_inode_mode(dentry->d_inode); + if (IS_ERR(sa->name)) { + /* + * deleted files are given a pass on permission checks when + * accessed through a file descriptor. + */ + if (PTR_ERR(sa->name) == -ENOENT && (check & AA_CHECK_FD)) + sa->denied_mask = 0; + else { + sa->denied_mask = sa->request_mask; + sa->error_code = PTR_ERR(sa->name); + if (sa->error_code == -ENOENT) + sa->info = "Failed name resolution - object not a valid entry"; + else if (sa->error_code == -ENAMETOOLONG) + sa->info = "Failed name resolution - name too long"; + else + sa->info = "Failed name resolution"; + } + sa->name = NULL; + } else + sa->denied_mask = aa_file_denied(profile, sa->name, + sa->request_mask, + &sa->audit_mask); + + if (!sa->denied_mask) + sa->error_code = 0; + + error = aa_audit_file(profile, sa); + aa_put_name_buffer(buffer); + + return error; +} + +/** + * aa_attr - check if attribute change is allowed + * @profile: profile to check against + * @dentry: dentry of the file to check + * @mnt: vfsmount of the file to check + * @iattr: attribute changes requested + */ +int aa_attr(struct aa_profile *profile, struct dentry *dentry, + struct vfsmount *mnt, struct iattr *iattr) +{ + struct inode *inode = dentry->d_inode; + int error, check; + struct aa_audit sa; + + memset(&sa, 0, sizeof(sa)); + sa.operation = "setattr"; + sa.gfp_mask = GFP_KERNEL; + sa.iattr = iattr; + sa.request_mask = MAY_WRITE; + sa.error_code = -EACCES; + + check = 0; + if (inode && S_ISDIR(inode->i_mode)) + check |= AA_CHECK_DIR; + if (iattr->ia_valid & ATTR_FILE) + check |= AA_CHECK_FD; + + error = aa_perm_dentry(profile, dentry, mnt, &sa, check); + + return error; +} + +/** + * aa_perm_xattr - check if xattr attribute change is allowed + * @profile: profile to check against + * @dentry: dentry of the file to check + * @mnt: vfsmount of the file to check + * @operation: xattr operation being done + * @mask: access mode requested + * @check: kind of check to perform + */ +int aa_perm_xattr(struct aa_profile *profile, const char *operation, + struct dentry *dentry, struct vfsmount *mnt, int mask, + int check) +{ + struct inode *inode = dentry->d_inode; + int error; + struct aa_audit sa; + + memset(&sa, 0, sizeof(sa)); + sa.operation = operation; + sa.gfp_mask = GFP_KERNEL; + sa.request_mask = mask; + sa.error_code = -EACCES; + + if (inode && S_ISDIR(inode->i_mode)) + check |= AA_CHECK_DIR; + + error = aa_perm_dentry(profile, dentry, mnt, &sa, check); + + return error; +} + +/** + * aa_perm - basic apparmor permissions check + * @profile: profile to check against + * @dentry: dentry of the file to check + * @mnt: vfsmount of the file to check + * @mask: access mode requested + * @check: kind of check to perform + * + * Determine if access @mask for the file is authorized by @profile. + * Returns 0 on success, or else an error code. + */ +int aa_perm(struct aa_profile *profile, const char *operation, + struct dentry *dentry, struct vfsmount *mnt, int mask, int check) +{ + struct aa_audit sa; + int error = 0; + + if (mask == 0) + goto out; + + memset(&sa, 0, sizeof(sa)); + sa.operation = operation; + sa.gfp_mask = GFP_KERNEL; + sa.request_mask = mask; + sa.error_code = -EACCES; + + error = aa_perm_dentry(profile, dentry, mnt, &sa, check); + +out: + return error; +} + +/** + * aa_perm_dir + * @profile: profile to check against + * @dentry: dentry of directory to check + * @mnt: vfsmount of directory to check + * @operation: directory operation being performed + * @mask: access mode requested + * + * Determine if directory operation (make/remove) for dentry is authorized + * by @profile. + * Returns 0 on success, or else an error code. + */ +int aa_perm_dir(struct aa_profile *profile, const char *operation, + struct dentry *dentry, struct vfsmount *mnt, int mask) +{ + struct aa_audit sa; + + memset(&sa, 0, sizeof(sa)); + sa.operation = operation; + sa.gfp_mask = GFP_KERNEL; + sa.request_mask = mask; + sa.error_code = -EACCES; + + return aa_perm_dentry(profile, dentry, mnt, &sa, AA_CHECK_DIR); +} + +int aa_perm_path(struct aa_profile *profile, const char *operation, + const char *name, int mask, uid_t uid) +{ + struct aa_audit sa; + + memset(&sa, 0, sizeof(sa)); + sa.operation = operation; + sa.gfp_mask = GFP_KERNEL; + sa.request_mask = mask; + sa.name = name; + if (current->fsuid == uid) + sa.request_mask = mask << AA_USER_SHIFT; + else + sa.request_mask = mask << AA_OTHER_SHIFT; + + sa.denied_mask = aa_file_denied(profile, name, sa.request_mask, + &sa.audit_mask) ; + sa.error_code = sa.denied_mask ? -EACCES : 0; + + return aa_audit_file(profile, &sa); +} + +/** + * aa_capability - test permission to use capability + * @cxt: aa_task_context with profile to check against + * @cap: capability to be tested + * + * Look up capability in profile capability set. + * Returns 0 on success, or else an error code. + */ +int aa_capability(struct aa_task_context *cxt, int cap) +{ + int error = cap_raised(cxt->profile->capabilities, cap) ? 0 : -EPERM; + struct aa_audit sa; + + /* test if cap has alread been logged */ + if (cap_raised(cxt->caps_logged, cap)) { + if (PROFILE_COMPLAIN(cxt->profile)) + error = 0; + return error; + } else + /* don't worry about rcu replacement of the cxt here. + * caps_logged is a cache to reduce the occurence of + * duplicate messages in the log. The worst that can + * happen is duplicate capability messages shows up in + * the audit log + */ + cap_raise(cxt->caps_logged, cap); + + memset(&sa, 0, sizeof(sa)); + sa.operation = "capable"; + sa.gfp_mask = GFP_ATOMIC; + sa.name = capability_names[cap]; + sa.error_code = error; + + error = aa_audit_caps(cxt->profile, &sa, cap); + + return error; +} + +/* must be used inside rcu_read_lock or task_lock */ +int aa_may_ptrace(struct aa_task_context *cxt, struct aa_profile *tracee) +{ + if (!cxt || cxt->profile == tracee) + return 0; + return aa_capability(cxt, CAP_SYS_PTRACE); +} + +/** + * aa_link - hard link check + * @profile: profile to check against + * @link: dentry of link being created + * @link_mnt: vfsmount of link being created + * @target: dentry of link target + * @target_mnt: vfsmunt of link target + * + * Returns 0 on success, or else an error code. + */ +int aa_link(struct aa_profile *profile, + struct dentry *link, struct vfsmount *link_mnt, + struct dentry *target, struct vfsmount *target_mnt) +{ + int error; + struct aa_audit sa; + char *buffer = NULL, *buffer2 = NULL; + + memset(&sa, 0, sizeof(sa)); + sa.operation = "inode_link"; + sa.gfp_mask = GFP_KERNEL; + sa.name = aa_get_name(link, link_mnt, &buffer, 0); + sa.name2 = aa_get_name(target, target_mnt, &buffer2, 0); + + if (IS_ERR(sa.name)) { + sa.error_code = PTR_ERR(sa.name); + sa.name = NULL; + } + if (IS_ERR(sa.name2)) { + sa.error_code = PTR_ERR(sa.name2); + sa.name2 = NULL; + } + + if (sa.name && sa.name2) { + sa.denied_mask = aa_link_denied(profile, sa.name, sa.name2, + aa_inode_mode(target->d_inode), + &sa.request_mask, + &sa.audit_mask); + sa.error_code = sa.denied_mask ? -EACCES : 0; + } + + error = aa_audit_file(profile, &sa); + + aa_put_name_buffer(buffer); + aa_put_name_buffer(buffer2); + + return error; +} + +int aa_net_perm(struct aa_profile *profile, char *operation, + int family, int type, int protocol) +{ + struct aa_audit sa; + int error = 0; + u16 family_mask, audit_mask, quiet_mask; + + if ((family < 0) || (family >= AF_MAX)) + return -EINVAL; + + if ((type < 0) || (type >= SOCK_MAX)) + return -EINVAL; + + /* unix domain and netlink sockets are handled by ipc */ + if (family == AF_UNIX || family == AF_NETLINK) + return 0; + + family_mask = profile->network_families[family]; + audit_mask = profile->audit_network[family]; + quiet_mask = profile->quiet_network[family]; + + error = (family_mask & (1 << type)) ? 0 : -EACCES; + + memset(&sa, 0, sizeof(sa)); + sa.operation = operation; + sa.gfp_mask = GFP_KERNEL; + sa.family = family; + sa.type = type; + sa.protocol = protocol; + sa.error_code = error; + + if (likely(!error)) { + if (!PROFILE_AUDIT(profile) && !(family_mask & audit_mask)) + return 0; + } else if (!((1 << type) & ~quiet_mask)) { + return error; + } + + error = aa_audit(profile, &sa); + + return error; +} + +int aa_revalidate_sk(struct sock *sk, char *operation) +{ + struct aa_profile *profile; + int error = 0; + + /* this is some debugging code to flush out the network hooks that + that are called in interrupt context */ + if (in_interrupt()) { + printk("AppArmor Debug: Hook being called from interrupt context\n"); + dump_stack(); + return 0; + } + + profile = aa_get_profile(current); + if (profile) + error = aa_net_perm(profile, operation, + sk->sk_family, sk->sk_type, + sk->sk_protocol); + aa_put_profile(profile); + + return error; +} +/** + * aa_task_setrlimit - test permission to set an rlimit + * @profile - profile confining the task + * @resource - the resource being set + * @new_rlim - the new resource limit + * + * Control raising the processes hard limit. + */ +int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource, + struct rlimit *new_rlim) +{ + struct aa_audit sa; + int error = 0; + + memset(&sa, 0, sizeof(sa)); + sa.operation = "setrlimit"; + sa.gfp_mask = GFP_KERNEL; + sa.rlimit = resource + 1; + + if (profile->rlimits.mask & (1 << resource) && + new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max) { + sa.error_code = -EACCES; + + error = aa_audit(profile, &sa); + } + + return error; +} + +static int aa_rlimit_nproc(struct aa_profile *profile) { + if (profile && (profile->rlimits.mask & (1 << RLIMIT_NPROC)) && + profile->task_count >= profile->rlimits.limits[RLIMIT_NPROC].rlim_max) + return -EAGAIN; + return 0; +} + +void aa_set_rlimits(struct task_struct *task, struct aa_profile *profile) +{ + int i, mask; + + if (!profile) + return; + + if (!profile->rlimits.mask) + return; + + task_lock(task->group_leader); + mask = 1; + for (i = 0; i < RLIM_NLIMITS; i++, mask <<= 1) { + struct rlimit new_rlim, *old_rlim; + + /* check to see if NPROC which is per profile and handled + * in clone/exec or whether this is a limit to be set + * can't set cpu limit either right now + */ + if (i == RLIMIT_NPROC || i == RLIMIT_CPU) + continue; + + old_rlim = task->signal->rlim + i; + new_rlim = *old_rlim; + + if (mask & profile->rlimits.mask && + profile->rlimits.limits[i].rlim_max < new_rlim.rlim_max) { + new_rlim.rlim_max = profile->rlimits.limits[i].rlim_max; + /* soft limit should not exceed hard limit */ + if (new_rlim.rlim_cur > new_rlim.rlim_max) + new_rlim.rlim_cur = new_rlim.rlim_max; + } + + *old_rlim = new_rlim; + } + task_unlock(task->group_leader); +} + +/******************************* + * Global task related functions + *******************************/ + +/** + * aa_clone - initialize the task context for a new task + * @child: task that is being created + * + * Returns 0 on success, or else an error code. + */ +int aa_clone(struct task_struct *child) +{ + struct aa_audit sa; + struct aa_task_context *cxt, *child_cxt; + struct aa_profile *profile; + + if (!aa_task_context(current)) + return 0; + child_cxt = aa_alloc_task_context(GFP_KERNEL); + if (!child_cxt) + return -ENOMEM; + + memset(&sa, 0, sizeof(sa)); + sa.operation = "clone"; + sa.task = child->pid; + sa.gfp_mask = GFP_KERNEL; + +repeat: + profile = aa_get_profile(current); + if (profile) { + lock_profile(profile); + cxt = aa_task_context(current); + if (unlikely(profile->isstale || !cxt || + cxt->profile != profile)) { + /** + * Race with profile replacement or removal, or with + * task context removal. + */ + unlock_profile(profile); + aa_put_profile(profile); + goto repeat; + } + + if (aa_rlimit_nproc(profile)) { + sa.info = "rlimit nproc limit exceeded"; + unlock_profile(profile); + aa_audit_reject(profile, &sa); + aa_put_profile(profile); + return -EAGAIN; + } + + /* No need to grab the child's task lock here. */ + aa_change_task_context(child, child_cxt, profile, + cxt->cookie, cxt->previous_profile); + + unlock_profile(profile); + + if (APPARMOR_COMPLAIN(child_cxt) && + profile == profile->ns->null_complain_profile) { + aa_audit_hint(profile, &sa); + } + aa_put_profile(profile); + } else + aa_free_task_context(child_cxt); + + return 0; +} + +static struct aa_profile * +aa_register_find(struct aa_profile *profile, const char* ns_name, + const char *name, int mandatory, int complain, + struct aa_audit *sa) +{ + struct aa_namespace *ns; + struct aa_profile *new_profile; + int ns_ref = 0; + + if (profile) + ns = profile->ns; + else + ns = default_namespace; + + if (ns_name) { + /* locate the profile namespace */ + ns = aa_find_namespace(ns_name); + if (!ns) { + if (mandatory) { + sa->info = "profile namespace not found"; + sa->denied_mask = sa->request_mask; + sa->error_code = -ENOENT; + return ERR_PTR(-ENOENT); + } else { + return NULL; + } + } + ns_ref++; + } + + /* Locate new profile */ + new_profile = aa_find_profile(ns, name); + + if (new_profile) { + AA_DEBUG("%s: setting profile %s\n", + __FUNCTION__, new_profile->name); + } else if (mandatory && profile) { + sa->info = "mandatory profile missing"; + sa->denied_mask = sa->request_mask; /* shifted MAY_EXEC */ + if (complain) { + aa_audit_hint(profile, sa); + new_profile = + aa_dup_profile(profile->ns->null_complain_profile); + } else { + sa->error_code = -EACCES; + if (ns_ref) + aa_put_namespace(ns); + return ERR_PTR(-EACCES); + } + } else { + /* Only way we can get into this code is if task + * is unconfined, pix, nix. + */ + AA_DEBUG("%s: No profile found for exec image '%s'\n", + __FUNCTION__, + name); + } + if (ns_ref) + aa_put_namespace(ns); + return new_profile; +} + +static struct aa_profile * +aa_x_to_profile(struct aa_profile *profile, const char *filename, int xmode, + struct aa_audit *sa, char **child) +{ + struct aa_profile *new_profile = NULL; + int ix = xmode & AA_EXEC_INHERIT; + int complain = PROFILE_COMPLAIN(profile); + int index; + + *child = NULL; + switch (xmode & AA_EXEC_MODIFIERS) { + case 0: + /* only valid with ix flag */ + ix = 1; + break; + case AA_EXEC_UNCONFINED: + /* only valid without ix flag */ + ix = 0; + break; + case AA_EXEC_PROFILE: + new_profile = aa_register_find(profile, NULL, filename, !ix, + complain, sa); + break; + case AA_EXEC_CHILD: + *child = new_compound_name(profile->name, filename); + sa->name2 = *child; + if (!*child) { + sa->info = "Failed name resolution - exec failed"; + sa->error_code = -ENOMEM; + new_profile = ERR_PTR(-ENOMEM); + } else { + new_profile = aa_register_find(profile, NULL, *child, + !ix, complain, sa); + } + break; + default: + /* all other indexes are named transitions */ + index = AA_EXEC_INDEX(xmode); + if (index - 4 > profile->exec_table_size) { + sa->info = "invalid named transition - exec failed"; + sa->error_code = -EACCES; + new_profile = ERR_PTR(-EACCES); + } else { + char *ns_name = NULL; + char *name = profile->exec_table[index - 4]; + if (*name == ':') { + ns_name = name + 1; + name = ns_name + strlen(ns_name) + 1; + } + sa->name2 = name; + sa->name3 = ns_name; + new_profile = + aa_register_find(profile, ns_name, name, + !ix, complain, sa); + } + } + if (IS_ERR(new_profile)) + /* all these failures must be audited - no quieting */ + return ERR_PTR(aa_audit_reject(profile, sa)); + return new_profile; +} + +/** + * aa_register - register a new program + * @bprm: binprm of program being registered + * + * Try to register a new program during execve(). This should give the + * new program a valid aa_task_context if confined. + */ +int aa_register(struct linux_binprm *bprm) +{ + const char *filename; + char *buffer = NULL, *child = NULL; + struct file *filp = bprm->file; + struct aa_profile *profile, *old_profile, *new_profile = NULL; + int exec_mode, complain = 0, shift; + struct aa_audit sa; + + AA_DEBUG("%s\n", __FUNCTION__); + + profile = aa_get_profile(current); + + shift = aa_inode_mode(filp->f_dentry->d_inode); + memset(&sa, 0, sizeof(sa)); + sa.operation = "exec"; + sa.gfp_mask = GFP_KERNEL; + sa.request_mask = MAY_EXEC << shift; + + filename = aa_get_name(filp->f_dentry, filp->f_vfsmnt, &buffer, 0); + if (IS_ERR(filename)) { + if (profile) { + sa.info = "Failed name resolution - exec failed"; + sa.error_code = PTR_ERR(filename); + aa_audit_file(profile, &sa); + return sa.error_code; + } else + return 0; + } + sa.name = filename; + + exec_mode = AA_EXEC_UNSAFE << shift; + +repeat: + if (profile) { + complain = PROFILE_COMPLAIN(profile); + + /* Confined task, determine what mode inherit, unconfined or + * mandatory to load new profile + */ + exec_mode = aa_match(profile->file_rules, filename, + &sa.audit_mask); + + + if (exec_mode & sa.request_mask) { + int xm = exec_mode >> shift; + new_profile = aa_x_to_profile(profile, filename, + xm, &sa, &child); + + if (!new_profile && (xm & AA_EXEC_INHERIT)) + /* (p|c|n|)ix - don't change profile */ + goto cleanup; + /* error case caught below */ + + } else if (sa.request_mask & AUDIT_QUIET_MASK(sa.audit_mask)) { + /* quiet failed exit */ + new_profile = ERR_PTR(-EACCES); + } else if (complain) { + /* There was no entry in calling profile + * describing mode to execute image in. + * Drop into null-profile (disabling secure exec). + */ + new_profile = + aa_dup_profile(profile->ns->null_complain_profile); + exec_mode |= AA_EXEC_UNSAFE << shift; + } else { + sa.denied_mask = sa.request_mask; + sa.error_code = -EACCES; + new_profile = ERR_PTR(aa_audit_file(profile, &sa)); + } + } else { + /* Unconfined task, load profile if it exists */ + new_profile = aa_register_find(NULL, NULL, filename, 0, 0, &sa); + if (new_profile == NULL) + goto cleanup; + } + + if (IS_ERR(new_profile)) + goto cleanup; + + old_profile = __aa_replace_profile(current, new_profile); + if (IS_ERR(old_profile)) { + aa_put_profile(new_profile); + aa_put_profile(profile); + if (PTR_ERR(old_profile) == -ESTALE) { + profile = aa_get_profile(current); + goto repeat; + } + if (PTR_ERR(old_profile) == -EPERM) { + sa.denied_mask = sa.request_mask; + sa.info = "unable to set profile due to ptrace"; + sa.task = current->parent->pid; + aa_audit_reject(profile, &sa); + } + if (PTR_ERR(old_profile) == -EAGAIN) { + sa.info = "rlimit nproc limit exceeded"; + aa_audit_reject(profile, &sa); + } + new_profile = old_profile; + goto cleanup; + } + aa_put_profile(old_profile); + aa_put_profile(profile); + + /* Handle confined exec. + * Can be at this point for the following reasons: + * 1. unconfined switching to confined + * 2. confined switching to different confinement + * 3. confined switching to unconfined + * + * Cases 2 and 3 are marked as requiring secure exec + * (unless policy specified "unsafe exec") + */ + if (!(exec_mode & (AA_EXEC_UNSAFE << shift))) { + unsigned long bprm_flags; + + bprm_flags = AA_SECURE_EXEC_NEEDED; + bprm->security = (void*) + ((unsigned long)bprm->security | bprm_flags); + } + + if (complain && new_profile && + new_profile == new_profile->ns->null_complain_profile) { + sa.request_mask = 0; + sa.name = NULL; + sa.info = "set profile"; + aa_audit_hint(new_profile, &sa); + } + +cleanup: + aa_put_name_buffer(child); + aa_put_name_buffer(buffer); + if (IS_ERR(new_profile)) + return PTR_ERR(new_profile); + aa_put_profile(new_profile); + return 0; +} + +/** + * aa_release - release a task context + * @task: task being released + * + * This is called after a task has exited and the parent has reaped it. + */ +void aa_release(struct task_struct *task) +{ + struct aa_task_context *cxt; + struct aa_profile *profile; + /* + * While the task context is still on a profile's task context + * list, another process could replace the profile under us, + * leaving us with a locked profile that is no longer attached + * to this task. So after locking the profile, we check that + * the profile is still attached. The profile lock is + * sufficient to prevent the replacement race so we do not lock + * the task. + * + * Use lock subtyping to avoid lockdep reporting a false irq + * possible inversion between the task_lock and profile_lock + * + * We also avoid taking the task_lock here because lock_dep + * would report another false {softirq-on-W} potential irq_lock + * inversion. + * + * If the task does not have a profile attached we are safe; + * nothing can race with us at this point. + */ + +repeat: + profile = aa_get_profile(task); + if (profile) { + lock_profile_nested(profile, aa_lock_task_release); + cxt = aa_task_context(task); + if (unlikely(!cxt || cxt->profile != profile)) { + unlock_profile(profile); + aa_put_profile(profile); + goto repeat; + } + aa_change_task_context(task, NULL, NULL, 0, NULL); + unlock_profile(profile); + aa_put_profile(profile); + } +} + +static int do_change_profile(struct aa_profile *expected, + struct aa_namespace *ns, const char *name, + u64 cookie, int restore, int hat, + struct aa_audit *sa) +{ + struct aa_profile *new_profile = NULL, *old_profile = NULL, + *previous_profile = NULL; + struct aa_task_context *new_cxt, *cxt; + int error = 0; + + sa->name = name; + + new_cxt = aa_alloc_task_context(GFP_KERNEL); + if (!new_cxt) + return -ENOMEM; + + new_profile = aa_find_profile(ns, name); + if (!new_profile && !restore) { + if (!PROFILE_COMPLAIN(expected)) { + aa_free_task_context(new_cxt); + return -ENOENT; + } + new_profile = aa_dup_profile(ns->null_complain_profile); + } else if (new_profile && hat && !PROFILE_IS_HAT(new_profile)) { + aa_free_task_context(new_cxt); + aa_put_profile(new_profile); + return error; + } + + cxt = lock_task_and_profiles(current, new_profile); + if (!cxt) { + error = -EPERM; + goto out; + } + old_profile = cxt->profile; + + if (cxt->profile != expected || (new_profile && new_profile->isstale)) { + error = -ESTALE; + goto out; + } + + if (cxt->previous_profile) { + if (cxt->cookie != cookie) { + error = -EACCES; + sa->info = "killing process"; + aa_audit_reject(cxt->profile, sa); + /* terminate process */ + (void)send_sig_info(SIGKILL, NULL, current); + goto out; + } + + if (!restore) + previous_profile = cxt->previous_profile; + } else + previous_profile = cxt->profile; + + if ((current->ptrace & PT_PTRACED) && aa_may_ptrace(cxt, new_profile)) { + error = -EACCES; + goto out; + } + + if ((error = aa_rlimit_nproc(new_profile))) { + sa->info = "rlimit nproc limit exceeded"; + aa_audit_reject(cxt->profile, sa); + goto out; + } + + if (new_profile == ns->null_complain_profile) + aa_audit_hint(cxt->profile, sa); + + if (APPARMOR_AUDIT(cxt)) + aa_audit_message(cxt->profile, sa, AUDIT_APPARMOR_AUDIT); + + if (!restore && cookie) + aa_change_task_context(current, new_cxt, new_profile, cookie, + previous_profile); + else + /* either return to previous_profile, or a permanent change */ + aa_change_task_context(current, new_cxt, new_profile, 0, NULL); + +out: + if (aa_task_context(current) != new_cxt) + aa_free_task_context(new_cxt); + task_unlock(current); + unlock_both_profiles(old_profile, new_profile); + aa_put_profile(new_profile); + return error; +} + +/** + * aa_change_profile - perform a one-way profile transition + * @ns_name: name of the profile namespace to change to + * @name: name of profile to change to + * Change to new profile @name. Unlike with hats, there is no way + * to change back. + * + * Returns %0 on success, error otherwise. + */ +int aa_change_profile(const char *ns_name, const char *name) +{ + struct aa_task_context *cxt; + struct aa_profile *profile = NULL; + struct aa_namespace *ns = NULL; + struct aa_audit sa; + unsigned int state; + int error = -EINVAL; + + if (!name) + return -EINVAL; + + memset(&sa, 0, sizeof(sa)); + sa.gfp_mask = GFP_ATOMIC; + sa.operation = "change_profile"; + +repeat: + task_lock(current); + cxt = aa_task_context(current); + if (cxt) + profile = aa_dup_profile(cxt->profile); + task_unlock(current); + + if (ns_name) + ns = aa_find_namespace(ns_name); + else if (profile) + ns = aa_get_namespace(profile->ns); + else + ns = aa_get_namespace(default_namespace); + + if (!ns) { + aa_put_profile(profile); + return -ENOENT; + } + + if (!profile || PROFILE_COMPLAIN(profile) || + (ns == profile->ns && + (aa_match(profile->file_rules, name, NULL) & AA_CHANGE_PROFILE))) + error = do_change_profile(profile, ns, name, 0, 0, 0, &sa); + else { + /* check for a rule with a namespace prepended */ + aa_match_state(profile->file_rules, DFA_START, ns->name, + &state); + state = aa_dfa_null_transition(profile->file_rules, state); + if ((aa_match_state(profile->file_rules, state, name, NULL) & + AA_CHANGE_PROFILE)) + error = do_change_profile(profile, ns, name, 0, 0, 0, + &sa); + else + /* no permission to transition to profile @name */ + error = -EACCES; + } + + aa_put_namespace(ns); + aa_put_profile(profile); + if (error == -ESTALE) + goto repeat; + + return error; +} + +/** + * aa_change_hat - change hat to/from subprofile + * @hat_name: hat to change to + * @cookie: magic value to validate the hat change + * + * Change to new @hat_name, and store the @hat_magic in the current task + * context. If the new @hat_name is %NULL and the @cookie matches that + * stored in the current task context and is not 0, return to the top level + * profile. + * Returns %0 on success, error otherwise. + */ +int aa_change_hat(const char *hat_name, u64 cookie) +{ + struct aa_task_context *cxt; + struct aa_profile *profile, *previous_profile; + struct aa_audit sa; + int error = 0; + + memset(&sa, 0, sizeof(sa)); + sa.gfp_mask = GFP_ATOMIC; + sa.operation = "change_hat"; + +repeat: + task_lock(current); + cxt = aa_task_context(current); + if (!cxt) { + task_unlock(current); + return -EPERM; + } + profile = aa_dup_profile(cxt->profile); + previous_profile = aa_dup_profile(cxt->previous_profile); + task_unlock(current); + + if (hat_name) { + char *name, *profile_name; + + if (previous_profile) + profile_name = previous_profile->name; + else + profile_name = profile->name; + + name = new_compound_name(profile_name, hat_name); + if (!name) { + error = -ENOMEM; + goto out; + } + error = do_change_profile(profile, profile->ns, name, cookie, + 0, 1, &sa); + aa_put_name_buffer(name); + } else if (previous_profile) + error = do_change_profile(profile, profile->ns, + previous_profile->name, cookie, 1, 0, + &sa); + /* else ignore restores when there is no saved profile */ + +out: + aa_put_profile(previous_profile); + aa_put_profile(profile); + if (error == -ESTALE) + goto repeat; + + return error; +} + +/** + * __aa_replace_profile - replace a task's profile + * @task: task to switch the profile of + * @profile: profile to switch to + * + * Returns a handle to the previous profile upon success, or else an + * error code. + */ +struct aa_profile *__aa_replace_profile(struct task_struct *task, + struct aa_profile *profile) +{ + struct aa_task_context *cxt, *new_cxt = NULL; + struct aa_profile *old_profile = NULL; + + if (profile) { + new_cxt = aa_alloc_task_context(GFP_KERNEL); + if (!new_cxt) + return ERR_PTR(-ENOMEM); + } + + cxt = lock_task_and_profiles(task, profile); + if (unlikely(profile && profile->isstale)) { + old_profile = ERR_PTR(-ESTALE); + goto error; + } + + if ((current->ptrace & PT_PTRACED) && aa_may_ptrace(cxt, profile)) { + old_profile = ERR_PTR(-EPERM); + goto error; + } + + if (aa_rlimit_nproc(profile)) { + old_profile = ERR_PTR(-EAGAIN); + goto error; + } + + if (cxt) + old_profile = aa_dup_profile(cxt->profile); + aa_change_task_context(task, new_cxt, profile, 0, NULL); + + task_unlock(task); + aa_set_rlimits(task, profile); + unlock_both_profiles(profile, old_profile); + return old_profile; + +error: + task_unlock(task); + unlock_both_profiles(profile, cxt ? cxt->profile : NULL); + aa_free_task_context(new_cxt); + return old_profile; +} + +/** + * lock_task_and_profiles - lock the task and confining profiles and @profile + * @task: task to lock + * @profile: extra profile to lock in addition to the current profile + * + * Handle the spinning on locking to make sure the task context and + * profile are consistent once all locks are aquired. + * + * return the aa_task_context currently confining the task. The task lock + * will be held whether or not the task is confined. + */ +struct aa_task_context * +lock_task_and_profiles(struct task_struct *task, struct aa_profile *profile) +{ + struct aa_task_context *cxt; + struct aa_profile *old_profile = NULL; + + rcu_read_lock(); +repeat: + cxt = aa_task_context(task); + if (cxt) + old_profile = cxt->profile; + + lock_both_profiles(profile, old_profile); + task_lock(task); + + /* check for race with profile transition, replacement or removal */ + if (unlikely(cxt != aa_task_context(task))) { + task_unlock(task); + unlock_both_profiles(profile, old_profile); + old_profile = NULL; + goto repeat; + } + rcu_read_unlock(); + return cxt; +} + +static void free_aa_task_context_rcu_callback(struct rcu_head *head) +{ + struct aa_task_context *cxt; + + cxt = container_of(head, struct aa_task_context, rcu); + aa_free_task_context(cxt); +} + +/** + * aa_change_task_context - switch a task to use a new context and profile + * @task: task that is having its task context changed + * @new_cxt: new task context to use after the switch + * @profile: new profile to use after the switch + * @cookie: magic value to switch to + * @previous_profile: profile the task can return to + */ +void aa_change_task_context(struct task_struct *task, + struct aa_task_context *new_cxt, + struct aa_profile *profile, u64 cookie, + struct aa_profile *previous_profile) +{ + struct aa_task_context *old_cxt = aa_task_context(task); + + if (old_cxt) { + list_del_init(&old_cxt->list); + old_cxt->profile->task_count--; + call_rcu(&old_cxt->rcu, free_aa_task_context_rcu_callback); + } + if (new_cxt) { + /* set the caps_logged cache to the quiet_caps mask + * this has the effect of quieting caps that are not + * supposed to be logged + */ + new_cxt->caps_logged = profile->quiet_caps; + new_cxt->cookie = cookie; + new_cxt->task = task; + new_cxt->profile = aa_dup_profile(profile); + profile->task_count++; + new_cxt->previous_profile = aa_dup_profile(previous_profile); + list_move(&new_cxt->list, &profile->task_contexts); + } + rcu_assign_pointer(task->security, new_cxt); +} --- linux-2.6.27.orig/block/blk-merge.c +++ linux-2.6.27/block/blk-merge.c @@ -95,6 +95,9 @@ nr_hw_segs++; } + if (nr_phys_segs == 1 && seg_size > rq->bio->bi_seg_front_size) + rq->bio->bi_seg_front_size = seg_size; + nr_phys_segs++; bvprv = bv; seg_size = bv->bv_len; @@ -106,6 +109,10 @@ rq->bio->bi_hw_front_size = hw_seg_size; if (hw_seg_size > rq->biotail->bi_hw_back_size) rq->biotail->bi_hw_back_size = hw_seg_size; + if (nr_phys_segs == 1 && seg_size > rq->bio->bi_seg_front_size) + rq->bio->bi_seg_front_size = seg_size; + if (seg_size > rq->biotail->bi_seg_back_size) + rq->biotail->bi_seg_back_size = seg_size; rq->nr_phys_segments = nr_phys_segs; rq->nr_hw_segments = nr_hw_segs; } @@ -133,7 +140,8 @@ if (!BIOVEC_PHYS_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt))) return 0; - if (bio->bi_size + nxt->bi_size > q->max_segment_size) + if (bio->bi_seg_back_size + nxt->bi_seg_front_size > + q->max_segment_size) return 0; /* @@ -377,6 +385,8 @@ { int total_phys_segments; int total_hw_segments; + unsigned int seg_size = + req->biotail->bi_seg_back_size + next->bio->bi_seg_front_size; /* * First check if the either of the requests are re-queued @@ -392,8 +402,13 @@ return 0; total_phys_segments = req->nr_phys_segments + next->nr_phys_segments; - if (blk_phys_contig_segment(q, req->biotail, next->bio)) + if (blk_phys_contig_segment(q, req->biotail, next->bio)) { + if (req->nr_phys_segments == 1) + req->bio->bi_seg_front_size = seg_size; + if (next->nr_phys_segments == 1) + next->biotail->bi_seg_back_size = seg_size; total_phys_segments--; + } if (total_phys_segments > q->max_phys_segments) return 0; --- linux-2.6.27.orig/block/scsi_ioctl.c +++ linux-2.6.27/block/scsi_ioctl.c @@ -208,6 +208,8 @@ rq->timeout = q->sg_timeout; if (!rq->timeout) rq->timeout = BLK_DEFAULT_SG_TIMEOUT; + if (rq->timeout < BLK_MIN_SG_TIMEOUT) + rq->timeout = BLK_MIN_SG_TIMEOUT; return 0; } --- linux-2.6.27.orig/block/bsg.c +++ linux-2.6.27/block/bsg.c @@ -202,6 +202,8 @@ rq->timeout = q->sg_timeout; if (!rq->timeout) rq->timeout = BLK_DEFAULT_SG_TIMEOUT; + if (rq->timeout < BLK_MIN_SG_TIMEOUT) + rq->timeout = BLK_MIN_SG_TIMEOUT; return 0; } --- linux-2.6.27.orig/lib/scatterlist.c +++ linux-2.6.27/lib/scatterlist.c @@ -395,7 +395,7 @@ WARN_ON(!irqs_disabled()); kunmap_atomic(miter->addr, KM_BIO_SRC_IRQ); } else - kunmap(miter->addr); + kunmap(miter->page); miter->page = NULL; miter->addr = NULL; --- linux-2.6.27.orig/lib/idr.c +++ linux-2.6.27/lib/idr.c @@ -121,7 +121,7 @@ { while (idp->id_free_cnt < IDR_FREE_MAX) { struct idr_layer *new; - new = kmem_cache_alloc(idr_layer_cache, gfp_mask); + new = kmem_cache_zalloc(idr_layer_cache, gfp_mask); if (new == NULL) return (0); move_to_free_list(idp, new); @@ -185,6 +185,7 @@ new = get_from_free_list(idp); if (!new) return -1; + new->layer = l-1; rcu_assign_pointer(p->ary[m], new); p->count++; } @@ -210,6 +211,7 @@ if (unlikely(!p)) { if (!(p = get_from_free_list(idp))) return -1; + p->layer = 0; layers = 1; } /* @@ -218,8 +220,14 @@ */ while ((layers < (MAX_LEVEL - 1)) && (id >= (1 << (layers*IDR_BITS)))) { layers++; - if (!p->count) + if (!p->count) { + /* special case: if the tree is currently empty, + * then we grow the tree by moving the top node + * upwards. + */ + p->layer++; continue; + } if (!(new = get_from_free_list(idp))) { /* * The allocation failed. If we built part of @@ -237,6 +245,7 @@ } new->ary[0] = p; new->count = 1; + new->layer = layers-1; if (p->bitmap == IDR_FULL) __set_bit(0, &new->bitmap); p = new; @@ -493,17 +502,21 @@ int n; struct idr_layer *p; - n = idp->layers * IDR_BITS; p = rcu_dereference(idp->top); + if (!p) + return NULL; + n = (p->layer+1) * IDR_BITS; /* Mask off upper bits we don't use for the search. */ id &= MAX_ID_MASK; if (id >= (1 << n)) return NULL; + BUG_ON(n == 0); while (n > 0 && p) { n -= IDR_BITS; + BUG_ON(n != p->layer*IDR_BITS); p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]); } return((void *)p); @@ -582,8 +595,11 @@ int n; struct idr_layer *p, *old_p; - n = idp->layers * IDR_BITS; p = idp->top; + if (!p) + return ERR_PTR(-EINVAL); + + n = (p->layer+1) * IDR_BITS; id &= MAX_ID_MASK; @@ -607,16 +623,10 @@ } EXPORT_SYMBOL(idr_replace); -static void idr_cache_ctor(void *idr_layer) -{ - memset(idr_layer, 0, sizeof(struct idr_layer)); -} - void __init idr_init_cache(void) { idr_layer_cache = kmem_cache_create("idr_layer_cache", - sizeof(struct idr_layer), 0, SLAB_PANIC, - idr_cache_ctor); + sizeof(struct idr_layer), 0, SLAB_PANIC, NULL); } /** --- linux-2.6.27.orig/include/asm-generic/memory_model.h +++ linux-2.6.27/include/asm-generic/memory_model.h @@ -34,7 +34,7 @@ #define __pfn_to_page(pfn) \ ({ unsigned long __pfn = (pfn); \ - unsigned long __nid = arch_pfn_to_nid(pfn); \ + unsigned long __nid = arch_pfn_to_nid(__pfn); \ NODE_DATA(__nid)->node_mem_map + arch_local_page_offset(__pfn, __nid);\ }) --- linux-2.6.27.orig/include/asm-mips/seccomp.h +++ linux-2.6.27/include/asm-mips/seccomp.h @@ -1,6 +1,5 @@ #ifndef __ASM_SECCOMP_H -#include #include #define __NR_seccomp_read __NR_read --- linux-2.6.27.orig/include/media/ir-common.h +++ linux-2.6.27/include/media/ir-common.h @@ -147,6 +147,7 @@ extern IR_KEYTAB_TYPE ir_codes_genius_tvgo_a11mce[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_powercolor_real_angel[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE]; +extern IR_KEYTAB_TYPE ir_codes_msi_tvanywhere_plus[IR_KEYTAB_SIZE]; #endif --- linux-2.6.27.orig/include/linux/security.h +++ linux-2.6.27/include/linux/security.h @@ -54,9 +54,11 @@ extern int cap_bprm_set_security(struct linux_binprm *bprm); extern void cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe); extern int cap_bprm_secureexec(struct linux_binprm *bprm); -extern int cap_inode_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags); -extern int cap_inode_removexattr(struct dentry *dentry, const char *name); +extern int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, const void *value, size_t size, + int flags, struct file *file); +extern int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, struct file *file); extern int cap_inode_need_killpriv(struct dentry *dentry); extern int cap_inode_killpriv(struct dentry *dentry); extern int cap_task_post_setuid(uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags); @@ -337,23 +339,28 @@ * Check permission to create a regular file. * @dir contains inode structure of the parent of the new file. * @dentry contains the dentry structure for the file to be created. + * @mnt is the vfsmount corresponding to @dentry (may be NULL). * @mode contains the file mode of the file to be created. * Return 0 if permission is granted. * @inode_link: * Check permission before creating a new hard link to a file. * @old_dentry contains the dentry structure for an existing link to the file. + * @old_mnt is the vfsmount corresponding to @old_dentry (may be NULL). * @dir contains the inode structure of the parent directory of the new link. * @new_dentry contains the dentry structure for the new link. + * @new_mnt is the vfsmount corresponding to @new_dentry (may be NULL). * Return 0 if permission is granted. * @inode_unlink: * Check the permission to remove a hard link to a file. * @dir contains the inode structure of parent directory of the file. * @dentry contains the dentry structure for file to be unlinked. + * @mnt is the vfsmount corresponding to @dentry (may be NULL). * Return 0 if permission is granted. * @inode_symlink: * Check the permission to create a symbolic link to a file. * @dir contains the inode structure of parent directory of the symbolic link. * @dentry contains the dentry structure of the symbolic link. + * @mnt is the vfsmount corresponding to @dentry (may be NULL). * @old_name contains the pathname of file. * Return 0 if permission is granted. * @inode_mkdir: @@ -361,12 +368,14 @@ * associated with inode strcture @dir. * @dir containst the inode structure of parent of the directory to be created. * @dentry contains the dentry structure of new directory. + * @mnt is the vfsmount corresponding to @dentry (may be NULL). * @mode contains the mode of new directory. * Return 0 if permission is granted. * @inode_rmdir: * Check the permission to remove a directory. * @dir contains the inode structure of parent of the directory to be removed. * @dentry contains the dentry structure of directory to be removed. + * @mnt is the vfsmount corresponding to @dentry (may be NULL). * Return 0 if permission is granted. * @inode_mknod: * Check permissions when creating a special file (or a socket or a fifo @@ -375,6 +384,7 @@ * and not this hook. * @dir contains the inode structure of parent of the new file. * @dentry contains the dentry structure of the new file. + * @mnt is the vfsmount corresponding to @dentry (may be NULL). * @mode contains the mode of the new file. * @dev contains the device number. * Return 0 if permission is granted. @@ -382,12 +392,15 @@ * Check for permission to rename a file or directory. * @old_dir contains the inode structure for parent of the old link. * @old_dentry contains the dentry structure of the old link. + * @old_mnt is the vfsmount corresponding to @old_dentry (may be NULL). * @new_dir contains the inode structure for parent of the new link. * @new_dentry contains the dentry structure of the new link. + * @new_mnt is the vfsmount corresponding to @new_dentry (may be NULL). * Return 0 if permission is granted. * @inode_readlink: * Check the permission to read the symbolic link. * @dentry contains the dentry structure for the file link. + * @mnt is the vfsmount corresponding to @dentry (may be NULL). * Return 0 if permission is granted. * @inode_follow_link: * Check permission to follow a symbolic link when looking up a pathname. @@ -411,6 +424,7 @@ * file attributes change (such as when a file is truncated, chown/chmod * operations, transferring disk quotas, etc). * @dentry contains the dentry structure for the file. + * @mnt is the vfsmount corresponding to @dentry (may be NULL). * @attr is the iattr structure containing the new file attributes. * Return 0 if permission is granted. * @inode_getattr: @@ -426,18 +440,18 @@ * inode. * @inode_setxattr: * Check permission before setting the extended attributes - * @value identified by @name for @dentry. + * @value identified by @name for @dentry and @mnt. * Return 0 if permission is granted. * @inode_post_setxattr: * Update inode security field after successful setxattr operation. - * @value identified by @name for @dentry. + * @value identified by @name for @dentry and @mnt. * @inode_getxattr: * Check permission before obtaining the extended attributes - * identified by @name for @dentry. + * identified by @name for @dentry and @mnt. * Return 0 if permission is granted. * @inode_listxattr: * Check permission before obtaining the list of extended attribute - * names for @dentry. + * names for @dentry and @mnt. * Return 0 if permission is granted. * @inode_removexattr: * Check permission before removing the extended attribute @@ -578,6 +592,20 @@ * file_permission, and recheck access if anything has changed * since inode_permission. * + * Security hook for path + * + * @path_permission: + * Check permission before accessing a path. This hook is called by the + * existing Linux permission function, so a security module can use it to + * provide additional checking for existing Linux permission checks. + * Notice that this hook is called when a file is opened (as well as many + * other operations), whereas the file_security_ops permission hook is + * called when the actual read/write operations are performed. This + * hook is optional and if absent, inode_permission will be substituted. + * @path contains the path structure to check. + * @mask contains the permission mask. + * Return 0 if permission is granted. + * Security hooks for task operations. * * @task_create: @@ -1354,32 +1382,45 @@ void (*inode_free_security) (struct inode *inode); int (*inode_init_security) (struct inode *inode, struct inode *dir, char **name, void **value, size_t *len); - int (*inode_create) (struct inode *dir, - struct dentry *dentry, int mode); - int (*inode_link) (struct dentry *old_dentry, - struct inode *dir, struct dentry *new_dentry); - int (*inode_unlink) (struct inode *dir, struct dentry *dentry); - int (*inode_symlink) (struct inode *dir, - struct dentry *dentry, const char *old_name); - int (*inode_mkdir) (struct inode *dir, struct dentry *dentry, int mode); - int (*inode_rmdir) (struct inode *dir, struct dentry *dentry); + int (*inode_create) (struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode); + int (*inode_link) (struct dentry *old_dentry, struct vfsmount *old_mnt, + struct inode *dir, struct dentry *new_dentry, + struct vfsmount *new_mnt); + int (*inode_unlink) (struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt); + int (*inode_symlink) (struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, const char *old_name); + int (*inode_mkdir) (struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode); + int (*inode_rmdir) (struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt); int (*inode_mknod) (struct inode *dir, struct dentry *dentry, - int mode, dev_t dev); + struct vfsmount *mnt, int mode, dev_t dev); int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry); - int (*inode_readlink) (struct dentry *dentry); + struct vfsmount *old_mnt, + struct inode *new_dir, struct dentry *new_dentry, + struct vfsmount *new_mnt); + int (*inode_readlink) (struct dentry *dentry, struct vfsmount *mnt); int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd); int (*inode_permission) (struct inode *inode, int mask); - int (*inode_setattr) (struct dentry *dentry, struct iattr *attr); + int (*inode_setattr) (struct dentry *dentry, struct vfsmount *, + struct iattr *attr); int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry); void (*inode_delete) (struct inode *inode); - int (*inode_setxattr) (struct dentry *dentry, const char *name, - const void *value, size_t size, int flags); - void (*inode_post_setxattr) (struct dentry *dentry, const char *name, - const void *value, size_t size, int flags); - int (*inode_getxattr) (struct dentry *dentry, const char *name); - int (*inode_listxattr) (struct dentry *dentry); - int (*inode_removexattr) (struct dentry *dentry, const char *name); + int (*inode_setxattr) (struct dentry *dentry, struct vfsmount *mnt, + const char *name, const void *value, size_t size, + int flags, struct file *file); + void (*inode_post_setxattr) (struct dentry *dentry, + struct vfsmount *mnt, + const char *name, const void *value, + size_t size, int flags); + int (*inode_getxattr) (struct dentry *dentry, struct vfsmount *mnt, + const char *name, struct file *file); + int (*inode_listxattr) (struct dentry *dentry, struct vfsmount *mnt, + struct file *file); + int (*inode_removexattr) (struct dentry *dentry, struct vfsmount *mnt, + const char *name, struct file *file); int (*inode_need_killpriv) (struct dentry *dentry); int (*inode_killpriv) (struct dentry *dentry); int (*inode_getsecurity) (const struct inode *inode, const char *name, void **buffer, bool alloc); @@ -1407,6 +1448,7 @@ struct fown_struct *fown, int sig); int (*file_receive) (struct file *file); int (*dentry_open) (struct file *file); + int (*path_permission) (struct path *path, int mask); int (*task_create) (unsigned long clone_flags); int (*task_alloc_security) (struct task_struct *p); @@ -1622,30 +1664,43 @@ void security_inode_free(struct inode *inode); int security_inode_init_security(struct inode *inode, struct inode *dir, char **name, void **value, size_t *len); -int security_inode_create(struct inode *dir, struct dentry *dentry, int mode); -int security_inode_link(struct dentry *old_dentry, struct inode *dir, - struct dentry *new_dentry); -int security_inode_unlink(struct inode *dir, struct dentry *dentry); +int security_inode_create(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode); +int security_inode_link(struct dentry *old_dentry, struct vfsmount *old_mnt, + struct inode *dir, struct dentry *new_dentry, + struct vfsmount *new_mnt); +int security_inode_unlink(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt); int security_inode_symlink(struct inode *dir, struct dentry *dentry, - const char *old_name); -int security_inode_mkdir(struct inode *dir, struct dentry *dentry, int mode); -int security_inode_rmdir(struct inode *dir, struct dentry *dentry); -int security_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev); + struct vfsmount *mnt, const char *old_name); +int security_inode_mkdir(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode); +int security_inode_rmdir(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt); +int security_inode_mknod(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode, dev_t dev); int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry); -int security_inode_readlink(struct dentry *dentry); + struct vfsmount *old_mnt, struct inode *new_dir, + struct dentry *new_dentry, struct vfsmount *new_mnt); +int security_inode_readlink(struct dentry *dentry, struct vfsmount *mnt); int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd); int security_inode_permission(struct inode *inode, int mask); -int security_inode_setattr(struct dentry *dentry, struct iattr *attr); +int security_inode_setattr(struct dentry *dentry, struct vfsmount *mnt, + struct iattr *attr); int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry); void security_inode_delete(struct inode *inode); -int security_inode_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags); -void security_inode_post_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags); -int security_inode_getxattr(struct dentry *dentry, const char *name); -int security_inode_listxattr(struct dentry *dentry); -int security_inode_removexattr(struct dentry *dentry, const char *name); +int security_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, const void *value, + size_t size, int flags, struct file *file); +void security_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, const void *value, + size_t size, int flags); +int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, struct file *file); +int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt, + struct file *file); +int security_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt, + const char *name, struct file *file); int security_inode_need_killpriv(struct dentry *dentry); int security_inode_killpriv(struct dentry *dentry); int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc); @@ -1668,6 +1723,7 @@ struct fown_struct *fown, int sig); int security_file_receive(struct file *file); int security_dentry_open(struct file *file); +int security_path_permission(struct path *path, int mask); int security_task_create(unsigned long clone_flags); int security_task_alloc(struct task_struct *p); void security_task_free(struct task_struct *p); @@ -1968,26 +2024,31 @@ static inline int security_inode_create(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode) { return 0; } static inline int security_inode_link(struct dentry *old_dentry, - struct inode *dir, - struct dentry *new_dentry) + struct vfsmount *old_mnt, + struct inode *dir, + struct dentry *new_dentry, + struct vfsmount *new_mnt) { return 0; } static inline int security_inode_unlink(struct inode *dir, - struct dentry *dentry) + struct dentry *dentry, + struct vfsmount *mnt) { return 0; } static inline int security_inode_symlink(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, const char *old_name) { return 0; @@ -1995,19 +2056,22 @@ static inline int security_inode_mkdir(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode) { return 0; } static inline int security_inode_rmdir(struct inode *dir, - struct dentry *dentry) + struct dentry *dentry, + struct vfsmount *mnt) { return 0; } static inline int security_inode_mknod(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode, dev_t dev) { return 0; @@ -2015,13 +2079,16 @@ static inline int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry, + struct vfsmount *old_mnt, struct inode *new_dir, - struct dentry *new_dentry) + struct dentry *new_dentry, + struct vfsmount *new_mnt) { return 0; } -static inline int security_inode_readlink(struct dentry *dentry) +static inline int security_inode_readlink(struct dentry *dentry, + struct vfsmount *mnt) { return 0; } @@ -2038,7 +2105,8 @@ } static inline int security_inode_setattr(struct dentry *dentry, - struct iattr *attr) + struct vfsmount *mnt, + struct iattr *attr) { return 0; } @@ -2053,30 +2121,42 @@ { } static inline int security_inode_setxattr(struct dentry *dentry, - const char *name, const void *value, size_t size, int flags) + struct vfsmount *mnt, + const char *name, const void *value, + size_t size, int flags, + struct file *file) { - return cap_inode_setxattr(dentry, name, value, size, flags); + return cap_inode_setxattr(dentry, mnt, name, value, size, flags, file); } static inline void security_inode_post_setxattr(struct dentry *dentry, - const char *name, const void *value, size_t size, int flags) + struct vfsmount *mnt, + const char *name, + const void *value, + size_t size, int flags) { } static inline int security_inode_getxattr(struct dentry *dentry, - const char *name) + struct vfsmount *mnt, + const char *name, + struct file *file) { return 0; } -static inline int security_inode_listxattr(struct dentry *dentry) +static inline int security_inode_listxattr(struct dentry *dentry, + struct vfsmount *mnt, + struct file *file) { return 0; } static inline int security_inode_removexattr(struct dentry *dentry, - const char *name) + struct vfsmount *mnt, + const char *name, + struct file *file) { - return cap_inode_removexattr(dentry, name); + return cap_inode_removexattr(dentry, mnt, name, file); } static inline int security_inode_need_killpriv(struct dentry *dentry) @@ -2177,6 +2257,11 @@ return 0; } +static inline int security_path_permission(struct path *path, int mask) +{ + return 0; +} + static inline int security_task_create(unsigned long clone_flags) { return 0; --- linux-2.6.27.orig/include/linux/ata.h +++ linux-2.6.27/include/linux/ata.h @@ -681,12 +681,17 @@ static inline int ata_id_is_cfa(const u16 *id) { - if (id[ATA_ID_CONFIG] == 0x848A) /* Standard CF */ + if (id[ATA_ID_CONFIG] == 0x848A) /* Traditional CF */ return 1; - /* Could be CF hiding as standard ATA */ - if (ata_id_major_version(id) >= 3 && - id[ATA_ID_COMMAND_SET_1] != 0xFFFF && - (id[ATA_ID_COMMAND_SET_1] & (1 << 2))) + /* + * CF specs don't require specific value in the word 0 anymore and yet + * they forbid to report the ATA version in the word 80 and require the + * CFA feature set support to be indicated in the word 83 in this case. + * Unfortunately, some cards only follow either of this requirements, + * and while those that don't indicate CFA feature support need some + * sort of quirk list, it seems impractical for the ones that do... + */ + if ((id[ATA_ID_COMMAND_SET_2] & 0xC004) == 0x4004) return 1; return 0; } --- linux-2.6.27.orig/include/linux/sched.h +++ linux-2.6.27/include/linux/sched.h @@ -587,6 +587,9 @@ atomic_t inotify_watches; /* How many inotify watches does this user have? */ atomic_t inotify_devs; /* How many inotify devs does this user have opened? */ #endif +#ifdef CONFIG_EPOLL + atomic_t epoll_watches; /* The number of file descriptors currently watched */ +#endif #ifdef CONFIG_POSIX_MQUEUE /* protected by mq_lock */ unsigned long mq_bytes; /* How many bytes can be allocated to mqueue? */ @@ -1286,7 +1289,9 @@ atomic_t fs_excl; /* holding fs exclusive resources */ struct rcu_head rcu; - /* + struct list_head *scm_work_list; + +/* * cache last used pipe for splice */ struct pipe_inode_info *splice_pipe; --- linux-2.6.27.orig/include/linux/capability.h +++ linux-2.6.27/include/linux/capability.h @@ -366,7 +366,21 @@ #define CAP_FOR_EACH_U32(__capi) \ for (__capi = 0; __capi < _KERNEL_CAPABILITY_U32S; ++__capi) +/* + * CAP_FS_MASK and CAP_NFSD_MASKS: + * + * The fs mask is all the privileges that fsuid==0 historically meant. + * At one time in the past, that included CAP_MKNOD and CAP_LINUX_IMMUTABLE. + * + * It has never meant setting security.* and trusted.* xattrs. + * + * We could also define fsmask as follows: + * 1. CAP_FS_MASK is the privilege to bypass all fs-related DAC permissions + * 2. The security.* and trusted.* xattrs are fs-related MAC permissions + */ + # define CAP_FS_MASK_B0 (CAP_TO_MASK(CAP_CHOWN) \ + | CAP_TO_MASK(CAP_MKNOD) \ | CAP_TO_MASK(CAP_DAC_OVERRIDE) \ | CAP_TO_MASK(CAP_DAC_READ_SEARCH) \ | CAP_TO_MASK(CAP_FOWNER) \ @@ -381,9 +395,12 @@ # define CAP_EMPTY_SET ((kernel_cap_t){{ 0, 0 }}) # define CAP_FULL_SET ((kernel_cap_t){{ ~0, ~0 }}) # define CAP_INIT_EFF_SET ((kernel_cap_t){{ ~CAP_TO_MASK(CAP_SETPCAP), ~0 }}) -# define CAP_FS_SET ((kernel_cap_t){{ CAP_FS_MASK_B0, CAP_FS_MASK_B1 } }) -# define CAP_NFSD_SET ((kernel_cap_t){{ CAP_FS_MASK_B0|CAP_TO_MASK(CAP_SYS_RESOURCE), \ - CAP_FS_MASK_B1 } }) +# define CAP_FS_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \ + | CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \ + CAP_FS_MASK_B1 } }) +# define CAP_NFSD_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \ + | CAP_TO_MASK(CAP_SYS_RESOURCE), \ + CAP_FS_MASK_B1 } }) #endif /* _KERNEL_CAPABILITY_U32S != 2 */ --- linux-2.6.27.orig/include/linux/blkdev.h +++ linux-2.6.27/include/linux/blkdev.h @@ -623,6 +623,7 @@ * default timeout for SG_IO if none specified */ #define BLK_DEFAULT_SG_TIMEOUT (60 * HZ) +#define BLK_MIN_SG_TIMEOUT (7 * HZ) #ifdef CONFIG_BOUNCE extern int init_emergency_isa_pool(void); --- linux-2.6.27.orig/include/linux/inotify.h +++ linux-2.6.27/include/linux/inotify.h @@ -134,6 +134,8 @@ struct inotify_watch *); extern void get_inotify_watch(struct inotify_watch *); extern void put_inotify_watch(struct inotify_watch *); +extern int pin_inotify_watch(struct inotify_watch *); +extern void unpin_inotify_watch(struct inotify_watch *); #else @@ -228,6 +230,15 @@ { } +extern inline int pin_inotify_watch(struct inotify_watch *watch) +{ + return 0; +} + +extern inline void unpin_inotify_watch(struct inotify_watch *watch) +{ +} + #endif /* CONFIG_INOTIFY */ #endif /* __KERNEL __ */ --- linux-2.6.27.orig/include/linux/aufs_type.h +++ linux-2.6.27/include/linux/aufs_type.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* $Id: aufs_type.h,v 1.124 2008/09/22 03:52:19 sfjro Exp $ */ + +#include + +#ifndef __AUFS_TYPE_H__ +#define __AUFS_TYPE_H__ + +#define AUFS_VERSION "20080922" + +/* move this to linux-2.6.19/include/magic.h */ +#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_BRANCH_MAX_127 +/* some environments treat 'char' as 'unsigned char' by default */ +typedef signed char aufs_bindex_t; +#define AUFS_BRANCH_MAX 127 +#else +typedef short aufs_bindex_t; +#ifdef CONFIG_AUFS_BRANCH_MAX_511 +#define AUFS_BRANCH_MAX 511 +#elif defined(CONFIG_AUFS_BRANCH_MAX_1023) +#define AUFS_BRANCH_MAX 1023 +#elif defined(CONFIG_AUFS_BRANCH_MAX_32767) +#define AUFS_BRANCH_MAX 32767 +#else +#error unknown CONFIG_AUFS_BRANCH_MAX value +#endif +#endif + +#define AUFS_NAME "aufs" +#define AUFS_FSTYPE AUFS_NAME + +#define AUFS_ROOT_INO 2 +#define AUFS_FIRST_INO 11 + +#define AUFS_WH_PFX ".wh." +#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1) +#define AUFS_XINO_FNAME "." AUFS_NAME ".xino" +#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME +#define AUFS_XINO_TRUNC_INIT 64 /* blocks */ +#define AUFS_XINO_TRUNC_STEP 4 /* blocks */ +#define AUFS_DIRWH_DEF 3 +#define AUFS_RDCACHE_DEF 10 /* seconds */ +#define AUFS_WKQ_NAME AUFS_NAME "d" +#define AUFS_NWKQ_DEF 4 +#define AUFS_MFS_SECOND_DEF 30 /* seconds */ +#define AUFS_PLINK_WARN 100 /* number of plinks */ + +#ifdef CONFIG_AUFS_COMPAT +#define AUFS_DIROPQ_NAME "__dir_opaque" +#else +#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */ +#endif +#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME + +/* will be whiteouted doubly */ +#define AUFS_WH_BASENAME AUFS_WH_PFX AUFS_NAME +#define AUFS_WH_PLINKDIR AUFS_WH_PFX "plnk" +#define AUFS_WH_TMPDIR AUFS_WH_PFX ".tmp" + +/* ---------------------------------------------------------------------- */ + +/* ioctl */ +#if 0 /* reserved for future use */ +enum { + AuCtlErr, + AuCtlErr_Last +}; +enum { + AuCtl_REFRESH, AuCtl_REFRESHV, + AuCtl_FLUSH_PLINK, + AuCtl_CPUP, + AuCtl_CPDOWN, AuCtl_MVDOWN, + AuCtl_DIROPQ +}; + +struct aufs_ctl_cp { + int bsrc, bdst; + int err; +}; + +#define AuCtlType 'A' +#define AUFS_CTL_REFRESH _IO(AuCtlType, AuCtl_REFRESH) +#define AUFS_CTL_REFRESHV _IO(AuCtlType, AuCtl_REFRESHV) +#define AUFS_CTL_FLUSH_PLINK _IOR(AuCtlType, AuCtl_FLUSH_PLINK) +#define AUFS_CTL_CPUP _IOWR(AuCtlType, AuCtl_CPUP, struct aufs_ctl_cp) +#define AUFS_CTL_CPDOWN \ + _IOWR(AuCtlType, AuCtl_CPDOWN, struct aufs_ctl_cp) +#define AUFS_CTL_MVDOWN \ + _IOWR(AuCtlType, AuCtl_MVDOWN, struct aufs_ctl_cp) +#define AUFS_CTL_DIROPQ _IO(AuCtlType, AuCtl_DIROPQ) +#endif + +#endif /* __AUFS_TYPE_H__ */ --- linux-2.6.27.orig/include/linux/pnp.h +++ linux-2.6.27/include/linux/pnp.h @@ -22,9 +22,11 @@ * Resource Management */ #ifdef CONFIG_PNP -struct resource *pnp_get_resource(struct pnp_dev *, unsigned int, unsigned int); +struct resource *pnp_get_resource(struct pnp_dev *dev, unsigned long type, + unsigned int num); #else -static inline struct resource *pnp_get_resource(struct pnp_dev *dev, unsigned int type, unsigned int num) +static inline struct resource *pnp_get_resource(struct pnp_dev *dev, + unsigned long type, unsigned int num) { return NULL; } --- linux-2.6.27.orig/include/linux/libata.h +++ linux-2.6.27/include/linux/libata.h @@ -364,6 +364,7 @@ ATA_HORKAGE_IPM = (1 << 7), /* Link PM problems */ ATA_HORKAGE_IVB = (1 << 8), /* cbl det validity bit bugs */ ATA_HORKAGE_STUCK_ERR = (1 << 9), /* stuck ERR on next PACKET */ + ATA_HORKAGE_FIRMWARE_WARN = (1 << 12), /* firwmare update warning */ /* DMA mask for user DMA control: User visible values; DO NOT renumber */ --- linux-2.6.27.orig/include/linux/dcache.h +++ linux-2.6.27/include/linux/dcache.h @@ -299,9 +299,12 @@ /* * helper function for dentry_operations.d_dname() members */ +#define D_PATH_FAIL_DELETED 1 +#define D_PATH_DISCONNECT 2 extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...); -extern char *__d_path(const struct path *path, struct path *root, char *, int); +extern char *__d_path(const struct path *path, struct path *root, char *, int, + int); extern char *d_path(const struct path *, char *, int); extern char *dentry_path(struct dentry *, char *, int); --- linux-2.6.27.orig/include/linux/swap.h +++ linux-2.6.27/include/linux/swap.h @@ -149,6 +149,7 @@ unsigned int max; unsigned int inuse_pages; int next; /* next entry on swap list */ + void (*notify_swap_entry_free_fn) (unsigned long); }; struct swap_list_t { @@ -251,6 +252,7 @@ extern struct swap_info_struct *get_swap_info_struct(unsigned); extern int can_share_swap_page(struct page *); extern int remove_exclusive_swap_page(struct page *); +extern void set_notify_swap_entry_free(unsigned, void (*) (unsigned long)); struct backing_dev_info; /* linux/mm/thrash.c */ --- linux-2.6.27.orig/include/linux/syscalls.h +++ linux-2.6.27/include/linux/syscalls.h @@ -54,6 +54,7 @@ struct compat_timeval; struct robust_list_head; struct getcpu_cache; +struct old_linux_dirent; #include #include @@ -65,6 +66,74 @@ #include #include +#define __SC_DECL1(t1, a1) t1 a1 +#define __SC_DECL2(t2, a2, ...) t2 a2, __SC_DECL1(__VA_ARGS__) +#define __SC_DECL3(t3, a3, ...) t3 a3, __SC_DECL2(__VA_ARGS__) +#define __SC_DECL4(t4, a4, ...) t4 a4, __SC_DECL3(__VA_ARGS__) +#define __SC_DECL5(t5, a5, ...) t5 a5, __SC_DECL4(__VA_ARGS__) +#define __SC_DECL6(t6, a6, ...) t6 a6, __SC_DECL5(__VA_ARGS__) + +#define __SC_LONG1(t1, a1) long a1 +#define __SC_LONG2(t2, a2, ...) long a2, __SC_LONG1(__VA_ARGS__) +#define __SC_LONG3(t3, a3, ...) long a3, __SC_LONG2(__VA_ARGS__) +#define __SC_LONG4(t4, a4, ...) long a4, __SC_LONG3(__VA_ARGS__) +#define __SC_LONG5(t5, a5, ...) long a5, __SC_LONG4(__VA_ARGS__) +#define __SC_LONG6(t6, a6, ...) long a6, __SC_LONG5(__VA_ARGS__) + +#define __SC_CAST1(t1, a1) (t1) a1 +#define __SC_CAST2(t2, a2, ...) (t2) a2, __SC_CAST1(__VA_ARGS__) +#define __SC_CAST3(t3, a3, ...) (t3) a3, __SC_CAST2(__VA_ARGS__) +#define __SC_CAST4(t4, a4, ...) (t4) a4, __SC_CAST3(__VA_ARGS__) +#define __SC_CAST5(t5, a5, ...) (t5) a5, __SC_CAST4(__VA_ARGS__) +#define __SC_CAST6(t6, a6, ...) (t6) a6, __SC_CAST5(__VA_ARGS__) + +#define __SC_TEST(type) BUILD_BUG_ON(sizeof(type) > sizeof(long)) +#define __SC_TEST1(t1, a1) __SC_TEST(t1) +#define __SC_TEST2(t2, a2, ...) __SC_TEST(t2); __SC_TEST1(__VA_ARGS__) +#define __SC_TEST3(t3, a3, ...) __SC_TEST(t3); __SC_TEST2(__VA_ARGS__) +#define __SC_TEST4(t4, a4, ...) __SC_TEST(t4); __SC_TEST3(__VA_ARGS__) +#define __SC_TEST5(t5, a5, ...) __SC_TEST(t5); __SC_TEST4(__VA_ARGS__) +#define __SC_TEST6(t6, a6, ...) __SC_TEST(t6); __SC_TEST5(__VA_ARGS__) + +#define SYSCALL_DEFINE0(name) asmlinkage long sys_##name(void) +#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__) +#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__) +#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__) +#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__) +#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__) +#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__) + +#ifdef CONFIG_PPC64 +#define SYSCALL_ALIAS(alias, name) \ + asm ("\t.globl " #alias "\n\t.set " #alias ", " #name "\n" \ + "\t.globl ." #alias "\n\t.set ." #alias ", ." #name) +#else +#define SYSCALL_ALIAS(alias, name) \ + asm ("\t.globl " #alias "\n\t.set " #alias ", " #name) +#endif + +#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS + +#define SYSCALL_DEFINE(name) static inline long SYSC_##name +#define SYSCALL_DEFINEx(x, name, ...) \ + asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__)); \ + static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__)); \ + asmlinkage long SyS##name(__SC_LONG##x(__VA_ARGS__)) \ + { \ + __SC_TEST##x(__VA_ARGS__); \ + return (long) SYSC##name(__SC_CAST##x(__VA_ARGS__)); \ + } \ + SYSCALL_ALIAS(sys##name, SyS##name); \ + static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__)) + +#else /* CONFIG_HAVE_SYSCALL_WRAPPERS */ + +#define SYSCALL_DEFINE(name) asmlinkage long sys_##name +#define SYSCALL_DEFINEx(x, name, ...) \ + asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__)) + +#endif /* CONFIG_HAVE_SYSCALL_WRAPPERS */ + asmlinkage long sys_time(time_t __user *tloc); asmlinkage long sys_stime(time_t __user *tptr); asmlinkage long sys_gettimeofday(struct timeval __user *tv, @@ -77,7 +146,7 @@ asmlinkage long sys_gettid(void); asmlinkage long sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp); -asmlinkage unsigned long sys_alarm(unsigned int seconds); +asmlinkage long sys_alarm(unsigned int seconds); asmlinkage long sys_getpid(void); asmlinkage long sys_getppid(void); asmlinkage long sys_getuid(void); @@ -166,7 +235,7 @@ unsigned long flags); asmlinkage long sys_exit(int error_code); -asmlinkage void sys_exit_group(int error_code); +asmlinkage long sys_exit_group(int error_code); asmlinkage long sys_wait4(pid_t pid, int __user *stat_addr, int options, struct rusage __user *ru); asmlinkage long sys_waitid(int which, pid_t pid, @@ -196,7 +265,7 @@ asmlinkage long sys_rt_sigqueueinfo(int pid, int sig, siginfo_t __user *uinfo); asmlinkage long sys_sgetmask(void); asmlinkage long sys_ssetmask(int newmask); -asmlinkage unsigned long sys_signal(int sig, __sighandler_t handler); +asmlinkage long sys_signal(int sig, __sighandler_t handler); asmlinkage long sys_pause(void); asmlinkage long sys_sync(void); @@ -246,29 +315,29 @@ const void __user *value, size_t size, int flags); asmlinkage long sys_fsetxattr(int fd, const char __user *name, const void __user *value, size_t size, int flags); -asmlinkage ssize_t sys_getxattr(const char __user *path, const char __user *name, - void __user *value, size_t size); -asmlinkage ssize_t sys_lgetxattr(const char __user *path, const char __user *name, - void __user *value, size_t size); -asmlinkage ssize_t sys_fgetxattr(int fd, const char __user *name, - void __user *value, size_t size); -asmlinkage ssize_t sys_listxattr(const char __user *path, char __user *list, - size_t size); -asmlinkage ssize_t sys_llistxattr(const char __user *path, char __user *list, - size_t size); -asmlinkage ssize_t sys_flistxattr(int fd, char __user *list, size_t size); +asmlinkage long sys_getxattr(const char __user *path, const char __user *name, + void __user *value, size_t size); +asmlinkage long sys_lgetxattr(const char __user *path, const char __user *name, + void __user *value, size_t size); +asmlinkage long sys_fgetxattr(int fd, const char __user *name, + void __user *value, size_t size); +asmlinkage long sys_listxattr(const char __user *path, char __user *list, + size_t size); +asmlinkage long sys_llistxattr(const char __user *path, char __user *list, + size_t size); +asmlinkage long sys_flistxattr(int fd, char __user *list, size_t size); asmlinkage long sys_removexattr(const char __user *path, const char __user *name); asmlinkage long sys_lremovexattr(const char __user *path, const char __user *name); asmlinkage long sys_fremovexattr(int fd, const char __user *name); -asmlinkage unsigned long sys_brk(unsigned long brk); +asmlinkage long sys_brk(unsigned long brk); asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot); -asmlinkage unsigned long sys_mremap(unsigned long addr, - unsigned long old_len, unsigned long new_len, - unsigned long flags, unsigned long new_addr); +asmlinkage long sys_mremap(unsigned long addr, + unsigned long old_len, unsigned long new_len, + unsigned long flags, unsigned long new_addr); asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size, unsigned long prot, unsigned long pgoff, unsigned long flags); @@ -321,10 +390,10 @@ struct iocb __user * __user *); asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb __user *iocb, struct io_event __user *result); -asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, - off_t __user *offset, size_t count); -asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, - loff_t __user *offset, size_t count); +asmlinkage long sys_sendfile(int out_fd, int in_fd, + off_t __user *offset, size_t count); +asmlinkage long sys_sendfile64(int out_fd, int in_fd, + loff_t __user *offset, size_t count); asmlinkage long sys_readlink(const char __user *path, char __user *buf, int bufsiz); asmlinkage long sys_creat(const char __user *pathname, int mode); @@ -368,26 +437,25 @@ struct utimbuf __user *times); asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes); -asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, - unsigned int origin); +asmlinkage long sys_lseek(unsigned int fd, off_t offset, + unsigned int origin); asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high, unsigned long offset_low, loff_t __user *result, unsigned int origin); -asmlinkage ssize_t sys_read(unsigned int fd, char __user *buf, - size_t count); -asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count); -asmlinkage ssize_t sys_readv(unsigned long fd, - const struct iovec __user *vec, - unsigned long vlen); -asmlinkage ssize_t sys_write(unsigned int fd, const char __user *buf, - size_t count); -asmlinkage ssize_t sys_writev(unsigned long fd, - const struct iovec __user *vec, - unsigned long vlen); -asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf, - size_t count, loff_t pos); -asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf, - size_t count, loff_t pos); +asmlinkage long sys_read(unsigned int fd, char __user *buf, size_t count); +asmlinkage long sys_readahead(int fd, loff_t offset, size_t count); +asmlinkage long sys_readv(unsigned long fd, + const struct iovec __user *vec, + unsigned long vlen); +asmlinkage long sys_write(unsigned int fd, const char __user *buf, + size_t count); +asmlinkage long sys_writev(unsigned long fd, + const struct iovec __user *vec, + unsigned long vlen); +asmlinkage long sys_pread64(unsigned int fd, char __user *buf, + size_t count, loff_t pos); +asmlinkage long sys_pwrite64(unsigned int fd, const char __user *buf, + size_t count, loff_t pos); asmlinkage long sys_getcwd(char __user *buf, unsigned long size); asmlinkage long sys_mkdir(const char __user *pathname, int mode); asmlinkage long sys_chdir(const char __user *filename); @@ -477,7 +545,7 @@ asmlinkage long sys_mq_open(const char __user *name, int oflag, mode_t mode, struct mq_attr __user *attr); asmlinkage long sys_mq_unlink(const char __user *name); asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec __user *abs_timeout); -asmlinkage ssize_t sys_mq_timedreceive(mqd_t mqdes, char __user *msg_ptr, size_t msg_len, unsigned int __user *msg_prio, const struct timespec __user *abs_timeout); +asmlinkage long sys_mq_timedreceive(mqd_t mqdes, char __user *msg_ptr, size_t msg_len, unsigned int __user *msg_prio, const struct timespec __user *abs_timeout); asmlinkage long sys_mq_notify(mqd_t mqdes, const struct sigevent __user *notification); asmlinkage long sys_mq_getsetattr(mqd_t mqdes, const struct mq_attr __user *mqstat, struct mq_attr __user *omqstat); @@ -531,11 +599,6 @@ const int __user *nodes, int __user *status, int flags); -asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_page, - __u32 __user *pages, - const int __user *nodes, - int __user *status, - int flags); asmlinkage long sys_mbind(unsigned long start, unsigned long len, unsigned long mode, unsigned long __user *nmask, @@ -550,7 +613,7 @@ asmlinkage long sys_inotify_init1(int flags); asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask); -asmlinkage long sys_inotify_rm_watch(int fd, u32 wd); +asmlinkage long sys_inotify_rm_watch(int fd, __s32 wd); asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus); @@ -584,13 +647,6 @@ int bufsiz); asmlinkage long sys_utimensat(int dfd, char __user *filename, struct timespec __user *utimes, int flags); -asmlinkage long compat_sys_futimesat(unsigned int dfd, char __user *filename, - struct compat_timeval __user *t); -asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user * filename, - struct compat_stat __user *statbuf, - int flag); -asmlinkage long compat_sys_openat(unsigned int dfd, const char __user *filename, - int flags, int mode); asmlinkage long sys_unshare(unsigned long unshare_flags); asmlinkage long sys_splice(int fd_in, loff_t __user *off_in, @@ -622,6 +678,15 @@ asmlinkage long sys_eventfd(unsigned int count); asmlinkage long sys_eventfd2(unsigned int count, int flags); asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len); +asmlinkage long sys_old_readdir(unsigned int, struct old_linux_dirent __user *, unsigned int); +asmlinkage long sys_pselect6(int, fd_set __user *, fd_set __user *, + fd_set __user *, struct timespec __user *, + void __user *); +asmlinkage long sys_ppoll(struct pollfd __user *, unsigned int, + struct timespec __user *, const sigset_t __user *, + size_t); +asmlinkage long sys_pipe2(int __user *, int); +asmlinkage long sys_pipe(int __user *); int kernel_execve(const char *filename, char *const argv[], char *const envp[]); --- linux-2.6.27.orig/include/linux/namei.h +++ linux-2.6.27/include/linux/namei.h @@ -80,6 +80,8 @@ extern struct dentry *lock_rename(struct dentry *, struct dentry *); extern void unlock_rename(struct dentry *, struct dentry *); +struct dentry * __lookup_hash(struct qstr *name, struct dentry * base, struct nameidata *nd); + static inline void nd_set_link(struct nameidata *nd, char *path) { nd->saved_names[nd->depth] = path; --- linux-2.6.27.orig/include/linux/Kbuild +++ linux-2.6.27/include/linux/Kbuild @@ -41,6 +41,7 @@ header-y += bfs_fs.h header-y += blkpg.h header-y += bpqether.h +header-y += bsg.h header-y += can.h header-y += cdk.h header-y += chio.h --- linux-2.6.27.orig/include/linux/personality.h +++ linux-2.6.27/include/linux/personality.h @@ -40,7 +40,10 @@ * Security-relevant compatibility flags that must be * cleared upon setuid or setgid exec: */ -#define PER_CLEAR_ON_SETID (READ_IMPLIES_EXEC|ADDR_NO_RANDOMIZE) +#define PER_CLEAR_ON_SETID (READ_IMPLIES_EXEC | \ + ADDR_NO_RANDOMIZE | \ + ADDR_COMPAT_LAYOUT | \ + MMAP_PAGE_ZERO) /* * Personality types. --- linux-2.6.27.orig/include/linux/module.h +++ linux-2.6.27/include/linux/module.h @@ -387,7 +387,6 @@ static inline void __module_get(struct module *module) { if (module) { - BUG_ON(module_refcount(module) == 0); local_inc(&module->ref[get_cpu()].count); put_cpu(); } --- linux-2.6.27.orig/include/linux/jbd.h +++ linux-2.6.27/include/linux/jbd.h @@ -908,7 +908,7 @@ (journal_t *, unsigned long, unsigned long, unsigned long); extern int journal_create (journal_t *); extern int journal_load (journal_t *journal); -extern void journal_destroy (journal_t *); +extern int journal_destroy (journal_t *); extern int journal_recover (journal_t *journal); extern int journal_wipe (journal_t *, int); extern int journal_skip_recovery (journal_t *); --- linux-2.6.27.orig/include/linux/radix-tree.h +++ linux-2.6.27/include/linux/radix-tree.h @@ -136,7 +136,7 @@ */ static inline void *radix_tree_deref_slot(void **pslot) { - void *ret = *pslot; + void *ret = rcu_dereference(*pslot); if (unlikely(radix_tree_is_indirect_ptr(ret))) ret = RADIX_TREE_RETRY; return ret; --- linux-2.6.27.orig/include/linux/writeback.h +++ linux-2.6.27/include/linux/writeback.h @@ -30,7 +30,6 @@ enum writeback_sync_modes { WB_SYNC_NONE, /* Don't wait on anything */ WB_SYNC_ALL, /* Wait on every mapping */ - WB_SYNC_HOLD, /* Hold the inode on sb_dirty for sys_sync() */ }; /* --- linux-2.6.27.orig/include/linux/mm.h +++ linux-2.6.27/include/linux/mm.h @@ -253,7 +253,6 @@ */ static inline int get_page_unless_zero(struct page *page) { - VM_BUG_ON(PageTail(page)); return atomic_inc_not_zero(&page->_count); } --- linux-2.6.27.orig/include/linux/fs.h +++ linux-2.6.27/include/linux/fs.h @@ -361,6 +361,10 @@ * Not an attribute, but an auxilary info for filesystems wanting to * implement an ftruncate() like method. NOTE: filesystem should * check for (ia_valid & ATTR_FILE), and not for (ia_file != NULL). + * + * NOTE: With patches.apparmor/fsetattr.diff applied, this is + * for compatibility with external file system modules only. There + * should not be any in-kernel users left. */ struct file *ia_file; }; @@ -403,6 +407,9 @@ #define AOP_FLAG_UNINTERRUPTIBLE 0x0001 /* will not do a short write */ #define AOP_FLAG_CONT_EXPAND 0x0002 /* called from cont_expand */ +#define AOP_FLAG_NOFS 0x0004 /* used by filesystem to direct + * helper code (eg buffer layer) + * to clear GFP_FS from alloc */ /* * oh the beauties of C type declarations. @@ -1077,7 +1084,6 @@ struct rw_semaphore s_umount; struct mutex s_lock; int s_count; - int s_syncing; int s_need_sync_fs; atomic_t s_active; #ifdef CONFIG_SECURITY @@ -1160,13 +1166,13 @@ */ extern int vfs_permission(struct nameidata *, int); extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *); -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 *); +extern int vfs_mkdir(struct inode *, struct dentry *, struct vfsmount *, int); +extern int vfs_mknod(struct inode *, struct dentry *, struct vfsmount *, int, dev_t); +extern int vfs_symlink(struct inode *, struct dentry *, struct vfsmount *, const char *); +extern int vfs_link(struct dentry *, struct vfsmount *, struct inode *, struct dentry *, struct vfsmount *); +extern int vfs_rmdir(struct inode *, struct dentry *, struct vfsmount *); +extern int vfs_unlink(struct inode *, struct dentry *, struct vfsmount *); +extern int vfs_rename(struct inode *, struct dentry *, struct vfsmount *, struct inode *, struct dentry *, struct vfsmount *); /* * VFS dentry helper functions. @@ -1179,6 +1185,11 @@ extern int file_permission(struct file *, int); /* + * VFS path helper functions. + */ +extern int path_permission(struct path *, int); + +/* * File types * * NOTE! These match bits 12..15 of stat.st_mode @@ -1260,6 +1271,7 @@ ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); int (*setlease)(struct file *, long, struct file_lock **); + int (*fsetattr)(struct file *, struct iattr *); }; struct inode_operations { @@ -1612,8 +1624,8 @@ /* fs/open.c */ -extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, - struct file *filp); +extern int do_truncate(struct dentry *, struct vfsmount *, loff_t start, + unsigned int time_attrs, struct file *filp); extern long do_sys_open(int dfd, const char __user *filename, int flags, int mode); extern struct file *filp_open(const char *, int, int); @@ -1771,7 +1783,8 @@ #ifdef CONFIG_BLOCK extern sector_t bmap(struct inode *, sector_t); #endif -extern int notify_change(struct dentry *, struct iattr *); +extern int notify_change(struct dentry *, struct vfsmount *, struct iattr *); +extern int fnotify_change(struct dentry *, struct vfsmount *, struct iattr *, struct file *); extern int inode_permission(struct inode *, int); extern int generic_permission(struct inode *, int, int (*check_acl)(struct inode *, int)); @@ -1959,7 +1972,7 @@ extern void *page_follow_link_light(struct dentry *, struct nameidata *); extern void page_put_link(struct dentry *, struct nameidata *, void *); extern int __page_symlink(struct inode *inode, const char *symname, int len, - gfp_t gfp_mask); + int nofs); extern int page_symlink(struct inode *inode, const char *symname, int len); extern const struct inode_operations page_symlink_inode_operations; extern int generic_readlink(struct dentry *, char __user *, int); --- linux-2.6.27.orig/include/linux/pci_hotplug.h +++ linux-2.6.27/include/linux/pci_hotplug.h @@ -142,8 +142,6 @@ /** * struct hotplug_slot - used to register a physical slot with the hotplug pci core - * @name: the name of the slot being registered. This string must - * be unique amoung slots registered on this system. * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot * @info: pointer to the &struct hotplug_slot_info for the initial values for * this slot. @@ -153,7 +151,6 @@ * needs. */ struct hotplug_slot { - char *name; struct hotplug_slot_ops *ops; struct hotplug_slot_info *info; void (*release) (struct hotplug_slot *slot); @@ -165,7 +162,13 @@ }; #define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj) -extern int pci_hp_register(struct hotplug_slot *, struct pci_bus *, int nr); +static inline const char *hotplug_slot_name(const struct hotplug_slot *slot) +{ + return pci_slot_name(slot->pci_slot); +} + +extern int pci_hp_register(struct hotplug_slot *, struct pci_bus *, int nr, + const char *name); extern int pci_hp_deregister(struct hotplug_slot *slot); extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info *info); --- linux-2.6.27.orig/include/linux/if_vlan.h +++ linux-2.6.27/include/linux/if_vlan.h @@ -114,6 +114,8 @@ extern int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, u16 vlan_tci, int polling); +extern int vlan_hwaccel_do_receive(struct sk_buff *skb); + #else static inline struct net_device *vlan_dev_real_dev(const struct net_device *dev) { @@ -133,6 +135,11 @@ BUG(); return NET_XMIT_SUCCESS; } + +static inline int vlan_hwaccel_do_receive(struct sk_buff *skb) +{ + return 0; +} #endif /** --- linux-2.6.27.orig/include/linux/xattr.h +++ linux-2.6.27/include/linux/xattr.h @@ -16,6 +16,8 @@ #ifdef __KERNEL__ #include +#include +#include /* Namespaces */ #define XATTR_OS2_PREFIX "os2." @@ -47,10 +49,10 @@ }; ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t); -ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t); -ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size); -int vfs_setxattr(struct dentry *, const char *, const void *, size_t, int); -int vfs_removexattr(struct dentry *, const char *); +ssize_t vfs_getxattr(struct dentry *, struct vfsmount *, const char *, void *, size_t, struct file *file); +ssize_t vfs_listxattr(struct dentry *d, struct vfsmount *, char *list, size_t size, struct file *file); +int vfs_setxattr(struct dentry *, struct vfsmount *, const char *, const void *, size_t, int, struct file *file); +int vfs_removexattr(struct dentry *, struct vfsmount *mnt, const char *, struct file *file); ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size); ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size); --- linux-2.6.27.orig/include/linux/acpi.h +++ linux-2.6.27/include/linux/acpi.h @@ -202,6 +202,53 @@ #endif /* CONFIG_ACPI_WMI */ +#define ACPI_VIDEO_OUTPUT_SWITCHING 0x0001 +#define ACPI_VIDEO_DEVICE_POSTING 0x0002 +#define ACPI_VIDEO_ROM_AVAILABLE 0x0004 +#define ACPI_VIDEO_BACKLIGHT 0x0008 +#define ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR 0x0010 +#define ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO 0x0020 +#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR 0x0040 +#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO 0x0080 +#define ACPI_VIDEO_BACKLIGHT_DMI_VENDOR 0x0100 +#define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO 0x0200 +#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR 0x0400 +#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800 + +#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE) + +extern long acpi_video_get_capabilities(acpi_handle graphics_dev_handle); +extern long acpi_is_video_device(struct acpi_device *device); +extern int acpi_video_backlight_support(void); +extern int acpi_video_display_switch_support(void); + +#else + +static inline long acpi_video_get_capabilities(acpi_handle graphics_dev_handle) +{ + return 0; +} + +static inline long acpi_is_video_device(struct acpi_device *device) +{ + return 0; +} + +static inline int acpi_video_backlight_support(void) +{ + return ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR; +} + +static inline int acpi_video_display_switch_support(void) +{ + return 0; +} + +#endif /* defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE) */ + +#define acpi_vendor_backlight_support() \ + (acpi_video_backlight_support() & ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR) + extern int acpi_blacklisted(void); #ifdef CONFIG_DMI extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d); --- linux-2.6.27.orig/include/linux/usb_usual.h +++ linux-2.6.27/include/linux/usb_usual.h @@ -52,8 +52,9 @@ US_FLAG(MAX_SECTORS_MIN,0x00002000) \ /* Sets max_sectors to arch min */ \ US_FLAG(BULK_IGNORE_TAG,0x00004000) \ - /* Ignore tag mismatch in bulk operations */ - + /* Ignore tag mismatch in bulk operations */ \ + US_FLAG(CAPACITY_OK, 0x00010000) \ + /* READ CAPACITY response is correct */ #define US_FLAG(name, value) US_FL_##name = value , enum { US_DO_ALL_FLAGS }; --- linux-2.6.27.orig/include/linux/dmi.h +++ linux-2.6.27/include/linux/dmi.h @@ -81,6 +81,7 @@ extern void dmi_scan_machine(void); extern int dmi_get_year(int field); extern int dmi_name_in_vendors(const char *str); +extern int dmi_name_in_serial(const char *str); extern int dmi_available; extern int dmi_walk(void (*decode)(const struct dmi_header *)); @@ -93,6 +94,7 @@ static inline void dmi_scan_machine(void) { return; } static inline int dmi_get_year(int year) { return 0; } static inline int dmi_name_in_vendors(const char *s) { return 0; } +static inline int dmi_name_in_serial(const char *s) { return 0; } #define dmi_available 0 static inline int dmi_walk(void (*decode)(const struct dmi_header *)) { return -1; } --- linux-2.6.27.orig/include/linux/mount.h +++ linux-2.6.27/include/linux/mount.h @@ -114,4 +114,6 @@ extern spinlock_t vfsmount_lock; extern dev_t name_to_dev_t(char *name); +extern char *d_namespace_path(struct dentry *, struct vfsmount *, char *, int); + #endif /* _LINUX_MOUNT_H */ --- linux-2.6.27.orig/include/linux/audit.h +++ linux-2.6.27/include/linux/audit.h @@ -33,7 +33,7 @@ * 1200 - 1299 messages internal to the audit daemon * 1300 - 1399 audit event messages * 1400 - 1499 SE Linux use - * 1500 - 1599 kernel LSPP events + * 1500 - 1599 AppArmor use * 1600 - 1699 kernel crypto events * 1700 - 1799 kernel anomaly records * 1800 - 1999 future kernel use (maybe integrity labels and related events) @@ -119,6 +119,13 @@ #define AUDIT_MAC_UNLBL_STCADD 1416 /* NetLabel: add a static label */ #define AUDIT_MAC_UNLBL_STCDEL 1417 /* NetLabel: del a static label */ +#define AUDIT_APPARMOR_AUDIT 1501 /* AppArmor audited grants */ +#define AUDIT_APPARMOR_ALLOWED 1502 /* Allowed Access for learning */ +#define AUDIT_APPARMOR_DENIED 1503 +#define AUDIT_APPARMOR_HINT 1504 /* Process Tracking information */ +#define AUDIT_APPARMOR_STATUS 1505 /* Changes in config */ +#define AUDIT_APPARMOR_ERROR 1506 /* Internal AppArmor Errors */ + #define AUDIT_FIRST_KERN_ANOM_MSG 1700 #define AUDIT_LAST_KERN_ANOM_MSG 1799 #define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */ @@ -545,6 +552,9 @@ __attribute__((format(printf,4,5))); extern struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type); +extern void audit_log_vformat(struct audit_buffer *ab, + const char *fmt, va_list args) + __attribute__((format(printf,2,0))); extern void audit_log_format(struct audit_buffer *ab, const char *fmt, ...) __attribute__((format(printf,2,3))); --- linux-2.6.27.orig/include/linux/binfmts.h +++ linux-2.6.27/include/linux/binfmts.h @@ -36,6 +36,7 @@ unsigned long p; /* current top of mem */ unsigned int sh_bang:1, misc_bang:1; + unsigned int recursion_depth; struct file * file; int e_uid, e_gid; kernel_cap_t cap_post_exec_permitted; @@ -58,6 +59,7 @@ #define BINPRM_FLAGS_EXECFD_BIT 1 #define BINPRM_FLAGS_EXECFD (1 << BINPRM_FLAGS_EXECFD_BIT) +#define BINPRM_MAX_RECURSION 4 /* * This structure defines the functions that are used to load the binary formats that --- linux-2.6.27.orig/include/linux/sysctl.h +++ linux-2.6.27/include/linux/sysctl.h @@ -996,6 +996,8 @@ extern int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int, struct file *, void __user *, size_t *, loff_t *); +extern char *sysctl_pathname(ctl_table *, char *, int); + extern int do_sysctl (int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen); --- linux-2.6.27.orig/include/linux/pagemap.h +++ linux-2.6.27/include/linux/pagemap.h @@ -213,7 +213,8 @@ unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index, int tag, unsigned int nr_pages, struct page **pages); -struct page *__grab_cache_page(struct address_space *mapping, pgoff_t index); +struct page *grab_cache_page_write_begin(struct address_space *mapping, + pgoff_t index, unsigned flags); /* * Returns locked page at given index in given cache, creating it if needed. --- linux-2.6.27.orig/include/linux/idr.h +++ linux-2.6.27/include/linux/idr.h @@ -52,13 +52,14 @@ unsigned long bitmap; /* A zero bit means "space here" */ struct idr_layer *ary[1<task_list); } +void __wake_up_common(wait_queue_head_t *q, unsigned int mode, + int nr_exclusive, int sync, void *key); void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr, void *key); extern void __wake_up_locked(wait_queue_head_t *q, unsigned int mode); extern void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr); @@ -342,16 +344,19 @@ for (;;) { \ prepare_to_wait_exclusive(&wq, &__wait, \ TASK_INTERRUPTIBLE); \ - if (condition) \ + if (condition) { \ + finish_wait(&wq, &__wait); \ break; \ + } \ if (!signal_pending(current)) { \ schedule(); \ continue; \ } \ ret = -ERESTARTSYS; \ + abort_exclusive_wait(&wq, &__wait, \ + TASK_INTERRUPTIBLE, NULL); \ break; \ } \ - finish_wait(&wq, &__wait); \ } while (0) #define wait_event_interruptible_exclusive(wq, condition) \ @@ -440,6 +445,8 @@ void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state); void prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state); void finish_wait(wait_queue_head_t *q, wait_queue_t *wait); +void abort_exclusive_wait(wait_queue_head_t *q, wait_queue_t *wait, + unsigned int mode, void *key); int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key); int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *key); --- linux-2.6.27.orig/include/linux/splice.h +++ linux-2.6.27/include/linux/splice.h @@ -71,4 +71,10 @@ extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *, splice_direct_actor *); +extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags); +extern long do_splice_to(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags); + #endif --- linux-2.6.27.orig/include/linux/jbd2.h +++ linux-2.6.27/include/linux/jbd2.h @@ -850,7 +850,8 @@ */ struct block_device *j_dev; int j_blocksize; - unsigned long long j_blk_offset; + unsigned long long j_blk_offset; + char j_devname[BDEVNAME_SIZE+24]; /* * Device which holds the client fs. For internal journal this will be --- linux-2.6.27.orig/include/linux/console_struct.h +++ linux-2.6.27/include/linux/console_struct.h @@ -53,7 +53,6 @@ unsigned short vc_hi_font_mask; /* [#] Attribute set for upper 256 chars of font or 0 if not supported */ struct console_font vc_font; /* Current VC font set */ unsigned short vc_video_erase_char; /* Background erase character */ - unsigned short vc_scrl_erase_char; /* Erase character for scroll */ /* VT terminal data */ unsigned int vc_state; /* Escape sequence parser state */ unsigned int vc_npar,vc_par[NPAR]; /* Parameters of current escape sequence */ --- linux-2.6.27.orig/include/linux/compat.h +++ linux-2.6.27/include/linux/compat.h @@ -278,5 +278,18 @@ asmlinkage long compat_sys_timerfd_gettime(int ufd, struct compat_itimerspec __user *otmr); +asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_page, + __u32 __user *pages, + const int __user *nodes, + int __user *status, + int flags); +asmlinkage long compat_sys_futimesat(unsigned int dfd, char __user *filename, + struct compat_timeval __user *t); +asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user * filename, + struct compat_stat __user *statbuf, + int flag); +asmlinkage long compat_sys_openat(unsigned int dfd, const char __user *filename, + int flags, int mode); + #endif /* CONFIG_COMPAT */ #endif /* _LINUX_COMPAT_H */ --- linux-2.6.27.orig/include/linux/pci.h +++ linux-2.6.27/include/linux/pci.h @@ -64,6 +64,11 @@ struct kobject kobj; }; +static inline const char *pci_slot_name(const struct pci_slot *slot) +{ + return kobject_name(&slot->kobj); +} + /* File state for mmap()s on /proc/bus/pci/X/Y */ enum pci_mmap_state { pci_mmap_io, @@ -509,7 +514,8 @@ struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr); struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, - const char *name); + const char *name, + struct hotplug_slot *hotplug); void pci_destroy_slot(struct pci_slot *slot); void pci_update_slot_number(struct pci_slot *slot, int slot_nr); int pci_scan_slot(struct pci_bus *bus, int devfn); @@ -633,7 +639,7 @@ /* ROM control related routines */ void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size); void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom); -size_t pci_get_rom_size(void __iomem *rom, size_t size); +size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size); /* Power management related routines */ int pci_save_state(struct pci_dev *dev); --- linux-2.6.27.orig/include/linux/pci_ids.h +++ linux-2.6.27/include/linux/pci_ids.h @@ -1346,6 +1346,7 @@ #define PCI_DEVICE_ID_VIA_8783_0 0x3208 #define PCI_DEVICE_ID_VIA_8237 0x3227 #define PCI_DEVICE_ID_VIA_8251 0x3287 +#define PCI_DEVICE_ID_VIA_8261 0x3402 #define PCI_DEVICE_ID_VIA_8237A 0x3337 #define PCI_DEVICE_ID_VIA_8237S 0x3372 #define PCI_DEVICE_ID_VIA_SATA_EIDE 0x5324 @@ -1355,10 +1356,13 @@ #define PCI_DEVICE_ID_VIA_CX700 0x8324 #define PCI_DEVICE_ID_VIA_CX700_IDE 0x0581 #define PCI_DEVICE_ID_VIA_VX800 0x8353 +#define PCI_DEVICE_ID_VIA_VX855 0x8409 #define PCI_DEVICE_ID_VIA_8371_1 0x8391 #define PCI_DEVICE_ID_VIA_82C598_1 0x8598 #define PCI_DEVICE_ID_VIA_838X_1 0xB188 #define PCI_DEVICE_ID_VIA_83_87XX_1 0xB198 +#define PCI_DEVICE_ID_VIA_C409_IDE 0XC409 +#define PCI_DEVICE_ID_VIA_ANON 0xFFFF #define PCI_VENDOR_ID_SIEMENS 0x110A #define PCI_DEVICE_ID_SIEMENS_DSCC4 0x2102 @@ -1751,6 +1755,7 @@ #define PCI_DEVICE_ID_SIIG_8S_20x_650 0x2081 #define PCI_DEVICE_ID_SIIG_8S_20x_850 0x2082 #define PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL 0x2050 +#define PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL 0x2530 #define PCI_VENDOR_ID_RADISYS 0x1331 @@ -1780,6 +1785,7 @@ #define PCI_DEVICE_ID_SEALEVEL_UCOMM232 0x7202 #define PCI_DEVICE_ID_SEALEVEL_COMM4 0x7401 #define PCI_DEVICE_ID_SEALEVEL_COMM8 0x7801 +#define PCI_DEVICE_ID_SEALEVEL_7803 0x7803 #define PCI_DEVICE_ID_SEALEVEL_UCOMM8 0x7804 #define PCI_VENDOR_ID_HYPERCOPE 0x1365 @@ -2148,6 +2154,7 @@ #define PCI_DEVICE_ID_RDC_R6040 0x6040 #define PCI_DEVICE_ID_RDC_R6060 0x6060 #define PCI_DEVICE_ID_RDC_R6061 0x6061 +#define PCI_DEVICE_ID_RDC_D1010 0x1010 #define PCI_VENDOR_ID_LENOVO 0x17aa @@ -2378,6 +2385,7 @@ #define PCI_DEVICE_ID_INTEL_ICH7_0 0x27b8 #define PCI_DEVICE_ID_INTEL_ICH7_1 0x27b9 #define PCI_DEVICE_ID_INTEL_ICH7_30 0x27b0 +#define PCI_DEVICE_ID_INTEL_TGP_LPC 0x27bc #define PCI_DEVICE_ID_INTEL_ICH7_31 0x27bd #define PCI_DEVICE_ID_INTEL_ICH7_17 0x27da #define PCI_DEVICE_ID_INTEL_ICH7_19 0x27dd --- linux-2.6.27.orig/include/linux/connector.h +++ linux-2.6.27/include/linux/connector.h @@ -39,8 +39,10 @@ #define CN_IDX_V86D 0x4 #define CN_VAL_V86D_UVESAFB 0x1 #define CN_IDX_BB 0x5 /* BlackBoard, from the TSP GPL sampling framework */ +#define CN_IDX_DRBD 0x6 +#define CN_VAL_DRBD 0x1 -#define CN_NETLINK_USERS 6 +#define CN_NETLINK_USERS 7 /* * Maximum connector's message size. --- linux-2.6.27.orig/include/linux/time.h +++ linux-2.6.27/include/linux/time.h @@ -99,6 +99,7 @@ extern int update_persistent_clock(struct timespec now); extern int no_sync_cmos_clock __read_mostly; void timekeeping_init(void); +extern int timekeeping_suspended; unsigned long get_seconds(void); struct timespec current_kernel_time(void); --- linux-2.6.27.orig/include/linux/bio.h +++ linux-2.6.27/include/linux/bio.h @@ -98,6 +98,13 @@ unsigned int bi_size; /* residual I/O count */ /* + * To keep track of the max segment size, we account for the + * sizes of the first and last mergeable segments in this bio. + */ + unsigned int bi_seg_front_size; + unsigned int bi_seg_back_size; + + /* * To keep track of the max hw size, we account for the * sizes of the first and last virtually mergeable segments * in this bio --- linux-2.6.27.orig/include/linux/mtd/cfi.h +++ linux-2.6.27/include/linux/mtd/cfi.h @@ -281,9 +281,25 @@ /* * Returns the command address according to the given geometry. */ -static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, int interleave, int type) +static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, + struct map_info *map, struct cfi_private *cfi) { - return (cmd_ofs * type) * interleave; + unsigned bankwidth = map_bankwidth(map); + unsigned interleave = cfi_interleave(cfi); + unsigned type = cfi->device_type; + uint32_t addr; + + addr = (cmd_ofs * type) * interleave; + + /* Modify the unlock address if we are in compatiblity mode. + * For 16bit devices on 8 bit busses + * and 32bit devices on 16 bit busses + * set the low bit of the alternating bit sequence of the address. + */ + if (((type * interleave) > bankwidth) && ((uint8_t)cmd_ofs == 0xaa)) + addr |= (type >> 1)*interleave; + + return addr; } /* @@ -429,7 +445,7 @@ int type, map_word *prev_val) { map_word val; - uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, cfi_interleave(cfi), type); + uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, map, cfi); val = cfi_build_cmd(cmd, map, cfi); --- linux-2.6.27.orig/include/linux/can/core.h +++ linux-2.6.27/include/linux/can/core.h @@ -19,7 +19,7 @@ #include #include -#define CAN_VERSION "20071116" +#define CAN_VERSION "20081130" /* increment this number each time you change some user-space interface */ #define CAN_ABI_VERSION "8" --- linux-2.6.27.orig/include/linux/netfilter/Kbuild +++ linux-2.6.27/include/linux/netfilter/Kbuild @@ -31,6 +31,8 @@ header-y += xt_owner.h header-y += xt_pkttype.h header-y += xt_rateest.h +header-y += xt_policy.h +header-y += xt_quota.h header-y += xt_realm.h header-y += xt_sctp.h header-y += xt_state.h --- linux-2.6.27.orig/include/linux/netfilter_ipv6/Kbuild +++ linux-2.6.27/include/linux/netfilter_ipv6/Kbuild @@ -11,6 +11,7 @@ header-y += ip6t_limit.h header-y += ip6t_mac.h header-y += ip6t_mark.h +header-y += ip6t_mh.h header-y += ip6t_multiport.h header-y += ip6t_opts.h header-y += ip6t_owner.h --- linux-2.6.27.orig/include/linux/nfsd/nfsd.h +++ linux-2.6.27/include/linux/nfsd/nfsd.h @@ -85,7 +85,8 @@ #ifdef CONFIG_NFSD_V4 __be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *, struct nfs4_acl *); -int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **); +int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, + struct vfsmount *mnt, struct nfs4_acl **); #endif /* CONFIG_NFSD_V4 */ __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, char *name, int len, struct iattr *attrs, --- linux-2.6.27.orig/include/acpi/pdc_intel.h +++ linux-2.6.27/include/acpi/pdc_intel.h @@ -14,6 +14,7 @@ #define ACPI_PDC_SMP_T_SWCOORD (0x0080) #define ACPI_PDC_C_C1_FFH (0x0100) #define ACPI_PDC_C_C2C3_FFH (0x0200) +#define ACPI_PDC_SMP_P_HWCOORD (0x0800) #define ACPI_PDC_EST_CAPABILITY_SMP (ACPI_PDC_SMP_C1PT | \ ACPI_PDC_C_C1_HALT | \ @@ -22,6 +23,7 @@ #define ACPI_PDC_EST_CAPABILITY_SWSMP (ACPI_PDC_SMP_C1PT | \ ACPI_PDC_C_C1_HALT | \ ACPI_PDC_SMP_P_SWCOORD | \ + ACPI_PDC_SMP_P_HWCOORD | \ ACPI_PDC_P_FFH) #define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \ --- linux-2.6.27.orig/include/acpi/acpi_bus.h +++ linux-2.6.27/include/acpi/acpi_bus.h @@ -373,6 +373,8 @@ int register_acpi_bus_type(struct acpi_bus_type *); int unregister_acpi_bus_type(struct acpi_bus_type *); struct device *acpi_get_physical_device(acpi_handle); +struct device *acpi_get_physical_pci_device(acpi_handle); + /* helper */ acpi_handle acpi_get_child(acpi_handle, acpi_integer); acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int); --- linux-2.6.27.orig/include/acpi/acpi_drivers.h +++ linux-2.6.27/include/acpi/acpi_drivers.h @@ -93,6 +93,7 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev); int acpi_power_get_inferred_state(struct acpi_device *device); int acpi_power_transition(struct acpi_device *device, int state); +extern int acpi_power_nocheck; #endif /* -------------------------------------------------------------------------- --- linux-2.6.27.orig/include/acpi/actypes.h +++ linux-2.6.27/include/acpi/actypes.h @@ -1225,8 +1225,8 @@ #pragma pack() -#define ACPI_RS_SIZE_MIN 12 #define ACPI_RS_SIZE_NO_DATA 8 /* Id + Length fields */ +#define ACPI_RS_SIZE_MIN (u32) ACPI_ROUND_UP_TO_NATIVE_WORD (12) #define ACPI_RS_SIZE(type) (u32) (ACPI_RS_SIZE_NO_DATA + sizeof (type)) #define ACPI_NEXT_RESOURCE(res) (struct acpi_resource *)((u8 *) res + res->length) --- linux-2.6.27.orig/include/asm-parisc/tlbflush.h +++ linux-2.6.27/include/asm-parisc/tlbflush.h @@ -44,9 +44,12 @@ { BUG_ON(mm == &init_mm); /* Should never happen */ -#ifdef CONFIG_SMP +#if 1 || defined(CONFIG_SMP) flush_tlb_all(); #else + /* FIXME: currently broken, causing space id and protection ids + * to go out of sync, resulting in faults on userspace accesses. + */ if (mm) { if (mm->context != 0) free_sid(mm->context); --- linux-2.6.27.orig/include/asm-x86/cpufeature.h +++ linux-2.6.27/include/asm-x86/cpufeature.h @@ -82,6 +82,7 @@ #define X86_FEATURE_11AP (3*32+19) /* Bad local APIC aka 11AP */ #define X86_FEATURE_NOPL (3*32+20) /* The NOPL (0F 1F) instructions */ #define X86_FEATURE_AMDC1E (3*32+21) /* AMD C1E detected */ +#define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ #define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */ @@ -94,6 +95,7 @@ #define X86_FEATURE_XTPR (4*32+14) /* Send Task Priority Messages */ #define X86_FEATURE_DCA (4*32+18) /* Direct Cache Access */ #define X86_FEATURE_XMM4_2 (4*32+20) /* Streaming SIMD Extensions-4.2 */ +#define X86_FEATURE_HYPERVISOR (4*32+31) /* Running on a hypervisor */ /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */ #define X86_FEATURE_XSTORE (5*32+ 2) /* on-CPU RNG present (xstore insn) */ @@ -193,6 +195,7 @@ #define cpu_has_arch_perfmon boot_cpu_has(X86_FEATURE_ARCH_PERFMON) #define cpu_has_pat boot_cpu_has(X86_FEATURE_PAT) #define cpu_has_xmm4_2 boot_cpu_has(X86_FEATURE_XMM4_2) +#define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR) #if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64) # define cpu_has_invlpg 1 --- linux-2.6.27.orig/include/asm-x86/pgalloc.h +++ linux-2.6.27/include/asm-x86/pgalloc.h @@ -42,6 +42,7 @@ static inline void pte_free(struct mm_struct *mm, struct page *pte) { + pgtable_page_dtor(pte); __free_page(pte); } --- linux-2.6.27.orig/include/asm-x86/pci_64.h +++ linux-2.6.27/include/asm-x86/pci_64.h @@ -34,8 +34,6 @@ */ #define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys) -#if defined(CONFIG_GART_IOMMU) || defined(CONFIG_CALGARY_IOMMU) - #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ dma_addr_t ADDR_NAME; #define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ @@ -49,18 +47,6 @@ #define pci_unmap_len_set(PTR, LEN_NAME, VAL) \ (((PTR)->LEN_NAME) = (VAL)) -#else -/* No IOMMU */ - -#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) -#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) -#define pci_unmap_addr(PTR, ADDR_NAME) (0) -#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0) -#define pci_unmap_len(PTR, LEN_NAME) (0) -#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) - -#endif - #endif /* __KERNEL__ */ #endif /* __x8664_PCI_H */ --- linux-2.6.27.orig/include/asm-x86/processor.h +++ linux-2.6.27/include/asm-x86/processor.h @@ -109,6 +109,7 @@ /* Index into per_cpu list: */ u16 cpu_index; #endif + unsigned int x86_hyper_vendor; } __attribute__((__aligned__(SMP_CACHE_BYTES))); #define X86_VENDOR_INTEL 0 @@ -122,6 +123,9 @@ #define X86_VENDOR_UNKNOWN 0xff +#define X86_HYPER_VENDOR_NONE 0 +#define X86_HYPER_VENDOR_VMWARE 1 + /* * capabilities of CPUs */ --- linux-2.6.27.orig/include/asm-x86/seccomp_32.h +++ linux-2.6.27/include/asm-x86/seccomp_32.h @@ -1,12 +1,6 @@ #ifndef _ASM_SECCOMP_H #define _ASM_SECCOMP_H -#include - -#ifdef TIF_32BIT -#error "unexpected TIF_32BIT on i386" -#endif - #include #define __NR_seccomp_read __NR_read --- linux-2.6.27.orig/include/asm-x86/vmi.h +++ linux-2.6.27/include/asm-x86/vmi.h @@ -223,9 +223,15 @@ } __attribute__((packed)); /* Function prototypes for bootstrapping */ +#ifdef CONFIG_VMI extern void vmi_init(void); +extern void vmi_activate(void); extern void vmi_bringup(void); -extern void vmi_apply_boot_page_allocations(void); +#else +static inline void vmi_init(void) {} +static inline void vmi_activate(void) {} +static inline void vmi_bringup(void) {} +#endif /* State needed to start an application processor in an SMP system. */ struct vmi_ap_state { --- linux-2.6.27.orig/include/asm-x86/mmzone_32.h +++ linux-2.6.27/include/asm-x86/mmzone_32.h @@ -34,10 +34,14 @@ extern int early_pfn_to_nid(unsigned long pfn); +extern void resume_map_numa_kva(pgd_t *pgd); + #else /* !CONFIG_NUMA */ #define get_memcfg_numa get_memcfg_numa_flat +static inline void resume_map_numa_kva(pgd_t *pgd) {} + #endif /* CONFIG_NUMA */ #ifdef CONFIG_DISCONTIGMEM --- linux-2.6.27.orig/include/asm-x86/vmware.h +++ linux-2.6.27/include/asm-x86/vmware.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2008, VMware, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef ASM_X86__VMWARE_H +#define ASM_X86__VMWARE_H + +extern unsigned long vmware_get_tsc_khz(void); +extern int vmware_platform(void); +extern void vmware_set_feature_bits(struct cpuinfo_x86 *c); + +#endif --- linux-2.6.27.orig/include/asm-x86/seccomp_64.h +++ linux-2.6.27/include/asm-x86/seccomp_64.h @@ -1,14 +1,6 @@ #ifndef _ASM_SECCOMP_H #define _ASM_SECCOMP_H -#include - -#ifdef TIF_32BIT -#error "unexpected TIF_32BIT on x86_64" -#else -#define TIF_32BIT TIF_IA32 -#endif - #include #include --- linux-2.6.27.orig/include/asm-x86/hypervisor.h +++ linux-2.6.27/include/asm-x86/hypervisor.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2008, VMware, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef ASM_X86__HYPERVISOR_H +#define ASM_X86__HYPERVISOR_H + +extern unsigned long get_hypervisor_tsc_freq(void); +extern void init_hypervisor(struct cpuinfo_x86 *c); + +#endif --- linux-2.6.27.orig/include/net/af_unix.h +++ linux-2.6.27/include/net/af_unix.h @@ -9,6 +9,7 @@ extern void unix_inflight(struct file *fp); extern void unix_notinflight(struct file *fp); extern void unix_gc(void); +extern void wait_for_unix_gc(void); #define UNIX_HASH_SIZE 256 @@ -54,6 +55,7 @@ atomic_long_t inflight; spinlock_t lock; unsigned int gc_candidate : 1; + unsigned int gc_maybe_cycle : 1; wait_queue_head_t peer_wait; }; #define unix_sk(__sk) ((struct unix_sock *)__sk) --- linux-2.6.27.orig/include/net/scm.h +++ linux-2.6.27/include/net/scm.h @@ -14,8 +14,9 @@ struct scm_fp_list { - int count; - struct file *fp[SCM_MAX_FD]; + struct list_head list; + int count; + struct file *fp[SCM_MAX_FD]; }; struct scm_cookie --- linux-2.6.27.orig/include/net/sctp/checksum.h +++ linux-2.6.27/include/net/sctp/checksum.h @@ -79,5 +79,5 @@ static inline __be32 sctp_end_cksum(__be32 crc32) { - return ~crc32; + return (__force __be32)~cpu_to_le32((__force u32)crc32); } --- linux-2.6.27.orig/include/math-emu/op-common.h +++ linux-2.6.27/include/math-emu/op-common.h @@ -139,18 +139,27 @@ if (X##_e <= _FP_WFRACBITS_##fs) \ { \ _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs); \ - _FP_ROUND(wc, X); \ if (_FP_FRAC_HIGH_##fs(X) \ & (_FP_OVERFLOW_##fs >> 1)) \ { \ X##_e = 1; \ _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ - FP_SET_EXCEPTION(FP_EX_INEXACT); \ } \ else \ { \ - X##_e = 0; \ - _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \ + _FP_ROUND(wc, X); \ + if (_FP_FRAC_HIGH_##fs(X) \ + & (_FP_OVERFLOW_##fs >> 1)) \ + { \ + X##_e = 1; \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + FP_SET_EXCEPTION(FP_EX_INEXACT); \ + } \ + else \ + { \ + X##_e = 0; \ + _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \ + } \ } \ if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT) || \ (FP_TRAPPING_EXCEPTIONS & FP_EX_UNDERFLOW)) \ --- linux-2.6.27.orig/fs/binfmt_misc.c +++ linux-2.6.27/fs/binfmt_misc.c @@ -117,7 +117,7 @@ goto _ret; retval = -ENOEXEC; - if (bprm->misc_bang) + if (bprm->recursion_depth > BINPRM_MAX_RECURSION) goto _ret; /* to keep locking time low, we copy the interpreter string */ @@ -197,7 +197,7 @@ if (retval < 0) goto _error; - bprm->misc_bang = 1; + bprm->recursion_depth++; retval = search_binary_handler (bprm, regs); if (retval < 0) --- linux-2.6.27.orig/fs/binfmt_script.c +++ linux-2.6.27/fs/binfmt_script.c @@ -22,14 +22,15 @@ char interp[BINPRM_BUF_SIZE]; int retval; - if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || (bprm->sh_bang)) + if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || + (bprm->recursion_depth > BINPRM_MAX_RECURSION)) return -ENOEXEC; /* * This section does the #! interpretation. * Sorta complicated, but hopefully it will work. -TYT */ - bprm->sh_bang = 1; + bprm->recursion_depth++; allow_write_access(bprm->file); fput(bprm->file); bprm->file = NULL; --- linux-2.6.27.orig/fs/open.c +++ linux-2.6.27/fs/open.c @@ -122,7 +122,7 @@ return 0; } -asmlinkage long sys_statfs(const char __user *pathname, struct statfs __user * buf) +SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf) { struct path path; int error; @@ -138,8 +138,7 @@ return error; } - -asmlinkage long sys_statfs64(const char __user *pathname, size_t sz, struct statfs64 __user *buf) +SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf) { struct path path; long error; @@ -157,8 +156,7 @@ return error; } - -asmlinkage long sys_fstatfs(unsigned int fd, struct statfs __user * buf) +SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf) { struct file * file; struct statfs tmp; @@ -176,7 +174,7 @@ return error; } -asmlinkage long sys_fstatfs64(unsigned int fd, size_t sz, struct statfs64 __user *buf) +SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf) { struct file * file; struct statfs64 tmp; @@ -197,8 +195,8 @@ return error; } -int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, - struct file *filp) +int do_truncate(struct dentry *dentry, struct vfsmount *mnt, loff_t length, + unsigned int time_attrs, struct file *filp) { int err; struct iattr newattrs; @@ -209,16 +207,15 @@ newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | time_attrs; - if (filp) { - newattrs.ia_file = filp; + + if (filp) newattrs.ia_valid |= ATTR_FILE; - } /* Remove suid/sgid on truncate too */ newattrs.ia_valid |= should_remove_suid(dentry); mutex_lock(&dentry->d_inode->i_mutex); - err = notify_change(dentry, &newattrs); + err = fnotify_change(dentry, mnt, &newattrs, filp); mutex_unlock(&dentry->d_inode->i_mutex); return err; } @@ -251,7 +248,7 @@ if (error) goto dput_and_out; - error = inode_permission(inode, MAY_WRITE); + error = path_permission(&path, MAY_WRITE); if (error) goto mnt_drop_write_and_out; @@ -274,7 +271,7 @@ error = locks_verify_truncate(inode, NULL, length); if (!error) { DQUOT_INIT(inode); - error = do_truncate(path.dentry, length, 0, NULL); + error = do_truncate(path.dentry, path.mnt, length, 0, NULL); } put_write_and_out: @@ -287,7 +284,7 @@ return error; } -asmlinkage long sys_truncate(const char __user * path, unsigned long length) +SYSCALL_DEFINE2(truncate, const char __user *, path, unsigned long, length) { /* on 32-bit boxen it will cut the range 2^31--2^32-1 off */ return do_sys_truncate(path, (long)length); @@ -329,14 +326,15 @@ error = locks_verify_truncate(inode, file, length); if (!error) - error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file); + error = do_truncate(dentry, file->f_path.mnt, length, + ATTR_MTIME|ATTR_CTIME, file); out_putf: fput(file); out: return error; } -asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length) +SYSCALL_DEFINE2(ftruncate, unsigned int, fd, unsigned long, length) { long ret = do_sys_ftruncate(fd, length, 1); /* avoid REGPARM breakage on x86: */ @@ -346,21 +344,35 @@ /* LFS versions of truncate are only needed on 32 bit machines */ #if BITS_PER_LONG == 32 -asmlinkage long sys_truncate64(const char __user * path, loff_t length) +SYSCALL_DEFINE(truncate64)(const char __user * path, loff_t length) { return do_sys_truncate(path, length); } +#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS +asmlinkage long SyS_truncate64(long path, loff_t length) +{ + return SYSC_truncate64((const char __user *) path, length); +} +SYSCALL_ALIAS(sys_truncate64, SyS_truncate64); +#endif -asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length) +SYSCALL_DEFINE(ftruncate64)(unsigned int fd, loff_t length) { long ret = do_sys_ftruncate(fd, length, 0); /* avoid REGPARM breakage on x86: */ asmlinkage_protect(2, ret, fd, length); return ret; } +#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS +asmlinkage long SyS_ftruncate64(long fd, loff_t length) +{ + return SYSC_ftruncate64((unsigned int) fd, length); +} +SYSCALL_ALIAS(sys_ftruncate64, SyS_ftruncate64); #endif +#endif /* BITS_PER_LONG == 32 */ -asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len) +SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len) { struct file *file; struct inode *inode; @@ -417,13 +429,20 @@ out: return ret; } +#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS +asmlinkage long SyS_fallocate(long fd, long mode, loff_t offset, loff_t len) +{ + return SYSC_fallocate((int)fd, (int)mode, offset, len); +} +SYSCALL_ALIAS(sys_fallocate, SyS_fallocate); +#endif /* * access() needs to use the real uid/gid, not the effective uid/gid. * We do this by temporarily clearing all FS-related capabilities and * switching the fsuid/fsgid around to the real ones. */ -asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) +SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) { struct path path; struct inode *inode; @@ -474,7 +493,7 @@ goto out_path_release; } - res = inode_permission(inode, mode | MAY_ACCESS); + res = path_permission(&path, mode | MAY_ACCESS); /* SuS v2 requires we report a read only fs too */ if (res || !(mode & S_IWOTH) || special_file(inode->i_mode)) goto out_path_release; @@ -503,12 +522,12 @@ return res; } -asmlinkage long sys_access(const char __user *filename, int mode) +SYSCALL_DEFINE2(access, const char __user *, filename, int, mode) { return sys_faccessat(AT_FDCWD, filename, mode); } -asmlinkage long sys_chdir(const char __user * filename) +SYSCALL_DEFINE1(chdir, const char __user *, filename) { struct path path; int error; @@ -517,7 +536,7 @@ if (error) goto out; - error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS); + error = path_permission(&path, MAY_EXEC | MAY_ACCESS); if (error) goto dput_and_out; @@ -529,7 +548,7 @@ return error; } -asmlinkage long sys_fchdir(unsigned int fd) +SYSCALL_DEFINE1(fchdir, unsigned int, fd) { struct file *file; struct inode *inode; @@ -546,7 +565,7 @@ if (!S_ISDIR(inode->i_mode)) goto out_putf; - error = inode_permission(inode, MAY_EXEC | MAY_ACCESS); + error = path_permission(&file->f_path, MAY_EXEC | MAY_ACCESS); if (!error) set_fs_pwd(current->fs, &file->f_path); out_putf: @@ -555,7 +574,7 @@ return error; } -asmlinkage long sys_chroot(const char __user * filename) +SYSCALL_DEFINE1(chroot, const char __user *, filename) { struct path path; int error; @@ -564,7 +583,7 @@ if (error) goto out; - error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS); + error = path_permission(&path, MAY_EXEC | MAY_ACCESS); if (error) goto dput_and_out; @@ -580,7 +599,7 @@ return error; } -asmlinkage long sys_fchmod(unsigned int fd, mode_t mode) +SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode) { struct inode * inode; struct dentry * dentry; @@ -604,8 +623,8 @@ if (mode == (mode_t) -1) mode = inode->i_mode; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); - newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; - err = notify_change(dentry, &newattrs); + newattrs.ia_valid = ATTR_MODE | ATTR_CTIME | ATTR_FILE; + err = fnotify_change(dentry, file->f_path.mnt, &newattrs, file); mutex_unlock(&inode->i_mutex); mnt_drop_write(file->f_path.mnt); out_putf: @@ -614,8 +633,7 @@ return err; } -asmlinkage long sys_fchmodat(int dfd, const char __user *filename, - mode_t mode) +SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode) { struct path path; struct inode *inode; @@ -635,7 +653,7 @@ mode = inode->i_mode; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; - error = notify_change(path.dentry, &newattrs); + error = notify_change(path.dentry, path.mnt, &newattrs); mutex_unlock(&inode->i_mutex); mnt_drop_write(path.mnt); dput_and_out: @@ -644,12 +662,13 @@ return error; } -asmlinkage long sys_chmod(const char __user *filename, mode_t mode) +SYSCALL_DEFINE2(chmod, const char __user *, filename, mode_t, mode) { return sys_fchmodat(AT_FDCWD, filename, mode); } -static int chown_common(struct dentry * dentry, uid_t user, gid_t group) +static int chown_common(struct dentry * dentry, struct vfsmount *mnt, + uid_t user, gid_t group, struct file *file) { struct inode *inode = dentry->d_inode; int error; @@ -667,14 +686,17 @@ if (!S_ISDIR(inode->i_mode)) newattrs.ia_valid |= ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; + if (file) + newattrs.ia_valid |= ATTR_FILE; + mutex_lock(&inode->i_mutex); - error = notify_change(dentry, &newattrs); + error = fnotify_change(dentry, mnt, &newattrs, file); mutex_unlock(&inode->i_mutex); return error; } -asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group) +SYSCALL_DEFINE3(chown, const char __user *, filename, uid_t, user, gid_t, group) { struct path path; int error; @@ -685,7 +707,7 @@ error = mnt_want_write(path.mnt); if (error) goto out_release; - error = chown_common(path.dentry, user, group); + error = chown_common(path.dentry, path.mnt, user, group, NULL); mnt_drop_write(path.mnt); out_release: path_put(&path); @@ -693,8 +715,8 @@ return error; } -asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user, - gid_t group, int flag) +SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user, + gid_t, group, int, flag) { struct path path; int error = -EINVAL; @@ -710,7 +732,7 @@ error = mnt_want_write(path.mnt); if (error) goto out_release; - error = chown_common(path.dentry, user, group); + error = chown_common(path.dentry, path.mnt, user, group, NULL); mnt_drop_write(path.mnt); out_release: path_put(&path); @@ -718,7 +740,7 @@ return error; } -asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group) +SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group) { struct path path; int error; @@ -729,7 +751,7 @@ error = mnt_want_write(path.mnt); if (error) goto out_release; - error = chown_common(path.dentry, user, group); + error = chown_common(path.dentry, path.mnt, user, group, NULL); mnt_drop_write(path.mnt); out_release: path_put(&path); @@ -737,8 +759,7 @@ return error; } - -asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group) +SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) { struct file * file; int error = -EBADF; @@ -753,7 +774,7 @@ goto out_fput; dentry = file->f_path.dentry; audit_inode(NULL, dentry); - error = chown_common(dentry, user, group); + error = chown_common(dentry, file->f_path.mnt, user, group, file); mnt_drop_write(file->f_path.mnt); out_fput: fput(file); @@ -1029,7 +1050,7 @@ return fd; } -asmlinkage long sys_open(const char __user *filename, int flags, int mode) +SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode) { long ret; @@ -1042,8 +1063,8 @@ return ret; } -asmlinkage long sys_openat(int dfd, const char __user *filename, int flags, - int mode) +SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags, + int, mode) { long ret; @@ -1062,7 +1083,7 @@ * For backward compatibility? Maybe this should be moved * into arch/i386 instead? */ -asmlinkage long sys_creat(const char __user * pathname, int mode) +SYSCALL_DEFINE2(creat, const char __user *, pathname, int, mode) { return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); } @@ -1098,7 +1119,7 @@ * releasing the fd. This ensures that one clone task can't release * an fd while another clone is opening it. */ -asmlinkage long sys_close(unsigned int fd) +SYSCALL_DEFINE1(close, unsigned int, fd) { struct file * filp; struct files_struct *files = current->files; @@ -1131,14 +1152,13 @@ spin_unlock(&files->file_lock); return -EBADF; } - EXPORT_SYMBOL(sys_close); /* * This routine simulates a hangup on the tty, to arrange that users * are given clean terminals at login time. */ -asmlinkage long sys_vhangup(void) +SYSCALL_DEFINE0(vhangup) { if (capable(CAP_SYS_TTY_CONFIG)) { /* XXX: this needs locking */ --- linux-2.6.27.orig/fs/stat.c +++ linux-2.6.27/fs/stat.c @@ -152,7 +152,7 @@ return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; } -asmlinkage long sys_stat(char __user * filename, struct __old_kernel_stat __user * statbuf) +SYSCALL_DEFINE2(stat, char __user *, filename, struct __old_kernel_stat __user *, statbuf) { struct kstat stat; int error = vfs_stat_fd(AT_FDCWD, filename, &stat); @@ -162,7 +162,8 @@ return error; } -asmlinkage long sys_lstat(char __user * filename, struct __old_kernel_stat __user * statbuf) + +SYSCALL_DEFINE2(lstat, char __user *, filename, struct __old_kernel_stat __user *, statbuf) { struct kstat stat; int error = vfs_lstat_fd(AT_FDCWD, filename, &stat); @@ -172,7 +173,8 @@ return error; } -asmlinkage long sys_fstat(unsigned int fd, struct __old_kernel_stat __user * statbuf) + +SYSCALL_DEFINE2(fstat, unsigned int, fd, struct __old_kernel_stat __user *, statbuf) { struct kstat stat; int error = vfs_fstat(fd, &stat); @@ -235,7 +237,7 @@ return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; } -asmlinkage long sys_newstat(char __user *filename, struct stat __user *statbuf) +SYSCALL_DEFINE2(newstat, char __user *, filename, struct stat __user *, statbuf) { struct kstat stat; int error = vfs_stat_fd(AT_FDCWD, filename, &stat); @@ -246,7 +248,7 @@ return error; } -asmlinkage long sys_newlstat(char __user *filename, struct stat __user *statbuf) +SYSCALL_DEFINE2(newlstat, char __user *, filename, struct stat __user *, statbuf) { struct kstat stat; int error = vfs_lstat_fd(AT_FDCWD, filename, &stat); @@ -258,8 +260,8 @@ } #if !defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_SYS_NEWFSTATAT) -asmlinkage long sys_newfstatat(int dfd, char __user *filename, - struct stat __user *statbuf, int flag) +SYSCALL_DEFINE4(newfstatat, int, dfd, char __user *, filename, + struct stat __user *, statbuf, int, flag) { struct kstat stat; int error = -EINVAL; @@ -280,7 +282,7 @@ } #endif -asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf) +SYSCALL_DEFINE2(newfstat, unsigned int, fd, struct stat __user *, statbuf) { struct kstat stat; int error = vfs_fstat(fd, &stat); @@ -291,8 +293,8 @@ return error; } -asmlinkage long sys_readlinkat(int dfd, const char __user *pathname, - char __user *buf, int bufsiz) +SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname, + char __user *, buf, int, bufsiz) { struct path path; int error; @@ -306,7 +308,7 @@ error = -EINVAL; if (inode->i_op && inode->i_op->readlink) { - error = security_inode_readlink(path.dentry); + error = security_inode_readlink(path.dentry, path.mnt); if (!error) { touch_atime(path.mnt, path.dentry); error = inode->i_op->readlink(path.dentry, @@ -318,8 +320,8 @@ return error; } -asmlinkage long sys_readlink(const char __user *path, char __user *buf, - int bufsiz) +SYSCALL_DEFINE3(readlink, const char __user *, path, char __user *, buf, + int, bufsiz) { return sys_readlinkat(AT_FDCWD, path, buf, bufsiz); } @@ -365,7 +367,7 @@ return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; } -asmlinkage long sys_stat64(char __user * filename, struct stat64 __user * statbuf) +SYSCALL_DEFINE2(stat64, char __user *, filename, struct stat64 __user *, statbuf) { struct kstat stat; int error = vfs_stat(filename, &stat); @@ -375,7 +377,8 @@ return error; } -asmlinkage long sys_lstat64(char __user * filename, struct stat64 __user * statbuf) + +SYSCALL_DEFINE2(lstat64, char __user *, filename, struct stat64 __user *, statbuf) { struct kstat stat; int error = vfs_lstat(filename, &stat); @@ -385,7 +388,8 @@ return error; } -asmlinkage long sys_fstat64(unsigned long fd, struct stat64 __user * statbuf) + +SYSCALL_DEFINE2(fstat64, unsigned long, fd, struct stat64 __user *, statbuf) { struct kstat stat; int error = vfs_fstat(fd, &stat); @@ -396,8 +400,8 @@ return error; } -asmlinkage long sys_fstatat64(int dfd, char __user *filename, - struct stat64 __user *statbuf, int flag) +SYSCALL_DEFINE4(fstatat64, int, dfd, char __user *, filename, + struct stat64 __user *, statbuf, int, flag) { struct kstat stat; int error = -EINVAL; --- linux-2.6.27.orig/fs/namespace.c +++ linux-2.6.27/fs/namespace.c @@ -1128,7 +1128,7 @@ * unixes. Our API is identical to OSF/1 to avoid making a mess of AMD */ -asmlinkage long sys_umount(char __user * name, int flags) +SYSCALL_DEFINE2(umount, char __user *, name, int, flags) { struct path path; int retval; @@ -1160,7 +1160,7 @@ /* * The 2.0 compatible umount. No flags. */ -asmlinkage long sys_oldumount(char __user * name) +SYSCALL_DEFINE1(oldumount, char __user *, name) { return sys_umount(name, 0); } @@ -1553,8 +1553,13 @@ if (!err) nd->path.mnt->mnt_flags = mnt_flags; up_write(&sb->s_umount); - if (!err) + if (!err) { security_sb_post_remount(nd->path.mnt, flags, data); + + spin_lock(&vfsmount_lock); + touch_mnt_namespace(nd->path.mnt->mnt_ns); + spin_unlock(&vfsmount_lock); + } return err; } @@ -2048,9 +2053,8 @@ return new_ns; } -asmlinkage long sys_mount(char __user * dev_name, char __user * dir_name, - char __user * type, unsigned long flags, - void __user * data) +SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, + char __user *, type, unsigned long, flags, void __user *, data) { int retval; unsigned long data_page; @@ -2175,8 +2179,8 @@ * though, so you may need to say mount --bind /nfs/my_root /nfs/my_root * first. */ -asmlinkage long sys_pivot_root(const char __user * new_root, - const char __user * put_old) +SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, + const char __user *, put_old) { struct vfsmount *tmp; struct path new, old, parent_path, root_parent, root; @@ -2352,3 +2356,33 @@ release_mounts(&umount_list); kfree(ns); } + +char *d_namespace_path(struct dentry *dentry, struct vfsmount *vfsmnt, + char *buf, int buflen) +{ + struct path root, tmp, ns_root = { }; + struct path path = { .mnt = vfsmnt, .dentry = dentry }; + char *res; + + read_lock(¤t->fs->lock); + root = current->fs->root; + path_get(¤t->fs->root); + read_unlock(¤t->fs->lock); + spin_lock(&vfsmount_lock); + if (root.mnt) + ns_root.mnt = mntget(root.mnt->mnt_ns->root); + if (ns_root.mnt) + ns_root.dentry = dget(ns_root.mnt->mnt_root); + spin_unlock(&vfsmount_lock); + tmp = ns_root; + res = __d_path(&path, &tmp, buf, buflen, + D_PATH_FAIL_DELETED | D_PATH_DISCONNECT); + path_put(&root); + path_put(&ns_root); + + /* Prevent empty path for lazily unmounted filesystems. */ + if (!IS_ERR(res) && *res == '\0') + *--res = '.'; + return res; +} +EXPORT_SYMBOL(d_namespace_path); --- linux-2.6.27.orig/fs/fcntl.c +++ linux-2.6.27/fs/fcntl.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -49,7 +50,7 @@ return res; } -asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags) +SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags) { int err = -EBADF; struct file * file, *tofree; @@ -112,7 +113,7 @@ return err; } -asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) +SYSCALL_DEFINE2(dup2, unsigned int, oldfd, unsigned int, newfd) { if (unlikely(newfd == oldfd)) { /* corner case */ struct files_struct *files = current->files; @@ -125,7 +126,7 @@ return sys_dup3(oldfd, newfd, 0); } -asmlinkage long sys_dup(unsigned int fildes) +SYSCALL_DEFINE1(dup, unsigned int, fildes) { int ret = -EBADF; struct file *file = fget(fildes); @@ -175,6 +176,11 @@ if (error) return error; + /* + * We still need a lock here for now to keep multiple FASYNC calls + * from racing with each other. + */ + lock_kernel(); if ((arg ^ filp->f_flags) & FASYNC) { if (filp->f_op && filp->f_op->fasync) { error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0); @@ -185,6 +191,7 @@ filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK); out: + unlock_kernel(); return error; } @@ -327,7 +334,7 @@ return err; } -asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) +SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) { struct file *filp; long err = -EBADF; @@ -350,7 +357,8 @@ } #if BITS_PER_LONG == 32 -asmlinkage long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) +SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, + unsigned long, arg) { struct file * filp; long err; --- linux-2.6.27.orig/fs/libfs.c +++ linux-2.6.27/fs/libfs.c @@ -360,7 +360,7 @@ index = pos >> PAGE_CACHE_SHIFT; from = pos & (PAGE_CACHE_SIZE - 1); - page = __grab_cache_page(mapping, index); + page = grab_cache_page_write_begin(mapping, index, flags); if (!page) return -ENOMEM; --- linux-2.6.27.orig/fs/select.c +++ linux-2.6.27/fs/select.c @@ -374,8 +374,8 @@ return ret; } -asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp, - fd_set __user *exp, struct timeval __user *tvp) +SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_set __user *, outp, + fd_set __user *, exp, struct timeval __user *, tvp) { s64 timeout = -1; struct timeval tv; @@ -427,9 +427,9 @@ } #ifdef HAVE_SET_RESTORE_SIGMASK -asmlinkage long sys_pselect7(int n, fd_set __user *inp, fd_set __user *outp, - fd_set __user *exp, struct timespec __user *tsp, - const sigset_t __user *sigmask, size_t sigsetsize) +static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp, + fd_set __user *exp, struct timespec __user *tsp, + const sigset_t __user *sigmask, size_t sigsetsize) { s64 timeout = MAX_SCHEDULE_TIMEOUT; sigset_t ksigmask, sigsaved; @@ -513,8 +513,9 @@ * which has a pointer to the sigset_t itself followed by a size_t containing * the sigset size. */ -asmlinkage long sys_pselect6(int n, fd_set __user *inp, fd_set __user *outp, - fd_set __user *exp, struct timespec __user *tsp, void __user *sig) +SYSCALL_DEFINE6(pselect6, int, n, fd_set __user *, inp, fd_set __user *, outp, + fd_set __user *, exp, struct timespec __user *, tsp, + void __user *, sig) { size_t sigsetsize = 0; sigset_t __user *up = NULL; @@ -527,7 +528,7 @@ return -EFAULT; } - return sys_pselect7(n, inp, outp, exp, tsp, up, sigsetsize); + return do_pselect(n, inp, outp, exp, tsp, up, sigsetsize); } #endif /* HAVE_SET_RESTORE_SIGMASK */ @@ -727,8 +728,8 @@ return ret; } -asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds, - long timeout_msecs) +SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds, + long, timeout_msecs) { s64 timeout_jiffies; int ret; @@ -761,9 +762,9 @@ } #ifdef HAVE_SET_RESTORE_SIGMASK -asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds, - struct timespec __user *tsp, const sigset_t __user *sigmask, - size_t sigsetsize) +SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds, + struct timespec __user *, tsp, const sigset_t __user *, sigmask, + size_t, sigsetsize) { sigset_t ksigmask, sigsaved; struct timespec ts; --- linux-2.6.27.orig/fs/readdir.c +++ linux-2.6.27/fs/readdir.c @@ -102,7 +102,8 @@ return -EFAULT; } -asmlinkage long old_readdir(unsigned int fd, struct old_linux_dirent __user * dirent, unsigned int count) +SYSCALL_DEFINE3(old_readdir, unsigned int, fd, + struct old_linux_dirent __user *, dirent, unsigned int, count) { int error; struct file * file; @@ -187,7 +188,8 @@ return -EFAULT; } -asmlinkage long sys_getdents(unsigned int fd, struct linux_dirent __user * dirent, unsigned int count) +SYSCALL_DEFINE3(getdents, unsigned int, fd, + struct linux_dirent __user *, dirent, unsigned int, count) { struct file * file; struct linux_dirent __user * lastdirent; @@ -271,7 +273,8 @@ return -EFAULT; } -asmlinkage long sys_getdents64(unsigned int fd, struct linux_dirent64 __user * dirent, unsigned int count) +SYSCALL_DEFINE3(getdents64, unsigned int, fd, + struct linux_dirent64 __user *, dirent, unsigned int, count) { struct file * file; struct linux_dirent64 __user * lastdirent; --- linux-2.6.27.orig/fs/locks.c +++ linux-2.6.27/fs/locks.c @@ -1564,7 +1564,7 @@ * %LOCK_MAND can be combined with %LOCK_READ or %LOCK_WRITE to allow other * processes read and write access respectively. */ -asmlinkage long sys_flock(unsigned int fd, unsigned int cmd) +SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd) { struct file *filp; struct file_lock *lock; --- linux-2.6.27.orig/fs/namei.c +++ linux-2.6.27/fs/namei.c @@ -227,7 +227,7 @@ return -EACCES; } -int inode_permission(struct inode *inode, int mask) +static int __inode_permission(struct inode *inode, int mask) { int retval; @@ -269,7 +269,12 @@ if (retval) return retval; - retval = devcgroup_inode_permission(inode, mask); + return devcgroup_inode_permission(inode, mask); +} + +int inode_permission(struct inode *inode, int mask) +{ + int retval = __inode_permission(inode, mask); if (retval) return retval; @@ -277,6 +282,15 @@ mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND)); } +int path_permission(struct path *path, int mask) +{ + int retval = __inode_permission(path->dentry->d_inode, mask); + if (retval) + return retval; + return security_path_permission(path, + mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND)); +} + /** * vfs_permission - check for access rights to a given path * @nd: lookup result that describes the path @@ -289,7 +303,7 @@ */ int vfs_permission(struct nameidata *nd, int mask) { - return inode_permission(nd->path.dentry->d_inode, mask); + return path_permission(&nd->path, mask); } /** @@ -306,7 +320,7 @@ */ int file_permission(struct file *file, int mask) { - return inode_permission(file->f_path.dentry->d_inode, mask); + return path_permission(&file->f_path, mask); } /* @@ -447,8 +461,9 @@ * short-cut DAC fails, then call permission() to do more * complete permission check. */ -static int exec_permission_lite(struct inode *inode) +static int exec_permission_lite(struct path *path) { + struct inode *inode = path->dentry->d_inode; umode_t mode = inode->i_mode; if (inode->i_op && inode->i_op->permission) @@ -473,7 +488,7 @@ return -EACCES; ok: - return security_inode_permission(inode, MAY_EXEC); + return security_path_permission(path, MAY_EXEC); } /* @@ -870,7 +885,7 @@ unsigned int c; nd->flags |= LOOKUP_CONTINUE; - err = exec_permission_lite(inode); + err = exec_permission_lite(&nd->path); if (err == -EAGAIN) err = vfs_permission(nd, MAY_EXEC); if (err) @@ -1065,24 +1080,21 @@ path_get(&fs->pwd); read_unlock(&fs->lock); } else { - struct dentry *dentry; - file = fget_light(dfd, &fput_needed); retval = -EBADF; if (!file) goto out_fail; - dentry = file->f_path.dentry; + nd->path = file->f_path; retval = -ENOTDIR; - if (!S_ISDIR(dentry->d_inode->i_mode)) + if (!S_ISDIR(nd->path.dentry->d_inode->i_mode)) goto fput_fail; retval = file_permission(file, MAY_EXEC); if (retval) goto fput_fail; - nd->path = file->f_path; path_get(&file->f_path); fput_light(file, fput_needed); @@ -1193,7 +1205,7 @@ nd, open_flags, create_mode); } -static struct dentry *__lookup_hash(struct qstr *name, +struct dentry *__lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd) { struct dentry *dentry; @@ -1245,7 +1257,7 @@ { int err; - err = inode_permission(nd->path.dentry->d_inode, MAY_EXEC); + err = path_permission(&nd->path, MAY_EXEC); if (err) return ERR_PTR(err); return __lookup_hash(&nd->last, nd->path.dentry, nd); @@ -1512,7 +1524,7 @@ return -EACCES; /* shouldn't it be ENOSYS? */ mode &= S_IALLUGO; mode |= S_IFREG; - error = security_inode_create(dir, dentry, mode); + error = security_inode_create(dir, dentry, nd ? nd->path.mnt : NULL, mode); if (error) return error; DQUOT_INIT(dir); @@ -1588,7 +1600,7 @@ if (!error) { DQUOT_INIT(inode); - error = do_truncate(dentry, 0, + error = do_truncate(dentry, nd->path.mnt, 0, ATTR_MTIME|ATTR_CTIME|ATTR_OPEN, NULL); } @@ -1945,7 +1957,8 @@ } EXPORT_SYMBOL_GPL(lookup_create); -int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +int vfs_mknod(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt, + int mode, dev_t dev) { int error = may_create(dir, dentry); @@ -1962,7 +1975,7 @@ if (error) return error; - error = security_inode_mknod(dir, dentry, mode, dev); + error = security_inode_mknod(dir, dentry, mnt, mode, dev); if (error) return error; @@ -1990,8 +2003,8 @@ } } -asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, - unsigned dev) +SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, int, mode, + unsigned, dev) { int error; char *tmp; @@ -2023,11 +2036,12 @@ error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd); break; case S_IFCHR: case S_IFBLK: - error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode, - new_decode_dev(dev)); + error = vfs_mknod(nd.path.dentry->d_inode, dentry, + nd.path.mnt, mode, new_decode_dev(dev)); break; case S_IFIFO: case S_IFSOCK: - error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0); + error = vfs_mknod(nd.path.dentry->d_inode, dentry, + nd.path.mnt, mode, 0); break; } mnt_drop_write(nd.path.mnt); @@ -2041,12 +2055,13 @@ return error; } -asmlinkage long sys_mknod(const char __user *filename, int mode, unsigned dev) +SYSCALL_DEFINE3(mknod, const char __user *, filename, int, mode, unsigned, dev) { return sys_mknodat(AT_FDCWD, filename, mode, dev); } -int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +int vfs_mkdir(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt, + int mode) { int error = may_create(dir, dentry); @@ -2057,7 +2072,7 @@ return -EPERM; mode &= (S_IRWXUGO|S_ISVTX); - error = security_inode_mkdir(dir, dentry, mode); + error = security_inode_mkdir(dir, dentry, mnt, mode); if (error) return error; @@ -2068,7 +2083,7 @@ return error; } -asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode) +SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, int, mode) { int error = 0; char * tmp; @@ -2089,7 +2104,7 @@ error = mnt_want_write(nd.path.mnt); if (error) goto out_dput; - error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); + error = vfs_mkdir(nd.path.dentry->d_inode, dentry, nd.path.mnt, mode); mnt_drop_write(nd.path.mnt); out_dput: dput(dentry); @@ -2101,7 +2116,7 @@ return error; } -asmlinkage long sys_mkdir(const char __user *pathname, int mode) +SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode) { return sys_mkdirat(AT_FDCWD, pathname, mode); } @@ -2133,7 +2148,7 @@ spin_unlock(&dcache_lock); } -int vfs_rmdir(struct inode *dir, struct dentry *dentry) +int vfs_rmdir(struct inode *dir, struct dentry *dentry,struct vfsmount *mnt) { int error = may_delete(dir, dentry, 1); @@ -2143,6 +2158,10 @@ if (!dir->i_op || !dir->i_op->rmdir) return -EPERM; + error = security_inode_rmdir(dir, dentry, mnt); + if (error) + return error; + DQUOT_INIT(dir); mutex_lock(&dentry->d_inode->i_mutex); @@ -2150,12 +2169,9 @@ if (d_mountpoint(dentry)) error = -EBUSY; else { - error = security_inode_rmdir(dir, dentry); - if (!error) { - error = dir->i_op->rmdir(dir, dentry); - if (!error) - dentry->d_inode->i_flags |= S_DEAD; - } + error = dir->i_op->rmdir(dir, dentry); + if (!error) + dentry->d_inode->i_flags |= S_DEAD; } mutex_unlock(&dentry->d_inode->i_mutex); if (!error) { @@ -2196,7 +2212,7 @@ error = mnt_want_write(nd.path.mnt); if (error) goto exit3; - error = vfs_rmdir(nd.path.dentry->d_inode, dentry); + error = vfs_rmdir(nd.path.dentry->d_inode, dentry, nd.path.mnt); mnt_drop_write(nd.path.mnt); exit3: dput(dentry); @@ -2208,12 +2224,12 @@ return error; } -asmlinkage long sys_rmdir(const char __user *pathname) +SYSCALL_DEFINE1(rmdir, const char __user *, pathname) { return do_rmdir(AT_FDCWD, pathname); } -int vfs_unlink(struct inode *dir, struct dentry *dentry) +int vfs_unlink(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt) { int error = may_delete(dir, dentry, 0); @@ -2229,7 +2245,7 @@ if (d_mountpoint(dentry)) error = -EBUSY; else { - error = security_inode_unlink(dir, dentry); + error = security_inode_unlink(dir, dentry, mnt); if (!error) error = dir->i_op->unlink(dir, dentry); } @@ -2278,7 +2294,7 @@ error = mnt_want_write(nd.path.mnt); if (error) goto exit2; - error = vfs_unlink(nd.path.dentry->d_inode, dentry); + error = vfs_unlink(nd.path.dentry->d_inode, dentry, nd.path.mnt); mnt_drop_write(nd.path.mnt); exit2: dput(dentry); @@ -2297,7 +2313,7 @@ goto exit2; } -asmlinkage long sys_unlinkat(int dfd, const char __user *pathname, int flag) +SYSCALL_DEFINE3(unlinkat, int, dfd, const char __user *, pathname, int, flag) { if ((flag & ~AT_REMOVEDIR) != 0) return -EINVAL; @@ -2308,12 +2324,13 @@ return do_unlinkat(dfd, pathname); } -asmlinkage long sys_unlink(const char __user *pathname) +SYSCALL_DEFINE1(unlink, const char __user *, pathname) { return do_unlinkat(AT_FDCWD, pathname); } -int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) +int vfs_symlink(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt, + const char *oldname) { int error = may_create(dir, dentry); @@ -2323,7 +2340,7 @@ if (!dir->i_op || !dir->i_op->symlink) return -EPERM; - error = security_inode_symlink(dir, dentry, oldname); + error = security_inode_symlink(dir, dentry, mnt, oldname); if (error) return error; @@ -2334,8 +2351,8 @@ return error; } -asmlinkage long sys_symlinkat(const char __user *oldname, - int newdfd, const char __user *newname) +SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, + int, newdfd, const char __user *, newname) { int error; char *from; @@ -2359,7 +2376,7 @@ error = mnt_want_write(nd.path.mnt); if (error) goto out_dput; - error = vfs_symlink(nd.path.dentry->d_inode, dentry, from); + error = vfs_symlink(nd.path.dentry->d_inode, dentry, nd.path.mnt, from); mnt_drop_write(nd.path.mnt); out_dput: dput(dentry); @@ -2372,12 +2389,12 @@ return error; } -asmlinkage long sys_symlink(const char __user *oldname, const char __user *newname) +SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newname) { return sys_symlinkat(oldname, AT_FDCWD, newname); } -int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) +int vfs_link(struct dentry *old_dentry, struct vfsmount *old_mnt, struct inode *dir, struct dentry *new_dentry, struct vfsmount *new_mnt) { struct inode *inode = old_dentry->d_inode; int error; @@ -2402,7 +2419,8 @@ if (S_ISDIR(inode->i_mode)) return -EPERM; - error = security_inode_link(old_dentry, dir, new_dentry); + error = security_inode_link(old_dentry, old_mnt, dir, new_dentry, + new_mnt); if (error) return error; @@ -2424,9 +2442,8 @@ * with linux 2.0, and to avoid hard-linking to directories * and other special files. --ADM */ -asmlinkage long sys_linkat(int olddfd, const char __user *oldname, - int newdfd, const char __user *newname, - int flags) +SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, + int, newdfd, const char __user *, newname, int, flags) { struct dentry *new_dentry; struct nameidata nd; @@ -2456,7 +2473,9 @@ error = mnt_want_write(nd.path.mnt); if (error) goto out_dput; - error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry); + error = vfs_link(old_path.dentry, old_path.mnt, + nd.path.dentry->d_inode, + new_dentry, nd.path.mnt); mnt_drop_write(nd.path.mnt); out_dput: dput(new_dentry); @@ -2471,7 +2490,7 @@ return error; } -asmlinkage long sys_link(const char __user *oldname, const char __user *newname) +SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname) { return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname, 0); } @@ -2509,7 +2528,8 @@ * locking]. */ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) + struct vfsmount *old_mnt, struct inode *new_dir, + struct dentry *new_dentry, struct vfsmount *new_mnt) { int error = 0; struct inode *target; @@ -2524,7 +2544,8 @@ return error; } - error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry); + error = security_inode_rename(old_dir, old_dentry, old_mnt, + new_dir, new_dentry, new_mnt); if (error) return error; @@ -2552,12 +2573,14 @@ } static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) + struct vfsmount *old_mnt, struct inode *new_dir, + struct dentry *new_dentry, struct vfsmount *new_mnt) { struct inode *target; int error; - error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry); + error = security_inode_rename(old_dir, old_dentry, old_mnt, + new_dir, new_dentry, new_mnt); if (error) return error; @@ -2580,7 +2603,8 @@ } int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) + struct vfsmount *old_mnt, struct inode *new_dir, + struct dentry *new_dentry, struct vfsmount *new_mnt) { int error; int is_dir = S_ISDIR(old_dentry->d_inode->i_mode); @@ -2609,9 +2633,11 @@ old_name = fsnotify_oldname_init(old_dentry->d_name.name); if (is_dir) - error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry); + error = vfs_rename_dir(old_dir, old_dentry, old_mnt, + new_dir, new_dentry, new_mnt); else - error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry); + error = vfs_rename_other(old_dir, old_dentry, old_mnt, + new_dir, new_dentry, new_mnt); if (!error) { const char *new_name = old_dentry->d_name.name; fsnotify_move(old_dir, new_dir, old_name, new_name, is_dir, @@ -2622,8 +2648,8 @@ return error; } -asmlinkage long sys_renameat(int olddfd, const char __user *oldname, - int newdfd, const char __user *newname) +SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname, + int, newdfd, const char __user *, newname) { struct dentry *old_dir, *new_dir; struct dentry *old_dentry, *new_dentry; @@ -2688,8 +2714,8 @@ error = mnt_want_write(oldnd.path.mnt); if (error) goto exit5; - error = vfs_rename(old_dir->d_inode, old_dentry, - new_dir->d_inode, new_dentry); + error = vfs_rename(old_dir->d_inode, old_dentry, oldnd.path.mnt, + new_dir->d_inode, new_dentry, newnd.path.mnt); mnt_drop_write(oldnd.path.mnt); exit5: dput(new_dentry); @@ -2707,7 +2733,7 @@ return error; } -asmlinkage long sys_rename(const char __user *oldname, const char __user *newname) +SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newname) { return sys_renameat(AT_FDCWD, oldname, AT_FDCWD, newname); } @@ -2797,18 +2823,23 @@ } } -int __page_symlink(struct inode *inode, const char *symname, int len, - gfp_t gfp_mask) +/* + * The nofs argument instructs pagecache_write_begin to pass AOP_FLAG_NOFS + */ +int __page_symlink(struct inode *inode, const char *symname, int len, int nofs) { struct address_space *mapping = inode->i_mapping; struct page *page; void *fsdata; int err; char *kaddr; + unsigned int flags = AOP_FLAG_UNINTERRUPTIBLE; + if (nofs) + flags |= AOP_FLAG_NOFS; retry: err = pagecache_write_begin(NULL, mapping, 0, len-1, - AOP_FLAG_UNINTERRUPTIBLE, &page, &fsdata); + flags, &page, &fsdata); if (err) goto fail; @@ -2832,7 +2863,7 @@ int page_symlink(struct inode *inode, const char *symname, int len) { return __page_symlink(inode, symname, len, - mapping_gfp_mask(inode->i_mapping)); + !(mapping_gfp_mask(inode->i_mapping) & __GFP_FS)); } const struct inode_operations page_symlink_inode_operations = { @@ -2857,6 +2888,7 @@ EXPORT_SYMBOL(path_lookup); EXPORT_SYMBOL(vfs_path_lookup); EXPORT_SYMBOL(inode_permission); +EXPORT_SYMBOL(path_permission); EXPORT_SYMBOL(vfs_permission); EXPORT_SYMBOL(file_permission); EXPORT_SYMBOL(unlock_rename); @@ -2873,3 +2905,5 @@ EXPORT_SYMBOL(vfs_unlink); EXPORT_SYMBOL(dentry_unhash); EXPORT_SYMBOL(generic_readlink); +EXPORT_SYMBOL(deny_write_access); +EXPORT_SYMBOL(__lookup_hash); --- linux-2.6.27.orig/fs/eventpoll.c +++ linux-2.6.27/fs/eventpoll.c @@ -102,6 +102,8 @@ #define EP_UNACTIVE_PTR ((void *) -1L) +#define EP_ITEM_COST (sizeof(struct epitem) + sizeof(struct eppoll_entry)) + struct epoll_filefd { struct file *file; int fd; @@ -200,6 +202,9 @@ * holding ->lock. */ struct epitem *ovflist; + + /* The user that created the eventpoll descriptor */ + struct user_struct *user; }; /* Wait structure used by the poll hooks */ @@ -227,9 +232,15 @@ }; /* + * Configuration options available inside /proc/sys/fs/epoll/ + */ +/* Maximum number of epoll watched descriptors, per user */ +static int max_user_watches __read_mostly; + +/* * This mutex is used to serialize ep_free() and eventpoll_release_file(). */ -static struct mutex epmutex; +static DEFINE_MUTEX(epmutex); /* Safe wake up implementation */ static struct poll_safewake psw; @@ -240,6 +251,25 @@ /* Slab cache used to allocate "struct eppoll_entry" */ static struct kmem_cache *pwq_cache __read_mostly; +#ifdef CONFIG_SYSCTL + +#include + +static int zero; + +ctl_table epoll_table[] = { + { + .procname = "max_user_watches", + .data = &max_user_watches, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .extra1 = &zero, + }, + { .ctl_name = 0 } +}; +#endif /* CONFIG_SYSCTL */ + /* Setup the structure that is used as key for the RB tree */ static inline void ep_set_ffd(struct epoll_filefd *ffd, @@ -402,6 +432,8 @@ /* At this point it is safe to free the eventpoll item */ kmem_cache_free(epi_cache, epi); + atomic_dec(&ep->user->epoll_watches); + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %p)\n", current, ep, file)); @@ -449,6 +481,7 @@ mutex_unlock(&epmutex); mutex_destroy(&ep->mtx); + free_uid(ep->user); kfree(ep); } @@ -532,10 +565,15 @@ static int ep_alloc(struct eventpoll **pep) { - struct eventpoll *ep = kzalloc(sizeof(*ep), GFP_KERNEL); + int error; + struct user_struct *user; + struct eventpoll *ep; - if (!ep) - return -ENOMEM; + user = get_current_user(); + error = -ENOMEM; + ep = kzalloc(sizeof(*ep), GFP_KERNEL); + if (unlikely(!ep)) + goto free_uid; spin_lock_init(&ep->lock); mutex_init(&ep->mtx); @@ -544,12 +582,17 @@ INIT_LIST_HEAD(&ep->rdllist); ep->rbr = RB_ROOT; ep->ovflist = EP_UNACTIVE_PTR; + ep->user = user; *pep = ep; DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_alloc() ep=%p\n", current, ep)); return 0; + +free_uid: + free_uid(user); + return error; } /* @@ -703,9 +746,11 @@ struct epitem *epi; struct ep_pqueue epq; - error = -ENOMEM; + if (unlikely(atomic_read(&ep->user->epoll_watches) >= + max_user_watches)) + return -ENOSPC; if (!(epi = kmem_cache_alloc(epi_cache, GFP_KERNEL))) - goto error_return; + return -ENOMEM; /* Item initialization follow here ... */ INIT_LIST_HEAD(&epi->rdllink); @@ -735,6 +780,7 @@ * install process. Namely an allocation for a wait queue failed due * high memory pressure. */ + error = -ENOMEM; if (epi->nwait < 0) goto error_unregister; @@ -765,6 +811,8 @@ spin_unlock_irqrestore(&ep->lock, flags); + atomic_inc(&ep->user->epoll_watches); + /* We have to call this outside the lock */ if (pwake) ep_poll_safewake(&psw, &ep->poll_wait); @@ -789,7 +837,7 @@ spin_unlock_irqrestore(&ep->lock, flags); kmem_cache_free(epi_cache, epi); -error_return: + return error; } @@ -1043,7 +1091,7 @@ /* * Open an eventpoll file descriptor. */ -asmlinkage long sys_epoll_create1(int flags) +SYSCALL_DEFINE1(epoll_create1, int, flags) { int error, fd = -1; struct eventpoll *ep; @@ -1082,7 +1130,7 @@ return fd; } -asmlinkage long sys_epoll_create(int size) +SYSCALL_DEFINE1(epoll_create, int, size) { if (size < 0) return -EINVAL; @@ -1095,8 +1143,8 @@ * the eventpoll file that enables the insertion/removal/change of * file descriptors inside the interest set. */ -asmlinkage long sys_epoll_ctl(int epfd, int op, int fd, - struct epoll_event __user *event) +SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, + struct epoll_event __user *, event) { int error; struct file *file, *tfile; @@ -1193,8 +1241,8 @@ * Implement the event wait interface for the eventpoll file. It is the kernel * part of the user space epoll_wait(2). */ -asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events, - int maxevents, int timeout) +SYSCALL_DEFINE4(epoll_wait, int, epfd, struct epoll_event __user *, events, + int, maxevents, int, timeout) { int error; struct file *file; @@ -1251,9 +1299,9 @@ * Implement the event wait interface for the eventpoll file. It is the kernel * part of the user space epoll_pwait(2). */ -asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events, - int maxevents, int timeout, const sigset_t __user *sigmask, - size_t sigsetsize) +SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events, + int, maxevents, int, timeout, const sigset_t __user *, sigmask, + size_t, sigsetsize) { int error; sigset_t ksigmask, sigsaved; @@ -1295,7 +1343,14 @@ static int __init eventpoll_init(void) { - mutex_init(&epmutex); + struct sysinfo si; + + si_meminfo(&si); + /* + * Allows top 4% of lomem to be allocated for epoll watches (per user). + */ + max_user_watches = (((si.totalram - si.totalhigh) / 25) << PAGE_SHIFT) / + EP_ITEM_COST; /* Initialize the structure used to perform safe poll wait head wake ups */ ep_poll_safewake_init(&psw); --- linux-2.6.27.orig/fs/file_table.c +++ linux-2.6.27/fs/file_table.c @@ -347,6 +347,7 @@ file_free(file); } } +EXPORT_SYMBOL(put_filp); void file_move(struct file *file, struct list_head *list) { --- linux-2.6.27.orig/fs/read_write.c +++ linux-2.6.27/fs/read_write.c @@ -112,7 +112,7 @@ } EXPORT_SYMBOL(vfs_llseek); -asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin) +SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, origin) { off_t retval; struct file * file; @@ -136,9 +136,9 @@ } #ifdef __ARCH_WANT_SYS_LLSEEK -asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high, - unsigned long offset_low, loff_t __user * result, - unsigned int origin) +SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high, + unsigned long, offset_low, loff_t __user *, result, + unsigned int, origin) { int retval; struct file * file; @@ -334,7 +334,7 @@ file->f_pos = pos; } -asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count) +SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) { struct file *file; ssize_t ret = -EBADF; @@ -351,7 +351,8 @@ return ret; } -asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count) +SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, + size_t, count) { struct file *file; ssize_t ret = -EBADF; @@ -368,8 +369,8 @@ return ret; } -asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf, - size_t count, loff_t pos) +SYSCALL_DEFINE(pread64)(unsigned int fd, char __user *buf, + size_t count, loff_t pos) { struct file *file; ssize_t ret = -EBADF; @@ -388,9 +389,17 @@ return ret; } +#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS +asmlinkage long SyS_pread64(long fd, long buf, long count, loff_t pos) +{ + return SYSC_pread64((unsigned int) fd, (char __user *) buf, + (size_t) count, pos); +} +SYSCALL_ALIAS(sys_pread64, SyS_pread64); +#endif -asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf, - size_t count, loff_t pos) +SYSCALL_DEFINE(pwrite64)(unsigned int fd, const char __user *buf, + size_t count, loff_t pos) { struct file *file; ssize_t ret = -EBADF; @@ -409,6 +418,14 @@ return ret; } +#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS +asmlinkage long SyS_pwrite64(long fd, long buf, long count, loff_t pos) +{ + return SYSC_pwrite64((unsigned int) fd, (const char __user *) buf, + (size_t) count, pos); +} +SYSCALL_ALIAS(sys_pwrite64, SyS_pwrite64); +#endif /* * Reduce an iovec's length in-place. Return the resulting number of segments @@ -637,8 +654,8 @@ EXPORT_SYMBOL(vfs_writev); -asmlinkage ssize_t -sys_readv(unsigned long fd, const struct iovec __user *vec, unsigned long vlen) +SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec, + unsigned long, vlen) { struct file *file; ssize_t ret = -EBADF; @@ -658,8 +675,8 @@ return ret; } -asmlinkage ssize_t -sys_writev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen) +SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec, + unsigned long, vlen) { struct file *file; ssize_t ret = -EBADF; @@ -777,7 +794,7 @@ return retval; } -asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t __user *offset, size_t count) +SYSCALL_DEFINE4(sendfile, int, out_fd, int, in_fd, off_t __user *, offset, size_t, count) { loff_t pos; off_t off; @@ -796,7 +813,7 @@ return do_sendfile(out_fd, in_fd, NULL, count, 0); } -asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t __user *offset, size_t count) +SYSCALL_DEFINE4(sendfile64, int, out_fd, int, in_fd, loff_t __user *, offset, size_t, count) { loff_t pos; ssize_t ret; --- linux-2.6.27.orig/fs/signalfd.c +++ linux-2.6.27/fs/signalfd.c @@ -205,8 +205,8 @@ .read = signalfd_read, }; -asmlinkage long sys_signalfd4(int ufd, sigset_t __user *user_mask, - size_t sizemask, int flags) +SYSCALL_DEFINE4(signalfd4, int, ufd, sigset_t __user *, user_mask, + size_t, sizemask, int, flags) { sigset_t sigmask; struct signalfd_ctx *ctx; @@ -259,8 +259,8 @@ return ufd; } -asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, - size_t sizemask) +SYSCALL_DEFINE3(signalfd, int, ufd, sigset_t __user *, user_mask, + size_t, sizemask) { return sys_signalfd4(ufd, user_mask, sizemask, 0); } --- linux-2.6.27.orig/fs/inotify.c +++ linux-2.6.27/fs/inotify.c @@ -106,6 +106,20 @@ } EXPORT_SYMBOL_GPL(get_inotify_watch); +int pin_inotify_watch(struct inotify_watch *watch) +{ + struct super_block *sb = watch->inode->i_sb; + spin_lock(&sb_lock); + if (sb->s_count >= S_BIAS) { + atomic_inc(&sb->s_active); + spin_unlock(&sb_lock); + atomic_inc(&watch->count); + return 1; + } + spin_unlock(&sb_lock); + return 0; +} + /** * put_inotify_watch - decrements the ref count on a given watch. cleans up * watch references if the count reaches zero. inotify_watch is freed by @@ -124,6 +138,13 @@ } EXPORT_SYMBOL_GPL(put_inotify_watch); +void unpin_inotify_watch(struct inotify_watch *watch) +{ + struct super_block *sb = watch->inode->i_sb; + put_inotify_watch(watch); + deactivate_super(sb); +} + /* * inotify_handle_get_wd - returns the next WD for use by the given handle * @@ -479,6 +500,112 @@ } EXPORT_SYMBOL_GPL(inotify_init_watch); +/* + * Watch removals suck violently. To kick the watch out we need (in this + * order) inode->inotify_mutex and ih->mutex. That's fine if we have + * a hold on inode; however, for all other cases we need to make damn sure + * we don't race with umount. We can *NOT* just grab a reference to a + * watch - inotify_unmount_inodes() will happily sail past it and we'll end + * with reference to inode potentially outliving its superblock. Ideally + * we just want to grab an active reference to superblock if we can; that + * will make sure we won't go into inotify_umount_inodes() until we are + * done. Cleanup is just deactivate_super(). However, that leaves a messy + * case - what if we *are* racing with umount() and active references to + * superblock can't be acquired anymore? We can bump ->s_count, grab + * ->s_umount, which will almost certainly wait until the superblock is shut + * down and the watch in question is pining for fjords. That's fine, but + * there is a problem - we might have hit the window between ->s_active + * getting to 0 / ->s_count - below S_BIAS (i.e. the moment when superblock + * is past the point of no return and is heading for shutdown) and the + * moment when deactivate_super() acquires ->s_umount. We could just do + * drop_super() yield() and retry, but that's rather antisocial and this + * stuff is luser-triggerable. OTOH, having grabbed ->s_umount and having + * found that we'd got there first (i.e. that ->s_root is non-NULL) we know + * that we won't race with inotify_umount_inodes(). So we could grab a + * reference to watch and do the rest as above, just with drop_super() instead + * of deactivate_super(), right? Wrong. We had to drop ih->mutex before we + * could grab ->s_umount. So the watch could've been gone already. + * + * That still can be dealt with - we need to save watch->wd, do idr_find() + * and compare its result with our pointer. If they match, we either have + * the damn thing still alive or we'd lost not one but two races at once, + * the watch had been killed and a new one got created with the same ->wd + * at the same address. That couldn't have happened in inotify_destroy(), + * but inotify_rm_wd() could run into that. Still, "new one got created" + * is not a problem - we have every right to kill it or leave it alone, + * whatever's more convenient. + * + * So we can use idr_find(...) == watch && watch->inode->i_sb == sb as + * "grab it and kill it" check. If it's been our original watch, we are + * fine, if it's a newcomer - nevermind, just pretend that we'd won the + * race and kill the fscker anyway; we are safe since we know that its + * superblock won't be going away. + * + * And yes, this is far beyond mere "not very pretty"; so's the entire + * concept of inotify to start with. + */ + +/** + * pin_to_kill - pin the watch down for removal + * @ih: inotify handle + * @watch: watch to kill + * + * Called with ih->mutex held, drops it. Possible return values: + * 0 - nothing to do, it has died + * 1 - remove it, drop the reference and deactivate_super() + * 2 - remove it, drop the reference and drop_super(); we tried hard to avoid + * that variant, since it involved a lot of PITA, but that's the best that + * could've been done. + */ +static int pin_to_kill(struct inotify_handle *ih, struct inotify_watch *watch) +{ + struct super_block *sb = watch->inode->i_sb; + s32 wd = watch->wd; + + spin_lock(&sb_lock); + if (sb->s_count >= S_BIAS) { + atomic_inc(&sb->s_active); + spin_unlock(&sb_lock); + get_inotify_watch(watch); + mutex_unlock(&ih->mutex); + return 1; /* the best outcome */ + } + sb->s_count++; + spin_unlock(&sb_lock); + mutex_unlock(&ih->mutex); /* can't grab ->s_umount under it */ + down_read(&sb->s_umount); + if (likely(!sb->s_root)) { + /* fs is already shut down; the watch is dead */ + drop_super(sb); + return 0; + } + /* raced with the final deactivate_super() */ + mutex_lock(&ih->mutex); + if (idr_find(&ih->idr, wd) != watch || watch->inode->i_sb != sb) { + /* the watch is dead */ + mutex_unlock(&ih->mutex); + drop_super(sb); + return 0; + } + /* still alive or freed and reused with the same sb and wd; kill */ + get_inotify_watch(watch); + mutex_unlock(&ih->mutex); + return 2; +} + +static void unpin_and_kill(struct inotify_watch *watch, int how) +{ + struct super_block *sb = watch->inode->i_sb; + put_inotify_watch(watch); + switch (how) { + case 1: + deactivate_super(sb); + break; + case 2: + drop_super(sb); + } +} + /** * inotify_destroy - clean up and destroy an inotify instance * @ih: inotify handle @@ -490,11 +617,15 @@ * pretty. We cannot do a simple iteration over the list, because we * do not know the inode until we iterate to the watch. But we need to * hold inode->inotify_mutex before ih->mutex. The following works. + * + * AV: it had to become even uglier to start working ;-/ */ while (1) { struct inotify_watch *watch; struct list_head *watches; + struct super_block *sb; struct inode *inode; + int how; mutex_lock(&ih->mutex); watches = &ih->watches; @@ -503,8 +634,10 @@ break; } watch = list_first_entry(watches, struct inotify_watch, h_list); - get_inotify_watch(watch); - mutex_unlock(&ih->mutex); + sb = watch->inode->i_sb; + how = pin_to_kill(ih, watch); + if (!how) + continue; inode = watch->inode; mutex_lock(&inode->inotify_mutex); @@ -518,7 +651,7 @@ mutex_unlock(&ih->mutex); mutex_unlock(&inode->inotify_mutex); - put_inotify_watch(watch); + unpin_and_kill(watch, how); } /* free this handle: the put matching the get in inotify_init() */ @@ -719,7 +852,9 @@ int inotify_rm_wd(struct inotify_handle *ih, u32 wd) { struct inotify_watch *watch; + struct super_block *sb; struct inode *inode; + int how; mutex_lock(&ih->mutex); watch = idr_find(&ih->idr, wd); @@ -727,9 +862,12 @@ mutex_unlock(&ih->mutex); return -EINVAL; } - get_inotify_watch(watch); + sb = watch->inode->i_sb; + how = pin_to_kill(ih, watch); + if (!how) + return 0; + inode = watch->inode; - mutex_unlock(&ih->mutex); mutex_lock(&inode->inotify_mutex); mutex_lock(&ih->mutex); @@ -740,7 +878,7 @@ mutex_unlock(&ih->mutex); mutex_unlock(&inode->inotify_mutex); - put_inotify_watch(watch); + unpin_and_kill(watch, how); return 0; } --- linux-2.6.27.orig/fs/binfmt_elf.c +++ linux-2.6.27/fs/binfmt_elf.c @@ -1188,9 +1188,11 @@ * check for an ELF header. If we find one, dump the first page to * aid in determining what was mapped here. */ - if (FILTER(ELF_HEADERS) && vma->vm_file != NULL && vma->vm_pgoff == 0) { + if (FILTER(ELF_HEADERS) && + vma->vm_pgoff == 0 && (vma->vm_flags & VM_READ)) { u32 __user *header = (u32 __user *) vma->vm_start; u32 word; + mm_segment_t fs = get_fs(); /* * Doing it this way gets the constant folded by GCC. */ @@ -1203,7 +1205,15 @@ magic.elfmag[EI_MAG1] = ELFMAG1; magic.elfmag[EI_MAG2] = ELFMAG2; magic.elfmag[EI_MAG3] = ELFMAG3; - if (get_user(word, header) == 0 && word == magic.cmp) + /* + * Switch to the user "segment" for get_user(), + * then put back what elf_core_dump() had in place. + */ + set_fs(USER_DS); + if (unlikely(get_user(word, header))) + word = 0; + set_fs(fs); + if (word == magic.cmp) return PAGE_SIZE; } --- linux-2.6.27.orig/fs/xattr.c +++ linux-2.6.27/fs/xattr.c @@ -67,8 +67,8 @@ } int -vfs_setxattr(struct dentry *dentry, const char *name, const void *value, - size_t size, int flags) +vfs_setxattr(struct dentry *dentry, struct vfsmount *mnt, const char *name, + const void *value, size_t size, int flags, struct file *file) { struct inode *inode = dentry->d_inode; int error; @@ -78,7 +78,7 @@ return error; mutex_lock(&inode->i_mutex); - error = security_inode_setxattr(dentry, name, value, size, flags); + error = security_inode_setxattr(dentry, mnt, name, value, size, flags, file); if (error) goto out; error = -EOPNOTSUPP; @@ -86,7 +86,7 @@ error = inode->i_op->setxattr(dentry, name, value, size, flags); if (!error) { fsnotify_xattr(dentry); - security_inode_post_setxattr(dentry, name, value, + security_inode_post_setxattr(dentry, mnt, name, value, size, flags); } } else if (!strncmp(name, XATTR_SECURITY_PREFIX, @@ -131,7 +131,8 @@ EXPORT_SYMBOL_GPL(xattr_getsecurity); ssize_t -vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) +vfs_getxattr(struct dentry *dentry, struct vfsmount *mnt, const char *name, + void *value, size_t size, struct file *file) { struct inode *inode = dentry->d_inode; int error; @@ -140,7 +141,7 @@ if (error) return error; - error = security_inode_getxattr(dentry, name); + error = security_inode_getxattr(dentry, mnt, name, file); if (error) return error; @@ -167,18 +168,20 @@ EXPORT_SYMBOL_GPL(vfs_getxattr); ssize_t -vfs_listxattr(struct dentry *d, char *list, size_t size) +vfs_listxattr(struct dentry *dentry, struct vfsmount *mnt, char *list, + size_t size, struct file *file) { + struct inode *inode = dentry->d_inode; ssize_t error; - error = security_inode_listxattr(d); + error = security_inode_listxattr(dentry, mnt, file); if (error) return error; error = -EOPNOTSUPP; - if (d->d_inode->i_op && d->d_inode->i_op->listxattr) { - error = d->d_inode->i_op->listxattr(d, list, size); - } else { - error = security_inode_listsecurity(d->d_inode, list, size); + if (inode->i_op && inode->i_op->listxattr) + error = inode->i_op->listxattr(dentry, list, size); + else { + error = security_inode_listsecurity(inode, list, size); if (size && error > size) error = -ERANGE; } @@ -187,7 +190,8 @@ EXPORT_SYMBOL_GPL(vfs_listxattr); int -vfs_removexattr(struct dentry *dentry, const char *name) +vfs_removexattr(struct dentry *dentry, struct vfsmount *mnt, const char *name, + struct file *file) { struct inode *inode = dentry->d_inode; int error; @@ -199,7 +203,7 @@ if (error) return error; - error = security_inode_removexattr(dentry, name); + error = security_inode_removexattr(dentry, mnt, name, file); if (error) return error; @@ -218,8 +222,8 @@ * Extended attribute SET operations */ static long -setxattr(struct dentry *d, const char __user *name, const void __user *value, - size_t size, int flags) +setxattr(struct dentry *dentry, struct vfsmount *mnt, const char __user *name, + const void __user *value, size_t size, int flags, struct file *file) { int error; void *kvalue = NULL; @@ -246,14 +250,14 @@ } } - error = vfs_setxattr(d, kname, kvalue, size, flags); + error = vfs_setxattr(dentry, mnt, kname, kvalue, size, flags, file); kfree(kvalue); return error; } -asmlinkage long -sys_setxattr(const char __user *pathname, const char __user *name, - const void __user *value, size_t size, int flags) +SYSCALL_DEFINE5(setxattr, const char __user *, pathname, + const char __user *, name, const void __user *, value, + size_t, size, int, flags) { struct path path; int error; @@ -263,16 +267,16 @@ return error; error = mnt_want_write(path.mnt); if (!error) { - error = setxattr(path.dentry, name, value, size, flags); + error = setxattr(path.dentry, path.mnt, name, value, size, flags, NULL); mnt_drop_write(path.mnt); } path_put(&path); return error; } -asmlinkage long -sys_lsetxattr(const char __user *pathname, const char __user *name, - const void __user *value, size_t size, int flags) +SYSCALL_DEFINE5(lsetxattr, const char __user *, pathname, + const char __user *, name, const void __user *, value, + size_t, size, int, flags) { struct path path; int error; @@ -282,16 +286,15 @@ return error; error = mnt_want_write(path.mnt); if (!error) { - error = setxattr(path.dentry, name, value, size, flags); + error = setxattr(path.dentry, path.mnt, name, value, size, flags, NULL); mnt_drop_write(path.mnt); } path_put(&path); return error; } -asmlinkage long -sys_fsetxattr(int fd, const char __user *name, const void __user *value, - size_t size, int flags) +SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name, + const void __user *,value, size_t, size, int, flags) { struct file *f; struct dentry *dentry; @@ -304,7 +307,8 @@ audit_inode(NULL, dentry); error = mnt_want_write(f->f_path.mnt); if (!error) { - error = setxattr(dentry, name, value, size, flags); + error = setxattr(dentry, f->f_vfsmnt, name, value, size, flags, + f); mnt_drop_write(f->f_path.mnt); } fput(f); @@ -315,8 +319,8 @@ * Extended attribute GET operations */ static ssize_t -getxattr(struct dentry *d, const char __user *name, void __user *value, - size_t size) +getxattr(struct dentry *dentry, struct vfsmount *mnt, const char __user *name, + void __user *value, size_t size, struct file *file) { ssize_t error; void *kvalue = NULL; @@ -336,7 +340,7 @@ return -ENOMEM; } - error = vfs_getxattr(d, kname, kvalue, size); + error = vfs_getxattr(dentry, mnt, kname, kvalue, size, file); if (error > 0) { if (size && copy_to_user(value, kvalue, error)) error = -EFAULT; @@ -349,9 +353,8 @@ return error; } -asmlinkage ssize_t -sys_getxattr(const char __user *pathname, const char __user *name, - void __user *value, size_t size) +SYSCALL_DEFINE4(getxattr, const char __user *, pathname, + const char __user *, name, void __user *, value, size_t, size) { struct path path; ssize_t error; @@ -359,14 +362,13 @@ error = user_path(pathname, &path); if (error) return error; - error = getxattr(path.dentry, name, value, size); + error = getxattr(path.dentry, path.mnt, name, value, size, NULL); path_put(&path); return error; } -asmlinkage ssize_t -sys_lgetxattr(const char __user *pathname, const char __user *name, void __user *value, - size_t size) +SYSCALL_DEFINE4(lgetxattr, const char __user *, pathname, + const char __user *, name, void __user *, value, size_t, size) { struct path path; ssize_t error; @@ -374,13 +376,13 @@ error = user_lpath(pathname, &path); if (error) return error; - error = getxattr(path.dentry, name, value, size); + error = getxattr(path.dentry, path.mnt, name, value, size, NULL); path_put(&path); return error; } -asmlinkage ssize_t -sys_fgetxattr(int fd, const char __user *name, void __user *value, size_t size) +SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name, + void __user *, value, size_t, size) { struct file *f; ssize_t error = -EBADF; @@ -389,7 +391,7 @@ if (!f) return error; audit_inode(NULL, f->f_path.dentry); - error = getxattr(f->f_path.dentry, name, value, size); + error = getxattr(f->f_path.dentry, f->f_path.mnt, name, value, size, f); fput(f); return error; } @@ -398,7 +400,8 @@ * Extended attribute LIST operations */ static ssize_t -listxattr(struct dentry *d, char __user *list, size_t size) +listxattr(struct dentry *dentry, struct vfsmount *mnt, char __user *list, + size_t size, struct file *file) { ssize_t error; char *klist = NULL; @@ -411,7 +414,7 @@ return -ENOMEM; } - error = vfs_listxattr(d, klist, size); + error = vfs_listxattr(dentry, mnt, klist, size, file); if (error > 0) { if (size && copy_to_user(list, klist, error)) error = -EFAULT; @@ -424,8 +427,8 @@ return error; } -asmlinkage ssize_t -sys_listxattr(const char __user *pathname, char __user *list, size_t size) +SYSCALL_DEFINE3(listxattr, const char __user *, pathname, char __user *, list, + size_t, size) { struct path path; ssize_t error; @@ -433,13 +436,13 @@ error = user_path(pathname, &path); if (error) return error; - error = listxattr(path.dentry, list, size); + error = listxattr(path.dentry, path.mnt, list, size, NULL); path_put(&path); return error; } -asmlinkage ssize_t -sys_llistxattr(const char __user *pathname, char __user *list, size_t size) +SYSCALL_DEFINE3(llistxattr, const char __user *, pathname, char __user *, list, + size_t, size) { struct path path; ssize_t error; @@ -447,13 +450,12 @@ error = user_lpath(pathname, &path); if (error) return error; - error = listxattr(path.dentry, list, size); + error = listxattr(path.dentry, path.mnt, list, size, NULL); path_put(&path); return error; } -asmlinkage ssize_t -sys_flistxattr(int fd, char __user *list, size_t size) +SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size) { struct file *f; ssize_t error = -EBADF; @@ -462,7 +464,7 @@ if (!f) return error; audit_inode(NULL, f->f_path.dentry); - error = listxattr(f->f_path.dentry, list, size); + error = listxattr(f->f_path.dentry, f->f_path.mnt, list, size, f); fput(f); return error; } @@ -471,7 +473,8 @@ * Extended attribute REMOVE operations */ static long -removexattr(struct dentry *d, const char __user *name) +removexattr(struct dentry *dentry, struct vfsmount *mnt, + const char __user *name, struct file *file) { int error; char kname[XATTR_NAME_MAX + 1]; @@ -482,11 +485,11 @@ if (error < 0) return error; - return vfs_removexattr(d, kname); + return vfs_removexattr(dentry, mnt, kname, file); } -asmlinkage long -sys_removexattr(const char __user *pathname, const char __user *name) +SYSCALL_DEFINE2(removexattr, const char __user *, pathname, + const char __user *, name) { struct path path; int error; @@ -496,15 +499,15 @@ return error; error = mnt_want_write(path.mnt); if (!error) { - error = removexattr(path.dentry, name); + error = removexattr(path.dentry, path.mnt, name, NULL); mnt_drop_write(path.mnt); } path_put(&path); return error; } -asmlinkage long -sys_lremovexattr(const char __user *pathname, const char __user *name) +SYSCALL_DEFINE2(lremovexattr, const char __user *, pathname, + const char __user *, name) { struct path path; int error; @@ -514,15 +517,14 @@ return error; error = mnt_want_write(path.mnt); if (!error) { - error = removexattr(path.dentry, name); + error = removexattr(path.dentry, path.mnt, name, NULL); mnt_drop_write(path.mnt); } path_put(&path); return error; } -asmlinkage long -sys_fremovexattr(int fd, const char __user *name) +SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name) { struct file *f; struct dentry *dentry; @@ -535,7 +537,7 @@ audit_inode(NULL, dentry); error = mnt_want_write(f->f_path.mnt); if (!error) { - error = removexattr(dentry, name); + error = removexattr(dentry, f->f_path.mnt, name, f); mnt_drop_write(f->f_path.mnt); } fput(f); --- linux-2.6.27.orig/fs/utimes.c +++ linux-2.6.27/fs/utimes.c @@ -24,7 +24,7 @@ * must be owner or have write permission. * Else, update from *times, must be owner or super user. */ -asmlinkage long sys_utime(char __user *filename, struct utimbuf __user *times) +SYSCALL_DEFINE2(utime, char __user *, filename, struct utimbuf __user *, times) { struct timespec tv[2]; @@ -48,7 +48,8 @@ return nsec >= 0 && nsec <= 999999999; } -static int utimes_common(struct path *path, struct timespec *times) +static int utimes_common(struct path *path, struct timespec *times, + struct file *f) { int error; struct iattr newattrs; @@ -102,7 +103,7 @@ } } mutex_lock(&inode->i_mutex); - error = notify_change(path->dentry, &newattrs); + error = fnotify_change(path->dentry, path->mnt, &newattrs, f); mutex_unlock(&inode->i_mutex); mnt_drop_write_and_out: @@ -149,7 +150,7 @@ if (!file) goto out; - error = utimes_common(&file->f_path, times); + error = utimes_common(&file->f_path, times, file); fput(file); } else { struct path path; @@ -162,7 +163,7 @@ if (error) goto out; - error = utimes_common(&path, times); + error = utimes_common(&path, times, NULL); path_put(&path); } @@ -170,7 +171,8 @@ return error; } -asmlinkage long sys_utimensat(int dfd, char __user *filename, struct timespec __user *utimes, int flags) +SYSCALL_DEFINE4(utimensat, int, dfd, char __user *, filename, + struct timespec __user *, utimes, int, flags) { struct timespec tstimes[2]; @@ -187,7 +189,8 @@ return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags); } -asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes) +SYSCALL_DEFINE3(futimesat, int, dfd, char __user *, filename, + struct timeval __user *, utimes) { struct timeval times[2]; struct timespec tstimes[2]; @@ -214,7 +217,8 @@ return do_utimes(dfd, filename, utimes ? tstimes : NULL, 0); } -asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes) +SYSCALL_DEFINE2(utimes, char __user *, filename, + struct timeval __user *, utimes) { return sys_futimesat(AT_FDCWD, filename, utimes); } --- linux-2.6.27.orig/fs/exec.c +++ linux-2.6.27/fs/exec.c @@ -105,7 +105,7 @@ * * Also note that we take the address to load from from the file itself. */ -asmlinkage long sys_uselib(const char __user * library) +SYSCALL_DEFINE1(uselib, const char __user *, library) { struct file *file; struct nameidata nd; @@ -1164,6 +1164,7 @@ */ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) { + unsigned int depth = bprm->recursion_depth; int try,retval; struct linux_binfmt *fmt; #ifdef __alpha__ @@ -1224,8 +1225,15 @@ continue; read_unlock(&binfmt_lock); retval = fn(bprm, regs); + /* + * Restore the depth counter to its starting value + * in this call, so we don't have to rely on every + * load_binary function to restore it on return. + */ + bprm->recursion_depth = depth; if (retval >= 0) { - tracehook_report_exec(fmt, bprm, regs); + if (depth == 0) + tracehook_report_exec(fmt, bprm, regs); put_binfmt(fmt); allow_write_access(bprm->file); if (bprm->file) @@ -1827,7 +1835,8 @@ goto close_fail; if (!file->f_op->write) goto close_fail; - if (!ispipe && do_truncate(file->f_path.dentry, 0, 0, file) != 0) + if (!ispipe && + do_truncate(file->f_path.dentry, file->f_path.mnt, 0, 0, file) != 0) goto close_fail; retval = binfmt->core_dump(signr, regs, file, core_limit); --- linux-2.6.27.orig/fs/ioprio.c +++ linux-2.6.27/fs/ioprio.c @@ -65,7 +65,7 @@ return err; } -asmlinkage long sys_ioprio_set(int which, int who, int ioprio) +SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio) { int class = IOPRIO_PRIO_CLASS(ioprio); int data = IOPRIO_PRIO_DATA(ioprio); @@ -181,7 +181,7 @@ return aprio; } -asmlinkage long sys_ioprio_get(int which, int who) +SYSCALL_DEFINE2(ioprio_get, int, which, int, who) { struct task_struct *g, *p; struct user_struct *user; @@ -245,4 +245,3 @@ read_unlock(&tasklist_lock); return ret; } - --- linux-2.6.27.orig/fs/attr.c +++ linux-2.6.27/fs/attr.c @@ -100,7 +100,8 @@ } EXPORT_SYMBOL(inode_setattr); -int notify_change(struct dentry * dentry, struct iattr * attr) +int fnotify_change(struct dentry *dentry, struct vfsmount *mnt, + struct iattr *attr, struct file *file) { struct inode *inode = dentry->d_inode; mode_t mode = inode->i_mode; @@ -163,13 +164,28 @@ down_write(&dentry->d_inode->i_alloc_sem); if (inode->i_op && inode->i_op->setattr) { - error = security_inode_setattr(dentry, attr); - if (!error) - error = inode->i_op->setattr(dentry, attr); + error = security_inode_setattr(dentry, mnt, attr); + if (!error) { + if (file && file->f_op && file->f_op->fsetattr) + error = file->f_op->fsetattr(file, attr); + else { + /* External file system still expect to be + * passed a file pointer via ia_file and + * have it announced via ATTR_FILE. This + * just makes it so they don't need to + * change their API just for us. External + * callers will have set these themselves. */ + if (file) { + attr->ia_valid |= ATTR_FILE; + attr->ia_file = file; + } + error = inode->i_op->setattr(dentry, attr); + } + } } else { error = inode_change_ok(inode, attr); if (!error) - error = security_inode_setattr(dentry, attr); + error = security_inode_setattr(dentry, mnt, attr); if (!error) { if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) @@ -187,5 +203,12 @@ return error; } +EXPORT_SYMBOL_GPL(fnotify_change); + +int notify_change(struct dentry *dentry, struct vfsmount *mnt, + struct iattr *attr) +{ + return fnotify_change(dentry, mnt, attr, NULL); +} EXPORT_SYMBOL(notify_change); --- linux-2.6.27.orig/fs/timerfd.c +++ linux-2.6.27/fs/timerfd.c @@ -179,7 +179,7 @@ return file; } -asmlinkage long sys_timerfd_create(int clockid, int flags) +SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags) { int ufd; struct timerfd_ctx *ctx; @@ -210,9 +210,9 @@ return ufd; } -asmlinkage long sys_timerfd_settime(int ufd, int flags, - const struct itimerspec __user *utmr, - struct itimerspec __user *otmr) +SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags, + const struct itimerspec __user *, utmr, + struct itimerspec __user *, otmr) { struct file *file; struct timerfd_ctx *ctx; @@ -267,7 +267,7 @@ return 0; } -asmlinkage long sys_timerfd_gettime(int ufd, struct itimerspec __user *otmr) +SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct itimerspec __user *, otmr) { struct file *file; struct timerfd_ctx *ctx; --- linux-2.6.27.orig/fs/quota.c +++ linux-2.6.27/fs/quota.c @@ -368,7 +368,8 @@ * calls. Maybe we need to add the process quotas etc. in the future, * but we probably should use rlimits for that. */ -asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, qid_t id, void __user *addr) +SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special, + qid_t, id, void __user *, addr) { uint cmds, type; struct super_block *sb = NULL; --- linux-2.6.27.orig/fs/pipe.c +++ linux-2.6.27/fs/pipe.c @@ -1051,7 +1051,7 @@ * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way Unix traditionally does this, though. */ -asmlinkage long __weak sys_pipe2(int __user *fildes, int flags) +SYSCALL_DEFINE2(pipe2, int __user *, fildes, int, flags) { int fd[2]; int error; @@ -1067,7 +1067,7 @@ return error; } -asmlinkage long __weak sys_pipe(int __user *fildes) +SYSCALL_DEFINE1(pipe, int __user *, fildes) { return sys_pipe2(fildes, 0); } --- linux-2.6.27.orig/fs/dcache.c +++ linux-2.6.27/fs/dcache.c @@ -1615,8 +1615,11 @@ */ memcpy(dentry->d_iname, target->d_name.name, target->d_name.len + 1); + dentry->d_name.len = target->d_name.len; + return; } } + do_switch(dentry->d_name.len, target->d_name.len); } /* @@ -1676,7 +1679,6 @@ /* Switch the names.. */ switch_names(dentry, target); - do_switch(dentry->d_name.len, target->d_name.len); do_switch(dentry->d_name.hash, target->d_name.hash); /* ... and switch the parents */ @@ -1781,7 +1783,6 @@ struct dentry *dparent, *aparent; switch_names(dentry, anon); - do_switch(dentry->d_name.len, anon->d_name.len); do_switch(dentry->d_name.hash, anon->d_name.hash); dparent = dentry->d_parent; @@ -1897,44 +1898,46 @@ * @root: root vfsmnt/dentry (may be modified by this function) * @buffer: buffer to return value in * @buflen: buffer length + * @flags: flags controling behavior of d_path * - * Convert a dentry into an ASCII path name. If the entry has been deleted - * the string " (deleted)" is appended. Note that this is ambiguous. - * - * Returns the buffer or an error code if the path was too long. - * - * "buflen" should be positive. Caller holds the dcache_lock. + * Convert a dentry into an ASCII path name. If the entry has been deleted, + * then if @flags has D_PATH_FAIL_DELETED set, ERR_PTR(-ENOENT) is returned. + * Otherwise, the string " (deleted)" is appended. Note that this is ambiguous. * * If path is not reachable from the supplied root, then the value of - * root is changed (without modifying refcounts). + * root is changed (without modifying refcounts). The path returned in this + * case will be relative (i.e., it will not start with a slash). + * + * Returns the buffer or an error code if the path was too long. */ char *__d_path(const struct path *path, struct path *root, - char *buffer, int buflen) + char *buffer, int buflen, int flags) { struct dentry *dentry = path->dentry; struct vfsmount *vfsmnt = path->mnt; - char *end = buffer + buflen; - char *retval; + const unsigned char *name; + int namelen; + + buffer += buflen; + prepend(&buffer, &buflen, "\0", 1); spin_lock(&vfsmount_lock); - prepend(&end, &buflen, "\0", 1); - if (!IS_ROOT(dentry) && d_unhashed(dentry) && - (prepend(&end, &buflen, " (deleted)", 10) != 0)) + spin_lock(&dcache_lock); + if (!IS_ROOT(dentry) && d_unhashed(dentry)) { + if (flags & D_PATH_FAIL_DELETED) { + buffer = ERR_PTR(-ENOENT); + goto out; + } + if (prepend(&buffer, &buflen, " (deleted)", 10) != 0) goto Elong; - + } if (buflen < 1) goto Elong; - /* Get '/' right */ - retval = end-1; - *retval = '/'; - for (;;) { + while (dentry != root->dentry || vfsmnt != root->mnt) { struct dentry * parent; - if (dentry == root->dentry && vfsmnt == root->mnt) - break; if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { - /* Global root? */ if (vfsmnt->mnt_parent == vfsmnt) { goto global_root; } @@ -1944,27 +1947,51 @@ } parent = dentry->d_parent; prefetch(parent); - if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) || - (prepend(&end, &buflen, "/", 1) != 0)) + if ((prepend_name(&buffer, &buflen, &dentry->d_name) != 0) || + (prepend(&buffer, &buflen, "/", 1) != 0)) goto Elong; - retval = end; dentry = parent; } + /* Get '/' right. */ + if (*buffer != '/' && prepend(&buffer, &buflen, "/", 1)) + goto Elong; out: + spin_unlock(&dcache_lock); spin_unlock(&vfsmount_lock); - return retval; + return buffer; global_root: - retval += 1; /* hit the slash */ - if (prepend_name(&retval, &buflen, &dentry->d_name) != 0) + /* + * We went past the (vfsmount, dentry) we were looking for and have + * either hit a root dentry, a lazily unmounted dentry, an + * unconnected dentry, or the file is on a pseudo filesystem. + */ + namelen = dentry->d_name.len; + name = dentry->d_name.name; + + /* + * If this is a root dentry, then overwrite the slash. This + * will also DTRT with pseudo filesystems which have root + * dentries named "foo:". + */ + if (IS_ROOT(dentry) && *buffer == '/') { + buffer++; + buflen++; + } + if ((flags & D_PATH_DISCONNECT) && *name == '/') { + /* Make sure we won't return a pathname starting with '/' */ + name++; + namelen--; + } + if (prepend(&buffer, &buflen, name, namelen)) goto Elong; root->mnt = vfsmnt; root->dentry = dentry; goto out; Elong: - retval = ERR_PTR(-ENAMETOOLONG); + buffer = ERR_PTR(-ENAMETOOLONG); goto out; } @@ -2001,10 +2028,8 @@ root = current->fs->root; path_get(&root); read_unlock(¤t->fs->lock); - spin_lock(&dcache_lock); tmp = root; - res = __d_path(path, &tmp, buf, buflen); - spin_unlock(&dcache_lock); + res = __d_path(path, &tmp, buf, buflen, 0); path_put(&root); return res; } @@ -2085,11 +2110,11 @@ * return NULL; * } */ -asmlinkage long sys_getcwd(char __user *buf, unsigned long size) +SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) { - int error; - struct path pwd, root; - char *page = (char *) __get_free_page(GFP_USER); + int error, len; + struct path pwd, root, tmp; + char *page = (char *) __get_free_page(GFP_USER), *cwd; if (!page) return -ENOMEM; @@ -2101,30 +2126,20 @@ path_get(&root); read_unlock(¤t->fs->lock); - error = -ENOENT; - /* Has the current directory has been unlinked? */ - spin_lock(&dcache_lock); - if (IS_ROOT(pwd.dentry) || !d_unhashed(pwd.dentry)) { - unsigned long len; - struct path tmp = root; - char * cwd; - - cwd = __d_path(&pwd, &tmp, page, PAGE_SIZE); - spin_unlock(&dcache_lock); - + tmp = root; + cwd = __d_path(&pwd, &tmp, page, PAGE_SIZE, D_PATH_FAIL_DELETED); + if (IS_ERR(cwd)) { error = PTR_ERR(cwd); - if (IS_ERR(cwd)) - goto out; + goto out; + } - error = -ERANGE; - len = PAGE_SIZE + page - cwd; - if (len <= size) { - error = len; - if (copy_to_user(buf, cwd, len)) - error = -EFAULT; - } - } else - spin_unlock(&dcache_lock); + error = -ERANGE; + len = PAGE_SIZE + page - cwd; + if (len <= size) { + error = len; + if (copy_to_user(buf, cwd, len)) + error = -EFAULT; + } out: path_put(&pwd); --- linux-2.6.27.orig/fs/fs-writeback.c +++ linux-2.6.27/fs/fs-writeback.c @@ -421,9 +421,6 @@ * If we're a pdlfush thread, then implement pdflush collision avoidance * against the entire list. * - * WB_SYNC_HOLD is a hack for sys_sync(): reattach the inode to sb->s_dirty so - * that it can be located for waiting on in __writeback_single_inode(). - * * If `bdi' is non-zero then we're being asked to writeback a specific queue. * This function assumes that the blockdev superblock's inodes are backed by * a variety of queues, so all inodes are searched. For other superblocks, @@ -443,6 +440,7 @@ struct writeback_control *wbc) { const unsigned long start = jiffies; /* livelock avoidance */ + int sync = wbc->sync_mode == WB_SYNC_ALL; spin_lock(&inode_lock); if (!wbc->for_kupdate || list_empty(&sb->s_io)) @@ -499,10 +497,6 @@ __iget(inode); pages_skipped = wbc->pages_skipped; __writeback_single_inode(inode, wbc); - if (wbc->sync_mode == WB_SYNC_HOLD) { - inode->dirtied_when = jiffies; - list_move(&inode->i_list, &sb->s_dirty); - } if (current_is_pdflush()) writeback_release(bdi); if (wbc->pages_skipped != pages_skipped) { @@ -523,7 +517,49 @@ if (!list_empty(&sb->s_more_io)) wbc->more_io = 1; } - spin_unlock(&inode_lock); + + if (sync) { + struct inode *inode, *old_inode = NULL; + + /* + * Data integrity sync. Must wait for all pages under writeback, + * because there may have been pages dirtied before our sync + * call, but which had writeout started before we write it out. + * In which case, the inode may not be on the dirty list, but + * we still have to wait for that writeout. + */ + list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { + struct address_space *mapping; + + if (inode->i_state & (I_FREEING|I_WILL_FREE)) + continue; + mapping = inode->i_mapping; + if (mapping->nrpages == 0) + continue; + __iget(inode); + spin_unlock(&inode_lock); + /* + * We hold a reference to 'inode' so it couldn't have + * been removed from s_inodes list while we dropped the + * inode_lock. We cannot iput the inode now as we can + * be holding the last reference and we cannot iput it + * under inode_lock. So we keep the reference and iput + * it later. + */ + iput(old_inode); + old_inode = inode; + + filemap_fdatawait(mapping); + + cond_resched(); + + spin_lock(&inode_lock); + } + spin_unlock(&inode_lock); + iput(old_inode); + } else + spin_unlock(&inode_lock); + return; /* Leave any unwritten inodes on s_io */ } EXPORT_SYMBOL_GPL(generic_sync_sb_inodes); @@ -588,8 +624,7 @@ /* * writeback and wait upon the filesystem's dirty inodes. The caller will - * do this in two passes - one to write, and one to wait. WB_SYNC_HOLD is - * used to park the written inodes on sb->s_dirty for the wait pass. + * do this in two passes - one to write, and one to wait. * * A finite limit is set on the number of pages which will be written. * To prevent infinite livelock of sys_sync(). @@ -600,30 +635,21 @@ void sync_inodes_sb(struct super_block *sb, int wait) { struct writeback_control wbc = { - .sync_mode = wait ? WB_SYNC_ALL : WB_SYNC_HOLD, + .sync_mode = wait ? WB_SYNC_ALL : WB_SYNC_NONE, .range_start = 0, .range_end = LLONG_MAX, }; - unsigned long nr_dirty = global_page_state(NR_FILE_DIRTY); - unsigned long nr_unstable = global_page_state(NR_UNSTABLE_NFS); - wbc.nr_to_write = nr_dirty + nr_unstable + - (inodes_stat.nr_inodes - inodes_stat.nr_unused) + - nr_dirty + nr_unstable; - wbc.nr_to_write += wbc.nr_to_write / 2; /* Bit more for luck */ - sync_sb_inodes(sb, &wbc); -} + if (!wait) { + unsigned long nr_dirty = global_page_state(NR_FILE_DIRTY); + unsigned long nr_unstable = global_page_state(NR_UNSTABLE_NFS); + + wbc.nr_to_write = nr_dirty + nr_unstable + + (inodes_stat.nr_inodes - inodes_stat.nr_unused); + } else + wbc.nr_to_write = LONG_MAX; /* doesn't actually matter */ -/* - * Rather lame livelock avoidance. - */ -static void set_sb_syncing(int val) -{ - struct super_block *sb; - spin_lock(&sb_lock); - list_for_each_entry_reverse(sb, &super_blocks, s_list) - sb->s_syncing = val; - spin_unlock(&sb_lock); + sync_sb_inodes(sb, &wbc); } /** @@ -652,9 +678,6 @@ spin_lock(&sb_lock); restart: list_for_each_entry(sb, &super_blocks, s_list) { - if (sb->s_syncing) - continue; - sb->s_syncing = 1; sb->s_count++; spin_unlock(&sb_lock); down_read(&sb->s_umount); @@ -672,13 +695,10 @@ void sync_inodes(int wait) { - set_sb_syncing(0); __sync_inodes(0); - if (wait) { - set_sb_syncing(0); + if (wait) __sync_inodes(1); - } } /** --- linux-2.6.27.orig/fs/ioctl.c +++ linux-2.6.27/fs/ioctl.c @@ -123,11 +123,9 @@ /* Did FASYNC state change ? */ if ((flag ^ filp->f_flags) & FASYNC) { - if (filp->f_op && filp->f_op->fasync) { - lock_kernel(); + if (filp->f_op && filp->f_op->fasync) error = filp->f_op->fasync(fd, filp, on); - unlock_kernel(); - } else + else error = -ENOTTY; } if (error) @@ -163,11 +161,17 @@ break; case FIONBIO: + /* BKL needed to avoid races tweaking f_flags */ + lock_kernel(); error = ioctl_fionbio(filp, argp); + unlock_kernel(); break; case FIOASYNC: + /* BKL needed to avoid races tweaking f_flags */ + lock_kernel(); error = ioctl_fioasync(fd, filp, argp); + unlock_kernel(); break; case FIOQSIZE: @@ -191,7 +195,7 @@ return error; } -asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) { struct file *filp; int error = -EBADF; --- linux-2.6.27.orig/fs/super.c +++ linux-2.6.27/fs/super.c @@ -534,7 +534,7 @@ return NULL; } -asmlinkage long sys_ustat(unsigned dev, struct ustat __user * ubuf) +SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf) { struct super_block *s; struct ustat tmp; --- linux-2.6.27.orig/fs/inotify_user.c +++ linux-2.6.27/fs/inotify_user.c @@ -372,7 +372,7 @@ if (error) return error; /* you can only watch an inode if you have read permissions on it */ - error = inode_permission(path->dentry->d_inode, MAY_READ); + error = path_permission(path, MAY_READ); if (error) path_put(path); return error; @@ -427,10 +427,61 @@ return ret; } +/* + * Get an inotify_kernel_event if one exists and is small + * enough to fit in "count". Return an error pointer if + * not large enough. + * + * Called with the device ev_mutex held. + */ +static struct inotify_kernel_event *get_one_event(struct inotify_device *dev, + size_t count) +{ + size_t event_size = sizeof(struct inotify_event); + struct inotify_kernel_event *kevent; + + if (list_empty(&dev->events)) + return NULL; + + kevent = inotify_dev_get_event(dev); + if (kevent->name) + event_size += kevent->event.len; + + if (event_size > count) + return ERR_PTR(-EINVAL); + + remove_kevent(dev, kevent); + return kevent; +} + +/* + * Copy an event to user space, returning how much we copied. + * + * We already checked that the event size is smaller than the + * buffer we had in "get_one_event()" above. + */ +static ssize_t copy_event_to_user(struct inotify_kernel_event *kevent, + char __user *buf) +{ + size_t event_size = sizeof(struct inotify_event); + + if (copy_to_user(buf, &kevent->event, event_size)) + return -EFAULT; + + if (kevent->name) { + buf += event_size; + + if (copy_to_user(buf, kevent->name, kevent->event.len)) + return -EFAULT; + + event_size += kevent->event.len; + } + return event_size; +} + static ssize_t inotify_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { - size_t event_size = sizeof (struct inotify_event); struct inotify_device *dev; char __user *start; int ret; @@ -440,81 +491,43 @@ dev = file->private_data; while (1) { + struct inotify_kernel_event *kevent; prepare_to_wait(&dev->wq, &wait, TASK_INTERRUPTIBLE); mutex_lock(&dev->ev_mutex); - if (!list_empty(&dev->events)) { - ret = 0; - break; - } + kevent = get_one_event(dev, count); mutex_unlock(&dev->ev_mutex); - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - break; - } - - if (signal_pending(current)) { - ret = -EINTR; - break; + if (kevent) { + ret = PTR_ERR(kevent); + if (IS_ERR(kevent)) + break; + ret = copy_event_to_user(kevent, buf); + free_kevent(kevent); + if (ret < 0) + break; + buf += ret; + count -= ret; + continue; } - schedule(); - } - - finish_wait(&dev->wq, &wait); - if (ret) - return ret; - - while (1) { - struct inotify_kernel_event *kevent; - - ret = buf - start; - if (list_empty(&dev->events)) + ret = -EAGAIN; + if (file->f_flags & O_NONBLOCK) break; - - kevent = inotify_dev_get_event(dev); - if (event_size + kevent->event.len > count) { - if (ret == 0 && count > 0) { - /* - * could not get a single event because we - * didn't have enough buffer space. - */ - ret = -EINVAL; - } + ret = -EINTR; + if (signal_pending(current)) break; - } - remove_kevent(dev, kevent); - /* - * Must perform the copy_to_user outside the mutex in order - * to avoid a lock order reversal with mmap_sem. - */ - mutex_unlock(&dev->ev_mutex); - - if (copy_to_user(buf, &kevent->event, event_size)) { - ret = -EFAULT; + if (start != buf) break; - } - buf += event_size; - count -= event_size; - - if (kevent->name) { - if (copy_to_user(buf, kevent->name, kevent->event.len)){ - ret = -EFAULT; - break; - } - buf += kevent->event.len; - count -= kevent->event.len; - } - free_kevent(kevent); - - mutex_lock(&dev->ev_mutex); + schedule(); } - mutex_unlock(&dev->ev_mutex); + finish_wait(&dev->wq, &wait); + if (start != buf && ret != -EFAULT) + ret = buf - start; return ret; } @@ -579,7 +592,7 @@ .destroy_watch = free_inotify_user_watch, }; -asmlinkage long sys_inotify_init1(int flags) +SYSCALL_DEFINE1(inotify_init1, int, flags) { struct inotify_device *dev; struct inotify_handle *ih; @@ -658,12 +671,13 @@ return ret; } -asmlinkage long sys_inotify_init(void) +SYSCALL_DEFINE0(inotify_init) { return sys_inotify_init1(0); } -asmlinkage long sys_inotify_add_watch(int fd, const char __user *pathname, u32 mask) +SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname, + u32, mask) { struct inode *inode; struct inotify_device *dev; @@ -707,7 +721,7 @@ return ret; } -asmlinkage long sys_inotify_rm_watch(int fd, u32 wd) +SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd) { struct file *filp; struct inotify_device *dev; --- linux-2.6.27.orig/fs/binfmt_em86.c +++ linux-2.6.27/fs/binfmt_em86.c @@ -43,7 +43,7 @@ return -ENOEXEC; } - bprm->sh_bang = 1; /* Well, the bang-shell is implicit... */ + bprm->recursion_depth++; /* Well, the bang-shell is implicit... */ allow_write_access(bprm->file); fput(bprm->file); bprm->file = NULL; --- linux-2.6.27.orig/fs/sync.c +++ linux-2.6.27/fs/sync.c @@ -36,7 +36,7 @@ laptop_sync_completion(); } -asmlinkage long sys_sync(void) +SYSCALL_DEFINE0(sync) { do_sync(1); return 0; @@ -118,12 +118,12 @@ return ret; } -asmlinkage long sys_fsync(unsigned int fd) +SYSCALL_DEFINE1(fsync, unsigned int, fd) { return __do_fsync(fd, 0); } -asmlinkage long sys_fdatasync(unsigned int fd) +SYSCALL_DEFINE1(fdatasync, unsigned int, fd) { return __do_fsync(fd, 1); } @@ -175,8 +175,8 @@ * already-instantiated disk blocks, there are no guarantees here that the data * will be available after a crash. */ -asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes, - unsigned int flags) +SYSCALL_DEFINE(sync_file_range)(int fd, loff_t offset, loff_t nbytes, + unsigned int flags) { int ret; struct file *file; @@ -236,14 +236,32 @@ out: return ret; } +#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS +asmlinkage long SyS_sync_file_range(long fd, loff_t offset, loff_t nbytes, + long flags) +{ + return SYSC_sync_file_range((int) fd, offset, nbytes, + (unsigned int) flags); +} +SYSCALL_ALIAS(sys_sync_file_range, SyS_sync_file_range); +#endif /* It would be nice if people remember that not all the world's an i386 when they introduce new system calls */ -asmlinkage long sys_sync_file_range2(int fd, unsigned int flags, - loff_t offset, loff_t nbytes) +SYSCALL_DEFINE(sync_file_range2)(int fd, unsigned int flags, + loff_t offset, loff_t nbytes) { return sys_sync_file_range(fd, offset, nbytes, flags); } +#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS +asmlinkage long SyS_sync_file_range2(long fd, long flags, + loff_t offset, loff_t nbytes) +{ + return SYSC_sync_file_range2((int) fd, (unsigned int) flags, + offset, nbytes); +} +SYSCALL_ALIAS(sys_sync_file_range2, SyS_sync_file_range2); +#endif /* * `endbyte' is inclusive @@ -269,7 +287,7 @@ if (flags & SYNC_FILE_RANGE_WRITE) { ret = __filemap_fdatawrite_range(mapping, offset, endbyte, - WB_SYNC_NONE); + WB_SYNC_ALL); if (ret < 0) goto out; } --- linux-2.6.27.orig/fs/dcookies.c +++ linux-2.6.27/fs/dcookies.c @@ -140,7 +140,7 @@ /* And here is where the userspace process can look up the cookie value * to retrieve the path. */ -asmlinkage long sys_lookup_dcookie(u64 cookie64, char __user * buf, size_t len) +SYSCALL_DEFINE(lookup_dcookie)(u64 cookie64, char __user * buf, size_t len) { unsigned long cookie = (unsigned long)cookie64; int err = -EINVAL; @@ -193,7 +193,13 @@ mutex_unlock(&dcookie_mutex); return err; } - +#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS +asmlinkage long SyS_lookup_dcookie(u64 cookie64, long buf, long len) +{ + return SYSC_lookup_dcookie(cookie64, (char __user *) buf, (size_t) len); +} +SYSCALL_ALIAS(sys_lookup_dcookie, SyS_lookup_dcookie); +#endif static int dcookie_init(void) { --- linux-2.6.27.orig/fs/eventfd.c +++ linux-2.6.27/fs/eventfd.c @@ -198,7 +198,7 @@ return file; } -asmlinkage long sys_eventfd2(unsigned int count, int flags) +SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags) { int fd; struct eventfd_ctx *ctx; @@ -228,8 +228,7 @@ return fd; } -asmlinkage long sys_eventfd(unsigned int count) +SYSCALL_DEFINE1(eventfd, unsigned int, count) { return sys_eventfd2(count, 0); } - --- linux-2.6.27.orig/fs/splice.c +++ linux-2.6.27/fs/splice.c @@ -735,10 +735,19 @@ * ->commit_write. Most of the time, these expect i_mutex to * be held. Since this may result in an ABBA deadlock with * pipe->inode, we have to order lock acquiry here. + * + * Outer lock must be inode->i_mutex, as pipe_wait() will + * release and reacquire pipe->inode->i_mutex, AND inode must + * never be a pipe. */ - inode_double_lock(inode, pipe->inode); + WARN_ON(S_ISFIFO(inode->i_mode)); + mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT); + if (pipe->inode) + mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_CHILD); ret = __splice_from_pipe(pipe, &sd, actor); - inode_double_unlock(inode, pipe->inode); + if (pipe->inode) + mutex_unlock(&pipe->inode->i_mutex); + mutex_unlock(&inode->i_mutex); return ret; } @@ -829,11 +838,17 @@ }; ssize_t ret; - inode_double_lock(inode, pipe->inode); + WARN_ON(S_ISFIFO(inode->i_mode)); + mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT); ret = file_remove_suid(out); - if (likely(!ret)) + if (likely(!ret)) { + if (pipe->inode) + mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_CHILD); ret = __splice_from_pipe(pipe, &sd, pipe_to_file); - inode_double_unlock(inode, pipe->inode); + if (pipe->inode) + mutex_unlock(&pipe->inode->i_mutex); + } + mutex_unlock(&inode->i_mutex); if (ret > 0) { unsigned long nr_pages; @@ -887,8 +902,8 @@ /* * Attempt to initiate a splice from pipe to file. */ -static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, - loff_t *ppos, size_t len, unsigned int flags) +long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags) { int ret; @@ -907,13 +922,14 @@ return out->f_op->splice_write(pipe, out, ppos, len, flags); } +EXPORT_SYMBOL(do_splice_from); /* * Attempt to initiate a splice from a file to a pipe. */ -static long do_splice_to(struct file *in, loff_t *ppos, - struct pipe_inode_info *pipe, size_t len, - unsigned int flags) +long do_splice_to(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags) { int ret; @@ -929,6 +945,7 @@ return in->f_op->splice_read(in, ppos, pipe, len, flags); } +EXPORT_SYMBOL(do_splice_to); /** * splice_direct_to_actor - splices data directly between two non-pipes @@ -1434,8 +1451,8 @@ * Currently we punt and implement it as a normal copy, see pipe_to_user(). * */ -asmlinkage long sys_vmsplice(int fd, const struct iovec __user *iov, - unsigned long nr_segs, unsigned int flags) +SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, iov, + unsigned long, nr_segs, unsigned int, flags) { struct file *file; long error; @@ -1460,9 +1477,9 @@ return error; } -asmlinkage long sys_splice(int fd_in, loff_t __user *off_in, - int fd_out, loff_t __user *off_out, - size_t len, unsigned int flags) +SYSCALL_DEFINE6(splice, int, fd_in, loff_t __user *, off_in, + int, fd_out, loff_t __user *, off_out, + size_t, len, unsigned int, flags) { long error; struct file *in, *out; @@ -1684,7 +1701,7 @@ return ret; } -asmlinkage long sys_tee(int fdin, int fdout, size_t len, unsigned int flags) +SYSCALL_DEFINE4(tee, int, fdin, int, fdout, size_t, len, unsigned int, flags) { struct file *in; int error, fput_in; --- linux-2.6.27.orig/fs/compat_ioctl.c +++ linux-2.6.27/fs/compat_ioctl.c @@ -538,6 +538,7 @@ * cannot be fixed without breaking all existing apps. */ case TUNSETIFF: + case TUNGETIFF: case SIOCGIFFLAGS: case SIOCGIFMETRIC: case SIOCGIFMTU: @@ -1982,6 +1983,11 @@ COMPATIBLE_IOCTL(TUNSETDEBUG) COMPATIBLE_IOCTL(TUNSETPERSIST) COMPATIBLE_IOCTL(TUNSETOWNER) +COMPATIBLE_IOCTL(TUNSETLINK) +COMPATIBLE_IOCTL(TUNSETGROUP) +COMPATIBLE_IOCTL(TUNGETFEATURES) +COMPATIBLE_IOCTL(TUNSETOFFLOAD) +COMPATIBLE_IOCTL(TUNSETTXFILTER) /* Big V */ COMPATIBLE_IOCTL(VT_SETMODE) COMPATIBLE_IOCTL(VT_GETMODE) @@ -2573,6 +2579,7 @@ HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc) HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc) HANDLE_IOCTL(TUNSETIFF, dev_ifsioc) +HANDLE_IOCTL(TUNGETIFF, dev_ifsioc) HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl) HANDLE_IOCTL(SIOCBONDENSLAVE, bond_ioctl) HANDLE_IOCTL(SIOCBONDRELEASE, bond_ioctl) --- linux-2.6.27.orig/fs/compat.c +++ linux-2.6.27/fs/compat.c @@ -1640,7 +1640,7 @@ } #ifdef HAVE_SET_RESTORE_SIGMASK -asmlinkage long compat_sys_pselect7(int n, compat_ulong_t __user *inp, +static long do_compat_pselect(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp, compat_ulong_t __user *exp, struct compat_timespec __user *tsp, compat_sigset_t __user *sigmask, compat_size_t sigsetsize) @@ -1748,8 +1748,8 @@ (compat_size_t __user *)(sig+sizeof(up)))) return -EFAULT; } - return compat_sys_pselect7(n, inp, outp, exp, tsp, compat_ptr(up), - sigsetsize); + return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(up), + sigsetsize); } asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds, --- linux-2.6.27.orig/fs/aio.c +++ linux-2.6.27/fs/aio.c @@ -1258,7 +1258,7 @@ * pointer is passed for ctxp. Will fail with -ENOSYS if not * implemented. */ -asmlinkage long sys_io_setup(unsigned nr_events, aio_context_t __user *ctxp) +SYSCALL_DEFINE2(io_setup, unsigned, nr_events, aio_context_t __user *, ctxp) { struct kioctx *ioctx = NULL; unsigned long ctx; @@ -1296,7 +1296,7 @@ * implemented. May fail with -EFAULT if the context pointed to * is invalid. */ -asmlinkage long sys_io_destroy(aio_context_t ctx) +SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx) { struct kioctx *ioctx = lookup_ioctx(ctx); if (likely(NULL != ioctx)) { @@ -1650,8 +1650,8 @@ * are available to queue any iocbs. Will return 0 if nr is 0. Will * fail with -ENOSYS if not implemented. */ -asmlinkage long sys_io_submit(aio_context_t ctx_id, long nr, - struct iocb __user * __user *iocbpp) +SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr, + struct iocb __user * __user *, iocbpp) { struct kioctx *ctx; long ret = 0; @@ -1725,8 +1725,8 @@ * invalid. May fail with -EAGAIN if the iocb specified was not * cancelled. Will fail with -ENOSYS if not implemented. */ -asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb __user *iocb, - struct io_event __user *result) +SYSCALL_DEFINE3(io_cancel, aio_context_t, ctx_id, struct iocb __user *, iocb, + struct io_event __user *, result) { int (*cancel)(struct kiocb *iocb, struct io_event *res); struct kioctx *ctx; @@ -1787,11 +1787,11 @@ * will be updated if not NULL and the operation blocks. Will fail * with -ENOSYS if not implemented. */ -asmlinkage long sys_io_getevents(aio_context_t ctx_id, - long min_nr, - long nr, - struct io_event __user *events, - struct timespec __user *timeout) +SYSCALL_DEFINE5(io_getevents, aio_context_t, ctx_id, + long, min_nr, + long, nr, + struct io_event __user *, events, + struct timespec __user *, timeout) { struct kioctx *ioctx = lookup_ioctx(ctx_id); long ret = -EINVAL; --- linux-2.6.27.orig/fs/filesystems.c +++ linux-2.6.27/fs/filesystems.c @@ -177,7 +177,7 @@ /* * Whee.. Weird sysv syscall. */ -asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2) +SYSCALL_DEFINE3(sysfs, int, option, unsigned long, arg1, unsigned long, arg2) { int retval = -EINVAL; --- linux-2.6.27.orig/fs/buffer.c +++ linux-2.6.27/fs/buffer.c @@ -1988,7 +1988,7 @@ page = *pagep; if (page == NULL) { ownpage = 1; - page = __grab_cache_page(mapping, index); + page = grab_cache_page_write_begin(mapping, index, flags); if (!page) { status = -ENOMEM; goto out; @@ -2494,7 +2494,7 @@ from = pos & (PAGE_CACHE_SIZE - 1); to = from + len; - page = __grab_cache_page(mapping, index); + page = grab_cache_page_write_begin(mapping, index, flags); if (!page) return -ENOMEM; *pagep = page; @@ -3177,7 +3177,7 @@ * Use of bdflush() is deprecated and will be removed in a future kernel. * The `pdflush' kernel threads fully replace bdflush daemons and this call. */ -asmlinkage long sys_bdflush(int func, long data) +SYSCALL_DEFINE2(bdflush, int, func, long, data) { static int msg_count; --- linux-2.6.27.orig/fs/nfsctl.c +++ linux-2.6.27/fs/nfsctl.c @@ -82,8 +82,8 @@ }, }; -long -asmlinkage sys_nfsservctl(int cmd, struct nfsctl_arg __user *arg, void __user *res) +SYSCALL_DEFINE3(nfsservctl, int, cmd, struct nfsctl_arg __user *, arg, + void __user *, res) { struct file *file; void __user *p = &arg->u; --- linux-2.6.27.orig/fs/seq_file.c +++ linux-2.6.27/fs/seq_file.c @@ -54,6 +54,64 @@ } EXPORT_SYMBOL(seq_open); +static int traverse(struct seq_file *m, loff_t offset) +{ + loff_t pos = 0, index; + int error = 0; + void *p; + + m->version = 0; + index = 0; + m->count = m->from = 0; + if (!offset) { + m->index = index; + return 0; + } + if (!m->buf) { + m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL); + if (!m->buf) + return -ENOMEM; + } + p = m->op->start(m, &index); + while (p) { + error = PTR_ERR(p); + if (IS_ERR(p)) + break; + error = m->op->show(m, p); + if (error < 0) + break; + if (unlikely(error)) { + error = 0; + m->count = 0; + } + if (m->count == m->size) + goto Eoverflow; + if (pos + m->count > offset) { + m->from = offset - pos; + m->count -= m->from; + m->index = index; + break; + } + pos += m->count; + m->count = 0; + if (pos == offset) { + index++; + m->index = index; + break; + } + p = m->op->next(m, p, &index); + } + m->op->stop(m, p); + m->index = index; + return error; + +Eoverflow: + m->op->stop(m, p); + kfree(m->buf); + m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); + return !m->buf ? -ENOMEM : -EAGAIN; +} + /** * seq_read - ->read() method for sequential files. * @file: the file to read from @@ -186,63 +244,6 @@ } EXPORT_SYMBOL(seq_read); -static int traverse(struct seq_file *m, loff_t offset) -{ - loff_t pos = 0, index; - int error = 0; - void *p; - - m->version = 0; - index = 0; - m->count = m->from = 0; - if (!offset) { - m->index = index; - return 0; - } - if (!m->buf) { - m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL); - if (!m->buf) - return -ENOMEM; - } - p = m->op->start(m, &index); - while (p) { - error = PTR_ERR(p); - if (IS_ERR(p)) - break; - error = m->op->show(m, p); - if (error < 0) - break; - if (unlikely(error)) { - error = 0; - m->count = 0; - } - if (m->count == m->size) - goto Eoverflow; - if (pos + m->count > offset) { - m->from = offset - pos; - m->count -= m->from; - m->index = index; - break; - } - pos += m->count; - m->count = 0; - if (pos == offset) { - index++; - m->index = index; - break; - } - p = m->op->next(m, p, &index); - } - m->op->stop(m, p); - return error; - -Eoverflow: - m->op->stop(m, p); - kfree(m->buf); - m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); - return !m->buf ? -ENOMEM : -EAGAIN; -} - /** * seq_lseek - ->llseek() method for sequential files. * @file: the file in question @@ -412,9 +413,7 @@ char *s = m->buf + m->count; char *p; - spin_lock(&dcache_lock); - p = __d_path(path, root, s, m->size - m->count); - spin_unlock(&dcache_lock); + p = __d_path(path, root, s, m->size - m->count, 0); err = PTR_ERR(p); if (!IS_ERR(p)) { s = mangle_path(s, p, esc); --- linux-2.6.27.orig/fs/minix/dir.c +++ linux-2.6.27/fs/minix/dir.c @@ -280,7 +280,7 @@ return -EINVAL; got_it: - pos = (page->index >> PAGE_CACHE_SHIFT) + p - (char*)page_address(page); + pos = page_offset(page) + p - (char *)page_address(page); err = __minix_write_begin(NULL, page->mapping, pos, sbi->s_dirsize, AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); if (err) --- linux-2.6.27.orig/fs/lockd/svclock.c +++ linux-2.6.27/fs/lockd/svclock.c @@ -418,7 +418,7 @@ goto out; case -EAGAIN: ret = nlm_lck_denied; - goto out; + break; case FILE_LOCK_DEFERRED: if (wait) break; @@ -434,6 +434,10 @@ goto out; } + ret = nlm_lck_denied; + if (!wait) + goto out; + ret = nlm_lck_blocked; /* Append to list of blocked */ --- linux-2.6.27.orig/fs/cifs/cifs_spnego.c +++ linux-2.6.27/fs/cifs/cifs_spnego.c @@ -70,7 +70,8 @@ strlen("ver=0xFF") */ #define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg in future could have strlen(";sec=ntlmsspi") */ -#define MAX_IPV6_ADDR_LEN 42 /* eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */ +/* max possible addr len eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/128 */ +#define MAX_IPV6_ADDR_LEN 43 /* get a key struct with a SPNEGO security blob, suitable for session setup */ struct key * cifs_get_spnego_key(struct cifsSesInfo *sesInfo) --- linux-2.6.27.orig/fs/cifs/misc.c +++ linux-2.6.27/fs/cifs/misc.c @@ -75,12 +75,12 @@ ret_buf = kzalloc(sizeof(struct cifsSesInfo), GFP_KERNEL); if (ret_buf) { - write_lock(&GlobalSMBSeslock); atomic_inc(&sesInfoAllocCount); ret_buf->status = CifsNew; - list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList); + ++ret_buf->ses_count; + INIT_LIST_HEAD(&ret_buf->smb_ses_list); + INIT_LIST_HEAD(&ret_buf->tcon_list); init_MUTEX(&ret_buf->sesSem); - write_unlock(&GlobalSMBSeslock); } return ret_buf; } @@ -93,10 +93,7 @@ return; } - write_lock(&GlobalSMBSeslock); atomic_dec(&sesInfoAllocCount); - list_del(&buf_to_free->cifsSessionList); - write_unlock(&GlobalSMBSeslock); kfree(buf_to_free->serverOS); kfree(buf_to_free->serverDomain); kfree(buf_to_free->serverNOS); @@ -111,17 +108,14 @@ struct cifsTconInfo *ret_buf; ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL); if (ret_buf) { - write_lock(&GlobalSMBSeslock); atomic_inc(&tconInfoAllocCount); - list_add(&ret_buf->cifsConnectionList, - &GlobalTreeConnectionList); ret_buf->tidStatus = CifsNew; + ++ret_buf->tc_count; INIT_LIST_HEAD(&ret_buf->openFileList); - init_MUTEX(&ret_buf->tconSem); + INIT_LIST_HEAD(&ret_buf->tcon_list); #ifdef CONFIG_CIFS_STATS spin_lock_init(&ret_buf->stat_lock); #endif - write_unlock(&GlobalSMBSeslock); } return ret_buf; } @@ -133,10 +127,7 @@ cFYI(1, ("Null buffer passed to tconInfoFree")); return; } - write_lock(&GlobalSMBSeslock); atomic_dec(&tconInfoAllocCount); - list_del(&buf_to_free->cifsConnectionList); - write_unlock(&GlobalSMBSeslock); kfree(buf_to_free->nativeFileSystem); kfree(buf_to_free); } @@ -354,9 +345,9 @@ if (current->fsuid != treeCon->ses->linux_uid) { cFYI(1, ("Multiuser mode and UID " "did not match tcon uid")); - read_lock(&GlobalSMBSeslock); - list_for_each(temp_item, &GlobalSMBSessionList) { - ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList); + read_lock(&cifs_tcp_ses_lock); + list_for_each(temp_item, &treeCon->ses->server->smb_ses_list) { + ses = list_entry(temp_item, struct cifsSesInfo, smb_ses_list); if (ses->linux_uid == current->fsuid) { if (ses->server == treeCon->ses->server) { cFYI(1, ("found matching uid substitute right smb_uid")); @@ -368,7 +359,7 @@ } } } - read_unlock(&GlobalSMBSeslock); + read_unlock(&cifs_tcp_ses_lock); } } } @@ -501,9 +492,10 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) { struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf; - struct list_head *tmp; - struct list_head *tmp1; + struct list_head *tmp, *tmp1, *tmp2; + struct cifsSesInfo *ses; struct cifsTconInfo *tcon; + struct cifsInodeInfo *pCifsInode; struct cifsFileInfo *netfile; cFYI(1, ("Checking for oplock break or dnotify response")); @@ -558,42 +550,42 @@ return false; /* look up tcon based on tid & uid */ - read_lock(&GlobalSMBSeslock); - list_for_each(tmp, &GlobalTreeConnectionList) { - tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); - if ((tcon->tid == buf->Tid) && (srv == tcon->ses->server)) { + read_lock(&cifs_tcp_ses_lock); + list_for_each(tmp, &srv->smb_ses_list) { + ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); + list_for_each(tmp1, &ses->tcon_list) { + tcon = list_entry(tmp1, struct cifsTconInfo, tcon_list); + if (tcon->tid != buf->Tid) + continue; + cifs_stats_inc(&tcon->num_oplock_brks); - list_for_each(tmp1, &tcon->openFileList) { - netfile = list_entry(tmp1, struct cifsFileInfo, + list_for_each(tmp2, &tcon->openFileList) { + netfile = list_entry(tmp2, struct cifsFileInfo, tlist); - if (pSMB->Fid == netfile->netfid) { - struct cifsInodeInfo *pCifsInode; - read_unlock(&GlobalSMBSeslock); - cFYI(1, - ("file id match, oplock break")); - pCifsInode = - CIFS_I(netfile->pInode); - pCifsInode->clientCanCacheAll = false; - if (pSMB->OplockLevel == 0) - pCifsInode->clientCanCacheRead - = false; - pCifsInode->oplockPending = true; - AllocOplockQEntry(netfile->pInode, - netfile->netfid, - tcon); - cFYI(1, - ("about to wake up oplock thread")); - if (oplockThread) - wake_up_process(oplockThread); - return true; - } + if (pSMB->Fid != netfile->netfid) + continue; + + read_unlock(&cifs_tcp_ses_lock); + cFYI(1, ("file id match, oplock break")); + pCifsInode = CIFS_I(netfile->pInode); + pCifsInode->clientCanCacheAll = false; + if (pSMB->OplockLevel == 0) + pCifsInode->clientCanCacheRead = false; + pCifsInode->oplockPending = true; + AllocOplockQEntry(netfile->pInode, + netfile->netfid, tcon); + cFYI(1, ("about to wake up oplock thread")); + if (oplockThread) + wake_up_process(oplockThread); + + return true; } - read_unlock(&GlobalSMBSeslock); + read_unlock(&cifs_tcp_ses_lock); cFYI(1, ("No matching file for oplock break")); return true; } } - read_unlock(&GlobalSMBSeslock); + read_unlock(&cifs_tcp_ses_lock); cFYI(1, ("Can not process oplock break for non-existent connection")); return true; } --- linux-2.6.27.orig/fs/cifs/README +++ linux-2.6.27/fs/cifs/README @@ -463,6 +463,9 @@ with cifs style mandatory byte range locks (and most cifs servers do not yet support requesting advisory byte range locks). + nodfs Disable DFS (global name space support) even if the + server claims to support it. This can help work around + a problem with parsing of DFS paths with Samba 3.0.24 server. remount remount the share (often used to change from ro to rw mounts or vice versa) cifsacl Report mode bits (e.g. on stat) based on the Windows ACL for --- linux-2.6.27.orig/fs/cifs/readdir.c +++ linux-2.6.27/fs/cifs/readdir.c @@ -640,6 +640,70 @@ } +static int cifs_save_resume_key(const char *current_entry, + struct cifsFileInfo *cifsFile) +{ + int rc = 0; + unsigned int len = 0; + __u16 level; + char *filename; + + if ((cifsFile == NULL) || (current_entry == NULL)) + return -EINVAL; + + level = cifsFile->srch_inf.info_level; + + if (level == SMB_FIND_FILE_UNIX) { + FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry; + + filename = &pFindData->FileName[0]; + if (cifsFile->srch_inf.unicode) { + len = cifs_unicode_bytelen(filename); + } else { + /* BB should we make this strnlen of PATH_MAX? */ + len = strnlen(filename, PATH_MAX); + } + cifsFile->srch_inf.resume_key = pFindData->ResumeKey; + } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) { + FILE_DIRECTORY_INFO *pFindData = + (FILE_DIRECTORY_INFO *)current_entry; + filename = &pFindData->FileName[0]; + len = le32_to_cpu(pFindData->FileNameLength); + cifsFile->srch_inf.resume_key = pFindData->FileIndex; + } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) { + FILE_FULL_DIRECTORY_INFO *pFindData = + (FILE_FULL_DIRECTORY_INFO *)current_entry; + filename = &pFindData->FileName[0]; + len = le32_to_cpu(pFindData->FileNameLength); + cifsFile->srch_inf.resume_key = pFindData->FileIndex; + } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) { + SEARCH_ID_FULL_DIR_INFO *pFindData = + (SEARCH_ID_FULL_DIR_INFO *)current_entry; + filename = &pFindData->FileName[0]; + len = le32_to_cpu(pFindData->FileNameLength); + cifsFile->srch_inf.resume_key = pFindData->FileIndex; + } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { + FILE_BOTH_DIRECTORY_INFO *pFindData = + (FILE_BOTH_DIRECTORY_INFO *)current_entry; + filename = &pFindData->FileName[0]; + len = le32_to_cpu(pFindData->FileNameLength); + cifsFile->srch_inf.resume_key = pFindData->FileIndex; + } else if (level == SMB_FIND_FILE_INFO_STANDARD) { + FIND_FILE_STANDARD_INFO *pFindData = + (FIND_FILE_STANDARD_INFO *)current_entry; + filename = &pFindData->FileName[0]; + /* one byte length, no name conversion */ + len = (unsigned int)pFindData->FileNameLength; + cifsFile->srch_inf.resume_key = pFindData->ResumeKey; + } else { + cFYI(1, ("Unknown findfirst level %d", level)); + return -EINVAL; + } + cifsFile->srch_inf.resume_name_len = len; + cifsFile->srch_inf.presume_name = filename; + return rc; +} + /* find the corresponding entry in the search */ /* Note that the SMB server returns search entries for . and .. which complicates logic here if we choose to parse for them and we do not @@ -698,6 +762,7 @@ rc)); return rc; } + cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile); } while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && @@ -705,6 +770,7 @@ cFYI(1, ("calling findnext2")); rc = CIFSFindNext(xid, pTcon, cifsFile->netfid, &cifsFile->srch_inf); + cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile); if (rc) return -ENOENT; } @@ -919,69 +985,6 @@ return rc; } -static int cifs_save_resume_key(const char *current_entry, - struct cifsFileInfo *cifsFile) -{ - int rc = 0; - unsigned int len = 0; - __u16 level; - char *filename; - - if ((cifsFile == NULL) || (current_entry == NULL)) - return -EINVAL; - - level = cifsFile->srch_inf.info_level; - - if (level == SMB_FIND_FILE_UNIX) { - FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry; - - filename = &pFindData->FileName[0]; - if (cifsFile->srch_inf.unicode) { - len = cifs_unicode_bytelen(filename); - } else { - /* BB should we make this strnlen of PATH_MAX? */ - len = strnlen(filename, PATH_MAX); - } - cifsFile->srch_inf.resume_key = pFindData->ResumeKey; - } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) { - FILE_DIRECTORY_INFO *pFindData = - (FILE_DIRECTORY_INFO *)current_entry; - filename = &pFindData->FileName[0]; - len = le32_to_cpu(pFindData->FileNameLength); - cifsFile->srch_inf.resume_key = pFindData->FileIndex; - } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) { - FILE_FULL_DIRECTORY_INFO *pFindData = - (FILE_FULL_DIRECTORY_INFO *)current_entry; - filename = &pFindData->FileName[0]; - len = le32_to_cpu(pFindData->FileNameLength); - cifsFile->srch_inf.resume_key = pFindData->FileIndex; - } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) { - SEARCH_ID_FULL_DIR_INFO *pFindData = - (SEARCH_ID_FULL_DIR_INFO *)current_entry; - filename = &pFindData->FileName[0]; - len = le32_to_cpu(pFindData->FileNameLength); - cifsFile->srch_inf.resume_key = pFindData->FileIndex; - } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { - FILE_BOTH_DIRECTORY_INFO *pFindData = - (FILE_BOTH_DIRECTORY_INFO *)current_entry; - filename = &pFindData->FileName[0]; - len = le32_to_cpu(pFindData->FileNameLength); - cifsFile->srch_inf.resume_key = pFindData->FileIndex; - } else if (level == SMB_FIND_FILE_INFO_STANDARD) { - FIND_FILE_STANDARD_INFO *pFindData = - (FIND_FILE_STANDARD_INFO *)current_entry; - filename = &pFindData->FileName[0]; - /* one byte length, no name conversion */ - len = (unsigned int)pFindData->FileNameLength; - cifsFile->srch_inf.resume_key = pFindData->ResumeKey; - } else { - cFYI(1, ("Unknown findfirst level %d", level)); - return -EINVAL; - } - cifsFile->srch_inf.resume_name_len = len; - cifsFile->srch_inf.presume_name = filename; - return rc; -} int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) { @@ -1072,7 +1075,7 @@ with the rare long characters alloc more to account for such multibyte target UTF-8 characters. cifs_unicode.c, which actually does the conversion, has the same limit */ - tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL); + tmp_buf = kmalloc((4 * NAME_MAX) + 2, GFP_KERNEL); for (i = 0; (i < num_to_fill) && (rc == 0); i++) { if (current_entry == NULL) { /* evaluate whether this case is an error */ --- linux-2.6.27.orig/fs/cifs/CHANGES +++ linux-2.6.27/fs/cifs/CHANGES @@ -1,3 +1,7 @@ +Fix "redzone overwritten" bug in cifs_put_tcon (CIFSTcon may allocate too +little memory for the "nativeFileSystem" field returned by the server +during mount). + Version 1.54 ------------ Fix premature write failure on congested networks (we would give up --- linux-2.6.27.orig/fs/cifs/transport.c +++ linux-2.6.27/fs/cifs/transport.c @@ -162,7 +162,7 @@ int smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, - unsigned int smb_buf_length, struct sockaddr *sin) + unsigned int smb_buf_length, struct sockaddr *sin, bool noblocksnd) { int rc = 0; int i = 0; @@ -179,7 +179,10 @@ smb_msg.msg_namelen = sizeof(struct sockaddr); smb_msg.msg_control = NULL; smb_msg.msg_controllen = 0; - smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ + if (noblocksnd) + smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; + else + smb_msg.msg_flags = MSG_NOSIGNAL; /* smb header is converted in header_assemble. bcc and rest of SMB word area, and byte area if necessary, is converted to littleendian in @@ -230,8 +233,8 @@ } static int -smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, - struct sockaddr *sin) +smb_send2(struct TCP_Server_Info *server, struct kvec *iov, int n_vec, + struct sockaddr *sin, bool noblocksnd) { int rc = 0; int i = 0; @@ -241,6 +244,7 @@ unsigned int total_len; int first_vec = 0; unsigned int smb_buf_length = smb_buffer->smb_buf_length; + struct socket *ssocket = server->ssocket; if (ssocket == NULL) return -ENOTSOCK; /* BB eventually add reconnect code here */ @@ -249,7 +253,10 @@ smb_msg.msg_namelen = sizeof(struct sockaddr); smb_msg.msg_control = NULL; smb_msg.msg_controllen = 0; - smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ + if (noblocksnd) + smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; + else + smb_msg.msg_flags = MSG_NOSIGNAL; /* smb header is converted in header_assemble. bcc and rest of SMB word area, and byte area if necessary, is converted to littleendian in @@ -284,8 +291,11 @@ if (rc < 0) break; - if (rc >= total_len) { - WARN_ON(rc > total_len); + if (rc == total_len) { + total_len = 0; + break; + } else if (rc > total_len) { + cERROR(1, ("sent %d requested %d", rc, total_len)); break; } if (rc == 0) { @@ -313,6 +323,16 @@ i = 0; /* in case we get ENOSPC on the next send */ } + if ((total_len > 0) && (total_len != smb_buf_length + 4)) { + cFYI(1, ("partial send (%d remaining), terminating session", + total_len)); + /* If we have only sent part of an SMB then the next SMB + could be taken as the remainder of this one. We need + to kill the socket so the server throws away the partial + SMB */ + server->tcpStatus = CifsNeedReconnect; + } + if (rc < 0) { cERROR(1, ("Error %d sending data on socket to server", rc)); } else @@ -519,8 +539,9 @@ #ifdef CONFIG_CIFS_STATS2 atomic_inc(&ses->server->inSend); #endif - rc = smb_send2(ses->server->ssocket, iov, n_vec, - (struct sockaddr *) &(ses->server->addr.sockAddr)); + rc = smb_send2(ses->server, iov, n_vec, + (struct sockaddr *) &(ses->server->addr.sockAddr), + ses->server->noblocksnd); #ifdef CONFIG_CIFS_STATS2 atomic_dec(&ses->server->inSend); midQ->when_sent = jiffies; @@ -712,7 +733,8 @@ atomic_inc(&ses->server->inSend); #endif rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, - (struct sockaddr *) &(ses->server->addr.sockAddr)); + (struct sockaddr *) &(ses->server->addr.sockAddr), + ses->server->noblocksnd); #ifdef CONFIG_CIFS_STATS2 atomic_dec(&ses->server->inSend); midQ->when_sent = jiffies; @@ -852,7 +874,8 @@ return rc; } rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, - (struct sockaddr *) &(ses->server->addr.sockAddr)); + (struct sockaddr *) &(ses->server->addr.sockAddr), + ses->server->noblocksnd); up(&ses->server->tcpSem); return rc; } @@ -942,7 +965,8 @@ atomic_inc(&ses->server->inSend); #endif rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, - (struct sockaddr *) &(ses->server->addr.sockAddr)); + (struct sockaddr *) &(ses->server->addr.sockAddr), + ses->server->noblocksnd); #ifdef CONFIG_CIFS_STATS2 atomic_dec(&ses->server->inSend); midQ->when_sent = jiffies; --- linux-2.6.27.orig/fs/cifs/file.c +++ linux-2.6.27/fs/cifs/file.c @@ -493,7 +493,7 @@ if (pTcon) { /* no sense reconnecting to close a file that is already closed */ - if (pTcon->tidStatus != CifsNeedReconnect) { + if (!pTcon->need_reconnect) { timeout = 2; while ((atomic_read(&pSMBFile->wrtPending) != 0) && (timeout <= 2048)) { @@ -1396,7 +1396,10 @@ if ((wbc->nr_to_write -= n_iov) <= 0) done = 1; index = next; - } + } else + /* Need to re-find the pages we skipped */ + index = pvec.pages[0]->index + 1; + pagevec_release(&pvec); } if (!scanned && !done) { @@ -1813,7 +1816,7 @@ pTcon = cifs_sb->tcon; pagevec_init(&lru_pvec, 0); - cFYI(DBG2, ("rpages: num pages %d", num_pages)); + cFYI(DBG2, ("rpages: num pages %d", num_pages)); for (i = 0; i < num_pages; ) { unsigned contig_pages; struct page *tmp_page; --- linux-2.6.27.orig/fs/cifs/sess.c +++ linux-2.6.27/fs/cifs/sess.c @@ -202,27 +202,26 @@ int words_left, len; char *data = *pbcc_area; - - cFYI(1, ("bleft %d", bleft)); - - /* SMB header is unaligned, so cifs servers word align start of - Unicode strings */ - data++; - bleft--; /* Windows servers do not always double null terminate - their final Unicode string - in which case we - now will not attempt to decode the byte of junk - which follows it */ + /* + * Windows servers do not always double null terminate their final + * Unicode string. Check to see if there are an uneven number of bytes + * left. If so, then add an extra NULL pad byte to the end of the + * response. + * + * See section 2.7.2 in "Implementing CIFS" for details + */ + if (bleft % 2) { + data[bleft] = 0; + ++bleft; + } words_left = bleft / 2; /* save off server operating system */ len = UniStrnlen((wchar_t *) data, words_left); -/* We look for obvious messed up bcc or strings in response so we do not go off - the end since (at least) WIN2K and Windows XP have a major bug in not null - terminating last Unicode string in response */ if (len >= words_left) return rc; @@ -260,13 +259,10 @@ return rc; kfree(ses->serverDomain); - ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */ - if (ses->serverDomain != NULL) { + ses->serverDomain = kzalloc((4 * len) + 2, GFP_KERNEL); + if (ses->serverDomain != NULL) cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, nls_cp); - ses->serverDomain[2*len] = 0; - ses->serverDomain[(2*len) + 1] = 0; - } data += 2 * (len + 1); words_left -= len + 1; @@ -616,12 +612,18 @@ } /* BB check if Unicode and decode strings */ - if (smb_buf->Flags2 & SMBFLG2_UNICODE) + if (smb_buf->Flags2 & SMBFLG2_UNICODE) { + /* unicode string area must be word-aligned */ + if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) { + ++bcc_ptr; + --bytes_remaining; + } rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining, - ses, nls_cp); - else + ses, nls_cp); + } else { rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, nls_cp); + } ssetup_exit: if (spnego_key) --- linux-2.6.27.orig/fs/cifs/cifsglob.h +++ linux-2.6.27/fs/cifs/cifsglob.h @@ -85,8 +85,7 @@ }; enum protocolEnum { - IPV4 = 0, - IPV6, + TCP = 0, SCTP /* Netbios frames protocol not supported at this time */ }; @@ -122,6 +121,9 @@ */ struct TCP_Server_Info { + struct list_head tcp_ses_list; + struct list_head smb_ses_list; + int srv_count; /* reference counter */ /* 15 character server name + 0x20 16th byte indicating type = srv */ char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; @@ -141,7 +143,8 @@ char versionMajor; char versionMinor; bool svlocal:1; /* local server or remote */ - atomic_t socketUseCount; /* number of open cifs sessions on socket */ + bool noblocksnd; /* use blocking sendmsg */ + bool noautotune; /* do not autotune send buf sizes */ atomic_t inFlight; /* number of requests on the wire to server */ #ifdef CONFIG_CIFS_STATS2 atomic_t inSend; /* requests trying to send */ @@ -192,13 +195,14 @@ * Session structure. One of these for each uid session with a particular host */ struct cifsSesInfo { - struct list_head cifsSessionList; + struct list_head smb_ses_list; + struct list_head tcon_list; struct semaphore sesSem; #if 0 struct cifsUidInfo *uidInfo; /* pointer to user info */ #endif struct TCP_Server_Info *server; /* pointer to server info */ - atomic_t inUse; /* # of mounts (tree connections) on this ses */ + int ses_count; /* reference counter */ enum statusEnum status; unsigned overrideSecFlg; /* if non-zero override global sec flags */ __u16 ipc_tid; /* special tid for connection to IPC share */ @@ -214,6 +218,7 @@ char userName[MAX_USERNAME_SIZE + 1]; char *domainName; char *password; + bool need_reconnect:1; /* connection reset, uid now invalid */ }; /* no more than one of the following three session flags may be set */ #define CIFS_SES_NT4 1 @@ -228,16 +233,15 @@ * session */ struct cifsTconInfo { - struct list_head cifsConnectionList; + struct list_head tcon_list; + int tc_count; struct list_head openFileList; - struct semaphore tconSem; struct cifsSesInfo *ses; /* pointer to session associated with */ char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */ char *nativeFileSystem; __u16 tid; /* The 2 byte tree id */ __u16 Flags; /* optional support bits */ enum statusEnum tidStatus; - atomic_t useCount; /* how many explicit/implicit mounts to share */ #ifdef CONFIG_CIFS_STATS atomic_t num_smbs_sent; atomic_t num_writes; @@ -285,6 +289,7 @@ bool seal:1; /* transport encryption for this mounted share */ bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol for this mount even if server would support */ + bool need_reconnect:1; /* connection reset, tid now invalid */ /* BB add field for back pointer to sb struct(s)? */ }; @@ -309,6 +314,7 @@ __u32 resume_key; char *ntwrk_buf_start; char *srch_entries_start; + char *last_entry; char *presume_name; unsigned int resume_name_len; bool endOfSearch:1; @@ -583,21 +589,21 @@ #endif /* - * The list of servers that did not respond with NT LM 0.12. - * This list helps improve performance and eliminate the messages indicating - * that we had a communications error talking to the server in this list. + * the list of TCP_Server_Info structures, ie each of the sockets + * connecting our client to a distinct server (ip address), is + * chained together by cifs_tcp_ses_list. The list of all our SMB + * sessions (and from that the tree connections) can be found + * by iterating over cifs_tcp_ses_list */ -/* Feature not supported */ -/* GLOBAL_EXTERN struct servers_not_supported *NotSuppList; */ +GLOBAL_EXTERN struct list_head cifs_tcp_ses_list; /* - * The following is a hash table of all the users we know about. + * This lock protects the cifs_tcp_ses_list, the list of smb sessions per + * tcp session, and the list of tcon's per smb session. It also protects + * the reference counters for the server, smb session, and tcon. Finally, + * changes to the tcon->tidStatus should be done while holding this lock. */ -GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH]; - -/* GLOBAL_EXTERN struct list_head GlobalServerList; BB not implemented yet */ -GLOBAL_EXTERN struct list_head GlobalSMBSessionList; -GLOBAL_EXTERN struct list_head GlobalTreeConnectionList; +GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock; GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ GLOBAL_EXTERN struct list_head GlobalOplock_Q; --- linux-2.6.27.orig/fs/cifs/cifsfs.c +++ linux-2.6.27/fs/cifs/cifsfs.c @@ -510,10 +510,11 @@ tcon = cifs_sb->tcon; if (tcon == NULL) return; - down(&tcon->tconSem); - if (atomic_read(&tcon->useCount) == 1) + + read_lock(&cifs_tcp_ses_lock); + if (tcon->tc_count == 1) tcon->tidStatus = CifsExiting; - up(&tcon->tconSem); + read_unlock(&cifs_tcp_ses_lock); /* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */ /* cancel_notify_requests(tcon); */ @@ -967,7 +968,7 @@ not bother sending an oplock release if session to server still is disconnected since oplock already released by the server in that case */ - if (pTcon->tidStatus != CifsNeedReconnect) { + if (!pTcon->need_reconnect) { rc = CIFSSMBLock(0, pTcon, netfid, 0 /* len */ , 0 /* offset */, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, @@ -985,24 +986,24 @@ static int cifs_dnotify_thread(void *dummyarg) { struct list_head *tmp; - struct cifsSesInfo *ses; + struct TCP_Server_Info *server; do { if (try_to_freeze()) continue; set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(15*HZ); - read_lock(&GlobalSMBSeslock); /* check if any stuck requests that need to be woken up and wakeq so the thread can wake up and error out */ - list_for_each(tmp, &GlobalSMBSessionList) { - ses = list_entry(tmp, struct cifsSesInfo, - cifsSessionList); - if (ses->server && atomic_read(&ses->server->inFlight)) - wake_up_all(&ses->server->response_q); + read_lock(&cifs_tcp_ses_lock); + list_for_each(tmp, &cifs_tcp_ses_list) { + server = list_entry(tmp, struct TCP_Server_Info, + tcp_ses_list); + if (atomic_read(&server->inFlight)) + wake_up_all(&server->response_q); } - read_unlock(&GlobalSMBSeslock); + read_unlock(&cifs_tcp_ses_lock); } while (!kthread_should_stop()); return 0; @@ -1013,9 +1014,7 @@ { int rc = 0; cifs_proc_init(); -/* INIT_LIST_HEAD(&GlobalServerList);*/ /* BB not implemented yet */ - INIT_LIST_HEAD(&GlobalSMBSessionList); - INIT_LIST_HEAD(&GlobalTreeConnectionList); + INIT_LIST_HEAD(&cifs_tcp_ses_list); INIT_LIST_HEAD(&GlobalOplock_Q); #ifdef CONFIG_CIFS_EXPERIMENTAL INIT_LIST_HEAD(&GlobalDnotifyReqList); @@ -1043,6 +1042,7 @@ GlobalMaxActiveXid = 0; memset(Local_System_Name, 0, 15); rwlock_init(&GlobalSMBSeslock); + rwlock_init(&cifs_tcp_ses_lock); spin_lock_init(&GlobalMid_Lock); if (cifs_max_pending < 2) { --- linux-2.6.27.orig/fs/cifs/connect.c +++ linux-2.6.27/fs/cifs/connect.c @@ -90,6 +90,9 @@ bool nocase:1; /* request case insensitive filenames */ bool nobrl:1; /* disable sending byte range locks to srv */ bool seal:1; /* request transport encryption on share */ + bool nodfs:1; + bool noblocksnd:1; + bool noautotune:1; unsigned int rsize; unsigned int wsize; unsigned int sockopt; @@ -100,9 +103,11 @@ static int ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, char *netb_name, - char *server_netb_name); + char *server_netb_name, + bool noblocksnd, + bool nosndbuf); /* ipv6 never set sndbuf size */ static int ipv6_connect(struct sockaddr_in6 *psin_server, - struct socket **csocket); + struct socket **csocket, bool noblocksnd); /* @@ -118,13 +123,13 @@ cifs_reconnect(struct TCP_Server_Info *server) { int rc = 0; - struct list_head *tmp; + struct list_head *tmp, *tmp2; struct cifsSesInfo *ses; struct cifsTconInfo *tcon; struct mid_q_entry *mid_entry; spin_lock(&GlobalMid_Lock); - if (kthread_should_stop()) { + if (server->tcpStatus == CifsExiting) { /* the demux thread will exit normally next time through the loop */ spin_unlock(&GlobalMid_Lock); @@ -138,23 +143,17 @@ /* before reconnecting the tcp session, mark the smb session (uid) and the tid bad so they are not used until reconnected */ - read_lock(&GlobalSMBSeslock); - list_for_each(tmp, &GlobalSMBSessionList) { - ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); - if (ses->server) { - if (ses->server == server) { - ses->status = CifsNeedReconnect; - ses->ipc_tid = 0; - } - } - /* else tcp and smb sessions need reconnection */ - } - list_for_each(tmp, &GlobalTreeConnectionList) { - tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); - if ((tcon->ses) && (tcon->ses->server == server)) - tcon->tidStatus = CifsNeedReconnect; + read_lock(&cifs_tcp_ses_lock); + list_for_each(tmp, &server->smb_ses_list) { + ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); + ses->need_reconnect = true; + ses->ipc_tid = 0; + list_for_each(tmp2, &ses->tcon_list) { + tcon = list_entry(tmp2, struct cifsTconInfo, tcon_list); + tcon->need_reconnect = true; + } } - read_unlock(&GlobalSMBSeslock); + read_unlock(&cifs_tcp_ses_lock); /* do not want to be sending data on a socket we are freeing */ down(&server->tcpSem); if (server->ssocket) { @@ -184,16 +183,18 @@ spin_unlock(&GlobalMid_Lock); up(&server->tcpSem); - while ((!kthread_should_stop()) && (server->tcpStatus != CifsGood)) { + while ((server->tcpStatus != CifsExiting) && + (server->tcpStatus != CifsGood)) { try_to_freeze(); - if (server->protocolType == IPV6) { + if (server->addr.sockAddr6.sin6_family == AF_INET6) { rc = ipv6_connect(&server->addr.sockAddr6, - &server->ssocket); + &server->ssocket, server->noautotune); } else { rc = ipv4_connect(&server->addr.sockAddr, &server->ssocket, server->workstation_RFC1001_name, - server->server_RFC1001_name); + server->server_RFC1001_name, + server->noblocksnd, server->noautotune); } if (rc) { cFYI(1, ("reconnect error %d", rc)); @@ -201,7 +202,7 @@ } else { atomic_inc(&tcpSesReconnectCount); spin_lock(&GlobalMid_Lock); - if (!kthread_should_stop()) + if (server->tcpStatus != CifsExiting) server->tcpStatus = CifsGood; server->sequence_number = 0; spin_unlock(&GlobalMid_Lock); @@ -356,7 +357,7 @@ GFP_KERNEL); set_freezable(); - while (!kthread_should_stop()) { + while (server->tcpStatus != CifsExiting) { if (try_to_freeze()) continue; if (bigbuf == NULL) { @@ -397,7 +398,7 @@ kernel_recvmsg(csocket, &smb_msg, &iov, 1, pdu_length, 0 /* BB other flags? */); - if (kthread_should_stop()) { + if (server->tcpStatus == CifsExiting) { break; } else if (server->tcpStatus == CifsNeedReconnect) { cFYI(1, ("Reconnect after server stopped responding")); @@ -409,8 +410,14 @@ msleep(1); /* minimum sleep to prevent looping allowing socket to clear and app threads to set tcpStatus CifsNeedReconnect if server hung */ - if (pdu_length < 4) + if (pdu_length < 4) { + iov.iov_base = (4 - pdu_length) + + (char *)smb_buffer; + iov.iov_len = pdu_length; + smb_msg.msg_control = NULL; + smb_msg.msg_controllen = 0; goto incomplete_rcv; + } else continue; } else if (length <= 0) { @@ -522,7 +529,7 @@ total_read += length) { length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, pdu_length - total_read, 0); - if (kthread_should_stop() || + if ((server->tcpStatus == CifsExiting) || (length == -EINTR)) { /* then will exit */ reconnect = 2; @@ -646,19 +653,16 @@ } } /* end while !EXITING */ + /* take it off the list, if it's not already */ + write_lock(&cifs_tcp_ses_lock); + list_del_init(&server->tcp_ses_list); + write_unlock(&cifs_tcp_ses_lock); + spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsExiting; spin_unlock(&GlobalMid_Lock); wake_up_all(&server->response_q); - /* don't exit until kthread_stop is called */ - set_current_state(TASK_UNINTERRUPTIBLE); - while (!kthread_should_stop()) { - schedule(); - set_current_state(TASK_UNINTERRUPTIBLE); - } - set_current_state(TASK_RUNNING); - /* check if we have blocked requests that need to free */ /* Note that cifs_max_pending is normally 50, but can be set at module install time to as little as two */ @@ -686,29 +690,29 @@ if (smallbuf) /* no sense logging a debug message if NULL */ cifs_small_buf_release(smallbuf); - read_lock(&GlobalSMBSeslock); + /* + * BB: we shouldn't have to do any of this. It shouldn't be + * possible to exit from the thread with active SMB sessions + */ + read_lock(&cifs_tcp_ses_lock); if (list_empty(&server->pending_mid_q)) { /* loop through server session structures attached to this and mark them dead */ - list_for_each(tmp, &GlobalSMBSessionList) { - ses = - list_entry(tmp, struct cifsSesInfo, - cifsSessionList); - if (ses->server == server) { - ses->status = CifsExiting; - ses->server = NULL; - } + list_for_each(tmp, &server->smb_ses_list) { + ses = list_entry(tmp, struct cifsSesInfo, + smb_ses_list); + ses->status = CifsExiting; + ses->server = NULL; } - read_unlock(&GlobalSMBSeslock); + read_unlock(&cifs_tcp_ses_lock); } else { /* although we can not zero the server struct pointer yet, since there are active requests which may depnd on them, mark the corresponding SMB sessions as exiting too */ - list_for_each(tmp, &GlobalSMBSessionList) { + list_for_each(tmp, &server->smb_ses_list) { ses = list_entry(tmp, struct cifsSesInfo, - cifsSessionList); - if (ses->server == server) - ses->status = CifsExiting; + smb_ses_list); + ses->status = CifsExiting; } spin_lock(&GlobalMid_Lock); @@ -723,7 +727,7 @@ } } spin_unlock(&GlobalMid_Lock); - read_unlock(&GlobalSMBSeslock); + read_unlock(&cifs_tcp_ses_lock); /* 1/8th of sec is more than enough time for them to exit */ msleep(125); } @@ -745,16 +749,16 @@ if there are any pointing to this (e.g if a crazy root user tried to kill cifsd kernel thread explicitly this might happen) */ - write_lock(&GlobalSMBSeslock); - list_for_each(tmp, &GlobalSMBSessionList) { - ses = list_entry(tmp, struct cifsSesInfo, - cifsSessionList); - if (ses->server == server) - ses->server = NULL; + /* BB: This shouldn't be necessary, see above */ + read_lock(&cifs_tcp_ses_lock); + list_for_each(tmp, &server->smb_ses_list) { + ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); + ses->server = NULL; } - write_unlock(&GlobalSMBSeslock); + read_unlock(&cifs_tcp_ses_lock); kfree(server->hostname); + task_to_wake = xchg(&server->tsk, NULL); kfree(server); length = atomic_dec_return(&tcpSesAllocCount); @@ -762,6 +766,16 @@ mempool_resize(cifs_req_poolp, length + cifs_min_rcv, GFP_KERNEL); + /* if server->tsk was NULL then wait for a signal before exiting */ + if (!task_to_wake) { + set_current_state(TASK_INTERRUPTIBLE); + while (!signal_pending(current)) { + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + } + set_current_state(TASK_RUNNING); + } + return 0; } @@ -1186,6 +1200,10 @@ /* ignore */ } else if (strnicmp(data, "rw", 2) == 0) { vol->rw = true; + } else if (strnicmp(data, "noblocksnd", 11) == 0) { + vol->noblocksnd = true; + } else if (strnicmp(data, "noautotune", 10) == 0) { + vol->noautotune = true; } else if ((strnicmp(data, "suid", 4) == 0) || (strnicmp(data, "nosuid", 6) == 0) || (strnicmp(data, "exec", 4) == 0) || @@ -1218,6 +1236,8 @@ vol->sfu_emul = 1; } else if (strnicmp(data, "nosfu", 5) == 0) { vol->sfu_emul = 0; + } else if (strnicmp(data, "nodfs", 5) == 0) { + vol->nodfs = 1; } else if (strnicmp(data, "posixpaths", 10) == 0) { vol->posix_paths = 1; } else if (strnicmp(data, "noposixpaths", 12) == 0) { @@ -1331,94 +1351,158 @@ return 0; } -static struct cifsSesInfo * -cifs_find_tcp_session(struct in_addr *target_ip_addr, - struct in6_addr *target_ip6_addr, - char *userName, struct TCP_Server_Info **psrvTcp) +static struct TCP_Server_Info * +cifs_find_tcp_session(struct sockaddr_storage *addr) { struct list_head *tmp; - struct cifsSesInfo *ses; - - *psrvTcp = NULL; + struct TCP_Server_Info *server; + struct sockaddr_in *addr4 = (struct sockaddr_in *) addr; + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr; + + write_lock(&cifs_tcp_ses_lock); + list_for_each(tmp, &cifs_tcp_ses_list) { + server = list_entry(tmp, struct TCP_Server_Info, + tcp_ses_list); + /* + * the demux thread can exit on its own while still in CifsNew + * so don't accept any sockets in that state. Since the + * tcpStatus never changes back to CifsNew it's safe to check + * for this without a lock. + */ + if (server->tcpStatus == CifsNew) + continue; - read_lock(&GlobalSMBSeslock); - list_for_each(tmp, &GlobalSMBSessionList) { - ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); - if (!ses->server) + if (addr->ss_family == AF_INET && + (addr4->sin_addr.s_addr != + server->addr.sockAddr.sin_addr.s_addr)) + continue; + else if (addr->ss_family == AF_INET6 && + memcmp(&server->addr.sockAddr6.sin6_addr, + &addr6->sin6_addr, sizeof(addr6->sin6_addr))) continue; - if (target_ip_addr && - ses->server->addr.sockAddr.sin_addr.s_addr != target_ip_addr->s_addr) - continue; - else if (target_ip6_addr && - memcmp(&ses->server->addr.sockAddr6.sin6_addr, - target_ip6_addr, sizeof(*target_ip6_addr))) - continue; - /* BB lock server and tcp session; increment use count here?? */ + ++server->srv_count; + write_unlock(&cifs_tcp_ses_lock); + cFYI(1, ("Existing tcp session with server found")); + return server; + } + write_unlock(&cifs_tcp_ses_lock); + return NULL; +} - /* found a match on the TCP session */ - *psrvTcp = ses->server; +static void +cifs_put_tcp_session(struct TCP_Server_Info *server) +{ + struct task_struct *task; - /* BB check if reconnection needed */ - if (strncmp(ses->userName, userName, MAX_USERNAME_SIZE) == 0) { - read_unlock(&GlobalSMBSeslock); - /* Found exact match on both TCP and - SMB sessions */ - return ses; - } - /* else tcp and smb sessions need reconnection */ + write_lock(&cifs_tcp_ses_lock); + if (--server->srv_count > 0) { + write_unlock(&cifs_tcp_ses_lock); + return; } - read_unlock(&GlobalSMBSeslock); - return NULL; + list_del_init(&server->tcp_ses_list); + write_unlock(&cifs_tcp_ses_lock); + + spin_lock(&GlobalMid_Lock); + server->tcpStatus = CifsExiting; + spin_unlock(&GlobalMid_Lock); + + task = xchg(&server->tsk, NULL); + if (task) + force_sig(SIGKILL, task); } -static struct cifsTconInfo * -find_unc(__be32 new_target_ip_addr, char *uncName, char *userName) +static struct cifsSesInfo * +cifs_find_smb_ses(struct TCP_Server_Info *server, char *username) { struct list_head *tmp; - struct cifsTconInfo *tcon; - __be32 old_ip; - - read_lock(&GlobalSMBSeslock); + struct cifsSesInfo *ses; - list_for_each(tmp, &GlobalTreeConnectionList) { - cFYI(1, ("Next tcon")); - tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); - if (!tcon->ses || !tcon->ses->server) + write_lock(&cifs_tcp_ses_lock); + list_for_each(tmp, &server->smb_ses_list) { + ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); + if (strncmp(ses->userName, username, MAX_USERNAME_SIZE)) continue; - old_ip = tcon->ses->server->addr.sockAddr.sin_addr.s_addr; - cFYI(1, ("old ip addr: %x == new ip %x ?", - old_ip, new_target_ip_addr)); + ++ses->ses_count; + write_unlock(&cifs_tcp_ses_lock); + return ses; + } + write_unlock(&cifs_tcp_ses_lock); + return NULL; +} - if (old_ip != new_target_ip_addr) - continue; +static void +cifs_put_smb_ses(struct cifsSesInfo *ses) +{ + int xid; + struct TCP_Server_Info *server = ses->server; - /* BB lock tcon, server, tcp session and increment use count? */ - /* found a match on the TCP session */ - /* BB check if reconnection needed */ - cFYI(1, ("IP match, old UNC: %s new: %s", - tcon->treeName, uncName)); + write_lock(&cifs_tcp_ses_lock); + if (--ses->ses_count > 0) { + write_unlock(&cifs_tcp_ses_lock); + return; + } - if (strncmp(tcon->treeName, uncName, MAX_TREE_SIZE)) - continue; + list_del_init(&ses->smb_ses_list); + write_unlock(&cifs_tcp_ses_lock); + + if (ses->status == CifsGood) { + xid = GetXid(); + CIFSSMBLogoff(xid, ses); + _FreeXid(xid); + } + sesInfoFree(ses); + cifs_put_tcp_session(server); +} - cFYI(1, ("and old usr: %s new: %s", - tcon->treeName, uncName)); +static struct cifsTconInfo * +cifs_find_tcon(struct cifsSesInfo *ses, const char *unc) +{ + struct list_head *tmp; + struct cifsTconInfo *tcon; - if (strncmp(tcon->ses->userName, userName, MAX_USERNAME_SIZE)) + write_lock(&cifs_tcp_ses_lock); + list_for_each(tmp, &ses->tcon_list) { + tcon = list_entry(tmp, struct cifsTconInfo, tcon_list); + if (tcon->tidStatus == CifsExiting) + continue; + if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE)) continue; - /* matched smb session (user name) */ - read_unlock(&GlobalSMBSeslock); + ++tcon->tc_count; + write_unlock(&cifs_tcp_ses_lock); return tcon; } - - read_unlock(&GlobalSMBSeslock); + write_unlock(&cifs_tcp_ses_lock); return NULL; } +static void +cifs_put_tcon(struct cifsTconInfo *tcon) +{ + int xid; + struct cifsSesInfo *ses = tcon->ses; + + write_lock(&cifs_tcp_ses_lock); + if (--tcon->tc_count > 0) { + write_unlock(&cifs_tcp_ses_lock); + return; + } + + list_del_init(&tcon->tcon_list); + write_unlock(&cifs_tcp_ses_lock); + + xid = GetXid(); + CIFSSMBTDis(xid, tcon); + _FreeXid(xid); + + DeleteTconOplockQEntries(tcon); + tconInfoFree(tcon); + cifs_put_smb_ses(ses); +} + int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, const struct nls_table *nls_codepage, unsigned int *pnum_referrals, @@ -1506,7 +1590,8 @@ static int ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, - char *netbios_name, char *target_name) + char *netbios_name, char *target_name, + bool noblocksnd, bool noautotune) { int rc = 0; int connected = 0; @@ -1578,11 +1663,15 @@ (*csocket)->sk->sk_sndbuf, (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo)); (*csocket)->sk->sk_rcvtimeo = 7 * HZ; + if (!noblocksnd) + (*csocket)->sk->sk_sndtimeo = 3 * HZ; /* make the bufsizes depend on wsize/rsize and max requests */ - if ((*csocket)->sk->sk_sndbuf < (200 * 1024)) - (*csocket)->sk->sk_sndbuf = 200 * 1024; - if ((*csocket)->sk->sk_rcvbuf < (140 * 1024)) - (*csocket)->sk->sk_rcvbuf = 140 * 1024; + if (noautotune) { + if ((*csocket)->sk->sk_sndbuf < (200 * 1024)) + (*csocket)->sk->sk_sndbuf = 200 * 1024; + if ((*csocket)->sk->sk_rcvbuf < (140 * 1024)) + (*csocket)->sk->sk_rcvbuf = 140 * 1024; + } /* send RFC1001 sessinit */ if (psin_server->sin_port == htons(RFC1001_PORT)) { @@ -1619,7 +1708,7 @@ /* sizeof RFC1002_SESSION_REQUEST with no scope */ smb_buf->smb_buf_length = 0x81000044; rc = smb_send(*csocket, smb_buf, 0x44, - (struct sockaddr *)psin_server); + (struct sockaddr *)psin_server, noblocksnd); kfree(ses_init_buf); msleep(1); /* RFC1001 layer in at least one server requires very short break before negprot @@ -1639,7 +1728,8 @@ } static int -ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) +ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket, + bool noblocksnd) { int rc = 0; int connected = 0; @@ -1708,6 +1798,8 @@ the default. sock_setsockopt not used because it expects user space buffer */ (*csocket)->sk->sk_rcvtimeo = 7 * HZ; + if (!noblocksnd) + (*csocket)->sk->sk_sndtimeo = 3 * HZ; return rc; } @@ -1845,19 +1937,104 @@ } } +static void setup_cifs_sb(struct smb_vol *pvolume_info, + struct cifs_sb_info *cifs_sb) +{ + if (pvolume_info->rsize > CIFSMaxBufSize) { + cERROR(1, ("rsize %d too large, using MaxBufSize", + pvolume_info->rsize)); + cifs_sb->rsize = CIFSMaxBufSize; + } else if ((pvolume_info->rsize) && + (pvolume_info->rsize <= CIFSMaxBufSize)) + cifs_sb->rsize = pvolume_info->rsize; + else /* default */ + cifs_sb->rsize = CIFSMaxBufSize; + + if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) { + cERROR(1, ("wsize %d too large, using 4096 instead", + pvolume_info->wsize)); + cifs_sb->wsize = 4096; + } else if (pvolume_info->wsize) + cifs_sb->wsize = pvolume_info->wsize; + else + cifs_sb->wsize = min_t(const int, + PAGEVEC_SIZE * PAGE_CACHE_SIZE, + 127*1024); + /* old default of CIFSMaxBufSize was too small now + that SMB Write2 can send multiple pages in kvec. + RFC1001 does not describe what happens when frame + bigger than 128K is sent so use that as max in + conjunction with 52K kvec constraint on arch with 4K + page size */ + + if (cifs_sb->rsize < 2048) { + cifs_sb->rsize = 2048; + /* Windows ME may prefer this */ + cFYI(1, ("readsize set to minimum: 2048")); + } + /* calculate prepath */ + cifs_sb->prepath = pvolume_info->prepath; + if (cifs_sb->prepath) { + cifs_sb->prepathlen = strlen(cifs_sb->prepath); + /* we can not convert the / to \ in the path + separators in the prefixpath yet because we do not + know (until reset_cifs_unix_caps is called later) + whether POSIX PATH CAP is available. We normalize + the / to \ after reset_cifs_unix_caps is called */ + pvolume_info->prepath = NULL; + } else + cifs_sb->prepathlen = 0; + cifs_sb->mnt_uid = pvolume_info->linux_uid; + cifs_sb->mnt_gid = pvolume_info->linux_gid; + cifs_sb->mnt_file_mode = pvolume_info->file_mode; + cifs_sb->mnt_dir_mode = pvolume_info->dir_mode; + cFYI(1, ("file mode: 0x%x dir mode: 0x%x", + cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode)); + + if (pvolume_info->noperm) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; + if (pvolume_info->setuids) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; + if (pvolume_info->server_ino) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; + if (pvolume_info->remap) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; + if (pvolume_info->no_xattr) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; + if (pvolume_info->sfu_emul) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; + if (pvolume_info->nobrl) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; + if (pvolume_info->cifs_acl) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; + if (pvolume_info->override_uid) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; + if (pvolume_info->override_gid) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; + if (pvolume_info->dynperm) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; + if (pvolume_info->direct_io) { + cFYI(1, ("mounting share using direct i/o")); + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; + } + + if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm)) + cERROR(1, ("mount option dynperm ignored if cifsacl " + "mount option supported")); +} + int cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, char *mount_data, const char *devname) { int rc = 0; int xid; - int address_type = AF_INET; struct socket *csocket = NULL; - struct sockaddr_in sin_server; - struct sockaddr_in6 sin_server6; + struct sockaddr_storage addr; + struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr; + struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr; struct smb_vol volume_info; struct cifsSesInfo *pSesInfo = NULL; - struct cifsSesInfo *existingCifsSes = NULL; struct cifsTconInfo *tcon = NULL; struct TCP_Server_Info *srvTcp = NULL; @@ -1865,6 +2042,7 @@ /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */ + memset(&addr, 0, sizeof(struct sockaddr_storage)); memset(&volume_info, 0, sizeof(struct smb_vol)); if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { rc = -EINVAL; @@ -1887,16 +2065,16 @@ if (volume_info.UNCip && volume_info.UNC) { rc = cifs_inet_pton(AF_INET, volume_info.UNCip, - &sin_server.sin_addr.s_addr); + &sin_server->sin_addr.s_addr); if (rc <= 0) { /* not ipv4 address, try ipv6 */ rc = cifs_inet_pton(AF_INET6, volume_info.UNCip, - &sin_server6.sin6_addr.in6_u); + &sin_server6->sin6_addr.in6_u); if (rc > 0) - address_type = AF_INET6; + addr.ss_family = AF_INET6; } else { - address_type = AF_INET; + addr.ss_family = AF_INET; } if (rc <= 0) { @@ -1936,38 +2114,25 @@ } } - if (address_type == AF_INET) - existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr, - NULL /* no ipv6 addr */, - volume_info.username, &srvTcp); - else if (address_type == AF_INET6) { - cFYI(1, ("looking for ipv6 address")); - existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */, - &sin_server6.sin6_addr, - volume_info.username, &srvTcp); - } else { - rc = -EINVAL; - goto out; - } - - if (srvTcp) { - cFYI(1, ("Existing tcp session with server found")); - } else { /* create socket */ - if (volume_info.port) - sin_server.sin_port = htons(volume_info.port); - else - sin_server.sin_port = 0; - if (address_type == AF_INET6) { + srvTcp = cifs_find_tcp_session(&addr); + if (!srvTcp) { /* create socket */ + if (addr.ss_family == AF_INET6) { cFYI(1, ("attempting ipv6 connect")); /* BB should we allow ipv6 on port 139? */ /* other OS never observed in Wild doing 139 with v6 */ - rc = ipv6_connect(&sin_server6, &csocket); - } else - rc = ipv4_connect(&sin_server, &csocket, - volume_info.source_rfc1001_name, - volume_info.target_rfc1001_name); + sin_server6->sin6_port = htons(volume_info.port); + rc = ipv6_connect(sin_server6, &csocket, + volume_info.noblocksnd); + } else { + sin_server->sin_port = htons(volume_info.port); + rc = ipv4_connect(sin_server, &csocket, + volume_info.source_rfc1001_name, + volume_info.target_rfc1001_name, + volume_info.noblocksnd, + volume_info.noautotune); + } if (rc < 0) { - cERROR(1, ("Error connecting to IPv4 socket. " + cERROR(1, ("Error connecting to socket. " "Aborting operation")); if (csocket != NULL) sock_release(csocket); @@ -1980,12 +2145,17 @@ sock_release(csocket); goto out; } else { - memcpy(&srvTcp->addr.sockAddr, &sin_server, - sizeof(struct sockaddr_in)); + srvTcp->noblocksnd = volume_info.noblocksnd; + srvTcp->noautotune = volume_info.noautotune; + if (addr.ss_family == AF_INET6) + memcpy(&srvTcp->addr.sockAddr6, sin_server6, + sizeof(struct sockaddr_in6)); + else + memcpy(&srvTcp->addr.sockAddr, sin_server, + sizeof(struct sockaddr_in)); atomic_set(&srvTcp->inFlight, 0); /* BB Add code for ipv6 case too */ srvTcp->ssocket = csocket; - srvTcp->protocolType = IPV4; srvTcp->hostname = extract_hostname(volume_info.UNC); if (IS_ERR(srvTcp->hostname)) { rc = PTR_ERR(srvTcp->hostname); @@ -2015,15 +2185,28 @@ memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name, 16); srvTcp->sequence_number = 0; + INIT_LIST_HEAD(&srvTcp->tcp_ses_list); + INIT_LIST_HEAD(&srvTcp->smb_ses_list); + ++srvTcp->srv_count; + write_lock(&cifs_tcp_ses_lock); + list_add(&srvTcp->tcp_ses_list, + &cifs_tcp_ses_list); + write_unlock(&cifs_tcp_ses_lock); } } - if (existingCifsSes) { - pSesInfo = existingCifsSes; + pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username); + if (pSesInfo) { cFYI(1, ("Existing smb sess found (status=%d)", pSesInfo->status)); + /* + * The existing SMB session already has a reference to srvTcp, + * so we can put back the extra one we got before + */ + cifs_put_tcp_session(srvTcp); + down(&pSesInfo->sesSem); - if (pSesInfo->status == CifsNeedReconnect) { + if (pSesInfo->need_reconnect) { cFYI(1, ("Session needs reconnect")); rc = cifs_setup_session(xid, pSesInfo, cifs_sb->local_nls); @@ -2032,180 +2215,100 @@ } else if (!rc) { cFYI(1, ("Existing smb sess not found")); pSesInfo = sesInfoAlloc(); - if (pSesInfo == NULL) + if (pSesInfo == NULL) { rc = -ENOMEM; - else { - pSesInfo->server = srvTcp; - sprintf(pSesInfo->serverName, "%u.%u.%u.%u", - NIPQUAD(sin_server.sin_addr.s_addr)); + goto mount_fail_check; } - if (!rc) { - /* volume_info.password freed at unmount */ - if (volume_info.password) { - pSesInfo->password = volume_info.password; - /* set to NULL to prevent freeing on exit */ - volume_info.password = NULL; - } - if (volume_info.username) - strncpy(pSesInfo->userName, - volume_info.username, - MAX_USERNAME_SIZE); - if (volume_info.domainname) { - int len = strlen(volume_info.domainname); - pSesInfo->domainName = - kmalloc(len + 1, GFP_KERNEL); - if (pSesInfo->domainName) - strcpy(pSesInfo->domainName, - volume_info.domainname); - } - pSesInfo->linux_uid = volume_info.linux_uid; - pSesInfo->overrideSecFlg = volume_info.secFlg; - down(&pSesInfo->sesSem); - /* BB FIXME need to pass vol->secFlgs BB */ - rc = cifs_setup_session(xid, pSesInfo, - cifs_sb->local_nls); - up(&pSesInfo->sesSem); - if (!rc) - atomic_inc(&srvTcp->socketUseCount); + /* new SMB session uses our srvTcp ref */ + pSesInfo->server = srvTcp; + sprintf(pSesInfo->serverName, "%u.%u.%u.%u", + NIPQUAD(sin_server->sin_addr.s_addr)); + + write_lock(&cifs_tcp_ses_lock); + list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list); + write_unlock(&cifs_tcp_ses_lock); + + /* volume_info.password freed at unmount */ + if (volume_info.password) { + pSesInfo->password = volume_info.password; + /* set to NULL to prevent freeing on exit */ + volume_info.password = NULL; + } + if (volume_info.username) + strncpy(pSesInfo->userName, volume_info.username, + MAX_USERNAME_SIZE); + if (volume_info.domainname) { + int len = strlen(volume_info.domainname); + pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL); + if (pSesInfo->domainName) + strcpy(pSesInfo->domainName, + volume_info.domainname); } + pSesInfo->linux_uid = volume_info.linux_uid; + pSesInfo->overrideSecFlg = volume_info.secFlg; + down(&pSesInfo->sesSem); + + /* BB FIXME need to pass vol->secFlgs BB */ + rc = cifs_setup_session(xid, pSesInfo, + cifs_sb->local_nls); + up(&pSesInfo->sesSem); } /* search for existing tcon to this server share */ if (!rc) { - if (volume_info.rsize > CIFSMaxBufSize) { - cERROR(1, ("rsize %d too large, using MaxBufSize", - volume_info.rsize)); - cifs_sb->rsize = CIFSMaxBufSize; - } else if ((volume_info.rsize) && - (volume_info.rsize <= CIFSMaxBufSize)) - cifs_sb->rsize = volume_info.rsize; - else /* default */ - cifs_sb->rsize = CIFSMaxBufSize; - - if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) { - cERROR(1, ("wsize %d too large, using 4096 instead", - volume_info.wsize)); - cifs_sb->wsize = 4096; - } else if (volume_info.wsize) - cifs_sb->wsize = volume_info.wsize; - else - cifs_sb->wsize = - min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE, - 127*1024); - /* old default of CIFSMaxBufSize was too small now - that SMB Write2 can send multiple pages in kvec. - RFC1001 does not describe what happens when frame - bigger than 128K is sent so use that as max in - conjunction with 52K kvec constraint on arch with 4K - page size */ - - if (cifs_sb->rsize < 2048) { - cifs_sb->rsize = 2048; - /* Windows ME may prefer this */ - cFYI(1, ("readsize set to minimum: 2048")); - } - /* calculate prepath */ - cifs_sb->prepath = volume_info.prepath; - if (cifs_sb->prepath) { - cifs_sb->prepathlen = strlen(cifs_sb->prepath); - /* we can not convert the / to \ in the path - separators in the prefixpath yet because we do not - know (until reset_cifs_unix_caps is called later) - whether POSIX PATH CAP is available. We normalize - the / to \ after reset_cifs_unix_caps is called */ - volume_info.prepath = NULL; - } else - cifs_sb->prepathlen = 0; - cifs_sb->mnt_uid = volume_info.linux_uid; - cifs_sb->mnt_gid = volume_info.linux_gid; - cifs_sb->mnt_file_mode = volume_info.file_mode; - cifs_sb->mnt_dir_mode = volume_info.dir_mode; - cFYI(1, ("file mode: 0x%x dir mode: 0x%x", - cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode)); - - if (volume_info.noperm) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; - if (volume_info.setuids) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; - if (volume_info.server_ino) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; - if (volume_info.remap) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; - if (volume_info.no_xattr) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; - if (volume_info.sfu_emul) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; - if (volume_info.nobrl) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; - if (volume_info.cifs_acl) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; - if (volume_info.override_uid) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; - if (volume_info.override_gid) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; - if (volume_info.dynperm) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; - if (volume_info.direct_io) { - cFYI(1, ("mounting share using direct i/o")); - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; - } - - if ((volume_info.cifs_acl) && (volume_info.dynperm)) - cERROR(1, ("mount option dynperm ignored if cifsacl " - "mount option supported")); - - tcon = - find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, - volume_info.username); + setup_cifs_sb(&volume_info, cifs_sb); + tcon = cifs_find_tcon(pSesInfo, volume_info.UNC); if (tcon) { cFYI(1, ("Found match on UNC path")); - /* we can have only one retry value for a connection - to a share so for resources mounted more than once - to the same server share the last value passed in - for the retry flag is used */ - tcon->retry = volume_info.retry; - tcon->nocase = volume_info.nocase; + /* existing tcon already has a reference */ + cifs_put_smb_ses(pSesInfo); if (tcon->seal != volume_info.seal) cERROR(1, ("transport encryption setting " "conflicts with existing tid")); } else { tcon = tconInfoAlloc(); - if (tcon == NULL) + if (tcon == NULL) { rc = -ENOMEM; - else { - /* check for null share name ie connecting to - * dfs root */ - - /* BB check if this works for exactly length - * three strings */ - if ((strchr(volume_info.UNC + 3, '\\') == NULL) - && (strchr(volume_info.UNC + 3, '/') == - NULL)) { -/* rc = connect_to_dfs_path(xid, pSesInfo, - "", cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR);*/ - cFYI(1, ("DFS root not supported")); - rc = -ENODEV; - goto out; - } else { - /* BB Do we need to wrap sesSem around - * this TCon call and Unix SetFS as - * we do on SessSetup and reconnect? */ - rc = CIFSTCon(xid, pSesInfo, - volume_info.UNC, - tcon, cifs_sb->local_nls); - cFYI(1, ("CIFS Tcon rc = %d", rc)); - } - if (!rc) { - atomic_inc(&pSesInfo->inUse); - tcon->retry = volume_info.retry; - tcon->nocase = volume_info.nocase; - tcon->seal = volume_info.seal; - } + goto mount_fail_check; } - } + tcon->ses = pSesInfo; + + /* check for null share name ie connect to dfs root */ + if ((strchr(volume_info.UNC + 3, '\\') == NULL) + && (strchr(volume_info.UNC + 3, '/') == NULL)) { + /* rc = connect_to_dfs_path(...) */ + cFYI(1, ("DFS root not supported")); + rc = -ENODEV; + goto mount_fail_check; + } else { + /* BB Do we need to wrap sesSem around + * this TCon call and Unix SetFS as + * we do on SessSetup and reconnect? */ + rc = CIFSTCon(xid, pSesInfo, volume_info.UNC, + tcon, cifs_sb->local_nls); + cFYI(1, ("CIFS Tcon rc = %d", rc)); + if (volume_info.nodfs) { + tcon->Flags &= + ~SMB_SHARE_IS_IN_DFS; + cFYI(1, ("DFS disabled (%d)", + tcon->Flags)); + } + } + if (rc) + goto mount_fail_check; + tcon->seal = volume_info.seal; + write_lock(&cifs_tcp_ses_lock); + list_add(&tcon->tcon_list, &pSesInfo->tcon_list); + write_unlock(&cifs_tcp_ses_lock); + } + + /* we can have only one retry value for a connection + to a share so for resources mounted more than once + to the same server share the last value passed in + for the retry flag is used */ + tcon->retry = volume_info.retry; + tcon->nocase = volume_info.nocase; } if (pSesInfo) { if (pSesInfo->capabilities & CAP_LARGE_FILES) { @@ -2217,92 +2320,50 @@ /* BB FIXME fix time_gran to be larger for LANMAN sessions */ sb->s_time_gran = 100; -/* on error free sesinfo and tcon struct if needed */ + /* on error free sesinfo and tcon struct if needed */ +mount_fail_check: if (rc) { - /* if session setup failed, use count is zero but - we still need to free cifsd thread */ - if (atomic_read(&srvTcp->socketUseCount) == 0) { - spin_lock(&GlobalMid_Lock); - srvTcp->tcpStatus = CifsExiting; - spin_unlock(&GlobalMid_Lock); - if (srvTcp->tsk) { - /* If we could verify that kthread_stop would - always wake up processes blocked in - tcp in recv_mesg then we could remove the - send_sig call */ - force_sig(SIGKILL, srvTcp->tsk); - kthread_stop(srvTcp->tsk); - } - } - /* If find_unc succeeded then rc == 0 so we can not end */ - if (tcon) /* up accidently freeing someone elses tcon struct */ - tconInfoFree(tcon); - if (existingCifsSes == NULL) { - if (pSesInfo) { - if ((pSesInfo->server) && - (pSesInfo->status == CifsGood)) { - int temp_rc; - temp_rc = CIFSSMBLogoff(xid, pSesInfo); - /* if the socketUseCount is now zero */ - if ((temp_rc == -ESHUTDOWN) && - (pSesInfo->server) && - (pSesInfo->server->tsk)) { - force_sig(SIGKILL, - pSesInfo->server->tsk); - kthread_stop(pSesInfo->server->tsk); - } - } else { - cFYI(1, ("No session or bad tcon")); - if ((pSesInfo->server) && - (pSesInfo->server->tsk)) { - force_sig(SIGKILL, - pSesInfo->server->tsk); - kthread_stop(pSesInfo->server->tsk); - } - } - sesInfoFree(pSesInfo); - /* pSesInfo = NULL; */ - } - } - } else { - atomic_inc(&tcon->useCount); - cifs_sb->tcon = tcon; - tcon->ses = pSesInfo; - - /* do not care if following two calls succeed - informational */ - if (!tcon->ipc) { - CIFSSMBQFSDeviceInfo(xid, tcon); - CIFSSMBQFSAttributeInfo(xid, tcon); - } - - /* tell server which Unix caps we support */ - if (tcon->ses->capabilities & CAP_UNIX) - /* reset of caps checks mount to see if unix extensions - disabled for just this mount */ - reset_cifs_unix_caps(xid, tcon, sb, &volume_info); + /* If find_unc succeeded then rc == 0 so we can not end */ + /* up accidently freeing someone elses tcon struct */ + if (tcon) + cifs_put_tcon(tcon); + else if (pSesInfo) + cifs_put_smb_ses(pSesInfo); else - tcon->unix_ext = 0; /* server does not support them */ + cifs_put_tcp_session(srvTcp); + goto out; + } + cifs_sb->tcon = tcon; - /* convert forward to back slashes in prepath here if needed */ - if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) - convert_delimiter(cifs_sb->prepath, - CIFS_DIR_SEP(cifs_sb)); - - if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) { - cifs_sb->rsize = 1024 * 127; - cFYI(DBG2, - ("no very large read support, rsize now 127K")); - } - if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X)) - cifs_sb->wsize = min(cifs_sb->wsize, - (tcon->ses->server->maxBuf - - MAX_CIFS_HDR_SIZE)); - if (!(tcon->ses->capabilities & CAP_LARGE_READ_X)) - cifs_sb->rsize = min(cifs_sb->rsize, - (tcon->ses->server->maxBuf - - MAX_CIFS_HDR_SIZE)); + /* do not care if following two calls succeed - informational */ + if (!tcon->ipc) { + CIFSSMBQFSDeviceInfo(xid, tcon); + CIFSSMBQFSAttributeInfo(xid, tcon); } + /* tell server which Unix caps we support */ + if (tcon->ses->capabilities & CAP_UNIX) + /* reset of caps checks mount to see if unix extensions + disabled for just this mount */ + reset_cifs_unix_caps(xid, tcon, sb, &volume_info); + else + tcon->unix_ext = 0; /* server does not support them */ + + /* convert forward to back slashes in prepath here if needed */ + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) + convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb)); + + if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) { + cifs_sb->rsize = 1024 * 127; + cFYI(DBG2, ("no very large read support, rsize now 127K")); + } + if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X)) + cifs_sb->wsize = min(cifs_sb->wsize, + (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); + if (!(tcon->ses->capabilities & CAP_LARGE_READ_X)) + cifs_sb->rsize = min(cifs_sb->rsize, + (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); + /* volume_info.password is freed above when existing session found (in which case it is not needed anymore) but when new sesion is created the password ptr is put in the new session structure (in which case the @@ -3471,6 +3532,7 @@ /* above now done in SendReceive */ if ((rc == 0) && (tcon != NULL)) { tcon->tidStatus = CifsGood; + tcon->need_reconnect = false; tcon->tid = smb_buffer_response->Tid; bcc_ptr = pByteArea(smb_buffer_response); length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); @@ -3496,7 +3558,7 @@ BCC(smb_buffer_response)) { kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = - kzalloc(length + 2, GFP_KERNEL); + kzalloc(2*(length + 1), GFP_KERNEL); if (tcon->nativeFileSystem) cifs_strfromUCS_le( tcon->nativeFileSystem, @@ -3542,52 +3604,17 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) { int rc = 0; - int xid; - struct cifsSesInfo *ses = NULL; - struct task_struct *cifsd_task; char *tmp; - xid = GetXid(); - - if (cifs_sb->tcon) { - ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/ - rc = CIFSSMBTDis(xid, cifs_sb->tcon); - if (rc == -EBUSY) { - FreeXid(xid); - return 0; - } - DeleteTconOplockQEntries(cifs_sb->tcon); - tconInfoFree(cifs_sb->tcon); - if ((ses) && (ses->server)) { - /* save off task so we do not refer to ses later */ - cifsd_task = ses->server->tsk; - cFYI(1, ("About to do SMBLogoff ")); - rc = CIFSSMBLogoff(xid, ses); - if (rc == -EBUSY) { - FreeXid(xid); - return 0; - } else if (rc == -ESHUTDOWN) { - cFYI(1, ("Waking up socket by sending signal")); - if (cifsd_task) { - force_sig(SIGKILL, cifsd_task); - kthread_stop(cifsd_task); - } - rc = 0; - } /* else - we have an smb session - left on this socket do not kill cifsd */ - } else - cFYI(1, ("No session or bad tcon")); - } + if (cifs_sb->tcon) + cifs_put_tcon(cifs_sb->tcon); cifs_sb->tcon = NULL; tmp = cifs_sb->prepath; cifs_sb->prepathlen = 0; cifs_sb->prepath = NULL; kfree(tmp); - if (ses) - sesInfoFree(ses); - FreeXid(xid); return rc; } @@ -3701,7 +3728,10 @@ cERROR(1, ("Send error in SessSetup = %d", rc)); } else { cFYI(1, ("CIFS Session Established successfully")); + spin_lock(&GlobalMid_Lock); pSesInfo->status = CifsGood; + pSesInfo->need_reconnect = false; + spin_unlock(&GlobalMid_Lock); } ss_err_exit: --- linux-2.6.27.orig/fs/cifs/cifssmb.c +++ linux-2.6.27/fs/cifs/cifssmb.c @@ -88,29 +88,29 @@ * on failure - errno */ static int -cifs_strncpy_to_host(char **dst, const char *src, const int maxlen, +cifs_strlcpy_to_host(char **dst, const char *src, const int maxlen, const bool is_unicode, const struct nls_table *nls_codepage) { - int plen; + int src_len, dst_len; if (is_unicode) { - plen = UniStrnlen((wchar_t *)src, maxlen); - *dst = kmalloc(plen + 2, GFP_KERNEL); + src_len = UniStrnlen((wchar_t *)src, maxlen); + *dst = kmalloc((4 * src_len) + 2, GFP_KERNEL); if (!*dst) - goto cifs_strncpy_to_host_ErrExit; - cifs_strfromUCS_le(*dst, (__le16 *)src, plen, nls_codepage); + goto cifs_strlcpy_to_host_ErrExit; + dst_len = cifs_strfromUCS_le(*dst, (__le16 *)src, src_len, + nls_codepage); + (*dst)[dst_len + 1] = 0; /* needed for Unicode */ } else { - plen = strnlen(src, maxlen); - *dst = kmalloc(plen + 2, GFP_KERNEL); + src_len = strnlen(src, maxlen); + *dst = kmalloc(src_len + 1, GFP_KERNEL); if (!*dst) - goto cifs_strncpy_to_host_ErrExit; - strncpy(*dst, src, plen); + goto cifs_strlcpy_to_host_ErrExit; + strlcpy(*dst, src, src_len + 1); } - (*dst)[plen] = 0; - (*dst)[plen+1] = 0; /* harmless for ASCII case, needed for Unicode */ return 0; -cifs_strncpy_to_host_ErrExit: +cifs_strlcpy_to_host_ErrExit: cERROR(1, ("Failed to allocate buffer for string\n")); return -ENOMEM; } @@ -190,10 +190,10 @@ /* need to prevent multiple threads trying to simultaneously reconnect the same SMB session */ down(&tcon->ses->sesSem); - if (tcon->ses->status == CifsNeedReconnect) + if (tcon->ses->need_reconnect) rc = cifs_setup_session(0, tcon->ses, nls_codepage); - if (!rc && (tcon->tidStatus == CifsNeedReconnect)) { + if (!rc && (tcon->need_reconnect)) { mark_open_files_invalid(tcon); rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nls_codepage); @@ -337,10 +337,10 @@ /* need to prevent multiple threads trying to simultaneously reconnect the same SMB session */ down(&tcon->ses->sesSem); - if (tcon->ses->status == CifsNeedReconnect) + if (tcon->ses->need_reconnect) rc = cifs_setup_session(0, tcon->ses, nls_codepage); - if (!rc && (tcon->tidStatus == CifsNeedReconnect)) { + if (!rc && (tcon->need_reconnect)) { mark_open_files_invalid(tcon); rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nls_codepage); @@ -664,8 +664,9 @@ rc = -EIO; goto neg_err_exit; } - - if (server->socketUseCount.counter > 1) { + read_lock(&cifs_tcp_ses_lock); + if (server->srv_count > 1) { + read_unlock(&cifs_tcp_ses_lock); if (memcmp(server->server_GUID, pSMBr->u.extended_response. GUID, 16) != 0) { @@ -674,9 +675,11 @@ pSMBr->u.extended_response.GUID, 16); } - } else + } else { + read_unlock(&cifs_tcp_ses_lock); memcpy(server->server_GUID, pSMBr->u.extended_response.GUID, 16); + } if (count == 16) { server->secType = RawNTLMSSP; @@ -739,50 +742,31 @@ int rc = 0; cFYI(1, ("In tree disconnect")); - /* - * If last user of the connection and - * connection alive - disconnect it - * If this is the last connection on the server session disconnect it - * (and inside session disconnect we should check if tcp socket needs - * to be freed and kernel thread woken up). - */ - if (tcon) - down(&tcon->tconSem); - else - return -EIO; - atomic_dec(&tcon->useCount); - if (atomic_read(&tcon->useCount) > 0) { - up(&tcon->tconSem); - return -EBUSY; - } + /* BB: do we need to check this? These should never be NULL. */ + if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) + return -EIO; - /* No need to return error on this operation if tid invalidated and - closed on server already e.g. due to tcp session crashing */ - if (tcon->tidStatus == CifsNeedReconnect) { - up(&tcon->tconSem); + /* + * No need to return error on this operation if tid invalidated and + * closed on server already e.g. due to tcp session crashing. Also, + * the tcon is no longer on the list, so no need to take lock before + * checking this. + */ + if (tcon->need_reconnect) return 0; - } - if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) { - up(&tcon->tconSem); - return -EIO; - } rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, (void **)&smb_buffer); - if (rc) { - up(&tcon->tconSem); + if (rc) return rc; - } rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0); if (rc) cFYI(1, ("Tree disconnect failed %d", rc)); - up(&tcon->tconSem); - /* No need to return error on this operation if tid invalidated and - closed on server already e.g. due to tcp session crashing */ + closed on server already e.g. due to tcp session crashing */ if (rc == -EAGAIN) rc = 0; @@ -796,43 +780,36 @@ int rc = 0; cFYI(1, ("In SMBLogoff for session disconnect")); - if (ses) - down(&ses->sesSem); - else + + /* + * BB: do we need to check validity of ses and server? They should + * always be valid since we have an active reference. If not, that + * should probably be a BUG() + */ + if (!ses || !ses->server) return -EIO; - atomic_dec(&ses->inUse); - if (atomic_read(&ses->inUse) > 0) { - up(&ses->sesSem); - return -EBUSY; - } + down(&ses->sesSem); + if (ses->need_reconnect) + goto session_already_dead; /* no need to send SMBlogoff if uid + already closed due to reconnect */ rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB); if (rc) { up(&ses->sesSem); return rc; } - if (ses->server) { - pSMB->hdr.Mid = GetNextMid(ses->server); + pSMB->hdr.Mid = GetNextMid(ses->server); - if (ses->server->secMode & + if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; - } pSMB->hdr.Uid = ses->Suid; pSMB->AndXCommand = 0xFF; rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0); - if (ses->server) { - atomic_dec(&ses->server->socketUseCount); - if (atomic_read(&ses->server->socketUseCount) == 0) { - spin_lock(&GlobalMid_Lock); - ses->server->tcpStatus = CifsExiting; - spin_unlock(&GlobalMid_Lock); - rc = -ESHUTDOWN; - } - } +session_already_dead: up(&ses->sesSem); /* if session dead then we do not need to do ulogoff, @@ -1534,7 +1511,7 @@ __u32 bytes_sent; __u16 byte_count; - /* cFYI(1,("write at %lld %d bytes",offset,count));*/ + /* cFYI(1, ("write at %lld %d bytes",offset,count));*/ if (tcon->ses == NULL) return -ECONNABORTED; @@ -3636,6 +3613,8 @@ le16_to_cpu(parms->SearchCount); psrch_inf->index_of_last_entry = 2 /* skip . and .. */ + psrch_inf->entries_in_buffer; + psrch_inf->last_entry = psrch_inf->srch_entries_start + + le16_to_cpu(parms->LastNameOffset); *pnetfid = parms->SearchHandle; } else { cifs_buf_release(pSMB); @@ -3751,6 +3730,8 @@ le16_to_cpu(parms->SearchCount); psrch_inf->index_of_last_entry += psrch_inf->entries_in_buffer; + psrch_inf->last_entry = psrch_inf->srch_entries_start + + le16_to_cpu(parms->LastNameOffset); /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d", psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */ @@ -3963,7 +3944,7 @@ /* copy DfsPath */ temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset); max_len = data_end - temp; - rc = cifs_strncpy_to_host(&(node->path_name), temp, + rc = cifs_strlcpy_to_host(&(node->path_name), temp, max_len, is_unicode, nls_codepage); if (rc) goto parse_DFS_referrals_exit; @@ -3971,7 +3952,7 @@ /* copy link target UNC */ temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset); max_len = data_end - temp; - rc = cifs_strncpy_to_host(&(node->node_name), temp, + rc = cifs_strlcpy_to_host(&(node->node_name), temp, max_len, is_unicode, nls_codepage); if (rc) goto parse_DFS_referrals_exit; --- linux-2.6.27.orig/fs/cifs/cifsproto.h +++ linux-2.6.27/fs/cifs/cifsproto.h @@ -36,7 +36,7 @@ extern struct smb_hdr *cifs_small_buf_get(void); extern void cifs_small_buf_release(void *); extern int smb_send(struct socket *, struct smb_hdr *, - unsigned int /* length */ , struct sockaddr *); + unsigned int /* length */ , struct sockaddr *, bool); extern unsigned int _GetXid(void); extern void _FreeXid(unsigned int); #define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current->fsuid)); --- linux-2.6.27.orig/fs/cifs/cifs_debug.c +++ linux-2.6.27/fs/cifs/cifs_debug.c @@ -107,12 +107,13 @@ #ifdef CONFIG_PROC_FS static int cifs_debug_data_proc_show(struct seq_file *m, void *v) { - struct list_head *tmp; - struct list_head *tmp1; + struct list_head *tmp1, *tmp2, *tmp3; struct mid_q_entry *mid_entry; + struct TCP_Server_Info *server; struct cifsSesInfo *ses; struct cifsTconInfo *tcon; - int i; + int i, j; + __u32 dev_type; seq_puts(m, "Display Internal CIFS Data Structures for Debugging\n" @@ -122,46 +123,78 @@ seq_printf(m, "Servers:"); i = 0; - read_lock(&GlobalSMBSeslock); - list_for_each(tmp, &GlobalSMBSessionList) { + read_lock(&cifs_tcp_ses_lock); + list_for_each(tmp1, &cifs_tcp_ses_list) { + server = list_entry(tmp1, struct TCP_Server_Info, + tcp_ses_list); i++; - ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); - if ((ses->serverDomain == NULL) || (ses->serverOS == NULL) || - (ses->serverNOS == NULL)) { - seq_printf(m, "\nentry for %s not fully " - "displayed\n\t", ses->serverName); - } else { - seq_printf(m, - "\n%d) Name: %s Domain: %s Mounts: %d OS:" - " %s \n\tNOS: %s\tCapability: 0x%x\n\tSMB" + list_for_each(tmp2, &server->smb_ses_list) { + ses = list_entry(tmp2, struct cifsSesInfo, + smb_ses_list); + if ((ses->serverDomain == NULL) || + (ses->serverOS == NULL) || + (ses->serverNOS == NULL)) { + seq_printf(m, "\n%d) entry for %s not fully " + "displayed\n\t", i, ses->serverName); + } else { + seq_printf(m, + "\n%d) Name: %s Domain: %s Uses: %d OS:" + " %s\n\tNOS: %s\tCapability: 0x%x\n\tSMB" " session status: %d\t", i, ses->serverName, ses->serverDomain, - atomic_read(&ses->inUse), - ses->serverOS, ses->serverNOS, + ses->ses_count, ses->serverOS, ses->serverNOS, ses->capabilities, ses->status); - } - if (ses->server) { + } seq_printf(m, "TCP status: %d\n\tLocal Users To " - "Server: %d SecMode: 0x%x Req On Wire: %d", - ses->server->tcpStatus, - atomic_read(&ses->server->socketUseCount), - ses->server->secMode, - atomic_read(&ses->server->inFlight)); + "Server: %d SecMode: 0x%x Req On Wire: %d", + server->tcpStatus, server->srv_count, + server->secMode, + atomic_read(&server->inFlight)); #ifdef CONFIG_CIFS_STATS2 seq_printf(m, " In Send: %d In MaxReq Wait: %d", - atomic_read(&ses->server->inSend), - atomic_read(&ses->server->num_waiters)); + atomic_read(&server->inSend), + atomic_read(&server->num_waiters)); #endif - seq_puts(m, "\nMIDs:\n"); + seq_puts(m, "\n\tShares:"); + j = 0; + list_for_each(tmp3, &ses->tcon_list) { + tcon = list_entry(tmp3, struct cifsTconInfo, + tcon_list); + ++j; + dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); + seq_printf(m, "\n\t%d) %s Mounts: %d ", j, + tcon->treeName, tcon->tc_count); + if (tcon->nativeFileSystem) { + seq_printf(m, "Type: %s ", + tcon->nativeFileSystem); + } + seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x" + "\nPathComponentMax: %d Status: 0x%d", + le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics), + le32_to_cpu(tcon->fsAttrInfo.Attributes), + le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength), + tcon->tidStatus); + if (dev_type == FILE_DEVICE_DISK) + seq_puts(m, " type: DISK "); + else if (dev_type == FILE_DEVICE_CD_ROM) + seq_puts(m, " type: CDROM "); + else + seq_printf(m, " type: %d ", dev_type); + + if (tcon->need_reconnect) + seq_puts(m, "\tDISCONNECTED "); + seq_putc(m, '\n'); + } + + seq_puts(m, "\n\tMIDs:\n"); spin_lock(&GlobalMid_Lock); - list_for_each(tmp1, &ses->server->pending_mid_q) { - mid_entry = list_entry(tmp1, struct - mid_q_entry, + list_for_each(tmp3, &server->pending_mid_q) { + mid_entry = list_entry(tmp3, struct mid_q_entry, qhead); - seq_printf(m, "State: %d com: %d pid:" + seq_printf(m, "\tState: %d com: %d pid:" " %d tsk: %p mid %d\n", mid_entry->midState, (int)mid_entry->command, @@ -171,44 +204,8 @@ } spin_unlock(&GlobalMid_Lock); } - } - read_unlock(&GlobalSMBSeslock); - seq_putc(m, '\n'); - - seq_puts(m, "Shares:"); - - i = 0; - read_lock(&GlobalSMBSeslock); - list_for_each(tmp, &GlobalTreeConnectionList) { - __u32 dev_type; - i++; - tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); - dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); - seq_printf(m, "\n%d) %s Uses: %d ", i, - tcon->treeName, atomic_read(&tcon->useCount)); - if (tcon->nativeFileSystem) { - seq_printf(m, "Type: %s ", - tcon->nativeFileSystem); - } - seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x" - "\nPathComponentMax: %d Status: %d", - le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics), - le32_to_cpu(tcon->fsAttrInfo.Attributes), - le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength), - tcon->tidStatus); - if (dev_type == FILE_DEVICE_DISK) - seq_puts(m, " type: DISK "); - else if (dev_type == FILE_DEVICE_CD_ROM) - seq_puts(m, " type: CDROM "); - else - seq_printf(m, " type: %d ", dev_type); - - if (tcon->tidStatus == CifsNeedReconnect) - seq_puts(m, "\tDISCONNECTED "); - } - read_unlock(&GlobalSMBSeslock); - + read_unlock(&cifs_tcp_ses_lock); seq_putc(m, '\n'); /* BB add code to dump additional info such as TCP session info now */ @@ -234,7 +231,9 @@ { char c; int rc; - struct list_head *tmp; + struct list_head *tmp1, *tmp2, *tmp3; + struct TCP_Server_Info *server; + struct cifsSesInfo *ses; struct cifsTconInfo *tcon; rc = get_user(c, buffer); @@ -242,33 +241,42 @@ return rc; if (c == '1' || c == 'y' || c == 'Y' || c == '0') { - read_lock(&GlobalSMBSeslock); #ifdef CONFIG_CIFS_STATS2 atomic_set(&totBufAllocCount, 0); atomic_set(&totSmBufAllocCount, 0); #endif /* CONFIG_CIFS_STATS2 */ - list_for_each(tmp, &GlobalTreeConnectionList) { - tcon = list_entry(tmp, struct cifsTconInfo, - cifsConnectionList); - atomic_set(&tcon->num_smbs_sent, 0); - atomic_set(&tcon->num_writes, 0); - atomic_set(&tcon->num_reads, 0); - atomic_set(&tcon->num_oplock_brks, 0); - atomic_set(&tcon->num_opens, 0); - atomic_set(&tcon->num_closes, 0); - atomic_set(&tcon->num_deletes, 0); - atomic_set(&tcon->num_mkdirs, 0); - atomic_set(&tcon->num_rmdirs, 0); - atomic_set(&tcon->num_renames, 0); - atomic_set(&tcon->num_t2renames, 0); - atomic_set(&tcon->num_ffirst, 0); - atomic_set(&tcon->num_fnext, 0); - atomic_set(&tcon->num_fclose, 0); - atomic_set(&tcon->num_hardlinks, 0); - atomic_set(&tcon->num_symlinks, 0); - atomic_set(&tcon->num_locks, 0); + read_lock(&cifs_tcp_ses_lock); + list_for_each(tmp1, &cifs_tcp_ses_list) { + server = list_entry(tmp1, struct TCP_Server_Info, + tcp_ses_list); + list_for_each(tmp2, &server->smb_ses_list) { + ses = list_entry(tmp2, struct cifsSesInfo, + smb_ses_list); + list_for_each(tmp3, &ses->tcon_list) { + tcon = list_entry(tmp3, + struct cifsTconInfo, + tcon_list); + atomic_set(&tcon->num_smbs_sent, 0); + atomic_set(&tcon->num_writes, 0); + atomic_set(&tcon->num_reads, 0); + atomic_set(&tcon->num_oplock_brks, 0); + atomic_set(&tcon->num_opens, 0); + atomic_set(&tcon->num_closes, 0); + atomic_set(&tcon->num_deletes, 0); + atomic_set(&tcon->num_mkdirs, 0); + atomic_set(&tcon->num_rmdirs, 0); + atomic_set(&tcon->num_renames, 0); + atomic_set(&tcon->num_t2renames, 0); + atomic_set(&tcon->num_ffirst, 0); + atomic_set(&tcon->num_fnext, 0); + atomic_set(&tcon->num_fclose, 0); + atomic_set(&tcon->num_hardlinks, 0); + atomic_set(&tcon->num_symlinks, 0); + atomic_set(&tcon->num_locks, 0); + } + } } - read_unlock(&GlobalSMBSeslock); + read_unlock(&cifs_tcp_ses_lock); } return count; @@ -277,7 +285,9 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v) { int i; - struct list_head *tmp; + struct list_head *tmp1, *tmp2, *tmp3; + struct TCP_Server_Info *server; + struct cifsSesInfo *ses; struct cifsTconInfo *tcon; seq_printf(m, @@ -306,44 +316,55 @@ GlobalCurrentXid, GlobalMaxActiveXid); i = 0; - read_lock(&GlobalSMBSeslock); - list_for_each(tmp, &GlobalTreeConnectionList) { - i++; - tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); - seq_printf(m, "\n%d) %s", i, tcon->treeName); - if (tcon->tidStatus == CifsNeedReconnect) - seq_puts(m, "\tDISCONNECTED "); - seq_printf(m, "\nSMBs: %d Oplock Breaks: %d", - atomic_read(&tcon->num_smbs_sent), - atomic_read(&tcon->num_oplock_brks)); - seq_printf(m, "\nReads: %d Bytes: %lld", - atomic_read(&tcon->num_reads), - (long long)(tcon->bytes_read)); - seq_printf(m, "\nWrites: %d Bytes: %lld", - atomic_read(&tcon->num_writes), - (long long)(tcon->bytes_written)); - seq_printf(m, - "\nLocks: %d HardLinks: %d Symlinks: %d", - atomic_read(&tcon->num_locks), - atomic_read(&tcon->num_hardlinks), - atomic_read(&tcon->num_symlinks)); - - seq_printf(m, "\nOpens: %d Closes: %d Deletes: %d", - atomic_read(&tcon->num_opens), - atomic_read(&tcon->num_closes), - atomic_read(&tcon->num_deletes)); - seq_printf(m, "\nMkdirs: %d Rmdirs: %d", - atomic_read(&tcon->num_mkdirs), - atomic_read(&tcon->num_rmdirs)); - seq_printf(m, "\nRenames: %d T2 Renames %d", - atomic_read(&tcon->num_renames), - atomic_read(&tcon->num_t2renames)); - seq_printf(m, "\nFindFirst: %d FNext %d FClose %d", - atomic_read(&tcon->num_ffirst), - atomic_read(&tcon->num_fnext), - atomic_read(&tcon->num_fclose)); + read_lock(&cifs_tcp_ses_lock); + list_for_each(tmp1, &cifs_tcp_ses_list) { + server = list_entry(tmp1, struct TCP_Server_Info, + tcp_ses_list); + list_for_each(tmp2, &server->smb_ses_list) { + ses = list_entry(tmp2, struct cifsSesInfo, + smb_ses_list); + list_for_each(tmp3, &ses->tcon_list) { + tcon = list_entry(tmp3, + struct cifsTconInfo, + tcon_list); + i++; + seq_printf(m, "\n%d) %s", i, tcon->treeName); + if (tcon->need_reconnect) + seq_puts(m, "\tDISCONNECTED "); + seq_printf(m, "\nSMBs: %d Oplock Breaks: %d", + atomic_read(&tcon->num_smbs_sent), + atomic_read(&tcon->num_oplock_brks)); + seq_printf(m, "\nReads: %d Bytes: %lld", + atomic_read(&tcon->num_reads), + (long long)(tcon->bytes_read)); + seq_printf(m, "\nWrites: %d Bytes: %lld", + atomic_read(&tcon->num_writes), + (long long)(tcon->bytes_written)); + seq_printf(m, "\nLocks: %d HardLinks: %d " + "Symlinks: %d", + atomic_read(&tcon->num_locks), + atomic_read(&tcon->num_hardlinks), + atomic_read(&tcon->num_symlinks)); + seq_printf(m, "\nOpens: %d Closes: %d" + "Deletes: %d", + atomic_read(&tcon->num_opens), + atomic_read(&tcon->num_closes), + atomic_read(&tcon->num_deletes)); + seq_printf(m, "\nMkdirs: %d Rmdirs: %d", + atomic_read(&tcon->num_mkdirs), + atomic_read(&tcon->num_rmdirs)); + seq_printf(m, "\nRenames: %d T2 Renames %d", + atomic_read(&tcon->num_renames), + atomic_read(&tcon->num_t2renames)); + seq_printf(m, "\nFindFirst: %d FNext %d " + "FClose %d", + atomic_read(&tcon->num_ffirst), + atomic_read(&tcon->num_fnext), + atomic_read(&tcon->num_fclose)); + } + } } - read_unlock(&GlobalSMBSeslock); + read_unlock(&cifs_tcp_ses_lock); seq_putc(m, '\n'); return 0; --- linux-2.6.27.orig/fs/udf/unicode.c +++ linux-2.6.27/fs/udf/unicode.c @@ -254,7 +254,7 @@ { const uint8_t *ocu; uint8_t cmp_id, ocu_len; - int i; + int i, len; ocu_len = ocu_i->u_len; @@ -279,8 +279,13 @@ if (cmp_id == 16) c = (c << 8) | ocu[i++]; - utf_o->u_len += nls->uni2char(c, &utf_o->u_name[utf_o->u_len], - UDF_NAME_LEN - utf_o->u_len); + len = nls->uni2char(c, &utf_o->u_name[utf_o->u_len], + UDF_NAME_LEN - utf_o->u_len); + /* Valid character? */ + if (len >= 0) + utf_o->u_len += len; + else + utf_o->u_name[utf_o->u_len++] = '?'; } utf_o->u_cmpID = 8; @@ -290,7 +295,8 @@ static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, int length) { - unsigned len, i, max_val; + int len; + unsigned i, max_val; uint16_t uni_char; int u_len; @@ -302,8 +308,13 @@ u_len = 0U; for (i = 0U; i < uni->u_len; i++) { len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char); - if (len <= 0) + if (!len) continue; + /* Invalid character, deal with it */ + if (len < 0) { + len = 1; + uni_char = '?'; + } if (uni_char > max_val) { max_val = 0xffffU; --- linux-2.6.27.orig/fs/reiserfs/xattr.c +++ linux-2.6.27/fs/reiserfs/xattr.c @@ -459,7 +459,7 @@ newattrs.ia_size = buffer_size; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; mutex_lock_nested(&xinode->i_mutex, I_MUTEX_XATTR); - err = notify_change(dentry, &newattrs); + err = notify_change(dentry, NULL, &newattrs); if (err) goto out_filp; @@ -746,7 +746,7 @@ if (dir->d_inode->i_nlink <= 2) { root = get_xa_root(inode->i_sb, XATTR_REPLACE); reiserfs_write_lock_xattrs(inode->i_sb); - err = vfs_rmdir(root->d_inode, dir); + err = vfs_rmdir(root->d_inode, dir, NULL); reiserfs_write_unlock_xattrs(inode->i_sb); dput(root); } else { @@ -790,7 +790,7 @@ } if (!S_ISDIR(xafile->d_inode->i_mode)) - err = notify_change(xafile, attrs); + err = notify_change(xafile, NULL, attrs); dput(xafile); return err; @@ -834,7 +834,7 @@ goto out_dir; } - err = notify_change(dir, attrs); + err = notify_change(dir, NULL, attrs); unlock_kernel(); out_dir: --- linux-2.6.27.orig/fs/reiserfs/inode.c +++ linux-2.6.27/fs/reiserfs/inode.c @@ -2565,7 +2565,7 @@ } index = pos >> PAGE_CACHE_SHIFT; - page = __grab_cache_page(mapping, index); + page = grab_cache_page_write_begin(mapping, index, flags); if (!page) return -ENOMEM; *pagep = page; --- linux-2.6.27.orig/fs/ext3/namei.c +++ linux-2.6.27/fs/ext3/namei.c @@ -1374,7 +1374,7 @@ struct fake_dirent *fde; blocksize = dir->i_sb->s_blocksize; - dxtrace(printk("Creating index\n")); + dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino)); retval = ext3_journal_get_write_access(handle, bh); if (retval) { ext3_std_error(dir->i_sb, retval); @@ -1383,6 +1383,19 @@ } root = (struct dx_root *) bh->b_data; + /* The 0th block becomes the root, move the dirents out */ + fde = &root->dotdot; + de = (struct ext3_dir_entry_2 *)((char *)fde + + ext3_rec_len_from_disk(fde->rec_len)); + if ((char *) de >= (((char *) root) + blocksize)) { + ext3_error(dir->i_sb, __func__, + "invalid rec_len for '..' in inode %lu", + dir->i_ino); + brelse(bh); + return -EIO; + } + len = ((char *) root) + blocksize - (char *) de; + bh2 = ext3_append (handle, dir, &block, &retval); if (!(bh2)) { brelse(bh); @@ -1391,11 +1404,6 @@ EXT3_I(dir)->i_flags |= EXT3_INDEX_FL; data1 = bh2->b_data; - /* The 0th block becomes the root, move the dirents out */ - fde = &root->dotdot; - de = (struct ext3_dir_entry_2 *)((char *)fde + - ext3_rec_len_from_disk(fde->rec_len)); - len = ((char *) root) + blocksize - (char *) de; memcpy (data1, de, len); de = (struct ext3_dir_entry_2 *) data1; top = data1 + len; @@ -2187,8 +2195,7 @@ * We have a transaction open. All is sweetness. It also sets * i_size in generic_commit_write(). */ - err = __page_symlink(inode, symname, l, - mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); + err = __page_symlink(inode, symname, l, 1); if (err) { drop_nlink(inode); ext3_mark_inode_dirty(handle, inode); --- linux-2.6.27.orig/fs/ext3/inode.c +++ linux-2.6.27/fs/ext3/inode.c @@ -1152,7 +1152,7 @@ to = from + len; retry: - page = __grab_cache_page(mapping, index); + page = grab_cache_page_write_begin(mapping, index, flags); if (!page) return -ENOMEM; *pagep = page; --- linux-2.6.27.orig/fs/ext3/balloc.c +++ linux-2.6.27/fs/ext3/balloc.c @@ -1547,6 +1547,7 @@ * turn off reservation for this allocation */ if (my_rsv && (free_blocks < windowsz) + && (free_blocks > 0) && (rsv_is_empty(&my_rsv->rsv_window))) my_rsv = NULL; @@ -1585,7 +1586,7 @@ * free blocks is less than half of the reservation * window size. */ - if (free_blocks <= (windowsz/2)) + if (my_rsv && (free_blocks <= (windowsz/2))) continue; brelse(bitmap_bh); --- linux-2.6.27.orig/fs/ext3/super.c +++ linux-2.6.27/fs/ext3/super.c @@ -2365,13 +2365,12 @@ static int ext3_sync_fs(struct super_block *sb, int wait) { - tid_t target; - sb->s_dirt = 0; - if (journal_start_commit(EXT3_SB(sb)->s_journal, &target)) { - if (wait) - log_wait_commit(EXT3_SB(sb)->s_journal, target); - } + if (wait) + ext3_force_commit(sb); + else + journal_start_commit(EXT3_SB(sb)->s_journal, NULL); + return 0; } --- linux-2.6.27.orig/fs/ext3/resize.c +++ linux-2.6.27/fs/ext3/resize.c @@ -790,7 +790,8 @@ if (reserved_gdb || gdb_off == 0) { if (!EXT3_HAS_COMPAT_FEATURE(sb, - EXT3_FEATURE_COMPAT_RESIZE_INODE)){ + EXT3_FEATURE_COMPAT_RESIZE_INODE) + || !le16_to_cpu(es->s_reserved_gdt_blocks)) { ext3_warning(sb, __func__, "No reserved GDT blocks, can't resize"); return -EPERM; --- linux-2.6.27.orig/fs/ext3/dir.c +++ linux-2.6.27/fs/ext3/dir.c @@ -102,6 +102,7 @@ int err; struct inode *inode = filp->f_path.dentry->d_inode; int ret = 0; + int dir_has_error = 0; sb = inode->i_sb; @@ -148,9 +149,12 @@ * of recovering data when there's a bad sector */ if (!bh) { - ext3_error (sb, "ext3_readdir", - "directory #%lu contains a hole at offset %lu", - inode->i_ino, (unsigned long)filp->f_pos); + if (!dir_has_error) { + ext3_error(sb, __func__, "directory #%lu " + "contains a hole at offset %lld", + inode->i_ino, filp->f_pos); + dir_has_error = 1; + } /* corrupt size? Maybe no more blocks to read */ if (filp->f_pos > inode->i_blocks << 9) break; @@ -410,7 +414,7 @@ get_dtype(sb, fname->file_type)); if (error) { filp->f_pos = curr_pos; - info->extra_fname = fname->next; + info->extra_fname = fname; return error; } fname = fname->next; @@ -449,11 +453,12 @@ * If there are any leftover names on the hash collision * chain, return them first. */ - if (info->extra_fname && - call_filldir(filp, dirent, filldir, info->extra_fname)) - goto finished; - - if (!info->curr_node) + if (info->extra_fname) { + if (call_filldir(filp, dirent, filldir, info->extra_fname)) + goto finished; + info->extra_fname = NULL; + goto next_node; + } else if (!info->curr_node) info->curr_node = rb_first(&info->root); while (1) { @@ -484,9 +489,14 @@ info->curr_minor_hash = fname->minor_hash; if (call_filldir(filp, dirent, filldir, fname)) break; - + next_node: info->curr_node = rb_next(info->curr_node); - if (!info->curr_node) { + if (info->curr_node) { + fname = rb_entry(info->curr_node, struct fname, + rb_hash); + info->curr_hash = fname->hash; + info->curr_minor_hash = fname->minor_hash; + } else { if (info->next_hash == ~0) { filp->f_pos = EXT3_HTREE_EOF; break; --- linux-2.6.27.orig/fs/affs/file.c +++ linux-2.6.27/fs/affs/file.c @@ -628,7 +628,7 @@ } index = pos >> PAGE_CACHE_SHIFT; - page = __grab_cache_page(mapping, index); + page = grab_cache_page_write_begin(mapping, index, flags); if (!page) return -ENOMEM; *pagep = page; --- linux-2.6.27.orig/fs/hfs/catalog.c +++ linux-2.6.27/fs/hfs/catalog.c @@ -190,6 +190,10 @@ fd->search_key->cat.ParID = rec.thread.ParID; len = fd->search_key->cat.CName.len = rec.thread.CName.len; + if (len > HFS_NAMELEN) { + printk(KERN_ERR "hfs: bad catalog namelength\n"); + return -EIO; + } memcpy(fd->search_key->cat.CName.name, rec.thread.CName.name, len); return hfs_brec_find(fd); } --- linux-2.6.27.orig/fs/jffs2/background.c +++ linux-2.6.27/fs/jffs2/background.c @@ -85,15 +85,15 @@ for (;;) { allow_signal(SIGHUP); again: + spin_lock(&c->erase_completion_lock); if (!jffs2_thread_should_wake(c)) { set_current_state (TASK_INTERRUPTIBLE); + spin_unlock(&c->erase_completion_lock); D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n")); - /* Yes, there's a race here; we checked jffs2_thread_should_wake() - before setting current->state to TASK_INTERRUPTIBLE. But it doesn't - matter - We don't care if we miss a wakeup, because the GC thread - is only an optimisation anyway. */ schedule(); - } + } else + spin_unlock(&c->erase_completion_lock); + /* This thread is purely an optimisation. But if it runs when other things could be running, it actually makes things a --- linux-2.6.27.orig/fs/jffs2/file.c +++ linux-2.6.27/fs/jffs2/file.c @@ -132,7 +132,7 @@ uint32_t pageofs = index << PAGE_CACHE_SHIFT; int ret = 0; - pg = __grab_cache_page(mapping, index); + pg = grab_cache_page_write_begin(mapping, index, flags); if (!pg) return -ENOMEM; *pagep = pg; --- linux-2.6.27.orig/fs/jffs2/compr_lzo.c +++ linux-2.6.27/fs/jffs2/compr_lzo.c @@ -19,7 +19,7 @@ static void *lzo_mem; static void *lzo_compress_buf; -static DEFINE_MUTEX(deflate_mutex); +static DEFINE_MUTEX(deflate_mutex); /* for lzo_mem and lzo_compress_buf */ static void free_workspace(void) { @@ -49,18 +49,21 @@ mutex_lock(&deflate_mutex); ret = lzo1x_1_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem); - mutex_unlock(&deflate_mutex); - if (ret != LZO_E_OK) - return -1; + goto fail; if (compress_size > *dstlen) - return -1; + goto fail; memcpy(cpage_out, lzo_compress_buf, compress_size); - *dstlen = compress_size; + mutex_unlock(&deflate_mutex); + *dstlen = compress_size; return 0; + + fail: + mutex_unlock(&deflate_mutex); + return -1; } static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out, --- linux-2.6.27.orig/fs/proc/task_mmu.c +++ linux-2.6.27/fs/proc/task_mmu.c @@ -198,11 +198,8 @@ return ret; } -static int show_map(struct seq_file *m, void *v) +static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) { - struct proc_maps_private *priv = m->private; - struct task_struct *task = priv->task; - struct vm_area_struct *vma = v; struct mm_struct *mm = vma->vm_mm; struct file *file = vma->vm_file; int flags = vma->vm_flags; @@ -210,9 +207,6 @@ dev_t dev = 0; int len; - if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ)) - return -EACCES; - if (file) { struct inode *inode = vma->vm_file->f_path.dentry->d_inode; dev = inode->i_sb->s_dev; @@ -257,6 +251,18 @@ } } seq_putc(m, '\n'); +} + +static int show_map(struct seq_file *m, void *v) +{ + struct vm_area_struct *vma = v; + struct proc_maps_private *priv = m->private; + struct task_struct *task = priv->task; + + if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ)) + return -EACCES; + + show_map_vma(m, vma); if (m->count < m->size) /* vma is copied successfully */ m->version = (vma != get_gate_vma(task))? vma->vm_start: 0; @@ -367,23 +373,25 @@ static int show_smap(struct seq_file *m, void *v) { + struct proc_maps_private *priv = m->private; + struct task_struct *task = priv->task; struct vm_area_struct *vma = v; struct mem_size_stats mss; - int ret; struct mm_walk smaps_walk = { .pmd_entry = smaps_pte_range, .mm = vma->vm_mm, .private = &mss, }; + if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ)) + return -EACCES; + memset(&mss, 0, sizeof mss); mss.vma = vma; if (vma->vm_mm && !is_vm_hugetlb_page(vma)) walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk); - ret = show_map(m, v); - if (ret) - return ret; + show_map_vma(m, vma); seq_printf(m, "Size: %8lu kB\n" @@ -405,7 +413,9 @@ mss.referenced >> 10, mss.swap >> 10); - return ret; + if (m->count < m->size) /* vma is copied successfully */ + m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0; + return 0; } static const struct seq_operations proc_pid_smaps_op = { @@ -553,9 +563,9 @@ return swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT); } -static unsigned long pte_to_pagemap_entry(pte_t pte) +static u64 pte_to_pagemap_entry(pte_t pte) { - unsigned long pme = 0; + u64 pme = 0; if (is_swap_pte(pte)) pme = PM_PFRAME(swap_pte_to_pagemap_entry(pte)) | PM_PSHIFT(PAGE_SHIFT) | PM_SWAP; --- linux-2.6.27.orig/fs/proc/proc_misc.c +++ linux-2.6.27/fs/proc/proc_misc.c @@ -703,6 +703,19 @@ return proc_calc_metrics(page, start, off, count, eof, len); } +#ifdef CONFIG_VERSION_SIGNATURE +static int version_signature_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + strcpy(page, CONFIG_VERSION_SIGNATURE); + strcat(page, "\n"); + len = strlen(page); + return proc_calc_metrics(page, start, off, count, eof, len); +} +#endif + #ifdef CONFIG_MAGIC_SYSRQ /* * writing 'C' to /proc/sysrq-trigger is like sysrq-C @@ -877,6 +890,9 @@ {"filesystems", filesystems_read_proc}, {"cmdline", cmdline_read_proc}, {"execdomains", execdomains_read_proc}, +#ifdef CONFIG_VERSION_SIGNATURE + {"version_signature", version_signature_read_proc}, +#endif {NULL,} }; for (p = simple_ones; p->name; p++) --- linux-2.6.27.orig/fs/proc/proc_sysctl.c +++ linux-2.6.27/fs/proc/proc_sysctl.c @@ -31,6 +31,7 @@ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_flags |= S_PRIVATE; /* tell selinux to ignore this inode */ inode->i_mode = table->mode; + inode->i_uid = inode->i_gid = 0; if (!table->child) { inode->i_mode |= S_IFREG; inode->i_op = &proc_sys_inode_operations; --- linux-2.6.27.orig/fs/afs/file.c +++ linux-2.6.27/fs/afs/file.c @@ -36,6 +36,7 @@ .fsync = afs_fsync, .lock = afs_lock, .flock = afs_flock, + .fsetattr = afs_fsetattr, }; const struct inode_operations afs_file_inode_operations = { --- linux-2.6.27.orig/fs/afs/internal.h +++ linux-2.6.27/fs/afs/internal.h @@ -548,6 +548,7 @@ extern int afs_validate(struct afs_vnode *, struct key *); extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern int afs_setattr(struct dentry *, struct iattr *); +extern int afs_fsetattr(struct file *, struct iattr *); extern void afs_clear_inode(struct inode *); /* --- linux-2.6.27.orig/fs/afs/inode.c +++ linux-2.6.27/fs/afs/inode.c @@ -358,7 +358,8 @@ /* * set the attributes of an inode */ -int afs_setattr(struct dentry *dentry, struct iattr *attr) +static int afs_do_setattr(struct dentry *dentry, struct iattr *attr, + struct file *file) { struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode); struct key *key; @@ -380,8 +381,8 @@ afs_writeback_all(vnode); } - if (attr->ia_valid & ATTR_FILE) { - key = attr->ia_file->private_data; + if (file) { + key = file->private_data; } else { key = afs_request_key(vnode->volume->cell); if (IS_ERR(key)) { @@ -391,10 +392,20 @@ } ret = afs_vnode_setattr(vnode, key, attr); - if (!(attr->ia_valid & ATTR_FILE)) + if (!file) key_put(key); error: _leave(" = %d", ret); return ret; } + +int afs_setattr(struct dentry *dentry, struct iattr *attr) +{ + return afs_do_setattr(dentry, attr, NULL); +} + +int afs_fsetattr(struct file *file, struct iattr *attr) +{ + return afs_do_setattr(file->f_path.dentry, attr, file); +} --- linux-2.6.27.orig/fs/afs/dir.c +++ linux-2.6.27/fs/afs/dir.c @@ -45,6 +45,7 @@ .release = afs_release, .readdir = afs_readdir, .lock = afs_lock, + .fsetattr = afs_fsetattr, }; const struct inode_operations afs_dir_inode_operations = { --- linux-2.6.27.orig/fs/ubifs/file.c +++ linux-2.6.27/fs/ubifs/file.c @@ -213,7 +213,8 @@ } static int write_begin_slow(struct address_space *mapping, - loff_t pos, unsigned len, struct page **pagep) + loff_t pos, unsigned len, struct page **pagep, + unsigned flags) { struct inode *inode = mapping->host; struct ubifs_info *c = inode->i_sb->s_fs_info; @@ -241,7 +242,7 @@ if (unlikely(err)) return err; - page = __grab_cache_page(mapping, index); + page = grab_cache_page_write_begin(mapping, index, flags); if (unlikely(!page)) { ubifs_release_budget(c, &req); return -ENOMEM; @@ -432,7 +433,7 @@ return -EROFS; /* Try out the fast-path part first */ - page = __grab_cache_page(mapping, index); + page = grab_cache_page_write_begin(mapping, index, flags); if (unlikely(!page)) return -ENOMEM; @@ -477,7 +478,7 @@ unlock_page(page); page_cache_release(page); - return write_begin_slow(mapping, pos, len, pagep); + return write_begin_slow(mapping, pos, len, pagep, flags); } /* --- linux-2.6.27.orig/fs/smbfs/file.c +++ linux-2.6.27/fs/smbfs/file.c @@ -297,7 +297,7 @@ struct page **pagep, void **fsdata) { pgoff_t index = pos >> PAGE_CACHE_SHIFT; - *pagep = __grab_cache_page(mapping, index); + *pagep = grab_cache_page_write_begin(mapping, index, flags); if (!*pagep) return -ENOMEM; return 0; --- linux-2.6.27.orig/fs/jbd2/commit.c +++ linux-2.6.27/fs/jbd2/commit.c @@ -126,8 +126,7 @@ JBUFFER_TRACE(descriptor, "submit commit block"); lock_buffer(bh); - get_bh(bh); - set_buffer_dirty(bh); + clear_buffer_dirty(bh); set_buffer_uptodate(bh); bh->b_end_io = journal_end_buffer_io_sync; @@ -160,7 +159,7 @@ /* And try again, without the barrier */ lock_buffer(bh); set_buffer_uptodate(bh); - set_buffer_dirty(bh); + clear_buffer_dirty(bh); ret = submit_bh(WRITE, bh); } *cbh = bh; --- linux-2.6.27.orig/fs/jbd2/journal.c +++ linux-2.6.27/fs/jbd2/journal.c @@ -901,10 +901,7 @@ static void jbd2_stats_proc_init(journal_t *journal) { - char name[BDEVNAME_SIZE]; - - bdevname(journal->j_dev, name); - journal->j_proc_entry = proc_mkdir(name, proc_jbd2_stats); + journal->j_proc_entry = proc_mkdir(journal->j_devname, proc_jbd2_stats); if (journal->j_proc_entry) { proc_create_data("history", S_IRUGO, journal->j_proc_entry, &jbd2_seq_history_fops, journal); @@ -915,12 +912,9 @@ static void jbd2_stats_proc_exit(journal_t *journal) { - char name[BDEVNAME_SIZE]; - - bdevname(journal->j_dev, name); remove_proc_entry("info", journal->j_proc_entry); remove_proc_entry("history", journal->j_proc_entry); - remove_proc_entry(name, proc_jbd2_stats); + remove_proc_entry(journal->j_devname, proc_jbd2_stats); } static void journal_init_stats(journal_t *journal) @@ -1018,6 +1012,7 @@ { journal_t *journal = journal_init_common(); struct buffer_head *bh; + char *p; int n; if (!journal) @@ -1039,6 +1034,10 @@ journal->j_fs_dev = fs_dev; journal->j_blk_offset = start; journal->j_maxlen = len; + bdevname(journal->j_dev, journal->j_devname); + p = journal->j_devname; + while ((p = strchr(p, '/'))) + *p = '!'; jbd2_stats_proc_init(journal); bh = __getblk(journal->j_dev, start, journal->j_blocksize); @@ -1061,6 +1060,7 @@ { struct buffer_head *bh; journal_t *journal = journal_init_common(); + char *p; int err; int n; unsigned long long blocknr; @@ -1070,6 +1070,12 @@ journal->j_dev = journal->j_fs_dev = inode->i_sb->s_bdev; journal->j_inode = inode; + bdevname(journal->j_dev, journal->j_devname); + p = journal->j_devname; + while ((p = strchr(p, '/'))) + *p = '!'; + p = journal->j_devname + strlen(journal->j_devname); + sprintf(p, ":%lu", journal->j_inode->i_ino); jbd_debug(1, "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n", journal, inode->i_sb->s_id, inode->i_ino, @@ -1253,6 +1259,22 @@ goto out; } + if (buffer_write_io_error(bh)) { + /* + * Oh, dear. A previous attempt to write the journal + * superblock failed. This could happen because the + * USB device was yanked out. Or it could happen to + * be a transient write error and maybe the block will + * be remapped. Nothing we can do but to retry the + * write and hope for the best. + */ + printk(KERN_ERR "JBD2: previous I/O error detected " + "for journal superblock update for %s.\n", + journal->j_devname); + clear_buffer_write_io_error(bh); + set_buffer_uptodate(bh); + } + spin_lock(&journal->j_state_lock); jbd_debug(1,"JBD: updating superblock (start %ld, seq %d, errno %d)\n", journal->j_tail, journal->j_tail_sequence, journal->j_errno); @@ -1264,9 +1286,16 @@ BUFFER_TRACE(bh, "marking dirty"); mark_buffer_dirty(bh); - if (wait) + if (wait) { sync_dirty_buffer(bh); - else + if (buffer_write_io_error(bh)) { + printk(KERN_ERR "JBD2: I/O error detected " + "when updating journal superblock for %s.\n", + journal->j_devname); + clear_buffer_write_io_error(bh); + set_buffer_uptodate(bh); + } + } else ll_rw_block(SWRITE, 1, &bh); out: --- linux-2.6.27.orig/fs/jbd2/checkpoint.c +++ linux-2.6.27/fs/jbd2/checkpoint.c @@ -114,7 +114,7 @@ */ void __jbd2_log_wait_for_space(journal_t *journal) { - int nblocks; + int nblocks, space_left; assert_spin_locked(&journal->j_state_lock); nblocks = jbd_space_needed(journal); @@ -126,14 +126,47 @@ /* * Test again, another process may have checkpointed while we - * were waiting for the checkpoint lock + * were waiting for the checkpoint lock. If there are no + * transactions ready to be checkpointed, try to recover + * journal space by calling cleanup_journal_tail(), and if + * that doesn't work, by waiting for the currently committing + * transaction to complete. If there is absolutely no way + * to make progress, this is either a BUG or corrupted + * filesystem, so abort the journal and leave a stack + * trace for forensic evidence. */ spin_lock(&journal->j_state_lock); + spin_lock(&journal->j_list_lock); nblocks = jbd_space_needed(journal); - if (__jbd2_log_space_left(journal) < nblocks) { + space_left = __jbd2_log_space_left(journal); + if (space_left < nblocks) { + int chkpt = journal->j_checkpoint_transactions != NULL; + tid_t tid = 0; + + if (journal->j_committing_transaction) + tid = journal->j_committing_transaction->t_tid; + spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_state_lock); - jbd2_log_do_checkpoint(journal); + if (chkpt) { + jbd2_log_do_checkpoint(journal); + } else if (jbd2_cleanup_journal_tail(journal) == 0) { + /* We were able to recover space; yay! */ + ; + } else if (tid) { + jbd2_log_wait_commit(journal, tid); + } else { + printk(KERN_ERR "%s: needed %d blocks and " + "only had %d space available\n", + __func__, nblocks, space_left); + printk(KERN_ERR "%s: no way to get more " + "journal space in %s\n", __func__, + journal->j_devname); + WARN_ON(1); + jbd2_journal_abort(journal, 0); + } spin_lock(&journal->j_state_lock); + } else { + spin_unlock(&journal->j_list_lock); } mutex_unlock(&journal->j_checkpoint_mutex); } --- linux-2.6.27.orig/fs/ecryptfs/inode.c +++ linux-2.6.27/fs/ecryptfs/inode.c @@ -403,19 +403,24 @@ struct dentry *new_dentry) { struct dentry *lower_old_dentry; + struct vfsmount *lower_old_mnt; struct dentry *lower_new_dentry; + struct vfsmount *lower_new_mnt; struct dentry *lower_dir_dentry; u64 file_size_save; int rc; file_size_save = i_size_read(old_dentry->d_inode); lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); + lower_old_mnt = ecryptfs_dentry_to_lower_mnt(old_dentry); lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); + lower_new_mnt = ecryptfs_dentry_to_lower_mnt(new_dentry); dget(lower_old_dentry); dget(lower_new_dentry); lower_dir_dentry = lock_parent(lower_new_dentry); - rc = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode, - lower_new_dentry); + rc = vfs_link(lower_old_dentry, lower_old_mnt, + lower_dir_dentry->d_inode, lower_new_dentry, + lower_new_mnt); if (rc || !lower_new_dentry->d_inode) goto out_lock; rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0); @@ -440,11 +445,12 @@ { int rc = 0; struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir); struct dentry *lower_dir_dentry; lower_dir_dentry = lock_parent(lower_dentry); - rc = vfs_unlink(lower_dir_inode, lower_dentry); + rc = vfs_unlink(lower_dir_inode, lower_dentry, lower_mnt); if (rc) { printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc); goto out_unlock; @@ -464,6 +470,7 @@ { int rc; struct dentry *lower_dentry; + struct vfsmount *lower_mnt; struct dentry *lower_dir_dentry; char *encoded_symname; int encoded_symlen; @@ -471,6 +478,7 @@ lower_dentry = ecryptfs_dentry_to_lower(dentry); dget(lower_dentry); + lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); lower_dir_dentry = lock_parent(lower_dentry); encoded_symlen = ecryptfs_encode_filename(crypt_stat, symname, strlen(symname), @@ -479,7 +487,7 @@ rc = encoded_symlen; goto out_lock; } - rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry, + rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry, lower_mnt, encoded_symname); kfree(encoded_symname); if (rc || !lower_dentry->d_inode) @@ -501,11 +509,14 @@ { int rc; struct dentry *lower_dentry; + struct vfsmount *lower_mnt; struct dentry *lower_dir_dentry; lower_dentry = ecryptfs_dentry_to_lower(dentry); + lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); lower_dir_dentry = lock_parent(lower_dentry); - rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, mode); + rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, lower_mnt, + mode); if (rc || !lower_dentry->d_inode) goto out; rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0); @@ -524,14 +535,16 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry) { struct dentry *lower_dentry; + struct vfsmount *lower_mnt; struct dentry *lower_dir_dentry; int rc; lower_dentry = ecryptfs_dentry_to_lower(dentry); + lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); dget(dentry); lower_dir_dentry = lock_parent(lower_dentry); dget(lower_dentry); - rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry); + rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry, lower_mnt); dput(lower_dentry); if (!rc) d_delete(lower_dentry); @@ -549,11 +562,14 @@ { int rc; struct dentry *lower_dentry; + struct vfsmount *lower_mnt; struct dentry *lower_dir_dentry; lower_dentry = ecryptfs_dentry_to_lower(dentry); + lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); lower_dir_dentry = lock_parent(lower_dentry); - rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, mode, dev); + rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, lower_mnt, mode, + dev); if (rc || !lower_dentry->d_inode) goto out; rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0); @@ -574,19 +590,24 @@ { int rc; struct dentry *lower_old_dentry; + struct vfsmount *lower_old_mnt; struct dentry *lower_new_dentry; + struct vfsmount *lower_new_mnt; struct dentry *lower_old_dir_dentry; struct dentry *lower_new_dir_dentry; lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); + lower_old_mnt = ecryptfs_dentry_to_lower_mnt(old_dentry); lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); + lower_new_mnt = ecryptfs_dentry_to_lower_mnt(new_dentry); dget(lower_old_dentry); dget(lower_new_dentry); lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, - lower_new_dir_dentry->d_inode, lower_new_dentry); + lower_old_mnt, lower_new_dir_dentry->d_inode, + lower_new_dentry, lower_new_mnt); if (rc) goto out_lock; fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode, NULL); @@ -673,10 +694,11 @@ ecryptfs_printk(KERN_DEBUG, "Calling readlink w/ " "dentry->d_name.name = [%s]\n", dentry->d_name.name); rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len); - buf[rc] = '\0'; set_fs(old_fs); if (rc < 0) goto out_free; + else + buf[rc] = '\0'; rc = 0; nd_set_link(nd, buf); goto out; @@ -849,6 +871,7 @@ { int rc = 0; struct dentry *lower_dentry; + struct vfsmount *lower_mnt; struct inode *inode; struct inode *lower_inode; struct ecryptfs_crypt_stat *crypt_stat; @@ -859,6 +882,7 @@ inode = dentry->d_inode; lower_inode = ecryptfs_inode_to_lower(inode); lower_dentry = ecryptfs_dentry_to_lower(dentry); + lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); mutex_lock(&crypt_stat->cs_mutex); if (S_ISDIR(dentry->d_inode->i_mode)) crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); @@ -910,7 +934,7 @@ ia->ia_valid &= ~ATTR_MODE; mutex_lock(&lower_dentry->d_inode->i_mutex); - rc = notify_change(lower_dentry, ia); + rc = notify_change(lower_dentry, lower_mnt, ia); mutex_unlock(&lower_dentry->d_inode->i_mutex); out: fsstack_copy_attr_all(inode, lower_inode, NULL); --- linux-2.6.27.orig/fs/ecryptfs/keystore.c +++ linux-2.6.27/fs/ecryptfs/keystore.c @@ -730,6 +730,13 @@ } (*new_auth_tok)->session_key.encrypted_key_size = (body_size - (ECRYPTFS_SALT_SIZE + 5)); + if ((*new_auth_tok)->session_key.encrypted_key_size + > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) { + printk(KERN_WARNING "Tag 3 packet contains key larger " + "than ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES\n"); + rc = -EINVAL; + goto out_free; + } if (unlikely(data[(*packet_size)++] != 0x04)) { printk(KERN_WARNING "Unknown version number [%d]\n", data[(*packet_size) - 1]); @@ -876,6 +883,12 @@ rc = -EINVAL; goto out; } + if (unlikely((*tag_11_contents_size) > max_contents_bytes)) { + printk(KERN_ERR "Literal data section in tag 11 packet exceeds " + "expected size\n"); + rc = -EINVAL; + goto out; + } if (data[(*packet_size)++] != 0x62) { printk(KERN_WARNING "Unrecognizable packet\n"); rc = -EINVAL; @@ -1037,17 +1050,14 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok, struct ecryptfs_crypt_stat *crypt_stat) { - struct scatterlist dst_sg; - struct scatterlist src_sg; + struct scatterlist dst_sg[2]; + struct scatterlist src_sg[2]; struct mutex *tfm_mutex; struct blkcipher_desc desc = { .flags = CRYPTO_TFM_REQ_MAY_SLEEP }; int rc = 0; - sg_init_table(&dst_sg, 1); - sg_init_table(&src_sg, 1); - if (unlikely(ecryptfs_verbosity > 0)) { ecryptfs_printk( KERN_DEBUG, "Session key encryption key (size [%d]):\n", @@ -1066,8 +1076,8 @@ } rc = virt_to_scatterlist(auth_tok->session_key.encrypted_key, auth_tok->session_key.encrypted_key_size, - &src_sg, 1); - if (rc != 1) { + src_sg, 2); + if (rc < 1 || rc > 2) { printk(KERN_ERR "Internal error whilst attempting to convert " "auth_tok->session_key.encrypted_key to scatterlist; " "expected rc = 1; got rc = [%d]. " @@ -1079,8 +1089,8 @@ auth_tok->session_key.encrypted_key_size; rc = virt_to_scatterlist(auth_tok->session_key.decrypted_key, auth_tok->session_key.decrypted_key_size, - &dst_sg, 1); - if (rc != 1) { + dst_sg, 2); + if (rc < 1 || rc > 2) { printk(KERN_ERR "Internal error whilst attempting to convert " "auth_tok->session_key.decrypted_key to scatterlist; " "expected rc = 1; got rc = [%d]\n", rc); @@ -1096,7 +1106,7 @@ rc = -EINVAL; goto out; } - rc = crypto_blkcipher_decrypt(&desc, &dst_sg, &src_sg, + rc = crypto_blkcipher_decrypt(&desc, dst_sg, src_sg, auth_tok->session_key.encrypted_key_size); mutex_unlock(tfm_mutex); if (unlikely(rc)) { @@ -1541,8 +1551,8 @@ size_t i; size_t encrypted_session_key_valid = 0; char session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES]; - struct scatterlist dst_sg; - struct scatterlist src_sg; + struct scatterlist dst_sg[2]; + struct scatterlist src_sg[2]; struct mutex *tfm_mutex = NULL; u8 cipher_code; size_t packet_size_length; @@ -1621,8 +1631,8 @@ ecryptfs_dump_hex(session_key_encryption_key, 16); } rc = virt_to_scatterlist(crypt_stat->key, key_rec->enc_key_size, - &src_sg, 1); - if (rc != 1) { + src_sg, 2); + if (rc < 1 || rc > 2) { ecryptfs_printk(KERN_ERR, "Error generating scatterlist " "for crypt_stat session key; expected rc = 1; " "got rc = [%d]. key_rec->enc_key_size = [%d]\n", @@ -1631,8 +1641,8 @@ goto out; } rc = virt_to_scatterlist(key_rec->enc_key, key_rec->enc_key_size, - &dst_sg, 1); - if (rc != 1) { + dst_sg, 2); + if (rc < 1 || rc > 2) { ecryptfs_printk(KERN_ERR, "Error generating scatterlist " "for crypt_stat encrypted session key; " "expected rc = 1; got rc = [%d]. " @@ -1653,7 +1663,7 @@ rc = 0; ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes of the key\n", crypt_stat->key_size); - rc = crypto_blkcipher_encrypt(&desc, &dst_sg, &src_sg, + rc = crypto_blkcipher_encrypt(&desc, dst_sg, src_sg, (*key_rec).enc_key_size); mutex_unlock(tfm_mutex); if (rc) { --- linux-2.6.27.orig/fs/ext4/ext4.h +++ linux-2.6.27/fs/ext4/ext4.h @@ -291,8 +291,6 @@ #define EXT4_IOC_SETFLAGS FS_IOC_SETFLAGS #define EXT4_IOC_GETVERSION _IOR('f', 3, long) #define EXT4_IOC_SETVERSION _IOW('f', 4, long) -#define EXT4_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long) -#define EXT4_IOC_GROUP_ADD _IOW('f', 8,struct ext4_new_group_input) #define EXT4_IOC_GETVERSION_OLD FS_IOC_GETVERSION #define EXT4_IOC_SETVERSION_OLD FS_IOC_SETVERSION #ifdef CONFIG_JBD2_DEBUG @@ -300,7 +298,10 @@ #endif #define EXT4_IOC_GETRSVSZ _IOR('f', 5, long) #define EXT4_IOC_SETRSVSZ _IOW('f', 6, long) -#define EXT4_IOC_MIGRATE _IO('f', 7) +#define EXT4_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long) +#define EXT4_IOC_GROUP_ADD _IOW('f', 8, struct ext4_new_group_input) +#define EXT4_IOC_MIGRATE _IO('f', 9) + /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */ /* * ioctl commands in 32 bit emulation @@ -1083,8 +1084,7 @@ extern long ext4_compat_ioctl (struct file *, unsigned int, unsigned long); /* migrate.c */ -extern int ext4_ext_migrate(struct inode *, struct file *, unsigned int, - unsigned long); +extern int ext4_ext_migrate(struct inode *); /* namei.c */ extern int ext4_orphan_add(handle_t *, struct inode *); extern int ext4_orphan_del(handle_t *, struct inode *); @@ -1167,8 +1167,11 @@ static inline loff_t ext4_isize(struct ext4_inode *raw_inode) { - return ((loff_t)le32_to_cpu(raw_inode->i_size_high) << 32) | - le32_to_cpu(raw_inode->i_size_lo); + if (S_ISREG(le16_to_cpu(raw_inode->i_mode))) + return ((loff_t)le32_to_cpu(raw_inode->i_size_high) << 32) | + le32_to_cpu(raw_inode->i_size_lo); + else + return (loff_t) le32_to_cpu(raw_inode->i_size_lo); } static inline void ext4_isize_set(struct ext4_inode *raw_inode, loff_t i_size) --- linux-2.6.27.orig/fs/ext4/namei.c +++ linux-2.6.27/fs/ext4/namei.c @@ -1377,7 +1377,7 @@ struct fake_dirent *fde; blocksize = dir->i_sb->s_blocksize; - dxtrace(printk("Creating index\n")); + dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino)); retval = ext4_journal_get_write_access(handle, bh); if (retval) { ext4_std_error(dir->i_sb, retval); @@ -1386,6 +1386,20 @@ } root = (struct dx_root *) bh->b_data; + /* The 0th block becomes the root, move the dirents out */ + fde = &root->dotdot; + de = (struct ext4_dir_entry_2 *)((char *)fde + + ext4_rec_len_from_disk(fde->rec_len)); + if ((char *) de >= (((char *) root) + blocksize)) { + ext4_error(dir->i_sb, __func__, + "invalid rec_len for '..' in inode %lu", + dir->i_ino); + brelse(bh); + return -EIO; + } + len = ((char *) root) + blocksize - (char *) de; + + /* Allocate new block for the 0th block's dirents */ bh2 = ext4_append (handle, dir, &block, &retval); if (!(bh2)) { brelse(bh); @@ -1394,11 +1408,6 @@ EXT4_I(dir)->i_flags |= EXT4_INDEX_FL; data1 = bh2->b_data; - /* The 0th block becomes the root, move the dirents out */ - fde = &root->dotdot; - de = (struct ext4_dir_entry_2 *)((char *)fde + - ext4_rec_len_from_disk(fde->rec_len)); - len = ((char *) root) + blocksize - (char *) de; memcpy (data1, de, len); de = (struct ext4_dir_entry_2 *) data1; top = data1 + len; @@ -2216,8 +2225,7 @@ * We have a transaction open. All is sweetness. It also sets * i_size in generic_commit_write(). */ - err = __page_symlink(inode, symname, l, - mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); + err = __page_symlink(inode, symname, l, 1); if (err) { clear_nlink(inode); ext4_mark_inode_dirty(handle, inode); --- linux-2.6.27.orig/fs/ext4/xattr.c +++ linux-2.6.27/fs/ext4/xattr.c @@ -959,6 +959,7 @@ struct ext4_xattr_block_find bs = { .s = { .not_found = -ENODATA, }, }; + unsigned long no_expand; int error; if (!name) @@ -966,6 +967,9 @@ if (strlen(name) > 255) return -ERANGE; down_write(&EXT4_I(inode)->xattr_sem); + no_expand = EXT4_I(inode)->i_state & EXT4_STATE_NO_EXPAND; + EXT4_I(inode)->i_state |= EXT4_STATE_NO_EXPAND; + error = ext4_get_inode_loc(inode, &is.iloc); if (error) goto cleanup; @@ -1042,6 +1046,8 @@ cleanup: brelse(is.iloc.bh); brelse(bs.bh); + if (no_expand == 0) + EXT4_I(inode)->i_state &= ~EXT4_STATE_NO_EXPAND; up_write(&EXT4_I(inode)->xattr_sem); return error; } --- linux-2.6.27.orig/fs/ext4/ialloc.c +++ linux-2.6.27/fs/ext4/ialloc.c @@ -715,6 +715,8 @@ gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); free = ext4_free_blocks_after_init(sb, group, gdp); gdp->bg_free_blocks_count = cpu_to_le16(free); + gdp->bg_checksum = ext4_group_desc_csum(sbi, group, + gdp); } spin_unlock(sb_bgl_lock(sbi, group)); --- linux-2.6.27.orig/fs/ext4/mballoc.c +++ linux-2.6.27/fs/ext4/mballoc.c @@ -2575,7 +2575,7 @@ pa = list_entry(cur, struct ext4_prealloc_space, pa_group_list); list_del(&pa->pa_group_list); count++; - kfree(pa); + kmem_cache_free(ext4_pspace_cachep, pa); } if (count) mb_debug("mballoc: %u PAs left\n", count); @@ -2785,14 +2785,20 @@ mode_t mode = S_IFREG | S_IRUGO | S_IWUSR; struct ext4_sb_info *sbi = EXT4_SB(sb); struct proc_dir_entry *proc; - char devname[64]; + char devname[BDEVNAME_SIZE], *p; if (proc_root_ext4 == NULL) { sbi->s_mb_proc = NULL; return -EINVAL; } bdevname(sb->s_bdev, devname); + p = devname; + while ((p = strchr(p, '/'))) + *p = '!'; + sbi->s_mb_proc = proc_mkdir(devname, proc_root_ext4); + if (!sbi->s_mb_proc) + goto err_create_dir; MB_PROC_HANDLER(EXT4_MB_STATS_NAME, stats); MB_PROC_HANDLER(EXT4_MB_MAX_TO_SCAN_NAME, max_to_scan); @@ -2804,7 +2810,6 @@ return 0; err_out: - printk(KERN_ERR "EXT4-fs: Unable to create %s\n", devname); remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_mb_proc); remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_mb_proc); remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_mb_proc); @@ -2813,6 +2818,8 @@ remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_mb_proc); remove_proc_entry(devname, proc_root_ext4); sbi->s_mb_proc = NULL; +err_create_dir: + printk(KERN_ERR "EXT4-fs: Unable to create %s\n", devname); return -ENOMEM; } @@ -2820,12 +2827,15 @@ static int ext4_mb_destroy_per_dev_proc(struct super_block *sb) { struct ext4_sb_info *sbi = EXT4_SB(sb); - char devname[64]; + char devname[BDEVNAME_SIZE], *p; if (sbi->s_mb_proc == NULL) return -EINVAL; bdevname(sb->s_bdev, devname); + p = devname; + while ((p = strchr(p, '/'))) + *p = '!'; remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_mb_proc); remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_mb_proc); remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_mb_proc); --- linux-2.6.27.orig/fs/ext4/inode.c +++ linux-2.6.27/fs/ext4/inode.c @@ -351,9 +351,9 @@ final = ptrs; } else { ext4_warning(inode->i_sb, "ext4_block_to_path", - "block %lu > max", + "block %lu > max in inode %lu", i_block + direct_blocks + - indirect_blocks + double_blocks); + indirect_blocks + double_blocks, inode->i_ino); } if (boundary) *boundary = final - 1 - (i_block & (ptrs - 1)); @@ -1370,7 +1370,7 @@ goto out; } - page = __grab_cache_page(mapping, index); + page = grab_cache_page_write_begin(mapping, index, flags); if (!page) { ext4_journal_stop(handle); ret = -ENOMEM; @@ -2242,6 +2242,8 @@ unlock_page(page); return 0; } + /* now mark the buffer_heads as dirty and uptodate */ + block_commit_write(page, 0, PAGE_CACHE_SIZE); } if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) @@ -2419,7 +2421,7 @@ goto out; } - page = __grab_cache_page(mapping, index); + page = grab_cache_page_write_begin(mapping, index, flags); if (!page) { ext4_journal_stop(handle); ret = -ENOMEM; @@ -4444,9 +4446,10 @@ static int ext4_index_trans_blocks(struct inode *inode, int nrblocks, int chunk) { if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)) - return ext4_indirect_trans_blocks(inode, nrblocks, 0); - return ext4_ext_index_trans_blocks(inode, nrblocks, 0); + return ext4_indirect_trans_blocks(inode, nrblocks, chunk); + return ext4_ext_index_trans_blocks(inode, nrblocks, chunk); } + /* * Account for index blocks, block groups bitmaps and block group * descriptor blocks if modify datablocks and index blocks --- linux-2.6.27.orig/fs/ext4/ioctl.c +++ linux-2.6.27/fs/ext4/ioctl.c @@ -267,7 +267,26 @@ } case EXT4_IOC_MIGRATE: - return ext4_ext_migrate(inode, filp, cmd, arg); + { + int err; + if (!is_owner_or_cap(inode)) + return -EACCES; + + err = mnt_want_write(filp->f_path.mnt); + if (err) + return err; + /* + * inode_mutex prevent write and truncate on the file. + * Read still goes through. We take i_data_sem in + * ext4_ext_swap_inode_data before we switch the + * inode format to prevent read. + */ + mutex_lock(&(inode->i_mutex)); + err = ext4_ext_migrate(inode); + mutex_unlock(&(inode->i_mutex)); + mnt_drop_write(filp->f_path.mnt); + return err; + } default: return -ENOTTY; --- linux-2.6.27.orig/fs/ext4/super.c +++ linux-2.6.27/fs/ext4/super.c @@ -1504,8 +1504,10 @@ sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex; groups_per_flex = 1 << sbi->s_log_groups_per_flex; - flex_group_count = (sbi->s_groups_count + groups_per_flex - 1) / - groups_per_flex; + /* We allocate both existing and potentially added groups */ + flex_group_count = ((sbi->s_groups_count + groups_per_flex - 1) + + ((le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) + 1) << + EXT4_DESC_PER_BLOCK_BITS(sb))) / groups_per_flex; sbi->s_flex_groups = kzalloc(flex_group_count * sizeof(struct flex_groups), GFP_KERNEL); if (sbi->s_flex_groups == NULL) { @@ -1623,8 +1625,10 @@ "Checksum for group %lu failed (%u!=%u)\n", i, le16_to_cpu(ext4_group_desc_csum(sbi, i, gdp)), le16_to_cpu(gdp->bg_checksum)); - if (!(sb->s_flags & MS_RDONLY)) + if (!(sb->s_flags & MS_RDONLY)) { + spin_unlock(sb_bgl_lock(sbi, i)); return 0; + } } spin_unlock(sb_bgl_lock(sbi, i)); if (!flexbg_flag) @@ -1916,8 +1920,8 @@ struct inode *root; int ret = -EINVAL; int blocksize; - int db_count; - int i; + unsigned int db_count; + unsigned int i; int needs_recovery; __le32 features; __u64 blocks_count; @@ -2195,20 +2199,30 @@ if (EXT4_BLOCKS_PER_GROUP(sb) == 0) goto cantfind_ext4; - /* ensure blocks_count calculation below doesn't sign-extend */ - if (ext4_blocks_count(es) + EXT4_BLOCKS_PER_GROUP(sb) < - le32_to_cpu(es->s_first_data_block) + 1) { - printk(KERN_WARNING "EXT4-fs: bad geometry: block count %llu, " - "first data block %u, blocks per group %lu\n", - ext4_blocks_count(es), - le32_to_cpu(es->s_first_data_block), - EXT4_BLOCKS_PER_GROUP(sb)); + /* + * It makes no sense for the first data block to be beyond the end + * of the filesystem. + */ + if (le32_to_cpu(es->s_first_data_block) >= ext4_blocks_count(es)) { + printk(KERN_WARNING "EXT4-fs: bad geometry: first data" + "block %u is beyond end of filesystem (%llu)\n", + le32_to_cpu(es->s_first_data_block), + ext4_blocks_count(es)); goto failed_mount; } blocks_count = (ext4_blocks_count(es) - le32_to_cpu(es->s_first_data_block) + EXT4_BLOCKS_PER_GROUP(sb) - 1); do_div(blocks_count, EXT4_BLOCKS_PER_GROUP(sb)); + if (blocks_count > ((uint64_t)1<<32) - EXT4_DESC_PER_BLOCK(sb)) { + printk(KERN_WARNING "EXT4-fs: groups count too large: %u " + "(block count %llu, first data block %u, " + "blocks per group %lu)\n", sbi->s_groups_count, + ext4_blocks_count(es), + le32_to_cpu(es->s_first_data_block), + EXT4_BLOCKS_PER_GROUP(sb)); + goto failed_mount; + } sbi->s_groups_count = blocks_count; db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / EXT4_DESC_PER_BLOCK(sb); @@ -2444,6 +2458,21 @@ "available.\n"); } + if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) { + printk(KERN_WARNING "EXT4-fs: Ignoring delalloc option - " + "requested data journaling mode\n"); + clear_opt(sbi->s_mount_opt, DELALLOC); + } else if (test_opt(sb, DELALLOC)) + printk(KERN_INFO "EXT4-fs: delayed allocation enabled\n"); + + ext4_ext_init(sb); + err = ext4_mb_init(sb, needs_recovery); + if (err) { + printk(KERN_ERR "EXT4-fs: failed to initalize mballoc (%d)\n", + err); + goto failed_mount4; + } + /* * akpm: core read_super() calls in here with the superblock locked. * That deadlocks, because orphan cleanup needs to lock the superblock @@ -2463,16 +2492,6 @@ test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA ? "ordered": "writeback"); - if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) { - printk(KERN_WARNING "EXT4-fs: Ignoring delalloc option - " - "requested data journaling mode\n"); - clear_opt(sbi->s_mount_opt, DELALLOC); - } else if (test_opt(sb, DELALLOC)) - printk(KERN_INFO "EXT4-fs: delayed allocation enabled\n"); - - ext4_ext_init(sb); - ext4_mb_init(sb, needs_recovery); - lock_kernel(); return 0; @@ -2799,13 +2818,34 @@ if (!sbh) return; + if (buffer_write_io_error(sbh)) { + /* + * Oh, dear. A previous attempt to write the + * superblock failed. This could happen because the + * USB device was yanked out. Or it could happen to + * be a transient write error and maybe the block will + * be remapped. Nothing we can do but to retry the + * write and hope for the best. + */ + printk(KERN_ERR "ext4: previous I/O error to " + "superblock detected for %s.\n", sb->s_id); + clear_buffer_write_io_error(sbh); + set_buffer_uptodate(sbh); + } es->s_wtime = cpu_to_le32(get_seconds()); ext4_free_blocks_count_set(es, ext4_count_free_blocks(sb)); es->s_free_inodes_count = cpu_to_le32(ext4_count_free_inodes(sb)); BUFFER_TRACE(sbh, "marking dirty"); mark_buffer_dirty(sbh); - if (sync) + if (sync) { sync_dirty_buffer(sbh); + if (buffer_write_io_error(sbh)) { + printk(KERN_ERR "ext4: I/O error while writing " + "superblock for %s.\n", sb->s_id); + clear_buffer_write_io_error(sbh); + set_buffer_uptodate(sbh); + } + } } @@ -2890,12 +2930,9 @@ /* * Ext4 always journals updates to the superblock itself, so we don't * have to propagate any other updates to the superblock on disk at this - * point. Just start an async writeback to get the buffers on their way - * to the disk. - * - * This implicitly triggers the writebehind on sync(). + * point. (We can probably nuke this function altogether, and remove + * any mention to sb->s_dirt in all of fs/ext4; eventual cleanup...) */ - static void ext4_write_super(struct super_block *sb) { if (mutex_trylock(&sb->s_lock) != 0) @@ -2905,14 +2942,14 @@ static int ext4_sync_fs(struct super_block *sb, int wait) { - tid_t target; + int ret = 0; sb->s_dirt = 0; - if (jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, &target)) { - if (wait) - jbd2_log_wait_commit(EXT4_SB(sb)->s_journal, target); - } - return 0; + if (wait) + ret = ext4_force_commit(sb); + else + jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, NULL); + return ret; } /* --- linux-2.6.27.orig/fs/ext4/resize.c +++ linux-2.6.27/fs/ext4/resize.c @@ -859,11 +859,13 @@ gdp = (struct ext4_group_desc *)((char *)primary->b_data + gdb_off * EXT4_DESC_SIZE(sb)); + memset(gdp, 0, EXT4_DESC_SIZE(sb)); ext4_block_bitmap_set(sb, gdp, input->block_bitmap); /* LV FIXME */ ext4_inode_bitmap_set(sb, gdp, input->inode_bitmap); /* LV FIXME */ ext4_inode_table_set(sb, gdp, input->inode_table); /* LV FIXME */ gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count); gdp->bg_free_inodes_count = cpu_to_le16(EXT4_INODES_PER_GROUP(sb)); + gdp->bg_flags = cpu_to_le16(EXT4_BG_INODE_ZEROED); gdp->bg_checksum = ext4_group_desc_csum(sbi, input->group, gdp); /* @@ -929,6 +931,15 @@ percpu_counter_add(&sbi->s_freeinodes_counter, EXT4_INODES_PER_GROUP(sb)); + if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) { + ext4_group_t flex_group; + flex_group = ext4_flex_group(sbi, input->group); + sbi->s_flex_groups[flex_group].free_blocks += + input->free_blocks_count; + sbi->s_flex_groups[flex_group].free_inodes += + EXT4_INODES_PER_GROUP(sb); + } + ext4_journal_dirty_metadata(handle, sbi->s_sbh); sb->s_dirt = 1; --- linux-2.6.27.orig/fs/ext4/migrate.c +++ linux-2.6.27/fs/ext4/migrate.c @@ -447,8 +447,7 @@ } -int ext4_ext_migrate(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int ext4_ext_migrate(struct inode *inode) { handle_t *handle; int retval = 0, i; @@ -516,12 +515,6 @@ * when we add extents we extent the journal */ /* - * inode_mutex prevent write and truncate on the file. Read still goes - * through. We take i_data_sem in ext4_ext_swap_inode_data before we - * switch the inode format to prevent read. - */ - mutex_lock(&(inode->i_mutex)); - /* * Even though we take i_mutex we can still cause block allocation * via mmap write to holes. If we have allocated new blocks we fail * migrate. New block allocation will clear EXT4_EXT_MIGRATE flag. @@ -623,7 +616,6 @@ tmp_inode->i_nlink = 0; ext4_journal_stop(handle); - mutex_unlock(&(inode->i_mutex)); if (tmp_inode) iput(tmp_inode); --- linux-2.6.27.orig/fs/ext4/dir.c +++ linux-2.6.27/fs/ext4/dir.c @@ -102,6 +102,7 @@ int err; struct inode *inode = filp->f_path.dentry->d_inode; int ret = 0; + int dir_has_error = 0; sb = inode->i_sb; @@ -148,9 +149,13 @@ * of recovering data when there's a bad sector */ if (!bh) { - ext4_error (sb, "ext4_readdir", - "directory #%lu contains a hole at offset %lu", - inode->i_ino, (unsigned long)filp->f_pos); + if (!dir_has_error) { + ext4_error(sb, __func__, "directory #%lu " + "contains a hole at offset %Lu", + inode->i_ino, + (unsigned long long) filp->f_pos); + dir_has_error = 1; + } /* corrupt size? Maybe no more blocks to read */ if (filp->f_pos > inode->i_blocks << 9) break; @@ -453,17 +458,8 @@ if (info->extra_fname) { if (call_filldir(filp, dirent, filldir, info->extra_fname)) goto finished; - info->extra_fname = NULL; - info->curr_node = rb_next(info->curr_node); - if (!info->curr_node) { - if (info->next_hash == ~0) { - filp->f_pos = EXT4_HTREE_EOF; - goto finished; - } - info->curr_hash = info->next_hash; - info->curr_minor_hash = 0; - } + goto next_node; } else if (!info->curr_node) info->curr_node = rb_first(&info->root); @@ -495,9 +491,14 @@ info->curr_minor_hash = fname->minor_hash; if (call_filldir(filp, dirent, filldir, fname)) break; - + next_node: info->curr_node = rb_next(info->curr_node); - if (!info->curr_node) { + if (info->curr_node) { + fname = rb_entry(info->curr_node, struct fname, + rb_hash); + info->curr_hash = fname->hash; + info->curr_minor_hash = fname->minor_hash; + } else { if (info->next_hash == ~0) { filp->f_pos = EXT4_HTREE_EOF; break; --- linux-2.6.27.orig/fs/fat/file.c +++ linux-2.6.27/fs/fat/file.c @@ -98,7 +98,7 @@ * out the RO attribute for checking by the security * module, just because it maps to a file mode. */ - err = security_inode_setattr(filp->f_path.dentry, &ia); + err = security_inode_setattr(filp->f_path.dentry, filp->f_path.mnt, &ia); if (err) goto up; --- linux-2.6.27.orig/fs/hpfs/namei.c +++ linux-2.6.27/fs/hpfs/namei.c @@ -426,7 +426,7 @@ /*printk("HPFS: truncating file before delete.\n");*/ newattrs.ia_size = 0; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; - err = notify_change(dentry, &newattrs); + err = notify_change(dentry, NULL, &newattrs); put_write_access(inode); if (!err) goto again; --- linux-2.6.27.orig/fs/nfs/file.c +++ linux-2.6.27/fs/nfs/file.c @@ -351,7 +351,7 @@ file->f_path.dentry->d_name.name, mapping->host->i_ino, len, (long long) pos); - page = __grab_cache_page(mapping, index); + page = grab_cache_page_write_begin(mapping, index, flags); if (!page) return -ENOMEM; *pagep = page; --- linux-2.6.27.orig/fs/nfs/read.c +++ linux-2.6.27/fs/nfs/read.c @@ -533,12 +533,6 @@ unsigned int len; int error; - error = nfs_wb_page(inode, page); - if (error) - goto out_unlock; - if (PageUptodate(page)) - goto out_unlock; - len = nfs_page_length(page); if (len == 0) return nfs_return_empty_page(page); --- linux-2.6.27.orig/fs/nfs/dir.c +++ linux-2.6.27/fs/nfs/dir.c @@ -1926,7 +1926,8 @@ case S_IFREG: /* NFSv4 has atomic_open... */ if (nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN) - && (mask & MAY_OPEN)) + && (mask & MAY_OPEN) + && !(mask & MAY_EXEC)) goto out; break; case S_IFDIR: --- linux-2.6.27.orig/fs/sysfs/bin.c +++ linux-2.6.27/fs/sysfs/bin.c @@ -62,6 +62,9 @@ loff_t offs = *off; int count = min_t(size_t, bytes, PAGE_SIZE); + if (!bytes) + return 0; + if (size) { if (offs > size) return 0; @@ -119,6 +122,9 @@ loff_t offs = *off; int count = min_t(size_t, bytes, PAGE_SIZE); + if (!bytes) + return 0; + if (size) { if (offs > size) return 0; --- linux-2.6.27.orig/fs/xfs/xfs_rename.c +++ linux-2.6.27/fs/xfs/xfs_rename.c @@ -212,7 +212,7 @@ if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) && (target_dp->i_d.di_projid != src_ip->i_d.di_projid))) { error = XFS_ERROR(EXDEV); - xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED); + xfs_rename_unlock4(inodes, XFS_ILOCK_EXCL); xfs_trans_cancel(tp, cancel_flags); goto std_return; } --- linux-2.6.27.orig/fs/xfs/xfs_log.c +++ linux-2.6.27/fs/xfs/xfs_log.c @@ -1033,11 +1033,12 @@ l = iclog->ic_log; /* - * If the ordered flag has been removed by a lower - * layer, it means the underlyin device no longer supports + * If the _XFS_BARRIER_FAILED flag was set by a lower + * layer, it means the underlying device no longer supports * barrier I/O. Warn loudly and turn off barriers. */ - if ((l->l_mp->m_flags & XFS_MOUNT_BARRIER) && !XFS_BUF_ISORDERED(bp)) { + if (bp->b_flags & _XFS_BARRIER_FAILED) { + bp->b_flags &= ~_XFS_BARRIER_FAILED; l->l_mp->m_flags &= ~XFS_MOUNT_BARRIER; xfs_fs_cmn_err(CE_WARN, l->l_mp, "xlog_iodone: Barriers are no longer supported" --- linux-2.6.27.orig/fs/xfs/linux-2.6/xfs_super.c +++ linux-2.6.27/fs/xfs/linux-2.6/xfs_super.c @@ -1323,7 +1323,7 @@ "XFS: mount option \"%s\" not supported for remount\n", p); return -EINVAL; #else - return 0; + break; #endif } } --- linux-2.6.27.orig/fs/xfs/linux-2.6/xfs_buf.c +++ linux-2.6.27/fs/xfs/linux-2.6/xfs_buf.c @@ -1001,12 +1001,13 @@ * We can get an EOPNOTSUPP to ordered writes. Here we clear the * ordered flag and reissue them. Because we can't tell the higher * layers directly that they should not issue ordered I/O anymore, they - * need to check if the ordered flag was cleared during I/O completion. + * need to check if the _XFS_BARRIER_FAILED flag was set during I/O completion. */ if ((bp->b_error == EOPNOTSUPP) && (bp->b_flags & (XBF_ORDERED|XBF_ASYNC)) == (XBF_ORDERED|XBF_ASYNC)) { XB_TRACE(bp, "ordered_retry", bp->b_iodone); bp->b_flags &= ~XBF_ORDERED; + bp->b_flags |= _XFS_BARRIER_FAILED; xfs_buf_iorequest(bp); } else if (bp->b_iodone) (*(bp->b_iodone))(bp); @@ -1113,8 +1114,7 @@ unsigned int blocksize = bp->b_target->bt_bsize; struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; - if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) - bp->b_error = EIO; + xfs_buf_ioerror(bp, -error); do { struct page *page = bvec->bv_page; --- linux-2.6.27.orig/fs/xfs/linux-2.6/xfs_buf.h +++ linux-2.6.27/fs/xfs/linux-2.6/xfs_buf.h @@ -85,6 +85,14 @@ * modifications being lost. */ _XBF_PAGE_LOCKED = (1 << 22), + + /* + * If we try a barrier write, but it fails we have to communicate + * this to the upper layers. Unfortunately b_error gets overwritten + * when the buffer is re-issued so we have to add another flag to + * keep this information. + */ + _XFS_BARRIER_FAILED = (1 << 23), } xfs_buf_flags_t; typedef enum { --- linux-2.6.27.orig/fs/dlm/plock.c +++ linux-2.6.27/fs/dlm/plock.c @@ -304,7 +304,9 @@ if (rv == -ENOENT) rv = 0; else if (rv > 0) { + locks_init_lock(fl); fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK; + fl->fl_flags = FL_POSIX; fl->fl_pid = op->info.pid; fl->fl_start = op->info.start; fl->fl_end = op->info.end; --- linux-2.6.27.orig/fs/ocfs2/file.c +++ linux-2.6.27/fs/ocfs2/file.c @@ -2089,7 +2089,7 @@ out->f_path.dentry->d_name.len, out->f_path.dentry->d_name.name); - inode_double_lock(inode, pipe->inode); + mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT); ret = ocfs2_rw_lock(inode, 1); if (ret < 0) { @@ -2104,12 +2104,16 @@ goto out_unlock; } + if (pipe->inode) + mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_CHILD); ret = generic_file_splice_write_nolock(pipe, out, ppos, len, flags); + if (pipe->inode) + mutex_unlock(&pipe->inode->i_mutex); out_unlock: ocfs2_rw_unlock(inode, 1); out: - inode_double_unlock(inode, pipe->inode); + mutex_unlock(&inode->i_mutex); mlog_exit(ret); return ret; --- linux-2.6.27.orig/fs/fuse/file.c +++ linux-2.6.27/fs/fuse/file.c @@ -54,7 +54,7 @@ ff->reserved_req = fuse_request_alloc(); if (!ff->reserved_req) { kfree(ff); - ff = NULL; + return NULL; } else { INIT_LIST_HEAD(&ff->write_entry); atomic_set(&ff->count, 0); @@ -644,7 +644,7 @@ { pgoff_t index = pos >> PAGE_CACHE_SHIFT; - *pagep = __grab_cache_page(mapping, index); + *pagep = grab_cache_page_write_begin(mapping, index, flags); if (!*pagep) return -ENOMEM; return 0; @@ -777,7 +777,7 @@ break; err = -ENOMEM; - page = __grab_cache_page(mapping, index); + page = grab_cache_page_write_begin(mapping, index, 0); if (!page) break; @@ -1465,6 +1465,11 @@ return retval; } +static int fuse_fsetattr(struct file *file, struct iattr *attr) +{ + return fuse_do_setattr(file->f_path.dentry, attr, file); +} + static const struct file_operations fuse_file_operations = { .llseek = fuse_file_llseek, .read = do_sync_read, @@ -1478,6 +1483,7 @@ .fsync = fuse_fsync, .lock = fuse_file_lock, .flock = fuse_file_flock, + .fsetattr = fuse_fsetattr, .splice_read = generic_file_splice_read, }; @@ -1491,6 +1497,7 @@ .fsync = fuse_fsync, .lock = fuse_file_lock, .flock = fuse_file_flock, + .fsetattr = fuse_fsetattr, /* no mmap and splice_read */ }; --- linux-2.6.27.orig/fs/fuse/inode.c +++ linux-2.6.27/fs/fuse/inode.c @@ -292,6 +292,7 @@ list_del(&fc->entry); fuse_ctl_remove_conn(fc); mutex_unlock(&fuse_mutex); + bdi_destroy(&fc->bdi); fuse_conn_put(fc); } @@ -531,7 +532,6 @@ if (fc->destroy_req) fuse_request_free(fc->destroy_req); mutex_destroy(&fc->inst_mutex); - bdi_destroy(&fc->bdi); kfree(fc); } } @@ -832,12 +832,16 @@ if (!file) return -EINVAL; - if (file->f_op != &fuse_dev_operations) + if (file->f_op != &fuse_dev_operations) { + fput(file); return -EINVAL; + } fc = new_conn(sb); - if (!fc) + if (!fc) { + fput(file); return -ENOMEM; + } fc->flags = d.flags; fc->user_id = d.user_id; --- linux-2.6.27.orig/fs/fuse/fuse_i.h +++ linux-2.6.27/fs/fuse/fuse_i.h @@ -551,6 +551,10 @@ */ int fuse_dev_init(void); + +int fuse_do_setattr(struct dentry *entry, struct iattr *attr, + struct file *file); + /** * Cleanup the client device */ --- linux-2.6.27.orig/fs/fuse/dev.c +++ linux-2.6.27/fs/fuse/dev.c @@ -281,7 +281,8 @@ fc->blocked = 0; wake_up_all(&fc->blocked_waitq); } - if (fc->num_background == FUSE_CONGESTION_THRESHOLD) { + if (fc->num_background == FUSE_CONGESTION_THRESHOLD && + fc->connected) { clear_bdi_congested(&fc->bdi, READ); clear_bdi_congested(&fc->bdi, WRITE); } --- linux-2.6.27.orig/fs/fuse/dir.c +++ linux-2.6.27/fs/fuse/dir.c @@ -1105,21 +1105,22 @@ return file ? fuse_fsync_common(file, de, datasync, 1) : 0; } -static bool update_mtime(unsigned ivalid) +static bool update_mtime(unsigned ivalid, bool have_file) { /* Always update if mtime is explicitly set */ if (ivalid & ATTR_MTIME_SET) return true; /* If it's an open(O_TRUNC) or an ftruncate(), don't update */ - if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE))) + if ((ivalid & ATTR_SIZE) && ((ivalid & ATTR_OPEN) || have_file)) return false; /* In all other cases update */ return true; } -static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) +static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg, + bool have_file) { unsigned ivalid = iattr->ia_valid; @@ -1138,7 +1139,7 @@ if (!(ivalid & ATTR_ATIME_SET)) arg->valid |= FATTR_ATIME_NOW; } - if ((ivalid & ATTR_MTIME) && update_mtime(ivalid)) { + if ((ivalid & ATTR_MTIME) && update_mtime(ivalid, have_file)) { arg->valid |= FATTR_MTIME; arg->mtime = iattr->ia_mtime.tv_sec; arg->mtimensec = iattr->ia_mtime.tv_nsec; @@ -1199,8 +1200,8 @@ * vmtruncate() doesn't allow for this case, so do the rlimit checking * and the actual truncation by hand. */ -static int fuse_do_setattr(struct dentry *entry, struct iattr *attr, - struct file *file) +int fuse_do_setattr(struct dentry *entry, struct iattr *attr, + struct file *file) { struct inode *inode = entry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); @@ -1244,7 +1245,7 @@ memset(&inarg, 0, sizeof(inarg)); memset(&outarg, 0, sizeof(outarg)); - iattr_to_fattr(attr, &inarg); + iattr_to_fattr(attr, &inarg, file != NULL); if (file) { struct fuse_file *ff = file->private_data; inarg.valid |= FATTR_FH; @@ -1314,10 +1315,7 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) { - if (attr->ia_valid & ATTR_FILE) - return fuse_do_setattr(entry, attr, attr->ia_file); - else - return fuse_do_setattr(entry, attr, NULL); + return fuse_do_setattr(entry, attr, NULL); } static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, --- linux-2.6.27.orig/fs/hfsplus/catalog.c +++ linux-2.6.27/fs/hfsplus/catalog.c @@ -168,6 +168,11 @@ return -EIO; } + if (be16_to_cpu(tmp.thread.nodeName.length) > 255) { + printk(KERN_ERR "hfs: catalog name length corrupted\n"); + return -EIO; + } + hfsplus_cat_build_key_uni(fd->search_key, be32_to_cpu(tmp.thread.parentID), &tmp.thread.nodeName); return hfs_brec_find(fd); --- linux-2.6.27.orig/fs/hfsplus/bitmap.c +++ linux-2.6.27/fs/hfsplus/bitmap.c @@ -32,6 +32,10 @@ mutex_lock(&HFSPLUS_SB(sb).alloc_file->i_mutex); mapping = HFSPLUS_SB(sb).alloc_file->i_mapping; page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS, NULL); + if (IS_ERR(page)) { + start = size; + goto out; + } pptr = kmap(page); curr = pptr + (offset & (PAGE_CACHE_BITS - 1)) / 32; i = offset % 32; @@ -73,6 +77,10 @@ break; page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS, NULL); + if (IS_ERR(page)) { + start = size; + goto out; + } curr = pptr = kmap(page); if ((size ^ offset) / PAGE_CACHE_BITS) end = pptr + PAGE_CACHE_BITS / 32; @@ -120,6 +128,10 @@ offset += PAGE_CACHE_BITS; page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS, NULL); + if (IS_ERR(page)) { + start = size; + goto out; + } pptr = kmap(page); curr = pptr; end = pptr + PAGE_CACHE_BITS / 32; --- linux-2.6.27.orig/fs/jbd/transaction.c +++ linux-2.6.27/fs/jbd/transaction.c @@ -954,9 +954,10 @@ journal_t *journal = handle->h_transaction->t_journal; int need_brelse = 0; struct journal_head *jh; + int ret = 0; if (is_handle_aborted(handle)) - return 0; + return ret; jh = journal_add_journal_head(bh); JBUFFER_TRACE(jh, "entry"); @@ -1067,7 +1068,16 @@ time if it is redirtied */ } - /* journal_clean_data_list() may have got there first */ + /* + * We cannot remove the buffer with io error from the + * committing transaction, because otherwise it would + * miss the error and the commit would not abort. + */ + if (unlikely(!buffer_uptodate(bh))) { + ret = -EIO; + goto no_journal; + } + if (jh->b_transaction != NULL) { JBUFFER_TRACE(jh, "unfile from commit"); __journal_temp_unlink_buffer(jh); @@ -1108,7 +1118,7 @@ } JBUFFER_TRACE(jh, "exit"); journal_put_journal_head(jh); - return 0; + return ret; } /** --- linux-2.6.27.orig/fs/jbd/journal.c +++ linux-2.6.27/fs/jbd/journal.c @@ -1121,9 +1121,12 @@ * * Release a journal_t structure once it is no longer in use by the * journaled object. + * Return <0 if we couldn't clean up the journal. */ -void journal_destroy(journal_t *journal) +int journal_destroy(journal_t *journal) { + int err = 0; + /* Wait for the commit thread to wake up and die. */ journal_kill_thread(journal); @@ -1146,11 +1149,16 @@ J_ASSERT(journal->j_checkpoint_transactions == NULL); spin_unlock(&journal->j_list_lock); - /* We can now mark the journal as empty. */ - journal->j_tail = 0; - journal->j_tail_sequence = ++journal->j_transaction_sequence; if (journal->j_sb_buffer) { - journal_update_superblock(journal, 1); + if (!is_journal_aborted(journal)) { + /* We can now mark the journal as empty. */ + journal->j_tail = 0; + journal->j_tail_sequence = + ++journal->j_transaction_sequence; + journal_update_superblock(journal, 1); + } else { + err = -EIO; + } brelse(journal->j_sb_buffer); } @@ -1160,6 +1168,8 @@ journal_destroy_revoke(journal); kfree(journal->j_wbuf); kfree(journal); + + return err; } @@ -1359,10 +1369,16 @@ spin_lock(&journal->j_list_lock); while (!err && journal->j_checkpoint_transactions != NULL) { spin_unlock(&journal->j_list_lock); + mutex_lock(&journal->j_checkpoint_mutex); err = log_do_checkpoint(journal); + mutex_unlock(&journal->j_checkpoint_mutex); spin_lock(&journal->j_list_lock); } spin_unlock(&journal->j_list_lock); + + if (is_journal_aborted(journal)) + return -EIO; + cleanup_journal_tail(journal); /* Finally, mark the journal as really needing no recovery. @@ -1384,7 +1400,7 @@ J_ASSERT(journal->j_head == journal->j_tail); J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence); spin_unlock(&journal->j_state_lock); - return err; + return 0; } /** --- linux-2.6.27.orig/fs/jbd/checkpoint.c +++ linux-2.6.27/fs/jbd/checkpoint.c @@ -93,7 +93,8 @@ int ret = 0; struct buffer_head *bh = jh2bh(jh); - if (jh->b_jlist == BJ_None && !buffer_locked(bh) && !buffer_dirty(bh)) { + if (jh->b_jlist == BJ_None && !buffer_locked(bh) && + !buffer_dirty(bh) && !buffer_write_io_error(bh)) { JBUFFER_TRACE(jh, "remove from checkpoint list"); ret = __journal_remove_checkpoint(jh) + 1; jbd_unlock_bh_state(bh); @@ -160,21 +161,25 @@ * buffers. Note that we take the buffers in the opposite ordering * from the one in which they were submitted for IO. * + * Return 0 on success, and return <0 if some buffers have failed + * to be written out. + * * Called with j_list_lock held. */ -static void __wait_cp_io(journal_t *journal, transaction_t *transaction) +static int __wait_cp_io(journal_t *journal, transaction_t *transaction) { struct journal_head *jh; struct buffer_head *bh; tid_t this_tid; int released = 0; + int ret = 0; this_tid = transaction->t_tid; restart: /* Did somebody clean up the transaction in the meanwhile? */ if (journal->j_checkpoint_transactions != transaction || transaction->t_tid != this_tid) - return; + return ret; while (!released && transaction->t_checkpoint_io_list) { jh = transaction->t_checkpoint_io_list; bh = jh2bh(jh); @@ -194,6 +199,9 @@ spin_lock(&journal->j_list_lock); goto restart; } + if (unlikely(buffer_write_io_error(bh))) + ret = -EIO; + /* * Now in whatever state the buffer currently is, we know that * it has been written out and so we can drop it from the list @@ -203,6 +211,8 @@ journal_remove_journal_head(bh); __brelse(bh); } + + return ret; } #define NR_BATCH 64 @@ -226,7 +236,8 @@ * Try to flush one buffer from the checkpoint list to disk. * * Return 1 if something happened which requires us to abort the current - * scan of the checkpoint list. + * scan of the checkpoint list. Return <0 if the buffer has failed to + * be written out. * * Called with j_list_lock held and drops it if 1 is returned * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it @@ -256,6 +267,9 @@ log_wait_commit(journal, tid); ret = 1; } else if (!buffer_dirty(bh)) { + ret = 1; + if (unlikely(buffer_write_io_error(bh))) + ret = -EIO; J_ASSERT_JH(jh, !buffer_jbddirty(bh)); BUFFER_TRACE(bh, "remove from checkpoint"); __journal_remove_checkpoint(jh); @@ -263,7 +277,6 @@ jbd_unlock_bh_state(bh); journal_remove_journal_head(bh); __brelse(bh); - ret = 1; } else { /* * Important: we are about to write the buffer, and @@ -295,6 +308,7 @@ * to disk. We submit larger chunks of data at once. * * The journal should be locked before calling this function. + * Called with j_checkpoint_mutex held. */ int log_do_checkpoint(journal_t *journal) { @@ -318,6 +332,7 @@ * OK, we need to start writing disk blocks. Take one transaction * and write it. */ + result = 0; spin_lock(&journal->j_list_lock); if (!journal->j_checkpoint_transactions) goto out; @@ -334,7 +349,7 @@ int batch_count = 0; struct buffer_head *bhs[NR_BATCH]; struct journal_head *jh; - int retry = 0; + int retry = 0, err; while (!retry && transaction->t_checkpoint_list) { struct buffer_head *bh; @@ -347,6 +362,8 @@ break; } retry = __process_buffer(journal, jh, bhs,&batch_count); + if (retry < 0 && !result) + result = retry; if (!retry && (need_resched() || spin_needbreak(&journal->j_list_lock))) { spin_unlock(&journal->j_list_lock); @@ -371,14 +388,18 @@ * Now we have cleaned up the first transaction's checkpoint * list. Let's clean up the second one */ - __wait_cp_io(journal, transaction); + err = __wait_cp_io(journal, transaction); + if (!result) + result = err; } out: spin_unlock(&journal->j_list_lock); - result = cleanup_journal_tail(journal); if (result < 0) - return result; - return 0; + journal_abort(journal, result); + else + result = cleanup_journal_tail(journal); + + return (result < 0) ? result : 0; } /* @@ -394,8 +415,9 @@ * This is the only part of the journaling code which really needs to be * aware of transaction aborts. Checkpointing involves writing to the * main filesystem area rather than to the journal, so it can proceed - * even in abort state, but we must not update the journal superblock if - * we have an abort error outstanding. + * even in abort state, but we must not update the super block if + * checkpointing may have failed. Otherwise, we would lose some metadata + * buffers which should be written-back to the filesystem. */ int cleanup_journal_tail(journal_t *journal) @@ -404,6 +426,9 @@ tid_t first_tid; unsigned long blocknr, freed; + if (is_journal_aborted(journal)) + return 1; + /* OK, work out the oldest transaction remaining in the log, and * the log block it starts at. * --- linux-2.6.27.orig/fs/jbd/recovery.c +++ linux-2.6.27/fs/jbd/recovery.c @@ -223,7 +223,7 @@ */ int journal_recover(journal_t *journal) { - int err; + int err, err2; journal_superblock_t * sb; struct recovery_info info; @@ -261,7 +261,10 @@ journal->j_transaction_sequence = ++info.end_transaction; journal_clear_revoke(journal); - sync_blockdev(journal->j_fs_dev); + err2 = sync_blockdev(journal->j_fs_dev); + if (!err) + err = err2; + return err; } --- linux-2.6.27.orig/fs/ext2/balloc.c +++ linux-2.6.27/fs/ext2/balloc.c @@ -1295,6 +1295,7 @@ * turn off reservation for this allocation */ if (my_rsv && (free_blocks < windowsz) + && (free_blocks > 0) && (rsv_is_empty(&my_rsv->rsv_window))) my_rsv = NULL; @@ -1332,7 +1333,7 @@ * free blocks is less than half of the reservation * window size. */ - if (free_blocks <= (windowsz/2)) + if (my_rsv && (free_blocks <= (windowsz/2))) continue; brelse(bitmap_bh); --- linux-2.6.27.orig/fs/ext2/dir.c +++ linux-2.6.27/fs/ext2/dir.c @@ -103,7 +103,7 @@ return err; } -static void ext2_check_page(struct page *page) +static void ext2_check_page(struct page *page, int quiet) { struct inode *dir = page->mapping->host; struct super_block *sb = dir->i_sb; @@ -146,10 +146,10 @@ /* Too bad, we had an error */ Ebadsize: - ext2_error(sb, "ext2_check_page", - "size of directory #%lu is not a multiple of chunk size", - dir->i_ino - ); + if (!quiet) + ext2_error(sb, __func__, + "size of directory #%lu is not a multiple " + "of chunk size", dir->i_ino); goto fail; Eshort: error = "rec_len is smaller than minimal"; @@ -166,32 +166,36 @@ Einumber: error = "inode out of bounds"; bad_entry: - ext2_error (sb, "ext2_check_page", "bad entry in directory #%lu: %s - " - "offset=%lu, inode=%lu, rec_len=%d, name_len=%d", - dir->i_ino, error, (page->index<inode), - rec_len, p->name_len); + if (!quiet) + ext2_error(sb, __func__, "bad entry in directory #%lu: : %s - " + "offset=%lu, inode=%lu, rec_len=%d, name_len=%d", + dir->i_ino, error, (page->index<inode), + rec_len, p->name_len); goto fail; Eend: - p = (ext2_dirent *)(kaddr + offs); - ext2_error (sb, "ext2_check_page", - "entry in directory #%lu spans the page boundary" - "offset=%lu, inode=%lu", - dir->i_ino, (page->index<inode)); + if (!quiet) { + p = (ext2_dirent *)(kaddr + offs); + ext2_error(sb, "ext2_check_page", + "entry in directory #%lu spans the page boundary" + "offset=%lu, inode=%lu", + dir->i_ino, (page->index<inode)); + } fail: SetPageChecked(page); SetPageError(page); } -static struct page * ext2_get_page(struct inode *dir, unsigned long n) +static struct page * ext2_get_page(struct inode *dir, unsigned long n, + int quiet) { struct address_space *mapping = dir->i_mapping; struct page *page = read_mapping_page(mapping, n, NULL); if (!IS_ERR(page)) { kmap(page); if (!PageChecked(page)) - ext2_check_page(page); + ext2_check_page(page, quiet); if (PageError(page)) goto fail; } @@ -292,7 +296,7 @@ for ( ; n < npages; n++, offset = 0) { char *kaddr, *limit; ext2_dirent *de; - struct page *page = ext2_get_page(inode, n); + struct page *page = ext2_get_page(inode, n, 0); if (IS_ERR(page)) { ext2_error(sb, __func__, @@ -361,6 +365,7 @@ struct page *page = NULL; struct ext2_inode_info *ei = EXT2_I(dir); ext2_dirent * de; + int dir_has_error = 0; if (npages == 0) goto out; @@ -374,7 +379,7 @@ n = start; do { char *kaddr; - page = ext2_get_page(dir, n); + page = ext2_get_page(dir, n, dir_has_error); if (!IS_ERR(page)) { kaddr = page_address(page); de = (ext2_dirent *) kaddr; @@ -391,7 +396,9 @@ de = ext2_next_entry(de); } ext2_put_page(page); - } + } else + dir_has_error = 1; + if (++n >= npages) n = 0; /* next page is past the blocks we've got */ @@ -414,7 +421,7 @@ struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p) { - struct page *page = ext2_get_page(dir, 0); + struct page *page = ext2_get_page(dir, 0, 0); ext2_dirent *de = NULL; if (!IS_ERR(page)) { @@ -487,7 +494,7 @@ for (n = 0; n <= npages; n++) { char *dir_end; - page = ext2_get_page(dir, n); + page = ext2_get_page(dir, n, 0); err = PTR_ERR(page); if (IS_ERR(page)) goto out; @@ -655,14 +662,17 @@ { struct page *page = NULL; unsigned long i, npages = dir_pages(inode); + int dir_has_error = 0; for (i = 0; i < npages; i++) { char *kaddr; ext2_dirent * de; - page = ext2_get_page(inode, i); + page = ext2_get_page(inode, i, dir_has_error); - if (IS_ERR(page)) + if (IS_ERR(page)) { + dir_has_error = 1; continue; + } kaddr = page_address(page); de = (ext2_dirent *)kaddr; --- linux-2.6.27.orig/fs/hostfs/hostfs_kern.c +++ linux-2.6.27/fs/hostfs/hostfs_kern.c @@ -500,7 +500,7 @@ { pgoff_t index = pos >> PAGE_CACHE_SHIFT; - *pagep = __grab_cache_page(mapping, index); + *pagep = grab_cache_page_write_begin(mapping, index, flags); if (!*pagep) return -ENOMEM; return 0; --- linux-2.6.27.orig/fs/gfs2/ops_address.c +++ linux-2.6.27/fs/gfs2/ops_address.c @@ -675,7 +675,7 @@ goto out_trans_fail; error = -ENOMEM; - page = __grab_cache_page(mapping, index); + page = grab_cache_page_write_begin(mapping, index, flags); *pagep = page; if (unlikely(!page)) goto out_endtrans; --- linux-2.6.27.orig/fs/nfsd/vfs.c +++ linux-2.6.27/fs/nfsd/vfs.c @@ -388,7 +388,7 @@ err = nfserr_notsync; if (!check_guard || guardtime == inode->i_ctime.tv_sec) { fh_lock(fhp); - host_err = notify_change(dentry, iap); + host_err = notify_change(dentry, fhp->fh_export->ex_path.mnt, iap); err = nfserrno(host_err); fh_unlock(fhp); } @@ -408,11 +408,12 @@ #if defined(CONFIG_NFSD_V2_ACL) || \ defined(CONFIG_NFSD_V3_ACL) || \ defined(CONFIG_NFSD_V4) -static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf) +static ssize_t nfsd_getxattr(struct dentry *dentry, struct vfsmount *mnt, + char *key, void **buf) { ssize_t buflen; - buflen = vfs_getxattr(dentry, key, NULL, 0); + buflen = vfs_getxattr(dentry, mnt, key, NULL, 0, NULL); if (buflen <= 0) return buflen; @@ -420,13 +421,14 @@ if (!*buf) return -ENOMEM; - return vfs_getxattr(dentry, key, *buf, buflen); + return vfs_getxattr(dentry, mnt, key, *buf, buflen, NULL); } #endif #if defined(CONFIG_NFSD_V4) static int -set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key) +set_nfsv4_acl_one(struct dentry *dentry, struct vfsmount *mnt, + struct posix_acl *pacl, char *key) { int len; size_t buflen; @@ -445,7 +447,7 @@ goto out; } - error = vfs_setxattr(dentry, key, buf, len, 0); + error = vfs_setxattr(dentry, mnt, key, buf, len, 0, NULL); out: kfree(buf); return error; @@ -458,6 +460,7 @@ __be32 error; int host_error; struct dentry *dentry; + struct vfsmount *mnt; struct inode *inode; struct posix_acl *pacl = NULL, *dpacl = NULL; unsigned int flags = 0; @@ -468,6 +471,7 @@ return error; dentry = fhp->fh_dentry; + mnt = fhp->fh_export->ex_path.mnt; inode = dentry->d_inode; if (S_ISDIR(inode->i_mode)) flags = NFS4_ACL_DIR; @@ -478,12 +482,14 @@ } else if (host_error < 0) goto out_nfserr; - host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); + host_error = set_nfsv4_acl_one(dentry, mnt, pacl, + POSIX_ACL_XATTR_ACCESS); if (host_error < 0) goto out_release; if (S_ISDIR(inode->i_mode)) - host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); + host_error = set_nfsv4_acl_one(dentry, mnt, dpacl, + POSIX_ACL_XATTR_DEFAULT); out_release: posix_acl_release(pacl); @@ -496,13 +502,13 @@ } static struct posix_acl * -_get_posix_acl(struct dentry *dentry, char *key) +_get_posix_acl(struct dentry *dentry, struct vfsmount *mnt, char *key) { void *buf = NULL; struct posix_acl *pacl = NULL; int buflen; - buflen = nfsd_getxattr(dentry, key, &buf); + buflen = nfsd_getxattr(dentry, mnt, key, &buf); if (!buflen) buflen = -ENODATA; if (buflen <= 0) @@ -514,14 +520,15 @@ } int -nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_acl **acl) +nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, + struct vfsmount *mnt, struct nfs4_acl **acl) { struct inode *inode = dentry->d_inode; int error = 0; struct posix_acl *pacl = NULL, *dpacl = NULL; unsigned int flags = 0; - pacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_ACCESS); + pacl = _get_posix_acl(dentry, mnt, POSIX_ACL_XATTR_ACCESS); if (IS_ERR(pacl) && PTR_ERR(pacl) == -ENODATA) pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); if (IS_ERR(pacl)) { @@ -531,7 +538,7 @@ } if (S_ISDIR(inode->i_mode)) { - dpacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_DEFAULT); + dpacl = _get_posix_acl(dentry, mnt, POSIX_ACL_XATTR_DEFAULT); if (IS_ERR(dpacl) && PTR_ERR(dpacl) == -ENODATA) dpacl = NULL; else if (IS_ERR(dpacl)) { @@ -944,13 +951,13 @@ return err; } -static void kill_suid(struct dentry *dentry) +static void kill_suid(struct dentry *dentry, struct vfsmount *mnt) { struct iattr ia; ia.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; mutex_lock(&dentry->d_inode->i_mutex); - notify_change(dentry, &ia); + notify_change(dentry, mnt, &ia); mutex_unlock(&dentry->d_inode->i_mutex); } @@ -1009,7 +1016,7 @@ /* clear setuid/setgid flag after write */ if (host_err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) - kill_suid(dentry); + kill_suid(dentry, exp->ex_path.mnt); if (host_err >= 0 && stable) { static ino_t last_ino; @@ -1187,6 +1194,7 @@ int type, dev_t rdev, struct svc_fh *resfhp) { struct dentry *dentry, *dchild = NULL; + struct svc_export *exp; struct inode *dirp; __be32 err; __be32 err2; @@ -1204,6 +1212,7 @@ goto out; dentry = fhp->fh_dentry; + exp = fhp->fh_export; dirp = dentry->d_inode; err = nfserr_notdir; @@ -1220,7 +1229,7 @@ host_err = PTR_ERR(dchild); if (IS_ERR(dchild)) goto out_nfserr; - err = fh_compose(resfhp, fhp->fh_export, dchild, fhp); + err = fh_compose(resfhp, exp, dchild, fhp); if (err) goto out; } else { @@ -1270,13 +1279,14 @@ host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); break; case S_IFDIR: - host_err = vfs_mkdir(dirp, dchild, iap->ia_mode); + host_err = vfs_mkdir(dirp, dchild, exp->ex_path.mnt, iap->ia_mode); break; case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: - host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); + host_err = vfs_mknod(dirp, dchild, exp->ex_path.mnt, + iap->ia_mode, rdev); break; } if (host_err < 0) { @@ -1284,7 +1294,7 @@ goto out_nfserr; } - if (EX_ISSYNC(fhp->fh_export)) { + if (EX_ISSYNC(exp)) { err = nfserrno(nfsd_sync_dir(dentry)); write_inode_now(dchild->d_inode, 1); } @@ -1514,6 +1524,7 @@ struct iattr *iap) { struct dentry *dentry, *dnew; + struct svc_export *exp; __be32 err, cerr; int host_err; @@ -1538,6 +1549,7 @@ if (host_err) goto out_nfserr; + exp = fhp->fh_export; if (unlikely(path[plen] != 0)) { char *path_alloced = kmalloc(plen+1, GFP_KERNEL); if (path_alloced == NULL) @@ -1545,14 +1557,16 @@ else { strncpy(path_alloced, path, plen); path_alloced[plen] = 0; - host_err = vfs_symlink(dentry->d_inode, dnew, path_alloced); + host_err = vfs_symlink(dentry->d_inode, dnew, + exp->ex_path.mnt, path_alloced); kfree(path_alloced); } } else - host_err = vfs_symlink(dentry->d_inode, dnew, path); + host_err = vfs_symlink(dentry->d_inode, dnew, exp->ex_path.mnt, + path); if (!host_err) { - if (EX_ISSYNC(fhp->fh_export)) + if (EX_ISSYNC(exp)) host_err = nfsd_sync_dir(dentry); } err = nfserrno(host_err); @@ -1560,7 +1574,7 @@ mnt_drop_write(fhp->fh_export->ex_path.mnt); - cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp); + cerr = fh_compose(resfhp, exp, dnew, fhp); dput(dnew); if (err==0) err = cerr; out: @@ -1615,7 +1629,8 @@ err = nfserrno(host_err); goto out_dput; } - host_err = vfs_link(dold, dirp, dnew); + host_err = vfs_link(dold, tfhp->fh_export->ex_path.mnt, dirp, + dnew, ffhp->fh_export->ex_path.mnt); if (!host_err) { if (EX_ISSYNC(ffhp->fh_export)) { err = nfserrno(nfsd_sync_dir(ddir)); @@ -1716,7 +1731,8 @@ if (host_err) goto out_dput_new; - host_err = vfs_rename(fdir, odentry, tdir, ndentry); + host_err = vfs_rename(fdir, odentry, ffhp->fh_export->ex_path.mnt, + tdir, ndentry, tfhp->fh_export->ex_path.mnt); if (!host_err && EX_ISSYNC(tfhp->fh_export)) { host_err = nfsd_sync_dir(tdentry); if (!host_err) @@ -1754,6 +1770,7 @@ char *fname, int flen) { struct dentry *dentry, *rdentry; + struct svc_export *exp; struct inode *dirp; __be32 err; int host_err; @@ -1768,6 +1785,7 @@ fh_lock_nested(fhp, I_MUTEX_PARENT); dentry = fhp->fh_dentry; dirp = dentry->d_inode; + exp = fhp->fh_export; rdentry = lookup_one_len(fname, dentry, flen); host_err = PTR_ERR(rdentry); @@ -1789,21 +1807,21 @@ if (type != S_IFDIR) { /* It's UNLINK */ #ifdef MSNFS - if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && + if ((exp->ex_flags & NFSEXP_MSNFS) && (atomic_read(&rdentry->d_count) > 1)) { host_err = -EPERM; } else #endif - host_err = vfs_unlink(dirp, rdentry); + host_err = vfs_unlink(dirp, rdentry, exp->ex_path.mnt); } else { /* It's RMDIR */ - host_err = vfs_rmdir(dirp, rdentry); + host_err = vfs_rmdir(dirp, rdentry, exp->ex_path.mnt); } dput(rdentry); if (host_err) goto out_drop; - if (EX_ISSYNC(fhp->fh_export)) + if (EX_ISSYNC(exp)) host_err = nfsd_sync_dir(dentry); out_drop: @@ -2036,7 +2054,8 @@ return ERR_PTR(-EOPNOTSUPP); } - size = nfsd_getxattr(fhp->fh_dentry, name, &value); + size = nfsd_getxattr(fhp->fh_dentry, fhp->fh_export->ex_path.mnt, name, + &value); if (size < 0) return ERR_PTR(size); @@ -2048,6 +2067,7 @@ int nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl) { + struct vfsmount *mnt; struct inode *inode = fhp->fh_dentry->d_inode; char *name; void *value = NULL; @@ -2080,21 +2100,24 @@ } else size = 0; - error = mnt_want_write(fhp->fh_export->ex_path.mnt); + mnt = fhp->fh_export->ex_path.mnt; + error = mnt_want_write(mnt); if (error) goto getout; if (size) - error = vfs_setxattr(fhp->fh_dentry, name, value, size, 0); + error = vfs_setxattr(fhp->fh_dentry, mnt, name, value, size, 0, + NULL); else { if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT) error = 0; else { - error = vfs_removexattr(fhp->fh_dentry, name); + error = vfs_removexattr(fhp->fh_dentry, mnt, name, + NULL); if (error == -ENODATA) error = 0; } } - mnt_drop_write(fhp->fh_export->ex_path.mnt); + mnt_drop_write(mnt); getout: kfree(value); --- linux-2.6.27.orig/fs/nfsd/nfs4state.c +++ linux-2.6.27/fs/nfsd/nfs4state.c @@ -2767,6 +2767,25 @@ } /* + * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN, + * so we do a temporary open here just to get an open file to pass to + * vfs_test_lock. (Arguably perhaps test_lock should be done with an + * inode operation.) + */ +static int nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) +{ + struct file *file; + int err; + + err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); + if (err) + return err; + err = vfs_test_lock(file, lock); + nfsd_close(file); + return err; +} + +/* * LOCKT operation */ __be32 @@ -2774,7 +2793,6 @@ struct nfsd4_lockt *lockt) { struct inode *inode; - struct file file; struct file_lock file_lock; int error; __be32 status; @@ -2822,7 +2840,6 @@ file_lock.fl_owner = (fl_owner_t)lockt->lt_stateowner; file_lock.fl_pid = current->tgid; file_lock.fl_flags = FL_POSIX; - file_lock.fl_lmops = &nfsd_posix_mng_ops; file_lock.fl_start = lockt->lt_offset; if ((lockt->lt_length == ~(u64)0) || LOFF_OVERFLOW(lockt->lt_offset, lockt->lt_length)) @@ -2832,16 +2849,8 @@ nfs4_transform_lock_offset(&file_lock); - /* vfs_test_lock uses the struct file _only_ to resolve the inode. - * since LOCKT doesn't require an OPEN, and therefore a struct - * file may not exist, pass vfs_test_lock a struct file with - * only the dentry:inode set. - */ - memset(&file, 0, sizeof (struct file)); - file.f_path.dentry = cstate->current_fh.fh_dentry; - status = nfs_ok; - error = vfs_test_lock(&file, &file_lock); + error = nfsd_test_lock(rqstp, &cstate->current_fh, &file_lock); if (error) { status = nfserrno(error); goto out; --- linux-2.6.27.orig/fs/nfsd/nfs4recover.c +++ linux-2.6.27/fs/nfsd/nfs4recover.c @@ -158,7 +158,8 @@ status = mnt_want_write(rec_dir.path.mnt); if (status) goto out_put; - status = vfs_mkdir(rec_dir.path.dentry->d_inode, dentry, S_IRWXU); + status = vfs_mkdir(rec_dir.path.dentry->d_inode, dentry, + rec_dir.path.mnt, S_IRWXU); mnt_drop_write(rec_dir.path.mnt); out_put: dput(dentry); @@ -263,7 +264,7 @@ return -EINVAL; } mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); - status = vfs_unlink(dir->d_inode, dentry); + status = vfs_unlink(dir->d_inode, dentry, rec_dir.path.mnt); mutex_unlock(&dir->d_inode->i_mutex); return status; } @@ -278,7 +279,7 @@ * a kernel from the future.... */ nfsd4_list_rec_dir(dentry, nfsd4_remove_clid_file); mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); - status = vfs_rmdir(dir->d_inode, dentry); + status = vfs_rmdir(dir->d_inode, dentry, rec_dir.path.mnt); mutex_unlock(&dir->d_inode->i_mutex); return status; } --- linux-2.6.27.orig/fs/nfsd/nfs4xdr.c +++ linux-2.6.27/fs/nfsd/nfs4xdr.c @@ -1446,7 +1446,7 @@ } if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT | FATTR4_WORD0_SUPPORTED_ATTRS)) { - err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl); + err = nfsd4_get_nfs4_acl(rqstp, dentry, exp->ex_path.mnt, &acl); aclsupport = (err == 0); if (bmval0 & FATTR4_WORD0_ACL) { if (err == -EOPNOTSUPP) --- linux-2.6.27.orig/init/initramfs.c +++ linux-2.6.27/init/initramfs.c @@ -6,6 +6,9 @@ #include #include #include +#ifdef ACPI_CONFIG +#include +#endif static __initdata char *message; static void __init error(char *x) @@ -80,6 +83,12 @@ static __initdata uid_t uid; static __initdata gid_t gid; static __initdata unsigned rdev; +#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD +static __initdata char *file_looked_for; +static __initdata struct acpi_table_header *file_mem; +#else +const char *file_looked_for = NULL; +#endif static void __init parse_header(char *s) { @@ -113,6 +122,7 @@ SkipIt, GotName, CopyFile, + CopyFileMem, GotSymlink, Reset } state, next_state; @@ -249,6 +259,54 @@ static __initdata int wfd; +#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD +static __init int is_file_looked_for(char *filename) +{ + char *tmp_collected = collected; + if (file_looked_for == NULL) + return 0; + if (!S_ISREG(mode)) + return 0; + /* remove the leading / */ + while (*tmp_collected == '/') + tmp_collected++; + return (strcmp(tmp_collected, file_looked_for) == 0); +} + +static int __init do_copy_mem(void) +{ + static void *file_current; /* current position in the memory */ + if (file_mem == NULL) { + if (body_len < 4) { /* check especially against empty files */ + error("file is less than 4 bytes"); + return 1; + } + file_mem = kmalloc(body_len, GFP_ATOMIC); + if (!file_mem) { + error("failed to allocate enough memory"); + return 1; + } + file_current = file_mem; + } + if (count >= body_len) { + memcpy(file_current, victim, body_len); + eat(body_len); + file_looked_for = NULL; /* don't find files with same name */ + state = SkipIt; + return 0; + } else { + memcpy(file_current, victim, count); + file_current += count; + body_len -= count; + eat(count); + return 1; + } +} +#else +static inline int is_file_looked_for(char *filename) {return 0;} +#define do_copy_mem NULL /* because it is used as a pointer */ +#endif + static int __init do_name(void) { state = SkipIt; @@ -257,6 +315,8 @@ free_hash(); return 0; } + if (is_file_looked_for(file_looked_for)) + state = CopyFileMem; if (dry_run) return 0; clean_path(collected, mode); @@ -323,6 +383,7 @@ [SkipIt] = do_skip, [GotName] = do_name, [CopyFile] = do_copy, + [CopyFileMem] = do_copy_mem, [GotSymlink] = do_symlink, [Reset] = do_reset, }; @@ -560,3 +621,31 @@ return 0; } rootfs_initcall(populate_rootfs); + +#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD +struct __init acpi_table_header *acpi_find_dsdt_initrd(void) +{ + char *err, *ramfs_dsdt_name = "DSDT.aml"; + + printk(KERN_INFO "ACPI: Checking initramfs for custom DSDT\n"); + file_mem = NULL; + file_looked_for = ramfs_dsdt_name; + err = unpack_to_rootfs((char *)initrd_start, + initrd_end - initrd_start, 1); + file_looked_for = NULL; + + if (err) { + /* + * Even if reading the DSDT file was successful, + * we give up if the initramfs cannot be entirely read. + */ + kfree(file_mem); + printk(KERN_ERR "ACPI: Aborted because %s.\n", err); + return NULL; + } + if (file_mem) + printk(KERN_INFO "ACPI: Found DSDT in %s.\n", ramfs_dsdt_name); + + return file_mem; +} +#endif --- linux-2.6.27.orig/init/Kconfig +++ linux-2.6.27/init/Kconfig @@ -101,6 +101,15 @@ which is done within the script "scripts/setlocalversion".) +config VERSION_SIGNATURE + string "Arbitrary version signature" + help + This string will be created in a file, /proc/version_signature. It + is useful in determining arbitrary data about your kernel. For instance, + if you have several kernels of the same version, but need to keep track + of a revision of the same kernel, but not affect it's ability to load + compatible modules, this is the easiest way to do that. + config SWAP bool "Support for paging of anonymous memory (swap)" depends on MMU && BLOCK --- linux-2.6.27.orig/init/version.c +++ linux-2.6.27/init/version.c @@ -39,7 +39,11 @@ /* FIXED STRINGS! Don't touch! */ const char linux_banner[] = "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" - LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n"; + LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION +#ifdef CONFIG_VERSION_SIGNATURE + " (" CONFIG_VERSION_SIGNATURE ")" +#endif + "\n"; const char linux_proc_banner[] = "%s version %s" --- linux-2.6.27.orig/init/do_mounts_rd.c +++ linux-2.6.27/init/do_mounts_rd.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -37,6 +38,7 @@ * numbers could not be found. * * We currently check for the following magic numbers: + * squashfs * minix * ext2 * romfs @@ -51,6 +53,7 @@ struct ext2_super_block *ext2sb; struct romfs_super_block *romfsb; struct cramfs_super *cramfsb; + struct squashfs_super_block *squashfsb; int nblocks = -1; unsigned char *buf; @@ -62,6 +65,7 @@ ext2sb = (struct ext2_super_block *) buf; romfsb = (struct romfs_super_block *) buf; cramfsb = (struct cramfs_super *) buf; + squashfsb = (struct squashfs_super_block *) buf; memset(buf, 0xe5, size); /* @@ -99,6 +103,18 @@ goto done; } + /* squashfs is at block zero too */ + if (squashfsb->s_magic == SQUASHFS_MAGIC) { + printk(KERN_NOTICE + "RAMDISK: squashfs filesystem found at block %d\n", + start_block); + if (squashfsb->s_major < 3) + nblocks = (squashfsb->bytes_used_2+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; + else + nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; + goto done; + } + /* * Read block 1 to test for minix and ext2 superblock */ --- linux-2.6.27.orig/ipc/util.c +++ linux-2.6.27/ipc/util.c @@ -266,9 +266,17 @@ if (ids->in_use >= size) return -ENOSPC; + spin_lock_init(&new->lock); + new->deleted = 0; + rcu_read_lock(); + spin_lock(&new->lock); + err = idr_get_new(&ids->ipcs_idr, new, &id); - if (err) + if (err) { + spin_unlock(&new->lock); + rcu_read_unlock(); return err; + } ids->in_use++; @@ -280,10 +288,6 @@ ids->seq = 0; new->id = ipc_buildid(id, new->seq); - spin_lock_init(&new->lock); - new->deleted = 0; - rcu_read_lock(); - spin_lock(&new->lock); return id; } --- linux-2.6.27.orig/ipc/sem.c +++ linux-2.6.27/ipc/sem.c @@ -308,7 +308,7 @@ return 0; } -asmlinkage long sys_semget(key_t key, int nsems, int semflg) +SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg) { struct ipc_namespace *ns; struct ipc_ops sem_ops; @@ -887,7 +887,7 @@ return err; } -asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg) +SYSCALL_DEFINE(semctl)(int semid, int semnum, int cmd, union semun arg) { int err = -EINVAL; int version; @@ -923,6 +923,13 @@ return -EINVAL; } } +#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS +asmlinkage long SyS_semctl(int semid, int semnum, int cmd, union semun arg) +{ + return SYSC_semctl((int) semid, (int) semnum, (int) cmd, arg); +} +SYSCALL_ALIAS(sys_semctl, SyS_semctl); +#endif /* If the task doesn't already have a undo_list, then allocate one * here. We guarantee there is only one thread using this undo list, @@ -1048,8 +1055,8 @@ return un; } -asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops, - unsigned nsops, const struct timespec __user *timeout) +SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, + unsigned, nsops, const struct timespec __user *, timeout) { int error = -EINVAL; struct sem_array *sma; @@ -1226,7 +1233,8 @@ return error; } -asmlinkage long sys_semop (int semid, struct sembuf __user *tsops, unsigned nsops) +SYSCALL_DEFINE3(semop, int, semid, struct sembuf __user *, tsops, + unsigned, nsops) { return sys_semtimedop(semid, tsops, nsops, NULL); } --- linux-2.6.27.orig/ipc/mqueue.c +++ linux-2.6.27/ipc/mqueue.c @@ -647,8 +647,8 @@ return dentry_open(dentry, mqueue_mnt, oflag); } -asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode, - struct mq_attr __user *u_attr) +SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, + struct mq_attr __user *, u_attr) { struct dentry *dentry; struct file *filp; @@ -715,7 +715,7 @@ return fd; } -asmlinkage long sys_mq_unlink(const char __user *u_name) +SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name) { int err; char *name; @@ -745,7 +745,7 @@ err = mnt_want_write(mqueue_mnt); if (err) goto out_err; - err = vfs_unlink(dentry->d_parent->d_inode, dentry); + err = vfs_unlink(dentry->d_parent->d_inode, dentry, mqueue_mnt); mnt_drop_write(mqueue_mnt); out_err: dput(dentry); @@ -808,9 +808,9 @@ sender->state = STATE_READY; } -asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr, - size_t msg_len, unsigned int msg_prio, - const struct timespec __user *u_abs_timeout) +SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr, + size_t, msg_len, unsigned int, msg_prio, + const struct timespec __user *, u_abs_timeout) { struct file *filp; struct inode *inode; @@ -896,9 +896,9 @@ return ret; } -asmlinkage ssize_t sys_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr, - size_t msg_len, unsigned int __user *u_msg_prio, - const struct timespec __user *u_abs_timeout) +SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr, + size_t, msg_len, unsigned int __user *, u_msg_prio, + const struct timespec __user *, u_abs_timeout) { long timeout; ssize_t ret; @@ -981,8 +981,8 @@ * and he isn't currently owner of notification, will be silently discarded. * It isn't explicitly defined in the POSIX. */ -asmlinkage long sys_mq_notify(mqd_t mqdes, - const struct sigevent __user *u_notification) +SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes, + const struct sigevent __user *, u_notification) { int ret; struct file *filp; @@ -1107,9 +1107,9 @@ return ret; } -asmlinkage long sys_mq_getsetattr(mqd_t mqdes, - const struct mq_attr __user *u_mqstat, - struct mq_attr __user *u_omqstat) +SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes, + const struct mq_attr __user *, u_mqstat, + struct mq_attr __user *, u_omqstat) { int ret; struct mq_attr mqstat, omqstat; --- linux-2.6.27.orig/ipc/shm.c +++ linux-2.6.27/ipc/shm.c @@ -440,7 +440,7 @@ return 0; } -asmlinkage long sys_shmget (key_t key, size_t size, int shmflg) +SYSCALL_DEFINE3(shmget, key_t, key, size_t, size, int, shmflg) { struct ipc_namespace *ns; struct ipc_ops shm_ops; @@ -565,11 +565,15 @@ struct hstate *h = hstate_file(shp->shm_file); *rss += pages_per_huge_page(h) * mapping->nrpages; } else { +#ifdef CONFIG_SHMEM struct shmem_inode_info *info = SHMEM_I(inode); spin_lock(&info->lock); *rss += inode->i_mapping->nrpages; *swp += info->swapped; spin_unlock(&info->lock); +#else + *rss += inode->i_mapping->nrpages; +#endif } total++; @@ -621,7 +625,7 @@ return err; } -asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf) +SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) { struct shmid_kernel *shp; int err, version; @@ -941,7 +945,7 @@ goto out_nattch; } -asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg) +SYSCALL_DEFINE3(shmat, int, shmid, char __user *, shmaddr, int, shmflg) { unsigned long ret; long err; @@ -957,7 +961,7 @@ * detach and kill segment if marked destroyed. * The work is done in shm_close. */ -asmlinkage long sys_shmdt(char __user *shmaddr) +SYSCALL_DEFINE1(shmdt, char __user *, shmaddr) { struct mm_struct *mm = current->mm; struct vm_area_struct *vma, *next; --- linux-2.6.27.orig/ipc/msg.c +++ linux-2.6.27/ipc/msg.c @@ -309,7 +309,7 @@ return security_msg_queue_associate(msq, msgflg); } -asmlinkage long sys_msgget(key_t key, int msgflg) +SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg) { struct ipc_namespace *ns; struct ipc_ops msg_ops; @@ -466,7 +466,7 @@ return err; } -asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) +SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf) { struct msg_queue *msq; int err, version; @@ -723,8 +723,8 @@ return err; } -asmlinkage long -sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg) +SYSCALL_DEFINE4(msgsnd, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz, + int, msgflg) { long mtype; @@ -904,8 +904,8 @@ return msgsz; } -asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz, - long msgtyp, int msgflg) +SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz, + long, msgtyp, int, msgflg) { long err, mtype; --- linux-2.6.27.orig/sound/soc/omap/omap-pcm.c +++ linux-2.6.27/sound/soc/omap/omap-pcm.c @@ -231,7 +231,7 @@ if (ret < 0) goto out; - prtd = kzalloc(sizeof(prtd), GFP_KERNEL); + prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); if (prtd == NULL) { ret = -ENOMEM; goto out; --- linux-2.6.27.orig/sound/pci/hda/hda_proc.c +++ linux-2.6.27/sound/pci/hda/hda_proc.c @@ -216,7 +216,7 @@ unsigned int caps, val; caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); - snd_iprintf(buffer, " Pincap 0x08%x:", caps); + snd_iprintf(buffer, " Pincap 0x%08x:", caps); if (caps & AC_PINCAP_IN) snd_iprintf(buffer, " IN"); if (caps & AC_PINCAP_OUT) --- linux-2.6.27.orig/sound/pci/hda/patch_realtek.c +++ linux-2.6.27/sound/pci/hda/patch_realtek.c @@ -100,6 +100,7 @@ ALC262_BENQ_T31, ALC262_ULTRA, ALC262_LENOVO_3000, + ALC262_NEC, ALC262_AUTO, ALC262_MODEL_LAST /* last tag */ }; @@ -291,6 +292,13 @@ /* for PLL fix */ hda_nid_t pll_nid; unsigned int pll_coef_idx, pll_coef_bit; + +#ifdef SND_HDA_NEEDS_RESUME +#define ALC_MAX_PINS 16 + unsigned int num_pins; + hda_nid_t pin_nids[ALC_MAX_PINS]; + unsigned int pin_cfgs[ALC_MAX_PINS]; +#endif }; /* @@ -912,6 +920,7 @@ case 0x10ec0267: case 0x10ec0268: case 0x10ec0269: + case 0x10ec0272: case 0x10ec0660: case 0x10ec0662: case 0x10ec0663: @@ -940,6 +949,7 @@ case 0x10ec0882: case 0x10ec0883: case 0x10ec0885: + case 0x10ec0887: case 0x10ec0889: snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7); @@ -2722,6 +2732,64 @@ codec->spec = NULL; /* to be sure */ } +#ifdef SND_HDA_NEEDS_RESUME +static void store_pin_configs(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t nid, end_nid; + + end_nid = codec->start_nid + codec->num_nodes; + for (nid = codec->start_nid; nid < end_nid; nid++) { + unsigned int wid_caps = get_wcaps(codec, nid); + unsigned int wid_type = + (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + if (wid_type != AC_WID_PIN) + continue; + if (spec->num_pins >= ARRAY_SIZE(spec->pin_nids)) + break; + spec->pin_nids[spec->num_pins] = nid; + spec->pin_cfgs[spec->num_pins] = + snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONFIG_DEFAULT, 0); + spec->num_pins++; + } +} + +static void resume_pin_configs(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->num_pins; i++) { + hda_nid_t pin_nid = spec->pin_nids[i]; + unsigned int pin_config = spec->pin_cfgs[i]; + snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, + pin_config & 0x000000ff); + snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, + (pin_config & 0x0000ff00) >> 8); + snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, + (pin_config & 0x00ff0000) >> 16); + snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, + pin_config >> 24); + } +} + +static int alc_resume(struct hda_codec *codec) +{ + resume_pin_configs(codec); + codec->patch_ops.init(codec); + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); + return 0; +} +#else +#define store_pin_configs(codec) +#endif + /* */ static struct hda_codec_ops alc_patch_ops = { @@ -2730,6 +2798,9 @@ .init = alc_init, .free = alc_free, .unsol_event = alc_unsol_event, +#ifdef SND_HDA_NEEDS_RESUME + .resume = alc_resume, +#endif #ifdef CONFIG_SND_HDA_POWER_SAVE .check_power_status = alc_check_power_status, #endif @@ -3776,6 +3847,7 @@ spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; + store_pin_configs(codec); return 1; } @@ -5124,6 +5196,7 @@ } spec->num_mixers++; + store_pin_configs(codec); return 1; } @@ -6554,16 +6627,19 @@ board_config = ALC885_MACPRO; break; case 0x106b1000: /* iMac 24 */ + case 0x106b2800: /* AppleTV */ board_config = ALC885_IMAC24; break; case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */ case 0x106b2c00: /* Macbook Pro rev3 */ case 0x106b3600: /* Macbook 3.1 */ + case 0x106b3800: /* MacbookPro4,1 - latter revision */ board_config = ALC885_MBP3; break; default: /* ALC889A is handled better as ALC888-compatible */ - if (codec->revision_id == 0x100103) { + if (codec->revision_id == 0x100101 || + codec->revision_id == 0x100103) { alc_free(codec); return patch_alc883(codec); } @@ -7940,6 +8016,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG), SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE), @@ -7950,6 +8027,7 @@ SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1043, 0x8284, "ASUS Z37E", ALC883_6ST_DIG), SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG), SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC), @@ -7984,12 +8062,15 @@ SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD), SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), + SND_PCI_QUIRK(0x1734, 0x1107, "FSC AMILO Xi2550", + ALC883_FUJITSU_PI2515), SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515), SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch), SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763), SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763), SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2), + SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG), SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL), @@ -8948,6 +9029,41 @@ } /* + * nec model + * 0x15 = headphone + * 0x16 = internal speaker + * 0x18 = external mic + */ + +static struct snd_kcontrol_new alc262_nec_mixer[] = { + HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static struct hda_verb alc262_nec_verbs[] = { + /* Unmute Speaker */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Headphone */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + /* External mic to headphone */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + /* External mic to speaker */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {} +}; + +/* * fujitsu model * 0x14 = headphone/spdif-out, 0x15 = internal speaker, * 0x1b = port replicator headphone out @@ -9693,6 +9809,7 @@ if (err < 0) return err; + store_pin_configs(codec); return 1; } @@ -9731,11 +9848,13 @@ [ALC262_SONY_ASSAMD] = "sony-assamd", [ALC262_ULTRA] = "ultra", [ALC262_LENOVO_3000] = "lenovo-3000", + [ALC262_NEC] = "nec", [ALC262_AUTO] = "auto", }; static struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO), + SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC), SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC), SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC), SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC), @@ -9769,6 +9888,7 @@ SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU), SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA), SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA), + SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO), SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000), SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31), @@ -9946,6 +10066,16 @@ .input_mux = &alc262_fujitsu_capture_source, .unsol_event = alc262_lenovo_3000_unsol_event, }, + [ALC262_NEC] = { + .mixers = { alc262_nec_mixer }, + .init_verbs = { alc262_nec_verbs }, + .num_dacs = ARRAY_SIZE(alc262_dac_nids), + .dac_nids = alc262_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc262_modes), + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + }, }; static int patch_alc262(struct hda_codec *codec) @@ -10712,6 +10842,7 @@ if (err < 0) return err; + store_pin_configs(codec); return 1; } @@ -10758,6 +10889,7 @@ SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA), SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA), + SND_PCI_QUIRK(0x1179, 0xff64, "TOSHIBA L305", ALC268_TOSHIBA), SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA), SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER), SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1), @@ -10990,6 +11122,14 @@ 0x08, }; +static hda_nid_t alc269_capsrc_nids[1] = { + 0x23, +}; + +/* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24), + * not a mux! + */ + static struct hda_input_mux alc269_eeepc_dmic_capture_source = { .num_items = 2, .items = { @@ -11356,6 +11496,10 @@ spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs; spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; + /* set default input source */ + snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0], + 0, AC_VERB_SET_CONNECT_SEL, + spec->input_mux->items[0].index); err = alc_auto_add_mic_boost(codec); if (err < 0) @@ -11364,6 +11508,7 @@ spec->mixers[spec->num_mixers] = alc269_capture_mixer; spec->num_mixers++; + store_pin_configs(codec); return 1; } @@ -11488,6 +11633,7 @@ spec->adc_nids = alc269_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); + spec->capsrc_nids = alc269_capsrc_nids; codec->patch_ops = alc_patch_ops; if (board_config == ALC269_AUTO) @@ -12431,6 +12577,7 @@ spec->mixers[spec->num_mixers] = alc861_capture_mixer; spec->num_mixers++; + store_pin_configs(codec); return 1; } @@ -13542,6 +13689,7 @@ if (err < 0) return err; + store_pin_configs(codec); return 1; } @@ -14789,6 +14937,8 @@ spec->mixers[spec->num_mixers] = alc662_capture_mixer; spec->num_mixers++; + + store_pin_configs(codec); return 1; } @@ -14846,6 +14996,9 @@ if (codec->vendor_id == 0x10ec0663) { spec->stream_name_analog = "ALC663 Analog"; spec->stream_name_digital = "ALC663 Digital"; + } else if (codec->vendor_id == 0x10ec0272) { + spec->stream_name_analog = "ALC272 Analog"; + spec->stream_name_digital = "ALC272 Digital"; } else { spec->stream_name_analog = "ALC662 Analog"; spec->stream_name_digital = "ALC662 Digital"; @@ -14883,6 +15036,7 @@ { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 }, { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 }, { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 }, + { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 }, { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", .patch = patch_alc861 }, { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, @@ -14896,9 +15050,12 @@ { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 }, + { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A", + .patch = patch_alc882 }, /* should be patch_alc883() in future */ { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A", .patch = patch_alc882 }, /* should be patch_alc883() in future */ { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, + { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc883 }, { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 }, { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 }, {} /* terminator */ --- linux-2.6.27.orig/sound/pci/hda/patch_conexant.c +++ linux-2.6.27/sound/pci/hda/patch_conexant.c @@ -1470,6 +1470,7 @@ SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP), SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2000Z", CXT5047_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6700", CXT5047_LAPTOP), SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD), {} }; --- linux-2.6.27.orig/sound/pci/hda/patch_analog.c +++ linux-2.6.27/sound/pci/hda/patch_analog.c @@ -629,6 +629,36 @@ HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = ad198x_mux_enum_info, + .get = ad198x_mux_enum_get, + .put = ad198x_mux_enum_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "External Amplifier", + .info = ad198x_eapd_info, + .get = ad198x_eapd_get, + .put = ad198x_eapd_put, + .private_value = 0x1b | (1 << 8), /* port-D, inversed */ + }, + { } /* end */ +}; + +static struct snd_kcontrol_new ad1986a_samsung_mixers[] = { + HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), + HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), + HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), @@ -917,6 +947,7 @@ AD1986A_LAPTOP_EAPD, AD1986A_LAPTOP_AUTOMUTE, AD1986A_ULTRA, + AD1986A_SAMSUNG, AD1986A_MODELS }; @@ -927,6 +958,7 @@ [AD1986A_LAPTOP_EAPD] = "laptop-eapd", [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", [AD1986A_ULTRA] = "ultra", + [AD1986A_SAMSUNG] = "samsung", }; static struct snd_pci_quirk ad1986a_cfg_tbl[] = { @@ -949,9 +981,9 @@ SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD), SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), - SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_SAMSUNG), + SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_SAMSUNG), + SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_SAMSUNG), SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), @@ -1033,6 +1065,17 @@ break; case AD1986A_LAPTOP_EAPD: spec->mixers[0] = ad1986a_laptop_eapd_mixers; + spec->num_init_verbs = 2; + spec->init_verbs[1] = ad1986a_eapd_init_verbs; + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = ad1986a_laptop_dac_nids; + if (!is_jack_available(codec, 0x25)) + spec->multiout.dig_out_nid = 0; + spec->input_mux = &ad1986a_laptop_eapd_capture_source; + break; + case AD1986A_SAMSUNG: + spec->mixers[0] = ad1986a_samsung_mixers; spec->num_init_verbs = 3; spec->init_verbs[1] = ad1986a_eapd_init_verbs; spec->init_verbs[2] = ad1986a_automic_verbs; @@ -2247,8 +2290,12 @@ /* AD1989 has no ADC -> SPDIF route */ static struct hda_verb ad1989_spdif_init_verbs[] = { - /* SPDIF out pin */ + /* SPDIF-1 out pin */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ + /* SPDIF-2/HDMI out pin */ + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ { } }; @@ -2868,6 +2915,7 @@ SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG), SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG), SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG), + SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG), {} }; @@ -3842,6 +3890,10 @@ static struct snd_pci_quirk ad1884a_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), + SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE), + SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x3614, "HP 6730s", AD1884A_LAPTOP), SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), {} }; --- linux-2.6.27.orig/sound/pci/hda/patch_sigmatel.c +++ linux-2.6.27/sound/pci/hda/patch_sigmatel.c @@ -66,7 +66,10 @@ enum { STAC_92HD73XX_REF, - STAC_DELL_M6, + STAC_DELL_M6_AMIC, + STAC_DELL_M6_DMIC, + STAC_DELL_M6_BOTH, + STAC_DELL_EQ, STAC_92HD73XX_MODELS }; @@ -74,6 +77,7 @@ STAC_92HD71BXX_REF, STAC_DELL_M4_1, STAC_DELL_M4_2, + STAC_DELL_M4_3, STAC_92HD71BXX_MODELS }; @@ -104,6 +108,7 @@ STAC_MACBOOK_PRO_V2, STAC_IMAC_INTEL, STAC_IMAC_INTEL_20, + STAC_ECS_202, STAC_922X_DELL_D81, STAC_922X_DELL_D82, STAC_922X_DELL_M81, @@ -125,6 +130,7 @@ unsigned int num_mixers; int board_config; + unsigned int eapd_switch: 1; unsigned int surr_switch: 1; unsigned int line_switch: 1; unsigned int mic_switch: 1; @@ -546,8 +552,8 @@ { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec}, /* setup audio connections */ { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, - { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02}, + { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x02}, + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01}, /* setup adcs to point to mixer */ { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, @@ -560,9 +566,7 @@ }; static struct hda_verb dell_m6_core_init[] = { - /* set master volume to max value without distortion - * and direct control */ - { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec}, + { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, /* setup audio connections */ { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, @@ -638,6 +642,7 @@ { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {} }; #define HD_DISABLE_PORTF 3 @@ -1296,12 +1301,18 @@ static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = { [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs, - [STAC_DELL_M6] = dell_m6_pin_configs, + [STAC_DELL_M6_AMIC] = dell_m6_pin_configs, + [STAC_DELL_M6_DMIC] = dell_m6_pin_configs, + [STAC_DELL_M6_BOTH] = dell_m6_pin_configs, + [STAC_DELL_EQ] = dell_m6_pin_configs, }; static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = { [STAC_92HD73XX_REF] = "ref", - [STAC_DELL_M6] = "dell-m6", + [STAC_DELL_M6_AMIC] = "dell-m6-amic", + [STAC_DELL_M6_DMIC] = "dell-m6-dmic", + [STAC_DELL_M6_BOTH] = "dell-m6", + [STAC_DELL_EQ] = "dell-eq", }; static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { @@ -1309,19 +1320,25 @@ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD73XX_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254, - "unknown Dell", STAC_DELL_M6), + "Dell Studio 1535", STAC_DELL_M6_DMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255, - "unknown Dell", STAC_DELL_M6), + "unknown Dell", STAC_DELL_M6_DMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256, - "unknown Dell", STAC_DELL_M6), + "unknown Dell", STAC_DELL_M6_BOTH), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257, - "unknown Dell", STAC_DELL_M6), + "unknown Dell", STAC_DELL_M6_BOTH), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e, - "unknown Dell", STAC_DELL_M6), + "unknown Dell", STAC_DELL_M6_AMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f, - "unknown Dell", STAC_DELL_M6), + "unknown Dell", STAC_DELL_M6_AMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271, - "unknown Dell", STAC_DELL_M6), + "unknown Dell", STAC_DELL_M6_DMIC), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0272, + "unknown Dell", STAC_DELL_M6_DMIC), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x029f, + "Dell Studio 1537", STAC_DELL_M6_DMIC), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a0, + "Dell Studio 17", STAC_DELL_M6_DMIC), {} /* terminator */ }; @@ -1343,10 +1360,17 @@ 0x40f000f0, 0x044413b0, }; +static unsigned int dell_m4_3_pin_configs[11] = { + 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110, + 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a000f0, + 0x40f000f0, 0x044413b0, 0x044413b0, +}; + static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs, [STAC_DELL_M4_1] = dell_m4_1_pin_configs, [STAC_DELL_M4_2] = dell_m4_2_pin_configs, + [STAC_DELL_M4_3] = dell_m4_3_pin_configs, }; static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { @@ -1381,6 +1405,8 @@ "unknown Dell", STAC_DELL_M4_2), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264, "unknown Dell", STAC_DELL_M4_2), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02aa, + "unknown Dell", STAC_DELL_M4_3), {} /* terminator */ }; @@ -1477,6 +1503,11 @@ 0x400000fc, 0x400000fb, }; +static unsigned int ecs202_pin_configs[10] = { + 0x0221401f, 0x02a19020, 0x01a19020, 0x01114010, + 0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1, + 0x9037012e, 0x40e000f2, +}; static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { [STAC_D945_REF] = ref922x_pin_configs, @@ -1495,6 +1526,7 @@ [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs, [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs, [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs, + [STAC_ECS_202] = ecs202_pin_configs, [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs, [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs, [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs, @@ -1518,6 +1550,7 @@ [STAC_MACBOOK_PRO_V2] = "macbook-pro", [STAC_IMAC_INTEL] = "imac-intel", [STAC_IMAC_INTEL_20] = "imac-intel-20", + [STAC_ECS_202] = "ecs202", [STAC_922X_DELL_D81] = "dell-d81", [STAC_922X_DELL_D82] = "dell-d82", [STAC_922X_DELL_M81] = "dell-m81", @@ -1604,6 +1637,33 @@ "unknown Dell", STAC_922X_DELL_D81), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7, "Dell XPS M1210", STAC_922X_DELL_M82), + /* ECS/PC Chips boards */ + SND_PCI_QUIRK(0x1019, 0x2144, + "ECS/PC chips", STAC_ECS_202), + SND_PCI_QUIRK(0x1019, 0x2608, + "ECS/PC chips", STAC_ECS_202), + SND_PCI_QUIRK(0x1019, 0x2633, + "ECS/PC chips P17G/1333", STAC_ECS_202), + SND_PCI_QUIRK(0x1019, 0x2811, + "ECS/PC chips", STAC_ECS_202), + SND_PCI_QUIRK(0x1019, 0x2812, + "ECS/PC chips", STAC_ECS_202), + SND_PCI_QUIRK(0x1019, 0x2813, + "ECS/PC chips", STAC_ECS_202), + SND_PCI_QUIRK(0x1019, 0x2814, + "ECS/PC chips", STAC_ECS_202), + SND_PCI_QUIRK(0x1019, 0x2815, + "ECS/PC chips", STAC_ECS_202), + SND_PCI_QUIRK(0x1019, 0x2816, + "ECS/PC chips", STAC_ECS_202), + SND_PCI_QUIRK(0x1019, 0x2817, + "ECS/PC chips", STAC_ECS_202), + SND_PCI_QUIRK(0x1019, 0x2818, + "ECS/PC chips", STAC_ECS_202), + SND_PCI_QUIRK(0x1019, 0x2819, + "ECS/PC chips", STAC_ECS_202), + SND_PCI_QUIRK(0x1019, 0x2820, + "ECS/PC chips", STAC_ECS_202), {} /* terminator */ }; @@ -2009,6 +2069,8 @@ info->name = "STAC92xx Analog"; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = + spec->multiout.dac_nids[0]; info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs; @@ -2467,7 +2529,7 @@ } } - if (cfg->hp_outs > 1) { + if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) { err = stac92xx_add_control(spec, STAC_CTL_WIDGET_HP_SWITCH, "Headphone as Line Out Switch", 0); @@ -3248,7 +3310,7 @@ for (i = 0; i < cfg->speaker_outs; i++) stac92xx_reset_pinctl(codec, cfg->speaker_pins[i], AC_PINCTL_OUT_EN); - if (spec->eapd_mask) + if (spec->eapd_mask && spec->eapd_switch) stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data & ~spec->eapd_mask); @@ -3262,7 +3324,7 @@ for (i = 0; i < cfg->speaker_outs; i++) stac92xx_set_pinctl(codec, cfg->speaker_pins[i], AC_PINCTL_OUT_EN); - if (spec->eapd_mask) + if (spec->eapd_mask && spec->eapd_switch) stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data | spec->eapd_mask); @@ -3324,6 +3386,16 @@ codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); return 0; } + +static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) +{ + struct sigmatel_spec *spec = codec->spec; + if (spec->eapd_mask) + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data & + ~spec->eapd_mask); + return 0; +} #endif static struct hda_codec_ops stac92xx_patch_ops = { @@ -3334,6 +3406,7 @@ .unsol_event = stac92xx_unsol_event, #ifdef SND_HDA_NEEDS_RESUME .resume = stac92xx_resume, + .suspend = stac92xx_suspend, #endif }; @@ -3560,25 +3633,25 @@ spec->gpio_data = 0x01; switch (spec->board_config) { - case STAC_DELL_M6: + case STAC_DELL_EQ: spec->init = dell_eq_core_init; - switch (codec->subsystem_id) { - case 0x1028025e: /* Analog Mics */ - case 0x1028025f: + /* fallthru */ + case STAC_DELL_M6_AMIC: + case STAC_DELL_M6_DMIC: + case STAC_DELL_M6_BOTH: + if (!spec->init) + spec->init = dell_m6_core_init; + spec->eapd_switch = 0; + switch (spec->board_config) { + case STAC_DELL_M6_AMIC: /* Analog Mics */ stac92xx_set_config_reg(codec, 0x0b, 0x90A70170); spec->num_dmics = 0; break; - case 0x10280271: /* Digital Mics */ - case 0x10280272: - spec->init = dell_m6_core_init; - /* fall-through */ - case 0x10280254: - case 0x10280255: + case STAC_DELL_M6_DMIC: /* Digital Mics */ stac92xx_set_config_reg(codec, 0x13, 0x90A60160); spec->num_dmics = 1; break; - case 0x10280256: /* Both */ - case 0x10280057: + case STAC_DELL_M6_BOTH: /* Both */ stac92xx_set_config_reg(codec, 0x0b, 0x90A70170); stac92xx_set_config_reg(codec, 0x13, 0x90A60160); spec->num_dmics = 1; @@ -3587,6 +3660,7 @@ break; default: spec->num_dmics = STAC92HD73XX_NUM_DMICS; + spec->eapd_switch = 1; } spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids); @@ -3912,6 +3986,7 @@ spec->num_pwrs = 0; spec->aloopback_mask = 0x40; spec->aloopback_shift = 0; + spec->eapd_switch = 1; err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); if (!err) { @@ -3989,6 +4064,7 @@ spec->aloopback_mask = 0x40; spec->aloopback_shift = 0; + spec->eapd_switch = 1; spec->multiout.dac_nids = spec->dac_nids; switch (spec->board_config){ --- linux-2.6.27.orig/sound/pci/hda/hda_intel.c +++ linux-2.6.27/sound/pci/hda/hda_intel.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include "hda_codec.h" @@ -385,6 +386,9 @@ /* for pending irqs */ struct work_struct irq_pending_work; + + /* reboot notifier (for mysterious hangup problem at power-down) */ + struct notifier_block reboot_notifier; }; /* driver types */ @@ -1890,12 +1894,36 @@ /* + * reboot notifier for hang-up problem at power-down + */ +static int azx_halt(struct notifier_block *nb, unsigned long event, void *buf) +{ + struct azx *chip = container_of(nb, struct azx, reboot_notifier); + azx_stop_chip(chip); + return NOTIFY_OK; +} + +static void azx_notifier_register(struct azx *chip) +{ + chip->reboot_notifier.notifier_call = azx_halt; + register_reboot_notifier(&chip->reboot_notifier); +} + +static void azx_notifier_unregister(struct azx *chip) +{ + if (chip->reboot_notifier.notifier_call) + unregister_reboot_notifier(&chip->reboot_notifier); +} + +/* * destructor */ static int azx_free(struct azx *chip) { int i; + azx_notifier_unregister(chip); + if (chip->initialized) { azx_clear_irq_pending(chip); for (i = 0; i < chip->num_streams; i++) @@ -1969,6 +1997,7 @@ SND_PCI_QUIRK(0x1014, 0x05b7, "Thinkpad Z60", 0x01), SND_PCI_QUIRK(0x17aa, 0x2010, "Thinkpad X/T/R60", 0x01), SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01), + SND_PCI_QUIRK(0x1028, 0x0271, "unknown Dell", 0x11), {} }; @@ -2250,6 +2279,7 @@ pci_set_drvdata(pci, card); chip->running = 1; power_down_all_codecs(chip); + azx_notifier_register(chip); dev++; return err; --- linux-2.6.27.orig/sound/pci/emu10k1/emu10k1_main.c +++ linux-2.6.27/sound/pci/emu10k1/emu10k1_main.c @@ -1464,6 +1464,7 @@ .ca0151_chip = 1, .spk71 = 1, .spdif_bug = 1, + .invert_shared_spdif = 1, /* digital/analog switch swapped */ .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20021102, .driver = "Audigy2", .name = "Audigy 2 ZS [SB0350]", @@ -1473,6 +1474,7 @@ .ca0151_chip = 1, .spk71 = 1, .spdif_bug = 1, + .invert_shared_spdif = 1, /* digital/analog switch swapped */ .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20011102, .driver = "Audigy2", .name = "Audigy 2 ZS [2001]", @@ -1482,6 +1484,7 @@ .ca0151_chip = 1, .spk71 = 1, .spdif_bug = 1, + .invert_shared_spdif = 1, /* digital/analog switch swapped */ .ac97_chip = 1} , /* Audigy 2 */ /* Tested by James@superbug.co.uk 3rd July 2005 */ --- linux-2.6.27.orig/sound/pci/oxygen/virtuoso.c +++ linux-2.6.27/sound/pci/oxygen/virtuoso.c @@ -26,7 +26,7 @@ * SPI 0 -> 1st PCM1796 (front) * SPI 1 -> 2nd PCM1796 (surround) * SPI 2 -> 3rd PCM1796 (center/LFE) - * SPI 4 -> 4th PCM1796 (back) + * SPI 4 -> 4th PCM1796 (back) and EEPROM self-destruct (do not use!) * * GPIO 2 -> M0 of CS5381 * GPIO 3 -> M1 of CS5381 @@ -142,6 +142,12 @@ static void pcm1796_write(struct oxygen *chip, unsigned int codec, u8 reg, u8 value) { + /* + * We don't want to do writes on SPI 4 because the EEPROM, which shares + * the same pin, might get confused and broken. We'd better take care + * that the driver works with the default register values ... + */ +#if 0 /* maps ALSA channel pair number to SPI output */ static const u8 codec_map[4] = { 0, 1, 2, 4 @@ -152,6 +158,7 @@ (codec_map[codec] << OXYGEN_SPI_CODEC_SHIFT) | OXYGEN_SPI_CEN_LATCH_CLOCK_HI, (reg << 8) | value); +#endif } static void cs4398_write(struct oxygen *chip, u8 reg, u8 value) @@ -539,6 +546,9 @@ static int xonar_d2_control_filter(struct snd_kcontrol_new *template) { + if (!strncmp(template->name, "Master Playback ", 16)) + /* disable volume/mute because they would require SPI writes */ + return 1; if (!strncmp(template->name, "CD Capture ", 11)) /* CD in is actually connected to the video in pin */ template->private_value ^= AC97_CD ^ AC97_VIDEO; @@ -588,9 +598,8 @@ .dac_volume_min = 0x0f, .dac_volume_max = 0xff, .misc_flags = OXYGEN_MISC_MIDI, - .function_flags = OXYGEN_FUNCTION_SPI | - OXYGEN_FUNCTION_ENABLE_SPI_4_5, - .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, + .function_flags = OXYGEN_FUNCTION_SPI, + .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S, .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }, [MODEL_D2X] = { @@ -619,9 +628,8 @@ .dac_volume_min = 0x0f, .dac_volume_max = 0xff, .misc_flags = OXYGEN_MISC_MIDI, - .function_flags = OXYGEN_FUNCTION_SPI | - OXYGEN_FUNCTION_ENABLE_SPI_4_5, - .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, + .function_flags = OXYGEN_FUNCTION_SPI, + .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S, .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }, [MODEL_D1] = { --- linux-2.6.27.orig/sound/core/control.c +++ linux-2.6.27/sound/core/control.c @@ -1427,12 +1427,12 @@ cardnum = card->number; snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO); - down_read(&card->controls_rwsem); + read_lock(&card->ctl_files_rwlock); list_for_each_entry(ctl, &card->ctl_files, list) { wake_up(&ctl->change_sleep); kill_fasync(&ctl->fasync, SIGIO, POLL_ERR); } - up_read(&card->controls_rwsem); + read_unlock(&card->ctl_files_rwlock); if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1)) < 0) --- linux-2.6.27.orig/sound/usb/usbaudio.c +++ linux-2.6.27/sound/usb/usbaudio.c @@ -2958,6 +2958,7 @@ return -EINVAL; } alts = &iface->altsetting[fp->altset_idx]; + fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); usb_set_interface(chip->dev, fp->iface, 0); init_usb_pitch(chip->dev, fp->iface, alts, fp); init_usb_sample_rate(chip->dev, fp->iface, alts, fp, fp->rate_max); --- linux-2.6.27.orig/sound/usb/caiaq/caiaq-device.h +++ linux-2.6.27/sound/usb/caiaq/caiaq-device.h @@ -75,6 +75,7 @@ wait_queue_head_t ep1_wait_queue; wait_queue_head_t prepare_wait_queue; int spec_received, audio_parm_answer; + int midi_out_active; char vendor_name[CAIAQ_USB_STR_LEN]; char product_name[CAIAQ_USB_STR_LEN]; --- linux-2.6.27.orig/sound/usb/caiaq/caiaq-midi.c +++ linux-2.6.27/sound/usb/caiaq/caiaq-midi.c @@ -59,6 +59,11 @@ static int snd_usb_caiaq_midi_output_close(struct snd_rawmidi_substream *substream) { + struct snd_usb_caiaqdev *dev = substream->rmidi->private_data; + if (dev->midi_out_active) { + usb_kill_urb(&dev->midi_out_urb); + dev->midi_out_active = 0; + } return 0; } @@ -69,7 +74,8 @@ dev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE; dev->midi_out_buf[1] = 0; /* port */ - len = snd_rawmidi_transmit_peek(substream, dev->midi_out_buf+3, EP1_BUFSIZE-3); + len = snd_rawmidi_transmit(substream, dev->midi_out_buf + 3, + EP1_BUFSIZE - 3); if (len <= 0) return; @@ -79,24 +85,24 @@ ret = usb_submit_urb(&dev->midi_out_urb, GFP_ATOMIC); if (ret < 0) - log("snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed, %d\n", - substream, ret); + log("snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed," + "ret=%d, len=%d\n", + substream, ret, len); + else + dev->midi_out_active = 1; } static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) { struct snd_usb_caiaqdev *dev = substream->rmidi->private_data; - if (dev->midi_out_substream != NULL) - return; - - if (!up) { + if (up) { + dev->midi_out_substream = substream; + if (!dev->midi_out_active) + snd_usb_caiaq_midi_send(dev, substream); + } else { dev->midi_out_substream = NULL; - return; } - - dev->midi_out_substream = substream; - snd_usb_caiaq_midi_send(dev, substream); } @@ -161,16 +167,14 @@ void snd_usb_caiaq_midi_output_done(struct urb* urb) { struct snd_usb_caiaqdev *dev = urb->context; - char *buf = urb->transfer_buffer; + dev->midi_out_active = 0; if (urb->status != 0) return; if (!dev->midi_out_substream) return; - snd_rawmidi_transmit_ack(dev->midi_out_substream, buf[2]); - dev->midi_out_substream = NULL; snd_usb_caiaq_midi_send(dev, dev->midi_out_substream); } --- linux-2.6.27.orig/sound/drivers/mtpav.c +++ linux-2.6.27/sound/drivers/mtpav.c @@ -706,7 +706,6 @@ mtp_card->card = card; mtp_card->irq = -1; mtp_card->share_irq = 0; - mtp_card->inmidiport = 0xffffffff; mtp_card->inmidistate = 0; mtp_card->outmidihwport = 0xffffffff; init_timer(&mtp_card->timer); @@ -715,6 +714,8 @@ card->private_free = snd_mtpav_free; + mtp_card->inmidiport = mtp_card->num_ports + MTPAV_PIDX_BROADCAST; + err = snd_mtpav_get_ISA(mtp_card); if (err < 0) goto __error; --- linux-2.6.27.orig/debian/control +++ linux-2.6.27/debian/control @@ -0,0 +1,204 @@ +Source: linux +Section: devel +Priority: optional +Maintainer: Ubuntu Kernel Team +Standards-Version: 3.6.1 +Build-Depends: debhelper (>= 3), module-init-tools, kernel-wedge (>= 2.24ubuntu1), makedumpfile +Build-Depends-Indep: xmlto, docbook-utils, gs, transfig, bzip2, sharutils +Vcs-Git: http://kernel.ubuntu.com/git-repos/ubuntu/ubuntu-intrepid.git + +Package: linux-source-2.6.27 +Architecture: all +Section: devel +Priority: optional +Provides: linux-source, linux-source-2.6 +Depends: binutils, bzip2, coreutils | fileutils (>= 4.0) +Recommends: libc-dev, gcc, make +Suggests: libncurses-dev | ncurses-dev, kernel-package, libqt3-dev +Description: Linux kernel source for version 2.6.27 with Ubuntu patches + This package provides the source code for the Linux kernel version + 2.6.27. + . + This package is mainly meant for other packages to use, in order to build + custom flavours. + . + If you wish to use this package to create a custom Linux kernel, then it + is suggested that you investigate the package kernel-package, which has + been designed to ease the task of creating kernel image packages. + . + If you are simply trying to build third-party modules for your kernel, + you do not want this package. Install the appropriate linux-headers + package instead. + +Package: linux-doc-2.6.27 +Architecture: all +Section: doc +Priority: optional +Provides: linux-doc-2.6 +Conflicts: linux-doc-2.6 +Replaces: linux-doc-2.6 +Depends: coreutils | fileutils (>= 4.0) +Description: Linux kernel specific documentation for version 2.6.27 + This package provides the various readme's in the 2.6.27 kernel + Documentation/ subdirectory: these typically contain kernel-specific + installation notes for some drivers for example. See + /usr/share/doc/linux-doc-2.6.27/Documentation/00-INDEX for a list of what + is contained in each file. Please read the Changes file, as it contains + information about the problems, which may result by upgrading your + kernel. + +Package: linux-headers-2.6.27-14 +Architecture: all +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0) +Provides: linux-headers, linux-headers-2.6 +Description: Header files related to Linux kernel version 2.6.27 + This package provides kernel header files for version 2.6.27, for sites + that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.27-14/debian.README.gz for details + +Package: linux-libc-dev +Architecture: i386 amd64 +Conflicts: libc6-dev (<< 2.3.2.ds1-6), libc6.1-dev (<< 2.3.2.ds1-6), dvb-dev (<< 1.0.1-6), amd64-libs-dev (<= 1.1), linux-kernel-headers +Replaces: libc6-dev (<< 2.3.2.ds1-6), libc6.1-dev (<< 2.3.2.ds1-6), dvb-dev (<< 1.0.1-6), linux-kernel-headers +Provides: linux-kernel-headers +Description: Linux Kernel Headers for development + This package provides headers from the Linux kernel. These headers + are used by the installed headers for GNU glibc and other system + libraries. They are NOT meant to be used to build third-party modules for + your kernel. Use linux-headers-* packages for that. + +Package: linux-image-2.6.27-14-generic +Architecture: i386 amd64 +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, kvm-api-4, redhat-cluster-modules, ivtv-modules, ndiswrapper-modules-1.9 +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: lilo (>= 19.1) | grub +Suggests: fdutils, linux-doc-2.6.27 | linux-source-2.6.27 +Description: Linux kernel image for version 2.6.27 on x86/x86_64 + This package contains the Linux kernel image for version 2.6.27 on + x86/x86_64. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Generic processors. + . + Geared toward desktop systems. + . + You likely do not want to install this package directly. Instead, install + the linux-generic meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.27-14-generic +Architecture: i386 amd64 +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.27-14, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.27 on x86/x86_64 + This package provides kernel header files for version 2.6.27 on + x86/x86_64. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.27-14/debian.README.gz for details. + +Package: linux-image-debug-2.6.27-14-generic +Architecture: i386 amd64 +Section: devel +Priority: optional +Provides: linux-debug +Description: Linux kernel debug image for version 2.6.27 on x86/x86_64 + This package provides a kernel debug image for version 2.6.27 on + x86/x86_64. + . + This is for sites that wish to debug the kernel. + . + The kernel image contained in this package is NOT meant to boot from. It + is uncompressed, and unstripped. This package also includes the + unstripped modules. + +Package: linux-image-2.6.27-14-server +Architecture: i386 amd64 +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, redhat-cluster-modules, kvm-api-4, ivtv-modules, ndiswrapper-modules-1.9 +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: lilo (>= 19.1) | grub +Suggests: fdutils, linux-doc-2.6.27 | linux-source-2.6.27 +Description: Linux kernel image for version 2.6.27 on x86/x86_64 + This package contains the Linux kernel image for version 2.6.27 on + x86/x86_64. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Server processors. + . + Geared toward server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-server meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.27-14-server +Architecture: i386 amd64 +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.27-14, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.27 on x86/x86_64 + This package provides kernel header files for version 2.6.27 on + x86/x86_64. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.27-14/debian.README.gz for details. + +Package: linux-image-debug-2.6.27-14-server +Architecture: i386 amd64 +Section: devel +Priority: optional +Provides: linux-debug +Description: Linux kernel debug image for version 2.6.27 on x86/x86_64 + This package provides a kernel debug image for version 2.6.27 on + x86/x86_64. + . + This is for sites that wish to debug the kernel. + . + The kernel image contained in this package is NOT meant to boot from. It + is uncompressed, and unstripped. This package also includes the + unstripped modules. + +Package: linux-image-2.6.27-14-virtual +Architecture: i386 amd64 +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, redhat-cluster-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1), linux-image-2.6.27-14-server +Recommends: lilo (>= 19.1) | grub +Suggests: fdutils, linux-doc-2.6.27 | linux-source-2.6.27 +Description: Linux kernel image for version 2.6.27 on x86/x86_64 + This package contains the Linux kernel image for version 2.6.27 on + x86/x86_64. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Virtual processors. + . + Geared toward virtual machine guests. + . + You likely do not want to install this package directly. Instead, install + the linux-virtual meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. --- linux-2.6.27.orig/debian/copyright +++ linux-2.6.27/debian/copyright @@ -0,0 +1,30 @@ +This is the Ubuntu prepackaged version of the Linux kernel. +Linux was written by Linus Torvalds +and others. + +This package was put together by the Ubuntu Kernel Team, from +sources retrieved from upstream linux git. +The sources may be found at most Linux ftp sites, including +ftp://ftp.kernel.org/pub/linux/kernel/ + +This package is currently maintained by the +Ubuntu Kernel Team + +Linux is copyrighted by Linus Torvalds and others. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 dated June, 1991. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + +On Ubuntu Linux systems, the complete text of the GNU General +Public License v2 can be found in `/usr/share/common-licenses/GPL-2'. --- linux-2.6.27.orig/debian/rules +++ linux-2.6.27/debian/rules @@ -0,0 +1,116 @@ +#!/usr/bin/make -f +# +# debian/rules for Ubuntu linux +# +# Use this however you want, just give credit where credit is due. +# +# Copyright (c) 2007 Ben Collins +# + +# dpkg-buildpackage passes options that are incomptatible +# with the kernel build. +unexport CFLAGS +unexport LDFLAGS + +# This is the debhelper compatability version to use. +export DH_COMPAT=4 +export LC_ALL=C +export SHELL=/bin/bash -e + +# Common variables for all architectures +include debian/rules.d/0-common-vars.mk + +# Pill in some arch specific stuff +include debian/rules.d/$(arch).mk + +# Maintainer targets +include debian/rules.d/1-maintainer.mk + +# Debian Build System targets +binary: binary-indep binary-arch + +build: build-arch build-indep + +clean: debian/control + dh_testdir + dh_testroot + dh_clean + + # d-i stuff + rm -rf modules kernel-versions package-list + rm -rf debian/d-i-$(arch) + + # normal build junk + rm -rf debian/abi/$(release)-$(revision) + rm -rf $(builddir) + rm -f $(stampdir)/stamp-* + rm -rf debian/linux-* + + # This gets rid of the d-i packages in control + cp -f debian/control.stub debian/control + +# Builds the image, arch headers and debug packages +include debian/rules.d/2-binary-arch.mk + +# Rules for building the udebs (debian-installer) +include debian/rules.d/5-udebs.mk + +# Builds the source, doc and linux-headers indep packages +include debian/rules.d/3-binary-indep.mk + +# Various checks to be performed on builds +include debian/rules.d/4-checks.mk + +# Misc stuff +debian/control.stub: debian/d-i/kernel-versions.in \ + debian/scripts/control-create \ + debian/control.stub.in \ + debian/changelog \ + $(wildcard debian/control.d/* debian/sub-flavours/*.vars) + for i in debian/d-i/kernel-versions.in debian/control.stub.in; do \ + new=`echo $$i | sed 's/\.in$$//'`; \ + cat $$i | sed -e 's/PKGVER/$(release)/g' -e 's/ABINUM/$(abinum)/g' > \ + $$new; \ + done + flavours="$(wildcard debian/control.d/vars.* debian/sub-flavours/*.vars)";\ + for i in $$flavours; do \ + $(SHELL) debian/scripts/control-create $$i | \ + sed -e 's/PKGVER/$(release)/g' -e 's/ABINUM/$(abinum)/g' >> \ + debian/control.stub; \ + done + cp debian/control.stub debian/control + +.PHONY: debian/control +debian/control: debian/control.stub + rm -rf modules kernel-versions package-list + mkdir -p modules/$(arch)/ + cp debian/d-i/modules/* modules/$(arch)/ + cp debian/d-i/package-list debian/d-i/kernel-versions . + touch modules/$(arch)/kernel-image + + # Per flavour module lists + flavour_modules=`ls debian/d-i/modules.$(arch)-* 2>/dev/null` \ + || true; \ + if [ "$$flavour_modules" != "" ]; then \ + for flav in $$flavour_modules; do \ + name=`echo $$flav | sed 's/.*\/modules.$(arch)-//'`; \ + mkdir modules/$(arch)-$$name; \ + (cd debian/d-i/modules/; tar cf - `cat ../../../$$flav`) |\ + (cd modules/$(arch)-$$name/; tar xf -); \ + touch modules/$(arch)-$$name/kernel-image; \ + done; \ + fi + + # Remove unwanted stuff + if [ -r "debian/d-i/exclude-modules.$(arch)" ]; then \ + (cat debian/d-i/exclude-modules.$(arch); \ + ls modules/$(arch)/) | sort | uniq -d | \ + (cd modules/$(arch)/; xargs rm -f); \ + fi + + if [ ! -d modules/$(build_arch) ]; then \ + mkdir -p modules/$(build_arch); \ + cp modules/$(arch)/* modules/$(build_arch); \ + fi + + kernel-wedge gen-control > debian/control --- linux-2.6.27.orig/debian/changelog.historical +++ linux-2.6.27/debian/changelog.historical @@ -0,0 +1,5745 @@ +linux (2.6.24-19.33) UNRELEASED; urgency=low + + CHANGELOG: Do not edit directly. Autogenerated at release. + CHANGELOG: Use the printchanges target to see the curent changes. + CHANGELOG: Use the insertchanges target to create the final log. + + -- Tim Gardner Sun, 04 May 2008 20:22:21 -0600 + +linux (2.6.24-18.32) hardy-security; urgency=low + + * CVE-2007-6694: [POWERPC] CHRP: Fix possible NULL pointer dereference + * fix SMP ordering hole in fcntl_setlk() (CVE-2008-1669) + * Fix dnotify/close race (CVE-2008-1375) + * tehuti: check register size (CVE-2008-1675) + * tehuti: move ioctl perm check closer to function start (CVE-2008-1675) + + -- Ben Collins Mon, 19 May 2008 16:50:11 +0000 + +linux (2.6.24-17.31) hardy; urgency=low + + [Alessio Igor Bogani] + + * rt: Fix mutex in the toshiba_acpi driver + * rt: Updated configuration files + + [Ben Collins] + + * build: Fix revert detection in git-ubuntu-log + * SAUCE: Re-add eeprom_bad_csum_allow module-param + - LP: #60388 + + [Stefan Bader] + + * Pulled updates to openvz custom build. Fixes openvz 'refuses to boot' problem. + - LP: #210672 + * sched: retain vruntime, fix delayed key events when CONFIG_FAIR_GROUP_SCHED. + - LP: #218516 + * UBUNTU: SAUCE: Add blacklist support to fix Belkin bluetooth dongle. + - LP: #140511 + + [Tim Gardner] + + * Enable CONFIG_ISCSI_TCP for -virtual + - LP: #218215 + * build: Add fancontrol modules to powerpc64-smp debian installer + * Fix Xen Dom0/DomU bridging + - LP: #218126 + * TSC Clocksource can cause hangs and time jumps + - LP: #221351 + * Kernel should use CONFIG_FAIR_CGROUP_SCHED. Fixes high load issues + with pulseaudio. + - LP: #188226 + + [Upstream Kernel Changes] + + * KVM: MMU: prepopulate guest pages after write-protecting + - LP: #221032 + + -- Tim Gardner Fri, 11 Apr 2008 07:59:10 -0600 + +linux (2.6.24-16.30) hardy; urgency=low + + * Fix amd64/i386 ABI and module check FTBS by creating an ignore + and ignore.modules in the ABI directory. + + -- Tim Gardner Wed, 09 Apr 2008 21:58:25 -0600 + +linux (2.6.24-16.29) hardy; urgency=low + + [Stephan Bader] + + * UBUNTU: SAUCE: mmc: Increase power_up deleay to fix TI readers + + [Alessio Igor Bogani] + + * rt: Updated configuration files + + [Chuck Short] + + * Xen updates for vitrio changes. + + [Tim Gardner] + + * openvz updates for vitrio changes. + + -- Tim Gardner Tue, 08 Apr 2008 21:48:16 -0600 + +linux (2.6.24-16.28) hardy; urgency=low + + [Tim Gardner] + + * Revert "UBUNTU: x86: tsc prevent time going backwards" + + [Kees Cook] + + * AppArmor: implement mmap_min_addr check as done in mainline. + + [Soren Hansen] + + * Bring our virtio code up to date with 2.6.25-rc7 + + [Upstream Kernel Changes] + + * Ubuntu: Revert all our virtio changes + * lguest: Reboot support + * lguest: adapt launcher to per-cpuness + * virtio: Implement skb_partial_csum_set, for setting partial csums on + untrusted packets. + * virtio: simplify config mechanism. + * virtio: explicit enable_cb/disable_cb rather than callback return. + * virtio: configuration change callback + * virtio: Fix vring_init/vring_size to take unsigned long + * virtio: clarify NO_NOTIFY flag usage + * virtio: remove unused id field from struct virtio_blk_outhdr + * virtio: Net header needs hdr_len + * virtio: Tweak virtio_net defines + * virtio: populate network rings in the probe routine, not open + * virtio: reset function + * virtio: handle interrupts after callbacks turned off + * virtio: Use the sg_phys convenience function. + * virtio: Allow virtio to be modular and used by modules + * virtnet: remove double ether_setup + * virtio: flush buffers on open + * virtio: free transmit skbs when notified, not on next xmit. + * virtio_net: parametrize the napi_weight for virtio receive queue. + * virtio_blk: provide getgeo + * virtio_blk: Dont waste major numbers + * virtio_blk: implement naming for vda-vdz,vdaa-vdzz,vdaaa-vdzzz + * virtio: PCI device + * virtio: Use PCI revision field to indicate virtio PCI ABI version + * virtio: balloon driver + * virtio net: fix oops on interface-up + * virtio: add missing #include + * virtio: fix race in enable_cb + * virtio: handle > 2 billion page balloon targets + * virtio_net: Fix oops on early interrupts - introduced by virtio reset + code + * lguest: Do not append space to guests kernel command line + * virtio: Use spin_lock_irqsave/restore for virtio-pci + * virtio: Fix sysfs bits to have proper block symlink + * virtio: Enable netpoll interface for netconsole logging + * virtio_pci: unregister virtio device at device remove + * lguest: Add puppies which where previously missing. + * lguest: lguest.txt documentation fix + * lguest: Don't need comment terminator before disk section. + * virtio_pci iomem annotations + * virtio_net: remove overzealous printk + * virtio: remove overzealous BUG_ON. + + -- Tim Gardner Tue, 08 Apr 2008 11:53:49 -0600 + +linux (2.6.24-15.27) hardy; urgency=low + + [Alan Stern] + + * usb-storage: don't access beyond the end of the sg buffer + - LP: #204922 + + [Mario Limonciello] + + * Enable Reset and SCO workaround on Dell 410 BT adapter + + [Tim Gardner] + + * Enable CONFIG_E1000 in the i386 virtual image. + - LP: #205646 + + [Thomas Gleixner] + + * x86: tsc prevent time going backwards + + [Matthew Garrett] + + * Fix framebuffer fonts on non-x86 platforms + + -- Tim Gardner Fri, 04 Apr 2008 08:14:49 -0600 + +linux (2.6.24-15.26) hardy; urgency=low + + [Colin Ian King] + + * airprime.c supports more devices + - LP: #208250 + + [Kees Cook] + + * AppArmor: get latest batch of upstream fixes into Hardy (svn 1160) + + [Stefan Bader] + + * ACPI: fix boot oops regression in kernel + - LP: #207014 + + [Tim Gardner] + + * Enable CGROUPS for non x86/x86_64 arches, all flavours. + - LP: #188226 + + -- Tim Gardner Thu, 03 Apr 2008 07:00:29 -0600 + +linux (2.6.24-14.25) hardy; urgency=low + + [Mario Limonciello] + + * Resolve sky2 race condition leading to failed suspends + - LP: #210877 + + [Tim Gardner] + + * Copy drivers/media internal header files into header + package for external LUM compilation. This paves the + way for LP #202065. + + -- Tim Gardner Wed, 02 Apr 2008 08:28:32 -0600 + +linux (2.6.24-14.24) hardy; urgency=low + + [Amit Kucheria] + + * LPIA: Update from moblin + * LPIA: Fix reboot problem after S3/S4 + * LPIA: Integrate latest Dabney thermal patches + * LPIA: Change-umd_dbg-debug-level-to-KERN_INFO + * LPIA: Compile modules into kernel to save on boot time + * LPIA: lots of Dabney CONFIG options dissapeared + * LPIA: Purge nonexistent config options + + [Jay Chetty] + + * UBUNTU:USBC:Integrated USBC 2.0.0.32L.0009 + + [Misha Zhilin] + + * USB: ehci: handle large bulk URBs correctly (again) + - LP: #204857 + + [Tim Gardner] + + * frame buffer regression - screen blank except for blinking cursor after + fbcon vtswitch + - LP: #201591 + * Blacklist Bluetooth Dell Wireless 370 for SCO MTU + - LP: #209715 + * Set CONFIG_FAIR_CGROUP_SCHED for server flavours. + - LP: #188226 + * Add DMI IO_DELAY support. + - LP: #200057 + + -- Tim Gardner Mon, 31 Mar 2008 11:19:49 -0600 + +linux (2.6.24-13.23) hardy; urgency=low + + [Alessio Igor Bogani] + + * rt: Updated configuration files + + [Ben Collins] + + * openvz: New custom flavour for OpenVZ + * config: Disable IDE AMD driver in favor of PATA version + - LP: #181561 + * config: Disable IDE VIA driver in favor of PATA version + - LP: #181561 + * drivers/video: Restore gutsy backlight dimming behavior + - LP: #205261 + * build/config: Enable CONFIG_CIFS_WEAK_PW_HASH + - LP: #202445 + + [Colin Ian King] + + * SAUCE: Add support for version 4 of Chelsio NICs in cxgb3 driver + - LP: #201893 + + [Kees Cook] + + * AppArmor: re-add missing "type" field in syslog reports. + - LP: #202888 + * kvm: reset TSS on x86_64 to avoid ioperm bitmap corruption + - LP: #144900 + + [Stefan Bader] + + * USB: EHCI: add separate IAA watchdog timer + - LP: #198619 + * SAUCE: Always use SCO protocol (disable eSCO support) + - LP: #39414 + * PM: Introduce PM_EVENT_HIBERNATE callback state + - LP: #201086 + + [Tim Gardner] + + * Disable DRM suspend/resume on pre-915 Intel chips + - LP: #207496 + * frame buffer regression - screen blank except for blinking cursor after fbcon + vtswitch + - LP: #201591 + + -- Tim Gardner Wed, 19 Mar 2008 10:05:05 -0400 + +linux (2.6.24-12.22) hardy; urgency=low + + [Ben Collins] + + * custom/rt: Disable toshiba_acpi, since it isn't compatible + + -- Ben Collins Wed, 12 Mar 2008 14:38:59 -0400 + +linux (2.6.24-12.21) hardy; urgency=low + + [Ben Collins] + + * build: Fix vesafb module inclusion into initrd subdir + - LP: #129910 + * net/bluetooth: POWERBOOK => APPLE, fix for apple keyboard patch + * custom/xen: Remove asix portion of xen patch, breaks driver + - LP: #199296 + + [Colin Ian King] + + * SAUCE: fix Udma not fully available in Acer 1694 Wlmi + - LP: #187121 + * SAUCE: Update toshiba_acpi.c to version 0.19a + - LP: #77026 + + [Stefan Bader] + + * x86: Clear DF before calling signal handler + * Enable FN key on Apple aluminum bluetooth keyboard + - LP: #162083 + + -- Ben Collins Tue, 11 Mar 2008 13:20:49 -0400 + +linux (2.6.24-12.20) hardy; urgency=low + + [Ben Collins] + + * Enable CONFIG_SOUND at least, so alsa build in lum works + - LP: #200338 + + -- Ben Collins Mon, 10 Mar 2008 08:15:00 -0400 + +linux (2.6.24-12.19) hardy; urgency=low + + * Re-upload of -12.18 to fix build failures + * Fixup binary-custom configs + * Fixup xen patch to cope with kvm changes + + [Amit Kucheria] + + * Move Marvell 8686 and 8688 to LUM + * Poulsbo: Sync patches with moblin/ume-hardy tree + * Break if a patch fails to apply + * SAUCE: implement smarter atime updates support + - LP: #199427 + * Enable USB_PERSIST to allow devices with /root on usb to work with + suspend + * Enable USB_PERSIST across the board + + [Ben Collins] + + * build/config: Really fix ide on smp ppc configs + * build/configs: Enable relatime config option for all flavors + * build/abi: Ignore ide-core module for ppc, moved to built-in + + [Colin Ian King] + + * fix reversed logic for bbuild check leads to -j1 default + - LP: #197040 + * Enable IDE_PMAC for powerpc-smp + - LP: #196686 + * Disable CONFIG_USB_OHCI_HCD_SSB + - LP: #182716 + * SAUCE: fix arcmsr + archttp64 calls dma_free_coherent() with irqs + disabled - dmesg filled with warnings + - LP: #194207 + + [Jorge Boncompte [DTI2]] + + * Fix Messed multicast lists after dev_mc_sync/unsync + - LP: #193468 + + [Stefan Bader] + + * Add support for Apple Aluminium keyboards. + - LP: #162083 + * SAUCE: Restore VT fonts on switch + + [Upstream Kernel Changes] + + * [NET]: Messed multicast lists after dev_mc_sync/unsync + * KVM: x86 emulator: add support for group decoding + * KVM: x86 emulator: group decoding for group 1A + * KVM: x86 emulator: Group decoding for group 3 + * KVM: x86 emulator: Group decoding for groups 4 and 5 + * KVM: x86 emulator: add group 7 decoding + * KVM: constify function pointer tables + * KVM: Only x86 has pio + * KVM: x86 emulator: group decoding for group 1 instructions + * KVM: MMU: Decouple mmio from shadow page tables + * KVM: Limit vcpu mmap size to one page on non-x86 + * KVM: VMX: Enable Virtual Processor Identification (VPID) + * KVM: Use CONFIG_PREEMPT_NOTIFIERS around struct preempt_notifier + * KVM: Disable pagefaults during copy_from_user_inatomic() + * KVM: make EFER_RESERVED_BITS configurable for architecture code + * KVM: align valid EFER bits with the features of the host system + * KVM: allow access to EFER in 32bit KVM + * kvm: i386 fix + * KVM: export information about NPT to generic x86 code + * KVM: MMU: make the __nonpaging_map function generic + * KVM: export the load_pdptrs() function to modules + * KVM: MMU: add TDP support to the KVM MMU + * KVM: x86 emulator: Fix 'jmp abs' + * KVM: x86 emulator: fix group 5 decoding + * KVM: Fix kvm_arch_vcpu_ioctl_set_sregs so that set_cr0 works properly + * KVM: Make the supported cpuid list a host property rather than a vm + property + * KVM: emulate access to MSR_IA32_MCG_CTL + * KVM: remove the usage of the mmap_sem for the protection of the memory + slots. + * KVM: SVM: allocate the MSR permission map per VCPU + * KVM: make MMU_DEBUG compile again + * KVM: paravirtualized clocksource: host part + * KVM: Add missing semicolon + * KVM: x86 emulator: add ad_mask static inline + * KVM: x86 emulator: make register_address, address_mask static inlines + * KVM: x86 emulator: make register_address_increment and JMP_REL static + inlines + * KVM: Add API to retrieve the number of supported vcpus per vm + * KVM: Increase vcpu count to 16 + * KVM: Add API for determining the number of supported memory slots + * KVM: Increase the number of user memory slots per vm + * KVM: Add stat counter for hypercalls + * KVM: x86 emulator: fix sparse warnings in x86_emulate.c + * KVM: sparse fixes for kvm/x86.c + * KVM: Implement dummy values for MSR_PERF_STATUS + * KVM: MMU: ignore zapped root pagetables + * KVM: call write_guest_time as soon as we register the paravirt clock + * KVM: MMU: large page support + * KVM: Prefix control register accessors with kvm_ to avoid namespace + pollution + * KVM: Avoid infinite-frequency local apic timer + * KVM: Route irq 0 to vcpu 0 exclusively + * KVM: SVM: add support for Nested Paging + * KVM: SVM: enable LBR virtualization + * KVM: SVM: make iopm_base static + * KVM: SVM: let init_vmcb() take struct vcpu_svm as parameter + * KVM: VMX: fix typo in VMX header define + * KVM: SVM: fix Windows XP 64 bit installation crash + * KVM: VMX: Fix invalid opcode of VPID + * KVM: VMX: Handle machines without EFER + * KVM: move alloc_apic_access_page() outside of non-preemptable region + * KVM: VMX: unifdef the EFER specific code + * KVM: SVM: move feature detection to hardware setup code + * KVM: Export include/linux/kvm.h only if $ARCH actually supports KVM + * dlm: fix rcom_names message to self + * virtio: Net header needs hdr_len + + -- Tim Gardner Mon, 03 Mar 2008 07:07:16 -0700 + +linux (2.6.24-11.17) hardy; urgency=low + + [Alan Cox] + + * Pull in fixes for pata_it821x. + - LP: #106931 + + [Alessio Igor Bogani] + + * rt: Synchronized with upstream (2.6.24.3-rt3) + * rt: Updated configuration files + + [Amit Kucheria] + + * Add AGP support for Radeon Mobility 9000 chipset + - LP: #178634 + * Bluetooth: SCO flow control to enable bluetooth headsets + + [Ben Collins] + + * binary: Include vesafs in initrd subdir, should fix vga= usage + + [Colin Ian King] + + * AMD SB700 south bridge support patches + - LP: #195354 + * BCM4311 Revision 2 fix + - LP: #184600 + + [Mauro Carvalho Chehab] + + * V4L/DVB (6753): Fix vivi to support non-zero minor node + + [Tim Gardner] + + * Merged 2.6.24.3 + * Add atl1 to d-i bits. + - LP: #159561 + * SAUCE: Add xpad support for RedOctane Guitar Hero + - LP: #196745 + + [Upstream Kernel Changes] + + * DVB: cx23885: add missing subsystem ID for Hauppauge HVR1800 Retail + * slab: fix bootstrap on memoryless node + * vm audit: add VM_DONTEXPAND to mmap for drivers that need it + (CVE-2008-0007) + * USB: keyspan: Fix oops + * usb gadget: fix fsl_usb2_udc potential OOPS + * USB: CP2101 New Device IDs + * USB: add support for 4348:5523 WinChipHead USB->RS 232 adapter + * USB: Sierra - Add support for Aircard 881U + * USB: Adding YC Cable USB Serial device to pl2303 + * USB: sierra driver - add devices + * USB: ftdi_sio - enabling multiple ELV devices, adding EM1010PC + * USB: ftdi-sio: Patch to add vendor/device id for ATK_16IC CCD + * USB: sierra: add support for Onda H600/Zte MF330 datacard to USB Driver + for Sierra Wireless + * USB: remove duplicate entry in Option driver and Pl2303 driver for + Huawei modem + * USB: pl2303: add support for RATOC REX-USB60F + * USB: ftdi driver - add support for optical probe device + * USB: use GFP_NOIO in reset path + * USB: Variant of the Dell Wireless 5520 driver + * USB: storage: Add unusual_dev for HP r707 + * USB: fix usbtest halt check on big endian systems + * USB: handle idVendor of 0x0000 + * USB: Fix usb_serial_driver structure for Kobil cardreader driver. + * forcedeth: mac address mcp77/79 + * lockdep: annotate epoll + * sys_remap_file_pages: fix ->vm_file accounting + * PCI: Fix fakephp deadlock + * ACPI: update ACPI blacklist + * x86: restore correct module name for apm + * sky2: restore multicast addresses after recovery + * sky2: fix for WOL on some devices + * b43: Fix suspend/resume + * b43: Drop packets we are not able to encrypt + * b43: Fix dma-slot resource leakage + * b43legacy: fix PIO crash + * b43legacy: fix suspend/resume + * b43legacy: drop packets we are not able to encrypt + * b43legacy: fix DMA slot resource leakage + * selinux: fix labeling of /proc/net inodes + * b43: Reject new firmware early + * sched: let +nice tasks have smaller impact + * sched: fix high wake up latencies with FAIR_USER_SCHED + * fix writev regression: pan hanging unkillable and un-straceable + * Driver core: Revert "Fix Firmware class name collision" + * drm: the drm really should call pci_set_master.. + * splice: missing user pointer access verification (CVE-2008-0009/10) + * Linux 2.6.24.1 + * splice: fix user pointer access in get_iovec_page_array() + * Linux 2.6.24.2 + * ACPI: video: Rationalise ACPI backlight implementation + * ACPI: video: Ignore ACPI video devices that aren't present in hardware + * SPARC/SPARC64: Fix usage of .section .sched.text in assembler code. + * NETFILTER: nf_conntrack_tcp: conntrack reopening fix + * NFS: Fix a potential file corruption issue when writing + * inotify: fix check for one-shot watches before destroying them + * hugetlb: add locking for overcommit sysctl + * XFS: Fix oops in xfs_file_readdir() + * Fix dl2k constants + * SCSI: sd: handle bad lba in sense information + * TCP: Fix a bug in strategy_allowed_congestion_control + * TC: oops in em_meta + * SELinux: Fix double free in selinux_netlbl_sock_setsid() + * PKT_SCHED: ematch: oops from uninitialized variable (resend) + * NET: Add if_addrlabel.h to sanitized headers. + * IPV4: fib_trie: apply fixes from fib_hash + * IPV4: fib: fix route replacement, fib_info is shared + * IPCOMP: Fix reception of incompressible packets + * IPCOMP: Fetch nexthdr before ipch is destroyed + * INET_DIAG: Fix inet_diag_lock_handler error path. + * INET: Prevent out-of-sync truesize on ip_fragment slow path + * BLUETOOTH: Add conn add/del workqueues to avoid connection fail. + * AUDIT: Increase skb->truesize in audit_expand + * Be more robust about bad arguments in get_user_pages() + * Disable G5 NAP mode during SMU commands on U3 + * hrtimer: fix *rmtp handling in hrtimer_nanosleep() + * hrtimer: fix *rmtp/restarts handling in compat_sys_nanosleep() + * SLUB: Deal with annoying gcc warning on kfree() + * hrtimer: check relative timeouts for overflow + * hrtimer: catch expired CLOCK_REALTIME timers early + * genirq: do not leave interupts enabled on free_irq + * S390: Fix futex_atomic_cmpxchg_std inline assembly. + * USB: fix pm counter leak in usblp + * SCSI: gdth: scan for scsi devices + * PCMCIA: Fix station address detection in smc + * POWERPC: Revert chrp_pci_fixup_vt8231_ata devinit to fix libata on + pegasos + * bonding: fix NULL pointer deref in startup processing + * x86_64: CPA, fix cache attribute inconsistency bug + * Linux 2.6.24.3 + + -- Tim Gardner Mon, 25 Feb 2008 12:28:13 -0700 + +linux (2.6.24-10.16) hardy; urgency=low + + [Alessio Igor Bogani] + + * rt: Synchronized with upstream (2.6.24.2-rt2) + * rt: Updated configuration files + + [Eric Piel] + + * SAUCE: ACPI: Allow custom DSDT tables to be loaded from initramfs + Amit Kucheria consolidated the DSDT patch with another fix that + ifdefs symbols required when BLK_DEV_INITR is disabled. + + [Stefan Bader] + + * Add Optiarc DVD drive to audio quirks list. + - LP: #186664 + * Update drm and i915 drm driver to fix suspend issues. + - LP: #189260 + + [Tim Gardner] + + * Fix FTBS without BLK_DEV_INITRD + - LP: #193507 + * 64 bit CPA cache attribute bug + - LP: #193736 + * Implemented default EDD control + + [Upstream Kernel Changes] + + * bonding: fix NULL pointer deref in startup processing + * dlm: bind connections from known local address when using TCP + * dlm: proper prototypes + * dlm: don't print common non-errors + * dlm: use dlm prefix on alloc and free functions + * dlm: close othercons + * dlm: align midcomms message buffer + * dlm: swap bytes for rcom lock reply + * dlm: use fixed errno values in messages + * dlm: clear ast_type when removing from astqueue + * dlm: recover locks waiting for overlap replies + * dlm: another call to confirm_master in receive_request_reply + * dlm: reject messages from non-members + * dlm: validate messages before processing + * dlm: reject normal unlock when lock is waiting for lookup + * dlm: limit dir lookup loop + * dlm: fix possible use-after-free + * dlm: change error message to debug + * dlm: keep cached master rsbs during recovery + * dlm: Sanity check namelen before copying it + * dlm: clean ups + * dlm: static initialization improvements + * dlm: use proper C for dlm/requestqueue stuff (and fix alignment bug) + * dlm: dlm_process_incoming_buffer() fixes + * dlm: do not byteswap rcom_lock + * dlm: do not byteswap rcom_config + * dlm: use proper type for ->ls_recover_buf + * dlm: missing length check in check_config() + * dlm: validate data in dlm_recover_directory() + * dlm: verify that places expecting rcom_lock have packet long enough + * dlm: receive_rcom_lock_args() overflow check + * dlm: make find_rsb() fail gracefully when namelen is too large + * dlm: fix overflows when copying from ->m_extra to lvb + * dlm: fix dlm_dir_lookup() handling of too long names + * dlm: dlm/user.c input validation fixes + * dlm: proper types for asts and basts + * dlm: eliminate astparam type casting + * dlm: add __init and __exit marks to init and exit functions + * virtio: Use PCI revision field to indicate virtio PCI ABI version + + -- Tim Gardner Tue, 19 Feb 2008 09:57:18 -0700 + +linux (2.6.24-9.15) hardy; urgency=low + + [Alessio Igor Bogani] + + * rt: Fix FTBS + * rt: Updated configuration files + + [Tim Gardner] + + * SAUCE: make /dev/kmem a config option + * SAUCE: x86: introduce /dev/mem restrictions with a config option + * Fixed CGROUP FTBS caused by AppArmor patch. + * Enabled CGROUP and CPUSETS for server flavor. + - LP: #182434 + + [Colin King] + + * Turn on /proc/acpi/alarm for x86_64 (amd64) + - LP: #186297 + + [Upstream Kernel Changes] + + * Ubuntu: LatencyTOP infrastructure patch + + -- Tim Gardner Thu, 14 Feb 2008 13:34:55 -0700 + +linux (2.6.24-8.14) hardy; urgency=low + + [cking] + + * Support Novatel U727 EVDO modem: Add pid and vid to + drivers/usb/serial/airprime.c + - LP: #150996 + * Enable speedstep for sonoma processors. + - LP: #132271 + + [Stefan Bader] + + * SAUCE: Export dm_disk function of device-mapper + + -- Tim Gardner Wed, 13 Feb 2008 21:47:18 -0700 + +linux (2.6.24-8.13) hardy; urgency=low + + [Soren Hansen] + + * Add missing iscsi modules to kernel udebs + + [Stefan Bader] + + * Lower message level for PCI memory and I/O allocation. + + [Tim Gardner] + + * Enabled IP_ADVANCED_ROUTER and IP_MULTIPLE_TABLES in sparc, hppa + - LP: #189560 + * Compile RealTek 8139 using PIO method. + - LP: #90271 + * Add WD WD800ADFS NCQ horkage quirk support. + - LP: #147858 + + [Upstream Kernel Changes] + + * Introduce WEXT scan capabilities + * DVB: cx23885: add missing subsystem ID for Hauppauge HVR1800 Retail + * slab: fix bootstrap on memoryless node + * vm audit: add VM_DONTEXPAND to mmap for drivers that need it + (CVE-2008-0007) + * USB: keyspan: Fix oops + * usb gadget: fix fsl_usb2_udc potential OOPS + * USB: CP2101 New Device IDs + * USB: add support for 4348:5523 WinChipHead USB->RS 232 adapter + * USB: Sierra - Add support for Aircard 881U + * USB: Adding YC Cable USB Serial device to pl2303 + * USB: sierra driver - add devices + * USB: ftdi_sio - enabling multiple ELV devices, adding EM1010PC + * USB: ftdi-sio: Patch to add vendor/device id for ATK_16IC CCD + * USB: sierra: add support for Onda H600/Zte MF330 datacard to USB Driver + for Sierra Wireless + * USB: remove duplicate entry in Option driver and Pl2303 driver for + Huawei modem + * USB: pl2303: add support for RATOC REX-USB60F + * USB: ftdi driver - add support for optical probe device + * USB: use GFP_NOIO in reset path + * USB: Variant of the Dell Wireless 5520 driver + * USB: storage: Add unusual_dev for HP r707 + * USB: fix usbtest halt check on big endian systems + * USB: handle idVendor of 0x0000 + * forcedeth: mac address mcp77/79 + * lockdep: annotate epoll + * sys_remap_file_pages: fix ->vm_file accounting + * PCI: Fix fakephp deadlock + * ACPI: update ACPI blacklist + * x86: restore correct module name for apm + * sky2: restore multicast addresses after recovery + * sky2: fix for WOL on some devices + * b43: Fix suspend/resume + * b43: Drop packets we are not able to encrypt + * b43: Fix dma-slot resource leakage + * b43legacy: fix PIO crash + * b43legacy: fix suspend/resume + * b43legacy: drop packets we are not able to encrypt + * b43legacy: fix DMA slot resource leakage + * selinux: fix labeling of /proc/net inodes + * b43: Reject new firmware early + * sched: let +nice tasks have smaller impact + * sched: fix high wake up latencies with FAIR_USER_SCHED + * fix writev regression: pan hanging unkillable and un-straceable + * Driver core: Revert "Fix Firmware class name collision" + * drm: the drm really should call pci_set_master.. + * splice: missing user pointer access verification (CVE-2008-0009/10) + * Linux 2.6.24.1 + * splice: fix user pointer access in get_iovec_page_array() + * Linux 2.6.24.2 + + -- Tim Gardner Thu, 07 Feb 2008 06:50:13 -0700 + +linux (2.6.24-7.12) hardy; urgency=low + + [Jay Chetty] + + * Added patch to fix legacy USB interrupt issue + * Enabled Poulsbo PATA udma5 support + * Add touchscreen doubleclick workaround + + [Amit Kucheria] + + * Add AGP support for Radeon Mobility 9000 chipset + - LP: #178634 + + [Soren Hansen] + + * Add virtio modules to the relevant udebs + * Add missing "?" for virtio modules in storage-core-modules + + [Stefan Bader] + + * Added vendor id for Dell 5720 broadband modem + + -- Jay Chetty Wed, 06 Feb 2008 14:13:41 -0800 + +linux (2.6.24-7.11) hardy; urgency=low + + [Jay Chetty] + + * poulsbo: Add a 100ms delay for SiB workaround + + [Tim Gardner] + + * -6.10 should have been an ABI bump, but due to incomplete build testing + went undetected. + + -- Tim Gardner Mon, 04 Feb 2008 19:13:52 -0700 + +linux (2.6.24-6.10) hardy; urgency=low + + [Alessio Igor Bogani] + + * rt: Synced with upstream, removed old kvm related patches and updated + configurations files. + + [Chuck Short] + + * SAUCE: Enable Xen + + [Soren Hansen] + + * Update kvm driver to kvm-60. + * Added CONFIG_ARCH_SUPPORTS_KVM=y for lpia, i386, and amd64 + * Add rtl8139 driver to -virtual flavour + + [Stefan Bader] + + * Fix usb_serial_driver structure for Kobil cardreader driver. + - LP: #183109 + * Lower warning level of pci resource allocation messages. + - LP: #159241 + + [Tim Gardner] + + * Enabled CONFIG_BLK_DEV_IDE_PMAC + - LP: #185862 + * Add virtio config options to lpiacompat. + * SAUCE: Export symbols for aufs (in lum). + * Enabled Xen + + [Upstream Kernel Changes] + + * KVM: mmu: add missing dirty page tracking cases + * KVM: Move virtualization deactivation from CPU_DEAD state to + CPU_DOWN_PREPARE + * KVM: Cosmetics + * KVM: vmx: hack set_cr0_no_modeswitch() to actually do modeswitch + * KVM: Use ARRAY_SIZE macro instead of manual calculation. + * KVM: Use page_private()/set_page_private() apis + * KVM: add MSR based hypercall API + * KVM: Add host hypercall support for vmx + * KVM: Add hypercall host support for svm + * KVM: Wire up hypercall handlers to a central arch-independent location + * KVM: svm: init cr0 with the wp bit set + * KVM: SVM: intercept SMI to handle it at host level + * KVM: More 0 -> NULL conversions + * kvm, dirty pages log: adding some calls to mark_page_dirty() + * KVM: Add internal filesystem for generating inodes + * KVM: Create an inode per virtual machine + * KVM: Rename some kvm_dev_ioctl_*() functions to kvm_vm_ioctl_*() + * KVM: Move kvm_vm_ioctl_create_vcpu() around + * KVM: Per-vcpu inodes + * KVM: Bump API version + * .gitignore: ignore emacs backup files (*~) + * kvm: dirty pages log: fix bitmap size/access calculation + * kvm: move do_remove_write_access() up + * kvm: dirty page logging: remove write access permissions when + dirty-page-logging is enabled + * KVM: Add missing calls to mark_page_dirty() + * KVM: Fix dirty page log bitmap size/access calculation + * kvm: move do_remove_write_access() up + * KVM: Remove write access permissions when dirty-page-logging is enabled + * KVM: Fix bogus failure in kvm.ko module initialization + * KVM: Move kvmfs magic number to + * KVM: Unset kvm_arch_ops if arch module loading failed + * KVM: Fix guest register corruption on paravirt hypercall + * KVM: Use the generic skip_emulated_instruction() in hypercall code + * KVM: Use own minor number + * KVM: Fix guest sysenter on vmx + * KVM: Export + * KVM: Fix bogus sign extension in mmu mapping audit + * KVM: MMU: Fix guest writes to nonpae pde + * KVM: MMU: Fix host memory corruption on i386 with >= 4GB ram + * KVM: trivial whitespace fixes + * KVM: always reload segment selectors + * KVM: Remove extraneous guest entry on mmio read + * added KVM_GET_MEM_MAP ioctl to get the memory bitmap for a memory slot + * KVM: Prevent system selectors leaking into guest on real->protected + mode transition on vmx + * KVM: Use a shared page for kernel/user communication when runing a vcpu + * KVM: Do not communicate to userspace through cpu registers during PIO + * KVM: Initialize PIO I/O count + * KVM: Handle cpuid in the kernel instead of punting to userspace + * KVM: Remove the 'emulated' field from the userspace interface + * KVM: Remove minor wart from KVM_CREATE_VCPU ioctl + * KVM: Renumber ioctls + * KVM: Add method to check for backwards-compatible API extensions + * KVM: Allow userspace to process hypercalls which have no kernel handler + * KVM: Fold kvm_run::exit_type into kvm_run::exit_reason + * KVM: Add a special exit reason when exiting due to an interrupt + * KVM: Initialize the apic_base msr on svm too + * KVM: Add guest mode signal mask + * KVM: Allow kernel to select size of mmap() buffer + * KVM: Future-proof argument-less ioctls + * KVM: Avoid guest virtual addresses in string pio userspace interface + * KVM: MMU: Remove unnecessary check for pdptr access + * KVM: MMU: Remove global pte tracking + * KVM: Workaround vmx inability to virtualize the reset state + * KVM: Remove set_cr0_no_modeswitch() arch op + * KVM: Modify guest segments after potentially switching modes + * KVM: Hack real-mode segments on vmx from KVM_SET_SREGS + * KVM: Don't allow the guest to turn off the cpu cache + * KVM: Remove unused and write-only variables + * KVM: Handle writes to MCG_STATUS msr + * KVM: MMU: Fix hugepage pdes mapping same physical address with + different access + * KVM: SVM: Ensure timestamp counter monotonicity + * KVM: Remove unused function + * KVM: Remove debug message + * KVM: x86 emulator: fix bit string operations operand size + * KVM: SVM: enable LBRV virtualization if available + * Add mmu cache clear function + * KVM: Simply gfn_to_page() + * KVM: Add physical memory aliasing feature + * KVM: Add fpu get/set operations + * KVM: Use kernel-standard types + * KVM: Fix overflow bug in overflow detection code + * KVM: Fix memory leak on pio completion + * KVM: Handle partial pae pdptr + * KVM: Fix string pio when count == 0 + * KVM: Use slab caches to allocate mmu data structures + * KVM: Retry sleeping allocation if atomic allocation fails + * KVM: Fix pio completion + * KVM: SVM: Report hardware exit reason to userspace instead of dmesg + * KVM: Handle guest page faults when emulating mmio + * KVM: VMX: Reduce unnecessary saving of host msrs + * KVM: Fix off-by-one when writing to a nonpae guest pde + * KVM: VMX: Don't switch 64-bit msrs for 32-bit guests + * KVM: Fold drivers/kvm/kvm_vmx.h into drivers/kvm/vmx.c + * KVM: VMX: Only save/restore MSR_K6_STAR if necessary + * KVM: Per-vcpu statistics + * KVM: Silence compile warning on i386 + * KVM: Allow passing 64-bit values to the emulated read/write API + * KVM: Lazy FPU support for SVM + * KVM: Fix msr-avoidance regression on Core processors + * KVM: Don't complain about cpu erratum AA15 + * KVM: Document MSR_K6_STAR's special place in the msr index array + * KVM: MMU: Avoid heavy ASSERT at non debug mode. + * KVM: Initialize cr0 to indicate an fpu is present + * KVM: We want asserts on debug builds, not release + * KVM: Avoid unused function warning due to assertion removal + * KVM: VMX: Avoid unnecessary vcpu_load()/vcpu_put() cycles + * KVM: Move need_resched() check to common code + * KVM: VMX: Properly shadow the CR0 register in the vcpu struct + * KVM: VMX: Add lazy FPU support for VT + * KVM: fix an if() condition + * KVM: SVM: Only save/restore MSRs when needed + * KVM: Remove trailing whitespace + * KVM: Remove extraneous guest entry on mmio read + * KVM: Don't require explicit indication of completion of mmio or pio + * KVM: Remove unused 'instruction_length' + * KVM: VMX: Enable io bitmaps to avoid IO port 0x80 VMEXITs + * KVM: SVM: Allow direct guest access to PC debug port + * KVM: Fix RMW mmio handling + * KVM: Assume that writes smaller than 4 bytes are to non-pagetable pages + * KVM: Avoid saving and restoring some host CPU state on lightweight + vmexit + * KVM: Unindent some code + * KVM: Reduce misfirings of the fork detector + * KVM: Be more careful restoring fs on lightweight vmexit + * KVM: Unify kvm_mmu_pre_write() and kvm_mmu_post_write() + * KVM: MMU: Respect nonpae pagetable quadrant when zapping ptes + * KVM: Update shadow pte on write to guest pte + * KVM: Increase mmu shadow cache to 1024 pages + * KVM: Fix potential guest state leak into host + * KVM: Prevent guest fpu state from leaking into the host + * KVM: Move some more msr mangling into vmx_save_host_state() + * KVM: Rationalize exception bitmap usage + * KVM: Consolidate guest fpu activation and deactivation + * KVM: Ensure host cr0.ts is saved + * KVM: Set cr0.mp for guests + * KVM: Implement IA32_EBL_CR_POWERON msr + * KVM: MMU: Simplify kvm_mmu_free_page() a tiny bit + * KVM: MMU: Store shadow page tables as kernel virtual addresses, not + physical + * KVM: VMX: Only reload guest msrs if they are already loaded + * KVM: Avoid corrupting tr in real mode + * KVM: Fix vmx I/O bitmap initialization on highmem systems + * KVM: Remove merge artifact + * KVM: VMX: Use local labels in inline assembly + * KVM: VMX: Handle #SS faults from real mode + * KVM: VMX: Avoid saving and restoring msrs on lightweight vmexit + * KVM: VMX: Compile-fix for 32-bit hosts + * KVM: VMX: Cleanup redundant code in MSR set + * KVM: VMX: Fix a typo which mixes X86_64 and CONFIG_X86_64 + * KVM: VMX: Avoid saving and restoring msr_efer on lightweight vmexit + * KVM: VMX: Remove warnings on i386 + * Use menuconfig objects II - KVM/Virt + * KVM: x86 emulator: implement wbinvd + * KVM: Fix includes + * KVM: Use symbolic constants instead of magic numbers + * KVM: MMU: Use slab caches for shadow pages and their headers + * KVM: MMU: Simplify fetch() a little bit + * KVM: MMU: Move set_pte_common() to pte width dependent code + * KVM: MMU: Pass the guest pde to set_pte_common + * KVM: MMU: Fold fix_read_pf() into set_pte_common() + * KVM: MMU: Fold fix_write_pf() into set_pte_common() + * KVM: Move shadow pte modifications from set_pte/set_pde to + set_pde_common() + * KVM: Make shadow pte updates atomic + * KVM: MMU: Make setting shadow ptes atomic on i386 + * KVM: MMU: Remove cr0.wp tricks + * KVM: MMU: Simpify accessed/dirty/present/nx bit handling + * KVM: MMU: Don't cache guest access bits in the shadow page table + * KVM: MMU: Remove unused large page marker + * KVM: VMX: Fix asm constraint + * KVM: Lazy guest cr3 switching + * KVM: Replace C code with call to ARRAY_SIZE() macro. + * KVM: Remove unnecessary initialization and checks in mark_page_dirty() + * KVM: Fix vcpu freeing for guest smp + * KVM: Fix adding an smp virtual machine to the vm list + * KVM: Enable guest smp + * KVM: Move duplicate halt handling code into kvm_main.c + * KVM: Emulate hlt on real mode for Intel + * KVM: Keep an upper bound of initialized vcpus + * KVM: Flush remote tlbs when reducing shadow pte permissions + * KVM: SVM: Replace memset(, 0, PAGESIZE) with clear_page() + * KVM: VMX: Replace memset(, 0, PAGESIZE) with clear_page() + * KVM: Require a cpu which can set 64-bit values atomically + * KVM: Initialize the BSP bit in the APIC_BASE msr correctly + * KVM: VMX: Ensure vcpu time stamp counter is monotonous + * KVM: Bring local tree in line with origin + * KVM: Implement emulation of "pop reg" instruction (opcode 0x58-0x5f) + * KVM: Implement emulation of instruction "ret" (opcode 0xc3) + * KVM: Adds support for in-kernel mmio handlers + * KVM: VMX: Fix interrupt checking on lightweight exit + * KVM: Add support for in-kernel pio handlers + * KVM: Fix x86 emulator writeback + * KVM: Avoid useless memory write when possible + * KVM: VMX: Reinitialize the real-mode tss when entering real mode + * KVM: MMU: Fix Wrong tlb flush order + * KVM: VMX: Remove unnecessary code in vmx_tlb_flush() + * KVM: SVM: Reliably detect if SVM was disabled by BIOS + * KVM: Remove kvmfs in favor of the anonymous inodes source + * KVM: Clean up #includes + * KVM: Fix svm availability check miscompile on i386 + * HOTPLUG: Add CPU_DYING notifier + * HOTPLUG: Adapt cpuset hotplug callback to CPU_DYING + * HOTPLUG: Adapt thermal throttle to CPU_DYING + * SMP: Implement on_cpu() + * KVM: Keep track of which cpus have virtualization enabled + * KVM: Tune hotplug/suspend IPIs + * KVM: Use CPU_DYING for disabling virtualization + * KVM: MMU: Store nx bit for large page shadows + * KVM: Fix *nopage() in kvm_main.c + * KVM: SMP: Add vcpu_id field in struct vcpu + * KVM - add hypercall nr to kvm_run + * KVM:: Future-proof the exit information union ABI + * KVM: In-kernel string pio write support + * KVM: Fix memory slot management functions for guest smp + * KVM: x86 emulator: implement rdmsr and wrmsr + * KVM: Trivial: /dev/kvm interface is no longer experimental. + * KVM: Trivial: Remove unused struct cpu_user_regs declaration + * KVM: Trivial: Make decode_register() static + * KVM: Trivial: Comment spelling may escape grep + * KVM: Trivial: Avoid hardware_disable predeclaration + * KVM: Trivial: Use standard CR0 flags macros from asm/cpu-features.h + * Use standard CR3 flags, tighten checking + * Use standard CR4 flags, tighten checking + * KVM: Trivial: Use standard BITMAP macros, open-code userspace-exposed + header + * KVM: Set exit_reason to KVM_EXIT_MMIO where run->mmio is initialized. + * KVM: Use standard CR8 flags, and fix TPR definition + * KVM: MMU: Fix oopses with SLUB + * KVM: x86 emulator: fix cmov for writeback changes + * KVM: MMU: Fix cleaning up the shadow page allocation cache + * KVM: Require CONFIG_ANON_INODES + * KVM: x86 emulator: fix faulty check for two-byte opcode + * KVM: Correctly handle writes crossing a page boundary + * KVM: Fix unlikely kvm_create vs decache_vcpus_on_cpu race + * KVM: Hoist kvm_mmu_reload() out of the critical section + * KVM: Fix removal of nx capability from guest cpuid + * KVM: Move gfn_to_page out of kmap/unmap pairs + * KVM: disable writeback for 0x0f 0x01 instructions. + * KVM: VMX: Import some constants of vmcs from IA32 SDM + * KVM: Remove dead code in the cmpxchg instruction emulation + * KVM: load_pdptrs() cleanups + * KVM: Remove arch specific components from the general code + * KVM: Dynamically allocate vcpus + * KVM: VMX: Improve the method of writing vmcs control + * KVM: Use the scheduler preemption notifiers to make kvm preemptible + * KVM: Convert vm lock to a mutex + * KVM: fx_init() needs preemption disabled while it plays with the FPU + state + * KVM: VMX: pass vcpu_vmx internally + * KVM: Remove three magic numbers + * KVM: SVM: de-containization + * KVM: SVM: internal function name cleanup + * KVM: x86 emulator: disable writeback for debug register instructions + * KVM: Change the emulator_{read,write,cmpxchg}_* functions to take a + vcpu + * KVM: Remove kvm_{read,write}_guest() + * KVM: Use kmem cache for allocating vcpus + * KVM: Use alignment properties of vcpu to simplify FPU ops + * KVM: kvm_vm_ioctl_get_dirty_log restore "nothing dirty" optimization + * KVM: VMX: Add cpu consistency check + * KVM: Don't assign vcpu->cr3 if it's invalid: check first, set last + * KVM: Cleanup mark_page_dirty + * KVM: SVM: Make set_msr_interception more reliable + * KVM: Remove redundant alloc_vmcs_cpu declaration + * KVM: Fix defined but not used warning in drivers/kvm/vmx.c + * KVM: Remove stat_set from debugfs + * KVM: Remove unneeded kvm_dev_open and kvm_dev_release functions. + * KVM: Add and use pr_unimpl for standard formatting of unimplemented + features + * KVM: Use kmem_cache_free for kmem_cache_zalloc'ed objects + * KVM: VMX: Remove a duplicated ia32e mode vm entry control + * KVM: Remove useless assignment + * KVM: Cleanup string I/O instruction emulation + * KVM: Clean up kvm_setup_pio() + * KVM: VMX: Don't require cr8 load/store exit capability when running on + 32-bit + * KVM: Close minor race in signal handling + * KVM: Communicate cr8 changes to userspace + * KVM: x86 emulator: implement 'and $imm, %{al|ax|eax}' + * KVM: x86 emulator: implement 'jmp rel' instruction (opcode 0xe9) + * KVM: x86 emulator: Implement 'jmp rel short' instruction (opcode 0xeb) + * KVM: x86 emulator: implement 'push reg' (opcodes 0x50-0x57) + * KVM: VMX: allow rmode_tss_base() to work with >2G of guest memory + * KVM: Avoid calling smp_call_function_single() with interrupts disabled + * KVM: MMU: Fix rare oops on guest context switch + * KVM: Support more memory slots + * KVM: X86 emulator: fix 'push reg' writeback + * KVM: VMX: Split segments reload in vmx_load_host_state() + * KVM: Add support for in-kernel PIC emulation + * KVM: Define and use cr8 access functions + * KVM: Emulate local APIC in kernel + * KVM: In-kernel I/O APIC model + * KVM: Emulate hlt in the kernel + * KVM: Protect in-kernel pio using kvm->lock + * KVM: Add get/set irqchip ioctls for in-kernel PIC live migration + support + * KVM: Bypass irq_pending get/set when using in kernel irqchip + * KVM: in-kernel IOAPIC save and restore support + * KVM: in-kernel LAPIC save and restore support + * KVM: pending irq save/restore + * KVM: VMX: Use shadow TPR/cr8 for 64-bits guests + * KVM: Keep track of missed timer irq injections + * KVM: Migrate lapic hrtimer when vcpu moves to another cpu + * KVM: disable tpr/cr8 sync when in-kernel APIC is used + * KVM: VMX: Fix tpr threshold updating + * KVM: deliver PIC interrupt only to vcpu0 + * KVM: round robin for APIC lowest priority delivery mode + * KVM: enable in-kernel APIC INIT/SIPI handling + * KVM: Set the ET flag in CR0 after initializing FX + * KVM: Remove the unused invlpg member of struct kvm_arch_ops. + * KVM: Clean up unloved invlpg emulation + * KVM: Keep control regs in sync + * KVM: Hoist SVM's get_cs_db_l_bits into core code. + * KVM: Simplify memory allocation + * KVM: Rename kvm_arch_ops to kvm_x86_ops + * KVM: Fix lapic 64-bit division on 32-bit hosts + * KVM: fix apic timer migration when inactive + * KVM: MMU: Don't do GFP_NOWAIT allocations + * KVM: Remove smp_processor_id() in kvm_vcpu_kick() + * KVM: VMX: Move vm entry failure handling to the exit handler + * KVM: Move main vcpu loop into subarch independent code + * KVM: Fix link error to "genapic" + * KVM: VMX: Fix exit qualification width on i386 + * KVM: x86 emulator: push imm8 + * KVM: x86 emulator: call near + * KVM: x86 emulator: pushf + * KVM: Improve emulation failure reporting + * KVM: VMX: Prevent setting CPU_BASED_TPR_SHADOW on i386 host + * KVM: x86 emulator: sort opcodes into ascending order + * KVM: x86 emulator: imlpement jump conditional relative + * KVM: X86 emulator: jump conditional short + * KVM: x86 emulator: lea + * KVM: x86 emulator: jmp abs + * KVM: x86 emulator: fix src, dst value initialization + * KVM: x86 emulator: popf + * KVM: Skip pio instruction when it is emulated, not executed + * KVM: fix PIC interrupt delivery on different APIC conditions + * KVM: Fix kvm_vcpu_ioctl_get_sregs() warning on i386 + * KVM: Remove errant printk() in kvm_vcpu_ioctl_get_sregs() + * KVM: Fix virtualization menu help text + * KVM: x86 emulator: Add vmmcall/vmcall to x86_emulate (v3) + * KVM: Refactor hypercall infrastructure (v3) + * KVM: x86 emulator: remove unused functions + * KVM: x86 emulator: move all x86_emulate_memop() to a structure + * KVM: x86 emulator: move all decoding process to function + x86_decode_insn() + * KVM: emulate_instruction() calls now x86_decode_insn() and + x86_emulate_insn() + * KVM: Call x86_decode_insn() only when needed + * KVM: Fix ioapic level-triggered interrupt redelivery + * KVM: Fix #UD exception delivery + * KVM: VMX: Further reduce efer reloads + * KVM: VMX: Fix build on i386 due to EFER_LMA not defined + * KVM: Fix ioapic.c compilation failure due to missing include + * KVM: x86 emulator: fix merge screwup due to emulator split + * KVM: x85 emulator: Correct inconcistency in between cr2 and ctxt->cr2. + * KVM: Avoid redelivery of edge-triggered irq if it is already in service + * KVM: Implement ioapic irq polarity bit + * KVM: x86 emulator: fix repne/repnz decoding + * KVM: Fix host oops due to guest changing efer + * KVM: Fix ioapic edge-triggered interrupts + * KVM: MMU: Set shadow pte atomically in mmu_pte_write_zap_pte() + * KVM: Allow not-present guest page faults to bypass kvm + * KVM: MMU: Make flooding detection work when guest page faults are + bypassed + * KVM: MMU: Ignore reserved bits in cr3 in non-pae mode + * KVM: x86 emulator: split some decoding into functions for readability + * KVM: x86 emulator: remove _eflags and use directly ctxt->eflags. + * KVM: x86 emulator: Remove no_wb, use dst.type = OP_NONE instead + * KVM: x86_emulator: no writeback for bt + * KVM: apic round robin cleanup + * KVM: Purify x86_decode_insn() error case management + * KVM: x86 emulator: Any legacy prefix after a REX prefix nullifies its + effect + * i386: Expose IOAPIC register definitions even if CONFIG_X86_IO_APIC is + not set + * KVM: x86 emulator: On a pop instruction, don't restore ECX and EIP on + error + * KVM: x86 emulator: remove unused variable + * KVM: VMX: Don't clear the vmcs if the vcpu is not loaded on any + processor + * KVM: VMX: Simplify vcpu_clear() + * KVM: Remove the usage of paeg->private field by rmap + * KVM: x86 emulator: Correct management of REP prefix + * KVM: Add general accessors to read and write guest memory + * KVM: Allow dynamic allocation of the mmu shadow cache size + * KVM: Check I/O APIC indirect index before writing + * KVM: Add kvm_free_lapic() to pair with kvm_create_lapic() + * KVM: Hoist kvm_create_lapic() into kvm_vcpu_init() + * KVM: Remove gratuitous casts from lapic.c + * KVM: CodingStyle cleanup + * KVM: VMX: Handle NMIs before enabling interrupts and preemption + * KVM: Support assigning userspace memory to the guest + * KVM: Export PIC reset for kernel device reset + * KVM: Split IOAPIC reset function and export for kernel RESET + * KVM: VMX: Reset mmu context when entering real mode + * KVM: Replace enum by #define + * KVM: Move x86 msr handling to new files x86.[ch] + * KVM: MMU: Clean up MMU functions to take struct kvm when appropriate + * KVM: MMU: More struct kvm_vcpu -> struct kvm cleanups + * KVM: Move guest pte dirty bit management to the guest pagetable walker + * KVM: MMU: Fix nx access bit for huge pages + * KVM: MMU: Disable write access on clean large pages + * KVM: MMU: Instatiate real-mode shadows as user writable shadows + * KVM: MMU: Move dirty bit updates to a separate function + * KVM: MMU: When updating the dirty bit, inform the mmu about it + * KVM: Portability: split kvm_vcpu_ioctl + * KVM: Restore missing #include + * KVM: Add some \n in ioapic_debug() + * KVM: x86 emulator: implement 'movnti mem, reg' + * KVM: MMU: Call update_dirty_bit() without disabling preemption + * KVM: Move apic timer interrupt backlog processing to common code + * KVM: Move interrupt injection out of interrupt disabled section + * KVM: Rename KVM_TLB_FLUSH to KVM_REQ_TLB_FLUSH + * KVM: VMX: Force vm86 mode if setting flags during real mode + * KVM: MMU: Simplify page table walker + * KVM: Actually move the interrupt injection code out of the critical + section + * KVM: x86 emulator: cmc, clc, cli, sti + * KVM: x86 emulator: use a defined flag definition + * KVM: x86 emulator: fix access registers for instructions with ModR/M + byte and Mod = 3 + * KVM: MMU: Add rmap_next(), a helper for walking kvm rmaps + * KVM: MMU: Keep a reverse mapping of non-writable translations + * KVM: MMU: Make gfn_to_page() always safe + * KVM: Partial swapping of guest memory + * KVM: VMX: Initialize vcpu with preemption enabled + * KVM: Use virtual cpu accounting if available for guest times. + * KVM: Move kvm_guest_exit() after local_irq_enable() + * KVM: MMU: Fix dirty bit pte gpa calculation + * KVM: Allocate userspace memory for older userspace + * KVM: Portability: Split kvm_vcpu into arch dependent and independent + parts (part 1) + * KVM: Fix local apic timer divide by zero + * KVM: Move vmx_vcpu_reset() out of vmx_vcpu_setup() + * KVM: Add a might_sleep() annotation to gfn_to_page() + * KVM: VMX: vmx_vcpu_setup(): remove unused variable. + * KVM: Per-architecture hypercall definitions + * KVM: Use new smp_call_function_mask() in kvm_flush_remote_tlbs() + * KVM: Unmap kernel-allocated memory on slot destruction + * KVM: Export memory slot allocation mechanism + * KVM: Add kernel-internal memory slots + * KVM: Add ioctl to tss address from userspace, + * KVM: x86 emulator: fix 'push imm8' emulation + * KVM: VMX: Let gcc to choose which registers to save (x86_64) + * KVM: VMX: Let gcc to choose which registers to save (i386) + * KVM: SVM: Let gcc to choose which registers to save (x86_64) + * KVM: SVM: Let gcc to choose which registers to save (i386) + * KVM: x86 emulator: invd instruction + * KVM: SVM: Intercept the 'invd' and 'wbinvd' instructions + * KVM: x86 emulator: don't depend on cr2 for mov abs emulation + * KVM: Move page fault processing to common code + * KVM: MMU: Topup the mmu memory preallocation caches before emulating an + insn + * KVM: Portability: Split kvm_vm_ioctl v3 + * KVM: Portability: Move memory segmentation to x86.c + * KVM: Portability: move get/set_apic_base to x86.c + * KVM: Portability: Move control register helper functions to x86.c + * KVM: VMX: Enable memory mapped TPR shadow (FlexPriority) + * KVM: Fix gfn_to_page() acquiring mmap_sem twice + * KVM: Portability: Move kvm_get/set_msr[_common] to x86.c + * KVM: Portability: Move x86 emulation and mmio device hook to x86.c + * KVM: Portability: Move pio emulation functions to x86.c + * KVM: x86 emulator: Extract the common code of SrcReg and DstReg + * KVM: x86 emulator: centralize decoding of one-byte register access + insns + * KVM: Simplify decode_register_operand() calling convention + * KVM: Make mark_page_dirty() work for aliased pages too. + * KVM: x86 emulator: Hoist modrm and abs decoding into separate functions + * KVM: Portability: Make exported debugfs data architecture-specific + * KVM: Portability: Move x86 instruction emulation code to x86.c + * KVM: Portability: Move x86 FPU handling to x86.c + * KVM: Portability: Move x86 vcpu ioctl handlers to x86.c + * KVM: x86 emulator: Move one-byte insns with reg operand into one-byte + section + * KVM: VMX: Fix repeated allocation of apic access page on smp + * KVM: SVM: Fix SMP with kernel apic + * KVM: Add make_page_dirty() to kvm_clear_guest_page() + * KVM: SVM: Defer nmi processing until switch to host state is complete + * KVM: VMX: Avoid reloading host efer on cpus that don't have it + * KVM: VMX: Use vmx to inject real interrupts + * KVM: Go back to atomically injecting interrupts + * KVM: VMX: Comment VMX primary/secondary exec ctl definitions + * KVM: VMX: wbinvd exiting + * KVM: x86 emulator: fix JMP_REL + * KVM: x86 emulator: fix the saving of of the eip value + * KVM: x86 emulator: remove 8 bytes operands emulator for call near + instruction + * KVM: Simplify CPU_TASKS_FROZEN cpu notifier handling + * KVM: add kvm_is_error_hva() + * KVM: introduce gfn_to_hva() + * KVM: Change kvm_{read,write}_guest() to use copy_{from,to}_user() + * KVM: Portability: Move some includes to x86.c + * KVM: Portability: Move kvm_x86_ops to x86.c + * KVM: Portability: Add vcpu and hardware management arch hooks + * KVM: Portability: Combine kvm_init and kvm_init_x86 + * KVM: Portability: Move x86 specific code from kvm_init() to kvm_arch() + * KVM: x86 emulator: modify 'lods', and 'stos' not to depend on CR2 + * KVM: Portability: move KVM_CHECK_EXTENSION + * KVM: VMX: Consolidate register usage in vmx_vcpu_run() + * KVM: Portability: Make kvm_vcpu_ioctl_translate arch dependent + * KVM: x86 emulator: Rename 'cr2' to 'memop' + * KVM: Remove ptr comparisons to 0 + * KVM: Remove __init attributes for kvm_init_debug and kvm_init_msr_list + * KVM: Portability: Add two hooks to handle kvm_create and destroy vm + * KVM: Replace 'light_exits' stat with 'host_state_reload' + * KVM: Add fpu_reload counter + * KVM: Add instruction emulation statistics + * KVM: Extend stats support for VM stats + * KVM: MMU: Add some mmu statistics + * KVM: x86 emulator: Use emulator_write_emulated and not + emulator_write_std + * KVM: Make unloading of FPU state when putting vcpu arch-independent + * KVM: SVM: Disable Lazy FPU optimization + * KVM: Portability: Move kvm_vcpu_ioctl_get_dirty_log to arch-specific + file + * KVM: Portability: MMU initialization and teardown split + * KVM: Portability: Move some macro definitions from kvm.h to x86.h + * KVM: Portability: Move struct kvm_x86_ops definition to x86.h + * KVM: Portability: Move vcpu regs enumeration definition to x86.h + * KVM: Move some static inline functions out from kvm.h into x86.h + * KVM: Portability: Move some function declarations to x86.h + * KVM: VMX: Force seg.base == (seg.sel << 4) in real mode + * KVM: MMU: Change guest pte access to kvm_{read,write}_guest() + * kvm: simplify kvm_clear_guest_page() + * KVM: Add missing #include + * KVM: MMU: Remove unused variable + * KVM: Remove unused "rmap_overflow" variable + * KVM: Correct consistent typo: "destory" -> "destroy" + * KVM: Move misplaced comment + * KVM: Portability: Move kvm_memory_alias to asm/kvm.h + * KVM: Portability: Move x86 pic strutctures + * KVM: Portability: Move kvm_regs to + * KVM: Portability: Move structure lapic_state to + * KVM: Portability: Move kvm_segment & kvm_dtable structure to + + * KVM: Portability: Move kvm_sregs and msr structures to + * KVM: Portability: Move cpuid structures to + * KVM: Export include/asm-x86/kvm.h + * KVM: MMU: Fix potential memory leak with smp real-mode + * KVM: MMU: Selectively set PageDirty when releasing guest memory + * KVM: x86 emulator: retire ->write_std() + * KVM: x86 emulator: prefetch up to 15 bytes of the instruction executed + * KVM: SVM: Fix FPU leak and re-enable lazy FPU switching + * KVM: Recalculate mmu pages needed for every memory region change + * KVM: Portability: Split kvm_set_memory_region() to have an arch + callout + * KVM: Split vcpu creation to avoid vcpu_load() before preemption setup + * KVM: MMU: Implement guest page fault bypass for nonpae + * KVM: Add statistic for remote tlb flushes + * KVM: MMU: Avoid unnecessary remote tlb flushes when guest updates a pte + * KVM: Add parentheses to silence gcc + * KVM: Don't bother the mmu if cr3 load doesn't change cr3 + * KVM: MMU: Code cleanup + * KVM: MMU: Introduce and use gpte_to_gfn() + * KVM: MMU: Move pse36 handling to the guest walker + * KVM: MMU: Remove extra gaddr parameter from set_pte_common() + * KVM: MMU: Remove set_pde() + * KVM: MMU: Adjust page_header_update_slot() to accept a gfn instead of a + gpa + * KVM: MMU: Introduce gfn_to_gpa() + * KVM: MMU: Simplify nonpaging_map() + * KVM: MMU: Remove gva_to_hpa() + * KVM: Remove gpa_to_hpa() + * KVM: MMU: Rename variable of type 'struct kvm_mmu_page *' + * KVM: MMU: Rename 'release_page' + * KVM: Disallow fork() and similar games when using a VM + * KVM: Enhance guest cpuid management + * KVM: Replace private 'struct segment descriptor' by x86's desc_struct + * KVM: Remove segment_descriptor, part 2 + * KVM: Fix compile error on i386 + * KVM: VMX: Read & store IDT_VECTORING_INFO_FIELD + * KVM: Fix faults during injection of real-mode interrupts + * KVM: x86 emulator: Fix instruction fetch cache hit check + * KVM: VMX: Remove the secondary execute control dependency on irqchip + * KVM: Portability: Move unalias_gfn to arch dependent file + * KVM: x86 emulator: Make a distinction between repeat prefixes F3 and F2 + * KVM: x86 emulator: address size and operand size overrides are sticky + * KVM: Remove desc.h include in kvm_main.c + * KVM: Revert segment_descriptor.h removal + * KVM: Remove misleading check for mmio during event injection + * KVM: MMU: mark pages that were inserted to the shadow pages table as + accessed + * KVM: x86 emulator: rename REP_REPE_PREFIX + * KVM: x86 emulator: cmps instruction + * KVM: Add ifdef in irqchip struct for x86 only structures + * KVM: Fix cpuid2 killing 32-bit guests on non-NX machines + * KVM: x86 emulator: Move rep processing before instruction execution + * KVM: x86 emulator: unify two switches + * KVM: x86 emulator: unify four switch statements into two + * KVM: Don't bypass the mmu if in pae and pdptrs changed + * KVM: Portability: Move KVM_INTERRUPT vcpu ioctl to x86.c + * KVM: Correct kvm_init() error paths not freeing bad_pge. + * KVM: Export include/linux/kvm.h only if $ARCH actually supports KVM + * KVM: SVM: Remove KVM specific defines for MSR_EFER + * KVM: Replace kvm_lapic with kvm_vcpu in ioapic/lapic interface + * KVM: Replace dest_Lowest_Prio and dest_Fixed with self-defined macros + * KVM: Extend ioapic code to support iosapic + * KVM: Portability: Move address types to their own header file + * KVM: Portability: Move IO device definitions to its own header file + * KVM: Portability: Stop including x86-specific headers in kvm_main.c + * KVM: Portability: Create kvm_arch_vcpu_runnable() function + * KVM: Convert KVM from ->nopage() to ->fault() + * KVM: MMU: Remove unused prev_shadow_ent variable from fetch() + * KVM: Generalize exception injection mechanism + * KVM: Replace page fault injection by the generalized exception queue + * KVM: Replace #GP injection by the generalized exception queue + * KVM: Use generalized exception queue for injecting #UD + * KVM: x86 emulator: fix eflags preparation for emulation + * KVM: VMX: Avoid exit when setting cr8 if the local apic is in the + kernel + * KVM: SVM: Emulate read/write access to cr8 + * KVM: x86 emulator: Fix stack instructions on 64-bit mode + * KVM: SVM: Trap access to the cr8 register + * KVM: VMX: Fix cr8 exit optimization + * KVM: MMU: Use cmpxchg for pte updates on walk_addr() + * KVM: MMU: Simplify calculation of pte access + * KVM: MMU: Set nx bit correctly on shadow ptes + * KVM: MMU: Move pte access calculation into a helper function + * KVM: MMU: Fix inherited permissions for emulated guest pte updates + * KVM: MMU: No need to pick up nx bit from guest pte + * KVM: MMU: Pass pte dirty flag to set_pte() instead of calculating it + on-site + * KVM: MMU: Remove walker argument to set_pte() + * KVM: MMU: Move set_pte() into guest paging mode independent code + * KVM: MMU: Adjust mmu_set_spte() debug code for gpte removal + * KVM: MMU: Use mmu_set_spte() for real-mode shadows + * KVM: SVM: Exit to userspace if write to cr8 and not using in-kernel + apic + * KVM: SVM: support writing 0 to K8 performance counter control registers + * KVM: MMU: Fix kunmap_atomic() call in cmpxchg_gpte() + * KVM: MMU: Fix SMP shadow instantiation race + * KVM: LAPIC: minor debugging compile fix + * KVM: MMU: emulated cmpxchg8b should be atomic on i386 + * KVM: Fix bad kunmap_atomic() paramerter inm cmpxchg emulation + * KVM: Make cmpxchg emulation compile on i386 + * KVM: Another cmpxchg i386 compile fix + * KVM: Another cmpxchg emulation compile fix + * KVM: Another cmpxchg emulation compile fix + * KVM: Portability: Move kvm{pic,ioapic} accesors to x86 specific code + * KVM: Portability: Introduce kvm_vcpu_arch + * KVM: Portability: Split mmu-related static inline functions to mmu.h + * KVM: Portability: Move kvm_vcpu definition back to kvm.h + * KVM: Portability: Expand the KVM_VCPU_COMM in kvm_vcpu structure. + * KVM: Portability: Move kvm_vcpu_stat to x86.h + * KVM: Portability: Move memslot aliases to new struct kvm_arch + * KVM: Portability: Move mmu-related fields to kvm_arch + * KVM: Portability: move vpic and vioapic to kvm_arch + * KVM: Portability: Move round_robin_prev_vcpu and tss_addr to kvm_arch + * KVM: Portability: Move kvm_vm_stat to x86.h + * KVM: VMX: Add printk_ratelimit in vmx_intr_assist + * KVM: Move arch dependent files to new directory arch/x86/kvm/ + * KVM: Move drivers/kvm/* to virt/kvm/ + * KVM: Fix compile error in asm/kvm_host.h + * KVM: Move irqchip declarations into new ioapic.h and lapic.h + * KVM: Move ioapic code to common directory. + * KVM: Move kvm_vcpu_kick() to x86.c + * KVM: Expose ioapic to ia64 save/restore APIs + * KVM: MMU: Coalesce remote tlb flushes + * KVM: MMU: Add cache miss statistic + * KVM: Print data for unimplemented wrmsr + * KVM: Ensure pages are copied on write + * KVM: MMU: Fix cmpxchg8b emulation on i386 (again) + * KVM: x86 emulator: Add vmmcall/vmcall to x86_emulate (v3) + * KVM: Refactor hypercall infrastructure (v3) + * KVM: x86 emulator: remove unused functions + * KVM: x86 emulator: move all x86_emulate_memop() to a structure + * KVM: x86 emulator: move all decoding process to function + x86_decode_insn() + * KVM: emulate_instruction() calls now x86_decode_insn() and + x86_emulate_insn() + * KVM: Call x86_decode_insn() only when needed + * KVM: VMX: Further reduce efer reloads + * KVM: Allow not-present guest page faults to bypass kvm + * KVM: MMU: Make flooding detection work when guest page faults are + bypassed + * KVM: MMU: Ignore reserved bits in cr3 in non-pae mode + * KVM: x86 emulator: split some decoding into functions for readability + * KVM: x86 emulator: remove _eflags and use directly ctxt->eflags. + * KVM: x86 emulator: Remove no_wb, use dst.type = OP_NONE instead + * KVM: x86_emulator: no writeback for bt + * KVM: Purify x86_decode_insn() error case management + * KVM: x86 emulator: Any legacy prefix after a REX prefix nullifies its + effect + * KVM: VMX: Don't clear the vmcs if the vcpu is not loaded on any + processor + * KVM: VMX: Simplify vcpu_clear() + * KVM: Remove the usage of page->private field by rmap + * KVM: Add general accessors to read and write guest memory + * KVM: Allow dynamic allocation of the mmu shadow cache size + * KVM: Add kvm_free_lapic() to pair with kvm_create_lapic() + * KVM: Hoist kvm_create_lapic() into kvm_vcpu_init() + * KVM: Remove gratuitous casts from lapic.c + * KVM: CodingStyle cleanup + * KVM: Support assigning userspace memory to the guest + * KVM: Move x86 msr handling to new files x86.[ch] + * KVM: MMU: Clean up MMU functions to take struct kvm when appropriate + * KVM: MMU: More struct kvm_vcpu -> struct kvm cleanups + * KVM: Move guest pte dirty bit management to the guest pagetable walker + * KVM: MMU: Fix nx access bit for huge pages + * KVM: MMU: Disable write access on clean large pages + * KVM: MMU: Instantiate real-mode shadows as user writable shadows + * KVM: MMU: Move dirty bit updates to a separate function + * KVM: MMU: When updating the dirty bit, inform the mmu about it + * KVM: Portability: split kvm_vcpu_ioctl + * KVM: apic round robin cleanup + * KVM: Add some \n in ioapic_debug() + * KVM: Move apic timer interrupt backlog processing to common code + * KVM: Rename KVM_TLB_FLUSH to KVM_REQ_TLB_FLUSH + * KVM: x86 emulator: Implement emulation of instruction: inc & dec + * KVM: MMU: Simplify page table walker + * KVM: x86 emulator: cmc, clc, cli, sti + * KVM: MMU: Add rmap_next(), a helper for walking kvm rmaps + * KVM: MMU: Keep a reverse mapping of non-writable translations + * KVM: MMU: Make gfn_to_page() always safe + * KVM: MMU: Partial swapping of guest memory + * KVM: Use virtual cpu accounting if available for guest times. + * KVM: Allocate userspace memory for older userspace + * KVM: Portability: Split kvm_vcpu into arch dependent and independent + parts (part 1) + * KVM: Move vmx_vcpu_reset() out of vmx_vcpu_setup() + * KVM: Add a might_sleep() annotation to gfn_to_page() + * KVM: Export PIC reset for kernel device reset + * KVM: Split IOAPIC reset function and export for kernel RESET + * KVM: Per-architecture hypercall definitions + * KVM: Unmap kernel-allocated memory on slot destruction + * KVM: Export memory slot allocation mechanism + * KVM: Add kernel-internal memory slots + * KVM: Add ioctl to tss address from userspace, + * KVM: VMX: Let gcc to choose which registers to save (x86_64) + * KVM: VMX: Let gcc to choose which registers to save (i386) + * KVM: SVM: Let gcc to choose which registers to save (x86_64) + * KVM: SVM: Let gcc to choose which registers to save (i386) + * KVM: x86 emulator: don't depend on cr2 for mov abs emulation + * KVM: Move page fault processing to common code + * KVM: MMU: Topup the mmu memory preallocation caches before emulating an + insn + * KVM: Portability: Split kvm_vm_ioctl v3 + * KVM: Portability: Move memory segmentation to x86.c + * KVM: Portability: move get/set_apic_base to x86.c + * KVM: Portability: Move control register helper functions to x86.c + * KVM: VMX: Enable memory mapped TPR shadow (FlexPriority) + * KVM: Fix gfn_to_page() acquiring mmap_sem twice + * KVM: Portability: Move kvm_get/set_msr[_common] to x86.c + * KVM: Portability: Move x86 emulation and mmio device hook to x86.c + * KVM: Portability: Move pio emulation functions to x86.c + * KVM: x86 emulator: Extract the common code of SrcReg and DstReg + * KVM: x86 emulator: centralize decoding of one-byte register access + insns + * KVM: Simplify decode_register_operand() calling convention + * KVM: Make mark_page_dirty() work for aliased pages too. + * KVM: x86 emulator: Hoist modrm and abs decoding into separate functions + * KVM: Portability: Make exported debugfs data architecture-specific + * KVM: Portability: Move x86 instruction emulation code to x86.c + * KVM: Portability: Move x86 FPU handling to x86.c + * KVM: Portability: Move x86 vcpu ioctl handlers to x86.c + * KVM: Add make_page_dirty() to kvm_clear_guest_page() + * KVM: VMX: Use vmx to inject real-mode interrupts + * KVM: VMX: Read & store IDT_VECTORING_INFO_FIELD + * KVM: Fix faults during injection of real-mode interrupts + * KVM: VMX: Comment VMX primary/secondary exec ctl definitions + * KVM: VMX: wbinvd exiting + * KVM: x86 emulator: remove 8 bytes operands emulator for call near + instruction + * KVM: Simplify CPU_TASKS_FROZEN cpu notifier handling + * KVM: add kvm_is_error_hva() + * KVM: introduce gfn_to_hva() + * KVM: Change kvm_{read,write}_guest() to use copy_{from,to}_user() + * KVM: Portability: Move some includes to x86.c + * KVM: Portability: Move kvm_x86_ops to x86.c + * KVM: Portability: Add vcpu and hardware management arch hooks + * KVM: Portability: Combine kvm_init and kvm_init_x86 + * KVM: Portability: Move x86 specific code from kvm_init() to kvm_arch() + * KVM: x86 emulator: modify 'lods', and 'stos' not to depend on CR2 + * KVM: Portability: move KVM_CHECK_EXTENSION + * KVM: VMX: Consolidate register usage in vmx_vcpu_run() + * KVM: Portability: Make kvm_vcpu_ioctl_translate arch dependent + * KVM: Remove ptr comparisons to 0 + * KVM: Remove __init attributes for kvm_init_debug and kvm_init_msr_list + * KVM: Portability: Add two hooks to handle kvm_create and destroy vm + * KVM: Replace 'light_exits' stat with 'host_state_reload' + * KVM: Add fpu_reload counter + * KVM: Add instruction emulation statistics + * KVM: Extend stats support for VM stats + * KVM: MMU: Add some mmu statistics + * KVM: Make unloading of FPU state when putting vcpu arch-independent + * KVM: Portability: Move kvm_vcpu_ioctl_get_dirty_log to arch-specific + file + * KVM: Portability: MMU initialization and teardown split + * KVM: Portability: Move some macro definitions from kvm.h to x86.h + * KVM: Portability: Move struct kvm_x86_ops definition to x86.h + * KVM: Portability: Move vcpu regs enumeration definition to x86.h + * KVM: Move some static inline functions out from kvm.h into x86.h + * KVM: Portability: Move some function declarations to x86.h + * KVM: VMX: Force seg.base == (seg.sel << 4) in real mode + * KVM: MMU: Change guest pte access to kvm_{read,write}_guest() + * KVM: Simplify kvm_clear_guest_page() + * KVM: Add missing #include + * KVM: MMU: Remove unused variable + * KVM: Remove unused "rmap_overflow" variable + * KVM: Correct consistent typo: "destory" -> "destroy" + * KVM: Move misplaced comment + * KVM: Portability: Move kvm_memory_alias to asm/kvm.h + * KVM: Portability: Move x86 pic strutctures + * KVM: Portability: Move kvm_regs to + * KVM: Portability: Move structure lapic_state to + * KVM: Portability: Move kvm_segment & kvm_dtable structure to + + * KVM: Portability: Move kvm_sregs and msr structures to + * KVM: Portability: Move cpuid structures to + * KVM: Export include/asm-x86/kvm.h + * KVM: MMU: Fix potential memory leak with smp real-mode + * KVM: MMU: Selectively set PageDirty when releasing guest memory + * KVM: x86 emulator: retire ->write_std() + * KVM: x86 emulator: prefetch up to 15 bytes of the instruction executed + * KVM: Recalculate mmu pages needed for every memory region change + * KVM: Portability: Split kvm_set_memory_region() to have an arch + callout + * KVM: Split vcpu creation to avoid vcpu_load() before preemption setup + * KVM: MMU: Implement guest page fault bypass for nonpae + * KVM: Add statistic for remote tlb flushes + * KVM: MMU: Avoid unnecessary remote tlb flushes when guest updates a pte + * KVM: Don't bother the mmu if cr3 load doesn't change cr3 + * KVM: MMU: Code cleanup + * KVM: MMU: Introduce and use gpte_to_gfn() + * KVM: MMU: Move pse36 handling to the guest walker + * KVM: MMU: Remove extra gaddr parameter from set_pte_common() + * KVM: MMU: Remove set_pde() + * KVM: MMU: Adjust page_header_update_slot() to accept a gfn instead of a + gpa + * KVM: MMU: Introduce gfn_to_gpa() + * KVM: MMU: Simplify nonpaging_map() + * KVM: MMU: Remove gva_to_hpa() + * KVM: Remove gpa_to_hpa() + * KVM: MMU: Rename variables of type 'struct kvm_mmu_page *' + * KVM: MMU: Rename 'release_page' + * KVM: Disallow fork() and similar games when using a VM + * KVM: Enhance guest cpuid management + * KVM: VMX: Remove the secondary execute control dependency on irqchip + * KVM: Portability: Move unalias_gfn to arch dependent file + * KVM: x86 emulator: Make a distinction between repeat prefixes F3 and F2 + * KVM: x86 emulator: address size and operand size overrides are sticky + * KVM: Remove misleading check for mmio during event injection + * KVM: MMU: mark pages that were inserted to the shadow pages table as + accessed + * KVM: x86 emulator: rename REP_REPE_PREFIX + * KVM: x86 emulator: Rename 'cr2' to 'memop' + * KVM: x86 emulator: cmps instruction + * KVM: Add ifdef in irqchip struct for x86 only structures + * KVM: Fix cpuid2 killing 32-bit guests on non-NX machines + * KVM: x86 emulator: Move rep processing before instruction execution + * KVM: x86 emulator: unify two switches + * KVM: x86 emulator: unify four switch statements into two + * KVM: Portability: Move KVM_INTERRUPT vcpu ioctl to x86.c + * KVM: Correct kvm_init() error paths not freeing bad_pge. + * KVM: Export include/linux/kvm.h only if $ARCH actually supports KVM + * KVM: SVM: Remove KVM specific defines for MSR_EFER + * KVM: Replace kvm_lapic with kvm_vcpu in ioapic/lapic interface + * KVM: Replace dest_Lowest_Prio and dest_Fixed with self-defined macros + * KVM: Extend ioapic code to support iosapic + * KVM: Portability: Move address types to their own header file + * KVM: Portability: Move IO device definitions to its own header file + * KVM: Portability: Stop including x86-specific headers in kvm_main.c + * KVM: Portability: Create kvm_arch_vcpu_runnable() function + * KVM: Convert KVM from ->nopage() to ->fault() + * KVM: MMU: Remove unused prev_shadow_ent variable from fetch() + * KVM: Generalize exception injection mechanism + * KVM: Replace page fault injection by the generalized exception queue + * KVM: Replace #GP injection by the generalized exception queue + * KVM: Use generalized exception queue for injecting #UD + * KVM: x86 emulator: fix eflags preparation for emulation + * KVM: VMX: Avoid exit when setting cr8 if the local apic is in the + kernel + * KVM: SVM: Emulate read/write access to cr8 + * KVM: x86 emulator: Fix stack instructions on 64-bit mode + * KVM: SVM: Trap access to the cr8 register + * KVM: VMX: Fix cr8 exit optimization + * KVM: MMU: Use cmpxchg for pte updates on walk_addr() + * KVM: MMU: Simplify calculation of pte access + * KVM: MMU: Set nx bit correctly on shadow ptes + * KVM: MMU: Move pte access calculation into a helper function + * KVM: MMU: Fix inherited permissions for emulated guest pte updates + * KVM: MMU: No need to pick up nx bit from guest pte + * KVM: MMU: Pass pte dirty flag to set_pte() instead of calculating it + on-site + * KVM: MMU: Remove walker argument to set_pte() + * KVM: MMU: Move set_pte() into guest paging mode independent code + * KVM: MMU: Adjust mmu_set_spte() debug code for gpte removal + * KVM: MMU: Use mmu_set_spte() for real-mode shadows + * KVM: SVM: Exit to userspace if write to cr8 and not using in-kernel + apic + * KVM: MMU: Fix SMP shadow instantiation race + * KVM: LAPIC: minor debugging compile fix + * KVM: SVM: support writing 0 to K8 performance counter control registers + * KVM: MMU: emulated cmpxchg8b should be atomic on i386 + * KVM: Portability: Move kvm{pic,ioapic} accesors to x86 specific code + * KVM: Portability: Introduce kvm_vcpu_arch + * KVM: Portability: Split mmu-related static inline functions to mmu.h + * KVM: Portability: Move kvm_vcpu definition back to kvm.h + * KVM: Portability: Expand the KVM_VCPU_COMM in kvm_vcpu structure. + * KVM: Portability: Move kvm_vcpu_stat to x86.h + * KVM: Portability: Move memslot aliases to new struct kvm_arch + * KVM: Portability: Move mmu-related fields to kvm_arch + * KVM: Portability: move vpic and vioapic to kvm_arch + * KVM: Portability: Move round_robin_prev_vcpu and tss_addr to kvm_arch + * KVM: Portability: Move kvm_vm_stat to x86.h + * KVM: VMX: Add printk_ratelimit in vmx_intr_assist + * KVM: Move arch dependent files to new directory arch/x86/kvm/ + * KVM: Move drivers/kvm/* to virt/kvm/ + * KVM: Move irqchip declarations into new ioapic.h and lapic.h + * KVM: Move ioapic code to common directory. + * KVM: Move kvm_vcpu_kick() to x86.c + * KVM: Expose ioapic to ia64 save/restore APIs + * KVM: MMU: Coalesce remote tlb flushes + * KVM: MMU: Add cache miss statistic + * KVM: Print data for unimplemented wrmsr + * KVM: Ensure pages are copied on write + * KVM: local APIC TPR access reporting facility + * KVM: Accelerated apic support + * KVM: Disable vapic support on Intel machines with FlexPriority + * KVM: MMU: Concurrent guest walkers + * KVM: Add kvm_read_guest_atomic() + * KVM: MMU: Avoid calling gfn_to_page() in mmu_set_spte() + * KVM: MMU: Switch to mmu spinlock + * KVM: MMU: Move kvm_free_some_pages() into critical section + * KVM: MMU: Broaden scope of mmap_sem to include actual mapping + * KVM: MMU: Fix recursive locking of mmap_sem() + * KVM: Fix unbalanced mmap_sem operations in cmpxchg8b emulation + * KVM: Mark vapic page as dirty for save/restore/migrate + * KVM: x86 emulator: Only allow VMCALL/VMMCALL trapped by #UD + * KVM: MMU: Update shadow ptes on partial guest pte writes + * KVM: MMU: Simplify hash table indexing + * KVM: Portability: Move kvm_fpu to asm-x86/kvm.h + * KVM: MMU: Fix dirty page setting for pages removed from rmap + * KVM: Initialize the mmu caches only after verifying cpu support + * KVM: Fix unbounded preemption latency + * KVM: Put kvm_para.h include outside __KERNEL__ + * KVM: Move apic timer migration away from critical section + * KVM: SVM: Fix lazy FPU switching + * KVM: MMU: Fix gpa truncation when reading a pte + * [GFS2] Handle multiple glock demote requests + * [GFS2] Clean up internal read function + * [GFS2] Use ->page_mkwrite() for mmap() + * [GFS2] Remove useless i_cache from inodes + * [GFS2] Remove unused field in struct gfs2_inode + * [GFS2] Add gfs2_is_writeback() + * [GFS2] Introduce gfs2_set_aops() + * [GFS2] Split gfs2_writepage into three cases + * [GFS2] Add writepages for GFS2 jdata + * [GFS2] Don't hold page lock when starting transaction + * [GFS2] Use correct include file in ops_address.c + * [GFS2] Remove unused variables + * [GFS2] Remove "reclaim limit" + * [GFS2] Add sync_page to metadata address space operations + * [GFS2] Reorder writeback for glock sync + * [GFS2] Remove flags no longer required + * [GFS2] Given device ID rather than s_id in "id" sysfs file + * [GFS2] check kthread_should_stop when waiting + * [GFS2] Don't add glocks to the journal + * [GFS2] Use atomic_t for journal free blocks counter + * [GFS2] Move gfs2_logd into log.c + * [GFS2] Don't periodically update the jindex + * [GFS2] Check for installation of mount helpers for DLM mounts + * [GFS2] tidy up error message + * [GFS2] Fix runtime issue with UP kernels + * [GFS2] remove unnecessary permission checks + * [GFS2] Fix build warnings + * [GFS2] Remove unrequired code + * [GFS2] Remove lock methods for lock_nolock protocol + * [GFS2] patch to check for recursive lock requests in gfs2_rename code + path + * [GFS2] Remove unused variable + * [GFS2] use pid for plock owner for nfs clients + * [GFS2] Remove function gfs2_get_block + * [GFS2] Journal extent mapping + * [GFS2] Get rid of useless "found" variable in quota.c + * [GFS2] Run through full bitmaps quicker in gfs2_bitfit + * [GFS2] Reorganize function gfs2_glmutex_lock + * [GFS2] Only fetch the dinode once in block_map + * [GFS2] Function meta_read optimization + * [GFS2] Incremental patch to fix compiler warning + * [GFS2] Eliminate the no longer needed sd_statfs_mutex + * [GFS2] Minor correction + * [GFS2] Fix log block mapper + * [GFS2] Remove unused variable + * [GFS2] Allow page migration for writeback and ordered pages + * [GFS2] Initialize extent_list earlier + * [GFS2] Fix problems relating to execution of files on GFS2 + * [GFS2] Fix assert in log code + * [GFS2] Reduce inode size by moving i_alloc out of line + * [GFS2] Remove unneeded i_spin + * [GFS2] gfs2_alloc_required performance + * [GFS2] Fix write alloc required shortcut calculation + * [GFS2] Fix typo + * [GFS2] Fix page_mkwrite truncation race path + * [GFS2] Lockup on error + * [GFS2] Allow journal recovery on read-only mount + + -- Tim Gardner Sun, 27 Jan 2008 20:37:18 -0700 + +linux (2.6.24-5.9) hardy; urgency=low + + [Amit Kucheria] + + * Fix LPIA FTBFS due to virtio Ignore: yes + + [Upstream Kernel Changes] + + * ACPI: processor: Fix null pointer dereference in throttling + * [SPARC64]: Fix of section mismatch warnings. + * [SPARC64]: Fix section error in sparcspkr + * [SPARC]: Constify function pointer tables. + * [BLUETOOTH]: Move children of connection device to NULL before + connection down. + * [TULIP] DMFE: Fix SROM parsing regression. + * [IPV4]: Add missing skb->truesize increment in ip_append_page(). + * iwlwifi: fix possible read attempt on ucode that is not available + * [NETNS]: Re-export init_net via EXPORT_SYMBOL. + * [INET]: Fix truesize setting in ip_append_data + * sis190: add cmos ram access code for the SiS19x/968 chipset pair + * sis190: remove duplicate INIT_WORK + * sis190: mdio operation failure is not correctly detected + * sis190: scheduling while atomic error + * Update ctime and mtime for memory-mapped files + * [SCSI] initio: fix module hangs on loading + * xen: disable vcpu_info placement for now + * agp/intel: add support for E7221 chipset + * drm/i915: add support for E7221 chipset + * DMI: move dmi_available declaration to linux/dmi.h + * DMI: create dmi_get_slot() + * ACPI: create acpi_dmi_dump() + * ACPI: on OSI(Linux), print needed DMI rather than requesting dmidecode + output + * ACPI: Delete Intel Customer Reference Board (CRB) from OSI(Linux) DMI + list + * ACPI: make _OSI(Linux) console messages smarter + * ACPI: Add ThinkPad R61, ThinkPad T61 to OSI(Linux) white-list + * ACPI: DMI blacklist to reduce console warnings on OSI(Linux) systems. + * ACPI: EC: fix dmesg spam regression + * ACPI: EC: add leading zeros to debug messages + * Pull bugzilla-9747 into release branch + * Pull bugzilla-8459 into release branch + * Pull bugzilla-9798 into release branch + * Pull dmi-2.6.24 into release branch + * [SPARC64]: Partially revert "Constify function pointer tables." + * lockdep: fix kernel crash on module unload + * sysctl: kill binary sysctl KERN_PPC_L2CR + * fix hugepages leak due to pagetable page sharing + * spi: omap2_mcspi PIO RX fix + * Linux 2.6.24 + + -- Tim Gardner Fri, 25 Jan 2008 01:44:27 -0700 + +linux (2.6.24-5.8) hardy; urgency=low + + [Alessio Igor Bogani] + + * rt: Update to 2.6.24-rc8-rt1 + * rt: Update configuration files + + [Amit Kucheria] + + * Asix: fix breakage caused in 2.6.24-rc7 + * Add CONFIG_CPUSETS to server-related flavours + - LP: #182434 + + [Chuck Short] + + * SAUCE: ata: blacklist FUJITSU MHW2160BH PL + - LP: #175834 + + [Kees Cook] + + * AppArmor: updated patch series to upstream SVN 1079. + + [Soren Hansen] + + * Updated configs to enable virtio stuff Ignore: yes + + [Stefan Bader] + + * Enabled CONFIG_BSD_PROCESS_ACCT=y for sparc. + - LP: #176587 + * Enable CONFIG_AUDITSYSCALL=y. + - LP: #140784 + * Added CONFIG_AUDIT_SYSCALL=y to custom lpia(compat) + * Enabled CONFIG_HUGETLBFS=y for i386/server amd64/server and ia64. + * Lower priority of pnpacpi resource messages to warning level. + - LP: #159241 + * Fix the messed up message level of pnpacpi parser. + + [Tim Gardner] + + * Start new release, bump ABI to -5 + * Disabled iwlwifi preperatory to moving it to l-u-m. + * Enabled CONFIG_USB_SERIAL_KEYSPAN + * Disabled CONFIG_CGROUPS. + * Virtio config settings for -rt. + * Re-enable IWLWIFI in the kernel. + * Fixed -rt saa7134-core.c FTBS + + [Upstream Kernel Changes] + + * Input: Handle EV_PWR type of input caps in input_set_capability. + * Input: jornada680_kbd - fix default keymap + * increase PNP_MAX_PORT to 40 from 24 + * sched: fix gcc warnings + * leds: Fix leds_list_lock locking issues + * leds: Fix locomo LED driver oops + * x86: fix asm-x86/byteorder.h for userspace export + * x86: fix asm-x86/msr.h for user-space export + * ACPI: EC: Enable boot EC before bus_scan + * ACPI: Make sysfs interface in ACPI power optional. + * fix lguest rmmod "bad pgd" + * slub: provide /proc/slabinfo + * [POWERPC] Fix build failure on Cell when CONFIG_SPU_FS=y + * slub: register slabinfo to procfs + * [SCSI] scsi_sysfs: restore prep_fn when ULD is removed + * Unify /proc/slabinfo configuration + * scsi: revert "[SCSI] Get rid of scsi_cmnd->done" + * restrict reading from /proc//maps to those who share ->mm or can + ptrace pid + * Fix kernel/ptrace.c compile problem (missing "may_attach()") + * hwmon: (w83627ehf) Be more careful when changing VID input level + * NFS: Fix a possible Oops in fs/nfs/super.c + * NFSv4: Fix circular locking dependency in nfs4_kill_renewd + * NFS: add newline to kernel warning message in auth_gss code + * NFSv4: nfs4_open_confirm must not set the open_owner as confirmed on + error + * NFSv4: Fix open_to_lock_owner sequenceid allocation... + * gameport: don't export functions that are static inline + * Input: spitzkbd - fix suspend key handling + * Input: pass EV_PWR events to event handlers + * [ARM] 4735/1: Unbreak pxa25x suspend/resume + * IB/srp: Fix list corruption/oops on module reload + * Console is utf-8 by default + * [IA64] Update Altix BTE error return status patch + * [IA64] Update Altix nofault code + * [X25]: Add missing x25_neigh_put + * [XFRM]: Do not define km_migrate() if !CONFIG_XFRM_MIGRATE + * [CASSINI]: Fix endianness bug. + * [CASSINI]: Revert 'dont touch page_count'. + * [CASSINI]: Program parent Intel31154 bridge when necessary. + * [CASSINI]: Set skb->truesize properly on receive packets. + * [CASSINI]: Fix two obvious NAPI bugs. + * [CASSINI]: Bump driver version and release date. + * [INET]: Fix netdev renaming and inet address labels + * [CONNECTOR]: Return proper error code in cn_call_callback() + * [ISDN] i4l: 'NO CARRIER' message lost after ldisc flush + * [ISDN]: i4l: Fix DLE handling for i4l-audio + * fix: using joysticks in 32 bit applications on 64 bit systems + * [ARM] 4691/1: add missing i2c_board_info struct for at91rm9200 + * hda_intel suspend latency: shorten codec read + * CPU hotplug: fix cpu_is_offline() on !CONFIG_HOTPLUG_CPU + * Linux 2.6.24-rc7 + * sh: Fix argument page dcache flushing regression. + * V4L/DVB (6944a): Fix Regression VIDIOCGMBUF ioctl hangs on bttv driver + * V4L/DVB (6916): ivtv: udelay has to be changed *after* the eeprom was + read, not before + * [MIPS] Move inclusing of kernel/time/Kconfig menu to appropriate place + * [MIPS] Alchemy: Fix use of __init code bug exposed by modpost warning + * [MIPS] Fix IP32 breakage + * [MIPS] Assume R4000/R4400 newer than 3.0 don't have the mfc0 count bug + * [MIPS] Fix CONFIG_BOOT_RAW. + * ACPI: Reintroduce run time configurable max_cstate for !CPU_IDLE case + * core dump: real_parent ppid + * acct: real_parent ppid + * IB/mlx4: Fix value of pkey_index in QP1 completions + * IB/srp: Release transport before removing host + * x86: fix do_fork_idle section mismatch + * spi_bitbang: always grab lock with irqs blocked + * fat: optimize fat_count_free_clusters() + * KEYS: fix macro + * md: fix data corruption when a degraded raid5 array is reshaped + * xip: fix get_zeroed_page with __GFP_HIGHMEM + * eCryptfs: fix dentry handling on create error, unlink, and inode + destroy + * vmcoreinfo: add the array length of "free_list" for filtering free + pages + * dmi-id: fix for __you_cannot_kmalloc_that_much failure + * snd_mixer_oss_build_input(): fix for __you_cannot_kmalloc_that_much + failure with gcc-3.2 + * Fix crash with FLAT_MEMORY and ARCH_PFN_OFFSET != 0 + * hfs: handle more on-disk corruptions without oopsing + * pl2303: Fix mode switching regression + * futex: Prevent stale futex owner when interrupted/timeout + * [NIU]: Fix slowpath interrupt handling. + * [NIU]: Missing ->last_rx update. + * [NIU]: Fix potentially stuck TCP socket send queues. + * [NIU]: Update driver version and release date. + * [IPV4] raw: Strengthen check on validity of iph->ihl + * [IPV4] ipconfig: Fix regression in ip command line processing + * [NET]: Fix netx-eth.c compilation. + * [METH]: Fix MAC address handling. + * [TULIP]: NAPI full quantum bug. + * [ATM]: [nicstar] delay irq setup until card is configured + * [SCTP]: Fix the name of the authentication event. + * [SCTP]: Correctly handle AUTH parameters in unexpected INIT + * [SCTP]: Add back the code that accounted for FORWARD_TSN parameter in + INIT. + * [IRDA]: irda_create() nuke user triggable printk + * b43: Fix rxheader channel parsing + * [NET]: Do not grab device reference when scheduling a NAPI poll. + * [NET]: Add NAPI_STATE_DISABLE. + * [NET]: Do not check netif_running() and carrier state in ->poll() + * ssb: Fix probing of PCI cores if PCI and PCIE core is available + * mac80211: return an error when SIWRATE doesn't match any rate + * [NETXEN]: Fix ->poll() done logic. + * [NET]: Fix drivers to handle napi_disable() disabling interrupts. + * [NET]: Stop polling when napi_disable() is pending. + * [NET]: Make ->poll() breakout consistent in Intel ethernet drivers. + * [NET] Intel ethernet drivers: update MAINTAINERS + * [NET]: kaweth was forgotten in msec switchover of usb_start_wait_urb + * [IPV4] ROUTE: ip_rt_dump() is unecessary slow + * [NET]: Clone the sk_buff 'iif' field in __skb_clone() + * [LRO] Fix lro_mgr->features checks + * [NET]: mcs7830 passes msecs instead of jiffies to usb_control_msg + * [FORCEDETH]: Fix reversing the MAC address on suspend. + * [XFRM]: xfrm_algo_clone() allocates too much memory + * [SOCK]: Adds a rcu_dereference() in sk_filter + * [CONNECTOR]: Don't touch queue dev after decrement of ref count. + * [IPV6]: IPV6_MULTICAST_IF setting is ignored on link-local connect() + * [ATM]: Check IP header validity in mpc_send_packet + * show_task: real_parent + * [SCSI] qla1280: fix 32 bit segment code + * [NIU]: Support for Marvell PHY + * [NEIGH]: Fix race between neigh_parms_release and neightbl_fill_parms + * [IPV4] ROUTE: fix rcu_dereference() uses in /proc/net/rt_cache + * [AX25]: Kill user triggable printks. + * [ARM] pxa: silence warnings from cpu_is_xxx() macros + * [POWERPC] efika: add phy-handle property for fec_mpc52xx + * [ARM] vfp: fix fuitod/fsitod instructions + * [CRYPTO] padlock: Fix alignment fault in aes_crypt_copy + * rt2x00: Allow rt61 to catch up after a missing tx report + * rt2x00: Corectly initialize rt2500usb MAC + * rt2x00: Put 802.11 data on 4 byte boundary + * NFSv4: Give the lock stateid its own sequence queue + * sata_qstor: use hardreset instead of softreset + * libata-sff: PCI IRQ handling fix + * pata_pdc202xx_old: Further fixups + * pata_ixp4xx_cf: fix compilation introduced by ata_port_desc() + conversion + * libata-pmp: 4726 hates SRST + * libata-pmp: propagate timeout to host link + * libata: don't normalize UNKNOWN to NONE after reset + * Update kernel parameter document for libata DMA mode setting knobs. + * sata_sil24: prevent hba lockup when pass-through ATA commands are used + * ide: workaround suspend bug for ACPI IDE + * ide: fix cable detection for SATA bridges + * trm290: do hook dma_host_{on,off} methods (take 2) + * libata and starting/stopping ATAPI floppy devices + * ACPI : Not register gsi for PCI IDE controller in legacy mode + * ACPICA: fix acpi_serialize hang regression + * sh: Force __access_ok() to obey address space limit. + * [AX25] af_ax25: Possible circular locking. + * ACPI: apply quirk_ich6_lpc_acpi to more ICH8 and ICH9 + * [POWERPC] Fix CPU hotplug when using the SLB shadow buffer + * [BLUETOOTH]: rfcomm tty BUG_ON() code fix + * [BLUETOOTH]: Always send explicit hci_ll wake-up acks. + * [DECNET] ROUTE: fix rcu_dereference() uses in /proc/net/decnet_cache + * [VLAN]: nested VLAN: fix lockdep's recursive locking warning + * [MACVLAN]: Prevent nesting macvlan devices + * [NETFILTER]: ip6t_eui64: Fixes calculation of Universal/Local bit + * [NETFILTER]: xt_helper: Do not bypass RCU + * [XFS] fix unaligned access in readdir + * Don't blatt first element of prv in sg_chain() + * loop: fix bad bio_alloc() nr_iovec request + * block: fix blktrace timestamps + * blktrace: kill the unneeded initcall + * V4L/DVB (6999): ivtv: stick to udelay=10 after all + * V4L/DVB (7001): av7110: fix section mismatch + * [MIPS] Wrong CONFIG option prevents setup of DMA zone. + * [MIPS] pnx8xxx: move to clocksource + * [MIPS] Malta: Fix software reset on big endian + * [MIPS] Lasat: Fix built in separate object directory. + * [MIPS] Replace 40c7869b693b18412491fdcff64682215b739f9e kludge + * Pull bugzilla-5637 into release branch + * Pull bugzilla-8171 into release branch + * Pull bugzilla-8973 into release branch + * PM: ACPI and APM must not be enabled at the same time + * Pull bugzilla-9194 into release branch + * Pull bugzilla-9494 into release branch + * Pull bugzilla-9535 into release branch + * Pull bugzilla-9627 into release branch + * Pull bugzilla-9683 into release branch + * IDE: terminate ACPI DMI list + * cache invalidation error for buffered write + * ps3fb: prevent use after free of fb_info + * ps3fb: fix deadlock on kexec() + * [NETFILTER]: bridge: fix double POST_ROUTING invocation + * xircom_cb endianness fixes + * de4x5 fixes + * endianness noise in tulip_core + * netxen: update MAINTAINERS + * netxen: update driver version + * netxen: stop second phy correctly + * netxen: optimize tx handling + * netxen: fix byte-swapping in tx and rx + * 3c509: PnP resource management fix + * Fixed a small typo in the loopback driver + * ip1000: menu location change + * r8169: fix missing loop variable increment + * [usb netdev] asix: fix regression + * fs_enet: check for phydev existence in the ethtool handlers + * Use access mode instead of open flags to determine needed permissions + * sky2: large memory workaround. + * sky2: remove check for PCI wakeup setting from BIOS + * spidernet MAINTAINERship update + * pnpacpi: print resource shortage message only once + * Pull bugzilla-9535 into release branch + * [SPARC]: Make gettimeofday() monotonic again. + * [SPARC64]: Fix build with SPARSEMEM_VMEMMAP disabled. + * remove task_ppid_nr_ns + * knfsd: Allow NFSv2/3 WRITE calls to succeed when krb5i etc is used. + * Input: improve Kconfig help entries for HP Jornada devices + * [TOKENRING]: rif_timer not initialized properly + * modules: de-mutex more symbol lookup paths in the module code + * w1: decrement slave counter only in ->release() callback + * Kick CPUS that might be sleeping in cpus_idle_wait + * TPM: fix suspend and resume failure + * MAINTAINERS: email update and add missing entry + * quicklists: Only consider memory that can be used with GFP_KERNEL + * macintosh: fix fabrication of caplock key events + * scsi/qla2xxx/qla_os.c section fix + * cciss: section mismatch + * advansys: fix section mismatch warning + * hugetlbfs: fix quota leak + * s3c2410fb: fix incorrect argument type in resume function + * CRIS: define __ARCH_WANT_SYS_RT_SIGSUSPEND in unistd.h for CRIS + * CRIS v10: correct do_signal to fix oops and clean up signal handling in + general + * CRIS v10: kernel/time.c needs to include linux/vmstat.h to compile + * uvesafb: fix section mismatch warnings + * CRIS v10: driver for ds1302 needs to include cris-specific i2c.h + * OSS msnd: fix array overflows + * i2c-omap: Fix NULL pointer dereferencing + * i2c: Spelling fixes + * i2c: Driver IDs are optional + * i2c-sibyte: Fix an error path + * fix the "remove task_ppid_nr_ns" commit + * [MIPS] Kconfig fixes for BCM47XX platform + * [MIPS] Cobalt: Fix ethernet interrupts for RaQ1 + * [MIPS] Cobalt: Qube1 has no serial port so don't use it + * [MIPS] Cacheops.h: Fix typo. + * ata_piix: ignore ATA_DMA_ERR on vmware ich4 + * sata_sil24: fix stupid typo + * sata_sil24: freeze on non-dev errors reported via CERR + * libata: relocate sdev->manage_start_stop configuration + * [POWERPC] Fix boot failure on POWER6 + * x86: fix boot crash on HIGHMEM4G && SPARSEMEM + * x86: asm-x86/msr.h: pull in linux/types.h + * x86: fix RTC_AIE with CONFIG_HPET_EMULATE_RTC + * Fix ARM profiling/instrumentation configuration + * Fix Blackfin HARDWARE_PM support + * libata fixes for sparse-found problems + * [libata] pata_bf54x: checkpatch fixes + * [libata] core checkpatch fix + * libata: correct handling of TSS DVD + * [IA64] Fix unaligned handler for floating point instructions with base + update + * Linux 2.6.24-rc8 + * lockdep: fix internal double unlock during self-test + * lockdep: fix workqueue creation API lockdep interaction + * lockdep: more hardirq annotations for notify_die() + * hostap: section mismatch warning + * wireless/libertas support for 88w8385 sdio older revision + * ipw2200: fix typo in kerneldoc + * b43: fix use-after-free rfkill bug + * rt2x00: Fix ieee80211 payload alignment + * sysfs: make sysfs_lookup() return ERR_PTR(-ENOENT) on failed lookup + * sysfs: fix bugs in sysfs_rename/move_dir() + * Use access mode instead of open flags to determine needed permissions + (CVE-2008-0001) + * IB/ipath: Fix receiving UD messages with immediate data + * [NET]: Fix TX timeout regression in Intel drivers. + * [NIU]: Fix 1G PHY link state handling. + * [SPARC64]: Fix hypervisor TLB operation error reporting. + * Input: mousedev - handle mice that use absolute coordinates + * Input: usbtouchscreen - fix buffer overflow, make more egalax work + * Input: psmouse - fix potential memory leak in psmouse_connect() + * Input: psmouse - fix input_dev leak in lifebook driver + * Input: ALPS - fix sync loss on Acer Aspire 5720ZG + * ipg: balance locking in irq handler + * ipg: plug Tx completion leak + * ipg: fix queue stop condition in the xmit handler + * ipg: fix Tx completion irq request + * cpufreq: Initialise default governor before use + * hfs: fix coverity-found null deref + * pnpacpi: print resource shortage message only once (more) + * CRIS v10: vmlinux.lds.S: ix kernel oops on boot and use common defines + * mm: fix section mismatch warning in page_alloc.c + * jbd: do not try lock_acquire after handle made invalid + * alpha: fix conversion from denormal float to double + * #ifdef very expensive debug check in page fault path + * Fix unbalanced helper_lock in kernel/kmod.c + * fix wrong sized spinlock flags argument + * bonding: fix locking in sysfs primary/active selection + * bonding: fix ASSERT_RTNL that produces spurious warnings + * bonding: fix locking during alb failover and slave removal + * bonding: release slaves when master removed via sysfs + * bonding: Fix up parameter parsing + * bonding: fix lock ordering for rtnl and bonding_rwsem + * bonding: Don't hold lock when calling rtnl_unlock + * Documentation: add a guideline for hard_start_xmit method + * atl1: fix frame length bug + * S2io: Fixed synchronization between scheduling of napi with card reset + and close + * dscc4 endian fixes + * wan/lmc bitfields fixes + * sbni endian fixes + * 3c574, 3c515 bitfields abuse + * dl2k: BMCR_t fixes + * dl2k: ANAR, ANLPAR fixes + * dl2k: BMSR fixes + * dl2k: MSCR, MSSR, ESR, PHY_SCR fixes + * dl2k: the rest + * Replace cpmac fix + * [WATCHDOG] Revert "Stop looking for device as soon as one is found" + * [WATCHDOG] clarify watchdog operation in documentation + * x86: add support for the latest Intel processors to Oprofile + * Selecting LGUEST should turn on Guest support, as in 2.6.23. + * ARM: OMAP1: Keymap fix for f-sample and p2-sample + * ARM: OMAP1: Fix compile for board-nokia770 + * pata_pdc202xx_old: Fix crashes with ATAPI + * arch: Ignore arch/i386 and arch/x86_64 + * Remove bogus duplicate CONFIG_LGUEST_GUEST entry. + * [ARM] pxa: don't rely on r2 being preserved over a function call + * [ARM] 4748/1: dca: source drivers/dca/Kconfig in arch/arm/Kconfig to + fix warning + * rfkill: call rfkill_led_trigger_unregister() on error + * [IPV6]: Mischecked tw match in __inet6_check_established. + * [IPV4] fib_hash: fix duplicated route issue + * [IPV4] fib_trie: fix duplicated route issue + * [NET]: Fix interrupt semaphore corruption in Intel drivers. + * [IPV4] FIB_HASH : Avoid unecessary loop in fn_hash_dump_zone() + * [IPV6] ROUTE: Make sending algorithm more friendly with RFC 4861. + * [NETFILTER]: bridge-netfilter: fix net_device refcnt leaks + * [NEIGH]: Revert 'Fix race between neigh_parms_release and + neightbl_fill_parms' + * [IrDA]: af_irda memory leak fixes + * [ATM] atm/idt77105.c: Fix section mismatch. + * [ATM] atm/suni.c: Fix section mismatch. + * [AF_KEY]: Fix skb leak on pfkey_send_migrate() error + * [NET]: rtnl_link: fix use-after-free + * [IPV6]: ICMP6_MIB_OUTMSGS increment duplicated + * [IPV6]: RFC 2011 compatibility broken + * [ICMP]: ICMP_MIB_OUTMSGS increment duplicated + * selinux: fix memory leak in netlabel code + * [MIPS] SMTC: Fix build error. + * [MIPS] Malta: Fix reading the PCI clock frequency on big-endian + * tc35815: Use irq number for tc35815-mac platform device id + * keyspan: fix oops + * hrtimer: fix section mismatch + * timer: fix section mismatch + * CRIS: add missed local_irq_restore call + * s3c2410_fb: fix line length calculation + * Fix filesystem capability support + * sched: group scheduler, set uid share fix + * hwmon: (it87) request only Environment Controller ports + * W1: w1_therm.c ds18b20 decode freezing temperatures correctly + * W1: w1_therm.c is flagging 0C etc as invalid + * rcu: fix section mismatch + * Fix file references in documentation and Kconfig + * x86: GEODE fix a race condition in the MFGPT timer tick + * virtnet: remove double ether_setup + * virtio:simplify-config-mechanism + * virtio: An entropy device, as suggested by hpa. + * virtio: Export vring functions for modules to use + * virtio: Put the virtio under the virtualization menu + * virtio:pci-device + * Fix vring_init/vring_size to take unsigned long + * virtio:vring-kick-when-empty + * virtio:explicit-callback-disable + * virtio:net-flush-queue-on-init + * virtio:net-fix-xmit-skb-free-real + * Parametrize the napi_weight for virtio receive queue. + * Handle module unload Add the device release function. + * Update all status fields on driver unload + * Make virtio modules GPL + * Make virtio_pci license be GPL2+ + * Use Qumranet donated PCI vendor/device IDs + * virtio:more-interrupt-suppression + * Reboot Implemented + * lguest:reboot-fix + * introduce vcpu struct + * adapt lguest launcher to per-cpuness + * initialize vcpu + * per-cpu run guest + * make write() operation smp aware + * make hypercalls use the vcpu struct + * per-vcpu lguest timers + * per-vcpu interrupt processing. + * map_switcher_in_guest() per-vcpu + * make emulate_insn receive a vcpu struct. + * make registers per-vcpu + * replace lguest_arch with lg_cpu_arch. + * per-vcpu lguest task management + * makes special fields be per-vcpu + * make pending notifications per-vcpu + * per-vcpu lguest pgdir management + + -- Tim Gardner Thu, 17 Jan 2008 14:45:01 -0700 + +linux (2.6.24-4.7) hardy; urgency=low + + [Amit Kucheria] + + * Poulsbo: Add SD8686 and 8688 WLAN drivers + * Poulsbo: Mass update of patches to be identical to those on moblin + * SAUCE: make fc transport removal of target configurable OriginalAuthor: + Michael Reed sgi.com> OriginalLocation: + http://thread.gmane.org/gmane.linux.scsi/25318 Bug: 163075 + + [Fabio M. Di Nitto] + + * Fix handling of gcc-4.1 for powerpc and ia64 + + [Tim Gardner] + + * Re-engineered architecture specific linux-headers compiler version + dependencies. + * Doh! Changed header-depends to header_depends. + + -- Tim Gardner Fri, 11 Jan 2008 07:10:46 -0700 + +linux (2.6.24-4.6) hardy; urgency=low + + [Alessio Igor Bogani] + + * Fix -rt build FTBS. + + [Amit Kucheria] + + * LPIACOMPAT: Update thermal patches to be inline with lpia flavour + * Poulsbo: Add USB Controller patch and corresponding config change + + [Fabio M. Di Nitto] + + * Enable aoe and nbd modules on hppa Ignore: yes + * Fix ia64 build by using gcc-4.1 + + [Tim Gardner] + + * Enable JFFS2 LZO compression. + - LP: #178343 + * Remove IS_G33 special handling. + - LP: #174367 + * Enabled CONFIG_SECURITY_CAPABILITIES and + CONFIG_SECURITY_FILE_CAPABILITIES + - LP: #95089 + * Enabled CONFIG_TASKSTATS and CONFIG_TASK_IO_ACCOUNTING + * Turned CONFIG_SECURITY_FILE_CAPABILITIES back off. + * Enabled CONFIG_B43LEGACY=m + * Enabled CONFIG_SCSI_QLOGIC_1280=m + * Enabled CONFIG_FUSION=y for virtual + * USB bluetooth device 0x0e5e:0x6622 floods errors to syslog + - LP: #152689 + * Removed lpia from d-i. + * Added ia64 modules. + * Added hppa32/64 modules. + + [Upstream Kernel Changes] + + * DMI autoload dcdbas on all Dell systems. + * sched: fix gcc warnings + * leds: Fix leds_list_lock locking issues + * leds: Fix locomo LED driver oops + * x86: fix asm-x86/byteorder.h for userspace export + * x86: fix asm-x86/msr.h for user-space export + * fix lguest rmmod "bad pgd" + * slub: provide /proc/slabinfo + * [POWERPC] Fix build failure on Cell when CONFIG_SPU_FS=y + * slub: register slabinfo to procfs + * [SCSI] scsi_sysfs: restore prep_fn when ULD is removed + * Unify /proc/slabinfo configuration + * scsi: revert "[SCSI] Get rid of scsi_cmnd->done" + * restrict reading from /proc//maps to those who share ->mm or can + ptrace pid + * Fix kernel/ptrace.c compile problem (missing "may_attach()") + * hwmon: (w83627ehf) Be more careful when changing VID input level + * NFS: Fix a possible Oops in fs/nfs/super.c + * NFSv4: Fix circular locking dependency in nfs4_kill_renewd + * NFS: add newline to kernel warning message in auth_gss code + * NFSv4: nfs4_open_confirm must not set the open_owner as confirmed on + error + * NFSv4: Fix open_to_lock_owner sequenceid allocation... + * IB/srp: Fix list corruption/oops on module reload + * Console is utf-8 by default + * [IA64] Update Altix BTE error return status patch + * [IA64] Update Altix nofault code + * [X25]: Add missing x25_neigh_put + * [XFRM]: Do not define km_migrate() if !CONFIG_XFRM_MIGRATE + * [CASSINI]: Fix endianness bug. + * [CASSINI]: Revert 'dont touch page_count'. + * [CASSINI]: Program parent Intel31154 bridge when necessary. + * [CASSINI]: Set skb->truesize properly on receive packets. + * [CASSINI]: Fix two obvious NAPI bugs. + * [CASSINI]: Bump driver version and release date. + * [INET]: Fix netdev renaming and inet address labels + * [CONNECTOR]: Return proper error code in cn_call_callback() + * [ISDN] i4l: 'NO CARRIER' message lost after ldisc flush + * [ISDN]: i4l: Fix DLE handling for i4l-audio + * fix: using joysticks in 32 bit applications on 64 bit systems + * hda_intel suspend latency: shorten codec read + * CPU hotplug: fix cpu_is_offline() on !CONFIG_HOTPLUG_CPU + * Linux 2.6.24-rc7 + * PIE executable randomization (upstream cherry pick by kees) + + -- Tim Gardner Fri, 04 Jan 2008 07:15:47 -0700 + +linux (2.6.24-3.5) hardy; urgency=low + + [Alessio Igor Bogani] + + * rt: Fix rt preempt patchset version + * Updated README file for binary custom flavours + * Fix -rt build FTBS. + * rt: Update configuration files + + [Tim Gardner] + + * SAUCE: Add extra headers to linux-libc-dev + + [Upstream Kernel Changes] + + * [WATCHDOG] at32ap700x_wdt: add support for boot status and add fix for + silicon errata + * [WATCHDOG] Stop looking for device as soon as one is found + * [WATCHDOG] bfin_wdt, remove SPIN_LOCK_UNLOCKED + * [WATCHDOG] Sbus: cpwatchdog, remove SPIN_LOCK_UNLOCKED + * [WATCHDOG] IT8212F watchdog driver + * ACPI: acpiphp: Remove dmesg spam on device remove + * [WATCHDOG] ipmi: add the standard watchdog timeout ioctls + * [WATCHDOG] add Nano 7240 driver + * ACPI: battery: fix ACPI battery technology reporting + * [ARM] 4667/1: CM-X270 fixes + * [ARM] 4690/1: PXA: fix CKEN corruption in PXA27x AC97 cold reset code + * [IPV6] XFRM: Fix auditing rt6i_flags; use RTF_xxx flags instead of + RTCF_xxx. + * [IPV4]: Swap the ifa allocation with the"ipv4_devconf_setall" call + * [IPv4] ESP: Discard dummy packets introduced in rfc4303 + * [IPv6] ESP: Discard dummy packets introduced in rfc4303 + * [UM]: Fix use of skb after netif_rx + * [XTENSA]: Fix use of skb after netif_rx + * [S390]: Fix use of skb after netif_rx + * [BNX2]: Add PHY_DIS_EARLY_DAC workaround. + * [BNX2]: Fix RX packet rot. + * [BNX2]: Update version to 1.6.9. + * [NET]: Fix wrong comments for unregister_net* + * [VLAN]: Fix potential race in vlan_cleanup_module vs + vlan_ioctl_handler. + * [IPSEC]: Fix potential dst leak in xfrm_lookup + * V4L/DVB (6485): ivtv: fix compile warning + * V4L/DVB (6540): em28xx: fix failing autodetection after the reboot + * V4L/DVB (6542): Fix S-video mode on tvp5150 + * V4L/DVB (6579): Fix bug #8824: Correct support for Diseqc on tda10086 + * V4L/DVB (6581): Fix: avoids negative vma usage count + * V4L/DVB (6601): V4L: videobuf-core locking fixes and comments + * V4L/DVB (6602): V4L: Convert videobuf drivers to videobuf_stop + * V4L/DVB (6615): V4L: Fix VIDIOCGMBUF locking in saa7146 + * V4L/DVB (6629): zl10353: fix default adc_clock and TRL nominal rate + calculation + * V4L/DVB (6666): saa7134-alsa: fix period handling + * V4L/DVB (6684): Complement va_start() with va_end() + style fixes + * V4L/DVB (6686): saa7134: fix composite over s-video input on the Tevion + MD 9717 + * V4L/DVB (6690): saa7134: fix ignored interrupts + * V4L/DVB (6751): V4L: Memory leak! Fix count in videobuf-vmalloc mmap + * V4L/DVB (6746): saa7134-dvb: fix tuning for WinTV HVR-1110 + * V4L/DVB (6750): Fix in-kernel compilation for cxusb + * V4L/DVB (6733): DVB: Compile 3000MC-specific DIB code only for + CONFIG_DVB_DIB3000MC + * V4L/DVB (6794): Fix compilation when dib3000mc is compiled as a module + * NFS: Fix NFS mountpoint crossing... + * V4L/DVB (6796): ivtv/ section fix + * V4L/DVB (6797): bt8xx/ section fixes + * NFSv2/v3: Fix a memory leak when using -onolock + * V4L/DVB (6609): Re-adds lock safe videobuf_read_start + * i2c: Delete an outdated piece of documentation + * i2c-gpio: Initialize adapter class + * i2c: Add missing spaces in split log messages + * i2c/isp1301_omap: Build fix + * [SERIAL] sparc: Infrastructure to fix section mismatch bugs. + * NFS: Fix an Oops in NFS unmount + * sdhci: describe quirks + * sdhci: don't warn about sdhci 2.0 controllers + * sdhci: use PIO when DMA can't satisfy the request + * sdhci: support JMicron JMB38x chips + * mmc: remove unused 'mode' from the mmc_host structure + * IB/ehca: Return correct number of SGEs for SRQ + * IB/ehca: Serialize HCA-related hCalls if necessary + * ide-scsi: add ide_scsi_hex_dump() helper + * ide: add missing checks for control register existence + * ide: deprecate CONFIG_BLK_DEV_OFFBOARD + * ide: fix ide_scan_pcibus() error message + * ide: coding style fixes for drivers/ide/setup-pci.c + * ide: add /sys/bus/ide/devices/*/{model,firmware,serial} sysfs entries + * ide: DMA reporting and validity checking fixes (take 3) + * ide-cd: remove dead post_transform_command() + * pdc202xx_new: fix Promise TX4 support + * hpt366: fix HPT37x PIO mode timings (take 2) + * ide: remove dead code from __ide_dma_test_irq() + * ide: remove stale changelog from ide-disk.c + * ide: remove stale changelog from ide-probe.c + * ide: fix ->io_32bit race in set_io_32bit() + * MAINTAINERS: update the NFS CLIENT entry + * V4L/DVB (6803): buf-core.c locking fixes + * [SPARC64]: Fix two kernel linear mapping setup bugs. + * IB/ehca: Fix lock flag variable location, bump version number + * kbuild: re-enable Makefile generation in a new O=... directory + * V4L/DVB (6798): saa7134: enable LNA in analog mode for Hauppauge WinTV + HVR-1110 + * V4L/DVB (6814): Makefile: always enter video/ + * V4L/DVB (6819): i2c: fix drivers/media/video/bt866.c + * V4L/DVB (6820): s5h1409: QAM SNR related fixes + * ACPI: video_device_list corruption + * ACPI: fix modpost warnings + * ACPI: thinkpad-acpi: fix lenovo keymap for brightness + * Pull thinkpad-2.6.24 into release branch + * Pull battery-2.6.24 into release branch + * [POWERPC] Fix typo #ifdef -> #ifndef + * [POWERPC] Kill non-existent symbols from ksyms and commproc.h + * [POWRPC] CPM2: Eliminate section mismatch warning in cpm2_reset(). + * [POWERPC] 82xx: mpc8272ads, pq2fads: Update defconfig with + CONFIG_FS_ENET_MDIO_FCC + * [POWERPC] iSeries: don't printk with HV spinlock held + * [POWERPC] Fix rounding bug in emulation for double float operating + * [POWERPC] Make PS3_SYS_MANAGER default y, not m + * [MIPS] time: Set up Cobalt's mips_hpt_frequency + * [MIPS] Alchemy: fix PCI resource conflict + * [MIPS] Alchemy: fix off by two error in __fixup_bigphys_addr() + * [MIPS] Atlas, Malta: Don't free firmware memory on free_initmem. + * [MIPS] PCI: Make pcibios_fixup_device_resources ignore legacy + resources. + * [MIPS] time: Delete weak definition of plat_time_init() due to gcc bug. + * [MIPS] Ensure that ST0_FR is never set on a 32 bit kernel + * [SPARC32]: Silence sparc32 warnings on missing syscalls. + * Pull hotplug into release branch + * ACPI: SBS: Reset alarm bit + * ACPI: SBS: Ignore alarms coming from unknown devices + * ACPI: SBS: Return rate in mW if capacity in mWh + * Pull bugzilla-9362 into release branch + * sky2: RX lockup fix + * sundance fixes + * starfire VLAN fix + * e100: free IRQ to remove warningwhenrebooting + * hamachi endianness fixes + * drivers/net/sis190.c section fix + * drivers/net/s2io.c section fixes + * ucc_geth: minor whitespace fix + * net: smc911x: shut up compiler warnings + * Net: ibm_newemac, remove SPIN_LOCK_UNLOCKED + * ixgb: make sure jumbos stay enabled after reset + * [NETFILTER]: ctnetlink: set expected bit for related conntracks + * [NETFILTER]: ip_tables: fix compat copy race + * [XFRM]: Display the audited SPI value in host byte order. + * [NETFILTER]: xt_hashlimit should use time_after_eq() + * [TIPC]: Fix semaphore handling. + * [SYNCPPP]: Endianness and 64bit fixes. + * [NETFILTER]: bridge: fix missing link layer headers on outgoing routed + packets + * [ATM]: Fix compiler warning noise with FORE200E driver + * [IPV4]: Updates to nfsroot documentation + * [BRIDGE]: Assign random address. + * [IPV6]: Fix the return value of ipv6_getsockopt + * [IPV4]: Make tcp_input_metrics() get minimum RTO via tcp_rto_min() + * [AX25]: Locking dependencies fix in ax25_disconnect(). + * [SCTP]: Flush fragment queue when exiting partial delivery. + * [IRDA]: Race between open and disconnect in irda-usb. + * [IRDA]: mcs7780 needs to free allocated rx buffer. + * [IRDA]: irlmp_unregister_link() needs to free lsaps. + * [IRDA]: stir4200 fixes. + * [IRDA]: irda parameters warning fixes. + * [S390] pud_present/pmd_present bug. + * [ARM] 4710/1: Fix coprocessor 14 usage for debug messages via ICEDCC + * [ARM] 4694/1: IXP4xx: Update clockevent support for shutdown and resume + * kobject: fix the documentation of how kobject_set_name works + * tipar: remove obsolete module + * HOWTO: Change man-page maintainer address for Japanese HOWTO + * Add Documentation for FAIR_USER_SCHED sysfs files + * HOWTO: change addresses of maintainer and lxr url for Korean HOWTO + * add stable_api_nonsense.txt in korean + * HOWTO: update misspelling and word incorrected + * PCI: Restore PCI expansion ROM P2P prefetch window creation + * USB: sierra: fix product id + * usb-storage: Fix devices that cannot handle 32k transfers + * USB: cp2101: new device id + * USB: option: Bind to the correct interface of the Huawei E220 + * usb.h: fix kernel-doc warning + * USB: fix locking loop by avoiding flush_scheduled_work + * USB: use IRQF_DISABLED for HCD interrupt handlers + * USB: at91_udc: correct hanging while disconnecting usb cable + * usb: Remove broken optimisation in OHCI IRQ handler + * USB: revert portions of "UNUSUAL_DEV: Sync up some reported devices + from Ubuntu" + * ocfs2: fix exit-while-locked bug in ocfs2_queue_orphans() + * ocfs2: Don't panic when truncating an empty extent + * ocfs2: Allow for debugging of transaction extends + * ocfs2: Re-journal buffers after transaction extend + * pcnet_cs: add new id + * ucc_geth: really fix section mismatch + * sis190 endianness + * libertas: add Dan Williams as maintainer + * zd1211rw: Fix alignment problems + * wireless/ipw2200.c: add __dev{init,exit} annotations + * ieee80211_rate: missed unlock + * iwlwifi3945/4965: fix rate control algo reference leak + * libertas: select WIRELESS_EXT + * bcm43xx_debugfs sscanf fix + * b43: Fix rfkill radio LED + * iwlwifi: fix rf_kill state inconsistent during suspend and resume + * sata_sil: fix spurious IRQ handling + * libata: clear link->eh_info.serror from ata_std_postreset() + * libata: add ST3160023AS / 3.42 to NCQ blacklist + * sata_mv: improve warnings about Highpoint RocketRAID 23xx cards + * libata-acpi: adjust constness in ata_acpi_gtm/stm() parameters + * libata: update ata_*_printk() macros such that level can be a variable + * libata: add more opcodes to ata.h + * libata: ata_dev_disable() should be called from EH context + * libata-acpi: add new hooks ata_acpi_dissociate() and + ata_acpi_on_disable() + * libata-acpi: implement and use ata_acpi_init_gtm() + * libata-acpi: implement dev->gtf_cache and evaluate _GTF right after + _STM during resume + * libata-acpi: improve ACPI disabling + * libata-acpi: improve _GTF execution error handling and reporting + * libata-acpi: implement _GTF command filtering + * libata: update atapi_eh_request_sense() such that lbam/lbah contains + buffer size + * libata: fix ATAPI draining + * fix headers_install + * revert "Hibernation: Use temporary page tables for kernel text mapping + on x86_64" + * uml: stop gdb from deleting breakpoints when running UML + * alpha: strncpy/strncat fixes + * rtc-at32ap700x: fix irq init oops + * parport: "dev->timeslice" is an unsigned long, not an int + * ecryptfs: initialize new auth_tokens before teardown + * Fix lguest documentation + * sparsemem: make SPARSEMEM_VMEMMAP selectable + * fs/Kconfig: grammar fix + * ext3, ext4: avoid divide by zero + * alpha: build fixes + * cpufreq: fix missing unlocks in cpufreq_add_dev error paths. + * mm/sparse.c: check the return value of sparse_index_alloc() + * mm/sparse.c: improve the error handling for sparse_add_one_section() + * pktcdvd: add kobject_put when kobject register fails + * drivers/macintosh/via-pmu.c: Added a missing iounmap + * drivers/cpufreq/cpufreq_stats.c section fix + * apm_event{,info}_t are userspace types + * mm: fix page allocation for larger I/O segments + * ecryptfs: set s_blocksize from lower fs in sb + * I/OAT: fixups from code comments + * I/OAT: fix null device in call to dev_err() + * fix bloat-o-meter for ppc64 + * ecryptfs: fix fsx data corruption problems + * Documentation: update hugetlb information + * Fix compilation warning in dquot.c + * SLUB: remove useless masking of GFP_ZERO + * quicklist: Set tlb->need_flush if pages are remaining in quicklist 0 + * sysctl: fix ax25 checks + * [XFS] Don't wait for pending I/Os when purging blocks beyond eof. + * [XFS] Put the correct offset in dirent d_off + * block: use jiffies conversion functions in scsi_ioctl.c + * as-iosched: fix incorrect comments + * as-iosched: fix write batch start point + * block: let elv_register() return void + * Cleanup umem driver: fix most checkpatch warnings, conform to kernel + * sched: fix crash on ia64, introduce task_current() + * sched: mark rwsem functions as __sched for wchan/profiling + * sched: sysctl, proc_dointvec_minmax() expects int values for + * sched: touch softlockup watchdog after idling + * sched: do not hurt SCHED_BATCH on wakeup + * oprofile: op_model_athlon.c support for AMD family 10h barcelona + performance counters + * clockevents: fix reprogramming decision in oneshot broadcast + * genirq: add unlocked version of set_irq_handler() + * timer: kernel/timer.c section fixes + * x86: jprobe bugfix + * x86: kprobes bugfix + * x86: also define AT_VECTOR_SIZE_ARCH + * genirq: revert lazy irq disable for simple irqs + * x86: fix "Kernel panic - not syncing: IO-APIC + timer doesn't work!" + * [SCSI] sym53c8xx: fix free_irq() regression + * [SCSI] dpt_i2o: driver is only 32 bit so don't set 64 bit DMA mask + * [SCSI] sym53c8xx: fix "irq X: nobody cared" regression + * [SCSI] initio: fix conflict when loading driver + * [SCSI] st: fix kernel BUG at include/linux/scatterlist.h:59! + * [SCSI] initio: bugfix for accessors patch + * IA64: Slim down __clear_bit_unlock + * [IA64] signal: remove redundant code in setup_sigcontext() + * [IA64] ia32 nopage + * [IA64] Avoid unnecessary TLB flushes when allocating memory + * [IA64] Two trivial spelling fixes + * [IA64] print kernel release in OOPS to make kerneloops.org happy + * [IA64] set_thread_area fails in IA32 chroot + * [IA64] Remove compiler warinings about uninitialized variable in + irq_ia64.c + * [IA64] Remove assembler warnings on head.S + * [IA64] Fix Altix BTE error return status + * [IA64] Guard elfcorehdr_addr with #if CONFIG_PROC_FS + * [IA64] make flush_tlb_kernel_range() an inline function + * [IA64] Adjust CMCI mask on CPU hotplug + * Do dirty page accounting when removing a page from the page cache + * x86 apic_32.c section fix + * x86 smpboot_32.c section fixes + * x86_32: select_idle_routine() must be __cpuinit + * x86_32: disable_pse must be __cpuinitdata + * x86: fix show cpuinfo cpu number always zero + * ps3fb: Update for firmware 2.10 + * ps3fb: Fix ps3fb free_irq() dev_id + * pata_hpt37x: Fix HPT374 detection + * mac80211: Drop out of associated state if link is lost + * mac80211: fix header ops + * NET: mac80211: fix inappropriate memory freeing + * [TG3]: Endianness annotations. + * [TG3]: Endianness bugfix. + * rtl8187: Add USB ID for Sitecom WL-168 v1 001 + * p54: add Kconfig description + * iwlwifi: fix possible priv->mutex deadlock during suspend + * ipw2200: prevent alloc of unspecified size on stack + * [IPV4] ARP: Remove not used code + * [IPSEC]: Avoid undefined shift operation when testing algorithm ID + * [XFRM]: Audit function arguments misordered + * [IPV4] ip_gre: set mac_header correctly in receive path + * [NET]: Correct two mistaken skb_reset_mac_header() conversions. + * [SPARC64]: Fix OOPS in dma_sync_*_for_device() + * sched: rt: account the cpu time during the tick + * debug: add end-of-oops marker + * mm: fix exit_mmap BUG() on a.out binary exit + * dm: table detect io beyond device + * dm mpath: hp requires scsi + * dm crypt: fix write endio + * dm: trigger change uevent on rename + * dm: merge max_hw_sector + * dm crypt: use bio_add_page + * [SPARC64]: Spelling fixes + * [SPARC32]: Spelling fixes + * [NET] include/net/: Spelling fixes + * [DCCP]: Spelling fixes + * [IRDA]: Spelling fixes + * [IPV6]: Spelling fixes + * [NET] net/core/: Spelling fixes + * [PKT_SCHED]: Spelling fixes + * [NETLABEL]: Spelling fixes + * [SCTP]: Spelling fixes + * [NETFILTER]: Spelling fixes + * [NETFILTER] ipv4: Spelling fixes + * [ATM]: Spelling fixes + * [NET]: Fix function put_cmsg() which may cause usr application memory + overflow + * x86: fix die() to not be preemptible + * x86: intel_cacheinfo.c: cpu cache info entry for Intel Tolapai + * [XFS] Fix mknod regression + * [XFS] Initialise current offset in xfs_file_readdir correctly + * Linux 2.6.24-rc6 + * [IPV4]: OOPS with NETLINK_FIB_LOOKUP netlink socket + * SLUB: Improve hackbench speed + * typhoon: endianness bug in tx/rx byte counters + * typhoon: missing le32_to_cpu() in get_drvinfo + * typhoon: set_settings broken on big-endian + * typhoon: missed rx overruns on big-endian + * typhoon: memory corruptor on big-endian if TSO is enabled + * typhoon: trivial endianness annotations + * cycx: annotations and fixes (.24 fodder?) + * asix fixes + * yellowfin: annotations and fixes (.24 fodder?) + * dl2k endianness fixes (.24 fodder?) + * r8169 endianness + * rrunner: use offsetof() instead of homegrown insanity + * 3c574 and 3c589 endianness fixes (.24?) + * fec_mpc52xx: write in C... + * 3c359 endianness annotations and fixes + * MACB: clear transmit buffers properly on transmit underrun + * UIO: Add a MAINTAINERS entry for Userspace I/O + * Modules: fix memory leak of module names + * USB: Unbreak fsl_usb2_udc + * USB: VID/PID update for sierra + * USB: New device ID for the CP2101 driver + * quicklists: do not release off node pages early + * ecryptfs: fix string overflow on long cipher names + * Fix computation of SKB size for quota messages + * Don't send quota messages repeatedly when hardlimit reached + * ecryptfs: fix unlocking in error paths + * ecryptfs: redo dget,mntget on dentry_open failure + * MAINTAINERS: mailing list archives are web links + * ps3: vuart: fix error path locking + * lib: proportion: fix underflow in prop_norm_percpu() + * pcmcia: remove pxa2xx_lubbock build warning + * kconfig: obey KCONFIG_ALLCONFIG choices with randconfig. + * tty: fix logic change introduced by wait_event_interruptible_timeout() + * uml: user of helper_wait() got missed when it got extra arguments + * V4L/DVB (6871): Kconfig: VIDEO_CX23885 must select DVB_LGDT330X + * V4L/DVB (6876): ivtv: mspx4xx needs a longer i2c udelay + * drivers/ide/: Spelling fixes + * ide-cd: fix SAMSUNG CD-ROM SCR-3231 quirk + * ide-cd: fix ACER/AOpen 24X CDROM speed reporting on big-endian machines + * ide-cd: use ide_cd_release() in ide_cd_probe() + * ide-cd: fix error messages in cdrom_{read,write}_check_ireason() + * ide-cd: add missing 'ireason' masking to cdrom_write_intr() + * ide-cd: fix error messages in cdrom_write_intr() + * ide-cd: add error message for DMA error to cdrom_read_intr() + * ide-cd: fix error message in cdrom_pc_intr() + * ide-cd: fix 'ireason' reporting in cdrom_pc_intr() + * MAINTAINERS: update ide-cd entry + * [SPARC64]: Implement pci_resource_to_user() + * mac80211: round station cleanup timer + * mac80211: warn when receiving frames with unaligned data + * [NETFILTER]: nf_conntrack_ipv4: fix module parameter compatibility + * [TUNTAP]: Fix wrong debug message. + * [NET] tc_nat: header install + * [VETH]: move veth.h to include/linux + * [IPV4]: Fix ip command line processing. + * Revert quicklist need->flush fix + * [CRYPTO] padlock: Fix spurious ECB page fault + * [POWERPC] Oprofile: Remove dependency on spufs module + * [POWERPC] PS3: Fix printing of os-area magic numbers + * [PCI] Do not enable CRS Software Visibility by default + * [IPV4] Fix ip=dhcp regression + * [SERIAL]: Fix section mismatches in Sun serial console drivers. + * [TCP]: use non-delayed ACK for congestion control RTT + * [BLUETOOTH]: put_device before device_del fix + + -- Tim Gardner Sat, 22 Dec 2007 15:16:11 -0700 + +linux (2.6.24-2.4) hardy; urgency=low + + [Alessio Igor Bogani] + + * rt: First import for Hardy + + [Amit Kucheria] + + * LPIA: Fix FTBFS for hda + * LPIA: Trim configs including disabling stock DRM + + [Tim Gardner] + + * SAUCE: Increase CONFIG_IDE_MAX_HWIFS to 8 (from 4) + - LP: #157909 + Then reverted since it causes an ABI bump. Will pick it up + again when next the ABI changes. + * Expose apm for applications. + + -- Tim Gardner Wed, 19 Dec 2007 13:17:31 -0700 + +linux (2.6.24-2.3) hardy; urgency=low + + [Amit Kucheria] + + * LPIA: Add thermal framework from Intel + * LPIA: Poulsbo-specific patches + * LPIA: Add thermal framework from Intel + + [Tim Gardner] + + * SAUCE: hdaps module does not load on Thinkpad T61P + - LP: #133636 + + [Upstream Kernel Changes] + + * Rebased against 2.6.24-rc5 + + -- Tim Gardner Wed, 12 Dec 2007 13:58:52 -0700 + +linux (2.6.24-1.2) hardy; urgency=low + + [Ben Collins] + + * cell: Remove cell custom flavour, merged upstream + * apparmor: Added module from SVN repo + * ubuntu: Update configs to enable apparmor + * ubuntu/configs: Disable vga type framebuffers on hppa32. Fixes FTBFS + + [Tim Gardner] + + * Add support for PPA builds. + + [Upstream Kernel Changes] + + * [SPARC64] Export symbols for sunvnet and sunvdc to be built modular + + -- Ben Collins Fri, 07 Dec 2007 15:18:32 -0500 + +linux (2.6.24-1.1) hardy; urgency=low + + [Ben Collins] + + * ubuntu: Disable custom binary flavours for now + * ubuntu: Remove cruft in headers-postinst + * ubuntu: Set skipabi/skipmodule to true if prev_revions == 0.0 + * ubuntu: Do not fail on missing module lists when skipmodule is set + * ubuntu: capability.ko is built-in now, no need to place in initrd. + * ubuntu: Change to "linux" instead of "linux-source-2.6.x" + * d-i: cdrom-modules disappeared, and sha256/aes modules renamed. + * ubuntu-build: Add asm_link= to arch rules, and use them + * config: Re-enable snd-hda-intel + + -- Ben Collins Wed, 28 Nov 2007 12:58:37 -0500 + +linux-source-2.6.22 (2.6.22-14.46) gutsy; urgency=low + + [Upstream Kernel Changes] + + * [SPARC64]: Fix bugs in SYSV IPC handling in 64-bit processes. + + -- Kyle McMartin Sun, 14 Oct 2007 20:30:09 +0000 + +linux-source-2.6.22 (2.6.22-14.45) gutsy; urgency=low + + [Upstream Kernel Changes] + + * [SPARC64]: Fix register usage in xor_raid_4(). + + -- Kyle McMartin Sun, 14 Oct 2007 12:34:44 -0400 + +linux-source-2.6.22 (2.6.22-14.44) gutsy; urgency=low + + [Kyle McMartin] + + * Revert "sparc wants ehci built in" + + [Upstream Kernel Changes] + + * Revert "[PATCH]: Gutsy OHCI hang workaround for Huron" + * [USB]: Serialize EHCI CF initialization. + + -- Kyle McMartin Sun, 14 Oct 2007 16:25:51 +0000 + +linux-source-2.6.22 (2.6.22-14.43) gutsy; urgency=low + + [Kyle McMartin] + + * sparc wants ehci built in + + -- Kyle McMartin Tue, 09 Oct 2007 20:07:58 +0000 + +linux-source-2.6.22 (2.6.22-14.42) gutsy; urgency=low + + [Kyle McMartin] + + * fix up module-check to bail early if asked to ignore modules + * disable kernel DRM on lpia (we provide one in lum) + - LP: #145168 + * add ignore for ia64 abi too + + [Upstream Kernel Changes] + + * [NIU]: Use netif_msg_*(). + * [NIU]: Use pr_info(). + * [NIU]: Remove redundant BUILD_BUG_ON() in __niu_wait_bits_clear(). + * [NIU]: Remove BUG_ON() NULL pointer checks. + * [NIU]: Use dev_err(). + * [NIU]: Fix x86_64 build failure. + * [NIU]: Use linux/io.h instead of asm/io.h + * [NIU]: Fix some checkpatch caught coding style issues. + * [NIU]: Fix shadowed local variables. + * [NIU]: Fix locking errors in link_status_10g(). + * [NIU]: Document a few magic constants using comments. + * [NIU]: MII phy handling fixes. + * [NIU]: Make sure link_up status is set to something in + link_status_{1,10}g(). + * [PATCH]: Gutsy OHCI hang workaround for Huron + + -- Kyle McMartin Tue, 09 Oct 2007 17:25:06 +0000 + +linux-source-2.6.22 (2.6.22-14.41) gutsy; urgency=low + + [Ben Collins] + + * ubuntu/d-i: Add niu to nic-modules + + [Kyle McMartin] + + * vesafb is not for ia64 + * remove CONFIG_NIU from places it shouldn't be + * fix orinoco_cs oops + - LP: #149997 + + [Upstream Kernel Changes] + + * [SPARC64]: Allow userspace to get at the machine description. + * [SPARC64]: Niagara-2 optimized copies. + * [SPARC64]: Do not touch %tick_cmpr on sun4v cpus. + * [SPARC64]: SMP trampoline needs to avoid %tick_cmpr on sun4v too. + * [SPARC64]: Create a HWCAP_SPARC_N2 and report it to userspace on + Niagara-2. + * [MATH-EMU]: Fix underflow exception reporting. + * [SPARC64]: Need to clobber global reg vars in switch_to(). + * [MATH]: Fix typo in FP_TRAPPING_EXCEPTIONS default setting. + * [SUNVDC]: Use slice 0xff on VD_DISK_TYPE_DISK. + * [SPARC64]: Fix type and constant sizes wrt. sun4u IMAP/ICLR handling. + * [SPARC64]: Enable MSI on sun4u Fire PCI-E controllers. + * [SPARC64]: Fix several bugs in MSI handling. + * [SPARC64]: Fix booting on V100 systems. + * [SPARC64]: Fix lockdep, particularly on SMP. + * [SPARC64]: Warn user if cpu is ignored. + * [SUNSAB]: Fix several bugs. + * [SUNSAB]: Fix broken SYSRQ. + * [SPARC64]: Fix missing load-twin usage in Niagara-1 memcpy. + * [SPARC64]: Don't use in/local regs for ldx/stx data in N1 memcpy. + * [SPARC64]: Fix domain-services port probing. + * [SPARC64]: VIO device addition log message level is too high. + * [SPARC64]: check fork_idle() error + * [SPARC64]: Fix 'niu' complex IRQ probing. + * [NIU]: Add Sun Neptune ethernet driver. + + -- Kyle McMartin Tue, 09 Oct 2007 00:38:16 +0000 + +linux-source-2.6.22 (2.6.22-13.40) gutsy; urgency=low + + [Amit Kucheria] + + * Enable CONFIG_VM86 for LPIA + - LP: #146311 + * Update configuration files + * Disable MSI by default + * Add mmconf documentation + * Update configuration files + + [Bartlomiej Zolnierkiewicz] + + * ide-disk: workaround for buggy HPA support on ST340823A (take 3) + - LP: #26119 + + [Ben Collins] + + * ubuntu/cell: Fixup ps3 related modules for d-i, enable RTAS console + * ubuntu/cell: Enable CELLEB and related modules (pata_scc) + * ubuntu/cell: Move ps3rom to storage-core. Also use spidernet, not + spider_net. + * ubuntu/cell: Set PS3_MANAGER=y + * ubuntu: Set NR_CPUS=256 for sparc64-smp + + [Chuck Short] + + * [USB] USB] Support for MediaTek MT6227 in cdc-acm. + - LP: #134123 + * [XEN] Fix xen vif create with more than 14 guests. + - LP: #14486 + + [Jorge Juan Chico] + + * ide: ST320413A has the same problem as ST340823A + - LP: #26119 + + [Kyle McMartin] + + * fix -rt build + * fix ia32entry-xen.S for CVE-2007-4573 + * fix build when CONFIG_PCI_MSI is not set + + [Matthew Garrett] + + * hostap: send events on data interface as well as master interface + - LP: #57146 + * A malformed _GTF object should not prevent ATA device recovery + - LP: #139079 + * hostap: send events on data interface as well as master interface + - LP: #57146 + * A malformed _GTF object should not prevent ATA device recovery + - LP: #139079 + * Don't lose appletouch button release events + * Fix build with appletouch change + * Disable Thinkpad backlight support on machines with ACPI video + - LP: #148055 + * Don't attempt to register a callback if there is no CMOS object + - LP: #145857 + * Update ACPI bay hotswap code to support locking + - LP: #148219 + * Update ACPI bay hotswap code to support locking + - LP: #148219 + * Don't attempt to register a callback if there is no CMOS object + - LP: #145857 + * Disable Thinkpad backlight support on machines with ACPI video + - LP: #148055 + + [Steffen Klassert] + + * 3c59x: fix duplex configuration + - LP: #94186 + + [Thomas Gleixner] + + * clockevents: remove the suspend/resume workaround^Wthinko + + [Tim Gardner] + + * orinoco_cs.ko missing + - LP: #125832 + * Marvell Technology ethernet card not recognized and not operational + - LP: #135316 + * Marvell Technology ethernet card not recognized and not operational + - LP: #135316 + * acpi_scan_rsdp() breaks some PCs by not honouring ACPI specification + - LP: #144336 + * VIA southbridge Intel id missing + - LP: #128289 + * Add T-Sinus 111card to hostap_cs driver to be able to upload firmware + - LP: #132466 + * RTL8111 PCI Express Gigabit driver r8169 big files produce slow file + transfer + - LP: #114171 + * Guest OS does not recognize a lun with non zero target id on Vmware ESX + Server + - LP: #140761 + * Modualrize vesafb + - LP: #139505 + * Nikon cameras need support in unusual_devs.h + - LP: #134477 + * agp for i830m broken in gutsy + - LP: #139767 + * hdaps: Added support for Thinkpad T61 + - LP: #147383 + * xen: Update config for i386 + - LP: #139047 + * xen: resync for amd64 + - LP: #139047 + * ide-disk: workaround for buggy HPA support on ST340823A (take 4) + - LP: #26119 + + [Upstream Kernel Changes] + + * Convert snd-page-alloc proc file to use seq_file (CVE-2007-4571) + * Linux 2.6.22.8 + * ACPI: disable lower idle C-states across suspend/resume + * V4L: ivtv: fix VIDIOC_S_FBUF: new OSD values were never set + * DVB: get_dvb_firmware: update script for new location of sp8870 + firmware + * DVB: get_dvb_firmware: update script for new location of tda10046 + firmware + * DVB: b2c2-flexcop: fix Airstar HD5000 tuning regression + * setpgid(child) fails if the child was forked by sub-thread + * sigqueue_free: fix the race with collect_signal() + * kconfig: oldconfig shall not set symbols if it does not need to + * MTD: Makefile fix for mtdsuper + * USB: fix linked list insertion bugfix for usb core + * ACPI: Validate XSDT, use RSDT if XSDT fails + * POWERPC: Flush registers to proper task context + * 3w-9xxx: Fix dma mask setting + * MTD: Initialise s_flags in get_sb_mtd_aux() + * JFFS2: fix write deadlock regression + * V4L: cx88: Avoid a NULL pointer dereference during mpeg_open() + * hwmon: End of I/O region off-by-one + * Fix debug regression in video/pwc + * splice: fix direct splice error handling + * rpc: fix garbage in printk in svc_tcp_accept() + * disable sys_timerfd() + * afs: mntput called before dput + * Fix DAC960 driver on machines which don't support 64-bit DMA + * Fix "Fix DAC960 driver on machines which don't support 64-bit DMA" + * firewire: fw-ohci: ignore failure of pci_set_power_state (fix suspend + regression) + * futex_compat: fix list traversal bugs + * Leases can be hidden by flocks + * ext34: ensure do_split leaves enough free space in both blocks + * nfs: fix oops re sysctls and V4 support + * dir_index: error out instead of BUG on corrupt dx dirs + * ieee1394: ohci1394: fix initialization if built non-modular + * Correctly close old nfsd/lockd sockets. + * Fix race with shared tag queue maps + * crypto: blkcipher_get_spot() handling of buffer at end of page + * fix realtek phy id in forcedeth + * Fix decnet device address listing. + * Fix device address listing for ipv4. + * Fix inet_diag OOPS. + * Fix IPV6 append OOPS. + * Fix IPSEC AH4 options handling + * Fix ipv6 double-sock-release with MSG_CONFIRM + * Fix IPV6 DAD handling + * Fix ipv6 source address handling. + * Fix oops in vlan and bridging code + * Fix tc_ematch kbuild + * Handle snd_una in tcp_cwnd_down() + * Fix TCP DSACK cwnd handling + * Fix datagram recvmsg NULL iov handling regression. + * Fix pktgen src_mac handling. + * Fix sparc64 v100 platform booting. + * bcm43xx: Fix cancellation of work queue crashes + * Linux 2.6.22.9 + * usb: serial/pl2303: support for BenQ Siemens Mobile Phone EF81 + * pata_it821x: fix lost interrupt with atapi devices + * i915: make vbl interrupts work properly on i965g/gm hw. + + -- Kyle McMartin Thu, 04 Oct 2007 13:57:53 +0000 + +linux-source-2.6.22 (2.6.22-12.39) gutsy; urgency=low + + [Ben Collins] + + * ubuntu: Re-order deps so that binary-custom is done before + binary-udebs. Fixes ppc build + + [Upstream Kernel Changes] + + * x86_64: Zero extend all registers after ptrace in 32bit entry path. + * Linux 2.6.22.7 + + -- Ben Collins Sun, 23 Sep 2007 11:05:32 -0400 + +linux-source-2.6.22 (2.6.22-12.38) gutsy; urgency=low + + [Kyle McMartin] + + * add -12 abi files + * update getabis for new flavours + + -- Kyle McMartin Fri, 21 Sep 2007 13:35:49 -0400 + +linux-source-2.6.22 (2.6.22-12.37) gutsy; urgency=low + + [Kyle McMartin] + + * enable d-i for cell flavour + * ignore ABI check on all hppa flavours + + -- Kyle McMartin Fri, 21 Sep 2007 11:28:34 -0400 + +linux-source-2.6.22 (2.6.22-12.36) gutsy; urgency=low + + [Ben Collins] + + * ABI bump due to LED support being enabled. + + [Kyle McMartin] + + * fix memory leak in psparse.c + - Bug introduced in previous commit to acpi + + [Upstream Kernel Changes] + + * Ubuntu: Allocate acpi_devices structure rather than leaving it on the + stack. + * ipw2100: Fix `iwpriv set_power` error + * Fix ipw2200 set wrong power parameter causing firmware error + * [SCSI] Fix async scanning double-add problems + - LP: #110997 + + -- Ben Collins Thu, 20 Sep 2007 11:34:52 -0400 + +linux-source-2.6.22 (2.6.22-11.34) gutsy; urgency=low + + [Alan Stern] + + * USB: disable autosuspend by default for non-hubs + - LP: #85488 + + [Ben Collins] + + * ubuntu: Enable LEDS_TRIGGERS and related options + - Needed for iwlwifi + * ubuntu: Add real ABI files for virtual flavour + * ubuntu: Re-enable missing CONFIG_SERPENT for hppa64 + - Noticed by Lamont + * ubuntu: Add linux-headers postinst to handle hooks + - LP: #125816 + * ubuntu: Add support for /etc/kernel/headers_postinst.d/ to + headers-postinst + - LP: #120049 + * cell: Add binary-custom flavour "cell" to support ps3 + + [Mattia Dongili] + + * sony-laptop: restore the last user requested brightness level on + resume. + - LP: #117331 + + [Tejun Heo] + + * ata_piix: fix suspend/resume for some TOSHIBA laptops + - LP: #139045 + * PCI: export __pci_reenable_device() + - needed for ata_piix change + + [Tim Gardner] + + * Enable Sierra Wireless MC8775 0x6813 + - LP: #131167 + + [Zhang Rui] + + * ACPI: work around duplicate name "VID" problem on T61 + - Noted by mjg59 + + -- Ben Collins Sun, 16 Sep 2007 22:31:47 -0400 + +linux-source-2.6.22 (2.6.22-11.33) gutsy; urgency=low + + [Alessio Igor Bogani] + + * rt: Update to rt9 + * rt: Update configuration files + + [Ben Collins] + + * ubuntu: Enable A100 driver + - LP: #138632 + * libata: Default to hpa being overridden + + [Chuck Short] + + * [HDAPS] Add support for Thinkpad R61. + * [LIBATA] Add more hard drives to blacklist. + * [USB] Added support for Sprint Pantech PX-500. + * [XEN] No really enable amd64. + * [XEN] Fix amd64 yet again. + + [Matthew Garrett] + + * alter default behaviour of ACPI video module + * Add infrastructure for notification on ACPI method execution + * Get thinkpad_acpi to send notifications on CMOS updates + * Add support to libata-acpi for acpi-based bay hotplug + + [Phillip Lougher] + + * Add kernel flavour optimised for virtualised environments + * Change abi-check script to check for $flavour.ignore in previous abi + * Disable abi and module check for virtual flavour + + [Richard Hughes] + + * Refresh laptop lid status on resume + + [Upstream Kernel Changes] + + * [pata_marvell]: Add more identifiers + + -- Ben Collins Sun, 16 Sep 2007 22:13:08 -0400 + +linux-source-2.6.22 (2.6.22-11.32) gutsy; urgency=low + + [Amit Kucheria] + + * Build system: Allow custom builds to comprise multiple patches + * Move UME to a Custom build and add first setup of thermal framework + + [Ben Collins] + + * ubuntu: Enable CONFIG_BLK_DEV_IO_TRACE + * bcm203x: Fix firmware loading + - LP: #85247 + * ubuntu: mtd changes caused module renaming. Ignore + * rt: Do not patch top level Makefile for SUBLEVEL. Will always end up + breaking + + [Chuck Short] + + * [USB] Unusual Device support for Gold MP3 Player Energy + - LP: #125250 + * [SIERRA] Adds support for Onda H600 ZTE MF330 + - LP: #129433 + * [HDAPS] Add Thinkpad T61P to whitelist. + - LP: #133636 + * [USB] Add support for Toshiba (Novatel Wireless) HSDPA for M400. + - LP: #133650 + + [Kyle McMartin] + + * apparmor 10.3 hooks + * unionfs 2.1 hooks + * nuke UNION_FS stuff from fs/{Kconfig,Makefile} + + [Tim Gardner] + + * Paravirt-ops I/O hypercalls + * Fix lazy vmalloc bug for Gutsy + * bluetooth headset patch + - LP: #130870 + * Add the PCI ID of this ICH4 in list of laptops that use short cables. + * v2.6.22.5 merge + * Update Xen config options. + - LP: #132726 + * Remove mtd modules from ABI + * Support parallel= in DEB_BUILD_OPTIONS + - LP: #136426 + + [Upstream Kernel Changes] + + * hwmon: fix w83781d temp sensor type setting + * hwmon: (smsc47m1) restore missing name attribute + * sky2: restore workarounds for lost interrupts + * sky2: carrier management + * sky2: check for more work before leaving NAPI + * sky2: check drop truncated packets + * revert "x86, serial: convert legacy COM ports to platform devices" + * ACPICA: Fixed possible corruption of global GPE list + * ACPICA: Clear reserved fields for incoming ACPI 1.0 FADTs + * AVR32: Fix atomic_add_unless() and atomic_sub_unless() + * r8169: avoid needless NAPI poll scheduling + * forcedeth: fix random hang in forcedeth driver when using netconsole + * libata: add ATI SB700 device IDs to AHCI driver + * Hibernation: do not try to mark invalid PFNs as nosave + * i386: allow debuggers to access the vsyscall page with compat vDSO + * x86_64: Check for .cfi_rel_offset in CFI probe + * x86_64: Change PMDS invocation to single macro + * i386: Handle P6s without performance counters in nmi watchdog + * i386: Fix double fault handler + * JFFS2 locking regression fix. + * [Input]: appletouch - improve powersaving for Geyser3 devices + * [Input]: add driver for Fujitsu serial touchscreens + * [sdhci]: add support to ENE-CB714 + * v2.6.22.5 + * [MTD] Makefile fix for mtdsuper + * ocfs2: Fix bad source start calculation during kernel writes + * NET: Share correct feature code between bridging and bonding + * sky2: don't clear phy power bits + * uml: fix previous request size limit fix + * i386: fix lazy mode vmalloc synchronization for paravirt + * signalfd: fix interaction with posix-timers + * signalfd: make it group-wide, fix posix-timers scheduling + * DCCP: Fix DCCP GFP_KERNEL allocation in atomic context + * IPV6: Fix kernel panic while send SCTP data with IP fragments + * IPv6: Invalid semicolon after if statement + * Fix soft-fp underflow handling. + * Netfilter: Missing Kbuild entry for netfilter + * SNAP: Fix SNAP protocol header accesses. + * NET: Fix missing rcu unlock in __sock_create() + * SPARC64: Fix sparc64 task stack traces. + * SPARC64: Fix sparc64 PCI config accesses on sun4u + * TCP: Do not autobind ports for TCP sockets + * TCP: Fix TCP rate-halving on bidirectional flows. + * TCP: Fix TCP handling of SACK in bidirectional flows. + * PPP: Fix PPP buffer sizing. + * PCI: lets kill the 'PCI hidden behind bridge' message + * PCI: disable MSI on RS690 + * PCI: disable MSI on RD580 + * PCI: disable MSI on RX790 + * USB: allow retry on descriptor fetch errors + * USB: fix DoS in pwc USB video driver + * usb: add PRODUCT, TYPE to usb-interface events + * Linux 2.6.22.6 + * V4L/DVB (6042): b2c2-flexcop: fix Airstar HD5000 tuning regression + * V4L/DVB (5967): ivtv: fix VIDIOC_S_FBUF:new OSD values where never set + * Re-add _GTM and _STM support + + -- Ben Collins Fri, 31 Aug 2007 16:26:56 -0400 + +linux-source-2.6.22 (2.6.22-10.30) gutsy; urgency=low + + * URGENT upload to fix FTBFS with xen-{i386,amd64} configs, + lpia d-i ftbfs, xen ftbfs. + * URGENT fix module-check to actually ignore things + * URGENT ignore ume modules + + [Alek Du] + + * Add Intel Poulsbo chipset Libata support + + [Amit Kucheria] + + * Update configuration files + * Enable stylus on Lenovo X60/X61 thinkpads + + [Ben Collins] + + * ubuntu: Disable snd-hda-intel, in favor of lum updated version + + [Kyle McMartin] + + * apparmor 10.3 hooks + * add lpia d-i udeb generation + * fix bits of rt/diff for -rt8 + * fix rt/diff for 2.6.22.3 changes + * fix up rt/diff for stable 2.6.22.4 + + [LaMont Jones] + + * Update configuration files + + [Phillip Lougher] + + * WriteSupportForNTFS: make fuse module available to d-i + + [Tim Gardner] + + * Gutsy Tribe 3 CD don't load on Dell Inspiron 1501 + - LP: #121111 + * Update configuration files + * Update configuration files + * Update configuration files + + [Upstream Kernel Changes] + + * [SPARC64]: Fix handling of multiple vdc-port nodes. + * [SPARC64]: Tweak assertions in sun4v_build_virq(). + * [SPARC64]: Fix log message type in vio_create_one(). + * [SPARC64]: Fix two year old bug in early bootup asm. + * [SPARC64]: Improve VIO device naming further. + * [SPARC64]: Handle multiple domain-services-port nodes properly. + * [SPARC64]: Add proper multicast support to VNET driver. + * [SPARC64]: Do not flood log with failed DS messages. + * [SPARC64]: Use KERN_ERR in IRQ manipulation error printks. + * [SPARC64]: Fix virq decomposition. + * [SPARC]: Fix serial console device detection. + * [SPARC64]: fix section mismatch warning in pci_sunv4 + * [SPARC64]: fix section mismatch warning in mdesc.c + * [SPARC64] viohs: extern on function definition + * [SPARC64]: Fix sun4u PCI config space accesses on sun4u. + * [SPARC64]: Fix show_stack() when stack argument is NULL. + * [SUNLANCE]: Fix sparc32 crashes by using of_*() interfaces. + * [SPARC]: Centralize find_in_proplist() instead of duplicating N times. + * [SPARC64]: Fix hard-coding of cpu type output in /proc/cpuinfo on + sun4v. + * [SPARC64]: Do not assume sun4v chips have load-twin/store-init support. + * [SPARC64]: Fix memory leak when cpu hotplugging. + * USB: cdc-acm: fix sysfs attribute registration bug + * TCP FRTO retransmit bug fix + * Fix TC deadlock. + * Fix IPCOMP crashes. + * Fix console write locking in sparc drivers. + * Add a PCI ID for santa rosa's PATA controller. + * Missing header include in ipt_iprange.h + * SCTP scope_id handling fix + * Fix rfkill IRQ flags. + * gen estimator timer unload race + * gen estimator deadlock fix + * Fix error queue socket lookup in ipv6 + * Fix ipv6 link down handling. + * Netpoll leak + * Sparc64 bootup assembler bug + * Fix ipv6 tunnel endianness bug. + * Fix sparc32 memset() + * Fix sparc32 udelay() rounding errors. + * Fix TCP IPV6 MD5 bug. + * KVM: SVM: Reliably detect if SVM was disabled by BIOS + * USB: fix warning caused by autosuspend counter going negative + * usb-serial: Fix edgeport regression on non-EPiC devices + * Fix reported task file values in sense data + * aacraid: fix security hole + * firewire: fw-sbp2: set correct maximum payload (fixes CardBus adapters) + * make timerfd return a u64 and fix the __put_user + * V4L: Add check for valid control ID to v4l2_ctrl_next + * V4L: ivtv: fix broken VBI output support + * V4L: ivtv: fix DMA timeout when capturing VBI + another stream + * V4L: ivtv: Add locking to ensure stream setup is atomic + * V4L: wm8775/wm8739: Fix memory leak when unloading module + * Input: lifebook - fix an oops on Panasonic CF-18 + * splice: fix double page unlock + * drm/i915: Fix i965 secured batchbuffer usage (CVE-2007-3851) + * Fix leak on /proc/lockdep_stats + * CPU online file permission + * Fix user struct leakage with locked IPC shem segment + * md: handle writes to broken raid10 arrays gracefully + * md: raid10: fix use-after-free of bio + * pcmcia: give socket time to power down + * Fix leaks on /proc/{*/sched, sched_debug, timer_list, timer_stats} + * futex: pass nr_wake2 to futex_wake_op + * "ext4_ext_put_in_cache" uses __u32 to receive physical block number + * Include serial_reg.h with userspace headers + * dm io: fix panic on large request + * i386: HPET, check if the counter works + * fw-ohci: fix "scheduling while atomic" + * firewire: fix memory leak of fw_request instances + * softmac: Fix ESSID problem + * eCryptfs: ecryptfs_setattr() bugfix + * nfsd: fix possible read-ahead cache and export table corruption + * readahead: MIN_RA_PAGES/MAX_RA_PAGES macros + * fs: 9p/conv.c error path fix + * forcedeth bug fix: cicada phy + * forcedeth bug fix: vitesse phy + * forcedeth bug fix: realtek phy + * acpi-cpufreq: Proper ReadModifyWrite of PERF_CTL MSR + * jbd commit: fix transaction dropping + * jbd2 commit: fix transaction dropping + * hugetlb: fix race in alloc_fresh_huge_page() + * do not limit locked memory when RLIMIT_MEMLOCK is RLIM_INFINITY + * uml: limit request size on COWed devices + * sony-laptop: fix bug in event handling + * destroy_workqueue() can livelock + * drivers/video/macmodes.c:mac_find_mode() mustn't be __devinit + * cfq-iosched: fix async queue behaviour + * libata: add FUJITSU MHV2080BH to NCQ blacklist + * ieee1394: revert "sbp2: enforce 32bit DMA mapping" + * nfsd: fix possible oops on re-insertion of rpcsec_gss modules + * dm raid1: fix status + * dm io: fix another panic on large request + * dm snapshot: permit invalid activation + * dm: disable barriers + * cr_backlight_probe() allocates too little storage for struct cr_panel + * ACPI: dock: fix opps after dock driver fails to initialize + * Hangup TTY before releasing rfcomm_dev + * Keep rfcomm_dev on the list until it is freed + * nf_conntrack: don't track locally generated special ICMP error + * IPV6: /proc/net/anycast6 unbalanced inet6_dev refcnt + * sysfs: release mutex when kmalloc() failed in sysfs_open_file(). + * Netfilter: Fix logging regression + * USB: fix for ftdi_sio quirk handling + * sx: switch subven and subid values + * UML: exports for hostfs + * Linux 2.6.22.2 + * fix oops in __audit_signal_info() + * random: fix bound check ordering (CVE-2007-3105) + * softmac: Fix deadlock of wx_set_essid with assoc work + * ata_piix: update map 10b for ich8m + * PPC: Revert "[POWERPC] Don't complain if size-cells == 0 in + prom_parse()" + * PPC: Revert "[POWERPC] Add 'mdio' to bus scan id list for platforms + with QE UEC" + * powerpc: Fix size check for hugetlbfs + * direct-io: fix error-path crashes + * stifb: detect cards in double buffer mode more reliably + * pata_atiixp: add SB700 PCI ID + * CPUFREQ: ondemand: fix tickless accounting and software coordination + bug + * CPUFREQ: ondemand: add a check to avoid negative load calculation + * Linux 2.6.22.3 + * intel_agp: really fix 945/965GME + * Reset current->pdeath_signal on SUID binary execution (CVE-2007-3848) + * MSS(mmc/sd/sdio) driver patch + + -- Kyle McMartin Thu, 16 Aug 2007 12:17:27 -0400 + +linux-source-2.6.22 (2.6.22-9.25) gutsy; urgency=low + + [Kyle McMartin] + + * ubuntu: Fix FTBFS -- forgot to bump debian/abi + + -- Kyle McMartin Thu, 02 Aug 2007 22:13:28 +0000 + +linux-source-2.6.22 (2.6.22-9.24) gutsy; urgency=low + + [Colin Watson] + + * provide Provides for fs-*-modules udebs + + [Matthias Klose] + + * test $dilist before using it + + [Lamont Jones] + + * hppa: Update abi files + + -- Kyle McMartin Thu, 02 Aug 2007 18:26:34 +0000 + +linux-source-2.6.22 (2.6.22-9.23) gutsy; urgency=low + + [Ben Collins] + + * ubuntu: Add missing newline to module-check script + * ubuntu: Add lpia to linux-libc-dev. Should finally build now. + + -- Ben Collins Thu, 02 Aug 2007 13:10:23 -0400 + +linux-source-2.6.22 (2.6.22-9.22) gutsy; urgency=low + + [Ben Collins] + + * ubuntu: Use DEB_HOST_ARCH, not DEB_HOST_ARCH_CPU + + -- Ben Collins Thu, 02 Aug 2007 08:44:09 -0400 + +linux-source-2.6.22 (2.6.22-9.21) gutsy; urgency=low + + [Ben Collins] + + * lpia: Add build stuff for lpia architecture + + [LaMont Jones] + + * abi files for hppa + * UBUNTU-HPPA: configs that seem to work + * hppa: abi files for 9.20 + + -- Ben Collins Wed, 01 Aug 2007 11:12:59 -0400 + +linux-source-2.6.22 (2.6.22-9.20) gutsy; urgency=low + + [Ben Collins] + + * tulip: Fix for Uli5261 chipsets. + * tulip: Define ULI PCI ID's + * tulip: Let dmfe handle davicom on non-sparc + * input: Allow root to inject unknown scan codes. + * irda: Default to dongle type 9 on IBM hardware + * input/mouse/alps: Do not call psmouse_reset() for alps + * pcmcia: Do not insert pcmcia cards on resume + * ide-cd: Disable verbose errors. + * block: Make CDROMEJECT more robust + * pm: Config option to disable handling of console during suspend/resume. + * version: Implement version_signature proc file. + * update toshiba_acpi to 0.19a-dev + * xpad: Update to latest version from xbox-linux. + * ubuntu: Enable setting of CONFIG_VERSION_SIGNATURE at build time + * toshiba_acpi: Don't use init_MUTEX_LOCKED + + [Chuck Short] + + * [USB]: add ASUS LCM to the blacklist + * [NET]: Add mcp73 to forcedeth. + * [USB]: Added support for Sanwa PC5000 multimeter usb cable (KB-USB2). + * [ATA] Add support for Sb700 AHCI nor-raid5 and raid5 + + [Fabio M. Di Nitto] + + * drivers/char/vt.c: make promcon driver init a boot option. + + [Kyle McMartin] + + * Disable MMCONFIG by default + + [Phillip Lougher] + + * fix NFS mounting regression from Edgy->Feisty + * r8169: disable TSO by default for RTL8111/8168B chipsets. + + [Tim Gardner] + + * Catch nonsense keycodes and silently ignore + * Cause SoftMac to emit an association event when setting ESSID. + + -- Ben Collins Mon, 30 Jul 2007 12:01:43 -0400 + +linux-source-2.6.22 (2.6.22-9.19) gutsy; urgency=low + + [Amit Kucheria] + + * Fix for FTBFS bug 123178 + * Fix for FTBFS bug 123178 + * Add devices to USB quirks to prevent USB autosuspend + * More devices added to USB quirks + - LP: #85488 + * Support for ENE CB-712/4 SD card reader + * Reorder quirk list based on Vendor/Product ID + + [Ben Collins] + + * ubuntu: Enable HOTPLUG_CPU in sparc64-smp config. + * ubuntu: Add xen to amd64 custom builds + * ubuntu: Update real-time kernel to -rt4 + * rt: Patch from Alessio Igor Bogani for RT-8 + + [Chuck Short] + + * IDE: add MHV2080BH to NCQ blacklist + * XEN: update to 2.6.22 final and amd64 support. + * NET: Add more pci-ids to zd1211rw + * IDE: add new PCI ID + * USB: fix oops in ftdi_sio + + [Eric Piel] + + * ACPI: Allow custom DSDT tables to be loaded from initramfs + + [Ryan Lortie] + + * Macbook calibration loop fix + - LP: #54621 + + [Upstream Kernel Changes] + + * NETFILTER: {ip, nf}_conntrack_sctp: fix remotely triggerable NULL ptr + dereference (CVE-2007-2876) + * Linux 2.6.22.1 + * [SPARC64]: Use KERN_ERR in sun4v IRQ printk()'s. + * [SPARC64]: Add LDOM virtual channel driver and VIO device layer. + * [SPARC64]: Add Sun LDOM virtual network driver. + * [SPARC64]: Add Sun LDOM virtual disk driver. + * [SPARC64]: Create proper obppath sysfs files for VIO bus devices. + * [SPARC64] LDC: Do limited polled retry on setting RX queue head. + * [SUNVNET]: Validate RX descriptor size field. + * [SPARC64]: Add missing symbol exports for LDOM infrastructure. + * [SPARC64]: Temporary workaround for LDC INO double-delivery. + * [SPARC64]: Create 'devspec' nodes for vio devices. + * [SPARC64]: vdev->type can be NULL, handle this in devspec_show(). + * [SPARC64]: Assorted LDC bug cures. + * [SPARC64]: Add domain-services nodes to VIO device tree. + * [SPARC64]: Export powerd facilities for external entities. + * [SPARC64]: Initial domain-services driver. + * [SPARC64]: Use more mearningful names for IRQ registry. + * [SPARC64]: Abstract out mdesc accesses for better MD update handling. + * [SPARC64]: Fix MD property lifetime bugs. + * [SPARC64]: Fix setting of variables in LDOM guest. + * [SPARC64]: Initial LDOM cpu hotplug support. + * [SPARC64]: Unconditionally register vio_bus_type. + * [SPARC64]: Fix build regressions added by dr-cpu changes. + * [SPARC64]: mdesc.c needs linux/mm.h + * [SPARC64]: SMP build fixes. + * [SPARC64]: More sensible udelay implementation. + * [SPARC64]: Process dr-cpu events in a kthread instead of workqueue. + * [SPARC64]: Add ->set_affinity IRQ handlers. + * [SPARC64]: Fix leak when DR added cpu does not bootup. + * [SPARC64]: Clear cpu_{core,sibling}_map[] in + smp_fill_in_sib_core_maps() + * [SPARC64]: Give more accurate errors in dr_cpu_configure(). + * [SERIAL]: Fix console write locking in sparc drivers. + * [TIMER]: Fix clockevent notifications on 64-bit. + * [SPARC64]: dr-cpu unconfigure support. + * [SPARC64]: Fix UP build. + * [SPARC64]: SMP build fix. + * [SPARC64]: Fix race between MD update and dr-cpu add. + * [SERIAL] SUNHV: Fix jerky console on LDOM guests. + * [SPARC64]: Kill explicit %gl register reference. + * [SPARC64]: Add basic infrastructure for MD add/remove notification. + * [SPARC64]: Simplify VDC device probing. + * [SPARC64]: Simplify VNET probing. + * [SPARC64]: Massively simplify VIO device layer and support hot + add/remove. + * [SPARC64]: Handle LDC resets properly in domain-services driver. + * [SPARC64]: Handle reset events in vio_link_state_change(). + * [SPARC64]: Fix reset handling in VNET driver. + * [SPARC64]: Set vio->desc_buf to NULL after freeing. + * [SPARC64]: Fix MODULE_DEVICE_TABLE() specification in VDC and VNET. + * [SPARC64]: Fix device type matching in VIO's devspec_show(). + * Add empty + * Add dummy isa_(bus|virt)_to_(virt|bus) inlines + * Clean up sti_flush + * Do not allow STI_CONSOLE to be modular + * Use compat_sys_getdents + + -- Ben Collins Sat, 28 Jul 2007 12:30:53 -0400 + +linux-source-2.6.22 (2.6.22-8.18) gutsy; urgency=low + + [Ben Collins] + + * ubuntu: *sigh* update xen config to fix FTBFS + + -- Ben Collins Thu, 12 Jul 2007 14:23:20 +0100 + +linux-source-2.6.22 (2.6.22-8.17) gutsy; urgency=low + + [Ben Collins] + + * ubuntu: Actually enable the -xen build. + + -- Ben Collins Thu, 12 Jul 2007 09:51:01 +0100 + +linux-source-2.6.22 (2.6.22-8.16) gutsy; urgency=low + + * Removed CONFIG_BLINK from all configs and added to modules.ignore + * This fixes a build failure for 8.15 + + [Alexey Starikovskiy] + + * Fix ACPI battery detection on Asus + + [Amit Kucheria] + + * Export symbols required to build GFS1 in LUM + * Update configuration files + * 2.6.22-7.14 ABI + * Remove old ABI + * Update d-i modules to support Sparc LDOM + * Introducing the UME kernel flavour + + [Jacob Pan] + + * Poulsbo SMBus Controller + * Intel Poulsbo SCH IDE Controller + * Intel Poulsbo HD audio controller + + [Phillip Lougher] + + * xen: Update custom binary flavour (Xen 3.1 for 2.6.22-rc5) + * xen: Update xen/config.i386 to enable PAE + + [Upstream Kernel Changes] + + * [SCSI] fusion: fix for BZ 8426 - massive slowdown on SCSI CD/DVD drive + * [XFS] Update the MAINTAINERS file entry for XFS. + * IB/mlx4: Fix handling of wq->tail for send completions + * IB/mlx4: Fix warning in rounding up queue sizes + * [SCSI] ESP: Don't forget to clear ESP_FLAG_RESETTING. + * firewire: fix hang after card ejection + * ieee1394: fix to ether1394_tx in ether1394.c + * [ARM] Add support for pause_on_oops and display preempt/smp options + * sh: Fix restartable syscall arg5 clobbering. + * ACPI: gracefully print null trip-point device + * ACPICA: fix error path in new external package objects as method + arguments + * sh: oops_enter()/oops_exit() in die(). + * [ARM] Update show_regs/oops register format + * IB/mlx4: Handle new FW requirement for send request prefetching + * IB/mlx4: Get rid of max_inline_data calculation + * IB/mlx4: Handle buffer wraparound in __mlx4_ib_cq_clean() + * IB/mlx4: Handle FW command interface rev 3 + * Fix signalfd interaction with thread-private signals + * sched: fix SysRq-N (normalize RT tasks) + * Fix possible runqueue lock starvation in wait_task_inactive() + * sh: Handle -ERESTART_RESTARTBLOCK for restartable syscalls. + * sh64: Handle -ERESTART_RESTARTBLOCK for restartable syscalls. + * [POWERPC] Fix snd-powermac refcounting bugs + * [XFS] s/memclear_highpage_flush/zero_user_page/ + * [XFS] Update the MAINTAINERS file entry for XFS - change git repo name. + * [XFRM]: Fix MTU calculation for non-ESP SAs + * [IPVS]: Fix state variable on failure to start ipvs threads + * [AF_RXRPC]: Return the number of bytes buffered in rxrpc_send_data() + * [S390] Missing blank when appending cio_ignore kernel parameter + * [S390] Fix zfcpdump header + * [S390] Fix yet another two section mismatches. + * [S390] Print list of modules on die(). + * [S390] Add oops_enter()/oops_exit() calls to die(). + * [S390] Move psw_set_key. + * [POWERPC] rheap - eliminates internal fragments caused by alignment + * [POWERPC] PowerPC: Prevent data exception in kernel space (32-bit) + * [POWERPC] Fix powermac late initcall to only run on powermac + * [MIPS] Don't drag a platform specific header into generic arch code. + * x86_64: Fix readahead/sync_file_range/fadvise64 compat calls + * x86_64: Fix eventd/timerfd syscalls + * x86: Disable DAC on VIA bridges + * x86_64: Quieten Atari keyboard warnings in Kconfig + * x86: Only make Macintosh drivers default on Macs + * x86: Disable KPROBES with DEBUG_RODATA for now + * x86: change_page_attr bandaids + * x86_64: fix link warning between for .text and .init.text + * Fix up CREDIT entry ordering + * firewire: Only set client->iso_context if allocation was successful. + * spidernet: null out skb pointer after its been used. + * spidernet: Cure RX ram full bug + * spidernet: Don't terminate the RX ring + * spidernet: silence the ramfull messages + * spidernet: turn off descriptor chain end interrupt. + * spidernet: checksum and ethtool + * bonding: Fix use after free in unregister path + * bonding: Fix 802.3ad no carrier on "no partner found" instance + * s390: print correct level for HiperSockets devices + * s390: qeth driver does not recover + * s390: avoid inconsistent lock state in qeth + * s390: qeth: wrong packet length in qdio header + * s390: Use ccw_device_get_id() in qeth/claw drivers + * s390: don't call iucv_path_connect from tasklet context + * s390: netiucv spinlock initializer cleanup + * s390: netiucv inlining cleanup + * forcedeth: use unicast receive mode for WoL + * natsemi irq flags + * cxgb3 - fix skb->dev dereference + * cxgb3 - fix netpoll hanlder + * cxgb3 - Fix direct XAUI support + * cxgb3 - Stop mac RX when changing MTU + * cxgb3 - MAC watchdog update + * PATA: Add the MCP73/77 support to PATA driver + * pata_it821x: (partially) fix DMA in RAID mode + * libata: more NONCQ devices + * kerneldoc fix in libata + * ahci: fix PORTS_IMPL override + * fix module_param mistake in it821x + * Blackfin arch: update ANOMALY handling + * Blackfin arch: update printk to use KERN_EMERG and reformat crash + output + * Blackfin arch: add missing braces around array bfin serial init + * Blackfin arch: match kernel startup messaage with new linker script + * Blackfin arch: move cond_syscall() behind __KERNEL__ like all other + architectures + * Blackfin arch: Add definition of dma_mapping_error + * Blackfin arch: add proper const volatile to addr argument to the read + functions + * [AGPGART] intel_agp: don't load if no IGD and AGP port + * IB/umem: Fix possible hang on process exit + * IPoIB/cm: Initialize RX before moving QP to RTR + * IPoIB/cm: Fix interoperability when MTU doesn't match + * IPoIB/cm: Remove dead definition of struct ipoib_cm_id + * IB/mlx4: Correct max_srq_wr returned from mlx4_ib_query_device() + * [PARISC] stop lcd driver from stripping initial whitespace + * [PARISC] Handle wrapping in expand_upwards() + * [PARISC] Fix unwinder on 64-bit kernels + * [PARISC] unwinder improvements + * page_mapping must avoid slub pages + * posix-timers: Prevent softirq starvation by small intervals and SIG_IGN + * Allow DEBUG_RODATA and KPROBES to co-exist + * [NETFILTER]: nf_conntrack_sip: add missing message types containing RTP + info + * [NETFILTER]: nfctnetlink: Don't allow to change helper + * [IPV6] NDISC: Fix thinko to control Router Preference support. + * [IPV4]: include sysctl.h from inetdevice.h + * i386: Make CMPXCHG64 only dependent on PAE + * x86_64: Fix only make Macintosh drivers default on Macs + * x86_64: Ignore compat mode SYSCALL when IA32_EMULATION is not defined + * [AVR32] Fix bug in invalidate_dcache_region() + * [AVR32] NGW100, Remove relics of the old USART mapping scheme + * [AVR32] Initialize dma_mask and dma_coherent_mask + * [AVR32] Update defconfigs + * ACPI: fix 2.6.20 SMP boot regression + * [SKBUFF]: Fix incorrect config #ifdef around skb_copy_secmark + * [TIPC]: Fix infinite loop in netlink handler + * [PPP]: Revert 606f585e363527da9feaed79465132c0c661fd9e + * [PPP]: Fix osize too small errors when decoding mppe. + * [TCP] tcp_read_sock: Allow recv_actor() return return negative error + value. + * [NET]: Re-enable irqs before pushing pending DMA requests + * [NET]: Make skb_seq_read unmap the last fragment + * hwmon/coretemp: fix a broken error path + * fix refcounting of nsproxy object when unshared + * console UTF-8 fixes (fix) + * SM501: suspend support + * SM501: initialise SDRAM clock before bus clocks + * SM501: Fix sm501_init_reg() mask/set order + * SM501: Clock updates and checks + * SM501: Add Documentation/SM501.txt + * SM501: Check SM501 ID register on initialisation + * SLUB: fix behavior if the text output of list_locations overflows + PAGE_SIZE + * sched: fix next_interval determination in idle_balance() + * update checkpatch.pl to version 0.05 + * alpha: fix alignment problem in csum_ipv6_magic() + * Char: stallion, fix oops during init with ISA cards + * uml: use generic BUG + * uml: add asm/paravirt.h + * "volatile considered harmful" + * document nlink function + * slab allocators: MAX_ORDER one off fix + * update checkpatch.pl to version 0.06 + * x86_64: fix misplaced `continue' in mce.c + * ext2: disallow setting xip on remount + * audit: fix oops removing watch if audit disabled + * ext3: lost brelse in ext3_read_inode() + * ext4: lost brelse in ext4_read_inode() + * ACPI: preserve the ebx value in acpi_copy_wakeup_routine + * FUTEX: Restore the dropped ERSCH fix + * Linus 2.6.22-rc6 + * [ARM] 4452/1: Force the literal pool dump before reloc_end + * [ARM] 4449/1: more entries in arch/arm/boot/.gitignore + * fix nmi_watchdog=2 bootup hang + * [POWERPC] Update g5_defconfig + * [POWERPC] Update defconfigs + * [POWERPC] Fix VDSO gettimeofday() when called with NULL struct timeval + * [POWERPC] Fix subtle FP state corruption bug in signal return on SMP + * USB: g_file_storage: call allow_signal() + * USB: ti serial driver sleeps with spinlock held + * USB: memory leak in iowarrior.c + * USB: usblcd doesn't limit memory consumption during write + * USB: fix race leading to use after free in io_edgeport + * USB: add new device id to option driver + * USB: ftdio_sio: New IPlus device ID + * [MIPS] __ucmpdi2 arguments are unsigned long long. + * [MIPS] add io_map_base to pci_controller on Cobalt + * [MIPS] remove "support for" from system type entry + * [MIPS] Alchemy: Fix wrong cast + * [MIPS] Fix pb1500 reg B access + * [MIPS] AP/SP requires shadow registers, auto enable support. + * [MIPS] 20K: Handle WAIT related bugs according to errata information + * [MIPS] use compat_siginfo in rt_sigframe_n32 + * [MIPS] Remove a duplicated local variable in test_and_clear_bit() + * [MIPS] EMMA2RH: Disable GEN_RTC, it can't possibly work. + * [MIPS] SMTC and non-SMTC kernel and modules are incompatible + * [MIPS] Count timer interrupts correctly. + * x86_64: set the irq_chip name for lapic + * x86_64 irq: use mask/unmask and proper locking in fixup_irqs() + * [SPARC64]: Add irqs to mdesc_node. + * [SPARC64]: Fix VIRQ enabling. + * [SPARC64]: Need to set state to IDLE during sun4v IRQ enable. + * [SPARC64]: Add LDOM virtual channel driver and VIO device layer. + * [SPARC64]: Add Sun LDOM virtual network driver. + * [SPARC64]: Add Sun LDOM virtual disk driver. + * [SPARC64]: Create proper obppath sysfs files for VIO bus devices. + * [SPARC64] LDC: Do limited polled retry on setting RX queue head. + * [GFS2] Fix gfs2_block_truncate_page err return + * [DLM] Telnet to port 21064 can stop all lockspaces + * [GFS2] inode size inconsistency + * [GFS2] remounting w/o acl option leaves acls enabled + * [GFS2] System won't suspend with GFS2 file system mounted + * [GFS2] git-gfs2-nmw-build-fix + * [GFS2] Obtaining no_formal_ino from directory entry + * [GFS2] Remove i_mode passing from NFS File Handle + * [SUNVNET]: Validate RX descriptor size field. + * [SPARC64]: Add missing symbol exports for LDOM infrastructure. + * [SPARC64]: Temporary workaround for LDC INO double-delivery. + * [SPARC64]: Create 'devspec' nodes for vio devices. + * [SPARC64]: vdev->type can be NULL, handle this in devspec_show(). + + -- Amit Kucheria Mon, 09 Jul 2007 12:55:56 +0300 + +linux-source-2.6.22 (2.6.22-7.14) gutsy; urgency=low + + [Ben Collins] + + * build/vars: Provide ivtv-modules + * Bump ABI + * ubuntu/config: Enable Intermediate Functional Block device + * coredump: Fix typo in patch merge + * ubuntu/scripts: Make sure to symlink *.lds for ia64 builds + * ubuntu/config: Enable NO_HZ for server and sparc64 targets. + * ubuntu/config: Remove bigiron target, see if anyone complains + * ubuntu: Ok, really remove bigiron + * ubuntu/control-scripts: Fo sho, remove the debconf stuff from controls + scripts + * AppArmor: Enable exports and changes for AppArmor usage + * ubuntu: Add feisty changelog for historical purposes. + + [Colin Watson] + + * Move isofs to storage-core-modules udeb from fs-core-modules. + + [Upstream Kernel Changes] + + * [MTD] [MAPS] don't force uclinux mtd map to be root dev + * [MTD] generalise the handling of MTD-specific superblocks + * [SCSI] zfcp: avoid clutter in erp_dbf + * [SCSI] zfcp: IO stall after deleting and path checker changes after + reenabling zfcp devices + * [SCSI] ipr: Proper return codes for eh_dev_reset for SATA devices + * [SCSI] stex: fix id mapping issue + * [SCSI] stex: extend hard reset wait time + * [SCSI] stex: fix reset recovery for console device + * [SCSI] stex: minor cleanup and version update + * [SCSI] MegaRAID: Update MAINTAINERS email-id + * [SCSI] tgt: fix a rdma indirect transfer error bug + * [SCSI] NCR53C9x: correct spelling mistake in deprecation notice + * [SCSI] aacraid: Correct sa platform support. (Was: [Bug 8469] Bad EIP + value on pentium3 SMP kernel-2.6.21.1) + * [SCSI] aacraid: fix panic on short Inquiry + * [WATCHDOG] ks8695_wdt.c - new KS8695 watchdog driver + * [JFFS2] Fix BUG() caused by failing to discard xattrs on deleted files. + * [JFFS2] Fix potential memory leak of dead xattrs on unmount. + * [SCSI] sd: fix refcounting regression in suspend/resume routines + * [SCSI] aacraid: apply commit config for reset_devices flag + * [SCSI] aic7xxx: fix aicasm build failure with gcc-3.4.6 + * [SCSI] aic94xx: asd_clear_nexus should fail if the cleared task does + not complete + * [SCSI] fusion: Fix |/|| confusion + * parisc: make command_line[] static + * parisc: sync compat getdents + * [PARISC] Move #undef to end of syscall table + * [PARISC] Wire up kexec_load syscall + * parisc: convert /proc/gsc/pcxl_dma to seq_file + * [PARISC] Let PA-8900 processors boot + * [PARISC] Disable LWS debugging + * [PARISC] spelling fixes: arch/parisc/ + * sh: section mismatch fixes for system timer. + * [PARISC] ROUND_UP macro cleanup in arch/parisc + * [PARISC] ROUNDUP macro cleanup in drivers/parisc + * [PPC] Fix COMMON symbol warnings + * [PPC] Remove duplicate export of __div64_32. + * [POWERPC] 52xx: unbreak lite5200 dts (_pic vs. -pic) + * [POWERPC] QE: fix Kconfig 'select' warning with UCC_FAST + * [POWERPC] Fix Section mismatch warnings + * [POWERPC] Fix modpost warning + * [PPC] Fix modpost warning + * [CIFS] Fix oops on failed cifs mount (in kthread_stop) + * [POWERPC] Fix Kconfig warning + * [CIFS] typo in previous patch + * [SCSI] megaraid_sas: intercept cmd timeout and throttle io + * [WATCHDOG] clean-up watchdog documentation + * drm: Spinlock initializer cleanup + * drm/radeon: add more IGP chipset pci ids + * drm: make sure the drawable code doesn't call malloc(0). + * [PARISC] kobject is embedded in subsys, not kset + * [PARISC] Build fixes for power.c + * [ARM] 4401/1: S3C2443: Add definitions for port GPIOJ + * [ARM] 4402/1: S3C2443: Add physical address of HSMMC controller + * [ARM] 4403/1: Make the PXA-I2C driver work with lockdep validator + * [ARM] 4404/1: Trivial IXP42x Kconfig cleanup + * [ARM] 4405/1: NSLU2, DSM-G600 frequency fixup code + * [ARM] 4406/1: Trivial NSLU2 / NAS-100D header & setup code cleanup + * [ARM] remove unused header file: arch/arm/mach-s3c2410/bast.h + * [PARISC] fix lasi_82596 build + * [PARISC] fix section mismatch in parport_gsc + * [PARISC] fix section mismatch in parisc STI video drivers + * [PARISC] fix section mismatch in ccio-dma + * [PARISC] fix section mismatches in arch/parisc/kernel + * [PARISC] fix section mismatch in parisc eisa driver + * [PARISC] fix section mismatch in superio serial drivers + * [PARISC] Wire up utimensat/signalfd/timerfd/eventfd syscalls + * hwmon/ds1621: Fix swapped temperature limits + * hwmon/coretemp: Add more safety checks + * hwmon/w83627hf: Be quiet when no chip is found + * hwmon-vid: Don't spam the logs when VRM version is missing + * hwmon/applesmc: Simplify dependencies + * hwmon/applesmc: Handle name file creation error and deletion + * ieee1394: sbp2: include workqueue.h + * ieee1394: eth1394: remove bogus netif_wake_queue + * ieee1394: eth1394: handle tlabel exhaustion + * ieee1394: eth1394: bring back a parent device + * ieee1394: raw1394: Fix async send + * firewire: Add missing byteswapping for receive DMA programs. + * firewire: prefix modules with firewire- instead of fw- + * firewire: fix return code + * [libata] Add drive to NCQ blacklist + * [ARM] enable arbitary speed tty ioctls and split input/output speed + * Input: db9 - do not ignore dev2 module parameter + * Input: logips2pp - fix typo in Kconfig + * [XFS] Write at EOF may not update filesize correctly. + * [SCSI] pluto: Use wait_for_completion_timeout. + * [SPARC64]: Kill unused DIE_PAGE_FAULT enum value. + * [SPARC64]: Don't be picky about virtual-dma values on sun4v. + * [SPARC32]: Removes mismatch section warnigs in sparc time.c file + * [SERIAL] sunzilog: section mismatch fix + * [SPARC64]: PCI device scan is way too verbose by default. + * [SCSI] jazz_esp: Converted to use esp_core. + * [SCSI] ESP: Kill SCSI_ESP_CORE and link directly just like jazz_esp + * [SPARC64]: Fix typo in sun4v_hvapi_register error handling. + * [SPARC64]: Report proper system soft state to the hypervisor. + * [SPARC64]: Negotiate hypervisor API for PCI services. + * [SPARC64]: Use machine description and OBP properly for cpu probing. + * [SPARC64]: Eliminate NR_CPUS limitations. + * [SPARC64]: arch/sparc64/time.c doesn't compile on Ultra 1 (no PCI) + * [SPARC]: Linux always started with 9600 8N1 + * [SPARC64]: Fix _PAGE_EXEC_4U check in sun4u I-TLB miss handler. + * [SPARC]: Emulate cmpxchg like parisc + * [SPARC]: Mark as emulating cmpxchg, add appropriate depends for DRM. + * [SPARC64]: Fix two bugs wrt. kernel 4MB TSB. + * [SPARC64]: Fill holes in hypervisor APIs and fix KTSB registry. + * mac80211: fail back to use associate from reassociate + * mac80211: fix memory leak when defrag fragments + * mac80211: always set carrier status on open + * mac80211: avoid null ptr deref in ieee80211_ibss_add_sta + * prism54: fix monitor mode oops + * ieee80211: fix incomplete error message + * softmac: alloc_ieee80211() NULL check + * hostap: Allocate enough tailroom for TKIP + * sparc64: fix alignment bug in linker definition script + * USB: replace flush_workqueue with cancel_sync_work + * ACPICA: allow Load(OEMx) tables + * ACPI: thermal: Replace pointer with name in trip_points + * ACPI: extend "acpi_osi=" boot option + * IB/mthca: Fix handling of send CQE with error for QPs connected to SRQ + * IPoIB/cm: Fix performance regression on Mellanox + * IB/cm: Fix stale connection detection + * IB/mlx4: Fix last allocated object tracking in bitmap allocator + * NOHZ: prevent multiplication overflow - stop timer for huge timeouts + * random: fix error in entropy extraction + * random: fix seeding with zero entropy + * ACPI: Make _OSI(Linux) a special case + * ACPI: add __init to acpi_initialize_subsystem() + * [PARISC] fix "ENTRY" macro redefinition + * [PARISC] fix section mismatch in smp.c + * [PARISC] remove remnants of parisc-specific softirq code + * [PARISC] fix trivial spelling nit in asm/linkage.h + * [PARISC] fix null ptr deref in unwind.c + * [PARISC] fix "reduce size of task_struct on 64-bit machines" fallout + * [PARISC] be more defensive in process.c::get_wchan + * [ARM] use __used attribute + * [ARM] Fix stacktrace FP range checking + * [ARM] oprofile: avoid lockdep warnings on mpcore oprofile init + * [ARM] 4411/1: KS8695: Another serial driver fix + * [ARM] 4412/1: S3C2412: reset errata fix + * [ARM] 4414/1: S3C2443: sparse fix for clock.c + * [ARM] 4415/1: AML5900: fix sparse warnings from map_io + * [ARM] 4416/1: NWFPE: fix undeclared symbols + * [ARM] 4410/1: Remove extern declarations in coyote/ixdpg425-pci.c + * [ARM] 4394/1: ARMv7: Add the TLB range operations + * [ARM] 4417/1: Serial: Fix AMBA drivers locking + * sky2: dont set bogus bit in PHY register + * sky2: checksum offload plus vlan bug + * sky2: program proper register for fiber PHY + * defxx: Fix the handling of ioremap() failures + * e1000: restore netif_poll_enable call but make sure IRQs are off + * sky2: enable IRQ on duplex renegotiation + * ehea: Fixed multi queue RX bug + * [SCSI] fix CONFIG_SCSI_WAIT_SCAN=m + * [SCSI] qla2xxx: fix timeout in qla2x00_down_timeout + * [ARM] Fix some section mismatch warnings + * alpha: cleanup in bitops.h + * alpha: support new syscalls + * fix possible null ptr deref in kallsyms_lookup + * NFS: Fix a refcount leakage in O_DIRECT + * a bug in ramfs_nommu_resize function, passing old size to vmtruncate + * sh: Fix pcrel too far for in_nmi label. + * sh: Trivial fix for dma-api compile failure. + * sh: Fix vsyscall build failure. + * sh: trivial build cleanups. + * sh: support older gcc's + * [ALSA] HDA: Add support for Gateway NX860 + * [ALSA] HDA: Add more systems to Sigmatel codec + * [ALSA] HDA: Fix headphone mute issue on non-eapd Conexant systems + * [ALSA] hda-codec - Add support for ASUS A8J modem + * [ALSA] ali5451 - Fix possible NULL dereference + * [ALSA] hda-intel: fix ASUS M2V detection + * [ALSA] Fix ASoC s3c24xx-pcm spinlock bug + * [ALSA] hda-codec - Add quirk for MSI S420 + * [ALSA] hda-codec - Add quirk for Supermicro PDSBA to alc883_cfg_tbl[] + * [ALSA] hda-codec - Add support for MSI K9N Ultra + * [ALSA] hda-codec - Fix pin configs for Gateway MX6453 + * [ALSA] hda-codec - Fix input with STAC92xx + * [ALSA] hda-codec - Fix STAC922x capture boost level + * [CRYPTO] cryptd: Fix problem with cryptd and the freezer + * [CASSINI]: Fix printk message typo. + * [XFRM]: Allow XFRM_ACQ_EXPIRES to be tunable via sysctl. + * [XFRM]: xfrm_larval_drop sysctl should be __read_mostly. + * [IPSEC]: Fix IPv6 AH calculation in outbound + * [IPV6] ROUTE: No longer handle ::/0 specially. + * [NET]: parse ip:port strings correctly in in4_pton + * [IPSEC]: Fix panic when using inter address familiy IPsec on loopback. + * [IPV4]: Kill references to bogus non-existent CONFIG_IP_NOSIOCRT + * [AF_PACKET]: Kill bogus CONFIG_PACKET_MULTICAST + * [IPV6]: Fix build warning. + * [AF_PACKET]: Kill CONFIG_PACKET_SOCKET. + * [SOCK]: Shrink struct sock by 8 bytes on 64-bit. + * [TCP]: Consolidate checking for tcp orphan count being too big. + * [NET] napi: Call __netif_rx_complete in netif_rx_complete + * [IPV6] ADDRCONF: Fix conflicts in DEVCONF_xxx constant. + * [TCP] tcp_probe: a trivial fix for mismatched number of printl + arguments. + * [TCP] tcp_probe: use GCC printf attribute + * [BRIDGE]: Reduce frequency of forwarding cleanup timer in bridge. + * [BRIDGE]: Round off STP perodic timers. + * [IPSEC]: Add xfrm_sysctl.txt. + * [SPARC64]: Add missing NCS and SVC hypervisor interfaces. + * [SPARC32]: Build fix. + * [SPARC]: Missing #include in drivers/sbus/char/flash.c + * [ALSA] version 1.0.14 + * neofb: Fix pseudo_palette array overrun in neofb_setcolreg + * smpboot: fix cachesize comparison in smp_tune_scheduling() + * at91: fix enable/disable_irq_wake symmetry in pcmcia driver + * SLUB: More documentation + * pci-quirks: fix MSI disabling on RS400-200 and RS480 + * ntfs_init_locked_inode(): fix array indexing + * m68k: runtime patching infrastructure + * SLUB: Fix NUMA / SYSFS bootstrap issue + * afs: needs sched.h + * m68k: discontinuous memory support + * [S390] Add exception handler for diagnose 224 + * [S390] dasd_eer: use mutex instead of semaphore + * [S390] arch/s390/kernel/debug.c: use mutex instead of semaphore + * [S390] raw3270: use mutex instead of semaphore + * [S390] Fix section annotations. + * [S390] cio: Use device_schedule_callback() for removing disconnected + devices. + * [S390] cio: deregister ccw device when pgid disband failed + * ACPI: thinkpad-acpi: do not use named sysfs groups + * ieee1394: fix calculation of sysfs attribute "address" + * ieee1394: sbp2: offer SAM-conforming target port ID in sysfs + * firewire: fw-sbp2: implement sysfs ieee1394_id + * firewire: add to MAINTAINERS + * firewire: Implement suspend/resume PCI driver hooks. + * firewire: Change struct fw_cdev_iso_packet to not use bitfields. + * firewire: Install firewire-constants.h and firewire-cdev.h for + userspace. + * EXT4: Fix whitespace + * Remove unnecessary exported symbols. + * ext4: Extent overlap bugfix + * When ext4_ext_insert_extent() fails to insert new blocks + * Define/reserve new ext4 superblock fields + * msi: fix ARM compile + * PCI: disable MSI by default on systems with Serverworks HT1000 chips + * PCI: Fix pci_find_present + * PCI: i386: fixup for Siemens Nixdorf AG FSC Multiprocessor Interrupt + Controllers + * PCI: quirk disable MSI on via vt3351 + * [XTENSA] fix bit operations in bitops.h + * [XTENSA] Spelling fixes in arch/xtensa + * [XTENSA] fix sources using deprecated assembler directive + * [XTENSA] Remove multi-exported symbols from xtensa_ksyms.c + * [XTENSA] Use generic 64-bit division + * [XTENSA] clean-up header files + * [XTENSA] Move common sections into bss sections + * [XTENSA] Remove non-rt signal handling + * Xtensa: use asm-generic/fcntl.h + * [JFFS2] Fix buffer length calculations in jffs2_get_inode_nodes() + * Fix vmi.c compilation + * x86_64: allocate sparsemem memmap above 4G + * Add select PHYLIB to the UCC_GETH Kconfig option + * Fix possible UDF data corruption + * m68k: parenthesis balance + * msi: fix the ordering of msix irqs + * msi: mask the msix vector before we unmap it + * potential parse error in ifdef + * parse errors in ifdefs + * pci_ids: update patch for Intel ICH9M + * x86: fix oprofile double free + * Work around Dell E520 BIOS reboot bug + * fix compat futex code for private futexes + * skeletonfb: fix of xxxfb_setup ifdef + * vt8623fb: arkfb: null pointer dereference fix + * cfag12864bfb: Use sys_ instead of cfb_ framebuffer accessors + * fbdev: Move declaration of fb_class to + * misc/tifm_7xx1: replace deprecated irq flag + * add a trivial patch style checker + * Documentation: How to use GDB to decode OOPSes + * RTC: use fallback IRQ if PNP tables don't provide one + * memory hotplug: fix unnecessary calling of init_currenty_empty_zone() + * tty: fix leakage of -ERESTARTSYS to userland + * ISDN4Linux: fix maturity label + * Fix broken CLIR in isdn driver + * prism54: MAINTAINERS update + * atmel_spi dma address bugfix + * h8300 trival patches + * ALPHA: support graphics on non-zero PCI domains + * ALPHA: correct low-level I/O routines for sable-lynx + * ALPHA: misc fixes + * Better documentation for ERESTARTSYS + * serial_core.h: include + * SPI: Freescale iMX SPI controller driver fixes + * SLUB: fix locking for hotplug callbacks + * pm3fb: switching between X and fb fix + * microcode: fix section mismatch warning + * isdn: fix section mismatch warnings + * acpi: fix section mismatch warning in asus + toshiba + * kvm: fix section mismatch warning in kvm-intel.o + * net/hp100: fix section mismatch warning + * timer statistics: fix race + * timer stats: speedups + * [SCSI] aacraid: fix shutdown handler to also disable interrupts. + * [MTD] Fix error checking after get_mtd_device() in get_sb_mtd functions + * [JFFS2] Fix obsoletion of metadata nodes in jffs2_add_tn_to_tree() + * ACPI: Section mismatch ... acpi_map_pxm_to_node + * ACPICA: Support for external package objects as method arguments + * Pull now into release branch + * Pull osi-now into release branch + * [POWERPC] Update documentation for of_find_node_by_type() + * [POWERPC] Fix ppc32 single-stepping out of syscalls + * [POWERPC] Fix compiler/assembler flags for Ebony platform boot files + * [POWERPC] Fix possible access to free pages + * [POWERPC] ps3/interrupt.c uses get_hard_smp_processor_id + * [POWERPC] pasemi idle uses hard_smp_processor_id + * [POWERPC] Create a zImage for legacy iSeries + * [POWERPC] Don't use HOSTCFLAGS in BOOTCFLAGS + * [POWERPC] Fix compile warning in pseries xics code + * [POWERPC] Fix return from pte_alloc_one() in out-of-memory case + * [POWERPC] Compare irq numbers with NO_IRQ not IRQ_NONE + * [POWERPC] Don't allow PMAC_APM_EMU for 64-bit + * [POWERPC] Fix compile breakage for IBM/AMCC 4xx arch/ppc platforms + * [POWERPC] Fix zImage.coff generation for 32-bit pmac + * [ARM] 4392/2: Do not corrupt the SP register in compressed/head.S + * [ARM] 4418/1: AT91: Number of programmable clocks differs + * [ARM] 4419/1: AT91: SAM9 USB clocks check for suspending + * [ARM] 4422/1: Fix default value handling in gpio_direction_output (PXA) + * [ARM] Solve buggy smp_processor_id() usage + * qla3xxx: device doesnt do hardware checksumming. + * VLAN: kill_vid is only useful for VLAN filtering devices + * sky2: Fix VLAN unregistration + * 8139cp: fix VLAN unregistration + * atl1: eliminate unneeded kill_vid code + * network drivers: eliminate unneeded kill_vid code + * e1000: disable polling before registering netdevice + * smc91x: sh solution engine fixes. + * Update tulip maintainer email address + * NetXen: Removal of extra free_irq call + * myri10ge: report link up/down in standard ethtool way + * NET: add MAINTAINERS entry for ucc_geth driver + * [ARM] 4421/1: AT91: Value of _KEY fields. + * [PARISC] Fix bug when syscall nr is __NR_Linux_syscalls + * [AF_UNIX]: Make socket locking much less confusing. + * [TG3]: Fix link problem on Dell's onboard 5906. + * [AF_UNIX]: Fix datagram connect race causing an OOPS. + * [TCP]: Use default 32768-61000 outgoing port range in all cases. + * [ATM]: Fix warning. + * [NET]: Make net watchdog timers 1 sec jiffy aligned. + * [NET]: Fix comparisons of unsigned < 0. + * [TCP]: Fix GSO ignorance of pkts_acked arg (cong.cntrl modules) + * [NET] gso: Fix GSO feature mask in sk_setup_caps + * [IPV4]: Fix "ipOutNoRoutes" counter error for TCP and UDP + * [ICMP]: Fix icmp_errors_use_inbound_ifaddr sysctl + * [VIDEO]: XVR500 and XVR2500 require FB=y + * [ATA]: Don't allow to enable this for SPARC64 without PCI. + * sh: Fix in_nmi symbol build error. + * sh: microdev: Fix compile warnings. + * sh: Fix SH4-202 clock fwk set_rate() mismatch. + * sh: voyagergx: Fix build warnings. + * sh: ioremap() through PMB needs asm/mmu.h. + * sh: Fix se73180 platform device registration. + * Input: ucb1x00 - do not access input_dev->private directly + * Input: reduce raciness when input handlers disconnect + * [PARISC] Fix kernel panic in check_ivt + * [SCSI] atari_NCR5380: update_timeout removal + * [SCSI] JAZZ ESP and SUN ESP need SPI_ATTRS + * [CIFS] fix mempool destroy done in wrong order in cifs error path + * SPI dynamic busid generation bugfix + * mtrr atomicity fix + * vanishing ioctl handler debugging + * libata: always use polling SETXFER + * Linux 2.6.22-rc4 + * [SPARC64]: Move topology init code into new file, sysfs.c + * [SPARC64]: Export basic cpu properties via sysfs. + * [SPARC64]: Fix service channel hypervisor function names. + * [SPARC64]: Provide mmu statistics via sysfs. + * [SPARC64]: Proper multi-core scheduling support. + * [SPARC64]: Make core and sibling groups equal on UltraSPARC-IV. + * [SPARC64]: Fix {mc,smt}_capable(). + * [SPARC64]: Fill in gaps in non-PCI dma_*() NOP implementation. + * [ATA]: Back out bogus (SPARC64 && !PCI) Kconfig depends. + * [VIDEO]: Fix section mismatch warning in promcon. + * [CIFS] whitespace cleanup + * [ARM] Fix 4417/1: Serial: Fix AMBA drivers locking + * [VIDEO] ffb: The pseudo_palette is only 16 elements long + * [ARM] pxa: fix pxa27x keyboard driver + * [VIDEO] sunxvr2500fb: Fix pseudo_palette array size + * [VIDEO] sunxvr500fb: Fix pseudo_palette array size + * [CIFS] whitespace cleanup part 2 + * [CIFS] Missing flag on negprot needed for some servers to force packet + signing + * [MIPS] Atlas, Malta, SEAD: Remove scroll from interrupt handler. + * [MIPS] Remove duplicate fpu enable hazard code. + * [MIPS] EMMA2RH: remove dead KGDB code + * [MIPS] RM300: Fix MMIO problems by marking the PCI INT ACK region busy + * [MIPS] Fix VGA corruption on RM300C + * [MIPS] Drop __ARCH_WANT_SYS_FADVISE64 + * [MIPS] Make dma_map_sg handle sg elements which are longer than one + page + * [MIPS] Fix some system calls with long long arguments + * [MIPS] Remove prototype for deleted function qemu_handle_int + * [MIPS] Fix some minor typoes in arch/mips/Kconfig. + * [MIPS] Fix warning by moving do_default_vi into CONFIG_CPU_MIPSR2_SRS + * [AGPGART] intel_agp: cleanup intel private data + * [AGPGART] intel_agp: use table for device probe + * [AGPGART] intel_agp: add support for 965GME/GLE + * [AGPGART] intel_agp: add support for 945GME + * [AGPGART] intel_agp: Add support for G33, Q33 and Q35 chipsets + * ocfs2: Fix masklog breakage + * ocfs2: Fix invalid assertion during write on 64k pages + * [POWERPC] pasemi: Fix iommu + 64K PAGE_SIZE bug + * [POWERPC] spufs: Refuse to load the module when not running on cell + * [POWERPC] spufs: Hook up spufs_release_mem + * [POWERPC] spufs: Fix gang destroy leaks + * [POWERPC] spufs: Free mm if spufs_fill_dir() failed + * [POWERPC] spufs: Synchronize pte invalidation vs ps close + * [POWERPC] spufs scheduler: Fix wakeup races + * [POWERPC] Fix pci_setup_phb_io_dynamic for pci_iomap + * [POWERPC] cbe_cpufreq: Limit frequency via cpufreq notifier chain + * [POWERPC] scc_sio: Fix link failure + * [POWERPC] Fix typo in booting-without-of-txt section numbering + * [POWERPC] spufs: Don't yield nosched context + * [POWERPC] Add table of contents to booting-without-of.txt + * [POWERPC] spufs: Fix error handling in spufs_fill_dir() + * mmc-atmel: remove linux/mmc/protocol.h dependencies + * au1xmmc: Replace C code with call to ARRAY_SIZE() macro. + * mmc: fix broken if clause + * mmc: don't call switch on old cards + * [POWERPC] Fix building of COFF zImages + * checkpatch.pl: should be executable + * Restrict clearing TIF_SIGPENDING + * mlx4_core: Fix CQ context layout + * mlx4_core: Initialize ctx_list and ctx_lock earlier + * mlx4_core: Free catastrophic error MSI-X interrupt with correct dev_id + * IB/mthca, mlx4_core: Fix typo in comment + * [BNX2]: Fix netdev watchdog on 5708. + * [BNX2]: Add missing wait in bnx2_init_5709_context(). + * [BNX2]: Enable DMA on 5709. + * [BNX2]: Fix occasional counter corruption on 5708. + * [BNX2]: Update version and reldate. + * [TCP]: Honour sk_bound_dev_if in tcp_v4_send_ack + * [IPV4]: Only panic if inetdev_init fails for loopback + * [IPV4]: Convert IPv4 devconf to an array + * [IPV4]: Add default config support after inetdev_init + * [IPV4]: Restore old behaviour of default config values + * [RFKILL]: Make rfkill->name const + * [TCP]: Use LIMIT_NETDEBUG in tcp_retransmit_timer(). + * [TCP] tcp_probe: Attach printf attribute properly to printl(). + * [NETLINK]: Mark netlink policies const + * [RTNETLINK]: ifindex 0 does not exist + * [NETFILTER]: nf_conntrack: fix helper module unload races + * [NETFILTER]: ip_tables: fix compat related crash + * [NETFILTER]: nf_conntrack_amanda: fix textsearch_prepare() error check + * [AF_UNIX]: Fix stream recvmsg() race. + * [UDP]: Revert 2-pass hashing changes. + * [NET]: Avoid duplicate netlink notification when changing link state + * [NET_SCHED]: Fix filter double free + * xfrm: Add security check before flushing SAD/SPD + * [SPARC64]: Fix 2 bugs in PCI Sabre bus scanning. + * [SPARC64]: Fix SBUS IRQ regression caused by PCI-E driver. + * frv: build fix + * enable interrupts in user path of page fault. + * RAMFS NOMMU: missed POSIX UID/GID inode attribute checking + * [SPARC64]: Include instead of . + * [SPARC64]: Handle PCI bridges without 'ranges' property. + * mlx4_core: Check firmware command interface revision + * mlx4_core: Don't set MTT address in dMPT entries with PA set + * IB/mlx4: Fix zeroing of rnr_retry value in ib_modify_qp() + * RDMA/cma: Fix initialization of next_port + * IB/mlx4: Make sure RQ allocation is always valid + * splice: move inode size check into generic_file_splice_read() + * splice: remove do_splice_direct() symbol export + * pipe: move pipe_inode_info structure decleration up before it's used + * splice: move balance_dirty_pages_ratelimited() outside of splice actor + * splice: __generic_file_splice_read: fix i_size_read() length checks + * splice: __generic_file_splice_read: fix read/truncate race + * V4L/DVB (5702): Fix Kconfig items to avoid linkedition errors + * V4L/DVB (5700): Saa7111: fix picture settings cache bug + * V4L/DVB (5699): Cinergyt2: fix file release handler + * V4L/DVB (5675): Move big PIO accesses from the interrupt handler to a + workhandler + * V4L/DVB (5716): Tda10086,tda826x: fix tuning, STR/SNR values + * V4L/DVB (5720): Usbvision: fix urb allocation and submits + * V4L/DVB (5730): Remove unused V4L2_CAP_VIDEO_OUTPUT_POS + * V4L/DVB (5732): Add ivtv CROPCAP support and fix ivtv S_CROP for video + output. + * V4L/DVB (5736): Add V4L2_FBUF_CAP/FLAG_LOCAL/GLOBAL_INV_ALPHA + * V4L/DVB (5673): Fix audio stuttering for saa711x/ivtv when in radio + mode. + * V4L/DVB (5761): Fix broken b2c2 dependency on non x86 architectures + * V4L/DVB (5751): Ivtv: fix ia64 printk format warnings. + * serverworks: remove crappy code + * serverworks: fix CSB6 tuning logic + * it821x: RAID mode fixes + * ide: HPA detect from resume + * ide: generic IDE PCI driver, add another device exception + * hpt366: disallow Ultra133 for HPT374 + * Add the PATA controller device ID to pci_ids.h for MCP73/MCP77. + * ide: Add the MCP73/77 support to PATA driver + * [CIFS] CIFS should honour umask + * update Documentation/driver-model/platform.txt + * Driver core: keep PHYSDEV for old struct class_device + * Driver core: kill unused code + * kobject: use the proper printk level for kobject error + * firmware: remove orphaned Email + * [IPV4]: Do not remove idev when addresses are cleared + * [NetLabel]: consolidate the struct socket/sock handling to just struct + sock + * [CIPSO]: Fix several unaligned kernel accesses in the CIPSO engine. + * USB: set default y for CONFIG_USB_DEVICE_CLASS + * usblp: Don't let suspend to kill ->used + * USB: usb gadgets avoid le{16,32}_to_cpup() + * USB: UNUSUAL_DEV: Sync up some reported devices from Ubuntu + * USB: cxacru: add Documentation file + * USB: cxacru: create sysfs attributes in atm_start instead of bind + * USB: cxacru: ignore error trying to start ADSL in atm_start + * USB: Fix up bogus bInterval values in endpoint descriptors + * OHCI: Fix machine check in ohci_hub_status_data + * update checkpatch.pl to version 0.03 + * m68knommu: fix ColdFire timer off by 1 + * nommu: report correct errno in message + * loop: preallocate eight loop devices + * document Acked-by: + * update feature-removal-schedule.txt to include deprecated functions + * mount -t tmpfs -o mpol=: check nodes online + * slab: fix alien cache handling + * potential parse error in ifdef part 3 + * SLUB: return ZERO_SIZE_PTR for kmalloc(0) + * uml: fix kernel stack size on x86_64 + * Documentation/atomic_ops.txt typo fix + * Move three functions that are only needed for CONFIG_MEMORY_HOTPLUG + * Char: stallion, don't fail with less than max panels + * Char: stallion, alloc tty before pci devices init + * Char: stallion, proper fail return values + * uml: get declaration of simple_strtoul + * isdn/diva: fix section mismatch + * sata_promise: use TF interface for polling NODATA commands + * rt-mutex: fix stale return value + * rt-mutex: fix chain walk early wakeup bug + * pi-futex: fix exit races and locking problems + * fix sysrq-m oops + * x86_64: oops_begin() fix + * reiserfs: mailing list has moved + * checkpatch: produce fewer lines of output + * MAINTAINERS: corrections + * hexdump: more output formatting + * update checkpatch.pl to version 0.04 + * Protect from multiple inclusion + * [IrDA]: Fix Rx/Tx path race. + * [IrDA]: f-timer reloading when sending rejected frames. + * ibmveth: Fix h_free_logical_lan error on pool resize + * ibmveth: Automatically enable larger rx buffer pools for larger mtu + * typo in via-velocity.c + * NetXen: Fix ping issue after reboot on Blades with 3.4.19 firmware + * NetXen: Fix compile failure seen on PPC architecture + * ehea: Fixed possible kernel panic on VLAN packet recv + * phylib: add RGMII-ID mode to the Marvell m88e1111 PHY to fix broken + ucc_geth + * net: fix typo in drivers/net/usb/Kconfig + * remove unused variable in pata_isapnp + * libata: disable NCQ for HITACHI HTS541680J9SA00/SB21C7EP + * libata: fix probe time irq printouts + * libata: print device model and firmware revision for ATAPI devices + * libata: fix hw_sata_spd_limit initialization + * ahci: Add MCP73/MCP77 support to AHCI driver + * libata-core/sff: Fix multiple assumptions about DMA + * libata: Correct abuse of language + * libata passthru: update protocol numbers + * libata passthru: support PIO multi commands + * libata passthru: map UDMA protocols + * libata passthru: always enforce correct DEV bit + * libata passthru: update cached device paramters + * i915: add new pciids for 945GME, 965GME/GLE + * drm/i915: Add support for the G33, Q33, and Q35 chipsets. + * drm: fix radeon setparam on 32/64 bit systems. + * [ARM] VFP: fix section mismatch error + * libata: force PIO on IOMEGA ZIP 250 ATAPI + * libata: limit post SRST nsect/lbal wait to ~100ms + * Blackfin arch: remove defconfig file + * Blackfin arch: DMA code minor naming convention fix + * Blackfin arch: spelling fixes + * Blackfin arch: fix bug ad1836 fails to build properly for BF533-EZKIT + * Blackfin arch: all symbols were offset by 4k, since we didn't have the + __text label. + * Blackfin arch: mark our memory init functions with __init so they get + freed after init + * Blackfin arch: implement a basic /proc/sram file for L1 allocation + visibility + * Blackfin arch: fixup Blackfin MAINTIANERS team member list + * Blackfin arch: scrub old console defines + * Blackfin arch: update defconfigs + * Blackfin arch: unify differences between our diff head.S files -- no + functional changes + * Blackfin arch: move more of our startup code to .init so it can be + freed once we are up and running + * Blackfin arch: add proper ENDPROC() + * Blackfin arch: try to split up functions like this into smaller units + according to LKML review + * Blackfin arch: fix spelling typo in output + * Blackfin arch: As Mike pointed out range goes form m..MAX_BLACKFIN_GPIO + -1 + * Blackfin arch: add missing gpio.h header to fix compiling in some pm + configurations + * Blackfin arch: add support for Alon Bar-Lev's dynamic kernel + command-line + * Blackfin arch: fix bug can not wakeup from sleep via push buttons + * Blackfin arch: make sure we initialize our L1 Data B section properly + based on the linked kernel + * Blackfin arch: redo our linker script a bit + * Blackfin arch: move HI/LO macros into blackfin.h and punt the rest of + macros.h as it includes VDSP macros we never use + * Blackfin serial driver: hook up our UARTs STP bit with userspaces + CMSPAR + * Blackfin serial driver: ignore framing and parity errors + * Blackfin serial driver: actually implement the break_ctl() function + * Blackfin serial driver: decouple PARODD and CMSPAR checking from PARENB + * Blackfin RTC drivers: update MAINTAINERS information + * Blackfin SPI driver: tweak spi cleanup function to match newer kernel + changes + * [ARM] 4442/1: OSIRIS: Fix CPLD register definitions + * [ARM] 4443/1: OSIRIS: Add watchdog device to machine devices + * [ARM] 4444/2: OSIRIS: CPLD suspend fix + * [ARM] 4445/1: ANUBIS: Fix CPLD registers + * Blackfin SPI driver: fix bug SPI DMA incomplete transmission + * Blackfin SMC91X ethernet supporting driver: SMC91C111 LEDs are note + drived in the kernel like in uboot + * [MIPS] Fix KMODE for the R3000 + * [MIPS] SMTC: Don't set and restore irqregs ptr from self_ipi. + * [MIPS] Always install the DSP exception handler. + * [MIPS] Atlas: Fix build. + * [MIPS] Wire up utimensat, signalfd, timerfd, eventfd + * [MIPS] SMTC: Fix warning. + * [MIPS] SMTC: Don't continue in set_vi_srs_handler on detected bad + arguments. + * [MIPS] SMTC: The MT ASE requires to initialize c0_pagemask and + c0_wired. + * [MIPS] SMTC: Fix build error caused by nonsense code. + * [MIPS] Fix modpost warnings by making start_secondary __cpuinit + * [MIPS] Fix IP27 build + * [MIPS] Fix smp barriers in test_and_{change,clear,set}_bit + * libertas: scan two channels per scan command + * libertas: rename wlan_association_worker + * libertas: a debug output was missing a newline + * libertas: fix removal of all debugfs files + * libertas: remove deprecated pm_register and associated code + * libertas: remove __FILE__ from debug output + * libertas: remove unused/superfluous definitions of DEV_NAME_LEN + * libertas: move vendor & product id's into if_usb.c + * libertas: make libertas_wlan_data_rates static + * libertas: fix scanning from associate path + * libertas: exclude non-used code when PROC_DEBUG is not set + * libertas: make debug configurable + * libertas: tune debug code + * libertas: single out mesh code + * libertas: change debug output of libertas_interrupt() + * libertas: get rid of libertas_sbi_get_priv() + * libertas: fix SSID output + * libertas: changed some occurences of kmalloc() + memset(&a,0,sz) to + kzalloc() + * libertas: move reset_device() code main.c to if_usb.c + * libertas: split wlan_add_card() + * libertas: fixed transmission flow control on the mesh interface + * libertas: fix error handling of card initialization + * libertas: added transmission failures to mesh statistics + * libertas: wakeup both mesh and normal wakeup when getting out of scan + * libertas: indirect all hardware access via hw_XXXX functions + * libertas: move contents of fw.h to decl.h + * libertas: split module into two (libertas.ko and usb8xxx.ko) + * libertas: fix RESET logic at unload time + * libertas: let DRV_NAME be overridable + * libertas: remove unused variables in wlan_dev_t + * libertas: fixed incorrect assigment of fcs errors to frag errors + * libertas: add URB debug info + * libertas: fixed kernel oops on module/card removal + * libertas: call SET_NETDEV_DEV from common code + * libertas: replace 'macaddress' with 'bssid' + * libertas: correctly unregister mesh netdev on error + * libertas: don't tear down netdev in libertas_activate_card + * libertas: version bump (321p0) and cmds update for new fw (5.220.10.p0) + * libertas: updated mesh commands for 5.220.9.p11 + * libertas: make scan result handling more flexible + * libertas: fix 'keep previous scan' behavior + * libertas: cleanup of fwt_list_route processing + * libertas: fix oops on rmmod + * libertas: move channel changing into association framework + * libertas: make association paths consistent + * libertas: use MAC_FMT and MAC_ARG where appropriate + * libertas: use compare_ether_addr() rather than memcmp() where + appropriate + * libertas: fix debug enter/leave prints for + libertas_execute_next_command + * libertas: correctly balance locking in libertas_process_rx_command + * libertas: correct error report paths for wlan_fwt_list_ioctl + * libertas: fix deadlock SIOCGIWSCAN handler + * libertas: fix default adhoc channel + * libertas: honor specific channel requests during association + * libertas: send SIOCGIWSCAN event after partial scans too + * libertas: debug print spacing fixes in assoc.c + * libertas: add more verbose debugging to libertas_cmd_80211_authenticate + * libertas: Make WPA work through supplicant handshake + * libertas: updated readme file + * libertas: make mac address configuration work with mesh interface too + * libertas: split wext for eth and msh + * libertas: support for mesh autostart on firmware 5.220.11 + * libertas: fix character set in README + * libertas: sparse fixes + * libertas: first pass at fixing up endianness issues + * libertas: More endianness fixes. + * libertas: more endianness fixes, in tx.c this time + * libertas: don't byte-swap firmware version number. It's a byte array. + * libertas: fix big-endian associate command. + * libertas: tweak association debug output + * libertas: remove structure WLAN_802_11_SSID and libertas_escape_essid + * libertas: remove WPA_SUPPLICANT structure + * libertas: reduce SSID and BSSID mixed-case abuse + * kbuild: fix sh64 section mismatch problems + * cfg80211: fix signed macaddress in sysfs + * mac80211: fix debugfs tx power reduction output + * mac80211: Don't stop tx queue on master device while scanning. + * Input: usbtouchscreen - fix fallout caused by move from drivers/usb + * Input: i8042 - add ASUS P65UP5 to the noloop list + * Input: i8042 - add ULI EV4873 to noloop list + * [PARISC] remove global_ack_eiem + * libertas: pull current channel from firmware on mesh autostart + * libertas: deauthenticate from AP in channel switch + * libertas: actually send mesh frames to mesh netdev + * libertas: convert libertas_mpp into anycast_mask + * [PPP_MPPE]: Fix "osize too small" check. + * NetXen: Fix link status messages + * myri10ge: limit the number of recoveries + * myri10ge: report when the link partner is running in Myrinet mode + * myri10ge: update driver version + * sysfs: store sysfs inode nrs in s_ino to avoid readdir oopses + * sysfs: fix condition check in sysfs_drop_dentry() + * sysfs: fix race condition around sd->s_dentry, take#2 + * [TCP]: Fix left_out setting during FRTO + * Input: move input-polldev to drivers/input + * [SPARC64]: Wire up cookie based sun4v interrupt registry. + * [SPARC64]: Fix IO/MEM space sizing for PCI. + * [SPARC64]: Really fix parport. + * [SPARC64]: Fix args to sun4v_ldc_revoke(). + * [TCP]: Set initial_ssthresh default to zero in Cubic and BIC. + * mmc-omap: fix sd response type 6 vs. 1 + * mmc: get back read-only switch function + * [SCTP]: Correctly set daddr for IPv6 sockets during peeloff + * [SCTP]: Allow unspecified port in sctp_bindx() + * [SCTP] Fix leak in sctp_getsockopt_local_addrs when copy_to_user fails + * [SCTP] Update pmtu handling to be similar to tcp + * [SCTP] Flag a pmtu change request + * [SCTP] Don't disable PMTU discovery when mtu is small + * [POWERPC] Fix per-cpu allocation on oldworld SMP powermacs + * [POWERPC] Fix console output getting dropped on platforms without + udbg_putc + * [AVR32] ratelimit segfault reporting rate + * [AVR32] gpio_*_cansleep() fix + * [AVR32] STK1000: Set SPI_MODE_3 in the ltv350qv board info + * [AVR32] Define ARCH_KMALLOC_MINALIGN to L1_CACHE_BYTES + * [MIPS] Malta: Fix for SOCitSC based Maltas + * [MIPS] Separate performance counter interrupts + * [MIPS] Fix builds where MSC01E_xxx is undefined. + * [TCP]: Add missing break to TCP option parsing code + * [IPV6] addrconf: Fix IPv6 on tuntap tunnels + * [AGPGART] intel_agp: fix device probe + * KVM: Prevent guest fpu state from leaking into the host + * splice: adjust balance_dirty_pages_ratelimited() call + * splice: fix leak of pages on short splice to pipe + * splice: only check do_wakeup in splice_to_pipe() for a real pipe + * [TCP]: Congestion control API RTT sampling fix + * [TCP]: Fix logic breakage due to DSACK separation + * [RXRPC] net/rxrpc/ar-connection.c: fix NULL dereference + * block: always requeue !fs requests at the front + * mm: Fix memory/cpu hotplug section mismatch and oops. + * Resume from RAM on HPC nx6325 broken + * ide-scsi: fix OOPS in idescsi_expiry() + * fix radeon setparam on 32/64 systems, harder. + * tty: restore locked ioctl file op + * i386: fix NMI watchdog not reserving its MSRs + * i386: use the right wrapper to disable the NMI watchdog + * SLUB slab validation: Alloc while interrupts are disabled must use + GFP_ATOMIC + * Restore shmid as inode# to fix /proc/pid/maps ABI breakage + * i386 mm: use pte_update() in ptep_test_and_clear_dirty() + * cpuset: zero malloc - fix for old cpusets + * toshiba_acpi: fix section mismatch in allyesconfig + * swsusp: Fix userland interface + * perfctr-watchdog: fix interchanged parameters to + release_{evntsel,perfctr}_nmi + * fuse: ->fs_flags fixlet + * md: fix two raid10 bugs + * md: fix bug in error handling during raid1 repair + * spi doc updates + * uml: remove PAGE_SIZE from libc code + * uml: kill x86_64 STACK_TOP_MAX + * random: fix output buffer folding + * Rework ptep_set_access_flags and fix sun4c + * SLUB: minimum alignment fixes + * udf: fix possible leakage of blocks + * hugetlb: fix get_policy for stacked shared memory files + * shm: fix the filename of hugetlb sysv shared memory + * Linux 2.6.22-rc5 + * [GFS2] flush the glock completely in inode_go_sync + * [DLM] fix a couple of races + * [GFS2] kernel changes to support new gfs2_grow command + * [GFS2] Kernel changes to support new gfs2_grow command (part 2) + * [GFS2] use zero_user_page + * [GFS2] Addendum patch 2 for gfs2_grow + * [GFS2] Reduce size of struct gdlm_lock + * [GFS2] Clean up inode number handling + * [GFS2] Quotas non-functional - fix bug + * [DLM] keep dlm from panicing when traversing rsb list in debugfs + * [DLM] block scand during recovery [1/6] + * [DLM] add lock timeouts and warnings [2/6] + * [DLM] dlm_device interface changes [3/6] + * [DLM] cancel in conversion deadlock [4/6] + * [DLM] fix new_lockspace error exit [5/6] + * [DLM] wait for config check during join [6/6] + * [DLM] fix compile breakage + * [GFS2] latest gfs2-nmw headers break userland build + * [DLM] Compile fix + * [DLM] timeout fixes + * [DLM] canceling deadlocked lock + * [DLM] dumping master locks + * [DLM] show default protocol + * [GFS2] Quotas non-functional - fix another bug + * [GFS2] Make the log reserved blocks depend on block size + * [DLM] fix socket shutdown + * [GFS2] fix jdata issues + * [GFS2] Fix sign problem in quota/statfs and cleanup _host structures + * [GFS2] Add nanosecond timestamp feature + * [DLM] fix reference counting + * [DLM] variable allocation + * [GFS2] Fix typo in rename of directories + * [GFS2] Fix bug in error path of inode + * [GFS2] Can't mount GFS2 file system on AoE device + * [GFS2] Recovery for lost unlinked inodes + * [GFS2] gfs2_lookupi() uninitialised var fix + * [GFS2] set plock owner in GETLK info + * [GFS2] return conflicts for GETLK + * [GFS2] Fix deallocation issues + * [DLM] don't require FS flag on all nodes + * [GFS2] Journaled file write/unstuff bug + * [GFS2] Remove bogus '\0' in rgrp.c + * [GFS2] Use zero_user_page() in stuffed_readpage() + * [GFS2] assertion failure after writing to journaled file, umount + * [GFS2] Simplify multiple glock aquisition + * [GFS2] Addendum to the journaled file/unmount patch + + -- Ben Collins Fri, 01 Jun 2007 12:15:58 -0400 + +linux-source-2.6.22 (2.6.22-6.13) gutsy; urgency=low + + [Ben Collins] + + * Bump ABI + * build/scripts: Remove all remnants of debconf from control scripts + * build/config: Re-enable paravirt/vmi + * build/config: Build ide-core as a module + * i386/x86_64: Allow disabling the putstr's from compressed boot wrapper + * PM: Do not require dev spew to get PM_DEBUG + * RTC: Ratelimit "lost interrupts" message + * UNUSUAL_DEV: Sync up some reported devices from Ubuntu + * build/d-i: Include ide-core in storage-core udeb, not that it's modular + * build/d-i: Make ide-modules depend on storage-code-modules + * build/config: Enable CONFIG_TIMER_STATS on x86_64. + * build/config: Disable CONFIG_RTC_DRV_CMOS + * build/config: Enable TIMER_STATS everywhere. + * build/config: Enable SND_AC97_POWER_SAVE + - LP: #116679 + * kmod: Improve call_usermodehelper_pipe to handle data close + * coredump: Convert to new call_usermodehelper_pipe symantics + * PPC: Only set hwif stuff when ide-core is non-modular + * PPC/MEDIABAY: Export some functions for modular ide-core/ppc-ide + + [Colin Watson] + + * Move isofs to storage-core-modules udeb from fs-core-modules. + + [Upstream Kernel Changes] + + * Input: logips2pp - add type 72 (PS/2 TrackMan Marble) + * Input: adbhid - do not access input_dev->private directly + * sh: Shut up compiler warnings in __do_page_fault(). + * sh: Fix up psw build rules for r7780rp. + * sh: Kill off pmb slab cache destructor. + * sh: landisk: rtc-rs5c313 support. + * sh: landisk: Header cleanups. + * input: hp680_ts compile fixes. + * [ARM] 4375/1: sharpsl_pm: Fix compile warnings + * [ARM] 4376/1: Selects GENERIC_GPIO for ARCH_IXP4XX in Kconfig + * [ARM] 4378/1: KS8695: Serial driver fix + * [ARM] Remove Integrator/CP SMP platform support + * [ARM] 4382/1: iop13xx: fix msi support + * [ARM] 4383/1: iop: fix usage of '__init' and 'inline' in iop files + * [ARM] 4384/1: S3C2412/13 SPI registers offset correction + * [ARM] Update ARM syscalls + * [ARM] Silence OMAP kernel configuration warning + * [ARM] gic: Fix gic cascade irq handling + * [ARM] integrator: fix pci_v3 compile error with DEBUG_LL + * [ARM] ARMv6: add CPU_HAS_ASID configuration + * [CRYPTO] padlock: Make CRYPTO_DEV_PADLOCK a tristate again + * [CRYPTO] tcrypt: Add missing error check + * eventfd use waitqueue lock ... + * timerfd use waitqueue lock ... + * [IA64] Fix bogus messages about system calls not implemented. + * [IA64] Yet another section mismatch warning + * Fix roundup_pow_of_two(1) + * Further update of the i386 boot documentation + * cciss: Fix pci_driver.shutdown while device is still active + * Linux v2.6.22-rc2 + * [CRYPTO] api: Read module pointer before freeing algorithm + * powerpc: Fix the MODALIAS generation in modpost for of devices + * kbuild: include limits.h in sumversion.c for PATH_MAX + * kconfig: search harder for curses library in check-lxdialog.sh + * kbuild: make modpost section warnings clearer + * kbuild: make better section mismatch reports on i386, arm and mips + * kbuild: add "Section mismatch" warning whitelist for powerpc + * all-archs: consolidate .text section definition in asm-generic + * all-archs: consolidate .data section definition in asm-generic + * kbuild: introduce __init_refok/__initdata_refok to supress section + mismatch warnings + * init/main: use __init_refok to fix section mismatch + * mm: fix section mismatch warnings + * mm/slab: fix section mismatch warning + * IB/core: Free umem when mm is already gone + * IB/ipath: Fix potential deadlock with multicast spinlocks + * IB/core: Add helpers for uncached GID and P_Key searches + * IB/core: Use start_port() and end_port() + * IPoIB: Handle P_Key table reordering + * IB/ehca: Return proper error code if register_mr fails + * IB/mthca: Fix use-after-free on device restart + * IB/mlx4: Fix check of max_qp_dest_rdma in modify QP + * IB/mthca: Set GRH:HopLimit when building MLX headers + * IB/mlx4: Set GRH:HopLimit when sending globally routed MADs + * IB/mthca: Fix RESET to ERROR transition + * IB/mlx4: Fix RESET to RESET and RESET to ERROR transitions + * mlx4_core: Fix array overrun in dump_dev_cap_flags() + * IB/mlx4: Fix check of opcode in mlx4_ib_post_send() + * [IPV6]: Add ip6_tunnel.h to headers_install + * [RFKILL]: Fix check for correct rfkill allocation + * [NET]: Fix net/core/skbuff.c gcc-3.2.3 compilation error + * [TCP] FRTO: Add missing ECN CWR sending to one of the responses + * [TCP] FRTO: Prevent state inconsistency in corner cases + * [IPSEC] pfkey: Load specific algorithm in pfkey_add rather than all + * [NETFILTER]: nf_conntrack: fix use-after-free in helper destroy + callback invocation + * [NETFILTER]: nf_conntrack_ipv4: fix incorrect #ifdef config name + * [IPV4]: icmp: fix crash with sysctl_icmp_errors_use_inbound_ifaddr + * [NET]: Fix race condition about network device name allocation. + * IB/mlx4: Pass send queue sizes from userspace to kernel + * [ARM] 4387/1: fix /proc/cpuinfo formatting for pre-ARM7 parts + * [ARM] 4388/1: no need for arm/mm mmap range checks for non-mmu + * [ARM] 4395/1: S3C24XX: add include of to relevant + machines + * [ARM] 4396/1: S3C2443: Add missing HCLK clocks + * [ARM] 4397/1: S3C2443: remove SDI0/1 IRQ ambiguity + * [ARM] 4398/1: S3C2443: Fix watchdog IRQ number + * [ARM] 4399/2: S3C2443: Fix SMDK2443 nand timings + * [ARM] 4400/1: S3C24XX: Add high-speed MMC device definition + * [ARM] at91_adc parenthesis balance + * [ARM] spelling fixes + * IB/mlx4: Check if SRQ is full when posting receive + * spelling fixes: arch/sh/ + * sh: revert addition of page fault notifiers + * sh: Wire up signalfd/timerfd/eventfd syscalls. + * sh: Fix up various compile warnings for SE boards. + * sh: Fix page size alignment in __copy_user_page(). + * sh: Disable psw support for R7785RP. + * fs: Kill sh dependency for binfmt_flat. + * sh: disable genrtc support. + * sh: sr.bl toggling around idle sleep. + * sh: Wire up kdump crash kernel exec in die(). + * sh: Fix clock multiplier on SH7722. + * sh: Fix dreamcast build for IRQ changes. + * [S390] cio: Update documentation. + * [S390] Wire up sys_utimensat. + * [S390] Wire up signald, timerfd and eventfd syscalls. + * [S390] Make use of kretprobe_assert. + * [S390] More verbose show_mem() like other architectures. + * Fix "fs: convert core functions to zero_user_page" + * Detach sched.h from mm.h + * Blackfin arch: Add Workaround for ANOMALY 05000257 + * Blackfin arch: add SPI MMC driver support on bf533-stamp, tested on + STAMP-BF533 + * Blackfin arch: ISP1761 doesn't work for USB flash disk + * Blackfin arch: fix a few random warnings + * Blackfin arch: Add configuration data for ISP176x on BF561 + * Blackfin arch: mark a bunch of local functions as static + * Blackfin arch: Fix reserved map after we changed PORT_H definition + * Blackfin arch: Move write to VR_CTL closer to IDLE + * Blackfin arch: DMA operation cleanup + * Blackfin arch: GPIO fix some defines + * Blackfin arch: fix trace output for FLAT binaries + * Blackfin arch: Fix bug using usb keyboard crashes kernel + * Blackfin arch: initial tepla-bf561 board support + * Blackfin arch: make sure we declare the revid functions as pure (since + they are) + * Blackfin arch: dont clear status register bits in SWRST so we can + actually use it + * Blackfin arch: finish removing p* volatile defines for MMRs + * Blackfin arch: move board specific setup out of common init code and + into the board specific init code + * Blackfin arch: issue reset via SWRST so we dont clobber the watchdog + state + * Blackfin arch: document why we have to touch the UART peripheral in our + boot up code + * Blackfin arch: dma_memcpy borken for > 64K + * Blackfin arch: dont clear the bit that tells coreb to start booting + * Blackfin arch: make sure we use local labels + * Blackfin arch: update blackfin header files to latest one in VDSP. + * Blackfin arch: cache SWRST value at bootup so other things like + watchdog can non-destructively query it + * Blackfin arch: fix signal handling bug + * Blackfin arch: Change NO_ACCESS_CHECK to ACCESS_CHECK + * Blackfin arch: add board default configs to blackfin arch + * Blackfin arch: update defconfig files + * Blackfin arch: update pm.c according to power management API change. + * Blackfin serial driver: fix overhead issue + * Blackfin serial driver: implement support for ignoring parity/break + errors + * Blackfin SPI: cleanup according to David Brownell's review + * x86_64: Update defconfig + * i386: Update defconfig + * x86_64: Support x86_64 in make buildtar + * i386: Fix K8/core2 oprofile on multiple CPUs + * x86_64: Support gcc 5 properly + * i386: Clear MCE flag on AMD K6 + * i386: Fix wrong CPU error message in early boot path + * i386: Enable CX8/PGE CPUID bits early on VIA C3 + * x86_64: early_print kernel console should send CRLF not LFCR + * x86_64: vsyscall time() fix + * i386: fix PGE mask + * LDM: Fix for Windows Vista dynamic disks + * IB/ipoib: Fix typos in error messages + * IPoIB/cm: Fix SRQ WR leak + * IB/cm: Improve local id allocation + * e1000: Don't enable polling in open() (was: e1000: assertion hit in + e1000_clean(), kernel 2.6.21.1) + * declance: Remove a dangling spin_unlock_irq() thingy + * Add constant for FCS/CRC length (frame check sequence) + * ahci: disable 64bit dma on sb600 + * libata: Add Seagate STT20000A to DMA blacklist. + * pata_hpt366: Enable bits are unreliable so don't use them + * ata_piix: clean up + * libata: Kiss post_set_mode goodbye + * libata: Trim trailing whitespace + * partitions/LDM: build fix + * Make 'headerscheck' stop immediately on an error + * Fix headers check fallout + * [POWERPC] Fix smp_call_function to be preempt-safe + * [POWERPC] Add missing pmc_type fields in cpu_table + * [POWERPC] Fix typo: MMCR0_PMA0 != MMCR0_PMAO + * [POWERPC] Fix powerpc vmlinux.lds.S + * [POWERPC] Fix warning in 32-bit builds with CONFIG_HIGHMEM + * libertas: skb dereferenced after netif_rx + * drivers/net/wireless/libertas/fw.c: fix use-before-check + * drivers/net/wireless/libertas/rx.c: fix use-after-free + * [IA64] Improve unwind checking. + * [IA64] Only unwind non-running tasks. + * [IA64] fix kmalloc(0) in arch/ia64/pci/pci.c + * i2c: Legacy i2c drivers shouldn't issue uevents + * i2c-tiny-usb: Fix truncated adapter name + * i2c-s3c2410: Fix build warning + * V4L/DVB (5639): Fix Kconfig dependencies for ivtv + * V4L/DVB (5640): Fix: em28xx shouldn't be selecting VIDEO_BUF + * V4L/DVB (5670): Adding new fields to v4l2_pix_format broke the ABI, + reverted that change + * V4L/DVB (5639a): Fix dst usage count + * V4L/DVB (5630): Dvb-core: Handle failures to create devices + * V4L/DVB (5680): Tuner-simple.c fix suport for SECAM with FI1216MF + * V4L/DVB (5690): Cafe_ccic: Properly power down the sensor + * V4L/DVB (5691): Ov7670: reset clkrc in rgb565 mode + * [IPSEC]: Fix warnings with casting int to pointer + * [AF_RXRPC]: AF_RXRPC depends on IPv4 + * [AF_RXRPC]: Make call state names available if CONFIG_PROC_FS=n + * [RTNETLINK]: Allow changing of subsets of netdevice flags in + rtnl_setlink + * [RTNETLINK]: Remove remains of wireless extensions over rtnetlink + * Input: iforce - fix force feedback not working + * Input: iforce - minor clean-ups + * Input: ALPS - force stream mode + * Input: ucb1400_ts - use sched_setscheduler() + * Input: ucb1x00-ts - remove commented out code + * Input: input-polldev - add module info + * Input: ads7846 - document that it handles tsc2046 too + * Input: ads7846 - SPI_CPHA mode bugfix + * USB: fix omninet memory leak found by coverity + * USB: remove useless check in mos7840 found by coverity + * usb-storage: ignore Sitecom WL-117 USB-WLAN + * USB: fix more ftdi-elan/u132-hcd #include lossage + * USB: handle more rndis_host oddities + * USB: remove usb DocBook warnings + * USB: address FIXME in usbnet w.r.t drivers claiming multiple interfaces + * EHCI: fix problem with BIOS handoff + * USB: more autosuspend timer stuff + * USB: remove unneeded WARN_ON + * USB: New device PID for ftdi_sio driver + * USB: set the correct Interrupt interval in usb_bulk_msg + * USB: fsl_usb2_udc: Fix UMTI_WIDE support and a compile warning + * USB: auerswald: fix file release handler + * USB: Remove duplicate IDs from option card driver + * USB: Deref URB after usbmon is done with it + * USB: remove short initial timeout for device descriptor fetch + * USB: don't try to kzalloc 0 bytes + * USB: Onetouch - switch to using input_dev->dev.parent + * USB: Fix debug output of ark3116 + * USB: usblp: Use correct DMA address in case of probe error + * USB: Fix USB OHCI Subvendor for Toshiba Portege 4000 + * USB: make the autosuspend workqueue thread freezable + * USB: handle errors in power/level attribute + * USB: fix ratelimit call semantics + * USB: ftdi_sio: Add USB Product Id for OpenDCC + * USB: ldusb bugfix + * USB: Add support for Sierra Wireless Aircard 595U + * USB: Add support for Olimex arm-usb-ocd JTAG interface serial port + * IB/mlx4: Don't allocate RQ doorbell if using SRQ + * [IA64] start_secondary() and smp_callin() should be __cpuinit + * add the IDE device ID for ATI SB700 + * ide/pci/serverworks.c: Fix corruption/timeouts with MegaIDE + * Add two missing chipsets to drivers/ide/ide-proc.c + * Match DMA blacklist entries between ide-dma.c and libata-core.c + * ide serverworks warning fixes + * freezer: close potential race between refrigerator and thaw_tasks + * freezer: fix vfork problem + * freezer: take kernel_execve into consideration + * freezer: fix kthread_create vs freezer theoretical race + * freezer: fix PF_NOFREEZE vs freezeable race + * freezer: move frozen_process() to kernel/power/process.c + * Ignore bogus ACPI info for offline CPUs + * SLUB Debug: Fix object size calculation + * fuse: fix mknod of regular file + * mpc52xx_psc_spi: fix it for CONFIG_PPC_MERGE + * spi doc update: describe clock mode bits + * NOHZ: Rate limit the local softirq pending warning output + * genhd: expose AN to user space + * genhd: send async notification on media change + * capability.h warning fix + * spi/spidev: check message size before copying + * uml: improve PTRACE_SYSEMU checking + * prohibit rcutorture from being compiled into the kernel + * Documentation: fix the explanation of Kconfig files + * Avoid zero size allocation in cache_k8_northbridges() + * recalc_sigpending_tsk fixes + * optimize compat_core_sys_select() by a using stack space for small fd + sets + * spi: potential memleak in spidev_ioctl + * fbdev: cleanup of sparc FB options + * pm2fb: RDAC_WR barriers clean up + * pm3fb: various fixes + * w100fb: fix compile warnings + * ps3fb: use FB_SYS_* instead of FB_CFB_* + * imxfb: remove ifdefs + * imxfb: fix memory hole + * Missing 'const' from reiserfs MIN_KEY declaration. + * uselib: add missing MNT_NOEXEC check + * fuse: generic_write_checks() for direct_io + * fuse: delete inode on drop + * fix unused setup_nr_node_ids + * SLUB Debug: fix check for super sized slabs (>512k 64bit, >256k 32bit) + * Char: cyclades, fix deadlock + * simplify cleanup_workqueue_thread() + * phantom: move to unlocked_ioctl + * Misc: phantom, take care of pci posting + * power: Fix sizeof(PAGE_SIZE) typo + * update dontdiff file + * signalfd: retrieve multiple signals with one read() call + * i2o: destroy event queue only when drv->event is set + * i2o: fix notifiers when max_drivers is configured + * i2o: eliminate a peculiar constraint on i2o_max_drivers + * i386, x86-64: show that CONFIG_HOTPLUG_CPU is required for suspend on + SMP + * md: avoid overflow in raid0 calculation with large components + * md: don't write more than is required of the last page of a bitmap + * md: fix bug with linear hot-add and elsewhere + * documentation: Documentation/initrd.txt + * HiSax: fix error checking for hisax_register()] + * applesmc - sensors patch missing from 2.6.22-rc2 + * Off by one in floppy.c + * eCryptfs: delay writing 0's after llseek until write + * document clocksources + * ehci-fsl: fix cache coherency problem on system with large memory + * Prevent going idle with softirq pending + * i386: fix early usage of atomic_add_return and local_add_return on real + i386 + * Documentation/memory-barriers.txt: various fixes + * omap_uwire: SPI_CPHA mode bugfix + * capifunc warning fixes + * drivers/isdn/hardware/eicon/message.c warning fixes + * i386 bigsmp: section mismatch fixes + * boot documentation: clarifications + * mmc: clean up unused parts of block driver + * mmc: mark unmaintained drivers + * mmc: Add maintainers for TI OMAP MMC interface + * mmc: add maintainer for iMX MMC interface + * mmc: add maintainer for ARM Primecell controller + * [CRYPTO] geode: Fix in-place operations and set key + * [Bluetooth] Always send HCI_Reset for Broadcom devices + * [Bluetooth] Fix L2CAP configuration parameter handling + * NFS: Avoid a deadlock situation on write + * NFS: Fix handful of compiler warnings in direct.c + * NFS: Fix nfs_direct_dirty_pages() + * Don't call a warnign a bug. It's a warning. + * [IA64] Fix using uninitialized data in _PDC setup + * [IA64] Cleanup acpi header to reuse the generic _PDC defines + * Documentation: Fix up docs still talking about i_sem + * [IA64] acpi_get_sysname() should be __init + * IB/mlx4: Initialize send queue entry ownership bits + * IB/ehca: Fix number of send WRs reported for new QP + * IPoIB/cm: Fix timeout check in ipoib_cm_dev_stop() + * IPoIB/cm: Drain cq in ipoib_cm_dev_stop() + * ucc_geth: Fix MODULE_DEVICE_TABLE() duplication + * ucc_geth:trivial fix + * asix.c - Add Belkin F5D5055 ids + * fix compiler warning in fixed.c + * remove unnecessary dependency on VIA velocity config + * meth driver renovation + * spidernet: skb used after netif_receive_skb + * chelsio parenthesis fix + * forcedeth: fix cpu irq mask + * [NET_SCHED]: Fix qdisc_restart return value when dequeue is empty + * [IPV6]: Ignore ipv6 events on non-IPV6 capable devices. + * [ATM]: Use mutex instead of binary semaphore in idt77252 driver. + * [DCCP]: Use menuconfig objects. + * [IPVS]: Use menuconfig objects. + * [SCTP]: Use menuconfig objects. + * [TIPC]: Use menuconfig objects. + * [ARCNET]: Use menuconfig objects. + * [TR]: Use menuconfig objects. + * [RTNETLINK]: Fix sending netlink message when replace route. + * [TIPC]: Fixed erroneous introduction of for_each_netdev + * [DCCP]: Fix build warning when debugging is disabled. + * [NET_SCHED]: sch_htb: fix event cache time calculation + * [NETFILTER]: nf_conntrack_ftp: fix newline sequence number update + * [NETFILTER]: nf_conntrack_ftp: fix newline sequence number calculation + * [NETFILTER]: nf_conntrack_h323: fix ASN.1 types + * [NETFILTER]: nf_conntrack_h323: fix get_h225_addr() for IPv6 address + access + * [NETFILTER]: nf_conntrack_h323: remove unnecessary process of + Information signal + * [NETFILTER]: nf_conntrack_h323: add missing T.120 address in OLCA + * [NETFILTER]: nf_nat_h323: call set_h225_addr instead of + set_h225_addr_hook + * [NET]: "wrong timeout value" in sk_wait_data() v2 + * hpt3x2n: Correct revision boundary + * pata_sis: Fix and clean up some timing setups + * ata_piix: add short 40c quirk for Acer Aspire 2030, take #2 + * libata: don't consider 0xff as port empty if SStatus is available + * libata: -ENODEV during prereset isn't an error + * pata_via: Handle laptops via DMI + * [CASSINI]: Check pci_set_mwi() return value. + * [XFRM]: Allow packet drops during larval state resolution. + * [libata] sata_promise: fix flags typo + * [libata] sata_mv: add TODO list + * Fix build failure for drivers/ata/pata_scc.c + * libata: sata_sis fixes + * [libata] Fix decoding of 6-byte commands + * [libata] sata_via, pata_via: Add PCI IDs. + * ocfs2: trylock in ocfs2_readpage() + * ocfs2: unmap_mapping_range() in ocfs2_truncate() + * ocfs2: use zero_user_page + * ocfs2: fix inode leak + * ocfs2: use generic_segment_checks + * pata: Trivia + * pata_hpt37x: Further improvements based on the IDE updates and vendor + drivers + * fix compat console unimap regression + * Linux 2.6.22-rc3 + + -- Ben Collins Thu, 31 May 2007 12:35:44 -0400 + +linux-source-2.6.22 (2.6.22-5.11) gutsy; urgency=low + + [Ben Collins] + + * build/headers/ppc: Correct asm-ppc -> asm for arch symlink + * build/headers/ia64: Fix find command line to correctly pull in *.lds + files + * Bump ABI + + [Upstream Kernel Changes] + + * [IA64] spelling fixes: arch/ia64/ + * [AVR32] Remove bogus comment in arch/avr32/kernel/irq.c + * [AVR32] optimize pagefault path + * [AVR32] Wire up signalfd, timerfd and eventfd + * [IA64] wire up {signal,timer,event}fd syscalls + * [IA64] kdump on INIT needs multi-nodes sync-up (v.2) + * [IA64] s/scalibility/scalability/ + * [AVR32] Implement platform hooks for atmel_lcdfb driver + * [IA64] Fix section conflict of ia64_mlogbuf_finish + * [SPARC64]: Add hypervisor API negotiation and fix console bugs. + * pata_scc had been missed by ata_std_prereset() switch + * libata: separate out ata_dev_reread_id() + * libata: during revalidation, check n_sectors after device is configured + * libata-acpi: add ATA_FLAG_ACPI_SATA port flag + * libata: fix shutdown warning message printing + * libata: track spindown status and skip spindown_compat if possible + * [ALSA] usb-audio: another Logitech QuickCam ID + * [ALSA] hda-codec - Make the mixer capability check more robust + * [ALSA] ASoC AC97 static GPL symbol fix + * [ALSA] ASoC AC97 device reg bugfix + * [ALSA] hda-codec - Fix ALC882/861VD codec support on some laptops + * [ALSA] version 1.0.14rc4 + * [ALSA] Fix probe of non-PnP ISA devices + * [ALSA] Include quirks from Ubuntu Dapper/Edgy/Feisty + * [ALSA] usbaudio - Coping with short replies in usbmixer + * [IA64] optimize pagefaults a little + * Fix ACPI suspend / device suspend ordering problem + * AFS: write back dirty data on unmount + * SLUB: It is legit to allocate a slab of the maximum permitted size + * slub: don't confuse ctor and dtor + * AFS: Fix afs_prepare_write() + * spi: fix spidev for >sizeof(long)/32 devices + * parport_pc needs dma-mapping.h + * Fix: find_or_create_page skips cpuset memory spreading. + * slob: implement RCU freeing + * Slab allocators: Drop support for destructors + * SLUB: Remove depends on EXPERIMENTAL and !ARCH_USES_SLAB_PAGE_STRUCT + * SLAB: Move two remaining SLAB specific definitions to slab_def.h + * SLUB: Define functions for cpu slab handling instead of using + PageActive + * slab: warn on zero-length allocations + * slub: fix handling of oversized slabs + * SLUB: slabinfo fixes + * SLUB: Do our own flags based on PG_active and PG_error + * Remove SLAB_CTOR_CONSTRUCTOR + * SLUB: Simplify debug code + * Slab allocators: define common size limitations + * acpi: fix potential call to a freed memory section. + * i386/x86-64: fix section mismatch + * Make __vunmap static + * simplify compat_sys_timerfd + * Let smp_call_function_single return -EBUSY on UP + * Refine SCREEN_INFO sanity check for vgacon initialization + * make freezeable workqueues singlethread + * parport: mailing list is subscribers-only + * docbook: make kernel-locking table readable + * gpio interface loosens call restrictions + * rtc-omap build fix + * rtc kconfig clarification + * icom: add new sub-device-id to support new adapter + * make sysctl/kernel/core_pattern and fs/exec.c agree on maximum core + filename size + * ecryptfs: use zero_user_page + * i386: don't check_pgt_cache in flush_tlb_mm + * circular locking dependency found in QUOTA OFF + * swsusp: fix sysfs interface + * Fix page allocation flags in grow_dev_page() + * mm: more rmap checking + * NS16550A: Restore HS settings in EXCR2 on resume + * Fix incorrect prototype for ipxrtr_route_packet() + * sky2: remove Gigabyte 88e8056 restriction + * sky2: PHY register settings + * sky2: keep track of receive alloc failures + * sky2: MIB counter overflow handling + * sky2: remove dual port workaround + * sky2: memory barriers change + * small netdevices.txt fix + * ibm_emac: fix section mismatch warnings + * ibm_emac: improved PHY support + * ibm_emac: fix link speed detection change + * gianfar: Add I/O barriers when touching buffer descriptor ownership. + * spidernet: node-aware skbuff allocation + * NetXen: Fix NetXen driver ping on system-p + * ixgb: don't print error if pci_enable_msi() fails, cleanup minor leak + * e1000: Fix msi enable leak on error, don't print error message, cleanup + * drivers/ata: remove the wildcard from sata_nv driver + * sata_nv: fix fallout of devres conversion + * libata: remove libata.spindown_compat + * sata_via: pcim_iomap_regions() conversion missed BAR5 + + -- Ben Collins Thu, 17 May 2007 14:54:16 -0400 + +linux-source-2.6.22 (2.6.22-4.10) gutsy; urgency=low + + [Ben Collins] + + * Bump ABI + * build/config: Disable obsolete tsdev driver. + * build: Add tsdev to list of modules intentionally removed. + * build/headers: Include *.lds files (fixes ia64 headers). + * build/headers: Add arch/powerpc/include/asm symlink to get all headers. + * build/module-check: Fix logic for printed messages. + * build/maintainer: Use linux instead of upstream-linux for local diffs + * build/config: Enable SLUB slab allocator (vs. SLAB). + * build/config: Disable orinoco_nortel, use prefered hostap_plx + * build/config: Disable ir-usb in favor of irda-usb + * build/config: Disable sis5513(ide) in favor of pata_sis(libata) + * build/config: Disable piix(ide) in favour of pata_oldpiix, ata_piix and + pata_mpiix (libata) + * build/config: Disable zaurus driver in favour of the cdc_ether driver + * build/abi: Note a few modules intentionally removed. + * build/config: Disable mxb and dpc7146 driver in favour of hexium_orion + * build/config: Disable usbtest driver (for development only) + * build/config: Disable keyspan driver in favour of keyspan_pda + * build/abi: Add mxb and usbtest to list of removed modules. + + [Upstream Kernel Changes] + + * net: Trivial MLX4_DEBUG dependency fix. + * mlx4_core: Remove unused doorbell_lock + * [CPUFREQ] Support rev H AMD64s in powernow-k8 + * [CPUFREQ] powernow-k7: fix MHz rounding issue with perflib + * [AGPGART] Fix wrong ID in via-agp.c + * sh64: ROUND_UP macro cleanup in arch/sh64/kernel/pci_sh5.c + * spelling fixes: arch/sh64/ + * sh64: Wire up many new syscalls. + * sh64: Fixups for the irq_regs changes. + * sh64: dma-mapping updates. + * sh64: ppoll/pselect6() and restartable syscalls. + * sh64: Fixup sh-sci build. + * sh64: Update cayman defconfig. + * sh64: generic quicklist support. + * sh64: Add .gitignore entry for syscalltab. + * IB/mlx4: Fix uninitialized spinlock for 32-bit archs + * IB/ipath: Shadow the gpio_mask register + * IB/ehca: Serialize hypervisor calls in ehca_register_mr() + * IB/ehca: Correctly set GRH mask bit in ehca_modify_qp() + * IB/ehca: Fix AQP0/1 QP number + * IB/ehca: Remove _irqsave, move #ifdef + * IB/ehca: Beautify sysfs attribute code and fix compiler warnings + * IB/ehca: Disable scaling code by default, bump version number + * RDMA/cma: Simplify device removal handling code + * RDMA/cma: Fix synchronization with device removal in cma_iw_handler + * RDMA/cma: Add check to validate that cm_id is bound to a device + * IB/mthca: Fix posting >255 recv WRs for Tavor + * IB/mthca: Set cleaned CQEs back to HW ownership when cleaning CQ + * IPoIB/cm: Optimize stale connection detection + * [CPUFREQ] Correct revision mask for powernow-k8 + * fix epoll single pass code and add wait-exclusive flag + * epoll locks changes and cleanups + * epoll: fix some comments + * epoll: move kfree inside ep_free + * nommu: add ioremap_page_range() + * h8300 atomic.h update + * alpha: fix hard_smp_processor_id compile error + * m68k: implement __clear_user() + * Remove cpu hotplug defines for __INIT & __INITDATA + * i386: move common parts of smp into their own file + * i386: fix voyager build + * SLUB: CONFIG_LARGE_ALLOCS must consider MAX_ORDER limit + * ll_rw_blk: fix gcc 4.2 warning on current_io_context() + * pasemi_mac: Fix register defines + * pasemi_mac: Interrupt ack fixes + * pasemi_mac: Terminate PCI ID list + * pasemi_mac: Fix local-mac-address parsing + * smc911x: fix compilation breakage + * ucc_geth: eliminate max-speed, change interface-type to + phy-connection-type + * pdc202xx_old: rewrite mode programming code (v2) + * serverworks: PIO mode setup fixes + * sis5513: PIO mode setup fixes + * alim15x3: use ide_tune_dma() + * pdc202xx_new: use ide_tune_dma() + * ide: always disable DMA before tuning it + * cs5530/sc1200: add ->udma_filter methods + * ide: use ide_tune_dma() part #2 + * cs5530/sc1200: DMA support cleanup + * cs5530/sc1200: add ->speedproc support + * sl82c105: add speedproc() method and MWDMA0/1 support + * ide: remove ide_dma_enable() + * ide: add missing validity checks for identify words 62 and 63 + * ide: remove ide_use_dma() + * sl82c105: Switch to ref counting API + * Use menuconfig objects: IDE + * x86: Fix discontigmem + non-HIGHMEM compile + * missing mm.h in fw-ohci + * missing dependencies for USB drivers in input + * missing includes in mlx4 + * em28xx and ivtv should depend on PCI + * rpadlpar breakage - fallout of struct subsystem removal + * m32r: __xchg() should be always_inline + * audit_match_signal() and friends are used only if CONFIG_AUDITSYSCALL + is set + * fix uml-x86_64 + * arm: walk_stacktrace() needs to be exported + + -- Ben Collins Tue, 15 May 2007 10:13:23 -0400 + +linux-source-2.6.22 (2.6.22-3.9) gutsy; urgency=low + + * Fixup firmware-modules -> efi-modules in exclude files. + + [Ben Collins] + + * build/config: Enable CONFIG_TIMER_STATS + * build/config: Disable CONFIG_IRQBALANCE, handled in userspace now + * build: Update modules that have been deprecated + * sparc64: Get some drivers compiling, till patches get upstream. + * powerpc: Add 64-bit cmp op for 32-bit. + * build/config: Disable apm_emu, pasemi_mac and cbe_cpufreq on ppc64 + * build/d-i(cjwatson): Rename firmware-modules to efi-modules + + -- Ben Collins Fri, 11 May 2007 09:38:50 +0200 + +linux-source-2.6.22 (2.6.22-2.7) gutsy; urgency=low + + [Changes for 2.7] + + * Added some more modules going missing to ignore. + * Disable ADB_PMU_LED on powerpc64. FTBFS. + + [Ben Collins] + + * XXX: Well, xen and rt got disabled in this upload. Hopefully things will + get working again soon. + + * build: Add check for nrcpus on buildd's for CONCURRENCY_LEVEL + * build: No longer provide ndiswrapper or ivtv modules (l-u-m does). + * build/d-i: Remove firmware lists, since we no longer supply those udebs + * build: Remove more firmware stuff + * build/control: Build-dep on coreutils + * Update configuration files + * build/custom: Updated xen/rt patches and configs. + * build: Make sure to use /bin/bash for headers_install + * build: Add SHELL=/bin/bash to headers_install + * Update configuration files + * Bump ABI + * Update module lists to match module name changes and merges. + * build/rt: Trimmed down real-time patch from Alessio Igor Bogani. + * Update configuration files + * Update configuration files + * build/rt: Fix typo in diff + * Update configuration files + * build: make explicit binary-headers target + * Update configuration files + * build/control-scripts: Remove debconf from pre-rm script + * build/ia64: Compress and use vmlinuz for target install + * build/config: Diable OSS i810_audio driver (Alsa driver prefered) + * build/config: Disable OSS cs4232 driver (Alsa prefered) + * build/config: Disable OSS via82xx driver (Alsa prefered) + * build/config: Disable OSS trident driver (Alsa prefered) + * build/config: Disable OSS Sound Blaster driver (Alsa prefered) + * build/config: Disable IDE generic, ata_generic prefered + * build/config: Disable siimage, pata_sil680 prefered + * build/module-check: More robust module checking + * build: Call module-check with perl, not $SHELL + * Update configuration files + * build: Fixup calling conventions of module-check + * build: Add modules.ignore from 1.3 revision + * build/config: Disable obsolete MOXA_SMARTIO in favor of new driver. + * build/config: Disable orinoco_cs in favor of hostap_cs + * build/config: Disable orinoco_pci in favor of hostap_pci + * build/config: Disable orinoco_{plx,tmd} in favor of hostap_plx + * build/config: Disable sk98lin in favor of skge + * build: Add more modules intentionally removed since 1.3 + + -- Ben Collins Fri, 27 Apr 2007 09:04:29 -0400 + +linux-source-2.6.22 (2.6.22-1.3) gutsy; urgency=low + + [Ben Collins] + + * build: Only use bzip2 for linux-image, and pre-depend on proper dpkg + + [2.6.22-1.2] + + [Ben Collins] + + * build: Add build-arch target. FTBFS + + [2.6.22-1.1] + + [Ben Collins] + + * debian: New build system, from scratch + * debian: Rename place holder so debian/stamps/ sticks around + * debian: Create stamp-flavours at start of build (for build scripts) + * debian/abi: Add revision 0.0 bootstrap module list. + * debian: Fix backwards logic in module/abi checkers. + * debian: Add arch= to vars.* files + * Update configuration files + * build: Added control scripts for images + * build/config: Disable CONFIG_PARAVIRT for now + * build/config: Enable CONFIG_FB_VESA + * build: Take CONCURRENCY_LEVEL from env if it exists. + * build: Do not print SHAs by default for changelog + * build/config(i386): Disable NO_HZ on all but generic + * build: Implement udeb rules + * build/d-i: Remove speakup-modules udeb + * build/udebs: Fix a couple trivial errors in the build. + * build/config: Disable CONFIG_FB_IMSTT on powerpc64-smp (no NVRAM) + * build/config: Disable some modules for ppc64 that don't use DMA API + * build/config: Yet another module to disable on ppc64 + * build/tests: New test infrastructure + * build: Special kernel build infrastructure + * build: Fix typo from last commit + * build/custom: Move custom files for each flavour into subdir. + * build/config: Disable some drivers on sparc that don't support DMA API + * build/sparc: Add new compress_file config, and use it for sparc + * build: Fix typo in compress_file commit. + * build/schedcfs: Update to v6 of the patch. + * build: Fix control file generation for custom images + * build: Correct message in link-headers + * build: 2.6.21 is released, force our SUBLEVEL to .22 + * build/vars: kvm API is at 4, provide that. + * build/custom: Allow custom builds to override things like build_image + * build/custom: Fix type causing custom rules not to be included. + * build/custom: Hello Xen 3.0.5 + * build/custom: Remove sched-cfs. Superseded in use by rt. + * build/custom: Add 2.6.21-rt1 patch for -rt custom flavour + * build/link-headers: Make sure to copy new files for custom + + -- Ben Collins Fri, 27 Apr 2007 08:29:00 -0400 --- linux-2.6.27.orig/debian/control.stub +++ linux-2.6.27/debian/control.stub @@ -0,0 +1,204 @@ +Source: linux +Section: devel +Priority: optional +Maintainer: Ubuntu Kernel Team +Standards-Version: 3.6.1 +Build-Depends: debhelper (>= 3), module-init-tools, kernel-wedge (>= 2.24ubuntu1), makedumpfile +Build-Depends-Indep: xmlto, docbook-utils, gs, transfig, bzip2, sharutils +Vcs-Git: http://kernel.ubuntu.com/git-repos/ubuntu/ubuntu-intrepid.git + +Package: linux-source-2.6.27 +Architecture: all +Section: devel +Priority: optional +Provides: linux-source, linux-source-2.6 +Depends: binutils, bzip2, coreutils | fileutils (>= 4.0) +Recommends: libc-dev, gcc, make +Suggests: libncurses-dev | ncurses-dev, kernel-package, libqt3-dev +Description: Linux kernel source for version 2.6.27 with Ubuntu patches + This package provides the source code for the Linux kernel version + 2.6.27. + . + This package is mainly meant for other packages to use, in order to build + custom flavours. + . + If you wish to use this package to create a custom Linux kernel, then it + is suggested that you investigate the package kernel-package, which has + been designed to ease the task of creating kernel image packages. + . + If you are simply trying to build third-party modules for your kernel, + you do not want this package. Install the appropriate linux-headers + package instead. + +Package: linux-doc-2.6.27 +Architecture: all +Section: doc +Priority: optional +Provides: linux-doc-2.6 +Conflicts: linux-doc-2.6 +Replaces: linux-doc-2.6 +Depends: coreutils | fileutils (>= 4.0) +Description: Linux kernel specific documentation for version 2.6.27 + This package provides the various readme's in the 2.6.27 kernel + Documentation/ subdirectory: these typically contain kernel-specific + installation notes for some drivers for example. See + /usr/share/doc/linux-doc-2.6.27/Documentation/00-INDEX for a list of what + is contained in each file. Please read the Changes file, as it contains + information about the problems, which may result by upgrading your + kernel. + +Package: linux-headers-2.6.27-14 +Architecture: all +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0) +Provides: linux-headers, linux-headers-2.6 +Description: Header files related to Linux kernel version 2.6.27 + This package provides kernel header files for version 2.6.27, for sites + that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.27-14/debian.README.gz for details + +Package: linux-libc-dev +Architecture: i386 amd64 +Conflicts: libc6-dev (<< 2.3.2.ds1-6), libc6.1-dev (<< 2.3.2.ds1-6), dvb-dev (<< 1.0.1-6), amd64-libs-dev (<= 1.1), linux-kernel-headers +Replaces: libc6-dev (<< 2.3.2.ds1-6), libc6.1-dev (<< 2.3.2.ds1-6), dvb-dev (<< 1.0.1-6), linux-kernel-headers +Provides: linux-kernel-headers +Description: Linux Kernel Headers for development + This package provides headers from the Linux kernel. These headers + are used by the installed headers for GNU glibc and other system + libraries. They are NOT meant to be used to build third-party modules for + your kernel. Use linux-headers-* packages for that. + +Package: linux-image-2.6.27-14-generic +Architecture: i386 amd64 +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, kvm-api-4, redhat-cluster-modules, ivtv-modules, ndiswrapper-modules-1.9 +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: lilo (>= 19.1) | grub +Suggests: fdutils, linux-doc-2.6.27 | linux-source-2.6.27 +Description: Linux kernel image for version 2.6.27 on x86/x86_64 + This package contains the Linux kernel image for version 2.6.27 on + x86/x86_64. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Generic processors. + . + Geared toward desktop systems. + . + You likely do not want to install this package directly. Instead, install + the linux-generic meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.27-14-generic +Architecture: i386 amd64 +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.27-14, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.27 on x86/x86_64 + This package provides kernel header files for version 2.6.27 on + x86/x86_64. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.27-14/debian.README.gz for details. + +Package: linux-image-debug-2.6.27-14-generic +Architecture: i386 amd64 +Section: devel +Priority: optional +Provides: linux-debug +Description: Linux kernel debug image for version 2.6.27 on x86/x86_64 + This package provides a kernel debug image for version 2.6.27 on + x86/x86_64. + . + This is for sites that wish to debug the kernel. + . + The kernel image contained in this package is NOT meant to boot from. It + is uncompressed, and unstripped. This package also includes the + unstripped modules. + +Package: linux-image-2.6.27-14-server +Architecture: i386 amd64 +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, redhat-cluster-modules, kvm-api-4, ivtv-modules, ndiswrapper-modules-1.9 +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: lilo (>= 19.1) | grub +Suggests: fdutils, linux-doc-2.6.27 | linux-source-2.6.27 +Description: Linux kernel image for version 2.6.27 on x86/x86_64 + This package contains the Linux kernel image for version 2.6.27 on + x86/x86_64. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Server processors. + . + Geared toward server systems. + . + You likely do not want to install this package directly. Instead, install + the linux-server meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-2.6.27-14-server +Architecture: i386 amd64 +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-2.6.27-14, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version 2.6.27 on x86/x86_64 + This package provides kernel header files for version 2.6.27 on + x86/x86_64. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-2.6.27-14/debian.README.gz for details. + +Package: linux-image-debug-2.6.27-14-server +Architecture: i386 amd64 +Section: devel +Priority: optional +Provides: linux-debug +Description: Linux kernel debug image for version 2.6.27 on x86/x86_64 + This package provides a kernel debug image for version 2.6.27 on + x86/x86_64. + . + This is for sites that wish to debug the kernel. + . + The kernel image contained in this package is NOT meant to boot from. It + is uncompressed, and unstripped. This package also includes the + unstripped modules. + +Package: linux-image-2.6.27-14-virtual +Architecture: i386 amd64 +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, redhat-cluster-modules +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1), linux-image-2.6.27-14-server +Recommends: lilo (>= 19.1) | grub +Suggests: fdutils, linux-doc-2.6.27 | linux-source-2.6.27 +Description: Linux kernel image for version 2.6.27 on x86/x86_64 + This package contains the Linux kernel image for version 2.6.27 on + x86/x86_64. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports Virtual processors. + . + Geared toward virtual machine guests. + . + You likely do not want to install this package directly. Instead, install + the linux-virtual meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. --- linux-2.6.27.orig/debian/NOTES +++ linux-2.6.27/debian/NOTES @@ -0,0 +1,4 @@ +eSCO patch removed. Replaced upstream with a disable_esco module parm. +airprime: Module gone, use option driver instead +AppArmor: Patch is all there and ported. Ooops when enabled, so default + off (still can be enabled apparmor=1) --- linux-2.6.27.orig/debian/changelog +++ linux-2.6.27/debian/changelog @@ -0,0 +1,4162 @@ +linux (2.6.27-14.40) intrepid-proposed; urgency=low + + [ Amit Kucheria ] + + * Disable DEVKMEM for all archs on Intrepid + - LP: #354221 + * SAUCE: Quirk for BT USB device on MacbookPro to be reset before use + - LP: #332443 + + [ Andy Isaacson ] + + * LIRC_PVR150: depends on VIDEO_IVTV + - LP: #341477 + * SAUCE: FSAM7400: select CHECK_SIGNATURE + - LP: #341712 + + [ Andy Whitcroft ] + + * SAUCE: hotkey quirks for various Zepto Znote and Fujitsu Amilo laptops + - LP: #330259 + * SAUCE: unusual devs: add an entry for the ScanLogic SL11R-IDE 0.78 + - LP: #336189 + + [ Anton Veretenenko ] + + * SAUCE: sony-laptop: add support for Sony Vaio FW series function/media + keys + - LP: #307592 + + [ Ayaz Abdulla ] + + * SAUCE: forcedeth: msi interrupt fix + - LP: #288281 + + [ Chuck Short ] + + * SAUCE: [USB] Unusual Device support for Gold MP3 Player Energy + - LP: #125250 + + [ Ike Panhc ] + + * squashfs: correct misspelling + - LP: #322306 + * SAUCE: Fixing symbol name in HECI module + - LP: #336549 + * Copy header files for various kernel media driver + - LP: #322732 + + [ Stefan Bader ] + + * SAUCE: vgacon: Return the upper half of 512 character fonts + - LP: #355057 + * SAUCE: input: Blacklist digitizers from joydev.c + - LP: #300143 + + [ Upstream Kernel Changes ] + + * libata: make sure port is thawed when skipping resets + - LP: #269652 + * x86-64: fix int $0x80 -ENOSYS return + - LP: #339743 + * rt2x00: Fix race conditions in flag handling + - LP: #258985 + * USB: cdc-acm: Add another conexant modem to the quirks + - LP: #323829 + * Bluetooth: Add fine grained mem_flags usage to btusb driver + - LP: #268502 + * Bluetooth: Handle bulk URBs in btusb driver from notify callback + - LP: #268502 + * Bluetooth: Submit bulk URBs along with interrupt URBs + - LP: #268502 + * hwmon: (abituguru3) Match partial DMI board name strings + - LP: #298798 + * x86: mtrr: don't modify RdDram/WrDram bits of fixed MTRRs + - LP: #292619 + * sis190: add identifier for Atheros AR8021 PHY + - LP: #247889 + * ath9k: implement IO serialization + - LP: #373034 + * ath9k: AR9280 PCI devices must serialize IO as well + - LP: #373034 + * acer-wmi: fix regression in backlight detection + - LP: #333386 + + + -- Stefan Bader Sat, 25 Jul 2009 01:47:16 +0200 + +linux (2.6.27-14.39) intrepid-security; urgency=low + + [ Upstream Kernel Changes ] + + * Make sock_sendpage() use kernel_sendpage() + - CVE-2009-2692 + + -- Stefan Bader Mon, 17 Aug 2009 20:22:51 +0200 + +linux (2.6.27-14.37) intrepid-security; urgency=low + + [ Upstream Kernel Changes ] + + * Add '-fno-delete-null-pointer-checks' to gcc CFLAGS + - LP: #403647 + * personality: fix PER_CLEAR_ON_SETID + - CVE-2009-1895 + * KVM: x86: check for cr3 validity in ioctl_set_sregs + - CVE-2009-2287 + * r8169: fix crash when large packets are received + - CVE-2009-1389 + * eCryptfs: Check Tag 11 literal data buffer size + - CVE-2009-2406 + * eCryptfs: parse_tag_3_packet check tag 3 packet encrypted key size + - CVE-2009-2407 + + -- Stefan Bader Thu, 23 Jul 2009 15:46:29 +0200 + +linux (2.6.27-14.35) intrepid-security; urgency=low + + [ Upstream Kernel Changes ] + + * nfsd: nfsd should drop CAP_MKNOD for non-root + - CVE-2009-1072 + * add some long-missing capabilities to fs_mask + - CVE-2009-1072 + * KVM: VMX: Don't allow uninhibited access to EFER on i386 + - CVE-2009-1242 + * exit_notify: kill the wrong capable(CAP_KILL) check + - CVE-2009-1337 + * e1000: add missing length check to e1000 receive routine + - CVE-2009-1385 + * Fix memory overwrite when saving nativeFileSystem field during mount + - CVE-2009-1439 + * cifs: Increase size of tmp_buf in cifs_readdir to avoid potential + overflows + - CVE-2009-1633 + * cifs: Rename cifs_strncpy_to_host and fix buffer size + - CVE-2009-1633 + * cifs: fix unicode string area word alignment in session setup + - CVE-2009-1633 + * cifs: Fix incorrect destination buffer size in cifs_strncpy_to_host + - CVE-2009-1633 + * sparc64: Fix crash with /proc/iomem + - CVE-2009-1914 + * splice: fix deadlock in splicing to file + - CVE-2009-1961 + * unreached code in selinux_ip_postroute_iptables_compat() (CVE-2009-1184) + - CVE-2009-1184 + * agp: zero pages before sending to userspace + - CVE-2009-1192 + * af_rose/x25: Sanity check the maximum user frame size + - CVE-2009-1265 + * nfs: Fix NFS v4 client handling of MAY_EXEC in nfs_permission. + - CVE-2009-1630 + * ipv6: don't use tw net when accounting for recycled tw + - CVE-2009-1360 + + -- Stefan Bader Mon, 15 Jun 2009 14:09:58 +0200 + +linux (2.6.27-14.33) intrepid-proposed; urgency=low + + [Stefan Bader] + + * Fix FTBS due to a mysteriously missing ABI directory. + + -- Stefan Bader Wed, 15 Apr 2009 19:04:05 +0200 + +linux (2.6.27-14.32) intrepid-proposed; urgency=low + + [Stefan Bader] + + * Rebuild of 2.6.27-14.30 with 2.6.27-11.31 security patches applied + + -- Stefan Bader Sat, 04 Apr 2009 06:59:24 +0200 + +linux (2.6.27-14.30) intrepid-proposed; urgency=low + + [ Alexey Starikovskiy ] + + * SAUCE: ACPI: EC: Limit workaround for ASUS notebooks even more + - LP: #288385 + + [ Huaxu Wan ] + + * SAUCE: report rfkill changes event if interface is down + - LP: #193970 + + [ Scott James Remnant ] + + * SAUCE: floppy: Provide a PnP device table in the module. + - LP: #255651 + + [ Steve Beattie ] + + * fix apparmor memory leak on deleted file ops + - LP: #329489 + + [ Stefan Bader ] + + * Revert "ACPI: Fix compiler warnings introduced by 32 to 64 bit acpi + conversions" + - LP: #337019 + * Revert "ACPI: Change acpi_evaluate_integer to support 64-bit on 32-bit + kernels" + - LP: #337019 + + [ Upstream Kernel Changes ] + + * KVM: MMU: Add locking around kvm_mmu_slot_remove_write_access() + - LP: #335097, #333409 + * ricoh_mmc: Handle newer models of Ricoh controllers + - LP: #311932 + + -- Stefan Bader Fri, 27 Feb 2009 11:58:17 +0100 + +linux (2.6.27-13.29) intrepid-proposed; urgency=low + + [ Colin Ian King ] + + * SAUCE: Bluetooth USB: fix kernel panic during suspend while streaming + audio to bluetooth headset + - LP: #331106, #322082 + + [ Stefan Bader ] + + * Revert "SAUCE: Work around ACPI corruption upon suspend on some Dell + machines." (replaced by stable update) + - LP: #330200 + * Revert "SAUCE: Add back in lost commit for Apple BT Wireless Keyboard" + (replaced by stable update) + - LP: #330902 + + [ Upstream Kernel Changes ] + + * Revert "vt: fix background color on line feed" + - LP: #330200 + * ti_usb_3410_5052: support alternate firmware + - LP: #231276 + * fuse: destroy bdi on umount + - LP: #324921 + * fuse: fix missing fput on error + - LP: #324921 + * fuse: fix NULL deref in fuse_file_alloc() + - LP: #324921 + * inotify: clean up inotify_read and fix locking problems + - LP: #324921 + * mac80211: decrement ref count to netdev after launching mesh discovery + - LP: #324921 + * sysfs: fix problems with binary files + - LP: #324921 + * x86, mm: fix pte_free() + - LP: #324921 + * alpha: nautilus - fix compile failure with gcc-4.3 + - LP: #324921 + * it821x: Add ultra_mask quirk for Vortex86SX + - LP: #324921 + * libata: pata_via: support VX855, future chips whose IDE controller use + 0x0571 + - LP: #324921 + * rtl8187: Add termination packet to prevent stall + - LP: #324921 + * serial_8250: support for Sealevel Systems Model 7803 COMM+8 + - LP: #324921 + * SUNRPC: Fix a memory leak in rpcb_getport_async + - LP: #324921 + * SUNRPC: Fix autobind on cloned rpc clients + - LP: #324921 + * USB: fix char-device disconnect handling + - LP: #324921 + * USB: storage: add unusual devs entry + - LP: #324921 + * USB: usbmon: Implement compat_ioctl + - LP: #324921 + * ALSA: hda - add another MacBook Pro 4, 1 subsystem ID + - LP: #324921 + * ALSA: hda - Add quirk for HP DV6700 laptop + - LP: #324921 + * ALSA: hda - Fix PCM reference NID for STAC/IDT analog outputs + - LP: #324921 + * bnx2x: Block nvram access when the device is inactive + - LP: #324921 + * crypto: authenc - Fix zero-length IV crash + - LP: #324921 + * crypto: ccm - Fix handling of null assoc data + - LP: #324921 + * epoll: drop max_user_instances and rely only on max_user_watches + - LP: #324921 + * ext3: Add sanity check to make_indexed_dir + - LP: #324921 + * include/linux: Add bsg.h to the Kernel exported headers + - LP: #324921 + * sgi-xpc: ensure flags are updated before bte_copy + - LP: #324921 + * sgi-xpc: Remove NULL pointer dereference. + - LP: #324921 + * sound: virtuoso: do not overwrite EEPROM on Xonar D2/D2X + - LP: #324921 + * rtl8187: Fix error in setting OFDM power settings for RTL8187L + - LP: #324921 + * PCI hotplug: fix lock imbalance in pciehp + - LP: #324921 + * relay: fix lock imbalance in relay_late_setup_files + - LP: #324921 + * Linux 2.6.27.14 + - LP: #324921 + * r8169: Tx performance tweak helper + - LP: #326891 + * r8169: use pci_find_capability for the PCI-E features + - LP: #326891 + * r8169: add 8168/8101 registers description + - LP: #326891 + * r8169: add hw start helpers for the 8168 and the 8101 + - LP: #326891 + * r8169: additional 8101 and 8102 support + - LP: #326891 + * ixgb: fix bug when freeing resources + - LP: #328652 + * m68knommu: set NO_DMA + - LP: #328652 + * sata_mv: fix 8-port timeouts on 508x/6081 chips + - LP: #328652 + * x86: use early clobbers in usercopy*.c + - LP: #328652 + * Add enable_ms to jsm driver + - LP: #328652 + * fbdev/atyfb: Fix DSP config on some PowerMacs & PowerBooks + - LP: #328652 + * Fix memory corruption in console selection + - LP: #328652 + * Input: atkbd - broaden the Dell DMI signatures + - LP: #328652, #261721 + * Input: atkbd - Samsung NC10 key repeat fix + - LP: #328652, #295251 + * net: fix packet socket delivery in rx irq handler + - LP: #328652 + * nfsd: Ensure nfsv4 calls the underlying filesystem on LOCKT + - LP: #328652 + * nfsd: only set file_lock.fl_lmops in nfsd4_lockt if a stateowner is + found + - LP: #328652 + * PCI: irq and pci_ids patch for Intel Tigerpoint DeviceIDs + - LP: #328652 + * sata_nv: rename nv_nf2_hardreset() + - LP: #328652 + * sata_nv: fix MCP5x reset + - LP: #328652 + * sata_nv: ck804 has borked hardreset too + - LP: #328652 + * x86: fix page attribute corruption with cpa() + - LP: #328652 + * cpuidle: update the last_state acpi cpuidle reflecting actual state + entered + - LP: #328652 + * cpuidle: upon BIOS bug, default to default_idle rather than polling + - LP: #328652 + * cpuidle: use last_state which can reflect the actual state entered + - LP: #328652 + * cpuidle: Add decaying history logic to menu idle predictor + - LP: #328652 + * ACPI: Avoid array address overflow when _CST MWAIT hint bits are set + - LP: #328652 + * ACPICA: Fixed a couple memory leaks associated with "implicit return" + - LP: #328652 + * ACPICA: Add check for invalid handle in acpi_get_object_info + - LP: #328652 + * ACPI: Change acpi_evaluate_integer to support 64-bit on 32-bit kernels + - LP: #328652 + * ACPI: Fix compiler warnings introduced by 32 to 64 bit acpi conversions + - LP: #328652 + * ACPI EC: Fix regression due to use of uninitialized variable + - LP: #328652 + * ACPICA: Fix wrong resource descriptor length for 64-bit build + - LP: #328652 + * asus-laptop: Add support for P30/P35 + - LP: #328652 + * asus-laptop: Fix the led behavior with value > 1 + - LP: #328652 + * video: always update the brightness when poking "brightness" + - LP: #328652 + * don't load asus-acpi if model is not supported + - LP: #328652 + * Newly inserted battery might differ from one just removed, so update of + battery info fields is required. + - LP: #328652 + * ACPI: Do not modify SCI_EN directly + - LP: #328652 + * ACPI suspend: Blacklist HP xw4600 Workstation for old code ordering + - LP: #328652 + * dlm: initialize file_lock struct in GETLK before copying conflicting + lock + - LP: #328652 + * sata_mv: Fix chip type for Hightpoint RocketRaid 1740/1742 + - LP: #328652 + * ACPICA: Allow multiple backslash prefix in namepaths + - LP: #328652 + * Linux 2.6.27.15 + - LP: #328652 + * ACPI: Enable bit 11 in _PDC to advertise hw coord + - LP: #330200 + * agp/intel: add support for G41 chipset + - LP: #330200 + * agp/intel: Fix broken Ā® symbol in device name. + - LP: #330200 + * agp/intel: Reduce extraneous PCI posting reads during init + - LP: #330200 + * e1000: fix bug with shared interrupt during reset + - LP: #330200 + * e1000: Fix PCI enable to honor the need_ioport flag + - LP: #330200 + * eeepc-laptop: fix oops when changing backlight brightness during + eeepc-laptop init + - LP: #330200 + * md: Ensure an md array never has too many devices. + - LP: #330200 + * module: remove over-zealous check in __module_get() + - LP: #330200 + * prevent kprobes from catching spurious page faults + - LP: #330200 + * sgi-xp: fix writing past the end of kzalloc()'d space + - LP: #330200 + * shm: fix shmctl(SHM_INFO) lockup with !CONFIG_SHMEM + - LP: #330200 + * sound: usb-audio: handle wMaxPacketSize for FIXED_ENDPOINT devices + - LP: #330200 + * wait: prevent exclusive waiter starvation + - LP: #330200 + * x86: APIC: enable workaround on AMD Fam10h CPUs + - LP: #330200 + * ieee1394: ohci1394: increase AT req. retries, fix ack_busy_X from + Panasonic camcorders and others + - LP: #330200 + * firewire: ohci: increase AT req. retries, fix ack_busy_X from Panasonic + camcorders and others + - LP: #330200 + * firewire: sbp2: fix DMA mapping leak on the failure path + - LP: #330200 + * firewire: sbp2: add workarounds for 2nd and 3rd generation iPods + - LP: #330200 + * ieee1394: sbp2: add workarounds for 2nd and 3rd generation iPods + - LP: #330200 + * 8250_pci: add support for netmos 9835 IBM devices + - LP: #330200 + * ACPICA: Fix table entry truncation calculation + - LP: #330200 + * ACPI: disable ACPI cleanly when bad RSDP found + - LP: #330200 + * ACPI: proc_dir_entry 'video/VGA' already registered + - LP: #330200 + * ACPI: Skip the first two elements in the _BCL package + - LP: #330200 + * Add support for '8-port RS-232 MIC-3620 from advantech' + - LP: #330200 + * ALSA: hda - Add missing COEF initialization for ALC887 + - LP: #330200 + * ALSA: hda - Add missing initialization for ALC272 + - LP: #330200 + * ALSA: hda - Add quirk for FSC Amilo Xi2550 + - LP: #330200 + * PCI: properly clean up ASPM link state on device remove + - LP: #330200 + * PCI: return error on failure to read PCI ROMs + - LP: #330200 + * seq_file: move traverse so it can be used from seq_read + - LP: #330200 + * seq_file: fix big-enough lseek() + read() + - LP: #330200 + * serial: set correct baud_base for Oxford Semiconductor Ltd EXSYS + EX-41092 Dual 16950 Serial adapter + - LP: #330200 + * elf core dump: fix get_user use + - LP: #330200 + * XFS: set b_error from bio error in xfs_buf_bio_end_io + - LP: #330200 + * Add a reference to sunrpc in svc_addsock + - LP: #330200 + * mm: remove UP version of lru_add_drain_all() + - LP: #330200 + * md: Don't try to set an array to 'read-auto' if it is already in that + state. + - LP: #330200 + * md: Allow metadata_version to be updated for externally managed + metadata. + - LP: #330200 + * ipw2200: fix scanning while associated + - LP: #330200 + * hso: rfkill type should be WWAN + - LP: #330200 + * dm mpath: avoid attempting to activate null path + - LP: #330200 + * ACPICA: Copy dynamically loaded tables to local buffer + - LP: #330200 + * ACPICA: Add function to dereference returned reference objects + - LP: #330200 + * ACPI: don't load acpi_cpufreq if acpi=off + - LP: #330200 + * ACPI: video: Fix reversed brightness behavior on ThinkPad SL series + - LP: #330200 + * Revert USB: option: add Pantech cards + - LP: #330200 + * USB: new id for ti_usb_3410_5052 driver + - LP: #330200 + * USB: option: New mobile broadband modems to be supported + - LP: #330200 + * USB: two more usb ids for ti_usb_3410_5052 + - LP: #330200 + * USB: usb-storage: add Pentax to the bad-vendor list + - LP: #330200 + * sctp: Fix another socket race during accept/peeloff + - LP: #330200 + * genirq: NULL struct irq_desc's member 'name' in dynamic_irq_cleanup() + - LP: #330200 + * Linux 2.6.27.16 + - LP: #330200 + * Linux 2.6.27.17 + - LP: #330200 + * Fix page writeback thinko, causing Berkeley DB slowdown + - LP: #330902 + * iwlwifi: scan correct setting of valid rx_chains + - LP: #330902 + * kernel-doc: fix syscall wrapper processing + - LP: #330902 + * lockd: fix regression in lockd's handling of blocked locks + - LP: #330902 + * nbd: fix I/O hang on disconnected nbds + - LP: #330902 + * parport: parport_serial, don't bind netmos ibm 0299 + - LP: #330902 + * powerpc: Fix swapcontext system for VSX + old ucontext size + - LP: #330902 + * powerpc/fsl-booke: Fix mapping functions to use phys_addr_t + - LP: #330902 + * syscall define: fix uml compile bug + - LP: #330902 + * w1: w1 temp calculation overflow fix + - LP: #330902 + * write-back: fix nr_to_write counter + - LP: #330902 + * writeback: fix break condition + - LP: #330902 + * x86, vmi: put a missing paravirt_release_pmd in pgd_dtor + - LP: #330902 + * zd1211rw: adding 0ace:0xa211 as a ZD1211 device + - LP: #330902 + * zd1211rw: treat MAXIM_NEW_RF(0x08) as UW2453_RF(0x09) for TP-Link + WN322/422G + - LP: #330902 + * sctp: Fix crc32c calculations on big-endian arhes. + - LP: #330902 + * sctp: Correctly start rtx timer on new packet transmissions. + - LP: #330902 + * sctp: Properly timestamp outgoing data chunks for rtx purposes + - LP: #330902 + * drivers/net/skfp: if !capable(CAP_NET_ADMIN): inverted logic + - LP: #330902 + * ipv4: fix infinite retry loop in IP-Config + - LP: #330902 + * ipv6: Disallow rediculious flowlabel option sizes. + - LP: #330902 + * ipv6: Copy cork options in ip6_append_data + - LP: #330902 + * net: 4 bytes kernel memory disclosure in SO_BSDCOMPAT gsopt try #2 + - LP: #330902 + * net: packet socket packet_lookup_frame fix + - LP: #330902 + * sky2: fix hard hang with netconsoling and iface going up + - LP: #330902 + * sungem: Soft lockup in sungem on Netra AC200 when switching interface + up + - LP: #330902 + * tun: Add some missing TUN compat ioctl translations. + - LP: #330902 + * tun: Fix unicast filter overflow + - LP: #330902 + * udp: Fix UDP short packet false positive + - LP: #330902 + * udp: increments sk_drops in __udp_queue_rcv_skb() + - LP: #330902 + * virtio_net: Fix MAX_PACKET_LEN to support 802.1Q VLANs + - LP: #330902 + * net: Fix frag_list handling in skb_seq_read + - LP: #330902 + * net: Fix OOPS in skb_seq_read(). + - LP: #330902 + * packet: Avoid lock_sock in mmap handler + - LP: #330902 + * tcp: splice as many packets as possible at once + - LP: #330902 + * tcp: Fix length tcp_splice_data_recv passes to skb_splice_bits. + - LP: #330902 + * sparc: Enable syscall wrappers for 64-bit (CVE-2009-0029) + - LP: #330902 + * sparc64: Annotate sparc64 specific syscalls with SYSCALL_DEFINEx() + - LP: #330902 + * netfilter: fix tuple inversion for Node information request + - LP: #330902 + * netfilter: xt_sctp: sctp chunk mapping doesn't work + - LP: #330902 + * bluetooth hid: enable quirk handling for Apple Wireless Keyboards in + 2.6.27 + - LP: #330902 + * HID: adjust report descriptor fixup for MS 1028 receiver + - LP: #330902, #281993 + * libata: fix EH device failure handling + - LP: #330902 + * ide/libata: fix ata_id_is_cfa() (take 4) + - LP: #330902 + * x86: fixup config space size of CPU functions for AMD family 11h + - LP: #330902 + * mac80211: fix a buffer overrun in station debug code + - LP: #330902 + * ALSA: mtpav - Fix initial value for input hwport + - LP: #330902 + * net: Fix data corruption when splicing from sockets. + - LP: #330902 + * Linux 2.6.27.18 + - LP: #330902 + + -- Stefan Bader Thu, 12 Feb 2009 20:17:51 +0100 + +linux (2.6.27-12.28) intrepid-proposed; urgency=low + + [ Alok Kataria ] + + * x86: add a synthetic TSC_RELIABLE feature bit + - LP: #319945 + * x86: add X86_FEATURE_HYPERVISOR feature bit + - LP: #319945 + * x86: Hypervisor detection and get tsc_freq from hypervisor + - LP: #319945 + * x86: Add a synthetic TSC_RELIABLE feature bit. + - LP: #319945 + * x86: Skip verification by the watchdog for TSC clocksource. + - LP: #319945 + * x86: VMware: Fix vmware_get_tsc code + - LP: #319945 + * x86: vmware: look for DMI string in the product serial key + - LP: #319945 + + [ Jani Monoses ] + + * Fix webcam having USB ID 0ac8:303b + - LP: #292086 + + [ Stefan Bader ] + + * Bump ABI to -12 Ignore: yes + + [ Upstream Kernel Changes ] + + * USB: gadget: fix rndis working at high speed + - LP: #321468 + * usb-storage: update unusual_devs entry for Nokia 5310 + - LP: #321468 + * USB: storage: unusual_devs.h: Nokia 3109c addition + - LP: #321468 + * USB: Unusual devs patch for Nokia 3500c + - LP: #321468 + * powerpc: Fix corruption error in rh_alloc_fixed() + - LP: #321468 + * async_xor: dma_map destination DMA_BIDIRECTIONAL + - LP: #321468 + * dmaengine: protect 'id' from concurrent registrations + - LP: #321468 + * ioat: wait for self-test completion + - LP: #321468 + * md: Don't read past end of bitmap when reading bitmap. + - LP: #321468 + * ALSA: Fix a Oops bug in omap soc driver. + - LP: #321468 + * SCSI: ibmvstgt: move crq_queue_create to the end of initialization + - LP: #321468 + * SCSI: aacraid: disable Dell Percraid quirk on Adaptec 2200S and 2120S + - LP: #321468 + * cciss: fix problem that deleting multiple logical drives could cause a + panic + - LP: #321468 + * ALSA: hda - Add missing terminators in patch_sigmatel.c + - LP: #321468 + * parisc: disable UP-optimized flush_tlb_mm + - LP: #321468 + * drivers/net: starfire: Fix napi ->poll() weight handling + - LP: #321468 + * AMD IOMMU: reset command buffer pointers manually + - LP: #321468 + * AMD IOMMU: allocate rlookup_table with __GFP_ZERO + - LP: #321468 + * AMD IOMMU: initialize phys_addr correctly in iommu_page_map + - LP: #321468 + * AMD IOMMU: fix wrong loop counter in free_pagetables + - LP: #321468 + * Linux 2.6.27.11 + - LP: #321468 + * Input: atkbd - add keyboard quirk for HP Pavilion ZV6100 laptop + - LP: #291878 + * ALSA: hda - Check model for Dell 92HD73xx laptops + - LP: #309512 + * ALSA: hda - Add quirk for Dell Studio 17 + - LP: #309512 + * iwlagn: fix RX skb alignment + - LP: #309731 + * ALSA: caiaq - Fix Oops with MIDI + - LP: #321472 + * ALSA: hda - Add quirk for HP6730B laptop + - LP: #321472 + * cgroups: fix a race between cgroup_clone and umount + - LP: #321472 + * devices cgroup: allow mkfifo + - LP: #321472 + * dm log: fix dm_io_client leak on error paths + - LP: #321472 + * dm raid1: fix error count + - LP: #321472 + * ioat: fix self test for multi-channel case + - LP: #321472 + * iwlwifi: use GFP_KERNEL to allocate Rx SKB memory + - LP: #321472 + * md: fix bitmap-on-external-file bug. + - LP: #321472 + * minix: fix add link's wrong position calculation + - LP: #321472 + * sched_clock: prevent scd->clock from moving backwards, take #2 + - LP: #321472 + * SCSI: aha152x_cs: Fix regression that keeps driver from using shared + interrupts + - LP: #321472 + * SCSI: eata: fix the data buffer accessors conversion regression + - LP: #321472 + * USB: emi26: fix oops on load + - LP: #321472 + * USB: isp1760: use a specific PLX bridge instead of any bdridge + - LP: #321472 + * USB: unusual_devs.h additions for Pentax K10D + - LP: #321472 + * x86: default to SWIOTLB=y on x86_64 + - LP: #321472 + * x86: fix incorrect __read_mostly on _boot_cpu_pda + - LP: #321472 + * x86, UV: remove erroneous BAU initialization + - LP: #321472 + * inotify: fix type errors in interfaces + - LP: #321472 + * Move compat system call declarations to compat header file + - LP: #321472 + * Convert all system calls to return a long + - LP: #321472 + * Rename old_readdir to sys_old_readdir + - LP: #321472 + * Remove __attribute__((weak)) from sys_pipe/sys_pipe2 + - LP: #321472 + * Make sys_pselect7 static + - LP: #321472 + * Make sys_syslog a conditional system call + - LP: #321472 + * System call wrapper infrastructure + - LP: #321472 + * powerpc: Enable syscall wrappers for 64-bit + - LP: #321472 + * s390: enable system call wrappers + - LP: #321472 + * System call wrapper special cases + - LP: #321472 + * System call wrappers part 01 + - LP: #321472 + * System call wrappers part 02 + - LP: #321472 + * System call wrappers part 03 + - LP: #321472 + * System call wrappers part 04 + - LP: #321472 + * System call wrappers part 05 + - LP: #321472 + * System call wrappers part 06 + - LP: #321472 + * System call wrappers part 07 + - LP: #321472 + * System call wrappers part 08 + - LP: #321472 + * System call wrappers part 09 + - LP: #321472 + * System call wrappers part 10 + - LP: #321472 + * System call wrappers part 11 + - LP: #321472 + * System call wrappers part 12 + - LP: #321472 + * System call wrappers part 13 + - LP: #321472 + * System call wrappers part 14 + - LP: #321472 + * System call wrappers part 15 + - LP: #321472 + * System call wrappers part 16 + - LP: #321472 + * System call wrappers part 17 + - LP: #321472 + * System call wrappers part 18 + - LP: #321472 + * System call wrappers part 19 + - LP: #321472 + * System call wrappers part 20 + - LP: #321472 + * System call wrappers part 21 + - LP: #321472 + * System call wrappers part 22 + - LP: #321472 + * System call wrappers part 23 + - LP: #321472 + * System call wrappers part 24 + - LP: #321472 + * System call wrappers part 25 + - LP: #321472 + * System call wrappers part 26 + - LP: #321472 + * System call wrappers part 27 + - LP: #321472 + * System call wrappers part 28 + - LP: #321472 + * System call wrappers part 29 + - LP: #321472 + * System call wrappers part 30 + - LP: #321472 + * System call wrappers part 31 + - LP: #321472 + * System call wrappers part 32 + - LP: #321472 + * System call wrappers part 33 + - LP: #321472 + * s390 specific system call wrappers + - LP: #321472 + * e1000e: fix IPMI traffic + - LP: #321472 + * eCryptfs: check readlink result was not an error before using it + - LP: #321472 + * fix switch_names() breakage in short-to-short case + - LP: #321472 + * fs: symlink write_begin allocation context fix + - LP: #321472 + * ibmvfc: Delay NPIV login retry and add retries + - LP: #321472 + * ibmvfc: Improve async event handling + - LP: #321472 + * mm: fix assertion + - LP: #321472 + * mm lockless pagecache barrier fix + - LP: #321472 + - LP: #312163 + * mvsas: increase port type detection delay to suit Seagate's 10k6 drive + ST3450856SS 0003 + - LP: #321472 + * nfs: remove redundant tests on reading new pages + - LP: #321472 + * powerpc: Disable Collaborative Memory Manager for kdump + - LP: #321472 + * USB: another unusual_devs entry for another bad Argosy storage device + - LP: #321472 + * USB: storage: extend unusual range for 067b:3507 + - LP: #321472 + * USB: storage: recognizing and enabling Nokia 5200 cell phoes + - LP: #321472 + * x86: avoid theoretical vmalloc fault loop + - LP: #321472 + * x86, cpa: dont use large pages for kernel identity mapping with + DEBUG_PAGEALLOC + - LP: #321472 + * x86: fix RIP printout in early_idt_handler + - LP: #321472 + * PCI: Rework default handling of suspend and resume + - LP: #321472 + * PCI: Suspend and resume PCI Express ports with interrupts disabled + - LP: #321472 + * PCI: handle PCI state saving with interrupts disabled + - LP: #321472 + * PCI PM: Split PCI Express port suspend-resume + - LP: #321472 + * Linux 2.6.27.12 + - LP: #321472 + * pkt_sched: sch_htb: Fix deadlock in hrtimers triggered by HTB + - LP: #321474 + * ipv6: Fix fib6_dump_table walker leak + - LP: #321474 + * sctp: Avoid memory overflow while FWD-TSN chunk is received with bad + stream ID + - LP: #321474 + * pkt_sched: cls_u32: Fix locking in u32_change() + - LP: #321474 + * r6040: fix wrong logic in mdio code + - LP: #321474 + * r6040: save and restore MIER correctly in the interrupt routine + - LP: #321474 + * r6040: bump release number to 0.19 + - LP: #321474 + * tcp: don't mask EOF and socket errors on nonblocking splice receive + - LP: #321474 + * usb-storage: add last-sector hacks + - LP: #321474 + * usb-storage: set CAPACITY_HEURISTICS flag for bad vendors + - LP: #321474 + * ALSA: hda - make laptop-eapd model back for AD1986A + - LP: #321474 + * drivers/net/irda/irda-usb.c: fix buffer overflow + - LP: #321474, #320814 + * IA64: Turn on CONFIG_HAVE_UNSTABLE_CLOCK + - LP: #321474 + * 'kill sig -1' must only apply to caller's namespace + - LP: #321474 + * lib/idr.c: use kmem_cache_zalloc() for the idr_layer cache + - LP: #321474 + * p54usb: Add USB ID for Thomson Speedtouch 121g + - LP: #321474 + * PCI: keep ASPM link state consistent throughout PCIe hierarchy + - LP: #321474 + * rt2x00: add USB ID for the Linksys WUSB200. + - LP: #321474 + * security: introduce missing kfree + - LP: #321474 + * sgi-xp: eliminate false detection of no heartbeat + - LP: #321474 + * clocksource: introduce clocksource_forward_now() + - LP: #321474 + * hwmon-vid: Add support for AMD family 10h CPUs + - LP: #321474 + * ath9k: quiet harmless ForceXPAon messages + - LP: #321474, #325469 + * dell_rbu: use scnprintf() instead of less secure sprintf() + - LP: #321474 + * hwmon: (abituguru3) Fix CONFIG_DMI=n fallback to probe + - LP: #321474 + * powerpc: is_hugepage_only_range() must account for both 4kB and 64kB + slices + - LP: #321474 + * mm: write_cache_pages cyclic fix + - LP: #321474 + * mm: write_cache_pages early loop termination + - LP: #321474 + * mm: write_cache_pages writepage error fix + - LP: #321474 + * mm: write_cache_pages integrity fix + - LP: #321474 + * mm: write_cache_pages cleanups + - LP: #321474 + * mm: write_cache_pages optimise page cleaning + - LP: #321474 + * mm: write_cache_pages terminate quickly + - LP: #321474 + * mm: write_cache_pages more terminate quickly + - LP: #321474 + * mm: do_sync_mapping_range integrity fix + - LP: #321474 + * mm: direct IO starvation improvement + - LP: #321474 + * fs: remove WB_SYNC_HOLD + - LP: #321474 + * fs: sync_sb_inodes fix + - LP: #321474 + * fs: sys_sync fix + - LP: #321474 + * Linux 2.6.27.13 + - LP: #321474 + + -- Stefan Bader Sun, 25 Jan 2009 22:11:01 +0100 + +linux (2.6.27-11.31) intrepid-security; urgency=low + + [ Steve Beattie ] + + * fix apparmor memory leak on deleted file ops Bug: #329489 + - LP: #329489 + + [ Upstream Kernel Changes ] + + * sctp: Avoid memory overflow while FWD-TSN chunk is received with bad + stream ID + - CVE-2009-0065 + * prevent kprobes from catching spurious page faults + - CVE-2009-0605 + * net: 4 bytes kernel memory disclosure in SO_BSDCOMPAT gsopt try #2 + - CVE-2009-0676 + * copy_process: fix CLONE_PARENT && parent_exec_id interaction + - CVE-2009-0028 + * security: introduce missing kfree + - CVE-2009-0031 + * eCryptfs: check readlink result was not an error before using it + - CVE-2009-0269 + * dell_rbu: use scnprintf() instead of less secure sprintf() + - CVE-2009-0322 + * drivers/net/skfp: if !capable(CAP_NET_ADMIN): inverted logic + - CVE-2009-0675 + * ext4: Initialize the new group descriptor when resizing the filesystem + - CVE-2009-0745 + * ext4: Add sanity check to make_indexed_dir + - CVE-2009-0746 + * ext4: only use i_size_high for regular files + - CVE-2009-0747 + * ext4: Add sanity checks for the superblock before mounting the + filesystem + - CVE-2009-0748 + * x86-64: syscall-audit: fix 32/64 syscall hole + - CVE-2009-0834 + * x86-64: seccomp: fix 32/64 syscall hole + - CVE-2009-0835 + * shm: fix shmctl(SHM_INFO) lockup with !CONFIG_SHMEM + - CVE-2009-0859 + * udf:SAUCE (drop after 2.6.30): Fix oops when invalid character in + filename occurs + - LP: #321606 + * Add '-fwrapv' to gcc CFLAGS + - LP: #348015 + * Move cc-option to below arch-specific setup + - LP: #348015 + * Fix memory corruption in console selection + - CVE-2009-1046 + + -- Stefan Bader Mon, 16 Mar 2009 18:48:27 +0100 + +linux (2.6.27-11.27) intrepid-security; urgency=low + + [ Upstream Kernel Changes ] + + * USB: isp1760: Fix probe in PCI glue code + - LP: #322553 + + -- Stefan Bader Thu, 29 Jan 2009 10:37:27 +0000 + +linux (2.6.27-11.26) intrepid-security; urgency=low + + Re-release of 2.6.27-11.25 as security release + + [Upstream Kernel Changes] + + * ATM: CVE-2008-5079: duplicate listen() on socket corrupts the vcc table + - CVE-2008-5079 + * Fix inotify watch removal/umount races + - CVE-2008-5182 + * net: Fix soft lockups/OOM issues w/ unix garbage collector + - CVE-2008-5300 + * parisc: fix kernel crash when unwinding a userspace process + - CVE-2008-5395 + * Enforce a minimum SG_IO timeout + - CVE-2008-5700 + * ib700wdt.c - fix buffer_underflow bug + - CVE-2008-5702 + + -- Stefan Bader Sat, 24 Jan 2009 15:21:43 +0100 + +linux (2.6.27-11.25) intrepid-proposed; urgency=low + + [ Jeff Layton ] + * SAUCE: cifs: make sure we allocate enough storage for socket address + - LP: #318565 + + -- Stefan Bader Thu, 22 Jan 2009 15:58:03 +0100 + +linux (2.6.27-11.24) intrepid-proposed; urgency=low + + [ Stefan Bader ] + + * Revert "SAUCE: don't use buggy _BCL/_BCM/_BQC for backlight control" + - LP: #311716 + * SAUCE: acpi: Hack to enable video and vendor backlight implementations + - LP: #311716 + * SAUCE: Force vendor backlight control on ThinkPad T61 + - LP: #311716 + + [ Upstream Kernel Changes ] + + * Revert "thinkpad_acpi: fingers off backlight if video.ko is serving + this functionality" + - LP: #311716 + + -- Stefan Bader Thu, 08 Jan 2009 15:08:52 +0100 + +linux (2.6.27-11.23) intrepid-proposed; urgency=low + + [ Andy Whitcroft ] + + * SAUCE: don't use buggy _BCL/_BCM/_BQC for backlight control + - LP: #311716, #314119 + + [ Jim Lieb ] + + * SAUCE: atl2: add tx bytes statistic + - LP: #268622 + + [ Upstream Kernel Changes ] + + * i915: Save/restore MCHBAR_RENDER_STANDBY on GM965/GM45 + - LP: #276943 + + -- Stefan Bader Wed, 7 Jan 2009 18:27:52 +0100 + +linux (2.6.27-11.22) intrepid-proposed; urgency=low + + [ Andy Whitcroft ] + + * Revert "synchronise our linux-libc-dev with the kernel userspace + headers". It was causing regressions. + - LP: #300803 + + [ Brian Rogers ] + + * SAUCE: Add support for MSI TV@nywhere Plus remote + - LP: #281647 + + [ Tim Gardner ] + + * SAUCE: Dell laptop digital mic does not work, PCI 1028:0271 + - LP: #309508 + + [ Upstream Kernel Changes ] + + * Revert "sched_clock: prevent scd->clock from moving backwards" + * AMD IOMMU: enable device isolation per default + * bonding: fix miimon failure counter + * x86 Fix VMI crash on boot in 2.6.28-rc8 + * libata: fix Seagate NCQ+FLUSH blacklist + * e1000e: fix double release of mutex + * can: Fix CAN_(EFF|RTR)_FLAG handling in can_filter + * can: omit received RTR frames for single ID filter lists + * iwlwifi: clean key table in iwl_clear_stations_table function + * net: eliminate warning from NETIF_F_UFO on bridge + * unicode table for cp437 + * console ASCII glyph 1:1 mapping + * key: fix setkey(8) policy set breakage + * firewire: fw-ohci: fix IOMMU resource exhaustion + * ieee1394: add quirk fix for Freecom HDD + * SUNRPC: Fix a performance regression in the RPC authentication code + * b1isa: fix b1isa_exit() to really remove registered capi controllers + * macfb: Do not overflow fb_fix_screeninfo.id + * setup_per_zone_pages_min(): take zone->lock instead of zone->lru_lock + * xilinx_hwicap: remove improper wording in license statement + * Linux 2.6.27.10 except for "iwlagn: fix RX skb alignment". Besides causing + an ABI bump it only applies to machines using > 4K page size (such as PowerPC). + Pick this one up on the next ABI bumping upload. + - LP: #309731 + + -- Tim Gardner Thu, 18 Dec 2008 20:57:31 -0700 + +linux (2.6.27-11.21) intrepid-proposed; urgency=low + + [ Andy Whitcroft ] + + * synchronise our linux-libc-dev with the kernel userspace headers + - LP: #300803 + + [ Jim Lieb ] + + * SAUCE: [PATCH 1/1] USB: Unusual devs patch for Nokia 5610 + - LP: #287701 + + [ Michael Krufky ] + + * sms1xxx: use new firmware for Hauppauge WinTV MiniStick + - LP: #299671 + * sms1xxx: add autodetection support for Hauppauge WinTV MiniCard + - LP: #299680 + * sms1xxx: add functions to configure and set gpio + - LP: #301405 + * sms1xxx: turn off LEDs after initialization of Hauppauge WinTV + MiniStick + - LP: #301405 + * sms1xxx: enable power LED on Hauppauge WinTV MiniStick + - LP: #301405 + * sms1xxx: enable LNA control on Hauppauge WinTV MiniCard + - LP: #301204 + * sms1xxx: fix invalid unc readings + - LP: #301405 + * sms1xxx: enable signal quality indicator LEDs on Hauppauge WinTV + MiniStick + - LP: #301405 + * sms1xxx: identify "Dell Digital TV Receiver" devices correctly + - LP: #302509 + + [ Stefan Bader ] + + * iscsitarget: Update to official 0.4.16 driver + - LP: #278625 + * uvcvideo: Commit streaming parameters when enabling the video stream. + - LP: #290506 + + [ Tim Gardner ] + + * ALSA: hda: Add STAC_DELL_M4_3 quirk + - LP: #301738 + * Fix compile error after updating iscsitarget + * [ALSA] Fix audio output regression. + - LP: #294418 + * Restore AMOI_VENDOR_ID/AMOI_PRODUCT_9508 macros + + [ Upstream Kernel Changes ] + + * V4L/DVB (8729): Use DIV_ROUND_UP + - LP: #301580 + * V4L/DVB (8754): uvcvideo: Implement the USB power management + reset_resume method. + - LP: #301572 + * V4L/DVB (8846): uvcvideo: Supress spurious "EOF in empty payload" trace + message + - LP: #301580 + * V4L/DVB (8847): uvcvideo: Add support for a Bison Electronics webcam + found in the Fujitsu Amilo SI2636. + - LP: #301576 + * V4L/DVB (9030): uvcvideo : Add support for Advent 4211 integrated + webcam + - LP: #301576 + * V4L/DVB (9031): uvcvideo: Fix incomplete frame drop when switching to a + variable size format. + - LP: #290506 + * V4L/DVB:usbvideo:don't use part of buffer for USB transfer #4 + - LP: #301580 + * V4L/DVB (9035): uvcvideo: Declare missing camera and processing unit + controls. + - LP: #290506 + * V4L/DVB (9036): uvcvideo: Fix control cache access when setting + composite auto-update controls + - LP: #301580 + * V4L/DVB (9169): uvcvideo: Support two new Bison Electronics webcams. + - LP: #301576 + * ALSA: hda - Add a quirk for Dell Studio 15 + - LP: #290549 + * ACPI: video: Ignore devices that aren't present in hardware + - LP: #257827 + * ACPI video: if no ACPI backlight support, use vendor drivers + - LP: #257827 + * Acer-WMI: fingers off backlight if video.ko is serving this + functionality + - LP: #257827 + * asus-acpi: fingers off backlight if video.ko is serving this + functionality + - LP: #257827 + * compal: fingers off backlight if video.ko is serving this functionality + - LP: #257827 + * eeepc-laptop: fingers off backlight if video.ko is serving this + functionality + - LP: #257827 + * fujitsu-laptop: fingers off backlight if video.ko is serving this + functionality + - LP: #257827 + * msi-laptop: fingers off backlight if video.ko is serving this + functionality + - LP: #257827 + * sony-laptop: fingers off backlight if video.ko is serving this + functionality + - LP: #257827 + * thinkpad_acpi: fingers off backlight if video.ko is serving this + functionality + - LP: #257827 + * USB: storage: updates unusual_devs entry for the Nokia 6300 + - LP: #287701 + * USB: storage: update unusual_devs entries for Nokia 5300 and 5310 + - LP: #287701 + + * stable kernel updates: + * USB: gadget rndis: send notifications + * USB: gadget rndis: stop windows self-immolation + * USB: usbmon: fix read(2) + * USB: fix SB700 usb subsystem hang bug + * USB: fix SB600 USB subsystem hang bug + * atl1e: fix broken multicast by removing unnecessary crc inversion + * cpuset: fix regression when failed to generate sched domains + * cgroups: fix a serious bug in cgroupstats + * pxa2xx_spi: bugfix full duplex dma data corruption + * fbdev: clean the penguin's dirty feet + * gpiolib: extend gpio label column width in debugfs file + * lib/scatterlist.c: fix kunmap() argument in sg_miter_stop() + * sysvipc: fix the ipc structures initialization + * parisc: fix kernel crash when unwinding a userspace process + * epoll: introduce resource usage limits + * Fix inotify watch removal/umount races + * IA64: fix boot panic caused by offline CPUs + * V4L/DVB (9352): Add some missing compat32 ioctls + * Input: atkbd - add keymap quirk for Inventec Symphony systems + * lib/idr.c: fix rcu related race with idr_find + * parport_serial: fix array overflow + * x86: more general identifier for Phoenix BIOS + * x86: always define DECLARE_PCI_UNMAP* macros + * ath9k: Fix SW-IOMMU bounce buffer starvation + * ath9k: correct expected max RX buffer size + * axnet_cs / pcnet_cs: moving PCMCIA_DEVICE_PROD_ID for Netgear FA411 + * PCI Hotplug core: add 'name' param pci_hp_register interface + * PCI: update pci_create_slot() to take a 'hotplug' param + * PCI Hotplug: serialize pci_hp_register and pci_hp_deregister + * PCI: prevent duplicate slot names + * PCI, PCI Hotplug: introduce slot_name helpers + * PCI: acpiphp: remove 'name' parameter + * PCI: cpci_hotplug: stop managing hotplug_slot->name + * PCI: cpqphp: stop managing hotplug_slot->name + * PCI: fakephp: remove 'name' parameter + * PCI: ibmphp: stop managing hotplug_slot->name + * PCI: pciehp: remove 'name' parameter + * PCI: rpaphp: kmalloc/kfree slot->name directly + * PCI: SGI Hotplug: stop managing bss_hotplug_slot->name + * PCI: shcphp: remove 'name' parameter + * PCI: Hotplug core: remove 'name' + * CPUFREQ: powernow-k8: ignore out-of-range PstateStatus value + * xen: do not reserve 2 pages of padding between hypervisor and fixmap. + * x86: Hibernate: Fix breakage on x86_32 with CONFIG_NUMA set + * x86: SB600: skip ACPI IRQ0 override if it is not routed to INT2 of + IOAPIC + * libata: Avoid overflow in libata when tf->hba_lbal > 127 + * x86: call dmi-quirks for HP Laptops after early-quirks are executed + * igb: Use device_set_wakeup_enable + * e1000: Use device_set_wakeup_enable + * e1000e: Use device_set_wakeup_enable + * libata: blacklist Seagate drives which time out FLUSH_CACHE when used + with NCQ + * rtl8187: add device ID 0bda:8198 + * rtl8187: Add USB ID for Belkin F5D7050 with RTL8187B chip + * cifs: Reduce number of socket retries in large write path + * cifs: Fix error in smb_send2 + * powerpc/spufs: Fix spinning in spufs_ps_fault on signal + * powerpc/spufs: add a missing mutex_unlock + * WATCHDOG: hpwdt: set the mapped BIOS address space as executable + * WATCHDOG: hpwdt: Fix kdump when using hpwdt + * Remove -mno-spe flags as they dont belong + * ACPI: EC: count interrupts only if called from interrupt handler. + * ieee1394: sbp2: another iPod mini quirk entry + * firewire: fw-sbp2: another iPod mini quirk entry + * IB/mlx4: Fix MTT leakage in resize CQ + * net: Fix soft lockups/OOM issues w/ unix garbage collector + (CVE-2008-5300) + * cifs: Fix cifs reconnection flags + * cifs: remove unused list, add new cifs sock list to prepare for + mount/umount fix + * cifs: clean up server protocol handling + * cifs: disable sharing session and tcon and add new TCP sharing code + * cifs: reinstate sharing of SMB sessions sans races + * cifs: minor cleanup to cifs_mount + * cifs: reinstate sharing of tree connections + * cifs: Fix build break + * cifs: Fix check for tcon seal setting and fix oops on failed mount from + earlier patch + * cifs: prevent cifs_writepages() from skipping unwritten pages + * cifs: fix check for dead tcon in smb_init + * ext4: Update flex_bg free blocks and free inodes counters when + resizing. + * ext4: fix #11321: create /proc/ext4/*/stats more carefully + * jbd2: fix /proc setup for devices that contain '/' in their names + * ext4: add missing unlock in ext4_check_descriptors() on error path + * ext4: elevate write count for migrate ioctl + * ext4: Renumber EXT4_IOC_MIGRATE + * ext4/jbd2: Avoid WARN() messages when failing to write to the + superblock + * jbd2: abort instead of waiting for nonexistent transaction + * jbd2: Fix buffer head leak when writing the commit block + * ext4: fix xattr deadlock + * ext4: Free ext4_prealloc_space using kmem_cache_free + * ext4: Do mballoc init before doing filesystem recovery + * ext4: Fix duplicate entries returned from getdents() system call + * jbd2: don't give up looking for space so easily in + __jbd2_log_wait_for_space + * ext4: Convert to host order before using the values. + * ext4: wait on all pending commits in ext4_sync_fs() + * ext4: calculate journal credits correctly + * ext4: Mark the buffer_heads as dirty and uptodate after prepare_write + * ext4: add checksum calculation when clearing UNINIT flag in + ext4_new_inode + * ext3: fix ext3_dx_readdir hash collision handling + * ext3: Fix duplicate entries returned from getdents() system call + * ext3: don't try to resize if there are no reserved gdt blocks left + * ext2: fix ext2 block reservation early ENOSPC issue + * ext3: fix ext3 block reservation early ENOSPC issue + * jbd: ordered data integrity fix + * Linux 2.6.27.8 + * [CIFS] Add nodfs mount option + - LP: #286828 + * libata: improve phantom device detection + * af_unix: netns: fix problem of return value + * niu: Fix readq implementation when architecture does not provide one. + * pppol2tp: Add missing sock_put() in pppol2tp_release() + * udp: multicast packets need to check namespace + * sparc64: Fix offset calculation in compute_size() + * sparc64: Fix __copy_{to,from}_user_inatomic defines. + * sparc64: Fix PCI resource mapping on sparc64 + * sparc64: Fix bug in PTRACE_SETFPREGS64 handling. + * sparc64: Fix VIS emulation bugs + * sparc64: Sync FPU state in VIS emulation handler. + * Enforce a minimum SG_IO timeout + * Fix a race condition in FASYNC handling + * ACPI suspend: Blacklist boxes that require us to set SCI_EN directly on + resume + * jbd: fix error handling for checkpoint io + * jbd: test BH_Write_EIO to detect errors on metadata buffers + * spi: avoid spidev crash when device is removed + * ATM: CVE-2008-5079: duplicate listen() on socket corrupts the vcc table + * powerpc/mpic: Don't reset affinity for secondary MPIC on boot + * Input: i8042 - add Blue FB5601 to noloop exception table + * Input: i8042 - add Dell XPS M1530 to nomux list + * Input: i8042 - add Compal Hel80 laptop to nomux blacklist + * edac: fix enabling of polling cell module + * USB: option: add Ericsson F3507g and Dell 5530 + * USB: option.c remove duplicate device ids now supported in hso.c + * USB: Option / AnyData new modem, same ID + * USB: option: add Pantech cards + * USB: add ZTE MF626 USB GSM modem entry + * USB: support Huawei data card product IDs + * USB: Add YISO u893 usb modem vendor and product IDs to option driver + * USB: serial: add more Onda device ids to option driver + * USB: unusual-devs: support Huawei data card product IDs + * USB: Unusual dev for Mio moov 330 gps + * USB: Unusual dev for the "Kyocera / Contax SL300R T*" digital camera. + * USB: add Nikon D300 camera to unusual_devs + * USB: unusual devs patch for Nokia 7610 Supernova + * USB: storage: unusual_devs entry for Mio C520-GPS + * USB: usb-storage: unusual_devs entry for Nikon D2H + * ALSA: HDA: hda_proc: Fix printf format specifier + * ALSA: hda - Fix sound on NEC Versa S9100 + * ALSA: hda: Add support for ECS/PC Chips boards with Sigmatel codecs + * ALSA: hda - Fix ALC269 capture source + * ALSA: hda - Add model for Toshiba L305 laptop + * ALSA: hda: fixed hp_nid DAC for DELL_M6 + * ALSA: HDA: patch_analog: Fix SPDIF output on AD1989B + * ALSA: HDA: patch_analog: Quirk for Asus P5Q Premium/Pro boards. + * ALSA: hda: appletv support + * ALSA: hda - Fix another ALC889A (rev 0x100101) + * ALSA: hda - Add ALC887 support + * ALSA: hda - Add support of ALC272 + * ALSA: hda - Restore default pin configs for realtek codecs + * ALSA: hda - Add another HP model for AD1884A + * ALSA: hda - Add a quirk for another Acer Aspire (1025:0090) + * ALSA: hda - Add a quirk for MEDION MD96630 + * ALSA: hda - Add another HP model (6730s) for AD1884A + * ALSA: hda - Make the HP EliteBook 8530p use AD1884A model laptop + * ALSA: hda - No 'Headphone as Line-out' swich without line-outs + * ALSA: hda - mark Dell studio 1535 quirk + * ALSA: emu10k1 - Add more invert_shared_spdif flag to Audigy models + * cxgb3 - fix race in EEH + * cxgb3 - remove duplicate tests in lro + * sched: fix a bug in sched domain degenerate + * x86: HPET: convert WARN_ON to WARN_ON_ONCE + * x86, memory hotplug: remove wrong -1 in calling init_memory_mapping() + * x86: remove debug code from arch_add_memory() + * sched: CPU remove deadlock fix + * PCI: stop leaking 'slot_name' in pci_create_slot + * PCIe: ASPM: Break out of endless loop waiting for PCI config bits to + switch + * uml: boot broken due to buffer overrun + * pagemap: fix 32-bit pagemap regression + * fix mapping_writably_mapped() + * atv: hid quirk for appletv IR receiver + * Allow recursion in binfmt_script and binfmt_misc + * tracehook: exec double-reporting fix + * powerpc/virtex5: Fix Virtex5 machine check handling + * ACPI: delete OSI(Linux) DMI dmesg spam + * cifs: fix a regression in cifs umount codepath + * pnp: make the resource type an unsigned long + * powerpc: Use cpu_thread_in_core in smp_init for of_spin_map + * XFS: Fix hang after disallowed rename across directory quota domains + * applicom: Fix an unchecked user ioctl range and an error return + * ib700wdt.c - fix buffer_underflow bug + * Linux 2.6.27.9 + - LP: #308761 + * lib/idr.c: Fix bug introduced by RCU fix + + [ Zhao Yakui ] + + * ACPI: Add "acpi.power_nocheck=1" to disable power state check in power + transition + - LP: #69925 + * ACPI: Attach the ACPI device to the ACPI handle as early as possible + - LP: #69925 + * ACPI: Add DMI check to disable power state check in power transition + - LP: #69925 + + -- Tim Gardner Mon, 24 Nov 2008 10:50:51 -0700 + +linux (2.6.27-10.20) intrepid-proposed; urgency=low + + [ Andy Whitcroft ] + + * SAUCE: update toshiba_acpi module to development snapshot 19a + - LP: #269831 + * SAUCE: toshiba_acpi -- convert to modern seq_file proc interfaces + - LP: #269831 + * move toshiba laptops back from tlsup to toshiba_acpi + - LP: #269831 + + [ Jim Lieb ] + + * SAUCE: Encryption keys can span a page boundary + - LP: #292429 + + [ Leann Ogasawara ] + + * Reboot stalls after installing Intrepid from alternate on a Dell + Optiplex 330 + - LP: #293372 + + [ Mohamed Abbas ] + + * SAUCE: iwlagn -- fix rfkill when on when driver loaded + - LP: #193970 + + [ Stefan Bader ] + + * (no-up) buildenv: Update git-ubuntu-log + + [ Steve Conklin ] + + * Fix typo in installer module list + - LP: #292411 + * Add HID quirk for dual USB gamepad + - LP: #140608 + + [ Tim Gardner ] + + * Revert "SAUCE: iwlagn: avoid sleep in softirq context" + * SAUCE: Firmware Version is invalid in cciss (version 2) + - LP: #284031 + * Add igb to debian installer udeb + - LP: #290073 + * Fix Vcs-Git path for the kernel repository. + - LP: #296915 + * [intrepid] Headphone jack doesn't work anymore - Dell Studio 15 + - LP: #294418 + + [ Upstream Kernel Changes ] + + * Revert "HID: Invert HWHEEL mappings for some Logitech mice" + * md: fix bug in raid10 recovery. + - LP: #285156 + * SCSI: sd: Fix handling of NO_SENSE check condition + * S390: Fix sysdev class file creation. + * sysfs: Fix return values for sysdev_store_{ulong, int} + * USB: fix crash when URBs are unlinked after the device is gone + * ALSA: hda - Add reboot notifier + * kbuild: mkspec - fix build rpm + * x86: fix /dev/mem mmap breakage when PAT is disabled + * atl1: fix vlan tag regression + * libertas: fix buffer overrun + * libata: initialize port_task when !CONFIG_ATA_SFF + * syncookies: fix inclusion of tcp options in syn-ack + * tcpv6: fix option space offsets with md5 + * pkt_sched: sch_generic: Fix oops in sch_teql + * sparc64: Fix race in arch/sparc64/kernel/trampoline.S + * math-emu: Fix signalling of underflow and inexact while packing result. + * firewire: fix setting tag and sy in iso transmission + * firewire: fix ioctl() return code + * firewire: Survive more than 256 bus resets + * firewire: fix struct fw_node memory leak + * firewire: fw-sbp2: delay first login to avoid retries + * firewire: fw-sbp2: fix races + * ACPI: Always report a sync event after a lid state change + * powerpc: fix i2c on PPC linkstation / kurobox machines + * powerpc: Reserve in bootmem lmb reserved regions that cross NUMA nodes + * powerpc/numa: Make memory reserve code more robust + * powerpc: Don't use a 16G page if beyond mem= limits + * i2c: The i2c mailing list is moving + * scx200_i2c: Add missing class parameter + * ALSA: use correct lock in snd_ctl_dev_disconnect() + * V4L: pvrusb2: Keep MPEG PTSs from drifting away + * DVB: s5h1411: bugfix: Setting serial or parallel mode could destroy + bits + * DVB: s5h1411: Perform s5h1411 soft reset after tuning + * DVB: s5h1411: Power down s5h1411 when not in use + * PCI: fix 64-vbit prefetchable memory resource BARs + * sched: disable the hrtick for now + * sched_clock: prevent scd->clock from moving backwards + * x86: avoid dereferencing beyond stack + THREAD_SIZE + * rtc-cmos: look for PNP RTC first, then for platform RTC + * USB: storage: Avoid I/O errors when issuing SCSI ioctls to JMicron + USB/ATA bridge + * sata_promise: add ATA engine reset to reset ops + * sata_nv: fix generic, nf2/3 detection regression + * ACPI: EC: Rename some variables + * ACPI: EC: Check for IBF=0 periodically if not in GPE mode + * libata: Fix LBA48 on pata_it821x RAID volumes. + * ACPI: Ingore the RESET_REG_SUP bit when using ACPI reset mechanism + * ACPI: Clear WAK_STS on resume + * hfsplus: fix Buffer overflow with a corrupted image (CVE-2008-4933) + * hfsplus: check read_mapping_page() return value (CVE-2008-4934) + * bonding: fix panic when taking bond interface down before removing + module + * file caps: always start with clear bprm->caps_* + * net: Fix recursive descent in __scm_destroy(). (CVE-2008-5029) + * Linux 2.6.27.5 + -LP: #300558 + * ext3: wait on all pending commits in ext3_sync_fs + * x86: add DMI quirk for AMI BIOS which corrupts address 0xc000 during + resume + * x86: reserve low 64K on AMI and Phoenix BIOS boxen + * x86: add X86_RESERVE_LOW_64K + * x86: fix CONFIG_X86_RESERVE_LOW_64K=y + * x86: fix macro with bad_bios_dmi_table + * cgroups: fix invalid cgrp->dentry before cgroup has been completely + removed + * hugetlb: pull gigantic page initialisation out of the default path + * hugetlbfs: handle pages higher order than MAX_ORDER + * cciss: fix sysfs broken symlink regression + * cciss: new hardware support + * md: linear: Fix a division by zero bug for very small arrays. + * JFFS2: fix race condition in jffs2_lzo_compress() + * JFFS2: Fix lack of locking in thread_should_wake() + * ARM: xsc3: fix xsc3_l2_inv_range + * MTD: [NOR] Fix cfi_send_gen_cmd handling of x16 devices in x8 mode (v4) + * x86: don't use tsc_khz to calculate lpj if notsc is passed + * net: unix: fix inflight counting bug in garbage collector + * r8169: get ethtool settings through the generic mii helper + * r8169: fix RxMissed register access + * r8169: wake up the PHY of the 8168 + * I/OAT: fix channel resources free for not allocated channels + * I/OAT: fix dma_pin_iovec_pages() error handling + * I/OAT: fix async_tx.callback checking + * dca: fixup initialization dependency + * iwlwifi: allow consecutive scans in unassociated state + * iwlwifi: allow association on radar channel in power save + * iwlwifi: remove HT flags from RXON when not in HT anymore + * iwlwifi: don't fail if scan is issued too early + * iwlwifi: use correct DMA_MASK + * iwlwifi: fix suspend to RAM in iwlwifi + * iwlwifi: generic init calibrations framework + * zd1211rw: Add 2 device IDs + * iwl3945: fix deadlock on suspend + * iwl3945: do not send scan command if channel count zero + * cpqarry: fix return value of cpqarray_init() + * ACPI: dock: avoid check _STA method + * ARM: 5300/1: fixup spitz reset during boot + * KEYS: Make request key instantiate the per-user keyrings + * libata: fix last_reset timestamp handling + * Fix __pfn_to_page(pfn) for CONFIG_DISCONTIGMEM=y + * mmc: increase SD write timeout for crappy cards + * hfs: fix namelength memory corruption (CVE-2008-5025) + * HID: fix incorrent length condition in hidraw_write() + * Linux 2.6.27.6 + -LP: #300560 + * sony-laptop: ignore missing _DIS method on pic device + - LP: #283126 + * Fix broken ownership of /proc/sys/ files + - LP: #298887 + * touch_mnt_namespace when the mount flags change + * iwlagn: avoid sleep in softirq context + * ath5k: fix suspend-related oops on rmmod + * ath5k: Fix reset sequence for AR5212 in general and RF5111 in + particular + * bnx2x: Removing the PMF indication when unloading + * bnx2x: PCI configuration bug on big-endian + * bnx2x: Calling netif_carrier_off at the end of the probe + * ARM: 5329/1: Feroceon: fix feroceon_l2_inv_range + * Fix platform drivers that crash on suspend/resume + * hostap: pad the skb->cb usage in lieu of a proper fix + * ACPI: avoid empty file name in sysfs + * ACPI: EC: make kernel messages more useful when GPE storm is detected + * hugetlb: make unmap_ref_private multi-size-aware + * rtl8187: Add Abocom USB ID + * rtl8187 : support for Sitecom WL-168 0001 v4 + * kbuild: Fixup deb-pkg target to generate separate firmware deb + * block: fix nr_phys_segments miscalculation bug + * powerpc/mpic: Fix regression caused by change of default IRQ affinity + * memory hotplug: fix page_zone() calculation in test_pages_isolated() + * r8169: select MII in Kconfig + * net: fix /proc/net/snmp as memory corruptor + * V4L/DVB (9624): CVE-2008-5033: fix OOPS on tvaudio when controlling + bass/treble + * S390: cpu topology: fix locking + * ACPI : Load device driver according to the status of acpi device + * m68k: Fix off-by-one in m68k_setup_user_interrupt() + * SCSI: qla2xxx: Return a FAILED status when abort mailbox-command fails. + * SCSI: qla2xxx: Do not honour max_vports from firmware for 2G ISPs and + below. + * SCSI: qla2xxx: Correct Atmel flash-part handling. + * SCSI: dpt_i2o: fix transferred data length for scsi_set_resid() + * dm raid1: flush workqueue before destruction + * USB: remove optional bus bindings in isp1760, fixing runtime warning + * USB: gadget: cdc-acm deadlock fix + * USB: unusual_devs entry for Argosy USB mass-storage interface + * USB: Fix PS3 USB shutdown problems + * USB: cdc-acm.c: fix recursive lock in acm_start_wb error path + * USB: EHCI: fix divide-by-zero bug + * USB: EHCI: fix handling of dead controllers + * USB: don't register endpoints for interfaces that are going away + * ACPI: EC: revert msleep patch + * ACPI: EC: wait for last write gpe + * ACPI: EC: restart failed command + * ACPI: EC: lower interrupt storm treshold + * ACPI: EC: Don't do transaction from GPE handler in poll mode. + * Linux 2.6.27.7 + -LP: #300561 + * V4L/DVB (9621): Avoid writing outside shadow.bytes[] array (unnumbered CVE) + + -- Tim Gardner Fri, 07 Nov 2008 09:37:42 -0700 + +linux (2.6.27-8.17) intrepid-proposed; urgency=low + + [ John W. Linville ] + + * SAUCE: iwlagn: avoid sleep in softirq context + -LP: #286285 + + [ Tim Gardner ] + + * Dell Wireless 365 needs BTUSB_RESET quirk. + - LP: #293670 + * SAUCE: ALSA: hda: make a STAC_DELL_EQ option (version 2) + - LP: #293271 + + [ Upstream Kernel Changes ] + + * iwlagn: downgrade BUG_ON in interrupt + * Input: atkbd - expand Latitude's force release quirk to other Dells + * fbcon_set_all_vcs: fix kernel crash when switching the rotated consoles + * modules: fix module "notes" kobject leak + * Driver core: Fix cleanup in device_create_vargs(). + * Driver core: Clarify device cleanup. + * ath9k/mac80211: disallow fragmentation in ath9k, report to userspace + * md: Fix rdev_size_store with size == 0 + * xfs: fix remount rw with unrecognized options + * OHCI: Allow broken controllers to auto-stop + * USB: OHCI: fix endless polling behavior + * USB: Fix s3c2410_udc usb speed handling + * USB: EHCI: log a warning if ehci-hcd is not loaded first + * usb gadget: cdc ethernet notification bugfix + * usb: musb_hdrc build fixes + * drm/i915: fix ioremap of a user address for non-root (CVE-2008-3831) + * DVB: au0828: add support for another USB id for Hauppauge HVR950Q + * DVB: sms1xxx: support two new revisions of the Hauppauge WinTV + MiniStick + * security: avoid calling a NULL function pointer in + drivers/video/tvaudio.c + * Linux 2.6.27.3 + -LP: #294152 + + * gpiolib: fix oops in gpio_get_value_cansleep() + * edac cell: fix incorrect edac_mode + * x86 ACPI: fix breakage of resume on 64-bit UP systems with SMP kernel + * sched: fix the wrong mask_len + * USB: cdc-wdm: make module autoload work + * USB: don't rebind drivers after failed resume or reset + * USB: fix memory leak in cdc-acm + * USB: Speedtouch: add pre_reset and post_reset routines + * dm kcopyd: avoid queue shuffle + * dm snapshot: fix primary_pe race + * amd_iommu: fix nasty bug that caused ILLEGAL_DEVICE_TABLE_ENTRY errors + * CIFS: fix saving of resume key before CIFSFindNext + * netfilter: xt_iprange: fix range inversion match + * netfilter: snmp nat leaks memory in case of failure + * netfilter: restore lost ifdef guarding defrag exception + * anon_vma_prepare: properly lock even newly allocated entries + * hvc_console: Fix free_irq in spinlocked section + * ACPI Suspend: Enable ACPI during resume if SCI_EN is not set + * ACPI suspend: Blacklist HP xw4600 Workstation for old code ordering + * ACPI suspend: Always use the 32-bit waking vector + * proc: fix vma display mismatch between /proc/pid/{maps,smaps} + * SCSI: scsi_dh: add Dell product information into rdac device handler + * PCI hotplug: cpqphp: fix kernel NULL pointer dereference + * V4L/DVB (9300): pvrusb2: Fix deadlock problem + * Linux 2.6.27.4 + -LP: #294155 + + -- Tim Gardner Tue, 04 Nov 2008 12:16:07 -0700 + +linux (2.6.27-7.16) intrepid-security; urgency=low + + [ Tim Gardner ] + + * ndiswrapper remote buffer overflows on long ESSIDs (CVE 2008-4395) + - LP: #275860 + + [ Upstream Kernel Changes ] + + * ext[234]: Avoid printk floods in the face of directory corruption + (CVE-2008-3528) + + -- Tim Gardner Mon, 03 Nov 2008 13:34:42 -0700 + +linux (2.6.27-7.15) intrepid-security; urgency=low + + [ Upstream Kernel Changes ] + + * tcp: Restore ordering of TCP options for the sake of inter-operability + - LP: #264019 + + -- Tim Gardner Mon, 27 Oct 2008 19:28:06 -0600 + +linux (2.6.27-7.14) intrepid; urgency=low + + [ Tim Gardner ] + + * Disable ath5k in 2.6.27 + - LP: #288148 + + -- Tim Gardner Thu, 23 Oct 2008 07:40:43 -0600 + +linux (2.6.27-7.13) intrepid; urgency=low + + [ Stefan Bader ] + + * gfs1: GFS1 can't create more than 4kb file + + [ Tim Gardner ] + + * Revert "SAUCE: x86: Reserve FIRST_DEVICE_VECTOR in used_vectors + bitmap.". Use upstream commit to avoid future conflicts. + * Revert "STABLE queue: mac80211: fix two issues in debugfs". + Use upstream commit to avoid future conflicts. + * Revert "x86, early_ioremap: fix fencepost error" + Use upstream commit to avoid future conflicts. + + [ Upstream Kernel Changes ] + + * sched_rt.c: resch needed in rt_rq_enqueue() for the root rt_rq + * x86: Reserve FIRST_DEVICE_VECTOR in used_vectors bitmap. + * mac80211: fix two issues in debugfs + * Fix barrier fail detection in XFS + * tty: Termios locking - sort out real_tty confusions and lock reads + * CIFS: make sure we have the right resume info before calling + CIFSFindNext + * rfkill: update LEDs for all state changes + * libertas: clear current command on card removal + * b43legacy: Fix failure in rate-adjustment mechanism + * x86, early_ioremap: fix fencepost error + * x86: SB450: skip IRQ0 override if it is not routed to INT2 of IOAPIC + * x86: improve UP kernel when CPU-hotplug and SMP is enabled + * sky2: Fix WOL regression + * netdrvr: atl1e: Don't take the mdio_lock in atl1e_probe + * Linux 2.6.27.2 + + [ Amit Kucheria ] + + * Ubuntu: agp: Fix stolen memory counting on G4X. + -LP: 285572 + + [ Scott Remnant ] + + * add MODULE_ALIAS to load ipmi_devintf with ipmi_si + + -- Tim Gardner Sun, 19 Oct 2008 10:06:21 -0600 + +linux (2.6.27-7.12) intrepid; urgency=low + + [ Chuck Short ] + + * xen: Add xen modules to virtual flavours. + + [ Mario Limonciello ] + + * SAUCE: Add back in lost commit for Apple BT Wireless Keyboard + - LP: #162083 + + [ Tim Gardner ] + + * Remove depmod created files from packages. + - LP: #250511 + * Changed default TCP congestion algorithm to 'cubic' (again) + - LP: #278801 + * Update configs for 'disable CONFIG_DYNAMIC_FTRACE' + - LP: #263555 + + [ Upstream Kernel Changes ] + + * x86: register a platform RTC device if PNP doesn't describe it + * disable CONFIG_DYNAMIC_FTRACE due to possible memory corruption on + module unload + + -- Tim Gardner Fri, 17 Oct 2008 11:25:39 -0600 + +linux (2.6.27-7.11) intrepid; urgency=low + + [ Amit Kucheria ] + + * STABLE queue: mac80211: fix two issues in debugfs + - LP: #275227 + * SAUCE: Adds support for COMPAL JHL90 webcam + + [ Ben Collins ] + + * SAUCE: (no-up) x86: Quiet "Kernel alive" messages + - LP: #39985 + * SAUCE: (no-up) Modularize vesafb + * build/config: Enable vesafb module + * build: Switch to vesafb as preferred. + + [ Leann Ogasawara ] + + * Add Dell Dimension 9200 reboot quirk + - LP: #271370 + + [ Michael Haas ] + + * SAUCE: Revert aufs changes from AppArmor merge + + [ Tim Gardner ] + + * fix virtio udeb layout + - LP: #257739 + * Enabled CONFIG_EXT4DEV_FS=m + * Changed default TCP congestion algorithm to 'cubic' + - LP: #278801 + * SAUCE: ipw2200: change default policy for auto-associate + - LP: #264104 + + [ Upstream Kernel Changes ] + + * x86, early_ioremap: fix fencepost error + - LP: #263543 + + -- Tim Gardner Sat, 11 Oct 2008 08:07:42 -0600 + +linux (2.6.27-7.10) intrepid; urgency=low + + [ Alexey Starikovskiy ] + + * SAUCE: ACPI: EC: do transaction from interrupt context + - LP: #277802 + + [ Ben Collins ] + + * build/d-i: Change virtio-modules udeb to prio standard + + [ Colin Ian King ] + + * SAUCE: Blacklist IBM 2656 in serio/i8042 + - LP: #21558 + + [ Henrik Rydberg ] + + * Revert "SAUCE: applesmc: Add MacBookAir" + * SAUCE: [PATCH 1/5] hwmon: applesmc: Specified number of bytes to read + should match actual + * SAUCE: [PATCH 2/5] hwmon: applesmc: Fix the 'wait status failed: c != + 8' problem + * SAUCE: [PATCH 3/5] hwmon: applesmc: Prolong status wait + * SAUCE: [PATCH 4/5] hwmon: applesmc: Allow for variable ALV0 and ALV1 + package length + * SAUCE: [PATCH 5/5] hwmon: applesmc: Add support for Macbook Air + * SAUCE: hwmon: applesmc: Add support for Macbook Pro 4 + * SAUCE: hwmon: applesmc: Add support for Macbook Pro 3 + * SAUCE: hwmon: applesmc: Lighter wait mechanism, drastic improvement + + [ Leann Ogasawara ] + + * Add automatic model setting for Samsung Q45 + - LP: #200210 + + [ Tim Gardner ] + + * SAUCE: Correctly blacklist Thinkpad r40e in ACPI + - LP: #278794 + * SAUCE: Update Wacom tablet driver to 1.49 + - LP: #260675 + * SAUCE: ALPS touchpad for Dell Latitude E6500/E6400 + - LP: #270643 + * SAUCE: Fix Wacom tablet 1.49 porting errors + * SAUCE: Enable an e1000e Intel Corporation 82567 Gigabit controller + * SAUCE: Fix Oops in wlan_setup + - LP: #263309 + + [ Upstream Kernel Changes ] + + * ath9k: fix oops on trying to hold the wrong spinlock + * [Bluetooth] Fix double frees on error paths of btusb and bpa10x drivers + * [Bluetooth] Add reset quirk for new Targus and Belkin dongles + * [Bluetooth] Add reset quirk for A-Link BlueUSB21 dongle + * Revert "ax25: Fix std timer socket destroy handling." + * ax25: Quick fix for making sure unaccepted sockets get destroyed. + * netrom: Fix sock_orphan() use in nr_release + * Revert "V4L/DVB (8904): cx88: add missing unlock_kernel" + * SLOB: fix bogus ksize calculation + * net: only invoke dev->change_rx_flags when device is UP + * tcp: Fix possible double-ack w/ user dma + * net: Fix netdev_run_todo dead-lock + * tcp: Fix tcp_hybla zero congestion window growth with small rho and large cwnd. + * [MIPS] Sibyte: Register PIO PATA device only for Swarm and Litte Sur + * eeepc-laptop: Fix hwmon interface + * hwmon: (it87) Prevent power-off on Shuttle SN68PT + * hwmon: Define sysfs interface for energy consumption register + * hwmon: (adt7473) Fix some bogosity in documentation file + * hwmon: (abituguru3) Enable reading from AUX3 fan on Abit AT8 32X + * hwmon: (abituguru3) Enable DMI probing feature on Abit AT8 32X + * [CPUFREQ] correct broken links and email addresses + * SLOB: fix bogus ksize calculation fix + * Don't allow splice() to files opened with O_APPEND + * Linux 2.6.27 + + -- Tim Gardner Wed, 08 Oct 2008 21:19:34 -0600 + +linux (2.6.27-6.9) intrepid; urgency=low + + [ Kees Cook ] + + * SAUCE: AppArmor: update to upstream subversion r1302 + - LP: #269921 + + [ Stefan Bader ] + + * Update configuration files to be compliant to desktop specs + - LP: #279019 + + [ Tim Gardner ] + + * Add support in e1000e for a couple of ICH10 PCI IDs + * Enable CONFIG_INPUT_PCSPKR=m + - LP: #275453 + + [ Upstream Kernel Changes ] + + * V4L/DVB (8559a): Fix a merge conflict at gspca/sonixb + * V4L/DVB (8789): wm8739: remove wrong kfree + * V4L/DVB (8883): w9968cf: Fix order of usb_alloc_urb validation + * V4L/DVB (8884): em28xx-audio: fix memory leak + * V4L/DVB (8885): cpia2_usb: fix memory leak + * V4L/DVB (8886): ov511: fix memory leak + * V4L/DVB (8887): gspca: fix memory leak + * V4L/DVB (8892): pvrusb2: Handle USB ID 2040:2950 same as 2040:2900 + * V4L/DVB (8904): cx88: add missing unlock_kernel + * V4L/DVB (8905): ov511: fix exposure sysfs attribute bug + * V4L/DVB (8909): gspca: PAC 7302 webcam 093a:262a added. + * hrtimer: migrate pending list on cpu offline + * hrtimer: fix migration of CB_IRQSAFE_NO_SOFTIRQ hrtimers + * hrtimer: mark migration state + * hrtimer: prevent migration of per CPU hrtimers + * [IA64] Put the space for cpu0 per-cpu area into .data section + * powerpc: Fix PCI in Holly device tree + * powerpc: Fix failure to shutdown with CPU hotplug + * mfd: Fix Kconfig accroding to the new gpiolib symbols + * mfd: Fix asic3 compilation + * x86: fix typo in enable_mtrr_cleanup early parameter + * ipsec: Fix pskb_expand_head corruption in xfrm_state_check_space + * iucv: Fix mismerge again. + * ALSA: ASoC: Fix cs4270 error path + * ALSA: hda - Fix model for Dell Inspiron 1525 + * sctp: Fix kernel panic while process protocol violation parameter + * x86: Fix broken LDT access in VMI + * x86, vmi: fix broken LDT access + * tcp: Fix NULL dereference in tcp_4_send_ack() + * ipv6: NULL pointer dereferrence in tcp_v6_send_ack + * XFRM,IPv6: initialize ip6_dst_blackhole_ops.kmem_cachep + * af_key: Free dumping state on socket close + * dm: always allow one page in dm_merge_bvec + * dm: cope with access beyond end of device in dm_merge_bvec + * dm mpath: add missing path switching locking + * MN10300: Fix IRQ handling + * pxa2xx_spi: fix build breakage + * e1000e: write protect ICHx NVM to prevent malicious write/erase + * powerpc: Fix boot hang regression on MPC8544DS + * ASoC: Set correct name for WM8753 rec mixer output + * ALSA: snd-powermac: mixers for PowerMac G4 AGP + * ALSA: snd-powermac: HP detection for 1st iMac G3 SL + * fbcon: fix monochrome color value calculation + * inotify: fix lock ordering wrt do_page_fault's mmap_sem + * braille_console: only register notifiers when the braille console is used + * fix error-path NULL deref in alloc_posix_timer() + * memory hotplug: missing zone->lock in test_pages_isolated() + * mm: tiny-shmem nommu fix + * mm: handle initialising compound pages at orders greater than MAX_ORDER + * e1000e: reset swflag after resetting hardware + * e1000e: do not ever sleep in interrupt context + * e1000e: remove phy read from inside spinlock + * e1000e: drop stats lock + * e1000e: debug contention on NVM SWFLAG + * e1000e: update version from k4 to k6 + * Check mapped ranges on sysfs resource files + * e1000e: Fix incorrect debug warning + * [MIPS] Build fix: Fix irq flags type + * [MIPS] SMTC: Build fix: Fix filename in Makefile + * [MIPS] SMTC: Fix holes in SMTC and FPU affinity support. + * [MIPS] SMTC: Close tiny holes in the SMTC IPI replay system. + * [MIPS] SMTC: Fix SMTC dyntick support. + * [S390] nohz: Fix __udelay. + * [S390] qdio: prevent stack clobber + * Fix init/main.c to use regular printk with '%pF' for initcall fn + * x86 setup: correct segfault in generation of 32-bit reloc kernel + * selinux: Fix an uninitialized variable BUG/panic in selinux_secattr_to_sid() + * rtc: fix kernel panic on second use of SIGIO nofitication + * fbdev: fix recursive notifier and locking when fbdev console is blanked + * orion_spi: fix handling of default transfer speed + * include/linux/stacktrace.h: declare struct task_struct + * cpusets: remove pj from cpuset maintainers + * MAINTAINERS: add mailing list for man-pages + * SubmitChecklist: interfaces changes should CC linux-api@ + * Documentation/HOWTO: info about interface changes should CC linux-api@vger + * dw_dmac: fix copy/paste bug in tasklet + * leds-fsg: change order of initialization and deinitialization + * leds-pca955x: add proper error handling and fix bogus memory handling + * ACPI: Make /proc/acpi/wakeup interface handle PCI devices (again) + * clockevents: check broadcast tick device not the clock events device + * V4L/DVB (8919): cx18: Fix tuner audio input for Compro H900 cards + * V4L/DVB (8926): gspca: Bad fix of leak memory (changeset 43d2ead315b1). + * V4L/DVB (8933): gspca: Disable light frquency for zc3xx cs2102 Kokom. + * V4L/DVB (8935): em28xx-cards: Remove duplicate entry (EM2800_BOARD_KWORLD_USB2800) + * V4L/DVB (8955): bttv: Prevent NULL pointer dereference in radio_open + * V4L/DVB (8957): zr36067: Restore the default pixel format + * V4L/DVB (8958): zr36067: Return proper bytes-per-line value + * V4L/DVB (8960): drivers/media/video/cafe_ccic.c needs mm.h + * V4L/DVB (8961): zr36067: Fix RGBR pixel format + * V4L/DVB (8963): s2255drv field count fix + * V4L/DVB (8967): Use correct XC3028L firmware for AMD ATI TV Wonder 600 + * V4L/DVB (8978): sms1xxx: fix product name for Hauppauge WinTV MiniStick + * V4L/DVB (8979): sms1xxx: Add new USB product ID for Hauppauge WinTV MiniStick + * V4L/DVB (9029): Fix deadlock in demux code + * V4L/DVB (9037): Fix support for Hauppauge Nova-S SE + * V4L/DVB (9043): S5H1420: Fix size of shadow-array to avoid overflow + * V4L/DVB (9053): fix buffer overflow in uvc-video + * V4L/DVB (9075): gspca: Bad check of returned status in i2c_read() spca561. + * V4L/DVB (9080): gspca: Add a delay after writing to the sonixj sensors. + * V4L/DVB (9092): gspca: Bad init values for sonixj ov7660. + * V4L/DVB (9099): em28xx: Add detection for K-WORLD DVB-T 310U + * V4L/DVB (9103): em28xx: HVR-900 B3C0 - fix audio clicking issue + * x86: gart iommu have direct mapping when agp is present too + * ide-cd: temporary tray close fix + * ide-dma: fix ide_build_dmatable() for TRM290 + * IDE: Fix platform device registration in Swarm IDE driver (v2) + * ide-cd: Optiarc DVD RW AD-7200A does play audio + * ide: workaround for bogus gcc warning in ide_sysfs_register_port() + * [MIPS] Fix CMP Kconfig configuration and mark as broken. + * [MIPS] IP27: Fix build errors if CONFIG_MAPPED_KERNEL=y + * x86 ACPI: Blacklist two HP machines with buggy BIOSes + * kgdb, x86: Avoid invoking kgdb_nmicallback twice per NMI + * kgdb: call touch_softlockup_watchdog on resume + * atmel-mci: Initialize BLKR before sending data transfer command + * Marker depmod fix core kernel list + * Linux 2.6.27-rc9 + + -- Tim Gardner Sun, 05 Oct 2008 21:27:49 -0600 + +linux (2.6.27-5.8) intrepid; urgency=low + + [ Amit Kucheria ] + + * Update AUFS-related Kconfig + - LP: #264048 + + [ Michael Haas ] + + * add proper aufs source tree from 20080922 + * Fix AUFS compilation in vfsub.c + * Add splice-2.6.23.patch from AUFS to export a symbol needed by AUFS + * Add put_filp.patch from AUFS to export a symbol needed by AUFS + * apply (modified) lhash.patch from AUFS to export __lookup_hash() + * Add deny_write_access.patch from AUFS - export deny_write_access + * Add sec_perm-2.6.24.patch from AUFS - export security_inode_permission + * make sure TMPFS_MAGIC is defined in AUFS Makefile + + [ Tim Gardner ] + + * Enabled CONFIG_IPWIRELESS + - LP: #274748 + * Enabled CONFIG_E1000E, disabled CONFIG_E1000E_NEW + This takes advantage of the upstream NVM protection fix in + commit 4a7703582836f55a1cbad0e2c1c6ebbee3f9b3a7. + + [ Upstream Kernel Changes ] + + * Revert "[Bluetooth] Eliminate checks for impossible conditions in IRQ + handler" + * [SCSI] qla2xxx: Defer enablement of RISC interrupts until ISP + initialization completes. + * PCI: Fix pcie_aspm=force + * PCI: fix compiler warnings in pci_get_subsys() + * UBIFS: create the name of the background thread in every case + * UBIFS: TNC / GC race fixes + * UBIFS: remove incorrect assert + * UBIFS: fix printk format warnings + * AMD IOMMU: set iommu sunc flag after command queuing + * AMD IOMMU: protect completion wait loop with iommu lock + * sparc64: Fix disappearing PCI devices on e3500. + * x86, oprofile: BUG scheduling while atomic + * ALSA: ASoC: Fix at32-pcm build breakage with PM enabled + * ath9k: connectivity is lost after Group rekeying is done + * wireless: zd1211rw: add device ID fix wifi dongle "trust nw-3100" + * [IA64] Ski simulator doesn't need check_sal_cache_flush + * [IA64] kexec fails on systems with blocks of uncached memory + * ath9k: Fix IRQ nobody cared issue with ath9k + * [Bluetooth] Fix I/O errors on MacBooks with Broadcom chips + * [Bluetooth] Fix wrong URB handling of btusb driver + * [Bluetooth] Fix USB disconnect handling of btusb driver + * sparc64: Fix missing devices due to PCI bridge test in + of_create_pci_dev(). + * [WATCHDOG] ibmasr: remove unnecessary spin_unlock() + * [WATCHDOG] wdt285: fix sparse warnings + * [WATCHDOG] unlocked_ioctl changes + * x86: fix 27-rc crash on vsmp due to paravirt during module load + * sched: fix init_hrtick() section mismatch warning + * clockevents: prevent cpu online to interfere with nohz + * x86: prevent stale state of c1e_mask across CPU offline/online + * clockevents: prevent stale tick_next_period for onlining CPUs + * clockevents: check broadcast device not tick device + * clockevents: prevent mode mismatch on cpu online + * x86: prevent C-states hang on AMD C1E enabled machines + * x86: c1e_idle: don't mark TSC unstable if CPU has invariant TSC + * timers: fix build error in !oneshot case + * ALSA: ASoC: maintainers - update email address for Liam Girdwood + * ibmasr: remove unnecessary spin_unlock() + * smb.h: do not include linux/time.h in userspace + * kernel-doc: allow structs whose members are all private + * kexec: fix segmentation fault in kimage_add_entry + * Documentation/DMA-mapping.txt: update for pci_dma_mapping_error() + changes + * sys_paccept: disable paccept() until API design is resolved + * mm: tiny-shmem fix lock ordering: mmap_sem vs i_mutex + * Documentation/sysctl/kernel.txt: fix softlockup_thresh description + * memcg: check under limit at shrink_usage + * atmel_serial: update the powersave handler to match serial core + * [SCSI] Fix hang with split requests + * USB Storage: Sierra: Non-configurable TRU-Install + * USB Serial: Sierra: Device addition & version rev + * USB: ehci: fix some ehci hangs and crashes + * USB: Fix the Nokia 6300 storage-mode. + * USB: Correct Sierra Wireless USB EVDO Modem Device ID + * USB: fix hcd interrupt disabling + * USB: update of Documentation/usb/anchors.txt + * usb gadget: fix omap_udc DMA regression + * USB: Fixing Nokia 3310c in storage mode + * usb: musb: fix include path + * USB: fix EHCI periodic transfers + * usb-serial: Add Siemens EF81 to PL-2303 hack triggers + * USB: SERIAL CP2101 add device IDs + * USB: unusual_devs addition for RockChip MP3 player + * USB: fsl_usb2_udc: fix VDBG() format string + * usb serial: ti_usb_3410_5052 obviously broken by firmware changes + * USB: ftdi_sio: Add 0x5050/0x0900 USB IDs (Papouch Quido USB 4/4) + * USB: serial: add ZTE CDMA Tech id to option driver + * USB Serial: Sierra: Add MC8785 VID/PID + * USB: drivers/usb/musb/: disable it on SuperH + * usb: ftdi_sio: add support for Domintell devices + * usb: unusual devs patch for Nokia 5310 Music Xpress + * USB: revert recovery from transient errors + * [MIPS] au1000: Fix gpio direction + * [MIPS] Fixe the definition of PTRS_PER_PGD + * x86: prevent stale state of c1e_mask across CPU offline/online, fix + * x86: disable apm on the olpc + * i2c-powermac: Fix section for probe and remove functions + * i2c-dev: Return correct error code on class_create() failure + * i2c: Fix mailing lists in two MAINTAINERS entries + * ath9k: disable MIB interrupts to fix interrupt storm + * 9p: implement proper trans module refcounting and unregistration + * 9p-trans_fd: fix trans_fd::p9_conn_destroy() + * 9p-trans_fd: clean up p9_conn_create() + * 9p-trans_fd: don't do fs segment mangling in p9_fd_poll() + * 9p-trans_fd: fix and clean up module init/exit paths + * 9p: introduce missing kfree + * 9p: use an IS_ERR test rather than a NULL test + * 9p: fix put_data error handling + * netfilter: ip6t_{hbh,dst}: Rejects not-strict mode on rule insertion + * MN10300: Move asm-arm/cnt32_to_63.h to include/linux/ + * MN10300: Make sched_clock() report time since boot + * ALSA: fix locking in snd_pcm_open*() and snd_rawmidi_open*() + * ALSA: remove unneeded power_mutex lock in snd_pcm_drop + * IPoIB: Fix crash when path record fails after path flush + * [XFS] Fix extent list corruption in xfs_iext_irec_compact_full(). + * [XFS] Remove xfs_iext_irec_compact_full() + * kgdb: could not write to the last of valid memory with kgdb + * kgdb, x86, arm, mips, powerpc: ignore user space single stepping + * kgdb, x86_64: gdb serial has BX and DX reversed + * kgdb, x86_64: fix PS CS SS registers in gdb serial + * kgdboc,tty: Fix tty polling search to use name correctly + * ARM: Delete ARM's own cnt32_to_63.h + * m32r: remove the unused NOHIGHMEM option + * m32r: don't offer CONFIG_ISA + * m32r: export empty_zero_page + * m32r: export __ndelay + * m32r/kernel/: cleanups + * [MIPS] au1000: Make sure GPIO value is zero or one + * [MIPS] IP27: Switch to dynamic interrupt routing avoding panic on + error. + * [MIPS] BCM47xx: Fix build error due to missing PCI functions + * [SSB] Initialise dma_mask for SSB_BUSTYPE_SSB devices + * Swarm: Fix crash due to missing initialization + * ide-tape: fix vendor strings + * ide: note that IDE generic may prevent other drivers from attaching + * cdrom: update ioctl documentation + * [SCSI] qlogicpti: fix sg list traversal error in continuation entries + * sata_nv: reinstate nv_hardreset() for non generic controllers + * scsi: fix fall out of sg-chaining patch in qlogicpti + * ALSA: make the CS4270 driver a new-style I2C driver + * ALSA: ASoC: Fix another cs4270 error path + * Fix NULL pointer dereference in proc_sys_compare + * kconfig: fix silentoldconfig + * kconfig: readd lost change count + * mm owner: fix race between swapoff and exit + * Linux 2.6.27-rc8 + * e1000e: write protect ICHx NVM to prevent malicious write/erase + + -- Amit Kucheria Tue, 30 Sep 2008 18:22:35 +0300 + +linux (2.6.27-4.7) intrepid; urgency=low + + [ Ben Collins ] + + * build/abi: Add gfs1 to perm blacklist + * build/abi: Ignored changes in gfs2 symbols + + [ Fabio M. Di Nitto ] + + * Revert "SAUCE: Export gfs2 symbols required for gfs1 kernel module" + * ubuntu: update GFS Cluster File System + + [ Stefan Bader ] + + * SAUCE: x86: Reserve FIRST_DEVICE_VECTOR in used_vectors bitmap. + - LP: #276334 + + [ Tim Gardner ] + + * Revert "Disable e1000e until the NVRAM corruption problem is found." + * Add atl1e and atl2 to Debian installer bits + - LP: #273904 + * SAUCE: e1000e: Map NV RAM dynamically only when needed. + - LP: #263555 + + -- Tim Gardner Fri, 26 Sep 2008 20:51:22 -0600 + +linux (2.6.27-4.6) intrepid; urgency=low + + [ Tim Gardner ] + + * Disable e1000e until the NVRAM corruption problem is found. + - LP: #263555 + + [ Upstream Kernel Changes ] + + * Revert "[Bluetooth] Eliminate checks for impossible conditions in IRQ + handler" + + -- Ben Collins Tue, 23 Sep 2008 09:53:57 -0400 + +linux (2.6.27-4.5) intrepid; urgency=low + + [ Upstream Kernel Changes ] + + * Revert "b43/b43legacy: add RFKILL_STATE_HARD_BLOCKED support" + * udf: Fix lock inversion between iprune_mutex and alloc_mutex (v2) + * udf: Fix error paths in udf_new_inode() + * [SCSI] sd: select CRC_T10DIF only when necessary + * [SCSI] zfcp: Fix request queue locking + * [SCSI] zfcp: Correctly query end flag in gpn_ft response + * [SCSI] zfcp: Simplify ccw notify handler + * [SCSI] zfcp: Fix reference counter for remote ports + * [SCSI] zfcp: channel cannot be detached due to refcount imbalance + * [SCSI] zfcp: Remove duplicated unlikely() macros. + * [SCSI] scsi_dh: make check_sense return ADD_TO_MLQUEUE + * [SCSI] make scsi_check_sense HARDWARE_ERROR return ADD_TO_MLQUEUE on + retry + * [SCSI] fix check of PQ and PDT bits for WLUNs + * pcm037: add rts/cts support for serial port + * i.MX serial: fix init failure + * imx serial: set RXD mux bit on i.MX27 and i.MX31 + * imx serial: fix rts handling for non imx1 based hardware + * mlx4_core: Set RAE and init mtt_sz field in FRMR MPT entries + * udf: add llseek method + * PCI/iommu: blacklist DMAR on Intel G31/G33 chipsets + * PCI: Fix printk warnings in probe.c + * PCI: Fix printk warnings in setup-bus.c + * PCI Hotplug: fakephp: fix deadlock... again + * clockevents: remove WARN_ON which was used to gather information + * ocfs2: Fix a bug in direct IO read. + * arch/x86/kernel/kdebugfs.c: introduce missing kfree + * [IA64] fix compile failure with non modular builds + * [IA64] fix up bte.h + * [IA64] arch/ia64/sn/pci/tioca_provider.c: introduce missing kfree + * PCI: fix pciehp_free_irq() + * [IA64] prevent ia64 from invoking irq handlers on offline CPUs + * ide: Fix pointer arithmetic in hpt3xx driver code (3rd try) + * add deprecated ide-scsi to feature-removal-schedule.txt + * swiotlb: fix back-off path when memory allocation fails + * sparc64: Fix interrupt register calculations on Psycho and Sabre. + * VIDEO_SH_MOBILE_CEU should depend on HAS_DMA + * m68k: Update defconfigs for 2.6.27-rc6 + * sparc32: Fix function signature of of_bus_sbus_get_flags(). + * sched: fix 2.6.27-rc5 couldn't boot on tulsa machine randomly + * sched: fix deadlock in setting scheduler parameter to zero + * KVM: SVM: fix random segfaults with NPT enabled + * KVM: SVM: fix guest global tlb flushes with NPT + * KVM: VMX: Always return old for clear_flush_young() when using EPT + * clocksource, acpi_pm.c: fix check for monotonicity + * [ARM] OMAP: Fix MMC device data + * block: disable sysfs parts of the disk command filter + * ath9k: Assign seq# when mac80211 requests this + * sg: disable interrupts inside sg_copy_buffer + * MN10300: Change the fault handler to check in_atomic() not + in_interrupt() + * [Bluetooth] Fix regression from using default link policy + * netlink: fix overrun in attribute iteration + * x86: fix possible x86_64 and EFI regression + * sparc64: Fix PCI error interrupt registry on PSYCHO. + * sparc: Fix user_regset 'n' field values. + * niu: panic on reset + * PCI: re-add debug prints for unmodified BARs + * [ARM] 5245/1: Fix warning about unused return value in drivers/pcmcia + * [ARM] 5246/1: tosa: add proper clock alias for tc6393xb clock + * [ARM] 5247/1: tosa: SW_EAR_IN support + * [ARM] Fix PCI_DMA_BUS_IS_PHYS for ARM + * ata: duplicate variable sparse warning + * sata_inic162x: enable LED blinking + * [libata] LBA28/LBA48 off-by-one bug in ata.h + * proc: more debugging for "already registered" case + * include/linux/ioport.h: add missing macro argument for devm_release_* + family + * cpuset: avoid changing cpuset's cpus when -errno returned + * cpuset: hotplug documentation fix + * coredump_filter: add description of bit 4 + * bfs: fix Lockdep warning + * mm: ifdef Quicklists in /proc/meminfo + * spi_mpc83xx: fix clockrate calculation for low speed + * spi_mpc83xx: reject invalid transfer sizes + * pxa2xx_spi: chipselect bugfixes + * pxa2xx_spi: dma bugfixes + * mm: mark the correct zone as full when scanning zonelists + * Documentation/ABI: /sys/class/gpio + * MAINTAINERS: fix USB VIDEO CLASS mail list address + * ia64: fix panic during `modprobe -r xpc' + * atmel_lcdfb: disable LCD and DMA engines when suspending + * spi_s3c24xx: fix section warning + * rescan_partitions(): make device capacity errors non-fatal + * memstick: fix MSProHG 8-bit interface mode support + * Add Uwe Kleine-Kƶnig to .mailmap + * xen: fix for xen guest with mem > 3.7G + * x86/paravirt: Remove duplicate paravirt_pagetable_setup_{start, done}() + * crypto: talitos - Avoid consecutive packets going out with same IV + * slub: fixed uninitialized counter in struct kmem_cache_node + * udp: Fix rcv socket locking + * IB/mlx4: Fix up fast register page list format + * [MIPS] VR41xx: unsigned irq cannot be negative + * x86: completely disable NOPL on 32 bits + * [S390] cio: Fix driver_data handling for ccwgroup devices. + * [S390] cio: fix orb initialization in cio_start_key + * sparc64: Fix OOPS in psycho_pcierr_intr_other(). + * sparc64: Fix SMP bootup with CONFIG_STACK_DEBUG or ftrace. + * RDMA/nes: Fix client side QP destroy + * IPoIB: Fix deadlock on RTNL between bcast join comp and ipoib_stop() + * clockevents: make device shutdown robust + * powerpc: Fix interrupt values for DMA2 in MPC8610 HPCD device tree + * hpplus: fix build regression + * Fix PNP build failure, bugzilla #11276 + * warn: Turn the netdev timeout WARN_ON() into a WARN() + * [XFS] Move memory allocations for log tracing out of the critical path + * [XFS] Fix regression introduced by remount fixup + * [XFS] Prevent direct I/O from mapping extents beyond eof + * [XFS] Fix barrier status change detection. + * [XFS] Prevent lockdep false positives when locking two inodes. + * [XFS] Fix use-after-free with buffers + * [XFS] Don't do I/O beyond eof when unreserving space + * powerpc: Holly board needs dtbImage target + * Fix compile failure with non modular builds + * [ARM] 5249/1: davinci: remove redundant check in davinci_psc_config() + * [ARM] omap: back out 'internal_clock' support + * sctp: set the skb->ip_summed correctly when sending over loopback. + * [ARM] 5255/1: Update jornada ssp to remove build errors/warnings + * sctp: do not enable peer features if we can't do them. + * sctp: Fix oops when INIT-ACK indicates that peer doesn't support AUTH + * bnx2: Promote vector field in bnx2_irq structure from u16 to unsigned + int + * forcedeth: call restore mac addr in nv_shutdown path + * e1000: prevent corruption of EEPROM/NVM + * e100: Use pci_pme_active to clear PME_Status and disable PME# + * md: Don't wait UNINTERRUPTIBLE for other resync to finish + * atstk1000: fix build breakage with BOARD_ATSTK100X_SW2_CUSTOM=y + * avr32: add .gitignore files + * avr32: add generic_find_next_le_bit bit function + * avr32: fix sys_sync_file_range() call convention + * avr32: nmi_enter() without nmi_exit() + * KVM: ia64: 'struct fdesc' build fix + * hwmon: (atxp1) Fix device detection logic + * hwmon: (it87) Fix fan tachometer reading in IT8712F rev 0x7 (I) + * hwmon: (ad7414) Make ad7414_update_device() static + * tmio_mmc: fix compilation with debug enabled + * atmel-mci: debugfs: enable clock before dumping regs + * atmel-mci: Fix memory leak in atmci_regs_show + * atmel-mci: Fix bogus debugfs file size + * atmel-mci: Set MMC_CAP_NEEDS_POLL if no detect_pin + * mmc_block: handle error from mmc_register_driver() + * mmc_test: initialize mmc_test_lock statically + * [MIPS] Fix 64-bit IP checksum code + * [MIPS] SMTC: Clear TIF_FPUBOUND on clone / fork. + * [MIPS] Fix potential latency problem due to non-atomic cpu_wait. + * [MIPS] vmlinux.lds.S: handle .text.* + * MAINTAINERS: Trivial whitespace cleanups + * MAINTAINERS: Various fixes + * Linux 2.6.27-rc7 + + -- Tim Gardner Sun, 21 Sep 2008 21:49:28 -0600 + +linux (2.6.27-3.4) intrepid; urgency=low + + [ Colin Ian King ] + + * SAUCE: fix kernel oops in VirtualBox during paravirt patching + - LP: #246067 + * SAUCE: qc-usb: Enable Logitech QuickCam Messenger + - LP: #209901 + * SAUCE: appleir: Enable driver for new MacBook Pro + - LP: #157919 + + [ Tim Gardner ] + + * Enabled CONFIG_DEBUG_RODATA=y + + [ Upstream Kernel Changes ] + + * Revert "ALSA: hda - Added model selection for iMac 24"" + * Revert "x86: fix HPET regression in 2.6.26 versus 2.6.25, check hpet + against BAR, v3" + * Revert "[ARM] use the new byteorder headers" + * Revert "mac80211: Use IWEVASSOCREQIE instead of IWEVCUSTOM" + * Revert "crypto: camellia - Use kernel-provided bitops, unaligned access + helpers" + * svcrdma: Fix race between svc_rdma_recvfrom thread and the dto_tasklet + * sched, cpuset: rework sched domains and CPU hotplug handling (v4) + * ACPI: Fix now signed module parameter. + * ACPI: Change package length error to warning + * ACPI: Fix now signed module parameter. + * ACPI: Fix typo in "Disable MWAIT via DMI on broken Compal board" + * acpi: add checking for NULL early param + * UBIFS: fix zero-length truncations + * Input: bcm5974 - add maintainer entry + * sh64: re-add the __strnlen_user() prototype + * sh: fix ptrace_64.c:user_disable_single_step() + * PNPACPI: ignore the producer/consumer bit for extended IRQ descriptors + * UBIFS: always read hashed-key nodes under TNC mutex + * UBIFS: allow for racing between GC and TNC + * [CIFS] Fix plaintext authentication + * sparc32: Implement smp_call_function_single(). + * sh: crash kernel resource fix + * sh: fix kexec entry point for crash kernels + * sh: fix platform_resource_setup_memory() section mismatch + * sh: update Migo-R defconfig + * sh: update AP325RXA defconfig + * sh: fix semtimedop syscall + * cifs: fix O_APPEND on directio mounts + * [CIFS] update cifs change log + * [CIFS] Turn off Unicode during session establishment for plaintext + authentication + * ACPI: thinkpad-acpi: wan radio control is not experimental + * sparc: Fix resource flags for PCI children in OF device tree. + * remove blk_register_filter and blk_unregister_filter in gendisk + * ALSA: oxygen: fix distorted output on AK4396-based cards + * ipv6: When we droped a packet, we should return NET_RX_DROP instead of + 0 + * pkt_sched: Fix locking of qdisc_root with qdisc_root_sleeping_lock() + * net: Unbreak userspace usage of linux/mroute.h + * Don't trigger softlockup detector on network fs blocked tasks + * Resource handling: add 'insert_resource_expand_to_fit()' function + * sparc64: setup_valid_addr_bitmap_from_pavail() should be __init + * UBIFS: do not update min_idx_lebs in stafs + * UBIFS: push empty flash hack down + * UBIFS: remove incorrect index space check + * UBIFS: improve statfs reporting + * UBIFS: fix assertion + * UBIFS: add forgotten gc_idx_lebs component + * UBIFS: introduce LEB overhead + * UBIFS: improve statfs reporting even more + * UBIFS: fill f_fsid + * drm/radeon: downgrade debug message from info to debug. + * Remove invalidate_partition call from do_md_stop. + * Fix problem with waiting while holding rcu read lock in md/bitmap.c + * ALSA: hda: Distortion fix for dell_m6_core_init + * ALSA: ASoC: fix pxa2xx-i2s clk_get call + * block: restore original behavior of /proc/partition when there's no + partition + * debugobjects: fix lockdep warning + * avr32: Fix lockup after Java stack underflow in user mode + * avr32: pm_standby low-power ram bug fix + * nfsd: fix compound state allocation error handling + * sunrpc: fix possible overrun on read of /proc/sys/sunrpc/transports + * nfsd: fix buffer overrun decoding NFSv4 acl + * audit: Moved variable declaration to beginning of function + * Fix modules_install on RO nfs-exported trees. + * Remove '#include ' from mm/page_isolation.c + * dabusb_fpga_download(): fix a memory leak + * [MTD] mtdchar.c: Fix regression in MEMGETREGIONINFO ioctl() + * ALSA: hda - Fix ALC663 auto-probe + * ALSA: hda - Add mic-boost controls to ALC662/663 auto configuration + * Un-break printk strings in x86 PCI probing code + * kernel/resource.c: fix new kernel-doc warning + * softlockup: minor cleanup, don't check task->state twice + * fix typo in arch/parisc/hpux/fs.c + * m68k: atari_keyb_init operator precedence fix + * ACPI: Fix typo in "Disable MWAIT via DMI on broken Compal board" + * don't diff generated firmware files + * IDE: compile fix for sff_dma_ops + * IDE: palm_bk3710: fix compile warning for unused variable + * ide: fix hwif_to_node() + * palm_bk3710: improve IDE registration + * ide-disk: remove stale init_idedisk_capacity() documentation + * ide/Kconfig: mark ide-scsi as deprecated + * net/wireless/Kconfig: clarify the description for + CONFIG_WIRELESS_EXT_SYSFS + * iwlwifi: do not use GFP_DMA in iwl_tx_queue_init + * iwlwifi: workaround interrupt handling no some platforms + * iwlwifi: fix apm_stop (wrong bit polarity for FLAG_INIT_DONE) + * iwlwifi: fix 64bit platform firmware loading + * orinoco: Multicast to the specified addresses + * wireless/libertas/if_cs.c: fix memory leaks + * mac80211: Fix debugfs union misuse and pointer corruption + * rt2x00: Compiler warning unmasked by fix of BUILD_BUG_ON + * ath9k: Incorrect key used when group and pairwise ciphers are + different. + * ath9: Fix ath_rx_flush_tid() for IRQs disabled kernel warning message. + * net/xfrm: Use an IS_ERR test rather than a NULL test + * ipv: Re-enable IP when MTU > 68 + * NTFS: update homepage + * mm: make setup_zone_migrate_reserve() aware of overlapping nodes + * VFS: fix dio write returning EIO when try_to_release_page fails + * acer-wmi: remove debugfs entries upon unloading + * mm/bootmem: silence section mismatch warning - + contig_page_data/bootmem_node_data + * MAINTAINERS: add a maintainer for the BCM5974 multitouch driver + * 8250: improve workaround for UARTs that don't re-assert THRE correctly + * mmc: at91_mci: don't use coherent dma buffers + * pid_ns: zap_pid_ns_processes: fix the ->child_reaper changing + * pid_ns: (BUG 11391) change ->child_reaper when init->group_leader exits + * cirrusfb: check_par fixes + * devcgroup: fix race against rmdir() + * mm: show quicklist usage in /proc/meminfo + * mm: size of quicklists shouldn't be proportional to the number of CPUs + * ipc: document the new auto_msgmni proc file + * hp-wmi: update to match current rfkill semantics + * hp-wmi: add proper hotkey support + * tdfxfb: fix SDRAM memory size detection + * tdfxfb: fix frame buffer name overrun + * rtc_time_to_tm: fix signed/unsigned arithmetic + * ibft: fix target info parsing in ibft module + * sysfs: document files in /sys/firmware/sgi_uv/ + * rtc-cmos: wake again from S5 + * pm_qos_requirement might sleep + * drivers/char/random.c: fix a race which can lead to a bogus BUG() + * ipsec: Fix deadlock in xfrm_state management. + * [x86] Fix TSC calibration issues + * tipc: Don't use structure names which easily globally conflict. + * sparc64: Fix IPI call locking. + * [ARM] omap: fix gpio.c build error + * sparc64: Prevent sparc64 from invoking irq handlers on offline CPUs + * powerpc: Fix uninitialised variable in VSX alignment code + * powerpc: Only make kernel text pages of linear mapping executable + * powerpc: Make sure _etext is after all kernel text + * powerpc: Work around gcc's -fno-omit-frame-pointer bug + * powerpc: Fix build error with 64K pages and !hugetlbfs + * powerpc: Fix for getting CPU number in power_save_ppc32_restore() + * UBIFS: amend f_fsid + * net/usb/pegasus: avoid hundreds of diagnostics + * ixgbe: initialize interrupt throttle rate + * pcnet-cs, axnet_cs: add new IDs, remove dup ID with less info + * netxen: Remove workaround for chipset quirk + * Split up PIT part of TSC calibration from native_calibrate_tsc + * iwlwifi: W/A for the TSF correction in IBSS + * iwlwifi: fix hidden ssid discovery in passive channels + * iwlwifi: remove false rxon if rx chain changes + * iwlwifi: fix station mimo power save values + * iwlwifi: fix rx_chain computation + * iwlwifi: fix Tx cmd memory allocation failure handling + * iwlwifi: call apm stop on exit + * iwlwifi: fix STATUS_EXIT_PENDING is not set on pci_remove + * ath9k: Fix TX status reporting + * ath9k: Fix TX control flag use for no ACK and RTS/CTS + * V4L/DVB (8555): au8522: add mechanism to configure IF frequency for vsb + and qam + * V4L/DVB (8556): au0828: add support for Hauppauge Woodbury + * V4L/DVB (8598): au8522: clean up function au8522_set_if + * V4L/DVB (8599): au8522: remove if frequency settings from vsb/qam + modulation tables + * V4L/DVB (8600): au0828: explicitly set 6 MHz IF frequency in + hauppauge_hvr950q_config + * V4L/DVB (8629): v4l2-ioctl: do not try to handle private V4L1 ioctls + * V4L/DVB (8633): ivtv: update ivtv version number + * V4L/DVB (8648): ivtv: improve CC support + * V4L/DVB (8660): gspca: Simplify the scan of URB packets in pac7311. + * V4L/DVB (8661): gspca: Bug in the previous changeset about pac7311. + * V4L/DVB (8663): gspca: Webcam 0c45:6128 added in sonixj. + * V4L/DVB (8664): gspca: The bridge/sensor of the webcam 093a:2621 is a + PAC 7302. + * V4L/DVB (8665): gspca: Fix the 640x480 resolution of the webcam + 093a:2621. + * V4L/DVB (8666): gspca: Bad scanning of frames in pac7311. + * V4L/DVB (8667): gspca: Bad probe of Z-Star/Vimicro webcams with pas106 + sensor. + * V4L/DVB (8668): gspca: Conflict GSPCA / ET61X251 for the webcam + 102c:6251. + * V4L/DVB (8669): gspca: Add white balance control for spca561 rev 012A. + * V4L/DVB (8671): gspca: Remove the unused field 'dev_name' of the device + structure. + * V4L/DVB (8672): gspca: Big rewrite of spca561. + * V4L/DVB (8673): gspca: Bad frame scanning again and bad init in + pac7311. + * V4L/DVB (8674): gspca: Webcam 0c45:612e added in sonixj. + * V4L/DVB (8675): gspca: Pixmap PJPG (Pixart 73xx JPEG) added, generated + by pac7311. + * V4L/DVB (8678): Remove the dead CONFIG_RADIO_MIROPCM20{,_RDS} code + * V4L/DVB (8681): v4l2-ioctl.c: fix warning + * V4L/DVB (8682): V4L: fix return value of register video func + * V4L/DVB (8701): cx18: Add missing lock for when the irq handler + manipulates the queues + * V4L/DVB (8703): gspca: Do controls work for spca561 revision 12a. + * V4L/DVB (8705): gspca: Adjust some control limits in spca561. + * V4L/DVB (8706): Make contrast and brightness work for pac7302. + * V4L/DVB (8707): gspca: Colors, hflip and vflip controls added for + pac7302. + * V4L/DVB (8709): gspca: Fix initialization and controls of sn9x110 - + ov7630. + * V4L/DVB (8710): gspca: Bad color control in sonixj. + * V4L/DVB (8711): gspca: Bad controls and quantization table of pac7311. + * V4L/DVB (8712): gspca: Bad start of sonixj webcams since changeset + a8779025e7e8. + * V4L/DVB (8713): gspca: Bad color control again in sonixj. + * V4L/DVB (8714): gspca: Bad start of sn9c110 and sensor om6802. + * V4L/DVB (8715): gspca: Change the name of some webcam in the gspca doc. + * V4L/DVB (8716): gspca: Bad start of sn9c110 and sensor ov7630. + * V4L/DVB (8717): gspca: Frame buffer too small for small resolutions + (sonixj and t613). + * V4L/DVB (8718): gspca: suspend/resume added. + * V4L/DVB (8719): gspca: Have VIDIOC_QUERYCTRL more compliant to the + spec. + * V4L/DVB (8720): gspca: V4L2_CAP_SENSOR_UPSIDE_DOWN added as a cap for + some webcams. + * V4L/DVB (8722): sms1xxx: fix typo in license header + * V4L/DVB (8726): link tuner before saa7134 + * V4L/DVB (8727): V4L1: make PMS not autoprobe when builtin. + * V4L/DVB (8728): 1-make-pms-not-autoprobe-when-builtin update + * V4L/DVB (8749): Fix error code, when camera is not turned on by sonypi + * V4L/DVB (8750): V4L: check inval in video_register_device_index() + * V4L/DVB (8751): vivi: Fix some issues at vivi register routine + * V4L/DVB (8757): v4l-dvb: fix a bunch of sparse warnings + * V4L/DVB (8769): cx18: Simplify queue flush logic to prevent oops in + cx18_flush_queues() + * V4L/DVB (8778): radio: fix incorrect video_register_device result check + * V4L/DVB (8779): v4l: fix more incorrect video_register_device result + checks + * V4L/DVB (8790): saa7115: call i2c_set_clientdata only when state != + NULL + * V4L/DVB (8803): s5h1409: Enable QAM_AUTO mode + * V4L/DVB (8804): s5h1411: Enable QAM_AUTO mode + * V4L/DVB (8805): Steven Toth email address change + * V4L/DVB (8809): gspca: Revert commit + 9a9335776548d01525141c6e8f0c12e86bbde982 + * V4L/DVB (8810): gspca: Compile error when CONFIG_PM not defined. + * V4L/DVB (8812): gspca: Do pac73xx webcams work. + * V4L/DVB (8813): gspca: Adjust SOF detection for pac73xx. + * V4L/DVB (8814): gspca: Set DISABLED the disabled controls at query + control time. + * V4L/DVB (8815): gspca: Fix problems with disabled controls. + * V4L/DVB (8816): gspca: Set disabled ctrls and fix a register pb with + ovxxxx in sonixb. + * V4L/DVB (8817): gspca: LED and proble changes in sonixb. + * V4L/DVB (8818): gspca: Reinitialize the device on resume. + * V4L/DVB (8819): gspca: Initialize the ov519 at open time and source + cleanup. + * V4L/DVB (8820): gspca: Change initialization and gamma of zc3xx - + pas106. + * V4L/DVB (8822): gspca: Change some subdriver functions for + suspend/resume. + * V4L/DVB (8823): gspca: H and V flips work for ov7670 only in ov519. + * V4L/DVB (8824): gspca: Too much code removed in the suspend/resume + changeset. + * V4L/DVB (8825): gspca: More controls for pac73xx and new webcam + 093a:2624. + * V4L/DVB (8826): gspca: Webcam Labtec 2200 (093a:2626) added in pac7311. + * V4L/DVB (8827): gspca: Stop pac7302 autogain oscillation. + * V4L/DVB (8828): gspca: Set the clock at the end of initialization in + sonixj. + * V4L/DVB (8829): gspca: Have a clean kmalloc-ated buffer for USB + exchanges. + * V4L/DVB (8830): gspca: Move some probe code to the new init function. + * V4L/DVB (8831): gspca: Resolve webcam conflicts between some drivers. + * V4L/DVB (8832): gspca: Bad pixelformat of vc0321 webcams. + * V4L/DVB (8833): gspca: Cleanup the sonixb code. + * V4L/DVB (8834): gspca: Have a bigger buffer for sn9c10x compressed + images. + * V4L/DVB (8835): gspca: Same pixfmt as the sn9c102 driver and raw Bayer + added in sonixb. + * V4L/DVB (8837): dvb: fix I2C adapters name size + * V4L/DVB (8839): dib0700: add comment to identify 35th USB id pair + * V4L/DVB (8840): dib0700: add basic support for Hauppauge Nova-TD-500 + (84xxx) + * V4L/DVB (8842): vivi_release(): fix use-after-free + * V4L/DVB (8843): tda10048_firmware_upload(): fix a memory leak + * V4L/DVB (8844): dabusb_fpga_download(): fix a memory leak + * bnx2x: Accessing un-mapped page + * SELinux: memory leak in security_context_to_sid_core + * x86: add io delay quirk for Presario F700 + * mmap: fix petty bug in anonymous shared mmap offset handling + * x86: Change warning message in TSC calibration. + * PCI: fix pbus_size_mem() resource alignment for CardBus controllers + * [ARM] omap: fix build error in ohci-omap.c + * [ARM] remove unused #include + * ACPI: Make Len Brown the ACPI maintainer again + * fujitsu-laptop: fix regression for P8010 in 2.6.27-rc + * ACPI: Avoid bogus timeout about SMbus check + * acer-wmi: remove debugfs entries upon unloading + * forgotten refcount on sysctl root table + * V4L/DVB (8868): gspca: Support for vga modes with sif sensors in + sonixb. + * V4L/DVB (8869): gspca: Move the Sonix webcams with TAS5110C1B from + sn9c102 to gspca. + * V4L/DVB (8870): gspca: Fix dark room problem with sonixb. + * V4L/DVB (8872): gspca: Bad image format and offset with rev072a of + spca561. + * V4L/DVB (8873): gspca: Bad image offset with rev012a of spca561 and + adjust exposure. + * V4L/DVB (8874): gspca: Adjust hstart for sn9c103/ov7630 and update + usb-id's. + * [ARM] omap: fix virtual vs physical address space confusions + * V4L/DVB (8876): budget: udelay changed to mdelay + * V4L/DVB (8877): b2c2 and bt8xx: udelay to mdelay + * V4L/DVB (8880): PATCH: Fix parents on some webcam drivers + * V4L/DVB (8881): gspca: After 'while (retry--) {...}', retry will be -1 + but not 0. + * powerpc/spufs: Fix multiple get_spu_context() + * powerpc/spufs: Fix race for a free SPU + * Input: bcm5974 - small formatting cleanup + * Input: bcm5974 - improve finger tracking and counting + * Input: bcm5974 - add BTN_TOUCH event for mousedev benefit + * Input: i8042 - make Lenovo 3000 N100 blacklist entry more specific + * sh: resume_kernel fix for kernel oops built with CONFIG_BKL_PREEMPT=y. + * sh64: resume_kernel fix for kernel oops built with + CONFIG_BKL_PREEMPT=y. + * i2c: fix i2c-sh_mobile timing issues + * clockevents: prevent clockevent event_handler ending up handler_noop + * clockevents: prevent endless loop in periodic broadcast handler + * clockevents: enforce reprogram in oneshot setup + * clockevents: prevent multiple init/shutdown + * clockevents: prevent endless loop lockup + * HPET: make minimum reprogramming delta useful + * [MTD] [NAND] tmio_nand: fix base address programming + * Fix conditional export of kvh.h and a.out.h to userspace. + * async_tx: fix the bug in async_tx_run_dependencies + * sched_clock: fix NOHZ interaction + * sched: fix process time monotonicity + * UBIFS: fix division by zero + * UBIFS: make minimum fanout 3 + * [MIPS] Fix data bus error recovery + * [MIPS] Fix WARNING: at kernel/smp.c:290 + * [MIPS] TXx9: Fix txx9_pcode initialization + * [MIPS] TX39xx: Add missing local_flush_icache_range initialization + * [MIPS] Probe initrd header only if explicitly specified + * res_counter: fix off-by-one bug in setting limit + * forcedeth: fix kexec regression + * atmel_lcdfb: fix oops in rmmod when framebuffer fails to register + * tracehook: comment pasto fixes + * drivers/mmc/card/block.c: fix refcount leak in mmc_block_open() + * x86: boot: stub out unimplemented CPU feature words + * x86: add NOPL as a synthetic CPU feature bit + * x86: use X86_FEATURE_NOPL in alternatives + * clockevents: broadcast fixup possible waiters + * x86: HPET fix moronic 32/64bit thinko + * x86: HPET: read back compare register before reading counter + * Fix CONFIG_AC97_BUS dependency + * [ARM] 5241/1: provide ioremap_wc() + * ntp: fix calculation of the next jiffie to trigger RTC sync + * clocksource, acpi_pm.c: use proper read function also in errata mode + * clocksource, acpi_pm.c: check for monotonicity + * x86: delay early cpu initialization until cpuid is done + * x86: move mtrr cpu cap setting early in early_init_xxxx + * sched: arch_reinit_sched_domains() must destroy domains to force + rebuild + * x86, xen: Use native_pte_flags instead of native_pte_val for .pte_flags + * x86: pda_init(): fix memory leak when using CPU hotplug + * x86: cpu_init(): fix memory leak when using CPU hotplug + * powerpc/spufs: Fix possible scheduling of a context to multiple SPEs + * netfilter: nf_conntrack_sip: de-static helper pointers + * netfilter: nf_conntrack_gre: more locking around keymap list + * netfilter: nf_conntrack_gre: nf_ct_gre_keymap_flush() fixlet + * netfilter: nf_conntrack_irc: make sure string is terminated before + calling simple_strtoul + * pkt_sched: Fix qdisc state in net_tx_action() + * powerpc: Fix rare boot build breakage + * ahci, pata_marvell: play nicely together + * sata_mv: add RocketRaid 1720 PCI ID to driver + * ahci: disable PMP for marvell ahcis + * sata_nv: disable hardreset for generic + * libata-sff: kill spurious WARN_ON() in ata_hsm_move() + * pata_sil680: remove duplicate pcim_enable_device + * ahci: RAID mode SATA patch for Intel Ibex Peak DeviceIDs + * [MIPS] IP22: Fix detection of second HPC3 on Challenge S + * xen: fix 2.6.27-rc5 xen balloon driver warnings + * x86: disable static NOPLs on 32 bits + * netns : fix kernel panic in timewait socket destruction + * bridge: don't allow setting hello time to zero + * NFS: Restore missing hunk in NFS mount option parser + * usb: fix null deferences in low level usb serial + * Fix format of MAINTAINERS + * sparc64: Disable timer interrupts in fixup_irqs(). + * [Bluetooth] Fix reference counting during ACL config stage + * [Bluetooth] Enforce correct authentication requirements + * [Bluetooth] Reject L2CAP connections on an insecure ACL link + * [S390] CVE-2008-1514: prevent ptrace padding area read/write in 31-bit + mode + * [S390] cio: Correct cleanup on error. + * [S390] cio: handle ssch() return codes correctly. + * [S390] cio: allow offline processing for disconnected devices + * ipsec: Restore larval states and socket policies in dump + * update Documentation/filesystems/Locking for 2.6.27 changes + * MAINTAINERS: add Atheros maintainer for atlx + * lib: Correct printk %pF to work on all architectures + * x86: fix memmap=exactmap boot argument + * clockevents: remove WARN_ON which was used to gather information + * ipv6: Fix OOPS in ip6_dst_lookup_tail(). + * Linux 2.6.27-rc6 + + -- Ben Collins Tue, 02 Sep 2008 12:45:56 -0400 + +linux (2.6.27-2.3) intrepid; urgency=low + + [ Ben Collins ] + + * build/retag: Make script save .orig of tags for later use + * ubuntu/lirc: Fix device_create call + * build/firmware: Put in-kernel firmware into version specific subdir + - LP: #262115 + * Rebase on linux-2.6 git. + * ABI bump + + [ Herton Ronaldo Krzesinski ] + + * SAUCE: (no-up) Apparmor warning fixes + + [ John Johansen ] + + * SAUCE: (no-up) Proper AppArmor ptrace updates for newer lsm API + + [ Mackenzie Morgan ] + + * SAUCE: Add quirk for ASUS Z37E to make sound audible after resume + - LP: #25896 + + -- Ben Collins Wed, 27 Aug 2008 14:03:05 -0400 + +linux (2.6.27-1.2) intrepid; urgency=low + + [ Amit Kucheria ] + + * SAUCE: make fc transport removal of target configurable + * SAUCE: pm: Config option to disable handling of console during + suspend/resume + + [ Ben Collins ] + + * SAUCE: Lower warning level of some PCI messages + * SAUCE: input/mouse/alps: Do not call psmouse_reset() for alps + * SAUCE: tulip: Let dmfe handle davicom on non-sparc + * SAUCE: tulip: Define ULI PCI ID's + * SAUCE: (no-up) version: Implement version_signature proc file. + * SAUCE: (no-up) connector.h: Add idx/val for drbd + * SAUCE: (no-up) swap: Add notify_swap_entry_free callback for compcache + * SAUCE: drivers: Remove some duplicate device entries in various modules + * SAUCE: (no-up) [AppArmor] merge with upstream subversion r1291 + * SAUCE: apparmor: Update for changes to ptrace lsm hooks + * SAUCE: (no-up) Enable ubuntu extra subdirectory + * SAUCE: applesmc: Add MacBookAir + * SAUCE: (no-up) ACPI: initramfs DSDT override support + * ubuntu: Add drbd module + * ubuntu: Add iscsitarget module + * ubuntu: Add BOM for iscsitarget + * ubuntu: Add squashfs driver + * SAUCE: (no-up) Check for squashfs superblock in initramfs mounting. + * ubuntu: Add aufs module + * ubuntu: Added atl2 driver + * ubuntu: Added et131x driver + * ubuntu: Add dm-raid4-5 driver + * ubuntu: Add ndiswrapper driver + * ubuntu: Added ram backed compressed swap module (compcache) + * ubuntu: Add misc drivers from hardy lum + * ubuntu: Add heci driver 3.2.0.24 + * ubuntu: Add ov511 and bt-sco drivers + * ubuntu: Add acx, prism2_usb wireless drivers + * ubuntu: Add at76 driver to build + * ubuntu: Add fsam7400 sw kill switch driver + * ubuntu: Added qc-usb driver + * ubuntu: e1000e: Upgraded module to 0.4.1.7 + * ubuntu: Added rfkill drivers + * ubuntu: VIA - Add VIA DRM Chrome9 3D engine + * ubuntu: unionfs: Added v1.4 module from hardy + * ubuntu: Add LIRC driver + * ubuntu: Add GFS driver + * ubuntu: New tlsup driver for toshiba laptops + * Update config files + * build/d-i: Remove obsolete dm modules + + [ Chuck Short ] + + * SAUCE: ata: blacklist FUJITSU MHW2160BH PL + + [ Colin Ian King ] + + * ubuntu: Add dm-loop + * SAUCE: Enable speedstep for sonoma processors. + + [ Dennis Noordsij ] + + * SAUCE: Work around ACPI corruption upon suspend on some Dell machines. + + [ Fabio M. Di Nitto ] + + * SAUCE: Export gfs2 symbols required for gfs1 kernel module + + [ Matthew Garrett ] + + * SAUCE: hostap: send events on data interface as well as master + interface + + [ Michael Frey (Senior Manager, MID ] + + * SAUCE: Send HCI_RESET for Broadcomm 2046 + + [ Phillip Lougher ] + + * SAUCE: r8169: disable TSO by default for RTL8111/8168B chipsets. + + [ Stefan Bader ] + + * SAUCE: (no-up) Export dm_disk function of device-mapper + * SAUCE: Restore VT fonts on switch + * SAUCE: mmc: Increase power_up deleay to fix TI readers + + [ Tim Gardner ] + + * SAUCE: Add extra headers to linux-libc-dev + * SAUCE: Catch nonsense keycodes and silently ignore + * SAUCE: Added support for HDAPS on various ThinkPads from Lenovo and IBM + * SAUCE: Guest OS does not recognize a lun with non zero target id on + Vmware ESX Server + * SAUCE: (no-up) Take care of orinoco_cs overlap with hostap_cs + * ubuntu: Add GNBD driver + + -- Ben Collins Sat, 23 Aug 2008 15:48:35 -0400 + +linux (2.6.27-0.0) intrepid; urgency=low + + * Not uploaded, placeholder for new release + + -- Ben Collins Sat, 23 Aug 2008 15:48:35 -0400 + +linux (2.6.26-5.17) intrepid; urgency=low + + [ Ben Collins ] + + * build/abi: Add tosh_smm symbol to blacklist + + -- Ben Collins Fri, 15 Aug 2008 09:29:34 -0400 + +linux (2.6.26-5.16) intrepid; urgency=low + + [ Ben Collins ] + + * Revert "SAUCE: toshiba_acpi: Rewrote most of the proc entry bits." + * Revert "SAUCE: Update toshiba_acpi.c to version 0.19a" + * build/config: Disable in-kernel toshiba driver(s) + * ubuntu/tlsup: New driver for toshiba laptops + * build/config: Enable TLSUP driver + * SAUCE: e1000e: Fix E1000E_ENABLED logic to check for our E1000E_NEW + driver as well + * ubuntu/e1000e: Remove E1000E_ENABLED option in local config + * build/config: Update configs to have E1000E_ENABLED set + * ubuntu/prism2: Remove duplicate device + + [ Fabio M. Di Nitto ] + + * SAUCE: Export gfs2 symbols required for gfs1 kernel module + + [ Stefan Bader ] + + * SAUCE: x86: HPET rework for SB700 + - LP: #255910 + + [ Tim Gardner ] + + * Add GNBD driver + * Enable GNBD driver + * SAUCE: Add GFS driver + * SAUCE: Enable gfs driver configs + * b43: Linksys WMP54G (BCM4306/3) card in a PCI format has an SPROM + coding + + [ Upstream Kernel Changes ] + + * KVM: x86 emulator: emulate clflush + * USB: quirk PLL power down mode + + -- Ben Collins Mon, 11 Aug 2008 13:19:28 -0400 + +linux (2.6.26-5.15) intrepid; urgency=low + + [ Ben Collins ] + + * Revert "SAUCE: Add blacklist support to fix Belkin bluetooth dongle." + - Superceded by upstream changes. + * build/config: New option enabled for uvcvideo + * build/control: Add Vcs-Git meta data to control file + * SAUCE: toshiba_acpi: Rewrote most of the new code + * abi/perm-blacklist: Add emu10k1 driver to blacklist + + [ Upstream Kernel Changes ] + + * pxamci: trivial fix of DMA alignment register bit clearing + * udplite: Protection against coverage value wrap-around + * ipv6: use timer pending + * ipv6: __KERNEL__ ifdef struct ipv6_devconf + * hdlcdrv: Fix CRC calculation. + * quota: fix possible infinite loop in quota code + * isofs: fix minor filesystem corruption + * KVM: VMX: Fix a wrong usage of vmcs_config + * KVM: SVM: fix suspend/resume support + * KVM: mmu_shrink: kvm_mmu_zap_page requires slots_lock to be held + * KVM: VMX: Add ept_sync_context in flush_tlb + * KVM: x86 emulator: Fix HLT instruction + * KVM: MMU: nuke shadowed pgtable pages and ptes on memslot destruction + * KVM: MMU: Fix potential race setting upper shadow ptes on nonpae hosts + * Patch Upstream: x86 ptrace: fix PTRACE_GETFPXREGS error + * rcu: fix rcu_try_flip_waitack_needed() to prevent grace-period stall + * Fix typos from signal_32/64.h merge + * x86 reboot quirks: add Dell Precision WorkStation T5400 + * USB: fix usb serial pm counter decrement for disconnected interfaces + * x86, suspend, acpi: enter Big Real Mode + * markers: fix duplicate modpost entry + * Fix build on COMPAT platforms when CONFIG_EPOLL is disabled + * proc: fix /proc/*/pagemap some more + * cpusets: fix wrong domain attr updates + * x86: fix crash due to missing debugctlmsr on AMD K6-3 + * ide-cd: fix oops when using growisofs + * rtc-at91rm9200: avoid spurious irqs + * vmlinux.lds: move __attribute__((__cold__)) functions back into final + .text section + * ARM: fix fls() for 64-bit arguments + * tcp: Clear probes_out more aggressively in tcp_ack(). + * sparc64: Fix lockdep issues in LDC protocol layer. + * sparc64: Fix cpufreq notifier registry. + * sparc64: Do not define BIO_VMERGE_BOUNDARY. + * iop-adma: fix platform driver hotplug/coldplug + * myri10ge: do not forget to setup the single slice pointers + * myri10ge: do not use mgp->max_intr_slots before loading the firmware + * ALSA: trident - pause s/pdif output + * V4L: cx18: Upgrade to newer firmware & update documentation + * DVB: dib0700: add support for Hauppauge Nova-TD Stick 52009 + * V4L: uvcvideo: Fix a buffer overflow in format descriptor parsing + * V4L: uvcvideo: Use GFP_NOIO when allocating memory during resume + * V4L: uvcvideo: Don't free URB buffers on suspend + * V4L: uvcvideo: Make input device support optional + * V4L: uvcvideo: Add support for Medion Akoya Mini E1210 integrated + webcam + * V4L: saa7134: Copy tuner data earlier to avoid overwriting manual tuner + type + * V4L: cx23885: Bugfix for concurrent use of /dev/video0 and /dev/video1 + * DVB: cx23885: Ensure PAD_CTRL is always reset to a sensible default + * DVB: cx23885: DVB Transport cards using DVB port VIDB/TS1 did not + stream + * DVB: cx23885: Reallocated the sram to avoid concurrent VIDB/C issues + * DVB: cx23885: SRAM changes for the 885 and 887 silicon parts + * x86: fix kernel_physical_mapping_init() for large x86 systems + * eCryptfs: use page_alloc not kmalloc to get a page of memory + * UML - Fix boot crash + * ixgbe: remove device ID for unsupported device + * mpc52xx_psc_spi: fix block transfer + * tmpfs: fix kernel BUG in shmem_delete_inode + * markers: fix markers read barrier for multiple probes + * VFS: increase pseudo-filesystem block size to PAGE_SIZE + * cpufreq acpi: only call _PPC after cpufreq ACPI init funcs got called + already + * b43legacy: Release mutex in error handling code + * ath5k: don't enable MSI, we cannot handle it yet + * Fix off-by-one error in iov_iter_advance() + * Linux 2.6.26.1 + * ftrace: remove unneeded documentation + * romfs_readpage: don't report errors for pages beyond i_size + * netfilter: nf_nat_sip: c= is optional for session + * SCSI: bsg: fix bsg_mutex hang with device removal + * x86: idle process - add checking for NULL early param + * x86: io delay - add checking for NULL early param + * Close race in md_probe + * Kprobe smoke test lockdep warning + * netfilter: xt_time: fix time's time_mt()'s use of do_div() + * linear: correct disk numbering error check + * SCSI: ch: fix ch_remove oops + * NFS: Ensure we zap only the access and acl caches when setting new acls + * jbd: fix race between free buffer and commit transaction + * Input: i8042 - add Intel D845PESV to nopnp list + * Input: i8042 - add Gericom Bellagio to nomux blacklist + * Input: i8042 - add Acer Aspire 1360 to nomux blacklist + * Bluetooth: Signal user-space for HIDP and BNEP socket errors + * Add compat handler for PTRACE_GETSIGINFO + * ALSA: hda - Fix wrong volumes in AD1988 auto-probe mode + * ALSA: hda - Fix DMA position inaccuracy + * ALSA: hda - Add missing Thinkpad Z60m support + * ALSA: emu10k1 - Fix inverted Analog/Digital mixer switch on Audigy2 + * vfs: fix lookup on deleted directory + * Ath5k: fix memory corruption + * Ath5k: kill tasklets on shutdown + * sound: ensure device number is valid in snd_seq_oss_synth_make_info + * Linux 2.6.26.2 + + -- Ben Collins Sun, 03 Aug 2008 13:25:02 -0400 + +linux (2.6.26-5.14) intrepid; urgency=low + + [ Ben Collins ] + + * SAUCE: applesmc: Add MacBookAir + * build: Do not build ddeb unless we are on the buildd + * build: control: Consistency in arch fields. + * SAUCE: Update toshiba_acpi.c to version 0.19a + - LP: #77026 + * build: Added perm blacklist support and per-module support to abi-check + - Blacklist p80211 module from abi checks + * ubuntu/lirc: Get rid of drivers symlink and use real include stuff + + + [ Colin Ian King ] + + * SAUCE: acerhk module - add support for Amilo A1650g keyboard + - LP: #84159 + * SAUCE: rt2x00: Fix OOPS on failed creation of rt2x00lib workqueue + - LP: #249242 + + [ Mario Limonciello ] + + * Add LIRC back in + + [ Tim Gardner ] + + * Makefile race condition can lead to ndiswrapper build failure + - LP: #241547 + * update linux-wlan-ng (prism2_usb) to upstream version 1861 + - LP: #245026 + + [ Upstream Kernel Changes ] + + * Fix typos from signal_32/64.h merge + + -- Ben Collins Fri, 01 Aug 2008 00:05:01 -0400 + +linux (2.6.26-5.13) intrepid; urgency=low + + [ Ben Collins ] + + * build: Make makedumpfile an amd64/i386 only build-dep + * ubuntu/acerhk: Fixup assembly to compile with newer binutils + + -- Ben Collins Sat, 26 Jul 2008 16:41:50 -0400 + +linux (2.6.26-4.12) intrepid; urgency=low + + [ Ben Collins ] + + * e1000e: Upgraded module to 0.4.1.7 upstream. Placed in ubuntu/, + in-kernel driver disabled + * config: Disable e1000e in-kernel, and enable newer driver in ubuntu/ + * rfkill: Update to 1.3 drivers, and move to common location + * ubuntu: Actually link kconfig/kbuild into rfkill subdir + * config: Enable loading dsdt from initramfs + - LP: #246222 + * ubuntu: [compcache] Update to fix crashes in improper BUG() + * build: Create a retag scripts to recover tags from rebases + * build: Updates for dbg pkg + * build: Make sure no empty lines show up in debian/files + * ubuntu: atl1e: Add new driver from 2.6.27-pre-rc1 + - LP: #243894 + * sys_getcwd: Fix some brokeness introduced by AppArmor __d_path + changes + - LP: #251223 + * ubuntu: unionfs: Added v1.4 module from hardy + * build: Add sub-flavour infrastructure, and virtual subflav + + [ Eric Piel ] + + * ACPI: Allow custom DSDT tables to be loaded from initramfs + + [ Kees Cook ] + + * AppArmor: Smack VFS patches + + [ Mario Limonciello ] + + * Work around ACPI corruption upon suspend on some Dell machines. + - LP: #183033 + + [ Tim Gardner ] + + * Export usbhid_modify_dquirk for LBM module bcm5974 + - LP: #250838 + * VIA - Add VIA DRM Chrome9 3D engine + - LP: #251862 + * Define TRUE/FALSE for VIA DRM driver. + + -- Ben Collins Tue, 15 Jul 2008 12:51:39 -0400 + +linux (2.6.26-4.11) intrepid; urgency=low + + [ Ben Collins ] + + * config: Enable bcm5974 driver in all configs + + [ 2.6.26-4.10 ] + + [ Amit Kucheria ] + + * Fix typo in GSPCA Makefile and make it compile + + [ Ben Collins ] + + * ubuntu: Remove UVC driver in favor of in-kernel one (-rc9) + * config: Updates for -rc9 + * ubuntu: Add acx, prism2_usb wireless drivers + * config: Enable prism2_usb and acx drivers. + * ubuntu: Add at76 driver to build + * config: Enable at76_usb driver. + * iscsitarget: Fix prototype for bi_end_io callback. + * acx: Fix section type mismatch warnings + * fsam7400: Add sw kill switch driver + * config: Enable fsam7400 driver + * qc-usb: Added new driver + * config: Enable qc-usb driver + * drbd: Remove built-in connector usage + * drbd: Do not define idx/val for connector here + * connector.h: Add idx/val for drbd + * bcm5974: Added new driver + + [ Kees Cook ] + + * SAUCE: [AppArmor] merge with upstream subversion r1291 + * SAUCE: [AppArmor] fix typo in selinux_inode_link + * SAUCE: [AppArmor] aufs patches + + [ Michael Frey (Senior Manager, MID ] + + * SAUCE: Send HCI_RESET for Broadcomm 2046 + - LP: #241749 + + [ Tim Gardner ] + + * SAUCE: Medion Akoya Mini E1210 + + [ Upstream Kernel Changes ] + + * Revert "BAST: Remove old IDE driver" + * ARM: OMAP: DMA: Don't mark channel active in omap_enable_channel_irq + * ARM: OMAP: Correcting the gpmc prefetch control register address + * debugobjects: fix lockdep warning + * [ARM] 5115/1: pxafb: fix ifdef for command line option handling + * [ARM] 5116/1: pxafb: cleanup and fix order of failure handling + * [ARM] 5109/1: Mark rtc sa1100 driver as wakeup source before + registering it + * [ARM] Export dma_sync_sg_for_device() + * fix cgroup-inflicted breakage in block_dev.c + * [patch for 2.6.26 2/4] vfs: utimensat(): be consistent with utime() for + immutable and append-only files + * [patch for 2.6.26 1/4] vfs: utimensat(): ignore tv_sec if tv_nsec == + UTIME_OMIT or UTIME_NOW + * [patch for 2.6.26 3/4] vfs: utimensat(): fix error checking for + {UTIME_NOW,UTIME_OMIT} case + * [patch for 2.6.26 4/4] vfs: utimensat(): fix write access check for + futimens() + * [patch 1/4] vfs: path_{get,put}() cleanups + * [patch 2/4] fs: make struct file arg to d_path const + * [patch 3/4] vfs: fix ERR_PTR abuse in generic_readlink + * [patch 4/4] flock: remove unused fields from file_lock_operations + * [patch 3/3] vfs: make d_path() consistent across mount operations + * [patch 1/3] vfs: dcache sparse fixes + * [patch 2/3] vfs: dcache cleanups + * udf: Fix regression in UDF anchor block detection + * [SCSI] ses: Fix timeout + * netfilter: ip6table_mangle: don't reroute in LOCAL_IN + * [SCSI] esp: Fix OOPS in esp_reset_cleanup(). + * kernel/audit.c: nlh->nlmsg_type is gotten more than once + * audit: fix kernel-doc parameter notation + * remove useless argument type in audit_filter_user() + * Blackfin arch: fix bug - kernel boot fails when Spinlock and rw-lock + debugging enabled + * Blackfin arch: fix up section mismatch warning + * mac80211: implement EU regulatory domain + * b43: Do not return TX_BUSY from op_tx + * b43legacy: Do not return TX_BUSY from op_tx + * b43: Fix possible MMIO access while device is down + * b43legacy: Fix possible NULL pointer dereference in DMA code + * rt2x00: Fix unbalanced mutex locking + * iwlwifi: improve scanning band selection management + * [SCSI] esp: tidy up target reference counting + * [ARM] 5117/1: pxafb: fix __devinit/exit annotations + * thermal: Create CONFIG_THERMAL_HWMON=n + * ACPI: don't walk tables if ACPI was disabled + * dock: bay: Don't call acpi_walk_namespace() when ACPI is disabled. + * x86: shift bits the right way in native_read_tscp + * x86: section/warning fixes + * V4L/DVB (8004): Fix INPUT dependency at budget-ci + * V4L/DVB (8005): Fix OOPS if frontend is null + * V4L/DVB (8007): cx18/cx25840: the S-Video LUMA input can use all + In1-In8 inputs + * V4L/DVB (8008): cx18: remove duplicate audio and video input enums + * V4L/DVB (8010): em28xx: Properly register extensions for already + attached devices + * V4L/DVB (8011): em28xx: enable DVB for HVR-900 + * V4L/DVB (8012): gl861: sleep a little to avoid I2C errors + * V4L/DVB (8013): gl861: remove useless identify_state + * V4L/DVB (8015): gl861: replace non critical msleep(0) with msleep(1) to + be on the safe side + * V4L/DVB (8017): Ensure em28xx extensions only get run against devs that + support them + * V4L/DVB (8018): Add em2860 chip ID + * V4L/DVB (8020): Fix callbacks functions of saa7134_empress + * V4L/DVB (8022): saa7134: fix race between opening and closing the + device + * V4L/DVB (8026): Avoids an OOPS if dev struct can't be successfully + recovered + * V4L/DVB (8027): saa7134: Avermedia A700: only s-video and composite + input are working + * V4L/DVB (8028): Improve error messages for tda1004x attach + * V4L/DVB (8029): Improve error message at tda1004x_attach + * V4L/DVB (8034): tda18271: fix IF notch frequency handling + * V4L/DVB (8035): tda18271: dont touch EB14 if rf_cal lookup is out of + range + * V4L/DVB (8036): tda18271: toggle rf agc speed mode on TDA18271HD/C2 + only + * V4L/DVB (8037): tda18271: ensure that the thermometer is off during + channel configuration + * V4L/DVB (8039): pxa-camera: fix platform_get_irq() error handling. + * V4L/DVB (8040): soc-camera: remove soc_camera_host_class class + * V4L/DVB (8042): DVB-USB UMT-010 channel scan oops + * V4L/DVB (8043): au0828: add support for additional USB device id's + * V4L/DVB (8044): au8522: tuning optimizations + * V4L/DVB (8048): saa7134: Fix entries for Avermedia A16d and Avermedia + E506 + * V4L/DVB (8061): cx18: only select tuner / frontend modules if + !DVB_FE_CUSTOMISE + * V4L/DVB (8063): cx18: Fix unintended auto configurations in + cx18-av-core + * V4L/DVB (8066): cx18: Fix audio mux input definitions for HVR-1600 Line + In 2 and FM radio + * V4L/DVB (8067): cx18: Fix firmware load for case when digital capture + happens first + * V4L/DVB (8068): cx18: Add I2C slave reset via GPIO upon initialization + * V4L/DVB (8069): cx18: Fix S-Video and Compsite inputs for the Yuan + MPC718 and enable card entry + * V4L/DVB (8071): tda10023: Fix possible kernel oops during + initialisation + * V4L/DVB (8073): av7110: Catch another type of ARM crash + * V4L/DVB (8074): av7110: OSD transfers should not be interrupted + * V4L/DVB (8075): stv0299: Uncorrected block count and bit error rate + fixed + * V4L/DVB (8092): videodev: simplify and fix standard enumeration + * V4L/DVB (8096): au8522: prevent false-positive lock status + * V4L/DVB (8097): xc5000: check device hardware state to determine if + firmware download is needed + * V4L/DVB (8100): V4L/vivi: fix possible memory leak in vivi_fillbuff + * V4L/DVB (8108): Fix open/close race in saa7134 + * s2io: fix documentation about intr_type + * tc35815: Mark carrier-off before starting PHY + * tc35815: Fix receiver hangup on Rx FIFO overflow + * ixgbe: fix EEH recovery during reset on PPC + * igb: fix EEH recovery during reset on PPC + * e1000e: fix EEH recovery during reset on PPC + * pcnet_cs, axnet_cs: clear bogus interrupt before request_irq + * drivers/net/r6040.c: Eliminate double sizeof + * ipg: fix jumbo frame compilation + * ipg: use NULL, not zero, for pointers + * [netdrvr] 3c59x: remove irqs_disabled warning from local_bh_enable + * [netdrvr] netxen: fix netxen_pci_tbl[] breakage + * e100: Do pci_dma_sync after skb_alloc for proper operation on ixp4xx + * e1000: only enable TSO6 via ethtool when using correct hardware + * [netdrvr] Fix IOMMU overflow checking in s2io.c + * qla3xxx: Hold RTNL while calling dev_close() + * Hold RTNL while calling dev_close() + * sata_uli: hardreset is broken + * rt2x00: Fix lock dependency errror + * prism: islpci_eth.c endianness fix + * mac80211: fix an oops in several failure paths in key allocation + * firewire: fw-sbp2: fix parsing of logical unit directories + * kbuild: fix a.out.h export to userspace with O= build. + * Ensure interrupted recovery completed properly (v1 metadata plus + bitmap) + * Don't acknowlege that stripe-expand is complete until it really is. + * Fix error paths if md_probe fails. + * hamradio: remove unused variable + * tcp: calculate tcp_mem based on low memory instead of all memory + * tcp: fix for splice receive when used with software LRO + * af_unix: fix 'poll for write'/connected DGRAM sockets + * netdevice: Fix typo of dev_unicast_add() comment + * pkt_sched: ERR_PTR() ususally encodes an negative errno, not positive. + * pkt_sched: Remove CONFIG_NET_SCH_RR + * include/linux/netdevice.h: don't export MAX_HEADER to userspace + * tcp: /proc/net/tcp rto,ato values not scaled properly (v2) + * netlink: Fix some doc comments in net/netlink/attr.c + * CONNECTOR: add a proc entry to list connectors + * inet fragments: fix race between inet_frag_find and + inet_frag_secret_rebuild + * net/inet_lro: remove setting skb->ip_summed when not LRO-able + * netlabel: Fix a problem when dumping the default IPv6 static labels + * ipv6 route: Convert rt6_device_match() to use RT6_LOOKUP_F_xxx flags. + * sched: fix cpu hotplug + * Fix and clean top .gitignore + * x86: fix cpu hotplug crash + * ptrace GET/SET FPXREGS broken + * Input: add KEY_MEDIA_REPEAT definition + * Input: fix locking in force-feedback core + * [ARM] 5131/1: Annotate platform_secondary_init with trace_hardirqs_off + * ide: fix /proc/ide/ide?/mate reporting + * netfilter: nf_conntrack_tcp: fixing to check the lower bound of valid + ACK + * textsearch: fix Boyer-Moore text search bug + * hostap: don't report useless WDS frames by default + * hostap: fix sparse warnings + * mac80211: don't accept WEP keys other than WEP40 and WEP104 + * V4L/DVB (8145a): USB Video Class driver + * [IA64] Bugfix for system with 32 cpus + * [IA64] export account_system_vtime + * sched: fix divide error when trying to configure rt_period to zero + * x86: fix NODES_SHIFT Kconfig range + * block: Fix the starving writes bug in the anticipatory IO scheduler + * Properly notify block layer of sync writes + * rcu: fix hotplug vs rcu race + * I2C: S3C2410: Check ACK on byte transmission + * I2C: S3C2410: Fixup error codes returned rom a transfer. + * I2C: S3C2410: Add MODULE_ALIAS() for s3c2440 device. + * PCI: Restrict VPD read permission to root + * powerpc/bootwrapper: update for initrd with simpleImage + * i2c: Documentation: fix device matching description + * i2c: Fix bad hint about irqs in i2c.h + * powerpc/legacy_serial: Bail if reg-offset/shift properties are present + * powerpc/mpc5200: Fix lite5200b suspend/resume + * ipv4: fix sysctl documentation of time related values + * net-sched: change tcf_destroy_chain() to clear start of filter list + * net-sched: fix filter destruction in atm/hfsc qdisc destruction + * netlink: Unneeded local variable + * net: Tyop of sk_filter() comment + * netdevice: Fix wrong string handle in kernel command line parsing + * net: fib_rules: fix error code for unsupported families + * dm crypt: use cond_resched + * V4L/DVB (8178): uvc: Fix compilation breakage for the other drivers, if + uvc is selected + * PCI: Limit VPD read/write lengths for Broadcom 5706, 5708, 5709 rev. + * PCI: acpiphp: cleanup notify handler on all root bridges + * drivers/input/ff-core.c needs + * DRM/i915: only use tiled blits on 965+ + * tty: Fix inverted logic in send_break + * x86: fix Intel Mac booting with EFI + * arch/x86/mm/init_64.c: early_memtest(): fix types + * 9p: fix O_APPEND in legacy mode + * slub: Do not use 192 byte sized cache if minimum alignment is 128 byte + * Do not overwrite nr_zones on !NUMA when initialising zlcache_ptr + * [MIPS] IP32: Fix unexpected irq 71 + * [MIPS] IP22: Fix crashes due to wrong L1_CACHE_BYTES + * [MIPS] cevt-txx9: Reset timer counter on initialization + * hrtimer: prevent migration for raising softirq + * svcrpc: fix handling of garbage args + * OHCI: Fix problem if SM501 and another platform driver is selected + * USB: fix cdc-acm resume() + * USB: ehci - fix timer regression + * USB: ohci - record data toggle after unlink + * USB: mass storage: new id for US_SC_CYP_ATACB + * sisusbvga: Fix oops on disconnect. + * USB: New device ID for ftdi_sio driver + * USB: fix interrupt disabling for HCDs with shared interrupt handlers + * USB: don't lose disconnections during suspend + * USB: another option device id + * USB: add a pl2303 device id + * USB: fix Oops on loading ipaq module since 2.6.26 + * USB: adding comment for ipaq forcing number of ports + * [MIPS] Fix bug in atomic_sub_if_positive. + * xen: fix address truncation in pte mfn<->pfn conversion + * sata_sil24: add DID for another adaptec flavor + * ahci: always clear all bits in irq_stat + * libata-sff: improve HSM violation reporting + * sata_mv: safer logic for limit_warnings + * Update maintainers for powerpc + * Christoph has moved + * mm: dirty page accounting vs VM_MIXEDMAP + * rtc: rtc_read_alarm() handles wraparound + * firmware: fix the request_firmware() dummy + * serial: fix serial_match_port() for dynamic major tty-device numbers + * get_user_pages(): fix possible page leak on oom + * rtc-x1205: Fix alarm set + * rtc: fix CMOS time error after writing /proc/acpi/alarm + * pci: VT3336 can't do MSI either + * Miguel Ojeda has moved + * ext3: add missing unlock to error path in ext3_quota_write() + * ext4: add missing unlock to an error path in ext4_quota_write() + * reiserfs: add missing unlock to an error path in reiserfs_quota_write() + * ecryptfs: remove unnecessary mux from ecryptfs_init_ecryptfs_miscdev() + * lib: taint kernel in common report_bug() WARN path. + * gpio: pca953x (i2c) handles max7310 too + * fsl_diu_fb: fix build with CONFIG_PM=y, plus fix some warnings + * Update taskstats-struct document for scaled time accounting + * cciss: fix regression that no device nodes are created if no logical + drives are configured. + * delay accounting: maintainer update + * Doc*/kernel-parameters.txt: fix stale references + * hdaps: add support for various newer Lenovo thinkpads + * mn10300: export certain arch symbols required to build allmodconfig + * mn10300: provide __ucmpdi2() for MN10300 + * Introduce rculist.h + * man-pages is supported + * ntfs: update help text + * add kernel-doc for simple_read_from_buffer and memory_read_from_buffer + * w100fb: do not depend on SHARPSL + * w100fb: add 80 MHz modeline + * MFD maintainer + * cgroups: document the effect of attaching PID 0 to a cgroup + * spi: fix the read path in spidev + * doc: doc maintainers + * security: filesystem capabilities: fix fragile setuid fixup code + * security: filesystem capabilities: fix CAP_SETPCAP handling + * Alpha Linux kernel fails with inconsistent kallsyms data + * cpusets: document proc status cpus and mems allowed lists + * MAINTAINERS: update the email address of Andreas Dilger + * cciss: read config to obtain max outstanding commands per controller + * olpc: sdhci: add quirk for the Marvell CaFe's vdd/powerup issue + * olpc: sdhci: add quirk for the Marvell CaFe's interrupt timeout + * cpumask: introduce new APIs + * mm: switch node meminfo Active & Inactive pages to Kbytes + * Update MAINTAINERS file for the TPM device driver + * devcgroup: fix odd behaviour when writing 'a' to devices.allow + * doc: document the relax_domain_level kernel boot argument + * mmc: don't use DMA on newer ENE controllers + * mempolicy: mask off internal flags for userspace API + * x86 ACPI: normalize segment descriptor register on resume + * x86 ACPI: fix resume from suspend to RAM on uniprocessor x86-64 + * softlockup: print a module list on being stuck + * ide: fix hwif->gendev refcounting + * ide: ide_unregister() warm-plug bugfix + * ide: ide_unregister() locking bugfix + * ahci: give another shot at clearing all bits in irq_stat + * Fix clear_refs_write() use of struct mm_walk + * Move _RET_IP_ and _THIS_IP_ to include/linux/kernel.h + * Fix pagemap_read() use of struct mm_walk + * Linux 2.6.26-rc9 + * Revert "USB: don't explicitly reenable root-hub status interrupts" + * Revert "PCI: Correct last two HP entries in the bfsort whitelist" + * iwlwifi: fix incorrect 5GHz rates reported in monitor mode + * iwlwifi: drop skb silently for Tx request in monitor mode + * libertas: support USB persistence on suspend/resume (resend) + * tcp: net/ipv4/tcp.c needs linux/scatterlist.h + * tcp: fix a size_t < 0 comparison in tcp_read_sock + * bridge: fix use-after-free in br_cleanup_bridges() + * Add missing skb->dev assignment in Frame Relay RX code + * forcedeth: fix lockdep warning on ethtool -s + * ehea: fix might sleep problem + * ehea: add MODULE_DEVICE_TABLE + * ehea: fix race condition + * ehea: Access iph->tot_len with correct endianness + * pasemi_mac: Access iph->tot_len with correct endianness + * ibm_newemac: Fixes kernel crashes when speed of cable connected changes + * ibm_newemac: Fixes entry of short packets + * fs_enet: restore promiscuous and multicast settings in restart() + * can: add sanity checks + * x86: KVM guest: Add memory clobber to hypercalls + * KVM: IOAPIC: Fix level-triggered irq injection hang + * [SCSI] erase invalid data returned by device + * pxamci: fix byte aligned DMA transfers + * vsprintf: split out '%s' handling logic + * vsprintf: split out '%p' handling logic + * vsprintf: add infrastructure support for extended '%p' specifiers + * vsprintf: add support for '%pS' and '%pF' pointer formats + * powerpc: Fix unterminated of_device_id array in legacy_serial.c + * [UML] fix gcc ICEs and unresolved externs + * ocfs2/dlm: Fixes oops in dlm_new_lockres() + * hostap_cs: correct poor NULL checks in suspend/resume routines + * drivers/net/wireless/iwlwifi/iwl-3945.c Fix type issue on 64bit + * mac80211: move netif_carrier_on to after + ieee80211_bss_info_change_notify + * mac80211: Only flush workqueue when last interface was removed + * zd1211rw: add ID for AirTies WUS-201 + * ssb-pcicore: Fix IRQ-vector init on embedded devices + * mac80211: don't report selected IBSS when not found + * crypto: tcrypt - Fix memory leak in test_cipher + * sctp: Mark the tsn as received after all allocations finish + * [S390] protect _PAGE_SPECIAL bit against mprotect + * irda: via-ircc proper dma freeing + * irda: New device ID for nsc-ircc + * irda: Fix netlink error path return value + * [SCSI] mptspi: fix oops in mptspi_dv_renegotiate_work() + * Correct hash flushing from huge_ptep_set_wrprotect() + * ide: add __ide_default_irq() inline helper + * palm_bk3710: fix IDECLK period calculation + * it8213: fix return value in it8213_init_one() + * [MIPS] Atlas, decstation: Fix section mismatches triggered by + defconfigs + * [MIPS] Fix 32bit kernels on R4k with 128 byte cache line size + * NFS: Fix readdir cache invalidation + * SUNRPC: Fix a double-free in rpcbind + * SUNRPC: Fix an rpcbind breakage for the case of IPv6 lookups + * reiserfs: discard prealloc in reiserfs_delete_inode + * Fix broken fix for fsl-diu-db + * RDMA/cxgb3: Fix regression caused by class_device -> device conversion + * ipv6: fix race between ipv6_del_addr and DAD timer + * sctp: Add documentation for sctp sysctl variable + * kernel/printk.c: Made printk_recursion_bug_msg static. + * powerpc: Add missing reference to coherent_dma_mask + * rc80211_pid: Fix fast_start parameter handling + * rt2x00: Disable synchronization during initialization + * zd1211rw: stop beacons on remove_interface + * libertas: fix memory alignment problems on the blackfin + * netfilter: nf_conntrack_tcp: fix endless loop + * netfilter: nf_nat_snmp_basic: fix a range check in NAT for SNMP + * md: ensure all blocks are uptodate or locked when syncing + * sched: fix cpu hotplug + * x86: fix /dev/mem compatibility under PAT + * crypto: chainiv - Invoke completion function + * ocfs2: Fix flags in ocfs2_file_lock + * kernel/kprobes.c: Made kprobe_blacklist static. + * arch/x86/kernel/.gitignore: Added vmlinux.lds to .gitignore file + because it shouldn't be tracked. + * ftrace: Documentation + * Fix PREEMPT_RCU without HOTPLUG_CPU + * sched: fix cpu hotplug, cleanup + * exec: fix stack excutability without PT_GNU_STACK + * slub: Fix use-after-preempt of per-CPU data structure + * Documentation: clarify tcp_{r,w}mem sysctl docs + * ip: sysctl documentation cleanup + * tcp: correct kcalloc usage + * ipv4: fib_trie: Fix lookup error return + * netlabel: netlink_unicast calls kfree_skb on error path by itself + * ipv6: missed namespace context in ipv6_rthdr_rcv + * xfrm: Add a XFRM_STATE_AF_UNSPEC flag to xfrm_usersa_info + * tun: Persistent devices can get stuck in xoff state + * tpm: add Intel TPM TIS device HID + * rapidio: fix device reference counting + * Fix name of Russell King in various comments + * rtc: fix reported IRQ rate for when HPET is enabled + * libata-acpi: filter out DIPM enable + * Added Targa Visionary 1000 IDE adapter to pata_sis.c + * libata-acpi: don't call sleeping function from invalid context + * Fix reference counting race on log buffers + * [SCSI] ipr: Fix HDIO_GET_IDENTITY oops for SATA devices + * IPMI: return correct value from ipmi_write + * x86: fix ldt limit for 64 bit + * [SCSI] fusion: default MSI to disabled for SPI and FC controllers + * [SCSI] bsg: fix oops on remove + * drivers/char/pcmcia/ipwireless/hardware.c fix resource leak + * drivers/isdn/i4l/isdn_common.c fix small resource leak + * fbdev: bugfix for multiprocess defio + * serial8250: sanity check nr_uarts on all paths. + * ov7670: clean up ov7670_read semantics + * rtc-fm3130: fix chip naming + * rtc-pcf8563: add chip id + * OProfile kernel maintainership changes + * frv: fix irqs_disabled() to return an int, not an unsigned long + * cifs: fix inode leak in cifs_get_inode_info_unix + * cifs: fix wksidarr declaration to be big-endian friendly + * cpusets, hotplug, scheduler: fix scheduler domain breakage + * Documentation/HOWTO: correct wrong kernel bugzilla FAQ URL + * devcgroup: always show positive major/minor num + * devcgroup: fix permission check when adding entry to child cgroup + * Linux 2.6.26 + + -- Ben Collins Mon, 14 Jul 2008 13:41:50 -0400 + +linux (2.6.26-3.9) intrepid; urgency=low + + * abi: Add dca and ioatdma to modules.ignore + + [ 2.6.26-3.8 ] + + [ Ben Collins ] + + * ubuntu: Add heci driver 3.2.0.24 + * ubuntu: Add heci to kconfig/kbuild + * config: Enable heci module on all flavours + * dm-bbr: Update to get it to compile with 2.6.26 + * config: Enable dm-bbr + * ubuntu: Add some media drivers + * config: Enable misc media drivers + * udeb: Switch to uvesafb in fb-modules + * abi: Add more modules to ignore (known) + + [ 2.6.26-3.7 ] + + [Amit Kucheria] + + * SAUCE: make fc transport removal of target configurable + - LP: #163075 + * SAUCE: pm: Config option to disable handling of console during + suspend/resume + + [Ben Collins] + + * SAUCE: input/mouse/alps: Do not call psmouse_reset() for alps + * SAUCE: irda: Default to dongle type 9 on IBM hardware + * SAUCE: tulip: Let dmfe handle davicom on non-sparc + * SAUCE: tulip: Define ULI PCI ID's + * SAUCE: version: Implement version_signature proc file. + * build: Cleanup arches + * build: Remove remnants of unused binary-custom infrastructure + * build: Remove disable_d_i (not needed) and cleanup ppa build stuff + * ubuntu: New modules, acer-acpi + * build: Remove -virtual, and rebuild configs + * ubuntu: Add drbd module + * acer-acpi: Fix makefile + * x86/Kconfig: Fix missing quote for ubuntu Kconfig source + * ubuntu: Add iscsitarget module + * ubuntu: Added Amiga FS driver + * ubuntu: Add squashfs driver + * ubuntu: Remove asfs (Amiga FS). Need to be in linux-ports instead + * squashfs: Move headers to real include directory + * build/configs: The Great Config Consistency Check of 2008 + * ubuntu: Move third-party includes to ubuntu/include + * ubuntu: Add aufs module + * ubuntu: Added atl2 driver + * ubuntu: Add dm-radi4-5 driver + * build: Add CONFIG_DEBUG_SECTION_MISMATCH=y to get old style warnings + from build + * ubuntu/Makefile: Fixup dm-raid4-5 and add kludge for kbuild + * squashfs: Fixes for VFS changes + * ubuntu/dm-raid4-5: Fixups for moved/renamed headers/functions in core + md + * ubuntu: Add ndiswrapper driver + * d-i: Update module listings + * build: Disable xd block device (ancient) + * ndiswrapper: Fixup makefile + * d-i: Remove efi-modules. The only module, efivars, is built-in + * build: Remove install-source, obsolete and caused build failure + * Ubuntu-2.6.26-1.3 + * build: linux-doc rules got broken when disabling html side. Fixed now. + * Ubuntu-2.6.26-1.4 + * x86: Update to -rc6 allows CONFIG_PCI_OLPC to work with PCI_GOANY + * d-i: Make virtio-ring optional (it's built-in on i386) + * Ubuntu-2.6.26-1.4 + * Ubuntu-2.6.26-1.5 + * config: Enable DVB devices + * ubuntu/aufs: Make aufs a bool config, since it needs to be built-in + * config: Build aufs into the kernels + * build: Fix arguments passed to link-headers script + * config: Disable early printk + * d-i: Move isofs to storage-core and kill st (scsi tape) from list + * config: Enable non-promiscuous access to /dev/mem + * x86: Add option to disable decompression info messages + * config: Enable no-bz-chatter config options + * build: Re-add linux-source package + * d-i: Re-add socket-modules. Accidentally removed + - LP: #241295 + * Ubuntu-2.6.26-2.6 + * Use makedumpfile to generate a vmcoreinfo file. + * build: Build-Depend on makedumpfile for vmcoreinfo generation + * build: Remove debug print from git-ubuntu-log + * Updated configs for -rc7 + * build: postinst, do not call depmod with -F + * config: Enable rtc-cmos as a built-in driver. + * control: Provide ndiswrapper-modules-1.9 + * build: Generate vmcoreinfo in image build for crashdumps without debug + image + * config: Disable vesafb, since we'll prefer uvesafb + * build: Copy uvesafb module to initrd mod directory + * abi-check: New, more robust script + * config: Enable heap randomization by default + * abi-check: Cleanup output and call with perl (not $SHELL) + * abi: Ignore missing vesafb (known) + * config: Disable pcspkr (in favor of snd-pcsp) + * swap: Add notify_swap_entry_free callback for compcache + * compcache: Added ram backed compressed swap module + * ubuntu: Enable kbuild and kconfig for compcache + * config: Enable compcache and tlsf allocator as modules + * config: Updated for -rc8. Disables XEN on i386 + * config: Switch i386-server to 64G, enable PAE, 64-bit res, and XEN + * ubuntu: Add misc drivers from hardy lum + * ubuntu: Enable build of misc/ subdir + * config: Enable misc drivers + * aufs: Fix warning about single non-string-literal arg to printf style + function + * drivers: Remove some duplicate device entries in various modules + * config: Disable some duplicate drivers + * keyspan: Remove duplicate device ID's + * check-aliases: Cleanup output, and fix rolling checks + * ubuntu: Disable dm-bbr for now + * dm-bbr: First cut at forward portiong. Still needs work. + * ubuntu: Disable dm-bbr in kbuild/kconfig + + [Chuck Short] + + * SAUCE: ata: blacklist FUJITSU MHW2160BH PL + - LP: #175834 + * SAUCE: [USB]: add ASUS LCM to the blacklist + + [Colin Ian King] + + * SAUCE: airprime.c supports more devices + - LP: #208250 + * SAUCE: Enable speedstep for sonoma processors. + - LP: #132271 + * Add dm-loop + * Add dm-loop BOM + + [Kyle McMartin] + + * SAUCE: fix orinoco_cs oops + + [Mario Limonciello] + + * SAUCE: Enable Reset and SCO workaround on Dell 410 BT adapter + + [Matthew Garrett] + + * SAUCE: hostap: send events on data interface as well as master + interface + + [Phillip Lougher] + + * SAUCE: r8169: disable TSO by default for RTL8111/8168B chipsets. + + [Stefan Bader] + + * SAUCE: Export dm_disk function of device-mapper + * SAUCE: Restore VT fonts on switch + * SAUCE: Always use SCO protocol (disable eSCO support) Bug: #39414 + * SAUCE: mmc: Increase power_up deleay to fix TI readers OriginalAuthor: + Pascal Terjan Bug: #137686 + * SAUCE: Add blacklist support to fix Belkin bluetooth dongle. Bug: + #140511 + * SAUCE: Lower warning level of pci resource allocation messages. Bug: + 159241 + * SAUCE: Lower message level for PCI memory and I/O allocation. + - LP: #159241 + * Modify log generation to catch bug numbers when adding with git-am. + + [Tim Gardner] + + * Added the debian directory. Ignore: yes + * Add support for UBUNTUINCLUDE Ignore: yes + * LUM headers go in /usr/src Ignore: yes + * First pass at 2.6.25 configs Ignore: yes + * i386 -generic builds. Ignore: yes + * SAUCE: Increase CONFIG_IDE_MAX_HWIFS to 8 (from 4) + * SAUCE: Add extra headers to linux-libc-dev OriginalAuthor: Soren Hansen + OriginalLocation: + https://lists.ubuntu.com/archives/kernel-team/2007-November/001891.html + * Set CONFIG_DEVKMEM=n Ignore: yes + * Enabled ALSA and CGROUPS for i386 Ignore: yes + * Enabled amd64 configs. Ignore: yes + * CONFIG_STANDALONE=n Ignore: yes + * CONFIG_BLK_DEV_4DRIVES=n for i386 Ignore: yes + * CONFIG: CONFIG_DEFAULT_RELATIME=y for all flavours. Ignore: yes + * Set CONFIG_EDD_OFF=y Ignore: yes + * SAUCE: Blacklist Bluetooth Dell Wireless 370 for SCO MTU + OriginalAuthor: Mario Limonciello Bug: + #209715 + * SAUCE: Catch nonsense keycodes and silently ignore + * SAUCE: frame buffer regression - screen blank except for blinking + cursor after fbcon vtswitch OriginalAuthor: Matthew Garrett + Bug: #201591 + * SAUCE: Added support for HDAPS on various ThinkPads from Lenovo and IBM + OriginalAuthor: Klaus S. Madsen + OriginalAuthor: Chuck Short + * SAUCE: Guest OS does not recognize a lun with non zero target id on + Vmware ESX Server + * SAUCE: orinoco_cs.ko missing + * Set CONFIG_FB_VESA=m for i386/amd64 Ignore: yes + * Set CONFIG_PM_DISABLE_CONSOLE=y for all flavours Ignore: yes + * Thorough review of amd64 -generic config Ignore: yes + * Build PPA packages for Hardy until the Intrepid archive is opened. + * Deleted obsolete flavours Ignore: yes + * Don't build docs for PPA Ignore: yes + * Build all standard packages in PPA. Ignore: yes + * Remove duplicate USB ids + * SAUCE: DVB-USB UMT-010 driver oops on install Bug: #115284 + * Update configs after rebase to 2.6.26-rc1 Ignore: yes + * Update configs after rebase Ignore: yes + * Disable V4L until the build issues get ironed out. Ignore: yes + * Update configs after rebase. Ignore: yes + * Another device enable pass Ignore: yes + * Update configs after merge. Ignore: yes + * SAUCE: fn key doesn't work in hardy with macbook pro fourth generation + (4,1) + - LP: #207127 + * Enabled CONFIG_CIFS_DFS_UPCALL=y and CONFIG_CIFS_UPCALL=y + - LP: #236830 + + [Upstream Kernel Changes] + + * Revert "[WATCHDOG] hpwdt: Add CFLAGS to get driver working" + * mac80211: detect driver tx bugs + * hwmon: (lm85) Fix function RANGE_TO_REG() + * hwmon: (adt7473) Initialize max_duty_at_overheat before use + * hwmon: Update the sysfs interface documentation + * hwmon: (abituguru3) Identify Abit AW8D board as such + * hwmon: (w83791d) new maintainer + * hwmon: (abituguru3) update driver detection + * hwmon: (lm75) sensor reading bugfix + * ipv6: Remove options header when setsockopt's optlen is 0 + * ipv6: Drop packets for loopback address from outside of the box. + * sched: rt: dont stop the period timer when there are tasks wanting to + run + * sched: fix wait_for_completion_timeout() spurious failure under heavy + load + * x86: fix NULL pointer deref in __switch_to + * xen: Use wmb instead of rmb in xen_evtchn_do_upcall(). + * xen: mask unwanted pte bits in __supported_pte_mask + * xen: don't drop NX bit + * sched: refactor wait_for_completion_timeout() + * Ext4: Fix online resize block group descriptor corruption + * [IA64] SN2: security hole in sn2_ptc_proc_write + * alpha: fix module load failures on smp (bug #10926) + * alpha: link failure fix + * alpha: fix compile failures with gcc-4.3 (bug #10438) + * alpha: resurrect Cypress IDE quirk + * pppoe: warning fix + * sctp: Make sure N * sizeof(union sctp_addr) does not overflow. + * netns: Don't receive new packets in a dead network namespace. + * Add return value to reserve_bootmem_node() + * Slab: Fix memory leak in fallback_alloc() + * Fix performance regression on lmbench select benchmark + * ALSA: aw2 - Fix Oops at initialization + * ALSA: sb - Fix wrong assertions + * futexes: fix fault handling in futex_lock_pi + * IB/mthca: Clear ICM pages before handing to FW + * tty_driver: Update required method documentation + * removed unused var real_tty on n_tty_ioctl() + * Fix ZERO_PAGE breakage with vmware + * mm: fix race in COW logic + * NFS: Reduce the NFS mount code stack usage. + * NFS: Fix filehandle size comparisons in the mount code + * NFS: nfs_updatepage(): don't mark page as dirty if an error occurred + * alpha: fix compile error in arch/alpha/mm/init.c + * KVM: Fix race between timer migration and vcpu migration + * KVM: close timer injection race window in __vcpu_run + * KVM: MMU: Fix rmap_write_protect() hugepage iteration bug + * KVM: MMU: large page update_pte issue with non-PAE 32-bit guests + (resend) + * KVM: MMU: Fix oops on guest userspace access to guest pagetable + * KVM: ioapic: fix lost interrupt when changing a device's irq + * KVM: VMX: Fix host msr corruption with preemption enabled + * [GFS2] BUG: unable to handle kernel paging request at ffff81002690e000 + * xen: remove support for non-PAE 32-bit + * kgdb: documentation update - remove kgdboe + * kgdb: sparse fix + * [IA64] Fix boot failure on ia64/sn2 + * [IA64] Handle count==0 in sn2_ptc_proc_write() + * [IA64] Eliminate NULL test after alloc_bootmem in iosapic_alloc_rte() + * [GFS2] fix gfs2 block allocation (cleaned up) + * x86: Add structs and functions for paravirt clocksource + * x86: Make xen use the paravirt clocksource structs and functions + * KVM: Make kvm host use the paravirt clocksource structs + * x86: KVM guest: Use the paravirt clocksource structs and functions + * KVM: Remove now unused structs from kvm_para.h + * enable bus mastering on i915 at resume time + * Linux 2.6.26-rc8 + * # Ubuntu external driver commit. + * # Ubuntu commit template. + + -- Ben Collins Sat, 21 Jun 2008 09:05:15 -0400 + +linux (2.6.26-2.6) intrepid; urgency=low + + [Ben Collins] + + * Revert "SAUCE: Export symbols for aufs (in lum) (not needed) + * config: Enable DVB devices + * ubuntu/aufs: Make aufs a bool config, since it needs to be built-in + * config: Build aufs into the kernels + * build: Fix arguments passed to link-headers script + * config: Disable early printk + * d-i: Move isofs to storage-core and kill st (scsi tape) from list + * config: Enable non-promiscuous access to /dev/mem + * x86: Add option to disable decompression info messages + * config: Enable no-bz-chatter config options + * build: Re-add linux-source package + * d-i: Re-add socket-modules. Accidentally removed + - LP: #241295 + + [Colin Ian King] + + * Add dm-loop + + [Tim Gardner] + + * Revert "SAUCE: USB bluetooth device 0x0e5e:0x6622 floods errors to + syslog (merged upstream) + + -- Ben Collins Mon, 16 Jun 2008 10:56:01 -0400 + +linux (2.6.26-1.5) intrepid; urgency=low + + * d-i: Make virtio-ring optional (it's built-in on i386) + * Rebased on 2.6.26-rc6 + + [Ubuntu-2.6.26-1.4 Changes below] + + * build: linux-doc rules got broken when disabling html side. Fixed now. + + [Ubuntu-2.6.26-1.3 Changes below] + + * build: Remove install-source, obsolete and caused build failure + + [Ubuntu-2.6.26-1.2 Changes below] + + * Remove efi-modules from d-i module list (efivars is built-in). Caused a + build failure. + * Patch to arch/x86/xen/time.c to remove __divdi3 usage (build failure on + i386). + + [Ubuntu-2.6.26-1.1 Changes below] + + [Amit Kucheria] + + * SAUCE: make fc transport removal of target configurable + * SAUCE: Add AGP support for Radeon Mobility 9000 chipset + * SAUCE: pm: Config option to disable handling of console during + suspend/resume + + [Ben Collins] + + * SAUCE: input/mouse/alps: Do not call psmouse_reset() for alps + * SAUCE: irda: Default to dongle type 9 on IBM hardware + * SAUCE: tulip: Let dmfe handle davicom on non-sparc + * SAUCE: tulip: Define ULI PCI ID's + * SAUCE: version: Implement version_signature proc file. + * build: Remove remnants of unused binary-custom infrastructure + * mmc_block: Fix bad allocation on 64-bit (zero len array) + * ubuntu: New modules, acer-acpi + * build: Remove -virtual, and rebuild configs + * ubuntu: Add drbd module + * ubuntu: Add iscsitarget module + * ubuntu: Add squashfs driver + * build/configs: The Great Config Consistency Check of 2008 + * ubuntu: Add aufs module + * ubuntu: Added atl2 driver + * ubuntu: Add dm-radi4-5 driver + * build: Add CONFIG_DEBUG_SECTION_MISMATCH=y to get old style warnings + from build + * squashfs: Fixes for VFS changes + * ubuntu/dm-raid4-5: Fixups for moved/renamed headers/functions in core + md + * ubuntu: Add ndiswrapper driver + * d-i: Update module listings + + [Chuck Short] + + * SAUCE: ata: blacklist FUJITSU MHW2160BH PL + * SAUCE: [USB]: add ASUS LCM to the blacklist + + [Colin Ian King] + + * SAUCE: Enable speedstep for sonoma processors. + * SAUCE: airprime.c supports more devices + + [Kyle McMartin] + + * SAUCE: fix orinoco_cs oops + + [Mario Limonciello] + + * SAUCE: Enable Reset and SCO workaround on Dell 410 BT adapter + + [Matthew Garrett] + + * SAUCE: hostap: send events on data interface as well as master + interface + + [Phillip Lougher] + + * SAUCE: r8169: disable TSO by default for RTL8111/8168B chipsets. + + [Stefan Bader] + + * SAUCE: Export dm_disk function of device-mapper + * SAUCE: Restore VT fonts on switch + * SAUCE: Always use SCO protocol (disable eSCO support) Bug: #39414 + * SAUCE: mmc: Increase power_up deleay to fix TI readers + * SAUCE: Add blacklist support to fix Belkin bluetooth dongle. + * SAUCE: Lower warning level of pci resource allocation messages. + * SAUCE: Lower message level for PCI memory and I/O allocation. + - LP: #159241 + * Modify log generation to catch bug numbers when adding with git-am. + + [Tim Gardner] + + * SAUCE: hdaps module does not load on Thinkpad T61P + * SAUCE: Add extra headers to linux-libc-dev + * SAUCE: Export symbols for aufs (in lum). + * SAUCE: USB bluetooth device 0x0e5e:0x6622 floods errors to syslog + * SAUCE: Blacklist Bluetooth Dell Wireless 370 for SCO MTU + * SAUCE: Catch nonsense keycodes and silently ignore + * SAUCE: frame buffer regression - screen blank except for blinking + cursor after fbcon vtswitch + * SAUCE: Added support for HDAPS on various ThinkPads from Lenovo and IBM + * SAUCE: Guest OS does not recognize a lun with non zero target id on + Vmware ESX Server + * SAUCE: Modualrize vesafb + * SAUCE: DVB-USB UMT-010 driver oops on install + * SAUCE: fn key doesn't work in hardy with macbook pro fourth generation + (4,1) + - LP: #207127 + + -- Ben Collins Wed, 11 Jun 2008 05:28:35 -0400 --- linux-2.6.27.orig/debian/control.stub.in +++ linux-2.6.27/debian/control.stub.in @@ -0,0 +1,70 @@ +Source: linux +Section: devel +Priority: optional +Maintainer: Ubuntu Kernel Team +Standards-Version: 3.6.1 +Build-Depends: debhelper (>= 3), module-init-tools, kernel-wedge (>= 2.24ubuntu1), makedumpfile +Build-Depends-Indep: xmlto, docbook-utils, gs, transfig, bzip2, sharutils +Vcs-Git: http://kernel.ubuntu.com/git-repos/ubuntu/ubuntu-intrepid.git + +Package: linux-source-PKGVER +Architecture: all +Section: devel +Priority: optional +Provides: linux-source, linux-source-2.6 +Depends: binutils, bzip2, coreutils | fileutils (>= 4.0) +Recommends: libc-dev, gcc, make +Suggests: libncurses-dev | ncurses-dev, kernel-package, libqt3-dev +Description: Linux kernel source for version PKGVER with Ubuntu patches + This package provides the source code for the Linux kernel version + PKGVER. + . + This package is mainly meant for other packages to use, in order to build + custom flavours. + . + If you wish to use this package to create a custom Linux kernel, then it + is suggested that you investigate the package kernel-package, which has + been designed to ease the task of creating kernel image packages. + . + If you are simply trying to build third-party modules for your kernel, + you do not want this package. Install the appropriate linux-headers + package instead. + +Package: linux-doc-PKGVER +Architecture: all +Section: doc +Priority: optional +Provides: linux-doc-2.6 +Conflicts: linux-doc-2.6 +Replaces: linux-doc-2.6 +Depends: coreutils | fileutils (>= 4.0) +Description: Linux kernel specific documentation for version PKGVER + This package provides the various readme's in the PKGVER kernel + Documentation/ subdirectory: these typically contain kernel-specific + installation notes for some drivers for example. See + /usr/share/doc/linux-doc-PKGVER/Documentation/00-INDEX for a list of what + is contained in each file. Please read the Changes file, as it contains + information about the problems, which may result by upgrading your + kernel. + +Package: linux-headers-PKGVER-ABINUM +Architecture: all +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0) +Provides: linux-headers, linux-headers-2.6 +Description: Header files related to Linux kernel version PKGVER + This package provides kernel header files for version PKGVER, for sites + that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-PKGVER-ABINUM/debian.README.gz for details + +Package: linux-libc-dev +Architecture: i386 amd64 +Conflicts: libc6-dev (<< 2.3.2.ds1-6), libc6.1-dev (<< 2.3.2.ds1-6), dvb-dev (<< 1.0.1-6), amd64-libs-dev (<= 1.1), linux-kernel-headers +Replaces: libc6-dev (<< 2.3.2.ds1-6), libc6.1-dev (<< 2.3.2.ds1-6), dvb-dev (<< 1.0.1-6), linux-kernel-headers +Provides: linux-kernel-headers +Description: Linux Kernel Headers for development + This package provides headers from the Linux kernel. These headers + are used by the installed headers for GNU glibc and other system + libraries. They are NOT meant to be used to build third-party modules for + your kernel. Use linux-headers-* packages for that. --- linux-2.6.27.orig/debian/sub-flavours/virtual.vars +++ linux-2.6.27/debian/sub-flavours/virtual.vars @@ -0,0 +1,11 @@ +# Based on server flavour +arch="i386 amd64" +supported="Virtual" +target="Geared toward virtual machine guests." +desc="x86/x86_64" +bootloader="lilo (>= 19.1) | grub" +is_sub="true" +based_on="server" +# The provides and conflicts are REQUIRED +provides="redhat-cluster-modules" +conflicts="linux-image-PKGVER-ABINUM-${based_on}" --- linux-2.6.27.orig/debian/sub-flavours/virtual.list +++ linux-2.6.27/debian/sub-flavours/virtual.list @@ -0,0 +1,111 @@ +arch/*/{crypto,kernel,oprofile} +crypto/* +drivers/acpi/* +drivers/ata/ata_generic.ko +drivers/ata/ata_piix.ko +drivers/ata/libata.ko +drivers/block/virtio_blk.ko +drivers/block/nbd.ko +drivers/block/loop.ko +drivers/block/floppy.ko +drivers/block/cryptoloop.ko +drivers/block/xen-blkfront.ko +drivers/cdrom/cdrom.ko +drivers/char/hangcheck-timer.ko +drivers/char/lp.ko +drivers/char/nvram.ko +drivers/char/ppdev.ko +drivers/char/raw.ko +drivers/input/evbug.ko +drivers/input/evdev.ko +drivers/input/gameport/gameport.ko +drivers/input/mouse/psmouse.ko +drivers/input/serio/serio_raw.ko +drivers/input/serio/serport.ko +drivers/input/joydev.ko +drivers/input/misc/uinput.ko +drivers/input/touchscreen/usbtouchscreen.ko +drivers/input/xen-kbdfront.ko +drivers/md/* +drivers/message/fusion* +drivers/misc/eeprom_93cx6.ko +drivers/net/8139too.ko +drivers/net/8139cp.ko +drivers/net/appletalk/ipddp.ko +drivers/net/bonding/bonding.ko +drivers/net/bsd_comp.ko +drivers/net/dummy.ko +drivers/net/e1000/e1000.ko +drivers/net/eql.ko +drivers/net/ifb.ko +drivers/net/mii.ko +drivers/net/ne2k-pci.ko +drivers/net/netconsole.ko +drivers/net/pcnet32.ko +drivers/net/ppp_async.ko +drivers/net/ppp_deflate.ko +drivers/net/ppp_generic.ko +drivers/net/ppp_mppe.ko +drivers/net/pppoe.ko +drivers/net/pppol2tp.ko +drivers/net/pppox.ko +drivers/net/ppp_synctty.ko +drivers/net/slhc.ko +drivers/net/slip.ko +drivers/net/tun.ko +drivers/net/veth.ko +drivers/net/virtio_net.ko +drivers/net/xen-netfront.ko +drivers/parport/parport.ko +drivers/parport/parport_pc.ko +drivers/net/tulip/tulip.ko +drivers/net/virtio_net.ko +drivers/scsi/BusLogic.ko +drivers/scsi/iscsi_tcp.ko +drivers/scsi/libiscsi.ko +drivers/scsi/libsas/* +drivers/scsi/libsas/libsas.ko +drivers/scsi/qla1280.ko +drivers/scsi/raid_class.ko +drivers/scsi/scsi_mod.ko +drivers/scsi/scsi_transport_fc.ko +drivers/scsi/scsi_transport_iscsi.ko +drivers/scsi/scsi_transport_sas.ko +drivers/scsi/scsi_transport_spi.ko +drivers/scsi/scsi_wait_scan.ko +drivers/scsi/sd_mod.ko +drivers/scsi/sg.ko +drivers/scsi/sr_mod.ko +drivers/usb/core/usbcore.ko +drivers/usb/host/ehci-hcd.ko +drivers/usb/host/uhci-hcd.ko +drivers/usb/storage/usb-storage.ko +drivers/video/cirrusfb.ko +drivers/video/console/bitblit.ko +drivers/video/console/fbcon.ko +drivers/video/console/font.ko +drivers/video/console/softcursor.ko +drivers/video/console/tileblit.ko +drivers/video/output.ko +drivers/video/syscopyarea.ko +drivers/video/sysfillrect.ko +drivers/video/sysimgblt.ko +drivers/video/vesafb.ko +drivers/video/vga16fb.ko +drivers/video/vgastate.ko +drivers/video/xen-fbfront.ko +drivers/virtio/virtio_balloon.ko +drivers/virtio/virtio.ko +drivers/virtio/virtio_pci.ko +drivers/virtio/virtio_ring.ko +drivers/watchdog/softdog.ko +drivers/xen/* +fs/* +lib/* +net/* +sound/core/* +sound/pci/snd-ens1370.ko +sound/drivers/pcsp/snd-pcsp.ko +ubuntu/e1000e/e1000e.ko +ubuntu/squashfs/squashfs.ko +ubuntu/iscsitarget/iscsi_trgt.ko --- linux-2.6.27.orig/debian/sub-flavours/README +++ linux-2.6.27/debian/sub-flavours/README @@ -0,0 +1,12 @@ +Sub flavours are flavours that are built based on other builds. IOW, they +are usually a subset of something else. + +Requirements: + +debian/sub-flavours/.list : The file list, uses glob syntax +debian/sub-flavours/.vars : The make vars, similar to normal flavours +debian/rules.d/.mk : Add _sub var listing the , e.g. + server_sub = virtual would mean virtual is + based on the server flavour. + +Note, the vars must include a conflicts with the flavour it was built on. --- linux-2.6.27.orig/debian/sub-flavours/control.stub +++ linux-2.6.27/debian/sub-flavours/control.stub @@ -0,0 +1,39 @@ +# Items that get replaced: +# FLAVOUR +# DESC +# ARCH +# SUPPORTED +# TARGET +# BOOTLOADER +# =PROVIDES= +# =CONFLICTS= +# +# Items marked with =FOO= are optional +# +# XXX: Leave the blank line before the first package!! + +Package: linux-image-PKGVER-ABINUM-FLAVOUR +Architecture: ARCH +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, =PROVIDES= +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1), =CONFLICTS= +Recommends: BOOTLOADER +Suggests: fdutils, linux-doc-PKGVER | linux-source-PKGVER +Description: Linux kernel image for version PKGVER on DESC + This package contains the Linux kernel image for version PKGVER on + DESC. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports SUPPORTED processors. + . + TARGET + . + You likely do not want to install this package directly. Instead, install + the linux-FLAVOUR meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. --- linux-2.6.27.orig/debian/control.d/vars.server +++ linux-2.6.27/debian/control.d/vars.server @@ -0,0 +1,6 @@ +arch="i386 amd64" +supported="Server" +target="Geared toward server systems." +desc="x86/x86_64" +bootloader="lilo (>= 19.1) | grub" +provides="redhat-cluster-modules, kvm-api-4, ivtv-modules, ndiswrapper-modules-1.9" --- linux-2.6.27.orig/debian/control.d/flavour-control.stub +++ linux-2.6.27/debian/control.d/flavour-control.stub @@ -0,0 +1,66 @@ +# Items that get replaced: +# FLAVOUR +# DESC +# ARCH +# SUPPORTED +# TARGET +# BOOTLOADER +# =PROVIDES= +# +# Items marked with =FOO= are optional +# +# XXX: Leave the blank line before the first package!! + +Package: linux-image-PKGVER-ABINUM-FLAVOUR +Architecture: ARCH +Section: base +Priority: optional +Pre-Depends: dpkg (>= 1.10.24) +Provides: linux-image, linux-image-2.6, fuse-module, =PROVIDES= +Depends: initramfs-tools (>= 0.36ubuntu6), coreutils | fileutils (>= 4.0), module-init-tools (>= 3.3-pre11-4ubuntu3) +Conflicts: hotplug (<< 0.0.20040105-1) +Recommends: BOOTLOADER +Suggests: fdutils, linux-doc-PKGVER | linux-source-PKGVER +Description: Linux kernel image for version PKGVER on DESC + This package contains the Linux kernel image for version PKGVER on + DESC. + . + Also includes the corresponding System.map file, the modules built by the + packager, and scripts that try to ensure that the system is not left in an + unbootable state after an update. + . + Supports SUPPORTED processors. + . + TARGET + . + You likely do not want to install this package directly. Instead, install + the linux-FLAVOUR meta-package, which will ensure that upgrades work + correctly, and that supporting packages are also installed. + +Package: linux-headers-PKGVER-ABINUM-FLAVOUR +Architecture: ARCH +Section: devel +Priority: optional +Depends: coreutils | fileutils (>= 4.0), linux-headers-PKGVER-ABINUM, ${shlibs:Depends} +Provides: linux-headers, linux-headers-2.6 +Description: Linux kernel headers for version PKGVER on DESC + This package provides kernel header files for version PKGVER on + DESC. + . + This is for sites that want the latest kernel headers. Please read + /usr/share/doc/linux-headers-PKGVER-ABINUM/debian.README.gz for details. + +Package: linux-image-debug-PKGVER-ABINUM-FLAVOUR +Architecture: ARCH +Section: devel +Priority: optional +Provides: linux-debug +Description: Linux kernel debug image for version PKGVER on DESC + This package provides a kernel debug image for version PKGVER on + DESC. + . + This is for sites that wish to debug the kernel. + . + The kernel image contained in this package is NOT meant to boot from. It + is uncompressed, and unstripped. This package also includes the + unstripped modules. --- linux-2.6.27.orig/debian/control.d/vars.generic +++ linux-2.6.27/debian/control.d/vars.generic @@ -0,0 +1,6 @@ +arch="i386 amd64" +supported="Generic" +target="Geared toward desktop systems." +desc="x86/x86_64" +bootloader="lilo (>= 19.1) | grub" +provides="kvm-api-4, redhat-cluster-modules, ivtv-modules, ndiswrapper-modules-1.9" --- linux-2.6.27.orig/debian/stamps/keep-dir +++ linux-2.6.27/debian/stamps/keep-dir @@ -0,0 +1 @@ +Place holder --- linux-2.6.27.orig/debian/abi/perm-blacklist +++ linux-2.6.27/debian/abi/perm-blacklist @@ -0,0 +1,3 @@ +M: ubuntu/misc/wireless/p80211/p80211 +M: sound/pci/emu10k1/snd-emu10k1 +M: fs/xfs/xfs --- linux-2.6.27.orig/debian/abi/2.6.27-14.39/i386/generic +++ linux-2.6.27/debian/abi/2.6.27-14.39/i386/generic @@ -0,0 +1,8167 @@ +EXPORT_SYMBOL arch/x86/kernel/scx200 0x254e5667 scx200_gpio_base +EXPORT_SYMBOL arch/x86/kernel/scx200 0x35a3c008 scx200_gpio_configure +EXPORT_SYMBOL arch/x86/kernel/scx200 0x8cfa375c scx200_gpio_shadow +EXPORT_SYMBOL arch/x86/kernel/scx200 0x907665bd scx200_cb_base +EXPORT_SYMBOL arch/x86/kvm/kvm 0x2383ed96 kvm_cpu_has_pending_timer +EXPORT_SYMBOL arch/x86/kvm/kvm 0x43401a5a kvm_read_guest_atomic +EXPORT_SYMBOL crypto/gf128mul 0x0c2f123f gf128mul_4k_bbe +EXPORT_SYMBOL crypto/gf128mul 0x1068004b gf128mul_bbe +EXPORT_SYMBOL crypto/gf128mul 0x2f2889a0 gf128mul_init_64k_lle +EXPORT_SYMBOL crypto/gf128mul 0x3755f990 gf128mul_init_64k_bbe +EXPORT_SYMBOL crypto/gf128mul 0x384ef9ce gf128mul_64k_bbe +EXPORT_SYMBOL crypto/gf128mul 0x56af0dbd gf128mul_x_ble +EXPORT_SYMBOL crypto/gf128mul 0x83581089 gf128mul_init_4k_lle +EXPORT_SYMBOL crypto/gf128mul 0x9b2560b9 gf128mul_init_4k_bbe +EXPORT_SYMBOL crypto/gf128mul 0x9e13f6f6 gf128mul_lle +EXPORT_SYMBOL crypto/gf128mul 0xbd17a0df gf128mul_4k_lle +EXPORT_SYMBOL crypto/gf128mul 0xc0890413 gf128mul_64k_lle +EXPORT_SYMBOL crypto/gf128mul 0xd60736ec gf128mul_free_64k +EXPORT_SYMBOL crypto/xor 0x5b6c00e6 xor_blocks +EXPORT_SYMBOL drivers/acpi/processor 0x0603377d acpi_processor_preregister_performance +EXPORT_SYMBOL drivers/acpi/processor 0x8461fbfe acpi_processor_unregister_performance +EXPORT_SYMBOL drivers/acpi/processor 0xd78b77e1 acpi_processor_register_performance +EXPORT_SYMBOL drivers/acpi/processor 0xe420d26f acpi_processor_notify_smm +EXPORT_SYMBOL drivers/acpi/processor 0xe8a3605f acpi_processor_set_thermal_limit +EXPORT_SYMBOL drivers/atm/suni 0x6793b509 suni_init +EXPORT_SYMBOL drivers/atm/uPD98402 0x69a90688 uPD98402_init +EXPORT_SYMBOL drivers/block/loop 0x6164292d loop_register_transfer +EXPORT_SYMBOL drivers/block/loop 0xbfee3ad5 loop_unregister_transfer +EXPORT_SYMBOL drivers/block/paride/paride 0x173be116 pi_release +EXPORT_SYMBOL drivers/block/paride/paride 0x435f916c pi_schedule_claimed +EXPORT_SYMBOL drivers/block/paride/paride 0x79f3b18b pi_do_claimed +EXPORT_SYMBOL drivers/block/paride/paride 0x8125dc28 pi_write_regr +EXPORT_SYMBOL drivers/block/paride/paride 0x8b7fb07a pi_read_regr +EXPORT_SYMBOL drivers/block/paride/paride 0x9f70720d paride_register +EXPORT_SYMBOL drivers/block/paride/paride 0x9fbb3f18 pi_disconnect +EXPORT_SYMBOL drivers/block/paride/paride 0xa7d0e5bb pi_init +EXPORT_SYMBOL drivers/block/paride/paride 0xca24a986 pi_write_block +EXPORT_SYMBOL drivers/block/paride/paride 0xd0d78e3c pi_read_block +EXPORT_SYMBOL drivers/block/paride/paride 0xd9914f20 pi_connect +EXPORT_SYMBOL drivers/block/paride/paride 0xf370c110 paride_unregister +EXPORT_SYMBOL drivers/cdrom/cdrom 0x4f476e96 init_cdrom_command +EXPORT_SYMBOL drivers/cdrom/cdrom 0x5bfb9602 cdrom_get_last_written +EXPORT_SYMBOL drivers/cdrom/cdrom 0x67e6e97f cdrom_number_of_slots +EXPORT_SYMBOL drivers/cdrom/cdrom 0x7a54fa41 register_cdrom +EXPORT_SYMBOL drivers/cdrom/cdrom 0x83777e84 cdrom_media_changed +EXPORT_SYMBOL drivers/cdrom/cdrom 0x91a6eb9c cdrom_mode_select +EXPORT_SYMBOL drivers/cdrom/cdrom 0x930dd372 cdrom_open +EXPORT_SYMBOL drivers/cdrom/cdrom 0xa4b06e56 cdrom_get_media_event +EXPORT_SYMBOL drivers/cdrom/cdrom 0xb1bfa3f8 cdrom_release +EXPORT_SYMBOL drivers/cdrom/cdrom 0xb5cd29bd cdrom_ioctl +EXPORT_SYMBOL drivers/cdrom/cdrom 0xc0e53521 cdrom_mode_sense +EXPORT_SYMBOL drivers/cdrom/cdrom 0xd7e2ab95 unregister_cdrom +EXPORT_SYMBOL drivers/char/agp/agpgart 0x163f2687 agp_generic_enable +EXPORT_SYMBOL drivers/char/agp/agpgart 0x1a6a9e94 agp_find_bridge +EXPORT_SYMBOL drivers/char/agp/agpgart 0x1aea51a2 agp3_generic_tlbflush +EXPORT_SYMBOL drivers/char/agp/agpgart 0x1e2f5175 agp_generic_destroy_page +EXPORT_SYMBOL drivers/char/agp/agpgart 0x2bf9e0b1 agp_generic_alloc_page +EXPORT_SYMBOL drivers/char/agp/agpgart 0x2e4a4ba3 agp_generic_type_to_mask_type +EXPORT_SYMBOL drivers/char/agp/agpgart 0x2ff403d5 agp_generic_free_by_type +EXPORT_SYMBOL drivers/char/agp/agpgart 0x30226ddf agp_device_command +EXPORT_SYMBOL drivers/char/agp/agpgart 0x3eccb323 agp_flush_chipset +EXPORT_SYMBOL drivers/char/agp/agpgart 0x3ed93335 agp_generic_remove_memory +EXPORT_SYMBOL drivers/char/agp/agpgart 0x4575d390 get_agp_version +EXPORT_SYMBOL drivers/char/agp/agpgart 0x47341ca5 agp_unbind_memory +EXPORT_SYMBOL drivers/char/agp/agpgart 0x4840bc44 agp_free_memory +EXPORT_SYMBOL drivers/char/agp/agpgart 0x4b085dbf agp3_generic_configure +EXPORT_SYMBOL drivers/char/agp/agpgart 0x508c9381 agp_backend_acquire +EXPORT_SYMBOL drivers/char/agp/agpgart 0x59ff930b agp_generic_alloc_user +EXPORT_SYMBOL drivers/char/agp/agpgart 0x5badf240 agp_bridge +EXPORT_SYMBOL drivers/char/agp/agpgart 0x5bff2025 agp_alloc_page_array +EXPORT_SYMBOL drivers/char/agp/agpgart 0x6436ca16 agp_bind_memory +EXPORT_SYMBOL drivers/char/agp/agpgart 0x666ec4c0 agp_generic_mask_memory +EXPORT_SYMBOL drivers/char/agp/agpgart 0x673f815e agp_bridges +EXPORT_SYMBOL drivers/char/agp/agpgart 0x6afc5c30 agp_create_memory +EXPORT_SYMBOL drivers/char/agp/agpgart 0x749119f0 agp_put_bridge +EXPORT_SYMBOL drivers/char/agp/agpgart 0x7538b132 agp_off +EXPORT_SYMBOL drivers/char/agp/agpgart 0x9ca2b69d agp_generic_alloc_by_type +EXPORT_SYMBOL drivers/char/agp/agpgart 0xa4441909 agp_alloc_bridge +EXPORT_SYMBOL drivers/char/agp/agpgart 0xa4d4f0e6 global_cache_flush +EXPORT_SYMBOL drivers/char/agp/agpgart 0xa600a365 agp_allocate_memory +EXPORT_SYMBOL drivers/char/agp/agpgart 0xa8a9a532 agp_generic_free_gatt_table +EXPORT_SYMBOL drivers/char/agp/agpgart 0xac50114e agp_generic_create_gatt_table +EXPORT_SYMBOL drivers/char/agp/agpgart 0xb04ea8f0 agp_rebind_memory +EXPORT_SYMBOL drivers/char/agp/agpgart 0xb084f55f agp_collect_device_status +EXPORT_SYMBOL drivers/char/agp/agpgart 0xc2424641 agp3_generic_cleanup +EXPORT_SYMBOL drivers/char/agp/agpgart 0xc5d9c46c agp_try_unsupported_boot +EXPORT_SYMBOL drivers/char/agp/agpgart 0xc65abeb7 agp3_generic_sizes +EXPORT_SYMBOL drivers/char/agp/agpgart 0xd0fef3b2 agp_free_key +EXPORT_SYMBOL drivers/char/agp/agpgart 0xd9d5c2d7 agp_enable +EXPORT_SYMBOL drivers/char/agp/agpgart 0xde9b17ed agp3_generic_fetch_size +EXPORT_SYMBOL drivers/char/agp/agpgart 0xe1899cfc agp_backend_release +EXPORT_SYMBOL drivers/char/agp/agpgart 0xe2e274c0 agp_free_page_array +EXPORT_SYMBOL drivers/char/agp/agpgart 0xeb5e7bfd agp_generic_insert_memory +EXPORT_SYMBOL drivers/char/agp/agpgart 0xedbfc74e agp_copy_info +EXPORT_SYMBOL drivers/char/generic_serial 0x16b722b6 gs_set_termios +EXPORT_SYMBOL drivers/char/generic_serial 0x17dc653f gs_chars_in_buffer +EXPORT_SYMBOL drivers/char/generic_serial 0x1dea473e gs_block_til_ready +EXPORT_SYMBOL drivers/char/generic_serial 0x2d7aa5b8 gs_write +EXPORT_SYMBOL drivers/char/generic_serial 0x41d9b4d1 gs_stop +EXPORT_SYMBOL drivers/char/generic_serial 0x45c38c8f gs_hangup +EXPORT_SYMBOL drivers/char/generic_serial 0x47ee9fda gs_flush_buffer +EXPORT_SYMBOL drivers/char/generic_serial 0x48c63a31 gs_init_port +EXPORT_SYMBOL drivers/char/generic_serial 0x524d3af9 gs_got_break +EXPORT_SYMBOL drivers/char/generic_serial 0x575dcae2 gs_put_char +EXPORT_SYMBOL drivers/char/generic_serial 0x62a8e6eb gs_getserial +EXPORT_SYMBOL drivers/char/generic_serial 0x7f0d8ff3 gs_flush_chars +EXPORT_SYMBOL drivers/char/generic_serial 0x867d8c81 gs_start +EXPORT_SYMBOL drivers/char/generic_serial 0xdef2e6c8 gs_write_room +EXPORT_SYMBOL drivers/char/generic_serial 0xeb04ff08 gs_close +EXPORT_SYMBOL drivers/char/generic_serial 0xf96ede3a gs_setserial +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x0bbb45b5 ipmi_set_my_LUN +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x198b9180 ipmi_request_supply_msgs +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x1d2f2240 ipmi_unregister_for_cmd +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x308f3b5b ipmi_smi_add_proc_entry +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x3419163d ipmi_set_my_address +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x365429a0 ipmi_destroy_user +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x3e6f0118 ipmi_smi_watcher_register +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x40f2b10c ipmi_alloc_smi_msg +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x53c8c46b ipmi_get_version +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x58e373f8 ipmi_set_maintenance_mode +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x649bfe2d ipmi_poll_interface +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x727b56a8 ipmi_set_gets_events +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x77f79b57 ipmi_create_user +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x804f922a ipmi_addr_length +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x84aa2bf8 ipmi_smi_watchdog_pretimeout +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x91f73f10 ipmi_register_smi +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x9ef944c3 ipmi_get_maintenance_mode +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xa1998bbf ipmi_smi_msg_received +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xa463f5a3 ipmi_free_recv_msg +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xc15c3c6a ipmi_get_my_address +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xdd2bcd1b ipmi_get_my_LUN +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xe4f4665b ipmi_validate_addr +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xe57787a1 ipmi_register_for_cmd +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xedc0cb52 ipmi_request_settime +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xf5974ffc ipmi_unregister_smi +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xff837431 ipmi_smi_watcher_unregister +EXPORT_SYMBOL drivers/char/nsc_gpio 0x22771650 nsc_gpio_dump +EXPORT_SYMBOL drivers/char/nsc_gpio 0xe6fc2958 nsc_gpio_write +EXPORT_SYMBOL drivers/char/nsc_gpio 0xf31a4193 nsc_gpio_read +EXPORT_SYMBOL drivers/char/nvram 0x0f28cb91 nvram_read_byte +EXPORT_SYMBOL drivers/char/nvram 0x17ff2c1d __nvram_read_byte +EXPORT_SYMBOL drivers/char/nvram 0x2adec1e0 __nvram_check_checksum +EXPORT_SYMBOL drivers/char/nvram 0x7da28f12 nvram_check_checksum +EXPORT_SYMBOL drivers/char/nvram 0x9ce3f83f nvram_write_byte +EXPORT_SYMBOL drivers/char/nvram 0xa8813189 __nvram_write_byte +EXPORT_SYMBOL drivers/cpufreq/cpufreq_conservative 0x833a5dbb cpufreq_gov_conservative +EXPORT_SYMBOL drivers/cpufreq/cpufreq_ondemand 0x83a131ed cpufreq_gov_ondemand +EXPORT_SYMBOL drivers/cpufreq/cpufreq_powersave 0x26d1a0fb cpufreq_gov_powersave +EXPORT_SYMBOL drivers/cpufreq/cpufreq_userspace 0x05761843 cpufreq_gov_userspace +EXPORT_SYMBOL drivers/edac/edac_core 0x83dac0e1 edac_mc_handle_fbd_ce +EXPORT_SYMBOL drivers/edac/edac_core 0x8be74a24 edac_mc_handle_fbd_ue +EXPORT_SYMBOL drivers/edac/edac_core 0xcc0b2b49 edac_mc_find +EXPORT_SYMBOL drivers/gpu/drm/drm 0x00f7124c drm_core_ioremap +EXPORT_SYMBOL drivers/gpu/drm/drm 0x059a7209 drm_exit +EXPORT_SYMBOL drivers/gpu/drm/drm 0x0836695c drm_sman_takedown +EXPORT_SYMBOL drivers/gpu/drm/drm 0x0ce834bd drm_sg_alloc +EXPORT_SYMBOL drivers/gpu/drm/drm 0x156f12ca drm_release +EXPORT_SYMBOL drivers/gpu/drm/drm 0x1d81b09c drm_addmap +EXPORT_SYMBOL drivers/gpu/drm/drm 0x20645642 drm_debug +EXPORT_SYMBOL drivers/gpu/drm/drm 0x20aa63c5 drm_ati_pcigart_cleanup +EXPORT_SYMBOL drivers/gpu/drm/drm 0x21451ac4 drm_sman_owner_cleanup +EXPORT_SYMBOL drivers/gpu/drm/drm 0x22283368 drm_rmmap +EXPORT_SYMBOL drivers/gpu/drm/drm 0x25dd3b58 drm_agp_bind +EXPORT_SYMBOL drivers/gpu/drm/drm 0x262117b1 drm_agp_info +EXPORT_SYMBOL drivers/gpu/drm/drm 0x2916bf63 drm_sman_cleanup +EXPORT_SYMBOL drivers/gpu/drm/drm 0x2eb2f903 drm_sman_free_key +EXPORT_SYMBOL drivers/gpu/drm/drm 0x2f9ec352 drm_ioctl +EXPORT_SYMBOL drivers/gpu/drm/drm 0x3074f033 drm_order +EXPORT_SYMBOL drivers/gpu/drm/drm 0x3401680f drm_poll +EXPORT_SYMBOL drivers/gpu/drm/drm 0x40444b22 drm_agp_unbind +EXPORT_SYMBOL drivers/gpu/drm/drm 0x55f060ee drm_sman_set_range +EXPORT_SYMBOL drivers/gpu/drm/drm 0x56ee11e4 drm_getsarea +EXPORT_SYMBOL drivers/gpu/drm/drm 0x5726bfe0 drm_open +EXPORT_SYMBOL drivers/gpu/drm/drm 0x59c011ab drm_vbl_send_signals +EXPORT_SYMBOL drivers/gpu/drm/drm 0x5adcc2a0 drm_idlelock_take +EXPORT_SYMBOL drivers/gpu/drm/drm 0x62dde739 drm_fasync +EXPORT_SYMBOL drivers/gpu/drm/drm 0x6d9f29e0 drm_agp_release +EXPORT_SYMBOL drivers/gpu/drm/drm 0x765a006a drm_i_have_hw_lock +EXPORT_SYMBOL drivers/gpu/drm/drm 0x77be935a drm_ati_pcigart_init +EXPORT_SYMBOL drivers/gpu/drm/drm 0x7d7c7926 drm_mmap +EXPORT_SYMBOL drivers/gpu/drm/drm 0x9c25b192 drm_core_get_map_ofs +EXPORT_SYMBOL drivers/gpu/drm/drm 0x9e10dd3f drm_pci_free +EXPORT_SYMBOL drivers/gpu/drm/drm 0xaf29788e drm_sman_init +EXPORT_SYMBOL drivers/gpu/drm/drm 0xb268f3c4 drm_core_ioremapfree +EXPORT_SYMBOL drivers/gpu/drm/drm 0xb4b6f84c drm_addbufs_pci +EXPORT_SYMBOL drivers/gpu/drm/drm 0xb6ea6299 drm_core_get_reg_ofs +EXPORT_SYMBOL drivers/gpu/drm/drm 0xb7588fe4 drm_core_reclaim_buffers +EXPORT_SYMBOL drivers/gpu/drm/drm 0xbafa5966 drm_agp_free +EXPORT_SYMBOL drivers/gpu/drm/drm 0xbc2a1f55 drm_get_drawable_info +EXPORT_SYMBOL drivers/gpu/drm/drm 0xc968c7c2 drm_agp_acquire +EXPORT_SYMBOL drivers/gpu/drm/drm 0xc9937be5 drm_core_ioremap_wc +EXPORT_SYMBOL drivers/gpu/drm/drm 0xcd06530b drm_irq_uninstall +EXPORT_SYMBOL drivers/gpu/drm/drm 0xd3028e75 drm_sman_set_manager +EXPORT_SYMBOL drivers/gpu/drm/drm 0xd981cce5 drm_get_resource_len +EXPORT_SYMBOL drivers/gpu/drm/drm 0xd981f732 drm_locked_tasklet +EXPORT_SYMBOL drivers/gpu/drm/drm 0xda8b4604 drm_pci_alloc +EXPORT_SYMBOL drivers/gpu/drm/drm 0xdb6aa67d drm_init +EXPORT_SYMBOL drivers/gpu/drm/drm 0xdfd5a7a3 drm_agp_alloc +EXPORT_SYMBOL drivers/gpu/drm/drm 0xe919dd5c drm_sman_owner_clean +EXPORT_SYMBOL drivers/gpu/drm/drm 0xed1d6c73 drm_agp_enable +EXPORT_SYMBOL drivers/gpu/drm/drm 0xf3194446 drm_get_resource_start +EXPORT_SYMBOL drivers/gpu/drm/drm 0xf720b656 drm_idlelock_release +EXPORT_SYMBOL drivers/gpu/drm/drm 0xf7e406de drm_addbufs_agp +EXPORT_SYMBOL drivers/gpu/drm/drm 0xfdfbad19 drm_sman_alloc +EXPORT_SYMBOL drivers/hwmon/hwmon-vid 0x0903c239 vid_from_reg +EXPORT_SYMBOL drivers/hwmon/hwmon-vid 0xef1c781c vid_which_vrm +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-bit 0x7780aa1e i2c_bit_add_bus +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-bit 0xb9d0f11b i2c_bit_add_numbered_bus +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-pca 0x5f3a3913 i2c_pca_add_bus +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-pca 0x866a32eb i2c_pca_add_numbered_bus +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-pcf 0x002c00be i2c_pcf_add_bus +EXPORT_SYMBOL drivers/i2c/busses/i2c-amd756 0xb8b4adb5 amd756_smbus +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0x02d4ad0f tps65013_set_low_pwr +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0x28485130 tps65010_config_vregs1 +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0x33739de7 tps65010_set_vib +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0x9fd44c69 tps65010_set_led +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0xb14080cc tps65010_set_low_pwr +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0xd5bb106d tps65010_set_vbus_draw +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0xe99b3f36 tps65010_set_gpio_out_value +EXPORT_SYMBOL drivers/i2c/i2c-core 0x05d2976e i2c_smbus_write_i2c_block_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0x0db0decf i2c_smbus_read_byte +EXPORT_SYMBOL drivers/i2c/i2c-core 0x1bdef718 i2c_smbus_read_block_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0x2854b7b0 i2c_attach_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0x29509f5a i2c_smbus_read_i2c_block_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0x2ad2f331 i2c_smbus_write_byte +EXPORT_SYMBOL drivers/i2c/i2c-core 0x319f1e43 i2c_detach_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0x370a78fc i2c_smbus_read_word_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0x3cc941e2 i2c_register_driver +EXPORT_SYMBOL drivers/i2c/i2c-core 0x42a7bec3 i2c_clients_command +EXPORT_SYMBOL drivers/i2c/i2c-core 0x4ee3b8a3 i2c_put_adapter +EXPORT_SYMBOL drivers/i2c/i2c-core 0x51f9b8f2 i2c_master_recv +EXPORT_SYMBOL drivers/i2c/i2c-core 0x54eaf784 i2c_transfer +EXPORT_SYMBOL drivers/i2c/i2c-core 0x5c11ff86 i2c_get_adapter +EXPORT_SYMBOL drivers/i2c/i2c-core 0x626a9f05 i2c_add_adapter +EXPORT_SYMBOL drivers/i2c/i2c-core 0x6b7d7c31 i2c_smbus_xfer +EXPORT_SYMBOL drivers/i2c/i2c-core 0x78930dab i2c_del_driver +EXPORT_SYMBOL drivers/i2c/i2c-core 0x7e5f7190 i2c_probe +EXPORT_SYMBOL drivers/i2c/i2c-core 0x8fc27c98 i2c_verify_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0x93fee89d i2c_smbus_write_word_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0xac3313d5 i2c_smbus_read_byte_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0xac395397 i2c_smbus_write_byte_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0xc0197c7e i2c_use_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0xc4314472 i2c_release_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0xc4c060cd i2c_master_send +EXPORT_SYMBOL drivers/i2c/i2c-core 0xf5cbb7a8 i2c_smbus_write_block_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0xf97401ba i2c_del_adapter +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x03ae941a hpsb_iso_stop +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0a68590c hpsb_get_hostinfo +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0c6da941 csr1212_release_keyval +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0e5a659c csr1212_new_directory +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x1026c699 hpsb_update_config_rom_image +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x13b4a268 csr1212_attach_keyval_to_directory +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x1ce8cc9b hpsb_get_hostinfo_bykey +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x1d20f7df hpsb_selfid_complete +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x219cbabe dma_region_offset_to_bus +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x22637374 hpsb_iso_wake +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x2752b9a8 csr1212_get_keyval +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x2a118a10 hpsb_iso_xmit_queue_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x2a642138 hpsb_iso_shutdown +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x358d3ab7 hpsb_destroy_hostinfo +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x37a736c9 csr1212_read +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x3ed624b3 hpsb_iso_recv_unlisten_channel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x4f828560 hpsb_node_fill_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x51769adf hpsb_iso_recv_release_packets +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x52de4d63 hpsb_set_packet_complete_task +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x59dee015 hpsb_iso_xmit_sync +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x5f88661c hpsb_protocol_class +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x5fc68198 hpsb_get_tlabel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x6180e6f9 hpsb_register_highlevel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x642f011b hpsb_make_lockpacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x672ad148 dma_region_sync_for_device +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x677daf9b hpsb_iso_recv_flush +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x685da8d6 __hpsb_register_protocol +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x6e084ffd hpsb_free_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x6ef70d72 hpsb_write +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x7046e886 csr1212_parse_keyval +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x730e628a hpsb_create_hostinfo +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x75ee910e hpsb_resume_host +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x76bc1a5c dma_region_free +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x76e8939c hpsb_unregister_highlevel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x79dc4432 hpsb_selfid_received +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x7cd59654 hpsb_make_readpacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x84c0d4c9 hpsb_iso_xmit_start +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x8518b899 hpsb_iso_packet_sent +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x8879f8f0 dma_region_sync_for_cpu +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x898bdd9b hpsb_make_streampacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x8ec2b312 dma_region_alloc +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x949ab8c7 hpsb_iso_recv_set_channel_mask +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x950b59ad hpsb_bus_reset +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x979b3052 dma_prog_region_init +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x9960598d hpsb_read +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x9cd89958 hpsb_send_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x9e42751e hpsb_update_config_rom +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x9f906100 hpsb_make_writepacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xa33e5aac hpsb_register_addrspace +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xa737b549 hpsb_make_lock64packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xa924dac6 dma_prog_region_alloc +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xaa3c2049 hpsb_node_write +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xaad80ce0 hpsb_packet_received +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xafab38fc hpsb_iso_n_ready +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xb0c78435 hpsb_iso_recv_init +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xb96583fb hpsb_set_hostinfo +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xbba70620 dma_prog_region_free +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xbe7e605c hpsb_remove_host +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xbefbac0c hpsb_alloc_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xbf829df2 hpsb_make_phypacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xc669a4d3 csr1212_detach_keyval_from_directory +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xc713ab27 hpsb_iso_xmit_init +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xc9f3473e hpsb_set_hostinfo_key +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xd02b1048 hpsb_packet_sent +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xd6e2b347 hpsb_free_tlabel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xdc30e690 hpsb_unregister_addrspace +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xdcb43707 dma_region_mmap +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xdda7d35d hpsb_reset_bus +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xe060e3f9 hpsb_packet_success +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xe2571502 hpsb_iso_packet_received +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xe59a428a hpsb_alloc_host +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xe683e154 hpsb_allocate_and_register_addrspace +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xea4152ff dma_region_init +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xecaf01bc hpsb_iso_recv_start +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xefc8fd0e hpsb_read_cycle_timer +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xf2c99a8c hpsb_unregister_protocol +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xf55ca8a5 hpsb_add_host +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xfa679ca6 hpsb_iso_recv_listen_channel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xfba57f51 hpsb_speedto_str +EXPORT_SYMBOL drivers/ieee1394/ohci1394 0x7612eca9 ohci1394_unregister_iso_tasklet +EXPORT_SYMBOL drivers/ieee1394/ohci1394 0xb352a454 ohci1394_register_iso_tasklet +EXPORT_SYMBOL drivers/ieee1394/ohci1394 0xb37ab086 ohci1394_init_iso_tasklet +EXPORT_SYMBOL drivers/ieee1394/ohci1394 0xf95630f4 ohci1394_stop_context +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0x058cb695 rdma_translate_ip +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0x3820958b rdma_copy_addr +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0x71de06c2 rdma_addr_register_client +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0xad0e356b rdma_resolve_ip +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0xbe81bb46 rdma_addr_unregister_client +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0xcf15fa81 rdma_addr_cancel +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x1232f2f4 ib_cm_notify +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x1266594a ib_destroy_cm_id +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x16733e30 ib_send_cm_mra +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x24864690 cm_class +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x2782816a ib_send_cm_req +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x28d20d5f ib_send_cm_lap +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x3524be17 ib_cm_init_qp_attr +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x3f0a5652 ib_send_cm_rej +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x4d0308c2 ib_send_cm_rtu +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x50b5e68b ib_send_cm_rep +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x51a0343f ib_send_cm_drep +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x5577c3c3 ib_send_cm_apr +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x6c89763a ib_send_cm_sidr_rep +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x7b1daa59 ib_send_cm_sidr_req +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x906dadaf ib_cm_listen +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0xbe7efa32 ib_send_cm_dreq +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0xda5fd829 ib_create_cm_id +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x001056b6 ib_create_fmr_pool +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x0abd0439 ib_register_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x0f087eaf ib_unregister_event_handler +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x12d3854f ib_modify_port +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x16609ad5 ib_dealloc_fmr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x1985bedd ib_attach_mcast +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x1c9dafee ib_dereg_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x1e491a04 ib_unmap_fmr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x2b823d78 ib_query_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x2c2c7853 ib_fmr_pool_unmap +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x317c8222 ib_set_client_data +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x327ecbeb ib_query_gid +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x3323a09d ib_destroy_fmr_pool +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x36e31176 ib_get_dma_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x3a1cf218 ib_alloc_fast_reg_page_list +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x3f7567fd ib_rate_to_mult +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x47a1ec7b ib_register_client +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x520b2638 ib_pack +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x55980089 ib_alloc_fmr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x58778179 ib_umem_page_count +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x5af8df3f ib_modify_cq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x5b344fa9 ib_modify_ah +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x5c27f061 ib_create_ah_from_wc +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x5dbb2d1c ib_get_cached_gid +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x5f3a53b6 ib_unregister_client +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x60364d3a ib_alloc_mw +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x65cc3b0d ib_rereg_phys_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x6b37891e ib_query_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x7284d669 ib_query_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x73821bca ib_detach_mcast +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x7479118e ib_query_ah +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x798d6152 ib_query_srq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x7a86034e ib_query_port +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x7b83977d ib_alloc_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x7f1b0d06 ib_destroy_cq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x81ffc46b ib_umem_get +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x82a8e504 ib_query_pkey +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x8640eaeb ib_modify_qp_is_ok +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x87b614d8 ib_ud_header_pack +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x8afe27ce ib_fmr_pool_map_phys +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x8c5a84f9 ib_dispatch_event +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x8f1681d1 ib_alloc_fast_reg_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x90ef4005 ib_get_cached_lmc +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x917969c8 ib_dealloc_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x9401753b ib_create_cq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x96ce6c46 rdma_node_get_transport +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x9701941f ib_create_ah +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x997d3197 ib_unregister_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x9d804fa1 mult_to_ib_rate +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x9ed68464 ib_init_ah_from_wc +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xa0fc8ce7 ib_free_fast_reg_page_list +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xa1096824 ib_alloc_pd +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xa1c2c830 ib_get_cached_pkey +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xa475933b ib_get_client_data +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xa4ab99d6 ib_find_gid +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xae844dd4 ib_destroy_ah +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xaf83a13f ib_dealloc_mw +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xb1a312e1 ib_unpack +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xb4128a48 ib_find_cached_gid +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xba90e495 ib_umem_release +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xc66d588d ib_destroy_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xc98f946d ib_flush_fmr_pool +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xca16dec8 ib_dealloc_pd +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xcbb8134b ib_resize_cq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xce7fd731 ib_find_cached_pkey +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xd064d78b ib_modify_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xd17ba9d1 ib_ud_header_init +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xd4fb2330 ib_create_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xda6fdea1 ib_find_pkey +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xe0dd6ec8 ib_destroy_srq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf36498b9 ib_ud_header_unpack +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xfca5222b ib_create_srq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xfe3c7788 ib_register_event_handler +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xfebbcd73 ib_modify_srq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xfee611d6 ib_reg_phys_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xfef863ff ib_modify_device +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x26b144c5 ib_register_mad_agent +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x4b4601f9 ib_unregister_mad_agent +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x4b941086 ib_free_send_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x4c71a941 ib_create_send_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x58532d87 ib_modify_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x6ef787ed ib_response_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x6f077fcf ib_get_mad_data_offset +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x782474af ib_redirect_mad_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x7b5d4b7a ib_is_mad_class_rmpp +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x80d7baed ib_post_send_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x81c54f40 ib_free_recv_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0xcfd92daa ib_cancel_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0xd3f5bc9d ib_get_rmpp_segment +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0xeb0b6d81 ib_process_mad_wc +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0xec5683de ib_register_mad_snoop +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x05d3e961 ib_sa_cancel_query +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x16199856 ib_sa_register_client +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x512ba124 ib_sa_unregister_client +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x53a60bb9 ib_sa_join_multicast +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x576fdbac ib_sa_free_multicast +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x6c018400 ib_sa_get_mcmember_rec +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0xac45fca2 ib_init_ah_from_path +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0xb50e6c3b ib_init_ah_from_mcmember +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0xcdba81ea ib_sa_service_rec_query +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0xe6fe560b ib_sa_path_rec_get +EXPORT_SYMBOL drivers/infiniband/core/ib_uverbs 0x02f847bc ib_copy_path_rec_from_user +EXPORT_SYMBOL drivers/infiniband/core/ib_uverbs 0x07cf5a51 ib_copy_ah_attr_to_user +EXPORT_SYMBOL drivers/infiniband/core/ib_uverbs 0x18382f6a ib_copy_path_rec_to_user +EXPORT_SYMBOL drivers/infiniband/core/ib_uverbs 0x184f3575 ib_copy_qp_attr_to_user +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x3171bd46 iw_destroy_cm_id +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x462798bb iw_cm_disconnect +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x79d3205e iw_cm_listen +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x8716208f iw_create_cm_id +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0xb7b2df42 iw_cm_accept +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0xe08c1903 iw_cm_init_qp_attr +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0xeeec05a3 iw_cm_connect +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0xfe68fafe iw_cm_reject +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x26a9ccdf rdma_init_qp_attr +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x33e17438 rdma_connect +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x356b6323 rdma_destroy_qp +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x4fadd7ef rdma_leave_multicast +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x90c5ef1c rdma_resolve_route +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xac1e2c0e rdma_listen +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xac495fd8 rdma_resolve_addr +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xb00aedd3 rdma_create_id +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xb4db387b rdma_bind_addr +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xb92c83ff rdma_accept +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xbf517a4c rdma_create_qp +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xc8bcaa6c rdma_join_multicast +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xc9d63acb rdma_reject +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xce35c1a5 rdma_set_ib_paths +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xd56aaa9a rdma_destroy_id +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xe046925e rdma_notify +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xf22eb7bb rdma_disconnect +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xf69aecf9 rdma_set_service_type +EXPORT_SYMBOL drivers/input/gameport/gameport 0x0c9eccb3 __gameport_register_driver +EXPORT_SYMBOL drivers/input/gameport/gameport 0x18053792 __gameport_register_port +EXPORT_SYMBOL drivers/input/gameport/gameport 0x274d3c05 gameport_set_phys +EXPORT_SYMBOL drivers/input/gameport/gameport 0x3b3a23b7 gameport_unregister_driver +EXPORT_SYMBOL drivers/input/gameport/gameport 0x5199dd18 gameport_close +EXPORT_SYMBOL drivers/input/gameport/gameport 0xa60e037a gameport_unregister_port +EXPORT_SYMBOL drivers/input/gameport/gameport 0xbb78e549 gameport_start_polling +EXPORT_SYMBOL drivers/input/gameport/gameport 0xe96508ed gameport_open +EXPORT_SYMBOL drivers/input/gameport/gameport 0xebde354a gameport_stop_polling +EXPORT_SYMBOL drivers/input/input-polldev 0x5cb4df01 input_unregister_polled_device +EXPORT_SYMBOL drivers/input/input-polldev 0x5e955ebd input_free_polled_device +EXPORT_SYMBOL drivers/input/input-polldev 0x85b02d76 input_allocate_polled_device +EXPORT_SYMBOL drivers/input/input-polldev 0xd2030fb3 input_register_polled_device +EXPORT_SYMBOL drivers/isdn/capi/capifs 0x2c54c957 capifs_free_ncci +EXPORT_SYMBOL drivers/isdn/capi/capifs 0xd0bc06ce capifs_new_ncci +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x04403fcf unregister_capi_driver +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x14f2aa5a capi20_get_version +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x17695f41 attach_capi_ctr +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x2b8eab1f capilib_free_ncci +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x2baa6586 capilib_new_ncci +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x31c24aa4 capi20_isinstalled +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x3a63f766 capi20_put_message +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x47d3fc51 capi_info2str +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x50b33ca4 capi_cmsg2message +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x55eeacf9 capi_ctr_suspend_output +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x6057c6f3 capi_message2cmsg +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x62e32d43 capilib_data_b3_conf +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x71e8d5ba capilib_data_b3_req +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x756995e7 capi20_register +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x7a33596c capi20_get_serial +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x7e6f1307 capi20_get_manufacturer +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x80103633 capi_ctr_ready +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x8cc1d275 capi20_set_callback +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x8f699913 capilib_release +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x9bef1b44 capi20_release +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x9cd417d2 capi_ctr_reseted +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x9f823278 register_capi_driver +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xa7c4fd6c capi_message2str +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xaa165d27 capilib_release_appl +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xb19fda8d capi_cmd2str +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xb60e5e5f capi_cmsg_header +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xba5156cb detach_capi_ctr +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xc10fe128 cdebbuf_free +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xcbef7a8b capi_ctr_handle_message +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xdd0f5e91 capi_ctr_resume_output +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xe19a11ac capi20_get_profile +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xe8ad9bd1 capi_cmsg2str +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xed061606 capi20_manufacturer +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x258d4902 b1_parse_version +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x29b6deaa b1_register_appl +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x2e3ca84e b1_free_card +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x3be344b3 avmcard_dma_alloc +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x48630ede b1_release_appl +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x52f84237 avmcard_dma_free +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x53e92c0e b1_loaded +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x63db6978 b1_send_message +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x85f09690 b1_irq_table +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x860a5ad4 b1_load_config +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x96f9d2f4 b1_interrupt +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x977e84c7 b1_load_firmware +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xb7abce06 b1_load_t4file +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xd1672f54 b1_alloc_card +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xdfd28376 b1_detect +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xf02d6d09 b1_reset_ctr +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xf8e779d7 b1_getrevision +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xfd90dcb4 b1ctl_read_proc +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x07cb4cce b1pciv4_detect +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x272b17f5 b1dma_release_appl +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x2a386384 b1dma_interrupt +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x557482a3 b1dma_register_appl +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x577bdab5 b1dma_load_firmware +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x5dd615b0 t1pci_detect +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0xb1dbec1c b1dma_reset +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0xb99714c7 b1dma_reset_ctr +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0xe7dae2fb b1dmactl_read_proc +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0xfa1aae27 b1dma_send_message +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1pcmcia 0x29562993 b1pcmcia_delcard +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1pcmcia 0xaec3240e b1pcmcia_addcard_m1 +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1pcmcia 0xea620116 b1pcmcia_addcard_m2 +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1pcmcia 0xf14bf8b1 b1pcmcia_addcard_b1 +EXPORT_SYMBOL drivers/isdn/hardware/eicon/divadidd 0x011a9f3e proc_net_eicon +EXPORT_SYMBOL drivers/isdn/hardware/eicon/divadidd 0x2974ead1 DIVA_DIDD_Read +EXPORT_SYMBOL drivers/isdn/hardware/mISDN/hfcmulti 0x5293ed86 plx_lock +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x07f4f2ce hisax_unregister +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x148f0c99 FsmFree +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x2844a899 FsmInitTimer +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x2c5d87f7 hisax_init_pcmcia +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x93a64734 FsmChangeState +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x9df0cd27 FsmEvent +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xc0c558f9 FsmRestartTimer +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xd94696e8 FsmDelTimer +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xee93522c hisax_register +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xf0a16657 FsmNew +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xfc27303b HiSax_closecard +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0x3f3b323a isac_d_l2l1 +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0x4d5e304c isac_init +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0x7a066594 isacsx_setup +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0x9adddc28 isacsx_irq +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0xe50d9f71 isac_irq +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0xfeaaec73 isac_setup +EXPORT_SYMBOL drivers/isdn/hisax/isdnhdlc 0x1ee629e2 isdnhdlc_rcv_init +EXPORT_SYMBOL drivers/isdn/hisax/isdnhdlc 0x95aed401 isdnhdlc_decode +EXPORT_SYMBOL drivers/isdn/hisax/isdnhdlc 0x9ffc8215 isdnhdlc_out_init +EXPORT_SYMBOL drivers/isdn/hisax/isdnhdlc 0xf5c8131d isdnhdlc_encode +EXPORT_SYMBOL drivers/isdn/i4l/isdn 0x1fe92838 isdn_ppp_register_compressor +EXPORT_SYMBOL drivers/isdn/i4l/isdn 0xae280aeb isdn_ppp_unregister_compressor +EXPORT_SYMBOL drivers/isdn/i4l/isdn 0xc42a8ea9 register_isdn +EXPORT_SYMBOL drivers/isdn/i4l/isdn 0xfa06820f isdn_register_divert +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x152aa9b4 mISDN_unregister_device +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x1e4a9441 mISDN_initbchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x2348cc3c mISDN_FsmFree +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x2c0a5f06 get_next_dframe +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x39809f65 recv_Dchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x39f17b92 confirm_Bsend +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x3ea336fd mISDN_FsmAddTimer +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x429129f2 mISDN_FsmRestartTimer +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x481a8f36 mISDN_freedchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x50c2230c mISDN_FsmChangeState +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x593303ba mISDN_register_Bprotocol +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x7f5d6e02 l1_event +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x85d736e8 mISDN_freebchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x93bb5147 create_l1 +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x96826fd1 recv_Bchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x9afbcc23 bchannel_senddata +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xaad6a2b9 recv_Bchannel_skb +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xace35cae mISDN_FsmDelTimer +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xcf2508a1 mISDN_unregister_Bprotocol +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xd25604f2 recv_Dchannel_skb +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xd5145151 mISDN_FsmEvent +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xd9a7fbfd mISDN_FsmInitTimer +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xdc0adc29 mISDN_initdchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xdcc9300d queue_ch_frame +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xe1c32d17 mISDN_register_device +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xea9e44a1 dchannel_senddata +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xf28c37d8 get_next_bframe +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xf9e7832f mISDN_FsmNew +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_dsp 0x4c2ec443 mISDN_dsp_element_register +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_dsp 0x60721da7 dsp_audio_law_to_s32 +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_dsp 0xa215f1b2 dsp_audio_s16_to_law +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_dsp 0xd3a023b8 mISDN_dsp_element_unregister +EXPORT_SYMBOL drivers/md/dm-log 0x414626ab dm_dirty_log_type_register +EXPORT_SYMBOL drivers/md/dm-log 0x6a88af38 dm_dirty_log_create +EXPORT_SYMBOL drivers/md/dm-log 0xab4bcaa9 dm_dirty_log_destroy +EXPORT_SYMBOL drivers/md/dm-log 0xb2e4d53b dm_dirty_log_type_unregister +EXPORT_SYMBOL drivers/md/dm-mod 0x00b9fa69 dm_kcopyd_copy +EXPORT_SYMBOL drivers/md/dm-mod 0x1a1d7bed dm_io_client_create +EXPORT_SYMBOL drivers/md/dm-mod 0x206f5c9e dm_table_get_mode +EXPORT_SYMBOL drivers/md/dm-mod 0x385f5ac3 dm_table_event +EXPORT_SYMBOL drivers/md/dm-mod 0x4b57a252 dm_table_unplug_all +EXPORT_SYMBOL drivers/md/dm-mod 0x5abecee5 dm_register_target +EXPORT_SYMBOL drivers/md/dm-mod 0x5f6db3bc dm_unregister_target +EXPORT_SYMBOL drivers/md/dm-mod 0x61b65fe3 dm_kcopyd_client_create +EXPORT_SYMBOL drivers/md/dm-mod 0x673d0edd dm_get_mapinfo +EXPORT_SYMBOL drivers/md/dm-mod 0x82f65633 dm_io_client_resize +EXPORT_SYMBOL drivers/md/dm-mod 0x8c45da29 dm_table_get_md +EXPORT_SYMBOL drivers/md/dm-mod 0x90cc5307 dm_table_get +EXPORT_SYMBOL drivers/md/dm-mod 0x954c8af3 dm_io_client_destroy +EXPORT_SYMBOL drivers/md/dm-mod 0x96050c57 dm_io +EXPORT_SYMBOL drivers/md/dm-mod 0xc79bcd36 dm_vcalloc +EXPORT_SYMBOL drivers/md/dm-mod 0xc7ab328b dm_table_get_size +EXPORT_SYMBOL drivers/md/dm-mod 0xcd7232b9 dm_put_device +EXPORT_SYMBOL drivers/md/dm-mod 0xd89106ba dm_table_put +EXPORT_SYMBOL drivers/md/dm-mod 0xe5cc56f4 dm_kcopyd_client_destroy +EXPORT_SYMBOL drivers/md/dm-mod 0xfd25a54e dm_get_device +EXPORT_SYMBOL drivers/md/md-mod 0x0b58634d md_unregister_thread +EXPORT_SYMBOL drivers/md/md-mod 0x21461e94 bitmap_end_sync +EXPORT_SYMBOL drivers/md/md-mod 0x3ded06fd bitmap_close_sync +EXPORT_SYMBOL drivers/md/md-mod 0x4cecc98c unregister_md_personality +EXPORT_SYMBOL drivers/md/md-mod 0x4ee3c69f md_wait_for_blocked_rdev +EXPORT_SYMBOL drivers/md/md-mod 0x573c27f3 md_check_recovery +EXPORT_SYMBOL drivers/md/md-mod 0x5ca076d7 md_done_sync +EXPORT_SYMBOL drivers/md/md-mod 0x71e7cd94 md_write_start +EXPORT_SYMBOL drivers/md/md-mod 0x793d741a md_register_thread +EXPORT_SYMBOL drivers/md/md-mod 0x8f02776c bitmap_endwrite +EXPORT_SYMBOL drivers/md/md-mod 0xae177c92 bitmap_unplug +EXPORT_SYMBOL drivers/md/md-mod 0xbaa69a53 md_error +EXPORT_SYMBOL drivers/md/md-mod 0xbdf02335 md_wakeup_thread +EXPORT_SYMBOL drivers/md/md-mod 0xcae8f5b4 md_write_end +EXPORT_SYMBOL drivers/md/md-mod 0xd4b9d8f3 bitmap_startwrite +EXPORT_SYMBOL drivers/md/md-mod 0xe4c96a44 bitmap_start_sync +EXPORT_SYMBOL drivers/md/md-mod 0xe6cb2d96 bitmap_cond_end_sync +EXPORT_SYMBOL drivers/md/md-mod 0xff1489a4 register_md_personality +EXPORT_SYMBOL drivers/media/common/tuners/mt2060 0x6e4c9778 mt2060_attach +EXPORT_SYMBOL drivers/media/common/tuners/mt2131 0x9870ca66 mt2131_attach +EXPORT_SYMBOL drivers/media/common/tuners/mt2266 0x3bb1dbaf mt2266_attach +EXPORT_SYMBOL drivers/media/common/tuners/mxl5005s 0x02bc0de8 mxl5005s_attach +EXPORT_SYMBOL drivers/media/common/tuners/qt1010 0x3eb0701c qt1010_attach +EXPORT_SYMBOL drivers/media/common/tuners/tuner-types 0x0cb4b189 tuners +EXPORT_SYMBOL drivers/media/common/tuners/tuner-types 0xc2821775 tuner_count +EXPORT_SYMBOL drivers/media/common/tuners/tuner-xc2028 0xfd05e832 xc2028_attach +EXPORT_SYMBOL drivers/media/common/tuners/xc5000 0xaa5cf637 xc5000_attach +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x00515b23 flexcop_device_kmalloc +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x14e577c2 flexcop_pass_dmx_data +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x18d810c7 flexcop_dma_config_timer +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x40928102 flexcop_dma_free +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x425a543c flexcop_i2c_request +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x5edc4ba6 flexcop_device_exit +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x68f809ad flexcop_wan_set_speed +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x75f45297 flexcop_dma_control_timer_irq +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x80c52491 flexcop_sram_ctrl +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x8573d2c7 flexcop_pass_dmx_packets +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x8e2d1e60 flexcop_eeprom_check_mac_addr +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x98946bc9 flexcop_dma_config +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x99a1dce3 flexcop_dma_control_size_irq +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xa8012f0b flexcop_dump_reg +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xb324da0a flexcop_dma_allocate +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xc6971b47 flexcop_device_kfree +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xde1ac8f1 flexcop_dma_xfer_control +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xe321b34b flexcop_sram_set_dest +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xf298253e flexcop_device_initialize +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0x1b9209ba bt878 +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0x5c8bdc8c bt878_device_control +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0x6de8c87d bt878_stop +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0x78c5891d bt878_start +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0xd5d0bdef bt878_num +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x050dcfa0 dst_pio_disable +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x1175aa1e dst_error_bailout +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x33bcd7eb dst_comm_init +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x59326a40 dst_wait_dst_ready +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x688d60ed write_dst +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x82a9a898 read_dst +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0xb21da0bb rdc_reset_state +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0xcef44853 dst_attach +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0xe94b8c9c dst_check_sum +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0xe9dc7d97 dst_error_recovery +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst_ca 0x5c1afabf dst_ca_attach +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x14eb630c dvb_ringbuffer_free +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x16075bda dvb_net_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x180b1168 dvb_ca_en50221_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x1b8e8b92 dvb_ca_en50221_camready_irq +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x1b8ebdd2 dvb_register_device +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x20756070 dvb_ca_en50221_camchange_irq +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x34926d03 dvb_frontend_reinitialise +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x35c11710 dvb_frontend_detach +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x36c8ea1f dvb_frontend_sleep_until +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x55b0e4be dvb_generic_open +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x5e99c1af dvb_generic_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x6198a006 dvb_generic_ioctl +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x635eb40e dvb_dmx_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x6f7f7d73 dvb_ringbuffer_empty +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x6f9c72e3 dvb_ringbuffer_read +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x717b7ef6 dvb_ca_en50221_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x74a5a698 dvb_filter_pes2ts_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x7aac6d20 dvb_net_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x80e3832d dvb_filter_get_ac3info +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x812e7c2e dvb_register_adapter +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x8b49a23f timeval_usec_diff +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x923aa88e dvb_ringbuffer_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x9cbff999 dvb_dmx_swfilter_204 +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xa8026d57 dvb_unregister_device +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xac4ca1b0 intlog2 +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xb2db2592 dvb_ringbuffer_write +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xb3322de2 dvb_unregister_adapter +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xb56f0404 dvb_dmx_swfilter_packets +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xb5b95805 dvb_ringbuffer_read_user +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xb7ccf30e dvb_dmxdev_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xbed559e1 dvb_dmx_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xc06c138b dvb_ca_en50221_frda_irq +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xc1fde1e0 dvb_unregister_frontend +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xc938e566 dvb_dmx_swfilter +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xe57fd982 dvb_register_frontend +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xe5ae8707 intlog10 +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xe7949e59 dvb_ringbuffer_flush_spinlock_wakeup +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xeb7daf80 dvb_ringbuffer_avail +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xf81a7570 dvb_dmxdev_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xf826deb0 dvb_filter_pes2ts +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x62ad06d1 dvb_usb_get_hexline +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x7f396a79 dvb_usb_device_exit +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x94d1f0f5 usb_cypress_load_firmware +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x95043ede dvb_usb_generic_rw +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0xaec13d35 dvb_usb_generic_write +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0xb2ac550a dvb_usb_device_init +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0xc9d78b87 dvb_usb_nec_rc_key_to_event +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-af9005-remote 0x2edc4728 af9005_rc_keys +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-af9005-remote 0xa1e78971 af9005_rc_decode +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-af9005-remote 0xd3383957 af9005_rc_keys_size +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x0af29944 dibusb_pid_filter_ctrl +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x3dc52a34 dibusb2_0_power_ctrl +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x4997551b dibusb_power_ctrl +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x6d13fc17 dibusb_dib3000mc_frontend_attach +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x97dcc8f1 dibusb2_0_streaming_ctrl +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xb284575d dibusb_pid_filter +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xc37a86c2 dibusb_streaming_ctrl +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xcaad53b5 dibusb_rc_query +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xd4d3dddc dibusb_rc_keys +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xe80f286b dibusb_dib3000mc_tuner_attach +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xf7ad5387 dibusb_read_eeprom_byte +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xffb31684 dibusb_i2c_algo +EXPORT_SYMBOL drivers/media/dvb/frontends/au8522 0x393578c9 au8522_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/bcm3510 0x7dde1a06 bcm3510_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/cx22700 0xaa92177a cx22700_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/cx22702 0x625f391c cx22702_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/cx24110 0x217fb0e7 cx24110_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/cx24123 0x417f1a09 cx24123_get_tuner_i2c_adapter +EXPORT_SYMBOL drivers/media/dvb/frontends/cx24123 0x996ece96 cx24123_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib0070 0xc2b3cf15 dib0070_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib0070 0xfb333904 dib0070_wbd_offset +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mb 0xd80724d8 dib3000mb_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0x25edc277 dib3000mc_pid_parse +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0x630597e8 dib3000mc_pid_control +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0x75640ced dib3000mc_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0xa6ec5295 dib3000mc_set_config +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0xd6e5eb9d dib3000mc_i2c_enumeration +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0xf7a12ab5 dib3000mc_get_tuner_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000m 0x28e307c0 dib7000m_get_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000m 0xe6799a4b dib7000m_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000m 0xecef827d dib7000m_i2c_enumeration +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0x1acb1d14 dib7000p_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0x1d33ef62 dib7000p_set_gpio +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0x2813be67 dib7000pc_detection +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0x2c8f6700 dib7000p_get_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0xc834a905 dib7000p_i2c_enumeration +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0xe881280b dib7000p_set_wbd_ref +EXPORT_SYMBOL drivers/media/dvb/frontends/dibx000_common 0x00563e3e dibx000_get_i2c_adapter +EXPORT_SYMBOL drivers/media/dvb/frontends/dibx000_common 0x02b5306a dibx000_init_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/dibx000_common 0x43e7a927 dibx000_exit_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/drx397xD 0xf7e396aa drx397xD_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dvb-pll 0x5ff29023 dvb_pll_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/isl6405 0xc5dfa8f2 isl6405_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/isl6421 0x525f39af isl6421_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/itd1000 0xcd4a4f26 itd1000_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/l64781 0xf501bb8e l64781_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/lgdt330x 0xb4c60d83 lgdt330x_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/lnbp21 0x1c548c57 lnbp21_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/mt312 0x1c649b4f mt312_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/mt352 0x13a94e04 mt352_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/nxt200x 0x69e84728 nxt200x_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/nxt6000 0x38d305c4 nxt6000_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/or51132 0xb649190a or51132_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/or51211 0x49df5865 or51211_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/s5h1409 0xb60ee129 s5h1409_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/s5h1411 0x58d85b48 s5h1411_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/s5h1420 0x1ce8b50b s5h1420_get_tuner_i2c_adapter +EXPORT_SYMBOL drivers/media/dvb/frontends/s5h1420 0x2cc5ff4c s5h1420_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/sp8870 0x74f29f03 sp8870_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/sp887x 0x97e0ae9f sp887x_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/stv0297 0xecc9d43c stv0297_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/stv0299 0x850e0a86 stv0299_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda10021 0x5f7b7a35 tda10021_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda10023 0xc18af3e4 tda10023_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda10048 0xbb6f2308 tda10048_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda1004x 0x26b2628d tda10046_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda1004x 0x5d429a57 tda10045_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda10086 0x51bb3962 tda10086_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda8083 0x68eee165 tda8083_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda826x 0x8ab76886 tda826x_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tua6100 0xfe70c342 tua6100_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/ves1820 0x48b70962 ves1820_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/ves1x93 0xbda16d23 ves1x93_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/zl10353 0xc04fb4bc zl10353_attach +EXPORT_SYMBOL drivers/media/dvb/ttpci/ttpci-eeprom 0x4c078c76 ttpci_eeprom_parse_mac +EXPORT_SYMBOL drivers/media/dvb/ttusb-dec/ttusbdecfe 0x5d2e6edf ttusbdecfe_dvbt_attach +EXPORT_SYMBOL drivers/media/dvb/ttusb-dec/ttusbdecfe 0x76e96f15 ttusbdecfe_dvbs_attach +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0x11dc4b6d bttv_gpio_enable +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0x63e350c6 bttv_sub_register +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0x89056380 bttv_get_pcidev +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0x8ecf4acc bttv_write_gpio +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0xbcf2d2fb bttv_read_gpio +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0xddc33cef bttv_sub_unregister +EXPORT_SYMBOL drivers/media/video/btcx-risc 0x23d43dfc btcx_riscmem_free +EXPORT_SYMBOL drivers/media/video/btcx-risc 0x495e4b0c btcx_calc_skips +EXPORT_SYMBOL drivers/media/video/btcx-risc 0x7c5624db btcx_riscmem_alloc +EXPORT_SYMBOL drivers/media/video/btcx-risc 0xad2fe38b btcx_sort_clips +EXPORT_SYMBOL drivers/media/video/btcx-risc 0xc368f8e6 btcx_align +EXPORT_SYMBOL drivers/media/video/btcx-risc 0xcda0ded2 btcx_screen_clips +EXPORT_SYMBOL drivers/media/video/cpia 0xa2937094 cpia_unregister_camera +EXPORT_SYMBOL drivers/media/video/cpia 0xafeb8585 cpia_register_camera +EXPORT_SYMBOL drivers/media/video/cx18/cx18 0x2cdea06d cx18_reset_ir_gpio +EXPORT_SYMBOL drivers/media/video/cx2341x 0x0224a947 cx2341x_update +EXPORT_SYMBOL drivers/media/video/cx2341x 0x3559ba71 cx2341x_ext_ctrls +EXPORT_SYMBOL drivers/media/video/cx2341x 0x8fdbede1 cx2341x_fill_defaults +EXPORT_SYMBOL drivers/media/video/cx2341x 0xcf8b77a4 cx2341x_mpeg_ctrls +EXPORT_SYMBOL drivers/media/video/cx2341x 0xde1da524 cx2341x_ctrl_query +EXPORT_SYMBOL drivers/media/video/cx2341x 0xeacc6fab cx2341x_ctrl_get_menu +EXPORT_SYMBOL drivers/media/video/cx2341x 0xfb8bd71f cx2341x_log_status +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0x09f021f5 cx23885_get_control +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0x31fb4117 cx23885_video_mux +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0x936e56a3 cx23885_set_control +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0xe12fa84c cx23885_ctrl_query +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0xf0e1726e cx23885_enum_input +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0xf3b54407 cx23885_set_freq +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0xfb885537 cx23885_user_ctrls +EXPORT_SYMBOL drivers/media/video/cx88/cx88-vp3054-i2c 0x3c5b8d04 vp3054_i2c_remove +EXPORT_SYMBOL drivers/media/video/cx88/cx88-vp3054-i2c 0xbfbb15e7 vp3054_i2c_probe +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0x034f86aa cx88_video_mux +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0x0ca1438c cx88_get_control +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0x0e9597f8 cx88_set_freq +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0x6daceb36 cx8800_ctrl_query +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0xac4e53b9 cx88_user_ctrls +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0xda6a0d58 cx88_set_control +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0xe947b80e cx88_enum_input +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x06ebe159 cx8802_get_device +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x2888d05e cx8802_register_driver +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x3760cfc8 cx8802_cancel_buffers +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x4115a43a cx8802_buf_prepare +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x928ca371 cx8802_unregister_driver +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0xaaac86d6 cx8802_get_driver +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0xc26b503f cx8802_buf_queue +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x021de5f8 cx88_core_put +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x041e725f cx88_risc_buffer +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x081c826d cx88_get_stereo +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x0f14a56d cx88_wakeup +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x13cca53b cx88_call_i2c_clients +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x24c61229 cx88_vdev_init +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x371d2924 cx88_risc_databuffer +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x5c0cf480 cx88_shutdown +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x6821d859 cx88_ir_stop +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x6e517db9 cx88_free_buffer +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x6e88ce78 cx88_set_tvnorm +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x7b5cdee1 cx88_tuner_callback +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x8ba93b0b cx88_core_get +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x8f338031 cx88_set_scale +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x904b8696 cx88_audio_thread +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x95d07e38 cx88_risc_stopper +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x9b140fff cx88_sram_channels +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xb451b893 cx88_newstation +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xb47f6cda cx88_print_irqbits +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xb4e42918 cx88_reset +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xc932f6b5 cx88_set_stereo +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xda825a81 cx88_sram_channel_setup +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xdbd9f3ee cx88_ir_start +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xe4dfc86d cx88_set_tvaudio +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xed4116fc cx88_sram_channel_dump +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xfc0cd569 cx88_core_irq +EXPORT_SYMBOL drivers/media/video/em28xx/em28xx 0x14b17e15 em28xx_unregister_extension +EXPORT_SYMBOL drivers/media/video/em28xx/em28xx 0xc4d7fe5e em28xx_register_extension +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x01eb885d gspca_disconnect +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x3d42f43b gspca_dev_probe +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x3fdfebeb gspca_resume +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x649c4169 gspca_frame_add +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x9670af2c gspca_debug +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x97544231 gspca_auto_gain_n_exposure +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0xec9e2ef8 gspca_suspend +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x0538e449 ivtv_cards_lock +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x06503468 ivtv_udma_prepare +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x14f67530 ivtv_debug +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x1c88ee79 ivtv_set_irq_mask +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x1f879f44 ivtv_udma_setup +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x3d3eba2a ivtv_api +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x420c9d65 ivtv_vapi_result +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x6094f7e4 ivtv_udma_unmap +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x70196ffb ivtv_cards_active +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x7435c5a6 ivtv_clear_irq_mask +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x7fd8cccd ivtv_vapi +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x900be2df ivtv_reset_ir_gpio +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x9a482593 ivtv_udma_alloc +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0xc5421e6b ivtv_cards +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0xe2636326 ivtv_init_on_first_open +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x077ee454 saa7134_ts_register +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x11c94ed6 saa7134_dmasound_init +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x1211df5d saa7134_devlist +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x3c5b6e92 saa7134_ts_unregister +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x6ceb3d2a saa_dsp_writel +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x7036112e saa7134_pgtable_build +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x85593767 saa7134_tuner_callback +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x93582fff saa7134_dmasound_exit +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x98af79c1 saa7134_boards +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0xacd7a73b saa7134_set_dmabits +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0xb607fd7c saa7134_tvaudio_setmute +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0xc0e6199d saa7134_pgtable_alloc +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0xd0cddaa4 saa7134_pgtable_free +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0xd51197b6 saa7134_set_gpio +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0xdf733598 saa7134_i2c_call_clients +EXPORT_SYMBOL drivers/media/video/soc_camera 0x18dbc9db soc_camera_video_stop +EXPORT_SYMBOL drivers/media/video/soc_camera 0x281f8df0 soc_camera_video_start +EXPORT_SYMBOL drivers/media/video/soc_camera 0x31db19ab soc_camera_device_register +EXPORT_SYMBOL drivers/media/video/soc_camera 0x99144bac soc_camera_host_register +EXPORT_SYMBOL drivers/media/video/soc_camera 0xab2580ba soc_camera_device_unregister +EXPORT_SYMBOL drivers/media/video/soc_camera 0xd31ae224 soc_camera_host_unregister +EXPORT_SYMBOL drivers/media/video/tveeprom 0xcfdce564 tveeprom_read +EXPORT_SYMBOL drivers/media/video/tveeprom 0xde8d8cfc tveeprom_hauppauge_analog +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x0d560ac1 usbvideo_RegisterVideoDevice +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x16a2915c RingQueue_Dequeue +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x3e9dfb70 usbvideo_register +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x407a321c RingQueue_WakeUpInterruptible +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x47f899b9 usbvideo_TestPattern +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x99765fa2 usbvideo_Deregister +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0xc5718210 usbvideo_DeinterlaceFrame +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0xddecac6d RingQueue_Enqueue +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0xe9038357 usbvideo_AllocateDevice +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0xf5011f67 RingQueue_Flush +EXPORT_SYMBOL drivers/media/video/v4l1-compat 0x5e540d09 v4l_compat_translate_ioctl +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x03165a85 v4l2_ctrl_get_menu +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x0dfb5e57 v4l2_prio_max +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x1c427ecb v4l2_ctrl_query_fill +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x2de2b633 v4l2_prio_check +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x2e9a955d v4l2_prio_close +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x42c8e001 v4l2_ctrl_next +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x57abfbd8 v4l2_chip_match_host +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x5fef1b4a v4l2_ctrl_query_fill_std +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x6ed58741 v4l2_chip_match_i2c_client +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x921fadba v4l2_i2c_attach +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x942892ab v4l2_prio_open +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xb2d1e17e v4l2_prio_change +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xc369097d v4l2_ctrl_check +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xd464e760 v4l2_ctrl_query_menu +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xe330bce9 v4l2_prio_init +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xe7e3a85c v4l2_chip_ident_i2c_client +EXPORT_SYMBOL drivers/media/video/videobuf-dvb 0x8ea7ac84 videobuf_dvb_register +EXPORT_SYMBOL drivers/media/video/videobuf-dvb 0xeed3379f videobuf_dvb_unregister +EXPORT_SYMBOL drivers/media/video/videocodec 0x02ef66f1 videocodec_register +EXPORT_SYMBOL drivers/media/video/videocodec 0x7eae4aa3 videocodec_attach +EXPORT_SYMBOL drivers/media/video/videocodec 0xc32950f9 videocodec_unregister +EXPORT_SYMBOL drivers/media/video/videocodec 0xe40bb4f6 videocodec_detach +EXPORT_SYMBOL drivers/media/video/videodev 0x123959a1 v4l2_type_names +EXPORT_SYMBOL drivers/media/video/videodev 0x3adbd595 v4l2_field_names +EXPORT_SYMBOL drivers/media/video/videodev 0x5e384916 video_usercopy +EXPORT_SYMBOL drivers/media/video/videodev 0x5ebefe4b v4l_printk_ioctl +EXPORT_SYMBOL drivers/media/video/videodev 0xa0053fe0 video_exclusive_open +EXPORT_SYMBOL drivers/media/video/videodev 0xc1a6c124 video_exclusive_release +EXPORT_SYMBOL drivers/media/video/videodev 0xc6ca96f9 video_device_release +EXPORT_SYMBOL drivers/media/video/videodev 0xd3d4f5ab video_register_device_index +EXPORT_SYMBOL drivers/media/video/videodev 0xd3d630b1 video_register_device +EXPORT_SYMBOL drivers/media/video/videodev 0xd6671fad video_ioctl2 +EXPORT_SYMBOL drivers/media/video/videodev 0xe2b92059 v4l2_video_std_construct +EXPORT_SYMBOL drivers/media/video/videodev 0xed84d68a video_devdata +EXPORT_SYMBOL drivers/media/video/videodev 0xee685916 video_device_alloc +EXPORT_SYMBOL drivers/media/video/videodev 0xf3251e7b v4l2_norm_to_name +EXPORT_SYMBOL drivers/media/video/videodev 0xf9cde6f3 video_unregister_device +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x0a500e2c mpt_findImVolumes +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x19093dd9 mpt_event_register +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x375d8126 mpt_add_sge +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x3ec2755f mpt_resume +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x4526289b mpt_event_deregister +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x524270a9 mpt_raid_phys_disk_pg0 +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x5249018d mpt_put_msg_frame_hi_pri +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x69257b54 mpt_print_ioc_summary +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x6cc5ede3 mpt_put_msg_frame +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x73e7a5ce mpt_detach +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x8d5347ad mpt_free_fw_memory +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x943b3ec5 mpt_HardResetHandler +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x9fbbe02a mpt_reset_register +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xa0b9e456 mpt_device_driver_register +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xa854d688 mpt_send_handshake_request +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xae44039d mpt_attach +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xaffbf8ab mpt_verify_adapter +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xb4c3c6a0 mpt_config +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xbfa476d3 mpt_get_msg_frame +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xc0e69f82 mpt_device_driver_deregister +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xc47c22e8 mpt_deregister +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xd4c9037a mpt_GetIocState +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xd54f4df5 mpt_alloc_fw_memory +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xd785247d mptbase_sas_persist_operation +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xd9a92a75 mpt_reset_deregister +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xdd805159 ioc_list +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xe002a6dc mpt_free_msg_frame +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xe2a6908a mpt_suspend +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xe2a6da97 mpt_register +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x1f768746 mptscsih_event_process +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x2049d337 mptscsih_bus_reset +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x20f36f40 mptscsih_dev_reset +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x2ec2d4cc mptscsih_taskmgmt_complete +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x39fd75f4 mptscsih_host_attrs +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x3d8552a0 mptscsih_abort +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x52af96f2 mptscsih_ioc_reset +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x764ddf1a mptscsih_timer_expired +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x77deb1c1 mptscsih_bios_param +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x7ce3766e mptscsih_scandv_complete +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x82735004 mptscsih_is_phys_disk +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x82abc01b mptscsih_shutdown +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x88f73282 mptscsih_host_reset +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x89724042 mptscsih_slave_destroy +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x8fbb6a81 mptscsih_suspend +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xa4318123 mptscsih_slave_configure +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xa907f0de mptscsih_qcmd +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xb6294a74 mptscsih_proc_info +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xc90a01b6 mptscsih_info +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xcfc9d511 mptscsih_TMHandler +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xd670f79b mptscsih_io_done +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xe06ac97b mptscsih_raid_id_to_num +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xf054010a mptscsih_change_queue_depth +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xf9814b38 mptscsih_remove +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xfe0b4947 mptscsih_resume +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x15bdbff2 i2o_driver_unregister +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x2516a54d i2o_parm_field_get +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x283148b8 i2o_msg_post_wait_mem +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x28bf2af2 i2o_iop_find_device +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x2a843bef i2o_dump_message +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x32f957aa i2o_driver_notify_device_remove_all +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x454118f3 i2o_driver_notify_controller_add_all +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x4ef5ee51 i2o_parm_table_get +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x509b55eb i2o_status_get +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x57d0a532 i2o_msg_get_wait +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x6cca425c i2o_event_register +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x6cdde922 i2o_driver_notify_controller_remove_all +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x78abeba4 i2o_device_claim_release +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x7ee094f6 i2o_device_claim +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x8f093880 i2o_exec_lct_get +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x95180d5c i2o_find_iop +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xb4c00dcf i2o_controllers +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xda43b622 i2o_parm_issue +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xea0581dd i2o_driver_notify_device_add_all +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xf6a1c366 i2o_driver_register +EXPORT_SYMBOL drivers/mfd/htc-pasic3 0x1d4494dd pasic3_read_register +EXPORT_SYMBOL drivers/mfd/htc-pasic3 0x8ea0d333 pasic3_write_register +EXPORT_SYMBOL drivers/misc/ioc4 0x02b0e649 ioc4_register_submodule +EXPORT_SYMBOL drivers/misc/ioc4 0x820bf151 ioc4_unregister_submodule +EXPORT_SYMBOL drivers/misc/sony-laptop 0x5bb1e117 sony_pic_camera_command +EXPORT_SYMBOL drivers/misc/tifm_core 0x09972fb1 tifm_alloc_adapter +EXPORT_SYMBOL drivers/misc/tifm_core 0x3597f915 tifm_map_sg +EXPORT_SYMBOL drivers/misc/tifm_core 0x39f86aa1 tifm_queue_work +EXPORT_SYMBOL drivers/misc/tifm_core 0x3eb3d2d1 tifm_free_device +EXPORT_SYMBOL drivers/misc/tifm_core 0x60bc6851 tifm_alloc_device +EXPORT_SYMBOL drivers/misc/tifm_core 0x64db78b2 tifm_eject +EXPORT_SYMBOL drivers/misc/tifm_core 0x6d8d29f2 tifm_add_adapter +EXPORT_SYMBOL drivers/misc/tifm_core 0x8af78b65 tifm_unregister_driver +EXPORT_SYMBOL drivers/misc/tifm_core 0x98da303e tifm_remove_adapter +EXPORT_SYMBOL drivers/misc/tifm_core 0x9b250cef tifm_has_ms_pif +EXPORT_SYMBOL drivers/misc/tifm_core 0xaf624605 tifm_register_driver +EXPORT_SYMBOL drivers/misc/tifm_core 0xf7c420df tifm_free_adapter +EXPORT_SYMBOL drivers/misc/tifm_core 0xf89af819 tifm_unmap_sg +EXPORT_SYMBOL drivers/mmc/card/mmc_block 0x2ba1767b mmc_cleanup_queue +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x0595bc4b mmc_suspend_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x0a707708 mmc_free_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x2d9801a0 mmc_unregister_driver +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x47ce4d56 mmc_remove_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x52718e48 mmc_request_done +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x68a6abaa mmc_set_data_timeout +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x8e4ec0c6 mmc_wait_for_req +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xb3283f6d mmc_release_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xb9876446 __mmc_claim_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xc6605fad mmc_detect_change +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xcedaad53 mmc_add_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xd27f749b mmc_alloc_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xd9e4990d mmc_wait_for_cmd +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xde11f668 mmc_align_data_size +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xeaa0a952 mmc_wait_for_app_cmd +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xf2300872 mmc_resume_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xfbc3c351 mmc_register_driver +EXPORT_SYMBOL drivers/mtd/chips/cfi_util 0x0c5df24d cfi_fixup +EXPORT_SYMBOL drivers/mtd/chips/cfi_util 0x28402303 cfi_varsize_frob +EXPORT_SYMBOL drivers/mtd/chips/cfi_util 0x89121ef2 cfi_read_pri +EXPORT_SYMBOL drivers/mtd/chips/chipreg 0x02eca375 map_destroy +EXPORT_SYMBOL drivers/mtd/chips/chipreg 0x0d4c6563 do_map_probe +EXPORT_SYMBOL drivers/mtd/chips/chipreg 0x1201f0d0 register_mtd_chip_driver +EXPORT_SYMBOL drivers/mtd/chips/chipreg 0x270fbeaf unregister_mtd_chip_driver +EXPORT_SYMBOL drivers/mtd/chips/gen_probe 0xa41a29ad mtd_do_chip_probe +EXPORT_SYMBOL drivers/mtd/maps/map_funcs 0x636ea062 simple_map_init +EXPORT_SYMBOL drivers/mtd/mtd 0xd1893294 del_mtd_partitions +EXPORT_SYMBOL drivers/mtd/mtd 0xd6914863 add_mtd_partitions +EXPORT_SYMBOL drivers/mtd/mtdconcat 0x0cd0d26f mtd_concat_destroy +EXPORT_SYMBOL drivers/mtd/mtdconcat 0xa6c89438 mtd_concat_create +EXPORT_SYMBOL drivers/mtd/nand/nand 0xa608fba6 nand_scan_bbt +EXPORT_SYMBOL drivers/mtd/nand/nand 0xe78a9f93 nand_default_bbt +EXPORT_SYMBOL drivers/mtd/nand/nand_ecc 0x254f230c nand_calculate_ecc +EXPORT_SYMBOL drivers/mtd/nand/nand_ecc 0x87406d9d nand_correct_data +EXPORT_SYMBOL drivers/mtd/nand/nand_ids 0x836bdb72 nand_flash_ids +EXPORT_SYMBOL drivers/mtd/nand/nand_ids 0xa336feb7 nand_manuf_ids +EXPORT_SYMBOL drivers/mtd/onenand/onenand 0x611b59a2 onenand_scan_bbt +EXPORT_SYMBOL drivers/mtd/onenand/onenand 0xeb4392a2 onenand_default_bbt +EXPORT_SYMBOL drivers/net/8390 0x324804a5 NS8390_init +EXPORT_SYMBOL drivers/net/8390 0x76f733bb __alloc_ei_netdev +EXPORT_SYMBOL drivers/net/8390 0x7d7e0dbc ei_interrupt +EXPORT_SYMBOL drivers/net/8390 0x93a36383 ei_poll +EXPORT_SYMBOL drivers/net/8390 0xa60aaf04 ei_close +EXPORT_SYMBOL drivers/net/8390 0xaa53789f ei_open +EXPORT_SYMBOL drivers/net/8390p 0x42a3c673 eip_poll +EXPORT_SYMBOL drivers/net/8390p 0x6e9647c1 eip_close +EXPORT_SYMBOL drivers/net/8390p 0x841bc69f eip_interrupt +EXPORT_SYMBOL drivers/net/8390p 0x915162b4 NS8390p_init +EXPORT_SYMBOL drivers/net/8390p 0x9f8a6c14 __alloc_eip_netdev +EXPORT_SYMBOL drivers/net/8390p 0xe1ea3dad eip_open +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x0ecc4a3f alloc_arcdev +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x454c8c1c arc_bcast_proto +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x4641bd7d arcnet_interrupt +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x51377537 arc_proto_default +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x6534792a arcnet_debug +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x97772116 arcnet_unregister_proto +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x9be0a7b7 arc_proto_map +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0xc5d53792 arc_raw_proto +EXPORT_SYMBOL drivers/net/arcnet/com20020 0x508efebd com20020_check +EXPORT_SYMBOL drivers/net/arcnet/com20020 0x763bfd14 com20020_found +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x1792727b t3_l2t_send_slow +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x30a20a9a cxgb3_ofld_send +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x3afa8624 t3_l2e_free +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x5b4570d5 cxgb3_free_atid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x5cb7e93a cxgb3_insert_tid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x64e8a7a6 t3_register_cpl_handler +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x6f8eeebc cxgb3_queue_tid_release +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x8e4307ef t3_l2t_send_event +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0xa26f8c30 cxgb3_free_stid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0xb30d02f1 cxgb3_remove_tid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0xbd9f83b6 cxgb3_unregister_client +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0xc456866c cxgb3_alloc_stid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0xd07c2701 dev2t3cdev +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0xd9747c72 cxgb3_alloc_atid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0xe007d772 t3_l2t_get +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0xf708d237 cxgb3_register_client +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0x21b78b6e hdlcdrv_register +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0x912711c9 hdlcdrv_arbitrate +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0xa5f3cb3b hdlcdrv_transmitter +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0xd137f740 hdlcdrv_receiver +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0xfd60b24b hdlcdrv_unregister +EXPORT_SYMBOL drivers/net/irda/sir-dev 0x1ac58fa5 sirdev_raw_read +EXPORT_SYMBOL drivers/net/irda/sir-dev 0x21f230e4 sirdev_set_dtr_rts +EXPORT_SYMBOL drivers/net/irda/sir-dev 0x2e9af2ed sirdev_raw_write +EXPORT_SYMBOL drivers/net/irda/sir-dev 0x76222144 sirdev_set_dongle +EXPORT_SYMBOL drivers/net/irda/sir-dev 0x79067421 irda_register_dongle +EXPORT_SYMBOL drivers/net/irda/sir-dev 0x884b54fd sirdev_write_complete +EXPORT_SYMBOL drivers/net/irda/sir-dev 0x8e6e4088 irda_unregister_dongle +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xa85d4ac9 sirdev_put_instance +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xd9567d8a sirdev_receive +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xda08dd8b sirdev_get_instance +EXPORT_SYMBOL drivers/net/mii 0x130442e2 generic_mii_ioctl +EXPORT_SYMBOL drivers/net/mii 0x16c57bdc mii_link_ok +EXPORT_SYMBOL drivers/net/mii 0x26e23117 mii_check_media +EXPORT_SYMBOL drivers/net/mii 0x82d6078e mii_check_link +EXPORT_SYMBOL drivers/net/mii 0x8a6c4bed mii_nway_restart +EXPORT_SYMBOL drivers/net/mii 0xbb0fac46 mii_ethtool_gset +EXPORT_SYMBOL drivers/net/mii 0xea19d7cc mii_ethtool_sset +EXPORT_SYMBOL drivers/net/mii 0xf9264f87 mii_check_gmii_support +EXPORT_SYMBOL drivers/net/phy/libphy 0x01bc5a06 mdiobus_unregister +EXPORT_SYMBOL drivers/net/phy/libphy 0x02388be2 phy_driver_register +EXPORT_SYMBOL drivers/net/phy/libphy 0x0417061a phy_driver_unregister +EXPORT_SYMBOL drivers/net/phy/libphy 0x07add479 mdiobus_register +EXPORT_SYMBOL drivers/net/phy/libphy 0x0ce47977 genphy_config_advert +EXPORT_SYMBOL drivers/net/phy/libphy 0x113a512f phy_disconnect +EXPORT_SYMBOL drivers/net/phy/libphy 0x1ac5f8f2 phy_print_status +EXPORT_SYMBOL drivers/net/phy/libphy 0x1f61ce8b genphy_read_status +EXPORT_SYMBOL drivers/net/phy/libphy 0x265ae68e phy_start +EXPORT_SYMBOL drivers/net/phy/libphy 0x2e333d91 phy_sanitize_settings +EXPORT_SYMBOL drivers/net/phy/libphy 0x34e341bb phy_start_interrupts +EXPORT_SYMBOL drivers/net/phy/libphy 0x34eeb39f phy_ethtool_sset +EXPORT_SYMBOL drivers/net/phy/libphy 0x5e5179d3 genphy_config_aneg +EXPORT_SYMBOL drivers/net/phy/libphy 0x7044afd1 phy_scan_fixups +EXPORT_SYMBOL drivers/net/phy/libphy 0x720af70d phy_ethtool_gset +EXPORT_SYMBOL drivers/net/phy/libphy 0x7cd5f8fe mdio_bus_type +EXPORT_SYMBOL drivers/net/phy/libphy 0x85feefac phy_connect +EXPORT_SYMBOL drivers/net/phy/libphy 0x88d0c0a4 phy_read +EXPORT_SYMBOL drivers/net/phy/libphy 0x93e71e80 phy_stop +EXPORT_SYMBOL drivers/net/phy/libphy 0x9600a4d5 phy_mii_ioctl +EXPORT_SYMBOL drivers/net/phy/libphy 0xa270da80 phy_register_fixup_for_id +EXPORT_SYMBOL drivers/net/phy/libphy 0xa67bf5ec phy_attach +EXPORT_SYMBOL drivers/net/phy/libphy 0xa9e66b5e genphy_update_link +EXPORT_SYMBOL drivers/net/phy/libphy 0xad685b90 phy_register_fixup_for_uid +EXPORT_SYMBOL drivers/net/phy/libphy 0xb65d80cc phy_start_aneg +EXPORT_SYMBOL drivers/net/phy/libphy 0xbde8e415 phy_enable_interrupts +EXPORT_SYMBOL drivers/net/phy/libphy 0xc788b11c phy_stop_interrupts +EXPORT_SYMBOL drivers/net/phy/libphy 0xc9af6a46 get_phy_id +EXPORT_SYMBOL drivers/net/phy/libphy 0xd59e9207 phy_disable_interrupts +EXPORT_SYMBOL drivers/net/phy/libphy 0xdcf346a0 phy_detach +EXPORT_SYMBOL drivers/net/phy/libphy 0xe2f644de phy_register_fixup +EXPORT_SYMBOL drivers/net/phy/libphy 0xe7849c78 phy_write +EXPORT_SYMBOL drivers/net/phy/libphy 0xec6e836a phy_device_create +EXPORT_SYMBOL drivers/net/phy/mdio-bitbang 0x3a46f4ae free_mdio_bitbang +EXPORT_SYMBOL drivers/net/phy/mdio-bitbang 0xbd5c59a2 alloc_mdio_bitbang +EXPORT_SYMBOL drivers/net/ppp_generic 0x0a596609 ppp_register_compressor +EXPORT_SYMBOL drivers/net/ppp_generic 0x27cfcd40 ppp_unregister_channel +EXPORT_SYMBOL drivers/net/ppp_generic 0x3c5caf5e ppp_register_channel +EXPORT_SYMBOL drivers/net/ppp_generic 0xa8fbd242 ppp_input_error +EXPORT_SYMBOL drivers/net/ppp_generic 0xac2f0c3d ppp_channel_index +EXPORT_SYMBOL drivers/net/ppp_generic 0xb98c564f ppp_unregister_compressor +EXPORT_SYMBOL drivers/net/ppp_generic 0xc96ffc41 ppp_unit_number +EXPORT_SYMBOL drivers/net/ppp_generic 0xe7167959 ppp_output_wakeup +EXPORT_SYMBOL drivers/net/ppp_generic 0xef91a03c ppp_input +EXPORT_SYMBOL drivers/net/pppox 0x64ebc576 pppox_unbind_sock +EXPORT_SYMBOL drivers/net/pppox 0xb94d880e register_pppox_proto +EXPORT_SYMBOL drivers/net/pppox 0xc4825e93 pppox_ioctl +EXPORT_SYMBOL drivers/net/pppox 0xe0ff7a18 unregister_pppox_proto +EXPORT_SYMBOL drivers/net/slhc 0x0ff2b602 slhc_compress +EXPORT_SYMBOL drivers/net/slhc 0x23c8f257 slhc_uncompress +EXPORT_SYMBOL drivers/net/slhc 0xa63d85ab slhc_remember +EXPORT_SYMBOL drivers/net/slhc 0xb5ca1c46 slhc_free +EXPORT_SYMBOL drivers/net/slhc 0xdfc5169b slhc_init +EXPORT_SYMBOL drivers/net/slhc 0xe8794ce1 slhc_toss +EXPORT_SYMBOL drivers/net/sungem_phy 0x18665c3d mii_phy_probe +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0x145d29e8 tms380tr_open +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0x29097d2e tmsdev_init +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0x518fcbfb tms380tr_interrupt +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0xb39d021d tmsdev_term +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0xd2328794 tms380tr_wait +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0xe91a8626 tms380tr_close +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0x38da4725 cycx_intr +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0x62be23ea cycx_setup +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0x66a4c4e6 cycx_down +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0x968458a6 cycx_peek +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0xb6f383de cycx_poke +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0xfe7cd576 cycx_exec +EXPORT_SYMBOL drivers/net/wan/hdlc 0x45812097 alloc_hdlcdev +EXPORT_SYMBOL drivers/net/wan/hdlc 0x6ed38ce4 hdlc_ioctl +EXPORT_SYMBOL drivers/net/wan/hdlc 0x83ee0137 hdlc_close +EXPORT_SYMBOL drivers/net/wan/hdlc 0xa2bf3a9e unregister_hdlc_device +EXPORT_SYMBOL drivers/net/wan/hdlc 0xbac797cd attach_hdlc_protocol +EXPORT_SYMBOL drivers/net/wan/hdlc 0xc2af0528 register_hdlc_protocol +EXPORT_SYMBOL drivers/net/wan/hdlc 0xc6280506 detach_hdlc_protocol +EXPORT_SYMBOL drivers/net/wan/hdlc 0xe2ed7b28 unregister_hdlc_protocol +EXPORT_SYMBOL drivers/net/wan/hdlc 0xffe1210f hdlc_open +EXPORT_SYMBOL drivers/net/wan/syncppp 0x0cd70545 sppp_do_ioctl +EXPORT_SYMBOL drivers/net/wan/syncppp 0x0f314988 sppp_detach +EXPORT_SYMBOL drivers/net/wan/syncppp 0x1c0c2fc6 sppp_reopen +EXPORT_SYMBOL drivers/net/wan/syncppp 0x6c1f8663 sppp_close +EXPORT_SYMBOL drivers/net/wan/syncppp 0x6e67b7d4 sppp_attach +EXPORT_SYMBOL drivers/net/wan/syncppp 0x746db4ba sppp_open +EXPORT_SYMBOL drivers/net/wan/z85230 0x0e5ab9ef z8530_queue_xmit +EXPORT_SYMBOL drivers/net/wan/z85230 0x10c78988 z8530_dead_port +EXPORT_SYMBOL drivers/net/wan/z85230 0x1b3d3bb6 z8530_sync_txdma_open +EXPORT_SYMBOL drivers/net/wan/z85230 0x1cd64da9 z8530_sync_open +EXPORT_SYMBOL drivers/net/wan/z85230 0x283e799e z8530_interrupt +EXPORT_SYMBOL drivers/net/wan/z85230 0x325894d4 z8530_dma_sync +EXPORT_SYMBOL drivers/net/wan/z85230 0x383bdfab z8530_txdma_sync +EXPORT_SYMBOL drivers/net/wan/z85230 0x3c00d4f5 z8530_sync_dma_open +EXPORT_SYMBOL drivers/net/wan/z85230 0x3e489cd7 z8530_describe +EXPORT_SYMBOL drivers/net/wan/z85230 0x52029564 z8530_sync +EXPORT_SYMBOL drivers/net/wan/z85230 0x59f2292e z8530_sync_txdma_close +EXPORT_SYMBOL drivers/net/wan/z85230 0x5bec890c z8530_null_rx +EXPORT_SYMBOL drivers/net/wan/z85230 0x5cd24d29 z8530_hdlc_kilostream +EXPORT_SYMBOL drivers/net/wan/z85230 0x94291a53 z8530_init +EXPORT_SYMBOL drivers/net/wan/z85230 0xb60004eb z8530_sync_dma_close +EXPORT_SYMBOL drivers/net/wan/z85230 0xd4fdcfad z8530_sync_close +EXPORT_SYMBOL drivers/net/wan/z85230 0xdcff4aee z8530_shutdown +EXPORT_SYMBOL drivers/net/wan/z85230 0xe3d80064 z8530_hdlc_kilostream_85230 +EXPORT_SYMBOL drivers/net/wan/z85230 0xe4515dc0 z8530_nop +EXPORT_SYMBOL drivers/net/wan/z85230 0xe62fe463 z8530_channel_load +EXPORT_SYMBOL drivers/net/wireless/airo 0x35b3c5f2 stop_airo_card +EXPORT_SYMBOL drivers/net/wireless/airo 0x436c574c init_airo_card +EXPORT_SYMBOL drivers/net/wireless/airo 0x73f7b8f8 reset_airo_card +EXPORT_SYMBOL drivers/net/wireless/atmel 0xc2ac4183 init_atmel_card +EXPORT_SYMBOL drivers/net/wireless/atmel 0xc6899620 stop_atmel_card +EXPORT_SYMBOL drivers/net/wireless/atmel 0xe73b17d1 atmel_open +EXPORT_SYMBOL drivers/net/wireless/hermes 0x4196c38b hermes_write_ltv +EXPORT_SYMBOL drivers/net/wireless/hermes 0xc60b5e9e hermes_bap_pwrite +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd38d8ae2 hermes_read_ltv +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd3f714e5 hermes_bap_pread +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd5168829 hermes_allocate +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd5336e5d hermes_init +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd54e219d hermes_docmd_wait +EXPORT_SYMBOL drivers/net/wireless/hermes 0xed47b224 hermes_struct_init +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x08c8f3f9 hostap_set_word +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x09a262b6 hostap_80211_ops +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x0ad69602 hostap_set_multicast_list_queue +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x0b1ba1e1 prism2_update_comms_qual +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x0f4b4ed9 hostap_handle_sta_tx_exc +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x1f0238f2 hostap_free_data +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x2a0bd49d hostap_remove_proc +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x331dbef5 hostap_init_ap_proc +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x3c2828db hostap_get_stats +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x5c8bbdd5 hostap_init_proc +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x649867ca hostap_set_hostapd_sta +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x6903f16c hostap_80211_get_hdrlen +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x6bd3c931 hostap_set_encryption +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x71e7ff3e hostap_set_antsel +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x72c933c9 hostap_add_interface +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x85f8628d hostap_setup_dev +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x86a10d0c hostap_set_roaming +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x8a959059 hostap_remove_interface +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x8ec810b4 hostap_80211_rx +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x9b4c564d hostap_set_auth_algs +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xa12ad27f hostap_dump_tx_header +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xa66edb3f hostap_get_porttype +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xb2a945e0 hostap_dump_rx_header +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xb5365ffa hostap_check_sta_fw_version +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xce05fb32 hostap_master_start_xmit +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xd1516edc hostap_info_process +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xf5061c29 hostap_info_init +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xf7072f47 hostap_set_string +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xf9d205ab hostap_init_data +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xfecb944f hostap_set_hostapd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x0293193f iwl_send_cmd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x04520f5d iwl_alloc_all +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x0753119e iwl_power_initialize +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x075808c5 iwl_dump_nic_error_log +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x0806cc78 iwl_setup_power_deferred_work +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x08b42118 iwl_txq_update_write_ptr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x0adc7812 iwl_rx_agg_stop +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x0beaf31a iwl_txq_ctx_stop +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x0d207cc2 iwlcore_eeprom_query_addr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x10137c60 iwl_rx_queue_space +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x1046e835 iwl_reset_run_time_calib +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x10e7346f iwl_rx_queue_restock +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x131927f2 iwl_leds_register +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x19205511 iwl_rx_reply_compressed_ba +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x19c694a0 iwl_setup_scan_deferred_work +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x1a345c70 iwl_tx_queue_reclaim +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x1adcff1c iwl_init_drv +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x1bba4252 iwl_rfkill_set_hw_state +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x1d77b399 iwl_bcast_addr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x2378d0ac iwl_init_sensitivity +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x27223309 iwl_eeprom_init +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x28e5d3f0 iwl_get_ra_sta_id +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x2ae0f4fa iwl_power_cancel_timeout +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x2b84bf31 iwl_send_cmd_pdu +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x307f7085 iwl_send_static_wepkey_cmd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x383dbe5a iwl_rx_queue_update_write_ptr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x3dc6c713 iwl_set_dynamic_key +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x40c2bcec iwl_uninit_drv +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x4292ebd7 iwl_rx_replenish +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x45d6952d iwl_scan_initiate +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x487b32bd iwl_hw_detect +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x52b09c09 iwl_power_update_mode +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x52fbcd45 iwl_get_sta_id +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x54457ad6 iwlcore_eeprom_release_semaphore +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x55cdbc6d iwl_chain_noise_calibration +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x57a6534c iwl_rf_kill_ct_config +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x585eec48 iwl_scan_cancel +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x58c00a70 iwlcore_eeprom_verify_signature +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x59f83236 iwl_reset_qos +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5c5c3a9b iwl_rx_reply_rx_phy +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5cd833ce iwl_eeprom_query_addr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5faa2fee iwl_set_tx_power +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x61f07490 iwl_tx_cmd_complete +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x62727d56 iwl_calib_set +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x63e8f319 iwl_init_channel_map +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x647569ef iwl_set_rxon_chain +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x6655a402 iwl_tx_skb +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x6872ec0e iwl_send_statistics_request +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x694e0a77 iwl_rx_queue_alloc +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x6f61b042 iwl_send_lq_cmd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x6fc2944a iwl_rx_agg_start +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x728ce8d2 iwl_verify_ucode +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x766dbde5 iwl_setup_mac +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x7843a8ed iwl_is_fat_tx_allowed +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x7c143b35 iwl_radio_kill_sw_disable_radio +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x7c7b8a8e iwl_leds_unregister +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x7eff5a9b iwl_remove_default_wep_key +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x7fe286bb iwl_hw_txq_attach_buf_to_tfd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x818007bd iwl_set_rxon_ht +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x83b7b372 iwl_dump_nic_event_log +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x8670273d iwl_hwrate_to_plcp_idx +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x867ed7cd iwl_leds_background +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x87f69afb iwl_power_set_system_mode +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x88abcdb4 iwl_rxon_add_station +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x899fa631 iwl_rx_reply_rx +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x8bc9c0cb iwl_rxq_stop +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x948756ce iwl_power_disable_management +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x97702d3b iwl_set_rxon_channel +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x9777b0db iwl_find_station +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x9b66eb9a iwl_send_calib_results +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x9cde1f24 iwl_queue_space +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xa3cd1c0d iwl_hwrate_to_tx_control +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xa76e513e iwl_remove_station +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xa80e90db iwl_rx_missed_beacon_notif +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xa97a9296 iwl_eeprom_get_mac +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xabb59f1b iwl_power_set_user_mode +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xafb92a90 iwl_send_cmd_pdu_async +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xb38a1e41 iwl_escape_essid +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xba272d4f iwl_hw_txq_free_tfd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xbc2e0fea iwl_get_channel_info +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc1f2ad10 iwl_setup_rx_scan_handlers +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc5075fda iwl_print_event_log +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc9f3d6ed iwl_clear_stations_table +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xca681805 iwl_txq_check_empty +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xcac11d23 iwlcore_eeprom_acquire_semaphore +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xcbaf4931 get_cmd_string +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xcc234b0f iwl_power_enable_management +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xccaa33fc iwl_tx_agg_start +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xd14d7a2c iwl_send_add_sta +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xd49ec3a3 iwl_eeprom_check_version +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xd4f09e48 iwl_hw_txq_ctx_free +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xd5003b77 iwl_power_temperature_change +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xdaaf6e8c iwl_rx_queue_reset +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xdc0e612a iwl_tx_agg_stop +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xdda916f8 iwl_rx_statistics +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xdfd81177 iwl_send_cmd_sync +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xe0bbedf1 iwl_eeprom_free +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xe11d8ce9 iwl_set_hw_params +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xe3614a52 iwl_eeprom_query16 +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xe4ed2f9c iwl_sta_modify_enable_tid_tx +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xe7ce5d70 iwl_rates +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xe9dc34f3 iwl_rfkill_unregister +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xeb23b3b6 iwl_scan_cancel_timeout +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xebe4f603 iwl_rfkill_init +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xec819e6d iwl_sensitivity_calibration +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xefcc7362 iwl_set_default_wep_key +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf13d996e iwl_add_station_flags +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf1506e39 iwl_hw_nic_init +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf5ea06e1 iwl_rx_queue_free +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf936be82 iwl_remove_dynamic_key +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xfc49d21b iwl_radio_kill_sw_enable_radio +EXPORT_SYMBOL drivers/net/wireless/orinoco 0x1a9d334a orinoco_interrupt +EXPORT_SYMBOL drivers/net/wireless/orinoco 0x3a9ea365 alloc_orinocodev +EXPORT_SYMBOL drivers/net/wireless/orinoco 0x47fc1f03 __orinoco_up +EXPORT_SYMBOL drivers/net/wireless/orinoco 0x8b8f6a2d free_orinocodev +EXPORT_SYMBOL drivers/net/wireless/orinoco 0xafd473f9 __orinoco_down +EXPORT_SYMBOL drivers/net/wireless/orinoco 0xf76ddebb orinoco_reinit_firmware +EXPORT_SYMBOL drivers/parport/parport 0x095b6fb5 parport_ieee1284_epp_write_addr +EXPORT_SYMBOL drivers/parport/parport 0x1dbe8d84 parport_irq_handler +EXPORT_SYMBOL drivers/parport/parport 0x23c43bf8 parport_ieee1284_epp_write_data +EXPORT_SYMBOL drivers/parport/parport 0x292457ed parport_claim_or_block +EXPORT_SYMBOL drivers/parport/parport 0x31d1bce6 parport_negotiate +EXPORT_SYMBOL drivers/parport/parport 0x4bf15dd0 parport_get_port +EXPORT_SYMBOL drivers/parport/parport 0x4d2a941b parport_ieee1284_interrupt +EXPORT_SYMBOL drivers/parport/parport 0x5991cbfd parport_unregister_driver +EXPORT_SYMBOL drivers/parport/parport 0x5de462fe parport_set_timeout +EXPORT_SYMBOL drivers/parport/parport 0x5e3ca2a4 parport_find_base +EXPORT_SYMBOL drivers/parport/parport 0x6045c53b parport_ieee1284_read_byte +EXPORT_SYMBOL drivers/parport/parport 0x639e45c9 parport_ieee1284_write_compat +EXPORT_SYMBOL drivers/parport/parport 0x6de54013 parport_ieee1284_epp_read_addr +EXPORT_SYMBOL drivers/parport/parport 0x728fdcca parport_put_port +EXPORT_SYMBOL drivers/parport/parport 0x79d3f465 parport_ieee1284_ecp_read_data +EXPORT_SYMBOL drivers/parport/parport 0x87d627fe parport_register_driver +EXPORT_SYMBOL drivers/parport/parport 0x8953a1e6 parport_wait_peripheral +EXPORT_SYMBOL drivers/parport/parport 0x89c812e4 parport_release +EXPORT_SYMBOL drivers/parport/parport 0x8a2a6483 parport_claim +EXPORT_SYMBOL drivers/parport/parport 0x98d6a445 parport_ieee1284_read_nibble +EXPORT_SYMBOL drivers/parport/parport 0xa2c08e83 parport_find_number +EXPORT_SYMBOL drivers/parport/parport 0xbda10d21 parport_write +EXPORT_SYMBOL drivers/parport/parport 0xc2e7ef4f parport_announce_port +EXPORT_SYMBOL drivers/parport/parport 0xcc3b326e parport_ieee1284_epp_read_data +EXPORT_SYMBOL drivers/parport/parport 0xd47aa01d parport_ieee1284_ecp_write_data +EXPORT_SYMBOL drivers/parport/parport 0xd8c975bd parport_read +EXPORT_SYMBOL drivers/parport/parport 0xdb606f42 parport_register_device +EXPORT_SYMBOL drivers/parport/parport 0xe1fe6f82 parport_unregister_device +EXPORT_SYMBOL drivers/parport/parport 0xe85732d6 parport_wait_event +EXPORT_SYMBOL drivers/parport/parport 0xe8838265 parport_register_port +EXPORT_SYMBOL drivers/parport/parport 0xfbb15137 parport_remove_port +EXPORT_SYMBOL drivers/parport/parport 0xfee5f450 parport_ieee1284_ecp_write_addr +EXPORT_SYMBOL drivers/parport/parport_pc 0x131616bb parport_pc_probe_port +EXPORT_SYMBOL drivers/parport/parport_pc 0xc0e78b30 parport_pc_unregister_port +EXPORT_SYMBOL drivers/pci/hotplug/pci_hotplug 0x6418b4ba acpi_get_hp_hw_control_from_firmware +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x42be2dbf pcmcia_get_mem_page +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x47663d7a pcmcia_request_window +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x52992213 pcmcia_register_driver +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x571c8305 pcmcia_request_configuration +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x629788c7 pcmcia_map_mem_page +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x69207fe0 pcmcia_request_irq +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x6ced3e02 pcmcia_unregister_driver +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x7609f333 pcmcia_get_window +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x8df0acf6 pcmcia_get_configuration_info +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x9a8e575b pcmcia_request_io +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xa3235cec pcmcia_access_configuration_register +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xd42b7ab5 pcmcia_dev_present +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xd55f9c8a pcmcia_modify_configuration +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xdb258037 pcmcia_release_window +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xe5315bb5 cs_error +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xe898fd14 pcmcia_disable_device +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x012f115b pcmcia_validate_mem +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x037d2f16 pcmcia_put_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x092f09e3 pccard_get_next_tuple +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x0ea7b2f8 pccard_static_ops +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x12f39ff3 pccard_validate_cis +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x14825402 pcmcia_read_cis_mem +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x212db8d2 pcmcia_socket_list +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x2cf709c4 pcmcia_socket_dev_suspend +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x2e4f6970 destroy_cis_cache +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x381575a1 pcmcia_write_cis_mem +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x391fbcfd pcmcia_replace_cis +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x49c28ebb pccard_get_tuple_data +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x49cc92d4 pcmcia_adjust_io_region +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x53f62ea9 pccard_register_pcmcia +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x62ce4513 pcmcia_find_mem_region +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x6ca2a98b pcmcia_find_io_region +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x768ac651 pccard_read_tuple +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x8841e570 pccard_reset_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x8fa42e62 pcmcia_socket_dev_resume +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x93042a73 release_cis_mem +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x941ce3cf pcmcia_socket_class +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x95e9fe78 pcmcia_parse_events +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xa6c8a2e9 pcmcia_get_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xc3200347 pcmcia_register_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xc368f687 pcmcia_socket_list_rwsem +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xcb6e31f7 pcmcia_insert_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xcd2ac1c1 pccard_parse_tuple +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xcf97f3bd dead_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xd68aaa9c pcmcia_eject_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xdbebeaa3 pcmcia_suspend_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xf8dd39c5 pcmcia_get_socket_by_nr +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xf92e878d pcmcia_resume_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xfd541f56 pcmcia_unregister_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xfe30f721 pccard_get_first_tuple +EXPORT_SYMBOL drivers/pcmcia/rsrc_nonstatic 0x111d2fab pccard_nonstatic_ops +EXPORT_SYMBOL drivers/scsi/53c700 0x3b1596c3 NCR_700_release +EXPORT_SYMBOL drivers/scsi/53c700 0x5175c0f0 NCR_700_intr +EXPORT_SYMBOL drivers/scsi/53c700 0xcd03b054 NCR_700_detect +EXPORT_SYMBOL drivers/scsi/megaraid/megaraid_mm 0x2250c66e mraid_mm_adapter_app_handle +EXPORT_SYMBOL drivers/scsi/megaraid/megaraid_mm 0x512c956d mraid_mm_unregister_adp +EXPORT_SYMBOL drivers/scsi/megaraid/megaraid_mm 0x608e54df mraid_mm_register_adp +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x072b4e1d qlogicfas408_bus_reset +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x09c6554e qlogicfas408_abort +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x10eb3ce3 qlogicfas408_info +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x3fd8cd71 qlogicfas408_detect +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x5964bc26 qlogicfas408_queuecommand +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x5cd179e6 qlogicfas408_ihandl +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0xbb2bed2a qlogicfas408_biosparam +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0xd9a60bdc qlogicfas408_disable_ints +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0xe76b3b20 qlogicfas408_get_chip_type +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0xf2b95199 qlogicfas408_setup +EXPORT_SYMBOL drivers/scsi/raid_class 0x0d4ba2cd raid_component_add +EXPORT_SYMBOL drivers/scsi/raid_class 0x6ad41989 raid_class_attach +EXPORT_SYMBOL drivers/scsi/raid_class 0xff5ad300 raid_class_release +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x025bc11c scsi_cmd_print_sense_hdr +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x036eac43 scsi_is_target_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x0451d1bc scsi_put_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x0c65e73c scsi_normalize_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x0c8c9e99 scsi_show_extd_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x0d2e438b scsi_scan_target +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x11267875 scsi_extd_sense_format +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x11588f7c scsicam_bios_param +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x12a41b01 scsi_print_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x13cced00 scsi_report_device_reset +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x147ccb58 scsi_dma_unmap +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1812ee62 __scsi_add_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x19ff424a scsi_register_interface +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1b9e0ff1 scsilun_to_int +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1c03e4cf scsi_command_normalize_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x21bad8c4 scsi_release_buffers +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x21c744cc scsi_block_requests +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2299d7d8 scsi_reset_provider +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x22dee56c scsi_host_put +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x23df8959 scsi_is_host_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x28a2ed02 scsi_build_sense_buffer +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x29018534 scsi_unblock_requests +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2a33b6b3 scsi_device_get +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2a902c72 scsi_req_abort_cmd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2b0ba2b0 scsi_sense_desc_find +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2d89342a scsi_show_sense_hdr +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2daad689 scsi_device_lookup +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x300346fa scsi_bios_ptable +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x309ddc0f scsi_allocate_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x3243731b scsi_get_host_dev +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x34fc5d97 scsi_mode_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x3b1856ab scsi_execute +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x3b74910f scsi_is_sdev_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x3db19f88 scsi_nonblockable_ioctl +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x40fa263e __scsi_put_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x432e0cc0 scsi_register_driver +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x435cee74 scsi_init_io +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x4563deaa scsi_host_set_state +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x45f4c935 scsi_host_get +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x493006db scsi_free_host_dev +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x4afe9a77 scsi_partsize +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x4e113139 scsi_print_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x4f7d46a3 scsi_device_resume +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x52be7da5 scsi_scan_host +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x53661301 scsi_rescan_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x53cc1b79 scsi_register +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x55bb2e47 scsi_track_queue_full +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x56c8799d scsi_kunmap_atomic_sg +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x58975988 scsi_device_lookup_by_target +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x589e353a scsi_host_alloc +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x5a40c0d0 scsi_ioctl +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x66baf8b6 scsi_finish_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x69d38ed9 __scsi_print_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x6d1ed6f5 __scsi_alloc_queue +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x6dd8560a scsi_setup_blk_pc_cmnd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x6e31f04d scsi_free_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x7156569b __starget_for_each_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x72ea7b2d scsi_device_type +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x795d5ac1 scsi_print_result +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x796fc5ce scsi_get_sense_info_fld +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x7d44ffab scsi_host_lookup +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x7f1e3268 starget_for_each_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x8092b42e scsi_execute_req +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x8875c484 scsi_get_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x8bfcf6f6 scsi_block_when_processing_errors +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x90b45355 scsi_remove_host +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x96cd2b04 scsi_sense_key_string +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x9cfd56c5 scsi_print_status +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x9e4afb33 scsi_setup_fs_cmnd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x9e672ff6 scsi_kmap_atomic_sg +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x9f9345a6 scsi_remove_target +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xa24adee5 scsi_eh_prep_cmnd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xad526960 scsi_test_unit_ready +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xae611171 scsi_target_resume +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xaf3dd7dc scsi_logging_level +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xb14a2a53 scsi_set_medium_removal +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xb1cbae4a scsi_unregister +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xb1fefc27 scsi_prep_state_check +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xb6c5a973 scsi_show_result +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xc3c46da6 scsi_add_host +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xc41a70ac scsi_eh_restore_cmnd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xca5dbc50 scsi_print_sense_hdr +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xcedd0ff8 scsi_adjust_queue_depth +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xd14a2357 scsi_calculate_bounce_limit +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xd944fdec __scsi_device_lookup_by_target +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xdc28dfba scsi_add_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xea10212a int_to_scsilun +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xea578411 scsi_prep_return +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xeb94307c scsi_device_set_state +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xec875ff6 scsi_remove_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xec998722 __scsi_iterate_devices +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xed7d2216 scsi_eh_finish_cmd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf008d7f1 scsi_report_bus_reset +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf16a9d62 scsi_device_put +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf2aa070f scsi_dma_map +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf807d856 scsi_device_quiesce +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf811e69d scsi_eh_flush_done_q +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf83ffc25 scsi_target_quiesce +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xfd809e08 __scsi_device_lookup +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xfef96e23 __scsi_print_command +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x047df979 fc_vport_terminate +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x089b81c6 fc_remote_port_rolechg +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x1ce31695 scsi_is_fc_rport +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x40233a43 fc_host_post_event +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x4e0ca009 fc_remote_port_add +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x7954b1ea fc_get_event_number +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x9bab2ccc fc_remote_port_delete +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0xaede5262 fc_remove_host +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0xc092c1c5 fc_release_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0xd80fedfd fc_attach_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0xfc1d8a30 fc_host_post_vendor_event +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0xfcbd33f5 scsi_is_fc_vport +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x06fbeae3 sas_read_port_mode_page +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x0bbedd51 sas_phy_free +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x195db787 sas_remove_children +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x1d5fa61c sas_port_alloc_num +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x26c14f70 sas_port_delete +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x26d212c8 sas_rphy_remove +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x285cd9e1 scsi_is_sas_phy +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x375c3034 sas_port_delete_phy +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x451fa52b scsi_is_sas_rphy +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x53dbe71d sas_attach_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x631d66cb sas_rphy_delete +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x8025b8a1 sas_phy_alloc +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x8130090c sas_port_add +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x8956d19c sas_expander_alloc +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x9042f50b sas_rphy_free +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x90554214 sas_end_device_alloc +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x9087111b sas_phy_delete +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x952e6cad sas_release_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x9f57662c sas_port_mark_backlink +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xa722a258 sas_remove_host +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xac70a36a sas_rphy_add +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xc502ec3e sas_port_alloc +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xd42d0331 sas_port_free +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xe3cdfa2a scsi_is_sas_port +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xe8622072 sas_phy_add +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xefe06dac sas_port_add_phy +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0x11268c12 spi_display_xfer_agreement +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0x30a4fe44 spi_dv_device +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0x3686ea09 spi_print_msg +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0x726b95cf spi_schedule_dv_device +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0x88f75c29 spi_release_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0xad853fee spi_attach_transport +EXPORT_SYMBOL drivers/ssb/ssb 0x0269f1d9 ssb_pcicore_dev_irqvecs_enable +EXPORT_SYMBOL drivers/ssb/ssb 0x03f57183 ssb_device_enable +EXPORT_SYMBOL drivers/ssb/ssb 0x17390daf ssb_bus_powerup +EXPORT_SYMBOL drivers/ssb/ssb 0x25917ecf __ssb_driver_register +EXPORT_SYMBOL drivers/ssb/ssb 0x320eea35 ssb_clockspeed +EXPORT_SYMBOL drivers/ssb/ssb 0x449229aa ssb_bus_suspend +EXPORT_SYMBOL drivers/ssb/ssb 0x68ef4669 ssb_device_disable +EXPORT_SYMBOL drivers/ssb/ssb 0x72927a58 ssb_bus_pcibus_register +EXPORT_SYMBOL drivers/ssb/ssb 0x745ddd65 ssb_bus_may_powerdown +EXPORT_SYMBOL drivers/ssb/ssb 0x7c8fae59 ssb_device_is_enabled +EXPORT_SYMBOL drivers/ssb/ssb 0x94149f0b ssb_driver_unregister +EXPORT_SYMBOL drivers/ssb/ssb 0x9ec6b7d1 ssb_bus_unregister +EXPORT_SYMBOL drivers/ssb/ssb 0xa0ecec55 ssb_dma_alloc_consistent +EXPORT_SYMBOL drivers/ssb/ssb 0xbeb5a772 ssb_dma_set_mask +EXPORT_SYMBOL drivers/ssb/ssb 0xc0512e0f ssb_admatch_base +EXPORT_SYMBOL drivers/ssb/ssb 0xce80705f ssb_dma_free_consistent +EXPORT_SYMBOL drivers/ssb/ssb 0xd0f8c77b ssb_set_devtypedata +EXPORT_SYMBOL drivers/ssb/ssb 0xd390966e ssb_dma_translation +EXPORT_SYMBOL drivers/ssb/ssb 0xd481192b ssb_admatch_size +EXPORT_SYMBOL drivers/ssb/ssb 0xf25d7be4 ssb_bus_resume +EXPORT_SYMBOL drivers/ssb/ssb 0xfc8f4d18 ssb_pcihost_register +EXPORT_SYMBOL drivers/telephony/ixj 0xd151644d ixj_pcmcia_probe +EXPORT_SYMBOL drivers/telephony/phonedev 0x3daa3f26 phone_register_device +EXPORT_SYMBOL drivers/telephony/phonedev 0x929f22f3 phone_unregister_device +EXPORT_SYMBOL drivers/usb/gadget/net2280 0xa6037a68 usb_gadget_register_driver +EXPORT_SYMBOL drivers/usb/gadget/net2280 0xb340da0c net2280_set_fifo_mode +EXPORT_SYMBOL drivers/usb/gadget/net2280 0xf4ae23b7 usb_gadget_unregister_driver +EXPORT_SYMBOL drivers/usb/host/sl811-hcd 0xf20db367 sl811h_driver +EXPORT_SYMBOL drivers/usb/serial/usbserial 0x6caaaf65 usb_serial_suspend +EXPORT_SYMBOL drivers/usb/serial/usbserial 0xe2570413 usb_serial_resume +EXPORT_SYMBOL drivers/video/backlight/corgi_bl 0xc86baa7c corgibl_limit_intensity +EXPORT_SYMBOL drivers/video/backlight/lcd 0x7abde1fa lcd_device_register +EXPORT_SYMBOL drivers/video/backlight/lcd 0x920d45fc lcd_device_unregister +EXPORT_SYMBOL drivers/video/console/bitblit 0x12f85f92 fbcon_set_bitops +EXPORT_SYMBOL drivers/video/console/font 0x09c8eb55 font_vga_8x16 +EXPORT_SYMBOL drivers/video/console/font 0xbb99125c get_default_font +EXPORT_SYMBOL drivers/video/console/font 0xf7584a9c find_font +EXPORT_SYMBOL drivers/video/console/softcursor 0x71d31eaa soft_cursor +EXPORT_SYMBOL drivers/video/console/tileblit 0x5bf42db7 fbcon_set_tileops +EXPORT_SYMBOL drivers/video/cyber2000fb 0x0cc3ede5 cyber2000fb_detach +EXPORT_SYMBOL drivers/video/cyber2000fb 0x3bb5a607 cyber2000fb_get_fb_var +EXPORT_SYMBOL drivers/video/cyber2000fb 0x4078d274 cyber2000fb_disable_extregs +EXPORT_SYMBOL drivers/video/cyber2000fb 0xc04ca68e cyber2000fb_enable_extregs +EXPORT_SYMBOL drivers/video/cyber2000fb 0xf018e80f cyber2000fb_attach +EXPORT_SYMBOL drivers/video/display/display 0xa0745a39 display_device_register +EXPORT_SYMBOL drivers/video/display/display 0xc7f4b880 display_device_unregister +EXPORT_SYMBOL drivers/video/macmodes 0x08ed0b62 mac_vmode_to_var +EXPORT_SYMBOL drivers/video/macmodes 0xe2304303 mac_map_monitor_sense +EXPORT_SYMBOL drivers/video/macmodes 0xe6a3bed2 mac_find_mode +EXPORT_SYMBOL drivers/video/matrox/g450_pll 0x9f4ab64c matroxfb_g450_setpll_cond +EXPORT_SYMBOL drivers/video/matrox/g450_pll 0xad2bdace matroxfb_g450_setclk +EXPORT_SYMBOL drivers/video/matrox/g450_pll 0xb03fab4a g450_mnp2f +EXPORT_SYMBOL drivers/video/matrox/matroxfb_DAC1064 0x7f42761f DAC1064_global_init +EXPORT_SYMBOL drivers/video/matrox/matroxfb_DAC1064 0xa00c7599 matrox_mystique +EXPORT_SYMBOL drivers/video/matrox/matroxfb_DAC1064 0xafbd523d matrox_G100 +EXPORT_SYMBOL drivers/video/matrox/matroxfb_DAC1064 0xf027ba08 DAC1064_global_restore +EXPORT_SYMBOL drivers/video/matrox/matroxfb_Ti3026 0xd3303aad matrox_millennium +EXPORT_SYMBOL drivers/video/matrox/matroxfb_accel 0xd45ee435 matrox_cfbX_init +EXPORT_SYMBOL drivers/video/matrox/matroxfb_base 0x3615b57d matroxfb_register_driver +EXPORT_SYMBOL drivers/video/matrox/matroxfb_base 0x99dfe681 matroxfb_wait_for_sync +EXPORT_SYMBOL drivers/video/matrox/matroxfb_base 0xad15d278 matroxfb_unregister_driver +EXPORT_SYMBOL drivers/video/matrox/matroxfb_base 0xdcd64244 matroxfb_enable_irq +EXPORT_SYMBOL drivers/video/matrox/matroxfb_g450 0xce028318 matroxfb_g450_shutdown +EXPORT_SYMBOL drivers/video/matrox/matroxfb_g450 0xede2ea8f matroxfb_g450_connect +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0x25cf8049 matroxfb_PLL_calcclock +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0x404abef0 matroxfb_vgaHWrestore +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0xa17f25cb matroxfb_DAC_in +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0xabd8e427 matroxfb_var2my +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0xbd416385 matroxfb_read_pins +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0xefe99073 matroxfb_vgaHWinit +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0xff35983f matroxfb_DAC_out +EXPORT_SYMBOL drivers/video/output 0x0948c179 video_output_unregister +EXPORT_SYMBOL drivers/video/output 0x81ec7b94 video_output_register +EXPORT_SYMBOL drivers/video/sis/sisfb 0x3037658e sis_malloc +EXPORT_SYMBOL drivers/video/sis/sisfb 0x454a3cf0 sis_free +EXPORT_SYMBOL drivers/video/svgalib 0x00d1fce9 svga_set_default_seq_regs +EXPORT_SYMBOL drivers/video/svgalib 0x0601c3a1 svga_get_tilemax +EXPORT_SYMBOL drivers/video/svgalib 0x07b3da30 svga_wseq_multi +EXPORT_SYMBOL drivers/video/svgalib 0x0bda9ff6 svga_tilecopy +EXPORT_SYMBOL drivers/video/svgalib 0x1740cb61 svga_tilecursor +EXPORT_SYMBOL drivers/video/svgalib 0x1b95c56a svga_check_timings +EXPORT_SYMBOL drivers/video/svgalib 0x2eec89e9 svga_settile +EXPORT_SYMBOL drivers/video/svgalib 0x63e898d1 svga_set_default_crt_regs +EXPORT_SYMBOL drivers/video/svgalib 0x7a3ae959 svga_wcrt_multi +EXPORT_SYMBOL drivers/video/svgalib 0x80408443 svga_set_timings +EXPORT_SYMBOL drivers/video/svgalib 0x857a3b03 svga_get_caps +EXPORT_SYMBOL drivers/video/svgalib 0x8fa8438b svga_set_textmode_vga_regs +EXPORT_SYMBOL drivers/video/svgalib 0x90810781 svga_tileblit +EXPORT_SYMBOL drivers/video/svgalib 0xab3b22ad svga_set_default_gfx_regs +EXPORT_SYMBOL drivers/video/svgalib 0xd622f7c3 svga_tilefill +EXPORT_SYMBOL drivers/video/svgalib 0xdad682b1 svga_set_default_atc_regs +EXPORT_SYMBOL drivers/video/svgalib 0xec83c473 svga_match_format +EXPORT_SYMBOL drivers/video/svgalib 0xef774f5d svga_compute_pll +EXPORT_SYMBOL drivers/video/syscopyarea 0xb5d94d0e sys_copyarea +EXPORT_SYMBOL drivers/video/sysfillrect 0xb5806f70 sys_fillrect +EXPORT_SYMBOL drivers/video/sysimgblt 0xb4bbcb10 sys_imageblit +EXPORT_SYMBOL drivers/video/vgastate 0x686de290 restore_vga +EXPORT_SYMBOL drivers/video/vgastate 0xe7a2620e save_vga +EXPORT_SYMBOL drivers/w1/slaves/w1_ds2760 0x0a241503 w1_ds2760_read +EXPORT_SYMBOL drivers/w1/slaves/w1_ds2760 0x84bcae12 w1_ds2760_write +EXPORT_SYMBOL drivers/w1/wire 0x8cf61660 w1_add_master_device +EXPORT_SYMBOL drivers/w1/wire 0x9dd29d9c w1_unregister_family +EXPORT_SYMBOL drivers/w1/wire 0xb01a8e3c w1_register_family +EXPORT_SYMBOL drivers/w1/wire 0xcda061c0 w1_remove_master_device +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0x04e133fc iTCO_vendor_check_noreboot_on +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0x672c9d44 iTCO_vendor_pre_keepalive +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0xa78bd894 iTCO_vendor_pre_set_heartbeat +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0xa8d6daac iTCO_vendor_pre_start +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0xd0efe320 iTCO_vendor_pre_stop +EXPORT_SYMBOL fs/configfs/configfs 0x0e00306b config_item_set_name +EXPORT_SYMBOL fs/configfs/configfs 0x2072b1a8 configfs_undepend_item +EXPORT_SYMBOL fs/configfs/configfs 0x24127e1c config_item_put +EXPORT_SYMBOL fs/configfs/configfs 0x37c9ddd7 configfs_unregister_subsystem +EXPORT_SYMBOL fs/configfs/configfs 0x3f60a85a config_group_find_item +EXPORT_SYMBOL fs/configfs/configfs 0x43f02542 config_group_init +EXPORT_SYMBOL fs/configfs/configfs 0x4f09d1d8 config_item_init_type_name +EXPORT_SYMBOL fs/configfs/configfs 0x652e9f04 config_item_init +EXPORT_SYMBOL fs/configfs/configfs 0xaee88303 configfs_depend_item +EXPORT_SYMBOL fs/configfs/configfs 0xc63a33b9 config_item_get +EXPORT_SYMBOL fs/configfs/configfs 0xe3acb574 configfs_register_subsystem +EXPORT_SYMBOL fs/configfs/configfs 0xfd1a572d config_group_init_type_name +EXPORT_SYMBOL fs/jbd/jbd 0x0315b132 journal_start_commit +EXPORT_SYMBOL fs/jbd/jbd 0x0a481ea8 journal_set_features +EXPORT_SYMBOL fs/jbd/jbd 0x0b96b944 journal_init_inode +EXPORT_SYMBOL fs/jbd/jbd 0x0e8a21ee journal_force_commit +EXPORT_SYMBOL fs/jbd/jbd 0x1265944f journal_get_undo_access +EXPORT_SYMBOL fs/jbd/jbd 0x17f9ed56 journal_destroy +EXPORT_SYMBOL fs/jbd/jbd 0x245fcc45 journal_clear_err +EXPORT_SYMBOL fs/jbd/jbd 0x2716ba76 journal_start +EXPORT_SYMBOL fs/jbd/jbd 0x2ab9ad68 journal_invalidatepage +EXPORT_SYMBOL fs/jbd/jbd 0x3871ade0 journal_dirty_metadata +EXPORT_SYMBOL fs/jbd/jbd 0x42806031 journal_wipe +EXPORT_SYMBOL fs/jbd/jbd 0x4be89d64 journal_lock_updates +EXPORT_SYMBOL fs/jbd/jbd 0x4f059447 journal_get_write_access +EXPORT_SYMBOL fs/jbd/jbd 0x53a16079 journal_extend +EXPORT_SYMBOL fs/jbd/jbd 0x61b5d3aa journal_check_used_features +EXPORT_SYMBOL fs/jbd/jbd 0x6b40a0ed journal_ack_err +EXPORT_SYMBOL fs/jbd/jbd 0x728a9a29 journal_restart +EXPORT_SYMBOL fs/jbd/jbd 0x7dc841a5 journal_stop +EXPORT_SYMBOL fs/jbd/jbd 0x827aa567 log_wait_commit +EXPORT_SYMBOL fs/jbd/jbd 0x8654bc8e journal_init_dev +EXPORT_SYMBOL fs/jbd/jbd 0x89ce55da journal_get_create_access +EXPORT_SYMBOL fs/jbd/jbd 0x90a24c7b journal_update_format +EXPORT_SYMBOL fs/jbd/jbd 0xa54cb54d journal_try_to_free_buffers +EXPORT_SYMBOL fs/jbd/jbd 0xac7b8438 journal_dirty_data +EXPORT_SYMBOL fs/jbd/jbd 0xae23a343 journal_abort +EXPORT_SYMBOL fs/jbd/jbd 0xb0ac8bdc journal_load +EXPORT_SYMBOL fs/jbd/jbd 0xbf7025c8 journal_blocks_per_page +EXPORT_SYMBOL fs/jbd/jbd 0xc2b85509 journal_check_available_features +EXPORT_SYMBOL fs/jbd/jbd 0xc7dd8ac2 journal_unlock_updates +EXPORT_SYMBOL fs/jbd/jbd 0xd1b49763 journal_errno +EXPORT_SYMBOL fs/jbd/jbd 0xe366aafb journal_release_buffer +EXPORT_SYMBOL fs/jbd/jbd 0xe9270e6b journal_flush +EXPORT_SYMBOL fs/jbd/jbd 0xf1e385b7 journal_force_commit_nested +EXPORT_SYMBOL fs/jbd/jbd 0xf2bc523f journal_forget +EXPORT_SYMBOL fs/jbd/jbd 0xf890676e journal_revoke +EXPORT_SYMBOL fs/jbd/jbd 0xfb749fad journal_create +EXPORT_SYMBOL fs/jbd2/jbd2 0x010482a6 jbd2_journal_flush +EXPORT_SYMBOL fs/jbd2/jbd2 0x046adaf7 jbd2_journal_check_available_features +EXPORT_SYMBOL fs/jbd2/jbd2 0x12790f4e jbd2_journal_load +EXPORT_SYMBOL fs/jbd2/jbd2 0x167b3bd8 jbd2_journal_release_jbd_inode +EXPORT_SYMBOL fs/jbd2/jbd2 0x1b4b5a82 jbd2_journal_init_jbd_inode +EXPORT_SYMBOL fs/jbd2/jbd2 0x1cadbed1 jbd2_journal_blocks_per_page +EXPORT_SYMBOL fs/jbd2/jbd2 0x1ed7d0ba jbd2_journal_forget +EXPORT_SYMBOL fs/jbd2/jbd2 0x3482298d jbd2_journal_check_used_features +EXPORT_SYMBOL fs/jbd2/jbd2 0x3790472e jbd2_journal_update_format +EXPORT_SYMBOL fs/jbd2/jbd2 0x51727558 jbd2_journal_extend +EXPORT_SYMBOL fs/jbd2/jbd2 0x545bbc88 jbd2_journal_invalidatepage +EXPORT_SYMBOL fs/jbd2/jbd2 0x5b2b66c9 jbd2_journal_file_inode +EXPORT_SYMBOL fs/jbd2/jbd2 0x5eb007cb jbd2_journal_clear_err +EXPORT_SYMBOL fs/jbd2/jbd2 0x62abb039 jbd2_journal_force_commit_nested +EXPORT_SYMBOL fs/jbd2/jbd2 0x62e93ecb jbd2_journal_ack_err +EXPORT_SYMBOL fs/jbd2/jbd2 0x6a65a93e jbd2_journal_release_buffer +EXPORT_SYMBOL fs/jbd2/jbd2 0x6f7cb843 jbd2_journal_create +EXPORT_SYMBOL fs/jbd2/jbd2 0x73b4cbfd jbd2_journal_get_undo_access +EXPORT_SYMBOL fs/jbd2/jbd2 0x799b20c5 jbd2_journal_revoke +EXPORT_SYMBOL fs/jbd2/jbd2 0x881fb693 jbd2_log_wait_commit +EXPORT_SYMBOL fs/jbd2/jbd2 0x8b85bee9 jbd2_journal_force_commit +EXPORT_SYMBOL fs/jbd2/jbd2 0x8c329783 jbd2_journal_stop +EXPORT_SYMBOL fs/jbd2/jbd2 0x8ca5d338 jbd2_journal_dirty_metadata +EXPORT_SYMBOL fs/jbd2/jbd2 0x944f8579 jbd2_journal_errno +EXPORT_SYMBOL fs/jbd2/jbd2 0x95db66d9 jbd2_journal_set_features +EXPORT_SYMBOL fs/jbd2/jbd2 0x971b6388 jbd2_journal_init_dev +EXPORT_SYMBOL fs/jbd2/jbd2 0xa8669d91 jbd2_journal_unlock_updates +EXPORT_SYMBOL fs/jbd2/jbd2 0xab406c46 jbd2_journal_clear_features +EXPORT_SYMBOL fs/jbd2/jbd2 0xb781e51e jbd2_journal_begin_ordered_truncate +EXPORT_SYMBOL fs/jbd2/jbd2 0xb83feb07 jbd2_journal_wipe +EXPORT_SYMBOL fs/jbd2/jbd2 0xbde788fb jbd2_journal_abort +EXPORT_SYMBOL fs/jbd2/jbd2 0xbded8196 jbd2_journal_get_write_access +EXPORT_SYMBOL fs/jbd2/jbd2 0xc1a5065f jbd2_journal_restart +EXPORT_SYMBOL fs/jbd2/jbd2 0xc541f7f3 jbd2_journal_lock_updates +EXPORT_SYMBOL fs/jbd2/jbd2 0xc7688423 jbd2_journal_start +EXPORT_SYMBOL fs/jbd2/jbd2 0xce7a072b jbd2_journal_destroy +EXPORT_SYMBOL fs/jbd2/jbd2 0xe94b398a jbd2_journal_get_create_access +EXPORT_SYMBOL fs/jbd2/jbd2 0xec91c5c7 jbd2_journal_try_to_free_buffers +EXPORT_SYMBOL fs/jbd2/jbd2 0xecc3fa89 jbd2_journal_init_inode +EXPORT_SYMBOL fs/jbd2/jbd2 0xf474f721 jbd2_journal_start_commit +EXPORT_SYMBOL fs/lockd/lockd 0x976e539e lockd_up +EXPORT_SYMBOL fs/lockd/lockd 0xa7b91a7b lockd_down +EXPORT_SYMBOL fs/lockd/lockd 0xad09c2db get_nfs_grace_period +EXPORT_SYMBOL fs/lockd/lockd 0xc3e85e55 nlmsvc_ops +EXPORT_SYMBOL fs/mbcache 0x225036c9 mb_cache_create +EXPORT_SYMBOL fs/mbcache 0x31c4fb13 mb_cache_entry_alloc +EXPORT_SYMBOL fs/mbcache 0x4849826f mb_cache_shrink +EXPORT_SYMBOL fs/mbcache 0xa01e8dbc mb_cache_entry_get +EXPORT_SYMBOL fs/mbcache 0xaa784f37 mb_cache_entry_release +EXPORT_SYMBOL fs/mbcache 0xbbb64644 mb_cache_entry_free +EXPORT_SYMBOL fs/mbcache 0xc7c99d88 mb_cache_entry_find_first +EXPORT_SYMBOL fs/mbcache 0xd4d39791 mb_cache_entry_insert +EXPORT_SYMBOL fs/mbcache 0xd5263820 mb_cache_destroy +EXPORT_SYMBOL fs/mbcache 0xeda7ff37 mb_cache_entry_find_next +EXPORT_SYMBOL fs/nfs_common/nfs_acl 0x4b77898d nfsacl_encode +EXPORT_SYMBOL fs/nfs_common/nfs_acl 0x74a3433f nfsacl_decode +EXPORT_SYMBOL fs/nfsd/nfsd 0x0f3e6e01 nfs4_acl_nfsv4_to_posix +EXPORT_SYMBOL fs/nfsd/nfsd 0x2095976a nfs4_acl_new +EXPORT_SYMBOL fs/nfsd/nfsd 0x35e33c1e nfs4_acl_write_who +EXPORT_SYMBOL fs/nfsd/nfsd 0x5a157ae4 nfs4_acl_get_whotype +EXPORT_SYMBOL fs/nfsd/nfsd 0x7ee78c79 nfs4_acl_posix_to_nfsv4 +EXPORT_SYMBOL fs/xfs/xfs 0xd706b620 xfs_qmcore_xfs +EXPORT_SYMBOL lib/crc-ccitt 0x3771b461 crc_ccitt +EXPORT_SYMBOL lib/crc-ccitt 0x75811312 crc_ccitt_table +EXPORT_SYMBOL lib/crc-itu-t 0xd29b009f crc_itu_t_table +EXPORT_SYMBOL lib/crc-itu-t 0xf5b4a948 crc_itu_t +EXPORT_SYMBOL lib/crc-t10dif 0xb6896671 crc_t10dif +EXPORT_SYMBOL lib/crc16 0x02a6ce5a crc16_table +EXPORT_SYMBOL lib/crc16 0x8ffdb3b8 crc16 +EXPORT_SYMBOL lib/crc7 0xa7587646 crc7 +EXPORT_SYMBOL lib/crc7 0xd80c3603 crc7_syndrome_table +EXPORT_SYMBOL lib/libcrc32c 0x2329b292 crc32c_be +EXPORT_SYMBOL lib/libcrc32c 0x37d0b921 crc32c_le +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0x315c65fd zlib_deflateInit2 +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0x48034724 zlib_deflateReset +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0xaf64ad0d zlib_deflate +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0xf0caf44b zlib_deflate_workspacesize +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0xf741c793 zlib_deflateEnd +EXPORT_SYMBOL net/802/p8023 0x5eb0753e make_8023_client +EXPORT_SYMBOL net/802/p8023 0xe6e70321 destroy_8023_client +EXPORT_SYMBOL net/9p/9pnet 0x00a6e1a5 p9_create_tclunk +EXPORT_SYMBOL net/9p/9pnet 0x0106a185 p9_create_tstat +EXPORT_SYMBOL net/9p/9pnet 0x02758ea0 p9_client_uwrite +EXPORT_SYMBOL net/9p/9pnet 0x15779868 p9_set_tag +EXPORT_SYMBOL net/9p/9pnet 0x18d276c1 p9_client_read +EXPORT_SYMBOL net/9p/9pnet 0x21523da9 p9_create_tattach +EXPORT_SYMBOL net/9p/9pnet 0x2190b98e p9_client_disconnect +EXPORT_SYMBOL net/9p/9pnet 0x21de3067 p9_client_write +EXPORT_SYMBOL net/9p/9pnet 0x272852a1 p9_client_uread +EXPORT_SYMBOL net/9p/9pnet 0x309767d8 p9_deserialize_stat +EXPORT_SYMBOL net/9p/9pnet 0x32b513a8 p9_client_auth +EXPORT_SYMBOL net/9p/9pnet 0x3455711e p9_idpool_destroy +EXPORT_SYMBOL net/9p/9pnet 0x3d73a797 p9_errstr2errno +EXPORT_SYMBOL net/9p/9pnet 0x3e42e72f p9_client_wstat +EXPORT_SYMBOL net/9p/9pnet 0x465c4e6f p9_printfcall +EXPORT_SYMBOL net/9p/9pnet 0x47f2a66e v9fs_register_trans +EXPORT_SYMBOL net/9p/9pnet 0x507c9d70 p9_create_tauth +EXPORT_SYMBOL net/9p/9pnet 0x6146a046 v9fs_get_default_trans +EXPORT_SYMBOL net/9p/9pnet 0x62d228ff p9_client_dirread +EXPORT_SYMBOL net/9p/9pnet 0x63a0cfb9 p9_client_remove +EXPORT_SYMBOL net/9p/9pnet 0x6461b8de p9_create_twrite +EXPORT_SYMBOL net/9p/9pnet 0x69e9d7f1 v9fs_get_trans_by_name +EXPORT_SYMBOL net/9p/9pnet 0x6f11c5c3 p9_create_twrite_u +EXPORT_SYMBOL net/9p/9pnet 0x71c7537d p9_create_tcreate +EXPORT_SYMBOL net/9p/9pnet 0x8104538a p9_client_create +EXPORT_SYMBOL net/9p/9pnet 0x81247f39 p9_create_tread +EXPORT_SYMBOL net/9p/9pnet 0x83e857c3 p9_client_attach +EXPORT_SYMBOL net/9p/9pnet 0x8432c83f p9_deserialize_fcall +EXPORT_SYMBOL net/9p/9pnet 0x950e6b03 p9_create_twstat +EXPORT_SYMBOL net/9p/9pnet 0xa9536064 p9_create_tversion +EXPORT_SYMBOL net/9p/9pnet 0xaab8671a p9_idpool_get +EXPORT_SYMBOL net/9p/9pnet 0xadfd597a p9_create_tremove +EXPORT_SYMBOL net/9p/9pnet 0xb420e61c p9_client_open +EXPORT_SYMBOL net/9p/9pnet 0xc7fa21d8 p9_client_readn +EXPORT_SYMBOL net/9p/9pnet 0xcae61af3 p9_idpool_create +EXPORT_SYMBOL net/9p/9pnet 0xd0faf92e p9_idpool_check +EXPORT_SYMBOL net/9p/9pnet 0xd75e505b p9_client_walk +EXPORT_SYMBOL net/9p/9pnet 0xd9dc9f2d p9_client_destroy +EXPORT_SYMBOL net/9p/9pnet 0xdc894ac7 p9_create_twalk +EXPORT_SYMBOL net/9p/9pnet 0xde9bb44a p9_client_stat +EXPORT_SYMBOL net/9p/9pnet 0xe58a3360 p9_error_init +EXPORT_SYMBOL net/9p/9pnet 0xef3f0705 p9_client_clunk +EXPORT_SYMBOL net/9p/9pnet 0xef7127b0 p9_idpool_put +EXPORT_SYMBOL net/9p/9pnet 0xf09b3efa p9_create_topen +EXPORT_SYMBOL net/9p/9pnet 0xf5c0b404 p9_client_fcreate +EXPORT_SYMBOL net/9p/9pnet 0xfa096122 v9fs_unregister_trans +EXPORT_SYMBOL net/9p/9pnet 0xfff27930 p9_create_tflush +EXPORT_SYMBOL net/appletalk/appletalk 0x27650d7b atrtr_get_dev +EXPORT_SYMBOL net/appletalk/appletalk 0x89a759fb aarp_send_ddp +EXPORT_SYMBOL net/appletalk/appletalk 0xb8d96c4f alloc_ltalkdev +EXPORT_SYMBOL net/appletalk/appletalk 0xfefb15c6 atalk_find_dev_addr +EXPORT_SYMBOL net/ax25/ax25 0x242852b9 ax25_uid_policy +EXPORT_SYMBOL net/ax25/ax25 0x3d2d82ec ax25_display_timer +EXPORT_SYMBOL net/ax25/ax25 0x433b4652 ax25_send_frame +EXPORT_SYMBOL net/ax25/ax25 0x444b3f0f ax25_listen_release +EXPORT_SYMBOL net/ax25/ax25 0x4502c65a asc2ax +EXPORT_SYMBOL net/ax25/ax25 0x49ab5314 ax25_findbyuid +EXPORT_SYMBOL net/ax25/ax25 0x53dea1ff ax2asc +EXPORT_SYMBOL net/ax25/ax25 0x5be7a513 ax25_hard_header +EXPORT_SYMBOL net/ax25/ax25 0x7628868f ax25_rebuild_header +EXPORT_SYMBOL net/ax25/ax25 0x78c33d48 ax25_linkfail_release +EXPORT_SYMBOL net/ax25/ax25 0x8c367dfc ax25_find_cb +EXPORT_SYMBOL net/ax25/ax25 0x8ede9e26 ax25_protocol_release +EXPORT_SYMBOL net/ax25/ax25 0xab285cc2 ax25_linkfail_register +EXPORT_SYMBOL net/ax25/ax25 0xc1444946 ax25cmp +EXPORT_SYMBOL net/ax25/ax25 0xc681f55d ax25_header_ops +EXPORT_SYMBOL net/ax25/ax25 0xd43ecbf1 null_ax25_address +EXPORT_SYMBOL net/ax25/ax25 0xfec5d055 ax25_listen_register +EXPORT_SYMBOL net/bluetooth/bluetooth 0x030aff77 hci_unregister_cb +EXPORT_SYMBOL net/bluetooth/bluetooth 0x0d80e9f2 hci_get_route +EXPORT_SYMBOL net/bluetooth/bluetooth 0x15bd0f79 hci_register_cb +EXPORT_SYMBOL net/bluetooth/bluetooth 0x16e5c209 hci_unregister_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0x3195a82e hci_connect +EXPORT_SYMBOL net/bluetooth/bluetooth 0x397c860e bt_sock_poll +EXPORT_SYMBOL net/bluetooth/bluetooth 0x44d25c05 hci_register_proto +EXPORT_SYMBOL net/bluetooth/bluetooth 0x49395e5b hci_free_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0x4989f585 bt_sock_ioctl +EXPORT_SYMBOL net/bluetooth/bluetooth 0x54310a59 hci_conn_auth +EXPORT_SYMBOL net/bluetooth/bluetooth 0x5fc31787 bt_sock_register +EXPORT_SYMBOL net/bluetooth/bluetooth 0x66195c35 hci_send_acl +EXPORT_SYMBOL net/bluetooth/bluetooth 0x7094f8ae bt_err +EXPORT_SYMBOL net/bluetooth/bluetooth 0x76ca7179 hci_resume_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0x9fa85224 bt_accept_dequeue +EXPORT_SYMBOL net/bluetooth/bluetooth 0xa7457743 hci_conn_encrypt +EXPORT_SYMBOL net/bluetooth/bluetooth 0xabeebe89 hci_unregister_proto +EXPORT_SYMBOL net/bluetooth/bluetooth 0xb45e5d26 bt_accept_unlink +EXPORT_SYMBOL net/bluetooth/bluetooth 0xb466ec30 hci_suspend_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0xc130d715 hci_send_sco +EXPORT_SYMBOL net/bluetooth/bluetooth 0xc2066af0 batostr +EXPORT_SYMBOL net/bluetooth/bluetooth 0xc3ad4cbb hci_alloc_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0xcc1fb551 baswap +EXPORT_SYMBOL net/bluetooth/bluetooth 0xd28f6939 bt_sock_unlink +EXPORT_SYMBOL net/bluetooth/bluetooth 0xd4f98e6e hci_recv_fragment +EXPORT_SYMBOL net/bluetooth/bluetooth 0xdbf84330 bt_sock_link +EXPORT_SYMBOL net/bluetooth/bluetooth 0xddf6a774 bt_accept_enqueue +EXPORT_SYMBOL net/bluetooth/bluetooth 0xe0963f84 hci_conn_check_link_mode +EXPORT_SYMBOL net/bluetooth/bluetooth 0xe675226a bt_sock_recvmsg +EXPORT_SYMBOL net/bluetooth/bluetooth 0xe89daff9 hci_conn_change_link_key +EXPORT_SYMBOL net/bluetooth/bluetooth 0xf0dfde1e hci_register_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0xf19294db bt_sock_unregister +EXPORT_SYMBOL net/bluetooth/bluetooth 0xf1e3c3b9 hci_conn_switch_role +EXPORT_SYMBOL net/bluetooth/bluetooth 0xfeb8e75f bt_sock_wait_state +EXPORT_SYMBOL net/bluetooth/l2cap 0xfc31fe88 l2cap_load +EXPORT_SYMBOL net/bridge/bridge 0x28767d0d br_should_route_hook +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x25bacdd6 ebt_register_match +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x278fbde3 ebt_unregister_watcher +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x48e3d285 ebt_register_target +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x629ea218 ebt_do_table +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x8367f4ef ebt_register_watcher +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x9a39abab ebt_unregister_match +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0xb4fd48cd ebt_unregister_table +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0xd088b3aa ebt_unregister_target +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0xd4947259 ebt_register_table +EXPORT_SYMBOL net/ieee80211/ieee80211 0x26a4bb9f ieee80211_rx +EXPORT_SYMBOL net/ieee80211/ieee80211 0x29056378 ieee80211_channel_to_index +EXPORT_SYMBOL net/ieee80211/ieee80211 0x347fcd82 ieee80211_channel_to_freq +EXPORT_SYMBOL net/ieee80211/ieee80211 0x3dc894de ieee80211_wx_get_scan +EXPORT_SYMBOL net/ieee80211/ieee80211 0x41e4a8c3 ieee80211_wx_set_encodeext +EXPORT_SYMBOL net/ieee80211/ieee80211 0x4d8966de ieee80211_get_geo +EXPORT_SYMBOL net/ieee80211/ieee80211 0x57bcf952 ieee80211_get_channel +EXPORT_SYMBOL net/ieee80211/ieee80211 0x5a325c20 ieee80211_wx_set_encode +EXPORT_SYMBOL net/ieee80211/ieee80211 0x7327cc6e ieee80211_set_geo +EXPORT_SYMBOL net/ieee80211/ieee80211 0x7a0d449b ieee80211_get_channel_flags +EXPORT_SYMBOL net/ieee80211/ieee80211 0x8417e0e7 ieee80211_is_valid_channel +EXPORT_SYMBOL net/ieee80211/ieee80211 0xa44c3100 ieee80211_freq_to_channel +EXPORT_SYMBOL net/ieee80211/ieee80211 0xa75c3a1c ieee80211_txb_free +EXPORT_SYMBOL net/ieee80211/ieee80211 0xa9fb135f escape_essid +EXPORT_SYMBOL net/ieee80211/ieee80211 0xad801d72 free_ieee80211 +EXPORT_SYMBOL net/ieee80211/ieee80211 0xc5b5563d ieee80211_wx_get_encode +EXPORT_SYMBOL net/ieee80211/ieee80211 0xdc296676 ieee80211_wx_get_encodeext +EXPORT_SYMBOL net/ieee80211/ieee80211 0xe0bbc39b alloc_ieee80211 +EXPORT_SYMBOL net/ieee80211/ieee80211 0xf1ad8a3b ieee80211_rx_mgt +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x10306461 ieee80211_register_crypto_ops +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x255ef650 ieee80211_unregister_crypto_ops +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x279e265f ieee80211_crypt_deinit_handler +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x327652a5 ieee80211_get_crypto_ops +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x469259e7 ieee80211_crypt_deinit_entries +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x5c503f08 ieee80211_crypt_delayed_deinit +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0xc993eb34 ieee80211_crypt_quiescing +EXPORT_SYMBOL net/ipv4/inet_lro 0x40e41bd0 lro_vlan_hwaccel_receive_frags +EXPORT_SYMBOL net/ipv4/inet_lro 0x6d621a25 lro_receive_skb +EXPORT_SYMBOL net/ipv4/inet_lro 0x80ebf575 lro_receive_frags +EXPORT_SYMBOL net/ipv4/inet_lro 0xb1fbecf6 lro_vlan_hwaccel_receive_skb +EXPORT_SYMBOL net/ipv4/inet_lro 0xbe73ca0a lro_flush_pkt +EXPORT_SYMBOL net/ipv4/inet_lro 0xf034f2b0 lro_flush_all +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x3a3b27bb register_ip_vs_app_inc +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x3a5b9fd5 ip_vs_conn_out_get +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x68169090 ip_vs_tcp_conn_listen +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x79ce59aa unregister_ip_vs_app +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x80f9b055 ip_vs_conn_in_get +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x8a325037 register_ip_vs_scheduler +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x8c4e1d1d register_ip_vs_app +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0xa1dbc2d8 ip_vs_proto_name +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0xbbc99ae5 ip_vs_skb_replace +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0xc77794df ip_vs_conn_new +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0xccfb5036 ip_vs_conn_put +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0xf9586de4 unregister_ip_vs_scheduler +EXPORT_SYMBOL net/ipv4/netfilter/arp_tables 0x4614b492 arpt_do_table +EXPORT_SYMBOL net/ipv4/netfilter/arp_tables 0x5c5a6572 arpt_unregister_table +EXPORT_SYMBOL net/ipv4/netfilter/arp_tables 0xee0cf217 arpt_register_table +EXPORT_SYMBOL net/ipv4/netfilter/ip_tables 0x74ec6984 ipt_register_table +EXPORT_SYMBOL net/ipv4/netfilter/ip_tables 0xe09de27b ipt_unregister_table +EXPORT_SYMBOL net/ipv4/netfilter/ip_tables 0xfdfc932d ipt_do_table +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0x093387d2 nf_nat_setup_info +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0x0da3caa9 nf_nat_mangle_udp_packet +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0x1167611a nf_nat_follow_master +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0x2445f79a nf_nat_mangle_tcp_packet +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0xc5cd90ce nf_nat_protocol_register +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0xcf5f7ac6 nf_nat_used_tuple +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0xe6623acb nf_nat_protocol_unregister +EXPORT_SYMBOL net/ipv4/tunnel4 0xabf667fa xfrm4_tunnel_deregister +EXPORT_SYMBOL net/ipv4/tunnel4 0xc4487c4f xfrm4_tunnel_register +EXPORT_SYMBOL net/ipv6/ipv6 0x02f59408 icmpv6_send +EXPORT_SYMBOL net/ipv6/ipv6 0x11d13702 xfrm6_rcv +EXPORT_SYMBOL net/ipv6/ipv6 0x18672af2 nf_ip6_checksum +EXPORT_SYMBOL net/ipv6/ipv6 0x1878112a inet6_ioctl +EXPORT_SYMBOL net/ipv6/ipv6 0x18befb64 inet6_register_protosw +EXPORT_SYMBOL net/ipv6/ipv6 0x1ddc494b inet6_unregister_protosw +EXPORT_SYMBOL net/ipv6/ipv6 0x26337a50 ipv6_setsockopt +EXPORT_SYMBOL net/ipv6/ipv6 0x2a39b3f4 ipv6_dev_get_saddr +EXPORT_SYMBOL net/ipv6/ipv6 0x30123eb5 icmpv6_statistics +EXPORT_SYMBOL net/ipv6/ipv6 0x538383c0 unregister_inet6addr_notifier +EXPORT_SYMBOL net/ipv6/ipv6 0x5589c232 inet6_bind +EXPORT_SYMBOL net/ipv6/ipv6 0x582c69d4 rt6_lookup +EXPORT_SYMBOL net/ipv6/ipv6 0x61ebbac6 xfrm6_input_addr +EXPORT_SYMBOL net/ipv6/ipv6 0x64721af6 ip6_frag_init +EXPORT_SYMBOL net/ipv6/ipv6 0x6be99ad2 xfrm6_prepare_output +EXPORT_SYMBOL net/ipv6/ipv6 0x6ceb6733 xfrm6_rcv_spi +EXPORT_SYMBOL net/ipv6/ipv6 0x75fb07d3 ipv6_getsockopt +EXPORT_SYMBOL net/ipv6/ipv6 0x844d176b ip6_xmit +EXPORT_SYMBOL net/ipv6/ipv6 0x861212be ipv6_push_nfrag_opts +EXPORT_SYMBOL net/ipv6/ipv6 0x98542218 ipv6_chk_prefix +EXPORT_SYMBOL net/ipv6/ipv6 0x9cf533a8 in6_dev_finish_destroy +EXPORT_SYMBOL net/ipv6/ipv6 0x9ed749b0 ip6_frag_match +EXPORT_SYMBOL net/ipv6/ipv6 0xa9f9c0c5 ipv6_chk_addr +EXPORT_SYMBOL net/ipv6/ipv6 0xb3e9c991 ip6_route_output +EXPORT_SYMBOL net/ipv6/ipv6 0xb905ad82 icmpv6_err_convert +EXPORT_SYMBOL net/ipv6/ipv6 0xce19bac5 register_inet6addr_notifier +EXPORT_SYMBOL net/ipv6/ipv6 0xdaae34df inet6_del_protocol +EXPORT_SYMBOL net/ipv6/ipv6 0xdbe32195 inet6_getname +EXPORT_SYMBOL net/ipv6/ipv6 0xe1a81c3a icmpv6msg_statistics +EXPORT_SYMBOL net/ipv6/ipv6 0xe690b8fd __ipv6_isatap_ifid +EXPORT_SYMBOL net/ipv6/ipv6 0xe8b945d8 ndisc_mc_map +EXPORT_SYMBOL net/ipv6/ipv6 0xe937de51 inet6_release +EXPORT_SYMBOL net/ipv6/ipv6 0xec5f721b ip6_route_me_harder +EXPORT_SYMBOL net/ipv6/ipv6 0xf6842d1d xfrm6_find_1stfragopt +EXPORT_SYMBOL net/ipv6/ipv6 0xf75ab72f inet6_add_protocol +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0x0526d22b ipv6_find_hdr +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0x3c425986 ip6t_unregister_table +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0x5085a03a ip6t_register_table +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0xb8bddf33 ip6t_ext_hdr +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0xd274f4fd ip6t_do_table +EXPORT_SYMBOL net/ipv6/tunnel6 0x0d88740a xfrm6_tunnel_deregister +EXPORT_SYMBOL net/ipv6/tunnel6 0x7764342f xfrm6_tunnel_register +EXPORT_SYMBOL net/ipv6/xfrm6_tunnel 0x9cd013f2 xfrm6_tunnel_alloc_spi +EXPORT_SYMBOL net/ipv6/xfrm6_tunnel 0xab14e193 xfrm6_tunnel_free_spi +EXPORT_SYMBOL net/ipv6/xfrm6_tunnel 0xdb1b42d1 xfrm6_tunnel_spi_lookup +EXPORT_SYMBOL net/irda/ircomm/ircomm 0x0f2fc9a2 ircomm_connect_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0x421407ce ircomm_connect_response +EXPORT_SYMBOL net/irda/ircomm/ircomm 0x6af7bd6e ircomm_data_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0x8f2ba2cf ircomm_control_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0xab4f7f5c ircomm_open +EXPORT_SYMBOL net/irda/ircomm/ircomm 0xb93279c9 ircomm_disconnect_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0xb97ccf5d ircomm_flow_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0xf08246c3 ircomm_close +EXPORT_SYMBOL net/irda/irda 0x01d1fcdb hashbin_delete +EXPORT_SYMBOL net/irda/irda 0x06a3ee58 irias_new_integer_value +EXPORT_SYMBOL net/irda/irda 0x072e026f irias_add_octseq_attrib +EXPORT_SYMBOL net/irda/irda 0x07d3647c irlmp_register_service +EXPORT_SYMBOL net/irda/irda 0x0b40d29a irttp_connect_response +EXPORT_SYMBOL net/irda/irda 0x0e28f5e5 irttp_close_tsap +EXPORT_SYMBOL net/irda/irda 0x1f79e154 irlmp_close_lsap +EXPORT_SYMBOL net/irda/irda 0x2036ad06 irda_param_insert +EXPORT_SYMBOL net/irda/irda 0x2ec7c747 irlmp_open_lsap +EXPORT_SYMBOL net/irda/irda 0x3462950f hashbin_remove +EXPORT_SYMBOL net/irda/irda 0x34921a92 irda_notify_init +EXPORT_SYMBOL net/irda/irda 0x34f9484e irlmp_data_request +EXPORT_SYMBOL net/irda/irda 0x3552db24 proc_irda +EXPORT_SYMBOL net/irda/irda 0x38a20e5b irda_debug +EXPORT_SYMBOL net/irda/irda 0x448b8aaa irda_qos_bits_to_value +EXPORT_SYMBOL net/irda/irda 0x46c1c4a2 irlmp_unregister_service +EXPORT_SYMBOL net/irda/irda 0x4d6b24e8 irlap_close +EXPORT_SYMBOL net/irda/irda 0x4fb98771 async_wrap_skb +EXPORT_SYMBOL net/irda/irda 0x567f4f19 irttp_open_tsap +EXPORT_SYMBOL net/irda/irda 0x60840212 irttp_udata_request +EXPORT_SYMBOL net/irda/irda 0x632ebe88 iriap_close +EXPORT_SYMBOL net/irda/irda 0x6758f8ac irias_new_object +EXPORT_SYMBOL net/irda/irda 0x68b7447c hashbin_find +EXPORT_SYMBOL net/irda/irda 0x6b043eba irda_init_max_qos_capabilies +EXPORT_SYMBOL net/irda/irda 0x6ff0115d irttp_connect_request +EXPORT_SYMBOL net/irda/irda 0x7042bc54 irlmp_register_client +EXPORT_SYMBOL net/irda/irda 0x747d6779 irias_delete_object +EXPORT_SYMBOL net/irda/irda 0x7621e908 hashbin_insert +EXPORT_SYMBOL net/irda/irda 0x76243bc9 irias_insert_object +EXPORT_SYMBOL net/irda/irda 0x763e54a4 irlmp_unregister_client +EXPORT_SYMBOL net/irda/irda 0x781e2db5 irias_find_object +EXPORT_SYMBOL net/irda/irda 0x7957f728 irlmp_update_client +EXPORT_SYMBOL net/irda/irda 0x7a57b6f3 hashbin_remove_this +EXPORT_SYMBOL net/irda/irda 0x7df54878 irda_device_set_media_busy +EXPORT_SYMBOL net/irda/irda 0x87db2534 irlap_open +EXPORT_SYMBOL net/irda/irda 0x91815586 irda_param_pack +EXPORT_SYMBOL net/irda/irda 0x9759f706 irttp_data_request +EXPORT_SYMBOL net/irda/irda 0x993ad14b irda_param_extract_all +EXPORT_SYMBOL net/irda/irda 0x9c44ec50 irttp_disconnect_request +EXPORT_SYMBOL net/irda/irda 0xa4516ef8 async_unwrap_char +EXPORT_SYMBOL net/irda/irda 0xb520d7d5 irlmp_disconnect_request +EXPORT_SYMBOL net/irda/irda 0xb9394173 irias_delete_value +EXPORT_SYMBOL net/irda/irda 0xbcd3ef13 irias_object_change_attribute +EXPORT_SYMBOL net/irda/irda 0xbdc391c8 irlmp_connect_response +EXPORT_SYMBOL net/irda/irda 0xbe40ace9 irlmp_discovery_request +EXPORT_SYMBOL net/irda/irda 0xc14e9b6a hashbin_get_next +EXPORT_SYMBOL net/irda/irda 0xc76a6545 iriap_getvaluebyclass_request +EXPORT_SYMBOL net/irda/irda 0xcd41236c hashbin_new +EXPORT_SYMBOL net/irda/irda 0xd7172ff4 hashbin_get_first +EXPORT_SYMBOL net/irda/irda 0xd72d04fd irlmp_connect_request +EXPORT_SYMBOL net/irda/irda 0xd8bfb6d4 hashbin_lock_find +EXPORT_SYMBOL net/irda/irda 0xdd17a12b alloc_irdadev +EXPORT_SYMBOL net/irda/irda 0xde4c6b3c irlmp_service_to_hint +EXPORT_SYMBOL net/irda/irda 0xe5260e0e irias_add_integer_attrib +EXPORT_SYMBOL net/irda/irda 0xec41fe7f irias_add_string_attrib +EXPORT_SYMBOL net/irda/irda 0xedd521c2 irlmp_get_discoveries +EXPORT_SYMBOL net/irda/irda 0xedff20ec irttp_dup +EXPORT_SYMBOL net/irda/irda 0xf39b7fe0 irda_setup_dma +EXPORT_SYMBOL net/irda/irda 0xf3c1aa1e irttp_flow_request +EXPORT_SYMBOL net/irda/irda 0xfd6c7d55 iriap_open +EXPORT_SYMBOL net/lapb/lapb 0x17aa7429 lapb_setparms +EXPORT_SYMBOL net/lapb/lapb 0x306398f7 lapb_unregister +EXPORT_SYMBOL net/lapb/lapb 0x7dd81019 lapb_connect_request +EXPORT_SYMBOL net/lapb/lapb 0x7f4cd15f lapb_disconnect_request +EXPORT_SYMBOL net/lapb/lapb 0x80c01725 lapb_register +EXPORT_SYMBOL net/lapb/lapb 0xa5a4a543 lapb_data_request +EXPORT_SYMBOL net/lapb/lapb 0xab4bc7bc lapb_data_received +EXPORT_SYMBOL net/lapb/lapb 0xc89d045e lapb_getparms +EXPORT_SYMBOL net/mac80211/mac80211 0x01f7e448 __ieee80211_get_rx_led_name +EXPORT_SYMBOL net/mac80211/mac80211 0x076476e8 ieee80211_stop_queues +EXPORT_SYMBOL net/mac80211/mac80211 0x078912a6 ieee80211_rts_get +EXPORT_SYMBOL net/mac80211/mac80211 0x0aa30f7c ieee80211_rate_control_unregister +EXPORT_SYMBOL net/mac80211/mac80211 0x0d6ac623 ieee80211_tx_status +EXPORT_SYMBOL net/mac80211/mac80211 0x17abd85c ieee80211_ctstoself_duration +EXPORT_SYMBOL net/mac80211/mac80211 0x3077afa2 ieee80211_wake_queue +EXPORT_SYMBOL net/mac80211/mac80211 0x33ab6277 ieee80211_generic_frame_duration +EXPORT_SYMBOL net/mac80211/mac80211 0x371f1600 ieee80211_scan_completed +EXPORT_SYMBOL net/mac80211/mac80211 0x3a4fb7ac __ieee80211_rx +EXPORT_SYMBOL net/mac80211/mac80211 0x3b3f150d ieee80211_start_tx_ba_cb_irqsafe +EXPORT_SYMBOL net/mac80211/mac80211 0x49ef338b ieee80211_get_hdrlen +EXPORT_SYMBOL net/mac80211/mac80211 0x51ed850a ieee80211_unregister_hw +EXPORT_SYMBOL net/mac80211/mac80211 0x68e9d438 ieee80211_notify_mac +EXPORT_SYMBOL net/mac80211/mac80211 0x6c1ca9e7 sta_info_get +EXPORT_SYMBOL net/mac80211/mac80211 0x76680b83 ieee80211_stop_queue +EXPORT_SYMBOL net/mac80211/mac80211 0x7bb95e09 ieee80211_rate_control_register +EXPORT_SYMBOL net/mac80211/mac80211 0x8bc65460 ieee80211_alloc_hw +EXPORT_SYMBOL net/mac80211/mac80211 0x8c35d732 ieee80211_hdrlen +EXPORT_SYMBOL net/mac80211/mac80211 0x93c8724c __ieee80211_get_radio_led_name +EXPORT_SYMBOL net/mac80211/mac80211 0x972bc3a3 __ieee80211_get_tx_led_name +EXPORT_SYMBOL net/mac80211/mac80211 0x9dd7870d ieee80211_stop_tx_ba_session +EXPORT_SYMBOL net/mac80211/mac80211 0xa900d206 ieee80211_get_tkip_key +EXPORT_SYMBOL net/mac80211/mac80211 0xaf85c222 ieee80211_get_buffered_bc +EXPORT_SYMBOL net/mac80211/mac80211 0xb5da8e19 __ieee80211_get_assoc_led_name +EXPORT_SYMBOL net/mac80211/mac80211 0xb660d6cd ieee80211_register_hw +EXPORT_SYMBOL net/mac80211/mac80211 0xc5257b1f ieee80211_ctstoself_get +EXPORT_SYMBOL net/mac80211/mac80211 0xc84cedbf ieee80211_rx_irqsafe +EXPORT_SYMBOL net/mac80211/mac80211 0xd661d2e7 ieee80211_tx_status_irqsafe +EXPORT_SYMBOL net/mac80211/mac80211 0xdbf3facc ieee80211_wake_queues +EXPORT_SYMBOL net/mac80211/mac80211 0xe26f05e5 ieee80211_beacon_get +EXPORT_SYMBOL net/mac80211/mac80211 0xebce0576 ieee80211_rts_duration +EXPORT_SYMBOL net/mac80211/mac80211 0xef61fde3 ieee80211_free_hw +EXPORT_SYMBOL net/mac80211/mac80211 0xf1df0e03 ieee80211_stop_tx_ba_cb +EXPORT_SYMBOL net/mac80211/mac80211 0xf319e038 ieee80211_stop_tx_ba_cb_irqsafe +EXPORT_SYMBOL net/mac80211/mac80211 0xf6807cdc ieee80211_start_tx_ba_session +EXPORT_SYMBOL net/mac80211/mac80211 0xf7ca845a ieee80211_start_tx_ba_cb +EXPORT_SYMBOL net/mac80211/mac80211 0xfb61dafe ieee80211_get_hdrlen_from_skb +EXPORT_SYMBOL net/netfilter/nf_conntrack 0x8fb4ee7a __nf_ct_ext_destroy +EXPORT_SYMBOL net/netfilter/nf_conntrack 0xe372c1b6 __nf_ct_ext_add +EXPORT_SYMBOL net/netfilter/nf_conntrack 0xed23741c per_cpu__nf_conntrack_stat +EXPORT_SYMBOL net/netfilter/nf_conntrack_proto_gre 0x82f94e40 nf_ct_gre_keymap_flush +EXPORT_SYMBOL net/netfilter/x_tables 0x02dd49cb xt_unregister_target +EXPORT_SYMBOL net/netfilter/x_tables 0x3b923219 xt_unregister_targets +EXPORT_SYMBOL net/netfilter/x_tables 0x3dcd58c5 xt_alloc_table_info +EXPORT_SYMBOL net/netfilter/x_tables 0x55a1e043 xt_find_match +EXPORT_SYMBOL net/netfilter/x_tables 0x8a7937ac xt_unregister_match +EXPORT_SYMBOL net/netfilter/x_tables 0xa40b417e xt_find_target +EXPORT_SYMBOL net/netfilter/x_tables 0xa9c7356c xt_register_targets +EXPORT_SYMBOL net/netfilter/x_tables 0xb2b065d1 xt_register_match +EXPORT_SYMBOL net/netfilter/x_tables 0xbf0e2bda xt_unregister_matches +EXPORT_SYMBOL net/netfilter/x_tables 0xda8fbfa1 xt_register_target +EXPORT_SYMBOL net/netfilter/x_tables 0xec7c6d97 xt_register_matches +EXPORT_SYMBOL net/netfilter/x_tables 0xf7037dc6 xt_free_table_info +EXPORT_SYMBOL net/rfkill/rfkill 0x00caa4dc rfkill_switch_all +EXPORT_SYMBOL net/rfkill/rfkill 0x06fd7395 rfkill_force_state +EXPORT_SYMBOL net/rfkill/rfkill 0x382b61b2 rfkill_register +EXPORT_SYMBOL net/rfkill/rfkill 0x4fa781e3 rfkill_free +EXPORT_SYMBOL net/rfkill/rfkill 0x8002093b rfkill_allocate +EXPORT_SYMBOL net/rfkill/rfkill 0xeee38826 rfkill_unregister +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x07e285e0 rxrpc_kernel_abort_call +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x1760336f rxrpc_get_server_data_key +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x240e7910 rxrpc_get_null_key +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x2ceb99a7 rxrpc_kernel_get_error_number +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x3f39235f rxrpc_kernel_intercept_rx_messages +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x48589d08 rxrpc_kernel_reject_call +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x4a37ac4a rxrpc_kernel_send_data +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x5be33fb8 rxrpc_kernel_free_skb +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x6d02f5f8 rxrpc_kernel_accept_call +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x7fe89663 rxrpc_kernel_end_call +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xb6f678c7 rxrpc_kernel_data_delivered +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xbf659992 key_type_rxrpc +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xcab03e2e rxrpc_kernel_get_abort_code +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xcd1759a7 rxrpc_kernel_is_data_last +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xfcc45f98 rxrpc_kernel_begin_call +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x00a7737b gss_mech_unregister +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x00ac081e gss_mech_get +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x00c52ef5 g_make_token_header +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x106d9f18 gss_mech_put +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x2ddec1f0 gss_svc_to_pseudoflavor +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x7accc60b gss_mech_get_by_name +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x87d57a2f gss_mech_get_by_pseudoflavor +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x8d1a827e svcauth_gss_register_pseudoflavor +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x9e42177d gss_service_to_auth_domain_name +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xa3838cc6 svcauth_gss_flavor +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xab5affbd gss_mech_register +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xb5dea7ef g_token_size +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xe9025dde gss_pseudoflavor_to_service +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xf8b2ff6e g_verify_token_header +EXPORT_SYMBOL net/sunrpc/sunrpc 0x01121bb1 rpc_queue_upcall +EXPORT_SYMBOL net/sunrpc/sunrpc 0x03b0ec2d auth_domain_find +EXPORT_SYMBOL net/sunrpc/sunrpc 0x05e807a9 xdr_encode_string +EXPORT_SYMBOL net/sunrpc/sunrpc 0x065994f1 xdr_encode_opaque_fixed +EXPORT_SYMBOL net/sunrpc/sunrpc 0x09850ef8 svc_wake_up +EXPORT_SYMBOL net/sunrpc/sunrpc 0x0ad57e92 svc_exit_thread +EXPORT_SYMBOL net/sunrpc/sunrpc 0x0f4f1a05 auth_unix_forget_old +EXPORT_SYMBOL net/sunrpc/sunrpc 0x0f668ba9 svc_auth_unregister +EXPORT_SYMBOL net/sunrpc/sunrpc 0x12e280e3 svc_proc_unregister +EXPORT_SYMBOL net/sunrpc/sunrpc 0x14f45a15 auth_domain_lookup +EXPORT_SYMBOL net/sunrpc/sunrpc 0x1bb5f3f2 xdr_buf_read_netobj +EXPORT_SYMBOL net/sunrpc/sunrpc 0x1e884002 rpc_mkpipe +EXPORT_SYMBOL net/sunrpc/sunrpc 0x1f956514 svc_sock_update_bufs +EXPORT_SYMBOL net/sunrpc/sunrpc 0x1fe45e39 xdr_shift_buf +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2034e9be xdr_init_encode +EXPORT_SYMBOL net/sunrpc/sunrpc 0x208e926a auth_unix_lookup +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2117757d cache_unregister +EXPORT_SYMBOL net/sunrpc/sunrpc 0x27c48174 cache_register +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2919b156 xdr_decode_string_inplace +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2b0a7307 xdr_inline_decode +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2b6da3dc svc_auth_register +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2eec63c9 xdr_encode_netobj +EXPORT_SYMBOL net/sunrpc/sunrpc 0x3be59a74 svc_set_num_threads +EXPORT_SYMBOL net/sunrpc/sunrpc 0x45b07d92 xdr_decode_array2 +EXPORT_SYMBOL net/sunrpc/sunrpc 0x4d762cf3 xdr_inline_pages +EXPORT_SYMBOL net/sunrpc/sunrpc 0x4f49ab87 auth_unix_add_addr +EXPORT_SYMBOL net/sunrpc/sunrpc 0x5128e0fb svc_create_pooled +EXPORT_SYMBOL net/sunrpc/sunrpc 0x5529f4c4 xdr_decode_word +EXPORT_SYMBOL net/sunrpc/sunrpc 0x580b3a28 auth_domain_put +EXPORT_SYMBOL net/sunrpc/sunrpc 0x5c4b67db xdr_encode_pages +EXPORT_SYMBOL net/sunrpc/sunrpc 0x612f0831 unix_domain_find +EXPORT_SYMBOL net/sunrpc/sunrpc 0x67001ec8 sunrpc_cache_lookup +EXPORT_SYMBOL net/sunrpc/sunrpc 0x6eea229d svcauth_unix_purge +EXPORT_SYMBOL net/sunrpc/sunrpc 0x71fa908a cache_flush +EXPORT_SYMBOL net/sunrpc/sunrpc 0x747e7886 svc_sock_names +EXPORT_SYMBOL net/sunrpc/sunrpc 0x7629e61d svc_drop +EXPORT_SYMBOL net/sunrpc/sunrpc 0x7a843744 xdr_init_decode +EXPORT_SYMBOL net/sunrpc/sunrpc 0x87312864 xdr_reserve_space +EXPORT_SYMBOL net/sunrpc/sunrpc 0x8c05638b xdr_encode_array2 +EXPORT_SYMBOL net/sunrpc/sunrpc 0x8d4daec3 svc_create +EXPORT_SYMBOL net/sunrpc/sunrpc 0xa10f39fd read_bytes_from_xdr_buf +EXPORT_SYMBOL net/sunrpc/sunrpc 0xa2a08d4d sunrpc_cache_update +EXPORT_SYMBOL net/sunrpc/sunrpc 0xa57d1cf3 rpc_unlink +EXPORT_SYMBOL net/sunrpc/sunrpc 0xa5b4d406 xdr_buf_subsegment +EXPORT_SYMBOL net/sunrpc/sunrpc 0xa72a49cb xdr_read_pages +EXPORT_SYMBOL net/sunrpc/sunrpc 0xb16c034e svc_destroy +EXPORT_SYMBOL net/sunrpc/sunrpc 0xb6c0a72d xdr_buf_from_iov +EXPORT_SYMBOL net/sunrpc/sunrpc 0xc3880471 xdr_decode_netobj +EXPORT_SYMBOL net/sunrpc/sunrpc 0xc8d0d018 svc_process +EXPORT_SYMBOL net/sunrpc/sunrpc 0xc8e96dea qword_addhex +EXPORT_SYMBOL net/sunrpc/sunrpc 0xcf01bf57 svcauth_unix_set_client +EXPORT_SYMBOL net/sunrpc/sunrpc 0xd3a60a76 xdr_enter_page +EXPORT_SYMBOL net/sunrpc/sunrpc 0xd65ed0b6 svc_proc_register +EXPORT_SYMBOL net/sunrpc/sunrpc 0xd7675e1a xdr_write_pages +EXPORT_SYMBOL net/sunrpc/sunrpc 0xd87844a0 svc_recv +EXPORT_SYMBOL net/sunrpc/sunrpc 0xd9312ec8 xdr_encode_word +EXPORT_SYMBOL net/sunrpc/sunrpc 0xdc6f1226 cache_purge +EXPORT_SYMBOL net/sunrpc/sunrpc 0xdde11ea2 svc_seq_show +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe5919cb1 xdr_encode_opaque +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe7d918e8 svc_authenticate +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe97f4ce5 qword_get +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe9ae825a svc_reserve +EXPORT_SYMBOL net/sunrpc/sunrpc 0xedcf6be4 qword_add +EXPORT_SYMBOL net/sunrpc/sunrpc 0xf5e7892a svc_set_client +EXPORT_SYMBOL net/sunrpc/sunrpc 0xf6aa7d9c xdr_process_buf +EXPORT_SYMBOL net/sunrpc/sunrpc 0xf6ed24bc svc_prepare_thread +EXPORT_SYMBOL net/sunrpc/sunrpc 0xf97def76 cache_check +EXPORT_SYMBOL net/tipc/tipc 0x04b26fac tipc_send_buf +EXPORT_SYMBOL net/tipc/tipc 0x08acf310 tipc_available_nodes +EXPORT_SYMBOL net/tipc/tipc 0x10d40fcd tipc_isconnected +EXPORT_SYMBOL net/tipc/tipc 0x11952ffe tipc_send_buf_fast +EXPORT_SYMBOL net/tipc/tipc 0x1394f72b tipc_recv_msg +EXPORT_SYMBOL net/tipc/tipc 0x1472b270 tipc_disconnect +EXPORT_SYMBOL net/tipc/tipc 0x1479cb03 tipc_deleteport +EXPORT_SYMBOL net/tipc/tipc 0x15b5ecde tipc_set_portunreliable +EXPORT_SYMBOL net/tipc/tipc 0x16f27683 tipc_block_bearer +EXPORT_SYMBOL net/tipc/tipc 0x17b3e71c tipc_reject_msg +EXPORT_SYMBOL net/tipc/tipc 0x242c94b1 tipc_createport_raw +EXPORT_SYMBOL net/tipc/tipc 0x259b74f9 tipc_acknowledge +EXPORT_SYMBOL net/tipc/tipc 0x27d8bb58 tipc_send2port +EXPORT_SYMBOL net/tipc/tipc 0x2a99f708 tipc_send_buf2name +EXPORT_SYMBOL net/tipc/tipc 0x310d1bc9 tipc_detach +EXPORT_SYMBOL net/tipc/tipc 0x3712e340 tipc_portunreliable +EXPORT_SYMBOL net/tipc/tipc 0x3976041f tipc_set_portimportance +EXPORT_SYMBOL net/tipc/tipc 0x4b2243c6 tipc_portimportance +EXPORT_SYMBOL net/tipc/tipc 0x4ba3cfc8 tipc_send2name +EXPORT_SYMBOL net/tipc/tipc 0x538b228a tipc_withdraw +EXPORT_SYMBOL net/tipc/tipc 0x5637ed44 tipc_get_mode +EXPORT_SYMBOL net/tipc/tipc 0x56e52bc1 tipc_continue +EXPORT_SYMBOL net/tipc/tipc 0x5c0d4b5c tipc_ref_valid +EXPORT_SYMBOL net/tipc/tipc 0x62a681a3 tipc_portunreturnable +EXPORT_SYMBOL net/tipc/tipc 0x64357d3c tipc_multicast +EXPORT_SYMBOL net/tipc/tipc 0x8001e3d7 tipc_forward2port +EXPORT_SYMBOL net/tipc/tipc 0x88b73627 tipc_get_addr +EXPORT_SYMBOL net/tipc/tipc 0x9c45558e tipc_enable_bearer +EXPORT_SYMBOL net/tipc/tipc 0x9ead10a0 tipc_send_buf2port +EXPORT_SYMBOL net/tipc/tipc 0xa936a24b tipc_get_port +EXPORT_SYMBOL net/tipc/tipc 0xadd203d0 tipc_connect2port +EXPORT_SYMBOL net/tipc/tipc 0xae0103c3 tipc_shutdown +EXPORT_SYMBOL net/tipc/tipc 0xb01ffc2c tipc_forward2name +EXPORT_SYMBOL net/tipc/tipc 0xb35b672c tipc_publish +EXPORT_SYMBOL net/tipc/tipc 0xbb2b2504 tipc_send +EXPORT_SYMBOL net/tipc/tipc 0xc0ab3033 tipc_createport +EXPORT_SYMBOL net/tipc/tipc 0xca36fd49 tipc_register_media +EXPORT_SYMBOL net/tipc/tipc 0xcec8514a tipc_set_portunreturnable +EXPORT_SYMBOL net/tipc/tipc 0xd44731e5 tipc_ownidentity +EXPORT_SYMBOL net/tipc/tipc 0xda7f9d3f tipc_attach +EXPORT_SYMBOL net/tipc/tipc 0xdd7cae4c tipc_forward_buf2name +EXPORT_SYMBOL net/tipc/tipc 0xdf5008fc tipc_peer +EXPORT_SYMBOL net/tipc/tipc 0xe7aece47 tipc_ispublished +EXPORT_SYMBOL net/tipc/tipc 0xeefd49b3 tipc_get_handle +EXPORT_SYMBOL net/tipc/tipc 0xef50a1ef tipc_disable_bearer +EXPORT_SYMBOL net/tipc/tipc 0xf025dc56 tipc_forward_buf2port +EXPORT_SYMBOL net/wanrouter/wanrouter 0x0ebe03d1 unregister_wan_device +EXPORT_SYMBOL net/wanrouter/wanrouter 0x7d26a863 register_wan_device +EXPORT_SYMBOL net/wireless/cfg80211 0x07e7ac5a ieee80211_radiotap_iterator_init +EXPORT_SYMBOL net/wireless/cfg80211 0x09c64fbd ieee80211_frequency_to_channel +EXPORT_SYMBOL net/wireless/cfg80211 0x377c88e4 wiphy_new +EXPORT_SYMBOL net/wireless/cfg80211 0xad44393f __ieee80211_get_channel +EXPORT_SYMBOL net/wireless/cfg80211 0xc4e85ec5 ieee80211_radiotap_iterator_next +EXPORT_SYMBOL net/wireless/cfg80211 0xccc291b3 ieee80211_channel_to_frequency +EXPORT_SYMBOL net/wireless/cfg80211 0xcd13e328 wiphy_unregister +EXPORT_SYMBOL net/wireless/cfg80211 0xdf8a4367 wiphy_free +EXPORT_SYMBOL net/wireless/cfg80211 0xf72c0ee6 wiphy_register +EXPORT_SYMBOL sound/ac97_bus 0xb65a27a1 ac97_bus_type +EXPORT_SYMBOL sound/core/oss/snd-mixer-oss 0xf6570018 snd_mixer_oss_ioctl_card +EXPORT_SYMBOL sound/core/seq/snd-seq 0x132d6103 snd_seq_kernel_client_enqueue_blocking +EXPORT_SYMBOL sound/core/seq/snd-seq 0x1a724fcc snd_seq_kernel_client_ctl +EXPORT_SYMBOL sound/core/seq/snd-seq 0x3061c52d snd_use_lock_sync_helper +EXPORT_SYMBOL sound/core/seq/snd-seq 0x3fb4d161 snd_seq_kernel_client_dispatch +EXPORT_SYMBOL sound/core/seq/snd-seq 0x56fddaed snd_seq_kernel_client_write_poll +EXPORT_SYMBOL sound/core/seq/snd-seq 0x6bb71038 snd_seq_delete_kernel_client +EXPORT_SYMBOL sound/core/seq/snd-seq 0x7ac2f329 snd_seq_expand_var_event +EXPORT_SYMBOL sound/core/seq/snd-seq 0x7b8699eb snd_seq_event_port_detach +EXPORT_SYMBOL sound/core/seq/snd-seq 0xb8e448a0 snd_seq_set_queue_tempo +EXPORT_SYMBOL sound/core/seq/snd-seq 0xcac0a3be snd_seq_kernel_client_enqueue +EXPORT_SYMBOL sound/core/seq/snd-seq 0xe4faad09 snd_seq_create_kernel_client +EXPORT_SYMBOL sound/core/seq/snd-seq 0xe934da1d snd_seq_dump_var_event +EXPORT_SYMBOL sound/core/seq/snd-seq 0xf52510c6 snd_seq_event_port_attach +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0x3a57f235 snd_seq_autoload_unlock +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0x6339b6d0 snd_seq_device_load_drivers +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0xb761f93e snd_seq_device_register_driver +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0xb90668b2 snd_seq_autoload_lock +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0xc622fb29 snd_seq_device_unregister_driver +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0xf5f89026 snd_seq_device_new +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-emul 0x6ea09972 snd_midi_channel_alloc_set +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-emul 0x833a3e07 snd_midi_channel_set_clear +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-emul 0xb9948d2c snd_midi_channel_free_set +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-emul 0xf0a1fdb3 snd_midi_process_event +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x17c15809 snd_midi_event_decode +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x4ad3f518 snd_midi_event_reset_decode +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x62384d3a snd_midi_event_encode +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x8a348811 snd_midi_event_reset_encode +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x9df7af8b snd_midi_event_free +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0xc482499d snd_midi_event_new +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0xd9072e1a snd_midi_event_no_status +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0xe6df29c7 snd_midi_event_encode_byte +EXPORT_SYMBOL sound/core/seq/snd-seq-virmidi 0xf43dca85 snd_virmidi_new +EXPORT_SYMBOL sound/core/snd 0x001d7f15 snd_device_new +EXPORT_SYMBOL sound/core/snd 0x0dcf535c snd_ctl_find_id +EXPORT_SYMBOL sound/core/snd 0x15a728d3 snd_info_create_module_entry +EXPORT_SYMBOL sound/core/snd 0x18e1683f snd_dma_program +EXPORT_SYMBOL sound/core/snd 0x191e88cf snd_dma_pointer +EXPORT_SYMBOL sound/core/snd 0x198788b4 snd_lookup_oss_minor_data +EXPORT_SYMBOL sound/core/snd 0x1af253e1 snd_card_file_remove +EXPORT_SYMBOL sound/core/snd 0x24345650 snd_ctl_add_slave +EXPORT_SYMBOL sound/core/snd 0x24a94b26 snd_info_get_line +EXPORT_SYMBOL sound/core/snd 0x30a89c2d snd_device_register +EXPORT_SYMBOL sound/core/snd 0x36257e30 snd_ctl_new1 +EXPORT_SYMBOL sound/core/snd 0x3971b4df snd_ecards_limit +EXPORT_SYMBOL sound/core/snd 0x3cfcfcd5 snd_info_create_card_entry +EXPORT_SYMBOL sound/core/snd 0x449a8b65 snd_card_free_when_closed +EXPORT_SYMBOL sound/core/snd 0x4838cc6a snd_ctl_add +EXPORT_SYMBOL sound/core/snd 0x4a3ea5c0 snd_request_card +EXPORT_SYMBOL sound/core/snd 0x4b5ae7bc snd_ctl_find_numid +EXPORT_SYMBOL sound/core/snd 0x4d4cba2d snd_cards +EXPORT_SYMBOL sound/core/snd 0x52fe113d release_and_free_resource +EXPORT_SYMBOL sound/core/snd 0x55611caa snd_component_add +EXPORT_SYMBOL sound/core/snd 0x5ea67507 snd_seq_root +EXPORT_SYMBOL sound/core/snd 0x602c96f0 copy_to_user_fromio +EXPORT_SYMBOL sound/core/snd 0x607d4cb9 snd_power_wait +EXPORT_SYMBOL sound/core/snd 0x653c30eb snd_unregister_device +EXPORT_SYMBOL sound/core/snd 0x68bffb24 snd_card_new +EXPORT_SYMBOL sound/core/snd 0x6e05d158 snd_ctl_remove +EXPORT_SYMBOL sound/core/snd 0x6f213bdb snd_card_free +EXPORT_SYMBOL sound/core/snd 0x70c15ac1 snd_dma_disable +EXPORT_SYMBOL sound/core/snd 0x778bf606 snd_pci_quirk_lookup +EXPORT_SYMBOL sound/core/snd 0x7c11b4b0 snd_register_oss_device +EXPORT_SYMBOL sound/core/snd 0x833a99d3 snd_unregister_oss_device +EXPORT_SYMBOL sound/core/snd 0x8df3789f snd_oss_info_register +EXPORT_SYMBOL sound/core/snd 0x8f595b11 snd_major +EXPORT_SYMBOL sound/core/snd 0x95c9d294 snd_ctl_boolean_mono_info +EXPORT_SYMBOL sound/core/snd 0x98457936 snd_ctl_boolean_stereo_info +EXPORT_SYMBOL sound/core/snd 0x99ee80de snd_register_device_for_dev +EXPORT_SYMBOL sound/core/snd 0xa784f349 snd_ctl_free_one +EXPORT_SYMBOL sound/core/snd 0xa9ea2624 snd_card_proc_new +EXPORT_SYMBOL sound/core/snd 0xafef45cb snd_ctl_unregister_ioctl +EXPORT_SYMBOL sound/core/snd 0xb213fe8b snd_info_get_str +EXPORT_SYMBOL sound/core/snd 0xb2e5ae4a snd_lookup_minor_data +EXPORT_SYMBOL sound/core/snd 0xb509441a snd_info_free_entry +EXPORT_SYMBOL sound/core/snd 0xb854637f snd_add_device_sysfs_file +EXPORT_SYMBOL sound/core/snd 0xbb4a488c snd_card_register +EXPORT_SYMBOL sound/core/snd 0xc4c17512 snd_ctl_remove_id +EXPORT_SYMBOL sound/core/snd 0xc82bd1d7 snd_card_disconnect +EXPORT_SYMBOL sound/core/snd 0xce3ca308 copy_from_user_toio +EXPORT_SYMBOL sound/core/snd 0xdb6103fb snd_card_file_add +EXPORT_SYMBOL sound/core/snd 0xdccf61f7 snd_info_register +EXPORT_SYMBOL sound/core/snd 0xe4854cea snd_iprintf +EXPORT_SYMBOL sound/core/snd 0xe9a40570 snd_ctl_rename_id +EXPORT_SYMBOL sound/core/snd 0xec6d336b snd_mixer_oss_notify_callback +EXPORT_SYMBOL sound/core/snd 0xeeed011e snd_ctl_make_virtual_master +EXPORT_SYMBOL sound/core/snd 0xf13c1b7d snd_device_free +EXPORT_SYMBOL sound/core/snd 0xf4993bfa snd_ctl_register_ioctl +EXPORT_SYMBOL sound/core/snd 0xf7f8b416 snd_ctl_notify +EXPORT_SYMBOL sound/core/snd-hwdep 0x37248322 snd_hwdep_new +EXPORT_SYMBOL sound/core/snd-page-alloc 0x3af99a85 snd_dma_alloc_pages_fallback +EXPORT_SYMBOL sound/core/snd-page-alloc 0x3b91f3af snd_free_pages +EXPORT_SYMBOL sound/core/snd-page-alloc 0x3cd381af snd_dma_alloc_pages +EXPORT_SYMBOL sound/core/snd-page-alloc 0x5958e14e snd_dma_reserve_buf +EXPORT_SYMBOL sound/core/snd-page-alloc 0x90b76857 snd_dma_free_pages +EXPORT_SYMBOL sound/core/snd-page-alloc 0xade88e76 snd_malloc_pages +EXPORT_SYMBOL sound/core/snd-page-alloc 0xee322055 snd_dma_get_reserved_buf +EXPORT_SYMBOL sound/core/snd-pcm 0x04cda566 snd_interval_refine +EXPORT_SYMBOL sound/core/snd-pcm 0x087b05e1 snd_pcm_mmap_data +EXPORT_SYMBOL sound/core/snd-pcm 0x0894d854 snd_pcm_lib_free_pages +EXPORT_SYMBOL sound/core/snd-pcm 0x0954db07 snd_pcm_lib_read +EXPORT_SYMBOL sound/core/snd-pcm 0x09f93eee snd_pcm_set_sync +EXPORT_SYMBOL sound/core/snd-pcm 0x12641fbc snd_pcm_set_ops +EXPORT_SYMBOL sound/core/snd-pcm 0x164b6b7b snd_pcm_new_stream +EXPORT_SYMBOL sound/core/snd-pcm 0x1bf84ada snd_pcm_hw_constraint_pow2 +EXPORT_SYMBOL sound/core/snd-pcm 0x1cf35618 snd_pcm_kernel_ioctl +EXPORT_SYMBOL sound/core/snd-pcm 0x1d027e4b snd_pcm_format_signed +EXPORT_SYMBOL sound/core/snd-pcm 0x1faa161d snd_pcm_open_substream +EXPORT_SYMBOL sound/core/snd-pcm 0x31b1000a snd_pcm_suspend +EXPORT_SYMBOL sound/core/snd-pcm 0x3796bdcc snd_pcm_format_little_endian +EXPORT_SYMBOL sound/core/snd-pcm 0x3ec7798c snd_pcm_lib_ioctl +EXPORT_SYMBOL sound/core/snd-pcm 0x3f4650b4 snd_pcm_suspend_all +EXPORT_SYMBOL sound/core/snd-pcm 0x4d9b6d35 snd_pcm_format_size +EXPORT_SYMBOL sound/core/snd-pcm 0x4eb91811 snd_pcm_lib_writev +EXPORT_SYMBOL sound/core/snd-pcm 0x4f816e9b snd_pcm_format_big_endian +EXPORT_SYMBOL sound/core/snd-pcm 0x5e7f4920 snd_pcm_format_set_silence +EXPORT_SYMBOL sound/core/snd-pcm 0x650f8603 snd_pcm_format_silence_64 +EXPORT_SYMBOL sound/core/snd-pcm 0x68a24153 snd_pcm_format_physical_width +EXPORT_SYMBOL sound/core/snd-pcm 0x68f5f4c1 snd_pcm_lib_malloc_pages +EXPORT_SYMBOL sound/core/snd-pcm 0x6ef8fcd8 snd_pcm_format_linear +EXPORT_SYMBOL sound/core/snd-pcm 0x715013d0 snd_pcm_limit_hw_rates +EXPORT_SYMBOL sound/core/snd-pcm 0x75564b65 snd_pcm_lib_mmap_iomem +EXPORT_SYMBOL sound/core/snd-pcm 0x773900bb snd_pcm_lib_preallocate_pages +EXPORT_SYMBOL sound/core/snd-pcm 0x7c5cec98 _snd_pcm_hw_params_any +EXPORT_SYMBOL sound/core/snd-pcm 0x7ce04390 snd_pcm_sgbuf_ops_page +EXPORT_SYMBOL sound/core/snd-pcm 0x7f7d474c snd_pcm_hw_constraint_list +EXPORT_SYMBOL sound/core/snd-pcm 0x88cc66cc snd_pcm_link_rwlock +EXPORT_SYMBOL sound/core/snd-pcm 0x89a31a56 _snd_pcm_hw_param_setempty +EXPORT_SYMBOL sound/core/snd-pcm 0x8ed0de1f snd_pcm_hw_constraint_integer +EXPORT_SYMBOL sound/core/snd-pcm 0x9c2ba934 snd_pcm_lib_write +EXPORT_SYMBOL sound/core/snd-pcm 0x9fdea959 snd_pcm_hw_param_value +EXPORT_SYMBOL sound/core/snd-pcm 0xa18baa53 snd_pcm_stop +EXPORT_SYMBOL sound/core/snd-pcm 0xa4a47492 snd_pcm_release_substream +EXPORT_SYMBOL sound/core/snd-pcm 0xa61aa028 snd_pcm_format_unsigned +EXPORT_SYMBOL sound/core/snd-pcm 0xa7890f07 snd_pcm_hw_rule_add +EXPORT_SYMBOL sound/core/snd-pcm 0xae8b2acd snd_pcm_lib_preallocate_free_for_all +EXPORT_SYMBOL sound/core/snd-pcm 0xb0b35cc0 snd_pcm_new +EXPORT_SYMBOL sound/core/snd-pcm 0xb423eaaf snd_pcm_notify +EXPORT_SYMBOL sound/core/snd-pcm 0xb591d79a snd_pcm_hw_constraint_msbits +EXPORT_SYMBOL sound/core/snd-pcm 0xb9638db4 snd_pcm_rate_to_rate_bit +EXPORT_SYMBOL sound/core/snd-pcm 0xbb50cb8f snd_pcm_hw_param_last +EXPORT_SYMBOL sound/core/snd-pcm 0xc2ef602e snd_pcm_lib_preallocate_pages_for_all +EXPORT_SYMBOL sound/core/snd-pcm 0xc891a252 snd_pcm_hw_constraint_minmax +EXPORT_SYMBOL sound/core/snd-pcm 0xd0b9b8b8 snd_interval_list +EXPORT_SYMBOL sound/core/snd-pcm 0xd82be959 snd_pcm_period_elapsed +EXPORT_SYMBOL sound/core/snd-pcm 0xdf0ffb6e snd_pcm_hw_param_first +EXPORT_SYMBOL sound/core/snd-pcm 0xe4a703ee snd_pcm_hw_constraint_ratdens +EXPORT_SYMBOL sound/core/snd-pcm 0xe56a9336 snd_pcm_format_width +EXPORT_SYMBOL sound/core/snd-pcm 0xe6e2f79d snd_pcm_hw_constraint_ratnums +EXPORT_SYMBOL sound/core/snd-pcm 0xe96dbcac snd_pcm_hw_refine +EXPORT_SYMBOL sound/core/snd-pcm 0xee9c74a0 snd_pcm_lib_readv +EXPORT_SYMBOL sound/core/snd-pcm 0xf2a0b15c snd_pcm_hw_constraint_step +EXPORT_SYMBOL sound/core/snd-pcm 0xf3797152 snd_interval_ratnum +EXPORT_SYMBOL sound/core/snd-rawmidi 0x12950b4a snd_rawmidi_transmit_empty +EXPORT_SYMBOL sound/core/snd-rawmidi 0x131ba3e0 snd_rawmidi_transmit_peek +EXPORT_SYMBOL sound/core/snd-rawmidi 0x2b33aaf7 snd_rawmidi_drop_output +EXPORT_SYMBOL sound/core/snd-rawmidi 0x2cc0b8a0 snd_rawmidi_kernel_read +EXPORT_SYMBOL sound/core/snd-rawmidi 0x3c38b7f7 snd_rawmidi_transmit +EXPORT_SYMBOL sound/core/snd-rawmidi 0x4ca70001 snd_rawmidi_receive +EXPORT_SYMBOL sound/core/snd-rawmidi 0x77a5e9c9 snd_rawmidi_kernel_write +EXPORT_SYMBOL sound/core/snd-rawmidi 0x9652917c snd_rawmidi_drain_input +EXPORT_SYMBOL sound/core/snd-rawmidi 0xa46652ad snd_rawmidi_new +EXPORT_SYMBOL sound/core/snd-rawmidi 0xb498c01f snd_rawmidi_transmit_ack +EXPORT_SYMBOL sound/core/snd-rawmidi 0xbedce6de snd_rawmidi_kernel_open +EXPORT_SYMBOL sound/core/snd-rawmidi 0xc1adf76e snd_rawmidi_kernel_release +EXPORT_SYMBOL sound/core/snd-rawmidi 0xe382d35d snd_rawmidi_drain_output +EXPORT_SYMBOL sound/core/snd-rawmidi 0xe8fa14aa snd_rawmidi_input_params +EXPORT_SYMBOL sound/core/snd-rawmidi 0xee725bfc snd_rawmidi_output_params +EXPORT_SYMBOL sound/core/snd-rawmidi 0xef2c640f snd_rawmidi_set_ops +EXPORT_SYMBOL sound/core/snd-rawmidi 0xfeacde11 snd_rawmidi_info_select +EXPORT_SYMBOL sound/core/snd-timer 0x04a88c63 snd_timer_global_register +EXPORT_SYMBOL sound/core/snd-timer 0x08b9f60c snd_timer_global_free +EXPORT_SYMBOL sound/core/snd-timer 0x0e22c0c9 snd_timer_continue +EXPORT_SYMBOL sound/core/snd-timer 0x1951467f snd_timer_global_new +EXPORT_SYMBOL sound/core/snd-timer 0x40c35fd4 snd_timer_interrupt +EXPORT_SYMBOL sound/core/snd-timer 0x80a509b6 snd_timer_open +EXPORT_SYMBOL sound/core/snd-timer 0x850aa2df snd_timer_pause +EXPORT_SYMBOL sound/core/snd-timer 0xba4f586b snd_timer_new +EXPORT_SYMBOL sound/core/snd-timer 0xbce07811 snd_timer_close +EXPORT_SYMBOL sound/core/snd-timer 0xc87d8c9d snd_timer_start +EXPORT_SYMBOL sound/core/snd-timer 0xe32d6ed4 snd_timer_stop +EXPORT_SYMBOL sound/core/snd-timer 0xe776b879 snd_timer_notify +EXPORT_SYMBOL sound/core/snd-timer 0xec3c8a36 snd_timer_resolution +EXPORT_SYMBOL sound/drivers/mpu401/snd-mpu401-uart 0x38627b82 snd_mpu401_uart_new +EXPORT_SYMBOL sound/drivers/mpu401/snd-mpu401-uart 0x73c4c993 snd_mpu401_uart_interrupt_tx +EXPORT_SYMBOL sound/drivers/mpu401/snd-mpu401-uart 0xfe618b58 snd_mpu401_uart_interrupt +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x05060a19 snd_opl3_regmap +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x09fb6389 snd_opl3_timer_new +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x52389bd8 snd_opl3_load_patch +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x610846f8 snd_opl3_hwdep_new +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x694993dc snd_opl3_init +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0xb7ec2607 snd_opl3_new +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0xd2e4da23 snd_opl3_interrupt +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0xe4df56d3 snd_opl3_find_patch +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0xfc2545bd snd_opl3_reset +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0xfe60953d snd_opl3_create +EXPORT_SYMBOL sound/drivers/opl4/snd-opl4-lib 0x345d531a snd_opl4_write +EXPORT_SYMBOL sound/drivers/opl4/snd-opl4-lib 0x8b53052e snd_opl4_create +EXPORT_SYMBOL sound/drivers/opl4/snd-opl4-lib 0x9681f2d4 snd_opl4_read_memory +EXPORT_SYMBOL sound/drivers/opl4/snd-opl4-lib 0xb51bd8c7 snd_opl4_write_memory +EXPORT_SYMBOL sound/drivers/opl4/snd-opl4-lib 0xdaec123e snd_opl4_read +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x1aa554f5 snd_vx_setup_firmware +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x1cadb14b snd_vx_irq_handler +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x3edb7110 snd_vx_resume +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x56717163 snd_vx_free_firmware +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x59364835 snd_vx_dsp_boot +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x6c1751da snd_vx_create +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0xbc3b6cdf snd_vx_dsp_load +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0xbfbcb6fb snd_vx_load_boot_image +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0xe85642b0 snd_vx_check_reg_bit +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0xf8b523d7 snd_vx_suspend +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0x83d4b463 snd_ak4114_check_rate_and_errors +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0xa72329b8 snd_ak4114_create +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0xabaa1b15 snd_ak4114_reinit +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0xb0a2cd0f snd_ak4114_reg_write +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0xbc0df119 snd_ak4114_build +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0xe9042ae6 snd_ak4114_external_rate +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x1d123b8f snd_ak4117_create +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x23516825 snd_ak4117_reg_write +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x2b651a81 snd_ak4117_reinit +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x4861900c snd_ak4117_build +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x809ee95c snd_ak4117_check_rate_and_errors +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0xd1cc1cd5 snd_ak4117_external_rate +EXPORT_SYMBOL sound/i2c/other/snd-ak4xxx-adda 0x42ac8a1d snd_akm4xxx_write +EXPORT_SYMBOL sound/i2c/other/snd-ak4xxx-adda 0x6ba17662 snd_akm4xxx_init +EXPORT_SYMBOL sound/i2c/other/snd-ak4xxx-adda 0xc787e554 snd_akm4xxx_reset +EXPORT_SYMBOL sound/i2c/other/snd-ak4xxx-adda 0xe13f73a1 snd_akm4xxx_build_controls +EXPORT_SYMBOL sound/i2c/other/snd-pt2258 0x1562e53f snd_pt2258_reset +EXPORT_SYMBOL sound/i2c/other/snd-pt2258 0xf4de0793 snd_pt2258_build_controls +EXPORT_SYMBOL sound/i2c/other/snd-tea575x-tuner 0xe9eb0235 snd_tea575x_init +EXPORT_SYMBOL sound/i2c/other/snd-tea575x-tuner 0xea4bf6d9 snd_tea575x_exit +EXPORT_SYMBOL sound/i2c/snd-cs8427 0x27228559 snd_cs8427_iec958_pcm +EXPORT_SYMBOL sound/i2c/snd-cs8427 0x43b2fe5c snd_cs8427_iec958_active +EXPORT_SYMBOL sound/i2c/snd-cs8427 0x7a47eadd snd_cs8427_reg_write +EXPORT_SYMBOL sound/i2c/snd-cs8427 0xa6b740c0 snd_cs8427_create +EXPORT_SYMBOL sound/i2c/snd-cs8427 0xf7804251 snd_cs8427_iec958_build +EXPORT_SYMBOL sound/i2c/snd-i2c 0x48d615d7 snd_i2c_probeaddr +EXPORT_SYMBOL sound/i2c/snd-i2c 0x543f6ee1 snd_i2c_bus_create +EXPORT_SYMBOL sound/i2c/snd-i2c 0x7d4829f9 snd_i2c_sendbytes +EXPORT_SYMBOL sound/i2c/snd-i2c 0xa2893951 snd_i2c_device_create +EXPORT_SYMBOL sound/i2c/snd-i2c 0xbc3c777f snd_i2c_device_free +EXPORT_SYMBOL sound/i2c/snd-i2c 0xc9574f0e snd_i2c_readbytes +EXPORT_SYMBOL sound/i2c/snd-tea6330t 0x2745766f snd_tea6330t_update_mixer +EXPORT_SYMBOL sound/i2c/snd-tea6330t 0x4445f4d1 snd_tea6330t_detect +EXPORT_SYMBOL sound/isa/ad1848/snd-ad1848-lib 0x22e81753 snd_ad1848_get_pcm_ops +EXPORT_SYMBOL sound/isa/ad1848/snd-ad1848-lib 0x9cc998c9 snd_ad1848_out +EXPORT_SYMBOL sound/isa/ad1848/snd-ad1848-lib 0xb1202c5c snd_ad1848_mixer +EXPORT_SYMBOL sound/isa/ad1848/snd-ad1848-lib 0xe203d787 snd_ad1848_pcm +EXPORT_SYMBOL sound/isa/ad1848/snd-ad1848-lib 0xe6314c32 snd_ad1848_add_ctl_elem +EXPORT_SYMBOL sound/isa/ad1848/snd-ad1848-lib 0xf5ce577c snd_ad1848_create +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x15da88ce snd_cs4231_mce_up +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x17987794 snd_cs4231_overrange +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x17b5057f snd_cs4231_create +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x1ba3533d snd_cs4231_info_double +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x27643eb3 snd_cs4231_out +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x310f92cf snd_cs4231_mixer +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x329d8cc9 snd_cs4236_ext_out +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x48780449 snd_cs4236_ext_in +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x5241ebcd snd_cs4231_get_double +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x63b925f7 snd_cs4231_get_single +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x6a60a4cd snd_cs4231_mce_down +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x8798b817 snd_cs4231_in +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x8de38693 snd_cs4231_info_single +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0xbb38a9aa snd_cs4231_interrupt +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0xce3ba68f snd_cs4231_put_double +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0xd4c0df37 snd_cs4231_pcm +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0xd7c0e05f snd_cs4231_chip_id +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0xf29e8c3d snd_cs4231_timer +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0xffc368b5 snd_cs4231_put_single +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4236-lib 0x122160e8 snd_cs4236_create +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4236-lib 0x8bc83b53 snd_cs4236_mixer +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4236-lib 0x977d871c snd_cs4236_pcm +EXPORT_SYMBOL sound/isa/es1688/snd-es1688-lib 0x3f1c94cc snd_es1688_mixer_write +EXPORT_SYMBOL sound/isa/es1688/snd-es1688-lib 0xa5a346d1 snd_es1688_create +EXPORT_SYMBOL sound/isa/es1688/snd-es1688-lib 0xc27ee2c4 snd_es1688_pcm +EXPORT_SYMBOL sound/isa/es1688/snd-es1688-lib 0xe66f2765 snd_es1688_mixer +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x01f26764 snd_gf1_alloc_voice +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x1005d2d9 snd_gus_dram_write +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x1ea2d386 snd_gf1_i_look8 +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x35629b4e snd_gf1_new_mixer +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x3c54e516 snd_gus_use_dec +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x3d3552c2 snd_gf1_peek +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x46db8d67 snd_gf1_lvol_to_gvol_raw +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x4f910245 snd_gf1_i_look16 +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x5729c8e5 snd_gf1_pcm_new +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x5ce246e3 snd_gus_create +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x5fb89cf8 snd_gf1_write16 +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x6efd29b0 snd_gf1_stop_voice +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x71b17310 snd_gf1_free_voice +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x76a707d8 snd_gus_initialize +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x76c904da snd_gf1_delay +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x78ea46e8 snd_gf1_write8 +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x7d0d4275 snd_gf1_translate_freq +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x7eca1990 snd_gf1_look8 +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x84128954 snd_gus_use_inc +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x84e31382 snd_gf1_look16 +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x9e2cc526 snd_gf1_ctrl_stop +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xa17eb5ae snd_gus_dram_read +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xae9bd741 snd_gf1_dram_addr +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xc1a3e9a5 snd_gf1_write_addr +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xc31af61d snd_gf1_mem_alloc +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xc43a5527 snd_gf1_atten_table +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xd76982b3 snd_gf1_i_write8 +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xd85053ba snd_gf1_mem_free +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xdb252880 snd_gf1_mem_xfree +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xeaa13001 snd_gf1_rawmidi_new +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xeca2dd3e snd_gf1_mem_lock +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xf6ff6492 snd_gf1_poke +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xf963a997 snd_gus_interrupt +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x1b099e1e snd_sbdsp_create +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x5e9584ef snd_sbmixer_resume +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x7e1d536d snd_sbmixer_read +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x8ebd315b snd_sbdsp_get_byte +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x90d51b0d snd_sbdsp_command +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xab636c19 snd_sbdsp_reset +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xb8a14976 snd_sbmixer_suspend +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xcf461714 snd_sbmixer_write +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xd53c1aac snd_sbmixer_add_ctl +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xfed5c4d0 snd_sbmixer_new +EXPORT_SYMBOL sound/isa/sb/snd-sb16-csp 0x280ce347 snd_sb_csp_new +EXPORT_SYMBOL sound/isa/sb/snd-sb16-dsp 0x0ba4ef1d snd_sb16dsp_interrupt +EXPORT_SYMBOL sound/isa/sb/snd-sb16-dsp 0x48c63077 snd_sb16dsp_pcm +EXPORT_SYMBOL sound/isa/sb/snd-sb16-dsp 0xd612d7cc snd_sb16dsp_configure +EXPORT_SYMBOL sound/isa/sb/snd-sb16-dsp 0xd6540bef snd_sb16dsp_get_pcm_ops +EXPORT_SYMBOL sound/isa/sb/snd-sb8-dsp 0x2241f64f snd_sb8dsp_midi +EXPORT_SYMBOL sound/isa/sb/snd-sb8-dsp 0x2d0eddec snd_sb8dsp_midi_interrupt +EXPORT_SYMBOL sound/isa/sb/snd-sb8-dsp 0xd04481d3 snd_sb8dsp_interrupt +EXPORT_SYMBOL sound/isa/sb/snd-sb8-dsp 0xd88bd334 snd_sb8dsp_pcm +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0x278ad9c1 snd_emu8000_poke_dw +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0x5622115e snd_emu8000_update_chorus_mode +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0x56ea03a4 snd_emu8000_dma_chan +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0x588f1420 snd_emu8000_load_reverb_fx +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0x67d16391 snd_emu8000_load_chorus_fx +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0x78b922a4 snd_emu8000_poke +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0xa85fa7ca snd_emu8000_peek_dw +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0xb71687ea snd_emu8000_update_equalizer +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0xd3f5c3af snd_emu8000_update_reverb_mode +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0xf8de0f7c snd_emu8000_init_fm +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0xfc53f61c snd_emu8000_peek +EXPORT_SYMBOL sound/oss/ad1848 0x141c5232 attach_ms_sound +EXPORT_SYMBOL sound/oss/ad1848 0x57f2b9e0 ad1848_detect +EXPORT_SYMBOL sound/oss/ad1848 0x8d660e70 probe_ms_sound +EXPORT_SYMBOL sound/oss/ad1848 0x98c80280 ad1848_init +EXPORT_SYMBOL sound/oss/ad1848 0x9bf1cc62 ad1848_unload +EXPORT_SYMBOL sound/oss/ad1848 0xb29a9148 unload_ms_sound +EXPORT_SYMBOL sound/oss/ad1848 0xc04f6f67 ad1848_control +EXPORT_SYMBOL sound/oss/mpu401 0x5febf284 unload_mpu401 +EXPORT_SYMBOL sound/oss/mpu401 0x813a35f5 probe_mpu401 +EXPORT_SYMBOL sound/oss/mpu401 0xfdff2b3d attach_mpu401 +EXPORT_SYMBOL sound/oss/msnd 0x1186f48f msnd_fifo_read +EXPORT_SYMBOL sound/oss/msnd 0x340a3ddf msnd_init_queue +EXPORT_SYMBOL sound/oss/msnd 0x3867b382 msnd_send_dsp_cmd +EXPORT_SYMBOL sound/oss/msnd 0x54230dc1 msnd_fifo_write +EXPORT_SYMBOL sound/oss/msnd 0x6601493b msnd_fifo_make_empty +EXPORT_SYMBOL sound/oss/msnd 0x8192a440 msnd_register +EXPORT_SYMBOL sound/oss/msnd 0x92098b5b msnd_send_word +EXPORT_SYMBOL sound/oss/msnd 0x9274d677 msnd_fifo_free +EXPORT_SYMBOL sound/oss/msnd 0x986ccb79 msnd_unregister +EXPORT_SYMBOL sound/oss/msnd 0xa0075e9f msnd_enable_irq +EXPORT_SYMBOL sound/oss/msnd 0xade99e25 msnd_fifo_alloc +EXPORT_SYMBOL sound/oss/msnd 0xb3520772 msnd_fifo_init +EXPORT_SYMBOL sound/oss/msnd 0xb46680d3 msnd_upload_host +EXPORT_SYMBOL sound/oss/msnd 0xc266c2da msnd_disable_irq +EXPORT_SYMBOL sound/oss/msnd 0xdf0f59eb msnd_fifo_write_io +EXPORT_SYMBOL sound/oss/msnd 0xf4c4f662 msnd_fifo_read_io +EXPORT_SYMBOL sound/oss/sb_lib 0x1766c866 sb_dsp_init +EXPORT_SYMBOL sound/oss/sb_lib 0x42424109 sb_be_quiet +EXPORT_SYMBOL sound/oss/sb_lib 0x450f9aea smw_free +EXPORT_SYMBOL sound/oss/sb_lib 0x74afd69c unload_sbmpu +EXPORT_SYMBOL sound/oss/sb_lib 0xc4884969 sb_dsp_unload +EXPORT_SYMBOL sound/oss/sb_lib 0xd8a2731c sb_dsp_detect +EXPORT_SYMBOL sound/oss/sb_lib 0xf3de55c6 probe_sbmpu +EXPORT_SYMBOL sound/oss/sound 0x04c87ec8 compute_finetune +EXPORT_SYMBOL sound/oss/sound 0x06339815 sound_unload_synthdev +EXPORT_SYMBOL sound/oss/sound 0x0f280035 conf_printf +EXPORT_SYMBOL sound/oss/sound 0x17ba231d seq_input_event +EXPORT_SYMBOL sound/oss/sound 0x1b3df3cf sound_alloc_mixerdev +EXPORT_SYMBOL sound/oss/sound 0x1d9983ad mixer_devs +EXPORT_SYMBOL sound/oss/sound 0x1f395686 MIDIbuf_avail +EXPORT_SYMBOL sound/oss/sound 0x2161d5e8 sound_timer_init +EXPORT_SYMBOL sound/oss/sound 0x2aa31695 midi_synth_kill_note +EXPORT_SYMBOL sound/oss/sound 0x394cb088 sound_free_dma +EXPORT_SYMBOL sound/oss/sound 0x3eaa2363 synth_devs +EXPORT_SYMBOL sound/oss/sound 0x418f5fbe sound_close_dma +EXPORT_SYMBOL sound/oss/sound 0x4b5abadd sound_install_audiodrv +EXPORT_SYMBOL sound/oss/sound 0x4cd01bdd num_audiodevs +EXPORT_SYMBOL sound/oss/sound 0x4ff47e9d midi_synth_setup_voice +EXPORT_SYMBOL sound/oss/sound 0x51e354b2 sound_alloc_timerdev +EXPORT_SYMBOL sound/oss/sound 0x56504ca2 midi_synth_reset +EXPORT_SYMBOL sound/oss/sound 0x5d986fc9 note_to_freq +EXPORT_SYMBOL sound/oss/sound 0x64aa07e5 midi_devs +EXPORT_SYMBOL sound/oss/sound 0x7679ee76 seq_copy_to_input +EXPORT_SYMBOL sound/oss/sound 0x7bdf0907 conf_printf2 +EXPORT_SYMBOL sound/oss/sound 0x892093e0 midi_synth_controller +EXPORT_SYMBOL sound/oss/sound 0x90bd9714 sequencer_timer +EXPORT_SYMBOL sound/oss/sound 0x917d3554 sound_install_mixer +EXPORT_SYMBOL sound/oss/sound 0x987bcf12 DMAbuf_outputintr +EXPORT_SYMBOL sound/oss/sound 0x9a95733f sound_alloc_dma +EXPORT_SYMBOL sound/oss/sound 0x9bdaf24d midi_synth_start_note +EXPORT_SYMBOL sound/oss/sound 0x9d845b18 num_mixers +EXPORT_SYMBOL sound/oss/sound 0xa1d5f04f load_mixer_volumes +EXPORT_SYMBOL sound/oss/sound 0xa1eae7cf num_midis +EXPORT_SYMBOL sound/oss/sound 0xa41ead5f sound_unload_timerdev +EXPORT_SYMBOL sound/oss/sound 0xa51c913b sound_unload_mixerdev +EXPORT_SYMBOL sound/oss/sound 0xa6bb414c sound_unload_mididev +EXPORT_SYMBOL sound/oss/sound 0xa948751e sound_unload_audiodev +EXPORT_SYMBOL sound/oss/sound 0xad45df73 midi_synth_close +EXPORT_SYMBOL sound/oss/sound 0xaef743b2 midi_synth_ioctl +EXPORT_SYMBOL sound/oss/sound 0xb14b22cd midi_synth_hw_control +EXPORT_SYMBOL sound/oss/sound 0xb4bbc2aa audio_devs +EXPORT_SYMBOL sound/oss/sound 0xb51587f6 do_midi_msg +EXPORT_SYMBOL sound/oss/sound 0xba413f87 sound_alloc_mididev +EXPORT_SYMBOL sound/oss/sound 0xba7dd041 midi_synth_bender +EXPORT_SYMBOL sound/oss/sound 0xc748d109 sound_alloc_synthdev +EXPORT_SYMBOL sound/oss/sound 0xcc4b8797 sound_open_dma +EXPORT_SYMBOL sound/oss/sound 0xd85be938 midi_synth_set_instr +EXPORT_SYMBOL sound/oss/sound 0xdb400afa midi_synth_panning +EXPORT_SYMBOL sound/oss/sound 0xe056b71c DMAbuf_start_dma +EXPORT_SYMBOL sound/oss/sound 0xe2675a79 sound_timer_interrupt +EXPORT_SYMBOL sound/oss/sound 0xeb315d99 DMAbuf_inputintr +EXPORT_SYMBOL sound/oss/sound 0xf1ea8a20 midi_synth_aftertouch +EXPORT_SYMBOL sound/oss/sound 0xf6b3a2fb midi_synth_open +EXPORT_SYMBOL sound/oss/sound 0xf6de2f33 sound_timer_devs +EXPORT_SYMBOL sound/oss/sound 0xf7426da3 midi_synth_load_patch +EXPORT_SYMBOL sound/oss/sound 0xf78f6363 sequencer_init +EXPORT_SYMBOL sound/oss/sound 0xfa6871be sound_timer_syncinterval +EXPORT_SYMBOL sound/oss/sound 0xfddcbfb3 midi_synth_send_sysex +EXPORT_SYMBOL sound/oss/uart401 0x3d26869e probe_uart401 +EXPORT_SYMBOL sound/oss/uart401 0x46248c57 uart401intr +EXPORT_SYMBOL sound/oss/uart401 0xecfdd9c9 unload_uart401 +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x0b57933b snd_ac97_bus +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x2c57a6c2 snd_ac97_update_bits +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x36ccdd6d snd_ac97_update +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x5c03b2e7 snd_ac97_get_short_name +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x5dd8df82 snd_ac97_resume +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x631d1ecd snd_ac97_set_rate +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x71283b7e snd_ac97_update_power +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xa7cb209a snd_ac97_pcm_double_rate_rules +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xac929152 snd_ac97_pcm_assign +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xb4377256 snd_ac97_write_cache +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xc071e42e snd_ac97_mixer +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xcbe6b405 snd_ac97_read +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xcc792f88 snd_ac97_suspend +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xe7285bbd snd_ac97_write +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xed2d5544 snd_ac97_pcm_close +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xf93b7e97 snd_ac97_tune_hardware +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xfcc88a79 snd_ac97_pcm_open +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x065fc78e snd_emu10k1_synth_copy_from_user +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x2e806f23 snd_emu10k1_voice_free +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x47d7e80e snd_emu10k1_synth_free +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x674e202d snd_emu10k1_voice_alloc +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x6dc8f74a snd_emu10k1_ptr_write +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x71f1fa03 snd_emu10k1_synth_bzero +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x79492580 snd_emu10k1_memblk_map +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0xcf19ce20 snd_emu10k1_synth_alloc +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0xd4875201 snd_emu10k1_ptr_read +EXPORT_SYMBOL sound/pci/ice1712/snd-ice17xx-ak4xxx 0x66e6be87 snd_ice1712_akm4xxx_build_controls +EXPORT_SYMBOL sound/pci/ice1712/snd-ice17xx-ak4xxx 0x83f1077b snd_ice1712_akm4xxx_init +EXPORT_SYMBOL sound/pci/ice1712/snd-ice17xx-ak4xxx 0xba3c8d63 snd_ice1712_akm4xxx_free +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x157327a4 oxygen_read16 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x477a4400 oxygen_write16_masked +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x585f4435 oxygen_read32 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x5cc1833b oxygen_pci_probe +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x633597ed oxygen_write8 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x682289b3 oxygen_write32 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x6b85a4c1 oxygen_write_ac97_masked +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x7b6ed7d9 oxygen_pci_remove +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x96e51db6 oxygen_read_ac97 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x99574df0 oxygen_read8 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x9d0ba7f2 oxygen_pci_suspend +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xa37add44 oxygen_pci_resume +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xab8f04f9 oxygen_write8_masked +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xc6e9c9df oxygen_write32_masked +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xcd87bf81 oxygen_write16 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xe048ac8d oxygen_write_i2c +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xf741322f oxygen_write_spi +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xf8c3d8da oxygen_write_ac97 +EXPORT_SYMBOL sound/pci/trident/snd-trident 0x8a36b64f snd_trident_alloc_voice +EXPORT_SYMBOL sound/pci/trident/snd-trident 0x97d3b7e5 snd_trident_write_voice_regs +EXPORT_SYMBOL sound/pci/trident/snd-trident 0xa506cd3e snd_trident_stop_voice +EXPORT_SYMBOL sound/pci/trident/snd-trident 0xcdf5a695 snd_trident_free_voice +EXPORT_SYMBOL sound/pci/trident/snd-trident 0xd186a4e5 snd_trident_start_voice +EXPORT_SYMBOL sound/sound_firmware 0x39e3dd23 mod_firmware_load +EXPORT_SYMBOL sound/soundcore 0x5a6588c2 register_sound_special +EXPORT_SYMBOL sound/soundcore 0x7afc9d8a unregister_sound_mixer +EXPORT_SYMBOL sound/soundcore 0x97302233 sound_class +EXPORT_SYMBOL sound/soundcore 0x99c95fa5 unregister_sound_special +EXPORT_SYMBOL sound/soundcore 0x9b779e17 register_sound_dsp +EXPORT_SYMBOL sound/soundcore 0x9fc51213 register_sound_special_device +EXPORT_SYMBOL sound/soundcore 0xcd083b10 unregister_sound_dsp +EXPORT_SYMBOL sound/soundcore 0xee0af731 register_sound_midi +EXPORT_SYMBOL sound/soundcore 0xf2e41ae4 register_sound_mixer +EXPORT_SYMBOL sound/soundcore 0xfdab6de3 unregister_sound_midi +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x1d2aeaeb snd_emux_terminate_all +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x31d45f25 snd_emux_lock_voice +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x655cb202 snd_sf_linear_to_log +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x73246c23 snd_emux_register +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x88a6f559 snd_emux_new +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x89d1c337 snd_emux_free +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0xfa3278d4 snd_emux_unlock_voice +EXPORT_SYMBOL sound/synth/snd-util-mem 0x20d65978 snd_util_memhdr_free +EXPORT_SYMBOL sound/synth/snd-util-mem 0x24886293 __snd_util_mem_alloc +EXPORT_SYMBOL sound/synth/snd-util-mem 0x569d614e snd_util_mem_free +EXPORT_SYMBOL sound/synth/snd-util-mem 0x7a007343 snd_util_memhdr_new +EXPORT_SYMBOL sound/synth/snd-util-mem 0xd197c5db __snd_util_memblk_new +EXPORT_SYMBOL sound/synth/snd-util-mem 0xd34b56e4 __snd_util_mem_free +EXPORT_SYMBOL sound/synth/snd-util-mem 0xd8b55e81 snd_util_mem_alloc +EXPORT_SYMBOL sound/synth/snd-util-mem 0xf158252c snd_util_mem_avail +EXPORT_SYMBOL sound/usb/snd-usb-lib 0x16756dc0 snd_usbmidi_input_start +EXPORT_SYMBOL sound/usb/snd-usb-lib 0x57f46070 snd_usb_create_midi_interface +EXPORT_SYMBOL sound/usb/snd-usb-lib 0x63343b1d snd_usbmidi_input_stop +EXPORT_SYMBOL sound/usb/snd-usb-lib 0xd9d2bb03 snd_usbmidi_disconnect +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0x5f50285c dm_mem_cache_alloc +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0x73ef45b9 dm_mem_cache_client_destroy +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0x9dc183b8 dm_mem_cache_grow +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0xb448fb14 dm_mem_cache_shrink +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0xbdb53a25 dm_mem_cache_free +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0xe352d5af dm_mem_cache_client_create +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-message 0x920a7a41 dm_message_parse +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x0329d132 rh_sector_to_region +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x108f2649 rh_dec +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x275fdd04 rh_recovery_start +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x48b0d82d rh_delay +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x48eeac98 rh_bio_to_region +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x5c2a0632 rh_recovery_end +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x62842029 rh_flush +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x6e9cb57c rh_init +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x8252ef05 rh_state +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x8821f9a7 rh_region_to_sector +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xa4a7321f rh_get_region_key +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xa923d788 rh_start_recovery +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xac274ed3 rh_stop_recovery +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xb513be98 rh_update_states +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xb79a51c3 rh_inc_pending +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xbb748327 rh_reg_set_context +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xc4fdf256 rh_recovery_prepare +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xc4ff7745 rh_reg_get_context +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xc57bafec rh_exit +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xd7a2d8b8 rh_delay_by_region +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xd99f0978 rh_inc +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xda581f7b rh_get_region_size +EXPORT_SYMBOL ubuntu/lirc/lirc_cmdir/commandir 0x29c887a9 set_tx_channels +EXPORT_SYMBOL ubuntu/lirc/lirc_cmdir/commandir 0x60b2e316 cmdir_read +EXPORT_SYMBOL ubuntu/lirc/lirc_cmdir/commandir 0x7789312a cmdir_write +EXPORT_SYMBOL ubuntu/lirc/lirc_dev/lirc_dev 0xac75542f lirc_get_pdata +EXPORT_SYMBOL ubuntu/lirc/lirc_dev/lirc_dev 0xe96379eb lirc_unregister_plugin +EXPORT_SYMBOL ubuntu/lirc/lirc_dev/lirc_dev 0xf3d17c88 lirc_register_plugin +EXPORT_SYMBOL ubuntu/misc/media/ov511/ov511 0x7db9be3c ov511_deregister_decomp_module +EXPORT_SYMBOL ubuntu/misc/media/ov511/ov511 0xe18cfb08 ov511_register_decomp_module +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x54a6d4d2 p80211_resume +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x5f9d362b wlan_setup +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x648595fc p80211wext_event_associated +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x6af9c9f2 register_wlandev +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x6fa50500 wlan_unsetup +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x76e3c42d p80211netdev_rx +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x9896f3de p80211_suspend +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x9d1a723d p80211skb_rxmeta_attach +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xa90d4475 unregister_wlandev +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xab7478de p80211skb_free +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xb0af0799 wlan_wext_write +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xb8b5dd89 p80211_allow_ioctls +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xd4417baa p80211netdev_hwremoved +EXPORT_SYMBOL vmlinux 0x00112f51 groups_alloc +EXPORT_SYMBOL vmlinux 0x00234e6e write_cache_pages +EXPORT_SYMBOL vmlinux 0x00282cb7 sock_create_kern +EXPORT_SYMBOL vmlinux 0x0034a511 __kill_fasync +EXPORT_SYMBOL vmlinux 0x004c2754 netdev_set_master +EXPORT_SYMBOL vmlinux 0x005ab538 arp_send +EXPORT_SYMBOL vmlinux 0x00701c0f put_io_context +EXPORT_SYMBOL vmlinux 0x00801678 flush_scheduled_work +EXPORT_SYMBOL vmlinux 0x0080fcd6 tcf_hash_release +EXPORT_SYMBOL vmlinux 0x0085b6e4 vfs_readv +EXPORT_SYMBOL vmlinux 0x009d258f _write_lock +EXPORT_SYMBOL vmlinux 0x00c1b0f3 generic_file_aio_write +EXPORT_SYMBOL vmlinux 0x00d184c3 pci_find_device +EXPORT_SYMBOL vmlinux 0x00e8097b csum_partial_copy_fromiovecend +EXPORT_SYMBOL vmlinux 0x01139ffc max_mapnr +EXPORT_SYMBOL vmlinux 0x012e6ebc register_tcf_proto_ops +EXPORT_SYMBOL vmlinux 0x0186d073 percpu_counter_set +EXPORT_SYMBOL vmlinux 0x01902adf netpoll_trap +EXPORT_SYMBOL vmlinux 0x019bb342 tcp_v4_send_check +EXPORT_SYMBOL vmlinux 0x01a4aab6 set_irq_chip_data +EXPORT_SYMBOL vmlinux 0x01bdac97 atm_dev_register +EXPORT_SYMBOL vmlinux 0x01d19038 acpi_enable_subsystem +EXPORT_SYMBOL vmlinux 0x0208eee5 bio_add_pc_page +EXPORT_SYMBOL vmlinux 0x02124474 ip_send_check +EXPORT_SYMBOL vmlinux 0x02138f9d bioset_integrity_create +EXPORT_SYMBOL vmlinux 0x0223d524 xfrm_user_policy +EXPORT_SYMBOL vmlinux 0x02291485 have_submounts +EXPORT_SYMBOL vmlinux 0x0237b57a arch_unregister_cpu +EXPORT_SYMBOL vmlinux 0x02422553 aio_complete +EXPORT_SYMBOL vmlinux 0x02440f6b serio_close +EXPORT_SYMBOL vmlinux 0x025277f6 profile_pc +EXPORT_SYMBOL vmlinux 0x0256389f bit_waitqueue +EXPORT_SYMBOL vmlinux 0x02649054 security_sock_rcv_skb +EXPORT_SYMBOL vmlinux 0x028f4cb5 dev_alloc_skb +EXPORT_SYMBOL vmlinux 0x029444f0 native_read_tsc +EXPORT_SYMBOL vmlinux 0x02a18c74 nf_conntrack_destroy +EXPORT_SYMBOL vmlinux 0x02afcc49 tty_get_baud_rate +EXPORT_SYMBOL vmlinux 0x02aff2f4 acpi_install_gpe_handler +EXPORT_SYMBOL vmlinux 0x02d81845 audit_log_task_context +EXPORT_SYMBOL vmlinux 0x02e84d1b per_cpu__cpu_sibling_map +EXPORT_SYMBOL vmlinux 0x02ee26c1 free_pages_exact +EXPORT_SYMBOL vmlinux 0x02f9b0df inet_listen +EXPORT_SYMBOL vmlinux 0x03092ff7 tcp_proc_register +EXPORT_SYMBOL vmlinux 0x030f4a87 __neigh_event_send +EXPORT_SYMBOL vmlinux 0x0334da4e scsi_command_size_tbl +EXPORT_SYMBOL vmlinux 0x0339bf2e blk_unplug +EXPORT_SYMBOL vmlinux 0x035086dc tc_classify +EXPORT_SYMBOL vmlinux 0x037a0cba kfree +EXPORT_SYMBOL vmlinux 0x039bcc43 bio_get_nr_vecs +EXPORT_SYMBOL vmlinux 0x03a6d915 filemap_fault +EXPORT_SYMBOL vmlinux 0x03a99c3b rb_prev +EXPORT_SYMBOL vmlinux 0x03c06156 bitmap_fold +EXPORT_SYMBOL vmlinux 0x03d77e68 udp_lib_setsockopt +EXPORT_SYMBOL vmlinux 0x03f8897d bio_integrity_prep +EXPORT_SYMBOL vmlinux 0x041fddcf pci_map_rom +EXPORT_SYMBOL vmlinux 0x0422fe4a inet_csk_timer_bug_msg +EXPORT_SYMBOL vmlinux 0x044fbf49 mempool_kzalloc +EXPORT_SYMBOL vmlinux 0x0487f831 fb_find_best_display +EXPORT_SYMBOL vmlinux 0x04b0fca7 page_address +EXPORT_SYMBOL vmlinux 0x04d4af50 inet_dgram_ops +EXPORT_SYMBOL vmlinux 0x04d8c750 release_perfctr_nmi +EXPORT_SYMBOL vmlinux 0x04e278fb rtnl_notify +EXPORT_SYMBOL vmlinux 0x04f3baf0 __skb_recv_datagram +EXPORT_SYMBOL vmlinux 0x051c6d2c pci_reenable_device +EXPORT_SYMBOL vmlinux 0x053e1d51 dquot_transfer +EXPORT_SYMBOL vmlinux 0x05486799 fifo_set_limit +EXPORT_SYMBOL vmlinux 0x0549dcea __brelse +EXPORT_SYMBOL vmlinux 0x05571bd8 fb_class +EXPORT_SYMBOL vmlinux 0x0560cdeb xfrm_state_flush +EXPORT_SYMBOL vmlinux 0x057ce975 hex_dump_to_buffer +EXPORT_SYMBOL vmlinux 0x058c75d9 acpi_get_pci_id +EXPORT_SYMBOL vmlinux 0x059c4659 __scm_send +EXPORT_SYMBOL vmlinux 0x059e95cb f_setown +EXPORT_SYMBOL vmlinux 0x05c27f93 nf_ip_checksum +EXPORT_SYMBOL vmlinux 0x05d8158c dentry_unhash +EXPORT_SYMBOL vmlinux 0x05dace84 bio_alloc +EXPORT_SYMBOL vmlinux 0x05f1d7bd bdev_read_only +EXPORT_SYMBOL vmlinux 0x060447b3 blk_get_request +EXPORT_SYMBOL vmlinux 0x061651be strcat +EXPORT_SYMBOL vmlinux 0x0641a02f iget_failed +EXPORT_SYMBOL vmlinux 0x065cc9a0 inet_csk_reset_keepalive_timer +EXPORT_SYMBOL vmlinux 0x065dc249 blk_init_queue +EXPORT_SYMBOL vmlinux 0x0670546a tcp_proc_unregister +EXPORT_SYMBOL vmlinux 0x067d8d35 security_release_secctx +EXPORT_SYMBOL vmlinux 0x06d728b1 tcp_parse_md5sig_option +EXPORT_SYMBOL vmlinux 0x06e962d8 blk_free_tags +EXPORT_SYMBOL vmlinux 0x06f6d6ba blk_execute_rq +EXPORT_SYMBOL vmlinux 0x06fe3b14 default_grn +EXPORT_SYMBOL vmlinux 0x0722f714 acpi_is_video_device +EXPORT_SYMBOL vmlinux 0x0727c4f3 iowrite8 +EXPORT_SYMBOL vmlinux 0x073cf807 clear_inode +EXPORT_SYMBOL vmlinux 0x073dfa12 generate_resume_trace +EXPORT_SYMBOL vmlinux 0x07467b5d sock_kmalloc +EXPORT_SYMBOL vmlinux 0x075705be tcp_v4_do_rcv +EXPORT_SYMBOL vmlinux 0x07608604 acpi_get_vendor_resource +EXPORT_SYMBOL vmlinux 0x07819b9c simple_transaction_get +EXPORT_SYMBOL vmlinux 0x0799aca4 local_bh_enable +EXPORT_SYMBOL vmlinux 0x079cd7f1 ns_to_timeval +EXPORT_SYMBOL vmlinux 0x07a890c8 fb_alloc_cmap +EXPORT_SYMBOL vmlinux 0x07cc4a5d printk_timed_ratelimit +EXPORT_SYMBOL vmlinux 0x07d50a24 csum_partial +EXPORT_SYMBOL vmlinux 0x08067aac __alloc_skb +EXPORT_SYMBOL vmlinux 0x082c3213 pci_root_buses +EXPORT_SYMBOL vmlinux 0x0847b7d7 dev_get_by_index +EXPORT_SYMBOL vmlinux 0x088947ce llc_sap_find +EXPORT_SYMBOL vmlinux 0x088e1762 blk_queue_bounce +EXPORT_SYMBOL vmlinux 0x08cda8c5 serio_rescan +EXPORT_SYMBOL vmlinux 0x08de0f33 ht_create_irq +EXPORT_SYMBOL vmlinux 0x09052c0c kset_unregister +EXPORT_SYMBOL vmlinux 0x0923be9b vfs_get_dqinfo +EXPORT_SYMBOL vmlinux 0x0933aae1 efi_enabled +EXPORT_SYMBOL vmlinux 0x093e947e posix_acl_create_masq +EXPORT_SYMBOL vmlinux 0x0948cde9 num_physpages +EXPORT_SYMBOL vmlinux 0x09775cdc kref_get +EXPORT_SYMBOL vmlinux 0x09833207 dma_async_memcpy_buf_to_buf +EXPORT_SYMBOL vmlinux 0x098b71c6 fb_dealloc_cmap +EXPORT_SYMBOL vmlinux 0x09a08458 vfs_readdir +EXPORT_SYMBOL vmlinux 0x09c55cec schedule_timeout_interruptible +EXPORT_SYMBOL vmlinux 0x09c9b5ef bio_integrity_enabled +EXPORT_SYMBOL vmlinux 0x09d44df9 in_lock_functions +EXPORT_SYMBOL vmlinux 0x09fd8805 udp_disconnect +EXPORT_SYMBOL vmlinux 0x09fe94d6 pci_release_region +EXPORT_SYMBOL vmlinux 0x0a06cde4 thermal_zone_bind_cooling_device +EXPORT_SYMBOL vmlinux 0x0a2487e0 unblock_all_signals +EXPORT_SYMBOL vmlinux 0x0a3131f6 strnchr +EXPORT_SYMBOL vmlinux 0x0a5add84 tcf_destroy_chain +EXPORT_SYMBOL vmlinux 0x0a642c78 vfs_read +EXPORT_SYMBOL vmlinux 0x0abc91cb sync_page_range +EXPORT_SYMBOL vmlinux 0x0acb1a3c __bitmap_shift_right +EXPORT_SYMBOL vmlinux 0x0b1beb31 vmalloc_32_user +EXPORT_SYMBOL vmlinux 0x0b3fbda8 sk_stream_kill_queues +EXPORT_SYMBOL vmlinux 0x0b4e568a tcp_enter_memory_pressure +EXPORT_SYMBOL vmlinux 0x0b6e326b destroy_EII_client +EXPORT_SYMBOL vmlinux 0x0b742fd7 simple_strtol +EXPORT_SYMBOL vmlinux 0x0bf84415 acpi_lock_ac_dir +EXPORT_SYMBOL vmlinux 0x0c4a6c14 scsi_cmd_ioctl +EXPORT_SYMBOL vmlinux 0x0c5c69e3 flow_cache_lookup +EXPORT_SYMBOL vmlinux 0x0c5ef91b per_cpu__vm_event_states +EXPORT_SYMBOL vmlinux 0x0c87c756 bio_split_pool +EXPORT_SYMBOL vmlinux 0x0cdc812f bdi_init +EXPORT_SYMBOL vmlinux 0x0ce00444 copy_strings_kernel +EXPORT_SYMBOL vmlinux 0x0d0d7b5e acpi_get_physical_pci_device +EXPORT_SYMBOL vmlinux 0x0d192157 nla_put +EXPORT_SYMBOL vmlinux 0x0d26a76d _write_lock_irq +EXPORT_SYMBOL vmlinux 0x0d3dda14 acpi_get_type +EXPORT_SYMBOL vmlinux 0x0d4b77b7 gen_pool_add +EXPORT_SYMBOL vmlinux 0x0d4c03b5 blk_queue_segment_boundary +EXPORT_SYMBOL vmlinux 0x0d542439 __ipv6_addr_type +EXPORT_SYMBOL vmlinux 0x0d6c963c copy_from_user +EXPORT_SYMBOL vmlinux 0x0d77f518 uart_remove_one_port +EXPORT_SYMBOL vmlinux 0x0d8ab500 param_set_copystring +EXPORT_SYMBOL vmlinux 0x0da10ec3 security_sock_graft +EXPORT_SYMBOL vmlinux 0x0da2c3d5 skb_free_datagram +EXPORT_SYMBOL vmlinux 0x0dadfdda I_BDEV +EXPORT_SYMBOL vmlinux 0x0dbd134b sock_i_uid +EXPORT_SYMBOL vmlinux 0x0dc8c344 unlock_buffer +EXPORT_SYMBOL vmlinux 0x0e093a55 nf_log_register +EXPORT_SYMBOL vmlinux 0x0e190607 pci_dev_put +EXPORT_SYMBOL vmlinux 0x0e52592a panic +EXPORT_SYMBOL vmlinux 0x0e6013c6 inet_twsk_deschedule +EXPORT_SYMBOL vmlinux 0x0e762d6e request_module +EXPORT_SYMBOL vmlinux 0x0e88d1bc thaw_bdev +EXPORT_SYMBOL vmlinux 0x0e9b0240 per_cpu__kstat +EXPORT_SYMBOL vmlinux 0x0eab2da6 ps2_command +EXPORT_SYMBOL vmlinux 0x0faef0ed __tasklet_schedule +EXPORT_SYMBOL vmlinux 0x0fb7000f bio_alloc_bioset +EXPORT_SYMBOL vmlinux 0x0fcb60d1 inode_permission +EXPORT_SYMBOL vmlinux 0x0fd00a68 acpi_clear_event +EXPORT_SYMBOL vmlinux 0x0ff386d1 blk_rq_map_integrity_sg +EXPORT_SYMBOL vmlinux 0x0ffbb282 tcp_connect +EXPORT_SYMBOL vmlinux 0x1001b549 dmam_release_declared_memory +EXPORT_SYMBOL vmlinux 0x10101525 blk_requeue_request +EXPORT_SYMBOL vmlinux 0x1055a579 fget +EXPORT_SYMBOL vmlinux 0x105e2ba0 path_get +EXPORT_SYMBOL vmlinux 0x10a24c0f fd_install +EXPORT_SYMBOL vmlinux 0x10aff556 page_follow_link_light +EXPORT_SYMBOL vmlinux 0x10b064b1 pcim_iounmap +EXPORT_SYMBOL vmlinux 0x10b51c97 unregister_sysctl_table +EXPORT_SYMBOL vmlinux 0x10b5614e xfrm_policy_destroy +EXPORT_SYMBOL vmlinux 0x10ee20bb default_blu +EXPORT_SYMBOL vmlinux 0x1136f558 xfrm_policy_alloc +EXPORT_SYMBOL vmlinux 0x1163f0a7 blk_max_low_pfn +EXPORT_SYMBOL vmlinux 0x117093be qdisc_class_hash_init +EXPORT_SYMBOL vmlinux 0x11743d91 __find_get_block +EXPORT_SYMBOL vmlinux 0x118f01ea putname +EXPORT_SYMBOL vmlinux 0x1195bb93 blk_get_backing_dev_info +EXPORT_SYMBOL vmlinux 0x11a18b14 __wake_up_bit +EXPORT_SYMBOL vmlinux 0x11f90d0d skb_put +EXPORT_SYMBOL vmlinux 0x1204820d ip_dev_find +EXPORT_SYMBOL vmlinux 0x120507ac idr_get_new +EXPORT_SYMBOL vmlinux 0x124ae478 __set_page_dirty_buffers +EXPORT_SYMBOL vmlinux 0x125fbca7 cad_pid +EXPORT_SYMBOL vmlinux 0x126970ed param_set_uint +EXPORT_SYMBOL vmlinux 0x12af5135 udp_proc_register +EXPORT_SYMBOL vmlinux 0x12c43ab4 generic_setlease +EXPORT_SYMBOL vmlinux 0x12da5bb2 __kmalloc +EXPORT_SYMBOL vmlinux 0x12db0093 tcp_prot +EXPORT_SYMBOL vmlinux 0x12f99022 inet_frags_init_net +EXPORT_SYMBOL vmlinux 0x1308e295 sync_dirty_buffer +EXPORT_SYMBOL vmlinux 0x1326a925 bio_integrity_clone +EXPORT_SYMBOL vmlinux 0x132f45f2 cookie_check_timestamp +EXPORT_SYMBOL vmlinux 0x133ba317 generic_osync_inode +EXPORT_SYMBOL vmlinux 0x1378e714 acpi_video_display_switch_support +EXPORT_SYMBOL vmlinux 0x137e2447 blk_integrity_compare +EXPORT_SYMBOL vmlinux 0x13878eeb __fatal_signal_pending +EXPORT_SYMBOL vmlinux 0x138e1014 find_task_by_pid_ns +EXPORT_SYMBOL vmlinux 0x1394f77d kunmap_high +EXPORT_SYMBOL vmlinux 0x13f71731 tcf_hash_lookup +EXPORT_SYMBOL vmlinux 0x1430e6e0 unregister_acpi_notifier +EXPORT_SYMBOL vmlinux 0x14ad2e23 filemap_fdatawrite +EXPORT_SYMBOL vmlinux 0x14af0cf7 gen_pool_destroy +EXPORT_SYMBOL vmlinux 0x14d93f2c ioctl_by_bdev +EXPORT_SYMBOL vmlinux 0x14e29ad0 proc_dointvec_jiffies +EXPORT_SYMBOL vmlinux 0x14f332ea up_read +EXPORT_SYMBOL vmlinux 0x1544aad4 genl_register_mc_group +EXPORT_SYMBOL vmlinux 0x1551dc51 bitmap_find_free_region +EXPORT_SYMBOL vmlinux 0x1577b414 inet_csk_accept +EXPORT_SYMBOL vmlinux 0x15acaa26 generic_listxattr +EXPORT_SYMBOL vmlinux 0x15d90577 tcp_setsockopt +EXPORT_SYMBOL vmlinux 0x15e163f0 clear_page_dirty_for_io +EXPORT_SYMBOL vmlinux 0x15ef2dd9 kfifo_free +EXPORT_SYMBOL vmlinux 0x15f2d0bf con_is_bound +EXPORT_SYMBOL vmlinux 0x160472ba task_pid_nr_ns +EXPORT_SYMBOL vmlinux 0x162e99dc posix_test_lock +EXPORT_SYMBOL vmlinux 0x1631a87c give_up_console +EXPORT_SYMBOL vmlinux 0x16370081 tcp_close +EXPORT_SYMBOL vmlinux 0x16701ed0 kernel_getsockname +EXPORT_SYMBOL vmlinux 0x167e7f9d __get_user_1 +EXPORT_SYMBOL vmlinux 0x16a35878 _read_unlock +EXPORT_SYMBOL vmlinux 0x170c25ee acpi_get_next_object +EXPORT_SYMBOL vmlinux 0x1710217e ilookup5_nowait +EXPORT_SYMBOL vmlinux 0x172e365f blk_rq_append_bio +EXPORT_SYMBOL vmlinux 0x172ed4d7 __vmalloc +EXPORT_SYMBOL vmlinux 0x173b2697 remove_inode_hash +EXPORT_SYMBOL vmlinux 0x175a298d acpi_set_firmware_waking_vector +EXPORT_SYMBOL vmlinux 0x177c86c5 fib_default_rule_add +EXPORT_SYMBOL vmlinux 0x17a76e71 rb_first +EXPORT_SYMBOL vmlinux 0x17df17bc sysctl_tcp_ecn +EXPORT_SYMBOL vmlinux 0x17e22fcc kmem_cache_name +EXPORT_SYMBOL vmlinux 0x181b6ff2 mempool_resize +EXPORT_SYMBOL vmlinux 0x181d9d6b bh_submit_read +EXPORT_SYMBOL vmlinux 0x183fa88b mempool_alloc_slab +EXPORT_SYMBOL vmlinux 0x18931ce1 request_firmware_nowait +EXPORT_SYMBOL vmlinux 0x189aeda5 mca_register_driver +EXPORT_SYMBOL vmlinux 0x189f6801 dev_load +EXPORT_SYMBOL vmlinux 0x18c891bd register_quota_format +EXPORT_SYMBOL vmlinux 0x18d2a8cf tcp_mtup_init +EXPORT_SYMBOL vmlinux 0x18f7bb03 noop_qdisc +EXPORT_SYMBOL vmlinux 0x19042959 cpu_sysdev_class +EXPORT_SYMBOL vmlinux 0x19098c4f tcp_read_sock +EXPORT_SYMBOL vmlinux 0x191b9299 dput +EXPORT_SYMBOL vmlinux 0x193473e8 unregister_console +EXPORT_SYMBOL vmlinux 0x19405629 ip_xfrm_me_harder +EXPORT_SYMBOL vmlinux 0x194a0459 sysctl_intvec +EXPORT_SYMBOL vmlinux 0x1982bcdb skb_under_panic +EXPORT_SYMBOL vmlinux 0x1985ed3c prepare_to_wait_exclusive +EXPORT_SYMBOL vmlinux 0x198bfcc3 inet_ioctl +EXPORT_SYMBOL vmlinux 0x199d2613 bio_integrity_set_tag +EXPORT_SYMBOL vmlinux 0x199ed0cd net_disable_timestamp +EXPORT_SYMBOL vmlinux 0x19a01ee9 vfs_rmdir +EXPORT_SYMBOL vmlinux 0x19afb86b mca_device_set_claim +EXPORT_SYMBOL vmlinux 0x19b91de2 register_8022_client +EXPORT_SYMBOL vmlinux 0x19d5d20a acpi_walk_namespace +EXPORT_SYMBOL vmlinux 0x19e1faf5 put_page +EXPORT_SYMBOL vmlinux 0x1a137cbf keyring_clear +EXPORT_SYMBOL vmlinux 0x1a1ab15d tty_mutex +EXPORT_SYMBOL vmlinux 0x1a45cb6c acpi_disabled +EXPORT_SYMBOL vmlinux 0x1a743047 pv_mmu_ops +EXPORT_SYMBOL vmlinux 0x1a75caa3 _read_lock +EXPORT_SYMBOL vmlinux 0x1a84fe8a touch_atime +EXPORT_SYMBOL vmlinux 0x1a854228 get_io_context +EXPORT_SYMBOL vmlinux 0x1a8a845e idle_nomwait +EXPORT_SYMBOL vmlinux 0x1a900c84 inode_change_ok +EXPORT_SYMBOL vmlinux 0x1ace138d bitmap_allocate_region +EXPORT_SYMBOL vmlinux 0x1acea4cb xfrm_register_type +EXPORT_SYMBOL vmlinux 0x1ae8d7dc param_set_invbool +EXPORT_SYMBOL vmlinux 0x1aed673b serio_unregister_child_port +EXPORT_SYMBOL vmlinux 0x1aff7cf1 blk_integrity_unregister +EXPORT_SYMBOL vmlinux 0x1b015d25 bitmap_parselist +EXPORT_SYMBOL vmlinux 0x1b3c3c81 xfrm_find_acq +EXPORT_SYMBOL vmlinux 0x1b3c678a gen_new_estimator +EXPORT_SYMBOL vmlinux 0x1b41fbf0 current_fs_time +EXPORT_SYMBOL vmlinux 0x1b6314fd in_aton +EXPORT_SYMBOL vmlinux 0x1b89419f add_wait_queue_exclusive +EXPORT_SYMBOL vmlinux 0x1b958c80 acpi_match_device_ids +EXPORT_SYMBOL vmlinux 0x1b9981cc set_irq_wake +EXPORT_SYMBOL vmlinux 0x1ba27bd4 input_grab_device +EXPORT_SYMBOL vmlinux 0x1bcf83d3 pci_do_scan_bus +EXPORT_SYMBOL vmlinux 0x1be32aaf proc_dointvec_ms_jiffies +EXPORT_SYMBOL vmlinux 0x1bf309ee __mpage_writepage +EXPORT_SYMBOL vmlinux 0x1bf6d545 ethtool_op_set_tx_csum +EXPORT_SYMBOL vmlinux 0x1bfb1c5a skb_append +EXPORT_SYMBOL vmlinux 0x1c202c68 blk_queue_start_tag +EXPORT_SYMBOL vmlinux 0x1c447d8a simple_lookup +EXPORT_SYMBOL vmlinux 0x1c5e5247 blk_queue_softirq_done +EXPORT_SYMBOL vmlinux 0x1c709922 __pagevec_release +EXPORT_SYMBOL vmlinux 0x1c78299a inet_getname +EXPORT_SYMBOL vmlinux 0x1ca69afa ip4_datagram_connect +EXPORT_SYMBOL vmlinux 0x1cae976a xfrm_state_walk +EXPORT_SYMBOL vmlinux 0x1cb85c5a d_add_ci +EXPORT_SYMBOL vmlinux 0x1cbe85cd textsearch_register +EXPORT_SYMBOL vmlinux 0x1cc6719a register_reboot_notifier +EXPORT_SYMBOL vmlinux 0x1cebd39b nf_getsockopt +EXPORT_SYMBOL vmlinux 0x1cecc61e __dev_get_by_name +EXPORT_SYMBOL vmlinux 0x1cefe352 wait_for_completion +EXPORT_SYMBOL vmlinux 0x1cfbc2ef tcp_sendpage +EXPORT_SYMBOL vmlinux 0x1d30b70c rwsem_wake +EXPORT_SYMBOL vmlinux 0x1d507f73 end_buffer_write_sync +EXPORT_SYMBOL vmlinux 0x1d665122 uart_update_timeout +EXPORT_SYMBOL vmlinux 0x1d821eb3 tcp_md5_hash_key +EXPORT_SYMBOL vmlinux 0x1d830520 cpu_possible_map +EXPORT_SYMBOL vmlinux 0x1dc36131 fb_destroy_modedb +EXPORT_SYMBOL vmlinux 0x1dd07bc6 skb_seq_read +EXPORT_SYMBOL vmlinux 0x1dd571e6 fb_copy_cmap +EXPORT_SYMBOL vmlinux 0x1e09ca3b dquot_mark_dquot_dirty +EXPORT_SYMBOL vmlinux 0x1e2b2069 tty_vhangup +EXPORT_SYMBOL vmlinux 0x1e33df0c inode_add_bytes +EXPORT_SYMBOL vmlinux 0x1e40a034 fb_set_cmap +EXPORT_SYMBOL vmlinux 0x1e5498fe page_readlink +EXPORT_SYMBOL vmlinux 0x1e6d26a8 strstr +EXPORT_SYMBOL vmlinux 0x1e8f5aaa mpage_writepage +EXPORT_SYMBOL vmlinux 0x1eaa615f bdi_register +EXPORT_SYMBOL vmlinux 0x1eb922a3 IO_APIC_get_PCI_irq_vector +EXPORT_SYMBOL vmlinux 0x1ee539bc km_state_expired +EXPORT_SYMBOL vmlinux 0x1efe283f __cap_full_set +EXPORT_SYMBOL vmlinux 0x1f2658dc kmalloc_caches +EXPORT_SYMBOL vmlinux 0x1f27d6d7 _write_unlock +EXPORT_SYMBOL vmlinux 0x1f52bf4b netdev_class_remove_file +EXPORT_SYMBOL vmlinux 0x1f6d8965 xfrm_state_check_expire +EXPORT_SYMBOL vmlinux 0x1f7c802b fb_get_buffer_offset +EXPORT_SYMBOL vmlinux 0x1f9cfe83 iomem_resource +EXPORT_SYMBOL vmlinux 0x1fc3de87 nf_log_unregister +EXPORT_SYMBOL vmlinux 0x1fc4ecb4 datagram_poll +EXPORT_SYMBOL vmlinux 0x1fdfb868 blk_queue_max_hw_segments +EXPORT_SYMBOL vmlinux 0x1fdfd58b per_cpu__softnet_data +EXPORT_SYMBOL vmlinux 0x1fe5ede6 per_cpu__irq_stat +EXPORT_SYMBOL vmlinux 0x1fee0061 blk_put_request +EXPORT_SYMBOL vmlinux 0x20000329 simple_strtoul +EXPORT_SYMBOL vmlinux 0x2005e68a acpi_remove_fixed_event_handler +EXPORT_SYMBOL vmlinux 0x201f679c unregister_netdev +EXPORT_SYMBOL vmlinux 0x208739f6 acpi_load_table +EXPORT_SYMBOL vmlinux 0x20a1981c pnp_stop_dev +EXPORT_SYMBOL vmlinux 0x20c8fc33 pci_osc_control_set +EXPORT_SYMBOL vmlinux 0x20c98fe5 inet_frag_find +EXPORT_SYMBOL vmlinux 0x210f73bd d_delete +EXPORT_SYMBOL vmlinux 0x215ebd78 bitrev16 +EXPORT_SYMBOL vmlinux 0x21752d3d sync_blockdev +EXPORT_SYMBOL vmlinux 0x21bd9f7c dma_async_device_unregister +EXPORT_SYMBOL vmlinux 0x21cfa43c locks_init_lock +EXPORT_SYMBOL vmlinux 0x21d9e23c kmem_ptr_validate +EXPORT_SYMBOL vmlinux 0x21e0ea22 acpi_get_id +EXPORT_SYMBOL vmlinux 0x21f1d06c __secpath_destroy +EXPORT_SYMBOL vmlinux 0x2204f305 udp_flush_pending_frames +EXPORT_SYMBOL vmlinux 0x2222f933 xfrm_state_unregister_afinfo +EXPORT_SYMBOL vmlinux 0x2223f2db tcf_em_tree_validate +EXPORT_SYMBOL vmlinux 0x222e7ce2 sysfs_streq +EXPORT_SYMBOL vmlinux 0x226e86a9 audit_log +EXPORT_SYMBOL vmlinux 0x2287367f ps2_cmd_aborted +EXPORT_SYMBOL vmlinux 0x2288378f system_state +EXPORT_SYMBOL vmlinux 0x228c7407 lock_may_read +EXPORT_SYMBOL vmlinux 0x22a73912 __tcp_put_md5sig_pool +EXPORT_SYMBOL vmlinux 0x22b325d5 kd_mksound +EXPORT_SYMBOL vmlinux 0x22b6533b xfrm_sad_getinfo +EXPORT_SYMBOL vmlinux 0x22b97522 blk_queue_dma_alignment +EXPORT_SYMBOL vmlinux 0x22edf522 bdget +EXPORT_SYMBOL vmlinux 0x23031fd8 input_inject_event +EXPORT_SYMBOL vmlinux 0x230c4875 pci_set_dma_max_seg_size +EXPORT_SYMBOL vmlinux 0x2313fc80 unregister_exec_domain +EXPORT_SYMBOL vmlinux 0x231f3a66 __kfifo_put +EXPORT_SYMBOL vmlinux 0x23240e1f seq_path +EXPORT_SYMBOL vmlinux 0x23269a13 strict_strtoul +EXPORT_SYMBOL vmlinux 0x23403b86 xfrm4_rcv_encap +EXPORT_SYMBOL vmlinux 0x2348984e adjust_resource +EXPORT_SYMBOL vmlinux 0x2368be6d posix_acl_to_xattr +EXPORT_SYMBOL vmlinux 0x236c098e tcf_action_exec +EXPORT_SYMBOL vmlinux 0x237ae623 redraw_screen +EXPORT_SYMBOL vmlinux 0x23a7a3bd maps_protect +EXPORT_SYMBOL vmlinux 0x23ad070a set_current_groups +EXPORT_SYMBOL vmlinux 0x23e8a364 sk_stream_write_space +EXPORT_SYMBOL vmlinux 0x23f2d36f memparse +EXPORT_SYMBOL vmlinux 0x23f38b58 pnp_unregister_driver +EXPORT_SYMBOL vmlinux 0x23fc8474 clear_bdi_congested +EXPORT_SYMBOL vmlinux 0x23fd3028 vmalloc_node +EXPORT_SYMBOL vmlinux 0x240493eb open_by_devnum +EXPORT_SYMBOL vmlinux 0x243ffddc idr_destroy +EXPORT_SYMBOL vmlinux 0x24428be5 strncpy_from_user +EXPORT_SYMBOL vmlinux 0x244c2670 posix_acl_permission +EXPORT_SYMBOL vmlinux 0x2459bbcc console_set_on_cmdline +EXPORT_SYMBOL vmlinux 0x245f45d4 tcp_v4_connect +EXPORT_SYMBOL vmlinux 0x24c02e61 seq_release_private +EXPORT_SYMBOL vmlinux 0x24c1ef2b acpi_evaluate_integer +EXPORT_SYMBOL vmlinux 0x24c5476f acpi_bus_generate_proc_event +EXPORT_SYMBOL vmlinux 0x24d353ff mpage_bio_submit +EXPORT_SYMBOL vmlinux 0x24fdac79 wake_bit_function +EXPORT_SYMBOL vmlinux 0x250113b4 memory_read_from_buffer +EXPORT_SYMBOL vmlinux 0x25041acd ipv4_specific +EXPORT_SYMBOL vmlinux 0x253d1b6e iput +EXPORT_SYMBOL vmlinux 0x2566948d textsearch_prepare +EXPORT_SYMBOL vmlinux 0x256887e1 warn_slowpath +EXPORT_SYMBOL vmlinux 0x25820c64 fs_overflowuid +EXPORT_SYMBOL vmlinux 0x258355b4 fb_find_best_mode +EXPORT_SYMBOL vmlinux 0x259efa16 pcim_enable_device +EXPORT_SYMBOL vmlinux 0x25c8e7ac security_inode_init_security +EXPORT_SYMBOL vmlinux 0x25d81960 posix_acl_equiv_mode +EXPORT_SYMBOL vmlinux 0x25ecfd7e simple_transaction_release +EXPORT_SYMBOL vmlinux 0x265b5e6c dma_declare_coherent_memory +EXPORT_SYMBOL vmlinux 0x268c0012 create_proc_entry +EXPORT_SYMBOL vmlinux 0x268cc6a2 sys_close +EXPORT_SYMBOL vmlinux 0x2693fac7 unbind_con_driver +EXPORT_SYMBOL vmlinux 0x26972d1a unload_nls +EXPORT_SYMBOL vmlinux 0x26981637 dquot_drop +EXPORT_SYMBOL vmlinux 0x26e76fb8 sysctl_udp_wmem_min +EXPORT_SYMBOL vmlinux 0x272d394e mtrr_del +EXPORT_SYMBOL vmlinux 0x272e7488 cond_resched_softirq +EXPORT_SYMBOL vmlinux 0x2733bfe3 take_over_console +EXPORT_SYMBOL vmlinux 0x273f066e _write_unlock_irq +EXPORT_SYMBOL vmlinux 0x274194c2 bio_integrity_add_page +EXPORT_SYMBOL vmlinux 0x274d7128 pcibios_align_resource +EXPORT_SYMBOL vmlinux 0x277d99db __next_cpu +EXPORT_SYMBOL vmlinux 0x27a9a7eb ns_to_timespec +EXPORT_SYMBOL vmlinux 0x27bbf221 disable_irq_nosync +EXPORT_SYMBOL vmlinux 0x27bf488d tty_set_operations +EXPORT_SYMBOL vmlinux 0x27c61ece qdisc_put_stab +EXPORT_SYMBOL vmlinux 0x27e2de4e mark_buffer_dirty_inode +EXPORT_SYMBOL vmlinux 0x282e607d free_netdev +EXPORT_SYMBOL vmlinux 0x285ac517 strict_strtoll +EXPORT_SYMBOL vmlinux 0x2890c85e tcp_splice_read +EXPORT_SYMBOL vmlinux 0x2893b758 cancel_dirty_page +EXPORT_SYMBOL vmlinux 0x28b715a6 isapnp_cfg_end +EXPORT_SYMBOL vmlinux 0x28dcf25c udplite_hash +EXPORT_SYMBOL vmlinux 0x28e54f13 input_close_device +EXPORT_SYMBOL vmlinux 0x2918ee19 blk_queue_stack_limits +EXPORT_SYMBOL vmlinux 0x2934f33d neigh_sysctl_register +EXPORT_SYMBOL vmlinux 0x29537c9e alloc_chrdev_region +EXPORT_SYMBOL vmlinux 0x29714da1 km_state_notify +EXPORT_SYMBOL vmlinux 0x298254c3 ip_fragment +EXPORT_SYMBOL vmlinux 0x299566bb blk_queue_invalidate_tags +EXPORT_SYMBOL vmlinux 0x29b1c366 __sg_alloc_table +EXPORT_SYMBOL vmlinux 0x29b867fa proc_create_data +EXPORT_SYMBOL vmlinux 0x29bd4c46 __cap_init_eff_set +EXPORT_SYMBOL vmlinux 0x29da7e60 sk_stream_wait_close +EXPORT_SYMBOL vmlinux 0x29f92193 pci_set_power_state +EXPORT_SYMBOL vmlinux 0x2a07ecc8 dev_getbyhwaddr +EXPORT_SYMBOL vmlinux 0x2a10b954 rtnetlink_put_metrics +EXPORT_SYMBOL vmlinux 0x2a12f9d6 cdev_add +EXPORT_SYMBOL vmlinux 0x2a303d4d check_signature +EXPORT_SYMBOL vmlinux 0x2aa0e4fc strncasecmp +EXPORT_SYMBOL vmlinux 0x2ab68ea9 generic_read_dir +EXPORT_SYMBOL vmlinux 0x2ac1e44f tcp_init_xmit_timers +EXPORT_SYMBOL vmlinux 0x2ac4eddf try_to_release_page +EXPORT_SYMBOL vmlinux 0x2ac5114e netlink_rcv_skb +EXPORT_SYMBOL vmlinux 0x2aeb2800 mempool_create_node +EXPORT_SYMBOL vmlinux 0x2b12cb05 security_sk_classify_flow +EXPORT_SYMBOL vmlinux 0x2b2ee9ba tty_chars_in_buffer +EXPORT_SYMBOL vmlinux 0x2b6aac8c tcp_sockets_allocated +EXPORT_SYMBOL vmlinux 0x2b86a602 mca_device_transform_memory +EXPORT_SYMBOL vmlinux 0x2ba707a8 sysctl_tcp_low_latency +EXPORT_SYMBOL vmlinux 0x2bb55d6e acpi_remove_notify_handler +EXPORT_SYMBOL vmlinux 0x2bbada51 check_disk_change +EXPORT_SYMBOL vmlinux 0x2bbb3fb3 send_sig_info +EXPORT_SYMBOL vmlinux 0x2bc95bd4 memset +EXPORT_SYMBOL vmlinux 0x2be09893 _atomic_dec_and_lock +EXPORT_SYMBOL vmlinux 0x2bf0938b uart_get_divisor +EXPORT_SYMBOL vmlinux 0x2bfeb410 acpi_get_handle +EXPORT_SYMBOL vmlinux 0x2c07744d iw_handler_set_spy +EXPORT_SYMBOL vmlinux 0x2c23362e __invalidate_device +EXPORT_SYMBOL vmlinux 0x2c55907f gnet_stats_copy_queue +EXPORT_SYMBOL vmlinux 0x2c5749e6 acpi_clear_gpe +EXPORT_SYMBOL vmlinux 0x2c807a1b arp_find +EXPORT_SYMBOL vmlinux 0x2c89bc37 request_key +EXPORT_SYMBOL vmlinux 0x2c8f5989 acpi_remove_address_space_handler +EXPORT_SYMBOL vmlinux 0x2c9874fe ida_remove +EXPORT_SYMBOL vmlinux 0x2c9e60cc thermal_zone_device_unregister +EXPORT_SYMBOL vmlinux 0x2ca1fcda sock_no_listen +EXPORT_SYMBOL vmlinux 0x2cb66d11 __serio_register_port +EXPORT_SYMBOL vmlinux 0x2cb8225f pagevec_lookup +EXPORT_SYMBOL vmlinux 0x2cb91368 block_sync_page +EXPORT_SYMBOL vmlinux 0x2cc2d52d vcc_hash +EXPORT_SYMBOL vmlinux 0x2cd8947f pci_remove_bus_device +EXPORT_SYMBOL vmlinux 0x2cd9e459 param_set_short +EXPORT_SYMBOL vmlinux 0x2cf190e3 request_irq +EXPORT_SYMBOL vmlinux 0x2cfcb5fe pci_set_dma_seg_boundary +EXPORT_SYMBOL vmlinux 0x2cfedcc3 seq_lseek +EXPORT_SYMBOL vmlinux 0x2d0a985c skb_copy_and_csum_datagram_iovec +EXPORT_SYMBOL vmlinux 0x2d3d9d52 sysctl_data +EXPORT_SYMBOL vmlinux 0x2d60fe79 tcf_action_dump_1 +EXPORT_SYMBOL vmlinux 0x2d6baa8b sock_no_shutdown +EXPORT_SYMBOL vmlinux 0x2dba519f inode_init_once +EXPORT_SYMBOL vmlinux 0x2dd16564 arch_register_cpu +EXPORT_SYMBOL vmlinux 0x2dd4ca94 blk_rq_map_sg +EXPORT_SYMBOL vmlinux 0x2de9f66f param_get_long +EXPORT_SYMBOL vmlinux 0x2dedc4c2 acpi_format_exception +EXPORT_SYMBOL vmlinux 0x2def7f76 rtc_cmos_write +EXPORT_SYMBOL vmlinux 0x2e0c26a5 inode_setattr +EXPORT_SYMBOL vmlinux 0x2e11b9a5 vfs_dq_quota_on_remount +EXPORT_SYMBOL vmlinux 0x2e2cbd79 input_open_device +EXPORT_SYMBOL vmlinux 0x2e2ce9e0 sysctl_tcp_syncookies +EXPORT_SYMBOL vmlinux 0x2e4a39f8 sysctl_udp_mem +EXPORT_SYMBOL vmlinux 0x2e4e5b02 task_nice +EXPORT_SYMBOL vmlinux 0x2e60bace memcpy +EXPORT_SYMBOL vmlinux 0x2e97859f rwsem_downgrade_wake +EXPORT_SYMBOL vmlinux 0x2eb9a0e8 _read_lock_irq +EXPORT_SYMBOL vmlinux 0x2ebbb708 netdev_features_change +EXPORT_SYMBOL vmlinux 0x2eeed6e2 keyring_search +EXPORT_SYMBOL vmlinux 0x2f06861f blk_rq_map_kern +EXPORT_SYMBOL vmlinux 0x2f1d0668 bio_pair_release +EXPORT_SYMBOL vmlinux 0x2f287f0d copy_to_user +EXPORT_SYMBOL vmlinux 0x2f98a90f nobh_truncate_page +EXPORT_SYMBOL vmlinux 0x2f9e3d9a seq_puts +EXPORT_SYMBOL vmlinux 0x2ff7efaa tcf_hash_new_index +EXPORT_SYMBOL vmlinux 0x302c7996 mca_register_driver_integrated +EXPORT_SYMBOL vmlinux 0x3038ede6 generic_fillattr +EXPORT_SYMBOL vmlinux 0x304cdaba get_user_pages +EXPORT_SYMBOL vmlinux 0x304e03ed input_unregister_handler +EXPORT_SYMBOL vmlinux 0x306493ca km_policy_expired +EXPORT_SYMBOL vmlinux 0x30896043 __any_online_cpu +EXPORT_SYMBOL vmlinux 0x309676dd blk_init_tags +EXPORT_SYMBOL vmlinux 0x30b4832d wait_on_sync_kiocb +EXPORT_SYMBOL vmlinux 0x30b782bd end_queued_request +EXPORT_SYMBOL vmlinux 0x30d45405 ioremap_prot +EXPORT_SYMBOL vmlinux 0x30de3b66 kmem_cache_create +EXPORT_SYMBOL vmlinux 0x30e4de72 cap_netlink_recv +EXPORT_SYMBOL vmlinux 0x30e74134 tty_termios_copy_hw +EXPORT_SYMBOL vmlinux 0x310917fe sort +EXPORT_SYMBOL vmlinux 0x3145216f pci_dev_present +EXPORT_SYMBOL vmlinux 0x3147857d default_red +EXPORT_SYMBOL vmlinux 0x316aec71 tty_unthrottle +EXPORT_SYMBOL vmlinux 0x3185851a nf_setsockopt +EXPORT_SYMBOL vmlinux 0x3191f109 __krealloc +EXPORT_SYMBOL vmlinux 0x31bb11e5 follow_up +EXPORT_SYMBOL vmlinux 0x31e76b57 recalibrate_cpu_khz +EXPORT_SYMBOL vmlinux 0x322c6fc2 __check_region +EXPORT_SYMBOL vmlinux 0x324121e1 pnp_unregister_card_driver +EXPORT_SYMBOL vmlinux 0x327ef442 tcp_v4_md5_lookup +EXPORT_SYMBOL vmlinux 0x3297f644 simple_rename +EXPORT_SYMBOL vmlinux 0x32a3fe0b proto_unregister +EXPORT_SYMBOL vmlinux 0x32aecef7 call_usermodehelper_setup +EXPORT_SYMBOL vmlinux 0x32c07bf0 blk_plug_device_unlocked +EXPORT_SYMBOL vmlinux 0x32c9f6a9 shrink_dcache_parent +EXPORT_SYMBOL vmlinux 0x32d01fec acpi_attach_data +EXPORT_SYMBOL vmlinux 0x3360a963 param_set_ulong +EXPORT_SYMBOL vmlinux 0x3367d7ae isapnp_protocol +EXPORT_SYMBOL vmlinux 0x3385c8cb per_cpu__this_cpu_off +EXPORT_SYMBOL vmlinux 0x33d92f9a prepare_to_wait +EXPORT_SYMBOL vmlinux 0x33df8ae9 sk_stream_wait_connect +EXPORT_SYMBOL vmlinux 0x3421272c efi +EXPORT_SYMBOL vmlinux 0x342f60fe apm_info +EXPORT_SYMBOL vmlinux 0x3435df2f neigh_for_each +EXPORT_SYMBOL vmlinux 0x3464bb18 registered_fb +EXPORT_SYMBOL vmlinux 0x34908c14 print_hex_dump_bytes +EXPORT_SYMBOL vmlinux 0x349cba85 strchr +EXPORT_SYMBOL vmlinux 0x34e43fce tcp_poll +EXPORT_SYMBOL vmlinux 0x35387741 netdev_bonding_change +EXPORT_SYMBOL vmlinux 0x35645500 blk_queue_resize_tags +EXPORT_SYMBOL vmlinux 0x35959b13 proto_register +EXPORT_SYMBOL vmlinux 0x35c2ba9e refrigerator +EXPORT_SYMBOL vmlinux 0x35d34f08 bd_release +EXPORT_SYMBOL vmlinux 0x35f0faa2 acpi_evaluate_object +EXPORT_SYMBOL vmlinux 0x360b1afe probe_irq_mask +EXPORT_SYMBOL vmlinux 0x36304158 neigh_sysctl_unregister +EXPORT_SYMBOL vmlinux 0x363ad247 cap_set_effective +EXPORT_SYMBOL vmlinux 0x3656bf5a lock_kernel +EXPORT_SYMBOL vmlinux 0x3701c9e4 drop_super +EXPORT_SYMBOL vmlinux 0x370bd665 single_open +EXPORT_SYMBOL vmlinux 0x3725ffc5 inet_frag_kill +EXPORT_SYMBOL vmlinux 0x37353f38 proc_doulongvec_ms_jiffies_minmax +EXPORT_SYMBOL vmlinux 0x3744cf36 vmalloc_to_pfn +EXPORT_SYMBOL vmlinux 0x374ed073 scnprintf +EXPORT_SYMBOL vmlinux 0x379d65f5 gen_pool_alloc +EXPORT_SYMBOL vmlinux 0x37affacd pci_get_slot +EXPORT_SYMBOL vmlinux 0x37befc70 jiffies_to_msecs +EXPORT_SYMBOL vmlinux 0x37d4ba2e pci_find_capability +EXPORT_SYMBOL vmlinux 0x37e74642 get_jiffies_64 +EXPORT_SYMBOL vmlinux 0x38178c0b unlock_super +EXPORT_SYMBOL vmlinux 0x38203ca1 __init_rwsem +EXPORT_SYMBOL vmlinux 0x384c76f5 user_revoke +EXPORT_SYMBOL vmlinux 0x3861cf8b pci_enable_bridges +EXPORT_SYMBOL vmlinux 0x387c0967 vfs_lstat +EXPORT_SYMBOL vmlinux 0x3882fe5f user_path_at +EXPORT_SYMBOL vmlinux 0x3892f16d sock_i_ino +EXPORT_SYMBOL vmlinux 0x38b92846 llc_remove_pack +EXPORT_SYMBOL vmlinux 0x38c2767c deactivate_super +EXPORT_SYMBOL vmlinux 0x38d3e1af qdisc_tree_decrease_qlen +EXPORT_SYMBOL vmlinux 0x39090fea ilookup +EXPORT_SYMBOL vmlinux 0x3927cac6 blk_queue_max_phys_segments +EXPORT_SYMBOL vmlinux 0x395d554f block_is_partially_uptodate +EXPORT_SYMBOL vmlinux 0x3967cc0e pci_enable_device_mem +EXPORT_SYMBOL vmlinux 0x3980aac1 unregister_reboot_notifier +EXPORT_SYMBOL vmlinux 0x39c645a2 schedule_delayed_work_on +EXPORT_SYMBOL vmlinux 0x39d13293 dev_queue_xmit +EXPORT_SYMBOL vmlinux 0x39e513cb kill_fasync +EXPORT_SYMBOL vmlinux 0x3a16785b blk_queue_prep_rq +EXPORT_SYMBOL vmlinux 0x3a2204c6 security_netlink_recv +EXPORT_SYMBOL vmlinux 0x3a9b6fb9 blk_unregister_region +EXPORT_SYMBOL vmlinux 0x3aa1dbcf _spin_unlock_bh +EXPORT_SYMBOL vmlinux 0x3ac69b1c seq_escape +EXPORT_SYMBOL vmlinux 0x3af8767c simple_dir_operations +EXPORT_SYMBOL vmlinux 0x3b1884fa __napi_schedule +EXPORT_SYMBOL vmlinux 0x3b2624ca seq_putc +EXPORT_SYMBOL vmlinux 0x3b3016d3 cpufreq_unregister_notifier +EXPORT_SYMBOL vmlinux 0x3b3a4132 skb_truesize_bug +EXPORT_SYMBOL vmlinux 0x3b560fdb blk_queue_ordered +EXPORT_SYMBOL vmlinux 0x3b62a9b0 neigh_seq_start +EXPORT_SYMBOL vmlinux 0x3b673473 pci_assign_resource +EXPORT_SYMBOL vmlinux 0x3b7bcbbb nf_ct_attach +EXPORT_SYMBOL vmlinux 0x3b891442 sock_register +EXPORT_SYMBOL vmlinux 0x3ba07f01 tty_driver_flush_buffer +EXPORT_SYMBOL vmlinux 0x3bb017c6 acpi_bus_get_status +EXPORT_SYMBOL vmlinux 0x3bd1b1f6 msecs_to_jiffies +EXPORT_SYMBOL vmlinux 0x3bfe1d50 sock_init_data +EXPORT_SYMBOL vmlinux 0x3c14a0d4 dev_getfirstbyhwtype +EXPORT_SYMBOL vmlinux 0x3c2c5af5 sprintf +EXPORT_SYMBOL vmlinux 0x3c460ae1 inet_del_protocol +EXPORT_SYMBOL vmlinux 0x3c4be096 blk_remove_plug +EXPORT_SYMBOL vmlinux 0x3c67ef22 grab_cache_page_write_begin +EXPORT_SYMBOL vmlinux 0x3c7227bf complete_all +EXPORT_SYMBOL vmlinux 0x3cb8a495 param_get_string +EXPORT_SYMBOL vmlinux 0x3cc0a3bb xfrm_spd_getinfo +EXPORT_SYMBOL vmlinux 0x3ce4ca6f disable_irq +EXPORT_SYMBOL vmlinux 0x3cf1f863 pnp_device_detach +EXPORT_SYMBOL vmlinux 0x3d0549fb pci_unmap_rom +EXPORT_SYMBOL vmlinux 0x3d0bcf92 set_anon_super +EXPORT_SYMBOL vmlinux 0x3d4eb411 pci_bus_alloc_resource +EXPORT_SYMBOL vmlinux 0x3d51fa5b genl_sock +EXPORT_SYMBOL vmlinux 0x3d774263 __inc_zone_page_state +EXPORT_SYMBOL vmlinux 0x3da171f9 pci_mem_start +EXPORT_SYMBOL vmlinux 0x3da5eb6d kfifo_alloc +EXPORT_SYMBOL vmlinux 0x3db57c80 input_set_keycode +EXPORT_SYMBOL vmlinux 0x3db65a4a mark_buffer_async_write +EXPORT_SYMBOL vmlinux 0x3dea48dd iw_handler_set_thrspy +EXPORT_SYMBOL vmlinux 0x3e1f073d wait_for_completion_timeout +EXPORT_SYMBOL vmlinux 0x3e219de6 try_wait_for_completion +EXPORT_SYMBOL vmlinux 0x3e2ae3a8 acpi_release_global_lock +EXPORT_SYMBOL vmlinux 0x3e371cad d_invalidate +EXPORT_SYMBOL vmlinux 0x3e45e9ff register_inetaddr_notifier +EXPORT_SYMBOL vmlinux 0x3e687e5b mpage_readpage +EXPORT_SYMBOL vmlinux 0x3e7fb5f7 truncate_inode_pages_range +EXPORT_SYMBOL vmlinux 0x3ed63055 zlib_inflateReset +EXPORT_SYMBOL vmlinux 0x3effb732 pci_find_bus +EXPORT_SYMBOL vmlinux 0x3f0546a8 ioread32_rep +EXPORT_SYMBOL vmlinux 0x3f1899f1 up +EXPORT_SYMBOL vmlinux 0x3f20c7b9 sock_no_ioctl +EXPORT_SYMBOL vmlinux 0x3f39b162 up_write +EXPORT_SYMBOL vmlinux 0x3f4547a7 put_unused_fd +EXPORT_SYMBOL vmlinux 0x3f56746a __generic_unplug_device +EXPORT_SYMBOL vmlinux 0x3fb2d1fc ip_getsockopt +EXPORT_SYMBOL vmlinux 0x3fb4e6a7 __pskb_pull_tail +EXPORT_SYMBOL vmlinux 0x3fbcddc3 netdev_compute_features +EXPORT_SYMBOL vmlinux 0x3fbeafa0 cpufreq_gov_performance +EXPORT_SYMBOL vmlinux 0x3ff62317 local_bh_disable +EXPORT_SYMBOL vmlinux 0x40576b02 acpi_get_physical_device +EXPORT_SYMBOL vmlinux 0x4059792f print_hex_dump +EXPORT_SYMBOL vmlinux 0x405c1144 get_seconds +EXPORT_SYMBOL vmlinux 0x405eab03 acpi_bus_unregister_driver +EXPORT_SYMBOL vmlinux 0x406d1842 acpi_bus_register_driver +EXPORT_SYMBOL vmlinux 0x40872ee5 pagecache_write_begin +EXPORT_SYMBOL vmlinux 0x409873e3 tty_termios_baud_rate +EXPORT_SYMBOL vmlinux 0x40c89d46 acpi_get_table_by_index +EXPORT_SYMBOL vmlinux 0x40cb2113 bio_clone +EXPORT_SYMBOL vmlinux 0x4108e69a fb_match_mode +EXPORT_SYMBOL vmlinux 0x41482d8b strndup_user +EXPORT_SYMBOL vmlinux 0x4185cf4b radix_tree_lookup_slot +EXPORT_SYMBOL vmlinux 0x4188d439 neigh_rand_reach_time +EXPORT_SYMBOL vmlinux 0x41a9c68d _spin_trylock_bh +EXPORT_SYMBOL vmlinux 0x41ccc474 security_req_classify_flow +EXPORT_SYMBOL vmlinux 0x41d0a361 alloc_buffer_head +EXPORT_SYMBOL vmlinux 0x41d9acf3 sysctl_jiffies +EXPORT_SYMBOL vmlinux 0x41f7fedb dquot_commit +EXPORT_SYMBOL vmlinux 0x41fcb36f pci_scan_bus_parented +EXPORT_SYMBOL vmlinux 0x41ff56a7 tcf_generic_walker +EXPORT_SYMBOL vmlinux 0x42076d8d arp_broken_ops +EXPORT_SYMBOL vmlinux 0x4211c3c1 zlib_inflateInit2 +EXPORT_SYMBOL vmlinux 0x42224298 sscanf +EXPORT_SYMBOL vmlinux 0x422c05d0 acpi_get_data +EXPORT_SYMBOL vmlinux 0x424325f1 fput +EXPORT_SYMBOL vmlinux 0x4292364c schedule +EXPORT_SYMBOL vmlinux 0x429759cf unregister_con_driver +EXPORT_SYMBOL vmlinux 0x42a0c4cf single_release +EXPORT_SYMBOL vmlinux 0x4302d0eb free_pages +EXPORT_SYMBOL vmlinux 0x43385ad9 acpi_pci_unregister_driver +EXPORT_SYMBOL vmlinux 0x434fa55c release_console_sem +EXPORT_SYMBOL vmlinux 0x4357e0a9 shrink_dcache_sb +EXPORT_SYMBOL vmlinux 0x435b566d _spin_unlock +EXPORT_SYMBOL vmlinux 0x436c2179 iowrite32 +EXPORT_SYMBOL vmlinux 0x43b19adb ip_mc_dec_group +EXPORT_SYMBOL vmlinux 0x43b40de7 kunmap_atomic +EXPORT_SYMBOL vmlinux 0x44161c19 unregister_shrinker +EXPORT_SYMBOL vmlinux 0x44314efb radix_tree_gang_lookup_tag_slot +EXPORT_SYMBOL vmlinux 0x444779c4 nla_find +EXPORT_SYMBOL vmlinux 0x445b6b88 vc_cons +EXPORT_SYMBOL vmlinux 0x44aaf30f tsc_khz +EXPORT_SYMBOL vmlinux 0x44b911c3 rb_replace_node +EXPORT_SYMBOL vmlinux 0x44bbadf5 devm_free_irq +EXPORT_SYMBOL vmlinux 0x44f21bea idr_for_each +EXPORT_SYMBOL vmlinux 0x4502fc9e udp_proc_unregister +EXPORT_SYMBOL vmlinux 0x4504408b dma_free_coherent +EXPORT_SYMBOL vmlinux 0x4550ba8a register_cpu_notifier +EXPORT_SYMBOL vmlinux 0x455fd57d acpi_set_register +EXPORT_SYMBOL vmlinux 0x459dba12 pci_bus_find_capability +EXPORT_SYMBOL vmlinux 0x459de514 blk_queue_end_tag +EXPORT_SYMBOL vmlinux 0x45b14ec8 register_exec_domain +EXPORT_SYMBOL vmlinux 0x45bb123e try_to_del_timer_sync +EXPORT_SYMBOL vmlinux 0x45d11c43 down_interruptible +EXPORT_SYMBOL vmlinux 0x460bdf1a pci_bus_size_bridges +EXPORT_SYMBOL vmlinux 0x462a2e75 match_strlcpy +EXPORT_SYMBOL vmlinux 0x464f1ec3 blk_integrity_register +EXPORT_SYMBOL vmlinux 0x466c14a7 __delay +EXPORT_SYMBOL vmlinux 0x466d8a79 init_buffer +EXPORT_SYMBOL vmlinux 0x466ef952 page_symlink +EXPORT_SYMBOL vmlinux 0x4676ff60 allocate_resource +EXPORT_SYMBOL vmlinux 0x46bc06ad dquot_free_inode +EXPORT_SYMBOL vmlinux 0x46ea82f9 sock_common_getsockopt +EXPORT_SYMBOL vmlinux 0x46fbb83f xfrm_unregister_mode +EXPORT_SYMBOL vmlinux 0x47027699 pci_get_class +EXPORT_SYMBOL vmlinux 0x472d2a9a radix_tree_lookup +EXPORT_SYMBOL vmlinux 0x47325002 free_buffer_head +EXPORT_SYMBOL vmlinux 0x4740562b inet_add_protocol +EXPORT_SYMBOL vmlinux 0x475100c2 inet_get_local_port_range +EXPORT_SYMBOL vmlinux 0x475f010b acpi_purge_cached_objects +EXPORT_SYMBOL vmlinux 0x478d10b2 ht_destroy_irq +EXPORT_SYMBOL vmlinux 0x47939e0d __tasklet_hi_schedule +EXPORT_SYMBOL vmlinux 0x479c3c86 find_next_zero_bit +EXPORT_SYMBOL vmlinux 0x47b4f4ad generic_file_splice_write +EXPORT_SYMBOL vmlinux 0x47bc39ee do_sync_read +EXPORT_SYMBOL vmlinux 0x47c62d70 xfrm_policy_flush +EXPORT_SYMBOL vmlinux 0x47ce1f2a rtnl_create_link +EXPORT_SYMBOL vmlinux 0x47cfc537 ip_mc_inc_group +EXPORT_SYMBOL vmlinux 0x47dcd40a __elv_add_request +EXPORT_SYMBOL vmlinux 0x47e6f669 elevator_exit +EXPORT_SYMBOL vmlinux 0x47fe25ba __module_put_and_exit +EXPORT_SYMBOL vmlinux 0x481cb9ab acpi_enter_sleep_state_prep +EXPORT_SYMBOL vmlinux 0x4850c4de generic_shutdown_super +EXPORT_SYMBOL vmlinux 0x4859b8bb rtc_year_days +EXPORT_SYMBOL vmlinux 0x486707ff end_request +EXPORT_SYMBOL vmlinux 0x486b6407 hweight64 +EXPORT_SYMBOL vmlinux 0x488aa6ae update_region +EXPORT_SYMBOL vmlinux 0x48a043ea tty_throttle +EXPORT_SYMBOL vmlinux 0x48a897bb dquot_acquire +EXPORT_SYMBOL vmlinux 0x48b7a275 bio_map_kern +EXPORT_SYMBOL vmlinux 0x49079ef3 input_event +EXPORT_SYMBOL vmlinux 0x49242227 netpoll_cleanup +EXPORT_SYMBOL vmlinux 0x493e25e1 udp_hash +EXPORT_SYMBOL vmlinux 0x49603fb8 security_sb_copy_data +EXPORT_SYMBOL vmlinux 0x497c7b93 dst_release +EXPORT_SYMBOL vmlinux 0x49d6751b mca_device_claimed +EXPORT_SYMBOL vmlinux 0x49da9a9a _read_unlock_bh +EXPORT_SYMBOL vmlinux 0x49e4966f pci_bus_write_config_byte +EXPORT_SYMBOL vmlinux 0x49f864b0 alloc_netdev_mq +EXPORT_SYMBOL vmlinux 0x4a268337 unregister_binfmt +EXPORT_SYMBOL vmlinux 0x4a358252 __bitmap_subset +EXPORT_SYMBOL vmlinux 0x4a3e2835 pci_restore_state +EXPORT_SYMBOL vmlinux 0x4a971ec7 radix_tree_delete +EXPORT_SYMBOL vmlinux 0x4acef45c security_d_instantiate +EXPORT_SYMBOL vmlinux 0x4b07e779 _spin_unlock_irqrestore +EXPORT_SYMBOL vmlinux 0x4b2f14b4 jiffies_to_timespec +EXPORT_SYMBOL vmlinux 0x4b34fbf5 block_all_signals +EXPORT_SYMBOL vmlinux 0x4b5cf81b skb_recv_datagram +EXPORT_SYMBOL vmlinux 0x4b77c0d1 tcf_hash_insert +EXPORT_SYMBOL vmlinux 0x4b804422 bio_endio +EXPORT_SYMBOL vmlinux 0x4b84244b fasync_helper +EXPORT_SYMBOL vmlinux 0x4bae7923 inc_zone_page_state +EXPORT_SYMBOL vmlinux 0x4bb4e80f skb_queue_tail +EXPORT_SYMBOL vmlinux 0x4bbc3e5f pm_flags +EXPORT_SYMBOL vmlinux 0x4bf1b639 serio_open +EXPORT_SYMBOL vmlinux 0x4c08e50d clip_tbl_hook +EXPORT_SYMBOL vmlinux 0x4c1182cb bitmap_scnprintf +EXPORT_SYMBOL vmlinux 0x4c4a97a2 dev_remove_pack +EXPORT_SYMBOL vmlinux 0x4c582569 dquot_alloc_space +EXPORT_SYMBOL vmlinux 0x4ca63e26 nobh_writepage +EXPORT_SYMBOL vmlinux 0x4cb5b140 generic_file_open +EXPORT_SYMBOL vmlinux 0x4cbbd171 __bitmap_weight +EXPORT_SYMBOL vmlinux 0x4d1f602c remap_vmalloc_range +EXPORT_SYMBOL vmlinux 0x4d23e025 pcix_get_max_mmrbc +EXPORT_SYMBOL vmlinux 0x4d2dc830 acpi_get_object_info +EXPORT_SYMBOL vmlinux 0x4d33fb1d register_qdisc +EXPORT_SYMBOL vmlinux 0x4d3c153f sigprocmask +EXPORT_SYMBOL vmlinux 0x4d5a160f serio_interrupt +EXPORT_SYMBOL vmlinux 0x4d630a27 kill_litter_super +EXPORT_SYMBOL vmlinux 0x4d8063d5 generic_file_llseek +EXPORT_SYMBOL vmlinux 0x4d84046a uart_unregister_driver +EXPORT_SYMBOL vmlinux 0x4dc2d7e8 uart_get_baud_rate +EXPORT_SYMBOL vmlinux 0x4dc5dbdd elevator_init +EXPORT_SYMBOL vmlinux 0x4ddc4b9f utf8_mbtowc +EXPORT_SYMBOL vmlinux 0x4df119fa __bitmap_parse +EXPORT_SYMBOL vmlinux 0x4e100f60 _spin_unlock_irq +EXPORT_SYMBOL vmlinux 0x4e17b492 pci_scan_slot +EXPORT_SYMBOL vmlinux 0x4e3567f7 match_int +EXPORT_SYMBOL vmlinux 0x4e6e8ea7 fg_console +EXPORT_SYMBOL vmlinux 0x4e7fec47 sk_reset_timer +EXPORT_SYMBOL vmlinux 0x4e830a3e strnicmp +EXPORT_SYMBOL vmlinux 0x4ef5954c bio_add_page +EXPORT_SYMBOL vmlinux 0x4f5438c1 idle_halt +EXPORT_SYMBOL vmlinux 0x4f60eede unregister_qdisc +EXPORT_SYMBOL vmlinux 0x4fa24eef blk_insert_request +EXPORT_SYMBOL vmlinux 0x4fb91b3b __rta_fill +EXPORT_SYMBOL vmlinux 0x4fd33551 filemap_fdatawrite_range +EXPORT_SYMBOL vmlinux 0x4fdda9ce kernel_bind +EXPORT_SYMBOL vmlinux 0x4fdee897 i8042_command +EXPORT_SYMBOL vmlinux 0x4ffa972a scm_fp_dup +EXPORT_SYMBOL vmlinux 0x500c25f2 xfrm_state_alloc +EXPORT_SYMBOL vmlinux 0x50211ee3 tcp_free_md5sig_pool +EXPORT_SYMBOL vmlinux 0x507abf88 blk_run_queue +EXPORT_SYMBOL vmlinux 0x51035ade dma_async_client_unregister +EXPORT_SYMBOL vmlinux 0x510b2913 qdisc_class_hash_grow +EXPORT_SYMBOL vmlinux 0x510e34f1 qdisc_reset +EXPORT_SYMBOL vmlinux 0x5118c382 secure_dccp_sequence_number +EXPORT_SYMBOL vmlinux 0x514c16f1 xfrm_prepare_input +EXPORT_SYMBOL vmlinux 0x5152e605 memcmp +EXPORT_SYMBOL vmlinux 0x5160b11f get_empty_filp +EXPORT_SYMBOL vmlinux 0x5182c4cf deny_write_access +EXPORT_SYMBOL vmlinux 0x518eb764 per_cpu__cpu_number +EXPORT_SYMBOL vmlinux 0x51cb4b70 pci_dev_get +EXPORT_SYMBOL vmlinux 0x51d12d4e acpi_pci_disabled +EXPORT_SYMBOL vmlinux 0x51d7a776 acpi_detach_data +EXPORT_SYMBOL vmlinux 0x51ef33b8 kstrndup +EXPORT_SYMBOL vmlinux 0x51f3402c dma_async_tx_descriptor_init +EXPORT_SYMBOL vmlinux 0x51fd9fff poll_initwait +EXPORT_SYMBOL vmlinux 0x52026cdf security_sb_parse_opts_str +EXPORT_SYMBOL vmlinux 0x522335ee sk_send_sigurg +EXPORT_SYMBOL vmlinux 0x5227a356 elv_rq_merge_ok +EXPORT_SYMBOL vmlinux 0x52300e50 __bio_clone +EXPORT_SYMBOL vmlinux 0x5233cef4 dev_kfree_skb_irq +EXPORT_SYMBOL vmlinux 0x5243c7f1 pci_release_regions +EXPORT_SYMBOL vmlinux 0x525362c0 blkdev_get +EXPORT_SYMBOL vmlinux 0x525a6c2b pid_task +EXPORT_SYMBOL vmlinux 0x5270ab3e blk_queue_hardsect_size +EXPORT_SYMBOL vmlinux 0x528c709d simple_read_from_buffer +EXPORT_SYMBOL vmlinux 0x529285f3 sync_page_range_nolock +EXPORT_SYMBOL vmlinux 0x52a58c24 ifla_policy +EXPORT_SYMBOL vmlinux 0x52d7b2fd llc_sap_list +EXPORT_SYMBOL vmlinux 0x52e24296 key_validate +EXPORT_SYMBOL vmlinux 0x52f36b3a pci_pme_capable +EXPORT_SYMBOL vmlinux 0x53058fc2 nf_register_hook +EXPORT_SYMBOL vmlinux 0x5305f83a block_commit_write +EXPORT_SYMBOL vmlinux 0x530b1e98 pm_suspend +EXPORT_SYMBOL vmlinux 0x532a8fe5 skb_checksum_help +EXPORT_SYMBOL vmlinux 0x532f2924 param_get_byte +EXPORT_SYMBOL vmlinux 0x53326531 mempool_alloc_pages +EXPORT_SYMBOL vmlinux 0x536358d5 make_EII_client +EXPORT_SYMBOL vmlinux 0x5397ddf7 acpi_unlock_ac_dir +EXPORT_SYMBOL vmlinux 0x53c0767c sk_chk_filter +EXPORT_SYMBOL vmlinux 0x53c6cbc2 tty_wait_until_sent +EXPORT_SYMBOL vmlinux 0x53de6ce0 devm_ioremap +EXPORT_SYMBOL vmlinux 0x53e0b7f4 notify_change +EXPORT_SYMBOL vmlinux 0x540941b9 zero_fill_bio +EXPORT_SYMBOL vmlinux 0x540e0617 qdisc_list_del +EXPORT_SYMBOL vmlinux 0x54290dc9 nla_validate +EXPORT_SYMBOL vmlinux 0x5449ea98 tcf_exts_validate +EXPORT_SYMBOL vmlinux 0x5455d79e dst_destroy +EXPORT_SYMBOL vmlinux 0x54935666 acpi_os_read_port +EXPORT_SYMBOL vmlinux 0x54958970 tty_name +EXPORT_SYMBOL vmlinux 0x54a32969 kmap_high +EXPORT_SYMBOL vmlinux 0x54aed1a5 per_cpu__current_task +EXPORT_SYMBOL vmlinux 0x54b38af8 elv_add_request +EXPORT_SYMBOL vmlinux 0x54b81541 init_timer_deferrable +EXPORT_SYMBOL vmlinux 0x54bad95d acpi_unlock_battery_dir +EXPORT_SYMBOL vmlinux 0x54e6fcdd net_enable_timestamp +EXPORT_SYMBOL vmlinux 0x553f9dd3 down_read_trylock +EXPORT_SYMBOL vmlinux 0x554dc103 nla_append +EXPORT_SYMBOL vmlinux 0x55588faa km_policy_notify +EXPORT_SYMBOL vmlinux 0x557b1e8f locks_remove_posix +EXPORT_SYMBOL vmlinux 0x5594be03 bitmap_remap +EXPORT_SYMBOL vmlinux 0x55b4b244 sg_miter_next +EXPORT_SYMBOL vmlinux 0x55eff5a5 alloc_trdev +EXPORT_SYMBOL vmlinux 0x5600904f fb_get_color_depth +EXPORT_SYMBOL vmlinux 0x562e53ea dev_unicast_unsync +EXPORT_SYMBOL vmlinux 0x5635a60a vmalloc_user +EXPORT_SYMBOL vmlinux 0x563952a3 kblockd_schedule_work +EXPORT_SYMBOL vmlinux 0x564a0c81 ps2_init +EXPORT_SYMBOL vmlinux 0x566ccfbd pcim_iomap_regions +EXPORT_SYMBOL vmlinux 0x56b7e4b2 atm_dev_lookup +EXPORT_SYMBOL vmlinux 0x56dcea37 lock_may_write +EXPORT_SYMBOL vmlinux 0x56df3a56 acpi_check_region +EXPORT_SYMBOL vmlinux 0x56f025de pci_pme_active +EXPORT_SYMBOL vmlinux 0x56f494e0 smp_call_function +EXPORT_SYMBOL vmlinux 0x56fca132 inode_get_bytes +EXPORT_SYMBOL vmlinux 0x5702ed14 tcp_hashinfo +EXPORT_SYMBOL vmlinux 0x570b8aa7 __kfree_skb +EXPORT_SYMBOL vmlinux 0x572e85d4 blk_lookup_devt +EXPORT_SYMBOL vmlinux 0x577cc638 mutex_unlock +EXPORT_SYMBOL vmlinux 0x57a6504e vsnprintf +EXPORT_SYMBOL vmlinux 0x580659a5 unregister_netdevice +EXPORT_SYMBOL vmlinux 0x5810115f new_inode +EXPORT_SYMBOL vmlinux 0x582cea72 pci_iounmap +EXPORT_SYMBOL vmlinux 0x5831cd11 skb_insert +EXPORT_SYMBOL vmlinux 0x5838f6c9 rtc_valid_tm +EXPORT_SYMBOL vmlinux 0x5840f1df xfrm_find_acq_byseq +EXPORT_SYMBOL vmlinux 0x584738f9 rdmsr_safe_on_cpu +EXPORT_SYMBOL vmlinux 0x584eaf46 register_netdevice +EXPORT_SYMBOL vmlinux 0x5857b225 ioread16_rep +EXPORT_SYMBOL vmlinux 0x58794a17 flush_tlb_page +EXPORT_SYMBOL vmlinux 0x587ef524 sock_no_mmap +EXPORT_SYMBOL vmlinux 0x58cc0bdd __lock_buffer +EXPORT_SYMBOL vmlinux 0x58e22ebc tty_hung_up_p +EXPORT_SYMBOL vmlinux 0x58ec6d2c tcp_shutdown +EXPORT_SYMBOL vmlinux 0x58f1d56f set_user_nice +EXPORT_SYMBOL vmlinux 0x58f26756 sg_miter_stop +EXPORT_SYMBOL vmlinux 0x58f4f26c stop_tty +EXPORT_SYMBOL vmlinux 0x58fef6f8 ist_info +EXPORT_SYMBOL vmlinux 0x5934392b fb_register_client +EXPORT_SYMBOL vmlinux 0x59412654 input_free_device +EXPORT_SYMBOL vmlinux 0x594bf15b ioport_map +EXPORT_SYMBOL vmlinux 0x595ab257 llc_set_station_handler +EXPORT_SYMBOL vmlinux 0x5987aa5e tty_port_init +EXPORT_SYMBOL vmlinux 0x599b1657 file_update_time +EXPORT_SYMBOL vmlinux 0x599b9216 tcf_em_register +EXPORT_SYMBOL vmlinux 0x59a912a0 neigh_table_init_no_netlink +EXPORT_SYMBOL vmlinux 0x59d696b6 register_module_notifier +EXPORT_SYMBOL vmlinux 0x5a2a0d74 blk_sync_queue +EXPORT_SYMBOL vmlinux 0x5a452edd set_blocksize +EXPORT_SYMBOL vmlinux 0x5a4896a8 __put_user_2 +EXPORT_SYMBOL vmlinux 0x5a5411b0 netdev_class_create_file +EXPORT_SYMBOL vmlinux 0x5a744b86 netlink_set_nonroot +EXPORT_SYMBOL vmlinux 0x5a8ac772 sockfd_lookup +EXPORT_SYMBOL vmlinux 0x5a8f872c sock_get_timestamp +EXPORT_SYMBOL vmlinux 0x5ab70adb dev_driver_string +EXPORT_SYMBOL vmlinux 0x5abbd49c input_unregister_handle +EXPORT_SYMBOL vmlinux 0x5ac376a5 acpi_install_fixed_event_handler +EXPORT_SYMBOL vmlinux 0x5ac53241 __bread +EXPORT_SYMBOL vmlinux 0x5ad94bcd cfb_imageblit +EXPORT_SYMBOL vmlinux 0x5af4b999 kernel_sendmsg +EXPORT_SYMBOL vmlinux 0x5b04634f pnp_find_card +EXPORT_SYMBOL vmlinux 0x5b19634d div_s64_rem +EXPORT_SYMBOL vmlinux 0x5b51c6a7 acpi_walk_resources +EXPORT_SYMBOL vmlinux 0x5bb300ca pci_disable_device +EXPORT_SYMBOL vmlinux 0x5bd110d0 pci_find_slot +EXPORT_SYMBOL vmlinux 0x5be92454 igrab +EXPORT_SYMBOL vmlinux 0x5c0ac388 udp_lib_getsockopt +EXPORT_SYMBOL vmlinux 0x5c265cba sg_init_one +EXPORT_SYMBOL vmlinux 0x5c45a223 pcie_set_readrq +EXPORT_SYMBOL vmlinux 0x5c512d8b skb_clone +EXPORT_SYMBOL vmlinux 0x5c68705b mca_read_pos +EXPORT_SYMBOL vmlinux 0x5c8da451 xfrm_state_delete_tunnel +EXPORT_SYMBOL vmlinux 0x5c9aa822 devm_ioport_map +EXPORT_SYMBOL vmlinux 0x5cbeb295 bdevname +EXPORT_SYMBOL vmlinux 0x5cdbf5aa bio_integrity_trim +EXPORT_SYMBOL vmlinux 0x5cee23e5 kobject_init +EXPORT_SYMBOL vmlinux 0x5d0c0014 skb_dequeue +EXPORT_SYMBOL vmlinux 0x5d510dce d_instantiate_unique +EXPORT_SYMBOL vmlinux 0x5d57c365 alloc_tty_driver +EXPORT_SYMBOL vmlinux 0x5d73b5f8 km_waitq +EXPORT_SYMBOL vmlinux 0x5d8789f4 uart_write_wakeup +EXPORT_SYMBOL vmlinux 0x5db64407 free_task +EXPORT_SYMBOL vmlinux 0x5dbcfa4f boot_cpu_physical_apicid +EXPORT_SYMBOL vmlinux 0x5dbf2cbd register_sysctl_paths +EXPORT_SYMBOL vmlinux 0x5dcc3953 vfs_create +EXPORT_SYMBOL vmlinux 0x5e14efa5 simple_transaction_read +EXPORT_SYMBOL vmlinux 0x5e1baf98 nobh_write_end +EXPORT_SYMBOL vmlinux 0x5e2230ba skb_make_writable +EXPORT_SYMBOL vmlinux 0x5e37cb88 ip_setsockopt +EXPORT_SYMBOL vmlinux 0x5e777fdc pcix_get_mmrbc +EXPORT_SYMBOL vmlinux 0x5e79ebec gen_replace_estimator +EXPORT_SYMBOL vmlinux 0x5ea520c5 tcp_select_initial_window +EXPORT_SYMBOL vmlinux 0x5eb7e7f3 netif_device_detach +EXPORT_SYMBOL vmlinux 0x5ed040b0 pm_set_vt_switch +EXPORT_SYMBOL vmlinux 0x5edd066d atm_charge +EXPORT_SYMBOL vmlinux 0x5edd0762 bin2bcd +EXPORT_SYMBOL vmlinux 0x5f04fe3a skb_copy_and_csum_dev +EXPORT_SYMBOL vmlinux 0x5f070c4d simple_dir_inode_operations +EXPORT_SYMBOL vmlinux 0x5f0ce5a4 dev_unicast_add +EXPORT_SYMBOL vmlinux 0x5f18c694 lock_sock_nested +EXPORT_SYMBOL vmlinux 0x5f1bd579 mca_find_adapter +EXPORT_SYMBOL vmlinux 0x5fb00dd9 request_firmware +EXPORT_SYMBOL vmlinux 0x5fb832ae close_bdev_excl +EXPORT_SYMBOL vmlinux 0x5fc8e574 framebuffer_release +EXPORT_SYMBOL vmlinux 0x5ff2b5a1 llc_sap_close +EXPORT_SYMBOL vmlinux 0x5ff42b08 acpi_video_get_capabilities +EXPORT_SYMBOL vmlinux 0x6002ea20 locks_copy_lock +EXPORT_SYMBOL vmlinux 0x6005137c inet_frags_fini +EXPORT_SYMBOL vmlinux 0x600683d3 do_unblank_screen +EXPORT_SYMBOL vmlinux 0x6011fdfa dmam_alloc_noncoherent +EXPORT_SYMBOL vmlinux 0x602a9272 tcp_md5_hash_skb_data +EXPORT_SYMBOL vmlinux 0x6031efa5 find_lock_page +EXPORT_SYMBOL vmlinux 0x60361169 call_usermodehelper_stdinpipe +EXPORT_SYMBOL vmlinux 0x60400b7f pv_lock_ops +EXPORT_SYMBOL vmlinux 0x608c2831 warn_on_slowpath +EXPORT_SYMBOL vmlinux 0x608cf83f ip_queue_xmit +EXPORT_SYMBOL vmlinux 0x609f1c7e synchronize_net +EXPORT_SYMBOL vmlinux 0x60a32ea9 pm_power_off +EXPORT_SYMBOL vmlinux 0x610156a3 d_genocide +EXPORT_SYMBOL vmlinux 0x6111e1bc init_timer +EXPORT_SYMBOL vmlinux 0x612390ad netpoll_set_trap +EXPORT_SYMBOL vmlinux 0x615a9dfb bdi_unregister +EXPORT_SYMBOL vmlinux 0x6162b65f get_sb_bdev +EXPORT_SYMBOL vmlinux 0x618b0e3e security_sb_clone_mnt_opts +EXPORT_SYMBOL vmlinux 0x618d8299 set_notify_swap_entry_free +EXPORT_SYMBOL vmlinux 0x61a06034 pcie_port_service_register +EXPORT_SYMBOL vmlinux 0x61b7b126 simple_strtoull +EXPORT_SYMBOL vmlinux 0x61de1b05 tcf_exts_destroy +EXPORT_SYMBOL vmlinux 0x61e5df8d init_special_inode +EXPORT_SYMBOL vmlinux 0x61eeafb0 __break_lease +EXPORT_SYMBOL vmlinux 0x62049256 acpi_disable +EXPORT_SYMBOL vmlinux 0x6206b1d9 open_exec +EXPORT_SYMBOL vmlinux 0x62264f7f fb_find_mode +EXPORT_SYMBOL vmlinux 0x622de90a __bforget +EXPORT_SYMBOL vmlinux 0x6237f6b5 acpi_enable_event +EXPORT_SYMBOL vmlinux 0x6241a2ab __copy_from_user_ll_nocache +EXPORT_SYMBOL vmlinux 0x6241fd2c acpi_install_address_space_handler +EXPORT_SYMBOL vmlinux 0x62737e1d sock_unregister +EXPORT_SYMBOL vmlinux 0x62827bec security_secctx_to_secid +EXPORT_SYMBOL vmlinux 0x628e3b83 set_page_dirty_lock +EXPORT_SYMBOL vmlinux 0x631299de inet_proto_csum_replace4 +EXPORT_SYMBOL vmlinux 0x6313a823 bio_integrity_alloc +EXPORT_SYMBOL vmlinux 0x636a5691 acpi_register_ioapic +EXPORT_SYMBOL vmlinux 0x638676ba dma_release_declared_memory +EXPORT_SYMBOL vmlinux 0x63a772d9 dcache_dir_open +EXPORT_SYMBOL vmlinux 0x63b51119 secpath_dup +EXPORT_SYMBOL vmlinux 0x63ecad53 register_netdevice_notifier +EXPORT_SYMBOL vmlinux 0x6402aaff release_resource +EXPORT_SYMBOL vmlinux 0x6403e338 tcp_memory_pressure +EXPORT_SYMBOL vmlinux 0x640a182c vfs_getattr +EXPORT_SYMBOL vmlinux 0x641275c3 load_nls_default +EXPORT_SYMBOL vmlinux 0x642e54ac __wake_up +EXPORT_SYMBOL vmlinux 0x644d78b0 mntput_no_expire +EXPORT_SYMBOL vmlinux 0x6451294b posix_acl_valid +EXPORT_SYMBOL vmlinux 0x6466a1e6 mempool_alloc +EXPORT_SYMBOL vmlinux 0x6478134c ec_burst_enable +EXPORT_SYMBOL vmlinux 0x64999478 congestion_wait +EXPORT_SYMBOL vmlinux 0x64a90c32 default_unplug_io_fn +EXPORT_SYMBOL vmlinux 0x64cd5d16 init_waitqueue_head +EXPORT_SYMBOL vmlinux 0x64df0ae0 skb_copy_expand +EXPORT_SYMBOL vmlinux 0x650029c0 mpage_readpages +EXPORT_SYMBOL vmlinux 0x650128e7 br_fdb_get_hook +EXPORT_SYMBOL vmlinux 0x650fb346 add_wait_queue +EXPORT_SYMBOL vmlinux 0x65408378 zlib_inflate_blob +EXPORT_SYMBOL vmlinux 0x65414e67 dev_valid_name +EXPORT_SYMBOL vmlinux 0x654e64e7 pci_get_subsys +EXPORT_SYMBOL vmlinux 0x6584d7d2 eisa_driver_unregister +EXPORT_SYMBOL vmlinux 0x65938591 dmam_pool_create +EXPORT_SYMBOL vmlinux 0x65f099ed unlock_rename +EXPORT_SYMBOL vmlinux 0x661a26d9 tcp_v4_md5_do_add +EXPORT_SYMBOL vmlinux 0x66283a8e ip_defrag +EXPORT_SYMBOL vmlinux 0x66606ac4 cont_write_begin +EXPORT_SYMBOL vmlinux 0x6674ca6c pci_request_selected_regions +EXPORT_SYMBOL vmlinux 0x66808b47 generic_file_llseek_unlocked +EXPORT_SYMBOL vmlinux 0x6684db9a tty_write_room +EXPORT_SYMBOL vmlinux 0x668da8d5 zlib_inflateIncomp +EXPORT_SYMBOL vmlinux 0x66a947ae add_disk +EXPORT_SYMBOL vmlinux 0x66dc2631 eth_header_cache_update +EXPORT_SYMBOL vmlinux 0x66e7a49f tty_register_ldisc +EXPORT_SYMBOL vmlinux 0x6729d3df __get_user_4 +EXPORT_SYMBOL vmlinux 0x676b8f37 nla_reserve +EXPORT_SYMBOL vmlinux 0x67b27ec1 tty_std_termios +EXPORT_SYMBOL vmlinux 0x67e71b77 __mutex_init +EXPORT_SYMBOL vmlinux 0x67f7318a kset_register +EXPORT_SYMBOL vmlinux 0x67fc7fbd devm_ioport_unmap +EXPORT_SYMBOL vmlinux 0x681e52bb nf_register_sockopt +EXPORT_SYMBOL vmlinux 0x683cea6d xfrm_dst_ifdown +EXPORT_SYMBOL vmlinux 0x6845e54d wireless_spy_update +EXPORT_SYMBOL vmlinux 0x686add6d mnt_unpin +EXPORT_SYMBOL vmlinux 0x6898568f do_mmap_pgoff +EXPORT_SYMBOL vmlinux 0x68e6e8e7 pci_match_id +EXPORT_SYMBOL vmlinux 0x68ea6bf3 tcp_rcv_state_process +EXPORT_SYMBOL vmlinux 0x693bb9e1 ip_mc_join_group +EXPORT_SYMBOL vmlinux 0x695762ed dcache_readdir +EXPORT_SYMBOL vmlinux 0x6971447a rtc_month_days +EXPORT_SYMBOL vmlinux 0x69763f65 __page_symlink +EXPORT_SYMBOL vmlinux 0x69806cab mca_bus_type +EXPORT_SYMBOL vmlinux 0x698ff7d4 get_sb_single +EXPORT_SYMBOL vmlinux 0x69927dff try_acquire_console_sem +EXPORT_SYMBOL vmlinux 0x69a0af13 llc_sap_open +EXPORT_SYMBOL vmlinux 0x69a0ca7d iowrite16be +EXPORT_SYMBOL vmlinux 0x69c3ac1e generic_file_aio_read +EXPORT_SYMBOL vmlinux 0x69c8c568 filemap_flush +EXPORT_SYMBOL vmlinux 0x69dac7a6 nf_log_packet +EXPORT_SYMBOL vmlinux 0x69f69995 genl_register_ops +EXPORT_SYMBOL vmlinux 0x6a037cf1 mempool_kfree +EXPORT_SYMBOL vmlinux 0x6a15d0d6 blk_queue_max_segment_size +EXPORT_SYMBOL vmlinux 0x6a27bfce csum_partial_copy_generic +EXPORT_SYMBOL vmlinux 0x6a47571d __set_personality +EXPORT_SYMBOL vmlinux 0x6a4bb295 bio_integrity_tag_size +EXPORT_SYMBOL vmlinux 0x6a54bb42 bdi_destroy +EXPORT_SYMBOL vmlinux 0x6a5f6c84 fb_set_suspend +EXPORT_SYMBOL vmlinux 0x6a6cc4bb key_payload_reserve +EXPORT_SYMBOL vmlinux 0x6ac87808 blk_rq_unmap_user +EXPORT_SYMBOL vmlinux 0x6acb973d iowrite32be +EXPORT_SYMBOL vmlinux 0x6accc590 __scm_destroy +EXPORT_SYMBOL vmlinux 0x6add5c9a dmi_find_device +EXPORT_SYMBOL vmlinux 0x6b0a7c2d sk_release_kernel +EXPORT_SYMBOL vmlinux 0x6b1b67d3 __bdevname +EXPORT_SYMBOL vmlinux 0x6b297291 sb_min_blocksize +EXPORT_SYMBOL vmlinux 0x6b2dc060 dump_stack +EXPORT_SYMBOL vmlinux 0x6b49f400 call_usermodehelper_setkeys +EXPORT_SYMBOL vmlinux 0x6b92ec2e dev_close +EXPORT_SYMBOL vmlinux 0x6b937ffb mca_mark_as_used +EXPORT_SYMBOL vmlinux 0x6b9b88f3 sleep_on +EXPORT_SYMBOL vmlinux 0x6bafbced mod_timer +EXPORT_SYMBOL vmlinux 0x6bd39098 pci_bus_type +EXPORT_SYMBOL vmlinux 0x6bdcfd99 qdisc_class_hash_remove +EXPORT_SYMBOL vmlinux 0x6c1ce5ce strcspn +EXPORT_SYMBOL vmlinux 0x6c2e3320 strncmp +EXPORT_SYMBOL vmlinux 0x6c389761 acpi_bus_get_private_data +EXPORT_SYMBOL vmlinux 0x6c4620df nf_afinfo +EXPORT_SYMBOL vmlinux 0x6c551514 __lock_page +EXPORT_SYMBOL vmlinux 0x6c61ce70 num_registered_fb +EXPORT_SYMBOL vmlinux 0x6c702af7 sysctl_udp_rmem_min +EXPORT_SYMBOL vmlinux 0x6c76f7e7 pci_back_from_sleep +EXPORT_SYMBOL vmlinux 0x6caeb960 cfb_fillrect +EXPORT_SYMBOL vmlinux 0x6cbecc2a pci_select_bars +EXPORT_SYMBOL vmlinux 0x6cd9f57e mca_device_read_stored_pos +EXPORT_SYMBOL vmlinux 0x6cdc5c6b nla_strlcpy +EXPORT_SYMBOL vmlinux 0x6cf79b1e cfb_copyarea +EXPORT_SYMBOL vmlinux 0x6cf956cc acpi_bus_add +EXPORT_SYMBOL vmlinux 0x6cfc7e13 __sk_mem_schedule +EXPORT_SYMBOL vmlinux 0x6d0da34c param_get_short +EXPORT_SYMBOL vmlinux 0x6d10832b key_put +EXPORT_SYMBOL vmlinux 0x6d1877f7 xfrm_alloc_spi +EXPORT_SYMBOL vmlinux 0x6d1ced27 vcc_sklist_lock +EXPORT_SYMBOL vmlinux 0x6d27ef64 __bitmap_empty +EXPORT_SYMBOL vmlinux 0x6d288375 radix_tree_next_hole +EXPORT_SYMBOL vmlinux 0x6d294e43 clock_t_to_jiffies +EXPORT_SYMBOL vmlinux 0x6d340f64 tty_termios_input_baud_rate +EXPORT_SYMBOL vmlinux 0x6d464175 __sg_free_table +EXPORT_SYMBOL vmlinux 0x6d532c2b eth_rebuild_header +EXPORT_SYMBOL vmlinux 0x6d56994a cmpxchg_486_u64 +EXPORT_SYMBOL vmlinux 0x6d687421 unregister_8022_client +EXPORT_SYMBOL vmlinux 0x6d831cfa end_buffer_read_sync +EXPORT_SYMBOL vmlinux 0x6dc0c24b complete_and_exit +EXPORT_SYMBOL vmlinux 0x6dee7be5 dump_fpu +EXPORT_SYMBOL vmlinux 0x6def2db2 half_md4_transform +EXPORT_SYMBOL vmlinux 0x6e0159b7 inet_addr_type +EXPORT_SYMBOL vmlinux 0x6e07a54e acpi_get_gpe_status +EXPORT_SYMBOL vmlinux 0x6e1a4bbb udp_hash_lock +EXPORT_SYMBOL vmlinux 0x6e440b58 memcpy_fromiovecend +EXPORT_SYMBOL vmlinux 0x6e4dda18 __nla_put_nohdr +EXPORT_SYMBOL vmlinux 0x6e5177b7 kill_anon_super +EXPORT_SYMBOL vmlinux 0x6e720ff2 rtnl_unlock +EXPORT_SYMBOL vmlinux 0x6e9b6439 ps2_handle_ack +EXPORT_SYMBOL vmlinux 0x6e9dd606 __symbol_put +EXPORT_SYMBOL vmlinux 0x6ea5c490 inode_double_lock +EXPORT_SYMBOL vmlinux 0x6ead242b cond_resched_lock +EXPORT_SYMBOL vmlinux 0x6efc8606 udp_ioctl +EXPORT_SYMBOL vmlinux 0x6efe996d tcp_check_req +EXPORT_SYMBOL vmlinux 0x6fb370b2 acpi_check_resource_conflict +EXPORT_SYMBOL vmlinux 0x6fcb87a1 touch_softlockup_watchdog +EXPORT_SYMBOL vmlinux 0x7008a9b7 timespec_to_jiffies +EXPORT_SYMBOL vmlinux 0x701d0ebd snprintf +EXPORT_SYMBOL vmlinux 0x70461a22 key_revoke +EXPORT_SYMBOL vmlinux 0x7054a3e4 request_dma +EXPORT_SYMBOL vmlinux 0x70c91a9a neigh_lookup_nodev +EXPORT_SYMBOL vmlinux 0x70d1f8f3 strncat +EXPORT_SYMBOL vmlinux 0x70d8ab82 acpi_acquire_global_lock +EXPORT_SYMBOL vmlinux 0x710391ae ip_nat_decode_session +EXPORT_SYMBOL vmlinux 0x7129e5f8 hex_asc +EXPORT_SYMBOL vmlinux 0x712aa29b _spin_lock_irqsave +EXPORT_SYMBOL vmlinux 0x71356fba remove_wait_queue +EXPORT_SYMBOL vmlinux 0x7149225e rtnl_unicast +EXPORT_SYMBOL vmlinux 0x7171121c overflowgid +EXPORT_SYMBOL vmlinux 0x71919b90 block_write_end +EXPORT_SYMBOL vmlinux 0x71a45e98 vmtruncate +EXPORT_SYMBOL vmlinux 0x71a50dbc register_blkdev +EXPORT_SYMBOL vmlinux 0x72270e35 do_gettimeofday +EXPORT_SYMBOL vmlinux 0x722e768b __xfrm_lookup +EXPORT_SYMBOL vmlinux 0x7290c30c misc_register +EXPORT_SYMBOL vmlinux 0x72b243d4 free_dma +EXPORT_SYMBOL vmlinux 0x72b2e93f ether_setup +EXPORT_SYMBOL vmlinux 0x72bf2140 mtrr_add +EXPORT_SYMBOL vmlinux 0x735a0bd5 native_io_delay +EXPORT_SYMBOL vmlinux 0x736ad430 tty_register_device +EXPORT_SYMBOL vmlinux 0x7373bf16 neigh_seq_stop +EXPORT_SYMBOL vmlinux 0x738803e6 strnlen +EXPORT_SYMBOL vmlinux 0x7389c9a8 acpi_bus_get_power +EXPORT_SYMBOL vmlinux 0x73913645 init_file +EXPORT_SYMBOL vmlinux 0x739c3c34 pskb_copy +EXPORT_SYMBOL vmlinux 0x73a8c7fe pci_remove_bus +EXPORT_SYMBOL vmlinux 0x73b284f2 blk_rq_count_integrity_sg +EXPORT_SYMBOL vmlinux 0x73e20c1c strlcpy +EXPORT_SYMBOL vmlinux 0x740a1b95 reserve_evntsel_nmi +EXPORT_SYMBOL vmlinux 0x7413793a EISA_bus +EXPORT_SYMBOL vmlinux 0x7413d4cc kill_pgrp +EXPORT_SYMBOL vmlinux 0x741bfea4 simple_write_begin +EXPORT_SYMBOL vmlinux 0x741cf87f vm_insert_page +EXPORT_SYMBOL vmlinux 0x741e35ca tcf_unregister_action +EXPORT_SYMBOL vmlinux 0x7450de49 task_tgid_nr_ns +EXPORT_SYMBOL vmlinux 0x7485e15e unregister_chrdev_region +EXPORT_SYMBOL vmlinux 0x7488c51b acpi_bus_start +EXPORT_SYMBOL vmlinux 0x748caf40 down +EXPORT_SYMBOL vmlinux 0x749bddf5 pskb_expand_head +EXPORT_SYMBOL vmlinux 0x74a0f33b mca_device_set_name +EXPORT_SYMBOL vmlinux 0x74a518a2 tcf_exts_dump_stats +EXPORT_SYMBOL vmlinux 0x74aa9295 sock_recvmsg +EXPORT_SYMBOL vmlinux 0x74cc1cbe unregister_cpu_notifier +EXPORT_SYMBOL vmlinux 0x74cc238d current_kernel_time +EXPORT_SYMBOL vmlinux 0x751d5524 iunique +EXPORT_SYMBOL vmlinux 0x751d8b42 set_binfmt +EXPORT_SYMBOL vmlinux 0x75271716 save_processor_state +EXPORT_SYMBOL vmlinux 0x75401437 submit_bio +EXPORT_SYMBOL vmlinux 0x75566739 complete_request_key +EXPORT_SYMBOL vmlinux 0x757d605f find_get_pages_tag +EXPORT_SYMBOL vmlinux 0x758a15ba register_key_type +EXPORT_SYMBOL vmlinux 0x75986126 mca_unregister_driver +EXPORT_SYMBOL vmlinux 0x75a1fa83 inet_shutdown +EXPORT_SYMBOL vmlinux 0x75a92e4c posix_lock_file_wait +EXPORT_SYMBOL vmlinux 0x75c60a2b xfrm_policy_register_afinfo +EXPORT_SYMBOL vmlinux 0x75c95c03 tty_devnum +EXPORT_SYMBOL vmlinux 0x75db8035 input_unregister_device +EXPORT_SYMBOL vmlinux 0x760a0f4f yield +EXPORT_SYMBOL vmlinux 0x760b437a unregister_inetaddr_notifier +EXPORT_SYMBOL vmlinux 0x7610ab5c should_remove_suid +EXPORT_SYMBOL vmlinux 0x76213515 __skb_checksum_complete_head +EXPORT_SYMBOL vmlinux 0x7673eb6e init_task +EXPORT_SYMBOL vmlinux 0x767ddb02 set_memory_wc +EXPORT_SYMBOL vmlinux 0x76845676 thermal_cooling_device_register +EXPORT_SYMBOL vmlinux 0x769270fc may_umount +EXPORT_SYMBOL vmlinux 0x76b0f8f8 bad_dma_address +EXPORT_SYMBOL vmlinux 0x76bf656d __bitmap_shift_left +EXPORT_SYMBOL vmlinux 0x76d3cd60 laptop_mode +EXPORT_SYMBOL vmlinux 0x76e4f297 netpoll_parse_options +EXPORT_SYMBOL vmlinux 0x76f3f8a5 num_k8_northbridges +EXPORT_SYMBOL vmlinux 0x770a0036 isapnp_cfg_begin +EXPORT_SYMBOL vmlinux 0x770bb653 vfs_dq_drop +EXPORT_SYMBOL vmlinux 0x77480b82 fb_set_var +EXPORT_SYMBOL vmlinux 0x774cc51e sock_alloc_send_skb +EXPORT_SYMBOL vmlinux 0x77a108df _write_unlock_irqrestore +EXPORT_SYMBOL vmlinux 0x77e55399 ip_ct_attach +EXPORT_SYMBOL vmlinux 0x77ea6153 kernel_listen +EXPORT_SYMBOL vmlinux 0x77ecac9f zlib_inflateEnd +EXPORT_SYMBOL vmlinux 0x7805c0c9 bd_claim +EXPORT_SYMBOL vmlinux 0x786d158f pcim_iomap_table +EXPORT_SYMBOL vmlinux 0x788a1526 register_con_driver +EXPORT_SYMBOL vmlinux 0x78a484c9 _read_unlock_irqrestore +EXPORT_SYMBOL vmlinux 0x78cb2783 down_write_trylock +EXPORT_SYMBOL vmlinux 0x78decd99 get_fs_type +EXPORT_SYMBOL vmlinux 0x78df6bd7 no_pci_devices +EXPORT_SYMBOL vmlinux 0x794439a0 mca_device_transform_ioport +EXPORT_SYMBOL vmlinux 0x794487ee disable_hlt +EXPORT_SYMBOL vmlinux 0x794c1398 dmi_check_system +EXPORT_SYMBOL vmlinux 0x7957670a page_symlink_inode_operations +EXPORT_SYMBOL vmlinux 0x79656409 cpu_online_map +EXPORT_SYMBOL vmlinux 0x7970b320 generic_delete_inode +EXPORT_SYMBOL vmlinux 0x79aa04a2 get_random_bytes +EXPORT_SYMBOL vmlinux 0x79aa05a8 match_token +EXPORT_SYMBOL vmlinux 0x79d78989 set_irq_chip +EXPORT_SYMBOL vmlinux 0x7a071a6c kernel_read +EXPORT_SYMBOL vmlinux 0x7a12c60c module_put +EXPORT_SYMBOL vmlinux 0x7a15aa4b qdisc_watchdog_init +EXPORT_SYMBOL vmlinux 0x7a1c6fce simple_release_fs +EXPORT_SYMBOL vmlinux 0x7a2a837d strict_strtol +EXPORT_SYMBOL vmlinux 0x7a80013f nonseekable_open +EXPORT_SYMBOL vmlinux 0x7a848702 _read_lock_irqsave +EXPORT_SYMBOL vmlinux 0x7ac29175 register_filesystem +EXPORT_SYMBOL vmlinux 0x7aca9c7b generic_readlink +EXPORT_SYMBOL vmlinux 0x7ad5e389 blk_cleanup_queue +EXPORT_SYMBOL vmlinux 0x7aebca18 dev_get_flags +EXPORT_SYMBOL vmlinux 0x7aec9089 clear_user +EXPORT_SYMBOL vmlinux 0x7b0c84c4 acpi_remove_table_handler +EXPORT_SYMBOL vmlinux 0x7b134ddf acpi_get_name +EXPORT_SYMBOL vmlinux 0x7b36fa1f bio_integrity_get_tag +EXPORT_SYMBOL vmlinux 0x7b4ab167 blk_queue_make_request +EXPORT_SYMBOL vmlinux 0x7b52a859 wrmsr_safe_on_cpu +EXPORT_SYMBOL vmlinux 0x7b5ffc1a proc_dointvec_minmax +EXPORT_SYMBOL vmlinux 0x7b69467e posix_acl_from_xattr +EXPORT_SYMBOL vmlinux 0x7b749597 serio_unregister_driver +EXPORT_SYMBOL vmlinux 0x7b8f96ca proc_doulongvec_minmax +EXPORT_SYMBOL vmlinux 0x7bcb19b8 __seq_open_private +EXPORT_SYMBOL vmlinux 0x7bcffb47 mod_zone_page_state +EXPORT_SYMBOL vmlinux 0x7bd634c9 get_unmapped_area +EXPORT_SYMBOL vmlinux 0x7beab71d blk_rq_map_user +EXPORT_SYMBOL vmlinux 0x7c3146ae __devm_request_region +EXPORT_SYMBOL vmlinux 0x7c46233a cpufreq_quick_get +EXPORT_SYMBOL vmlinux 0x7c5ba928 unregister_snap_client +EXPORT_SYMBOL vmlinux 0x7c60d66e getname +EXPORT_SYMBOL vmlinux 0x7c66ce17 mapping_tagged +EXPORT_SYMBOL vmlinux 0x7c7bc010 neigh_parms_alloc +EXPORT_SYMBOL vmlinux 0x7c8e8b15 devm_request_irq +EXPORT_SYMBOL vmlinux 0x7c904ded unregister_module_notifier +EXPORT_SYMBOL vmlinux 0x7ca984f3 simple_write_end +EXPORT_SYMBOL vmlinux 0x7cab4602 xfrm_unregister_type +EXPORT_SYMBOL vmlinux 0x7cb1ae69 cpu_down +EXPORT_SYMBOL vmlinux 0x7cdc2f78 key_task_permission +EXPORT_SYMBOL vmlinux 0x7cfe97d8 pnp_start_dev +EXPORT_SYMBOL vmlinux 0x7d047e7e acpi_ut_exception +EXPORT_SYMBOL vmlinux 0x7d0c41cc ethtool_op_set_sg +EXPORT_SYMBOL vmlinux 0x7d10dbc9 tty_check_change +EXPORT_SYMBOL vmlinux 0x7d11c268 jiffies +EXPORT_SYMBOL vmlinux 0x7d47fe7a cdev_del +EXPORT_SYMBOL vmlinux 0x7d4d118a generic_ro_fops +EXPORT_SYMBOL vmlinux 0x7d79a978 request_key_with_auxdata +EXPORT_SYMBOL vmlinux 0x7d850612 utf8_mbstowcs +EXPORT_SYMBOL vmlinux 0x7d948097 load_nls +EXPORT_SYMBOL vmlinux 0x7dac7049 qdisc_create_dflt +EXPORT_SYMBOL vmlinux 0x7dceceac capable +EXPORT_SYMBOL vmlinux 0x7dfd4939 vc_resize +EXPORT_SYMBOL vmlinux 0x7e1c4449 netpoll_poll +EXPORT_SYMBOL vmlinux 0x7e7c6414 skb_copy_and_csum_bits +EXPORT_SYMBOL vmlinux 0x7e83f2c2 neigh_compat_output +EXPORT_SYMBOL vmlinux 0x7e9ebb05 kernel_thread +EXPORT_SYMBOL vmlinux 0x7eabea5e pagecache_write_end +EXPORT_SYMBOL vmlinux 0x7ec45a69 kernel_sock_shutdown +EXPORT_SYMBOL vmlinux 0x7ee91c1d _spin_trylock +EXPORT_SYMBOL vmlinux 0x7efbe560 per_cpu__cpu_core_map +EXPORT_SYMBOL vmlinux 0x7f24de73 jiffies_to_usecs +EXPORT_SYMBOL vmlinux 0x7f4cfeb1 pnp_request_card_device +EXPORT_SYMBOL vmlinux 0x7f5728af key_type_keyring +EXPORT_SYMBOL vmlinux 0x7f78c4d1 blk_queue_free_tags +EXPORT_SYMBOL vmlinux 0x7f8723bd pcie_mch_quirk +EXPORT_SYMBOL vmlinux 0x7f9fd080 invalidate_mapping_pages +EXPORT_SYMBOL vmlinux 0x7ff3efc1 pci_save_state +EXPORT_SYMBOL vmlinux 0x800d9d7e audit_log_end +EXPORT_SYMBOL vmlinux 0x8014ed34 redirty_page_for_writepage +EXPORT_SYMBOL vmlinux 0x801afc1c netif_device_attach +EXPORT_SYMBOL vmlinux 0x8063f83d radix_tree_gang_lookup +EXPORT_SYMBOL vmlinux 0x806729c4 netif_carrier_on +EXPORT_SYMBOL vmlinux 0x806a99f3 sock_wake_async +EXPORT_SYMBOL vmlinux 0x807aa964 inet_select_addr +EXPORT_SYMBOL vmlinux 0x8090cf92 d_prune_aliases +EXPORT_SYMBOL vmlinux 0x80b04ee4 nobh_write_begin +EXPORT_SYMBOL vmlinux 0x80c3406e dev_set_mac_address +EXPORT_SYMBOL vmlinux 0x80e0de24 simple_prepare_write +EXPORT_SYMBOL vmlinux 0x80fdc39a sync_inode +EXPORT_SYMBOL vmlinux 0x81472677 acpi_get_table +EXPORT_SYMBOL vmlinux 0x814e7730 nf_ct_destroy +EXPORT_SYMBOL vmlinux 0x815b5dd4 match_octal +EXPORT_SYMBOL vmlinux 0x815f2897 empty_zero_page +EXPORT_SYMBOL vmlinux 0x816c4c0b pci_disable_msi +EXPORT_SYMBOL vmlinux 0x8177c762 contig_page_data +EXPORT_SYMBOL vmlinux 0x81799cee vscnprintf +EXPORT_SYMBOL vmlinux 0x81988006 ethtool_op_get_tx_csum +EXPORT_SYMBOL vmlinux 0x819e204e neigh_table_clear +EXPORT_SYMBOL vmlinux 0x81e6b37f dmi_get_system_info +EXPORT_SYMBOL vmlinux 0x82072614 tasklet_kill +EXPORT_SYMBOL vmlinux 0x820d225f print_mac +EXPORT_SYMBOL vmlinux 0x8235805b memmove +EXPORT_SYMBOL vmlinux 0x823d4212 skb_kill_datagram +EXPORT_SYMBOL vmlinux 0x8251bcc3 bitmap_release_region +EXPORT_SYMBOL vmlinux 0x82673561 schedule_delayed_work +EXPORT_SYMBOL vmlinux 0x828f6b2b request_key_async +EXPORT_SYMBOL vmlinux 0x829af37d find_inode_number +EXPORT_SYMBOL vmlinux 0x83170e6e vfs_get_dqblk +EXPORT_SYMBOL vmlinux 0x8317e20a completion_done +EXPORT_SYMBOL vmlinux 0x832fda62 bio_free +EXPORT_SYMBOL vmlinux 0x835eca8e block_read_full_page +EXPORT_SYMBOL vmlinux 0x8363c3d4 smp_call_function_mask +EXPORT_SYMBOL vmlinux 0x8367e824 netdev_state_change +EXPORT_SYMBOL vmlinux 0x836deff5 unmap_mapping_range +EXPORT_SYMBOL vmlinux 0x837063c0 skb_copy +EXPORT_SYMBOL vmlinux 0x83800bfa kref_init +EXPORT_SYMBOL vmlinux 0x839400e1 xfrm_state_update +EXPORT_SYMBOL vmlinux 0x83a476ce bitmap_scnlistprintf +EXPORT_SYMBOL vmlinux 0x83deb5c7 __tcf_em_tree_match +EXPORT_SYMBOL vmlinux 0x83f4a5cf __nla_put +EXPORT_SYMBOL vmlinux 0x8402d06c open_bdev_excl +EXPORT_SYMBOL vmlinux 0x84603ac5 neigh_create +EXPORT_SYMBOL vmlinux 0x84ccc6c8 genl_unregister_ops +EXPORT_SYMBOL vmlinux 0x84cdcc53 blkdev_put +EXPORT_SYMBOL vmlinux 0x84de85b6 uart_register_driver +EXPORT_SYMBOL vmlinux 0x8524847d follow_down +EXPORT_SYMBOL vmlinux 0x852abecf __request_region +EXPORT_SYMBOL vmlinux 0x8539c162 pci_bus_add_devices +EXPORT_SYMBOL vmlinux 0x85670f1d rtnl_is_locked +EXPORT_SYMBOL vmlinux 0x857c8e36 skb_dequeue_tail +EXPORT_SYMBOL vmlinux 0x858c20c2 mark_page_accessed +EXPORT_SYMBOL vmlinux 0x85a43efc alloc_hippi_dev +EXPORT_SYMBOL vmlinux 0x85aac777 pci_request_regions +EXPORT_SYMBOL vmlinux 0x85df9b6c strsep +EXPORT_SYMBOL vmlinux 0x85e7deb2 iov_iter_fault_in_readable +EXPORT_SYMBOL vmlinux 0x860e370b audit_log_format +EXPORT_SYMBOL vmlinux 0x863cb91a utf8_wcstombs +EXPORT_SYMBOL vmlinux 0x8664f62e cpufreq_update_policy +EXPORT_SYMBOL vmlinux 0x868acba5 get_options +EXPORT_SYMBOL vmlinux 0x868e025e bio_phys_segments +EXPORT_SYMBOL vmlinux 0x86ba2a3b dev_mc_unsync +EXPORT_SYMBOL vmlinux 0x86d173dd sb_set_blocksize +EXPORT_SYMBOL vmlinux 0x86ed41ae textsearch_destroy +EXPORT_SYMBOL vmlinux 0x86fb9b05 bitmap_parse_user +EXPORT_SYMBOL vmlinux 0x872856f6 netpoll_setup +EXPORT_SYMBOL vmlinux 0x8733e9a3 sleep_on_timeout +EXPORT_SYMBOL vmlinux 0x8744a016 simple_unlink +EXPORT_SYMBOL vmlinux 0x876dafc3 ec_write +EXPORT_SYMBOL vmlinux 0x877863ce xfrm_policy_walk +EXPORT_SYMBOL vmlinux 0x878441f7 kernel_connect +EXPORT_SYMBOL vmlinux 0x8785725d param_set_charp +EXPORT_SYMBOL vmlinux 0x87894d34 tcp_v4_conn_request +EXPORT_SYMBOL vmlinux 0x878ab3ce sysctl_tcp_adv_win_scale +EXPORT_SYMBOL vmlinux 0x87fef8a6 sync_mapping_buffers +EXPORT_SYMBOL vmlinux 0x880eeff1 generic_file_splice_write_nolock +EXPORT_SYMBOL vmlinux 0x881039d0 zlib_inflate +EXPORT_SYMBOL vmlinux 0x8856652b tcp_parse_options +EXPORT_SYMBOL vmlinux 0x885f2e90 pfifo_qdisc_ops +EXPORT_SYMBOL vmlinux 0x8862c540 skb_find_text +EXPORT_SYMBOL vmlinux 0x8868670e tty_insert_flip_string_flags +EXPORT_SYMBOL vmlinux 0x888259f5 skb_queue_head +EXPORT_SYMBOL vmlinux 0x8884beae tcp_create_openreq_child +EXPORT_SYMBOL vmlinux 0x88904e9b skb_copy_bits +EXPORT_SYMBOL vmlinux 0x88fc45a2 fb_is_primary_device +EXPORT_SYMBOL vmlinux 0x88ffbf9b pci_release_selected_regions +EXPORT_SYMBOL vmlinux 0x8922c41b save_mount_options +EXPORT_SYMBOL vmlinux 0x892b26a0 set_memory_nx +EXPORT_SYMBOL vmlinux 0x89304c9c devm_iounmap +EXPORT_SYMBOL vmlinux 0x8931b32a init_net +EXPORT_SYMBOL vmlinux 0x8946bf9e blk_start_queue +EXPORT_SYMBOL vmlinux 0x8949858b schedule_work +EXPORT_SYMBOL vmlinux 0x8953bb27 del_timer +EXPORT_SYMBOL vmlinux 0x8960b815 blk_alloc_queue +EXPORT_SYMBOL vmlinux 0x8969b997 ida_get_new +EXPORT_SYMBOL vmlinux 0x896a050a arch_acpi_processor_init_pdc +EXPORT_SYMBOL vmlinux 0x897473df mktime +EXPORT_SYMBOL vmlinux 0x898b1fec mutex_trylock +EXPORT_SYMBOL vmlinux 0x89949018 down_timeout +EXPORT_SYMBOL vmlinux 0x89c6480d unregister_filesystem +EXPORT_SYMBOL vmlinux 0x89d5538d fb_pad_aligned_buffer +EXPORT_SYMBOL vmlinux 0x89d66811 build_ehash_secret +EXPORT_SYMBOL vmlinux 0x8a1fe6bb dma_ops +EXPORT_SYMBOL vmlinux 0x8a3d1a2e netlink_kernel_create +EXPORT_SYMBOL vmlinux 0x8a3eabf0 __wait_on_bit +EXPORT_SYMBOL vmlinux 0x8a5b85cd tty_hangup +EXPORT_SYMBOL vmlinux 0x8a70d862 simple_sync_file +EXPORT_SYMBOL vmlinux 0x8a7d1c31 high_memory +EXPORT_SYMBOL vmlinux 0x8a99a016 mempool_free_slab +EXPORT_SYMBOL vmlinux 0x8aac2917 vfs_llseek +EXPORT_SYMBOL vmlinux 0x8aaf8654 mutex_lock +EXPORT_SYMBOL vmlinux 0x8b04411e tcp_md5_hash_header +EXPORT_SYMBOL vmlinux 0x8b11dc4a eth_header +EXPORT_SYMBOL vmlinux 0x8b18496f __copy_to_user_ll +EXPORT_SYMBOL vmlinux 0x8b3ca835 cpu_present_map +EXPORT_SYMBOL vmlinux 0x8b4b3947 linkwatch_fire_event +EXPORT_SYMBOL vmlinux 0x8b50bd1c udp_memory_allocated +EXPORT_SYMBOL vmlinux 0x8b57e096 gnet_stats_copy_app +EXPORT_SYMBOL vmlinux 0x8b5a3350 inet_csk_clear_xmit_timers +EXPORT_SYMBOL vmlinux 0x8b618d08 overflowuid +EXPORT_SYMBOL vmlinux 0x8b7ae544 tcf_register_action +EXPORT_SYMBOL vmlinux 0x8b989cf9 acpi_bus_can_wakeup +EXPORT_SYMBOL vmlinux 0x8b99c59e ip_route_input +EXPORT_SYMBOL vmlinux 0x8bb948b5 sk_filter +EXPORT_SYMBOL vmlinux 0x8bd73cc6 sk_run_filter +EXPORT_SYMBOL vmlinux 0x8bf3996f eisa_driver_register +EXPORT_SYMBOL vmlinux 0x8bfbbe85 ip_route_me_harder +EXPORT_SYMBOL vmlinux 0x8c183cbe iowrite16 +EXPORT_SYMBOL vmlinux 0x8c22cf29 __dec_zone_page_state +EXPORT_SYMBOL vmlinux 0x8c26104b __breadahead +EXPORT_SYMBOL vmlinux 0x8c277cae nf_reinject +EXPORT_SYMBOL vmlinux 0x8c3d9d72 bio_uncopy_user +EXPORT_SYMBOL vmlinux 0x8c54c599 no_llseek +EXPORT_SYMBOL vmlinux 0x8c611294 alloc_pci_dev +EXPORT_SYMBOL vmlinux 0x8cc79cab iowrite16_rep +EXPORT_SYMBOL vmlinux 0x8cd3caac ethtool_op_set_ufo +EXPORT_SYMBOL vmlinux 0x8cee4aec call_usermodehelper_exec +EXPORT_SYMBOL vmlinux 0x8d0a8abe xfrm_register_km +EXPORT_SYMBOL vmlinux 0x8d156db9 textsearch_unregister +EXPORT_SYMBOL vmlinux 0x8d3894f2 _ctype +EXPORT_SYMBOL vmlinux 0x8d4b1e1f register_console +EXPORT_SYMBOL vmlinux 0x8d551bef sysctl_tcp_rmem +EXPORT_SYMBOL vmlinux 0x8d5b4f16 read_cache_page_async +EXPORT_SYMBOL vmlinux 0x8d6f81b4 __div64_32 +EXPORT_SYMBOL vmlinux 0x8d82699a register_binfmt +EXPORT_SYMBOL vmlinux 0x8d8d96c6 acpi_get_sleep_type_data +EXPORT_SYMBOL vmlinux 0x8d8ee180 neigh_lookup +EXPORT_SYMBOL vmlinux 0x8dc6e564 restore_processor_state +EXPORT_SYMBOL vmlinux 0x8e002cda acpi_remove_gpe_block +EXPORT_SYMBOL vmlinux 0x8e040c62 llc_mac_hdr_init +EXPORT_SYMBOL vmlinux 0x8e0637ba i8253_lock +EXPORT_SYMBOL vmlinux 0x8e0b7743 ipv6_ext_hdr +EXPORT_SYMBOL vmlinux 0x8e1ccc00 __dev_get_by_index +EXPORT_SYMBOL vmlinux 0x8e725985 nf_log_unregister_pf +EXPORT_SYMBOL vmlinux 0x8e829b70 pci_set_consistent_dma_mask +EXPORT_SYMBOL vmlinux 0x8e99cf65 mca_device_write_pos +EXPORT_SYMBOL vmlinux 0x8e9abd78 find_get_page +EXPORT_SYMBOL vmlinux 0x8ecb113a sock_no_setsockopt +EXPORT_SYMBOL vmlinux 0x8ee6b61c ip_mc_rejoin_group +EXPORT_SYMBOL vmlinux 0x8f1b487a pci_get_bus_and_slot +EXPORT_SYMBOL vmlinux 0x8f26feb5 __alloc_pages_internal +EXPORT_SYMBOL vmlinux 0x8f3fc9eb tcp_make_synack +EXPORT_SYMBOL vmlinux 0x8f6b7950 set_irq_data +EXPORT_SYMBOL vmlinux 0x8f7f90b9 dma_pool_create +EXPORT_SYMBOL vmlinux 0x8f839bd9 seq_release +EXPORT_SYMBOL vmlinux 0x8f9c199c __get_user_2 +EXPORT_SYMBOL vmlinux 0x8fd34de9 kernel_accept +EXPORT_SYMBOL vmlinux 0x8feddcce proc_mkdir +EXPORT_SYMBOL vmlinux 0x90035333 secure_tcpv6_sequence_number +EXPORT_SYMBOL vmlinux 0x9050d3cc generic_file_readonly_mmap +EXPORT_SYMBOL vmlinux 0x906a6b09 inet_sock_destruct +EXPORT_SYMBOL vmlinux 0x9072ce9b inet_unregister_protosw +EXPORT_SYMBOL vmlinux 0x908e8afa do_splice_to +EXPORT_SYMBOL vmlinux 0x90a943ba nmi_active +EXPORT_SYMBOL vmlinux 0x90e5858d set_page_dirty +EXPORT_SYMBOL vmlinux 0x90ed2f8e atm_dev_deregister +EXPORT_SYMBOL vmlinux 0x910c1c87 __mark_inode_dirty +EXPORT_SYMBOL vmlinux 0x91264fef __set_page_dirty_nobuffers +EXPORT_SYMBOL vmlinux 0x9144a8e2 ec_burst_disable +EXPORT_SYMBOL vmlinux 0x91481982 __ratelimit +EXPORT_SYMBOL vmlinux 0x914bf68f arp_tbl +EXPORT_SYMBOL vmlinux 0x91607d95 set_memory_wb +EXPORT_SYMBOL vmlinux 0x91ca8959 acpi_get_register +EXPORT_SYMBOL vmlinux 0x91d06d03 ip_route_output_key +EXPORT_SYMBOL vmlinux 0x91e4228a dquot_alloc_inode +EXPORT_SYMBOL vmlinux 0x91f6761c atm_init_aal5 +EXPORT_SYMBOL vmlinux 0x9276fe5b nf_register_hooks +EXPORT_SYMBOL vmlinux 0x92897e3d default_idle +EXPORT_SYMBOL vmlinux 0x92d810b6 skb_checksum +EXPORT_SYMBOL vmlinux 0x92f68674 bio_init +EXPORT_SYMBOL vmlinux 0x9305f8e6 cpufreq_get +EXPORT_SYMBOL vmlinux 0x9330cb9f sg_alloc_table +EXPORT_SYMBOL vmlinux 0x93880474 dquot_commit_info +EXPORT_SYMBOL vmlinux 0x9391b4b0 ilookup5 +EXPORT_SYMBOL vmlinux 0x93a6e0b2 io_schedule +EXPORT_SYMBOL vmlinux 0x93afa72e vm_get_page_prot +EXPORT_SYMBOL vmlinux 0x93b8ef56 mutex_lock_interruptible +EXPORT_SYMBOL vmlinux 0x93c69acf param_set_byte +EXPORT_SYMBOL vmlinux 0x93cbd1ec _spin_lock_bh +EXPORT_SYMBOL vmlinux 0x93db1f4d ethtool_op_set_tx_hw_csum +EXPORT_SYMBOL vmlinux 0x93e43924 llc_add_pack +EXPORT_SYMBOL vmlinux 0x93fca811 __get_free_pages +EXPORT_SYMBOL vmlinux 0x942f77a7 pci_set_dma_mask +EXPORT_SYMBOL vmlinux 0x948f98ff dev_set_mtu +EXPORT_SYMBOL vmlinux 0x94961283 vunmap +EXPORT_SYMBOL vmlinux 0x94cf0eb8 proc_net_netfilter +EXPORT_SYMBOL vmlinux 0x94d1cce2 scm_detach_fds +EXPORT_SYMBOL vmlinux 0x94e45a17 file_permission +EXPORT_SYMBOL vmlinux 0x94f0124d elv_rb_latter_request +EXPORT_SYMBOL vmlinux 0x94f736dd wireless_send_event +EXPORT_SYMBOL vmlinux 0x94f91e85 submit_bh +EXPORT_SYMBOL vmlinux 0x94fcf08e bioset_create +EXPORT_SYMBOL vmlinux 0x9504f68f pneigh_enqueue +EXPORT_SYMBOL vmlinux 0x9542960f __inet6_hash +EXPORT_SYMBOL vmlinux 0x954488a4 syncookie_secret +EXPORT_SYMBOL vmlinux 0x9545af6d tasklet_init +EXPORT_SYMBOL vmlinux 0x954cbb26 vsprintf +EXPORT_SYMBOL vmlinux 0x95667d47 netlink_kernel_release +EXPORT_SYMBOL vmlinux 0x95871d5d gnet_stats_start_copy_compat +EXPORT_SYMBOL vmlinux 0x95f638d5 posix_acl_chmod_masq +EXPORT_SYMBOL vmlinux 0x96481cc7 per_cpu__x86_cpu_to_apicid +EXPORT_SYMBOL vmlinux 0x96898769 sysfs_format_mac +EXPORT_SYMBOL vmlinux 0x96939c04 pv_cpu_ops +EXPORT_SYMBOL vmlinux 0x96e5890f pcie_get_readrq +EXPORT_SYMBOL vmlinux 0x971ac54a input_get_keycode +EXPORT_SYMBOL vmlinux 0x973873ab _spin_lock +EXPORT_SYMBOL vmlinux 0x9754ec10 radix_tree_preload +EXPORT_SYMBOL vmlinux 0x9780e385 pci_choose_state +EXPORT_SYMBOL vmlinux 0x97aa7ea8 sysctl_string +EXPORT_SYMBOL vmlinux 0x97c2cebd lock_rename +EXPORT_SYMBOL vmlinux 0x97de0ddd acpi_install_gpe_block +EXPORT_SYMBOL vmlinux 0x980884a9 bio_copy_user +EXPORT_SYMBOL vmlinux 0x981026f6 km_report +EXPORT_SYMBOL vmlinux 0x98238493 thermal_zone_device_register +EXPORT_SYMBOL vmlinux 0x986e6135 fb_pad_unaligned_buffer +EXPORT_SYMBOL vmlinux 0x987985f9 generic_write_end +EXPORT_SYMBOL vmlinux 0x98814b8c kill_block_super +EXPORT_SYMBOL vmlinux 0x988ed85d set_memory_x +EXPORT_SYMBOL vmlinux 0x98a3a6fc sock_get_timestampns +EXPORT_SYMBOL vmlinux 0x99052a84 acpi_os_write_port +EXPORT_SYMBOL vmlinux 0x994a21ad generic_write_checks +EXPORT_SYMBOL vmlinux 0x995df0a3 register_framebuffer +EXPORT_SYMBOL vmlinux 0x9994c0ca ps2_is_keyboard_id +EXPORT_SYMBOL vmlinux 0x999e8297 vfree +EXPORT_SYMBOL vmlinux 0x99aadb21 param_get_ulong +EXPORT_SYMBOL vmlinux 0x99bfbe39 get_unused_fd +EXPORT_SYMBOL vmlinux 0x99c3c0b0 vfs_fstat +EXPORT_SYMBOL vmlinux 0x99cdc86b sysctl_tcp_reordering +EXPORT_SYMBOL vmlinux 0x99dd55f4 xfrm_register_mode +EXPORT_SYMBOL vmlinux 0x99ea12ce panic_blink +EXPORT_SYMBOL vmlinux 0x9a03d4c2 arch_debugfs_dir +EXPORT_SYMBOL vmlinux 0x9a15483d netpoll_print_options +EXPORT_SYMBOL vmlinux 0x9a15836c may_umount_tree +EXPORT_SYMBOL vmlinux 0x9a1dfd65 strpbrk +EXPORT_SYMBOL vmlinux 0x9a4c1b63 bio_map_user +EXPORT_SYMBOL vmlinux 0x9a6a83f9 cmos_lock +EXPORT_SYMBOL vmlinux 0x9a8a2b8e d_namespace_path +EXPORT_SYMBOL vmlinux 0x9a8d3d4a kmem_cache_free +EXPORT_SYMBOL vmlinux 0x9a9985be percpu_counter_destroy +EXPORT_SYMBOL vmlinux 0x9ad8b986 compute_creds +EXPORT_SYMBOL vmlinux 0x9b1b2fa2 netlink_clear_multicast_users +EXPORT_SYMBOL vmlinux 0x9b388444 get_zeroed_page +EXPORT_SYMBOL vmlinux 0x9b4de8eb idr_replace +EXPORT_SYMBOL vmlinux 0x9b58563c set_pages_uc +EXPORT_SYMBOL vmlinux 0x9b6540a1 sg_miter_start +EXPORT_SYMBOL vmlinux 0x9b9675de release_sock +EXPORT_SYMBOL vmlinux 0x9ba7089d argv_split +EXPORT_SYMBOL vmlinux 0x9bbb68a3 neigh_table_init +EXPORT_SYMBOL vmlinux 0x9bf30228 pci_enable_wake +EXPORT_SYMBOL vmlinux 0x9c012508 fb_parse_edid +EXPORT_SYMBOL vmlinux 0x9c22a4b8 inet_frag_evictor +EXPORT_SYMBOL vmlinux 0x9c2c944a __copy_from_user_ll_nocache_nozero +EXPORT_SYMBOL vmlinux 0x9c6aec16 pci_prepare_to_sleep +EXPORT_SYMBOL vmlinux 0x9c7077bd enable_hlt +EXPORT_SYMBOL vmlinux 0x9cac0cbd blk_plug_device +EXPORT_SYMBOL vmlinux 0x9cb4a68a xfrm_policy_unregister_afinfo +EXPORT_SYMBOL vmlinux 0x9cb96e92 qdisc_put_rtab +EXPORT_SYMBOL vmlinux 0x9ccb2622 finish_wait +EXPORT_SYMBOL vmlinux 0x9ceb163c memcpy_toiovec +EXPORT_SYMBOL vmlinux 0x9ced38aa down_trylock +EXPORT_SYMBOL vmlinux 0x9d2ae2ae tcf_em_unregister +EXPORT_SYMBOL vmlinux 0x9d33ef5e acpi_enable +EXPORT_SYMBOL vmlinux 0x9d43755c request_resource +EXPORT_SYMBOL vmlinux 0x9d711f1f percpu_counter_init +EXPORT_SYMBOL vmlinux 0x9d7afa7f dev_add_pack +EXPORT_SYMBOL vmlinux 0x9d9f0d41 rwsem_down_write_failed +EXPORT_SYMBOL vmlinux 0x9dd3bfcd blk_queue_merge_bvec +EXPORT_SYMBOL vmlinux 0x9e26f1a2 key_unlink +EXPORT_SYMBOL vmlinux 0x9e316cfc hippi_type_trans +EXPORT_SYMBOL vmlinux 0x9e449f5d blk_recount_segments +EXPORT_SYMBOL vmlinux 0x9e64fbfe rtc_cmos_read +EXPORT_SYMBOL vmlinux 0x9e7d6bd0 __udelay +EXPORT_SYMBOL vmlinux 0x9ea614f5 ioremap_cache +EXPORT_SYMBOL vmlinux 0x9ed685ee iov_iter_advance +EXPORT_SYMBOL vmlinux 0x9eecde16 do_brk +EXPORT_SYMBOL vmlinux 0x9ef0491e serio_unregister_port +EXPORT_SYMBOL vmlinux 0x9ef749e2 unregister_chrdev +EXPORT_SYMBOL vmlinux 0x9f00d14e skb_split +EXPORT_SYMBOL vmlinux 0x9f04e917 pcim_iounmap_regions +EXPORT_SYMBOL vmlinux 0x9f100139 jiffies_to_clock_t +EXPORT_SYMBOL vmlinux 0x9f2bdaac __bitmap_or +EXPORT_SYMBOL vmlinux 0x9f3c4d51 unregister_nls +EXPORT_SYMBOL vmlinux 0x9f55b8fb sock_no_accept +EXPORT_SYMBOL vmlinux 0x9f6470f3 input_release_device +EXPORT_SYMBOL vmlinux 0x9f984513 strrchr +EXPORT_SYMBOL vmlinux 0x9fa274b4 dq_data_lock +EXPORT_SYMBOL vmlinux 0x9fb3dd30 memcpy_fromiovec +EXPORT_SYMBOL vmlinux 0x9fb73a95 path_permission +EXPORT_SYMBOL vmlinux 0x9fe57fe1 fb_blank +EXPORT_SYMBOL vmlinux 0x9feaf287 sonet_subtract_stats +EXPORT_SYMBOL vmlinux 0x9ff3a4bd pci_enable_msi +EXPORT_SYMBOL vmlinux 0x9ffd5c59 neigh_seq_next +EXPORT_SYMBOL vmlinux 0x9ffed01d d_alloc_root +EXPORT_SYMBOL vmlinux 0xa008ce9c dma_supported +EXPORT_SYMBOL vmlinux 0xa03523d5 security_unix_stream_connect +EXPORT_SYMBOL vmlinux 0xa04a01bd qdisc_class_hash_insert +EXPORT_SYMBOL vmlinux 0xa05c03df mempool_kmalloc +EXPORT_SYMBOL vmlinux 0xa0654786 vfs_symlink +EXPORT_SYMBOL vmlinux 0xa0674db1 uart_resume_port +EXPORT_SYMBOL vmlinux 0xa06878b8 pci_unregister_driver +EXPORT_SYMBOL vmlinux 0xa06fc142 tcf_em_tree_dump +EXPORT_SYMBOL vmlinux 0xa0a05018 __netif_schedule +EXPORT_SYMBOL vmlinux 0xa0b04675 vmalloc_32 +EXPORT_SYMBOL vmlinux 0xa0ceef51 out_of_line_wait_on_bit +EXPORT_SYMBOL vmlinux 0xa0fbac79 wake_up_bit +EXPORT_SYMBOL vmlinux 0xa0fc1985 unlock_page +EXPORT_SYMBOL vmlinux 0xa108288f inet_accept +EXPORT_SYMBOL vmlinux 0xa108eb4d sysctl_optmem_max +EXPORT_SYMBOL vmlinux 0xa10f4fef dev_open +EXPORT_SYMBOL vmlinux 0xa11904d6 dev_change_flags +EXPORT_SYMBOL vmlinux 0xa120d33c tty_unregister_ldisc +EXPORT_SYMBOL vmlinux 0xa13798f8 printk_ratelimit +EXPORT_SYMBOL vmlinux 0xa14bfce7 alloc_disk_node +EXPORT_SYMBOL vmlinux 0xa14f0431 set_trace_device +EXPORT_SYMBOL vmlinux 0xa15299ae xfrm_stateonly_find +EXPORT_SYMBOL vmlinux 0xa199ee23 xfrm_input_resume +EXPORT_SYMBOL vmlinux 0xa1b759ce fb_add_videomode +EXPORT_SYMBOL vmlinux 0xa1c76e0a _cond_resched +EXPORT_SYMBOL vmlinux 0xa1e0d001 neigh_ifdown +EXPORT_SYMBOL vmlinux 0xa1ef76cf input_allocate_device +EXPORT_SYMBOL vmlinux 0xa1fdad2f inet_dgram_connect +EXPORT_SYMBOL vmlinux 0xa203e165 input_flush_device +EXPORT_SYMBOL vmlinux 0xa20ce1b8 net_msg_warn +EXPORT_SYMBOL vmlinux 0xa24447e6 sock_common_recvmsg +EXPORT_SYMBOL vmlinux 0xa256f5f0 kick_iocb +EXPORT_SYMBOL vmlinux 0xa25fd77d xfrm_policy_insert +EXPORT_SYMBOL vmlinux 0xa26df7ce wake_up_process +EXPORT_SYMBOL vmlinux 0xa286ce0c inet_dev_addr_type +EXPORT_SYMBOL vmlinux 0xa299238c dev_set_promiscuity +EXPORT_SYMBOL vmlinux 0xa2a1e5c9 _write_lock_bh +EXPORT_SYMBOL vmlinux 0xa2a5fd77 inet_ehash_secret +EXPORT_SYMBOL vmlinux 0xa2b81e18 __tcp_get_md5sig_pool +EXPORT_SYMBOL vmlinux 0xa2c59327 skb_store_bits +EXPORT_SYMBOL vmlinux 0xa2ea2542 do_splice_from +EXPORT_SYMBOL vmlinux 0xa2f33683 arp_xmit +EXPORT_SYMBOL vmlinux 0xa329f07e register_shrinker +EXPORT_SYMBOL vmlinux 0xa32ffafb skb_prepare_seq_read +EXPORT_SYMBOL vmlinux 0xa3330e16 block_truncate_page +EXPORT_SYMBOL vmlinux 0xa3420d61 __percpu_counter_sum +EXPORT_SYMBOL vmlinux 0xa34ca908 udp_sendmsg +EXPORT_SYMBOL vmlinux 0xa34f1ef5 crc32_le +EXPORT_SYMBOL vmlinux 0xa35c1f05 acpi_extract_package +EXPORT_SYMBOL vmlinux 0xa35de80f ipv4_config +EXPORT_SYMBOL vmlinux 0xa3656da9 acpi_lock_battery_dir +EXPORT_SYMBOL vmlinux 0xa3722dfd simple_link +EXPORT_SYMBOL vmlinux 0xa38725e1 tcf_hash_search +EXPORT_SYMBOL vmlinux 0xa3bbcd80 acpi_set_gpe_type +EXPORT_SYMBOL vmlinux 0xa3c76300 __serio_register_driver +EXPORT_SYMBOL vmlinux 0xa3c7e2a8 fddi_type_trans +EXPORT_SYMBOL vmlinux 0xa3d56969 vfs_unlink +EXPORT_SYMBOL vmlinux 0xa3e5713d __dev_getfirstbyhwtype +EXPORT_SYMBOL vmlinux 0xa42956df ps2_drain +EXPORT_SYMBOL vmlinux 0xa44072fc posix_acl_alloc +EXPORT_SYMBOL vmlinux 0xa44ad274 wait_for_completion_interruptible_timeout +EXPORT_SYMBOL vmlinux 0xa451d207 netlink_unicast +EXPORT_SYMBOL vmlinux 0xa4562a8f vfs_set_dqinfo +EXPORT_SYMBOL vmlinux 0xa46449cc filemap_fdatawait +EXPORT_SYMBOL vmlinux 0xa46b7236 sock_rfree +EXPORT_SYMBOL vmlinux 0xa46cae6a blk_queue_max_sectors +EXPORT_SYMBOL vmlinux 0xa47a76a9 posix_unblock_lock +EXPORT_SYMBOL vmlinux 0xa49be1d3 mca_device_read_pos +EXPORT_SYMBOL vmlinux 0xa49cd81c sk_wait_data +EXPORT_SYMBOL vmlinux 0xa4b94fea iowrite8_rep +EXPORT_SYMBOL vmlinux 0xa4df1151 kref_set +EXPORT_SYMBOL vmlinux 0xa4e190cc invalidate_bdev +EXPORT_SYMBOL vmlinux 0xa4f7454c neigh_resolve_output +EXPORT_SYMBOL vmlinux 0xa51cdfe8 __FIXADDR_TOP +EXPORT_SYMBOL vmlinux 0xa5423cc4 param_get_int +EXPORT_SYMBOL vmlinux 0xa5662fa5 vfs_quota_on_path +EXPORT_SYMBOL vmlinux 0xa5693df7 posix_acl_clone +EXPORT_SYMBOL vmlinux 0xa56f1315 mempool_free +EXPORT_SYMBOL vmlinux 0xa57197e6 dma_async_client_chan_request +EXPORT_SYMBOL vmlinux 0xa58b6804 nla_parse +EXPORT_SYMBOL vmlinux 0xa5922bb1 kfifo_init +EXPORT_SYMBOL vmlinux 0xa598e29c vesa_modes +EXPORT_SYMBOL vmlinux 0xa598fe90 call_usermodehelper_pipe +EXPORT_SYMBOL vmlinux 0xa5a633b9 sg_last +EXPORT_SYMBOL vmlinux 0xa5ac453e vfs_quota_on +EXPORT_SYMBOL vmlinux 0xa5c40677 block_page_mkwrite +EXPORT_SYMBOL vmlinux 0xa5ca589f pci_find_parent_resource +EXPORT_SYMBOL vmlinux 0xa5da0abd acpi_enter_sleep_state_s4bios +EXPORT_SYMBOL vmlinux 0xa6046122 arp_create +EXPORT_SYMBOL vmlinux 0xa60d6b71 pnp_activate_dev +EXPORT_SYMBOL vmlinux 0xa616ae27 kmem_cache_size +EXPORT_SYMBOL vmlinux 0xa61eef57 elv_dispatch_add_tail +EXPORT_SYMBOL vmlinux 0xa621254f iommu_bio_merge +EXPORT_SYMBOL vmlinux 0xa65075f3 skb_copy_datagram_from_iovec +EXPORT_SYMBOL vmlinux 0xa6630c40 tty_register_driver +EXPORT_SYMBOL vmlinux 0xa68124fa hweight8 +EXPORT_SYMBOL vmlinux 0xa6814433 groups_free +EXPORT_SYMBOL vmlinux 0xa681fe88 generate_random_uuid +EXPORT_SYMBOL vmlinux 0xa693b117 pnp_register_driver +EXPORT_SYMBOL vmlinux 0xa69a07a8 pci_request_region +EXPORT_SYMBOL vmlinux 0xa6b480cc dev_get_by_name +EXPORT_SYMBOL vmlinux 0xa6dcc773 rb_insert_color +EXPORT_SYMBOL vmlinux 0xa6dfc26e tr_type_trans +EXPORT_SYMBOL vmlinux 0xa6e93205 dev_mc_sync +EXPORT_SYMBOL vmlinux 0xa7046549 vprintk +EXPORT_SYMBOL vmlinux 0xa705070d dmam_alloc_coherent +EXPORT_SYMBOL vmlinux 0xa70fabbe release_evntsel_nmi +EXPORT_SYMBOL vmlinux 0xa7502f48 jiffies_to_timeval +EXPORT_SYMBOL vmlinux 0xa75e1b6a pcim_iomap +EXPORT_SYMBOL vmlinux 0xa7619849 console_start +EXPORT_SYMBOL vmlinux 0xa770b803 kblockd_flush_work +EXPORT_SYMBOL vmlinux 0xa794ac3c udp_poll +EXPORT_SYMBOL vmlinux 0xa7c35c6b getnstimeofday +EXPORT_SYMBOL vmlinux 0xa7c9e918 __inet6_lookup_established +EXPORT_SYMBOL vmlinux 0xa7cde5e1 xfrm4_rcv +EXPORT_SYMBOL vmlinux 0xa7e57a10 cdev_alloc +EXPORT_SYMBOL vmlinux 0xa83a4c5f __locks_copy_lock +EXPORT_SYMBOL vmlinux 0xa83b6315 inode_double_unlock +EXPORT_SYMBOL vmlinux 0xa86398c8 tcp_v4_md5_do_del +EXPORT_SYMBOL vmlinux 0xa89acbb3 acpi_evaluate_reference +EXPORT_SYMBOL vmlinux 0xa89ca3ed d_splice_alias +EXPORT_SYMBOL vmlinux 0xa8a13f70 bio_integrity_free +EXPORT_SYMBOL vmlinux 0xa8db9eee elv_dispatch_sort +EXPORT_SYMBOL vmlinux 0xa8fef7bb security_unix_may_send +EXPORT_SYMBOL vmlinux 0xa904a40e pci_bus_read_config_byte +EXPORT_SYMBOL vmlinux 0xa91b5561 acpi_video_backlight_support +EXPORT_SYMBOL vmlinux 0xa925899a param_set_bool +EXPORT_SYMBOL vmlinux 0xa92af63b d_alloc_anon +EXPORT_SYMBOL vmlinux 0xa94b6055 xfrm_nl +EXPORT_SYMBOL vmlinux 0xa953b6a2 kernel_sock_ioctl +EXPORT_SYMBOL vmlinux 0xa959cd9d pci_enable_device +EXPORT_SYMBOL vmlinux 0xa96516b6 blk_verify_command +EXPORT_SYMBOL vmlinux 0xa975c28a skb_pad +EXPORT_SYMBOL vmlinux 0xa97a3aad kmap +EXPORT_SYMBOL vmlinux 0xa98158ff generic_block_bmap +EXPORT_SYMBOL vmlinux 0xa98648af get_sb_nodev +EXPORT_SYMBOL vmlinux 0xa98d5003 audit_log_start +EXPORT_SYMBOL vmlinux 0xa9a14377 unregister_key_type +EXPORT_SYMBOL vmlinux 0xa9b321c9 rtnl_set_sk_err +EXPORT_SYMBOL vmlinux 0xa9b5d989 bio_integrity_advance +EXPORT_SYMBOL vmlinux 0xa9be76e8 clocksource_register +EXPORT_SYMBOL vmlinux 0xa9ea5200 handle_sysrq +EXPORT_SYMBOL vmlinux 0xa9fcf31d wait_for_completion_interruptible +EXPORT_SYMBOL vmlinux 0xa9fee667 sock_queue_rcv_skb +EXPORT_SYMBOL vmlinux 0xaa024146 sonet_copy_stats +EXPORT_SYMBOL vmlinux 0xaa2b14d3 dma_pool_free +EXPORT_SYMBOL vmlinux 0xaa84a8ae acpi_processor_power_init_bm_check +EXPORT_SYMBOL vmlinux 0xaab06af8 _write_lock_irqsave +EXPORT_SYMBOL vmlinux 0xaac6ccf8 dmam_free_noncoherent +EXPORT_SYMBOL vmlinux 0xaadc2b18 tcp_timewait_state_process +EXPORT_SYMBOL vmlinux 0xaae8ab0e acpi_bus_power_manageable +EXPORT_SYMBOL vmlinux 0xaaebe34f mca_write_pos +EXPORT_SYMBOL vmlinux 0xaafdc258 strcasecmp +EXPORT_SYMBOL vmlinux 0xaaffb9a5 acpi_bus_private_data_handler +EXPORT_SYMBOL vmlinux 0xab04234e misc_deregister +EXPORT_SYMBOL vmlinux 0xab0a0c7a n_tty_ioctl +EXPORT_SYMBOL vmlinux 0xab471003 param_array_set +EXPORT_SYMBOL vmlinux 0xab600421 probe_irq_off +EXPORT_SYMBOL vmlinux 0xab61f04e set_pages_wb +EXPORT_SYMBOL vmlinux 0xab65ed80 set_memory_uc +EXPORT_SYMBOL vmlinux 0xab73fe04 security_sb_set_mnt_opts +EXPORT_SYMBOL vmlinux 0xab8ac12c put_tty_driver +EXPORT_SYMBOL vmlinux 0xabcd3845 thermal_zone_unbind_cooling_device +EXPORT_SYMBOL vmlinux 0xabd0c91c rtc_time_to_tm +EXPORT_SYMBOL vmlinux 0xac3b3cee __bitmap_and +EXPORT_SYMBOL vmlinux 0xac58ea5e acpi_unload_table_id +EXPORT_SYMBOL vmlinux 0xac6a8ce4 key_alloc +EXPORT_SYMBOL vmlinux 0xaca08684 inet_sk_rebuild_header +EXPORT_SYMBOL vmlinux 0xaccabc6a in4_pton +EXPORT_SYMBOL vmlinux 0xace3e6c9 neigh_parms_release +EXPORT_SYMBOL vmlinux 0xacef6db1 dentry_open +EXPORT_SYMBOL vmlinux 0xacf4d843 match_strdup +EXPORT_SYMBOL vmlinux 0xacfa76af tcp_getsockopt +EXPORT_SYMBOL vmlinux 0xad0413d4 match_hex +EXPORT_SYMBOL vmlinux 0xad07fcc5 __first_cpu +EXPORT_SYMBOL vmlinux 0xad13c689 acpi_os_execute +EXPORT_SYMBOL vmlinux 0xad1de030 tty_schedule_flip +EXPORT_SYMBOL vmlinux 0xad322e83 __xfrm_policy_check +EXPORT_SYMBOL vmlinux 0xad9edd5f blk_rq_init +EXPORT_SYMBOL vmlinux 0xadaa2657 cpufreq_register_notifier +EXPORT_SYMBOL vmlinux 0xadd20bbc is_container_init +EXPORT_SYMBOL vmlinux 0xae52248c elv_rb_former_request +EXPORT_SYMBOL vmlinux 0xae56cdcc call_usermodehelper_freeinfo +EXPORT_SYMBOL vmlinux 0xae74b0d0 pnp_is_active +EXPORT_SYMBOL vmlinux 0xae75f004 ida_destroy +EXPORT_SYMBOL vmlinux 0xae85cfa6 nf_hook_slow +EXPORT_SYMBOL vmlinux 0xaec655c7 alloc_pages_exact +EXPORT_SYMBOL vmlinux 0xaed8cc77 register_sysctl_table +EXPORT_SYMBOL vmlinux 0xaf36e5db xfrm_lookup +EXPORT_SYMBOL vmlinux 0xaf3fd62f generic_permission +EXPORT_SYMBOL vmlinux 0xaf4b1540 acpi_get_irq_routing_table +EXPORT_SYMBOL vmlinux 0xaf58acdf dget_locked +EXPORT_SYMBOL vmlinux 0xaf6bb468 pci_fixup_device +EXPORT_SYMBOL vmlinux 0xafcdd75e __xfrm_decode_session +EXPORT_SYMBOL vmlinux 0xafe01377 down_read +EXPORT_SYMBOL vmlinux 0xaff85ccd pci_remove_behind_bridge +EXPORT_SYMBOL vmlinux 0xb0686d28 pnp_device_attach +EXPORT_SYMBOL vmlinux 0xb077ef32 acpi_enter_sleep_state +EXPORT_SYMBOL vmlinux 0xb07dfb3d acpi_remove_gpe_handler +EXPORT_SYMBOL vmlinux 0xb0857cf2 devm_ioremap_nocache +EXPORT_SYMBOL vmlinux 0xb08f76ad gen_pool_free +EXPORT_SYMBOL vmlinux 0xb0b847ac __bitmap_full +EXPORT_SYMBOL vmlinux 0xb0e10781 get_option +EXPORT_SYMBOL vmlinux 0xb0f3a7b7 __f_setown +EXPORT_SYMBOL vmlinux 0xb121390a probe_irq_on +EXPORT_SYMBOL vmlinux 0xb13c4dba down_write +EXPORT_SYMBOL vmlinux 0xb16d7f6b vfs_writev +EXPORT_SYMBOL vmlinux 0xb1700629 kernel_getsockopt +EXPORT_SYMBOL vmlinux 0xb19760c3 bitmap_onto +EXPORT_SYMBOL vmlinux 0xb1c3a01a oops_in_progress +EXPORT_SYMBOL vmlinux 0xb1c9c9de block_invalidatepage +EXPORT_SYMBOL vmlinux 0xb1cfad22 rdmsr_on_cpu +EXPORT_SYMBOL vmlinux 0xb1e7c4ef pci_enable_device_io +EXPORT_SYMBOL vmlinux 0xb1f1b58b sock_no_connect +EXPORT_SYMBOL vmlinux 0xb1f975aa unlock_kernel +EXPORT_SYMBOL vmlinux 0xb2017c1d per_cpu__x86_bios_cpu_apicid +EXPORT_SYMBOL vmlinux 0xb20c3bb4 vfs_follow_link +EXPORT_SYMBOL vmlinux 0xb2299a6c bdi_register_dev +EXPORT_SYMBOL vmlinux 0xb25e4224 inet_csk_delete_keepalive_timer +EXPORT_SYMBOL vmlinux 0xb26f4fe0 inet_register_protosw +EXPORT_SYMBOL vmlinux 0xb277b42d netif_rx +EXPORT_SYMBOL vmlinux 0xb29751ae vfs_set_dqblk +EXPORT_SYMBOL vmlinux 0xb29bc8bd idr_remove +EXPORT_SYMBOL vmlinux 0xb2be638a dma_chan_cleanup +EXPORT_SYMBOL vmlinux 0xb2d1caaf send_sig +EXPORT_SYMBOL vmlinux 0xb2d85f18 netlink_broadcast +EXPORT_SYMBOL vmlinux 0xb2efb6be mca_read_stored_pos +EXPORT_SYMBOL vmlinux 0xb2fd5ceb __put_user_4 +EXPORT_SYMBOL vmlinux 0xb3003d1d pci_enable_msix +EXPORT_SYMBOL vmlinux 0xb30abf8d idr_get_new_above +EXPORT_SYMBOL vmlinux 0xb312f05a gnet_stats_finish_copy +EXPORT_SYMBOL vmlinux 0xb31526ee sg_copy_from_buffer +EXPORT_SYMBOL vmlinux 0xb3205415 wait_for_completion_killable +EXPORT_SYMBOL vmlinux 0xb3284531 acpi_dbg_layer +EXPORT_SYMBOL vmlinux 0xb341f7f7 page_put_link +EXPORT_SYMBOL vmlinux 0xb34d4c2e acpi_terminate +EXPORT_SYMBOL vmlinux 0xb352177e find_first_bit +EXPORT_SYMBOL vmlinux 0xb3692eb4 ioremap_wc +EXPORT_SYMBOL vmlinux 0xb376d79d radix_tree_tagged +EXPORT_SYMBOL vmlinux 0xb379cdad xfrm_bundle_ok +EXPORT_SYMBOL vmlinux 0xb382261e force_sig +EXPORT_SYMBOL vmlinux 0xb3a307c6 si_meminfo +EXPORT_SYMBOL vmlinux 0xb3b1fdeb invalidate_partition +EXPORT_SYMBOL vmlinux 0xb3c6fd37 end_dequeued_request +EXPORT_SYMBOL vmlinux 0xb3e0590d acpi_set_current_resources +EXPORT_SYMBOL vmlinux 0xb3f0156d simple_getattr +EXPORT_SYMBOL vmlinux 0xb407b205 ioport_resource +EXPORT_SYMBOL vmlinux 0xb4145f21 alloc_etherdev_mq +EXPORT_SYMBOL vmlinux 0xb4163713 kthread_stop +EXPORT_SYMBOL vmlinux 0xb423dba1 console_blanked +EXPORT_SYMBOL vmlinux 0xb4288979 path_put +EXPORT_SYMBOL vmlinux 0xb429410a posix_acl_from_mode +EXPORT_SYMBOL vmlinux 0xb437e785 netif_rx_ni +EXPORT_SYMBOL vmlinux 0xb4390f9a mcount +EXPORT_SYMBOL vmlinux 0xb43e1637 __xfrm_state_delete +EXPORT_SYMBOL vmlinux 0xb45578b8 memscan +EXPORT_SYMBOL vmlinux 0xb45b24f6 k8_nb_ids +EXPORT_SYMBOL vmlinux 0xb45ccbf0 sock_map_fd +EXPORT_SYMBOL vmlinux 0xb47a8443 skb_over_panic +EXPORT_SYMBOL vmlinux 0xb494e82a br_fdb_put_hook +EXPORT_SYMBOL vmlinux 0xb4ca9447 __kfifo_get +EXPORT_SYMBOL vmlinux 0xb4cee97e dma_async_device_register +EXPORT_SYMBOL vmlinux 0xb4d3eaaf pnp_release_card_device +EXPORT_SYMBOL vmlinux 0xb4de870b tcp_sendmsg +EXPORT_SYMBOL vmlinux 0xb4e78465 vcc_insert_socket +EXPORT_SYMBOL vmlinux 0xb5044271 vsscanf +EXPORT_SYMBOL vmlinux 0xb52955db tcp_sync_mss +EXPORT_SYMBOL vmlinux 0xb54533f7 usecs_to_jiffies +EXPORT_SYMBOL vmlinux 0xb55454e8 pnp_find_dev +EXPORT_SYMBOL vmlinux 0xb5a459dc unregister_blkdev +EXPORT_SYMBOL vmlinux 0xb5d52c27 ec_transaction +EXPORT_SYMBOL vmlinux 0xb5f1c510 grab_cache_page_nowait +EXPORT_SYMBOL vmlinux 0xb60e34a8 nla_memcpy +EXPORT_SYMBOL vmlinux 0xb64a86c7 mark_info_dirty +EXPORT_SYMBOL vmlinux 0xb660114f __inode_dir_notify +EXPORT_SYMBOL vmlinux 0xb678366f int_sqrt +EXPORT_SYMBOL vmlinux 0xb68427ea kfree_skb +EXPORT_SYMBOL vmlinux 0xb68a6987 bio_integrity_split +EXPORT_SYMBOL vmlinux 0xb68b136b elv_rb_add +EXPORT_SYMBOL vmlinux 0xb6a61a86 qdisc_get_rtab +EXPORT_SYMBOL vmlinux 0xb6be6ded tcp_child_process +EXPORT_SYMBOL vmlinux 0xb6ce1c70 generic_file_aio_write_nolock +EXPORT_SYMBOL vmlinux 0xb6d505e8 filemap_write_and_wait +EXPORT_SYMBOL vmlinux 0xb6e227aa rtc_lock +EXPORT_SYMBOL vmlinux 0xb6ed1e53 strncpy +EXPORT_SYMBOL vmlinux 0xb703911e release_firmware +EXPORT_SYMBOL vmlinux 0xb714a981 console_print +EXPORT_SYMBOL vmlinux 0xb719680a del_gendisk +EXPORT_SYMBOL vmlinux 0xb72397d5 printk +EXPORT_SYMBOL vmlinux 0xb74fd805 ip_generic_getfrag +EXPORT_SYMBOL vmlinux 0xb7555f12 timeval_to_jiffies +EXPORT_SYMBOL vmlinux 0xb758b225 acpi_disable_event +EXPORT_SYMBOL vmlinux 0xb79ccf20 mem_map +EXPORT_SYMBOL vmlinux 0xb79f13d4 file_fsync +EXPORT_SYMBOL vmlinux 0xb7a29412 tc_classify_compat +EXPORT_SYMBOL vmlinux 0xb7b61546 crc32_be +EXPORT_SYMBOL vmlinux 0xb82fb5ed dev_alloc_name +EXPORT_SYMBOL vmlinux 0xb850d039 nla_reserve_nohdr +EXPORT_SYMBOL vmlinux 0xb85b2bac vm_stat +EXPORT_SYMBOL vmlinux 0xb86e4ab9 random32 +EXPORT_SYMBOL vmlinux 0xb88531c8 eth_header_cache +EXPORT_SYMBOL vmlinux 0xb894926d schedule_work_on +EXPORT_SYMBOL vmlinux 0xb89af9bf srandom32 +EXPORT_SYMBOL vmlinux 0xb8a5dfa5 find_or_create_page +EXPORT_SYMBOL vmlinux 0xb8ac6cd1 ethtool_op_get_sg +EXPORT_SYMBOL vmlinux 0xb8c69010 __dev_remove_pack +EXPORT_SYMBOL vmlinux 0xb8e6d617 generic_file_buffered_write +EXPORT_SYMBOL vmlinux 0xb8e7ce2c __put_user_8 +EXPORT_SYMBOL vmlinux 0xb8f19929 tcp_alloc_md5sig_pool +EXPORT_SYMBOL vmlinux 0xb9005b99 sk_stop_timer +EXPORT_SYMBOL vmlinux 0xb91253b7 nf_register_queue_handler +EXPORT_SYMBOL vmlinux 0xb91725c2 balance_dirty_pages_ratelimited_nr +EXPORT_SYMBOL vmlinux 0xb922e5b2 dcache_dir_close +EXPORT_SYMBOL vmlinux 0xb93d87b4 bio_unmap_user +EXPORT_SYMBOL vmlinux 0xb940ff04 pnp_disable_dev +EXPORT_SYMBOL vmlinux 0xb942941d kernel_recvmsg +EXPORT_SYMBOL vmlinux 0xb96ac3d4 mnt_pin +EXPORT_SYMBOL vmlinux 0xb9878842 pnpbios_protocol +EXPORT_SYMBOL vmlinux 0xb98a0185 rtc_tm_to_time +EXPORT_SYMBOL vmlinux 0xb99b859f sock_no_sendpage +EXPORT_SYMBOL vmlinux 0xb9b865e6 inet_frags_init +EXPORT_SYMBOL vmlinux 0xb9c74bf1 gen_kill_estimator +EXPORT_SYMBOL vmlinux 0xb9d287f8 get_super +EXPORT_SYMBOL vmlinux 0xb9e83510 generic_getxattr +EXPORT_SYMBOL vmlinux 0xb9fd2205 add_efi_memmap +EXPORT_SYMBOL vmlinux 0xba090335 end_page_writeback +EXPORT_SYMBOL vmlinux 0xba2d8594 ec_read +EXPORT_SYMBOL vmlinux 0xba385456 generic_setxattr +EXPORT_SYMBOL vmlinux 0xba497f13 loops_per_jiffy +EXPORT_SYMBOL vmlinux 0xba699274 sk_free +EXPORT_SYMBOL vmlinux 0xba85f68f kmap_atomic +EXPORT_SYMBOL vmlinux 0xbad05da7 ethtool_op_get_link +EXPORT_SYMBOL vmlinux 0xbad5e487 dmam_declare_coherent_memory +EXPORT_SYMBOL vmlinux 0xbad6c11d path_lookup +EXPORT_SYMBOL vmlinux 0xbb167766 fb_var_to_videomode +EXPORT_SYMBOL vmlinux 0xbb189cad disallow_signal +EXPORT_SYMBOL vmlinux 0xbb3944f5 netdev_rx_csum_fault +EXPORT_SYMBOL vmlinux 0xbb5d343d xfrm_get_acqseq +EXPORT_SYMBOL vmlinux 0xbb7dde88 blk_queue_update_dma_alignment +EXPORT_SYMBOL vmlinux 0xbb83bd29 xfrm_cfg_mutex +EXPORT_SYMBOL vmlinux 0xbb89de17 ida_init +EXPORT_SYMBOL vmlinux 0xbb8e709f nf_unregister_sockopt +EXPORT_SYMBOL vmlinux 0xbb921e53 vfs_quota_on_mount +EXPORT_SYMBOL vmlinux 0xbba2723b alloc_fcdev +EXPORT_SYMBOL vmlinux 0xbbb8bd93 sock_no_getname +EXPORT_SYMBOL vmlinux 0xbbc8e804 param_set_ushort +EXPORT_SYMBOL vmlinux 0xbbcccab4 elv_rb_del +EXPORT_SYMBOL vmlinux 0xbbf04131 generic_writepages +EXPORT_SYMBOL vmlinux 0xbbfe98b0 kobject_add +EXPORT_SYMBOL vmlinux 0xbc65d542 iov_iter_copy_from_user_atomic +EXPORT_SYMBOL vmlinux 0xbc7cd4b2 vfs_path_lookup +EXPORT_SYMBOL vmlinux 0xbc860dd8 seq_read +EXPORT_SYMBOL vmlinux 0xbc972596 pci_bus_assign_resources +EXPORT_SYMBOL vmlinux 0xbca105c7 lookup_one_len +EXPORT_SYMBOL vmlinux 0xbcc308bb strnlen_user +EXPORT_SYMBOL vmlinux 0xbcf0f4d8 k8_northbridges +EXPORT_SYMBOL vmlinux 0xbd233944 get_sb_pseudo +EXPORT_SYMBOL vmlinux 0xbd68054b nlmsg_notify +EXPORT_SYMBOL vmlinux 0xbdbc5213 backlight_device_register +EXPORT_SYMBOL vmlinux 0xbdc40bf2 iov_iter_copy_from_user +EXPORT_SYMBOL vmlinux 0xbe0c691c tcf_hash_create +EXPORT_SYMBOL vmlinux 0xbe0e5118 nla_memcmp +EXPORT_SYMBOL vmlinux 0xbe49ab57 vmalloc_to_page +EXPORT_SYMBOL vmlinux 0xbe4a565b xrlim_allow +EXPORT_SYMBOL vmlinux 0xbe508b28 flock_lock_file_wait +EXPORT_SYMBOL vmlinux 0xbe6aeb67 dmam_free_coherent +EXPORT_SYMBOL vmlinux 0xbe6f03ab unregister_framebuffer +EXPORT_SYMBOL vmlinux 0xbe814995 xfrm_input +EXPORT_SYMBOL vmlinux 0xbe895c16 deregister_atm_ioctl +EXPORT_SYMBOL vmlinux 0xbeb4c9be remove_proc_entry +EXPORT_SYMBOL vmlinux 0xbecadcf2 task_pgrp_nr_ns +EXPORT_SYMBOL vmlinux 0xbef43296 console_conditional_schedule +EXPORT_SYMBOL vmlinux 0xbf095db3 kill_pid +EXPORT_SYMBOL vmlinux 0xbf13b163 rwsem_down_read_failed +EXPORT_SYMBOL vmlinux 0xbf282c90 pcibios_set_irq_routing +EXPORT_SYMBOL vmlinux 0xbf341a45 inode_needs_sync +EXPORT_SYMBOL vmlinux 0xbf48a7c7 per_cpu__cpu_info +EXPORT_SYMBOL vmlinux 0xbf4af4fb cpufreq_get_policy +EXPORT_SYMBOL vmlinux 0xbf5f0f16 sock_no_recvmsg +EXPORT_SYMBOL vmlinux 0xbf60e532 sock_create_lite +EXPORT_SYMBOL vmlinux 0xbf682bee fb_validate_mode +EXPORT_SYMBOL vmlinux 0xbf7fd2f5 schedule_timeout_killable +EXPORT_SYMBOL vmlinux 0xbf8b39e9 isapnp_present +EXPORT_SYMBOL vmlinux 0xbf9bcc8d __cap_empty_set +EXPORT_SYMBOL vmlinux 0xbfc177bc iowrite32_rep +EXPORT_SYMBOL vmlinux 0xbfe5f5c6 xfrm_init_state +EXPORT_SYMBOL vmlinux 0xbfe8c1b4 blk_alloc_queue_node +EXPORT_SYMBOL vmlinux 0xc003c637 __strncpy_from_user +EXPORT_SYMBOL vmlinux 0xc01c94f6 sysctl_ms_jiffies +EXPORT_SYMBOL vmlinux 0xc01eed33 __copy_from_user_ll_nozero +EXPORT_SYMBOL vmlinux 0xc0230f15 xfrm4_prepare_output +EXPORT_SYMBOL vmlinux 0xc045ad4e timespec_trunc +EXPORT_SYMBOL vmlinux 0xc0580937 rb_erase +EXPORT_SYMBOL vmlinux 0xc0988027 set_bdi_congested +EXPORT_SYMBOL vmlinux 0xc0994f58 register_nls +EXPORT_SYMBOL vmlinux 0xc0a3d105 find_next_bit +EXPORT_SYMBOL vmlinux 0xc0b8edc7 set_disk_ro +EXPORT_SYMBOL vmlinux 0xc0bc923a pci_bus_read_config_word +EXPORT_SYMBOL vmlinux 0xc0f65988 machine_real_restart +EXPORT_SYMBOL vmlinux 0xc1087228 set_pages_nx +EXPORT_SYMBOL vmlinux 0xc11d8093 iov_shorten +EXPORT_SYMBOL vmlinux 0xc1423573 qdisc_calculate_pkt_len +EXPORT_SYMBOL vmlinux 0xc147c874 get_write_access +EXPORT_SYMBOL vmlinux 0xc190a2c8 udplite_prot +EXPORT_SYMBOL vmlinux 0xc197ff7c bio_split +EXPORT_SYMBOL vmlinux 0xc1ca3fc7 tcp_rcv_established +EXPORT_SYMBOL vmlinux 0xc1ce2d53 gnet_stats_copy_basic +EXPORT_SYMBOL vmlinux 0xc1e1f497 cdev_init +EXPORT_SYMBOL vmlinux 0xc1f7a269 input_register_handle +EXPORT_SYMBOL vmlinux 0xc1ff5853 skb_abort_seq_read +EXPORT_SYMBOL vmlinux 0xc2248c8d make_bad_inode +EXPORT_SYMBOL vmlinux 0xc254af48 dcache_lock +EXPORT_SYMBOL vmlinux 0xc256e762 __bitmap_equal +EXPORT_SYMBOL vmlinux 0xc280a525 __copy_from_user_ll +EXPORT_SYMBOL vmlinux 0xc2abda0f vfs_quota_sync +EXPORT_SYMBOL vmlinux 0xc2aea626 set_pages_x +EXPORT_SYMBOL vmlinux 0xc2d711e1 krealloc +EXPORT_SYMBOL vmlinux 0xc2e587d1 reset_devices +EXPORT_SYMBOL vmlinux 0xc2f963fa nf_unregister_hook +EXPORT_SYMBOL vmlinux 0xc33f6f4c on_each_cpu +EXPORT_SYMBOL vmlinux 0xc3485019 udp_prot +EXPORT_SYMBOL vmlinux 0xc34eb9db key_link +EXPORT_SYMBOL vmlinux 0xc38e5923 udp_stats_in6 +EXPORT_SYMBOL vmlinux 0xc3970edf simple_rmdir +EXPORT_SYMBOL vmlinux 0xc3a127d5 acpi_notifier_call_chain +EXPORT_SYMBOL vmlinux 0xc3aaf0a9 __put_user_1 +EXPORT_SYMBOL vmlinux 0xc3c52517 locks_mandatory_area +EXPORT_SYMBOL vmlinux 0xc3cf1128 in_group_p +EXPORT_SYMBOL vmlinux 0xc3d14b5f sk_stream_error +EXPORT_SYMBOL vmlinux 0xc3dc74b0 blk_queue_dma_pad +EXPORT_SYMBOL vmlinux 0xc3fa6a59 memchr +EXPORT_SYMBOL vmlinux 0xc402cc99 register_acpi_notifier +EXPORT_SYMBOL vmlinux 0xc40668e1 elv_rb_find +EXPORT_SYMBOL vmlinux 0xc409c11b try_to_free_buffers +EXPORT_SYMBOL vmlinux 0xc4544af8 d_path +EXPORT_SYMBOL vmlinux 0xc47f625d remove_arg_zero +EXPORT_SYMBOL vmlinux 0xc490f210 dev_kfree_skb_any +EXPORT_SYMBOL vmlinux 0xc499ae1e kstrdup +EXPORT_SYMBOL vmlinux 0xc4c4a663 __neigh_for_each_release +EXPORT_SYMBOL vmlinux 0xc4cba526 filp_close +EXPORT_SYMBOL vmlinux 0xc4f15fac sock_no_bind +EXPORT_SYMBOL vmlinux 0xc521ee22 netlink_dump_start +EXPORT_SYMBOL vmlinux 0xc52f5714 fb_videomode_to_var +EXPORT_SYMBOL vmlinux 0xc5534d64 ioread16 +EXPORT_SYMBOL vmlinux 0xc55f7dc7 _write_trylock +EXPORT_SYMBOL vmlinux 0xc5718627 sg_copy_to_buffer +EXPORT_SYMBOL vmlinux 0xc574404f generic_show_options +EXPORT_SYMBOL vmlinux 0xc57a488f pci_add_new_bus +EXPORT_SYMBOL vmlinux 0xc582b2e9 serial8250_register_port +EXPORT_SYMBOL vmlinux 0xc5844fb8 __per_cpu_offset +EXPORT_SYMBOL vmlinux 0xc5a122ab qdisc_destroy +EXPORT_SYMBOL vmlinux 0xc5b2d707 neigh_connected_output +EXPORT_SYMBOL vmlinux 0xc5e2e193 vfs_quota_off +EXPORT_SYMBOL vmlinux 0xc6052cb9 elv_dequeue_request +EXPORT_SYMBOL vmlinux 0xc60a7746 tcp_v4_destroy_sock +EXPORT_SYMBOL vmlinux 0xc6116454 pagevec_lookup_tag +EXPORT_SYMBOL vmlinux 0xc63e2236 tcf_exts_dump +EXPORT_SYMBOL vmlinux 0xc642a1a6 sk_receive_skb +EXPORT_SYMBOL vmlinux 0xc6c1f35a pci_bus_read_config_dword +EXPORT_SYMBOL vmlinux 0xc6c9cf14 blk_queue_update_dma_pad +EXPORT_SYMBOL vmlinux 0xc6d671da xfrm_state_delete +EXPORT_SYMBOL vmlinux 0xc6ebbbed directly_mappable_cdev_bdi +EXPORT_SYMBOL vmlinux 0xc6f2e002 textsearch_find_continuous +EXPORT_SYMBOL vmlinux 0xc6fa3578 proc_dointvec_userhz_jiffies +EXPORT_SYMBOL vmlinux 0xc7208c3a serial8250_resume_port +EXPORT_SYMBOL vmlinux 0xc7a4fbed rtnl_lock +EXPORT_SYMBOL vmlinux 0xc7e2ea03 framebuffer_alloc +EXPORT_SYMBOL vmlinux 0xc7ec6c27 strspn +EXPORT_SYMBOL vmlinux 0xc8187c8f skb_push +EXPORT_SYMBOL vmlinux 0xc84a72da proc_dostring +EXPORT_SYMBOL vmlinux 0xc8b57c27 autoremove_wake_function +EXPORT_SYMBOL vmlinux 0xc8c3fda8 dev_unicast_delete +EXPORT_SYMBOL vmlinux 0xc8ca3e25 acpi_get_child +EXPORT_SYMBOL vmlinux 0xc926b964 blk_register_region +EXPORT_SYMBOL vmlinux 0xc93b8597 eth_type_trans +EXPORT_SYMBOL vmlinux 0xc94a9dc3 bdput +EXPORT_SYMBOL vmlinux 0xc95d4651 tcp_simple_retransmit +EXPORT_SYMBOL vmlinux 0xc95da1a0 seq_printf +EXPORT_SYMBOL vmlinux 0xc998d641 icmp_err_convert +EXPORT_SYMBOL vmlinux 0xc9a728c6 inet_sendmsg +EXPORT_SYMBOL vmlinux 0xc9ab2eef acpi_os_wait_events_complete +EXPORT_SYMBOL vmlinux 0xc9c498fc block_write_full_page +EXPORT_SYMBOL vmlinux 0xc9d16d8d sock_create +EXPORT_SYMBOL vmlinux 0xc9da9e3a dev_unicast_sync +EXPORT_SYMBOL vmlinux 0xc9e03ed5 bio_put +EXPORT_SYMBOL vmlinux 0xc9e1160e do_SAK +EXPORT_SYMBOL vmlinux 0xca03cabe call_usermodehelper_setcleanup +EXPORT_SYMBOL vmlinux 0xca207cab inode_sub_bytes +EXPORT_SYMBOL vmlinux 0xca21960f put_filp +EXPORT_SYMBOL vmlinux 0xca323db8 __splice_from_pipe +EXPORT_SYMBOL vmlinux 0xca548fce iw_handler_get_spy +EXPORT_SYMBOL vmlinux 0xca5d0f8c skb_trim +EXPORT_SYMBOL vmlinux 0xca6a603a tcp_recvmsg +EXPORT_SYMBOL vmlinux 0xca71e96f alloc_disk +EXPORT_SYMBOL vmlinux 0xca8acc78 acpi_dbg_level +EXPORT_SYMBOL vmlinux 0xcacc54a1 generic_make_request +EXPORT_SYMBOL vmlinux 0xcb20e72c __pagevec_lru_add +EXPORT_SYMBOL vmlinux 0xcb32da10 param_set_int +EXPORT_SYMBOL vmlinux 0xcb4a33bf console_stop +EXPORT_SYMBOL vmlinux 0xcb6beb40 hweight32 +EXPORT_SYMBOL vmlinux 0xcb7131fb fb_get_options +EXPORT_SYMBOL vmlinux 0xcb733bf2 acpi_bus_set_power +EXPORT_SYMBOL vmlinux 0xcb8481fe kernel_setsockopt +EXPORT_SYMBOL vmlinux 0xcb95c94e simple_fill_super +EXPORT_SYMBOL vmlinux 0xcbdac96c d_rehash +EXPORT_SYMBOL vmlinux 0xcbdf9cda d_find_alias +EXPORT_SYMBOL vmlinux 0xcbed0287 vm_insert_mixed +EXPORT_SYMBOL vmlinux 0xcc248d26 serial8250_suspend_port +EXPORT_SYMBOL vmlinux 0xcc36f32e fb_unregister_client +EXPORT_SYMBOL vmlinux 0xcc380848 unregister_sysrq_key +EXPORT_SYMBOL vmlinux 0xcc39edb4 dma_alloc_coherent +EXPORT_SYMBOL vmlinux 0xcc5005fe msleep_interruptible +EXPORT_SYMBOL vmlinux 0xcc51ee50 dma_spin_lock +EXPORT_SYMBOL vmlinux 0xcc6694eb icmp_send +EXPORT_SYMBOL vmlinux 0xcc7fa952 local_bh_enable_ip +EXPORT_SYMBOL vmlinux 0xcc855b77 alloc_file +EXPORT_SYMBOL vmlinux 0xcc8732f4 tty_unregister_driver +EXPORT_SYMBOL vmlinux 0xcc8bf8fd simple_pin_fs +EXPORT_SYMBOL vmlinux 0xccf09278 inet_csk_init_xmit_timers +EXPORT_SYMBOL vmlinux 0xccf1251c fsync_bdev +EXPORT_SYMBOL vmlinux 0xcd3f2997 vm_insert_pfn +EXPORT_SYMBOL vmlinux 0xcd6916b1 pci_bus_write_config_dword +EXPORT_SYMBOL vmlinux 0xcd86dbd3 register_sysrq_key +EXPORT_SYMBOL vmlinux 0xcdd8d85e generic_file_mmap +EXPORT_SYMBOL vmlinux 0xcde7f7f5 alloc_fddidev +EXPORT_SYMBOL vmlinux 0xce36ded6 sysctl_tcp_mem +EXPORT_SYMBOL vmlinux 0xce4904a4 acpi_leave_sleep_state +EXPORT_SYMBOL vmlinux 0xce4a332e kernel_sendpage +EXPORT_SYMBOL vmlinux 0xce5ac24f zlib_inflate_workspacesize +EXPORT_SYMBOL vmlinux 0xce9d0cc0 blkdev_issue_flush +EXPORT_SYMBOL vmlinux 0xcefcd99a serial8250_unregister_port +EXPORT_SYMBOL vmlinux 0xcf047c83 acpi_disable_gpe +EXPORT_SYMBOL vmlinux 0xcf3c97c4 splice_direct_to_actor +EXPORT_SYMBOL vmlinux 0xcf7ce191 uart_suspend_port +EXPORT_SYMBOL vmlinux 0xcf915f6a d_alloc_name +EXPORT_SYMBOL vmlinux 0xcfadd723 __percpu_counter_add +EXPORT_SYMBOL vmlinux 0xcfb536d1 find_vma +EXPORT_SYMBOL vmlinux 0xcfc36594 d_validate +EXPORT_SYMBOL vmlinux 0xcfce5d71 flush_old_exec +EXPORT_SYMBOL vmlinux 0xcfd3018e set_normalized_timespec +EXPORT_SYMBOL vmlinux 0xd0181f4f __bitmap_xor +EXPORT_SYMBOL vmlinux 0xd02088b4 d_move +EXPORT_SYMBOL vmlinux 0xd0269974 test_set_page_writeback +EXPORT_SYMBOL vmlinux 0xd02cc869 __bitmap_andnot +EXPORT_SYMBOL vmlinux 0xd0305e80 input_set_capability +EXPORT_SYMBOL vmlinux 0xd04530db __wait_on_buffer +EXPORT_SYMBOL vmlinux 0xd080db3f is_bad_inode +EXPORT_SYMBOL vmlinux 0xd08197fa acpi_load_tables +EXPORT_SYMBOL vmlinux 0xd08d1aff dst_discard +EXPORT_SYMBOL vmlinux 0xd0d8621b strlen +EXPORT_SYMBOL vmlinux 0xd0e286fe sock_wmalloc +EXPORT_SYMBOL vmlinux 0xd0ee38b8 schedule_timeout_uninterruptible +EXPORT_SYMBOL vmlinux 0xd128550f nf_unregister_queue_handler +EXPORT_SYMBOL vmlinux 0xd1472061 acpi_pci_register_driver +EXPORT_SYMBOL vmlinux 0xd18b6eb2 acpi_unmap_lsapic +EXPORT_SYMBOL vmlinux 0xd19e94c2 pci_scan_bridge +EXPORT_SYMBOL vmlinux 0xd1b1cc17 dquot_release +EXPORT_SYMBOL vmlinux 0xd1f6c5f3 smp_num_siblings +EXPORT_SYMBOL vmlinux 0xd1f91bcd dev_base_lock +EXPORT_SYMBOL vmlinux 0xd232aa61 aio_put_req +EXPORT_SYMBOL vmlinux 0xd23e8eac prepare_binprm +EXPORT_SYMBOL vmlinux 0xd251d7b0 security_socket_getpeersec_dgram +EXPORT_SYMBOL vmlinux 0xd2555f19 jiffies_64_to_clock_t +EXPORT_SYMBOL vmlinux 0xd25b5856 inet_frags_exit_net +EXPORT_SYMBOL vmlinux 0xd25d4f74 console_blank_hook +EXPORT_SYMBOL vmlinux 0xd267d42c down_killable +EXPORT_SYMBOL vmlinux 0xd2965f6f kthread_should_stop +EXPORT_SYMBOL vmlinux 0xd2981b51 request_key_async_with_auxdata +EXPORT_SYMBOL vmlinux 0xd2a941d4 sg_init_table +EXPORT_SYMBOL vmlinux 0xd2a94276 pci_setup_cardbus +EXPORT_SYMBOL vmlinux 0xd2e1f294 skb_queue_purge +EXPORT_SYMBOL vmlinux 0xd323af89 nf_unregister_hooks +EXPORT_SYMBOL vmlinux 0xd34f0c62 gen_pool_create +EXPORT_SYMBOL vmlinux 0xd3951da4 acpi_resource_to_address64 +EXPORT_SYMBOL vmlinux 0xd3a4b617 fifo_create_dflt +EXPORT_SYMBOL vmlinux 0xd3a7e1c8 blk_complete_request +EXPORT_SYMBOL vmlinux 0xd3aa24cf register_gifconf +EXPORT_SYMBOL vmlinux 0xd3b7fe17 vlan_ioctl_set +EXPORT_SYMBOL vmlinux 0xd3cd3f1b kthread_bind +EXPORT_SYMBOL vmlinux 0xd3f74cf1 interruptible_sleep_on_timeout +EXPORT_SYMBOL vmlinux 0xd3f8e6f8 __ip_select_ident +EXPORT_SYMBOL vmlinux 0xd406202b do_sync_write +EXPORT_SYMBOL vmlinux 0xd413242c kmem_cache_destroy +EXPORT_SYMBOL vmlinux 0xd42b7232 _write_unlock_bh +EXPORT_SYMBOL vmlinux 0xd48dab25 __free_pages +EXPORT_SYMBOL vmlinux 0xd4a7fe74 inet_frag_destroy +EXPORT_SYMBOL vmlinux 0xd505edbc xfrm_policy_byid +EXPORT_SYMBOL vmlinux 0xd523cf3f skb_append_datato_frags +EXPORT_SYMBOL vmlinux 0xd554edae d_instantiate +EXPORT_SYMBOL vmlinux 0xd55dce9a xfrm_state_lookup_byaddr +EXPORT_SYMBOL vmlinux 0xd5688a7a radix_tree_insert +EXPORT_SYMBOL vmlinux 0xd594e0dc km_query +EXPORT_SYMBOL vmlinux 0xd5b037e1 kref_put +EXPORT_SYMBOL vmlinux 0xd5cb16b9 tty_port_free_xmit_buf +EXPORT_SYMBOL vmlinux 0xd6035d05 do_settimeofday +EXPORT_SYMBOL vmlinux 0xd62981ac sb_has_dirty_inodes +EXPORT_SYMBOL vmlinux 0xd62c833f schedule_timeout +EXPORT_SYMBOL vmlinux 0xd640cdb0 generic_removexattr +EXPORT_SYMBOL vmlinux 0xd6a78d08 smp_call_function_single +EXPORT_SYMBOL vmlinux 0xd6b33026 cpu_khz +EXPORT_SYMBOL vmlinux 0xd6ee688f vmalloc +EXPORT_SYMBOL vmlinux 0xd73571d6 brioctl_set +EXPORT_SYMBOL vmlinux 0xd764e15c seq_open_private +EXPORT_SYMBOL vmlinux 0xd77a2498 mca_device_status +EXPORT_SYMBOL vmlinux 0xd79b5a02 allow_signal +EXPORT_SYMBOL vmlinux 0xd7a6fafa panic_notifier_list +EXPORT_SYMBOL vmlinux 0xd7d36d1a idr_find +EXPORT_SYMBOL vmlinux 0xd7dd777b reserve_perfctr_nmi +EXPORT_SYMBOL vmlinux 0xd7e16bee ___pskb_trim +EXPORT_SYMBOL vmlinux 0xd7f4e894 skb_gso_segment +EXPORT_SYMBOL vmlinux 0xd824adf0 fb_firmware_edid +EXPORT_SYMBOL vmlinux 0xd876ece8 inet_csk_destroy_sock +EXPORT_SYMBOL vmlinux 0xd8792631 km_new_mapping +EXPORT_SYMBOL vmlinux 0xd88f695a __mod_timer +EXPORT_SYMBOL vmlinux 0xd89da37f movable_zone +EXPORT_SYMBOL vmlinux 0xd89e09cf kobject_del +EXPORT_SYMBOL vmlinux 0xd8a2ab95 in_egroup_p +EXPORT_SYMBOL vmlinux 0xd8cd9356 ipv6_skip_exthdr +EXPORT_SYMBOL vmlinux 0xd8da8437 write_one_page +EXPORT_SYMBOL vmlinux 0xd8e484f0 register_chrdev_region +EXPORT_SYMBOL vmlinux 0xd9091363 acpi_install_notify_handler +EXPORT_SYMBOL vmlinux 0xd924d0a9 bio_copy_kern +EXPORT_SYMBOL vmlinux 0xd94f007c __blockdev_direct_IO +EXPORT_SYMBOL vmlinux 0xd9847637 unregister_quota_format +EXPORT_SYMBOL vmlinux 0xd985dc99 mempool_free_pages +EXPORT_SYMBOL vmlinux 0xd996d859 idr_pre_get +EXPORT_SYMBOL vmlinux 0xd9c272aa mca_mark_as_unused +EXPORT_SYMBOL vmlinux 0xd9d79739 put_disk +EXPORT_SYMBOL vmlinux 0xd9dc2880 cpu_mask_all +EXPORT_SYMBOL vmlinux 0xd9ddf09a unlock_new_inode +EXPORT_SYMBOL vmlinux 0xd9ee078c tcp_v4_syn_recv_sock +EXPORT_SYMBOL vmlinux 0xd9ff3424 generic_unplug_device +EXPORT_SYMBOL vmlinux 0xda08afd6 pnp_possible_config +EXPORT_SYMBOL vmlinux 0xda08c0d7 pcibios_get_irq_routing_table +EXPORT_SYMBOL vmlinux 0xda0a6b0e acpi_map_lsapic +EXPORT_SYMBOL vmlinux 0xda1a7335 kasprintf +EXPORT_SYMBOL vmlinux 0xda63aff0 tcf_hash_check +EXPORT_SYMBOL vmlinux 0xda6a70de set_bh_page +EXPORT_SYMBOL vmlinux 0xda7ca6cb fb_mode_is_equal +EXPORT_SYMBOL vmlinux 0xda8af7ad fb_find_nearest_mode +EXPORT_SYMBOL vmlinux 0xda8fd495 isapnp_write_byte +EXPORT_SYMBOL vmlinux 0xda928914 nmi_watchdog +EXPORT_SYMBOL vmlinux 0xdaa57ec3 totalhigh_pages +EXPORT_SYMBOL vmlinux 0xdabe6dfd neigh_update +EXPORT_SYMBOL vmlinux 0xdad96e87 thermal_cooling_device_unregister +EXPORT_SYMBOL vmlinux 0xdaef4d97 blk_start_queueing +EXPORT_SYMBOL vmlinux 0xdb3c15ee ethtool_op_get_flags +EXPORT_SYMBOL vmlinux 0xdb663b3b skb_unlink +EXPORT_SYMBOL vmlinux 0xdb6ce750 copy_io_context +EXPORT_SYMBOL vmlinux 0xdb864d65 iov_iter_single_seg_count +EXPORT_SYMBOL vmlinux 0xdbaee4b6 tcp_tso_segment +EXPORT_SYMBOL vmlinux 0xdbb3d5da iw_handler_get_thrspy +EXPORT_SYMBOL vmlinux 0xdbcd416e sysctl_ip_nonlocal_bind +EXPORT_SYMBOL vmlinux 0xdbfe447d vfs_write +EXPORT_SYMBOL vmlinux 0xdc14eda7 pci_pci_problems +EXPORT_SYMBOL vmlinux 0xdc1be3f0 sk_common_release +EXPORT_SYMBOL vmlinux 0xdc2adb35 add_taint +EXPORT_SYMBOL vmlinux 0xdc43a9c8 daemonize +EXPORT_SYMBOL vmlinux 0xdc442c6a dquot_free_space +EXPORT_SYMBOL vmlinux 0xdc5cdb72 simple_readpage +EXPORT_SYMBOL vmlinux 0xdc873a70 screen_info +EXPORT_SYMBOL vmlinux 0xdc8e6a89 simple_empty +EXPORT_SYMBOL vmlinux 0xdcd50d27 dquot_initialize +EXPORT_SYMBOL vmlinux 0xdcee764c register_atm_ioctl +EXPORT_SYMBOL vmlinux 0xdcf59e28 default_llseek +EXPORT_SYMBOL vmlinux 0xdd0a2ba2 strlcat +EXPORT_SYMBOL vmlinux 0xdd2e9786 read_cache_pages +EXPORT_SYMBOL vmlinux 0xdd5aa779 pci_get_device +EXPORT_SYMBOL vmlinux 0xdd5aad98 __ht_create_irq +EXPORT_SYMBOL vmlinux 0xdd6bfccd radix_tree_tag_set +EXPORT_SYMBOL vmlinux 0xdd8daf5f __lookup_hash +EXPORT_SYMBOL vmlinux 0xdda63d36 dma_async_memcpy_pg_to_pg +EXPORT_SYMBOL vmlinux 0xddad899f ll_rw_block +EXPORT_SYMBOL vmlinux 0xddc1ac11 bioset_integrity_free +EXPORT_SYMBOL vmlinux 0xdddae72b vfs_readlink +EXPORT_SYMBOL vmlinux 0xddee4ad5 blk_queue_bounce_limit +EXPORT_SYMBOL vmlinux 0xddeef053 vfs_stat +EXPORT_SYMBOL vmlinux 0xde2a3061 fb_show_logo +EXPORT_SYMBOL vmlinux 0xde656978 fb_get_mode +EXPORT_SYMBOL vmlinux 0xde65b995 simple_set_mnt +EXPORT_SYMBOL vmlinux 0xde75b689 set_irq_type +EXPORT_SYMBOL vmlinux 0xde9360ba totalram_pages +EXPORT_SYMBOL vmlinux 0xde99ac9d dma_sync_wait +EXPORT_SYMBOL vmlinux 0xdef0a908 tcf_em_tree_destroy +EXPORT_SYMBOL vmlinux 0xdf087d72 ip_cmsg_recv +EXPORT_SYMBOL vmlinux 0xdf0da3cc acpi_get_devices +EXPORT_SYMBOL vmlinux 0xdf4236bd inet_stream_connect +EXPORT_SYMBOL vmlinux 0xdf461ac0 __nla_reserve +EXPORT_SYMBOL vmlinux 0xdf46cbaf ethtool_op_set_tx_ipv6_csum +EXPORT_SYMBOL vmlinux 0xdf60cc27 __print_symbol +EXPORT_SYMBOL vmlinux 0xdf744e16 netif_receive_skb +EXPORT_SYMBOL vmlinux 0xdf8c695a __ndelay +EXPORT_SYMBOL vmlinux 0xdf929370 fs_overflowgid +EXPORT_SYMBOL vmlinux 0xdfba47eb kunmap +EXPORT_SYMBOL vmlinux 0xdfe8decf sk_stream_wait_memory +EXPORT_SYMBOL vmlinux 0xdff6866a eisa_bus_type +EXPORT_SYMBOL vmlinux 0xe057baf8 sock_setsockopt +EXPORT_SYMBOL vmlinux 0xe05f1f06 sock_no_getsockopt +EXPORT_SYMBOL vmlinux 0xe06b4431 wait_for_key_construction +EXPORT_SYMBOL vmlinux 0xe06e91d6 ethtool_op_set_tso +EXPORT_SYMBOL vmlinux 0xe075d6eb iter_div_u64_rem +EXPORT_SYMBOL vmlinux 0xe0833add read_dev_sector +EXPORT_SYMBOL vmlinux 0xe0868620 pci_target_state +EXPORT_SYMBOL vmlinux 0xe094ef39 sg_next +EXPORT_SYMBOL vmlinux 0xe0a05e80 nla_put_nohdr +EXPORT_SYMBOL vmlinux 0xe0a501e3 idr_remove_all +EXPORT_SYMBOL vmlinux 0xe0ac8bd2 acpi_bus_generate_netlink_event +EXPORT_SYMBOL vmlinux 0xe0b13336 argv_free +EXPORT_SYMBOL vmlinux 0xe0c1248e generic_splice_sendpage +EXPORT_SYMBOL vmlinux 0xe0e35950 input_register_handler +EXPORT_SYMBOL vmlinux 0xe1142199 add_to_page_cache_locked +EXPORT_SYMBOL vmlinux 0xe12e28d3 skb_copy_datagram_iovec +EXPORT_SYMBOL vmlinux 0xe13b724c pneigh_lookup +EXPORT_SYMBOL vmlinux 0xe13cd8a7 dmi_name_in_vendors +EXPORT_SYMBOL vmlinux 0xe15aeee2 downgrade_write +EXPORT_SYMBOL vmlinux 0xe16f8a79 per_cpu__irq_regs +EXPORT_SYMBOL vmlinux 0xe1761617 security_inet_conn_request +EXPORT_SYMBOL vmlinux 0xe17725e2 register_snap_client +EXPORT_SYMBOL vmlinux 0xe1b1aa53 neigh_destroy +EXPORT_SYMBOL vmlinux 0xe1b949b0 atm_alloc_charge +EXPORT_SYMBOL vmlinux 0xe1c5cc52 xfrm_state_register_afinfo +EXPORT_SYMBOL vmlinux 0xe1c9f15a pcix_set_mmrbc +EXPORT_SYMBOL vmlinux 0xe1dfeb16 find_task_by_vpid +EXPORT_SYMBOL vmlinux 0xe1ecc966 tcp_initialize_rcv_mss +EXPORT_SYMBOL vmlinux 0xe2059fb9 backlight_device_unregister +EXPORT_SYMBOL vmlinux 0xe237bc07 inet_put_port +EXPORT_SYMBOL vmlinux 0xe24d3a97 jiffies_64 +EXPORT_SYMBOL vmlinux 0xe2924872 in_dev_finish_destroy +EXPORT_SYMBOL vmlinux 0xe2d5255a strcmp +EXPORT_SYMBOL vmlinux 0xe2fae716 kmemdup +EXPORT_SYMBOL vmlinux 0xe328eec4 search_binary_handler +EXPORT_SYMBOL vmlinux 0xe351633f genl_register_family +EXPORT_SYMBOL vmlinux 0xe3588d77 vfs_link +EXPORT_SYMBOL vmlinux 0xe3652eef vmap +EXPORT_SYMBOL vmlinux 0xe3987435 inet_bind +EXPORT_SYMBOL vmlinux 0xe3c60158 blk_stop_queue +EXPORT_SYMBOL vmlinux 0xe3fbe148 acpi_install_table_handler +EXPORT_SYMBOL vmlinux 0xe42d8239 sget +EXPORT_SYMBOL vmlinux 0xe42e295f pci_clear_mwi +EXPORT_SYMBOL vmlinux 0xe43617f7 acpi_gbl_FADT +EXPORT_SYMBOL vmlinux 0xe447afc8 neigh_event_ns +EXPORT_SYMBOL vmlinux 0xe449e30f dma_pool_alloc +EXPORT_SYMBOL vmlinux 0xe454b949 names_cachep +EXPORT_SYMBOL vmlinux 0xe456bd3a complete +EXPORT_SYMBOL vmlinux 0xe484e35f ioread32 +EXPORT_SYMBOL vmlinux 0xe4870354 _read_trylock +EXPORT_SYMBOL vmlinux 0xe48f3039 ida_get_new_above +EXPORT_SYMBOL vmlinux 0xe499aa3d kobject_put +EXPORT_SYMBOL vmlinux 0xe49a9db8 gnet_stats_start_copy +EXPORT_SYMBOL vmlinux 0xe4c1df3e _read_lock_bh +EXPORT_SYMBOL vmlinux 0xe4c270a5 freeze_bdev +EXPORT_SYMBOL vmlinux 0xe503d573 qdisc_watchdog_cancel +EXPORT_SYMBOL vmlinux 0xe5122890 flow_cache_genid +EXPORT_SYMBOL vmlinux 0xe523ad75 synchronize_irq +EXPORT_SYMBOL vmlinux 0xe5431684 uart_add_one_port +EXPORT_SYMBOL vmlinux 0xe55704ab nf_hooks +EXPORT_SYMBOL vmlinux 0xe5633bc5 elv_next_request +EXPORT_SYMBOL vmlinux 0xe57878a1 in6_pton +EXPORT_SYMBOL vmlinux 0xe58457ca remap_pfn_range +EXPORT_SYMBOL vmlinux 0xe5867808 dlci_ioctl_set +EXPORT_SYMBOL vmlinux 0xe5c78a99 do_blank_screen +EXPORT_SYMBOL vmlinux 0xe5d17610 generic_file_direct_write +EXPORT_SYMBOL vmlinux 0xe60b9921 bmap +EXPORT_SYMBOL vmlinux 0xe6342450 __getblk +EXPORT_SYMBOL vmlinux 0xe65cae46 proc_symlink +EXPORT_SYMBOL vmlinux 0xe68f09e6 kobject_set_name +EXPORT_SYMBOL vmlinux 0xe6d6cfcf tcf_exts_change +EXPORT_SYMBOL vmlinux 0xe6dfc9fa page_zero_new_buffers +EXPORT_SYMBOL vmlinux 0xe6ebc016 key_create_or_update +EXPORT_SYMBOL vmlinux 0xe6fbe430 can_do_mlock +EXPORT_SYMBOL vmlinux 0xe716baed acpi_unregister_ioapic +EXPORT_SYMBOL vmlinux 0xe726771c dcache_dir_lseek +EXPORT_SYMBOL vmlinux 0xe74abff5 tcp_disconnect +EXPORT_SYMBOL vmlinux 0xe7a200c0 key_negate_and_link +EXPORT_SYMBOL vmlinux 0xe7a9e23a lock_super +EXPORT_SYMBOL vmlinux 0xe7b8798b tcp_v4_remember_stamp +EXPORT_SYMBOL vmlinux 0xe7d4daac seq_list_next +EXPORT_SYMBOL vmlinux 0xe7f91269 kmem_cache_shrink +EXPORT_SYMBOL vmlinux 0xe80ce219 sysctl_tcp_dma_copybreak +EXPORT_SYMBOL vmlinux 0xe80fda89 posix_lock_file +EXPORT_SYMBOL vmlinux 0xe82ba075 eth_header_parse +EXPORT_SYMBOL vmlinux 0xe85ecbf2 pci_try_set_mwi +EXPORT_SYMBOL vmlinux 0xe8793009 iget5_locked +EXPORT_SYMBOL vmlinux 0xe8cb6729 xfrm_state_add +EXPORT_SYMBOL vmlinux 0xe8cd902e hweight16 +EXPORT_SYMBOL vmlinux 0xe910b532 del_timer_sync +EXPORT_SYMBOL vmlinux 0xe911db6f block_write_begin +EXPORT_SYMBOL vmlinux 0xe914d009 ioremap_nocache +EXPORT_SYMBOL vmlinux 0xe914e41e strcpy +EXPORT_SYMBOL vmlinux 0xe92d3f78 register_chrdev +EXPORT_SYMBOL vmlinux 0xe9456a5a sysctl_xfrm_aevent_rseqth +EXPORT_SYMBOL vmlinux 0xe997667b wrmsr_on_cpu +EXPORT_SYMBOL vmlinux 0xe9d8356d bfifo_qdisc_ops +EXPORT_SYMBOL vmlinux 0xe9ef82fb bio_hw_segments +EXPORT_SYMBOL vmlinux 0xea10655a __bitmap_intersects +EXPORT_SYMBOL vmlinux 0xea2d33a2 radix_tree_gang_lookup_slot +EXPORT_SYMBOL vmlinux 0xea6fcdaa genl_unregister_family +EXPORT_SYMBOL vmlinux 0xea7987f1 key_update +EXPORT_SYMBOL vmlinux 0xea858cb5 radix_tree_gang_lookup_tag +EXPORT_SYMBOL vmlinux 0xea96b8ac udp_lib_get_port +EXPORT_SYMBOL vmlinux 0xeaa4fcbb xfrm_unregister_km +EXPORT_SYMBOL vmlinux 0xeab3bb45 inet_release +EXPORT_SYMBOL vmlinux 0xeaccd6c7 mpage_writepages +EXPORT_SYMBOL vmlinux 0xeae339e3 xfrm_policy_delete +EXPORT_SYMBOL vmlinux 0xeae3dfd6 __const_udelay +EXPORT_SYMBOL vmlinux 0xeaec8c5a get_disk +EXPORT_SYMBOL vmlinux 0xeaf94fcd uart_match_port +EXPORT_SYMBOL vmlinux 0xeb04c180 simple_statfs +EXPORT_SYMBOL vmlinux 0xeb1fabf6 interruptible_sleep_on +EXPORT_SYMBOL vmlinux 0xeb395084 param_get_invbool +EXPORT_SYMBOL vmlinux 0xeb50ccd0 dmam_pool_destroy +EXPORT_SYMBOL vmlinux 0xeb5bc454 bd_set_size +EXPORT_SYMBOL vmlinux 0xeb764b3a netlink_ack +EXPORT_SYMBOL vmlinux 0xeb8f54b3 strstrip +EXPORT_SYMBOL vmlinux 0xebcc9f57 dev_disable_lro +EXPORT_SYMBOL vmlinux 0xebd273a6 strict_strtoull +EXPORT_SYMBOL vmlinux 0xebe0124b __xfrm_state_destroy +EXPORT_SYMBOL vmlinux 0xec203266 tty_unregister_device +EXPORT_SYMBOL vmlinux 0xec2a526e pnp_register_card_driver +EXPORT_SYMBOL vmlinux 0xec3b67ba acpi_bus_get_device +EXPORT_SYMBOL vmlinux 0xec430c7c boot_cpu_data +EXPORT_SYMBOL vmlinux 0xec59de7f sock_no_sendmsg +EXPORT_SYMBOL vmlinux 0xec76275b skb_pull +EXPORT_SYMBOL vmlinux 0xec7d5fc8 filp_open +EXPORT_SYMBOL vmlinux 0xec860422 bioset_free +EXPORT_SYMBOL vmlinux 0xecde1418 _spin_lock_irq +EXPORT_SYMBOL vmlinux 0xed2351a2 generic_file_splice_read +EXPORT_SYMBOL vmlinux 0xed44a3e9 dev_mc_delete +EXPORT_SYMBOL vmlinux 0xed633abc pv_irq_ops +EXPORT_SYMBOL vmlinux 0xed668919 module_refcount +EXPORT_SYMBOL vmlinux 0xed784d95 do_munmap +EXPORT_SYMBOL vmlinux 0xed8255ce sock_release +EXPORT_SYMBOL vmlinux 0xedbaee5e nla_strcmp +EXPORT_SYMBOL vmlinux 0xedc03953 iounmap +EXPORT_SYMBOL vmlinux 0xedd14538 param_get_uint +EXPORT_SYMBOL vmlinux 0xedda7993 gnet_stats_copy_rate_est +EXPORT_SYMBOL vmlinux 0xedfa28a1 kthread_create +EXPORT_SYMBOL vmlinux 0xee04fd53 __netdev_alloc_skb +EXPORT_SYMBOL vmlinux 0xee0afa82 __nla_reserve_nohdr +EXPORT_SYMBOL vmlinux 0xee2d0fc7 _local_bh_enable +EXPORT_SYMBOL vmlinux 0xee4835a4 __sk_mem_reclaim +EXPORT_SYMBOL vmlinux 0xee48c5c8 ethtool_op_get_tso +EXPORT_SYMBOL vmlinux 0xee5731a2 __xfrm_route_forward +EXPORT_SYMBOL vmlinux 0xee7dab5b atm_proc_root +EXPORT_SYMBOL vmlinux 0xee7eb9e1 pnp_platform_devices +EXPORT_SYMBOL vmlinux 0xeea55927 sock_sendmsg +EXPORT_SYMBOL vmlinux 0xeea8482c sock_kfree_s +EXPORT_SYMBOL vmlinux 0xeea8850a input_register_device +EXPORT_SYMBOL vmlinux 0xeea9dbaf bitmap_bitremap +EXPORT_SYMBOL vmlinux 0xeeb1717c param_array_get +EXPORT_SYMBOL vmlinux 0xeed2113f sock_no_socketpair +EXPORT_SYMBOL vmlinux 0xeee7c0f4 write_inode_now +EXPORT_SYMBOL vmlinux 0xeef7ebc2 bdi_set_max_ratio +EXPORT_SYMBOL vmlinux 0xef0cbbe0 con_copy_unimap +EXPORT_SYMBOL vmlinux 0xef358df3 create_empty_buffers +EXPORT_SYMBOL vmlinux 0xef3bd862 mca_find_unused_adapter +EXPORT_SYMBOL vmlinux 0xef48063b lookup_bdev +EXPORT_SYMBOL vmlinux 0xef51e08a file_remove_suid +EXPORT_SYMBOL vmlinux 0xef5c24be netif_carrier_off +EXPORT_SYMBOL vmlinux 0xef622a77 __blk_run_queue +EXPORT_SYMBOL vmlinux 0xef628a48 seq_open +EXPORT_SYMBOL vmlinux 0xef654f6e unregister_tcf_proto_ops +EXPORT_SYMBOL vmlinux 0xef77910e iget_locked +EXPORT_SYMBOL vmlinux 0xef79ac56 __release_region +EXPORT_SYMBOL vmlinux 0xef9aedfc boot_option_idle_override +EXPORT_SYMBOL vmlinux 0xefa31858 bio_integrity_alloc_bioset +EXPORT_SYMBOL vmlinux 0xefad5ad7 ethtool_op_set_flags +EXPORT_SYMBOL vmlinux 0xefc5a8a3 sock_no_poll +EXPORT_SYMBOL vmlinux 0xefcd9fa9 __sk_dst_check +EXPORT_SYMBOL vmlinux 0xefdd70ce security_secid_to_secctx +EXPORT_SYMBOL vmlinux 0xefe099c3 acpi_get_event_status +EXPORT_SYMBOL vmlinux 0xf0009fee put_pages_list +EXPORT_SYMBOL vmlinux 0xf0541743 bio_integrity_endio +EXPORT_SYMBOL vmlinux 0xf065f629 ioread16be +EXPORT_SYMBOL vmlinux 0xf0b38717 blk_init_queue_node +EXPORT_SYMBOL vmlinux 0xf0b57c68 param_set_long +EXPORT_SYMBOL vmlinux 0xf0c82fe2 netdev_boot_setup_check +EXPORT_SYMBOL vmlinux 0xf0f1246c kvasprintf +EXPORT_SYMBOL vmlinux 0xf101204f set_device_ro +EXPORT_SYMBOL vmlinux 0xf10143d7 pci_scan_single_device +EXPORT_SYMBOL vmlinux 0xf1066643 pcie_port_service_unregister +EXPORT_SYMBOL vmlinux 0xf10de535 ioread8 +EXPORT_SYMBOL vmlinux 0xf11543ff find_first_zero_bit +EXPORT_SYMBOL vmlinux 0xf16284f5 proc_dointvec +EXPORT_SYMBOL vmlinux 0xf162fe2d sysctl_xfrm_aevent_etime +EXPORT_SYMBOL vmlinux 0xf174e70c kernel_getpeername +EXPORT_SYMBOL vmlinux 0xf174ed48 acquire_console_sem +EXPORT_SYMBOL vmlinux 0xf179b3f0 register_netdev +EXPORT_SYMBOL vmlinux 0xf1882357 dump_trace +EXPORT_SYMBOL vmlinux 0xf195c682 fb_invert_cmaps +EXPORT_SYMBOL vmlinux 0xf1db0114 wait_on_page_bit +EXPORT_SYMBOL vmlinux 0xf1deabf2 div64_u64 +EXPORT_SYMBOL vmlinux 0xf1e98c74 avenrun +EXPORT_SYMBOL vmlinux 0xf20dabd8 free_irq +EXPORT_SYMBOL vmlinux 0xf21f9f36 sock_common_setsockopt +EXPORT_SYMBOL vmlinux 0xf22dc4b3 pci_dev_driver +EXPORT_SYMBOL vmlinux 0xf2399fec kmem_cache_alloc +EXPORT_SYMBOL vmlinux 0xf246de13 tcf_hash_destroy +EXPORT_SYMBOL vmlinux 0xf26cc3d2 tty_port_alloc_xmit_buf +EXPORT_SYMBOL vmlinux 0xf2997713 tty_termios_hw_change +EXPORT_SYMBOL vmlinux 0xf2a6d2bf xfrm_policy_count +EXPORT_SYMBOL vmlinux 0xf2afa595 param_get_charp +EXPORT_SYMBOL vmlinux 0xf2e3143a blk_queue_find_tag +EXPORT_SYMBOL vmlinux 0xf2e74040 mca_set_adapter_name +EXPORT_SYMBOL vmlinux 0xf2e80ec6 tcp_v4_md5_hash_skb +EXPORT_SYMBOL vmlinux 0xf3113562 inetdev_by_index +EXPORT_SYMBOL vmlinux 0xf313da4e sha_transform +EXPORT_SYMBOL vmlinux 0xf31e1a8a xfrm_state_insert +EXPORT_SYMBOL vmlinux 0xf31f6de9 vfs_rename +EXPORT_SYMBOL vmlinux 0xf3341268 __clear_user +EXPORT_SYMBOL vmlinux 0xf338d4c3 netlink_unregister_notifier +EXPORT_SYMBOL vmlinux 0xf3462039 d_alloc +EXPORT_SYMBOL vmlinux 0xf346231f seq_list_start_head +EXPORT_SYMBOL vmlinux 0xf3662d8a br_handle_frame_hook +EXPORT_SYMBOL vmlinux 0xf39bf4d9 put_cmsg +EXPORT_SYMBOL vmlinux 0xf3bf0bce __bitmap_complement +EXPORT_SYMBOL vmlinux 0xf3d6f81e tty_flip_buffer_push +EXPORT_SYMBOL vmlinux 0xf3e69e70 invalidate_inodes +EXPORT_SYMBOL vmlinux 0xf43e9082 task_session_nr_ns +EXPORT_SYMBOL vmlinux 0xf441ac43 ioread8_rep +EXPORT_SYMBOL vmlinux 0xf46ae544 vfs_dq_transfer +EXPORT_SYMBOL vmlinux 0xf46d69c6 dev_mc_add +EXPORT_SYMBOL vmlinux 0xf47d47e0 acpi_enable_gpe +EXPORT_SYMBOL vmlinux 0xf48a2c4c MCA_bus +EXPORT_SYMBOL vmlinux 0xf48baec8 vfs_mkdir +EXPORT_SYMBOL vmlinux 0xf49395fa setup_arg_pages +EXPORT_SYMBOL vmlinux 0xf49a8f2d vfs_statfs +EXPORT_SYMBOL vmlinux 0xf49b9fce inode_set_bytes +EXPORT_SYMBOL vmlinux 0xf49bc67a atm_pcr_goal +EXPORT_SYMBOL vmlinux 0xf4a5c213 avail_to_resrv_perfctr_nmi_bit +EXPORT_SYMBOL vmlinux 0xf4ae9d51 ida_pre_get +EXPORT_SYMBOL vmlinux 0xf4f14de6 rtnl_trylock +EXPORT_SYMBOL vmlinux 0xf4f52f93 dqstats +EXPORT_SYMBOL vmlinux 0xf4fa7f13 read_cache_page +EXPORT_SYMBOL vmlinux 0xf502d273 acpi_get_current_resources +EXPORT_SYMBOL vmlinux 0xf517aca8 __dst_free +EXPORT_SYMBOL vmlinux 0xf51ae235 touch_nmi_watchdog +EXPORT_SYMBOL vmlinux 0xf5330403 sk_dst_check +EXPORT_SYMBOL vmlinux 0xf53d4c26 qdisc_class_hash_destroy +EXPORT_SYMBOL vmlinux 0xf59bca06 vfs_mknod +EXPORT_SYMBOL vmlinux 0xf5c05914 generic_segment_checks +EXPORT_SYMBOL vmlinux 0xf5ce9811 tcp_memory_allocated +EXPORT_SYMBOL vmlinux 0xf5d2600f key_instantiate_and_link +EXPORT_SYMBOL vmlinux 0xf5d9369b kobject_get +EXPORT_SYMBOL vmlinux 0xf5daa08b generic_cont_expand_simple +EXPORT_SYMBOL vmlinux 0xf5df1315 serio_reconnect +EXPORT_SYMBOL vmlinux 0xf602915a find_task_by_pid_type_ns +EXPORT_SYMBOL vmlinux 0xf60c4182 bh_uptodate_or_lock +EXPORT_SYMBOL vmlinux 0xf662e628 tty_insert_flip_string +EXPORT_SYMBOL vmlinux 0xf663d7d0 dev_get_by_flags +EXPORT_SYMBOL vmlinux 0xf6b54e39 vcc_release_async +EXPORT_SYMBOL vmlinux 0xf6bb4198 __skb_warn_lro_forwarding +EXPORT_SYMBOL vmlinux 0xf6bb4729 color_table +EXPORT_SYMBOL vmlinux 0xf6cf7da3 dma_set_mask +EXPORT_SYMBOL vmlinux 0xf6ebc03b net_ratelimit +EXPORT_SYMBOL vmlinux 0xf738217e pci_set_mwi +EXPORT_SYMBOL vmlinux 0xf73c9751 __pci_register_driver +EXPORT_SYMBOL vmlinux 0xf73e855c __vlan_hwaccel_rx +EXPORT_SYMBOL vmlinux 0xf7623914 radix_tree_tag_clear +EXPORT_SYMBOL vmlinux 0xf77a738d security_task_getsecid +EXPORT_SYMBOL vmlinux 0xf786ef5e idr_init +EXPORT_SYMBOL vmlinux 0xf78d04ab netlink_register_notifier +EXPORT_SYMBOL vmlinux 0xf7b0819e poll_freewait +EXPORT_SYMBOL vmlinux 0xf7ee849b mca_device_transform_irq +EXPORT_SYMBOL vmlinux 0xf7fdeaad netlink_change_ngroups +EXPORT_SYMBOL vmlinux 0xf81121d4 sock_wfree +EXPORT_SYMBOL vmlinux 0xf82abc1d isa_dma_bridge_buggy +EXPORT_SYMBOL vmlinux 0xf82e3d47 acpi_initialize_objects +EXPORT_SYMBOL vmlinux 0xf82f1109 utf8_wctomb +EXPORT_SYMBOL vmlinux 0xf86dfee5 acpi_check_mem_region +EXPORT_SYMBOL vmlinux 0xf8814f73 rb_last +EXPORT_SYMBOL vmlinux 0xf888cc52 acpi_root_dir +EXPORT_SYMBOL vmlinux 0xf88e0ee2 acpi_get_table_header +EXPORT_SYMBOL vmlinux 0xf890fe7f pm_idle +EXPORT_SYMBOL vmlinux 0xf8aa47ae mutex_lock_killable +EXPORT_SYMBOL vmlinux 0xf8b30e93 mempool_create +EXPORT_SYMBOL vmlinux 0xf8b81ac8 blk_queue_init_tags +EXPORT_SYMBOL vmlinux 0xf8cf9ee5 abort_exclusive_wait +EXPORT_SYMBOL vmlinux 0xf8d64afc dev_set_allmulti +EXPORT_SYMBOL vmlinux 0xf8e0bb34 llc_build_and_send_ui_pkt +EXPORT_SYMBOL vmlinux 0xf95b2250 lease_modify +EXPORT_SYMBOL vmlinux 0xf9842c14 inet_stream_ops +EXPORT_SYMBOL vmlinux 0xf987afe6 pci_iomap +EXPORT_SYMBOL vmlinux 0xf98c65d1 __devm_release_region +EXPORT_SYMBOL vmlinux 0xf9a482f9 msleep +EXPORT_SYMBOL vmlinux 0xf9e14099 fb_pan_display +EXPORT_SYMBOL vmlinux 0xf9ef313f mark_buffer_dirty +EXPORT_SYMBOL vmlinux 0xfa0564fc __wait_on_bit_lock +EXPORT_SYMBOL vmlinux 0xfa06d562 lease_get_mtime +EXPORT_SYMBOL vmlinux 0xfab40d04 pci_find_next_bus +EXPORT_SYMBOL vmlinux 0xfabfd75c neigh_changeaddr +EXPORT_SYMBOL vmlinux 0xfadffb48 vfs_permission +EXPORT_SYMBOL vmlinux 0xfae4c0a3 xfrm_state_lookup +EXPORT_SYMBOL vmlinux 0xfaf98462 bitrev32 +EXPORT_SYMBOL vmlinux 0xfafbf469 dec_zone_page_state +EXPORT_SYMBOL vmlinux 0xfb0443fb acpi_get_parent +EXPORT_SYMBOL vmlinux 0xfb0cf2e9 touch_all_softlockup_watchdogs +EXPORT_SYMBOL vmlinux 0xfb5bad89 dma_async_memcpy_buf_to_pg +EXPORT_SYMBOL vmlinux 0xfb6af58d recalc_sigpending +EXPORT_SYMBOL vmlinux 0xfb7fca7e d_lookup +EXPORT_SYMBOL vmlinux 0xfba0c2e0 llc_sap_list_lock +EXPORT_SYMBOL vmlinux 0xfbd74ce5 blk_dump_rq_flags +EXPORT_SYMBOL vmlinux 0xfbd7e11f __mod_zone_page_state +EXPORT_SYMBOL vmlinux 0xfbf92453 param_get_bool +EXPORT_SYMBOL vmlinux 0xfc02b7ad sysctl_tcp_wmem +EXPORT_SYMBOL vmlinux 0xfc309c3e cancel_delayed_work_sync +EXPORT_SYMBOL vmlinux 0xfc35ed7f start_tty +EXPORT_SYMBOL vmlinux 0xfc39e32f ioport_unmap +EXPORT_SYMBOL vmlinux 0xfc41f270 ethtool_op_get_ufo +EXPORT_SYMBOL vmlinux 0xfc5545ec dma_pool_destroy +EXPORT_SYMBOL vmlinux 0xfc5ce9dd pci_disable_msix +EXPORT_SYMBOL vmlinux 0xfc5ee606 netpoll_send_udp +EXPORT_SYMBOL vmlinux 0xfca7da9f pci_set_master +EXPORT_SYMBOL vmlinux 0xfcaa04a0 out_of_line_wait_on_bit_lock +EXPORT_SYMBOL vmlinux 0xfcadde4d find_get_pages_contig +EXPORT_SYMBOL vmlinux 0xfcb2e382 struct_module +EXPORT_SYMBOL vmlinux 0xfcc81899 __skb_checksum_complete +EXPORT_SYMBOL vmlinux 0xfcccab06 dst_alloc +EXPORT_SYMBOL vmlinux 0xfcda63a3 node_states +EXPORT_SYMBOL vmlinux 0xfcdd8cf6 param_get_ushort +EXPORT_SYMBOL vmlinux 0xfce2eb81 __insert_inode_hash +EXPORT_SYMBOL vmlinux 0xfce483ab pcim_iomap_regions_request_all +EXPORT_SYMBOL vmlinux 0xfce85aa6 skb_realloc_headroom +EXPORT_SYMBOL vmlinux 0xfcec0987 enable_irq +EXPORT_SYMBOL vmlinux 0xfcfa03ff fb_videomode_to_modelist +EXPORT_SYMBOL vmlinux 0xfd00cac1 ps2_handle_response +EXPORT_SYMBOL vmlinux 0xfd086d25 truncate_inode_pages +EXPORT_SYMBOL vmlinux 0xfd69360f con_set_default_unimap +EXPORT_SYMBOL vmlinux 0xfd94f378 flush_signals +EXPORT_SYMBOL vmlinux 0xfd98879a rb_next +EXPORT_SYMBOL vmlinux 0xfdb9b629 ioread32be +EXPORT_SYMBOL vmlinux 0xfdd2c82a dma_async_client_register +EXPORT_SYMBOL vmlinux 0xfde2145a boot_tvec_bases +EXPORT_SYMBOL vmlinux 0xfe054973 dma_mark_declared_memory_occupied +EXPORT_SYMBOL vmlinux 0xfe3e0dcd pci_bus_write_config_word +EXPORT_SYMBOL vmlinux 0xfe5d4bb2 sys_tz +EXPORT_SYMBOL vmlinux 0xfe5e3c04 xfrm_policy_bysel_ctx +EXPORT_SYMBOL vmlinux 0xfe6afc25 unmap_underlying_metadata +EXPORT_SYMBOL vmlinux 0xfe769456 unregister_netdevice_notifier +EXPORT_SYMBOL vmlinux 0xfe7c4287 nr_cpu_ids +EXPORT_SYMBOL vmlinux 0xfe9c1ed0 qdisc_watchdog_schedule +EXPORT_SYMBOL vmlinux 0xfec3c2f2 bcd2bin +EXPORT_SYMBOL vmlinux 0xfedc7ca9 ps2_sendbyte +EXPORT_SYMBOL vmlinux 0xfedd35fc console_suspend_enabled +EXPORT_SYMBOL vmlinux 0xfee54c20 sk_alloc +EXPORT_SYMBOL vmlinux 0xff1e9dd8 seq_list_start +EXPORT_SYMBOL vmlinux 0xff219e12 elv_queue_empty +EXPORT_SYMBOL vmlinux 0xff66af9a pnp_get_resource +EXPORT_SYMBOL vmlinux 0xff6878cf fb_default_cmap +EXPORT_SYMBOL vmlinux 0xff708fd3 mempool_destroy +EXPORT_SYMBOL vmlinux 0xff9ca065 fb_edid_to_monspecs +EXPORT_SYMBOL vmlinux 0xffa5aad8 pcim_pin_device +EXPORT_SYMBOL vmlinux 0xffafdc5c _read_unlock_irq +EXPORT_SYMBOL vmlinux 0xffbaea98 tcp_ioctl +EXPORT_SYMBOL vmlinux 0xffcff409 block_prepare_write +EXPORT_SYMBOL vmlinux 0xffd5a395 default_wake_function +EXPORT_SYMBOL vmlinux 0xffdb82bc sg_free_table +EXPORT_SYMBOL_GPL arch/x86/kernel/cpu/cpufreq/speedstep-lib 0x16836e04 speedstep_detect_processor +EXPORT_SYMBOL_GPL arch/x86/kernel/cpu/cpufreq/speedstep-lib 0x4cdb4bd0 speedstep_get_processor_frequency +EXPORT_SYMBOL_GPL arch/x86/kernel/cpu/cpufreq/speedstep-lib 0xd494ee54 speedstep_get_freqs +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x00aaf935 kvm_disable_tdp +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x04541f7e kvm_get_msr_common +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x08f8dc01 kvm_lmsw +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x094ac8f4 kvm_get_pfn +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x0b2885d9 kvm_put_guest_fpu +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x0d2d2c23 kvm_lapic_reset +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x0f4e1efa kvm_task_switch +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x109dd22d kvm_mmu_unprotect_page_virt +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x1197d0e2 kvm_set_cr3 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x12d1b23b kvm_release_pfn_clean +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x13f2b2f8 kvm_read_guest_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x14581540 kvm_lapic_set_tpr +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x1e4580bb kvm_release_pfn_dirty +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x1f6658f1 kvm_get_kvm +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x2112f153 kvm_vcpu_uninit +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x211d3854 kvm_set_cr4 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x2322e039 kvm_set_pfn_accessed +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x24671bdf kvm_get_apic_base +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x24da8984 is_error_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x267ba55b gfn_to_pfn +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x26b5c7b4 kvm_emulate_hypercall +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x27046576 kvm_exit +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x286f82f0 kvm_report_emulation_failure +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x2cd1af3a kvm_emulate_pio +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x317f9e6b kvm_enable_efer_bits +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x322ecead kvm_mmu_reset_context +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x36d6b4ab kvm_lapic_get_base +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x3c48b8d8 kvm_resched +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x42208e25 kvm_lapic_enabled +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x4443bb1b kvm_load_guest_fpu +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x496eb467 kvm_set_cr0 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x4a7cbe69 is_error_pfn +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x599086dd kvm_handle_fault_on_reboot +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x5cc1c4e4 kvm_read_guest +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x619e3b18 kvm_queue_exception +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x64e4869f emulator_read_std +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x735f5f53 kvm_put_kvm +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x73c25753 __kvm_set_memory_region +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x741658de kvm_lapic_get_cr8 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x76d95630 kvm_mmu_load +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x776ed20d emulate_instruction +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x7b70df13 emulator_write_emulated +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x81299ac1 kvm_get_cr8 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x88cd8052 gfn_to_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8ce4f3ab kvm_enable_tdp +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8e7f9b47 segment_base +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x9008ef56 kvm_set_msr_common +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x9211a5ea kvm_release_page_clean +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x9236849a kvm_vcpu_cache +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x92586ff3 kvm_init +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x95a76348 kvm_vcpu_init +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x9858f2d6 kvm_clear_guest_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x9989ac01 kvm_set_cr8 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xa361bc65 kvm_set_pfn_dirty +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xa580c714 kvm_queue_exception_e +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xa5fbd8b2 gfn_to_hva +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xad4e2b33 kvm_mmu_page_fault +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xae7d3898 kvm_write_guest_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xaf9744d6 kvm_emulate_cpuid +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xb0521d26 kvm_clear_guest +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xb3424b71 load_pdptrs +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbaf3eb45 fx_init +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbb254472 kvm_set_page_dirty +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbd377dc9 kvm_mmu_set_nonpresent_ptes +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbd94103b kvm_mmu_set_base_ptes +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbfb0152c kvm_create_lapic +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xc1014136 kvm_get_cs_db_l_bits +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd0b2727a kvm_mmu_set_mask_ptes +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd296def9 kvm_is_error_hva +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd3b1aecd kvm_lapic_find_highest_irr +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd44b461d kvm_emulate_pio_string +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd71623b9 kvm_release_page_dirty +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xda24e53a kvm_emulate_halt +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xe03cfa70 kvm_cpu_has_interrupt +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xebb070ff kvm_cpu_get_interrupt +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xed4928ca kvm_timer_intr_post +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xf3d24757 kvm_set_apic_base +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xf4466f4b kvm_inject_pending_timer_irqs +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xf4744ddd kvm_is_visible_gfn +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xf949b749 kvm_set_memory_region +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xfb928f3d kvm_inject_nmi +EXPORT_SYMBOL_GPL crypto/aead 0x4ea44011 crypto_grab_aead +EXPORT_SYMBOL_GPL crypto/aead 0x6387b192 crypto_alloc_aead +EXPORT_SYMBOL_GPL crypto/aead 0x6d5ce56d aead_geniv_init +EXPORT_SYMBOL_GPL crypto/aead 0x8cd78c4c crypto_nivaead_type +EXPORT_SYMBOL_GPL crypto/aead 0x9719876c aead_geniv_exit +EXPORT_SYMBOL_GPL crypto/aead 0x9f746f5e crypto_aead_type +EXPORT_SYMBOL_GPL crypto/aead 0xa7eaa145 crypto_aead_setauthsize +EXPORT_SYMBOL_GPL crypto/aead 0xef497127 aead_geniv_free +EXPORT_SYMBOL_GPL crypto/aead 0xf9d33596 aead_geniv_alloc +EXPORT_SYMBOL_GPL crypto/aes_generic 0x1381bf2d crypto_ft_tab +EXPORT_SYMBOL_GPL crypto/aes_generic 0x22894d94 crypto_il_tab +EXPORT_SYMBOL_GPL crypto/aes_generic 0x5f943003 crypto_it_tab +EXPORT_SYMBOL_GPL crypto/aes_generic 0x5fe743de crypto_aes_expand_key +EXPORT_SYMBOL_GPL crypto/aes_generic 0x6e9cc2ba crypto_fl_tab +EXPORT_SYMBOL_GPL crypto/aes_generic 0x959d1946 crypto_aes_set_key +EXPORT_SYMBOL_GPL crypto/async_tx/async_memcpy 0xeeb06a0b async_memcpy +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0x02f4f338 async_tx_quiesce +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0x6b4a6db2 async_tx_issue_pending_all +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0x7956b500 __async_tx_find_channel +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0x8c3f27b2 dma_wait_for_async_tx +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0xd733292f async_tx_submit +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0xe0198ab7 async_tx_run_dependencies +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0xedd84bda async_trigger_callback +EXPORT_SYMBOL_GPL crypto/async_tx/async_xor 0x3a38a0eb async_xor_zero_sum +EXPORT_SYMBOL_GPL crypto/async_tx/async_xor 0xcf3aa3dd async_xor +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x09a87972 skcipher_geniv_exit +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x0b0bf833 crypto_givcipher_type +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x2745cfea crypto_alloc_ablkcipher +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x466b9b63 skcipher_geniv_init +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x4f04ee71 crypto_blkcipher_type +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x68eaaf34 crypto_ablkcipher_type +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x724106a0 blkcipher_walk_phys +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x7310f661 blkcipher_walk_done +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x74869552 skcipher_geniv_free +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0xa878fd15 blkcipher_walk_virt_block +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0xaacd79f1 crypto_grab_skcipher +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0xc421af07 blkcipher_walk_virt +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0xeb5d528b skcipher_geniv_alloc +EXPORT_SYMBOL_GPL crypto/des_generic 0xcfd9a2c0 des_ekey +EXPORT_SYMBOL_GPL crypto/twofish_common 0xcb3f501c twofish_setkey +EXPORT_SYMBOL_GPL drivers/acpi/dock 0x100c48a2 unregister_dock_notifier +EXPORT_SYMBOL_GPL drivers/acpi/dock 0x2611fbee register_hotplug_dock_device +EXPORT_SYMBOL_GPL drivers/acpi/dock 0x318920b1 register_dock_notifier +EXPORT_SYMBOL_GPL drivers/acpi/dock 0xbd506a46 unregister_hotplug_dock_device +EXPORT_SYMBOL_GPL drivers/acpi/dock 0xcc6ab305 is_dock_device +EXPORT_SYMBOL_GPL drivers/acpi/sbshc 0x0ad5c33f acpi_smbus_register_callback +EXPORT_SYMBOL_GPL drivers/acpi/sbshc 0x158c2ad0 acpi_smbus_unregister_callback +EXPORT_SYMBOL_GPL drivers/acpi/sbshc 0x526b867a acpi_smbus_read +EXPORT_SYMBOL_GPL drivers/acpi/sbshc 0xb3d5e527 acpi_smbus_write +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0x3ecf6cfc wmi_install_notify_handler +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0x64ebe677 wmi_query_block +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0xa9b7afd8 wmi_set_block +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0xb5a6ebe2 wmi_remove_notify_handler +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0xc5e3dddf wmi_get_event_data +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0xc9d4d6d1 wmi_has_guid +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0xe2426710 wmi_evaluate_method +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0067df75 ata_tf_from_fis +EXPORT_SYMBOL_GPL drivers/ata/libata 0x00ebcb5d ata_id_string +EXPORT_SYMBOL_GPL drivers/ata/libata 0x03de3942 ata_sff_thaw +EXPORT_SYMBOL_GPL drivers/ata/libata 0x03e3686c ata_timing_cycle2mode +EXPORT_SYMBOL_GPL drivers/ata/libata 0x048e75d0 ata_port_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0531dcb8 ata_dev_classify +EXPORT_SYMBOL_GPL drivers/ata/libata 0x05b93c01 ata_scsi_simulate +EXPORT_SYMBOL_GPL drivers/ata/libata 0x061b7297 ata_host_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0x072b0d87 ata_std_bios_param +EXPORT_SYMBOL_GPL drivers/ata/libata 0x086f59a4 sata_set_spd +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0b4b6a0e ata_ehi_clear_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0b9380af ata_eh_qc_retry +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0b97663d ata_port_abort +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0f15dfa8 ata_do_set_mode +EXPORT_SYMBOL_GPL drivers/ata/libata 0x10244432 ata_sas_port_stop +EXPORT_SYMBOL_GPL drivers/ata/libata 0x1168f682 ata_sff_irq_on +EXPORT_SYMBOL_GPL drivers/ata/libata 0x183f6249 ata_sff_wait_after_reset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x196a4ad1 ata_sff_qc_fill_rtf +EXPORT_SYMBOL_GPL drivers/ata/libata 0x200986c8 ata_sas_queuecmd +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2048a89a ata_sff_dev_classify +EXPORT_SYMBOL_GPL drivers/ata/libata 0x23607004 ata_sas_port_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0x24082893 ata_sff_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2a29f025 ata_sff_dumb_qc_prep +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2aff3a8a ata_sff_softreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2d942f05 ata_sff_error_handler +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2f365f26 ata_ehi_push_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0x309d6aea ata_sff_qc_prep +EXPORT_SYMBOL_GPL drivers/ata/libata 0x33f2c0a9 ata_port_disable +EXPORT_SYMBOL_GPL drivers/ata/libata 0x34188f41 ata_dummy_port_info +EXPORT_SYMBOL_GPL drivers/ata/libata 0x374cb8f0 ata_bmdma_stop +EXPORT_SYMBOL_GPL drivers/ata/libata 0x3aa71548 ata_pci_remove_one +EXPORT_SYMBOL_GPL drivers/ata/libata 0x3b2b4969 ata_sff_dev_select +EXPORT_SYMBOL_GPL drivers/ata/libata 0x40af0dec ata_xfer_mode2mask +EXPORT_SYMBOL_GPL drivers/ata/libata 0x42947018 sata_link_debounce +EXPORT_SYMBOL_GPL drivers/ata/libata 0x433ae513 ata_eh_thaw_port +EXPORT_SYMBOL_GPL drivers/ata/libata 0x43f56e82 ata_xfer_mode2shift +EXPORT_SYMBOL_GPL drivers/ata/libata 0x441c4904 dev_attr_sw_activity +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4627a8e1 ata_acpi_gtm +EXPORT_SYMBOL_GPL drivers/ata/libata 0x475fcbe8 ata_pci_sff_init_host +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4b74e212 ata_port_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4eee21b1 ata_pci_bmdma_init +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4fdc945d sata_deb_timing_normal +EXPORT_SYMBOL_GPL drivers/ata/libata 0x52542fe5 ata_sff_host_intr +EXPORT_SYMBOL_GPL drivers/ata/libata 0x530cf3f5 ata_qc_complete_multiple +EXPORT_SYMBOL_GPL drivers/ata/libata 0x53533e7a ata_pci_device_suspend +EXPORT_SYMBOL_GPL drivers/ata/libata 0x556e8acf sata_std_hardreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x57ea7ee1 ata_timing_compute +EXPORT_SYMBOL_GPL drivers/ata/libata 0x5853855d ata_std_qc_defer +EXPORT_SYMBOL_GPL drivers/ata/libata 0x5adfe210 ata_cable_unknown +EXPORT_SYMBOL_GPL drivers/ata/libata 0x5cfe9121 ata_dummy_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x5d8a878f ata_host_alloc +EXPORT_SYMBOL_GPL drivers/ata/libata 0x5ecf60d1 ata_acpi_gtm_xfermask +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6061c757 ata_sas_port_destroy +EXPORT_SYMBOL_GPL drivers/ata/libata 0x61542486 ata_pio_need_iordy +EXPORT_SYMBOL_GPL drivers/ata/libata 0x67f1a43a ata_dev_disable +EXPORT_SYMBOL_GPL drivers/ata/libata 0x69550a1c ata_sas_slave_configure +EXPORT_SYMBOL_GPL drivers/ata/libata 0x69e20aef ata_sff_prereset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x69e9a2cb ata_scsi_slave_config +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6ba585f5 ata_bus_reset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6e4b425f ata_bmdma_mode_filter +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6f01fa9d ata_sff_data_xfer_noirq +EXPORT_SYMBOL_GPL drivers/ata/libata 0x707ff1bb ata_xfer_mask2mode +EXPORT_SYMBOL_GPL drivers/ata/libata 0x713ab78f sata_scr_valid +EXPORT_SYMBOL_GPL drivers/ata/libata 0x73a48b4a ata_sff_std_ports +EXPORT_SYMBOL_GPL drivers/ata/libata 0x73ac84cf ata_bmdma_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0x743a165e ata_pack_xfermask +EXPORT_SYMBOL_GPL drivers/ata/libata 0x76729003 ata_host_resume +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7b18e548 ata_cable_80wire +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7baea1d9 ata_bmdma_setup +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7bbcc01e ata_eh_analyze_ncq_error +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7c3497ec sata_link_resume +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7c482c71 sata_pmp_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7cdf231f ata_sff_dma_pause +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7ddad04b ata_sff_postreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7f592fdd sata_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x80092328 ata_pci_sff_activate_host +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8040c872 sata_scr_write +EXPORT_SYMBOL_GPL drivers/ata/libata 0x809106a7 ata_sff_check_status +EXPORT_SYMBOL_GPL drivers/ata/libata 0x83375a62 ata_sg_init +EXPORT_SYMBOL_GPL drivers/ata/libata 0x84405365 sata_link_hardreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8460ee0e ata_pci_device_resume +EXPORT_SYMBOL_GPL drivers/ata/libata 0x850b523f pci_test_config_bits +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8740a863 ata_host_alloc_pinfo +EXPORT_SYMBOL_GPL drivers/ata/libata 0x89a84ed4 ata_port_probe +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8aabdf33 ata_eh_qc_complete +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8b752ac1 ata_tf_to_fis +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8c2f3873 ata_noop_qc_prep +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8fbd372d ata_sff_hsm_move +EXPORT_SYMBOL_GPL drivers/ata/libata 0x93146830 ata_host_init +EXPORT_SYMBOL_GPL drivers/ata/libata 0x94a68723 ata_scsi_slave_destroy +EXPORT_SYMBOL_GPL drivers/ata/libata 0x94dc62d2 ata_scsi_ioctl +EXPORT_SYMBOL_GPL drivers/ata/libata 0x96b6994c ata_host_activate +EXPORT_SYMBOL_GPL drivers/ata/libata 0x9833afd9 ata_pci_device_do_suspend +EXPORT_SYMBOL_GPL drivers/ata/libata 0x993f7235 ata_acpi_cbl_80wire +EXPORT_SYMBOL_GPL drivers/ata/libata 0x995a3898 ata_wait_after_reset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x9a846ae0 ata_do_dev_read_id +EXPORT_SYMBOL_GPL drivers/ata/libata 0x9aaddadd ata_sff_qc_issue +EXPORT_SYMBOL_GPL drivers/ata/libata 0xa1e383d2 ata_pci_device_do_resume +EXPORT_SYMBOL_GPL drivers/ata/libata 0xa20c959b ata_link_abort +EXPORT_SYMBOL_GPL drivers/ata/libata 0xa3704002 ata_scsi_queuecmd +EXPORT_SYMBOL_GPL drivers/ata/libata 0xabd155f1 sata_pmp_qc_defer_cmd_switch +EXPORT_SYMBOL_GPL drivers/ata/libata 0xacc7c1c7 ata_std_error_handler +EXPORT_SYMBOL_GPL drivers/ata/libata 0xaddf7f49 ata_cable_ignore +EXPORT_SYMBOL_GPL drivers/ata/libata 0xaeda658f ata_sff_pause +EXPORT_SYMBOL_GPL drivers/ata/libata 0xaef22dee ata_host_suspend +EXPORT_SYMBOL_GPL drivers/ata/libata 0xb59a30cb ata_dev_pair +EXPORT_SYMBOL_GPL drivers/ata/libata 0xb60cef36 ata_port_freeze +EXPORT_SYMBOL_GPL drivers/ata/libata 0xb6aeb661 ata_id_c_string +EXPORT_SYMBOL_GPL drivers/ata/libata 0xb6eb7dde ata_sff_irq_clear +EXPORT_SYMBOL_GPL drivers/ata/libata 0xb9d79b82 ata_sff_port_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0xbbc736cc ata_cable_sata +EXPORT_SYMBOL_GPL drivers/ata/libata 0xbbecf662 ata_std_postreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0xbe1887e4 ata_unpack_xfermask +EXPORT_SYMBOL_GPL drivers/ata/libata 0xbf02cce4 ata_host_detach +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc1a6673d ata_bmdma_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc2b9a260 ata_acpi_stm +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc3481734 ata_do_eh +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc428068d sata_deb_timing_long +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc48b7ccf ata_mode_string +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc56a8140 sata_scr_read +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc673e23e ata_scsi_change_queue_depth +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcae772c5 ata_sff_exec_command +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcccfb2fa sata_deb_timing_hotplug +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcd04cbc8 ata_sff_freeze +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcd31c4ac ata_std_prereset +EXPORT_SYMBOL_GPL drivers/ata/libata 0xce3647e8 ata_link_online +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcf678fd1 ata_sff_busy_sleep +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd01a9b68 ata_port_pbar_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd84cd7f4 ata_timing_find_mode +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd8b7a143 ata_sff_post_internal_cmd +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd9129720 ata_sff_tf_read +EXPORT_SYMBOL_GPL drivers/ata/libata 0xdab43e22 ata_port_schedule_eh +EXPORT_SYMBOL_GPL drivers/ata/libata 0xdb1d5281 sata_sff_hardreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0xdb1f6be4 ata_link_offline +EXPORT_SYMBOL_GPL drivers/ata/libata 0xdb7472ef ata_sas_port_init +EXPORT_SYMBOL_GPL drivers/ata/libata 0xdd8696f6 dev_attr_em_message_type +EXPORT_SYMBOL_GPL drivers/ata/libata 0xdf3022b2 ata_sff_interrupt +EXPORT_SYMBOL_GPL drivers/ata/libata 0xe18c9859 ata_pci_sff_prepare_host +EXPORT_SYMBOL_GPL drivers/ata/libata 0xe253551a __ata_ehi_push_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0xe49ff3b0 ata_wait_register +EXPORT_SYMBOL_GPL drivers/ata/libata 0xe4d50f41 dev_attr_em_message +EXPORT_SYMBOL_GPL drivers/ata/libata 0xe6daf180 ata_pci_sff_init_one +EXPORT_SYMBOL_GPL drivers/ata/libata 0xea418e0f atapi_cmd_type +EXPORT_SYMBOL_GPL drivers/ata/libata 0xeb3097e7 ata_cable_40wire +EXPORT_SYMBOL_GPL drivers/ata/libata 0xeda501d4 dev_attr_link_power_management_policy +EXPORT_SYMBOL_GPL drivers/ata/libata 0xee5928c3 ata_sff_data_xfer +EXPORT_SYMBOL_GPL drivers/ata/libata 0xef5ce7bd ata_sff_wait_ready +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf0cd71d4 ata_base_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf188aba0 ata_bmdma_status +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf3d5cc13 ata_timing_merge +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf4113f4a ata_sas_port_alloc +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf4c74771 ata_host_register +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf5fe1855 ata_sff_tf_load +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf81190e7 sata_async_notification +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf8f12876 sata_scr_write_flush +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf8f3a0fb ata_ratelimit +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf9ca3160 ata_id_xfermask +EXPORT_SYMBOL_GPL drivers/ata/libata 0xfb804e95 ata_pci_bmdma_clear_simplex +EXPORT_SYMBOL_GPL drivers/ata/libata 0xfc112b2a ata_qc_complete +EXPORT_SYMBOL_GPL drivers/ata/libata 0xfe487d06 sata_pmp_error_handler +EXPORT_SYMBOL_GPL drivers/ata/libata 0xfea69963 ata_eh_freeze_port +EXPORT_SYMBOL_GPL drivers/ata/pata_sis 0x6bb729bd sis_info133_for_sata +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x02ff9464 cfag12864b_isinited +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x0ecb2e5d cfag12864b_disable +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x305dc3c6 cfag12864b_isenabled +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x3389f926 cfag12864b_enable +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x9522a342 cfag12864b_getrate +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0xc48e9d95 cfag12864b_buffer +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0x14102f23 ks0108_displaystate +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0x48a70518 ks0108_writedata +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0x4f506333 ks0108_startline +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0x6edae968 ks0108_isinited +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0xbf4774db ks0108_writecontrol +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0xedde6df2 ks0108_page +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0xfee8ef7b ks0108_address +EXPORT_SYMBOL_GPL drivers/char/agp/agpgart 0x68d1fe0e agp_add_bridge +EXPORT_SYMBOL_GPL drivers/char/agp/agpgart 0xd6feefa5 agp_num_entries +EXPORT_SYMBOL_GPL drivers/char/agp/agpgart 0xdb5c69ec agp_remove_bridge +EXPORT_SYMBOL_GPL drivers/char/agp/agpgart 0xe089cfcc agp_memory_reserved +EXPORT_SYMBOL_GPL drivers/char/scx200_gpio 0xc6b79753 scx200_gpio_ops +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x1805b4f3 tpm_show_temp_deactivated +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x1cd93b13 tpm_show_caps +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x39da35bb tpm_get_timeouts +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x3e0ef7df tpm_show_enabled +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x5be97390 tpm_gen_interrupt +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x5d3e7d86 tpm_remove_hardware +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x69f71761 tpm_calc_ordinal_duration +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x70c03019 tpm_write +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x79743930 tpm_show_caps_1_2 +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x7bd391ee tpm_open +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x7fdc89dc tpm_store_cancel +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x831ccdf3 tpm_pm_resume +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x99252a7a tpm_release +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xa01db71d tpm_show_active +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xab7e44cc tpm_show_pubek +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xade7b79e tpm_read +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xb191e08e tpm_register_hardware +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xd16c33b5 tpm_show_owned +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xde052e88 tpm_pm_suspend +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xef9432fd tpm_show_pcrs +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xf4d283bc tpm_continue_selftest +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm_bios 0x7612fa7b tpm_bios_log_setup +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm_bios 0xa924b417 tpm_bios_log_teardown +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x07146b6f cpufreq_frequency_table_verify +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x2f47d8c7 cpufreq_frequency_get_table +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x5dcfc85f cpufreq_frequency_table_target +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x5e9329f1 cpufreq_freq_attr_scaling_available_freqs +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x706b3a33 cpufreq_frequency_table_get_attr +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x7ae1ae8e cpufreq_frequency_table_put_attr +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0xa26344c7 cpufreq_frequency_table_cpuinfo +EXPORT_SYMBOL_GPL drivers/dca/dca 0x00791e87 dca3_get_tag +EXPORT_SYMBOL_GPL drivers/dca/dca 0x2e471f01 dca_register_notify +EXPORT_SYMBOL_GPL drivers/dca/dca 0x31a2c8df dca_get_tag +EXPORT_SYMBOL_GPL drivers/dca/dca 0x36d754a2 dca_remove_requester +EXPORT_SYMBOL_GPL drivers/dca/dca 0x6394e99b register_dca_provider +EXPORT_SYMBOL_GPL drivers/dca/dca 0x6c67dcfd unregister_dca_provider +EXPORT_SYMBOL_GPL drivers/dca/dca 0x6fc76e0c alloc_dca_provider +EXPORT_SYMBOL_GPL drivers/dca/dca 0x8006c614 dca_unregister_notify +EXPORT_SYMBOL_GPL drivers/dca/dca 0xdc9dab6d free_dca_provider +EXPORT_SYMBOL_GPL drivers/dca/dca 0xf341a766 dca_add_requester +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x08c0ec14 edac_mc_handle_ue +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x1d398240 edac_pci_handle_npe +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x21102986 edac_mc_free +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x3f35bcaa edac_device_free_ctl_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x44388f6b edac_pci_create_generic_ctl +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x4ae038ae edac_pci_add_device +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x514782a3 edac_pci_free_ctl_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x56c5177c edac_mc_alloc +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x59ce74ce edac_device_handle_ue +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x5d427e80 edac_pci_alloc_ctl_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x5f3007d4 edac_mc_add_mc +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x6030ac31 edac_device_alloc_ctl_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x681c869b edac_pci_handle_pe +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x796f74a6 edac_device_add_device +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x81938dda edac_mc_del_mc +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x94c5c621 edac_pci_del_device +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xa022361d edac_pci_release_generic_ctl +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xb6dc7d06 edac_mc_find_csrow_by_page +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xbb00a728 edac_mc_handle_ce_no_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xbb59e130 edac_mc_handle_ce +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xbec92de3 edac_device_del_device +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xc644b087 edac_mc_handle_ue_no_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xcdbe177c edac_device_handle_ce +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xd940395c edac_pci_reset_delay_period +EXPORT_SYMBOL_GPL drivers/hid/hid 0x030f0aa9 hidinput_connect +EXPORT_SYMBOL_GPL drivers/hid/hid 0x2e6ff3ed hidinput_disconnect +EXPORT_SYMBOL_GPL drivers/hid/hid 0x2eff8ef6 hidinput_find_field +EXPORT_SYMBOL_GPL drivers/hid/hid 0x52b401b4 hid_output_report +EXPORT_SYMBOL_GPL drivers/hid/hid 0x71a756fd hid_input_report +EXPORT_SYMBOL_GPL drivers/hid/hid 0x7979ade0 hidinput_report_event +EXPORT_SYMBOL_GPL drivers/hid/hid 0x8725d565 hidraw_connect +EXPORT_SYMBOL_GPL drivers/hid/hid 0xa395e055 hid_free_device +EXPORT_SYMBOL_GPL drivers/hid/hid 0xa593a105 hid_parse_report +EXPORT_SYMBOL_GPL drivers/hid/hid 0xb3810755 hidraw_disconnect +EXPORT_SYMBOL_GPL drivers/hid/hid 0xbfa17174 hid_set_field +EXPORT_SYMBOL_GPL drivers/hid/hid 0xd1616d39 hidraw_report_event +EXPORT_SYMBOL_GPL drivers/hid/usbhid/usbhid 0x01fd453e usbhid_lookup_quirk +EXPORT_SYMBOL_GPL drivers/hid/usbhid/usbhid 0xb35a7577 hiddev_hid_event +EXPORT_SYMBOL_GPL drivers/i2c/busses/i2c-nforce2 0xa2a2ee82 nforce2_smbus +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0x1faabfcb i2c_new_probed_device +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0x34564629 i2c_unregister_device +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0x3a62127c i2c_bus_type +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0x4635b710 i2c_new_device +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0x723c5774 i2c_add_numbered_adapter +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0xe03e61cd i2c_new_dummy +EXPORT_SYMBOL_GPL drivers/ieee1394/ieee1394 0x60cfc04c hpsb_config_rom_ip1394_remove +EXPORT_SYMBOL_GPL drivers/ieee1394/ieee1394 0xa7bc2c5e hpsb_config_rom_ip1394_add +EXPORT_SYMBOL_GPL drivers/ieee1394/ieee1394 0xec8d18cf hpsb_disable_irm +EXPORT_SYMBOL_GPL drivers/input/ff-memless 0xd5626bf8 input_ff_create_memless +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x38dde1d8 wm97xx_unregister_mach_ops +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x4855ac68 wm9705_codec +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x4e299136 wm97xx_read_aux_adc +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x512e9538 wm97xx_reg_read +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x55ebb132 wm9712_codec +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x75ff16eb wm97xx_reg_write +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x993d089c wm97xx_config_gpio +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x9941b1ac wm9713_codec +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xa9931b20 wm97xx_set_suspend_mode +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xb8daa307 wm97xx_register_mach_ops +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xd56539d3 wm97xx_set_gpio +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xda674a9c wm97xx_get_gpio +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x0bd9c095 gigaset_shutdown +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x26a6b31d gigaset_start +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x29a46e75 gigaset_blockdriver +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x2cc001b9 gigaset_fill_inbuf +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x2ed1191a gigaset_freedriver +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x454aa44f gigaset_debuglevel +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x456b02c6 gigaset_freecs +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x4e792275 gigaset_dbg_buffer +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x63043537 gigaset_handle_modem_response +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x65baa9d3 gigaset_if_receive +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x8c2d08cb gigaset_stop +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x9f8b366d gigaset_initdriver +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0xb65a0483 gigaset_m10x_input +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0xc16e443c gigaset_initcs +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0xcd1fa9d7 gigaset_add_event +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0xd3a7f6d6 gigaset_skb_sent +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0xf1a9c3cf gigaset_m10x_send_skb +EXPORT_SYMBOL_GPL drivers/leds/led-class 0x101a6020 led_classdev_suspend +EXPORT_SYMBOL_GPL drivers/leds/led-class 0x435e4e53 led_classdev_register +EXPORT_SYMBOL_GPL drivers/leds/led-class 0x6fefed35 led_classdev_unregister +EXPORT_SYMBOL_GPL drivers/leds/led-class 0xbec5e11f led_classdev_resume +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0x79e859f8 dm_set_device_limits +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0x8aa659bf dm_noflush_suspending +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0xa240a925 dm_device_name +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0xc361bc07 dm_put +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0xc9378593 dm_path_uevent +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0xeaf71759 dm_disk +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0xf4fb64e5 dm_send_uevents +EXPORT_SYMBOL_GPL drivers/md/dm-multipath 0x3fc11b4f dm_unregister_path_selector +EXPORT_SYMBOL_GPL drivers/md/dm-multipath 0xaa0eab02 dm_register_path_selector +EXPORT_SYMBOL_GPL drivers/md/md-mod 0x5d8a9e2a sync_page_io +EXPORT_SYMBOL_GPL drivers/md/md-mod 0x8014ac46 md_new_event +EXPORT_SYMBOL_GPL drivers/md/md-mod 0xd089a2ac md_allow_write +EXPORT_SYMBOL_GPL drivers/md/md-mod 0xfddeac9d md_do_sync +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x04662e0f ir_codes_fusionhdtv_mce +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x07e92917 ir_codes_avermedia_a16d +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x083661f9 ir_codes_avertv_303 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x088631b9 ir_codes_behold +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x1cb148f5 ir_extract_bits +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x2456e513 ir_decode_pulsedistance +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x2a4852cc ir_codes_dntv_live_dvb_t +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x2af1a608 ir_codes_proteus_2309 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x306a2095 ir_input_keydown +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x3811daea ir_codes_manli +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x43c89ef4 ir_decode_biphase +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x45b08f68 ir_codes_pinnacle_grey +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x4740e7a3 ir_codes_empty +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x4ea698a2 ir_codes_purpletv +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x55338dda ir_codes_pixelview_new +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x589cad50 ir_codes_apac_viewcomp +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x5db13554 ir_codes_encore_enltv +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x611bb4f8 ir_input_nokey +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6606596a ir_rc5_timer_keyup +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6adc476d ir_codes_powercolor_real_angel +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6aefdbea ir_codes_npgtech +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6b87c69d ir_codes_iodata_bctv7e +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6ca27b55 ir_input_init +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6d6511e7 ir_dump_samples +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6e2a1870 ir_codes_adstech_dvb_t_pci +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x7277973d ir_codes_pctv_sedna +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x75e89cc3 ir_codes_flydvb +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x772a30a2 ir_codes_nebula +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x85d37490 ir_codes_dntv_live_dvbt_pro +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x89cc1189 ir_codes_winfast +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x902a3cd2 ir_codes_hauppauge_new +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x933d0bb3 ir_codes_msi_tvanywhere +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x9451e232 ir_codes_behold_columbus +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x96470cab ir_codes_cinergy +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xb1f4eb35 ir_codes_avermedia_dvbt +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xb6cd4666 ir_codes_eztv +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xbb08d146 ir_codes_msi_tvanywhere_plus +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xbdce6594 ir_codes_tt_1500 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xc1fea0c1 ir_codes_pv951 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xc42bd037 ir_codes_budget_ci_old +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xc6c5a7a1 ir_codes_em_terratec +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xd1e0258a ir_codes_flyvideo +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xd55e6891 ir_codes_gotview7135 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xd9c7f010 ir_codes_rc5_tv +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xdaa041ad ir_codes_cinergy_1400 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xdfcf23df ir_codes_norwood +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xee2f5e0e ir_codes_pinnacle_pctv_hd +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xf07533a1 ir_codes_videomate_tv_pvr +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xf0fc9374 ir_codes_avermedia +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xf2b421aa ir_codes_genius_tvgo_a11mce +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xf4f7a4d6 ir_rc5_timer_end +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xfa177653 ir_codes_pixelview +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xfb981300 ir_codes_pinnacle_color +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xfc54a5cd ir_codes_asus_pc39 +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x0550333b saa7146_vmalloc_build_pgtable +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x3d6c9d20 saa7146_pgtable_build_single +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x46952d28 saa7146_pgtable_free +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x4bb5daca saa7146_i2c_adapter_prepare +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x4c40fffa saa7146_wait_for_debi_done +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x555d2601 saa7146_register_extension +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x6869a3dd saa7146_unregister_extension +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xc17ee3d6 saa7146_pgtable_alloc +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xc98faf20 saa7146_devices_lock +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xcc856ec9 saa7146_setgpio +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xcf683cf2 saa7146_devices +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xe3cd9b5c saa7146_debug +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xee944413 saa7146_vfree_destroy_pgtable +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0x1679cbcd saa7146_unregister_device +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0x1beb6fc6 saa7146_set_hps_source_and_sync +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0x1e8dc80c saa7146_stop_preview +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0x58cc747b saa7146_start_preview +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0xa5ccaf4d saa7146_vv_init +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0xce8ce1cd saa7146_vv_release +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0xf4e7228c saa7146_register_device +EXPORT_SYMBOL_GPL drivers/media/common/tuners/mt20xx 0x745cff2a microtune_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/mxl5007t 0x17c94be6 mxl5007t_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda18271 0xe15a5db6 tda18271_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda827x 0x2881b149 tda827x_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda8290 0xe30cfd58 tda829x_probe +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda8290 0xf61614f5 tda829x_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda9887 0x1a7b9dcd tda9887_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tea5761 0x44d495a8 tea5761_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tea5761 0xeea7b3de tea5761_autodetection +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tea5767 0x0720c36a tea5767_autodetection +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tea5767 0x0ef019ee tea5767_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tuner-simple 0x80353472 simple_tuner_attach +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x0a525cd7 ttpci_budget_init +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x13b8f9bd ttpci_budget_deinit +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x2878e21c ttpci_budget_debiread +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x4554c633 ttpci_budget_irq10_handler +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x7948c222 budget_debug +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x8c05489b ttpci_budget_debiwrite +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x99531fba ttpci_budget_set_video_port +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0xf15ab872 ttpci_budget_init_hooks +EXPORT_SYMBOL_GPL drivers/media/video/compat_ioctl32 0xf77b1a5a v4l_compat_ioctl32 +EXPORT_SYMBOL_GPL drivers/media/video/cx88/cx88xx 0x943d7b3e cx88_setup_xc3028 +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0x26d31308 em28xx_uninit_isoc +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0x5d6fb9c4 em28xx_set_mode +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0x6e0ad81e em28xx_init_isoc +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0xd22c24eb em28xx_tuner_callback +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0xf93bce64 em28xx_audio_analog_set +EXPORT_SYMBOL_GPL drivers/media/video/saa7134/saa7134 0x382d3666 saa7134_g_ctrl_internal +EXPORT_SYMBOL_GPL drivers/media/video/saa7134/saa7134 0x88e0834e saa7134_s_ctrl_internal +EXPORT_SYMBOL_GPL drivers/media/video/saa7134/saa7134 0x90df59a9 saa7134_ts_qops +EXPORT_SYMBOL_GPL drivers/media/video/saa7134/saa7134 0xd0af8189 saa7134_queryctrl +EXPORT_SYMBOL_GPL drivers/media/video/v4l2-int-device 0xab0675b0 v4l2_int_device_unregister +EXPORT_SYMBOL_GPL drivers/media/video/v4l2-int-device 0xc75ef203 v4l2_int_device_register +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x116cbeb7 videobuf_next_field +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x2057abe2 videobuf_mmap_mapper +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x2bf9fd80 videobuf_qbuf +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x2e2140af videobuf_reqbufs +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x34aaecf7 videobuf_alloc +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x38874e02 __videobuf_mmap_setup +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x50b6266f videobuf_queue_to_vmalloc +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x57ff67f0 videobuf_queue_cancel +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x5ed5da44 videobuf_cgmbuf +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x63ff9828 videobuf_querybuf +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x69f6dafd videobuf_mmap_setup +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x6e4c9998 videobuf_read_one +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x7361f6af videobuf_poll_stream +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x7e1682e9 videobuf_streamon +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x8001d631 videobuf_read_start +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x834e2039 videobuf_mmap_free +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x8b3c1816 videobuf_queue_core_init +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x91a87779 videobuf_dqbuf +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x949369ea videobuf_read_stop +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x9c562a1e videobuf_streamoff +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xc3d3b65b videobuf_stop +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xc819ac6d videobuf_queue_is_busy +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xc8c15e63 videobuf_iolock +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xec3895b2 videobuf_waiton +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xf278999d videobuf_read_stream +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-contig 0x36c56b35 videobuf_dma_contig_free +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-contig 0x8c294003 videobuf_to_dma_contig +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-contig 0xb9f9d090 videobuf_queue_dma_contig_init +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x020677c4 videobuf_dma_map +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x3ae7c457 videobuf_dma_init_kernel +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x3d814579 videobuf_dma_init_user +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x69626586 videobuf_queue_sg_init +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x70edb305 videobuf_sg_dma_unmap +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x83021045 videobuf_dma_init +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x8b8a4cf8 videobuf_dma_sync +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x916f2eb6 videobuf_sg_dma_map +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x94e77690 videobuf_dma_unmap +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0xa825c75b videobuf_sg_alloc +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0xaaecdaa3 videobuf_to_dma +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0xd9020d0d videobuf_dma_init_overlay +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0xe8a24336 videobuf_vmalloc_to_sg +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0xfa325666 videobuf_dma_free +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-vmalloc 0x1beb4deb videobuf_vmalloc_free +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-vmalloc 0x1ed2cbf5 videobuf_to_vmalloc +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-vmalloc 0x3d504530 videobuf_queue_vmalloc_init +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0x092f2323 sm501_misc_control +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0x0bf27ed4 sm501_set_clock +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0x408622fa sm501_modify_reg +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0x80a2da40 sm501_find_clock +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0xf688a019 sm501_unit_power +EXPORT_SYMBOL_GPL drivers/misc/eeprom_93cx6 0x2df115d4 eeprom_93cx6_multiread +EXPORT_SYMBOL_GPL drivers/misc/eeprom_93cx6 0x63d14d2f eeprom_93cx6_read +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0x2a842dfa enclosure_register +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0x339fc797 enclosure_unregister +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0x42801409 enclosure_remove_device +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0x573cdf34 enclosure_find +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0x7733a083 enclosure_for_each_device +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0xc10c71e9 enclosure_add_device +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0xdc2306b9 enclosure_component_register +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x00c427c2 sdio_writeb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x048e8c9f sdio_writel +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x1823e066 sdio_claim_irq +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x18776171 sdio_register_driver +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x2259c084 sdio_release_host +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x2c10b5f9 sdio_writew +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x38828e0e sdio_f0_writeb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x55436798 sdio_readb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x5566734b sdio_enable_func +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x57aa3a9d sdio_memcpy_toio +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x5edf6c48 sdio_f0_readb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x6e7f77db sdio_readw +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x81df932b sdio_memcpy_fromio +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x87ddac10 sdio_release_irq +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xab9a7548 sdio_disable_func +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xaf3101e7 sdio_readsb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xb00997dd sdio_claim_host +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xbe550161 sdio_unregister_driver +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xc786aeb0 sdio_writesb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xd0d7e56e sdio_set_block_size +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xe3a2966f sdio_readl +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xeb2e1a55 sdio_align_size +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0x3732fc77 sdhci_resume_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0x62321a8b sdhci_remove_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0x75dd834f sdhci_suspend_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0x7e421023 sdhci_alloc_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0xac9c8a4d sdhci_free_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0xf338abed sdhci_add_host +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0001 0x0c78e9eb cfi_cmdset_0003 +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0001 0x67712b3a cfi_cmdset_0200 +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0001 0x953c9067 cfi_cmdset_0001 +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0002 0x40dad52d cfi_cmdset_0002 +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0020 0x3d0927d3 cfi_cmdset_0020 +EXPORT_SYMBOL_GPL drivers/mtd/devices/doc2000 0x369b6acc DoC2k_init +EXPORT_SYMBOL_GPL drivers/mtd/devices/doc2001 0xd07625eb DoCMil_init +EXPORT_SYMBOL_GPL drivers/mtd/devices/doc2001plus 0x30feac3b DoCMilPlus_init +EXPORT_SYMBOL_GPL drivers/mtd/devices/docecc 0x45937659 doc_decode_ecc +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x02bd7e6f mtd_erase_callback +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x0be5e26c add_mtd_device +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x12f5952e unregister_mtd_user +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x20286d6a kill_mtd_super +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x271bdddb get_mtd_device +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x35e2c5bf parse_mtd_partitions +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x50f167c0 deregister_mtd_parser +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xaa4b3e61 put_mtd_device +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xab387b6c get_mtd_device_nm +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xb9182d53 get_sb_mtd +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xbe7925d7 default_mtd_writev +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xbfed2d3d register_mtd_parser +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xc01d66e0 del_mtd_device +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xe399888f mtd_table +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xeff64be1 mtd_table_mutex +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xfe88221b register_mtd_user +EXPORT_SYMBOL_GPL drivers/mtd/mtd_blkdevs 0x284b50fd del_mtd_blktrans_dev +EXPORT_SYMBOL_GPL drivers/mtd/mtd_blkdevs 0x440bae57 add_mtd_blktrans_dev +EXPORT_SYMBOL_GPL drivers/mtd/mtd_blkdevs 0x5f4a7b2b register_mtd_blktrans +EXPORT_SYMBOL_GPL drivers/mtd/mtd_blkdevs 0x7ad4b81f deregister_mtd_blktrans +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0x64caa7f3 nand_scan_tail +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0x67764035 nand_release +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0xac9971ca nand_wait_ready +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0xd27cc038 nand_scan +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0xe335bcf8 nand_scan_ident +EXPORT_SYMBOL_GPL drivers/mtd/onenand/onenand 0xb88ec006 onenand_release +EXPORT_SYMBOL_GPL drivers/mtd/onenand/onenand 0xec87fffa onenand_scan +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x42801d20 ubi_sync +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x5ec6880b ubi_get_volume_info +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x6501e8df ubi_leb_read +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x6f409987 ubi_leb_write +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x7ae18e05 ubi_is_mapped +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x7f5f791b ubi_leb_unmap +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x7fb70d8a ubi_leb_change +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xae645358 ubi_close_volume +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xbc505df4 ubi_get_device_info +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xcc96440d ubi_open_volume +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xe5f5fda5 ubi_leb_map +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xf3fdbd58 ubi_open_volume_nm +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xfb824a08 ubi_leb_erase +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x0211544b mlx4_pd_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x111520d6 mlx4_srq_arm +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x1bc6a85b mlx4_multicast_detach +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x1d4738f3 mlx4_INIT_PORT +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x1d928135 mlx4_fmr_enable +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x214e9ed1 mlx4_buf_write_mtt +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x2e0ee29b mlx4_qp_remove +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x3782c83b mlx4_srq_query +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x39a7e148 mlx4_register_interface +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x3acb4f1b mlx4_mr_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x3dcf93af mlx4_alloc_hwq_res +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x449fb32f mlx4_mtt_init +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x44f25dcd mlx4_fmr_unmap +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x4a6d90f7 mlx4_qp_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x4bc69c51 mlx4_pd_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x5139d984 mlx4_cq_modify +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x51f708a5 mlx4_cq_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x5d0bba6a mlx4_CLOSE_PORT +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x63dd4824 mlx4_alloc_cmd_mailbox +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x676d19f2 mlx4_db_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x6e8a50d0 mlx4_mtt_cleanup +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x701195fd mlx4_SYNC_TPT +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x72c3e9ec mlx4_buf_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x7d3721e5 mlx4_multicast_attach +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x825631eb mlx4_unregister_interface +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x825d0510 mlx4_qp_to_ready +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x82bb57ea mlx4_cq_resize +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x898c02ef __mlx4_cmd +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x9109a5e6 mlx4_fmr_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x914fae80 mlx4_cq_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x98c54b3c mlx4_db_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x9b613b18 mlx4_qp_modify +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x9bfea6b0 mlx4_write_mtt +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xa7bc169b mlx4_map_phys_fmr +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xa9b3787e mlx4_fmr_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xb0302bbc mlx4_uar_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xb6a5731e mlx4_qp_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xc1555382 mlx4_mr_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xc20864ff mlx4_srq_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xcd9694ea mlx4_mr_enable +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xd1d2cb8e mlx4_srq_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xd211ebda mlx4_free_cmd_mailbox +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xdf59c2c9 mlx4_mtt_addr +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xe5962301 mlx4_buf_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xedd74102 mlx4_free_hwq_res +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xf611661c mlx4_uar_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xfdd6e8ba mlx4_qp_query +EXPORT_SYMBOL_GPL drivers/net/usb/cdc_ether 0x3988fefe usbnet_generic_cdc_bind +EXPORT_SYMBOL_GPL drivers/net/usb/cdc_ether 0xca211ce3 usbnet_cdc_unbind +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0x51963a68 rndis_tx_fixup +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0x63691d18 rndis_unbind +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0x90de2e75 rndis_rx_fixup +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0x9fbd962d generic_rndis_bind +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0xc04df383 rndis_status +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0xf2c526c2 rndis_command +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x20a7a1b1 usbnet_get_msglevel +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x2413a1b4 usbnet_skb_return +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x33285aac usbnet_probe +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x398a9507 usbnet_disconnect +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x484a28c6 usbnet_defer_kevent +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x4e580be3 usbnet_set_msglevel +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x667a3934 usbnet_get_endpoints +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x670f22d8 usbnet_unlink_rx_urbs +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x6f2380b3 usbnet_resume +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x80206b33 usbnet_suspend +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x8f0e18b8 usbnet_get_settings +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xa9ae12ea usbnet_set_settings +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xc80c8793 usbnet_nway_reset +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xcee9ac0e usbnet_get_link +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xd9731490 usbnet_get_drvinfo +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x0df01924 lbs_suspend +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x1ac01ed2 __lbs_cmd +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x26da5672 lbs_host_sleep_cfg +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x2edd07dd lbs_process_rxed_packet +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x2fc42d4e lbs_host_to_card_done +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x35be5e9d lbs_stop_card +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x4d6f3c3b lbs_notify_command_response +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x5c603edb lbs_resume +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x65babdf2 lbs_cmd_copyback +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x87dbc040 lbs_cmd_802_11_rate_adapt_rateset +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x9a64b40a lbs_add_card +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xcc920043 lbs_queue_event +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xd95b9991 lbs_send_tx_feedback +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xdfbd368d lbs_remove_card +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xe7bb72b4 lbs_start_card +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xf64277de lbs_debug +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0x3ac4b67e p54_rx +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0x52b3e6e2 p54_init_common +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0x8aa71b5b p54_parse_firmware +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0x93009638 p54_parse_eeprom +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0x9c947b39 p54_free_common +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0xaa748adb p54_fill_eeprom_readback +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x1e4a15d3 rt2x00mac_add_interface +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x3c29f9c9 rt2x00mac_tx +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x3e192104 rt2x00mac_remove_interface +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x443ecd89 rt2x00mac_get_tx_stats +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x48de0b18 rt2x00mac_config_interface +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x4d4b44af rt2x00lib_beacondone +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x4d589840 rt2x00lib_resume +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x62cf9a84 rt2x00mac_stop +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x8487f6ea rt2x00queue_get_entry +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x9b64be17 rt2x00queue_map_txskb +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xc93a6130 rt2x00lib_probe_dev +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xce05eef6 rt2x00mac_configure_filter +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xd97feb43 rt2x00lib_txdone +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xe1a34173 rt2x00queue_get_queue +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xe23ee9bc rt2x00mac_config +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xe4e9f963 rt2x00lib_suspend +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xf19a7b36 rt2x00lib_rxdone +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xf19faeb4 rt2x00mac_get_stats +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xf2b6504b rt2x00mac_start +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xf4349f3f rt2x00mac_conf_tx +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xf6bdeb64 rt2x00lib_remove_dev +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xf967f293 rt2x00mac_bss_info_changed +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0x2543455f rt2x00pci_probe +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0x331da71b rt2x00pci_resume +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0x67afeda0 rt2x00pci_write_tx_data +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0x72a54154 rt2x00pci_rxdone +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0xa3cb677b rt2x00pci_uninitialize +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0xbdfecbdd rt2x00pci_initialize +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0xcb9630b6 rt2x00pci_remove +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0xd108a389 rt2x00pci_suspend +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x18f13ea5 rt2x00usb_vendor_request_large_buff +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x3601853f rt2x00usb_vendor_request +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x4b643887 rt2x00usb_init_txentry +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x51d6a135 rt2x00usb_init_rxentry +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x57d95f95 rt2x00usb_disconnect +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x5f219e74 rt2x00usb_initialize +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x6a98dd63 rt2x00usb_vendor_req_buff_lock +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x751f0df0 rt2x00usb_write_tx_data +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x7824e827 rt2x00usb_probe +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x7fb7adbe rt2x00usb_vendor_request_buff +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0xa2fbc029 rt2x00usb_kick_tx_queue +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0xc189c876 rt2x00usb_disable_radio +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0xc70f277f rt2x00usb_uninitialize +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0xcf169d52 rt2x00usb_resume +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0xcff933a9 rt2x00usb_suspend +EXPORT_SYMBOL_GPL drivers/pci/hotplug/acpiphp 0xb8b45144 acpiphp_unregister_attention +EXPORT_SYMBOL_GPL drivers/pci/hotplug/acpiphp 0xccac0594 acpiphp_register_attention +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x06839218 cpci_hp_register_controller +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x1ad3b491 acpi_root_bridge +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x2fe84fb3 pci_hp_deregister +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x36ee686b pci_hp_change_slot_info +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x43f49b1c pci_hp_register +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x6a8441be cpci_hp_start +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x7704e572 cpci_hp_register_bus +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x8b26d43d acpi_get_hp_params_from_firmware +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x94ef4d05 cpci_hp_stop +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0xa8721cee cpci_hp_unregister_controller +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0xbf33b2bf cpci_hp_unregister_bus +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x53a4e70d scsi_dh_attach +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x593a36c2 scsi_dh_handler_exist +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x6142e5ba scsi_register_device_handler +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x6bdcbb53 scsi_dh_activate +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x82c983f8 scsi_dh_detach +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x926769cf scsi_unregister_device_handler +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x0233f349 iscsi_pool_init +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x066245e7 iscsi_conn_setup +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x10f39971 iscsi_host_alloc +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x11ef7044 iscsi_prep_unsolicit_data_pdu +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x18bc06e6 iscsi_host_add +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x289647cd iscsi_queuecommand +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x2e391ca7 iscsi_requeue_task +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x2e50cc6d iscsi_conn_teardown +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x3be0dd77 iscsi_complete_pdu +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x41ba1d14 iscsi_pool_free +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x42a5fb94 iscsi_conn_send_pdu +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x50e1761b iscsi_session_recovery_timedout +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x5886f9db iscsi_eh_abort +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x599d7f81 iscsi_host_remove +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x706f0fab iscsi_itt_to_ctask +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x805f78c3 iscsi_host_free +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x85154e10 iscsi_update_cmdsn +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x854420d7 iscsi_verify_itt +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x95140772 iscsi_eh_host_reset +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x9df75d6c __iscsi_get_task +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xa03c6d36 iscsi_change_queue_depth +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xb2fcde36 iscsi_conn_get_param +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xb774a086 iscsi_put_task +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xb9f3ec98 iscsi_conn_stop +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xbfdd8483 iscsi_eh_device_reset +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xca76efa9 iscsi_session_setup +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xcf487a3f iscsi_set_param +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xd656cc40 __iscsi_complete_pdu +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xd7f44a4e iscsi_conn_bind +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xdba62cf4 iscsi_conn_start +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xdd0b2f87 iscsi_host_set_param +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xe4457c90 iscsi_session_teardown +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xe5c8a9fc iscsi_conn_failure +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xeb018f27 iscsi_suspend_tx +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xf34b88b7 iscsi_host_get_param +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xf8cc1a92 iscsi_session_get_param +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x0e66f048 sas_slave_destroy +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x19143e5e sas_phy_enable +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x3756f919 sas_target_alloc +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x4eca1776 sas_eh_device_reset_handler +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x5a8747e0 sas_task_abort +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x6902b2eb sas_ioctl +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x70870ca2 sas_target_destroy +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x716eddde sas_ssp_task_response +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x75fe164a sas_domain_attach_transport +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x81a02d22 sas_domain_release_transport +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x84e5df32 sas_slave_alloc +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x8a85ad44 sas_change_queue_type +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x93fe415e sas_queuecommand +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x989f89e1 sas_find_local_phy +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x9c5c4a3b sas_eh_bus_reset_handler +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xa462c2e8 __sas_task_abort +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xb27188ad sas_request_addr +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xd4d366c6 sas_phy_reset +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xd8224e23 sas_slave_configure +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xe33620c7 sas_unregister_ha +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xe48e398a sas_register_ha +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xf7d47d57 sas_bios_param +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xfe48c0e5 sas_change_queue_depth +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x1ca8f94d srp_target_free +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x39cd0ccc srp_target_alloc +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x5afd39da srp_iu_get +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x7c6c6e76 srp_cmd_queue +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0xa131a76f srp_iu_put +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0xddc10ee4 srp_transfer_data +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x02123c9c scsi_internal_device_unblock +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x05112b05 sdev_evt_send +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x07a2f5fa scsi_target_block +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x147de63a sdev_evt_send_simple +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x1aafbff7 scsi_flush_work +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x20a5024b scsi_target_unblock +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x26c90ea4 scsi_eh_get_sense +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x350c9d5c __scsi_get_command +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x35d8c94a sdev_evt_alloc +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x39bd766b scsi_bus_type +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x4c6f6261 scsi_schedule_eh +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x572c2001 scsi_mode_select +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x66a39391 scsi_eh_ready_devs +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x7e275ea8 scsi_complete_async_scans +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xb4a0d14b scsi_nl_sock +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xbd69a279 scsi_queue_work +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xc17bc958 scsi_execute_async +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xca7ac52c scsi_internal_device_block +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x1499d0ac scsi_tgt_alloc_queue +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x2c3c658f scsi_tgt_cmd_to_host +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x43ee0fc1 scsi_tgt_free_queue +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x7c55ca0d scsi_tgt_queue_command +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x80eee21e scsi_host_get_command +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x9391204e scsi_tgt_it_nexus_destroy +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x93c8198b scsi_tgt_it_nexus_create +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0xad5a2861 scsi_host_put_command +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0xe53750b6 scsi_tgt_tsk_mgmt_request +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x3115fa86 iscsi_create_endpoint +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x31878573 iscsi_register_transport +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x345fc3f4 iscsi_host_for_each_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x37018412 iscsi_alloc_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x3b1b2d29 iscsi_recv_pdu +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x5f532069 iscsi_conn_error +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x66145a93 iscsi_destroy_conn +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x92d883e2 iscsi_free_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x94b46af3 iscsi_unregister_transport +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x9d1b886b iscsi_remove_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x9ef18350 iscsi_session_chkready +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xa2f2251c iscsi_scan_finished +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xb10d0bc8 iscsi_lookup_endpoint +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xba621229 iscsi_destroy_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xbe6b0f2c iscsi_unblock_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xc7514708 iscsi_block_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xd899714e iscsi_add_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xdf64a2a1 iscsi_session_event +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xec8da594 iscsi_destroy_endpoint +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xee32cb7f iscsi_create_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xfac0372f iscsi_create_conn +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_spi 0x0ef06974 spi_populate_ppr_msg +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_spi 0xa0c71dac spi_populate_sync_msg +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_spi 0xcffa2aff spi_populate_width_msg +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0x049e44f7 srp_release_transport +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0x244f0f84 srp_rport_add +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0x4b34174b srp_rport_del +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0xbf1fdb7a srp_attach_transport +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0xd1fa35b1 srp_remove_host +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0x1be2a89a spi_bitbang_setup_transfer +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0x1ff74300 spi_bitbang_start +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0x72ad0c5a spi_bitbang_transfer +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0x74fae0b9 spi_bitbang_setup +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0xbb8b975d spi_bitbang_cleanup +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0xed708a1c spi_bitbang_stop +EXPORT_SYMBOL_GPL drivers/uio/uio 0x458b9d7d __uio_register_device +EXPORT_SYMBOL_GPL drivers/uio/uio 0xd65e4a69 uio_unregister_device +EXPORT_SYMBOL_GPL drivers/uio/uio 0xfee16022 uio_event_notify +EXPORT_SYMBOL_GPL drivers/usb/atm/usbatm 0x3e7f9324 usbatm_usb_probe +EXPORT_SYMBOL_GPL drivers/usb/atm/usbatm 0x5079d584 usbatm_usb_disconnect +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x011a8b49 usb_store_new_id +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x066e2336 usb_buffer_unmap_sg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x089862fa usb_hcd_pci_probe +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x0c0b0ac3 usb_hcd_unlink_urb_from_ep +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x10a54b26 usb_get_descriptor +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x10fc5ee9 usb_get_current_frame_number +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x11bf8562 usb_hcd_giveback_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x19a304ba usb_disabled +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x1e8832af usb_put_intf +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x2033577a usb_ifnum_to_if +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x249d0af1 usb_unlink_anchored_urbs +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x2ce86a38 usb_remove_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x2e8af597 usb_buffer_free +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x3953d27b usb_set_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x39ec398d usb_deregister +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x3be89d3c usb_register_notify +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x3d708fe3 usb_hcd_pci_suspend +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x3ddb5f79 usb_register_driver +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x4278efd8 usb_hcd_platform_shutdown +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x44928f2d usb_hcd_poll_rh_status +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x4deb2ba8 usb_lock_device_for_reset +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x5059510f usb_create_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x53fc2a7f usb_driver_release_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x5a3bd481 usb_init_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x65181995 usb_mon_register +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x69301155 usb_driver_set_configuration +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x6dce94bf usb_bus_list_lock +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x6e959d3d usb_altnum_to_altsetting +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x6fa9afa0 usb_bulk_msg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x700e1785 usb_get_status +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x72f60e02 usb_put_dev +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x7868aae2 usb_match_one_id +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x78a7ec2a usb_alloc_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x7b498f68 usb_deregister_device_driver +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x7e57db36 usb_sg_cancel +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x7e64181d usb_calc_bus_time +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x7efe0541 usb_kill_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x80a3972b usb_interrupt_msg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x81c62f33 usb_get_intf +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x84e79894 usb_get_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x86b10394 ehci_cf_port_reset_rwsem +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x86cb2d50 usb_match_id +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x891e4095 usb_ep0_reinit +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x892b0d4e usb_root_hub_lost_power +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x894d359a usb_buffer_alloc +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x8e15634a usb_clear_halt +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x90981f8a usb_reset_configuration +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x90f921a2 usb_hcd_check_unlink_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x91ac1e5e usb_driver_claim_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x926782bd usb_hcd_link_urb_to_ep +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x9311a242 usb_hcd_resume_root_hub +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x94a61a19 usb_free_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x951185b6 usb_submit_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x9924c496 __usb_get_extra_descriptor +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x9a37ed24 usb_hc_died +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xace5c0fc usb_bus_list +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xb0b100a6 usb_string +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xb27f4efc usb_sg_init +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xb3b22675 usb_hcd_pci_resume +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xb4c6f333 usb_find_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xb9bb9953 usb_control_msg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xbad146a9 usb_reset_device +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xbc3a242f usb_wait_anchor_empty_timeout +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xbf2625b4 usb_autopm_put_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xbf381fd1 usb_autopm_get_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xc17515d7 usb_hcds_loaded +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xc8339bba usb_hub_tt_clear_buffer +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xcc104b36 usb_get_dev +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xce8ed250 usb_hcd_pci_shutdown +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xdac44a8a usb_hcd_pci_remove +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xdd70de6e usb_unlink_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xe3875d2a usb_kill_anchored_urbs +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xe4031827 usb_autopm_set_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xe83c99e6 usb_register_device_driver +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xe9587909 usb_unregister_notify +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xeb1442d0 usb_put_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xec359ee6 usb_register_dev +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xec3d52b2 usb_sg_wait +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xed324a67 usb_buffer_map_sg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xeebf65c3 usb_unanchor_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xf4a12c69 usb_add_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xfb74ddb0 usb_get_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xfdc93c03 usb_anchor_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xfed11ed1 usb_mon_deregister +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xff78ae9a usb_deregister_dev +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x191ea200 usb_ftdi_elan_edset_output +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x1ae569c6 usb_ftdi_elan_edset_single +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x256ec92d usb_ftdi_elan_edset_setup +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x4b156a2a usb_ftdi_elan_edset_empty +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x548b0a5a usb_ftdi_elan_read_pcimem +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x552612ba ftdi_elan_gone_away +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x99b07670 usb_ftdi_elan_edset_flush +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0xcd6a060a usb_ftdi_elan_write_pcimem +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0xf7b766ff usb_ftdi_elan_edset_input +EXPORT_SYMBOL_GPL drivers/usb/misc/phidget 0x5bfbf2b8 phidget_class +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x02ad7c84 usb_serial_disconnect +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x0a0c6a84 ezusb_writememory +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x37a34a40 ezusb_set_reset +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x3f99b572 usb_serial_register +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x568bc99f usb_serial_generic_open +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x6edeae9b usb_serial_generic_write_bulk_callback +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x71a08760 usb_serial_deregister +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x94dd3156 usb_serial_probe +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0xd3d7c30e usb_serial_port_softint +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0xf9ef38cc usb_serial_generic_read_bulk_callback +EXPORT_SYMBOL_GPL drivers/usb/storage/libusual 0x3edad223 usb_usual_clear_present +EXPORT_SYMBOL_GPL drivers/usb/storage/libusual 0x89d4dbaf usb_usual_check_type +EXPORT_SYMBOL_GPL drivers/usb/storage/libusual 0xcd9991a9 usb_usual_set_present +EXPORT_SYMBOL_GPL drivers/usb/storage/libusual 0xde134c69 storage_usb_ids +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x08b46a8e ili9320_shutdown +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x12d23f2b ili9320_write +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x4159205d ili9320_remove +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x8c635f50 ili9320_write_regs +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x9a777f92 ili9320_resume +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0xafd10f0b ili9320_suspend +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0xea6f55bb ili9320_probe_spi +EXPORT_SYMBOL_GPL drivers/video/fb_ddc 0x5fa1a4f1 fb_ddc_read +EXPORT_SYMBOL_GPL drivers/video/fb_sys_fops 0x216bb1eb fb_sys_write +EXPORT_SYMBOL_GPL drivers/video/fb_sys_fops 0xf9d19527 fb_sys_read +EXPORT_SYMBOL_GPL drivers/video/sis/sisfb 0x168f9b86 sis_malloc_new +EXPORT_SYMBOL_GPL drivers/video/sis/sisfb 0x6c0f0c12 sis_free_new +EXPORT_SYMBOL_GPL drivers/video/vermilion/vmlfb 0x016e6c20 vmlfb_unregister_subsys +EXPORT_SYMBOL_GPL drivers/video/vermilion/vmlfb 0x90c018c6 vmlfb_register_subsys +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0x075a1f84 unregister_virtio_driver +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0x31090a49 unregister_virtio_device +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0xa1b8be23 register_virtio_device +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0xa7847deb register_virtio_driver +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0xed3f94ed virtio_check_driver_offered_feature +EXPORT_SYMBOL_GPL drivers/virtio/virtio_ring 0x03c4687d vring_interrupt +EXPORT_SYMBOL_GPL drivers/virtio/virtio_ring 0x725ff6f7 vring_transport_features +EXPORT_SYMBOL_GPL drivers/virtio/virtio_ring 0xa8279936 vring_new_virtqueue +EXPORT_SYMBOL_GPL drivers/virtio/virtio_ring 0xcc838a30 vring_del_virtqueue +EXPORT_SYMBOL_GPL drivers/w1/wire 0x50c66761 w1_write_8 +EXPORT_SYMBOL_GPL drivers/w1/wire 0x7c2f2afb w1_calc_crc8 +EXPORT_SYMBOL_GPL drivers/w1/wire 0x9a5a25aa w1_write_block +EXPORT_SYMBOL_GPL drivers/w1/wire 0xa3ad80c5 w1_reset_bus +EXPORT_SYMBOL_GPL drivers/w1/wire 0xb50662cb w1_read_block +EXPORT_SYMBOL_GPL drivers/w1/wire 0xf1fc3c6b w1_reset_select_slave +EXPORT_SYMBOL_GPL fs/dlm/dlm 0x36f2796e dlm_posix_lock +EXPORT_SYMBOL_GPL fs/dlm/dlm 0x3bfb0074 dlm_posix_get +EXPORT_SYMBOL_GPL fs/dlm/dlm 0x9321df95 dlm_lock +EXPORT_SYMBOL_GPL fs/dlm/dlm 0x9a76cb41 dlm_posix_unlock +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xcf9f3328 dlm_release_lockspace +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xdc583c08 dlm_unlock +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xdf3c14de dlm_new_lockspace +EXPORT_SYMBOL_GPL fs/exportfs/exportfs 0x151212b9 exportfs_decode_fh +EXPORT_SYMBOL_GPL fs/exportfs/exportfs 0xa12e7d4a exportfs_encode_fh +EXPORT_SYMBOL_GPL fs/fat/fat 0x01e0ce9b fat_fill_super +EXPORT_SYMBOL_GPL fs/fat/fat 0x0933c14c fat_setattr +EXPORT_SYMBOL_GPL fs/fat/fat 0x2713fdda fat_attach +EXPORT_SYMBOL_GPL fs/fat/fat 0x339be916 fat_flush_inodes +EXPORT_SYMBOL_GPL fs/fat/fat 0x408f7eb5 fat_get_dotdot_entry +EXPORT_SYMBOL_GPL fs/fat/fat 0x5f2b4054 fat_alloc_new_dir +EXPORT_SYMBOL_GPL fs/fat/fat 0x6d127ac1 fat_sync_inode +EXPORT_SYMBOL_GPL fs/fat/fat 0x70f44307 fat_add_entries +EXPORT_SYMBOL_GPL fs/fat/fat 0x7163b07c fat_build_inode +EXPORT_SYMBOL_GPL fs/fat/fat 0x7f034cb8 fat_remove_entries +EXPORT_SYMBOL_GPL fs/fat/fat 0x879d2812 fat_scan +EXPORT_SYMBOL_GPL fs/fat/fat 0xa1c311ab fat_detach +EXPORT_SYMBOL_GPL fs/fat/fat 0xb0f208b6 fat_getattr +EXPORT_SYMBOL_GPL fs/fat/fat 0xb68ea16d fat_date_unix2dos +EXPORT_SYMBOL_GPL fs/fat/fat 0xc184962e fat_free_clusters +EXPORT_SYMBOL_GPL fs/fat/fat 0xca4c8048 fat_fs_panic +EXPORT_SYMBOL_GPL fs/fat/fat 0xd2d5db64 fat_search_long +EXPORT_SYMBOL_GPL fs/fat/fat 0xd6bca19f fat_dir_empty +EXPORT_SYMBOL_GPL fs/gfs2/gfs2 0x29ea9118 gfs2_register_lockproto +EXPORT_SYMBOL_GPL fs/gfs2/gfs2 0xdbee07bd gfs2_unregister_lockproto +EXPORT_SYMBOL_GPL fs/lockd/lockd 0x1a618932 nlmsvc_unlock_all_by_ip +EXPORT_SYMBOL_GPL fs/lockd/lockd 0x8ca62ea5 nlmclnt_done +EXPORT_SYMBOL_GPL fs/lockd/lockd 0xc6c7ced7 nlmsvc_unlock_all_by_sb +EXPORT_SYMBOL_GPL fs/lockd/lockd 0xe12c4623 nlmclnt_init +EXPORT_SYMBOL_GPL fs/lockd/lockd 0xfaf5db43 nlmclnt_proc +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x1b89c6ee o2hb_fill_node_map +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x1cb231d0 mlog_not_bits +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x1d747ce3 o2hb_check_node_heartbeating +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x2378a89f o2nm_node_put +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x28faa8c5 o2hb_setup_callback +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x36418553 o2net_send_message +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x4900035b o2hb_stop_all_regions +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x4999f203 o2hb_register_callback +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x5f7436a5 o2nm_get_node_by_ip +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x687f6251 mlog_and_bits +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x940d4c9d o2nm_get_node_by_num +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xa449b147 o2hb_unregister_callback +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xa82a8645 o2nm_this_node +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xa87bc9e7 o2nm_configured_node_map +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xa9f5379a o2net_send_message_vec +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xae808bac o2net_register_handler +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xbaeb4700 o2hb_check_node_heartbeating_from_callback +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xd60f2c6c o2hb_check_local_node_heartbeating +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xe096953f o2nm_node_get +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xf1a5611d o2net_unregister_handler_list +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0x0837d6a2 dlmunlock +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0x119d80a5 dlm_unregister_domain +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0x3a121890 dlmlock +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0x7a1211f8 dlm_setup_eviction_cb +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0x9b0bc589 dlm_register_domain +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xcbc0b1f5 dlm_print_one_lock +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xd7ba575e dlm_errmsg +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xd8fa57a6 dlm_unregister_eviction_cb +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xe6259c78 dlm_register_eviction_cb +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xfb86b96f dlm_errname +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x0562c415 ocfs2_cluster_this_node +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x0e27f909 ocfs2_dlm_lock +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x21db5b88 ocfs2_cluster_disconnect +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x4a1f6fe9 ocfs2_cluster_connect +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x4d3af7fa ocfs2_cluster_hangup +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x59602db7 ocfs2_stack_glue_register +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x5b14c343 ocfs2_stack_glue_unregister +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x81c85a68 ocfs2_dlm_lock_status +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x91fab465 ocfs2_dlm_lvb +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x963932a3 ocfs2_stack_glue_set_locking_protocol +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0xa7d5c1c0 ocfs2_dlm_unlock +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0xd066711e ocfs2_dlm_dump_lksb +EXPORT_SYMBOL_GPL lib/lzo/lzo_compress 0x56b63670 lzo1x_1_compress +EXPORT_SYMBOL_GPL lib/lzo/lzo_decompress 0xf30fda27 lzo1x_decompress_safe +EXPORT_SYMBOL_GPL lib/reed_solomon/reed_solomon 0x300d7e57 free_rs +EXPORT_SYMBOL_GPL lib/reed_solomon/reed_solomon 0x6fbb3bd9 init_rs_non_canonical +EXPORT_SYMBOL_GPL lib/reed_solomon/reed_solomon 0xabda1e2e decode_rs16 +EXPORT_SYMBOL_GPL lib/reed_solomon/reed_solomon 0xb050f329 init_rs +EXPORT_SYMBOL_GPL net/802/garp 0x0f2ca7ce garp_init_applicant +EXPORT_SYMBOL_GPL net/802/garp 0x3269430c garp_request_join +EXPORT_SYMBOL_GPL net/802/garp 0x5477e7ac garp_unregister_application +EXPORT_SYMBOL_GPL net/802/garp 0x8d474613 garp_uninit_applicant +EXPORT_SYMBOL_GPL net/802/garp 0x916423c4 garp_request_leave +EXPORT_SYMBOL_GPL net/802/garp 0xb27c7950 garp_register_application +EXPORT_SYMBOL_GPL net/802/stp 0x1ec0e31c stp_proto_unregister +EXPORT_SYMBOL_GPL net/802/stp 0xf35fca25 stp_proto_register +EXPORT_SYMBOL_GPL net/ax25/ax25 0xac93ae05 ax25_bcast +EXPORT_SYMBOL_GPL net/ax25/ax25 0xaeb7451e ax25_defaddr +EXPORT_SYMBOL_GPL net/ax25/ax25 0xd72f8793 ax25_register_pid +EXPORT_SYMBOL_GPL net/bluetooth/bluetooth 0xbca43e47 bt_class +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x063d2f2e tfrc_lh_interval_add +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x09c5ed3c tfrc_tx_hist_purge +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x0a487ea5 tfrc_calc_x +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x106fe6d3 tfrc_tx_hist_rtt +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x34c1ebde tfrc_rx_hist_duplicate +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x5ca89c9f tfrc_lh_update_i_mean +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x69ec5731 tfrc_tx_hist_add +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x6c252d29 tfrc_calc_x_reverse_lookup +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x7983279b tfrc_rx_hist_add_packet +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x902206f0 tfrc_lh_cleanup +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x92285650 tfrc_rx_hist_alloc +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0xa2a62dcc tfrc_rx_hist_sample_rtt +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0xc612a5b6 tfrc_rx_hist_purge +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0xda06c3a3 tfrc_rx_handle_loss +EXPORT_SYMBOL_GPL net/dccp/dccp 0x00b71088 ccid_hc_tx_delete +EXPORT_SYMBOL_GPL net/dccp/dccp 0x017209d7 dccp_create_openreq_child +EXPORT_SYMBOL_GPL net/dccp/dccp 0x113a1a0e dccp_done +EXPORT_SYMBOL_GPL net/dccp/dccp 0x12d8b335 dccp_reqsk_send_ack +EXPORT_SYMBOL_GPL net/dccp/dccp 0x147e2b6b dccp_poll +EXPORT_SYMBOL_GPL net/dccp/dccp 0x15245f31 dccp_rcv_state_process +EXPORT_SYMBOL_GPL net/dccp/dccp 0x1d99d49a dccp_timestamp +EXPORT_SYMBOL_GPL net/dccp/dccp 0x1dc250a1 inet_dccp_listen +EXPORT_SYMBOL_GPL net/dccp/dccp 0x2187b157 ccid_new +EXPORT_SYMBOL_GPL net/dccp/dccp 0x21af2c1a dccp_close +EXPORT_SYMBOL_GPL net/dccp/dccp 0x306f5e2e dccp_parse_options +EXPORT_SYMBOL_GPL net/dccp/dccp 0x33a24ef9 ccid_hc_rx_delete +EXPORT_SYMBOL_GPL net/dccp/dccp 0x39616356 dccp_feat_clone +EXPORT_SYMBOL_GPL net/dccp/dccp 0x39d4563c dccp_connect +EXPORT_SYMBOL_GPL net/dccp/dccp 0x3b276b51 dccp_send_ack +EXPORT_SYMBOL_GPL net/dccp/dccp 0x3b3c0b1b dccp_feat_clean +EXPORT_SYMBOL_GPL net/dccp/dccp 0x4282ffc3 dccp_hashinfo +EXPORT_SYMBOL_GPL net/dccp/dccp 0x4d0e39ea dccp_reqsk_init +EXPORT_SYMBOL_GPL net/dccp/dccp 0x4d3f0ab9 dccp_disconnect +EXPORT_SYMBOL_GPL net/dccp/dccp 0x52a13f55 dccp_destroy_sock +EXPORT_SYMBOL_GPL net/dccp/dccp 0x56758644 dccp_death_row +EXPORT_SYMBOL_GPL net/dccp/dccp 0x56ea266a dccp_state_name +EXPORT_SYMBOL_GPL net/dccp/dccp 0x57f1a03a dccp_insert_option_timestamp +EXPORT_SYMBOL_GPL net/dccp/dccp 0x60036c62 dccp_sample_rtt +EXPORT_SYMBOL_GPL net/dccp/dccp 0x678bf2ff dccp_send_sync +EXPORT_SYMBOL_GPL net/dccp/dccp 0x6c0fe55c dccp_check_req +EXPORT_SYMBOL_GPL net/dccp/dccp 0x75af5c75 dccp_init_sock +EXPORT_SYMBOL_GPL net/dccp/dccp 0x7c1b5be8 ccid_hc_tx_new +EXPORT_SYMBOL_GPL net/dccp/dccp 0x7f52d04a ccid_register +EXPORT_SYMBOL_GPL net/dccp/dccp 0x83f861e3 dccp_sync_mss +EXPORT_SYMBOL_GPL net/dccp/dccp 0x86be7924 dccp_packet_name +EXPORT_SYMBOL_GPL net/dccp/dccp 0x86d385e3 dccp_shutdown +EXPORT_SYMBOL_GPL net/dccp/dccp 0x88873f1f dccp_child_process +EXPORT_SYMBOL_GPL net/dccp/dccp 0x8b7d8caf dccp_statistics +EXPORT_SYMBOL_GPL net/dccp/dccp 0x8c2d2f63 dccp_insert_option +EXPORT_SYMBOL_GPL net/dccp/dccp 0x90fc0993 dccp_ctl_make_reset +EXPORT_SYMBOL_GPL net/dccp/dccp 0x93d13ab8 dccp_insert_option_elapsed_time +EXPORT_SYMBOL_GPL net/dccp/dccp 0x962e1e48 dccp_set_state +EXPORT_SYMBOL_GPL net/dccp/dccp 0x98b4383b dccp_sendmsg +EXPORT_SYMBOL_GPL net/dccp/dccp 0x9d6a3846 dccp_orphan_count +EXPORT_SYMBOL_GPL net/dccp/dccp 0xa529176a ccid_unregister +EXPORT_SYMBOL_GPL net/dccp/dccp 0xb9728eea dccp_make_response +EXPORT_SYMBOL_GPL net/dccp/dccp 0xbdbbeb1e dccp_getsockopt +EXPORT_SYMBOL_GPL net/dccp/dccp 0xbe4cf010 dccp_feat_init +EXPORT_SYMBOL_GPL net/dccp/dccp 0xbf6b58ba dccp_feat_change +EXPORT_SYMBOL_GPL net/dccp/dccp 0xc63f2d3b dccp_rcv_established +EXPORT_SYMBOL_GPL net/dccp/dccp 0xe1907bd1 dccp_recvmsg +EXPORT_SYMBOL_GPL net/dccp/dccp 0xe2f44b01 dccp_feat_confirm_recv +EXPORT_SYMBOL_GPL net/dccp/dccp 0xe929b500 ccid_hc_rx_new +EXPORT_SYMBOL_GPL net/dccp/dccp 0xebba6e00 dccp_setsockopt +EXPORT_SYMBOL_GPL net/dccp/dccp 0xed3c4512 dccp_feat_change_recv +EXPORT_SYMBOL_GPL net/dccp/dccp 0xef1fd3ce dccp_ioctl +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0x198898c1 dccp_v4_request_recv_sock +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0x7a471796 dccp_v4_conn_request +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0x8a565026 dccp_v4_send_check +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0x90aeaa61 dccp_invalid_packet +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0xcfafd2c7 dccp_v4_do_rcv +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0xd30c1f1e dccp_v4_connect +EXPORT_SYMBOL_GPL net/ieee80211/ieee80211 0xdbc53111 ieee80211_rx_any +EXPORT_SYMBOL_GPL net/ipv4/ipvs/ip_vs 0xe6476b4a net_vs_ctl_path +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_conntrack_ipv4 0x6d40a921 need_ipv4_conntrack +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_conntrack_ipv4 0xcb101f94 nf_nat_seq_adjust_hook +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x04eb3423 nf_nat_proto_find_get +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x07ae60b6 nf_nat_proto_in_range +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x4270a7d8 nf_nat_proto_put +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x59c3072f nf_nat_proto_unique_tuple +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x94a08134 nf_nat_proto_nlattr_to_range +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x97d29e5d nf_nat_proto_range_to_nlattr +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0xd5ccae4f nf_nat_icmp_reply_translation +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0xee071445 nf_nat_packet +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat_proto_gre 0x636b12c8 nf_nat_need_gre +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0x284dd9b0 tcp_vegas_get_info +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0x2dcd591d tcp_vegas_pkts_acked +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0x5ce5aea2 tcp_vegas_init +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0x819d888d tcp_vegas_cwnd_event +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0xbf5a2d25 tcp_vegas_state +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x08a3e5d1 net_ipv6_ctl_path +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x0de56de6 inet6_csk_addr2sockaddr +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x20608df9 inet6_sk_rebuild_header +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x288d7c28 ip6_dst_blackhole +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x3b0f49b6 inet6_csk_xmit +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x5361a7f7 ip6_local_out +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x74c384c5 ipv6_find_tlv +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x9acd902d inet6_destroy_sock +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x9e52b7a0 ipv6_opt_accepted +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0xc75b0bfd ip6_dst_lookup +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0xdfdee829 ip6_sk_dst_lookup +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0xe38ae031 inet6_csk_reqsk_queue_hash_add +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0xf1a26a65 ipv6_dup_options +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0xf2bd1c45 fl6_sock_lookup +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0xfc3980bc inet6_csk_search_req +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0xfc3e0fbf inet6_csk_bind_conflict +EXPORT_SYMBOL_GPL net/mac80211/mac80211 0x3c68a258 ieee80211_iterate_active_interfaces +EXPORT_SYMBOL_GPL net/mac80211/mac80211 0xb40b4122 ieee80211_iterate_active_interfaces_atomic +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x041013fd nf_conntrack_lock +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x045072cd nf_ct_port_nla_policy +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x05f1fb7b nf_ct_expect_init +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x09d468d5 nf_conntrack_helper_unregister +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x0ea4f6dc nf_ct_iterate_cleanup +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x1283d711 nf_ct_expect_unregister_notifier +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x15c10b0b nf_conntrack_unregister_notifier +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x1ae6803f nf_ct_unlink_expect +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x248d7f93 nf_conntrack_alloc +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x25e649f2 nf_ct_log_invalid +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x2731ac8a __nf_ct_helper_find +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x2b9580cb nf_conntrack_flush +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x2bdd5581 nf_conntrack_helper_register +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x31fc7a87 nf_ct_get_tuplepr +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x3609de81 nf_conntrack_count +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x38630158 nf_conntrack_tuple_taken +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x38c9440b nf_ct_extend_register +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x3dea264b nf_ct_expect_find_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x3f5b1415 nf_ct_port_nlattr_to_tuple +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x40387ccf __nf_ct_event_cache_init +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x415446b6 __nf_ct_expect_find +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x4fda6dd5 nf_ct_port_tuple_to_nlattr +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x500b21d7 nf_ct_l3proto_put +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x50966e4d nf_ct_expect_alloc +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x52b7a328 nf_conntrack_l4proto_tcp6 +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x5888994a __nf_conntrack_confirm +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x5a6b2aa9 __nf_ct_l4proto_find +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6081c1aa nf_conntrack_l4proto_tcp4 +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6cd91ee0 per_cpu__nf_conntrack_ecache +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6dbe9313 nf_conntrack_in +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6e224a7a need_conntrack +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x72836f4a nf_conntrack_free +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x74b83b98 nf_ct_l4proto_put +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x77aadb54 nf_conntrack_alter_reply +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x78f9b710 nf_ct_l3proto_try_module_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x79ca2e53 nf_ct_expect_chain +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x7d91821e nf_ct_l3proto_find_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x806a75c6 nf_ct_l4proto_find_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x886a1333 seq_print_acct +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x8ffe7e89 nf_conntrack_htable_size +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x90ff6c9f nf_ct_invert_tuplepr +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x9bbfa160 nf_conntrack_l4proto_register +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xa1a3d198 __nf_conntrack_helper_find_byname +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xa6f62ec0 nf_conntrack_set_hashsize +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xaa883a0f __nf_ct_refresh_acct +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xacbd26b4 nf_ct_unexpect_related +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xace98352 nf_conntrack_hash +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xaf57e66f nf_ct_extend_unregister +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xb3053b9b nf_conntrack_l3proto_generic +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xb602c57e nf_ct_l3proto_module_put +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xb76accc2 __nf_conntrack_find +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xb9ac10ce nf_ct_expect_related +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xb9c4191b __nf_ct_kill_acct +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xb9e30797 nf_ct_acct +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xbc887e16 nf_ct_expect_register_notifier +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xbe3f2939 nf_conntrack_checksum +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc044befe nf_ct_free_hashtable +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc18ac88d nf_ct_expect_hsize +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc24b4318 nf_ct_get_tuple +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc35a7a3e nf_conntrack_chain +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc7b64d79 nf_conntrack_hash_insert +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xcbf7fd2a nf_conntrack_register_notifier +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xcd32cd92 nf_conntrack_l4proto_udp4 +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd0eec826 nf_ct_l3protos +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd50a96a2 nf_ct_alloc_hashtable +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd6a413ae nf_ct_expect_put +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd7c683c4 nf_conntrack_find_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd80c494a nf_ct_invert_tuple +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd9efb053 nf_ct_deliver_cached_events +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xe23ea2f4 print_tuple +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xeb8459a8 nf_conntrack_tcp_update +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xec8beba6 nf_ct_expect_hash +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xecaf7306 nf_conntrack_l3proto_unregister +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xf42c60c1 nf_conntrack_l3proto_register +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xf9ae81a1 nf_conntrack_max +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xfa169dac nf_conntrack_untracked +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xfb839673 nf_ct_remove_expectations +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xfda5e4d5 nf_ct_helper_ext_add +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xfe222ed4 nf_conntrack_l4proto_unregister +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xff04af10 nf_conntrack_l4proto_udp6 +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_amanda 0x927055f3 nf_nat_amanda_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_ftp 0x21014fa4 nf_nat_ftp_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x045e4e88 set_h245_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x264c0cf3 get_h225_addr +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x3744e358 nat_rtp_rtcp_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x71313e61 nat_q931_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x8bb4ef2c set_h225_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0xc063639e set_ras_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0xc3da0f59 nat_callforwarding_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0xc6518119 nat_h245_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0xd1cc7609 set_sig_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0xd1f8c110 nat_t120_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_irc 0xc4e8b606 nf_nat_irc_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_pptp 0x16b086b5 nf_nat_pptp_hook_outbound +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_pptp 0x67658cb4 nf_nat_pptp_hook_exp_gre +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_pptp 0x9c0c7dde nf_nat_pptp_hook_inbound +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_pptp 0xbbc0c90c nf_nat_pptp_hook_expectfn +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_proto_gre 0x05f8e58c nf_ct_gre_keymap_destroy +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_proto_gre 0x6f59d77c nf_ct_gre_keymap_add +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x13169b79 ct_sip_parse_request +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x2a2e7272 nf_nat_sip_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x3c2058a6 ct_sip_parse_numerical_param +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x5333cb69 ct_sip_parse_header_uri +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x5343611e ct_sip_get_sdp_header +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x56ad8f6e ct_sip_parse_address_param +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x78b61dff nf_nat_sdp_port_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x882cffea nf_nat_sdp_media_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x96a25fc6 nf_nat_sdp_session_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0xa1efca95 nf_nat_sip_expect_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0xe7831015 nf_nat_sdp_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0xf8b610ea ct_sip_get_header +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_tftp 0x19a7fb03 nf_nat_tftp_hook +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0x03732193 nfnetlink_send +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0x69abdc74 nfnetlink_subsys_register +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0x77d98efa nfnetlink_subsys_unregister +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0x7b206a6c nfnetlink_unicast +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0xeca95329 nfnetlink_has_listeners +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x033f07b1 xt_check_target +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x113787da xt_unregister_table +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x1c5fb8ae xt_register_table +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x33c09e06 xt_request_find_target +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x40b3b386 xt_proto_init +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x57d440dd xt_proto_fini +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x63f05053 xt_find_revision +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x82334f01 xt_table_unlock +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x86ce4e90 xt_find_table_lock +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0xeeea88ec xt_check_match +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0xfa1c465b xt_replace_table +EXPORT_SYMBOL_GPL net/netfilter/xt_RATEEST 0xc177bee0 xt_rateest_put +EXPORT_SYMBOL_GPL net/netfilter/xt_RATEEST 0xdb8418cc xt_rateest_lookup +EXPORT_SYMBOL_GPL net/rfkill/rfkill 0x83b2e956 register_rfkill_notifier +EXPORT_SYMBOL_GPL net/rfkill/rfkill 0x86c722f8 rfkill_epo +EXPORT_SYMBOL_GPL net/rfkill/rfkill 0xa6f4320d unregister_rfkill_notifier +EXPORT_SYMBOL_GPL net/rxrpc/af-rxrpc 0xba462d78 rxrpc_unregister_security +EXPORT_SYMBOL_GPL net/rxrpc/af-rxrpc 0xc37d8d51 rxrpc_register_security +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x06536814 svc_find_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x07ca67ca rpc_sleep_on +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x152c3cc0 xprt_set_retrans_timeout_rtt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x16073de4 rpcauth_init_cred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x1a6ad1e1 rpcb_getport_async +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x246e434c svc_xprt_received +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x25a21ab8 xprt_wake_pending_tasks +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x286bd690 svc_xprt_put +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x2aa17774 rpc_free_iostats +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x2c0c4d94 xprt_register_transport +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x2cb07555 rpc_malloc +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x2e4a521e rpc_proc_register +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x301cf841 svc_xprt_init +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x306770ed rpc_put_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x31a89d59 rpc_debug +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x35bfb0fc rpcauth_destroy_credcache +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x3602a9db xprt_reserve_xprt_cong +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x3db24b97 xprt_complete_rqst +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x405e7dc4 svc_xprt_enqueue +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x49c519d2 rpc_exit_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x4bac3636 svc_xprt_names +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x4c0395f8 rpcauth_init_credcache +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x4ede8a4b rpcauth_lookup_credcache +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x51c5ca71 xdr_skb_read_bits +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x5266e053 xprt_release_rqst_cong +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x53445f68 nlm_debug +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x540edf4f xprt_reserve_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x550547a3 rpc_destroy_wait_queue +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x59d4c09f xprt_wait_for_buffer_space +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x5bd26000 rpc_proc_unregister +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x5d8b0706 rpc_call_sync +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x5ecb19ca csum_partial_copy_to_xdr +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x65befebb __rpc_wait_for_completion_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x679088b2 rpc_lookup_cred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x69dd85d7 rpc_run_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x6c507380 rpc_peeraddr2str +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x6c5304c5 rpcb_getport_sync +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x6f984cb8 xprt_release_xprt_cong +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x70d9da4d rpc_call_async +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7b409ad8 rpc_restart_call +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7befa825 rpc_killall_tasks +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7cf5169a rpc_max_payload +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7d30cf77 svc_create_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7de53067 rpc_init_rtt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7eaad009 rpc_shutdown_client +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x86e959e3 rpcauth_unregister +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x891fb5b1 xprt_disconnect_done +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x8d01dd97 rpcauth_generic_bind_cred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x8f5566c7 rpc_bind_new_program +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x9347bfe4 rpc_alloc_iostats +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x9d4a1b46 xprt_write_space +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x9d5c46c6 rpc_wake_up_next +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xa0091857 svc_close_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xa5a01a15 svc_max_payload +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xa67e316f svc_addsock +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xac416954 xprt_lookup_rqst +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xae204626 put_rpccred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xaf5bf6ef nfs_debug +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xb387b246 rpc_wake_up_status +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xb6983596 rpc_create +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xb70695ed rpc_print_iostats +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xba99a57b rpcauth_create +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xbe92b84f svc_reg_xprt_class +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xbf9d1b96 nfsd_debug +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xc0fbac39 rpc_call_start +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xc12435e3 rpc_calc_rto +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xc3d25cf2 rpc_force_rebind +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xc676c71e rpc_clone_client +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xc6e9fb40 rpc_call_null +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xd22ebf3f rpc_wake_up_queued_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xd446aae2 xprt_release_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xd82c728e rpc_init_wait_queue +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xda1f5f8e rpc_lookup_machine_cred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xda99b7f1 rpcauth_register +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xdc4f952c rpc_delay +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xdcbe24c0 rpc_peeraddr +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xdd353e9c svc_unreg_xprt_class +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xddc9f690 xprt_adjust_cwnd +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xe260f503 svc_xprt_copy_addrs +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xe3a6d192 svc_print_addr +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xe48be112 rpc_setbufsize +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xedd1ba52 rpc_wake_up +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xeeacab69 rpc_update_rtt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xf8ad854c xprt_update_rtt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xf9d1164c rpc_free +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xfd54ec33 xdr_partial_copy_from_skb +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xffaafe25 xprt_unregister_transport +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xffe6b831 xprt_set_retrans_timeout_def +EXPORT_SYMBOL_GPL net/xfrm/xfrm_ipcomp 0x123677aa ipcomp_input +EXPORT_SYMBOL_GPL net/xfrm/xfrm_ipcomp 0x4d2cd61a ipcomp_destroy +EXPORT_SYMBOL_GPL net/xfrm/xfrm_ipcomp 0x6283846b ipcomp_output +EXPORT_SYMBOL_GPL net/xfrm/xfrm_ipcomp 0x749abae2 ipcomp_init_state +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x031fc78a snd_soc_cnew +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x1fc8dc4f snd_soc_dapm_sync +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x2901b48c snd_soc_new_ac97_codec +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x3ae1722a snd_soc_dai_set_tristate +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x3ce70c50 snd_soc_dai_set_sysclk +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x3fbe6282 snd_soc_get_volsw_2r +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x4c7f9f88 snd_soc_dapm_get_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x535c1aa6 snd_soc_info_volsw_s8 +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x57791d99 snd_soc_info_enum_ext +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x57a2c930 snd_soc_info_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x58a54210 snd_soc_dapm_get_pin_status +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x5e1f462b snd_soc_dapm_new_control +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x6166a561 snd_soc_dapm_put_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x668f980a snd_soc_get_volsw_s8 +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x6ae22919 snd_soc_put_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x6eaed5de snd_soc_dapm_free +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x784c9df1 snd_soc_dai_set_clkdiv +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x78722979 snd_soc_info_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x7b4c13f1 snd_soc_set_runtime_hwparams +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x7b7ccccf snd_soc_dapm_get_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x80db5667 snd_soc_dai_set_pll +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x80e78da0 snd_soc_put_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x817e05b1 snd_soc_put_volsw_s8 +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x8434b650 snd_soc_dai_digital_mute +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x895b381f snd_soc_free_ac97_codec +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x91b9ac87 snd_soc_dai_set_tdm_slot +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x9db3e442 snd_soc_dapm_enable_pin +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x9df11930 snd_soc_dai_set_fmt +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xa03e2027 dapm_reg_event +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xa134c691 snd_soc_dapm_disable_pin +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xa4262c8e snd_soc_dapm_stream_event +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xa7dc6f7c snd_soc_dapm_new_controls +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xa8a5ade4 snd_soc_test_bits +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xab67a7ea snd_soc_new_pcms +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xadbc0ed2 snd_soc_get_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xadfeb749 snd_soc_get_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xb4433b2a snd_soc_dapm_new_widgets +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xbc22eb04 snd_soc_dapm_put_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xc13246ca snd_soc_info_volsw_ext +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xc18c6eee snd_soc_dapm_connect_input +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xc70176ad snd_soc_update_bits +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xcc5faea6 snd_soc_register_card +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xd19b85da snd_soc_info_volsw_2r +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xd84fff39 snd_soc_put_volsw_2r +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xe4764bcb snd_soc_dapm_add_routes +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xfb294d30 snd_soc_free_pcms +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0x1584fdb9 tlsf_destroy_memory_pool +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0x42a50f11 tlsf_malloc +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0x66da3d8f tlsf_create_memory_pool +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0xe6acc368 tlsf_free +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0xee6c65c9 tlsf_get_used_size +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0xeec8caeb tlsf_get_total_size +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0xf9805f1b tlsf_calloc +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x02500586 thinkpad_ec_unlock +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x0dc7484e thinkpad_ec_try_read_row +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x2552d213 thinkpad_ec_lock +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x3dbfef12 thinkpad_ec_read_row +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x8dbbd831 thinkpad_ec_invalidate +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0xa3042743 thinkpad_ec_prefetch_row +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0xfb5aa917 thinkpad_ec_try_lock +EXPORT_SYMBOL_GPL vmlinux 0x0020355c crypto_enqueue_request +EXPORT_SYMBOL_GPL vmlinux 0x00566d8f inotify_get_cookie +EXPORT_SYMBOL_GPL vmlinux 0x006482d9 bus_get_device_klist +EXPORT_SYMBOL_GPL vmlinux 0x006d7cad srcu_batches_completed +EXPORT_SYMBOL_GPL vmlinux 0x01032b44 get_device +EXPORT_SYMBOL_GPL vmlinux 0x011a8b72 platform_bus +EXPORT_SYMBOL_GPL vmlinux 0x012f06c2 nf_unregister_afinfo +EXPORT_SYMBOL_GPL vmlinux 0x01848a8e local_apic_timer_c2_ok +EXPORT_SYMBOL_GPL vmlinux 0x01932ef4 vfs_setlease +EXPORT_SYMBOL_GPL vmlinux 0x01a4ea6d unregister_die_notifier +EXPORT_SYMBOL_GPL vmlinux 0x01b3b6dc relay_open +EXPORT_SYMBOL_GPL vmlinux 0x01c0889c __rt_mutex_init +EXPORT_SYMBOL_GPL vmlinux 0x01e1a8de kgdb_breakpoint +EXPORT_SYMBOL_GPL vmlinux 0x02278d4c hvc_instantiate +EXPORT_SYMBOL_GPL vmlinux 0x0245067b __mnt_is_readonly +EXPORT_SYMBOL_GPL vmlinux 0x0279ccb2 spi_add_device +EXPORT_SYMBOL_GPL vmlinux 0x029e22ac tcp_reno_min_cwnd +EXPORT_SYMBOL_GPL vmlinux 0x02ab1f28 sysdev_driver_unregister +EXPORT_SYMBOL_GPL vmlinux 0x02ccea56 lock_policy_rwsem_write +EXPORT_SYMBOL_GPL vmlinux 0x030b2f53 blk_end_bidi_request +EXPORT_SYMBOL_GPL vmlinux 0x0343bdf1 __i2c_board_list +EXPORT_SYMBOL_GPL vmlinux 0x03a6f99d platform_add_devices +EXPORT_SYMBOL_GPL vmlinux 0x04486e88 rcu_batches_completed +EXPORT_SYMBOL_GPL vmlinux 0x0451a9c0 blk_rq_cur_bytes +EXPORT_SYMBOL_GPL vmlinux 0x04566c7f init_srcu_struct +EXPORT_SYMBOL_GPL vmlinux 0x048b9c39 inotify_init +EXPORT_SYMBOL_GPL vmlinux 0x04b362c3 crypto_hash_walk_first +EXPORT_SYMBOL_GPL vmlinux 0x054e550b kernel_halt +EXPORT_SYMBOL_GPL vmlinux 0x05e835d3 klist_node_attached +EXPORT_SYMBOL_GPL vmlinux 0x064db9a5 mark_mounts_for_expiry +EXPORT_SYMBOL_GPL vmlinux 0x06721c65 k_handler +EXPORT_SYMBOL_GPL vmlinux 0x06cd958e rtc_irq_unregister +EXPORT_SYMBOL_GPL vmlinux 0x06d222f8 device_resume +EXPORT_SYMBOL_GPL vmlinux 0x070704ba pid_vnr +EXPORT_SYMBOL_GPL vmlinux 0x0764906c devres_remove_group +EXPORT_SYMBOL_GPL vmlinux 0x07b52e38 rtnl_unregister +EXPORT_SYMBOL_GPL vmlinux 0x08969112 pci_find_ht_capability +EXPORT_SYMBOL_GPL vmlinux 0x08b0785a audit_log_untrustedstring +EXPORT_SYMBOL_GPL vmlinux 0x08e7a6cb device_move +EXPORT_SYMBOL_GPL vmlinux 0x08ebd45f device_initialize +EXPORT_SYMBOL_GPL vmlinux 0x091eb9b4 round_jiffies +EXPORT_SYMBOL_GPL vmlinux 0x0920c71f tty_wakeup +EXPORT_SYMBOL_GPL vmlinux 0x09b0773c inet_csk_listen_start +EXPORT_SYMBOL_GPL vmlinux 0x0acf090d driver_create_file +EXPORT_SYMBOL_GPL vmlinux 0x0b9e724f class_interface_unregister +EXPORT_SYMBOL_GPL vmlinux 0x0bbab27f sched_setscheduler +EXPORT_SYMBOL_GPL vmlinux 0x0bc151e5 klist_init +EXPORT_SYMBOL_GPL vmlinux 0x0c17e274 xfrm_aalg_get_byid +EXPORT_SYMBOL_GPL vmlinux 0x0c408ae9 attribute_container_register +EXPORT_SYMBOL_GPL vmlinux 0x0c4717f7 srcu_init_notifier_head +EXPORT_SYMBOL_GPL vmlinux 0x0c9ab147 get_current_tty +EXPORT_SYMBOL_GPL vmlinux 0x0d0d7c07 vfs_setxattr +EXPORT_SYMBOL_GPL vmlinux 0x0d12f14b blk_queue_dma_drain +EXPORT_SYMBOL_GPL vmlinux 0x0d18d070 device_create_bin_file +EXPORT_SYMBOL_GPL vmlinux 0x0d366ca8 input_class +EXPORT_SYMBOL_GPL vmlinux 0x0d797cb6 disk_round_stats +EXPORT_SYMBOL_GPL vmlinux 0x0e02acfd __sock_recv_timestamp +EXPORT_SYMBOL_GPL vmlinux 0x0ea6b449 platform_device_put +EXPORT_SYMBOL_GPL vmlinux 0x0ef84c65 hrtimer_start +EXPORT_SYMBOL_GPL vmlinux 0x0f0d238a key_type_user +EXPORT_SYMBOL_GPL vmlinux 0x0f4e5891 crypto_unregister_template +EXPORT_SYMBOL_GPL vmlinux 0x0f5953cc sysdev_class_unregister +EXPORT_SYMBOL_GPL vmlinux 0x10018797 sysdev_show_int +EXPORT_SYMBOL_GPL vmlinux 0x1050bc52 hrtimer_init +EXPORT_SYMBOL_GPL vmlinux 0x10b17493 led_trigger_set +EXPORT_SYMBOL_GPL vmlinux 0x1101fb18 __rtnl_link_unregister +EXPORT_SYMBOL_GPL vmlinux 0x11382702 user_match +EXPORT_SYMBOL_GPL vmlinux 0x1150c7d4 generic_drop_inode +EXPORT_SYMBOL_GPL vmlinux 0x11787557 vfs_test_lock +EXPORT_SYMBOL_GPL vmlinux 0x117c86e3 debugfs_create_u8 +EXPORT_SYMBOL_GPL vmlinux 0x124f2056 crypto_get_attr_type +EXPORT_SYMBOL_GPL vmlinux 0x1251d30f call_rcu +EXPORT_SYMBOL_GPL vmlinux 0x125a43e4 macvlan_handle_frame_hook +EXPORT_SYMBOL_GPL vmlinux 0x12aa4e9a unregister_kretprobes +EXPORT_SYMBOL_GPL vmlinux 0x13354608 scatterwalk_map_and_copy +EXPORT_SYMBOL_GPL vmlinux 0x138d82aa pci_create_slot +EXPORT_SYMBOL_GPL vmlinux 0x13b2a946 register_keyboard_notifier +EXPORT_SYMBOL_GPL vmlinux 0x145eebd0 device_power_up +EXPORT_SYMBOL_GPL vmlinux 0x149db923 selinux_string_to_sid +EXPORT_SYMBOL_GPL vmlinux 0x154acf37 inverse_translate +EXPORT_SYMBOL_GPL vmlinux 0x1598dc9d unregister_netevent_notifier +EXPORT_SYMBOL_GPL vmlinux 0x15addb28 skb_to_sgvec +EXPORT_SYMBOL_GPL vmlinux 0x15b0606e e820_any_mapped +EXPORT_SYMBOL_GPL vmlinux 0x16f76869 probe_kernel_read +EXPORT_SYMBOL_GPL vmlinux 0x171546f8 skb_partial_csum_set +EXPORT_SYMBOL_GPL vmlinux 0x172e72d4 vdso_enabled +EXPORT_SYMBOL_GPL vmlinux 0x1769f2c6 user_instantiate +EXPORT_SYMBOL_GPL vmlinux 0x1782bc99 rtc_class_open +EXPORT_SYMBOL_GPL vmlinux 0x17b24ea1 __blk_add_trace +EXPORT_SYMBOL_GPL vmlinux 0x17c1bd2b driver_register +EXPORT_SYMBOL_GPL vmlinux 0x17d2ddce vfs_kern_mount +EXPORT_SYMBOL_GPL vmlinux 0x18213aaf exit_fs +EXPORT_SYMBOL_GPL vmlinux 0x1878f62b edac_err_assert +EXPORT_SYMBOL_GPL vmlinux 0x18a7c4b1 unregister_pernet_subsys +EXPORT_SYMBOL_GPL vmlinux 0x18acddd4 register_net_sysctl_table +EXPORT_SYMBOL_GPL vmlinux 0x18d53420 kgdb_register_io_module +EXPORT_SYMBOL_GPL vmlinux 0x19ecd3cb blkdev_ioctl +EXPORT_SYMBOL_GPL vmlinux 0x1a43c332 unregister_jprobe +EXPORT_SYMBOL_GPL vmlinux 0x1a938737 atomic_notifier_chain_register +EXPORT_SYMBOL_GPL vmlinux 0x1ac576cb crypto_hash_type +EXPORT_SYMBOL_GPL vmlinux 0x1acda5b2 atomic_notifier_chain_unregister +EXPORT_SYMBOL_GPL vmlinux 0x1b60d688 sysfs_create_group +EXPORT_SYMBOL_GPL vmlinux 0x1b62c43d debugfs_create_x8 +EXPORT_SYMBOL_GPL vmlinux 0x1b9aca3f jprobe_return +EXPORT_SYMBOL_GPL vmlinux 0x1bf912fb tcp_twsk_unique +EXPORT_SYMBOL_GPL vmlinux 0x1c0c5782 __inet_twsk_hashdance +EXPORT_SYMBOL_GPL vmlinux 0x1c8b4809 free_vm_area +EXPORT_SYMBOL_GPL vmlinux 0x1cc8a668 sysfs_remove_link +EXPORT_SYMBOL_GPL vmlinux 0x1dbb53ac pci_destroy_slot +EXPORT_SYMBOL_GPL vmlinux 0x1dbfb3f2 map_vm_area +EXPORT_SYMBOL_GPL vmlinux 0x1dd70100 dmi_walk +EXPORT_SYMBOL_GPL vmlinux 0x1e7bbcb3 kernel_restart +EXPORT_SYMBOL_GPL vmlinux 0x1eb9516e round_jiffies_relative +EXPORT_SYMBOL_GPL vmlinux 0x1f8ec1b3 acpi_get_pci_rootbridge_handle +EXPORT_SYMBOL_GPL vmlinux 0x1f9a0fbf hpet_unregister_irq_handler +EXPORT_SYMBOL_GPL vmlinux 0x1fb7a50b xfrm_audit_state_delete +EXPORT_SYMBOL_GPL vmlinux 0x1fcece42 inet_twdr_twcal_tick +EXPORT_SYMBOL_GPL vmlinux 0x20577ea2 xfrm_ealg_get_byidx +EXPORT_SYMBOL_GPL vmlinux 0x20b82470 hpet_register_irq_handler +EXPORT_SYMBOL_GPL vmlinux 0x20bc3470 orderly_poweroff +EXPORT_SYMBOL_GPL vmlinux 0x20e4484f class_create_file +EXPORT_SYMBOL_GPL vmlinux 0x216d7c39 __blk_end_request +EXPORT_SYMBOL_GPL vmlinux 0x218e2a38 save_stack_trace_tsk +EXPORT_SYMBOL_GPL vmlinux 0x21bb9b8e rtc_set_time +EXPORT_SYMBOL_GPL vmlinux 0x21db6481 sysfs_remove_bin_file +EXPORT_SYMBOL_GPL vmlinux 0x2238da42 cpufreq_cpu_get +EXPORT_SYMBOL_GPL vmlinux 0x22472bf4 xfrm_calg_get_byid +EXPORT_SYMBOL_GPL vmlinux 0x22644069 rtnl_link_unregister +EXPORT_SYMBOL_GPL vmlinux 0x2296c00d crypto_attr_u32 +EXPORT_SYMBOL_GPL vmlinux 0x22d98f2c power_supply_unregister +EXPORT_SYMBOL_GPL vmlinux 0x23679939 __iowrite32_copy +EXPORT_SYMBOL_GPL vmlinux 0x23864ce7 cpuset_mem_spread_node +EXPORT_SYMBOL_GPL vmlinux 0x23a3ce82 input_ff_upload +EXPORT_SYMBOL_GPL vmlinux 0x23fe76d0 blk_rq_bytes +EXPORT_SYMBOL_GPL vmlinux 0x24196ba2 init_uts_ns +EXPORT_SYMBOL_GPL vmlinux 0x2447533c ktime_get_real +EXPORT_SYMBOL_GPL vmlinux 0x24855636 inotify_destroy +EXPORT_SYMBOL_GPL vmlinux 0x24eb7e32 leds_list +EXPORT_SYMBOL_GPL vmlinux 0x250872b0 __inet_inherit_port +EXPORT_SYMBOL_GPL vmlinux 0x25dc7f43 device_remove_bin_file +EXPORT_SYMBOL_GPL vmlinux 0x25e6a7c5 device_destroy +EXPORT_SYMBOL_GPL vmlinux 0x2692187d bdi_writeout_inc +EXPORT_SYMBOL_GPL vmlinux 0x26b2d364 sysdev_class_create_file +EXPORT_SYMBOL_GPL vmlinux 0x2712cce3 transport_setup_device +EXPORT_SYMBOL_GPL vmlinux 0x2714c98c klist_del +EXPORT_SYMBOL_GPL vmlinux 0x272e1a1d relay_reset +EXPORT_SYMBOL_GPL vmlinux 0x277ecf60 __cpufreq_driver_target +EXPORT_SYMBOL_GPL vmlinux 0x279002da proc_net_fops_create +EXPORT_SYMBOL_GPL vmlinux 0x28088f0f pv_time_ops +EXPORT_SYMBOL_GPL vmlinux 0x28961016 init_user_ns +EXPORT_SYMBOL_GPL vmlinux 0x2897359a rtc_class_close +EXPORT_SYMBOL_GPL vmlinux 0x28d664ff __raw_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x28e23139 xfrm_probe_algs +EXPORT_SYMBOL_GPL vmlinux 0x293cf0fc inet_csk_bind_conflict +EXPORT_SYMBOL_GPL vmlinux 0x295394e2 raw_seq_next +EXPORT_SYMBOL_GPL vmlinux 0x29ad2ee1 relay_close +EXPORT_SYMBOL_GPL vmlinux 0x29c029bc fsstack_copy_attr_all +EXPORT_SYMBOL_GPL vmlinux 0x2a09a53e rtc_device_unregister +EXPORT_SYMBOL_GPL vmlinux 0x2a678a13 __suspend_report_result +EXPORT_SYMBOL_GPL vmlinux 0x2a680d4a spi_new_device +EXPORT_SYMBOL_GPL vmlinux 0x2b9f8e23 nf_net_ipv4_netfilter_sysctl_path +EXPORT_SYMBOL_GPL vmlinux 0x2bfdeb4e sysdev_remove_file +EXPORT_SYMBOL_GPL vmlinux 0x2c16ed76 xfrm_calg_get_byname +EXPORT_SYMBOL_GPL vmlinux 0x2c33f64a input_ff_erase +EXPORT_SYMBOL_GPL vmlinux 0x2c73134d debugfs_create_x32 +EXPORT_SYMBOL_GPL vmlinux 0x2c7900c5 input_ff_create +EXPORT_SYMBOL_GPL vmlinux 0x2d364ea5 rtc_device_register +EXPORT_SYMBOL_GPL vmlinux 0x2d45bcda crypto_alg_sem +EXPORT_SYMBOL_GPL vmlinux 0x2d59c954 edac_handlers +EXPORT_SYMBOL_GPL vmlinux 0x2d5a88ee rtc_irq_set_freq +EXPORT_SYMBOL_GPL vmlinux 0x2d77eae8 generic_fh_to_dentry +EXPORT_SYMBOL_GPL vmlinux 0x2d9f2ce3 sched_clock_idle_wakeup_event +EXPORT_SYMBOL_GPL vmlinux 0x2ddb03e9 debugfs_rename +EXPORT_SYMBOL_GPL vmlinux 0x2e081ab0 kern_mount_data +EXPORT_SYMBOL_GPL vmlinux 0x2e6e7aee smp_ops +EXPORT_SYMBOL_GPL vmlinux 0x2eb91dfe scatterwalk_map +EXPORT_SYMBOL_GPL vmlinux 0x2ed92ddb spi_sync +EXPORT_SYMBOL_GPL vmlinux 0x2f870319 __class_register +EXPORT_SYMBOL_GPL vmlinux 0x2fbb897b simple_attr_read +EXPORT_SYMBOL_GPL vmlinux 0x30171a2e cpufreq_register_governor +EXPORT_SYMBOL_GPL vmlinux 0x303974d2 invalidate_inode_pages2 +EXPORT_SYMBOL_GPL vmlinux 0x30d35846 cpuidle_enable_device +EXPORT_SYMBOL_GPL vmlinux 0x3167f035 class_unregister +EXPORT_SYMBOL_GPL vmlinux 0x316d9888 device_create_vargs +EXPORT_SYMBOL_GPL vmlinux 0x32b0eb3e led_trigger_set_default +EXPORT_SYMBOL_GPL vmlinux 0x33b6e752 acpi_ec_remove_query_handler +EXPORT_SYMBOL_GPL vmlinux 0x34164a4f inotify_find_watch +EXPORT_SYMBOL_GPL vmlinux 0x3427c46a fnotify_change +EXPORT_SYMBOL_GPL vmlinux 0x3441c3d6 gpio_set_value_cansleep +EXPORT_SYMBOL_GPL vmlinux 0x34cc69ca do_add_mount +EXPORT_SYMBOL_GPL vmlinux 0x351a6622 crypto_register_instance +EXPORT_SYMBOL_GPL vmlinux 0x35ff7536 tty_perform_flush +EXPORT_SYMBOL_GPL vmlinux 0x3609b38b kset_create_and_add +EXPORT_SYMBOL_GPL vmlinux 0x361e2bcc save_stack_trace +EXPORT_SYMBOL_GPL vmlinux 0x362e23ec call_rcu_bh +EXPORT_SYMBOL_GPL vmlinux 0x363a73ee device_create_file +EXPORT_SYMBOL_GPL vmlinux 0x367f00e2 sysdev_create_file +EXPORT_SYMBOL_GPL vmlinux 0x379880a8 device_reprobe +EXPORT_SYMBOL_GPL vmlinux 0x37d17fb7 anon_transport_class_register +EXPORT_SYMBOL_GPL vmlinux 0x37dcd893 relay_file_operations +EXPORT_SYMBOL_GPL vmlinux 0x38443b8e copy_fs_struct +EXPORT_SYMBOL_GPL vmlinux 0x3895233b srcu_notifier_chain_unregister +EXPORT_SYMBOL_GPL vmlinux 0x38b64c27 blk_set_cmd_filter_defaults +EXPORT_SYMBOL_GPL vmlinux 0x39676259 platform_get_resource_byname +EXPORT_SYMBOL_GPL vmlinux 0x3970b9a3 debugfs_remove +EXPORT_SYMBOL_GPL vmlinux 0x39907ced sock_prot_inuse_get +EXPORT_SYMBOL_GPL vmlinux 0x3997afb4 attribute_container_find_class_device +EXPORT_SYMBOL_GPL vmlinux 0x39d154f4 led_trigger_register +EXPORT_SYMBOL_GPL vmlinux 0x3a33c6f2 alloc_vm_area +EXPORT_SYMBOL_GPL vmlinux 0x3a7f8b86 __local_bh_enable +EXPORT_SYMBOL_GPL vmlinux 0x3a9a440d gpiochip_add +EXPORT_SYMBOL_GPL vmlinux 0x3a9ce59f xattr_getsecurity +EXPORT_SYMBOL_GPL vmlinux 0x3ac3d8d2 unregister_pernet_gen_device +EXPORT_SYMBOL_GPL vmlinux 0x3ad819ae crypto_register_template +EXPORT_SYMBOL_GPL vmlinux 0x3be7af02 get_max_files +EXPORT_SYMBOL_GPL vmlinux 0x3bfd99b3 uhci_check_and_reset_hc +EXPORT_SYMBOL_GPL vmlinux 0x3c23e37f spi_register_driver +EXPORT_SYMBOL_GPL vmlinux 0x3c3a2d2d tcp_reno_cong_avoid +EXPORT_SYMBOL_GPL vmlinux 0x3c63c935 dma_get_required_mask +EXPORT_SYMBOL_GPL vmlinux 0x3c942368 profile_event_unregister +EXPORT_SYMBOL_GPL vmlinux 0x3c9432cb sysdev_unregister +EXPORT_SYMBOL_GPL vmlinux 0x3cd06035 add_input_randomness +EXPORT_SYMBOL_GPL vmlinux 0x3cfedb3f register_pm_notifier +EXPORT_SYMBOL_GPL vmlinux 0x3d711cb9 sysdev_driver_register +EXPORT_SYMBOL_GPL vmlinux 0x3dbf6dd9 bus_find_device +EXPORT_SYMBOL_GPL vmlinux 0x3e2dbe3e tty_mode_ioctl +EXPORT_SYMBOL_GPL vmlinux 0x3ea9f1de __class_create +EXPORT_SYMBOL_GPL vmlinux 0x3ebbb18a pciserial_suspend_ports +EXPORT_SYMBOL_GPL vmlinux 0x3ecfc58a tty_ldisc_ref_wait +EXPORT_SYMBOL_GPL vmlinux 0x3efb35c9 get_online_cpus +EXPORT_SYMBOL_GPL vmlinux 0x3f01570a probe_kernel_write +EXPORT_SYMBOL_GPL vmlinux 0x3f0734e2 spi_write_then_read +EXPORT_SYMBOL_GPL vmlinux 0x3f238101 dcookie_register +EXPORT_SYMBOL_GPL vmlinux 0x3f5046f3 get_user_pages_fast +EXPORT_SYMBOL_GPL vmlinux 0x3f600e7e __inet_lookup_established +EXPORT_SYMBOL_GPL vmlinux 0x3f9e537a tty_get_pgrp +EXPORT_SYMBOL_GPL vmlinux 0x404feb30 devres_alloc +EXPORT_SYMBOL_GPL vmlinux 0x41aad989 led_trigger_store +EXPORT_SYMBOL_GPL vmlinux 0x41f3cc90 xfrm_aalg_get_byname +EXPORT_SYMBOL_GPL vmlinux 0x425291b8 isa_unregister_driver +EXPORT_SYMBOL_GPL vmlinux 0x425508d3 stop_machine +EXPORT_SYMBOL_GPL vmlinux 0x42b364ef scatterwalk_done +EXPORT_SYMBOL_GPL vmlinux 0x432fd7f6 __gpio_set_value +EXPORT_SYMBOL_GPL vmlinux 0x4471a21f inotify_dentry_parent_queue_event +EXPORT_SYMBOL_GPL vmlinux 0x44a65d5c lock_policy_rwsem_read +EXPORT_SYMBOL_GPL vmlinux 0x44ab0c7a gpiochip_remove +EXPORT_SYMBOL_GPL vmlinux 0x452c04a4 transport_destroy_device +EXPORT_SYMBOL_GPL vmlinux 0x453ccdb3 sysdev_store_int +EXPORT_SYMBOL_GPL vmlinux 0x455bc07c cpuidle_unregister_device +EXPORT_SYMBOL_GPL vmlinux 0x457594fa crypto_alg_list +EXPORT_SYMBOL_GPL vmlinux 0x45793f6a crypto_free_tfm +EXPORT_SYMBOL_GPL vmlinux 0x45bf1ff3 crypto_inc +EXPORT_SYMBOL_GPL vmlinux 0x460f31aa rodata_test_data +EXPORT_SYMBOL_GPL vmlinux 0x46132fb1 xfrm_audit_state_add +EXPORT_SYMBOL_GPL vmlinux 0x4617c4f9 sysfs_chmod_file +EXPORT_SYMBOL_GPL vmlinux 0x464b5e67 seq_open_net +EXPORT_SYMBOL_GPL vmlinux 0x4665356e sysctl_pathname +EXPORT_SYMBOL_GPL vmlinux 0x467972cd pci_block_user_cfg_access +EXPORT_SYMBOL_GPL vmlinux 0x469b8187 rt_mutex_destroy +EXPORT_SYMBOL_GPL vmlinux 0x46df52eb bus_create_file +EXPORT_SYMBOL_GPL vmlinux 0x46edc2c3 pci_disable_pcie_error_reporting +EXPORT_SYMBOL_GPL vmlinux 0x47229b5c gpio_request +EXPORT_SYMBOL_GPL vmlinux 0x47524907 register_kretprobes +EXPORT_SYMBOL_GPL vmlinux 0x479a56eb do_sync_mapping_range +EXPORT_SYMBOL_GPL vmlinux 0x47b1575b cpufreq_cpu_put +EXPORT_SYMBOL_GPL vmlinux 0x4896213a elv_register +EXPORT_SYMBOL_GPL vmlinux 0x499043d3 crypto_init_queue +EXPORT_SYMBOL_GPL vmlinux 0x4a7e30d9 marker_probe_unregister_private_data +EXPORT_SYMBOL_GPL vmlinux 0x4ace6f42 platform_bus_type +EXPORT_SYMBOL_GPL vmlinux 0x4bbb890f relay_subbufs_consumed +EXPORT_SYMBOL_GPL vmlinux 0x4c759827 byte_rev_table +EXPORT_SYMBOL_GPL vmlinux 0x4cbb6a52 sysfs_remove_file +EXPORT_SYMBOL_GPL vmlinux 0x4dfb1df2 ip_route_output_flow +EXPORT_SYMBOL_GPL vmlinux 0x4fbe446a console_drivers +EXPORT_SYMBOL_GPL vmlinux 0x4fe470da crypto_mod_put +EXPORT_SYMBOL_GPL vmlinux 0x50634025 net_assign_generic +EXPORT_SYMBOL_GPL vmlinux 0x50b67174 xfrm_ealg_get_byid +EXPORT_SYMBOL_GPL vmlinux 0x50b6d981 inet_diag_register +EXPORT_SYMBOL_GPL vmlinux 0x50e7193a __i2c_first_dynamic_bus_num +EXPORT_SYMBOL_GPL vmlinux 0x50f723dd tcp_twsk_destructor +EXPORT_SYMBOL_GPL vmlinux 0x5108b3fc acpi_os_map_memory +EXPORT_SYMBOL_GPL vmlinux 0x518c2fc6 hpet_rtc_dropped_irq +EXPORT_SYMBOL_GPL vmlinux 0x519cf20d xfrm_inner_extract_output +EXPORT_SYMBOL_GPL vmlinux 0x51dd6488 xfrm_aalg_get_byidx +EXPORT_SYMBOL_GPL vmlinux 0x524c1b7d fib_rules_register +EXPORT_SYMBOL_GPL vmlinux 0x528d863a blk_end_request +EXPORT_SYMBOL_GPL vmlinux 0x52d111ea pm_qos_update_requirement +EXPORT_SYMBOL_GPL vmlinux 0x533167f8 inet_csk_reqsk_queue_hash_add +EXPORT_SYMBOL_GPL vmlinux 0x534b53ef inet_csk_route_req +EXPORT_SYMBOL_GPL vmlinux 0x5373b9a7 inet_twsk_alloc +EXPORT_SYMBOL_GPL vmlinux 0x53986488 register_die_notifier +EXPORT_SYMBOL_GPL vmlinux 0x53a1082f inet6_hash_connect +EXPORT_SYMBOL_GPL vmlinux 0x540375c6 xfrm_audit_policy_delete +EXPORT_SYMBOL_GPL vmlinux 0x56398615 mark_tsc_unstable +EXPORT_SYMBOL_GPL vmlinux 0x5641485b tty_termios_encode_baud_rate +EXPORT_SYMBOL_GPL vmlinux 0x57651584 sock_prot_inuse_add +EXPORT_SYMBOL_GPL vmlinux 0x579e0bf5 rtnl_unregister_all +EXPORT_SYMBOL_GPL vmlinux 0x585c3d0c devres_close_group +EXPORT_SYMBOL_GPL vmlinux 0x587516a5 class_remove_file +EXPORT_SYMBOL_GPL vmlinux 0x5897563e pciserial_remove_ports +EXPORT_SYMBOL_GPL vmlinux 0x58aaed1f pci_enable_pcie_error_reporting +EXPORT_SYMBOL_GPL vmlinux 0x58e1673f __pneigh_lookup +EXPORT_SYMBOL_GPL vmlinux 0x594168b9 unregister_kretprobe +EXPORT_SYMBOL_GPL vmlinux 0x594ce7d5 bus_unregister +EXPORT_SYMBOL_GPL vmlinux 0x597f3bc3 marker_get_private_data +EXPORT_SYMBOL_GPL vmlinux 0x59b951a6 rtnl_put_cacheinfo +EXPORT_SYMBOL_GPL vmlinux 0x59beb150 __trace_note_message +EXPORT_SYMBOL_GPL vmlinux 0x59dfc631 crypto_mod_get +EXPORT_SYMBOL_GPL vmlinux 0x59f67fd0 cpuidle_disable_device +EXPORT_SYMBOL_GPL vmlinux 0x5ac8c6b7 unregister_kprobes +EXPORT_SYMBOL_GPL vmlinux 0x5b16bb0d crypto_hash_walk_done +EXPORT_SYMBOL_GPL vmlinux 0x5b392b04 hrtimer_try_to_cancel +EXPORT_SYMBOL_GPL vmlinux 0x5b5114f9 driver_remove_file +EXPORT_SYMBOL_GPL vmlinux 0x5b81bfdb inet_csk_listen_stop +EXPORT_SYMBOL_GPL vmlinux 0x5bb44a32 klist_add_head +EXPORT_SYMBOL_GPL vmlinux 0x5bfc03c3 unregister_keyboard_notifier +EXPORT_SYMBOL_GPL vmlinux 0x5ca4f946 platform_get_irq_byname +EXPORT_SYMBOL_GPL vmlinux 0x5cfcf0f1 percpu_free +EXPORT_SYMBOL_GPL vmlinux 0x5d0f6f57 kbd_table +EXPORT_SYMBOL_GPL vmlinux 0x5d51bcf7 scatterwalk_start +EXPORT_SYMBOL_GPL vmlinux 0x5d730e7b raw_notifier_chain_unregister +EXPORT_SYMBOL_GPL vmlinux 0x5dd67618 register_netevent_notifier +EXPORT_SYMBOL_GPL vmlinux 0x5dff3243 apply_to_page_range +EXPORT_SYMBOL_GPL vmlinux 0x5e047c90 hwmon_device_unregister +EXPORT_SYMBOL_GPL vmlinux 0x5e689ef4 sysdev_store_ulong +EXPORT_SYMBOL_GPL vmlinux 0x5f2da8c4 check_tsc_unstable +EXPORT_SYMBOL_GPL vmlinux 0x5f316348 device_register +EXPORT_SYMBOL_GPL vmlinux 0x5f408bac klist_next +EXPORT_SYMBOL_GPL vmlinux 0x5fea940b hrtimer_forward +EXPORT_SYMBOL_GPL vmlinux 0x6091797f synchronize_rcu +EXPORT_SYMBOL_GPL vmlinux 0x60a13e90 rcu_barrier +EXPORT_SYMBOL_GPL vmlinux 0x60c6355a devm_kfree +EXPORT_SYMBOL_GPL vmlinux 0x60c6ca1f rtc_irq_set_state +EXPORT_SYMBOL_GPL vmlinux 0x60e9ccff platform_device_register_simple +EXPORT_SYMBOL_GPL vmlinux 0x619ce986 mnt_want_write +EXPORT_SYMBOL_GPL vmlinux 0x622c4f29 pci_unblock_user_cfg_access +EXPORT_SYMBOL_GPL vmlinux 0x62321339 rtc_set_mmss +EXPORT_SYMBOL_GPL vmlinux 0x6233ecc6 security_inode_setattr +EXPORT_SYMBOL_GPL vmlinux 0x62984697 inet_hash_connect +EXPORT_SYMBOL_GPL vmlinux 0x62ec808a debugfs_create_x16 +EXPORT_SYMBOL_GPL vmlinux 0x633f14ca transport_configure_device +EXPORT_SYMBOL_GPL vmlinux 0x63ae27d6 add_nops +EXPORT_SYMBOL_GPL vmlinux 0x63c5b0e2 inotify_find_update_watch +EXPORT_SYMBOL_GPL vmlinux 0x63fb2ac8 put_pid +EXPORT_SYMBOL_GPL vmlinux 0x644cf8d9 spi_unregister_master +EXPORT_SYMBOL_GPL vmlinux 0x64773527 posix_timer_event +EXPORT_SYMBOL_GPL vmlinux 0x64a52b7f devres_remove +EXPORT_SYMBOL_GPL vmlinux 0x64ec15b3 cpuidle_register_device +EXPORT_SYMBOL_GPL vmlinux 0x64f9112a queue_delayed_work_on +EXPORT_SYMBOL_GPL vmlinux 0x64fd27e0 devres_find +EXPORT_SYMBOL_GPL vmlinux 0x650c6356 find_pid_ns +EXPORT_SYMBOL_GPL vmlinux 0x65ccb6f0 call_netevent_notifiers +EXPORT_SYMBOL_GPL vmlinux 0x65d6d0f0 gpio_direction_input +EXPORT_SYMBOL_GPL vmlinux 0x65d8c6b3 set_cpus_allowed_ptr +EXPORT_SYMBOL_GPL vmlinux 0x6610ad99 synchronize_srcu +EXPORT_SYMBOL_GPL vmlinux 0x661601de sprint_symbol +EXPORT_SYMBOL_GPL vmlinux 0x667b1b0d inet_ctl_sock_create +EXPORT_SYMBOL_GPL vmlinux 0x66b2a859 nr_free_buffer_pages +EXPORT_SYMBOL_GPL vmlinux 0x66c223ef simple_attr_write +EXPORT_SYMBOL_GPL vmlinux 0x66d87d38 symbol_put_addr +EXPORT_SYMBOL_GPL vmlinux 0x67423cca flush_workqueue +EXPORT_SYMBOL_GPL vmlinux 0x67955ce6 profile_hits +EXPORT_SYMBOL_GPL vmlinux 0x67b2db11 sysdev_class_remove_file +EXPORT_SYMBOL_GPL vmlinux 0x67e0f70b skb_morph +EXPORT_SYMBOL_GPL vmlinux 0x67fc7e64 devres_release_group +EXPORT_SYMBOL_GPL vmlinux 0x681ba094 inet_twsk_schedule +EXPORT_SYMBOL_GPL vmlinux 0x6834cc83 klist_add_after +EXPORT_SYMBOL_GPL vmlinux 0x683e0bf4 pci_slots_kset +EXPORT_SYMBOL_GPL vmlinux 0x6852fc63 xfrm_audit_state_notfound_simple +EXPORT_SYMBOL_GPL vmlinux 0x686c703f xfrm_count_auth_supported +EXPORT_SYMBOL_GPL vmlinux 0x6892088c unregister_pm_notifier +EXPORT_SYMBOL_GPL vmlinux 0x68b3f394 crypto_alloc_instance +EXPORT_SYMBOL_GPL vmlinux 0x68db9c59 unregister_net_sysctl_table +EXPORT_SYMBOL_GPL vmlinux 0x68ddc4b8 pci_restore_msi_state +EXPORT_SYMBOL_GPL vmlinux 0x69064c59 bus_get_kset +EXPORT_SYMBOL_GPL vmlinux 0x691884ef pv_apic_ops +EXPORT_SYMBOL_GPL vmlinux 0x6931b84f fb_deferred_io_fsync +EXPORT_SYMBOL_GPL vmlinux 0x696aa636 kernel_kobj +EXPORT_SYMBOL_GPL vmlinux 0x69af0016 single_open_net +EXPORT_SYMBOL_GPL vmlinux 0x6a347cb1 __crypto_alg_lookup +EXPORT_SYMBOL_GPL vmlinux 0x6a73a650 attribute_container_classdev_to_container +EXPORT_SYMBOL_GPL vmlinux 0x6a8ea489 inet6_lookup_listener +EXPORT_SYMBOL_GPL vmlinux 0x6a99047f isa_register_driver +EXPORT_SYMBOL_GPL vmlinux 0x6abde631 vfs_listxattr +EXPORT_SYMBOL_GPL vmlinux 0x6b07a368 klist_add_before +EXPORT_SYMBOL_GPL vmlinux 0x6b671740 vfs_lock_file +EXPORT_SYMBOL_GPL vmlinux 0x6b6f9367 input_ff_event +EXPORT_SYMBOL_GPL vmlinux 0x6b7e7db6 __crypto_alloc_tfm +EXPORT_SYMBOL_GPL vmlinux 0x6bd59712 platform_device_del +EXPORT_SYMBOL_GPL vmlinux 0x6c0b4ad4 inotify_rm_watch +EXPORT_SYMBOL_GPL vmlinux 0x6c11059b __srcu_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x6c49c4f2 clockevents_notify +EXPORT_SYMBOL_GPL vmlinux 0x6c8d5ae8 __gpio_get_value +EXPORT_SYMBOL_GPL vmlinux 0x6ebe305d raw_seq_stop +EXPORT_SYMBOL_GPL vmlinux 0x6ee94c95 __inet_hash_nolisten +EXPORT_SYMBOL_GPL vmlinux 0x6f9c2efe marker_probe_cb +EXPORT_SYMBOL_GPL vmlinux 0x6ffb5b60 klist_add_tail +EXPORT_SYMBOL_GPL vmlinux 0x7037d79d k8_flush_garts +EXPORT_SYMBOL_GPL vmlinux 0x704bac1a cpufreq_unregister_driver +EXPORT_SYMBOL_GPL vmlinux 0x7090f0e1 driver_attach +EXPORT_SYMBOL_GPL vmlinux 0x7105320a sk_setup_caps +EXPORT_SYMBOL_GPL vmlinux 0x71141299 tcp_set_state +EXPORT_SYMBOL_GPL vmlinux 0x715863a8 inet_csk_clone +EXPORT_SYMBOL_GPL vmlinux 0x71c8bc95 kgdb_unregister_io_module +EXPORT_SYMBOL_GPL vmlinux 0x72750f8c fb_deferred_io_open +EXPORT_SYMBOL_GPL vmlinux 0x7278d328 all_vm_events +EXPORT_SYMBOL_GPL vmlinux 0x73201149 klist_iter_init_node +EXPORT_SYMBOL_GPL vmlinux 0x73b1f76d do_posix_clock_nosettime +EXPORT_SYMBOL_GPL vmlinux 0x73d01f94 platform_driver_unregister +EXPORT_SYMBOL_GPL vmlinux 0x74740576 sysfs_remove_group +EXPORT_SYMBOL_GPL vmlinux 0x74abdafa task_handoff_register +EXPORT_SYMBOL_GPL vmlinux 0x74d61a4d get_dcookie +EXPORT_SYMBOL_GPL vmlinux 0x74deb10c used_vectors +EXPORT_SYMBOL_GPL vmlinux 0x751bc7fa vfs_getxattr +EXPORT_SYMBOL_GPL vmlinux 0x7521afb6 leave_mm +EXPORT_SYMBOL_GPL vmlinux 0x7543a836 kobject_init_and_add +EXPORT_SYMBOL_GPL vmlinux 0x7568b92e register_jprobes +EXPORT_SYMBOL_GPL vmlinux 0x75c00c51 driver_add_kobj +EXPORT_SYMBOL_GPL vmlinux 0x75c40c7b debugfs_create_dir +EXPORT_SYMBOL_GPL vmlinux 0x75c8a11c inet_twdr_twkill_work +EXPORT_SYMBOL_GPL vmlinux 0x75e8f3c3 crypto_register_notifier +EXPORT_SYMBOL_GPL vmlinux 0x7626e1ac bus_unregister_notifier +EXPORT_SYMBOL_GPL vmlinux 0x763a97d8 vlan_dev_vlan_id +EXPORT_SYMBOL_GPL vmlinux 0x77945727 raw_unhash_sk +EXPORT_SYMBOL_GPL vmlinux 0x78af1b91 inet_twsk_purge +EXPORT_SYMBOL_GPL vmlinux 0x7979a446 debugfs_create_blob +EXPORT_SYMBOL_GPL vmlinux 0x79ece86c kobject_uevent +EXPORT_SYMBOL_GPL vmlinux 0x7a4c1438 pv_info +EXPORT_SYMBOL_GPL vmlinux 0x7a53efb8 crypto_attr_alg +EXPORT_SYMBOL_GPL vmlinux 0x7ade3e90 platform_device_add +EXPORT_SYMBOL_GPL vmlinux 0x7ae9f782 sysfs_schedule_callback +EXPORT_SYMBOL_GPL vmlinux 0x7afdd2e4 __get_vm_area +EXPORT_SYMBOL_GPL vmlinux 0x7b0b4551 sysdev_show_ulong +EXPORT_SYMBOL_GPL vmlinux 0x7b1d544d edac_handler_set +EXPORT_SYMBOL_GPL vmlinux 0x7b9cc3a2 tty_ldisc_flush +EXPORT_SYMBOL_GPL vmlinux 0x7c084e78 platform_device_add_data +EXPORT_SYMBOL_GPL vmlinux 0x7c37bcd5 inotify_rm_wd +EXPORT_SYMBOL_GPL vmlinux 0x7c7bcf38 register_pernet_device +EXPORT_SYMBOL_GPL vmlinux 0x7cd551b3 led_trigger_show +EXPORT_SYMBOL_GPL vmlinux 0x7cfc08c4 device_del +EXPORT_SYMBOL_GPL vmlinux 0x7d28f410 firmware_kobj +EXPORT_SYMBOL_GPL vmlinux 0x7d438537 uart_set_options +EXPORT_SYMBOL_GPL vmlinux 0x7d5dda2a proc_net_mkdir +EXPORT_SYMBOL_GPL vmlinux 0x7da8d037 marker_probe_register +EXPORT_SYMBOL_GPL vmlinux 0x7dc37d96 device_schedule_callback_owner +EXPORT_SYMBOL_GPL vmlinux 0x7dc5d0b6 crypto_unregister_notifier +EXPORT_SYMBOL_GPL vmlinux 0x7dd3e4bd devres_open_group +EXPORT_SYMBOL_GPL vmlinux 0x7e084cb6 kobject_create_and_add +EXPORT_SYMBOL_GPL vmlinux 0x7e698a51 unregister_jprobes +EXPORT_SYMBOL_GPL vmlinux 0x7f19c836 unlock_policy_rwsem_write +EXPORT_SYMBOL_GPL vmlinux 0x7f7e0159 sysfs_create_file +EXPORT_SYMBOL_GPL vmlinux 0x7f9af2f3 device_find_child +EXPORT_SYMBOL_GPL vmlinux 0x7ff10ccf raw_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x802bc0ef sysfs_notify +EXPORT_SYMBOL_GPL vmlinux 0x80353106 gpiochip_is_requested +EXPORT_SYMBOL_GPL vmlinux 0x8039d043 selinux_secmark_relabel_packet_permission +EXPORT_SYMBOL_GPL vmlinux 0x8093e65f kobject_get_path +EXPORT_SYMBOL_GPL vmlinux 0x80ab9720 debugfs_create_u64 +EXPORT_SYMBOL_GPL vmlinux 0x80ee55c3 selinux_secmark_refcount_inc +EXPORT_SYMBOL_GPL vmlinux 0x818e30ec platform_driver_register +EXPORT_SYMBOL_GPL vmlinux 0x8190faf3 debugfs_create_file +EXPORT_SYMBOL_GPL vmlinux 0x81e634d0 class_interface_register +EXPORT_SYMBOL_GPL vmlinux 0x8226642f __gpio_cansleep +EXPORT_SYMBOL_GPL vmlinux 0x824a2b07 file_ra_state_init +EXPORT_SYMBOL_GPL vmlinux 0x826360fd do_posix_clock_nonanosleep +EXPORT_SYMBOL_GPL vmlinux 0x828afb0c queue_delayed_work +EXPORT_SYMBOL_GPL vmlinux 0x82b806c0 tty_encode_baud_rate +EXPORT_SYMBOL_GPL vmlinux 0x82d79b51 sysctl_vfs_cache_pressure +EXPORT_SYMBOL_GPL vmlinux 0x82f5273b register_timer_hook +EXPORT_SYMBOL_GPL vmlinux 0x82f776b7 gpio_export +EXPORT_SYMBOL_GPL vmlinux 0x841e8bfe pci_bus_add_device +EXPORT_SYMBOL_GPL vmlinux 0x84893620 d_materialise_unique +EXPORT_SYMBOL_GPL vmlinux 0x84f004d7 led_trigger_remove +EXPORT_SYMBOL_GPL vmlinux 0x85a6d303 rtnl_link_register +EXPORT_SYMBOL_GPL vmlinux 0x85c10896 rcu_batches_completed_bh +EXPORT_SYMBOL_GPL vmlinux 0x85d7edfd hpet_set_periodic_freq +EXPORT_SYMBOL_GPL vmlinux 0x85e5a3db ktime_get_ts +EXPORT_SYMBOL_GPL vmlinux 0x868784cb __symbol_get +EXPORT_SYMBOL_GPL vmlinux 0x86b1667d hwrng_unregister +EXPORT_SYMBOL_GPL vmlinux 0x86d271c6 dequeue_signal +EXPORT_SYMBOL_GPL vmlinux 0x86d9791b sysdev_class_register +EXPORT_SYMBOL_GPL vmlinux 0x870404b8 crypto_chain +EXPORT_SYMBOL_GPL vmlinux 0x873fbaea edac_atomic_assert_error +EXPORT_SYMBOL_GPL vmlinux 0x876b550b spi_register_master +EXPORT_SYMBOL_GPL vmlinux 0x87754115 raw_notifier_chain_register +EXPORT_SYMBOL_GPL vmlinux 0x87947f1d put_inotify_watch +EXPORT_SYMBOL_GPL vmlinux 0x87e003d7 rt_mutex_unlock +EXPORT_SYMBOL_GPL vmlinux 0x880b189a __atomic_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x8810ad5e crypto_xor +EXPORT_SYMBOL_GPL vmlinux 0x885142a6 nf_net_netfilter_sysctl_path +EXPORT_SYMBOL_GPL vmlinux 0x886736fc olpc_platform_info +EXPORT_SYMBOL_GPL vmlinux 0x89d887ad device_unregister +EXPORT_SYMBOL_GPL vmlinux 0x8a83fa58 tty_ldisc_ref +EXPORT_SYMBOL_GPL vmlinux 0x8abed13d xfrm_aead_get_byname +EXPORT_SYMBOL_GPL vmlinux 0x8b62f231 audit_log_d_path +EXPORT_SYMBOL_GPL vmlinux 0x8bf8233d crypto_lookup_template +EXPORT_SYMBOL_GPL vmlinux 0x8c367222 vfs_cancel_lock +EXPORT_SYMBOL_GPL vmlinux 0x8c9053f9 securityfs_create_dir +EXPORT_SYMBOL_GPL vmlinux 0x8ceae58a pci_find_ext_capability +EXPORT_SYMBOL_GPL vmlinux 0x8d1192d1 generic_fh_to_parent +EXPORT_SYMBOL_GPL vmlinux 0x8d5d1bd1 user_update +EXPORT_SYMBOL_GPL vmlinux 0x8da17b42 scatterwalk_copychunks +EXPORT_SYMBOL_GPL vmlinux 0x8dd78d25 blocking_notifier_chain_register +EXPORT_SYMBOL_GPL vmlinux 0x8e1e3192 blk_trace_setup +EXPORT_SYMBOL_GPL vmlinux 0x8e6d9a0a user_read +EXPORT_SYMBOL_GPL vmlinux 0x8eb58c6e __wake_up_sync +EXPORT_SYMBOL_GPL vmlinux 0x8f41fbe7 fib_rules_unregister +EXPORT_SYMBOL_GPL vmlinux 0x8f6cee77 __round_jiffies_relative +EXPORT_SYMBOL_GPL vmlinux 0x8fd5c28c devres_get +EXPORT_SYMBOL_GPL vmlinux 0x8ff8dbcd blocking_notifier_chain_cond_register +EXPORT_SYMBOL_GPL vmlinux 0x9009602a acpi_bus_get_ejd +EXPORT_SYMBOL_GPL vmlinux 0x906b805e srcu_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x90a1004a crypto_has_alg +EXPORT_SYMBOL_GPL vmlinux 0x90aec860 blk_trace_startstop +EXPORT_SYMBOL_GPL vmlinux 0x9146276a device_add +EXPORT_SYMBOL_GPL vmlinux 0x91464a76 led_trigger_unregister_simple +EXPORT_SYMBOL_GPL vmlinux 0x9159b9d6 profile_event_register +EXPORT_SYMBOL_GPL vmlinux 0x917ee697 sysfs_create_bin_file +EXPORT_SYMBOL_GPL vmlinux 0x91a575e5 generic_sync_sb_inodes +EXPORT_SYMBOL_GPL vmlinux 0x91c9a0d4 attribute_container_unregister +EXPORT_SYMBOL_GPL vmlinux 0x91dacaa2 acpi_processor_ffh_cstate_probe +EXPORT_SYMBOL_GPL vmlinux 0x91db4476 platform_device_add_resources +EXPORT_SYMBOL_GPL vmlinux 0x9241c3ee device_power_down +EXPORT_SYMBOL_GPL vmlinux 0x92445aee hrtimer_get_res +EXPORT_SYMBOL_GPL vmlinux 0x92667ed9 raw_seq_open +EXPORT_SYMBOL_GPL vmlinux 0x926bcccd driver_find_device +EXPORT_SYMBOL_GPL vmlinux 0x92e67ffe crypto_init_spawn +EXPORT_SYMBOL_GPL vmlinux 0x92fb217b dcookie_unregister +EXPORT_SYMBOL_GPL vmlinux 0x933740ca cancel_work_sync +EXPORT_SYMBOL_GPL vmlinux 0x935aac3d sg_scsi_ioctl +EXPORT_SYMBOL_GPL vmlinux 0x93d2422d snmp_mib_free +EXPORT_SYMBOL_GPL vmlinux 0x942c1704 cleanup_srcu_struct +EXPORT_SYMBOL_GPL vmlinux 0x952664c5 do_exit +EXPORT_SYMBOL_GPL vmlinux 0x956a91ba gpio_get_value_cansleep +EXPORT_SYMBOL_GPL vmlinux 0x9577271c hpet_rtc_interrupt +EXPORT_SYMBOL_GPL vmlinux 0x958d0914 inet6_lookup +EXPORT_SYMBOL_GPL vmlinux 0x95f5c45b proc_net_remove +EXPORT_SYMBOL_GPL vmlinux 0x961758c4 pci_update_slot_number +EXPORT_SYMBOL_GPL vmlinux 0x961a8cd3 unlock_policy_rwsem_read +EXPORT_SYMBOL_GPL vmlinux 0x962395bf acpi_bus_trim +EXPORT_SYMBOL_GPL vmlinux 0x96cbcf31 pm_qos_add_notifier +EXPORT_SYMBOL_GPL vmlinux 0x971d09b2 xfrm_output +EXPORT_SYMBOL_GPL vmlinux 0x973bd175 preempt_notifier_register +EXPORT_SYMBOL_GPL vmlinux 0x979a3515 crypto_ahash_type +EXPORT_SYMBOL_GPL vmlinux 0x97ddbfff dev_set_name +EXPORT_SYMBOL_GPL vmlinux 0x97e2b32a blkdev_driver_ioctl +EXPORT_SYMBOL_GPL vmlinux 0x97e8d82b __ip_route_output_key +EXPORT_SYMBOL_GPL vmlinux 0x97f321b1 pci_bus_max_busnr +EXPORT_SYMBOL_GPL vmlinux 0x9833bc0c hvc_kick +EXPORT_SYMBOL_GPL vmlinux 0x99374ee0 rt_mutex_lock +EXPORT_SYMBOL_GPL vmlinux 0x995d1071 prof_on +EXPORT_SYMBOL_GPL vmlinux 0x99833fb6 device_bind_driver +EXPORT_SYMBOL_GPL vmlinux 0x9988b657 register_posix_clock +EXPORT_SYMBOL_GPL vmlinux 0x9a11a0fc crypto_attr_alg_name +EXPORT_SYMBOL_GPL vmlinux 0x9a2c9bc8 default_backing_dev_info +EXPORT_SYMBOL_GPL vmlinux 0x9a398f5c xfrm_ealg_get_byname +EXPORT_SYMBOL_GPL vmlinux 0x9a43a090 uhci_reset_hc +EXPORT_SYMBOL_GPL vmlinux 0x9a665632 pci_intx +EXPORT_SYMBOL_GPL vmlinux 0x9b22b11d blk_execute_rq_nowait +EXPORT_SYMBOL_GPL vmlinux 0x9ba0501e unregister_vt_notifier +EXPORT_SYMBOL_GPL vmlinux 0x9bb6aebc tcp_slow_start +EXPORT_SYMBOL_GPL vmlinux 0x9bc8c394 __inet_lookup_listener +EXPORT_SYMBOL_GPL vmlinux 0x9bda11e4 page_cache_sync_readahead +EXPORT_SYMBOL_GPL vmlinux 0x9be54386 pciserial_resume_ports +EXPORT_SYMBOL_GPL vmlinux 0x9c2336dc rt_mutex_trylock +EXPORT_SYMBOL_GPL vmlinux 0x9cb8037b xfrm_count_enc_supported +EXPORT_SYMBOL_GPL vmlinux 0x9d50bb1b sysfs_add_file_to_group +EXPORT_SYMBOL_GPL vmlinux 0x9d957902 bus_find_device_by_name +EXPORT_SYMBOL_GPL vmlinux 0x9e04d90c tty_buffer_request_room +EXPORT_SYMBOL_GPL vmlinux 0x9e711ad2 pm_qos_requirement +EXPORT_SYMBOL_GPL vmlinux 0x9eae490d device_create +EXPORT_SYMBOL_GPL vmlinux 0x9f00f799 tcp_get_info +EXPORT_SYMBOL_GPL vmlinux 0x9fab22a2 inotify_add_watch +EXPORT_SYMBOL_GPL vmlinux 0x9fce80db fb_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x9ffe62a5 class_find_device +EXPORT_SYMBOL_GPL vmlinux 0xa0255440 net_ipv4_ctl_path +EXPORT_SYMBOL_GPL vmlinux 0xa089f7f8 bus_register_notifier +EXPORT_SYMBOL_GPL vmlinux 0xa0b5ca25 crypto_larval_lookup +EXPORT_SYMBOL_GPL vmlinux 0xa11b02e5 tcp_death_row +EXPORT_SYMBOL_GPL vmlinux 0xa12f9fa4 inet_csk_search_req +EXPORT_SYMBOL_GPL vmlinux 0xa1596d98 acpi_processor_ffh_cstate_enter +EXPORT_SYMBOL_GPL vmlinux 0xa171bdbf simple_attr_open +EXPORT_SYMBOL_GPL vmlinux 0xa1b822f9 tty_find_polling_driver +EXPORT_SYMBOL_GPL vmlinux 0xa2e1bb99 register_pernet_subsys +EXPORT_SYMBOL_GPL vmlinux 0xa2e67f08 acpi_bus_generate_proc_event4 +EXPORT_SYMBOL_GPL vmlinux 0xa32a0b04 rtc_irq_register +EXPORT_SYMBOL_GPL vmlinux 0xa3823f94 hvc_alloc +EXPORT_SYMBOL_GPL vmlinux 0xa3844137 nf_unregister_queue_handlers +EXPORT_SYMBOL_GPL vmlinux 0xa39d98e7 led_trigger_event +EXPORT_SYMBOL_GPL vmlinux 0xa3fc96f0 marker_probe_cb_noarg +EXPORT_SYMBOL_GPL vmlinux 0xa42fee40 simple_attr_release +EXPORT_SYMBOL_GPL vmlinux 0xa452c297 hpet_mask_rtc_irq_bit +EXPORT_SYMBOL_GPL vmlinux 0xa4dbbe3c relay_switch_subbuf +EXPORT_SYMBOL_GPL vmlinux 0xa52feeda bd_release_from_disk +EXPORT_SYMBOL_GPL vmlinux 0xa53dfab6 rtnl_register +EXPORT_SYMBOL_GPL vmlinux 0xa5bf5c3e pm_qos_add_requirement +EXPORT_SYMBOL_GPL vmlinux 0xa5c36cec inotify_unmount_inodes +EXPORT_SYMBOL_GPL vmlinux 0xa5cd5e41 inotify_remove_watch_locked +EXPORT_SYMBOL_GPL vmlinux 0xa68b4e7f __mmu_notifier_register +EXPORT_SYMBOL_GPL vmlinux 0xa6c4464f sysfs_remove_file_from_group +EXPORT_SYMBOL_GPL vmlinux 0xa7d8a48b register_net_sysctl_rotable +EXPORT_SYMBOL_GPL vmlinux 0xa7f1c377 cpufreq_register_driver +EXPORT_SYMBOL_GPL vmlinux 0xa8f59416 gpio_direction_output +EXPORT_SYMBOL_GPL vmlinux 0xa8fe2e11 xfrm_output_resume +EXPORT_SYMBOL_GPL vmlinux 0xa9126bff hpet_set_rtc_irq_bit +EXPORT_SYMBOL_GPL vmlinux 0xa956a362 register_jprobe +EXPORT_SYMBOL_GPL vmlinux 0xa963f49c tcp_orphan_count +EXPORT_SYMBOL_GPL vmlinux 0xa96d10cd cpufreq_unregister_governor +EXPORT_SYMBOL_GPL vmlinux 0xa98f04e0 tty_prepare_flip_string +EXPORT_SYMBOL_GPL vmlinux 0xa9c0ac91 pci_stop_bus_device +EXPORT_SYMBOL_GPL vmlinux 0xa9c530b8 unregister_oom_notifier +EXPORT_SYMBOL_GPL vmlinux 0xa9fc6d8b spi_busnum_to_master +EXPORT_SYMBOL_GPL vmlinux 0xaa2a72bf __iowrite64_copy +EXPORT_SYMBOL_GPL vmlinux 0xaa8c4696 cpu_clock +EXPORT_SYMBOL_GPL vmlinux 0xaaef383c inotify_inode_queue_event +EXPORT_SYMBOL_GPL vmlinux 0xaaeff472 xfrm_audit_state_notfound +EXPORT_SYMBOL_GPL vmlinux 0xab1ad17e debugfs_create_u32 +EXPORT_SYMBOL_GPL vmlinux 0xab84ad20 hvc_poll +EXPORT_SYMBOL_GPL vmlinux 0xac0292be blocking_notifier_chain_unregister +EXPORT_SYMBOL_GPL vmlinux 0xacc19485 ibft_addr +EXPORT_SYMBOL_GPL vmlinux 0xaccfc678 cpu_bit_bitmap +EXPORT_SYMBOL_GPL vmlinux 0xad09832a inet_twsk_put +EXPORT_SYMBOL_GPL vmlinux 0xad157c4a securityfs_remove +EXPORT_SYMBOL_GPL vmlinux 0xad7a9d70 tcp_reno_ssthresh +EXPORT_SYMBOL_GPL vmlinux 0xadf130f4 relay_buf_full +EXPORT_SYMBOL_GPL vmlinux 0xadf216c3 mnt_drop_write +EXPORT_SYMBOL_GPL vmlinux 0xae0c87ee pm_qos_remove_notifier +EXPORT_SYMBOL_GPL vmlinux 0xaeb7f977 __blocking_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0xaf16ec38 cpuidle_register_driver +EXPORT_SYMBOL_GPL vmlinux 0xaf644d04 crypto_spawn_tfm +EXPORT_SYMBOL_GPL vmlinux 0xafc1b07f register_kretprobe +EXPORT_SYMBOL_GPL vmlinux 0xb021c3d3 devres_add +EXPORT_SYMBOL_GPL vmlinux 0xb0ab9f8c flush_work +EXPORT_SYMBOL_GPL vmlinux 0xb10d55bc cn_netlink_send +EXPORT_SYMBOL_GPL vmlinux 0xb120ab95 klist_remove +EXPORT_SYMBOL_GPL vmlinux 0xb1347720 find_get_pid +EXPORT_SYMBOL_GPL vmlinux 0xb1acbcce rcu_barrier_sched +EXPORT_SYMBOL_GPL vmlinux 0xb1c7d7cf mmput +EXPORT_SYMBOL_GPL vmlinux 0xb27005f5 device_suspend +EXPORT_SYMBOL_GPL vmlinux 0xb28c5cad raw_seq_start +EXPORT_SYMBOL_GPL vmlinux 0xb305fa4b bus_remove_file +EXPORT_SYMBOL_GPL vmlinux 0xb313a59e unregister_kprobe +EXPORT_SYMBOL_GPL vmlinux 0xb3253ed9 hpet_rtc_timer_init +EXPORT_SYMBOL_GPL vmlinux 0xb3f681ab xfrm_audit_state_icvfail +EXPORT_SYMBOL_GPL vmlinux 0xb4003cb8 platform_driver_probe +EXPORT_SYMBOL_GPL vmlinux 0xb4c3ea18 bus_register +EXPORT_SYMBOL_GPL vmlinux 0xb4ea7cf7 kgdb_connected +EXPORT_SYMBOL_GPL vmlinux 0xb51fbd64 edac_op_state +EXPORT_SYMBOL_GPL vmlinux 0xb53ae573 cpu_idle_wait +EXPORT_SYMBOL_GPL vmlinux 0xb5bdacb3 inotify_init_watch +EXPORT_SYMBOL_GPL vmlinux 0xb63550f5 __i2c_board_lock +EXPORT_SYMBOL_GPL vmlinux 0xb65091b3 selinux_secmark_refcount_dec +EXPORT_SYMBOL_GPL vmlinux 0xb7249842 platform_device_register +EXPORT_SYMBOL_GPL vmlinux 0xb7d7c12e hpet_set_alarm_time +EXPORT_SYMBOL_GPL vmlinux 0xb84c1915 skb_icv_walk +EXPORT_SYMBOL_GPL vmlinux 0xb8714aaa tty_ldisc_deref +EXPORT_SYMBOL_GPL vmlinux 0xb8de6da6 input_ff_destroy +EXPORT_SYMBOL_GPL vmlinux 0xb9115a7f skb_segment +EXPORT_SYMBOL_GPL vmlinux 0xb91ddd15 rt_mutex_timed_lock +EXPORT_SYMBOL_GPL vmlinux 0xb9eb3aa9 add_uevent_var +EXPORT_SYMBOL_GPL vmlinux 0xba0606de elv_unregister +EXPORT_SYMBOL_GPL vmlinux 0xba402c15 sysdev_register +EXPORT_SYMBOL_GPL vmlinux 0xba5c9082 fs_kobj +EXPORT_SYMBOL_GPL vmlinux 0xba9b3a6f class_destroy +EXPORT_SYMBOL_GPL vmlinux 0xbae8be8f vfs_removexattr +EXPORT_SYMBOL_GPL vmlinux 0xbb4832b7 zap_vma_ptes +EXPORT_SYMBOL_GPL vmlinux 0xbb502333 mm_kobj +EXPORT_SYMBOL_GPL vmlinux 0xbb88d37f crypto_shoot_alg +EXPORT_SYMBOL_GPL vmlinux 0xbb90e9a5 pci_cleanup_aer_uncorrect_error_status +EXPORT_SYMBOL_GPL vmlinux 0xbbb98859 edid_info +EXPORT_SYMBOL_GPL vmlinux 0xbc2eb3a5 power_supply_am_i_supplied +EXPORT_SYMBOL_GPL vmlinux 0xbcca4c4f screen_glyph +EXPORT_SYMBOL_GPL vmlinux 0xbd03cc41 skb_cow_data +EXPORT_SYMBOL_GPL vmlinux 0xbd3ac7d6 page_mkclean +EXPORT_SYMBOL_GPL vmlinux 0xbd89193b tty_put_char +EXPORT_SYMBOL_GPL vmlinux 0xbdcce1b1 register_kprobe +EXPORT_SYMBOL_GPL vmlinux 0xbe34bf6a device_release_driver +EXPORT_SYMBOL_GPL vmlinux 0xbf940f88 debugfs_create_symlink +EXPORT_SYMBOL_GPL vmlinux 0xbfb739f8 device_attach +EXPORT_SYMBOL_GPL vmlinux 0xbfd1996d class_for_each_device +EXPORT_SYMBOL_GPL vmlinux 0xc0179dbe crypto_larval_kill +EXPORT_SYMBOL_GPL vmlinux 0xc06bcadb spi_alloc_device +EXPORT_SYMBOL_GPL vmlinux 0xc097eb8e hrtimer_get_remaining +EXPORT_SYMBOL_GPL vmlinux 0xc0ed34aa bus_for_each_drv +EXPORT_SYMBOL_GPL vmlinux 0xc16cbc91 fsstack_copy_inode_size +EXPORT_SYMBOL_GPL vmlinux 0xc17eb04e rtc_read_time +EXPORT_SYMBOL_GPL vmlinux 0xc1b9670d leds_list_lock +EXPORT_SYMBOL_GPL vmlinux 0xc1dd60a9 lookup_create +EXPORT_SYMBOL_GPL vmlinux 0xc200f1f0 queue_work_on +EXPORT_SYMBOL_GPL vmlinux 0xc2233908 vlan_dev_real_dev +EXPORT_SYMBOL_GPL vmlinux 0xc2662857 debugfs_create_bool +EXPORT_SYMBOL_GPL vmlinux 0xc2779f5e rtc_update_irq +EXPORT_SYMBOL_GPL vmlinux 0xc290164c securityfs_create_file +EXPORT_SYMBOL_GPL vmlinux 0xc31be7c8 put_device +EXPORT_SYMBOL_GPL vmlinux 0xc34efe27 snmp_fold_field +EXPORT_SYMBOL_GPL vmlinux 0xc35b1a81 __rtnl_link_register +EXPORT_SYMBOL_GPL vmlinux 0xc36420ce transport_class_unregister +EXPORT_SYMBOL_GPL vmlinux 0xc41520b1 sysfs_create_link +EXPORT_SYMBOL_GPL vmlinux 0xc493e76c platform_device_unregister +EXPORT_SYMBOL_GPL vmlinux 0xc4acfb62 cpufreq_driver_target +EXPORT_SYMBOL_GPL vmlinux 0xc4eb3f5d __mmdrop +EXPORT_SYMBOL_GPL vmlinux 0xc512626a __supported_pte_mask +EXPORT_SYMBOL_GPL vmlinux 0xc52e2261 inet_hash +EXPORT_SYMBOL_GPL vmlinux 0xc574fd8a transport_add_device +EXPORT_SYMBOL_GPL vmlinux 0xc58cdb60 lookup_address +EXPORT_SYMBOL_GPL vmlinux 0xc5ba00df fb_deferred_io_init +EXPORT_SYMBOL_GPL vmlinux 0xc6270b90 tcp_register_congestion_control +EXPORT_SYMBOL_GPL vmlinux 0xc63db010 unregister_pernet_device +EXPORT_SYMBOL_GPL vmlinux 0xc6b402e5 __percpu_alloc_mask +EXPORT_SYMBOL_GPL vmlinux 0xc6cabb03 device_remove_file +EXPORT_SYMBOL_GPL vmlinux 0xc73e5874 preempt_notifier_unregister +EXPORT_SYMBOL_GPL vmlinux 0xc7ec11f6 atomic_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0xc81d40a6 hrtimer_cancel +EXPORT_SYMBOL_GPL vmlinux 0xc87c1f84 ktime_get +EXPORT_SYMBOL_GPL vmlinux 0xc87e487a sched_clock_idle_sleep_event +EXPORT_SYMBOL_GPL vmlinux 0xc93bda9b inet_csk_get_port +EXPORT_SYMBOL_GPL vmlinux 0xc953f147 platform_get_resource +EXPORT_SYMBOL_GPL vmlinux 0xc9561772 fb_destroy_modelist +EXPORT_SYMBOL_GPL vmlinux 0xca8a6a1f get_task_mm +EXPORT_SYMBOL_GPL vmlinux 0xca92bced fb_deferred_io_cleanup +EXPORT_SYMBOL_GPL vmlinux 0xcabe04de cpuidle_resume_and_unlock +EXPORT_SYMBOL_GPL vmlinux 0xcb922768 fib_rules_lookup +EXPORT_SYMBOL_GPL vmlinux 0xcbdbf956 device_rename +EXPORT_SYMBOL_GPL vmlinux 0xcbf20127 klist_iter_init +EXPORT_SYMBOL_GPL vmlinux 0xcc1f1c3d inet_twdr_hangman +EXPORT_SYMBOL_GPL vmlinux 0xcc8bed9f __create_workqueue_key +EXPORT_SYMBOL_GPL vmlinux 0xcce7faf2 pci_find_aer_capability +EXPORT_SYMBOL_GPL vmlinux 0xcdd6550e register_kprobes +EXPORT_SYMBOL_GPL vmlinux 0xce8ebc6a pci_set_pcie_reset_state +EXPORT_SYMBOL_GPL vmlinux 0xcee8cd15 queue_work +EXPORT_SYMBOL_GPL vmlinux 0xcf0bfd12 start_thread +EXPORT_SYMBOL_GPL vmlinux 0xcf899cd8 blk_trace_remove +EXPORT_SYMBOL_GPL vmlinux 0xcfcc83ad register_vt_notifier +EXPORT_SYMBOL_GPL vmlinux 0xd027a07d marker_probe_unregister +EXPORT_SYMBOL_GPL vmlinux 0xd03c7700 secure_ipv4_port_ephemeral +EXPORT_SYMBOL_GPL vmlinux 0xd0c05159 emergency_restart +EXPORT_SYMBOL_GPL vmlinux 0xd0c71012 tty_prepare_flip_string_flags +EXPORT_SYMBOL_GPL vmlinux 0xd0f3df81 inet_unhash +EXPORT_SYMBOL_GPL vmlinux 0xd124e095 pcie_port_bus_type +EXPORT_SYMBOL_GPL vmlinux 0xd12ac59b olpc_ec_cmd +EXPORT_SYMBOL_GPL vmlinux 0xd16712f3 crypto_check_attr_type +EXPORT_SYMBOL_GPL vmlinux 0xd177204e spi_alloc_master +EXPORT_SYMBOL_GPL vmlinux 0xd19a5406 fib_rules_cleanup_ops +EXPORT_SYMBOL_GPL vmlinux 0xd1aabf25 device_for_each_child +EXPORT_SYMBOL_GPL vmlinux 0xd1c672a1 hwmon_device_register +EXPORT_SYMBOL_GPL vmlinux 0xd1f8dee0 bus_rescan_devices +EXPORT_SYMBOL_GPL vmlinux 0xd2c997e3 find_vpid +EXPORT_SYMBOL_GPL vmlinux 0xd31e59e0 drop_file_write_access +EXPORT_SYMBOL_GPL vmlinux 0xd35a5a09 rtc_read_alarm +EXPORT_SYMBOL_GPL vmlinux 0xd3619d19 inet_csk_reqsk_queue_prune +EXPORT_SYMBOL_GPL vmlinux 0xd3ffecb0 security_inode_permission +EXPORT_SYMBOL_GPL vmlinux 0xd53a82fc crypto_alloc_base +EXPORT_SYMBOL_GPL vmlinux 0xd555c9ff crypto_register_alg +EXPORT_SYMBOL_GPL vmlinux 0xd5cbd4ce audit_log_vformat +EXPORT_SYMBOL_GPL vmlinux 0xd7d0159d power_supply_register +EXPORT_SYMBOL_GPL vmlinux 0xd7d79132 put_online_cpus +EXPORT_SYMBOL_GPL vmlinux 0xd806c963 page_cache_async_readahead +EXPORT_SYMBOL_GPL vmlinux 0xd86e2d10 rtnl_kill_links +EXPORT_SYMBOL_GPL vmlinux 0xd89f2217 bus_for_each_dev +EXPORT_SYMBOL_GPL vmlinux 0xd93ff79a pskb_put +EXPORT_SYMBOL_GPL vmlinux 0xda2a5a98 uart_console_write +EXPORT_SYMBOL_GPL vmlinux 0xda6fb5f2 platform_device_alloc +EXPORT_SYMBOL_GPL vmlinux 0xdaa0dd47 relay_flush +EXPORT_SYMBOL_GPL vmlinux 0xdaf4dfb3 fb_mode_option +EXPORT_SYMBOL_GPL vmlinux 0xdb2a1107 get_driver +EXPORT_SYMBOL_GPL vmlinux 0xdb44346f tcp_unregister_congestion_control +EXPORT_SYMBOL_GPL vmlinux 0xdb4472f7 anon_inode_getfd +EXPORT_SYMBOL_GPL vmlinux 0xdb958233 tcp_init_congestion_ops +EXPORT_SYMBOL_GPL vmlinux 0xdbaf10b1 power_supply_changed +EXPORT_SYMBOL_GPL vmlinux 0xdc046069 driver_find +EXPORT_SYMBOL_GPL vmlinux 0xdc0d4c42 ip_local_out +EXPORT_SYMBOL_GPL vmlinux 0xdccada48 destroy_workqueue +EXPORT_SYMBOL_GPL vmlinux 0xdcd3fbc3 pci_scan_child_bus +EXPORT_SYMBOL_GPL vmlinux 0xdce1301c skb_pull_rcsum +EXPORT_SYMBOL_GPL vmlinux 0xdd5c4942 srcu_notifier_chain_register +EXPORT_SYMBOL_GPL vmlinux 0xddf18fca alloc_page_buffers +EXPORT_SYMBOL_GPL vmlinux 0xdeaa98e0 blk_end_request_callback +EXPORT_SYMBOL_GPL vmlinux 0xdee17dd1 dnotify_parent +EXPORT_SYMBOL_GPL vmlinux 0xdf29615d get_cpu_sysdev +EXPORT_SYMBOL_GPL vmlinux 0xdf3c19ec cn_add_callback +EXPORT_SYMBOL_GPL vmlinux 0xdf7f8108 __blk_put_request +EXPORT_SYMBOL_GPL vmlinux 0xdf8b07ff rtc_set_alarm +EXPORT_SYMBOL_GPL vmlinux 0xdfd6cb4a raw_hash_sk +EXPORT_SYMBOL_GPL vmlinux 0xe039acd0 xfrm_audit_state_replay_overflow +EXPORT_SYMBOL_GPL vmlinux 0xe0406b5a blocking_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0xe095b039 mmu_notifier_register +EXPORT_SYMBOL_GPL vmlinux 0xe0c368ae get_inotify_watch +EXPORT_SYMBOL_GPL vmlinux 0xe17a0741 devres_destroy +EXPORT_SYMBOL_GPL vmlinux 0xe1d1c888 bd_claim_by_disk +EXPORT_SYMBOL_GPL vmlinux 0xe295c0ff is_hpet_enabled +EXPORT_SYMBOL_GPL vmlinux 0xe3039085 kobject_rename +EXPORT_SYMBOL_GPL vmlinux 0xe3687db4 driver_unregister +EXPORT_SYMBOL_GPL vmlinux 0xe3a7d930 inet_csk_addr2sockaddr +EXPORT_SYMBOL_GPL vmlinux 0xe4659142 inotify_inode_is_dead +EXPORT_SYMBOL_GPL vmlinux 0xe48d5eac acpi_ec_add_query_handler +EXPORT_SYMBOL_GPL vmlinux 0xe4b3d006 crypto_dequeue_request +EXPORT_SYMBOL_GPL vmlinux 0xe4c331b6 acpi_os_unmap_memory +EXPORT_SYMBOL_GPL vmlinux 0xe4dcc2c3 crypto_tfm_in_queue +EXPORT_SYMBOL_GPL vmlinux 0xe513afc0 cache_k8_northbridges +EXPORT_SYMBOL_GPL vmlinux 0xe530071c pm_qos_remove_requirement +EXPORT_SYMBOL_GPL vmlinux 0xe58542b9 debugfs_create_u16 +EXPORT_SYMBOL_GPL vmlinux 0xe61a6d2f gpio_unexport +EXPORT_SYMBOL_GPL vmlinux 0xe6241888 spi_bus_type +EXPORT_SYMBOL_GPL vmlinux 0xe6488b47 cpufreq_notify_transition +EXPORT_SYMBOL_GPL vmlinux 0xe674a5cb srcu_read_lock +EXPORT_SYMBOL_GPL vmlinux 0xe7fa47ad srcu_read_unlock +EXPORT_SYMBOL_GPL vmlinux 0xe87c35c4 xfrm_audit_policy_add +EXPORT_SYMBOL_GPL vmlinux 0xe88ba3e6 pci_find_next_ht_capability +EXPORT_SYMBOL_GPL vmlinux 0xe8bb067a put_driver +EXPORT_SYMBOL_GPL vmlinux 0xe93203b5 crypto_drop_spawn +EXPORT_SYMBOL_GPL vmlinux 0xe93e49c3 devres_free +EXPORT_SYMBOL_GPL vmlinux 0xe93eb140 inet_diag_unregister +EXPORT_SYMBOL_GPL vmlinux 0xe9df60aa devm_kzalloc +EXPORT_SYMBOL_GPL vmlinux 0xea065e01 task_handoff_unregister +EXPORT_SYMBOL_GPL vmlinux 0xea0d8fab led_trigger_register_simple +EXPORT_SYMBOL_GPL vmlinux 0xea579888 sk_clone +EXPORT_SYMBOL_GPL vmlinux 0xeb9df14f init_pid_ns +EXPORT_SYMBOL_GPL vmlinux 0xec357b03 crypto_alg_mod_lookup +EXPORT_SYMBOL_GPL vmlinux 0xed72c1d0 transport_class_register +EXPORT_SYMBOL_GPL vmlinux 0xedbab11b kill_pid_info_as_uid +EXPORT_SYMBOL_GPL vmlinux 0xede65e13 transport_remove_device +EXPORT_SYMBOL_GPL vmlinux 0xef2dc7b9 power_supply_class +EXPORT_SYMBOL_GPL vmlinux 0xef47cdb9 lookup_instantiate_filp +EXPORT_SYMBOL_GPL vmlinux 0xefe21106 snmp_mib_init +EXPORT_SYMBOL_GPL vmlinux 0xf096a4a7 debugfs_remove_recursive +EXPORT_SYMBOL_GPL vmlinux 0xf1676b41 user_describe +EXPORT_SYMBOL_GPL vmlinux 0xf17578fe crypto_unregister_alg +EXPORT_SYMBOL_GPL vmlinux 0xf184d189 kernel_power_off +EXPORT_SYMBOL_GPL vmlinux 0xf18fa97a register_pernet_gen_device +EXPORT_SYMBOL_GPL vmlinux 0xf27d1f53 nf_register_afinfo +EXPORT_SYMBOL_GPL vmlinux 0xf2e1031d __audit_inode_child +EXPORT_SYMBOL_GPL vmlinux 0xf2fca922 uart_parse_options +EXPORT_SYMBOL_GPL vmlinux 0xf37fef28 rt_mutex_lock_interruptible +EXPORT_SYMBOL_GPL vmlinux 0xf426b6a7 mmu_notifier_unregister +EXPORT_SYMBOL_GPL vmlinux 0xf4841f48 led_trigger_unregister +EXPORT_SYMBOL_GPL vmlinux 0xf499fdb2 rcu_barrier_bh +EXPORT_SYMBOL_GPL vmlinux 0xf553318d cpuidle_pause_and_lock +EXPORT_SYMBOL_GPL vmlinux 0xf5a691cd invalidate_bh_lrus +EXPORT_SYMBOL_GPL vmlinux 0xf5a974d6 tcp_is_cwnd_limited +EXPORT_SYMBOL_GPL vmlinux 0xf61eda48 single_release_net +EXPORT_SYMBOL_GPL vmlinux 0xf63b757c driver_for_each_device +EXPORT_SYMBOL_GPL vmlinux 0xf686b48b __rtnl_register +EXPORT_SYMBOL_GPL vmlinux 0xf6bcbd73 hwrng_register +EXPORT_SYMBOL_GPL vmlinux 0xf6e8e130 pci_find_next_capability +EXPORT_SYMBOL_GPL vmlinux 0xf70c28cd seq_release_net +EXPORT_SYMBOL_GPL vmlinux 0xf779cc02 cpuidle_unregister_driver +EXPORT_SYMBOL_GPL vmlinux 0xf7c4fb67 sysfs_update_group +EXPORT_SYMBOL_GPL vmlinux 0xf7f0b7ec pciserial_init_ports +EXPORT_SYMBOL_GPL vmlinux 0xf82f16b3 execute_in_process_context +EXPORT_SYMBOL_GPL vmlinux 0xf8802492 print_stack_trace +EXPORT_SYMBOL_GPL vmlinux 0xf8ee0827 __cpufreq_driver_getavg +EXPORT_SYMBOL_GPL vmlinux 0xf9238304 anon_transport_class_unregister +EXPORT_SYMBOL_GPL vmlinux 0xf9333d7d fb_bl_default_curve +EXPORT_SYMBOL_GPL vmlinux 0xf97bee69 ip_build_and_send_pkt +EXPORT_SYMBOL_GPL vmlinux 0xf97c4aae klist_iter_exit +EXPORT_SYMBOL_GPL vmlinux 0xf9a054b5 __round_jiffies +EXPORT_SYMBOL_GPL vmlinux 0xf9f01a87 netlink_has_listeners +EXPORT_SYMBOL_GPL vmlinux 0xfa35f6f3 invalidate_inode_pages2_range +EXPORT_SYMBOL_GPL vmlinux 0xfb2a3293 math_state_restore +EXPORT_SYMBOL_GPL vmlinux 0xfb4bbbe5 do_kern_mount +EXPORT_SYMBOL_GPL vmlinux 0xfb6e0678 platform_get_irq +EXPORT_SYMBOL_GPL vmlinux 0xfbf9be5d register_oom_notifier +EXPORT_SYMBOL_GPL vmlinux 0xfc90b5af tcp_done +EXPORT_SYMBOL_GPL vmlinux 0xfd3930d7 unregister_timer_hook +EXPORT_SYMBOL_GPL vmlinux 0xfda74e28 user_destroy +EXPORT_SYMBOL_GPL vmlinux 0xfde0b92c crypto_larval_error +EXPORT_SYMBOL_GPL vmlinux 0xfdf1c041 per_cpu__gdt_page +EXPORT_SYMBOL_GPL vmlinux 0xfe990052 gpio_free +EXPORT_SYMBOL_GPL vmlinux 0xfecbff96 __mark_empty_function +EXPORT_SYMBOL_GPL vmlinux 0xff5a8cfe cn_del_callback +EXPORT_SYMBOL_GPL vmlinux 0xff5d89a0 kobject_uevent_env +EXPORT_UNUSED_SYMBOL vmlinux 0x00000000 init_mm --- linux-2.6.27.orig/debian/abi/2.6.27-14.39/i386/server +++ linux-2.6.27/debian/abi/2.6.27-14.39/i386/server @@ -0,0 +1,8203 @@ +EXPORT_SYMBOL arch/x86/kernel/scx200 0x254e5667 scx200_gpio_base +EXPORT_SYMBOL arch/x86/kernel/scx200 0x35a3c008 scx200_gpio_configure +EXPORT_SYMBOL arch/x86/kernel/scx200 0x8cfa375c scx200_gpio_shadow +EXPORT_SYMBOL arch/x86/kernel/scx200 0x907665bd scx200_cb_base +EXPORT_SYMBOL arch/x86/kvm/kvm 0x093a9f46 kvm_cpu_has_pending_timer +EXPORT_SYMBOL arch/x86/kvm/kvm 0xcd4340c5 kvm_read_guest_atomic +EXPORT_SYMBOL crypto/gf128mul 0x0c2f123f gf128mul_4k_bbe +EXPORT_SYMBOL crypto/gf128mul 0x1068004b gf128mul_bbe +EXPORT_SYMBOL crypto/gf128mul 0x2f2889a0 gf128mul_init_64k_lle +EXPORT_SYMBOL crypto/gf128mul 0x3755f990 gf128mul_init_64k_bbe +EXPORT_SYMBOL crypto/gf128mul 0x384ef9ce gf128mul_64k_bbe +EXPORT_SYMBOL crypto/gf128mul 0x56af0dbd gf128mul_x_ble +EXPORT_SYMBOL crypto/gf128mul 0x83581089 gf128mul_init_4k_lle +EXPORT_SYMBOL crypto/gf128mul 0x9b2560b9 gf128mul_init_4k_bbe +EXPORT_SYMBOL crypto/gf128mul 0x9e13f6f6 gf128mul_lle +EXPORT_SYMBOL crypto/gf128mul 0xbd17a0df gf128mul_4k_lle +EXPORT_SYMBOL crypto/gf128mul 0xc0890413 gf128mul_64k_lle +EXPORT_SYMBOL crypto/gf128mul 0xd60736ec gf128mul_free_64k +EXPORT_SYMBOL crypto/xor 0x5b6c00e6 xor_blocks +EXPORT_SYMBOL drivers/acpi/processor 0x0603377d acpi_processor_preregister_performance +EXPORT_SYMBOL drivers/acpi/processor 0x8461fbfe acpi_processor_unregister_performance +EXPORT_SYMBOL drivers/acpi/processor 0xd78b77e1 acpi_processor_register_performance +EXPORT_SYMBOL drivers/acpi/processor 0xe420d26f acpi_processor_notify_smm +EXPORT_SYMBOL drivers/acpi/processor 0xe8a3605f acpi_processor_set_thermal_limit +EXPORT_SYMBOL drivers/atm/suni 0xda89c74d suni_init +EXPORT_SYMBOL drivers/atm/uPD98402 0x7f4a6202 uPD98402_init +EXPORT_SYMBOL drivers/block/loop 0x2d43dd5d loop_register_transfer +EXPORT_SYMBOL drivers/block/loop 0xbfee3ad5 loop_unregister_transfer +EXPORT_SYMBOL drivers/block/paride/paride 0x0273763a pi_do_claimed +EXPORT_SYMBOL drivers/block/paride/paride 0x04698cd4 paride_unregister +EXPORT_SYMBOL drivers/block/paride/paride 0x1b1cd8b4 pi_connect +EXPORT_SYMBOL drivers/block/paride/paride 0x2e5246f4 pi_disconnect +EXPORT_SYMBOL drivers/block/paride/paride 0x4f33168d pi_write_block +EXPORT_SYMBOL drivers/block/paride/paride 0x5aa87729 pi_release +EXPORT_SYMBOL drivers/block/paride/paride 0x5c868611 pi_read_regr +EXPORT_SYMBOL drivers/block/paride/paride 0x611185a1 pi_schedule_claimed +EXPORT_SYMBOL drivers/block/paride/paride 0x9f818994 pi_write_regr +EXPORT_SYMBOL drivers/block/paride/paride 0xb51af6d0 paride_register +EXPORT_SYMBOL drivers/block/paride/paride 0xb9944237 pi_read_block +EXPORT_SYMBOL drivers/block/paride/paride 0xf9c72f44 pi_init +EXPORT_SYMBOL drivers/cdrom/cdrom 0x2a2fd430 cdrom_open +EXPORT_SYMBOL drivers/cdrom/cdrom 0x3dd29ec4 cdrom_media_changed +EXPORT_SYMBOL drivers/cdrom/cdrom 0x4f476e96 init_cdrom_command +EXPORT_SYMBOL drivers/cdrom/cdrom 0x58cc8099 unregister_cdrom +EXPORT_SYMBOL drivers/cdrom/cdrom 0x6cbab49e cdrom_number_of_slots +EXPORT_SYMBOL drivers/cdrom/cdrom 0x85729206 cdrom_release +EXPORT_SYMBOL drivers/cdrom/cdrom 0x9d11b62d register_cdrom +EXPORT_SYMBOL drivers/cdrom/cdrom 0xb126aa01 cdrom_get_last_written +EXPORT_SYMBOL drivers/cdrom/cdrom 0xc1b44a3f cdrom_ioctl +EXPORT_SYMBOL drivers/cdrom/cdrom 0xd1f65902 cdrom_mode_select +EXPORT_SYMBOL drivers/cdrom/cdrom 0xdf7c1813 cdrom_get_media_event +EXPORT_SYMBOL drivers/cdrom/cdrom 0xf38bcf5e cdrom_mode_sense +EXPORT_SYMBOL drivers/char/agp/agpgart 0x032e385a agp_generic_alloc_user +EXPORT_SYMBOL drivers/char/agp/agpgart 0x04405aa2 agp_generic_create_gatt_table +EXPORT_SYMBOL drivers/char/agp/agpgart 0x1e2f5175 agp_generic_destroy_page +EXPORT_SYMBOL drivers/char/agp/agpgart 0x2825ebd5 agp_generic_insert_memory +EXPORT_SYMBOL drivers/char/agp/agpgart 0x296a4cbd agp_generic_enable +EXPORT_SYMBOL drivers/char/agp/agpgart 0x30226ddf agp_device_command +EXPORT_SYMBOL drivers/char/agp/agpgart 0x30fe2673 agp_generic_free_by_type +EXPORT_SYMBOL drivers/char/agp/agpgart 0x35a96cbf agp_backend_acquire +EXPORT_SYMBOL drivers/char/agp/agpgart 0x37e6a734 agp_backend_release +EXPORT_SYMBOL drivers/char/agp/agpgart 0x3eca3f4a agp_copy_info +EXPORT_SYMBOL drivers/char/agp/agpgart 0x3f8ff072 agp_bridge +EXPORT_SYMBOL drivers/char/agp/agpgart 0x44f01cb6 agp_allocate_memory +EXPORT_SYMBOL drivers/char/agp/agpgart 0x47061750 agp_enable +EXPORT_SYMBOL drivers/char/agp/agpgart 0x49fe94fc agp_generic_free_gatt_table +EXPORT_SYMBOL drivers/char/agp/agpgart 0x4b085dbf agp3_generic_configure +EXPORT_SYMBOL drivers/char/agp/agpgart 0x4dfb7520 agp_generic_alloc_by_type +EXPORT_SYMBOL drivers/char/agp/agpgart 0x59bd70d0 agp_flush_chipset +EXPORT_SYMBOL drivers/char/agp/agpgart 0x673f815e agp_bridges +EXPORT_SYMBOL drivers/char/agp/agpgart 0x7538b132 agp_off +EXPORT_SYMBOL drivers/char/agp/agpgart 0x7656a614 agp_generic_alloc_page +EXPORT_SYMBOL drivers/char/agp/agpgart 0x76ad0f41 agp_find_bridge +EXPORT_SYMBOL drivers/char/agp/agpgart 0x8e8af8bf agp_create_memory +EXPORT_SYMBOL drivers/char/agp/agpgart 0x8f7ce969 agp_free_page_array +EXPORT_SYMBOL drivers/char/agp/agpgart 0x903f6a7e agp_alloc_page_array +EXPORT_SYMBOL drivers/char/agp/agpgart 0x908641cb agp_free_memory +EXPORT_SYMBOL drivers/char/agp/agpgart 0xa4d4f0e6 global_cache_flush +EXPORT_SYMBOL drivers/char/agp/agpgart 0xa8abab00 agp_generic_remove_memory +EXPORT_SYMBOL drivers/char/agp/agpgart 0xaf260cb2 agp_bind_memory +EXPORT_SYMBOL drivers/char/agp/agpgart 0xb04ea8f0 agp_rebind_memory +EXPORT_SYMBOL drivers/char/agp/agpgart 0xb75944df agp3_generic_tlbflush +EXPORT_SYMBOL drivers/char/agp/agpgart 0xc2424641 agp3_generic_cleanup +EXPORT_SYMBOL drivers/char/agp/agpgart 0xc5d9c46c agp_try_unsupported_boot +EXPORT_SYMBOL drivers/char/agp/agpgart 0xc65abeb7 agp3_generic_sizes +EXPORT_SYMBOL drivers/char/agp/agpgart 0xc67dac16 agp_generic_mask_memory +EXPORT_SYMBOL drivers/char/agp/agpgart 0xca289509 agp_generic_type_to_mask_type +EXPORT_SYMBOL drivers/char/agp/agpgart 0xd0fef3b2 agp_free_key +EXPORT_SYMBOL drivers/char/agp/agpgart 0xd97d642d agp_alloc_bridge +EXPORT_SYMBOL drivers/char/agp/agpgart 0xdc3496b9 agp_collect_device_status +EXPORT_SYMBOL drivers/char/agp/agpgart 0xde9b17ed agp3_generic_fetch_size +EXPORT_SYMBOL drivers/char/agp/agpgart 0xdfa80bdb agp_unbind_memory +EXPORT_SYMBOL drivers/char/agp/agpgart 0xe0e609e8 agp_put_bridge +EXPORT_SYMBOL drivers/char/agp/agpgart 0xfd40f5fd get_agp_version +EXPORT_SYMBOL drivers/char/generic_serial 0x100b3626 gs_getserial +EXPORT_SYMBOL drivers/char/generic_serial 0x11c7862a gs_stop +EXPORT_SYMBOL drivers/char/generic_serial 0x1e859cda gs_put_char +EXPORT_SYMBOL drivers/char/generic_serial 0x26d49a0c gs_set_termios +EXPORT_SYMBOL drivers/char/generic_serial 0x391631d0 gs_write +EXPORT_SYMBOL drivers/char/generic_serial 0x3d51e464 gs_flush_buffer +EXPORT_SYMBOL drivers/char/generic_serial 0x4cf1f490 gs_got_break +EXPORT_SYMBOL drivers/char/generic_serial 0x5ee2e008 gs_hangup +EXPORT_SYMBOL drivers/char/generic_serial 0x6bcd6c55 gs_block_til_ready +EXPORT_SYMBOL drivers/char/generic_serial 0x7861b1ad gs_close +EXPORT_SYMBOL drivers/char/generic_serial 0xa98f3507 gs_setserial +EXPORT_SYMBOL drivers/char/generic_serial 0xb2d4bd98 gs_start +EXPORT_SYMBOL drivers/char/generic_serial 0xc1939d49 gs_chars_in_buffer +EXPORT_SYMBOL drivers/char/generic_serial 0xc1bbe7e1 gs_init_port +EXPORT_SYMBOL drivers/char/generic_serial 0xdf65de50 gs_write_room +EXPORT_SYMBOL drivers/char/generic_serial 0xf05b418a gs_flush_chars +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x0c35318b ipmi_free_recv_msg +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x212ccedf ipmi_register_smi +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x40f2b10c ipmi_alloc_smi_msg +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x42fd5a71 ipmi_destroy_user +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x4c41f06b ipmi_set_my_address +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x51021a27 ipmi_set_my_LUN +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x52bf6400 ipmi_unregister_for_cmd +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x5f9bab2b ipmi_register_for_cmd +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x62a83b37 ipmi_get_version +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x66001bd8 ipmi_request_supply_msgs +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x804f922a ipmi_addr_length +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x88bb3794 ipmi_poll_interface +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x9e4aa29e ipmi_smi_msg_received +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xa02b163f ipmi_get_maintenance_mode +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xa7255c27 ipmi_request_settime +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xa76153f1 ipmi_smi_add_proc_entry +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xa7ffc25a ipmi_get_my_LUN +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xbe9b5b65 ipmi_create_user +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xd3f6945b ipmi_smi_watcher_unregister +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xd42c64a3 ipmi_set_gets_events +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xd6b8e22d ipmi_set_maintenance_mode +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xe4f4665b ipmi_validate_addr +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xe50d2e46 ipmi_unregister_smi +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xea3e57ca ipmi_smi_watcher_register +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xf2185cd5 ipmi_get_my_address +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xfb123eee ipmi_smi_watchdog_pretimeout +EXPORT_SYMBOL drivers/char/nsc_gpio 0x22771650 nsc_gpio_dump +EXPORT_SYMBOL drivers/char/nsc_gpio 0xe6fc2958 nsc_gpio_write +EXPORT_SYMBOL drivers/char/nsc_gpio 0xf31a4193 nsc_gpio_read +EXPORT_SYMBOL drivers/char/nvram 0x0f28cb91 nvram_read_byte +EXPORT_SYMBOL drivers/char/nvram 0x17ff2c1d __nvram_read_byte +EXPORT_SYMBOL drivers/char/nvram 0x2adec1e0 __nvram_check_checksum +EXPORT_SYMBOL drivers/char/nvram 0x7da28f12 nvram_check_checksum +EXPORT_SYMBOL drivers/char/nvram 0x9ce3f83f nvram_write_byte +EXPORT_SYMBOL drivers/char/nvram 0xa8813189 __nvram_write_byte +EXPORT_SYMBOL drivers/cpufreq/cpufreq_conservative 0xa356038f cpufreq_gov_conservative +EXPORT_SYMBOL drivers/cpufreq/cpufreq_ondemand 0x83a131ed cpufreq_gov_ondemand +EXPORT_SYMBOL drivers/cpufreq/cpufreq_powersave 0x26d1a0fb cpufreq_gov_powersave +EXPORT_SYMBOL drivers/cpufreq/cpufreq_userspace 0xa6424238 cpufreq_gov_userspace +EXPORT_SYMBOL drivers/edac/edac_core 0x2cdfe8b4 edac_mc_handle_fbd_ue +EXPORT_SYMBOL drivers/edac/edac_core 0x4979f705 edac_mc_handle_fbd_ce +EXPORT_SYMBOL drivers/edac/edac_core 0x7925b30d edac_mc_find +EXPORT_SYMBOL drivers/gpu/drm/drm 0x0062ca55 drm_agp_free +EXPORT_SYMBOL drivers/gpu/drm/drm 0x02739ced drm_core_ioremapfree +EXPORT_SYMBOL drivers/gpu/drm/drm 0x05ce20f3 drm_release +EXPORT_SYMBOL drivers/gpu/drm/drm 0x0836695c drm_sman_takedown +EXPORT_SYMBOL drivers/gpu/drm/drm 0x0e2fe47c drm_exit +EXPORT_SYMBOL drivers/gpu/drm/drm 0x20645642 drm_debug +EXPORT_SYMBOL drivers/gpu/drm/drm 0x21451ac4 drm_sman_owner_cleanup +EXPORT_SYMBOL drivers/gpu/drm/drm 0x254a43b2 drm_i_have_hw_lock +EXPORT_SYMBOL drivers/gpu/drm/drm 0x2916bf63 drm_sman_cleanup +EXPORT_SYMBOL drivers/gpu/drm/drm 0x2eb2f903 drm_sman_free_key +EXPORT_SYMBOL drivers/gpu/drm/drm 0x3074f033 drm_order +EXPORT_SYMBOL drivers/gpu/drm/drm 0x31d7bd80 drm_open +EXPORT_SYMBOL drivers/gpu/drm/drm 0x37e02ea6 drm_core_ioremap_wc +EXPORT_SYMBOL drivers/gpu/drm/drm 0x3ddbbe6a drm_agp_bind +EXPORT_SYMBOL drivers/gpu/drm/drm 0x48bc65f1 drm_get_drawable_info +EXPORT_SYMBOL drivers/gpu/drm/drm 0x55f060ee drm_sman_set_range +EXPORT_SYMBOL drivers/gpu/drm/drm 0x584c3c83 drm_idlelock_take +EXPORT_SYMBOL drivers/gpu/drm/drm 0x6704672a drm_ati_pcigart_cleanup +EXPORT_SYMBOL drivers/gpu/drm/drm 0x69f1af39 drm_poll +EXPORT_SYMBOL drivers/gpu/drm/drm 0x6cd97bcd drm_agp_release +EXPORT_SYMBOL drivers/gpu/drm/drm 0x6ceb1d5b drm_addbufs_pci +EXPORT_SYMBOL drivers/gpu/drm/drm 0x8e89ef50 drm_agp_unbind +EXPORT_SYMBOL drivers/gpu/drm/drm 0x969615d3 drm_agp_info +EXPORT_SYMBOL drivers/gpu/drm/drm 0x9a59f4aa drm_core_ioremap +EXPORT_SYMBOL drivers/gpu/drm/drm 0x9c25b192 drm_core_get_map_ofs +EXPORT_SYMBOL drivers/gpu/drm/drm 0xac39f996 drm_addmap +EXPORT_SYMBOL drivers/gpu/drm/drm 0xacf9a808 drm_idlelock_release +EXPORT_SYMBOL drivers/gpu/drm/drm 0xad2d971a drm_get_resource_start +EXPORT_SYMBOL drivers/gpu/drm/drm 0xaf29788e drm_sman_init +EXPORT_SYMBOL drivers/gpu/drm/drm 0xafdfbcc7 drm_getsarea +EXPORT_SYMBOL drivers/gpu/drm/drm 0xb5d8bfe6 drm_get_resource_len +EXPORT_SYMBOL drivers/gpu/drm/drm 0xb73671fc drm_core_reclaim_buffers +EXPORT_SYMBOL drivers/gpu/drm/drm 0xb7c83dbe drm_vbl_send_signals +EXPORT_SYMBOL drivers/gpu/drm/drm 0xb980c369 drm_agp_enable +EXPORT_SYMBOL drivers/gpu/drm/drm 0xbcd4c6fb drm_pci_alloc +EXPORT_SYMBOL drivers/gpu/drm/drm 0xbf0c8a52 drm_mmap +EXPORT_SYMBOL drivers/gpu/drm/drm 0xc532d756 drm_agp_acquire +EXPORT_SYMBOL drivers/gpu/drm/drm 0xc67e258f drm_fasync +EXPORT_SYMBOL drivers/gpu/drm/drm 0xcc275c3e drm_rmmap +EXPORT_SYMBOL drivers/gpu/drm/drm 0xcc40780f drm_core_get_reg_ofs +EXPORT_SYMBOL drivers/gpu/drm/drm 0xcf090a90 drm_sg_alloc +EXPORT_SYMBOL drivers/gpu/drm/drm 0xd3028e75 drm_sman_set_manager +EXPORT_SYMBOL drivers/gpu/drm/drm 0xdcdd7fb1 drm_ati_pcigart_init +EXPORT_SYMBOL drivers/gpu/drm/drm 0xdd802693 drm_agp_alloc +EXPORT_SYMBOL drivers/gpu/drm/drm 0xe2f42105 drm_pci_free +EXPORT_SYMBOL drivers/gpu/drm/drm 0xe7e6f71c drm_locked_tasklet +EXPORT_SYMBOL drivers/gpu/drm/drm 0xe919dd5c drm_sman_owner_clean +EXPORT_SYMBOL drivers/gpu/drm/drm 0xefcb0736 drm_addbufs_agp +EXPORT_SYMBOL drivers/gpu/drm/drm 0xf023faba drm_init +EXPORT_SYMBOL drivers/gpu/drm/drm 0xf6462f01 drm_ioctl +EXPORT_SYMBOL drivers/gpu/drm/drm 0xf89bb4fe drm_irq_uninstall +EXPORT_SYMBOL drivers/gpu/drm/drm 0xfdfbad19 drm_sman_alloc +EXPORT_SYMBOL drivers/hwmon/hwmon-vid 0x0903c239 vid_from_reg +EXPORT_SYMBOL drivers/hwmon/hwmon-vid 0xef1c781c vid_which_vrm +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-bit 0x6404efdd i2c_bit_add_bus +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-bit 0x8afa3ed8 i2c_bit_add_numbered_bus +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-pca 0x5ff8b8c8 i2c_pca_add_bus +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-pca 0xfe2d64fa i2c_pca_add_numbered_bus +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-pcf 0x71113f9e i2c_pcf_add_bus +EXPORT_SYMBOL drivers/i2c/busses/i2c-amd756 0xae51c670 amd756_smbus +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0x02d4ad0f tps65013_set_low_pwr +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0x28485130 tps65010_config_vregs1 +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0x33739de7 tps65010_set_vib +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0x9fd44c69 tps65010_set_led +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0xb14080cc tps65010_set_low_pwr +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0xd5bb106d tps65010_set_vbus_draw +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0xe99b3f36 tps65010_set_gpio_out_value +EXPORT_SYMBOL drivers/i2c/i2c-core 0x1c0f85bd i2c_del_driver +EXPORT_SYMBOL drivers/i2c/i2c-core 0x1c9c1b85 i2c_master_send +EXPORT_SYMBOL drivers/i2c/i2c-core 0x1d0ad6f4 i2c_add_adapter +EXPORT_SYMBOL drivers/i2c/i2c-core 0x21eff101 i2c_clients_command +EXPORT_SYMBOL drivers/i2c/i2c-core 0x24f6c70d i2c_smbus_write_byte +EXPORT_SYMBOL drivers/i2c/i2c-core 0x265b13ed i2c_verify_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0x360883ef i2c_put_adapter +EXPORT_SYMBOL drivers/i2c/i2c-core 0x36a8606d i2c_release_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0x4f82d424 i2c_probe +EXPORT_SYMBOL drivers/i2c/i2c-core 0x52009339 i2c_smbus_write_i2c_block_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0x53d78f5a i2c_smbus_read_byte_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0x55a38702 i2c_register_driver +EXPORT_SYMBOL drivers/i2c/i2c-core 0x69a3d163 i2c_get_adapter +EXPORT_SYMBOL drivers/i2c/i2c-core 0x794e2054 i2c_smbus_read_block_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0x868fcdbc i2c_smbus_xfer +EXPORT_SYMBOL drivers/i2c/i2c-core 0x9aa4bed9 i2c_smbus_write_word_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0xa19ec298 i2c_del_adapter +EXPORT_SYMBOL drivers/i2c/i2c-core 0xa8b6f879 i2c_detach_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0xb4725c32 i2c_master_recv +EXPORT_SYMBOL drivers/i2c/i2c-core 0xb7febf1c i2c_smbus_read_word_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0xc03d6847 i2c_smbus_read_i2c_block_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0xd065fa59 i2c_smbus_read_byte +EXPORT_SYMBOL drivers/i2c/i2c-core 0xdfac00fe i2c_attach_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0xe0df60a2 i2c_use_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0xf1e1f6ba i2c_smbus_write_block_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0xf3cc92ed i2c_smbus_write_byte_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0xff6f84d0 i2c_transfer +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0b234c4e dma_prog_region_alloc +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0c6da941 csr1212_release_keyval +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0c703544 hpsb_resume_host +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0db4c882 hpsb_packet_received +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0e5a659c csr1212_new_directory +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x12fe12f1 hpsb_make_lock64packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x13b4a268 csr1212_attach_keyval_to_directory +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x158ac548 dma_region_offset_to_bus +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x1b5d3914 hpsb_selfid_received +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x1d435466 hpsb_update_config_rom_image +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x1df231b2 hpsb_iso_stop +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x2155e4d8 hpsb_make_writepacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x24994d7a hpsb_packet_sent +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x2626d4b2 hpsb_add_host +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x2752b9a8 csr1212_get_keyval +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x2ab6c1be hpsb_create_hostinfo +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x2ebf6e5a dma_prog_region_init +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x36a37419 hpsb_free_tlabel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x37a736c9 csr1212_read +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x39f11b94 hpsb_reset_bus +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x3f378984 hpsb_register_highlevel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x418b6896 hpsb_alloc_host +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x42a37443 hpsb_iso_recv_listen_channel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x448b9348 hpsb_iso_wake +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x48edc09e hpsb_send_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x4a2efae3 hpsb_iso_recv_unlisten_channel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x4edcc647 hpsb_get_hostinfo +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x50289517 hpsb_free_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x5424ee7d hpsb_set_hostinfo_key +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x5477a00d hpsb_unregister_highlevel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x590bd11a hpsb_iso_n_ready +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x5bb79dd1 hpsb_read +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x60c47843 hpsb_get_tlabel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x62b97c0d hpsb_unregister_addrspace +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x672ad148 dma_region_sync_for_device +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x6f961f18 hpsb_allocate_and_register_addrspace +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x6fd7d622 hpsb_remove_host +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x7046e886 csr1212_parse_keyval +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x70c443cd hpsb_set_hostinfo +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x76bc1a5c dma_region_free +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x80f29bb0 hpsb_selfid_complete +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x8269207d hpsb_make_readpacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x8300e879 hpsb_read_cycle_timer +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x83609b03 hpsb_update_config_rom +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x846d05b6 hpsb_iso_xmit_start +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x852b9095 hpsb_make_lockpacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x8879f8f0 dma_region_sync_for_cpu +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x8ec2b312 dma_region_alloc +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x93bb3c46 hpsb_iso_recv_flush +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x955fa1e7 hpsb_iso_recv_start +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x95a09282 __hpsb_register_protocol +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x9d1056ed hpsb_node_write +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xa5a119ab hpsb_register_addrspace +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xa67376b2 hpsb_get_hostinfo_bykey +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xacb3d53d hpsb_make_streampacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xaddf7dc4 hpsb_set_packet_complete_task +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xb0931dd5 hpsb_iso_xmit_queue_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xb18ac27d hpsb_iso_xmit_init +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xb1badbc5 hpsb_unregister_protocol +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xb47bd9d2 hpsb_node_fill_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xb60dc4dc hpsb_iso_xmit_sync +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xbf885f7d hpsb_iso_packet_received +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xc18c8006 hpsb_bus_reset +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xc301e746 hpsb_write +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xc453be1c dma_region_mmap +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xc460131a hpsb_iso_recv_release_packets +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xc6198a1f hpsb_protocol_class +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xc65eed6f hpsb_iso_recv_init +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xc669a4d3 csr1212_detach_keyval_from_directory +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xcd9e772b dma_prog_region_free +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xd0adccf9 hpsb_destroy_hostinfo +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xdb18fe0b hpsb_packet_success +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xe394c983 hpsb_iso_recv_set_channel_mask +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xe3c572b0 hpsb_iso_packet_sent +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xe5067352 hpsb_iso_shutdown +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xea4152ff dma_region_init +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xeb0768d4 hpsb_alloc_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xf5185ce1 hpsb_make_phypacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xfba57f51 hpsb_speedto_str +EXPORT_SYMBOL drivers/ieee1394/ohci1394 0x6b084905 ohci1394_unregister_iso_tasklet +EXPORT_SYMBOL drivers/ieee1394/ohci1394 0xb37ab086 ohci1394_init_iso_tasklet +EXPORT_SYMBOL drivers/ieee1394/ohci1394 0xce6a8385 ohci1394_stop_context +EXPORT_SYMBOL drivers/ieee1394/ohci1394 0xddc8beeb ohci1394_register_iso_tasklet +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0x0cb7d858 rdma_resolve_ip +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0x186d6113 rdma_copy_addr +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0x4de32379 rdma_translate_ip +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0x6d95e179 rdma_addr_cancel +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0x71de06c2 rdma_addr_register_client +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0xbe81bb46 rdma_addr_unregister_client +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x236621f2 ib_send_cm_req +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x2443c78a ib_send_cm_lap +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x25903507 ib_cm_listen +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x267b63d8 ib_send_cm_rtu +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x4ba401de ib_create_cm_id +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x61ad2300 ib_send_cm_mra +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x6e8cdb50 ib_send_cm_sidr_rep +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x8786646b ib_send_cm_dreq +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x87d4324d ib_cm_notify +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x89cceab6 ib_send_cm_drep +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x9cebc455 ib_send_cm_apr +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0xb10fb0fa ib_cm_init_qp_attr +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0xc77a2671 ib_send_cm_sidr_req +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0xc7eeadd2 ib_send_cm_rep +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0xcbf0450f ib_send_cm_rej +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0xd401b020 cm_class +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0xf263fd58 ib_destroy_cm_id +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x06532d82 ib_alloc_mw +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x0924d0cf ib_alloc_fast_reg_page_list +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x0ce2082a ib_query_gid +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x1260a569 ib_query_ah +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x1a7a43e8 ib_flush_fmr_pool +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x1e491a04 ib_unmap_fmr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x21098589 ib_create_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x23eb1835 ib_modify_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x26788ca7 ib_find_gid +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x28479567 ib_dealloc_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x2bacca82 ib_create_ah_from_wc +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x2eef17f7 ib_find_cached_pkey +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x345f0083 ib_detach_mcast +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x357d6bd8 ib_alloc_pd +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x362e7796 ib_destroy_cq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x395ccc4f ib_modify_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x3af0c5ee ib_find_pkey +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x3eea4e2c ib_destroy_fmr_pool +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x3f7567fd ib_rate_to_mult +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x44b3ed7f ib_query_srq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x4929164f ib_modify_ah +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x4c5def16 ib_create_srq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x4dd5a08f ib_umem_get +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x520b2638 ib_pack +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x5bd945dc ib_alloc_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x5def6673 ib_register_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x63230df6 ib_query_pkey +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x6426747c ib_unregister_event_handler +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x65d169a5 ib_dealloc_mw +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x66f33ef6 ib_destroy_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x68bdc6a3 ib_register_event_handler +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x6bc91d5a ib_create_fmr_pool +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x6c10e679 ib_query_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x75298f08 ib_modify_srq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x7b5e152b ib_alloc_fast_reg_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x7e368d4f ib_register_client +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x7f91c819 ib_query_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x8640eaeb ib_modify_qp_is_ok +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x8742cc90 ib_init_ah_from_wc +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x87b614d8 ib_ud_header_pack +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x8b175730 ib_umem_release +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x8c24b3a9 ib_get_cached_pkey +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x909c4fb4 ib_destroy_srq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x9396b865 ib_query_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x96ce6c46 rdma_node_get_transport +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x98fbb6ca ib_reg_phys_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x9d08a088 ib_unregister_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x9d804fa1 mult_to_ib_rate +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x9ee17103 ib_free_fast_reg_page_list +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xa2ed04d6 ib_resize_cq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xb1a312e1 ib_unpack +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xb3f56ba4 ib_find_cached_gid +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xb7cc0d63 ib_get_cached_lmc +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xbe9ffe40 ib_fmr_pool_map_phys +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xbf47ed12 ib_get_cached_gid +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xcf9f4538 ib_get_client_data +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xd17ba9d1 ib_ud_header_init +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xd3f2f398 ib_rereg_phys_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xd4fa10a1 ib_modify_port +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xd5c4672a ib_set_client_data +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xd815c0cc ib_attach_mcast +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xdc409c00 ib_fmr_pool_unmap +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xdf777f4e ib_alloc_fmr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xe0ac7923 ib_create_ah +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xe0d3cc87 ib_unregister_client +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xe14aeffd ib_create_cq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xe84a1b0d ib_get_dma_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xec234524 ib_umem_page_count +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf0cd4236 ib_dereg_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf26aa560 ib_dealloc_fmr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf36498b9 ib_ud_header_unpack +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf3970ec8 ib_query_port +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf57d99ae ib_modify_cq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf6a5fabc ib_dispatch_event +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf8860d68 ib_destroy_ah +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xffb64290 ib_dealloc_pd +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x085faafd ib_redirect_mad_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x13b242ae ib_cancel_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x215ab834 ib_get_rmpp_segment +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x67e24293 ib_modify_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x6cc3d7ac ib_free_recv_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x6ef787ed ib_response_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x6f077fcf ib_get_mad_data_offset +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x732afafa ib_free_send_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x7338290d ib_process_mad_wc +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x7b5d4b7a ib_is_mad_class_rmpp +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x8ea605c8 ib_create_send_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0xb5c70139 ib_post_send_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0xc12d8d71 ib_register_mad_snoop +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0xd8c312a6 ib_register_mad_agent +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0xe05d0de8 ib_unregister_mad_agent +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x0c9f6475 ib_sa_path_rec_get +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x16199856 ib_sa_register_client +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x512ba124 ib_sa_unregister_client +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x576fdbac ib_sa_free_multicast +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x5f7c13fc ib_init_ah_from_path +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x78ceb160 ib_init_ah_from_mcmember +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x9b4ebfa8 ib_sa_service_rec_query +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0xac55f564 ib_sa_get_mcmember_rec +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0xfc92afb7 ib_sa_join_multicast +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0xfddb508e ib_sa_cancel_query +EXPORT_SYMBOL drivers/infiniband/core/ib_uverbs 0x02f847bc ib_copy_path_rec_from_user +EXPORT_SYMBOL drivers/infiniband/core/ib_uverbs 0x07cf5a51 ib_copy_ah_attr_to_user +EXPORT_SYMBOL drivers/infiniband/core/ib_uverbs 0x18382f6a ib_copy_path_rec_to_user +EXPORT_SYMBOL drivers/infiniband/core/ib_uverbs 0x184f3575 ib_copy_qp_attr_to_user +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x422cfe14 iw_cm_accept +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x52243850 iw_destroy_cm_id +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x70cc1574 iw_cm_init_qp_attr +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x781079f9 iw_cm_listen +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x7dc149f3 iw_create_cm_id +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x83349df6 iw_cm_reject +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x972f05a0 iw_cm_disconnect +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0xa81dd57c iw_cm_connect +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x3dfe9aed rdma_resolve_addr +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x5105cdff rdma_set_service_type +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x7293b181 rdma_create_qp +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x98fba5df rdma_connect +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x9f643e06 rdma_reject +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xa7dbbcaf rdma_leave_multicast +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xac75266c rdma_destroy_qp +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xaecea954 rdma_listen +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xb3fe9f56 rdma_accept +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xb9226db5 rdma_notify +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xbde8c11d rdma_join_multicast +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xbf3e09d5 rdma_resolve_route +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xccb3d40e rdma_set_ib_paths +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xd118803a rdma_destroy_id +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xdc939548 rdma_init_qp_attr +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xee406f41 rdma_disconnect +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xf28ed69d rdma_bind_addr +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xf6348bcc rdma_create_id +EXPORT_SYMBOL drivers/input/gameport/gameport 0x155040b2 gameport_unregister_port +EXPORT_SYMBOL drivers/input/gameport/gameport 0x335f8f50 __gameport_register_driver +EXPORT_SYMBOL drivers/input/gameport/gameport 0x3679cc73 gameport_set_phys +EXPORT_SYMBOL drivers/input/gameport/gameport 0x537ac582 __gameport_register_port +EXPORT_SYMBOL drivers/input/gameport/gameport 0x9686db78 gameport_close +EXPORT_SYMBOL drivers/input/gameport/gameport 0x9885d528 gameport_start_polling +EXPORT_SYMBOL drivers/input/gameport/gameport 0xa7024bcc gameport_open +EXPORT_SYMBOL drivers/input/gameport/gameport 0xe413db8a gameport_stop_polling +EXPORT_SYMBOL drivers/input/gameport/gameport 0xf868c35a gameport_unregister_driver +EXPORT_SYMBOL drivers/input/input-polldev 0x5cb4df01 input_unregister_polled_device +EXPORT_SYMBOL drivers/input/input-polldev 0x5e955ebd input_free_polled_device +EXPORT_SYMBOL drivers/input/input-polldev 0x85b02d76 input_allocate_polled_device +EXPORT_SYMBOL drivers/input/input-polldev 0xd2030fb3 input_register_polled_device +EXPORT_SYMBOL drivers/isdn/capi/capifs 0x2c54c957 capifs_free_ncci +EXPORT_SYMBOL drivers/isdn/capi/capifs 0xd0bc06ce capifs_new_ncci +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x04403fcf unregister_capi_driver +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x14f2aa5a capi20_get_version +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x189f0602 detach_capi_ctr +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x2b6c8b05 capi_ctr_resume_output +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x2b8eab1f capilib_free_ncci +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x2baa6586 capilib_new_ncci +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x31c24aa4 capi20_isinstalled +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x47d3fc51 capi_info2str +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x50b33ca4 capi_cmsg2message +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x6057c6f3 capi_message2cmsg +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x62e32d43 capilib_data_b3_conf +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x6f471c81 capi_ctr_handle_message +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x71e8d5ba capilib_data_b3_req +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x7a33596c capi20_get_serial +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x7e6f1307 capi20_get_manufacturer +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x8132582f capi_ctr_reseted +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x8e422e7f capi20_release +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x8f699913 capilib_release +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x9f823278 register_capi_driver +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xa7c4fd6c capi_message2str +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xaa165d27 capilib_release_appl +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xac67f4e1 capi20_register +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xb19fda8d capi_cmd2str +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xb60e5e5f capi_cmsg_header +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xbc795c59 capi20_put_message +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xc10fe128 cdebbuf_free +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xda5e8176 attach_capi_ctr +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xe19a11ac capi20_get_profile +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xe1d80a79 capi_ctr_ready +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xe4c07306 capi_ctr_suspend_output +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xe8ad9bd1 capi_cmsg2str +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xed061606 capi20_manufacturer +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xfad5ab53 capi20_set_callback +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x022d7990 b1_free_card +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x1f103e45 b1_load_firmware +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x30225ffc b1_load_t4file +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x3049e777 b1_reset_ctr +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x49a9a940 b1ctl_read_proc +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x635041c6 b1_getrevision +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x6528cb04 b1_loaded +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x72c3922d b1_register_appl +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x85f09690 b1_irq_table +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x8cc20ab4 b1_alloc_card +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x96f9d2f4 b1_interrupt +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x9a17c7cb b1_send_message +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xa8042e0a avmcard_dma_free +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xa8de9c3f b1_release_appl +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xb0a0a974 b1_load_config +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xd4cf174a avmcard_dma_alloc +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xdfd28376 b1_detect +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xe91f7c60 b1_parse_version +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x2a386384 b1dma_interrupt +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x2ee32b21 b1dma_send_message +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x37c50e7a b1dma_reset +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x3d72422b b1dma_release_appl +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x60b51416 b1dma_reset_ctr +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x62687b24 b1dma_register_appl +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x6f9e3970 b1dma_load_firmware +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x9b9f5522 b1pciv4_detect +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0xa148e62f t1pci_detect +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0xfa1c0c5b b1dmactl_read_proc +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1pcmcia 0x29562993 b1pcmcia_delcard +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1pcmcia 0xaec3240e b1pcmcia_addcard_m1 +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1pcmcia 0xea620116 b1pcmcia_addcard_m2 +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1pcmcia 0xf14bf8b1 b1pcmcia_addcard_b1 +EXPORT_SYMBOL drivers/isdn/hardware/eicon/divadidd 0x2974ead1 DIVA_DIDD_Read +EXPORT_SYMBOL drivers/isdn/hardware/eicon/divadidd 0x2a2406c3 proc_net_eicon +EXPORT_SYMBOL drivers/isdn/hardware/mISDN/hfcmulti 0x5293ed86 plx_lock +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x07f4f2ce hisax_unregister +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x138d887b hisax_init_pcmcia +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x148f0c99 FsmFree +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x2844a899 FsmInitTimer +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x93a64734 FsmChangeState +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x9df0cd27 FsmEvent +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xc0c558f9 FsmRestartTimer +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xd94696e8 FsmDelTimer +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xee93522c hisax_register +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xf0a16657 FsmNew +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xfc27303b HiSax_closecard +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0x1e7d5dd0 isacsx_irq +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0x36dceee8 isacsx_setup +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0x3ec3a822 isac_init +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0x3f3b323a isac_d_l2l1 +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0xe5029528 isac_setup +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0xfc7b179d isac_irq +EXPORT_SYMBOL drivers/isdn/hisax/isdnhdlc 0x1ee629e2 isdnhdlc_rcv_init +EXPORT_SYMBOL drivers/isdn/hisax/isdnhdlc 0x95aed401 isdnhdlc_decode +EXPORT_SYMBOL drivers/isdn/hisax/isdnhdlc 0x9ffc8215 isdnhdlc_out_init +EXPORT_SYMBOL drivers/isdn/hisax/isdnhdlc 0xf5c8131d isdnhdlc_encode +EXPORT_SYMBOL drivers/isdn/i4l/isdn 0x0a59a06c register_isdn +EXPORT_SYMBOL drivers/isdn/i4l/isdn 0xb2e721db isdn_ppp_register_compressor +EXPORT_SYMBOL drivers/isdn/i4l/isdn 0xc51dd74e isdn_ppp_unregister_compressor +EXPORT_SYMBOL drivers/isdn/i4l/isdn 0xfa06820f isdn_register_divert +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x09e86807 l1_event +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x2348cc3c mISDN_FsmFree +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x38723ed2 recv_Bchannel_skb +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x3a6e3cc4 mISDN_register_Bprotocol +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x3ea336fd mISDN_FsmAddTimer +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x429129f2 mISDN_FsmRestartTimer +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x4d38d767 create_l1 +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x50c2230c mISDN_FsmChangeState +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x5698c95c mISDN_freebchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x589d1bc9 queue_ch_frame +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x593b6b5e mISDN_initdchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x678d21c3 get_next_bframe +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x7a44334d mISDN_register_device +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x9e2e4d07 recv_Bchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xa8203663 mISDN_unregister_device +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xab62bb97 recv_Dchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xace35cae mISDN_FsmDelTimer +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xcf727108 mISDN_freedchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xd2c9523b bchannel_senddata +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xd36ba2c9 recv_Dchannel_skb +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xd5145151 mISDN_FsmEvent +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xd8c180e8 confirm_Bsend +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xd9a7fbfd mISDN_FsmInitTimer +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xdc7b5f2a dchannel_senddata +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xdeb1fed5 get_next_dframe +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xe3c37271 mISDN_initbchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xea95590c mISDN_unregister_Bprotocol +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xf9e7832f mISDN_FsmNew +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_dsp 0x4c2ec443 mISDN_dsp_element_register +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_dsp 0x60721da7 dsp_audio_law_to_s32 +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_dsp 0xa215f1b2 dsp_audio_s16_to_law +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_dsp 0xd3a023b8 mISDN_dsp_element_unregister +EXPORT_SYMBOL drivers/md/dm-log 0x06a77207 dm_dirty_log_create +EXPORT_SYMBOL drivers/md/dm-log 0x197b5fd9 dm_dirty_log_destroy +EXPORT_SYMBOL drivers/md/dm-log 0x43af940d dm_dirty_log_type_unregister +EXPORT_SYMBOL drivers/md/dm-log 0xd2f42257 dm_dirty_log_type_register +EXPORT_SYMBOL drivers/md/dm-mod 0x0043cbad dm_table_get_size +EXPORT_SYMBOL drivers/md/dm-mod 0x03a7fb6c dm_table_put +EXPORT_SYMBOL drivers/md/dm-mod 0x07e17cbb dm_table_get +EXPORT_SYMBOL drivers/md/dm-mod 0x0c7642b3 dm_get_device +EXPORT_SYMBOL drivers/md/dm-mod 0x0f8aef14 dm_table_unplug_all +EXPORT_SYMBOL drivers/md/dm-mod 0x11725300 dm_table_get_md +EXPORT_SYMBOL drivers/md/dm-mod 0x1a1d7bed dm_io_client_create +EXPORT_SYMBOL drivers/md/dm-mod 0x2350fc47 dm_register_target +EXPORT_SYMBOL drivers/md/dm-mod 0x4135252a dm_get_mapinfo +EXPORT_SYMBOL drivers/md/dm-mod 0x580a59ab dm_io +EXPORT_SYMBOL drivers/md/dm-mod 0x6f63cdc2 dm_put_device +EXPORT_SYMBOL drivers/md/dm-mod 0x70a6be98 dm_kcopyd_copy +EXPORT_SYMBOL drivers/md/dm-mod 0x82f65633 dm_io_client_resize +EXPORT_SYMBOL drivers/md/dm-mod 0x921c020b dm_table_get_mode +EXPORT_SYMBOL drivers/md/dm-mod 0x928b1b3f dm_table_event +EXPORT_SYMBOL drivers/md/dm-mod 0x954c8af3 dm_io_client_destroy +EXPORT_SYMBOL drivers/md/dm-mod 0xc6dd63e2 dm_kcopyd_client_create +EXPORT_SYMBOL drivers/md/dm-mod 0xc79bcd36 dm_vcalloc +EXPORT_SYMBOL drivers/md/dm-mod 0xc81c8453 dm_unregister_target +EXPORT_SYMBOL drivers/md/dm-mod 0xe5cb1395 dm_kcopyd_client_destroy +EXPORT_SYMBOL drivers/md/md-mod 0x1ab98a6b md_wakeup_thread +EXPORT_SYMBOL drivers/md/md-mod 0x2d15a9d9 bitmap_cond_end_sync +EXPORT_SYMBOL drivers/md/md-mod 0x39586236 bitmap_endwrite +EXPORT_SYMBOL drivers/md/md-mod 0x41e8c0cb register_md_personality +EXPORT_SYMBOL drivers/md/md-mod 0x539254c1 md_wait_for_blocked_rdev +EXPORT_SYMBOL drivers/md/md-mod 0x5ba063bc md_write_start +EXPORT_SYMBOL drivers/md/md-mod 0x6f94d12b bitmap_close_sync +EXPORT_SYMBOL drivers/md/md-mod 0x76e22927 unregister_md_personality +EXPORT_SYMBOL drivers/md/md-mod 0x85adcbcc bitmap_start_sync +EXPORT_SYMBOL drivers/md/md-mod 0x8fe25c07 md_done_sync +EXPORT_SYMBOL drivers/md/md-mod 0xa06d9335 bitmap_end_sync +EXPORT_SYMBOL drivers/md/md-mod 0xa33170d2 md_error +EXPORT_SYMBOL drivers/md/md-mod 0xcb2de3f8 bitmap_startwrite +EXPORT_SYMBOL drivers/md/md-mod 0xd482df3e md_unregister_thread +EXPORT_SYMBOL drivers/md/md-mod 0xd60bdd70 bitmap_unplug +EXPORT_SYMBOL drivers/md/md-mod 0xf0df1e2c md_write_end +EXPORT_SYMBOL drivers/md/md-mod 0xf12f2505 md_check_recovery +EXPORT_SYMBOL drivers/md/md-mod 0xf660f0d3 md_register_thread +EXPORT_SYMBOL drivers/media/common/tuners/mt2060 0x667fef94 mt2060_attach +EXPORT_SYMBOL drivers/media/common/tuners/mt2131 0x9043b28a mt2131_attach +EXPORT_SYMBOL drivers/media/common/tuners/mt2266 0xc0906546 mt2266_attach +EXPORT_SYMBOL drivers/media/common/tuners/mxl5005s 0xba94ae59 mxl5005s_attach +EXPORT_SYMBOL drivers/media/common/tuners/qt1010 0xc591cef5 qt1010_attach +EXPORT_SYMBOL drivers/media/common/tuners/tuner-types 0x0cb4b189 tuners +EXPORT_SYMBOL drivers/media/common/tuners/tuner-types 0xc2821775 tuner_count +EXPORT_SYMBOL drivers/media/common/tuners/tuner-xc2028 0xe54eaaeb xc2028_attach +EXPORT_SYMBOL drivers/media/common/tuners/xc5000 0x3e200c68 xc5000_attach +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x04436444 flexcop_device_kmalloc +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x1fa70900 flexcop_dma_free +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x2841629a flexcop_dma_control_size_irq +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x4877fbb3 flexcop_device_kfree +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x4ad509d7 flexcop_sram_set_dest +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x76ad1118 flexcop_dma_control_timer_irq +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x83a6c8d1 flexcop_pass_dmx_data +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x910e42a2 flexcop_i2c_request +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xa8ca9b28 flexcop_dump_reg +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xabc98bab flexcop_eeprom_check_mac_addr +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xb6e70241 flexcop_dma_xfer_control +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xc811afdf flexcop_device_initialize +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xdf38b620 flexcop_sram_ctrl +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xe21a190d flexcop_dma_config +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xe6e28b50 flexcop_wan_set_speed +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xeddea287 flexcop_dma_config_timer +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xf1f03d48 flexcop_dma_allocate +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xf85624ca flexcop_pass_dmx_packets +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xfa21477a flexcop_device_exit +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0x30df43ed bt878_start +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0xb03b86c9 bt878_device_control +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0xbb74fc90 bt878 +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0xd5d0bdef bt878_num +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0xdb076ffd bt878_stop +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x33ab562b rdc_reset_state +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x4a4141db dst_error_bailout +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x5d949553 dst_attach +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x9220984e read_dst +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x9b76e7e1 dst_wait_dst_ready +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x9f914769 dst_error_recovery +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0xa391fc3b write_dst +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0xabfaf783 dst_pio_disable +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0xb44d85ea dst_comm_init +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0xe94b8c9c dst_check_sum +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst_ca 0xf4deec29 dst_ca_attach +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x14eb630c dvb_ringbuffer_free +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x1dff9e1b dvb_unregister_device +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x21a0b107 dvb_ca_en50221_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x36c8ea1f dvb_frontend_sleep_until +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x3ba3130c dvb_unregister_adapter +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x44e7f443 dvb_ca_en50221_camchange_irq +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x4f5f92fb dvb_ca_en50221_frda_irq +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x5edd1770 dvb_dmxdev_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x635eb40e dvb_dmx_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x664aa71d dvb_ca_en50221_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x6f7f7d73 dvb_ringbuffer_empty +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x6f9c72e3 dvb_ringbuffer_read +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x74a5a698 dvb_filter_pes2ts_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x79526a3a dvb_frontend_reinitialise +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x798c8b4d dvb_net_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x80e3832d dvb_filter_get_ac3info +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x879e1f21 dvb_register_device +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x8b49a23f timeval_usec_diff +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x8bb5a37e dvb_register_adapter +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x9205235d dvb_generic_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x923aa88e dvb_ringbuffer_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x9cbff999 dvb_dmx_swfilter_204 +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xa26e3405 dvb_ca_en50221_camready_irq +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xac4ca1b0 intlog2 +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xad674883 dvb_net_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xb1d5f332 dvb_register_frontend +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xb2db2592 dvb_ringbuffer_write +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xb56f0404 dvb_dmx_swfilter_packets +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xb5b95805 dvb_ringbuffer_read_user +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xb6574870 dvb_unregister_frontend +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xbaa41dbf dvb_generic_ioctl +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xbed559e1 dvb_dmx_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xc938e566 dvb_dmx_swfilter +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xd27666a0 dvb_dmxdev_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xe5ae8707 intlog10 +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xe7949e59 dvb_ringbuffer_flush_spinlock_wakeup +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xeb7daf80 dvb_ringbuffer_avail +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xf3e9b0fe dvb_frontend_detach +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xf4ee93de dvb_generic_open +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xf826deb0 dvb_filter_pes2ts +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x2ec4b03a dvb_usb_device_exit +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x62ad06d1 dvb_usb_get_hexline +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x6e468eca dvb_usb_generic_rw +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0xbaaf7f0e dvb_usb_generic_write +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0xc7136c35 dvb_usb_nec_rc_key_to_event +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0xd0bdf454 usb_cypress_load_firmware +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0xd48e6d1d dvb_usb_device_init +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-af9005-remote 0x2edc4728 af9005_rc_keys +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-af9005-remote 0xbbbe28c4 af9005_rc_decode +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-af9005-remote 0xd3383957 af9005_rc_keys_size +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x0521a8a3 dibusb_power_ctrl +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x116e2c40 dibusb_dib3000mc_frontend_attach +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x12407f2f dibusb_streaming_ctrl +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x2be9364d dibusb2_0_streaming_ctrl +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x2cf0209d dibusb_i2c_algo +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x34238872 dibusb_rc_query +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x4154a8d6 dibusb_pid_filter +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x4db37e82 dibusb2_0_power_ctrl +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x9b883b55 dibusb_read_eeprom_byte +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x9d2388b6 dibusb_pid_filter_ctrl +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xc874a193 dibusb_dib3000mc_tuner_attach +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xd4d3dddc dibusb_rc_keys +EXPORT_SYMBOL drivers/media/dvb/frontends/au8522 0xdbf37369 au8522_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/bcm3510 0xa48d9571 bcm3510_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/cx22700 0xd597d00f cx22700_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/cx22702 0xf24341a0 cx22702_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/cx24110 0x5e7a7792 cx24110_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/cx24123 0x54d8f682 cx24123_get_tuner_i2c_adapter +EXPORT_SYMBOL drivers/media/dvb/frontends/cx24123 0xa3d82a41 cx24123_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib0070 0x3b3f7aa8 dib0070_wbd_offset +EXPORT_SYMBOL drivers/media/dvb/frontends/dib0070 0x5c94b332 dib0070_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mb 0xac43117d dib3000mb_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0x2b0907dd dib3000mc_set_config +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0x73dd9aef dib3000mc_pid_control +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0x89dec4dc dib3000mc_i2c_enumeration +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0xa51e4935 dib3000mc_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0xb9f6ab6f dib3000mc_get_tuner_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0xd83f7091 dib3000mc_pid_parse +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000m 0x6260d626 dib7000m_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000m 0x7eab2b46 dib7000m_get_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000m 0xe445d4ce dib7000m_i2c_enumeration +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0x2674b874 dib7000pc_detection +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0x54e38699 dib7000p_set_gpio +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0x550c8c83 dib7000p_set_wbd_ref +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0x7ac74b86 dib7000p_get_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0x89930cb9 dib7000p_i2c_enumeration +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0xf8c637e9 dib7000p_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dibx000_common 0x7b596fea dibx000_get_i2c_adapter +EXPORT_SYMBOL drivers/media/dvb/frontends/dibx000_common 0x8477ed4f dibx000_exit_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/dibx000_common 0xdaf5af2e dibx000_init_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/drx397xD 0x2487a81c drx397xD_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dvb-pll 0xc9a95639 dvb_pll_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/isl6405 0x57424da3 isl6405_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/isl6421 0xc0c2dcfe isl6421_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/itd1000 0x6e2f6229 itd1000_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/l64781 0x8fb81658 l64781_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/lgdt330x 0x281178b0 lgdt330x_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/lnbp21 0x67f74727 lnbp21_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/mt312 0x40e5538f mt312_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/mt352 0x87d5b45b mt352_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/nxt200x 0x0d3a3c75 nxt200x_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/nxt6000 0xc31fbd90 nxt6000_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/or51132 0xd29b6257 or51132_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/or51211 0x3d9b6dc0 or51211_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/s5h1409 0xe9db697c s5h1409_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/s5h1411 0x2e44a59f s5h1411_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/s5h1420 0x094f5980 s5h1420_get_tuner_i2c_adapter +EXPORT_SYMBOL drivers/media/dvb/frontends/s5h1420 0x877abd7d s5h1420_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/sp8870 0xc469ae51 sp8870_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/sp887x 0x277b9fcd sp887x_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/stv0297 0x551a4925 stv0297_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/stv0299 0x095f6fba stv0299_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda10021 0x49d5f293 tda10021_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda10023 0xae1e2bf8 tda10023_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda10048 0x6d79240b tda10048_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda1004x 0x0d6339e4 tda10046_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda1004x 0x7693c13e tda10045_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda10086 0x15c23d22 tda10086_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda8083 0x17eb2610 tda8083_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda826x 0xb997fc7a tda826x_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tua6100 0xa15fbf36 tua6100_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/ves1820 0x79d56f9e ves1820_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/ves1x93 0xc709350f ves1x93_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/zl10353 0xd5f14b8e zl10353_attach +EXPORT_SYMBOL drivers/media/dvb/ttpci/ttpci-eeprom 0x48359f1c ttpci_eeprom_parse_mac +EXPORT_SYMBOL drivers/media/dvb/ttusb-dec/ttusbdecfe 0x1ad99e84 ttusbdecfe_dvbt_attach +EXPORT_SYMBOL drivers/media/dvb/ttusb-dec/ttusbdecfe 0x311e9f4e ttusbdecfe_dvbs_attach +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0x08ed5683 bttv_sub_register +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0x0c0765f3 bttv_sub_unregister +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0x11dc4b6d bttv_gpio_enable +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0x378eadb7 bttv_get_pcidev +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0x8ecf4acc bttv_write_gpio +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0xbcf2d2fb bttv_read_gpio +EXPORT_SYMBOL drivers/media/video/btcx-risc 0x390acdb5 btcx_riscmem_free +EXPORT_SYMBOL drivers/media/video/btcx-risc 0x42c5244c btcx_riscmem_alloc +EXPORT_SYMBOL drivers/media/video/btcx-risc 0x495e4b0c btcx_calc_skips +EXPORT_SYMBOL drivers/media/video/btcx-risc 0xad2fe38b btcx_sort_clips +EXPORT_SYMBOL drivers/media/video/btcx-risc 0xc368f8e6 btcx_align +EXPORT_SYMBOL drivers/media/video/btcx-risc 0xcda0ded2 btcx_screen_clips +EXPORT_SYMBOL drivers/media/video/cpia 0x3e416540 cpia_unregister_camera +EXPORT_SYMBOL drivers/media/video/cpia 0xe0a68600 cpia_register_camera +EXPORT_SYMBOL drivers/media/video/cx18/cx18 0x2cdea06d cx18_reset_ir_gpio +EXPORT_SYMBOL drivers/media/video/cx2341x 0x0224a947 cx2341x_update +EXPORT_SYMBOL drivers/media/video/cx2341x 0x3559ba71 cx2341x_ext_ctrls +EXPORT_SYMBOL drivers/media/video/cx2341x 0x8fdbede1 cx2341x_fill_defaults +EXPORT_SYMBOL drivers/media/video/cx2341x 0xcf8b77a4 cx2341x_mpeg_ctrls +EXPORT_SYMBOL drivers/media/video/cx2341x 0xde1da524 cx2341x_ctrl_query +EXPORT_SYMBOL drivers/media/video/cx2341x 0xeacc6fab cx2341x_ctrl_get_menu +EXPORT_SYMBOL drivers/media/video/cx2341x 0xfb8bd71f cx2341x_log_status +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0x00bc6266 cx23885_video_mux +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0x36aab41f cx23885_set_control +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0x477e385c cx23885_get_control +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0xa660600f cx23885_set_freq +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0xe12fa84c cx23885_ctrl_query +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0xf0674a30 cx23885_enum_input +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0xfb885537 cx23885_user_ctrls +EXPORT_SYMBOL drivers/media/video/cx88/cx88-vp3054-i2c 0x12172e2f vp3054_i2c_remove +EXPORT_SYMBOL drivers/media/video/cx88/cx88-vp3054-i2c 0x14f69ceb vp3054_i2c_probe +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0x013e9102 cx88_enum_input +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0x06fcfa25 cx88_set_freq +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0x2a86df42 cx8800_ctrl_query +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0x5a0d53e1 cx88_get_control +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0x80870d23 cx88_video_mux +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0x90ee5aca cx88_set_control +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0xac4e53b9 cx88_user_ctrls +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x2c2d5037 cx8802_unregister_driver +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x38aa6b6b cx8802_get_driver +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x410533d5 cx8802_buf_queue +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x49f8e15e cx8802_register_driver +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x587b039d cx8802_cancel_buffers +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x81e0f225 cx8802_get_device +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0xc931de45 cx8802_buf_prepare +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x27c4f7d2 cx88_core_put +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x39c143e7 cx88_newstation +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x43b7d23d cx88_core_irq +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x4c263378 cx88_core_get +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x4cd52d5c cx88_sram_channel_setup +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x708c273e cx88_sram_channel_dump +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x7b5cdee1 cx88_tuner_callback +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x8ea1d561 cx88_wakeup +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x8ebdadec cx88_free_buffer +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x904b8696 cx88_audio_thread +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x92864249 cx88_risc_databuffer +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x960f8101 cx88_set_tvaudio +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x9b13d09d cx88_shutdown +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x9b140fff cx88_sram_channels +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x9cf99b5b cx88_vdev_init +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xa72a519c cx88_risc_buffer +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xb1f303bf cx88_set_scale +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xb47f6cda cx88_print_irqbits +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xb8ec905f cx88_ir_start +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xc09beda1 cx88_set_stereo +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xd9a9a7e0 cx88_get_stereo +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xe1e1b542 cx88_call_i2c_clients +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xf03c227d cx88_reset +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xf296e737 cx88_risc_stopper +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xf2aaf148 cx88_set_tvnorm +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xfecef318 cx88_ir_stop +EXPORT_SYMBOL drivers/media/video/em28xx/em28xx 0x4ea70ee5 em28xx_register_extension +EXPORT_SYMBOL drivers/media/video/em28xx/em28xx 0x987ff71e em28xx_unregister_extension +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x006bff29 gspca_suspend +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x7a8acbaf gspca_frame_add +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x9670af2c gspca_debug +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0xab747a85 gspca_disconnect +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0xc2312ba2 gspca_resume +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0xd5e9735a gspca_auto_gain_n_exposure +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0xe2a0baa2 gspca_dev_probe +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x0538e449 ivtv_cards_lock +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x14f67530 ivtv_debug +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x48ce9f98 ivtv_clear_irq_mask +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x5d1cb6d6 ivtv_init_on_first_open +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x624f57d1 ivtv_api +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x70196ffb ivtv_cards_active +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x77a2b881 ivtv_udma_alloc +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x81c758fd ivtv_vapi_result +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x99c7d0b8 ivtv_vapi +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x9ae1232d ivtv_reset_ir_gpio +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0xa96a0690 ivtv_udma_setup +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0xb3e7d798 ivtv_udma_unmap +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0xc8dd580e ivtv_udma_prepare +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0xdf96d38d ivtv_set_irq_mask +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0xf3e61d49 ivtv_cards +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x1211df5d saa7134_devlist +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x4817de34 saa7134_pgtable_build +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x587543ec saa7134_set_dmabits +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x642f3127 saa_dsp_writel +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x696a273f saa7134_ts_register +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x7c5804a7 saa7134_i2c_call_clients +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x7c61c69d saa7134_ts_unregister +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x85593767 saa7134_tuner_callback +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x962fbeb4 saa7134_dmasound_exit +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x98af79c1 saa7134_boards +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0xb25dffa7 saa7134_pgtable_alloc +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0xbee71a16 saa7134_set_gpio +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0xc296c5ef saa7134_dmasound_init +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0xc8f5321b saa7134_pgtable_free +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0xcb4a8a1a saa7134_tvaudio_setmute +EXPORT_SYMBOL drivers/media/video/soc_camera 0x151bde59 soc_camera_host_register +EXPORT_SYMBOL drivers/media/video/soc_camera 0x61acd70b soc_camera_device_unregister +EXPORT_SYMBOL drivers/media/video/soc_camera 0x8af57a20 soc_camera_video_stop +EXPORT_SYMBOL drivers/media/video/soc_camera 0xa4b93fa7 soc_camera_video_start +EXPORT_SYMBOL drivers/media/video/soc_camera 0xf20b3723 soc_camera_device_register +EXPORT_SYMBOL drivers/media/video/soc_camera 0xf9d25181 soc_camera_host_unregister +EXPORT_SYMBOL drivers/media/video/tveeprom 0x8533ae6a tveeprom_read +EXPORT_SYMBOL drivers/media/video/tveeprom 0xb2f6bcd5 tveeprom_hauppauge_analog +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x16a2915c RingQueue_Dequeue +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x2177e78c usbvideo_Deregister +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x407a321c RingQueue_WakeUpInterruptible +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x7ca83305 usbvideo_AllocateDevice +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0xa00baaef usbvideo_register +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0xafa59b8f usbvideo_TestPattern +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0xcbe18f5e usbvideo_RegisterVideoDevice +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0xddecac6d RingQueue_Enqueue +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0xf5011f67 RingQueue_Flush +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0xf8a35a8d usbvideo_DeinterlaceFrame +EXPORT_SYMBOL drivers/media/video/v4l1-compat 0x96b423bc v4l_compat_translate_ioctl +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x03165a85 v4l2_ctrl_get_menu +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x0dfb5e57 v4l2_prio_max +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x1c427ecb v4l2_ctrl_query_fill +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x2de2b633 v4l2_prio_check +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x2e9a955d v4l2_prio_close +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x42c8e001 v4l2_ctrl_next +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x57abfbd8 v4l2_chip_match_host +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x57e30e16 v4l2_i2c_attach +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x5fef1b4a v4l2_ctrl_query_fill_std +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x942892ab v4l2_prio_open +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xb2d1e17e v4l2_prio_change +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xc369097d v4l2_ctrl_check +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xcb01d6a6 v4l2_chip_match_i2c_client +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xd464e760 v4l2_ctrl_query_menu +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xe330bce9 v4l2_prio_init +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xeb78b5cc v4l2_chip_ident_i2c_client +EXPORT_SYMBOL drivers/media/video/videobuf-dvb 0xad603900 videobuf_dvb_unregister +EXPORT_SYMBOL drivers/media/video/videobuf-dvb 0xfe163f81 videobuf_dvb_register +EXPORT_SYMBOL drivers/media/video/videocodec 0x02ef66f1 videocodec_register +EXPORT_SYMBOL drivers/media/video/videocodec 0x7eae4aa3 videocodec_attach +EXPORT_SYMBOL drivers/media/video/videocodec 0xc32950f9 videocodec_unregister +EXPORT_SYMBOL drivers/media/video/videocodec 0xe40bb4f6 videocodec_detach +EXPORT_SYMBOL drivers/media/video/videodev 0x123959a1 v4l2_type_names +EXPORT_SYMBOL drivers/media/video/videodev 0x37b30140 video_exclusive_open +EXPORT_SYMBOL drivers/media/video/videodev 0x3adbd595 v4l2_field_names +EXPORT_SYMBOL drivers/media/video/videodev 0x44b5b27f video_devdata +EXPORT_SYMBOL drivers/media/video/videodev 0x5ebefe4b v4l_printk_ioctl +EXPORT_SYMBOL drivers/media/video/videodev 0x6657ccc4 video_usercopy +EXPORT_SYMBOL drivers/media/video/videodev 0x674eda75 video_exclusive_release +EXPORT_SYMBOL drivers/media/video/videodev 0x8a407215 video_register_device_index +EXPORT_SYMBOL drivers/media/video/videodev 0x8f3f1518 video_register_device +EXPORT_SYMBOL drivers/media/video/videodev 0x93f957ec video_unregister_device +EXPORT_SYMBOL drivers/media/video/videodev 0xc8966655 video_ioctl2 +EXPORT_SYMBOL drivers/media/video/videodev 0xd43f52d8 video_device_alloc +EXPORT_SYMBOL drivers/media/video/videodev 0xe2b92059 v4l2_video_std_construct +EXPORT_SYMBOL drivers/media/video/videodev 0xf3251e7b v4l2_norm_to_name +EXPORT_SYMBOL drivers/media/video/videodev 0xfcfec0a4 video_device_release +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x01752f6c mpt_get_msg_frame +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x04fa635f mpt_put_msg_frame_hi_pri +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x0872c333 mpt_print_ioc_summary +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x105d4f47 mpt_add_sge +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x22c5a2d7 mpt_reset_register +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x23c03e42 mpt_suspend +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x28d2d518 mpt_alloc_fw_memory +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x3dac3cf2 mpt_send_handshake_request +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x409e129e mpt_HardResetHandler +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x4526289b mpt_event_deregister +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x5492e312 mpt_device_driver_register +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x5edc7b12 mpt_free_msg_frame +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x6219b10b mpt_detach +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x7b0a717f mpt_config +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x86d56bb2 mpt_put_msg_frame +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x8c92d4c3 mpt_resume +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xb12b9ce0 mpt_attach +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xc0e69f82 mpt_device_driver_deregister +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xc1b85b39 mpt_free_fw_memory +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xc40e02be mpt_GetIocState +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xc47c22e8 mpt_deregister +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xc89ab11a mpt_verify_adapter +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xd04e517a mptbase_sas_persist_operation +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xd9a92a75 mpt_reset_deregister +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xdd805159 ioc_list +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xe8815a7f mpt_event_register +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xec7f5cfb mpt_raid_phys_disk_pg0 +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xedf8e7ba mpt_register +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xf18b519c mpt_findImVolumes +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x1953019c mptscsih_io_done +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x19b61ecd mptscsih_shutdown +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x241d1cfe mptscsih_slave_configure +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x26f17b7b mptscsih_host_attrs +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x2a5f74c5 mptscsih_ioc_reset +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x2f4699c1 mptscsih_bios_param +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x349ec6e1 mptscsih_abort +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x35dfa61c mptscsih_raid_id_to_num +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x440d615a mptscsih_slave_destroy +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x44144855 mptscsih_remove +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x4796cfcf mptscsih_event_process +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x4b155513 mptscsih_host_reset +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x6f2101fb mptscsih_change_queue_depth +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x725b2d22 mptscsih_qcmd +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x75fffa0f mptscsih_info +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x764ddf1a mptscsih_timer_expired +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xb695a124 mptscsih_taskmgmt_complete +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xc940ef47 mptscsih_suspend +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xcc76c6a5 mptscsih_bus_reset +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xdbef019f mptscsih_TMHandler +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xe0ee30ca mptscsih_dev_reset +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xe4c9fc29 mptscsih_resume +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xf23e8100 mptscsih_scandv_complete +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xf38cceaf mptscsih_is_phys_disk +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xf81f4bc2 mptscsih_proc_info +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x035e2d98 i2o_find_iop +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x06313bed i2o_parm_table_get +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x106799e3 i2o_parm_field_get +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x1e62f450 i2o_msg_get_wait +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x2a843bef i2o_dump_message +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x2d03d6af i2o_device_claim_release +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x3c311288 i2o_driver_unregister +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x42155d92 i2o_iop_find_device +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x4654cba5 i2o_driver_register +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x72eac3e3 i2o_driver_notify_controller_add_all +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x7cfcf526 i2o_driver_notify_device_remove_all +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x81026c79 i2o_device_claim +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x8250230b i2o_parm_issue +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x87700b6c i2o_exec_lct_get +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x9882971e i2o_status_get +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xb4c00dcf i2o_controllers +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xb56abc8d i2o_driver_notify_device_add_all +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xbed7c909 i2o_event_register +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xdf396cc2 i2o_msg_post_wait_mem +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xfc411041 i2o_driver_notify_controller_remove_all +EXPORT_SYMBOL drivers/mfd/htc-pasic3 0x4521b614 pasic3_write_register +EXPORT_SYMBOL drivers/mfd/htc-pasic3 0xb01f0a5d pasic3_read_register +EXPORT_SYMBOL drivers/misc/ioc4 0x3b5580db ioc4_unregister_submodule +EXPORT_SYMBOL drivers/misc/ioc4 0xedb327f4 ioc4_register_submodule +EXPORT_SYMBOL drivers/misc/sony-laptop 0x5bb1e117 sony_pic_camera_command +EXPORT_SYMBOL drivers/misc/tifm_core 0x07956357 tifm_add_adapter +EXPORT_SYMBOL drivers/misc/tifm_core 0x264b9655 tifm_register_driver +EXPORT_SYMBOL drivers/misc/tifm_core 0x39f86aa1 tifm_queue_work +EXPORT_SYMBOL drivers/misc/tifm_core 0x63a67376 tifm_remove_adapter +EXPORT_SYMBOL drivers/misc/tifm_core 0x662a6213 tifm_has_ms_pif +EXPORT_SYMBOL drivers/misc/tifm_core 0x6db4ebff tifm_eject +EXPORT_SYMBOL drivers/misc/tifm_core 0x74264615 tifm_alloc_device +EXPORT_SYMBOL drivers/misc/tifm_core 0x87b1005f tifm_unregister_driver +EXPORT_SYMBOL drivers/misc/tifm_core 0xa8b7c46a tifm_map_sg +EXPORT_SYMBOL drivers/misc/tifm_core 0xc5fc2fe9 tifm_alloc_adapter +EXPORT_SYMBOL drivers/misc/tifm_core 0xd0597301 tifm_free_adapter +EXPORT_SYMBOL drivers/misc/tifm_core 0xd197bad7 tifm_free_device +EXPORT_SYMBOL drivers/misc/tifm_core 0xec1c586c tifm_unmap_sg +EXPORT_SYMBOL drivers/mmc/card/mmc_block 0x8572565a mmc_cleanup_queue +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x09053528 mmc_unregister_driver +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x0f1ad238 mmc_set_data_timeout +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x171634ad mmc_detect_change +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x17a13da4 mmc_wait_for_app_cmd +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x2de49f6f mmc_remove_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x31b5d7bb mmc_free_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x3291a940 mmc_release_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x38af5ce1 mmc_wait_for_cmd +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x42fd4410 mmc_suspend_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x45c74161 mmc_align_data_size +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x542c3a78 mmc_alloc_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x552922bd mmc_add_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xa0a7bb8f mmc_resume_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xa6937bbf __mmc_claim_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xc3aca6e7 mmc_register_driver +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xdd4b1dd4 mmc_wait_for_req +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xf4bc1ed9 mmc_request_done +EXPORT_SYMBOL drivers/mtd/chips/cfi_util 0x17d37500 cfi_varsize_frob +EXPORT_SYMBOL drivers/mtd/chips/cfi_util 0x2e925a97 cfi_fixup +EXPORT_SYMBOL drivers/mtd/chips/cfi_util 0x609d9027 cfi_read_pri +EXPORT_SYMBOL drivers/mtd/chips/chipreg 0x25921fa5 do_map_probe +EXPORT_SYMBOL drivers/mtd/chips/chipreg 0x3cafeabe map_destroy +EXPORT_SYMBOL drivers/mtd/chips/chipreg 0x46953602 unregister_mtd_chip_driver +EXPORT_SYMBOL drivers/mtd/chips/chipreg 0x995d3f76 register_mtd_chip_driver +EXPORT_SYMBOL drivers/mtd/chips/gen_probe 0x74bc4e94 mtd_do_chip_probe +EXPORT_SYMBOL drivers/mtd/maps/map_funcs 0xac500447 simple_map_init +EXPORT_SYMBOL drivers/mtd/mtd 0x7bc41ba7 add_mtd_partitions +EXPORT_SYMBOL drivers/mtd/mtd 0x8ee6a061 del_mtd_partitions +EXPORT_SYMBOL drivers/mtd/mtdconcat 0x639eaa1b mtd_concat_destroy +EXPORT_SYMBOL drivers/mtd/mtdconcat 0xc19247e5 mtd_concat_create +EXPORT_SYMBOL drivers/mtd/nand/nand 0x2907fd32 nand_default_bbt +EXPORT_SYMBOL drivers/mtd/nand/nand 0xbf69d4c6 nand_scan_bbt +EXPORT_SYMBOL drivers/mtd/nand/nand_ecc 0x254f230c nand_calculate_ecc +EXPORT_SYMBOL drivers/mtd/nand/nand_ecc 0x87406d9d nand_correct_data +EXPORT_SYMBOL drivers/mtd/nand/nand_ids 0x836bdb72 nand_flash_ids +EXPORT_SYMBOL drivers/mtd/nand/nand_ids 0xa336feb7 nand_manuf_ids +EXPORT_SYMBOL drivers/mtd/onenand/onenand 0x1ceeb563 onenand_default_bbt +EXPORT_SYMBOL drivers/mtd/onenand/onenand 0xf8532292 onenand_scan_bbt +EXPORT_SYMBOL drivers/net/8390 0x046ea9ae __alloc_ei_netdev +EXPORT_SYMBOL drivers/net/8390 0x41ed0687 ei_open +EXPORT_SYMBOL drivers/net/8390 0x5e4bf81a ei_close +EXPORT_SYMBOL drivers/net/8390 0x7d7e0dbc ei_interrupt +EXPORT_SYMBOL drivers/net/8390 0x8106989e NS8390_init +EXPORT_SYMBOL drivers/net/8390 0xaa9e5ad7 ei_poll +EXPORT_SYMBOL drivers/net/8390p 0x2b91b1e0 eip_open +EXPORT_SYMBOL drivers/net/8390p 0x841bc69f eip_interrupt +EXPORT_SYMBOL drivers/net/8390p 0x8df77056 eip_close +EXPORT_SYMBOL drivers/net/8390p 0xaffa4748 NS8390p_init +EXPORT_SYMBOL drivers/net/8390p 0xf2251165 __alloc_eip_netdev +EXPORT_SYMBOL drivers/net/8390p 0xf8c4d22d eip_poll +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x08fba262 arc_raw_proto +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x4641bd7d arcnet_interrupt +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x618bbec3 arcnet_unregister_proto +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x6534792a arcnet_debug +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0xae4103c3 alloc_arcdev +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0xc25baeaa arc_proto_default +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0xd195c744 arc_bcast_proto +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0xf558a24a arc_proto_map +EXPORT_SYMBOL drivers/net/arcnet/com20020 0x724e64bd com20020_found +EXPORT_SYMBOL drivers/net/arcnet/com20020 0xf3f13bed com20020_check +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x02248990 cxgb3_free_atid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x0e94bd83 cxgb3_insert_tid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x18f6d96e t3_l2t_send_event +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x2d048bf2 cxgb3_remove_tid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x3385a5b8 cxgb3_free_stid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x361fc49e dev2t3cdev +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x3740f0f0 cxgb3_register_client +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x439dc15b t3_l2t_send_slow +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x6bd95240 cxgb3_alloc_stid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x71a95237 cxgb3_ofld_send +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x785737dc t3_l2t_get +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x937543cc cxgb3_unregister_client +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x9ee77acc cxgb3_alloc_atid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0xc644662c t3_l2e_free +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0xcb48b4f8 t3_register_cpl_handler +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0xf75fd740 cxgb3_queue_tid_release +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0x39ed15b1 hdlcdrv_arbitrate +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0xca30224d hdlcdrv_receiver +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0xcf711a0c hdlcdrv_transmitter +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0xcf98ba55 hdlcdrv_register +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0xfc4bdbaf hdlcdrv_unregister +EXPORT_SYMBOL drivers/net/irda/sir-dev 0x0d092e03 irda_unregister_dongle +EXPORT_SYMBOL drivers/net/irda/sir-dev 0x2571c77d sirdev_put_instance +EXPORT_SYMBOL drivers/net/irda/sir-dev 0x637be7e1 sirdev_receive +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xa0ae8caf sirdev_set_dtr_rts +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xabdc9470 sirdev_raw_write +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xc69fdbe7 sirdev_write_complete +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xd93631d1 sirdev_get_instance +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xdea83fbd irda_register_dongle +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xe1fb6603 sirdev_raw_read +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xe2a14725 sirdev_set_dongle +EXPORT_SYMBOL drivers/net/mii 0x0b54df65 mii_check_link +EXPORT_SYMBOL drivers/net/mii 0x22978408 mii_check_gmii_support +EXPORT_SYMBOL drivers/net/mii 0x77430000 mii_nway_restart +EXPORT_SYMBOL drivers/net/mii 0xbbcdf407 mii_ethtool_gset +EXPORT_SYMBOL drivers/net/mii 0xc39e29ac mii_link_ok +EXPORT_SYMBOL drivers/net/mii 0xceaab80e generic_mii_ioctl +EXPORT_SYMBOL drivers/net/mii 0xd53c9d49 mii_ethtool_sset +EXPORT_SYMBOL drivers/net/mii 0xeb8e68c9 mii_check_media +EXPORT_SYMBOL drivers/net/phy/libphy 0x07474ab4 genphy_config_aneg +EXPORT_SYMBOL drivers/net/phy/libphy 0x13004d82 phy_attach +EXPORT_SYMBOL drivers/net/phy/libphy 0x18b42c0a phy_sanitize_settings +EXPORT_SYMBOL drivers/net/phy/libphy 0x2289c362 phy_device_create +EXPORT_SYMBOL drivers/net/phy/libphy 0x25bfdc60 phy_connect +EXPORT_SYMBOL drivers/net/phy/libphy 0x2c653292 mdio_bus_type +EXPORT_SYMBOL drivers/net/phy/libphy 0x33a54271 get_phy_id +EXPORT_SYMBOL drivers/net/phy/libphy 0x357aa18c genphy_update_link +EXPORT_SYMBOL drivers/net/phy/libphy 0x3702f8a7 phy_write +EXPORT_SYMBOL drivers/net/phy/libphy 0x40133905 phy_stop +EXPORT_SYMBOL drivers/net/phy/libphy 0x50e0fc13 phy_register_fixup_for_id +EXPORT_SYMBOL drivers/net/phy/libphy 0x5757c71c phy_scan_fixups +EXPORT_SYMBOL drivers/net/phy/libphy 0x6941fed9 genphy_config_advert +EXPORT_SYMBOL drivers/net/phy/libphy 0x79f97c65 genphy_read_status +EXPORT_SYMBOL drivers/net/phy/libphy 0x7c42167a phy_read +EXPORT_SYMBOL drivers/net/phy/libphy 0x85261fc0 mdiobus_unregister +EXPORT_SYMBOL drivers/net/phy/libphy 0x87b2aef5 mdiobus_register +EXPORT_SYMBOL drivers/net/phy/libphy 0x89d75637 phy_enable_interrupts +EXPORT_SYMBOL drivers/net/phy/libphy 0x908197c4 phy_stop_interrupts +EXPORT_SYMBOL drivers/net/phy/libphy 0x909c6f4a phy_ethtool_sset +EXPORT_SYMBOL drivers/net/phy/libphy 0x967c353f phy_driver_register +EXPORT_SYMBOL drivers/net/phy/libphy 0x98560009 phy_start_aneg +EXPORT_SYMBOL drivers/net/phy/libphy 0xa4870660 phy_register_fixup +EXPORT_SYMBOL drivers/net/phy/libphy 0xacf85e77 phy_disable_interrupts +EXPORT_SYMBOL drivers/net/phy/libphy 0xad6fd52d phy_register_fixup_for_uid +EXPORT_SYMBOL drivers/net/phy/libphy 0xb25f9606 phy_print_status +EXPORT_SYMBOL drivers/net/phy/libphy 0xbdc3250b phy_ethtool_gset +EXPORT_SYMBOL drivers/net/phy/libphy 0xc22473f9 phy_driver_unregister +EXPORT_SYMBOL drivers/net/phy/libphy 0xcf4544e2 phy_start_interrupts +EXPORT_SYMBOL drivers/net/phy/libphy 0xd3b420f4 phy_start +EXPORT_SYMBOL drivers/net/phy/libphy 0xd8525263 phy_mii_ioctl +EXPORT_SYMBOL drivers/net/phy/libphy 0xe03c5af7 phy_disconnect +EXPORT_SYMBOL drivers/net/phy/libphy 0xfb67dd68 phy_detach +EXPORT_SYMBOL drivers/net/phy/mdio-bitbang 0x3a46f4ae free_mdio_bitbang +EXPORT_SYMBOL drivers/net/phy/mdio-bitbang 0xbd5c59a2 alloc_mdio_bitbang +EXPORT_SYMBOL drivers/net/ppp_generic 0x2135c684 ppp_output_wakeup +EXPORT_SYMBOL drivers/net/ppp_generic 0x3486f1d8 ppp_register_compressor +EXPORT_SYMBOL drivers/net/ppp_generic 0x34bf72fe ppp_register_channel +EXPORT_SYMBOL drivers/net/ppp_generic 0x383c39a1 ppp_unregister_compressor +EXPORT_SYMBOL drivers/net/ppp_generic 0x408bc142 ppp_unit_number +EXPORT_SYMBOL drivers/net/ppp_generic 0x64e7e3ca ppp_channel_index +EXPORT_SYMBOL drivers/net/ppp_generic 0x70e24fe9 ppp_unregister_channel +EXPORT_SYMBOL drivers/net/ppp_generic 0x8a860da2 ppp_input +EXPORT_SYMBOL drivers/net/ppp_generic 0xdfc86ceb ppp_input_error +EXPORT_SYMBOL drivers/net/pppox 0x44df4ae6 pppox_ioctl +EXPORT_SYMBOL drivers/net/pppox 0xb31cf001 register_pppox_proto +EXPORT_SYMBOL drivers/net/pppox 0xe0ff7a18 unregister_pppox_proto +EXPORT_SYMBOL drivers/net/pppox 0xf90e454f pppox_unbind_sock +EXPORT_SYMBOL drivers/net/slhc 0x0ff2b602 slhc_compress +EXPORT_SYMBOL drivers/net/slhc 0x23c8f257 slhc_uncompress +EXPORT_SYMBOL drivers/net/slhc 0xa63d85ab slhc_remember +EXPORT_SYMBOL drivers/net/slhc 0xb5ca1c46 slhc_free +EXPORT_SYMBOL drivers/net/slhc 0xdfc5169b slhc_init +EXPORT_SYMBOL drivers/net/slhc 0xe8794ce1 slhc_toss +EXPORT_SYMBOL drivers/net/sungem_phy 0xd1a90089 mii_phy_probe +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0x3935f9db tms380tr_open +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0x518fcbfb tms380tr_interrupt +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0x559df547 tmsdev_init +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0xbbf533f4 tms380tr_close +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0xcb63b884 tmsdev_term +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0xd2328794 tms380tr_wait +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0x38da4725 cycx_intr +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0x62be23ea cycx_setup +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0x66a4c4e6 cycx_down +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0x968458a6 cycx_peek +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0xb6f383de cycx_poke +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0xfe7cd576 cycx_exec +EXPORT_SYMBOL drivers/net/wan/hdlc 0x38ce84ef hdlc_open +EXPORT_SYMBOL drivers/net/wan/hdlc 0x3db01d35 register_hdlc_protocol +EXPORT_SYMBOL drivers/net/wan/hdlc 0x630a038f attach_hdlc_protocol +EXPORT_SYMBOL drivers/net/wan/hdlc 0x78be3ab1 detach_hdlc_protocol +EXPORT_SYMBOL drivers/net/wan/hdlc 0x83e09335 alloc_hdlcdev +EXPORT_SYMBOL drivers/net/wan/hdlc 0xa569ddc7 unregister_hdlc_protocol +EXPORT_SYMBOL drivers/net/wan/hdlc 0xa6c36817 hdlc_ioctl +EXPORT_SYMBOL drivers/net/wan/hdlc 0xd3223739 hdlc_close +EXPORT_SYMBOL drivers/net/wan/hdlc 0xe1c8a96a unregister_hdlc_device +EXPORT_SYMBOL drivers/net/wan/syncppp 0x3f4221a6 sppp_do_ioctl +EXPORT_SYMBOL drivers/net/wan/syncppp 0x48a16387 sppp_detach +EXPORT_SYMBOL drivers/net/wan/syncppp 0x5bd8de77 sppp_reopen +EXPORT_SYMBOL drivers/net/wan/syncppp 0x93de24da sppp_open +EXPORT_SYMBOL drivers/net/wan/syncppp 0xa0de3be8 sppp_attach +EXPORT_SYMBOL drivers/net/wan/syncppp 0xcc58e8bf sppp_close +EXPORT_SYMBOL drivers/net/wan/z85230 0x083004b5 z8530_sync_txdma_open +EXPORT_SYMBOL drivers/net/wan/z85230 0x0c041fdc z8530_sync_dma_close +EXPORT_SYMBOL drivers/net/wan/z85230 0x0ebc27b5 z8530_init +EXPORT_SYMBOL drivers/net/wan/z85230 0x10c78988 z8530_dead_port +EXPORT_SYMBOL drivers/net/wan/z85230 0x1632fe03 z8530_queue_xmit +EXPORT_SYMBOL drivers/net/wan/z85230 0x283e799e z8530_interrupt +EXPORT_SYMBOL drivers/net/wan/z85230 0x53cef04d z8530_nop +EXPORT_SYMBOL drivers/net/wan/z85230 0x5846a4b0 z8530_sync_open +EXPORT_SYMBOL drivers/net/wan/z85230 0x5cd24d29 z8530_hdlc_kilostream +EXPORT_SYMBOL drivers/net/wan/z85230 0x70ce6673 z8530_channel_load +EXPORT_SYMBOL drivers/net/wan/z85230 0x7cf1bb3a z8530_shutdown +EXPORT_SYMBOL drivers/net/wan/z85230 0x99e4e69d z8530_dma_sync +EXPORT_SYMBOL drivers/net/wan/z85230 0x9ff80920 z8530_describe +EXPORT_SYMBOL drivers/net/wan/z85230 0xa0612a62 z8530_null_rx +EXPORT_SYMBOL drivers/net/wan/z85230 0xa78b904b z8530_txdma_sync +EXPORT_SYMBOL drivers/net/wan/z85230 0xaa4eba76 z8530_sync_close +EXPORT_SYMBOL drivers/net/wan/z85230 0xaeb46915 z8530_sync_dma_open +EXPORT_SYMBOL drivers/net/wan/z85230 0xc1bcf554 z8530_sync +EXPORT_SYMBOL drivers/net/wan/z85230 0xda743859 z8530_sync_txdma_close +EXPORT_SYMBOL drivers/net/wan/z85230 0xe3d80064 z8530_hdlc_kilostream_85230 +EXPORT_SYMBOL drivers/net/wireless/airo 0x8de607cd reset_airo_card +EXPORT_SYMBOL drivers/net/wireless/airo 0xcbeb8a82 init_airo_card +EXPORT_SYMBOL drivers/net/wireless/airo 0xe18a4062 stop_airo_card +EXPORT_SYMBOL drivers/net/wireless/atmel 0x0fecbc7d atmel_open +EXPORT_SYMBOL drivers/net/wireless/atmel 0x805fbfbc stop_atmel_card +EXPORT_SYMBOL drivers/net/wireless/atmel 0x986608b1 init_atmel_card +EXPORT_SYMBOL drivers/net/wireless/hermes 0x4196c38b hermes_write_ltv +EXPORT_SYMBOL drivers/net/wireless/hermes 0xc60b5e9e hermes_bap_pwrite +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd38d8ae2 hermes_read_ltv +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd3f714e5 hermes_bap_pread +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd5168829 hermes_allocate +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd5336e5d hermes_init +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd54e219d hermes_docmd_wait +EXPORT_SYMBOL drivers/net/wireless/hermes 0xed47b224 hermes_struct_init +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x0ad69602 hostap_set_multicast_list_queue +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x0f97adf6 hostap_set_encryption +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x1a6240e8 hostap_free_data +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x1c3938b7 hostap_info_init +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x31d3e5f1 prism2_update_comms_qual +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x332da425 hostap_set_hostapd_sta +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x33dfb96a hostap_remove_proc +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x372998e5 hostap_init_proc +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x3aa2f43c hostap_info_process +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x4dc64593 hostap_80211_rx +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x5697132e hostap_get_porttype +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x5ba63a0f hostap_set_string +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x66963fe5 hostap_set_hostapd +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x6903f16c hostap_80211_get_hdrlen +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x6ea57d9a hostap_set_word +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x7275c948 hostap_remove_interface +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x85e29bba hostap_check_sta_fw_version +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x907eca43 hostap_handle_sta_tx_exc +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x9598bfb4 hostap_get_stats +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x966247d3 hostap_set_auth_algs +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xa12ad27f hostap_dump_tx_header +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xa7821c22 hostap_set_antsel +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xb2a945e0 hostap_dump_rx_header +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xb34f2478 hostap_add_interface +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xcb9f4cf6 hostap_init_data +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xd49cea9e hostap_init_ap_proc +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xdaf6546f hostap_set_roaming +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xeceef62d hostap_setup_dev +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xf97c81cb hostap_80211_ops +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xfb7db903 hostap_master_start_xmit +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x034a763f iwl_send_cmd_sync +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x04603b49 iwl_eeprom_free +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x04d8b40f iwl_sta_modify_enable_tid_tx +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x050ef538 iwl_rx_queue_update_write_ptr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x066cbf93 iwl_rx_reply_rx +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x07bdf879 iwl_power_temperature_change +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x084ad759 iwl_leds_unregister +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x09e6fc92 iwl_rx_queue_space +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x13340e0a iwl_get_channel_info +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x15ef5f07 iwl_eeprom_init +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x18d85773 iwl_tx_agg_start +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x1951092a iwl_init_sensitivity +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x19d02508 iwl_remove_dynamic_key +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x1ae4bb67 iwl_rx_queue_free +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x1c878c67 iwl_setup_rx_scan_handlers +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x1d77b399 iwl_bcast_addr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x233273ba iwl_rx_queue_reset +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x24b246e0 iwl_setup_scan_deferred_work +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x28179cf5 iwl_remove_default_wep_key +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x297f438a iwl_send_add_sta +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x2b764366 iwl_uninit_drv +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x31160763 iwlcore_eeprom_acquire_semaphore +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x33bc261b iwl_set_tx_power +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x37039bb3 iwl_power_initialize +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x3821e17a iwl_rx_reply_compressed_ba +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x3cc73a7b iwl_tx_skb +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x3ffb373c iwl_hw_txq_free_tfd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x42884ad6 iwl_eeprom_query16 +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x431cc7eb iwl_power_cancel_timeout +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x45383e5e iwl_tx_queue_reclaim +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x455b4bde iwl_send_cmd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x457430f5 iwl_rfkill_unregister +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x4798963d iwl_setup_power_deferred_work +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x49029b39 iwl_tx_cmd_complete +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x4a55ff26 iwl_leds_background +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x4affcf37 iwl_rxon_add_station +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x4cd0131d iwl_eeprom_get_mac +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x4e33b7f9 iwl_power_set_system_mode +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x4e610044 iwl_print_event_log +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x55522f00 iwl_rfkill_set_hw_state +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x574602bc iwl_rx_queue_alloc +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5834878e iwl_find_station +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x58ff38d2 iwl_init_drv +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5a67fe8a iwlcore_eeprom_query_addr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5a8a48df iwl_eeprom_check_version +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5b3f033d iwl_rxq_stop +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5bdf08c8 iwl_add_station_flags +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5bf7d3a5 iwl_rx_queue_restock +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5c9dc4b9 iwl_dump_nic_event_log +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5d957932 iwl_txq_ctx_stop +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5dbdd3f9 iwl_rx_reply_rx_phy +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5dc4048a iwl_init_channel_map +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5e84c301 iwl_txq_check_empty +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x601419cc iwl_rx_replenish +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x60774702 iwl_queue_space +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x61a4a54e iwlcore_eeprom_verify_signature +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x62727d56 iwl_calib_set +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x6615a14e iwl_alloc_all +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x6edd0740 iwl_chain_noise_calibration +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x711f931c iwl_power_disable_management +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x7185bdbc iwl_send_cmd_pdu_async +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x71babf5a iwl_set_dynamic_key +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x75160779 iwl_setup_mac +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x75a8ff14 iwl_set_hw_params +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x7708254e iwl_send_statistics_request +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x80743bc9 iwl_reset_run_time_calib +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x8092b2a9 iwl_eeprom_query_addr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x8359a0e3 iwl_rfkill_init +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x846fa2d9 iwl_hw_detect +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x8670273d iwl_hwrate_to_plcp_idx +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x86e830ee iwl_send_lq_cmd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x8956c896 iwl_dump_nic_error_log +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x89d380a0 iwl_tx_agg_stop +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x8b3abea0 iwl_sensitivity_calibration +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x92c57770 iwl_power_enable_management +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x9442c1ca iwl_rx_statistics +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x95eb9cde iwl_hwrate_to_tx_control +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x997aee34 iwl_power_set_user_mode +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x9ccd0c27 iwl_scan_cancel_timeout +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x9f3e3627 iwl_set_default_wep_key +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xa5e35ad1 iwl_rx_agg_stop +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xab49421b iwl_radio_kill_sw_enable_radio +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xad3e5645 iwl_txq_update_write_ptr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xaf9ea765 iwl_scan_cancel +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xb2460107 iwl_send_static_wepkey_cmd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xb38a1e41 iwl_escape_essid +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xb4ae3d13 iwl_get_ra_sta_id +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xb76bbeee iwl_set_rxon_channel +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xb8ea66a0 iwl_set_rxon_ht +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xbe66b1d2 iwl_radio_kill_sw_disable_radio +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc1e162e9 iwl_reset_qos +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc3305164 iwl_rx_missed_beacon_notif +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc65832d7 iwl_send_cmd_pdu +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc72b3d1e iwl_remove_station +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc84de1a4 iwl_verify_ucode +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc895601e iwl_scan_initiate +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc900c7a9 iwl_is_fat_tx_allowed +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xcaaf4ff5 iwl_rx_agg_start +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xcbaf4931 get_cmd_string +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xd80d360f iwlcore_eeprom_release_semaphore +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xdeb82217 iwl_send_calib_results +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xe2cd2f9b iwl_leds_register +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xe35867b2 iwl_power_update_mode +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xe7ce5d70 iwl_rates +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xedf8323c iwl_hw_txq_attach_buf_to_tfd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf1eddcda iwl_hw_txq_ctx_free +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf4d9cd06 iwl_hw_nic_init +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf7f464c7 iwl_clear_stations_table +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf8a34de9 iwl_get_sta_id +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf93e31f6 iwl_set_rxon_chain +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xfea6c5ba iwl_rf_kill_ct_config +EXPORT_SYMBOL drivers/net/wireless/orinoco 0x1a9d334a orinoco_interrupt +EXPORT_SYMBOL drivers/net/wireless/orinoco 0x2c6fa8bb __orinoco_up +EXPORT_SYMBOL drivers/net/wireless/orinoco 0x60f985ba __orinoco_down +EXPORT_SYMBOL drivers/net/wireless/orinoco 0x6ea9643c alloc_orinocodev +EXPORT_SYMBOL drivers/net/wireless/orinoco 0xe0edfedf free_orinocodev +EXPORT_SYMBOL drivers/net/wireless/orinoco 0xe8ee8eb7 orinoco_reinit_firmware +EXPORT_SYMBOL drivers/parport/parport 0x03b4fca9 parport_claim_or_block +EXPORT_SYMBOL drivers/parport/parport 0x0ec8f52c parport_negotiate +EXPORT_SYMBOL drivers/parport/parport 0x15b1a365 parport_read +EXPORT_SYMBOL drivers/parport/parport 0x1dbe8d84 parport_irq_handler +EXPORT_SYMBOL drivers/parport/parport 0x20f276c6 parport_wait_peripheral +EXPORT_SYMBOL drivers/parport/parport 0x224770fc parport_release +EXPORT_SYMBOL drivers/parport/parport 0x27a43e2a parport_ieee1284_epp_write_addr +EXPORT_SYMBOL drivers/parport/parport 0x2ff78fc8 parport_write +EXPORT_SYMBOL drivers/parport/parport 0x3a04b805 parport_get_port +EXPORT_SYMBOL drivers/parport/parport 0x3a4d95c8 parport_find_base +EXPORT_SYMBOL drivers/parport/parport 0x3f7f3e4f parport_announce_port +EXPORT_SYMBOL drivers/parport/parport 0x4298c3ee parport_ieee1284_epp_read_addr +EXPORT_SYMBOL drivers/parport/parport 0x4d2a941b parport_ieee1284_interrupt +EXPORT_SYMBOL drivers/parport/parport 0x5a9037c2 parport_register_driver +EXPORT_SYMBOL drivers/parport/parport 0x5e037212 parport_ieee1284_ecp_write_data +EXPORT_SYMBOL drivers/parport/parport 0x64439f6f parport_register_port +EXPORT_SYMBOL drivers/parport/parport 0x6d6d77f4 parport_claim +EXPORT_SYMBOL drivers/parport/parport 0x7b0ca4ac parport_ieee1284_read_byte +EXPORT_SYMBOL drivers/parport/parport 0x7f401593 parport_remove_port +EXPORT_SYMBOL drivers/parport/parport 0x80cafeda parport_ieee1284_ecp_read_data +EXPORT_SYMBOL drivers/parport/parport 0x8481aac5 parport_wait_event +EXPORT_SYMBOL drivers/parport/parport 0x8d484cf7 parport_ieee1284_ecp_write_addr +EXPORT_SYMBOL drivers/parport/parport 0x94a0351d parport_ieee1284_write_compat +EXPORT_SYMBOL drivers/parport/parport 0xb3d4fe1c parport_register_device +EXPORT_SYMBOL drivers/parport/parport 0xb4f85a64 parport_ieee1284_read_nibble +EXPORT_SYMBOL drivers/parport/parport 0xc69c4ad2 parport_put_port +EXPORT_SYMBOL drivers/parport/parport 0xccb0dc17 parport_set_timeout +EXPORT_SYMBOL drivers/parport/parport 0xd1a69b2e parport_find_number +EXPORT_SYMBOL drivers/parport/parport 0xd1e00fa2 parport_unregister_device +EXPORT_SYMBOL drivers/parport/parport 0xe41aa02d parport_ieee1284_epp_read_data +EXPORT_SYMBOL drivers/parport/parport 0xe5d3f0df parport_unregister_driver +EXPORT_SYMBOL drivers/parport/parport 0xf4ef00cf parport_ieee1284_epp_write_data +EXPORT_SYMBOL drivers/parport/parport_pc 0x393a0676 parport_pc_probe_port +EXPORT_SYMBOL drivers/parport/parport_pc 0xf0ffecc3 parport_pc_unregister_port +EXPORT_SYMBOL drivers/pci/hotplug/pci_hotplug 0xc87a9fbb acpi_get_hp_hw_control_from_firmware +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x10d28ec1 pcmcia_register_driver +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x257232c3 pcmcia_request_io +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x5b752aae pcmcia_get_configuration_info +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x69f1443d pcmcia_dev_present +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x7ec5df33 pcmcia_request_irq +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x92061fda pcmcia_access_configuration_register +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x9c0aba83 pcmcia_disable_device +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x9d59236a pcmcia_get_window +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xaf6e563d pcmcia_unregister_driver +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xb0e6bffc pcmcia_request_window +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xb4f38f56 pcmcia_request_configuration +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xbc6adb2d pcmcia_get_mem_page +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xbd033cd2 pcmcia_release_window +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xcb90d845 pcmcia_map_mem_page +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xea6e7163 cs_error +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xf4cd60ef pcmcia_modify_configuration +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x082f89af destroy_cis_cache +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x1586d5d7 pcmcia_socket_class +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x212db8d2 pcmcia_socket_list +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x29af7a78 pcmcia_parse_events +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x2d4bba20 pcmcia_replace_cis +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x35df2708 pcmcia_suspend_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x489e8951 pcmcia_unregister_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x498a1de0 pcmcia_insert_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x4cc33cfd pcmcia_write_cis_mem +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x4cd59efc pcmcia_get_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x4dd4a7ac pcmcia_socket_dev_resume +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x551f7c2e pcmcia_eject_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x55ed6d27 pccard_reset_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x64b2b9fb pcmcia_get_socket_by_nr +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x725b49da pcmcia_adjust_io_region +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x78215df5 pccard_get_first_tuple +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x7857d534 release_cis_mem +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x79a8ccc6 pccard_validate_cis +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x93968a0e pccard_get_tuple_data +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xa55b29e8 pcmcia_put_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xa68708ad pcmcia_find_mem_region +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xb47c57c4 pccard_get_next_tuple +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xc2e5f3b1 pcmcia_validate_mem +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xc368f687 pcmcia_socket_list_rwsem +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xc8af853d pccard_register_pcmcia +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xc94186ad pccard_read_tuple +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xcd2ac1c1 pccard_parse_tuple +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xcf97f3bd dead_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xd12a905d pcmcia_resume_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xdae2ea44 pcmcia_find_io_region +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xe9b8ad57 pcmcia_read_cis_mem +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xe9dfd386 pccard_static_ops +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xf72251ad pcmcia_register_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xfe55035a pcmcia_socket_dev_suspend +EXPORT_SYMBOL drivers/pcmcia/rsrc_nonstatic 0x6d4ac9fe pccard_nonstatic_ops +EXPORT_SYMBOL drivers/scsi/53c700 0x11b4c8b2 NCR_700_release +EXPORT_SYMBOL drivers/scsi/53c700 0x24f32a6d NCR_700_detect +EXPORT_SYMBOL drivers/scsi/53c700 0x5175c0f0 NCR_700_intr +EXPORT_SYMBOL drivers/scsi/megaraid/megaraid_mm 0x2250c66e mraid_mm_adapter_app_handle +EXPORT_SYMBOL drivers/scsi/megaraid/megaraid_mm 0x512c956d mraid_mm_unregister_adp +EXPORT_SYMBOL drivers/scsi/megaraid/megaraid_mm 0x57c3976f mraid_mm_register_adp +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x0c18a5d2 qlogicfas408_bus_reset +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x10205b5e qlogicfas408_queuecommand +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x3fd8cd71 qlogicfas408_detect +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x5cd179e6 qlogicfas408_ihandl +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x8b4035f4 qlogicfas408_abort +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x9084759d qlogicfas408_info +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0xb0a045bb qlogicfas408_disable_ints +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0xdd32fce1 qlogicfas408_biosparam +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0xe76b3b20 qlogicfas408_get_chip_type +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0xf2b95199 qlogicfas408_setup +EXPORT_SYMBOL drivers/scsi/raid_class 0x251c8b4e raid_component_add +EXPORT_SYMBOL drivers/scsi/raid_class 0x7b8c5d03 raid_class_release +EXPORT_SYMBOL drivers/scsi/raid_class 0xccf10938 raid_class_attach +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x028ce6c2 scsi_device_put +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x0617777e scsi_ioctl +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x0c65e73c scsi_normalize_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x0c8c9e99 scsi_show_extd_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x0eb5cfd5 scsi_setup_fs_cmnd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x11267875 scsi_extd_sense_format +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x156f8e98 scsi_dma_unmap +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x15b172fb scsi_adjust_queue_depth +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x19df1d55 scsi_block_when_processing_errors +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1b9e0ff1 scsilun_to_int +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1c14cce5 scsi_is_sdev_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1e06bf23 scsi_finish_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1e87fc3a scsi_report_bus_reset +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1f6306c7 scsi_unblock_requests +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1f7ce162 scsi_is_target_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x20e7ba0e __starget_for_each_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x264c56b9 scsi_eh_finish_cmd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x28a2ed02 scsi_build_sense_buffer +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2b0ba2b0 scsi_sense_desc_find +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2d89342a scsi_show_sense_hdr +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2ec546b8 starget_for_each_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x313f1a68 scsi_is_host_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x3174e4e9 scsi_scan_host +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x3389d1af scsi_device_quiesce +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x3cbb64e4 scsi_register +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x45530cd5 scsi_free_host_dev +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x466936f7 scsi_allocate_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x46b6fdd8 scsi_scan_target +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x46fdbe47 __scsi_device_lookup +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x48b2ff5f scsi_host_put +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x4a0bd599 scsi_release_buffers +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x4a1f1678 __scsi_put_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x4afe9a77 scsi_partsize +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x51ee3b09 scsi_eh_restore_cmnd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x563b8343 scsi_target_quiesce +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x56c8799d scsi_kunmap_atomic_sg +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x58579021 __scsi_alloc_queue +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x5921f0ef scsi_print_result +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x5ccbc2b7 scsi_host_alloc +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x6249d8ac __scsi_device_lookup_by_target +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x646a8e0c scsi_print_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x6565d33f scsi_kmap_atomic_sg +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x65fa4bd7 scsi_cmd_print_sense_hdr +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x6631977c scsi_rescan_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x68b8bae6 scsi_req_abort_cmd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x69d38ed9 __scsi_print_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x706e47ca scsi_get_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x726de01c scsi_report_device_reset +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x727673c5 scsi_remove_host +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x72ea7b2d scsi_device_type +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x7872d454 scsi_unregister +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x796fc5ce scsi_get_sense_info_fld +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x7a7bee99 scsi_print_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x7dc6f7fe scsicam_bios_param +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x7dc82340 scsi_add_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x7f40bdde scsi_eh_prep_cmnd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x84662605 scsi_track_queue_full +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x84cf5e56 scsi_set_medium_removal +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x8c61f3cd scsi_device_lookup_by_target +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x8d81cf45 scsi_put_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x8db375aa scsi_prep_return +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x8f1ef251 scsi_bios_ptable +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x90b0c997 scsi_test_unit_ready +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x9669becf scsi_dma_map +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x96a7f3c9 scsi_device_lookup +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x96cd2b04 scsi_sense_key_string +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x9cfd56c5 scsi_print_status +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x9e301053 scsi_block_requests +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xa0ea2327 scsi_add_host +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xa1926864 scsi_device_resume +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xaf3dd7dc scsi_logging_level +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xafa57863 scsi_host_get +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xb09fc10e scsi_command_normalize_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xb19c5d79 scsi_nonblockable_ioctl +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xb6c5a973 scsi_show_result +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xbb8058c4 scsi_reset_provider +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xbbee9918 scsi_execute +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xbdd1017c scsi_register_driver +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xbecb4f92 scsi_device_set_state +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xc088ea82 scsi_host_set_state +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xc18c5c3c scsi_device_get +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xc1a34e27 scsi_remove_target +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xc26aae5b scsi_mode_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xc44107fb __scsi_add_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xc7ac25a8 scsi_get_host_dev +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xca5dbc50 scsi_print_sense_hdr +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xccb2857d scsi_remove_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xcec33438 scsi_init_io +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xd03526e2 scsi_register_interface +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xda500e58 scsi_setup_blk_pc_cmnd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xe1cd2cf8 scsi_prep_state_check +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xe409a149 __scsi_iterate_devices +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xe49b942f scsi_execute_req +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xea10212a int_to_scsilun +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xedfd0af0 scsi_target_resume +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf811e69d scsi_eh_flush_done_q +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf97d8fa5 scsi_calculate_bounce_limit +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf9b2902f scsi_host_lookup +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xfcb8444e scsi_free_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xfef96e23 __scsi_print_command +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x030a2cb0 fc_remote_port_delete +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x0c309612 scsi_is_fc_rport +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x32e829d9 fc_vport_terminate +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x3859b540 fc_remote_port_add +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x3fd5778b fc_host_post_event +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x5066e80c fc_remote_port_rolechg +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x697149f4 fc_attach_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x7954b1ea fc_get_event_number +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x8c91a37e fc_host_post_vendor_event +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0xe8c7f5bd fc_release_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0xecb4501c fc_remove_host +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0xfb2c5a25 scsi_is_fc_vport +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x0862e836 sas_port_delete +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x107b4b03 sas_phy_free +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x1408101e sas_rphy_free +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x17138876 sas_port_alloc +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x1db06962 sas_phy_add +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x20dc634e scsi_is_sas_phy +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x40513d24 sas_port_free +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x410e703d sas_port_add_phy +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x4612c8e2 scsi_is_sas_rphy +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x4f70cdf9 sas_remove_host +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x573aced5 sas_remove_children +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x632f90d5 sas_expander_alloc +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x70ec7938 sas_phy_delete +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x878bf0e2 sas_rphy_add +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x908be24d sas_port_alloc_num +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xa554dfab sas_port_mark_backlink +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xbe686530 sas_read_port_mode_page +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xc897fcce sas_port_add +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xcfd69270 scsi_is_sas_port +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xd17d88d2 sas_attach_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xd8369f09 sas_phy_alloc +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xe13b0587 sas_release_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xe2a6f893 sas_rphy_remove +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xe5fdb578 sas_rphy_delete +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xf7703b28 sas_port_delete_phy +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xf85088e8 sas_end_device_alloc +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0x3686ea09 spi_print_msg +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0x7941fa2b spi_release_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0xa2f2fa9f spi_attach_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0xac051d20 spi_dv_device +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0xcdcea05a spi_display_xfer_agreement +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0xe95496b5 spi_schedule_dv_device +EXPORT_SYMBOL drivers/ssb/ssb 0x025eb6a4 ssb_bus_resume +EXPORT_SYMBOL drivers/ssb/ssb 0x0916a1d4 ssb_dma_set_mask +EXPORT_SYMBOL drivers/ssb/ssb 0x14860c85 ssb_device_enable +EXPORT_SYMBOL drivers/ssb/ssb 0x2ff71338 ssb_dma_alloc_consistent +EXPORT_SYMBOL drivers/ssb/ssb 0x320a877b ssb_bus_may_powerdown +EXPORT_SYMBOL drivers/ssb/ssb 0x33cc936c ssb_driver_unregister +EXPORT_SYMBOL drivers/ssb/ssb 0x3aa6eea8 ssb_bus_pcibus_register +EXPORT_SYMBOL drivers/ssb/ssb 0x40d2628e ssb_device_disable +EXPORT_SYMBOL drivers/ssb/ssb 0x5fdf0494 ssb_pcihost_register +EXPORT_SYMBOL drivers/ssb/ssb 0x6486065f ssb_clockspeed +EXPORT_SYMBOL drivers/ssb/ssb 0x6fca2f91 ssb_bus_unregister +EXPORT_SYMBOL drivers/ssb/ssb 0x9180d451 ssb_bus_powerup +EXPORT_SYMBOL drivers/ssb/ssb 0xa032e5e7 ssb_pcicore_dev_irqvecs_enable +EXPORT_SYMBOL drivers/ssb/ssb 0xa3907a95 ssb_bus_suspend +EXPORT_SYMBOL drivers/ssb/ssb 0xaca79f3a ssb_set_devtypedata +EXPORT_SYMBOL drivers/ssb/ssb 0xaefb3cec ssb_dma_translation +EXPORT_SYMBOL drivers/ssb/ssb 0xc0512e0f ssb_admatch_base +EXPORT_SYMBOL drivers/ssb/ssb 0xd016cf4c ssb_device_is_enabled +EXPORT_SYMBOL drivers/ssb/ssb 0xd0728ac6 __ssb_driver_register +EXPORT_SYMBOL drivers/ssb/ssb 0xd481192b ssb_admatch_size +EXPORT_SYMBOL drivers/ssb/ssb 0xf501179e ssb_dma_free_consistent +EXPORT_SYMBOL drivers/telephony/ixj 0xdba1b8f9 ixj_pcmcia_probe +EXPORT_SYMBOL drivers/telephony/phonedev 0x3a2f12eb phone_unregister_device +EXPORT_SYMBOL drivers/telephony/phonedev 0xe6da25da phone_register_device +EXPORT_SYMBOL drivers/usb/gadget/net2280 0x0298e812 usb_gadget_unregister_driver +EXPORT_SYMBOL drivers/usb/gadget/net2280 0x8ff41b9d net2280_set_fifo_mode +EXPORT_SYMBOL drivers/usb/gadget/net2280 0xefba764c usb_gadget_register_driver +EXPORT_SYMBOL drivers/usb/host/sl811-hcd 0xe02e02df sl811h_driver +EXPORT_SYMBOL drivers/usb/serial/usbserial 0x11fa5198 usb_serial_resume +EXPORT_SYMBOL drivers/usb/serial/usbserial 0x70abe10d usb_serial_suspend +EXPORT_SYMBOL drivers/video/backlight/corgi_bl 0xc86baa7c corgibl_limit_intensity +EXPORT_SYMBOL drivers/video/backlight/lcd 0x18b87ebe lcd_device_unregister +EXPORT_SYMBOL drivers/video/backlight/lcd 0xff095381 lcd_device_register +EXPORT_SYMBOL drivers/video/console/bitblit 0xd40e5484 fbcon_set_bitops +EXPORT_SYMBOL drivers/video/console/font 0x09c8eb55 font_vga_8x16 +EXPORT_SYMBOL drivers/video/console/font 0xbb99125c get_default_font +EXPORT_SYMBOL drivers/video/console/font 0xf7584a9c find_font +EXPORT_SYMBOL drivers/video/console/softcursor 0xd592612e soft_cursor +EXPORT_SYMBOL drivers/video/console/tileblit 0x88c552af fbcon_set_tileops +EXPORT_SYMBOL drivers/video/cyber2000fb 0x0cc3ede5 cyber2000fb_detach +EXPORT_SYMBOL drivers/video/cyber2000fb 0x5a1c5311 cyber2000fb_attach +EXPORT_SYMBOL drivers/video/cyber2000fb 0x71cf1c66 cyber2000fb_disable_extregs +EXPORT_SYMBOL drivers/video/cyber2000fb 0x74133524 cyber2000fb_get_fb_var +EXPORT_SYMBOL drivers/video/cyber2000fb 0xc2d9f4d8 cyber2000fb_enable_extregs +EXPORT_SYMBOL drivers/video/display/display 0xa0745a39 display_device_register +EXPORT_SYMBOL drivers/video/display/display 0xc7f4b880 display_device_unregister +EXPORT_SYMBOL drivers/video/macmodes 0x08ed0b62 mac_vmode_to_var +EXPORT_SYMBOL drivers/video/macmodes 0x3453fbe1 mac_find_mode +EXPORT_SYMBOL drivers/video/macmodes 0xe2304303 mac_map_monitor_sense +EXPORT_SYMBOL drivers/video/matrox/g450_pll 0x8767572c matroxfb_g450_setclk +EXPORT_SYMBOL drivers/video/matrox/g450_pll 0x8806a325 g450_mnp2f +EXPORT_SYMBOL drivers/video/matrox/g450_pll 0x8e2c5e2e matroxfb_g450_setpll_cond +EXPORT_SYMBOL drivers/video/matrox/matroxfb_DAC1064 0x2f8f5b0f matrox_G100 +EXPORT_SYMBOL drivers/video/matrox/matroxfb_DAC1064 0x778d37a8 DAC1064_global_init +EXPORT_SYMBOL drivers/video/matrox/matroxfb_DAC1064 0xa129af3d DAC1064_global_restore +EXPORT_SYMBOL drivers/video/matrox/matroxfb_DAC1064 0xf537a96d matrox_mystique +EXPORT_SYMBOL drivers/video/matrox/matroxfb_Ti3026 0x2c85d5d0 matrox_millennium +EXPORT_SYMBOL drivers/video/matrox/matroxfb_accel 0xbe24c758 matrox_cfbX_init +EXPORT_SYMBOL drivers/video/matrox/matroxfb_base 0x10ec53e9 matroxfb_enable_irq +EXPORT_SYMBOL drivers/video/matrox/matroxfb_base 0x11813a23 matroxfb_unregister_driver +EXPORT_SYMBOL drivers/video/matrox/matroxfb_base 0x1307c303 matroxfb_wait_for_sync +EXPORT_SYMBOL drivers/video/matrox/matroxfb_base 0x5c74f892 matroxfb_register_driver +EXPORT_SYMBOL drivers/video/matrox/matroxfb_g450 0x158ec337 matroxfb_g450_shutdown +EXPORT_SYMBOL drivers/video/matrox/matroxfb_g450 0x874dc8b6 matroxfb_g450_connect +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0x07165ea1 matroxfb_DAC_in +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0x25cf8049 matroxfb_PLL_calcclock +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0x988a1625 matroxfb_read_pins +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0xa10a85ff matroxfb_DAC_out +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0xabd8e427 matroxfb_var2my +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0xc975df3c matroxfb_vgaHWinit +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0xef62ea47 matroxfb_vgaHWrestore +EXPORT_SYMBOL drivers/video/output 0x0948c179 video_output_unregister +EXPORT_SYMBOL drivers/video/output 0x81ec7b94 video_output_register +EXPORT_SYMBOL drivers/video/sis/sisfb 0x3037658e sis_malloc +EXPORT_SYMBOL drivers/video/sis/sisfb 0x454a3cf0 sis_free +EXPORT_SYMBOL drivers/video/svgalib 0x00d1fce9 svga_set_default_seq_regs +EXPORT_SYMBOL drivers/video/svgalib 0x07b3da30 svga_wseq_multi +EXPORT_SYMBOL drivers/video/svgalib 0x1b95c56a svga_check_timings +EXPORT_SYMBOL drivers/video/svgalib 0x33e87efa svga_get_caps +EXPORT_SYMBOL drivers/video/svgalib 0x48ef4193 svga_get_tilemax +EXPORT_SYMBOL drivers/video/svgalib 0x63e898d1 svga_set_default_crt_regs +EXPORT_SYMBOL drivers/video/svgalib 0x7a3ae959 svga_wcrt_multi +EXPORT_SYMBOL drivers/video/svgalib 0x80408443 svga_set_timings +EXPORT_SYMBOL drivers/video/svgalib 0x89d403d5 svga_tilefill +EXPORT_SYMBOL drivers/video/svgalib 0x8fa8438b svga_set_textmode_vga_regs +EXPORT_SYMBOL drivers/video/svgalib 0xab3b22ad svga_set_default_gfx_regs +EXPORT_SYMBOL drivers/video/svgalib 0xdad682b1 svga_set_default_atc_regs +EXPORT_SYMBOL drivers/video/svgalib 0xe165c5da svga_tilecursor +EXPORT_SYMBOL drivers/video/svgalib 0xe782167e svga_settile +EXPORT_SYMBOL drivers/video/svgalib 0xec83c473 svga_match_format +EXPORT_SYMBOL drivers/video/svgalib 0xef774f5d svga_compute_pll +EXPORT_SYMBOL drivers/video/svgalib 0xf8907b8e svga_tileblit +EXPORT_SYMBOL drivers/video/svgalib 0xfc337031 svga_tilecopy +EXPORT_SYMBOL drivers/video/syscopyarea 0x2a769f2f sys_copyarea +EXPORT_SYMBOL drivers/video/sysfillrect 0xf20fed33 sys_fillrect +EXPORT_SYMBOL drivers/video/sysimgblt 0x78762447 sys_imageblit +EXPORT_SYMBOL drivers/video/vgastate 0x686de290 restore_vga +EXPORT_SYMBOL drivers/video/vgastate 0xe7a2620e save_vga +EXPORT_SYMBOL drivers/w1/slaves/w1_ds2760 0x0a241503 w1_ds2760_read +EXPORT_SYMBOL drivers/w1/slaves/w1_ds2760 0x84bcae12 w1_ds2760_write +EXPORT_SYMBOL drivers/w1/wire 0x80ee4378 w1_register_family +EXPORT_SYMBOL drivers/w1/wire 0x8cf61660 w1_add_master_device +EXPORT_SYMBOL drivers/w1/wire 0x8da0a77e w1_unregister_family +EXPORT_SYMBOL drivers/w1/wire 0xcda061c0 w1_remove_master_device +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0x04e133fc iTCO_vendor_check_noreboot_on +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0x672c9d44 iTCO_vendor_pre_keepalive +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0xa78bd894 iTCO_vendor_pre_set_heartbeat +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0xa8d6daac iTCO_vendor_pre_start +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0xd0efe320 iTCO_vendor_pre_stop +EXPORT_SYMBOL fs/configfs/configfs 0x0e00306b config_item_set_name +EXPORT_SYMBOL fs/configfs/configfs 0x2072b1a8 configfs_undepend_item +EXPORT_SYMBOL fs/configfs/configfs 0x24127e1c config_item_put +EXPORT_SYMBOL fs/configfs/configfs 0x37c9ddd7 configfs_unregister_subsystem +EXPORT_SYMBOL fs/configfs/configfs 0x3f60a85a config_group_find_item +EXPORT_SYMBOL fs/configfs/configfs 0x43f02542 config_group_init +EXPORT_SYMBOL fs/configfs/configfs 0x4f09d1d8 config_item_init_type_name +EXPORT_SYMBOL fs/configfs/configfs 0x652e9f04 config_item_init +EXPORT_SYMBOL fs/configfs/configfs 0xaee88303 configfs_depend_item +EXPORT_SYMBOL fs/configfs/configfs 0xc63a33b9 config_item_get +EXPORT_SYMBOL fs/configfs/configfs 0xe3acb574 configfs_register_subsystem +EXPORT_SYMBOL fs/configfs/configfs 0xfd1a572d config_group_init_type_name +EXPORT_SYMBOL fs/jbd/jbd 0x0143e3b3 journal_unlock_updates +EXPORT_SYMBOL fs/jbd/jbd 0x0b065c07 journal_check_available_features +EXPORT_SYMBOL fs/jbd/jbd 0x0f209e46 journal_lock_updates +EXPORT_SYMBOL fs/jbd/jbd 0x10dd5f84 journal_stop +EXPORT_SYMBOL fs/jbd/jbd 0x1872f7b5 journal_start_commit +EXPORT_SYMBOL fs/jbd/jbd 0x287a5dbe journal_dirty_metadata +EXPORT_SYMBOL fs/jbd/jbd 0x2941d469 journal_init_inode +EXPORT_SYMBOL fs/jbd/jbd 0x29e0453a journal_get_undo_access +EXPORT_SYMBOL fs/jbd/jbd 0x2c6c508e journal_try_to_free_buffers +EXPORT_SYMBOL fs/jbd/jbd 0x324f2b97 journal_check_used_features +EXPORT_SYMBOL fs/jbd/jbd 0x3891352d journal_ack_err +EXPORT_SYMBOL fs/jbd/jbd 0x3cded738 journal_dirty_data +EXPORT_SYMBOL fs/jbd/jbd 0x4996c32d journal_wipe +EXPORT_SYMBOL fs/jbd/jbd 0x50195077 journal_update_format +EXPORT_SYMBOL fs/jbd/jbd 0x5361a98b journal_invalidatepage +EXPORT_SYMBOL fs/jbd/jbd 0x560e5b5e journal_load +EXPORT_SYMBOL fs/jbd/jbd 0x680376ef log_wait_commit +EXPORT_SYMBOL fs/jbd/jbd 0x71e3d94a journal_forget +EXPORT_SYMBOL fs/jbd/jbd 0x78a7e30e journal_restart +EXPORT_SYMBOL fs/jbd/jbd 0x7e238184 journal_extend +EXPORT_SYMBOL fs/jbd/jbd 0x806bf581 journal_force_commit +EXPORT_SYMBOL fs/jbd/jbd 0x80a4d6b7 journal_start +EXPORT_SYMBOL fs/jbd/jbd 0x894edc65 journal_clear_err +EXPORT_SYMBOL fs/jbd/jbd 0x897d2f48 journal_set_features +EXPORT_SYMBOL fs/jbd/jbd 0x96da887c journal_errno +EXPORT_SYMBOL fs/jbd/jbd 0x9ddcf2a9 journal_abort +EXPORT_SYMBOL fs/jbd/jbd 0xa89ad485 journal_force_commit_nested +EXPORT_SYMBOL fs/jbd/jbd 0xa9b31ee6 journal_get_write_access +EXPORT_SYMBOL fs/jbd/jbd 0xb76d6e22 journal_revoke +EXPORT_SYMBOL fs/jbd/jbd 0xce5ea039 journal_flush +EXPORT_SYMBOL fs/jbd/jbd 0xdb65f05b journal_get_create_access +EXPORT_SYMBOL fs/jbd/jbd 0xe1c96866 journal_destroy +EXPORT_SYMBOL fs/jbd/jbd 0xe61b8253 journal_release_buffer +EXPORT_SYMBOL fs/jbd/jbd 0xe815e7e8 journal_create +EXPORT_SYMBOL fs/jbd/jbd 0xea2cfe62 journal_init_dev +EXPORT_SYMBOL fs/jbd/jbd 0xf340545b journal_blocks_per_page +EXPORT_SYMBOL fs/jbd2/jbd2 0x00fff626 jbd2_journal_clear_err +EXPORT_SYMBOL fs/jbd2/jbd2 0x0496af0f jbd2_journal_dirty_metadata +EXPORT_SYMBOL fs/jbd2/jbd2 0x06c2ee31 jbd2_journal_force_commit_nested +EXPORT_SYMBOL fs/jbd2/jbd2 0x0909925b jbd2_journal_begin_ordered_truncate +EXPORT_SYMBOL fs/jbd2/jbd2 0x0b16ac0e jbd2_journal_init_jbd_inode +EXPORT_SYMBOL fs/jbd2/jbd2 0x0d7fb694 jbd2_journal_clear_features +EXPORT_SYMBOL fs/jbd2/jbd2 0x13193afb jbd2_journal_ack_err +EXPORT_SYMBOL fs/jbd2/jbd2 0x189f03e9 jbd2_journal_release_buffer +EXPORT_SYMBOL fs/jbd2/jbd2 0x21f6280c jbd2_journal_load +EXPORT_SYMBOL fs/jbd2/jbd2 0x2b47e4c0 jbd2_journal_unlock_updates +EXPORT_SYMBOL fs/jbd2/jbd2 0x348b6ce9 jbd2_journal_start_commit +EXPORT_SYMBOL fs/jbd2/jbd2 0x439662d2 jbd2_journal_lock_updates +EXPORT_SYMBOL fs/jbd2/jbd2 0x457f2136 jbd2_journal_update_format +EXPORT_SYMBOL fs/jbd2/jbd2 0x491451d3 jbd2_journal_stop +EXPORT_SYMBOL fs/jbd2/jbd2 0x51001eb6 jbd2_journal_start +EXPORT_SYMBOL fs/jbd2/jbd2 0x5436709a jbd2_journal_destroy +EXPORT_SYMBOL fs/jbd2/jbd2 0x5687fc62 jbd2_journal_check_used_features +EXPORT_SYMBOL fs/jbd2/jbd2 0x5ac76a63 jbd2_journal_get_create_access +EXPORT_SYMBOL fs/jbd2/jbd2 0x5d2d16f9 jbd2_journal_extend +EXPORT_SYMBOL fs/jbd2/jbd2 0x659c9065 jbd2_journal_invalidatepage +EXPORT_SYMBOL fs/jbd2/jbd2 0x70e18cc4 jbd2_journal_init_dev +EXPORT_SYMBOL fs/jbd2/jbd2 0x712bb010 jbd2_log_wait_commit +EXPORT_SYMBOL fs/jbd2/jbd2 0x71312431 jbd2_journal_flush +EXPORT_SYMBOL fs/jbd2/jbd2 0x71f147d8 jbd2_journal_get_write_access +EXPORT_SYMBOL fs/jbd2/jbd2 0x8bc0add3 jbd2_journal_get_undo_access +EXPORT_SYMBOL fs/jbd2/jbd2 0x8ecd0ecb jbd2_journal_set_features +EXPORT_SYMBOL fs/jbd2/jbd2 0x97828b58 jbd2_journal_file_inode +EXPORT_SYMBOL fs/jbd2/jbd2 0x98e4e9d0 jbd2_journal_try_to_free_buffers +EXPORT_SYMBOL fs/jbd2/jbd2 0x9ffa3097 jbd2_journal_create +EXPORT_SYMBOL fs/jbd2/jbd2 0xc5871752 jbd2_journal_wipe +EXPORT_SYMBOL fs/jbd2/jbd2 0xd88ddaa8 jbd2_journal_init_inode +EXPORT_SYMBOL fs/jbd2/jbd2 0xd8e0f532 jbd2_journal_revoke +EXPORT_SYMBOL fs/jbd2/jbd2 0xda2cbb97 jbd2_journal_forget +EXPORT_SYMBOL fs/jbd2/jbd2 0xe2a48c05 jbd2_journal_restart +EXPORT_SYMBOL fs/jbd2/jbd2 0xe4d17642 jbd2_journal_check_available_features +EXPORT_SYMBOL fs/jbd2/jbd2 0xe513119a jbd2_journal_blocks_per_page +EXPORT_SYMBOL fs/jbd2/jbd2 0xe8c66fcc jbd2_journal_release_jbd_inode +EXPORT_SYMBOL fs/jbd2/jbd2 0xf0eefc6e jbd2_journal_errno +EXPORT_SYMBOL fs/jbd2/jbd2 0xf5d39ad3 jbd2_journal_abort +EXPORT_SYMBOL fs/jbd2/jbd2 0xfb101f51 jbd2_journal_force_commit +EXPORT_SYMBOL fs/lockd/lockd 0x71e3dac2 nlmsvc_ops +EXPORT_SYMBOL fs/lockd/lockd 0x976e539e lockd_up +EXPORT_SYMBOL fs/lockd/lockd 0xa7b91a7b lockd_down +EXPORT_SYMBOL fs/lockd/lockd 0xad09c2db get_nfs_grace_period +EXPORT_SYMBOL fs/mbcache 0x0e973879 mb_cache_entry_find_next +EXPORT_SYMBOL fs/mbcache 0x1020a88a mb_cache_entry_free +EXPORT_SYMBOL fs/mbcache 0x3b1e3afb mb_cache_create +EXPORT_SYMBOL fs/mbcache 0x73dc74bb mb_cache_shrink +EXPORT_SYMBOL fs/mbcache 0x978f7629 mb_cache_entry_release +EXPORT_SYMBOL fs/mbcache 0xacc47a55 mb_cache_entry_insert +EXPORT_SYMBOL fs/mbcache 0xd5263820 mb_cache_destroy +EXPORT_SYMBOL fs/mbcache 0xea54ff88 mb_cache_entry_get +EXPORT_SYMBOL fs/mbcache 0xeb8facbb mb_cache_entry_find_first +EXPORT_SYMBOL fs/mbcache 0xf6655f1c mb_cache_entry_alloc +EXPORT_SYMBOL fs/nfs_common/nfs_acl 0x1f79e031 nfsacl_encode +EXPORT_SYMBOL fs/nfs_common/nfs_acl 0x522f1496 nfsacl_decode +EXPORT_SYMBOL fs/nfsd/nfsd 0x0f3e6e01 nfs4_acl_nfsv4_to_posix +EXPORT_SYMBOL fs/nfsd/nfsd 0x2095976a nfs4_acl_new +EXPORT_SYMBOL fs/nfsd/nfsd 0x35e33c1e nfs4_acl_write_who +EXPORT_SYMBOL fs/nfsd/nfsd 0x5a157ae4 nfs4_acl_get_whotype +EXPORT_SYMBOL fs/nfsd/nfsd 0x7ee78c79 nfs4_acl_posix_to_nfsv4 +EXPORT_SYMBOL fs/xfs/xfs 0x4c3bf9e6 xfs_qmcore_xfs +EXPORT_SYMBOL lib/crc-ccitt 0x3771b461 crc_ccitt +EXPORT_SYMBOL lib/crc-ccitt 0x75811312 crc_ccitt_table +EXPORT_SYMBOL lib/crc-itu-t 0xd29b009f crc_itu_t_table +EXPORT_SYMBOL lib/crc-itu-t 0xf5b4a948 crc_itu_t +EXPORT_SYMBOL lib/crc-t10dif 0xb6896671 crc_t10dif +EXPORT_SYMBOL lib/crc16 0x02a6ce5a crc16_table +EXPORT_SYMBOL lib/crc16 0x8ffdb3b8 crc16 +EXPORT_SYMBOL lib/crc7 0xa7587646 crc7 +EXPORT_SYMBOL lib/crc7 0xd80c3603 crc7_syndrome_table +EXPORT_SYMBOL lib/libcrc32c 0x2329b292 crc32c_be +EXPORT_SYMBOL lib/libcrc32c 0x37d0b921 crc32c_le +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0x315c65fd zlib_deflateInit2 +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0x48034724 zlib_deflateReset +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0xaf64ad0d zlib_deflate +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0xf0caf44b zlib_deflate_workspacesize +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0xf741c793 zlib_deflateEnd +EXPORT_SYMBOL net/802/p8023 0xb20ad96f make_8023_client +EXPORT_SYMBOL net/802/p8023 0xfea48b1f destroy_8023_client +EXPORT_SYMBOL net/9p/9pnet 0x00a6e1a5 p9_create_tclunk +EXPORT_SYMBOL net/9p/9pnet 0x0106a185 p9_create_tstat +EXPORT_SYMBOL net/9p/9pnet 0x0ce19b8e p9_client_clunk +EXPORT_SYMBOL net/9p/9pnet 0x15779868 p9_set_tag +EXPORT_SYMBOL net/9p/9pnet 0x21523da9 p9_create_tattach +EXPORT_SYMBOL net/9p/9pnet 0x2de2d9c1 p9_client_disconnect +EXPORT_SYMBOL net/9p/9pnet 0x309767d8 p9_deserialize_stat +EXPORT_SYMBOL net/9p/9pnet 0x3455711e p9_idpool_destroy +EXPORT_SYMBOL net/9p/9pnet 0x3490c6ee p9_client_uwrite +EXPORT_SYMBOL net/9p/9pnet 0x39d5d8db p9_client_walk +EXPORT_SYMBOL net/9p/9pnet 0x3d73a797 p9_errstr2errno +EXPORT_SYMBOL net/9p/9pnet 0x3e700a09 p9_client_create +EXPORT_SYMBOL net/9p/9pnet 0x465c4e6f p9_printfcall +EXPORT_SYMBOL net/9p/9pnet 0x47f2a66e v9fs_register_trans +EXPORT_SYMBOL net/9p/9pnet 0x507c9d70 p9_create_tauth +EXPORT_SYMBOL net/9p/9pnet 0x607b7ef1 p9_client_uread +EXPORT_SYMBOL net/9p/9pnet 0x6146a046 v9fs_get_default_trans +EXPORT_SYMBOL net/9p/9pnet 0x6461b8de p9_create_twrite +EXPORT_SYMBOL net/9p/9pnet 0x68845db8 p9_client_read +EXPORT_SYMBOL net/9p/9pnet 0x69e9d7f1 v9fs_get_trans_by_name +EXPORT_SYMBOL net/9p/9pnet 0x6f11c5c3 p9_create_twrite_u +EXPORT_SYMBOL net/9p/9pnet 0x71c7537d p9_create_tcreate +EXPORT_SYMBOL net/9p/9pnet 0x75d8133e p9_client_remove +EXPORT_SYMBOL net/9p/9pnet 0x81247f39 p9_create_tread +EXPORT_SYMBOL net/9p/9pnet 0x8432c83f p9_deserialize_fcall +EXPORT_SYMBOL net/9p/9pnet 0x88ffe05a p9_client_attach +EXPORT_SYMBOL net/9p/9pnet 0x8b43255b p9_client_open +EXPORT_SYMBOL net/9p/9pnet 0x950e6b03 p9_create_twstat +EXPORT_SYMBOL net/9p/9pnet 0x9f7827b7 p9_client_destroy +EXPORT_SYMBOL net/9p/9pnet 0xa9536064 p9_create_tversion +EXPORT_SYMBOL net/9p/9pnet 0xaab8671a p9_idpool_get +EXPORT_SYMBOL net/9p/9pnet 0xadfd597a p9_create_tremove +EXPORT_SYMBOL net/9p/9pnet 0xaf0f6154 p9_client_auth +EXPORT_SYMBOL net/9p/9pnet 0xb2005953 p9_client_dirread +EXPORT_SYMBOL net/9p/9pnet 0xcae61af3 p9_idpool_create +EXPORT_SYMBOL net/9p/9pnet 0xcafdee58 p9_client_write +EXPORT_SYMBOL net/9p/9pnet 0xd0faf92e p9_idpool_check +EXPORT_SYMBOL net/9p/9pnet 0xdc894ac7 p9_create_twalk +EXPORT_SYMBOL net/9p/9pnet 0xe58a3360 p9_error_init +EXPORT_SYMBOL net/9p/9pnet 0xe95a099f p9_client_fcreate +EXPORT_SYMBOL net/9p/9pnet 0xef7127b0 p9_idpool_put +EXPORT_SYMBOL net/9p/9pnet 0xf09b3efa p9_create_topen +EXPORT_SYMBOL net/9p/9pnet 0xf52d778a p9_client_readn +EXPORT_SYMBOL net/9p/9pnet 0xfa096122 v9fs_unregister_trans +EXPORT_SYMBOL net/9p/9pnet 0xfd4454c5 p9_client_wstat +EXPORT_SYMBOL net/9p/9pnet 0xfeb1fa64 p9_client_stat +EXPORT_SYMBOL net/9p/9pnet 0xfff27930 p9_create_tflush +EXPORT_SYMBOL net/appletalk/appletalk 0x0362edec atrtr_get_dev +EXPORT_SYMBOL net/appletalk/appletalk 0x1717224a atalk_find_dev_addr +EXPORT_SYMBOL net/appletalk/appletalk 0x219194f0 aarp_send_ddp +EXPORT_SYMBOL net/appletalk/appletalk 0x9d14fdcb alloc_ltalkdev +EXPORT_SYMBOL net/ax25/ax25 0x1379717f ax25_send_frame +EXPORT_SYMBOL net/ax25/ax25 0x1ddbf910 ax25_linkfail_register +EXPORT_SYMBOL net/ax25/ax25 0x242852b9 ax25_uid_policy +EXPORT_SYMBOL net/ax25/ax25 0x3b1a1ecb ax25_rebuild_header +EXPORT_SYMBOL net/ax25/ax25 0x3d2d82ec ax25_display_timer +EXPORT_SYMBOL net/ax25/ax25 0x4502c65a asc2ax +EXPORT_SYMBOL net/ax25/ax25 0x49ab5314 ax25_findbyuid +EXPORT_SYMBOL net/ax25/ax25 0x4dc00537 ax25_listen_release +EXPORT_SYMBOL net/ax25/ax25 0x53dea1ff ax2asc +EXPORT_SYMBOL net/ax25/ax25 0x6ef7cc7e ax25_header_ops +EXPORT_SYMBOL net/ax25/ax25 0x7caa2346 ax25_hard_header +EXPORT_SYMBOL net/ax25/ax25 0x8ede9e26 ax25_protocol_release +EXPORT_SYMBOL net/ax25/ax25 0x936b9ead ax25_find_cb +EXPORT_SYMBOL net/ax25/ax25 0xbae7cfa2 ax25_listen_register +EXPORT_SYMBOL net/ax25/ax25 0xc1444946 ax25cmp +EXPORT_SYMBOL net/ax25/ax25 0xd43ecbf1 null_ax25_address +EXPORT_SYMBOL net/ax25/ax25 0xfe9e133a ax25_linkfail_release +EXPORT_SYMBOL net/bluetooth/bluetooth 0x0123e4dd bt_sock_wait_state +EXPORT_SYMBOL net/bluetooth/bluetooth 0x049788ca hci_get_route +EXPORT_SYMBOL net/bluetooth/bluetooth 0x23db9cef bt_sock_recvmsg +EXPORT_SYMBOL net/bluetooth/bluetooth 0x28ff0d31 bt_sock_register +EXPORT_SYMBOL net/bluetooth/bluetooth 0x2ae399b8 bt_sock_unlink +EXPORT_SYMBOL net/bluetooth/bluetooth 0x417fa9d9 hci_resume_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0x45bc170f hci_conn_encrypt +EXPORT_SYMBOL net/bluetooth/bluetooth 0x4dd3dbbf hci_unregister_cb +EXPORT_SYMBOL net/bluetooth/bluetooth 0x54cf5789 bt_sock_link +EXPORT_SYMBOL net/bluetooth/bluetooth 0x5a8c057d hci_conn_change_link_key +EXPORT_SYMBOL net/bluetooth/bluetooth 0x61a48176 hci_unregister_proto +EXPORT_SYMBOL net/bluetooth/bluetooth 0x69250321 hci_free_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0x6e77a253 hci_suspend_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0x7094f8ae bt_err +EXPORT_SYMBOL net/bluetooth/bluetooth 0x742b7082 bt_accept_unlink +EXPORT_SYMBOL net/bluetooth/bluetooth 0x76e3d52b bt_sock_ioctl +EXPORT_SYMBOL net/bluetooth/bluetooth 0x7f6632f9 bt_sock_poll +EXPORT_SYMBOL net/bluetooth/bluetooth 0x8338fa54 hci_send_acl +EXPORT_SYMBOL net/bluetooth/bluetooth 0x8bde1550 hci_connect +EXPORT_SYMBOL net/bluetooth/bluetooth 0x96b4ba4d hci_send_sco +EXPORT_SYMBOL net/bluetooth/bluetooth 0xa9197885 hci_recv_fragment +EXPORT_SYMBOL net/bluetooth/bluetooth 0xad916a0a hci_register_proto +EXPORT_SYMBOL net/bluetooth/bluetooth 0xbc858b55 hci_alloc_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0xc2066af0 batostr +EXPORT_SYMBOL net/bluetooth/bluetooth 0xc2bca0e8 hci_conn_check_link_mode +EXPORT_SYMBOL net/bluetooth/bluetooth 0xc44dec03 hci_conn_switch_role +EXPORT_SYMBOL net/bluetooth/bluetooth 0xc9b536d5 hci_conn_auth +EXPORT_SYMBOL net/bluetooth/bluetooth 0xcc1fb551 baswap +EXPORT_SYMBOL net/bluetooth/bluetooth 0xce9f25c7 hci_register_cb +EXPORT_SYMBOL net/bluetooth/bluetooth 0xed5862e8 bt_accept_dequeue +EXPORT_SYMBOL net/bluetooth/bluetooth 0xf19294db bt_sock_unregister +EXPORT_SYMBOL net/bluetooth/bluetooth 0xf5bf81ac bt_accept_enqueue +EXPORT_SYMBOL net/bluetooth/bluetooth 0xf61ace6b hci_unregister_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0xfec24a6b hci_register_dev +EXPORT_SYMBOL net/bluetooth/l2cap 0xfc31fe88 l2cap_load +EXPORT_SYMBOL net/bridge/bridge 0xb14653fd br_should_route_hook +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x1f6b317f ebt_register_target +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x20d99e90 ebt_do_table +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x3fd95217 ebt_unregister_target +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x4528d9b4 ebt_register_table +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x67e2df58 ebt_register_watcher +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x7aa33258 ebt_unregister_match +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x7cbb9986 ebt_register_match +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x8149d9d8 ebt_unregister_table +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x9b52cefb ebt_unregister_watcher +EXPORT_SYMBOL net/ieee80211/ieee80211 0x04e7c871 ieee80211_channel_to_freq +EXPORT_SYMBOL net/ieee80211/ieee80211 0x3232e7d9 ieee80211_wx_set_encode +EXPORT_SYMBOL net/ieee80211/ieee80211 0x3a914678 ieee80211_wx_get_encode +EXPORT_SYMBOL net/ieee80211/ieee80211 0x42b1db16 alloc_ieee80211 +EXPORT_SYMBOL net/ieee80211/ieee80211 0x42cbbd1f ieee80211_is_valid_channel +EXPORT_SYMBOL net/ieee80211/ieee80211 0x5204b834 ieee80211_wx_set_encodeext +EXPORT_SYMBOL net/ieee80211/ieee80211 0x60626d3d ieee80211_channel_to_index +EXPORT_SYMBOL net/ieee80211/ieee80211 0x727df091 ieee80211_wx_get_encodeext +EXPORT_SYMBOL net/ieee80211/ieee80211 0x906cffd2 ieee80211_wx_get_scan +EXPORT_SYMBOL net/ieee80211/ieee80211 0x910edb92 ieee80211_freq_to_channel +EXPORT_SYMBOL net/ieee80211/ieee80211 0x9b30fa6d free_ieee80211 +EXPORT_SYMBOL net/ieee80211/ieee80211 0x9d70601f ieee80211_rx_mgt +EXPORT_SYMBOL net/ieee80211/ieee80211 0x9da23022 ieee80211_get_geo +EXPORT_SYMBOL net/ieee80211/ieee80211 0xa9b783be ieee80211_get_channel_flags +EXPORT_SYMBOL net/ieee80211/ieee80211 0xa9fb135f escape_essid +EXPORT_SYMBOL net/ieee80211/ieee80211 0xbd3bfa6d ieee80211_set_geo +EXPORT_SYMBOL net/ieee80211/ieee80211 0xd0f00f44 ieee80211_rx +EXPORT_SYMBOL net/ieee80211/ieee80211 0xdfadafcd ieee80211_txb_free +EXPORT_SYMBOL net/ieee80211/ieee80211 0xee425dc6 ieee80211_get_channel +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x15dde1a8 ieee80211_get_crypto_ops +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x17799b42 ieee80211_crypt_deinit_entries +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x21152ede ieee80211_crypt_delayed_deinit +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x279e265f ieee80211_crypt_deinit_handler +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x50a50b3a ieee80211_crypt_quiescing +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0xb281f6e4 ieee80211_unregister_crypto_ops +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0xe943f14f ieee80211_register_crypto_ops +EXPORT_SYMBOL net/ipv4/inet_lro 0x05382f2f lro_flush_all +EXPORT_SYMBOL net/ipv4/inet_lro 0x31cddfa2 lro_vlan_hwaccel_receive_skb +EXPORT_SYMBOL net/ipv4/inet_lro 0x3d79840e lro_receive_skb +EXPORT_SYMBOL net/ipv4/inet_lro 0x731f3aae lro_vlan_hwaccel_receive_frags +EXPORT_SYMBOL net/ipv4/inet_lro 0x9f20fda9 lro_flush_pkt +EXPORT_SYMBOL net/ipv4/inet_lro 0xd14df7ef lro_receive_frags +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x01812ee0 register_ip_vs_app_inc +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x309b7ee3 ip_vs_conn_out_get +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x3ab5d840 unregister_ip_vs_app +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x40b6a1db ip_vs_conn_in_get +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x8e627302 ip_vs_conn_put +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x90b2fa48 ip_vs_tcp_conn_listen +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x98ef8929 ip_vs_skb_replace +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0xa1dbc2d8 ip_vs_proto_name +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0xb1fe37d3 register_ip_vs_scheduler +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0xb5bbf702 register_ip_vs_app +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0xd04eda23 unregister_ip_vs_scheduler +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0xdb1535ec ip_vs_conn_new +EXPORT_SYMBOL net/ipv4/netfilter/arp_tables 0x172c2b70 arpt_do_table +EXPORT_SYMBOL net/ipv4/netfilter/arp_tables 0x1b6a6225 arpt_register_table +EXPORT_SYMBOL net/ipv4/netfilter/arp_tables 0x34977271 arpt_unregister_table +EXPORT_SYMBOL net/ipv4/netfilter/ip_tables 0x46cef4ea ipt_unregister_table +EXPORT_SYMBOL net/ipv4/netfilter/ip_tables 0x8bd6e1c6 ipt_register_table +EXPORT_SYMBOL net/ipv4/netfilter/ip_tables 0xea9d0928 ipt_do_table +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0x093387d2 nf_nat_setup_info +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0x330ed74b nf_nat_mangle_udp_packet +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0x4d4086ff nf_nat_protocol_register +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0x5302b7d4 nf_nat_protocol_unregister +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0xae59cece nf_nat_mangle_tcp_packet +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0xcf5f7ac6 nf_nat_used_tuple +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0xff41b4e6 nf_nat_follow_master +EXPORT_SYMBOL net/ipv4/tunnel4 0x1475b07c xfrm4_tunnel_register +EXPORT_SYMBOL net/ipv4/tunnel4 0x8da6b639 xfrm4_tunnel_deregister +EXPORT_SYMBOL net/ipv6/ipv6 0x089ed7ca ip6_route_output +EXPORT_SYMBOL net/ipv6/ipv6 0x09a1466c inet6_bind +EXPORT_SYMBOL net/ipv6/ipv6 0x1da2d864 xfrm6_find_1stfragopt +EXPORT_SYMBOL net/ipv6/ipv6 0x2062d7eb ndisc_mc_map +EXPORT_SYMBOL net/ipv6/ipv6 0x247224c5 inet6_unregister_protosw +EXPORT_SYMBOL net/ipv6/ipv6 0x2d5e5378 xfrm6_rcv_spi +EXPORT_SYMBOL net/ipv6/ipv6 0x30123eb5 icmpv6_statistics +EXPORT_SYMBOL net/ipv6/ipv6 0x39176283 ipv6_dev_get_saddr +EXPORT_SYMBOL net/ipv6/ipv6 0x3fad008e inet6_getname +EXPORT_SYMBOL net/ipv6/ipv6 0x4381137a inet6_ioctl +EXPORT_SYMBOL net/ipv6/ipv6 0x538383c0 unregister_inet6addr_notifier +EXPORT_SYMBOL net/ipv6/ipv6 0x59ef9ac7 ip6_xmit +EXPORT_SYMBOL net/ipv6/ipv6 0x5e53fbef ipv6_chk_addr +EXPORT_SYMBOL net/ipv6/ipv6 0x5ff976fb ip6_frag_init +EXPORT_SYMBOL net/ipv6/ipv6 0x6228e2da nf_ip6_checksum +EXPORT_SYMBOL net/ipv6/ipv6 0x695e2640 inet6_del_protocol +EXPORT_SYMBOL net/ipv6/ipv6 0x784d8f4c inet6_register_protosw +EXPORT_SYMBOL net/ipv6/ipv6 0x883e428a ipv6_getsockopt +EXPORT_SYMBOL net/ipv6/ipv6 0x988b0a0d ip6_route_me_harder +EXPORT_SYMBOL net/ipv6/ipv6 0x9a1564e7 xfrm6_rcv +EXPORT_SYMBOL net/ipv6/ipv6 0xa56c6609 xfrm6_input_addr +EXPORT_SYMBOL net/ipv6/ipv6 0xad1d0215 in6_dev_finish_destroy +EXPORT_SYMBOL net/ipv6/ipv6 0xb339744a icmpv6_send +EXPORT_SYMBOL net/ipv6/ipv6 0xb8fb5941 ipv6_setsockopt +EXPORT_SYMBOL net/ipv6/ipv6 0xb905ad82 icmpv6_err_convert +EXPORT_SYMBOL net/ipv6/ipv6 0xc265ae06 rt6_lookup +EXPORT_SYMBOL net/ipv6/ipv6 0xc9e96030 xfrm6_prepare_output +EXPORT_SYMBOL net/ipv6/ipv6 0xce19bac5 register_inet6addr_notifier +EXPORT_SYMBOL net/ipv6/ipv6 0xd0ec672b ipv6_chk_prefix +EXPORT_SYMBOL net/ipv6/ipv6 0xdf35922d ipv6_push_nfrag_opts +EXPORT_SYMBOL net/ipv6/ipv6 0xe1a81c3a icmpv6msg_statistics +EXPORT_SYMBOL net/ipv6/ipv6 0xe690b8fd __ipv6_isatap_ifid +EXPORT_SYMBOL net/ipv6/ipv6 0xeaf641a5 inet6_release +EXPORT_SYMBOL net/ipv6/ipv6 0xf63c3e1a inet6_add_protocol +EXPORT_SYMBOL net/ipv6/ipv6 0xff0fbec8 ip6_frag_match +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0x518d5eb9 ip6t_unregister_table +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0x679bcc0e ip6t_register_table +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0x873d3272 ipv6_find_hdr +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0xb8bddf33 ip6t_ext_hdr +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0xc8e27d12 ip6t_do_table +EXPORT_SYMBOL net/ipv6/tunnel6 0x2adccbeb xfrm6_tunnel_register +EXPORT_SYMBOL net/ipv6/tunnel6 0x3b459620 xfrm6_tunnel_deregister +EXPORT_SYMBOL net/ipv6/xfrm6_tunnel 0x9cd013f2 xfrm6_tunnel_alloc_spi +EXPORT_SYMBOL net/ipv6/xfrm6_tunnel 0xab14e193 xfrm6_tunnel_free_spi +EXPORT_SYMBOL net/ipv6/xfrm6_tunnel 0xdb1b42d1 xfrm6_tunnel_spi_lookup +EXPORT_SYMBOL net/irda/ircomm/ircomm 0x2103c1fc ircomm_data_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0xace2774f ircomm_close +EXPORT_SYMBOL net/irda/ircomm/ircomm 0xaf5490e2 ircomm_open +EXPORT_SYMBOL net/irda/ircomm/ircomm 0xb9ca54fc ircomm_connect_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0xc45fc8cf ircomm_flow_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0xc4e48c8a ircomm_connect_response +EXPORT_SYMBOL net/irda/ircomm/ircomm 0xd5bb78f0 ircomm_disconnect_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0xd8b91695 ircomm_control_request +EXPORT_SYMBOL net/irda/irda 0x01d1fcdb hashbin_delete +EXPORT_SYMBOL net/irda/irda 0x062abb6c irttp_data_request +EXPORT_SYMBOL net/irda/irda 0x06a3ee58 irias_new_integer_value +EXPORT_SYMBOL net/irda/irda 0x072e026f irias_add_octseq_attrib +EXPORT_SYMBOL net/irda/irda 0x07d3647c irlmp_register_service +EXPORT_SYMBOL net/irda/irda 0x2036ad06 irda_param_insert +EXPORT_SYMBOL net/irda/irda 0x2643190e proc_irda +EXPORT_SYMBOL net/irda/irda 0x2a2cd33b async_unwrap_char +EXPORT_SYMBOL net/irda/irda 0x2b632ccb iriap_open +EXPORT_SYMBOL net/irda/irda 0x2e1fc239 irttp_open_tsap +EXPORT_SYMBOL net/irda/irda 0x32f78ac9 irlap_close +EXPORT_SYMBOL net/irda/irda 0x3462950f hashbin_remove +EXPORT_SYMBOL net/irda/irda 0x38a20e5b irda_debug +EXPORT_SYMBOL net/irda/irda 0x38f16934 irttp_flow_request +EXPORT_SYMBOL net/irda/irda 0x3fb332ed irlmp_connect_response +EXPORT_SYMBOL net/irda/irda 0x43e6c41c irttp_connect_response +EXPORT_SYMBOL net/irda/irda 0x448b8aaa irda_qos_bits_to_value +EXPORT_SYMBOL net/irda/irda 0x46006a24 alloc_irdadev +EXPORT_SYMBOL net/irda/irda 0x46c1c4a2 irlmp_unregister_service +EXPORT_SYMBOL net/irda/irda 0x4f3063c5 iriap_getvaluebyclass_request +EXPORT_SYMBOL net/irda/irda 0x59c388d2 irttp_dup +EXPORT_SYMBOL net/irda/irda 0x6758f8ac irias_new_object +EXPORT_SYMBOL net/irda/irda 0x686f458b irlmp_close_lsap +EXPORT_SYMBOL net/irda/irda 0x68b7447c hashbin_find +EXPORT_SYMBOL net/irda/irda 0x6b043eba irda_init_max_qos_capabilies +EXPORT_SYMBOL net/irda/irda 0x7042bc54 irlmp_register_client +EXPORT_SYMBOL net/irda/irda 0x747d6779 irias_delete_object +EXPORT_SYMBOL net/irda/irda 0x7621e908 hashbin_insert +EXPORT_SYMBOL net/irda/irda 0x76243bc9 irias_insert_object +EXPORT_SYMBOL net/irda/irda 0x763e54a4 irlmp_unregister_client +EXPORT_SYMBOL net/irda/irda 0x781e2db5 irias_find_object +EXPORT_SYMBOL net/irda/irda 0x7957f728 irlmp_update_client +EXPORT_SYMBOL net/irda/irda 0x7a57b6f3 hashbin_remove_this +EXPORT_SYMBOL net/irda/irda 0x80603253 irttp_close_tsap +EXPORT_SYMBOL net/irda/irda 0x80bf4452 irlmp_connect_request +EXPORT_SYMBOL net/irda/irda 0x8ae0d028 irlmp_disconnect_request +EXPORT_SYMBOL net/irda/irda 0x9078ce26 irttp_connect_request +EXPORT_SYMBOL net/irda/irda 0x91815586 irda_param_pack +EXPORT_SYMBOL net/irda/irda 0x95ccd2e0 async_wrap_skb +EXPORT_SYMBOL net/irda/irda 0x97c710aa irda_notify_init +EXPORT_SYMBOL net/irda/irda 0x993ad14b irda_param_extract_all +EXPORT_SYMBOL net/irda/irda 0xa3144642 irlap_open +EXPORT_SYMBOL net/irda/irda 0xa4a40929 iriap_close +EXPORT_SYMBOL net/irda/irda 0xab9dcf15 irlmp_open_lsap +EXPORT_SYMBOL net/irda/irda 0xb685eb84 irttp_disconnect_request +EXPORT_SYMBOL net/irda/irda 0xb9394173 irias_delete_value +EXPORT_SYMBOL net/irda/irda 0xbc982b38 irttp_udata_request +EXPORT_SYMBOL net/irda/irda 0xbcd3ef13 irias_object_change_attribute +EXPORT_SYMBOL net/irda/irda 0xbe40ace9 irlmp_discovery_request +EXPORT_SYMBOL net/irda/irda 0xc14e9b6a hashbin_get_next +EXPORT_SYMBOL net/irda/irda 0xcd41236c hashbin_new +EXPORT_SYMBOL net/irda/irda 0xd6deeaae irda_setup_dma +EXPORT_SYMBOL net/irda/irda 0xd7172ff4 hashbin_get_first +EXPORT_SYMBOL net/irda/irda 0xd8bfb6d4 hashbin_lock_find +EXPORT_SYMBOL net/irda/irda 0xde4c6b3c irlmp_service_to_hint +EXPORT_SYMBOL net/irda/irda 0xe5260e0e irias_add_integer_attrib +EXPORT_SYMBOL net/irda/irda 0xec41fe7f irias_add_string_attrib +EXPORT_SYMBOL net/irda/irda 0xedd521c2 irlmp_get_discoveries +EXPORT_SYMBOL net/irda/irda 0xefd08e31 irda_device_set_media_busy +EXPORT_SYMBOL net/irda/irda 0xfb4a1eaa irlmp_data_request +EXPORT_SYMBOL net/lapb/lapb 0x025e8676 lapb_disconnect_request +EXPORT_SYMBOL net/lapb/lapb 0x0748e562 lapb_getparms +EXPORT_SYMBOL net/lapb/lapb 0x50092f90 lapb_connect_request +EXPORT_SYMBOL net/lapb/lapb 0x78546fc1 lapb_register +EXPORT_SYMBOL net/lapb/lapb 0x823094d2 lapb_data_received +EXPORT_SYMBOL net/lapb/lapb 0x93330e79 lapb_data_request +EXPORT_SYMBOL net/lapb/lapb 0xa84fa15e lapb_setparms +EXPORT_SYMBOL net/lapb/lapb 0xc1a28a8d lapb_unregister +EXPORT_SYMBOL net/mac80211/mac80211 0x01ff4cb4 __ieee80211_get_radio_led_name +EXPORT_SYMBOL net/mac80211/mac80211 0x0b80a792 ieee80211_rate_control_register +EXPORT_SYMBOL net/mac80211/mac80211 0x1c926f6c ieee80211_rts_get +EXPORT_SYMBOL net/mac80211/mac80211 0x1cb3046a ieee80211_get_buffered_bc +EXPORT_SYMBOL net/mac80211/mac80211 0x25b87113 ieee80211_stop_queues +EXPORT_SYMBOL net/mac80211/mac80211 0x33b737da ieee80211_scan_completed +EXPORT_SYMBOL net/mac80211/mac80211 0x3d5b6923 __ieee80211_get_assoc_led_name +EXPORT_SYMBOL net/mac80211/mac80211 0x3e1aed4c ieee80211_rts_duration +EXPORT_SYMBOL net/mac80211/mac80211 0x49ef338b ieee80211_get_hdrlen +EXPORT_SYMBOL net/mac80211/mac80211 0x500f132a ieee80211_register_hw +EXPORT_SYMBOL net/mac80211/mac80211 0x509020e3 ieee80211_tx_status_irqsafe +EXPORT_SYMBOL net/mac80211/mac80211 0x539a9bb8 ieee80211_stop_tx_ba_session +EXPORT_SYMBOL net/mac80211/mac80211 0x5970a421 ieee80211_start_tx_ba_cb_irqsafe +EXPORT_SYMBOL net/mac80211/mac80211 0x5ce5aedf ieee80211_ctstoself_duration +EXPORT_SYMBOL net/mac80211/mac80211 0x5f113712 ieee80211_free_hw +EXPORT_SYMBOL net/mac80211/mac80211 0x60776390 ieee80211_wake_queue +EXPORT_SYMBOL net/mac80211/mac80211 0x6215a297 ieee80211_start_tx_ba_cb +EXPORT_SYMBOL net/mac80211/mac80211 0x66a92564 ieee80211_unregister_hw +EXPORT_SYMBOL net/mac80211/mac80211 0x6d28e989 __ieee80211_rx +EXPORT_SYMBOL net/mac80211/mac80211 0x74dd4fe6 ieee80211_get_tkip_key +EXPORT_SYMBOL net/mac80211/mac80211 0x7c6a4d51 ieee80211_start_tx_ba_session +EXPORT_SYMBOL net/mac80211/mac80211 0x8927fbe1 ieee80211_rate_control_unregister +EXPORT_SYMBOL net/mac80211/mac80211 0x8c35d732 ieee80211_hdrlen +EXPORT_SYMBOL net/mac80211/mac80211 0x8c38fa31 ieee80211_get_hdrlen_from_skb +EXPORT_SYMBOL net/mac80211/mac80211 0xae5cef28 ieee80211_tx_status +EXPORT_SYMBOL net/mac80211/mac80211 0xb5cca597 ieee80211_stop_tx_ba_cb +EXPORT_SYMBOL net/mac80211/mac80211 0xbd2fdfc5 ieee80211_notify_mac +EXPORT_SYMBOL net/mac80211/mac80211 0xbf0e3f77 ieee80211_ctstoself_get +EXPORT_SYMBOL net/mac80211/mac80211 0xca8bba24 ieee80211_stop_tx_ba_cb_irqsafe +EXPORT_SYMBOL net/mac80211/mac80211 0xcacea5d6 __ieee80211_get_tx_led_name +EXPORT_SYMBOL net/mac80211/mac80211 0xcf033f44 ieee80211_beacon_get +EXPORT_SYMBOL net/mac80211/mac80211 0xd775ccfc ieee80211_generic_frame_duration +EXPORT_SYMBOL net/mac80211/mac80211 0xdd54b520 __ieee80211_get_rx_led_name +EXPORT_SYMBOL net/mac80211/mac80211 0xddbd9e15 ieee80211_alloc_hw +EXPORT_SYMBOL net/mac80211/mac80211 0xe8f16e9f ieee80211_rx_irqsafe +EXPORT_SYMBOL net/mac80211/mac80211 0xefea3989 ieee80211_wake_queues +EXPORT_SYMBOL net/mac80211/mac80211 0xfb4ce9e9 ieee80211_stop_queue +EXPORT_SYMBOL net/mac80211/mac80211 0xfccc9480 sta_info_get +EXPORT_SYMBOL net/netfilter/nf_conntrack 0x8fb4ee7a __nf_ct_ext_destroy +EXPORT_SYMBOL net/netfilter/nf_conntrack 0xe372c1b6 __nf_ct_ext_add +EXPORT_SYMBOL net/netfilter/nf_conntrack 0xed23741c per_cpu__nf_conntrack_stat +EXPORT_SYMBOL net/netfilter/nf_conntrack_proto_gre 0x82f94e40 nf_ct_gre_keymap_flush +EXPORT_SYMBOL net/netfilter/x_tables 0x3dcd58c5 xt_alloc_table_info +EXPORT_SYMBOL net/netfilter/x_tables 0x4bf1b661 xt_unregister_matches +EXPORT_SYMBOL net/netfilter/x_tables 0x55ff592a xt_find_match +EXPORT_SYMBOL net/netfilter/x_tables 0x6c8dced4 xt_find_target +EXPORT_SYMBOL net/netfilter/x_tables 0x733c63f4 xt_register_target +EXPORT_SYMBOL net/netfilter/x_tables 0x89f7c75f xt_unregister_match +EXPORT_SYMBOL net/netfilter/x_tables 0xa825f382 xt_register_targets +EXPORT_SYMBOL net/netfilter/x_tables 0xc8e59071 xt_unregister_targets +EXPORT_SYMBOL net/netfilter/x_tables 0xcb2adab2 xt_register_match +EXPORT_SYMBOL net/netfilter/x_tables 0xe38ca08b xt_register_matches +EXPORT_SYMBOL net/netfilter/x_tables 0xf282243d xt_unregister_target +EXPORT_SYMBOL net/netfilter/x_tables 0xf7037dc6 xt_free_table_info +EXPORT_SYMBOL net/rfkill/rfkill 0x00caa4dc rfkill_switch_all +EXPORT_SYMBOL net/rfkill/rfkill 0x06fd7395 rfkill_force_state +EXPORT_SYMBOL net/rfkill/rfkill 0x382b61b2 rfkill_register +EXPORT_SYMBOL net/rfkill/rfkill 0x4fa781e3 rfkill_free +EXPORT_SYMBOL net/rfkill/rfkill 0x8002093b rfkill_allocate +EXPORT_SYMBOL net/rfkill/rfkill 0xeee38826 rfkill_unregister +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x1e5d2b8d rxrpc_kernel_get_abort_code +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x240e7910 rxrpc_get_null_key +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x2bb8fff7 rxrpc_kernel_reject_call +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x3e03db6f rxrpc_kernel_end_call +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x6b199f8a rxrpc_kernel_data_delivered +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x9c4a1336 rxrpc_kernel_intercept_rx_messages +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xa8d6f7a2 rxrpc_kernel_abort_call +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xb5fab354 rxrpc_kernel_get_error_number +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xb6c35c0a rxrpc_kernel_begin_call +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xbf659992 key_type_rxrpc +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xc6334f78 rxrpc_kernel_send_data +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xcad22bbe rxrpc_kernel_is_data_last +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xdb67f9b4 rxrpc_kernel_free_skb +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xf14764f8 rxrpc_kernel_accept_call +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xf23d902e rxrpc_get_server_data_key +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x00c52ef5 g_make_token_header +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x0348f912 gss_service_to_auth_domain_name +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x14fbb5b5 gss_mech_get +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x2c2d2217 gss_mech_get_by_name +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x3339c682 gss_mech_unregister +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x5edbfe95 gss_mech_put +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x74b86a97 gss_mech_register +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x7ba86ae9 gss_pseudoflavor_to_service +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x8d1a827e svcauth_gss_register_pseudoflavor +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xb5dea7ef g_token_size +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xbfe27012 gss_svc_to_pseudoflavor +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xc2945036 svcauth_gss_flavor +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xd5f5451a gss_mech_get_by_pseudoflavor +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xf8b2ff6e g_verify_token_header +EXPORT_SYMBOL net/sunrpc/sunrpc 0x03561364 svc_set_client +EXPORT_SYMBOL net/sunrpc/sunrpc 0x05e807a9 xdr_encode_string +EXPORT_SYMBOL net/sunrpc/sunrpc 0x065994f1 xdr_encode_opaque_fixed +EXPORT_SYMBOL net/sunrpc/sunrpc 0x0972e7e8 svc_authenticate +EXPORT_SYMBOL net/sunrpc/sunrpc 0x0f668ba9 svc_auth_unregister +EXPORT_SYMBOL net/sunrpc/sunrpc 0x12e280e3 svc_proc_unregister +EXPORT_SYMBOL net/sunrpc/sunrpc 0x1342fd2f cache_check +EXPORT_SYMBOL net/sunrpc/sunrpc 0x1998a638 xdr_buf_from_iov +EXPORT_SYMBOL net/sunrpc/sunrpc 0x1eaf8be3 xdr_inline_pages +EXPORT_SYMBOL net/sunrpc/sunrpc 0x23b0f2b3 svc_create +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2919b156 xdr_decode_string_inplace +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2ebb9394 svc_process +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2eec63c9 xdr_encode_netobj +EXPORT_SYMBOL net/sunrpc/sunrpc 0x36d6a30c xdr_process_buf +EXPORT_SYMBOL net/sunrpc/sunrpc 0x46785d45 svc_set_num_threads +EXPORT_SYMBOL net/sunrpc/sunrpc 0x46c54241 auth_domain_put +EXPORT_SYMBOL net/sunrpc/sunrpc 0x46f1de95 auth_domain_lookup +EXPORT_SYMBOL net/sunrpc/sunrpc 0x554b1765 cache_register +EXPORT_SYMBOL net/sunrpc/sunrpc 0x5b06d62f sunrpc_cache_lookup +EXPORT_SYMBOL net/sunrpc/sunrpc 0x5d215d40 svc_seq_show +EXPORT_SYMBOL net/sunrpc/sunrpc 0x5e714338 auth_domain_find +EXPORT_SYMBOL net/sunrpc/sunrpc 0x60c37c1f xdr_decode_array2 +EXPORT_SYMBOL net/sunrpc/sunrpc 0x638bafd6 xdr_reserve_space +EXPORT_SYMBOL net/sunrpc/sunrpc 0x64ab346d auth_unix_forget_old +EXPORT_SYMBOL net/sunrpc/sunrpc 0x67519771 svc_recv +EXPORT_SYMBOL net/sunrpc/sunrpc 0x69499127 svc_proc_register +EXPORT_SYMBOL net/sunrpc/sunrpc 0x6b0988e4 xdr_init_decode +EXPORT_SYMBOL net/sunrpc/sunrpc 0x6dd53729 svc_destroy +EXPORT_SYMBOL net/sunrpc/sunrpc 0x6e42596e svc_create_pooled +EXPORT_SYMBOL net/sunrpc/sunrpc 0x6eea229d svcauth_unix_purge +EXPORT_SYMBOL net/sunrpc/sunrpc 0x6f5be186 rpc_queue_upcall +EXPORT_SYMBOL net/sunrpc/sunrpc 0x6f91ab36 rpc_mkpipe +EXPORT_SYMBOL net/sunrpc/sunrpc 0x71fa908a cache_flush +EXPORT_SYMBOL net/sunrpc/sunrpc 0x7b1a5048 xdr_encode_pages +EXPORT_SYMBOL net/sunrpc/sunrpc 0x9e8105ed xdr_read_pages +EXPORT_SYMBOL net/sunrpc/sunrpc 0x9f47a6d1 xdr_buf_subsegment +EXPORT_SYMBOL net/sunrpc/sunrpc 0xa3db9cb7 xdr_shift_buf +EXPORT_SYMBOL net/sunrpc/sunrpc 0xa46b4f4c xdr_enter_page +EXPORT_SYMBOL net/sunrpc/sunrpc 0xad02dc7a xdr_encode_word +EXPORT_SYMBOL net/sunrpc/sunrpc 0xad382eeb svcauth_unix_set_client +EXPORT_SYMBOL net/sunrpc/sunrpc 0xae9ac3b0 cache_unregister +EXPORT_SYMBOL net/sunrpc/sunrpc 0xaead6c25 xdr_decode_word +EXPORT_SYMBOL net/sunrpc/sunrpc 0xb90504bb svc_sock_update_bufs +EXPORT_SYMBOL net/sunrpc/sunrpc 0xb9ac97b0 cache_purge +EXPORT_SYMBOL net/sunrpc/sunrpc 0xbb57afbf rpc_unlink +EXPORT_SYMBOL net/sunrpc/sunrpc 0xc3880471 xdr_decode_netobj +EXPORT_SYMBOL net/sunrpc/sunrpc 0xc4dd5bbc svc_sock_names +EXPORT_SYMBOL net/sunrpc/sunrpc 0xc85e9907 svc_auth_register +EXPORT_SYMBOL net/sunrpc/sunrpc 0xc8e96dea qword_addhex +EXPORT_SYMBOL net/sunrpc/sunrpc 0xce86d9f9 xdr_encode_array2 +EXPORT_SYMBOL net/sunrpc/sunrpc 0xcfc567af xdr_init_encode +EXPORT_SYMBOL net/sunrpc/sunrpc 0xd34f467d xdr_write_pages +EXPORT_SYMBOL net/sunrpc/sunrpc 0xd4cc9462 xdr_buf_read_netobj +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe14ab31d svc_wake_up +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe232f53a xdr_inline_decode +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe2602a9d svc_prepare_thread +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe4936643 unix_domain_find +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe5919cb1 xdr_encode_opaque +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe60fe8d7 sunrpc_cache_update +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe6d6e4e4 read_bytes_from_xdr_buf +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe8a90b07 svc_reserve +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe97f4ce5 qword_get +EXPORT_SYMBOL net/sunrpc/sunrpc 0xed8dd441 auth_unix_add_addr +EXPORT_SYMBOL net/sunrpc/sunrpc 0xedcf6be4 qword_add +EXPORT_SYMBOL net/sunrpc/sunrpc 0xf178189a svc_drop +EXPORT_SYMBOL net/sunrpc/sunrpc 0xfc65f5ac auth_unix_lookup +EXPORT_SYMBOL net/sunrpc/sunrpc 0xfd0122ea svc_exit_thread +EXPORT_SYMBOL net/tipc/tipc 0x08acf310 tipc_available_nodes +EXPORT_SYMBOL net/tipc/tipc 0x10d40fcd tipc_isconnected +EXPORT_SYMBOL net/tipc/tipc 0x1472b270 tipc_disconnect +EXPORT_SYMBOL net/tipc/tipc 0x1479cb03 tipc_deleteport +EXPORT_SYMBOL net/tipc/tipc 0x15b5ecde tipc_set_portunreliable +EXPORT_SYMBOL net/tipc/tipc 0x16f27683 tipc_block_bearer +EXPORT_SYMBOL net/tipc/tipc 0x22a66796 tipc_reject_msg +EXPORT_SYMBOL net/tipc/tipc 0x259b74f9 tipc_acknowledge +EXPORT_SYMBOL net/tipc/tipc 0x27d8bb58 tipc_send2port +EXPORT_SYMBOL net/tipc/tipc 0x2a696bcc tipc_send_buf_fast +EXPORT_SYMBOL net/tipc/tipc 0x310d1bc9 tipc_detach +EXPORT_SYMBOL net/tipc/tipc 0x3712e340 tipc_portunreliable +EXPORT_SYMBOL net/tipc/tipc 0x3976041f tipc_set_portimportance +EXPORT_SYMBOL net/tipc/tipc 0x4004f50a tipc_createport +EXPORT_SYMBOL net/tipc/tipc 0x40379ca6 tipc_register_media +EXPORT_SYMBOL net/tipc/tipc 0x4b2243c6 tipc_portimportance +EXPORT_SYMBOL net/tipc/tipc 0x4ba3cfc8 tipc_send2name +EXPORT_SYMBOL net/tipc/tipc 0x538b228a tipc_withdraw +EXPORT_SYMBOL net/tipc/tipc 0x5637ed44 tipc_get_mode +EXPORT_SYMBOL net/tipc/tipc 0x56e52bc1 tipc_continue +EXPORT_SYMBOL net/tipc/tipc 0x5c0d4b5c tipc_ref_valid +EXPORT_SYMBOL net/tipc/tipc 0x62a681a3 tipc_portunreturnable +EXPORT_SYMBOL net/tipc/tipc 0x64357d3c tipc_multicast +EXPORT_SYMBOL net/tipc/tipc 0x6608fde5 tipc_send_buf2port +EXPORT_SYMBOL net/tipc/tipc 0x78e2f96b tipc_forward_buf2name +EXPORT_SYMBOL net/tipc/tipc 0x8001e3d7 tipc_forward2port +EXPORT_SYMBOL net/tipc/tipc 0x88b73627 tipc_get_addr +EXPORT_SYMBOL net/tipc/tipc 0x89134236 tipc_createport_raw +EXPORT_SYMBOL net/tipc/tipc 0x8a3135ff tipc_forward_buf2port +EXPORT_SYMBOL net/tipc/tipc 0x99737465 tipc_send_buf +EXPORT_SYMBOL net/tipc/tipc 0x9c45558e tipc_enable_bearer +EXPORT_SYMBOL net/tipc/tipc 0xa936a24b tipc_get_port +EXPORT_SYMBOL net/tipc/tipc 0xadd203d0 tipc_connect2port +EXPORT_SYMBOL net/tipc/tipc 0xae0103c3 tipc_shutdown +EXPORT_SYMBOL net/tipc/tipc 0xb01ffc2c tipc_forward2name +EXPORT_SYMBOL net/tipc/tipc 0xb35b672c tipc_publish +EXPORT_SYMBOL net/tipc/tipc 0xbb2b2504 tipc_send +EXPORT_SYMBOL net/tipc/tipc 0xc7b5ee5a tipc_recv_msg +EXPORT_SYMBOL net/tipc/tipc 0xcec8514a tipc_set_portunreturnable +EXPORT_SYMBOL net/tipc/tipc 0xd44731e5 tipc_ownidentity +EXPORT_SYMBOL net/tipc/tipc 0xda7f9d3f tipc_attach +EXPORT_SYMBOL net/tipc/tipc 0xddb9ff3b tipc_send_buf2name +EXPORT_SYMBOL net/tipc/tipc 0xdf5008fc tipc_peer +EXPORT_SYMBOL net/tipc/tipc 0xe7aece47 tipc_ispublished +EXPORT_SYMBOL net/tipc/tipc 0xeefd49b3 tipc_get_handle +EXPORT_SYMBOL net/tipc/tipc 0xef50a1ef tipc_disable_bearer +EXPORT_SYMBOL net/wanrouter/wanrouter 0x0ebe03d1 unregister_wan_device +EXPORT_SYMBOL net/wanrouter/wanrouter 0x111f8bb6 register_wan_device +EXPORT_SYMBOL net/wireless/cfg80211 0x07e7ac5a ieee80211_radiotap_iterator_init +EXPORT_SYMBOL net/wireless/cfg80211 0x09c64fbd ieee80211_frequency_to_channel +EXPORT_SYMBOL net/wireless/cfg80211 0x3fbfb1f3 wiphy_register +EXPORT_SYMBOL net/wireless/cfg80211 0x433480bb __ieee80211_get_channel +EXPORT_SYMBOL net/wireless/cfg80211 0x70a8e730 wiphy_new +EXPORT_SYMBOL net/wireless/cfg80211 0x7d88b84c wiphy_free +EXPORT_SYMBOL net/wireless/cfg80211 0xb5463688 wiphy_unregister +EXPORT_SYMBOL net/wireless/cfg80211 0xc4e85ec5 ieee80211_radiotap_iterator_next +EXPORT_SYMBOL net/wireless/cfg80211 0xccc291b3 ieee80211_channel_to_frequency +EXPORT_SYMBOL sound/ac97_bus 0xb65a27a1 ac97_bus_type +EXPORT_SYMBOL sound/core/oss/snd-mixer-oss 0x4c588293 snd_mixer_oss_ioctl_card +EXPORT_SYMBOL sound/core/seq/snd-seq 0x14203a0b snd_seq_create_kernel_client +EXPORT_SYMBOL sound/core/seq/snd-seq 0x1a724fcc snd_seq_kernel_client_ctl +EXPORT_SYMBOL sound/core/seq/snd-seq 0x3061c52d snd_use_lock_sync_helper +EXPORT_SYMBOL sound/core/seq/snd-seq 0x3fb4d161 snd_seq_kernel_client_dispatch +EXPORT_SYMBOL sound/core/seq/snd-seq 0x68c82e57 snd_seq_kernel_client_write_poll +EXPORT_SYMBOL sound/core/seq/snd-seq 0x6bb71038 snd_seq_delete_kernel_client +EXPORT_SYMBOL sound/core/seq/snd-seq 0x7ac2f329 snd_seq_expand_var_event +EXPORT_SYMBOL sound/core/seq/snd-seq 0x7b8699eb snd_seq_event_port_detach +EXPORT_SYMBOL sound/core/seq/snd-seq 0xb8e448a0 snd_seq_set_queue_tempo +EXPORT_SYMBOL sound/core/seq/snd-seq 0xcac0a3be snd_seq_kernel_client_enqueue +EXPORT_SYMBOL sound/core/seq/snd-seq 0xcfe8e468 snd_seq_kernel_client_enqueue_blocking +EXPORT_SYMBOL sound/core/seq/snd-seq 0xe6f7b503 snd_seq_event_port_attach +EXPORT_SYMBOL sound/core/seq/snd-seq 0xe934da1d snd_seq_dump_var_event +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0x3a57f235 snd_seq_autoload_unlock +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0x6339b6d0 snd_seq_device_load_drivers +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0xa6f94d66 snd_seq_device_register_driver +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0xb90668b2 snd_seq_autoload_lock +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0xbb2487a5 snd_seq_device_new +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0xc622fb29 snd_seq_device_unregister_driver +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-emul 0x6ea09972 snd_midi_channel_alloc_set +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-emul 0x833a3e07 snd_midi_channel_set_clear +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-emul 0xb9948d2c snd_midi_channel_free_set +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-emul 0xf0a1fdb3 snd_midi_process_event +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x17c15809 snd_midi_event_decode +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x4ad3f518 snd_midi_event_reset_decode +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x62384d3a snd_midi_event_encode +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x8a348811 snd_midi_event_reset_encode +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x9df7af8b snd_midi_event_free +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0xc482499d snd_midi_event_new +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0xd9072e1a snd_midi_event_no_status +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0xe6df29c7 snd_midi_event_encode_byte +EXPORT_SYMBOL sound/core/seq/snd-seq-virmidi 0x189a115f snd_virmidi_new +EXPORT_SYMBOL sound/core/snd 0x0861d49a snd_info_create_module_entry +EXPORT_SYMBOL sound/core/snd 0x0c82e6ee snd_cards +EXPORT_SYMBOL sound/core/snd 0x18e1683f snd_dma_program +EXPORT_SYMBOL sound/core/snd 0x191e88cf snd_dma_pointer +EXPORT_SYMBOL sound/core/snd 0x198788b4 snd_lookup_oss_minor_data +EXPORT_SYMBOL sound/core/snd 0x1de4d8ce snd_card_free +EXPORT_SYMBOL sound/core/snd 0x213a009c snd_info_create_card_entry +EXPORT_SYMBOL sound/core/snd 0x24a94b26 snd_info_get_line +EXPORT_SYMBOL sound/core/snd 0x253d9df5 snd_seq_root +EXPORT_SYMBOL sound/core/snd 0x256bf7c0 snd_ctl_unregister_ioctl +EXPORT_SYMBOL sound/core/snd 0x2b30e6de snd_power_wait +EXPORT_SYMBOL sound/core/snd 0x2d3a848a snd_device_new +EXPORT_SYMBOL sound/core/snd 0x376e04bf release_and_free_resource +EXPORT_SYMBOL sound/core/snd 0x3971b4df snd_ecards_limit +EXPORT_SYMBOL sound/core/snd 0x3dd2a59c snd_ctl_add +EXPORT_SYMBOL sound/core/snd 0x47089922 snd_ctl_boolean_mono_info +EXPORT_SYMBOL sound/core/snd 0x4a3ea5c0 snd_request_card +EXPORT_SYMBOL sound/core/snd 0x52ce1605 snd_info_free_entry +EXPORT_SYMBOL sound/core/snd 0x52dd4a18 snd_add_device_sysfs_file +EXPORT_SYMBOL sound/core/snd 0x5a0076bf snd_card_file_remove +EXPORT_SYMBOL sound/core/snd 0x5af697c3 snd_ctl_find_numid +EXPORT_SYMBOL sound/core/snd 0x602c96f0 copy_to_user_fromio +EXPORT_SYMBOL sound/core/snd 0x644686f2 snd_mixer_oss_notify_callback +EXPORT_SYMBOL sound/core/snd 0x659b191b snd_ctl_free_one +EXPORT_SYMBOL sound/core/snd 0x65a8c586 snd_register_oss_device +EXPORT_SYMBOL sound/core/snd 0x70c15ac1 snd_dma_disable +EXPORT_SYMBOL sound/core/snd 0x7bef6949 snd_card_new +EXPORT_SYMBOL sound/core/snd 0x842c6d2b snd_ctl_rename_id +EXPORT_SYMBOL sound/core/snd 0x85357719 snd_ctl_new1 +EXPORT_SYMBOL sound/core/snd 0x8540e411 snd_device_free +EXPORT_SYMBOL sound/core/snd 0x862ec860 snd_device_register +EXPORT_SYMBOL sound/core/snd 0x87b0e2e0 snd_ctl_make_virtual_master +EXPORT_SYMBOL sound/core/snd 0x88610433 snd_ctl_remove +EXPORT_SYMBOL sound/core/snd 0x8c07124f snd_ctl_boolean_stereo_info +EXPORT_SYMBOL sound/core/snd 0x8df3789f snd_oss_info_register +EXPORT_SYMBOL sound/core/snd 0x8f595b11 snd_major +EXPORT_SYMBOL sound/core/snd 0x930b905b snd_ctl_register_ioctl +EXPORT_SYMBOL sound/core/snd 0xb213fe8b snd_info_get_str +EXPORT_SYMBOL sound/core/snd 0xb2e5ae4a snd_lookup_minor_data +EXPORT_SYMBOL sound/core/snd 0xb7dbfa60 snd_register_device_for_dev +EXPORT_SYMBOL sound/core/snd 0xb9d86cc4 snd_unregister_device +EXPORT_SYMBOL sound/core/snd 0xb9e74766 snd_card_free_when_closed +EXPORT_SYMBOL sound/core/snd 0xbf945f02 snd_card_register +EXPORT_SYMBOL sound/core/snd 0xc1b21cb1 snd_ctl_add_slave +EXPORT_SYMBOL sound/core/snd 0xc5840b14 snd_unregister_oss_device +EXPORT_SYMBOL sound/core/snd 0xc604a6ec snd_ctl_find_id +EXPORT_SYMBOL sound/core/snd 0xcb357faf snd_ctl_remove_id +EXPORT_SYMBOL sound/core/snd 0xcbf90854 snd_info_register +EXPORT_SYMBOL sound/core/snd 0xce3ca308 copy_from_user_toio +EXPORT_SYMBOL sound/core/snd 0xdf00f36b snd_card_disconnect +EXPORT_SYMBOL sound/core/snd 0xe32a5cf5 snd_ctl_notify +EXPORT_SYMBOL sound/core/snd 0xe4854cea snd_iprintf +EXPORT_SYMBOL sound/core/snd 0xebac32b3 snd_pci_quirk_lookup +EXPORT_SYMBOL sound/core/snd 0xf2896f84 snd_card_proc_new +EXPORT_SYMBOL sound/core/snd 0xf6a5c407 snd_card_file_add +EXPORT_SYMBOL sound/core/snd 0xf8a404b1 snd_component_add +EXPORT_SYMBOL sound/core/snd-hwdep 0x06d07731 snd_hwdep_new +EXPORT_SYMBOL sound/core/snd-page-alloc 0x16c34e9a snd_dma_reserve_buf +EXPORT_SYMBOL sound/core/snd-page-alloc 0x346e1919 snd_dma_alloc_pages_fallback +EXPORT_SYMBOL sound/core/snd-page-alloc 0x3b91f3af snd_free_pages +EXPORT_SYMBOL sound/core/snd-page-alloc 0x668992a5 snd_dma_free_pages +EXPORT_SYMBOL sound/core/snd-page-alloc 0x79676aa9 snd_dma_get_reserved_buf +EXPORT_SYMBOL sound/core/snd-page-alloc 0xade88e76 snd_malloc_pages +EXPORT_SYMBOL sound/core/snd-page-alloc 0xf676ccd2 snd_dma_alloc_pages +EXPORT_SYMBOL sound/core/snd-pcm 0x04cda566 snd_interval_refine +EXPORT_SYMBOL sound/core/snd-pcm 0x0724fd32 snd_pcm_mmap_data +EXPORT_SYMBOL sound/core/snd-pcm 0x08184b40 snd_pcm_hw_rule_add +EXPORT_SYMBOL sound/core/snd-pcm 0x0d07a760 snd_pcm_notify +EXPORT_SYMBOL sound/core/snd-pcm 0x1a2725e7 snd_pcm_hw_constraint_msbits +EXPORT_SYMBOL sound/core/snd-pcm 0x1a2c01a9 snd_pcm_lib_preallocate_pages_for_all +EXPORT_SYMBOL sound/core/snd-pcm 0x1a72bc73 snd_pcm_hw_constraint_ratnums +EXPORT_SYMBOL sound/core/snd-pcm 0x1d027e4b snd_pcm_format_signed +EXPORT_SYMBOL sound/core/snd-pcm 0x1d8a17c7 snd_pcm_release_substream +EXPORT_SYMBOL sound/core/snd-pcm 0x246a7a9d snd_pcm_lib_preallocate_pages +EXPORT_SYMBOL sound/core/snd-pcm 0x26da19e2 snd_pcm_lib_readv +EXPORT_SYMBOL sound/core/snd-pcm 0x2b17ab1e snd_pcm_suspend_all +EXPORT_SYMBOL sound/core/snd-pcm 0x30d7dbf6 snd_pcm_lib_mmap_iomem +EXPORT_SYMBOL sound/core/snd-pcm 0x3796bdcc snd_pcm_format_little_endian +EXPORT_SYMBOL sound/core/snd-pcm 0x458c038e snd_pcm_suspend +EXPORT_SYMBOL sound/core/snd-pcm 0x4c2eb761 snd_pcm_period_elapsed +EXPORT_SYMBOL sound/core/snd-pcm 0x4d9b6d35 snd_pcm_format_size +EXPORT_SYMBOL sound/core/snd-pcm 0x4f816e9b snd_pcm_format_big_endian +EXPORT_SYMBOL sound/core/snd-pcm 0x592be123 snd_pcm_hw_constraint_list +EXPORT_SYMBOL sound/core/snd-pcm 0x5beb17f1 snd_pcm_lib_preallocate_free_for_all +EXPORT_SYMBOL sound/core/snd-pcm 0x5d56a959 snd_pcm_hw_refine +EXPORT_SYMBOL sound/core/snd-pcm 0x5e4d9f8a snd_pcm_open_substream +EXPORT_SYMBOL sound/core/snd-pcm 0x5e7f4920 snd_pcm_format_set_silence +EXPORT_SYMBOL sound/core/snd-pcm 0x5fe19489 snd_pcm_stop +EXPORT_SYMBOL sound/core/snd-pcm 0x6385f68f snd_pcm_set_ops +EXPORT_SYMBOL sound/core/snd-pcm 0x650f8603 snd_pcm_format_silence_64 +EXPORT_SYMBOL sound/core/snd-pcm 0x68a24153 snd_pcm_format_physical_width +EXPORT_SYMBOL sound/core/snd-pcm 0x6b8bd7a2 snd_pcm_kernel_ioctl +EXPORT_SYMBOL sound/core/snd-pcm 0x6ef8fcd8 snd_pcm_format_linear +EXPORT_SYMBOL sound/core/snd-pcm 0x72488638 snd_pcm_new +EXPORT_SYMBOL sound/core/snd-pcm 0x7b074cea snd_pcm_hw_constraint_step +EXPORT_SYMBOL sound/core/snd-pcm 0x7c5cec98 _snd_pcm_hw_params_any +EXPORT_SYMBOL sound/core/snd-pcm 0x7efb3a3d snd_pcm_lib_free_pages +EXPORT_SYMBOL sound/core/snd-pcm 0x7f873fca snd_pcm_lib_read +EXPORT_SYMBOL sound/core/snd-pcm 0x88cc66cc snd_pcm_link_rwlock +EXPORT_SYMBOL sound/core/snd-pcm 0x89a31a56 _snd_pcm_hw_param_setempty +EXPORT_SYMBOL sound/core/snd-pcm 0x8ab99bec snd_pcm_hw_constraint_ratdens +EXPORT_SYMBOL sound/core/snd-pcm 0x93a8435c snd_pcm_set_sync +EXPORT_SYMBOL sound/core/snd-pcm 0x9c2a3376 snd_pcm_sgbuf_ops_page +EXPORT_SYMBOL sound/core/snd-pcm 0x9e8b024c snd_pcm_hw_constraint_minmax +EXPORT_SYMBOL sound/core/snd-pcm 0x9fdea959 snd_pcm_hw_param_value +EXPORT_SYMBOL sound/core/snd-pcm 0xa61aa028 snd_pcm_format_unsigned +EXPORT_SYMBOL sound/core/snd-pcm 0xa664267b snd_pcm_hw_param_first +EXPORT_SYMBOL sound/core/snd-pcm 0xa841d7e8 snd_pcm_lib_malloc_pages +EXPORT_SYMBOL sound/core/snd-pcm 0xaf842332 snd_pcm_lib_writev +EXPORT_SYMBOL sound/core/snd-pcm 0xb6def759 snd_pcm_lib_ioctl +EXPORT_SYMBOL sound/core/snd-pcm 0xb9638db4 snd_pcm_rate_to_rate_bit +EXPORT_SYMBOL sound/core/snd-pcm 0xd0b9b8b8 snd_interval_list +EXPORT_SYMBOL sound/core/snd-pcm 0xd6eb7eed snd_pcm_hw_param_last +EXPORT_SYMBOL sound/core/snd-pcm 0xda857458 snd_pcm_hw_constraint_integer +EXPORT_SYMBOL sound/core/snd-pcm 0xe1092ff6 snd_pcm_new_stream +EXPORT_SYMBOL sound/core/snd-pcm 0xe56a9336 snd_pcm_format_width +EXPORT_SYMBOL sound/core/snd-pcm 0xeab7348c snd_pcm_lib_write +EXPORT_SYMBOL sound/core/snd-pcm 0xefbe0d43 snd_pcm_limit_hw_rates +EXPORT_SYMBOL sound/core/snd-pcm 0xf2fdc728 snd_pcm_hw_constraint_pow2 +EXPORT_SYMBOL sound/core/snd-pcm 0xf3797152 snd_interval_ratnum +EXPORT_SYMBOL sound/core/snd-rawmidi 0x05ce58f3 snd_rawmidi_kernel_open +EXPORT_SYMBOL sound/core/snd-rawmidi 0x0808c554 snd_rawmidi_set_ops +EXPORT_SYMBOL sound/core/snd-rawmidi 0x1d0ca56c snd_rawmidi_drop_output +EXPORT_SYMBOL sound/core/snd-rawmidi 0x1eb589cf snd_rawmidi_input_params +EXPORT_SYMBOL sound/core/snd-rawmidi 0x2456c05d snd_rawmidi_transmit_peek +EXPORT_SYMBOL sound/core/snd-rawmidi 0x34aadd65 snd_rawmidi_transmit +EXPORT_SYMBOL sound/core/snd-rawmidi 0x4b0fd032 snd_rawmidi_receive +EXPORT_SYMBOL sound/core/snd-rawmidi 0x664ffdae snd_rawmidi_kernel_read +EXPORT_SYMBOL sound/core/snd-rawmidi 0x753426af snd_rawmidi_transmit_empty +EXPORT_SYMBOL sound/core/snd-rawmidi 0x80612c44 snd_rawmidi_output_params +EXPORT_SYMBOL sound/core/snd-rawmidi 0x970a0954 snd_rawmidi_drain_input +EXPORT_SYMBOL sound/core/snd-rawmidi 0xd76bac21 snd_rawmidi_new +EXPORT_SYMBOL sound/core/snd-rawmidi 0xdbd6492a snd_rawmidi_drain_output +EXPORT_SYMBOL sound/core/snd-rawmidi 0xe2ddaf28 snd_rawmidi_info_select +EXPORT_SYMBOL sound/core/snd-rawmidi 0xf3292c0e snd_rawmidi_kernel_write +EXPORT_SYMBOL sound/core/snd-rawmidi 0xfaa27856 snd_rawmidi_transmit_ack +EXPORT_SYMBOL sound/core/snd-rawmidi 0xffaeb6e0 snd_rawmidi_kernel_release +EXPORT_SYMBOL sound/core/snd-timer 0x1441ce4b snd_timer_interrupt +EXPORT_SYMBOL sound/core/snd-timer 0x36569dd4 snd_timer_global_free +EXPORT_SYMBOL sound/core/snd-timer 0x498e23f9 snd_timer_close +EXPORT_SYMBOL sound/core/snd-timer 0x56079c81 snd_timer_pause +EXPORT_SYMBOL sound/core/snd-timer 0x56289da1 snd_timer_stop +EXPORT_SYMBOL sound/core/snd-timer 0x5eb24c0f snd_timer_resolution +EXPORT_SYMBOL sound/core/snd-timer 0x6a76b63c snd_timer_notify +EXPORT_SYMBOL sound/core/snd-timer 0x7d8e4d7b snd_timer_global_register +EXPORT_SYMBOL sound/core/snd-timer 0x94715ba0 snd_timer_new +EXPORT_SYMBOL sound/core/snd-timer 0x981e17c5 snd_timer_start +EXPORT_SYMBOL sound/core/snd-timer 0xbfb6a378 snd_timer_global_new +EXPORT_SYMBOL sound/core/snd-timer 0xce73c3d3 snd_timer_continue +EXPORT_SYMBOL sound/core/snd-timer 0xff916ec9 snd_timer_open +EXPORT_SYMBOL sound/drivers/mpu401/snd-mpu401-uart 0x73c4c993 snd_mpu401_uart_interrupt_tx +EXPORT_SYMBOL sound/drivers/mpu401/snd-mpu401-uart 0x888152b8 snd_mpu401_uart_new +EXPORT_SYMBOL sound/drivers/mpu401/snd-mpu401-uart 0xfe618b58 snd_mpu401_uart_interrupt +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x05060a19 snd_opl3_regmap +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x0a0a5640 snd_opl3_interrupt +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x232961ef snd_opl3_init +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x2ee9fdbe snd_opl3_hwdep_new +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x820ece01 snd_opl3_timer_new +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0xad5b3183 snd_opl3_reset +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0xb035b92b snd_opl3_new +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0xbf38e75c snd_opl3_find_patch +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0xd45ac3a1 snd_opl3_load_patch +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0xd75f032d snd_opl3_create +EXPORT_SYMBOL sound/drivers/opl4/snd-opl4-lib 0x0e2d2155 snd_opl4_write +EXPORT_SYMBOL sound/drivers/opl4/snd-opl4-lib 0x1409172d snd_opl4_create +EXPORT_SYMBOL sound/drivers/opl4/snd-opl4-lib 0x6734a7de snd_opl4_write_memory +EXPORT_SYMBOL sound/drivers/opl4/snd-opl4-lib 0xaab14b6d snd_opl4_read +EXPORT_SYMBOL sound/drivers/opl4/snd-opl4-lib 0xd6b339aa snd_opl4_read_memory +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x1cadb14b snd_vx_irq_handler +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x207f8c9d snd_vx_dsp_load +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x353953d2 snd_vx_create +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x3cf04165 snd_vx_load_boot_image +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x55183fec snd_vx_resume +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x896b6d77 snd_vx_dsp_boot +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x8c3ee262 snd_vx_free_firmware +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x8e36596c snd_vx_check_reg_bit +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0xb8b667dd snd_vx_suspend +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0xe4edbaa2 snd_vx_setup_firmware +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0x01f88e54 snd_ak4114_build +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0x41e371a3 snd_ak4114_reinit +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0x722419ab snd_ak4114_create +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0x77418c9a snd_ak4114_reg_write +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0xe6c31d55 snd_ak4114_external_rate +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0xff40e624 snd_ak4114_check_rate_and_errors +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x4165390b snd_ak4117_check_rate_and_errors +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x47623f3c snd_ak4117_create +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x7853b5e6 snd_ak4117_reg_write +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x9db085b7 snd_ak4117_external_rate +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0xa247829b snd_ak4117_reinit +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0xb9412006 snd_ak4117_build +EXPORT_SYMBOL sound/i2c/other/snd-ak4xxx-adda 0x1155b138 snd_akm4xxx_reset +EXPORT_SYMBOL sound/i2c/other/snd-ak4xxx-adda 0x251b2b98 snd_akm4xxx_build_controls +EXPORT_SYMBOL sound/i2c/other/snd-ak4xxx-adda 0xa5858513 snd_akm4xxx_write +EXPORT_SYMBOL sound/i2c/other/snd-ak4xxx-adda 0xd320234a snd_akm4xxx_init +EXPORT_SYMBOL sound/i2c/other/snd-pt2258 0x7aab1206 snd_pt2258_reset +EXPORT_SYMBOL sound/i2c/other/snd-pt2258 0x90c16c28 snd_pt2258_build_controls +EXPORT_SYMBOL sound/i2c/other/snd-tea575x-tuner 0x1c4b085d snd_tea575x_init +EXPORT_SYMBOL sound/i2c/other/snd-tea575x-tuner 0x52e0df6c snd_tea575x_exit +EXPORT_SYMBOL sound/i2c/snd-cs8427 0x4381a4fb snd_cs8427_iec958_active +EXPORT_SYMBOL sound/i2c/snd-cs8427 0x4a671e50 snd_cs8427_iec958_pcm +EXPORT_SYMBOL sound/i2c/snd-cs8427 0x6342ef35 snd_cs8427_reg_write +EXPORT_SYMBOL sound/i2c/snd-cs8427 0x98a6adad snd_cs8427_create +EXPORT_SYMBOL sound/i2c/snd-cs8427 0xbdf68ee7 snd_cs8427_iec958_build +EXPORT_SYMBOL sound/i2c/snd-i2c 0x085417e6 snd_i2c_readbytes +EXPORT_SYMBOL sound/i2c/snd-i2c 0x32b626a4 snd_i2c_bus_create +EXPORT_SYMBOL sound/i2c/snd-i2c 0x5644129c snd_i2c_device_free +EXPORT_SYMBOL sound/i2c/snd-i2c 0x8de492ea snd_i2c_device_create +EXPORT_SYMBOL sound/i2c/snd-i2c 0xa3c6105a snd_i2c_probeaddr +EXPORT_SYMBOL sound/i2c/snd-i2c 0xe6e27bf0 snd_i2c_sendbytes +EXPORT_SYMBOL sound/i2c/snd-tea6330t 0x2637ad67 snd_tea6330t_update_mixer +EXPORT_SYMBOL sound/i2c/snd-tea6330t 0xb7b0e794 snd_tea6330t_detect +EXPORT_SYMBOL sound/isa/ad1848/snd-ad1848-lib 0x16aec7ba snd_ad1848_create +EXPORT_SYMBOL sound/isa/ad1848/snd-ad1848-lib 0x4082cec1 snd_ad1848_out +EXPORT_SYMBOL sound/isa/ad1848/snd-ad1848-lib 0x4f082481 snd_ad1848_add_ctl_elem +EXPORT_SYMBOL sound/isa/ad1848/snd-ad1848-lib 0x90f6214c snd_ad1848_get_pcm_ops +EXPORT_SYMBOL sound/isa/ad1848/snd-ad1848-lib 0xba797a6d snd_ad1848_mixer +EXPORT_SYMBOL sound/isa/ad1848/snd-ad1848-lib 0xe80cf05d snd_ad1848_pcm +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x138eb3b2 snd_cs4231_chip_id +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x2334b4bd snd_cs4231_overrange +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x2979a173 snd_cs4231_info_single +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x2c7d318b snd_cs4231_create +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x405e0605 snd_cs4231_mce_up +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x558f4a55 snd_cs4231_out +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x662e9e83 snd_cs4231_put_double +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x6b3213c0 snd_cs4231_pcm +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x6c373cf7 snd_cs4231_get_single +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x7bbc3a01 snd_cs4236_ext_out +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x849714c2 snd_cs4236_ext_in +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0x98b3a890 snd_cs4231_mixer +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0xa2a24a72 snd_cs4231_timer +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0xbb38a9aa snd_cs4231_interrupt +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0xc57e2991 snd_cs4231_get_double +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0xc820e791 snd_cs4231_in +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0xcf678be5 snd_cs4231_put_single +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0xdcc2949f snd_cs4231_info_double +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4231-lib 0xfb22a79a snd_cs4231_mce_down +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4236-lib 0x037eef81 snd_cs4236_create +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4236-lib 0x0823f3cd snd_cs4236_mixer +EXPORT_SYMBOL sound/isa/cs423x/snd-cs4236-lib 0xc56d49a9 snd_cs4236_pcm +EXPORT_SYMBOL sound/isa/es1688/snd-es1688-lib 0x2cb4d784 snd_es1688_mixer +EXPORT_SYMBOL sound/isa/es1688/snd-es1688-lib 0x4a2ff07c snd_es1688_mixer_write +EXPORT_SYMBOL sound/isa/es1688/snd-es1688-lib 0x6f33592f snd_es1688_create +EXPORT_SYMBOL sound/isa/es1688/snd-es1688-lib 0xe45b4cf9 snd_es1688_pcm +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x07708530 snd_gf1_free_voice +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x0ea82401 snd_gf1_look16 +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x15caa73f snd_gf1_i_look8 +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x2a88f594 snd_gf1_peek +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x391fb439 snd_gf1_i_look16 +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x3b8d7990 snd_gf1_translate_freq +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x3db6e104 snd_gus_use_inc +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x431980dc snd_gf1_dram_addr +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x46db8d67 snd_gf1_lvol_to_gvol_raw +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x50ee546b snd_gf1_write16 +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x5916baa9 snd_gf1_poke +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x5b66f850 snd_gus_use_dec +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x687e3bef snd_gf1_pcm_new +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x819fcbcb snd_gf1_write8 +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x8f17dc72 snd_gf1_stop_voice +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0x9d643089 snd_gf1_i_write8 +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xaa6ca82d snd_gf1_rawmidi_new +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xae72a767 snd_gf1_new_mixer +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xb5590a1b snd_gf1_write_addr +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xc31af61d snd_gf1_mem_alloc +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xc43a5527 snd_gf1_atten_table +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xc5d658a7 snd_gf1_alloc_voice +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xcba114fe snd_gus_dram_write +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xd7cde444 snd_gus_create +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xd85053ba snd_gf1_mem_free +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xdb252880 snd_gf1_mem_xfree +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xddecea44 snd_gus_dram_read +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xe7111bfa snd_gus_initialize +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xeca2dd3e snd_gf1_mem_lock +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xf4ff2f2d snd_gf1_look8 +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xf79fe968 snd_gf1_ctrl_stop +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xf963a997 snd_gus_interrupt +EXPORT_SYMBOL sound/isa/gus/snd-gus-lib 0xfa343e0a snd_gf1_delay +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x171537f0 snd_sbmixer_write +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x64b2518f snd_sbmixer_resume +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x6ac7dcd8 snd_sbdsp_reset +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x7d2b8d31 snd_sbdsp_create +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xbf5a6f18 snd_sbdsp_get_byte +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xcbec52f8 snd_sbdsp_command +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xcd04fa28 snd_sbmixer_new +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xd8c65e2f snd_sbmixer_suspend +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xe82b53be snd_sbmixer_read +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xf1ca193c snd_sbmixer_add_ctl +EXPORT_SYMBOL sound/isa/sb/snd-sb16-csp 0xa52a072a snd_sb_csp_new +EXPORT_SYMBOL sound/isa/sb/snd-sb16-dsp 0x0ba4ef1d snd_sb16dsp_interrupt +EXPORT_SYMBOL sound/isa/sb/snd-sb16-dsp 0x118b4f1d snd_sb16dsp_pcm +EXPORT_SYMBOL sound/isa/sb/snd-sb16-dsp 0x247fab9c snd_sb16dsp_get_pcm_ops +EXPORT_SYMBOL sound/isa/sb/snd-sb16-dsp 0x7545f62f snd_sb16dsp_configure +EXPORT_SYMBOL sound/isa/sb/snd-sb8-dsp 0x6adb9239 snd_sb8dsp_pcm +EXPORT_SYMBOL sound/isa/sb/snd-sb8-dsp 0xd785ab06 snd_sb8dsp_midi_interrupt +EXPORT_SYMBOL sound/isa/sb/snd-sb8-dsp 0xe8cccfd9 snd_sb8dsp_interrupt +EXPORT_SYMBOL sound/isa/sb/snd-sb8-dsp 0xea8d6b21 snd_sb8dsp_midi +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0x176e8bde snd_emu8000_peek +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0x3a94cb9f snd_emu8000_peek_dw +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0x5791d72b snd_emu8000_poke +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0x7c06a9b7 snd_emu8000_dma_chan +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0x8ba7df4e snd_emu8000_update_equalizer +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0xb63739e7 snd_emu8000_load_chorus_fx +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0xb9d52391 snd_emu8000_update_chorus_mode +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0xbb584a0f snd_emu8000_init_fm +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0xc7b18729 snd_emu8000_load_reverb_fx +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0xed76f758 snd_emu8000_poke_dw +EXPORT_SYMBOL sound/isa/sb/snd-sbawe 0xf4d81858 snd_emu8000_update_reverb_mode +EXPORT_SYMBOL sound/oss/ad1848 0x6c643a3b attach_ms_sound +EXPORT_SYMBOL sound/oss/ad1848 0x9839a618 probe_ms_sound +EXPORT_SYMBOL sound/oss/ad1848 0x9bf1cc62 ad1848_unload +EXPORT_SYMBOL sound/oss/ad1848 0xb29a9148 unload_ms_sound +EXPORT_SYMBOL sound/oss/ad1848 0xc04f6f67 ad1848_control +EXPORT_SYMBOL sound/oss/ad1848 0xe0f280b3 ad1848_init +EXPORT_SYMBOL sound/oss/ad1848 0xf06eb004 ad1848_detect +EXPORT_SYMBOL sound/oss/mpu401 0x1d98014e attach_mpu401 +EXPORT_SYMBOL sound/oss/mpu401 0x5febf284 unload_mpu401 +EXPORT_SYMBOL sound/oss/mpu401 0x8874e39a probe_mpu401 +EXPORT_SYMBOL sound/oss/msnd 0x1186f48f msnd_fifo_read +EXPORT_SYMBOL sound/oss/msnd 0x340a3ddf msnd_init_queue +EXPORT_SYMBOL sound/oss/msnd 0x3867b382 msnd_send_dsp_cmd +EXPORT_SYMBOL sound/oss/msnd 0x54230dc1 msnd_fifo_write +EXPORT_SYMBOL sound/oss/msnd 0x6601493b msnd_fifo_make_empty +EXPORT_SYMBOL sound/oss/msnd 0x8192a440 msnd_register +EXPORT_SYMBOL sound/oss/msnd 0x92098b5b msnd_send_word +EXPORT_SYMBOL sound/oss/msnd 0x9274d677 msnd_fifo_free +EXPORT_SYMBOL sound/oss/msnd 0x986ccb79 msnd_unregister +EXPORT_SYMBOL sound/oss/msnd 0xa0075e9f msnd_enable_irq +EXPORT_SYMBOL sound/oss/msnd 0xade99e25 msnd_fifo_alloc +EXPORT_SYMBOL sound/oss/msnd 0xb3520772 msnd_fifo_init +EXPORT_SYMBOL sound/oss/msnd 0xb46680d3 msnd_upload_host +EXPORT_SYMBOL sound/oss/msnd 0xc266c2da msnd_disable_irq +EXPORT_SYMBOL sound/oss/msnd 0xdf0f59eb msnd_fifo_write_io +EXPORT_SYMBOL sound/oss/msnd 0xf4c4f662 msnd_fifo_read_io +EXPORT_SYMBOL sound/oss/sb_lib 0x28f1fbe5 probe_sbmpu +EXPORT_SYMBOL sound/oss/sb_lib 0x42424109 sb_be_quiet +EXPORT_SYMBOL sound/oss/sb_lib 0x450f9aea smw_free +EXPORT_SYMBOL sound/oss/sb_lib 0x74afd69c unload_sbmpu +EXPORT_SYMBOL sound/oss/sb_lib 0x76479444 sb_dsp_init +EXPORT_SYMBOL sound/oss/sb_lib 0xc4884969 sb_dsp_unload +EXPORT_SYMBOL sound/oss/sb_lib 0xd8a2731c sb_dsp_detect +EXPORT_SYMBOL sound/oss/sound 0x04c87ec8 compute_finetune +EXPORT_SYMBOL sound/oss/sound 0x06339815 sound_unload_synthdev +EXPORT_SYMBOL sound/oss/sound 0x0f280035 conf_printf +EXPORT_SYMBOL sound/oss/sound 0x141cf792 midi_devs +EXPORT_SYMBOL sound/oss/sound 0x17ba231d seq_input_event +EXPORT_SYMBOL sound/oss/sound 0x1b3df3cf sound_alloc_mixerdev +EXPORT_SYMBOL sound/oss/sound 0x1f395686 MIDIbuf_avail +EXPORT_SYMBOL sound/oss/sound 0x2161d5e8 sound_timer_init +EXPORT_SYMBOL sound/oss/sound 0x21984561 sound_install_mixer +EXPORT_SYMBOL sound/oss/sound 0x2aa31695 midi_synth_kill_note +EXPORT_SYMBOL sound/oss/sound 0x2fff6b5f synth_devs +EXPORT_SYMBOL sound/oss/sound 0x394cb088 sound_free_dma +EXPORT_SYMBOL sound/oss/sound 0x418f5fbe sound_close_dma +EXPORT_SYMBOL sound/oss/sound 0x4cd01bdd num_audiodevs +EXPORT_SYMBOL sound/oss/sound 0x4ff47e9d midi_synth_setup_voice +EXPORT_SYMBOL sound/oss/sound 0x51e354b2 sound_alloc_timerdev +EXPORT_SYMBOL sound/oss/sound 0x56504ca2 midi_synth_reset +EXPORT_SYMBOL sound/oss/sound 0x5d986fc9 note_to_freq +EXPORT_SYMBOL sound/oss/sound 0x7679ee76 seq_copy_to_input +EXPORT_SYMBOL sound/oss/sound 0x7bdf0907 conf_printf2 +EXPORT_SYMBOL sound/oss/sound 0x892093e0 midi_synth_controller +EXPORT_SYMBOL sound/oss/sound 0x90bd9714 sequencer_timer +EXPORT_SYMBOL sound/oss/sound 0x987bcf12 DMAbuf_outputintr +EXPORT_SYMBOL sound/oss/sound 0x9a95733f sound_alloc_dma +EXPORT_SYMBOL sound/oss/sound 0x9bdaf24d midi_synth_start_note +EXPORT_SYMBOL sound/oss/sound 0x9d845b18 num_mixers +EXPORT_SYMBOL sound/oss/sound 0xa1d5f04f load_mixer_volumes +EXPORT_SYMBOL sound/oss/sound 0xa1eae7cf num_midis +EXPORT_SYMBOL sound/oss/sound 0xa41ead5f sound_unload_timerdev +EXPORT_SYMBOL sound/oss/sound 0xa51c913b sound_unload_mixerdev +EXPORT_SYMBOL sound/oss/sound 0xa6bb414c sound_unload_mididev +EXPORT_SYMBOL sound/oss/sound 0xa948751e sound_unload_audiodev +EXPORT_SYMBOL sound/oss/sound 0xad45df73 midi_synth_close +EXPORT_SYMBOL sound/oss/sound 0xae2d00f4 sound_install_audiodrv +EXPORT_SYMBOL sound/oss/sound 0xaef743b2 midi_synth_ioctl +EXPORT_SYMBOL sound/oss/sound 0xb14b22cd midi_synth_hw_control +EXPORT_SYMBOL sound/oss/sound 0xb51587f6 do_midi_msg +EXPORT_SYMBOL sound/oss/sound 0xba413f87 sound_alloc_mididev +EXPORT_SYMBOL sound/oss/sound 0xba7dd041 midi_synth_bender +EXPORT_SYMBOL sound/oss/sound 0xc748d109 sound_alloc_synthdev +EXPORT_SYMBOL sound/oss/sound 0xcb285f60 sound_timer_devs +EXPORT_SYMBOL sound/oss/sound 0xcc4b8797 sound_open_dma +EXPORT_SYMBOL sound/oss/sound 0xd85be938 midi_synth_set_instr +EXPORT_SYMBOL sound/oss/sound 0xd8a05be1 audio_devs +EXPORT_SYMBOL sound/oss/sound 0xdb400afa midi_synth_panning +EXPORT_SYMBOL sound/oss/sound 0xe056b71c DMAbuf_start_dma +EXPORT_SYMBOL sound/oss/sound 0xe2675a79 sound_timer_interrupt +EXPORT_SYMBOL sound/oss/sound 0xe2ddbf45 mixer_devs +EXPORT_SYMBOL sound/oss/sound 0xeb315d99 DMAbuf_inputintr +EXPORT_SYMBOL sound/oss/sound 0xf1ea8a20 midi_synth_aftertouch +EXPORT_SYMBOL sound/oss/sound 0xf6b3a2fb midi_synth_open +EXPORT_SYMBOL sound/oss/sound 0xf7426da3 midi_synth_load_patch +EXPORT_SYMBOL sound/oss/sound 0xf78f6363 sequencer_init +EXPORT_SYMBOL sound/oss/sound 0xfa6871be sound_timer_syncinterval +EXPORT_SYMBOL sound/oss/sound 0xfddcbfb3 midi_synth_send_sysex +EXPORT_SYMBOL sound/oss/uart401 0x46248c57 uart401intr +EXPORT_SYMBOL sound/oss/uart401 0x58854d40 probe_uart401 +EXPORT_SYMBOL sound/oss/uart401 0xecfdd9c9 unload_uart401 +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x02715b46 snd_ac97_tune_hardware +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x1c566317 snd_ac97_pcm_open +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x37547a14 snd_ac97_resume +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x38f2d500 snd_ac97_pcm_double_rate_rules +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x467d6b2c snd_ac97_update_power +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x5c4327a9 snd_ac97_bus +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x62c030f7 snd_ac97_set_rate +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x671042b6 snd_ac97_update_bits +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x737ad571 snd_ac97_suspend +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x78ae204a snd_ac97_get_short_name +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xac5f6738 snd_ac97_update +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xb6011c31 snd_ac97_write_cache +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xc1b40a61 snd_ac97_pcm_close +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xc3afb134 snd_ac97_mixer +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xd8e2991e snd_ac97_write +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xdcf73a1b snd_ac97_read +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xf854e792 snd_ac97_pcm_assign +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x11b08a59 snd_emu10k1_voice_free +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x2a83cd7d snd_emu10k1_synth_copy_from_user +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x3ae97c17 snd_emu10k1_synth_alloc +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x778a82d0 snd_emu10k1_memblk_map +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x93205c7f snd_emu10k1_ptr_read +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0xa44a2a07 snd_emu10k1_voice_alloc +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0xbc004fae snd_emu10k1_synth_free +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0xe6399f55 snd_emu10k1_synth_bzero +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0xfd7eafe7 snd_emu10k1_ptr_write +EXPORT_SYMBOL sound/pci/ice1712/snd-ice17xx-ak4xxx 0x1b87bfb8 snd_ice1712_akm4xxx_init +EXPORT_SYMBOL sound/pci/ice1712/snd-ice17xx-ak4xxx 0x62aa01a2 snd_ice1712_akm4xxx_free +EXPORT_SYMBOL sound/pci/ice1712/snd-ice17xx-ak4xxx 0x63bea5a7 snd_ice1712_akm4xxx_build_controls +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x004a2011 oxygen_write32_masked +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x0ca11091 oxygen_read16 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x1996df7f oxygen_pci_remove +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x22605ba8 oxygen_write32 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x282935ee oxygen_write16_masked +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x2c43a442 oxygen_read_ac97 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x369fbc5b oxygen_write_ac97 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x48f4d3bd oxygen_read8 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x61f326bc oxygen_write8_masked +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x77d9bc8d oxygen_pci_resume +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x8d4857d8 oxygen_write_ac97_masked +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xb1b796ee oxygen_write8 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xde53f053 oxygen_read32 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xe4bbd53f oxygen_write_i2c +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xeb9c4017 oxygen_write16 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xf58bf35c oxygen_pci_probe +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xf86bc556 oxygen_write_spi +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xfb6b2861 oxygen_pci_suspend +EXPORT_SYMBOL sound/pci/trident/snd-trident 0x2daf25a5 snd_trident_alloc_voice +EXPORT_SYMBOL sound/pci/trident/snd-trident 0x6aa379c8 snd_trident_stop_voice +EXPORT_SYMBOL sound/pci/trident/snd-trident 0x72921ba3 snd_trident_write_voice_regs +EXPORT_SYMBOL sound/pci/trident/snd-trident 0x83704dea snd_trident_start_voice +EXPORT_SYMBOL sound/pci/trident/snd-trident 0xba43673b snd_trident_free_voice +EXPORT_SYMBOL sound/sound_firmware 0x39e3dd23 mod_firmware_load +EXPORT_SYMBOL sound/soundcore 0x350c9931 register_sound_special_device +EXPORT_SYMBOL sound/soundcore 0x3fb2b3a6 register_sound_dsp +EXPORT_SYMBOL sound/soundcore 0x593ae1d1 register_sound_mixer +EXPORT_SYMBOL sound/soundcore 0x63b80c06 sound_class +EXPORT_SYMBOL sound/soundcore 0x7afc9d8a unregister_sound_mixer +EXPORT_SYMBOL sound/soundcore 0x99c95fa5 unregister_sound_special +EXPORT_SYMBOL sound/soundcore 0xa6654fd5 register_sound_midi +EXPORT_SYMBOL sound/soundcore 0xcd083b10 unregister_sound_dsp +EXPORT_SYMBOL sound/soundcore 0xf87ae7ce register_sound_special +EXPORT_SYMBOL sound/soundcore 0xfdab6de3 unregister_sound_midi +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x0e776733 snd_emux_unlock_voice +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x37afbe77 snd_emux_terminate_all +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x3a6ead48 snd_emux_lock_voice +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x655cb202 snd_sf_linear_to_log +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x925989c2 snd_emux_register +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0xab268576 snd_emux_free +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0xe1614bfc snd_emux_new +EXPORT_SYMBOL sound/synth/snd-util-mem 0x20d65978 snd_util_memhdr_free +EXPORT_SYMBOL sound/synth/snd-util-mem 0x24886293 __snd_util_mem_alloc +EXPORT_SYMBOL sound/synth/snd-util-mem 0x569d614e snd_util_mem_free +EXPORT_SYMBOL sound/synth/snd-util-mem 0x7a007343 snd_util_memhdr_new +EXPORT_SYMBOL sound/synth/snd-util-mem 0xd197c5db __snd_util_memblk_new +EXPORT_SYMBOL sound/synth/snd-util-mem 0xd34b56e4 __snd_util_mem_free +EXPORT_SYMBOL sound/synth/snd-util-mem 0xd8b55e81 snd_util_mem_alloc +EXPORT_SYMBOL sound/synth/snd-util-mem 0xf158252c snd_util_mem_avail +EXPORT_SYMBOL sound/usb/snd-usb-lib 0x16756dc0 snd_usbmidi_input_start +EXPORT_SYMBOL sound/usb/snd-usb-lib 0x63343b1d snd_usbmidi_input_stop +EXPORT_SYMBOL sound/usb/snd-usb-lib 0x6a3fe86d snd_usb_create_midi_interface +EXPORT_SYMBOL sound/usb/snd-usb-lib 0xd9d2bb03 snd_usbmidi_disconnect +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0x10f38e1e dm_mem_cache_grow +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0x17925a29 dm_mem_cache_free +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0x1a38c17a dm_mem_cache_client_create +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0x5ae80bdd dm_mem_cache_client_destroy +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0x864267ad dm_mem_cache_shrink +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0xb3d406a3 dm_mem_cache_alloc +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-message 0x920a7a41 dm_message_parse +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x0329d132 rh_sector_to_region +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x108f2649 rh_dec +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x275fdd04 rh_recovery_start +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x5c2a0632 rh_recovery_end +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x61444eb2 rh_bio_to_region +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x62842029 rh_flush +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x8252ef05 rh_state +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x8821f9a7 rh_region_to_sector +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x9143e533 rh_init +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xa4a7321f rh_get_region_key +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xa923d788 rh_start_recovery +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xac274ed3 rh_stop_recovery +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xb12ba46e rh_delay +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xb513be98 rh_update_states +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xbb748327 rh_reg_set_context +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xc4fdf256 rh_recovery_prepare +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xc4ff7745 rh_reg_get_context +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xc57bafec rh_exit +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xd99f0978 rh_inc +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xda581f7b rh_get_region_size +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xef444fb5 rh_delay_by_region +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xf156fc00 rh_inc_pending +EXPORT_SYMBOL ubuntu/lirc/lirc_cmdir/commandir 0x29c887a9 set_tx_channels +EXPORT_SYMBOL ubuntu/lirc/lirc_cmdir/commandir 0x60b2e316 cmdir_read +EXPORT_SYMBOL ubuntu/lirc/lirc_cmdir/commandir 0x7789312a cmdir_write +EXPORT_SYMBOL ubuntu/lirc/lirc_dev/lirc_dev 0x5d1bf3e8 lirc_get_pdata +EXPORT_SYMBOL ubuntu/lirc/lirc_dev/lirc_dev 0xabd610b3 lirc_register_plugin +EXPORT_SYMBOL ubuntu/lirc/lirc_dev/lirc_dev 0xe96379eb lirc_unregister_plugin +EXPORT_SYMBOL ubuntu/misc/media/ov511/ov511 0x34fa6dcd ov511_register_decomp_module +EXPORT_SYMBOL ubuntu/misc/media/ov511/ov511 0x7db9be3c ov511_deregister_decomp_module +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x1748d68d p80211netdev_hwremoved +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x1fbd435b p80211_suspend +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x2bb982b0 unregister_wlandev +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x3b60ab0d p80211netdev_rx +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x4b9a4fb4 register_wlandev +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x5557651b wlan_setup +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x96197861 p80211_allow_ioctls +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xb0af0799 wlan_wext_write +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xc580186c p80211_resume +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xd795d811 wlan_unsetup +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xe3ed89ed p80211skb_free +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xec90492b p80211skb_rxmeta_attach +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xf2ed8b92 p80211wext_event_associated +EXPORT_SYMBOL vmlinux 0x000bfa58 try_to_free_buffers +EXPORT_SYMBOL vmlinux 0x00112f51 groups_alloc +EXPORT_SYMBOL vmlinux 0x001ab40b end_request +EXPORT_SYMBOL vmlinux 0x00536561 xfrm_register_mode +EXPORT_SYMBOL vmlinux 0x0068bfee sock_no_getname +EXPORT_SYMBOL vmlinux 0x00694db2 pci_do_scan_bus +EXPORT_SYMBOL vmlinux 0x00701c0f put_io_context +EXPORT_SYMBOL vmlinux 0x00801678 flush_scheduled_work +EXPORT_SYMBOL vmlinux 0x0080fcd6 tcf_hash_release +EXPORT_SYMBOL vmlinux 0x008915d9 pci_enable_device_io +EXPORT_SYMBOL vmlinux 0x009d258f _write_lock +EXPORT_SYMBOL vmlinux 0x00e8097b csum_partial_copy_fromiovecend +EXPORT_SYMBOL vmlinux 0x00efda19 inet_stream_connect +EXPORT_SYMBOL vmlinux 0x01139ffc max_mapnr +EXPORT_SYMBOL vmlinux 0x0170d2ec alloc_pci_dev +EXPORT_SYMBOL vmlinux 0x0186d073 percpu_counter_set +EXPORT_SYMBOL vmlinux 0x01902adf netpoll_trap +EXPORT_SYMBOL vmlinux 0x01a4aab6 set_irq_chip_data +EXPORT_SYMBOL vmlinux 0x01ccc7e0 pci_release_selected_regions +EXPORT_SYMBOL vmlinux 0x01d19038 acpi_enable_subsystem +EXPORT_SYMBOL vmlinux 0x02124474 ip_send_check +EXPORT_SYMBOL vmlinux 0x02138f9d bioset_integrity_create +EXPORT_SYMBOL vmlinux 0x0230a1d2 dcache_dir_close +EXPORT_SYMBOL vmlinux 0x0237b57a arch_unregister_cpu +EXPORT_SYMBOL vmlinux 0x025277f6 profile_pc +EXPORT_SYMBOL vmlinux 0x0256389f bit_waitqueue +EXPORT_SYMBOL vmlinux 0x026154ee d_splice_alias +EXPORT_SYMBOL vmlinux 0x02649054 security_sock_rcv_skb +EXPORT_SYMBOL vmlinux 0x026aac61 dmam_free_coherent +EXPORT_SYMBOL vmlinux 0x029444f0 native_read_tsc +EXPORT_SYMBOL vmlinux 0x02a18c74 nf_conntrack_destroy +EXPORT_SYMBOL vmlinux 0x02aff2f4 acpi_install_gpe_handler +EXPORT_SYMBOL vmlinux 0x02b17d4e sock_init_data +EXPORT_SYMBOL vmlinux 0x02d14144 vm_get_page_prot +EXPORT_SYMBOL vmlinux 0x02d81845 audit_log_task_context +EXPORT_SYMBOL vmlinux 0x02d8c550 tty_port_init +EXPORT_SYMBOL vmlinux 0x02e84d1b per_cpu__cpu_sibling_map +EXPORT_SYMBOL vmlinux 0x02ee26c1 free_pages_exact +EXPORT_SYMBOL vmlinux 0x02fea7a7 xfrm_policy_walk +EXPORT_SYMBOL vmlinux 0x0313cdee alloc_netdev_mq +EXPORT_SYMBOL vmlinux 0x0334da4e scsi_command_size_tbl +EXPORT_SYMBOL vmlinux 0x037a0cba kfree +EXPORT_SYMBOL vmlinux 0x03a99c3b rb_prev +EXPORT_SYMBOL vmlinux 0x03c06156 bitmap_fold +EXPORT_SYMBOL vmlinux 0x040ca68d __xfrm_route_forward +EXPORT_SYMBOL vmlinux 0x041525ad xfrm_register_type +EXPORT_SYMBOL vmlinux 0x0422fe4a inet_csk_timer_bug_msg +EXPORT_SYMBOL vmlinux 0x04279179 rtnl_create_link +EXPORT_SYMBOL vmlinux 0x044fbf49 mempool_kzalloc +EXPORT_SYMBOL vmlinux 0x047b0dfd register_netdev +EXPORT_SYMBOL vmlinux 0x0487f831 fb_find_best_display +EXPORT_SYMBOL vmlinux 0x04b78d79 dev_get_by_index +EXPORT_SYMBOL vmlinux 0x04d8c750 release_perfctr_nmi +EXPORT_SYMBOL vmlinux 0x04f1862f audit_log_format +EXPORT_SYMBOL vmlinux 0x052de4c0 km_query +EXPORT_SYMBOL vmlinux 0x054b4ce3 pskb_copy +EXPORT_SYMBOL vmlinux 0x055afe9d tcp_recvmsg +EXPORT_SYMBOL vmlinux 0x0560cdeb xfrm_state_flush +EXPORT_SYMBOL vmlinux 0x0566a0c7 sock_register +EXPORT_SYMBOL vmlinux 0x057ce975 hex_dump_to_buffer +EXPORT_SYMBOL vmlinux 0x058c75d9 acpi_get_pci_id +EXPORT_SYMBOL vmlinux 0x05a362ef skb_queue_tail +EXPORT_SYMBOL vmlinux 0x05cbfa5e ps2_command +EXPORT_SYMBOL vmlinux 0x05f7b52f tty_insert_flip_string_flags +EXPORT_SYMBOL vmlinux 0x0604c556 kunmap_high +EXPORT_SYMBOL vmlinux 0x061651be strcat +EXPORT_SYMBOL vmlinux 0x067d8d35 security_release_secctx +EXPORT_SYMBOL vmlinux 0x06944942 netif_rx +EXPORT_SYMBOL vmlinux 0x06ad208c backlight_device_register +EXPORT_SYMBOL vmlinux 0x06d728b1 tcp_parse_md5sig_option +EXPORT_SYMBOL vmlinux 0x06d729ef xfrm_policy_insert +EXPORT_SYMBOL vmlinux 0x06eef5a7 inet_add_protocol +EXPORT_SYMBOL vmlinux 0x06fd22e2 input_register_handle +EXPORT_SYMBOL vmlinux 0x06fe3b14 default_grn +EXPORT_SYMBOL vmlinux 0x0722f714 acpi_is_video_device +EXPORT_SYMBOL vmlinux 0x0727c4f3 iowrite8 +EXPORT_SYMBOL vmlinux 0x073dfa12 generate_resume_trace +EXPORT_SYMBOL vmlinux 0x07608604 acpi_get_vendor_resource +EXPORT_SYMBOL vmlinux 0x0769ba84 xfrm_dst_ifdown +EXPORT_SYMBOL vmlinux 0x0796da32 call_usermodehelper_exec +EXPORT_SYMBOL vmlinux 0x0799aca4 local_bh_enable +EXPORT_SYMBOL vmlinux 0x079cd7f1 ns_to_timeval +EXPORT_SYMBOL vmlinux 0x07a890c8 fb_alloc_cmap +EXPORT_SYMBOL vmlinux 0x07ba90cb block_is_partially_uptodate +EXPORT_SYMBOL vmlinux 0x07cc4a5d printk_timed_ratelimit +EXPORT_SYMBOL vmlinux 0x07d50a24 csum_partial +EXPORT_SYMBOL vmlinux 0x07ec3c49 module_refcount +EXPORT_SYMBOL vmlinux 0x081a228d unregister_exec_domain +EXPORT_SYMBOL vmlinux 0x082c3213 pci_root_buses +EXPORT_SYMBOL vmlinux 0x0876365f generic_ro_fops +EXPORT_SYMBOL vmlinux 0x08d469e6 force_sig +EXPORT_SYMBOL vmlinux 0x0904db95 remap_vmalloc_range +EXPORT_SYMBOL vmlinux 0x09052c0c kset_unregister +EXPORT_SYMBOL vmlinux 0x092ca09a linkwatch_fire_event +EXPORT_SYMBOL vmlinux 0x0933aae1 efi_enabled +EXPORT_SYMBOL vmlinux 0x093e947e posix_acl_create_masq +EXPORT_SYMBOL vmlinux 0x0948cde9 num_physpages +EXPORT_SYMBOL vmlinux 0x094d9f3d d_path +EXPORT_SYMBOL vmlinux 0x096d342e unbind_con_driver +EXPORT_SYMBOL vmlinux 0x09775cdc kref_get +EXPORT_SYMBOL vmlinux 0x098b71c6 fb_dealloc_cmap +EXPORT_SYMBOL vmlinux 0x09c2638f bio_copy_user +EXPORT_SYMBOL vmlinux 0x09c55cec schedule_timeout_interruptible +EXPORT_SYMBOL vmlinux 0x09d44df9 in_lock_functions +EXPORT_SYMBOL vmlinux 0x09dfad8f elevator_init +EXPORT_SYMBOL vmlinux 0x09e502fe xfrm_policy_byid +EXPORT_SYMBOL vmlinux 0x09e5d30b netlink_kernel_create +EXPORT_SYMBOL vmlinux 0x0a03a696 tcp_timewait_state_process +EXPORT_SYMBOL vmlinux 0x0a06cde4 thermal_zone_bind_cooling_device +EXPORT_SYMBOL vmlinux 0x0a1b44f1 eth_rebuild_header +EXPORT_SYMBOL vmlinux 0x0a1e61f9 ethtool_op_set_tx_csum +EXPORT_SYMBOL vmlinux 0x0a2487e0 unblock_all_signals +EXPORT_SYMBOL vmlinux 0x0a3131f6 strnchr +EXPORT_SYMBOL vmlinux 0x0a49634c pci_bus_write_config_word +EXPORT_SYMBOL vmlinux 0x0a5130b4 update_region +EXPORT_SYMBOL vmlinux 0x0a544d0c lease_modify +EXPORT_SYMBOL vmlinux 0x0a7142f4 vmtruncate +EXPORT_SYMBOL vmlinux 0x0ab32c5d xfrm4_prepare_output +EXPORT_SYMBOL vmlinux 0x0acb1a3c __bitmap_shift_right +EXPORT_SYMBOL vmlinux 0x0ace23ff fb_get_mode +EXPORT_SYMBOL vmlinux 0x0acf4106 filemap_fdatawrite +EXPORT_SYMBOL vmlinux 0x0ae5d923 end_queued_request +EXPORT_SYMBOL vmlinux 0x0af7d079 tcp_prot +EXPORT_SYMBOL vmlinux 0x0afaabb6 clip_tbl_hook +EXPORT_SYMBOL vmlinux 0x0b1beb31 vmalloc_32_user +EXPORT_SYMBOL vmlinux 0x0b37813b bio_add_pc_page +EXPORT_SYMBOL vmlinux 0x0b4f405c datagram_poll +EXPORT_SYMBOL vmlinux 0x0b50ed94 tcp_initialize_rcv_mss +EXPORT_SYMBOL vmlinux 0x0b5b9322 pci_request_region +EXPORT_SYMBOL vmlinux 0x0b5e52fb generic_delete_inode +EXPORT_SYMBOL vmlinux 0x0b742fd7 simple_strtol +EXPORT_SYMBOL vmlinux 0x0bb89fb3 bio_copy_kern +EXPORT_SYMBOL vmlinux 0x0bbc4abf blk_init_queue_node +EXPORT_SYMBOL vmlinux 0x0bf3e283 tty_wait_until_sent +EXPORT_SYMBOL vmlinux 0x0bf84415 acpi_lock_ac_dir +EXPORT_SYMBOL vmlinux 0x0c0c99a7 genl_register_ops +EXPORT_SYMBOL vmlinux 0x0c2bada9 gnet_stats_start_copy_compat +EXPORT_SYMBOL vmlinux 0x0c364d78 tty_vhangup +EXPORT_SYMBOL vmlinux 0x0c5c69e3 flow_cache_lookup +EXPORT_SYMBOL vmlinux 0x0c5d5713 dmam_alloc_noncoherent +EXPORT_SYMBOL vmlinux 0x0c5ef91b per_cpu__vm_event_states +EXPORT_SYMBOL vmlinux 0x0c87c756 bio_split_pool +EXPORT_SYMBOL vmlinux 0x0cd895d3 poll_freewait +EXPORT_SYMBOL vmlinux 0x0ce1993b skb_insert +EXPORT_SYMBOL vmlinux 0x0cfb5e07 truncate_inode_pages_range +EXPORT_SYMBOL vmlinux 0x0cff66c3 fb_validate_mode +EXPORT_SYMBOL vmlinux 0x0d0d7b5e acpi_get_physical_pci_device +EXPORT_SYMBOL vmlinux 0x0d0dd460 simple_transaction_read +EXPORT_SYMBOL vmlinux 0x0d13a057 bdi_unregister +EXPORT_SYMBOL vmlinux 0x0d181112 iw_handler_set_thrspy +EXPORT_SYMBOL vmlinux 0x0d26a76d _write_lock_irq +EXPORT_SYMBOL vmlinux 0x0d384c76 inet_frag_evictor +EXPORT_SYMBOL vmlinux 0x0d3dda14 acpi_get_type +EXPORT_SYMBOL vmlinux 0x0d4b77b7 gen_pool_add +EXPORT_SYMBOL vmlinux 0x0d542439 __ipv6_addr_type +EXPORT_SYMBOL vmlinux 0x0d6c963c copy_from_user +EXPORT_SYMBOL vmlinux 0x0d805530 arp_broken_ops +EXPORT_SYMBOL vmlinux 0x0d853ab9 unregister_netdev +EXPORT_SYMBOL vmlinux 0x0d8ab500 param_set_copystring +EXPORT_SYMBOL vmlinux 0x0d8ac8db filemap_fdatawrite_range +EXPORT_SYMBOL vmlinux 0x0da10ec3 security_sock_graft +EXPORT_SYMBOL vmlinux 0x0dacb976 __elv_add_request +EXPORT_SYMBOL vmlinux 0x0dc86a98 blk_queue_find_tag +EXPORT_SYMBOL vmlinux 0x0de0acd4 blk_requeue_request +EXPORT_SYMBOL vmlinux 0x0deff780 pci_add_new_bus +EXPORT_SYMBOL vmlinux 0x0e0283e7 alloc_disk +EXPORT_SYMBOL vmlinux 0x0e358374 per_cpu__softnet_data +EXPORT_SYMBOL vmlinux 0x0e52592a panic +EXPORT_SYMBOL vmlinux 0x0e5e89b5 netlink_rcv_skb +EXPORT_SYMBOL vmlinux 0x0e6040c9 xfrm_register_km +EXPORT_SYMBOL vmlinux 0x0e762d6e request_module +EXPORT_SYMBOL vmlinux 0x0e8af647 neigh_lookup_nodev +EXPORT_SYMBOL vmlinux 0x0e9b0240 per_cpu__kstat +EXPORT_SYMBOL vmlinux 0x0eb668b6 proc_dointvec_userhz_jiffies +EXPORT_SYMBOL vmlinux 0x0ecc87f3 skb_realloc_headroom +EXPORT_SYMBOL vmlinux 0x0f0256b6 register_qdisc +EXPORT_SYMBOL vmlinux 0x0f46535e tty_register_device +EXPORT_SYMBOL vmlinux 0x0f8cbfc6 inode_needs_sync +EXPORT_SYMBOL vmlinux 0x0faef0ed __tasklet_schedule +EXPORT_SYMBOL vmlinux 0x0fd00a68 acpi_clear_event +EXPORT_SYMBOL vmlinux 0x0ff1bf4d inode_setattr +EXPORT_SYMBOL vmlinux 0x0ffac43a pci_fixup_device +EXPORT_SYMBOL vmlinux 0x0ffd3981 register_gifconf +EXPORT_SYMBOL vmlinux 0x1001b549 dmam_release_declared_memory +EXPORT_SYMBOL vmlinux 0x100ec1d6 dma_mark_declared_memory_occupied +EXPORT_SYMBOL vmlinux 0x10320d8f nf_unregister_queue_handler +EXPORT_SYMBOL vmlinux 0x10910040 fb_set_var +EXPORT_SYMBOL vmlinux 0x10a0f74a __inet6_lookup_established +EXPORT_SYMBOL vmlinux 0x10cf6de1 inet_frags_init +EXPORT_SYMBOL vmlinux 0x10cffbb2 generic_unplug_device +EXPORT_SYMBOL vmlinux 0x10eafade blk_complete_request +EXPORT_SYMBOL vmlinux 0x10ee20bb default_blu +EXPORT_SYMBOL vmlinux 0x11302ff3 dev_remove_pack +EXPORT_SYMBOL vmlinux 0x114c06d9 per_cpu__current_task +EXPORT_SYMBOL vmlinux 0x1158f758 sk_stream_write_space +EXPORT_SYMBOL vmlinux 0x11630341 pagevec_lookup +EXPORT_SYMBOL vmlinux 0x1163f0a7 blk_max_low_pfn +EXPORT_SYMBOL vmlinux 0x116b344c __dev_getfirstbyhwtype +EXPORT_SYMBOL vmlinux 0x117093be qdisc_class_hash_init +EXPORT_SYMBOL vmlinux 0x118e795c path_lookup +EXPORT_SYMBOL vmlinux 0x118f01ea putname +EXPORT_SYMBOL vmlinux 0x1198cf5b dev_mc_unsync +EXPORT_SYMBOL vmlinux 0x11a18b14 __wake_up_bit +EXPORT_SYMBOL vmlinux 0x11b846a4 uart_update_timeout +EXPORT_SYMBOL vmlinux 0x11c95f82 sk_filter +EXPORT_SYMBOL vmlinux 0x11f92998 ip_nat_decode_session +EXPORT_SYMBOL vmlinux 0x120507ac idr_get_new +EXPORT_SYMBOL vmlinux 0x122d2754 netif_rx_ni +EXPORT_SYMBOL vmlinux 0x124028b5 dev_alloc_name +EXPORT_SYMBOL vmlinux 0x125fbca7 cad_pid +EXPORT_SYMBOL vmlinux 0x126494ec pci_bus_read_config_dword +EXPORT_SYMBOL vmlinux 0x126970ed param_set_uint +EXPORT_SYMBOL vmlinux 0x129b1f23 udp_lib_getsockopt +EXPORT_SYMBOL vmlinux 0x12adfec6 neigh_table_clear +EXPORT_SYMBOL vmlinux 0x12cd5b4a tcf_hash_check +EXPORT_SYMBOL vmlinux 0x12da5bb2 __kmalloc +EXPORT_SYMBOL vmlinux 0x12f99022 inet_frags_init_net +EXPORT_SYMBOL vmlinux 0x132f45f2 cookie_check_timestamp +EXPORT_SYMBOL vmlinux 0x13781784 gnet_stats_finish_copy +EXPORT_SYMBOL vmlinux 0x1378e714 acpi_video_display_switch_support +EXPORT_SYMBOL vmlinux 0x137c27ba hippi_type_trans +EXPORT_SYMBOL vmlinux 0x13b02087 iget_failed +EXPORT_SYMBOL vmlinux 0x13f71731 tcf_hash_lookup +EXPORT_SYMBOL vmlinux 0x13feacaf tcf_em_tree_validate +EXPORT_SYMBOL vmlinux 0x13ff24b7 dmam_alloc_coherent +EXPORT_SYMBOL vmlinux 0x140bef27 iw_handler_get_spy +EXPORT_SYMBOL vmlinux 0x1430e6e0 unregister_acpi_notifier +EXPORT_SYMBOL vmlinux 0x1455a721 fasync_helper +EXPORT_SYMBOL vmlinux 0x1455b596 input_set_capability +EXPORT_SYMBOL vmlinux 0x148f1e0d xfrm_bundle_ok +EXPORT_SYMBOL vmlinux 0x1494507f vlan_ioctl_set +EXPORT_SYMBOL vmlinux 0x14a36e46 unregister_sysctl_table +EXPORT_SYMBOL vmlinux 0x14af0cf7 gen_pool_destroy +EXPORT_SYMBOL vmlinux 0x14bc1ed1 vfs_link +EXPORT_SYMBOL vmlinux 0x14c17a38 sync_mapping_buffers +EXPORT_SYMBOL vmlinux 0x14eb771a nla_put_nohdr +EXPORT_SYMBOL vmlinux 0x14f0ca9a dma_pool_destroy +EXPORT_SYMBOL vmlinux 0x14f332ea up_read +EXPORT_SYMBOL vmlinux 0x14feae82 xfrm_unregister_mode +EXPORT_SYMBOL vmlinux 0x150a6a1a user_path_at +EXPORT_SYMBOL vmlinux 0x152c0966 security_sb_clone_mnt_opts +EXPORT_SYMBOL vmlinux 0x152e8695 sock_no_recvmsg +EXPORT_SYMBOL vmlinux 0x1544aad4 genl_register_mc_group +EXPORT_SYMBOL vmlinux 0x1551dc51 bitmap_find_free_region +EXPORT_SYMBOL vmlinux 0x15570080 input_event +EXPORT_SYMBOL vmlinux 0x15ce86b8 ethtool_op_get_tx_csum +EXPORT_SYMBOL vmlinux 0x15ef2dd9 kfifo_free +EXPORT_SYMBOL vmlinux 0x162612e1 elevator_exit +EXPORT_SYMBOL vmlinux 0x166181ab cfb_fillrect +EXPORT_SYMBOL vmlinux 0x1675606f bad_dma_address +EXPORT_SYMBOL vmlinux 0x167e7f9d __get_user_1 +EXPORT_SYMBOL vmlinux 0x16a35878 _read_unlock +EXPORT_SYMBOL vmlinux 0x16df0a0e xfrm_state_check_expire +EXPORT_SYMBOL vmlinux 0x16eeec74 pci_set_master +EXPORT_SYMBOL vmlinux 0x170c25ee acpi_get_next_object +EXPORT_SYMBOL vmlinux 0x171c883e dma_pool_alloc +EXPORT_SYMBOL vmlinux 0x175a298d acpi_set_firmware_waking_vector +EXPORT_SYMBOL vmlinux 0x17a76e71 rb_first +EXPORT_SYMBOL vmlinux 0x17df17bc sysctl_tcp_ecn +EXPORT_SYMBOL vmlinux 0x17e28de2 proc_dointvec_minmax +EXPORT_SYMBOL vmlinux 0x17fdd919 register_atm_ioctl +EXPORT_SYMBOL vmlinux 0x1815b0e9 netdev_state_change +EXPORT_SYMBOL vmlinux 0x181b6ff2 mempool_resize +EXPORT_SYMBOL vmlinux 0x18225140 tcp_getsockopt +EXPORT_SYMBOL vmlinux 0x183fa88b mempool_alloc_slab +EXPORT_SYMBOL vmlinux 0x18630052 read_cache_page +EXPORT_SYMBOL vmlinux 0x1869d749 __ip_select_ident +EXPORT_SYMBOL vmlinux 0x189aeda5 mca_register_driver +EXPORT_SYMBOL vmlinux 0x18c6743d sockfd_lookup +EXPORT_SYMBOL vmlinux 0x18d8b8c8 sock_get_timestampns +EXPORT_SYMBOL vmlinux 0x18e3949b qdisc_watchdog_cancel +EXPORT_SYMBOL vmlinux 0x190f57df write_inode_now +EXPORT_SYMBOL vmlinux 0x1937415f generic_listxattr +EXPORT_SYMBOL vmlinux 0x193c1135 blk_queue_max_phys_segments +EXPORT_SYMBOL vmlinux 0x19662a9a nobh_truncate_page +EXPORT_SYMBOL vmlinux 0x19710d72 sock_queue_rcv_skb +EXPORT_SYMBOL vmlinux 0x1985ed3c prepare_to_wait_exclusive +EXPORT_SYMBOL vmlinux 0x199ed0cd net_disable_timestamp +EXPORT_SYMBOL vmlinux 0x19afb86b mca_device_set_claim +EXPORT_SYMBOL vmlinux 0x19c3eeb4 unregister_binfmt +EXPORT_SYMBOL vmlinux 0x19d5d20a acpi_walk_namespace +EXPORT_SYMBOL vmlinux 0x1a0e4baa sock_wake_async +EXPORT_SYMBOL vmlinux 0x1a137cbf keyring_clear +EXPORT_SYMBOL vmlinux 0x1a1ab15d tty_mutex +EXPORT_SYMBOL vmlinux 0x1a3d1fbf mnt_unpin +EXPORT_SYMBOL vmlinux 0x1a45cb6c acpi_disabled +EXPORT_SYMBOL vmlinux 0x1a48d0b4 vfs_create +EXPORT_SYMBOL vmlinux 0x1a75caa3 _read_lock +EXPORT_SYMBOL vmlinux 0x1a854228 get_io_context +EXPORT_SYMBOL vmlinux 0x1a8a845e idle_nomwait +EXPORT_SYMBOL vmlinux 0x1a8da421 xfrm_state_delete_tunnel +EXPORT_SYMBOL vmlinux 0x1a959e15 register_netdevice +EXPORT_SYMBOL vmlinux 0x1a95a3ee dev_getbyhwaddr +EXPORT_SYMBOL vmlinux 0x1ac24b60 neigh_parms_release +EXPORT_SYMBOL vmlinux 0x1ace138d bitmap_allocate_region +EXPORT_SYMBOL vmlinux 0x1ae8d7dc param_set_invbool +EXPORT_SYMBOL vmlinux 0x1b015d25 bitmap_parselist +EXPORT_SYMBOL vmlinux 0x1b198e87 mem_map +EXPORT_SYMBOL vmlinux 0x1b3c678a gen_new_estimator +EXPORT_SYMBOL vmlinux 0x1b5b3296 tcp_create_openreq_child +EXPORT_SYMBOL vmlinux 0x1b6314fd in_aton +EXPORT_SYMBOL vmlinux 0x1b6d1977 elv_rb_latter_request +EXPORT_SYMBOL vmlinux 0x1b89419f add_wait_queue_exclusive +EXPORT_SYMBOL vmlinux 0x1b9981cc set_irq_wake +EXPORT_SYMBOL vmlinux 0x1bbeb6f4 xfrm_find_acq_byseq +EXPORT_SYMBOL vmlinux 0x1c0a989a generic_setxattr +EXPORT_SYMBOL vmlinux 0x1c4a08c4 register_exec_domain +EXPORT_SYMBOL vmlinux 0x1c65bd2e sock_setsockopt +EXPORT_SYMBOL vmlinux 0x1c84a772 release_sock +EXPORT_SYMBOL vmlinux 0x1cbb7765 ilookup5 +EXPORT_SYMBOL vmlinux 0x1cbe85cd textsearch_register +EXPORT_SYMBOL vmlinux 0x1cc6719a register_reboot_notifier +EXPORT_SYMBOL vmlinux 0x1ce23b37 no_llseek +EXPORT_SYMBOL vmlinux 0x1cefe352 wait_for_completion +EXPORT_SYMBOL vmlinux 0x1cf2cf5f arp_xmit +EXPORT_SYMBOL vmlinux 0x1d0b0ea3 atm_dev_register +EXPORT_SYMBOL vmlinux 0x1d11e097 skb_dequeue_tail +EXPORT_SYMBOL vmlinux 0x1d30b70c rwsem_wake +EXPORT_SYMBOL vmlinux 0x1d71d58f vfs_read +EXPORT_SYMBOL vmlinux 0x1d72438c dev_set_allmulti +EXPORT_SYMBOL vmlinux 0x1d830520 cpu_possible_map +EXPORT_SYMBOL vmlinux 0x1da6681a d_alloc_root +EXPORT_SYMBOL vmlinux 0x1dc36131 fb_destroy_modedb +EXPORT_SYMBOL vmlinux 0x1dce38c0 generic_file_splice_write +EXPORT_SYMBOL vmlinux 0x1dd571e6 fb_copy_cmap +EXPORT_SYMBOL vmlinux 0x1dd68918 path_permission +EXPORT_SYMBOL vmlinux 0x1e37cbfb skb_copy_and_csum_bits +EXPORT_SYMBOL vmlinux 0x1e48674e skb_prepare_seq_read +EXPORT_SYMBOL vmlinux 0x1e6d26a8 strstr +EXPORT_SYMBOL vmlinux 0x1eb628a8 generic_file_aio_write +EXPORT_SYMBOL vmlinux 0x1eb922a3 IO_APIC_get_PCI_irq_vector +EXPORT_SYMBOL vmlinux 0x1eb94677 dma_free_coherent +EXPORT_SYMBOL vmlinux 0x1ebd7115 kick_iocb +EXPORT_SYMBOL vmlinux 0x1ed5e6ed create_proc_entry +EXPORT_SYMBOL vmlinux 0x1ee7492c blk_queue_ordered +EXPORT_SYMBOL vmlinux 0x1ee962fb simple_empty +EXPORT_SYMBOL vmlinux 0x1ef47973 __neigh_event_send +EXPORT_SYMBOL vmlinux 0x1efca83a blk_verify_command +EXPORT_SYMBOL vmlinux 0x1efe283f __cap_full_set +EXPORT_SYMBOL vmlinux 0x1f219b12 pci_bus_assign_resources +EXPORT_SYMBOL vmlinux 0x1f27d6d7 _write_unlock +EXPORT_SYMBOL vmlinux 0x1f79d54b sock_wfree +EXPORT_SYMBOL vmlinux 0x1f904852 tcp_v4_destroy_sock +EXPORT_SYMBOL vmlinux 0x1f91bec2 cdev_add +EXPORT_SYMBOL vmlinux 0x1f9ec75c ip_defrag +EXPORT_SYMBOL vmlinux 0x1fa93e96 con_set_default_unimap +EXPORT_SYMBOL vmlinux 0x1fe5ede6 per_cpu__irq_stat +EXPORT_SYMBOL vmlinux 0x20000329 simple_strtoul +EXPORT_SYMBOL vmlinux 0x2005e68a acpi_remove_fixed_event_handler +EXPORT_SYMBOL vmlinux 0x204e6997 dev_kfree_skb_any +EXPORT_SYMBOL vmlinux 0x206a7988 input_inject_event +EXPORT_SYMBOL vmlinux 0x208739f6 acpi_load_table +EXPORT_SYMBOL vmlinux 0x20a1981c pnp_stop_dev +EXPORT_SYMBOL vmlinux 0x20b11dae inode_double_unlock +EXPORT_SYMBOL vmlinux 0x20c8fc33 pci_osc_control_set +EXPORT_SYMBOL vmlinux 0x20cde608 dquot_release +EXPORT_SYMBOL vmlinux 0x20f7ca0d vfs_quota_on +EXPORT_SYMBOL vmlinux 0x21154675 qdisc_reset +EXPORT_SYMBOL vmlinux 0x2124772a tcp_read_sock +EXPORT_SYMBOL vmlinux 0x215ebd78 bitrev16 +EXPORT_SYMBOL vmlinux 0x21793318 put_page +EXPORT_SYMBOL vmlinux 0x21cf2fb6 elv_rb_former_request +EXPORT_SYMBOL vmlinux 0x21e0ea22 acpi_get_id +EXPORT_SYMBOL vmlinux 0x21f64c97 xfrm_alloc_spi +EXPORT_SYMBOL vmlinux 0x21f6ba2f dev_set_mac_address +EXPORT_SYMBOL vmlinux 0x21fadd79 dev_unicast_add +EXPORT_SYMBOL vmlinux 0x221f0f89 vfs_get_dqinfo +EXPORT_SYMBOL vmlinux 0x222e7ce2 sysfs_streq +EXPORT_SYMBOL vmlinux 0x22399dd0 skb_copy +EXPORT_SYMBOL vmlinux 0x224c54a6 set_pages_nx +EXPORT_SYMBOL vmlinux 0x226e86a9 audit_log +EXPORT_SYMBOL vmlinux 0x2288378f system_state +EXPORT_SYMBOL vmlinux 0x22a73912 __tcp_put_md5sig_pool +EXPORT_SYMBOL vmlinux 0x22b325d5 kd_mksound +EXPORT_SYMBOL vmlinux 0x22b6533b xfrm_sad_getinfo +EXPORT_SYMBOL vmlinux 0x231f3a66 __kfifo_put +EXPORT_SYMBOL vmlinux 0x23223cdf lock_sock_nested +EXPORT_SYMBOL vmlinux 0x23240e1f seq_path +EXPORT_SYMBOL vmlinux 0x23269a13 strict_strtoul +EXPORT_SYMBOL vmlinux 0x2368be6d posix_acl_to_xattr +EXPORT_SYMBOL vmlinux 0x236d5fbf fifo_create_dflt +EXPORT_SYMBOL vmlinux 0x23716927 __scm_send +EXPORT_SYMBOL vmlinux 0x23a7a3bd maps_protect +EXPORT_SYMBOL vmlinux 0x23ad070a set_current_groups +EXPORT_SYMBOL vmlinux 0x23c81a4b neigh_sysctl_unregister +EXPORT_SYMBOL vmlinux 0x23f2d36f memparse +EXPORT_SYMBOL vmlinux 0x23f38b58 pnp_unregister_driver +EXPORT_SYMBOL vmlinux 0x23f66574 register_chrdev +EXPORT_SYMBOL vmlinux 0x23fd3028 vmalloc_node +EXPORT_SYMBOL vmlinux 0x24039b28 get_empty_filp +EXPORT_SYMBOL vmlinux 0x242a3321 unregister_sysrq_key +EXPORT_SYMBOL vmlinux 0x243510dd kmap_atomic +EXPORT_SYMBOL vmlinux 0x243ffddc idr_destroy +EXPORT_SYMBOL vmlinux 0x24428be5 strncpy_from_user +EXPORT_SYMBOL vmlinux 0x2445c7b0 eth_type_trans +EXPORT_SYMBOL vmlinux 0x2459bbcc console_set_on_cmdline +EXPORT_SYMBOL vmlinux 0x24782049 km_state_expired +EXPORT_SYMBOL vmlinux 0x24a0c822 send_sig +EXPORT_SYMBOL vmlinux 0x24c02e61 seq_release_private +EXPORT_SYMBOL vmlinux 0x24c1ef2b acpi_evaluate_integer +EXPORT_SYMBOL vmlinux 0x24f0d1f2 neigh_compat_output +EXPORT_SYMBOL vmlinux 0x24fdac79 wake_bit_function +EXPORT_SYMBOL vmlinux 0x250113b4 memory_read_from_buffer +EXPORT_SYMBOL vmlinux 0x2501a201 xfrm_policy_alloc +EXPORT_SYMBOL vmlinux 0x25117e0a bio_integrity_get_tag +EXPORT_SYMBOL vmlinux 0x252bf8a0 open_by_devnum +EXPORT_SYMBOL vmlinux 0x25413bdd dquot_initialize +EXPORT_SYMBOL vmlinux 0x2558364d find_task_by_pid_type_ns +EXPORT_SYMBOL vmlinux 0x2566948d textsearch_prepare +EXPORT_SYMBOL vmlinux 0x256887e1 warn_slowpath +EXPORT_SYMBOL vmlinux 0x2568e258 ps2_sendbyte +EXPORT_SYMBOL vmlinux 0x25820c64 fs_overflowuid +EXPORT_SYMBOL vmlinux 0x258355b4 fb_find_best_mode +EXPORT_SYMBOL vmlinux 0x25aad63a request_firmware +EXPORT_SYMBOL vmlinux 0x25ab1691 bio_alloc +EXPORT_SYMBOL vmlinux 0x25ac9afe struct_module +EXPORT_SYMBOL vmlinux 0x25d81960 posix_acl_equiv_mode +EXPORT_SYMBOL vmlinux 0x265f5700 ether_setup +EXPORT_SYMBOL vmlinux 0x2685c3d7 __sg_alloc_table +EXPORT_SYMBOL vmlinux 0x268cc6a2 sys_close +EXPORT_SYMBOL vmlinux 0x26972d1a unload_nls +EXPORT_SYMBOL vmlinux 0x26a7ab93 input_allocate_device +EXPORT_SYMBOL vmlinux 0x26e76fb8 sysctl_udp_wmem_min +EXPORT_SYMBOL vmlinux 0x272d394e mtrr_del +EXPORT_SYMBOL vmlinux 0x272e7488 cond_resched_softirq +EXPORT_SYMBOL vmlinux 0x2739e3c1 blk_queue_free_tags +EXPORT_SYMBOL vmlinux 0x273a9802 pci_enable_device +EXPORT_SYMBOL vmlinux 0x273f066e _write_unlock_irq +EXPORT_SYMBOL vmlinux 0x277025c1 call_usermodehelper_pipe +EXPORT_SYMBOL vmlinux 0x277d99db __next_cpu +EXPORT_SYMBOL vmlinux 0x2786867d __blk_run_queue +EXPORT_SYMBOL vmlinux 0x2797ceea bio_endio +EXPORT_SYMBOL vmlinux 0x27a9a7eb ns_to_timespec +EXPORT_SYMBOL vmlinux 0x27ab2f58 bdput +EXPORT_SYMBOL vmlinux 0x27bbf221 disable_irq_nosync +EXPORT_SYMBOL vmlinux 0x27c61ece qdisc_put_stab +EXPORT_SYMBOL vmlinux 0x285ac517 strict_strtoll +EXPORT_SYMBOL vmlinux 0x28713f3a __netdev_alloc_skb +EXPORT_SYMBOL vmlinux 0x28a9c80e __dev_get_by_name +EXPORT_SYMBOL vmlinux 0x28b715a6 isapnp_cfg_end +EXPORT_SYMBOL vmlinux 0x28c4c872 sock_no_sendmsg +EXPORT_SYMBOL vmlinux 0x28dcf25c udplite_hash +EXPORT_SYMBOL vmlinux 0x2901aa11 generic_file_open +EXPORT_SYMBOL vmlinux 0x2924881d blk_stop_queue +EXPORT_SYMBOL vmlinux 0x29264962 pci_find_next_bus +EXPORT_SYMBOL vmlinux 0x29537c9e alloc_chrdev_region +EXPORT_SYMBOL vmlinux 0x29915c85 pci_release_regions +EXPORT_SYMBOL vmlinux 0x29b035f5 tcf_exts_dump_stats +EXPORT_SYMBOL vmlinux 0x29bd4c46 __cap_init_eff_set +EXPORT_SYMBOL vmlinux 0x29f59a92 sync_page_range +EXPORT_SYMBOL vmlinux 0x29f5b057 pci_unregister_driver +EXPORT_SYMBOL vmlinux 0x29fc6154 dev_mc_add +EXPORT_SYMBOL vmlinux 0x2a271201 genl_unregister_ops +EXPORT_SYMBOL vmlinux 0x2a303d4d check_signature +EXPORT_SYMBOL vmlinux 0x2a42bf3a acpi_notifier_call_chain +EXPORT_SYMBOL vmlinux 0x2a4b82f4 d_rehash +EXPORT_SYMBOL vmlinux 0x2a4d13ad d_alloc +EXPORT_SYMBOL vmlinux 0x2a7898c2 block_write_full_page +EXPORT_SYMBOL vmlinux 0x2a835cc1 sock_common_setsockopt +EXPORT_SYMBOL vmlinux 0x2a84030c sock_rfree +EXPORT_SYMBOL vmlinux 0x2a865d5c skb_clone +EXPORT_SYMBOL vmlinux 0x2a9d50f3 tcf_action_exec +EXPORT_SYMBOL vmlinux 0x2aa0e4fc strncasecmp +EXPORT_SYMBOL vmlinux 0x2aab0d5a setup_arg_pages +EXPORT_SYMBOL vmlinux 0x2ad63e9c eth_header +EXPORT_SYMBOL vmlinux 0x2aeb2800 mempool_create_node +EXPORT_SYMBOL vmlinux 0x2afebdbf inet_dgram_ops +EXPORT_SYMBOL vmlinux 0x2b0b412a pcibios_align_resource +EXPORT_SYMBOL vmlinux 0x2b12cb05 security_sk_classify_flow +EXPORT_SYMBOL vmlinux 0x2b5861d5 bfifo_qdisc_ops +EXPORT_SYMBOL vmlinux 0x2b6aac8c tcp_sockets_allocated +EXPORT_SYMBOL vmlinux 0x2b724e3c d_alloc_anon +EXPORT_SYMBOL vmlinux 0x2b86a602 mca_device_transform_memory +EXPORT_SYMBOL vmlinux 0x2b9b2fe3 pid_task +EXPORT_SYMBOL vmlinux 0x2ba707a8 sysctl_tcp_low_latency +EXPORT_SYMBOL vmlinux 0x2bb3d8f9 simple_lookup +EXPORT_SYMBOL vmlinux 0x2bb55d6e acpi_remove_notify_handler +EXPORT_SYMBOL vmlinux 0x2bc95bd4 memset +EXPORT_SYMBOL vmlinux 0x2be09893 _atomic_dec_and_lock +EXPORT_SYMBOL vmlinux 0x2bfeb410 acpi_get_handle +EXPORT_SYMBOL vmlinux 0x2c187451 put_disk +EXPORT_SYMBOL vmlinux 0x2c54d241 devm_request_irq +EXPORT_SYMBOL vmlinux 0x2c5749e6 acpi_clear_gpe +EXPORT_SYMBOL vmlinux 0x2c645999 vfs_quota_sync +EXPORT_SYMBOL vmlinux 0x2c6cb8f7 sock_map_fd +EXPORT_SYMBOL vmlinux 0x2c7acd94 kthread_stop +EXPORT_SYMBOL vmlinux 0x2c89bc37 request_key +EXPORT_SYMBOL vmlinux 0x2c8f5989 acpi_remove_address_space_handler +EXPORT_SYMBOL vmlinux 0x2c94c5f9 xfrm_state_alloc +EXPORT_SYMBOL vmlinux 0x2c9874fe ida_remove +EXPORT_SYMBOL vmlinux 0x2c9e60cc thermal_zone_device_unregister +EXPORT_SYMBOL vmlinux 0x2cbfbdeb sock_no_shutdown +EXPORT_SYMBOL vmlinux 0x2cc18d9f inetdev_by_index +EXPORT_SYMBOL vmlinux 0x2cc2d52d vcc_hash +EXPORT_SYMBOL vmlinux 0x2cce2c20 ip_mc_rejoin_group +EXPORT_SYMBOL vmlinux 0x2cd9e459 param_set_short +EXPORT_SYMBOL vmlinux 0x2cf190e3 request_irq +EXPORT_SYMBOL vmlinux 0x2cfedcc3 seq_lseek +EXPORT_SYMBOL vmlinux 0x2d0014d8 dget_locked +EXPORT_SYMBOL vmlinux 0x2d5c1fef d_prune_aliases +EXPORT_SYMBOL vmlinux 0x2d838453 __dev_remove_pack +EXPORT_SYMBOL vmlinux 0x2d955762 generic_block_bmap +EXPORT_SYMBOL vmlinux 0x2d96c515 do_splice_to +EXPORT_SYMBOL vmlinux 0x2dab0013 key_task_permission +EXPORT_SYMBOL vmlinux 0x2dd16564 arch_register_cpu +EXPORT_SYMBOL vmlinux 0x2de9f66f param_get_long +EXPORT_SYMBOL vmlinux 0x2dedc4c2 acpi_format_exception +EXPORT_SYMBOL vmlinux 0x2deea25b sock_wmalloc +EXPORT_SYMBOL vmlinux 0x2def7f76 rtc_cmos_write +EXPORT_SYMBOL vmlinux 0x2dfa4371 kmem_cache_size +EXPORT_SYMBOL vmlinux 0x2e2ce9e0 sysctl_tcp_syncookies +EXPORT_SYMBOL vmlinux 0x2e328ea8 flush_old_exec +EXPORT_SYMBOL vmlinux 0x2e3b3519 call_usermodehelper_setkeys +EXPORT_SYMBOL vmlinux 0x2e4905a7 dst_release +EXPORT_SYMBOL vmlinux 0x2e4a39f8 sysctl_udp_mem +EXPORT_SYMBOL vmlinux 0x2e4cbd64 xfrm_input +EXPORT_SYMBOL vmlinux 0x2e60bace memcpy +EXPORT_SYMBOL vmlinux 0x2e778e2b pci_bus_write_config_dword +EXPORT_SYMBOL vmlinux 0x2e8576d2 elv_dispatch_add_tail +EXPORT_SYMBOL vmlinux 0x2e97859f rwsem_downgrade_wake +EXPORT_SYMBOL vmlinux 0x2e97f677 vfs_set_dqinfo +EXPORT_SYMBOL vmlinux 0x2e9e6b3a dmam_free_noncoherent +EXPORT_SYMBOL vmlinux 0x2eaa21c0 page_symlink_inode_operations +EXPORT_SYMBOL vmlinux 0x2eb9a0e8 _read_lock_irq +EXPORT_SYMBOL vmlinux 0x2ec24648 may_umount +EXPORT_SYMBOL vmlinux 0x2ec59de6 simple_write_begin +EXPORT_SYMBOL vmlinux 0x2ee17ced netlink_broadcast +EXPORT_SYMBOL vmlinux 0x2eeed6e2 keyring_search +EXPORT_SYMBOL vmlinux 0x2ef1374e eth_header_cache +EXPORT_SYMBOL vmlinux 0x2f1fe1ae bio_put +EXPORT_SYMBOL vmlinux 0x2f287f0d copy_to_user +EXPORT_SYMBOL vmlinux 0x2f3547ed qdisc_create_dflt +EXPORT_SYMBOL vmlinux 0x2f513ad0 ps2_cmd_aborted +EXPORT_SYMBOL vmlinux 0x2f9e3d9a seq_puts +EXPORT_SYMBOL vmlinux 0x2fb24c75 fget +EXPORT_SYMBOL vmlinux 0x2ff7efaa tcf_hash_new_index +EXPORT_SYMBOL vmlinux 0x302c7996 mca_register_driver_integrated +EXPORT_SYMBOL vmlinux 0x3039a7f5 blk_queue_start_tag +EXPORT_SYMBOL vmlinux 0x30896043 __any_online_cpu +EXPORT_SYMBOL vmlinux 0x309edecf sb_set_blocksize +EXPORT_SYMBOL vmlinux 0x30af4405 end_dequeued_request +EXPORT_SYMBOL vmlinux 0x30cfbbde sync_inode +EXPORT_SYMBOL vmlinux 0x30e74134 tty_termios_copy_hw +EXPORT_SYMBOL vmlinux 0x30f2e1fb kernel_sendpage +EXPORT_SYMBOL vmlinux 0x310917fe sort +EXPORT_SYMBOL vmlinux 0x312b5460 blk_integrity_compare +EXPORT_SYMBOL vmlinux 0x3145216f pci_dev_present +EXPORT_SYMBOL vmlinux 0x3147857d default_red +EXPORT_SYMBOL vmlinux 0x318e7ca4 tcp_disconnect +EXPORT_SYMBOL vmlinux 0x3191f109 __krealloc +EXPORT_SYMBOL vmlinux 0x319eaf9e skb_recv_datagram +EXPORT_SYMBOL vmlinux 0x31bf96e7 unlock_new_inode +EXPORT_SYMBOL vmlinux 0x31c60175 tcf_destroy_chain +EXPORT_SYMBOL vmlinux 0x31cd02f8 posix_acl_permission +EXPORT_SYMBOL vmlinux 0x31e76b57 recalibrate_cpu_khz +EXPORT_SYMBOL vmlinux 0x31f0f615 pci_bus_write_config_byte +EXPORT_SYMBOL vmlinux 0x323a2e14 __page_symlink +EXPORT_SYMBOL vmlinux 0x324121e1 pnp_unregister_card_driver +EXPORT_SYMBOL vmlinux 0x324fdbf8 bd_set_size +EXPORT_SYMBOL vmlinux 0x3271cf1e inet_dev_addr_type +EXPORT_SYMBOL vmlinux 0x32888bcc pci_bus_find_capability +EXPORT_SYMBOL vmlinux 0x32a74200 dmam_pool_create +EXPORT_SYMBOL vmlinux 0x32d01fec acpi_attach_data +EXPORT_SYMBOL vmlinux 0x3309140c register_tcf_proto_ops +EXPORT_SYMBOL vmlinux 0x330ef833 __lock_page +EXPORT_SYMBOL vmlinux 0x331a0a94 generic_writepages +EXPORT_SYMBOL vmlinux 0x3360a963 param_set_ulong +EXPORT_SYMBOL vmlinux 0x3367d7ae isapnp_protocol +EXPORT_SYMBOL vmlinux 0x337a68cc bio_hw_segments +EXPORT_SYMBOL vmlinux 0x3385c8cb per_cpu__this_cpu_off +EXPORT_SYMBOL vmlinux 0x33c6ecbb uart_add_one_port +EXPORT_SYMBOL vmlinux 0x33d92f9a prepare_to_wait +EXPORT_SYMBOL vmlinux 0x33ffb12b bio_integrity_endio +EXPORT_SYMBOL vmlinux 0x3407f0c1 blk_execute_rq +EXPORT_SYMBOL vmlinux 0x3421272c efi +EXPORT_SYMBOL vmlinux 0x342f60fe apm_info +EXPORT_SYMBOL vmlinux 0x34371024 nobh_write_end +EXPORT_SYMBOL vmlinux 0x34908c14 print_hex_dump_bytes +EXPORT_SYMBOL vmlinux 0x349cba85 strchr +EXPORT_SYMBOL vmlinux 0x3503dcc3 xfrm_input_resume +EXPORT_SYMBOL vmlinux 0x3534bc1a bdget +EXPORT_SYMBOL vmlinux 0x3570cbc6 netpoll_send_udp +EXPORT_SYMBOL vmlinux 0x35abf4ef generic_file_aio_write_nolock +EXPORT_SYMBOL vmlinux 0x35c2ba9e refrigerator +EXPORT_SYMBOL vmlinux 0x35c706c3 remap_pfn_range +EXPORT_SYMBOL vmlinux 0x35cd0ef1 vfs_set_dqblk +EXPORT_SYMBOL vmlinux 0x35f0faa2 acpi_evaluate_object +EXPORT_SYMBOL vmlinux 0x360b1afe probe_irq_mask +EXPORT_SYMBOL vmlinux 0x361d117e llc_set_station_handler +EXPORT_SYMBOL vmlinux 0x363ad247 cap_set_effective +EXPORT_SYMBOL vmlinux 0x3642184f udp_ioctl +EXPORT_SYMBOL vmlinux 0x3656bf5a lock_kernel +EXPORT_SYMBOL vmlinux 0x365a622e scm_detach_fds +EXPORT_SYMBOL vmlinux 0x36617e1a generic_splice_sendpage +EXPORT_SYMBOL vmlinux 0x36693f5d get_sb_nodev +EXPORT_SYMBOL vmlinux 0x36971609 __breadahead +EXPORT_SYMBOL vmlinux 0x370bd665 single_open +EXPORT_SYMBOL vmlinux 0x371b96bd misc_deregister +EXPORT_SYMBOL vmlinux 0x3744cf36 vmalloc_to_pfn +EXPORT_SYMBOL vmlinux 0x374ed073 scnprintf +EXPORT_SYMBOL vmlinux 0x37831120 bio_add_page +EXPORT_SYMBOL vmlinux 0x378dab1d pci_setup_cardbus +EXPORT_SYMBOL vmlinux 0x379d65f5 gen_pool_alloc +EXPORT_SYMBOL vmlinux 0x37befc70 jiffies_to_msecs +EXPORT_SYMBOL vmlinux 0x37de02b8 skb_gso_segment +EXPORT_SYMBOL vmlinux 0x37e74642 get_jiffies_64 +EXPORT_SYMBOL vmlinux 0x38203ca1 __init_rwsem +EXPORT_SYMBOL vmlinux 0x384c76f5 user_revoke +EXPORT_SYMBOL vmlinux 0x3871bde8 iov_iter_copy_from_user_atomic +EXPORT_SYMBOL vmlinux 0x387c0967 vfs_lstat +EXPORT_SYMBOL vmlinux 0x38b3117c nf_log_packet +EXPORT_SYMBOL vmlinux 0x38b92846 llc_remove_pack +EXPORT_SYMBOL vmlinux 0x38d21a19 udp_proc_unregister +EXPORT_SYMBOL vmlinux 0x38f6c822 neigh_sysctl_register +EXPORT_SYMBOL vmlinux 0x39170a6c acpi_check_resource_conflict +EXPORT_SYMBOL vmlinux 0x392fd1c7 blk_integrity_register +EXPORT_SYMBOL vmlinux 0x3938257c proc_dointvec_ms_jiffies +EXPORT_SYMBOL vmlinux 0x394ff9c4 find_get_pages_tag +EXPORT_SYMBOL vmlinux 0x3980aac1 unregister_reboot_notifier +EXPORT_SYMBOL vmlinux 0x39854807 serio_open +EXPORT_SYMBOL vmlinux 0x3997c1a9 block_write_end +EXPORT_SYMBOL vmlinux 0x39a772b0 sock_no_listen +EXPORT_SYMBOL vmlinux 0x39c645a2 schedule_delayed_work_on +EXPORT_SYMBOL vmlinux 0x3a165b62 free_task +EXPORT_SYMBOL vmlinux 0x3a1cd704 cpu_sysdev_class +EXPORT_SYMBOL vmlinux 0x3a1f17c8 serio_close +EXPORT_SYMBOL vmlinux 0x3a2204c6 security_netlink_recv +EXPORT_SYMBOL vmlinux 0x3a898787 kernel_getpeername +EXPORT_SYMBOL vmlinux 0x3a9b6fb9 blk_unregister_region +EXPORT_SYMBOL vmlinux 0x3aa1dbcf _spin_unlock_bh +EXPORT_SYMBOL vmlinux 0x3aa2b056 kmap +EXPORT_SYMBOL vmlinux 0x3aae0ee1 get_sb_single +EXPORT_SYMBOL vmlinux 0x3abacd76 kill_pgrp +EXPORT_SYMBOL vmlinux 0x3ac69b1c seq_escape +EXPORT_SYMBOL vmlinux 0x3ad96b4b blk_queue_merge_bvec +EXPORT_SYMBOL vmlinux 0x3b1d12c4 tty_throttle +EXPORT_SYMBOL vmlinux 0x3b2624ca seq_putc +EXPORT_SYMBOL vmlinux 0x3b3016d3 cpufreq_unregister_notifier +EXPORT_SYMBOL vmlinux 0x3b3c478f mpage_writepage +EXPORT_SYMBOL vmlinux 0x3b3c4aa6 bio_free +EXPORT_SYMBOL vmlinux 0x3b3e70d8 kill_anon_super +EXPORT_SYMBOL vmlinux 0x3b6bc24d atm_dev_deregister +EXPORT_SYMBOL vmlinux 0x3baafbb9 kmem_cache_shrink +EXPORT_SYMBOL vmlinux 0x3bb8ab4a xfrm_user_policy +EXPORT_SYMBOL vmlinux 0x3bd1b1f6 msecs_to_jiffies +EXPORT_SYMBOL vmlinux 0x3be779ad posix_lock_file_wait +EXPORT_SYMBOL vmlinux 0x3c2c5af5 sprintf +EXPORT_SYMBOL vmlinux 0x3c7227bf complete_all +EXPORT_SYMBOL vmlinux 0x3cb3931b sg_copy_to_buffer +EXPORT_SYMBOL vmlinux 0x3cb8a495 param_get_string +EXPORT_SYMBOL vmlinux 0x3cbbaaf8 input_unregister_handle +EXPORT_SYMBOL vmlinux 0x3cc0a3bb xfrm_spd_getinfo +EXPORT_SYMBOL vmlinux 0x3cc779e4 register_8022_client +EXPORT_SYMBOL vmlinux 0x3ccf2d69 tcp_v4_md5_do_del +EXPORT_SYMBOL vmlinux 0x3ce4ca6f disable_irq +EXPORT_SYMBOL vmlinux 0x3cf1f863 pnp_device_detach +EXPORT_SYMBOL vmlinux 0x3d003e40 tcp_mtup_init +EXPORT_SYMBOL vmlinux 0x3d0245b1 km_state_notify +EXPORT_SYMBOL vmlinux 0x3d1aa2fb qdisc_destroy +EXPORT_SYMBOL vmlinux 0x3d790fc5 end_buffer_read_sync +EXPORT_SYMBOL vmlinux 0x3da171f9 pci_mem_start +EXPORT_SYMBOL vmlinux 0x3da5eb6d kfifo_alloc +EXPORT_SYMBOL vmlinux 0x3dc82cae sock_no_getsockopt +EXPORT_SYMBOL vmlinux 0x3df1d34b fb_pan_display +EXPORT_SYMBOL vmlinux 0x3e1f073d wait_for_completion_timeout +EXPORT_SYMBOL vmlinux 0x3e219de6 try_wait_for_completion +EXPORT_SYMBOL vmlinux 0x3e2427a1 acpi_check_region +EXPORT_SYMBOL vmlinux 0x3e2ae3a8 acpi_release_global_lock +EXPORT_SYMBOL vmlinux 0x3e45e9ff register_inetaddr_notifier +EXPORT_SYMBOL vmlinux 0x3e477390 dev_alloc_skb +EXPORT_SYMBOL vmlinux 0x3e835a9d eth_header_parse +EXPORT_SYMBOL vmlinux 0x3ec50939 kmem_cache_create +EXPORT_SYMBOL vmlinux 0x3ed63055 zlib_inflateReset +EXPORT_SYMBOL vmlinux 0x3ed7952d bio_clone +EXPORT_SYMBOL vmlinux 0x3f0546a8 ioread32_rep +EXPORT_SYMBOL vmlinux 0x3f1899f1 up +EXPORT_SYMBOL vmlinux 0x3f2287b0 atm_charge +EXPORT_SYMBOL vmlinux 0x3f39b162 up_write +EXPORT_SYMBOL vmlinux 0x3f4547a7 put_unused_fd +EXPORT_SYMBOL vmlinux 0x3f6a80f3 __pagevec_lru_add +EXPORT_SYMBOL vmlinux 0x3f7d4e52 page_address +EXPORT_SYMBOL vmlinux 0x3fbcddc3 netdev_compute_features +EXPORT_SYMBOL vmlinux 0x3fbeafa0 cpufreq_gov_performance +EXPORT_SYMBOL vmlinux 0x3fec048f sg_next +EXPORT_SYMBOL vmlinux 0x3ff62317 local_bh_disable +EXPORT_SYMBOL vmlinux 0x40051683 vm_insert_mixed +EXPORT_SYMBOL vmlinux 0x402af5cc skb_kill_datagram +EXPORT_SYMBOL vmlinux 0x40576b02 acpi_get_physical_device +EXPORT_SYMBOL vmlinux 0x4059792f print_hex_dump +EXPORT_SYMBOL vmlinux 0x405c1144 get_seconds +EXPORT_SYMBOL vmlinux 0x406e8588 make_bad_inode +EXPORT_SYMBOL vmlinux 0x409873e3 tty_termios_baud_rate +EXPORT_SYMBOL vmlinux 0x40c89d46 acpi_get_table_by_index +EXPORT_SYMBOL vmlinux 0x40e26c13 serio_unregister_port +EXPORT_SYMBOL vmlinux 0x40ea9a58 elv_dispatch_sort +EXPORT_SYMBOL vmlinux 0x40ed240b default_llseek +EXPORT_SYMBOL vmlinux 0x40fd1fc2 truncate_inode_pages +EXPORT_SYMBOL vmlinux 0x4108e69a fb_match_mode +EXPORT_SYMBOL vmlinux 0x41438f4e kmem_cache_destroy +EXPORT_SYMBOL vmlinux 0x41482d8b strndup_user +EXPORT_SYMBOL vmlinux 0x416a925e netdev_features_change +EXPORT_SYMBOL vmlinux 0x4185cf4b radix_tree_lookup_slot +EXPORT_SYMBOL vmlinux 0x4188d439 neigh_rand_reach_time +EXPORT_SYMBOL vmlinux 0x41a9c68d _spin_trylock_bh +EXPORT_SYMBOL vmlinux 0x41cca257 flush_tlb_page +EXPORT_SYMBOL vmlinux 0x41ccc474 security_req_classify_flow +EXPORT_SYMBOL vmlinux 0x41dcae00 tty_hung_up_p +EXPORT_SYMBOL vmlinux 0x41efe9a2 simple_statfs +EXPORT_SYMBOL vmlinux 0x420f6d79 proc_doulongvec_ms_jiffies_minmax +EXPORT_SYMBOL vmlinux 0x4211c3c1 zlib_inflateInit2 +EXPORT_SYMBOL vmlinux 0x42224298 sscanf +EXPORT_SYMBOL vmlinux 0x422c05d0 acpi_get_data +EXPORT_SYMBOL vmlinux 0x42635430 pci_dev_get +EXPORT_SYMBOL vmlinux 0x4292364c schedule +EXPORT_SYMBOL vmlinux 0x42a0c4cf single_release +EXPORT_SYMBOL vmlinux 0x4302d0eb free_pages +EXPORT_SYMBOL vmlinux 0x43385ad9 acpi_pci_unregister_driver +EXPORT_SYMBOL vmlinux 0x434fa55c release_console_sem +EXPORT_SYMBOL vmlinux 0x435b566d _spin_unlock +EXPORT_SYMBOL vmlinux 0x436c2179 iowrite32 +EXPORT_SYMBOL vmlinux 0x43841eb4 dquot_free_space +EXPORT_SYMBOL vmlinux 0x43b146b4 bdi_init +EXPORT_SYMBOL vmlinux 0x43b40de7 kunmap_atomic +EXPORT_SYMBOL vmlinux 0x43bcd584 vcc_insert_socket +EXPORT_SYMBOL vmlinux 0x43bdd372 request_resource +EXPORT_SYMBOL vmlinux 0x43ccfa4e input_register_device +EXPORT_SYMBOL vmlinux 0x44161c19 unregister_shrinker +EXPORT_SYMBOL vmlinux 0x44314efb radix_tree_gang_lookup_tag_slot +EXPORT_SYMBOL vmlinux 0x444779c4 nla_find +EXPORT_SYMBOL vmlinux 0x44aaf30f tsc_khz +EXPORT_SYMBOL vmlinux 0x44b911c3 rb_replace_node +EXPORT_SYMBOL vmlinux 0x44c11af8 pci_dev_driver +EXPORT_SYMBOL vmlinux 0x44f21bea idr_for_each +EXPORT_SYMBOL vmlinux 0x451f306c blk_put_request +EXPORT_SYMBOL vmlinux 0x4550ba8a register_cpu_notifier +EXPORT_SYMBOL vmlinux 0x455fd57d acpi_set_register +EXPORT_SYMBOL vmlinux 0x459ee138 __sk_mem_schedule +EXPORT_SYMBOL vmlinux 0x45bb123e try_to_del_timer_sync +EXPORT_SYMBOL vmlinux 0x45d11c43 down_interruptible +EXPORT_SYMBOL vmlinux 0x45d84bef xfrm_state_register_afinfo +EXPORT_SYMBOL vmlinux 0x45fefe1a xfrm_state_add +EXPORT_SYMBOL vmlinux 0x462a2e75 match_strlcpy +EXPORT_SYMBOL vmlinux 0x46318048 xfrm_nl +EXPORT_SYMBOL vmlinux 0x4640b3b9 pci_bus_read_config_word +EXPORT_SYMBOL vmlinux 0x46534c4e locks_mandatory_area +EXPORT_SYMBOL vmlinux 0x466c14a7 __delay +EXPORT_SYMBOL vmlinux 0x46c5bf0b skb_append_datato_frags +EXPORT_SYMBOL vmlinux 0x46e2f716 __inc_zone_page_state +EXPORT_SYMBOL vmlinux 0x471e7a88 iov_iter_copy_from_user +EXPORT_SYMBOL vmlinux 0x4726cf2e tcf_hash_search +EXPORT_SYMBOL vmlinux 0x472d2a9a radix_tree_lookup +EXPORT_SYMBOL vmlinux 0x4738b6d3 d_namespace_path +EXPORT_SYMBOL vmlinux 0x475100c2 inet_get_local_port_range +EXPORT_SYMBOL vmlinux 0x4757e0a1 scsi_cmd_ioctl +EXPORT_SYMBOL vmlinux 0x475f010b acpi_purge_cached_objects +EXPORT_SYMBOL vmlinux 0x477ed071 fb_class +EXPORT_SYMBOL vmlinux 0x478d10b2 ht_destroy_irq +EXPORT_SYMBOL vmlinux 0x47939e0d __tasklet_hi_schedule +EXPORT_SYMBOL vmlinux 0x479c3c86 find_next_zero_bit +EXPORT_SYMBOL vmlinux 0x47c62d70 xfrm_policy_flush +EXPORT_SYMBOL vmlinux 0x47c705d9 skb_checksum +EXPORT_SYMBOL vmlinux 0x47dcf04e ilookup5_nowait +EXPORT_SYMBOL vmlinux 0x481cb9ab acpi_enter_sleep_state_prep +EXPORT_SYMBOL vmlinux 0x4859b8bb rtc_year_days +EXPORT_SYMBOL vmlinux 0x486b6407 hweight64 +EXPORT_SYMBOL vmlinux 0x48755290 serio_interrupt +EXPORT_SYMBOL vmlinux 0x48b56f60 inet_twsk_deschedule +EXPORT_SYMBOL vmlinux 0x48f6e001 fput +EXPORT_SYMBOL vmlinux 0x493e25e1 udp_hash +EXPORT_SYMBOL vmlinux 0x495f62df skb_over_panic +EXPORT_SYMBOL vmlinux 0x49603fb8 security_sb_copy_data +EXPORT_SYMBOL vmlinux 0x498724dd d_find_alias +EXPORT_SYMBOL vmlinux 0x498c98a2 pci_enable_device_mem +EXPORT_SYMBOL vmlinux 0x499d4f85 unlock_rename +EXPORT_SYMBOL vmlinux 0x49c49e39 sync_dirty_buffer +EXPORT_SYMBOL vmlinux 0x49d6751b mca_device_claimed +EXPORT_SYMBOL vmlinux 0x49d771bc bio_integrity_add_page +EXPORT_SYMBOL vmlinux 0x49da9a9a _read_unlock_bh +EXPORT_SYMBOL vmlinux 0x4a157e7f register_sysrq_key +EXPORT_SYMBOL vmlinux 0x4a358252 __bitmap_subset +EXPORT_SYMBOL vmlinux 0x4a3ab6af locks_init_lock +EXPORT_SYMBOL vmlinux 0x4a971ec7 radix_tree_delete +EXPORT_SYMBOL vmlinux 0x4ab3c77e simple_set_mnt +EXPORT_SYMBOL vmlinux 0x4adf7a28 pfifo_qdisc_ops +EXPORT_SYMBOL vmlinux 0x4b018a2e zero_fill_bio +EXPORT_SYMBOL vmlinux 0x4b07e779 _spin_unlock_irqrestore +EXPORT_SYMBOL vmlinux 0x4b0d3263 nf_setsockopt +EXPORT_SYMBOL vmlinux 0x4b2f14b4 jiffies_to_timespec +EXPORT_SYMBOL vmlinux 0x4b34fbf5 block_all_signals +EXPORT_SYMBOL vmlinux 0x4b489b6c give_up_console +EXPORT_SYMBOL vmlinux 0x4b5139c2 flush_signals +EXPORT_SYMBOL vmlinux 0x4b5a9e94 iw_handler_get_thrspy +EXPORT_SYMBOL vmlinux 0x4b77c0d1 tcf_hash_insert +EXPORT_SYMBOL vmlinux 0x4b946414 arp_create +EXPORT_SYMBOL vmlinux 0x4b947329 pv_mmu_ops +EXPORT_SYMBOL vmlinux 0x4bb264e1 skb_under_panic +EXPORT_SYMBOL vmlinux 0x4bbc3e5f pm_flags +EXPORT_SYMBOL vmlinux 0x4c1182cb bitmap_scnprintf +EXPORT_SYMBOL vmlinux 0x4c16bd63 inet_getname +EXPORT_SYMBOL vmlinux 0x4c3af445 __request_region +EXPORT_SYMBOL vmlinux 0x4c474cfc llc_add_pack +EXPORT_SYMBOL vmlinux 0x4ca9023a gnet_stats_copy_rate_est +EXPORT_SYMBOL vmlinux 0x4cb692ba misc_register +EXPORT_SYMBOL vmlinux 0x4cbbd171 __bitmap_weight +EXPORT_SYMBOL vmlinux 0x4cc7c4a4 pci_choose_state +EXPORT_SYMBOL vmlinux 0x4ccb3a50 __inet6_hash +EXPORT_SYMBOL vmlinux 0x4ce4a4cd generic_make_request +EXPORT_SYMBOL vmlinux 0x4d01d6ae skb_free_datagram +EXPORT_SYMBOL vmlinux 0x4d2dc830 acpi_get_object_info +EXPORT_SYMBOL vmlinux 0x4d3c153f sigprocmask +EXPORT_SYMBOL vmlinux 0x4d50da33 proc_dointvec_jiffies +EXPORT_SYMBOL vmlinux 0x4d5ecaef rtnl_set_sk_err +EXPORT_SYMBOL vmlinux 0x4d6507f8 filemap_fault +EXPORT_SYMBOL vmlinux 0x4daa5393 __lock_buffer +EXPORT_SYMBOL vmlinux 0x4ddc4b9f utf8_mbtowc +EXPORT_SYMBOL vmlinux 0x4df119fa __bitmap_parse +EXPORT_SYMBOL vmlinux 0x4e100f60 _spin_unlock_irq +EXPORT_SYMBOL vmlinux 0x4e3475ed get_sb_pseudo +EXPORT_SYMBOL vmlinux 0x4e3567f7 match_int +EXPORT_SYMBOL vmlinux 0x4e6e8ea7 fg_console +EXPORT_SYMBOL vmlinux 0x4e7548e4 inet_del_protocol +EXPORT_SYMBOL vmlinux 0x4e830a3e strnicmp +EXPORT_SYMBOL vmlinux 0x4ecc67a3 init_buffer +EXPORT_SYMBOL vmlinux 0x4ed5cf93 vfs_rename +EXPORT_SYMBOL vmlinux 0x4ee33ddc do_mmap_pgoff +EXPORT_SYMBOL vmlinux 0x4f17bae7 __bread +EXPORT_SYMBOL vmlinux 0x4f1e5d8c sock_alloc_send_skb +EXPORT_SYMBOL vmlinux 0x4f26cbbe vmap +EXPORT_SYMBOL vmlinux 0x4f5438c1 idle_halt +EXPORT_SYMBOL vmlinux 0x4f73d0d6 simple_rmdir +EXPORT_SYMBOL vmlinux 0x4f89abe8 input_free_device +EXPORT_SYMBOL vmlinux 0x4fbe3608 dst_destroy +EXPORT_SYMBOL vmlinux 0x4fd853db pci_pme_active +EXPORT_SYMBOL vmlinux 0x4fdee897 i8042_command +EXPORT_SYMBOL vmlinux 0x4fe418a2 path_get +EXPORT_SYMBOL vmlinux 0x50211ee3 tcp_free_md5sig_pool +EXPORT_SYMBOL vmlinux 0x504a5136 inode_change_ok +EXPORT_SYMBOL vmlinux 0x50698c1b fb_show_logo +EXPORT_SYMBOL vmlinux 0x50a42878 ioctl_by_bdev +EXPORT_SYMBOL vmlinux 0x50f8bb67 nf_hook_slow +EXPORT_SYMBOL vmlinux 0x5118c382 secure_dccp_sequence_number +EXPORT_SYMBOL vmlinux 0x5152e605 memcmp +EXPORT_SYMBOL vmlinux 0x517a354c call_usermodehelper_freeinfo +EXPORT_SYMBOL vmlinux 0x51871d4b tcp_check_req +EXPORT_SYMBOL vmlinux 0x518eb764 per_cpu__cpu_number +EXPORT_SYMBOL vmlinux 0x51d12d4e acpi_pci_disabled +EXPORT_SYMBOL vmlinux 0x51d7a776 acpi_detach_data +EXPORT_SYMBOL vmlinux 0x51ef33b8 kstrndup +EXPORT_SYMBOL vmlinux 0x51f84954 d_delete +EXPORT_SYMBOL vmlinux 0x52026cdf security_sb_parse_opts_str +EXPORT_SYMBOL vmlinux 0x5213d083 read_cache_pages +EXPORT_SYMBOL vmlinux 0x52398855 backlight_device_unregister +EXPORT_SYMBOL vmlinux 0x52670b5a sock_create +EXPORT_SYMBOL vmlinux 0x526a3da7 acpi_bus_start +EXPORT_SYMBOL vmlinux 0x526d662b read_cache_page_async +EXPORT_SYMBOL vmlinux 0x526e4a14 test_set_page_writeback +EXPORT_SYMBOL vmlinux 0x527d582f tcp_md5_hash_header +EXPORT_SYMBOL vmlinux 0x528a0689 blk_rq_map_sg +EXPORT_SYMBOL vmlinux 0x528c709d simple_read_from_buffer +EXPORT_SYMBOL vmlinux 0x52a58c24 ifla_policy +EXPORT_SYMBOL vmlinux 0x52a712b5 vfs_dq_transfer +EXPORT_SYMBOL vmlinux 0x52bc01e2 input_close_device +EXPORT_SYMBOL vmlinux 0x52d7b2fd llc_sap_list +EXPORT_SYMBOL vmlinux 0x52e24296 key_validate +EXPORT_SYMBOL vmlinux 0x52ef43b8 tcf_exts_dump +EXPORT_SYMBOL vmlinux 0x530080bc generic_show_options +EXPORT_SYMBOL vmlinux 0x530b1e98 pm_suspend +EXPORT_SYMBOL vmlinux 0x5316d935 __nla_reserve +EXPORT_SYMBOL vmlinux 0x53289562 rtnl_unicast +EXPORT_SYMBOL vmlinux 0x532e84e3 set_anon_super +EXPORT_SYMBOL vmlinux 0x532f2924 param_get_byte +EXPORT_SYMBOL vmlinux 0x53326531 mempool_alloc_pages +EXPORT_SYMBOL vmlinux 0x5338b31f tcp_v4_md5_do_add +EXPORT_SYMBOL vmlinux 0x5374fee7 alloc_file +EXPORT_SYMBOL vmlinux 0x5397ddf7 acpi_unlock_ac_dir +EXPORT_SYMBOL vmlinux 0x53a1b8e1 ll_rw_block +EXPORT_SYMBOL vmlinux 0x53a84af9 skb_trim +EXPORT_SYMBOL vmlinux 0x53c0767c sk_chk_filter +EXPORT_SYMBOL vmlinux 0x542559cc sk_free +EXPORT_SYMBOL vmlinux 0x54290dc9 nla_validate +EXPORT_SYMBOL vmlinux 0x542cfe64 xfrm_state_delete +EXPORT_SYMBOL vmlinux 0x543e305a drop_super +EXPORT_SYMBOL vmlinux 0x546bd256 bio_integrity_set_tag +EXPORT_SYMBOL vmlinux 0x5472dd9c blk_queue_init_tags +EXPORT_SYMBOL vmlinux 0x54935666 acpi_os_read_port +EXPORT_SYMBOL vmlinux 0x54b61413 tty_unthrottle +EXPORT_SYMBOL vmlinux 0x54b81541 init_timer_deferrable +EXPORT_SYMBOL vmlinux 0x54bad95d acpi_unlock_battery_dir +EXPORT_SYMBOL vmlinux 0x54c82ea8 vfs_unlink +EXPORT_SYMBOL vmlinux 0x54cf6872 uart_register_driver +EXPORT_SYMBOL vmlinux 0x54e6fcdd net_enable_timestamp +EXPORT_SYMBOL vmlinux 0x55349a8d handle_sysrq +EXPORT_SYMBOL vmlinux 0x553f9dd3 down_read_trylock +EXPORT_SYMBOL vmlinux 0x55497a66 wait_on_page_bit +EXPORT_SYMBOL vmlinux 0x554cac81 nf_unregister_hook +EXPORT_SYMBOL vmlinux 0x555229c3 generic_setlease +EXPORT_SYMBOL vmlinux 0x5554749f devm_free_irq +EXPORT_SYMBOL vmlinux 0x557e1fe6 alloc_buffer_head +EXPORT_SYMBOL vmlinux 0x5594be03 bitmap_remap +EXPORT_SYMBOL vmlinux 0x5596af16 wireless_send_event +EXPORT_SYMBOL vmlinux 0x5600904f fb_get_color_depth +EXPORT_SYMBOL vmlinux 0x560cdb9b sk_receive_skb +EXPORT_SYMBOL vmlinux 0x5635a60a vmalloc_user +EXPORT_SYMBOL vmlinux 0x563952a3 kblockd_schedule_work +EXPORT_SYMBOL vmlinux 0x563d4754 skb_dequeue +EXPORT_SYMBOL vmlinux 0x564fe246 ethtool_op_get_tso +EXPORT_SYMBOL vmlinux 0x5663a1c6 ip4_datagram_connect +EXPORT_SYMBOL vmlinux 0x566b3dd1 input_unregister_device +EXPORT_SYMBOL vmlinux 0x567bb0ac elv_add_request +EXPORT_SYMBOL vmlinux 0x56a01e9a call_usermodehelper_setup +EXPORT_SYMBOL vmlinux 0x56bf8cfa alloc_fddidev +EXPORT_SYMBOL vmlinux 0x56db211e generic_removexattr +EXPORT_SYMBOL vmlinux 0x56e74a02 sg_miter_next +EXPORT_SYMBOL vmlinux 0x56f494e0 smp_call_function +EXPORT_SYMBOL vmlinux 0x5718c7f0 dst_alloc +EXPORT_SYMBOL vmlinux 0x572e85d4 blk_lookup_devt +EXPORT_SYMBOL vmlinux 0x5766cec3 bio_phys_segments +EXPORT_SYMBOL vmlinux 0x577cc638 mutex_unlock +EXPORT_SYMBOL vmlinux 0x578ee764 fb_firmware_edid +EXPORT_SYMBOL vmlinux 0x57975ecf alloc_tty_driver +EXPORT_SYMBOL vmlinux 0x57a6504e vsnprintf +EXPORT_SYMBOL vmlinux 0x57abc4b7 task_pid_nr_ns +EXPORT_SYMBOL vmlinux 0x57bce311 atm_dev_lookup +EXPORT_SYMBOL vmlinux 0x57e37975 bio_integrity_tag_size +EXPORT_SYMBOL vmlinux 0x5800191f blkdev_get +EXPORT_SYMBOL vmlinux 0x5838f6c9 rtc_valid_tm +EXPORT_SYMBOL vmlinux 0x583d40a8 __xfrm_state_destroy +EXPORT_SYMBOL vmlinux 0x5843af4e neigh_parms_alloc +EXPORT_SYMBOL vmlinux 0x584738f9 rdmsr_safe_on_cpu +EXPORT_SYMBOL vmlinux 0x5857b225 ioread16_rep +EXPORT_SYMBOL vmlinux 0x58952c74 vm_insert_page +EXPORT_SYMBOL vmlinux 0x58b2afe3 ethtool_op_set_tx_ipv6_csum +EXPORT_SYMBOL vmlinux 0x58d12a58 blk_rq_map_user +EXPORT_SYMBOL vmlinux 0x58ec63ab qdisc_calculate_pkt_len +EXPORT_SYMBOL vmlinux 0x58fef6f8 ist_info +EXPORT_SYMBOL vmlinux 0x592f1120 simple_getattr +EXPORT_SYMBOL vmlinux 0x5934392b fb_register_client +EXPORT_SYMBOL vmlinux 0x594bf15b ioport_map +EXPORT_SYMBOL vmlinux 0x59566d71 __serio_register_driver +EXPORT_SYMBOL vmlinux 0x595ee407 deregister_atm_ioctl +EXPORT_SYMBOL vmlinux 0x5987dded blk_sync_queue +EXPORT_SYMBOL vmlinux 0x5989a130 tcp_simple_retransmit +EXPORT_SYMBOL vmlinux 0x59c584dd tcf_em_tree_dump +EXPORT_SYMBOL vmlinux 0x59cc54c7 page_readlink +EXPORT_SYMBOL vmlinux 0x59d696b6 register_module_notifier +EXPORT_SYMBOL vmlinux 0x59d83a5f pcim_iomap +EXPORT_SYMBOL vmlinux 0x5a4896a8 __put_user_2 +EXPORT_SYMBOL vmlinux 0x5a607e04 fb_find_mode +EXPORT_SYMBOL vmlinux 0x5a6b0d06 vfs_writev +EXPORT_SYMBOL vmlinux 0x5a744b86 netlink_set_nonroot +EXPORT_SYMBOL vmlinux 0x5ab70adb dev_driver_string +EXPORT_SYMBOL vmlinux 0x5ac376a5 acpi_install_fixed_event_handler +EXPORT_SYMBOL vmlinux 0x5ac86fcd close_bdev_excl +EXPORT_SYMBOL vmlinux 0x5af85d33 __nla_put +EXPORT_SYMBOL vmlinux 0x5b04634f pnp_find_card +EXPORT_SYMBOL vmlinux 0x5b0d53e1 skb_abort_seq_read +EXPORT_SYMBOL vmlinux 0x5b19634d div_s64_rem +EXPORT_SYMBOL vmlinux 0x5b4b3cd8 sk_dst_check +EXPORT_SYMBOL vmlinux 0x5b51c6a7 acpi_walk_resources +EXPORT_SYMBOL vmlinux 0x5b5af8b8 kill_litter_super +EXPORT_SYMBOL vmlinux 0x5c0b9dbc cancel_dirty_page +EXPORT_SYMBOL vmlinux 0x5c4e9cf3 dma_pool_free +EXPORT_SYMBOL vmlinux 0x5c68705b mca_read_pos +EXPORT_SYMBOL vmlinux 0x5c6bcbf7 bio_alloc_bioset +EXPORT_SYMBOL vmlinux 0x5c9aa822 devm_ioport_map +EXPORT_SYMBOL vmlinux 0x5ca50fd4 cdev_del +EXPORT_SYMBOL vmlinux 0x5cee23e5 kobject_init +EXPORT_SYMBOL vmlinux 0x5cf22388 unregister_con_driver +EXPORT_SYMBOL vmlinux 0x5cf99bbd elv_queue_empty +EXPORT_SYMBOL vmlinux 0x5d18fb94 pcie_port_service_unregister +EXPORT_SYMBOL vmlinux 0x5d29d27f tcp_v4_md5_hash_skb +EXPORT_SYMBOL vmlinux 0x5d73b5f8 km_waitq +EXPORT_SYMBOL vmlinux 0x5d8eb80c ip_getsockopt +EXPORT_SYMBOL vmlinux 0x5d92f21f pci_disable_device +EXPORT_SYMBOL vmlinux 0x5d97b82c __nla_reserve_nohdr +EXPORT_SYMBOL vmlinux 0x5d991093 inet_frags_fini +EXPORT_SYMBOL vmlinux 0x5dbcfa4f boot_cpu_physical_apicid +EXPORT_SYMBOL vmlinux 0x5dd2b30a neigh_destroy +EXPORT_SYMBOL vmlinux 0x5ddd65c7 pci_set_mwi +EXPORT_SYMBOL vmlinux 0x5e2c2d94 xfrm_policy_delete +EXPORT_SYMBOL vmlinux 0x5e486068 dev_disable_lro +EXPORT_SYMBOL vmlinux 0x5e4b5eb0 invalidate_bdev +EXPORT_SYMBOL vmlinux 0x5e79ebec gen_replace_estimator +EXPORT_SYMBOL vmlinux 0x5ea3f4f1 iput +EXPORT_SYMBOL vmlinux 0x5ea520c5 tcp_select_initial_window +EXPORT_SYMBOL vmlinux 0x5eab5ea6 tcf_register_action +EXPORT_SYMBOL vmlinux 0x5ed040b0 pm_set_vt_switch +EXPORT_SYMBOL vmlinux 0x5ed8e8aa netdev_set_master +EXPORT_SYMBOL vmlinux 0x5edd0762 bin2bcd +EXPORT_SYMBOL vmlinux 0x5f143697 blk_integrity_unregister +EXPORT_SYMBOL vmlinux 0x5f1bd579 mca_find_adapter +EXPORT_SYMBOL vmlinux 0x5f270f04 filp_open +EXPORT_SYMBOL vmlinux 0x5f8af9a3 pcix_get_mmrbc +EXPORT_SYMBOL vmlinux 0x5f8e0ff5 kmem_ptr_validate +EXPORT_SYMBOL vmlinux 0x5f9ac560 dev_add_pack +EXPORT_SYMBOL vmlinux 0x5ff2ba21 __module_put_and_exit +EXPORT_SYMBOL vmlinux 0x5ff42b08 acpi_video_get_capabilities +EXPORT_SYMBOL vmlinux 0x5ff9c774 tcp_make_synack +EXPORT_SYMBOL vmlinux 0x600683d3 do_unblank_screen +EXPORT_SYMBOL vmlinux 0x603b400d sysctl_string +EXPORT_SYMBOL vmlinux 0x60400b7f pv_lock_ops +EXPORT_SYMBOL vmlinux 0x6061cc77 dcache_dir_open +EXPORT_SYMBOL vmlinux 0x607de5fc udp_disconnect +EXPORT_SYMBOL vmlinux 0x608c2831 warn_on_slowpath +EXPORT_SYMBOL vmlinux 0x609f1c7e synchronize_net +EXPORT_SYMBOL vmlinux 0x60a32ea9 pm_power_off +EXPORT_SYMBOL vmlinux 0x60a7bbdb current_fs_time +EXPORT_SYMBOL vmlinux 0x60b6780c simple_unlink +EXPORT_SYMBOL vmlinux 0x60be56e2 udp_poll +EXPORT_SYMBOL vmlinux 0x60f1b3e6 dst_discard +EXPORT_SYMBOL vmlinux 0x6111e1bc init_timer +EXPORT_SYMBOL vmlinux 0x611241c7 netif_carrier_on +EXPORT_SYMBOL vmlinux 0x612390ad netpoll_set_trap +EXPORT_SYMBOL vmlinux 0x615cd35f sg_miter_stop +EXPORT_SYMBOL vmlinux 0x61727eb0 tty_insert_flip_string +EXPORT_SYMBOL vmlinux 0x618d8299 set_notify_swap_entry_free +EXPORT_SYMBOL vmlinux 0x61957eaf __vlan_hwaccel_rx +EXPORT_SYMBOL vmlinux 0x619b3f3c blk_insert_request +EXPORT_SYMBOL vmlinux 0x61aa2ec0 __serio_register_port +EXPORT_SYMBOL vmlinux 0x61b7b126 simple_strtoull +EXPORT_SYMBOL vmlinux 0x6202864e new_inode +EXPORT_SYMBOL vmlinux 0x62049256 acpi_disable +EXPORT_SYMBOL vmlinux 0x6224446a tty_flip_buffer_push +EXPORT_SYMBOL vmlinux 0x6237f6b5 acpi_enable_event +EXPORT_SYMBOL vmlinux 0x6241a2ab __copy_from_user_ll_nocache +EXPORT_SYMBOL vmlinux 0x6241fd2c acpi_install_address_space_handler +EXPORT_SYMBOL vmlinux 0x625098b5 follow_down +EXPORT_SYMBOL vmlinux 0x625c0344 blk_queue_update_dma_alignment +EXPORT_SYMBOL vmlinux 0x6265d7a5 sock_release +EXPORT_SYMBOL vmlinux 0x62737e1d sock_unregister +EXPORT_SYMBOL vmlinux 0x62827bec security_secctx_to_secid +EXPORT_SYMBOL vmlinux 0x62930e73 udp_sendmsg +EXPORT_SYMBOL vmlinux 0x62a5b74f ip_route_input +EXPORT_SYMBOL vmlinux 0x62abfb96 sk_stream_wait_memory +EXPORT_SYMBOL vmlinux 0x62b09f37 pcim_iounmap_regions +EXPORT_SYMBOL vmlinux 0x62d4d016 inet_proto_csum_replace4 +EXPORT_SYMBOL vmlinux 0x62e57418 generic_permission +EXPORT_SYMBOL vmlinux 0x62ecc29d __break_lease +EXPORT_SYMBOL vmlinux 0x630f996f proc_dointvec +EXPORT_SYMBOL vmlinux 0x63189e8d input_get_keycode +EXPORT_SYMBOL vmlinux 0x636a5691 acpi_register_ioapic +EXPORT_SYMBOL vmlinux 0x63701f24 generic_file_splice_read +EXPORT_SYMBOL vmlinux 0x638676ba dma_release_declared_memory +EXPORT_SYMBOL vmlinux 0x63a8af6c ethtool_op_set_flags +EXPORT_SYMBOL vmlinux 0x63ac890d sk_reset_timer +EXPORT_SYMBOL vmlinux 0x63ecad53 register_netdevice_notifier +EXPORT_SYMBOL vmlinux 0x63ed4f65 ioremap_cache +EXPORT_SYMBOL vmlinux 0x63f08831 acpi_bus_unregister_driver +EXPORT_SYMBOL vmlinux 0x6403e338 tcp_memory_pressure +EXPORT_SYMBOL vmlinux 0x641275c3 load_nls_default +EXPORT_SYMBOL vmlinux 0x642e54ac __wake_up +EXPORT_SYMBOL vmlinux 0x643f228a proc_dostring +EXPORT_SYMBOL vmlinux 0x6451294b posix_acl_valid +EXPORT_SYMBOL vmlinux 0x6466a1e6 mempool_alloc +EXPORT_SYMBOL vmlinux 0x6478134c ec_burst_enable +EXPORT_SYMBOL vmlinux 0x6478cb90 tcp_connect +EXPORT_SYMBOL vmlinux 0x64999478 congestion_wait +EXPORT_SYMBOL vmlinux 0x64b3fc45 ip_ct_attach +EXPORT_SYMBOL vmlinux 0x64cd5d16 init_waitqueue_head +EXPORT_SYMBOL vmlinux 0x64e84c57 sg_miter_start +EXPORT_SYMBOL vmlinux 0x650128e7 br_fdb_get_hook +EXPORT_SYMBOL vmlinux 0x650fb346 add_wait_queue +EXPORT_SYMBOL vmlinux 0x65408378 zlib_inflate_blob +EXPORT_SYMBOL vmlinux 0x65414e67 dev_valid_name +EXPORT_SYMBOL vmlinux 0x657356ea write_one_page +EXPORT_SYMBOL vmlinux 0x6584d7d2 eisa_driver_unregister +EXPORT_SYMBOL vmlinux 0x65ed22c7 sb_has_dirty_inodes +EXPORT_SYMBOL vmlinux 0x660cb933 dquot_drop +EXPORT_SYMBOL vmlinux 0x66204bdb bio_integrity_prep +EXPORT_SYMBOL vmlinux 0x66406643 vfs_write +EXPORT_SYMBOL vmlinux 0x66514dc6 arp_send +EXPORT_SYMBOL vmlinux 0x666ac1d8 vc_cons +EXPORT_SYMBOL vmlinux 0x668da8d5 zlib_inflateIncomp +EXPORT_SYMBOL vmlinux 0x669e65f5 skb_truesize_bug +EXPORT_SYMBOL vmlinux 0x670189af register_binfmt +EXPORT_SYMBOL vmlinux 0x6729d3df __get_user_4 +EXPORT_SYMBOL vmlinux 0x6730a642 gnet_stats_start_copy +EXPORT_SYMBOL vmlinux 0x678f43c3 mntput_no_expire +EXPORT_SYMBOL vmlinux 0x67b27ec1 tty_std_termios +EXPORT_SYMBOL vmlinux 0x67bedfb7 destroy_EII_client +EXPORT_SYMBOL vmlinux 0x67c68639 page_put_link +EXPORT_SYMBOL vmlinux 0x67e71b77 __mutex_init +EXPORT_SYMBOL vmlinux 0x67f7318a kset_register +EXPORT_SYMBOL vmlinux 0x67fc7fbd devm_ioport_unmap +EXPORT_SYMBOL vmlinux 0x681ecea1 d_genocide +EXPORT_SYMBOL vmlinux 0x6871c8e7 fb_get_buffer_offset +EXPORT_SYMBOL vmlinux 0x68cefb17 find_or_create_page +EXPORT_SYMBOL vmlinux 0x6905075c blk_queue_invalidate_tags +EXPORT_SYMBOL vmlinux 0x694c5f6f iget5_locked +EXPORT_SYMBOL vmlinux 0x6953d9dc __find_get_block +EXPORT_SYMBOL vmlinux 0x69618c83 directly_mappable_cdev_bdi +EXPORT_SYMBOL vmlinux 0x6971447a rtc_month_days +EXPORT_SYMBOL vmlinux 0x69806cab mca_bus_type +EXPORT_SYMBOL vmlinux 0x69927dff try_acquire_console_sem +EXPORT_SYMBOL vmlinux 0x69a0ca7d iowrite16be +EXPORT_SYMBOL vmlinux 0x69a5c232 dcache_readdir +EXPORT_SYMBOL vmlinux 0x69e69213 iget_locked +EXPORT_SYMBOL vmlinux 0x69f7cde2 do_munmap +EXPORT_SYMBOL vmlinux 0x6a037cf1 mempool_kfree +EXPORT_SYMBOL vmlinux 0x6a05afca kmap_high +EXPORT_SYMBOL vmlinux 0x6a27bfce csum_partial_copy_generic +EXPORT_SYMBOL vmlinux 0x6a47571d __set_personality +EXPORT_SYMBOL vmlinux 0x6a6cc4bb key_payload_reserve +EXPORT_SYMBOL vmlinux 0x6a8058ab sk_wait_data +EXPORT_SYMBOL vmlinux 0x6a88b45b generic_write_end +EXPORT_SYMBOL vmlinux 0x6a903418 blkdev_put +EXPORT_SYMBOL vmlinux 0x6a9d9337 sock_no_connect +EXPORT_SYMBOL vmlinux 0x6aa84573 blk_start_queue +EXPORT_SYMBOL vmlinux 0x6aae09de gnet_stats_copy_basic +EXPORT_SYMBOL vmlinux 0x6ab9a319 security_sb_set_mnt_opts +EXPORT_SYMBOL vmlinux 0x6acb973d iowrite32be +EXPORT_SYMBOL vmlinux 0x6add5c9a dmi_find_device +EXPORT_SYMBOL vmlinux 0x6ae4b58a file_fsync +EXPORT_SYMBOL vmlinux 0x6b1b67d3 __bdevname +EXPORT_SYMBOL vmlinux 0x6b2dc060 dump_stack +EXPORT_SYMBOL vmlinux 0x6b35cf5e inet_frag_kill +EXPORT_SYMBOL vmlinux 0x6b40313c xfrm4_rcv_encap +EXPORT_SYMBOL vmlinux 0x6b5aaa0d netlink_clear_multicast_users +EXPORT_SYMBOL vmlinux 0x6b6b7dd8 cfb_imageblit +EXPORT_SYMBOL vmlinux 0x6b8a7f42 inet_dgram_connect +EXPORT_SYMBOL vmlinux 0x6b8bd8b8 sock_get_timestamp +EXPORT_SYMBOL vmlinux 0x6b937ffb mca_mark_as_used +EXPORT_SYMBOL vmlinux 0x6b9b88f3 sleep_on +EXPORT_SYMBOL vmlinux 0x6ba41ac8 neigh_ifdown +EXPORT_SYMBOL vmlinux 0x6bafbced mod_timer +EXPORT_SYMBOL vmlinux 0x6bb8e376 neigh_update +EXPORT_SYMBOL vmlinux 0x6bc30671 xfrm_find_acq +EXPORT_SYMBOL vmlinux 0x6bdcfd99 qdisc_class_hash_remove +EXPORT_SYMBOL vmlinux 0x6bfaacaa inet_ioctl +EXPORT_SYMBOL vmlinux 0x6c1ce5ce strcspn +EXPORT_SYMBOL vmlinux 0x6c2b8f75 xfrm_prepare_input +EXPORT_SYMBOL vmlinux 0x6c2e3320 strncmp +EXPORT_SYMBOL vmlinux 0x6c389761 acpi_bus_get_private_data +EXPORT_SYMBOL vmlinux 0x6c58650d ip_mc_join_group +EXPORT_SYMBOL vmlinux 0x6c5c3927 security_inode_init_security +EXPORT_SYMBOL vmlinux 0x6c61ce70 num_registered_fb +EXPORT_SYMBOL vmlinux 0x6c702af7 sysctl_udp_rmem_min +EXPORT_SYMBOL vmlinux 0x6c939240 pci_get_subsys +EXPORT_SYMBOL vmlinux 0x6cc37b54 acpi_root_dir +EXPORT_SYMBOL vmlinux 0x6cd9f57e mca_device_read_stored_pos +EXPORT_SYMBOL vmlinux 0x6cdc5c6b nla_strlcpy +EXPORT_SYMBOL vmlinux 0x6ce93950 tty_devnum +EXPORT_SYMBOL vmlinux 0x6cf18467 pci_target_state +EXPORT_SYMBOL vmlinux 0x6d0da34c param_get_short +EXPORT_SYMBOL vmlinux 0x6d10832b key_put +EXPORT_SYMBOL vmlinux 0x6d1ced27 vcc_sklist_lock +EXPORT_SYMBOL vmlinux 0x6d27ef64 __bitmap_empty +EXPORT_SYMBOL vmlinux 0x6d288375 radix_tree_next_hole +EXPORT_SYMBOL vmlinux 0x6d294e43 clock_t_to_jiffies +EXPORT_SYMBOL vmlinux 0x6d340f64 tty_termios_input_baud_rate +EXPORT_SYMBOL vmlinux 0x6d34b6e1 __xfrm_decode_session +EXPORT_SYMBOL vmlinux 0x6d3b7f5d bdi_set_max_ratio +EXPORT_SYMBOL vmlinux 0x6d5da1c2 xfrm_state_walk +EXPORT_SYMBOL vmlinux 0x6dc0c24b complete_and_exit +EXPORT_SYMBOL vmlinux 0x6dee7be5 dump_fpu +EXPORT_SYMBOL vmlinux 0x6def2db2 half_md4_transform +EXPORT_SYMBOL vmlinux 0x6e07a54e acpi_get_gpe_status +EXPORT_SYMBOL vmlinux 0x6e1a4bbb udp_hash_lock +EXPORT_SYMBOL vmlinux 0x6e34a2fc vm_insert_pfn +EXPORT_SYMBOL vmlinux 0x6e3c6e3f nf_register_hook +EXPORT_SYMBOL vmlinux 0x6e440b58 memcpy_fromiovecend +EXPORT_SYMBOL vmlinux 0x6e57e76b blk_dump_rq_flags +EXPORT_SYMBOL vmlinux 0x6e71701e file_permission +EXPORT_SYMBOL vmlinux 0x6e720ff2 rtnl_unlock +EXPORT_SYMBOL vmlinux 0x6e9dd606 __symbol_put +EXPORT_SYMBOL vmlinux 0x6ead242b cond_resched_lock +EXPORT_SYMBOL vmlinux 0x6ef98516 pci_pme_capable +EXPORT_SYMBOL vmlinux 0x6f602879 tcf_em_unregister +EXPORT_SYMBOL vmlinux 0x6f6b7960 tcp_rcv_state_process +EXPORT_SYMBOL vmlinux 0x6f8ce70c blk_run_queue +EXPORT_SYMBOL vmlinux 0x6fa9e95f pci_scan_single_device +EXPORT_SYMBOL vmlinux 0x6fabf2c7 blk_queue_end_tag +EXPORT_SYMBOL vmlinux 0x6fcb87a1 touch_softlockup_watchdog +EXPORT_SYMBOL vmlinux 0x6fdb9c87 pci_set_dma_mask +EXPORT_SYMBOL vmlinux 0x7008a9b7 timespec_to_jiffies +EXPORT_SYMBOL vmlinux 0x700a0fc1 __scm_destroy +EXPORT_SYMBOL vmlinux 0x701d0ebd snprintf +EXPORT_SYMBOL vmlinux 0x702ac1d2 elv_rb_del +EXPORT_SYMBOL vmlinux 0x703912c2 dma_ops +EXPORT_SYMBOL vmlinux 0x70461a22 key_revoke +EXPORT_SYMBOL vmlinux 0x7054a3e4 request_dma +EXPORT_SYMBOL vmlinux 0x7098c27c dev_get_flags +EXPORT_SYMBOL vmlinux 0x70a55667 filemap_fdatawait +EXPORT_SYMBOL vmlinux 0x70d09066 genl_sock +EXPORT_SYMBOL vmlinux 0x70d1f8f3 strncat +EXPORT_SYMBOL vmlinux 0x70d8ab82 acpi_acquire_global_lock +EXPORT_SYMBOL vmlinux 0x71292fbd xfrm_policy_bysel_ctx +EXPORT_SYMBOL vmlinux 0x7129e5f8 hex_asc +EXPORT_SYMBOL vmlinux 0x712aa29b _spin_lock_irqsave +EXPORT_SYMBOL vmlinux 0x71356fba remove_wait_queue +EXPORT_SYMBOL vmlinux 0x7150fcb9 dev_getfirstbyhwtype +EXPORT_SYMBOL vmlinux 0x7152be1e skb_split +EXPORT_SYMBOL vmlinux 0x716e54ff tcp_v4_md5_lookup +EXPORT_SYMBOL vmlinux 0x7171121c overflowgid +EXPORT_SYMBOL vmlinux 0x71a50dbc register_blkdev +EXPORT_SYMBOL vmlinux 0x71ce8525 write_cache_pages +EXPORT_SYMBOL vmlinux 0x71fbfe1f atm_init_aal5 +EXPORT_SYMBOL vmlinux 0x72270e35 do_gettimeofday +EXPORT_SYMBOL vmlinux 0x72624148 sock_no_setsockopt +EXPORT_SYMBOL vmlinux 0x726428a4 __lookup_hash +EXPORT_SYMBOL vmlinux 0x72b243d4 free_dma +EXPORT_SYMBOL vmlinux 0x72bf2140 mtrr_add +EXPORT_SYMBOL vmlinux 0x72cc8452 elv_dequeue_request +EXPORT_SYMBOL vmlinux 0x72e59f17 __bio_clone +EXPORT_SYMBOL vmlinux 0x72f67dc3 blk_queue_update_dma_pad +EXPORT_SYMBOL vmlinux 0x730efe6c __tcf_em_tree_match +EXPORT_SYMBOL vmlinux 0x734234db skb_find_text +EXPORT_SYMBOL vmlinux 0x735a0bd5 native_io_delay +EXPORT_SYMBOL vmlinux 0x7373bf16 neigh_seq_stop +EXPORT_SYMBOL vmlinux 0x738803e6 strnlen +EXPORT_SYMBOL vmlinux 0x7389c9a8 acpi_bus_get_power +EXPORT_SYMBOL vmlinux 0x7389f523 tty_write_room +EXPORT_SYMBOL vmlinux 0x738f3302 sock_sendmsg +EXPORT_SYMBOL vmlinux 0x7393cba4 tcp_parse_options +EXPORT_SYMBOL vmlinux 0x73e20c1c strlcpy +EXPORT_SYMBOL vmlinux 0x740a1b95 reserve_evntsel_nmi +EXPORT_SYMBOL vmlinux 0x7413793a EISA_bus +EXPORT_SYMBOL vmlinux 0x741c7d1c skb_copy_datagram_from_iovec +EXPORT_SYMBOL vmlinux 0x74202777 ioremap_prot +EXPORT_SYMBOL vmlinux 0x743241d9 kernel_listen +EXPORT_SYMBOL vmlinux 0x74348096 module_put +EXPORT_SYMBOL vmlinux 0x74560b73 sock_no_mmap +EXPORT_SYMBOL vmlinux 0x747f430b sk_stream_kill_queues +EXPORT_SYMBOL vmlinux 0x7485e15e unregister_chrdev_region +EXPORT_SYMBOL vmlinux 0x748caf40 down +EXPORT_SYMBOL vmlinux 0x74a0f33b mca_device_set_name +EXPORT_SYMBOL vmlinux 0x74cc1cbe unregister_cpu_notifier +EXPORT_SYMBOL vmlinux 0x74cc238d current_kernel_time +EXPORT_SYMBOL vmlinux 0x74f1cdec ht_create_irq +EXPORT_SYMBOL vmlinux 0x75271716 save_processor_state +EXPORT_SYMBOL vmlinux 0x753b7b08 __secpath_destroy +EXPORT_SYMBOL vmlinux 0x75566739 complete_request_key +EXPORT_SYMBOL vmlinux 0x758a15ba register_key_type +EXPORT_SYMBOL vmlinux 0x75920c05 neigh_lookup +EXPORT_SYMBOL vmlinux 0x75986126 mca_unregister_driver +EXPORT_SYMBOL vmlinux 0x75b6fe92 arp_find +EXPORT_SYMBOL vmlinux 0x75bf4aaf stop_tty +EXPORT_SYMBOL vmlinux 0x75d9949c ethtool_op_get_ufo +EXPORT_SYMBOL vmlinux 0x760a0f4f yield +EXPORT_SYMBOL vmlinux 0x760b437a unregister_inetaddr_notifier +EXPORT_SYMBOL vmlinux 0x7648d935 __xfrm_policy_check +EXPORT_SYMBOL vmlinux 0x76490a2c udp_lib_get_port +EXPORT_SYMBOL vmlinux 0x767ddb02 set_memory_wc +EXPORT_SYMBOL vmlinux 0x76845676 thermal_cooling_device_register +EXPORT_SYMBOL vmlinux 0x768c3a51 generic_getxattr +EXPORT_SYMBOL vmlinux 0x769f4722 ip_fragment +EXPORT_SYMBOL vmlinux 0x76bf656d __bitmap_shift_left +EXPORT_SYMBOL vmlinux 0x76d3cd60 laptop_mode +EXPORT_SYMBOL vmlinux 0x76f3f8a5 num_k8_northbridges +EXPORT_SYMBOL vmlinux 0x7707988a lease_get_mtime +EXPORT_SYMBOL vmlinux 0x770a0036 isapnp_cfg_begin +EXPORT_SYMBOL vmlinux 0x773699ee contig_page_data +EXPORT_SYMBOL vmlinux 0x774470a0 dev_set_mtu +EXPORT_SYMBOL vmlinux 0x7780e76d task_session_nr_ns +EXPORT_SYMBOL vmlinux 0x77a108df _write_unlock_irqrestore +EXPORT_SYMBOL vmlinux 0x77ac71c1 alloc_fcdev +EXPORT_SYMBOL vmlinux 0x77ecac9f zlib_inflateEnd +EXPORT_SYMBOL vmlinux 0x77f3e743 dentry_unhash +EXPORT_SYMBOL vmlinux 0x781d22ad pci_scan_bus_parented +EXPORT_SYMBOL vmlinux 0x781d3894 acpi_bus_get_status +EXPORT_SYMBOL vmlinux 0x783f3678 get_sb_bdev +EXPORT_SYMBOL vmlinux 0x7868b50f bmap +EXPORT_SYMBOL vmlinux 0x7875fab7 sget +EXPORT_SYMBOL vmlinux 0x78948825 __dev_get_by_index +EXPORT_SYMBOL vmlinux 0x789c12ad nf_unregister_sockopt +EXPORT_SYMBOL vmlinux 0x78a484c9 _read_unlock_irqrestore +EXPORT_SYMBOL vmlinux 0x78c02f31 filemap_write_and_wait +EXPORT_SYMBOL vmlinux 0x78cb2783 down_write_trylock +EXPORT_SYMBOL vmlinux 0x78d1ca6a vfs_quota_on_mount +EXPORT_SYMBOL vmlinux 0x78decd99 get_fs_type +EXPORT_SYMBOL vmlinux 0x78df6bd7 no_pci_devices +EXPORT_SYMBOL vmlinux 0x78f07f21 dquot_acquire +EXPORT_SYMBOL vmlinux 0x7943bace blk_alloc_queue +EXPORT_SYMBOL vmlinux 0x794439a0 mca_device_transform_ioport +EXPORT_SYMBOL vmlinux 0x794487ee disable_hlt +EXPORT_SYMBOL vmlinux 0x794c1398 dmi_check_system +EXPORT_SYMBOL vmlinux 0x79656409 cpu_online_map +EXPORT_SYMBOL vmlinux 0x79789e03 ethtool_op_set_tso +EXPORT_SYMBOL vmlinux 0x79807827 tcp_hashinfo +EXPORT_SYMBOL vmlinux 0x79a704b9 blk_queue_stack_limits +EXPORT_SYMBOL vmlinux 0x79aa04a2 get_random_bytes +EXPORT_SYMBOL vmlinux 0x79aa05a8 match_token +EXPORT_SYMBOL vmlinux 0x79d097b3 block_sync_page +EXPORT_SYMBOL vmlinux 0x79d78989 set_irq_chip +EXPORT_SYMBOL vmlinux 0x7a037301 __fatal_signal_pending +EXPORT_SYMBOL vmlinux 0x7a2a837d strict_strtol +EXPORT_SYMBOL vmlinux 0x7a7b68a0 nf_log_unregister +EXPORT_SYMBOL vmlinux 0x7a848702 _read_lock_irqsave +EXPORT_SYMBOL vmlinux 0x7ab166e9 inet_csk_clear_xmit_timers +EXPORT_SYMBOL vmlinux 0x7ac29175 register_filesystem +EXPORT_SYMBOL vmlinux 0x7aec9089 clear_user +EXPORT_SYMBOL vmlinux 0x7b0c84c4 acpi_remove_table_handler +EXPORT_SYMBOL vmlinux 0x7b134ddf acpi_get_name +EXPORT_SYMBOL vmlinux 0x7b390952 generic_shutdown_super +EXPORT_SYMBOL vmlinux 0x7b52a859 wrmsr_safe_on_cpu +EXPORT_SYMBOL vmlinux 0x7b5df251 redirty_page_for_writepage +EXPORT_SYMBOL vmlinux 0x7b69467e posix_acl_from_xattr +EXPORT_SYMBOL vmlinux 0x7b7e3165 pci_unmap_rom +EXPORT_SYMBOL vmlinux 0x7bcb19b8 __seq_open_private +EXPORT_SYMBOL vmlinux 0x7bdd6002 neigh_for_each +EXPORT_SYMBOL vmlinux 0x7bee8b7b __pagevec_release +EXPORT_SYMBOL vmlinux 0x7c1ffe4a arp_tbl +EXPORT_SYMBOL vmlinux 0x7c46233a cpufreq_quick_get +EXPORT_SYMBOL vmlinux 0x7c5d23ff __dec_zone_page_state +EXPORT_SYMBOL vmlinux 0x7c5e4942 neigh_resolve_output +EXPORT_SYMBOL vmlinux 0x7c60d66e getname +EXPORT_SYMBOL vmlinux 0x7c7cd740 neigh_create +EXPORT_SYMBOL vmlinux 0x7c904ded unregister_module_notifier +EXPORT_SYMBOL vmlinux 0x7c9daca5 vfs_dq_quota_on_remount +EXPORT_SYMBOL vmlinux 0x7ca064c6 vfs_readlink +EXPORT_SYMBOL vmlinux 0x7cb1ae69 cpu_down +EXPORT_SYMBOL vmlinux 0x7cfe97d8 pnp_start_dev +EXPORT_SYMBOL vmlinux 0x7d047e7e acpi_ut_exception +EXPORT_SYMBOL vmlinux 0x7d11c268 jiffies +EXPORT_SYMBOL vmlinux 0x7d6a9133 tcp_sendpage +EXPORT_SYMBOL vmlinux 0x7d79a978 request_key_with_auxdata +EXPORT_SYMBOL vmlinux 0x7d80925e pci_find_capability +EXPORT_SYMBOL vmlinux 0x7d850612 utf8_mbstowcs +EXPORT_SYMBOL vmlinux 0x7d948097 load_nls +EXPORT_SYMBOL vmlinux 0x7d9a041e invalidate_inodes +EXPORT_SYMBOL vmlinux 0x7dceceac capable +EXPORT_SYMBOL vmlinux 0x7dd0e8d3 find_vma +EXPORT_SYMBOL vmlinux 0x7defa9a2 balance_dirty_pages_ratelimited_nr +EXPORT_SYMBOL vmlinux 0x7e4063eb dev_change_flags +EXPORT_SYMBOL vmlinux 0x7e593012 tcp_init_xmit_timers +EXPORT_SYMBOL vmlinux 0x7e79e3c8 tty_register_ldisc +EXPORT_SYMBOL vmlinux 0x7e862304 vfs_get_dqblk +EXPORT_SYMBOL vmlinux 0x7e9ebb05 kernel_thread +EXPORT_SYMBOL vmlinux 0x7ea8d414 pnp_get_resource +EXPORT_SYMBOL vmlinux 0x7ee91c1d _spin_trylock +EXPORT_SYMBOL vmlinux 0x7efbe560 per_cpu__cpu_core_map +EXPORT_SYMBOL vmlinux 0x7f24de73 jiffies_to_usecs +EXPORT_SYMBOL vmlinux 0x7f2aacaf block_write_begin +EXPORT_SYMBOL vmlinux 0x7f39ff4a remove_inode_hash +EXPORT_SYMBOL vmlinux 0x7f4cfeb1 pnp_request_card_device +EXPORT_SYMBOL vmlinux 0x7f5728af key_type_keyring +EXPORT_SYMBOL vmlinux 0x7f8723bd pcie_mch_quirk +EXPORT_SYMBOL vmlinux 0x7fe9e2dd elv_rb_add +EXPORT_SYMBOL vmlinux 0x7fef5916 nf_register_hooks +EXPORT_SYMBOL vmlinux 0x7fefc556 is_container_init +EXPORT_SYMBOL vmlinux 0x7ff4de7c task_pgrp_nr_ns +EXPORT_SYMBOL vmlinux 0x7ffd9451 prepare_binprm +EXPORT_SYMBOL vmlinux 0x8000fd95 check_disk_change +EXPORT_SYMBOL vmlinux 0x801b5b53 __skb_checksum_complete +EXPORT_SYMBOL vmlinux 0x801cc62e pcix_get_max_mmrbc +EXPORT_SYMBOL vmlinux 0x805ca887 blk_plug_device_unlocked +EXPORT_SYMBOL vmlinux 0x8063f83d radix_tree_gang_lookup +EXPORT_SYMBOL vmlinux 0x806ad20f do_sync_read +EXPORT_SYMBOL vmlinux 0x80d3e02e dev_mc_sync +EXPORT_SYMBOL vmlinux 0x80ea8022 blk_queue_prep_rq +EXPORT_SYMBOL vmlinux 0x8109201f skb_pull +EXPORT_SYMBOL vmlinux 0x8132e5e1 d_instantiate_unique +EXPORT_SYMBOL vmlinux 0x81472677 acpi_get_table +EXPORT_SYMBOL vmlinux 0x814c379e ilookup +EXPORT_SYMBOL vmlinux 0x814e7730 nf_ct_destroy +EXPORT_SYMBOL vmlinux 0x815082ad skb_copy_and_csum_dev +EXPORT_SYMBOL vmlinux 0x815b5dd4 match_octal +EXPORT_SYMBOL vmlinux 0x815f2897 empty_zero_page +EXPORT_SYMBOL vmlinux 0x81799cee vscnprintf +EXPORT_SYMBOL vmlinux 0x81a2f4d1 bdevname +EXPORT_SYMBOL vmlinux 0x81a79e9f tcf_generic_walker +EXPORT_SYMBOL vmlinux 0x81c56769 clear_page_dirty_for_io +EXPORT_SYMBOL vmlinux 0x81daa947 tty_check_change +EXPORT_SYMBOL vmlinux 0x81de38aa get_user_pages +EXPORT_SYMBOL vmlinux 0x81e6b37f dmi_get_system_info +EXPORT_SYMBOL vmlinux 0x81efcb62 pcie_get_readrq +EXPORT_SYMBOL vmlinux 0x82072614 tasklet_kill +EXPORT_SYMBOL vmlinux 0x820d225f print_mac +EXPORT_SYMBOL vmlinux 0x8235805b memmove +EXPORT_SYMBOL vmlinux 0x8251bcc3 bitmap_release_region +EXPORT_SYMBOL vmlinux 0x82673561 schedule_delayed_work +EXPORT_SYMBOL vmlinux 0x828f6b2b request_key_async +EXPORT_SYMBOL vmlinux 0x82a1ef73 generic_file_llseek_unlocked +EXPORT_SYMBOL vmlinux 0x82adc4b1 d_add_ci +EXPORT_SYMBOL vmlinux 0x82c2c9cd tty_register_driver +EXPORT_SYMBOL vmlinux 0x830ed528 elv_rb_find +EXPORT_SYMBOL vmlinux 0x8317e20a completion_done +EXPORT_SYMBOL vmlinux 0x833e670a dquot_commit_info +EXPORT_SYMBOL vmlinux 0x835f2437 pci_request_regions +EXPORT_SYMBOL vmlinux 0x8363c3d4 smp_call_function_mask +EXPORT_SYMBOL vmlinux 0x83765be1 llc_build_and_send_ui_pkt +EXPORT_SYMBOL vmlinux 0x83800bfa kref_init +EXPORT_SYMBOL vmlinux 0x8397072e get_write_access +EXPORT_SYMBOL vmlinux 0x83a476ce bitmap_scnlistprintf +EXPORT_SYMBOL vmlinux 0x83c433cf posix_lock_file +EXPORT_SYMBOL vmlinux 0x84279870 dev_close +EXPORT_SYMBOL vmlinux 0x844ee789 inode_get_bytes +EXPORT_SYMBOL vmlinux 0x84808f15 kunmap +EXPORT_SYMBOL vmlinux 0x84b72694 generic_file_llseek +EXPORT_SYMBOL vmlinux 0x84d5115c tcp_v4_send_check +EXPORT_SYMBOL vmlinux 0x84debf36 pci_bus_read_config_byte +EXPORT_SYMBOL vmlinux 0x84e58727 netlink_change_ngroups +EXPORT_SYMBOL vmlinux 0x85470c23 ip_queue_xmit +EXPORT_SYMBOL vmlinux 0x85670f1d rtnl_is_locked +EXPORT_SYMBOL vmlinux 0x85967a17 sock_i_uid +EXPORT_SYMBOL vmlinux 0x85a10d1e netpoll_parse_options +EXPORT_SYMBOL vmlinux 0x85df9b6c strsep +EXPORT_SYMBOL vmlinux 0x85e7deb2 iov_iter_fault_in_readable +EXPORT_SYMBOL vmlinux 0x85f4c2e3 qdisc_list_del +EXPORT_SYMBOL vmlinux 0x85f6d98f uart_remove_one_port +EXPORT_SYMBOL vmlinux 0x8611ea2b bio_integrity_advance +EXPORT_SYMBOL vmlinux 0x86315ae8 ethtool_op_set_tx_hw_csum +EXPORT_SYMBOL vmlinux 0x863714b9 pci_disable_msix +EXPORT_SYMBOL vmlinux 0x863cb91a utf8_wcstombs +EXPORT_SYMBOL vmlinux 0x8664f62e cpufreq_update_policy +EXPORT_SYMBOL vmlinux 0x866930c8 tty_unregister_driver +EXPORT_SYMBOL vmlinux 0x867cb666 serio_unregister_child_port +EXPORT_SYMBOL vmlinux 0x868acba5 get_options +EXPORT_SYMBOL vmlinux 0x86a809c1 __nla_put_nohdr +EXPORT_SYMBOL vmlinux 0x86aa43a5 netlink_dump_start +EXPORT_SYMBOL vmlinux 0x86cdb19b pcim_iomap_table +EXPORT_SYMBOL vmlinux 0x86ed41ae textsearch_destroy +EXPORT_SYMBOL vmlinux 0x86fb9b05 bitmap_parse_user +EXPORT_SYMBOL vmlinux 0x8733e9a3 sleep_on_timeout +EXPORT_SYMBOL vmlinux 0x8740f267 d_move +EXPORT_SYMBOL vmlinux 0x8767511d con_copy_unimap +EXPORT_SYMBOL vmlinux 0x87692c49 pnp_possible_config +EXPORT_SYMBOL vmlinux 0x876dafc3 ec_write +EXPORT_SYMBOL vmlinux 0x8785725d param_set_charp +EXPORT_SYMBOL vmlinux 0x878ab3ce sysctl_tcp_adv_win_scale +EXPORT_SYMBOL vmlinux 0x87b7917e vfs_follow_link +EXPORT_SYMBOL vmlinux 0x881039d0 zlib_inflate +EXPORT_SYMBOL vmlinux 0x882a5d80 dquot_alloc_inode +EXPORT_SYMBOL vmlinux 0x8870e1ec register_quota_format +EXPORT_SYMBOL vmlinux 0x8913e813 aio_complete +EXPORT_SYMBOL vmlinux 0x892b26a0 set_memory_nx +EXPORT_SYMBOL vmlinux 0x89304c9c devm_iounmap +EXPORT_SYMBOL vmlinux 0x8931b32a init_net +EXPORT_SYMBOL vmlinux 0x8949858b schedule_work +EXPORT_SYMBOL vmlinux 0x8953bb27 del_timer +EXPORT_SYMBOL vmlinux 0x8958fba8 __set_page_dirty_buffers +EXPORT_SYMBOL vmlinux 0x8969b997 ida_get_new +EXPORT_SYMBOL vmlinux 0x896a050a arch_acpi_processor_init_pdc +EXPORT_SYMBOL vmlinux 0x897473df mktime +EXPORT_SYMBOL vmlinux 0x89848e49 find_get_pages_contig +EXPORT_SYMBOL vmlinux 0x898b1fec mutex_trylock +EXPORT_SYMBOL vmlinux 0x898eda8b gnet_stats_copy_app +EXPORT_SYMBOL vmlinux 0x89949018 down_timeout +EXPORT_SYMBOL vmlinux 0x899927bf inet_csk_accept +EXPORT_SYMBOL vmlinux 0x89b74ecf call_usermodehelper_setcleanup +EXPORT_SYMBOL vmlinux 0x89c6480d unregister_filesystem +EXPORT_SYMBOL vmlinux 0x89d5538d fb_pad_aligned_buffer +EXPORT_SYMBOL vmlinux 0x89d66811 build_ehash_secret +EXPORT_SYMBOL vmlinux 0x8a0b87e2 tcp_v4_do_rcv +EXPORT_SYMBOL vmlinux 0x8a1cb661 pneigh_lookup +EXPORT_SYMBOL vmlinux 0x8a2aba0c dquot_free_inode +EXPORT_SYMBOL vmlinux 0x8a3d2f14 make_EII_client +EXPORT_SYMBOL vmlinux 0x8a3eabf0 __wait_on_bit +EXPORT_SYMBOL vmlinux 0x8a7d1c31 high_memory +EXPORT_SYMBOL vmlinux 0x8a90d932 allocate_resource +EXPORT_SYMBOL vmlinux 0x8a99a016 mempool_free_slab +EXPORT_SYMBOL vmlinux 0x8aaf8654 mutex_lock +EXPORT_SYMBOL vmlinux 0x8ac33768 submit_bh +EXPORT_SYMBOL vmlinux 0x8ac35aa2 xfrm_init_state +EXPORT_SYMBOL vmlinux 0x8ad53e8d tcp_shutdown +EXPORT_SYMBOL vmlinux 0x8adb915f create_empty_buffers +EXPORT_SYMBOL vmlinux 0x8b0317ab sock_no_ioctl +EXPORT_SYMBOL vmlinux 0x8b18496f __copy_to_user_ll +EXPORT_SYMBOL vmlinux 0x8b189c00 dev_get_by_flags +EXPORT_SYMBOL vmlinux 0x8b35e873 sg_last +EXPORT_SYMBOL vmlinux 0x8b3ca835 cpu_present_map +EXPORT_SYMBOL vmlinux 0x8b3ee135 sync_blockdev +EXPORT_SYMBOL vmlinux 0x8b50bd1c udp_memory_allocated +EXPORT_SYMBOL vmlinux 0x8b618d08 overflowuid +EXPORT_SYMBOL vmlinux 0x8b989cf9 acpi_bus_can_wakeup +EXPORT_SYMBOL vmlinux 0x8bb33e7d __release_region +EXPORT_SYMBOL vmlinux 0x8bd3e6d1 free_buffer_head +EXPORT_SYMBOL vmlinux 0x8bf3996f eisa_driver_register +EXPORT_SYMBOL vmlinux 0x8c0ad791 n_tty_ioctl +EXPORT_SYMBOL vmlinux 0x8c183cbe iowrite16 +EXPORT_SYMBOL vmlinux 0x8c25e2d7 vfs_llseek +EXPORT_SYMBOL vmlinux 0x8c3011e3 tty_schedule_flip +EXPORT_SYMBOL vmlinux 0x8c4cd8a9 pnpbios_protocol +EXPORT_SYMBOL vmlinux 0x8cc19cdc sk_release_kernel +EXPORT_SYMBOL vmlinux 0x8cc79cab iowrite16_rep +EXPORT_SYMBOL vmlinux 0x8cedcb78 pci_bus_add_devices +EXPORT_SYMBOL vmlinux 0x8d156db9 textsearch_unregister +EXPORT_SYMBOL vmlinux 0x8d2b2895 uart_resume_port +EXPORT_SYMBOL vmlinux 0x8d3894f2 _ctype +EXPORT_SYMBOL vmlinux 0x8d551bef sysctl_tcp_rmem +EXPORT_SYMBOL vmlinux 0x8d6ede06 pcie_set_readrq +EXPORT_SYMBOL vmlinux 0x8d6f81b4 __div64_32 +EXPORT_SYMBOL vmlinux 0x8d8d96c6 acpi_get_sleep_type_data +EXPORT_SYMBOL vmlinux 0x8dab71d9 bio_integrity_split +EXPORT_SYMBOL vmlinux 0x8dc5c4c7 bh_uptodate_or_lock +EXPORT_SYMBOL vmlinux 0x8dc6e564 restore_processor_state +EXPORT_SYMBOL vmlinux 0x8de70cb6 blk_rq_map_kern +EXPORT_SYMBOL vmlinux 0x8df9ff59 __netif_schedule +EXPORT_SYMBOL vmlinux 0x8e002cda acpi_remove_gpe_block +EXPORT_SYMBOL vmlinux 0x8e0637ba i8253_lock +EXPORT_SYMBOL vmlinux 0x8e0b7743 ipv6_ext_hdr +EXPORT_SYMBOL vmlinux 0x8e181bf4 vfs_symlink +EXPORT_SYMBOL vmlinux 0x8e268ef7 page_follow_link_light +EXPORT_SYMBOL vmlinux 0x8e3fac1f serio_reconnect +EXPORT_SYMBOL vmlinux 0x8e519e3a simple_rename +EXPORT_SYMBOL vmlinux 0x8e5291fe pci_reenable_device +EXPORT_SYMBOL vmlinux 0x8e725985 nf_log_unregister_pf +EXPORT_SYMBOL vmlinux 0x8e882356 have_submounts +EXPORT_SYMBOL vmlinux 0x8e99cf65 mca_device_write_pos +EXPORT_SYMBOL vmlinux 0x8edf3973 fb_blank +EXPORT_SYMBOL vmlinux 0x8f07bcd4 register_console +EXPORT_SYMBOL vmlinux 0x8f19ff6d tcp_sync_mss +EXPORT_SYMBOL vmlinux 0x8f2255f9 vfs_permission +EXPORT_SYMBOL vmlinux 0x8f6023a7 generic_fillattr +EXPORT_SYMBOL vmlinux 0x8f6b7950 set_irq_data +EXPORT_SYMBOL vmlinux 0x8f7645d4 blk_recount_segments +EXPORT_SYMBOL vmlinux 0x8f839bd9 seq_release +EXPORT_SYMBOL vmlinux 0x8f9c199c __get_user_2 +EXPORT_SYMBOL vmlinux 0x8fa40fe0 locks_remove_posix +EXPORT_SYMBOL vmlinux 0x8fe0a612 fib_default_rule_add +EXPORT_SYMBOL vmlinux 0x8fe4b45a pci_select_bars +EXPORT_SYMBOL vmlinux 0x8ffcb38e k8_northbridges +EXPORT_SYMBOL vmlinux 0x90035333 secure_tcpv6_sequence_number +EXPORT_SYMBOL vmlinux 0x9026a07e block_truncate_page +EXPORT_SYMBOL vmlinux 0x9070b3f2 ioport_resource +EXPORT_SYMBOL vmlinux 0x9071a1de simple_link +EXPORT_SYMBOL vmlinux 0x90a943ba nmi_active +EXPORT_SYMBOL vmlinux 0x90d5064d skb_make_writable +EXPORT_SYMBOL vmlinux 0x9144a8e2 ec_burst_disable +EXPORT_SYMBOL vmlinux 0x91481982 __ratelimit +EXPORT_SYMBOL vmlinux 0x9158722a tcf_em_tree_destroy +EXPORT_SYMBOL vmlinux 0x91607d95 set_memory_wb +EXPORT_SYMBOL vmlinux 0x916d4f56 icmp_send +EXPORT_SYMBOL vmlinux 0x91b82a29 tcp_v4_syn_recv_sock +EXPORT_SYMBOL vmlinux 0x91ca8959 acpi_get_register +EXPORT_SYMBOL vmlinux 0x91da990e set_page_dirty_lock +EXPORT_SYMBOL vmlinux 0x92625a81 blk_queue_bounce +EXPORT_SYMBOL vmlinux 0x9262de12 uart_get_divisor +EXPORT_SYMBOL vmlinux 0x92749351 sync_page_range_nolock +EXPORT_SYMBOL vmlinux 0x927c891b sk_stop_timer +EXPORT_SYMBOL vmlinux 0x92897e3d default_idle +EXPORT_SYMBOL vmlinux 0x92d56873 tty_get_baud_rate +EXPORT_SYMBOL vmlinux 0x930501bd may_umount_tree +EXPORT_SYMBOL vmlinux 0x9305f8e6 cpufreq_get +EXPORT_SYMBOL vmlinux 0x932eb6c6 __locks_copy_lock +EXPORT_SYMBOL vmlinux 0x93394182 inet_sk_rebuild_header +EXPORT_SYMBOL vmlinux 0x933edda4 tcp_proc_unregister +EXPORT_SYMBOL vmlinux 0x93589865 tty_set_operations +EXPORT_SYMBOL vmlinux 0x939fd437 tcp_sendmsg +EXPORT_SYMBOL vmlinux 0x93a6e0b2 io_schedule +EXPORT_SYMBOL vmlinux 0x93b8ef56 mutex_lock_interruptible +EXPORT_SYMBOL vmlinux 0x93c69acf param_set_byte +EXPORT_SYMBOL vmlinux 0x93cbd1ec _spin_lock_bh +EXPORT_SYMBOL vmlinux 0x93f00ff5 tty_driver_flush_buffer +EXPORT_SYMBOL vmlinux 0x93fca811 __get_free_pages +EXPORT_SYMBOL vmlinux 0x942863c3 ip_mc_inc_group +EXPORT_SYMBOL vmlinux 0x942c2b9c lookup_one_len +EXPORT_SYMBOL vmlinux 0x94961283 vunmap +EXPORT_SYMBOL vmlinux 0x94aab5fe eth_header_cache_update +EXPORT_SYMBOL vmlinux 0x94b61db0 tcf_exts_validate +EXPORT_SYMBOL vmlinux 0x94ec1d03 __generic_unplug_device +EXPORT_SYMBOL vmlinux 0x94fcf08e bioset_create +EXPORT_SYMBOL vmlinux 0x954488a4 syncookie_secret +EXPORT_SYMBOL vmlinux 0x9545af6d tasklet_init +EXPORT_SYMBOL vmlinux 0x954cbb26 vsprintf +EXPORT_SYMBOL vmlinux 0x95947906 remove_arg_zero +EXPORT_SYMBOL vmlinux 0x95d9ac7d sock_create_lite +EXPORT_SYMBOL vmlinux 0x95eaa276 skb_copy_datagram_iovec +EXPORT_SYMBOL vmlinux 0x95f638d5 posix_acl_chmod_masq +EXPORT_SYMBOL vmlinux 0x96481cc7 per_cpu__x86_cpu_to_apicid +EXPORT_SYMBOL vmlinux 0x96898769 sysfs_format_mac +EXPORT_SYMBOL vmlinux 0x96939c04 pv_cpu_ops +EXPORT_SYMBOL vmlinux 0x96bd82d7 nla_reserve_nohdr +EXPORT_SYMBOL vmlinux 0x9706e8dd pcim_pin_device +EXPORT_SYMBOL vmlinux 0x973873ab _spin_lock +EXPORT_SYMBOL vmlinux 0x9754ec10 radix_tree_preload +EXPORT_SYMBOL vmlinux 0x979a8424 framebuffer_release +EXPORT_SYMBOL vmlinux 0x97a77b40 invalidate_partition +EXPORT_SYMBOL vmlinux 0x97c2bf73 pci_prepare_to_sleep +EXPORT_SYMBOL vmlinux 0x97dca32f nonseekable_open +EXPORT_SYMBOL vmlinux 0x97de0ddd acpi_install_gpe_block +EXPORT_SYMBOL vmlinux 0x9803f8c2 vfs_rmdir +EXPORT_SYMBOL vmlinux 0x981026f6 km_report +EXPORT_SYMBOL vmlinux 0x981ca8ad serio_unregister_driver +EXPORT_SYMBOL vmlinux 0x9821c6a1 call_usermodehelper_stdinpipe +EXPORT_SYMBOL vmlinux 0x98238493 thermal_zone_device_register +EXPORT_SYMBOL vmlinux 0x9855868c pcibios_set_irq_routing +EXPORT_SYMBOL vmlinux 0x9865599f pcix_set_mmrbc +EXPORT_SYMBOL vmlinux 0x986e6135 fb_pad_unaligned_buffer +EXPORT_SYMBOL vmlinux 0x988ed85d set_memory_x +EXPORT_SYMBOL vmlinux 0x989deaeb nla_reserve +EXPORT_SYMBOL vmlinux 0x98b1a743 skb_queue_purge +EXPORT_SYMBOL vmlinux 0x98c49d6e kmem_cache_alloc +EXPORT_SYMBOL vmlinux 0x98f2f4f1 sock_recvmsg +EXPORT_SYMBOL vmlinux 0x99052a84 acpi_os_write_port +EXPORT_SYMBOL vmlinux 0x996c9dac search_binary_handler +EXPORT_SYMBOL vmlinux 0x996e4d4b vcc_release_async +EXPORT_SYMBOL vmlinux 0x9970d656 __ht_create_irq +EXPORT_SYMBOL vmlinux 0x997ae3bc generic_file_buffered_write +EXPORT_SYMBOL vmlinux 0x998dcbb9 ps2_init +EXPORT_SYMBOL vmlinux 0x9994c0ca ps2_is_keyboard_id +EXPORT_SYMBOL vmlinux 0x9999ac56 xfrm_policy_register_afinfo +EXPORT_SYMBOL vmlinux 0x9999e1d8 bio_integrity_free +EXPORT_SYMBOL vmlinux 0x999e8297 vfree +EXPORT_SYMBOL vmlinux 0x99aadb21 param_get_ulong +EXPORT_SYMBOL vmlinux 0x99bfbe39 get_unused_fd +EXPORT_SYMBOL vmlinux 0x99c3c0b0 vfs_fstat +EXPORT_SYMBOL vmlinux 0x99cdc86b sysctl_tcp_reordering +EXPORT_SYMBOL vmlinux 0x99e1f65f alloc_trdev +EXPORT_SYMBOL vmlinux 0x99ea12ce panic_blink +EXPORT_SYMBOL vmlinux 0x9a04909f kernel_getsockopt +EXPORT_SYMBOL vmlinux 0x9a1dfd65 strpbrk +EXPORT_SYMBOL vmlinux 0x9a3089b2 kernel_bind +EXPORT_SYMBOL vmlinux 0x9a6a83f9 cmos_lock +EXPORT_SYMBOL vmlinux 0x9a7c20cf __insert_inode_hash +EXPORT_SYMBOL vmlinux 0x9a9985be percpu_counter_destroy +EXPORT_SYMBOL vmlinux 0x9ad48664 xfrm_state_update +EXPORT_SYMBOL vmlinux 0x9b388444 get_zeroed_page +EXPORT_SYMBOL vmlinux 0x9b3d0b41 nf_ct_attach +EXPORT_SYMBOL vmlinux 0x9b442e8a netlink_unicast +EXPORT_SYMBOL vmlinux 0x9b4744a5 simple_write_end +EXPORT_SYMBOL vmlinux 0x9b4de8eb idr_replace +EXPORT_SYMBOL vmlinux 0x9ba7089d argv_split +EXPORT_SYMBOL vmlinux 0x9c012508 fb_parse_edid +EXPORT_SYMBOL vmlinux 0x9c1d241b ps2_drain +EXPORT_SYMBOL vmlinux 0x9c2c944a __copy_from_user_ll_nocache_nozero +EXPORT_SYMBOL vmlinux 0x9c491f60 sg_alloc_table +EXPORT_SYMBOL vmlinux 0x9c654810 tcf_unregister_action +EXPORT_SYMBOL vmlinux 0x9c7077bd enable_hlt +EXPORT_SYMBOL vmlinux 0x9cb96e92 qdisc_put_rtab +EXPORT_SYMBOL vmlinux 0x9ccb2622 finish_wait +EXPORT_SYMBOL vmlinux 0x9cdbb5c7 uart_write_wakeup +EXPORT_SYMBOL vmlinux 0x9ceb163c memcpy_toiovec +EXPORT_SYMBOL vmlinux 0x9ced38aa down_trylock +EXPORT_SYMBOL vmlinux 0x9d21c622 should_remove_suid +EXPORT_SYMBOL vmlinux 0x9d2347c6 deny_write_access +EXPORT_SYMBOL vmlinux 0x9d33ef5e acpi_enable +EXPORT_SYMBOL vmlinux 0x9d47dc20 ethtool_op_get_sg +EXPORT_SYMBOL vmlinux 0x9d6e0a59 alloc_disk_node +EXPORT_SYMBOL vmlinux 0x9d6f814f d_invalidate +EXPORT_SYMBOL vmlinux 0x9d70214d set_device_ro +EXPORT_SYMBOL vmlinux 0x9d711f1f percpu_counter_init +EXPORT_SYMBOL vmlinux 0x9d9c3524 pcie_port_service_register +EXPORT_SYMBOL vmlinux 0x9d9f0d41 rwsem_down_write_failed +EXPORT_SYMBOL vmlinux 0x9dac7517 do_SAK +EXPORT_SYMBOL vmlinux 0x9db383b8 grab_cache_page_nowait +EXPORT_SYMBOL vmlinux 0x9dcdf415 nla_append +EXPORT_SYMBOL vmlinux 0x9de67ac1 pci_restore_state +EXPORT_SYMBOL vmlinux 0x9e0973a1 add_to_page_cache_locked +EXPORT_SYMBOL vmlinux 0x9e20ab00 inet_register_protosw +EXPORT_SYMBOL vmlinux 0x9e26f1a2 key_unlink +EXPORT_SYMBOL vmlinux 0x9e3fccf8 d_validate +EXPORT_SYMBOL vmlinux 0x9e4b3747 sg_copy_from_buffer +EXPORT_SYMBOL vmlinux 0x9e583217 generic_file_aio_read +EXPORT_SYMBOL vmlinux 0x9e64fbfe rtc_cmos_read +EXPORT_SYMBOL vmlinux 0x9e7d6bd0 __udelay +EXPORT_SYMBOL vmlinux 0x9e95480e nobh_write_begin +EXPORT_SYMBOL vmlinux 0x9ea0ad49 __sg_free_table +EXPORT_SYMBOL vmlinux 0x9ed685ee iov_iter_advance +EXPORT_SYMBOL vmlinux 0x9eecde16 do_brk +EXPORT_SYMBOL vmlinux 0x9ef749e2 unregister_chrdev +EXPORT_SYMBOL vmlinux 0x9f100139 jiffies_to_clock_t +EXPORT_SYMBOL vmlinux 0x9f16c881 mpage_readpage +EXPORT_SYMBOL vmlinux 0x9f2bdaac __bitmap_or +EXPORT_SYMBOL vmlinux 0x9f38a56f nf_getsockopt +EXPORT_SYMBOL vmlinux 0x9f3c4091 framebuffer_alloc +EXPORT_SYMBOL vmlinux 0x9f3c4d51 unregister_nls +EXPORT_SYMBOL vmlinux 0x9f3c596d bdi_register +EXPORT_SYMBOL vmlinux 0x9f5439a4 pcim_iomap_regions +EXPORT_SYMBOL vmlinux 0x9f638af8 poll_initwait +EXPORT_SYMBOL vmlinux 0x9f984513 strrchr +EXPORT_SYMBOL vmlinux 0x9f9fcebf clear_bdi_congested +EXPORT_SYMBOL vmlinux 0x9fa274b4 dq_data_lock +EXPORT_SYMBOL vmlinux 0x9fb3dd30 memcpy_fromiovec +EXPORT_SYMBOL vmlinux 0x9fd47b14 posix_test_lock +EXPORT_SYMBOL vmlinux 0x9feaf287 sonet_subtract_stats +EXPORT_SYMBOL vmlinux 0x9ffd5c59 neigh_seq_next +EXPORT_SYMBOL vmlinux 0xa008ce9c dma_supported +EXPORT_SYMBOL vmlinux 0xa03523d5 security_unix_stream_connect +EXPORT_SYMBOL vmlinux 0xa03e8eee cap_netlink_recv +EXPORT_SYMBOL vmlinux 0xa04a01bd qdisc_class_hash_insert +EXPORT_SYMBOL vmlinux 0xa05c03df mempool_kmalloc +EXPORT_SYMBOL vmlinux 0xa065fbfc vfs_path_lookup +EXPORT_SYMBOL vmlinux 0xa0a6f5e6 uart_unregister_driver +EXPORT_SYMBOL vmlinux 0xa0a9a87d __mod_zone_page_state +EXPORT_SYMBOL vmlinux 0xa0ae13fb skb_append +EXPORT_SYMBOL vmlinux 0xa0b04675 vmalloc_32 +EXPORT_SYMBOL vmlinux 0xa0ceef51 out_of_line_wait_on_bit +EXPORT_SYMBOL vmlinux 0xa0fbac79 wake_up_bit +EXPORT_SYMBOL vmlinux 0xa108eb4d sysctl_optmem_max +EXPORT_SYMBOL vmlinux 0xa1109dfc proto_unregister +EXPORT_SYMBOL vmlinux 0xa120d33c tty_unregister_ldisc +EXPORT_SYMBOL vmlinux 0xa13798f8 printk_ratelimit +EXPORT_SYMBOL vmlinux 0xa1402186 set_user_nice +EXPORT_SYMBOL vmlinux 0xa1b5f904 dquot_alloc_space +EXPORT_SYMBOL vmlinux 0xa1b759ce fb_add_videomode +EXPORT_SYMBOL vmlinux 0xa1c76e0a _cond_resched +EXPORT_SYMBOL vmlinux 0xa1e911ec pagecache_write_begin +EXPORT_SYMBOL vmlinux 0xa1ef1a97 kernel_connect +EXPORT_SYMBOL vmlinux 0xa20ce1b8 net_msg_warn +EXPORT_SYMBOL vmlinux 0xa2491f1c nf_register_sockopt +EXPORT_SYMBOL vmlinux 0xa26b860c elv_next_request +EXPORT_SYMBOL vmlinux 0xa28e583a bio_get_nr_vecs +EXPORT_SYMBOL vmlinux 0xa2a1e5c9 _write_lock_bh +EXPORT_SYMBOL vmlinux 0xa2a5fd77 inet_ehash_secret +EXPORT_SYMBOL vmlinux 0xa2de6ef5 pci_map_rom +EXPORT_SYMBOL vmlinux 0xa2eec4e8 neigh_table_init_no_netlink +EXPORT_SYMBOL vmlinux 0xa329f07e register_shrinker +EXPORT_SYMBOL vmlinux 0xa3420d61 __percpu_counter_sum +EXPORT_SYMBOL vmlinux 0xa34f1ef5 crc32_le +EXPORT_SYMBOL vmlinux 0xa35c1f05 acpi_extract_package +EXPORT_SYMBOL vmlinux 0xa35de80f ipv4_config +EXPORT_SYMBOL vmlinux 0xa3656da9 acpi_lock_battery_dir +EXPORT_SYMBOL vmlinux 0xa36b03dd kernel_setsockopt +EXPORT_SYMBOL vmlinux 0xa399191b dquot_transfer +EXPORT_SYMBOL vmlinux 0xa3b70741 __sk_mem_reclaim +EXPORT_SYMBOL vmlinux 0xa3bbcd80 acpi_set_gpe_type +EXPORT_SYMBOL vmlinux 0xa3c3aa3a bdi_destroy +EXPORT_SYMBOL vmlinux 0xa3da23d6 vfs_quota_off +EXPORT_SYMBOL vmlinux 0xa41dff84 ip_mc_dec_group +EXPORT_SYMBOL vmlinux 0xa44072fc posix_acl_alloc +EXPORT_SYMBOL vmlinux 0xa44ad274 wait_for_completion_interruptible_timeout +EXPORT_SYMBOL vmlinux 0xa45472d2 notify_change +EXPORT_SYMBOL vmlinux 0xa477970d sock_no_socketpair +EXPORT_SYMBOL vmlinux 0xa47eb3a0 blk_rq_init +EXPORT_SYMBOL vmlinux 0xa49be1d3 mca_device_read_pos +EXPORT_SYMBOL vmlinux 0xa4b94fea iowrite8_rep +EXPORT_SYMBOL vmlinux 0xa4df1151 kref_set +EXPORT_SYMBOL vmlinux 0xa4e1ac18 touch_atime +EXPORT_SYMBOL vmlinux 0xa503959b __sk_dst_check +EXPORT_SYMBOL vmlinux 0xa5095aa9 qdisc_class_hash_grow +EXPORT_SYMBOL vmlinux 0xa5115f97 bd_claim +EXPORT_SYMBOL vmlinux 0xa51cdfe8 __FIXADDR_TOP +EXPORT_SYMBOL vmlinux 0xa51de2af grab_cache_page_write_begin +EXPORT_SYMBOL vmlinux 0xa5384233 pci_clear_mwi +EXPORT_SYMBOL vmlinux 0xa5423cc4 param_get_int +EXPORT_SYMBOL vmlinux 0xa565413f sk_stream_wait_close +EXPORT_SYMBOL vmlinux 0xa5693df7 posix_acl_clone +EXPORT_SYMBOL vmlinux 0xa56f1315 mempool_free +EXPORT_SYMBOL vmlinux 0xa58b6804 nla_parse +EXPORT_SYMBOL vmlinux 0xa58d8d72 proc_mkdir +EXPORT_SYMBOL vmlinux 0xa5922bb1 kfifo_init +EXPORT_SYMBOL vmlinux 0xa598e29c vesa_modes +EXPORT_SYMBOL vmlinux 0xa5b3c348 blk_rq_unmap_user +EXPORT_SYMBOL vmlinux 0xa5da0abd acpi_enter_sleep_state_s4bios +EXPORT_SYMBOL vmlinux 0xa60926da blk_init_queue +EXPORT_SYMBOL vmlinux 0xa60d6b71 pnp_activate_dev +EXPORT_SYMBOL vmlinux 0xa621254f iommu_bio_merge +EXPORT_SYMBOL vmlinux 0xa68124fa hweight8 +EXPORT_SYMBOL vmlinux 0xa6814433 groups_free +EXPORT_SYMBOL vmlinux 0xa681fe88 generate_random_uuid +EXPORT_SYMBOL vmlinux 0xa68b1f9a llc_sap_open +EXPORT_SYMBOL vmlinux 0xa693b117 pnp_register_driver +EXPORT_SYMBOL vmlinux 0xa69446b9 nf_reinject +EXPORT_SYMBOL vmlinux 0xa6d63944 dev_unicast_delete +EXPORT_SYMBOL vmlinux 0xa6dcc773 rb_insert_color +EXPORT_SYMBOL vmlinux 0xa6e0b150 sock_no_bind +EXPORT_SYMBOL vmlinux 0xa6fcba0a fd_install +EXPORT_SYMBOL vmlinux 0xa7046549 vprintk +EXPORT_SYMBOL vmlinux 0xa704c42f unregister_netdevice +EXPORT_SYMBOL vmlinux 0xa70fabbe release_evntsel_nmi +EXPORT_SYMBOL vmlinux 0xa71ee1ad netpoll_poll +EXPORT_SYMBOL vmlinux 0xa7502f48 jiffies_to_timeval +EXPORT_SYMBOL vmlinux 0xa770b803 kblockd_flush_work +EXPORT_SYMBOL vmlinux 0xa781d8aa dmam_declare_coherent_memory +EXPORT_SYMBOL vmlinux 0xa7849bc6 pci_find_slot +EXPORT_SYMBOL vmlinux 0xa78b5fad ip_dev_find +EXPORT_SYMBOL vmlinux 0xa7986e4a set_page_dirty +EXPORT_SYMBOL vmlinux 0xa7c35c6b getnstimeofday +EXPORT_SYMBOL vmlinux 0xa7cc04ab pci_set_power_state +EXPORT_SYMBOL vmlinux 0xa7f573f9 tc_classify_compat +EXPORT_SYMBOL vmlinux 0xa89acbb3 acpi_evaluate_reference +EXPORT_SYMBOL vmlinux 0xa89e2a23 registered_fb +EXPORT_SYMBOL vmlinux 0xa8dab47e udp_proc_register +EXPORT_SYMBOL vmlinux 0xa8fef7bb security_unix_may_send +EXPORT_SYMBOL vmlinux 0xa8ffab5f sock_common_recvmsg +EXPORT_SYMBOL vmlinux 0xa91b5561 acpi_video_backlight_support +EXPORT_SYMBOL vmlinux 0xa925899a param_set_bool +EXPORT_SYMBOL vmlinux 0xa92734bb init_file +EXPORT_SYMBOL vmlinux 0xa981de57 inode_init_once +EXPORT_SYMBOL vmlinux 0xa9a14377 unregister_key_type +EXPORT_SYMBOL vmlinux 0xa9be76e8 clocksource_register +EXPORT_SYMBOL vmlinux 0xa9fcf31d wait_for_completion_interruptible +EXPORT_SYMBOL vmlinux 0xaa024146 sonet_copy_stats +EXPORT_SYMBOL vmlinux 0xaa0b5d76 blk_queue_resize_tags +EXPORT_SYMBOL vmlinux 0xaa1cdf93 bh_submit_read +EXPORT_SYMBOL vmlinux 0xaa3f8335 blk_queue_max_segment_size +EXPORT_SYMBOL vmlinux 0xaa52224e tty_port_free_xmit_buf +EXPORT_SYMBOL vmlinux 0xaa84a8ae acpi_processor_power_init_bm_check +EXPORT_SYMBOL vmlinux 0xaa98f548 tty_chars_in_buffer +EXPORT_SYMBOL vmlinux 0xaaa7a5df acpi_bus_get_device +EXPORT_SYMBOL vmlinux 0xaab06af8 _write_lock_irqsave +EXPORT_SYMBOL vmlinux 0xaabe3e17 netpoll_cleanup +EXPORT_SYMBOL vmlinux 0xaac5a254 llc_sap_find +EXPORT_SYMBOL vmlinux 0xaae8ab0e acpi_bus_power_manageable +EXPORT_SYMBOL vmlinux 0xaaebe34f mca_write_pos +EXPORT_SYMBOL vmlinux 0xaafdc258 strcasecmp +EXPORT_SYMBOL vmlinux 0xaafe448f tcf_hash_create +EXPORT_SYMBOL vmlinux 0xaaffb9a5 acpi_bus_private_data_handler +EXPORT_SYMBOL vmlinux 0xab471003 param_array_set +EXPORT_SYMBOL vmlinux 0xab47c062 task_tgid_nr_ns +EXPORT_SYMBOL vmlinux 0xab4923e3 do_sync_write +EXPORT_SYMBOL vmlinux 0xab544215 netif_device_attach +EXPORT_SYMBOL vmlinux 0xab600421 probe_irq_off +EXPORT_SYMBOL vmlinux 0xab65ed80 set_memory_uc +EXPORT_SYMBOL vmlinux 0xab6b1252 register_sysctl_paths +EXPORT_SYMBOL vmlinux 0xab78b573 bio_unmap_user +EXPORT_SYMBOL vmlinux 0xabab04ba __alloc_pages_internal +EXPORT_SYMBOL vmlinux 0xabab33ac end_page_writeback +EXPORT_SYMBOL vmlinux 0xabcd3845 thermal_zone_unbind_cooling_device +EXPORT_SYMBOL vmlinux 0xabd0c91c rtc_time_to_tm +EXPORT_SYMBOL vmlinux 0xabe6d2b1 skb_pad +EXPORT_SYMBOL vmlinux 0xabf34fa3 free_netdev +EXPORT_SYMBOL vmlinux 0xac3b3cee __bitmap_and +EXPORT_SYMBOL vmlinux 0xac58ea5e acpi_unload_table_id +EXPORT_SYMBOL vmlinux 0xac6d1f6f simple_release_fs +EXPORT_SYMBOL vmlinux 0xac856cf9 d_instantiate +EXPORT_SYMBOL vmlinux 0xac913c95 lock_rename +EXPORT_SYMBOL vmlinux 0xac999c50 devm_ioremap +EXPORT_SYMBOL vmlinux 0xaca970ca bdev_read_only +EXPORT_SYMBOL vmlinux 0xacbb2868 kmem_cache_name +EXPORT_SYMBOL vmlinux 0xaccabc6a in4_pton +EXPORT_SYMBOL vmlinux 0xacd79d9d pci_get_class +EXPORT_SYMBOL vmlinux 0xacf4d843 match_strdup +EXPORT_SYMBOL vmlinux 0xad0413d4 match_hex +EXPORT_SYMBOL vmlinux 0xad07fcc5 __first_cpu +EXPORT_SYMBOL vmlinux 0xad13c689 acpi_os_execute +EXPORT_SYMBOL vmlinux 0xad489b25 skb_copy_bits +EXPORT_SYMBOL vmlinux 0xadaa2657 cpufreq_register_notifier +EXPORT_SYMBOL vmlinux 0xadc95c7f mpage_bio_submit +EXPORT_SYMBOL vmlinux 0xadc9cde9 pskb_expand_head +EXPORT_SYMBOL vmlinux 0xaddfb71e default_unplug_io_fn +EXPORT_SYMBOL vmlinux 0xae137ad2 neigh_connected_output +EXPORT_SYMBOL vmlinux 0xae3e3b31 tcp_ioctl +EXPORT_SYMBOL vmlinux 0xae4d6432 blk_register_region +EXPORT_SYMBOL vmlinux 0xae74b0d0 pnp_is_active +EXPORT_SYMBOL vmlinux 0xae75f004 ida_destroy +EXPORT_SYMBOL vmlinux 0xae98f9b7 lookup_bdev +EXPORT_SYMBOL vmlinux 0xaeadca00 pci_enable_msi +EXPORT_SYMBOL vmlinux 0xaec655c7 alloc_pages_exact +EXPORT_SYMBOL vmlinux 0xaef22474 pneigh_enqueue +EXPORT_SYMBOL vmlinux 0xaf2c36eb inet_listen +EXPORT_SYMBOL vmlinux 0xaf2dfabf flock_lock_file_wait +EXPORT_SYMBOL vmlinux 0xaf2e824f input_release_device +EXPORT_SYMBOL vmlinux 0xaf3a4cb4 kernel_sendmsg +EXPORT_SYMBOL vmlinux 0xaf42ff05 find_task_by_vpid +EXPORT_SYMBOL vmlinux 0xaf4b1540 acpi_get_irq_routing_table +EXPORT_SYMBOL vmlinux 0xaf518ce4 sock_kfree_s +EXPORT_SYMBOL vmlinux 0xaf8dd4f5 locks_copy_lock +EXPORT_SYMBOL vmlinux 0xaf980b28 bio_integrity_enabled +EXPORT_SYMBOL vmlinux 0xafe01377 down_read +EXPORT_SYMBOL vmlinux 0xb023b1bd dcache_dir_lseek +EXPORT_SYMBOL vmlinux 0xb039e798 xfrm_lookup +EXPORT_SYMBOL vmlinux 0xb043d040 unlock_buffer +EXPORT_SYMBOL vmlinux 0xb0686d28 pnp_device_attach +EXPORT_SYMBOL vmlinux 0xb077ef32 acpi_enter_sleep_state +EXPORT_SYMBOL vmlinux 0xb07dfb3d acpi_remove_gpe_handler +EXPORT_SYMBOL vmlinux 0xb08f76ad gen_pool_free +EXPORT_SYMBOL vmlinux 0xb09eb615 register_con_driver +EXPORT_SYMBOL vmlinux 0xb0ac2fb3 kfree_skb +EXPORT_SYMBOL vmlinux 0xb0b847ac __bitmap_full +EXPORT_SYMBOL vmlinux 0xb0c2647a submit_bio +EXPORT_SYMBOL vmlinux 0xb0cf28cf aio_put_req +EXPORT_SYMBOL vmlinux 0xb0cf992b atm_proc_root +EXPORT_SYMBOL vmlinux 0xb0d6ad2b tcp_md5_hash_skb_data +EXPORT_SYMBOL vmlinux 0xb0e10781 get_option +EXPORT_SYMBOL vmlinux 0xb0e3ec72 fb_is_primary_device +EXPORT_SYMBOL vmlinux 0xb0f8fee1 kill_pid +EXPORT_SYMBOL vmlinux 0xb0fb5c2d set_disk_ro +EXPORT_SYMBOL vmlinux 0xb121390a probe_irq_on +EXPORT_SYMBOL vmlinux 0xb13c4dba down_write +EXPORT_SYMBOL vmlinux 0xb13db54d set_blocksize +EXPORT_SYMBOL vmlinux 0xb1645a2e sg_free_table +EXPORT_SYMBOL vmlinux 0xb1906837 devm_ioremap_nocache +EXPORT_SYMBOL vmlinux 0xb19760c3 bitmap_onto +EXPORT_SYMBOL vmlinux 0xb1b3b214 inet_shutdown +EXPORT_SYMBOL vmlinux 0xb1c3a01a oops_in_progress +EXPORT_SYMBOL vmlinux 0xb1cfad22 rdmsr_on_cpu +EXPORT_SYMBOL vmlinux 0xb1e5ce9c shrink_dcache_sb +EXPORT_SYMBOL vmlinux 0xb1f975aa unlock_kernel +EXPORT_SYMBOL vmlinux 0xb2017c1d per_cpu__x86_bios_cpu_apicid +EXPORT_SYMBOL vmlinux 0xb29bc8bd idr_remove +EXPORT_SYMBOL vmlinux 0xb29e1c8e sock_kmalloc +EXPORT_SYMBOL vmlinux 0xb2adf2a0 pci_get_device +EXPORT_SYMBOL vmlinux 0xb2d24a7a __splice_from_pipe +EXPORT_SYMBOL vmlinux 0xb2efb6be mca_read_stored_pos +EXPORT_SYMBOL vmlinux 0xb2fd5ceb __put_user_4 +EXPORT_SYMBOL vmlinux 0xb30abf8d idr_get_new_above +EXPORT_SYMBOL vmlinux 0xb3205415 wait_for_completion_killable +EXPORT_SYMBOL vmlinux 0xb3284531 acpi_dbg_layer +EXPORT_SYMBOL vmlinux 0xb33b47e0 sk_send_sigurg +EXPORT_SYMBOL vmlinux 0xb34d4c2e acpi_terminate +EXPORT_SYMBOL vmlinux 0xb352177e find_first_bit +EXPORT_SYMBOL vmlinux 0xb3692eb4 ioremap_wc +EXPORT_SYMBOL vmlinux 0xb36c7677 pci_back_from_sleep +EXPORT_SYMBOL vmlinux 0xb376d79d radix_tree_tagged +EXPORT_SYMBOL vmlinux 0xb3a307c6 si_meminfo +EXPORT_SYMBOL vmlinux 0xb3e0590d acpi_set_current_resources +EXPORT_SYMBOL vmlinux 0xb423dba1 console_blanked +EXPORT_SYMBOL vmlinux 0xb4265793 tcp_alloc_md5sig_pool +EXPORT_SYMBOL vmlinux 0xb429410a posix_acl_from_mode +EXPORT_SYMBOL vmlinux 0xb429b47b sock_no_poll +EXPORT_SYMBOL vmlinux 0xb4390f9a mcount +EXPORT_SYMBOL vmlinux 0xb45578b8 memscan +EXPORT_SYMBOL vmlinux 0xb45b24f6 k8_nb_ids +EXPORT_SYMBOL vmlinux 0xb483e892 __kfree_skb +EXPORT_SYMBOL vmlinux 0xb488181a netlink_kernel_release +EXPORT_SYMBOL vmlinux 0xb48f3b94 sock_common_getsockopt +EXPORT_SYMBOL vmlinux 0xb494e82a br_fdb_put_hook +EXPORT_SYMBOL vmlinux 0xb4a9c6b9 xfrm_state_unregister_afinfo +EXPORT_SYMBOL vmlinux 0xb4ca9447 __kfifo_get +EXPORT_SYMBOL vmlinux 0xb4d3eaaf pnp_release_card_device +EXPORT_SYMBOL vmlinux 0xb4dcf1f9 block_read_full_page +EXPORT_SYMBOL vmlinux 0xb5044271 vsscanf +EXPORT_SYMBOL vmlinux 0xb54533f7 usecs_to_jiffies +EXPORT_SYMBOL vmlinux 0xb54c2ca4 inet_select_addr +EXPORT_SYMBOL vmlinux 0xb55454e8 pnp_find_dev +EXPORT_SYMBOL vmlinux 0xb577ec42 cont_write_begin +EXPORT_SYMBOL vmlinux 0xb59c966d __free_pages +EXPORT_SYMBOL vmlinux 0xb5a459dc unregister_blkdev +EXPORT_SYMBOL vmlinux 0xb5aea4ec acpi_match_device_ids +EXPORT_SYMBOL vmlinux 0xb5d52c27 ec_transaction +EXPORT_SYMBOL vmlinux 0xb60e34a8 nla_memcpy +EXPORT_SYMBOL vmlinux 0xb6244511 sg_init_one +EXPORT_SYMBOL vmlinux 0xb62bdea0 generic_file_splice_write_nolock +EXPORT_SYMBOL vmlinux 0xb678366f int_sqrt +EXPORT_SYMBOL vmlinux 0xb67c1aaa inode_permission +EXPORT_SYMBOL vmlinux 0xb6a61a86 qdisc_get_rtab +EXPORT_SYMBOL vmlinux 0xb6e227aa rtc_lock +EXPORT_SYMBOL vmlinux 0xb6ed1e53 strncpy +EXPORT_SYMBOL vmlinux 0xb6f18985 dquot_commit +EXPORT_SYMBOL vmlinux 0xb703911e release_firmware +EXPORT_SYMBOL vmlinux 0xb7043b26 pcim_enable_device +EXPORT_SYMBOL vmlinux 0xb714a981 console_print +EXPORT_SYMBOL vmlinux 0xb72397d5 printk +EXPORT_SYMBOL vmlinux 0xb746a396 splice_direct_to_actor +EXPORT_SYMBOL vmlinux 0xb74abc5b blk_plug_device +EXPORT_SYMBOL vmlinux 0xb7555f12 timeval_to_jiffies +EXPORT_SYMBOL vmlinux 0xb758b225 acpi_disable_event +EXPORT_SYMBOL vmlinux 0xb75910d5 fb_set_suspend +EXPORT_SYMBOL vmlinux 0xb7b61546 crc32_be +EXPORT_SYMBOL vmlinux 0xb7e8ad62 put_tty_driver +EXPORT_SYMBOL vmlinux 0xb7e9bc35 __xfrm_state_delete +EXPORT_SYMBOL vmlinux 0xb7fea0d6 skb_unlink +EXPORT_SYMBOL vmlinux 0xb811ba0e __vmalloc +EXPORT_SYMBOL vmlinux 0xb83722ae input_unregister_handler +EXPORT_SYMBOL vmlinux 0xb85b2bac vm_stat +EXPORT_SYMBOL vmlinux 0xb86e4ab9 random32 +EXPORT_SYMBOL vmlinux 0xb88024f9 proc_doulongvec_minmax +EXPORT_SYMBOL vmlinux 0xb894926d schedule_work_on +EXPORT_SYMBOL vmlinux 0xb89af9bf srandom32 +EXPORT_SYMBOL vmlinux 0xb8b65c5a pcim_iomap_regions_request_all +EXPORT_SYMBOL vmlinux 0xb8c3517b llc_mac_hdr_init +EXPORT_SYMBOL vmlinux 0xb8d049e7 simple_readpage +EXPORT_SYMBOL vmlinux 0xb8d74790 inet_csk_init_xmit_timers +EXPORT_SYMBOL vmlinux 0xb8e7ce2c __put_user_8 +EXPORT_SYMBOL vmlinux 0xb93ba681 serio_rescan +EXPORT_SYMBOL vmlinux 0xb940ff04 pnp_disable_dev +EXPORT_SYMBOL vmlinux 0xb945f0e4 dev_load +EXPORT_SYMBOL vmlinux 0xb94980a9 netdev_rx_csum_fault +EXPORT_SYMBOL vmlinux 0xb9646f3b tcp_tso_segment +EXPORT_SYMBOL vmlinux 0xb98a0185 rtc_tm_to_time +EXPORT_SYMBOL vmlinux 0xb9a83da0 cpufreq_get_policy +EXPORT_SYMBOL vmlinux 0xb9c74bf1 gen_kill_estimator +EXPORT_SYMBOL vmlinux 0xb9f9477f skb_seq_read +EXPORT_SYMBOL vmlinux 0xb9fd2205 add_efi_memmap +EXPORT_SYMBOL vmlinux 0xb9ff5517 unregister_snap_client +EXPORT_SYMBOL vmlinux 0xba057ea4 nf_afinfo +EXPORT_SYMBOL vmlinux 0xba08f2fc bio_integrity_alloc_bioset +EXPORT_SYMBOL vmlinux 0xba2d8594 ec_read +EXPORT_SYMBOL vmlinux 0xba354fc3 skb_copy_and_csum_datagram_iovec +EXPORT_SYMBOL vmlinux 0xba497f13 loops_per_jiffy +EXPORT_SYMBOL vmlinux 0xba7699a5 brioctl_set +EXPORT_SYMBOL vmlinux 0xba7e084b ipv4_specific +EXPORT_SYMBOL vmlinux 0xbaa67c71 pci_find_bus +EXPORT_SYMBOL vmlinux 0xbaad5305 mark_buffer_dirty_inode +EXPORT_SYMBOL vmlinux 0xbacf09a1 tcp_close +EXPORT_SYMBOL vmlinux 0xbb167766 fb_var_to_videomode +EXPORT_SYMBOL vmlinux 0xbb189cad disallow_signal +EXPORT_SYMBOL vmlinux 0xbb4e4693 pci_disable_msi +EXPORT_SYMBOL vmlinux 0xbb5d343d xfrm_get_acqseq +EXPORT_SYMBOL vmlinux 0xbb6b8107 pagecache_write_end +EXPORT_SYMBOL vmlinux 0xbb78bd14 neigh_changeaddr +EXPORT_SYMBOL vmlinux 0xbb8126fb input_set_keycode +EXPORT_SYMBOL vmlinux 0xbb83bd29 xfrm_cfg_mutex +EXPORT_SYMBOL vmlinux 0xbb85d839 filemap_flush +EXPORT_SYMBOL vmlinux 0xbb89de17 ida_init +EXPORT_SYMBOL vmlinux 0xbbc8d034 blk_cleanup_queue +EXPORT_SYMBOL vmlinux 0xbbc8e804 param_set_ushort +EXPORT_SYMBOL vmlinux 0xbbcb6931 netlink_ack +EXPORT_SYMBOL vmlinux 0xbbed7868 generic_readlink +EXPORT_SYMBOL vmlinux 0xbbfcf0a1 __devm_request_region +EXPORT_SYMBOL vmlinux 0xbbfe98b0 kobject_add +EXPORT_SYMBOL vmlinux 0xbc08e1ae inode_sub_bytes +EXPORT_SYMBOL vmlinux 0xbc69c164 dev_open +EXPORT_SYMBOL vmlinux 0xbc860dd8 seq_read +EXPORT_SYMBOL vmlinux 0xbc99b8c9 tty_port_alloc_xmit_buf +EXPORT_SYMBOL vmlinux 0xbcc308bb strnlen_user +EXPORT_SYMBOL vmlinux 0xbcece191 bdi_register_dev +EXPORT_SYMBOL vmlinux 0xbcf32d83 igrab +EXPORT_SYMBOL vmlinux 0xbd1f3e2a set_trace_device +EXPORT_SYMBOL vmlinux 0xbd25bf97 tcf_action_dump_1 +EXPORT_SYMBOL vmlinux 0xbd4490e0 find_task_by_pid_ns +EXPORT_SYMBOL vmlinux 0xbd6ee09f neigh_seq_start +EXPORT_SYMBOL vmlinux 0xbd932b5f unregister_tcf_proto_ops +EXPORT_SYMBOL vmlinux 0xbdf8db7a ethtool_op_get_link +EXPORT_SYMBOL vmlinux 0xbe0e5118 nla_memcmp +EXPORT_SYMBOL vmlinux 0xbe40b9d8 __brelse +EXPORT_SYMBOL vmlinux 0xbe66369a noop_qdisc +EXPORT_SYMBOL vmlinux 0xbef43296 console_conditional_schedule +EXPORT_SYMBOL vmlinux 0xbf13b163 rwsem_down_read_failed +EXPORT_SYMBOL vmlinux 0xbf28cfea xfrm_policy_unregister_afinfo +EXPORT_SYMBOL vmlinux 0xbf40f989 inet_put_port +EXPORT_SYMBOL vmlinux 0xbf48a7c7 per_cpu__cpu_info +EXPORT_SYMBOL vmlinux 0xbf6c956a inode_set_bytes +EXPORT_SYMBOL vmlinux 0xbf6c9dc7 __set_page_dirty_nobuffers +EXPORT_SYMBOL vmlinux 0xbf7fd2f5 schedule_timeout_killable +EXPORT_SYMBOL vmlinux 0xbf89048a __inode_dir_notify +EXPORT_SYMBOL vmlinux 0xbf8b39e9 isapnp_present +EXPORT_SYMBOL vmlinux 0xbf93453d I_BDEV +EXPORT_SYMBOL vmlinux 0xbf9bcc8d __cap_empty_set +EXPORT_SYMBOL vmlinux 0xbfc177bc iowrite32_rep +EXPORT_SYMBOL vmlinux 0xc003c637 __strncpy_from_user +EXPORT_SYMBOL vmlinux 0xc00cd43e input_grab_device +EXPORT_SYMBOL vmlinux 0xc00dfffa km_policy_expired +EXPORT_SYMBOL vmlinux 0xc01eed33 __copy_from_user_ll_nozero +EXPORT_SYMBOL vmlinux 0xc029a2f5 blk_queue_max_sectors +EXPORT_SYMBOL vmlinux 0xc045ad4e timespec_trunc +EXPORT_SYMBOL vmlinux 0xc0580937 rb_erase +EXPORT_SYMBOL vmlinux 0xc0813abd mnt_pin +EXPORT_SYMBOL vmlinux 0xc0994f58 register_nls +EXPORT_SYMBOL vmlinux 0xc09d4a50 tcp_v4_remember_stamp +EXPORT_SYMBOL vmlinux 0xc0a3d105 find_next_bit +EXPORT_SYMBOL vmlinux 0xc0c8e07f shrink_dcache_parent +EXPORT_SYMBOL vmlinux 0xc0d03105 bio_pair_release +EXPORT_SYMBOL vmlinux 0xc0f65988 machine_real_restart +EXPORT_SYMBOL vmlinux 0xc1134e38 __neigh_for_each_release +EXPORT_SYMBOL vmlinux 0xc11d8093 iov_shorten +EXPORT_SYMBOL vmlinux 0xc14a4adf km_policy_notify +EXPORT_SYMBOL vmlinux 0xc1749f44 secpath_dup +EXPORT_SYMBOL vmlinux 0xc174aee0 put_filp +EXPORT_SYMBOL vmlinux 0xc1b893f0 kmalloc_caches +EXPORT_SYMBOL vmlinux 0xc1e1486f bd_release +EXPORT_SYMBOL vmlinux 0xc203d348 udplite_prot +EXPORT_SYMBOL vmlinux 0xc20b738e inet_csk_reset_keepalive_timer +EXPORT_SYMBOL vmlinux 0xc254af48 dcache_lock +EXPORT_SYMBOL vmlinux 0xc255a509 gnet_stats_copy_queue +EXPORT_SYMBOL vmlinux 0xc256e762 __bitmap_equal +EXPORT_SYMBOL vmlinux 0xc2613476 sock_no_sendpage +EXPORT_SYMBOL vmlinux 0xc280a525 __copy_from_user_ll +EXPORT_SYMBOL vmlinux 0xc28a7ea6 tcp_enter_memory_pressure +EXPORT_SYMBOL vmlinux 0xc291a078 pcim_iounmap +EXPORT_SYMBOL vmlinux 0xc2b70b19 follow_up +EXPORT_SYMBOL vmlinux 0xc2c87292 netpoll_print_options +EXPORT_SYMBOL vmlinux 0xc2d316f2 block_prepare_write +EXPORT_SYMBOL vmlinux 0xc2d711e1 krealloc +EXPORT_SYMBOL vmlinux 0xc2e587d1 reset_devices +EXPORT_SYMBOL vmlinux 0xc321ec31 pci_get_bus_and_slot +EXPORT_SYMBOL vmlinux 0xc33f6f4c on_each_cpu +EXPORT_SYMBOL vmlinux 0xc34eb9db key_link +EXPORT_SYMBOL vmlinux 0xc370d09e kernel_getsockname +EXPORT_SYMBOL vmlinux 0xc3833a0e unmap_mapping_range +EXPORT_SYMBOL vmlinux 0xc38e5923 udp_stats_in6 +EXPORT_SYMBOL vmlinux 0xc3aaf0a9 __put_user_1 +EXPORT_SYMBOL vmlinux 0xc3cf1128 in_group_p +EXPORT_SYMBOL vmlinux 0xc3f47a2e nlmsg_notify +EXPORT_SYMBOL vmlinux 0xc3fa6a59 memchr +EXPORT_SYMBOL vmlinux 0xc402cc99 register_acpi_notifier +EXPORT_SYMBOL vmlinux 0xc434a577 proc_create_data +EXPORT_SYMBOL vmlinux 0xc4454aed simple_sync_file +EXPORT_SYMBOL vmlinux 0xc458c71d fddi_type_trans +EXPORT_SYMBOL vmlinux 0xc499ae1e kstrdup +EXPORT_SYMBOL vmlinux 0xc4b72524 qdisc_tree_decrease_qlen +EXPORT_SYMBOL vmlinux 0xc4e499c3 open_exec +EXPORT_SYMBOL vmlinux 0xc5027b76 dev_get_by_name +EXPORT_SYMBOL vmlinux 0xc51d196b cdev_init +EXPORT_SYMBOL vmlinux 0xc52f5714 fb_videomode_to_var +EXPORT_SYMBOL vmlinux 0xc5452f41 mapping_tagged +EXPORT_SYMBOL vmlinux 0xc5534d64 ioread16 +EXPORT_SYMBOL vmlinux 0xc55f7dc7 _write_trylock +EXPORT_SYMBOL vmlinux 0xc5608ed8 blk_rq_count_integrity_sg +EXPORT_SYMBOL vmlinux 0xc5844fb8 __per_cpu_offset +EXPORT_SYMBOL vmlinux 0xc585e709 dev_set_promiscuity +EXPORT_SYMBOL vmlinux 0xc5aba6e0 ethtool_op_get_flags +EXPORT_SYMBOL vmlinux 0xc5b05570 kernel_recvmsg +EXPORT_SYMBOL vmlinux 0xc5eb11df alloc_hippi_dev +EXPORT_SYMBOL vmlinux 0xc5fd4253 pci_match_id +EXPORT_SYMBOL vmlinux 0xc608b75d __alloc_skb +EXPORT_SYMBOL vmlinux 0xc63d90a0 skb_put +EXPORT_SYMBOL vmlinux 0xc6c30426 thaw_bdev +EXPORT_SYMBOL vmlinux 0xc6f2e002 textsearch_find_continuous +EXPORT_SYMBOL vmlinux 0xc7208c3a serial8250_resume_port +EXPORT_SYMBOL vmlinux 0xc74bc004 __kill_fasync +EXPORT_SYMBOL vmlinux 0xc74da7ab bio_uncopy_user +EXPORT_SYMBOL vmlinux 0xc758cd3e __blockdev_direct_IO +EXPORT_SYMBOL vmlinux 0xc767ae08 set_pages_wb +EXPORT_SYMBOL vmlinux 0xc7a4fbed rtnl_lock +EXPORT_SYMBOL vmlinux 0xc7bd1792 inet_frag_find +EXPORT_SYMBOL vmlinux 0xc7e01792 inode_double_lock +EXPORT_SYMBOL vmlinux 0xc7ec6c27 strspn +EXPORT_SYMBOL vmlinux 0xc80060d8 serial8250_register_port +EXPORT_SYMBOL vmlinux 0xc815f0fc tcp_rcv_established +EXPORT_SYMBOL vmlinux 0xc84052dc set_bh_page +EXPORT_SYMBOL vmlinux 0xc897c382 sg_init_table +EXPORT_SYMBOL vmlinux 0xc8b57c27 autoremove_wake_function +EXPORT_SYMBOL vmlinux 0xc8bb23e8 nla_put +EXPORT_SYMBOL vmlinux 0xc8ca3e25 acpi_get_child +EXPORT_SYMBOL vmlinux 0xc8d6a037 kernel_accept +EXPORT_SYMBOL vmlinux 0xc8e9f5e4 init_special_inode +EXPORT_SYMBOL vmlinux 0xc91ff9ef inet_stream_ops +EXPORT_SYMBOL vmlinux 0xc95da1a0 seq_printf +EXPORT_SYMBOL vmlinux 0xc966b01b mark_buffer_async_write +EXPORT_SYMBOL vmlinux 0xc98efcac open_bdev_excl +EXPORT_SYMBOL vmlinux 0xc998d641 icmp_err_convert +EXPORT_SYMBOL vmlinux 0xc9ab2eef acpi_os_wait_events_complete +EXPORT_SYMBOL vmlinux 0xc9ab5737 key_alloc +EXPORT_SYMBOL vmlinux 0xc9cdca68 fb_set_cmap +EXPORT_SYMBOL vmlinux 0xc9f390ad fifo_set_limit +EXPORT_SYMBOL vmlinux 0xca0878da save_mount_options +EXPORT_SYMBOL vmlinux 0xca275daa lock_may_read +EXPORT_SYMBOL vmlinux 0xca6fb540 xfrm_state_lookup_byaddr +EXPORT_SYMBOL vmlinux 0xca8acc78 acpi_dbg_level +EXPORT_SYMBOL vmlinux 0xca9c0c4d ps2_handle_response +EXPORT_SYMBOL vmlinux 0xca9d6aaf dec_zone_page_state +EXPORT_SYMBOL vmlinux 0xcada4639 tcp_v4_conn_request +EXPORT_SYMBOL vmlinux 0xcadb5aac sk_run_filter +EXPORT_SYMBOL vmlinux 0xcae03e38 blk_init_tags +EXPORT_SYMBOL vmlinux 0xcb32da10 param_set_int +EXPORT_SYMBOL vmlinux 0xcb42e30c br_handle_frame_hook +EXPORT_SYMBOL vmlinux 0xcb5b341f remove_proc_entry +EXPORT_SYMBOL vmlinux 0xcb66182d proc_symlink +EXPORT_SYMBOL vmlinux 0xcb6beb40 hweight32 +EXPORT_SYMBOL vmlinux 0xcb7131fb fb_get_options +EXPORT_SYMBOL vmlinux 0xcb733bf2 acpi_bus_set_power +EXPORT_SYMBOL vmlinux 0xcb9ce189 vfs_mkdir +EXPORT_SYMBOL vmlinux 0xcbdd28b2 mark_page_accessed +EXPORT_SYMBOL vmlinux 0xcc248d26 serial8250_suspend_port +EXPORT_SYMBOL vmlinux 0xcc32852e netif_device_detach +EXPORT_SYMBOL vmlinux 0xcc36f32e fb_unregister_client +EXPORT_SYMBOL vmlinux 0xcc5005fe msleep_interruptible +EXPORT_SYMBOL vmlinux 0xcc51ee50 dma_spin_lock +EXPORT_SYMBOL vmlinux 0xcc65ec12 blk_queue_bounce_limit +EXPORT_SYMBOL vmlinux 0xcc7fa952 local_bh_enable_ip +EXPORT_SYMBOL vmlinux 0xccbb6f5c unmap_underlying_metadata +EXPORT_SYMBOL vmlinux 0xcce07094 tcf_exts_destroy +EXPORT_SYMBOL vmlinux 0xcd0dc881 mark_buffer_dirty +EXPORT_SYMBOL vmlinux 0xcd46106e security_d_instantiate +EXPORT_SYMBOL vmlinux 0xcd9f64f4 deactivate_super +EXPORT_SYMBOL vmlinux 0xcdf4af7c nf_register_queue_handler +EXPORT_SYMBOL vmlinux 0xce13a3e3 dev_queue_xmit +EXPORT_SYMBOL vmlinux 0xce18f3b7 cfb_copyarea +EXPORT_SYMBOL vmlinux 0xce36ded6 sysctl_tcp_mem +EXPORT_SYMBOL vmlinux 0xce4904a4 acpi_leave_sleep_state +EXPORT_SYMBOL vmlinux 0xce5ac24f zlib_inflate_workspacesize +EXPORT_SYMBOL vmlinux 0xce5f47be kill_block_super +EXPORT_SYMBOL vmlinux 0xce62d5f4 vfs_mknod +EXPORT_SYMBOL vmlinux 0xcea4932c kthread_bind +EXPORT_SYMBOL vmlinux 0xcefcd99a serial8250_unregister_port +EXPORT_SYMBOL vmlinux 0xcf047c83 acpi_disable_gpe +EXPORT_SYMBOL vmlinux 0xcf791e8d netdev_boot_setup_check +EXPORT_SYMBOL vmlinux 0xcf84ac0b tcp_v4_connect +EXPORT_SYMBOL vmlinux 0xcf919faa llc_sap_close +EXPORT_SYMBOL vmlinux 0xcfadd723 __percpu_counter_add +EXPORT_SYMBOL vmlinux 0xcfd3018e set_normalized_timespec +EXPORT_SYMBOL vmlinux 0xcfd4f342 compute_creds +EXPORT_SYMBOL vmlinux 0xcfd67bec sock_i_ino +EXPORT_SYMBOL vmlinux 0xcff7adfe f_setown +EXPORT_SYMBOL vmlinux 0xd0181f4f __bitmap_xor +EXPORT_SYMBOL vmlinux 0xd02cc869 __bitmap_andnot +EXPORT_SYMBOL vmlinux 0xd08197fa acpi_load_tables +EXPORT_SYMBOL vmlinux 0xd0bd3a71 sk_alloc +EXPORT_SYMBOL vmlinux 0xd0cc46fd km_new_mapping +EXPORT_SYMBOL vmlinux 0xd0d8621b strlen +EXPORT_SYMBOL vmlinux 0xd0da02cd set_pages_uc +EXPORT_SYMBOL vmlinux 0xd0e9b79b skb_copy_expand +EXPORT_SYMBOL vmlinux 0xd0ee38b8 schedule_timeout_uninterruptible +EXPORT_SYMBOL vmlinux 0xd1182380 pci_remove_bus_device +EXPORT_SYMBOL vmlinux 0xd1329d2e names_cachep +EXPORT_SYMBOL vmlinux 0xd134440d set_pages_x +EXPORT_SYMBOL vmlinux 0xd1472061 acpi_pci_register_driver +EXPORT_SYMBOL vmlinux 0xd1701485 dev_unicast_sync +EXPORT_SYMBOL vmlinux 0xd18615e8 pci_remove_behind_bridge +EXPORT_SYMBOL vmlinux 0xd18b6eb2 acpi_unmap_lsapic +EXPORT_SYMBOL vmlinux 0xd1ada35e xfrm_stateonly_find +EXPORT_SYMBOL vmlinux 0xd1e5fe9a simple_dir_inode_operations +EXPORT_SYMBOL vmlinux 0xd1f6c5f3 smp_num_siblings +EXPORT_SYMBOL vmlinux 0xd1f91bcd dev_base_lock +EXPORT_SYMBOL vmlinux 0xd1f9617a skb_checksum_help +EXPORT_SYMBOL vmlinux 0xd20ff8f0 ip_cmsg_recv +EXPORT_SYMBOL vmlinux 0xd251d7b0 security_socket_getpeersec_dgram +EXPORT_SYMBOL vmlinux 0xd2555f19 jiffies_64_to_clock_t +EXPORT_SYMBOL vmlinux 0xd25d4f74 console_blank_hook +EXPORT_SYMBOL vmlinux 0xd267d42c down_killable +EXPORT_SYMBOL vmlinux 0xd26b62d1 iunique +EXPORT_SYMBOL vmlinux 0xd27db078 dev_mc_delete +EXPORT_SYMBOL vmlinux 0xd2965f6f kthread_should_stop +EXPORT_SYMBOL vmlinux 0xd2981b51 request_key_async_with_auxdata +EXPORT_SYMBOL vmlinux 0xd2a031fb neigh_table_init +EXPORT_SYMBOL vmlinux 0xd2b15757 inet_unregister_protosw +EXPORT_SYMBOL vmlinux 0xd2b5ddfe cdev_alloc +EXPORT_SYMBOL vmlinux 0xd2b694ac __pskb_pull_tail +EXPORT_SYMBOL vmlinux 0xd2b6be6d __napi_schedule +EXPORT_SYMBOL vmlinux 0xd2e4f1b5 dev_kfree_skb_irq +EXPORT_SYMBOL vmlinux 0xd2e7dc92 generic_write_checks +EXPORT_SYMBOL vmlinux 0xd30d24cd dma_pool_create +EXPORT_SYMBOL vmlinux 0xd33a7181 inet_bind +EXPORT_SYMBOL vmlinux 0xd34f0c62 gen_pool_create +EXPORT_SYMBOL vmlinux 0xd355f49d unregister_quota_format +EXPORT_SYMBOL vmlinux 0xd363090e xfrm_state_insert +EXPORT_SYMBOL vmlinux 0xd374d45a blk_alloc_queue_node +EXPORT_SYMBOL vmlinux 0xd3951da4 acpi_resource_to_address64 +EXPORT_SYMBOL vmlinux 0xd3a84951 pci_bus_alloc_resource +EXPORT_SYMBOL vmlinux 0xd3b34c4a netdev_class_create_file +EXPORT_SYMBOL vmlinux 0xd3f74cf1 interruptible_sleep_on_timeout +EXPORT_SYMBOL vmlinux 0xd4068d75 iw_handler_set_spy +EXPORT_SYMBOL vmlinux 0xd4087acb init_task +EXPORT_SYMBOL vmlinux 0xd42b7232 _write_unlock_bh +EXPORT_SYMBOL vmlinux 0xd4630661 d_lookup +EXPORT_SYMBOL vmlinux 0xd46ee0b7 netpoll_setup +EXPORT_SYMBOL vmlinux 0xd48f9a01 tc_classify +EXPORT_SYMBOL vmlinux 0xd496e0ca __pci_register_driver +EXPORT_SYMBOL vmlinux 0xd4a176fa dump_trace +EXPORT_SYMBOL vmlinux 0xd4ac14e6 ip_xfrm_me_harder +EXPORT_SYMBOL vmlinux 0xd4addc34 nf_unregister_hooks +EXPORT_SYMBOL vmlinux 0xd4b0d06a __tcp_get_md5sig_pool +EXPORT_SYMBOL vmlinux 0xd4c2784d nf_ip_checksum +EXPORT_SYMBOL vmlinux 0xd4dd37c4 bio_init +EXPORT_SYMBOL vmlinux 0xd4ecd965 __invalidate_device +EXPORT_SYMBOL vmlinux 0xd4f095ed find_get_page +EXPORT_SYMBOL vmlinux 0xd4f15987 pci_enable_msix +EXPORT_SYMBOL vmlinux 0xd4f294fa audit_log_end +EXPORT_SYMBOL vmlinux 0xd5688a7a radix_tree_insert +EXPORT_SYMBOL vmlinux 0xd5b037e1 kref_put +EXPORT_SYMBOL vmlinux 0xd5dd84f9 proc_net_netfilter +EXPORT_SYMBOL vmlinux 0xd5fbb0b5 pci_set_consistent_dma_mask +EXPORT_SYMBOL vmlinux 0xd6035d05 do_settimeofday +EXPORT_SYMBOL vmlinux 0xd6036a9f blk_get_backing_dev_info +EXPORT_SYMBOL vmlinux 0xd624f5ab udp_lib_setsockopt +EXPORT_SYMBOL vmlinux 0xd62bfb21 kthread_create +EXPORT_SYMBOL vmlinux 0xd62c833f schedule_timeout +EXPORT_SYMBOL vmlinux 0xd688f4cd set_binfmt +EXPORT_SYMBOL vmlinux 0xd6912d32 netif_carrier_off +EXPORT_SYMBOL vmlinux 0xd6940098 unregister_qdisc +EXPORT_SYMBOL vmlinux 0xd6a78d08 smp_call_function_single +EXPORT_SYMBOL vmlinux 0xd6b33026 cpu_khz +EXPORT_SYMBOL vmlinux 0xd6ee688f vmalloc +EXPORT_SYMBOL vmlinux 0xd70568c9 __dst_free +EXPORT_SYMBOL vmlinux 0xd71cc3c3 blk_queue_hardsect_size +EXPORT_SYMBOL vmlinux 0xd7205886 filp_close +EXPORT_SYMBOL vmlinux 0xd72d41c8 sk_stream_wait_connect +EXPORT_SYMBOL vmlinux 0xd764e15c seq_open_private +EXPORT_SYMBOL vmlinux 0xd77441d3 con_is_bound +EXPORT_SYMBOL vmlinux 0xd77a2498 mca_device_status +EXPORT_SYMBOL vmlinux 0xd78537fc bio_integrity_clone +EXPORT_SYMBOL vmlinux 0xd79b5a02 allow_signal +EXPORT_SYMBOL vmlinux 0xd79f21a7 __xfrm_lookup +EXPORT_SYMBOL vmlinux 0xd7a6fafa panic_notifier_list +EXPORT_SYMBOL vmlinux 0xd7d36d1a idr_find +EXPORT_SYMBOL vmlinux 0xd7dd777b reserve_perfctr_nmi +EXPORT_SYMBOL vmlinux 0xd81f53dc sk_stream_error +EXPORT_SYMBOL vmlinux 0xd85c4c5e __wait_on_buffer +EXPORT_SYMBOL vmlinux 0xd8723891 security_task_getsecid +EXPORT_SYMBOL vmlinux 0xd873ae76 kernel_sock_ioctl +EXPORT_SYMBOL vmlinux 0xd88f695a __mod_timer +EXPORT_SYMBOL vmlinux 0xd89da37f movable_zone +EXPORT_SYMBOL vmlinux 0xd89e09cf kobject_del +EXPORT_SYMBOL vmlinux 0xd8a2ab95 in_egroup_p +EXPORT_SYMBOL vmlinux 0xd8c5185c pci_iounmap +EXPORT_SYMBOL vmlinux 0xd8e0dca9 inet_sock_destruct +EXPORT_SYMBOL vmlinux 0xd8e484f0 register_chrdev_region +EXPORT_SYMBOL vmlinux 0xd9091363 acpi_install_notify_handler +EXPORT_SYMBOL vmlinux 0xd9316126 blk_queue_softirq_done +EXPORT_SYMBOL vmlinux 0xd985dc99 mempool_free_pages +EXPORT_SYMBOL vmlinux 0xd99240c0 pci_enable_bridges +EXPORT_SYMBOL vmlinux 0xd994f005 __getblk +EXPORT_SYMBOL vmlinux 0xd996d859 idr_pre_get +EXPORT_SYMBOL vmlinux 0xd9a1c35f set_bdi_congested +EXPORT_SYMBOL vmlinux 0xd9c272aa mca_mark_as_unused +EXPORT_SYMBOL vmlinux 0xd9dc2880 cpu_mask_all +EXPORT_SYMBOL vmlinux 0xd9ed229c blk_queue_make_request +EXPORT_SYMBOL vmlinux 0xda08c0d7 pcibios_get_irq_routing_table +EXPORT_SYMBOL vmlinux 0xda0a6b0e acpi_map_lsapic +EXPORT_SYMBOL vmlinux 0xda133953 generic_read_dir +EXPORT_SYMBOL vmlinux 0xda1a7335 kasprintf +EXPORT_SYMBOL vmlinux 0xda673859 request_firmware_nowait +EXPORT_SYMBOL vmlinux 0xda72fe1a acpi_check_mem_region +EXPORT_SYMBOL vmlinux 0xda73a1d0 __check_region +EXPORT_SYMBOL vmlinux 0xda7ca6cb fb_mode_is_equal +EXPORT_SYMBOL vmlinux 0xda7cdb7f skb_store_bits +EXPORT_SYMBOL vmlinux 0xda8af7ad fb_find_nearest_mode +EXPORT_SYMBOL vmlinux 0xda8f0879 tty_name +EXPORT_SYMBOL vmlinux 0xda8fd495 isapnp_write_byte +EXPORT_SYMBOL vmlinux 0xda928914 nmi_watchdog +EXPORT_SYMBOL vmlinux 0xdaa4c6e1 xfrm_unregister_km +EXPORT_SYMBOL vmlinux 0xdaa57ec3 totalhigh_pages +EXPORT_SYMBOL vmlinux 0xdaa5b155 nobh_writepage +EXPORT_SYMBOL vmlinux 0xdace038e netdev_class_remove_file +EXPORT_SYMBOL vmlinux 0xdacec2f7 blk_free_tags +EXPORT_SYMBOL vmlinux 0xdacf7d01 udp_prot +EXPORT_SYMBOL vmlinux 0xdad96e87 thermal_cooling_device_unregister +EXPORT_SYMBOL vmlinux 0xdaea8f2e tty_unregister_device +EXPORT_SYMBOL vmlinux 0xdb025278 copy_strings_kernel +EXPORT_SYMBOL vmlinux 0xdb183e9b console_stop +EXPORT_SYMBOL vmlinux 0xdb6ce750 copy_io_context +EXPORT_SYMBOL vmlinux 0xdb864d65 iov_iter_single_seg_count +EXPORT_SYMBOL vmlinux 0xdb88697b get_super +EXPORT_SYMBOL vmlinux 0xdbcd416e sysctl_ip_nonlocal_bind +EXPORT_SYMBOL vmlinux 0xdc14eda7 pci_pci_problems +EXPORT_SYMBOL vmlinux 0xdc222d18 xfrm4_rcv +EXPORT_SYMBOL vmlinux 0xdc2adb35 add_taint +EXPORT_SYMBOL vmlinux 0xdc317c05 vmalloc_to_page +EXPORT_SYMBOL vmlinux 0xdc3eaf70 iomem_resource +EXPORT_SYMBOL vmlinux 0xdc43a9c8 daemonize +EXPORT_SYMBOL vmlinux 0xdc873a70 screen_info +EXPORT_SYMBOL vmlinux 0xdc985ee5 redraw_screen +EXPORT_SYMBOL vmlinux 0xdc9bb54a unlock_super +EXPORT_SYMBOL vmlinux 0xdc9c4ce9 inet_release +EXPORT_SYMBOL vmlinux 0xdcc4e069 end_buffer_write_sync +EXPORT_SYMBOL vmlinux 0xdce23458 vfs_dq_drop +EXPORT_SYMBOL vmlinux 0xdcfa5cee tcp_md5_hash_key +EXPORT_SYMBOL vmlinux 0xdd0a2ba2 strlcat +EXPORT_SYMBOL vmlinux 0xdd3a0fee bio_integrity_trim +EXPORT_SYMBOL vmlinux 0xdd3e7f85 pci_save_state +EXPORT_SYMBOL vmlinux 0xdd6bfccd radix_tree_tag_set +EXPORT_SYMBOL vmlinux 0xddc1ac11 bioset_integrity_free +EXPORT_SYMBOL vmlinux 0xddeef053 vfs_stat +EXPORT_SYMBOL vmlinux 0xde432b7d freeze_bdev +EXPORT_SYMBOL vmlinux 0xde5c3e06 inet_sendmsg +EXPORT_SYMBOL vmlinux 0xde75b689 set_irq_type +EXPORT_SYMBOL vmlinux 0xde9360ba totalram_pages +EXPORT_SYMBOL vmlinux 0xdee633e8 ethtool_op_set_sg +EXPORT_SYMBOL vmlinux 0xdef48367 blk_queue_max_hw_segments +EXPORT_SYMBOL vmlinux 0xdf0da3cc acpi_get_devices +EXPORT_SYMBOL vmlinux 0xdf36db3c inet_addr_type +EXPORT_SYMBOL vmlinux 0xdf4b0ebd input_flush_device +EXPORT_SYMBOL vmlinux 0xdf60cc27 __print_symbol +EXPORT_SYMBOL vmlinux 0xdf6d6b15 bio_integrity_alloc +EXPORT_SYMBOL vmlinux 0xdf8c695a __ndelay +EXPORT_SYMBOL vmlinux 0xdf929370 fs_overflowgid +EXPORT_SYMBOL vmlinux 0xdf961cfc blk_unplug +EXPORT_SYMBOL vmlinux 0xdfdf69bf sysctl_ms_jiffies +EXPORT_SYMBOL vmlinux 0xdff6866a eisa_bus_type +EXPORT_SYMBOL vmlinux 0xe00ee246 find_lock_page +EXPORT_SYMBOL vmlinux 0xe00fb238 release_resource +EXPORT_SYMBOL vmlinux 0xe028c51f tr_type_trans +EXPORT_SYMBOL vmlinux 0xe03f8cdd arch_debugfs_dir +EXPORT_SYMBOL vmlinux 0xe06b4431 wait_for_key_construction +EXPORT_SYMBOL vmlinux 0xe075d6eb iter_div_u64_rem +EXPORT_SYMBOL vmlinux 0xe0a501e3 idr_remove_all +EXPORT_SYMBOL vmlinux 0xe0ac8bd2 acpi_bus_generate_netlink_event +EXPORT_SYMBOL vmlinux 0xe0b13336 argv_free +EXPORT_SYMBOL vmlinux 0xe0b5502d adjust_resource +EXPORT_SYMBOL vmlinux 0xe13cd8a7 dmi_name_in_vendors +EXPORT_SYMBOL vmlinux 0xe15aeee2 downgrade_write +EXPORT_SYMBOL vmlinux 0xe16f8a79 per_cpu__irq_regs +EXPORT_SYMBOL vmlinux 0xe1761617 security_inet_conn_request +EXPORT_SYMBOL vmlinux 0xe1f179be uart_suspend_port +EXPORT_SYMBOL vmlinux 0xe2292e0b skb_queue_head +EXPORT_SYMBOL vmlinux 0xe24d3a97 jiffies_64 +EXPORT_SYMBOL vmlinux 0xe27d5e9d rtnetlink_put_metrics +EXPORT_SYMBOL vmlinux 0xe2819ad5 dma_alloc_coherent +EXPORT_SYMBOL vmlinux 0xe2ae5252 ethtool_op_set_ufo +EXPORT_SYMBOL vmlinux 0xe2d5255a strcmp +EXPORT_SYMBOL vmlinux 0xe2fae716 kmemdup +EXPORT_SYMBOL vmlinux 0xe3150644 unregister_console +EXPORT_SYMBOL vmlinux 0xe351633f genl_register_family +EXPORT_SYMBOL vmlinux 0xe3895789 acpi_bus_register_driver +EXPORT_SYMBOL vmlinux 0xe3ad315a clear_inode +EXPORT_SYMBOL vmlinux 0xe3fbe148 acpi_install_table_handler +EXPORT_SYMBOL vmlinux 0xe40cc1f4 tcf_exts_change +EXPORT_SYMBOL vmlinux 0xe43617f7 acpi_gbl_FADT +EXPORT_SYMBOL vmlinux 0xe4398a07 __devm_release_region +EXPORT_SYMBOL vmlinux 0xe44bd062 kmem_cache_free +EXPORT_SYMBOL vmlinux 0xe44ff8a7 file_update_time +EXPORT_SYMBOL vmlinux 0xe456bd3a complete +EXPORT_SYMBOL vmlinux 0xe484e35f ioread32 +EXPORT_SYMBOL vmlinux 0xe4870354 _read_trylock +EXPORT_SYMBOL vmlinux 0xe48f3039 ida_get_new_above +EXPORT_SYMBOL vmlinux 0xe499aa3d kobject_put +EXPORT_SYMBOL vmlinux 0xe49ae565 is_bad_inode +EXPORT_SYMBOL vmlinux 0xe4c1df3e _read_lock_bh +EXPORT_SYMBOL vmlinux 0xe4fbcece acpi_bus_add +EXPORT_SYMBOL vmlinux 0xe5122890 flow_cache_genid +EXPORT_SYMBOL vmlinux 0xe5203770 mark_info_dirty +EXPORT_SYMBOL vmlinux 0xe523ad75 synchronize_irq +EXPORT_SYMBOL vmlinux 0xe540d5ae blk_queue_segment_boundary +EXPORT_SYMBOL vmlinux 0xe5518b37 tcp_proc_register +EXPORT_SYMBOL vmlinux 0xe55704ab nf_hooks +EXPORT_SYMBOL vmlinux 0xe57878a1 in6_pton +EXPORT_SYMBOL vmlinux 0xe5800ceb alloc_etherdev_mq +EXPORT_SYMBOL vmlinux 0xe5867808 dlci_ioctl_set +EXPORT_SYMBOL vmlinux 0xe5967d3c page_symlink +EXPORT_SYMBOL vmlinux 0xe5995935 kill_fasync +EXPORT_SYMBOL vmlinux 0xe5c78a99 do_blank_screen +EXPORT_SYMBOL vmlinux 0xe5e31e72 page_zero_new_buffers +EXPORT_SYMBOL vmlinux 0xe62866c2 vfs_getattr +EXPORT_SYMBOL vmlinux 0xe64a8428 kernel_read +EXPORT_SYMBOL vmlinux 0xe64e1426 block_commit_write +EXPORT_SYMBOL vmlinux 0xe68f09e6 kobject_set_name +EXPORT_SYMBOL vmlinux 0xe6a2b231 path_put +EXPORT_SYMBOL vmlinux 0xe6b3902a find_inode_number +EXPORT_SYMBOL vmlinux 0xe6ba7a57 pci_bus_size_bridges +EXPORT_SYMBOL vmlinux 0xe6ebc016 key_create_or_update +EXPORT_SYMBOL vmlinux 0xe6f65a59 vfs_statfs +EXPORT_SYMBOL vmlinux 0xe6fbe430 can_do_mlock +EXPORT_SYMBOL vmlinux 0xe70f3944 do_splice_from +EXPORT_SYMBOL vmlinux 0xe716baed acpi_unregister_ioapic +EXPORT_SYMBOL vmlinux 0xe7783577 get_unmapped_area +EXPORT_SYMBOL vmlinux 0xe7926aaa sysctl_jiffies +EXPORT_SYMBOL vmlinux 0xe7a200c0 key_negate_and_link +EXPORT_SYMBOL vmlinux 0xe7c5bbbe posix_unblock_lock +EXPORT_SYMBOL vmlinux 0xe7cfa31b task_nice +EXPORT_SYMBOL vmlinux 0xe7d4daac seq_list_next +EXPORT_SYMBOL vmlinux 0xe80812b6 wake_up_process +EXPORT_SYMBOL vmlinux 0xe81d2383 atm_alloc_charge +EXPORT_SYMBOL vmlinux 0xe85fe445 in_dev_finish_destroy +EXPORT_SYMBOL vmlinux 0xe8cd902e hweight16 +EXPORT_SYMBOL vmlinux 0xe8f055a4 uart_get_baud_rate +EXPORT_SYMBOL vmlinux 0xe910b532 del_timer_sync +EXPORT_SYMBOL vmlinux 0xe914e41e strcpy +EXPORT_SYMBOL vmlinux 0xe925a86f dquot_mark_dquot_dirty +EXPORT_SYMBOL vmlinux 0xe9456a5a sysctl_xfrm_aevent_rseqth +EXPORT_SYMBOL vmlinux 0xe96cf72c dev_unicast_unsync +EXPORT_SYMBOL vmlinux 0xe997667b wrmsr_on_cpu +EXPORT_SYMBOL vmlinux 0xe99783d6 uart_match_port +EXPORT_SYMBOL vmlinux 0xe9b8d47a wireless_spy_update +EXPORT_SYMBOL vmlinux 0xe9bf6e6a xfrm_policy_destroy +EXPORT_SYMBOL vmlinux 0xe9ec0b40 inet_frag_destroy +EXPORT_SYMBOL vmlinux 0xe9eecce8 tcp_setsockopt +EXPORT_SYMBOL vmlinux 0xea10655a __bitmap_intersects +EXPORT_SYMBOL vmlinux 0xea2d33a2 radix_tree_gang_lookup_slot +EXPORT_SYMBOL vmlinux 0xea2f8c61 vfs_readv +EXPORT_SYMBOL vmlinux 0xea64f32c tcp_splice_read +EXPORT_SYMBOL vmlinux 0xea6fcdaa genl_unregister_family +EXPORT_SYMBOL vmlinux 0xea770a1b ___pskb_trim +EXPORT_SYMBOL vmlinux 0xea7987f1 key_update +EXPORT_SYMBOL vmlinux 0xea858cb5 radix_tree_gang_lookup_tag +EXPORT_SYMBOL vmlinux 0xeaac29c0 get_disk +EXPORT_SYMBOL vmlinux 0xeae3dfd6 __const_udelay +EXPORT_SYMBOL vmlinux 0xeb1fabf6 interruptible_sleep_on +EXPORT_SYMBOL vmlinux 0xeb395084 param_get_invbool +EXPORT_SYMBOL vmlinux 0xeb688572 sock_no_accept +EXPORT_SYMBOL vmlinux 0xeb79e921 input_register_handler +EXPORT_SYMBOL vmlinux 0xeb8f54b3 strstrip +EXPORT_SYMBOL vmlinux 0xebc23a99 pci_remove_bus +EXPORT_SYMBOL vmlinux 0xebd273a6 strict_strtoull +EXPORT_SYMBOL vmlinux 0xec187ca8 netdev_bonding_change +EXPORT_SYMBOL vmlinux 0xec1ca34a __skb_checksum_complete_head +EXPORT_SYMBOL vmlinux 0xec2330f7 inet_csk_delete_keepalive_timer +EXPORT_SYMBOL vmlinux 0xec2a526e pnp_register_card_driver +EXPORT_SYMBOL vmlinux 0xec430c7c boot_cpu_data +EXPORT_SYMBOL vmlinux 0xec72c108 pci_get_slot +EXPORT_SYMBOL vmlinux 0xec860422 bioset_free +EXPORT_SYMBOL vmlinux 0xec8683f2 take_over_console +EXPORT_SYMBOL vmlinux 0xecc088c7 pci_try_set_mwi +EXPORT_SYMBOL vmlinux 0xecc0f464 pci_enable_wake +EXPORT_SYMBOL vmlinux 0xecde1418 _spin_lock_irq +EXPORT_SYMBOL vmlinux 0xece2203a inode_add_bytes +EXPORT_SYMBOL vmlinux 0xed28cb47 netif_receive_skb +EXPORT_SYMBOL vmlinux 0xed3492c4 vfs_readdir +EXPORT_SYMBOL vmlinux 0xed409589 pagevec_lookup_tag +EXPORT_SYMBOL vmlinux 0xed40abde kernel_sock_shutdown +EXPORT_SYMBOL vmlinux 0xed58ef06 blk_queue_dma_alignment +EXPORT_SYMBOL vmlinux 0xed5b2bd1 blk_start_queueing +EXPORT_SYMBOL vmlinux 0xed633abc pv_irq_ops +EXPORT_SYMBOL vmlinux 0xed738778 generic_file_mmap +EXPORT_SYMBOL vmlinux 0xed7be9b1 inet_frags_exit_net +EXPORT_SYMBOL vmlinux 0xed8c0e77 mod_zone_page_state +EXPORT_SYMBOL vmlinux 0xedbaee5e nla_strcmp +EXPORT_SYMBOL vmlinux 0xedc03953 iounmap +EXPORT_SYMBOL vmlinux 0xedcab7dd dma_declare_coherent_memory +EXPORT_SYMBOL vmlinux 0xedd14538 param_get_uint +EXPORT_SYMBOL vmlinux 0xedfbb839 pci_assign_resource +EXPORT_SYMBOL vmlinux 0xee00aea1 nf_log_register +EXPORT_SYMBOL vmlinux 0xee295b9f skb_push +EXPORT_SYMBOL vmlinux 0xee2d0fc7 _local_bh_enable +EXPORT_SYMBOL vmlinux 0xee2eb374 read_dev_sector +EXPORT_SYMBOL vmlinux 0xee7eb9e1 pnp_platform_devices +EXPORT_SYMBOL vmlinux 0xeea9dbaf bitmap_bitremap +EXPORT_SYMBOL vmlinux 0xeeb1717c param_array_get +EXPORT_SYMBOL vmlinux 0xeedb3afc sysctl_intvec +EXPORT_SYMBOL vmlinux 0xef172e77 inet_accept +EXPORT_SYMBOL vmlinux 0xef3bd862 mca_find_unused_adapter +EXPORT_SYMBOL vmlinux 0xef628a48 seq_open +EXPORT_SYMBOL vmlinux 0xef9aedfc boot_option_idle_override +EXPORT_SYMBOL vmlinux 0xefdd70ce security_secid_to_secctx +EXPORT_SYMBOL vmlinux 0xefe099c3 acpi_get_event_status +EXPORT_SYMBOL vmlinux 0xf0009fee put_pages_list +EXPORT_SYMBOL vmlinux 0xf0203112 tcp_child_process +EXPORT_SYMBOL vmlinux 0xf022be46 inc_zone_page_state +EXPORT_SYMBOL vmlinux 0xf03825ca pci_bus_type +EXPORT_SYMBOL vmlinux 0xf0572d3c register_sysctl_table +EXPORT_SYMBOL vmlinux 0xf065f629 ioread16be +EXPORT_SYMBOL vmlinux 0xf06b8089 del_gendisk +EXPORT_SYMBOL vmlinux 0xf070e96e pci_scan_slot +EXPORT_SYMBOL vmlinux 0xf075b374 ip_route_me_harder +EXPORT_SYMBOL vmlinux 0xf0a778d9 blk_get_request +EXPORT_SYMBOL vmlinux 0xf0b57c68 param_set_long +EXPORT_SYMBOL vmlinux 0xf0d1d471 blk_rq_append_bio +EXPORT_SYMBOL vmlinux 0xf0f1246c kvasprintf +EXPORT_SYMBOL vmlinux 0xf0f3f41a bio_map_kern +EXPORT_SYMBOL vmlinux 0xf1039607 tcf_em_register +EXPORT_SYMBOL vmlinux 0xf1086259 register_framebuffer +EXPORT_SYMBOL vmlinux 0xf10de535 ioread8 +EXPORT_SYMBOL vmlinux 0xf10f68ed pci_scan_bridge +EXPORT_SYMBOL vmlinux 0xf11543ff find_first_zero_bit +EXPORT_SYMBOL vmlinux 0xf162fe2d sysctl_xfrm_aevent_etime +EXPORT_SYMBOL vmlinux 0xf174ed48 acquire_console_sem +EXPORT_SYMBOL vmlinux 0xf17d481f rtnl_notify +EXPORT_SYMBOL vmlinux 0xf195c682 fb_invert_cmaps +EXPORT_SYMBOL vmlinux 0xf19effcd tcp_poll +EXPORT_SYMBOL vmlinux 0xf1aa8007 sk_common_release +EXPORT_SYMBOL vmlinux 0xf1cc0042 acpi_bus_generate_proc_event +EXPORT_SYMBOL vmlinux 0xf1deabf2 div64_u64 +EXPORT_SYMBOL vmlinux 0xf1e98c74 avenrun +EXPORT_SYMBOL vmlinux 0xf20dabd8 free_irq +EXPORT_SYMBOL vmlinux 0xf227476f try_to_release_page +EXPORT_SYMBOL vmlinux 0xf246de13 tcf_hash_destroy +EXPORT_SYMBOL vmlinux 0xf2666351 bio_split +EXPORT_SYMBOL vmlinux 0xf272584f block_page_mkwrite +EXPORT_SYMBOL vmlinux 0xf2997713 tty_termios_hw_change +EXPORT_SYMBOL vmlinux 0xf2a6d2bf xfrm_policy_count +EXPORT_SYMBOL vmlinux 0xf2afa595 param_get_charp +EXPORT_SYMBOL vmlinux 0xf2d4a410 wait_on_sync_kiocb +EXPORT_SYMBOL vmlinux 0xf2e74040 mca_set_adapter_name +EXPORT_SYMBOL vmlinux 0xf2efed68 elv_rq_merge_ok +EXPORT_SYMBOL vmlinux 0xf2fe7081 audit_log_start +EXPORT_SYMBOL vmlinux 0xf2feb84c lock_super +EXPORT_SYMBOL vmlinux 0xf313da4e sha_transform +EXPORT_SYMBOL vmlinux 0xf3341268 __clear_user +EXPORT_SYMBOL vmlinux 0xf338d4c3 netlink_unregister_notifier +EXPORT_SYMBOL vmlinux 0xf3437ca2 pci_dev_put +EXPORT_SYMBOL vmlinux 0xf346231f seq_list_start_head +EXPORT_SYMBOL vmlinux 0xf36a0f7c generic_file_readonly_mmap +EXPORT_SYMBOL vmlinux 0xf39bf4d9 put_cmsg +EXPORT_SYMBOL vmlinux 0xf3b8b179 console_start +EXPORT_SYMBOL vmlinux 0xf3bf0bce __bitmap_complement +EXPORT_SYMBOL vmlinux 0xf3ecdd22 xfrm_unregister_type +EXPORT_SYMBOL vmlinux 0xf3f9f5bf xfrm_state_lookup +EXPORT_SYMBOL vmlinux 0xf441ac43 ioread8_rep +EXPORT_SYMBOL vmlinux 0xf44e5c1b blk_queue_dma_pad +EXPORT_SYMBOL vmlinux 0xf47d47e0 acpi_enable_gpe +EXPORT_SYMBOL vmlinux 0xf48a2c4c MCA_bus +EXPORT_SYMBOL vmlinux 0xf49bc67a atm_pcr_goal +EXPORT_SYMBOL vmlinux 0xf4a5c213 avail_to_resrv_perfctr_nmi_bit +EXPORT_SYMBOL vmlinux 0xf4ae9d51 ida_pre_get +EXPORT_SYMBOL vmlinux 0xf4b2a31c bio_map_user +EXPORT_SYMBOL vmlinux 0xf4bfa90d scm_fp_dup +EXPORT_SYMBOL vmlinux 0xf4c531c0 generic_file_direct_write +EXPORT_SYMBOL vmlinux 0xf4f14de6 rtnl_trylock +EXPORT_SYMBOL vmlinux 0xf4f52f93 dqstats +EXPORT_SYMBOL vmlinux 0xf502d273 acpi_get_current_resources +EXPORT_SYMBOL vmlinux 0xf51ae235 touch_nmi_watchdog +EXPORT_SYMBOL vmlinux 0xf53d4c26 qdisc_class_hash_destroy +EXPORT_SYMBOL vmlinux 0xf53db8c0 lock_may_write +EXPORT_SYMBOL vmlinux 0xf57c0aaa generic_cont_expand_simple +EXPORT_SYMBOL vmlinux 0xf58d2a7d simple_fill_super +EXPORT_SYMBOL vmlinux 0xf5919af3 pci_set_dma_seg_boundary +EXPORT_SYMBOL vmlinux 0xf5c05914 generic_segment_checks +EXPORT_SYMBOL vmlinux 0xf5ce9811 tcp_memory_allocated +EXPORT_SYMBOL vmlinux 0xf5d2600f key_instantiate_and_link +EXPORT_SYMBOL vmlinux 0xf5d9369b kobject_get +EXPORT_SYMBOL vmlinux 0xf639ac77 send_sig_info +EXPORT_SYMBOL vmlinux 0xf656add1 inet_csk_destroy_sock +EXPORT_SYMBOL vmlinux 0xf66451b3 start_tty +EXPORT_SYMBOL vmlinux 0xf6bb4729 color_table +EXPORT_SYMBOL vmlinux 0xf6cf7da3 dma_set_mask +EXPORT_SYMBOL vmlinux 0xf6ebc03b net_ratelimit +EXPORT_SYMBOL vmlinux 0xf71a9153 pci_request_selected_regions +EXPORT_SYMBOL vmlinux 0xf72ddaec qdisc_watchdog_init +EXPORT_SYMBOL vmlinux 0xf7623914 radix_tree_tag_clear +EXPORT_SYMBOL vmlinux 0xf786ef5e idr_init +EXPORT_SYMBOL vmlinux 0xf786f637 simple_prepare_write +EXPORT_SYMBOL vmlinux 0xf78d04ab netlink_register_notifier +EXPORT_SYMBOL vmlinux 0xf78eaf55 unregister_8022_client +EXPORT_SYMBOL vmlinux 0xf79289e0 __skb_warn_lro_forwarding +EXPORT_SYMBOL vmlinux 0xf7b8f31d pci_find_parent_resource +EXPORT_SYMBOL vmlinux 0xf7bfb098 simple_dir_operations +EXPORT_SYMBOL vmlinux 0xf7ce1a5f __f_setown +EXPORT_SYMBOL vmlinux 0xf7ee849b mca_device_transform_irq +EXPORT_SYMBOL vmlinux 0xf802783e simple_transaction_get +EXPORT_SYMBOL vmlinux 0xf82abc1d isa_dma_bridge_buggy +EXPORT_SYMBOL vmlinux 0xf82e3d47 acpi_initialize_objects +EXPORT_SYMBOL vmlinux 0xf82f1109 utf8_wctomb +EXPORT_SYMBOL vmlinux 0xf85b266d invalidate_mapping_pages +EXPORT_SYMBOL vmlinux 0xf8814f73 rb_last +EXPORT_SYMBOL vmlinux 0xf88e0ee2 acpi_get_table_header +EXPORT_SYMBOL vmlinux 0xf890fe7f pm_idle +EXPORT_SYMBOL vmlinux 0xf8aa47ae mutex_lock_killable +EXPORT_SYMBOL vmlinux 0xf8b30e93 mempool_create +EXPORT_SYMBOL vmlinux 0xf8c7f614 add_disk +EXPORT_SYMBOL vmlinux 0xf8ca3d38 unregister_framebuffer +EXPORT_SYMBOL vmlinux 0xf8cf9ee5 abort_exclusive_wait +EXPORT_SYMBOL vmlinux 0xf8dba3b4 sb_min_blocksize +EXPORT_SYMBOL vmlinux 0xf8f21065 __bforget +EXPORT_SYMBOL vmlinux 0xf950d92e pci_set_dma_max_seg_size +EXPORT_SYMBOL vmlinux 0xf9a482f9 msleep +EXPORT_SYMBOL vmlinux 0xf9c6f893 blkdev_issue_flush +EXPORT_SYMBOL vmlinux 0xfa03b972 ip_route_output_key +EXPORT_SYMBOL vmlinux 0xfa040cb4 blk_rq_map_integrity_sg +EXPORT_SYMBOL vmlinux 0xfa0564fc __wait_on_bit_lock +EXPORT_SYMBOL vmlinux 0xfa121311 __rta_fill +EXPORT_SYMBOL vmlinux 0xfa69091e file_remove_suid +EXPORT_SYMBOL vmlinux 0xfa702610 proto_register +EXPORT_SYMBOL vmlinux 0xfaae9f7f fsync_bdev +EXPORT_SYMBOL vmlinux 0xfab53ef6 tty_hangup +EXPORT_SYMBOL vmlinux 0xfae22556 mpage_readpages +EXPORT_SYMBOL vmlinux 0xfaf98462 bitrev32 +EXPORT_SYMBOL vmlinux 0xfb0443fb acpi_get_parent +EXPORT_SYMBOL vmlinux 0xfb0cf2e9 touch_all_softlockup_watchdogs +EXPORT_SYMBOL vmlinux 0xfb6af58d recalc_sigpending +EXPORT_SYMBOL vmlinux 0xfb71a55e blk_remove_plug +EXPORT_SYMBOL vmlinux 0xfba0aac1 dmam_pool_destroy +EXPORT_SYMBOL vmlinux 0xfba0c2e0 llc_sap_list_lock +EXPORT_SYMBOL vmlinux 0xfbed20d8 ioremap_nocache +EXPORT_SYMBOL vmlinux 0xfbf92453 param_get_bool +EXPORT_SYMBOL vmlinux 0xfc02b7ad sysctl_tcp_wmem +EXPORT_SYMBOL vmlinux 0xfc0f99bc ipv6_skip_exthdr +EXPORT_SYMBOL vmlinux 0xfc309c3e cancel_delayed_work_sync +EXPORT_SYMBOL vmlinux 0xfc39e32f ioport_unmap +EXPORT_SYMBOL vmlinux 0xfc59e84b dentry_open +EXPORT_SYMBOL vmlinux 0xfc68a7b5 neigh_event_ns +EXPORT_SYMBOL vmlinux 0xfc7ceac1 __mark_inode_dirty +EXPORT_SYMBOL vmlinux 0xfc9be079 qdisc_watchdog_schedule +EXPORT_SYMBOL vmlinux 0xfcaa04a0 out_of_line_wait_on_bit_lock +EXPORT_SYMBOL vmlinux 0xfcb9d2c3 generic_osync_inode +EXPORT_SYMBOL vmlinux 0xfcda63a3 node_states +EXPORT_SYMBOL vmlinux 0xfcdd8cf6 param_get_ushort +EXPORT_SYMBOL vmlinux 0xfcec0987 enable_irq +EXPORT_SYMBOL vmlinux 0xfcfa03ff fb_videomode_to_modelist +EXPORT_SYMBOL vmlinux 0xfcfd6e6d ps2_handle_ack +EXPORT_SYMBOL vmlinux 0xfd4778b3 udp_flush_pending_frames +EXPORT_SYMBOL vmlinux 0xfd4f7bab d_alloc_name +EXPORT_SYMBOL vmlinux 0xfd73195c simple_transaction_release +EXPORT_SYMBOL vmlinux 0xfd8bd906 unlock_page +EXPORT_SYMBOL vmlinux 0xfd98879a rb_next +EXPORT_SYMBOL vmlinux 0xfdae75f9 ip_setsockopt +EXPORT_SYMBOL vmlinux 0xfdb44140 sysctl_data +EXPORT_SYMBOL vmlinux 0xfdb9b629 ioread32be +EXPORT_SYMBOL vmlinux 0xfdc48165 xrlim_allow +EXPORT_SYMBOL vmlinux 0xfdc5fefa pci_iomap +EXPORT_SYMBOL vmlinux 0xfde2145a boot_tvec_bases +EXPORT_SYMBOL vmlinux 0xfde2bd58 __mpage_writepage +EXPORT_SYMBOL vmlinux 0xfdf2025b register_snap_client +EXPORT_SYMBOL vmlinux 0xfe5aba5c block_invalidatepage +EXPORT_SYMBOL vmlinux 0xfe5d4bb2 sys_tz +EXPORT_SYMBOL vmlinux 0xfe62b4a8 pci_release_region +EXPORT_SYMBOL vmlinux 0xfe769456 unregister_netdevice_notifier +EXPORT_SYMBOL vmlinux 0xfe7c4287 nr_cpu_ids +EXPORT_SYMBOL vmlinux 0xfe9be922 __skb_recv_datagram +EXPORT_SYMBOL vmlinux 0xfeb0e550 simple_pin_fs +EXPORT_SYMBOL vmlinux 0xfec3c2f2 bcd2bin +EXPORT_SYMBOL vmlinux 0xfecb1bf6 sock_create_kern +EXPORT_SYMBOL vmlinux 0xfecbd874 ip_generic_getfrag +EXPORT_SYMBOL vmlinux 0xfedd35fc console_suspend_enabled +EXPORT_SYMBOL vmlinux 0xff1e9dd8 seq_list_start +EXPORT_SYMBOL vmlinux 0xff2eee35 vc_resize +EXPORT_SYMBOL vmlinux 0xff345e74 mpage_writepages +EXPORT_SYMBOL vmlinux 0xff4235b2 vfs_quota_on_path +EXPORT_SYMBOL vmlinux 0xff5a772d input_open_device +EXPORT_SYMBOL vmlinux 0xff6878cf fb_default_cmap +EXPORT_SYMBOL vmlinux 0xff6d6957 dput +EXPORT_SYMBOL vmlinux 0xff708fd3 mempool_destroy +EXPORT_SYMBOL vmlinux 0xff9ca065 fb_edid_to_monspecs +EXPORT_SYMBOL vmlinux 0xffafdc5c _read_unlock_irq +EXPORT_SYMBOL vmlinux 0xffb119e6 pci_find_device +EXPORT_SYMBOL vmlinux 0xffd5a395 default_wake_function +EXPORT_SYMBOL_GPL arch/x86/kernel/cpu/cpufreq/speedstep-lib 0x16836e04 speedstep_detect_processor +EXPORT_SYMBOL_GPL arch/x86/kernel/cpu/cpufreq/speedstep-lib 0x4cdb4bd0 speedstep_get_processor_frequency +EXPORT_SYMBOL_GPL arch/x86/kernel/cpu/cpufreq/speedstep-lib 0xd494ee54 speedstep_get_freqs +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x00aaf935 kvm_disable_tdp +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x05b4018d kvm_mmu_unprotect_page_virt +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x07cf7344 kvm_lapic_find_highest_irr +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x07fa02be kvm_set_cr0 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x09276228 kvm_get_msr_common +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x094ac8f4 kvm_get_pfn +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x0a07e0b0 kvm_lapic_get_cr8 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x0f4d0ab4 emulator_write_emulated +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x10f9b8bb kvm_queue_exception_e +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x12d1b23b kvm_release_pfn_clean +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x17d4d015 kvm_set_page_dirty +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x1bd65ec3 kvm_inject_nmi +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x1c664b36 kvm_timer_intr_post +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x1cc3d5f2 kvm_lmsw +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x1e4580bb kvm_release_pfn_dirty +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x1f45591a kvm_cpu_has_interrupt +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x22fd6e5e kvm_clear_guest_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x2322e039 kvm_set_pfn_accessed +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x27046576 kvm_exit +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x2c877f2b kvm_read_guest_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x317f9e6b kvm_enable_efer_bits +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x337b8e2e load_pdptrs +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x346dd1e9 kvm_set_cr3 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x3a72d858 kvm_resched +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x3abf76e9 kvm_set_cr8 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x3b2f4983 kvm_emulate_hypercall +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x3fc68979 is_error_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x46f105d3 kvm_put_guest_fpu +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x49922ff4 gfn_to_hva +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x4a7cbe69 is_error_pfn +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x4be6152e kvm_vcpu_cache +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x500908cb kvm_get_cr8 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x5193956c fx_init +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x599086dd kvm_handle_fault_on_reboot +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x5fb88649 kvm_emulate_halt +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x601b87ae gfn_to_pfn +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x62811eba kvm_lapic_set_tpr +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x6736055d kvm_clear_guest +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x692d1a57 kvm_put_kvm +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x69ac6d05 kvm_get_kvm +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x6e14f288 __kvm_set_memory_region +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x704baf67 kvm_load_guest_fpu +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x7989f1ec kvm_lapic_get_base +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x80f1c7ea kvm_lapic_reset +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8a70eb7a kvm_read_guest +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8c4442df kvm_mmu_reset_context +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8ce4f3ab kvm_enable_tdp +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8d85dac4 kvm_get_cs_db_l_bits +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8e7f9b47 segment_base +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x96f155c8 kvm_mmu_load +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x992885c4 emulator_read_std +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x9ecf6e39 kvm_lapic_enabled +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xa361bc65 kvm_set_pfn_dirty +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xa432a5f2 kvm_emulate_pio +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xa48951c1 kvm_mmu_page_fault +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xa4dc3707 kvm_vcpu_uninit +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xaa702831 gfn_to_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xb0b94ed7 kvm_release_page_clean +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xb65208c6 kvm_set_msr_common +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbaa232f9 kvm_vcpu_init +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbc9f08c5 kvm_get_apic_base +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbd377dc9 kvm_mmu_set_nonpresent_ptes +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbd59397c kvm_write_guest_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbd94103b kvm_mmu_set_base_ptes +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xc1eef9b9 kvm_release_page_dirty +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xc1fb2c0b kvm_create_lapic +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xc505f90b kvm_emulate_cpuid +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xcee530f1 kvm_report_emulation_failure +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd0b2727a kvm_mmu_set_mask_ptes +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd296def9 kvm_is_error_hva +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd2d211cf kvm_set_memory_region +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd6e8d5d7 kvm_inject_pending_timer_irqs +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd7d84444 kvm_set_apic_base +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xda02024e kvm_task_switch +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xe996185f kvm_emulate_pio_string +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xed16d0a4 kvm_queue_exception +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xed3b2562 kvm_init +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xeec9a34f emulate_instruction +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xf4e03bb5 kvm_set_cr4 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xfde6f7a7 kvm_cpu_get_interrupt +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xff8f6386 kvm_is_visible_gfn +EXPORT_SYMBOL_GPL crypto/aead 0x5b42f062 crypto_aead_type +EXPORT_SYMBOL_GPL crypto/aead 0x98c59330 crypto_nivaead_type +EXPORT_SYMBOL_GPL crypto/aead 0x9ee5c895 aead_geniv_free +EXPORT_SYMBOL_GPL crypto/aead 0xa07ed6d7 aead_geniv_init +EXPORT_SYMBOL_GPL crypto/aead 0xa4fafd28 crypto_alloc_aead +EXPORT_SYMBOL_GPL crypto/aead 0xa70fa6d1 aead_geniv_exit +EXPORT_SYMBOL_GPL crypto/aead 0xb30e7616 aead_geniv_alloc +EXPORT_SYMBOL_GPL crypto/aead 0xbf44df8d crypto_aead_setauthsize +EXPORT_SYMBOL_GPL crypto/aead 0xf0928ce8 crypto_grab_aead +EXPORT_SYMBOL_GPL crypto/aes_generic 0x1381bf2d crypto_ft_tab +EXPORT_SYMBOL_GPL crypto/aes_generic 0x22894d94 crypto_il_tab +EXPORT_SYMBOL_GPL crypto/aes_generic 0x5f943003 crypto_it_tab +EXPORT_SYMBOL_GPL crypto/aes_generic 0x5fe743de crypto_aes_expand_key +EXPORT_SYMBOL_GPL crypto/aes_generic 0x6e9cc2ba crypto_fl_tab +EXPORT_SYMBOL_GPL crypto/aes_generic 0x959d1946 crypto_aes_set_key +EXPORT_SYMBOL_GPL crypto/async_tx/async_memcpy 0xd71a9805 async_memcpy +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0x6becb18a async_trigger_callback +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0x9ad555e8 async_tx_submit +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0xe31fefbc async_tx_quiesce +EXPORT_SYMBOL_GPL crypto/async_tx/async_xor 0x0f8d26f9 async_xor_zero_sum +EXPORT_SYMBOL_GPL crypto/async_tx/async_xor 0x48016458 async_xor +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x246ff3d6 blkcipher_walk_phys +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x2fedfe6a blkcipher_walk_done +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x37688d94 blkcipher_walk_virt +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x3f99dedb crypto_alloc_ablkcipher +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x4798810f skcipher_geniv_free +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x628657ea skcipher_geniv_init +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x766e3a10 blkcipher_walk_virt_block +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x87bd25ae crypto_ablkcipher_type +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x89914870 crypto_givcipher_type +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0xab7ad554 crypto_grab_skcipher +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0xadcc2859 skcipher_geniv_alloc +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0xc9fff6bd skcipher_geniv_exit +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0xcd9e5e32 crypto_blkcipher_type +EXPORT_SYMBOL_GPL crypto/des_generic 0xcfd9a2c0 des_ekey +EXPORT_SYMBOL_GPL crypto/twofish_common 0xcb3f501c twofish_setkey +EXPORT_SYMBOL_GPL drivers/acpi/dock 0x100c48a2 unregister_dock_notifier +EXPORT_SYMBOL_GPL drivers/acpi/dock 0x2611fbee register_hotplug_dock_device +EXPORT_SYMBOL_GPL drivers/acpi/dock 0x318920b1 register_dock_notifier +EXPORT_SYMBOL_GPL drivers/acpi/dock 0xbd506a46 unregister_hotplug_dock_device +EXPORT_SYMBOL_GPL drivers/acpi/dock 0xcc6ab305 is_dock_device +EXPORT_SYMBOL_GPL drivers/acpi/sbshc 0x0ad5c33f acpi_smbus_register_callback +EXPORT_SYMBOL_GPL drivers/acpi/sbshc 0x158c2ad0 acpi_smbus_unregister_callback +EXPORT_SYMBOL_GPL drivers/acpi/sbshc 0x526b867a acpi_smbus_read +EXPORT_SYMBOL_GPL drivers/acpi/sbshc 0xb3d5e527 acpi_smbus_write +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0x3ecf6cfc wmi_install_notify_handler +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0x64ebe677 wmi_query_block +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0xa9b7afd8 wmi_set_block +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0xb5a6ebe2 wmi_remove_notify_handler +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0xc5e3dddf wmi_get_event_data +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0xc9d4d6d1 wmi_has_guid +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0xe2426710 wmi_evaluate_method +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0067df75 ata_tf_from_fis +EXPORT_SYMBOL_GPL drivers/ata/libata 0x00ebcb5d ata_id_string +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0310a715 ata_sff_tf_load +EXPORT_SYMBOL_GPL drivers/ata/libata 0x034b7f97 sata_link_hardreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0394d25f ata_do_set_mode +EXPORT_SYMBOL_GPL drivers/ata/libata 0x03d05fe9 ata_sff_freeze +EXPORT_SYMBOL_GPL drivers/ata/libata 0x03e3686c ata_timing_cycle2mode +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0531dcb8 ata_dev_classify +EXPORT_SYMBOL_GPL drivers/ata/libata 0x060bfed7 ata_pci_remove_one +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0638d738 ata_sff_tf_read +EXPORT_SYMBOL_GPL drivers/ata/libata 0x06feafcf ata_acpi_gtm +EXPORT_SYMBOL_GPL drivers/ata/libata 0x08e1feb0 ata_sff_wait_after_reset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0ad7e7c3 ata_cable_ignore +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0b84399c dev_attr_em_message_type +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0cbdca86 ata_pci_device_do_suspend +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0f0b564a ata_pci_sff_prepare_host +EXPORT_SYMBOL_GPL drivers/ata/libata 0x12c93c0e ata_sas_queuecmd +EXPORT_SYMBOL_GPL drivers/ata/libata 0x12eafa20 ata_sas_port_stop +EXPORT_SYMBOL_GPL drivers/ata/libata 0x16591887 ata_host_resume +EXPORT_SYMBOL_GPL drivers/ata/libata 0x199418e4 ata_sff_postreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x1999a763 ata_host_init +EXPORT_SYMBOL_GPL drivers/ata/libata 0x1aee479f ata_host_detach +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2341d49b ata_sff_port_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0x26111705 ata_link_online +EXPORT_SYMBOL_GPL drivers/ata/libata 0x275610c1 ata_pci_sff_init_host +EXPORT_SYMBOL_GPL drivers/ata/libata 0x278be46a ata_port_disable +EXPORT_SYMBOL_GPL drivers/ata/libata 0x27cef065 ata_cable_40wire +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2b126444 ata_eh_qc_complete +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2c69466a sata_scr_write +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2c8d8391 ata_bmdma_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2d0a9545 ata_port_probe +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2d3d81b1 ata_port_abort +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2d905a7f ata_std_postreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2eac2e4e ata_sff_qc_fill_rtf +EXPORT_SYMBOL_GPL drivers/ata/libata 0x3383fdbe ata_sas_slave_configure +EXPORT_SYMBOL_GPL drivers/ata/libata 0x340737f4 ata_scsi_simulate +EXPORT_SYMBOL_GPL drivers/ata/libata 0x34474ef9 ata_sg_init +EXPORT_SYMBOL_GPL drivers/ata/libata 0x352615fc ata_sff_wait_ready +EXPORT_SYMBOL_GPL drivers/ata/libata 0x362be22f ata_host_alloc +EXPORT_SYMBOL_GPL drivers/ata/libata 0x3678d7d1 ata_sff_busy_sleep +EXPORT_SYMBOL_GPL drivers/ata/libata 0x38f31a98 ata_sff_data_xfer_noirq +EXPORT_SYMBOL_GPL drivers/ata/libata 0x3dcd76e8 ata_eh_freeze_port +EXPORT_SYMBOL_GPL drivers/ata/libata 0x3e9cb453 sata_link_resume +EXPORT_SYMBOL_GPL drivers/ata/libata 0x3f720aab sata_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x40af0dec ata_xfer_mode2mask +EXPORT_SYMBOL_GPL drivers/ata/libata 0x41f3ac95 ata_sff_data_xfer +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4330b638 ata_sff_error_handler +EXPORT_SYMBOL_GPL drivers/ata/libata 0x43f56e82 ata_xfer_mode2shift +EXPORT_SYMBOL_GPL drivers/ata/libata 0x442218d8 ata_noop_qc_prep +EXPORT_SYMBOL_GPL drivers/ata/libata 0x446d2ed3 dev_attr_em_message +EXPORT_SYMBOL_GPL drivers/ata/libata 0x44d37f0d ata_ehi_push_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0x472a369e ata_dummy_port_info +EXPORT_SYMBOL_GPL drivers/ata/libata 0x478d89e3 ata_eh_analyze_ncq_error +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4a7b351e ata_sff_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4d4e2619 ata_bmdma_mode_filter +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4e43919b ata_sff_pause +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4fcdc949 ata_port_freeze +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4fdc945d sata_deb_timing_normal +EXPORT_SYMBOL_GPL drivers/ata/libata 0x549eb3e0 ata_pci_device_do_resume +EXPORT_SYMBOL_GPL drivers/ata/libata 0x55ef6593 ata_dev_disable +EXPORT_SYMBOL_GPL drivers/ata/libata 0x5632e20c ata_pci_device_resume +EXPORT_SYMBOL_GPL drivers/ata/libata 0x5a196d83 ata_sff_dev_select +EXPORT_SYMBOL_GPL drivers/ata/libata 0x5abd034d dev_attr_sw_activity +EXPORT_SYMBOL_GPL drivers/ata/libata 0x5ddbcc6d ata_sff_softreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x60fd4287 ata_cable_unknown +EXPORT_SYMBOL_GPL drivers/ata/libata 0x62483422 ata_sff_thaw +EXPORT_SYMBOL_GPL drivers/ata/libata 0x69e9a2cb ata_scsi_slave_config +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6ba3ca2b ata_sas_port_alloc +EXPORT_SYMBOL_GPL drivers/ata/libata 0x70629948 ata_sff_dma_pause +EXPORT_SYMBOL_GPL drivers/ata/libata 0x70737cf4 ata_pci_device_suspend +EXPORT_SYMBOL_GPL drivers/ata/libata 0x707ff1bb ata_xfer_mask2mode +EXPORT_SYMBOL_GPL drivers/ata/libata 0x70b29190 ata_scsi_queuecmd +EXPORT_SYMBOL_GPL drivers/ata/libata 0x70bd6e0e ata_pci_sff_activate_host +EXPORT_SYMBOL_GPL drivers/ata/libata 0x734dbb55 sata_scr_valid +EXPORT_SYMBOL_GPL drivers/ata/libata 0x73a48b4a ata_sff_std_ports +EXPORT_SYMBOL_GPL drivers/ata/libata 0x743a165e ata_pack_xfermask +EXPORT_SYMBOL_GPL drivers/ata/libata 0x74541077 ata_pci_bmdma_init +EXPORT_SYMBOL_GPL drivers/ata/libata 0x78043289 ata_port_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7939a5ac ata_timing_compute +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7af4b4f4 ata_sff_dumb_qc_prep +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7c94f0f5 sata_pmp_qc_defer_cmd_switch +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7da5f15b ata_sff_irq_clear +EXPORT_SYMBOL_GPL drivers/ata/libata 0x80b3b666 ata_base_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x816f4930 ata_port_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0x82c9cdac sata_sff_hardreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x85a2edd8 ata_host_alloc_pinfo +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8796a8ce sata_link_debounce +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8a15a35a ata_bmdma_status +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8b060946 ata_bus_reset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8b752ac1 ata_tf_to_fis +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8eccfb83 ata_sff_exec_command +EXPORT_SYMBOL_GPL drivers/ata/libata 0x90f176cc ata_eh_thaw_port +EXPORT_SYMBOL_GPL drivers/ata/libata 0x9323f870 ata_sas_port_destroy +EXPORT_SYMBOL_GPL drivers/ata/libata 0x93a1cdfd ata_port_pbar_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0x942b7fe0 ata_pci_sff_init_one +EXPORT_SYMBOL_GPL drivers/ata/libata 0x94a68723 ata_scsi_slave_destroy +EXPORT_SYMBOL_GPL drivers/ata/libata 0x94dc62d2 ata_scsi_ioctl +EXPORT_SYMBOL_GPL drivers/ata/libata 0x962d0578 ata_eh_qc_retry +EXPORT_SYMBOL_GPL drivers/ata/libata 0x96ae0f12 ata_acpi_stm +EXPORT_SYMBOL_GPL drivers/ata/libata 0x979ee78b sata_async_notification +EXPORT_SYMBOL_GPL drivers/ata/libata 0x98171c56 ata_sff_qc_issue +EXPORT_SYMBOL_GPL drivers/ata/libata 0x99698439 ata_std_error_handler +EXPORT_SYMBOL_GPL drivers/ata/libata 0x9c52baf8 ata_sff_prereset +EXPORT_SYMBOL_GPL drivers/ata/libata 0xa2cc772e ata_host_suspend +EXPORT_SYMBOL_GPL drivers/ata/libata 0xa471cd81 ata_link_offline +EXPORT_SYMBOL_GPL drivers/ata/libata 0xa81bf36f ata_pci_bmdma_clear_simplex +EXPORT_SYMBOL_GPL drivers/ata/libata 0xa9499cb5 ata_sff_post_internal_cmd +EXPORT_SYMBOL_GPL drivers/ata/libata 0xa9d416cc ata_bmdma_setup +EXPORT_SYMBOL_GPL drivers/ata/libata 0xabf82d91 ata_sff_check_status +EXPORT_SYMBOL_GPL drivers/ata/libata 0xad540078 ata_host_activate +EXPORT_SYMBOL_GPL drivers/ata/libata 0xad55f0aa ata_sff_hsm_move +EXPORT_SYMBOL_GPL drivers/ata/libata 0xb6aeb661 ata_id_c_string +EXPORT_SYMBOL_GPL drivers/ata/libata 0xb78b3e53 ata_acpi_gtm_xfermask +EXPORT_SYMBOL_GPL drivers/ata/libata 0xb8804885 ata_bmdma_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0xb8a32d9b ata_port_schedule_eh +EXPORT_SYMBOL_GPL drivers/ata/libata 0xbb94d6ae ata_sff_qc_prep +EXPORT_SYMBOL_GPL drivers/ata/libata 0xbe1887e4 ata_unpack_xfermask +EXPORT_SYMBOL_GPL drivers/ata/libata 0xbf344439 ata_std_qc_defer +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc428068d sata_deb_timing_long +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc48b7ccf ata_mode_string +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc673e23e ata_scsi_change_queue_depth +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc697e005 sata_pmp_error_handler +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc7f77d53 sata_scr_write_flush +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc94bad0d sata_set_spd +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc9b73355 ata_acpi_cbl_80wire +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc9c83713 ata_cable_sata +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcccfb2fa sata_deb_timing_hotplug +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcf683d94 ata_std_prereset +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd03ec93a ata_sff_dev_classify +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd4fc8440 __ata_ehi_push_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd5c64f2f ata_pio_need_iordy +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd60286c3 ata_do_dev_read_id +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd7d81c11 ata_bmdma_stop +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd84cd7f4 ata_timing_find_mode +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd908d00a dev_attr_link_power_management_policy +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd92d4b75 ata_host_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd9de796b ata_dev_pair +EXPORT_SYMBOL_GPL drivers/ata/libata 0xddf48005 ata_qc_complete +EXPORT_SYMBOL_GPL drivers/ata/libata 0xde7d96d5 sata_std_hardreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0xdf3022b2 ata_sff_interrupt +EXPORT_SYMBOL_GPL drivers/ata/libata 0xe1035e05 ata_ehi_clear_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0xe30baa6d ata_sff_irq_on +EXPORT_SYMBOL_GPL drivers/ata/libata 0xe4046baa ata_link_abort +EXPORT_SYMBOL_GPL drivers/ata/libata 0xe49ff3b0 ata_wait_register +EXPORT_SYMBOL_GPL drivers/ata/libata 0xe5bef437 sata_scr_read +EXPORT_SYMBOL_GPL drivers/ata/libata 0xe897c937 ata_std_bios_param +EXPORT_SYMBOL_GPL drivers/ata/libata 0xe93facde ata_sas_port_init +EXPORT_SYMBOL_GPL drivers/ata/libata 0xea418e0f atapi_cmd_type +EXPORT_SYMBOL_GPL drivers/ata/libata 0xeb75f0d3 ata_sff_host_intr +EXPORT_SYMBOL_GPL drivers/ata/libata 0xed931ed9 ata_do_eh +EXPORT_SYMBOL_GPL drivers/ata/libata 0xef2fa0f1 sata_pmp_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0xef30f48b ata_sas_port_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf08b8f60 ata_dummy_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf2223c18 ata_host_register +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf231be14 ata_wait_after_reset +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf3d5cc13 ata_timing_merge +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf8f3a0fb ata_ratelimit +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf9ca3160 ata_id_xfermask +EXPORT_SYMBOL_GPL drivers/ata/libata 0xfb8ac227 ata_qc_complete_multiple +EXPORT_SYMBOL_GPL drivers/ata/libata 0xfdb7d69a ata_cable_80wire +EXPORT_SYMBOL_GPL drivers/ata/libata 0xfec768ab pci_test_config_bits +EXPORT_SYMBOL_GPL drivers/ata/pata_sis 0x67898120 sis_info133_for_sata +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x02ff9464 cfag12864b_isinited +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x0ecb2e5d cfag12864b_disable +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x305dc3c6 cfag12864b_isenabled +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x3389f926 cfag12864b_enable +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x9522a342 cfag12864b_getrate +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0xc48e9d95 cfag12864b_buffer +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0x14102f23 ks0108_displaystate +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0x48a70518 ks0108_writedata +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0x4f506333 ks0108_startline +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0x6edae968 ks0108_isinited +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0xbf4774db ks0108_writecontrol +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0xedde6df2 ks0108_page +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0xfee8ef7b ks0108_address +EXPORT_SYMBOL_GPL drivers/char/agp/agpgart 0x4843a0df agp_add_bridge +EXPORT_SYMBOL_GPL drivers/char/agp/agpgart 0xb9007180 agp_remove_bridge +EXPORT_SYMBOL_GPL drivers/char/agp/agpgart 0xd6feefa5 agp_num_entries +EXPORT_SYMBOL_GPL drivers/char/agp/agpgart 0xe089cfcc agp_memory_reserved +EXPORT_SYMBOL_GPL drivers/char/scx200_gpio 0xca5b936b scx200_gpio_ops +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x033e5798 tpm_show_owned +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x035cbe82 tpm_show_pubek +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x08a8bb37 tpm_pm_suspend +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x0cffc2fb tpm_pm_resume +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x1384fdb3 tpm_register_hardware +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x157eed5f tpm_open +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x17f860c0 tpm_get_timeouts +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x19804d7c tpm_release +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x24e3062f tpm_show_pcrs +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x31972ce3 tpm_show_temp_deactivated +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x343e0119 tpm_remove_hardware +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x45bfffbf tpm_store_cancel +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x4d0bda60 tpm_calc_ordinal_duration +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x5050b4bd tpm_continue_selftest +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x566fd472 tpm_show_enabled +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x56a70ff0 tpm_write +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x572c962c tpm_show_caps +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x591e4a2f tpm_read +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xa55f2d63 tpm_show_caps_1_2 +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xd8f1ef2f tpm_show_active +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xfda10afe tpm_gen_interrupt +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm_bios 0x3e158d9d tpm_bios_log_teardown +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm_bios 0xd4085aac tpm_bios_log_setup +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x07146b6f cpufreq_frequency_table_verify +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x2f47d8c7 cpufreq_frequency_get_table +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x5dcfc85f cpufreq_frequency_table_target +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x5e9329f1 cpufreq_freq_attr_scaling_available_freqs +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x706b3a33 cpufreq_frequency_table_get_attr +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x7ae1ae8e cpufreq_frequency_table_put_attr +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0xa26344c7 cpufreq_frequency_table_cpuinfo +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x097ac319 edac_mc_handle_ce +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x2be4e726 edac_mc_handle_ue +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x48347fb7 edac_mc_del_mc +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x4c76371a edac_pci_alloc_ctl_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x54b71090 edac_mc_find_csrow_by_page +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x616e6159 edac_mc_handle_ue_no_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x6890a6aa edac_pci_handle_npe +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x69827f26 edac_device_handle_ue +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x7892e765 edac_pci_free_ctl_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x815fa3c9 edac_mc_handle_ce_no_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x9bbec774 edac_pci_reset_delay_period +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x9bd3d301 edac_pci_create_generic_ctl +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xabddaeb7 edac_mc_add_mc +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xadc2d3b5 edac_pci_add_device +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xaef59279 edac_device_add_device +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xbc4deeb1 edac_mc_free +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xbe29a24c edac_pci_release_generic_ctl +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xc7517508 edac_pci_del_device +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xc784743c edac_device_free_ctl_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xcd84e04f edac_mc_alloc +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xe8ffd55e edac_device_handle_ce +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xf141a337 edac_device_alloc_ctl_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xfbc0e1b3 edac_pci_handle_pe +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xfd88ca3e edac_device_del_device +EXPORT_SYMBOL_GPL drivers/hid/hid 0x0176ba16 hid_parse_report +EXPORT_SYMBOL_GPL drivers/hid/hid 0x02276bb2 hid_set_field +EXPORT_SYMBOL_GPL drivers/hid/hid 0x030f0aa9 hidinput_connect +EXPORT_SYMBOL_GPL drivers/hid/hid 0x2e6ff3ed hidinput_disconnect +EXPORT_SYMBOL_GPL drivers/hid/hid 0x2eff8ef6 hidinput_find_field +EXPORT_SYMBOL_GPL drivers/hid/hid 0x7040a57a hidraw_report_event +EXPORT_SYMBOL_GPL drivers/hid/hid 0x7979ade0 hidinput_report_event +EXPORT_SYMBOL_GPL drivers/hid/hid 0xe4c30556 hid_free_device +EXPORT_SYMBOL_GPL drivers/hid/hid 0xe7032c45 hidraw_disconnect +EXPORT_SYMBOL_GPL drivers/hid/hid 0xf21f8e13 hid_input_report +EXPORT_SYMBOL_GPL drivers/hid/hid 0xf54f2388 hid_output_report +EXPORT_SYMBOL_GPL drivers/hid/hid 0xf562822c hidraw_connect +EXPORT_SYMBOL_GPL drivers/hid/usbhid/usbhid 0x01fd453e usbhid_lookup_quirk +EXPORT_SYMBOL_GPL drivers/hid/usbhid/usbhid 0x6437cf4d hiddev_hid_event +EXPORT_SYMBOL_GPL drivers/i2c/busses/i2c-nforce2 0x63af1ea4 nforce2_smbus +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0x070d08f2 i2c_add_numbered_adapter +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0x4bb93020 i2c_new_dummy +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0x6a4f7df8 i2c_new_probed_device +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0xd895751b i2c_new_device +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0xdc2be8cd i2c_bus_type +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0xe2a67a08 i2c_unregister_device +EXPORT_SYMBOL_GPL drivers/ieee1394/ieee1394 0x3d742152 hpsb_config_rom_ip1394_add +EXPORT_SYMBOL_GPL drivers/ieee1394/ieee1394 0xb0b2bffc hpsb_config_rom_ip1394_remove +EXPORT_SYMBOL_GPL drivers/ieee1394/ieee1394 0xec8d18cf hpsb_disable_irm +EXPORT_SYMBOL_GPL drivers/input/ff-memless 0xd5626bf8 input_ff_create_memless +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x04101bac wm97xx_read_aux_adc +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x0f2fe222 wm97xx_config_gpio +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x137328e1 wm9713_codec +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x6228a97e wm97xx_reg_read +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x73c323e4 wm97xx_unregister_mach_ops +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x7505cf92 wm97xx_set_suspend_mode +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x7e58fe9b wm97xx_register_mach_ops +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xba3f973c wm97xx_get_gpio +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xc2673525 wm9705_codec +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xc66d2125 wm97xx_set_gpio +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xde596eb5 wm97xx_reg_write +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xdfd9287f wm9712_codec +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x024b4846 gigaset_initcs +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x0425a56d gigaset_start +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x177557b5 gigaset_initdriver +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x1c1cfbc3 gigaset_if_receive +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x1c3cbd0d gigaset_m10x_send_skb +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x1d52be5f gigaset_add_event +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x30095ea1 gigaset_freecs +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x38c9fd6a gigaset_freedriver +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x454aa44f gigaset_debuglevel +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x4e792275 gigaset_dbg_buffer +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x54aaa1a8 gigaset_fill_inbuf +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x5f576b84 gigaset_m10x_input +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x6318281a gigaset_skb_sent +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x7c0ae806 gigaset_blockdriver +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x822f3524 gigaset_handle_modem_response +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x94e25ad2 gigaset_stop +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0xfb27f56c gigaset_shutdown +EXPORT_SYMBOL_GPL drivers/leds/led-class 0x101a6020 led_classdev_suspend +EXPORT_SYMBOL_GPL drivers/leds/led-class 0x435e4e53 led_classdev_register +EXPORT_SYMBOL_GPL drivers/leds/led-class 0x6fefed35 led_classdev_unregister +EXPORT_SYMBOL_GPL drivers/leds/led-class 0xbec5e11f led_classdev_resume +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0x1cb0c8c1 dm_disk +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0x253f6d1d dm_path_uevent +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0x3f349fc5 dm_put +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0x49a939cc dm_send_uevents +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0x5d25e7e2 dm_set_device_limits +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0x944eac9e dm_noflush_suspending +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0x9d1aaf84 dm_device_name +EXPORT_SYMBOL_GPL drivers/md/dm-multipath 0x77c837b2 dm_unregister_path_selector +EXPORT_SYMBOL_GPL drivers/md/dm-multipath 0xc9f69e65 dm_register_path_selector +EXPORT_SYMBOL_GPL drivers/md/md-mod 0x962a74c7 md_do_sync +EXPORT_SYMBOL_GPL drivers/md/md-mod 0xcddb2382 md_new_event +EXPORT_SYMBOL_GPL drivers/md/md-mod 0xda2acc6c md_allow_write +EXPORT_SYMBOL_GPL drivers/md/md-mod 0xf9e5cb85 sync_page_io +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x04662e0f ir_codes_fusionhdtv_mce +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x07e92917 ir_codes_avermedia_a16d +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x083661f9 ir_codes_avertv_303 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x088631b9 ir_codes_behold +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x1cb148f5 ir_extract_bits +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x2456e513 ir_decode_pulsedistance +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x2a4852cc ir_codes_dntv_live_dvb_t +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x2af1a608 ir_codes_proteus_2309 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x306a2095 ir_input_keydown +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x3811daea ir_codes_manli +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x43c89ef4 ir_decode_biphase +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x45b08f68 ir_codes_pinnacle_grey +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x4740e7a3 ir_codes_empty +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x4ea698a2 ir_codes_purpletv +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x55338dda ir_codes_pixelview_new +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x589cad50 ir_codes_apac_viewcomp +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x5db13554 ir_codes_encore_enltv +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x611bb4f8 ir_input_nokey +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6606596a ir_rc5_timer_keyup +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6adc476d ir_codes_powercolor_real_angel +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6aefdbea ir_codes_npgtech +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6b87c69d ir_codes_iodata_bctv7e +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6ca27b55 ir_input_init +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6d6511e7 ir_dump_samples +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6e2a1870 ir_codes_adstech_dvb_t_pci +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x7277973d ir_codes_pctv_sedna +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x75e89cc3 ir_codes_flydvb +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x772a30a2 ir_codes_nebula +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x85d37490 ir_codes_dntv_live_dvbt_pro +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x89cc1189 ir_codes_winfast +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x902a3cd2 ir_codes_hauppauge_new +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x933d0bb3 ir_codes_msi_tvanywhere +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x9451e232 ir_codes_behold_columbus +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x96470cab ir_codes_cinergy +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xb1f4eb35 ir_codes_avermedia_dvbt +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xb6cd4666 ir_codes_eztv +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xbb08d146 ir_codes_msi_tvanywhere_plus +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xbdce6594 ir_codes_tt_1500 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xc1fea0c1 ir_codes_pv951 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xc42bd037 ir_codes_budget_ci_old +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xc6c5a7a1 ir_codes_em_terratec +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xd1e0258a ir_codes_flyvideo +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xd55e6891 ir_codes_gotview7135 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xd9c7f010 ir_codes_rc5_tv +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xdaa041ad ir_codes_cinergy_1400 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xdfcf23df ir_codes_norwood +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xee2f5e0e ir_codes_pinnacle_pctv_hd +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xf07533a1 ir_codes_videomate_tv_pvr +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xf0fc9374 ir_codes_avermedia +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xf2b421aa ir_codes_genius_tvgo_a11mce +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xf4f7a4d6 ir_rc5_timer_end +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xfa177653 ir_codes_pixelview +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xfb981300 ir_codes_pinnacle_color +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xfc54a5cd ir_codes_asus_pc39 +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x079bbdb8 saa7146_unregister_extension +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x439127d6 saa7146_pgtable_alloc +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x444f850b saa7146_register_extension +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x5f6bba41 saa7146_i2c_adapter_prepare +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x7215d922 saa7146_pgtable_free +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x7697cb81 saa7146_vmalloc_build_pgtable +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xa671b77f saa7146_vfree_destroy_pgtable +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xc1ec0450 saa7146_setgpio +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xc98faf20 saa7146_devices_lock +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xcf683cf2 saa7146_devices +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xd6ff8917 saa7146_wait_for_debi_done +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xe3cd9b5c saa7146_debug +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xfbbac092 saa7146_pgtable_build_single +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0x6831fb3d saa7146_stop_preview +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0x6ff2ca6e saa7146_start_preview +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0x751b8c19 saa7146_vv_release +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0x8940b600 saa7146_vv_init +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0xae419795 saa7146_register_device +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0xc14f8fc8 saa7146_unregister_device +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0xc8815acf saa7146_set_hps_source_and_sync +EXPORT_SYMBOL_GPL drivers/media/common/tuners/mt20xx 0x236b6573 microtune_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/mxl5007t 0xa88648aa mxl5007t_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda18271 0x7972db7e tda18271_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda827x 0x8fd66a0d tda827x_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda8290 0x11ffaa60 tda829x_probe +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda8290 0xeeb20235 tda829x_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda9887 0x308fe1f4 tda9887_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tea5761 0x6e20e991 tea5761_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tea5761 0xb238909c tea5761_autodetection +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tea5767 0x240465d7 tea5767_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tea5767 0xe9860395 tea5767_autodetection +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tuner-simple 0x6a90db95 simple_tuner_attach +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x0cbb4edb ttpci_budget_debiwrite +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x0ecbb72b ttpci_budget_deinit +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x5bb83fd6 ttpci_budget_irq10_handler +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x7948c222 budget_debug +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x9cb9bd76 ttpci_budget_debiread +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0xb13c835f ttpci_budget_set_video_port +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0xcd2e4658 ttpci_budget_init +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0xd1f416a2 ttpci_budget_init_hooks +EXPORT_SYMBOL_GPL drivers/media/video/compat_ioctl32 0xebdcec06 v4l_compat_ioctl32 +EXPORT_SYMBOL_GPL drivers/media/video/cx88/cx88xx 0x7c57cec4 cx88_setup_xc3028 +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0x3e66a183 em28xx_set_mode +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0x75c518f3 em28xx_uninit_isoc +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0x936a1bf7 em28xx_init_isoc +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0xb2cc727b em28xx_audio_analog_set +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0xd22c24eb em28xx_tuner_callback +EXPORT_SYMBOL_GPL drivers/media/video/saa7134/saa7134 0x40a5670a saa7134_queryctrl +EXPORT_SYMBOL_GPL drivers/media/video/saa7134/saa7134 0xbbc8de02 saa7134_ts_qops +EXPORT_SYMBOL_GPL drivers/media/video/saa7134/saa7134 0xe2f4f413 saa7134_s_ctrl_internal +EXPORT_SYMBOL_GPL drivers/media/video/saa7134/saa7134 0xf77004c7 saa7134_g_ctrl_internal +EXPORT_SYMBOL_GPL drivers/media/video/v4l2-int-device 0x92888e75 v4l2_int_device_unregister +EXPORT_SYMBOL_GPL drivers/media/video/v4l2-int-device 0xef9659ce v4l2_int_device_register +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x0f34cf54 videobuf_queue_cancel +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x1b277f05 videobuf_queue_core_init +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x1e28e91d videobuf_mmap_free +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x2b5a9462 videobuf_streamon +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x4171ba49 videobuf_mmap_mapper +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x4176bf46 __videobuf_mmap_setup +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x4614e826 videobuf_iolock +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x467bad21 videobuf_reqbufs +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x4efcef03 videobuf_streamoff +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x53d0165e videobuf_cgmbuf +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x5f0bf299 videobuf_poll_stream +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x6e576969 videobuf_stop +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x708f3888 videobuf_read_stream +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x778aabe6 videobuf_queue_is_busy +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x7a423d30 videobuf_mmap_setup +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x84f7e126 videobuf_next_field +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x863360c9 videobuf_dqbuf +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x8f057f7a videobuf_qbuf +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xa1e61b38 videobuf_read_one +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xa28f7185 videobuf_queue_to_vmalloc +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xb62a6db9 videobuf_waiton +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xc953c4a1 videobuf_alloc +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xd124d826 videobuf_read_stop +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xe4e380d4 videobuf_querybuf +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xf19af61b videobuf_read_start +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-contig 0x8a612c33 videobuf_to_dma_contig +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-contig 0xb1bf6998 videobuf_queue_dma_contig_init +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-contig 0xf8d3a596 videobuf_dma_contig_free +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x1b618a66 videobuf_dma_map +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x441b1eb6 videobuf_dma_sync +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x5dc89941 videobuf_queue_sg_init +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x69138d3c videobuf_to_dma +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x7c1619bc videobuf_sg_dma_map +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x82f08f95 videobuf_dma_unmap +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x839a2313 videobuf_dma_init_user +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x933dfb43 videobuf_vmalloc_to_sg +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0xa825c75b videobuf_sg_alloc +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0xc6879e34 videobuf_dma_init +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0xc6c878bf videobuf_dma_free +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0xdf96315e videobuf_dma_init_overlay +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0xe831d64f videobuf_dma_init_kernel +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0xfb61d611 videobuf_sg_dma_unmap +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-vmalloc 0x139fff32 videobuf_vmalloc_free +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-vmalloc 0x620680d5 videobuf_to_vmalloc +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-vmalloc 0xf10f9c54 videobuf_queue_vmalloc_init +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0x23ee6853 sm501_unit_power +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0x50eec631 sm501_modify_reg +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0x89455343 sm501_find_clock +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0xa353fe77 sm501_misc_control +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0xff78668b sm501_set_clock +EXPORT_SYMBOL_GPL drivers/misc/eeprom_93cx6 0x2df115d4 eeprom_93cx6_multiread +EXPORT_SYMBOL_GPL drivers/misc/eeprom_93cx6 0x63d14d2f eeprom_93cx6_read +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0x2a842dfa enclosure_register +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0x339fc797 enclosure_unregister +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0x42801409 enclosure_remove_device +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0x573cdf34 enclosure_find +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0x7733a083 enclosure_for_each_device +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0xc10c71e9 enclosure_add_device +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0xdc2306b9 enclosure_component_register +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x0a1c2315 sdio_f0_writeb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x26c06450 sdio_writew +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x27d53cec sdio_f0_readb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x2f327785 sdio_unregister_driver +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x31313b9e sdio_claim_irq +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x346da630 sdio_writel +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x51553595 sdio_memcpy_fromio +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x57ae950d sdio_writesb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x5ee6e5a9 sdio_set_block_size +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x63511ea8 sdio_align_size +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x6a8dd594 sdio_readb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x752e64af sdio_readw +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x875a6694 sdio_readl +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x88f78617 sdio_enable_func +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x8e9236b1 sdio_disable_func +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x9283f4bd sdio_memcpy_toio +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x93ef41b0 sdio_register_driver +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xb41af3aa sdio_release_host +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xc6f23b7f sdio_release_irq +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xdb9f186d sdio_writeb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xf381b1cc sdio_claim_host +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xf9399fba sdio_readsb +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0x223812bf sdhci_add_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0x27480bb8 sdhci_alloc_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0x46b816ea sdhci_suspend_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0xd5863349 sdhci_remove_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0xd91cff1b sdhci_resume_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0xdd854ed6 sdhci_free_host +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0001 0x1c786555 cfi_cmdset_0200 +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0001 0x7771a784 cfi_cmdset_0003 +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0001 0xee35de08 cfi_cmdset_0001 +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0002 0x3bd39b42 cfi_cmdset_0002 +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0020 0x460069bc cfi_cmdset_0020 +EXPORT_SYMBOL_GPL drivers/mtd/devices/doc2000 0x94b59ff3 DoC2k_init +EXPORT_SYMBOL_GPL drivers/mtd/devices/doc2001 0xe06bbfe3 DoCMil_init +EXPORT_SYMBOL_GPL drivers/mtd/devices/doc2001plus 0xcfac3f5b DoCMilPlus_init +EXPORT_SYMBOL_GPL drivers/mtd/devices/docecc 0x45937659 doc_decode_ecc +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x001ab492 del_mtd_device +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x14c3f0b5 get_mtd_device_nm +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x1c3c1c40 deregister_mtd_parser +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x1f0229d5 register_mtd_parser +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x39313253 default_mtd_writev +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x3f6ce919 kill_mtd_super +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x599a78fb get_mtd_device +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x5c350faf parse_mtd_partitions +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x889b6e05 get_sb_mtd +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x8d7a9438 unregister_mtd_user +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xa2692988 put_mtd_device +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xcb20e8d1 mtd_erase_callback +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xd0dd61c5 add_mtd_device +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xef18154d register_mtd_user +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xeff64be1 mtd_table_mutex +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xf3245eee mtd_table +EXPORT_SYMBOL_GPL drivers/mtd/mtd_blkdevs 0x44a83cd2 register_mtd_blktrans +EXPORT_SYMBOL_GPL drivers/mtd/mtd_blkdevs 0x856398cc deregister_mtd_blktrans +EXPORT_SYMBOL_GPL drivers/mtd/mtd_blkdevs 0x8cfae41f add_mtd_blktrans_dev +EXPORT_SYMBOL_GPL drivers/mtd/mtd_blkdevs 0xff8c5362 del_mtd_blktrans_dev +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0x50f71ea9 nand_scan_tail +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0x522fe8b5 nand_scan_ident +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0x90b5b39e nand_wait_ready +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0xac7efadd nand_scan +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0xd81057bf nand_release +EXPORT_SYMBOL_GPL drivers/mtd/onenand/onenand 0x0729cd44 onenand_release +EXPORT_SYMBOL_GPL drivers/mtd/onenand/onenand 0x97d91a8b onenand_scan +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x059c5fee ubi_get_volume_info +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x183da2a8 ubi_is_mapped +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x28acee15 ubi_leb_read +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x42801d20 ubi_sync +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x4e8ed4a9 ubi_leb_map +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x51578335 ubi_leb_unmap +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x52e18654 ubi_leb_write +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x5f87fe64 ubi_leb_erase +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x76094253 ubi_open_volume_nm +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x93a5b0a7 ubi_open_volume +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xb80a43ec ubi_close_volume +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xbc505df4 ubi_get_device_info +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xfe14c855 ubi_leb_change +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x0504a5ca mlx4_srq_query +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x15b45de5 mlx4_mr_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x1a0eb5c4 mlx4_srq_arm +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x1bc44bfe mlx4_fmr_enable +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x1f3984c4 mlx4_srq_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x1f39db4b mlx4_db_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x2d8098b1 mlx4_CLOSE_PORT +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x2f502628 mlx4_register_interface +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x3052ceff mlx4_qp_remove +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x31474c21 mlx4_SYNC_TPT +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x34ad7bba mlx4_mr_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x3c56667f mlx4_qp_query +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x3c94ce97 mlx4_srq_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x40bf391b mlx4_map_phys_fmr +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x40da4083 mlx4_cq_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x5f1be58e mlx4_write_mtt +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x6e26647c mlx4_qp_to_ready +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x7204ef85 mlx4_mtt_init +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x7457f705 mlx4_pd_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x745a033a __mlx4_cmd +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x760352b3 mlx4_fmr_unmap +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x796b5a53 mlx4_uar_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x7a248c74 mlx4_unregister_interface +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x7d23b5d9 mlx4_cq_resize +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x817d0458 mlx4_INIT_PORT +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x86add686 mlx4_qp_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x8d9fd7bd mlx4_alloc_cmd_mailbox +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x8fd20ae3 mlx4_cq_modify +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x9b519851 mlx4_fmr_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xb45ac3a3 mlx4_buf_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xb49a0794 mlx4_fmr_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xb7d8a5b8 mlx4_uar_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xb94d957a mlx4_db_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xbbaac436 mlx4_free_cmd_mailbox +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xc7f6f900 mlx4_qp_modify +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xce8fbebf mlx4_pd_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xd2b131c7 mlx4_mtt_addr +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xd664c308 mlx4_mr_enable +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xd91e79d5 mlx4_free_hwq_res +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xdf4235a4 mlx4_multicast_attach +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xe6680ae6 mlx4_qp_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xef57b85a mlx4_buf_write_mtt +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xf22be5b1 mlx4_alloc_hwq_res +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xf6e08fd4 mlx4_mtt_cleanup +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xf88e9cf4 mlx4_multicast_detach +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xfac7186c mlx4_buf_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xfd8baccd mlx4_cq_free +EXPORT_SYMBOL_GPL drivers/net/usb/cdc_ether 0x7af8db7e usbnet_generic_cdc_bind +EXPORT_SYMBOL_GPL drivers/net/usb/cdc_ether 0x9cae7673 usbnet_cdc_unbind +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0x03f263dc rndis_tx_fixup +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0x3a03ea11 generic_rndis_bind +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0xa1cf8d9f rndis_command +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0xbf6f0770 rndis_unbind +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0xf00adb03 rndis_rx_fixup +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0xfacb62af rndis_status +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x23d6e6db usbnet_resume +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x41d714c8 usbnet_get_msglevel +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x4d2d31b7 usbnet_set_settings +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x5d596f20 usbnet_suspend +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x5e67209c usbnet_nway_reset +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x64b3c276 usbnet_skb_return +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x8d666079 usbnet_unlink_rx_urbs +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x92fd1108 usbnet_set_msglevel +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xb441047d usbnet_get_link +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xc8dd582f usbnet_probe +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xd229ead5 usbnet_defer_kevent +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xd74d6140 usbnet_get_settings +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xd8e08481 usbnet_get_drvinfo +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xe6d49efe usbnet_disconnect +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xe81ed518 usbnet_get_endpoints +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x025b2dae lbs_cmd_copyback +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x22380417 lbs_notify_command_response +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x334365ca lbs_queue_event +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x5b6a3b4c lbs_stop_card +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x5ff954b2 lbs_send_tx_feedback +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x601a985a lbs_add_card +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x740c2ed7 lbs_process_rxed_packet +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x7ccea019 lbs_suspend +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x81ed1a43 __lbs_cmd +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x90659e5e lbs_resume +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xaa06e5dd lbs_host_to_card_done +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xb4aa78d8 lbs_cmd_802_11_rate_adapt_rateset +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xc3106138 lbs_remove_card +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xd7669533 lbs_start_card +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xe5888016 lbs_host_sleep_cfg +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xf64277de lbs_debug +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0x008f711f p54_free_common +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0xa24dcb61 p54_parse_eeprom +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0xaa748adb p54_fill_eeprom_readback +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0xae2a49dc p54_init_common +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0xdb5b0820 p54_rx +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0xe19d36d1 p54_parse_firmware +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x1a08831c rt2x00lib_resume +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x1c3a334b rt2x00mac_bss_info_changed +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x264065fa rt2x00mac_stop +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x2d54535d rt2x00lib_beacondone +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x4e84c57a rt2x00mac_configure_filter +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x58289573 rt2x00mac_config_interface +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x590df37c rt2x00mac_get_tx_stats +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x5eec7240 rt2x00mac_tx +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x6ccd43b5 rt2x00mac_get_stats +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x7d5d25f3 rt2x00mac_conf_tx +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x8f0a6d62 rt2x00mac_config +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x8f6e3d9d rt2x00queue_get_queue +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x98f7b8aa rt2x00lib_suspend +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xb5c2bc88 rt2x00lib_rxdone +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xbd320fe7 rt2x00mac_add_interface +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xcaf6ccc7 rt2x00lib_remove_dev +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xd01c5534 rt2x00lib_txdone +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xd2ef15ce rt2x00queue_map_txskb +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xe02eb74f rt2x00mac_remove_interface +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xe3762c22 rt2x00queue_get_entry +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xe492601d rt2x00lib_probe_dev +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xe896083a rt2x00mac_start +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0x021c975f rt2x00pci_initialize +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0x1dd092e7 rt2x00pci_suspend +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0x20ad0f9f rt2x00pci_write_tx_data +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0x2891457d rt2x00pci_remove +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0x422abf46 rt2x00pci_probe +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0x48e7b9c7 rt2x00pci_rxdone +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0x624301c5 rt2x00pci_resume +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0xcb1a377b rt2x00pci_uninitialize +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x06ec64f5 rt2x00usb_disable_radio +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x0890c654 rt2x00usb_uninitialize +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x1ab56dca rt2x00usb_suspend +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x1e4ca5b4 rt2x00usb_kick_tx_queue +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x2e0b0b5f rt2x00usb_disconnect +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x3bb5a66d rt2x00usb_vendor_req_buff_lock +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x46344c0e rt2x00usb_vendor_request_large_buff +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x656831c3 rt2x00usb_vendor_request +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x91591b88 rt2x00usb_resume +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x94c0e09e rt2x00usb_vendor_request_buff +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x9a380c2c rt2x00usb_init_rxentry +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0xa58783f0 rt2x00usb_probe +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0xae40be8f rt2x00usb_initialize +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0xbf8a7402 rt2x00usb_init_txentry +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0xf80b36f2 rt2x00usb_write_tx_data +EXPORT_SYMBOL_GPL drivers/pci/hotplug/acpiphp 0xed011223 acpiphp_register_attention +EXPORT_SYMBOL_GPL drivers/pci/hotplug/acpiphp 0xf417c0bd acpiphp_unregister_attention +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x1ad3b491 acpi_root_bridge +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x2aab9b3a cpci_hp_register_controller +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x6a8441be cpci_hp_start +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x6ad5e754 cpci_hp_unregister_bus +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x8882f851 pci_hp_deregister +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x94ef4d05 cpci_hp_stop +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0xaf67b145 cpci_hp_unregister_controller +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0xbcf80c7b acpi_get_hp_params_from_firmware +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0xc1f57d33 pci_hp_change_slot_info +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0xc56b1a53 pci_hp_register +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0xea8a49a3 cpci_hp_register_bus +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x0aa80077 scsi_dh_activate +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x0d487d07 scsi_dh_detach +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x42d816ea scsi_dh_attach +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x593a36c2 scsi_dh_handler_exist +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x7403f2df scsi_register_device_handler +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0xcf6a514b scsi_unregister_device_handler +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x01874156 iscsi_eh_device_reset +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x0233f349 iscsi_pool_init +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x04bba9d9 iscsi_conn_teardown +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x0cf4d804 iscsi_conn_failure +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x144f506f iscsi_prep_unsolicit_data_pdu +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x2376456a iscsi_complete_pdu +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x36ea56d2 iscsi_queuecommand +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x3c44405b __iscsi_get_task +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x3f0400a5 iscsi_itt_to_ctask +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x41ba1d14 iscsi_pool_free +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x4e8a7575 iscsi_update_cmdsn +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x5f54cd8f iscsi_eh_abort +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x695ecf88 iscsi_host_alloc +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x6b96123a iscsi_conn_start +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x6f132002 iscsi_put_task +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x7014d678 iscsi_verify_itt +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x7989acdf iscsi_host_get_param +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x7add9dd8 iscsi_conn_setup +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x7ea159d0 iscsi_session_setup +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x7f3f3093 iscsi_change_queue_depth +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x8b1aced2 iscsi_requeue_task +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x91c28fd0 __iscsi_complete_pdu +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x985c6e02 iscsi_host_free +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xa570073b iscsi_host_add +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xa60adc92 iscsi_session_get_param +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xa9db6948 iscsi_host_remove +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xb8dd243a iscsi_session_teardown +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xba1b8274 iscsi_set_param +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xc1e1b33e iscsi_eh_host_reset +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xd9c47825 iscsi_conn_send_pdu +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xde57fae1 iscsi_session_recovery_timedout +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xe16dc406 iscsi_suspend_tx +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xeb170278 iscsi_conn_get_param +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xee08c885 iscsi_conn_bind +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xf55bf4d4 iscsi_conn_stop +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xf61e04c8 iscsi_host_set_param +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x003ae359 sas_phy_enable +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x01fdb893 __sas_task_abort +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x0a19fb0b sas_change_queue_type +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x14c6e839 sas_slave_configure +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x193e5d0f sas_request_addr +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x2547d389 sas_unregister_ha +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x2d6d55a2 sas_ssp_task_response +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x2f711c6c sas_bios_param +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x3fee819c sas_ioctl +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x414a30eb sas_domain_release_transport +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x69553213 sas_target_alloc +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x7c51cf3d sas_slave_destroy +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x83793bd5 sas_queuecommand +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x903087dc sas_eh_device_reset_handler +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x9eb36f40 sas_domain_attach_transport +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xb27b4c82 sas_task_abort +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xd4651157 sas_find_local_phy +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xdda0fbcd sas_eh_bus_reset_handler +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xe61be639 sas_phy_reset +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xe68f8971 sas_slave_alloc +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xe81ee3ef sas_register_ha +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xeaf53b5e sas_target_destroy +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xfbab9a44 sas_change_queue_depth +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x0722011a srp_iu_put +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x1e8d0415 srp_target_alloc +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x2b481f28 srp_cmd_queue +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x99c24b67 srp_target_free +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0xae4c8ff0 srp_transfer_data +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0xf9393e48 srp_iu_get +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x0abf5a10 scsi_execute_async +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x0d704330 scsi_queue_work +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x16f500f3 scsi_eh_ready_devs +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x17b35d30 sdev_evt_send +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x26c90ea4 scsi_eh_get_sense +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x35d8c94a sdev_evt_alloc +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x4493a71d scsi_target_unblock +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x48e2a3c6 scsi_bus_type +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x769cde65 scsi_mode_select +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x786719f5 scsi_schedule_eh +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x7e275ea8 scsi_complete_async_scans +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x9dbe975e scsi_nl_sock +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xa2d87dc2 sdev_evt_send_simple +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xb1560b38 scsi_flush_work +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xcd171e12 __scsi_get_command +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xce04c1c5 scsi_internal_device_unblock +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xebd7ddec scsi_target_block +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xf826dbb6 scsi_internal_device_block +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x011e3ef5 scsi_tgt_cmd_to_host +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x2b232124 scsi_tgt_tsk_mgmt_request +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x721898e0 scsi_host_put_command +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x80217ef4 scsi_tgt_it_nexus_create +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0xa3fffc9e scsi_host_get_command +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0xa5335153 scsi_tgt_free_queue +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0xacda4832 scsi_tgt_alloc_queue +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0xcfc48cfe scsi_tgt_it_nexus_destroy +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0xd0008057 scsi_tgt_queue_command +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x1c08aed0 iscsi_scan_finished +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x1f0428d9 iscsi_destroy_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x2a2c1651 iscsi_session_event +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x2ee1e05c iscsi_create_endpoint +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x36136fb6 iscsi_add_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x3d1e27ad iscsi_unblock_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x447cb711 iscsi_free_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x51dbdaab iscsi_unregister_transport +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x5db42ddd iscsi_session_chkready +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x5f4b345a iscsi_destroy_endpoint +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xa16ac379 iscsi_alloc_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xab3ff1f6 iscsi_create_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xaef91112 iscsi_lookup_endpoint +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xbd8df618 iscsi_block_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xd210a397 iscsi_recv_pdu +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xdc3d2fcb iscsi_create_conn +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xdc98f12c iscsi_host_for_each_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xe373ed2b iscsi_destroy_conn +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xee8e28f1 iscsi_conn_error +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xf2ce357a iscsi_remove_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xfcf14f68 iscsi_register_transport +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_spi 0x0ef06974 spi_populate_ppr_msg +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_spi 0xa0c71dac spi_populate_sync_msg +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_spi 0xcffa2aff spi_populate_width_msg +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0x2ade7ae6 srp_attach_transport +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0x948e4fc9 srp_rport_add +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0x97e3926e srp_release_transport +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0xddc6a0e6 srp_rport_del +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0xf3b98b00 srp_remove_host +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0x129d3e71 spi_bitbang_stop +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0x4cf34858 spi_bitbang_start +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0x5adb7707 spi_bitbang_setup +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0x92ebb8cc spi_bitbang_transfer +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0xc40f71f2 spi_bitbang_cleanup +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0xf94a7511 spi_bitbang_setup_transfer +EXPORT_SYMBOL_GPL drivers/uio/uio 0x2282d1eb uio_unregister_device +EXPORT_SYMBOL_GPL drivers/uio/uio 0x99a7b97f uio_event_notify +EXPORT_SYMBOL_GPL drivers/uio/uio 0xb65c0a32 __uio_register_device +EXPORT_SYMBOL_GPL drivers/usb/atm/usbatm 0x4ab17693 usbatm_usb_probe +EXPORT_SYMBOL_GPL drivers/usb/atm/usbatm 0x7b2998f2 usbatm_usb_disconnect +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x02cd0b2e usb_hcd_pci_resume +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x0531d935 usb_get_descriptor +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x06f9dc7a usb_buffer_alloc +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x07194e90 usb_get_dev +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x07359fb3 usb_string +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x0d03ba49 usb_hcd_pci_shutdown +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x0e261dcb usb_hcd_pci_probe +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x0eeaac1c usb_driver_set_configuration +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x0f801a5b usb_altnum_to_altsetting +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x190fc167 usb_mon_register +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x19a304ba usb_disabled +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x1d72074d usb_hcd_unlink_urb_from_ep +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x22ad6417 usb_reset_device +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x244605d8 usb_sg_init +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x249d0af1 usb_unlink_anchored_urbs +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x24a85797 usb_get_intf +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x38f200fd usb_find_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x3ba43a0c usb_sg_cancel +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x3be89d3c usb_register_notify +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x413fc7e9 usb_lock_device_for_reset +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x4ca7ca03 usb_set_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x4f3c1e9e usb_alloc_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x51d7d5d8 usb_hc_died +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x53a2a509 usb_init_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x55a31db7 usb_hcd_pci_remove +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x58c5dff7 usb_hcd_link_urb_to_ep +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x5af20778 usb_get_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x5b8ad988 usb_hub_tt_clear_buffer +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x5bd3d243 usb_deregister +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x5f64e98d usb_clear_halt +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x5fb69e22 usb_put_dev +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x652a3086 usb_unlink_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x676a2745 usb_store_new_id +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x6af93037 usb_get_current_frame_number +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x6be4359c usb_bulk_msg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x6c045575 usb_buffer_map_sg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x6c502efd usb_driver_claim_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x6c516984 usb_buffer_free +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x6ca9476b usb_submit_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x6dce94bf usb_bus_list_lock +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x743aee39 usb_hcd_poll_rh_status +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x748baebe usb_create_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x74bfedd1 usb_unanchor_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x76dd7ed0 usb_hcd_giveback_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x79eea104 usb_reset_configuration +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x7e64181d usb_calc_bus_time +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x86b10394 ehci_cf_port_reset_rwsem +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x89dbc47d usb_free_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x8ae7d51b usb_get_status +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x91d63719 usb_remove_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x92f6cc3b usb_register_dev +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x944be4cc usb_match_id +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x9924c496 __usb_get_extra_descriptor +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x99619c3f usb_register_device_driver +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x9b859bb8 usb_sg_wait +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xa332c814 usb_control_msg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xa8815b17 usb_hcd_resume_root_hub +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xa8969fb8 usb_autopm_set_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xa99e1ecf usb_hcd_platform_shutdown +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xabea3ffe usb_kill_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xace5c0fc usb_bus_list +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xad55cdfc usb_autopm_put_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xb0968a00 usb_register_driver +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xb4a3a768 usb_ifnum_to_if +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xbc3a242f usb_wait_anchor_empty_timeout +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xbe25ba3b usb_autopm_get_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xc03eefdd usb_driver_release_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xc0cac656 usb_put_intf +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xc17515d7 usb_hcds_loaded +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xc311e28e usb_buffer_unmap_sg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xc72edc7f usb_get_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xca1daff4 usb_hcd_pci_suspend +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xcc4ad095 usb_put_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xd13ac177 usb_interrupt_msg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xd6fed7bf usb_ep0_reinit +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xdf9eaf39 usb_anchor_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xdfd24c18 usb_hcd_check_unlink_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xe3875d2a usb_kill_anchored_urbs +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xe9587909 usb_unregister_notify +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xeb1fb7f8 usb_add_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xec5aad3a usb_deregister_dev +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xf8dd0018 usb_match_one_id +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xfb2541c3 usb_deregister_device_driver +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xfb4935ae usb_root_hub_lost_power +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xfed11ed1 usb_mon_deregister +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x03150901 usb_ftdi_elan_edset_output +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x0e74f153 usb_ftdi_elan_edset_input +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x32ac95a1 usb_ftdi_elan_edset_flush +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x3f06c55c usb_ftdi_elan_edset_setup +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x6055418c usb_ftdi_elan_edset_single +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0xa7449373 usb_ftdi_elan_write_pcimem +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0xb7931317 usb_ftdi_elan_read_pcimem +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0xd7fc9d01 usb_ftdi_elan_edset_empty +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0xec85bfa3 ftdi_elan_gone_away +EXPORT_SYMBOL_GPL drivers/usb/misc/phidget 0x5bfbf2b8 phidget_class +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x147100ff usb_serial_disconnect +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x272be7bf ezusb_writememory +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x609302bd usb_serial_port_softint +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x60b0914e usb_serial_generic_read_bulk_callback +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x6ba477ce usb_serial_generic_write_bulk_callback +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x863c3720 usb_serial_probe +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x8a239e88 usb_serial_generic_open +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0xac1214f3 usb_serial_register +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0xea297116 usb_serial_deregister +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0xf4809bf9 ezusb_set_reset +EXPORT_SYMBOL_GPL drivers/usb/storage/libusual 0x3edad223 usb_usual_clear_present +EXPORT_SYMBOL_GPL drivers/usb/storage/libusual 0x89d4dbaf usb_usual_check_type +EXPORT_SYMBOL_GPL drivers/usb/storage/libusual 0xcd9991a9 usb_usual_set_present +EXPORT_SYMBOL_GPL drivers/usb/storage/libusual 0xde134c69 storage_usb_ids +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x0d5149af ili9320_remove +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x19fe7833 ili9320_resume +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x4c795343 ili9320_suspend +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x550301e6 ili9320_write +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x6983c9fb ili9320_write_regs +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x8339b1f0 ili9320_shutdown +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0xb40ca6ed ili9320_probe_spi +EXPORT_SYMBOL_GPL drivers/video/fb_ddc 0x246215b6 fb_ddc_read +EXPORT_SYMBOL_GPL drivers/video/fb_sys_fops 0x703b9021 fb_sys_read +EXPORT_SYMBOL_GPL drivers/video/fb_sys_fops 0x76779704 fb_sys_write +EXPORT_SYMBOL_GPL drivers/video/sis/sisfb 0x2cef495c sis_malloc_new +EXPORT_SYMBOL_GPL drivers/video/sis/sisfb 0xe4f2e191 sis_free_new +EXPORT_SYMBOL_GPL drivers/video/vermilion/vmlfb 0x016e6c20 vmlfb_unregister_subsys +EXPORT_SYMBOL_GPL drivers/video/vermilion/vmlfb 0x90c018c6 vmlfb_register_subsys +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0x261fa192 unregister_virtio_device +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0x476cefc7 unregister_virtio_driver +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0x9e98f739 virtio_check_driver_offered_feature +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0xb6ae15f8 register_virtio_device +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0xe7b28da8 register_virtio_driver +EXPORT_SYMBOL_GPL drivers/virtio/virtio_ring 0x03c4687d vring_interrupt +EXPORT_SYMBOL_GPL drivers/virtio/virtio_ring 0x45a846b3 vring_del_virtqueue +EXPORT_SYMBOL_GPL drivers/virtio/virtio_ring 0x65495d2c vring_transport_features +EXPORT_SYMBOL_GPL drivers/virtio/virtio_ring 0xcea361be vring_new_virtqueue +EXPORT_SYMBOL_GPL drivers/w1/wire 0x50c66761 w1_write_8 +EXPORT_SYMBOL_GPL drivers/w1/wire 0x7c2f2afb w1_calc_crc8 +EXPORT_SYMBOL_GPL drivers/w1/wire 0x9a5a25aa w1_write_block +EXPORT_SYMBOL_GPL drivers/w1/wire 0xa3ad80c5 w1_reset_bus +EXPORT_SYMBOL_GPL drivers/w1/wire 0xb50662cb w1_read_block +EXPORT_SYMBOL_GPL drivers/w1/wire 0xf1fc3c6b w1_reset_select_slave +EXPORT_SYMBOL_GPL fs/dlm/dlm 0x43c87487 dlm_posix_lock +EXPORT_SYMBOL_GPL fs/dlm/dlm 0x7ca1fb08 dlm_posix_get +EXPORT_SYMBOL_GPL fs/dlm/dlm 0x9321df95 dlm_lock +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xcc20edb7 dlm_posix_unlock +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xcf9f3328 dlm_release_lockspace +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xdc583c08 dlm_unlock +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xdf3c14de dlm_new_lockspace +EXPORT_SYMBOL_GPL fs/exportfs/exportfs 0x151212b9 exportfs_decode_fh +EXPORT_SYMBOL_GPL fs/exportfs/exportfs 0xa12e7d4a exportfs_encode_fh +EXPORT_SYMBOL_GPL fs/fat/fat 0x37701887 fat_add_entries +EXPORT_SYMBOL_GPL fs/fat/fat 0x41b44574 fat_detach +EXPORT_SYMBOL_GPL fs/fat/fat 0x5b9cbd10 fat_search_long +EXPORT_SYMBOL_GPL fs/fat/fat 0x6664a8cd fat_flush_inodes +EXPORT_SYMBOL_GPL fs/fat/fat 0x6ec6f27b fat_alloc_new_dir +EXPORT_SYMBOL_GPL fs/fat/fat 0x7315a013 fat_dir_empty +EXPORT_SYMBOL_GPL fs/fat/fat 0x830cbe95 fat_fill_super +EXPORT_SYMBOL_GPL fs/fat/fat 0x9c5caa77 fat_setattr +EXPORT_SYMBOL_GPL fs/fat/fat 0x9f46109a fat_get_dotdot_entry +EXPORT_SYMBOL_GPL fs/fat/fat 0xb636dcee fat_free_clusters +EXPORT_SYMBOL_GPL fs/fat/fat 0xb68ea16d fat_date_unix2dos +EXPORT_SYMBOL_GPL fs/fat/fat 0xba7e1f62 fat_scan +EXPORT_SYMBOL_GPL fs/fat/fat 0xbd0c2b1c fat_sync_inode +EXPORT_SYMBOL_GPL fs/fat/fat 0xc8dedf84 fat_getattr +EXPORT_SYMBOL_GPL fs/fat/fat 0xc8e1065a fat_remove_entries +EXPORT_SYMBOL_GPL fs/fat/fat 0xe1fca569 fat_attach +EXPORT_SYMBOL_GPL fs/fat/fat 0xe50ba062 fat_fs_panic +EXPORT_SYMBOL_GPL fs/fat/fat 0xee6ae009 fat_build_inode +EXPORT_SYMBOL_GPL fs/gfs2/gfs2 0x44c9defd gfs2_register_lockproto +EXPORT_SYMBOL_GPL fs/gfs2/gfs2 0x5fe597a7 gfs2_unregister_lockproto +EXPORT_SYMBOL_GPL fs/lockd/lockd 0x1a618932 nlmsvc_unlock_all_by_ip +EXPORT_SYMBOL_GPL fs/lockd/lockd 0x7ea76b4f nlmsvc_unlock_all_by_sb +EXPORT_SYMBOL_GPL fs/lockd/lockd 0x9e41a5ef nlmclnt_init +EXPORT_SYMBOL_GPL fs/lockd/lockd 0xb07aaa67 nlmclnt_proc +EXPORT_SYMBOL_GPL fs/lockd/lockd 0xef9d0f60 nlmclnt_done +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x1b89c6ee o2hb_fill_node_map +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x1cb231d0 mlog_not_bits +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x1d747ce3 o2hb_check_node_heartbeating +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x36418553 o2net_send_message +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x388b6c02 o2nm_get_node_by_ip +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x4900035b o2hb_stop_all_regions +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x4d80e1f2 o2hb_setup_callback +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x5ec6aac4 o2nm_get_node_by_num +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x687f6251 mlog_and_bits +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x880ca82b o2hb_unregister_callback +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xa82a8645 o2nm_this_node +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xa87bc9e7 o2nm_configured_node_map +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xa9f5379a o2net_send_message_vec +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xae808bac o2net_register_handler +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xbaeb4700 o2hb_check_node_heartbeating_from_callback +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xd60f2c6c o2hb_check_local_node_heartbeating +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xdcfa81dc o2hb_register_callback +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xe804f888 o2nm_node_get +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xe9e2049f o2nm_node_put +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xf1a5611d o2net_unregister_handler_list +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0x132f3074 dlmlock +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0x5a32b5b9 dlm_register_domain +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0x7a1211f8 dlm_setup_eviction_cb +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xab24085a dlm_unregister_domain +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xb179563b dlm_register_eviction_cb +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xcbc0b1f5 dlm_print_one_lock +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xd7ba575e dlm_errmsg +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xd8fa57a6 dlm_unregister_eviction_cb +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xe39f3a90 dlmunlock +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xfb86b96f dlm_errname +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x0562c415 ocfs2_cluster_this_node +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x0e27f909 ocfs2_dlm_lock +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x21db5b88 ocfs2_cluster_disconnect +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x4a1f6fe9 ocfs2_cluster_connect +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x4d3af7fa ocfs2_cluster_hangup +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x59602db7 ocfs2_stack_glue_register +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x5b14c343 ocfs2_stack_glue_unregister +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x81c85a68 ocfs2_dlm_lock_status +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x91fab465 ocfs2_dlm_lvb +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x963932a3 ocfs2_stack_glue_set_locking_protocol +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0xa7d5c1c0 ocfs2_dlm_unlock +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0xd066711e ocfs2_dlm_dump_lksb +EXPORT_SYMBOL_GPL lib/lzo/lzo_compress 0x56b63670 lzo1x_1_compress +EXPORT_SYMBOL_GPL lib/lzo/lzo_decompress 0xf30fda27 lzo1x_decompress_safe +EXPORT_SYMBOL_GPL lib/reed_solomon/reed_solomon 0x300d7e57 free_rs +EXPORT_SYMBOL_GPL lib/reed_solomon/reed_solomon 0x6fbb3bd9 init_rs_non_canonical +EXPORT_SYMBOL_GPL lib/reed_solomon/reed_solomon 0xabda1e2e decode_rs16 +EXPORT_SYMBOL_GPL lib/reed_solomon/reed_solomon 0xb050f329 init_rs +EXPORT_SYMBOL_GPL net/802/garp 0x239ee75c garp_request_leave +EXPORT_SYMBOL_GPL net/802/garp 0x3364becc garp_request_join +EXPORT_SYMBOL_GPL net/802/garp 0x78d23671 garp_init_applicant +EXPORT_SYMBOL_GPL net/802/garp 0x7e0560fc garp_uninit_applicant +EXPORT_SYMBOL_GPL net/802/garp 0xadb56537 garp_unregister_application +EXPORT_SYMBOL_GPL net/802/garp 0xdb64a2e6 garp_register_application +EXPORT_SYMBOL_GPL net/802/stp 0x470c791f stp_proto_unregister +EXPORT_SYMBOL_GPL net/802/stp 0xa1f64917 stp_proto_register +EXPORT_SYMBOL_GPL net/ax25/ax25 0xac93ae05 ax25_bcast +EXPORT_SYMBOL_GPL net/ax25/ax25 0xaeb7451e ax25_defaddr +EXPORT_SYMBOL_GPL net/ax25/ax25 0xfbf28f07 ax25_register_pid +EXPORT_SYMBOL_GPL net/bluetooth/bluetooth 0xb58578a7 bt_class +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x09c5ed3c tfrc_tx_hist_purge +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x0a487ea5 tfrc_calc_x +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x106fe6d3 tfrc_tx_hist_rtt +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x13496a72 tfrc_lh_interval_add +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x69ec5731 tfrc_tx_hist_add +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x6c252d29 tfrc_calc_x_reverse_lookup +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x902206f0 tfrc_lh_cleanup +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x92285650 tfrc_rx_hist_alloc +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0xaa22b7b4 tfrc_rx_hist_duplicate +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0xb87984e1 tfrc_rx_hist_add_packet +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0xb8e089ae tfrc_rx_hist_sample_rtt +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0xbcf85a63 tfrc_rx_handle_loss +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0xc612a5b6 tfrc_rx_hist_purge +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0xc738068e tfrc_lh_update_i_mean +EXPORT_SYMBOL_GPL net/dccp/dccp 0x03540aaa dccp_rcv_established +EXPORT_SYMBOL_GPL net/dccp/dccp 0x0434eb78 ccid_register +EXPORT_SYMBOL_GPL net/dccp/dccp 0x045da15e dccp_feat_clone +EXPORT_SYMBOL_GPL net/dccp/dccp 0x05fb7199 dccp_connect +EXPORT_SYMBOL_GPL net/dccp/dccp 0x0687c17e dccp_child_process +EXPORT_SYMBOL_GPL net/dccp/dccp 0x0c4000ed dccp_rcv_state_process +EXPORT_SYMBOL_GPL net/dccp/dccp 0x0e9c1eda dccp_reqsk_send_ack +EXPORT_SYMBOL_GPL net/dccp/dccp 0x13bdf201 dccp_destroy_sock +EXPORT_SYMBOL_GPL net/dccp/dccp 0x18d4449c dccp_done +EXPORT_SYMBOL_GPL net/dccp/dccp 0x1bccce53 inet_dccp_listen +EXPORT_SYMBOL_GPL net/dccp/dccp 0x1d99d49a dccp_timestamp +EXPORT_SYMBOL_GPL net/dccp/dccp 0x1e81fcd7 dccp_close +EXPORT_SYMBOL_GPL net/dccp/dccp 0x2b2bbb42 ccid_hc_rx_delete +EXPORT_SYMBOL_GPL net/dccp/dccp 0x2cdebb5e dccp_setsockopt +EXPORT_SYMBOL_GPL net/dccp/dccp 0x32107e06 dccp_insert_option +EXPORT_SYMBOL_GPL net/dccp/dccp 0x36b19207 dccp_insert_option_elapsed_time +EXPORT_SYMBOL_GPL net/dccp/dccp 0x3b3c0b1b dccp_feat_clean +EXPORT_SYMBOL_GPL net/dccp/dccp 0x3c39759d dccp_insert_option_timestamp +EXPORT_SYMBOL_GPL net/dccp/dccp 0x47cbfd0c ccid_unregister +EXPORT_SYMBOL_GPL net/dccp/dccp 0x56ea266a dccp_state_name +EXPORT_SYMBOL_GPL net/dccp/dccp 0x61c90821 dccp_ioctl +EXPORT_SYMBOL_GPL net/dccp/dccp 0x6384aa09 ccid_hc_rx_new +EXPORT_SYMBOL_GPL net/dccp/dccp 0x6d12f1fb ccid_hc_tx_delete +EXPORT_SYMBOL_GPL net/dccp/dccp 0x71a2a639 dccp_feat_confirm_recv +EXPORT_SYMBOL_GPL net/dccp/dccp 0x7a084944 dccp_send_ack +EXPORT_SYMBOL_GPL net/dccp/dccp 0x86be7924 dccp_packet_name +EXPORT_SYMBOL_GPL net/dccp/dccp 0x8b7d8caf dccp_statistics +EXPORT_SYMBOL_GPL net/dccp/dccp 0x8c26990a dccp_send_sync +EXPORT_SYMBOL_GPL net/dccp/dccp 0x8ffe3a63 dccp_create_openreq_child +EXPORT_SYMBOL_GPL net/dccp/dccp 0x9b9151e4 dccp_getsockopt +EXPORT_SYMBOL_GPL net/dccp/dccp 0x9d1ef8cb dccp_set_state +EXPORT_SYMBOL_GPL net/dccp/dccp 0x9d6a3846 dccp_orphan_count +EXPORT_SYMBOL_GPL net/dccp/dccp 0xa07b57eb dccp_poll +EXPORT_SYMBOL_GPL net/dccp/dccp 0xa3b93bfc dccp_make_response +EXPORT_SYMBOL_GPL net/dccp/dccp 0xab2aae5e ccid_new +EXPORT_SYMBOL_GPL net/dccp/dccp 0xaba83571 dccp_parse_options +EXPORT_SYMBOL_GPL net/dccp/dccp 0xb4528421 dccp_recvmsg +EXPORT_SYMBOL_GPL net/dccp/dccp 0xb6cd561a dccp_sample_rtt +EXPORT_SYMBOL_GPL net/dccp/dccp 0xba1381bd dccp_reqsk_init +EXPORT_SYMBOL_GPL net/dccp/dccp 0xbb2c9182 dccp_ctl_make_reset +EXPORT_SYMBOL_GPL net/dccp/dccp 0xbc0d0229 dccp_disconnect +EXPORT_SYMBOL_GPL net/dccp/dccp 0xbe3d1925 dccp_check_req +EXPORT_SYMBOL_GPL net/dccp/dccp 0xbe4cf010 dccp_feat_init +EXPORT_SYMBOL_GPL net/dccp/dccp 0xbf6b58ba dccp_feat_change +EXPORT_SYMBOL_GPL net/dccp/dccp 0xe7a868c1 dccp_sync_mss +EXPORT_SYMBOL_GPL net/dccp/dccp 0xe7e8b6c4 dccp_feat_change_recv +EXPORT_SYMBOL_GPL net/dccp/dccp 0xea635186 dccp_init_sock +EXPORT_SYMBOL_GPL net/dccp/dccp 0xeab5b425 dccp_sendmsg +EXPORT_SYMBOL_GPL net/dccp/dccp 0xed2e19c6 dccp_death_row +EXPORT_SYMBOL_GPL net/dccp/dccp 0xf03d8e87 dccp_shutdown +EXPORT_SYMBOL_GPL net/dccp/dccp 0xf6b644e1 ccid_hc_tx_new +EXPORT_SYMBOL_GPL net/dccp/dccp 0xfd7c1c40 dccp_hashinfo +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0x0e26ff1e dccp_v4_conn_request +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0x2243c654 dccp_invalid_packet +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0x49ab9dcb dccp_v4_do_rcv +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0x6c4ea8e0 dccp_v4_request_recv_sock +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0x7459ce40 dccp_v4_send_check +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0xcc74f904 dccp_v4_connect +EXPORT_SYMBOL_GPL net/ieee80211/ieee80211 0x326d103d ieee80211_rx_any +EXPORT_SYMBOL_GPL net/ipv4/ipvs/ip_vs 0xe6476b4a net_vs_ctl_path +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_conntrack_ipv4 0x05dee9e5 nf_nat_seq_adjust_hook +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_conntrack_ipv4 0x6d40a921 need_ipv4_conntrack +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x07ae60b6 nf_nat_proto_in_range +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x3c6d4e49 nf_nat_proto_put +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x59c3072f nf_nat_proto_unique_tuple +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x94a08134 nf_nat_proto_nlattr_to_range +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0xb0b04dac nf_nat_packet +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0xcf963905 nf_nat_proto_range_to_nlattr +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0xd303ac18 nf_nat_icmp_reply_translation +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0xf6929249 nf_nat_proto_find_get +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat_proto_gre 0x636b12c8 nf_nat_need_gre +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0x358d045e tcp_vegas_state +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0x6f9653aa tcp_vegas_init +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0x757cac29 tcp_vegas_pkts_acked +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0x7fcdd2e8 tcp_vegas_cwnd_event +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0xaf91d7e3 tcp_vegas_get_info +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x042c93e6 inet6_csk_reqsk_queue_hash_add +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x08a3e5d1 net_ipv6_ctl_path +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x21a52d85 inet6_destroy_sock +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x27f030aa fl6_sock_lookup +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x3c43ea3b ipv6_dup_options +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x5b7b4f6e ip6_local_out +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x7435606b inet6_csk_xmit +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x782c1c07 inet6_csk_bind_conflict +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x87ec80d9 inet6_csk_search_req +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x91c48c23 ip6_sk_dst_lookup +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x91e55181 ip6_dst_lookup +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0xab2f9af6 inet6_csk_addr2sockaddr +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0xaf84f19f ipv6_find_tlv +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0xe72ce3b5 inet6_sk_rebuild_header +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0xfb2e3cd3 ipv6_opt_accepted +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0xfb47cf15 ip6_dst_blackhole +EXPORT_SYMBOL_GPL net/mac80211/mac80211 0x5341aa28 ieee80211_iterate_active_interfaces_atomic +EXPORT_SYMBOL_GPL net/mac80211/mac80211 0xa33d9d44 ieee80211_iterate_active_interfaces +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x041013fd nf_conntrack_lock +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x045072cd nf_ct_port_nla_policy +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x08da7b2b nf_conntrack_tcp_update +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x0ea4f6dc nf_ct_iterate_cleanup +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x1283d711 nf_ct_expect_unregister_notifier +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x15c10b0b nf_conntrack_unregister_notifier +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x223dc924 nf_ct_l3protos +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x248d7f93 nf_conntrack_alloc +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x25e649f2 nf_ct_log_invalid +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x2b9580cb nf_conntrack_flush +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x2bcd28a2 nf_conntrack_l4proto_unregister +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x31f5b6a0 __nf_ct_kill_acct +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x3609de81 nf_conntrack_count +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x364d495b __nf_conntrack_helper_find_byname +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x37e4f344 nf_ct_expect_alloc +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x38630158 nf_conntrack_tuple_taken +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x38c9440b nf_ct_extend_register +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x3f5b1415 nf_ct_port_nlattr_to_tuple +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x40387ccf __nf_ct_event_cache_init +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x442b814b nf_ct_invert_tuple +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x49eef5d4 __nf_conntrack_confirm +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x4dd24a92 nf_conntrack_l4proto_tcp6 +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x586e4eaf nf_conntrack_l3proto_generic +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x5ae9ded9 __nf_ct_refresh_acct +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x5efef316 nf_conntrack_l3proto_register +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x68a8078e nf_ct_unexpect_related +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6cd91ee0 per_cpu__nf_conntrack_ecache +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6e224a7a need_conntrack +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6e7f6fbb print_tuple +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x71789aca nf_conntrack_l4proto_register +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x72836f4a nf_conntrack_free +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x751a5c17 nf_ct_port_tuple_to_nlattr +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x77aadb54 nf_conntrack_alter_reply +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x78f9b710 nf_ct_l3proto_try_module_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x79ca2e53 nf_ct_expect_chain +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x79d6a8be nf_ct_get_tuplepr +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x7fe42810 nf_conntrack_l4proto_tcp4 +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x8532a4de nf_conntrack_helper_unregister +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x86d43eea nf_conntrack_l4proto_udp4 +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x87cd735f __nf_ct_expect_find +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x886a1333 seq_print_acct +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x8ffe7e89 nf_conntrack_htable_size +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x906cd2d6 nf_ct_get_tuple +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x90ff6c9f nf_ct_invert_tuplepr +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x93c11c9b nf_ct_expect_related +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x950b6819 nf_ct_helper_ext_add +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x9ab9a021 nf_ct_unlink_expect +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x9c821d11 __nf_ct_helper_find +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xa08f4e82 nf_ct_expect_init +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xa5af9758 nf_ct_expect_put +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xa5b1faee nf_ct_l3proto_put +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xa6f62ec0 nf_conntrack_set_hashsize +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xa8530890 nf_ct_l4proto_put +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xa9d5f2a1 nf_conntrack_helper_register +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xace98352 nf_conntrack_hash +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xaf57e66f nf_ct_extend_unregister +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xb4e25c68 nf_conntrack_l4proto_udp6 +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xb602c57e nf_ct_l3proto_module_put +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xb76accc2 __nf_conntrack_find +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xb9e30797 nf_ct_acct +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xbaa7aaa0 nf_ct_l4proto_find_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xbc887e16 nf_ct_expect_register_notifier +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xbe3f2939 nf_conntrack_checksum +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc044befe nf_ct_free_hashtable +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc18ac88d nf_ct_expect_hsize +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc35a7a3e nf_conntrack_chain +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc7b64d79 nf_conntrack_hash_insert +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xcbf7fd2a nf_conntrack_register_notifier +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xcedc8a7a nf_conntrack_in +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd30ae9e1 __nf_ct_l4proto_find +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd3a66321 nf_conntrack_l3proto_unregister +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd50a96a2 nf_ct_alloc_hashtable +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd7c683c4 nf_conntrack_find_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd9efb053 nf_ct_deliver_cached_events +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xe4e56c54 nf_ct_expect_find_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xec8beba6 nf_ct_expect_hash +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xf484dcda nf_ct_l3proto_find_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xf9ae81a1 nf_conntrack_max +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xfa169dac nf_conntrack_untracked +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xfb839673 nf_ct_remove_expectations +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_amanda 0xbe88fa06 nf_nat_amanda_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_ftp 0x96655dfc nf_nat_ftp_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x1a4cf1c8 nat_rtp_rtcp_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x1abcba83 nat_t120_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x264c0cf3 get_h225_addr +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x50f189ad set_h225_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x67edfd0e set_ras_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x6aa8c51b nat_callforwarding_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x9f8370a9 set_h245_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0xa7ed60f7 set_sig_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0xaa532e71 nat_h245_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0xc45ef928 nat_q931_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_irc 0xf0d6dfb0 nf_nat_irc_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_pptp 0x169920be nf_nat_pptp_hook_outbound +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_pptp 0x4c9d7246 nf_nat_pptp_hook_exp_gre +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_pptp 0x9b599766 nf_nat_pptp_hook_inbound +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_pptp 0xfac4cd12 nf_nat_pptp_hook_expectfn +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_proto_gre 0x05f8e58c nf_ct_gre_keymap_destroy +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_proto_gre 0x6f59d77c nf_ct_gre_keymap_add +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x0179ed3c nf_nat_sdp_media_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x13169b79 ct_sip_parse_request +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x3c2058a6 ct_sip_parse_numerical_param +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x4f36b1b3 nf_nat_sip_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x5333cb69 ct_sip_parse_header_uri +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x5343611e ct_sip_get_sdp_header +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x56ad8f6e ct_sip_parse_address_param +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x7191490a nf_nat_sdp_port_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x736727e0 nf_nat_sdp_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0xa236aa5e nf_nat_sdp_session_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0xd29af0d9 nf_nat_sip_expect_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0xf8b610ea ct_sip_get_header +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_tftp 0xf1e85d29 nf_nat_tftp_hook +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0xa82eb04a nfnetlink_subsys_unregister +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0xb63ffdb0 nfnetlink_unicast +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0xcb90512c nfnetlink_send +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0xd0afaa14 nfnetlink_subsys_register +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0xeca95329 nfnetlink_has_listeners +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x074e591c xt_proto_fini +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x2fe0a6d8 xt_check_target +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x3a94e1dc xt_proto_init +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x5a7807c9 xt_check_match +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x63f05053 xt_find_revision +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x679fab86 xt_request_find_target +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x69cb73d0 xt_table_unlock +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x77dbd8ab xt_unregister_table +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x9f08c18f xt_find_table_lock +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0xc2c2a7d3 xt_replace_table +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0xeb652686 xt_register_table +EXPORT_SYMBOL_GPL net/netfilter/xt_RATEEST 0xc177bee0 xt_rateest_put +EXPORT_SYMBOL_GPL net/netfilter/xt_RATEEST 0xdb8418cc xt_rateest_lookup +EXPORT_SYMBOL_GPL net/rfkill/rfkill 0x83b2e956 register_rfkill_notifier +EXPORT_SYMBOL_GPL net/rfkill/rfkill 0x86c722f8 rfkill_epo +EXPORT_SYMBOL_GPL net/rfkill/rfkill 0xa6f4320d unregister_rfkill_notifier +EXPORT_SYMBOL_GPL net/rxrpc/af-rxrpc 0xd3313ff5 rxrpc_unregister_security +EXPORT_SYMBOL_GPL net/rxrpc/af-rxrpc 0xe124cafc rxrpc_register_security +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x00f3c924 rpc_wake_up_queued_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x01313fbd rpcauth_generic_bind_cred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x10d51507 rpc_peeraddr2str +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x16ecad8b rpc_clone_client +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x1a3ae35e rpc_lookup_machine_cred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x1bcd3360 rpcauth_create +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x2524b9b6 xprt_wait_for_buffer_space +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x26777a11 rpc_setbufsize +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x28785734 xprt_lookup_rqst +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x29b6cf5f rpc_run_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x2aa17774 rpc_free_iostats +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x2e9df7e0 rpcauth_init_cred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x31a89d59 rpc_debug +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x321533a3 rpc_call_async +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x35cb4660 rpc_restart_call +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x39862309 rpc_shutdown_client +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x3a6a33a5 rpc_put_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x3f343fb5 rpc_exit_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x4350c740 rpc_create +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x4445a01b svc_xprt_put +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x4512e764 xprt_register_transport +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x4d5dea42 rpc_call_sync +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x4f318d69 rpc_proc_register +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x53445f68 nlm_debug +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x550547a3 rpc_destroy_wait_queue +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x55860d79 rpcauth_register +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x56b408fc xdr_partial_copy_from_skb +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x5bd26000 rpc_proc_unregister +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x5f8f7e2b xprt_set_retrans_timeout_def +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x5f9c7598 rpcauth_destroy_credcache +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x66ff6a5e rpcauth_lookup_credcache +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x6c5304c5 rpcb_getport_sync +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x79ece8d8 xprt_unregister_transport +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7ddd47d1 rpc_print_iostats +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7de53067 rpc_init_rtt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7f8fe20f rpc_lookup_cred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x82a64b6d svc_unreg_xprt_class +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x8ad47529 rpc_delay +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x8b051198 rpcauth_init_credcache +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x8b80169e xprt_release_rqst_cong +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x8ce310c6 xprt_write_space +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x8d3cf831 xdr_skb_read_bits +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x8e46c025 svc_print_addr +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x8f023ad8 svc_xprt_received +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x945da6cf rpc_bind_new_program +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x94635311 csum_partial_copy_to_xdr +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x94d2f162 svc_xprt_names +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x97fa53af rpc_killall_tasks +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x9a958027 rpc_alloc_iostats +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x9e0e1b49 rpc_call_null +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x9ee12da4 svc_addsock +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xa171437a xprt_complete_rqst +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xa2a3f521 xprt_set_retrans_timeout_rtt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xa3898961 xprt_release_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xa947633b svc_create_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xad3fb699 rpcauth_unregister +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xad92b63c rpcb_getport_async +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xaf5bf6ef nfs_debug +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xb035cb02 xprt_adjust_cwnd +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xb2bbbdcf svc_max_payload +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xb323e40c svc_xprt_init +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xb387b246 rpc_wake_up_status +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xb5ed494f xprt_update_rtt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xbf9d1b96 nfsd_debug +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xbfb3f297 svc_reg_xprt_class +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xc0ff57a5 rpc_force_rebind +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xc10d184e rpc_peeraddr +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xc12435e3 rpc_calc_rto +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xc76db90e xprt_reserve_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xcbffab8d svc_xprt_copy_addrs +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xd645e4fb __rpc_wait_for_completion_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xd73262b3 rpc_max_payload +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xd82c728e rpc_init_wait_queue +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xdd7dce53 xprt_wake_pending_tasks +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xde73cb5d rpc_sleep_on +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xe10c1f4a rpc_call_start +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xe9232aa1 svc_find_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xec59d62a xprt_release_xprt_cong +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xec5f5a63 rpc_malloc +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xedd1ba52 rpc_wake_up +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xeeacab69 rpc_update_rtt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xefd32048 xprt_disconnect_done +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xf22a329e svc_close_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xf3334fcb svc_xprt_enqueue +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xf7366ec1 put_rpccred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xf9d1164c rpc_free +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xfd44524f rpc_wake_up_next +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xffb9619c xprt_reserve_xprt_cong +EXPORT_SYMBOL_GPL net/xfrm/xfrm_ipcomp 0x7f9356df ipcomp_destroy +EXPORT_SYMBOL_GPL net/xfrm/xfrm_ipcomp 0x89410e61 ipcomp_init_state +EXPORT_SYMBOL_GPL net/xfrm/xfrm_ipcomp 0x943e1259 ipcomp_input +EXPORT_SYMBOL_GPL net/xfrm/xfrm_ipcomp 0xe0caad85 ipcomp_output +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x01143f5b snd_soc_dapm_sync +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x041878c9 snd_soc_info_enum_ext +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x09d86a92 snd_soc_info_volsw_2r +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x09ed479b snd_soc_dapm_free +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x0c476547 snd_soc_dai_digital_mute +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x14585366 snd_soc_get_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x19ec4bb6 snd_soc_set_runtime_hwparams +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x26375c16 snd_soc_dapm_get_pin_status +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x304611a4 snd_soc_put_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x34e423d3 snd_soc_put_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x3f150934 snd_soc_dapm_stream_event +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x42ffe492 snd_soc_dai_set_fmt +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x44db58b8 snd_soc_dapm_new_controls +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x4f54a14b snd_soc_dapm_add_routes +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x58a44b77 snd_soc_info_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x5ba727ac snd_soc_get_volsw_2r +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x5baea5ad snd_soc_dapm_get_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x5f9f23f5 snd_soc_free_pcms +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x6991ba66 snd_soc_dapm_enable_pin +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x6c19bf5e snd_soc_dai_set_clkdiv +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x6f291ca9 snd_soc_dapm_connect_input +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x7a02ee03 snd_soc_info_volsw_s8 +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x7d3d7669 snd_soc_put_volsw_2r +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x7dfd3846 snd_soc_new_pcms +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x88dffbc8 snd_soc_new_ac97_codec +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x88ea0c63 snd_soc_dapm_get_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x999cd4db snd_soc_dai_set_tristate +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x9cb53d19 dapm_reg_event +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x9d191cd3 snd_soc_dai_set_sysclk +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xa6299f39 snd_soc_dai_set_tdm_slot +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xa83a8cfb snd_soc_update_bits +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xacf44ea1 snd_soc_dapm_put_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xb6c9e0e0 snd_soc_dapm_put_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xb8f2843d snd_soc_dapm_disable_pin +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xbeb3432f snd_soc_dapm_new_control +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xbff06f8c snd_soc_info_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xc8659819 snd_soc_dai_set_pll +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xcdf662aa snd_soc_free_ac97_codec +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xd36bca30 snd_soc_cnew +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xd983669e snd_soc_get_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xdbd55758 snd_soc_register_card +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xdcdc5efa snd_soc_get_volsw_s8 +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xe1327eb4 snd_soc_info_volsw_ext +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xe6347a4d snd_soc_test_bits +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xfa460f3f snd_soc_put_volsw_s8 +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xfaf5ba84 snd_soc_dapm_new_widgets +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0x1584fdb9 tlsf_destroy_memory_pool +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0x42a50f11 tlsf_malloc +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0x66da3d8f tlsf_create_memory_pool +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0xe6acc368 tlsf_free +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0xee6c65c9 tlsf_get_used_size +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0xeec8caeb tlsf_get_total_size +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0xf9805f1b tlsf_calloc +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x02500586 thinkpad_ec_unlock +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x0dc7484e thinkpad_ec_try_read_row +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x2552d213 thinkpad_ec_lock +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x3dbfef12 thinkpad_ec_read_row +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x8dbbd831 thinkpad_ec_invalidate +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0xa3042743 thinkpad_ec_prefetch_row +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0xfb5aa917 thinkpad_ec_try_lock +EXPORT_SYMBOL_GPL vmlinux 0x002c5bc8 rt_mutex_timed_lock +EXPORT_SYMBOL_GPL vmlinux 0x00566d8f inotify_get_cookie +EXPORT_SYMBOL_GPL vmlinux 0x00570f31 get_cpu_sysdev +EXPORT_SYMBOL_GPL vmlinux 0x006482d9 bus_get_device_klist +EXPORT_SYMBOL_GPL vmlinux 0x006d7cad srcu_batches_completed +EXPORT_SYMBOL_GPL vmlinux 0x008c793d inotify_add_watch +EXPORT_SYMBOL_GPL vmlinux 0x01032b44 get_device +EXPORT_SYMBOL_GPL vmlinux 0x01181aed get_user_pages_fast +EXPORT_SYMBOL_GPL vmlinux 0x011a8b72 platform_bus +EXPORT_SYMBOL_GPL vmlinux 0x01710c6e exit_fs +EXPORT_SYMBOL_GPL vmlinux 0x01848a8e local_apic_timer_c2_ok +EXPORT_SYMBOL_GPL vmlinux 0x01a43c5d pci_find_next_capability +EXPORT_SYMBOL_GPL vmlinux 0x01a4ea6d unregister_die_notifier +EXPORT_SYMBOL_GPL vmlinux 0x01e1a8de kgdb_breakpoint +EXPORT_SYMBOL_GPL vmlinux 0x022169bc vfs_removexattr +EXPORT_SYMBOL_GPL vmlinux 0x02390125 __inet_inherit_port +EXPORT_SYMBOL_GPL vmlinux 0x0279ccb2 spi_add_device +EXPORT_SYMBOL_GPL vmlinux 0x02981269 do_kern_mount +EXPORT_SYMBOL_GPL vmlinux 0x02ab1f28 sysdev_driver_unregister +EXPORT_SYMBOL_GPL vmlinux 0x02ccea56 lock_policy_rwsem_write +EXPORT_SYMBOL_GPL vmlinux 0x033827f5 inet_twsk_purge +EXPORT_SYMBOL_GPL vmlinux 0x0343bdf1 __i2c_board_list +EXPORT_SYMBOL_GPL vmlinux 0x0362601d platform_device_del +EXPORT_SYMBOL_GPL vmlinux 0x0364f3f5 tcp_twsk_unique +EXPORT_SYMBOL_GPL vmlinux 0x03978b21 __rt_mutex_init +EXPORT_SYMBOL_GPL vmlinux 0x0400c6e1 inet_diag_unregister +EXPORT_SYMBOL_GPL vmlinux 0x04486e88 rcu_batches_completed +EXPORT_SYMBOL_GPL vmlinux 0x04566c7f init_srcu_struct +EXPORT_SYMBOL_GPL vmlinux 0x04c3f2c1 gnttab_empty_grant_references +EXPORT_SYMBOL_GPL vmlinux 0x04ce7fa1 crypto_drop_spawn +EXPORT_SYMBOL_GPL vmlinux 0x054e550b kernel_halt +EXPORT_SYMBOL_GPL vmlinux 0x05e835d3 klist_node_attached +EXPORT_SYMBOL_GPL vmlinux 0x0625f604 securityfs_create_file +EXPORT_SYMBOL_GPL vmlinux 0x064db9a5 mark_mounts_for_expiry +EXPORT_SYMBOL_GPL vmlinux 0x06d05052 __inet_twsk_hashdance +EXPORT_SYMBOL_GPL vmlinux 0x06d222f8 device_resume +EXPORT_SYMBOL_GPL vmlinux 0x06d32e48 xfrm_audit_state_add +EXPORT_SYMBOL_GPL vmlinux 0x0716a907 zap_vma_ptes +EXPORT_SYMBOL_GPL vmlinux 0x073a792f fb_deferred_io_fsync +EXPORT_SYMBOL_GPL vmlinux 0x0764906c devres_remove_group +EXPORT_SYMBOL_GPL vmlinux 0x07b52e38 rtnl_unregister +EXPORT_SYMBOL_GPL vmlinux 0x07cd0845 uhci_check_and_reset_hc +EXPORT_SYMBOL_GPL vmlinux 0x07ff4aea xenbus_scanf +EXPORT_SYMBOL_GPL vmlinux 0x08e12af7 debugfs_create_x32 +EXPORT_SYMBOL_GPL vmlinux 0x08e7a6cb device_move +EXPORT_SYMBOL_GPL vmlinux 0x08ebd45f device_initialize +EXPORT_SYMBOL_GPL vmlinux 0x091eb9b4 round_jiffies +EXPORT_SYMBOL_GPL vmlinux 0x0963248c rtnl_link_unregister +EXPORT_SYMBOL_GPL vmlinux 0x09f19a4c proc_net_remove +EXPORT_SYMBOL_GPL vmlinux 0x0a0f6324 bd_release_from_disk +EXPORT_SYMBOL_GPL vmlinux 0x0acf090d driver_create_file +EXPORT_SYMBOL_GPL vmlinux 0x0b91107a get_inotify_watch +EXPORT_SYMBOL_GPL vmlinux 0x0b9e724f class_interface_unregister +EXPORT_SYMBOL_GPL vmlinux 0x0bc151e5 klist_init +EXPORT_SYMBOL_GPL vmlinux 0x0c17e274 xfrm_aalg_get_byid +EXPORT_SYMBOL_GPL vmlinux 0x0c408ae9 attribute_container_register +EXPORT_SYMBOL_GPL vmlinux 0x0c4717f7 srcu_init_notifier_head +EXPORT_SYMBOL_GPL vmlinux 0x0ce8f480 inotify_rm_wd +EXPORT_SYMBOL_GPL vmlinux 0x0d18d070 device_create_bin_file +EXPORT_SYMBOL_GPL vmlinux 0x0d4f8b68 __create_workqueue_key +EXPORT_SYMBOL_GPL vmlinux 0x0d99f90d security_inode_setattr +EXPORT_SYMBOL_GPL vmlinux 0x0ec210b8 xen_start_info +EXPORT_SYMBOL_GPL vmlinux 0x0ef84c65 hrtimer_start +EXPORT_SYMBOL_GPL vmlinux 0x0f0d238a key_type_user +EXPORT_SYMBOL_GPL vmlinux 0x0f5953cc sysdev_class_unregister +EXPORT_SYMBOL_GPL vmlinux 0x0fe2d570 xenbus_directory +EXPORT_SYMBOL_GPL vmlinux 0x10018797 sysdev_show_int +EXPORT_SYMBOL_GPL vmlinux 0x1050bc52 hrtimer_init +EXPORT_SYMBOL_GPL vmlinux 0x10836bba pci_set_pcie_reset_state +EXPORT_SYMBOL_GPL vmlinux 0x10902502 register_posix_clock +EXPORT_SYMBOL_GPL vmlinux 0x10b17493 led_trigger_set +EXPORT_SYMBOL_GPL vmlinux 0x10f7768a seq_open_net +EXPORT_SYMBOL_GPL vmlinux 0x110fe2c0 platform_driver_probe +EXPORT_SYMBOL_GPL vmlinux 0x11382702 user_match +EXPORT_SYMBOL_GPL vmlinux 0x11856140 raw_hash_sk +EXPORT_SYMBOL_GPL vmlinux 0x124f2056 crypto_get_attr_type +EXPORT_SYMBOL_GPL vmlinux 0x1251d30f call_rcu +EXPORT_SYMBOL_GPL vmlinux 0x1269c99f platform_device_add +EXPORT_SYMBOL_GPL vmlinux 0x12bb9861 inet_csk_reqsk_queue_hash_add +EXPORT_SYMBOL_GPL vmlinux 0x13725286 tty_perform_flush +EXPORT_SYMBOL_GPL vmlinux 0x13b2a946 register_keyboard_notifier +EXPORT_SYMBOL_GPL vmlinux 0x1457f86f xenbus_unregister_driver +EXPORT_SYMBOL_GPL vmlinux 0x145eebd0 device_power_up +EXPORT_SYMBOL_GPL vmlinux 0x149db923 selinux_string_to_sid +EXPORT_SYMBOL_GPL vmlinux 0x14fe2302 alloc_vm_area +EXPORT_SYMBOL_GPL vmlinux 0x15568631 lookup_address +EXPORT_SYMBOL_GPL vmlinux 0x1598dc9d unregister_netevent_notifier +EXPORT_SYMBOL_GPL vmlinux 0x15b0606e e820_any_mapped +EXPORT_SYMBOL_GPL vmlinux 0x15b2457c debugfs_remove +EXPORT_SYMBOL_GPL vmlinux 0x15eee9ad file_ra_state_init +EXPORT_SYMBOL_GPL vmlinux 0x166a6332 __rtnl_link_unregister +EXPORT_SYMBOL_GPL vmlinux 0x1684c810 xenbus_alloc_evtchn +EXPORT_SYMBOL_GPL vmlinux 0x16f76869 probe_kernel_read +EXPORT_SYMBOL_GPL vmlinux 0x172e72d4 vdso_enabled +EXPORT_SYMBOL_GPL vmlinux 0x1769f2c6 user_instantiate +EXPORT_SYMBOL_GPL vmlinux 0x17c1bd2b driver_register +EXPORT_SYMBOL_GPL vmlinux 0x17c53a06 pci_bus_add_device +EXPORT_SYMBOL_GPL vmlinux 0x18159862 fib_rules_register +EXPORT_SYMBOL_GPL vmlinux 0x1878f62b edac_err_assert +EXPORT_SYMBOL_GPL vmlinux 0x18a7c4b1 unregister_pernet_subsys +EXPORT_SYMBOL_GPL vmlinux 0x18d53420 kgdb_register_io_module +EXPORT_SYMBOL_GPL vmlinux 0x18e8ccfe debugfs_create_dir +EXPORT_SYMBOL_GPL vmlinux 0x18f83fab gnttab_grant_foreign_access_ref +EXPORT_SYMBOL_GPL vmlinux 0x1963617f blk_trace_remove +EXPORT_SYMBOL_GPL vmlinux 0x1a4154cf inet_csk_reqsk_queue_prune +EXPORT_SYMBOL_GPL vmlinux 0x1a43c332 unregister_jprobe +EXPORT_SYMBOL_GPL vmlinux 0x1a938737 atomic_notifier_chain_register +EXPORT_SYMBOL_GPL vmlinux 0x1acda5b2 atomic_notifier_chain_unregister +EXPORT_SYMBOL_GPL vmlinux 0x1b60d688 sysfs_create_group +EXPORT_SYMBOL_GPL vmlinux 0x1b99adcf invalidate_inode_pages2 +EXPORT_SYMBOL_GPL vmlinux 0x1b9aca3f jprobe_return +EXPORT_SYMBOL_GPL vmlinux 0x1bccef40 crypto_shoot_alg +EXPORT_SYMBOL_GPL vmlinux 0x1bd4a0af init_pid_ns +EXPORT_SYMBOL_GPL vmlinux 0x1bd7dc77 inotify_rm_watch +EXPORT_SYMBOL_GPL vmlinux 0x1bf3dc21 input_ff_event +EXPORT_SYMBOL_GPL vmlinux 0x1c8b0310 __mmdrop +EXPORT_SYMBOL_GPL vmlinux 0x1cc8a668 sysfs_remove_link +EXPORT_SYMBOL_GPL vmlinux 0x1dd70100 dmi_walk +EXPORT_SYMBOL_GPL vmlinux 0x1e61717e bdi_writeout_inc +EXPORT_SYMBOL_GPL vmlinux 0x1e7bbcb3 kernel_restart +EXPORT_SYMBOL_GPL vmlinux 0x1eb9516e round_jiffies_relative +EXPORT_SYMBOL_GPL vmlinux 0x1f5c910d relay_close +EXPORT_SYMBOL_GPL vmlinux 0x1f74ffe9 raw_unhash_sk +EXPORT_SYMBOL_GPL vmlinux 0x1f8ec1b3 acpi_get_pci_rootbridge_handle +EXPORT_SYMBOL_GPL vmlinux 0x1f90ea51 nf_unregister_afinfo +EXPORT_SYMBOL_GPL vmlinux 0x1f9a0fbf hpet_unregister_irq_handler +EXPORT_SYMBOL_GPL vmlinux 0x1fcc438a queue_delayed_work +EXPORT_SYMBOL_GPL vmlinux 0x1fcece42 inet_twdr_twcal_tick +EXPORT_SYMBOL_GPL vmlinux 0x20430986 mmu_notifier_register +EXPORT_SYMBOL_GPL vmlinux 0x20577ea2 xfrm_ealg_get_byidx +EXPORT_SYMBOL_GPL vmlinux 0x20b82470 hpet_register_irq_handler +EXPORT_SYMBOL_GPL vmlinux 0x20bc3470 orderly_poweroff +EXPORT_SYMBOL_GPL vmlinux 0x20e0c2fb unregister_kretprobes +EXPORT_SYMBOL_GPL vmlinux 0x20e4484f class_create_file +EXPORT_SYMBOL_GPL vmlinux 0x212c19be xenbus_unmap_ring_vfree +EXPORT_SYMBOL_GPL vmlinux 0x21b75891 inotify_find_watch +EXPORT_SYMBOL_GPL vmlinux 0x21bad556 preempt_notifier_register +EXPORT_SYMBOL_GPL vmlinux 0x21d208c5 __cpufreq_driver_target +EXPORT_SYMBOL_GPL vmlinux 0x21db6481 sysfs_remove_bin_file +EXPORT_SYMBOL_GPL vmlinux 0x21f892d7 lookup_create +EXPORT_SYMBOL_GPL vmlinux 0x22472bf4 xfrm_calg_get_byid +EXPORT_SYMBOL_GPL vmlinux 0x226094a9 dequeue_signal +EXPORT_SYMBOL_GPL vmlinux 0x2296c00d crypto_attr_u32 +EXPORT_SYMBOL_GPL vmlinux 0x22d98f2c power_supply_unregister +EXPORT_SYMBOL_GPL vmlinux 0x2348bcd7 cpufreq_cpu_get +EXPORT_SYMBOL_GPL vmlinux 0x23679939 __iowrite32_copy +EXPORT_SYMBOL_GPL vmlinux 0x23864ce7 cpuset_mem_spread_node +EXPORT_SYMBOL_GPL vmlinux 0x23893dda device_bind_driver +EXPORT_SYMBOL_GPL vmlinux 0x24196ba2 init_uts_ns +EXPORT_SYMBOL_GPL vmlinux 0x2447533c ktime_get_real +EXPORT_SYMBOL_GPL vmlinux 0x246b0aac pci_enable_pcie_error_reporting +EXPORT_SYMBOL_GPL vmlinux 0x248f3856 crypto_enqueue_request +EXPORT_SYMBOL_GPL vmlinux 0x24938bd5 anon_inode_getfd +EXPORT_SYMBOL_GPL vmlinux 0x24c7698a xenbus_write +EXPORT_SYMBOL_GPL vmlinux 0x24eb7e32 leds_list +EXPORT_SYMBOL_GPL vmlinux 0x2523b4e0 pci_unblock_user_cfg_access +EXPORT_SYMBOL_GPL vmlinux 0x25386d16 vlan_dev_real_dev +EXPORT_SYMBOL_GPL vmlinux 0x2545c170 unregister_xenbus_watch +EXPORT_SYMBOL_GPL vmlinux 0x25886776 cpufreq_driver_target +EXPORT_SYMBOL_GPL vmlinux 0x25dc7f43 device_remove_bin_file +EXPORT_SYMBOL_GPL vmlinux 0x25e6a7c5 device_destroy +EXPORT_SYMBOL_GPL vmlinux 0x264b18a4 fb_deferred_io_init +EXPORT_SYMBOL_GPL vmlinux 0x26599c90 register_kretprobes +EXPORT_SYMBOL_GPL vmlinux 0x267cbf12 vfs_getxattr +EXPORT_SYMBOL_GPL vmlinux 0x26b2d364 sysdev_class_create_file +EXPORT_SYMBOL_GPL vmlinux 0x2712cce3 transport_setup_device +EXPORT_SYMBOL_GPL vmlinux 0x2714c98c klist_del +EXPORT_SYMBOL_GPL vmlinux 0x279b2c4a drop_file_write_access +EXPORT_SYMBOL_GPL vmlinux 0x27b56abe kernel_kobj +EXPORT_SYMBOL_GPL vmlinux 0x27e16c73 crypto_hash_walk_done +EXPORT_SYMBOL_GPL vmlinux 0x28088f0f pv_time_ops +EXPORT_SYMBOL_GPL vmlinux 0x28961016 init_user_ns +EXPORT_SYMBOL_GPL vmlinux 0x28d664ff __raw_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x28e23139 xfrm_probe_algs +EXPORT_SYMBOL_GPL vmlinux 0x2908789f inet_csk_listen_start +EXPORT_SYMBOL_GPL vmlinux 0x292892ac platform_get_resource_byname +EXPORT_SYMBOL_GPL vmlinux 0x295394e2 raw_seq_next +EXPORT_SYMBOL_GPL vmlinux 0x295c4c15 inet_csk_listen_stop +EXPORT_SYMBOL_GPL vmlinux 0x29c029bc fsstack_copy_attr_all +EXPORT_SYMBOL_GPL vmlinux 0x2a678a13 __suspend_report_result +EXPORT_SYMBOL_GPL vmlinux 0x2a680d4a spi_new_device +EXPORT_SYMBOL_GPL vmlinux 0x2b279e90 crypto_register_alg +EXPORT_SYMBOL_GPL vmlinux 0x2b9f8e23 nf_net_ipv4_netfilter_sysctl_path +EXPORT_SYMBOL_GPL vmlinux 0x2bfdeb4e sysdev_remove_file +EXPORT_SYMBOL_GPL vmlinux 0x2c16ed76 xfrm_calg_get_byname +EXPORT_SYMBOL_GPL vmlinux 0x2c40a9ef mmu_notifier_unregister +EXPORT_SYMBOL_GPL vmlinux 0x2c737f41 elv_unregister +EXPORT_SYMBOL_GPL vmlinux 0x2d45bcda crypto_alg_sem +EXPORT_SYMBOL_GPL vmlinux 0x2d59c954 edac_handlers +EXPORT_SYMBOL_GPL vmlinux 0x2d9c9c61 xfrm_audit_policy_delete +EXPORT_SYMBOL_GPL vmlinux 0x2d9f2ce3 sched_clock_idle_wakeup_event +EXPORT_SYMBOL_GPL vmlinux 0x2e59e12e single_release_net +EXPORT_SYMBOL_GPL vmlinux 0x2e6e7aee smp_ops +EXPORT_SYMBOL_GPL vmlinux 0x2ed92ddb spi_sync +EXPORT_SYMBOL_GPL vmlinux 0x2f0340d4 inet_twsk_alloc +EXPORT_SYMBOL_GPL vmlinux 0x2f8458e5 pciserial_init_ports +EXPORT_SYMBOL_GPL vmlinux 0x2f870319 __class_register +EXPORT_SYMBOL_GPL vmlinux 0x30560bf1 tty_mode_ioctl +EXPORT_SYMBOL_GPL vmlinux 0x3058f591 generic_sync_sb_inodes +EXPORT_SYMBOL_GPL vmlinux 0x30f35ed8 __crypto_alloc_tfm +EXPORT_SYMBOL_GPL vmlinux 0x3167f035 class_unregister +EXPORT_SYMBOL_GPL vmlinux 0x316d9888 device_create_vargs +EXPORT_SYMBOL_GPL vmlinux 0x319ca116 blk_execute_rq_nowait +EXPORT_SYMBOL_GPL vmlinux 0x325e677c gnttab_grant_foreign_transfer_ref +EXPORT_SYMBOL_GPL vmlinux 0x326c16e6 inverse_translate +EXPORT_SYMBOL_GPL vmlinux 0x32924a4d scatterwalk_copychunks +EXPORT_SYMBOL_GPL vmlinux 0x32b0eb3e led_trigger_set_default +EXPORT_SYMBOL_GPL vmlinux 0x3395ab87 simple_attr_read +EXPORT_SYMBOL_GPL vmlinux 0x33b6e752 acpi_ec_remove_query_handler +EXPORT_SYMBOL_GPL vmlinux 0x340c9bb2 sysctl_pathname +EXPORT_SYMBOL_GPL vmlinux 0x34153db5 __blk_put_request +EXPORT_SYMBOL_GPL vmlinux 0x341f20c1 __inet_lookup_listener +EXPORT_SYMBOL_GPL vmlinux 0x3441c3d6 gpio_set_value_cansleep +EXPORT_SYMBOL_GPL vmlinux 0x359e2127 page_cache_sync_readahead +EXPORT_SYMBOL_GPL vmlinux 0x3609b38b kset_create_and_add +EXPORT_SYMBOL_GPL vmlinux 0x360f627e crypto_register_instance +EXPORT_SYMBOL_GPL vmlinux 0x361e2bcc save_stack_trace +EXPORT_SYMBOL_GPL vmlinux 0x362e23ec call_rcu_bh +EXPORT_SYMBOL_GPL vmlinux 0x363a73ee device_create_file +EXPORT_SYMBOL_GPL vmlinux 0x367f00e2 sysdev_create_file +EXPORT_SYMBOL_GPL vmlinux 0x369cec2c crypto_hash_walk_first +EXPORT_SYMBOL_GPL vmlinux 0x379880a8 device_reprobe +EXPORT_SYMBOL_GPL vmlinux 0x37d17fb7 anon_transport_class_register +EXPORT_SYMBOL_GPL vmlinux 0x3857ebc4 __audit_inode_child +EXPORT_SYMBOL_GPL vmlinux 0x385ec560 xenbus_frontend_closed +EXPORT_SYMBOL_GPL vmlinux 0x38658882 crypto_ahash_type +EXPORT_SYMBOL_GPL vmlinux 0x3893cea0 security_inode_permission +EXPORT_SYMBOL_GPL vmlinux 0x3895233b srcu_notifier_chain_unregister +EXPORT_SYMBOL_GPL vmlinux 0x38a0c03e pci_create_slot +EXPORT_SYMBOL_GPL vmlinux 0x3981dd66 map_vm_area +EXPORT_SYMBOL_GPL vmlinux 0x3997afb4 attribute_container_find_class_device +EXPORT_SYMBOL_GPL vmlinux 0x39ae8d0f kern_mount_data +EXPORT_SYMBOL_GPL vmlinux 0x39d154f4 led_trigger_register +EXPORT_SYMBOL_GPL vmlinux 0x3a410ae0 do_add_mount +EXPORT_SYMBOL_GPL vmlinux 0x3a7f8b86 __local_bh_enable +EXPORT_SYMBOL_GPL vmlinux 0x3a9a440d gpiochip_add +EXPORT_SYMBOL_GPL vmlinux 0x3ac3d8d2 unregister_pernet_gen_device +EXPORT_SYMBOL_GPL vmlinux 0x3be7af02 get_max_files +EXPORT_SYMBOL_GPL vmlinux 0x3c23e37f spi_register_driver +EXPORT_SYMBOL_GPL vmlinux 0x3c63c935 dma_get_required_mask +EXPORT_SYMBOL_GPL vmlinux 0x3c942368 profile_event_unregister +EXPORT_SYMBOL_GPL vmlinux 0x3c9432cb sysdev_unregister +EXPORT_SYMBOL_GPL vmlinux 0x3cd06035 add_input_randomness +EXPORT_SYMBOL_GPL vmlinux 0x3cfedb3f register_pm_notifier +EXPORT_SYMBOL_GPL vmlinux 0x3d4ca898 sysfs_chmod_file +EXPORT_SYMBOL_GPL vmlinux 0x3d59f18c platform_device_alloc +EXPORT_SYMBOL_GPL vmlinux 0x3d711cb9 sysdev_driver_register +EXPORT_SYMBOL_GPL vmlinux 0x3d7ea99a gnttab_grant_foreign_transfer +EXPORT_SYMBOL_GPL vmlinux 0x3dbf6dd9 bus_find_device +EXPORT_SYMBOL_GPL vmlinux 0x3de3fc4a crypto_tfm_in_queue +EXPORT_SYMBOL_GPL vmlinux 0x3e1c0353 simple_attr_write +EXPORT_SYMBOL_GPL vmlinux 0x3e9afe1c tcp_reno_cong_avoid +EXPORT_SYMBOL_GPL vmlinux 0x3ea9f1de __class_create +EXPORT_SYMBOL_GPL vmlinux 0x3efb35c9 get_online_cpus +EXPORT_SYMBOL_GPL vmlinux 0x3f01570a probe_kernel_write +EXPORT_SYMBOL_GPL vmlinux 0x3f0734e2 spi_write_then_read +EXPORT_SYMBOL_GPL vmlinux 0x3f081cd9 do_sync_mapping_range +EXPORT_SYMBOL_GPL vmlinux 0x3f0e334f rtnl_register +EXPORT_SYMBOL_GPL vmlinux 0x3f238101 dcookie_register +EXPORT_SYMBOL_GPL vmlinux 0x3f84d4c9 gnttab_release_grant_reference +EXPORT_SYMBOL_GPL vmlinux 0x403f40d6 xenbus_grant_ring +EXPORT_SYMBOL_GPL vmlinux 0x404cb03b pciserial_resume_ports +EXPORT_SYMBOL_GPL vmlinux 0x404feb30 devres_alloc +EXPORT_SYMBOL_GPL vmlinux 0x41aad989 led_trigger_store +EXPORT_SYMBOL_GPL vmlinux 0x41bca762 rtc_class_open +EXPORT_SYMBOL_GPL vmlinux 0x41f3cc90 xfrm_aalg_get_byname +EXPORT_SYMBOL_GPL vmlinux 0x424acc6d scatterwalk_done +EXPORT_SYMBOL_GPL vmlinux 0x425291b8 isa_unregister_driver +EXPORT_SYMBOL_GPL vmlinux 0x425508d3 stop_machine +EXPORT_SYMBOL_GPL vmlinux 0x431aa3a8 fb_bl_default_curve +EXPORT_SYMBOL_GPL vmlinux 0x432fd7f6 __gpio_set_value +EXPORT_SYMBOL_GPL vmlinux 0x434b0bc7 xfrm_output +EXPORT_SYMBOL_GPL vmlinux 0x44092701 xfrm_inner_extract_output +EXPORT_SYMBOL_GPL vmlinux 0x447b6d47 ip_build_and_send_pkt +EXPORT_SYMBOL_GPL vmlinux 0x44a19489 debugfs_rename +EXPORT_SYMBOL_GPL vmlinux 0x44a65d5c lock_policy_rwsem_read +EXPORT_SYMBOL_GPL vmlinux 0x44ab0c7a gpiochip_remove +EXPORT_SYMBOL_GPL vmlinux 0x44cf7b09 device_attach +EXPORT_SYMBOL_GPL vmlinux 0x452c04a4 transport_destroy_device +EXPORT_SYMBOL_GPL vmlinux 0x453ccdb3 sysdev_store_int +EXPORT_SYMBOL_GPL vmlinux 0x457594fa crypto_alg_list +EXPORT_SYMBOL_GPL vmlinux 0x45bf1ff3 crypto_inc +EXPORT_SYMBOL_GPL vmlinux 0x45d14bdf hypercall_page +EXPORT_SYMBOL_GPL vmlinux 0x45eea23f __sock_recv_timestamp +EXPORT_SYMBOL_GPL vmlinux 0x460f31aa rodata_test_data +EXPORT_SYMBOL_GPL vmlinux 0x462b63f7 generic_fh_to_parent +EXPORT_SYMBOL_GPL vmlinux 0x464942b2 crypto_init_spawn +EXPORT_SYMBOL_GPL vmlinux 0x467eb930 debugfs_create_x16 +EXPORT_SYMBOL_GPL vmlinux 0x468dda06 sysfs_add_file_to_group +EXPORT_SYMBOL_GPL vmlinux 0x468fc5ca relay_flush +EXPORT_SYMBOL_GPL vmlinux 0x4697e879 proc_net_fops_create +EXPORT_SYMBOL_GPL vmlinux 0x46df52eb bus_create_file +EXPORT_SYMBOL_GPL vmlinux 0x47229b5c gpio_request +EXPORT_SYMBOL_GPL vmlinux 0x484108ba vfs_test_lock +EXPORT_SYMBOL_GPL vmlinux 0x4846eb95 tty_prepare_flip_string_flags +EXPORT_SYMBOL_GPL vmlinux 0x499043d3 crypto_init_queue +EXPORT_SYMBOL_GPL vmlinux 0x4a11a4fb bind_virq_to_irqhandler +EXPORT_SYMBOL_GPL vmlinux 0x4a53e7c9 pci_find_aer_capability +EXPORT_SYMBOL_GPL vmlinux 0x4a7e30d9 marker_probe_unregister_private_data +EXPORT_SYMBOL_GPL vmlinux 0x4ace6f42 platform_bus_type +EXPORT_SYMBOL_GPL vmlinux 0x4b1a7a02 relay_subbufs_consumed +EXPORT_SYMBOL_GPL vmlinux 0x4bf8e03b sysfs_remove_file_from_group +EXPORT_SYMBOL_GPL vmlinux 0x4c2551c2 securityfs_remove +EXPORT_SYMBOL_GPL vmlinux 0x4c4418c3 platform_device_add_resources +EXPORT_SYMBOL_GPL vmlinux 0x4c481816 crypto_alg_mod_lookup +EXPORT_SYMBOL_GPL vmlinux 0x4c759827 byte_rev_table +EXPORT_SYMBOL_GPL vmlinux 0x4c7c07e2 inet_csk_get_port +EXPORT_SYMBOL_GPL vmlinux 0x4c7da7df find_get_pid +EXPORT_SYMBOL_GPL vmlinux 0x4ca43a5c uart_console_write +EXPORT_SYMBOL_GPL vmlinux 0x4d72b5c2 pci_disable_pcie_error_reporting +EXPORT_SYMBOL_GPL vmlinux 0x4d7cf1ec fib_rules_cleanup_ops +EXPORT_SYMBOL_GPL vmlinux 0x4eb3f0bb vfs_setxattr +EXPORT_SYMBOL_GPL vmlinux 0x4eb99e84 get_task_mm +EXPORT_SYMBOL_GPL vmlinux 0x50250b21 blkdev_ioctl +EXPORT_SYMBOL_GPL vmlinux 0x50634025 net_assign_generic +EXPORT_SYMBOL_GPL vmlinux 0x50b67174 xfrm_ealg_get_byid +EXPORT_SYMBOL_GPL vmlinux 0x50dfe95a xfrm_audit_state_replay_overflow +EXPORT_SYMBOL_GPL vmlinux 0x50e7193a __i2c_first_dynamic_bus_num +EXPORT_SYMBOL_GPL vmlinux 0x5108b3fc acpi_os_map_memory +EXPORT_SYMBOL_GPL vmlinux 0x51242816 __rtnl_link_register +EXPORT_SYMBOL_GPL vmlinux 0x518c2fc6 hpet_rtc_dropped_irq +EXPORT_SYMBOL_GPL vmlinux 0x51dd6488 xfrm_aalg_get_byidx +EXPORT_SYMBOL_GPL vmlinux 0x51f10184 inet_csk_search_req +EXPORT_SYMBOL_GPL vmlinux 0x5244df92 crypto_free_tfm +EXPORT_SYMBOL_GPL vmlinux 0x5250d9d3 debugfs_create_u8 +EXPORT_SYMBOL_GPL vmlinux 0x5275edbb free_vm_area +EXPORT_SYMBOL_GPL vmlinux 0x52d111ea pm_qos_update_requirement +EXPORT_SYMBOL_GPL vmlinux 0x52d8c675 crypto_register_template +EXPORT_SYMBOL_GPL vmlinux 0x535cc48e mnt_drop_write +EXPORT_SYMBOL_GPL vmlinux 0x53986488 register_die_notifier +EXPORT_SYMBOL_GPL vmlinux 0x53b4587b xenbus_map_ring +EXPORT_SYMBOL_GPL vmlinux 0x543655a9 relay_file_operations +EXPORT_SYMBOL_GPL vmlinux 0x552c5845 tcp_twsk_destructor +EXPORT_SYMBOL_GPL vmlinux 0x55526907 xen_features +EXPORT_SYMBOL_GPL vmlinux 0x555f2d04 tty_prepare_flip_string +EXPORT_SYMBOL_GPL vmlinux 0x5582d5bf fs_kobj +EXPORT_SYMBOL_GPL vmlinux 0x55a9bfd8 inotify_destroy +EXPORT_SYMBOL_GPL vmlinux 0x56398615 mark_tsc_unstable +EXPORT_SYMBOL_GPL vmlinux 0x5641485b tty_termios_encode_baud_rate +EXPORT_SYMBOL_GPL vmlinux 0x5709e714 platform_get_irq +EXPORT_SYMBOL_GPL vmlinux 0x5733312d sysfs_remove_file +EXPORT_SYMBOL_GPL vmlinux 0x5750d0de preempt_notifier_unregister +EXPORT_SYMBOL_GPL vmlinux 0x5779d445 xenbus_exists +EXPORT_SYMBOL_GPL vmlinux 0x579e0bf5 rtnl_unregister_all +EXPORT_SYMBOL_GPL vmlinux 0x57d4588c blk_set_cmd_filter_defaults +EXPORT_SYMBOL_GPL vmlinux 0x584e9b0d debugfs_create_x8 +EXPORT_SYMBOL_GPL vmlinux 0x585c3d0c devres_close_group +EXPORT_SYMBOL_GPL vmlinux 0x587516a5 class_remove_file +EXPORT_SYMBOL_GPL vmlinux 0x589d9a5c __blk_end_request +EXPORT_SYMBOL_GPL vmlinux 0x58eade0f d_materialise_unique +EXPORT_SYMBOL_GPL vmlinux 0x594ce7d5 bus_unregister +EXPORT_SYMBOL_GPL vmlinux 0x597f3bc3 marker_get_private_data +EXPORT_SYMBOL_GPL vmlinux 0x59c0b84a pci_update_slot_number +EXPORT_SYMBOL_GPL vmlinux 0x5a2b1b67 gnttab_free_grant_reference +EXPORT_SYMBOL_GPL vmlinux 0x5ac8c6b7 unregister_kprobes +EXPORT_SYMBOL_GPL vmlinux 0x5af03a28 gnttab_claim_grant_reference +EXPORT_SYMBOL_GPL vmlinux 0x5b392b04 hrtimer_try_to_cancel +EXPORT_SYMBOL_GPL vmlinux 0x5b5114f9 driver_remove_file +EXPORT_SYMBOL_GPL vmlinux 0x5ba3bc48 elv_register +EXPORT_SYMBOL_GPL vmlinux 0x5bb44a32 klist_add_head +EXPORT_SYMBOL_GPL vmlinux 0x5bc97df7 tcp_done +EXPORT_SYMBOL_GPL vmlinux 0x5bfc03c3 unregister_keyboard_notifier +EXPORT_SYMBOL_GPL vmlinux 0x5ccb9fc4 generic_drop_inode +EXPORT_SYMBOL_GPL vmlinux 0x5cfcf0f1 percpu_free +EXPORT_SYMBOL_GPL vmlinux 0x5d0f6f57 kbd_table +EXPORT_SYMBOL_GPL vmlinux 0x5d2972de crypto_larval_kill +EXPORT_SYMBOL_GPL vmlinux 0x5d366dec gnttab_cancel_free_callback +EXPORT_SYMBOL_GPL vmlinux 0x5d730e7b raw_notifier_chain_unregister +EXPORT_SYMBOL_GPL vmlinux 0x5d9631ca cpufreq_unregister_driver +EXPORT_SYMBOL_GPL vmlinux 0x5dc0d1b7 ip_local_out +EXPORT_SYMBOL_GPL vmlinux 0x5dd67618 register_netevent_notifier +EXPORT_SYMBOL_GPL vmlinux 0x5e047c90 hwmon_device_unregister +EXPORT_SYMBOL_GPL vmlinux 0x5e689ef4 sysdev_store_ulong +EXPORT_SYMBOL_GPL vmlinux 0x5eb62351 proc_net_mkdir +EXPORT_SYMBOL_GPL vmlinux 0x5f094d34 inotify_remove_watch_locked +EXPORT_SYMBOL_GPL vmlinux 0x5f236ef4 skb_partial_csum_set +EXPORT_SYMBOL_GPL vmlinux 0x5f2da8c4 check_tsc_unstable +EXPORT_SYMBOL_GPL vmlinux 0x5f316348 device_register +EXPORT_SYMBOL_GPL vmlinux 0x5f408bac klist_next +EXPORT_SYMBOL_GPL vmlinux 0x5fea940b hrtimer_forward +EXPORT_SYMBOL_GPL vmlinux 0x5fef2e55 tty_encode_baud_rate +EXPORT_SYMBOL_GPL vmlinux 0x606f49b6 xfrm_audit_policy_add +EXPORT_SYMBOL_GPL vmlinux 0x6091797f synchronize_rcu +EXPORT_SYMBOL_GPL vmlinux 0x60a13e90 rcu_barrier +EXPORT_SYMBOL_GPL vmlinux 0x60ad4cfd sock_prot_inuse_get +EXPORT_SYMBOL_GPL vmlinux 0x60c6355a devm_kfree +EXPORT_SYMBOL_GPL vmlinux 0x6133f533 fb_deferred_io_cleanup +EXPORT_SYMBOL_GPL vmlinux 0x61880b8d __get_vm_area +EXPORT_SYMBOL_GPL vmlinux 0x62772690 platform_driver_register +EXPORT_SYMBOL_GPL vmlinux 0x633f14ca transport_configure_device +EXPORT_SYMBOL_GPL vmlinux 0x636f256b sk_clone +EXPORT_SYMBOL_GPL vmlinux 0x63842c4f xenbus_dev_fatal +EXPORT_SYMBOL_GPL vmlinux 0x638c5470 tcp_init_congestion_ops +EXPORT_SYMBOL_GPL vmlinux 0x63ae27d6 add_nops +EXPORT_SYMBOL_GPL vmlinux 0x644cf8d9 spi_unregister_master +EXPORT_SYMBOL_GPL vmlinux 0x64a52b7f devres_remove +EXPORT_SYMBOL_GPL vmlinux 0x64fd27e0 devres_find +EXPORT_SYMBOL_GPL vmlinux 0x6591ff95 xenbus_free_evtchn +EXPORT_SYMBOL_GPL vmlinux 0x65ccb6f0 call_netevent_notifiers +EXPORT_SYMBOL_GPL vmlinux 0x65d6d0f0 gpio_direction_input +EXPORT_SYMBOL_GPL vmlinux 0x6610ad99 synchronize_srcu +EXPORT_SYMBOL_GPL vmlinux 0x66114346 platform_device_put +EXPORT_SYMBOL_GPL vmlinux 0x661601de sprint_symbol +EXPORT_SYMBOL_GPL vmlinux 0x66b2a859 nr_free_buffer_pages +EXPORT_SYMBOL_GPL vmlinux 0x66d87d38 symbol_put_addr +EXPORT_SYMBOL_GPL vmlinux 0x66f0668d simple_attr_open +EXPORT_SYMBOL_GPL vmlinux 0x67955ce6 profile_hits +EXPORT_SYMBOL_GPL vmlinux 0x67b2db11 sysdev_class_remove_file +EXPORT_SYMBOL_GPL vmlinux 0x67fc7e64 devres_release_group +EXPORT_SYMBOL_GPL vmlinux 0x6834cc83 klist_add_after +EXPORT_SYMBOL_GPL vmlinux 0x683e0bf4 pci_slots_kset +EXPORT_SYMBOL_GPL vmlinux 0x683fe95d rtc_set_mmss +EXPORT_SYMBOL_GPL vmlinux 0x6846f4f2 register_kretprobe +EXPORT_SYMBOL_GPL vmlinux 0x686c703f xfrm_count_auth_supported +EXPORT_SYMBOL_GPL vmlinux 0x6892088c unregister_pm_notifier +EXPORT_SYMBOL_GPL vmlinux 0x68eede2d pciserial_suspend_ports +EXPORT_SYMBOL_GPL vmlinux 0x69064c59 bus_get_kset +EXPORT_SYMBOL_GPL vmlinux 0x691884ef pv_apic_ops +EXPORT_SYMBOL_GPL vmlinux 0x696ddbe3 crypto_attr_alg +EXPORT_SYMBOL_GPL vmlinux 0x69b148fd xenbus_watch_pathfmt +EXPORT_SYMBOL_GPL vmlinux 0x69fa1f00 blk_end_bidi_request +EXPORT_SYMBOL_GPL vmlinux 0x6a73a650 attribute_container_classdev_to_container +EXPORT_SYMBOL_GPL vmlinux 0x6a99047f isa_register_driver +EXPORT_SYMBOL_GPL vmlinux 0x6b036a07 posix_timer_event +EXPORT_SYMBOL_GPL vmlinux 0x6b07a368 klist_add_before +EXPORT_SYMBOL_GPL vmlinux 0x6b9178b3 xenbus_strstate +EXPORT_SYMBOL_GPL vmlinux 0x6c11059b __srcu_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x6c49c4f2 clockevents_notify +EXPORT_SYMBOL_GPL vmlinux 0x6c589d12 set_cpus_allowed_ptr +EXPORT_SYMBOL_GPL vmlinux 0x6c8d5ae8 __gpio_get_value +EXPORT_SYMBOL_GPL vmlinux 0x6cb3475a skb_pull_rcsum +EXPORT_SYMBOL_GPL vmlinux 0x6d2adfac save_stack_trace_tsk +EXPORT_SYMBOL_GPL vmlinux 0x6d8488df crypto_unregister_alg +EXPORT_SYMBOL_GPL vmlinux 0x6e58ddf0 gnttab_end_foreign_transfer_ref +EXPORT_SYMBOL_GPL vmlinux 0x6ebe305d raw_seq_stop +EXPORT_SYMBOL_GPL vmlinux 0x6f9c2efe marker_probe_cb +EXPORT_SYMBOL_GPL vmlinux 0x6fad110e tty_put_char +EXPORT_SYMBOL_GPL vmlinux 0x6ffb5b60 klist_add_tail +EXPORT_SYMBOL_GPL vmlinux 0x6ffc096e rtc_irq_set_freq +EXPORT_SYMBOL_GPL vmlinux 0x7037d79d k8_flush_garts +EXPORT_SYMBOL_GPL vmlinux 0x713db324 xenbus_bind_evtchn +EXPORT_SYMBOL_GPL vmlinux 0x71c8bc95 kgdb_unregister_io_module +EXPORT_SYMBOL_GPL vmlinux 0x7258be1d blk_end_request +EXPORT_SYMBOL_GPL vmlinux 0x7278d328 all_vm_events +EXPORT_SYMBOL_GPL vmlinux 0x72ed7d9f unregister_kretprobe +EXPORT_SYMBOL_GPL vmlinux 0x73201149 klist_iter_init_node +EXPORT_SYMBOL_GPL vmlinux 0x7365f957 acpi_bus_trim +EXPORT_SYMBOL_GPL vmlinux 0x73a157bd __rtnl_register +EXPORT_SYMBOL_GPL vmlinux 0x73b1f76d do_posix_clock_nosettime +EXPORT_SYMBOL_GPL vmlinux 0x73c5f06d vfs_cancel_lock +EXPORT_SYMBOL_GPL vmlinux 0x73d7fe07 pci_cleanup_aer_uncorrect_error_status +EXPORT_SYMBOL_GPL vmlinux 0x74740576 sysfs_remove_group +EXPORT_SYMBOL_GPL vmlinux 0x74816ce3 hvc_alloc +EXPORT_SYMBOL_GPL vmlinux 0x74abdafa task_handoff_register +EXPORT_SYMBOL_GPL vmlinux 0x74d61a4d get_dcookie +EXPORT_SYMBOL_GPL vmlinux 0x74deb10c used_vectors +EXPORT_SYMBOL_GPL vmlinux 0x7506c0fd driver_attach +EXPORT_SYMBOL_GPL vmlinux 0x7508bbab crypto_alloc_base +EXPORT_SYMBOL_GPL vmlinux 0x7521afb6 leave_mm +EXPORT_SYMBOL_GPL vmlinux 0x7543a836 kobject_init_and_add +EXPORT_SYMBOL_GPL vmlinux 0x7568b92e register_jprobes +EXPORT_SYMBOL_GPL vmlinux 0x75a14ffc vfs_listxattr +EXPORT_SYMBOL_GPL vmlinux 0x75c00c51 driver_add_kobj +EXPORT_SYMBOL_GPL vmlinux 0x75c8a11c inet_twdr_twkill_work +EXPORT_SYMBOL_GPL vmlinux 0x75e8f3c3 crypto_register_notifier +EXPORT_SYMBOL_GPL vmlinux 0x75ec173b inotify_dentry_parent_queue_event +EXPORT_SYMBOL_GPL vmlinux 0x7626e1ac bus_unregister_notifier +EXPORT_SYMBOL_GPL vmlinux 0x76edd2b0 inet6_lookup +EXPORT_SYMBOL_GPL vmlinux 0x7712771a unbind_from_irqhandler +EXPORT_SYMBOL_GPL vmlinux 0x77bbf064 mmput +EXPORT_SYMBOL_GPL vmlinux 0x77c6d7dd platform_get_irq_byname +EXPORT_SYMBOL_GPL vmlinux 0x7840115c page_mkclean +EXPORT_SYMBOL_GPL vmlinux 0x794f3946 sysfs_notify +EXPORT_SYMBOL_GPL vmlinux 0x7a4c1438 pv_info +EXPORT_SYMBOL_GPL vmlinux 0x7b0b4551 sysdev_show_ulong +EXPORT_SYMBOL_GPL vmlinux 0x7b1d544d edac_handler_set +EXPORT_SYMBOL_GPL vmlinux 0x7bcf5e30 cpuidle_register_device +EXPORT_SYMBOL_GPL vmlinux 0x7c7bcf38 register_pernet_device +EXPORT_SYMBOL_GPL vmlinux 0x7cc2be7b tcp_register_congestion_control +EXPORT_SYMBOL_GPL vmlinux 0x7cd551b3 led_trigger_show +EXPORT_SYMBOL_GPL vmlinux 0x7cfc08c4 device_del +EXPORT_SYMBOL_GPL vmlinux 0x7d0a56b0 put_inotify_watch +EXPORT_SYMBOL_GPL vmlinux 0x7d28f410 firmware_kobj +EXPORT_SYMBOL_GPL vmlinux 0x7d9bf24f __ip_route_output_key +EXPORT_SYMBOL_GPL vmlinux 0x7da8d037 marker_probe_register +EXPORT_SYMBOL_GPL vmlinux 0x7dc37d96 device_schedule_callback_owner +EXPORT_SYMBOL_GPL vmlinux 0x7dc5d0b6 crypto_unregister_notifier +EXPORT_SYMBOL_GPL vmlinux 0x7dd3e4bd devres_open_group +EXPORT_SYMBOL_GPL vmlinux 0x7deee94d pci_find_next_ht_capability +EXPORT_SYMBOL_GPL vmlinux 0x7e084cb6 kobject_create_and_add +EXPORT_SYMBOL_GPL vmlinux 0x7e698a51 unregister_jprobes +EXPORT_SYMBOL_GPL vmlinux 0x7ec8a54b default_backing_dev_info +EXPORT_SYMBOL_GPL vmlinux 0x7ed2810f xfrm_audit_state_delete +EXPORT_SYMBOL_GPL vmlinux 0x7f19c836 unlock_policy_rwsem_write +EXPORT_SYMBOL_GPL vmlinux 0x7f770b57 register_net_sysctl_table +EXPORT_SYMBOL_GPL vmlinux 0x7f79419f inet_twsk_put +EXPORT_SYMBOL_GPL vmlinux 0x7f9af2f3 device_find_child +EXPORT_SYMBOL_GPL vmlinux 0x7fbcd945 inotify_find_update_watch +EXPORT_SYMBOL_GPL vmlinux 0x7fdd1819 flush_workqueue +EXPORT_SYMBOL_GPL vmlinux 0x7ff10ccf raw_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x80353106 gpiochip_is_requested +EXPORT_SYMBOL_GPL vmlinux 0x8039d043 selinux_secmark_relabel_packet_permission +EXPORT_SYMBOL_GPL vmlinux 0x805aae6a tty_ldisc_ref +EXPORT_SYMBOL_GPL vmlinux 0x8093e65f kobject_get_path +EXPORT_SYMBOL_GPL vmlinux 0x80ee55c3 selinux_secmark_refcount_inc +EXPORT_SYMBOL_GPL vmlinux 0x80ef327a rtnl_kill_links +EXPORT_SYMBOL_GPL vmlinux 0x817b0855 __cpufreq_driver_getavg +EXPORT_SYMBOL_GPL vmlinux 0x81e634d0 class_interface_register +EXPORT_SYMBOL_GPL vmlinux 0x8226642f __gpio_cansleep +EXPORT_SYMBOL_GPL vmlinux 0x826360fd do_posix_clock_nonanosleep +EXPORT_SYMBOL_GPL vmlinux 0x82cd19f3 register_xenstore_notifier +EXPORT_SYMBOL_GPL vmlinux 0x82d79b51 sysctl_vfs_cache_pressure +EXPORT_SYMBOL_GPL vmlinux 0x82f5273b register_timer_hook +EXPORT_SYMBOL_GPL vmlinux 0x82f776b7 gpio_export +EXPORT_SYMBOL_GPL vmlinux 0x83357346 macvlan_handle_frame_hook +EXPORT_SYMBOL_GPL vmlinux 0x845959f6 debugfs_create_symlink +EXPORT_SYMBOL_GPL vmlinux 0x84f004d7 led_trigger_remove +EXPORT_SYMBOL_GPL vmlinux 0x85c10896 rcu_batches_completed_bh +EXPORT_SYMBOL_GPL vmlinux 0x85d7edfd hpet_set_periodic_freq +EXPORT_SYMBOL_GPL vmlinux 0x85e5a3db ktime_get_ts +EXPORT_SYMBOL_GPL vmlinux 0x86623fd7 notify_remote_via_irq +EXPORT_SYMBOL_GPL vmlinux 0x8685873a input_ff_erase +EXPORT_SYMBOL_GPL vmlinux 0x868784cb __symbol_get +EXPORT_SYMBOL_GPL vmlinux 0x86a51007 gnttab_end_foreign_transfer +EXPORT_SYMBOL_GPL vmlinux 0x86b1667d hwrng_unregister +EXPORT_SYMBOL_GPL vmlinux 0x86bcbc37 pci_restore_msi_state +EXPORT_SYMBOL_GPL vmlinux 0x86d9791b sysdev_class_register +EXPORT_SYMBOL_GPL vmlinux 0x870404b8 crypto_chain +EXPORT_SYMBOL_GPL vmlinux 0x873fbaea edac_atomic_assert_error +EXPORT_SYMBOL_GPL vmlinux 0x876b550b spi_register_master +EXPORT_SYMBOL_GPL vmlinux 0x87754115 raw_notifier_chain_register +EXPORT_SYMBOL_GPL vmlinux 0x87c58029 single_open_net +EXPORT_SYMBOL_GPL vmlinux 0x880b189a __atomic_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x8810ad5e crypto_xor +EXPORT_SYMBOL_GPL vmlinux 0x885142a6 nf_net_netfilter_sysctl_path +EXPORT_SYMBOL_GPL vmlinux 0x885507b8 platform_get_resource +EXPORT_SYMBOL_GPL vmlinux 0x886736fc olpc_platform_info +EXPORT_SYMBOL_GPL vmlinux 0x88e08b03 rtc_device_register +EXPORT_SYMBOL_GPL vmlinux 0x88fa86e2 copy_fs_struct +EXPORT_SYMBOL_GPL vmlinux 0x89d887ad device_unregister +EXPORT_SYMBOL_GPL vmlinux 0x89f70321 raw_seq_open +EXPORT_SYMBOL_GPL vmlinux 0x89fc4eef cpufreq_cpu_put +EXPORT_SYMBOL_GPL vmlinux 0x8a8e8460 nf_unregister_queue_handlers +EXPORT_SYMBOL_GPL vmlinux 0x8abed13d xfrm_aead_get_byname +EXPORT_SYMBOL_GPL vmlinux 0x8b338829 inet6_lookup_listener +EXPORT_SYMBOL_GPL vmlinux 0x8bbf79e5 queue_delayed_work_on +EXPORT_SYMBOL_GPL vmlinux 0x8bf964f7 cpuidle_enable_device +EXPORT_SYMBOL_GPL vmlinux 0x8c06a108 xenbus_transaction_start +EXPORT_SYMBOL_GPL vmlinux 0x8c38074a unregister_xenstore_notifier +EXPORT_SYMBOL_GPL vmlinux 0x8c5d4f5e disk_round_stats +EXPORT_SYMBOL_GPL vmlinux 0x8c65e490 relay_reset +EXPORT_SYMBOL_GPL vmlinux 0x8d009047 __trace_note_message +EXPORT_SYMBOL_GPL vmlinux 0x8d535ca3 rtc_irq_unregister +EXPORT_SYMBOL_GPL vmlinux 0x8d5d1bd1 user_update +EXPORT_SYMBOL_GPL vmlinux 0x8dd7827c pid_vnr +EXPORT_SYMBOL_GPL vmlinux 0x8dd78d25 blocking_notifier_chain_register +EXPORT_SYMBOL_GPL vmlinux 0x8e6d9a0a user_read +EXPORT_SYMBOL_GPL vmlinux 0x8eb58c6e __wake_up_sync +EXPORT_SYMBOL_GPL vmlinux 0x8eb5ea3a relay_switch_subbuf +EXPORT_SYMBOL_GPL vmlinux 0x8ec3b09b rtc_irq_register +EXPORT_SYMBOL_GPL vmlinux 0x8f6cee77 __round_jiffies_relative +EXPORT_SYMBOL_GPL vmlinux 0x8f88e8c4 debugfs_create_u32 +EXPORT_SYMBOL_GPL vmlinux 0x8f9ad498 nf_register_afinfo +EXPORT_SYMBOL_GPL vmlinux 0x8fc653c0 queue_work +EXPORT_SYMBOL_GPL vmlinux 0x8fd5c28c devres_get +EXPORT_SYMBOL_GPL vmlinux 0x8ff8dbcd blocking_notifier_chain_cond_register +EXPORT_SYMBOL_GPL vmlinux 0x9009602a acpi_bus_get_ejd +EXPORT_SYMBOL_GPL vmlinux 0x902909e8 platform_driver_unregister +EXPORT_SYMBOL_GPL vmlinux 0x906b805e srcu_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x90a1004a crypto_has_alg +EXPORT_SYMBOL_GPL vmlinux 0x9111285d cpufreq_register_governor +EXPORT_SYMBOL_GPL vmlinux 0x9118a6df rt_mutex_trylock +EXPORT_SYMBOL_GPL vmlinux 0x9146276a device_add +EXPORT_SYMBOL_GPL vmlinux 0x91464a76 led_trigger_unregister_simple +EXPORT_SYMBOL_GPL vmlinux 0x9159b9d6 profile_event_register +EXPORT_SYMBOL_GPL vmlinux 0x917ee697 sysfs_create_bin_file +EXPORT_SYMBOL_GPL vmlinux 0x918a7a47 get_current_tty +EXPORT_SYMBOL_GPL vmlinux 0x91c9a0d4 attribute_container_unregister +EXPORT_SYMBOL_GPL vmlinux 0x91dacaa2 acpi_processor_ffh_cstate_probe +EXPORT_SYMBOL_GPL vmlinux 0x9241c3ee device_power_down +EXPORT_SYMBOL_GPL vmlinux 0x92445aee hrtimer_get_res +EXPORT_SYMBOL_GPL vmlinux 0x9261bf09 blk_end_request_callback +EXPORT_SYMBOL_GPL vmlinux 0x926bcccd driver_find_device +EXPORT_SYMBOL_GPL vmlinux 0x92fb217b dcookie_unregister +EXPORT_SYMBOL_GPL vmlinux 0x933740ca cancel_work_sync +EXPORT_SYMBOL_GPL vmlinux 0x93d2422d snmp_mib_free +EXPORT_SYMBOL_GPL vmlinux 0x942c1704 cleanup_srcu_struct +EXPORT_SYMBOL_GPL vmlinux 0x94b6fa1d k_handler +EXPORT_SYMBOL_GPL vmlinux 0x952664c5 do_exit +EXPORT_SYMBOL_GPL vmlinux 0x956a91ba gpio_get_value_cansleep +EXPORT_SYMBOL_GPL vmlinux 0x9577271c hpet_rtc_interrupt +EXPORT_SYMBOL_GPL vmlinux 0x958377be page_cache_async_readahead +EXPORT_SYMBOL_GPL vmlinux 0x961a8cd3 unlock_policy_rwsem_read +EXPORT_SYMBOL_GPL vmlinux 0x96b279ad rtnl_link_register +EXPORT_SYMBOL_GPL vmlinux 0x96cbcf31 pm_qos_add_notifier +EXPORT_SYMBOL_GPL vmlinux 0x97c6e495 xfrm_audit_state_icvfail +EXPORT_SYMBOL_GPL vmlinux 0x97d5fe75 inet6_hash_connect +EXPORT_SYMBOL_GPL vmlinux 0x97ddbfff dev_set_name +EXPORT_SYMBOL_GPL vmlinux 0x9833bc0c hvc_kick +EXPORT_SYMBOL_GPL vmlinux 0x995d1071 prof_on +EXPORT_SYMBOL_GPL vmlinux 0x9a11a0fc crypto_attr_alg_name +EXPORT_SYMBOL_GPL vmlinux 0x9a398f5c xfrm_ealg_get_byname +EXPORT_SYMBOL_GPL vmlinux 0x9a66d738 fib_rules_lookup +EXPORT_SYMBOL_GPL vmlinux 0x9b3f6a94 inet_hash_connect +EXPORT_SYMBOL_GPL vmlinux 0x9b830fb6 alloc_page_buffers +EXPORT_SYMBOL_GPL vmlinux 0x9ba0501e unregister_vt_notifier +EXPORT_SYMBOL_GPL vmlinux 0x9c1513d9 inotify_init_watch +EXPORT_SYMBOL_GPL vmlinux 0x9c65c062 __mmu_notifier_register +EXPORT_SYMBOL_GPL vmlinux 0x9cb8037b xfrm_count_enc_supported +EXPORT_SYMBOL_GPL vmlinux 0x9d06688b register_xenbus_watch +EXPORT_SYMBOL_GPL vmlinux 0x9d3850e1 gnttab_alloc_grant_references +EXPORT_SYMBOL_GPL vmlinux 0x9d553257 __inet_lookup_established +EXPORT_SYMBOL_GPL vmlinux 0x9d957902 bus_find_device_by_name +EXPORT_SYMBOL_GPL vmlinux 0x9df2bea6 dnotify_parent +EXPORT_SYMBOL_GPL vmlinux 0x9e100628 inet_hash +EXPORT_SYMBOL_GPL vmlinux 0x9e355fd3 sysfs_schedule_callback +EXPORT_SYMBOL_GPL vmlinux 0x9e53efb5 skb_icv_walk +EXPORT_SYMBOL_GPL vmlinux 0x9e711ad2 pm_qos_requirement +EXPORT_SYMBOL_GPL vmlinux 0x9e7d3442 xenbus_resume +EXPORT_SYMBOL_GPL vmlinux 0x9eae490d device_create +EXPORT_SYMBOL_GPL vmlinux 0x9ec7c07e audit_log_vformat +EXPORT_SYMBOL_GPL vmlinux 0x9f33279b seq_release_net +EXPORT_SYMBOL_GPL vmlinux 0x9f61c05d tty_wakeup +EXPORT_SYMBOL_GPL vmlinux 0x9fa44d83 input_ff_destroy +EXPORT_SYMBOL_GPL vmlinux 0x9fa62488 fnotify_change +EXPORT_SYMBOL_GPL vmlinux 0x9fce80db fb_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x9ffe62a5 class_find_device +EXPORT_SYMBOL_GPL vmlinux 0xa0255440 net_ipv4_ctl_path +EXPORT_SYMBOL_GPL vmlinux 0xa0612a38 inet_unhash +EXPORT_SYMBOL_GPL vmlinux 0xa089f7f8 bus_register_notifier +EXPORT_SYMBOL_GPL vmlinux 0xa1011ab0 put_pid +EXPORT_SYMBOL_GPL vmlinux 0xa101bf38 debugfs_create_blob +EXPORT_SYMBOL_GPL vmlinux 0xa1596d98 acpi_processor_ffh_cstate_enter +EXPORT_SYMBOL_GPL vmlinux 0xa185e32d inet_twsk_schedule +EXPORT_SYMBOL_GPL vmlinux 0xa2c03841 bind_evtchn_to_irqhandler +EXPORT_SYMBOL_GPL vmlinux 0xa2e1bb99 register_pernet_subsys +EXPORT_SYMBOL_GPL vmlinux 0xa2e67f08 acpi_bus_generate_proc_event4 +EXPORT_SYMBOL_GPL vmlinux 0xa353fffc xenbus_rm +EXPORT_SYMBOL_GPL vmlinux 0xa39d98e7 led_trigger_event +EXPORT_SYMBOL_GPL vmlinux 0xa3fc96f0 marker_probe_cb_noarg +EXPORT_SYMBOL_GPL vmlinux 0xa415249a input_class +EXPORT_SYMBOL_GPL vmlinux 0xa439ae9a debugfs_create_u64 +EXPORT_SYMBOL_GPL vmlinux 0xa447d0a0 pskb_put +EXPORT_SYMBOL_GPL vmlinux 0xa447e0eb debugfs_create_file +EXPORT_SYMBOL_GPL vmlinux 0xa452c297 hpet_mask_rtc_irq_bit +EXPORT_SYMBOL_GPL vmlinux 0xa4a5cc45 crypto_mod_put +EXPORT_SYMBOL_GPL vmlinux 0xa4a8f73d device_release_driver +EXPORT_SYMBOL_GPL vmlinux 0xa59dad3a vfs_setlease +EXPORT_SYMBOL_GPL vmlinux 0xa5bf5c3e pm_qos_add_requirement +EXPORT_SYMBOL_GPL vmlinux 0xa5c36cec inotify_unmount_inodes +EXPORT_SYMBOL_GPL vmlinux 0xa6ffad5e unregister_net_sysctl_table +EXPORT_SYMBOL_GPL vmlinux 0xa74158c6 skb_cow_data +EXPORT_SYMBOL_GPL vmlinux 0xa8f59416 gpio_direction_output +EXPORT_SYMBOL_GPL vmlinux 0xa9005668 blk_rq_bytes +EXPORT_SYMBOL_GPL vmlinux 0xa90427a3 sk_setup_caps +EXPORT_SYMBOL_GPL vmlinux 0xa9126bff hpet_set_rtc_irq_bit +EXPORT_SYMBOL_GPL vmlinux 0xa956a362 register_jprobe +EXPORT_SYMBOL_GPL vmlinux 0xa963f49c tcp_orphan_count +EXPORT_SYMBOL_GPL vmlinux 0xa9928dee xenbus_watch_path +EXPORT_SYMBOL_GPL vmlinux 0xa9c530b8 unregister_oom_notifier +EXPORT_SYMBOL_GPL vmlinux 0xa9eabac9 platform_device_add_data +EXPORT_SYMBOL_GPL vmlinux 0xa9fc6d8b spi_busnum_to_master +EXPORT_SYMBOL_GPL vmlinux 0xaa2a72bf __iowrite64_copy +EXPORT_SYMBOL_GPL vmlinux 0xaa8c4696 cpu_clock +EXPORT_SYMBOL_GPL vmlinux 0xaae5794a inet_csk_addr2sockaddr +EXPORT_SYMBOL_GPL vmlinux 0xab01acbe gnttab_request_free_callback +EXPORT_SYMBOL_GPL vmlinux 0xabb45429 inet_csk_bind_conflict +EXPORT_SYMBOL_GPL vmlinux 0xabc28976 force_evtchn_callback +EXPORT_SYMBOL_GPL vmlinux 0xac0292be blocking_notifier_chain_unregister +EXPORT_SYMBOL_GPL vmlinux 0xac241063 platform_device_unregister +EXPORT_SYMBOL_GPL vmlinux 0xac5204fb inet_diag_register +EXPORT_SYMBOL_GPL vmlinux 0xacc19485 ibft_addr +EXPORT_SYMBOL_GPL vmlinux 0xaccfc678 cpu_bit_bitmap +EXPORT_SYMBOL_GPL vmlinux 0xad096363 xenbus_printf +EXPORT_SYMBOL_GPL vmlinux 0xad15be26 crypto_lookup_template +EXPORT_SYMBOL_GPL vmlinux 0xad943b4c skb_morph +EXPORT_SYMBOL_GPL vmlinux 0xae0c87ee pm_qos_remove_notifier +EXPORT_SYMBOL_GPL vmlinux 0xae466e29 xenbus_switch_state +EXPORT_SYMBOL_GPL vmlinux 0xae84f02d cpufreq_unregister_governor +EXPORT_SYMBOL_GPL vmlinux 0xae9b1752 hvc_poll +EXPORT_SYMBOL_GPL vmlinux 0xaeb7f977 __blocking_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0xaf00f091 pci_destroy_slot +EXPORT_SYMBOL_GPL vmlinux 0xaf16ec38 cpuidle_register_driver +EXPORT_SYMBOL_GPL vmlinux 0xb021c3d3 devres_add +EXPORT_SYMBOL_GPL vmlinux 0xb0ab9f8c flush_work +EXPORT_SYMBOL_GPL vmlinux 0xb10d55bc cn_netlink_send +EXPORT_SYMBOL_GPL vmlinux 0xb120ab95 klist_remove +EXPORT_SYMBOL_GPL vmlinux 0xb1a6196c ip_route_output_flow +EXPORT_SYMBOL_GPL vmlinux 0xb1acbcce rcu_barrier_sched +EXPORT_SYMBOL_GPL vmlinux 0xb20df77d tty_buffer_request_room +EXPORT_SYMBOL_GPL vmlinux 0xb27005f5 device_suspend +EXPORT_SYMBOL_GPL vmlinux 0xb28c5cad raw_seq_start +EXPORT_SYMBOL_GPL vmlinux 0xb305fa4b bus_remove_file +EXPORT_SYMBOL_GPL vmlinux 0xb313a59e unregister_kprobe +EXPORT_SYMBOL_GPL vmlinux 0xb3253ed9 hpet_rtc_timer_init +EXPORT_SYMBOL_GPL vmlinux 0xb3bace04 bd_claim_by_disk +EXPORT_SYMBOL_GPL vmlinux 0xb448b33a __pneigh_lookup +EXPORT_SYMBOL_GPL vmlinux 0xb45d615b kill_pid_info_as_uid +EXPORT_SYMBOL_GPL vmlinux 0xb4c3ea18 bus_register +EXPORT_SYMBOL_GPL vmlinux 0xb4e14553 gnttab_query_foreign_access +EXPORT_SYMBOL_GPL vmlinux 0xb4ea7cf7 kgdb_connected +EXPORT_SYMBOL_GPL vmlinux 0xb5193419 xattr_getsecurity +EXPORT_SYMBOL_GPL vmlinux 0xb51fbd64 edac_op_state +EXPORT_SYMBOL_GPL vmlinux 0xb53ae573 cpu_idle_wait +EXPORT_SYMBOL_GPL vmlinux 0xb5673101 invalidate_inode_pages2_range +EXPORT_SYMBOL_GPL vmlinux 0xb5674329 find_pid_ns +EXPORT_SYMBOL_GPL vmlinux 0xb56f2603 __mnt_is_readonly +EXPORT_SYMBOL_GPL vmlinux 0xb6230f1f gnttab_grant_foreign_access +EXPORT_SYMBOL_GPL vmlinux 0xb63550f5 __i2c_board_lock +EXPORT_SYMBOL_GPL vmlinux 0xb65091b3 selinux_secmark_refcount_dec +EXPORT_SYMBOL_GPL vmlinux 0xb684e001 inet_ctl_sock_create +EXPORT_SYMBOL_GPL vmlinux 0xb68f9d36 audit_log_d_path +EXPORT_SYMBOL_GPL vmlinux 0xb6bc49a9 __supported_pte_mask +EXPORT_SYMBOL_GPL vmlinux 0xb6bfe3f5 destroy_workqueue +EXPORT_SYMBOL_GPL vmlinux 0xb79b66e9 blk_trace_startstop +EXPORT_SYMBOL_GPL vmlinux 0xb7d7c12e hpet_set_alarm_time +EXPORT_SYMBOL_GPL vmlinux 0xb8f10cf2 xfrm_audit_state_notfound +EXPORT_SYMBOL_GPL vmlinux 0xb903674c scatterwalk_map_and_copy +EXPORT_SYMBOL_GPL vmlinux 0xb950b29c rt_mutex_lock +EXPORT_SYMBOL_GPL vmlinux 0xb963eed1 rtc_update_irq +EXPORT_SYMBOL_GPL vmlinux 0xb99d5837 xenbus_read +EXPORT_SYMBOL_GPL vmlinux 0xb9eb3aa9 add_uevent_var +EXPORT_SYMBOL_GPL vmlinux 0xba402c15 sysdev_register +EXPORT_SYMBOL_GPL vmlinux 0xba9b3a6f class_destroy +EXPORT_SYMBOL_GPL vmlinux 0xbac4c1ee kobject_uevent_env +EXPORT_SYMBOL_GPL vmlinux 0xbb0d4bf1 rtc_device_unregister +EXPORT_SYMBOL_GPL vmlinux 0xbb43b7ed uhci_reset_hc +EXPORT_SYMBOL_GPL vmlinux 0xbb502333 mm_kobj +EXPORT_SYMBOL_GPL vmlinux 0xbbb98859 edid_info +EXPORT_SYMBOL_GPL vmlinux 0xbc2eb3a5 power_supply_am_i_supplied +EXPORT_SYMBOL_GPL vmlinux 0xbc771ac5 pci_stop_bus_device +EXPORT_SYMBOL_GPL vmlinux 0xbd1eeb64 relay_buf_full +EXPORT_SYMBOL_GPL vmlinux 0xbd3ba53c netlink_has_listeners +EXPORT_SYMBOL_GPL vmlinux 0xbdcce1b1 register_kprobe +EXPORT_SYMBOL_GPL vmlinux 0xbe183f0b tcp_set_state +EXPORT_SYMBOL_GPL vmlinux 0xbebc45a5 rt_mutex_destroy +EXPORT_SYMBOL_GPL vmlinux 0xbfc0e78c pci_find_ext_capability +EXPORT_SYMBOL_GPL vmlinux 0xbfce9232 console_drivers +EXPORT_SYMBOL_GPL vmlinux 0xbfd1996d class_for_each_device +EXPORT_SYMBOL_GPL vmlinux 0xbfeada34 tcp_reno_ssthresh +EXPORT_SYMBOL_GPL vmlinux 0xc06bcadb spi_alloc_device +EXPORT_SYMBOL_GPL vmlinux 0xc097eb8e hrtimer_get_remaining +EXPORT_SYMBOL_GPL vmlinux 0xc0ed34aa bus_for_each_drv +EXPORT_SYMBOL_GPL vmlinux 0xc104f4fb securityfs_create_dir +EXPORT_SYMBOL_GPL vmlinux 0xc1177b03 debugfs_create_u16 +EXPORT_SYMBOL_GPL vmlinux 0xc16cbc91 fsstack_copy_inode_size +EXPORT_SYMBOL_GPL vmlinux 0xc1b9670d leds_list_lock +EXPORT_SYMBOL_GPL vmlinux 0xc248a3cf blk_rq_cur_bytes +EXPORT_SYMBOL_GPL vmlinux 0xc26351f8 bind_evtchn_to_irq +EXPORT_SYMBOL_GPL vmlinux 0xc2e7203b inotify_inode_is_dead +EXPORT_SYMBOL_GPL vmlinux 0xc2f5c042 platform_device_register_simple +EXPORT_SYMBOL_GPL vmlinux 0xc31be7c8 put_device +EXPORT_SYMBOL_GPL vmlinux 0xc34efe27 snmp_fold_field +EXPORT_SYMBOL_GPL vmlinux 0xc36420ce transport_class_unregister +EXPORT_SYMBOL_GPL vmlinux 0xc41520b1 sysfs_create_link +EXPORT_SYMBOL_GPL vmlinux 0xc42f2f94 xenbus_read_driver_state +EXPORT_SYMBOL_GPL vmlinux 0xc5397da6 xenbus_mkdir +EXPORT_SYMBOL_GPL vmlinux 0xc54e4ce3 blk_queue_dma_drain +EXPORT_SYMBOL_GPL vmlinux 0xc56c45b4 pci_intx +EXPORT_SYMBOL_GPL vmlinux 0xc574fd8a transport_add_device +EXPORT_SYMBOL_GPL vmlinux 0xc5d6815a apply_to_page_range +EXPORT_SYMBOL_GPL vmlinux 0xc63db010 unregister_pernet_device +EXPORT_SYMBOL_GPL vmlinux 0xc6a8eae2 relay_open +EXPORT_SYMBOL_GPL vmlinux 0xc6b402e5 __percpu_alloc_mask +EXPORT_SYMBOL_GPL vmlinux 0xc6cabb03 device_remove_file +EXPORT_SYMBOL_GPL vmlinux 0xc7ec11f6 atomic_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0xc81d40a6 hrtimer_cancel +EXPORT_SYMBOL_GPL vmlinux 0xc87c1f84 ktime_get +EXPORT_SYMBOL_GPL vmlinux 0xc87e487a sched_clock_idle_sleep_event +EXPORT_SYMBOL_GPL vmlinux 0xc8f843fe cpuidle_unregister_device +EXPORT_SYMBOL_GPL vmlinux 0xc9561772 fb_destroy_modelist +EXPORT_SYMBOL_GPL vmlinux 0xca81ea9a xenbus_transaction_end +EXPORT_SYMBOL_GPL vmlinux 0xcabe04de cpuidle_resume_and_unlock +EXPORT_SYMBOL_GPL vmlinux 0xcbc9b63c simple_attr_release +EXPORT_SYMBOL_GPL vmlinux 0xcbdbf956 device_rename +EXPORT_SYMBOL_GPL vmlinux 0xcbf20127 klist_iter_init +EXPORT_SYMBOL_GPL vmlinux 0xcc1f1c3d inet_twdr_hangman +EXPORT_SYMBOL_GPL vmlinux 0xcced21c2 xfrm_audit_state_notfound_simple +EXPORT_SYMBOL_GPL vmlinux 0xcdd6550e register_kprobes +EXPORT_SYMBOL_GPL vmlinux 0xcdd6e202 sysfs_create_file +EXPORT_SYMBOL_GPL vmlinux 0xcf0bfd12 start_thread +EXPORT_SYMBOL_GPL vmlinux 0xcf25c17b tcp_unregister_congestion_control +EXPORT_SYMBOL_GPL vmlinux 0xcf8557d0 xenbus_unmap_ring +EXPORT_SYMBOL_GPL vmlinux 0xcfc62aa8 skb_segment +EXPORT_SYMBOL_GPL vmlinux 0xcfcc83ad register_vt_notifier +EXPORT_SYMBOL_GPL vmlinux 0xd027a07d marker_probe_unregister +EXPORT_SYMBOL_GPL vmlinux 0xd03c7700 secure_ipv4_port_ephemeral +EXPORT_SYMBOL_GPL vmlinux 0xd0bab9aa uart_set_options +EXPORT_SYMBOL_GPL vmlinux 0xd0c05159 emergency_restart +EXPORT_SYMBOL_GPL vmlinux 0xd0df4bed blkdev_driver_ioctl +EXPORT_SYMBOL_GPL vmlinux 0xd124e095 pcie_port_bus_type +EXPORT_SYMBOL_GPL vmlinux 0xd12a813b sock_prot_inuse_add +EXPORT_SYMBOL_GPL vmlinux 0xd12ac59b olpc_ec_cmd +EXPORT_SYMBOL_GPL vmlinux 0xd16712f3 crypto_check_attr_type +EXPORT_SYMBOL_GPL vmlinux 0xd177204e spi_alloc_master +EXPORT_SYMBOL_GPL vmlinux 0xd17959f3 tty_ldisc_deref +EXPORT_SYMBOL_GPL vmlinux 0xd1aabf25 device_for_each_child +EXPORT_SYMBOL_GPL vmlinux 0xd1c0de74 pci_bus_max_busnr +EXPORT_SYMBOL_GPL vmlinux 0xd1c672a1 hwmon_device_register +EXPORT_SYMBOL_GPL vmlinux 0xd1f8dee0 bus_rescan_devices +EXPORT_SYMBOL_GPL vmlinux 0xd3b78da3 xenbus_suspend_cancel +EXPORT_SYMBOL_GPL vmlinux 0xd3e6ec04 tcp_is_cwnd_limited +EXPORT_SYMBOL_GPL vmlinux 0xd4b5d346 rtnl_put_cacheinfo +EXPORT_SYMBOL_GPL vmlinux 0xd55ea29a debugfs_remove_recursive +EXPORT_SYMBOL_GPL vmlinux 0xd5d2f027 platform_add_devices +EXPORT_SYMBOL_GPL vmlinux 0xd696e21e tty_ldisc_flush +EXPORT_SYMBOL_GPL vmlinux 0xd6d5fa53 __inet_hash_nolisten +EXPORT_SYMBOL_GPL vmlinux 0xd734a7c5 crypto_larval_lookup +EXPORT_SYMBOL_GPL vmlinux 0xd7d0159d power_supply_register +EXPORT_SYMBOL_GPL vmlinux 0xd7d79132 put_online_cpus +EXPORT_SYMBOL_GPL vmlinux 0xd7f1235e mnt_want_write +EXPORT_SYMBOL_GPL vmlinux 0xd89f2217 bus_for_each_dev +EXPORT_SYMBOL_GPL vmlinux 0xd903a420 tcp_slow_start +EXPORT_SYMBOL_GPL vmlinux 0xd9042fa8 scatterwalk_map +EXPORT_SYMBOL_GPL vmlinux 0xd9f650ac tty_ldisc_ref_wait +EXPORT_SYMBOL_GPL vmlinux 0xdaf4dfb3 fb_mode_option +EXPORT_SYMBOL_GPL vmlinux 0xdb2a1107 get_driver +EXPORT_SYMBOL_GPL vmlinux 0xdba957bb pci_scan_child_bus +EXPORT_SYMBOL_GPL vmlinux 0xdbaf10b1 power_supply_changed +EXPORT_SYMBOL_GPL vmlinux 0xdc046069 driver_find +EXPORT_SYMBOL_GPL vmlinux 0xdc5db777 queue_work_on +EXPORT_SYMBOL_GPL vmlinux 0xdcb23aa9 input_ff_create +EXPORT_SYMBOL_GPL vmlinux 0xdd5c4942 srcu_notifier_chain_register +EXPORT_SYMBOL_GPL vmlinux 0xdd669a85 rtc_read_alarm +EXPORT_SYMBOL_GPL vmlinux 0xdd88215b tcp_get_info +EXPORT_SYMBOL_GPL vmlinux 0xddba2a95 pci_find_ht_capability +EXPORT_SYMBOL_GPL vmlinux 0xddf75399 cpufreq_register_driver +EXPORT_SYMBOL_GPL vmlinux 0xdf368266 find_vpid +EXPORT_SYMBOL_GPL vmlinux 0xdf3c19ec cn_add_callback +EXPORT_SYMBOL_GPL vmlinux 0xdf936f4d platform_device_register +EXPORT_SYMBOL_GPL vmlinux 0xe0406b5a blocking_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0xe10a529d pci_block_user_cfg_access +EXPORT_SYMBOL_GPL vmlinux 0xe17a0741 devres_destroy +EXPORT_SYMBOL_GPL vmlinux 0xe22938d1 pciserial_remove_ports +EXPORT_SYMBOL_GPL vmlinux 0xe295c0ff is_hpet_enabled +EXPORT_SYMBOL_GPL vmlinux 0xe3039085 kobject_rename +EXPORT_SYMBOL_GPL vmlinux 0xe3687db4 driver_unregister +EXPORT_SYMBOL_GPL vmlinux 0xe3857604 crypto_mod_get +EXPORT_SYMBOL_GPL vmlinux 0xe486ca2e rtc_set_alarm +EXPORT_SYMBOL_GPL vmlinux 0xe48d5eac acpi_ec_add_query_handler +EXPORT_SYMBOL_GPL vmlinux 0xe4aecd41 vfs_lock_file +EXPORT_SYMBOL_GPL vmlinux 0xe4c331b6 acpi_os_unmap_memory +EXPORT_SYMBOL_GPL vmlinux 0xe4ca55f6 sched_setscheduler +EXPORT_SYMBOL_GPL vmlinux 0xe513afc0 cache_k8_northbridges +EXPORT_SYMBOL_GPL vmlinux 0xe530071c pm_qos_remove_requirement +EXPORT_SYMBOL_GPL vmlinux 0xe61a6d2f gpio_unexport +EXPORT_SYMBOL_GPL vmlinux 0xe6241888 spi_bus_type +EXPORT_SYMBOL_GPL vmlinux 0xe6488b47 cpufreq_notify_transition +EXPORT_SYMBOL_GPL vmlinux 0xe64d1bce generic_fh_to_dentry +EXPORT_SYMBOL_GPL vmlinux 0xe6543313 crypto_unregister_template +EXPORT_SYMBOL_GPL vmlinux 0xe674a5cb srcu_read_lock +EXPORT_SYMBOL_GPL vmlinux 0xe6883f06 xfrm_output_resume +EXPORT_SYMBOL_GPL vmlinux 0xe703cd32 sg_scsi_ioctl +EXPORT_SYMBOL_GPL vmlinux 0xe75b42f3 __blk_add_trace +EXPORT_SYMBOL_GPL vmlinux 0xe7fa47ad srcu_read_unlock +EXPORT_SYMBOL_GPL vmlinux 0xe832d049 lookup_instantiate_filp +EXPORT_SYMBOL_GPL vmlinux 0xe8a5ed88 rtc_set_time +EXPORT_SYMBOL_GPL vmlinux 0xe8bb067a put_driver +EXPORT_SYMBOL_GPL vmlinux 0xe93e49c3 devres_free +EXPORT_SYMBOL_GPL vmlinux 0xe9df60aa devm_kzalloc +EXPORT_SYMBOL_GPL vmlinux 0xe9f6e0fc debugfs_create_bool +EXPORT_SYMBOL_GPL vmlinux 0xea065e01 task_handoff_unregister +EXPORT_SYMBOL_GPL vmlinux 0xea0d8fab led_trigger_register_simple +EXPORT_SYMBOL_GPL vmlinux 0xeaff2e58 tty_find_polling_driver +EXPORT_SYMBOL_GPL vmlinux 0xeb8b8413 input_ff_upload +EXPORT_SYMBOL_GPL vmlinux 0xebe8f0bc __xenbus_register_frontend +EXPORT_SYMBOL_GPL vmlinux 0xec690ab0 __crypto_alg_lookup +EXPORT_SYMBOL_GPL vmlinux 0xed1b1c10 blk_trace_setup +EXPORT_SYMBOL_GPL vmlinux 0xed72c1d0 transport_class_register +EXPORT_SYMBOL_GPL vmlinux 0xedbc6f67 gnttab_end_foreign_access +EXPORT_SYMBOL_GPL vmlinux 0xede65e13 transport_remove_device +EXPORT_SYMBOL_GPL vmlinux 0xee69f1f7 xenbus_dev_error +EXPORT_SYMBOL_GPL vmlinux 0xeeffd3d9 kobject_uevent +EXPORT_SYMBOL_GPL vmlinux 0xef2dc7b9 power_supply_class +EXPORT_SYMBOL_GPL vmlinux 0xef33ae1d rtc_read_time +EXPORT_SYMBOL_GPL vmlinux 0xefab6c7f rt_mutex_lock_interruptible +EXPORT_SYMBOL_GPL vmlinux 0xefe1ffe0 inet_csk_route_req +EXPORT_SYMBOL_GPL vmlinux 0xefe21106 snmp_mib_init +EXPORT_SYMBOL_GPL vmlinux 0xeffba0d3 crypto_hash_type +EXPORT_SYMBOL_GPL vmlinux 0xf1676b41 user_describe +EXPORT_SYMBOL_GPL vmlinux 0xf184d189 kernel_power_off +EXPORT_SYMBOL_GPL vmlinux 0xf18fa97a register_pernet_gen_device +EXPORT_SYMBOL_GPL vmlinux 0xf1c38350 tcp_death_row +EXPORT_SYMBOL_GPL vmlinux 0xf2fca922 uart_parse_options +EXPORT_SYMBOL_GPL vmlinux 0xf37979fe vfs_kern_mount +EXPORT_SYMBOL_GPL vmlinux 0xf3e77fa6 rt_mutex_unlock +EXPORT_SYMBOL_GPL vmlinux 0xf4841f48 led_trigger_unregister +EXPORT_SYMBOL_GPL vmlinux 0xf487ce85 rtc_class_close +EXPORT_SYMBOL_GPL vmlinux 0xf499fdb2 rcu_barrier_bh +EXPORT_SYMBOL_GPL vmlinux 0xf4aebdc3 xenbus_suspend +EXPORT_SYMBOL_GPL vmlinux 0xf4cc4638 tcp_reno_min_cwnd +EXPORT_SYMBOL_GPL vmlinux 0xf4f47443 vlan_dev_vlan_id +EXPORT_SYMBOL_GPL vmlinux 0xf543be6a crypto_alloc_instance +EXPORT_SYMBOL_GPL vmlinux 0xf553318d cpuidle_pause_and_lock +EXPORT_SYMBOL_GPL vmlinux 0xf5945bac gnttab_free_grant_references +EXPORT_SYMBOL_GPL vmlinux 0xf5a691cd invalidate_bh_lrus +EXPORT_SYMBOL_GPL vmlinux 0xf5b6db29 audit_log_untrustedstring +EXPORT_SYMBOL_GPL vmlinux 0xf5b8ecc3 fb_deferred_io_open +EXPORT_SYMBOL_GPL vmlinux 0xf63b757c driver_for_each_device +EXPORT_SYMBOL_GPL vmlinux 0xf63ee07f skb_to_sgvec +EXPORT_SYMBOL_GPL vmlinux 0xf6bcbd73 hwrng_register +EXPORT_SYMBOL_GPL vmlinux 0xf7016530 xenbus_gather +EXPORT_SYMBOL_GPL vmlinux 0xf779cc02 cpuidle_unregister_driver +EXPORT_SYMBOL_GPL vmlinux 0xf79b0abe crypto_spawn_tfm +EXPORT_SYMBOL_GPL vmlinux 0xf7c4fb67 sysfs_update_group +EXPORT_SYMBOL_GPL vmlinux 0xf82f16b3 execute_in_process_context +EXPORT_SYMBOL_GPL vmlinux 0xf879147a rtc_irq_set_state +EXPORT_SYMBOL_GPL vmlinux 0xf8802492 print_stack_trace +EXPORT_SYMBOL_GPL vmlinux 0xf9238304 anon_transport_class_unregister +EXPORT_SYMBOL_GPL vmlinux 0xf97c4aae klist_iter_exit +EXPORT_SYMBOL_GPL vmlinux 0xf9a054b5 __round_jiffies +EXPORT_SYMBOL_GPL vmlinux 0xf9b0dc77 inotify_init +EXPORT_SYMBOL_GPL vmlinux 0xfa1f4662 scatterwalk_start +EXPORT_SYMBOL_GPL vmlinux 0xfa4df138 tty_get_pgrp +EXPORT_SYMBOL_GPL vmlinux 0xfa9b9761 inotify_inode_queue_event +EXPORT_SYMBOL_GPL vmlinux 0xfb08a8bd fib_rules_unregister +EXPORT_SYMBOL_GPL vmlinux 0xfb2a3293 math_state_restore +EXPORT_SYMBOL_GPL vmlinux 0xfb733dd2 cpuidle_disable_device +EXPORT_SYMBOL_GPL vmlinux 0xfbf9be5d register_oom_notifier +EXPORT_SYMBOL_GPL vmlinux 0xfbfcfa70 inet_csk_clone +EXPORT_SYMBOL_GPL vmlinux 0xfc0be0dc screen_glyph +EXPORT_SYMBOL_GPL vmlinux 0xfc5d3a4c xenbus_map_ring_valloc +EXPORT_SYMBOL_GPL vmlinux 0xfcc437fb hvc_instantiate +EXPORT_SYMBOL_GPL vmlinux 0xfd3930d7 unregister_timer_hook +EXPORT_SYMBOL_GPL vmlinux 0xfd51b281 gnttab_end_foreign_access_ref +EXPORT_SYMBOL_GPL vmlinux 0xfda74e28 user_destroy +EXPORT_SYMBOL_GPL vmlinux 0xfde0b92c crypto_larval_error +EXPORT_SYMBOL_GPL vmlinux 0xfde4baa8 register_net_sysctl_rotable +EXPORT_SYMBOL_GPL vmlinux 0xfdf1c041 per_cpu__gdt_page +EXPORT_SYMBOL_GPL vmlinux 0xfdfe6c26 crypto_dequeue_request +EXPORT_SYMBOL_GPL vmlinux 0xfe727411 get_phys_to_machine +EXPORT_SYMBOL_GPL vmlinux 0xfe990052 gpio_free +EXPORT_SYMBOL_GPL vmlinux 0xfecbff96 __mark_empty_function +EXPORT_SYMBOL_GPL vmlinux 0xff5a8cfe cn_del_callback +EXPORT_UNUSED_SYMBOL vmlinux 0x00000000 init_mm --- linux-2.6.27.orig/debian/abi/2.6.27-14.39/i386/generic.modules +++ linux-2.6.27/debian/abi/2.6.27-14.39/i386/generic.modules @@ -0,0 +1,2286 @@ +3c359 +3c501 +3c503 +3c505 +3c507 +3c509 +3c515 +3c523 +3c527 +3c574_cs +3c589_cs +3c59x +3w-9xxx +3w-xxxx +53c700 +6pack +8021q +8139cp +8139too +8250_accent +8250_boca +8250_exar_st16c554 +8250_fourport +8250_hub6 +8250_mca +82596 +8390 +8390p +9p +9pnet +9pnet_virtio +a100u2w +a3d +aacraid +abituguru +abituguru3 +abyss +ac +ac3200 +ac97_bus +acecad +acenic +acerhk +acer-wmi +acpi-cpufreq +acpiphp +acpiphp_ibm +acquirewdt +act2000 +act200l-sir +act_gact +act_ipt +actisys-sir +act_mirred +act_nat +act_pedit +act_police +act_simple +acx +ad1848 +ad7414 +ad7418 +adcxx +adfs +adi +adm1021 +adm1025 +adm1026 +adm1029 +adm1031 +adm8211 +adm9240 +ads7828 +ads7846 +adt7470 +adt7473 +adutux +adv7170 +adv7175 +advansys +advantechwdt +aead +aedsp16 +aes_generic +aes-i586 +affs +af_key +af_packet +af-rxrpc +agpgart +ah4 +ah6 +aha152x +aha152x_cs +aha1542 +aha1740 +ahci +aic79xx +aic7xxx +aic94xx +aiptek +aircable +airo +airo_cs +alauda +ali-agp +ali-ircc +alim1535_wdt +alim7101_wdt +ambassador +amd64-agp +amd76x_edac +amd76xrom +amd8111e +amd-k7-agp +amd-rng +analog +anubis +aoe +apm +appledisplay +appleir +applesmc +appletalk +appletouch +applicom +ar7part +arc4 +arcfb +arcmsr +arcnet +arc-rawmode +arc-rimi +ark3116 +arkfb +arlan +arptable_filter +arp_tables +arpt_mangle +asb100 +asix +asus-laptop +async_memcpy +async_tx +async_xor +at1700 +at24 +at25 +at76_usb +ata_generic +ata_piix +aten +ath9k +ati-agp +ati_remote +ati_remote2 +atl1 +atl1e +atl2 +atlas_btns +atmel +atmel_cs +atmel_pci +atmtcp +atp +atp870u +atxp1 +aty128fb +atyfb +au0828 +au8522 +aufs +authenc +auth_rpcgss +autofs +autofs4 +av5100 +avma1_cs +avm_cs +ax25 +axnet_cs +b1 +b1dma +b1isa +b1pci +b1pcmcia +b2c2-flexcop +b2c2-flexcop-pci +b2c2-flexcop-usb +b43 +b43legacy +b44 +bas_gigaset +battery +bay +baycom_epp +baycom_par +baycom_ser_fdx +baycom_ser_hdx +bcm203x +bcm3510 +bcm5974 +befs +belkin_sa +berry_charge +bfs +bfusb +binfmt_aout +binfmt_misc +bitblit +block2mtd +blowfish +bluecard_cs +bluetooth +bnep +bnx2 +bnx2x +bonding +bpa10x +bpck +bpck6 +bpqether +br2684 +bridge +broadcom +bsd_comp +bt3c_cs +bt819 +bt856 +bt878 +btcx-risc +btsdio +bttv +btuart_cs +btusb +budget +budget-av +budget-ci +budget-core +budget-patch +BusLogic +button +bw-qcam +c101 +c4 +c67x00 +cafe_ccic +cafe_nand +camellia +capi +capidrv +capifs +capmode +carminefb +cassini +cast5 +cast6 +catc +cbc +cciss +ccm +cdc-acm +cdc_ether +cdc_subset +cdc-wdm +cdrom +cfag12864b +cfag12864bfb +cfg80211 +cfi_cmdset_0001 +cfi_cmdset_0002 +cfi_cmdset_0020 +cfi_probe +cfi_util +ch +ch341 +chipreg +cicada +cifs +cinergyT2 +cirrusfb +ck804xrom +cls_basic +cls_fw +cls_route +cls_rsvp +cls_rsvp6 +cls_tcindex +cls_u32 +cm4000_cs +cm4040_cs +cmtp +cobra +coda +com20020 +com20020_cs +com20020-isa +com20020-pci +com90io +com90xx +comm +commandir +compal-laptop +compat_ioctl32 +compcache +configfs +container +coretemp +corgi_bl +cosa +cp2101 +cpcihp_generic +cpcihp_zt5550 +cpia +cpia2 +cpia_pp +cpia_usb +cpqarray +cpqphp +cpu5wdt +cpufreq_conservative +cpufreq-nforce2 +cpufreq_ondemand +cpufreq_powersave +cpufreq_stats +cpufreq_userspace +cpuid +c-qcam +cr_bllcd +crc16 +crc32c +crc7 +crc-ccitt +crc-itu-t +crc-t10dif +crvml +cryptd +crypto_blkcipher +cryptoloop +crypto_null +cs5345 +cs53l32a +cs5535_gpio +cs553x_nand +cs89x0 +ct82c710 +ctr +cts +cx18 +cx22700 +cx22702 +cx2341x +cx23885 +cx24110 +cx24123 +cx25840 +cx8800 +cx8802 +cx88-alsa +cx88-blackbird +cx88-dvb +cx88-vp3054-i2c +cx88xx +cxacru +cxgb +cxgb3 +cyber2000fb +cyberjack +cyblafb +cyclades +cyclomx +cycx_drv +cypress_cy7c63 +cypress_m8 +cytherm +DAC960 +davicom +db9 +dc395x +dca +dccp +dccp_ccid2 +dccp_ccid3 +dccp_diag +dccp_ipv4 +dccp_ipv6 +dccp_probe +dccp_tfrc_lib +dcdbas +de2104x +de4x5 +de600 +de620 +decnet +deflate +defxx +dell_rbu +depca +des_generic +dib0070 +dib3000mb +dib3000mc +dib7000m +dib7000p +dibx000_common +digi_acceleport +dilnetpc +diskonchip +display +divacapi +divadidd +diva_idi +diva_mnt +divas +dlci +dlm +dm9601 +dm-bbr +dm-crypt +dme1737 +dmfe +dm-log +dm-loop +dm-mem-cache +dm-message +dm-mirror +dm-mod +dm-multipath +dm-raid4-5 +dm-region_hash +dm-round-robin +dm-snapshot +dmx3191d +dm-zero +dn_rtmsg +doc2000 +doc2001 +doc2001plus +docecc +dock +docprobe +donauboe +dpc7146 +dpt_i2o +drbd +drm +drx397xD +ds1621 +ds1682 +ds2482 +ds2490 +ds2760_battery +dsbr100 +dscc4 +dss1_divert +dst +dst_ca +dstr +dtc +dtl1_cs +dtlk +dummy +dv1394 +dvb-bt8xx +dvb-core +dvb-pll +dvb-ttpci +dvb-ttusb-budget +dvb-usb +dvb-usb-a800 +dvb-usb-af9005 +dvb-usb-af9005-remote +dvb-usb-anysee +dvb-usb-au6610 +dvb-usb-cxusb +dvb-usb-dib0700 +dvb-usb-dibusb-common +dvb-usb-dibusb-mb +dvb-usb-dibusb-mc +dvb-usb-digitv +dvb-usb-dtt200u +dvb-usb-dw2102 +dvb-usb-gl861 +dvb-usb-gp8psk +dvb-usb-m920x +dvb-usb-nova-t-usb2 +dvb-usb-opera +dvb-usb-ttusb2 +dvb-usb-umt-010 +dvb-usb-vp702x +dvb-usb-vp7045 +e100 +e1000 +e1000e +e2100 +e752x_edac +e7xxx_edac +eata +ebt_802_3 +ebtable_broute +ebtable_filter +ebtable_nat +ebtables +ebt_among +ebt_arp +ebt_arpreply +ebt_dnat +ebt_ip +ebt_ip6 +ebt_limit +ebt_log +ebt_mark +ebt_mark_m +ebt_nflog +ebt_pkttype +ebt_redirect +ebt_snat +ebt_stp +ebt_ulog +ebt_vlan +ecb +econet +ecryptfs +edac_core +eeepc-laptop +eepro +eepro100 +eeprom +eeprom_93cx6 +eexpress +efficeon-agp +efs +ehci-hcd +elo +elsa_cs +em28xx +em28xx-alsa +em28xx-dvb +em_cmp +emi26 +emi62 +em_meta +em_nbyte +empeg +em_text +emu10k1-gp +em_u32 +enclosure +eni +epat +epca +epia +epic100 +eql +es3210 +esb2rom +esi-sir +esp +esp4 +esp6 +et131x +et61x251 +eth1394 +eth16i +eurotechwdt +evbug +evdev +ewrk3 +exportfs +ext2 +ext3 +ext4dev +f71805f +f71882fg +f75375s +fakephp +fan +farsync +fat +faulty +fbcon +fb_ddc +fb_sys_fops +fcrypt +fd_mcs +fdomain +fdomain_cs +fealnx +ff-memless +firestream +fit2 +fit3 +floppy +fm801-gp +fmvj18x_cs +font +forcedeth +fore_200e +freevxfs +freq_table +friq +frpw +fsam7400 +fscher +fschmd +fscpos +ftdi-elan +ftdi_sio +ftl +fujitsu-laptop +fujitsu_ts +funsoft +fuse +g450_pll +gadgetfs +gamecon +gameport +garmin_gps +garp +g_cdc +gcm +gdth +generic_serial +gen_probe +geode-aes +geode-rng +g_ether +gf128mul +gf2k +g_file_storage +gfs +gfs2 +gigaset +girbil-sir +gl518sm +gl520sm +gl620a +gnbd +g_NCR5380 +g_NCR5380_mmio +gpio_keys +gpio_mouse +grip +grip_mp +g_serial +gspca_conex +gspca_etoms +gspca_main +gspca_mars +gspca_ov519 +gspca_pac207 +gspca_pac7311 +gspca_sonixb +gspca_sonixj +gspca_spca500 +gspca_spca501 +gspca_spca505 +gspca_spca506 +gspca_spca508 +gspca_spca561 +gspca_stk014 +gspca_sunplus +gspca_t613 +gspca_tv8532 +gspca_vc032x +gspca_zc3xx +gtco +guillemot +gunze +gx1fb +gxfb +gx-suspmod +g_zero +hamachi +hangcheck-timer +hci_uart +hci_vhci +hdaps +hdlc +hdlc_cisco +hdlcdrv +hdlc_fr +hdlc_ppp +hdlc_raw +hdlc_raw_eth +hdlc_x25 +he +heci +hecubafb +hermes +hexium_gemini +hexium_orion +hfc4s8s_l1 +hfcmulti +hfcpci +hfc_usb +hfs +hfsplus +hgafb +hid +hidp +hifn_795x +hisax +hisax_fcpcipnp +hisax_isac +hisax_st5481 +horizon +hostap +hostap_cs +hostap_pci +hostap_plx +hostess_sv11 +hp +hp100 +hp4x +hpfs +hpilo +hp-plus +hptiop +hp-wmi +hso +htc-pasic3 +htcpen +hwmon-vid +hysdn +i2c-algo-bit +i2c-algo-pca +i2c-algo-pcf +i2c-ali1535 +i2c-ali1563 +i2c-ali15x3 +i2c-amd756 +i2c-amd756-s4882 +i2c-amd8111 +i2c-core +i2c-dev +i2c-gpio +i2c-i801 +i2c-isch +i2c-matroxfb +i2c-nforce2 +i2c-nforce2-s4985 +i2c-ocores +i2c-parport +i2c-parport-light +i2c-pca-isa +i2c-pca-platform +i2c-piix4 +i2c-simtec +i2c-sis5595 +i2c-sis630 +i2c-sis96x +i2c-stub +i2c-taos-evm +i2c-tiny-usb +i2c-via +i2c-viapro +i2c-voodoo3 +i2o_block +i2o_bus +i2o_config +i2o_core +i2o_proc +i2o_scsi +i3000_edac +i5000_edac +i5100_edac +i5k_amb +i6300esb +i810 +i810fb +i82092 +i82365 +i82860_edac +i82875p_edac +i82975x_edac +i830 +i8k +i915 +ib700wdt +ib_addr +ib_cm +ib_core +ib_ipoib +ib_iser +ib_mad +ibmaem +ibmasm +ibmasr +ibmcam +ibmlana +ibmmca +ibmpex +ibmphp +ib_mthca +ibmtr +ibmtr_cs +ib_sa +ib_srp +ib_ucm +ib_umad +ib_uverbs +ichxrom +icn +icplus +idmouse +idt77252 +ieee1394 +ieee80211 +ieee80211_crypt +ieee80211_crypt_ccmp +ieee80211_crypt_tkip +ieee80211_crypt_wep +ifb +iforce +igb +ili9320 +imm +in2000 +inet_lro +inexio +inftl +initio +inport +input-polldev +intel-agp +intelfb +intel_menlow +intel-rng +intel_vr_nor +interact +ioatdma +ioc4 +io_edgeport +io_ti +iowarrior +ip2 +ip6_queue +ip6table_filter +ip6table_mangle +ip6table_raw +ip6_tables +ip6table_security +ip6t_ah +ip6t_eui64 +ip6t_frag +ip6t_hbh +ip6t_HL +ip6t_hl +ip6t_ipv6header +ip6t_LOG +ip6t_mh +ip6t_REJECT +ip6t_rt +ip6_tunnel +ipaq +ipcomp +ipcomp6 +ipddp +ipg +ip_gre +iphase +ipip +ipmi_devintf +ipmi_msghandler +ipmi_poweroff +ipmi_si +ipmi_watchdog +ip_queue +ipr +ips +iptable_filter +iptable_mangle +iptable_nat +iptable_raw +ip_tables +iptable_security +ipt_addrtype +ipt_ah +ipt_CLUSTERIP +ipt_ECN +ipt_ecn +ipt_LOG +ipt_MASQUERADE +ipt_NETMAP +ipt_recent +ipt_REDIRECT +ipt_REJECT +ipt_TTL +ipt_ttl +ipt_ULOG +ipv6 +ip_vs +ip_vs_dh +ip_vs_ftp +ip_vs_lblc +ip_vs_lblcr +ip_vs_lc +ip_vs_nq +ip_vs_rr +ip_vs_sed +ip_vs_sh +ip_vs_wlc +ip_vs_wrr +ipw +ipw2100 +ipw2200 +ipwireless +ipx +ircomm +ir-common +ircomm-tty +irda +irda-usb +ir-kbd-i2c +irlan +irnet +irtty-sir +iscsi_ibft +iscsi_tcp +iscsi_trgt +isdn +isdn_bsdcomp +isdnhdlc +isight_firmware +isl6405 +isl6421 +isofs +isp116x-hcd +isp1760 +it87 +it8712f_wdt +iTCO_vendor_support +iTCO_wdt +itd1000 +ivtv +ivtvfb +iw_c2 +iw_cm +iw_cxgb3 +iwl3945 +iwlagn +iwlcore +ixgb +ixgbe +ixj +ixj_pcmcia +jbd +jbd2 +jedec_probe +jffs2 +jfs +joydev +joydump +jsm +k8temp +kafs +kahlua +kaweth +kbic +kbtab +kernelcapi +keyspan +keyspan_pda +keyspan_remote +khazad +kingsun-sir +kl5kusb105 +kobil_sct +konicawc +ks0108 +ks0127 +ks959-sir +ksdazzle-sir +ktti +kvm +kvm-amd +kvm-intel +kyrofb +l1oip +l2cap +l440gx +l64781 +lanai +lance +lanstreamer +lapb +lapbether +lcd +ldusb +lec +led-class +leds-gpio +leds-net48xx +leds-pca9532 +leds-pca955x +leds-wrap +ledtrig-default-on +ledtrig-heartbeat +ledtrig-timer +legousbtower +lgdt330x +libata +libcrc32c +libertas +libertas_cs +libertas_sdio +libiscsi +libphy +libsas +libsrp +libusual +lightning +linear +lirc_atiusb +lirc_bt829 +lirc_cmdir +lirc_dev +lirc_i2c +lirc_igorplugusb +lirc_imon +lirc_it87 +lirc_mceusb +lirc_mceusb2 +lirc_pvr150 +lirc_sasem +lirc_serial +lirc_serial_igor +lirc_sir +lirc_streamzap +lirc_ttusbir +litelink-sir +lkkbd +llc2 +lm63 +lm70 +lm75 +lm77 +lm78 +lm80 +lm83 +lm85 +lm87 +lm90 +lm92 +lm93 +lmc +lmpcm_usb +lnbp21 +lne390 +lockd +lock_dlm +logibm +longhaul +longrun +loop +lp +lp486e +lpfc +lrw +ltpc +ltv350qv +lxfb +lxt +lzo +lzo_compress +lzo_decompress +m25p80 +m52790 +ma600-sir +mac80211 +machzwd +macmodes +macvlan +madgemc +magellan +map_absent +map_funcs +map_ram +map_rom +marvell +matroxfb_accel +matroxfb_base +matroxfb_crtc2 +matroxfb_DAC1064 +matroxfb_g450 +matroxfb_maven +matroxfb_misc +matroxfb_Ti3026 +matrox_w1 +max1619 +max6650 +max6875 +max7301 +max732x +mbcache +mbp_nvidia_bl +mcp2120-sir +mcp23s08 +mcs7780 +mcs7830 +mct_u232 +md4 +mdacon +mdc800 +mdio-bitbang +md-mod +megaraid +megaraid_mbox +megaraid_mm +megaraid_sas +meye +mga +michael_mic +microcode +microtek +mii +minix +mISDN_core +mISDN_dsp +mixcomwd +mk712 +mkiss +mlx4_core +mlx4_ib +mmc_block +mmc_core +mos7720 +mos7840 +moto_modem +moxa +mpoa +mptbase +mptctl +mptfc +mptlan +mptsas +mptscsih +mptspi +mpu401 +msdos +msi-laptop +msnd +msnd_classic +msnd_pinnacle +msp3400 +msr +mt2060 +mt20xx +mt2131 +mt2266 +mt312 +mt352 +mt9m001 +mt9v022 +mtd +mtd_blkdevs +mtdblock +mtdblock_ro +mtdchar +mtdconcat +mtd_dataflash +mtdoops +mtdram +mtouch +multipath +mwave +mxb +mxl5005s +mxl5007t +mxser +myri10ge +n2 +nand +nand_ecc +nand_ids +nandsim +natsemi +navman +nbd +ncpfs +NCR53c406a +NCR_D700 +NCR_Q720_mod +ndiswrapper +ne +ne2 +ne2k-pci +ne3210 +neofb +net1080 +net2280 +netconsole +netrom +netsc520 +nettel +netwave_cs +netxen_nic +newtonkbd +nf_conntrack +nf_conntrack_amanda +nf_conntrack_ftp +nf_conntrack_h323 +nf_conntrack_ipv4 +nf_conntrack_ipv6 +nf_conntrack_irc +nf_conntrack_netbios_ns +nf_conntrack_netlink +nf_conntrack_pptp +nf_conntrack_proto_gre +nf_conntrack_proto_sctp +nf_conntrack_proto_udplite +nf_conntrack_sip +nf_conntrack_tftp +nf_nat +nf_nat_amanda +nf_nat_ftp +nf_nat_h323 +nf_nat_irc +nf_nat_pptp +nf_nat_proto_gre +nf_nat_proto_sctp +nf_nat_proto_udplite +nf_nat_sip +nf_nat_snmp_basic +nf_nat_tftp +nfnetlink +nfnetlink_log +nfnetlink_queue +nfs +nfs_acl +nfsd +nftl +n_hdlc +ni52 +ni65 +nicstar +niu +nls_ascii +nls_cp1250 +nls_cp1251 +nls_cp1255 +nls_cp437 +nls_cp737 +nls_cp775 +nls_cp850 +nls_cp852 +nls_cp855 +nls_cp857 +nls_cp860 +nls_cp861 +nls_cp862 +nls_cp863 +nls_cp864 +nls_cp865 +nls_cp866 +nls_cp869 +nls_cp874 +nls_cp932 +nls_cp936 +nls_cp949 +nls_cp950 +nls_euc-jp +nls_iso8859-1 +nls_iso8859-13 +nls_iso8859-14 +nls_iso8859-15 +nls_iso8859-2 +nls_iso8859-3 +nls_iso8859-4 +nls_iso8859-5 +nls_iso8859-6 +nls_iso8859-7 +nls_iso8859-9 +nls_koi8-r +nls_koi8-ru +nls_koi8-u +nls_utf8 +nmclan_cs +nozomi +n_r3964 +ns558 +ns83820 +nsc_gpio +nsc-ircc +nsp32 +nsp_cs +ntfs +nvidia-agp +nvidiafb +nvram +nxt200x +nxt6000 +ocfs2 +ocfs2_dlm +ocfs2_dlmfs +ocfs2_nodemanager +ocfs2_stackglue +ocfs2_stack_o2cb +ocfs2_stack_user +ohci1394 +ohci-hcd +old_belkin-sir +olpc_battery +olympic +omfs +omninet +on20 +on26 +onenand +onenand_sim +opl3 +oprofile +option +or51132 +or51211 +orinoco +orinoco_cs +orinoco_nortel +orinoco_pci +orinoco_plx +orinoco_tmd +osst +oti6858 +output +ov511 +ov511_decomp +ov518_decomp +ov7670 +ovcamchip +p4-clockmod +p54common +p54pci +p54usb +p80211 +p8023 +padlock-aes +padlock-sha +paride +parkbd +parport +parport_ax88796 +parport_cs +parport_pc +parport_serial +pas16 +pas2 +pata_acpi +pata_ali +pata_amd +pata_artop +pata_atiixp +pata_cmd64x +pata_cs5520 +pata_cs5530 +pata_cs5535 +pata_cs5536 +pata_efar +pata_hpt366 +pata_hpt37x +pata_hpt3x3 +pata_it8213 +pata_it821x +pata_jmicron +pata_legacy +pata_marvell +pata_mpiix +pata_netcell +pata_ninja32 +pata_ns87410 +pata_ns87415 +pata_oldpiix +pata_pcmcia +pata_pdc2027x +pata_pdc202xx_old +pata_qdi +pata_rz1000 +pata_sch +pata_serverworks +pata_sil680 +pata_sis +pata_sl82c105 +pata_triflex +pata_via +pata_winbond +pbe5 +pc110pad +pc300 +pc87360 +pc8736x_gpio +pc87413_wdt +pc87427 +pca953x +pcbc +pcbit +pcd +pcf857x +pcf8591 +pci +pci200syn +pciehp +pci_hotplug +pcilynx +pcips2 +pci_slot +pcmcia +pcmcia_core +pcnet32 +pcnet_cs +pcspkr +pcwd +pcwd_pci +pcwd_usb +pd +pd6729 +pda_power +pdc_adma +pegasus +penmount +pf +pg +phantom +phidget +phidgetkit +phidgetmotorcontrol +phidgetservo +phonedev +phram +physmap +pktcdvd +pktgen +pl2303 +platform_lcd +plat_nand +plat-ram +plip +plusb +pluto2 +pm2fb +pm3fb +pmc551 +pms +powermate +powernow-k6 +powernow-k7 +powernow-k8 +ppa +ppdev +ppp_async +ppp_deflate +ppp_generic +ppp_mppe +pppoatm +pppoe +pppol2tp +pppox +ppp_synctty +prism2_usb +prism54 +processor +progear_bl +proteon +psmouse +pss +pt +pvrusb2 +pwc +qla1280 +qla2xxx +qla3xxx +qla4xxx +qlogic_cs +qlogicfas +qlogicfas408 +qnx4 +qsemi +qt1010 +quickcam +quickcam_messenger +quota_v1 +quota_v2 +r128 +r8169 +r82600_edac +r8a66597-hcd +radeon +radeonfb +radio-aimslab +radio-aztech +radio-cadet +radio-gemtek +radio-gemtek-pci +radio-maestro +radio-maxiradio +radio-rtrack2 +radio-sf16fmi +radio-sf16fmr2 +radio-si470x +radio-terratec +radio-trust +radio-typhoon +radio-zoltrix +raid0 +raid1 +raid10 +raid456 +raid_class +raw +raw1394 +ray_cs +rdma_cm +rdma_ucm +redboot +reed_solomon +reiserfs +rfc1051 +rfc1201 +rfcomm +rfd_ftl +rfkill +rfkill-input +ricoh_mmc +rio +rio500 +riscom8 +rivafb +rmd128 +rmd160 +rmd256 +rmd320 +rndis_host +rndis_wlan +rocket +romfs +rose +rpcsec_gss_krb5 +rpcsec_gss_spkm3 +rrunner +rsrc_nonstatic +rt2400pci +rt2500pci +rt2500usb +rt2x00lib +rt2x00pci +rt2x00usb +rt61pci +rt73usb +rtc-ds1305 +rtc-ds1307 +rtc-ds1374 +rtc-ds1553 +rtc-ds1672 +rtc-ds1742 +rtc-fm3130 +rtc-isl1208 +rtc-m41t80 +rtc-m41t94 +rtc-m48t59 +rtc-m48t86 +rtc-max6900 +rtc-max6902 +rtc-pcf8563 +rtc-pcf8583 +rtc-rs5c348 +rtc-rs5c372 +rtc-stk17ta8 +rtc-test +rtc-v3020 +rtc-x1205 +rtl8150 +rtl8180 +rtl8187 +rxkad +s1d13xxxfb +s2255drv +s2io +s3fb +s5h1409 +s5h1411 +s5h1420 +saa5246a +saa5249 +saa6588 +saa6752hs +saa7110 +saa7111 +saa7114 +saa7115 +saa7127 +saa7134 +saa7134-alsa +saa7134-dvb +saa7134-empress +saa7146 +saa7146_vv +saa717x +saa7185 +safe_serial +salsa20_generic +salsa20-i586 +sata_inic162x +sata_mv +sata_nv +sata_promise +sata_qstor +sata_sil +sata_sil24 +sata_sis +sata_svw +sata_sx4 +sata_uli +sata_via +sata_vsc +savage +savagefb +sb +sb1000 +sbc60xxwdt +sbc7240_wdt +sbc8360 +sbc_epx_c3 +sbc_gxx +sb_lib +sbni +sbp2 +sbs +sbshc +sc +sc1200wdt +sc520cdp +sc520_wdt +sc92031 +scb2_flash +scc +sch_atm +sch_cbq +sch_dsmark +sch_gred +sch_hfsc +sch_htb +sch_ingress +sch_netem +sch_prio +sch_red +sch_sfq +sch_tbf +sch_teql +sco +scsi_debug +scsi_dh +scsi_dh_alua +scsi_dh_emc +scsi_dh_hp_sw +scsi_dh_rdac +scsi_mod +scsi_tgt +scsi_transport_fc +scsi_transport_iscsi +scsi_transport_sas +scsi_transport_spi +scsi_transport_srp +scsi_wait_scan +sctp +scx200 +scx200_acb +scx200_docflash +scx200_gpio +scx200_hrt +scx200_i2c +scx200_wdt +sdhci +sdhci-pci +sdio_uart +sdla +sd_mod +sdricoh_cs +se401 +sealevel +sedlbauer_cs +seed +seeq8005 +seqiv +ser_gigaset +serial_cs +serio_raw +sermouse +serpent +serport +ses +sfc +sg +sha1_generic +sha256_generic +sha512_generic +sh_mobile_ceu_camera +shpchp +sidewinder +sierra +sim710 +sir-dev +sis +sis190 +sis5595 +sis900 +sis-agp +sisfb +sisusbvga +sit +skfp +skge +skisa +sky2 +sl811_cs +sl811-hcd +slhc +slip +slram +sm501 +sm501fb +smbfs +smc9194 +smc91c92_cs +smc-mca +smctr +smc-ultra +smc-ultra32 +sms1xxx +smsc +smsc37b787_wdt +smsc47b397 +smsc47m1 +smsc47m192 +smsc-ircc2 +sn9c102 +snd +snd-ac97-codec +snd-ad1816a +snd-ad1848 +snd-ad1848-lib +snd-ad1889 +snd-adlib +snd-ak4114 +snd-ak4117 +snd-ak4xxx-adda +snd-ali5451 +snd-als100 +snd-als300 +snd-als4000 +snd-atiixp +snd-atiixp-modem +snd-au8810 +snd-au8820 +snd-au8830 +snd-aw2 +snd-azt2320 +snd-azt3328 +snd-bt87x +snd-bt-sco +snd-ca0106 +snd-cmi8330 +snd-cmipci +snd-cs4231 +snd-cs4231-lib +snd-cs4232 +snd-cs4236 +snd-cs4236-lib +snd-cs4281 +snd-cs46xx +snd-cs5530 +snd-cs5535audio +snd-cs8427 +snd-darla20 +snd-darla24 +snd-dt019x +snd-dummy +snd-echo3g +snd-emu10k1 +snd-emu10k1-synth +snd-emu10k1x +snd-emu8000-synth +snd-emux-synth +snd-ens1370 +snd-ens1371 +snd-es1688 +snd-es1688-lib +snd-es18xx +snd-es1938 +snd-es1968 +snd-es968 +snd-fm801 +snd-gina20 +snd-gina24 +snd-gusclassic +snd-gusextreme +snd-gus-lib +snd-gusmax +snd-hda-intel +snd-hdsp +snd-hdspm +snd-hifier +snd-hwdep +snd-i2c +snd-ice1712 +snd-ice1724 +snd-ice17xx-ak4xxx +snd-indigo +snd-indigodj +snd-indigoio +snd-intel8x0 +snd-intel8x0m +snd-interwave +snd-interwave-stb +snd-korg1212 +snd-layla20 +snd-layla24 +snd-maestro3 +snd-mia +snd-miro +snd-mixart +snd-mixer-oss +snd-mona +snd-mpu401 +snd-mpu401-uart +snd-mtpav +snd-mts64 +snd-nm256 +snd-opl3-lib +snd-opl3sa2 +snd-opl3-synth +snd-opl4-lib +snd-opl4-synth +snd-opti92x-ad1848 +snd-opti92x-cs4231 +snd-opti93x +snd-oxygen +snd-oxygen-lib +snd-page-alloc +snd-pcm +snd-pcm-oss +snd-pcsp +snd-pcxhr +snd-pdaudiocf +snd-portman2x4 +snd-pt2258 +snd-rawmidi +snd-riptide +snd-rme32 +snd-rme96 +snd-rme9652 +snd-sb16 +snd-sb16-csp +snd-sb16-dsp +snd-sb8 +snd-sb8-dsp +snd-sbawe +snd-sb-common +snd-sc6000 +snd-seq +snd-seq-device +snd-seq-dummy +snd-seq-midi +snd-seq-midi-emul +snd-seq-midi-event +snd-seq-oss +snd-seq-virmidi +snd-serial-u16550 +snd-sgalaxy +snd-sis7019 +snd-soc-core +snd-sonicvibes +snd-sscape +snd-tea575x-tuner +snd-tea6330t +snd-timer +snd-trident +snd-usb-audio +snd-usb-caiaq +snd-usb-lib +snd-usb-usx2y +snd-util-mem +snd-via82xx +snd-via82xx-modem +snd-virmidi +snd-virtuoso +snd-vx222 +snd-vx-lib +snd-vxpocket +snd-wavefront +snd-ymfpci +soc_camera +soc_camera_platform +softcursor +softdog +sony-laptop +sonypi +sound +soundcore +sound_firmware +sp8870 +sp887x +spaceball +spaceorb +spcp8x5 +specialix +spectrum_cs +speedstep-centrino +speedstep-ich +speedstep-lib +speedstep-smi +speedtch +spi_bitbang +spi_butterfly +spidev +spi_lm70llp +squashfs +sr_mod +ssb +sscape +ssfdc +sstfb +st +starfire +stex +stinger +stir4200 +stkwebcam +stowaway +stp +stradis +strip +stv0297 +stv0299 +stv680 +sundance +sungem +sungem_phy +sunhme +suni +sunkbd +sunrpc +svcrdma +svgalib +sworks-agp +sx +sx8 +sym53c416 +sym53c500_cs +sym53c8xx +synclink +synclink_cs +synclink_gt +synclinkmp +syncppp +syscopyarea +sysfillrect +sysimgblt +sysv +t128 +t1isa +t1pci +tc1100-wmi +tcic +tcp_bic +tcp_highspeed +tcp_htcp +tcp_hybla +tcp_illinois +tcp_lp +tcp_probe +tcp_scalable +tcp_vegas +tcp_veno +tcp_westwood +tcp_yeah +tcrypt +tda10021 +tda10023 +tda10048 +tda1004x +tda10086 +tda18271 +tda7432 +tda8083 +tda826x +tda827x +tda8290 +tda9840 +tda9875 +tda9887 +tdfx +tdfxfb +tea +tea5761 +tea5767 +tea6415c +tea6420 +tehuti +tekram-sir +teles_cs +tg3 +tgr192 +thermal +thinkpad_acpi +thinkpad_ec +thmc50 +tifm_7xx1 +tifm_core +tifm_sd +tileblit +tipc +ti_usb_3410_5052 +tlan +tlclk +tle62x0 +tlsf +tmdc +tms380tr +tmscsim +tmspci +toshiba_acpi +touchit213 +touchright +touchwin +tpm +tpm_atmel +tpm_bios +tpm_infineon +tpm_nsc +tpm_tis +tps65010 +tp_smapi +trancevibrator +tridentfb +trix +ts5500_flash +ts_bm +ts_fsm +ts_kmp +tsl2550 +ttpci-eeprom +ttusb_dec +ttusbdecfe +tua6100 +tulip +tun +tuner +tuner-3036 +tuner-simple +tuner-types +tuner-xc2028 +tunnel4 +tunnel6 +turbografx +tvaudio +tveeprom +tvp5150 +twidjoy +twofish +twofish_common +twofish-i586 +typhoon +u132-hcd +u14-34f +uart401 +uart6850 +ub +ubi +ubifs +ucb1400_ts +udf +ueagle-atm +ufs +uhci-hcd +uinput +uio +uio_cif +uio_pdrv +uio_pdrv_genirq +uio_smx +uli526x +ultracam +ultrastor +umem +unionfs +upd64031a +upd64083 +uPD98402 +usb8xxx +usbatm +usbcore +usb_debug +usb_gigaset +usbhid +usbkbd +usblcd +usbled +usblp +usbmon +usbmouse +usbnet +usbserial +usb-storage +usbtouchscreen +usbvideo +usbvision +uss720 +uvcvideo +uvesafb +v4l1-compat +v4l2-common +v4l2-int-device +ves1820 +ves1x93 +vesafb +veth +vfat +vga16fb +vgastate +vgg2432a4 +via +via686a +via-agp +via_chrome9 +via-ircc +via-rhine +via-rng +via-velocity +vicam +video +video1394 +videobuf-core +videobuf-dma-contig +videobuf-dma-sg +videobuf-dvb +videobuf-vmalloc +videocodec +videodev +virtio +virtio_balloon +virtio_blk +virtio_console +virtio_net +virtio_pci +virtio_ring +virtio-rng +visor +vitesse +vivi +vlsi_ir +v_midi +vmlfb +vp27smpx +vpx3220 +vsxxxaa +vt1211 +vt8231 +vt8623fb +w1_ds2433 +w1_ds2760 +w1-gpio +w1_smem +w1_therm +w83627ehf +w83627hf +w83627hf_wdt +w83697hf_wdt +w83781d +w83791d +w83792d +w83793 +w83877f_wdt +w83977af_ir +w83977f_wdt +w83l785ts +w83l786ng +w9966 +w9968cf +wacom +wafer5823wdt +wanrouter +wanxl +warrior +wavelan +wavelan_cs +wbsd +wd +wd7000 +wdt +wdt_pci +whiteheat +winbond-840 +wire +wistron_btns +wl3501_cs +wm8739 +wm8775 +wm97xx-ts +wmi +wp512 +x25 +x25_asy +xc5000 +xcbc +xfrm4_mode_beet +xfrm4_mode_transport +xfrm4_mode_tunnel +xfrm4_tunnel +xfrm6_mode_beet +xfrm6_mode_ro +xfrm6_mode_transport +xfrm6_mode_tunnel +xfrm6_tunnel +xfrm_ipcomp +xfrm_user +xfs +xirc2ps_cs +xircom_cb +xor +xpad +xprtrdma +x_tables +xt_CLASSIFY +xt_comment +xt_connbytes +xt_connlimit +xt_CONNMARK +xt_connmark +xt_CONNSECMARK +xt_conntrack +xt_dccp +xt_DSCP +xt_dscp +xt_esp +xt_hashlimit +xt_helper +xt_iprange +xtkbd +xt_length +xt_limit +xt_mac +xt_MARK +xt_mark +xt_multiport +xt_NFLOG +xt_NFQUEUE +xt_NOTRACK +xt_owner +xt_physdev +xt_pkttype +xt_policy +xt_quota +xt_RATEEST +xt_rateest +xt_realm +xts +xt_sctp +xt_SECMARK +xt_state +xt_statistic +xt_string +xt_TCPMSS +xt_tcpmss +xt_tcpudp +xt_time +xt_TRACE +xt_u32 +xusbatm +yam +yealink +yellowfin +yenta_socket +z85230 +zatm +zaurus +zc0301 +zd1201 +zd1211rw +zhenhua +zl10353 +zlib_deflate +znet +zr36016 +zr36050 +zr36060 +zr36067 +zr364xx --- linux-2.6.27.orig/debian/abi/2.6.27-14.39/i386/server.modules +++ linux-2.6.27/debian/abi/2.6.27-14.39/i386/server.modules @@ -0,0 +1,2288 @@ +3c359 +3c501 +3c503 +3c505 +3c507 +3c509 +3c515 +3c523 +3c527 +3c574_cs +3c589_cs +3c59x +3w-9xxx +3w-xxxx +53c700 +6pack +8021q +8139cp +8139too +8250_accent +8250_boca +8250_exar_st16c554 +8250_fourport +8250_hub6 +8250_mca +82596 +8390 +8390p +9p +9pnet +9pnet_virtio +a100u2w +a3d +aacraid +abituguru +abituguru3 +abyss +ac +ac3200 +ac97_bus +acecad +acenic +acerhk +acer-wmi +acpi-cpufreq +acpiphp +acpiphp_ibm +acquirewdt +act2000 +act200l-sir +act_gact +act_ipt +actisys-sir +act_mirred +act_nat +act_pedit +act_police +act_simple +acx +ad1848 +ad7414 +ad7418 +adcxx +adfs +adi +adm1021 +adm1025 +adm1026 +adm1029 +adm1031 +adm8211 +adm9240 +ads7828 +ads7846 +adt7470 +adt7473 +adutux +adv7170 +adv7175 +advansys +advantechwdt +aead +aedsp16 +aes_generic +aes-i586 +affs +af_key +af_packet +af-rxrpc +agpgart +ah4 +ah6 +aha152x +aha152x_cs +aha1542 +aha1740 +ahci +aic79xx +aic7xxx +aic94xx +aiptek +aircable +airo +airo_cs +alauda +ali-agp +ali-ircc +alim1535_wdt +alim7101_wdt +ambassador +amd64-agp +amd76x_edac +amd76xrom +amd8111e +amd-k7-agp +amd-rng +analog +anubis +aoe +apm +appledisplay +appleir +applesmc +appletalk +appletouch +applicom +ar7part +arc4 +arcfb +arcmsr +arcnet +arc-rawmode +arc-rimi +ark3116 +arkfb +arlan +arptable_filter +arp_tables +arpt_mangle +asb100 +asix +asus-laptop +async_memcpy +async_tx +async_xor +at1700 +at24 +at25 +at76_usb +ata_generic +ata_piix +aten +ath9k +ati-agp +ati_remote +ati_remote2 +atl1 +atl1e +atl2 +atlas_btns +atmel +atmel_cs +atmel_pci +atmtcp +atp +atp870u +atxp1 +aty128fb +atyfb +au0828 +au8522 +aufs +authenc +auth_rpcgss +autofs +autofs4 +av5100 +avma1_cs +avm_cs +ax25 +axnet_cs +b1 +b1dma +b1isa +b1pci +b1pcmcia +b2c2-flexcop +b2c2-flexcop-pci +b2c2-flexcop-usb +b43 +b43legacy +b44 +bas_gigaset +battery +bay +baycom_epp +baycom_par +baycom_ser_fdx +baycom_ser_hdx +bcm203x +bcm3510 +bcm5974 +befs +belkin_sa +berry_charge +bfs +bfusb +binfmt_aout +binfmt_misc +bitblit +block2mtd +blowfish +bluecard_cs +bluetooth +bnep +bnx2 +bnx2x +bonding +bpa10x +bpck +bpck6 +bpqether +br2684 +bridge +broadcom +bsd_comp +bt3c_cs +bt819 +bt856 +bt878 +btcx-risc +btsdio +bttv +btuart_cs +btusb +budget +budget-av +budget-ci +budget-core +budget-patch +BusLogic +button +bw-qcam +c101 +c4 +c67x00 +cafe_ccic +cafe_nand +camellia +capi +capidrv +capifs +capmode +carminefb +cassini +cast5 +cast6 +catc +cbc +cciss +ccm +cdc-acm +cdc_ether +cdc_subset +cdc-wdm +cdrom +cfag12864b +cfag12864bfb +cfg80211 +cfi_cmdset_0001 +cfi_cmdset_0002 +cfi_cmdset_0020 +cfi_probe +cfi_util +ch +ch341 +chipreg +cicada +cifs +cinergyT2 +cirrusfb +ck804xrom +cls_basic +cls_fw +cls_route +cls_rsvp +cls_rsvp6 +cls_tcindex +cls_u32 +cm4000_cs +cm4040_cs +cmtp +cobra +coda +com20020 +com20020_cs +com20020-isa +com20020-pci +com90io +com90xx +comm +commandir +compal-laptop +compat_ioctl32 +compcache +configfs +container +coretemp +corgi_bl +cosa +cp2101 +cpcihp_generic +cpcihp_zt5550 +cpia +cpia2 +cpia_pp +cpia_usb +cpqarray +cpqphp +cpu5wdt +cpufreq_conservative +cpufreq-nforce2 +cpufreq_ondemand +cpufreq_powersave +cpufreq_stats +cpufreq_userspace +cpuid +c-qcam +cr_bllcd +crc16 +crc32c +crc7 +crc-ccitt +crc-itu-t +crc-t10dif +crvml +cryptd +crypto_blkcipher +cryptoloop +crypto_null +cs5345 +cs53l32a +cs5535_gpio +cs553x_nand +cs89x0 +ct82c710 +ctr +cts +cx18 +cx22700 +cx22702 +cx2341x +cx23885 +cx24110 +cx24123 +cx25840 +cx8800 +cx8802 +cx88-alsa +cx88-blackbird +cx88-dvb +cx88-vp3054-i2c +cx88xx +cxacru +cxgb +cxgb3 +cyber2000fb +cyberjack +cyblafb +cyclades +cyclomx +cycx_drv +cypress_cy7c63 +cypress_m8 +cytherm +DAC960 +davicom +db9 +dc395x +dccp +dccp_ccid2 +dccp_ccid3 +dccp_diag +dccp_ipv4 +dccp_ipv6 +dccp_probe +dccp_tfrc_lib +dcdbas +de2104x +de4x5 +de600 +de620 +decnet +deflate +defxx +dell_rbu +depca +des_generic +dib0070 +dib3000mb +dib3000mc +dib7000m +dib7000p +dibx000_common +digi_acceleport +dilnetpc +diskonchip +display +divacapi +divadidd +diva_idi +diva_mnt +divas +dlci +dlm +dm9601 +dm-bbr +dm-crypt +dme1737 +dmfe +dm-log +dm-loop +dm-mem-cache +dm-message +dm-mirror +dm-mod +dm-multipath +dm-raid4-5 +dm-region_hash +dm-round-robin +dm-snapshot +dmx3191d +dm-zero +dn_rtmsg +doc2000 +doc2001 +doc2001plus +docecc +dock +docprobe +donauboe +dpc7146 +dpt_i2o +drbd +drm +drx397xD +ds1621 +ds1682 +ds2482 +ds2490 +ds2760_battery +dsbr100 +dscc4 +dss1_divert +dst +dst_ca +dstr +dtc +dtl1_cs +dtlk +dummy +dv1394 +dvb-bt8xx +dvb-core +dvb-pll +dvb-ttpci +dvb-ttusb-budget +dvb-usb +dvb-usb-a800 +dvb-usb-af9005 +dvb-usb-af9005-remote +dvb-usb-anysee +dvb-usb-au6610 +dvb-usb-cxusb +dvb-usb-dib0700 +dvb-usb-dibusb-common +dvb-usb-dibusb-mb +dvb-usb-dibusb-mc +dvb-usb-digitv +dvb-usb-dtt200u +dvb-usb-dw2102 +dvb-usb-gl861 +dvb-usb-gp8psk +dvb-usb-m920x +dvb-usb-nova-t-usb2 +dvb-usb-opera +dvb-usb-ttusb2 +dvb-usb-umt-010 +dvb-usb-vp702x +dvb-usb-vp7045 +e100 +e1000 +e1000e +e2100 +e752x_edac +e7xxx_edac +eata +ebt_802_3 +ebtable_broute +ebtable_filter +ebtable_nat +ebtables +ebt_among +ebt_arp +ebt_arpreply +ebt_dnat +ebt_ip +ebt_ip6 +ebt_limit +ebt_log +ebt_mark +ebt_mark_m +ebt_nflog +ebt_pkttype +ebt_redirect +ebt_snat +ebt_stp +ebt_ulog +ebt_vlan +ecb +econet +ecryptfs +edac_core +eeepc-laptop +eepro +eepro100 +eeprom +eeprom_93cx6 +eexpress +efficeon-agp +efs +ehci-hcd +elo +elsa_cs +em28xx +em28xx-alsa +em28xx-dvb +em_cmp +emi26 +emi62 +em_meta +em_nbyte +empeg +em_text +emu10k1-gp +em_u32 +enclosure +eni +epat +epca +epia +epic100 +eql +es3210 +esb2rom +esi-sir +esp +esp4 +esp6 +et131x +et61x251 +eth1394 +eth16i +eurotechwdt +evbug +evdev +ewrk3 +exportfs +ext2 +ext3 +ext4dev +f71805f +f71882fg +f75375s +fakephp +fan +farsync +fat +faulty +fbcon +fb_ddc +fb_sys_fops +fcrypt +fd_mcs +fdomain +fdomain_cs +fealnx +ff-memless +firestream +fit2 +fit3 +floppy +fm801-gp +fmvj18x_cs +font +forcedeth +fore_200e +freevxfs +freq_table +friq +frpw +fsam7400 +fscher +fschmd +fscpos +ftdi-elan +ftdi_sio +ftl +fujitsu-laptop +fujitsu_ts +funsoft +fuse +g450_pll +gadgetfs +gamecon +gameport +garmin_gps +garp +g_cdc +gcm +gdth +generic_serial +gen_probe +geode-aes +geode-rng +g_ether +gf128mul +gf2k +g_file_storage +gfs +gfs2 +gigaset +girbil-sir +gl518sm +gl520sm +gl620a +gnbd +g_NCR5380 +g_NCR5380_mmio +gpio_keys +gpio_mouse +grip +grip_mp +g_serial +gspca_conex +gspca_etoms +gspca_main +gspca_mars +gspca_ov519 +gspca_pac207 +gspca_pac7311 +gspca_sonixb +gspca_sonixj +gspca_spca500 +gspca_spca501 +gspca_spca505 +gspca_spca506 +gspca_spca508 +gspca_spca561 +gspca_stk014 +gspca_sunplus +gspca_t613 +gspca_tv8532 +gspca_vc032x +gspca_zc3xx +gtco +guillemot +gunze +gx1fb +gxfb +gx-suspmod +g_zero +hamachi +hangcheck-timer +hci_uart +hci_vhci +hdaps +hdlc +hdlc_cisco +hdlcdrv +hdlc_fr +hdlc_ppp +hdlc_raw +hdlc_raw_eth +hdlc_x25 +he +heci +hecubafb +hermes +hexium_gemini +hexium_orion +hfc4s8s_l1 +hfcmulti +hfcpci +hfc_usb +hfs +hfsplus +hgafb +hid +hidp +hifn_795x +hisax +hisax_fcpcipnp +hisax_isac +hisax_st5481 +horizon +hostap +hostap_cs +hostap_pci +hostap_plx +hostess_sv11 +hp +hp100 +hp4x +hpfs +hpilo +hp-plus +hptiop +hp-wmi +hso +htc-pasic3 +htcpen +hwmon-vid +hysdn +i2c-algo-bit +i2c-algo-pca +i2c-algo-pcf +i2c-ali1535 +i2c-ali1563 +i2c-ali15x3 +i2c-amd756 +i2c-amd756-s4882 +i2c-amd8111 +i2c-core +i2c-dev +i2c-gpio +i2c-i801 +i2c-isch +i2c-matroxfb +i2c-nforce2 +i2c-nforce2-s4985 +i2c-ocores +i2c-parport +i2c-parport-light +i2c-pca-isa +i2c-pca-platform +i2c-piix4 +i2c-simtec +i2c-sis5595 +i2c-sis630 +i2c-sis96x +i2c-stub +i2c-taos-evm +i2c-tiny-usb +i2c-via +i2c-viapro +i2c-voodoo3 +i2o_block +i2o_bus +i2o_config +i2o_core +i2o_proc +i2o_scsi +i3000_edac +i5000_edac +i5100_edac +i5k_amb +i6300esb +i810 +i810fb +i82092 +i82365 +i82860_edac +i82875p_edac +i82975x_edac +i830 +i8k +i915 +ib700wdt +ib_addr +ib_cm +ib_core +ib_ipoib +ib_iser +ib_mad +ibmaem +ibmasm +ibmasr +ibmcam +ibmlana +ibmmca +ibmpex +ibmphp +ib_mthca +ibmtr +ibmtr_cs +ib_sa +ib_srp +ib_ucm +ib_umad +ib_uverbs +ichxrom +icn +icplus +idmouse +idt77252 +ieee1394 +ieee80211 +ieee80211_crypt +ieee80211_crypt_ccmp +ieee80211_crypt_tkip +ieee80211_crypt_wep +ifb +iforce +igb +ili9320 +imm +in2000 +inet_lro +inexio +inftl +initio +inport +input-polldev +intel-agp +intelfb +intel_menlow +intel-rng +intel_vr_nor +interact +ioc4 +io_edgeport +io_ti +iowarrior +ip2 +ip6_queue +ip6table_filter +ip6table_mangle +ip6table_raw +ip6_tables +ip6table_security +ip6t_ah +ip6t_eui64 +ip6t_frag +ip6t_hbh +ip6t_HL +ip6t_hl +ip6t_ipv6header +ip6t_LOG +ip6t_mh +ip6t_REJECT +ip6t_rt +ip6_tunnel +ipaq +ipcomp +ipcomp6 +ipddp +ipg +ip_gre +iphase +ipip +ipmi_devintf +ipmi_msghandler +ipmi_poweroff +ipmi_si +ipmi_watchdog +ip_queue +ipr +ips +iptable_filter +iptable_mangle +iptable_nat +iptable_raw +ip_tables +iptable_security +ipt_addrtype +ipt_ah +ipt_CLUSTERIP +ipt_ECN +ipt_ecn +ipt_LOG +ipt_MASQUERADE +ipt_NETMAP +ipt_recent +ipt_REDIRECT +ipt_REJECT +ipt_TTL +ipt_ttl +ipt_ULOG +ipv6 +ip_vs +ip_vs_dh +ip_vs_ftp +ip_vs_lblc +ip_vs_lblcr +ip_vs_lc +ip_vs_nq +ip_vs_rr +ip_vs_sed +ip_vs_sh +ip_vs_wlc +ip_vs_wrr +ipw +ipw2100 +ipw2200 +ipwireless +ipx +ircomm +ir-common +ircomm-tty +irda +irda-usb +ir-kbd-i2c +irlan +irnet +irtty-sir +iscsi_ibft +iscsi_tcp +iscsi_trgt +isdn +isdn_bsdcomp +isdnhdlc +isight_firmware +isl6405 +isl6421 +isofs +isp116x-hcd +isp1760 +it87 +it8712f_wdt +iTCO_vendor_support +iTCO_wdt +itd1000 +ivtv +ivtvfb +iw_c2 +iw_cm +iw_cxgb3 +iwl3945 +iwlagn +iwlcore +ixgb +ixgbe +ixj +ixj_pcmcia +jbd +jbd2 +jedec_probe +jffs2 +jfs +joydev +joydump +jsm +k8temp +kafs +kahlua +kaweth +kbic +kbtab +kernelcapi +keyspan +keyspan_pda +keyspan_remote +khazad +kingsun-sir +kl5kusb105 +kobil_sct +konicawc +ks0108 +ks0127 +ks959-sir +ksdazzle-sir +ktti +kvm +kvm-amd +kvm-intel +kyrofb +l1oip +l2cap +l440gx +l64781 +lanai +lance +lanstreamer +lapb +lapbether +lcd +ldusb +lec +led-class +leds-gpio +leds-net48xx +leds-pca9532 +leds-pca955x +leds-wrap +ledtrig-default-on +ledtrig-heartbeat +ledtrig-timer +legousbtower +lgdt330x +libata +libcrc32c +libertas +libertas_cs +libertas_sdio +libiscsi +libphy +libsas +libsrp +libusual +lightning +linear +lirc_atiusb +lirc_bt829 +lirc_cmdir +lirc_dev +lirc_i2c +lirc_igorplugusb +lirc_imon +lirc_it87 +lirc_mceusb +lirc_mceusb2 +lirc_pvr150 +lirc_sasem +lirc_serial +lirc_serial_igor +lirc_sir +lirc_streamzap +lirc_ttusbir +litelink-sir +lkkbd +llc2 +lm63 +lm70 +lm75 +lm77 +lm78 +lm80 +lm83 +lm85 +lm87 +lm90 +lm92 +lm93 +lmc +lmpcm_usb +lnbp21 +lne390 +lockd +lock_dlm +logibm +longhaul +longrun +loop +lp +lp486e +lpfc +lrw +ltpc +ltv350qv +lxfb +lxt +lzo +lzo_compress +lzo_decompress +m25p80 +m52790 +ma600-sir +mac80211 +machzwd +macmodes +macvlan +madgemc +magellan +map_absent +map_funcs +map_ram +map_rom +marvell +matroxfb_accel +matroxfb_base +matroxfb_crtc2 +matroxfb_DAC1064 +matroxfb_g450 +matroxfb_maven +matroxfb_misc +matroxfb_Ti3026 +matrox_w1 +max1619 +max6650 +max6875 +max7301 +max732x +mbcache +mbp_nvidia_bl +mcp2120-sir +mcp23s08 +mcs7780 +mcs7830 +mct_u232 +md4 +mdacon +mdc800 +mdio-bitbang +md-mod +megaraid +megaraid_mbox +megaraid_mm +megaraid_sas +meye +mga +michael_mic +microcode +microtek +mii +minix +mISDN_core +mISDN_dsp +mixcomwd +mk712 +mkiss +mlx4_core +mlx4_ib +mmc_block +mmc_core +mos7720 +mos7840 +moto_modem +moxa +mpoa +mptbase +mptctl +mptfc +mptlan +mptsas +mptscsih +mptspi +mpu401 +msdos +msi-laptop +msnd +msnd_classic +msnd_pinnacle +msp3400 +msr +mt2060 +mt20xx +mt2131 +mt2266 +mt312 +mt352 +mt9m001 +mt9v022 +mtd +mtd_blkdevs +mtdblock +mtdblock_ro +mtdchar +mtdconcat +mtd_dataflash +mtdoops +mtdram +mtouch +multipath +mwave +mxb +mxl5005s +mxl5007t +mxser +myri10ge +n2 +nand +nand_ecc +nand_ids +nandsim +natsemi +navman +nbd +ncpfs +NCR53c406a +NCR_D700 +NCR_Q720_mod +ndiswrapper +ne +ne2 +ne2k-pci +ne3210 +neofb +net1080 +net2280 +netconsole +netrom +netsc520 +nettel +netwave_cs +netxen_nic +newtonkbd +nf_conntrack +nf_conntrack_amanda +nf_conntrack_ftp +nf_conntrack_h323 +nf_conntrack_ipv4 +nf_conntrack_ipv6 +nf_conntrack_irc +nf_conntrack_netbios_ns +nf_conntrack_netlink +nf_conntrack_pptp +nf_conntrack_proto_gre +nf_conntrack_proto_sctp +nf_conntrack_proto_udplite +nf_conntrack_sip +nf_conntrack_tftp +nf_nat +nf_nat_amanda +nf_nat_ftp +nf_nat_h323 +nf_nat_irc +nf_nat_pptp +nf_nat_proto_gre +nf_nat_proto_sctp +nf_nat_proto_udplite +nf_nat_sip +nf_nat_snmp_basic +nf_nat_tftp +nfnetlink +nfnetlink_log +nfnetlink_queue +nfs +nfs_acl +nfsd +nftl +n_hdlc +ni52 +ni65 +nicstar +niu +nls_ascii +nls_cp1250 +nls_cp1251 +nls_cp1255 +nls_cp437 +nls_cp737 +nls_cp775 +nls_cp850 +nls_cp852 +nls_cp855 +nls_cp857 +nls_cp860 +nls_cp861 +nls_cp862 +nls_cp863 +nls_cp864 +nls_cp865 +nls_cp866 +nls_cp869 +nls_cp874 +nls_cp932 +nls_cp936 +nls_cp949 +nls_cp950 +nls_euc-jp +nls_iso8859-1 +nls_iso8859-13 +nls_iso8859-14 +nls_iso8859-15 +nls_iso8859-2 +nls_iso8859-3 +nls_iso8859-4 +nls_iso8859-5 +nls_iso8859-6 +nls_iso8859-7 +nls_iso8859-9 +nls_koi8-r +nls_koi8-ru +nls_koi8-u +nls_utf8 +nmclan_cs +nozomi +n_r3964 +ns558 +ns83820 +nsc_gpio +nsc-ircc +nsp32 +nsp_cs +ntfs +nvidia-agp +nvidiafb +nvram +nxt200x +nxt6000 +ocfs2 +ocfs2_dlm +ocfs2_dlmfs +ocfs2_nodemanager +ocfs2_stackglue +ocfs2_stack_o2cb +ocfs2_stack_user +ohci1394 +ohci-hcd +old_belkin-sir +olpc_battery +olympic +omfs +omninet +on20 +on26 +onenand +onenand_sim +opl3 +oprofile +option +or51132 +or51211 +orinoco +orinoco_cs +orinoco_nortel +orinoco_pci +orinoco_plx +orinoco_tmd +osst +oti6858 +output +ov511 +ov511_decomp +ov518_decomp +ov7670 +ovcamchip +p4-clockmod +p54common +p54pci +p54usb +p80211 +p8023 +padlock-aes +padlock-sha +paride +parkbd +parport +parport_ax88796 +parport_cs +parport_pc +parport_serial +pas16 +pas2 +pata_acpi +pata_ali +pata_amd +pata_artop +pata_atiixp +pata_cmd64x +pata_cs5520 +pata_cs5530 +pata_cs5535 +pata_cs5536 +pata_efar +pata_hpt366 +pata_hpt37x +pata_hpt3x3 +pata_it8213 +pata_it821x +pata_jmicron +pata_legacy +pata_marvell +pata_mpiix +pata_netcell +pata_ninja32 +pata_ns87410 +pata_ns87415 +pata_oldpiix +pata_pcmcia +pata_pdc2027x +pata_pdc202xx_old +pata_qdi +pata_rz1000 +pata_sch +pata_serverworks +pata_sil680 +pata_sis +pata_sl82c105 +pata_triflex +pata_via +pata_winbond +pbe5 +pc110pad +pc300 +pc87360 +pc8736x_gpio +pc87413_wdt +pc87427 +pca953x +pcbc +pcbit +pcd +pcf857x +pcf8591 +pci +pci200syn +pciehp +pci_hotplug +pcilynx +pcips2 +pci_slot +pcmcia +pcmcia_core +pcnet32 +pcnet_cs +pcspkr +pcwd +pcwd_pci +pcwd_usb +pd +pd6729 +pda_power +pdc_adma +pegasus +penmount +pf +pg +phantom +phidget +phidgetkit +phidgetmotorcontrol +phidgetservo +phonedev +phram +physmap +pktcdvd +pktgen +pl2303 +platform_lcd +plat_nand +plat-ram +plip +plusb +pluto2 +pm2fb +pm3fb +pmc551 +pms +powermate +powernow-k6 +powernow-k7 +powernow-k8 +ppa +ppdev +ppp_async +ppp_deflate +ppp_generic +ppp_mppe +pppoatm +pppoe +pppol2tp +pppox +ppp_synctty +prism2_usb +prism54 +processor +progear_bl +proteon +psmouse +pss +pt +pvrusb2 +pwc +qla1280 +qla2xxx +qla3xxx +qla4xxx +qlogic_cs +qlogicfas +qlogicfas408 +qnx4 +qsemi +qt1010 +quickcam +quickcam_messenger +quota_v1 +quota_v2 +r128 +r8169 +r82600_edac +r8a66597-hcd +radeon +radeonfb +radio-aimslab +radio-aztech +radio-cadet +radio-gemtek +radio-gemtek-pci +radio-maestro +radio-maxiradio +radio-rtrack2 +radio-sf16fmi +radio-sf16fmr2 +radio-si470x +radio-terratec +radio-trust +radio-typhoon +radio-zoltrix +raid0 +raid1 +raid10 +raid456 +raid_class +raw +raw1394 +ray_cs +rdma_cm +rdma_ucm +redboot +reed_solomon +reiserfs +rfc1051 +rfc1201 +rfcomm +rfd_ftl +rfkill +rfkill-input +ricoh_mmc +rio +rio500 +riscom8 +rivafb +rmd128 +rmd160 +rmd256 +rmd320 +rndis_host +rndis_wlan +rocket +romfs +rose +rpcsec_gss_krb5 +rpcsec_gss_spkm3 +rrunner +rsrc_nonstatic +rt2400pci +rt2500pci +rt2500usb +rt2x00lib +rt2x00pci +rt2x00usb +rt61pci +rt73usb +rtc-ds1305 +rtc-ds1307 +rtc-ds1374 +rtc-ds1553 +rtc-ds1672 +rtc-ds1742 +rtc-fm3130 +rtc-isl1208 +rtc-m41t80 +rtc-m41t94 +rtc-m48t59 +rtc-m48t86 +rtc-max6900 +rtc-max6902 +rtc-pcf8563 +rtc-pcf8583 +rtc-rs5c348 +rtc-rs5c372 +rtc-stk17ta8 +rtc-test +rtc-v3020 +rtc-x1205 +rtl8150 +rtl8180 +rtl8187 +rxkad +s1d13xxxfb +s2255drv +s2io +s3fb +s5h1409 +s5h1411 +s5h1420 +saa5246a +saa5249 +saa6588 +saa6752hs +saa7110 +saa7111 +saa7114 +saa7115 +saa7127 +saa7134 +saa7134-alsa +saa7134-dvb +saa7134-empress +saa7146 +saa7146_vv +saa717x +saa7185 +safe_serial +salsa20_generic +salsa20-i586 +sata_inic162x +sata_mv +sata_nv +sata_promise +sata_qstor +sata_sil +sata_sil24 +sata_sis +sata_svw +sata_sx4 +sata_uli +sata_via +sata_vsc +savage +savagefb +sb +sb1000 +sbc60xxwdt +sbc7240_wdt +sbc8360 +sbc_epx_c3 +sbc_gxx +sb_lib +sbni +sbp2 +sbs +sbshc +sc +sc1200wdt +sc520cdp +sc520_wdt +sc92031 +scb2_flash +scc +sch_atm +sch_cbq +sch_dsmark +sch_gred +sch_hfsc +sch_htb +sch_ingress +sch_netem +sch_prio +sch_red +sch_sfq +sch_tbf +sch_teql +sco +scsi_debug +scsi_dh +scsi_dh_alua +scsi_dh_emc +scsi_dh_hp_sw +scsi_dh_rdac +scsi_mod +scsi_tgt +scsi_transport_fc +scsi_transport_iscsi +scsi_transport_sas +scsi_transport_spi +scsi_transport_srp +scsi_wait_scan +sctp +scx200 +scx200_acb +scx200_docflash +scx200_gpio +scx200_hrt +scx200_i2c +scx200_wdt +sdhci +sdhci-pci +sdio_uart +sdla +sd_mod +sdricoh_cs +se401 +sealevel +sedlbauer_cs +seed +seeq8005 +seqiv +ser_gigaset +serial_cs +serio_raw +sermouse +serpent +serport +ses +sfc +sg +sha1_generic +sha256_generic +sha512_generic +sh_mobile_ceu_camera +shpchp +sidewinder +sierra +sim710 +sir-dev +sis +sis190 +sis5595 +sis900 +sis-agp +sisfb +sisusbvga +sit +skfp +skge +skisa +sky2 +sl811_cs +sl811-hcd +slhc +slip +slram +sm501 +sm501fb +smbfs +smc9194 +smc91c92_cs +smc-mca +smctr +smc-ultra +smc-ultra32 +sms1xxx +smsc +smsc37b787_wdt +smsc47b397 +smsc47m1 +smsc47m192 +smsc-ircc2 +sn9c102 +snd +snd-ac97-codec +snd-ad1816a +snd-ad1848 +snd-ad1848-lib +snd-ad1889 +snd-adlib +snd-ak4114 +snd-ak4117 +snd-ak4xxx-adda +snd-ali5451 +snd-als100 +snd-als300 +snd-als4000 +snd-atiixp +snd-atiixp-modem +snd-au8810 +snd-au8820 +snd-au8830 +snd-aw2 +snd-azt2320 +snd-azt3328 +snd-bt87x +snd-bt-sco +snd-ca0106 +snd-cmi8330 +snd-cmipci +snd-cs4231 +snd-cs4231-lib +snd-cs4232 +snd-cs4236 +snd-cs4236-lib +snd-cs4281 +snd-cs46xx +snd-cs5530 +snd-cs5535audio +snd-cs8427 +snd-darla20 +snd-darla24 +snd-dt019x +snd-dummy +snd-echo3g +snd-emu10k1 +snd-emu10k1-synth +snd-emu10k1x +snd-emu8000-synth +snd-emux-synth +snd-ens1370 +snd-ens1371 +snd-es1688 +snd-es1688-lib +snd-es18xx +snd-es1938 +snd-es1968 +snd-es968 +snd-fm801 +snd-gina20 +snd-gina24 +snd-gusclassic +snd-gusextreme +snd-gus-lib +snd-gusmax +snd-hda-intel +snd-hdsp +snd-hdspm +snd-hifier +snd-hwdep +snd-i2c +snd-ice1712 +snd-ice1724 +snd-ice17xx-ak4xxx +snd-indigo +snd-indigodj +snd-indigoio +snd-intel8x0 +snd-intel8x0m +snd-interwave +snd-interwave-stb +snd-korg1212 +snd-layla20 +snd-layla24 +snd-maestro3 +snd-mia +snd-miro +snd-mixart +snd-mixer-oss +snd-mona +snd-mpu401 +snd-mpu401-uart +snd-mtpav +snd-mts64 +snd-nm256 +snd-opl3-lib +snd-opl3sa2 +snd-opl3-synth +snd-opl4-lib +snd-opl4-synth +snd-opti92x-ad1848 +snd-opti92x-cs4231 +snd-opti93x +snd-oxygen +snd-oxygen-lib +snd-page-alloc +snd-pcm +snd-pcm-oss +snd-pcsp +snd-pcxhr +snd-pdaudiocf +snd-portman2x4 +snd-pt2258 +snd-rawmidi +snd-riptide +snd-rme32 +snd-rme96 +snd-rme9652 +snd-sb16 +snd-sb16-csp +snd-sb16-dsp +snd-sb8 +snd-sb8-dsp +snd-sbawe +snd-sb-common +snd-sc6000 +snd-seq +snd-seq-device +snd-seq-dummy +snd-seq-midi +snd-seq-midi-emul +snd-seq-midi-event +snd-seq-oss +snd-seq-virmidi +snd-serial-u16550 +snd-sgalaxy +snd-sis7019 +snd-soc-core +snd-sonicvibes +snd-sscape +snd-tea575x-tuner +snd-tea6330t +snd-timer +snd-trident +snd-usb-audio +snd-usb-caiaq +snd-usb-lib +snd-usb-usx2y +snd-util-mem +snd-via82xx +snd-via82xx-modem +snd-virmidi +snd-virtuoso +snd-vx222 +snd-vx-lib +snd-vxpocket +snd-wavefront +snd-ymfpci +soc_camera +soc_camera_platform +softcursor +softdog +sony-laptop +sonypi +sound +soundcore +sound_firmware +sp8870 +sp887x +spaceball +spaceorb +spcp8x5 +specialix +spectrum_cs +speedstep-centrino +speedstep-ich +speedstep-lib +speedstep-smi +speedtch +spi_bitbang +spi_butterfly +spidev +spi_lm70llp +squashfs +sr_mod +ssb +sscape +ssfdc +sstfb +st +starfire +stex +stinger +stir4200 +stkwebcam +stowaway +stp +stradis +strip +stv0297 +stv0299 +stv680 +sundance +sungem +sungem_phy +sunhme +suni +sunkbd +sunrpc +svcrdma +svgalib +sworks-agp +sx +sx8 +sym53c416 +sym53c500_cs +sym53c8xx +synclink +synclink_cs +synclink_gt +synclinkmp +syncppp +syscopyarea +sysfillrect +sysimgblt +sysv +t128 +t1isa +t1pci +tc1100-wmi +tcic +tcp_bic +tcp_highspeed +tcp_htcp +tcp_hybla +tcp_illinois +tcp_lp +tcp_probe +tcp_scalable +tcp_vegas +tcp_veno +tcp_westwood +tcp_yeah +tcrypt +tda10021 +tda10023 +tda10048 +tda1004x +tda10086 +tda18271 +tda7432 +tda8083 +tda826x +tda827x +tda8290 +tda9840 +tda9875 +tda9887 +tdfx +tdfxfb +tea +tea5761 +tea5767 +tea6415c +tea6420 +tehuti +tekram-sir +teles_cs +tg3 +tgr192 +thermal +thinkpad_acpi +thinkpad_ec +thmc50 +tifm_7xx1 +tifm_core +tifm_sd +tileblit +tipc +ti_usb_3410_5052 +tlan +tlclk +tle62x0 +tlsf +tmdc +tms380tr +tmscsim +tmspci +toshiba_acpi +touchit213 +touchright +touchwin +tpm +tpm_atmel +tpm_bios +tpm_infineon +tpm_nsc +tpm_tis +tps65010 +tp_smapi +trancevibrator +tridentfb +trix +ts5500_flash +ts_bm +ts_fsm +ts_kmp +tsl2550 +ttpci-eeprom +ttusb_dec +ttusbdecfe +tua6100 +tulip +tun +tuner +tuner-3036 +tuner-simple +tuner-types +tuner-xc2028 +tunnel4 +tunnel6 +turbografx +tvaudio +tveeprom +tvp5150 +twidjoy +twofish +twofish_common +twofish-i586 +typhoon +u132-hcd +u14-34f +uart401 +uart6850 +ub +ubi +ubifs +ucb1400_ts +udf +ueagle-atm +ufs +uhci-hcd +uinput +uio +uio_cif +uio_pdrv +uio_pdrv_genirq +uio_smx +uli526x +ultracam +ultrastor +umem +unionfs +upd64031a +upd64083 +uPD98402 +usb8xxx +usbatm +usbcore +usb_debug +usb_gigaset +usbhid +usbkbd +usblcd +usbled +usblp +usbmon +usbmouse +usbnet +usbserial +usb-storage +usbtouchscreen +usbvideo +usbvision +uss720 +uvcvideo +uvesafb +v4l1-compat +v4l2-common +v4l2-int-device +ves1820 +ves1x93 +vesafb +veth +vfat +vga16fb +vgastate +vgg2432a4 +via +via686a +via-agp +via_chrome9 +via-ircc +via-rhine +via-rng +via-velocity +vicam +video +video1394 +videobuf-core +videobuf-dma-contig +videobuf-dma-sg +videobuf-dvb +videobuf-vmalloc +videocodec +videodev +virtio +virtio_balloon +virtio_blk +virtio_console +virtio_net +virtio_pci +virtio_ring +virtio-rng +visor +vitesse +vivi +vlsi_ir +v_midi +vmlfb +vp27smpx +vpx3220 +vsxxxaa +vt1211 +vt8231 +vt8623fb +w1_ds2433 +w1_ds2760 +w1-gpio +w1_smem +w1_therm +w83627ehf +w83627hf +w83627hf_wdt +w83697hf_wdt +w83781d +w83791d +w83792d +w83793 +w83877f_wdt +w83977af_ir +w83977f_wdt +w83l785ts +w83l786ng +w9966 +w9968cf +wacom +wafer5823wdt +wanrouter +wanxl +warrior +wavelan +wavelan_cs +wbsd +wd +wd7000 +wdt +wdt_pci +whiteheat +winbond-840 +wire +wistron_btns +wl3501_cs +wm8739 +wm8775 +wm97xx-ts +wmi +wp512 +x25 +x25_asy +xc5000 +xcbc +xen-blkfront +xen-fbfront +xen-kbdfront +xen-netfront +xfrm4_mode_beet +xfrm4_mode_transport +xfrm4_mode_tunnel +xfrm4_tunnel +xfrm6_mode_beet +xfrm6_mode_ro +xfrm6_mode_transport +xfrm6_mode_tunnel +xfrm6_tunnel +xfrm_ipcomp +xfrm_user +xfs +xirc2ps_cs +xircom_cb +xor +xpad +xprtrdma +x_tables +xt_CLASSIFY +xt_comment +xt_connbytes +xt_connlimit +xt_CONNMARK +xt_connmark +xt_CONNSECMARK +xt_conntrack +xt_dccp +xt_DSCP +xt_dscp +xt_esp +xt_hashlimit +xt_helper +xt_iprange +xtkbd +xt_length +xt_limit +xt_mac +xt_MARK +xt_mark +xt_multiport +xt_NFLOG +xt_NFQUEUE +xt_NOTRACK +xt_owner +xt_physdev +xt_pkttype +xt_policy +xt_quota +xt_RATEEST +xt_rateest +xt_realm +xts +xt_sctp +xt_SECMARK +xt_state +xt_statistic +xt_string +xt_TCPMSS +xt_tcpmss +xt_tcpudp +xt_time +xt_TRACE +xt_u32 +xusbatm +yam +yealink +yellowfin +yenta_socket +z85230 +zatm +zaurus +zc0301 +zd1201 +zd1211rw +zhenhua +zl10353 +zlib_deflate +znet +zr36016 +zr36050 +zr36060 +zr36067 +zr364xx --- linux-2.6.27.orig/debian/abi/2.6.27-14.39/amd64/generic +++ linux-2.6.27/debian/abi/2.6.27-14.39/amd64/generic @@ -0,0 +1,8123 @@ +EXPORT_SYMBOL arch/x86/kvm/kvm 0x42eb62ef kvm_cpu_has_pending_timer +EXPORT_SYMBOL arch/x86/kvm/kvm 0xa87cebcc kvm_read_guest_atomic +EXPORT_SYMBOL crypto/gf128mul 0x0c2f123f gf128mul_4k_bbe +EXPORT_SYMBOL crypto/gf128mul 0x1068004b gf128mul_bbe +EXPORT_SYMBOL crypto/gf128mul 0x2f2889a0 gf128mul_init_64k_lle +EXPORT_SYMBOL crypto/gf128mul 0x3755f990 gf128mul_init_64k_bbe +EXPORT_SYMBOL crypto/gf128mul 0x384ef9ce gf128mul_64k_bbe +EXPORT_SYMBOL crypto/gf128mul 0x56af0dbd gf128mul_x_ble +EXPORT_SYMBOL crypto/gf128mul 0x83581089 gf128mul_init_4k_lle +EXPORT_SYMBOL crypto/gf128mul 0x9b2560b9 gf128mul_init_4k_bbe +EXPORT_SYMBOL crypto/gf128mul 0x9e13f6f6 gf128mul_lle +EXPORT_SYMBOL crypto/gf128mul 0xbd17a0df gf128mul_4k_lle +EXPORT_SYMBOL crypto/gf128mul 0xc0890413 gf128mul_64k_lle +EXPORT_SYMBOL crypto/gf128mul 0xd60736ec gf128mul_free_64k +EXPORT_SYMBOL crypto/xor 0x5b6c00e6 xor_blocks +EXPORT_SYMBOL drivers/acpi/processor 0x0603377d acpi_processor_preregister_performance +EXPORT_SYMBOL drivers/acpi/processor 0x8461fbfe acpi_processor_unregister_performance +EXPORT_SYMBOL drivers/acpi/processor 0xcc337eed acpi_processor_notify_smm +EXPORT_SYMBOL drivers/acpi/processor 0xd78b77e1 acpi_processor_register_performance +EXPORT_SYMBOL drivers/acpi/processor 0xe8a3605f acpi_processor_set_thermal_limit +EXPORT_SYMBOL drivers/atm/suni 0x6ed6facc suni_init +EXPORT_SYMBOL drivers/atm/uPD98402 0x8ac2f15b uPD98402_init +EXPORT_SYMBOL drivers/block/loop 0xbfee3ad5 loop_unregister_transfer +EXPORT_SYMBOL drivers/block/loop 0xda0738b7 loop_register_transfer +EXPORT_SYMBOL drivers/block/paride/paride 0x12c3aebf pi_schedule_claimed +EXPORT_SYMBOL drivers/block/paride/paride 0x13d0d228 pi_connect +EXPORT_SYMBOL drivers/block/paride/paride 0x37e56c6e pi_write_regr +EXPORT_SYMBOL drivers/block/paride/paride 0x3ef1488d pi_read_block +EXPORT_SYMBOL drivers/block/paride/paride 0x4f201349 pi_read_regr +EXPORT_SYMBOL drivers/block/paride/paride 0x82ca49b5 paride_unregister +EXPORT_SYMBOL drivers/block/paride/paride 0x8f5598b8 pi_write_block +EXPORT_SYMBOL drivers/block/paride/paride 0x94dc2bc6 pi_do_claimed +EXPORT_SYMBOL drivers/block/paride/paride 0xa319e633 pi_release +EXPORT_SYMBOL drivers/block/paride/paride 0xa9d4cd2d pi_disconnect +EXPORT_SYMBOL drivers/block/paride/paride 0xf467bdab paride_register +EXPORT_SYMBOL drivers/block/paride/paride 0xfd4d185e pi_init +EXPORT_SYMBOL drivers/cdrom/cdrom 0x192190da cdrom_get_last_written +EXPORT_SYMBOL drivers/cdrom/cdrom 0x22d812e3 cdrom_open +EXPORT_SYMBOL drivers/cdrom/cdrom 0x2bdd265d cdrom_ioctl +EXPORT_SYMBOL drivers/cdrom/cdrom 0x39db512a cdrom_number_of_slots +EXPORT_SYMBOL drivers/cdrom/cdrom 0x4e2d1cf8 cdrom_media_changed +EXPORT_SYMBOL drivers/cdrom/cdrom 0x4f476e96 init_cdrom_command +EXPORT_SYMBOL drivers/cdrom/cdrom 0x5fb84030 cdrom_release +EXPORT_SYMBOL drivers/cdrom/cdrom 0x68d652e6 cdrom_get_media_event +EXPORT_SYMBOL drivers/cdrom/cdrom 0x980b7eb0 unregister_cdrom +EXPORT_SYMBOL drivers/cdrom/cdrom 0x997e12a2 cdrom_mode_select +EXPORT_SYMBOL drivers/cdrom/cdrom 0xcd525e47 cdrom_mode_sense +EXPORT_SYMBOL drivers/cdrom/cdrom 0xe065326c register_cdrom +EXPORT_SYMBOL drivers/char/generic_serial 0x0b6a70f2 gs_start +EXPORT_SYMBOL drivers/char/generic_serial 0x144b1f11 gs_chars_in_buffer +EXPORT_SYMBOL drivers/char/generic_serial 0x3df7f106 gs_flush_chars +EXPORT_SYMBOL drivers/char/generic_serial 0x5c867aa8 gs_write +EXPORT_SYMBOL drivers/char/generic_serial 0x6d7f76d5 gs_set_termios +EXPORT_SYMBOL drivers/char/generic_serial 0x76178bde gs_getserial +EXPORT_SYMBOL drivers/char/generic_serial 0x8d605ee0 gs_got_break +EXPORT_SYMBOL drivers/char/generic_serial 0x97b41249 gs_close +EXPORT_SYMBOL drivers/char/generic_serial 0x9880879c gs_setserial +EXPORT_SYMBOL drivers/char/generic_serial 0x9c1bf9e5 gs_init_port +EXPORT_SYMBOL drivers/char/generic_serial 0xb512aa44 gs_stop +EXPORT_SYMBOL drivers/char/generic_serial 0xb909e5e7 gs_put_char +EXPORT_SYMBOL drivers/char/generic_serial 0xcd29e2c7 gs_hangup +EXPORT_SYMBOL drivers/char/generic_serial 0xe9bbba8e gs_flush_buffer +EXPORT_SYMBOL drivers/char/generic_serial 0xf0e69448 gs_write_room +EXPORT_SYMBOL drivers/char/generic_serial 0xf5e924a4 gs_block_til_ready +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x1ad90dc6 ipmi_set_maintenance_mode +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x232d014d ipmi_destroy_user +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x274f977b ipmi_set_gets_events +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x33beadab ipmi_smi_msg_received +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x40f2b10c ipmi_alloc_smi_msg +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x4c59ec1f ipmi_set_my_LUN +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x538e7d1b ipmi_set_my_address +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x67f5363c ipmi_get_my_address +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x6b930cca ipmi_free_recv_msg +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x70f2763a ipmi_smi_add_proc_entry +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x7f91a69d ipmi_request_supply_msgs +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x804f922a ipmi_addr_length +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x8a480e46 ipmi_unregister_smi +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x9655c1ae ipmi_get_my_LUN +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x99031808 ipmi_get_version +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xa0e28a35 ipmi_create_user +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xb60014a8 ipmi_poll_interface +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xb6e60293 ipmi_get_maintenance_mode +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xc085be97 ipmi_smi_watcher_unregister +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xce6fe5db ipmi_smi_watcher_register +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xd00390e8 ipmi_register_for_cmd +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xd335574d ipmi_request_settime +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xd66b3360 ipmi_unregister_for_cmd +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xe4f4665b ipmi_validate_addr +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xf2f01bb4 ipmi_smi_watchdog_pretimeout +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xf92ef271 ipmi_register_smi +EXPORT_SYMBOL drivers/char/nsc_gpio 0x3c090386 nsc_gpio_dump +EXPORT_SYMBOL drivers/char/nsc_gpio 0x464404c1 nsc_gpio_read +EXPORT_SYMBOL drivers/char/nsc_gpio 0xa63d05c4 nsc_gpio_write +EXPORT_SYMBOL drivers/char/nvram 0x0f28cb91 nvram_read_byte +EXPORT_SYMBOL drivers/char/nvram 0x17ff2c1d __nvram_read_byte +EXPORT_SYMBOL drivers/char/nvram 0x2adec1e0 __nvram_check_checksum +EXPORT_SYMBOL drivers/char/nvram 0x7da28f12 nvram_check_checksum +EXPORT_SYMBOL drivers/char/nvram 0x9ce3f83f nvram_write_byte +EXPORT_SYMBOL drivers/char/nvram 0xa8813189 __nvram_write_byte +EXPORT_SYMBOL drivers/cpufreq/cpufreq_conservative 0x8a98db8b cpufreq_gov_conservative +EXPORT_SYMBOL drivers/cpufreq/cpufreq_ondemand 0x6a9cfc28 cpufreq_gov_ondemand +EXPORT_SYMBOL drivers/cpufreq/cpufreq_powersave 0xcd36ab09 cpufreq_gov_powersave +EXPORT_SYMBOL drivers/cpufreq/cpufreq_userspace 0x359dc287 cpufreq_gov_userspace +EXPORT_SYMBOL drivers/edac/edac_core 0x8d99203c edac_mc_handle_fbd_ue +EXPORT_SYMBOL drivers/edac/edac_core 0xa6f4766c edac_mc_find +EXPORT_SYMBOL drivers/edac/edac_core 0xf50ba9f6 edac_mc_handle_fbd_ce +EXPORT_SYMBOL drivers/gpu/drm/drm 0x016c6051 drm_core_ioremapfree +EXPORT_SYMBOL drivers/gpu/drm/drm 0x02067f63 drm_ati_pcigart_init +EXPORT_SYMBOL drivers/gpu/drm/drm 0x0836695c drm_sman_takedown +EXPORT_SYMBOL drivers/gpu/drm/drm 0x0a0db752 drm_addbufs_pci +EXPORT_SYMBOL drivers/gpu/drm/drm 0x0cd4ce51 drm_core_ioremap +EXPORT_SYMBOL drivers/gpu/drm/drm 0x0f0d10d1 drm_get_resource_len +EXPORT_SYMBOL drivers/gpu/drm/drm 0x13215f69 drm_i_have_hw_lock +EXPORT_SYMBOL drivers/gpu/drm/drm 0x15f35590 drm_rmmap +EXPORT_SYMBOL drivers/gpu/drm/drm 0x1be06a67 drm_locked_tasklet +EXPORT_SYMBOL drivers/gpu/drm/drm 0x1cae8929 drm_getsarea +EXPORT_SYMBOL drivers/gpu/drm/drm 0x20645642 drm_debug +EXPORT_SYMBOL drivers/gpu/drm/drm 0x21451ac4 drm_sman_owner_cleanup +EXPORT_SYMBOL drivers/gpu/drm/drm 0x2916bf63 drm_sman_cleanup +EXPORT_SYMBOL drivers/gpu/drm/drm 0x2eb2f903 drm_sman_free_key +EXPORT_SYMBOL drivers/gpu/drm/drm 0x3074f033 drm_order +EXPORT_SYMBOL drivers/gpu/drm/drm 0x36b91c9f drm_agp_release +EXPORT_SYMBOL drivers/gpu/drm/drm 0x3ba92735 drm_agp_alloc +EXPORT_SYMBOL drivers/gpu/drm/drm 0x3ee4e806 drm_exit +EXPORT_SYMBOL drivers/gpu/drm/drm 0x3f31885e drm_addbufs_agp +EXPORT_SYMBOL drivers/gpu/drm/drm 0x43ba74a0 drm_get_drawable_info +EXPORT_SYMBOL drivers/gpu/drm/drm 0x51863651 drm_init +EXPORT_SYMBOL drivers/gpu/drm/drm 0x543316ba drm_pci_free +EXPORT_SYMBOL drivers/gpu/drm/drm 0x558fe78e drm_mmap +EXPORT_SYMBOL drivers/gpu/drm/drm 0x55f060ee drm_sman_set_range +EXPORT_SYMBOL drivers/gpu/drm/drm 0x574a9829 drm_get_resource_start +EXPORT_SYMBOL drivers/gpu/drm/drm 0x576534e8 drm_compat_ioctl +EXPORT_SYMBOL drivers/gpu/drm/drm 0x5848c432 drm_addmap +EXPORT_SYMBOL drivers/gpu/drm/drm 0x597695a7 drm_open +EXPORT_SYMBOL drivers/gpu/drm/drm 0x5de94840 drm_irq_uninstall +EXPORT_SYMBOL drivers/gpu/drm/drm 0x7235dfcd drm_pci_alloc +EXPORT_SYMBOL drivers/gpu/drm/drm 0x7388f69e drm_idlelock_take +EXPORT_SYMBOL drivers/gpu/drm/drm 0x786ab359 drm_release +EXPORT_SYMBOL drivers/gpu/drm/drm 0x7dcaeb15 drm_agp_unbind +EXPORT_SYMBOL drivers/gpu/drm/drm 0x84aa6990 drm_agp_bind +EXPORT_SYMBOL drivers/gpu/drm/drm 0x858c5554 drm_idlelock_release +EXPORT_SYMBOL drivers/gpu/drm/drm 0x9c25b192 drm_core_get_map_ofs +EXPORT_SYMBOL drivers/gpu/drm/drm 0xa8962fdf drm_ioctl +EXPORT_SYMBOL drivers/gpu/drm/drm 0xaf29788e drm_sman_init +EXPORT_SYMBOL drivers/gpu/drm/drm 0xbfa5b3ff drm_poll +EXPORT_SYMBOL drivers/gpu/drm/drm 0xc15fc3a2 drm_core_ioremap_wc +EXPORT_SYMBOL drivers/gpu/drm/drm 0xc5a4a604 drm_ati_pcigart_cleanup +EXPORT_SYMBOL drivers/gpu/drm/drm 0xc852620c drm_vbl_send_signals +EXPORT_SYMBOL drivers/gpu/drm/drm 0xcbebb049 drm_core_get_reg_ofs +EXPORT_SYMBOL drivers/gpu/drm/drm 0xd046ec23 drm_fasync +EXPORT_SYMBOL drivers/gpu/drm/drm 0xd2138fcd drm_sg_alloc +EXPORT_SYMBOL drivers/gpu/drm/drm 0xd3028e75 drm_sman_set_manager +EXPORT_SYMBOL drivers/gpu/drm/drm 0xd5c7af13 drm_agp_enable +EXPORT_SYMBOL drivers/gpu/drm/drm 0xe57af146 drm_agp_acquire +EXPORT_SYMBOL drivers/gpu/drm/drm 0xe919dd5c drm_sman_owner_clean +EXPORT_SYMBOL drivers/gpu/drm/drm 0xee6e6544 drm_agp_free +EXPORT_SYMBOL drivers/gpu/drm/drm 0xf702a542 drm_agp_info +EXPORT_SYMBOL drivers/gpu/drm/drm 0xf9dfb525 drm_core_reclaim_buffers +EXPORT_SYMBOL drivers/gpu/drm/drm 0xfdfbad19 drm_sman_alloc +EXPORT_SYMBOL drivers/hwmon/hwmon-vid 0x0903c239 vid_from_reg +EXPORT_SYMBOL drivers/hwmon/hwmon-vid 0xef1c781c vid_which_vrm +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-bit 0x76a15344 i2c_bit_add_numbered_bus +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-bit 0xaa21220d i2c_bit_add_bus +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-pca 0x21c7ce25 i2c_pca_add_numbered_bus +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-pca 0x7cb0efa2 i2c_pca_add_bus +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-pcf 0x4247dceb i2c_pcf_add_bus +EXPORT_SYMBOL drivers/i2c/busses/i2c-amd756 0x7be0448f amd756_smbus +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0x02d4ad0f tps65013_set_low_pwr +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0x28485130 tps65010_config_vregs1 +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0x33739de7 tps65010_set_vib +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0x9fd44c69 tps65010_set_led +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0xb14080cc tps65010_set_low_pwr +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0xd5bb106d tps65010_set_vbus_draw +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0xe99b3f36 tps65010_set_gpio_out_value +EXPORT_SYMBOL drivers/i2c/i2c-core 0x079e8c06 i2c_verify_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0x24f6f563 i2c_smbus_xfer +EXPORT_SYMBOL drivers/i2c/i2c-core 0x2cddfb97 i2c_smbus_read_word_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0x31ea6d9f i2c_transfer +EXPORT_SYMBOL drivers/i2c/i2c-core 0x36a6f18c i2c_smbus_read_byte_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0x399c89f0 i2c_smbus_write_i2c_block_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0x3a3efd43 i2c_smbus_write_word_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0x3a8d6008 i2c_release_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0x3c216405 i2c_detach_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0x3dfc5fd3 i2c_get_adapter +EXPORT_SYMBOL drivers/i2c/i2c-core 0x5a7110d3 i2c_attach_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0x6c562273 i2c_smbus_write_block_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0x78c6a457 i2c_add_adapter +EXPORT_SYMBOL drivers/i2c/i2c-core 0x7e369678 i2c_master_recv +EXPORT_SYMBOL drivers/i2c/i2c-core 0x7ff65204 i2c_del_adapter +EXPORT_SYMBOL drivers/i2c/i2c-core 0x9a77f4c8 i2c_smbus_read_i2c_block_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0xb3d27114 i2c_smbus_read_byte +EXPORT_SYMBOL drivers/i2c/i2c-core 0xbd2088f9 i2c_put_adapter +EXPORT_SYMBOL drivers/i2c/i2c-core 0xc63dfb9c i2c_smbus_read_block_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0xd6266c53 i2c_register_driver +EXPORT_SYMBOL drivers/i2c/i2c-core 0xd7269ecd i2c_use_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0xd97f555f i2c_smbus_write_byte_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0xe1c595d5 i2c_probe +EXPORT_SYMBOL drivers/i2c/i2c-core 0xe4e08cc6 i2c_master_send +EXPORT_SYMBOL drivers/i2c/i2c-core 0xe69633ea i2c_smbus_write_byte +EXPORT_SYMBOL drivers/i2c/i2c-core 0xfa83f1fe i2c_clients_command +EXPORT_SYMBOL drivers/i2c/i2c-core 0xfa8fe351 i2c_del_driver +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0428d633 hpsb_make_writepacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x049abdd1 hpsb_unregister_highlevel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0b234c4e dma_prog_region_alloc +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0b7a2edb hpsb_read +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0c6da941 csr1212_release_keyval +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0c75232d hpsb_free_tlabel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0e5a659c csr1212_new_directory +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x1197b213 hpsb_node_write +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x12ee6828 hpsb_register_addrspace +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x13b4a268 csr1212_attach_keyval_to_directory +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x158ac548 dma_region_offset_to_bus +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x19f1f97b csr1212_parse_keyval +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x1c4fa3e4 hpsb_node_fill_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x1eb1bde3 hpsb_packet_received +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x25fbeb4c hpsb_register_highlevel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x262bc01e hpsb_iso_stop +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x2956fad8 hpsb_selfid_received +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x2dd29f75 csr1212_read +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x2ebf6e5a dma_prog_region_init +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x40281746 hpsb_packet_success +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x478c1518 hpsb_make_readpacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x4790f0f1 hpsb_iso_recv_unlisten_channel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x4ef15d4f hpsb_bus_reset +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x4f4aeb57 hpsb_iso_recv_release_packets +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x51d547b0 hpsb_get_tlabel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x5283e839 hpsb_iso_recv_listen_channel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x53b2bccc hpsb_make_phypacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x5978a496 hpsb_unregister_protocol +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x5e52389c hpsb_free_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x606d6a0b hpsb_protocol_class +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x672ad148 dma_region_sync_for_device +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x68bdf951 hpsb_add_host +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x6d7de354 hpsb_iso_wake +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x74b4449b hpsb_iso_xmit_sync +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x76bc1a5c dma_region_free +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x79530b08 csr1212_get_keyval +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x7d21ba8a hpsb_send_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x802d76fa hpsb_make_streampacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x81db99da hpsb_iso_recv_flush +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x8879f8f0 dma_region_sync_for_cpu +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x88ab873e hpsb_iso_xmit_queue_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x8ec2b312 dma_region_alloc +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x9530b20c hpsb_packet_sent +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x95cd109a hpsb_selfid_complete +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x9b167936 hpsb_iso_recv_set_channel_mask +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x9bd57a42 hpsb_unregister_addrspace +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xa0ccf3b3 hpsb_iso_packet_received +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xa92ccd09 dma_region_mmap +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xaec9368b hpsb_update_config_rom_image +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xaf1c5440 hpsb_resume_host +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xafedf7e1 hpsb_iso_recv_init +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xb2b2c7a1 hpsb_destroy_hostinfo +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xb5f090b2 hpsb_remove_host +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xbad29a07 hpsb_set_hostinfo_key +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xbd6a73f8 hpsb_iso_packet_sent +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xc3f909b1 hpsb_get_hostinfo +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xc4c32ab3 hpsb_allocate_and_register_addrspace +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xc5c5f782 hpsb_make_lock64packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xc669a4d3 csr1212_detach_keyval_from_directory +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xcd9e772b dma_prog_region_free +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xcff18917 hpsb_read_cycle_timer +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xd0a2cb3f hpsb_update_config_rom +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xd839d8f3 hpsb_iso_xmit_init +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xdade9c86 hpsb_write +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xdaf0a3b2 hpsb_make_lockpacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xe17d4ef3 hpsb_reset_bus +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xe4189dc7 __hpsb_register_protocol +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xe6e46c46 hpsb_iso_shutdown +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xe9fadca4 hpsb_set_packet_complete_task +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xea4152ff dma_region_init +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xee87e51d hpsb_iso_n_ready +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xf0d9960b hpsb_iso_xmit_start +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xf53a55ca hpsb_set_hostinfo +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xf6531ee9 hpsb_get_hostinfo_bykey +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xf79b92ab hpsb_alloc_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xfba57f51 hpsb_speedto_str +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xfdbc5ab2 hpsb_iso_recv_start +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xfe093883 hpsb_alloc_host +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xff6c8d3f hpsb_create_hostinfo +EXPORT_SYMBOL drivers/ieee1394/ohci1394 0x0d4fe9d5 ohci1394_stop_context +EXPORT_SYMBOL drivers/ieee1394/ohci1394 0xa0293c47 ohci1394_unregister_iso_tasklet +EXPORT_SYMBOL drivers/ieee1394/ohci1394 0xb37ab086 ohci1394_init_iso_tasklet +EXPORT_SYMBOL drivers/ieee1394/ohci1394 0xbf186416 ohci1394_register_iso_tasklet +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0x465abc1d rdma_translate_ip +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0x71de06c2 rdma_addr_register_client +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0xbe81bb46 rdma_addr_unregister_client +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0xc4a5ba2b rdma_addr_cancel +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0xcfdf4b0c rdma_resolve_ip +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0xe362de74 rdma_copy_addr +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x2c89379f ib_send_cm_apr +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x2ead2ef4 ib_send_cm_sidr_req +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x40137a98 ib_cm_listen +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x42788db5 cm_class +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x4364abbd ib_create_cm_id +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x4ec838ab ib_cm_init_qp_attr +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x500ed67a ib_cm_notify +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x53dd7554 ib_send_cm_drep +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x5fd77eaa ib_send_cm_rep +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x7ae669d7 ib_send_cm_sidr_rep +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x7c00d5c1 ib_send_cm_dreq +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x7fe02918 ib_send_cm_req +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x8f459ed4 ib_send_cm_rej +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0xb06ec358 ib_destroy_cm_id +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0xb1ecb93a ib_send_cm_lap +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0xec439551 ib_send_cm_mra +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0xf98a0c2f ib_send_cm_rtu +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x06830b9a ib_pack +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x0964c4da ib_modify_cq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x0b248c8d ib_find_cached_gid +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x0f957906 ib_query_pkey +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x10122270 ib_destroy_cq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x1271c09a ib_create_fmr_pool +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x1921fc61 ib_query_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x1e491a04 ib_unmap_fmr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x1f58ecc1 ib_get_cached_pkey +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x231a6e93 ib_alloc_fast_reg_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x259834f1 ib_init_ah_from_wc +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x2b8f6d54 ib_get_cached_lmc +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x3506abbb ib_set_client_data +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x36848662 ib_register_event_handler +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x373c6da1 ib_detach_mcast +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x3b5e707b ib_query_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x3eb9d53f ib_query_srq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x3f7567fd ib_rate_to_mult +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x4432c666 ib_rereg_phys_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x474ca838 ib_register_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x588a0061 ib_dealloc_pd +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x592ca5ce ib_create_srq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x62ae14cd ib_umem_release +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x699ff3b6 ib_destroy_fmr_pool +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x6a2bb8f9 ib_destroy_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x6b10f6ab ib_modify_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x704e804b ib_dereg_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x7235ee5d ib_destroy_ah +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x728d4eea ib_modify_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x731b6898 ib_alloc_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x735ea645 ib_flush_fmr_pool +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x753191e7 ib_fmr_pool_map_phys +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x78b45481 ib_create_ah +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x7967e26e ib_dealloc_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x7cf9419d ib_unregister_client +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x855a57ca ib_find_cached_pkey +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x856dc8ae ib_get_dma_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x8640eaeb ib_modify_qp_is_ok +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x86dc4a4c ib_create_ah_from_wc +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x87b614d8 ib_ud_header_pack +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x907707a5 ib_umem_page_count +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x95b6837c ib_create_cq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x96ce6c46 rdma_node_get_transport +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x99a2094a ib_dealloc_mw +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x9d804fa1 mult_to_ib_rate +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xa17c4d91 ib_query_ah +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xa5984d7b ib_alloc_pd +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xa73cb4ca ib_alloc_mw +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xab693bd0 ib_dealloc_fmr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xadd9225d ib_get_client_data +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xb07c55e4 ib_dispatch_event +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xb3004b57 ib_modify_ah +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xb774bb9f ib_reg_phys_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xb7b1f331 ib_query_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xbc1f0063 ib_find_gid +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xc0e27f25 ib_destroy_srq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xcabf41af ib_alloc_fmr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xd17ba9d1 ib_ud_header_init +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xd77f8f39 ib_modify_srq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xd93d3258 ib_attach_mcast +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xdc93a1f7 ib_unregister_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xddc775a0 ib_query_port +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xdeda17d2 ib_get_cached_gid +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xe3374fd3 ib_free_fast_reg_page_list +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xe44a6d2b ib_unregister_event_handler +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xe4b25a7c ib_find_pkey +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xe9ba86dd ib_alloc_fast_reg_page_list +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xe9fd8052 ib_modify_port +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xed5ed015 ib_resize_cq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xee72ba70 ib_register_client +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf2d2bcae ib_query_gid +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf36498b9 ib_ud_header_unpack +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf3e1ace5 ib_create_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf57b2598 ib_fmr_pool_unmap +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf96fc9de ib_unpack +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf9831468 ib_umem_get +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x0fc9cca2 ib_modify_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x267035d0 ib_register_mad_snoop +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x3750239d ib_process_mad_wc +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x4ac70f4f ib_unregister_mad_agent +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x52d45043 ib_create_send_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x56343a94 ib_redirect_mad_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x6b63e17b ib_cancel_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x6ef787ed ib_response_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x6f077fcf ib_get_mad_data_offset +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x7b5d4b7a ib_is_mad_class_rmpp +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0xb13fd774 ib_get_rmpp_segment +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0xe06ea7bd ib_register_mad_agent +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0xe0916d6b ib_post_send_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0xf1109a13 ib_free_send_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0xf6ac6a5d ib_free_recv_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x16199856 ib_sa_register_client +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x1f8df4ab ib_init_ah_from_path +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x512ba124 ib_sa_unregister_client +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x576fdbac ib_sa_free_multicast +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x8c0388fc ib_sa_get_mcmember_rec +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0xa3a2ff6e ib_sa_cancel_query +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0xa487a41c ib_sa_service_rec_query +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0xb99bf08c ib_sa_path_rec_get +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0xe79e5753 ib_init_ah_from_mcmember +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0xfae37340 ib_sa_join_multicast +EXPORT_SYMBOL drivers/infiniband/core/ib_uverbs 0x02f847bc ib_copy_path_rec_from_user +EXPORT_SYMBOL drivers/infiniband/core/ib_uverbs 0x07cf5a51 ib_copy_ah_attr_to_user +EXPORT_SYMBOL drivers/infiniband/core/ib_uverbs 0x18382f6a ib_copy_path_rec_to_user +EXPORT_SYMBOL drivers/infiniband/core/ib_uverbs 0x184f3575 ib_copy_qp_attr_to_user +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x024070f3 iw_cm_init_qp_attr +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x0fe2d77b iw_cm_disconnect +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x6e929c50 iw_create_cm_id +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x7c9da8b4 iw_cm_accept +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0xb0d99b2d iw_cm_reject +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0xbf424f07 iw_cm_listen +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0xd21d5d07 iw_cm_connect +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0xdab98fa1 iw_destroy_cm_id +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x0deed028 rdma_init_qp_attr +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x0e26f252 rdma_reject +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x153389fe rdma_resolve_route +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x1f31eea0 rdma_leave_multicast +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x4528432e rdma_join_multicast +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x4a4c7dbb rdma_resolve_addr +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x56070c87 rdma_connect +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x6d1da4f4 rdma_create_id +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x72749340 rdma_listen +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x921170de rdma_create_qp +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x9f985a83 rdma_destroy_id +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xa1ad4b53 rdma_set_service_type +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xa298ad31 rdma_set_ib_paths +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xa53ace18 rdma_bind_addr +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xdd2835e2 rdma_accept +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xe0a9dd32 rdma_disconnect +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xe46e0fb6 rdma_notify +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xe85d17f5 rdma_destroy_qp +EXPORT_SYMBOL drivers/input/gameport/gameport 0x2abd60a7 gameport_set_phys +EXPORT_SYMBOL drivers/input/gameport/gameport 0x479f6b03 __gameport_register_driver +EXPORT_SYMBOL drivers/input/gameport/gameport 0x90cadb26 gameport_stop_polling +EXPORT_SYMBOL drivers/input/gameport/gameport 0x94ea3ccd __gameport_register_port +EXPORT_SYMBOL drivers/input/gameport/gameport 0x9e166883 gameport_start_polling +EXPORT_SYMBOL drivers/input/gameport/gameport 0xa693b497 gameport_close +EXPORT_SYMBOL drivers/input/gameport/gameport 0xc4b07247 gameport_unregister_driver +EXPORT_SYMBOL drivers/input/gameport/gameport 0xcf51c759 gameport_unregister_port +EXPORT_SYMBOL drivers/input/gameport/gameport 0xdb8de8ed gameport_open +EXPORT_SYMBOL drivers/input/input-polldev 0x2001320b input_unregister_polled_device +EXPORT_SYMBOL drivers/input/input-polldev 0x471db174 input_register_polled_device +EXPORT_SYMBOL drivers/input/input-polldev 0x8820049f input_free_polled_device +EXPORT_SYMBOL drivers/input/input-polldev 0xd7d51bc6 input_allocate_polled_device +EXPORT_SYMBOL drivers/isdn/capi/capifs 0x2c54c957 capifs_free_ncci +EXPORT_SYMBOL drivers/isdn/capi/capifs 0xd0bc06ce capifs_new_ncci +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x04403fcf unregister_capi_driver +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x063083d1 capi_ctr_handle_message +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x14f2aa5a capi20_get_version +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x2b8eab1f capilib_free_ncci +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x2baa6586 capilib_new_ncci +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x31c24aa4 capi20_isinstalled +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x3eb76e1f capi_ctr_reseted +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x3efa95b8 capi_ctr_suspend_output +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x47d3fc51 capi_info2str +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x47dbfa0a capi_message2str +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x50b33ca4 capi_cmsg2message +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x56d99518 capi20_set_callback +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x6057c6f3 capi_message2cmsg +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x62e32d43 capilib_data_b3_conf +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x71e8d5ba capilib_data_b3_req +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x788d398c capi_cmsg2str +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x7a33596c capi20_get_serial +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x7e6f1307 capi20_get_manufacturer +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x8f699913 capilib_release +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x8f71ada9 capi20_release +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x9b37a67d attach_capi_ctr +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x9f823278 register_capi_driver +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xaa165d27 capilib_release_appl +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xada5fb07 capi20_put_message +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xb19fda8d capi_cmd2str +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xb60e5e5f capi_cmsg_header +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xc5327ee3 capi20_register +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xd422510f detach_capi_ctr +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xe19a11ac capi20_get_profile +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xe46ddddd capi_ctr_ready +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xe9f62f29 cdebbuf_free +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xed061606 capi20_manufacturer +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xfcbd8c6a capi_ctr_resume_output +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x0c083cad b1_load_config +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x1c6f14fe avmcard_dma_free +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x6255dd36 b1ctl_read_proc +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x6860d3c8 b1_free_card +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x6c2cad8c b1_load_t4file +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x7bcd36e0 b1_parse_version +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x845e81f1 b1_send_message +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x85f09690 b1_irq_table +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x8cf25b66 b1_reset_ctr +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x96f9d2f4 b1_interrupt +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xab4804bd b1_alloc_card +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xac12bf96 b1_release_appl +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xbb61030d b1_register_appl +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xd9cea233 b1_loaded +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xddba37dd b1_load_firmware +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xdfd28376 b1_detect +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xecc24205 b1_getrevision +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xece37f1e avmcard_dma_alloc +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x15a81ce9 b1dma_register_appl +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x22416f8f t1pci_detect +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x2a386384 b1dma_interrupt +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x36813403 b1dma_load_firmware +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x49565182 b1pciv4_detect +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x68cab23c b1dma_reset +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x810f174a b1dma_release_appl +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0xb0e19889 b1dma_send_message +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0xccabd7da b1dmactl_read_proc +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0xed04740c b1dma_reset_ctr +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1pcmcia 0x29562993 b1pcmcia_delcard +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1pcmcia 0xaec3240e b1pcmcia_addcard_m1 +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1pcmcia 0xea620116 b1pcmcia_addcard_m2 +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1pcmcia 0xf14bf8b1 b1pcmcia_addcard_b1 +EXPORT_SYMBOL drivers/isdn/hardware/eicon/divadidd 0x2974ead1 DIVA_DIDD_Read +EXPORT_SYMBOL drivers/isdn/hardware/eicon/divadidd 0x9767d6b0 proc_net_eicon +EXPORT_SYMBOL drivers/isdn/hardware/mISDN/hfcmulti 0x5293ed86 plx_lock +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x07f4f2ce hisax_unregister +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x148f0c99 FsmFree +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x2844a899 FsmInitTimer +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x93a64734 FsmChangeState +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x9df0cd27 FsmEvent +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xb071ba1a hisax_init_pcmcia +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xc0c558f9 FsmRestartTimer +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xd94696e8 FsmDelTimer +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xee93522c hisax_register +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xf0a16657 FsmNew +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xfc27303b HiSax_closecard +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0x02161f1f isac_irq +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0x20b32ae1 isacsx_irq +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0x26f9f0fd isacsx_setup +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0x3f3b323a isac_d_l2l1 +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0xf20e25fb isac_init +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0xfa75da48 isac_setup +EXPORT_SYMBOL drivers/isdn/hisax/isdnhdlc 0x1ee629e2 isdnhdlc_rcv_init +EXPORT_SYMBOL drivers/isdn/hisax/isdnhdlc 0x95aed401 isdnhdlc_decode +EXPORT_SYMBOL drivers/isdn/hisax/isdnhdlc 0x9ffc8215 isdnhdlc_out_init +EXPORT_SYMBOL drivers/isdn/hisax/isdnhdlc 0xf5c8131d isdnhdlc_encode +EXPORT_SYMBOL drivers/isdn/i4l/isdn 0x031110ee isdn_ppp_register_compressor +EXPORT_SYMBOL drivers/isdn/i4l/isdn 0x55ac72f2 isdn_ppp_unregister_compressor +EXPORT_SYMBOL drivers/isdn/i4l/isdn 0xc44258d8 register_isdn +EXPORT_SYMBOL drivers/isdn/i4l/isdn 0xfa06820f isdn_register_divert +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x0f662ec1 mISDN_register_Bprotocol +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x2348cc3c mISDN_FsmFree +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x3e5c383a dchannel_senddata +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x3ea336fd mISDN_FsmAddTimer +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x429129f2 mISDN_FsmRestartTimer +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x4a441a3c create_l1 +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x50c2230c mISDN_FsmChangeState +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x5456a7ae mISDN_register_device +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x6b5b72fe recv_Dchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x8316b46a mISDN_freedchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x852819b0 mISDN_initbchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x8ac129fb recv_Dchannel_skb +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x8b5a5721 mISDN_unregister_device +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x8e01b874 queue_ch_frame +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x93a91da3 confirm_Bsend +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x9632f7f9 recv_Bchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x96653ee4 l1_event +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x98d35fb2 bchannel_senddata +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xab78d973 mISDN_freebchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xace35cae mISDN_FsmDelTimer +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xae74e58a recv_Bchannel_skb +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xb1e52f0e mISDN_initdchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xc1a13e2f get_next_dframe +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xd5145151 mISDN_FsmEvent +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xd593cf94 mISDN_unregister_Bprotocol +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xd9a7fbfd mISDN_FsmInitTimer +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xf9e7832f mISDN_FsmNew +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xfbad0b3a get_next_bframe +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_dsp 0x4c2ec443 mISDN_dsp_element_register +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_dsp 0x60721da7 dsp_audio_law_to_s32 +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_dsp 0xa215f1b2 dsp_audio_s16_to_law +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_dsp 0xd3a023b8 mISDN_dsp_element_unregister +EXPORT_SYMBOL drivers/md/dm-log 0x4880c264 dm_dirty_log_destroy +EXPORT_SYMBOL drivers/md/dm-log 0x644b6a5a dm_dirty_log_create +EXPORT_SYMBOL drivers/md/dm-log 0xbf2dc12e dm_dirty_log_type_unregister +EXPORT_SYMBOL drivers/md/dm-log 0xd7385f07 dm_dirty_log_type_register +EXPORT_SYMBOL drivers/md/dm-mod 0x003bed6e dm_table_unplug_all +EXPORT_SYMBOL drivers/md/dm-mod 0x00e3d04b dm_kcopyd_client_destroy +EXPORT_SYMBOL drivers/md/dm-mod 0x0dea331b dm_put_device +EXPORT_SYMBOL drivers/md/dm-mod 0x1a1d7bed dm_io_client_create +EXPORT_SYMBOL drivers/md/dm-mod 0x2eb9a50a dm_table_get_md +EXPORT_SYMBOL drivers/md/dm-mod 0x6694edb0 dm_io +EXPORT_SYMBOL drivers/md/dm-mod 0x68e1d866 dm_table_get_size +EXPORT_SYMBOL drivers/md/dm-mod 0x810eb350 dm_get_device +EXPORT_SYMBOL drivers/md/dm-mod 0x82f65633 dm_io_client_resize +EXPORT_SYMBOL drivers/md/dm-mod 0x8ae69d26 dm_kcopyd_copy +EXPORT_SYMBOL drivers/md/dm-mod 0x8f9f74ff dm_table_get +EXPORT_SYMBOL drivers/md/dm-mod 0x954c8af3 dm_io_client_destroy +EXPORT_SYMBOL drivers/md/dm-mod 0x99f61493 dm_kcopyd_client_create +EXPORT_SYMBOL drivers/md/dm-mod 0x9e8a1636 dm_table_put +EXPORT_SYMBOL drivers/md/dm-mod 0xbaa86806 dm_unregister_target +EXPORT_SYMBOL drivers/md/dm-mod 0xc01512a1 dm_table_event +EXPORT_SYMBOL drivers/md/dm-mod 0xc79bcd36 dm_vcalloc +EXPORT_SYMBOL drivers/md/dm-mod 0xe98743a1 dm_register_target +EXPORT_SYMBOL drivers/md/dm-mod 0xebffc4a0 dm_table_get_mode +EXPORT_SYMBOL drivers/md/dm-mod 0xf6d4b659 dm_get_mapinfo +EXPORT_SYMBOL drivers/md/md-mod 0x13e24e1a md_wakeup_thread +EXPORT_SYMBOL drivers/md/md-mod 0x41e9596e md_write_start +EXPORT_SYMBOL drivers/md/md-mod 0x6661b97c bitmap_start_sync +EXPORT_SYMBOL drivers/md/md-mod 0x6cebe08d md_done_sync +EXPORT_SYMBOL drivers/md/md-mod 0x6e4bf850 bitmap_unplug +EXPORT_SYMBOL drivers/md/md-mod 0x79131fe0 register_md_personality +EXPORT_SYMBOL drivers/md/md-mod 0x84659205 md_check_recovery +EXPORT_SYMBOL drivers/md/md-mod 0x915132f0 md_write_end +EXPORT_SYMBOL drivers/md/md-mod 0x9a713c99 md_register_thread +EXPORT_SYMBOL drivers/md/md-mod 0x9faed9d0 bitmap_startwrite +EXPORT_SYMBOL drivers/md/md-mod 0xb77a3b41 bitmap_end_sync +EXPORT_SYMBOL drivers/md/md-mod 0xb8e75239 md_wait_for_blocked_rdev +EXPORT_SYMBOL drivers/md/md-mod 0xdc231cc7 unregister_md_personality +EXPORT_SYMBOL drivers/md/md-mod 0xe2821d25 md_error +EXPORT_SYMBOL drivers/md/md-mod 0xe48eedcf bitmap_cond_end_sync +EXPORT_SYMBOL drivers/md/md-mod 0xe79ced82 bitmap_close_sync +EXPORT_SYMBOL drivers/md/md-mod 0xf182bcb7 bitmap_endwrite +EXPORT_SYMBOL drivers/md/md-mod 0xf4e572b6 md_unregister_thread +EXPORT_SYMBOL drivers/media/common/tuners/mt2060 0x802a6a6c mt2060_attach +EXPORT_SYMBOL drivers/media/common/tuners/mt2131 0x76163772 mt2131_attach +EXPORT_SYMBOL drivers/media/common/tuners/mt2266 0x6cb35daf mt2266_attach +EXPORT_SYMBOL drivers/media/common/tuners/mxl5005s 0x926da07a mxl5005s_attach +EXPORT_SYMBOL drivers/media/common/tuners/qt1010 0x69b2f61c qt1010_attach +EXPORT_SYMBOL drivers/media/common/tuners/tuner-types 0x0cb4b189 tuners +EXPORT_SYMBOL drivers/media/common/tuners/tuner-types 0xc2821775 tuner_count +EXPORT_SYMBOL drivers/media/common/tuners/tuner-xc2028 0xe82039d3 xc2028_attach +EXPORT_SYMBOL drivers/media/common/tuners/xc5000 0xe7dfb692 xc5000_attach +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x19d93b07 flexcop_wan_set_speed +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x2400fd97 flexcop_device_kmalloc +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x3d0c7010 flexcop_dump_reg +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x3f953981 flexcop_eeprom_check_mac_addr +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x514586ed flexcop_device_initialize +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x5fe810ae flexcop_sram_set_dest +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x673e04e9 flexcop_dma_control_timer_irq +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x7e70da54 flexcop_dma_allocate +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x84f88350 flexcop_dma_free +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xad8832c3 flexcop_dma_control_size_irq +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xafefe471 flexcop_device_kfree +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xb30f12b0 flexcop_dma_config_timer +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xb66848c4 flexcop_device_exit +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xc5559095 flexcop_dma_config +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xce1da88d flexcop_dma_xfer_control +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xda431c8f flexcop_i2c_request +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xdae6d364 flexcop_pass_dmx_packets +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xdbf919b5 flexcop_sram_ctrl +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xfacb36bd flexcop_pass_dmx_data +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0x5ce4e38b bt878_stop +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0x6d59c988 bt878_start +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0xabe7cdc2 bt878_device_control +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0xd5d0bdef bt878_num +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0xd9149ae7 bt878 +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x396fadc6 dst_attach +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x6a944033 read_dst +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x7a9c6b00 dst_error_recovery +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x9738caf5 dst_pio_disable +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x9f935995 rdc_reset_state +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0xa5886aca write_dst +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0xb3e88cba dst_error_bailout +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0xbabe6726 dst_wait_dst_ready +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0xcd385511 dst_comm_init +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0xe94b8c9c dst_check_sum +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst_ca 0x9a902048 dst_ca_attach +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x04751e94 dvb_ca_en50221_camchange_irq +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x0522643a dvb_ca_en50221_frda_irq +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x0c457c5c dvb_ringbuffer_flush_spinlock_wakeup +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x27c442da dvb_register_adapter +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x2d91ccd5 dvb_frontend_reinitialise +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x36c8ea1f dvb_frontend_sleep_until +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x36ee6a8d dvb_generic_ioctl +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x41dbd5c2 dvb_frontend_detach +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x4a1833cb dvb_net_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x4c3aa726 dvb_ca_en50221_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x4db3899f dvb_dmx_swfilter_packets +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x51f3767c dvb_ringbuffer_read +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x588fcdd7 dvb_generic_open +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x6988f784 dvb_ringbuffer_read_user +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x6baad588 dvb_generic_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x6d86d432 dvb_ca_en50221_camready_irq +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x74a5a698 dvb_filter_pes2ts_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x80e3832d dvb_filter_get_ac3info +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x8981f50e dvb_dmxdev_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x8b49a23f timeval_usec_diff +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x926a9013 dvb_ca_en50221_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xac4ca1b0 intlog2 +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xb3538843 dvb_register_device +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xc14ee960 dvb_register_frontend +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xc324b69b dvb_dmx_swfilter_204 +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xc80754c1 dvb_dmx_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xcb89fc7d dvb_ringbuffer_free +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xcbb0fa2f dvb_unregister_device +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xcbfa9467 dvb_unregister_adapter +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xcca08cb5 dvb_ringbuffer_avail +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xcce0eeed dvb_ringbuffer_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xd16af7c8 dvb_net_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xd639b9bc dvb_ringbuffer_write +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xd7765e69 dvb_ringbuffer_empty +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xda72f1dd dvb_unregister_frontend +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xe5ae8707 intlog10 +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xee73de0a dvb_dmx_swfilter +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xf5523dbf dvb_dmxdev_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xf826deb0 dvb_filter_pes2ts +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xf86f20c5 dvb_dmx_init +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x123b460a dvb_usb_generic_write +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x15b79b40 dvb_usb_nec_rc_key_to_event +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x71d07d28 dvb_usb_device_init +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x7c37843c usb_cypress_load_firmware +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x8a412dc2 dvb_usb_get_hexline +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x9cd69676 dvb_usb_generic_rw +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0xe63853cb dvb_usb_device_exit +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-af9005-remote 0x2edc4728 af9005_rc_keys +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-af9005-remote 0x75d47674 af9005_rc_decode +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-af9005-remote 0xd3383957 af9005_rc_keys_size +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x3b24ac0e dibusb_dib3000mc_frontend_attach +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x453e54ad dibusb_pid_filter +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x600dee9b dibusb_dib3000mc_tuner_attach +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x66c10282 dibusb2_0_power_ctrl +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x90c32ea9 dibusb_read_eeprom_byte +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x93d5c8b4 dibusb_power_ctrl +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xb1b1eb62 dibusb_rc_query +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xb6264045 dibusb_streaming_ctrl +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xca64ae74 dibusb_pid_filter_ctrl +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xd4d3dddc dibusb_rc_keys +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xeb2055c5 dibusb_i2c_algo +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xf3531d55 dibusb2_0_streaming_ctrl +EXPORT_SYMBOL drivers/media/dvb/frontends/au8522 0x2cc85018 au8522_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/bcm3510 0xa26586fd bcm3510_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/cx22700 0x6a32bf83 cx22700_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/cx22702 0xe18867aa cx22702_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/cx24110 0xe1df181e cx24110_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/cx24123 0x61cdd990 cx24123_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/cx24123 0xfff1acfc cx24123_get_tuner_i2c_adapter +EXPORT_SYMBOL drivers/media/dvb/frontends/dib0070 0xb0a7fdda dib0070_wbd_offset +EXPORT_SYMBOL drivers/media/dvb/frontends/dib0070 0xd3daf29a dib0070_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mb 0xee7cdb91 dib3000mb_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0x0411c931 dib3000mc_i2c_enumeration +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0x2e530589 dib3000mc_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0x44e678f1 dib3000mc_set_config +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0x818bae84 dib3000mc_pid_parse +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0xf683482f dib3000mc_pid_control +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0xfe0ff8f9 dib3000mc_get_tuner_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000m 0x4bb865b8 dib7000m_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000m 0xb7586a51 dib7000m_i2c_enumeration +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000m 0xbc21e602 dib7000m_get_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0x220c1264 dib7000p_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0x763641ef dib7000pc_detection +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0x7c60dcc2 dib7000p_i2c_enumeration +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0xb84d86c2 dib7000p_get_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0xc17e5363 dib7000p_set_gpio +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0xefdc1cbe dib7000p_set_wbd_ref +EXPORT_SYMBOL drivers/media/dvb/frontends/dibx000_common 0x2417075f dibx000_init_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/dibx000_common 0xd9151fcb dibx000_get_i2c_adapter +EXPORT_SYMBOL drivers/media/dvb/frontends/dibx000_common 0xfe4f9a6f dibx000_exit_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/drx397xD 0x1e015655 drx397xD_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dvb-pll 0x0c7552d5 dvb_pll_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/isl6405 0x10f1e93a isl6405_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/isl6421 0x87717867 isl6421_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/itd1000 0xc9913e31 itd1000_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/l64781 0xeb81b99a l64781_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/lgdt330x 0xa9ef4257 lgdt330x_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/lnbp21 0x2c9555ed lnbp21_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/mt312 0x93e429e4 mt312_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/mt352 0x5e2a0ea1 mt352_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/nxt200x 0xf6de9d04 nxt200x_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/nxt6000 0xa2ddaedb nxt6000_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/or51132 0x297fc326 or51132_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/or51211 0x7fa4a72c or51211_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/s5h1409 0xa4e2737b s5h1409_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/s5h1411 0x17abd4e6 s5h1411_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/s5h1420 0x454eab5e s5h1420_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/s5h1420 0xa26603fe s5h1420_get_tuner_i2c_adapter +EXPORT_SYMBOL drivers/media/dvb/frontends/sp8870 0xbc03e529 sp8870_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/sp887x 0x5f11d4b5 sp887x_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/stv0297 0x65f75d7a stv0297_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/stv0299 0x7c1e23d9 stv0299_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda10021 0x61378c2f tda10021_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda10023 0x44794fe3 tda10023_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda10048 0x4402de1c tda10048_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda1004x 0x2190d55c tda10046_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda1004x 0x5a602d86 tda10045_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda10086 0xb6fdc76e tda10086_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda8083 0xa84e499c tda8083_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda826x 0xfee79f00 tda826x_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tua6100 0xaddcc849 tua6100_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/ves1820 0x2bf3dbc4 ves1820_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/ves1x93 0x444bbcee ves1x93_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/zl10353 0xf208ee85 zl10353_attach +EXPORT_SYMBOL drivers/media/dvb/ttpci/ttpci-eeprom 0x8839516f ttpci_eeprom_parse_mac +EXPORT_SYMBOL drivers/media/dvb/ttusb-dec/ttusbdecfe 0x9773ca7a ttusbdecfe_dvbt_attach +EXPORT_SYMBOL drivers/media/dvb/ttusb-dec/ttusbdecfe 0xbcb4cbb0 ttusbdecfe_dvbs_attach +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0x11dc4b6d bttv_gpio_enable +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0x2ac30048 bttv_sub_unregister +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0x8ecf4acc bttv_write_gpio +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0xbcf2d2fb bttv_read_gpio +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0xf0725e89 bttv_get_pcidev +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0xf5d735dc bttv_sub_register +EXPORT_SYMBOL drivers/media/video/btcx-risc 0x495e4b0c btcx_calc_skips +EXPORT_SYMBOL drivers/media/video/btcx-risc 0x91b1cffb btcx_riscmem_alloc +EXPORT_SYMBOL drivers/media/video/btcx-risc 0xad2fe38b btcx_sort_clips +EXPORT_SYMBOL drivers/media/video/btcx-risc 0xc368f8e6 btcx_align +EXPORT_SYMBOL drivers/media/video/btcx-risc 0xcda0ded2 btcx_screen_clips +EXPORT_SYMBOL drivers/media/video/btcx-risc 0xee085e2c btcx_riscmem_free +EXPORT_SYMBOL drivers/media/video/cpia 0x8da9ad62 cpia_register_camera +EXPORT_SYMBOL drivers/media/video/cpia 0x9cc3595c cpia_unregister_camera +EXPORT_SYMBOL drivers/media/video/cx18/cx18 0x2cdea06d cx18_reset_ir_gpio +EXPORT_SYMBOL drivers/media/video/cx2341x 0x0224a947 cx2341x_update +EXPORT_SYMBOL drivers/media/video/cx2341x 0x3559ba71 cx2341x_ext_ctrls +EXPORT_SYMBOL drivers/media/video/cx2341x 0x8fdbede1 cx2341x_fill_defaults +EXPORT_SYMBOL drivers/media/video/cx2341x 0xcf8b77a4 cx2341x_mpeg_ctrls +EXPORT_SYMBOL drivers/media/video/cx2341x 0xde1da524 cx2341x_ctrl_query +EXPORT_SYMBOL drivers/media/video/cx2341x 0xeacc6fab cx2341x_ctrl_get_menu +EXPORT_SYMBOL drivers/media/video/cx2341x 0xfb8bd71f cx2341x_log_status +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0x07228018 cx23885_get_control +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0x1f9d7ab5 cx23885_video_mux +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0x383a0ae1 cx23885_set_freq +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0x8910c45b cx23885_enum_input +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0xbfa08473 cx23885_set_control +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0xe12fa84c cx23885_ctrl_query +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0xfb885537 cx23885_user_ctrls +EXPORT_SYMBOL drivers/media/video/cx88/cx88-vp3054-i2c 0x34dafda5 vp3054_i2c_probe +EXPORT_SYMBOL drivers/media/video/cx88/cx88-vp3054-i2c 0x8270649e vp3054_i2c_remove +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0x56683629 cx88_video_mux +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0x733a2229 cx88_set_control +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0x7b21b296 cx88_set_freq +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0xac4e53b9 cx88_user_ctrls +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0xaea777cd cx88_get_control +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0xd0d8cbc6 cx88_enum_input +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0xd0f368ef cx8800_ctrl_query +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x00385a82 cx8802_unregister_driver +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x0073112d cx8802_buf_prepare +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x440c2508 cx8802_register_driver +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x4872fe68 cx8802_cancel_buffers +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x51009162 cx8802_get_device +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0xa11af5ad cx8802_buf_queue +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0xd76ca09d cx8802_get_driver +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x0c27df63 cx88_set_stereo +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x0e624d12 cx88_free_buffer +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x0f535e62 cx88_risc_databuffer +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x17941b25 cx88_shutdown +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x2b6fc184 cx88_risc_buffer +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x3017d712 cx88_wakeup +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x31982517 cx88_core_get +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x347aecfb cx88_core_put +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x3c645094 cx88_ir_start +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x41752c3e cx88_ir_stop +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x42fa2631 cx88_risc_stopper +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x53b528a1 cx88_call_i2c_clients +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x61b2b94d cx88_get_stereo +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x6311fa2f cx88_set_tvaudio +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x6a02ff01 cx88_core_irq +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x7abbbda3 cx88_reset +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x7b5cdee1 cx88_tuner_callback +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x904b8696 cx88_audio_thread +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x9b140fff cx88_sram_channels +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xa10fdd69 cx88_newstation +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xa6594439 cx88_set_scale +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xb47f6cda cx88_print_irqbits +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xb486f4a5 cx88_set_tvnorm +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xcdc6bab2 cx88_sram_channel_dump +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xe28f254a cx88_sram_channel_setup +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xfb276e82 cx88_vdev_init +EXPORT_SYMBOL drivers/media/video/em28xx/em28xx 0x13933f70 em28xx_unregister_extension +EXPORT_SYMBOL drivers/media/video/em28xx/em28xx 0x2f83d2f4 em28xx_register_extension +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x01939cc3 gspca_disconnect +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x02f6326e gspca_frame_add +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x0c6fedd7 gspca_auto_gain_n_exposure +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x11e8dadf gspca_resume +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x4132d23f gspca_dev_probe +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x9670af2c gspca_debug +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0xfcba1ad4 gspca_suspend +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x0538e449 ivtv_cards_lock +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x14f67530 ivtv_debug +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x1c2aa420 ivtv_vapi +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x3e553df3 ivtv_udma_setup +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x4d164a15 ivtv_udma_unmap +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x5be94161 ivtv_reset_ir_gpio +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x621a0d52 ivtv_cards +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x6b45222a ivtv_udma_prepare +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x70196ffb ivtv_cards_active +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x7f965b6c ivtv_set_irq_mask +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x82f5c83b ivtv_udma_alloc +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0xa558da6d ivtv_vapi_result +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0xc0df6722 ivtv_api +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0xcd15415d ivtv_clear_irq_mask +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0xe92992f0 ivtv_init_on_first_open +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x09f2ee38 saa7134_ts_register +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x1211df5d saa7134_devlist +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x21c1f4ec saa7134_set_dmabits +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x2611c782 saa7134_tvaudio_setmute +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x38ff2deb saa7134_i2c_call_clients +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x3cba7d8f saa7134_pgtable_alloc +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x3e3eeafa saa7134_set_gpio +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x4d614a2f saa7134_dmasound_init +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x7f6328e8 saa_dsp_writel +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x85593767 saa7134_tuner_callback +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x98af79c1 saa7134_boards +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x9b440c46 saa7134_pgtable_free +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0xbb68df84 saa7134_dmasound_exit +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0xc072e34b saa7134_pgtable_build +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0xe0e18d95 saa7134_ts_unregister +EXPORT_SYMBOL drivers/media/video/soc_camera 0x028c2e1a soc_camera_host_unregister +EXPORT_SYMBOL drivers/media/video/soc_camera 0x1453f678 soc_camera_video_stop +EXPORT_SYMBOL drivers/media/video/soc_camera 0x55930e29 soc_camera_video_start +EXPORT_SYMBOL drivers/media/video/soc_camera 0x60b80062 soc_camera_host_register +EXPORT_SYMBOL drivers/media/video/soc_camera 0xd3784769 soc_camera_device_register +EXPORT_SYMBOL drivers/media/video/soc_camera 0xefad99d5 soc_camera_device_unregister +EXPORT_SYMBOL drivers/media/video/tveeprom 0x17c01529 tveeprom_hauppauge_analog +EXPORT_SYMBOL drivers/media/video/tveeprom 0x520a750b tveeprom_read +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x139da847 usbvideo_register +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x16a2915c RingQueue_Dequeue +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x36b07bc5 usbvideo_DeinterlaceFrame +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x407a321c RingQueue_WakeUpInterruptible +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x5bb24860 usbvideo_TestPattern +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x688e8812 usbvideo_AllocateDevice +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0xddecac6d RingQueue_Enqueue +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0xeba59f07 usbvideo_Deregister +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0xef1cf297 usbvideo_RegisterVideoDevice +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0xf5011f67 RingQueue_Flush +EXPORT_SYMBOL drivers/media/video/v4l1-compat 0x6c44a0e6 v4l_compat_translate_ioctl +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x03165a85 v4l2_ctrl_get_menu +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x0dfb5e57 v4l2_prio_max +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x19c8e921 v4l2_i2c_attach +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x1c427ecb v4l2_ctrl_query_fill +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x26b0405b v4l2_chip_ident_i2c_client +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x2de2b633 v4l2_prio_check +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x2e9a955d v4l2_prio_close +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x42c8e001 v4l2_ctrl_next +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x57abfbd8 v4l2_chip_match_host +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x5fef1b4a v4l2_ctrl_query_fill_std +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x942892ab v4l2_prio_open +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xb2d1e17e v4l2_prio_change +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xb3089592 v4l2_chip_match_i2c_client +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xc369097d v4l2_ctrl_check +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xd464e760 v4l2_ctrl_query_menu +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xe330bce9 v4l2_prio_init +EXPORT_SYMBOL drivers/media/video/videobuf-dvb 0x271e3eb4 videobuf_dvb_register +EXPORT_SYMBOL drivers/media/video/videobuf-dvb 0xd8c944ea videobuf_dvb_unregister +EXPORT_SYMBOL drivers/media/video/videocodec 0x1cef83e6 videocodec_detach +EXPORT_SYMBOL drivers/media/video/videocodec 0x1fa1a848 videocodec_unregister +EXPORT_SYMBOL drivers/media/video/videocodec 0x7124aaa6 videocodec_attach +EXPORT_SYMBOL drivers/media/video/videocodec 0xb1088af6 videocodec_register +EXPORT_SYMBOL drivers/media/video/videodev 0x123959a1 v4l2_type_names +EXPORT_SYMBOL drivers/media/video/videodev 0x3adbd595 v4l2_field_names +EXPORT_SYMBOL drivers/media/video/videodev 0x52acb94a video_devdata +EXPORT_SYMBOL drivers/media/video/videodev 0x5ebefe4b v4l_printk_ioctl +EXPORT_SYMBOL drivers/media/video/videodev 0x68f61025 video_exclusive_open +EXPORT_SYMBOL drivers/media/video/videodev 0x9024b01b video_device_alloc +EXPORT_SYMBOL drivers/media/video/videodev 0x9437b34e video_unregister_device +EXPORT_SYMBOL drivers/media/video/videodev 0x9caf47ea video_usercopy +EXPORT_SYMBOL drivers/media/video/videodev 0xa6b7b2e4 video_exclusive_release +EXPORT_SYMBOL drivers/media/video/videodev 0xab644d95 video_device_release +EXPORT_SYMBOL drivers/media/video/videodev 0xd4dd549b video_register_device_index +EXPORT_SYMBOL drivers/media/video/videodev 0xe2b92059 v4l2_video_std_construct +EXPORT_SYMBOL drivers/media/video/videodev 0xf1604981 video_ioctl2 +EXPORT_SYMBOL drivers/media/video/videodev 0xf3251e7b v4l2_norm_to_name +EXPORT_SYMBOL drivers/media/video/videodev 0xffcc7636 video_register_device +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x027a83aa mpt_get_msg_frame +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x0cc3f95d mpt_config +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x105d4f47 mpt_add_sge +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x11a3872a mpt_HardResetHandler +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x3acf18a1 mpt_GetIocState +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x3b0fd5b9 mpt_print_ioc_summary +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x44bc642c mpt_put_msg_frame +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x4526289b mpt_event_deregister +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x4791682d mpt_put_msg_frame_hi_pri +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x7096a170 mpt_resume +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x70b8f845 mpt_send_handshake_request +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x7aa442a4 mpt_free_msg_frame +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x80051f59 mpt_verify_adapter +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x9584940b mpt_alloc_fw_memory +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xb5cefc99 mpt_findImVolumes +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xb835d6ea mpt_event_register +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xba74b069 mpt_device_driver_register +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xc0e69f82 mpt_device_driver_deregister +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xc2fa3490 mptbase_sas_persist_operation +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xc47c22e8 mpt_deregister +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xd2714b19 mpt_free_fw_memory +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xd497351b mpt_reset_register +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xd9a92a75 mpt_reset_deregister +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xdd805159 ioc_list +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xe1b02806 mpt_attach +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xe5e23766 mpt_suspend +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xe5f15319 mpt_register +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xeb1193fc mpt_raid_phys_disk_pg0 +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xf53283d2 mpt_detach +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x02e01774 mptscsih_scandv_complete +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x09b23d2d mptscsih_bios_param +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x145997d4 mptscsih_slave_destroy +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x1786badd mptscsih_io_done +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x2476a998 mptscsih_raid_id_to_num +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x36fa3412 mptscsih_dev_reset +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x410ed0b5 mptscsih_host_attrs +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x50252c41 mptscsih_host_reset +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x51eb3579 mptscsih_shutdown +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x53394b02 mptscsih_change_queue_depth +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x5a0b8d02 mptscsih_ioc_reset +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x764ddf1a mptscsih_timer_expired +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x84a16028 mptscsih_TMHandler +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x959baf25 mptscsih_info +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x9e936429 mptscsih_taskmgmt_complete +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xa57fd7d2 mptscsih_is_phys_disk +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xac8e2232 mptscsih_abort +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xb0e3929c mptscsih_qcmd +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xcde48782 mptscsih_slave_configure +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xd04ecb38 mptscsih_suspend +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xd0672251 mptscsih_event_process +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xdeb5fed4 mptscsih_remove +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xeb86b652 mptscsih_bus_reset +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xf9843e7f mptscsih_resume +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xfe902918 mptscsih_proc_info +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x06ce7844 i2o_msg_get_wait +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x0db26b8f i2o_driver_notify_device_remove_all +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x1aba1919 i2o_parm_field_get +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x23520576 i2o_parm_table_get +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x260a3d8f i2o_parm_issue +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x2a843bef i2o_dump_message +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x34916206 i2o_status_get +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x35a0a446 i2o_msg_post_wait_mem +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x3ad6d0cf i2o_driver_register +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x3e589e94 i2o_driver_unregister +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x40800879 i2o_iop_find_device +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x42987e0b i2o_driver_notify_controller_remove_all +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x484a717b i2o_cntxt_list_get_ptr +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x69d4cc55 i2o_device_claim +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xa9e72e5a i2o_cntxt_list_remove +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xad3452b3 i2o_cntxt_list_get +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xb4c00dcf i2o_controllers +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xb6043517 i2o_cntxt_list_add +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xb9fd230c i2o_find_iop +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xd4e1dd5d i2o_event_register +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xd6228d6e i2o_device_claim_release +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xe172b1ab i2o_driver_notify_device_add_all +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xf2643a49 i2o_exec_lct_get +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xf37fcea1 i2o_driver_notify_controller_add_all +EXPORT_SYMBOL drivers/mfd/htc-pasic3 0x255ff146 pasic3_write_register +EXPORT_SYMBOL drivers/mfd/htc-pasic3 0xee8dd864 pasic3_read_register +EXPORT_SYMBOL drivers/misc/ioc4 0x19d81ffd ioc4_register_submodule +EXPORT_SYMBOL drivers/misc/ioc4 0x4220d7c2 ioc4_unregister_submodule +EXPORT_SYMBOL drivers/misc/sony-laptop 0x5bb1e117 sony_pic_camera_command +EXPORT_SYMBOL drivers/misc/tifm_core 0x2d81c904 tifm_alloc_adapter +EXPORT_SYMBOL drivers/misc/tifm_core 0x38c39bad tifm_has_ms_pif +EXPORT_SYMBOL drivers/misc/tifm_core 0x3f09c79c tifm_alloc_device +EXPORT_SYMBOL drivers/misc/tifm_core 0x488bc82f tifm_unmap_sg +EXPORT_SYMBOL drivers/misc/tifm_core 0x6f0cdd25 tifm_eject +EXPORT_SYMBOL drivers/misc/tifm_core 0x8934dd37 tifm_remove_adapter +EXPORT_SYMBOL drivers/misc/tifm_core 0xa8c2ec46 tifm_queue_work +EXPORT_SYMBOL drivers/misc/tifm_core 0xb843f8e8 tifm_register_driver +EXPORT_SYMBOL drivers/misc/tifm_core 0xca563e37 tifm_free_device +EXPORT_SYMBOL drivers/misc/tifm_core 0xd12204a5 tifm_add_adapter +EXPORT_SYMBOL drivers/misc/tifm_core 0xd8fac6eb tifm_free_adapter +EXPORT_SYMBOL drivers/misc/tifm_core 0xdbdc7ff2 tifm_map_sg +EXPORT_SYMBOL drivers/misc/tifm_core 0xde47cc2b tifm_unregister_driver +EXPORT_SYMBOL drivers/mmc/card/mmc_block 0x814b2fdb mmc_cleanup_queue +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x1e0dc572 mmc_release_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x24ae9297 mmc_unregister_driver +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x24c0bdc2 mmc_register_driver +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x32ec7416 mmc_add_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x3fec2088 mmc_detect_change +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x411caf65 __mmc_claim_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x43149b02 mmc_free_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x45a3e863 mmc_align_data_size +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x694b74c2 mmc_request_done +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x8b42fd95 mmc_alloc_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x9f786f06 mmc_wait_for_app_cmd +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xa216a59d mmc_resume_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xa84613ff mmc_set_data_timeout +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xabb4a513 mmc_remove_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xb0e161e0 mmc_wait_for_cmd +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xd8ff3d3c mmc_suspend_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xeb548bd6 mmc_wait_for_req +EXPORT_SYMBOL drivers/mtd/chips/cfi_util 0x1e4b389b cfi_varsize_frob +EXPORT_SYMBOL drivers/mtd/chips/cfi_util 0x3c1e14f3 cfi_fixup +EXPORT_SYMBOL drivers/mtd/chips/cfi_util 0xfc973538 cfi_read_pri +EXPORT_SYMBOL drivers/mtd/chips/chipreg 0x6d01b9fa map_destroy +EXPORT_SYMBOL drivers/mtd/chips/chipreg 0xb34366f0 do_map_probe +EXPORT_SYMBOL drivers/mtd/chips/chipreg 0xc9da98fe unregister_mtd_chip_driver +EXPORT_SYMBOL drivers/mtd/chips/chipreg 0xea12a65f register_mtd_chip_driver +EXPORT_SYMBOL drivers/mtd/chips/gen_probe 0x9b953f85 mtd_do_chip_probe +EXPORT_SYMBOL drivers/mtd/maps/map_funcs 0xf493222a simple_map_init +EXPORT_SYMBOL drivers/mtd/mtd 0xc5ea1aa7 add_mtd_partitions +EXPORT_SYMBOL drivers/mtd/mtd 0xf3edb1e3 del_mtd_partitions +EXPORT_SYMBOL drivers/mtd/mtdconcat 0x0f08418a mtd_concat_create +EXPORT_SYMBOL drivers/mtd/mtdconcat 0x3b32f920 mtd_concat_destroy +EXPORT_SYMBOL drivers/mtd/nand/nand 0x4a05f8be nand_scan_bbt +EXPORT_SYMBOL drivers/mtd/nand/nand 0xc3af03b0 nand_default_bbt +EXPORT_SYMBOL drivers/mtd/nand/nand_ecc 0x254f230c nand_calculate_ecc +EXPORT_SYMBOL drivers/mtd/nand/nand_ecc 0x87406d9d nand_correct_data +EXPORT_SYMBOL drivers/mtd/nand/nand_ids 0x836bdb72 nand_flash_ids +EXPORT_SYMBOL drivers/mtd/nand/nand_ids 0xa336feb7 nand_manuf_ids +EXPORT_SYMBOL drivers/mtd/onenand/onenand 0x9926269f onenand_default_bbt +EXPORT_SYMBOL drivers/mtd/onenand/onenand 0xda3a6e1b onenand_scan_bbt +EXPORT_SYMBOL drivers/net/8390 0x7d7e0dbc ei_interrupt +EXPORT_SYMBOL drivers/net/8390 0xc3a6fa20 __alloc_ei_netdev +EXPORT_SYMBOL drivers/net/8390 0xd06a7ab1 ei_close +EXPORT_SYMBOL drivers/net/8390 0xd9a4667c ei_open +EXPORT_SYMBOL drivers/net/8390 0xe239585a NS8390_init +EXPORT_SYMBOL drivers/net/8390 0xe37e150f ei_poll +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x4641bd7d arcnet_interrupt +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x65061363 arc_proto_default +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x6534792a arcnet_debug +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x743c7bd7 arc_proto_map +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x8a116e64 alloc_arcdev +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x9d7a8702 arc_raw_proto +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0xa6d63a8b arcnet_unregister_proto +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0xff6ced25 arc_bcast_proto +EXPORT_SYMBOL drivers/net/arcnet/com20020 0x26ceae0b com20020_check +EXPORT_SYMBOL drivers/net/arcnet/com20020 0xaf23de7e com20020_found +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x297f9ece cxgb3_alloc_stid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x4d1fdce6 t3_l2t_send_event +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x4fd25c1e cxgb3_unregister_client +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x51369cfc cxgb3_free_stid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x573ecd15 cxgb3_insert_tid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x6df7f87b cxgb3_ofld_send +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x6f553fe9 cxgb3_remove_tid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x708a0bbd t3_l2t_send_slow +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x7752dceb cxgb3_alloc_atid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x7817be94 cxgb3_queue_tid_release +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x81011c39 cxgb3_register_client +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x91bba536 t3_register_cpl_handler +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x927cadda dev2t3cdev +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0xc4915e11 t3_l2e_free +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0xc5fed689 cxgb3_free_atid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0xc6e11690 t3_l2t_get +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0x05dc63af hdlcdrv_receiver +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0x4d6ed53a hdlcdrv_transmitter +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0x50374b81 hdlcdrv_arbitrate +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0x5a2bb698 hdlcdrv_register +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0xeec0d55a hdlcdrv_unregister +EXPORT_SYMBOL drivers/net/irda/sir-dev 0x0558ba06 sirdev_set_dtr_rts +EXPORT_SYMBOL drivers/net/irda/sir-dev 0x064e1bb9 sirdev_get_instance +EXPORT_SYMBOL drivers/net/irda/sir-dev 0x80c44fec sirdev_raw_read +EXPORT_SYMBOL drivers/net/irda/sir-dev 0x99d49b52 sirdev_put_instance +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xcc56a3c6 sirdev_receive +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xd18a5827 irda_register_dongle +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xd4e74ae9 sirdev_raw_write +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xee8e9615 irda_unregister_dongle +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xf13669c3 sirdev_write_complete +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xf36e8d94 sirdev_set_dongle +EXPORT_SYMBOL drivers/net/mii 0x0f84ae31 mii_check_media +EXPORT_SYMBOL drivers/net/mii 0x41aa0dd9 mii_check_gmii_support +EXPORT_SYMBOL drivers/net/mii 0x7fda68bc generic_mii_ioctl +EXPORT_SYMBOL drivers/net/mii 0x856549cc mii_nway_restart +EXPORT_SYMBOL drivers/net/mii 0x9a94c089 mii_ethtool_gset +EXPORT_SYMBOL drivers/net/mii 0x9cd83215 mii_link_ok +EXPORT_SYMBOL drivers/net/mii 0xa6932822 mii_ethtool_sset +EXPORT_SYMBOL drivers/net/mii 0xcf15ed7f mii_check_link +EXPORT_SYMBOL drivers/net/phy/libphy 0x03b40f02 genphy_config_advert +EXPORT_SYMBOL drivers/net/phy/libphy 0x06f0db8e phy_read +EXPORT_SYMBOL drivers/net/phy/libphy 0x0d918fa3 genphy_config_aneg +EXPORT_SYMBOL drivers/net/phy/libphy 0x2ca8686e phy_print_status +EXPORT_SYMBOL drivers/net/phy/libphy 0x2e44dbc5 mdio_bus_type +EXPORT_SYMBOL drivers/net/phy/libphy 0x30015658 phy_start_interrupts +EXPORT_SYMBOL drivers/net/phy/libphy 0x35e0a8f2 phy_disconnect +EXPORT_SYMBOL drivers/net/phy/libphy 0x3e60c5f2 phy_scan_fixups +EXPORT_SYMBOL drivers/net/phy/libphy 0x5a98e0d3 phy_start +EXPORT_SYMBOL drivers/net/phy/libphy 0x5bd3ff73 phy_driver_unregister +EXPORT_SYMBOL drivers/net/phy/libphy 0x6d1b9f9a phy_ethtool_gset +EXPORT_SYMBOL drivers/net/phy/libphy 0x6f5953b6 phy_mii_ioctl +EXPORT_SYMBOL drivers/net/phy/libphy 0x7228436e phy_write +EXPORT_SYMBOL drivers/net/phy/libphy 0x7f02404b phy_stop +EXPORT_SYMBOL drivers/net/phy/libphy 0x87d97ea9 get_phy_id +EXPORT_SYMBOL drivers/net/phy/libphy 0x8d40cde0 mdiobus_unregister +EXPORT_SYMBOL drivers/net/phy/libphy 0x91c6086c phy_register_fixup +EXPORT_SYMBOL drivers/net/phy/libphy 0x97ddeef4 phy_device_create +EXPORT_SYMBOL drivers/net/phy/libphy 0x99c4f86c phy_attach +EXPORT_SYMBOL drivers/net/phy/libphy 0x9d36b938 mdiobus_register +EXPORT_SYMBOL drivers/net/phy/libphy 0xacdb2209 phy_stop_interrupts +EXPORT_SYMBOL drivers/net/phy/libphy 0xad74007c genphy_read_status +EXPORT_SYMBOL drivers/net/phy/libphy 0xb054b2b8 phy_connect +EXPORT_SYMBOL drivers/net/phy/libphy 0xb0f61aa4 phy_register_fixup_for_id +EXPORT_SYMBOL drivers/net/phy/libphy 0xb1d970ec phy_disable_interrupts +EXPORT_SYMBOL drivers/net/phy/libphy 0xba236fc2 phy_detach +EXPORT_SYMBOL drivers/net/phy/libphy 0xc748dadc phy_driver_register +EXPORT_SYMBOL drivers/net/phy/libphy 0xd3a042fb phy_start_aneg +EXPORT_SYMBOL drivers/net/phy/libphy 0xe4d1e473 genphy_update_link +EXPORT_SYMBOL drivers/net/phy/libphy 0xe99e73c7 phy_enable_interrupts +EXPORT_SYMBOL drivers/net/phy/libphy 0xf219d4b2 phy_ethtool_sset +EXPORT_SYMBOL drivers/net/phy/libphy 0xf339b4ae phy_register_fixup_for_uid +EXPORT_SYMBOL drivers/net/phy/libphy 0xfa1e9067 phy_sanitize_settings +EXPORT_SYMBOL drivers/net/phy/mdio-bitbang 0x024be098 free_mdio_bitbang +EXPORT_SYMBOL drivers/net/phy/mdio-bitbang 0xcd11f89d alloc_mdio_bitbang +EXPORT_SYMBOL drivers/net/ppp_generic 0x01101d5d ppp_output_wakeup +EXPORT_SYMBOL drivers/net/ppp_generic 0x043c0ee8 ppp_channel_index +EXPORT_SYMBOL drivers/net/ppp_generic 0x2b9d9dcc ppp_unregister_channel +EXPORT_SYMBOL drivers/net/ppp_generic 0x4aaba9a9 ppp_register_channel +EXPORT_SYMBOL drivers/net/ppp_generic 0x4ecd6cf9 ppp_unregister_compressor +EXPORT_SYMBOL drivers/net/ppp_generic 0xa5dba8be ppp_input +EXPORT_SYMBOL drivers/net/ppp_generic 0xebf42592 ppp_register_compressor +EXPORT_SYMBOL drivers/net/ppp_generic 0xf04df8b6 ppp_unit_number +EXPORT_SYMBOL drivers/net/ppp_generic 0xf486df6b ppp_input_error +EXPORT_SYMBOL drivers/net/pppox 0x389c00b7 pppox_ioctl +EXPORT_SYMBOL drivers/net/pppox 0x601719ab pppox_unbind_sock +EXPORT_SYMBOL drivers/net/pppox 0x9d0fc5ce register_pppox_proto +EXPORT_SYMBOL drivers/net/pppox 0xe0ff7a18 unregister_pppox_proto +EXPORT_SYMBOL drivers/net/slhc 0x0ff2b602 slhc_compress +EXPORT_SYMBOL drivers/net/slhc 0x23c8f257 slhc_uncompress +EXPORT_SYMBOL drivers/net/slhc 0xa63d85ab slhc_remember +EXPORT_SYMBOL drivers/net/slhc 0xb5ca1c46 slhc_free +EXPORT_SYMBOL drivers/net/slhc 0xdfc5169b slhc_init +EXPORT_SYMBOL drivers/net/slhc 0xe8794ce1 slhc_toss +EXPORT_SYMBOL drivers/net/sungem_phy 0x6e1bda5a mii_phy_probe +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0x152a875a tms380tr_close +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0x518fcbfb tms380tr_interrupt +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0x96f51ab6 tmsdev_term +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0x98d743a8 tmsdev_init +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0xa27a5738 tms380tr_open +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0xd2328794 tms380tr_wait +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0x38da4725 cycx_intr +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0x62be23ea cycx_setup +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0x66a4c4e6 cycx_down +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0x968458a6 cycx_peek +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0xb6f383de cycx_poke +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0xfe7cd576 cycx_exec +EXPORT_SYMBOL drivers/net/wan/hdlc 0x7704ce78 unregister_hdlc_protocol +EXPORT_SYMBOL drivers/net/wan/hdlc 0x89131c79 unregister_hdlc_device +EXPORT_SYMBOL drivers/net/wan/hdlc 0x89a18b71 attach_hdlc_protocol +EXPORT_SYMBOL drivers/net/wan/hdlc 0x91303d3b detach_hdlc_protocol +EXPORT_SYMBOL drivers/net/wan/hdlc 0x9e8bc109 hdlc_open +EXPORT_SYMBOL drivers/net/wan/hdlc 0xeb4e70e2 hdlc_close +EXPORT_SYMBOL drivers/net/wan/hdlc 0xef57f97a hdlc_ioctl +EXPORT_SYMBOL drivers/net/wan/hdlc 0xf2d1f6f5 register_hdlc_protocol +EXPORT_SYMBOL drivers/net/wan/hdlc 0xf31f1c04 alloc_hdlcdev +EXPORT_SYMBOL drivers/net/wan/syncppp 0x1b0272eb sppp_do_ioctl +EXPORT_SYMBOL drivers/net/wan/syncppp 0x5d5888de sppp_close +EXPORT_SYMBOL drivers/net/wan/syncppp 0x6243989f sppp_open +EXPORT_SYMBOL drivers/net/wan/syncppp 0x9abf5a92 sppp_attach +EXPORT_SYMBOL drivers/net/wan/syncppp 0x9b560dfa sppp_reopen +EXPORT_SYMBOL drivers/net/wan/syncppp 0xdcc0f81d sppp_detach +EXPORT_SYMBOL drivers/net/wireless/airo 0x04700d7a init_airo_card +EXPORT_SYMBOL drivers/net/wireless/airo 0x1bc3262e stop_airo_card +EXPORT_SYMBOL drivers/net/wireless/airo 0xfea86502 reset_airo_card +EXPORT_SYMBOL drivers/net/wireless/atmel 0x0f8d94a7 stop_atmel_card +EXPORT_SYMBOL drivers/net/wireless/atmel 0x4f8a67c4 init_atmel_card +EXPORT_SYMBOL drivers/net/wireless/atmel 0xf06866b1 atmel_open +EXPORT_SYMBOL drivers/net/wireless/hermes 0x4196c38b hermes_write_ltv +EXPORT_SYMBOL drivers/net/wireless/hermes 0xc60b5e9e hermes_bap_pwrite +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd38d8ae2 hermes_read_ltv +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd3f714e5 hermes_bap_pread +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd5168829 hermes_allocate +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd5336e5d hermes_init +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd54e219d hermes_docmd_wait +EXPORT_SYMBOL drivers/net/wireless/hermes 0xed47b224 hermes_struct_init +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x02c2d997 hostap_set_roaming +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x0398e31b hostap_set_word +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x0a5ad871 hostap_remove_interface +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x0ae80fe0 hostap_set_auth_algs +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x1723ac32 hostap_set_multicast_list_queue +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x2a0837e4 hostap_init_proc +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x2da03a92 hostap_setup_dev +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x32f9ca5d hostap_init_data +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x3c60f43f hostap_set_hostapd +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x48d4206c hostap_handle_sta_tx_exc +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x491f910f hostap_master_start_xmit +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x5829c70b hostap_set_hostapd_sta +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x5adf5cd2 hostap_info_process +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x5eb7d661 hostap_get_porttype +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x6903f16c hostap_80211_get_hdrlen +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x6e04b8c4 hostap_80211_rx +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x9dbda1dd prism2_update_comms_qual +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xa12ad27f hostap_dump_tx_header +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xa27a989c hostap_info_init +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xac189748 hostap_check_sta_fw_version +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xb28d410e hostap_init_ap_proc +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xb2a945e0 hostap_dump_rx_header +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xb3b8fb9d hostap_remove_proc +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xb8ce1b39 hostap_free_data +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xde130f81 hostap_set_string +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xdef1227e hostap_get_stats +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xe11d9e24 hostap_set_encryption +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xe8592b4d hostap_add_interface +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xea634d62 hostap_set_antsel +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xf848824d hostap_80211_ops +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x054256cc iwl_chain_noise_calibration +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x078a6690 iwl_rx_queue_free +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x07cf64d6 iwl_power_set_user_mode +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x080b648e iwl_rx_reply_rx_phy +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x080eb507 iwl_send_cmd_sync +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x09a281f5 iwl_scan_cancel_timeout +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x0dc11698 iwl_print_event_log +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x105ffd1d iwl_rx_agg_start +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x12cf6e94 iwl_reset_qos +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x1356104b iwl_send_cmd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x15c46a0d iwl_hw_txq_free_tfd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x172acabe iwl_is_fat_tx_allowed +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x18dffce1 iwl_setup_power_deferred_work +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x1d77b399 iwl_bcast_addr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x20c35748 iwl_uninit_drv +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x216b7756 iwl_set_rxon_chain +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x22f13ab0 iwl_eeprom_free +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x23126b64 iwl_eeprom_check_version +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x24b999dc iwl_rf_kill_ct_config +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x2890cf04 iwl_set_rxon_ht +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x2d8e7b6c iwl_power_temperature_change +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x2f6e3ac9 iwl_power_update_mode +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x305abe92 iwl_sta_modify_enable_tid_tx +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x30763c16 iwl_get_channel_info +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x3491f138 iwl_rxq_stop +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x34d5da87 iwl_eeprom_query16 +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x357aaa53 iwl_hw_txq_ctx_free +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x3a06b2e2 iwl_send_statistics_request +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x3d06ab92 iwl_set_tx_power +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x3f93769f iwl_leds_unregister +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x4836bf10 iwl_hw_nic_init +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x4e4537ae iwl_remove_station +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x50aa01a2 iwl_send_cmd_pdu_async +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x53055abc iwl_hw_detect +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x538b0cc3 iwl_rx_statistics +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x560734f4 iwl_set_rxon_channel +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x56f396a7 iwl_sensitivity_calibration +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x56f49efe iwl_rfkill_set_hw_state +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5ab275ad iwl_rx_reply_rx +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5c550d8d iwl_remove_default_wep_key +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5dd22120 iwl_power_set_system_mode +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5e5fdbba iwl_eeprom_query_addr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5fa1f21b iwlcore_eeprom_verify_signature +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5fa83880 iwl_leds_register +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x60774702 iwl_queue_space +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x61f83672 iwl_init_sensitivity +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x6320468a iwl_init_drv +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x658728c6 iwl_rx_queue_restock +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x6633a7d7 iwl_rx_queue_space +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x664c6248 iwl_reset_run_time_calib +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x6ad86663 iwl_rx_replenish +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x6cc05b65 iwl_find_station +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x7280863a iwl_tx_agg_start +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x73a0ac6e iwl_rxon_add_station +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x7b24806d iwl_hwrate_to_tx_control +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x7cef5b11 iwl_rx_queue_update_write_ptr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x7e42ac53 iwl_eeprom_get_mac +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x813be53c iwl_tx_queue_reclaim +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x8490b3a4 iwl_power_enable_management +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x84a23ce0 iwl_txq_update_write_ptr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x84c1fc33 iwlcore_eeprom_acquire_semaphore +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x8670273d iwl_hwrate_to_plcp_idx +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x876f3fd5 iwl_dump_nic_event_log +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x8b2e9a42 iwl_radio_kill_sw_enable_radio +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x8c16de26 iwl_scan_initiate +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x90d1eeee iwl_setup_rx_scan_handlers +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x925b1af3 iwl_tx_skb +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x9a2287d0 iwl_rx_queue_alloc +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x9faced57 iwl_calib_set +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xa0b1f130 iwl_init_channel_map +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xa7c931f9 iwl_rx_queue_reset +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xaa4c460a iwl_setup_mac +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xaac2e0db iwl_set_hw_params +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xaaff1e20 iwl_rfkill_unregister +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xabe3bb3b iwl_set_default_wep_key +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xad0c715b iwl_txq_ctx_stop +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xb22a9e29 iwl_get_ra_sta_id +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xb323dcc2 iwl_rx_missed_beacon_notif +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xb38a1e41 iwl_escape_essid +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xb38d1862 iwl_send_static_wepkey_cmd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xbf08b234 iwl_scan_cancel +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc111e519 iwlcore_eeprom_query_addr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc203a39d iwl_verify_ucode +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc5d40627 iwl_send_calib_results +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc6b294d1 iwl_power_cancel_timeout +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc6d4eb0d iwl_send_lq_cmd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xcb2893ac iwl_get_sta_id +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xcbaf4931 get_cmd_string +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xce54c3a0 iwl_clear_stations_table +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xcf4c4595 iwl_rx_reply_compressed_ba +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xd654d618 iwl_set_dynamic_key +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xd71c95ed iwl_dump_nic_error_log +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xdd7cc04d iwl_tx_cmd_complete +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xddb29814 iwl_leds_background +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xdf5a4c21 iwl_send_add_sta +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xe06e6128 iwl_txq_check_empty +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xe65087ea iwl_hw_txq_attach_buf_to_tfd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xe7ce5d70 iwl_rates +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xe8595fbf iwl_add_station_flags +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xea86b8ac iwl_power_initialize +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xeb6e8747 iwl_setup_scan_deferred_work +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xedb282fd iwl_radio_kill_sw_disable_radio +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xedd89224 iwl_send_cmd_pdu +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xee989d41 iwl_alloc_all +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf07aa0b9 iwlcore_eeprom_release_semaphore +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf2239bbe iwl_rx_agg_stop +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf30e213e iwl_eeprom_init +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf47e0b44 iwl_rfkill_init +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf4a17617 iwl_remove_dynamic_key +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xfbc24d00 iwl_power_disable_management +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xfed273e2 iwl_tx_agg_stop +EXPORT_SYMBOL drivers/net/wireless/orinoco 0x0787d441 free_orinocodev +EXPORT_SYMBOL drivers/net/wireless/orinoco 0x1a9d334a orinoco_interrupt +EXPORT_SYMBOL drivers/net/wireless/orinoco 0x76d454ca orinoco_reinit_firmware +EXPORT_SYMBOL drivers/net/wireless/orinoco 0x9281a14f alloc_orinocodev +EXPORT_SYMBOL drivers/net/wireless/orinoco 0xbe05f995 __orinoco_down +EXPORT_SYMBOL drivers/net/wireless/orinoco 0xf6df7e42 __orinoco_up +EXPORT_SYMBOL drivers/parport/parport 0x120325d3 parport_ieee1284_ecp_write_addr +EXPORT_SYMBOL drivers/parport/parport 0x14dc98d8 parport_negotiate +EXPORT_SYMBOL drivers/parport/parport 0x1a41dc31 parport_ieee1284_epp_write_data +EXPORT_SYMBOL drivers/parport/parport 0x1dbe8d84 parport_irq_handler +EXPORT_SYMBOL drivers/parport/parport 0x372ca585 parport_ieee1284_ecp_write_data +EXPORT_SYMBOL drivers/parport/parport 0x3b22c97f parport_ieee1284_epp_read_addr +EXPORT_SYMBOL drivers/parport/parport 0x3f6e5c67 parport_ieee1284_epp_write_addr +EXPORT_SYMBOL drivers/parport/parport 0x415dfd7d parport_unregister_device +EXPORT_SYMBOL drivers/parport/parport 0x480c778b parport_wait_peripheral +EXPORT_SYMBOL drivers/parport/parport 0x4d2a941b parport_ieee1284_interrupt +EXPORT_SYMBOL drivers/parport/parport 0x4f23d05f parport_claim +EXPORT_SYMBOL drivers/parport/parport 0x5649a7bf parport_set_timeout +EXPORT_SYMBOL drivers/parport/parport 0x5b6ccbee parport_ieee1284_read_nibble +EXPORT_SYMBOL drivers/parport/parport 0x5d2bd076 parport_ieee1284_write_compat +EXPORT_SYMBOL drivers/parport/parport 0x632c8aae parport_put_port +EXPORT_SYMBOL drivers/parport/parport 0x65f2cfa1 parport_wait_event +EXPORT_SYMBOL drivers/parport/parport 0x7652756e parport_register_port +EXPORT_SYMBOL drivers/parport/parport 0x7f1864a3 parport_ieee1284_read_byte +EXPORT_SYMBOL drivers/parport/parport 0x89fb4c12 parport_unregister_driver +EXPORT_SYMBOL drivers/parport/parport 0x9d8a6642 parport_claim_or_block +EXPORT_SYMBOL drivers/parport/parport 0x9e8eecee parport_find_base +EXPORT_SYMBOL drivers/parport/parport 0xa1a86b8c parport_write +EXPORT_SYMBOL drivers/parport/parport 0xa5f7cad0 parport_find_number +EXPORT_SYMBOL drivers/parport/parport 0xb28a268a parport_remove_port +EXPORT_SYMBOL drivers/parport/parport 0xbdf757f5 parport_ieee1284_epp_read_data +EXPORT_SYMBOL drivers/parport/parport 0xcb967a71 parport_ieee1284_ecp_read_data +EXPORT_SYMBOL drivers/parport/parport 0xd003567a parport_get_port +EXPORT_SYMBOL drivers/parport/parport 0xd745d233 parport_announce_port +EXPORT_SYMBOL drivers/parport/parport 0xd9670cd7 parport_register_device +EXPORT_SYMBOL drivers/parport/parport 0xeb651244 parport_release +EXPORT_SYMBOL drivers/parport/parport 0xf1a3e988 parport_read +EXPORT_SYMBOL drivers/parport/parport 0xf2b81bec parport_register_driver +EXPORT_SYMBOL drivers/parport/parport_pc 0x3bfdce12 parport_pc_unregister_port +EXPORT_SYMBOL drivers/parport/parport_pc 0xeacccf75 parport_pc_probe_port +EXPORT_SYMBOL drivers/pci/hotplug/pci_hotplug 0x1a9cf8d3 acpi_get_hp_hw_control_from_firmware +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x08d3ce0f pcmcia_register_driver +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x2ed8dbd8 pcmcia_request_io +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x4cc7d3ea pcmcia_unregister_driver +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x651f96f8 cs_error +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x6e504775 pcmcia_release_window +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x73cd6557 pcmcia_map_mem_page +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x77bdb8ae pcmcia_get_window +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x8374b4fc pcmcia_dev_present +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x8822c514 pcmcia_request_window +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x8da9bd97 pcmcia_request_configuration +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x9a2c8397 pcmcia_access_configuration_register +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xb169ce88 pcmcia_get_configuration_info +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xc91f8c19 pcmcia_get_mem_page +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xca9f69da pcmcia_modify_configuration +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xe1a09dc7 pcmcia_request_irq +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xffab5460 pcmcia_disable_device +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x05d1a894 pcmcia_find_mem_region +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x0e0189b6 pcmcia_find_io_region +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x212db8d2 pcmcia_socket_list +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x2549a38a pccard_validate_cis +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x42a6c43c pcmcia_replace_cis +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x4693608e pccard_get_next_tuple +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x47257b71 pcmcia_eject_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x4d55843c pccard_register_pcmcia +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x520035ab pcmcia_parse_events +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x5cfae6a7 pccard_reset_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x6c77d140 pcmcia_put_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x6d43fcca pcmcia_validate_mem +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x6d6949fd pcmcia_insert_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x70875132 release_cis_mem +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x727709e6 destroy_cis_cache +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x7d7d304c pcmcia_socket_dev_suspend +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x881a01a9 pccard_read_tuple +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x8981d9f7 pcmcia_write_cis_mem +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x8ce00554 pcmcia_get_socket_by_nr +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x9cc48af1 pcmcia_resume_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xa44f2739 pcmcia_register_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xa4609834 pcmcia_socket_dev_resume +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xa8df65b6 pcmcia_socket_list_rwsem +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xab1e5679 pccard_get_tuple_data +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xad6d1e6b pcmcia_adjust_io_region +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xb25dc28d pcmcia_socket_class +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xb3c5c547 pcmcia_get_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xc57f13b5 pccard_static_ops +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xcd2ac1c1 pccard_parse_tuple +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xcf97f3bd dead_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xd151ade6 pccard_get_first_tuple +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xe05b3adc pcmcia_unregister_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xe3452b77 pcmcia_suspend_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xf62066dd pcmcia_read_cis_mem +EXPORT_SYMBOL drivers/pcmcia/rsrc_nonstatic 0x564be6bd pccard_nonstatic_ops +EXPORT_SYMBOL drivers/scsi/megaraid/megaraid_mm 0x2250c66e mraid_mm_adapter_app_handle +EXPORT_SYMBOL drivers/scsi/megaraid/megaraid_mm 0x30793671 mraid_mm_register_adp +EXPORT_SYMBOL drivers/scsi/megaraid/megaraid_mm 0x512c956d mraid_mm_unregister_adp +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x16d4591c qlogicfas408_disable_ints +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x243c7b23 qlogicfas408_info +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x3fd8cd71 qlogicfas408_detect +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x48cacc97 qlogicfas408_biosparam +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x5cb878c3 qlogicfas408_queuecommand +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x5cd179e6 qlogicfas408_ihandl +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x5e6cbb9a qlogicfas408_abort +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x65d8fd4b qlogicfas408_bus_reset +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0xe76b3b20 qlogicfas408_get_chip_type +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0xf2b95199 qlogicfas408_setup +EXPORT_SYMBOL drivers/scsi/raid_class 0x14030efe raid_component_add +EXPORT_SYMBOL drivers/scsi/raid_class 0x5d335f6d raid_class_release +EXPORT_SYMBOL drivers/scsi/raid_class 0xbf70c053 raid_class_attach +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x0138e14b scsi_register_driver +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x0382d5db scsi_reset_provider +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x0c65e73c scsi_normalize_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x0c8c9e99 scsi_show_extd_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x11267875 scsi_extd_sense_format +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1b9e0ff1 scsilun_to_int +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1c8c4bbb starget_for_each_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1e1789ab __scsi_add_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1f985ff8 scsi_host_lookup +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1fdec236 scsi_device_lookup +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x21bb54e9 scsi_mode_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x21bb9c44 scsi_prep_state_check +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x21eee89e scsi_host_put +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x22d618e2 scsi_get_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x26ba707b scsi_scan_host +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x28a2ed02 scsi_build_sense_buffer +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x290762dc scsi_adjust_queue_depth +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2951e317 scsi_scan_target +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2b0ba2b0 scsi_sense_desc_find +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2c109390 scsi_set_medium_removal +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2d89342a scsi_show_sense_hdr +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2e7c625e scsi_calculate_bounce_limit +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2f46fb43 scsi_eh_restore_cmnd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x33236019 scsi_allocate_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x337cd433 scsi_report_bus_reset +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x34a67a43 scsi_target_quiesce +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x355ba822 scsi_command_normalize_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x36a9784f scsi_eh_finish_cmd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x396de25f scsi_is_host_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x397d2c3b scsi_print_result +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x3aefd224 scsi_bios_ptable +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x3c7aa9fc scsi_setup_blk_pc_cmnd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x3db674fa scsi_target_resume +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x3ed0160f scsi_rescan_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x3fa8d430 scsi_device_resume +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x465e559a scsi_add_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x4afe9a77 scsi_partsize +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x5135fc96 scsi_is_target_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x55ac944c scsi_put_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x5690d3cc scsi_get_host_dev +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x56c8799d scsi_kunmap_atomic_sg +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x5e45ee18 scsicam_bios_param +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x5e77bdbe scsi_dma_map +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x69d38ed9 __scsi_print_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x6a0207ec scsi_finish_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x6b273f18 scsi_host_alloc +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x6da7312b scsi_device_set_state +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x7022d1a5 scsi_prep_return +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x71a8ace4 scsi_remove_host +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x71e7ab08 scsi_ioctl +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x72ea7b2d scsi_device_type +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x731ea688 __scsi_iterate_devices +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x73b45582 scsi_remove_target +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x76c0017c __scsi_put_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x796fc5ce scsi_get_sense_info_fld +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x7b3e1151 scsi_unblock_requests +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x8407ca76 __scsi_device_lookup +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x8fea6da6 scsi_is_sdev_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x90a6bb1b scsi_free_host_dev +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x943866b4 scsi_host_set_state +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x943d738d scsi_register +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x952f36e6 scsi_print_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x96cd2b04 scsi_sense_key_string +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x9c3235a3 scsi_device_lookup_by_target +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x9cfd56c5 scsi_print_status +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xa172ca1a scsi_remove_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xa2843543 scsi_free_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xa5e7e0ef scsi_track_queue_full +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xa5eeaecb scsi_test_unit_ready +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xa7ce434b scsi_execute_req +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xa9afd8b7 scsi_req_abort_cmd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xae1faaa1 scsi_eh_prep_cmnd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xaf3dd7dc scsi_logging_level +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xb3f3a4c9 scsi_unregister +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xb6c5a973 scsi_show_result +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xb7f415db scsi_host_get +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xb84af6d5 scsi_device_quiesce +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xc1825173 scsi_cmd_print_sense_hdr +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xc2f04930 __scsi_alloc_queue +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xca5dbc50 scsi_print_sense_hdr +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xca989c1e scsi_execute +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xcc794118 scsi_device_get +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xcc8aa498 scsi_init_io +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xd3038ab7 scsi_block_when_processing_errors +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xd775e4a9 scsi_dma_unmap +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xd8db0224 scsi_setup_fs_cmnd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xda3d1143 scsi_print_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xe2b6fc2a scsi_register_interface +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xe3e86ccd scsi_add_host +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xe86208a7 scsi_nonblockable_ioctl +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xea10212a int_to_scsilun +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xeb30e953 __scsi_device_lookup_by_target +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xefcea339 scsi_report_device_reset +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf08eb08f scsi_device_put +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf0e65317 scsi_release_buffers +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf4528073 scsi_kmap_atomic_sg +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf5dc487b __starget_for_each_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf811e69d scsi_eh_flush_done_q +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xfcf56390 scsi_block_requests +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xfef96e23 __scsi_print_command +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x05eef3c9 fc_remote_port_delete +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x3f5d4e57 scsi_is_fc_vport +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x4733ed42 fc_remote_port_add +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x7954b1ea fc_get_event_number +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x837f83cb fc_remove_host +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x8411f7d4 fc_host_post_vendor_event +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x9e2b90e8 fc_vport_terminate +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0xaaa38330 fc_remote_port_rolechg +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0xdf00ec53 fc_attach_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0xef86ae27 scsi_is_fc_rport +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0xf39afd18 fc_host_post_event +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0xf3bdd7c4 fc_release_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x0c6401b8 sas_attach_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x20b6b11e sas_rphy_delete +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x2223006a sas_phy_alloc +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x2314f2e2 sas_port_delete +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x2c5c0a4a sas_port_add +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x53b0c7cd scsi_is_sas_rphy +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x59e74794 sas_port_alloc +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x604c56f5 sas_phy_free +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x6a753c10 sas_phy_delete +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x708c61a5 sas_port_delete_phy +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x7d1a8090 sas_rphy_add +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x7d334f8e sas_port_free +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x82f29d1e scsi_is_sas_port +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x8877718f sas_release_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x8ae25afd sas_port_mark_backlink +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xb9a2f638 sas_expander_alloc +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xc960cfb4 sas_read_port_mode_page +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xcae3ab78 sas_remove_children +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xd18caa2c sas_phy_add +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xd33cfc6e sas_remove_host +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xd3ae44dd sas_port_alloc_num +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xd5f70312 sas_end_device_alloc +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xd77822d6 sas_rphy_remove +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xdc6a52a8 sas_port_add_phy +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xf3d90438 scsi_is_sas_phy +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xf811aef6 sas_rphy_free +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0x16e30ba7 spi_release_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0x361100ff spi_schedule_dv_device +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0x3686ea09 spi_print_msg +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0x3b810ffa spi_attach_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0xc08675d4 spi_display_xfer_agreement +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0xfc35560e spi_dv_device +EXPORT_SYMBOL drivers/ssb/ssb 0x058b6a70 ssb_bus_may_powerdown +EXPORT_SYMBOL drivers/ssb/ssb 0x1de4ff62 ssb_bus_suspend +EXPORT_SYMBOL drivers/ssb/ssb 0x2c6c218f ssb_pcicore_dev_irqvecs_enable +EXPORT_SYMBOL drivers/ssb/ssb 0x3d3d938a ssb_device_enable +EXPORT_SYMBOL drivers/ssb/ssb 0x3de57056 ssb_dma_set_mask +EXPORT_SYMBOL drivers/ssb/ssb 0x41366069 ssb_bus_pcibus_register +EXPORT_SYMBOL drivers/ssb/ssb 0x47886871 ssb_dma_translation +EXPORT_SYMBOL drivers/ssb/ssb 0x60501173 __ssb_driver_register +EXPORT_SYMBOL drivers/ssb/ssb 0x6d8fb826 ssb_clockspeed +EXPORT_SYMBOL drivers/ssb/ssb 0x8f5c9cf8 ssb_device_disable +EXPORT_SYMBOL drivers/ssb/ssb 0xc0512e0f ssb_admatch_base +EXPORT_SYMBOL drivers/ssb/ssb 0xc1364764 ssb_dma_free_consistent +EXPORT_SYMBOL drivers/ssb/ssb 0xcc9ebf7f ssb_set_devtypedata +EXPORT_SYMBOL drivers/ssb/ssb 0xd481192b ssb_admatch_size +EXPORT_SYMBOL drivers/ssb/ssb 0xd4ae3d04 ssb_device_is_enabled +EXPORT_SYMBOL drivers/ssb/ssb 0xd659f75f ssb_bus_powerup +EXPORT_SYMBOL drivers/ssb/ssb 0xd8b49524 ssb_driver_unregister +EXPORT_SYMBOL drivers/ssb/ssb 0xdb368a39 ssb_pcihost_register +EXPORT_SYMBOL drivers/ssb/ssb 0xdc78fb5c ssb_bus_unregister +EXPORT_SYMBOL drivers/ssb/ssb 0xf5f08953 ssb_bus_resume +EXPORT_SYMBOL drivers/ssb/ssb 0xf915c12b ssb_dma_alloc_consistent +EXPORT_SYMBOL drivers/telephony/ixj 0xe3082383 ixj_pcmcia_probe +EXPORT_SYMBOL drivers/telephony/phonedev 0x04d0bd13 phone_unregister_device +EXPORT_SYMBOL drivers/telephony/phonedev 0x8f9c2a56 phone_register_device +EXPORT_SYMBOL drivers/usb/gadget/net2280 0x3f966fad usb_gadget_register_driver +EXPORT_SYMBOL drivers/usb/gadget/net2280 0x65500a09 net2280_set_fifo_mode +EXPORT_SYMBOL drivers/usb/gadget/net2280 0x9519c541 usb_gadget_unregister_driver +EXPORT_SYMBOL drivers/usb/host/sl811-hcd 0x8ee69d40 sl811h_driver +EXPORT_SYMBOL drivers/usb/serial/usbserial 0x9b28adb3 usb_serial_resume +EXPORT_SYMBOL drivers/usb/serial/usbserial 0xb8b712cd usb_serial_suspend +EXPORT_SYMBOL drivers/video/backlight/corgi_bl 0xc86baa7c corgibl_limit_intensity +EXPORT_SYMBOL drivers/video/backlight/lcd 0xc2d6d3f0 lcd_device_unregister +EXPORT_SYMBOL drivers/video/backlight/lcd 0xfa44f217 lcd_device_register +EXPORT_SYMBOL drivers/video/console/bitblit 0xb60bcf3d fbcon_set_bitops +EXPORT_SYMBOL drivers/video/console/font 0x09c8eb55 font_vga_8x16 +EXPORT_SYMBOL drivers/video/console/font 0xbb99125c get_default_font +EXPORT_SYMBOL drivers/video/console/font 0xf7584a9c find_font +EXPORT_SYMBOL drivers/video/console/softcursor 0xcf2f30a9 soft_cursor +EXPORT_SYMBOL drivers/video/console/tileblit 0x61b8a072 fbcon_set_tileops +EXPORT_SYMBOL drivers/video/cyber2000fb 0x0cc3ede5 cyber2000fb_detach +EXPORT_SYMBOL drivers/video/cyber2000fb 0x0ce85cb0 cyber2000fb_disable_extregs +EXPORT_SYMBOL drivers/video/cyber2000fb 0x29e6f9bf cyber2000fb_attach +EXPORT_SYMBOL drivers/video/cyber2000fb 0x6e6ea3f3 cyber2000fb_enable_extregs +EXPORT_SYMBOL drivers/video/cyber2000fb 0xa3b9801b cyber2000fb_get_fb_var +EXPORT_SYMBOL drivers/video/display/display 0x0a72c73a display_device_unregister +EXPORT_SYMBOL drivers/video/display/display 0x9c5117c6 display_device_register +EXPORT_SYMBOL drivers/video/macmodes 0x08ed0b62 mac_vmode_to_var +EXPORT_SYMBOL drivers/video/macmodes 0x48058ff3 mac_find_mode +EXPORT_SYMBOL drivers/video/macmodes 0xe2304303 mac_map_monitor_sense +EXPORT_SYMBOL drivers/video/matrox/g450_pll 0x97cfdef3 g450_mnp2f +EXPORT_SYMBOL drivers/video/matrox/g450_pll 0xa7916536 matroxfb_g450_setpll_cond +EXPORT_SYMBOL drivers/video/matrox/g450_pll 0xe3f09095 matroxfb_g450_setclk +EXPORT_SYMBOL drivers/video/matrox/matroxfb_DAC1064 0x284b9f52 DAC1064_global_init +EXPORT_SYMBOL drivers/video/matrox/matroxfb_DAC1064 0x2afe9faa matrox_mystique +EXPORT_SYMBOL drivers/video/matrox/matroxfb_DAC1064 0xd3717e1b matrox_G100 +EXPORT_SYMBOL drivers/video/matrox/matroxfb_DAC1064 0xee38303c DAC1064_global_restore +EXPORT_SYMBOL drivers/video/matrox/matroxfb_Ti3026 0x6784de09 matrox_millennium +EXPORT_SYMBOL drivers/video/matrox/matroxfb_accel 0x4cfc0223 matrox_cfbX_init +EXPORT_SYMBOL drivers/video/matrox/matroxfb_base 0x82b4e21d matroxfb_enable_irq +EXPORT_SYMBOL drivers/video/matrox/matroxfb_base 0xadcab999 matroxfb_wait_for_sync +EXPORT_SYMBOL drivers/video/matrox/matroxfb_base 0xb50eb858 matroxfb_unregister_driver +EXPORT_SYMBOL drivers/video/matrox/matroxfb_base 0xff041bee matroxfb_register_driver +EXPORT_SYMBOL drivers/video/matrox/matroxfb_g450 0x07d80da5 matroxfb_g450_connect +EXPORT_SYMBOL drivers/video/matrox/matroxfb_g450 0xccc8db05 matroxfb_g450_shutdown +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0x25cf8049 matroxfb_PLL_calcclock +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0x368f4a4c matroxfb_vgaHWinit +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0x8bb8fa52 matroxfb_vgaHWrestore +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0xabd8e427 matroxfb_var2my +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0xb609b19e matroxfb_DAC_in +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0xee714544 matroxfb_DAC_out +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0xf7e2e08d matroxfb_read_pins +EXPORT_SYMBOL drivers/video/output 0xb2100689 video_output_unregister +EXPORT_SYMBOL drivers/video/output 0xdd202b9e video_output_register +EXPORT_SYMBOL drivers/video/sis/sisfb 0x3037658e sis_malloc +EXPORT_SYMBOL drivers/video/sis/sisfb 0x454a3cf0 sis_free +EXPORT_SYMBOL drivers/video/svgalib 0x00d1fce9 svga_set_default_seq_regs +EXPORT_SYMBOL drivers/video/svgalib 0x07b3da30 svga_wseq_multi +EXPORT_SYMBOL drivers/video/svgalib 0x1b95c56a svga_check_timings +EXPORT_SYMBOL drivers/video/svgalib 0x3fc4cd5a svga_get_tilemax +EXPORT_SYMBOL drivers/video/svgalib 0x58f6cb37 svga_tilecopy +EXPORT_SYMBOL drivers/video/svgalib 0x63e898d1 svga_set_default_crt_regs +EXPORT_SYMBOL drivers/video/svgalib 0x7a3ae959 svga_wcrt_multi +EXPORT_SYMBOL drivers/video/svgalib 0x80408443 svga_set_timings +EXPORT_SYMBOL drivers/video/svgalib 0x8fa8438b svga_set_textmode_vga_regs +EXPORT_SYMBOL drivers/video/svgalib 0x9b6efc30 svga_tileblit +EXPORT_SYMBOL drivers/video/svgalib 0xab3b22ad svga_set_default_gfx_regs +EXPORT_SYMBOL drivers/video/svgalib 0xb8e4ee54 svga_tilecursor +EXPORT_SYMBOL drivers/video/svgalib 0xc7c1c822 svga_get_caps +EXPORT_SYMBOL drivers/video/svgalib 0xdad682b1 svga_set_default_atc_regs +EXPORT_SYMBOL drivers/video/svgalib 0xec83c473 svga_match_format +EXPORT_SYMBOL drivers/video/svgalib 0xece84ae0 svga_tilefill +EXPORT_SYMBOL drivers/video/svgalib 0xef689bbf svga_settile +EXPORT_SYMBOL drivers/video/svgalib 0xef774f5d svga_compute_pll +EXPORT_SYMBOL drivers/video/syscopyarea 0x9175322b sys_copyarea +EXPORT_SYMBOL drivers/video/sysfillrect 0xa08a405f sys_fillrect +EXPORT_SYMBOL drivers/video/sysimgblt 0x53b9e59d sys_imageblit +EXPORT_SYMBOL drivers/video/vgastate 0x686de290 restore_vga +EXPORT_SYMBOL drivers/video/vgastate 0xe7a2620e save_vga +EXPORT_SYMBOL drivers/w1/slaves/w1_ds2760 0x6036e6b3 w1_ds2760_read +EXPORT_SYMBOL drivers/w1/slaves/w1_ds2760 0x73b3cf34 w1_ds2760_write +EXPORT_SYMBOL drivers/w1/wire 0x6724f7bc w1_unregister_family +EXPORT_SYMBOL drivers/w1/wire 0x8cf61660 w1_add_master_device +EXPORT_SYMBOL drivers/w1/wire 0x96c33d8b w1_register_family +EXPORT_SYMBOL drivers/w1/wire 0xcda061c0 w1_remove_master_device +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0x04e133fc iTCO_vendor_check_noreboot_on +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0x672c9d44 iTCO_vendor_pre_keepalive +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0xa78bd894 iTCO_vendor_pre_set_heartbeat +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0xa8d6daac iTCO_vendor_pre_start +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0xd0efe320 iTCO_vendor_pre_stop +EXPORT_SYMBOL fs/configfs/configfs 0x24517370 config_item_put +EXPORT_SYMBOL fs/configfs/configfs 0x27e53180 config_group_find_item +EXPORT_SYMBOL fs/configfs/configfs 0x41f59339 configfs_undepend_item +EXPORT_SYMBOL fs/configfs/configfs 0x7638efe3 configfs_register_subsystem +EXPORT_SYMBOL fs/configfs/configfs 0x778209f5 config_group_init +EXPORT_SYMBOL fs/configfs/configfs 0x9290e281 config_item_init +EXPORT_SYMBOL fs/configfs/configfs 0xa2501a2c config_item_set_name +EXPORT_SYMBOL fs/configfs/configfs 0xac7418e1 configfs_depend_item +EXPORT_SYMBOL fs/configfs/configfs 0xae812660 config_group_init_type_name +EXPORT_SYMBOL fs/configfs/configfs 0xb06f4821 config_item_get +EXPORT_SYMBOL fs/configfs/configfs 0xd1279084 config_item_init_type_name +EXPORT_SYMBOL fs/configfs/configfs 0xfe5b5d89 configfs_unregister_subsystem +EXPORT_SYMBOL fs/jbd/jbd 0x0ae93e9d journal_create +EXPORT_SYMBOL fs/jbd/jbd 0x10410af5 journal_init_dev +EXPORT_SYMBOL fs/jbd/jbd 0x1f131598 journal_get_write_access +EXPORT_SYMBOL fs/jbd/jbd 0x25e0c528 journal_try_to_free_buffers +EXPORT_SYMBOL fs/jbd/jbd 0x2e0b4ae4 journal_invalidatepage +EXPORT_SYMBOL fs/jbd/jbd 0x342774ae journal_ack_err +EXPORT_SYMBOL fs/jbd/jbd 0x4a4e1b39 journal_get_undo_access +EXPORT_SYMBOL fs/jbd/jbd 0x4b7901c0 journal_stop +EXPORT_SYMBOL fs/jbd/jbd 0x4d551cbc journal_check_available_features +EXPORT_SYMBOL fs/jbd/jbd 0x4efbd1e4 journal_dirty_metadata +EXPORT_SYMBOL fs/jbd/jbd 0x52f8749a log_wait_commit +EXPORT_SYMBOL fs/jbd/jbd 0x564c0c1a journal_blocks_per_page +EXPORT_SYMBOL fs/jbd/jbd 0x607b3e53 journal_dirty_data +EXPORT_SYMBOL fs/jbd/jbd 0x741ecb8a journal_clear_err +EXPORT_SYMBOL fs/jbd/jbd 0x7b937f85 journal_wipe +EXPORT_SYMBOL fs/jbd/jbd 0x7c9380f1 journal_destroy +EXPORT_SYMBOL fs/jbd/jbd 0x827092da journal_force_commit +EXPORT_SYMBOL fs/jbd/jbd 0x882ab474 journal_flush +EXPORT_SYMBOL fs/jbd/jbd 0x905057c0 journal_abort +EXPORT_SYMBOL fs/jbd/jbd 0x99e7d787 journal_lock_updates +EXPORT_SYMBOL fs/jbd/jbd 0x9c062319 journal_update_format +EXPORT_SYMBOL fs/jbd/jbd 0xa2b83d23 journal_unlock_updates +EXPORT_SYMBOL fs/jbd/jbd 0xb6aab3ff journal_release_buffer +EXPORT_SYMBOL fs/jbd/jbd 0xc3c834ec journal_restart +EXPORT_SYMBOL fs/jbd/jbd 0xc703b299 journal_set_features +EXPORT_SYMBOL fs/jbd/jbd 0xc94400a0 journal_extend +EXPORT_SYMBOL fs/jbd/jbd 0xda8cd68d journal_errno +EXPORT_SYMBOL fs/jbd/jbd 0xe036343f journal_forget +EXPORT_SYMBOL fs/jbd/jbd 0xe39df4a9 journal_get_create_access +EXPORT_SYMBOL fs/jbd/jbd 0xe86e6210 journal_start +EXPORT_SYMBOL fs/jbd/jbd 0xea049045 journal_revoke +EXPORT_SYMBOL fs/jbd/jbd 0xeedfdb3a journal_check_used_features +EXPORT_SYMBOL fs/jbd/jbd 0xf65c9c2c journal_load +EXPORT_SYMBOL fs/jbd/jbd 0xf77417b5 journal_init_inode +EXPORT_SYMBOL fs/jbd/jbd 0xfb279459 journal_start_commit +EXPORT_SYMBOL fs/jbd/jbd 0xfe39ce31 journal_force_commit_nested +EXPORT_SYMBOL fs/jbd2/jbd2 0x04653f13 jbd2_journal_clear_features +EXPORT_SYMBOL fs/jbd2/jbd2 0x04e24c2b jbd2_journal_restart +EXPORT_SYMBOL fs/jbd2/jbd2 0x271f0dc1 jbd2_journal_force_commit +EXPORT_SYMBOL fs/jbd2/jbd2 0x281456cb jbd2_journal_unlock_updates +EXPORT_SYMBOL fs/jbd2/jbd2 0x28d098bf jbd2_journal_set_features +EXPORT_SYMBOL fs/jbd2/jbd2 0x296a41e8 jbd2_journal_dirty_metadata +EXPORT_SYMBOL fs/jbd2/jbd2 0x2b420a95 jbd2_journal_blocks_per_page +EXPORT_SYMBOL fs/jbd2/jbd2 0x3b7a7db1 jbd2_log_wait_commit +EXPORT_SYMBOL fs/jbd2/jbd2 0x42d818bb jbd2_journal_try_to_free_buffers +EXPORT_SYMBOL fs/jbd2/jbd2 0x448f1e86 jbd2_journal_flush +EXPORT_SYMBOL fs/jbd2/jbd2 0x4a506058 jbd2_journal_check_used_features +EXPORT_SYMBOL fs/jbd2/jbd2 0x5d1803cb jbd2_journal_release_jbd_inode +EXPORT_SYMBOL fs/jbd2/jbd2 0x65068d4c jbd2_journal_get_create_access +EXPORT_SYMBOL fs/jbd2/jbd2 0x66c29ce4 jbd2_journal_init_inode +EXPORT_SYMBOL fs/jbd2/jbd2 0x6b2d5003 jbd2_journal_create +EXPORT_SYMBOL fs/jbd2/jbd2 0x7c4cc8dc jbd2_journal_start_commit +EXPORT_SYMBOL fs/jbd2/jbd2 0x91afba31 jbd2_journal_lock_updates +EXPORT_SYMBOL fs/jbd2/jbd2 0xaec2f619 jbd2_journal_get_undo_access +EXPORT_SYMBOL fs/jbd2/jbd2 0xb40a3c9f jbd2_journal_ack_err +EXPORT_SYMBOL fs/jbd2/jbd2 0xb4ff58d7 jbd2_journal_file_inode +EXPORT_SYMBOL fs/jbd2/jbd2 0xbaf2671e jbd2_journal_begin_ordered_truncate +EXPORT_SYMBOL fs/jbd2/jbd2 0xbc1cc5b1 jbd2_journal_revoke +EXPORT_SYMBOL fs/jbd2/jbd2 0xbfaae622 jbd2_journal_get_write_access +EXPORT_SYMBOL fs/jbd2/jbd2 0xc0cd8853 jbd2_journal_start +EXPORT_SYMBOL fs/jbd2/jbd2 0xc56ec42e jbd2_journal_load +EXPORT_SYMBOL fs/jbd2/jbd2 0xc6b6766b jbd2_journal_force_commit_nested +EXPORT_SYMBOL fs/jbd2/jbd2 0xc7cc7658 jbd2_journal_update_format +EXPORT_SYMBOL fs/jbd2/jbd2 0xc991e355 jbd2_journal_check_available_features +EXPORT_SYMBOL fs/jbd2/jbd2 0xcb6ab90c jbd2_journal_errno +EXPORT_SYMBOL fs/jbd2/jbd2 0xcbd739bb jbd2_journal_forget +EXPORT_SYMBOL fs/jbd2/jbd2 0xcd7b74ef jbd2_journal_release_buffer +EXPORT_SYMBOL fs/jbd2/jbd2 0xd0407b0f jbd2_journal_extend +EXPORT_SYMBOL fs/jbd2/jbd2 0xe2499f78 jbd2_journal_clear_err +EXPORT_SYMBOL fs/jbd2/jbd2 0xe2ab8702 jbd2_journal_wipe +EXPORT_SYMBOL fs/jbd2/jbd2 0xe4499b83 jbd2_journal_stop +EXPORT_SYMBOL fs/jbd2/jbd2 0xe49c7a6b jbd2_journal_init_dev +EXPORT_SYMBOL fs/jbd2/jbd2 0xf1f0ee15 jbd2_journal_init_jbd_inode +EXPORT_SYMBOL fs/jbd2/jbd2 0xf82a406d jbd2_journal_invalidatepage +EXPORT_SYMBOL fs/jbd2/jbd2 0xfb0812b0 jbd2_journal_abort +EXPORT_SYMBOL fs/jbd2/jbd2 0xfe637d17 jbd2_journal_destroy +EXPORT_SYMBOL fs/lockd/lockd 0x47e4e496 nlmsvc_ops +EXPORT_SYMBOL fs/lockd/lockd 0x976e539e lockd_up +EXPORT_SYMBOL fs/lockd/lockd 0xa7b91a7b lockd_down +EXPORT_SYMBOL fs/lockd/lockd 0xad09c2db get_nfs_grace_period +EXPORT_SYMBOL fs/mbcache 0x077fcb51 mb_cache_entry_get +EXPORT_SYMBOL fs/mbcache 0x5f37873e mb_cache_shrink +EXPORT_SYMBOL fs/mbcache 0x60c90ebd mb_cache_entry_release +EXPORT_SYMBOL fs/mbcache 0x61c6990d mb_cache_create +EXPORT_SYMBOL fs/mbcache 0x7087f1af mb_cache_entry_insert +EXPORT_SYMBOL fs/mbcache 0x7ac0de17 mb_cache_entry_alloc +EXPORT_SYMBOL fs/mbcache 0xac45785f mb_cache_entry_find_next +EXPORT_SYMBOL fs/mbcache 0xb1ee9e93 mb_cache_entry_find_first +EXPORT_SYMBOL fs/mbcache 0xc231ff75 mb_cache_entry_free +EXPORT_SYMBOL fs/mbcache 0xd5263820 mb_cache_destroy +EXPORT_SYMBOL fs/nfs_common/nfs_acl 0x0c608226 nfsacl_encode +EXPORT_SYMBOL fs/nfs_common/nfs_acl 0xbcdcbea6 nfsacl_decode +EXPORT_SYMBOL fs/nfsd/nfsd 0x23f0a2c8 nfs4_acl_nfsv4_to_posix +EXPORT_SYMBOL fs/nfsd/nfsd 0x35e33c1e nfs4_acl_write_who +EXPORT_SYMBOL fs/nfsd/nfsd 0x46ffdc39 nfs4_acl_posix_to_nfsv4 +EXPORT_SYMBOL fs/nfsd/nfsd 0x5a157ae4 nfs4_acl_get_whotype +EXPORT_SYMBOL fs/nfsd/nfsd 0x96ce9bb4 nfs4_acl_new +EXPORT_SYMBOL fs/xfs/xfs 0x5c4d0851 xfs_qmcore_xfs +EXPORT_SYMBOL lib/crc-ccitt 0x651c2313 crc_ccitt +EXPORT_SYMBOL lib/crc-ccitt 0x75811312 crc_ccitt_table +EXPORT_SYMBOL lib/crc-itu-t 0x276c7e62 crc_itu_t +EXPORT_SYMBOL lib/crc-itu-t 0xd29b009f crc_itu_t_table +EXPORT_SYMBOL lib/crc-t10dif 0x782acba5 crc_t10dif +EXPORT_SYMBOL lib/crc16 0x02a6ce5a crc16_table +EXPORT_SYMBOL lib/crc16 0x9aabc564 crc16 +EXPORT_SYMBOL lib/crc7 0xc086bfba crc7 +EXPORT_SYMBOL lib/crc7 0xd80c3603 crc7_syndrome_table +EXPORT_SYMBOL lib/libcrc32c 0x13c0c38e crc32c_le +EXPORT_SYMBOL lib/libcrc32c 0x41bcd8b3 crc32c_be +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0x315c65fd zlib_deflateInit2 +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0x48034724 zlib_deflateReset +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0xaf64ad0d zlib_deflate +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0xf0caf44b zlib_deflate_workspacesize +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0xf741c793 zlib_deflateEnd +EXPORT_SYMBOL net/802/p8023 0x6a0f48de make_8023_client +EXPORT_SYMBOL net/802/p8023 0xb72269aa destroy_8023_client +EXPORT_SYMBOL net/9p/9pnet 0x00a6e1a5 p9_create_tclunk +EXPORT_SYMBOL net/9p/9pnet 0x0106a185 p9_create_tstat +EXPORT_SYMBOL net/9p/9pnet 0x0b26ff5a v9fs_unregister_trans +EXPORT_SYMBOL net/9p/9pnet 0x0dc94010 p9_client_read +EXPORT_SYMBOL net/9p/9pnet 0x15779868 p9_set_tag +EXPORT_SYMBOL net/9p/9pnet 0x15beb258 p9_client_stat +EXPORT_SYMBOL net/9p/9pnet 0x20f85208 p9_client_readn +EXPORT_SYMBOL net/9p/9pnet 0x21523da9 p9_create_tattach +EXPORT_SYMBOL net/9p/9pnet 0x244c6d40 p9_idpool_get +EXPORT_SYMBOL net/9p/9pnet 0x28cdbddc p9_client_open +EXPORT_SYMBOL net/9p/9pnet 0x2cae9487 p9_client_fcreate +EXPORT_SYMBOL net/9p/9pnet 0x309767d8 p9_deserialize_stat +EXPORT_SYMBOL net/9p/9pnet 0x315526bd p9_client_uwrite +EXPORT_SYMBOL net/9p/9pnet 0x31855989 p9_client_disconnect +EXPORT_SYMBOL net/9p/9pnet 0x3d73a797 p9_errstr2errno +EXPORT_SYMBOL net/9p/9pnet 0x465c4e6f p9_printfcall +EXPORT_SYMBOL net/9p/9pnet 0x507c9d70 p9_create_tauth +EXPORT_SYMBOL net/9p/9pnet 0x52b030cd p9_client_auth +EXPORT_SYMBOL net/9p/9pnet 0x58cc1098 p9_client_destroy +EXPORT_SYMBOL net/9p/9pnet 0x5e0ef374 p9_idpool_check +EXPORT_SYMBOL net/9p/9pnet 0x61852dea p9_idpool_put +EXPORT_SYMBOL net/9p/9pnet 0x6461b8de p9_create_twrite +EXPORT_SYMBOL net/9p/9pnet 0x6c5e479c p9_idpool_create +EXPORT_SYMBOL net/9p/9pnet 0x6f11c5c3 p9_create_twrite_u +EXPORT_SYMBOL net/9p/9pnet 0x71c7537d p9_create_tcreate +EXPORT_SYMBOL net/9p/9pnet 0x75d8f435 p9_client_wstat +EXPORT_SYMBOL net/9p/9pnet 0x7c3123e0 p9_client_write +EXPORT_SYMBOL net/9p/9pnet 0x81247f39 p9_create_tread +EXPORT_SYMBOL net/9p/9pnet 0x8432c83f p9_deserialize_fcall +EXPORT_SYMBOL net/9p/9pnet 0x845f41ff p9_client_clunk +EXPORT_SYMBOL net/9p/9pnet 0x950e6b03 p9_create_twstat +EXPORT_SYMBOL net/9p/9pnet 0x95abb195 p9_client_attach +EXPORT_SYMBOL net/9p/9pnet 0x9eca3ca7 p9_client_dirread +EXPORT_SYMBOL net/9p/9pnet 0xa7d22910 p9_client_remove +EXPORT_SYMBOL net/9p/9pnet 0xa9536064 p9_create_tversion +EXPORT_SYMBOL net/9p/9pnet 0xad806a33 p9_client_uread +EXPORT_SYMBOL net/9p/9pnet 0xadfd597a p9_create_tremove +EXPORT_SYMBOL net/9p/9pnet 0xaffd854f p9_client_create +EXPORT_SYMBOL net/9p/9pnet 0xbaa17b44 p9_idpool_destroy +EXPORT_SYMBOL net/9p/9pnet 0xbb0bb702 v9fs_get_trans_by_name +EXPORT_SYMBOL net/9p/9pnet 0xdc894ac7 p9_create_twalk +EXPORT_SYMBOL net/9p/9pnet 0xe09b7d13 p9_client_walk +EXPORT_SYMBOL net/9p/9pnet 0xe58a3360 p9_error_init +EXPORT_SYMBOL net/9p/9pnet 0xe6238993 v9fs_get_default_trans +EXPORT_SYMBOL net/9p/9pnet 0xf09b3efa p9_create_topen +EXPORT_SYMBOL net/9p/9pnet 0xf85870ff v9fs_register_trans +EXPORT_SYMBOL net/9p/9pnet 0xfff27930 p9_create_tflush +EXPORT_SYMBOL net/appletalk/appletalk 0x85bfa1fb aarp_send_ddp +EXPORT_SYMBOL net/appletalk/appletalk 0x8d893465 atalk_find_dev_addr +EXPORT_SYMBOL net/appletalk/appletalk 0xc4b8533c atrtr_get_dev +EXPORT_SYMBOL net/appletalk/appletalk 0xc596bff9 alloc_ltalkdev +EXPORT_SYMBOL net/ax25/ax25 0x0479d44f ax25_findbyuid +EXPORT_SYMBOL net/ax25/ax25 0x060e2328 ax25_rebuild_header +EXPORT_SYMBOL net/ax25/ax25 0x105e7bfb ax25_hard_header +EXPORT_SYMBOL net/ax25/ax25 0x242852b9 ax25_uid_policy +EXPORT_SYMBOL net/ax25/ax25 0x3d2d82ec ax25_display_timer +EXPORT_SYMBOL net/ax25/ax25 0x410761d7 ax25_linkfail_release +EXPORT_SYMBOL net/ax25/ax25 0x4502c65a asc2ax +EXPORT_SYMBOL net/ax25/ax25 0x53dea1ff ax2asc +EXPORT_SYMBOL net/ax25/ax25 0x7788fcbe ax25_send_frame +EXPORT_SYMBOL net/ax25/ax25 0x7fa435ab ax25_find_cb +EXPORT_SYMBOL net/ax25/ax25 0x81f5564c ax25_listen_release +EXPORT_SYMBOL net/ax25/ax25 0x8ede9e26 ax25_protocol_release +EXPORT_SYMBOL net/ax25/ax25 0x97b85f2d ax25_listen_register +EXPORT_SYMBOL net/ax25/ax25 0xc1444946 ax25cmp +EXPORT_SYMBOL net/ax25/ax25 0xc42ee6b7 ax25_header_ops +EXPORT_SYMBOL net/ax25/ax25 0xd43ecbf1 null_ax25_address +EXPORT_SYMBOL net/ax25/ax25 0xf477a4a5 ax25_linkfail_register +EXPORT_SYMBOL net/bluetooth/bluetooth 0x0d24b97c bt_accept_unlink +EXPORT_SYMBOL net/bluetooth/bluetooth 0x0f01807c hci_suspend_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0x10809060 hci_connect +EXPORT_SYMBOL net/bluetooth/bluetooth 0x111cba60 hci_conn_auth +EXPORT_SYMBOL net/bluetooth/bluetooth 0x178e8929 hci_resume_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0x17d2f095 hci_unregister_cb +EXPORT_SYMBOL net/bluetooth/bluetooth 0x23a6a8d1 hci_conn_encrypt +EXPORT_SYMBOL net/bluetooth/bluetooth 0x29f30a4f hci_get_route +EXPORT_SYMBOL net/bluetooth/bluetooth 0x2bfcf4d4 bt_sock_link +EXPORT_SYMBOL net/bluetooth/bluetooth 0x31e6fcf2 hci_send_acl +EXPORT_SYMBOL net/bluetooth/bluetooth 0x42d04eac hci_register_cb +EXPORT_SYMBOL net/bluetooth/bluetooth 0x442ee147 bt_sock_unlink +EXPORT_SYMBOL net/bluetooth/bluetooth 0x457bf861 hci_register_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0x49731587 hci_send_sco +EXPORT_SYMBOL net/bluetooth/bluetooth 0x4d04a9a0 bt_accept_enqueue +EXPORT_SYMBOL net/bluetooth/bluetooth 0x4fa222b1 hci_register_proto +EXPORT_SYMBOL net/bluetooth/bluetooth 0x52cf7088 hci_unregister_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0x5d71811f hci_conn_change_link_key +EXPORT_SYMBOL net/bluetooth/bluetooth 0x5f34aaf1 hci_unregister_proto +EXPORT_SYMBOL net/bluetooth/bluetooth 0x6461fbff bt_sock_ioctl +EXPORT_SYMBOL net/bluetooth/bluetooth 0x7094f8ae bt_err +EXPORT_SYMBOL net/bluetooth/bluetooth 0x79b31dd2 bt_sock_poll +EXPORT_SYMBOL net/bluetooth/bluetooth 0x79bfa4ea hci_conn_check_link_mode +EXPORT_SYMBOL net/bluetooth/bluetooth 0x94d57354 bt_accept_dequeue +EXPORT_SYMBOL net/bluetooth/bluetooth 0x97c1bd94 bt_sock_recvmsg +EXPORT_SYMBOL net/bluetooth/bluetooth 0xa0eb0173 hci_recv_fragment +EXPORT_SYMBOL net/bluetooth/bluetooth 0xa3f86604 hci_alloc_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0xba8ac00f bt_sock_wait_state +EXPORT_SYMBOL net/bluetooth/bluetooth 0xc2066af0 batostr +EXPORT_SYMBOL net/bluetooth/bluetooth 0xcc1fb551 baswap +EXPORT_SYMBOL net/bluetooth/bluetooth 0xe000b944 hci_conn_switch_role +EXPORT_SYMBOL net/bluetooth/bluetooth 0xe73f3018 hci_free_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0xf19294db bt_sock_unregister +EXPORT_SYMBOL net/bluetooth/bluetooth 0xfa86224b bt_sock_register +EXPORT_SYMBOL net/bluetooth/l2cap 0xfc31fe88 l2cap_load +EXPORT_SYMBOL net/bridge/bridge 0x6490d476 br_should_route_hook +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x156d4094 ebt_unregister_watcher +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x5e5e36eb ebt_register_table +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x645b14ec ebt_unregister_target +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x85565456 ebt_register_watcher +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x8c519b7a ebt_unregister_match +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0xbcd9eebb ebt_unregister_table +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0xc6fee6e4 ebt_register_match +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0xc7ec82df ebt_register_target +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0xf0966dc3 ebt_do_table +EXPORT_SYMBOL net/ieee80211/ieee80211 0x14d61d7b ieee80211_wx_get_encode +EXPORT_SYMBOL net/ieee80211/ieee80211 0x1f19db99 ieee80211_txb_free +EXPORT_SYMBOL net/ieee80211/ieee80211 0x333e9afa ieee80211_wx_get_scan +EXPORT_SYMBOL net/ieee80211/ieee80211 0x68ab885d ieee80211_get_geo +EXPORT_SYMBOL net/ieee80211/ieee80211 0x6a5e8b8f ieee80211_wx_set_encode +EXPORT_SYMBOL net/ieee80211/ieee80211 0x6ff5c858 ieee80211_get_channel_flags +EXPORT_SYMBOL net/ieee80211/ieee80211 0x790edbc5 ieee80211_get_channel +EXPORT_SYMBOL net/ieee80211/ieee80211 0x86a05709 ieee80211_wx_get_encodeext +EXPORT_SYMBOL net/ieee80211/ieee80211 0x976076fc ieee80211_rx_mgt +EXPORT_SYMBOL net/ieee80211/ieee80211 0x9af579a5 alloc_ieee80211 +EXPORT_SYMBOL net/ieee80211/ieee80211 0x9d0cd3f7 ieee80211_channel_to_index +EXPORT_SYMBOL net/ieee80211/ieee80211 0xa56e06bc ieee80211_is_valid_channel +EXPORT_SYMBOL net/ieee80211/ieee80211 0xa8b8c448 ieee80211_freq_to_channel +EXPORT_SYMBOL net/ieee80211/ieee80211 0xa9fb135f escape_essid +EXPORT_SYMBOL net/ieee80211/ieee80211 0xaeef3e29 ieee80211_set_geo +EXPORT_SYMBOL net/ieee80211/ieee80211 0xe144d001 free_ieee80211 +EXPORT_SYMBOL net/ieee80211/ieee80211 0xf015aaf5 ieee80211_wx_set_encodeext +EXPORT_SYMBOL net/ieee80211/ieee80211 0xf1ca90aa ieee80211_channel_to_freq +EXPORT_SYMBOL net/ieee80211/ieee80211 0xff4d7406 ieee80211_rx +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x043cc01d ieee80211_crypt_quiescing +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x279e265f ieee80211_crypt_deinit_handler +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x2d7aa8f8 ieee80211_get_crypto_ops +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x4135c493 ieee80211_crypt_delayed_deinit +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x5d8f43ae ieee80211_register_crypto_ops +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x93271ffc ieee80211_unregister_crypto_ops +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0xfbbba599 ieee80211_crypt_deinit_entries +EXPORT_SYMBOL net/ipv4/inet_lro 0x2b86542c lro_vlan_hwaccel_receive_skb +EXPORT_SYMBOL net/ipv4/inet_lro 0x4ea839ef lro_flush_all +EXPORT_SYMBOL net/ipv4/inet_lro 0x6d595e75 lro_vlan_hwaccel_receive_frags +EXPORT_SYMBOL net/ipv4/inet_lro 0x7c6ac434 lro_flush_pkt +EXPORT_SYMBOL net/ipv4/inet_lro 0x9cfbf6c8 lro_receive_skb +EXPORT_SYMBOL net/ipv4/inet_lro 0xf2e5c239 lro_receive_frags +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x251a3a01 register_ip_vs_app_inc +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x29039c0a ip_vs_conn_new +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x4b8714bc register_ip_vs_scheduler +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x5b729b8e ip_vs_conn_out_get +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x762dd3f4 unregister_ip_vs_scheduler +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x7c57d3f2 ip_vs_tcp_conn_listen +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x98313633 ip_vs_skb_replace +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x9ddc19ab register_ip_vs_app +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0xa1dbc2d8 ip_vs_proto_name +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0xa5f09b74 ip_vs_conn_put +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0xc202388b ip_vs_conn_in_get +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0xd08bc1f9 unregister_ip_vs_app +EXPORT_SYMBOL net/ipv4/netfilter/arp_tables 0xaea94aab arpt_unregister_table +EXPORT_SYMBOL net/ipv4/netfilter/arp_tables 0xc0f28649 arpt_register_table +EXPORT_SYMBOL net/ipv4/netfilter/arp_tables 0xcd819d95 arpt_do_table +EXPORT_SYMBOL net/ipv4/netfilter/ip_tables 0x6d90b192 ipt_do_table +EXPORT_SYMBOL net/ipv4/netfilter/ip_tables 0xb6495ff6 ipt_unregister_table +EXPORT_SYMBOL net/ipv4/netfilter/ip_tables 0xe52f98a5 ipt_register_table +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0x093387d2 nf_nat_setup_info +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0x82498fce nf_nat_mangle_tcp_packet +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0xa2311568 nf_nat_protocol_unregister +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0xad7e2bce nf_nat_follow_master +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0xb0b79443 nf_nat_protocol_register +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0xcf5f7ac6 nf_nat_used_tuple +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0xf8ea685a nf_nat_mangle_udp_packet +EXPORT_SYMBOL net/ipv4/tunnel4 0x1135f298 xfrm4_tunnel_register +EXPORT_SYMBOL net/ipv4/tunnel4 0xcd6b95bf xfrm4_tunnel_deregister +EXPORT_SYMBOL net/ipv6/ipv6 0x14b48c83 xfrm6_rcv +EXPORT_SYMBOL net/ipv6/ipv6 0x2df79d8c ip6_frag_init +EXPORT_SYMBOL net/ipv6/ipv6 0x30123eb5 icmpv6_statistics +EXPORT_SYMBOL net/ipv6/ipv6 0x40e4e3a9 ndisc_mc_map +EXPORT_SYMBOL net/ipv6/ipv6 0x432b94f4 compat_ipv6_getsockopt +EXPORT_SYMBOL net/ipv6/ipv6 0x459fdd5c inet6_add_protocol +EXPORT_SYMBOL net/ipv6/ipv6 0x502a94d0 ipv6_push_nfrag_opts +EXPORT_SYMBOL net/ipv6/ipv6 0x538383c0 unregister_inet6addr_notifier +EXPORT_SYMBOL net/ipv6/ipv6 0x5e05cd61 ip6_route_output +EXPORT_SYMBOL net/ipv6/ipv6 0x6a1a874d inet6_unregister_protosw +EXPORT_SYMBOL net/ipv6/ipv6 0x6d2ae8fb in6_dev_finish_destroy +EXPORT_SYMBOL net/ipv6/ipv6 0x79089826 inet6_ioctl +EXPORT_SYMBOL net/ipv6/ipv6 0x7e42ae69 xfrm6_rcv_spi +EXPORT_SYMBOL net/ipv6/ipv6 0x8130541e rt6_lookup +EXPORT_SYMBOL net/ipv6/ipv6 0x830ea66c xfrm6_prepare_output +EXPORT_SYMBOL net/ipv6/ipv6 0x865fae04 ip6_xmit +EXPORT_SYMBOL net/ipv6/ipv6 0x8804c527 compat_ipv6_setsockopt +EXPORT_SYMBOL net/ipv6/ipv6 0x9185e9e2 ip6_frag_match +EXPORT_SYMBOL net/ipv6/ipv6 0x9d51b0e3 xfrm6_find_1stfragopt +EXPORT_SYMBOL net/ipv6/ipv6 0xab4ac243 ipv6_getsockopt +EXPORT_SYMBOL net/ipv6/ipv6 0xb1167cb5 xfrm6_input_addr +EXPORT_SYMBOL net/ipv6/ipv6 0xb6298ea7 ipv6_chk_prefix +EXPORT_SYMBOL net/ipv6/ipv6 0xb905ad82 icmpv6_err_convert +EXPORT_SYMBOL net/ipv6/ipv6 0xbf77ac61 ip6_route_me_harder +EXPORT_SYMBOL net/ipv6/ipv6 0xc001615d inet6_register_protosw +EXPORT_SYMBOL net/ipv6/ipv6 0xcbe54708 ipv6_dev_get_saddr +EXPORT_SYMBOL net/ipv6/ipv6 0xccb5db18 ipv6_chk_addr +EXPORT_SYMBOL net/ipv6/ipv6 0xcdb507a2 inet6_bind +EXPORT_SYMBOL net/ipv6/ipv6 0xce19bac5 register_inet6addr_notifier +EXPORT_SYMBOL net/ipv6/ipv6 0xd5977f7e inet6_getname +EXPORT_SYMBOL net/ipv6/ipv6 0xdab6d09f inet6_release +EXPORT_SYMBOL net/ipv6/ipv6 0xdcda5ece ipv6_setsockopt +EXPORT_SYMBOL net/ipv6/ipv6 0xe1a81c3a icmpv6msg_statistics +EXPORT_SYMBOL net/ipv6/ipv6 0xe4163511 icmpv6_send +EXPORT_SYMBOL net/ipv6/ipv6 0xe690b8fd __ipv6_isatap_ifid +EXPORT_SYMBOL net/ipv6/ipv6 0xebccd8cd inet6_del_protocol +EXPORT_SYMBOL net/ipv6/ipv6 0xf20b6c1a nf_ip6_checksum +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0x078f144d ip6t_register_table +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0x7692945a ip6t_do_table +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0xb8bddf33 ip6t_ext_hdr +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0xc9012fc8 ip6t_unregister_table +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0xdbf88b36 ipv6_find_hdr +EXPORT_SYMBOL net/ipv6/tunnel6 0x2ef1ec69 xfrm6_tunnel_deregister +EXPORT_SYMBOL net/ipv6/tunnel6 0x4b40fb15 xfrm6_tunnel_register +EXPORT_SYMBOL net/ipv6/xfrm6_tunnel 0x9cd013f2 xfrm6_tunnel_alloc_spi +EXPORT_SYMBOL net/ipv6/xfrm6_tunnel 0xab14e193 xfrm6_tunnel_free_spi +EXPORT_SYMBOL net/ipv6/xfrm6_tunnel 0xdb1b42d1 xfrm6_tunnel_spi_lookup +EXPORT_SYMBOL net/irda/ircomm/ircomm 0x30de0805 ircomm_flow_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0x45e01f3e ircomm_close +EXPORT_SYMBOL net/irda/ircomm/ircomm 0x5405eaaa ircomm_data_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0x75589783 ircomm_connect_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0x8b7baa6b ircomm_disconnect_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0x994d10d3 ircomm_connect_response +EXPORT_SYMBOL net/irda/ircomm/ircomm 0xb25d0bb8 ircomm_control_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0xec1c5eac ircomm_open +EXPORT_SYMBOL net/irda/irda 0x01d1fcdb hashbin_delete +EXPORT_SYMBOL net/irda/irda 0x06a3ee58 irias_new_integer_value +EXPORT_SYMBOL net/irda/irda 0x072e026f irias_add_octseq_attrib +EXPORT_SYMBOL net/irda/irda 0x07d3647c irlmp_register_service +EXPORT_SYMBOL net/irda/irda 0x0aaafe02 irttp_dup +EXPORT_SYMBOL net/irda/irda 0x1e6abfe2 irttp_open_tsap +EXPORT_SYMBOL net/irda/irda 0x2036ad06 irda_param_insert +EXPORT_SYMBOL net/irda/irda 0x2717bc25 iriap_open +EXPORT_SYMBOL net/irda/irda 0x2895f6d4 irlmp_open_lsap +EXPORT_SYMBOL net/irda/irda 0x3462950f hashbin_remove +EXPORT_SYMBOL net/irda/irda 0x38a20e5b irda_debug +EXPORT_SYMBOL net/irda/irda 0x4186f1c9 irttp_disconnect_request +EXPORT_SYMBOL net/irda/irda 0x448b8aaa irda_qos_bits_to_value +EXPORT_SYMBOL net/irda/irda 0x46c1c4a2 irlmp_unregister_service +EXPORT_SYMBOL net/irda/irda 0x518ccd53 irlap_close +EXPORT_SYMBOL net/irda/irda 0x58356106 irttp_connect_request +EXPORT_SYMBOL net/irda/irda 0x670cbbbc irlmp_connect_request +EXPORT_SYMBOL net/irda/irda 0x6758f8ac irias_new_object +EXPORT_SYMBOL net/irda/irda 0x68b7447c hashbin_find +EXPORT_SYMBOL net/irda/irda 0x6b043eba irda_init_max_qos_capabilies +EXPORT_SYMBOL net/irda/irda 0x6dd0c96a irttp_connect_response +EXPORT_SYMBOL net/irda/irda 0x7042bc54 irlmp_register_client +EXPORT_SYMBOL net/irda/irda 0x72bc4cbf irlmp_disconnect_request +EXPORT_SYMBOL net/irda/irda 0x747d6779 irias_delete_object +EXPORT_SYMBOL net/irda/irda 0x7621e908 hashbin_insert +EXPORT_SYMBOL net/irda/irda 0x76243bc9 irias_insert_object +EXPORT_SYMBOL net/irda/irda 0x763e54a4 irlmp_unregister_client +EXPORT_SYMBOL net/irda/irda 0x76bfafae irda_notify_init +EXPORT_SYMBOL net/irda/irda 0x781e2db5 irias_find_object +EXPORT_SYMBOL net/irda/irda 0x7957f728 irlmp_update_client +EXPORT_SYMBOL net/irda/irda 0x7a57b6f3 hashbin_remove_this +EXPORT_SYMBOL net/irda/irda 0x8e9d6ebb irlmp_close_lsap +EXPORT_SYMBOL net/irda/irda 0x908bad75 irttp_data_request +EXPORT_SYMBOL net/irda/irda 0x90ab3819 iriap_getvaluebyclass_request +EXPORT_SYMBOL net/irda/irda 0x91815586 irda_param_pack +EXPORT_SYMBOL net/irda/irda 0x993ad14b irda_param_extract_all +EXPORT_SYMBOL net/irda/irda 0x9e5e780a irlmp_connect_response +EXPORT_SYMBOL net/irda/irda 0xa336963a async_wrap_skb +EXPORT_SYMBOL net/irda/irda 0xb9394173 irias_delete_value +EXPORT_SYMBOL net/irda/irda 0xbbf9cb84 irttp_flow_request +EXPORT_SYMBOL net/irda/irda 0xbc1a9922 iriap_close +EXPORT_SYMBOL net/irda/irda 0xbcd3ef13 irias_object_change_attribute +EXPORT_SYMBOL net/irda/irda 0xbe40ace9 irlmp_discovery_request +EXPORT_SYMBOL net/irda/irda 0xc14e9b6a hashbin_get_next +EXPORT_SYMBOL net/irda/irda 0xc14f0dbd alloc_irdadev +EXPORT_SYMBOL net/irda/irda 0xc5e7ef83 async_unwrap_char +EXPORT_SYMBOL net/irda/irda 0xcb3d3f3b irda_device_set_media_busy +EXPORT_SYMBOL net/irda/irda 0xcb83e5b9 irttp_close_tsap +EXPORT_SYMBOL net/irda/irda 0xcd41236c hashbin_new +EXPORT_SYMBOL net/irda/irda 0xd6deeaae irda_setup_dma +EXPORT_SYMBOL net/irda/irda 0xd7172ff4 hashbin_get_first +EXPORT_SYMBOL net/irda/irda 0xd824e355 irttp_udata_request +EXPORT_SYMBOL net/irda/irda 0xd8bfb6d4 hashbin_lock_find +EXPORT_SYMBOL net/irda/irda 0xdce38bb1 irlap_open +EXPORT_SYMBOL net/irda/irda 0xde4c6b3c irlmp_service_to_hint +EXPORT_SYMBOL net/irda/irda 0xe0fa1417 irlmp_data_request +EXPORT_SYMBOL net/irda/irda 0xe4357a0f proc_irda +EXPORT_SYMBOL net/irda/irda 0xe5260e0e irias_add_integer_attrib +EXPORT_SYMBOL net/irda/irda 0xec41fe7f irias_add_string_attrib +EXPORT_SYMBOL net/irda/irda 0xedd521c2 irlmp_get_discoveries +EXPORT_SYMBOL net/lapb/lapb 0x05584f2a lapb_getparms +EXPORT_SYMBOL net/lapb/lapb 0x1d7451d4 lapb_disconnect_request +EXPORT_SYMBOL net/lapb/lapb 0x2359b04e lapb_register +EXPORT_SYMBOL net/lapb/lapb 0x41c430aa lapb_connect_request +EXPORT_SYMBOL net/lapb/lapb 0x63766318 lapb_unregister +EXPORT_SYMBOL net/lapb/lapb 0x84496cc5 lapb_setparms +EXPORT_SYMBOL net/lapb/lapb 0xb8e2dff9 lapb_data_received +EXPORT_SYMBOL net/lapb/lapb 0xe85268db lapb_data_request +EXPORT_SYMBOL net/mac80211/mac80211 0x1e6c8ea4 ieee80211_unregister_hw +EXPORT_SYMBOL net/mac80211/mac80211 0x202664ec ieee80211_rts_duration +EXPORT_SYMBOL net/mac80211/mac80211 0x22413910 ieee80211_ctstoself_get +EXPORT_SYMBOL net/mac80211/mac80211 0x2849a5ce ieee80211_free_hw +EXPORT_SYMBOL net/mac80211/mac80211 0x29632737 __ieee80211_get_rx_led_name +EXPORT_SYMBOL net/mac80211/mac80211 0x3cc6c385 ieee80211_rx_irqsafe +EXPORT_SYMBOL net/mac80211/mac80211 0x3dc3b989 ieee80211_wake_queues +EXPORT_SYMBOL net/mac80211/mac80211 0x47c37e4f ieee80211_stop_tx_ba_cb_irqsafe +EXPORT_SYMBOL net/mac80211/mac80211 0x49ef338b ieee80211_get_hdrlen +EXPORT_SYMBOL net/mac80211/mac80211 0x51d6d5a5 ieee80211_beacon_get +EXPORT_SYMBOL net/mac80211/mac80211 0x56253610 ieee80211_tx_status +EXPORT_SYMBOL net/mac80211/mac80211 0x567ef4cc ieee80211_stop_queue +EXPORT_SYMBOL net/mac80211/mac80211 0x6ddc0fba ieee80211_rate_control_unregister +EXPORT_SYMBOL net/mac80211/mac80211 0x72f9bd88 sta_info_get +EXPORT_SYMBOL net/mac80211/mac80211 0x76f9b9ff ieee80211_start_tx_ba_cb_irqsafe +EXPORT_SYMBOL net/mac80211/mac80211 0x8875cf48 ieee80211_wake_queue +EXPORT_SYMBOL net/mac80211/mac80211 0x8928213a ieee80211_get_hdrlen_from_skb +EXPORT_SYMBOL net/mac80211/mac80211 0x89353a08 ieee80211_tx_status_irqsafe +EXPORT_SYMBOL net/mac80211/mac80211 0x8c35d732 ieee80211_hdrlen +EXPORT_SYMBOL net/mac80211/mac80211 0x90816a3b ieee80211_start_tx_ba_session +EXPORT_SYMBOL net/mac80211/mac80211 0x932ac41f ieee80211_generic_frame_duration +EXPORT_SYMBOL net/mac80211/mac80211 0x9793d408 __ieee80211_rx +EXPORT_SYMBOL net/mac80211/mac80211 0x9f26255f ieee80211_stop_tx_ba_session +EXPORT_SYMBOL net/mac80211/mac80211 0xa1816607 ieee80211_stop_queues +EXPORT_SYMBOL net/mac80211/mac80211 0xa26462a4 __ieee80211_get_radio_led_name +EXPORT_SYMBOL net/mac80211/mac80211 0xb2967d8d ieee80211_register_hw +EXPORT_SYMBOL net/mac80211/mac80211 0xc3ece5c9 ieee80211_ctstoself_duration +EXPORT_SYMBOL net/mac80211/mac80211 0xc4001f78 ieee80211_start_tx_ba_cb +EXPORT_SYMBOL net/mac80211/mac80211 0xc80b9175 ieee80211_rate_control_register +EXPORT_SYMBOL net/mac80211/mac80211 0xcd5a99e1 ieee80211_scan_completed +EXPORT_SYMBOL net/mac80211/mac80211 0xd0feaad1 __ieee80211_get_assoc_led_name +EXPORT_SYMBOL net/mac80211/mac80211 0xd11dc96b __ieee80211_get_tx_led_name +EXPORT_SYMBOL net/mac80211/mac80211 0xd4451b16 ieee80211_get_buffered_bc +EXPORT_SYMBOL net/mac80211/mac80211 0xda68ba85 ieee80211_get_tkip_key +EXPORT_SYMBOL net/mac80211/mac80211 0xe4ae72d8 ieee80211_stop_tx_ba_cb +EXPORT_SYMBOL net/mac80211/mac80211 0xedd80dce ieee80211_alloc_hw +EXPORT_SYMBOL net/mac80211/mac80211 0xee915e66 ieee80211_rts_get +EXPORT_SYMBOL net/mac80211/mac80211 0xff7678f1 ieee80211_notify_mac +EXPORT_SYMBOL net/netfilter/nf_conntrack 0x8fb4ee7a __nf_ct_ext_destroy +EXPORT_SYMBOL net/netfilter/nf_conntrack 0xe372c1b6 __nf_ct_ext_add +EXPORT_SYMBOL net/netfilter/nf_conntrack 0xed23741c per_cpu__nf_conntrack_stat +EXPORT_SYMBOL net/netfilter/nf_conntrack_proto_gre 0x82f94e40 nf_ct_gre_keymap_flush +EXPORT_SYMBOL net/netfilter/x_tables 0x0ce22d7f xt_unregister_matches +EXPORT_SYMBOL net/netfilter/x_tables 0x115bdb59 xt_register_match +EXPORT_SYMBOL net/netfilter/x_tables 0x17f348be xt_register_matches +EXPORT_SYMBOL net/netfilter/x_tables 0x199b8b5a xt_find_match +EXPORT_SYMBOL net/netfilter/x_tables 0x2a017b7d xt_unregister_match +EXPORT_SYMBOL net/netfilter/x_tables 0x3dcd58c5 xt_alloc_table_info +EXPORT_SYMBOL net/netfilter/x_tables 0x61e3a8c8 xt_find_target +EXPORT_SYMBOL net/netfilter/x_tables 0x68b356ec xt_unregister_targets +EXPORT_SYMBOL net/netfilter/x_tables 0xa2d46f13 xt_unregister_target +EXPORT_SYMBOL net/netfilter/x_tables 0xd0e6ea75 xt_register_target +EXPORT_SYMBOL net/netfilter/x_tables 0xef73b569 xt_register_targets +EXPORT_SYMBOL net/netfilter/x_tables 0xf7037dc6 xt_free_table_info +EXPORT_SYMBOL net/rfkill/rfkill 0x00caa4dc rfkill_switch_all +EXPORT_SYMBOL net/rfkill/rfkill 0x39b8d0b4 rfkill_force_state +EXPORT_SYMBOL net/rfkill/rfkill 0x922403d1 rfkill_register +EXPORT_SYMBOL net/rfkill/rfkill 0x970421d5 rfkill_allocate +EXPORT_SYMBOL net/rfkill/rfkill 0xa8ca9fb3 rfkill_free +EXPORT_SYMBOL net/rfkill/rfkill 0xffe113fb rfkill_unregister +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x1bda303a rxrpc_kernel_data_delivered +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x1e050a28 key_type_rxrpc +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x2157c2e9 rxrpc_kernel_end_call +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x2a6985e1 rxrpc_kernel_reject_call +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x3734e657 rxrpc_kernel_get_abort_code +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x42f42197 rxrpc_kernel_is_data_last +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x535d8e53 rxrpc_get_server_data_key +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x8c71d610 rxrpc_kernel_free_skb +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x967cfb8c rxrpc_kernel_intercept_rx_messages +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xae046a2a rxrpc_get_null_key +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xb5c8c320 rxrpc_kernel_abort_call +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xbc6a796d rxrpc_kernel_send_data +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xc19dfdeb rxrpc_kernel_accept_call +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xe05c051e rxrpc_kernel_get_error_number +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xeacf6a81 rxrpc_kernel_begin_call +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x00c52ef5 g_make_token_header +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x0216792c gss_mech_get_by_name +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x19dfee39 gss_svc_to_pseudoflavor +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x44ee4b5b gss_mech_register +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x5aa3ff67 gss_mech_get_by_pseudoflavor +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x8d1a827e svcauth_gss_register_pseudoflavor +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xa5de67ca gss_mech_get +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xb25af472 gss_pseudoflavor_to_service +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xb5dea7ef g_token_size +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xba56b978 gss_mech_put +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xd85a1e88 gss_service_to_auth_domain_name +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xdf39e5cb svcauth_gss_flavor +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xed9de267 gss_mech_unregister +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xf8b2ff6e g_verify_token_header +EXPORT_SYMBOL net/sunrpc/sunrpc 0x05e807a9 xdr_encode_string +EXPORT_SYMBOL net/sunrpc/sunrpc 0x065994f1 xdr_encode_opaque_fixed +EXPORT_SYMBOL net/sunrpc/sunrpc 0x09d32528 xdr_inline_decode +EXPORT_SYMBOL net/sunrpc/sunrpc 0x0eb45819 svc_destroy +EXPORT_SYMBOL net/sunrpc/sunrpc 0x0f668ba9 svc_auth_unregister +EXPORT_SYMBOL net/sunrpc/sunrpc 0x0f94e9fb xdr_init_encode +EXPORT_SYMBOL net/sunrpc/sunrpc 0x10201749 xdr_buf_read_netobj +EXPORT_SYMBOL net/sunrpc/sunrpc 0x103495f6 svc_auth_register +EXPORT_SYMBOL net/sunrpc/sunrpc 0x12e280e3 svc_proc_unregister +EXPORT_SYMBOL net/sunrpc/sunrpc 0x1eee46e1 svc_create +EXPORT_SYMBOL net/sunrpc/sunrpc 0x20c4f49c svc_process +EXPORT_SYMBOL net/sunrpc/sunrpc 0x25e17ced auth_unix_add_addr +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2709c490 xdr_inline_pages +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2805597e xdr_read_pages +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2919b156 xdr_decode_string_inplace +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2c9cbb2e xdr_encode_word +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2eec63c9 xdr_encode_netobj +EXPORT_SYMBOL net/sunrpc/sunrpc 0x30da676f rpc_queue_upcall +EXPORT_SYMBOL net/sunrpc/sunrpc 0x34e53e75 xdr_buf_from_iov +EXPORT_SYMBOL net/sunrpc/sunrpc 0x3b6e7d57 svc_sock_names +EXPORT_SYMBOL net/sunrpc/sunrpc 0x3f8773e9 rpc_mkpipe +EXPORT_SYMBOL net/sunrpc/sunrpc 0x4013b034 cache_register +EXPORT_SYMBOL net/sunrpc/sunrpc 0x447ee341 xdr_write_pages +EXPORT_SYMBOL net/sunrpc/sunrpc 0x52a297bd auth_unix_lookup +EXPORT_SYMBOL net/sunrpc/sunrpc 0x597b1c5d xdr_shift_buf +EXPORT_SYMBOL net/sunrpc/sunrpc 0x5997bf0e unix_domain_find +EXPORT_SYMBOL net/sunrpc/sunrpc 0x5cb64696 svc_prepare_thread +EXPORT_SYMBOL net/sunrpc/sunrpc 0x60792270 cache_unregister +EXPORT_SYMBOL net/sunrpc/sunrpc 0x636e3a0e xdr_process_buf +EXPORT_SYMBOL net/sunrpc/sunrpc 0x639898ad sunrpc_cache_lookup +EXPORT_SYMBOL net/sunrpc/sunrpc 0x6eea229d svcauth_unix_purge +EXPORT_SYMBOL net/sunrpc/sunrpc 0x711cf05b svc_sock_update_bufs +EXPORT_SYMBOL net/sunrpc/sunrpc 0x71fa908a cache_flush +EXPORT_SYMBOL net/sunrpc/sunrpc 0x7417bfeb auth_domain_lookup +EXPORT_SYMBOL net/sunrpc/sunrpc 0x74cc2685 auth_domain_put +EXPORT_SYMBOL net/sunrpc/sunrpc 0x74d7cecb sunrpc_cache_update +EXPORT_SYMBOL net/sunrpc/sunrpc 0x7697c611 svc_exit_thread +EXPORT_SYMBOL net/sunrpc/sunrpc 0x83870535 svc_set_client +EXPORT_SYMBOL net/sunrpc/sunrpc 0x89d9626a svc_seq_show +EXPORT_SYMBOL net/sunrpc/sunrpc 0x8f59b775 read_bytes_from_xdr_buf +EXPORT_SYMBOL net/sunrpc/sunrpc 0x91c0cf27 xdr_init_decode +EXPORT_SYMBOL net/sunrpc/sunrpc 0x95787501 auth_unix_forget_old +EXPORT_SYMBOL net/sunrpc/sunrpc 0x9abf1ac1 svc_proc_register +EXPORT_SYMBOL net/sunrpc/sunrpc 0x9d02d58e rpc_unlink +EXPORT_SYMBOL net/sunrpc/sunrpc 0x9ea98931 xdr_enter_page +EXPORT_SYMBOL net/sunrpc/sunrpc 0xa89a8d7d xdr_decode_array2 +EXPORT_SYMBOL net/sunrpc/sunrpc 0xaf727587 svc_create_pooled +EXPORT_SYMBOL net/sunrpc/sunrpc 0xb64e0a6a xdr_decode_word +EXPORT_SYMBOL net/sunrpc/sunrpc 0xbcec48a9 svc_set_num_threads +EXPORT_SYMBOL net/sunrpc/sunrpc 0xc3880471 xdr_decode_netobj +EXPORT_SYMBOL net/sunrpc/sunrpc 0xc4bccd95 svc_reserve +EXPORT_SYMBOL net/sunrpc/sunrpc 0xc6caf040 xdr_buf_subsegment +EXPORT_SYMBOL net/sunrpc/sunrpc 0xc8e96dea qword_addhex +EXPORT_SYMBOL net/sunrpc/sunrpc 0xc9d73990 svc_drop +EXPORT_SYMBOL net/sunrpc/sunrpc 0xcc1c6233 auth_domain_find +EXPORT_SYMBOL net/sunrpc/sunrpc 0xccc1778e xdr_encode_pages +EXPORT_SYMBOL net/sunrpc/sunrpc 0xd45bc2e5 svcauth_unix_set_client +EXPORT_SYMBOL net/sunrpc/sunrpc 0xd4ffe391 svc_authenticate +EXPORT_SYMBOL net/sunrpc/sunrpc 0xdf927045 xdr_reserve_space +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe1700352 xdr_encode_array2 +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe5919cb1 xdr_encode_opaque +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe74fdbd0 cache_check +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe97f4ce5 qword_get +EXPORT_SYMBOL net/sunrpc/sunrpc 0xeaa75333 svc_wake_up +EXPORT_SYMBOL net/sunrpc/sunrpc 0xedc3058e svc_recv +EXPORT_SYMBOL net/sunrpc/sunrpc 0xedcf6be4 qword_add +EXPORT_SYMBOL net/sunrpc/sunrpc 0xf079be86 cache_purge +EXPORT_SYMBOL net/tipc/tipc 0x08acf310 tipc_available_nodes +EXPORT_SYMBOL net/tipc/tipc 0x0b074a7b tipc_multicast +EXPORT_SYMBOL net/tipc/tipc 0x10d40fcd tipc_isconnected +EXPORT_SYMBOL net/tipc/tipc 0x1472b270 tipc_disconnect +EXPORT_SYMBOL net/tipc/tipc 0x1479cb03 tipc_deleteport +EXPORT_SYMBOL net/tipc/tipc 0x15b5ecde tipc_set_portunreliable +EXPORT_SYMBOL net/tipc/tipc 0x16f27683 tipc_block_bearer +EXPORT_SYMBOL net/tipc/tipc 0x23daecbd tipc_send +EXPORT_SYMBOL net/tipc/tipc 0x259b74f9 tipc_acknowledge +EXPORT_SYMBOL net/tipc/tipc 0x310d1bc9 tipc_detach +EXPORT_SYMBOL net/tipc/tipc 0x316e4054 tipc_send_buf +EXPORT_SYMBOL net/tipc/tipc 0x3712e340 tipc_portunreliable +EXPORT_SYMBOL net/tipc/tipc 0x37bf0dcb tipc_createport +EXPORT_SYMBOL net/tipc/tipc 0x3976041f tipc_set_portimportance +EXPORT_SYMBOL net/tipc/tipc 0x3ab760d5 tipc_reject_msg +EXPORT_SYMBOL net/tipc/tipc 0x419b02fc tipc_send2port +EXPORT_SYMBOL net/tipc/tipc 0x46c3cb95 tipc_send_buf_fast +EXPORT_SYMBOL net/tipc/tipc 0x4b2243c6 tipc_portimportance +EXPORT_SYMBOL net/tipc/tipc 0x538b228a tipc_withdraw +EXPORT_SYMBOL net/tipc/tipc 0x5637ed44 tipc_get_mode +EXPORT_SYMBOL net/tipc/tipc 0x56e52bc1 tipc_continue +EXPORT_SYMBOL net/tipc/tipc 0x5c0d4b5c tipc_ref_valid +EXPORT_SYMBOL net/tipc/tipc 0x62a681a3 tipc_portunreturnable +EXPORT_SYMBOL net/tipc/tipc 0x76bda8d3 tipc_send_buf2name +EXPORT_SYMBOL net/tipc/tipc 0x869b78ef tipc_recv_msg +EXPORT_SYMBOL net/tipc/tipc 0x88b73627 tipc_get_addr +EXPORT_SYMBOL net/tipc/tipc 0x933be652 tipc_send_buf2port +EXPORT_SYMBOL net/tipc/tipc 0x9c45558e tipc_enable_bearer +EXPORT_SYMBOL net/tipc/tipc 0xa1b42d32 tipc_forward2port +EXPORT_SYMBOL net/tipc/tipc 0xa936a24b tipc_get_port +EXPORT_SYMBOL net/tipc/tipc 0xadd203d0 tipc_connect2port +EXPORT_SYMBOL net/tipc/tipc 0xae0103c3 tipc_shutdown +EXPORT_SYMBOL net/tipc/tipc 0xb1f8eacc tipc_send2name +EXPORT_SYMBOL net/tipc/tipc 0xb35b672c tipc_publish +EXPORT_SYMBOL net/tipc/tipc 0xbcb3874d tipc_register_media +EXPORT_SYMBOL net/tipc/tipc 0xc4063085 tipc_forward_buf2name +EXPORT_SYMBOL net/tipc/tipc 0xcec8514a tipc_set_portunreturnable +EXPORT_SYMBOL net/tipc/tipc 0xcee290be tipc_forward2name +EXPORT_SYMBOL net/tipc/tipc 0xd44731e5 tipc_ownidentity +EXPORT_SYMBOL net/tipc/tipc 0xda7f9d3f tipc_attach +EXPORT_SYMBOL net/tipc/tipc 0xdf5008fc tipc_peer +EXPORT_SYMBOL net/tipc/tipc 0xe1a669d5 tipc_forward_buf2port +EXPORT_SYMBOL net/tipc/tipc 0xe7aece47 tipc_ispublished +EXPORT_SYMBOL net/tipc/tipc 0xeacad92e tipc_createport_raw +EXPORT_SYMBOL net/tipc/tipc 0xeefd49b3 tipc_get_handle +EXPORT_SYMBOL net/tipc/tipc 0xef50a1ef tipc_disable_bearer +EXPORT_SYMBOL net/wanrouter/wanrouter 0x0ebe03d1 unregister_wan_device +EXPORT_SYMBOL net/wanrouter/wanrouter 0x7d0e8206 register_wan_device +EXPORT_SYMBOL net/wireless/cfg80211 0x07e7ac5a ieee80211_radiotap_iterator_init +EXPORT_SYMBOL net/wireless/cfg80211 0x09c64fbd ieee80211_frequency_to_channel +EXPORT_SYMBOL net/wireless/cfg80211 0x2acfec9a wiphy_free +EXPORT_SYMBOL net/wireless/cfg80211 0x5b810249 wiphy_unregister +EXPORT_SYMBOL net/wireless/cfg80211 0x679ee52d wiphy_register +EXPORT_SYMBOL net/wireless/cfg80211 0x99d10488 wiphy_new +EXPORT_SYMBOL net/wireless/cfg80211 0xc4e85ec5 ieee80211_radiotap_iterator_next +EXPORT_SYMBOL net/wireless/cfg80211 0xccc291b3 ieee80211_channel_to_frequency +EXPORT_SYMBOL net/wireless/cfg80211 0xef5e4ef4 __ieee80211_get_channel +EXPORT_SYMBOL sound/ac97_bus 0xa370459a ac97_bus_type +EXPORT_SYMBOL sound/core/oss/snd-mixer-oss 0x9a20006c snd_mixer_oss_ioctl_card +EXPORT_SYMBOL sound/core/seq/snd-seq 0x1a724fcc snd_seq_kernel_client_ctl +EXPORT_SYMBOL sound/core/seq/snd-seq 0x3061c52d snd_use_lock_sync_helper +EXPORT_SYMBOL sound/core/seq/snd-seq 0x3fb4d161 snd_seq_kernel_client_dispatch +EXPORT_SYMBOL sound/core/seq/snd-seq 0x6bb71038 snd_seq_delete_kernel_client +EXPORT_SYMBOL sound/core/seq/snd-seq 0x7ac2f329 snd_seq_expand_var_event +EXPORT_SYMBOL sound/core/seq/snd-seq 0x7b8699eb snd_seq_event_port_detach +EXPORT_SYMBOL sound/core/seq/snd-seq 0x89fac170 snd_seq_event_port_attach +EXPORT_SYMBOL sound/core/seq/snd-seq 0xa824614f snd_seq_kernel_client_write_poll +EXPORT_SYMBOL sound/core/seq/snd-seq 0xb8e448a0 snd_seq_set_queue_tempo +EXPORT_SYMBOL sound/core/seq/snd-seq 0xcac0a3be snd_seq_kernel_client_enqueue +EXPORT_SYMBOL sound/core/seq/snd-seq 0xd923bef5 snd_seq_kernel_client_enqueue_blocking +EXPORT_SYMBOL sound/core/seq/snd-seq 0xe8ee99d2 snd_seq_create_kernel_client +EXPORT_SYMBOL sound/core/seq/snd-seq 0xe934da1d snd_seq_dump_var_event +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0x3a57f235 snd_seq_autoload_unlock +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0x3d531a53 snd_seq_device_register_driver +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0x6339b6d0 snd_seq_device_load_drivers +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0xb90668b2 snd_seq_autoload_lock +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0xc622fb29 snd_seq_device_unregister_driver +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0xdf762f15 snd_seq_device_new +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-emul 0x6ea09972 snd_midi_channel_alloc_set +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-emul 0x833a3e07 snd_midi_channel_set_clear +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-emul 0xb9948d2c snd_midi_channel_free_set +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-emul 0xf0a1fdb3 snd_midi_process_event +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x17c15809 snd_midi_event_decode +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x4ad3f518 snd_midi_event_reset_decode +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x62384d3a snd_midi_event_encode +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x8a348811 snd_midi_event_reset_encode +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x9df7af8b snd_midi_event_free +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0xc482499d snd_midi_event_new +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0xd9072e1a snd_midi_event_no_status +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0xe6df29c7 snd_midi_event_encode_byte +EXPORT_SYMBOL sound/core/seq/snd-seq-virmidi 0x653056ef snd_virmidi_new +EXPORT_SYMBOL sound/core/snd 0x1387d4bf snd_cards +EXPORT_SYMBOL sound/core/snd 0x18e1683f snd_dma_program +EXPORT_SYMBOL sound/core/snd 0x191e88cf snd_dma_pointer +EXPORT_SYMBOL sound/core/snd 0x198788b4 snd_lookup_oss_minor_data +EXPORT_SYMBOL sound/core/snd 0x212f08c6 snd_card_free_when_closed +EXPORT_SYMBOL sound/core/snd 0x21c83b7a snd_ctl_remove +EXPORT_SYMBOL sound/core/snd 0x22a92354 snd_card_register +EXPORT_SYMBOL sound/core/snd 0x24a94b26 snd_info_get_line +EXPORT_SYMBOL sound/core/snd 0x25bb2d3b snd_device_new +EXPORT_SYMBOL sound/core/snd 0x2b92b250 snd_seq_root +EXPORT_SYMBOL sound/core/snd 0x319e9bcc snd_ctl_boolean_mono_info +EXPORT_SYMBOL sound/core/snd 0x376e04bf release_and_free_resource +EXPORT_SYMBOL sound/core/snd 0x3971b4df snd_ecards_limit +EXPORT_SYMBOL sound/core/snd 0x3eb94fd0 snd_ctl_find_numid +EXPORT_SYMBOL sound/core/snd 0x3efacc50 snd_ctl_notify +EXPORT_SYMBOL sound/core/snd 0x3f6a3e4a snd_card_file_add +EXPORT_SYMBOL sound/core/snd 0x40a0a0a9 snd_add_device_sysfs_file +EXPORT_SYMBOL sound/core/snd 0x4a3ea5c0 snd_request_card +EXPORT_SYMBOL sound/core/snd 0x4acc7735 snd_ctl_add +EXPORT_SYMBOL sound/core/snd 0x4ca8165a snd_register_device_for_dev +EXPORT_SYMBOL sound/core/snd 0x50b3d6f6 snd_info_create_card_entry +EXPORT_SYMBOL sound/core/snd 0x518bb7f8 copy_from_user_toio +EXPORT_SYMBOL sound/core/snd 0x56c75344 snd_unregister_device +EXPORT_SYMBOL sound/core/snd 0x5bea928a snd_card_free +EXPORT_SYMBOL sound/core/snd 0x5e21c2a5 snd_card_proc_new +EXPORT_SYMBOL sound/core/snd 0x70c15ac1 snd_dma_disable +EXPORT_SYMBOL sound/core/snd 0x725682fb snd_ctl_new1 +EXPORT_SYMBOL sound/core/snd 0x75491c41 snd_card_new +EXPORT_SYMBOL sound/core/snd 0x781921f3 snd_ctl_unregister_ioctl +EXPORT_SYMBOL sound/core/snd 0x7882b674 snd_device_register +EXPORT_SYMBOL sound/core/snd 0x79e802f0 snd_info_create_module_entry +EXPORT_SYMBOL sound/core/snd 0x83dd3f44 snd_ctl_boolean_stereo_info +EXPORT_SYMBOL sound/core/snd 0x8df3789f snd_oss_info_register +EXPORT_SYMBOL sound/core/snd 0x8f595b11 snd_major +EXPORT_SYMBOL sound/core/snd 0x9580466f snd_component_add +EXPORT_SYMBOL sound/core/snd 0x9841887a snd_pci_quirk_lookup +EXPORT_SYMBOL sound/core/snd 0xa23a0df2 snd_mixer_oss_notify_callback +EXPORT_SYMBOL sound/core/snd 0xa4536e8a snd_power_wait +EXPORT_SYMBOL sound/core/snd 0xa7624412 snd_ctl_unregister_ioctl_compat +EXPORT_SYMBOL sound/core/snd 0xa797fd2d snd_ctl_find_id +EXPORT_SYMBOL sound/core/snd 0xa7d10983 snd_card_disconnect +EXPORT_SYMBOL sound/core/snd 0xaa27e543 snd_unregister_oss_device +EXPORT_SYMBOL sound/core/snd 0xb213fe8b snd_info_get_str +EXPORT_SYMBOL sound/core/snd 0xb2e5ae4a snd_lookup_minor_data +EXPORT_SYMBOL sound/core/snd 0xc2083274 snd_card_file_remove +EXPORT_SYMBOL sound/core/snd 0xc4981435 snd_info_free_entry +EXPORT_SYMBOL sound/core/snd 0xcac4d5bc snd_ctl_make_virtual_master +EXPORT_SYMBOL sound/core/snd 0xda520747 snd_ctl_register_ioctl_compat +EXPORT_SYMBOL sound/core/snd 0xe1946b77 snd_ctl_add_slave +EXPORT_SYMBOL sound/core/snd 0xe243dde3 copy_to_user_fromio +EXPORT_SYMBOL sound/core/snd 0xe4854cea snd_iprintf +EXPORT_SYMBOL sound/core/snd 0xeccfb06a snd_ctl_rename_id +EXPORT_SYMBOL sound/core/snd 0xf217c251 snd_ctl_register_ioctl +EXPORT_SYMBOL sound/core/snd 0xf32ce321 snd_register_oss_device +EXPORT_SYMBOL sound/core/snd 0xf7210cf7 snd_ctl_free_one +EXPORT_SYMBOL sound/core/snd 0xf7faccf0 snd_device_free +EXPORT_SYMBOL sound/core/snd 0xfb7b1f5e snd_info_register +EXPORT_SYMBOL sound/core/snd 0xfd38e632 snd_ctl_remove_id +EXPORT_SYMBOL sound/core/snd-hwdep 0x557d3626 snd_hwdep_new +EXPORT_SYMBOL sound/core/snd-page-alloc 0x17e7ccaf snd_dma_alloc_pages_fallback +EXPORT_SYMBOL sound/core/snd-page-alloc 0x19cc2ce3 snd_free_pages +EXPORT_SYMBOL sound/core/snd-page-alloc 0x682905e9 snd_dma_alloc_pages +EXPORT_SYMBOL sound/core/snd-page-alloc 0x7b7daac3 snd_dma_reserve_buf +EXPORT_SYMBOL sound/core/snd-page-alloc 0x929f75da snd_dma_get_reserved_buf +EXPORT_SYMBOL sound/core/snd-page-alloc 0x97070bfa snd_dma_free_pages +EXPORT_SYMBOL sound/core/snd-page-alloc 0xc6829020 snd_malloc_pages +EXPORT_SYMBOL sound/core/snd-pcm 0x04cda566 snd_interval_refine +EXPORT_SYMBOL sound/core/snd-pcm 0x11814411 snd_pcm_lib_ioctl +EXPORT_SYMBOL sound/core/snd-pcm 0x1d027e4b snd_pcm_format_signed +EXPORT_SYMBOL sound/core/snd-pcm 0x2034d2e3 snd_pcm_lib_writev +EXPORT_SYMBOL sound/core/snd-pcm 0x219d20c7 snd_pcm_mmap_data +EXPORT_SYMBOL sound/core/snd-pcm 0x22f48703 snd_pcm_hw_constraint_list +EXPORT_SYMBOL sound/core/snd-pcm 0x230cc1d0 snd_pcm_hw_rule_add +EXPORT_SYMBOL sound/core/snd-pcm 0x3017b209 snd_pcm_lib_preallocate_pages_for_all +EXPORT_SYMBOL sound/core/snd-pcm 0x32abb656 snd_pcm_release_substream +EXPORT_SYMBOL sound/core/snd-pcm 0x3796bdcc snd_pcm_format_little_endian +EXPORT_SYMBOL sound/core/snd-pcm 0x419223d6 snd_pcm_new_stream +EXPORT_SYMBOL sound/core/snd-pcm 0x4dec81c7 snd_pcm_lib_read +EXPORT_SYMBOL sound/core/snd-pcm 0x4f816e9b snd_pcm_format_big_endian +EXPORT_SYMBOL sound/core/snd-pcm 0x55bd9ee4 snd_pcm_hw_constraint_integer +EXPORT_SYMBOL sound/core/snd-pcm 0x590bef13 snd_pcm_lib_write +EXPORT_SYMBOL sound/core/snd-pcm 0x5e7f4920 snd_pcm_format_set_silence +EXPORT_SYMBOL sound/core/snd-pcm 0x604bb022 snd_pcm_new +EXPORT_SYMBOL sound/core/snd-pcm 0x650f8603 snd_pcm_format_silence_64 +EXPORT_SYMBOL sound/core/snd-pcm 0x68a24153 snd_pcm_format_physical_width +EXPORT_SYMBOL sound/core/snd-pcm 0x69a1808a snd_pcm_lib_readv +EXPORT_SYMBOL sound/core/snd-pcm 0x6adb5b33 snd_pcm_lib_preallocate_pages +EXPORT_SYMBOL sound/core/snd-pcm 0x6ef8fcd8 snd_pcm_format_linear +EXPORT_SYMBOL sound/core/snd-pcm 0x7c5cec98 _snd_pcm_hw_params_any +EXPORT_SYMBOL sound/core/snd-pcm 0x7cacad1a snd_pcm_period_elapsed +EXPORT_SYMBOL sound/core/snd-pcm 0x814bcfe3 snd_pcm_open_substream +EXPORT_SYMBOL sound/core/snd-pcm 0x88cc66cc snd_pcm_link_rwlock +EXPORT_SYMBOL sound/core/snd-pcm 0x89a31a56 _snd_pcm_hw_param_setempty +EXPORT_SYMBOL sound/core/snd-pcm 0x90df90da snd_pcm_lib_malloc_pages +EXPORT_SYMBOL sound/core/snd-pcm 0x96aff3f2 snd_pcm_stop +EXPORT_SYMBOL sound/core/snd-pcm 0x9d9aa8ad snd_pcm_hw_constraint_ratnums +EXPORT_SYMBOL sound/core/snd-pcm 0x9fab36e6 snd_pcm_lib_preallocate_free_for_all +EXPORT_SYMBOL sound/core/snd-pcm 0x9fdea959 snd_pcm_hw_param_value +EXPORT_SYMBOL sound/core/snd-pcm 0xa61aa028 snd_pcm_format_unsigned +EXPORT_SYMBOL sound/core/snd-pcm 0xa6447c5f snd_pcm_limit_hw_rates +EXPORT_SYMBOL sound/core/snd-pcm 0xae735b37 snd_pcm_hw_param_last +EXPORT_SYMBOL sound/core/snd-pcm 0xb05f6e32 snd_pcm_hw_constraint_step +EXPORT_SYMBOL sound/core/snd-pcm 0xb7d09867 snd_pcm_notify +EXPORT_SYMBOL sound/core/snd-pcm 0xb9638db4 snd_pcm_rate_to_rate_bit +EXPORT_SYMBOL sound/core/snd-pcm 0xbb1bba41 snd_pcm_hw_refine +EXPORT_SYMBOL sound/core/snd-pcm 0xbe6eee61 snd_pcm_kernel_ioctl +EXPORT_SYMBOL sound/core/snd-pcm 0xc824e424 snd_pcm_hw_constraint_pow2 +EXPORT_SYMBOL sound/core/snd-pcm 0xcc1ff2fd snd_pcm_hw_constraint_minmax +EXPORT_SYMBOL sound/core/snd-pcm 0xcd3a1641 snd_pcm_hw_constraint_msbits +EXPORT_SYMBOL sound/core/snd-pcm 0xd0b9b8b8 snd_interval_list +EXPORT_SYMBOL sound/core/snd-pcm 0xd17061ee snd_pcm_set_ops +EXPORT_SYMBOL sound/core/snd-pcm 0xd2360740 snd_pcm_lib_free_pages +EXPORT_SYMBOL sound/core/snd-pcm 0xdaf11552 snd_pcm_sgbuf_ops_page +EXPORT_SYMBOL sound/core/snd-pcm 0xe1f8f90e snd_pcm_set_sync +EXPORT_SYMBOL sound/core/snd-pcm 0xe3470731 snd_pcm_suspend_all +EXPORT_SYMBOL sound/core/snd-pcm 0xe51a1c64 snd_pcm_format_size +EXPORT_SYMBOL sound/core/snd-pcm 0xe56a9336 snd_pcm_format_width +EXPORT_SYMBOL sound/core/snd-pcm 0xe60a2685 snd_pcm_lib_mmap_iomem +EXPORT_SYMBOL sound/core/snd-pcm 0xe9709ffa snd_pcm_hw_constraint_ratdens +EXPORT_SYMBOL sound/core/snd-pcm 0xee0b2970 snd_pcm_hw_param_first +EXPORT_SYMBOL sound/core/snd-pcm 0xf3797152 snd_interval_ratnum +EXPORT_SYMBOL sound/core/snd-pcm 0xfa95a11c snd_pcm_suspend +EXPORT_SYMBOL sound/core/snd-rawmidi 0x02d0f1a2 snd_rawmidi_kernel_release +EXPORT_SYMBOL sound/core/snd-rawmidi 0x1f6876df snd_rawmidi_receive +EXPORT_SYMBOL sound/core/snd-rawmidi 0x28486578 snd_rawmidi_transmit_ack +EXPORT_SYMBOL sound/core/snd-rawmidi 0x30cdc654 snd_rawmidi_kernel_read +EXPORT_SYMBOL sound/core/snd-rawmidi 0x4483d190 snd_rawmidi_drop_output +EXPORT_SYMBOL sound/core/snd-rawmidi 0x48fd026e snd_rawmidi_kernel_write +EXPORT_SYMBOL sound/core/snd-rawmidi 0x533f315a snd_rawmidi_drain_output +EXPORT_SYMBOL sound/core/snd-rawmidi 0x5e384a22 snd_rawmidi_kernel_open +EXPORT_SYMBOL sound/core/snd-rawmidi 0x6eb81689 snd_rawmidi_output_params +EXPORT_SYMBOL sound/core/snd-rawmidi 0x71013eef snd_rawmidi_transmit +EXPORT_SYMBOL sound/core/snd-rawmidi 0x773b69ab snd_rawmidi_drain_input +EXPORT_SYMBOL sound/core/snd-rawmidi 0x8afc6738 snd_rawmidi_transmit_peek +EXPORT_SYMBOL sound/core/snd-rawmidi 0xb8b266bc snd_rawmidi_info_select +EXPORT_SYMBOL sound/core/snd-rawmidi 0xbe407d25 snd_rawmidi_new +EXPORT_SYMBOL sound/core/snd-rawmidi 0xdc05e13b snd_rawmidi_input_params +EXPORT_SYMBOL sound/core/snd-rawmidi 0xea81d5f8 snd_rawmidi_set_ops +EXPORT_SYMBOL sound/core/snd-rawmidi 0xfc7a9780 snd_rawmidi_transmit_empty +EXPORT_SYMBOL sound/core/snd-timer 0x122adcaf snd_timer_stop +EXPORT_SYMBOL sound/core/snd-timer 0x23a41857 snd_timer_continue +EXPORT_SYMBOL sound/core/snd-timer 0x2466d595 snd_timer_global_new +EXPORT_SYMBOL sound/core/snd-timer 0x36f772b1 snd_timer_new +EXPORT_SYMBOL sound/core/snd-timer 0x5515f577 snd_timer_close +EXPORT_SYMBOL sound/core/snd-timer 0x5f4517a7 snd_timer_start +EXPORT_SYMBOL sound/core/snd-timer 0x7d731a6b snd_timer_pause +EXPORT_SYMBOL sound/core/snd-timer 0x9d54f7ff snd_timer_interrupt +EXPORT_SYMBOL sound/core/snd-timer 0xc7d2647a snd_timer_global_free +EXPORT_SYMBOL sound/core/snd-timer 0xceb386f4 snd_timer_global_register +EXPORT_SYMBOL sound/core/snd-timer 0xd2986cf6 snd_timer_open +EXPORT_SYMBOL sound/core/snd-timer 0xdcb1846a snd_timer_resolution +EXPORT_SYMBOL sound/core/snd-timer 0xf2605655 snd_timer_notify +EXPORT_SYMBOL sound/drivers/mpu401/snd-mpu401-uart 0x73c4c993 snd_mpu401_uart_interrupt_tx +EXPORT_SYMBOL sound/drivers/mpu401/snd-mpu401-uart 0x99600858 snd_mpu401_uart_new +EXPORT_SYMBOL sound/drivers/mpu401/snd-mpu401-uart 0xfe618b58 snd_mpu401_uart_interrupt +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x05060a19 snd_opl3_regmap +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x297ec2fe snd_opl3_find_patch +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x36d3e101 snd_opl3_init +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x48dba016 snd_opl3_hwdep_new +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x6280aedb snd_opl3_reset +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x79560ed7 snd_opl3_timer_new +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x985efecb snd_opl3_new +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0xa11ef2e5 snd_opl3_interrupt +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0xb44de9ea snd_opl3_create +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0xcb162c71 snd_opl3_load_patch +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x107f396b snd_vx_setup_firmware +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x1cadb14b snd_vx_irq_handler +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x3e4d6ff7 snd_vx_check_reg_bit +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x45313d7f snd_vx_resume +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x7e8524c5 snd_vx_load_boot_image +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x88278c6c snd_vx_dsp_load +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x954bbbec snd_vx_create +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0xb461e805 snd_vx_free_firmware +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0xbeb6db69 snd_vx_dsp_boot +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0xf8af6fd7 snd_vx_suspend +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0x17745d0c snd_ak4114_create +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0x3982bc5d snd_ak4114_external_rate +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0x65c2a196 snd_ak4114_check_rate_and_errors +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0xd272e922 snd_ak4114_reinit +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0xd9b16369 snd_ak4114_build +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0xe9f2a7c2 snd_ak4114_reg_write +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x05217f6b snd_ak4117_external_rate +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x1397a08e snd_ak4117_create +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x273d9177 snd_ak4117_check_rate_and_errors +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x73e13e28 snd_ak4117_reinit +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x950ee747 snd_ak4117_reg_write +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0xc8365e9a snd_ak4117_build +EXPORT_SYMBOL sound/i2c/other/snd-ak4xxx-adda 0xb116186b snd_akm4xxx_write +EXPORT_SYMBOL sound/i2c/other/snd-ak4xxx-adda 0xca520655 snd_akm4xxx_build_controls +EXPORT_SYMBOL sound/i2c/other/snd-ak4xxx-adda 0xda4ff4d1 snd_akm4xxx_reset +EXPORT_SYMBOL sound/i2c/other/snd-ak4xxx-adda 0xe41a7689 snd_akm4xxx_init +EXPORT_SYMBOL sound/i2c/other/snd-pt2258 0x287e85da snd_pt2258_reset +EXPORT_SYMBOL sound/i2c/other/snd-pt2258 0x4a3f2cd3 snd_pt2258_build_controls +EXPORT_SYMBOL sound/i2c/other/snd-tea575x-tuner 0x7a7222b8 snd_tea575x_exit +EXPORT_SYMBOL sound/i2c/other/snd-tea575x-tuner 0x7bef8a89 snd_tea575x_init +EXPORT_SYMBOL sound/i2c/snd-cs8427 0x07faf2f0 snd_cs8427_create +EXPORT_SYMBOL sound/i2c/snd-cs8427 0x112d0ac9 snd_cs8427_iec958_build +EXPORT_SYMBOL sound/i2c/snd-cs8427 0xe1bdf340 snd_cs8427_iec958_pcm +EXPORT_SYMBOL sound/i2c/snd-cs8427 0xf06114b8 snd_cs8427_reg_write +EXPORT_SYMBOL sound/i2c/snd-cs8427 0xfcf31b72 snd_cs8427_iec958_active +EXPORT_SYMBOL sound/i2c/snd-i2c 0x23e46169 snd_i2c_device_free +EXPORT_SYMBOL sound/i2c/snd-i2c 0x7d889dd7 snd_i2c_probeaddr +EXPORT_SYMBOL sound/i2c/snd-i2c 0x8c0150d2 snd_i2c_readbytes +EXPORT_SYMBOL sound/i2c/snd-i2c 0x96494d19 snd_i2c_sendbytes +EXPORT_SYMBOL sound/i2c/snd-i2c 0xa3e097d3 snd_i2c_device_create +EXPORT_SYMBOL sound/i2c/snd-i2c 0xfbfa6fc6 snd_i2c_bus_create +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x18181560 snd_sbmixer_new +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x223553f9 snd_sbdsp_create +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x248154cf snd_sbmixer_resume +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x4fbb6deb snd_sbmixer_suspend +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x504922bd snd_sbmixer_write +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xc29ac229 snd_sbmixer_add_ctl +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xcf979c88 snd_sbmixer_read +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xdc8cfbd5 snd_sbdsp_command +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xe943dae6 snd_sbdsp_get_byte +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xf130d7b2 snd_sbdsp_reset +EXPORT_SYMBOL sound/isa/sb/snd-sb16-dsp 0x0ba4ef1d snd_sb16dsp_interrupt +EXPORT_SYMBOL sound/isa/sb/snd-sb16-dsp 0x4c9e673e snd_sb16dsp_get_pcm_ops +EXPORT_SYMBOL sound/isa/sb/snd-sb16-dsp 0xb14cbadb snd_sb16dsp_configure +EXPORT_SYMBOL sound/isa/sb/snd-sb16-dsp 0xc45c9264 snd_sb16dsp_pcm +EXPORT_SYMBOL sound/oss/ad1848 0x9839a618 probe_ms_sound +EXPORT_SYMBOL sound/oss/ad1848 0x9bf1cc62 ad1848_unload +EXPORT_SYMBOL sound/oss/ad1848 0xb29a9148 unload_ms_sound +EXPORT_SYMBOL sound/oss/ad1848 0xc04f6f67 ad1848_control +EXPORT_SYMBOL sound/oss/ad1848 0xcb2840df attach_ms_sound +EXPORT_SYMBOL sound/oss/ad1848 0xf06eb004 ad1848_detect +EXPORT_SYMBOL sound/oss/ad1848 0xf46156f7 ad1848_init +EXPORT_SYMBOL sound/oss/mpu401 0x5febf284 unload_mpu401 +EXPORT_SYMBOL sound/oss/mpu401 0x8874e39a probe_mpu401 +EXPORT_SYMBOL sound/oss/mpu401 0xdb3d1f19 attach_mpu401 +EXPORT_SYMBOL sound/oss/sb_lib 0x42424109 sb_be_quiet +EXPORT_SYMBOL sound/oss/sb_lib 0x450f9aea smw_free +EXPORT_SYMBOL sound/oss/sb_lib 0x74afd69c unload_sbmpu +EXPORT_SYMBOL sound/oss/sb_lib 0x807e7c9b sb_dsp_init +EXPORT_SYMBOL sound/oss/sb_lib 0xbe235dd7 probe_sbmpu +EXPORT_SYMBOL sound/oss/sb_lib 0xc4884969 sb_dsp_unload +EXPORT_SYMBOL sound/oss/sb_lib 0xd8a2731c sb_dsp_detect +EXPORT_SYMBOL sound/oss/sound 0x04c87ec8 compute_finetune +EXPORT_SYMBOL sound/oss/sound 0x06339815 sound_unload_synthdev +EXPORT_SYMBOL sound/oss/sound 0x0f280035 conf_printf +EXPORT_SYMBOL sound/oss/sound 0x17ba231d seq_input_event +EXPORT_SYMBOL sound/oss/sound 0x1b3df3cf sound_alloc_mixerdev +EXPORT_SYMBOL sound/oss/sound 0x1f395686 MIDIbuf_avail +EXPORT_SYMBOL sound/oss/sound 0x2161d5e8 sound_timer_init +EXPORT_SYMBOL sound/oss/sound 0x2aa31695 midi_synth_kill_note +EXPORT_SYMBOL sound/oss/sound 0x394cb088 sound_free_dma +EXPORT_SYMBOL sound/oss/sound 0x3beaaf1c sound_install_audiodrv +EXPORT_SYMBOL sound/oss/sound 0x418f5fbe sound_close_dma +EXPORT_SYMBOL sound/oss/sound 0x4cd01bdd num_audiodevs +EXPORT_SYMBOL sound/oss/sound 0x4ff47e9d midi_synth_setup_voice +EXPORT_SYMBOL sound/oss/sound 0x51e354b2 sound_alloc_timerdev +EXPORT_SYMBOL sound/oss/sound 0x526729c4 sound_timer_devs +EXPORT_SYMBOL sound/oss/sound 0x56504ca2 midi_synth_reset +EXPORT_SYMBOL sound/oss/sound 0x5d986fc9 note_to_freq +EXPORT_SYMBOL sound/oss/sound 0x5dc6b350 synth_devs +EXPORT_SYMBOL sound/oss/sound 0x7679ee76 seq_copy_to_input +EXPORT_SYMBOL sound/oss/sound 0x7bdf0907 conf_printf2 +EXPORT_SYMBOL sound/oss/sound 0x892093e0 midi_synth_controller +EXPORT_SYMBOL sound/oss/sound 0x90bd9714 sequencer_timer +EXPORT_SYMBOL sound/oss/sound 0x987bcf12 DMAbuf_outputintr +EXPORT_SYMBOL sound/oss/sound 0x9a95733f sound_alloc_dma +EXPORT_SYMBOL sound/oss/sound 0x9bdaf24d midi_synth_start_note +EXPORT_SYMBOL sound/oss/sound 0x9d845b18 num_mixers +EXPORT_SYMBOL sound/oss/sound 0xa1d5f04f load_mixer_volumes +EXPORT_SYMBOL sound/oss/sound 0xa1eae7cf num_midis +EXPORT_SYMBOL sound/oss/sound 0xa41ead5f sound_unload_timerdev +EXPORT_SYMBOL sound/oss/sound 0xa51c913b sound_unload_mixerdev +EXPORT_SYMBOL sound/oss/sound 0xa6bb414c sound_unload_mididev +EXPORT_SYMBOL sound/oss/sound 0xa948751e sound_unload_audiodev +EXPORT_SYMBOL sound/oss/sound 0xad45df73 midi_synth_close +EXPORT_SYMBOL sound/oss/sound 0xaef743b2 midi_synth_ioctl +EXPORT_SYMBOL sound/oss/sound 0xb062dcd5 midi_devs +EXPORT_SYMBOL sound/oss/sound 0xb14b22cd midi_synth_hw_control +EXPORT_SYMBOL sound/oss/sound 0xb51587f6 do_midi_msg +EXPORT_SYMBOL sound/oss/sound 0xba413f87 sound_alloc_mididev +EXPORT_SYMBOL sound/oss/sound 0xba7dd041 midi_synth_bender +EXPORT_SYMBOL sound/oss/sound 0xc664d1de mixer_devs +EXPORT_SYMBOL sound/oss/sound 0xc748d109 sound_alloc_synthdev +EXPORT_SYMBOL sound/oss/sound 0xcc4b8797 sound_open_dma +EXPORT_SYMBOL sound/oss/sound 0xd85be938 midi_synth_set_instr +EXPORT_SYMBOL sound/oss/sound 0xdb400afa midi_synth_panning +EXPORT_SYMBOL sound/oss/sound 0xe056b71c DMAbuf_start_dma +EXPORT_SYMBOL sound/oss/sound 0xe1f31a35 audio_devs +EXPORT_SYMBOL sound/oss/sound 0xe2675a79 sound_timer_interrupt +EXPORT_SYMBOL sound/oss/sound 0xe3dab76c sound_install_mixer +EXPORT_SYMBOL sound/oss/sound 0xeb315d99 DMAbuf_inputintr +EXPORT_SYMBOL sound/oss/sound 0xf1ea8a20 midi_synth_aftertouch +EXPORT_SYMBOL sound/oss/sound 0xf6b3a2fb midi_synth_open +EXPORT_SYMBOL sound/oss/sound 0xf7426da3 midi_synth_load_patch +EXPORT_SYMBOL sound/oss/sound 0xf78f6363 sequencer_init +EXPORT_SYMBOL sound/oss/sound 0xfa6871be sound_timer_syncinterval +EXPORT_SYMBOL sound/oss/sound 0xfddcbfb3 midi_synth_send_sysex +EXPORT_SYMBOL sound/oss/uart401 0x46248c57 uart401intr +EXPORT_SYMBOL sound/oss/uart401 0xe3882365 probe_uart401 +EXPORT_SYMBOL sound/oss/uart401 0xecfdd9c9 unload_uart401 +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x0a108780 snd_ac97_tune_hardware +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x1ff92794 snd_ac97_bus +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x26b9e789 snd_ac97_pcm_close +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x2e44d586 snd_ac97_set_rate +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x30d83c92 snd_ac97_suspend +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x3c2e4fa7 snd_ac97_write +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x3cea8f9f snd_ac97_pcm_double_rate_rules +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x5a37de37 snd_ac97_resume +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x7d3f4ae4 snd_ac97_mixer +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x81662dd5 snd_ac97_write_cache +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x8c699689 snd_ac97_pcm_open +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x9ae7600e snd_ac97_pcm_assign +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x9dce93a2 snd_ac97_update_bits +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x9fe13a39 snd_ac97_get_short_name +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xc01b7344 snd_ac97_update_power +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xd6dd12d4 snd_ac97_read +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xeefb6e21 snd_ac97_update +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x038c8c67 snd_emu10k1_ptr_write +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x0cc13e50 snd_emu10k1_voice_alloc +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x1d48037d snd_emu10k1_synth_free +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x48c1abd0 snd_emu10k1_ptr_read +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x6689877f snd_emu10k1_voice_free +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x6de30db0 snd_emu10k1_memblk_map +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x72c1537a snd_emu10k1_synth_bzero +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x9be25b72 snd_emu10k1_synth_alloc +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0xc8c0a4f1 snd_emu10k1_synth_copy_from_user +EXPORT_SYMBOL sound/pci/ice1712/snd-ice17xx-ak4xxx 0x8569c46e snd_ice1712_akm4xxx_build_controls +EXPORT_SYMBOL sound/pci/ice1712/snd-ice17xx-ak4xxx 0xa5046fb4 snd_ice1712_akm4xxx_free +EXPORT_SYMBOL sound/pci/ice1712/snd-ice17xx-ak4xxx 0xbe5523b2 snd_ice1712_akm4xxx_init +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x07a5b026 oxygen_read_ac97 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x0fe1d3c3 oxygen_write_spi +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x271f12ec oxygen_write8_masked +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x2b4c9197 oxygen_write_ac97_masked +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x396c9328 oxygen_write_i2c +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x47a908be oxygen_write_ac97 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x4c6ce0a6 oxygen_pci_suspend +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x6e3c34df oxygen_read32 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x82b67ef5 oxygen_read8 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x8303562a oxygen_pci_remove +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x8c929c8f oxygen_read16 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xa61bd30d oxygen_write16_masked +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xb9cd989e oxygen_write8 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xbe701bc0 oxygen_pci_resume +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xc4cda6f7 oxygen_pci_probe +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xc6f271f5 oxygen_write32 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xeaf2c85a oxygen_write16 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xfca07931 oxygen_write32_masked +EXPORT_SYMBOL sound/pci/trident/snd-trident 0x40412c50 snd_trident_free_voice +EXPORT_SYMBOL sound/pci/trident/snd-trident 0x6c52647b snd_trident_stop_voice +EXPORT_SYMBOL sound/pci/trident/snd-trident 0x8d40a9a0 snd_trident_start_voice +EXPORT_SYMBOL sound/pci/trident/snd-trident 0x9e8ba6f3 snd_trident_alloc_voice +EXPORT_SYMBOL sound/pci/trident/snd-trident 0xd1f7e15c snd_trident_write_voice_regs +EXPORT_SYMBOL sound/sound_firmware 0x39e3dd23 mod_firmware_load +EXPORT_SYMBOL sound/soundcore 0x348d7b76 register_sound_special +EXPORT_SYMBOL sound/soundcore 0x3daf3c9a sound_class +EXPORT_SYMBOL sound/soundcore 0x5d7ea562 register_sound_special_device +EXPORT_SYMBOL sound/soundcore 0x7afc9d8a unregister_sound_mixer +EXPORT_SYMBOL sound/soundcore 0x8d95780d register_sound_mixer +EXPORT_SYMBOL sound/soundcore 0x99c95fa5 unregister_sound_special +EXPORT_SYMBOL sound/soundcore 0x9edb9010 register_sound_dsp +EXPORT_SYMBOL sound/soundcore 0xcd083b10 unregister_sound_dsp +EXPORT_SYMBOL sound/soundcore 0xfad30795 register_sound_midi +EXPORT_SYMBOL sound/soundcore 0xfdab6de3 unregister_sound_midi +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x23c52470 snd_emux_free +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x38d88440 snd_emux_register +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x5862b758 snd_emux_terminate_all +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x655cb202 snd_sf_linear_to_log +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x797bbafb snd_emux_lock_voice +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x95a80c15 snd_emux_new +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0xf4b6afd4 snd_emux_unlock_voice +EXPORT_SYMBOL sound/synth/snd-util-mem 0x20d65978 snd_util_memhdr_free +EXPORT_SYMBOL sound/synth/snd-util-mem 0x24886293 __snd_util_mem_alloc +EXPORT_SYMBOL sound/synth/snd-util-mem 0x569d614e snd_util_mem_free +EXPORT_SYMBOL sound/synth/snd-util-mem 0x7a007343 snd_util_memhdr_new +EXPORT_SYMBOL sound/synth/snd-util-mem 0xd197c5db __snd_util_memblk_new +EXPORT_SYMBOL sound/synth/snd-util-mem 0xd34b56e4 __snd_util_mem_free +EXPORT_SYMBOL sound/synth/snd-util-mem 0xd8b55e81 snd_util_mem_alloc +EXPORT_SYMBOL sound/synth/snd-util-mem 0xf158252c snd_util_mem_avail +EXPORT_SYMBOL sound/usb/snd-usb-lib 0x16756dc0 snd_usbmidi_input_start +EXPORT_SYMBOL sound/usb/snd-usb-lib 0x63343b1d snd_usbmidi_input_stop +EXPORT_SYMBOL sound/usb/snd-usb-lib 0xa3797b40 snd_usb_create_midi_interface +EXPORT_SYMBOL sound/usb/snd-usb-lib 0xd9d2bb03 snd_usbmidi_disconnect +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0x24acbe54 dm_mem_cache_alloc +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0x42fa8172 dm_mem_cache_client_create +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0x4b8f3a66 dm_mem_cache_shrink +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0x591aaba0 dm_mem_cache_free +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0x6b263368 dm_mem_cache_grow +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0xa055161f dm_mem_cache_client_destroy +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-message 0x920a7a41 dm_message_parse +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x0050f52c rh_get_region_key +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x216444e0 rh_delay_by_region +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x275fdd04 rh_recovery_start +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x28b7e0fe rh_init +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x29e53a6b rh_dec +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x50a4e06e rh_inc_pending +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x5c2a0632 rh_recovery_end +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x62842029 rh_flush +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x83baca27 rh_state +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x87d45b9d rh_get_region_size +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xa923d788 rh_start_recovery +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xac274ed3 rh_stop_recovery +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xb513be98 rh_update_states +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xbb748327 rh_reg_set_context +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xbd3452f9 rh_sector_to_region +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xc4fdf256 rh_recovery_prepare +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xc4ff7745 rh_reg_get_context +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xc57bafec rh_exit +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xca70f3e5 rh_delay +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xe9f7f71a rh_region_to_sector +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xf3e0a2b0 rh_inc +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xf684a160 rh_bio_to_region +EXPORT_SYMBOL ubuntu/lirc/lirc_cmdir/commandir 0x29c887a9 set_tx_channels +EXPORT_SYMBOL ubuntu/lirc/lirc_cmdir/commandir 0x7789312a cmdir_write +EXPORT_SYMBOL ubuntu/lirc/lirc_cmdir/commandir 0xf4c689aa cmdir_read +EXPORT_SYMBOL ubuntu/lirc/lirc_dev/lirc_dev 0x0d00d112 lirc_register_plugin +EXPORT_SYMBOL ubuntu/lirc/lirc_dev/lirc_dev 0xb52dbac8 lirc_get_pdata +EXPORT_SYMBOL ubuntu/lirc/lirc_dev/lirc_dev 0xe96379eb lirc_unregister_plugin +EXPORT_SYMBOL ubuntu/misc/media/ov511/ov511 0x2763a531 ov511_register_decomp_module +EXPORT_SYMBOL ubuntu/misc/media/ov511/ov511 0x7db9be3c ov511_deregister_decomp_module +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x57eedff0 p80211netdev_rx +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x5b8fc410 p80211skb_rxmeta_attach +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x5d19cd19 unregister_wlandev +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x6555baed wlan_unsetup +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x75578f8d register_wlandev +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x78595066 wlan_setup +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x843509f3 p80211_allow_ioctls +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x9322444f p80211_suspend +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x9784a64d p80211netdev_hwremoved +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xb0af0799 wlan_wext_write +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xbdfb5ac7 p80211skb_free +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xc1862c0b p80211wext_event_associated +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xe841ff8d p80211_resume +EXPORT_SYMBOL vmlinux 0x001d2a83 mark_info_dirty +EXPORT_SYMBOL vmlinux 0x001f43a6 blk_queue_hardsect_size +EXPORT_SYMBOL vmlinux 0x004551f5 tcf_em_register +EXPORT_SYMBOL vmlinux 0x005227a0 bio_map_user +EXPORT_SYMBOL vmlinux 0x005e1445 lock_may_write +EXPORT_SYMBOL vmlinux 0x00801678 flush_scheduled_work +EXPORT_SYMBOL vmlinux 0x0080fcd6 tcf_hash_release +EXPORT_SYMBOL vmlinux 0x008fe885 d_alloc_root +EXPORT_SYMBOL vmlinux 0x009d258f _write_lock +EXPORT_SYMBOL vmlinux 0x00a0b113 pci_disable_msix +EXPORT_SYMBOL vmlinux 0x01000e51 schedule +EXPORT_SYMBOL vmlinux 0x013cc82b agp_create_memory +EXPORT_SYMBOL vmlinux 0x014f69b1 submit_bh +EXPORT_SYMBOL vmlinux 0x01522a16 register_framebuffer +EXPORT_SYMBOL vmlinux 0x015af241 blk_remove_plug +EXPORT_SYMBOL vmlinux 0x0186d073 percpu_counter_set +EXPORT_SYMBOL vmlinux 0x01902adf netpoll_trap +EXPORT_SYMBOL vmlinux 0x01a4aab6 set_irq_chip_data +EXPORT_SYMBOL vmlinux 0x01a95de9 get_unmapped_area +EXPORT_SYMBOL vmlinux 0x01d19038 acpi_enable_subsystem +EXPORT_SYMBOL vmlinux 0x01fff936 posix_test_lock +EXPORT_SYMBOL vmlinux 0x02124474 ip_send_check +EXPORT_SYMBOL vmlinux 0x02138f9d bioset_integrity_create +EXPORT_SYMBOL vmlinux 0x0215fbf5 ip4_datagram_connect +EXPORT_SYMBOL vmlinux 0x0227c66a uart_match_port +EXPORT_SYMBOL vmlinux 0x0237b57a arch_unregister_cpu +EXPORT_SYMBOL vmlinux 0x0256389f bit_waitqueue +EXPORT_SYMBOL vmlinux 0x02649054 security_sock_rcv_skb +EXPORT_SYMBOL vmlinux 0x02724ca8 skb_queue_tail +EXPORT_SYMBOL vmlinux 0x027a6079 open_exec +EXPORT_SYMBOL vmlinux 0x029444f0 native_read_tsc +EXPORT_SYMBOL vmlinux 0x02a18c74 nf_conntrack_destroy +EXPORT_SYMBOL vmlinux 0x02aff2f4 acpi_install_gpe_handler +EXPORT_SYMBOL vmlinux 0x02b59c84 neigh_seq_next +EXPORT_SYMBOL vmlinux 0x02d81845 audit_log_task_context +EXPORT_SYMBOL vmlinux 0x02e84d1b per_cpu__cpu_sibling_map +EXPORT_SYMBOL vmlinux 0x02fbe442 dma_async_client_chan_request +EXPORT_SYMBOL vmlinux 0x03072b5c ip_route_input +EXPORT_SYMBOL vmlinux 0x0334da4e scsi_command_size_tbl +EXPORT_SYMBOL vmlinux 0x037a0cba kfree +EXPORT_SYMBOL vmlinux 0x03a25444 bio_integrity_tag_size +EXPORT_SYMBOL vmlinux 0x03a99c3b rb_prev +EXPORT_SYMBOL vmlinux 0x03c06156 bitmap_fold +EXPORT_SYMBOL vmlinux 0x03c471ee qdisc_list_del +EXPORT_SYMBOL vmlinux 0x03c6abb5 dma_async_device_unregister +EXPORT_SYMBOL vmlinux 0x0400acce call_usermodehelper_freeinfo +EXPORT_SYMBOL vmlinux 0x0413d25d sync_mapping_buffers +EXPORT_SYMBOL vmlinux 0x0422fe4a inet_csk_timer_bug_msg +EXPORT_SYMBOL vmlinux 0x044fbf49 mempool_kzalloc +EXPORT_SYMBOL vmlinux 0x047ea62c nf_register_sockopt +EXPORT_SYMBOL vmlinux 0x0487f831 fb_find_best_display +EXPORT_SYMBOL vmlinux 0x048c15d1 bio_get_nr_vecs +EXPORT_SYMBOL vmlinux 0x04a951c1 elevator_init +EXPORT_SYMBOL vmlinux 0x04bf5eb0 nonseekable_open +EXPORT_SYMBOL vmlinux 0x04d40a71 register_netdev +EXPORT_SYMBOL vmlinux 0x04d8c750 release_perfctr_nmi +EXPORT_SYMBOL vmlinux 0x04fee575 fasync_helper +EXPORT_SYMBOL vmlinux 0x05092292 skb_copy_and_csum_bits +EXPORT_SYMBOL vmlinux 0x052c739d tcp_hashinfo +EXPORT_SYMBOL vmlinux 0x053aed2a tty_register_ldisc +EXPORT_SYMBOL vmlinux 0x053b018b ps2_cmd_aborted +EXPORT_SYMBOL vmlinux 0x0545bf28 dev_set_mtu +EXPORT_SYMBOL vmlinux 0x05746783 neigh_sysctl_register +EXPORT_SYMBOL vmlinux 0x058c75d9 acpi_get_pci_id +EXPORT_SYMBOL vmlinux 0x05ebc344 pci_set_dma_mask +EXPORT_SYMBOL vmlinux 0x05f81370 block_commit_write +EXPORT_SYMBOL vmlinux 0x05fda9e0 nlmsg_notify +EXPORT_SYMBOL vmlinux 0x061651be strcat +EXPORT_SYMBOL vmlinux 0x063724e2 lease_get_mtime +EXPORT_SYMBOL vmlinux 0x063c01cb cfb_copyarea +EXPORT_SYMBOL vmlinux 0x067d8d35 security_release_secctx +EXPORT_SYMBOL vmlinux 0x06a3de08 skb_seq_read +EXPORT_SYMBOL vmlinux 0x06a485f2 __krealloc +EXPORT_SYMBOL vmlinux 0x06d728b1 tcp_parse_md5sig_option +EXPORT_SYMBOL vmlinux 0x06df9557 simple_lookup +EXPORT_SYMBOL vmlinux 0x06fe3b14 default_grn +EXPORT_SYMBOL vmlinux 0x070cfde3 elv_rb_del +EXPORT_SYMBOL vmlinux 0x0727c4f3 iowrite8 +EXPORT_SYMBOL vmlinux 0x073dfa12 generate_resume_trace +EXPORT_SYMBOL vmlinux 0x075a2000 tcp_v4_send_check +EXPORT_SYMBOL vmlinux 0x0768f5a9 free_buffer_head +EXPORT_SYMBOL vmlinux 0x0784667f sock_rfree +EXPORT_SYMBOL vmlinux 0x0784ef79 dmam_free_coherent +EXPORT_SYMBOL vmlinux 0x078c036b poll_freewait +EXPORT_SYMBOL vmlinux 0x0799aca4 local_bh_enable +EXPORT_SYMBOL vmlinux 0x079cd7f1 ns_to_timeval +EXPORT_SYMBOL vmlinux 0x07a890c8 fb_alloc_cmap +EXPORT_SYMBOL vmlinux 0x07cc4a5d printk_timed_ratelimit +EXPORT_SYMBOL vmlinux 0x082c3213 pci_root_buses +EXPORT_SYMBOL vmlinux 0x083183e9 register_exec_domain +EXPORT_SYMBOL vmlinux 0x0845fbdb inet_put_port +EXPORT_SYMBOL vmlinux 0x0856ce6a blkdev_get +EXPORT_SYMBOL vmlinux 0x0933aae1 efi_enabled +EXPORT_SYMBOL vmlinux 0x0948cde9 num_physpages +EXPORT_SYMBOL vmlinux 0x09554a68 dma_set_mask +EXPORT_SYMBOL vmlinux 0x096debe6 wireless_spy_update +EXPORT_SYMBOL vmlinux 0x09775cdc kref_get +EXPORT_SYMBOL vmlinux 0x098431ba acpi_get_current_resources +EXPORT_SYMBOL vmlinux 0x098b71c6 fb_dealloc_cmap +EXPORT_SYMBOL vmlinux 0x09a17895 file_remove_suid +EXPORT_SYMBOL vmlinux 0x09b1335a pci_enable_bridges +EXPORT_SYMBOL vmlinux 0x09c55cec schedule_timeout_interruptible +EXPORT_SYMBOL vmlinux 0x09cc758d keyring_search +EXPORT_SYMBOL vmlinux 0x09d0421e vmap +EXPORT_SYMBOL vmlinux 0x09d29dff key_link +EXPORT_SYMBOL vmlinux 0x09d44df9 in_lock_functions +EXPORT_SYMBOL vmlinux 0x09fda52e find_inode_number +EXPORT_SYMBOL vmlinux 0x0a2487e0 unblock_all_signals +EXPORT_SYMBOL vmlinux 0x0a425fba fb_find_mode +EXPORT_SYMBOL vmlinux 0x0a6a6538 d_add_ci +EXPORT_SYMBOL vmlinux 0x0acb1a3c __bitmap_shift_right +EXPORT_SYMBOL vmlinux 0x0aef3079 llc_sap_find +EXPORT_SYMBOL vmlinux 0x0b0ac6d1 register_filesystem +EXPORT_SYMBOL vmlinux 0x0b15192a seq_printf +EXPORT_SYMBOL vmlinux 0x0b1beb31 vmalloc_32_user +EXPORT_SYMBOL vmlinux 0x0b4a72b7 unmap_underlying_metadata +EXPORT_SYMBOL vmlinux 0x0b4b9edf alloc_disk_node +EXPORT_SYMBOL vmlinux 0x0b6551fd flush_signals +EXPORT_SYMBOL vmlinux 0x0b742fd7 simple_strtol +EXPORT_SYMBOL vmlinux 0x0b78c2ba dev_change_flags +EXPORT_SYMBOL vmlinux 0x0bfd0579 bio_integrity_enabled +EXPORT_SYMBOL vmlinux 0x0c046bbd migrate_page +EXPORT_SYMBOL vmlinux 0x0c2d75ed neigh_lookup_nodev +EXPORT_SYMBOL vmlinux 0x0c5c69e3 flow_cache_lookup +EXPORT_SYMBOL vmlinux 0x0c5db825 xfrm_state_insert +EXPORT_SYMBOL vmlinux 0x0c5ef91b per_cpu__vm_event_states +EXPORT_SYMBOL vmlinux 0x0c87c756 bio_split_pool +EXPORT_SYMBOL vmlinux 0x0cea9bae pagecache_write_end +EXPORT_SYMBOL vmlinux 0x0cf01b5d blk_queue_bounce_limit +EXPORT_SYMBOL vmlinux 0x0cfc39c3 ip_nat_decode_session +EXPORT_SYMBOL vmlinux 0x0d26a76d _write_lock_irq +EXPORT_SYMBOL vmlinux 0x0d3dda14 acpi_get_type +EXPORT_SYMBOL vmlinux 0x0d542439 __ipv6_addr_type +EXPORT_SYMBOL vmlinux 0x0d894213 kmem_cache_create +EXPORT_SYMBOL vmlinux 0x0d894e7f agp_alloc_page_array +EXPORT_SYMBOL vmlinux 0x0d8ab500 param_set_copystring +EXPORT_SYMBOL vmlinux 0x0d9e07c6 nf_hook_slow +EXPORT_SYMBOL vmlinux 0x0da10ec3 security_sock_graft +EXPORT_SYMBOL vmlinux 0x0daeb6f2 tcp_create_openreq_child +EXPORT_SYMBOL vmlinux 0x0dc84ae2 proc_dointvec_minmax +EXPORT_SYMBOL vmlinux 0x0e0252ec downgrade_write +EXPORT_SYMBOL vmlinux 0x0e0872da sk_stream_wait_connect +EXPORT_SYMBOL vmlinux 0x0e1eaf06 unregister_snap_client +EXPORT_SYMBOL vmlinux 0x0e3fffa5 elevator_exit +EXPORT_SYMBOL vmlinux 0x0e4af292 xfrm_alloc_spi +EXPORT_SYMBOL vmlinux 0x0e50c71f skb_pad +EXPORT_SYMBOL vmlinux 0x0e52592a panic +EXPORT_SYMBOL vmlinux 0x0e6ea02c module_refcount +EXPORT_SYMBOL vmlinux 0x0e762d6e request_module +EXPORT_SYMBOL vmlinux 0x0e7bb697 acpi_unlock_ac_dir +EXPORT_SYMBOL vmlinux 0x0e930954 tcf_hash_check +EXPORT_SYMBOL vmlinux 0x0ed577ec end_dequeued_request +EXPORT_SYMBOL vmlinux 0x0ed95a49 ethtool_op_set_tx_csum +EXPORT_SYMBOL vmlinux 0x0eec0352 tty_wait_until_sent +EXPORT_SYMBOL vmlinux 0x0f033da8 xfrm_init_state +EXPORT_SYMBOL vmlinux 0x0f130caf __alloc_skb +EXPORT_SYMBOL vmlinux 0x0f2bd82f proc_net_netfilter +EXPORT_SYMBOL vmlinux 0x0f668286 eth_header_cache_update +EXPORT_SYMBOL vmlinux 0x0f714769 skb_dequeue_tail +EXPORT_SYMBOL vmlinux 0x0facabf1 clip_tbl_hook +EXPORT_SYMBOL vmlinux 0x0faef0ed __tasklet_schedule +EXPORT_SYMBOL vmlinux 0x0fbc3f05 blk_plug_device +EXPORT_SYMBOL vmlinux 0x0fc5e8eb radix_tree_gang_lookup_slot +EXPORT_SYMBOL vmlinux 0x0fd00a68 acpi_clear_event +EXPORT_SYMBOL vmlinux 0x103b8f40 thermal_zone_unbind_cooling_device +EXPORT_SYMBOL vmlinux 0x1055db10 pci_back_from_sleep +EXPORT_SYMBOL vmlinux 0x1072a394 csum_partial_copy_from_user +EXPORT_SYMBOL vmlinux 0x107acb6e d_namespace_path +EXPORT_SYMBOL vmlinux 0x109f5dce inet_frag_find +EXPORT_SYMBOL vmlinux 0x10e2900d elv_dequeue_request +EXPORT_SYMBOL vmlinux 0x10ee20bb default_blu +EXPORT_SYMBOL vmlinux 0x114cab3a alloc_tty_driver +EXPORT_SYMBOL vmlinux 0x11554b5e pci_scan_slot +EXPORT_SYMBOL vmlinux 0x116240db key_instantiate_and_link +EXPORT_SYMBOL vmlinux 0x1163f0a7 blk_max_low_pfn +EXPORT_SYMBOL vmlinux 0x1167903f xfrm_policy_bysel_ctx +EXPORT_SYMBOL vmlinux 0x117093be qdisc_class_hash_init +EXPORT_SYMBOL vmlinux 0x118f01ea putname +EXPORT_SYMBOL vmlinux 0x119cb6e0 llc_sap_open +EXPORT_SYMBOL vmlinux 0x11a18b14 __wake_up_bit +EXPORT_SYMBOL vmlinux 0x11cc83c5 sock_no_mmap +EXPORT_SYMBOL vmlinux 0x11d2eca2 inet_csk_accept +EXPORT_SYMBOL vmlinux 0x11d309ea simple_statfs +EXPORT_SYMBOL vmlinux 0x11dab346 __down_read +EXPORT_SYMBOL vmlinux 0x125fbca7 cad_pid +EXPORT_SYMBOL vmlinux 0x126970ed param_set_uint +EXPORT_SYMBOL vmlinux 0x127df2cd mpage_readpages +EXPORT_SYMBOL vmlinux 0x12d0569d __tcp_get_md5sig_pool +EXPORT_SYMBOL vmlinux 0x12e153b0 tty_port_free_xmit_buf +EXPORT_SYMBOL vmlinux 0x12f62a2e dput +EXPORT_SYMBOL vmlinux 0x12f99022 inet_frags_init_net +EXPORT_SYMBOL vmlinux 0x132f45f2 cookie_check_timestamp +EXPORT_SYMBOL vmlinux 0x1378e714 acpi_video_display_switch_support +EXPORT_SYMBOL vmlinux 0x138610a0 bdput +EXPORT_SYMBOL vmlinux 0x13dfaa42 nobh_truncate_page +EXPORT_SYMBOL vmlinux 0x13f71731 tcf_hash_lookup +EXPORT_SYMBOL vmlinux 0x1405141b xfrm_state_alloc +EXPORT_SYMBOL vmlinux 0x141a8542 pcie_port_service_register +EXPORT_SYMBOL vmlinux 0x1430e6e0 unregister_acpi_notifier +EXPORT_SYMBOL vmlinux 0x143419b7 sysctl_string +EXPORT_SYMBOL vmlinux 0x146f090a neigh_table_clear +EXPORT_SYMBOL vmlinux 0x14a798d5 pci_match_id +EXPORT_SYMBOL vmlinux 0x14af0cf7 gen_pool_destroy +EXPORT_SYMBOL vmlinux 0x14cacb20 set_user_nice +EXPORT_SYMBOL vmlinux 0x14ee8ace clear_bdi_congested +EXPORT_SYMBOL vmlinux 0x15098518 filemap_flush +EXPORT_SYMBOL vmlinux 0x150bbb58 ps2_handle_ack +EXPORT_SYMBOL vmlinux 0x1544aad4 genl_register_mc_group +EXPORT_SYMBOL vmlinux 0x15464c6f dquot_mark_dquot_dirty +EXPORT_SYMBOL vmlinux 0x154a466b invalidate_bdev +EXPORT_SYMBOL vmlinux 0x1551dc51 bitmap_find_free_region +EXPORT_SYMBOL vmlinux 0x15a461a5 atm_proc_root +EXPORT_SYMBOL vmlinux 0x15b470df invalidate_partition +EXPORT_SYMBOL vmlinux 0x15b7263c kmalloc_caches +EXPORT_SYMBOL vmlinux 0x15ef2dd9 kfifo_free +EXPORT_SYMBOL vmlinux 0x16517eb7 pci_iounmap +EXPORT_SYMBOL vmlinux 0x1675606f bad_dma_address +EXPORT_SYMBOL vmlinux 0x167e7f9d __get_user_1 +EXPORT_SYMBOL vmlinux 0x16a35878 _read_unlock +EXPORT_SYMBOL vmlinux 0x16b3a779 tcp_rcv_state_process +EXPORT_SYMBOL vmlinux 0x16d3a378 file_permission +EXPORT_SYMBOL vmlinux 0x170a2bc3 pnp_unregister_card_driver +EXPORT_SYMBOL vmlinux 0x170b9b15 agp_generic_alloc_by_type +EXPORT_SYMBOL vmlinux 0x170c25ee acpi_get_next_object +EXPORT_SYMBOL vmlinux 0x170d1c34 blk_init_queue +EXPORT_SYMBOL vmlinux 0x17224d88 have_submounts +EXPORT_SYMBOL vmlinux 0x172ed4d7 __vmalloc +EXPORT_SYMBOL vmlinux 0x17a76e71 rb_first +EXPORT_SYMBOL vmlinux 0x17c85a66 radix_tree_tagged +EXPORT_SYMBOL vmlinux 0x17df17bc sysctl_tcp_ecn +EXPORT_SYMBOL vmlinux 0x181b6ff2 mempool_resize +EXPORT_SYMBOL vmlinux 0x183da72c dentry_open +EXPORT_SYMBOL vmlinux 0x183fa88b mempool_alloc_slab +EXPORT_SYMBOL vmlinux 0x184c3fd0 dev_get_by_flags +EXPORT_SYMBOL vmlinux 0x185219bf swiotlb_free_coherent +EXPORT_SYMBOL vmlinux 0x186172e6 mapping_tagged +EXPORT_SYMBOL vmlinux 0x18673690 input_get_keycode +EXPORT_SYMBOL vmlinux 0x1885ea88 sock_alloc_send_skb +EXPORT_SYMBOL vmlinux 0x18993d08 setup_arg_pages +EXPORT_SYMBOL vmlinux 0x189b6bac memory_read_from_buffer +EXPORT_SYMBOL vmlinux 0x18d53597 call_usermodehelper_exec +EXPORT_SYMBOL vmlinux 0x18f5188a key_put +EXPORT_SYMBOL vmlinux 0x19134ac1 proc_create_data +EXPORT_SYMBOL vmlinux 0x19391763 iov_iter_fault_in_readable +EXPORT_SYMBOL vmlinux 0x1972f370 xfrm_unregister_km +EXPORT_SYMBOL vmlinux 0x1985ed3c prepare_to_wait_exclusive +EXPORT_SYMBOL vmlinux 0x199ed0cd net_disable_timestamp +EXPORT_SYMBOL vmlinux 0x19d5d20a acpi_walk_namespace +EXPORT_SYMBOL vmlinux 0x19f4b2a2 blk_queue_dma_alignment +EXPORT_SYMBOL vmlinux 0x1a1ab15d tty_mutex +EXPORT_SYMBOL vmlinux 0x1a2eb2f3 dec_zone_page_state +EXPORT_SYMBOL vmlinux 0x1a45cb6c acpi_disabled +EXPORT_SYMBOL vmlinux 0x1a75caa3 _read_lock +EXPORT_SYMBOL vmlinux 0x1a8a845e idle_nomwait +EXPORT_SYMBOL vmlinux 0x1a9669fa sock_sendmsg +EXPORT_SYMBOL vmlinux 0x1ac02507 sock_no_poll +EXPORT_SYMBOL vmlinux 0x1ace138d bitmap_allocate_region +EXPORT_SYMBOL vmlinux 0x1ae8d7dc param_set_invbool +EXPORT_SYMBOL vmlinux 0x1b015d25 bitmap_parselist +EXPORT_SYMBOL vmlinux 0x1b083e6c deregister_atm_ioctl +EXPORT_SYMBOL vmlinux 0x1b1384f6 kobject_add +EXPORT_SYMBOL vmlinux 0x1b19a0ea pci_scan_bridge +EXPORT_SYMBOL vmlinux 0x1b3813de simple_transaction_release +EXPORT_SYMBOL vmlinux 0x1b3b06b3 vm_insert_mixed +EXPORT_SYMBOL vmlinux 0x1b3b863c pci_set_consistent_dma_mask +EXPORT_SYMBOL vmlinux 0x1b3c678a gen_new_estimator +EXPORT_SYMBOL vmlinux 0x1b42c4de alloc_fcdev +EXPORT_SYMBOL vmlinux 0x1b47d602 netlink_broadcast +EXPORT_SYMBOL vmlinux 0x1b6314fd in_aton +EXPORT_SYMBOL vmlinux 0x1b818707 dmam_alloc_noncoherent +EXPORT_SYMBOL vmlinux 0x1b854087 __scm_send +EXPORT_SYMBOL vmlinux 0x1b89419f add_wait_queue_exclusive +EXPORT_SYMBOL vmlinux 0x1b9981cc set_irq_wake +EXPORT_SYMBOL vmlinux 0x1b9b306f generic_file_llseek +EXPORT_SYMBOL vmlinux 0x1baa9c86 node_to_cpumask_map +EXPORT_SYMBOL vmlinux 0x1bb00ebd tcp_v4_md5_hash_skb +EXPORT_SYMBOL vmlinux 0x1c102b40 register_quota_format +EXPORT_SYMBOL vmlinux 0x1c11f71e pnp_get_resource +EXPORT_SYMBOL vmlinux 0x1c37e16a input_allocate_device +EXPORT_SYMBOL vmlinux 0x1c39aeed generic_ro_fops +EXPORT_SYMBOL vmlinux 0x1c3e93ef tty_port_alloc_xmit_buf +EXPORT_SYMBOL vmlinux 0x1c4a113f seq_putc +EXPORT_SYMBOL vmlinux 0x1c5f1b98 pci_find_capability +EXPORT_SYMBOL vmlinux 0x1c678db9 bio_alloc_bioset +EXPORT_SYMBOL vmlinux 0x1c85a77a pcie_set_readrq +EXPORT_SYMBOL vmlinux 0x1c8fc816 add_disk +EXPORT_SYMBOL vmlinux 0x1cc6719a register_reboot_notifier +EXPORT_SYMBOL vmlinux 0x1ce4f76c skb_realloc_headroom +EXPORT_SYMBOL vmlinux 0x1cefe352 wait_for_completion +EXPORT_SYMBOL vmlinux 0x1cf3709f acpi_evaluate_integer +EXPORT_SYMBOL vmlinux 0x1cf422d5 set_pages_uc +EXPORT_SYMBOL vmlinux 0x1d219b78 inetdev_by_index +EXPORT_SYMBOL vmlinux 0x1d264e30 swiotlb_dma_mapping_error +EXPORT_SYMBOL vmlinux 0x1d31abfb sock_no_sendmsg +EXPORT_SYMBOL vmlinux 0x1d4c1dc0 vfs_permission +EXPORT_SYMBOL vmlinux 0x1d6a9f34 sb_min_blocksize +EXPORT_SYMBOL vmlinux 0x1d830520 cpu_possible_map +EXPORT_SYMBOL vmlinux 0x1d9cb13c ll_rw_block +EXPORT_SYMBOL vmlinux 0x1dadf9ea xfrm_input +EXPORT_SYMBOL vmlinux 0x1db7706b __copy_user_nocache +EXPORT_SYMBOL vmlinux 0x1db81d30 udp_proc_register +EXPORT_SYMBOL vmlinux 0x1dc36131 fb_destroy_modedb +EXPORT_SYMBOL vmlinux 0x1dd17996 filp_open +EXPORT_SYMBOL vmlinux 0x1dd571e6 fb_copy_cmap +EXPORT_SYMBOL vmlinux 0x1df89cae rtnetlink_put_metrics +EXPORT_SYMBOL vmlinux 0x1e142e48 arch_acpi_processor_init_pdc +EXPORT_SYMBOL vmlinux 0x1e1fc55f pci_map_rom +EXPORT_SYMBOL vmlinux 0x1e2f5175 agp_generic_destroy_page +EXPORT_SYMBOL vmlinux 0x1e6d26a8 strstr +EXPORT_SYMBOL vmlinux 0x1e73c367 init_special_inode +EXPORT_SYMBOL vmlinux 0x1e8d7b94 sysctl_ms_jiffies +EXPORT_SYMBOL vmlinux 0x1eaa5045 take_over_console +EXPORT_SYMBOL vmlinux 0x1edc77f8 kobject_set_name +EXPORT_SYMBOL vmlinux 0x1eddf0c3 iw_handler_get_thrspy +EXPORT_SYMBOL vmlinux 0x1ee873e6 compat_mc_setsockopt +EXPORT_SYMBOL vmlinux 0x1efe283f __cap_full_set +EXPORT_SYMBOL vmlinux 0x1f04966f complete_request_key +EXPORT_SYMBOL vmlinux 0x1f14f72f udp_sendmsg +EXPORT_SYMBOL vmlinux 0x1f27d6d7 _write_unlock +EXPORT_SYMBOL vmlinux 0x1f6b1fa6 uart_write_wakeup +EXPORT_SYMBOL vmlinux 0x20000329 simple_strtoul +EXPORT_SYMBOL vmlinux 0x2005e68a acpi_remove_fixed_event_handler +EXPORT_SYMBOL vmlinux 0x20092385 acpi_enter_sleep_state_s4bios +EXPORT_SYMBOL vmlinux 0x20106892 register_console +EXPORT_SYMBOL vmlinux 0x203e7022 pci_request_selected_regions +EXPORT_SYMBOL vmlinux 0x2064dbf0 ethtool_op_set_tx_ipv6_csum +EXPORT_SYMBOL vmlinux 0x20676a47 skb_truesize_bug +EXPORT_SYMBOL vmlinux 0x20770b05 eth_header_parse +EXPORT_SYMBOL vmlinux 0x208739f6 acpi_load_table +EXPORT_SYMBOL vmlinux 0x20b6eb79 nla_put +EXPORT_SYMBOL vmlinux 0x20c74d9f kobject_put +EXPORT_SYMBOL vmlinux 0x20c8fc33 pci_osc_control_set +EXPORT_SYMBOL vmlinux 0x20dfcb03 serio_unregister_driver +EXPORT_SYMBOL vmlinux 0x20eadeb6 ip_compute_csum +EXPORT_SYMBOL vmlinux 0x20ed07d4 input_open_device +EXPORT_SYMBOL vmlinux 0x20f9322a idr_pre_get +EXPORT_SYMBOL vmlinux 0x21033e88 pnp_disable_dev +EXPORT_SYMBOL vmlinux 0x2111b445 alloc_disk +EXPORT_SYMBOL vmlinux 0x21230e91 tty_schedule_flip +EXPORT_SYMBOL vmlinux 0x215ebd78 bitrev16 +EXPORT_SYMBOL vmlinux 0x21736ce5 call_usermodehelper_setup +EXPORT_SYMBOL vmlinux 0x21964e44 xfrm_register_mode +EXPORT_SYMBOL vmlinux 0x21e0ea22 acpi_get_id +EXPORT_SYMBOL vmlinux 0x21e5679c copy_user_generic +EXPORT_SYMBOL vmlinux 0x2224ea14 nf_unregister_hooks +EXPORT_SYMBOL vmlinux 0x22293822 nf_ip_checksum +EXPORT_SYMBOL vmlinux 0x222e7ce2 sysfs_streq +EXPORT_SYMBOL vmlinux 0x2253c959 kblockd_flush_work +EXPORT_SYMBOL vmlinux 0x226e86a9 audit_log +EXPORT_SYMBOL vmlinux 0x227f3fe1 udplite_prot +EXPORT_SYMBOL vmlinux 0x2288378f system_state +EXPORT_SYMBOL vmlinux 0x2288a618 tcp_disconnect +EXPORT_SYMBOL vmlinux 0x22a73912 __tcp_put_md5sig_pool +EXPORT_SYMBOL vmlinux 0x22b325d5 kd_mksound +EXPORT_SYMBOL vmlinux 0x22b6533b xfrm_sad_getinfo +EXPORT_SYMBOL vmlinux 0x22d400e1 vmalloc_to_page +EXPORT_SYMBOL vmlinux 0x22e9512e swiotlb_sync_sg_for_device +EXPORT_SYMBOL vmlinux 0x231f3a66 __kfifo_put +EXPORT_SYMBOL vmlinux 0x23269a13 strict_strtoul +EXPORT_SYMBOL vmlinux 0x23404bf8 pci_bus_read_config_dword +EXPORT_SYMBOL vmlinux 0x2341f72e __netdev_alloc_skb +EXPORT_SYMBOL vmlinux 0x234509f3 strncat +EXPORT_SYMBOL vmlinux 0x2360fc52 block_write_full_page +EXPORT_SYMBOL vmlinux 0x236c8c64 memcpy +EXPORT_SYMBOL vmlinux 0x238a48dc bdi_set_max_ratio +EXPORT_SYMBOL vmlinux 0x23a0aa7a sk_free +EXPORT_SYMBOL vmlinux 0x23a7a3bd maps_protect +EXPORT_SYMBOL vmlinux 0x23aab75e sock_map_fd +EXPORT_SYMBOL vmlinux 0x23b99e92 node_states +EXPORT_SYMBOL vmlinux 0x23f2d36f memparse +EXPORT_SYMBOL vmlinux 0x23fd3028 vmalloc_node +EXPORT_SYMBOL vmlinux 0x24428be5 strncpy_from_user +EXPORT_SYMBOL vmlinux 0x24457dc6 sockfd_lookup +EXPORT_SYMBOL vmlinux 0x2459bbcc console_set_on_cmdline +EXPORT_SYMBOL vmlinux 0x24609f0c vfs_rmdir +EXPORT_SYMBOL vmlinux 0x24866a7e inet_twsk_deschedule +EXPORT_SYMBOL vmlinux 0x24b6488b tcf_em_unregister +EXPORT_SYMBOL vmlinux 0x24c66c95 tcp_alloc_md5sig_pool +EXPORT_SYMBOL vmlinux 0x24fdac79 wake_bit_function +EXPORT_SYMBOL vmlinux 0x252b43d5 pci_bus_write_config_byte +EXPORT_SYMBOL vmlinux 0x25330040 inode_setattr +EXPORT_SYMBOL vmlinux 0x25552984 serial8250_register_port +EXPORT_SYMBOL vmlinux 0x2559df80 blk_queue_segment_boundary +EXPORT_SYMBOL vmlinux 0x25643d2c genl_unregister_ops +EXPORT_SYMBOL vmlinux 0x256887e1 warn_slowpath +EXPORT_SYMBOL vmlinux 0x25820c64 fs_overflowuid +EXPORT_SYMBOL vmlinux 0x258355b4 fb_find_best_mode +EXPORT_SYMBOL vmlinux 0x25d2e79e read_cache_page +EXPORT_SYMBOL vmlinux 0x25e62b68 kmem_cache_shrink +EXPORT_SYMBOL vmlinux 0x25ec1b28 strlen +EXPORT_SYMBOL vmlinux 0x263782b5 cancel_delayed_work_sync +EXPORT_SYMBOL vmlinux 0x2644a055 sk_stop_timer +EXPORT_SYMBOL vmlinux 0x26770333 ethtool_op_get_flags +EXPORT_SYMBOL vmlinux 0x2685c3d7 __sg_alloc_table +EXPORT_SYMBOL vmlinux 0x269240d6 pskb_expand_head +EXPORT_SYMBOL vmlinux 0x26a68573 mark_buffer_dirty_inode +EXPORT_SYMBOL vmlinux 0x26c41501 inode_set_bytes +EXPORT_SYMBOL vmlinux 0x26debcc9 km_policy_expired +EXPORT_SYMBOL vmlinux 0x26e76fb8 sysctl_udp_wmem_min +EXPORT_SYMBOL vmlinux 0x2704fe55 bmap +EXPORT_SYMBOL vmlinux 0x27250ebe mark_buffer_dirty +EXPORT_SYMBOL vmlinux 0x272d394e mtrr_del +EXPORT_SYMBOL vmlinux 0x272e7488 cond_resched_softirq +EXPORT_SYMBOL vmlinux 0x273f066e _write_unlock_irq +EXPORT_SYMBOL vmlinux 0x27475f90 skb_append +EXPORT_SYMBOL vmlinux 0x275ee2f2 skb_copy_and_csum_datagram_iovec +EXPORT_SYMBOL vmlinux 0x277d99db __next_cpu +EXPORT_SYMBOL vmlinux 0x27884fc0 __xfrm_state_destroy +EXPORT_SYMBOL vmlinux 0x279936a7 inet_addr_type +EXPORT_SYMBOL vmlinux 0x27a9a7eb ns_to_timespec +EXPORT_SYMBOL vmlinux 0x27bbf221 disable_irq_nosync +EXPORT_SYMBOL vmlinux 0x27c33efe csum_ipv6_magic +EXPORT_SYMBOL vmlinux 0x27c61ece qdisc_put_stab +EXPORT_SYMBOL vmlinux 0x27cefc17 read_cache_page_async +EXPORT_SYMBOL vmlinux 0x27e7f6d6 ip_xfrm_me_harder +EXPORT_SYMBOL vmlinux 0x280dafb6 blk_queue_resize_tags +EXPORT_SYMBOL vmlinux 0x2819d4a0 dquot_initialize +EXPORT_SYMBOL vmlinux 0x28288472 qdisc_reset +EXPORT_SYMBOL vmlinux 0x285373ff inet_bind +EXPORT_SYMBOL vmlinux 0x285ac517 strict_strtoll +EXPORT_SYMBOL vmlinux 0x2876a6d3 memcpy_toiovec +EXPORT_SYMBOL vmlinux 0x28d89ea3 serio_interrupt +EXPORT_SYMBOL vmlinux 0x28dcf25c udplite_hash +EXPORT_SYMBOL vmlinux 0x2904ae29 vfs_set_dqblk +EXPORT_SYMBOL vmlinux 0x2908596b xfrm_state_unregister_afinfo +EXPORT_SYMBOL vmlinux 0x295029a1 acpi_notifier_call_chain +EXPORT_SYMBOL vmlinux 0x2950d2a6 generic_listxattr +EXPORT_SYMBOL vmlinux 0x29537c9e alloc_chrdev_region +EXPORT_SYMBOL vmlinux 0x2991f2c0 tcp_v4_md5_do_add +EXPORT_SYMBOL vmlinux 0x2992a945 get_sb_pseudo +EXPORT_SYMBOL vmlinux 0x2995861b end_page_writeback +EXPORT_SYMBOL vmlinux 0x29bd4c46 __cap_init_eff_set +EXPORT_SYMBOL vmlinux 0x2a303d4d check_signature +EXPORT_SYMBOL vmlinux 0x2a322673 nf_register_queue_handler +EXPORT_SYMBOL vmlinux 0x2a8986ba thermal_cooling_device_unregister +EXPORT_SYMBOL vmlinux 0x2a8b5483 pci_do_scan_bus +EXPORT_SYMBOL vmlinux 0x2a90995c task_session_nr_ns +EXPORT_SYMBOL vmlinux 0x2a9f7d6e blk_queue_init_tags +EXPORT_SYMBOL vmlinux 0x2ae57c75 do_sync_write +EXPORT_SYMBOL vmlinux 0x2aeb2800 mempool_create_node +EXPORT_SYMBOL vmlinux 0x2aeb9531 blk_queue_find_tag +EXPORT_SYMBOL vmlinux 0x2b08273b path_put +EXPORT_SYMBOL vmlinux 0x2b0b412a pcibios_align_resource +EXPORT_SYMBOL vmlinux 0x2b12cb05 security_sk_classify_flow +EXPORT_SYMBOL vmlinux 0x2b2ac98d blk_rq_map_kern +EXPORT_SYMBOL vmlinux 0x2b367794 simple_set_mnt +EXPORT_SYMBOL vmlinux 0x2b627756 simple_dir_operations +EXPORT_SYMBOL vmlinux 0x2b690e69 __splice_from_pipe +EXPORT_SYMBOL vmlinux 0x2b6aac8c tcp_sockets_allocated +EXPORT_SYMBOL vmlinux 0x2b96cf54 generic_file_direct_write +EXPORT_SYMBOL vmlinux 0x2b9d2712 ioctl_by_bdev +EXPORT_SYMBOL vmlinux 0x2ba707a8 sysctl_tcp_low_latency +EXPORT_SYMBOL vmlinux 0x2bb55d6e acpi_remove_notify_handler +EXPORT_SYMBOL vmlinux 0x2bd23896 compat_nf_getsockopt +EXPORT_SYMBOL vmlinux 0x2be09893 _atomic_dec_and_lock +EXPORT_SYMBOL vmlinux 0x2be246ef find_vma +EXPORT_SYMBOL vmlinux 0x2bfeb410 acpi_get_handle +EXPORT_SYMBOL vmlinux 0x2c5749e6 acpi_clear_gpe +EXPORT_SYMBOL vmlinux 0x2c757e17 udp_flush_pending_frames +EXPORT_SYMBOL vmlinux 0x2c86c760 agp_allocate_memory +EXPORT_SYMBOL vmlinux 0x2cb5bd3d secpath_dup +EXPORT_SYMBOL vmlinux 0x2cc08b06 tcp_enter_memory_pressure +EXPORT_SYMBOL vmlinux 0x2cc2d52d vcc_hash +EXPORT_SYMBOL vmlinux 0x2cc2fd21 __lock_buffer +EXPORT_SYMBOL vmlinux 0x2cc6e9f0 udp_poll +EXPORT_SYMBOL vmlinux 0x2cd9e459 param_set_short +EXPORT_SYMBOL vmlinux 0x2cf190e3 request_irq +EXPORT_SYMBOL vmlinux 0x2cf3ff12 tcf_unregister_action +EXPORT_SYMBOL vmlinux 0x2d09b960 __xfrm_lookup +EXPORT_SYMBOL vmlinux 0x2d23a5cf skb_push +EXPORT_SYMBOL vmlinux 0x2d27770b lock_may_read +EXPORT_SYMBOL vmlinux 0x2d5528c9 sg_copy_to_buffer +EXPORT_SYMBOL vmlinux 0x2dac916d compat_tcp_getsockopt +EXPORT_SYMBOL vmlinux 0x2dba3dbc input_close_device +EXPORT_SYMBOL vmlinux 0x2dd16564 arch_register_cpu +EXPORT_SYMBOL vmlinux 0x2de9f66f param_get_long +EXPORT_SYMBOL vmlinux 0x2dedc4c2 acpi_format_exception +EXPORT_SYMBOL vmlinux 0x2def7f76 rtc_cmos_write +EXPORT_SYMBOL vmlinux 0x2e2ce9e0 sysctl_tcp_syncookies +EXPORT_SYMBOL vmlinux 0x2e36655e swiotlb_map_single_attrs +EXPORT_SYMBOL vmlinux 0x2e4a39f8 sysctl_udp_mem +EXPORT_SYMBOL vmlinux 0x2e6ffdd8 get_fs_type +EXPORT_SYMBOL vmlinux 0x2e9190a5 sock_no_recvmsg +EXPORT_SYMBOL vmlinux 0x2e92eb7c udp_lib_get_port +EXPORT_SYMBOL vmlinux 0x2e97a729 idr_remove +EXPORT_SYMBOL vmlinux 0x2eacf710 dmam_pool_create +EXPORT_SYMBOL vmlinux 0x2eb9a0e8 _read_lock_irq +EXPORT_SYMBOL vmlinux 0x2ec1186c find_task_by_pid_ns +EXPORT_SYMBOL vmlinux 0x2edd8d00 pci_bus_assign_resources +EXPORT_SYMBOL vmlinux 0x2efe1ac4 arch_debugfs_dir +EXPORT_SYMBOL vmlinux 0x2f7a90d0 rtnl_unicast +EXPORT_SYMBOL vmlinux 0x2fa5a500 memcmp +EXPORT_SYMBOL vmlinux 0x2ff063b5 acpi_get_name +EXPORT_SYMBOL vmlinux 0x2ff7efaa tcf_hash_new_index +EXPORT_SYMBOL vmlinux 0x3006782f bio_integrity_prep +EXPORT_SYMBOL vmlinux 0x3007ffbd neigh_table_init_no_netlink +EXPORT_SYMBOL vmlinux 0x301cdbff user_revoke +EXPORT_SYMBOL vmlinux 0x30226ddf agp_device_command +EXPORT_SYMBOL vmlinux 0x30299447 dget_locked +EXPORT_SYMBOL vmlinux 0x30321700 sg_miter_stop +EXPORT_SYMBOL vmlinux 0x304c2b86 blk_sync_queue +EXPORT_SYMBOL vmlinux 0x306bd3c3 vfs_fstat +EXPORT_SYMBOL vmlinux 0x30896043 __any_online_cpu +EXPORT_SYMBOL vmlinux 0x30896920 compat_mc_getsockopt +EXPORT_SYMBOL vmlinux 0x30a75973 register_atm_ioctl +EXPORT_SYMBOL vmlinux 0x30a94c37 pci_reenable_device +EXPORT_SYMBOL vmlinux 0x30c5ac52 pnp_unregister_driver +EXPORT_SYMBOL vmlinux 0x30de8b2e copy_io_context +EXPORT_SYMBOL vmlinux 0x30e74134 tty_termios_copy_hw +EXPORT_SYMBOL vmlinux 0x30fe83a7 pci_remove_bus +EXPORT_SYMBOL vmlinux 0x3116e6d3 bdi_destroy +EXPORT_SYMBOL vmlinux 0x311c659e ip_mc_inc_group +EXPORT_SYMBOL vmlinux 0x3132f872 load_nls +EXPORT_SYMBOL vmlinux 0x3145216f pci_dev_present +EXPORT_SYMBOL vmlinux 0x3147857d default_red +EXPORT_SYMBOL vmlinux 0x315172a6 blk_alloc_queue_node +EXPORT_SYMBOL vmlinux 0x31616d67 textsearch_find_continuous +EXPORT_SYMBOL vmlinux 0x31855bbe kernel_getpeername +EXPORT_SYMBOL vmlinux 0x31b31f5c csum_partial_copy_nocheck +EXPORT_SYMBOL vmlinux 0x31b331f3 sock_i_uid +EXPORT_SYMBOL vmlinux 0x31ccfb97 sb_has_dirty_inodes +EXPORT_SYMBOL vmlinux 0x31cdfefa __nla_reserve_nohdr +EXPORT_SYMBOL vmlinux 0x31ebadcd in_group_p +EXPORT_SYMBOL vmlinux 0x322d76d1 neigh_destroy +EXPORT_SYMBOL vmlinux 0x322fe5bb pci_release_region +EXPORT_SYMBOL vmlinux 0x324094ae kick_iocb +EXPORT_SYMBOL vmlinux 0x326ba0c4 km_report +EXPORT_SYMBOL vmlinux 0x326d5bcd blk_put_request +EXPORT_SYMBOL vmlinux 0x3285b00f neigh_event_ns +EXPORT_SYMBOL vmlinux 0x32b1b647 register_snap_client +EXPORT_SYMBOL vmlinux 0x32d01fec acpi_attach_data +EXPORT_SYMBOL vmlinux 0x32ee1827 pci_add_new_bus +EXPORT_SYMBOL vmlinux 0x32f87920 inet_frag_kill +EXPORT_SYMBOL vmlinux 0x330d556f gnet_stats_copy_app +EXPORT_SYMBOL vmlinux 0x33421241 tcp_child_process +EXPORT_SYMBOL vmlinux 0x3360a963 param_set_ulong +EXPORT_SYMBOL vmlinux 0x33675053 xfrm_bundle_ok +EXPORT_SYMBOL vmlinux 0x33705bf9 tty_port_init +EXPORT_SYMBOL vmlinux 0x33830488 put_disk +EXPORT_SYMBOL vmlinux 0x33ab317c ilookup5 +EXPORT_SYMBOL vmlinux 0x33b84f74 copy_page +EXPORT_SYMBOL vmlinux 0x33c40c98 __dev_get_by_index +EXPORT_SYMBOL vmlinux 0x33cda660 posix_acl_from_mode +EXPORT_SYMBOL vmlinux 0x33d92f9a prepare_to_wait +EXPORT_SYMBOL vmlinux 0x3421272c efi +EXPORT_SYMBOL vmlinux 0x344d4366 per_cpu__softnet_data +EXPORT_SYMBOL vmlinux 0x3456b45d tty_flip_buffer_push +EXPORT_SYMBOL vmlinux 0x3491f153 elv_queue_empty +EXPORT_SYMBOL vmlinux 0x349cba85 strchr +EXPORT_SYMBOL vmlinux 0x34aba257 generic_file_aio_write_nolock +EXPORT_SYMBOL vmlinux 0x34c1babf swiotlb_sync_sg_for_cpu +EXPORT_SYMBOL vmlinux 0x34faa7ac blk_queue_invalidate_tags +EXPORT_SYMBOL vmlinux 0x3509f037 pci_choose_state +EXPORT_SYMBOL vmlinux 0x3516e788 input_unregister_handle +EXPORT_SYMBOL vmlinux 0x352a325e inet_unregister_protosw +EXPORT_SYMBOL vmlinux 0x353cc2f1 tty_throttle +EXPORT_SYMBOL vmlinux 0x3544f184 tcp_read_sock +EXPORT_SYMBOL vmlinux 0x3573be36 agp_generic_type_to_mask_type +EXPORT_SYMBOL vmlinux 0x3580f9b6 dev_unicast_delete +EXPORT_SYMBOL vmlinux 0x35a07e32 vfs_stat +EXPORT_SYMBOL vmlinux 0x35b0650f vsnprintf +EXPORT_SYMBOL vmlinux 0x35c2ba9e refrigerator +EXPORT_SYMBOL vmlinux 0x360b1afe probe_irq_mask +EXPORT_SYMBOL vmlinux 0x36139a51 memcpy_fromiovec +EXPORT_SYMBOL vmlinux 0x362f045c node_data +EXPORT_SYMBOL vmlinux 0x363ad247 cap_set_effective +EXPORT_SYMBOL vmlinux 0x364e2dd2 neigh_ifdown +EXPORT_SYMBOL vmlinux 0x36509e1d block_page_mkwrite +EXPORT_SYMBOL vmlinux 0x3652cf8a __xfrm_policy_check +EXPORT_SYMBOL vmlinux 0x3656bf5a lock_kernel +EXPORT_SYMBOL vmlinux 0x365bcea3 d_alloc_anon +EXPORT_SYMBOL vmlinux 0x367478aa kmem_cache_destroy +EXPORT_SYMBOL vmlinux 0x36834ccb iw_handler_get_spy +EXPORT_SYMBOL vmlinux 0x3686c0fb pci_find_device +EXPORT_SYMBOL vmlinux 0x369a9322 nla_put_nohdr +EXPORT_SYMBOL vmlinux 0x36ba200b inode_sub_bytes +EXPORT_SYMBOL vmlinux 0x36f72945 ps2_sendbyte +EXPORT_SYMBOL vmlinux 0x3701a196 csum_partial_copy_to_user +EXPORT_SYMBOL vmlinux 0x370d6961 acpi_match_device_ids +EXPORT_SYMBOL vmlinux 0x372369ce generic_file_splice_write_nolock +EXPORT_SYMBOL vmlinux 0x372f8750 dev_mc_unsync +EXPORT_SYMBOL vmlinux 0x3740ff9d bio_put +EXPORT_SYMBOL vmlinux 0x3744cf36 vmalloc_to_pfn +EXPORT_SYMBOL vmlinux 0x375465a7 radix_tree_gang_lookup_tag_slot +EXPORT_SYMBOL vmlinux 0x37befc70 jiffies_to_msecs +EXPORT_SYMBOL vmlinux 0x37c373bf cfb_fillrect +EXPORT_SYMBOL vmlinux 0x37d555d1 vfs_statfs +EXPORT_SYMBOL vmlinux 0x37dbcf6b blk_queue_stack_limits +EXPORT_SYMBOL vmlinux 0x37df03da xfrm_state_lookup +EXPORT_SYMBOL vmlinux 0x3850337f swiotlb_unmap_single +EXPORT_SYMBOL vmlinux 0x385ee2d2 bio_integrity_endio +EXPORT_SYMBOL vmlinux 0x3861ac8b framebuffer_alloc +EXPORT_SYMBOL vmlinux 0x388efd63 tcp_proc_unregister +EXPORT_SYMBOL vmlinux 0x38b92846 llc_remove_pack +EXPORT_SYMBOL vmlinux 0x38bc4123 sock_register +EXPORT_SYMBOL vmlinux 0x38e8b52d d_delete +EXPORT_SYMBOL vmlinux 0x38f33bed dump_fpu +EXPORT_SYMBOL vmlinux 0x39170a6c acpi_check_resource_conflict +EXPORT_SYMBOL vmlinux 0x39291a03 tcf_hash_search +EXPORT_SYMBOL vmlinux 0x39415277 dev_alloc_skb +EXPORT_SYMBOL vmlinux 0x396d5ee8 input_free_device +EXPORT_SYMBOL vmlinux 0x3971dde8 unregister_binfmt +EXPORT_SYMBOL vmlinux 0x3980aac1 unregister_reboot_notifier +EXPORT_SYMBOL vmlinux 0x39b25ffb dma_sync_wait +EXPORT_SYMBOL vmlinux 0x39c16f1e release_firmware +EXPORT_SYMBOL vmlinux 0x39cd891a __down_write_trylock +EXPORT_SYMBOL vmlinux 0x3a1b195a __generic_unplug_device +EXPORT_SYMBOL vmlinux 0x3a2204c6 security_netlink_recv +EXPORT_SYMBOL vmlinux 0x3a539bfb inode_init_once +EXPORT_SYMBOL vmlinux 0x3a8f42fe pci_find_next_bus +EXPORT_SYMBOL vmlinux 0x3a9b6fb9 blk_unregister_region +EXPORT_SYMBOL vmlinux 0x3aa1dbcf _spin_unlock_bh +EXPORT_SYMBOL vmlinux 0x3aaea436 __dev_get_by_name +EXPORT_SYMBOL vmlinux 0x3ad9f179 __set_page_dirty_nobuffers +EXPORT_SYMBOL vmlinux 0x3b06bc64 pcim_iomap_table +EXPORT_SYMBOL vmlinux 0x3b241c39 pcie_port_service_unregister +EXPORT_SYMBOL vmlinux 0x3b2ddb19 lock_rename +EXPORT_SYMBOL vmlinux 0x3b3016d3 cpufreq_unregister_notifier +EXPORT_SYMBOL vmlinux 0x3b635e5d backlight_device_register +EXPORT_SYMBOL vmlinux 0x3b63a26b tty_insert_flip_string +EXPORT_SYMBOL vmlinux 0x3b67cbbf __init_rwsem +EXPORT_SYMBOL vmlinux 0x3b6839a6 ethtool_op_get_sg +EXPORT_SYMBOL vmlinux 0x3b9e0ae4 bdevname +EXPORT_SYMBOL vmlinux 0x3ba67189 fget +EXPORT_SYMBOL vmlinux 0x3bb00fd0 elv_add_request +EXPORT_SYMBOL vmlinux 0x3bcba798 gnet_stats_copy_queue +EXPORT_SYMBOL vmlinux 0x3bd1b1f6 msecs_to_jiffies +EXPORT_SYMBOL vmlinux 0x3bf2f65a agp_backend_acquire +EXPORT_SYMBOL vmlinux 0x3c10be47 security_inode_init_security +EXPORT_SYMBOL vmlinux 0x3c2c5af5 sprintf +EXPORT_SYMBOL vmlinux 0x3c40b192 __sk_mem_reclaim +EXPORT_SYMBOL vmlinux 0x3c43dcd7 seq_release_private +EXPORT_SYMBOL vmlinux 0x3c6ed352 posix_lock_file_wait +EXPORT_SYMBOL vmlinux 0x3c7227bf complete_all +EXPORT_SYMBOL vmlinux 0x3c7e58d4 ethtool_op_set_tso +EXPORT_SYMBOL vmlinux 0x3c821eea create_empty_buffers +EXPORT_SYMBOL vmlinux 0x3c958b39 unregister_framebuffer +EXPORT_SYMBOL vmlinux 0x3c96f2a7 inet_sock_destruct +EXPORT_SYMBOL vmlinux 0x3cb8a495 param_get_string +EXPORT_SYMBOL vmlinux 0x3cc0a3bb xfrm_spd_getinfo +EXPORT_SYMBOL vmlinux 0x3cc31e07 skb_abort_seq_read +EXPORT_SYMBOL vmlinux 0x3cda15d0 agp_generic_alloc_page +EXPORT_SYMBOL vmlinux 0x3ce4ca6f disable_irq +EXPORT_SYMBOL vmlinux 0x3cfdba79 __rta_fill +EXPORT_SYMBOL vmlinux 0x3d32d0d7 udp_prot +EXPORT_SYMBOL vmlinux 0x3d6f4f80 pci_save_state +EXPORT_SYMBOL vmlinux 0x3d808af7 lock_super +EXPORT_SYMBOL vmlinux 0x3d9ee9f0 clear_page +EXPORT_SYMBOL vmlinux 0x3da171f9 pci_mem_start +EXPORT_SYMBOL vmlinux 0x3da5eb6d kfifo_alloc +EXPORT_SYMBOL vmlinux 0x3db2e258 radix_tree_gang_lookup +EXPORT_SYMBOL vmlinux 0x3db4b13d simple_dir_inode_operations +EXPORT_SYMBOL vmlinux 0x3ddb50cc bio_integrity_alloc_bioset +EXPORT_SYMBOL vmlinux 0x3de3f7b5 fd_install +EXPORT_SYMBOL vmlinux 0x3e076c0f kernel_connect +EXPORT_SYMBOL vmlinux 0x3e1f073d wait_for_completion_timeout +EXPORT_SYMBOL vmlinux 0x3e219de6 try_wait_for_completion +EXPORT_SYMBOL vmlinux 0x3e2427a1 acpi_check_region +EXPORT_SYMBOL vmlinux 0x3e2a63fa sk_stream_kill_queues +EXPORT_SYMBOL vmlinux 0x3e2ae3a8 acpi_release_global_lock +EXPORT_SYMBOL vmlinux 0x3e427531 pnp_device_detach +EXPORT_SYMBOL vmlinux 0x3e45e9ff register_inetaddr_notifier +EXPORT_SYMBOL vmlinux 0x3e5f0bad __bforget +EXPORT_SYMBOL vmlinux 0x3e805830 page_readlink +EXPORT_SYMBOL vmlinux 0x3e9e57d5 d_validate +EXPORT_SYMBOL vmlinux 0x3ea31414 bio_add_page +EXPORT_SYMBOL vmlinux 0x3eac1bc2 udp_lib_setsockopt +EXPORT_SYMBOL vmlinux 0x3ed63055 zlib_inflateReset +EXPORT_SYMBOL vmlinux 0x3f0546a8 ioread32_rep +EXPORT_SYMBOL vmlinux 0x3f1899f1 up +EXPORT_SYMBOL vmlinux 0x3f4547a7 put_unused_fd +EXPORT_SYMBOL vmlinux 0x3f5111b8 block_truncate_page +EXPORT_SYMBOL vmlinux 0x3f57e84a inet_accept +EXPORT_SYMBOL vmlinux 0x3fa2fc00 fb_set_var +EXPORT_SYMBOL vmlinux 0x3fa913da strspn +EXPORT_SYMBOL vmlinux 0x3faa8457 pci_request_region +EXPORT_SYMBOL vmlinux 0x3fab766a blk_dump_rq_flags +EXPORT_SYMBOL vmlinux 0x3fbcddc3 netdev_compute_features +EXPORT_SYMBOL vmlinux 0x3fd35619 generic_splice_sendpage +EXPORT_SYMBOL vmlinux 0x3fec048f sg_next +EXPORT_SYMBOL vmlinux 0x3ff62317 local_bh_disable +EXPORT_SYMBOL vmlinux 0x401e998a blk_queue_update_dma_alignment +EXPORT_SYMBOL vmlinux 0x40413642 tcp_connect +EXPORT_SYMBOL vmlinux 0x405c1144 get_seconds +EXPORT_SYMBOL vmlinux 0x407bde66 __dst_free +EXPORT_SYMBOL vmlinux 0x4087cd1b blk_get_backing_dev_info +EXPORT_SYMBOL vmlinux 0x40958f9f vfs_get_dqblk +EXPORT_SYMBOL vmlinux 0x409873e3 tty_termios_baud_rate +EXPORT_SYMBOL vmlinux 0x40c5ca55 sk_common_release +EXPORT_SYMBOL vmlinux 0x40c89d46 acpi_get_table_by_index +EXPORT_SYMBOL vmlinux 0x40dd8c9f uart_get_baud_rate +EXPORT_SYMBOL vmlinux 0x40e2cad5 register_tcf_proto_ops +EXPORT_SYMBOL vmlinux 0x4108e69a fb_match_mode +EXPORT_SYMBOL vmlinux 0x41482d8b strndup_user +EXPORT_SYMBOL vmlinux 0x41711c46 seq_puts +EXPORT_SYMBOL vmlinux 0x4188d439 neigh_rand_reach_time +EXPORT_SYMBOL vmlinux 0x41a7c227 schedule_delayed_work +EXPORT_SYMBOL vmlinux 0x41a991d3 shrink_dcache_sb +EXPORT_SYMBOL vmlinux 0x41a9c68d _spin_trylock_bh +EXPORT_SYMBOL vmlinux 0x41b8942e add_to_page_cache_locked +EXPORT_SYMBOL vmlinux 0x41ccc474 security_req_classify_flow +EXPORT_SYMBOL vmlinux 0x4211c3c1 zlib_inflateInit2 +EXPORT_SYMBOL vmlinux 0x42224298 sscanf +EXPORT_SYMBOL vmlinux 0x422c05d0 acpi_get_data +EXPORT_SYMBOL vmlinux 0x42a084ea blk_cleanup_queue +EXPORT_SYMBOL vmlinux 0x42a4bdf2 in_egroup_p +EXPORT_SYMBOL vmlinux 0x42b40b63 tcp_v4_do_rcv +EXPORT_SYMBOL vmlinux 0x42ff8385 do_munmap +EXPORT_SYMBOL vmlinux 0x4302d0eb free_pages +EXPORT_SYMBOL vmlinux 0x4327f0d5 memset_io +EXPORT_SYMBOL vmlinux 0x43385ad9 acpi_pci_unregister_driver +EXPORT_SYMBOL vmlinux 0x433aa697 generic_readlink +EXPORT_SYMBOL vmlinux 0x434561d8 unregister_netdev +EXPORT_SYMBOL vmlinux 0x434fa55c release_console_sem +EXPORT_SYMBOL vmlinux 0x43570bcf tcf_generic_walker +EXPORT_SYMBOL vmlinux 0x4358aa14 end_buffer_write_sync +EXPORT_SYMBOL vmlinux 0x435b566d _spin_unlock +EXPORT_SYMBOL vmlinux 0x43698e39 skb_make_writable +EXPORT_SYMBOL vmlinux 0x436c2179 iowrite32 +EXPORT_SYMBOL vmlinux 0x438215a9 udp_proc_unregister +EXPORT_SYMBOL vmlinux 0x43916c6d generic_write_checks +EXPORT_SYMBOL vmlinux 0x4393e170 neigh_lookup +EXPORT_SYMBOL vmlinux 0x43bdd372 request_resource +EXPORT_SYMBOL vmlinux 0x43be8bf3 pci_prepare_to_sleep +EXPORT_SYMBOL vmlinux 0x43d4c9d1 blk_rq_unmap_user +EXPORT_SYMBOL vmlinux 0x43d66d3a unlock_new_inode +EXPORT_SYMBOL vmlinux 0x43eb56b7 new_inode +EXPORT_SYMBOL vmlinux 0x43ec913a put_cmsg +EXPORT_SYMBOL vmlinux 0x43ef8119 kmem_cache_alloc_node +EXPORT_SYMBOL vmlinux 0x43f49573 arp_broken_ops +EXPORT_SYMBOL vmlinux 0x44161c19 unregister_shrinker +EXPORT_SYMBOL vmlinux 0x44416efa seq_lseek +EXPORT_SYMBOL vmlinux 0x44455db6 find_get_pages_contig +EXPORT_SYMBOL vmlinux 0x444779c4 nla_find +EXPORT_SYMBOL vmlinux 0x4476ef7e register_chrdev +EXPORT_SYMBOL vmlinux 0x44aaf30f tsc_khz +EXPORT_SYMBOL vmlinux 0x44b911c3 rb_replace_node +EXPORT_SYMBOL vmlinux 0x44d560e3 init_level4_pgt +EXPORT_SYMBOL vmlinux 0x44f95e87 inode_double_unlock +EXPORT_SYMBOL vmlinux 0x4550ba8a register_cpu_notifier +EXPORT_SYMBOL vmlinux 0x455fd57d acpi_set_register +EXPORT_SYMBOL vmlinux 0x45704798 print_hex_dump_bytes +EXPORT_SYMBOL vmlinux 0x4572534c key_payload_reserve +EXPORT_SYMBOL vmlinux 0x457da49f d_rehash +EXPORT_SYMBOL vmlinux 0x457e7ce9 agp_find_bridge +EXPORT_SYMBOL vmlinux 0x45915126 serio_close +EXPORT_SYMBOL vmlinux 0x4592ea9e register_qdisc +EXPORT_SYMBOL vmlinux 0x45a79889 do_mmap_pgoff +EXPORT_SYMBOL vmlinux 0x45bb123e try_to_del_timer_sync +EXPORT_SYMBOL vmlinux 0x45d11c43 down_interruptible +EXPORT_SYMBOL vmlinux 0x45f4a3aa path_permission +EXPORT_SYMBOL vmlinux 0x462211c9 nf_log_register +EXPORT_SYMBOL vmlinux 0x463d9136 find_get_pages_tag +EXPORT_SYMBOL vmlinux 0x464b7070 cancel_dirty_page +EXPORT_SYMBOL vmlinux 0x466c14a7 __delay +EXPORT_SYMBOL vmlinux 0x468a7be7 kernel_setsockopt +EXPORT_SYMBOL vmlinux 0x469e57da blk_init_queue_node +EXPORT_SYMBOL vmlinux 0x46c47fb6 __node_distance +EXPORT_SYMBOL vmlinux 0x46f0a87c __mod_zone_page_state +EXPORT_SYMBOL vmlinux 0x46f53f77 dump_trace +EXPORT_SYMBOL vmlinux 0x47445f17 devm_free_irq +EXPORT_SYMBOL vmlinux 0x475100c2 inet_get_local_port_range +EXPORT_SYMBOL vmlinux 0x475f010b acpi_purge_cached_objects +EXPORT_SYMBOL vmlinux 0x475f05af acpi_set_firmware_waking_vector +EXPORT_SYMBOL vmlinux 0x47634d83 agp_enable +EXPORT_SYMBOL vmlinux 0x477c990d agp_alloc_bridge +EXPORT_SYMBOL vmlinux 0x478239cf follow_up +EXPORT_SYMBOL vmlinux 0x478d10b2 ht_destroy_irq +EXPORT_SYMBOL vmlinux 0x47939e0d __tasklet_hi_schedule +EXPORT_SYMBOL vmlinux 0x479c3c86 find_next_zero_bit +EXPORT_SYMBOL vmlinux 0x47c7a7d1 block_read_full_page +EXPORT_SYMBOL vmlinux 0x481cb9ab acpi_enter_sleep_state_prep +EXPORT_SYMBOL vmlinux 0x4822990e udp_lib_getsockopt +EXPORT_SYMBOL vmlinux 0x48389354 uart_add_one_port +EXPORT_SYMBOL vmlinux 0x483af8d0 pci_iomap +EXPORT_SYMBOL vmlinux 0x4859b8bb rtc_year_days +EXPORT_SYMBOL vmlinux 0x486a35df blk_rq_map_sg +EXPORT_SYMBOL vmlinux 0x486b6407 hweight64 +EXPORT_SYMBOL vmlinux 0x48732822 d_invalidate +EXPORT_SYMBOL vmlinux 0x48824c11 elv_rb_former_request +EXPORT_SYMBOL vmlinux 0x4895effc tcp_proc_register +EXPORT_SYMBOL vmlinux 0x48a8a9c4 swiotlb_sync_single_for_cpu +EXPORT_SYMBOL vmlinux 0x48df9556 put_page +EXPORT_SYMBOL vmlinux 0x48e209f0 rtnl_create_link +EXPORT_SYMBOL vmlinux 0x48fa6671 tcp_initialize_rcv_mss +EXPORT_SYMBOL vmlinux 0x492f53ce xfrm_unregister_type +EXPORT_SYMBOL vmlinux 0x493e25e1 udp_hash +EXPORT_SYMBOL vmlinux 0x495e1ee8 generic_unplug_device +EXPORT_SYMBOL vmlinux 0x49603fb8 security_sb_copy_data +EXPORT_SYMBOL vmlinux 0x496082ac blk_integrity_register +EXPORT_SYMBOL vmlinux 0x496d6048 __skb_checksum_complete +EXPORT_SYMBOL vmlinux 0x49ae7671 do_sync_read +EXPORT_SYMBOL vmlinux 0x49d86741 block_write_begin +EXPORT_SYMBOL vmlinux 0x49da9a9a _read_unlock_bh +EXPORT_SYMBOL vmlinux 0x49ed5cd7 get_write_access +EXPORT_SYMBOL vmlinux 0x49f3f92f set_pages_wb +EXPORT_SYMBOL vmlinux 0x4a1df70f tty_hung_up_p +EXPORT_SYMBOL vmlinux 0x4a23935a submit_bio +EXPORT_SYMBOL vmlinux 0x4a258355 eth_header_cache +EXPORT_SYMBOL vmlinux 0x4a358252 __bitmap_subset +EXPORT_SYMBOL vmlinux 0x4a6ae63e directly_mappable_cdev_bdi +EXPORT_SYMBOL vmlinux 0x4a7d3a35 neigh_create +EXPORT_SYMBOL vmlinux 0x4aea4349 start_tty +EXPORT_SYMBOL vmlinux 0x4b07e779 _spin_unlock_irqrestore +EXPORT_SYMBOL vmlinux 0x4b085dbf agp3_generic_configure +EXPORT_SYMBOL vmlinux 0x4b2f14b4 jiffies_to_timespec +EXPORT_SYMBOL vmlinux 0x4b41395e wait_on_sync_kiocb +EXPORT_SYMBOL vmlinux 0x4b5c47fe sock_queue_rcv_skb +EXPORT_SYMBOL vmlinux 0x4b77c0d1 tcf_hash_insert +EXPORT_SYMBOL vmlinux 0x4b8353a3 dma_pool_free +EXPORT_SYMBOL vmlinux 0x4b971ad2 sk_send_sigurg +EXPORT_SYMBOL vmlinux 0x4ba5baa0 load_gs_index +EXPORT_SYMBOL vmlinux 0x4bbc3e5f pm_flags +EXPORT_SYMBOL vmlinux 0x4bc7c776 acpi_lock_ac_dir +EXPORT_SYMBOL vmlinux 0x4bd30066 alloc_fddidev +EXPORT_SYMBOL vmlinux 0x4bd540dd agp_bind_memory +EXPORT_SYMBOL vmlinux 0x4bdf028e idr_find +EXPORT_SYMBOL vmlinux 0x4c10f276 blk_queue_start_tag +EXPORT_SYMBOL vmlinux 0x4c1182cb bitmap_scnprintf +EXPORT_SYMBOL vmlinux 0x4c15c799 prepare_binprm +EXPORT_SYMBOL vmlinux 0x4c3af445 __request_region +EXPORT_SYMBOL vmlinux 0x4c3fc4f9 kill_litter_super +EXPORT_SYMBOL vmlinux 0x4c4c956e nla_memcmp +EXPORT_SYMBOL vmlinux 0x4cbbd171 __bitmap_weight +EXPORT_SYMBOL vmlinux 0x4cf9a740 security_sb_clone_mnt_opts +EXPORT_SYMBOL vmlinux 0x4d0fc892 __set_page_dirty_buffers +EXPORT_SYMBOL vmlinux 0x4d392ff5 pci_dev_get +EXPORT_SYMBOL vmlinux 0x4d548b28 __getblk +EXPORT_SYMBOL vmlinux 0x4d82b657 __secpath_destroy +EXPORT_SYMBOL vmlinux 0x4db1e1d4 posix_acl_equiv_mode +EXPORT_SYMBOL vmlinux 0x4dc2a7bc truncate_inode_pages_range +EXPORT_SYMBOL vmlinux 0x4dda726b match_strlcpy +EXPORT_SYMBOL vmlinux 0x4ddc4b9f utf8_mbtowc +EXPORT_SYMBOL vmlinux 0x4df119fa __bitmap_parse +EXPORT_SYMBOL vmlinux 0x4df47e9f xfrm_state_flush +EXPORT_SYMBOL vmlinux 0x4e100f60 _spin_unlock_irq +EXPORT_SYMBOL vmlinux 0x4e3567f7 match_int +EXPORT_SYMBOL vmlinux 0x4e55331d blk_unplug +EXPORT_SYMBOL vmlinux 0x4e5dc447 skb_dequeue +EXPORT_SYMBOL vmlinux 0x4e6e8ea7 fg_console +EXPORT_SYMBOL vmlinux 0x4eab2647 mntput_no_expire +EXPORT_SYMBOL vmlinux 0x4ec0792a inet_csk_reset_keepalive_timer +EXPORT_SYMBOL vmlinux 0x4edd72f7 block_all_signals +EXPORT_SYMBOL vmlinux 0x4f0b1f30 dst_alloc +EXPORT_SYMBOL vmlinux 0x4f5438c1 idle_halt +EXPORT_SYMBOL vmlinux 0x4f7b02d4 tcp_make_synack +EXPORT_SYMBOL vmlinux 0x4fa75270 inet_frags_fini +EXPORT_SYMBOL vmlinux 0x4fcee107 __up_read +EXPORT_SYMBOL vmlinux 0x4fdee897 i8042_command +EXPORT_SYMBOL vmlinux 0x500aa5b1 kernel_getsockname +EXPORT_SYMBOL vmlinux 0x50211ee3 tcp_free_md5sig_pool +EXPORT_SYMBOL vmlinux 0x503a3efe pci_unmap_rom +EXPORT_SYMBOL vmlinux 0x503c8340 fifo_create_dflt +EXPORT_SYMBOL vmlinux 0x5065881a uart_suspend_port +EXPORT_SYMBOL vmlinux 0x5074e297 pneigh_enqueue +EXPORT_SYMBOL vmlinux 0x50b5cb2d idr_get_new_above +EXPORT_SYMBOL vmlinux 0x50ba769a kblockd_schedule_work +EXPORT_SYMBOL vmlinux 0x50e893e9 xfrm_find_acq +EXPORT_SYMBOL vmlinux 0x50e91ba1 llc_set_station_handler +EXPORT_SYMBOL vmlinux 0x5113b071 __breadahead +EXPORT_SYMBOL vmlinux 0x5118c382 secure_dccp_sequence_number +EXPORT_SYMBOL vmlinux 0x511a070e pnp_release_card_device +EXPORT_SYMBOL vmlinux 0x5190cbe9 lookup_bdev +EXPORT_SYMBOL vmlinux 0x51d12d4e acpi_pci_disabled +EXPORT_SYMBOL vmlinux 0x51d7a776 acpi_detach_data +EXPORT_SYMBOL vmlinux 0x52026cdf security_sb_parse_opts_str +EXPORT_SYMBOL vmlinux 0x5212317c pci_set_dma_seg_boundary +EXPORT_SYMBOL vmlinux 0x521d63ec wait_for_key_construction +EXPORT_SYMBOL vmlinux 0x522f5573 pv_irq_ops +EXPORT_SYMBOL vmlinux 0x5252f304 __memcpy_toio +EXPORT_SYMBOL vmlinux 0x52728747 blk_init_tags +EXPORT_SYMBOL vmlinux 0x52a58c24 ifla_policy +EXPORT_SYMBOL vmlinux 0x52cbba4c create_proc_entry +EXPORT_SYMBOL vmlinux 0x52d7b2fd llc_sap_list +EXPORT_SYMBOL vmlinux 0x52db29e7 release_sock +EXPORT_SYMBOL vmlinux 0x52fa20c8 xfrm_policy_register_afinfo +EXPORT_SYMBOL vmlinux 0x530b1e98 pm_suspend +EXPORT_SYMBOL vmlinux 0x532f2924 param_get_byte +EXPORT_SYMBOL vmlinux 0x53326531 mempool_alloc_pages +EXPORT_SYMBOL vmlinux 0x533f9e15 devm_request_irq +EXPORT_SYMBOL vmlinux 0x5343b657 pagevec_lookup_tag +EXPORT_SYMBOL vmlinux 0x5394eced boot_cpu_data +EXPORT_SYMBOL vmlinux 0x53c0767c sk_chk_filter +EXPORT_SYMBOL vmlinux 0x53c09bf4 sk_release_kernel +EXPORT_SYMBOL vmlinux 0x53c1bc6c sync_dirty_buffer +EXPORT_SYMBOL vmlinux 0x53ff09fb pci_find_parent_resource +EXPORT_SYMBOL vmlinux 0x54290dc9 nla_validate +EXPORT_SYMBOL vmlinux 0x542c818f netlink_rcv_skb +EXPORT_SYMBOL vmlinux 0x542f6a04 tcp_tso_segment +EXPORT_SYMBOL vmlinux 0x543affb5 per_cpu__kstat +EXPORT_SYMBOL vmlinux 0x54aea442 d_find_alias +EXPORT_SYMBOL vmlinux 0x54b81541 init_timer_deferrable +EXPORT_SYMBOL vmlinux 0x54c075b6 iw_handler_set_thrspy +EXPORT_SYMBOL vmlinux 0x54c6a6f1 inet_select_addr +EXPORT_SYMBOL vmlinux 0x54cc0bda devm_ioremap +EXPORT_SYMBOL vmlinux 0x54e6fcdd net_enable_timestamp +EXPORT_SYMBOL vmlinux 0x550f8ade groups_alloc +EXPORT_SYMBOL vmlinux 0x552600da fsync_bdev +EXPORT_SYMBOL vmlinux 0x552d8241 eth_rebuild_header +EXPORT_SYMBOL vmlinux 0x5594be03 bitmap_remap +EXPORT_SYMBOL vmlinux 0x55d05f19 unregister_8022_client +EXPORT_SYMBOL vmlinux 0x55f151fe cap_netlink_recv +EXPORT_SYMBOL vmlinux 0x5600904f fb_get_color_depth +EXPORT_SYMBOL vmlinux 0x5635a60a vmalloc_user +EXPORT_SYMBOL vmlinux 0x566eab07 compat_ip_setsockopt +EXPORT_SYMBOL vmlinux 0x5675ee96 compute_creds +EXPORT_SYMBOL vmlinux 0x56895db1 vfs_quota_on_path +EXPORT_SYMBOL vmlinux 0x56a1951c kset_unregister +EXPORT_SYMBOL vmlinux 0x56f494e0 smp_call_function +EXPORT_SYMBOL vmlinux 0x570b27bd bdev_read_only +EXPORT_SYMBOL vmlinux 0x570fcf65 inode_permission +EXPORT_SYMBOL vmlinux 0x5724935d page_zero_new_buffers +EXPORT_SYMBOL vmlinux 0x572e85d4 blk_lookup_devt +EXPORT_SYMBOL vmlinux 0x574108ef inet_release +EXPORT_SYMBOL vmlinux 0x5749cbab skb_queue_purge +EXPORT_SYMBOL vmlinux 0x5752f472 pci_bus_type +EXPORT_SYMBOL vmlinux 0x577cc638 mutex_unlock +EXPORT_SYMBOL vmlinux 0x5782e706 __kill_fasync +EXPORT_SYMBOL vmlinux 0x579b9ae6 dev_get_flags +EXPORT_SYMBOL vmlinux 0x57a0870a agp_generic_create_gatt_table +EXPORT_SYMBOL vmlinux 0x57a14a6e vfs_getattr +EXPORT_SYMBOL vmlinux 0x5810f6f2 put_io_context +EXPORT_SYMBOL vmlinux 0x5838f6c9 rtc_valid_tm +EXPORT_SYMBOL vmlinux 0x584738f9 rdmsr_safe_on_cpu +EXPORT_SYMBOL vmlinux 0x5857b225 ioread16_rep +EXPORT_SYMBOL vmlinux 0x58a332b7 compat_sock_get_timestampns +EXPORT_SYMBOL vmlinux 0x58c8d4f1 nf_register_hooks +EXPORT_SYMBOL vmlinux 0x59129563 dquot_release +EXPORT_SYMBOL vmlinux 0x59199cdc tcf_exts_dump +EXPORT_SYMBOL vmlinux 0x5926b831 proto_unregister +EXPORT_SYMBOL vmlinux 0x5934392b fb_register_client +EXPORT_SYMBOL vmlinux 0x594bf15b ioport_map +EXPORT_SYMBOL vmlinux 0x5967c1ba netpoll_send_udp +EXPORT_SYMBOL vmlinux 0x599453a0 pci_unregister_driver +EXPORT_SYMBOL vmlinux 0x59a6ff40 pnp_activate_dev +EXPORT_SYMBOL vmlinux 0x59a74381 fddi_type_trans +EXPORT_SYMBOL vmlinux 0x59c100e9 fail_migrate_page +EXPORT_SYMBOL vmlinux 0x59cf829e inode_double_lock +EXPORT_SYMBOL vmlinux 0x59d140d7 proc_dostring +EXPORT_SYMBOL vmlinux 0x59d696b6 register_module_notifier +EXPORT_SYMBOL vmlinux 0x59da3c6f pci_enable_device_io +EXPORT_SYMBOL vmlinux 0x59ef1f23 pci_fixup_device +EXPORT_SYMBOL vmlinux 0x5a34a45c __kmalloc +EXPORT_SYMBOL vmlinux 0x5a3a0b8b inet_del_protocol +EXPORT_SYMBOL vmlinux 0x5a4896a8 __put_user_2 +EXPORT_SYMBOL vmlinux 0x5a527d4b ip_mc_dec_group +EXPORT_SYMBOL vmlinux 0x5a5e7ea3 simple_read_from_buffer +EXPORT_SYMBOL vmlinux 0x5a62ed47 inode_get_bytes +EXPORT_SYMBOL vmlinux 0x5a69219f __up_write +EXPORT_SYMBOL vmlinux 0x5a744b86 netlink_set_nonroot +EXPORT_SYMBOL vmlinux 0x5a824c9b generic_fillattr +EXPORT_SYMBOL vmlinux 0x5ab65ae7 km_policy_notify +EXPORT_SYMBOL vmlinux 0x5ac376a5 acpi_install_fixed_event_handler +EXPORT_SYMBOL vmlinux 0x5ae46c42 sock_create_lite +EXPORT_SYMBOL vmlinux 0x5b0945b6 pnp_register_card_driver +EXPORT_SYMBOL vmlinux 0x5b10dbf8 noop_qdisc +EXPORT_SYMBOL vmlinux 0x5b51c6a7 acpi_walk_resources +EXPORT_SYMBOL vmlinux 0x5b97c5f8 bio_split +EXPORT_SYMBOL vmlinux 0x5bacdbbc netdev_bonding_change +EXPORT_SYMBOL vmlinux 0x5bae2eac acpi_extract_package +EXPORT_SYMBOL vmlinux 0x5bec44cb __down_write +EXPORT_SYMBOL vmlinux 0x5befbfd3 inet_dgram_ops +EXPORT_SYMBOL vmlinux 0x5bf98e14 dev_set_allmulti +EXPORT_SYMBOL vmlinux 0x5c137694 tcp_sync_mss +EXPORT_SYMBOL vmlinux 0x5c46b6fa posix_acl_chmod_masq +EXPORT_SYMBOL vmlinux 0x5c65d7f6 register_nls +EXPORT_SYMBOL vmlinux 0x5c9a6c03 swiotlb_map_sg_attrs +EXPORT_SYMBOL vmlinux 0x5ca0000d schedule_delayed_work_on +EXPORT_SYMBOL vmlinux 0x5cc8e015 iov_iter_single_seg_count +EXPORT_SYMBOL vmlinux 0x5d113035 vm_stat +EXPORT_SYMBOL vmlinux 0x5d1d43dd dquot_commit_info +EXPORT_SYMBOL vmlinux 0x5d44d6c5 dev_kfree_skb_irq +EXPORT_SYMBOL vmlinux 0x5d559449 acpi_lock_battery_dir +EXPORT_SYMBOL vmlinux 0x5d5666fd page_symlink_inode_operations +EXPORT_SYMBOL vmlinux 0x5d6d7f16 kernel_bind +EXPORT_SYMBOL vmlinux 0x5d7320b1 __blk_run_queue +EXPORT_SYMBOL vmlinux 0x5d73b5f8 km_waitq +EXPORT_SYMBOL vmlinux 0x5d8a25aa sock_no_setsockopt +EXPORT_SYMBOL vmlinux 0x5dbcfa4f boot_cpu_physical_apicid +EXPORT_SYMBOL vmlinux 0x5e0f7602 pcix_set_mmrbc +EXPORT_SYMBOL vmlinux 0x5e2f2632 tty_write_room +EXPORT_SYMBOL vmlinux 0x5e372f4b __inet6_lookup_established +EXPORT_SYMBOL vmlinux 0x5e57c206 compat_sock_get_timestamp +EXPORT_SYMBOL vmlinux 0x5e79ebec gen_replace_estimator +EXPORT_SYMBOL vmlinux 0x5e7f6a25 tcp_setsockopt +EXPORT_SYMBOL vmlinux 0x5e8867a8 bh_uptodate_or_lock +EXPORT_SYMBOL vmlinux 0x5e9f09df get_io_context +EXPORT_SYMBOL vmlinux 0x5ea520c5 tcp_select_initial_window +EXPORT_SYMBOL vmlinux 0x5ec07152 skb_free_datagram +EXPORT_SYMBOL vmlinux 0x5ed040b0 pm_set_vt_switch +EXPORT_SYMBOL vmlinux 0x5edd0762 bin2bcd +EXPORT_SYMBOL vmlinux 0x5ee22164 block_is_partially_uptodate +EXPORT_SYMBOL vmlinux 0x5ef7e27d __inc_zone_page_state +EXPORT_SYMBOL vmlinux 0x5f317c0b arp_create +EXPORT_SYMBOL vmlinux 0x5f5f8b03 alloc_pages_current +EXPORT_SYMBOL vmlinux 0x5f73ba75 bdget +EXPORT_SYMBOL vmlinux 0x5fcb26f7 seq_open +EXPORT_SYMBOL vmlinux 0x5ff42b08 acpi_video_get_capabilities +EXPORT_SYMBOL vmlinux 0x600683d3 do_unblank_screen +EXPORT_SYMBOL vmlinux 0x6037ae52 pcim_pin_device +EXPORT_SYMBOL vmlinux 0x60400b7f pv_lock_ops +EXPORT_SYMBOL vmlinux 0x60477b53 generic_delete_inode +EXPORT_SYMBOL vmlinux 0x60492806 ethtool_op_set_ufo +EXPORT_SYMBOL vmlinux 0x604d1c98 end_buffer_read_sync +EXPORT_SYMBOL vmlinux 0x6053ccbf pid_task +EXPORT_SYMBOL vmlinux 0x60593e57 inet_sendmsg +EXPORT_SYMBOL vmlinux 0x605bdba3 module_put +EXPORT_SYMBOL vmlinux 0x605c8bde radix_tree_delete +EXPORT_SYMBOL vmlinux 0x608c2831 warn_on_slowpath +EXPORT_SYMBOL vmlinux 0x609f1c7e synchronize_net +EXPORT_SYMBOL vmlinux 0x60a32ea9 pm_power_off +EXPORT_SYMBOL vmlinux 0x60cf0637 skb_append_datato_frags +EXPORT_SYMBOL vmlinux 0x60da7694 agp_generic_insert_memory +EXPORT_SYMBOL vmlinux 0x60facb3b netlink_unicast +EXPORT_SYMBOL vmlinux 0x60fdd212 sock_common_getsockopt +EXPORT_SYMBOL vmlinux 0x6111e1bc init_timer +EXPORT_SYMBOL vmlinux 0x611a6f34 netpoll_cleanup +EXPORT_SYMBOL vmlinux 0x612390ad netpoll_set_trap +EXPORT_SYMBOL vmlinux 0x6141dde5 km_new_mapping +EXPORT_SYMBOL vmlinux 0x61567f48 serio_open +EXPORT_SYMBOL vmlinux 0x6159c44d request_key_async +EXPORT_SYMBOL vmlinux 0x616e6349 vfs_quota_off +EXPORT_SYMBOL vmlinux 0x618d8299 set_notify_swap_entry_free +EXPORT_SYMBOL vmlinux 0x61a02066 simple_readpage +EXPORT_SYMBOL vmlinux 0x61b7b126 simple_strtoull +EXPORT_SYMBOL vmlinux 0x61c1c365 unregister_key_type +EXPORT_SYMBOL vmlinux 0x62049256 acpi_disable +EXPORT_SYMBOL vmlinux 0x6225f204 filp_close +EXPORT_SYMBOL vmlinux 0x6226ed77 register_netdevice +EXPORT_SYMBOL vmlinux 0x6237f6b5 acpi_enable_event +EXPORT_SYMBOL vmlinux 0x62737e1d sock_unregister +EXPORT_SYMBOL vmlinux 0x62748e70 acpi_set_current_resources +EXPORT_SYMBOL vmlinux 0x62827bec security_secctx_to_secid +EXPORT_SYMBOL vmlinux 0x62e7bc79 blk_start_queueing +EXPORT_SYMBOL vmlinux 0x6334052a xfrm4_rcv_encap +EXPORT_SYMBOL vmlinux 0x63499009 pci_assign_resource +EXPORT_SYMBOL vmlinux 0x6355bac4 dst_destroy +EXPORT_SYMBOL vmlinux 0x63694ce7 key_unlink +EXPORT_SYMBOL vmlinux 0x636a5691 acpi_register_ioapic +EXPORT_SYMBOL vmlinux 0x638675b4 swiotlb_sync_single_for_device +EXPORT_SYMBOL vmlinux 0x6397ca94 inet_stream_connect +EXPORT_SYMBOL vmlinux 0x63ba6312 skb_recv_datagram +EXPORT_SYMBOL vmlinux 0x63c56dc0 dev_unicast_add +EXPORT_SYMBOL vmlinux 0x63ecad53 register_netdevice_notifier +EXPORT_SYMBOL vmlinux 0x63ed4f65 ioremap_cache +EXPORT_SYMBOL vmlinux 0x63f1d58f request_key_async_with_auxdata +EXPORT_SYMBOL vmlinux 0x63fc232f strlen_user +EXPORT_SYMBOL vmlinux 0x6403e338 tcp_memory_pressure +EXPORT_SYMBOL vmlinux 0x6406156b skb_queue_head +EXPORT_SYMBOL vmlinux 0x640ae2c7 netpoll_setup +EXPORT_SYMBOL vmlinux 0x642e54ac __wake_up +EXPORT_SYMBOL vmlinux 0x643bfac1 find_task_by_pid_type_ns +EXPORT_SYMBOL vmlinux 0x644703ed sock_create_kern +EXPORT_SYMBOL vmlinux 0x644809c5 register_sysctl_paths +EXPORT_SYMBOL vmlinux 0x6451294b posix_acl_valid +EXPORT_SYMBOL vmlinux 0x6466a1e6 mempool_alloc +EXPORT_SYMBOL vmlinux 0x6478134c ec_burst_enable +EXPORT_SYMBOL vmlinux 0x6482dd65 pci_bus_size_bridges +EXPORT_SYMBOL vmlinux 0x6492cc6e sg_miter_next +EXPORT_SYMBOL vmlinux 0x64999478 congestion_wait +EXPORT_SYMBOL vmlinux 0x64cd5d16 init_waitqueue_head +EXPORT_SYMBOL vmlinux 0x64ea1189 tcf_em_tree_validate +EXPORT_SYMBOL vmlinux 0x650128e7 br_fdb_get_hook +EXPORT_SYMBOL vmlinux 0x650fb346 add_wait_queue +EXPORT_SYMBOL vmlinux 0x65408378 zlib_inflate_blob +EXPORT_SYMBOL vmlinux 0x65414e67 dev_valid_name +EXPORT_SYMBOL vmlinux 0x656b8dfc netif_device_attach +EXPORT_SYMBOL vmlinux 0x65930cce pcim_enable_device +EXPORT_SYMBOL vmlinux 0x6615b0e3 vfs_dq_transfer +EXPORT_SYMBOL vmlinux 0x665eba3d kernel_recvmsg +EXPORT_SYMBOL vmlinux 0x66895f4c blk_verify_command +EXPORT_SYMBOL vmlinux 0x668da8d5 zlib_inflateIncomp +EXPORT_SYMBOL vmlinux 0x66b57a38 elv_dispatch_sort +EXPORT_SYMBOL vmlinux 0x66c0a7f6 blk_queue_max_hw_segments +EXPORT_SYMBOL vmlinux 0x66cac0ec ether_setup +EXPORT_SYMBOL vmlinux 0x671c7d41 call_usermodehelper_stdinpipe +EXPORT_SYMBOL vmlinux 0x672144bd strlcpy +EXPORT_SYMBOL vmlinux 0x6729d3df __get_user_4 +EXPORT_SYMBOL vmlinux 0x673f815e agp_bridges +EXPORT_SYMBOL vmlinux 0x6768497e pcim_iomap_regions +EXPORT_SYMBOL vmlinux 0x6782a2e5 cdev_alloc +EXPORT_SYMBOL vmlinux 0x67a10240 k8_northbridges +EXPORT_SYMBOL vmlinux 0x67b27ec1 tty_std_termios +EXPORT_SYMBOL vmlinux 0x67bf331d seq_open_private +EXPORT_SYMBOL vmlinux 0x67dd338f kthread_bind +EXPORT_SYMBOL vmlinux 0x67e71b77 __mutex_init +EXPORT_SYMBOL vmlinux 0x6826e8f2 bdi_register_dev +EXPORT_SYMBOL vmlinux 0x684f5e71 textsearch_unregister +EXPORT_SYMBOL vmlinux 0x687c3f59 icmp_send +EXPORT_SYMBOL vmlinux 0x688421c6 agp_bridge +EXPORT_SYMBOL vmlinux 0x689e14de compat_ip_getsockopt +EXPORT_SYMBOL vmlinux 0x68c2eb30 sock_no_socketpair +EXPORT_SYMBOL vmlinux 0x6907d4e9 idr_for_each +EXPORT_SYMBOL vmlinux 0x69192b5a iommu_num_pages +EXPORT_SYMBOL vmlinux 0x6925ce73 tty_unthrottle +EXPORT_SYMBOL vmlinux 0x695f9ac9 bd_set_size +EXPORT_SYMBOL vmlinux 0x6971447a rtc_month_days +EXPORT_SYMBOL vmlinux 0x697353be fb_blank +EXPORT_SYMBOL vmlinux 0x697b066f simple_write_begin +EXPORT_SYMBOL vmlinux 0x698d17d4 cdev_init +EXPORT_SYMBOL vmlinux 0x69927dff try_acquire_console_sem +EXPORT_SYMBOL vmlinux 0x69a0ca7d iowrite16be +EXPORT_SYMBOL vmlinux 0x6a037cf1 mempool_kfree +EXPORT_SYMBOL vmlinux 0x6a300ae5 remove_arg_zero +EXPORT_SYMBOL vmlinux 0x6a38f31a iov_iter_copy_from_user_atomic +EXPORT_SYMBOL vmlinux 0x6a43f317 acpi_bus_register_driver +EXPORT_SYMBOL vmlinux 0x6a47571d __set_personality +EXPORT_SYMBOL vmlinux 0x6a5f98a0 ida_get_new_above +EXPORT_SYMBOL vmlinux 0x6a5fa363 sigprocmask +EXPORT_SYMBOL vmlinux 0x6a78d717 nf_ct_attach +EXPORT_SYMBOL vmlinux 0x6a9ca5db kobject_get +EXPORT_SYMBOL vmlinux 0x6aadbdb7 blk_run_queue +EXPORT_SYMBOL vmlinux 0x6acb973d iowrite32be +EXPORT_SYMBOL vmlinux 0x6ad276b6 handle_sysrq +EXPORT_SYMBOL vmlinux 0x6add5c9a dmi_find_device +EXPORT_SYMBOL vmlinux 0x6af37040 pnp_possible_config +EXPORT_SYMBOL vmlinux 0x6afb950f proc_symlink +EXPORT_SYMBOL vmlinux 0x6b08e390 kmem_ptr_validate +EXPORT_SYMBOL vmlinux 0x6b1b67d3 __bdevname +EXPORT_SYMBOL vmlinux 0x6b2dc060 dump_stack +EXPORT_SYMBOL vmlinux 0x6b4e5a52 radix_tree_lookup_slot +EXPORT_SYMBOL vmlinux 0x6b8e83e1 poll_initwait +EXPORT_SYMBOL vmlinux 0x6b9b88f3 sleep_on +EXPORT_SYMBOL vmlinux 0x6bad91c0 sock_get_timestamp +EXPORT_SYMBOL vmlinux 0x6bafbced mod_timer +EXPORT_SYMBOL vmlinux 0x6bc56c67 radix_tree_next_hole +EXPORT_SYMBOL vmlinux 0x6bdcfd99 qdisc_class_hash_remove +EXPORT_SYMBOL vmlinux 0x6be934dd sock_wfree +EXPORT_SYMBOL vmlinux 0x6c03ddfb skb_kill_datagram +EXPORT_SYMBOL vmlinux 0x6c1066f3 __page_cache_alloc +EXPORT_SYMBOL vmlinux 0x6c389761 acpi_bus_get_private_data +EXPORT_SYMBOL vmlinux 0x6c50a24c arp_xmit +EXPORT_SYMBOL vmlinux 0x6c59a8b8 mpage_writepage +EXPORT_SYMBOL vmlinux 0x6c61ce70 num_registered_fb +EXPORT_SYMBOL vmlinux 0x6c702af7 sysctl_udp_rmem_min +EXPORT_SYMBOL vmlinux 0x6c768fb0 bio_pair_release +EXPORT_SYMBOL vmlinux 0x6c9bda15 pci_bus_add_devices +EXPORT_SYMBOL vmlinux 0x6cbe7632 posix_acl_to_xattr +EXPORT_SYMBOL vmlinux 0x6cf1d262 con_is_bound +EXPORT_SYMBOL vmlinux 0x6d0da34c param_get_short +EXPORT_SYMBOL vmlinux 0x6d11e3fc vfs_readv +EXPORT_SYMBOL vmlinux 0x6d1ced27 vcc_sklist_lock +EXPORT_SYMBOL vmlinux 0x6d27ef64 __bitmap_empty +EXPORT_SYMBOL vmlinux 0x6d294e43 clock_t_to_jiffies +EXPORT_SYMBOL vmlinux 0x6d2dfc61 scsi_cmd_ioctl +EXPORT_SYMBOL vmlinux 0x6d2f7425 tcp_timewait_state_process +EXPORT_SYMBOL vmlinux 0x6d334118 __get_user_8 +EXPORT_SYMBOL vmlinux 0x6d340f64 tty_termios_input_baud_rate +EXPORT_SYMBOL vmlinux 0x6d47d90d groups_free +EXPORT_SYMBOL vmlinux 0x6d6a5315 sock_no_accept +EXPORT_SYMBOL vmlinux 0x6d86f138 register_binfmt +EXPORT_SYMBOL vmlinux 0x6d9e5438 generic_read_dir +EXPORT_SYMBOL vmlinux 0x6db2c5ed is_bad_inode +EXPORT_SYMBOL vmlinux 0x6dc0c24b complete_and_exit +EXPORT_SYMBOL vmlinux 0x6de6bf83 radix_tree_lookup +EXPORT_SYMBOL vmlinux 0x6debff71 dev_mc_add +EXPORT_SYMBOL vmlinux 0x6def2db2 half_md4_transform +EXPORT_SYMBOL vmlinux 0x6e07a54e acpi_get_gpe_status +EXPORT_SYMBOL vmlinux 0x6e1a4bbb udp_hash_lock +EXPORT_SYMBOL vmlinux 0x6e20eada dev_disable_lro +EXPORT_SYMBOL vmlinux 0x6e57a640 inet_proto_csum_replace4 +EXPORT_SYMBOL vmlinux 0x6e5c88b0 kobject_del +EXPORT_SYMBOL vmlinux 0x6e634265 __sk_dst_check +EXPORT_SYMBOL vmlinux 0x6e67679e arp_tbl +EXPORT_SYMBOL vmlinux 0x6e720ff2 rtnl_unlock +EXPORT_SYMBOL vmlinux 0x6e7f3879 d_instantiate_unique +EXPORT_SYMBOL vmlinux 0x6e9dd606 __symbol_put +EXPORT_SYMBOL vmlinux 0x6e9f7e97 iov_iter_copy_from_user +EXPORT_SYMBOL vmlinux 0x6ead242b cond_resched_lock +EXPORT_SYMBOL vmlinux 0x6ebd8306 skb_copy_datagram_from_iovec +EXPORT_SYMBOL vmlinux 0x6eda0328 remove_proc_entry +EXPORT_SYMBOL vmlinux 0x6ee24c32 zero_fill_bio +EXPORT_SYMBOL vmlinux 0x6eeb97e9 qdisc_destroy +EXPORT_SYMBOL vmlinux 0x6f2474eb elv_rb_add +EXPORT_SYMBOL vmlinux 0x6f2cf09b tcp_v4_syn_recv_sock +EXPORT_SYMBOL vmlinux 0x6f4b6a66 con_set_default_unimap +EXPORT_SYMBOL vmlinux 0x6f5d6ad7 __inet6_hash +EXPORT_SYMBOL vmlinux 0x6f7b9cf1 per_cpu__cpu_info +EXPORT_SYMBOL vmlinux 0x6f93e46e sock_no_ioctl +EXPORT_SYMBOL vmlinux 0x6fc4b239 netlink_ack +EXPORT_SYMBOL vmlinux 0x6fcb87a1 touch_softlockup_watchdog +EXPORT_SYMBOL vmlinux 0x7008a9b7 timespec_to_jiffies +EXPORT_SYMBOL vmlinux 0x7034d267 skb_prepare_seq_read +EXPORT_SYMBOL vmlinux 0x7054a3e4 request_dma +EXPORT_SYMBOL vmlinux 0x70830857 __invalidate_device +EXPORT_SYMBOL vmlinux 0x70d8ab82 acpi_acquire_global_lock +EXPORT_SYMBOL vmlinux 0x70f14d15 generic_write_end +EXPORT_SYMBOL vmlinux 0x70f540d1 tcp_parse_options +EXPORT_SYMBOL vmlinux 0x7129e5f8 hex_asc +EXPORT_SYMBOL vmlinux 0x712aa29b _spin_lock_irqsave +EXPORT_SYMBOL vmlinux 0x71342640 blk_queue_bounce +EXPORT_SYMBOL vmlinux 0x71356fba remove_wait_queue +EXPORT_SYMBOL vmlinux 0x7150811f __seq_open_private +EXPORT_SYMBOL vmlinux 0x7171121c overflowgid +EXPORT_SYMBOL vmlinux 0x71a50dbc register_blkdev +EXPORT_SYMBOL vmlinux 0x71c45313 remap_vmalloc_range +EXPORT_SYMBOL vmlinux 0x71f6eb38 sg_copy_from_buffer +EXPORT_SYMBOL vmlinux 0x72207ad0 elv_rb_latter_request +EXPORT_SYMBOL vmlinux 0x72270e35 do_gettimeofday +EXPORT_SYMBOL vmlinux 0x7242e96d strnchr +EXPORT_SYMBOL vmlinux 0x729ec54a __alloc_pages_internal +EXPORT_SYMBOL vmlinux 0x729feaa1 __wait_on_buffer +EXPORT_SYMBOL vmlinux 0x72a795bc write_cache_pages +EXPORT_SYMBOL vmlinux 0x72b243d4 free_dma +EXPORT_SYMBOL vmlinux 0x72b3cbd5 ipv4_specific +EXPORT_SYMBOL vmlinux 0x72bc4179 agp_copy_info +EXPORT_SYMBOL vmlinux 0x72bf2140 mtrr_add +EXPORT_SYMBOL vmlinux 0x72df78b4 bh_submit_read +EXPORT_SYMBOL vmlinux 0x72e87387 kernel_sock_ioctl +EXPORT_SYMBOL vmlinux 0x735a0bd5 native_io_delay +EXPORT_SYMBOL vmlinux 0x7389c9a8 acpi_bus_get_power +EXPORT_SYMBOL vmlinux 0x739ee22d gen_pool_add +EXPORT_SYMBOL vmlinux 0x73bc7f6a kill_fasync +EXPORT_SYMBOL vmlinux 0x73e2a595 __scm_destroy +EXPORT_SYMBOL vmlinux 0x740a1b95 reserve_evntsel_nmi +EXPORT_SYMBOL vmlinux 0x740a36e6 vfs_get_dqinfo +EXPORT_SYMBOL vmlinux 0x74202777 ioremap_prot +EXPORT_SYMBOL vmlinux 0x7456b0d0 unregister_qdisc +EXPORT_SYMBOL vmlinux 0x7485e15e unregister_chrdev_region +EXPORT_SYMBOL vmlinux 0x748caf40 down +EXPORT_SYMBOL vmlinux 0x74cc1cbe unregister_cpu_notifier +EXPORT_SYMBOL vmlinux 0x74cc238d current_kernel_time +EXPORT_SYMBOL vmlinux 0x74e48b14 blk_complete_request +EXPORT_SYMBOL vmlinux 0x74fcae6e remap_pfn_range +EXPORT_SYMBOL vmlinux 0x7538b132 agp_off +EXPORT_SYMBOL vmlinux 0x756e6992 strnicmp +EXPORT_SYMBOL vmlinux 0x75bdea12 iommu_area_alloc +EXPORT_SYMBOL vmlinux 0x75ea9531 key_negate_and_link +EXPORT_SYMBOL vmlinux 0x75f7d5de acpi_bus_get_status +EXPORT_SYMBOL vmlinux 0x760a0f4f yield +EXPORT_SYMBOL vmlinux 0x760b437a unregister_inetaddr_notifier +EXPORT_SYMBOL vmlinux 0x7632c515 __kfree_skb +EXPORT_SYMBOL vmlinux 0x765adb05 fb_class +EXPORT_SYMBOL vmlinux 0x767dd8fd acpi_get_irq_routing_table +EXPORT_SYMBOL vmlinux 0x767ddb02 set_memory_wc +EXPORT_SYMBOL vmlinux 0x7693cb26 __neigh_event_send +EXPORT_SYMBOL vmlinux 0x76a83290 netif_carrier_on +EXPORT_SYMBOL vmlinux 0x76bf656d __bitmap_shift_left +EXPORT_SYMBOL vmlinux 0x76d03c8a generic_setlease +EXPORT_SYMBOL vmlinux 0x76d3cd60 laptop_mode +EXPORT_SYMBOL vmlinux 0x76f3f8a5 num_k8_northbridges +EXPORT_SYMBOL vmlinux 0x7712d13c qdisc_watchdog_init +EXPORT_SYMBOL vmlinux 0x77449a9b elv_rq_merge_ok +EXPORT_SYMBOL vmlinux 0x77452c0a uart_remove_one_port +EXPORT_SYMBOL vmlinux 0x77489bd3 register_key_type +EXPORT_SYMBOL vmlinux 0x77a108df _write_unlock_irqrestore +EXPORT_SYMBOL vmlinux 0x77dd1ba8 blk_integrity_unregister +EXPORT_SYMBOL vmlinux 0x77eb5848 vfs_set_dqinfo +EXPORT_SYMBOL vmlinux 0x77ecac9f zlib_inflateEnd +EXPORT_SYMBOL vmlinux 0x77f53abc acpi_get_vendor_resource +EXPORT_SYMBOL vmlinux 0x781b3007 fb_validate_mode +EXPORT_SYMBOL vmlinux 0x782e226c skb_copy +EXPORT_SYMBOL vmlinux 0x785148a3 idr_destroy +EXPORT_SYMBOL vmlinux 0x786858b4 task_nice +EXPORT_SYMBOL vmlinux 0x7876648c sock_release +EXPORT_SYMBOL vmlinux 0x78a484c9 _read_unlock_irqrestore +EXPORT_SYMBOL vmlinux 0x78ae6073 init_net +EXPORT_SYMBOL vmlinux 0x78c44d93 xfrm_state_register_afinfo +EXPORT_SYMBOL vmlinux 0x78df6bd7 no_pci_devices +EXPORT_SYMBOL vmlinux 0x79002a41 neigh_connected_output +EXPORT_SYMBOL vmlinux 0x794c1398 dmi_check_system +EXPORT_SYMBOL vmlinux 0x794cacce sg_miter_start +EXPORT_SYMBOL vmlinux 0x79656409 cpu_online_map +EXPORT_SYMBOL vmlinux 0x799b0338 dev_driver_string +EXPORT_SYMBOL vmlinux 0x79aa04a2 get_random_bytes +EXPORT_SYMBOL vmlinux 0x79aa05a8 match_token +EXPORT_SYMBOL vmlinux 0x79b0144d close_bdev_excl +EXPORT_SYMBOL vmlinux 0x79ce1a0b try_to_free_buffers +EXPORT_SYMBOL vmlinux 0x79d78989 set_irq_chip +EXPORT_SYMBOL vmlinux 0x7a2a837d strict_strtol +EXPORT_SYMBOL vmlinux 0x7a36d6ca free_netdev +EXPORT_SYMBOL vmlinux 0x7a3e0db2 init_task +EXPORT_SYMBOL vmlinux 0x7a848702 _read_lock_irqsave +EXPORT_SYMBOL vmlinux 0x7aad16b2 alloc_etherdev_mq +EXPORT_SYMBOL vmlinux 0x7ab4b211 llc_mac_hdr_init +EXPORT_SYMBOL vmlinux 0x7abb01e6 dev_alloc_name +EXPORT_SYMBOL vmlinux 0x7ae26053 input_register_handler +EXPORT_SYMBOL vmlinux 0x7ae73de1 alloc_pages_exact +EXPORT_SYMBOL vmlinux 0x7aec9089 clear_user +EXPORT_SYMBOL vmlinux 0x7b0c84c4 acpi_remove_table_handler +EXPORT_SYMBOL vmlinux 0x7b52a859 wrmsr_safe_on_cpu +EXPORT_SYMBOL vmlinux 0x7b57e3db alloc_netdev_mq +EXPORT_SYMBOL vmlinux 0x7b759471 alloc_file +EXPORT_SYMBOL vmlinux 0x7b82c913 blk_queue_ordered +EXPORT_SYMBOL vmlinux 0x7b8f4c40 key_create_or_update +EXPORT_SYMBOL vmlinux 0x7bac9caf copy_strings_kernel +EXPORT_SYMBOL vmlinux 0x7bfd9907 agp_generic_free_gatt_table +EXPORT_SYMBOL vmlinux 0x7bff3be7 iov_iter_advance +EXPORT_SYMBOL vmlinux 0x7c14c409 skb_pull +EXPORT_SYMBOL vmlinux 0x7c21f7b4 bio_endio +EXPORT_SYMBOL vmlinux 0x7c3c7cf8 qdisc_class_hash_grow +EXPORT_SYMBOL vmlinux 0x7c46233a cpufreq_quick_get +EXPORT_SYMBOL vmlinux 0x7c60d66e getname +EXPORT_SYMBOL vmlinux 0x7c70d500 tcp_v4_md5_do_del +EXPORT_SYMBOL vmlinux 0x7c725bd8 __fatal_signal_pending +EXPORT_SYMBOL vmlinux 0x7c904ded unregister_module_notifier +EXPORT_SYMBOL vmlinux 0x7cb1ae69 cpu_down +EXPORT_SYMBOL vmlinux 0x7cb693b2 sock_setsockopt +EXPORT_SYMBOL vmlinux 0x7cd7e6e6 misc_deregister +EXPORT_SYMBOL vmlinux 0x7cdb981b ip_defrag +EXPORT_SYMBOL vmlinux 0x7d047e7e acpi_ut_exception +EXPORT_SYMBOL vmlinux 0x7d11c268 jiffies +EXPORT_SYMBOL vmlinux 0x7d64fdcf acpi_bus_start +EXPORT_SYMBOL vmlinux 0x7d698583 swiotlb_unmap_single_attrs +EXPORT_SYMBOL vmlinux 0x7d6e5a2e pci_set_power_state +EXPORT_SYMBOL vmlinux 0x7d84d232 sysctl_data +EXPORT_SYMBOL vmlinux 0x7d850612 utf8_mbstowcs +EXPORT_SYMBOL vmlinux 0x7d8e01cb do_splice_to +EXPORT_SYMBOL vmlinux 0x7d94f746 acpi_os_write_port +EXPORT_SYMBOL vmlinux 0x7da56a06 alloc_pci_dev +EXPORT_SYMBOL vmlinux 0x7dc8ef71 ilookup +EXPORT_SYMBOL vmlinux 0x7dcd35be blk_queue_merge_bvec +EXPORT_SYMBOL vmlinux 0x7dceceac capable +EXPORT_SYMBOL vmlinux 0x7dd2d084 ip_fragment +EXPORT_SYMBOL vmlinux 0x7ded3931 kill_pgrp +EXPORT_SYMBOL vmlinux 0x7e16c6db blk_requeue_request +EXPORT_SYMBOL vmlinux 0x7e25dbae pci_dev_put +EXPORT_SYMBOL vmlinux 0x7e3c84b8 ip_queue_xmit +EXPORT_SYMBOL vmlinux 0x7e8e9363 xfrm_nl +EXPORT_SYMBOL vmlinux 0x7e9a55ea xfrm_lookup +EXPORT_SYMBOL vmlinux 0x7e9ebb05 kernel_thread +EXPORT_SYMBOL vmlinux 0x7ebbe134 grab_cache_page_nowait +EXPORT_SYMBOL vmlinux 0x7ec9bfbc strncpy +EXPORT_SYMBOL vmlinux 0x7ecb5517 ps2_init +EXPORT_SYMBOL vmlinux 0x7ee91c1d _spin_trylock +EXPORT_SYMBOL vmlinux 0x7eeafd7c names_cachep +EXPORT_SYMBOL vmlinux 0x7ef92d6c ___pskb_trim +EXPORT_SYMBOL vmlinux 0x7efbe560 per_cpu__cpu_core_map +EXPORT_SYMBOL vmlinux 0x7f24de73 jiffies_to_usecs +EXPORT_SYMBOL vmlinux 0x7f293ce1 mark_page_accessed +EXPORT_SYMBOL vmlinux 0x7f3397b0 block_invalidatepage +EXPORT_SYMBOL vmlinux 0x7f60dd6e set_pages_nx +EXPORT_SYMBOL vmlinux 0x7f8723bd pcie_mch_quirk +EXPORT_SYMBOL vmlinux 0x7f9ca7d9 dentry_unhash +EXPORT_SYMBOL vmlinux 0x7fc4880f sync_inode +EXPORT_SYMBOL vmlinux 0x7fda79f0 d_prune_aliases +EXPORT_SYMBOL vmlinux 0x7fedbd8f console_stop +EXPORT_SYMBOL vmlinux 0x7ff17874 nf_getsockopt +EXPORT_SYMBOL vmlinux 0x7ff78ebe proc_doulongvec_ms_jiffies_minmax +EXPORT_SYMBOL vmlinux 0x80158208 sock_common_setsockopt +EXPORT_SYMBOL vmlinux 0x8022e7a7 dev_mc_sync +EXPORT_SYMBOL vmlinux 0x807af780 vfs_quota_sync +EXPORT_SYMBOL vmlinux 0x80f79a03 simple_rename +EXPORT_SYMBOL vmlinux 0x810fbf64 scm_fp_dup +EXPORT_SYMBOL vmlinux 0x814066cd find_lock_page +EXPORT_SYMBOL vmlinux 0x81409231 sock_i_ino +EXPORT_SYMBOL vmlinux 0x81472677 acpi_get_table +EXPORT_SYMBOL vmlinux 0x814e7730 nf_ct_destroy +EXPORT_SYMBOL vmlinux 0x815b5dd4 match_octal +EXPORT_SYMBOL vmlinux 0x815f2897 empty_zero_page +EXPORT_SYMBOL vmlinux 0x81be3fbc inet_ioctl +EXPORT_SYMBOL vmlinux 0x81c8f33e dma_async_memcpy_buf_to_pg +EXPORT_SYMBOL vmlinux 0x81df6172 skb_unlink +EXPORT_SYMBOL vmlinux 0x81e6b37f dmi_get_system_info +EXPORT_SYMBOL vmlinux 0x81ed6dbe pskb_copy +EXPORT_SYMBOL vmlinux 0x82072614 tasklet_kill +EXPORT_SYMBOL vmlinux 0x820d225f print_mac +EXPORT_SYMBOL vmlinux 0x8251bcc3 bitmap_release_region +EXPORT_SYMBOL vmlinux 0x828744bc make_EII_client +EXPORT_SYMBOL vmlinux 0x82a0aa6f bio_alloc +EXPORT_SYMBOL vmlinux 0x82a70d7d tty_name +EXPORT_SYMBOL vmlinux 0x82b40820 swiotlb_unmap_sg_attrs +EXPORT_SYMBOL vmlinux 0x82d53040 simple_pin_fs +EXPORT_SYMBOL vmlinux 0x82e9c083 csum_partial_copy_fromiovecend +EXPORT_SYMBOL vmlinux 0x8300c0db sock_no_bind +EXPORT_SYMBOL vmlinux 0x8317e20a completion_done +EXPORT_SYMBOL vmlinux 0x8344a050 posix_unblock_lock +EXPORT_SYMBOL vmlinux 0x8363c3d4 smp_call_function_mask +EXPORT_SYMBOL vmlinux 0x83800bfa kref_init +EXPORT_SYMBOL vmlinux 0x8381e9ce dev_getbyhwaddr +EXPORT_SYMBOL vmlinux 0x8395236c pci_dev_driver +EXPORT_SYMBOL vmlinux 0x83a476ce bitmap_scnlistprintf +EXPORT_SYMBOL vmlinux 0x84005c54 pcim_iounmap_regions +EXPORT_SYMBOL vmlinux 0x8408fe69 __serio_register_driver +EXPORT_SYMBOL vmlinux 0x84251ca9 f_setown +EXPORT_SYMBOL vmlinux 0x845fe06f nf_unregister_queue_handler +EXPORT_SYMBOL vmlinux 0x84d7f055 gnet_stats_start_copy_compat +EXPORT_SYMBOL vmlinux 0x8508869b current_fs_time +EXPORT_SYMBOL vmlinux 0x85348c80 ethtool_op_get_tso +EXPORT_SYMBOL vmlinux 0x8540ffeb xfrm_policy_byid +EXPORT_SYMBOL vmlinux 0x854427e6 udp_ioctl +EXPORT_SYMBOL vmlinux 0x85670f1d rtnl_is_locked +EXPORT_SYMBOL vmlinux 0x856ff879 ethtool_op_get_link +EXPORT_SYMBOL vmlinux 0x859b24ba acpi_is_video_device +EXPORT_SYMBOL vmlinux 0x859b768b bio_integrity_trim +EXPORT_SYMBOL vmlinux 0x85abc85f strncmp +EXPORT_SYMBOL vmlinux 0x85d1d0d5 path_lookup +EXPORT_SYMBOL vmlinux 0x85df9b6c strsep +EXPORT_SYMBOL vmlinux 0x8622fd49 xfrm_find_acq_byseq +EXPORT_SYMBOL vmlinux 0x8631f188 radix_tree_tag_set +EXPORT_SYMBOL vmlinux 0x863cb91a utf8_wcstombs +EXPORT_SYMBOL vmlinux 0x86612156 single_release +EXPORT_SYMBOL vmlinux 0x8664f62e cpufreq_update_policy +EXPORT_SYMBOL vmlinux 0x86713cd3 keyring_clear +EXPORT_SYMBOL vmlinux 0x8687e33e tcf_hash_create +EXPORT_SYMBOL vmlinux 0x868acba5 get_options +EXPORT_SYMBOL vmlinux 0x86a2ec10 blk_alloc_queue +EXPORT_SYMBOL vmlinux 0x86b1941b get_user_pages +EXPORT_SYMBOL vmlinux 0x86d8d8da audit_log_start +EXPORT_SYMBOL vmlinux 0x86fb9b05 bitmap_parse_user +EXPORT_SYMBOL vmlinux 0x87248639 destroy_EII_client +EXPORT_SYMBOL vmlinux 0x8727c879 genl_register_ops +EXPORT_SYMBOL vmlinux 0x8733e9a3 sleep_on_timeout +EXPORT_SYMBOL vmlinux 0x876dafc3 ec_write +EXPORT_SYMBOL vmlinux 0x8785725d param_set_charp +EXPORT_SYMBOL vmlinux 0x878615a0 swiotlb_map_sg +EXPORT_SYMBOL vmlinux 0x87888a99 locks_copy_lock +EXPORT_SYMBOL vmlinux 0x878ab3ce sysctl_tcp_adv_win_scale +EXPORT_SYMBOL vmlinux 0x8794e0ce __devm_release_region +EXPORT_SYMBOL vmlinux 0x87a750ac generic_block_bmap +EXPORT_SYMBOL vmlinux 0x87e05f3d sock_get_timestampns +EXPORT_SYMBOL vmlinux 0x87f0b4bd agp_generic_alloc_user +EXPORT_SYMBOL vmlinux 0x881039d0 zlib_inflate +EXPORT_SYMBOL vmlinux 0x881156d3 vfs_llseek +EXPORT_SYMBOL vmlinux 0x8850fd31 devm_ioremap_nocache +EXPORT_SYMBOL vmlinux 0x886ea253 swiotlb_alloc_coherent +EXPORT_SYMBOL vmlinux 0x88cbf4b6 nf_unregister_sockopt +EXPORT_SYMBOL vmlinux 0x8900fde6 wait_on_page_bit +EXPORT_SYMBOL vmlinux 0x89086584 sk_stream_write_space +EXPORT_SYMBOL vmlinux 0x892b26a0 set_memory_nx +EXPORT_SYMBOL vmlinux 0x894350bd tcp_v4_remember_stamp +EXPORT_SYMBOL vmlinux 0x894f1de9 ethtool_op_get_ufo +EXPORT_SYMBOL vmlinux 0x89503fd9 tcp_init_xmit_timers +EXPORT_SYMBOL vmlinux 0x8953bb27 del_timer +EXPORT_SYMBOL vmlinux 0x895469d3 pci_get_device +EXPORT_SYMBOL vmlinux 0x897473df mktime +EXPORT_SYMBOL vmlinux 0x898a713e tcf_exts_dump_stats +EXPORT_SYMBOL vmlinux 0x898b1fec mutex_trylock +EXPORT_SYMBOL vmlinux 0x89949018 down_timeout +EXPORT_SYMBOL vmlinux 0x89b232d1 sock_no_listen +EXPORT_SYMBOL vmlinux 0x89d5538d fb_pad_aligned_buffer +EXPORT_SYMBOL vmlinux 0x89d66811 build_ehash_secret +EXPORT_SYMBOL vmlinux 0x89e3ca41 kthread_stop +EXPORT_SYMBOL vmlinux 0x89ea052d vlan_ioctl_set +EXPORT_SYMBOL vmlinux 0x8a1a818f dev_get_by_index +EXPORT_SYMBOL vmlinux 0x8a3eabf0 __wait_on_bit +EXPORT_SYMBOL vmlinux 0x8a7d1c31 high_memory +EXPORT_SYMBOL vmlinux 0x8a90c927 bdi_unregister +EXPORT_SYMBOL vmlinux 0x8a90d932 allocate_resource +EXPORT_SYMBOL vmlinux 0x8a98232b vfs_path_lookup +EXPORT_SYMBOL vmlinux 0x8a99a016 mempool_free_slab +EXPORT_SYMBOL vmlinux 0x8aaf8654 mutex_lock +EXPORT_SYMBOL vmlinux 0x8ac40297 iommu_area_free +EXPORT_SYMBOL vmlinux 0x8af47b77 touch_atime +EXPORT_SYMBOL vmlinux 0x8b2ce3bb filemap_fdatawrite_range +EXPORT_SYMBOL vmlinux 0x8b2f862e sock_no_connect +EXPORT_SYMBOL vmlinux 0x8b35c568 atm_dev_register +EXPORT_SYMBOL vmlinux 0x8b35e873 sg_last +EXPORT_SYMBOL vmlinux 0x8b3ca835 cpu_present_map +EXPORT_SYMBOL vmlinux 0x8b50bd1c udp_memory_allocated +EXPORT_SYMBOL vmlinux 0x8b618d08 overflowuid +EXPORT_SYMBOL vmlinux 0x8b66bdbc uart_register_driver +EXPORT_SYMBOL vmlinux 0x8b7fe311 kmemdup +EXPORT_SYMBOL vmlinux 0x8b922c0f __strnlen_user +EXPORT_SYMBOL vmlinux 0x8b966b63 sn_rtc_cycles_per_second +EXPORT_SYMBOL vmlinux 0x8b96acd3 generic_file_open +EXPORT_SYMBOL vmlinux 0x8b989cf9 acpi_bus_can_wakeup +EXPORT_SYMBOL vmlinux 0x8bb2f3c8 ethtool_op_set_tx_hw_csum +EXPORT_SYMBOL vmlinux 0x8bb33e7d __release_region +EXPORT_SYMBOL vmlinux 0x8bfa0ced atm_init_aal5 +EXPORT_SYMBOL vmlinux 0x8c183cbe iowrite16 +EXPORT_SYMBOL vmlinux 0x8c5393c4 vfs_rename +EXPORT_SYMBOL vmlinux 0x8c5986da simple_release_fs +EXPORT_SYMBOL vmlinux 0x8c98f1c1 generic_cont_expand_simple +EXPORT_SYMBOL vmlinux 0x8cab4c47 bio_uncopy_user +EXPORT_SYMBOL vmlinux 0x8cb3fec3 nobh_write_begin +EXPORT_SYMBOL vmlinux 0x8cc79cab iowrite16_rep +EXPORT_SYMBOL vmlinux 0x8d3894f2 _ctype +EXPORT_SYMBOL vmlinux 0x8d4ab2f6 send_sig +EXPORT_SYMBOL vmlinux 0x8d551bef sysctl_tcp_rmem +EXPORT_SYMBOL vmlinux 0x8d6ac59e inet_stream_ops +EXPORT_SYMBOL vmlinux 0x8d7c30bf tcp_sendpage +EXPORT_SYMBOL vmlinux 0x8d8d96c6 acpi_get_sleep_type_data +EXPORT_SYMBOL vmlinux 0x8d8e7a97 tcp_ioctl +EXPORT_SYMBOL vmlinux 0x8db0c353 notify_change +EXPORT_SYMBOL vmlinux 0x8e002cda acpi_remove_gpe_block +EXPORT_SYMBOL vmlinux 0x8e0637ba i8253_lock +EXPORT_SYMBOL vmlinux 0x8e0b7743 ipv6_ext_hdr +EXPORT_SYMBOL vmlinux 0x8e3c9cc3 vprintk +EXPORT_SYMBOL vmlinux 0x8e449875 nla_append +EXPORT_SYMBOL vmlinux 0x8e63e42a ipv6_skip_exthdr +EXPORT_SYMBOL vmlinux 0x8e725985 nf_log_unregister_pf +EXPORT_SYMBOL vmlinux 0x8e930f4f unregister_tcf_proto_ops +EXPORT_SYMBOL vmlinux 0x8e98b8c5 __neigh_for_each_release +EXPORT_SYMBOL vmlinux 0x8e9f3161 uart_unregister_driver +EXPORT_SYMBOL vmlinux 0x8ee61ef0 cpufreq_gov_performance +EXPORT_SYMBOL vmlinux 0x8eef4aea should_remove_suid +EXPORT_SYMBOL vmlinux 0x8f031c95 xfrm_policy_alloc +EXPORT_SYMBOL vmlinux 0x8f1a10a4 __skb_checksum_complete_head +EXPORT_SYMBOL vmlinux 0x8f2b7e66 inet_sk_rebuild_header +EXPORT_SYMBOL vmlinux 0x8f39f14b dmam_free_noncoherent +EXPORT_SYMBOL vmlinux 0x8f400c5c kernel_sock_shutdown +EXPORT_SYMBOL vmlinux 0x8f6b7950 set_irq_data +EXPORT_SYMBOL vmlinux 0x8f6e7cd2 get_sb_nodev +EXPORT_SYMBOL vmlinux 0x8f7b895b make_bad_inode +EXPORT_SYMBOL vmlinux 0x8f84448d iget_locked +EXPORT_SYMBOL vmlinux 0x8f9c199c __get_user_2 +EXPORT_SYMBOL vmlinux 0x8fa0ed99 default_unplug_io_fn +EXPORT_SYMBOL vmlinux 0x90022b44 xfrm_policy_flush +EXPORT_SYMBOL vmlinux 0x90035333 secure_tcpv6_sequence_number +EXPORT_SYMBOL vmlinux 0x9015b5e0 generic_permission +EXPORT_SYMBOL vmlinux 0x90233375 input_release_device +EXPORT_SYMBOL vmlinux 0x9054927a input_register_device +EXPORT_SYMBOL vmlinux 0x9068a4d9 tcp_recvmsg +EXPORT_SYMBOL vmlinux 0x9070b3f2 ioport_resource +EXPORT_SYMBOL vmlinux 0x90a943ba nmi_active +EXPORT_SYMBOL vmlinux 0x90aa4adc unlock_page +EXPORT_SYMBOL vmlinux 0x90c96746 serio_rescan +EXPORT_SYMBOL vmlinux 0x90f2000c dev_get_by_name +EXPORT_SYMBOL vmlinux 0x9144a8e2 ec_burst_disable +EXPORT_SYMBOL vmlinux 0x91481982 __ratelimit +EXPORT_SYMBOL vmlinux 0x91607d95 set_memory_wb +EXPORT_SYMBOL vmlinux 0x917d3f3c sk_stream_wait_close +EXPORT_SYMBOL vmlinux 0x91a74ec3 registered_fb +EXPORT_SYMBOL vmlinux 0x91ca8959 acpi_get_register +EXPORT_SYMBOL vmlinux 0x91e03d25 filemap_write_and_wait +EXPORT_SYMBOL vmlinux 0x9211f26c tcf_em_tree_destroy +EXPORT_SYMBOL vmlinux 0x9212a1d7 pcix_get_max_mmrbc +EXPORT_SYMBOL vmlinux 0x92392cd9 iov_shorten +EXPORT_SYMBOL vmlinux 0x9252c8eb lock_sock_nested +EXPORT_SYMBOL vmlinux 0x92599728 dma_async_tx_descriptor_init +EXPORT_SYMBOL vmlinux 0x926cdff3 pci_enable_msix +EXPORT_SYMBOL vmlinux 0x927cf8df deny_write_access +EXPORT_SYMBOL vmlinux 0x927e989f gen_pool_alloc +EXPORT_SYMBOL vmlinux 0x92924f53 bio_integrity_alloc +EXPORT_SYMBOL vmlinux 0x92a1fee1 file_update_time +EXPORT_SYMBOL vmlinux 0x92cda47e skb_store_bits +EXPORT_SYMBOL vmlinux 0x92ea4ae4 crc32_le +EXPORT_SYMBOL vmlinux 0x92fe4055 pci_release_selected_regions +EXPORT_SYMBOL vmlinux 0x9305f8e6 cpufreq_get +EXPORT_SYMBOL vmlinux 0x931bba5a sock_kmalloc +EXPORT_SYMBOL vmlinux 0x93400cf1 input_set_keycode +EXPORT_SYMBOL vmlinux 0x936195d9 dev_add_pack +EXPORT_SYMBOL vmlinux 0x93a6e0b2 io_schedule +EXPORT_SYMBOL vmlinux 0x93afa72e vm_get_page_prot +EXPORT_SYMBOL vmlinux 0x93b8ef56 mutex_lock_interruptible +EXPORT_SYMBOL vmlinux 0x93bdc1cf dquot_transfer +EXPORT_SYMBOL vmlinux 0x93c69acf param_set_byte +EXPORT_SYMBOL vmlinux 0x93cbd1ec _spin_lock_bh +EXPORT_SYMBOL vmlinux 0x93ecfd0e tty_devnum +EXPORT_SYMBOL vmlinux 0x93fca811 __get_free_pages +EXPORT_SYMBOL vmlinux 0x93fdb82a init_file +EXPORT_SYMBOL vmlinux 0x93fff787 seq_release +EXPORT_SYMBOL vmlinux 0x940875ad tcp_v4_destroy_sock +EXPORT_SYMBOL vmlinux 0x940ec91b textsearch_register +EXPORT_SYMBOL vmlinux 0x943e868f ida_get_new +EXPORT_SYMBOL vmlinux 0x94439ad9 seq_read +EXPORT_SYMBOL vmlinux 0x94444edf tty_vhangup +EXPORT_SYMBOL vmlinux 0x944a5ea2 xfrm_prepare_input +EXPORT_SYMBOL vmlinux 0x945bc6a7 copy_from_user +EXPORT_SYMBOL vmlinux 0x945e5e54 d_alloc +EXPORT_SYMBOL vmlinux 0x9470a550 grab_cache_page_write_begin +EXPORT_SYMBOL vmlinux 0x94883ab2 gnet_stats_copy_rate_est +EXPORT_SYMBOL vmlinux 0x9492c2d3 agp_backend_release +EXPORT_SYMBOL vmlinux 0x94961283 vunmap +EXPORT_SYMBOL vmlinux 0x949fd41d __module_put_and_exit +EXPORT_SYMBOL vmlinux 0x94bd1d0c proc_dointvec_userhz_jiffies +EXPORT_SYMBOL vmlinux 0x94fcf08e bioset_create +EXPORT_SYMBOL vmlinux 0x95158526 ip_generic_getfrag +EXPORT_SYMBOL vmlinux 0x954488a4 syncookie_secret +EXPORT_SYMBOL vmlinux 0x9545af6d tasklet_init +EXPORT_SYMBOL vmlinux 0x954cbb26 vsprintf +EXPORT_SYMBOL vmlinux 0x95866011 do_SAK +EXPORT_SYMBOL vmlinux 0x95999216 tcp_shutdown +EXPORT_SYMBOL vmlinux 0x95a50df0 arp_send +EXPORT_SYMBOL vmlinux 0x95a568c1 freeze_bdev +EXPORT_SYMBOL vmlinux 0x95adf643 compat_nf_setsockopt +EXPORT_SYMBOL vmlinux 0x95ceb864 key_update +EXPORT_SYMBOL vmlinux 0x95dd999a gnet_stats_finish_copy +EXPORT_SYMBOL vmlinux 0x961c3a15 generic_file_readonly_mmap +EXPORT_SYMBOL vmlinux 0x962be501 redraw_screen +EXPORT_SYMBOL vmlinux 0x963bb6a1 pci_set_master +EXPORT_SYMBOL vmlinux 0x96481cc7 per_cpu__x86_cpu_to_apicid +EXPORT_SYMBOL vmlinux 0x965824c8 kmem_cache_name +EXPORT_SYMBOL vmlinux 0x96629d98 pci_get_bus_and_slot +EXPORT_SYMBOL vmlinux 0x9696d326 unregister_nls +EXPORT_SYMBOL vmlinux 0x96baac45 blk_register_region +EXPORT_SYMBOL vmlinux 0x96c7d23a wireless_send_event +EXPORT_SYMBOL vmlinux 0x96f33400 up_read +EXPORT_SYMBOL vmlinux 0x96fa4082 test_set_page_writeback +EXPORT_SYMBOL vmlinux 0x9703d98d blk_rq_append_bio +EXPORT_SYMBOL vmlinux 0x972d9a4d page_symlink +EXPORT_SYMBOL vmlinux 0x973873ab _spin_lock +EXPORT_SYMBOL vmlinux 0x974921ac agp_unbind_memory +EXPORT_SYMBOL vmlinux 0x9754ec10 radix_tree_preload +EXPORT_SYMBOL vmlinux 0x9788fb3f __dec_zone_page_state +EXPORT_SYMBOL vmlinux 0x97dc5dd3 neigh_changeaddr +EXPORT_SYMBOL vmlinux 0x97de0ddd acpi_install_gpe_block +EXPORT_SYMBOL vmlinux 0x9817d2ce xfrm_unregister_mode +EXPORT_SYMBOL vmlinux 0x981c5cbf sock_init_data +EXPORT_SYMBOL vmlinux 0x981e9721 security_sb_set_mnt_opts +EXPORT_SYMBOL vmlinux 0x984703c0 init_buffer +EXPORT_SYMBOL vmlinux 0x9865f54a cdev_del +EXPORT_SYMBOL vmlinux 0x986e6135 fb_pad_unaligned_buffer +EXPORT_SYMBOL vmlinux 0x988ed85d set_memory_x +EXPORT_SYMBOL vmlinux 0x98cb881e acpi_bus_get_device +EXPORT_SYMBOL vmlinux 0x990e54e4 unregister_filesystem +EXPORT_SYMBOL vmlinux 0x9994c0ca ps2_is_keyboard_id +EXPORT_SYMBOL vmlinux 0x999e8297 vfree +EXPORT_SYMBOL vmlinux 0x99aadb21 param_get_ulong +EXPORT_SYMBOL vmlinux 0x99bfbe39 get_unused_fd +EXPORT_SYMBOL vmlinux 0x99cdc86b sysctl_tcp_reordering +EXPORT_SYMBOL vmlinux 0x99ea12ce panic_blink +EXPORT_SYMBOL vmlinux 0x9a035c27 __napi_schedule +EXPORT_SYMBOL vmlinux 0x9a11afb1 dev_unicast_unsync +EXPORT_SYMBOL vmlinux 0x9a1dfd65 strpbrk +EXPORT_SYMBOL vmlinux 0x9a295b9b struct_module +EXPORT_SYMBOL vmlinux 0x9a58e3c2 pci_set_mwi +EXPORT_SYMBOL vmlinux 0x9a59a7cb bio_integrity_add_page +EXPORT_SYMBOL vmlinux 0x9a9985be percpu_counter_destroy +EXPORT_SYMBOL vmlinux 0x9ac30f38 blk_free_tags +EXPORT_SYMBOL vmlinux 0x9ad46346 sysctl_intvec +EXPORT_SYMBOL vmlinux 0x9af9829d vfs_symlink +EXPORT_SYMBOL vmlinux 0x9b025751 sk_run_filter +EXPORT_SYMBOL vmlinux 0x9b388444 get_zeroed_page +EXPORT_SYMBOL vmlinux 0x9b6408d6 gnet_stats_start_copy +EXPORT_SYMBOL vmlinux 0x9b877ffb netlink_kernel_create +EXPORT_SYMBOL vmlinux 0x9ba5dd6f generic_make_request +EXPORT_SYMBOL vmlinux 0x9ba7089d argv_split +EXPORT_SYMBOL vmlinux 0x9bbf70c7 ip_dev_find +EXPORT_SYMBOL vmlinux 0x9bc565c5 memcpy_fromiovecend +EXPORT_SYMBOL vmlinux 0x9bd7c1b6 follow_down +EXPORT_SYMBOL vmlinux 0x9be559a9 bio_integrity_clone +EXPORT_SYMBOL vmlinux 0x9c012508 fb_parse_edid +EXPORT_SYMBOL vmlinux 0x9c0ea3cd memscan +EXPORT_SYMBOL vmlinux 0x9c1bd24b blk_queue_max_segment_size +EXPORT_SYMBOL vmlinux 0x9c35f9b3 rtnl_notify +EXPORT_SYMBOL vmlinux 0x9c491f60 sg_alloc_table +EXPORT_SYMBOL vmlinux 0x9c4c5735 atm_dev_deregister +EXPORT_SYMBOL vmlinux 0x9c4df108 tcf_destroy_chain +EXPORT_SYMBOL vmlinux 0x9c7c1320 km_state_notify +EXPORT_SYMBOL vmlinux 0x9c8027bf __xfrm_decode_session +EXPORT_SYMBOL vmlinux 0x9c8e2966 mem_section +EXPORT_SYMBOL vmlinux 0x9c9dc702 km_state_expired +EXPORT_SYMBOL vmlinux 0x9ca95a0e sort +EXPORT_SYMBOL vmlinux 0x9cb96e92 qdisc_put_rtab +EXPORT_SYMBOL vmlinux 0x9cbbf787 kernel_sendpage +EXPORT_SYMBOL vmlinux 0x9ccb2622 finish_wait +EXPORT_SYMBOL vmlinux 0x9cd0e060 kfree_skb +EXPORT_SYMBOL vmlinux 0x9ceba535 dquot_free_inode +EXPORT_SYMBOL vmlinux 0x9ced38aa down_trylock +EXPORT_SYMBOL vmlinux 0x9d2441e5 sock_no_sendpage +EXPORT_SYMBOL vmlinux 0x9d33ef5e acpi_enable +EXPORT_SYMBOL vmlinux 0x9d3e75c1 sync_blockdev +EXPORT_SYMBOL vmlinux 0x9d4f5ac4 buffer_migrate_page +EXPORT_SYMBOL vmlinux 0x9d663c64 invalidate_inodes +EXPORT_SYMBOL vmlinux 0x9d711f1f percpu_counter_init +EXPORT_SYMBOL vmlinux 0x9d98f450 _cpu_pda +EXPORT_SYMBOL vmlinux 0x9da5612d uart_get_divisor +EXPORT_SYMBOL vmlinux 0x9db21624 hex_dump_to_buffer +EXPORT_SYMBOL vmlinux 0x9dd4d218 inet_register_protosw +EXPORT_SYMBOL vmlinux 0x9e00de31 tcp_v4_md5_lookup +EXPORT_SYMBOL vmlinux 0x9e05d1cc dev_remove_pack +EXPORT_SYMBOL vmlinux 0x9e0e3bf0 netif_rx_ni +EXPORT_SYMBOL vmlinux 0x9e2ffd96 dev_unicast_sync +EXPORT_SYMBOL vmlinux 0x9e535888 acpi_get_physical_device +EXPORT_SYMBOL vmlinux 0x9e64fbfe rtc_cmos_read +EXPORT_SYMBOL vmlinux 0x9e7d6bd0 __udelay +EXPORT_SYMBOL vmlinux 0x9ea0ad49 __sg_free_table +EXPORT_SYMBOL vmlinux 0x9ea23fad tcf_register_action +EXPORT_SYMBOL vmlinux 0x9ea28ec7 acpi_evaluate_object +EXPORT_SYMBOL vmlinux 0x9edbecae snprintf +EXPORT_SYMBOL vmlinux 0x9ee56ef6 tcp_simple_retransmit +EXPORT_SYMBOL vmlinux 0x9eecde16 do_brk +EXPORT_SYMBOL vmlinux 0x9ef749e2 unregister_chrdev +EXPORT_SYMBOL vmlinux 0x9f0e3bd3 eth_header +EXPORT_SYMBOL vmlinux 0x9f100139 jiffies_to_clock_t +EXPORT_SYMBOL vmlinux 0x9f17ad5f iw_handler_set_spy +EXPORT_SYMBOL vmlinux 0x9f26f470 generic_file_splice_write +EXPORT_SYMBOL vmlinux 0x9f2bdaac __bitmap_or +EXPORT_SYMBOL vmlinux 0x9f330c2f set_page_dirty +EXPORT_SYMBOL vmlinux 0x9f6b6587 inet_frags_exit_net +EXPORT_SYMBOL vmlinux 0x9f984513 strrchr +EXPORT_SYMBOL vmlinux 0x9fa274b4 dq_data_lock +EXPORT_SYMBOL vmlinux 0x9fa72993 skb_split +EXPORT_SYMBOL vmlinux 0x9fbbd002 __xfrm_route_forward +EXPORT_SYMBOL vmlinux 0x9feaf287 sonet_subtract_stats +EXPORT_SYMBOL vmlinux 0xa0243b4b neigh_resolve_output +EXPORT_SYMBOL vmlinux 0xa03523d5 security_unix_stream_connect +EXPORT_SYMBOL vmlinux 0xa04a01bd qdisc_class_hash_insert +EXPORT_SYMBOL vmlinux 0xa05c03df mempool_kmalloc +EXPORT_SYMBOL vmlinux 0xa0965fe2 unload_nls +EXPORT_SYMBOL vmlinux 0xa0b04675 vmalloc_32 +EXPORT_SYMBOL vmlinux 0xa0b685f0 save_mount_options +EXPORT_SYMBOL vmlinux 0xa0ceef51 out_of_line_wait_on_bit +EXPORT_SYMBOL vmlinux 0xa0fbac79 wake_up_bit +EXPORT_SYMBOL vmlinux 0xa108eb4d sysctl_optmem_max +EXPORT_SYMBOL vmlinux 0xa116268a tcf_exts_change +EXPORT_SYMBOL vmlinux 0xa120d33c tty_unregister_ldisc +EXPORT_SYMBOL vmlinux 0xa13366d2 generic_removexattr +EXPORT_SYMBOL vmlinux 0xa13798f8 printk_ratelimit +EXPORT_SYMBOL vmlinux 0xa13bd4ec __pskb_pull_tail +EXPORT_SYMBOL vmlinux 0xa15da336 filemap_fdatawait +EXPORT_SYMBOL vmlinux 0xa1a5bb0a km_query +EXPORT_SYMBOL vmlinux 0xa1b02665 dev_close +EXPORT_SYMBOL vmlinux 0xa1b759ce fb_add_videomode +EXPORT_SYMBOL vmlinux 0xa1c76e0a _cond_resched +EXPORT_SYMBOL vmlinux 0xa1c8761a input_set_capability +EXPORT_SYMBOL vmlinux 0xa1d5521d netpoll_poll +EXPORT_SYMBOL vmlinux 0xa20433ba inode_change_ok +EXPORT_SYMBOL vmlinux 0xa20ce1b8 net_msg_warn +EXPORT_SYMBOL vmlinux 0xa235943d vfs_link +EXPORT_SYMBOL vmlinux 0xa23ede36 check_disk_change +EXPORT_SYMBOL vmlinux 0xa2473147 xfrm_policy_unregister_afinfo +EXPORT_SYMBOL vmlinux 0xa27716ea request_firmware_nowait +EXPORT_SYMBOL vmlinux 0xa2a1e5c9 _write_lock_bh +EXPORT_SYMBOL vmlinux 0xa2a5fd77 inet_ehash_secret +EXPORT_SYMBOL vmlinux 0xa2a85e8e uart_update_timeout +EXPORT_SYMBOL vmlinux 0xa30e8206 qdisc_tree_decrease_qlen +EXPORT_SYMBOL vmlinux 0xa315bc7c call_usermodehelper_setkeys +EXPORT_SYMBOL vmlinux 0xa31f172d __copy_from_user_inatomic +EXPORT_SYMBOL vmlinux 0xa325e2fc no_llseek +EXPORT_SYMBOL vmlinux 0xa329f07e register_shrinker +EXPORT_SYMBOL vmlinux 0xa33f7c7c nla_strlcpy +EXPORT_SYMBOL vmlinux 0xa3420d61 __percpu_counter_sum +EXPORT_SYMBOL vmlinux 0xa34b076d tcf_action_dump_1 +EXPORT_SYMBOL vmlinux 0xa355a9b0 sock_no_shutdown +EXPORT_SYMBOL vmlinux 0xa35de80f ipv4_config +EXPORT_SYMBOL vmlinux 0xa3a5be95 memmove +EXPORT_SYMBOL vmlinux 0xa3a9aac6 dma_pool_destroy +EXPORT_SYMBOL vmlinux 0xa3bbcd80 acpi_set_gpe_type +EXPORT_SYMBOL vmlinux 0xa3c7a0b2 dcache_readdir +EXPORT_SYMBOL vmlinux 0xa3ca3814 seq_path +EXPORT_SYMBOL vmlinux 0xa3cc3268 blk_rq_map_user +EXPORT_SYMBOL vmlinux 0xa4155a53 nf_log_packet +EXPORT_SYMBOL vmlinux 0xa44072fc posix_acl_alloc +EXPORT_SYMBOL vmlinux 0xa44ad274 wait_for_completion_interruptible_timeout +EXPORT_SYMBOL vmlinux 0xa4501cd1 pnp_request_card_device +EXPORT_SYMBOL vmlinux 0xa49d2078 register_8022_client +EXPORT_SYMBOL vmlinux 0xa4b94fea iowrite8_rep +EXPORT_SYMBOL vmlinux 0xa4d4f0e6 global_cache_flush +EXPORT_SYMBOL vmlinux 0xa4df1151 kref_set +EXPORT_SYMBOL vmlinux 0xa4e41f0e acpi_root_dir +EXPORT_SYMBOL vmlinux 0xa51dd867 proc_dointvec_jiffies +EXPORT_SYMBOL vmlinux 0xa51e6c5f __netif_schedule +EXPORT_SYMBOL vmlinux 0xa53f9c7d xfrm4_prepare_output +EXPORT_SYMBOL vmlinux 0xa5423cc4 param_get_int +EXPORT_SYMBOL vmlinux 0xa5693df7 posix_acl_clone +EXPORT_SYMBOL vmlinux 0xa56f1315 mempool_free +EXPORT_SYMBOL vmlinux 0xa573763b kernel_read +EXPORT_SYMBOL vmlinux 0xa58b6804 nla_parse +EXPORT_SYMBOL vmlinux 0xa5922bb1 kfifo_init +EXPORT_SYMBOL vmlinux 0xa598e29c vesa_modes +EXPORT_SYMBOL vmlinux 0xa59affdc vfs_follow_link +EXPORT_SYMBOL vmlinux 0xa5adbe8c ida_destroy +EXPORT_SYMBOL vmlinux 0xa5ff222d mod_zone_page_state +EXPORT_SYMBOL vmlinux 0xa61bc856 inet_csk_clear_xmit_timers +EXPORT_SYMBOL vmlinux 0xa6205220 qdisc_watchdog_cancel +EXPORT_SYMBOL vmlinux 0xa6244c96 sk_alloc +EXPORT_SYMBOL vmlinux 0xa631435f tcp_rcv_established +EXPORT_SYMBOL vmlinux 0xa6462410 filemap_fdatawrite +EXPORT_SYMBOL vmlinux 0xa68124fa hweight8 +EXPORT_SYMBOL vmlinux 0xa681fe88 generate_random_uuid +EXPORT_SYMBOL vmlinux 0xa6b3b2a0 agp_generic_enable +EXPORT_SYMBOL vmlinux 0xa6dcc773 rb_insert_color +EXPORT_SYMBOL vmlinux 0xa703ecba generic_getxattr +EXPORT_SYMBOL vmlinux 0xa70fabbe release_evntsel_nmi +EXPORT_SYMBOL vmlinux 0xa729d6ad vcc_insert_socket +EXPORT_SYMBOL vmlinux 0xa7502f48 jiffies_to_timeval +EXPORT_SYMBOL vmlinux 0xa7816c27 bio_integrity_advance +EXPORT_SYMBOL vmlinux 0xa7924958 sk_stream_wait_memory +EXPORT_SYMBOL vmlinux 0xa7931d07 __ip_select_ident +EXPORT_SYMBOL vmlinux 0xa7c35c6b getnstimeofday +EXPORT_SYMBOL vmlinux 0xa7db6bc9 proc_dointvec +EXPORT_SYMBOL vmlinux 0xa80e59ae get_sb_bdev +EXPORT_SYMBOL vmlinux 0xa816c525 schedule_work_on +EXPORT_SYMBOL vmlinux 0xa822dae7 down_read +EXPORT_SYMBOL vmlinux 0xa8388473 d_lookup +EXPORT_SYMBOL vmlinux 0xa84da066 proc_doulongvec_minmax +EXPORT_SYMBOL vmlinux 0xa862e721 sk_wait_data +EXPORT_SYMBOL vmlinux 0xa86518a2 register_gifconf +EXPORT_SYMBOL vmlinux 0xa8655691 single_open +EXPORT_SYMBOL vmlinux 0xa867aa49 pagecache_write_begin +EXPORT_SYMBOL vmlinux 0xa86e3159 blk_queue_dma_pad +EXPORT_SYMBOL vmlinux 0xa87df9c7 skb_trim +EXPORT_SYMBOL vmlinux 0xa886a958 krealloc +EXPORT_SYMBOL vmlinux 0xa89fd057 blk_queue_update_dma_pad +EXPORT_SYMBOL vmlinux 0xa8b29083 linkwatch_fire_event +EXPORT_SYMBOL vmlinux 0xa8b57857 bio_integrity_get_tag +EXPORT_SYMBOL vmlinux 0xa8d3f4ea blk_rq_count_integrity_sg +EXPORT_SYMBOL vmlinux 0xa8eca3c1 vm_insert_page +EXPORT_SYMBOL vmlinux 0xa8f102af thermal_cooling_device_register +EXPORT_SYMBOL vmlinux 0xa8f30a16 fb_firmware_edid +EXPORT_SYMBOL vmlinux 0xa8fbf582 idr_replace +EXPORT_SYMBOL vmlinux 0xa8fef7bb security_unix_may_send +EXPORT_SYMBOL vmlinux 0xa916446b blk_stop_queue +EXPORT_SYMBOL vmlinux 0xa91726f5 pci_bus_alloc_resource +EXPORT_SYMBOL vmlinux 0xa91b5561 acpi_video_backlight_support +EXPORT_SYMBOL vmlinux 0xa925899a param_set_bool +EXPORT_SYMBOL vmlinux 0xa934eef1 remove_inode_hash +EXPORT_SYMBOL vmlinux 0xa937079d agp_free_page_array +EXPORT_SYMBOL vmlinux 0xa956b37e tcp_v4_connect +EXPORT_SYMBOL vmlinux 0xa9724f50 __skb_warn_lro_forwarding +EXPORT_SYMBOL vmlinux 0xa9be76e8 clocksource_register +EXPORT_SYMBOL vmlinux 0xa9e22b8d kmem_cache_alloc +EXPORT_SYMBOL vmlinux 0xa9e350bf request_firmware +EXPORT_SYMBOL vmlinux 0xa9fcf31d wait_for_completion_interruptible +EXPORT_SYMBOL vmlinux 0xaa024146 sonet_copy_stats +EXPORT_SYMBOL vmlinux 0xaa84a8ae acpi_processor_power_init_bm_check +EXPORT_SYMBOL vmlinux 0xaa8856bc bio_copy_user +EXPORT_SYMBOL vmlinux 0xaab06af8 _write_lock_irqsave +EXPORT_SYMBOL vmlinux 0xaae8ab0e acpi_bus_power_manageable +EXPORT_SYMBOL vmlinux 0xaaf61973 mpage_bio_submit +EXPORT_SYMBOL vmlinux 0xaafdc258 strcasecmp +EXPORT_SYMBOL vmlinux 0xaaffb9a5 acpi_bus_private_data_handler +EXPORT_SYMBOL vmlinux 0xab1737ae pci_bus_write_config_word +EXPORT_SYMBOL vmlinux 0xab471003 param_array_set +EXPORT_SYMBOL vmlinux 0xab565120 devm_ioport_map +EXPORT_SYMBOL vmlinux 0xab600421 probe_irq_off +EXPORT_SYMBOL vmlinux 0xab65ed80 set_memory_uc +EXPORT_SYMBOL vmlinux 0xab79bd21 nla_reserve +EXPORT_SYMBOL vmlinux 0xaba714af hippi_type_trans +EXPORT_SYMBOL vmlinux 0xabaa4b55 may_umount_tree +EXPORT_SYMBOL vmlinux 0xabd0c91c rtc_time_to_tm +EXPORT_SYMBOL vmlinux 0xabe85a21 idr_init +EXPORT_SYMBOL vmlinux 0xabeba1f0 security_task_getsecid +EXPORT_SYMBOL vmlinux 0xabebe3f1 truncate_inode_pages +EXPORT_SYMBOL vmlinux 0xabfbb4cf __elv_add_request +EXPORT_SYMBOL vmlinux 0xac0bbfa8 _proxy_pda +EXPORT_SYMBOL vmlinux 0xac0e5edd xfrm_state_walk +EXPORT_SYMBOL vmlinux 0xac338e1f thermal_zone_device_register +EXPORT_SYMBOL vmlinux 0xac383451 radix_tree_tag_clear +EXPORT_SYMBOL vmlinux 0xac3b3cee __bitmap_and +EXPORT_SYMBOL vmlinux 0xac5709f7 per_cpu__x86_cpu_to_node_map +EXPORT_SYMBOL vmlinux 0xac58ea5e acpi_unload_table_id +EXPORT_SYMBOL vmlinux 0xac7d6645 __locks_copy_lock +EXPORT_SYMBOL vmlinux 0xac815040 netif_carrier_off +EXPORT_SYMBOL vmlinux 0xac9695ff tc_classify_compat +EXPORT_SYMBOL vmlinux 0xacafd225 kernel_getsockopt +EXPORT_SYMBOL vmlinux 0xacc34c1f acpi_get_physical_pci_device +EXPORT_SYMBOL vmlinux 0xaccabc6a in4_pton +EXPORT_SYMBOL vmlinux 0xacd14477 kthread_create +EXPORT_SYMBOL vmlinux 0xace1e672 tc_classify +EXPORT_SYMBOL vmlinux 0xace78505 tcp_md5_hash_header +EXPORT_SYMBOL vmlinux 0xacf4d843 match_strdup +EXPORT_SYMBOL vmlinux 0xacf527d2 vfs_write +EXPORT_SYMBOL vmlinux 0xacf544f2 atm_charge +EXPORT_SYMBOL vmlinux 0xacfaed0d __vlan_hwaccel_rx +EXPORT_SYMBOL vmlinux 0xad0413d4 match_hex +EXPORT_SYMBOL vmlinux 0xad07fcc5 __first_cpu +EXPORT_SYMBOL vmlinux 0xad13c689 acpi_os_execute +EXPORT_SYMBOL vmlinux 0xad25fb12 __memcpy +EXPORT_SYMBOL vmlinux 0xad445bcf inet_add_protocol +EXPORT_SYMBOL vmlinux 0xad8de1b3 acpi_remove_address_space_handler +EXPORT_SYMBOL vmlinux 0xad90a0ff compat_sock_common_setsockopt +EXPORT_SYMBOL vmlinux 0xada5eeae tty_driver_flush_buffer +EXPORT_SYMBOL vmlinux 0xadaa2657 cpufreq_register_notifier +EXPORT_SYMBOL vmlinux 0xadf83898 xfrm_register_type +EXPORT_SYMBOL vmlinux 0xadffd6f8 generic_file_aio_write +EXPORT_SYMBOL vmlinux 0xae060059 __inode_dir_notify +EXPORT_SYMBOL vmlinux 0xae07f306 unregister_sysctl_table +EXPORT_SYMBOL vmlinux 0xae1548b4 swiotlb_unmap_sg +EXPORT_SYMBOL vmlinux 0xae207c01 skb_clone +EXPORT_SYMBOL vmlinux 0xae5f915c nf_afinfo +EXPORT_SYMBOL vmlinux 0xaef7237f task_pid_nr_ns +EXPORT_SYMBOL vmlinux 0xaf089f66 ps2_drain +EXPORT_SYMBOL vmlinux 0xaf50d12d task_pgrp_nr_ns +EXPORT_SYMBOL vmlinux 0xaf52c2d3 iommu_bio_merge +EXPORT_SYMBOL vmlinux 0xaf5e8a24 tcf_exts_validate +EXPORT_SYMBOL vmlinux 0xafa8c531 bio_integrity_set_tag +EXPORT_SYMBOL vmlinux 0xafe82e10 strcspn +EXPORT_SYMBOL vmlinux 0xb024cb4b uart_resume_port +EXPORT_SYMBOL vmlinux 0xb04ea8f0 agp_rebind_memory +EXPORT_SYMBOL vmlinux 0xb051909f ida_init +EXPORT_SYMBOL vmlinux 0xb064614f datagram_poll +EXPORT_SYMBOL vmlinux 0xb0778156 neigh_parms_release +EXPORT_SYMBOL vmlinux 0xb07dfb3d acpi_remove_gpe_handler +EXPORT_SYMBOL vmlinux 0xb08d1b9f atm_dev_lookup +EXPORT_SYMBOL vmlinux 0xb0b68e5a inet_getname +EXPORT_SYMBOL vmlinux 0xb0b847ac __bitmap_full +EXPORT_SYMBOL vmlinux 0xb0e10781 get_option +EXPORT_SYMBOL vmlinux 0xb0e3a128 bio_phys_segments +EXPORT_SYMBOL vmlinux 0xb0fbe2e9 pci_try_set_mwi +EXPORT_SYMBOL vmlinux 0xb116807f vfs_lstat +EXPORT_SYMBOL vmlinux 0xb11fa1ce strlcat +EXPORT_SYMBOL vmlinux 0xb121390a probe_irq_on +EXPORT_SYMBOL vmlinux 0xb1645a2e sg_free_table +EXPORT_SYMBOL vmlinux 0xb18e02c3 radix_tree_gang_lookup_tag +EXPORT_SYMBOL vmlinux 0xb1911bd4 blk_queue_make_request +EXPORT_SYMBOL vmlinux 0xb19760c3 bitmap_onto +EXPORT_SYMBOL vmlinux 0xb1a0aa11 skb_insert +EXPORT_SYMBOL vmlinux 0xb1acfd47 kset_register +EXPORT_SYMBOL vmlinux 0xb1c3a01a oops_in_progress +EXPORT_SYMBOL vmlinux 0xb1cf4100 get_super +EXPORT_SYMBOL vmlinux 0xb1cfad22 rdmsr_on_cpu +EXPORT_SYMBOL vmlinux 0xb1e591f3 fb_pan_display +EXPORT_SYMBOL vmlinux 0xb1f975aa unlock_kernel +EXPORT_SYMBOL vmlinux 0xb2017c1d per_cpu__x86_bios_cpu_apicid +EXPORT_SYMBOL vmlinux 0xb21e9ddb pci_enable_device +EXPORT_SYMBOL vmlinux 0xb2581b7d tty_register_device +EXPORT_SYMBOL vmlinux 0xb2607cfa __break_lease +EXPORT_SYMBOL vmlinux 0xb26665db bio_add_pc_page +EXPORT_SYMBOL vmlinux 0xb2be638a dma_chan_cleanup +EXPORT_SYMBOL vmlinux 0xb2e0fbac nf_register_hook +EXPORT_SYMBOL vmlinux 0xb2e85462 netdev_class_remove_file +EXPORT_SYMBOL vmlinux 0xb2f529e4 tr_type_trans +EXPORT_SYMBOL vmlinux 0xb2fd5ceb __put_user_4 +EXPORT_SYMBOL vmlinux 0xb3205415 wait_for_completion_killable +EXPORT_SYMBOL vmlinux 0xb3284531 acpi_dbg_layer +EXPORT_SYMBOL vmlinux 0xb3318ded __down_read_trylock +EXPORT_SYMBOL vmlinux 0xb34d4c2e acpi_terminate +EXPORT_SYMBOL vmlinux 0xb352177e find_first_bit +EXPORT_SYMBOL vmlinux 0xb3692eb4 ioremap_wc +EXPORT_SYMBOL vmlinux 0xb3a307c6 si_meminfo +EXPORT_SYMBOL vmlinux 0xb3b5de37 llc_add_pack +EXPORT_SYMBOL vmlinux 0xb3ff1f69 free_pages_exact +EXPORT_SYMBOL vmlinux 0xb423dba1 console_blanked +EXPORT_SYMBOL vmlinux 0xb4390f9a mcount +EXPORT_SYMBOL vmlinux 0xb43a83e2 dcache_dir_lseek +EXPORT_SYMBOL vmlinux 0xb45b24f6 k8_nb_ids +EXPORT_SYMBOL vmlinux 0xb47ee7ad sock_no_getsockopt +EXPORT_SYMBOL vmlinux 0xb494e82a br_fdb_put_hook +EXPORT_SYMBOL vmlinux 0xb4ca9447 __kfifo_get +EXPORT_SYMBOL vmlinux 0xb4cbb490 bio_copy_kern +EXPORT_SYMBOL vmlinux 0xb4d9569c dma_pool_create +EXPORT_SYMBOL vmlinux 0xb501bd1a alloc_buffer_head +EXPORT_SYMBOL vmlinux 0xb5044271 vsscanf +EXPORT_SYMBOL vmlinux 0xb512290f __dev_remove_pack +EXPORT_SYMBOL vmlinux 0xb52c5efb __skb_recv_datagram +EXPORT_SYMBOL vmlinux 0xb54533f7 usecs_to_jiffies +EXPORT_SYMBOL vmlinux 0xb5814df1 update_region +EXPORT_SYMBOL vmlinux 0xb58e9a61 unregister_netdevice +EXPORT_SYMBOL vmlinux 0xb5a459dc unregister_blkdev +EXPORT_SYMBOL vmlinux 0xb5aa81b4 blk_plug_device_unlocked +EXPORT_SYMBOL vmlinux 0xb5bed5db skb_checksum_help +EXPORT_SYMBOL vmlinux 0xb5d52c27 ec_transaction +EXPORT_SYMBOL vmlinux 0xb60e34a8 nla_memcpy +EXPORT_SYMBOL vmlinux 0xb6244511 sg_init_one +EXPORT_SYMBOL vmlinux 0xb6381b3d vcc_release_async +EXPORT_SYMBOL vmlinux 0xb63f65c8 generic_setxattr +EXPORT_SYMBOL vmlinux 0xb66d6534 dquot_free_space +EXPORT_SYMBOL vmlinux 0xb678366f int_sqrt +EXPORT_SYMBOL vmlinux 0xb6841ee7 set_bdi_congested +EXPORT_SYMBOL vmlinux 0xb6a61a86 qdisc_get_rtab +EXPORT_SYMBOL vmlinux 0xb6ba8bc6 pci_select_bars +EXPORT_SYMBOL vmlinux 0xb6bc274e sk_stream_error +EXPORT_SYMBOL vmlinux 0xb6be8aa5 d_genocide +EXPORT_SYMBOL vmlinux 0xb6cb110e send_sig_info +EXPORT_SYMBOL vmlinux 0xb6cbe886 acpi_get_node +EXPORT_SYMBOL vmlinux 0xb6e227aa rtc_lock +EXPORT_SYMBOL vmlinux 0xb6eefc18 swiotlb_dma_supported +EXPORT_SYMBOL vmlinux 0xb714a981 console_print +EXPORT_SYMBOL vmlinux 0xb715680b fib_default_rule_add +EXPORT_SYMBOL vmlinux 0xb7161553 xrlim_allow +EXPORT_SYMBOL vmlinux 0xb7555f12 timeval_to_jiffies +EXPORT_SYMBOL vmlinux 0xb758b225 acpi_disable_event +EXPORT_SYMBOL vmlinux 0xb79eacec scm_detach_fds +EXPORT_SYMBOL vmlinux 0xb7a6d97e simple_getattr +EXPORT_SYMBOL vmlinux 0xb7b61aa7 bio_unmap_user +EXPORT_SYMBOL vmlinux 0xb7ee3f25 inet_frag_destroy +EXPORT_SYMBOL vmlinux 0xb84e75b1 thaw_bdev +EXPORT_SYMBOL vmlinux 0xb86e4ab9 random32 +EXPORT_SYMBOL vmlinux 0xb89af9bf srandom32 +EXPORT_SYMBOL vmlinux 0xb8a334e5 blk_queue_prep_rq +EXPORT_SYMBOL vmlinux 0xb8b5abe2 pci_bus_read_config_byte +EXPORT_SYMBOL vmlinux 0xb8e7ce2c __put_user_8 +EXPORT_SYMBOL vmlinux 0xb8fd8461 vfs_dq_drop +EXPORT_SYMBOL vmlinux 0xb9032354 tcp_md5_hash_skb_data +EXPORT_SYMBOL vmlinux 0xb945a45f kill_pid +EXPORT_SYMBOL vmlinux 0xb9805b0c down_read_trylock +EXPORT_SYMBOL vmlinux 0xb98a0185 rtc_tm_to_time +EXPORT_SYMBOL vmlinux 0xb9c74bf1 gen_kill_estimator +EXPORT_SYMBOL vmlinux 0xb9fd2205 add_efi_memmap +EXPORT_SYMBOL vmlinux 0xba1b271c sync_page_range_nolock +EXPORT_SYMBOL vmlinux 0xba2d8594 ec_read +EXPORT_SYMBOL vmlinux 0xba49389e kill_anon_super +EXPORT_SYMBOL vmlinux 0xba497f13 loops_per_jiffy +EXPORT_SYMBOL vmlinux 0xba542af2 kernel_listen +EXPORT_SYMBOL vmlinux 0xbaa2782a kstrndup +EXPORT_SYMBOL vmlinux 0xbac311b7 simple_write_end +EXPORT_SYMBOL vmlinux 0xbaf75a4d xfrm_state_delete_tunnel +EXPORT_SYMBOL vmlinux 0xbb167766 fb_var_to_videomode +EXPORT_SYMBOL vmlinux 0xbb189cad disallow_signal +EXPORT_SYMBOL vmlinux 0xbb200c6a ethtool_op_set_sg +EXPORT_SYMBOL vmlinux 0xbb2e9409 bfifo_qdisc_ops +EXPORT_SYMBOL vmlinux 0xbb5b62df dev_kfree_skb_any +EXPORT_SYMBOL vmlinux 0xbb5d343d xfrm_get_acqseq +EXPORT_SYMBOL vmlinux 0xbb83bd29 xfrm_cfg_mutex +EXPORT_SYMBOL vmlinux 0xbbc8e804 param_set_ushort +EXPORT_SYMBOL vmlinux 0xbbe058e9 dev_queue_xmit +EXPORT_SYMBOL vmlinux 0xbc03317f neigh_seq_start +EXPORT_SYMBOL vmlinux 0xbc0b7719 sock_wake_async +EXPORT_SYMBOL vmlinux 0xbca0d6f8 set_bh_page +EXPORT_SYMBOL vmlinux 0xbca183c4 kill_block_super +EXPORT_SYMBOL vmlinux 0xbcc308bb strnlen_user +EXPORT_SYMBOL vmlinux 0xbccbb49c idr_remove_all +EXPORT_SYMBOL vmlinux 0xbcd1d393 user_path_at +EXPORT_SYMBOL vmlinux 0xbcdc28fd udp_disconnect +EXPORT_SYMBOL vmlinux 0xbcf148cf inet_frag_evictor +EXPORT_SYMBOL vmlinux 0xbd2db4cb simple_fill_super +EXPORT_SYMBOL vmlinux 0xbdaf5b07 acpi_os_read_port +EXPORT_SYMBOL vmlinux 0xbde1535c __dev_getfirstbyhwtype +EXPORT_SYMBOL vmlinux 0xbe4784e8 clear_inode +EXPORT_SYMBOL vmlinux 0xbe4901ee agp_flush_chipset +EXPORT_SYMBOL vmlinux 0xbe499d81 copy_to_user +EXPORT_SYMBOL vmlinux 0xbea85dc6 tty_chars_in_buffer +EXPORT_SYMBOL vmlinux 0xbea8fa39 unregister_con_driver +EXPORT_SYMBOL vmlinux 0xbebe5996 locks_init_lock +EXPORT_SYMBOL vmlinux 0xbecdce74 ida_pre_get +EXPORT_SYMBOL vmlinux 0xbedc3503 acpi_bus_add +EXPORT_SYMBOL vmlinux 0xbee14701 qdisc_create_dflt +EXPORT_SYMBOL vmlinux 0xbee2ab20 mnt_unpin +EXPORT_SYMBOL vmlinux 0xbee332b9 block_prepare_write +EXPORT_SYMBOL vmlinux 0xbef43296 console_conditional_schedule +EXPORT_SYMBOL vmlinux 0xbefee397 acpi_get_object_info +EXPORT_SYMBOL vmlinux 0xbf1a686e unlock_super +EXPORT_SYMBOL vmlinux 0xbf2f030d skb_copy_expand +EXPORT_SYMBOL vmlinux 0xbf7fd2f5 schedule_timeout_killable +EXPORT_SYMBOL vmlinux 0xbf9bcc8d __cap_empty_set +EXPORT_SYMBOL vmlinux 0xbfa3d14f skb_put +EXPORT_SYMBOL vmlinux 0xbfaa8891 tcf_exts_destroy +EXPORT_SYMBOL vmlinux 0xbfbaaed7 thermal_zone_bind_cooling_device +EXPORT_SYMBOL vmlinux 0xbfc177bc iowrite32_rep +EXPORT_SYMBOL vmlinux 0xbfc62d50 iget_failed +EXPORT_SYMBOL vmlinux 0xbfe0ee26 flush_old_exec +EXPORT_SYMBOL vmlinux 0xbfe4e38f blk_rq_map_integrity_sg +EXPORT_SYMBOL vmlinux 0xbfe8828f nla_reserve_nohdr +EXPORT_SYMBOL vmlinux 0xc003c637 __strncpy_from_user +EXPORT_SYMBOL vmlinux 0xc00efd44 fb_show_logo +EXPORT_SYMBOL vmlinux 0xc0222c20 fifo_set_limit +EXPORT_SYMBOL vmlinux 0xc045ad4e timespec_trunc +EXPORT_SYMBOL vmlinux 0xc0580937 rb_erase +EXPORT_SYMBOL vmlinux 0xc079de2d netdev_features_change +EXPORT_SYMBOL vmlinux 0xc07cfe86 bio_integrity_split +EXPORT_SYMBOL vmlinux 0xc07d43ae acpi_evaluate_reference +EXPORT_SYMBOL vmlinux 0xc082ba2f try_to_release_page +EXPORT_SYMBOL vmlinux 0xc09651d9 crc32_be +EXPORT_SYMBOL vmlinux 0xc0a3d105 find_next_bit +EXPORT_SYMBOL vmlinux 0xc0ed93b3 dquot_acquire +EXPORT_SYMBOL vmlinux 0xc12264ac pci_release_regions +EXPORT_SYMBOL vmlinux 0xc13d7e4c __downgrade_write +EXPORT_SYMBOL vmlinux 0xc1652095 fb_set_cmap +EXPORT_SYMBOL vmlinux 0xc18a0dac __page_symlink +EXPORT_SYMBOL vmlinux 0xc1efbe5b textsearch_prepare +EXPORT_SYMBOL vmlinux 0xc1ffcf58 llc_sap_close +EXPORT_SYMBOL vmlinux 0xc21c407b arp_find +EXPORT_SYMBOL vmlinux 0xc2424641 agp3_generic_cleanup +EXPORT_SYMBOL vmlinux 0xc24883b4 pcim_iomap_regions_request_all +EXPORT_SYMBOL vmlinux 0xc254af48 dcache_lock +EXPORT_SYMBOL vmlinux 0xc256e762 __bitmap_equal +EXPORT_SYMBOL vmlinux 0xc2781502 wake_up_process +EXPORT_SYMBOL vmlinux 0xc278b27c generic_file_splice_read +EXPORT_SYMBOL vmlinux 0xc2e587d1 reset_devices +EXPORT_SYMBOL vmlinux 0xc2f40cdf write_inode_now +EXPORT_SYMBOL vmlinux 0xc3057c76 con_copy_unimap +EXPORT_SYMBOL vmlinux 0xc319af63 blk_recount_segments +EXPORT_SYMBOL vmlinux 0xc321369f sb_set_blocksize +EXPORT_SYMBOL vmlinux 0xc32473c8 dev_set_mac_address +EXPORT_SYMBOL vmlinux 0xc32d8d4b fput +EXPORT_SYMBOL vmlinux 0xc33f6f4c on_each_cpu +EXPORT_SYMBOL vmlinux 0xc3696aa9 pnp_is_active +EXPORT_SYMBOL vmlinux 0xc3771761 blkdev_put +EXPORT_SYMBOL vmlinux 0xc38e5923 udp_stats_in6 +EXPORT_SYMBOL vmlinux 0xc38fd85c compat_tcp_setsockopt +EXPORT_SYMBOL vmlinux 0xc3aaf0a9 __put_user_1 +EXPORT_SYMBOL vmlinux 0xc3d40060 free_task +EXPORT_SYMBOL vmlinux 0xc3fb92c4 register_sysctl_table +EXPORT_SYMBOL vmlinux 0xc402cc99 register_acpi_notifier +EXPORT_SYMBOL vmlinux 0xc406f6b2 drop_super +EXPORT_SYMBOL vmlinux 0xc415b30d agp3_generic_tlbflush +EXPORT_SYMBOL vmlinux 0xc449f381 pci_get_subsys +EXPORT_SYMBOL vmlinux 0xc45da5fb elv_next_request +EXPORT_SYMBOL vmlinux 0xc4626d9c get_empty_filp +EXPORT_SYMBOL vmlinux 0xc468f0c5 pcix_get_mmrbc +EXPORT_SYMBOL vmlinux 0xc48554ad proc_mkdir +EXPORT_SYMBOL vmlinux 0xc489da34 dma_ops +EXPORT_SYMBOL vmlinux 0xc499ae1e kstrdup +EXPORT_SYMBOL vmlinux 0xc4ad39b1 posix_lock_file +EXPORT_SYMBOL vmlinux 0xc4bc539a ethtool_op_get_tx_csum +EXPORT_SYMBOL vmlinux 0xc4c62b1c dst_discard +EXPORT_SYMBOL vmlinux 0xc4d489e9 up_write +EXPORT_SYMBOL vmlinux 0xc52f5714 fb_videomode_to_var +EXPORT_SYMBOL vmlinux 0xc53c882d idr_get_new +EXPORT_SYMBOL vmlinux 0xc54a356f register_sysrq_key +EXPORT_SYMBOL vmlinux 0xc5534d64 ioread16 +EXPORT_SYMBOL vmlinux 0xc558530d profile_pc +EXPORT_SYMBOL vmlinux 0xc55f7dc7 _write_trylock +EXPORT_SYMBOL vmlinux 0xc56e67a3 tcf_action_exec +EXPORT_SYMBOL vmlinux 0xc590ad35 __tcf_em_tree_match +EXPORT_SYMBOL vmlinux 0xc5b20fd1 bd_claim +EXPORT_SYMBOL vmlinux 0xc5bb1696 serio_reconnect +EXPORT_SYMBOL vmlinux 0xc5d9c46c agp_try_unsupported_boot +EXPORT_SYMBOL vmlinux 0xc5e29365 pci_clear_mwi +EXPORT_SYMBOL vmlinux 0xc5f22bdb blkdev_issue_flush +EXPORT_SYMBOL vmlinux 0xc5fc7576 netdev_rx_csum_fault +EXPORT_SYMBOL vmlinux 0xc6038fd8 open_bdev_excl +EXPORT_SYMBOL vmlinux 0xc62d6dfa redirty_page_for_writepage +EXPORT_SYMBOL vmlinux 0xc64975c7 ip_route_output_key +EXPORT_SYMBOL vmlinux 0xc65abeb7 agp3_generic_sizes +EXPORT_SYMBOL vmlinux 0xc678d274 sk_filter +EXPORT_SYMBOL vmlinux 0xc67b57c6 pci_target_state +EXPORT_SYMBOL vmlinux 0xc694b653 unlock_buffer +EXPORT_SYMBOL vmlinux 0xc6a02ad5 mnt_pin +EXPORT_SYMBOL vmlinux 0xc6b83c26 inet_csk_destroy_sock +EXPORT_SYMBOL vmlinux 0xc6d088f7 filemap_fault +EXPORT_SYMBOL vmlinux 0xc6d61f51 misc_register +EXPORT_SYMBOL vmlinux 0xc7014d25 bio_hw_segments +EXPORT_SYMBOL vmlinux 0xc7208c3a serial8250_resume_port +EXPORT_SYMBOL vmlinux 0xc740c64a memchr +EXPORT_SYMBOL vmlinux 0xc7566ca4 unregister_sysrq_key +EXPORT_SYMBOL vmlinux 0xc769046f iput +EXPORT_SYMBOL vmlinux 0xc7a24d76 sysfs_format_mac +EXPORT_SYMBOL vmlinux 0xc7a4fbed rtnl_lock +EXPORT_SYMBOL vmlinux 0xc7ba0fff n_tty_ioctl +EXPORT_SYMBOL vmlinux 0xc7ca1dfc __ht_create_irq +EXPORT_SYMBOL vmlinux 0xc7cf4b56 genl_sock +EXPORT_SYMBOL vmlinux 0xc7e75829 agp_generic_mask_memory +EXPORT_SYMBOL vmlinux 0xc80e481f tty_hangup +EXPORT_SYMBOL vmlinux 0xc81ff710 neigh_parms_alloc +EXPORT_SYMBOL vmlinux 0xc84edb59 stop_tty +EXPORT_SYMBOL vmlinux 0xc852bba7 lookup_one_len +EXPORT_SYMBOL vmlinux 0xc867ecab ip_getsockopt +EXPORT_SYMBOL vmlinux 0xc8785ecd inode_needs_sync +EXPORT_SYMBOL vmlinux 0xc897c382 sg_init_table +EXPORT_SYMBOL vmlinux 0xc8b57c27 autoremove_wake_function +EXPORT_SYMBOL vmlinux 0xc8ca3e25 acpi_get_child +EXPORT_SYMBOL vmlinux 0xc8d368ef fb_get_mode +EXPORT_SYMBOL vmlinux 0xc8e94ef8 key_validate +EXPORT_SYMBOL vmlinux 0xc909cd70 bio_integrity_free +EXPORT_SYMBOL vmlinux 0xc92b8d9b netif_device_detach +EXPORT_SYMBOL vmlinux 0xc9437ede __down_write_nested +EXPORT_SYMBOL vmlinux 0xc959ae92 vfs_readdir +EXPORT_SYMBOL vmlinux 0xc967ebf6 __blockdev_direct_IO +EXPORT_SYMBOL vmlinux 0xc998d641 icmp_err_convert +EXPORT_SYMBOL vmlinux 0xc9ab2eef acpi_os_wait_events_complete +EXPORT_SYMBOL vmlinux 0xc9c0cd17 gnet_stats_copy_basic +EXPORT_SYMBOL vmlinux 0xc9c220dd netlink_change_ngroups +EXPORT_SYMBOL vmlinux 0xc9cc7b0f devm_iounmap +EXPORT_SYMBOL vmlinux 0xc9e0f778 blk_queue_softirq_done +EXPORT_SYMBOL vmlinux 0xc9e8a187 set_pages_x +EXPORT_SYMBOL vmlinux 0xca18ccae unlock_rename +EXPORT_SYMBOL vmlinux 0xca366851 __xfrm_state_delete +EXPORT_SYMBOL vmlinux 0xca37ea9d kernel_accept +EXPORT_SYMBOL vmlinux 0xca74bea6 vfs_mknod +EXPORT_SYMBOL vmlinux 0xca831be3 dma_async_memcpy_buf_to_buf +EXPORT_SYMBOL vmlinux 0xca8abced request_key_with_auxdata +EXPORT_SYMBOL vmlinux 0xca8acc78 acpi_dbg_level +EXPORT_SYMBOL vmlinux 0xcaa64048 cpu_sysdev_class +EXPORT_SYMBOL vmlinux 0xcaaa075a tcp_mtup_init +EXPORT_SYMBOL vmlinux 0xcaaf9d43 swiotlb_map_single +EXPORT_SYMBOL vmlinux 0xcaec63a7 simple_sync_file +EXPORT_SYMBOL vmlinux 0xcb26ccb2 xfrm_input_resume +EXPORT_SYMBOL vmlinux 0xcb32da10 param_set_int +EXPORT_SYMBOL vmlinux 0xcb36487c br_handle_frame_hook +EXPORT_SYMBOL vmlinux 0xcb6beb40 hweight32 +EXPORT_SYMBOL vmlinux 0xcb7131fb fb_get_options +EXPORT_SYMBOL vmlinux 0xcb733bf2 acpi_bus_set_power +EXPORT_SYMBOL vmlinux 0xcbc3c814 skb_copy_and_csum_dev +EXPORT_SYMBOL vmlinux 0xcbd938d3 bio_init +EXPORT_SYMBOL vmlinux 0xcbe4271e unregister_quota_format +EXPORT_SYMBOL vmlinux 0xcc07af75 strnlen +EXPORT_SYMBOL vmlinux 0xcc248d26 serial8250_suspend_port +EXPORT_SYMBOL vmlinux 0xcc36f32e fb_unregister_client +EXPORT_SYMBOL vmlinux 0xcc5005fe msleep_interruptible +EXPORT_SYMBOL vmlinux 0xcc51ee50 dma_spin_lock +EXPORT_SYMBOL vmlinux 0xcc523f61 sysctl_jiffies +EXPORT_SYMBOL vmlinux 0xcc7f8443 pnp_start_dev +EXPORT_SYMBOL vmlinux 0xcc7fa952 local_bh_enable_ip +EXPORT_SYMBOL vmlinux 0xcc9237ea pci_remove_behind_bridge +EXPORT_SYMBOL vmlinux 0xccedf984 neigh_update +EXPORT_SYMBOL vmlinux 0xcd30312e kmem_cache_free +EXPORT_SYMBOL vmlinux 0xcd4e0970 dquot_alloc_space +EXPORT_SYMBOL vmlinux 0xcd513a23 set_page_dirty_lock +EXPORT_SYMBOL vmlinux 0xcd6e79cd netdev_set_master +EXPORT_SYMBOL vmlinux 0xcdbb2c66 dcache_dir_close +EXPORT_SYMBOL vmlinux 0xcdc80919 generic_file_mmap +EXPORT_SYMBOL vmlinux 0xce36ded6 sysctl_tcp_mem +EXPORT_SYMBOL vmlinux 0xce4904a4 acpi_leave_sleep_state +EXPORT_SYMBOL vmlinux 0xce5ac24f zlib_inflate_workspacesize +EXPORT_SYMBOL vmlinux 0xce61e785 generic_show_options +EXPORT_SYMBOL vmlinux 0xcea71318 netlink_clear_multicast_users +EXPORT_SYMBOL vmlinux 0xcedfeaac netdev_class_create_file +EXPORT_SYMBOL vmlinux 0xcefcd99a serial8250_unregister_port +EXPORT_SYMBOL vmlinux 0xcf047c83 acpi_disable_gpe +EXPORT_SYMBOL vmlinux 0xcf08ce0d unmap_mapping_range +EXPORT_SYMBOL vmlinux 0xcf170545 skb_find_text +EXPORT_SYMBOL vmlinux 0xcf728d24 d_splice_alias +EXPORT_SYMBOL vmlinux 0xcf86be54 vc_cons +EXPORT_SYMBOL vmlinux 0xcfadd723 __percpu_counter_add +EXPORT_SYMBOL vmlinux 0xcfba4121 xfrm_state_update +EXPORT_SYMBOL vmlinux 0xcfc6c603 key_alloc +EXPORT_SYMBOL vmlinux 0xcfd3018e set_normalized_timespec +EXPORT_SYMBOL vmlinux 0xcfd8a794 __lock_page +EXPORT_SYMBOL vmlinux 0xcfe0bd64 __free_pages +EXPORT_SYMBOL vmlinux 0xd000610a pagevec_lookup +EXPORT_SYMBOL vmlinux 0xd0181f4f __bitmap_xor +EXPORT_SYMBOL vmlinux 0xd021b5ee __find_get_block +EXPORT_SYMBOL vmlinux 0xd02cc869 __bitmap_andnot +EXPORT_SYMBOL vmlinux 0xd02db6fa textsearch_destroy +EXPORT_SYMBOL vmlinux 0xd046763e __pagevec_lru_add +EXPORT_SYMBOL vmlinux 0xd0696d67 xfrm_user_policy +EXPORT_SYMBOL vmlinux 0xd08197fa acpi_load_tables +EXPORT_SYMBOL vmlinux 0xd0ee38b8 schedule_timeout_uninterruptible +EXPORT_SYMBOL vmlinux 0xd0fef3b2 agp_free_key +EXPORT_SYMBOL vmlinux 0xd1042f4b vm_insert_pfn +EXPORT_SYMBOL vmlinux 0xd10496aa input_register_handle +EXPORT_SYMBOL vmlinux 0xd104eec7 bio_free +EXPORT_SYMBOL vmlinux 0xd1472061 acpi_pci_register_driver +EXPORT_SYMBOL vmlinux 0xd153a550 blk_queue_end_tag +EXPORT_SYMBOL vmlinux 0xd18b6eb2 acpi_unmap_lsapic +EXPORT_SYMBOL vmlinux 0xd19bb294 acpi_install_address_space_handler +EXPORT_SYMBOL vmlinux 0xd19c7f38 ht_create_irq +EXPORT_SYMBOL vmlinux 0xd1efb33a give_up_console +EXPORT_SYMBOL vmlinux 0xd1f6c5f3 smp_num_siblings +EXPORT_SYMBOL vmlinux 0xd1f91bcd dev_base_lock +EXPORT_SYMBOL vmlinux 0xd21101fe dma_async_client_unregister +EXPORT_SYMBOL vmlinux 0xd21645d8 __bio_clone +EXPORT_SYMBOL vmlinux 0xd251d7b0 security_socket_getpeersec_dgram +EXPORT_SYMBOL vmlinux 0xd2555f19 jiffies_64_to_clock_t +EXPORT_SYMBOL vmlinux 0xd255c07c default_llseek +EXPORT_SYMBOL vmlinux 0xd255efdf end_queued_request +EXPORT_SYMBOL vmlinux 0xd25d4f74 console_blank_hook +EXPORT_SYMBOL vmlinux 0xd267d42c down_killable +EXPORT_SYMBOL vmlinux 0xd2812d23 tcp_close +EXPORT_SYMBOL vmlinux 0xd2965f6f kthread_should_stop +EXPORT_SYMBOL vmlinux 0xd29f3bd6 force_sig +EXPORT_SYMBOL vmlinux 0xd2b39dd4 agp_free_memory +EXPORT_SYMBOL vmlinux 0xd2d746c4 input_inject_event +EXPORT_SYMBOL vmlinux 0xd334386b block_write_end +EXPORT_SYMBOL vmlinux 0xd34f0c62 gen_pool_create +EXPORT_SYMBOL vmlinux 0xd351abb1 inc_zone_page_state +EXPORT_SYMBOL vmlinux 0xd357cc57 set_device_ro +EXPORT_SYMBOL vmlinux 0xd36f5997 proto_register +EXPORT_SYMBOL vmlinux 0xd37b5e86 bdi_register +EXPORT_SYMBOL vmlinux 0xd3951da4 acpi_resource_to_address64 +EXPORT_SYMBOL vmlinux 0xd3d0fe73 __mpage_writepage +EXPORT_SYMBOL vmlinux 0xd3f4c3bb nobh_writepage +EXPORT_SYMBOL vmlinux 0xd3f74cf1 interruptible_sleep_on_timeout +EXPORT_SYMBOL vmlinux 0xd42b7232 _write_unlock_bh +EXPORT_SYMBOL vmlinux 0xd42c3a7b inet_csk_delete_keepalive_timer +EXPORT_SYMBOL vmlinux 0xd46c157a tty_set_operations +EXPORT_SYMBOL vmlinux 0xd4a84ef9 __pagevec_release +EXPORT_SYMBOL vmlinux 0xd4bfa570 xfrm4_rcv +EXPORT_SYMBOL vmlinux 0xd4d5e73c generic_file_llseek_unlocked +EXPORT_SYMBOL vmlinux 0xd4db002c __serio_register_port +EXPORT_SYMBOL vmlinux 0xd4e39c1a inet_csk_init_xmit_timers +EXPORT_SYMBOL vmlinux 0xd50e9f86 ethtool_op_set_flags +EXPORT_SYMBOL vmlinux 0xd513e29e eth_type_trans +EXPORT_SYMBOL vmlinux 0xd51a6652 ps2_command +EXPORT_SYMBOL vmlinux 0xd51bb9d0 tcp_v4_conn_request +EXPORT_SYMBOL vmlinux 0xd53f3e5c input_unregister_device +EXPORT_SYMBOL vmlinux 0xd568308e __devm_request_region +EXPORT_SYMBOL vmlinux 0xd56d2013 nf_unregister_hook +EXPORT_SYMBOL vmlinux 0xd5797488 kobject_init +EXPORT_SYMBOL vmlinux 0xd57a4443 invalidate_mapping_pages +EXPORT_SYMBOL vmlinux 0xd5b037e1 kref_put +EXPORT_SYMBOL vmlinux 0xd5d47347 netif_receive_skb +EXPORT_SYMBOL vmlinux 0xd5dc42e5 proc_dointvec_ms_jiffies +EXPORT_SYMBOL vmlinux 0xd6035d05 do_settimeofday +EXPORT_SYMBOL vmlinux 0xd60d7af4 ida_remove +EXPORT_SYMBOL vmlinux 0xd62c833f schedule_timeout +EXPORT_SYMBOL vmlinux 0xd647f526 vc_resize +EXPORT_SYMBOL vmlinux 0xd69688b5 d_alloc_name +EXPORT_SYMBOL vmlinux 0xd6a78d08 smp_call_function_single +EXPORT_SYMBOL vmlinux 0xd6b33026 cpu_khz +EXPORT_SYMBOL vmlinux 0xd6ee688f vmalloc +EXPORT_SYMBOL vmlinux 0xd6f3b1a7 xfrm_policy_insert +EXPORT_SYMBOL vmlinux 0xd6f7ab50 sock_no_getname +EXPORT_SYMBOL vmlinux 0xd70af353 dma_async_client_register +EXPORT_SYMBOL vmlinux 0xd7504317 dcache_dir_open +EXPORT_SYMBOL vmlinux 0xd7504f39 blk_queue_max_phys_segments +EXPORT_SYMBOL vmlinux 0xd760aa26 pcim_iomap +EXPORT_SYMBOL vmlinux 0xd79b5a02 allow_signal +EXPORT_SYMBOL vmlinux 0xd7a6fafa panic_notifier_list +EXPORT_SYMBOL vmlinux 0xd7bc5729 vfs_quota_on_mount +EXPORT_SYMBOL vmlinux 0xd7d211ed xfrm_policy_walk +EXPORT_SYMBOL vmlinux 0xd7da2336 vfs_readlink +EXPORT_SYMBOL vmlinux 0xd7dd777b reserve_perfctr_nmi +EXPORT_SYMBOL vmlinux 0xd7f09e60 nf_reinject +EXPORT_SYMBOL vmlinux 0xd80fe15e netdev_boot_setup_check +EXPORT_SYMBOL vmlinux 0xd85e4496 skb_checksum +EXPORT_SYMBOL vmlinux 0xd88f695a __mod_timer +EXPORT_SYMBOL vmlinux 0xd89da37f movable_zone +EXPORT_SYMBOL vmlinux 0xd8b3f247 elv_dispatch_add_tail +EXPORT_SYMBOL vmlinux 0xd8e484f0 register_chrdev_region +EXPORT_SYMBOL vmlinux 0xd903ac70 inet_shutdown +EXPORT_SYMBOL vmlinux 0xd9091363 acpi_install_notify_handler +EXPORT_SYMBOL vmlinux 0xd93315e9 input_event +EXPORT_SYMBOL vmlinux 0xd9449590 dev_mc_delete +EXPORT_SYMBOL vmlinux 0xd972ed41 netlink_kernel_release +EXPORT_SYMBOL vmlinux 0xd981c191 lease_modify +EXPORT_SYMBOL vmlinux 0xd985dc99 mempool_free_pages +EXPORT_SYMBOL vmlinux 0xd9941836 __brelse +EXPORT_SYMBOL vmlinux 0xd9a365b3 blk_rq_init +EXPORT_SYMBOL vmlinux 0xd9a79ade netpoll_parse_options +EXPORT_SYMBOL vmlinux 0xd9b7c442 balance_dirty_pages_ratelimited_nr +EXPORT_SYMBOL vmlinux 0xd9e543d5 neigh_sysctl_unregister +EXPORT_SYMBOL vmlinux 0xd9f2a87a generic_shutdown_super +EXPORT_SYMBOL vmlinux 0xda0a6b0e acpi_map_lsapic +EXPORT_SYMBOL vmlinux 0xda136780 serio_unregister_child_port +EXPORT_SYMBOL vmlinux 0xda1a7335 kasprintf +EXPORT_SYMBOL vmlinux 0xda2b8ace agp_generic_free_by_type +EXPORT_SYMBOL vmlinux 0xda4629e4 radix_tree_insert +EXPORT_SYMBOL vmlinux 0xda4ad484 iunique +EXPORT_SYMBOL vmlinux 0xda72fe1a acpi_check_mem_region +EXPORT_SYMBOL vmlinux 0xda73a1d0 __check_region +EXPORT_SYMBOL vmlinux 0xda7ca6cb fb_mode_is_equal +EXPORT_SYMBOL vmlinux 0xda8af7ad fb_find_nearest_mode +EXPORT_SYMBOL vmlinux 0xda928914 nmi_watchdog +EXPORT_SYMBOL vmlinux 0xdaa98ff4 pfifo_qdisc_ops +EXPORT_SYMBOL vmlinux 0xdaafff7f rtnl_set_sk_err +EXPORT_SYMBOL vmlinux 0xdac3e5a2 xfrm_state_delete +EXPORT_SYMBOL vmlinux 0xdae0dc74 dma_alloc_coherent +EXPORT_SYMBOL vmlinux 0xdaedc84e simple_rmdir +EXPORT_SYMBOL vmlinux 0xdb347ebb get_agp_version +EXPORT_SYMBOL vmlinux 0xdb66b165 aio_put_req +EXPORT_SYMBOL vmlinux 0xdb7c30be pnp_register_driver +EXPORT_SYMBOL vmlinux 0xdbcd416e sysctl_ip_nonlocal_bind +EXPORT_SYMBOL vmlinux 0xdbd1d593 qdisc_calculate_pkt_len +EXPORT_SYMBOL vmlinux 0xdc04fbfa mark_buffer_async_write +EXPORT_SYMBOL vmlinux 0xdc14eda7 pci_pci_problems +EXPORT_SYMBOL vmlinux 0xdc2adb35 add_taint +EXPORT_SYMBOL vmlinux 0xdc3eaf70 iomem_resource +EXPORT_SYMBOL vmlinux 0xdc40932b generic_file_aio_read +EXPORT_SYMBOL vmlinux 0xdc43a9c8 daemonize +EXPORT_SYMBOL vmlinux 0xdc68bbd4 sync_page_range +EXPORT_SYMBOL vmlinux 0xdc873a70 screen_info +EXPORT_SYMBOL vmlinux 0xdc9e8d46 xfrm_register_km +EXPORT_SYMBOL vmlinux 0xdcb0349b sys_close +EXPORT_SYMBOL vmlinux 0xdcbd16b6 read_cache_pages +EXPORT_SYMBOL vmlinux 0xdcc74817 simple_link +EXPORT_SYMBOL vmlinux 0xdcda205a acpi_bus_unregister_driver +EXPORT_SYMBOL vmlinux 0xdcdd40ff pci_request_regions +EXPORT_SYMBOL vmlinux 0xdd0ebf56 set_anon_super +EXPORT_SYMBOL vmlinux 0xdd135e5d cfb_imageblit +EXPORT_SYMBOL vmlinux 0xdd47b644 input_flush_device +EXPORT_SYMBOL vmlinux 0xdd62b45d find_task_by_vpid +EXPORT_SYMBOL vmlinux 0xdd72f76b blk_insert_request +EXPORT_SYMBOL vmlinux 0xddc09646 dma_supported +EXPORT_SYMBOL vmlinux 0xddc1ac11 bioset_integrity_free +EXPORT_SYMBOL vmlinux 0xddedf5ab skb_under_panic +EXPORT_SYMBOL vmlinux 0xde0bdcff memset +EXPORT_SYMBOL vmlinux 0xde4129b3 blk_queue_max_sectors +EXPORT_SYMBOL vmlinux 0xde5c08e2 fb_get_buffer_offset +EXPORT_SYMBOL vmlinux 0xde682433 pci_scan_single_device +EXPORT_SYMBOL vmlinux 0xde72b41d pci_bus_find_capability +EXPORT_SYMBOL vmlinux 0xde75b689 set_irq_type +EXPORT_SYMBOL vmlinux 0xde90ac48 pci_bus_read_config_word +EXPORT_SYMBOL vmlinux 0xde9360ba totalram_pages +EXPORT_SYMBOL vmlinux 0xde9b17ed agp3_generic_fetch_size +EXPORT_SYMBOL vmlinux 0xde9f91ab __insert_inode_hash +EXPORT_SYMBOL vmlinux 0xdea915db generic_file_buffered_write +EXPORT_SYMBOL vmlinux 0xdebe4d9d get_sb_single +EXPORT_SYMBOL vmlinux 0xdf0da3cc acpi_get_devices +EXPORT_SYMBOL vmlinux 0xdf2a62ca pci_remove_bus_device +EXPORT_SYMBOL vmlinux 0xdf60cc27 __print_symbol +EXPORT_SYMBOL vmlinux 0xdf8c695a __ndelay +EXPORT_SYMBOL vmlinux 0xdf929370 fs_overflowgid +EXPORT_SYMBOL vmlinux 0xdfab3516 agp_collect_device_status +EXPORT_SYMBOL vmlinux 0xe00fb238 release_resource +EXPORT_SYMBOL vmlinux 0xe012292d vmtruncate +EXPORT_SYMBOL vmlinux 0xe061deae tty_check_change +EXPORT_SYMBOL vmlinux 0xe075d6eb iter_div_u64_rem +EXPORT_SYMBOL vmlinux 0xe085650d bdi_init +EXPORT_SYMBOL vmlinux 0xe09f7a59 nf_setsockopt +EXPORT_SYMBOL vmlinux 0xe0ac8bd2 acpi_bus_generate_netlink_event +EXPORT_SYMBOL vmlinux 0xe0b13336 argv_free +EXPORT_SYMBOL vmlinux 0xe0b5502d adjust_resource +EXPORT_SYMBOL vmlinux 0xe0d625aa pci_setup_cardbus +EXPORT_SYMBOL vmlinux 0xe0d8d25b blk_queue_free_tags +EXPORT_SYMBOL vmlinux 0xe0fbbb15 I_BDEV +EXPORT_SYMBOL vmlinux 0xe113bbbc csum_partial +EXPORT_SYMBOL vmlinux 0xe13cd8a7 dmi_name_in_vendors +EXPORT_SYMBOL vmlinux 0xe1761617 security_inet_conn_request +EXPORT_SYMBOL vmlinux 0xe1a03c63 tcf_em_tree_dump +EXPORT_SYMBOL vmlinux 0xe1b19e8a audit_log_end +EXPORT_SYMBOL vmlinux 0xe1fa05f0 agp_generic_remove_memory +EXPORT_SYMBOL vmlinux 0xe1fe8cae sock_wmalloc +EXPORT_SYMBOL vmlinux 0xe20aa063 clear_page_dirty_for_io +EXPORT_SYMBOL vmlinux 0xe20d59ab pnp_stop_dev +EXPORT_SYMBOL vmlinux 0xe20ff39c tcp_prot +EXPORT_SYMBOL vmlinux 0xe22604f4 may_umount +EXPORT_SYMBOL vmlinux 0xe24050c7 scnprintf +EXPORT_SYMBOL vmlinux 0xe24d3a97 jiffies_64 +EXPORT_SYMBOL vmlinux 0xe24d5a02 ip_cmsg_recv +EXPORT_SYMBOL vmlinux 0xe26b1fe7 read_dev_sector +EXPORT_SYMBOL vmlinux 0xe2a17e0f dmam_alloc_coherent +EXPORT_SYMBOL vmlinux 0xe2b89662 xfrm_dst_ifdown +EXPORT_SYMBOL vmlinux 0xe2c8a6f4 inet_dev_addr_type +EXPORT_SYMBOL vmlinux 0xe2d5255a strcmp +EXPORT_SYMBOL vmlinux 0xe302ce6c cont_write_begin +EXPORT_SYMBOL vmlinux 0xe33e3dca kmem_cache_size +EXPORT_SYMBOL vmlinux 0xe33f2f86 get_disk +EXPORT_SYMBOL vmlinux 0xe351633f genl_register_family +EXPORT_SYMBOL vmlinux 0xe38ed5d1 skb_over_panic +EXPORT_SYMBOL vmlinux 0xe3a334d3 __nla_put_nohdr +EXPORT_SYMBOL vmlinux 0xe3b0192b vscnprintf +EXPORT_SYMBOL vmlinux 0xe3beb57f dma_async_memcpy_pg_to_pg +EXPORT_SYMBOL vmlinux 0xe3f09148 neigh_compat_output +EXPORT_SYMBOL vmlinux 0xe3fbe148 acpi_install_table_handler +EXPORT_SYMBOL vmlinux 0xe40af88d pci_disable_msi +EXPORT_SYMBOL vmlinux 0xe414d795 dquot_drop +EXPORT_SYMBOL vmlinux 0xe43617f7 acpi_gbl_FADT +EXPORT_SYMBOL vmlinux 0xe4488a99 sk_dst_check +EXPORT_SYMBOL vmlinux 0xe44928c2 flock_lock_file_wait +EXPORT_SYMBOL vmlinux 0xe456bd3a complete +EXPORT_SYMBOL vmlinux 0xe45a1e90 vfs_create +EXPORT_SYMBOL vmlinux 0xe4781db5 sock_kfree_s +EXPORT_SYMBOL vmlinux 0xe484e35f ioread32 +EXPORT_SYMBOL vmlinux 0xe4870354 _read_trylock +EXPORT_SYMBOL vmlinux 0xe4c1df3e _read_lock_bh +EXPORT_SYMBOL vmlinux 0xe4c37a71 blk_get_request +EXPORT_SYMBOL vmlinux 0xe5122890 flow_cache_genid +EXPORT_SYMBOL vmlinux 0xe523ad75 synchronize_irq +EXPORT_SYMBOL vmlinux 0xe52947e7 __phys_addr +EXPORT_SYMBOL vmlinux 0xe52bed82 unbind_con_driver +EXPORT_SYMBOL vmlinux 0xe538f6df elv_rb_find +EXPORT_SYMBOL vmlinux 0xe543e1fd splice_direct_to_actor +EXPORT_SYMBOL vmlinux 0xe55484ce neigh_seq_stop +EXPORT_SYMBOL vmlinux 0xe55704ab nf_hooks +EXPORT_SYMBOL vmlinux 0xe57878a1 in6_pton +EXPORT_SYMBOL vmlinux 0xe5867808 dlci_ioctl_set +EXPORT_SYMBOL vmlinux 0xe5ba71a2 __f_setown +EXPORT_SYMBOL vmlinux 0xe5c78a99 do_blank_screen +EXPORT_SYMBOL vmlinux 0xe694cc8a set_current_groups +EXPORT_SYMBOL vmlinux 0xe69ca86a __pci_register_driver +EXPORT_SYMBOL vmlinux 0xe69f63ff d_path +EXPORT_SYMBOL vmlinux 0xe6c2053d pci_get_slot +EXPORT_SYMBOL vmlinux 0xe6ce2e19 file_fsync +EXPORT_SYMBOL vmlinux 0xe6df4c74 dma_pool_alloc +EXPORT_SYMBOL vmlinux 0xe6ebe162 skb_copy_bits +EXPORT_SYMBOL vmlinux 0xe6fb18a3 ip_ct_attach +EXPORT_SYMBOL vmlinux 0xe6fbe430 can_do_mlock +EXPORT_SYMBOL vmlinux 0xe716baed acpi_unregister_ioapic +EXPORT_SYMBOL vmlinux 0xe7177e73 end_request +EXPORT_SYMBOL vmlinux 0xe7537902 brioctl_set +EXPORT_SYMBOL vmlinux 0xe775b220 mpage_writepages +EXPORT_SYMBOL vmlinux 0xe78effae tcp_check_req +EXPORT_SYMBOL vmlinux 0xe7a43b61 bio_clone +EXPORT_SYMBOL vmlinux 0xe7bfcb3c dst_release +EXPORT_SYMBOL vmlinux 0xe7d0a9a0 nf_log_unregister +EXPORT_SYMBOL vmlinux 0xe7d4daac seq_list_next +EXPORT_SYMBOL vmlinux 0xe80ce219 sysctl_tcp_dma_copybreak +EXPORT_SYMBOL vmlinux 0xe8104dbe input_grab_device +EXPORT_SYMBOL vmlinux 0xe8116e08 __kmalloc_node +EXPORT_SYMBOL vmlinux 0xe81a4746 call_usermodehelper_pipe +EXPORT_SYMBOL vmlinux 0xe820304e mpage_readpage +EXPORT_SYMBOL vmlinux 0xe8259d6c qdisc_watchdog_schedule +EXPORT_SYMBOL vmlinux 0xe8315025 netlink_dump_start +EXPORT_SYMBOL vmlinux 0xe8583614 posix_acl_from_xattr +EXPORT_SYMBOL vmlinux 0xe89a3b39 inode_add_bytes +EXPORT_SYMBOL vmlinux 0xe8a12d11 shrink_dcache_parent +EXPORT_SYMBOL vmlinux 0xe8a26983 ip_mc_join_group +EXPORT_SYMBOL vmlinux 0xe8c35ee7 simple_transaction_get +EXPORT_SYMBOL vmlinux 0xe8cc2910 dev_open +EXPORT_SYMBOL vmlinux 0xe8cd902e hweight16 +EXPORT_SYMBOL vmlinux 0xe910b532 del_timer_sync +EXPORT_SYMBOL vmlinux 0xe911a2c1 __mark_inode_dirty +EXPORT_SYMBOL vmlinux 0xe914e41e strcpy +EXPORT_SYMBOL vmlinux 0xe9456a5a sysctl_xfrm_aevent_rseqth +EXPORT_SYMBOL vmlinux 0xe997667b wrmsr_on_cpu +EXPORT_SYMBOL vmlinux 0xe9cdba0c inet_listen +EXPORT_SYMBOL vmlinux 0xe9e9bd42 key_task_permission +EXPORT_SYMBOL vmlinux 0xe9f44cb5 pci_enable_device_mem +EXPORT_SYMBOL vmlinux 0xea0fafac write_one_page +EXPORT_SYMBOL vmlinux 0xea10655a __bitmap_intersects +EXPORT_SYMBOL vmlinux 0xea147363 printk +EXPORT_SYMBOL vmlinux 0xea3ddc95 vfs_read +EXPORT_SYMBOL vmlinux 0xea44461f key_type_keyring +EXPORT_SYMBOL vmlinux 0xea69a8a6 kernel_sendmsg +EXPORT_SYMBOL vmlinux 0xea6fcdaa genl_unregister_family +EXPORT_SYMBOL vmlinux 0xea757d9e inet_frags_init +EXPORT_SYMBOL vmlinux 0xea8636c6 xfrm_stateonly_find +EXPORT_SYMBOL vmlinux 0xead58fb9 print_hex_dump +EXPORT_SYMBOL vmlinux 0xeae3dfd6 __const_udelay +EXPORT_SYMBOL vmlinux 0xeaf31a69 sock_create +EXPORT_SYMBOL vmlinux 0xeb1fabf6 interruptible_sleep_on +EXPORT_SYMBOL vmlinux 0xeb228272 posix_acl_create_masq +EXPORT_SYMBOL vmlinux 0xeb395084 param_get_invbool +EXPORT_SYMBOL vmlinux 0xeb4c5c40 netpoll_print_options +EXPORT_SYMBOL vmlinux 0xeb57136e __bread +EXPORT_SYMBOL vmlinux 0xeb7710ca pv_mmu_ops +EXPORT_SYMBOL vmlinux 0xeb879792 tcp_poll +EXPORT_SYMBOL vmlinux 0xeb8f54b3 strstrip +EXPORT_SYMBOL vmlinux 0xebbc1f62 cpufreq_get_policy +EXPORT_SYMBOL vmlinux 0xebbf1dba strncasecmp +EXPORT_SYMBOL vmlinux 0xebd273a6 strict_strtoull +EXPORT_SYMBOL vmlinux 0xec39a70d xfrm_policy_delete +EXPORT_SYMBOL vmlinux 0xec4a2113 dev_getfirstbyhwtype +EXPORT_SYMBOL vmlinux 0xec7744af xfrm_state_lookup_byaddr +EXPORT_SYMBOL vmlinux 0xec860422 bioset_free +EXPORT_SYMBOL vmlinux 0xec8a79c2 do_splice_from +EXPORT_SYMBOL vmlinux 0xecb3f10d pci_bus_write_config_dword +EXPORT_SYMBOL vmlinux 0xecde1418 _spin_lock_irq +EXPORT_SYMBOL vmlinux 0xecf65ffe audit_log_format +EXPORT_SYMBOL vmlinux 0xed933491 llc_build_and_send_ui_pkt +EXPORT_SYMBOL vmlinux 0xedbaee5e nla_strcmp +EXPORT_SYMBOL vmlinux 0xedc03953 iounmap +EXPORT_SYMBOL vmlinux 0xedd14538 param_get_uint +EXPORT_SYMBOL vmlinux 0xee007bf5 vfs_unlink +EXPORT_SYMBOL vmlinux 0xee019f0b atm_alloc_charge +EXPORT_SYMBOL vmlinux 0xee2d0fc7 _local_bh_enable +EXPORT_SYMBOL vmlinux 0xee4cf46e dev_set_promiscuity +EXPORT_SYMBOL vmlinux 0xee60c909 compat_sock_common_getsockopt +EXPORT_SYMBOL vmlinux 0xee668708 page_follow_link_light +EXPORT_SYMBOL vmlinux 0xee6718a0 fb_set_suspend +EXPORT_SYMBOL vmlinux 0xee7eb9e1 pnp_platform_devices +EXPORT_SYMBOL vmlinux 0xee9c3dd7 pneigh_lookup +EXPORT_SYMBOL vmlinux 0xeea2e5f2 ip_mc_rejoin_group +EXPORT_SYMBOL vmlinux 0xeea9dbaf bitmap_bitremap +EXPORT_SYMBOL vmlinux 0xeeb1717c param_array_get +EXPORT_SYMBOL vmlinux 0xeec0352f neigh_for_each +EXPORT_SYMBOL vmlinux 0xeec45628 page_put_link +EXPORT_SYMBOL vmlinux 0xeecaea22 down_write_trylock +EXPORT_SYMBOL vmlinux 0xeed022bd console_start +EXPORT_SYMBOL vmlinux 0xeefc3673 task_tgid_nr_ns +EXPORT_SYMBOL vmlinux 0xef0d2fff sk_reset_timer +EXPORT_SYMBOL vmlinux 0xef488713 tcp_md5_hash_key +EXPORT_SYMBOL vmlinux 0xef4f7783 pci_pme_capable +EXPORT_SYMBOL vmlinux 0xef5a5e81 simple_unlink +EXPORT_SYMBOL vmlinux 0xef9aedfc boot_option_idle_override +EXPORT_SYMBOL vmlinux 0xefdd70ce security_secid_to_secctx +EXPORT_SYMBOL vmlinux 0xefe099c3 acpi_get_event_status +EXPORT_SYMBOL vmlinux 0xeff3237e del_gendisk +EXPORT_SYMBOL vmlinux 0xeff62008 pci_restore_state +EXPORT_SYMBOL vmlinux 0xf0009fee put_pages_list +EXPORT_SYMBOL vmlinux 0xf03cae64 posix_acl_permission +EXPORT_SYMBOL vmlinux 0xf03f6857 unregister_console +EXPORT_SYMBOL vmlinux 0xf060a8ac generic_writepages +EXPORT_SYMBOL vmlinux 0xf065f629 ioread16be +EXPORT_SYMBOL vmlinux 0xf092cfdb igrab +EXPORT_SYMBOL vmlinux 0xf0a51f91 serio_unregister_port +EXPORT_SYMBOL vmlinux 0xf0b57c68 param_set_long +EXPORT_SYMBOL vmlinux 0xf0f1246c kvasprintf +EXPORT_SYMBOL vmlinux 0xf10681dc open_by_devnum +EXPORT_SYMBOL vmlinux 0xf10de535 ioread8 +EXPORT_SYMBOL vmlinux 0xf11543ff find_first_zero_bit +EXPORT_SYMBOL vmlinux 0xf116d4b5 copy_in_user +EXPORT_SYMBOL vmlinux 0xf1331904 generic_osync_inode +EXPORT_SYMBOL vmlinux 0xf13772f5 set_disk_ro +EXPORT_SYMBOL vmlinux 0xf13a402f tty_unregister_device +EXPORT_SYMBOL vmlinux 0xf1470748 acpi_bus_generate_proc_event +EXPORT_SYMBOL vmlinux 0xf162fe2d sysctl_xfrm_aevent_etime +EXPORT_SYMBOL vmlinux 0xf16afa2f register_con_driver +EXPORT_SYMBOL vmlinux 0xf174ed48 acquire_console_sem +EXPORT_SYMBOL vmlinux 0xf17bb80c simple_transaction_read +EXPORT_SYMBOL vmlinux 0xf18bcd33 find_get_page +EXPORT_SYMBOL vmlinux 0xf195c682 fb_invert_cmaps +EXPORT_SYMBOL vmlinux 0xf1aba93a pci_enable_wake +EXPORT_SYMBOL vmlinux 0xf1c6a746 d_move +EXPORT_SYMBOL vmlinux 0xf1c91e9d set_binfmt +EXPORT_SYMBOL vmlinux 0xf1cecbda nobh_write_end +EXPORT_SYMBOL vmlinux 0xf1d4329b cdev_add +EXPORT_SYMBOL vmlinux 0xf1d98b34 neigh_table_init +EXPORT_SYMBOL vmlinux 0xf1dc9939 simple_empty +EXPORT_SYMBOL vmlinux 0xf1e98c74 avenrun +EXPORT_SYMBOL vmlinux 0xf20dabd8 free_irq +EXPORT_SYMBOL vmlinux 0xf2126d75 dma_async_device_register +EXPORT_SYMBOL vmlinux 0xf225158b skb_copy_datagram_iovec +EXPORT_SYMBOL vmlinux 0xf230200b blk_start_queue +EXPORT_SYMBOL vmlinux 0xf246de13 tcf_hash_destroy +EXPORT_SYMBOL vmlinux 0xf2997713 tty_termios_hw_change +EXPORT_SYMBOL vmlinux 0xf2a6d2bf xfrm_policy_count +EXPORT_SYMBOL vmlinux 0xf2afa595 param_get_charp +EXPORT_SYMBOL vmlinux 0xf2b4b9be vfs_dq_quota_on_remount +EXPORT_SYMBOL vmlinux 0xf2c9786e put_filp +EXPORT_SYMBOL vmlinux 0xf3045cde unregister_exec_domain +EXPORT_SYMBOL vmlinux 0xf313da4e sha_transform +EXPORT_SYMBOL vmlinux 0xf3341268 __clear_user +EXPORT_SYMBOL vmlinux 0xf335e5f8 netif_rx +EXPORT_SYMBOL vmlinux 0xf338d4c3 netlink_unregister_notifier +EXPORT_SYMBOL vmlinux 0xf34236da pci_disable_device +EXPORT_SYMBOL vmlinux 0xf34242f8 tty_insert_flip_string_flags +EXPORT_SYMBOL vmlinux 0xf3431eb9 vfs_quota_on +EXPORT_SYMBOL vmlinux 0xf346231f seq_list_start_head +EXPORT_SYMBOL vmlinux 0xf35e7ab3 bd_release +EXPORT_SYMBOL vmlinux 0xf3652ceb set_blocksize +EXPORT_SYMBOL vmlinux 0xf373278b dquot_commit +EXPORT_SYMBOL vmlinux 0xf3b30b6d locks_remove_posix +EXPORT_SYMBOL vmlinux 0xf3bf0bce __bitmap_complement +EXPORT_SYMBOL vmlinux 0xf3ecd8e7 xfrm_state_add +EXPORT_SYMBOL vmlinux 0xf40545ff d_instantiate +EXPORT_SYMBOL vmlinux 0xf4236e3b agp_put_bridge +EXPORT_SYMBOL vmlinux 0xf42ae8c8 ilookup5_nowait +EXPORT_SYMBOL vmlinux 0xf441ac43 ioread8_rep +EXPORT_SYMBOL vmlinux 0xf47d47e0 acpi_enable_gpe +EXPORT_SYMBOL vmlinux 0xf49bc67a atm_pcr_goal +EXPORT_SYMBOL vmlinux 0xf4a5c213 avail_to_resrv_perfctr_nmi_bit +EXPORT_SYMBOL vmlinux 0xf4f14de6 rtnl_trylock +EXPORT_SYMBOL vmlinux 0xf4f28009 iget5_locked +EXPORT_SYMBOL vmlinux 0xf4f52f93 dqstats +EXPORT_SYMBOL vmlinux 0xf4f8cddd ps2_handle_response +EXPORT_SYMBOL vmlinux 0xf50f4340 alloc_trdev +EXPORT_SYMBOL vmlinux 0xf5120315 ip_setsockopt +EXPORT_SYMBOL vmlinux 0xf5143170 ip_route_me_harder +EXPORT_SYMBOL vmlinux 0xf51ae235 touch_nmi_watchdog +EXPORT_SYMBOL vmlinux 0xf528dfde sock_recvmsg +EXPORT_SYMBOL vmlinux 0xf53d4c26 qdisc_class_hash_destroy +EXPORT_SYMBOL vmlinux 0xf58f4c88 __nla_put +EXPORT_SYMBOL vmlinux 0xf5a73bf9 pci_enable_msi +EXPORT_SYMBOL vmlinux 0xf5ce9811 tcp_memory_allocated +EXPORT_SYMBOL vmlinux 0xf5f0b7cd pci_set_dma_max_seg_size +EXPORT_SYMBOL vmlinux 0xf5f38475 thermal_zone_device_unregister +EXPORT_SYMBOL vmlinux 0xf61f6666 dmam_pool_destroy +EXPORT_SYMBOL vmlinux 0xf63b2fe7 backlight_device_unregister +EXPORT_SYMBOL vmlinux 0xf63e1c82 tcp_getsockopt +EXPORT_SYMBOL vmlinux 0xf666cbb3 __memcpy_fromio +EXPORT_SYMBOL vmlinux 0xf676f27c pci_find_bus +EXPORT_SYMBOL vmlinux 0xf6b7689b find_or_create_page +EXPORT_SYMBOL vmlinux 0xf6bb4729 color_table +EXPORT_SYMBOL vmlinux 0xf6cdb69b key_revoke +EXPORT_SYMBOL vmlinux 0xf6ebc03b net_ratelimit +EXPORT_SYMBOL vmlinux 0xf708c0a3 aio_complete +EXPORT_SYMBOL vmlinux 0xf7439a94 skb_gso_segment +EXPORT_SYMBOL vmlinux 0xf749534a gen_pool_free +EXPORT_SYMBOL vmlinux 0xf7665d17 dev_load +EXPORT_SYMBOL vmlinux 0xf76b5983 sock_common_recvmsg +EXPORT_SYMBOL vmlinux 0xf78a07a6 tcp_splice_read +EXPORT_SYMBOL vmlinux 0xf78d04ab netlink_register_notifier +EXPORT_SYMBOL vmlinux 0xf791ca2c tty_unregister_driver +EXPORT_SYMBOL vmlinux 0xf7c7ad11 deactivate_super +EXPORT_SYMBOL vmlinux 0xf7caa6ed inet_dgram_connect +EXPORT_SYMBOL vmlinux 0xf7d17bb9 bio_map_kern +EXPORT_SYMBOL vmlinux 0xf7dfff37 tcp_sendmsg +EXPORT_SYMBOL vmlinux 0xf80d9017 dma_free_coherent +EXPORT_SYMBOL vmlinux 0xf81512da locks_mandatory_area +EXPORT_SYMBOL vmlinux 0xf82786f0 sget +EXPORT_SYMBOL vmlinux 0xf82abc1d isa_dma_bridge_buggy +EXPORT_SYMBOL vmlinux 0xf82e3d47 acpi_initialize_objects +EXPORT_SYMBOL vmlinux 0xf82f1109 utf8_wctomb +EXPORT_SYMBOL vmlinux 0xf8814f73 rb_last +EXPORT_SYMBOL vmlinux 0xf88e0ee2 acpi_get_table_header +EXPORT_SYMBOL vmlinux 0xf88f5be6 security_d_instantiate +EXPORT_SYMBOL vmlinux 0xf890fe7f pm_idle +EXPORT_SYMBOL vmlinux 0xf89843f9 schedule_work +EXPORT_SYMBOL vmlinux 0xf8aa47ae mutex_lock_killable +EXPORT_SYMBOL vmlinux 0xf8b30e93 mempool_create +EXPORT_SYMBOL vmlinux 0xf8cf9ee5 abort_exclusive_wait +EXPORT_SYMBOL vmlinux 0xf8cfff29 tty_get_baud_rate +EXPORT_SYMBOL vmlinux 0xf8d42c80 set_trace_device +EXPORT_SYMBOL vmlinux 0xf8e126c9 blk_execute_rq +EXPORT_SYMBOL vmlinux 0xf8eecb79 __nla_reserve +EXPORT_SYMBOL vmlinux 0xf9163729 xfrm_policy_destroy +EXPORT_SYMBOL vmlinux 0xf943f0de seq_escape +EXPORT_SYMBOL vmlinux 0xf97a76a6 pv_cpu_ops +EXPORT_SYMBOL vmlinux 0xf9a482f9 msleep +EXPORT_SYMBOL vmlinux 0xf9fbc29a put_tty_driver +EXPORT_SYMBOL vmlinux 0xfa0564fc __wait_on_bit_lock +EXPORT_SYMBOL vmlinux 0xfa19c69e pci_scan_bus_parented +EXPORT_SYMBOL vmlinux 0xfa5283cb input_unregister_handler +EXPORT_SYMBOL vmlinux 0xfa6ee97a pci_get_class +EXPORT_SYMBOL vmlinux 0xfa842fdc down_write +EXPORT_SYMBOL vmlinux 0xfa935760 __sk_mem_schedule +EXPORT_SYMBOL vmlinux 0xfaaee3ce tty_register_driver +EXPORT_SYMBOL vmlinux 0xfab96681 load_nls_default +EXPORT_SYMBOL vmlinux 0xfae600b6 is_container_init +EXPORT_SYMBOL vmlinux 0xfaf98462 bitrev32 +EXPORT_SYMBOL vmlinux 0xfb0443fb acpi_get_parent +EXPORT_SYMBOL vmlinux 0xfb0cf2e9 touch_all_softlockup_watchdogs +EXPORT_SYMBOL vmlinux 0xfb6af58d recalc_sigpending +EXPORT_SYMBOL vmlinux 0xfba0c2e0 llc_sap_list_lock +EXPORT_SYMBOL vmlinux 0xfbb469ed acpi_unlock_battery_dir +EXPORT_SYMBOL vmlinux 0xfbbad7ad vfs_writev +EXPORT_SYMBOL vmlinux 0xfbdec3ba sk_receive_skb +EXPORT_SYMBOL vmlinux 0xfbed20d8 ioremap_nocache +EXPORT_SYMBOL vmlinux 0xfbf5c747 framebuffer_release +EXPORT_SYMBOL vmlinux 0xfbf92453 param_get_bool +EXPORT_SYMBOL vmlinux 0xfc02b7ad sysctl_tcp_wmem +EXPORT_SYMBOL vmlinux 0xfc1106ae alloc_hippi_dev +EXPORT_SYMBOL vmlinux 0xfc383907 pcim_iounmap +EXPORT_SYMBOL vmlinux 0xfc39e32f ioport_unmap +EXPORT_SYMBOL vmlinux 0xfc52c08c pcie_get_readrq +EXPORT_SYMBOL vmlinux 0xfc8b429c devm_ioport_unmap +EXPORT_SYMBOL vmlinux 0xfc8f9de2 path_get +EXPORT_SYMBOL vmlinux 0xfc94e4e8 dquot_alloc_inode +EXPORT_SYMBOL vmlinux 0xfc959bbc __lookup_hash +EXPORT_SYMBOL vmlinux 0xfcaa04a0 out_of_line_wait_on_bit_lock +EXPORT_SYMBOL vmlinux 0xfcb5e850 xfrm_state_check_expire +EXPORT_SYMBOL vmlinux 0xfcb97d2f pnp_device_attach +EXPORT_SYMBOL vmlinux 0xfcdd8cf6 param_get_ushort +EXPORT_SYMBOL vmlinux 0xfcec0987 enable_irq +EXPORT_SYMBOL vmlinux 0xfcfa03ff fb_videomode_to_modelist +EXPORT_SYMBOL vmlinux 0xfd12c14a call_usermodehelper_setcleanup +EXPORT_SYMBOL vmlinux 0xfd1c92a8 per_cpu____irq_regs +EXPORT_SYMBOL vmlinux 0xfd1ee432 pci_find_slot +EXPORT_SYMBOL vmlinux 0xfd98879a rb_next +EXPORT_SYMBOL vmlinux 0xfd99bf71 in_dev_finish_destroy +EXPORT_SYMBOL vmlinux 0xfdb9b629 ioread32be +EXPORT_SYMBOL vmlinux 0xfde2145a boot_tvec_bases +EXPORT_SYMBOL vmlinux 0xfdf2d800 pci_pme_active +EXPORT_SYMBOL vmlinux 0xfe047ce6 acpi_enter_sleep_state +EXPORT_SYMBOL vmlinux 0xfe0f5e62 request_key +EXPORT_SYMBOL vmlinux 0xfe144965 search_binary_handler +EXPORT_SYMBOL vmlinux 0xfe26fc7c nr_node_ids +EXPORT_SYMBOL vmlinux 0xfe3543fb block_sync_page +EXPORT_SYMBOL vmlinux 0xfe392bcd generic_segment_checks +EXPORT_SYMBOL vmlinux 0xfe4bf321 simple_prepare_write +EXPORT_SYMBOL vmlinux 0xfe5d4bb2 sys_tz +EXPORT_SYMBOL vmlinux 0xfe769456 unregister_netdevice_notifier +EXPORT_SYMBOL vmlinux 0xfe7c4287 nr_cpu_ids +EXPORT_SYMBOL vmlinux 0xfea24a29 blk_integrity_compare +EXPORT_SYMBOL vmlinux 0xfec3c2f2 bcd2bin +EXPORT_SYMBOL vmlinux 0xfedd35fc console_suspend_enabled +EXPORT_SYMBOL vmlinux 0xff1e9dd8 seq_list_start +EXPORT_SYMBOL vmlinux 0xff1f2cf8 vfs_mkdir +EXPORT_SYMBOL vmlinux 0xff6878cf fb_default_cmap +EXPORT_SYMBOL vmlinux 0xff708fd3 mempool_destroy +EXPORT_SYMBOL vmlinux 0xff9ca065 fb_edid_to_monspecs +EXPORT_SYMBOL vmlinux 0xffafdc5c _read_unlock_irq +EXPORT_SYMBOL vmlinux 0xffd563f2 netdev_state_change +EXPORT_SYMBOL vmlinux 0xffd5a395 default_wake_function +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x00aaf935 kvm_disable_tdp +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x02f5beff kvm_release_page_clean +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x03024463 kvm_read_guest_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x063882d2 emulate_instruction +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x07b248b1 kvm_set_memory_region +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x094ac8f4 kvm_get_pfn +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x0b644f75 kvm_get_cs_db_l_bits +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x0d2a52b7 kvm_emulate_halt +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x0e0f57b7 kvm_lmsw +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x0fc5bd2d kvm_vcpu_init +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x12d1b23b kvm_release_pfn_clean +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x16b0f339 kvm_set_cr3 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x1cb40c6a kvm_init +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x1e4580bb kvm_release_pfn_dirty +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x2322e039 kvm_set_pfn_accessed +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x258ba34e kvm_load_guest_fpu +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x25a64765 kvm_lapic_set_tpr +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x27046576 kvm_exit +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x2860368e kvm_task_switch +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x28982f9e load_pdptrs +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x317f9e6b kvm_enable_efer_bits +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x3259bae0 emulator_write_emulated +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x32770619 kvm_put_guest_fpu +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x3c18bdce kvm_mmu_unprotect_page_virt +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x41e427f1 kvm_resched +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x480f7919 kvm_mmu_page_fault +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x4a7cbe69 is_error_pfn +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x51700a43 kvm_set_page_dirty +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x543ca756 kvm_read_guest +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x54db764b kvm_mmu_load +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x551c950e kvm_vcpu_uninit +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x56df6293 kvm_timer_intr_post +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x58553d8c is_error_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x5a5264b0 kvm_emulate_pio +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x5cbf8c7a gfn_to_hva +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x60affbca kvm_set_cr0 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x61ab18b1 kvm_set_cr4 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x6263cc8d emulator_read_std +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x62a63d3c kvm_set_cr8 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x69a08865 kvm_cpu_get_interrupt +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x6a711094 kvm_clear_guest +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x6cdf6b6e kvm_set_apic_base +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8010d66e kvm_lapic_get_base +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x80fae6d5 gfn_to_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8be69d74 kvm_clear_guest_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8c6b4891 kvm_create_lapic +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8ce4f3ab kvm_enable_tdp +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8e7f9b47 segment_base +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8fb12e44 kvm_lapic_reset +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xa361bc65 kvm_set_pfn_dirty +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xb130cd02 kvm_get_kvm +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xb296a7ec kvm_inject_nmi +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xba5a40d1 kvm_get_msr_common +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbcd62c8c kvm_put_kvm +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbcec10aa kvm_cpu_has_interrupt +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbd377dc9 kvm_mmu_set_nonpresent_ptes +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbd86163a kvm_handle_fault_on_reboot +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbd94103b kvm_mmu_set_base_ptes +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xc04e7e70 kvm_lapic_find_highest_irr +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xc11fb845 kvm_lapic_enabled +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xc20bbcdf kvm_is_visible_gfn +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xc4f2a713 kvm_set_msr_common +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xc8cb24fb gfn_to_pfn +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xcd231ca7 fx_init +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xcea10f4a kvm_get_apic_base +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd0b2727a kvm_mmu_set_mask_ptes +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd291c548 kvm_queue_exception +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd296def9 kvm_is_error_hva +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd2f1fa51 kvm_emulate_hypercall +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd632aa8e kvm_queue_exception_e +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd893b928 kvm_inject_pending_timer_irqs +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xdbb79092 kvm_emulate_pio_string +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xdc7e4739 kvm_get_cr8 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xddf46322 kvm_write_guest_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xdf095746 kvm_report_emulation_failure +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xea089346 kvm_lapic_get_cr8 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xed4f60fb kvm_release_page_dirty +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xee72f347 kvm_mmu_reset_context +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xf0b1ff70 __kvm_set_memory_region +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xf2ae219d kvm_vcpu_cache +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xfa5d1b13 kvm_emulate_cpuid +EXPORT_SYMBOL_GPL crypto/aead 0x4349aca8 aead_geniv_exit +EXPORT_SYMBOL_GPL crypto/aead 0x4b91e559 aead_geniv_alloc +EXPORT_SYMBOL_GPL crypto/aead 0x6a1abce3 crypto_nivaead_type +EXPORT_SYMBOL_GPL crypto/aead 0x77417b3d crypto_aead_setauthsize +EXPORT_SYMBOL_GPL crypto/aead 0x9a69805e crypto_alloc_aead +EXPORT_SYMBOL_GPL crypto/aead 0x9d23fc1a aead_geniv_free +EXPORT_SYMBOL_GPL crypto/aead 0xced86b9a aead_geniv_init +EXPORT_SYMBOL_GPL crypto/aead 0xe09cb8f7 crypto_grab_aead +EXPORT_SYMBOL_GPL crypto/aead 0xe6839bae crypto_aead_type +EXPORT_SYMBOL_GPL crypto/aes_generic 0x1381bf2d crypto_ft_tab +EXPORT_SYMBOL_GPL crypto/aes_generic 0x22894d94 crypto_il_tab +EXPORT_SYMBOL_GPL crypto/aes_generic 0x465dc396 crypto_aes_set_key +EXPORT_SYMBOL_GPL crypto/aes_generic 0x5f943003 crypto_it_tab +EXPORT_SYMBOL_GPL crypto/aes_generic 0x5fe743de crypto_aes_expand_key +EXPORT_SYMBOL_GPL crypto/aes_generic 0x6e9cc2ba crypto_fl_tab +EXPORT_SYMBOL_GPL crypto/async_tx/async_memcpy 0x8e73562f async_memcpy +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0x46c982af __async_tx_find_channel +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0x6093049c async_tx_quiesce +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0x6b4a6db2 async_tx_issue_pending_all +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0xa1f43ed1 dma_wait_for_async_tx +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0xaf83023a async_tx_run_dependencies +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0xde7b5108 async_tx_submit +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0xfec58724 async_trigger_callback +EXPORT_SYMBOL_GPL crypto/async_tx/async_xor 0xe1b70046 async_xor +EXPORT_SYMBOL_GPL crypto/async_tx/async_xor 0xf4136bf0 async_xor_zero_sum +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x01410703 blkcipher_walk_virt +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x0787fb98 crypto_ablkcipher_type +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x0a206bca blkcipher_walk_virt_block +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x0ebc9dbc skcipher_geniv_free +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x1c35cb76 crypto_alloc_ablkcipher +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x2bbc05cc skcipher_geniv_exit +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x54ccea79 skcipher_geniv_init +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x713e14b2 blkcipher_walk_phys +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x9227a3a7 crypto_blkcipher_type +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0xacc49a94 skcipher_geniv_alloc +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0xc0a800fd crypto_grab_skcipher +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0xd088ccd5 blkcipher_walk_done +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0xd628b5e5 crypto_givcipher_type +EXPORT_SYMBOL_GPL crypto/des_generic 0xcfd9a2c0 des_ekey +EXPORT_SYMBOL_GPL crypto/twofish_common 0x97065ba1 twofish_setkey +EXPORT_SYMBOL_GPL drivers/acpi/dock 0x100c48a2 unregister_dock_notifier +EXPORT_SYMBOL_GPL drivers/acpi/dock 0x2611fbee register_hotplug_dock_device +EXPORT_SYMBOL_GPL drivers/acpi/dock 0x318920b1 register_dock_notifier +EXPORT_SYMBOL_GPL drivers/acpi/dock 0xbd506a46 unregister_hotplug_dock_device +EXPORT_SYMBOL_GPL drivers/acpi/dock 0xcc6ab305 is_dock_device +EXPORT_SYMBOL_GPL drivers/acpi/sbshc 0x0ad5c33f acpi_smbus_register_callback +EXPORT_SYMBOL_GPL drivers/acpi/sbshc 0x158c2ad0 acpi_smbus_unregister_callback +EXPORT_SYMBOL_GPL drivers/acpi/sbshc 0x526b867a acpi_smbus_read +EXPORT_SYMBOL_GPL drivers/acpi/sbshc 0xb3d5e527 acpi_smbus_write +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0x3ecf6cfc wmi_install_notify_handler +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0x561c634a wmi_evaluate_method +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0x876d29f1 wmi_get_event_data +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0xb5a6ebe2 wmi_remove_notify_handler +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0xc9d4d6d1 wmi_has_guid +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0xda29f8b0 wmi_set_block +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0xfb882fb7 wmi_query_block +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0067df75 ata_tf_from_fis +EXPORT_SYMBOL_GPL drivers/ata/libata 0x00ebcb5d ata_id_string +EXPORT_SYMBOL_GPL drivers/ata/libata 0x011ef430 ata_acpi_stm +EXPORT_SYMBOL_GPL drivers/ata/libata 0x01973548 sata_scr_read +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0305fee1 ata_eh_thaw_port +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0307dd01 ata_sff_data_xfer +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0313ef6a ata_sff_host_intr +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0354bfd7 ata_acpi_gtm +EXPORT_SYMBOL_GPL drivers/ata/libata 0x03e3686c ata_timing_cycle2mode +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0531dcb8 ata_dev_classify +EXPORT_SYMBOL_GPL drivers/ata/libata 0x08068987 ata_port_abort +EXPORT_SYMBOL_GPL drivers/ata/libata 0x087a8d5d ata_scsi_queuecmd +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0961bd88 ata_sff_dma_pause +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0a3b59b3 sata_pmp_error_handler +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0b0b6a20 ata_port_freeze +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0ed51578 ata_sff_port_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0x116a9a26 ata_bus_reset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x12188e2a ata_dev_disable +EXPORT_SYMBOL_GPL drivers/ata/libata 0x17337e16 ata_host_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0x17f0bb9d sata_set_spd +EXPORT_SYMBOL_GPL drivers/ata/libata 0x1aebf2c7 ata_bmdma_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0x1ba12c30 ata_pci_device_do_resume +EXPORT_SYMBOL_GPL drivers/ata/libata 0x26995bd7 ata_sg_init +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2a2b63df ata_link_abort +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2a9e5c44 sata_link_debounce +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2d09a4e1 ata_sff_postreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x35e5fa4d ata_host_resume +EXPORT_SYMBOL_GPL drivers/ata/libata 0x39962572 sata_link_resume +EXPORT_SYMBOL_GPL drivers/ata/libata 0x3b047baf ata_sff_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x3b58e833 ata_pci_bmdma_clear_simplex +EXPORT_SYMBOL_GPL drivers/ata/libata 0x3bedc4f6 ata_port_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0x3e9a3e67 ata_sff_exec_command +EXPORT_SYMBOL_GPL drivers/ata/libata 0x40370180 ata_bmdma_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x40af0dec ata_xfer_mode2mask +EXPORT_SYMBOL_GPL drivers/ata/libata 0x42cc525a ata_do_dev_read_id +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4340b201 ata_cable_80wire +EXPORT_SYMBOL_GPL drivers/ata/libata 0x43f56e82 ata_xfer_mode2shift +EXPORT_SYMBOL_GPL drivers/ata/libata 0x456d3236 ata_sff_irq_on +EXPORT_SYMBOL_GPL drivers/ata/libata 0x479f6fca ata_bmdma_status +EXPORT_SYMBOL_GPL drivers/ata/libata 0x48487e8a ata_sff_irq_clear +EXPORT_SYMBOL_GPL drivers/ata/libata 0x485c9bca ata_cable_40wire +EXPORT_SYMBOL_GPL drivers/ata/libata 0x48fa3b0f ata_host_register +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4af6c5b5 ata_sff_softreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4c1e047c ata_sff_dumb_qc_prep +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4c5bd8f8 ata_pci_sff_init_host +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4d472010 dev_attr_em_message +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4fb4573e ata_sff_tf_read +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4fdc945d sata_deb_timing_normal +EXPORT_SYMBOL_GPL drivers/ata/libata 0x505308a9 ata_sff_data_xfer_noirq +EXPORT_SYMBOL_GPL drivers/ata/libata 0x53385ca5 sata_pmp_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x54a6c777 ata_qc_complete_multiple +EXPORT_SYMBOL_GPL drivers/ata/libata 0x55b07061 ata_dev_pair +EXPORT_SYMBOL_GPL drivers/ata/libata 0x565cf554 ata_sff_wait_ready +EXPORT_SYMBOL_GPL drivers/ata/libata 0x57a01a88 ata_base_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x58d9ba49 dev_attr_sw_activity +EXPORT_SYMBOL_GPL drivers/ata/libata 0x5e0de9f4 ata_host_init +EXPORT_SYMBOL_GPL drivers/ata/libata 0x5e644061 pci_test_config_bits +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6008bc3a ata_host_suspend +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6253cb98 ata_pci_device_do_suspend +EXPORT_SYMBOL_GPL drivers/ata/libata 0x63465ed1 ata_dummy_port_info +EXPORT_SYMBOL_GPL drivers/ata/libata 0x65382e96 ata_cable_sata +EXPORT_SYMBOL_GPL drivers/ata/libata 0x678fc2c4 ata_cable_unknown +EXPORT_SYMBOL_GPL drivers/ata/libata 0x697bfae9 sata_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x69d04571 ata_sff_qc_prep +EXPORT_SYMBOL_GPL drivers/ata/libata 0x69e9a2cb ata_scsi_slave_config +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6b0026b7 ata_sas_slave_configure +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6b24551c ata_pci_device_suspend +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6be44d3f ata_bmdma_mode_filter +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6c71ac01 ata_sff_tf_load +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6e87847c __ata_ehi_push_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0x707ff1bb ata_xfer_mask2mode +EXPORT_SYMBOL_GPL drivers/ata/libata 0x73a48b4a ata_sff_std_ports +EXPORT_SYMBOL_GPL drivers/ata/libata 0x743a165e ata_pack_xfermask +EXPORT_SYMBOL_GPL drivers/ata/libata 0x74d0df6e ata_do_eh +EXPORT_SYMBOL_GPL drivers/ata/libata 0x76888917 ata_sff_thaw +EXPORT_SYMBOL_GPL drivers/ata/libata 0x795d982a sata_link_hardreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7b8b56b0 sata_scr_write +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7c003354 ata_link_online +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7c1512e6 ata_wait_after_reset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7fc8140a ata_sas_queuecmd +EXPORT_SYMBOL_GPL drivers/ata/libata 0x806b8a72 sata_scr_valid +EXPORT_SYMBOL_GPL drivers/ata/libata 0x821660b2 ata_scsi_simulate +EXPORT_SYMBOL_GPL drivers/ata/libata 0x82753eb1 ata_host_alloc +EXPORT_SYMBOL_GPL drivers/ata/libata 0x863c4db0 ata_dummy_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8b752ac1 ata_tf_to_fis +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8d5904c2 ata_eh_analyze_ncq_error +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8d721ca7 ata_sff_hsm_move +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8d874dcc ata_sff_busy_sleep +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8e141dca sata_async_notification +EXPORT_SYMBOL_GPL drivers/ata/libata 0x92bc23c1 ata_host_alloc_pinfo +EXPORT_SYMBOL_GPL drivers/ata/libata 0x9374bbb1 ata_sas_port_init +EXPORT_SYMBOL_GPL drivers/ata/libata 0x93ec66b2 ata_port_pbar_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0x94723b31 ata_std_postreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x94a68723 ata_scsi_slave_destroy +EXPORT_SYMBOL_GPL drivers/ata/libata 0x94dc62d2 ata_scsi_ioctl +EXPORT_SYMBOL_GPL drivers/ata/libata 0x95cf5fc8 ata_sff_dev_classify +EXPORT_SYMBOL_GPL drivers/ata/libata 0x96bd7b68 ata_sff_wait_after_reset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x9711dc34 ata_eh_qc_retry +EXPORT_SYMBOL_GPL drivers/ata/libata 0x98de957a ata_std_qc_defer +EXPORT_SYMBOL_GPL drivers/ata/libata 0x99061e99 ata_link_offline +EXPORT_SYMBOL_GPL drivers/ata/libata 0x991e0ffd ata_qc_complete +EXPORT_SYMBOL_GPL drivers/ata/libata 0x997ce746 ata_port_disable +EXPORT_SYMBOL_GPL drivers/ata/libata 0x99b54994 ata_std_error_handler +EXPORT_SYMBOL_GPL drivers/ata/libata 0xa1f6a4db dev_attr_em_message_type +EXPORT_SYMBOL_GPL drivers/ata/libata 0xa23b73fe ata_bmdma_stop +EXPORT_SYMBOL_GPL drivers/ata/libata 0xa5aa403e ata_host_activate +EXPORT_SYMBOL_GPL drivers/ata/libata 0xa7bd2b96 ata_pci_sff_init_one +EXPORT_SYMBOL_GPL drivers/ata/libata 0xab641028 ata_port_probe +EXPORT_SYMBOL_GPL drivers/ata/libata 0xac751708 ata_sff_check_status +EXPORT_SYMBOL_GPL drivers/ata/libata 0xacff8938 ata_timing_compute +EXPORT_SYMBOL_GPL drivers/ata/libata 0xb4bcbe38 ata_eh_qc_complete +EXPORT_SYMBOL_GPL drivers/ata/libata 0xb4eaefe9 ata_acpi_gtm_xfermask +EXPORT_SYMBOL_GPL drivers/ata/libata 0xb6aeb661 ata_id_c_string +EXPORT_SYMBOL_GPL drivers/ata/libata 0xb93b40af ata_sas_port_destroy +EXPORT_SYMBOL_GPL drivers/ata/libata 0xba45b767 ata_eh_freeze_port +EXPORT_SYMBOL_GPL drivers/ata/libata 0xbad6e1d9 ata_port_schedule_eh +EXPORT_SYMBOL_GPL drivers/ata/libata 0xbdc7441b ata_pci_remove_one +EXPORT_SYMBOL_GPL drivers/ata/libata 0xbe1887e4 ata_unpack_xfermask +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc06ff638 ata_cable_ignore +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc12abf59 ata_acpi_cbl_80wire +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc428068d sata_deb_timing_long +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc48b7ccf ata_mode_string +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc673e23e ata_scsi_change_queue_depth +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc7dd1c38 ata_sas_port_stop +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc8a3eff5 ata_sas_port_alloc +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcaab1ea9 sata_pmp_qc_defer_cmd_switch +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcba82ad8 ata_sff_freeze +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcc6c1f53 ata_ehi_push_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0xccc50bf7 ata_sff_qc_issue +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcccfb2fa sata_deb_timing_hotplug +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcfb08673 ata_sff_prereset +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcfd74d4c ata_std_bios_param +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd327d0c5 ata_bmdma_setup +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd65b9c99 ata_sff_qc_fill_rtf +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd6749301 sata_sff_hardreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd6c93ea8 ata_sff_pause +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd6fe8800 ata_sff_dev_select +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd84cd7f4 ata_timing_find_mode +EXPORT_SYMBOL_GPL drivers/ata/libata 0xde8e9e43 ata_noop_qc_prep +EXPORT_SYMBOL_GPL drivers/ata/libata 0xdec397fb sata_std_hardreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0xdf3022b2 ata_sff_interrupt +EXPORT_SYMBOL_GPL drivers/ata/libata 0xdf3c3b0e ata_sff_error_handler +EXPORT_SYMBOL_GPL drivers/ata/libata 0xe49ff3b0 ata_wait_register +EXPORT_SYMBOL_GPL drivers/ata/libata 0xe90c20ab ata_pci_bmdma_init +EXPORT_SYMBOL_GPL drivers/ata/libata 0xea418e0f atapi_cmd_type +EXPORT_SYMBOL_GPL drivers/ata/libata 0xea6c6ca2 ata_pci_device_resume +EXPORT_SYMBOL_GPL drivers/ata/libata 0xecfebf3b sata_scr_write_flush +EXPORT_SYMBOL_GPL drivers/ata/libata 0xee93726e ata_ehi_clear_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf3b2b521 dev_attr_link_power_management_policy +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf3d5cc13 ata_timing_merge +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf4b3c1ac ata_pio_need_iordy +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf7d0b479 ata_pci_sff_activate_host +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf85e5c94 ata_std_prereset +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf8f3a0fb ata_ratelimit +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf9ca3160 ata_id_xfermask +EXPORT_SYMBOL_GPL drivers/ata/libata 0xfb78f7b7 ata_sas_port_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0xfb95bef7 ata_sff_post_internal_cmd +EXPORT_SYMBOL_GPL drivers/ata/libata 0xfda093f8 ata_do_set_mode +EXPORT_SYMBOL_GPL drivers/ata/libata 0xfdac3214 ata_port_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0xfe9eb576 ata_host_detach +EXPORT_SYMBOL_GPL drivers/ata/libata 0xff1eecac ata_pci_sff_prepare_host +EXPORT_SYMBOL_GPL drivers/ata/pata_sis 0x304d063b sis_info133_for_sata +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x02ff9464 cfag12864b_isinited +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x0ecb2e5d cfag12864b_disable +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x305dc3c6 cfag12864b_isenabled +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x3389f926 cfag12864b_enable +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x9522a342 cfag12864b_getrate +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0xc48e9d95 cfag12864b_buffer +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0x14102f23 ks0108_displaystate +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0x48a70518 ks0108_writedata +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0x4f506333 ks0108_startline +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0x6edae968 ks0108_isinited +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0xbf4774db ks0108_writecontrol +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0xedde6df2 ks0108_page +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0xfee8ef7b ks0108_address +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x024ad1e1 tpm_gen_interrupt +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x1d10417d tpm_read +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x222ea86a tpm_show_caps +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x236f8e63 tpm_remove_hardware +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x2664a4cb tpm_show_pcrs +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x41dbca80 tpm_store_cancel +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x516c00a0 tpm_pm_suspend +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x540ebd33 tpm_calc_ordinal_duration +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x61a30e27 tpm_show_caps_1_2 +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x78850807 tpm_show_owned +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x7a9cb235 tpm_register_hardware +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x9ddd53f1 tpm_pm_resume +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x9e5f3947 tpm_open +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xa103f875 tpm_show_active +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xa1b0b89e tpm_show_pubek +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xad0dde48 tpm_release +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xbed53e39 tpm_show_enabled +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xcab9d8f4 tpm_get_timeouts +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xd25fa700 tpm_show_temp_deactivated +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xd9ce073d tpm_continue_selftest +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xff5e9eab tpm_write +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm_bios 0xbedb48ef tpm_bios_log_setup +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm_bios 0xfb33319c tpm_bios_log_teardown +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x01b354b4 cpufreq_frequency_table_target +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x2f47d8c7 cpufreq_frequency_get_table +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x3361319f cpufreq_frequency_table_cpuinfo +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x706b3a33 cpufreq_frequency_table_get_attr +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x7ae1ae8e cpufreq_frequency_table_put_attr +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x7bc780a5 cpufreq_frequency_table_verify +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0xa861f3b5 cpufreq_freq_attr_scaling_available_freqs +EXPORT_SYMBOL_GPL drivers/dca/dca 0x05b3551e unregister_dca_provider +EXPORT_SYMBOL_GPL drivers/dca/dca 0x2cd03ed5 register_dca_provider +EXPORT_SYMBOL_GPL drivers/dca/dca 0x2e471f01 dca_register_notify +EXPORT_SYMBOL_GPL drivers/dca/dca 0x31a2c8df dca_get_tag +EXPORT_SYMBOL_GPL drivers/dca/dca 0x4324d628 dca3_get_tag +EXPORT_SYMBOL_GPL drivers/dca/dca 0x48ac0971 dca_add_requester +EXPORT_SYMBOL_GPL drivers/dca/dca 0x652621dc dca_remove_requester +EXPORT_SYMBOL_GPL drivers/dca/dca 0x8006c614 dca_unregister_notify +EXPORT_SYMBOL_GPL drivers/dca/dca 0xc58266af alloc_dca_provider +EXPORT_SYMBOL_GPL drivers/dca/dca 0xda71046d free_dca_provider +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x0211c6c4 edac_device_handle_ce +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x029073b9 edac_mc_del_mc +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x04ac8ef6 edac_mc_handle_ce +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x0b717549 edac_pci_add_device +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x20855591 edac_pci_reset_delay_period +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x247407cd edac_mc_handle_ue_no_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x2700b0b5 edac_device_del_device +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x2ed57370 edac_mc_find_csrow_by_page +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x4012f69c edac_mc_add_mc +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x4169a4a8 edac_pci_del_device +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x6aaff303 edac_pci_handle_pe +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x77e2a1ee edac_pci_free_ctl_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x8e6064b6 edac_device_free_ctl_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xa1f3248e edac_device_add_device +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xa225e666 edac_pci_release_generic_ctl +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xa35a8855 edac_mc_alloc +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xa96e048d edac_mc_handle_ue +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xbfd242cb edac_pci_create_generic_ctl +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xc72e08bf edac_device_handle_ue +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xc873c147 edac_mc_handle_ce_no_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xcd62b43a edac_mc_free +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xd7165fb2 edac_pci_handle_npe +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xe40115ea edac_device_alloc_ctl_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xe651ceba edac_pci_alloc_ctl_info +EXPORT_SYMBOL_GPL drivers/hid/hid 0x2b368f3c hidinput_connect +EXPORT_SYMBOL_GPL drivers/hid/hid 0x2f05ae23 hid_free_device +EXPORT_SYMBOL_GPL drivers/hid/hid 0x33486e06 hidinput_report_event +EXPORT_SYMBOL_GPL drivers/hid/hid 0x37acefd2 hidinput_disconnect +EXPORT_SYMBOL_GPL drivers/hid/hid 0x3baf0797 hid_output_report +EXPORT_SYMBOL_GPL drivers/hid/hid 0x4ed56b91 hidraw_report_event +EXPORT_SYMBOL_GPL drivers/hid/hid 0x556844c8 hidraw_disconnect +EXPORT_SYMBOL_GPL drivers/hid/hid 0x63c366d8 hid_input_report +EXPORT_SYMBOL_GPL drivers/hid/hid 0x98d1847c hidraw_connect +EXPORT_SYMBOL_GPL drivers/hid/hid 0xc29c9390 hid_set_field +EXPORT_SYMBOL_GPL drivers/hid/hid 0xe9b1cb71 hid_parse_report +EXPORT_SYMBOL_GPL drivers/hid/hid 0xfbdf75db hidinput_find_field +EXPORT_SYMBOL_GPL drivers/hid/usbhid/usbhid 0x01fd453e usbhid_lookup_quirk +EXPORT_SYMBOL_GPL drivers/hid/usbhid/usbhid 0x4e57751b hiddev_hid_event +EXPORT_SYMBOL_GPL drivers/i2c/busses/i2c-nforce2 0x68e4534f nforce2_smbus +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0x3a8ec298 i2c_new_device +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0x3fc26e45 i2c_unregister_device +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0x55cbe224 i2c_new_probed_device +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0x6bcc220c i2c_add_numbered_adapter +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0x9f55c9ab i2c_new_dummy +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0xa55b9ad7 i2c_bus_type +EXPORT_SYMBOL_GPL drivers/ieee1394/ieee1394 0x08829f7c hpsb_config_rom_ip1394_add +EXPORT_SYMBOL_GPL drivers/ieee1394/ieee1394 0x79e9f1b3 hpsb_config_rom_ip1394_remove +EXPORT_SYMBOL_GPL drivers/ieee1394/ieee1394 0xec8d18cf hpsb_disable_irm +EXPORT_SYMBOL_GPL drivers/infiniband/hw/ipath/ib_ipath 0x1514b2b2 ipath_debug +EXPORT_SYMBOL_GPL drivers/input/ff-memless 0xc609debe input_ff_create_memless +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x1368b328 wm97xx_reg_write +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x1b2eca97 wm97xx_config_gpio +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x233d4fbb wm97xx_get_gpio +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x2863c918 wm97xx_register_mach_ops +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x2d77d280 wm9713_codec +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x3d8e92d4 wm97xx_set_suspend_mode +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x73bd2ad7 wm97xx_reg_read +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xc73a95e4 wm97xx_unregister_mach_ops +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xcad15329 wm97xx_read_aux_adc +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xe1ddd21e wm9712_codec +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xec16e71d wm97xx_set_gpio +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xfc63cf44 wm9705_codec +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x205d2222 gigaset_initcs +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x2c0979ce gigaset_dbg_buffer +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x32522fb6 gigaset_stop +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x454aa44f gigaset_debuglevel +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x491e3ff5 gigaset_m10x_send_skb +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x4cc52616 gigaset_freedriver +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x73785ae7 gigaset_handle_modem_response +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x7dabdf52 gigaset_initdriver +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x958ceda9 gigaset_fill_inbuf +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x9a558944 gigaset_blockdriver +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x9ab916c7 gigaset_m10x_input +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x9b1b1ff4 gigaset_start +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0xa6ff5bf9 gigaset_skb_sent +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0xc0f41444 gigaset_if_receive +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0xdf14a9e7 gigaset_freecs +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0xe1813396 gigaset_add_event +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0xfc8e8650 gigaset_shutdown +EXPORT_SYMBOL_GPL drivers/leds/led-class 0x3dbc6938 led_classdev_unregister +EXPORT_SYMBOL_GPL drivers/leds/led-class 0x606f5703 led_classdev_resume +EXPORT_SYMBOL_GPL drivers/leds/led-class 0x748348da led_classdev_suspend +EXPORT_SYMBOL_GPL drivers/leds/led-class 0x96910d35 led_classdev_register +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0x3c6370f3 dm_send_uevents +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0x4f7bb9d8 dm_path_uevent +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0x55694df2 dm_set_device_limits +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0xb668dbbc dm_put +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0xb692a533 dm_device_name +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0xdb0d3221 dm_disk +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0xfca7d597 dm_noflush_suspending +EXPORT_SYMBOL_GPL drivers/md/dm-multipath 0xcf1c0ddf dm_unregister_path_selector +EXPORT_SYMBOL_GPL drivers/md/dm-multipath 0xfa6eec39 dm_register_path_selector +EXPORT_SYMBOL_GPL drivers/md/md-mod 0x87a8c3e7 sync_page_io +EXPORT_SYMBOL_GPL drivers/md/md-mod 0x9cf27e45 md_allow_write +EXPORT_SYMBOL_GPL drivers/md/md-mod 0xda0a124e md_do_sync +EXPORT_SYMBOL_GPL drivers/md/md-mod 0xf5686100 md_new_event +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x04662e0f ir_codes_fusionhdtv_mce +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x07e92917 ir_codes_avermedia_a16d +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x083661f9 ir_codes_avertv_303 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x088631b9 ir_codes_behold +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x1cb148f5 ir_extract_bits +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x2456e513 ir_decode_pulsedistance +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x24e377fe ir_input_init +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x2a4852cc ir_codes_dntv_live_dvb_t +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x2af1a608 ir_codes_proteus_2309 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x3811daea ir_codes_manli +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x43c89ef4 ir_decode_biphase +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x45b08f68 ir_codes_pinnacle_grey +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x4740e7a3 ir_codes_empty +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x4ea698a2 ir_codes_purpletv +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x55338dda ir_codes_pixelview_new +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x589cad50 ir_codes_apac_viewcomp +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x5db13554 ir_codes_encore_enltv +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6606596a ir_rc5_timer_keyup +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6adc476d ir_codes_powercolor_real_angel +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6aefdbea ir_codes_npgtech +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6b87c69d ir_codes_iodata_bctv7e +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6d6511e7 ir_dump_samples +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6e2a1870 ir_codes_adstech_dvb_t_pci +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x7277973d ir_codes_pctv_sedna +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x75e89cc3 ir_codes_flydvb +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x772a30a2 ir_codes_nebula +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x85d37490 ir_codes_dntv_live_dvbt_pro +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x89cc1189 ir_codes_winfast +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x902a3cd2 ir_codes_hauppauge_new +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x933d0bb3 ir_codes_msi_tvanywhere +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x9451e232 ir_codes_behold_columbus +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x96470cab ir_codes_cinergy +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xaf13fcc6 ir_input_keydown +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xb1f4eb35 ir_codes_avermedia_dvbt +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xb6cd4666 ir_codes_eztv +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xbb08d146 ir_codes_msi_tvanywhere_plus +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xbdce6594 ir_codes_tt_1500 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xc1fea0c1 ir_codes_pv951 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xc42bd037 ir_codes_budget_ci_old +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xc6c5a7a1 ir_codes_em_terratec +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xc78b14a1 ir_input_nokey +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xd1e0258a ir_codes_flyvideo +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xd55e6891 ir_codes_gotview7135 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xd9c7f010 ir_codes_rc5_tv +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xdaa041ad ir_codes_cinergy_1400 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xdfcf23df ir_codes_norwood +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xee2f5e0e ir_codes_pinnacle_pctv_hd +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xf07533a1 ir_codes_videomate_tv_pvr +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xf0fc9374 ir_codes_avermedia +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xf2b421aa ir_codes_genius_tvgo_a11mce +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xf4f7a4d6 ir_rc5_timer_end +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xfa177653 ir_codes_pixelview +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xfb981300 ir_codes_pinnacle_color +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xfc54a5cd ir_codes_asus_pc39 +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x068e1889 saa7146_vmalloc_build_pgtable +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x2faf04d1 saa7146_setgpio +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x4fadb1a7 saa7146_pgtable_build_single +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x632146c4 saa7146_unregister_extension +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x63ceb9bc saa7146_wait_for_debi_done +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x6fe17b76 saa7146_register_extension +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xb06a5ed9 saa7146_vfree_destroy_pgtable +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xb9c9c1b8 saa7146_pgtable_alloc +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xc492699f saa7146_pgtable_free +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xc98faf20 saa7146_devices_lock +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xcf683cf2 saa7146_devices +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xe3cd9b5c saa7146_debug +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xeee0e0a8 saa7146_i2c_adapter_prepare +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0x17f322ae saa7146_stop_preview +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0x19e196af saa7146_vv_release +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0x6ef11cf2 saa7146_start_preview +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0xad80744a saa7146_unregister_device +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0xebe801c4 saa7146_register_device +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0xedc5af33 saa7146_set_hps_source_and_sync +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0xf6510ecc saa7146_vv_init +EXPORT_SYMBOL_GPL drivers/media/common/tuners/mt20xx 0xe3dd8aa9 microtune_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/mxl5007t 0xe6481d8d mxl5007t_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda18271 0xaae45236 tda18271_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda827x 0x6b3c58f1 tda827x_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda8290 0x30770c39 tda829x_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda8290 0x789dde6b tda829x_probe +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda9887 0x05e3a63f tda9887_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tea5761 0x5b4cae5a tea5761_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tea5761 0xd69cd675 tea5761_autodetection +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tea5767 0x1168221c tea5767_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tea5767 0x5f216f77 tea5767_autodetection +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tuner-simple 0x37b331e5 simple_tuner_attach +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x0d53fad0 ttpci_budget_set_video_port +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x25582062 ttpci_budget_deinit +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x400e1c98 ttpci_budget_irq10_handler +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x618745aa ttpci_budget_init_hooks +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x74f51b31 ttpci_budget_debiwrite +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x7948c222 budget_debug +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x890031ac ttpci_budget_debiread +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0xa9fad84e ttpci_budget_init +EXPORT_SYMBOL_GPL drivers/media/video/compat_ioctl32 0xe316f053 v4l_compat_ioctl32 +EXPORT_SYMBOL_GPL drivers/media/video/cx88/cx88xx 0xf951856b cx88_setup_xc3028 +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0x098e7072 em28xx_audio_analog_set +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0x8295897f em28xx_uninit_isoc +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0xd22c24eb em28xx_tuner_callback +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0xd3e55506 em28xx_init_isoc +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0xd44fe1bf em28xx_set_mode +EXPORT_SYMBOL_GPL drivers/media/video/saa7134/saa7134 0x012f6f7d saa7134_g_ctrl_internal +EXPORT_SYMBOL_GPL drivers/media/video/saa7134/saa7134 0x52ba89c3 saa7134_queryctrl +EXPORT_SYMBOL_GPL drivers/media/video/saa7134/saa7134 0x5cd16c3c saa7134_ts_qops +EXPORT_SYMBOL_GPL drivers/media/video/saa7134/saa7134 0xde2faa55 saa7134_s_ctrl_internal +EXPORT_SYMBOL_GPL drivers/media/video/v4l2-int-device 0x297e992a v4l2_int_device_unregister +EXPORT_SYMBOL_GPL drivers/media/video/v4l2-int-device 0xd14620db v4l2_int_device_register +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x0147f284 videobuf_streamoff +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x01d93f07 videobuf_streamon +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x048943e3 videobuf_dqbuf +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x0a36a8eb videobuf_waiton +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x0ec912c4 videobuf_mmap_setup +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x47a6070d videobuf_querybuf +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x48bdf8f4 videobuf_read_stop +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x4d0d87ca videobuf_next_field +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x6394f1c4 videobuf_read_stream +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x6dac653f videobuf_poll_stream +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x757351a9 videobuf_queue_core_init +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x78b1bfbf videobuf_cgmbuf +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x7acfeb44 videobuf_iolock +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x7e981702 videobuf_reqbufs +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x82d92a95 videobuf_stop +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x833ef841 videobuf_queue_cancel +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x8870f8fd videobuf_read_one +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xb480814e videobuf_queue_to_vmalloc +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xb4ec507a videobuf_mmap_free +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xc25559fd videobuf_qbuf +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xc439d02d videobuf_queue_is_busy +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xce49e3be videobuf_alloc +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xd0f64433 __videobuf_mmap_setup +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xee15411e videobuf_mmap_mapper +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xf6661fe2 videobuf_read_start +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-contig 0x382a226c videobuf_dma_contig_free +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-contig 0x9f72cb47 videobuf_queue_dma_contig_init +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-contig 0xd85c1198 videobuf_to_dma_contig +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x0346f558 videobuf_sg_dma_unmap +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x0e097414 videobuf_queue_sg_init +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x1788d15b videobuf_dma_sync +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x25776fca videobuf_dma_unmap +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x48dbf1aa videobuf_dma_map +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x585f1480 videobuf_sg_dma_map +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x669b0dc6 videobuf_to_dma +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x6f09d8e2 videobuf_dma_init +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x8ab4c971 videobuf_dma_free +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x8edb5815 videobuf_dma_init_kernel +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x933dfb43 videobuf_vmalloc_to_sg +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0xa38faed2 videobuf_sg_alloc +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0xc887f37e videobuf_dma_init_overlay +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0xf782dcfa videobuf_dma_init_user +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-vmalloc 0x619868bd videobuf_vmalloc_free +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-vmalloc 0xcb49bf72 videobuf_queue_vmalloc_init +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-vmalloc 0xe4b983da videobuf_to_vmalloc +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0x18d2ca57 sm501_unit_power +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0x7248c01b sm501_set_clock +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0xbb6de885 sm501_find_clock +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0xe02bdb6b sm501_modify_reg +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0xe65eab65 sm501_misc_control +EXPORT_SYMBOL_GPL drivers/misc/eeprom_93cx6 0x2df115d4 eeprom_93cx6_multiread +EXPORT_SYMBOL_GPL drivers/misc/eeprom_93cx6 0x63d14d2f eeprom_93cx6_read +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0x58a17c64 enclosure_remove_device +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0x6c13472f enclosure_add_device +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0x958b1da4 enclosure_register +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0x9ab6f7fd enclosure_component_register +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0xc1339762 enclosure_find +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0xd359f806 enclosure_unregister +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0xf342e30f enclosure_for_each_device +EXPORT_SYMBOL_GPL drivers/misc/sgi-gru/gru 0x2293c8e0 gru_get_next_message +EXPORT_SYMBOL_GPL drivers/misc/sgi-gru/gru 0x5927a880 gru_send_message_gpa +EXPORT_SYMBOL_GPL drivers/misc/sgi-gru/gru 0x7e83f3fc gru_free_message +EXPORT_SYMBOL_GPL drivers/misc/sgi-gru/gru 0x81b3b8e3 gru_create_message_queue +EXPORT_SYMBOL_GPL drivers/misc/sgi-gru/gru 0x9c7283a1 gru_copy_gpa +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0x345c9217 xpc_disconnect +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0x39046c7a xpc_clear_interface +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0x43a01eea xpc_registrations +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0x6285dfe8 xp_cpu_to_nasid +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0x64ba5017 xp_pa +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0x76e36d39 xp_region_size +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0x9823adb0 xpc_set_interface +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0x9acd8cf8 xpc_interface +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0xba3694f3 xp_remote_memcpy +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0xead4f7fe xp_max_npartitions +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0xf3b47f67 xp_partition_id +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0xfe709b6c xpc_connect +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x087544d1 sdio_enable_func +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x2081c271 sdio_writeb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x376aaa75 sdio_align_size +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x414514e7 sdio_f0_writeb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x4415d799 sdio_disable_func +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x45644fe8 sdio_readw +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x58300c38 sdio_readl +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x6e0d3070 sdio_memcpy_toio +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x6e88a923 sdio_writel +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x6fd87903 sdio_unregister_driver +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x70d16bd7 sdio_release_irq +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x7a3e67bb sdio_memcpy_fromio +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x823d9e9a sdio_f0_readb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x8960d10e sdio_release_host +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x8a227a24 sdio_register_driver +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x9b619be5 sdio_writesb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xa610d65e sdio_readsb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xa9cc833a sdio_claim_host +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xc714568c sdio_writew +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xcbc04550 sdio_claim_irq +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xea785e12 sdio_readb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xff74c9e5 sdio_set_block_size +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0x0b1f39ae sdhci_suspend_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0x51b669e0 sdhci_resume_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0x5ef184df sdhci_add_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0x6a739170 sdhci_free_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0xa2fd7a61 sdhci_remove_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0xabd4a035 sdhci_alloc_host +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0001 0x57390696 cfi_cmdset_0001 +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0001 0xa574bdcb cfi_cmdset_0200 +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0001 0xce7d7f1a cfi_cmdset_0003 +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0002 0x82df43dc cfi_cmdset_0002 +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0020 0xff0cb122 cfi_cmdset_0020 +EXPORT_SYMBOL_GPL drivers/mtd/devices/doc2000 0x68a62f65 DoC2k_init +EXPORT_SYMBOL_GPL drivers/mtd/devices/doc2001 0x92b52cc0 DoCMil_init +EXPORT_SYMBOL_GPL drivers/mtd/devices/doc2001plus 0xf4b38d40 DoCMilPlus_init +EXPORT_SYMBOL_GPL drivers/mtd/devices/docecc 0x45937659 doc_decode_ecc +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x06e946cf put_mtd_device +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x305bbcd3 mtd_table +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x49cc76d0 deregister_mtd_parser +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x4d55e2cb get_mtd_device_nm +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x5aa5d30b unregister_mtd_user +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x5dd108f7 del_mtd_device +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x97b3d01a register_mtd_user +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x9a150064 parse_mtd_partitions +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xaac99e1c mtd_erase_callback +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xb4981eda default_mtd_writev +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xc23c70d9 register_mtd_parser +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xcd69cdb4 add_mtd_device +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xecbcf900 kill_mtd_super +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xee3d2e5a get_mtd_device +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xeff64be1 mtd_table_mutex +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xf467e47a get_sb_mtd +EXPORT_SYMBOL_GPL drivers/mtd/mtd_blkdevs 0x9ae8761b del_mtd_blktrans_dev +EXPORT_SYMBOL_GPL drivers/mtd/mtd_blkdevs 0xa317ae44 deregister_mtd_blktrans +EXPORT_SYMBOL_GPL drivers/mtd/mtd_blkdevs 0xb8f3d62d add_mtd_blktrans_dev +EXPORT_SYMBOL_GPL drivers/mtd/mtd_blkdevs 0xd6f37562 register_mtd_blktrans +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0x5ec3a233 nand_wait_ready +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0x9f9b582a nand_scan +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0xa7bbffe0 nand_scan_tail +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0xae791bab nand_scan_ident +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0xbcfce9c5 nand_release +EXPORT_SYMBOL_GPL drivers/mtd/onenand/onenand 0x0323ef35 onenand_release +EXPORT_SYMBOL_GPL drivers/mtd/onenand/onenand 0x07b79c74 onenand_scan +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x01a2b2fd ubi_open_volume +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x3b336589 ubi_leb_write +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x42801d20 ubi_sync +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x4f2bdf92 ubi_get_volume_info +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x5885ca05 ubi_close_volume +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x73296454 ubi_is_mapped +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x7f3f14d3 ubi_leb_erase +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x8c9549f8 ubi_leb_map +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xbc505df4 ubi_get_device_info +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xc18853b5 ubi_leb_change +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xd5a972db ubi_leb_read +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xd858699a ubi_leb_unmap +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xfe96383e ubi_open_volume_nm +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x010d8ce4 mlx4_cq_modify +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x0b537f8b mlx4_CLOSE_PORT +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x181a0565 mlx4_free_hwq_res +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x1c6fc717 mlx4_mtt_init +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x1d446d71 mlx4_qp_modify +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x23e9bb54 mlx4_fmr_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x2a45b47f mlx4_srq_arm +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x2be82087 mlx4_srq_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x378c5be5 mlx4_cq_resize +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x382df159 mlx4_buf_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x3ff35ec7 mlx4_srq_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x4b608888 mlx4_map_phys_fmr +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x4ce0b3d7 mlx4_cq_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x4f374ab5 mlx4_srq_query +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x51905ba0 mlx4_SYNC_TPT +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x51cad764 mlx4_fmr_unmap +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x53b279de mlx4_buf_write_mtt +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x5539058a mlx4_alloc_hwq_res +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x5a35efa4 mlx4_pd_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x629799b1 mlx4_mr_enable +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x65675603 mlx4_fmr_enable +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x68817f39 mlx4_qp_query +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x688e38e9 mlx4_uar_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x73c823aa mlx4_mtt_addr +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x7892ca3b mlx4_multicast_detach +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x8265350f mlx4_pd_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x82e97ece mlx4_qp_remove +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x8c32de27 mlx4_write_mtt +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xa6fc5e1f __mlx4_cmd +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xb327fbc8 mlx4_db_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xb59c6d9b mlx4_buf_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xb7663a4e mlx4_register_interface +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xbaaaff31 mlx4_mtt_cleanup +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xbbc28468 mlx4_fmr_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xbfcd1b47 mlx4_uar_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xbfd56320 mlx4_free_cmd_mailbox +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xc048f4ab mlx4_cq_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xc228bc16 mlx4_qp_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xc29809cf mlx4_alloc_cmd_mailbox +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xc94cf72b mlx4_db_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xd0709200 mlx4_INIT_PORT +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xdb8ebd86 mlx4_mr_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xde3317b1 mlx4_qp_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xe30641f3 mlx4_multicast_attach +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xea6077c6 mlx4_qp_to_ready +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xed747120 mlx4_unregister_interface +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xf0bb0ffb mlx4_mr_alloc +EXPORT_SYMBOL_GPL drivers/net/usb/cdc_ether 0xb7f8fe0a usbnet_generic_cdc_bind +EXPORT_SYMBOL_GPL drivers/net/usb/cdc_ether 0xc7d58706 usbnet_cdc_unbind +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0x67e35cb7 rndis_status +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0x740827c3 rndis_tx_fixup +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0x7645e1e5 generic_rndis_bind +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0xeedd3fc9 rndis_rx_fixup +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0xf72a6883 rndis_unbind +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0xff9d13d1 rndis_command +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x211c2589 usbnet_set_msglevel +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x3d9152e3 usbnet_get_link +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x423dbf9f usbnet_unlink_rx_urbs +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x4d9d426f usbnet_get_endpoints +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x59e07c0d usbnet_suspend +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x5a05000f usbnet_disconnect +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x62056718 usbnet_get_drvinfo +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x7023cfa9 usbnet_get_settings +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x7478ffad usbnet_get_msglevel +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x96037c38 usbnet_skb_return +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xb1f07be1 usbnet_resume +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xbed2856d usbnet_nway_reset +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xd53e25c7 usbnet_defer_kevent +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xdd224854 usbnet_set_settings +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xf63e1931 usbnet_probe +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x0602cac1 lbs_suspend +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x0be023ae lbs_stop_card +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x0c5e40b5 lbs_cmd_802_11_rate_adapt_rateset +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x26e5dbfe lbs_host_sleep_cfg +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x308d94ad lbs_cmd_copyback +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x3e29ed5a lbs_process_rxed_packet +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x6eb01a31 lbs_queue_event +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x8c064947 lbs_start_card +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x930757d9 lbs_resume +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xb226c912 lbs_remove_card +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xb4b18159 lbs_send_tx_feedback +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xc22b6817 lbs_add_card +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xdce69e6a lbs_notify_command_response +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xf64277de lbs_debug +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xf82859bd __lbs_cmd +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xf9d8db24 lbs_host_to_card_done +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0x00690516 p54_parse_firmware +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0x61ecb650 p54_free_common +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0xa1d75bf5 p54_parse_eeprom +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0xaa748adb p54_fill_eeprom_readback +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0xc9d7c699 p54_init_common +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0xe4a2f9a1 p54_rx +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x06b59e86 rt2x00mac_config_interface +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x1b2801ca rt2x00mac_stop +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x2c9b4cd4 rt2x00mac_remove_interface +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x2e3997c4 rt2x00lib_probe_dev +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x4883e94c rt2x00queue_get_entry +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x4bb9fb2e rt2x00lib_txdone +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x6dcceb49 rt2x00queue_map_txskb +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x7e62024b rt2x00queue_get_queue +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x84073a85 rt2x00mac_configure_filter +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x856a1fe7 rt2x00mac_bss_info_changed +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x87c7abe0 rt2x00mac_conf_tx +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x938b4d39 rt2x00mac_get_tx_stats +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x95025ccc rt2x00lib_remove_dev +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x9ef624c5 rt2x00lib_beacondone +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xa2ebdded rt2x00mac_add_interface +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xa3254a77 rt2x00mac_config +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xb5fbd062 rt2x00mac_get_stats +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xbea33e90 rt2x00mac_tx +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xd1891627 rt2x00lib_resume +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xd1a465e1 rt2x00mac_start +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xdcb88b1f rt2x00lib_rxdone +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xe922f4d8 rt2x00lib_suspend +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0x6abb08f2 rt2x00pci_resume +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0x7ce519f8 rt2x00pci_uninitialize +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0xacae4409 rt2x00pci_suspend +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0xb168c3a4 rt2x00pci_rxdone +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0xb630272c rt2x00pci_write_tx_data +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0xd44a2ac8 rt2x00pci_remove +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0xf21fe1a4 rt2x00pci_initialize +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0xf3863960 rt2x00pci_probe +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x0867b6e4 rt2x00usb_vendor_request_buff +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x0f7cac3e rt2x00usb_vendor_req_buff_lock +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x168bea10 rt2x00usb_resume +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x2ed8a663 rt2x00usb_suspend +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x4354593c rt2x00usb_probe +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x4ca1ca20 rt2x00usb_initialize +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x54d52da6 rt2x00usb_vendor_request +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x5e52134f rt2x00usb_init_rxentry +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x81117fe1 rt2x00usb_kick_tx_queue +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x8fb60349 rt2x00usb_uninitialize +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x9e45c57c rt2x00usb_vendor_request_large_buff +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0xa834c04a rt2x00usb_disable_radio +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0xb68cb2fc rt2x00usb_write_tx_data +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0xc337fe6d rt2x00usb_disconnect +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0xf904f32d rt2x00usb_init_txentry +EXPORT_SYMBOL_GPL drivers/pci/hotplug/acpiphp 0x999ed3b7 acpiphp_register_attention +EXPORT_SYMBOL_GPL drivers/pci/hotplug/acpiphp 0xda0d631d acpiphp_unregister_attention +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x1ad3b491 acpi_root_bridge +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x6a8441be cpci_hp_start +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x7e21a060 cpci_hp_unregister_bus +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x7e68536d cpci_hp_register_controller +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x7f2100fc cpci_hp_register_bus +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x94ef4d05 cpci_hp_stop +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0xa291d1fd pci_hp_register +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0xb97116e5 cpci_hp_unregister_controller +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0xcd7791b0 pci_hp_deregister +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0xd1fb62f2 pci_hp_change_slot_info +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0xf7e825f6 acpi_get_hp_params_from_firmware +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x001b18a4 scsi_register_device_handler +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x041d97ad scsi_dh_detach +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x09552a8a scsi_unregister_device_handler +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x593a36c2 scsi_dh_handler_exist +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x7c4c5379 scsi_dh_attach +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x99f7a5d2 scsi_dh_activate +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x0233f349 iscsi_pool_init +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x05241ec2 iscsi_prep_unsolicit_data_pdu +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x07c121c7 iscsi_conn_teardown +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x1540b5ba iscsi_suspend_tx +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x273c202d __iscsi_complete_pdu +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x2929000e iscsi_change_queue_depth +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x30c35bca iscsi_conn_stop +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x319775bb iscsi_conn_setup +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x41ba1d14 iscsi_pool_free +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x4381d090 iscsi_conn_get_param +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x451fe9b8 iscsi_set_param +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x48a82dfd iscsi_requeue_task +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x5253a7de iscsi_session_recovery_timedout +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x54d9c43f iscsi_itt_to_ctask +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x59a97db7 iscsi_eh_host_reset +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x66cb48b2 iscsi_conn_start +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x6c105266 iscsi_complete_pdu +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x804425a3 iscsi_put_task +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x817b1759 iscsi_session_setup +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x893d14d4 iscsi_host_set_param +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x8c38a498 iscsi_queuecommand +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x8ec64c9d iscsi_verify_itt +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x8f12f0c1 iscsi_conn_bind +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x9a7d19eb iscsi_host_remove +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x9b587b20 iscsi_host_free +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xa274dd8c iscsi_eh_abort +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xa766ed6f __iscsi_get_task +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xbbeaba73 iscsi_eh_device_reset +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xcbd676b2 iscsi_update_cmdsn +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xcd3e4a8e iscsi_conn_failure +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xdf30c3c2 iscsi_host_alloc +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xe54aca86 iscsi_host_get_param +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xeabdc1e0 iscsi_session_get_param +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xec6c6806 iscsi_session_teardown +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xede66f4b iscsi_host_add +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xf8f1595d iscsi_conn_send_pdu +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x0cc78f4d sas_queuecommand +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x0d072f2d sas_ssp_task_response +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x10232a42 sas_domain_attach_transport +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x1e23c474 sas_slave_destroy +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x222c0f70 sas_change_queue_type +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x2736fc1e sas_task_abort +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x27a57fb3 sas_register_ha +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x3c43b881 sas_domain_release_transport +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x3fc9e71d sas_phy_reset +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x4cb284d9 sas_find_local_phy +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x597dcd69 __sas_task_abort +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x60ccefd5 sas_bios_param +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x64b445e2 sas_phy_enable +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x725daf1b sas_slave_configure +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x74ccd3b2 sas_unregister_ha +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x8da178a8 sas_target_alloc +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x9649f0e8 sas_request_addr +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x9a7908e2 sas_ioctl +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xb8dac1e7 sas_eh_device_reset_handler +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xce2dc861 sas_change_queue_depth +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xd43b03cd sas_slave_alloc +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xea0a613a sas_eh_bus_reset_handler +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xef8d2ad7 sas_target_destroy +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x06609f3a srp_iu_put +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x10ddf03e srp_target_free +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x1b2800c1 srp_transfer_data +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x2bff6332 srp_cmd_queue +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x5d8e8e07 srp_iu_get +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x8a91fd35 srp_target_alloc +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x08cb47fd sdev_evt_send +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x26c90ea4 scsi_eh_get_sense +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x35d8c94a sdev_evt_alloc +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x4a3a42e1 scsi_target_block +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x4fa8ece7 scsi_mode_select +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x56116358 scsi_nl_sock +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x7653d91c scsi_eh_ready_devs +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x7e275ea8 scsi_complete_async_scans +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x9778bcd4 scsi_schedule_eh +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x9c871012 scsi_target_unblock +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x9faf413a __scsi_get_command +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xca85a3b6 scsi_internal_device_block +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xcc67b080 scsi_queue_work +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xd30001e5 scsi_flush_work +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xd7b43cf3 scsi_execute_async +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xd9982753 sdev_evt_send_simple +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xda723572 scsi_bus_type +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xe0697a22 scsi_internal_device_unblock +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x05472d63 scsi_tgt_it_nexus_destroy +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x1db6d800 scsi_host_put_command +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x3630babd scsi_tgt_cmd_to_host +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x5715dde4 scsi_tgt_tsk_mgmt_request +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0xaa32ff1c scsi_tgt_queue_command +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0xe915977b scsi_tgt_alloc_queue +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0xf43be2f1 scsi_host_get_command +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0xf681e4b3 scsi_tgt_free_queue +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0xfa7386ea scsi_tgt_it_nexus_create +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x093d7688 iscsi_destroy_conn +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x1614df41 iscsi_unblock_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x16b462f0 iscsi_create_conn +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x1746b105 iscsi_session_chkready +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x1c150793 iscsi_recv_pdu +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x2bd25c9c iscsi_host_for_each_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x35eede99 iscsi_block_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x3be8ce1c iscsi_conn_error +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x5654144d iscsi_destroy_endpoint +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x5862fb33 iscsi_free_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x5ef140e2 iscsi_add_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x6404128c iscsi_lookup_endpoint +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x6710016b iscsi_session_event +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x9c467c74 iscsi_unregister_transport +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xa700d665 iscsi_create_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xb993b082 iscsi_register_transport +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xba210d2a iscsi_scan_finished +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xc7779819 iscsi_destroy_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xce0b3ac5 iscsi_alloc_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xe41ce3c2 iscsi_create_endpoint +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xfe84db82 iscsi_remove_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_spi 0x0ef06974 spi_populate_ppr_msg +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_spi 0xa0c71dac spi_populate_sync_msg +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_spi 0xcffa2aff spi_populate_width_msg +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0x18af8164 srp_rport_del +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0x26c894ef srp_remove_host +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0x3d4c9026 srp_attach_transport +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0x60902ef3 srp_rport_add +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0xa2f1c184 srp_release_transport +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0x6f3c57e1 spi_bitbang_cleanup +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0x89f022c2 spi_bitbang_stop +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0x9fce090a spi_bitbang_start +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0xa7370f75 spi_bitbang_setup +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0xc3f248d3 spi_bitbang_setup_transfer +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0xe97b9576 spi_bitbang_transfer +EXPORT_SYMBOL_GPL drivers/uio/uio 0x4bbc499c __uio_register_device +EXPORT_SYMBOL_GPL drivers/uio/uio 0xa3ebfd18 uio_event_notify +EXPORT_SYMBOL_GPL drivers/uio/uio 0xae627116 uio_unregister_device +EXPORT_SYMBOL_GPL drivers/usb/atm/usbatm 0xa7940c6c usbatm_usb_probe +EXPORT_SYMBOL_GPL drivers/usb/atm/usbatm 0xb1b3e2dd usbatm_usb_disconnect +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x04b31971 usb_control_msg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x0603e884 usb_get_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x089ccbdf usb_driver_claim_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x12c69986 usb_hcd_poll_rh_status +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x1341f38e usb_autopm_set_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x19a304ba usb_disabled +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x22de98fe usb_sg_wait +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x23b19a43 usb_driver_release_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x249d0af1 usb_unlink_anchored_urbs +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x25fd518f usb_put_dev +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x27268665 usb_kill_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x2d1f9df1 usb_clear_halt +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x32e1339c usb_autopm_get_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x3be89d3c usb_register_notify +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x41fbf3d6 usb_hcd_platform_shutdown +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x492ff4af usb_add_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x495d102b usb_match_id +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x49e5cf8a usb_driver_set_configuration +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x4ecf7c7f usb_hcd_link_urb_to_ep +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x54f9109d usb_reset_configuration +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x58641d9e usb_sg_init +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x589bfc75 usb_hcd_pci_suspend +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x5b14da51 usb_register_dev +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x5b740637 usb_register_driver +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x5cb54918 usb_buffer_map_sg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x62288a57 usb_deregister +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x632f5ca0 usb_root_hub_lost_power +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x654683ff usb_get_status +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x6592183e usb_alloc_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x6d23dcdd usb_hub_tt_clear_buffer +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x6dce94bf usb_bus_list_lock +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x6e8f64c5 usb_create_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x71f99dc2 usb_altnum_to_altsetting +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x7395578c usb_buffer_alloc +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x7628f57e usb_get_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x7668d003 usb_hcd_pci_shutdown +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x7e64181d usb_calc_bus_time +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x81a9edf9 usb_reset_device +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x862774b6 usb_hcd_pci_resume +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x8cebbc73 usb_bulk_msg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x92e32f66 usb_free_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x9924c496 __usb_get_extra_descriptor +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x9bed64ee usb_set_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x9e1fd331 usb_anchor_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x9fc0634a usb_init_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xa626fee8 usb_buffer_unmap_sg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xaaee8705 usb_ifnum_to_if +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xab199f8c usb_put_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xace5c0fc usb_bus_list +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xade031bf usb_hcd_giveback_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xaff72bb4 usb_sg_cancel +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xb15128b5 usb_mon_register +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xb3ce9211 usb_unlink_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xbb182a0e usb_buffer_free +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xbbff46f6 usb_hcd_pci_remove +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xbc3a242f usb_wait_anchor_empty_timeout +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xbef55551 usb_get_intf +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xc17515d7 usb_hcds_loaded +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xc4424d9b usb_lock_device_for_reset +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xcbc33b99 usb_put_intf +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xd319881d usb_unanchor_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xd4da3526 usb_get_dev +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xd5e589b1 usb_interrupt_msg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xd7f5dffa usb_get_current_frame_number +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xd8fb7f09 usb_hcd_pci_probe +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xde40722e usb_string +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xdedfe3dc usb_get_descriptor +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xe3875d2a usb_kill_anchored_urbs +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xe3d614c4 usb_find_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xe532d7e9 usb_ep0_reinit +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xe66bec8d usb_hc_died +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xe9587909 usb_unregister_notify +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xe98f1d47 usb_submit_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xea4105dc usb_remove_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xed0690a5 ehci_cf_port_reset_rwsem +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xed2564f8 usb_register_device_driver +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xee35c2f1 usb_autopm_put_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xef727bff usb_deregister_dev +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xf204d5f1 usb_hcd_check_unlink_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xf2056555 usb_hcd_resume_root_hub +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xf2a2aa20 usb_match_one_id +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xf45fbbef usb_store_new_id +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xf57d1a34 usb_hcd_unlink_urb_from_ep +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xf7f8191f usb_deregister_device_driver +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xfed11ed1 usb_mon_deregister +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x3061f110 usb_ftdi_elan_read_pcimem +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x44c13e92 usb_ftdi_elan_edset_input +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x6f296360 usb_ftdi_elan_write_pcimem +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x72f3e4ed usb_ftdi_elan_edset_empty +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x8ded87d6 usb_ftdi_elan_edset_flush +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x8f911794 usb_ftdi_elan_edset_output +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0xc02312d9 usb_ftdi_elan_edset_single +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0xc936506e ftdi_elan_gone_away +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0xd0dc6ad9 usb_ftdi_elan_edset_setup +EXPORT_SYMBOL_GPL drivers/usb/misc/phidget 0x87f7008c phidget_class +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x29ab785c ezusb_set_reset +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x46d40d7d usb_serial_deregister +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x4e978d1a ezusb_writememory +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x5506d797 usb_serial_generic_read_bulk_callback +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x55fb9d96 usb_serial_port_softint +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x62669c33 usb_serial_generic_write_bulk_callback +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x78347ba4 usb_serial_probe +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x792e9157 usb_serial_generic_open +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0xa6aa71fd usb_serial_register +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0xff6a9fc7 usb_serial_disconnect +EXPORT_SYMBOL_GPL drivers/usb/storage/libusual 0x3edad223 usb_usual_clear_present +EXPORT_SYMBOL_GPL drivers/usb/storage/libusual 0x89d4dbaf usb_usual_check_type +EXPORT_SYMBOL_GPL drivers/usb/storage/libusual 0xcd9991a9 usb_usual_set_present +EXPORT_SYMBOL_GPL drivers/usb/storage/libusual 0xde134c69 storage_usb_ids +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x0cc52025 ili9320_resume +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x2b0b68b5 ili9320_write_regs +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x344cea0c ili9320_probe_spi +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x74c92c2e ili9320_shutdown +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0xa294dcd6 ili9320_suspend +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0xa4cbb9ed ili9320_remove +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0xd24038c1 ili9320_write +EXPORT_SYMBOL_GPL drivers/video/fb_ddc 0xd210409e fb_ddc_read +EXPORT_SYMBOL_GPL drivers/video/fb_sys_fops 0x7ac492ca fb_sys_read +EXPORT_SYMBOL_GPL drivers/video/fb_sys_fops 0xeaab9611 fb_sys_write +EXPORT_SYMBOL_GPL drivers/video/sis/sisfb 0x05bbce99 sis_free_new +EXPORT_SYMBOL_GPL drivers/video/sis/sisfb 0x54862ef8 sis_malloc_new +EXPORT_SYMBOL_GPL drivers/video/vermilion/vmlfb 0x016e6c20 vmlfb_unregister_subsys +EXPORT_SYMBOL_GPL drivers/video/vermilion/vmlfb 0x90c018c6 vmlfb_register_subsys +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0x0f191ab7 register_virtio_device +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0x16f5900f virtio_check_driver_offered_feature +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0x7aaa1838 unregister_virtio_device +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0xa9973f03 register_virtio_driver +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0xbab696b5 unregister_virtio_driver +EXPORT_SYMBOL_GPL drivers/virtio/virtio_ring 0x03c4687d vring_interrupt +EXPORT_SYMBOL_GPL drivers/virtio/virtio_ring 0x11a51fb2 vring_transport_features +EXPORT_SYMBOL_GPL drivers/virtio/virtio_ring 0xaf7c0454 vring_del_virtqueue +EXPORT_SYMBOL_GPL drivers/virtio/virtio_ring 0xc0e0aa23 vring_new_virtqueue +EXPORT_SYMBOL_GPL drivers/w1/wire 0x225e421c w1_write_block +EXPORT_SYMBOL_GPL drivers/w1/wire 0x6af5326e w1_reset_select_slave +EXPORT_SYMBOL_GPL drivers/w1/wire 0x7c2f2afb w1_calc_crc8 +EXPORT_SYMBOL_GPL drivers/w1/wire 0x82b56f84 w1_write_8 +EXPORT_SYMBOL_GPL drivers/w1/wire 0xcf6a6b2d w1_reset_bus +EXPORT_SYMBOL_GPL drivers/w1/wire 0xda0c6759 w1_read_block +EXPORT_SYMBOL_GPL fs/dlm/dlm 0x9321df95 dlm_lock +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xb1d92a2b dlm_posix_lock +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xc641235b dlm_posix_get +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xcf9f3328 dlm_release_lockspace +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xdc583c08 dlm_unlock +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xdcdd95e9 dlm_posix_unlock +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xdf3c14de dlm_new_lockspace +EXPORT_SYMBOL_GPL fs/exportfs/exportfs 0xb4f9166a exportfs_decode_fh +EXPORT_SYMBOL_GPL fs/exportfs/exportfs 0xf3bebb4b exportfs_encode_fh +EXPORT_SYMBOL_GPL fs/fat/fat 0x103c4fc2 fat_scan +EXPORT_SYMBOL_GPL fs/fat/fat 0x192777b3 fat_fill_super +EXPORT_SYMBOL_GPL fs/fat/fat 0x2f141b3f fat_sync_inode +EXPORT_SYMBOL_GPL fs/fat/fat 0x3490ba95 fat_search_long +EXPORT_SYMBOL_GPL fs/fat/fat 0x3d8e2ab0 fat_free_clusters +EXPORT_SYMBOL_GPL fs/fat/fat 0x4ece8c97 fat_fs_panic +EXPORT_SYMBOL_GPL fs/fat/fat 0x6f7139df fat_setattr +EXPORT_SYMBOL_GPL fs/fat/fat 0x72dcb9e0 fat_detach +EXPORT_SYMBOL_GPL fs/fat/fat 0x7a600b46 fat_build_inode +EXPORT_SYMBOL_GPL fs/fat/fat 0x9230234b fat_attach +EXPORT_SYMBOL_GPL fs/fat/fat 0x97715a93 fat_alloc_new_dir +EXPORT_SYMBOL_GPL fs/fat/fat 0xa79bf4a6 fat_flush_inodes +EXPORT_SYMBOL_GPL fs/fat/fat 0xaeb55307 fat_remove_entries +EXPORT_SYMBOL_GPL fs/fat/fat 0xaf45fa26 fat_getattr +EXPORT_SYMBOL_GPL fs/fat/fat 0xb68ea16d fat_date_unix2dos +EXPORT_SYMBOL_GPL fs/fat/fat 0xe8d15566 fat_get_dotdot_entry +EXPORT_SYMBOL_GPL fs/fat/fat 0xed264ddb fat_dir_empty +EXPORT_SYMBOL_GPL fs/fat/fat 0xfbaf9238 fat_add_entries +EXPORT_SYMBOL_GPL fs/gfs2/gfs2 0x4c739163 gfs2_unregister_lockproto +EXPORT_SYMBOL_GPL fs/gfs2/gfs2 0x7b0bd18c gfs2_register_lockproto +EXPORT_SYMBOL_GPL fs/lockd/lockd 0x104c1c6d nlmclnt_proc +EXPORT_SYMBOL_GPL fs/lockd/lockd 0x1a618932 nlmsvc_unlock_all_by_ip +EXPORT_SYMBOL_GPL fs/lockd/lockd 0x26b35026 nlmclnt_init +EXPORT_SYMBOL_GPL fs/lockd/lockd 0xd0a90c03 nlmsvc_unlock_all_by_sb +EXPORT_SYMBOL_GPL fs/lockd/lockd 0xe0e4f75d nlmclnt_done +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x1b89c6ee o2hb_fill_node_map +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x1d747ce3 o2hb_check_node_heartbeating +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x35ac10b1 o2hb_unregister_callback +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x36418553 o2net_send_message +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x4900035b o2hb_stop_all_regions +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x51eb6c7f o2hb_setup_callback +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x521e0726 o2net_send_message_vec +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x81a17396 mlog_and_bits +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x9b4682fc o2nm_get_node_by_num +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xa216f565 o2nm_get_node_by_ip +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xa82a8645 o2nm_this_node +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xa87bc9e7 o2nm_configured_node_map +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xae808bac o2net_register_handler +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xb469169a o2hb_register_callback +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xbaeb4700 o2hb_check_node_heartbeating_from_callback +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xd4eacdf8 o2nm_node_put +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xd60f2c6c o2hb_check_local_node_heartbeating +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xebf297a9 o2nm_node_get +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xf1a5611d o2net_unregister_handler_list +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xf56c2017 mlog_not_bits +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0x0ea641be dlm_unregister_domain +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0x37d19a24 dlmunlock +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0x7a1211f8 dlm_setup_eviction_cb +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0x8f1a26a7 dlm_register_domain +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xcbc0b1f5 dlm_print_one_lock +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xd7ba575e dlm_errmsg +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xd8fa57a6 dlm_unregister_eviction_cb +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xf93f3dab dlm_register_eviction_cb +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xfb86b96f dlm_errname +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xfbbc0b03 dlmlock +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x0562c415 ocfs2_cluster_this_node +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x0a831369 ocfs2_stack_glue_unregister +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x0e27f909 ocfs2_dlm_lock +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x21db5b88 ocfs2_cluster_disconnect +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x4a1f6fe9 ocfs2_cluster_connect +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x4d3af7fa ocfs2_cluster_hangup +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x81c85a68 ocfs2_dlm_lock_status +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x91fab465 ocfs2_dlm_lvb +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x9456503c ocfs2_stack_glue_register +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x963932a3 ocfs2_stack_glue_set_locking_protocol +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0xa7d5c1c0 ocfs2_dlm_unlock +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0xd066711e ocfs2_dlm_dump_lksb +EXPORT_SYMBOL_GPL lib/lzo/lzo_compress 0x2e1d43cf lzo1x_1_compress +EXPORT_SYMBOL_GPL lib/lzo/lzo_decompress 0x2a1538ca lzo1x_decompress_safe +EXPORT_SYMBOL_GPL lib/reed_solomon/reed_solomon 0x300d7e57 free_rs +EXPORT_SYMBOL_GPL lib/reed_solomon/reed_solomon 0x6fbb3bd9 init_rs_non_canonical +EXPORT_SYMBOL_GPL lib/reed_solomon/reed_solomon 0xabda1e2e decode_rs16 +EXPORT_SYMBOL_GPL lib/reed_solomon/reed_solomon 0xb050f329 init_rs +EXPORT_SYMBOL_GPL net/802/garp 0x1732d7a6 garp_uninit_applicant +EXPORT_SYMBOL_GPL net/802/garp 0x6c6fb931 garp_unregister_application +EXPORT_SYMBOL_GPL net/802/garp 0x7aaed301 garp_init_applicant +EXPORT_SYMBOL_GPL net/802/garp 0x7dc508c1 garp_request_leave +EXPORT_SYMBOL_GPL net/802/garp 0x8046363f garp_register_application +EXPORT_SYMBOL_GPL net/802/garp 0xfffbc4f8 garp_request_join +EXPORT_SYMBOL_GPL net/802/stp 0x737325e8 stp_proto_unregister +EXPORT_SYMBOL_GPL net/802/stp 0xc8750db9 stp_proto_register +EXPORT_SYMBOL_GPL net/ax25/ax25 0x5c9d67d9 ax25_register_pid +EXPORT_SYMBOL_GPL net/ax25/ax25 0xac93ae05 ax25_bcast +EXPORT_SYMBOL_GPL net/ax25/ax25 0xaeb7451e ax25_defaddr +EXPORT_SYMBOL_GPL net/bluetooth/bluetooth 0x1f82cc3e bt_class +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x0836683b tfrc_rx_hist_sample_rtt +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x09c5ed3c tfrc_tx_hist_purge +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x0a487ea5 tfrc_calc_x +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x106fe6d3 tfrc_tx_hist_rtt +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x197c78bd tfrc_rx_handle_loss +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x43c58bad tfrc_rx_hist_duplicate +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x54d1745f tfrc_lh_interval_add +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x69ec5731 tfrc_tx_hist_add +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x6c252d29 tfrc_calc_x_reverse_lookup +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x902206f0 tfrc_lh_cleanup +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x92285650 tfrc_rx_hist_alloc +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0xc612a5b6 tfrc_rx_hist_purge +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0xdebbee6c tfrc_lh_update_i_mean +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0xe405007b tfrc_rx_hist_add_packet +EXPORT_SYMBOL_GPL net/dccp/dccp 0x05fdd0e9 ccid_register +EXPORT_SYMBOL_GPL net/dccp/dccp 0x0c5c6d38 dccp_insert_option_timestamp +EXPORT_SYMBOL_GPL net/dccp/dccp 0x0df4f650 dccp_destroy_sock +EXPORT_SYMBOL_GPL net/dccp/dccp 0x118a40b3 dccp_ctl_make_reset +EXPORT_SYMBOL_GPL net/dccp/dccp 0x121668a2 dccp_send_sync +EXPORT_SYMBOL_GPL net/dccp/dccp 0x187b9cbe dccp_init_sock +EXPORT_SYMBOL_GPL net/dccp/dccp 0x1d99d49a dccp_timestamp +EXPORT_SYMBOL_GPL net/dccp/dccp 0x1ed10c32 ccid_hc_rx_new +EXPORT_SYMBOL_GPL net/dccp/dccp 0x2e701182 dccp_feat_change_recv +EXPORT_SYMBOL_GPL net/dccp/dccp 0x353bbc5a dccp_send_ack +EXPORT_SYMBOL_GPL net/dccp/dccp 0x3b3c0b1b dccp_feat_clean +EXPORT_SYMBOL_GPL net/dccp/dccp 0x43b7a411 dccp_feat_clone +EXPORT_SYMBOL_GPL net/dccp/dccp 0x44b950e8 dccp_shutdown +EXPORT_SYMBOL_GPL net/dccp/dccp 0x458c3ad3 dccp_connect +EXPORT_SYMBOL_GPL net/dccp/dccp 0x48a72555 inet_dccp_listen +EXPORT_SYMBOL_GPL net/dccp/dccp 0x557553c6 dccp_rcv_established +EXPORT_SYMBOL_GPL net/dccp/dccp 0x56ea266a dccp_state_name +EXPORT_SYMBOL_GPL net/dccp/dccp 0x5cb34c26 dccp_recvmsg +EXPORT_SYMBOL_GPL net/dccp/dccp 0x5eaebc49 dccp_parse_options +EXPORT_SYMBOL_GPL net/dccp/dccp 0x626d8bee dccp_getsockopt +EXPORT_SYMBOL_GPL net/dccp/dccp 0x6eeb0630 dccp_check_req +EXPORT_SYMBOL_GPL net/dccp/dccp 0x7e26f141 ccid_hc_rx_delete +EXPORT_SYMBOL_GPL net/dccp/dccp 0x86be7924 dccp_packet_name +EXPORT_SYMBOL_GPL net/dccp/dccp 0x883a2664 dccp_death_row +EXPORT_SYMBOL_GPL net/dccp/dccp 0x8995dab1 ccid_unregister +EXPORT_SYMBOL_GPL net/dccp/dccp 0x8b0fd41d compat_dccp_getsockopt +EXPORT_SYMBOL_GPL net/dccp/dccp 0x8b7d8caf dccp_statistics +EXPORT_SYMBOL_GPL net/dccp/dccp 0x8bc3d9f1 dccp_sendmsg +EXPORT_SYMBOL_GPL net/dccp/dccp 0x8be3e2da ccid_hc_tx_new +EXPORT_SYMBOL_GPL net/dccp/dccp 0x9373d9ec dccp_set_state +EXPORT_SYMBOL_GPL net/dccp/dccp 0x985e865f ccid_hc_tx_delete +EXPORT_SYMBOL_GPL net/dccp/dccp 0x9d6a3846 dccp_orphan_count +EXPORT_SYMBOL_GPL net/dccp/dccp 0x9ec71ae0 dccp_done +EXPORT_SYMBOL_GPL net/dccp/dccp 0xac864a97 dccp_rcv_state_process +EXPORT_SYMBOL_GPL net/dccp/dccp 0xb8fbb2ae dccp_poll +EXPORT_SYMBOL_GPL net/dccp/dccp 0xbc7b3869 dccp_disconnect +EXPORT_SYMBOL_GPL net/dccp/dccp 0xbc89e7d0 dccp_reqsk_send_ack +EXPORT_SYMBOL_GPL net/dccp/dccp 0xbe4cf010 dccp_feat_init +EXPORT_SYMBOL_GPL net/dccp/dccp 0xbf6b58ba dccp_feat_change +EXPORT_SYMBOL_GPL net/dccp/dccp 0xc2b9ca8c dccp_feat_confirm_recv +EXPORT_SYMBOL_GPL net/dccp/dccp 0xc3e72880 dccp_ioctl +EXPORT_SYMBOL_GPL net/dccp/dccp 0xcffaa78b dccp_make_response +EXPORT_SYMBOL_GPL net/dccp/dccp 0xd2ae3de8 dccp_sample_rtt +EXPORT_SYMBOL_GPL net/dccp/dccp 0xd67f0865 ccid_new +EXPORT_SYMBOL_GPL net/dccp/dccp 0xd6b4ead9 dccp_hashinfo +EXPORT_SYMBOL_GPL net/dccp/dccp 0xdf3a1ccd dccp_setsockopt +EXPORT_SYMBOL_GPL net/dccp/dccp 0xe72cf73d dccp_insert_option_elapsed_time +EXPORT_SYMBOL_GPL net/dccp/dccp 0xeebb6978 dccp_insert_option +EXPORT_SYMBOL_GPL net/dccp/dccp 0xf051e4b5 dccp_create_openreq_child +EXPORT_SYMBOL_GPL net/dccp/dccp 0xf2cbfacc dccp_sync_mss +EXPORT_SYMBOL_GPL net/dccp/dccp 0xfa2748e6 dccp_child_process +EXPORT_SYMBOL_GPL net/dccp/dccp 0xfd33e862 dccp_close +EXPORT_SYMBOL_GPL net/dccp/dccp 0xfd6b57b4 dccp_reqsk_init +EXPORT_SYMBOL_GPL net/dccp/dccp 0xfe8d1c8c compat_dccp_setsockopt +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0x171c7b98 dccp_v4_send_check +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0x23b032d7 dccp_invalid_packet +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0x3909f626 dccp_v4_do_rcv +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0x5353e8ee dccp_v4_request_recv_sock +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0xa90603c1 dccp_v4_conn_request +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0xc685998c dccp_v4_connect +EXPORT_SYMBOL_GPL net/ieee80211/ieee80211 0x2cf5fff3 ieee80211_rx_any +EXPORT_SYMBOL_GPL net/ipv4/ipvs/ip_vs 0xe6476b4a net_vs_ctl_path +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_conntrack_ipv4 0x06d3fe28 nf_nat_seq_adjust_hook +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_conntrack_ipv4 0x6d40a921 need_ipv4_conntrack +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x07ae60b6 nf_nat_proto_in_range +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x2aff4511 nf_nat_proto_find_get +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x408193a5 nf_nat_icmp_reply_translation +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x59c3072f nf_nat_proto_unique_tuple +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x935dbd25 nf_nat_proto_range_to_nlattr +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x94a08134 nf_nat_proto_nlattr_to_range +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0xb1920cb7 nf_nat_packet +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0xb267d194 nf_nat_proto_put +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat_proto_gre 0x636b12c8 nf_nat_need_gre +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0x2c6ce25c tcp_vegas_pkts_acked +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0x3a729979 tcp_vegas_get_info +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0x5065cc4c tcp_vegas_init +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0xb082db43 tcp_vegas_cwnd_event +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0xe6491e34 tcp_vegas_state +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x01270b43 ip6_dst_lookup +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x04548cb8 ipv6_find_tlv +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x08a3e5d1 net_ipv6_ctl_path +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x0c9befb5 inet6_sk_rebuild_header +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x13fa6972 ip6_local_out +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x2048c2fa fl6_sock_lookup +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x21ca859b inet6_csk_bind_conflict +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x2268702f ipv6_dup_options +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x4bb58ec5 inet6_csk_reqsk_queue_hash_add +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x55f91c50 ip6_dst_blackhole +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x6f1c1030 inet6_csk_addr2sockaddr +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x821c54aa ipv6_opt_accepted +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x86831cd2 inet6_csk_xmit +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0xb07c3e94 inet6_destroy_sock +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0xd33c27ea ip6_sk_dst_lookup +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0xf679fde4 inet6_csk_search_req +EXPORT_SYMBOL_GPL net/mac80211/mac80211 0x4eddb345 ieee80211_iterate_active_interfaces +EXPORT_SYMBOL_GPL net/mac80211/mac80211 0x9d2e76d0 ieee80211_iterate_active_interfaces_atomic +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x041013fd nf_conntrack_lock +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x045072cd nf_ct_port_nla_policy +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x0ea4f6dc nf_ct_iterate_cleanup +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x1283d711 nf_ct_expect_unregister_notifier +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x15c10b0b nf_conntrack_unregister_notifier +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x17c9367e nf_conntrack_helper_register +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x1d5b1ae1 nf_conntrack_l4proto_udp4 +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x248d7f93 nf_conntrack_alloc +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x25e649f2 nf_ct_log_invalid +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x2b9580cb nf_conntrack_flush +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x2e5d2cce nf_ct_expect_find_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x2f6d7863 nf_conntrack_l4proto_udp6 +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x3609de81 nf_conntrack_count +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x36bf1b41 nf_conntrack_l3proto_generic +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x38630158 nf_conntrack_tuple_taken +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x38c9440b nf_ct_extend_register +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x3f5b1415 nf_ct_port_nlattr_to_tuple +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x40387ccf __nf_ct_event_cache_init +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x4fa2388b nf_conntrack_l4proto_tcp6 +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x5bc88365 __nf_conntrack_helper_find_byname +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x5fde0387 nf_ct_expect_put +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6030839d nf_ct_port_tuple_to_nlattr +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x624149a9 nf_ct_l3protos +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x64e7eef0 __nf_ct_helper_find +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x684e889c __nf_ct_expect_find +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x68a94ae4 nf_conntrack_l3proto_register +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x68d269aa nf_ct_expect_related +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6add762d nf_conntrack_in +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6c02f72a nf_ct_l4proto_put +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6cd91ee0 per_cpu__nf_conntrack_ecache +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6e224a7a need_conntrack +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6eedbc99 nf_ct_l3proto_put +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x700d1765 seq_print_acct +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x72836f4a nf_conntrack_free +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x77aadb54 nf_conntrack_alter_reply +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x78f9b710 nf_ct_l3proto_try_module_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x79ca2e53 nf_ct_expect_chain +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x7d945a09 nf_conntrack_l4proto_tcp4 +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x85fe2cee nf_ct_expect_alloc +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x892e8797 nf_conntrack_l3proto_unregister +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x8ffe7e89 nf_conntrack_htable_size +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x90ff6c9f nf_ct_invert_tuplepr +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x9b38b540 nf_ct_get_tuple +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xa6f62ec0 nf_conntrack_set_hashsize +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xa869cd8c nf_conntrack_l4proto_register +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xaa072598 nf_conntrack_l4proto_unregister +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xaa7f735f __nf_conntrack_confirm +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xace98352 nf_conntrack_hash +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xad36f24b nf_ct_get_tuplepr +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xaf57e66f nf_ct_extend_unregister +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xb602c57e nf_ct_l3proto_module_put +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xb6f9a8a5 nf_ct_invert_tuple +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xb76accc2 __nf_conntrack_find +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xb9e30797 nf_ct_acct +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xbc887e16 nf_ct_expect_register_notifier +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xbe3f2939 nf_conntrack_checksum +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc044befe nf_ct_free_hashtable +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc18ac88d nf_ct_expect_hsize +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc35a7a3e nf_conntrack_chain +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc6bfe9ba __nf_ct_l4proto_find +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc7b64d79 nf_conntrack_hash_insert +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc86cbcbb nf_ct_expect_init +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc97799ba __nf_ct_refresh_acct +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xcbf7fd2a nf_conntrack_register_notifier +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd22893c1 nf_ct_unlink_expect +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd46e3724 __nf_ct_kill_acct +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd50a96a2 nf_ct_alloc_hashtable +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd553c300 nf_ct_l3proto_find_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd7c683c4 nf_conntrack_find_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd9efb053 nf_ct_deliver_cached_events +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xe3e83b8a nf_ct_l4proto_find_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xe3eda4b2 nf_ct_helper_ext_add +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xec8beba6 nf_ct_expect_hash +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xf25a47a0 nf_conntrack_tcp_update +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xf398fab4 nf_ct_unexpect_related +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xf6a2087d print_tuple +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xf9ae81a1 nf_conntrack_max +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xfa169dac nf_conntrack_untracked +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xfb839673 nf_ct_remove_expectations +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xfdfcd327 nf_conntrack_helper_unregister +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_amanda 0x1e7f07ca nf_nat_amanda_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_ftp 0xe3696262 nf_nat_ftp_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x14ee4acf set_sig_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x264c0cf3 get_h225_addr +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x4a815505 nat_q931_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x627dbfb0 nat_callforwarding_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x838b3d14 nat_t120_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x9475943e set_ras_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0xb51a4a7d nat_rtp_rtcp_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0xb671f98e nat_h245_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0xb8d77f64 set_h245_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0xfbc09389 set_h225_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_irc 0x9b561981 nf_nat_irc_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_pptp 0x24362528 nf_nat_pptp_hook_outbound +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_pptp 0x2d788e10 nf_nat_pptp_hook_inbound +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_pptp 0x60a1a957 nf_nat_pptp_hook_expectfn +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_pptp 0x907404bf nf_nat_pptp_hook_exp_gre +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_proto_gre 0x05f8e58c nf_ct_gre_keymap_destroy +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_proto_gre 0x6f59d77c nf_ct_gre_keymap_add +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x02d1acc2 nf_nat_sdp_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x13169b79 ct_sip_parse_request +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x25646c96 nf_nat_sdp_session_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x3c2058a6 ct_sip_parse_numerical_param +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x5333cb69 ct_sip_parse_header_uri +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x5343611e ct_sip_get_sdp_header +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x56ad8f6e ct_sip_parse_address_param +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x63547df4 nf_nat_sip_expect_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x66d73f0f nf_nat_sip_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x69dc74f6 nf_nat_sdp_port_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0xed35ddfc nf_nat_sdp_media_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0xf8b610ea ct_sip_get_header +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_tftp 0x2949c4d4 nf_nat_tftp_hook +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0x3d3ad67f nfnetlink_subsys_unregister +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0x4753d0eb nfnetlink_unicast +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0xb978a6ce nfnetlink_subsys_register +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0xcc82c49d nfnetlink_send +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0xeca95329 nfnetlink_has_listeners +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x2f32d4da xt_compat_lock +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x3b083e81 xt_compat_match_from_user +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x3cf5a35b xt_compat_match_to_user +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x3d619fea xt_unregister_table +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x50d7f1aa xt_compat_calc_jump +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x59c179ae xt_compat_target_from_user +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x6239c30f xt_compat_add_offset +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x63f05053 xt_find_revision +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x696109ee xt_compat_flush_offsets +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x6b86ebc8 xt_register_table +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x6c6c2b4d xt_compat_target_offset +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x6e835ca6 xt_request_find_target +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x822d2e96 xt_compat_target_to_user +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x86267b21 xt_check_target +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x86945c5e xt_table_unlock +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x8a3d4708 xt_compat_match_offset +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x911b586d xt_find_table_lock +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x955cccf3 xt_proto_fini +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x9e30bcb3 xt_proto_init +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0xcfddc8ad xt_replace_table +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0xe53911a2 xt_compat_unlock +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0xf6cf112d xt_check_match +EXPORT_SYMBOL_GPL net/netfilter/xt_RATEEST 0xc177bee0 xt_rateest_put +EXPORT_SYMBOL_GPL net/netfilter/xt_RATEEST 0xdb8418cc xt_rateest_lookup +EXPORT_SYMBOL_GPL net/rfkill/rfkill 0x83b2e956 register_rfkill_notifier +EXPORT_SYMBOL_GPL net/rfkill/rfkill 0x86c722f8 rfkill_epo +EXPORT_SYMBOL_GPL net/rfkill/rfkill 0xa6f4320d unregister_rfkill_notifier +EXPORT_SYMBOL_GPL net/rxrpc/af-rxrpc 0x2e916274 rxrpc_register_security +EXPORT_SYMBOL_GPL net/rxrpc/af-rxrpc 0xaf3b7cb4 rxrpc_unregister_security +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x05f78c2e svc_create_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x0ceead61 rpc_create +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x0df5cadc rpc_call_sync +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x17388b0f xprt_reserve_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x2578af4e xdr_skb_read_bits +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x25929dac rpcauth_register +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x2aa17774 rpc_free_iostats +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x2ad94124 rpc_sleep_on +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x2ea46c1d rpc_force_rebind +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x2eff00c1 rpc_call_null +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x31a89d59 rpc_debug +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x341cd07e xprt_unregister_transport +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x37f8f7f5 rpcauth_init_cred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x39d221b1 rpcb_getport_async +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x3f935f05 svc_xprt_enqueue +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x4571f263 rpc_peeraddr +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x481c9745 rpc_bind_new_program +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x48605515 rpc_restart_call +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x49dbc863 rpc_alloc_iostats +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x51a58a69 rpc_shutdown_client +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x53445f68 nlm_debug +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x53d073fc rpc_put_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x54d53105 svc_max_payload +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x550547a3 rpc_destroy_wait_queue +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x5b2f5a98 rpc_peeraddr2str +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x5bd26000 rpc_proc_unregister +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x616922a1 xprt_release_rqst_cong +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x6392642b rpc_malloc +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x65336dcb rpc_wake_up_queued_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x65a0509e svc_reg_xprt_class +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x69186c7d xprt_wait_for_buffer_space +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x6addd3d0 xprt_complete_rqst +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x6c5304c5 rpcb_getport_sync +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x6cd718ba rpcauth_unregister +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x712b860f rpc_setbufsize +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x78f8d2f8 xprt_write_space +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7938578d xprt_release_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x79b58f7a svc_addsock +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x79fd30ee rpcauth_lookup_credcache +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7ca553fa xprt_lookup_rqst +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7ce3014a xprt_set_retrans_timeout_rtt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7d59fa3f svc_xprt_init +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7de53067 rpc_init_rtt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x80cf6fa9 rpc_print_iostats +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x814cf549 xprt_set_retrans_timeout_def +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x81f87a1e rpcauth_init_credcache +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x85edb45b rpc_delay +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x90d8a820 rpc_max_payload +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x96e0214a rpc_call_start +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x97014523 rpc_killall_tasks +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x97c4f07b rpc_wake_up_next +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x97f7ebcd rpc_clone_client +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xa5e4b04b xprt_adjust_cwnd +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xa727fa86 svc_close_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xab7d314d svc_xprt_names +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xab8e3367 csum_partial_copy_to_xdr +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xac92f899 svc_xprt_copy_addrs +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xad55c221 rpcauth_create +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xaf5bf6ef nfs_debug +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xb387b246 rpc_wake_up_status +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xb46e2f62 rpc_lookup_cred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xbae9b026 svc_find_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xbf9d1b96 nfsd_debug +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xbfc3b992 rpc_lookup_machine_cred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xc12435e3 rpc_calc_rto +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xc7079d4c rpcauth_destroy_credcache +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xc7859fe1 xprt_update_rtt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xccb88495 xprt_reserve_xprt_cong +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xce115853 xprt_disconnect_done +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xd385a9c8 svc_print_addr +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xd82c728e rpc_init_wait_queue +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xda284d03 xdr_partial_copy_from_skb +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xe14fc829 put_rpccred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xe1bed8fe rpc_run_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xe242e6df rpc_proc_register +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xe59331fd xprt_register_transport +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xe667e62c xprt_release_xprt_cong +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xe6bacec1 rpc_exit_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xedd1ba52 rpc_wake_up +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xeeacab69 rpc_update_rtt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xf5a1f3af __rpc_wait_for_completion_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xf66ab2aa svc_xprt_put +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xf9d1164c rpc_free +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xfa3a4b4b rpc_call_async +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xfd981ce3 svc_unreg_xprt_class +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xfe03371e xprt_wake_pending_tasks +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xffa315be rpcauth_generic_bind_cred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xffe933d0 svc_xprt_received +EXPORT_SYMBOL_GPL net/xfrm/xfrm_ipcomp 0x395dc9a4 ipcomp_input +EXPORT_SYMBOL_GPL net/xfrm/xfrm_ipcomp 0x7c2cbe80 ipcomp_destroy +EXPORT_SYMBOL_GPL net/xfrm/xfrm_ipcomp 0xabddec04 ipcomp_output +EXPORT_SYMBOL_GPL net/xfrm/xfrm_ipcomp 0xcb39961c ipcomp_init_state +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x02289ecc snd_soc_dai_set_fmt +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x0698e603 snd_soc_dapm_new_controls +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x07e7f965 dapm_reg_event +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x0a8f8409 snd_soc_cnew +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x2a013c49 snd_soc_info_enum_ext +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x39ffdb73 snd_soc_dapm_add_routes +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x3d119574 snd_soc_new_pcms +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x405bcb81 snd_soc_dai_set_tdm_slot +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x4191620a snd_soc_dai_set_clkdiv +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x490c2bc2 snd_soc_get_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x494d70c1 snd_soc_put_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x4f68e9c8 snd_soc_info_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x509c6497 snd_soc_register_card +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x57aefd84 snd_soc_info_volsw_2r +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x5ccb8e6d snd_soc_dapm_get_pin_status +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x6122104b snd_soc_free_ac97_codec +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x61474fa0 snd_soc_new_ac97_codec +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x65bfe6e0 snd_soc_dapm_get_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x65febde3 snd_soc_dapm_put_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x713f6f16 snd_soc_dapm_free +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x7f57be48 snd_soc_dai_digital_mute +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x80669a9d snd_soc_dapm_connect_input +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x81c7a388 snd_soc_dapm_put_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x88051adb snd_soc_info_volsw_ext +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x9555313b snd_soc_dapm_new_control +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x9770750c snd_soc_info_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x9a510dfe snd_soc_get_volsw_2r +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xa4664f78 snd_soc_dapm_enable_pin +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xaec75bb9 snd_soc_info_volsw_s8 +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xb49d5df6 snd_soc_test_bits +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xb76622ca snd_soc_dapm_stream_event +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xb770e1c2 snd_soc_put_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xbb15872b snd_soc_dapm_disable_pin +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xbc66bc25 snd_soc_dai_set_pll +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xbe288b70 snd_soc_put_volsw_s8 +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xc0662ed3 snd_soc_update_bits +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xc2c02849 snd_soc_get_volsw_s8 +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xc76d13c8 snd_soc_free_pcms +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xd4e3733e snd_soc_dapm_get_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xd6d7177e snd_soc_dapm_sync +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xe2543174 snd_soc_get_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xe5c5661b snd_soc_set_runtime_hwparams +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xe6b9aec7 snd_soc_put_volsw_2r +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xede5360a snd_soc_dai_set_tristate +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xf5c726e0 snd_soc_dai_set_sysclk +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xf8566a36 snd_soc_dapm_new_widgets +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0x0d93d0e1 tlsf_create_memory_pool +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0x1584fdb9 tlsf_destroy_memory_pool +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0x2c383ca4 tlsf_calloc +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0x54064cb9 tlsf_get_used_size +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0x60d233a6 tlsf_malloc +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0xbe77d1fe tlsf_get_total_size +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0xe6acc368 tlsf_free +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x02500586 thinkpad_ec_unlock +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x0dc7484e thinkpad_ec_try_read_row +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x2552d213 thinkpad_ec_lock +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x3dbfef12 thinkpad_ec_read_row +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x8dbbd831 thinkpad_ec_invalidate +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0xa3042743 thinkpad_ec_prefetch_row +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0xfb5aa917 thinkpad_ec_try_lock +EXPORT_SYMBOL_GPL vmlinux 0x00566d8f inotify_get_cookie +EXPORT_SYMBOL_GPL vmlinux 0x006d7cad srcu_batches_completed +EXPORT_SYMBOL_GPL vmlinux 0x009ea0e5 sk_setup_caps +EXPORT_SYMBOL_GPL vmlinux 0x00b8ecf8 __iowrite32_copy +EXPORT_SYMBOL_GPL vmlinux 0x01848a8e local_apic_timer_c2_ok +EXPORT_SYMBOL_GPL vmlinux 0x01a4ea6d unregister_die_notifier +EXPORT_SYMBOL_GPL vmlinux 0x01e1a8de kgdb_breakpoint +EXPORT_SYMBOL_GPL vmlinux 0x028e6f97 __blocking_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x02a9ac14 user_update +EXPORT_SYMBOL_GPL vmlinux 0x02aaeb73 inotify_init +EXPORT_SYMBOL_GPL vmlinux 0x02ccea56 lock_policy_rwsem_write +EXPORT_SYMBOL_GPL vmlinux 0x0343bdf1 __i2c_board_list +EXPORT_SYMBOL_GPL vmlinux 0x0359f82a blk_end_request_callback +EXPORT_SYMBOL_GPL vmlinux 0x0375c1b8 generic_fh_to_parent +EXPORT_SYMBOL_GPL vmlinux 0x03dc0992 rtnl_kill_links +EXPORT_SYMBOL_GPL vmlinux 0x03fe2cca flush_work +EXPORT_SYMBOL_GPL vmlinux 0x0427901f transport_add_device +EXPORT_SYMBOL_GPL vmlinux 0x0447d159 raw_seq_stop +EXPORT_SYMBOL_GPL vmlinux 0x04486e88 rcu_batches_completed +EXPORT_SYMBOL_GPL vmlinux 0x04566c7f init_srcu_struct +EXPORT_SYMBOL_GPL vmlinux 0x047c1883 __inet_lookup_established +EXPORT_SYMBOL_GPL vmlinux 0x04c3f2c1 gnttab_empty_grant_references +EXPORT_SYMBOL_GPL vmlinux 0x04e628cd leds_list_lock +EXPORT_SYMBOL_GPL vmlinux 0x04ea8706 __iowrite64_copy +EXPORT_SYMBOL_GPL vmlinux 0x054e550b kernel_halt +EXPORT_SYMBOL_GPL vmlinux 0x05b0e01d input_ff_upload +EXPORT_SYMBOL_GPL vmlinux 0x05e1f291 vfs_cancel_lock +EXPORT_SYMBOL_GPL vmlinux 0x05e835d3 klist_node_attached +EXPORT_SYMBOL_GPL vmlinux 0x060833f0 input_class +EXPORT_SYMBOL_GPL vmlinux 0x0611d011 vfs_test_lock +EXPORT_SYMBOL_GPL vmlinux 0x064db9a5 mark_mounts_for_expiry +EXPORT_SYMBOL_GPL vmlinux 0x06bcd220 xenbus_unregister_driver +EXPORT_SYMBOL_GPL vmlinux 0x06d222f8 device_resume +EXPORT_SYMBOL_GPL vmlinux 0x06f64229 tty_get_pgrp +EXPORT_SYMBOL_GPL vmlinux 0x074a3aab device_initialize +EXPORT_SYMBOL_GPL vmlinux 0x074d8299 k_handler +EXPORT_SYMBOL_GPL vmlinux 0x07a708b2 pci_find_next_ht_capability +EXPORT_SYMBOL_GPL vmlinux 0x07b52e38 rtnl_unregister +EXPORT_SYMBOL_GPL vmlinux 0x07ff4aea xenbus_scanf +EXPORT_SYMBOL_GPL vmlinux 0x085ef4b4 inotify_remove_watch_locked +EXPORT_SYMBOL_GPL vmlinux 0x0871083f sysdev_class_unregister +EXPORT_SYMBOL_GPL vmlinux 0x08a3fe89 spi_new_device +EXPORT_SYMBOL_GPL vmlinux 0x091eb9b4 round_jiffies +EXPORT_SYMBOL_GPL vmlinux 0x09b5fba5 user_instantiate +EXPORT_SYMBOL_GPL vmlinux 0x0a1cfb74 blk_set_cmd_filter_defaults +EXPORT_SYMBOL_GPL vmlinux 0x0a264f8c cpufreq_register_driver +EXPORT_SYMBOL_GPL vmlinux 0x0aebf5b5 get_cpu_sysdev +EXPORT_SYMBOL_GPL vmlinux 0x0b34024c bdi_writeout_inc +EXPORT_SYMBOL_GPL vmlinux 0x0b42ff5b bus_rescan_devices +EXPORT_SYMBOL_GPL vmlinux 0x0b5e484c tty_ldisc_deref +EXPORT_SYMBOL_GPL vmlinux 0x0bc151e5 klist_init +EXPORT_SYMBOL_GPL vmlinux 0x0bfa774b fs_kobj +EXPORT_SYMBOL_GPL vmlinux 0x0c17e274 xfrm_aalg_get_byid +EXPORT_SYMBOL_GPL vmlinux 0x0c2de216 xfrm_inner_extract_output +EXPORT_SYMBOL_GPL vmlinux 0x0c4717f7 srcu_init_notifier_head +EXPORT_SYMBOL_GPL vmlinux 0x0cb8753f vlan_dev_vlan_id +EXPORT_SYMBOL_GPL vmlinux 0x0d20656a class_unregister +EXPORT_SYMBOL_GPL vmlinux 0x0d5ce501 attribute_container_find_class_device +EXPORT_SYMBOL_GPL vmlinux 0x0d9a47e7 simple_attr_release +EXPORT_SYMBOL_GPL vmlinux 0x0de6697e led_trigger_unregister +EXPORT_SYMBOL_GPL vmlinux 0x0ec210b8 xen_start_info +EXPORT_SYMBOL_GPL vmlinux 0x0ef84c65 hrtimer_start +EXPORT_SYMBOL_GPL vmlinux 0x0f1ee23a blkdev_driver_ioctl +EXPORT_SYMBOL_GPL vmlinux 0x0f48167d crypto_register_instance +EXPORT_SYMBOL_GPL vmlinux 0x0fe2d570 xenbus_directory +EXPORT_SYMBOL_GPL vmlinux 0x0ff8687d rtc_device_register +EXPORT_SYMBOL_GPL vmlinux 0x0ff8bb3f map_vm_area +EXPORT_SYMBOL_GPL vmlinux 0x10421ec3 get_task_mm +EXPORT_SYMBOL_GPL vmlinux 0x1050bc52 hrtimer_init +EXPORT_SYMBOL_GPL vmlinux 0x107db31d xenbus_free_evtchn +EXPORT_SYMBOL_GPL vmlinux 0x10aced1e __xenbus_register_frontend +EXPORT_SYMBOL_GPL vmlinux 0x10b10ab3 pci_find_ext_capability +EXPORT_SYMBOL_GPL vmlinux 0x11a2a943 tty_perform_flush +EXPORT_SYMBOL_GPL vmlinux 0x11fcdf4d device_for_each_child +EXPORT_SYMBOL_GPL vmlinux 0x1239a941 sock_prot_inuse_get +EXPORT_SYMBOL_GPL vmlinux 0x124f2056 crypto_get_attr_type +EXPORT_SYMBOL_GPL vmlinux 0x1251d30f call_rcu +EXPORT_SYMBOL_GPL vmlinux 0x12e285ec is_uv_system +EXPORT_SYMBOL_GPL vmlinux 0x1352e336 xfrm_output +EXPORT_SYMBOL_GPL vmlinux 0x138b472b __percpu_alloc_mask +EXPORT_SYMBOL_GPL vmlinux 0x13b2a946 register_keyboard_notifier +EXPORT_SYMBOL_GPL vmlinux 0x145eebd0 device_power_up +EXPORT_SYMBOL_GPL vmlinux 0x146bee29 spi_register_master +EXPORT_SYMBOL_GPL vmlinux 0x149db923 selinux_string_to_sid +EXPORT_SYMBOL_GPL vmlinux 0x14d5425d bus_find_device_by_name +EXPORT_SYMBOL_GPL vmlinux 0x14e367f8 debugfs_create_file +EXPORT_SYMBOL_GPL vmlinux 0x1534ba7a bus_unregister +EXPORT_SYMBOL_GPL vmlinux 0x1598dc9d unregister_netevent_notifier +EXPORT_SYMBOL_GPL vmlinux 0x1598ef3e devres_close_group +EXPORT_SYMBOL_GPL vmlinux 0x15b0606e e820_any_mapped +EXPORT_SYMBOL_GPL vmlinux 0x163958ff mmput +EXPORT_SYMBOL_GPL vmlinux 0x166b6ad5 spi_bus_type +EXPORT_SYMBOL_GPL vmlinux 0x16a2ff76 rt_mutex_lock_interruptible +EXPORT_SYMBOL_GPL vmlinux 0x16a5b4c8 key_type_user +EXPORT_SYMBOL_GPL vmlinux 0x16b6e800 driver_remove_file +EXPORT_SYMBOL_GPL vmlinux 0x17ff49b4 save_stack_trace_tsk +EXPORT_SYMBOL_GPL vmlinux 0x1808b560 blk_queue_dma_drain +EXPORT_SYMBOL_GPL vmlinux 0x187551b2 spi_write_then_read +EXPORT_SYMBOL_GPL vmlinux 0x1878f62b edac_err_assert +EXPORT_SYMBOL_GPL vmlinux 0x18d53420 kgdb_register_io_module +EXPORT_SYMBOL_GPL vmlinux 0x18e24ff8 vfs_listxattr +EXPORT_SYMBOL_GPL vmlinux 0x18f83fab gnttab_grant_foreign_access_ref +EXPORT_SYMBOL_GPL vmlinux 0x18fa5171 inet_csk_get_port +EXPORT_SYMBOL_GPL vmlinux 0x1906cdee elv_unregister +EXPORT_SYMBOL_GPL vmlinux 0x1a10607f unregister_jprobes +EXPORT_SYMBOL_GPL vmlinux 0x1a7b9c47 relay_close +EXPORT_SYMBOL_GPL vmlinux 0x1a938737 atomic_notifier_chain_register +EXPORT_SYMBOL_GPL vmlinux 0x1acda5b2 atomic_notifier_chain_unregister +EXPORT_SYMBOL_GPL vmlinux 0x1b9aca3f jprobe_return +EXPORT_SYMBOL_GPL vmlinux 0x1c49acfe inet_csk_compat_setsockopt +EXPORT_SYMBOL_GPL vmlinux 0x1c5e06b3 inotify_add_watch +EXPORT_SYMBOL_GPL vmlinux 0x1c995eea get_user_pages_fast +EXPORT_SYMBOL_GPL vmlinux 0x1c99ba30 mnt_drop_write +EXPORT_SYMBOL_GPL vmlinux 0x1cac9211 get_driver +EXPORT_SYMBOL_GPL vmlinux 0x1d0d4070 crypto_init_spawn +EXPORT_SYMBOL_GPL vmlinux 0x1dd70100 dmi_walk +EXPORT_SYMBOL_GPL vmlinux 0x1ddf95ba sysdev_show_int +EXPORT_SYMBOL_GPL vmlinux 0x1e053cb0 kobject_rename +EXPORT_SYMBOL_GPL vmlinux 0x1e53dfd2 inotify_init_watch +EXPORT_SYMBOL_GPL vmlinux 0x1e698d14 debugfs_create_u64 +EXPORT_SYMBOL_GPL vmlinux 0x1e7bbcb3 kernel_restart +EXPORT_SYMBOL_GPL vmlinux 0x1eb9516e round_jiffies_relative +EXPORT_SYMBOL_GPL vmlinux 0x1ebae765 spi_sync +EXPORT_SYMBOL_GPL vmlinux 0x1f0b31b2 disk_round_stats +EXPORT_SYMBOL_GPL vmlinux 0x1f5c95f5 platform_device_put +EXPORT_SYMBOL_GPL vmlinux 0x1f68581f debugfs_create_symlink +EXPORT_SYMBOL_GPL vmlinux 0x1f6be5f2 tcp_twsk_unique +EXPORT_SYMBOL_GPL vmlinux 0x1f8ec1b3 acpi_get_pci_rootbridge_handle +EXPORT_SYMBOL_GPL vmlinux 0x1f9a0fbf hpet_unregister_irq_handler +EXPORT_SYMBOL_GPL vmlinux 0x1f9f2a01 inet_twsk_purge +EXPORT_SYMBOL_GPL vmlinux 0x1fcece42 inet_twdr_twcal_tick +EXPORT_SYMBOL_GPL vmlinux 0x20123563 tty_prepare_flip_string_flags +EXPORT_SYMBOL_GPL vmlinux 0x203bf9d1 sysctl_pathname +EXPORT_SYMBOL_GPL vmlinux 0x20577ea2 xfrm_ealg_get_byidx +EXPORT_SYMBOL_GPL vmlinux 0x2074c42e bus_register_notifier +EXPORT_SYMBOL_GPL vmlinux 0x20b82470 hpet_register_irq_handler +EXPORT_SYMBOL_GPL vmlinux 0x20bc3470 orderly_poweroff +EXPORT_SYMBOL_GPL vmlinux 0x217ac1b2 inet_csk_clone +EXPORT_SYMBOL_GPL vmlinux 0x217ef29a kill_pid_info_as_uid +EXPORT_SYMBOL_GPL vmlinux 0x21f9011b transport_class_register +EXPORT_SYMBOL_GPL vmlinux 0x21ff4e3f sysfs_remove_bin_file +EXPORT_SYMBOL_GPL vmlinux 0x2240d211 unregister_jprobe +EXPORT_SYMBOL_GPL vmlinux 0x22472bf4 xfrm_calg_get_byid +EXPORT_SYMBOL_GPL vmlinux 0x226f4e93 transport_setup_device +EXPORT_SYMBOL_GPL vmlinux 0x2296c00d crypto_attr_u32 +EXPORT_SYMBOL_GPL vmlinux 0x22a4c758 class_create_file +EXPORT_SYMBOL_GPL vmlinux 0x22bce646 debugfs_create_u8 +EXPORT_SYMBOL_GPL vmlinux 0x2305365b register_pernet_subsys +EXPORT_SYMBOL_GPL vmlinux 0x23864ce7 cpuset_mem_spread_node +EXPORT_SYMBOL_GPL vmlinux 0x23bbb214 devres_remove +EXPORT_SYMBOL_GPL vmlinux 0x23d18c07 __ip_route_output_key +EXPORT_SYMBOL_GPL vmlinux 0x23ecc82d tcp_twsk_destructor +EXPORT_SYMBOL_GPL vmlinux 0x24196ba2 init_uts_ns +EXPORT_SYMBOL_GPL vmlinux 0x24241f10 inotify_inode_queue_event +EXPORT_SYMBOL_GPL vmlinux 0x2447533c ktime_get_real +EXPORT_SYMBOL_GPL vmlinux 0x24c7698a xenbus_write +EXPORT_SYMBOL_GPL vmlinux 0x24e74b12 blk_trace_startstop +EXPORT_SYMBOL_GPL vmlinux 0x24eb7e32 leds_list +EXPORT_SYMBOL_GPL vmlinux 0x2502a974 pci_find_next_capability +EXPORT_SYMBOL_GPL vmlinux 0x2545c170 unregister_xenbus_watch +EXPORT_SYMBOL_GPL vmlinux 0x257e29cf spi_register_driver +EXPORT_SYMBOL_GPL vmlinux 0x2580d986 sched_setscheduler +EXPORT_SYMBOL_GPL vmlinux 0x25f141e7 driver_find_device +EXPORT_SYMBOL_GPL vmlinux 0x261ea931 debugfs_remove_recursive +EXPORT_SYMBOL_GPL vmlinux 0x26a7ca85 debugfs_rename +EXPORT_SYMBOL_GPL vmlinux 0x2714c98c klist_del +EXPORT_SYMBOL_GPL vmlinux 0x27bd158c unregister_pernet_gen_device +EXPORT_SYMBOL_GPL vmlinux 0x28088f0f pv_time_ops +EXPORT_SYMBOL_GPL vmlinux 0x28a2a498 debugfs_create_x8 +EXPORT_SYMBOL_GPL vmlinux 0x28d664ff __raw_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x28e23139 xfrm_probe_algs +EXPORT_SYMBOL_GPL vmlinux 0x28ff5fd3 blk_trace_remove +EXPORT_SYMBOL_GPL vmlinux 0x297c604e uhci_reset_hc +EXPORT_SYMBOL_GPL vmlinux 0x29e23aa7 rtc_irq_unregister +EXPORT_SYMBOL_GPL vmlinux 0x2a2cd7ba rtc_irq_set_freq +EXPORT_SYMBOL_GPL vmlinux 0x2a678a13 __suspend_report_result +EXPORT_SYMBOL_GPL vmlinux 0x2b24e4a0 uv_blade_info +EXPORT_SYMBOL_GPL vmlinux 0x2b3e8dfb platform_device_alloc +EXPORT_SYMBOL_GPL vmlinux 0x2b9f8e23 nf_net_ipv4_netfilter_sysctl_path +EXPORT_SYMBOL_GPL vmlinux 0x2bc15c10 inotify_inode_is_dead +EXPORT_SYMBOL_GPL vmlinux 0x2c16ed76 xfrm_calg_get_byname +EXPORT_SYMBOL_GPL vmlinux 0x2c639fad bd_claim_by_disk +EXPORT_SYMBOL_GPL vmlinux 0x2cc9feb2 queue_delayed_work_on +EXPORT_SYMBOL_GPL vmlinux 0x2cf2bf8b rtnl_link_unregister +EXPORT_SYMBOL_GPL vmlinux 0x2d088e2b led_trigger_set +EXPORT_SYMBOL_GPL vmlinux 0x2d59c954 edac_handlers +EXPORT_SYMBOL_GPL vmlinux 0x2d9f2ce3 sched_clock_idle_wakeup_event +EXPORT_SYMBOL_GPL vmlinux 0x2daba87c __inet_lookup_listener +EXPORT_SYMBOL_GPL vmlinux 0x2e3db831 sock_prot_inuse_add +EXPORT_SYMBOL_GPL vmlinux 0x2e6e7aee smp_ops +EXPORT_SYMBOL_GPL vmlinux 0x2eafd72f sysdev_unregister +EXPORT_SYMBOL_GPL vmlinux 0x2ec92012 scatterwalk_copychunks +EXPORT_SYMBOL_GPL vmlinux 0x2f1d6c37 led_trigger_show +EXPORT_SYMBOL_GPL vmlinux 0x2fe94ced xenbus_grant_ring +EXPORT_SYMBOL_GPL vmlinux 0x30ec9492 dev_set_name +EXPORT_SYMBOL_GPL vmlinux 0x316d56cd register_net_sysctl_rotable +EXPORT_SYMBOL_GPL vmlinux 0x3232c63c inet_twsk_put +EXPORT_SYMBOL_GPL vmlinux 0x324c274e lookup_create +EXPORT_SYMBOL_GPL vmlinux 0x325e677c gnttab_grant_foreign_transfer_ref +EXPORT_SYMBOL_GPL vmlinux 0x32674a70 tty_ldisc_ref +EXPORT_SYMBOL_GPL vmlinux 0x329d2333 crypto_spawn_tfm +EXPORT_SYMBOL_GPL vmlinux 0x33b6e752 acpi_ec_remove_query_handler +EXPORT_SYMBOL_GPL vmlinux 0x33f4cd16 sysfs_create_bin_file +EXPORT_SYMBOL_GPL vmlinux 0x3403a5b3 inotify_find_watch +EXPORT_SYMBOL_GPL vmlinux 0x3441c3d6 gpio_set_value_cansleep +EXPORT_SYMBOL_GPL vmlinux 0x344a986d rt_mutex_timed_lock +EXPORT_SYMBOL_GPL vmlinux 0x352ab1b9 fb_deferred_io_open +EXPORT_SYMBOL_GPL vmlinux 0x35ba78ac user_match +EXPORT_SYMBOL_GPL vmlinux 0x35d8cb4a debugfs_create_u32 +EXPORT_SYMBOL_GPL vmlinux 0x3613a502 crypto_tfm_in_queue +EXPORT_SYMBOL_GPL vmlinux 0x361e2bcc save_stack_trace +EXPORT_SYMBOL_GPL vmlinux 0x3621a014 sysdev_show_ulong +EXPORT_SYMBOL_GPL vmlinux 0x362e23ec call_rcu_bh +EXPORT_SYMBOL_GPL vmlinux 0x365a7222 xattr_getsecurity +EXPORT_SYMBOL_GPL vmlinux 0x36d36f09 register_kretprobes +EXPORT_SYMBOL_GPL vmlinux 0x36fa3f8c relay_reset +EXPORT_SYMBOL_GPL vmlinux 0x370be381 securityfs_remove +EXPORT_SYMBOL_GPL vmlinux 0x37a5f246 kernel_kobj +EXPORT_SYMBOL_GPL vmlinux 0x37afac06 xfrm_audit_state_add +EXPORT_SYMBOL_GPL vmlinux 0x3895233b srcu_notifier_chain_unregister +EXPORT_SYMBOL_GPL vmlinux 0x38973c6d generic_sync_sb_inodes +EXPORT_SYMBOL_GPL vmlinux 0x38ebeb63 tcp_reno_cong_avoid +EXPORT_SYMBOL_GPL vmlinux 0x38fc47e5 platform_get_irq +EXPORT_SYMBOL_GPL vmlinux 0x39b2e814 pci_restore_msi_state +EXPORT_SYMBOL_GPL vmlinux 0x39b87751 put_inotify_watch +EXPORT_SYMBOL_GPL vmlinux 0x3a311560 unregister_kprobes +EXPORT_SYMBOL_GPL vmlinux 0x3a7bdbf8 sysdev_remove_file +EXPORT_SYMBOL_GPL vmlinux 0x3a7f8b86 __local_bh_enable +EXPORT_SYMBOL_GPL vmlinux 0x3a865912 sysdev_create_file +EXPORT_SYMBOL_GPL vmlinux 0x3b1446fb platform_device_register +EXPORT_SYMBOL_GPL vmlinux 0x3b1d7e44 cpuidle_disable_device +EXPORT_SYMBOL_GPL vmlinux 0x3b4ec75d platform_get_resource_byname +EXPORT_SYMBOL_GPL vmlinux 0x3bc12515 class_find_device +EXPORT_SYMBOL_GPL vmlinux 0x3bc13dac devres_remove_group +EXPORT_SYMBOL_GPL vmlinux 0x3be7af02 get_max_files +EXPORT_SYMBOL_GPL vmlinux 0x3c942368 profile_event_unregister +EXPORT_SYMBOL_GPL vmlinux 0x3cd06035 add_input_randomness +EXPORT_SYMBOL_GPL vmlinux 0x3cfedb3f register_pm_notifier +EXPORT_SYMBOL_GPL vmlinux 0x3d29867d per_cpu__gdt_page +EXPORT_SYMBOL_GPL vmlinux 0x3d5f392d acpi_os_unmap_memory +EXPORT_SYMBOL_GPL vmlinux 0x3d7ea99a gnttab_grant_foreign_transfer +EXPORT_SYMBOL_GPL vmlinux 0x3d86deb4 class_remove_file +EXPORT_SYMBOL_GPL vmlinux 0x3e31a810 platform_add_devices +EXPORT_SYMBOL_GPL vmlinux 0x3eb8ea3e sk_clone +EXPORT_SYMBOL_GPL vmlinux 0x3ee3bb7c xfrm_audit_policy_add +EXPORT_SYMBOL_GPL vmlinux 0x3efb35c9 get_online_cpus +EXPORT_SYMBOL_GPL vmlinux 0x3f238101 dcookie_register +EXPORT_SYMBOL_GPL vmlinux 0x3f6bef12 security_inode_permission +EXPORT_SYMBOL_GPL vmlinux 0x3f84d4c9 gnttab_release_grant_reference +EXPORT_SYMBOL_GPL vmlinux 0x3f8d883a swiotlb_sync_single_range_for_cpu +EXPORT_SYMBOL_GPL vmlinux 0x3ff8fafd rtc_device_unregister +EXPORT_SYMBOL_GPL vmlinux 0x40d30f24 generic_drop_inode +EXPORT_SYMBOL_GPL vmlinux 0x412902aa copy_fs_struct +EXPORT_SYMBOL_GPL vmlinux 0x4133a719 tcp_register_congestion_control +EXPORT_SYMBOL_GPL vmlinux 0x41f3cc90 xfrm_aalg_get_byname +EXPORT_SYMBOL_GPL vmlinux 0x4241dc2c pciserial_resume_ports +EXPORT_SYMBOL_GPL vmlinux 0x424acc6d scatterwalk_done +EXPORT_SYMBOL_GPL vmlinux 0x425508d3 stop_machine +EXPORT_SYMBOL_GPL vmlinux 0x432969ec devm_kzalloc +EXPORT_SYMBOL_GPL vmlinux 0x432fd7f6 __gpio_set_value +EXPORT_SYMBOL_GPL vmlinux 0x43e0164a hvc_instantiate +EXPORT_SYMBOL_GPL vmlinux 0x449086a3 tty_wakeup +EXPORT_SYMBOL_GPL vmlinux 0x44a65d5c lock_policy_rwsem_read +EXPORT_SYMBOL_GPL vmlinux 0x44bc6fde skb_pull_rcsum +EXPORT_SYMBOL_GPL vmlinux 0x454a14a4 transport_remove_device +EXPORT_SYMBOL_GPL vmlinux 0x456804e0 debugfs_create_blob +EXPORT_SYMBOL_GPL vmlinux 0x456d7b79 cpufreq_unregister_governor +EXPORT_SYMBOL_GPL vmlinux 0x457594fa crypto_alg_list +EXPORT_SYMBOL_GPL vmlinux 0x45bf1ff3 crypto_inc +EXPORT_SYMBOL_GPL vmlinux 0x45c9f3e5 xenbus_map_ring_valloc +EXPORT_SYMBOL_GPL vmlinux 0x45d14bdf hypercall_page +EXPORT_SYMBOL_GPL vmlinux 0x460f31aa rodata_test_data +EXPORT_SYMBOL_GPL vmlinux 0x4619d2b5 xfrm_audit_state_replay_overflow +EXPORT_SYMBOL_GPL vmlinux 0x465d28ae xenbus_bind_evtchn +EXPORT_SYMBOL_GPL vmlinux 0x46b9a6c3 tcp_get_info +EXPORT_SYMBOL_GPL vmlinux 0x46ced5b5 inet_csk_listen_start +EXPORT_SYMBOL_GPL vmlinux 0x46e26e4c securityfs_create_file +EXPORT_SYMBOL_GPL vmlinux 0x46e9125d agp_add_bridge +EXPORT_SYMBOL_GPL vmlinux 0x47229b5c gpio_request +EXPORT_SYMBOL_GPL vmlinux 0x47821d95 destroy_workqueue +EXPORT_SYMBOL_GPL vmlinux 0x47ee26a7 find_get_pid +EXPORT_SYMBOL_GPL vmlinux 0x48bbc799 __mmu_notifier_register +EXPORT_SYMBOL_GPL vmlinux 0x48fb5d48 __sock_recv_timestamp +EXPORT_SYMBOL_GPL vmlinux 0x499043d3 crypto_init_queue +EXPORT_SYMBOL_GPL vmlinux 0x49f266fc crypto_drop_spawn +EXPORT_SYMBOL_GPL vmlinux 0x4a11a4fb bind_virq_to_irqhandler +EXPORT_SYMBOL_GPL vmlinux 0x4a7e30d9 marker_probe_unregister_private_data +EXPORT_SYMBOL_GPL vmlinux 0x4a8173d0 acpi_bus_trim +EXPORT_SYMBOL_GPL vmlinux 0x4ab25168 spi_add_device +EXPORT_SYMBOL_GPL vmlinux 0x4ae33030 drop_file_write_access +EXPORT_SYMBOL_GPL vmlinux 0x4aeaf238 anon_transport_class_unregister +EXPORT_SYMBOL_GPL vmlinux 0x4b600bf5 skb_segment +EXPORT_SYMBOL_GPL vmlinux 0x4b762828 start_thread +EXPORT_SYMBOL_GPL vmlinux 0x4bc83227 sysdev_class_register +EXPORT_SYMBOL_GPL vmlinux 0x4c6ed311 bus_for_each_drv +EXPORT_SYMBOL_GPL vmlinux 0x4c759827 byte_rev_table +EXPORT_SYMBOL_GPL vmlinux 0x4cb409fb single_release_net +EXPORT_SYMBOL_GPL vmlinux 0x4db3ad1c crypto_dequeue_request +EXPORT_SYMBOL_GPL vmlinux 0x4eb0d47f tcp_reno_ssthresh +EXPORT_SYMBOL_GPL vmlinux 0x4ec45440 inotify_destroy +EXPORT_SYMBOL_GPL vmlinux 0x4ec6a70b device_create +EXPORT_SYMBOL_GPL vmlinux 0x4f1bc946 register_net_sysctl_table +EXPORT_SYMBOL_GPL vmlinux 0x4f2198f8 __inet_inherit_port +EXPORT_SYMBOL_GPL vmlinux 0x4f56118a kobject_uevent +EXPORT_SYMBOL_GPL vmlinux 0x4f6d609d blk_rq_cur_bytes +EXPORT_SYMBOL_GPL vmlinux 0x5083fccb tcp_slow_start +EXPORT_SYMBOL_GPL vmlinux 0x509f8eaa page_mkclean +EXPORT_SYMBOL_GPL vmlinux 0x50b319ce cpu_bit_bitmap +EXPORT_SYMBOL_GPL vmlinux 0x50b67174 xfrm_ealg_get_byid +EXPORT_SYMBOL_GPL vmlinux 0x50e7193a __i2c_first_dynamic_bus_num +EXPORT_SYMBOL_GPL vmlinux 0x50fbb319 tty_ldisc_ref_wait +EXPORT_SYMBOL_GPL vmlinux 0x5122801a register_kretprobe +EXPORT_SYMBOL_GPL vmlinux 0x518c2fc6 hpet_rtc_dropped_irq +EXPORT_SYMBOL_GPL vmlinux 0x51a4c094 unregister_kprobe +EXPORT_SYMBOL_GPL vmlinux 0x51dd6488 xfrm_aalg_get_byidx +EXPORT_SYMBOL_GPL vmlinux 0x52d111ea pm_qos_update_requirement +EXPORT_SYMBOL_GPL vmlinux 0x531daa18 tty_buffer_request_room +EXPORT_SYMBOL_GPL vmlinux 0x53565c65 xenbus_watch_pathfmt +EXPORT_SYMBOL_GPL vmlinux 0x53986488 register_die_notifier +EXPORT_SYMBOL_GPL vmlinux 0x53c2d13a platform_get_resource +EXPORT_SYMBOL_GPL vmlinux 0x53d36086 blk_end_request +EXPORT_SYMBOL_GPL vmlinux 0x543f4547 free_vm_area +EXPORT_SYMBOL_GPL vmlinux 0x547dd35a __rtnl_register +EXPORT_SYMBOL_GPL vmlinux 0x54e14341 relay_open +EXPORT_SYMBOL_GPL vmlinux 0x5525e708 tcp_death_row +EXPORT_SYMBOL_GPL vmlinux 0x55526907 xen_features +EXPORT_SYMBOL_GPL vmlinux 0x56398615 mark_tsc_unstable +EXPORT_SYMBOL_GPL vmlinux 0x5641485b tty_termios_encode_baud_rate +EXPORT_SYMBOL_GPL vmlinux 0x573f13b0 screen_glyph +EXPORT_SYMBOL_GPL vmlinux 0x575c5f94 execute_in_process_context +EXPORT_SYMBOL_GPL vmlinux 0x5779d445 xenbus_exists +EXPORT_SYMBOL_GPL vmlinux 0x579e0bf5 rtnl_unregister_all +EXPORT_SYMBOL_GPL vmlinux 0x579e79cf xfrm_output_resume +EXPORT_SYMBOL_GPL vmlinux 0x58013efe class_interface_register +EXPORT_SYMBOL_GPL vmlinux 0x58842224 uart_console_write +EXPORT_SYMBOL_GPL vmlinux 0x595cbe8f driver_add_kobj +EXPORT_SYMBOL_GPL vmlinux 0x597f3bc3 marker_get_private_data +EXPORT_SYMBOL_GPL vmlinux 0x59930a88 fib_rules_register +EXPORT_SYMBOL_GPL vmlinux 0x59f99611 uhci_check_and_reset_hc +EXPORT_SYMBOL_GPL vmlinux 0x5a1ebda4 unregister_net_sysctl_table +EXPORT_SYMBOL_GPL vmlinux 0x5a2b1b67 gnttab_free_grant_reference +EXPORT_SYMBOL_GPL vmlinux 0x5a8e4a9d skb_to_sgvec +EXPORT_SYMBOL_GPL vmlinux 0x5af03a28 gnttab_claim_grant_reference +EXPORT_SYMBOL_GPL vmlinux 0x5b392b04 hrtimer_try_to_cancel +EXPORT_SYMBOL_GPL vmlinux 0x5b4317cf crypto_mod_get +EXPORT_SYMBOL_GPL vmlinux 0x5b5ff40b power_supply_changed +EXPORT_SYMBOL_GPL vmlinux 0x5bb44a32 klist_add_head +EXPORT_SYMBOL_GPL vmlinux 0x5bfc03c3 unregister_keyboard_notifier +EXPORT_SYMBOL_GPL vmlinux 0x5cfcf0f1 percpu_free +EXPORT_SYMBOL_GPL vmlinux 0x5d0f6f57 kbd_table +EXPORT_SYMBOL_GPL vmlinux 0x5d366dec gnttab_cancel_free_callback +EXPORT_SYMBOL_GPL vmlinux 0x5d679e21 inet_csk_compat_getsockopt +EXPORT_SYMBOL_GPL vmlinux 0x5d730e7b raw_notifier_chain_unregister +EXPORT_SYMBOL_GPL vmlinux 0x5dade1a9 blk_execute_rq_nowait +EXPORT_SYMBOL_GPL vmlinux 0x5dd67618 register_netevent_notifier +EXPORT_SYMBOL_GPL vmlinux 0x5e916cdb platform_bus +EXPORT_SYMBOL_GPL vmlinux 0x5eb05848 raw_seq_next +EXPORT_SYMBOL_GPL vmlinux 0x5f10e819 attribute_container_classdev_to_container +EXPORT_SYMBOL_GPL vmlinux 0x5f2da8c4 check_tsc_unstable +EXPORT_SYMBOL_GPL vmlinux 0x5f408bac klist_next +EXPORT_SYMBOL_GPL vmlinux 0x5fe069c2 unregister_pernet_device +EXPORT_SYMBOL_GPL vmlinux 0x5fea940b hrtimer_forward +EXPORT_SYMBOL_GPL vmlinux 0x604068c7 fsstack_copy_inode_size +EXPORT_SYMBOL_GPL vmlinux 0x606d7398 xenbus_dev_fatal +EXPORT_SYMBOL_GPL vmlinux 0x6091797f synchronize_rcu +EXPORT_SYMBOL_GPL vmlinux 0x60a13e90 rcu_barrier +EXPORT_SYMBOL_GPL vmlinux 0x60aff99f xenbus_frontend_closed +EXPORT_SYMBOL_GPL vmlinux 0x61dcd665 tcp_done +EXPORT_SYMBOL_GPL vmlinux 0x62843a48 class_interface_unregister +EXPORT_SYMBOL_GPL vmlinux 0x629637b6 platform_driver_probe +EXPORT_SYMBOL_GPL vmlinux 0x6313ab08 rtc_class_open +EXPORT_SYMBOL_GPL vmlinux 0x631a9974 ip_local_out +EXPORT_SYMBOL_GPL vmlinux 0x639e12dc tcp_unregister_congestion_control +EXPORT_SYMBOL_GPL vmlinux 0x63ae27d6 add_nops +EXPORT_SYMBOL_GPL vmlinux 0x6485d13c devres_add +EXPORT_SYMBOL_GPL vmlinux 0x64e563e9 inet_twsk_alloc +EXPORT_SYMBOL_GPL vmlinux 0x657fd497 do_sync_mapping_range +EXPORT_SYMBOL_GPL vmlinux 0x65ccb6f0 call_netevent_notifiers +EXPORT_SYMBOL_GPL vmlinux 0x65d6d0f0 gpio_direction_input +EXPORT_SYMBOL_GPL vmlinux 0x65ee75c3 tty_find_polling_driver +EXPORT_SYMBOL_GPL vmlinux 0x6610ad99 synchronize_srcu +EXPORT_SYMBOL_GPL vmlinux 0x661601de sprint_symbol +EXPORT_SYMBOL_GPL vmlinux 0x6644e04f sysfs_add_file_to_group +EXPORT_SYMBOL_GPL vmlinux 0x664d14f7 platform_device_del +EXPORT_SYMBOL_GPL vmlinux 0x66b2a859 nr_free_buffer_pages +EXPORT_SYMBOL_GPL vmlinux 0x66d87d38 symbol_put_addr +EXPORT_SYMBOL_GPL vmlinux 0x6738b621 fib_rules_lookup +EXPORT_SYMBOL_GPL vmlinux 0x67955ce6 profile_hits +EXPORT_SYMBOL_GPL vmlinux 0x6834cc83 klist_add_after +EXPORT_SYMBOL_GPL vmlinux 0x686c703f xfrm_count_auth_supported +EXPORT_SYMBOL_GPL vmlinux 0x688df66c rtc_read_alarm +EXPORT_SYMBOL_GPL vmlinux 0x6892088c unregister_pm_notifier +EXPORT_SYMBOL_GPL vmlinux 0x689822cc devm_kfree +EXPORT_SYMBOL_GPL vmlinux 0x691884ef pv_apic_ops +EXPORT_SYMBOL_GPL vmlinux 0x697ee61b uart_set_options +EXPORT_SYMBOL_GPL vmlinux 0x6b07a368 klist_add_before +EXPORT_SYMBOL_GPL vmlinux 0x6b10495b devres_alloc +EXPORT_SYMBOL_GPL vmlinux 0x6b31b660 xfrm_audit_state_icvfail +EXPORT_SYMBOL_GPL vmlinux 0x6b9178b3 xenbus_strstate +EXPORT_SYMBOL_GPL vmlinux 0x6b93bf60 inet_twdr_twkill_work +EXPORT_SYMBOL_GPL vmlinux 0x6be62dfd probe_kernel_read +EXPORT_SYMBOL_GPL vmlinux 0x6bfd1ba9 pciserial_suspend_ports +EXPORT_SYMBOL_GPL vmlinux 0x6c02fc7c inet_hash_connect +EXPORT_SYMBOL_GPL vmlinux 0x6c11059b __srcu_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x6c49c4f2 clockevents_notify +EXPORT_SYMBOL_GPL vmlinux 0x6c82e92f x86_bios_freq_base +EXPORT_SYMBOL_GPL vmlinux 0x6c8d5ae8 __gpio_get_value +EXPORT_SYMBOL_GPL vmlinux 0x6cb6b12f put_device +EXPORT_SYMBOL_GPL vmlinux 0x6d27432b crypto_hash_walk_done +EXPORT_SYMBOL_GPL vmlinux 0x6d4299ea fnotify_change +EXPORT_SYMBOL_GPL vmlinux 0x6d5b11f4 attribute_container_register +EXPORT_SYMBOL_GPL vmlinux 0x6d629bc0 ip_route_output_flow +EXPORT_SYMBOL_GPL vmlinux 0x6e58ddf0 gnttab_end_foreign_transfer_ref +EXPORT_SYMBOL_GPL vmlinux 0x6ebb0a57 kobject_uevent_env +EXPORT_SYMBOL_GPL vmlinux 0x6f11b038 inet_unhash +EXPORT_SYMBOL_GPL vmlinux 0x6f211436 xenbus_unmap_ring_vfree +EXPORT_SYMBOL_GPL vmlinux 0x6f893983 register_pernet_gen_device +EXPORT_SYMBOL_GPL vmlinux 0x6f9c2efe marker_probe_cb +EXPORT_SYMBOL_GPL vmlinux 0x6ffb5b60 klist_add_tail +EXPORT_SYMBOL_GPL vmlinux 0x70075cb1 led_trigger_remove +EXPORT_SYMBOL_GPL vmlinux 0x702a6e6a init_pid_ns +EXPORT_SYMBOL_GPL vmlinux 0x7037d79d k8_flush_garts +EXPORT_SYMBOL_GPL vmlinux 0x71c8bc95 kgdb_unregister_io_module +EXPORT_SYMBOL_GPL vmlinux 0x71cea111 put_driver +EXPORT_SYMBOL_GPL vmlinux 0x72598bb0 init_user_ns +EXPORT_SYMBOL_GPL vmlinux 0x7278d328 all_vm_events +EXPORT_SYMBOL_GPL vmlinux 0x731433ee unregister_timer_hook +EXPORT_SYMBOL_GPL vmlinux 0x73201149 klist_iter_init_node +EXPORT_SYMBOL_GPL vmlinux 0x7342836e pci_disable_pcie_error_reporting +EXPORT_SYMBOL_GPL vmlinux 0x73b1f76d do_posix_clock_nosettime +EXPORT_SYMBOL_GPL vmlinux 0x74544739 rt_mutex_unlock +EXPORT_SYMBOL_GPL vmlinux 0x7489ac58 driver_unregister +EXPORT_SYMBOL_GPL vmlinux 0x74abdafa task_handoff_register +EXPORT_SYMBOL_GPL vmlinux 0x74d61a4d get_dcookie +EXPORT_SYMBOL_GPL vmlinux 0x7521afb6 leave_mm +EXPORT_SYMBOL_GPL vmlinux 0x75ce259a sysdev_class_remove_file +EXPORT_SYMBOL_GPL vmlinux 0x75e8f3c3 crypto_register_notifier +EXPORT_SYMBOL_GPL vmlinux 0x7612c257 crypto_hash_type +EXPORT_SYMBOL_GPL vmlinux 0x762d809c net_assign_generic +EXPORT_SYMBOL_GPL vmlinux 0x76a679c3 rtnl_put_cacheinfo +EXPORT_SYMBOL_GPL vmlinux 0x76ada266 tcp_is_cwnd_limited +EXPORT_SYMBOL_GPL vmlinux 0x7712771a unbind_from_irqhandler +EXPORT_SYMBOL_GPL vmlinux 0x77620316 device_find_child +EXPORT_SYMBOL_GPL vmlinux 0x77954ed4 nf_register_afinfo +EXPORT_SYMBOL_GPL vmlinux 0x78fa77c7 sysdev_store_int +EXPORT_SYMBOL_GPL vmlinux 0x79115873 crypto_unregister_alg +EXPORT_SYMBOL_GPL vmlinux 0x7927d8a8 raw_hash_sk +EXPORT_SYMBOL_GPL vmlinux 0x7a0c257c bus_create_file +EXPORT_SYMBOL_GPL vmlinux 0x7a393193 crypto_alg_mod_lookup +EXPORT_SYMBOL_GPL vmlinux 0x7a4c1438 pv_info +EXPORT_SYMBOL_GPL vmlinux 0x7ac10ebc uv_node_to_blade +EXPORT_SYMBOL_GPL vmlinux 0x7b1d544d edac_handler_set +EXPORT_SYMBOL_GPL vmlinux 0x7b20543f vfs_setlease +EXPORT_SYMBOL_GPL vmlinux 0x7b47588d debugfs_create_u16 +EXPORT_SYMBOL_GPL vmlinux 0x7b6cbb67 device_create_file +EXPORT_SYMBOL_GPL vmlinux 0x7c07d61c pskb_put +EXPORT_SYMBOL_GPL vmlinux 0x7c52826e fib_rules_cleanup_ops +EXPORT_SYMBOL_GPL vmlinux 0x7c6b16b1 platform_device_add_resources +EXPORT_SYMBOL_GPL vmlinux 0x7c6d7605 blocking_notifier_chain_unregister +EXPORT_SYMBOL_GPL vmlinux 0x7c7e692d alloc_page_buffers +EXPORT_SYMBOL_GPL vmlinux 0x7d62cc28 pci_create_slot +EXPORT_SYMBOL_GPL vmlinux 0x7da8d037 marker_probe_register +EXPORT_SYMBOL_GPL vmlinux 0x7dc5d0b6 crypto_unregister_notifier +EXPORT_SYMBOL_GPL vmlinux 0x7ded3f1d inet_csk_reqsk_queue_prune +EXPORT_SYMBOL_GPL vmlinux 0x7e59a2d0 xenbus_alloc_evtchn +EXPORT_SYMBOL_GPL vmlinux 0x7e8633c9 get_inotify_watch +EXPORT_SYMBOL_GPL vmlinux 0x7ec83ccc fsstack_copy_attr_all +EXPORT_SYMBOL_GPL vmlinux 0x7f0aac9d sysfs_create_link +EXPORT_SYMBOL_GPL vmlinux 0x7f19a9bf spi_unregister_master +EXPORT_SYMBOL_GPL vmlinux 0x7f19c836 unlock_policy_rwsem_write +EXPORT_SYMBOL_GPL vmlinux 0x7f27564e fb_deferred_io_cleanup +EXPORT_SYMBOL_GPL vmlinux 0x7fc3c90d rtc_set_alarm +EXPORT_SYMBOL_GPL vmlinux 0x7ff10ccf raw_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x8039d043 selinux_secmark_relabel_packet_permission +EXPORT_SYMBOL_GPL vmlinux 0x8088d5ba led_trigger_set_default +EXPORT_SYMBOL_GPL vmlinux 0x80eac2a6 device_attach +EXPORT_SYMBOL_GPL vmlinux 0x80ee55c3 selinux_secmark_refcount_inc +EXPORT_SYMBOL_GPL vmlinux 0x80f9fb84 sysfs_create_file +EXPORT_SYMBOL_GPL vmlinux 0x81cdc540 mnt_want_write +EXPORT_SYMBOL_GPL vmlinux 0x81e6fa78 bus_get_kset +EXPORT_SYMBOL_GPL vmlinux 0x8226642f __gpio_cansleep +EXPORT_SYMBOL_GPL vmlinux 0x823a47a1 crypto_register_template +EXPORT_SYMBOL_GPL vmlinux 0x826360fd do_posix_clock_nonanosleep +EXPORT_SYMBOL_GPL vmlinux 0x829f0d2f skb_partial_csum_set +EXPORT_SYMBOL_GPL vmlinux 0x82af6582 platform_driver_register +EXPORT_SYMBOL_GPL vmlinux 0x82bfaee4 tty_prepare_flip_string +EXPORT_SYMBOL_GPL vmlinux 0x82cd19f3 register_xenstore_notifier +EXPORT_SYMBOL_GPL vmlinux 0x82d46785 inotify_dentry_parent_queue_event +EXPORT_SYMBOL_GPL vmlinux 0x82d79b51 sysctl_vfs_cache_pressure +EXPORT_SYMBOL_GPL vmlinux 0x82f776b7 gpio_export +EXPORT_SYMBOL_GPL vmlinux 0x8315abb2 raw_seq_start +EXPORT_SYMBOL_GPL vmlinux 0x835074f5 rtnl_register +EXPORT_SYMBOL_GPL vmlinux 0x83640498 crypto_mod_put +EXPORT_SYMBOL_GPL vmlinux 0x836a6f89 xfrm_audit_state_notfound +EXPORT_SYMBOL_GPL vmlinux 0x83afa919 register_pernet_device +EXPORT_SYMBOL_GPL vmlinux 0x83e40b1f cpufreq_cpu_get +EXPORT_SYMBOL_GPL vmlinux 0x83f5d687 sysdev_driver_register +EXPORT_SYMBOL_GPL vmlinux 0x83f6b2d2 dma_get_required_mask +EXPORT_SYMBOL_GPL vmlinux 0x84869be8 fb_deferred_io_fsync +EXPORT_SYMBOL_GPL vmlinux 0x85a750bf __blk_add_trace +EXPORT_SYMBOL_GPL vmlinux 0x85c10896 rcu_batches_completed_bh +EXPORT_SYMBOL_GPL vmlinux 0x85c15f9c __blk_put_request +EXPORT_SYMBOL_GPL vmlinux 0x85d7edfd hpet_set_periodic_freq +EXPORT_SYMBOL_GPL vmlinux 0x85d86844 kobject_init_and_add +EXPORT_SYMBOL_GPL vmlinux 0x85e5a3db ktime_get_ts +EXPORT_SYMBOL_GPL vmlinux 0x860e76a9 crypto_ahash_type +EXPORT_SYMBOL_GPL vmlinux 0x861cc2cc proc_net_mkdir +EXPORT_SYMBOL_GPL vmlinux 0x863f0092 __cpufreq_driver_getavg +EXPORT_SYMBOL_GPL vmlinux 0x86623fd7 notify_remote_via_irq +EXPORT_SYMBOL_GPL vmlinux 0x868784cb __symbol_get +EXPORT_SYMBOL_GPL vmlinux 0x8694affa relay_file_operations +EXPORT_SYMBOL_GPL vmlinux 0x86a51007 gnttab_end_foreign_transfer +EXPORT_SYMBOL_GPL vmlinux 0x86b1667d hwrng_unregister +EXPORT_SYMBOL_GPL vmlinux 0x871a9910 register_kprobes +EXPORT_SYMBOL_GPL vmlinux 0x873fbaea edac_atomic_assert_error +EXPORT_SYMBOL_GPL vmlinux 0x87754115 raw_notifier_chain_register +EXPORT_SYMBOL_GPL vmlinux 0x87f2cf3a blocking_notifier_chain_cond_register +EXPORT_SYMBOL_GPL vmlinux 0x880b189a __atomic_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x8810ad5e crypto_xor +EXPORT_SYMBOL_GPL vmlinux 0x885142a6 nf_net_netfilter_sysctl_path +EXPORT_SYMBOL_GPL vmlinux 0x887d2576 __crypto_alg_lookup +EXPORT_SYMBOL_GPL vmlinux 0x88f0db24 cancel_work_sync +EXPORT_SYMBOL_GPL vmlinux 0x89165e6e blk_trace_setup +EXPORT_SYMBOL_GPL vmlinux 0x891bf7e9 cpufreq_register_governor +EXPORT_SYMBOL_GPL vmlinux 0x89a81636 transport_configure_device +EXPORT_SYMBOL_GPL vmlinux 0x89bae393 platform_bus_type +EXPORT_SYMBOL_GPL vmlinux 0x89e3642e rtc_read_time +EXPORT_SYMBOL_GPL vmlinux 0x8a625087 pci_unblock_user_cfg_access +EXPORT_SYMBOL_GPL vmlinux 0x8a8ff62f vlan_dev_real_dev +EXPORT_SYMBOL_GPL vmlinux 0x8abed13d xfrm_aead_get_byname +EXPORT_SYMBOL_GPL vmlinux 0x8ac15e85 inotify_rm_watch +EXPORT_SYMBOL_GPL vmlinux 0x8b0f003d device_schedule_callback_owner +EXPORT_SYMBOL_GPL vmlinux 0x8b4f208e do_kern_mount +EXPORT_SYMBOL_GPL vmlinux 0x8b65ecc8 platform_driver_unregister +EXPORT_SYMBOL_GPL vmlinux 0x8b81d720 xenbus_switch_state +EXPORT_SYMBOL_GPL vmlinux 0x8b9200fd lookup_address +EXPORT_SYMBOL_GPL vmlinux 0x8c06a108 xenbus_transaction_start +EXPORT_SYMBOL_GPL vmlinux 0x8c38074a unregister_xenstore_notifier +EXPORT_SYMBOL_GPL vmlinux 0x8d4c2bb7 inet6_lookup_listener +EXPORT_SYMBOL_GPL vmlinux 0x8d4c2fdf flush_workqueue +EXPORT_SYMBOL_GPL vmlinux 0x8ddf68a7 inotify_rm_wd +EXPORT_SYMBOL_GPL vmlinux 0x8eb58c6e __wake_up_sync +EXPORT_SYMBOL_GPL vmlinux 0x8ee53b1e inverse_translate +EXPORT_SYMBOL_GPL vmlinux 0x8ef4891e device_remove_bin_file +EXPORT_SYMBOL_GPL vmlinux 0x8f6cee77 __round_jiffies_relative +EXPORT_SYMBOL_GPL vmlinux 0x8f6d851c __mmdrop +EXPORT_SYMBOL_GPL vmlinux 0x8fdc8162 netlink_has_listeners +EXPORT_SYMBOL_GPL vmlinux 0x9009602a acpi_bus_get_ejd +EXPORT_SYMBOL_GPL vmlinux 0x906b805e srcu_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x90a1004a crypto_has_alg +EXPORT_SYMBOL_GPL vmlinux 0x90bfc439 pci_intx +EXPORT_SYMBOL_GPL vmlinux 0x90c738bc elv_register +EXPORT_SYMBOL_GPL vmlinux 0x90e24811 preempt_notifier_unregister +EXPORT_SYMBOL_GPL vmlinux 0x90f94ef8 led_trigger_unregister_simple +EXPORT_SYMBOL_GPL vmlinux 0x9159b9d6 profile_event_register +EXPORT_SYMBOL_GPL vmlinux 0x917445dc power_supply_unregister +EXPORT_SYMBOL_GPL vmlinux 0x9192b8fe gpiochip_remove +EXPORT_SYMBOL_GPL vmlinux 0x91dacaa2 acpi_processor_ffh_cstate_probe +EXPORT_SYMBOL_GPL vmlinux 0x91e83a09 rtc_irq_set_state +EXPORT_SYMBOL_GPL vmlinux 0x91fd4fb8 device_rename +EXPORT_SYMBOL_GPL vmlinux 0x92183295 crypto_chain +EXPORT_SYMBOL_GPL vmlinux 0x92238352 led_trigger_store +EXPORT_SYMBOL_GPL vmlinux 0x9241c3ee device_power_down +EXPORT_SYMBOL_GPL vmlinux 0x92445aee hrtimer_get_res +EXPORT_SYMBOL_GPL vmlinux 0x924f366e exit_fs +EXPORT_SYMBOL_GPL vmlinux 0x92fb217b dcookie_unregister +EXPORT_SYMBOL_GPL vmlinux 0x9388c53b tcp_init_congestion_ops +EXPORT_SYMBOL_GPL vmlinux 0x93a2fc0f tty_encode_baud_rate +EXPORT_SYMBOL_GPL vmlinux 0x93d2422d snmp_mib_free +EXPORT_SYMBOL_GPL vmlinux 0x93e4a8a0 simple_attr_open +EXPORT_SYMBOL_GPL vmlinux 0x942c1704 cleanup_srcu_struct +EXPORT_SYMBOL_GPL vmlinux 0x94822b45 inet_diag_unregister +EXPORT_SYMBOL_GPL vmlinux 0x94d742f6 pcie_port_bus_type +EXPORT_SYMBOL_GPL vmlinux 0x952664c5 do_exit +EXPORT_SYMBOL_GPL vmlinux 0x9552df38 device_create_vargs +EXPORT_SYMBOL_GPL vmlinux 0x956a91ba gpio_get_value_cansleep +EXPORT_SYMBOL_GPL vmlinux 0x9577271c hpet_rtc_interrupt +EXPORT_SYMBOL_GPL vmlinux 0x95d2a718 crypto_enqueue_request +EXPORT_SYMBOL_GPL vmlinux 0x961a8cd3 unlock_policy_rwsem_read +EXPORT_SYMBOL_GPL vmlinux 0x964d5c39 acpi_os_map_memory +EXPORT_SYMBOL_GPL vmlinux 0x966d7352 transport_destroy_device +EXPORT_SYMBOL_GPL vmlinux 0x967fda38 rtc_class_close +EXPORT_SYMBOL_GPL vmlinux 0x96cbcf31 pm_qos_add_notifier +EXPORT_SYMBOL_GPL vmlinux 0x97028da3 led_trigger_register +EXPORT_SYMBOL_GPL vmlinux 0x976fbcbd tcp_reno_min_cwnd +EXPORT_SYMBOL_GPL vmlinux 0x9795720e bus_get_device_klist +EXPORT_SYMBOL_GPL vmlinux 0x981ad70f inet6_lookup +EXPORT_SYMBOL_GPL vmlinux 0x9833bc0c hvc_kick +EXPORT_SYMBOL_GPL vmlinux 0x98531f95 xfrm_audit_state_notfound_simple +EXPORT_SYMBOL_GPL vmlinux 0x988b642c device_unregister +EXPORT_SYMBOL_GPL vmlinux 0x995d1071 prof_on +EXPORT_SYMBOL_GPL vmlinux 0x999a0c6a input_ff_erase +EXPORT_SYMBOL_GPL vmlinux 0x9a11a0fc crypto_attr_alg_name +EXPORT_SYMBOL_GPL vmlinux 0x9a398f5c xfrm_ealg_get_byname +EXPORT_SYMBOL_GPL vmlinux 0x9a69acf9 tty_mode_ioctl +EXPORT_SYMBOL_GPL vmlinux 0x9b1220e6 blk_rq_bytes +EXPORT_SYMBOL_GPL vmlinux 0x9ba0501e unregister_vt_notifier +EXPORT_SYMBOL_GPL vmlinux 0x9bdf1586 proc_net_fops_create +EXPORT_SYMBOL_GPL vmlinux 0x9bfc99ee simple_attr_read +EXPORT_SYMBOL_GPL vmlinux 0x9c7b96cf vfs_removexattr +EXPORT_SYMBOL_GPL vmlinux 0x9cb8037b xfrm_count_enc_supported +EXPORT_SYMBOL_GPL vmlinux 0x9d06688b register_xenbus_watch +EXPORT_SYMBOL_GPL vmlinux 0x9d3850e1 gnttab_alloc_grant_references +EXPORT_SYMBOL_GPL vmlinux 0x9de44396 anon_inode_getfd +EXPORT_SYMBOL_GPL vmlinux 0x9de6c874 inet_csk_bind_conflict +EXPORT_SYMBOL_GPL vmlinux 0x9e25bfa6 fb_bl_default_curve +EXPORT_SYMBOL_GPL vmlinux 0x9e711ad2 pm_qos_requirement +EXPORT_SYMBOL_GPL vmlinux 0x9e7d3442 xenbus_resume +EXPORT_SYMBOL_GPL vmlinux 0x9e9662ab user_describe +EXPORT_SYMBOL_GPL vmlinux 0x9f51582e pci_find_ht_capability +EXPORT_SYMBOL_GPL vmlinux 0x9fce80db fb_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x9fcf7653 pci_bus_add_device +EXPORT_SYMBOL_GPL vmlinux 0x9ff9b2bd rtnl_link_register +EXPORT_SYMBOL_GPL vmlinux 0xa0255440 net_ipv4_ctl_path +EXPORT_SYMBOL_GPL vmlinux 0xa06724b2 default_backing_dev_info +EXPORT_SYMBOL_GPL vmlinux 0xa09fdf59 sysfs_notify +EXPORT_SYMBOL_GPL vmlinux 0xa0a612a0 device_del +EXPORT_SYMBOL_GPL vmlinux 0xa0c30548 debugfs_create_dir +EXPORT_SYMBOL_GPL vmlinux 0xa10360ff kern_mount_data +EXPORT_SYMBOL_GPL vmlinux 0xa1596d98 acpi_processor_ffh_cstate_enter +EXPORT_SYMBOL_GPL vmlinux 0xa1eea7bc cpuidle_register_device +EXPORT_SYMBOL_GPL vmlinux 0xa1f90571 platform_device_add +EXPORT_SYMBOL_GPL vmlinux 0xa2c03841 bind_evtchn_to_irqhandler +EXPORT_SYMBOL_GPL vmlinux 0xa2e67f08 acpi_bus_generate_proc_event4 +EXPORT_SYMBOL_GPL vmlinux 0xa2f1e19f class_for_each_device +EXPORT_SYMBOL_GPL vmlinux 0xa306d6fc relay_buf_full +EXPORT_SYMBOL_GPL vmlinux 0xa313b981 generic_fh_to_dentry +EXPORT_SYMBOL_GPL vmlinux 0xa3165bd4 tty_ldisc_flush +EXPORT_SYMBOL_GPL vmlinux 0xa3499aec get_device +EXPORT_SYMBOL_GPL vmlinux 0xa353fffc xenbus_rm +EXPORT_SYMBOL_GPL vmlinux 0xa37b3022 blkdev_ioctl +EXPORT_SYMBOL_GPL vmlinux 0xa3f560c1 skb_cow_data +EXPORT_SYMBOL_GPL vmlinux 0xa3fc96f0 marker_probe_cb_noarg +EXPORT_SYMBOL_GPL vmlinux 0xa452c297 hpet_mask_rtc_irq_bit +EXPORT_SYMBOL_GPL vmlinux 0xa47145a5 nf_unregister_afinfo +EXPORT_SYMBOL_GPL vmlinux 0xa4d58669 math_state_restore +EXPORT_SYMBOL_GPL vmlinux 0xa4f1c318 set_cpus_allowed_ptr +EXPORT_SYMBOL_GPL vmlinux 0xa557d46f crypto_larval_lookup +EXPORT_SYMBOL_GPL vmlinux 0xa5622624 power_supply_register +EXPORT_SYMBOL_GPL vmlinux 0xa5bf5c3e pm_qos_add_requirement +EXPORT_SYMBOL_GPL vmlinux 0xa5c36cec inotify_unmount_inodes +EXPORT_SYMBOL_GPL vmlinux 0xa694453e preempt_notifier_register +EXPORT_SYMBOL_GPL vmlinux 0xa7235bb8 input_ff_create +EXPORT_SYMBOL_GPL vmlinux 0xa7fcb6ef inet_csk_route_req +EXPORT_SYMBOL_GPL vmlinux 0xa815dda5 gpiochip_add +EXPORT_SYMBOL_GPL vmlinux 0xa878c628 __audit_inode_child +EXPORT_SYMBOL_GPL vmlinux 0xa8f59416 gpio_direction_output +EXPORT_SYMBOL_GPL vmlinux 0xa9126bff hpet_set_rtc_irq_bit +EXPORT_SYMBOL_GPL vmlinux 0xa963f49c tcp_orphan_count +EXPORT_SYMBOL_GPL vmlinux 0xa97310db __inet_twsk_hashdance +EXPORT_SYMBOL_GPL vmlinux 0xa9c530b8 unregister_oom_notifier +EXPORT_SYMBOL_GPL vmlinux 0xaa429881 sysfs_update_group +EXPORT_SYMBOL_GPL vmlinux 0xaa86cfb5 uv_possible_blades +EXPORT_SYMBOL_GPL vmlinux 0xaa8c4696 cpu_clock +EXPORT_SYMBOL_GPL vmlinux 0xaa9aa97a queue_work_on +EXPORT_SYMBOL_GPL vmlinux 0xaad399dc __get_vm_area +EXPORT_SYMBOL_GPL vmlinux 0xab01acbe gnttab_request_free_callback +EXPORT_SYMBOL_GPL vmlinux 0xab398839 pci_cleanup_aer_uncorrect_error_status +EXPORT_SYMBOL_GPL vmlinux 0xabc28976 force_evtchn_callback +EXPORT_SYMBOL_GPL vmlinux 0xabe9e854 put_pid +EXPORT_SYMBOL_GPL vmlinux 0xac1ee37d sysdev_store_ulong +EXPORT_SYMBOL_GPL vmlinux 0xacc19485 ibft_addr +EXPORT_SYMBOL_GPL vmlinux 0xacd03c8c rtc_set_time +EXPORT_SYMBOL_GPL vmlinux 0xad096363 xenbus_printf +EXPORT_SYMBOL_GPL vmlinux 0xad63a24e per_cpu____uv_hub_info +EXPORT_SYMBOL_GPL vmlinux 0xae0c87ee pm_qos_remove_notifier +EXPORT_SYMBOL_GPL vmlinux 0xaec245ed sysdev_driver_unregister +EXPORT_SYMBOL_GPL vmlinux 0xaf35b9db driver_create_file +EXPORT_SYMBOL_GPL vmlinux 0xafae3c4b pci_stop_bus_device +EXPORT_SYMBOL_GPL vmlinux 0xafdfa5ff platform_get_irq_byname +EXPORT_SYMBOL_GPL vmlinux 0xafe3ca88 crypto_attr_alg +EXPORT_SYMBOL_GPL vmlinux 0xb0889179 swiotlb_sync_single_range_for_device +EXPORT_SYMBOL_GPL vmlinux 0xb10d55bc cn_netlink_send +EXPORT_SYMBOL_GPL vmlinux 0xb120ab95 klist_remove +EXPORT_SYMBOL_GPL vmlinux 0xb1acbcce rcu_barrier_sched +EXPORT_SYMBOL_GPL vmlinux 0xb2196033 gpiochip_is_requested +EXPORT_SYMBOL_GPL vmlinux 0xb221ee72 pci_destroy_slot +EXPORT_SYMBOL_GPL vmlinux 0xb252fbdd agp_remove_bridge +EXPORT_SYMBOL_GPL vmlinux 0xb27005f5 device_suspend +EXPORT_SYMBOL_GPL vmlinux 0xb2b10979 debugfs_create_x32 +EXPORT_SYMBOL_GPL vmlinux 0xb3253ed9 hpet_rtc_timer_init +EXPORT_SYMBOL_GPL vmlinux 0xb37474a4 power_supply_class +EXPORT_SYMBOL_GPL vmlinux 0xb3a0bd63 inet6_hash_connect +EXPORT_SYMBOL_GPL vmlinux 0xb3c6720c __rtnl_link_register +EXPORT_SYMBOL_GPL vmlinux 0xb3e0b0f0 devres_release_group +EXPORT_SYMBOL_GPL vmlinux 0xb46c54ab hwmon_device_unregister +EXPORT_SYMBOL_GPL vmlinux 0xb4e14553 gnttab_query_foreign_access +EXPORT_SYMBOL_GPL vmlinux 0xb4ea7cf7 kgdb_connected +EXPORT_SYMBOL_GPL vmlinux 0xb51cd6a6 device_create_bin_file +EXPORT_SYMBOL_GPL vmlinux 0xb51fbd64 edac_op_state +EXPORT_SYMBOL_GPL vmlinux 0xb53ae573 cpu_idle_wait +EXPORT_SYMBOL_GPL vmlinux 0xb5c18a16 device_release_driver +EXPORT_SYMBOL_GPL vmlinux 0xb612444d snmp_mib_init +EXPORT_SYMBOL_GPL vmlinux 0xb61c5c63 platform_device_register_simple +EXPORT_SYMBOL_GPL vmlinux 0xb6230f1f gnttab_grant_foreign_access +EXPORT_SYMBOL_GPL vmlinux 0xb63550f5 __i2c_board_lock +EXPORT_SYMBOL_GPL vmlinux 0xb65091b3 selinux_secmark_refcount_dec +EXPORT_SYMBOL_GPL vmlinux 0xb6d0eace mmu_notifier_unregister +EXPORT_SYMBOL_GPL vmlinux 0xb6e62bbb __class_register +EXPORT_SYMBOL_GPL vmlinux 0xb7014595 __trace_note_message +EXPORT_SYMBOL_GPL vmlinux 0xb7104dbb cpufreq_driver_target +EXPORT_SYMBOL_GPL vmlinux 0xb7a70397 d_materialise_unique +EXPORT_SYMBOL_GPL vmlinux 0xb7b443de sysfs_remove_group +EXPORT_SYMBOL_GPL vmlinux 0xb7d7c12e hpet_set_alarm_time +EXPORT_SYMBOL_GPL vmlinux 0xb903674c scatterwalk_map_and_copy +EXPORT_SYMBOL_GPL vmlinux 0xb9291bc2 sysfs_remove_file +EXPORT_SYMBOL_GPL vmlinux 0xb9761b49 alloc_vm_area +EXPORT_SYMBOL_GPL vmlinux 0xb97e6c02 anon_transport_class_register +EXPORT_SYMBOL_GPL vmlinux 0xb99d5837 xenbus_read +EXPORT_SYMBOL_GPL vmlinux 0xb9eb3aa9 add_uevent_var +EXPORT_SYMBOL_GPL vmlinux 0xb9edd4f8 apply_to_page_range +EXPORT_SYMBOL_GPL vmlinux 0xba4de1dd sysfs_create_group +EXPORT_SYMBOL_GPL vmlinux 0xba8352af audit_log_vformat +EXPORT_SYMBOL_GPL vmlinux 0xbb29f2cf vfs_setxattr +EXPORT_SYMBOL_GPL vmlinux 0xbb7295b5 power_supply_am_i_supplied +EXPORT_SYMBOL_GPL vmlinux 0xbbb98859 edid_info +EXPORT_SYMBOL_GPL vmlinux 0xbbc9a768 relay_subbufs_consumed +EXPORT_SYMBOL_GPL vmlinux 0xbbd1e034 device_register +EXPORT_SYMBOL_GPL vmlinux 0xbc089f3b __class_create +EXPORT_SYMBOL_GPL vmlinux 0xbd0f4a30 inet_csk_search_req +EXPORT_SYMBOL_GPL vmlinux 0xbe7ef09b pci_set_pcie_reset_state +EXPORT_SYMBOL_GPL vmlinux 0xbf00a09b spi_busnum_to_master +EXPORT_SYMBOL_GPL vmlinux 0xbf74eb20 probe_kernel_write +EXPORT_SYMBOL_GPL vmlinux 0xc08015b1 cpuidle_unregister_device +EXPORT_SYMBOL_GPL vmlinux 0xc097eb8e hrtimer_get_remaining +EXPORT_SYMBOL_GPL vmlinux 0xc0ce6b54 cpuidle_unregister_driver +EXPORT_SYMBOL_GPL vmlinux 0xc11038d0 inotify_find_update_watch +EXPORT_SYMBOL_GPL vmlinux 0xc1133988 led_trigger_event +EXPORT_SYMBOL_GPL vmlinux 0xc1184bc8 sysfs_remove_file_from_group +EXPORT_SYMBOL_GPL vmlinux 0xc1285beb tty_put_char +EXPORT_SYMBOL_GPL vmlinux 0xc18ad2c1 devres_find +EXPORT_SYMBOL_GPL vmlinux 0xc1f351d3 unregister_kretprobes +EXPORT_SYMBOL_GPL vmlinux 0xc226b1e1 crypto_hash_walk_first +EXPORT_SYMBOL_GPL vmlinux 0xc26351f8 bind_evtchn_to_irq +EXPORT_SYMBOL_GPL vmlinux 0xc26aba23 firmware_kobj +EXPORT_SYMBOL_GPL vmlinux 0xc2945138 bus_remove_file +EXPORT_SYMBOL_GPL vmlinux 0xc2c93e67 fib_rules_unregister +EXPORT_SYMBOL_GPL vmlinux 0xc34efe27 snmp_fold_field +EXPORT_SYMBOL_GPL vmlinux 0xc427a823 crypto_larval_kill +EXPORT_SYMBOL_GPL vmlinux 0xc42f2f94 xenbus_read_driver_state +EXPORT_SYMBOL_GPL vmlinux 0xc4ddecd7 cpufreq_cpu_put +EXPORT_SYMBOL_GPL vmlinux 0xc509bb71 crypto_unregister_template +EXPORT_SYMBOL_GPL vmlinux 0xc512626a __supported_pte_mask +EXPORT_SYMBOL_GPL vmlinux 0xc5397da6 xenbus_mkdir +EXPORT_SYMBOL_GPL vmlinux 0xc5b4e65b hvc_poll +EXPORT_SYMBOL_GPL vmlinux 0xc625cc57 inet_csk_addr2sockaddr +EXPORT_SYMBOL_GPL vmlinux 0xc647dabc rt_mutex_trylock +EXPORT_SYMBOL_GPL vmlinux 0xc68976a8 spi_alloc_device +EXPORT_SYMBOL_GPL vmlinux 0xc7592c31 pci_find_aer_capability +EXPORT_SYMBOL_GPL vmlinux 0xc7ec11f6 atomic_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0xc7f603ba ip_build_and_send_pkt +EXPORT_SYMBOL_GPL vmlinux 0xc81be572 kobject_create_and_add +EXPORT_SYMBOL_GPL vmlinux 0xc81d40a6 hrtimer_cancel +EXPORT_SYMBOL_GPL vmlinux 0xc87c1f84 ktime_get +EXPORT_SYMBOL_GPL vmlinux 0xc87e487a sched_clock_idle_sleep_event +EXPORT_SYMBOL_GPL vmlinux 0xc8d563aa inet_twsk_schedule +EXPORT_SYMBOL_GPL vmlinux 0xc9561772 fb_destroy_modelist +EXPORT_SYMBOL_GPL vmlinux 0xc9878077 vfs_getxattr +EXPORT_SYMBOL_GPL vmlinux 0xc9b50daf get_current_tty +EXPORT_SYMBOL_GPL vmlinux 0xca81ea9a xenbus_transaction_end +EXPORT_SYMBOL_GPL vmlinux 0xcabe04de cpuidle_resume_and_unlock +EXPORT_SYMBOL_GPL vmlinux 0xcb131356 proc_net_remove +EXPORT_SYMBOL_GPL vmlinux 0xcbd7a5ee inet_csk_listen_stop +EXPORT_SYMBOL_GPL vmlinux 0xcbf20127 klist_iter_init +EXPORT_SYMBOL_GPL vmlinux 0xcc018d9c register_kprobe +EXPORT_SYMBOL_GPL vmlinux 0xcc1f1c3d inet_twdr_hangman +EXPORT_SYMBOL_GPL vmlinux 0xcc55902e posix_timer_event +EXPORT_SYMBOL_GPL vmlinux 0xcd80211d invalidate_inode_pages2 +EXPORT_SYMBOL_GPL vmlinux 0xcda73000 devres_open_group +EXPORT_SYMBOL_GPL vmlinux 0xcde9679b cpuidle_register_driver +EXPORT_SYMBOL_GPL vmlinux 0xcf024a73 console_drivers +EXPORT_SYMBOL_GPL vmlinux 0xcf7335a4 relay_switch_subbuf +EXPORT_SYMBOL_GPL vmlinux 0xcf982013 __pneigh_lookup +EXPORT_SYMBOL_GPL vmlinux 0xcfcc83ad register_vt_notifier +EXPORT_SYMBOL_GPL vmlinux 0xcffad590 seq_open_net +EXPORT_SYMBOL_GPL vmlinux 0xd027a07d marker_probe_unregister +EXPORT_SYMBOL_GPL vmlinux 0xd03c7700 secure_ipv4_port_ephemeral +EXPORT_SYMBOL_GPL vmlinux 0xd0674f85 rtc_irq_register +EXPORT_SYMBOL_GPL vmlinux 0xd0764ae2 crypto_alloc_instance +EXPORT_SYMBOL_GPL vmlinux 0xd0c05159 emergency_restart +EXPORT_SYMBOL_GPL vmlinux 0xd10c15cd pci_scan_child_bus +EXPORT_SYMBOL_GPL vmlinux 0xd162f18a find_pid_ns +EXPORT_SYMBOL_GPL vmlinux 0xd16712f3 crypto_check_attr_type +EXPORT_SYMBOL_GPL vmlinux 0xd1ee0737 device_add +EXPORT_SYMBOL_GPL vmlinux 0xd34003a7 find_vpid +EXPORT_SYMBOL_GPL vmlinux 0xd3b19ecd rt_mutex_lock +EXPORT_SYMBOL_GPL vmlinux 0xd3b78da3 xenbus_suspend_cancel +EXPORT_SYMBOL_GPL vmlinux 0xd3ef4639 transport_class_unregister +EXPORT_SYMBOL_GPL vmlinux 0xd44bcdb7 unregister_kretprobe +EXPORT_SYMBOL_GPL vmlinux 0xd51036aa nf_unregister_queue_handlers +EXPORT_SYMBOL_GPL vmlinux 0xd516bffd platform_device_add_data +EXPORT_SYMBOL_GPL vmlinux 0xd63bfaf6 raw_unhash_sk +EXPORT_SYMBOL_GPL vmlinux 0xd6a51ac1 debugfs_remove +EXPORT_SYMBOL_GPL vmlinux 0xd6feefa5 agp_num_entries +EXPORT_SYMBOL_GPL vmlinux 0xd7d79132 put_online_cpus +EXPORT_SYMBOL_GPL vmlinux 0xd82f8964 devres_get +EXPORT_SYMBOL_GPL vmlinux 0xd869cc44 securityfs_create_dir +EXPORT_SYMBOL_GPL vmlinux 0xd9042fa8 scatterwalk_map +EXPORT_SYMBOL_GPL vmlinux 0xd9f8681a attribute_container_unregister +EXPORT_SYMBOL_GPL vmlinux 0xda680a07 fb_deferred_io_init +EXPORT_SYMBOL_GPL vmlinux 0xda77b6fe seq_release_net +EXPORT_SYMBOL_GPL vmlinux 0xdaaa88c2 hwmon_device_register +EXPORT_SYMBOL_GPL vmlinux 0xdab73ce8 vfs_kern_mount +EXPORT_SYMBOL_GPL vmlinux 0xdac7687b queue_work +EXPORT_SYMBOL_GPL vmlinux 0xdaf4dfb3 fb_mode_option +EXPORT_SYMBOL_GPL vmlinux 0xdb2558e7 inet_diag_register +EXPORT_SYMBOL_GPL vmlinux 0xdbee78fe spi_alloc_master +EXPORT_SYMBOL_GPL vmlinux 0xdc1f8f2e register_timer_hook +EXPORT_SYMBOL_GPL vmlinux 0xdc4c337d simple_attr_write +EXPORT_SYMBOL_GPL vmlinux 0xdc6d7696 __inet_hash_nolisten +EXPORT_SYMBOL_GPL vmlinux 0xdc9fdf45 kset_create_and_add +EXPORT_SYMBOL_GPL vmlinux 0xdcf56e9a zap_vma_ptes +EXPORT_SYMBOL_GPL vmlinux 0xdd4e1073 mmu_notifier_register +EXPORT_SYMBOL_GPL vmlinux 0xdd5c4942 srcu_notifier_chain_register +EXPORT_SYMBOL_GPL vmlinux 0xddb6d1c1 bus_register +EXPORT_SYMBOL_GPL vmlinux 0xddf7e7f7 raw_seq_open +EXPORT_SYMBOL_GPL vmlinux 0xde7ed175 device_destroy +EXPORT_SYMBOL_GPL vmlinux 0xdebc3bc7 sysfs_chmod_file +EXPORT_SYMBOL_GPL vmlinux 0xdf3c19ec cn_add_callback +EXPORT_SYMBOL_GPL vmlinux 0xdf78d42b xfrm_audit_state_delete +EXPORT_SYMBOL_GPL vmlinux 0xdf814e95 macvlan_handle_frame_hook +EXPORT_SYMBOL_GPL vmlinux 0xe089cfcc agp_memory_reserved +EXPORT_SYMBOL_GPL vmlinux 0xe0b4a4e5 rtc_update_irq +EXPORT_SYMBOL_GPL vmlinux 0xe24ff917 blocking_notifier_chain_register +EXPORT_SYMBOL_GPL vmlinux 0xe295c0ff is_hpet_enabled +EXPORT_SYMBOL_GPL vmlinux 0xe2dbd55a led_trigger_register_simple +EXPORT_SYMBOL_GPL vmlinux 0xe2e3f4a1 pci_slots_kset +EXPORT_SYMBOL_GPL vmlinux 0xe34c1ef8 debugfs_create_bool +EXPORT_SYMBOL_GPL vmlinux 0xe3ddc593 dnotify_parent +EXPORT_SYMBOL_GPL vmlinux 0xe3e07cda tcp_set_state +EXPORT_SYMBOL_GPL vmlinux 0xe3e7ba4a user_read +EXPORT_SYMBOL_GPL vmlinux 0xe48d5eac acpi_ec_add_query_handler +EXPORT_SYMBOL_GPL vmlinux 0xe513afc0 cache_k8_northbridges +EXPORT_SYMBOL_GPL vmlinux 0xe530071c pm_qos_remove_requirement +EXPORT_SYMBOL_GPL vmlinux 0xe57963a0 platform_device_unregister +EXPORT_SYMBOL_GPL vmlinux 0xe5e62a34 hvc_alloc +EXPORT_SYMBOL_GPL vmlinux 0xe61a6d2f gpio_unexport +EXPORT_SYMBOL_GPL vmlinux 0xe6488b47 cpufreq_notify_transition +EXPORT_SYMBOL_GPL vmlinux 0xe66df9c8 driver_register +EXPORT_SYMBOL_GPL vmlinux 0xe674a5cb srcu_read_lock +EXPORT_SYMBOL_GPL vmlinux 0xe75eedf8 crypto_lookup_template +EXPORT_SYMBOL_GPL vmlinux 0xe7671836 file_ra_state_init +EXPORT_SYMBOL_GPL vmlinux 0xe7de7122 device_reprobe +EXPORT_SYMBOL_GPL vmlinux 0xe7fa47ad srcu_read_unlock +EXPORT_SYMBOL_GPL vmlinux 0xe81af31a crypto_alg_sem +EXPORT_SYMBOL_GPL vmlinux 0xe83aafab mm_kobj +EXPORT_SYMBOL_GPL vmlinux 0xe8f9dfaf uv_cpu_to_blade +EXPORT_SYMBOL_GPL vmlinux 0xe9251b2c __crypto_alloc_tfm +EXPORT_SYMBOL_GPL vmlinux 0xe93e49c3 devres_free +EXPORT_SYMBOL_GPL vmlinux 0xe9468b9f input_ff_event +EXPORT_SYMBOL_GPL vmlinux 0xe992f29f sysfs_remove_link +EXPORT_SYMBOL_GPL vmlinux 0xe9ccaa26 sg_scsi_ioctl +EXPORT_SYMBOL_GPL vmlinux 0xe9dd844d bus_unregister_notifier +EXPORT_SYMBOL_GPL vmlinux 0xe9f5cc25 inet_ctl_sock_create +EXPORT_SYMBOL_GPL vmlinux 0xea065e01 task_handoff_unregister +EXPORT_SYMBOL_GPL vmlinux 0xea3b5fb7 vfs_lock_file +EXPORT_SYMBOL_GPL vmlinux 0xeab35970 single_open_net +EXPORT_SYMBOL_GPL vmlinux 0xeafe4181 page_cache_async_readahead +EXPORT_SYMBOL_GPL vmlinux 0xeafe7cca rtc_set_mmss +EXPORT_SYMBOL_GPL vmlinux 0xeb257fdd __blk_end_request +EXPORT_SYMBOL_GPL vmlinux 0xeb27d352 pci_update_slot_number +EXPORT_SYMBOL_GPL vmlinux 0xeb2fc492 skb_icv_walk +EXPORT_SYMBOL_GPL vmlinux 0xeb864b6e bus_for_each_dev +EXPORT_SYMBOL_GPL vmlinux 0xec24ad24 audit_log_untrustedstring +EXPORT_SYMBOL_GPL vmlinux 0xec2d8616 blk_end_bidi_request +EXPORT_SYMBOL_GPL vmlinux 0xecf8c328 xenbus_watch_path +EXPORT_SYMBOL_GPL vmlinux 0xed05aef7 xenbus_map_ring +EXPORT_SYMBOL_GPL vmlinux 0xed2b349d xenbus_unmap_ring +EXPORT_SYMBOL_GPL vmlinux 0xed48ee29 pciserial_init_ports +EXPORT_SYMBOL_GPL vmlinux 0xed835714 input_ff_destroy +EXPORT_SYMBOL_GPL vmlinux 0xed907658 devres_destroy +EXPORT_SYMBOL_GPL vmlinux 0xedbc6f67 gnttab_end_foreign_access +EXPORT_SYMBOL_GPL vmlinux 0xeecd1984 invalidate_inode_pages2_range +EXPORT_SYMBOL_GPL vmlinux 0xef67109f pci_bus_max_busnr +EXPORT_SYMBOL_GPL vmlinux 0xef9af54a __cpufreq_driver_target +EXPORT_SYMBOL_GPL vmlinux 0xefecadf7 device_remove_file +EXPORT_SYMBOL_GPL vmlinux 0xf0809b34 driver_for_each_device +EXPORT_SYMBOL_GPL vmlinux 0xf1516b93 page_cache_sync_readahead +EXPORT_SYMBOL_GPL vmlinux 0xf184d189 kernel_power_off +EXPORT_SYMBOL_GPL vmlinux 0xf1d411c8 audit_log_d_path +EXPORT_SYMBOL_GPL vmlinux 0xf1d928c3 class_destroy +EXPORT_SYMBOL_GPL vmlinux 0xf259eb08 driver_find +EXPORT_SYMBOL_GPL vmlinux 0xf2bace93 lookup_instantiate_filp +EXPORT_SYMBOL_GPL vmlinux 0xf2d0061b __rt_mutex_init +EXPORT_SYMBOL_GPL vmlinux 0xf2fca922 uart_parse_options +EXPORT_SYMBOL_GPL vmlinux 0xf31f2249 cpufreq_unregister_driver +EXPORT_SYMBOL_GPL vmlinux 0xf36a4c7f relay_flush +EXPORT_SYMBOL_GPL vmlinux 0xf3a6af55 register_jprobes +EXPORT_SYMBOL_GPL vmlinux 0xf45c203b crypto_alloc_base +EXPORT_SYMBOL_GPL vmlinux 0xf499fdb2 rcu_barrier_bh +EXPORT_SYMBOL_GPL vmlinux 0xf4aebdc3 xenbus_suspend +EXPORT_SYMBOL_GPL vmlinux 0xf4b77513 pid_vnr +EXPORT_SYMBOL_GPL vmlinux 0xf515ce1a crypto_free_tfm +EXPORT_SYMBOL_GPL vmlinux 0xf553318d cpuidle_pause_and_lock +EXPORT_SYMBOL_GPL vmlinux 0xf5945bac gnttab_free_grant_references +EXPORT_SYMBOL_GPL vmlinux 0xf5a691cd invalidate_bh_lrus +EXPORT_SYMBOL_GPL vmlinux 0xf5d148a1 user_destroy +EXPORT_SYMBOL_GPL vmlinux 0xf67ae112 bus_find_device +EXPORT_SYMBOL_GPL vmlinux 0xf6bcbd73 hwrng_register +EXPORT_SYMBOL_GPL vmlinux 0xf6ef1000 crypto_shoot_alg +EXPORT_SYMBOL_GPL vmlinux 0xf7016530 xenbus_gather +EXPORT_SYMBOL_GPL vmlinux 0xf72b3f8c inet_hash +EXPORT_SYMBOL_GPL vmlinux 0xf7427c4c register_jprobe +EXPORT_SYMBOL_GPL vmlinux 0xf7584904 bd_release_from_disk +EXPORT_SYMBOL_GPL vmlinux 0xf79ce51a pci_enable_pcie_error_reporting +EXPORT_SYMBOL_GPL vmlinux 0xf7be7f23 cpuidle_enable_device +EXPORT_SYMBOL_GPL vmlinux 0xf7f64d38 device_bind_driver +EXPORT_SYMBOL_GPL vmlinux 0xf840a220 driver_attach +EXPORT_SYMBOL_GPL vmlinux 0xf8802492 print_stack_trace +EXPORT_SYMBOL_GPL vmlinux 0xf8c3423d __mnt_is_readonly +EXPORT_SYMBOL_GPL vmlinux 0xf8d12d24 do_add_mount +EXPORT_SYMBOL_GPL vmlinux 0xf8df02fc crypto_register_alg +EXPORT_SYMBOL_GPL vmlinux 0xf917cf16 queue_delayed_work +EXPORT_SYMBOL_GPL vmlinux 0xf97c4aae klist_iter_exit +EXPORT_SYMBOL_GPL vmlinux 0xf984ccd1 __create_workqueue_key +EXPORT_SYMBOL_GPL vmlinux 0xf9a054b5 __round_jiffies +EXPORT_SYMBOL_GPL vmlinux 0xf9b0bb5f __rtnl_link_unregister +EXPORT_SYMBOL_GPL vmlinux 0xfa073338 inet_csk_reqsk_queue_hash_add +EXPORT_SYMBOL_GPL vmlinux 0xfa1f4662 scatterwalk_start +EXPORT_SYMBOL_GPL vmlinux 0xfb72ff5c xenbus_dev_error +EXPORT_SYMBOL_GPL vmlinux 0xfb8840d3 register_posix_clock +EXPORT_SYMBOL_GPL vmlinux 0xfbc016de blocking_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0xfbf9be5d register_oom_notifier +EXPORT_SYMBOL_GPL vmlinux 0xfc2e9abe debugfs_create_x16 +EXPORT_SYMBOL_GPL vmlinux 0xfc992a43 device_move +EXPORT_SYMBOL_GPL vmlinux 0xfd29ca8f dequeue_signal +EXPORT_SYMBOL_GPL vmlinux 0xfd51b281 gnttab_end_foreign_access_ref +EXPORT_SYMBOL_GPL vmlinux 0xfd6bbdaa security_inode_setattr +EXPORT_SYMBOL_GPL vmlinux 0xfd721947 sysdev_register +EXPORT_SYMBOL_GPL vmlinux 0xfde0b92c crypto_larval_error +EXPORT_SYMBOL_GPL vmlinux 0xfdf7fcbf kobject_get_path +EXPORT_SYMBOL_GPL vmlinux 0xfe727411 get_phys_to_machine +EXPORT_SYMBOL_GPL vmlinux 0xfe990052 gpio_free +EXPORT_SYMBOL_GPL vmlinux 0xfe9b10de pciserial_remove_ports +EXPORT_SYMBOL_GPL vmlinux 0xfea1e8a3 pci_block_user_cfg_access +EXPORT_SYMBOL_GPL vmlinux 0xfecbff96 __mark_empty_function +EXPORT_SYMBOL_GPL vmlinux 0xfed3b909 xfrm_audit_policy_delete +EXPORT_SYMBOL_GPL vmlinux 0xfeeeb3c7 skb_morph +EXPORT_SYMBOL_GPL vmlinux 0xff4af680 unregister_pernet_subsys +EXPORT_SYMBOL_GPL vmlinux 0xff5a8cfe cn_del_callback +EXPORT_SYMBOL_GPL vmlinux 0xff793790 sysdev_class_create_file +EXPORT_SYMBOL_GPL vmlinux 0xff94a4ba rt_mutex_destroy +EXPORT_SYMBOL_GPL vmlinux 0xffeceb70 sysfs_schedule_callback +EXPORT_UNUSED_SYMBOL vmlinux 0x00000000 init_mm --- linux-2.6.27.orig/debian/abi/2.6.27-14.39/amd64/server +++ linux-2.6.27/debian/abi/2.6.27-14.39/amd64/server @@ -0,0 +1,8123 @@ +EXPORT_SYMBOL arch/x86/kvm/kvm 0x42eb62ef kvm_cpu_has_pending_timer +EXPORT_SYMBOL arch/x86/kvm/kvm 0xa87cebcc kvm_read_guest_atomic +EXPORT_SYMBOL crypto/gf128mul 0x0c2f123f gf128mul_4k_bbe +EXPORT_SYMBOL crypto/gf128mul 0x1068004b gf128mul_bbe +EXPORT_SYMBOL crypto/gf128mul 0x2f2889a0 gf128mul_init_64k_lle +EXPORT_SYMBOL crypto/gf128mul 0x3755f990 gf128mul_init_64k_bbe +EXPORT_SYMBOL crypto/gf128mul 0x384ef9ce gf128mul_64k_bbe +EXPORT_SYMBOL crypto/gf128mul 0x56af0dbd gf128mul_x_ble +EXPORT_SYMBOL crypto/gf128mul 0x83581089 gf128mul_init_4k_lle +EXPORT_SYMBOL crypto/gf128mul 0x9b2560b9 gf128mul_init_4k_bbe +EXPORT_SYMBOL crypto/gf128mul 0x9e13f6f6 gf128mul_lle +EXPORT_SYMBOL crypto/gf128mul 0xbd17a0df gf128mul_4k_lle +EXPORT_SYMBOL crypto/gf128mul 0xc0890413 gf128mul_64k_lle +EXPORT_SYMBOL crypto/gf128mul 0xd60736ec gf128mul_free_64k +EXPORT_SYMBOL crypto/xor 0x5b6c00e6 xor_blocks +EXPORT_SYMBOL drivers/acpi/processor 0x0603377d acpi_processor_preregister_performance +EXPORT_SYMBOL drivers/acpi/processor 0x8461fbfe acpi_processor_unregister_performance +EXPORT_SYMBOL drivers/acpi/processor 0xcc337eed acpi_processor_notify_smm +EXPORT_SYMBOL drivers/acpi/processor 0xd78b77e1 acpi_processor_register_performance +EXPORT_SYMBOL drivers/acpi/processor 0xe8a3605f acpi_processor_set_thermal_limit +EXPORT_SYMBOL drivers/atm/suni 0x6ed6facc suni_init +EXPORT_SYMBOL drivers/atm/uPD98402 0x8ac2f15b uPD98402_init +EXPORT_SYMBOL drivers/block/loop 0xbfee3ad5 loop_unregister_transfer +EXPORT_SYMBOL drivers/block/loop 0xda0738b7 loop_register_transfer +EXPORT_SYMBOL drivers/block/paride/paride 0x12c3aebf pi_schedule_claimed +EXPORT_SYMBOL drivers/block/paride/paride 0x13d0d228 pi_connect +EXPORT_SYMBOL drivers/block/paride/paride 0x37e56c6e pi_write_regr +EXPORT_SYMBOL drivers/block/paride/paride 0x3ef1488d pi_read_block +EXPORT_SYMBOL drivers/block/paride/paride 0x4f201349 pi_read_regr +EXPORT_SYMBOL drivers/block/paride/paride 0x82ca49b5 paride_unregister +EXPORT_SYMBOL drivers/block/paride/paride 0x8f5598b8 pi_write_block +EXPORT_SYMBOL drivers/block/paride/paride 0x94dc2bc6 pi_do_claimed +EXPORT_SYMBOL drivers/block/paride/paride 0xa319e633 pi_release +EXPORT_SYMBOL drivers/block/paride/paride 0xa9d4cd2d pi_disconnect +EXPORT_SYMBOL drivers/block/paride/paride 0xf467bdab paride_register +EXPORT_SYMBOL drivers/block/paride/paride 0xfd4d185e pi_init +EXPORT_SYMBOL drivers/cdrom/cdrom 0x192190da cdrom_get_last_written +EXPORT_SYMBOL drivers/cdrom/cdrom 0x22d812e3 cdrom_open +EXPORT_SYMBOL drivers/cdrom/cdrom 0x2bdd265d cdrom_ioctl +EXPORT_SYMBOL drivers/cdrom/cdrom 0x39db512a cdrom_number_of_slots +EXPORT_SYMBOL drivers/cdrom/cdrom 0x4e2d1cf8 cdrom_media_changed +EXPORT_SYMBOL drivers/cdrom/cdrom 0x4f476e96 init_cdrom_command +EXPORT_SYMBOL drivers/cdrom/cdrom 0x5fb84030 cdrom_release +EXPORT_SYMBOL drivers/cdrom/cdrom 0x68d652e6 cdrom_get_media_event +EXPORT_SYMBOL drivers/cdrom/cdrom 0x980b7eb0 unregister_cdrom +EXPORT_SYMBOL drivers/cdrom/cdrom 0x997e12a2 cdrom_mode_select +EXPORT_SYMBOL drivers/cdrom/cdrom 0xcd525e47 cdrom_mode_sense +EXPORT_SYMBOL drivers/cdrom/cdrom 0xe065326c register_cdrom +EXPORT_SYMBOL drivers/char/generic_serial 0x0b6a70f2 gs_start +EXPORT_SYMBOL drivers/char/generic_serial 0x144b1f11 gs_chars_in_buffer +EXPORT_SYMBOL drivers/char/generic_serial 0x3df7f106 gs_flush_chars +EXPORT_SYMBOL drivers/char/generic_serial 0x5c867aa8 gs_write +EXPORT_SYMBOL drivers/char/generic_serial 0x6d7f76d5 gs_set_termios +EXPORT_SYMBOL drivers/char/generic_serial 0x76178bde gs_getserial +EXPORT_SYMBOL drivers/char/generic_serial 0x8d605ee0 gs_got_break +EXPORT_SYMBOL drivers/char/generic_serial 0x97b41249 gs_close +EXPORT_SYMBOL drivers/char/generic_serial 0x9880879c gs_setserial +EXPORT_SYMBOL drivers/char/generic_serial 0x9c1bf9e5 gs_init_port +EXPORT_SYMBOL drivers/char/generic_serial 0xb512aa44 gs_stop +EXPORT_SYMBOL drivers/char/generic_serial 0xb909e5e7 gs_put_char +EXPORT_SYMBOL drivers/char/generic_serial 0xcd29e2c7 gs_hangup +EXPORT_SYMBOL drivers/char/generic_serial 0xe9bbba8e gs_flush_buffer +EXPORT_SYMBOL drivers/char/generic_serial 0xf0e69448 gs_write_room +EXPORT_SYMBOL drivers/char/generic_serial 0xf5e924a4 gs_block_til_ready +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x1ad90dc6 ipmi_set_maintenance_mode +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x232d014d ipmi_destroy_user +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x274f977b ipmi_set_gets_events +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x33beadab ipmi_smi_msg_received +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x40f2b10c ipmi_alloc_smi_msg +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x4c59ec1f ipmi_set_my_LUN +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x538e7d1b ipmi_set_my_address +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x67f5363c ipmi_get_my_address +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x6b930cca ipmi_free_recv_msg +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x70f2763a ipmi_smi_add_proc_entry +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x7f91a69d ipmi_request_supply_msgs +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x804f922a ipmi_addr_length +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x8a480e46 ipmi_unregister_smi +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x9655c1ae ipmi_get_my_LUN +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0x99031808 ipmi_get_version +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xa0e28a35 ipmi_create_user +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xb60014a8 ipmi_poll_interface +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xb6e60293 ipmi_get_maintenance_mode +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xc085be97 ipmi_smi_watcher_unregister +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xce6fe5db ipmi_smi_watcher_register +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xd00390e8 ipmi_register_for_cmd +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xd335574d ipmi_request_settime +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xd66b3360 ipmi_unregister_for_cmd +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xe4f4665b ipmi_validate_addr +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xf2f01bb4 ipmi_smi_watchdog_pretimeout +EXPORT_SYMBOL drivers/char/ipmi/ipmi_msghandler 0xf92ef271 ipmi_register_smi +EXPORT_SYMBOL drivers/char/nsc_gpio 0x3c090386 nsc_gpio_dump +EXPORT_SYMBOL drivers/char/nsc_gpio 0x464404c1 nsc_gpio_read +EXPORT_SYMBOL drivers/char/nsc_gpio 0xa63d05c4 nsc_gpio_write +EXPORT_SYMBOL drivers/char/nvram 0x0f28cb91 nvram_read_byte +EXPORT_SYMBOL drivers/char/nvram 0x17ff2c1d __nvram_read_byte +EXPORT_SYMBOL drivers/char/nvram 0x2adec1e0 __nvram_check_checksum +EXPORT_SYMBOL drivers/char/nvram 0x7da28f12 nvram_check_checksum +EXPORT_SYMBOL drivers/char/nvram 0x9ce3f83f nvram_write_byte +EXPORT_SYMBOL drivers/char/nvram 0xa8813189 __nvram_write_byte +EXPORT_SYMBOL drivers/cpufreq/cpufreq_conservative 0x8a98db8b cpufreq_gov_conservative +EXPORT_SYMBOL drivers/cpufreq/cpufreq_ondemand 0x6a9cfc28 cpufreq_gov_ondemand +EXPORT_SYMBOL drivers/cpufreq/cpufreq_powersave 0xcd36ab09 cpufreq_gov_powersave +EXPORT_SYMBOL drivers/cpufreq/cpufreq_userspace 0x359dc287 cpufreq_gov_userspace +EXPORT_SYMBOL drivers/edac/edac_core 0x8d99203c edac_mc_handle_fbd_ue +EXPORT_SYMBOL drivers/edac/edac_core 0xa6f4766c edac_mc_find +EXPORT_SYMBOL drivers/edac/edac_core 0xf50ba9f6 edac_mc_handle_fbd_ce +EXPORT_SYMBOL drivers/gpu/drm/drm 0x016c6051 drm_core_ioremapfree +EXPORT_SYMBOL drivers/gpu/drm/drm 0x02067f63 drm_ati_pcigart_init +EXPORT_SYMBOL drivers/gpu/drm/drm 0x0836695c drm_sman_takedown +EXPORT_SYMBOL drivers/gpu/drm/drm 0x0a0db752 drm_addbufs_pci +EXPORT_SYMBOL drivers/gpu/drm/drm 0x0cd4ce51 drm_core_ioremap +EXPORT_SYMBOL drivers/gpu/drm/drm 0x0f0d10d1 drm_get_resource_len +EXPORT_SYMBOL drivers/gpu/drm/drm 0x13215f69 drm_i_have_hw_lock +EXPORT_SYMBOL drivers/gpu/drm/drm 0x15f35590 drm_rmmap +EXPORT_SYMBOL drivers/gpu/drm/drm 0x1be06a67 drm_locked_tasklet +EXPORT_SYMBOL drivers/gpu/drm/drm 0x1cae8929 drm_getsarea +EXPORT_SYMBOL drivers/gpu/drm/drm 0x20645642 drm_debug +EXPORT_SYMBOL drivers/gpu/drm/drm 0x21451ac4 drm_sman_owner_cleanup +EXPORT_SYMBOL drivers/gpu/drm/drm 0x2916bf63 drm_sman_cleanup +EXPORT_SYMBOL drivers/gpu/drm/drm 0x2eb2f903 drm_sman_free_key +EXPORT_SYMBOL drivers/gpu/drm/drm 0x3074f033 drm_order +EXPORT_SYMBOL drivers/gpu/drm/drm 0x36b91c9f drm_agp_release +EXPORT_SYMBOL drivers/gpu/drm/drm 0x3ba92735 drm_agp_alloc +EXPORT_SYMBOL drivers/gpu/drm/drm 0x3ee4e806 drm_exit +EXPORT_SYMBOL drivers/gpu/drm/drm 0x3f31885e drm_addbufs_agp +EXPORT_SYMBOL drivers/gpu/drm/drm 0x43ba74a0 drm_get_drawable_info +EXPORT_SYMBOL drivers/gpu/drm/drm 0x51863651 drm_init +EXPORT_SYMBOL drivers/gpu/drm/drm 0x543316ba drm_pci_free +EXPORT_SYMBOL drivers/gpu/drm/drm 0x558fe78e drm_mmap +EXPORT_SYMBOL drivers/gpu/drm/drm 0x55f060ee drm_sman_set_range +EXPORT_SYMBOL drivers/gpu/drm/drm 0x574a9829 drm_get_resource_start +EXPORT_SYMBOL drivers/gpu/drm/drm 0x576534e8 drm_compat_ioctl +EXPORT_SYMBOL drivers/gpu/drm/drm 0x5848c432 drm_addmap +EXPORT_SYMBOL drivers/gpu/drm/drm 0x597695a7 drm_open +EXPORT_SYMBOL drivers/gpu/drm/drm 0x5de94840 drm_irq_uninstall +EXPORT_SYMBOL drivers/gpu/drm/drm 0x7235dfcd drm_pci_alloc +EXPORT_SYMBOL drivers/gpu/drm/drm 0x7388f69e drm_idlelock_take +EXPORT_SYMBOL drivers/gpu/drm/drm 0x786ab359 drm_release +EXPORT_SYMBOL drivers/gpu/drm/drm 0x7dcaeb15 drm_agp_unbind +EXPORT_SYMBOL drivers/gpu/drm/drm 0x84aa6990 drm_agp_bind +EXPORT_SYMBOL drivers/gpu/drm/drm 0x858c5554 drm_idlelock_release +EXPORT_SYMBOL drivers/gpu/drm/drm 0x9c25b192 drm_core_get_map_ofs +EXPORT_SYMBOL drivers/gpu/drm/drm 0xa8962fdf drm_ioctl +EXPORT_SYMBOL drivers/gpu/drm/drm 0xaf29788e drm_sman_init +EXPORT_SYMBOL drivers/gpu/drm/drm 0xbfa5b3ff drm_poll +EXPORT_SYMBOL drivers/gpu/drm/drm 0xc15fc3a2 drm_core_ioremap_wc +EXPORT_SYMBOL drivers/gpu/drm/drm 0xc5a4a604 drm_ati_pcigart_cleanup +EXPORT_SYMBOL drivers/gpu/drm/drm 0xc852620c drm_vbl_send_signals +EXPORT_SYMBOL drivers/gpu/drm/drm 0xcbebb049 drm_core_get_reg_ofs +EXPORT_SYMBOL drivers/gpu/drm/drm 0xd046ec23 drm_fasync +EXPORT_SYMBOL drivers/gpu/drm/drm 0xd2138fcd drm_sg_alloc +EXPORT_SYMBOL drivers/gpu/drm/drm 0xd3028e75 drm_sman_set_manager +EXPORT_SYMBOL drivers/gpu/drm/drm 0xd5c7af13 drm_agp_enable +EXPORT_SYMBOL drivers/gpu/drm/drm 0xe57af146 drm_agp_acquire +EXPORT_SYMBOL drivers/gpu/drm/drm 0xe919dd5c drm_sman_owner_clean +EXPORT_SYMBOL drivers/gpu/drm/drm 0xee6e6544 drm_agp_free +EXPORT_SYMBOL drivers/gpu/drm/drm 0xf702a542 drm_agp_info +EXPORT_SYMBOL drivers/gpu/drm/drm 0xf9dfb525 drm_core_reclaim_buffers +EXPORT_SYMBOL drivers/gpu/drm/drm 0xfdfbad19 drm_sman_alloc +EXPORT_SYMBOL drivers/hwmon/hwmon-vid 0x0903c239 vid_from_reg +EXPORT_SYMBOL drivers/hwmon/hwmon-vid 0xef1c781c vid_which_vrm +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-bit 0x76a15344 i2c_bit_add_numbered_bus +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-bit 0xaa21220d i2c_bit_add_bus +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-pca 0x21c7ce25 i2c_pca_add_numbered_bus +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-pca 0x7cb0efa2 i2c_pca_add_bus +EXPORT_SYMBOL drivers/i2c/algos/i2c-algo-pcf 0x4247dceb i2c_pcf_add_bus +EXPORT_SYMBOL drivers/i2c/busses/i2c-amd756 0x7be0448f amd756_smbus +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0x02d4ad0f tps65013_set_low_pwr +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0x28485130 tps65010_config_vregs1 +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0x33739de7 tps65010_set_vib +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0x9fd44c69 tps65010_set_led +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0xb14080cc tps65010_set_low_pwr +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0xd5bb106d tps65010_set_vbus_draw +EXPORT_SYMBOL drivers/i2c/chips/tps65010 0xe99b3f36 tps65010_set_gpio_out_value +EXPORT_SYMBOL drivers/i2c/i2c-core 0x079e8c06 i2c_verify_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0x24f6f563 i2c_smbus_xfer +EXPORT_SYMBOL drivers/i2c/i2c-core 0x2cddfb97 i2c_smbus_read_word_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0x31ea6d9f i2c_transfer +EXPORT_SYMBOL drivers/i2c/i2c-core 0x36a6f18c i2c_smbus_read_byte_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0x399c89f0 i2c_smbus_write_i2c_block_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0x3a3efd43 i2c_smbus_write_word_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0x3a8d6008 i2c_release_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0x3c216405 i2c_detach_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0x3dfc5fd3 i2c_get_adapter +EXPORT_SYMBOL drivers/i2c/i2c-core 0x5a7110d3 i2c_attach_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0x6c562273 i2c_smbus_write_block_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0x78c6a457 i2c_add_adapter +EXPORT_SYMBOL drivers/i2c/i2c-core 0x7e369678 i2c_master_recv +EXPORT_SYMBOL drivers/i2c/i2c-core 0x7ff65204 i2c_del_adapter +EXPORT_SYMBOL drivers/i2c/i2c-core 0x9a77f4c8 i2c_smbus_read_i2c_block_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0xb3d27114 i2c_smbus_read_byte +EXPORT_SYMBOL drivers/i2c/i2c-core 0xbd2088f9 i2c_put_adapter +EXPORT_SYMBOL drivers/i2c/i2c-core 0xc63dfb9c i2c_smbus_read_block_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0xd6266c53 i2c_register_driver +EXPORT_SYMBOL drivers/i2c/i2c-core 0xd7269ecd i2c_use_client +EXPORT_SYMBOL drivers/i2c/i2c-core 0xd97f555f i2c_smbus_write_byte_data +EXPORT_SYMBOL drivers/i2c/i2c-core 0xe1c595d5 i2c_probe +EXPORT_SYMBOL drivers/i2c/i2c-core 0xe4e08cc6 i2c_master_send +EXPORT_SYMBOL drivers/i2c/i2c-core 0xe69633ea i2c_smbus_write_byte +EXPORT_SYMBOL drivers/i2c/i2c-core 0xfa83f1fe i2c_clients_command +EXPORT_SYMBOL drivers/i2c/i2c-core 0xfa8fe351 i2c_del_driver +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0428d633 hpsb_make_writepacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x049abdd1 hpsb_unregister_highlevel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0b234c4e dma_prog_region_alloc +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0b7a2edb hpsb_read +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0c6da941 csr1212_release_keyval +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0c75232d hpsb_free_tlabel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x0e5a659c csr1212_new_directory +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x1197b213 hpsb_node_write +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x12ee6828 hpsb_register_addrspace +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x13b4a268 csr1212_attach_keyval_to_directory +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x158ac548 dma_region_offset_to_bus +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x19f1f97b csr1212_parse_keyval +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x1c4fa3e4 hpsb_node_fill_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x1eb1bde3 hpsb_packet_received +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x25fbeb4c hpsb_register_highlevel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x262bc01e hpsb_iso_stop +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x2956fad8 hpsb_selfid_received +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x2dd29f75 csr1212_read +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x2ebf6e5a dma_prog_region_init +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x40281746 hpsb_packet_success +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x478c1518 hpsb_make_readpacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x4790f0f1 hpsb_iso_recv_unlisten_channel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x4ef15d4f hpsb_bus_reset +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x4f4aeb57 hpsb_iso_recv_release_packets +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x51d547b0 hpsb_get_tlabel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x5283e839 hpsb_iso_recv_listen_channel +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x53b2bccc hpsb_make_phypacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x5978a496 hpsb_unregister_protocol +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x5e52389c hpsb_free_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x606d6a0b hpsb_protocol_class +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x672ad148 dma_region_sync_for_device +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x68bdf951 hpsb_add_host +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x6d7de354 hpsb_iso_wake +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x74b4449b hpsb_iso_xmit_sync +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x76bc1a5c dma_region_free +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x79530b08 csr1212_get_keyval +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x7d21ba8a hpsb_send_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x802d76fa hpsb_make_streampacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x81db99da hpsb_iso_recv_flush +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x8879f8f0 dma_region_sync_for_cpu +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x88ab873e hpsb_iso_xmit_queue_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x8ec2b312 dma_region_alloc +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x9530b20c hpsb_packet_sent +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x95cd109a hpsb_selfid_complete +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x9b167936 hpsb_iso_recv_set_channel_mask +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0x9bd57a42 hpsb_unregister_addrspace +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xa0ccf3b3 hpsb_iso_packet_received +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xa92ccd09 dma_region_mmap +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xaec9368b hpsb_update_config_rom_image +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xaf1c5440 hpsb_resume_host +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xafedf7e1 hpsb_iso_recv_init +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xb2b2c7a1 hpsb_destroy_hostinfo +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xb5f090b2 hpsb_remove_host +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xbad29a07 hpsb_set_hostinfo_key +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xbd6a73f8 hpsb_iso_packet_sent +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xc3f909b1 hpsb_get_hostinfo +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xc4c32ab3 hpsb_allocate_and_register_addrspace +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xc5c5f782 hpsb_make_lock64packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xc669a4d3 csr1212_detach_keyval_from_directory +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xcd9e772b dma_prog_region_free +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xcff18917 hpsb_read_cycle_timer +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xd0a2cb3f hpsb_update_config_rom +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xd839d8f3 hpsb_iso_xmit_init +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xdade9c86 hpsb_write +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xdaf0a3b2 hpsb_make_lockpacket +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xe17d4ef3 hpsb_reset_bus +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xe4189dc7 __hpsb_register_protocol +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xe6e46c46 hpsb_iso_shutdown +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xe9fadca4 hpsb_set_packet_complete_task +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xea4152ff dma_region_init +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xee87e51d hpsb_iso_n_ready +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xf0d9960b hpsb_iso_xmit_start +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xf53a55ca hpsb_set_hostinfo +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xf6531ee9 hpsb_get_hostinfo_bykey +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xf79b92ab hpsb_alloc_packet +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xfba57f51 hpsb_speedto_str +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xfdbc5ab2 hpsb_iso_recv_start +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xfe093883 hpsb_alloc_host +EXPORT_SYMBOL drivers/ieee1394/ieee1394 0xff6c8d3f hpsb_create_hostinfo +EXPORT_SYMBOL drivers/ieee1394/ohci1394 0x0d4fe9d5 ohci1394_stop_context +EXPORT_SYMBOL drivers/ieee1394/ohci1394 0xa0293c47 ohci1394_unregister_iso_tasklet +EXPORT_SYMBOL drivers/ieee1394/ohci1394 0xb37ab086 ohci1394_init_iso_tasklet +EXPORT_SYMBOL drivers/ieee1394/ohci1394 0xbf186416 ohci1394_register_iso_tasklet +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0x465abc1d rdma_translate_ip +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0x71de06c2 rdma_addr_register_client +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0xbe81bb46 rdma_addr_unregister_client +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0xc4a5ba2b rdma_addr_cancel +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0xcfdf4b0c rdma_resolve_ip +EXPORT_SYMBOL drivers/infiniband/core/ib_addr 0xe362de74 rdma_copy_addr +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x2c89379f ib_send_cm_apr +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x2ead2ef4 ib_send_cm_sidr_req +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x40137a98 ib_cm_listen +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x42788db5 cm_class +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x4364abbd ib_create_cm_id +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x4ec838ab ib_cm_init_qp_attr +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x500ed67a ib_cm_notify +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x53dd7554 ib_send_cm_drep +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x5fd77eaa ib_send_cm_rep +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x7ae669d7 ib_send_cm_sidr_rep +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x7c00d5c1 ib_send_cm_dreq +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x7fe02918 ib_send_cm_req +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0x8f459ed4 ib_send_cm_rej +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0xb06ec358 ib_destroy_cm_id +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0xb1ecb93a ib_send_cm_lap +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0xec439551 ib_send_cm_mra +EXPORT_SYMBOL drivers/infiniband/core/ib_cm 0xf98a0c2f ib_send_cm_rtu +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x06830b9a ib_pack +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x0964c4da ib_modify_cq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x0b248c8d ib_find_cached_gid +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x0f957906 ib_query_pkey +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x10122270 ib_destroy_cq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x1271c09a ib_create_fmr_pool +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x1921fc61 ib_query_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x1e491a04 ib_unmap_fmr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x1f58ecc1 ib_get_cached_pkey +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x231a6e93 ib_alloc_fast_reg_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x259834f1 ib_init_ah_from_wc +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x2b8f6d54 ib_get_cached_lmc +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x3506abbb ib_set_client_data +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x36848662 ib_register_event_handler +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x373c6da1 ib_detach_mcast +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x3b5e707b ib_query_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x3eb9d53f ib_query_srq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x3f7567fd ib_rate_to_mult +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x4432c666 ib_rereg_phys_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x474ca838 ib_register_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x588a0061 ib_dealloc_pd +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x592ca5ce ib_create_srq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x62ae14cd ib_umem_release +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x699ff3b6 ib_destroy_fmr_pool +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x6a2bb8f9 ib_destroy_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x6b10f6ab ib_modify_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x704e804b ib_dereg_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x7235ee5d ib_destroy_ah +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x728d4eea ib_modify_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x731b6898 ib_alloc_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x735ea645 ib_flush_fmr_pool +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x753191e7 ib_fmr_pool_map_phys +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x78b45481 ib_create_ah +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x7967e26e ib_dealloc_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x7cf9419d ib_unregister_client +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x855a57ca ib_find_cached_pkey +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x856dc8ae ib_get_dma_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x8640eaeb ib_modify_qp_is_ok +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x86dc4a4c ib_create_ah_from_wc +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x87b614d8 ib_ud_header_pack +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x907707a5 ib_umem_page_count +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x95b6837c ib_create_cq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x96ce6c46 rdma_node_get_transport +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x99a2094a ib_dealloc_mw +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0x9d804fa1 mult_to_ib_rate +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xa17c4d91 ib_query_ah +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xa5984d7b ib_alloc_pd +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xa73cb4ca ib_alloc_mw +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xab693bd0 ib_dealloc_fmr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xadd9225d ib_get_client_data +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xb07c55e4 ib_dispatch_event +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xb3004b57 ib_modify_ah +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xb774bb9f ib_reg_phys_mr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xb7b1f331 ib_query_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xbc1f0063 ib_find_gid +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xc0e27f25 ib_destroy_srq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xcabf41af ib_alloc_fmr +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xd17ba9d1 ib_ud_header_init +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xd77f8f39 ib_modify_srq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xd93d3258 ib_attach_mcast +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xdc93a1f7 ib_unregister_device +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xddc775a0 ib_query_port +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xdeda17d2 ib_get_cached_gid +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xe3374fd3 ib_free_fast_reg_page_list +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xe44a6d2b ib_unregister_event_handler +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xe4b25a7c ib_find_pkey +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xe9ba86dd ib_alloc_fast_reg_page_list +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xe9fd8052 ib_modify_port +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xed5ed015 ib_resize_cq +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xee72ba70 ib_register_client +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf2d2bcae ib_query_gid +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf36498b9 ib_ud_header_unpack +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf3e1ace5 ib_create_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf57b2598 ib_fmr_pool_unmap +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf96fc9de ib_unpack +EXPORT_SYMBOL drivers/infiniband/core/ib_core 0xf9831468 ib_umem_get +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x0fc9cca2 ib_modify_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x267035d0 ib_register_mad_snoop +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x3750239d ib_process_mad_wc +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x4ac70f4f ib_unregister_mad_agent +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x52d45043 ib_create_send_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x56343a94 ib_redirect_mad_qp +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x6b63e17b ib_cancel_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x6ef787ed ib_response_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x6f077fcf ib_get_mad_data_offset +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0x7b5d4b7a ib_is_mad_class_rmpp +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0xb13fd774 ib_get_rmpp_segment +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0xe06ea7bd ib_register_mad_agent +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0xe0916d6b ib_post_send_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0xf1109a13 ib_free_send_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_mad 0xf6ac6a5d ib_free_recv_mad +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x16199856 ib_sa_register_client +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x1f8df4ab ib_init_ah_from_path +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x512ba124 ib_sa_unregister_client +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x576fdbac ib_sa_free_multicast +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0x8c0388fc ib_sa_get_mcmember_rec +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0xa3a2ff6e ib_sa_cancel_query +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0xa487a41c ib_sa_service_rec_query +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0xb99bf08c ib_sa_path_rec_get +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0xe79e5753 ib_init_ah_from_mcmember +EXPORT_SYMBOL drivers/infiniband/core/ib_sa 0xfae37340 ib_sa_join_multicast +EXPORT_SYMBOL drivers/infiniband/core/ib_uverbs 0x02f847bc ib_copy_path_rec_from_user +EXPORT_SYMBOL drivers/infiniband/core/ib_uverbs 0x07cf5a51 ib_copy_ah_attr_to_user +EXPORT_SYMBOL drivers/infiniband/core/ib_uverbs 0x18382f6a ib_copy_path_rec_to_user +EXPORT_SYMBOL drivers/infiniband/core/ib_uverbs 0x184f3575 ib_copy_qp_attr_to_user +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x024070f3 iw_cm_init_qp_attr +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x0fe2d77b iw_cm_disconnect +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x6e929c50 iw_create_cm_id +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0x7c9da8b4 iw_cm_accept +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0xb0d99b2d iw_cm_reject +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0xbf424f07 iw_cm_listen +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0xd21d5d07 iw_cm_connect +EXPORT_SYMBOL drivers/infiniband/core/iw_cm 0xdab98fa1 iw_destroy_cm_id +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x0deed028 rdma_init_qp_attr +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x0e26f252 rdma_reject +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x153389fe rdma_resolve_route +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x1f31eea0 rdma_leave_multicast +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x4528432e rdma_join_multicast +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x4a4c7dbb rdma_resolve_addr +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x56070c87 rdma_connect +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x6d1da4f4 rdma_create_id +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x72749340 rdma_listen +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x921170de rdma_create_qp +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0x9f985a83 rdma_destroy_id +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xa1ad4b53 rdma_set_service_type +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xa298ad31 rdma_set_ib_paths +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xa53ace18 rdma_bind_addr +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xdd2835e2 rdma_accept +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xe0a9dd32 rdma_disconnect +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xe46e0fb6 rdma_notify +EXPORT_SYMBOL drivers/infiniband/core/rdma_cm 0xe85d17f5 rdma_destroy_qp +EXPORT_SYMBOL drivers/input/gameport/gameport 0x2abd60a7 gameport_set_phys +EXPORT_SYMBOL drivers/input/gameport/gameport 0x479f6b03 __gameport_register_driver +EXPORT_SYMBOL drivers/input/gameport/gameport 0x90cadb26 gameport_stop_polling +EXPORT_SYMBOL drivers/input/gameport/gameport 0x94ea3ccd __gameport_register_port +EXPORT_SYMBOL drivers/input/gameport/gameport 0x9e166883 gameport_start_polling +EXPORT_SYMBOL drivers/input/gameport/gameport 0xa693b497 gameport_close +EXPORT_SYMBOL drivers/input/gameport/gameport 0xc4b07247 gameport_unregister_driver +EXPORT_SYMBOL drivers/input/gameport/gameport 0xcf51c759 gameport_unregister_port +EXPORT_SYMBOL drivers/input/gameport/gameport 0xdb8de8ed gameport_open +EXPORT_SYMBOL drivers/input/input-polldev 0x2001320b input_unregister_polled_device +EXPORT_SYMBOL drivers/input/input-polldev 0x471db174 input_register_polled_device +EXPORT_SYMBOL drivers/input/input-polldev 0x8820049f input_free_polled_device +EXPORT_SYMBOL drivers/input/input-polldev 0xd7d51bc6 input_allocate_polled_device +EXPORT_SYMBOL drivers/isdn/capi/capifs 0x2c54c957 capifs_free_ncci +EXPORT_SYMBOL drivers/isdn/capi/capifs 0xd0bc06ce capifs_new_ncci +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x04403fcf unregister_capi_driver +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x063083d1 capi_ctr_handle_message +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x14f2aa5a capi20_get_version +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x2b8eab1f capilib_free_ncci +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x2baa6586 capilib_new_ncci +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x31c24aa4 capi20_isinstalled +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x3eb76e1f capi_ctr_reseted +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x3efa95b8 capi_ctr_suspend_output +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x47d3fc51 capi_info2str +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x47dbfa0a capi_message2str +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x50b33ca4 capi_cmsg2message +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x56d99518 capi20_set_callback +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x6057c6f3 capi_message2cmsg +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x62e32d43 capilib_data_b3_conf +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x71e8d5ba capilib_data_b3_req +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x788d398c capi_cmsg2str +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x7a33596c capi20_get_serial +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x7e6f1307 capi20_get_manufacturer +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x8f699913 capilib_release +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x8f71ada9 capi20_release +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x9b37a67d attach_capi_ctr +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0x9f823278 register_capi_driver +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xaa165d27 capilib_release_appl +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xada5fb07 capi20_put_message +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xb19fda8d capi_cmd2str +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xb60e5e5f capi_cmsg_header +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xc5327ee3 capi20_register +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xd422510f detach_capi_ctr +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xe19a11ac capi20_get_profile +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xe46ddddd capi_ctr_ready +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xe9f62f29 cdebbuf_free +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xed061606 capi20_manufacturer +EXPORT_SYMBOL drivers/isdn/capi/kernelcapi 0xfcbd8c6a capi_ctr_resume_output +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x0c083cad b1_load_config +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x1c6f14fe avmcard_dma_free +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x6255dd36 b1ctl_read_proc +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x6860d3c8 b1_free_card +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x6c2cad8c b1_load_t4file +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x7bcd36e0 b1_parse_version +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x845e81f1 b1_send_message +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x85f09690 b1_irq_table +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x8cf25b66 b1_reset_ctr +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0x96f9d2f4 b1_interrupt +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xab4804bd b1_alloc_card +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xac12bf96 b1_release_appl +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xbb61030d b1_register_appl +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xd9cea233 b1_loaded +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xddba37dd b1_load_firmware +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xdfd28376 b1_detect +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xecc24205 b1_getrevision +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1 0xece37f1e avmcard_dma_alloc +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x15a81ce9 b1dma_register_appl +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x22416f8f t1pci_detect +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x2a386384 b1dma_interrupt +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x36813403 b1dma_load_firmware +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x49565182 b1pciv4_detect +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x68cab23c b1dma_reset +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0x810f174a b1dma_release_appl +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0xb0e19889 b1dma_send_message +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0xccabd7da b1dmactl_read_proc +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1dma 0xed04740c b1dma_reset_ctr +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1pcmcia 0x29562993 b1pcmcia_delcard +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1pcmcia 0xaec3240e b1pcmcia_addcard_m1 +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1pcmcia 0xea620116 b1pcmcia_addcard_m2 +EXPORT_SYMBOL drivers/isdn/hardware/avm/b1pcmcia 0xf14bf8b1 b1pcmcia_addcard_b1 +EXPORT_SYMBOL drivers/isdn/hardware/eicon/divadidd 0x2974ead1 DIVA_DIDD_Read +EXPORT_SYMBOL drivers/isdn/hardware/eicon/divadidd 0x9767d6b0 proc_net_eicon +EXPORT_SYMBOL drivers/isdn/hardware/mISDN/hfcmulti 0x5293ed86 plx_lock +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x07f4f2ce hisax_unregister +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x148f0c99 FsmFree +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x2844a899 FsmInitTimer +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x93a64734 FsmChangeState +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0x9df0cd27 FsmEvent +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xb071ba1a hisax_init_pcmcia +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xc0c558f9 FsmRestartTimer +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xd94696e8 FsmDelTimer +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xee93522c hisax_register +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xf0a16657 FsmNew +EXPORT_SYMBOL drivers/isdn/hisax/hisax 0xfc27303b HiSax_closecard +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0x02161f1f isac_irq +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0x20b32ae1 isacsx_irq +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0x26f9f0fd isacsx_setup +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0x3f3b323a isac_d_l2l1 +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0xf20e25fb isac_init +EXPORT_SYMBOL drivers/isdn/hisax/hisax_isac 0xfa75da48 isac_setup +EXPORT_SYMBOL drivers/isdn/hisax/isdnhdlc 0x1ee629e2 isdnhdlc_rcv_init +EXPORT_SYMBOL drivers/isdn/hisax/isdnhdlc 0x95aed401 isdnhdlc_decode +EXPORT_SYMBOL drivers/isdn/hisax/isdnhdlc 0x9ffc8215 isdnhdlc_out_init +EXPORT_SYMBOL drivers/isdn/hisax/isdnhdlc 0xf5c8131d isdnhdlc_encode +EXPORT_SYMBOL drivers/isdn/i4l/isdn 0x031110ee isdn_ppp_register_compressor +EXPORT_SYMBOL drivers/isdn/i4l/isdn 0x55ac72f2 isdn_ppp_unregister_compressor +EXPORT_SYMBOL drivers/isdn/i4l/isdn 0xc44258d8 register_isdn +EXPORT_SYMBOL drivers/isdn/i4l/isdn 0xfa06820f isdn_register_divert +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x0f662ec1 mISDN_register_Bprotocol +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x2348cc3c mISDN_FsmFree +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x3e5c383a dchannel_senddata +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x3ea336fd mISDN_FsmAddTimer +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x429129f2 mISDN_FsmRestartTimer +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x4a441a3c create_l1 +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x50c2230c mISDN_FsmChangeState +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x5456a7ae mISDN_register_device +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x6b5b72fe recv_Dchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x8316b46a mISDN_freedchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x852819b0 mISDN_initbchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x8ac129fb recv_Dchannel_skb +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x8b5a5721 mISDN_unregister_device +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x8e01b874 queue_ch_frame +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x93a91da3 confirm_Bsend +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x9632f7f9 recv_Bchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x96653ee4 l1_event +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0x98d35fb2 bchannel_senddata +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xab78d973 mISDN_freebchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xace35cae mISDN_FsmDelTimer +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xae74e58a recv_Bchannel_skb +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xb1e52f0e mISDN_initdchannel +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xc1a13e2f get_next_dframe +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xd5145151 mISDN_FsmEvent +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xd593cf94 mISDN_unregister_Bprotocol +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xd9a7fbfd mISDN_FsmInitTimer +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xf9e7832f mISDN_FsmNew +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_core 0xfbad0b3a get_next_bframe +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_dsp 0x4c2ec443 mISDN_dsp_element_register +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_dsp 0x60721da7 dsp_audio_law_to_s32 +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_dsp 0xa215f1b2 dsp_audio_s16_to_law +EXPORT_SYMBOL drivers/isdn/mISDN/mISDN_dsp 0xd3a023b8 mISDN_dsp_element_unregister +EXPORT_SYMBOL drivers/md/dm-log 0x4880c264 dm_dirty_log_destroy +EXPORT_SYMBOL drivers/md/dm-log 0x644b6a5a dm_dirty_log_create +EXPORT_SYMBOL drivers/md/dm-log 0xbf2dc12e dm_dirty_log_type_unregister +EXPORT_SYMBOL drivers/md/dm-log 0xd7385f07 dm_dirty_log_type_register +EXPORT_SYMBOL drivers/md/dm-mod 0x003bed6e dm_table_unplug_all +EXPORT_SYMBOL drivers/md/dm-mod 0x00e3d04b dm_kcopyd_client_destroy +EXPORT_SYMBOL drivers/md/dm-mod 0x0dea331b dm_put_device +EXPORT_SYMBOL drivers/md/dm-mod 0x1a1d7bed dm_io_client_create +EXPORT_SYMBOL drivers/md/dm-mod 0x2eb9a50a dm_table_get_md +EXPORT_SYMBOL drivers/md/dm-mod 0x6694edb0 dm_io +EXPORT_SYMBOL drivers/md/dm-mod 0x68e1d866 dm_table_get_size +EXPORT_SYMBOL drivers/md/dm-mod 0x810eb350 dm_get_device +EXPORT_SYMBOL drivers/md/dm-mod 0x82f65633 dm_io_client_resize +EXPORT_SYMBOL drivers/md/dm-mod 0x8ae69d26 dm_kcopyd_copy +EXPORT_SYMBOL drivers/md/dm-mod 0x8f9f74ff dm_table_get +EXPORT_SYMBOL drivers/md/dm-mod 0x954c8af3 dm_io_client_destroy +EXPORT_SYMBOL drivers/md/dm-mod 0x99f61493 dm_kcopyd_client_create +EXPORT_SYMBOL drivers/md/dm-mod 0x9e8a1636 dm_table_put +EXPORT_SYMBOL drivers/md/dm-mod 0xbaa86806 dm_unregister_target +EXPORT_SYMBOL drivers/md/dm-mod 0xc01512a1 dm_table_event +EXPORT_SYMBOL drivers/md/dm-mod 0xc79bcd36 dm_vcalloc +EXPORT_SYMBOL drivers/md/dm-mod 0xe98743a1 dm_register_target +EXPORT_SYMBOL drivers/md/dm-mod 0xebffc4a0 dm_table_get_mode +EXPORT_SYMBOL drivers/md/dm-mod 0xf6d4b659 dm_get_mapinfo +EXPORT_SYMBOL drivers/md/md-mod 0x13e24e1a md_wakeup_thread +EXPORT_SYMBOL drivers/md/md-mod 0x41e9596e md_write_start +EXPORT_SYMBOL drivers/md/md-mod 0x6661b97c bitmap_start_sync +EXPORT_SYMBOL drivers/md/md-mod 0x6cebe08d md_done_sync +EXPORT_SYMBOL drivers/md/md-mod 0x6e4bf850 bitmap_unplug +EXPORT_SYMBOL drivers/md/md-mod 0x79131fe0 register_md_personality +EXPORT_SYMBOL drivers/md/md-mod 0x84659205 md_check_recovery +EXPORT_SYMBOL drivers/md/md-mod 0x915132f0 md_write_end +EXPORT_SYMBOL drivers/md/md-mod 0x9a713c99 md_register_thread +EXPORT_SYMBOL drivers/md/md-mod 0x9faed9d0 bitmap_startwrite +EXPORT_SYMBOL drivers/md/md-mod 0xb77a3b41 bitmap_end_sync +EXPORT_SYMBOL drivers/md/md-mod 0xb8e75239 md_wait_for_blocked_rdev +EXPORT_SYMBOL drivers/md/md-mod 0xdc231cc7 unregister_md_personality +EXPORT_SYMBOL drivers/md/md-mod 0xe2821d25 md_error +EXPORT_SYMBOL drivers/md/md-mod 0xe48eedcf bitmap_cond_end_sync +EXPORT_SYMBOL drivers/md/md-mod 0xe79ced82 bitmap_close_sync +EXPORT_SYMBOL drivers/md/md-mod 0xf182bcb7 bitmap_endwrite +EXPORT_SYMBOL drivers/md/md-mod 0xf4e572b6 md_unregister_thread +EXPORT_SYMBOL drivers/media/common/tuners/mt2060 0x802a6a6c mt2060_attach +EXPORT_SYMBOL drivers/media/common/tuners/mt2131 0x76163772 mt2131_attach +EXPORT_SYMBOL drivers/media/common/tuners/mt2266 0x6cb35daf mt2266_attach +EXPORT_SYMBOL drivers/media/common/tuners/mxl5005s 0x926da07a mxl5005s_attach +EXPORT_SYMBOL drivers/media/common/tuners/qt1010 0x69b2f61c qt1010_attach +EXPORT_SYMBOL drivers/media/common/tuners/tuner-types 0x0cb4b189 tuners +EXPORT_SYMBOL drivers/media/common/tuners/tuner-types 0xc2821775 tuner_count +EXPORT_SYMBOL drivers/media/common/tuners/tuner-xc2028 0xe82039d3 xc2028_attach +EXPORT_SYMBOL drivers/media/common/tuners/xc5000 0xe7dfb692 xc5000_attach +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x19d93b07 flexcop_wan_set_speed +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x2400fd97 flexcop_device_kmalloc +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x3d0c7010 flexcop_dump_reg +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x3f953981 flexcop_eeprom_check_mac_addr +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x514586ed flexcop_device_initialize +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x5fe810ae flexcop_sram_set_dest +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x673e04e9 flexcop_dma_control_timer_irq +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x7e70da54 flexcop_dma_allocate +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0x84f88350 flexcop_dma_free +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xad8832c3 flexcop_dma_control_size_irq +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xafefe471 flexcop_device_kfree +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xb30f12b0 flexcop_dma_config_timer +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xb66848c4 flexcop_device_exit +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xc5559095 flexcop_dma_config +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xce1da88d flexcop_dma_xfer_control +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xda431c8f flexcop_i2c_request +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xdae6d364 flexcop_pass_dmx_packets +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xdbf919b5 flexcop_sram_ctrl +EXPORT_SYMBOL drivers/media/dvb/b2c2/b2c2-flexcop 0xfacb36bd flexcop_pass_dmx_data +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0x5ce4e38b bt878_stop +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0x6d59c988 bt878_start +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0xabe7cdc2 bt878_device_control +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0xd5d0bdef bt878_num +EXPORT_SYMBOL drivers/media/dvb/bt8xx/bt878 0xd9149ae7 bt878 +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x396fadc6 dst_attach +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x6a944033 read_dst +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x7a9c6b00 dst_error_recovery +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x9738caf5 dst_pio_disable +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0x9f935995 rdc_reset_state +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0xa5886aca write_dst +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0xb3e88cba dst_error_bailout +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0xbabe6726 dst_wait_dst_ready +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0xcd385511 dst_comm_init +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst 0xe94b8c9c dst_check_sum +EXPORT_SYMBOL drivers/media/dvb/bt8xx/dst_ca 0x9a902048 dst_ca_attach +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x04751e94 dvb_ca_en50221_camchange_irq +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x0522643a dvb_ca_en50221_frda_irq +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x0c457c5c dvb_ringbuffer_flush_spinlock_wakeup +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x27c442da dvb_register_adapter +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x2d91ccd5 dvb_frontend_reinitialise +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x36c8ea1f dvb_frontend_sleep_until +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x36ee6a8d dvb_generic_ioctl +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x41dbd5c2 dvb_frontend_detach +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x4a1833cb dvb_net_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x4c3aa726 dvb_ca_en50221_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x4db3899f dvb_dmx_swfilter_packets +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x51f3767c dvb_ringbuffer_read +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x588fcdd7 dvb_generic_open +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x6988f784 dvb_ringbuffer_read_user +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x6baad588 dvb_generic_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x6d86d432 dvb_ca_en50221_camready_irq +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x74a5a698 dvb_filter_pes2ts_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x80e3832d dvb_filter_get_ac3info +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x8981f50e dvb_dmxdev_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x8b49a23f timeval_usec_diff +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0x926a9013 dvb_ca_en50221_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xac4ca1b0 intlog2 +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xb3538843 dvb_register_device +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xc14ee960 dvb_register_frontend +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xc324b69b dvb_dmx_swfilter_204 +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xc80754c1 dvb_dmx_release +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xcb89fc7d dvb_ringbuffer_free +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xcbb0fa2f dvb_unregister_device +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xcbfa9467 dvb_unregister_adapter +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xcca08cb5 dvb_ringbuffer_avail +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xcce0eeed dvb_ringbuffer_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xd16af7c8 dvb_net_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xd639b9bc dvb_ringbuffer_write +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xd7765e69 dvb_ringbuffer_empty +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xda72f1dd dvb_unregister_frontend +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xe5ae8707 intlog10 +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xee73de0a dvb_dmx_swfilter +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xf5523dbf dvb_dmxdev_init +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xf826deb0 dvb_filter_pes2ts +EXPORT_SYMBOL drivers/media/dvb/dvb-core/dvb-core 0xf86f20c5 dvb_dmx_init +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x123b460a dvb_usb_generic_write +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x15b79b40 dvb_usb_nec_rc_key_to_event +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x71d07d28 dvb_usb_device_init +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x7c37843c usb_cypress_load_firmware +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x8a412dc2 dvb_usb_get_hexline +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0x9cd69676 dvb_usb_generic_rw +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb 0xe63853cb dvb_usb_device_exit +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-af9005-remote 0x2edc4728 af9005_rc_keys +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-af9005-remote 0x75d47674 af9005_rc_decode +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-af9005-remote 0xd3383957 af9005_rc_keys_size +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x3b24ac0e dibusb_dib3000mc_frontend_attach +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x453e54ad dibusb_pid_filter +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x600dee9b dibusb_dib3000mc_tuner_attach +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x66c10282 dibusb2_0_power_ctrl +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x90c32ea9 dibusb_read_eeprom_byte +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0x93d5c8b4 dibusb_power_ctrl +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xb1b1eb62 dibusb_rc_query +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xb6264045 dibusb_streaming_ctrl +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xca64ae74 dibusb_pid_filter_ctrl +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xd4d3dddc dibusb_rc_keys +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xeb2055c5 dibusb_i2c_algo +EXPORT_SYMBOL drivers/media/dvb/dvb-usb/dvb-usb-dibusb-common 0xf3531d55 dibusb2_0_streaming_ctrl +EXPORT_SYMBOL drivers/media/dvb/frontends/au8522 0x2cc85018 au8522_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/bcm3510 0xa26586fd bcm3510_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/cx22700 0x6a32bf83 cx22700_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/cx22702 0xe18867aa cx22702_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/cx24110 0xe1df181e cx24110_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/cx24123 0x61cdd990 cx24123_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/cx24123 0xfff1acfc cx24123_get_tuner_i2c_adapter +EXPORT_SYMBOL drivers/media/dvb/frontends/dib0070 0xb0a7fdda dib0070_wbd_offset +EXPORT_SYMBOL drivers/media/dvb/frontends/dib0070 0xd3daf29a dib0070_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mb 0xee7cdb91 dib3000mb_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0x0411c931 dib3000mc_i2c_enumeration +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0x2e530589 dib3000mc_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0x44e678f1 dib3000mc_set_config +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0x818bae84 dib3000mc_pid_parse +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0xf683482f dib3000mc_pid_control +EXPORT_SYMBOL drivers/media/dvb/frontends/dib3000mc 0xfe0ff8f9 dib3000mc_get_tuner_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000m 0x4bb865b8 dib7000m_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000m 0xb7586a51 dib7000m_i2c_enumeration +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000m 0xbc21e602 dib7000m_get_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0x220c1264 dib7000p_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0x763641ef dib7000pc_detection +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0x7c60dcc2 dib7000p_i2c_enumeration +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0xb84d86c2 dib7000p_get_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0xc17e5363 dib7000p_set_gpio +EXPORT_SYMBOL drivers/media/dvb/frontends/dib7000p 0xefdc1cbe dib7000p_set_wbd_ref +EXPORT_SYMBOL drivers/media/dvb/frontends/dibx000_common 0x2417075f dibx000_init_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/dibx000_common 0xd9151fcb dibx000_get_i2c_adapter +EXPORT_SYMBOL drivers/media/dvb/frontends/dibx000_common 0xfe4f9a6f dibx000_exit_i2c_master +EXPORT_SYMBOL drivers/media/dvb/frontends/drx397xD 0x1e015655 drx397xD_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/dvb-pll 0x0c7552d5 dvb_pll_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/isl6405 0x10f1e93a isl6405_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/isl6421 0x87717867 isl6421_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/itd1000 0xc9913e31 itd1000_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/l64781 0xeb81b99a l64781_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/lgdt330x 0xa9ef4257 lgdt330x_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/lnbp21 0x2c9555ed lnbp21_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/mt312 0x93e429e4 mt312_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/mt352 0x5e2a0ea1 mt352_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/nxt200x 0xf6de9d04 nxt200x_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/nxt6000 0xa2ddaedb nxt6000_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/or51132 0x297fc326 or51132_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/or51211 0x7fa4a72c or51211_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/s5h1409 0xa4e2737b s5h1409_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/s5h1411 0x17abd4e6 s5h1411_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/s5h1420 0x454eab5e s5h1420_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/s5h1420 0xa26603fe s5h1420_get_tuner_i2c_adapter +EXPORT_SYMBOL drivers/media/dvb/frontends/sp8870 0xbc03e529 sp8870_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/sp887x 0x5f11d4b5 sp887x_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/stv0297 0x65f75d7a stv0297_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/stv0299 0x7c1e23d9 stv0299_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda10021 0x61378c2f tda10021_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda10023 0x44794fe3 tda10023_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda10048 0x4402de1c tda10048_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda1004x 0x2190d55c tda10046_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda1004x 0x5a602d86 tda10045_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda10086 0xb6fdc76e tda10086_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda8083 0xa84e499c tda8083_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tda826x 0xfee79f00 tda826x_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/tua6100 0xaddcc849 tua6100_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/ves1820 0x2bf3dbc4 ves1820_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/ves1x93 0x444bbcee ves1x93_attach +EXPORT_SYMBOL drivers/media/dvb/frontends/zl10353 0xf208ee85 zl10353_attach +EXPORT_SYMBOL drivers/media/dvb/ttpci/ttpci-eeprom 0x8839516f ttpci_eeprom_parse_mac +EXPORT_SYMBOL drivers/media/dvb/ttusb-dec/ttusbdecfe 0x9773ca7a ttusbdecfe_dvbt_attach +EXPORT_SYMBOL drivers/media/dvb/ttusb-dec/ttusbdecfe 0xbcb4cbb0 ttusbdecfe_dvbs_attach +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0x11dc4b6d bttv_gpio_enable +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0x2ac30048 bttv_sub_unregister +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0x8ecf4acc bttv_write_gpio +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0xbcf2d2fb bttv_read_gpio +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0xf0725e89 bttv_get_pcidev +EXPORT_SYMBOL drivers/media/video/bt8xx/bttv 0xf5d735dc bttv_sub_register +EXPORT_SYMBOL drivers/media/video/btcx-risc 0x495e4b0c btcx_calc_skips +EXPORT_SYMBOL drivers/media/video/btcx-risc 0x91b1cffb btcx_riscmem_alloc +EXPORT_SYMBOL drivers/media/video/btcx-risc 0xad2fe38b btcx_sort_clips +EXPORT_SYMBOL drivers/media/video/btcx-risc 0xc368f8e6 btcx_align +EXPORT_SYMBOL drivers/media/video/btcx-risc 0xcda0ded2 btcx_screen_clips +EXPORT_SYMBOL drivers/media/video/btcx-risc 0xee085e2c btcx_riscmem_free +EXPORT_SYMBOL drivers/media/video/cpia 0x8da9ad62 cpia_register_camera +EXPORT_SYMBOL drivers/media/video/cpia 0x9cc3595c cpia_unregister_camera +EXPORT_SYMBOL drivers/media/video/cx18/cx18 0x2cdea06d cx18_reset_ir_gpio +EXPORT_SYMBOL drivers/media/video/cx2341x 0x0224a947 cx2341x_update +EXPORT_SYMBOL drivers/media/video/cx2341x 0x3559ba71 cx2341x_ext_ctrls +EXPORT_SYMBOL drivers/media/video/cx2341x 0x8fdbede1 cx2341x_fill_defaults +EXPORT_SYMBOL drivers/media/video/cx2341x 0xcf8b77a4 cx2341x_mpeg_ctrls +EXPORT_SYMBOL drivers/media/video/cx2341x 0xde1da524 cx2341x_ctrl_query +EXPORT_SYMBOL drivers/media/video/cx2341x 0xeacc6fab cx2341x_ctrl_get_menu +EXPORT_SYMBOL drivers/media/video/cx2341x 0xfb8bd71f cx2341x_log_status +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0x07228018 cx23885_get_control +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0x1f9d7ab5 cx23885_video_mux +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0x383a0ae1 cx23885_set_freq +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0x8910c45b cx23885_enum_input +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0xbfa08473 cx23885_set_control +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0xe12fa84c cx23885_ctrl_query +EXPORT_SYMBOL drivers/media/video/cx23885/cx23885 0xfb885537 cx23885_user_ctrls +EXPORT_SYMBOL drivers/media/video/cx88/cx88-vp3054-i2c 0x34dafda5 vp3054_i2c_probe +EXPORT_SYMBOL drivers/media/video/cx88/cx88-vp3054-i2c 0x8270649e vp3054_i2c_remove +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0x56683629 cx88_video_mux +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0x733a2229 cx88_set_control +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0x7b21b296 cx88_set_freq +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0xac4e53b9 cx88_user_ctrls +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0xaea777cd cx88_get_control +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0xd0d8cbc6 cx88_enum_input +EXPORT_SYMBOL drivers/media/video/cx88/cx8800 0xd0f368ef cx8800_ctrl_query +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x00385a82 cx8802_unregister_driver +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x0073112d cx8802_buf_prepare +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x440c2508 cx8802_register_driver +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x4872fe68 cx8802_cancel_buffers +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0x51009162 cx8802_get_device +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0xa11af5ad cx8802_buf_queue +EXPORT_SYMBOL drivers/media/video/cx88/cx8802 0xd76ca09d cx8802_get_driver +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x0c27df63 cx88_set_stereo +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x0e624d12 cx88_free_buffer +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x0f535e62 cx88_risc_databuffer +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x17941b25 cx88_shutdown +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x2b6fc184 cx88_risc_buffer +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x3017d712 cx88_wakeup +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x31982517 cx88_core_get +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x347aecfb cx88_core_put +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x3c645094 cx88_ir_start +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x41752c3e cx88_ir_stop +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x42fa2631 cx88_risc_stopper +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x53b528a1 cx88_call_i2c_clients +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x61b2b94d cx88_get_stereo +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x6311fa2f cx88_set_tvaudio +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x6a02ff01 cx88_core_irq +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x7abbbda3 cx88_reset +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x7b5cdee1 cx88_tuner_callback +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x904b8696 cx88_audio_thread +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0x9b140fff cx88_sram_channels +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xa10fdd69 cx88_newstation +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xa6594439 cx88_set_scale +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xb47f6cda cx88_print_irqbits +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xb486f4a5 cx88_set_tvnorm +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xcdc6bab2 cx88_sram_channel_dump +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xe28f254a cx88_sram_channel_setup +EXPORT_SYMBOL drivers/media/video/cx88/cx88xx 0xfb276e82 cx88_vdev_init +EXPORT_SYMBOL drivers/media/video/em28xx/em28xx 0x13933f70 em28xx_unregister_extension +EXPORT_SYMBOL drivers/media/video/em28xx/em28xx 0x2f83d2f4 em28xx_register_extension +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x01939cc3 gspca_disconnect +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x02f6326e gspca_frame_add +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x0c6fedd7 gspca_auto_gain_n_exposure +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x11e8dadf gspca_resume +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x4132d23f gspca_dev_probe +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0x9670af2c gspca_debug +EXPORT_SYMBOL drivers/media/video/gspca/gspca_main 0xfcba1ad4 gspca_suspend +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x0538e449 ivtv_cards_lock +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x14f67530 ivtv_debug +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x1c2aa420 ivtv_vapi +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x3e553df3 ivtv_udma_setup +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x4d164a15 ivtv_udma_unmap +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x5be94161 ivtv_reset_ir_gpio +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x621a0d52 ivtv_cards +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x6b45222a ivtv_udma_prepare +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x70196ffb ivtv_cards_active +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x7f965b6c ivtv_set_irq_mask +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0x82f5c83b ivtv_udma_alloc +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0xa558da6d ivtv_vapi_result +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0xc0df6722 ivtv_api +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0xcd15415d ivtv_clear_irq_mask +EXPORT_SYMBOL drivers/media/video/ivtv/ivtv 0xe92992f0 ivtv_init_on_first_open +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x09f2ee38 saa7134_ts_register +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x1211df5d saa7134_devlist +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x21c1f4ec saa7134_set_dmabits +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x2611c782 saa7134_tvaudio_setmute +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x38ff2deb saa7134_i2c_call_clients +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x3cba7d8f saa7134_pgtable_alloc +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x3e3eeafa saa7134_set_gpio +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x4d614a2f saa7134_dmasound_init +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x7f6328e8 saa_dsp_writel +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x85593767 saa7134_tuner_callback +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x98af79c1 saa7134_boards +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0x9b440c46 saa7134_pgtable_free +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0xbb68df84 saa7134_dmasound_exit +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0xc072e34b saa7134_pgtable_build +EXPORT_SYMBOL drivers/media/video/saa7134/saa7134 0xe0e18d95 saa7134_ts_unregister +EXPORT_SYMBOL drivers/media/video/soc_camera 0x028c2e1a soc_camera_host_unregister +EXPORT_SYMBOL drivers/media/video/soc_camera 0x1453f678 soc_camera_video_stop +EXPORT_SYMBOL drivers/media/video/soc_camera 0x55930e29 soc_camera_video_start +EXPORT_SYMBOL drivers/media/video/soc_camera 0x60b80062 soc_camera_host_register +EXPORT_SYMBOL drivers/media/video/soc_camera 0xd3784769 soc_camera_device_register +EXPORT_SYMBOL drivers/media/video/soc_camera 0xefad99d5 soc_camera_device_unregister +EXPORT_SYMBOL drivers/media/video/tveeprom 0x17c01529 tveeprom_hauppauge_analog +EXPORT_SYMBOL drivers/media/video/tveeprom 0x520a750b tveeprom_read +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x139da847 usbvideo_register +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x16a2915c RingQueue_Dequeue +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x36b07bc5 usbvideo_DeinterlaceFrame +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x407a321c RingQueue_WakeUpInterruptible +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x5bb24860 usbvideo_TestPattern +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0x688e8812 usbvideo_AllocateDevice +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0xddecac6d RingQueue_Enqueue +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0xeba59f07 usbvideo_Deregister +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0xef1cf297 usbvideo_RegisterVideoDevice +EXPORT_SYMBOL drivers/media/video/usbvideo/usbvideo 0xf5011f67 RingQueue_Flush +EXPORT_SYMBOL drivers/media/video/v4l1-compat 0x6c44a0e6 v4l_compat_translate_ioctl +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x03165a85 v4l2_ctrl_get_menu +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x0dfb5e57 v4l2_prio_max +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x19c8e921 v4l2_i2c_attach +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x1c427ecb v4l2_ctrl_query_fill +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x26b0405b v4l2_chip_ident_i2c_client +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x2de2b633 v4l2_prio_check +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x2e9a955d v4l2_prio_close +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x42c8e001 v4l2_ctrl_next +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x57abfbd8 v4l2_chip_match_host +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x5fef1b4a v4l2_ctrl_query_fill_std +EXPORT_SYMBOL drivers/media/video/v4l2-common 0x942892ab v4l2_prio_open +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xb2d1e17e v4l2_prio_change +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xb3089592 v4l2_chip_match_i2c_client +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xc369097d v4l2_ctrl_check +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xd464e760 v4l2_ctrl_query_menu +EXPORT_SYMBOL drivers/media/video/v4l2-common 0xe330bce9 v4l2_prio_init +EXPORT_SYMBOL drivers/media/video/videobuf-dvb 0x271e3eb4 videobuf_dvb_register +EXPORT_SYMBOL drivers/media/video/videobuf-dvb 0xd8c944ea videobuf_dvb_unregister +EXPORT_SYMBOL drivers/media/video/videocodec 0x1cef83e6 videocodec_detach +EXPORT_SYMBOL drivers/media/video/videocodec 0x1fa1a848 videocodec_unregister +EXPORT_SYMBOL drivers/media/video/videocodec 0x7124aaa6 videocodec_attach +EXPORT_SYMBOL drivers/media/video/videocodec 0xb1088af6 videocodec_register +EXPORT_SYMBOL drivers/media/video/videodev 0x123959a1 v4l2_type_names +EXPORT_SYMBOL drivers/media/video/videodev 0x3adbd595 v4l2_field_names +EXPORT_SYMBOL drivers/media/video/videodev 0x52acb94a video_devdata +EXPORT_SYMBOL drivers/media/video/videodev 0x5ebefe4b v4l_printk_ioctl +EXPORT_SYMBOL drivers/media/video/videodev 0x68f61025 video_exclusive_open +EXPORT_SYMBOL drivers/media/video/videodev 0x9024b01b video_device_alloc +EXPORT_SYMBOL drivers/media/video/videodev 0x9437b34e video_unregister_device +EXPORT_SYMBOL drivers/media/video/videodev 0x9caf47ea video_usercopy +EXPORT_SYMBOL drivers/media/video/videodev 0xa6b7b2e4 video_exclusive_release +EXPORT_SYMBOL drivers/media/video/videodev 0xab644d95 video_device_release +EXPORT_SYMBOL drivers/media/video/videodev 0xd4dd549b video_register_device_index +EXPORT_SYMBOL drivers/media/video/videodev 0xe2b92059 v4l2_video_std_construct +EXPORT_SYMBOL drivers/media/video/videodev 0xf1604981 video_ioctl2 +EXPORT_SYMBOL drivers/media/video/videodev 0xf3251e7b v4l2_norm_to_name +EXPORT_SYMBOL drivers/media/video/videodev 0xffcc7636 video_register_device +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x027a83aa mpt_get_msg_frame +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x0cc3f95d mpt_config +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x105d4f47 mpt_add_sge +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x11a3872a mpt_HardResetHandler +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x3acf18a1 mpt_GetIocState +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x3b0fd5b9 mpt_print_ioc_summary +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x44bc642c mpt_put_msg_frame +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x4526289b mpt_event_deregister +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x4791682d mpt_put_msg_frame_hi_pri +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x7096a170 mpt_resume +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x70b8f845 mpt_send_handshake_request +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x7aa442a4 mpt_free_msg_frame +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x80051f59 mpt_verify_adapter +EXPORT_SYMBOL drivers/message/fusion/mptbase 0x9584940b mpt_alloc_fw_memory +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xb5cefc99 mpt_findImVolumes +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xb835d6ea mpt_event_register +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xba74b069 mpt_device_driver_register +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xc0e69f82 mpt_device_driver_deregister +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xc2fa3490 mptbase_sas_persist_operation +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xc47c22e8 mpt_deregister +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xd2714b19 mpt_free_fw_memory +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xd497351b mpt_reset_register +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xd9a92a75 mpt_reset_deregister +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xdd805159 ioc_list +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xe1b02806 mpt_attach +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xe5e23766 mpt_suspend +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xe5f15319 mpt_register +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xeb1193fc mpt_raid_phys_disk_pg0 +EXPORT_SYMBOL drivers/message/fusion/mptbase 0xf53283d2 mpt_detach +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x02e01774 mptscsih_scandv_complete +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x09b23d2d mptscsih_bios_param +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x145997d4 mptscsih_slave_destroy +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x1786badd mptscsih_io_done +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x2476a998 mptscsih_raid_id_to_num +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x36fa3412 mptscsih_dev_reset +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x410ed0b5 mptscsih_host_attrs +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x50252c41 mptscsih_host_reset +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x51eb3579 mptscsih_shutdown +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x53394b02 mptscsih_change_queue_depth +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x5a0b8d02 mptscsih_ioc_reset +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x764ddf1a mptscsih_timer_expired +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x84a16028 mptscsih_TMHandler +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x959baf25 mptscsih_info +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0x9e936429 mptscsih_taskmgmt_complete +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xa57fd7d2 mptscsih_is_phys_disk +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xac8e2232 mptscsih_abort +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xb0e3929c mptscsih_qcmd +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xcde48782 mptscsih_slave_configure +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xd04ecb38 mptscsih_suspend +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xd0672251 mptscsih_event_process +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xdeb5fed4 mptscsih_remove +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xeb86b652 mptscsih_bus_reset +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xf9843e7f mptscsih_resume +EXPORT_SYMBOL drivers/message/fusion/mptscsih 0xfe902918 mptscsih_proc_info +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x06ce7844 i2o_msg_get_wait +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x0db26b8f i2o_driver_notify_device_remove_all +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x1aba1919 i2o_parm_field_get +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x23520576 i2o_parm_table_get +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x260a3d8f i2o_parm_issue +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x2a843bef i2o_dump_message +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x34916206 i2o_status_get +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x35a0a446 i2o_msg_post_wait_mem +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x3ad6d0cf i2o_driver_register +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x3e589e94 i2o_driver_unregister +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x40800879 i2o_iop_find_device +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x42987e0b i2o_driver_notify_controller_remove_all +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x484a717b i2o_cntxt_list_get_ptr +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0x69d4cc55 i2o_device_claim +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xa9e72e5a i2o_cntxt_list_remove +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xad3452b3 i2o_cntxt_list_get +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xb4c00dcf i2o_controllers +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xb6043517 i2o_cntxt_list_add +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xb9fd230c i2o_find_iop +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xd4e1dd5d i2o_event_register +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xd6228d6e i2o_device_claim_release +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xe172b1ab i2o_driver_notify_device_add_all +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xf2643a49 i2o_exec_lct_get +EXPORT_SYMBOL drivers/message/i2o/i2o_core 0xf37fcea1 i2o_driver_notify_controller_add_all +EXPORT_SYMBOL drivers/mfd/htc-pasic3 0x255ff146 pasic3_write_register +EXPORT_SYMBOL drivers/mfd/htc-pasic3 0xee8dd864 pasic3_read_register +EXPORT_SYMBOL drivers/misc/ioc4 0x19d81ffd ioc4_register_submodule +EXPORT_SYMBOL drivers/misc/ioc4 0x4220d7c2 ioc4_unregister_submodule +EXPORT_SYMBOL drivers/misc/sony-laptop 0x5bb1e117 sony_pic_camera_command +EXPORT_SYMBOL drivers/misc/tifm_core 0x2d81c904 tifm_alloc_adapter +EXPORT_SYMBOL drivers/misc/tifm_core 0x38c39bad tifm_has_ms_pif +EXPORT_SYMBOL drivers/misc/tifm_core 0x3f09c79c tifm_alloc_device +EXPORT_SYMBOL drivers/misc/tifm_core 0x488bc82f tifm_unmap_sg +EXPORT_SYMBOL drivers/misc/tifm_core 0x6f0cdd25 tifm_eject +EXPORT_SYMBOL drivers/misc/tifm_core 0x8934dd37 tifm_remove_adapter +EXPORT_SYMBOL drivers/misc/tifm_core 0xa8c2ec46 tifm_queue_work +EXPORT_SYMBOL drivers/misc/tifm_core 0xb843f8e8 tifm_register_driver +EXPORT_SYMBOL drivers/misc/tifm_core 0xca563e37 tifm_free_device +EXPORT_SYMBOL drivers/misc/tifm_core 0xd12204a5 tifm_add_adapter +EXPORT_SYMBOL drivers/misc/tifm_core 0xd8fac6eb tifm_free_adapter +EXPORT_SYMBOL drivers/misc/tifm_core 0xdbdc7ff2 tifm_map_sg +EXPORT_SYMBOL drivers/misc/tifm_core 0xde47cc2b tifm_unregister_driver +EXPORT_SYMBOL drivers/mmc/card/mmc_block 0x814b2fdb mmc_cleanup_queue +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x1e0dc572 mmc_release_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x24ae9297 mmc_unregister_driver +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x24c0bdc2 mmc_register_driver +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x32ec7416 mmc_add_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x3fec2088 mmc_detect_change +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x411caf65 __mmc_claim_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x43149b02 mmc_free_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x45a3e863 mmc_align_data_size +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x694b74c2 mmc_request_done +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x8b42fd95 mmc_alloc_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0x9f786f06 mmc_wait_for_app_cmd +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xa216a59d mmc_resume_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xa84613ff mmc_set_data_timeout +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xabb4a513 mmc_remove_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xb0e161e0 mmc_wait_for_cmd +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xd8ff3d3c mmc_suspend_host +EXPORT_SYMBOL drivers/mmc/core/mmc_core 0xeb548bd6 mmc_wait_for_req +EXPORT_SYMBOL drivers/mtd/chips/cfi_util 0x1e4b389b cfi_varsize_frob +EXPORT_SYMBOL drivers/mtd/chips/cfi_util 0x3c1e14f3 cfi_fixup +EXPORT_SYMBOL drivers/mtd/chips/cfi_util 0xfc973538 cfi_read_pri +EXPORT_SYMBOL drivers/mtd/chips/chipreg 0x6d01b9fa map_destroy +EXPORT_SYMBOL drivers/mtd/chips/chipreg 0xb34366f0 do_map_probe +EXPORT_SYMBOL drivers/mtd/chips/chipreg 0xc9da98fe unregister_mtd_chip_driver +EXPORT_SYMBOL drivers/mtd/chips/chipreg 0xea12a65f register_mtd_chip_driver +EXPORT_SYMBOL drivers/mtd/chips/gen_probe 0x9b953f85 mtd_do_chip_probe +EXPORT_SYMBOL drivers/mtd/maps/map_funcs 0xf493222a simple_map_init +EXPORT_SYMBOL drivers/mtd/mtd 0xc5ea1aa7 add_mtd_partitions +EXPORT_SYMBOL drivers/mtd/mtd 0xf3edb1e3 del_mtd_partitions +EXPORT_SYMBOL drivers/mtd/mtdconcat 0x0f08418a mtd_concat_create +EXPORT_SYMBOL drivers/mtd/mtdconcat 0x3b32f920 mtd_concat_destroy +EXPORT_SYMBOL drivers/mtd/nand/nand 0x4a05f8be nand_scan_bbt +EXPORT_SYMBOL drivers/mtd/nand/nand 0xc3af03b0 nand_default_bbt +EXPORT_SYMBOL drivers/mtd/nand/nand_ecc 0x254f230c nand_calculate_ecc +EXPORT_SYMBOL drivers/mtd/nand/nand_ecc 0x87406d9d nand_correct_data +EXPORT_SYMBOL drivers/mtd/nand/nand_ids 0x836bdb72 nand_flash_ids +EXPORT_SYMBOL drivers/mtd/nand/nand_ids 0xa336feb7 nand_manuf_ids +EXPORT_SYMBOL drivers/mtd/onenand/onenand 0x9926269f onenand_default_bbt +EXPORT_SYMBOL drivers/mtd/onenand/onenand 0xda3a6e1b onenand_scan_bbt +EXPORT_SYMBOL drivers/net/8390 0x7d7e0dbc ei_interrupt +EXPORT_SYMBOL drivers/net/8390 0xc3a6fa20 __alloc_ei_netdev +EXPORT_SYMBOL drivers/net/8390 0xd06a7ab1 ei_close +EXPORT_SYMBOL drivers/net/8390 0xd9a4667c ei_open +EXPORT_SYMBOL drivers/net/8390 0xe239585a NS8390_init +EXPORT_SYMBOL drivers/net/8390 0xe37e150f ei_poll +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x4641bd7d arcnet_interrupt +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x65061363 arc_proto_default +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x6534792a arcnet_debug +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x743c7bd7 arc_proto_map +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x8a116e64 alloc_arcdev +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0x9d7a8702 arc_raw_proto +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0xa6d63a8b arcnet_unregister_proto +EXPORT_SYMBOL drivers/net/arcnet/arcnet 0xff6ced25 arc_bcast_proto +EXPORT_SYMBOL drivers/net/arcnet/com20020 0x26ceae0b com20020_check +EXPORT_SYMBOL drivers/net/arcnet/com20020 0xaf23de7e com20020_found +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x297f9ece cxgb3_alloc_stid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x4d1fdce6 t3_l2t_send_event +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x4fd25c1e cxgb3_unregister_client +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x51369cfc cxgb3_free_stid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x573ecd15 cxgb3_insert_tid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x6df7f87b cxgb3_ofld_send +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x6f553fe9 cxgb3_remove_tid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x708a0bbd t3_l2t_send_slow +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x7752dceb cxgb3_alloc_atid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x7817be94 cxgb3_queue_tid_release +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x81011c39 cxgb3_register_client +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x91bba536 t3_register_cpl_handler +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0x927cadda dev2t3cdev +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0xc4915e11 t3_l2e_free +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0xc5fed689 cxgb3_free_atid +EXPORT_SYMBOL drivers/net/cxgb3/cxgb3 0xc6e11690 t3_l2t_get +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0x05dc63af hdlcdrv_receiver +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0x4d6ed53a hdlcdrv_transmitter +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0x50374b81 hdlcdrv_arbitrate +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0x5a2bb698 hdlcdrv_register +EXPORT_SYMBOL drivers/net/hamradio/hdlcdrv 0xeec0d55a hdlcdrv_unregister +EXPORT_SYMBOL drivers/net/irda/sir-dev 0x0558ba06 sirdev_set_dtr_rts +EXPORT_SYMBOL drivers/net/irda/sir-dev 0x064e1bb9 sirdev_get_instance +EXPORT_SYMBOL drivers/net/irda/sir-dev 0x80c44fec sirdev_raw_read +EXPORT_SYMBOL drivers/net/irda/sir-dev 0x99d49b52 sirdev_put_instance +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xcc56a3c6 sirdev_receive +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xd18a5827 irda_register_dongle +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xd4e74ae9 sirdev_raw_write +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xee8e9615 irda_unregister_dongle +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xf13669c3 sirdev_write_complete +EXPORT_SYMBOL drivers/net/irda/sir-dev 0xf36e8d94 sirdev_set_dongle +EXPORT_SYMBOL drivers/net/mii 0x0f84ae31 mii_check_media +EXPORT_SYMBOL drivers/net/mii 0x41aa0dd9 mii_check_gmii_support +EXPORT_SYMBOL drivers/net/mii 0x7fda68bc generic_mii_ioctl +EXPORT_SYMBOL drivers/net/mii 0x856549cc mii_nway_restart +EXPORT_SYMBOL drivers/net/mii 0x9a94c089 mii_ethtool_gset +EXPORT_SYMBOL drivers/net/mii 0x9cd83215 mii_link_ok +EXPORT_SYMBOL drivers/net/mii 0xa6932822 mii_ethtool_sset +EXPORT_SYMBOL drivers/net/mii 0xcf15ed7f mii_check_link +EXPORT_SYMBOL drivers/net/phy/libphy 0x03b40f02 genphy_config_advert +EXPORT_SYMBOL drivers/net/phy/libphy 0x06f0db8e phy_read +EXPORT_SYMBOL drivers/net/phy/libphy 0x0d918fa3 genphy_config_aneg +EXPORT_SYMBOL drivers/net/phy/libphy 0x2ca8686e phy_print_status +EXPORT_SYMBOL drivers/net/phy/libphy 0x2e44dbc5 mdio_bus_type +EXPORT_SYMBOL drivers/net/phy/libphy 0x30015658 phy_start_interrupts +EXPORT_SYMBOL drivers/net/phy/libphy 0x35e0a8f2 phy_disconnect +EXPORT_SYMBOL drivers/net/phy/libphy 0x3e60c5f2 phy_scan_fixups +EXPORT_SYMBOL drivers/net/phy/libphy 0x5a98e0d3 phy_start +EXPORT_SYMBOL drivers/net/phy/libphy 0x5bd3ff73 phy_driver_unregister +EXPORT_SYMBOL drivers/net/phy/libphy 0x6d1b9f9a phy_ethtool_gset +EXPORT_SYMBOL drivers/net/phy/libphy 0x6f5953b6 phy_mii_ioctl +EXPORT_SYMBOL drivers/net/phy/libphy 0x7228436e phy_write +EXPORT_SYMBOL drivers/net/phy/libphy 0x7f02404b phy_stop +EXPORT_SYMBOL drivers/net/phy/libphy 0x87d97ea9 get_phy_id +EXPORT_SYMBOL drivers/net/phy/libphy 0x8d40cde0 mdiobus_unregister +EXPORT_SYMBOL drivers/net/phy/libphy 0x91c6086c phy_register_fixup +EXPORT_SYMBOL drivers/net/phy/libphy 0x97ddeef4 phy_device_create +EXPORT_SYMBOL drivers/net/phy/libphy 0x99c4f86c phy_attach +EXPORT_SYMBOL drivers/net/phy/libphy 0x9d36b938 mdiobus_register +EXPORT_SYMBOL drivers/net/phy/libphy 0xacdb2209 phy_stop_interrupts +EXPORT_SYMBOL drivers/net/phy/libphy 0xad74007c genphy_read_status +EXPORT_SYMBOL drivers/net/phy/libphy 0xb054b2b8 phy_connect +EXPORT_SYMBOL drivers/net/phy/libphy 0xb0f61aa4 phy_register_fixup_for_id +EXPORT_SYMBOL drivers/net/phy/libphy 0xb1d970ec phy_disable_interrupts +EXPORT_SYMBOL drivers/net/phy/libphy 0xba236fc2 phy_detach +EXPORT_SYMBOL drivers/net/phy/libphy 0xc748dadc phy_driver_register +EXPORT_SYMBOL drivers/net/phy/libphy 0xd3a042fb phy_start_aneg +EXPORT_SYMBOL drivers/net/phy/libphy 0xe4d1e473 genphy_update_link +EXPORT_SYMBOL drivers/net/phy/libphy 0xe99e73c7 phy_enable_interrupts +EXPORT_SYMBOL drivers/net/phy/libphy 0xf219d4b2 phy_ethtool_sset +EXPORT_SYMBOL drivers/net/phy/libphy 0xf339b4ae phy_register_fixup_for_uid +EXPORT_SYMBOL drivers/net/phy/libphy 0xfa1e9067 phy_sanitize_settings +EXPORT_SYMBOL drivers/net/phy/mdio-bitbang 0x024be098 free_mdio_bitbang +EXPORT_SYMBOL drivers/net/phy/mdio-bitbang 0xcd11f89d alloc_mdio_bitbang +EXPORT_SYMBOL drivers/net/ppp_generic 0x01101d5d ppp_output_wakeup +EXPORT_SYMBOL drivers/net/ppp_generic 0x043c0ee8 ppp_channel_index +EXPORT_SYMBOL drivers/net/ppp_generic 0x2b9d9dcc ppp_unregister_channel +EXPORT_SYMBOL drivers/net/ppp_generic 0x4aaba9a9 ppp_register_channel +EXPORT_SYMBOL drivers/net/ppp_generic 0x4ecd6cf9 ppp_unregister_compressor +EXPORT_SYMBOL drivers/net/ppp_generic 0xa5dba8be ppp_input +EXPORT_SYMBOL drivers/net/ppp_generic 0xebf42592 ppp_register_compressor +EXPORT_SYMBOL drivers/net/ppp_generic 0xf04df8b6 ppp_unit_number +EXPORT_SYMBOL drivers/net/ppp_generic 0xf486df6b ppp_input_error +EXPORT_SYMBOL drivers/net/pppox 0x389c00b7 pppox_ioctl +EXPORT_SYMBOL drivers/net/pppox 0x601719ab pppox_unbind_sock +EXPORT_SYMBOL drivers/net/pppox 0x9d0fc5ce register_pppox_proto +EXPORT_SYMBOL drivers/net/pppox 0xe0ff7a18 unregister_pppox_proto +EXPORT_SYMBOL drivers/net/slhc 0x0ff2b602 slhc_compress +EXPORT_SYMBOL drivers/net/slhc 0x23c8f257 slhc_uncompress +EXPORT_SYMBOL drivers/net/slhc 0xa63d85ab slhc_remember +EXPORT_SYMBOL drivers/net/slhc 0xb5ca1c46 slhc_free +EXPORT_SYMBOL drivers/net/slhc 0xdfc5169b slhc_init +EXPORT_SYMBOL drivers/net/slhc 0xe8794ce1 slhc_toss +EXPORT_SYMBOL drivers/net/sungem_phy 0x6e1bda5a mii_phy_probe +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0x152a875a tms380tr_close +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0x518fcbfb tms380tr_interrupt +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0x96f51ab6 tmsdev_term +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0x98d743a8 tmsdev_init +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0xa27a5738 tms380tr_open +EXPORT_SYMBOL drivers/net/tokenring/tms380tr 0xd2328794 tms380tr_wait +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0x38da4725 cycx_intr +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0x62be23ea cycx_setup +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0x66a4c4e6 cycx_down +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0x968458a6 cycx_peek +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0xb6f383de cycx_poke +EXPORT_SYMBOL drivers/net/wan/cycx_drv 0xfe7cd576 cycx_exec +EXPORT_SYMBOL drivers/net/wan/hdlc 0x7704ce78 unregister_hdlc_protocol +EXPORT_SYMBOL drivers/net/wan/hdlc 0x89131c79 unregister_hdlc_device +EXPORT_SYMBOL drivers/net/wan/hdlc 0x89a18b71 attach_hdlc_protocol +EXPORT_SYMBOL drivers/net/wan/hdlc 0x91303d3b detach_hdlc_protocol +EXPORT_SYMBOL drivers/net/wan/hdlc 0x9e8bc109 hdlc_open +EXPORT_SYMBOL drivers/net/wan/hdlc 0xeb4e70e2 hdlc_close +EXPORT_SYMBOL drivers/net/wan/hdlc 0xef57f97a hdlc_ioctl +EXPORT_SYMBOL drivers/net/wan/hdlc 0xf2d1f6f5 register_hdlc_protocol +EXPORT_SYMBOL drivers/net/wan/hdlc 0xf31f1c04 alloc_hdlcdev +EXPORT_SYMBOL drivers/net/wan/syncppp 0x1b0272eb sppp_do_ioctl +EXPORT_SYMBOL drivers/net/wan/syncppp 0x5d5888de sppp_close +EXPORT_SYMBOL drivers/net/wan/syncppp 0x6243989f sppp_open +EXPORT_SYMBOL drivers/net/wan/syncppp 0x9abf5a92 sppp_attach +EXPORT_SYMBOL drivers/net/wan/syncppp 0x9b560dfa sppp_reopen +EXPORT_SYMBOL drivers/net/wan/syncppp 0xdcc0f81d sppp_detach +EXPORT_SYMBOL drivers/net/wireless/airo 0x04700d7a init_airo_card +EXPORT_SYMBOL drivers/net/wireless/airo 0x1bc3262e stop_airo_card +EXPORT_SYMBOL drivers/net/wireless/airo 0xfea86502 reset_airo_card +EXPORT_SYMBOL drivers/net/wireless/atmel 0x0f8d94a7 stop_atmel_card +EXPORT_SYMBOL drivers/net/wireless/atmel 0x4f8a67c4 init_atmel_card +EXPORT_SYMBOL drivers/net/wireless/atmel 0xf06866b1 atmel_open +EXPORT_SYMBOL drivers/net/wireless/hermes 0x4196c38b hermes_write_ltv +EXPORT_SYMBOL drivers/net/wireless/hermes 0xc60b5e9e hermes_bap_pwrite +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd38d8ae2 hermes_read_ltv +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd3f714e5 hermes_bap_pread +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd5168829 hermes_allocate +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd5336e5d hermes_init +EXPORT_SYMBOL drivers/net/wireless/hermes 0xd54e219d hermes_docmd_wait +EXPORT_SYMBOL drivers/net/wireless/hermes 0xed47b224 hermes_struct_init +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x02c2d997 hostap_set_roaming +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x0398e31b hostap_set_word +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x0a5ad871 hostap_remove_interface +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x0ae80fe0 hostap_set_auth_algs +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x1723ac32 hostap_set_multicast_list_queue +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x2a0837e4 hostap_init_proc +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x2da03a92 hostap_setup_dev +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x32f9ca5d hostap_init_data +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x3c60f43f hostap_set_hostapd +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x48d4206c hostap_handle_sta_tx_exc +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x491f910f hostap_master_start_xmit +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x5829c70b hostap_set_hostapd_sta +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x5adf5cd2 hostap_info_process +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x5eb7d661 hostap_get_porttype +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x6903f16c hostap_80211_get_hdrlen +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x6e04b8c4 hostap_80211_rx +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0x9dbda1dd prism2_update_comms_qual +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xa12ad27f hostap_dump_tx_header +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xa27a989c hostap_info_init +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xac189748 hostap_check_sta_fw_version +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xb28d410e hostap_init_ap_proc +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xb2a945e0 hostap_dump_rx_header +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xb3b8fb9d hostap_remove_proc +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xb8ce1b39 hostap_free_data +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xde130f81 hostap_set_string +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xdef1227e hostap_get_stats +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xe11d9e24 hostap_set_encryption +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xe8592b4d hostap_add_interface +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xea634d62 hostap_set_antsel +EXPORT_SYMBOL drivers/net/wireless/hostap/hostap 0xf848824d hostap_80211_ops +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x054256cc iwl_chain_noise_calibration +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x078a6690 iwl_rx_queue_free +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x07cf64d6 iwl_power_set_user_mode +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x080b648e iwl_rx_reply_rx_phy +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x080eb507 iwl_send_cmd_sync +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x09a281f5 iwl_scan_cancel_timeout +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x0dc11698 iwl_print_event_log +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x105ffd1d iwl_rx_agg_start +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x12cf6e94 iwl_reset_qos +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x1356104b iwl_send_cmd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x15c46a0d iwl_hw_txq_free_tfd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x172acabe iwl_is_fat_tx_allowed +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x18dffce1 iwl_setup_power_deferred_work +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x1d77b399 iwl_bcast_addr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x20c35748 iwl_uninit_drv +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x216b7756 iwl_set_rxon_chain +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x22f13ab0 iwl_eeprom_free +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x23126b64 iwl_eeprom_check_version +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x24b999dc iwl_rf_kill_ct_config +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x2890cf04 iwl_set_rxon_ht +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x2d8e7b6c iwl_power_temperature_change +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x2f6e3ac9 iwl_power_update_mode +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x305abe92 iwl_sta_modify_enable_tid_tx +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x30763c16 iwl_get_channel_info +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x3491f138 iwl_rxq_stop +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x34d5da87 iwl_eeprom_query16 +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x357aaa53 iwl_hw_txq_ctx_free +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x3a06b2e2 iwl_send_statistics_request +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x3d06ab92 iwl_set_tx_power +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x3f93769f iwl_leds_unregister +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x4836bf10 iwl_hw_nic_init +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x4e4537ae iwl_remove_station +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x50aa01a2 iwl_send_cmd_pdu_async +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x53055abc iwl_hw_detect +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x538b0cc3 iwl_rx_statistics +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x560734f4 iwl_set_rxon_channel +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x56f396a7 iwl_sensitivity_calibration +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x56f49efe iwl_rfkill_set_hw_state +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5ab275ad iwl_rx_reply_rx +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5c550d8d iwl_remove_default_wep_key +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5dd22120 iwl_power_set_system_mode +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5e5fdbba iwl_eeprom_query_addr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5fa1f21b iwlcore_eeprom_verify_signature +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x5fa83880 iwl_leds_register +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x60774702 iwl_queue_space +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x61f83672 iwl_init_sensitivity +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x6320468a iwl_init_drv +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x658728c6 iwl_rx_queue_restock +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x6633a7d7 iwl_rx_queue_space +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x664c6248 iwl_reset_run_time_calib +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x6ad86663 iwl_rx_replenish +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x6cc05b65 iwl_find_station +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x7280863a iwl_tx_agg_start +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x73a0ac6e iwl_rxon_add_station +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x7b24806d iwl_hwrate_to_tx_control +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x7cef5b11 iwl_rx_queue_update_write_ptr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x7e42ac53 iwl_eeprom_get_mac +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x813be53c iwl_tx_queue_reclaim +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x8490b3a4 iwl_power_enable_management +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x84a23ce0 iwl_txq_update_write_ptr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x84c1fc33 iwlcore_eeprom_acquire_semaphore +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x8670273d iwl_hwrate_to_plcp_idx +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x876f3fd5 iwl_dump_nic_event_log +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x8b2e9a42 iwl_radio_kill_sw_enable_radio +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x8c16de26 iwl_scan_initiate +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x90d1eeee iwl_setup_rx_scan_handlers +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x925b1af3 iwl_tx_skb +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x9a2287d0 iwl_rx_queue_alloc +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0x9faced57 iwl_calib_set +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xa0b1f130 iwl_init_channel_map +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xa7c931f9 iwl_rx_queue_reset +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xaa4c460a iwl_setup_mac +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xaac2e0db iwl_set_hw_params +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xaaff1e20 iwl_rfkill_unregister +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xabe3bb3b iwl_set_default_wep_key +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xad0c715b iwl_txq_ctx_stop +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xb22a9e29 iwl_get_ra_sta_id +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xb323dcc2 iwl_rx_missed_beacon_notif +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xb38a1e41 iwl_escape_essid +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xb38d1862 iwl_send_static_wepkey_cmd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xbf08b234 iwl_scan_cancel +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc111e519 iwlcore_eeprom_query_addr +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc203a39d iwl_verify_ucode +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc5d40627 iwl_send_calib_results +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc6b294d1 iwl_power_cancel_timeout +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xc6d4eb0d iwl_send_lq_cmd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xcb2893ac iwl_get_sta_id +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xcbaf4931 get_cmd_string +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xce54c3a0 iwl_clear_stations_table +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xcf4c4595 iwl_rx_reply_compressed_ba +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xd654d618 iwl_set_dynamic_key +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xd71c95ed iwl_dump_nic_error_log +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xdd7cc04d iwl_tx_cmd_complete +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xddb29814 iwl_leds_background +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xdf5a4c21 iwl_send_add_sta +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xe06e6128 iwl_txq_check_empty +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xe65087ea iwl_hw_txq_attach_buf_to_tfd +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xe7ce5d70 iwl_rates +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xe8595fbf iwl_add_station_flags +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xea86b8ac iwl_power_initialize +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xeb6e8747 iwl_setup_scan_deferred_work +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xedb282fd iwl_radio_kill_sw_disable_radio +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xedd89224 iwl_send_cmd_pdu +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xee989d41 iwl_alloc_all +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf07aa0b9 iwlcore_eeprom_release_semaphore +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf2239bbe iwl_rx_agg_stop +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf30e213e iwl_eeprom_init +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf47e0b44 iwl_rfkill_init +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xf4a17617 iwl_remove_dynamic_key +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xfbc24d00 iwl_power_disable_management +EXPORT_SYMBOL drivers/net/wireless/iwlwifi/iwlcore 0xfed273e2 iwl_tx_agg_stop +EXPORT_SYMBOL drivers/net/wireless/orinoco 0x0787d441 free_orinocodev +EXPORT_SYMBOL drivers/net/wireless/orinoco 0x1a9d334a orinoco_interrupt +EXPORT_SYMBOL drivers/net/wireless/orinoco 0x76d454ca orinoco_reinit_firmware +EXPORT_SYMBOL drivers/net/wireless/orinoco 0x9281a14f alloc_orinocodev +EXPORT_SYMBOL drivers/net/wireless/orinoco 0xbe05f995 __orinoco_down +EXPORT_SYMBOL drivers/net/wireless/orinoco 0xf6df7e42 __orinoco_up +EXPORT_SYMBOL drivers/parport/parport 0x120325d3 parport_ieee1284_ecp_write_addr +EXPORT_SYMBOL drivers/parport/parport 0x14dc98d8 parport_negotiate +EXPORT_SYMBOL drivers/parport/parport 0x1a41dc31 parport_ieee1284_epp_write_data +EXPORT_SYMBOL drivers/parport/parport 0x1dbe8d84 parport_irq_handler +EXPORT_SYMBOL drivers/parport/parport 0x372ca585 parport_ieee1284_ecp_write_data +EXPORT_SYMBOL drivers/parport/parport 0x3b22c97f parport_ieee1284_epp_read_addr +EXPORT_SYMBOL drivers/parport/parport 0x3f6e5c67 parport_ieee1284_epp_write_addr +EXPORT_SYMBOL drivers/parport/parport 0x415dfd7d parport_unregister_device +EXPORT_SYMBOL drivers/parport/parport 0x480c778b parport_wait_peripheral +EXPORT_SYMBOL drivers/parport/parport 0x4d2a941b parport_ieee1284_interrupt +EXPORT_SYMBOL drivers/parport/parport 0x4f23d05f parport_claim +EXPORT_SYMBOL drivers/parport/parport 0x5649a7bf parport_set_timeout +EXPORT_SYMBOL drivers/parport/parport 0x5b6ccbee parport_ieee1284_read_nibble +EXPORT_SYMBOL drivers/parport/parport 0x5d2bd076 parport_ieee1284_write_compat +EXPORT_SYMBOL drivers/parport/parport 0x632c8aae parport_put_port +EXPORT_SYMBOL drivers/parport/parport 0x65f2cfa1 parport_wait_event +EXPORT_SYMBOL drivers/parport/parport 0x7652756e parport_register_port +EXPORT_SYMBOL drivers/parport/parport 0x7f1864a3 parport_ieee1284_read_byte +EXPORT_SYMBOL drivers/parport/parport 0x89fb4c12 parport_unregister_driver +EXPORT_SYMBOL drivers/parport/parport 0x9d8a6642 parport_claim_or_block +EXPORT_SYMBOL drivers/parport/parport 0x9e8eecee parport_find_base +EXPORT_SYMBOL drivers/parport/parport 0xa1a86b8c parport_write +EXPORT_SYMBOL drivers/parport/parport 0xa5f7cad0 parport_find_number +EXPORT_SYMBOL drivers/parport/parport 0xb28a268a parport_remove_port +EXPORT_SYMBOL drivers/parport/parport 0xbdf757f5 parport_ieee1284_epp_read_data +EXPORT_SYMBOL drivers/parport/parport 0xcb967a71 parport_ieee1284_ecp_read_data +EXPORT_SYMBOL drivers/parport/parport 0xd003567a parport_get_port +EXPORT_SYMBOL drivers/parport/parport 0xd745d233 parport_announce_port +EXPORT_SYMBOL drivers/parport/parport 0xd9670cd7 parport_register_device +EXPORT_SYMBOL drivers/parport/parport 0xeb651244 parport_release +EXPORT_SYMBOL drivers/parport/parport 0xf1a3e988 parport_read +EXPORT_SYMBOL drivers/parport/parport 0xf2b81bec parport_register_driver +EXPORT_SYMBOL drivers/parport/parport_pc 0x3bfdce12 parport_pc_unregister_port +EXPORT_SYMBOL drivers/parport/parport_pc 0xeacccf75 parport_pc_probe_port +EXPORT_SYMBOL drivers/pci/hotplug/pci_hotplug 0x1a9cf8d3 acpi_get_hp_hw_control_from_firmware +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x08d3ce0f pcmcia_register_driver +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x2ed8dbd8 pcmcia_request_io +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x4cc7d3ea pcmcia_unregister_driver +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x651f96f8 cs_error +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x6e504775 pcmcia_release_window +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x73cd6557 pcmcia_map_mem_page +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x77bdb8ae pcmcia_get_window +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x8374b4fc pcmcia_dev_present +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x8822c514 pcmcia_request_window +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x8da9bd97 pcmcia_request_configuration +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0x9a2c8397 pcmcia_access_configuration_register +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xb169ce88 pcmcia_get_configuration_info +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xc91f8c19 pcmcia_get_mem_page +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xca9f69da pcmcia_modify_configuration +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xe1a09dc7 pcmcia_request_irq +EXPORT_SYMBOL drivers/pcmcia/pcmcia 0xffab5460 pcmcia_disable_device +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x05d1a894 pcmcia_find_mem_region +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x0e0189b6 pcmcia_find_io_region +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x212db8d2 pcmcia_socket_list +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x2549a38a pccard_validate_cis +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x42a6c43c pcmcia_replace_cis +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x4693608e pccard_get_next_tuple +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x47257b71 pcmcia_eject_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x4d55843c pccard_register_pcmcia +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x520035ab pcmcia_parse_events +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x5cfae6a7 pccard_reset_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x6c77d140 pcmcia_put_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x6d43fcca pcmcia_validate_mem +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x6d6949fd pcmcia_insert_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x70875132 release_cis_mem +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x727709e6 destroy_cis_cache +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x7d7d304c pcmcia_socket_dev_suspend +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x881a01a9 pccard_read_tuple +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x8981d9f7 pcmcia_write_cis_mem +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x8ce00554 pcmcia_get_socket_by_nr +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0x9cc48af1 pcmcia_resume_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xa44f2739 pcmcia_register_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xa4609834 pcmcia_socket_dev_resume +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xa8df65b6 pcmcia_socket_list_rwsem +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xab1e5679 pccard_get_tuple_data +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xad6d1e6b pcmcia_adjust_io_region +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xb25dc28d pcmcia_socket_class +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xb3c5c547 pcmcia_get_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xc57f13b5 pccard_static_ops +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xcd2ac1c1 pccard_parse_tuple +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xcf97f3bd dead_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xd151ade6 pccard_get_first_tuple +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xe05b3adc pcmcia_unregister_socket +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xe3452b77 pcmcia_suspend_card +EXPORT_SYMBOL drivers/pcmcia/pcmcia_core 0xf62066dd pcmcia_read_cis_mem +EXPORT_SYMBOL drivers/pcmcia/rsrc_nonstatic 0x564be6bd pccard_nonstatic_ops +EXPORT_SYMBOL drivers/scsi/megaraid/megaraid_mm 0x2250c66e mraid_mm_adapter_app_handle +EXPORT_SYMBOL drivers/scsi/megaraid/megaraid_mm 0x30793671 mraid_mm_register_adp +EXPORT_SYMBOL drivers/scsi/megaraid/megaraid_mm 0x512c956d mraid_mm_unregister_adp +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x16d4591c qlogicfas408_disable_ints +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x243c7b23 qlogicfas408_info +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x3fd8cd71 qlogicfas408_detect +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x48cacc97 qlogicfas408_biosparam +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x5cb878c3 qlogicfas408_queuecommand +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x5cd179e6 qlogicfas408_ihandl +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x5e6cbb9a qlogicfas408_abort +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0x65d8fd4b qlogicfas408_bus_reset +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0xe76b3b20 qlogicfas408_get_chip_type +EXPORT_SYMBOL drivers/scsi/qlogicfas408 0xf2b95199 qlogicfas408_setup +EXPORT_SYMBOL drivers/scsi/raid_class 0x14030efe raid_component_add +EXPORT_SYMBOL drivers/scsi/raid_class 0x5d335f6d raid_class_release +EXPORT_SYMBOL drivers/scsi/raid_class 0xbf70c053 raid_class_attach +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x0138e14b scsi_register_driver +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x0382d5db scsi_reset_provider +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x0c65e73c scsi_normalize_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x0c8c9e99 scsi_show_extd_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x11267875 scsi_extd_sense_format +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1b9e0ff1 scsilun_to_int +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1c8c4bbb starget_for_each_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1e1789ab __scsi_add_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1f985ff8 scsi_host_lookup +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x1fdec236 scsi_device_lookup +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x21bb54e9 scsi_mode_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x21bb9c44 scsi_prep_state_check +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x21eee89e scsi_host_put +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x22d618e2 scsi_get_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x26ba707b scsi_scan_host +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x28a2ed02 scsi_build_sense_buffer +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x290762dc scsi_adjust_queue_depth +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2951e317 scsi_scan_target +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2b0ba2b0 scsi_sense_desc_find +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2c109390 scsi_set_medium_removal +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2d89342a scsi_show_sense_hdr +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2e7c625e scsi_calculate_bounce_limit +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x2f46fb43 scsi_eh_restore_cmnd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x33236019 scsi_allocate_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x337cd433 scsi_report_bus_reset +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x34a67a43 scsi_target_quiesce +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x355ba822 scsi_command_normalize_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x36a9784f scsi_eh_finish_cmd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x396de25f scsi_is_host_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x397d2c3b scsi_print_result +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x3aefd224 scsi_bios_ptable +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x3c7aa9fc scsi_setup_blk_pc_cmnd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x3db674fa scsi_target_resume +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x3ed0160f scsi_rescan_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x3fa8d430 scsi_device_resume +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x465e559a scsi_add_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x4afe9a77 scsi_partsize +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x5135fc96 scsi_is_target_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x55ac944c scsi_put_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x5690d3cc scsi_get_host_dev +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x56c8799d scsi_kunmap_atomic_sg +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x5e45ee18 scsicam_bios_param +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x5e77bdbe scsi_dma_map +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x69d38ed9 __scsi_print_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x6a0207ec scsi_finish_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x6b273f18 scsi_host_alloc +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x6da7312b scsi_device_set_state +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x7022d1a5 scsi_prep_return +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x71a8ace4 scsi_remove_host +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x71e7ab08 scsi_ioctl +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x72ea7b2d scsi_device_type +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x731ea688 __scsi_iterate_devices +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x73b45582 scsi_remove_target +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x76c0017c __scsi_put_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x796fc5ce scsi_get_sense_info_fld +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x7b3e1151 scsi_unblock_requests +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x8407ca76 __scsi_device_lookup +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x8fea6da6 scsi_is_sdev_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x90a6bb1b scsi_free_host_dev +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x943866b4 scsi_host_set_state +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x943d738d scsi_register +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x952f36e6 scsi_print_sense +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x96cd2b04 scsi_sense_key_string +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x9c3235a3 scsi_device_lookup_by_target +EXPORT_SYMBOL drivers/scsi/scsi_mod 0x9cfd56c5 scsi_print_status +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xa172ca1a scsi_remove_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xa2843543 scsi_free_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xa5e7e0ef scsi_track_queue_full +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xa5eeaecb scsi_test_unit_ready +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xa7ce434b scsi_execute_req +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xa9afd8b7 scsi_req_abort_cmd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xae1faaa1 scsi_eh_prep_cmnd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xaf3dd7dc scsi_logging_level +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xb3f3a4c9 scsi_unregister +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xb6c5a973 scsi_show_result +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xb7f415db scsi_host_get +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xb84af6d5 scsi_device_quiesce +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xc1825173 scsi_cmd_print_sense_hdr +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xc2f04930 __scsi_alloc_queue +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xca5dbc50 scsi_print_sense_hdr +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xca989c1e scsi_execute +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xcc794118 scsi_device_get +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xcc8aa498 scsi_init_io +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xd3038ab7 scsi_block_when_processing_errors +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xd775e4a9 scsi_dma_unmap +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xd8db0224 scsi_setup_fs_cmnd +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xda3d1143 scsi_print_command +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xe2b6fc2a scsi_register_interface +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xe3e86ccd scsi_add_host +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xe86208a7 scsi_nonblockable_ioctl +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xea10212a int_to_scsilun +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xeb30e953 __scsi_device_lookup_by_target +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xefcea339 scsi_report_device_reset +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf08eb08f scsi_device_put +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf0e65317 scsi_release_buffers +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf4528073 scsi_kmap_atomic_sg +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf5dc487b __starget_for_each_device +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xf811e69d scsi_eh_flush_done_q +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xfcf56390 scsi_block_requests +EXPORT_SYMBOL drivers/scsi/scsi_mod 0xfef96e23 __scsi_print_command +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x05eef3c9 fc_remote_port_delete +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x3f5d4e57 scsi_is_fc_vport +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x4733ed42 fc_remote_port_add +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x7954b1ea fc_get_event_number +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x837f83cb fc_remove_host +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x8411f7d4 fc_host_post_vendor_event +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0x9e2b90e8 fc_vport_terminate +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0xaaa38330 fc_remote_port_rolechg +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0xdf00ec53 fc_attach_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0xef86ae27 scsi_is_fc_rport +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0xf39afd18 fc_host_post_event +EXPORT_SYMBOL drivers/scsi/scsi_transport_fc 0xf3bdd7c4 fc_release_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x0c6401b8 sas_attach_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x20b6b11e sas_rphy_delete +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x2223006a sas_phy_alloc +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x2314f2e2 sas_port_delete +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x2c5c0a4a sas_port_add +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x53b0c7cd scsi_is_sas_rphy +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x59e74794 sas_port_alloc +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x604c56f5 sas_phy_free +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x6a753c10 sas_phy_delete +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x708c61a5 sas_port_delete_phy +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x7d1a8090 sas_rphy_add +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x7d334f8e sas_port_free +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x82f29d1e scsi_is_sas_port +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x8877718f sas_release_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0x8ae25afd sas_port_mark_backlink +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xb9a2f638 sas_expander_alloc +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xc960cfb4 sas_read_port_mode_page +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xcae3ab78 sas_remove_children +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xd18caa2c sas_phy_add +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xd33cfc6e sas_remove_host +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xd3ae44dd sas_port_alloc_num +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xd5f70312 sas_end_device_alloc +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xd77822d6 sas_rphy_remove +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xdc6a52a8 sas_port_add_phy +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xf3d90438 scsi_is_sas_phy +EXPORT_SYMBOL drivers/scsi/scsi_transport_sas 0xf811aef6 sas_rphy_free +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0x16e30ba7 spi_release_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0x361100ff spi_schedule_dv_device +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0x3686ea09 spi_print_msg +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0x3b810ffa spi_attach_transport +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0xc08675d4 spi_display_xfer_agreement +EXPORT_SYMBOL drivers/scsi/scsi_transport_spi 0xfc35560e spi_dv_device +EXPORT_SYMBOL drivers/ssb/ssb 0x058b6a70 ssb_bus_may_powerdown +EXPORT_SYMBOL drivers/ssb/ssb 0x1de4ff62 ssb_bus_suspend +EXPORT_SYMBOL drivers/ssb/ssb 0x2c6c218f ssb_pcicore_dev_irqvecs_enable +EXPORT_SYMBOL drivers/ssb/ssb 0x3d3d938a ssb_device_enable +EXPORT_SYMBOL drivers/ssb/ssb 0x3de57056 ssb_dma_set_mask +EXPORT_SYMBOL drivers/ssb/ssb 0x41366069 ssb_bus_pcibus_register +EXPORT_SYMBOL drivers/ssb/ssb 0x47886871 ssb_dma_translation +EXPORT_SYMBOL drivers/ssb/ssb 0x60501173 __ssb_driver_register +EXPORT_SYMBOL drivers/ssb/ssb 0x6d8fb826 ssb_clockspeed +EXPORT_SYMBOL drivers/ssb/ssb 0x8f5c9cf8 ssb_device_disable +EXPORT_SYMBOL drivers/ssb/ssb 0xc0512e0f ssb_admatch_base +EXPORT_SYMBOL drivers/ssb/ssb 0xc1364764 ssb_dma_free_consistent +EXPORT_SYMBOL drivers/ssb/ssb 0xcc9ebf7f ssb_set_devtypedata +EXPORT_SYMBOL drivers/ssb/ssb 0xd481192b ssb_admatch_size +EXPORT_SYMBOL drivers/ssb/ssb 0xd4ae3d04 ssb_device_is_enabled +EXPORT_SYMBOL drivers/ssb/ssb 0xd659f75f ssb_bus_powerup +EXPORT_SYMBOL drivers/ssb/ssb 0xd8b49524 ssb_driver_unregister +EXPORT_SYMBOL drivers/ssb/ssb 0xdb368a39 ssb_pcihost_register +EXPORT_SYMBOL drivers/ssb/ssb 0xdc78fb5c ssb_bus_unregister +EXPORT_SYMBOL drivers/ssb/ssb 0xf5f08953 ssb_bus_resume +EXPORT_SYMBOL drivers/ssb/ssb 0xf915c12b ssb_dma_alloc_consistent +EXPORT_SYMBOL drivers/telephony/ixj 0xe3082383 ixj_pcmcia_probe +EXPORT_SYMBOL drivers/telephony/phonedev 0x04d0bd13 phone_unregister_device +EXPORT_SYMBOL drivers/telephony/phonedev 0x8f9c2a56 phone_register_device +EXPORT_SYMBOL drivers/usb/gadget/net2280 0x3f966fad usb_gadget_register_driver +EXPORT_SYMBOL drivers/usb/gadget/net2280 0x65500a09 net2280_set_fifo_mode +EXPORT_SYMBOL drivers/usb/gadget/net2280 0x9519c541 usb_gadget_unregister_driver +EXPORT_SYMBOL drivers/usb/host/sl811-hcd 0x8ee69d40 sl811h_driver +EXPORT_SYMBOL drivers/usb/serial/usbserial 0x9b28adb3 usb_serial_resume +EXPORT_SYMBOL drivers/usb/serial/usbserial 0xb8b712cd usb_serial_suspend +EXPORT_SYMBOL drivers/video/backlight/corgi_bl 0xc86baa7c corgibl_limit_intensity +EXPORT_SYMBOL drivers/video/backlight/lcd 0xc2d6d3f0 lcd_device_unregister +EXPORT_SYMBOL drivers/video/backlight/lcd 0xfa44f217 lcd_device_register +EXPORT_SYMBOL drivers/video/console/bitblit 0xb60bcf3d fbcon_set_bitops +EXPORT_SYMBOL drivers/video/console/font 0x09c8eb55 font_vga_8x16 +EXPORT_SYMBOL drivers/video/console/font 0xbb99125c get_default_font +EXPORT_SYMBOL drivers/video/console/font 0xf7584a9c find_font +EXPORT_SYMBOL drivers/video/console/softcursor 0xcf2f30a9 soft_cursor +EXPORT_SYMBOL drivers/video/console/tileblit 0x61b8a072 fbcon_set_tileops +EXPORT_SYMBOL drivers/video/cyber2000fb 0x0cc3ede5 cyber2000fb_detach +EXPORT_SYMBOL drivers/video/cyber2000fb 0x0ce85cb0 cyber2000fb_disable_extregs +EXPORT_SYMBOL drivers/video/cyber2000fb 0x29e6f9bf cyber2000fb_attach +EXPORT_SYMBOL drivers/video/cyber2000fb 0x6e6ea3f3 cyber2000fb_enable_extregs +EXPORT_SYMBOL drivers/video/cyber2000fb 0xa3b9801b cyber2000fb_get_fb_var +EXPORT_SYMBOL drivers/video/display/display 0x0a72c73a display_device_unregister +EXPORT_SYMBOL drivers/video/display/display 0x9c5117c6 display_device_register +EXPORT_SYMBOL drivers/video/macmodes 0x08ed0b62 mac_vmode_to_var +EXPORT_SYMBOL drivers/video/macmodes 0x48058ff3 mac_find_mode +EXPORT_SYMBOL drivers/video/macmodes 0xe2304303 mac_map_monitor_sense +EXPORT_SYMBOL drivers/video/matrox/g450_pll 0x97cfdef3 g450_mnp2f +EXPORT_SYMBOL drivers/video/matrox/g450_pll 0xa7916536 matroxfb_g450_setpll_cond +EXPORT_SYMBOL drivers/video/matrox/g450_pll 0xe3f09095 matroxfb_g450_setclk +EXPORT_SYMBOL drivers/video/matrox/matroxfb_DAC1064 0x284b9f52 DAC1064_global_init +EXPORT_SYMBOL drivers/video/matrox/matroxfb_DAC1064 0x2afe9faa matrox_mystique +EXPORT_SYMBOL drivers/video/matrox/matroxfb_DAC1064 0xd3717e1b matrox_G100 +EXPORT_SYMBOL drivers/video/matrox/matroxfb_DAC1064 0xee38303c DAC1064_global_restore +EXPORT_SYMBOL drivers/video/matrox/matroxfb_Ti3026 0x6784de09 matrox_millennium +EXPORT_SYMBOL drivers/video/matrox/matroxfb_accel 0x4cfc0223 matrox_cfbX_init +EXPORT_SYMBOL drivers/video/matrox/matroxfb_base 0x82b4e21d matroxfb_enable_irq +EXPORT_SYMBOL drivers/video/matrox/matroxfb_base 0xadcab999 matroxfb_wait_for_sync +EXPORT_SYMBOL drivers/video/matrox/matroxfb_base 0xb50eb858 matroxfb_unregister_driver +EXPORT_SYMBOL drivers/video/matrox/matroxfb_base 0xff041bee matroxfb_register_driver +EXPORT_SYMBOL drivers/video/matrox/matroxfb_g450 0x07d80da5 matroxfb_g450_connect +EXPORT_SYMBOL drivers/video/matrox/matroxfb_g450 0xccc8db05 matroxfb_g450_shutdown +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0x25cf8049 matroxfb_PLL_calcclock +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0x368f4a4c matroxfb_vgaHWinit +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0x8bb8fa52 matroxfb_vgaHWrestore +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0xabd8e427 matroxfb_var2my +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0xb609b19e matroxfb_DAC_in +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0xee714544 matroxfb_DAC_out +EXPORT_SYMBOL drivers/video/matrox/matroxfb_misc 0xf7e2e08d matroxfb_read_pins +EXPORT_SYMBOL drivers/video/output 0xb2100689 video_output_unregister +EXPORT_SYMBOL drivers/video/output 0xdd202b9e video_output_register +EXPORT_SYMBOL drivers/video/sis/sisfb 0x3037658e sis_malloc +EXPORT_SYMBOL drivers/video/sis/sisfb 0x454a3cf0 sis_free +EXPORT_SYMBOL drivers/video/svgalib 0x00d1fce9 svga_set_default_seq_regs +EXPORT_SYMBOL drivers/video/svgalib 0x07b3da30 svga_wseq_multi +EXPORT_SYMBOL drivers/video/svgalib 0x1b95c56a svga_check_timings +EXPORT_SYMBOL drivers/video/svgalib 0x3fc4cd5a svga_get_tilemax +EXPORT_SYMBOL drivers/video/svgalib 0x58f6cb37 svga_tilecopy +EXPORT_SYMBOL drivers/video/svgalib 0x63e898d1 svga_set_default_crt_regs +EXPORT_SYMBOL drivers/video/svgalib 0x7a3ae959 svga_wcrt_multi +EXPORT_SYMBOL drivers/video/svgalib 0x80408443 svga_set_timings +EXPORT_SYMBOL drivers/video/svgalib 0x8fa8438b svga_set_textmode_vga_regs +EXPORT_SYMBOL drivers/video/svgalib 0x9b6efc30 svga_tileblit +EXPORT_SYMBOL drivers/video/svgalib 0xab3b22ad svga_set_default_gfx_regs +EXPORT_SYMBOL drivers/video/svgalib 0xb8e4ee54 svga_tilecursor +EXPORT_SYMBOL drivers/video/svgalib 0xc7c1c822 svga_get_caps +EXPORT_SYMBOL drivers/video/svgalib 0xdad682b1 svga_set_default_atc_regs +EXPORT_SYMBOL drivers/video/svgalib 0xec83c473 svga_match_format +EXPORT_SYMBOL drivers/video/svgalib 0xece84ae0 svga_tilefill +EXPORT_SYMBOL drivers/video/svgalib 0xef689bbf svga_settile +EXPORT_SYMBOL drivers/video/svgalib 0xef774f5d svga_compute_pll +EXPORT_SYMBOL drivers/video/syscopyarea 0x9175322b sys_copyarea +EXPORT_SYMBOL drivers/video/sysfillrect 0xa08a405f sys_fillrect +EXPORT_SYMBOL drivers/video/sysimgblt 0x53b9e59d sys_imageblit +EXPORT_SYMBOL drivers/video/vgastate 0x686de290 restore_vga +EXPORT_SYMBOL drivers/video/vgastate 0xe7a2620e save_vga +EXPORT_SYMBOL drivers/w1/slaves/w1_ds2760 0x6036e6b3 w1_ds2760_read +EXPORT_SYMBOL drivers/w1/slaves/w1_ds2760 0x73b3cf34 w1_ds2760_write +EXPORT_SYMBOL drivers/w1/wire 0x6724f7bc w1_unregister_family +EXPORT_SYMBOL drivers/w1/wire 0x8cf61660 w1_add_master_device +EXPORT_SYMBOL drivers/w1/wire 0x96c33d8b w1_register_family +EXPORT_SYMBOL drivers/w1/wire 0xcda061c0 w1_remove_master_device +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0x04e133fc iTCO_vendor_check_noreboot_on +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0x672c9d44 iTCO_vendor_pre_keepalive +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0xa78bd894 iTCO_vendor_pre_set_heartbeat +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0xa8d6daac iTCO_vendor_pre_start +EXPORT_SYMBOL drivers/watchdog/iTCO_vendor_support 0xd0efe320 iTCO_vendor_pre_stop +EXPORT_SYMBOL fs/configfs/configfs 0x24517370 config_item_put +EXPORT_SYMBOL fs/configfs/configfs 0x27e53180 config_group_find_item +EXPORT_SYMBOL fs/configfs/configfs 0x41f59339 configfs_undepend_item +EXPORT_SYMBOL fs/configfs/configfs 0x7638efe3 configfs_register_subsystem +EXPORT_SYMBOL fs/configfs/configfs 0x778209f5 config_group_init +EXPORT_SYMBOL fs/configfs/configfs 0x9290e281 config_item_init +EXPORT_SYMBOL fs/configfs/configfs 0xa2501a2c config_item_set_name +EXPORT_SYMBOL fs/configfs/configfs 0xac7418e1 configfs_depend_item +EXPORT_SYMBOL fs/configfs/configfs 0xae812660 config_group_init_type_name +EXPORT_SYMBOL fs/configfs/configfs 0xb06f4821 config_item_get +EXPORT_SYMBOL fs/configfs/configfs 0xd1279084 config_item_init_type_name +EXPORT_SYMBOL fs/configfs/configfs 0xfe5b5d89 configfs_unregister_subsystem +EXPORT_SYMBOL fs/jbd/jbd 0x0ae93e9d journal_create +EXPORT_SYMBOL fs/jbd/jbd 0x10410af5 journal_init_dev +EXPORT_SYMBOL fs/jbd/jbd 0x1f131598 journal_get_write_access +EXPORT_SYMBOL fs/jbd/jbd 0x25e0c528 journal_try_to_free_buffers +EXPORT_SYMBOL fs/jbd/jbd 0x2e0b4ae4 journal_invalidatepage +EXPORT_SYMBOL fs/jbd/jbd 0x342774ae journal_ack_err +EXPORT_SYMBOL fs/jbd/jbd 0x4a4e1b39 journal_get_undo_access +EXPORT_SYMBOL fs/jbd/jbd 0x4b7901c0 journal_stop +EXPORT_SYMBOL fs/jbd/jbd 0x4d551cbc journal_check_available_features +EXPORT_SYMBOL fs/jbd/jbd 0x4efbd1e4 journal_dirty_metadata +EXPORT_SYMBOL fs/jbd/jbd 0x52f8749a log_wait_commit +EXPORT_SYMBOL fs/jbd/jbd 0x564c0c1a journal_blocks_per_page +EXPORT_SYMBOL fs/jbd/jbd 0x607b3e53 journal_dirty_data +EXPORT_SYMBOL fs/jbd/jbd 0x741ecb8a journal_clear_err +EXPORT_SYMBOL fs/jbd/jbd 0x7b937f85 journal_wipe +EXPORT_SYMBOL fs/jbd/jbd 0x7c9380f1 journal_destroy +EXPORT_SYMBOL fs/jbd/jbd 0x827092da journal_force_commit +EXPORT_SYMBOL fs/jbd/jbd 0x882ab474 journal_flush +EXPORT_SYMBOL fs/jbd/jbd 0x905057c0 journal_abort +EXPORT_SYMBOL fs/jbd/jbd 0x99e7d787 journal_lock_updates +EXPORT_SYMBOL fs/jbd/jbd 0x9c062319 journal_update_format +EXPORT_SYMBOL fs/jbd/jbd 0xa2b83d23 journal_unlock_updates +EXPORT_SYMBOL fs/jbd/jbd 0xb6aab3ff journal_release_buffer +EXPORT_SYMBOL fs/jbd/jbd 0xc3c834ec journal_restart +EXPORT_SYMBOL fs/jbd/jbd 0xc703b299 journal_set_features +EXPORT_SYMBOL fs/jbd/jbd 0xc94400a0 journal_extend +EXPORT_SYMBOL fs/jbd/jbd 0xda8cd68d journal_errno +EXPORT_SYMBOL fs/jbd/jbd 0xe036343f journal_forget +EXPORT_SYMBOL fs/jbd/jbd 0xe39df4a9 journal_get_create_access +EXPORT_SYMBOL fs/jbd/jbd 0xe86e6210 journal_start +EXPORT_SYMBOL fs/jbd/jbd 0xea049045 journal_revoke +EXPORT_SYMBOL fs/jbd/jbd 0xeedfdb3a journal_check_used_features +EXPORT_SYMBOL fs/jbd/jbd 0xf65c9c2c journal_load +EXPORT_SYMBOL fs/jbd/jbd 0xf77417b5 journal_init_inode +EXPORT_SYMBOL fs/jbd/jbd 0xfb279459 journal_start_commit +EXPORT_SYMBOL fs/jbd/jbd 0xfe39ce31 journal_force_commit_nested +EXPORT_SYMBOL fs/jbd2/jbd2 0x04653f13 jbd2_journal_clear_features +EXPORT_SYMBOL fs/jbd2/jbd2 0x04e24c2b jbd2_journal_restart +EXPORT_SYMBOL fs/jbd2/jbd2 0x271f0dc1 jbd2_journal_force_commit +EXPORT_SYMBOL fs/jbd2/jbd2 0x281456cb jbd2_journal_unlock_updates +EXPORT_SYMBOL fs/jbd2/jbd2 0x28d098bf jbd2_journal_set_features +EXPORT_SYMBOL fs/jbd2/jbd2 0x296a41e8 jbd2_journal_dirty_metadata +EXPORT_SYMBOL fs/jbd2/jbd2 0x2b420a95 jbd2_journal_blocks_per_page +EXPORT_SYMBOL fs/jbd2/jbd2 0x3b7a7db1 jbd2_log_wait_commit +EXPORT_SYMBOL fs/jbd2/jbd2 0x42d818bb jbd2_journal_try_to_free_buffers +EXPORT_SYMBOL fs/jbd2/jbd2 0x448f1e86 jbd2_journal_flush +EXPORT_SYMBOL fs/jbd2/jbd2 0x4a506058 jbd2_journal_check_used_features +EXPORT_SYMBOL fs/jbd2/jbd2 0x5d1803cb jbd2_journal_release_jbd_inode +EXPORT_SYMBOL fs/jbd2/jbd2 0x65068d4c jbd2_journal_get_create_access +EXPORT_SYMBOL fs/jbd2/jbd2 0x66c29ce4 jbd2_journal_init_inode +EXPORT_SYMBOL fs/jbd2/jbd2 0x6b2d5003 jbd2_journal_create +EXPORT_SYMBOL fs/jbd2/jbd2 0x7c4cc8dc jbd2_journal_start_commit +EXPORT_SYMBOL fs/jbd2/jbd2 0x91afba31 jbd2_journal_lock_updates +EXPORT_SYMBOL fs/jbd2/jbd2 0xaec2f619 jbd2_journal_get_undo_access +EXPORT_SYMBOL fs/jbd2/jbd2 0xb40a3c9f jbd2_journal_ack_err +EXPORT_SYMBOL fs/jbd2/jbd2 0xb4ff58d7 jbd2_journal_file_inode +EXPORT_SYMBOL fs/jbd2/jbd2 0xbaf2671e jbd2_journal_begin_ordered_truncate +EXPORT_SYMBOL fs/jbd2/jbd2 0xbc1cc5b1 jbd2_journal_revoke +EXPORT_SYMBOL fs/jbd2/jbd2 0xbfaae622 jbd2_journal_get_write_access +EXPORT_SYMBOL fs/jbd2/jbd2 0xc0cd8853 jbd2_journal_start +EXPORT_SYMBOL fs/jbd2/jbd2 0xc56ec42e jbd2_journal_load +EXPORT_SYMBOL fs/jbd2/jbd2 0xc6b6766b jbd2_journal_force_commit_nested +EXPORT_SYMBOL fs/jbd2/jbd2 0xc7cc7658 jbd2_journal_update_format +EXPORT_SYMBOL fs/jbd2/jbd2 0xc991e355 jbd2_journal_check_available_features +EXPORT_SYMBOL fs/jbd2/jbd2 0xcb6ab90c jbd2_journal_errno +EXPORT_SYMBOL fs/jbd2/jbd2 0xcbd739bb jbd2_journal_forget +EXPORT_SYMBOL fs/jbd2/jbd2 0xcd7b74ef jbd2_journal_release_buffer +EXPORT_SYMBOL fs/jbd2/jbd2 0xd0407b0f jbd2_journal_extend +EXPORT_SYMBOL fs/jbd2/jbd2 0xe2499f78 jbd2_journal_clear_err +EXPORT_SYMBOL fs/jbd2/jbd2 0xe2ab8702 jbd2_journal_wipe +EXPORT_SYMBOL fs/jbd2/jbd2 0xe4499b83 jbd2_journal_stop +EXPORT_SYMBOL fs/jbd2/jbd2 0xe49c7a6b jbd2_journal_init_dev +EXPORT_SYMBOL fs/jbd2/jbd2 0xf1f0ee15 jbd2_journal_init_jbd_inode +EXPORT_SYMBOL fs/jbd2/jbd2 0xf82a406d jbd2_journal_invalidatepage +EXPORT_SYMBOL fs/jbd2/jbd2 0xfb0812b0 jbd2_journal_abort +EXPORT_SYMBOL fs/jbd2/jbd2 0xfe637d17 jbd2_journal_destroy +EXPORT_SYMBOL fs/lockd/lockd 0x47e4e496 nlmsvc_ops +EXPORT_SYMBOL fs/lockd/lockd 0x976e539e lockd_up +EXPORT_SYMBOL fs/lockd/lockd 0xa7b91a7b lockd_down +EXPORT_SYMBOL fs/lockd/lockd 0xad09c2db get_nfs_grace_period +EXPORT_SYMBOL fs/mbcache 0x077fcb51 mb_cache_entry_get +EXPORT_SYMBOL fs/mbcache 0x5f37873e mb_cache_shrink +EXPORT_SYMBOL fs/mbcache 0x60c90ebd mb_cache_entry_release +EXPORT_SYMBOL fs/mbcache 0x61c6990d mb_cache_create +EXPORT_SYMBOL fs/mbcache 0x7087f1af mb_cache_entry_insert +EXPORT_SYMBOL fs/mbcache 0x7ac0de17 mb_cache_entry_alloc +EXPORT_SYMBOL fs/mbcache 0xac45785f mb_cache_entry_find_next +EXPORT_SYMBOL fs/mbcache 0xb1ee9e93 mb_cache_entry_find_first +EXPORT_SYMBOL fs/mbcache 0xc231ff75 mb_cache_entry_free +EXPORT_SYMBOL fs/mbcache 0xd5263820 mb_cache_destroy +EXPORT_SYMBOL fs/nfs_common/nfs_acl 0x0c608226 nfsacl_encode +EXPORT_SYMBOL fs/nfs_common/nfs_acl 0xbcdcbea6 nfsacl_decode +EXPORT_SYMBOL fs/nfsd/nfsd 0x23f0a2c8 nfs4_acl_nfsv4_to_posix +EXPORT_SYMBOL fs/nfsd/nfsd 0x35e33c1e nfs4_acl_write_who +EXPORT_SYMBOL fs/nfsd/nfsd 0x46ffdc39 nfs4_acl_posix_to_nfsv4 +EXPORT_SYMBOL fs/nfsd/nfsd 0x5a157ae4 nfs4_acl_get_whotype +EXPORT_SYMBOL fs/nfsd/nfsd 0x96ce9bb4 nfs4_acl_new +EXPORT_SYMBOL fs/xfs/xfs 0x5c4d0851 xfs_qmcore_xfs +EXPORT_SYMBOL lib/crc-ccitt 0x651c2313 crc_ccitt +EXPORT_SYMBOL lib/crc-ccitt 0x75811312 crc_ccitt_table +EXPORT_SYMBOL lib/crc-itu-t 0x276c7e62 crc_itu_t +EXPORT_SYMBOL lib/crc-itu-t 0xd29b009f crc_itu_t_table +EXPORT_SYMBOL lib/crc-t10dif 0x782acba5 crc_t10dif +EXPORT_SYMBOL lib/crc16 0x02a6ce5a crc16_table +EXPORT_SYMBOL lib/crc16 0x9aabc564 crc16 +EXPORT_SYMBOL lib/crc7 0xc086bfba crc7 +EXPORT_SYMBOL lib/crc7 0xd80c3603 crc7_syndrome_table +EXPORT_SYMBOL lib/libcrc32c 0x13c0c38e crc32c_le +EXPORT_SYMBOL lib/libcrc32c 0x41bcd8b3 crc32c_be +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0x315c65fd zlib_deflateInit2 +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0x48034724 zlib_deflateReset +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0xaf64ad0d zlib_deflate +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0xf0caf44b zlib_deflate_workspacesize +EXPORT_SYMBOL lib/zlib_deflate/zlib_deflate 0xf741c793 zlib_deflateEnd +EXPORT_SYMBOL net/802/p8023 0x6a0f48de make_8023_client +EXPORT_SYMBOL net/802/p8023 0xb72269aa destroy_8023_client +EXPORT_SYMBOL net/9p/9pnet 0x00a6e1a5 p9_create_tclunk +EXPORT_SYMBOL net/9p/9pnet 0x0106a185 p9_create_tstat +EXPORT_SYMBOL net/9p/9pnet 0x0b26ff5a v9fs_unregister_trans +EXPORT_SYMBOL net/9p/9pnet 0x0dc94010 p9_client_read +EXPORT_SYMBOL net/9p/9pnet 0x15779868 p9_set_tag +EXPORT_SYMBOL net/9p/9pnet 0x15beb258 p9_client_stat +EXPORT_SYMBOL net/9p/9pnet 0x20f85208 p9_client_readn +EXPORT_SYMBOL net/9p/9pnet 0x21523da9 p9_create_tattach +EXPORT_SYMBOL net/9p/9pnet 0x244c6d40 p9_idpool_get +EXPORT_SYMBOL net/9p/9pnet 0x28cdbddc p9_client_open +EXPORT_SYMBOL net/9p/9pnet 0x2cae9487 p9_client_fcreate +EXPORT_SYMBOL net/9p/9pnet 0x309767d8 p9_deserialize_stat +EXPORT_SYMBOL net/9p/9pnet 0x315526bd p9_client_uwrite +EXPORT_SYMBOL net/9p/9pnet 0x31855989 p9_client_disconnect +EXPORT_SYMBOL net/9p/9pnet 0x3d73a797 p9_errstr2errno +EXPORT_SYMBOL net/9p/9pnet 0x465c4e6f p9_printfcall +EXPORT_SYMBOL net/9p/9pnet 0x507c9d70 p9_create_tauth +EXPORT_SYMBOL net/9p/9pnet 0x52b030cd p9_client_auth +EXPORT_SYMBOL net/9p/9pnet 0x58cc1098 p9_client_destroy +EXPORT_SYMBOL net/9p/9pnet 0x5e0ef374 p9_idpool_check +EXPORT_SYMBOL net/9p/9pnet 0x61852dea p9_idpool_put +EXPORT_SYMBOL net/9p/9pnet 0x6461b8de p9_create_twrite +EXPORT_SYMBOL net/9p/9pnet 0x6c5e479c p9_idpool_create +EXPORT_SYMBOL net/9p/9pnet 0x6f11c5c3 p9_create_twrite_u +EXPORT_SYMBOL net/9p/9pnet 0x71c7537d p9_create_tcreate +EXPORT_SYMBOL net/9p/9pnet 0x75d8f435 p9_client_wstat +EXPORT_SYMBOL net/9p/9pnet 0x7c3123e0 p9_client_write +EXPORT_SYMBOL net/9p/9pnet 0x81247f39 p9_create_tread +EXPORT_SYMBOL net/9p/9pnet 0x8432c83f p9_deserialize_fcall +EXPORT_SYMBOL net/9p/9pnet 0x845f41ff p9_client_clunk +EXPORT_SYMBOL net/9p/9pnet 0x950e6b03 p9_create_twstat +EXPORT_SYMBOL net/9p/9pnet 0x95abb195 p9_client_attach +EXPORT_SYMBOL net/9p/9pnet 0x9eca3ca7 p9_client_dirread +EXPORT_SYMBOL net/9p/9pnet 0xa7d22910 p9_client_remove +EXPORT_SYMBOL net/9p/9pnet 0xa9536064 p9_create_tversion +EXPORT_SYMBOL net/9p/9pnet 0xad806a33 p9_client_uread +EXPORT_SYMBOL net/9p/9pnet 0xadfd597a p9_create_tremove +EXPORT_SYMBOL net/9p/9pnet 0xaffd854f p9_client_create +EXPORT_SYMBOL net/9p/9pnet 0xbaa17b44 p9_idpool_destroy +EXPORT_SYMBOL net/9p/9pnet 0xbb0bb702 v9fs_get_trans_by_name +EXPORT_SYMBOL net/9p/9pnet 0xdc894ac7 p9_create_twalk +EXPORT_SYMBOL net/9p/9pnet 0xe09b7d13 p9_client_walk +EXPORT_SYMBOL net/9p/9pnet 0xe58a3360 p9_error_init +EXPORT_SYMBOL net/9p/9pnet 0xe6238993 v9fs_get_default_trans +EXPORT_SYMBOL net/9p/9pnet 0xf09b3efa p9_create_topen +EXPORT_SYMBOL net/9p/9pnet 0xf85870ff v9fs_register_trans +EXPORT_SYMBOL net/9p/9pnet 0xfff27930 p9_create_tflush +EXPORT_SYMBOL net/appletalk/appletalk 0x85bfa1fb aarp_send_ddp +EXPORT_SYMBOL net/appletalk/appletalk 0x8d893465 atalk_find_dev_addr +EXPORT_SYMBOL net/appletalk/appletalk 0xc4b8533c atrtr_get_dev +EXPORT_SYMBOL net/appletalk/appletalk 0xc596bff9 alloc_ltalkdev +EXPORT_SYMBOL net/ax25/ax25 0x0479d44f ax25_findbyuid +EXPORT_SYMBOL net/ax25/ax25 0x060e2328 ax25_rebuild_header +EXPORT_SYMBOL net/ax25/ax25 0x105e7bfb ax25_hard_header +EXPORT_SYMBOL net/ax25/ax25 0x242852b9 ax25_uid_policy +EXPORT_SYMBOL net/ax25/ax25 0x3d2d82ec ax25_display_timer +EXPORT_SYMBOL net/ax25/ax25 0x410761d7 ax25_linkfail_release +EXPORT_SYMBOL net/ax25/ax25 0x4502c65a asc2ax +EXPORT_SYMBOL net/ax25/ax25 0x53dea1ff ax2asc +EXPORT_SYMBOL net/ax25/ax25 0x7788fcbe ax25_send_frame +EXPORT_SYMBOL net/ax25/ax25 0x7fa435ab ax25_find_cb +EXPORT_SYMBOL net/ax25/ax25 0x81f5564c ax25_listen_release +EXPORT_SYMBOL net/ax25/ax25 0x8ede9e26 ax25_protocol_release +EXPORT_SYMBOL net/ax25/ax25 0x97b85f2d ax25_listen_register +EXPORT_SYMBOL net/ax25/ax25 0xc1444946 ax25cmp +EXPORT_SYMBOL net/ax25/ax25 0xc42ee6b7 ax25_header_ops +EXPORT_SYMBOL net/ax25/ax25 0xd43ecbf1 null_ax25_address +EXPORT_SYMBOL net/ax25/ax25 0xf477a4a5 ax25_linkfail_register +EXPORT_SYMBOL net/bluetooth/bluetooth 0x0d24b97c bt_accept_unlink +EXPORT_SYMBOL net/bluetooth/bluetooth 0x0f01807c hci_suspend_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0x10809060 hci_connect +EXPORT_SYMBOL net/bluetooth/bluetooth 0x111cba60 hci_conn_auth +EXPORT_SYMBOL net/bluetooth/bluetooth 0x178e8929 hci_resume_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0x17d2f095 hci_unregister_cb +EXPORT_SYMBOL net/bluetooth/bluetooth 0x23a6a8d1 hci_conn_encrypt +EXPORT_SYMBOL net/bluetooth/bluetooth 0x29f30a4f hci_get_route +EXPORT_SYMBOL net/bluetooth/bluetooth 0x2bfcf4d4 bt_sock_link +EXPORT_SYMBOL net/bluetooth/bluetooth 0x31e6fcf2 hci_send_acl +EXPORT_SYMBOL net/bluetooth/bluetooth 0x42d04eac hci_register_cb +EXPORT_SYMBOL net/bluetooth/bluetooth 0x442ee147 bt_sock_unlink +EXPORT_SYMBOL net/bluetooth/bluetooth 0x457bf861 hci_register_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0x49731587 hci_send_sco +EXPORT_SYMBOL net/bluetooth/bluetooth 0x4d04a9a0 bt_accept_enqueue +EXPORT_SYMBOL net/bluetooth/bluetooth 0x4fa222b1 hci_register_proto +EXPORT_SYMBOL net/bluetooth/bluetooth 0x52cf7088 hci_unregister_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0x5d71811f hci_conn_change_link_key +EXPORT_SYMBOL net/bluetooth/bluetooth 0x5f34aaf1 hci_unregister_proto +EXPORT_SYMBOL net/bluetooth/bluetooth 0x6461fbff bt_sock_ioctl +EXPORT_SYMBOL net/bluetooth/bluetooth 0x7094f8ae bt_err +EXPORT_SYMBOL net/bluetooth/bluetooth 0x79b31dd2 bt_sock_poll +EXPORT_SYMBOL net/bluetooth/bluetooth 0x79bfa4ea hci_conn_check_link_mode +EXPORT_SYMBOL net/bluetooth/bluetooth 0x94d57354 bt_accept_dequeue +EXPORT_SYMBOL net/bluetooth/bluetooth 0x97c1bd94 bt_sock_recvmsg +EXPORT_SYMBOL net/bluetooth/bluetooth 0xa0eb0173 hci_recv_fragment +EXPORT_SYMBOL net/bluetooth/bluetooth 0xa3f86604 hci_alloc_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0xba8ac00f bt_sock_wait_state +EXPORT_SYMBOL net/bluetooth/bluetooth 0xc2066af0 batostr +EXPORT_SYMBOL net/bluetooth/bluetooth 0xcc1fb551 baswap +EXPORT_SYMBOL net/bluetooth/bluetooth 0xe000b944 hci_conn_switch_role +EXPORT_SYMBOL net/bluetooth/bluetooth 0xe73f3018 hci_free_dev +EXPORT_SYMBOL net/bluetooth/bluetooth 0xf19294db bt_sock_unregister +EXPORT_SYMBOL net/bluetooth/bluetooth 0xfa86224b bt_sock_register +EXPORT_SYMBOL net/bluetooth/l2cap 0xfc31fe88 l2cap_load +EXPORT_SYMBOL net/bridge/bridge 0x6490d476 br_should_route_hook +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x156d4094 ebt_unregister_watcher +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x5e5e36eb ebt_register_table +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x645b14ec ebt_unregister_target +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x85565456 ebt_register_watcher +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0x8c519b7a ebt_unregister_match +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0xbcd9eebb ebt_unregister_table +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0xc6fee6e4 ebt_register_match +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0xc7ec82df ebt_register_target +EXPORT_SYMBOL net/bridge/netfilter/ebtables 0xf0966dc3 ebt_do_table +EXPORT_SYMBOL net/ieee80211/ieee80211 0x14d61d7b ieee80211_wx_get_encode +EXPORT_SYMBOL net/ieee80211/ieee80211 0x1f19db99 ieee80211_txb_free +EXPORT_SYMBOL net/ieee80211/ieee80211 0x333e9afa ieee80211_wx_get_scan +EXPORT_SYMBOL net/ieee80211/ieee80211 0x68ab885d ieee80211_get_geo +EXPORT_SYMBOL net/ieee80211/ieee80211 0x6a5e8b8f ieee80211_wx_set_encode +EXPORT_SYMBOL net/ieee80211/ieee80211 0x6ff5c858 ieee80211_get_channel_flags +EXPORT_SYMBOL net/ieee80211/ieee80211 0x790edbc5 ieee80211_get_channel +EXPORT_SYMBOL net/ieee80211/ieee80211 0x86a05709 ieee80211_wx_get_encodeext +EXPORT_SYMBOL net/ieee80211/ieee80211 0x976076fc ieee80211_rx_mgt +EXPORT_SYMBOL net/ieee80211/ieee80211 0x9af579a5 alloc_ieee80211 +EXPORT_SYMBOL net/ieee80211/ieee80211 0x9d0cd3f7 ieee80211_channel_to_index +EXPORT_SYMBOL net/ieee80211/ieee80211 0xa56e06bc ieee80211_is_valid_channel +EXPORT_SYMBOL net/ieee80211/ieee80211 0xa8b8c448 ieee80211_freq_to_channel +EXPORT_SYMBOL net/ieee80211/ieee80211 0xa9fb135f escape_essid +EXPORT_SYMBOL net/ieee80211/ieee80211 0xaeef3e29 ieee80211_set_geo +EXPORT_SYMBOL net/ieee80211/ieee80211 0xe144d001 free_ieee80211 +EXPORT_SYMBOL net/ieee80211/ieee80211 0xf015aaf5 ieee80211_wx_set_encodeext +EXPORT_SYMBOL net/ieee80211/ieee80211 0xf1ca90aa ieee80211_channel_to_freq +EXPORT_SYMBOL net/ieee80211/ieee80211 0xff4d7406 ieee80211_rx +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x043cc01d ieee80211_crypt_quiescing +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x279e265f ieee80211_crypt_deinit_handler +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x2d7aa8f8 ieee80211_get_crypto_ops +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x4135c493 ieee80211_crypt_delayed_deinit +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x5d8f43ae ieee80211_register_crypto_ops +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0x93271ffc ieee80211_unregister_crypto_ops +EXPORT_SYMBOL net/ieee80211/ieee80211_crypt 0xfbbba599 ieee80211_crypt_deinit_entries +EXPORT_SYMBOL net/ipv4/inet_lro 0x2b86542c lro_vlan_hwaccel_receive_skb +EXPORT_SYMBOL net/ipv4/inet_lro 0x4ea839ef lro_flush_all +EXPORT_SYMBOL net/ipv4/inet_lro 0x6d595e75 lro_vlan_hwaccel_receive_frags +EXPORT_SYMBOL net/ipv4/inet_lro 0x7c6ac434 lro_flush_pkt +EXPORT_SYMBOL net/ipv4/inet_lro 0x9cfbf6c8 lro_receive_skb +EXPORT_SYMBOL net/ipv4/inet_lro 0xf2e5c239 lro_receive_frags +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x251a3a01 register_ip_vs_app_inc +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x29039c0a ip_vs_conn_new +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x4b8714bc register_ip_vs_scheduler +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x5b729b8e ip_vs_conn_out_get +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x762dd3f4 unregister_ip_vs_scheduler +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x7c57d3f2 ip_vs_tcp_conn_listen +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x98313633 ip_vs_skb_replace +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0x9ddc19ab register_ip_vs_app +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0xa1dbc2d8 ip_vs_proto_name +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0xa5f09b74 ip_vs_conn_put +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0xc202388b ip_vs_conn_in_get +EXPORT_SYMBOL net/ipv4/ipvs/ip_vs 0xd08bc1f9 unregister_ip_vs_app +EXPORT_SYMBOL net/ipv4/netfilter/arp_tables 0xaea94aab arpt_unregister_table +EXPORT_SYMBOL net/ipv4/netfilter/arp_tables 0xc0f28649 arpt_register_table +EXPORT_SYMBOL net/ipv4/netfilter/arp_tables 0xcd819d95 arpt_do_table +EXPORT_SYMBOL net/ipv4/netfilter/ip_tables 0x6d90b192 ipt_do_table +EXPORT_SYMBOL net/ipv4/netfilter/ip_tables 0xb6495ff6 ipt_unregister_table +EXPORT_SYMBOL net/ipv4/netfilter/ip_tables 0xe52f98a5 ipt_register_table +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0x093387d2 nf_nat_setup_info +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0x82498fce nf_nat_mangle_tcp_packet +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0xa2311568 nf_nat_protocol_unregister +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0xad7e2bce nf_nat_follow_master +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0xb0b79443 nf_nat_protocol_register +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0xcf5f7ac6 nf_nat_used_tuple +EXPORT_SYMBOL net/ipv4/netfilter/nf_nat 0xf8ea685a nf_nat_mangle_udp_packet +EXPORT_SYMBOL net/ipv4/tunnel4 0x1135f298 xfrm4_tunnel_register +EXPORT_SYMBOL net/ipv4/tunnel4 0xcd6b95bf xfrm4_tunnel_deregister +EXPORT_SYMBOL net/ipv6/ipv6 0x14b48c83 xfrm6_rcv +EXPORT_SYMBOL net/ipv6/ipv6 0x2df79d8c ip6_frag_init +EXPORT_SYMBOL net/ipv6/ipv6 0x30123eb5 icmpv6_statistics +EXPORT_SYMBOL net/ipv6/ipv6 0x40e4e3a9 ndisc_mc_map +EXPORT_SYMBOL net/ipv6/ipv6 0x432b94f4 compat_ipv6_getsockopt +EXPORT_SYMBOL net/ipv6/ipv6 0x459fdd5c inet6_add_protocol +EXPORT_SYMBOL net/ipv6/ipv6 0x502a94d0 ipv6_push_nfrag_opts +EXPORT_SYMBOL net/ipv6/ipv6 0x538383c0 unregister_inet6addr_notifier +EXPORT_SYMBOL net/ipv6/ipv6 0x5e05cd61 ip6_route_output +EXPORT_SYMBOL net/ipv6/ipv6 0x6a1a874d inet6_unregister_protosw +EXPORT_SYMBOL net/ipv6/ipv6 0x6d2ae8fb in6_dev_finish_destroy +EXPORT_SYMBOL net/ipv6/ipv6 0x79089826 inet6_ioctl +EXPORT_SYMBOL net/ipv6/ipv6 0x7e42ae69 xfrm6_rcv_spi +EXPORT_SYMBOL net/ipv6/ipv6 0x8130541e rt6_lookup +EXPORT_SYMBOL net/ipv6/ipv6 0x830ea66c xfrm6_prepare_output +EXPORT_SYMBOL net/ipv6/ipv6 0x865fae04 ip6_xmit +EXPORT_SYMBOL net/ipv6/ipv6 0x8804c527 compat_ipv6_setsockopt +EXPORT_SYMBOL net/ipv6/ipv6 0x9185e9e2 ip6_frag_match +EXPORT_SYMBOL net/ipv6/ipv6 0x9d51b0e3 xfrm6_find_1stfragopt +EXPORT_SYMBOL net/ipv6/ipv6 0xab4ac243 ipv6_getsockopt +EXPORT_SYMBOL net/ipv6/ipv6 0xb1167cb5 xfrm6_input_addr +EXPORT_SYMBOL net/ipv6/ipv6 0xb6298ea7 ipv6_chk_prefix +EXPORT_SYMBOL net/ipv6/ipv6 0xb905ad82 icmpv6_err_convert +EXPORT_SYMBOL net/ipv6/ipv6 0xbf77ac61 ip6_route_me_harder +EXPORT_SYMBOL net/ipv6/ipv6 0xc001615d inet6_register_protosw +EXPORT_SYMBOL net/ipv6/ipv6 0xcbe54708 ipv6_dev_get_saddr +EXPORT_SYMBOL net/ipv6/ipv6 0xccb5db18 ipv6_chk_addr +EXPORT_SYMBOL net/ipv6/ipv6 0xcdb507a2 inet6_bind +EXPORT_SYMBOL net/ipv6/ipv6 0xce19bac5 register_inet6addr_notifier +EXPORT_SYMBOL net/ipv6/ipv6 0xd5977f7e inet6_getname +EXPORT_SYMBOL net/ipv6/ipv6 0xdab6d09f inet6_release +EXPORT_SYMBOL net/ipv6/ipv6 0xdcda5ece ipv6_setsockopt +EXPORT_SYMBOL net/ipv6/ipv6 0xe1a81c3a icmpv6msg_statistics +EXPORT_SYMBOL net/ipv6/ipv6 0xe4163511 icmpv6_send +EXPORT_SYMBOL net/ipv6/ipv6 0xe690b8fd __ipv6_isatap_ifid +EXPORT_SYMBOL net/ipv6/ipv6 0xebccd8cd inet6_del_protocol +EXPORT_SYMBOL net/ipv6/ipv6 0xf20b6c1a nf_ip6_checksum +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0x078f144d ip6t_register_table +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0x7692945a ip6t_do_table +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0xb8bddf33 ip6t_ext_hdr +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0xc9012fc8 ip6t_unregister_table +EXPORT_SYMBOL net/ipv6/netfilter/ip6_tables 0xdbf88b36 ipv6_find_hdr +EXPORT_SYMBOL net/ipv6/tunnel6 0x2ef1ec69 xfrm6_tunnel_deregister +EXPORT_SYMBOL net/ipv6/tunnel6 0x4b40fb15 xfrm6_tunnel_register +EXPORT_SYMBOL net/ipv6/xfrm6_tunnel 0x9cd013f2 xfrm6_tunnel_alloc_spi +EXPORT_SYMBOL net/ipv6/xfrm6_tunnel 0xab14e193 xfrm6_tunnel_free_spi +EXPORT_SYMBOL net/ipv6/xfrm6_tunnel 0xdb1b42d1 xfrm6_tunnel_spi_lookup +EXPORT_SYMBOL net/irda/ircomm/ircomm 0x30de0805 ircomm_flow_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0x45e01f3e ircomm_close +EXPORT_SYMBOL net/irda/ircomm/ircomm 0x5405eaaa ircomm_data_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0x75589783 ircomm_connect_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0x8b7baa6b ircomm_disconnect_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0x994d10d3 ircomm_connect_response +EXPORT_SYMBOL net/irda/ircomm/ircomm 0xb25d0bb8 ircomm_control_request +EXPORT_SYMBOL net/irda/ircomm/ircomm 0xec1c5eac ircomm_open +EXPORT_SYMBOL net/irda/irda 0x01d1fcdb hashbin_delete +EXPORT_SYMBOL net/irda/irda 0x06a3ee58 irias_new_integer_value +EXPORT_SYMBOL net/irda/irda 0x072e026f irias_add_octseq_attrib +EXPORT_SYMBOL net/irda/irda 0x07d3647c irlmp_register_service +EXPORT_SYMBOL net/irda/irda 0x0aaafe02 irttp_dup +EXPORT_SYMBOL net/irda/irda 0x1e6abfe2 irttp_open_tsap +EXPORT_SYMBOL net/irda/irda 0x2036ad06 irda_param_insert +EXPORT_SYMBOL net/irda/irda 0x2717bc25 iriap_open +EXPORT_SYMBOL net/irda/irda 0x2895f6d4 irlmp_open_lsap +EXPORT_SYMBOL net/irda/irda 0x3462950f hashbin_remove +EXPORT_SYMBOL net/irda/irda 0x38a20e5b irda_debug +EXPORT_SYMBOL net/irda/irda 0x4186f1c9 irttp_disconnect_request +EXPORT_SYMBOL net/irda/irda 0x448b8aaa irda_qos_bits_to_value +EXPORT_SYMBOL net/irda/irda 0x46c1c4a2 irlmp_unregister_service +EXPORT_SYMBOL net/irda/irda 0x518ccd53 irlap_close +EXPORT_SYMBOL net/irda/irda 0x58356106 irttp_connect_request +EXPORT_SYMBOL net/irda/irda 0x670cbbbc irlmp_connect_request +EXPORT_SYMBOL net/irda/irda 0x6758f8ac irias_new_object +EXPORT_SYMBOL net/irda/irda 0x68b7447c hashbin_find +EXPORT_SYMBOL net/irda/irda 0x6b043eba irda_init_max_qos_capabilies +EXPORT_SYMBOL net/irda/irda 0x6dd0c96a irttp_connect_response +EXPORT_SYMBOL net/irda/irda 0x7042bc54 irlmp_register_client +EXPORT_SYMBOL net/irda/irda 0x72bc4cbf irlmp_disconnect_request +EXPORT_SYMBOL net/irda/irda 0x747d6779 irias_delete_object +EXPORT_SYMBOL net/irda/irda 0x7621e908 hashbin_insert +EXPORT_SYMBOL net/irda/irda 0x76243bc9 irias_insert_object +EXPORT_SYMBOL net/irda/irda 0x763e54a4 irlmp_unregister_client +EXPORT_SYMBOL net/irda/irda 0x76bfafae irda_notify_init +EXPORT_SYMBOL net/irda/irda 0x781e2db5 irias_find_object +EXPORT_SYMBOL net/irda/irda 0x7957f728 irlmp_update_client +EXPORT_SYMBOL net/irda/irda 0x7a57b6f3 hashbin_remove_this +EXPORT_SYMBOL net/irda/irda 0x8e9d6ebb irlmp_close_lsap +EXPORT_SYMBOL net/irda/irda 0x908bad75 irttp_data_request +EXPORT_SYMBOL net/irda/irda 0x90ab3819 iriap_getvaluebyclass_request +EXPORT_SYMBOL net/irda/irda 0x91815586 irda_param_pack +EXPORT_SYMBOL net/irda/irda 0x993ad14b irda_param_extract_all +EXPORT_SYMBOL net/irda/irda 0x9e5e780a irlmp_connect_response +EXPORT_SYMBOL net/irda/irda 0xa336963a async_wrap_skb +EXPORT_SYMBOL net/irda/irda 0xb9394173 irias_delete_value +EXPORT_SYMBOL net/irda/irda 0xbbf9cb84 irttp_flow_request +EXPORT_SYMBOL net/irda/irda 0xbc1a9922 iriap_close +EXPORT_SYMBOL net/irda/irda 0xbcd3ef13 irias_object_change_attribute +EXPORT_SYMBOL net/irda/irda 0xbe40ace9 irlmp_discovery_request +EXPORT_SYMBOL net/irda/irda 0xc14e9b6a hashbin_get_next +EXPORT_SYMBOL net/irda/irda 0xc14f0dbd alloc_irdadev +EXPORT_SYMBOL net/irda/irda 0xc5e7ef83 async_unwrap_char +EXPORT_SYMBOL net/irda/irda 0xcb3d3f3b irda_device_set_media_busy +EXPORT_SYMBOL net/irda/irda 0xcb83e5b9 irttp_close_tsap +EXPORT_SYMBOL net/irda/irda 0xcd41236c hashbin_new +EXPORT_SYMBOL net/irda/irda 0xd6deeaae irda_setup_dma +EXPORT_SYMBOL net/irda/irda 0xd7172ff4 hashbin_get_first +EXPORT_SYMBOL net/irda/irda 0xd824e355 irttp_udata_request +EXPORT_SYMBOL net/irda/irda 0xd8bfb6d4 hashbin_lock_find +EXPORT_SYMBOL net/irda/irda 0xdce38bb1 irlap_open +EXPORT_SYMBOL net/irda/irda 0xde4c6b3c irlmp_service_to_hint +EXPORT_SYMBOL net/irda/irda 0xe0fa1417 irlmp_data_request +EXPORT_SYMBOL net/irda/irda 0xe4357a0f proc_irda +EXPORT_SYMBOL net/irda/irda 0xe5260e0e irias_add_integer_attrib +EXPORT_SYMBOL net/irda/irda 0xec41fe7f irias_add_string_attrib +EXPORT_SYMBOL net/irda/irda 0xedd521c2 irlmp_get_discoveries +EXPORT_SYMBOL net/lapb/lapb 0x05584f2a lapb_getparms +EXPORT_SYMBOL net/lapb/lapb 0x1d7451d4 lapb_disconnect_request +EXPORT_SYMBOL net/lapb/lapb 0x2359b04e lapb_register +EXPORT_SYMBOL net/lapb/lapb 0x41c430aa lapb_connect_request +EXPORT_SYMBOL net/lapb/lapb 0x63766318 lapb_unregister +EXPORT_SYMBOL net/lapb/lapb 0x84496cc5 lapb_setparms +EXPORT_SYMBOL net/lapb/lapb 0xb8e2dff9 lapb_data_received +EXPORT_SYMBOL net/lapb/lapb 0xe85268db lapb_data_request +EXPORT_SYMBOL net/mac80211/mac80211 0x1e6c8ea4 ieee80211_unregister_hw +EXPORT_SYMBOL net/mac80211/mac80211 0x202664ec ieee80211_rts_duration +EXPORT_SYMBOL net/mac80211/mac80211 0x22413910 ieee80211_ctstoself_get +EXPORT_SYMBOL net/mac80211/mac80211 0x2849a5ce ieee80211_free_hw +EXPORT_SYMBOL net/mac80211/mac80211 0x29632737 __ieee80211_get_rx_led_name +EXPORT_SYMBOL net/mac80211/mac80211 0x3cc6c385 ieee80211_rx_irqsafe +EXPORT_SYMBOL net/mac80211/mac80211 0x3dc3b989 ieee80211_wake_queues +EXPORT_SYMBOL net/mac80211/mac80211 0x47c37e4f ieee80211_stop_tx_ba_cb_irqsafe +EXPORT_SYMBOL net/mac80211/mac80211 0x49ef338b ieee80211_get_hdrlen +EXPORT_SYMBOL net/mac80211/mac80211 0x51d6d5a5 ieee80211_beacon_get +EXPORT_SYMBOL net/mac80211/mac80211 0x56253610 ieee80211_tx_status +EXPORT_SYMBOL net/mac80211/mac80211 0x567ef4cc ieee80211_stop_queue +EXPORT_SYMBOL net/mac80211/mac80211 0x6ddc0fba ieee80211_rate_control_unregister +EXPORT_SYMBOL net/mac80211/mac80211 0x72f9bd88 sta_info_get +EXPORT_SYMBOL net/mac80211/mac80211 0x76f9b9ff ieee80211_start_tx_ba_cb_irqsafe +EXPORT_SYMBOL net/mac80211/mac80211 0x8875cf48 ieee80211_wake_queue +EXPORT_SYMBOL net/mac80211/mac80211 0x8928213a ieee80211_get_hdrlen_from_skb +EXPORT_SYMBOL net/mac80211/mac80211 0x89353a08 ieee80211_tx_status_irqsafe +EXPORT_SYMBOL net/mac80211/mac80211 0x8c35d732 ieee80211_hdrlen +EXPORT_SYMBOL net/mac80211/mac80211 0x90816a3b ieee80211_start_tx_ba_session +EXPORT_SYMBOL net/mac80211/mac80211 0x932ac41f ieee80211_generic_frame_duration +EXPORT_SYMBOL net/mac80211/mac80211 0x9793d408 __ieee80211_rx +EXPORT_SYMBOL net/mac80211/mac80211 0x9f26255f ieee80211_stop_tx_ba_session +EXPORT_SYMBOL net/mac80211/mac80211 0xa1816607 ieee80211_stop_queues +EXPORT_SYMBOL net/mac80211/mac80211 0xa26462a4 __ieee80211_get_radio_led_name +EXPORT_SYMBOL net/mac80211/mac80211 0xb2967d8d ieee80211_register_hw +EXPORT_SYMBOL net/mac80211/mac80211 0xc3ece5c9 ieee80211_ctstoself_duration +EXPORT_SYMBOL net/mac80211/mac80211 0xc4001f78 ieee80211_start_tx_ba_cb +EXPORT_SYMBOL net/mac80211/mac80211 0xc80b9175 ieee80211_rate_control_register +EXPORT_SYMBOL net/mac80211/mac80211 0xcd5a99e1 ieee80211_scan_completed +EXPORT_SYMBOL net/mac80211/mac80211 0xd0feaad1 __ieee80211_get_assoc_led_name +EXPORT_SYMBOL net/mac80211/mac80211 0xd11dc96b __ieee80211_get_tx_led_name +EXPORT_SYMBOL net/mac80211/mac80211 0xd4451b16 ieee80211_get_buffered_bc +EXPORT_SYMBOL net/mac80211/mac80211 0xda68ba85 ieee80211_get_tkip_key +EXPORT_SYMBOL net/mac80211/mac80211 0xe4ae72d8 ieee80211_stop_tx_ba_cb +EXPORT_SYMBOL net/mac80211/mac80211 0xedd80dce ieee80211_alloc_hw +EXPORT_SYMBOL net/mac80211/mac80211 0xee915e66 ieee80211_rts_get +EXPORT_SYMBOL net/mac80211/mac80211 0xff7678f1 ieee80211_notify_mac +EXPORT_SYMBOL net/netfilter/nf_conntrack 0x8fb4ee7a __nf_ct_ext_destroy +EXPORT_SYMBOL net/netfilter/nf_conntrack 0xe372c1b6 __nf_ct_ext_add +EXPORT_SYMBOL net/netfilter/nf_conntrack 0xed23741c per_cpu__nf_conntrack_stat +EXPORT_SYMBOL net/netfilter/nf_conntrack_proto_gre 0x82f94e40 nf_ct_gre_keymap_flush +EXPORT_SYMBOL net/netfilter/x_tables 0x0ce22d7f xt_unregister_matches +EXPORT_SYMBOL net/netfilter/x_tables 0x115bdb59 xt_register_match +EXPORT_SYMBOL net/netfilter/x_tables 0x17f348be xt_register_matches +EXPORT_SYMBOL net/netfilter/x_tables 0x199b8b5a xt_find_match +EXPORT_SYMBOL net/netfilter/x_tables 0x2a017b7d xt_unregister_match +EXPORT_SYMBOL net/netfilter/x_tables 0x3dcd58c5 xt_alloc_table_info +EXPORT_SYMBOL net/netfilter/x_tables 0x61e3a8c8 xt_find_target +EXPORT_SYMBOL net/netfilter/x_tables 0x68b356ec xt_unregister_targets +EXPORT_SYMBOL net/netfilter/x_tables 0xa2d46f13 xt_unregister_target +EXPORT_SYMBOL net/netfilter/x_tables 0xd0e6ea75 xt_register_target +EXPORT_SYMBOL net/netfilter/x_tables 0xef73b569 xt_register_targets +EXPORT_SYMBOL net/netfilter/x_tables 0xf7037dc6 xt_free_table_info +EXPORT_SYMBOL net/rfkill/rfkill 0x00caa4dc rfkill_switch_all +EXPORT_SYMBOL net/rfkill/rfkill 0x39b8d0b4 rfkill_force_state +EXPORT_SYMBOL net/rfkill/rfkill 0x922403d1 rfkill_register +EXPORT_SYMBOL net/rfkill/rfkill 0x970421d5 rfkill_allocate +EXPORT_SYMBOL net/rfkill/rfkill 0xa8ca9fb3 rfkill_free +EXPORT_SYMBOL net/rfkill/rfkill 0xffe113fb rfkill_unregister +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x1bda303a rxrpc_kernel_data_delivered +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x1e050a28 key_type_rxrpc +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x2157c2e9 rxrpc_kernel_end_call +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x2a6985e1 rxrpc_kernel_reject_call +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x3734e657 rxrpc_kernel_get_abort_code +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x42f42197 rxrpc_kernel_is_data_last +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x535d8e53 rxrpc_get_server_data_key +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x8c71d610 rxrpc_kernel_free_skb +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0x967cfb8c rxrpc_kernel_intercept_rx_messages +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xae046a2a rxrpc_get_null_key +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xb5c8c320 rxrpc_kernel_abort_call +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xbc6a796d rxrpc_kernel_send_data +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xc19dfdeb rxrpc_kernel_accept_call +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xe05c051e rxrpc_kernel_get_error_number +EXPORT_SYMBOL net/rxrpc/af-rxrpc 0xeacf6a81 rxrpc_kernel_begin_call +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x00c52ef5 g_make_token_header +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x0216792c gss_mech_get_by_name +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x19dfee39 gss_svc_to_pseudoflavor +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x44ee4b5b gss_mech_register +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x5aa3ff67 gss_mech_get_by_pseudoflavor +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0x8d1a827e svcauth_gss_register_pseudoflavor +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xa5de67ca gss_mech_get +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xb25af472 gss_pseudoflavor_to_service +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xb5dea7ef g_token_size +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xba56b978 gss_mech_put +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xd85a1e88 gss_service_to_auth_domain_name +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xdf39e5cb svcauth_gss_flavor +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xed9de267 gss_mech_unregister +EXPORT_SYMBOL net/sunrpc/auth_gss/auth_rpcgss 0xf8b2ff6e g_verify_token_header +EXPORT_SYMBOL net/sunrpc/sunrpc 0x05e807a9 xdr_encode_string +EXPORT_SYMBOL net/sunrpc/sunrpc 0x065994f1 xdr_encode_opaque_fixed +EXPORT_SYMBOL net/sunrpc/sunrpc 0x09d32528 xdr_inline_decode +EXPORT_SYMBOL net/sunrpc/sunrpc 0x0eb45819 svc_destroy +EXPORT_SYMBOL net/sunrpc/sunrpc 0x0f668ba9 svc_auth_unregister +EXPORT_SYMBOL net/sunrpc/sunrpc 0x0f94e9fb xdr_init_encode +EXPORT_SYMBOL net/sunrpc/sunrpc 0x10201749 xdr_buf_read_netobj +EXPORT_SYMBOL net/sunrpc/sunrpc 0x103495f6 svc_auth_register +EXPORT_SYMBOL net/sunrpc/sunrpc 0x12e280e3 svc_proc_unregister +EXPORT_SYMBOL net/sunrpc/sunrpc 0x1eee46e1 svc_create +EXPORT_SYMBOL net/sunrpc/sunrpc 0x20c4f49c svc_process +EXPORT_SYMBOL net/sunrpc/sunrpc 0x25e17ced auth_unix_add_addr +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2709c490 xdr_inline_pages +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2805597e xdr_read_pages +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2919b156 xdr_decode_string_inplace +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2c9cbb2e xdr_encode_word +EXPORT_SYMBOL net/sunrpc/sunrpc 0x2eec63c9 xdr_encode_netobj +EXPORT_SYMBOL net/sunrpc/sunrpc 0x30da676f rpc_queue_upcall +EXPORT_SYMBOL net/sunrpc/sunrpc 0x34e53e75 xdr_buf_from_iov +EXPORT_SYMBOL net/sunrpc/sunrpc 0x3b6e7d57 svc_sock_names +EXPORT_SYMBOL net/sunrpc/sunrpc 0x3f8773e9 rpc_mkpipe +EXPORT_SYMBOL net/sunrpc/sunrpc 0x4013b034 cache_register +EXPORT_SYMBOL net/sunrpc/sunrpc 0x447ee341 xdr_write_pages +EXPORT_SYMBOL net/sunrpc/sunrpc 0x52a297bd auth_unix_lookup +EXPORT_SYMBOL net/sunrpc/sunrpc 0x597b1c5d xdr_shift_buf +EXPORT_SYMBOL net/sunrpc/sunrpc 0x5997bf0e unix_domain_find +EXPORT_SYMBOL net/sunrpc/sunrpc 0x5cb64696 svc_prepare_thread +EXPORT_SYMBOL net/sunrpc/sunrpc 0x60792270 cache_unregister +EXPORT_SYMBOL net/sunrpc/sunrpc 0x636e3a0e xdr_process_buf +EXPORT_SYMBOL net/sunrpc/sunrpc 0x639898ad sunrpc_cache_lookup +EXPORT_SYMBOL net/sunrpc/sunrpc 0x6eea229d svcauth_unix_purge +EXPORT_SYMBOL net/sunrpc/sunrpc 0x711cf05b svc_sock_update_bufs +EXPORT_SYMBOL net/sunrpc/sunrpc 0x71fa908a cache_flush +EXPORT_SYMBOL net/sunrpc/sunrpc 0x7417bfeb auth_domain_lookup +EXPORT_SYMBOL net/sunrpc/sunrpc 0x74cc2685 auth_domain_put +EXPORT_SYMBOL net/sunrpc/sunrpc 0x74d7cecb sunrpc_cache_update +EXPORT_SYMBOL net/sunrpc/sunrpc 0x7697c611 svc_exit_thread +EXPORT_SYMBOL net/sunrpc/sunrpc 0x83870535 svc_set_client +EXPORT_SYMBOL net/sunrpc/sunrpc 0x89d9626a svc_seq_show +EXPORT_SYMBOL net/sunrpc/sunrpc 0x8f59b775 read_bytes_from_xdr_buf +EXPORT_SYMBOL net/sunrpc/sunrpc 0x91c0cf27 xdr_init_decode +EXPORT_SYMBOL net/sunrpc/sunrpc 0x95787501 auth_unix_forget_old +EXPORT_SYMBOL net/sunrpc/sunrpc 0x9abf1ac1 svc_proc_register +EXPORT_SYMBOL net/sunrpc/sunrpc 0x9d02d58e rpc_unlink +EXPORT_SYMBOL net/sunrpc/sunrpc 0x9ea98931 xdr_enter_page +EXPORT_SYMBOL net/sunrpc/sunrpc 0xa89a8d7d xdr_decode_array2 +EXPORT_SYMBOL net/sunrpc/sunrpc 0xaf727587 svc_create_pooled +EXPORT_SYMBOL net/sunrpc/sunrpc 0xb64e0a6a xdr_decode_word +EXPORT_SYMBOL net/sunrpc/sunrpc 0xbcec48a9 svc_set_num_threads +EXPORT_SYMBOL net/sunrpc/sunrpc 0xc3880471 xdr_decode_netobj +EXPORT_SYMBOL net/sunrpc/sunrpc 0xc4bccd95 svc_reserve +EXPORT_SYMBOL net/sunrpc/sunrpc 0xc6caf040 xdr_buf_subsegment +EXPORT_SYMBOL net/sunrpc/sunrpc 0xc8e96dea qword_addhex +EXPORT_SYMBOL net/sunrpc/sunrpc 0xc9d73990 svc_drop +EXPORT_SYMBOL net/sunrpc/sunrpc 0xcc1c6233 auth_domain_find +EXPORT_SYMBOL net/sunrpc/sunrpc 0xccc1778e xdr_encode_pages +EXPORT_SYMBOL net/sunrpc/sunrpc 0xd45bc2e5 svcauth_unix_set_client +EXPORT_SYMBOL net/sunrpc/sunrpc 0xd4ffe391 svc_authenticate +EXPORT_SYMBOL net/sunrpc/sunrpc 0xdf927045 xdr_reserve_space +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe1700352 xdr_encode_array2 +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe5919cb1 xdr_encode_opaque +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe74fdbd0 cache_check +EXPORT_SYMBOL net/sunrpc/sunrpc 0xe97f4ce5 qword_get +EXPORT_SYMBOL net/sunrpc/sunrpc 0xeaa75333 svc_wake_up +EXPORT_SYMBOL net/sunrpc/sunrpc 0xedc3058e svc_recv +EXPORT_SYMBOL net/sunrpc/sunrpc 0xedcf6be4 qword_add +EXPORT_SYMBOL net/sunrpc/sunrpc 0xf079be86 cache_purge +EXPORT_SYMBOL net/tipc/tipc 0x08acf310 tipc_available_nodes +EXPORT_SYMBOL net/tipc/tipc 0x0b074a7b tipc_multicast +EXPORT_SYMBOL net/tipc/tipc 0x10d40fcd tipc_isconnected +EXPORT_SYMBOL net/tipc/tipc 0x1472b270 tipc_disconnect +EXPORT_SYMBOL net/tipc/tipc 0x1479cb03 tipc_deleteport +EXPORT_SYMBOL net/tipc/tipc 0x15b5ecde tipc_set_portunreliable +EXPORT_SYMBOL net/tipc/tipc 0x16f27683 tipc_block_bearer +EXPORT_SYMBOL net/tipc/tipc 0x23daecbd tipc_send +EXPORT_SYMBOL net/tipc/tipc 0x259b74f9 tipc_acknowledge +EXPORT_SYMBOL net/tipc/tipc 0x310d1bc9 tipc_detach +EXPORT_SYMBOL net/tipc/tipc 0x316e4054 tipc_send_buf +EXPORT_SYMBOL net/tipc/tipc 0x3712e340 tipc_portunreliable +EXPORT_SYMBOL net/tipc/tipc 0x37bf0dcb tipc_createport +EXPORT_SYMBOL net/tipc/tipc 0x3976041f tipc_set_portimportance +EXPORT_SYMBOL net/tipc/tipc 0x3ab760d5 tipc_reject_msg +EXPORT_SYMBOL net/tipc/tipc 0x419b02fc tipc_send2port +EXPORT_SYMBOL net/tipc/tipc 0x46c3cb95 tipc_send_buf_fast +EXPORT_SYMBOL net/tipc/tipc 0x4b2243c6 tipc_portimportance +EXPORT_SYMBOL net/tipc/tipc 0x538b228a tipc_withdraw +EXPORT_SYMBOL net/tipc/tipc 0x5637ed44 tipc_get_mode +EXPORT_SYMBOL net/tipc/tipc 0x56e52bc1 tipc_continue +EXPORT_SYMBOL net/tipc/tipc 0x5c0d4b5c tipc_ref_valid +EXPORT_SYMBOL net/tipc/tipc 0x62a681a3 tipc_portunreturnable +EXPORT_SYMBOL net/tipc/tipc 0x76bda8d3 tipc_send_buf2name +EXPORT_SYMBOL net/tipc/tipc 0x869b78ef tipc_recv_msg +EXPORT_SYMBOL net/tipc/tipc 0x88b73627 tipc_get_addr +EXPORT_SYMBOL net/tipc/tipc 0x933be652 tipc_send_buf2port +EXPORT_SYMBOL net/tipc/tipc 0x9c45558e tipc_enable_bearer +EXPORT_SYMBOL net/tipc/tipc 0xa1b42d32 tipc_forward2port +EXPORT_SYMBOL net/tipc/tipc 0xa936a24b tipc_get_port +EXPORT_SYMBOL net/tipc/tipc 0xadd203d0 tipc_connect2port +EXPORT_SYMBOL net/tipc/tipc 0xae0103c3 tipc_shutdown +EXPORT_SYMBOL net/tipc/tipc 0xb1f8eacc tipc_send2name +EXPORT_SYMBOL net/tipc/tipc 0xb35b672c tipc_publish +EXPORT_SYMBOL net/tipc/tipc 0xbcb3874d tipc_register_media +EXPORT_SYMBOL net/tipc/tipc 0xc4063085 tipc_forward_buf2name +EXPORT_SYMBOL net/tipc/tipc 0xcec8514a tipc_set_portunreturnable +EXPORT_SYMBOL net/tipc/tipc 0xcee290be tipc_forward2name +EXPORT_SYMBOL net/tipc/tipc 0xd44731e5 tipc_ownidentity +EXPORT_SYMBOL net/tipc/tipc 0xda7f9d3f tipc_attach +EXPORT_SYMBOL net/tipc/tipc 0xdf5008fc tipc_peer +EXPORT_SYMBOL net/tipc/tipc 0xe1a669d5 tipc_forward_buf2port +EXPORT_SYMBOL net/tipc/tipc 0xe7aece47 tipc_ispublished +EXPORT_SYMBOL net/tipc/tipc 0xeacad92e tipc_createport_raw +EXPORT_SYMBOL net/tipc/tipc 0xeefd49b3 tipc_get_handle +EXPORT_SYMBOL net/tipc/tipc 0xef50a1ef tipc_disable_bearer +EXPORT_SYMBOL net/wanrouter/wanrouter 0x0ebe03d1 unregister_wan_device +EXPORT_SYMBOL net/wanrouter/wanrouter 0x7d0e8206 register_wan_device +EXPORT_SYMBOL net/wireless/cfg80211 0x07e7ac5a ieee80211_radiotap_iterator_init +EXPORT_SYMBOL net/wireless/cfg80211 0x09c64fbd ieee80211_frequency_to_channel +EXPORT_SYMBOL net/wireless/cfg80211 0x2acfec9a wiphy_free +EXPORT_SYMBOL net/wireless/cfg80211 0x5b810249 wiphy_unregister +EXPORT_SYMBOL net/wireless/cfg80211 0x679ee52d wiphy_register +EXPORT_SYMBOL net/wireless/cfg80211 0x99d10488 wiphy_new +EXPORT_SYMBOL net/wireless/cfg80211 0xc4e85ec5 ieee80211_radiotap_iterator_next +EXPORT_SYMBOL net/wireless/cfg80211 0xccc291b3 ieee80211_channel_to_frequency +EXPORT_SYMBOL net/wireless/cfg80211 0xef5e4ef4 __ieee80211_get_channel +EXPORT_SYMBOL sound/ac97_bus 0xa370459a ac97_bus_type +EXPORT_SYMBOL sound/core/oss/snd-mixer-oss 0x9a20006c snd_mixer_oss_ioctl_card +EXPORT_SYMBOL sound/core/seq/snd-seq 0x1a724fcc snd_seq_kernel_client_ctl +EXPORT_SYMBOL sound/core/seq/snd-seq 0x3061c52d snd_use_lock_sync_helper +EXPORT_SYMBOL sound/core/seq/snd-seq 0x3fb4d161 snd_seq_kernel_client_dispatch +EXPORT_SYMBOL sound/core/seq/snd-seq 0x6bb71038 snd_seq_delete_kernel_client +EXPORT_SYMBOL sound/core/seq/snd-seq 0x7ac2f329 snd_seq_expand_var_event +EXPORT_SYMBOL sound/core/seq/snd-seq 0x7b8699eb snd_seq_event_port_detach +EXPORT_SYMBOL sound/core/seq/snd-seq 0x89fac170 snd_seq_event_port_attach +EXPORT_SYMBOL sound/core/seq/snd-seq 0xa824614f snd_seq_kernel_client_write_poll +EXPORT_SYMBOL sound/core/seq/snd-seq 0xb8e448a0 snd_seq_set_queue_tempo +EXPORT_SYMBOL sound/core/seq/snd-seq 0xcac0a3be snd_seq_kernel_client_enqueue +EXPORT_SYMBOL sound/core/seq/snd-seq 0xd923bef5 snd_seq_kernel_client_enqueue_blocking +EXPORT_SYMBOL sound/core/seq/snd-seq 0xe8ee99d2 snd_seq_create_kernel_client +EXPORT_SYMBOL sound/core/seq/snd-seq 0xe934da1d snd_seq_dump_var_event +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0x3a57f235 snd_seq_autoload_unlock +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0x3d531a53 snd_seq_device_register_driver +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0x6339b6d0 snd_seq_device_load_drivers +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0xb90668b2 snd_seq_autoload_lock +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0xc622fb29 snd_seq_device_unregister_driver +EXPORT_SYMBOL sound/core/seq/snd-seq-device 0xdf762f15 snd_seq_device_new +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-emul 0x6ea09972 snd_midi_channel_alloc_set +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-emul 0x833a3e07 snd_midi_channel_set_clear +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-emul 0xb9948d2c snd_midi_channel_free_set +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-emul 0xf0a1fdb3 snd_midi_process_event +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x17c15809 snd_midi_event_decode +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x4ad3f518 snd_midi_event_reset_decode +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x62384d3a snd_midi_event_encode +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x8a348811 snd_midi_event_reset_encode +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0x9df7af8b snd_midi_event_free +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0xc482499d snd_midi_event_new +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0xd9072e1a snd_midi_event_no_status +EXPORT_SYMBOL sound/core/seq/snd-seq-midi-event 0xe6df29c7 snd_midi_event_encode_byte +EXPORT_SYMBOL sound/core/seq/snd-seq-virmidi 0x653056ef snd_virmidi_new +EXPORT_SYMBOL sound/core/snd 0x1387d4bf snd_cards +EXPORT_SYMBOL sound/core/snd 0x18e1683f snd_dma_program +EXPORT_SYMBOL sound/core/snd 0x191e88cf snd_dma_pointer +EXPORT_SYMBOL sound/core/snd 0x198788b4 snd_lookup_oss_minor_data +EXPORT_SYMBOL sound/core/snd 0x212f08c6 snd_card_free_when_closed +EXPORT_SYMBOL sound/core/snd 0x21c83b7a snd_ctl_remove +EXPORT_SYMBOL sound/core/snd 0x22a92354 snd_card_register +EXPORT_SYMBOL sound/core/snd 0x24a94b26 snd_info_get_line +EXPORT_SYMBOL sound/core/snd 0x25bb2d3b snd_device_new +EXPORT_SYMBOL sound/core/snd 0x2b92b250 snd_seq_root +EXPORT_SYMBOL sound/core/snd 0x319e9bcc snd_ctl_boolean_mono_info +EXPORT_SYMBOL sound/core/snd 0x376e04bf release_and_free_resource +EXPORT_SYMBOL sound/core/snd 0x3971b4df snd_ecards_limit +EXPORT_SYMBOL sound/core/snd 0x3eb94fd0 snd_ctl_find_numid +EXPORT_SYMBOL sound/core/snd 0x3efacc50 snd_ctl_notify +EXPORT_SYMBOL sound/core/snd 0x3f6a3e4a snd_card_file_add +EXPORT_SYMBOL sound/core/snd 0x40a0a0a9 snd_add_device_sysfs_file +EXPORT_SYMBOL sound/core/snd 0x4a3ea5c0 snd_request_card +EXPORT_SYMBOL sound/core/snd 0x4acc7735 snd_ctl_add +EXPORT_SYMBOL sound/core/snd 0x4ca8165a snd_register_device_for_dev +EXPORT_SYMBOL sound/core/snd 0x50b3d6f6 snd_info_create_card_entry +EXPORT_SYMBOL sound/core/snd 0x518bb7f8 copy_from_user_toio +EXPORT_SYMBOL sound/core/snd 0x56c75344 snd_unregister_device +EXPORT_SYMBOL sound/core/snd 0x5bea928a snd_card_free +EXPORT_SYMBOL sound/core/snd 0x5e21c2a5 snd_card_proc_new +EXPORT_SYMBOL sound/core/snd 0x70c15ac1 snd_dma_disable +EXPORT_SYMBOL sound/core/snd 0x725682fb snd_ctl_new1 +EXPORT_SYMBOL sound/core/snd 0x75491c41 snd_card_new +EXPORT_SYMBOL sound/core/snd 0x781921f3 snd_ctl_unregister_ioctl +EXPORT_SYMBOL sound/core/snd 0x7882b674 snd_device_register +EXPORT_SYMBOL sound/core/snd 0x79e802f0 snd_info_create_module_entry +EXPORT_SYMBOL sound/core/snd 0x83dd3f44 snd_ctl_boolean_stereo_info +EXPORT_SYMBOL sound/core/snd 0x8df3789f snd_oss_info_register +EXPORT_SYMBOL sound/core/snd 0x8f595b11 snd_major +EXPORT_SYMBOL sound/core/snd 0x9580466f snd_component_add +EXPORT_SYMBOL sound/core/snd 0x9841887a snd_pci_quirk_lookup +EXPORT_SYMBOL sound/core/snd 0xa23a0df2 snd_mixer_oss_notify_callback +EXPORT_SYMBOL sound/core/snd 0xa4536e8a snd_power_wait +EXPORT_SYMBOL sound/core/snd 0xa7624412 snd_ctl_unregister_ioctl_compat +EXPORT_SYMBOL sound/core/snd 0xa797fd2d snd_ctl_find_id +EXPORT_SYMBOL sound/core/snd 0xa7d10983 snd_card_disconnect +EXPORT_SYMBOL sound/core/snd 0xaa27e543 snd_unregister_oss_device +EXPORT_SYMBOL sound/core/snd 0xb213fe8b snd_info_get_str +EXPORT_SYMBOL sound/core/snd 0xb2e5ae4a snd_lookup_minor_data +EXPORT_SYMBOL sound/core/snd 0xc2083274 snd_card_file_remove +EXPORT_SYMBOL sound/core/snd 0xc4981435 snd_info_free_entry +EXPORT_SYMBOL sound/core/snd 0xcac4d5bc snd_ctl_make_virtual_master +EXPORT_SYMBOL sound/core/snd 0xda520747 snd_ctl_register_ioctl_compat +EXPORT_SYMBOL sound/core/snd 0xe1946b77 snd_ctl_add_slave +EXPORT_SYMBOL sound/core/snd 0xe243dde3 copy_to_user_fromio +EXPORT_SYMBOL sound/core/snd 0xe4854cea snd_iprintf +EXPORT_SYMBOL sound/core/snd 0xeccfb06a snd_ctl_rename_id +EXPORT_SYMBOL sound/core/snd 0xf217c251 snd_ctl_register_ioctl +EXPORT_SYMBOL sound/core/snd 0xf32ce321 snd_register_oss_device +EXPORT_SYMBOL sound/core/snd 0xf7210cf7 snd_ctl_free_one +EXPORT_SYMBOL sound/core/snd 0xf7faccf0 snd_device_free +EXPORT_SYMBOL sound/core/snd 0xfb7b1f5e snd_info_register +EXPORT_SYMBOL sound/core/snd 0xfd38e632 snd_ctl_remove_id +EXPORT_SYMBOL sound/core/snd-hwdep 0x557d3626 snd_hwdep_new +EXPORT_SYMBOL sound/core/snd-page-alloc 0x17e7ccaf snd_dma_alloc_pages_fallback +EXPORT_SYMBOL sound/core/snd-page-alloc 0x19cc2ce3 snd_free_pages +EXPORT_SYMBOL sound/core/snd-page-alloc 0x682905e9 snd_dma_alloc_pages +EXPORT_SYMBOL sound/core/snd-page-alloc 0x7b7daac3 snd_dma_reserve_buf +EXPORT_SYMBOL sound/core/snd-page-alloc 0x929f75da snd_dma_get_reserved_buf +EXPORT_SYMBOL sound/core/snd-page-alloc 0x97070bfa snd_dma_free_pages +EXPORT_SYMBOL sound/core/snd-page-alloc 0xc6829020 snd_malloc_pages +EXPORT_SYMBOL sound/core/snd-pcm 0x04cda566 snd_interval_refine +EXPORT_SYMBOL sound/core/snd-pcm 0x11814411 snd_pcm_lib_ioctl +EXPORT_SYMBOL sound/core/snd-pcm 0x1d027e4b snd_pcm_format_signed +EXPORT_SYMBOL sound/core/snd-pcm 0x2034d2e3 snd_pcm_lib_writev +EXPORT_SYMBOL sound/core/snd-pcm 0x219d20c7 snd_pcm_mmap_data +EXPORT_SYMBOL sound/core/snd-pcm 0x22f48703 snd_pcm_hw_constraint_list +EXPORT_SYMBOL sound/core/snd-pcm 0x230cc1d0 snd_pcm_hw_rule_add +EXPORT_SYMBOL sound/core/snd-pcm 0x3017b209 snd_pcm_lib_preallocate_pages_for_all +EXPORT_SYMBOL sound/core/snd-pcm 0x32abb656 snd_pcm_release_substream +EXPORT_SYMBOL sound/core/snd-pcm 0x3796bdcc snd_pcm_format_little_endian +EXPORT_SYMBOL sound/core/snd-pcm 0x419223d6 snd_pcm_new_stream +EXPORT_SYMBOL sound/core/snd-pcm 0x4dec81c7 snd_pcm_lib_read +EXPORT_SYMBOL sound/core/snd-pcm 0x4f816e9b snd_pcm_format_big_endian +EXPORT_SYMBOL sound/core/snd-pcm 0x55bd9ee4 snd_pcm_hw_constraint_integer +EXPORT_SYMBOL sound/core/snd-pcm 0x590bef13 snd_pcm_lib_write +EXPORT_SYMBOL sound/core/snd-pcm 0x5e7f4920 snd_pcm_format_set_silence +EXPORT_SYMBOL sound/core/snd-pcm 0x604bb022 snd_pcm_new +EXPORT_SYMBOL sound/core/snd-pcm 0x650f8603 snd_pcm_format_silence_64 +EXPORT_SYMBOL sound/core/snd-pcm 0x68a24153 snd_pcm_format_physical_width +EXPORT_SYMBOL sound/core/snd-pcm 0x69a1808a snd_pcm_lib_readv +EXPORT_SYMBOL sound/core/snd-pcm 0x6adb5b33 snd_pcm_lib_preallocate_pages +EXPORT_SYMBOL sound/core/snd-pcm 0x6ef8fcd8 snd_pcm_format_linear +EXPORT_SYMBOL sound/core/snd-pcm 0x7c5cec98 _snd_pcm_hw_params_any +EXPORT_SYMBOL sound/core/snd-pcm 0x7cacad1a snd_pcm_period_elapsed +EXPORT_SYMBOL sound/core/snd-pcm 0x814bcfe3 snd_pcm_open_substream +EXPORT_SYMBOL sound/core/snd-pcm 0x88cc66cc snd_pcm_link_rwlock +EXPORT_SYMBOL sound/core/snd-pcm 0x89a31a56 _snd_pcm_hw_param_setempty +EXPORT_SYMBOL sound/core/snd-pcm 0x90df90da snd_pcm_lib_malloc_pages +EXPORT_SYMBOL sound/core/snd-pcm 0x96aff3f2 snd_pcm_stop +EXPORT_SYMBOL sound/core/snd-pcm 0x9d9aa8ad snd_pcm_hw_constraint_ratnums +EXPORT_SYMBOL sound/core/snd-pcm 0x9fab36e6 snd_pcm_lib_preallocate_free_for_all +EXPORT_SYMBOL sound/core/snd-pcm 0x9fdea959 snd_pcm_hw_param_value +EXPORT_SYMBOL sound/core/snd-pcm 0xa61aa028 snd_pcm_format_unsigned +EXPORT_SYMBOL sound/core/snd-pcm 0xa6447c5f snd_pcm_limit_hw_rates +EXPORT_SYMBOL sound/core/snd-pcm 0xae735b37 snd_pcm_hw_param_last +EXPORT_SYMBOL sound/core/snd-pcm 0xb05f6e32 snd_pcm_hw_constraint_step +EXPORT_SYMBOL sound/core/snd-pcm 0xb7d09867 snd_pcm_notify +EXPORT_SYMBOL sound/core/snd-pcm 0xb9638db4 snd_pcm_rate_to_rate_bit +EXPORT_SYMBOL sound/core/snd-pcm 0xbb1bba41 snd_pcm_hw_refine +EXPORT_SYMBOL sound/core/snd-pcm 0xbe6eee61 snd_pcm_kernel_ioctl +EXPORT_SYMBOL sound/core/snd-pcm 0xc824e424 snd_pcm_hw_constraint_pow2 +EXPORT_SYMBOL sound/core/snd-pcm 0xcc1ff2fd snd_pcm_hw_constraint_minmax +EXPORT_SYMBOL sound/core/snd-pcm 0xcd3a1641 snd_pcm_hw_constraint_msbits +EXPORT_SYMBOL sound/core/snd-pcm 0xd0b9b8b8 snd_interval_list +EXPORT_SYMBOL sound/core/snd-pcm 0xd17061ee snd_pcm_set_ops +EXPORT_SYMBOL sound/core/snd-pcm 0xd2360740 snd_pcm_lib_free_pages +EXPORT_SYMBOL sound/core/snd-pcm 0xdaf11552 snd_pcm_sgbuf_ops_page +EXPORT_SYMBOL sound/core/snd-pcm 0xe1f8f90e snd_pcm_set_sync +EXPORT_SYMBOL sound/core/snd-pcm 0xe3470731 snd_pcm_suspend_all +EXPORT_SYMBOL sound/core/snd-pcm 0xe51a1c64 snd_pcm_format_size +EXPORT_SYMBOL sound/core/snd-pcm 0xe56a9336 snd_pcm_format_width +EXPORT_SYMBOL sound/core/snd-pcm 0xe60a2685 snd_pcm_lib_mmap_iomem +EXPORT_SYMBOL sound/core/snd-pcm 0xe9709ffa snd_pcm_hw_constraint_ratdens +EXPORT_SYMBOL sound/core/snd-pcm 0xee0b2970 snd_pcm_hw_param_first +EXPORT_SYMBOL sound/core/snd-pcm 0xf3797152 snd_interval_ratnum +EXPORT_SYMBOL sound/core/snd-pcm 0xfa95a11c snd_pcm_suspend +EXPORT_SYMBOL sound/core/snd-rawmidi 0x02d0f1a2 snd_rawmidi_kernel_release +EXPORT_SYMBOL sound/core/snd-rawmidi 0x1f6876df snd_rawmidi_receive +EXPORT_SYMBOL sound/core/snd-rawmidi 0x28486578 snd_rawmidi_transmit_ack +EXPORT_SYMBOL sound/core/snd-rawmidi 0x30cdc654 snd_rawmidi_kernel_read +EXPORT_SYMBOL sound/core/snd-rawmidi 0x4483d190 snd_rawmidi_drop_output +EXPORT_SYMBOL sound/core/snd-rawmidi 0x48fd026e snd_rawmidi_kernel_write +EXPORT_SYMBOL sound/core/snd-rawmidi 0x533f315a snd_rawmidi_drain_output +EXPORT_SYMBOL sound/core/snd-rawmidi 0x5e384a22 snd_rawmidi_kernel_open +EXPORT_SYMBOL sound/core/snd-rawmidi 0x6eb81689 snd_rawmidi_output_params +EXPORT_SYMBOL sound/core/snd-rawmidi 0x71013eef snd_rawmidi_transmit +EXPORT_SYMBOL sound/core/snd-rawmidi 0x773b69ab snd_rawmidi_drain_input +EXPORT_SYMBOL sound/core/snd-rawmidi 0x8afc6738 snd_rawmidi_transmit_peek +EXPORT_SYMBOL sound/core/snd-rawmidi 0xb8b266bc snd_rawmidi_info_select +EXPORT_SYMBOL sound/core/snd-rawmidi 0xbe407d25 snd_rawmidi_new +EXPORT_SYMBOL sound/core/snd-rawmidi 0xdc05e13b snd_rawmidi_input_params +EXPORT_SYMBOL sound/core/snd-rawmidi 0xea81d5f8 snd_rawmidi_set_ops +EXPORT_SYMBOL sound/core/snd-rawmidi 0xfc7a9780 snd_rawmidi_transmit_empty +EXPORT_SYMBOL sound/core/snd-timer 0x122adcaf snd_timer_stop +EXPORT_SYMBOL sound/core/snd-timer 0x23a41857 snd_timer_continue +EXPORT_SYMBOL sound/core/snd-timer 0x2466d595 snd_timer_global_new +EXPORT_SYMBOL sound/core/snd-timer 0x36f772b1 snd_timer_new +EXPORT_SYMBOL sound/core/snd-timer 0x5515f577 snd_timer_close +EXPORT_SYMBOL sound/core/snd-timer 0x5f4517a7 snd_timer_start +EXPORT_SYMBOL sound/core/snd-timer 0x7d731a6b snd_timer_pause +EXPORT_SYMBOL sound/core/snd-timer 0x9d54f7ff snd_timer_interrupt +EXPORT_SYMBOL sound/core/snd-timer 0xc7d2647a snd_timer_global_free +EXPORT_SYMBOL sound/core/snd-timer 0xceb386f4 snd_timer_global_register +EXPORT_SYMBOL sound/core/snd-timer 0xd2986cf6 snd_timer_open +EXPORT_SYMBOL sound/core/snd-timer 0xdcb1846a snd_timer_resolution +EXPORT_SYMBOL sound/core/snd-timer 0xf2605655 snd_timer_notify +EXPORT_SYMBOL sound/drivers/mpu401/snd-mpu401-uart 0x73c4c993 snd_mpu401_uart_interrupt_tx +EXPORT_SYMBOL sound/drivers/mpu401/snd-mpu401-uart 0x99600858 snd_mpu401_uart_new +EXPORT_SYMBOL sound/drivers/mpu401/snd-mpu401-uart 0xfe618b58 snd_mpu401_uart_interrupt +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x05060a19 snd_opl3_regmap +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x297ec2fe snd_opl3_find_patch +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x36d3e101 snd_opl3_init +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x48dba016 snd_opl3_hwdep_new +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x6280aedb snd_opl3_reset +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x79560ed7 snd_opl3_timer_new +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0x985efecb snd_opl3_new +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0xa11ef2e5 snd_opl3_interrupt +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0xb44de9ea snd_opl3_create +EXPORT_SYMBOL sound/drivers/opl3/snd-opl3-lib 0xcb162c71 snd_opl3_load_patch +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x107f396b snd_vx_setup_firmware +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x1cadb14b snd_vx_irq_handler +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x3e4d6ff7 snd_vx_check_reg_bit +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x45313d7f snd_vx_resume +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x7e8524c5 snd_vx_load_boot_image +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x88278c6c snd_vx_dsp_load +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0x954bbbec snd_vx_create +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0xb461e805 snd_vx_free_firmware +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0xbeb6db69 snd_vx_dsp_boot +EXPORT_SYMBOL sound/drivers/vx/snd-vx-lib 0xf8af6fd7 snd_vx_suspend +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0x17745d0c snd_ak4114_create +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0x3982bc5d snd_ak4114_external_rate +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0x65c2a196 snd_ak4114_check_rate_and_errors +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0xd272e922 snd_ak4114_reinit +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0xd9b16369 snd_ak4114_build +EXPORT_SYMBOL sound/i2c/other/snd-ak4114 0xe9f2a7c2 snd_ak4114_reg_write +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x05217f6b snd_ak4117_external_rate +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x1397a08e snd_ak4117_create +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x273d9177 snd_ak4117_check_rate_and_errors +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x73e13e28 snd_ak4117_reinit +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0x950ee747 snd_ak4117_reg_write +EXPORT_SYMBOL sound/i2c/other/snd-ak4117 0xc8365e9a snd_ak4117_build +EXPORT_SYMBOL sound/i2c/other/snd-ak4xxx-adda 0xb116186b snd_akm4xxx_write +EXPORT_SYMBOL sound/i2c/other/snd-ak4xxx-adda 0xca520655 snd_akm4xxx_build_controls +EXPORT_SYMBOL sound/i2c/other/snd-ak4xxx-adda 0xda4ff4d1 snd_akm4xxx_reset +EXPORT_SYMBOL sound/i2c/other/snd-ak4xxx-adda 0xe41a7689 snd_akm4xxx_init +EXPORT_SYMBOL sound/i2c/other/snd-pt2258 0x287e85da snd_pt2258_reset +EXPORT_SYMBOL sound/i2c/other/snd-pt2258 0x4a3f2cd3 snd_pt2258_build_controls +EXPORT_SYMBOL sound/i2c/other/snd-tea575x-tuner 0x7a7222b8 snd_tea575x_exit +EXPORT_SYMBOL sound/i2c/other/snd-tea575x-tuner 0x7bef8a89 snd_tea575x_init +EXPORT_SYMBOL sound/i2c/snd-cs8427 0x07faf2f0 snd_cs8427_create +EXPORT_SYMBOL sound/i2c/snd-cs8427 0x112d0ac9 snd_cs8427_iec958_build +EXPORT_SYMBOL sound/i2c/snd-cs8427 0xe1bdf340 snd_cs8427_iec958_pcm +EXPORT_SYMBOL sound/i2c/snd-cs8427 0xf06114b8 snd_cs8427_reg_write +EXPORT_SYMBOL sound/i2c/snd-cs8427 0xfcf31b72 snd_cs8427_iec958_active +EXPORT_SYMBOL sound/i2c/snd-i2c 0x23e46169 snd_i2c_device_free +EXPORT_SYMBOL sound/i2c/snd-i2c 0x7d889dd7 snd_i2c_probeaddr +EXPORT_SYMBOL sound/i2c/snd-i2c 0x8c0150d2 snd_i2c_readbytes +EXPORT_SYMBOL sound/i2c/snd-i2c 0x96494d19 snd_i2c_sendbytes +EXPORT_SYMBOL sound/i2c/snd-i2c 0xa3e097d3 snd_i2c_device_create +EXPORT_SYMBOL sound/i2c/snd-i2c 0xfbfa6fc6 snd_i2c_bus_create +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x18181560 snd_sbmixer_new +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x223553f9 snd_sbdsp_create +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x248154cf snd_sbmixer_resume +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x4fbb6deb snd_sbmixer_suspend +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0x504922bd snd_sbmixer_write +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xc29ac229 snd_sbmixer_add_ctl +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xcf979c88 snd_sbmixer_read +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xdc8cfbd5 snd_sbdsp_command +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xe943dae6 snd_sbdsp_get_byte +EXPORT_SYMBOL sound/isa/sb/snd-sb-common 0xf130d7b2 snd_sbdsp_reset +EXPORT_SYMBOL sound/isa/sb/snd-sb16-dsp 0x0ba4ef1d snd_sb16dsp_interrupt +EXPORT_SYMBOL sound/isa/sb/snd-sb16-dsp 0x4c9e673e snd_sb16dsp_get_pcm_ops +EXPORT_SYMBOL sound/isa/sb/snd-sb16-dsp 0xb14cbadb snd_sb16dsp_configure +EXPORT_SYMBOL sound/isa/sb/snd-sb16-dsp 0xc45c9264 snd_sb16dsp_pcm +EXPORT_SYMBOL sound/oss/ad1848 0x9839a618 probe_ms_sound +EXPORT_SYMBOL sound/oss/ad1848 0x9bf1cc62 ad1848_unload +EXPORT_SYMBOL sound/oss/ad1848 0xb29a9148 unload_ms_sound +EXPORT_SYMBOL sound/oss/ad1848 0xc04f6f67 ad1848_control +EXPORT_SYMBOL sound/oss/ad1848 0xcb2840df attach_ms_sound +EXPORT_SYMBOL sound/oss/ad1848 0xf06eb004 ad1848_detect +EXPORT_SYMBOL sound/oss/ad1848 0xf46156f7 ad1848_init +EXPORT_SYMBOL sound/oss/mpu401 0x5febf284 unload_mpu401 +EXPORT_SYMBOL sound/oss/mpu401 0x8874e39a probe_mpu401 +EXPORT_SYMBOL sound/oss/mpu401 0xdb3d1f19 attach_mpu401 +EXPORT_SYMBOL sound/oss/sb_lib 0x42424109 sb_be_quiet +EXPORT_SYMBOL sound/oss/sb_lib 0x450f9aea smw_free +EXPORT_SYMBOL sound/oss/sb_lib 0x74afd69c unload_sbmpu +EXPORT_SYMBOL sound/oss/sb_lib 0x807e7c9b sb_dsp_init +EXPORT_SYMBOL sound/oss/sb_lib 0xbe235dd7 probe_sbmpu +EXPORT_SYMBOL sound/oss/sb_lib 0xc4884969 sb_dsp_unload +EXPORT_SYMBOL sound/oss/sb_lib 0xd8a2731c sb_dsp_detect +EXPORT_SYMBOL sound/oss/sound 0x04c87ec8 compute_finetune +EXPORT_SYMBOL sound/oss/sound 0x06339815 sound_unload_synthdev +EXPORT_SYMBOL sound/oss/sound 0x0f280035 conf_printf +EXPORT_SYMBOL sound/oss/sound 0x17ba231d seq_input_event +EXPORT_SYMBOL sound/oss/sound 0x1b3df3cf sound_alloc_mixerdev +EXPORT_SYMBOL sound/oss/sound 0x1f395686 MIDIbuf_avail +EXPORT_SYMBOL sound/oss/sound 0x2161d5e8 sound_timer_init +EXPORT_SYMBOL sound/oss/sound 0x2aa31695 midi_synth_kill_note +EXPORT_SYMBOL sound/oss/sound 0x394cb088 sound_free_dma +EXPORT_SYMBOL sound/oss/sound 0x3beaaf1c sound_install_audiodrv +EXPORT_SYMBOL sound/oss/sound 0x418f5fbe sound_close_dma +EXPORT_SYMBOL sound/oss/sound 0x4cd01bdd num_audiodevs +EXPORT_SYMBOL sound/oss/sound 0x4ff47e9d midi_synth_setup_voice +EXPORT_SYMBOL sound/oss/sound 0x51e354b2 sound_alloc_timerdev +EXPORT_SYMBOL sound/oss/sound 0x526729c4 sound_timer_devs +EXPORT_SYMBOL sound/oss/sound 0x56504ca2 midi_synth_reset +EXPORT_SYMBOL sound/oss/sound 0x5d986fc9 note_to_freq +EXPORT_SYMBOL sound/oss/sound 0x5dc6b350 synth_devs +EXPORT_SYMBOL sound/oss/sound 0x7679ee76 seq_copy_to_input +EXPORT_SYMBOL sound/oss/sound 0x7bdf0907 conf_printf2 +EXPORT_SYMBOL sound/oss/sound 0x892093e0 midi_synth_controller +EXPORT_SYMBOL sound/oss/sound 0x90bd9714 sequencer_timer +EXPORT_SYMBOL sound/oss/sound 0x987bcf12 DMAbuf_outputintr +EXPORT_SYMBOL sound/oss/sound 0x9a95733f sound_alloc_dma +EXPORT_SYMBOL sound/oss/sound 0x9bdaf24d midi_synth_start_note +EXPORT_SYMBOL sound/oss/sound 0x9d845b18 num_mixers +EXPORT_SYMBOL sound/oss/sound 0xa1d5f04f load_mixer_volumes +EXPORT_SYMBOL sound/oss/sound 0xa1eae7cf num_midis +EXPORT_SYMBOL sound/oss/sound 0xa41ead5f sound_unload_timerdev +EXPORT_SYMBOL sound/oss/sound 0xa51c913b sound_unload_mixerdev +EXPORT_SYMBOL sound/oss/sound 0xa6bb414c sound_unload_mididev +EXPORT_SYMBOL sound/oss/sound 0xa948751e sound_unload_audiodev +EXPORT_SYMBOL sound/oss/sound 0xad45df73 midi_synth_close +EXPORT_SYMBOL sound/oss/sound 0xaef743b2 midi_synth_ioctl +EXPORT_SYMBOL sound/oss/sound 0xb062dcd5 midi_devs +EXPORT_SYMBOL sound/oss/sound 0xb14b22cd midi_synth_hw_control +EXPORT_SYMBOL sound/oss/sound 0xb51587f6 do_midi_msg +EXPORT_SYMBOL sound/oss/sound 0xba413f87 sound_alloc_mididev +EXPORT_SYMBOL sound/oss/sound 0xba7dd041 midi_synth_bender +EXPORT_SYMBOL sound/oss/sound 0xc664d1de mixer_devs +EXPORT_SYMBOL sound/oss/sound 0xc748d109 sound_alloc_synthdev +EXPORT_SYMBOL sound/oss/sound 0xcc4b8797 sound_open_dma +EXPORT_SYMBOL sound/oss/sound 0xd85be938 midi_synth_set_instr +EXPORT_SYMBOL sound/oss/sound 0xdb400afa midi_synth_panning +EXPORT_SYMBOL sound/oss/sound 0xe056b71c DMAbuf_start_dma +EXPORT_SYMBOL sound/oss/sound 0xe1f31a35 audio_devs +EXPORT_SYMBOL sound/oss/sound 0xe2675a79 sound_timer_interrupt +EXPORT_SYMBOL sound/oss/sound 0xe3dab76c sound_install_mixer +EXPORT_SYMBOL sound/oss/sound 0xeb315d99 DMAbuf_inputintr +EXPORT_SYMBOL sound/oss/sound 0xf1ea8a20 midi_synth_aftertouch +EXPORT_SYMBOL sound/oss/sound 0xf6b3a2fb midi_synth_open +EXPORT_SYMBOL sound/oss/sound 0xf7426da3 midi_synth_load_patch +EXPORT_SYMBOL sound/oss/sound 0xf78f6363 sequencer_init +EXPORT_SYMBOL sound/oss/sound 0xfa6871be sound_timer_syncinterval +EXPORT_SYMBOL sound/oss/sound 0xfddcbfb3 midi_synth_send_sysex +EXPORT_SYMBOL sound/oss/uart401 0x46248c57 uart401intr +EXPORT_SYMBOL sound/oss/uart401 0xe3882365 probe_uart401 +EXPORT_SYMBOL sound/oss/uart401 0xecfdd9c9 unload_uart401 +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x0a108780 snd_ac97_tune_hardware +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x1ff92794 snd_ac97_bus +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x26b9e789 snd_ac97_pcm_close +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x2e44d586 snd_ac97_set_rate +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x30d83c92 snd_ac97_suspend +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x3c2e4fa7 snd_ac97_write +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x3cea8f9f snd_ac97_pcm_double_rate_rules +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x5a37de37 snd_ac97_resume +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x7d3f4ae4 snd_ac97_mixer +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x81662dd5 snd_ac97_write_cache +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x8c699689 snd_ac97_pcm_open +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x9ae7600e snd_ac97_pcm_assign +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x9dce93a2 snd_ac97_update_bits +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0x9fe13a39 snd_ac97_get_short_name +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xc01b7344 snd_ac97_update_power +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xd6dd12d4 snd_ac97_read +EXPORT_SYMBOL sound/pci/ac97/snd-ac97-codec 0xeefb6e21 snd_ac97_update +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x038c8c67 snd_emu10k1_ptr_write +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x0cc13e50 snd_emu10k1_voice_alloc +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x1d48037d snd_emu10k1_synth_free +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x48c1abd0 snd_emu10k1_ptr_read +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x6689877f snd_emu10k1_voice_free +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x6de30db0 snd_emu10k1_memblk_map +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x72c1537a snd_emu10k1_synth_bzero +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0x9be25b72 snd_emu10k1_synth_alloc +EXPORT_SYMBOL sound/pci/emu10k1/snd-emu10k1 0xc8c0a4f1 snd_emu10k1_synth_copy_from_user +EXPORT_SYMBOL sound/pci/ice1712/snd-ice17xx-ak4xxx 0x8569c46e snd_ice1712_akm4xxx_build_controls +EXPORT_SYMBOL sound/pci/ice1712/snd-ice17xx-ak4xxx 0xa5046fb4 snd_ice1712_akm4xxx_free +EXPORT_SYMBOL sound/pci/ice1712/snd-ice17xx-ak4xxx 0xbe5523b2 snd_ice1712_akm4xxx_init +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x07a5b026 oxygen_read_ac97 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x0fe1d3c3 oxygen_write_spi +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x271f12ec oxygen_write8_masked +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x2b4c9197 oxygen_write_ac97_masked +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x396c9328 oxygen_write_i2c +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x47a908be oxygen_write_ac97 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x4c6ce0a6 oxygen_pci_suspend +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x6e3c34df oxygen_read32 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x82b67ef5 oxygen_read8 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x8303562a oxygen_pci_remove +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0x8c929c8f oxygen_read16 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xa61bd30d oxygen_write16_masked +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xb9cd989e oxygen_write8 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xbe701bc0 oxygen_pci_resume +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xc4cda6f7 oxygen_pci_probe +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xc6f271f5 oxygen_write32 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xeaf2c85a oxygen_write16 +EXPORT_SYMBOL sound/pci/oxygen/snd-oxygen-lib 0xfca07931 oxygen_write32_masked +EXPORT_SYMBOL sound/pci/trident/snd-trident 0x40412c50 snd_trident_free_voice +EXPORT_SYMBOL sound/pci/trident/snd-trident 0x6c52647b snd_trident_stop_voice +EXPORT_SYMBOL sound/pci/trident/snd-trident 0x8d40a9a0 snd_trident_start_voice +EXPORT_SYMBOL sound/pci/trident/snd-trident 0x9e8ba6f3 snd_trident_alloc_voice +EXPORT_SYMBOL sound/pci/trident/snd-trident 0xd1f7e15c snd_trident_write_voice_regs +EXPORT_SYMBOL sound/sound_firmware 0x39e3dd23 mod_firmware_load +EXPORT_SYMBOL sound/soundcore 0x348d7b76 register_sound_special +EXPORT_SYMBOL sound/soundcore 0x3daf3c9a sound_class +EXPORT_SYMBOL sound/soundcore 0x5d7ea562 register_sound_special_device +EXPORT_SYMBOL sound/soundcore 0x7afc9d8a unregister_sound_mixer +EXPORT_SYMBOL sound/soundcore 0x8d95780d register_sound_mixer +EXPORT_SYMBOL sound/soundcore 0x99c95fa5 unregister_sound_special +EXPORT_SYMBOL sound/soundcore 0x9edb9010 register_sound_dsp +EXPORT_SYMBOL sound/soundcore 0xcd083b10 unregister_sound_dsp +EXPORT_SYMBOL sound/soundcore 0xfad30795 register_sound_midi +EXPORT_SYMBOL sound/soundcore 0xfdab6de3 unregister_sound_midi +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x23c52470 snd_emux_free +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x38d88440 snd_emux_register +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x5862b758 snd_emux_terminate_all +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x655cb202 snd_sf_linear_to_log +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x797bbafb snd_emux_lock_voice +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0x95a80c15 snd_emux_new +EXPORT_SYMBOL sound/synth/emux/snd-emux-synth 0xf4b6afd4 snd_emux_unlock_voice +EXPORT_SYMBOL sound/synth/snd-util-mem 0x20d65978 snd_util_memhdr_free +EXPORT_SYMBOL sound/synth/snd-util-mem 0x24886293 __snd_util_mem_alloc +EXPORT_SYMBOL sound/synth/snd-util-mem 0x569d614e snd_util_mem_free +EXPORT_SYMBOL sound/synth/snd-util-mem 0x7a007343 snd_util_memhdr_new +EXPORT_SYMBOL sound/synth/snd-util-mem 0xd197c5db __snd_util_memblk_new +EXPORT_SYMBOL sound/synth/snd-util-mem 0xd34b56e4 __snd_util_mem_free +EXPORT_SYMBOL sound/synth/snd-util-mem 0xd8b55e81 snd_util_mem_alloc +EXPORT_SYMBOL sound/synth/snd-util-mem 0xf158252c snd_util_mem_avail +EXPORT_SYMBOL sound/usb/snd-usb-lib 0x16756dc0 snd_usbmidi_input_start +EXPORT_SYMBOL sound/usb/snd-usb-lib 0x63343b1d snd_usbmidi_input_stop +EXPORT_SYMBOL sound/usb/snd-usb-lib 0xa3797b40 snd_usb_create_midi_interface +EXPORT_SYMBOL sound/usb/snd-usb-lib 0xd9d2bb03 snd_usbmidi_disconnect +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0x24acbe54 dm_mem_cache_alloc +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0x42fa8172 dm_mem_cache_client_create +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0x4b8f3a66 dm_mem_cache_shrink +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0x591aaba0 dm_mem_cache_free +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0x6b263368 dm_mem_cache_grow +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-mem-cache 0xa055161f dm_mem_cache_client_destroy +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-message 0x920a7a41 dm_message_parse +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x0050f52c rh_get_region_key +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x216444e0 rh_delay_by_region +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x275fdd04 rh_recovery_start +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x28b7e0fe rh_init +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x29e53a6b rh_dec +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x50a4e06e rh_inc_pending +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x5c2a0632 rh_recovery_end +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x62842029 rh_flush +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x83baca27 rh_state +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0x87d45b9d rh_get_region_size +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xa923d788 rh_start_recovery +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xac274ed3 rh_stop_recovery +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xb513be98 rh_update_states +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xbb748327 rh_reg_set_context +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xbd3452f9 rh_sector_to_region +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xc4fdf256 rh_recovery_prepare +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xc4ff7745 rh_reg_get_context +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xc57bafec rh_exit +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xca70f3e5 rh_delay +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xe9f7f71a rh_region_to_sector +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xf3e0a2b0 rh_inc +EXPORT_SYMBOL ubuntu/dm-raid4-5/dm-region_hash 0xf684a160 rh_bio_to_region +EXPORT_SYMBOL ubuntu/lirc/lirc_cmdir/commandir 0x29c887a9 set_tx_channels +EXPORT_SYMBOL ubuntu/lirc/lirc_cmdir/commandir 0x7789312a cmdir_write +EXPORT_SYMBOL ubuntu/lirc/lirc_cmdir/commandir 0xf4c689aa cmdir_read +EXPORT_SYMBOL ubuntu/lirc/lirc_dev/lirc_dev 0x0d00d112 lirc_register_plugin +EXPORT_SYMBOL ubuntu/lirc/lirc_dev/lirc_dev 0xb52dbac8 lirc_get_pdata +EXPORT_SYMBOL ubuntu/lirc/lirc_dev/lirc_dev 0xe96379eb lirc_unregister_plugin +EXPORT_SYMBOL ubuntu/misc/media/ov511/ov511 0x2763a531 ov511_register_decomp_module +EXPORT_SYMBOL ubuntu/misc/media/ov511/ov511 0x7db9be3c ov511_deregister_decomp_module +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x57eedff0 p80211netdev_rx +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x5b8fc410 p80211skb_rxmeta_attach +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x5d19cd19 unregister_wlandev +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x6555baed wlan_unsetup +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x75578f8d register_wlandev +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x78595066 wlan_setup +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x843509f3 p80211_allow_ioctls +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x9322444f p80211_suspend +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0x9784a64d p80211netdev_hwremoved +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xb0af0799 wlan_wext_write +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xbdfb5ac7 p80211skb_free +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xc1862c0b p80211wext_event_associated +EXPORT_SYMBOL ubuntu/misc/wireless/p80211/p80211 0xe841ff8d p80211_resume +EXPORT_SYMBOL vmlinux 0x001d2a83 mark_info_dirty +EXPORT_SYMBOL vmlinux 0x001f43a6 blk_queue_hardsect_size +EXPORT_SYMBOL vmlinux 0x004551f5 tcf_em_register +EXPORT_SYMBOL vmlinux 0x005227a0 bio_map_user +EXPORT_SYMBOL vmlinux 0x005e1445 lock_may_write +EXPORT_SYMBOL vmlinux 0x00801678 flush_scheduled_work +EXPORT_SYMBOL vmlinux 0x0080fcd6 tcf_hash_release +EXPORT_SYMBOL vmlinux 0x008fe885 d_alloc_root +EXPORT_SYMBOL vmlinux 0x009d258f _write_lock +EXPORT_SYMBOL vmlinux 0x00a0b113 pci_disable_msix +EXPORT_SYMBOL vmlinux 0x01000e51 schedule +EXPORT_SYMBOL vmlinux 0x013cc82b agp_create_memory +EXPORT_SYMBOL vmlinux 0x014f69b1 submit_bh +EXPORT_SYMBOL vmlinux 0x01522a16 register_framebuffer +EXPORT_SYMBOL vmlinux 0x015af241 blk_remove_plug +EXPORT_SYMBOL vmlinux 0x0186d073 percpu_counter_set +EXPORT_SYMBOL vmlinux 0x01902adf netpoll_trap +EXPORT_SYMBOL vmlinux 0x01a4aab6 set_irq_chip_data +EXPORT_SYMBOL vmlinux 0x01a95de9 get_unmapped_area +EXPORT_SYMBOL vmlinux 0x01d19038 acpi_enable_subsystem +EXPORT_SYMBOL vmlinux 0x01fff936 posix_test_lock +EXPORT_SYMBOL vmlinux 0x02124474 ip_send_check +EXPORT_SYMBOL vmlinux 0x02138f9d bioset_integrity_create +EXPORT_SYMBOL vmlinux 0x0215fbf5 ip4_datagram_connect +EXPORT_SYMBOL vmlinux 0x0227c66a uart_match_port +EXPORT_SYMBOL vmlinux 0x0237b57a arch_unregister_cpu +EXPORT_SYMBOL vmlinux 0x0256389f bit_waitqueue +EXPORT_SYMBOL vmlinux 0x02649054 security_sock_rcv_skb +EXPORT_SYMBOL vmlinux 0x02724ca8 skb_queue_tail +EXPORT_SYMBOL vmlinux 0x027a6079 open_exec +EXPORT_SYMBOL vmlinux 0x029444f0 native_read_tsc +EXPORT_SYMBOL vmlinux 0x02a18c74 nf_conntrack_destroy +EXPORT_SYMBOL vmlinux 0x02aff2f4 acpi_install_gpe_handler +EXPORT_SYMBOL vmlinux 0x02b59c84 neigh_seq_next +EXPORT_SYMBOL vmlinux 0x02d81845 audit_log_task_context +EXPORT_SYMBOL vmlinux 0x02e84d1b per_cpu__cpu_sibling_map +EXPORT_SYMBOL vmlinux 0x02fbe442 dma_async_client_chan_request +EXPORT_SYMBOL vmlinux 0x03072b5c ip_route_input +EXPORT_SYMBOL vmlinux 0x0334da4e scsi_command_size_tbl +EXPORT_SYMBOL vmlinux 0x037a0cba kfree +EXPORT_SYMBOL vmlinux 0x03a25444 bio_integrity_tag_size +EXPORT_SYMBOL vmlinux 0x03a99c3b rb_prev +EXPORT_SYMBOL vmlinux 0x03c06156 bitmap_fold +EXPORT_SYMBOL vmlinux 0x03c471ee qdisc_list_del +EXPORT_SYMBOL vmlinux 0x03c6abb5 dma_async_device_unregister +EXPORT_SYMBOL vmlinux 0x0400acce call_usermodehelper_freeinfo +EXPORT_SYMBOL vmlinux 0x0413d25d sync_mapping_buffers +EXPORT_SYMBOL vmlinux 0x0422fe4a inet_csk_timer_bug_msg +EXPORT_SYMBOL vmlinux 0x044fbf49 mempool_kzalloc +EXPORT_SYMBOL vmlinux 0x047ea62c nf_register_sockopt +EXPORT_SYMBOL vmlinux 0x0487f831 fb_find_best_display +EXPORT_SYMBOL vmlinux 0x048c15d1 bio_get_nr_vecs +EXPORT_SYMBOL vmlinux 0x04a951c1 elevator_init +EXPORT_SYMBOL vmlinux 0x04bf5eb0 nonseekable_open +EXPORT_SYMBOL vmlinux 0x04d40a71 register_netdev +EXPORT_SYMBOL vmlinux 0x04d8c750 release_perfctr_nmi +EXPORT_SYMBOL vmlinux 0x04fee575 fasync_helper +EXPORT_SYMBOL vmlinux 0x05092292 skb_copy_and_csum_bits +EXPORT_SYMBOL vmlinux 0x052c739d tcp_hashinfo +EXPORT_SYMBOL vmlinux 0x053aed2a tty_register_ldisc +EXPORT_SYMBOL vmlinux 0x053b018b ps2_cmd_aborted +EXPORT_SYMBOL vmlinux 0x0545bf28 dev_set_mtu +EXPORT_SYMBOL vmlinux 0x05746783 neigh_sysctl_register +EXPORT_SYMBOL vmlinux 0x058c75d9 acpi_get_pci_id +EXPORT_SYMBOL vmlinux 0x05ebc344 pci_set_dma_mask +EXPORT_SYMBOL vmlinux 0x05f81370 block_commit_write +EXPORT_SYMBOL vmlinux 0x05fda9e0 nlmsg_notify +EXPORT_SYMBOL vmlinux 0x061651be strcat +EXPORT_SYMBOL vmlinux 0x063724e2 lease_get_mtime +EXPORT_SYMBOL vmlinux 0x063c01cb cfb_copyarea +EXPORT_SYMBOL vmlinux 0x067d8d35 security_release_secctx +EXPORT_SYMBOL vmlinux 0x06a3de08 skb_seq_read +EXPORT_SYMBOL vmlinux 0x06a485f2 __krealloc +EXPORT_SYMBOL vmlinux 0x06d728b1 tcp_parse_md5sig_option +EXPORT_SYMBOL vmlinux 0x06df9557 simple_lookup +EXPORT_SYMBOL vmlinux 0x06fe3b14 default_grn +EXPORT_SYMBOL vmlinux 0x070cfde3 elv_rb_del +EXPORT_SYMBOL vmlinux 0x0727c4f3 iowrite8 +EXPORT_SYMBOL vmlinux 0x073dfa12 generate_resume_trace +EXPORT_SYMBOL vmlinux 0x075a2000 tcp_v4_send_check +EXPORT_SYMBOL vmlinux 0x0768f5a9 free_buffer_head +EXPORT_SYMBOL vmlinux 0x0784667f sock_rfree +EXPORT_SYMBOL vmlinux 0x0784ef79 dmam_free_coherent +EXPORT_SYMBOL vmlinux 0x078c036b poll_freewait +EXPORT_SYMBOL vmlinux 0x0799aca4 local_bh_enable +EXPORT_SYMBOL vmlinux 0x079cd7f1 ns_to_timeval +EXPORT_SYMBOL vmlinux 0x07a890c8 fb_alloc_cmap +EXPORT_SYMBOL vmlinux 0x07cc4a5d printk_timed_ratelimit +EXPORT_SYMBOL vmlinux 0x082c3213 pci_root_buses +EXPORT_SYMBOL vmlinux 0x083183e9 register_exec_domain +EXPORT_SYMBOL vmlinux 0x0845fbdb inet_put_port +EXPORT_SYMBOL vmlinux 0x0856ce6a blkdev_get +EXPORT_SYMBOL vmlinux 0x0933aae1 efi_enabled +EXPORT_SYMBOL vmlinux 0x0948cde9 num_physpages +EXPORT_SYMBOL vmlinux 0x09554a68 dma_set_mask +EXPORT_SYMBOL vmlinux 0x096debe6 wireless_spy_update +EXPORT_SYMBOL vmlinux 0x09775cdc kref_get +EXPORT_SYMBOL vmlinux 0x098431ba acpi_get_current_resources +EXPORT_SYMBOL vmlinux 0x098b71c6 fb_dealloc_cmap +EXPORT_SYMBOL vmlinux 0x09a17895 file_remove_suid +EXPORT_SYMBOL vmlinux 0x09b1335a pci_enable_bridges +EXPORT_SYMBOL vmlinux 0x09c55cec schedule_timeout_interruptible +EXPORT_SYMBOL vmlinux 0x09cc758d keyring_search +EXPORT_SYMBOL vmlinux 0x09d0421e vmap +EXPORT_SYMBOL vmlinux 0x09d29dff key_link +EXPORT_SYMBOL vmlinux 0x09d44df9 in_lock_functions +EXPORT_SYMBOL vmlinux 0x09fda52e find_inode_number +EXPORT_SYMBOL vmlinux 0x0a2487e0 unblock_all_signals +EXPORT_SYMBOL vmlinux 0x0a425fba fb_find_mode +EXPORT_SYMBOL vmlinux 0x0a6a6538 d_add_ci +EXPORT_SYMBOL vmlinux 0x0acb1a3c __bitmap_shift_right +EXPORT_SYMBOL vmlinux 0x0aef3079 llc_sap_find +EXPORT_SYMBOL vmlinux 0x0b0ac6d1 register_filesystem +EXPORT_SYMBOL vmlinux 0x0b15192a seq_printf +EXPORT_SYMBOL vmlinux 0x0b1beb31 vmalloc_32_user +EXPORT_SYMBOL vmlinux 0x0b4a72b7 unmap_underlying_metadata +EXPORT_SYMBOL vmlinux 0x0b4b9edf alloc_disk_node +EXPORT_SYMBOL vmlinux 0x0b6551fd flush_signals +EXPORT_SYMBOL vmlinux 0x0b742fd7 simple_strtol +EXPORT_SYMBOL vmlinux 0x0b78c2ba dev_change_flags +EXPORT_SYMBOL vmlinux 0x0bfd0579 bio_integrity_enabled +EXPORT_SYMBOL vmlinux 0x0c046bbd migrate_page +EXPORT_SYMBOL vmlinux 0x0c2d75ed neigh_lookup_nodev +EXPORT_SYMBOL vmlinux 0x0c5c69e3 flow_cache_lookup +EXPORT_SYMBOL vmlinux 0x0c5db825 xfrm_state_insert +EXPORT_SYMBOL vmlinux 0x0c5ef91b per_cpu__vm_event_states +EXPORT_SYMBOL vmlinux 0x0c87c756 bio_split_pool +EXPORT_SYMBOL vmlinux 0x0cea9bae pagecache_write_end +EXPORT_SYMBOL vmlinux 0x0cf01b5d blk_queue_bounce_limit +EXPORT_SYMBOL vmlinux 0x0cfc39c3 ip_nat_decode_session +EXPORT_SYMBOL vmlinux 0x0d26a76d _write_lock_irq +EXPORT_SYMBOL vmlinux 0x0d3dda14 acpi_get_type +EXPORT_SYMBOL vmlinux 0x0d542439 __ipv6_addr_type +EXPORT_SYMBOL vmlinux 0x0d894213 kmem_cache_create +EXPORT_SYMBOL vmlinux 0x0d894e7f agp_alloc_page_array +EXPORT_SYMBOL vmlinux 0x0d8ab500 param_set_copystring +EXPORT_SYMBOL vmlinux 0x0d9e07c6 nf_hook_slow +EXPORT_SYMBOL vmlinux 0x0da10ec3 security_sock_graft +EXPORT_SYMBOL vmlinux 0x0daeb6f2 tcp_create_openreq_child +EXPORT_SYMBOL vmlinux 0x0dc84ae2 proc_dointvec_minmax +EXPORT_SYMBOL vmlinux 0x0e0252ec downgrade_write +EXPORT_SYMBOL vmlinux 0x0e0872da sk_stream_wait_connect +EXPORT_SYMBOL vmlinux 0x0e1eaf06 unregister_snap_client +EXPORT_SYMBOL vmlinux 0x0e3fffa5 elevator_exit +EXPORT_SYMBOL vmlinux 0x0e4af292 xfrm_alloc_spi +EXPORT_SYMBOL vmlinux 0x0e50c71f skb_pad +EXPORT_SYMBOL vmlinux 0x0e52592a panic +EXPORT_SYMBOL vmlinux 0x0e6ea02c module_refcount +EXPORT_SYMBOL vmlinux 0x0e762d6e request_module +EXPORT_SYMBOL vmlinux 0x0e7bb697 acpi_unlock_ac_dir +EXPORT_SYMBOL vmlinux 0x0e930954 tcf_hash_check +EXPORT_SYMBOL vmlinux 0x0ed577ec end_dequeued_request +EXPORT_SYMBOL vmlinux 0x0ed95a49 ethtool_op_set_tx_csum +EXPORT_SYMBOL vmlinux 0x0eec0352 tty_wait_until_sent +EXPORT_SYMBOL vmlinux 0x0f033da8 xfrm_init_state +EXPORT_SYMBOL vmlinux 0x0f130caf __alloc_skb +EXPORT_SYMBOL vmlinux 0x0f2bd82f proc_net_netfilter +EXPORT_SYMBOL vmlinux 0x0f668286 eth_header_cache_update +EXPORT_SYMBOL vmlinux 0x0f714769 skb_dequeue_tail +EXPORT_SYMBOL vmlinux 0x0facabf1 clip_tbl_hook +EXPORT_SYMBOL vmlinux 0x0faef0ed __tasklet_schedule +EXPORT_SYMBOL vmlinux 0x0fbc3f05 blk_plug_device +EXPORT_SYMBOL vmlinux 0x0fc5e8eb radix_tree_gang_lookup_slot +EXPORT_SYMBOL vmlinux 0x0fd00a68 acpi_clear_event +EXPORT_SYMBOL vmlinux 0x103b8f40 thermal_zone_unbind_cooling_device +EXPORT_SYMBOL vmlinux 0x1055db10 pci_back_from_sleep +EXPORT_SYMBOL vmlinux 0x1072a394 csum_partial_copy_from_user +EXPORT_SYMBOL vmlinux 0x107acb6e d_namespace_path +EXPORT_SYMBOL vmlinux 0x109f5dce inet_frag_find +EXPORT_SYMBOL vmlinux 0x10e2900d elv_dequeue_request +EXPORT_SYMBOL vmlinux 0x10ee20bb default_blu +EXPORT_SYMBOL vmlinux 0x114cab3a alloc_tty_driver +EXPORT_SYMBOL vmlinux 0x11554b5e pci_scan_slot +EXPORT_SYMBOL vmlinux 0x116240db key_instantiate_and_link +EXPORT_SYMBOL vmlinux 0x1163f0a7 blk_max_low_pfn +EXPORT_SYMBOL vmlinux 0x1167903f xfrm_policy_bysel_ctx +EXPORT_SYMBOL vmlinux 0x117093be qdisc_class_hash_init +EXPORT_SYMBOL vmlinux 0x118f01ea putname +EXPORT_SYMBOL vmlinux 0x119cb6e0 llc_sap_open +EXPORT_SYMBOL vmlinux 0x11a18b14 __wake_up_bit +EXPORT_SYMBOL vmlinux 0x11cc83c5 sock_no_mmap +EXPORT_SYMBOL vmlinux 0x11d2eca2 inet_csk_accept +EXPORT_SYMBOL vmlinux 0x11d309ea simple_statfs +EXPORT_SYMBOL vmlinux 0x11dab346 __down_read +EXPORT_SYMBOL vmlinux 0x125fbca7 cad_pid +EXPORT_SYMBOL vmlinux 0x126970ed param_set_uint +EXPORT_SYMBOL vmlinux 0x127df2cd mpage_readpages +EXPORT_SYMBOL vmlinux 0x12d0569d __tcp_get_md5sig_pool +EXPORT_SYMBOL vmlinux 0x12e153b0 tty_port_free_xmit_buf +EXPORT_SYMBOL vmlinux 0x12f62a2e dput +EXPORT_SYMBOL vmlinux 0x12f99022 inet_frags_init_net +EXPORT_SYMBOL vmlinux 0x132f45f2 cookie_check_timestamp +EXPORT_SYMBOL vmlinux 0x1378e714 acpi_video_display_switch_support +EXPORT_SYMBOL vmlinux 0x138610a0 bdput +EXPORT_SYMBOL vmlinux 0x13dfaa42 nobh_truncate_page +EXPORT_SYMBOL vmlinux 0x13f71731 tcf_hash_lookup +EXPORT_SYMBOL vmlinux 0x1405141b xfrm_state_alloc +EXPORT_SYMBOL vmlinux 0x141a8542 pcie_port_service_register +EXPORT_SYMBOL vmlinux 0x1430e6e0 unregister_acpi_notifier +EXPORT_SYMBOL vmlinux 0x143419b7 sysctl_string +EXPORT_SYMBOL vmlinux 0x146f090a neigh_table_clear +EXPORT_SYMBOL vmlinux 0x14a798d5 pci_match_id +EXPORT_SYMBOL vmlinux 0x14af0cf7 gen_pool_destroy +EXPORT_SYMBOL vmlinux 0x14cacb20 set_user_nice +EXPORT_SYMBOL vmlinux 0x14ee8ace clear_bdi_congested +EXPORT_SYMBOL vmlinux 0x15098518 filemap_flush +EXPORT_SYMBOL vmlinux 0x150bbb58 ps2_handle_ack +EXPORT_SYMBOL vmlinux 0x1544aad4 genl_register_mc_group +EXPORT_SYMBOL vmlinux 0x15464c6f dquot_mark_dquot_dirty +EXPORT_SYMBOL vmlinux 0x154a466b invalidate_bdev +EXPORT_SYMBOL vmlinux 0x1551dc51 bitmap_find_free_region +EXPORT_SYMBOL vmlinux 0x15a461a5 atm_proc_root +EXPORT_SYMBOL vmlinux 0x15b470df invalidate_partition +EXPORT_SYMBOL vmlinux 0x15b7263c kmalloc_caches +EXPORT_SYMBOL vmlinux 0x15ef2dd9 kfifo_free +EXPORT_SYMBOL vmlinux 0x16517eb7 pci_iounmap +EXPORT_SYMBOL vmlinux 0x1675606f bad_dma_address +EXPORT_SYMBOL vmlinux 0x167e7f9d __get_user_1 +EXPORT_SYMBOL vmlinux 0x16a35878 _read_unlock +EXPORT_SYMBOL vmlinux 0x16b3a779 tcp_rcv_state_process +EXPORT_SYMBOL vmlinux 0x16d3a378 file_permission +EXPORT_SYMBOL vmlinux 0x170a2bc3 pnp_unregister_card_driver +EXPORT_SYMBOL vmlinux 0x170b9b15 agp_generic_alloc_by_type +EXPORT_SYMBOL vmlinux 0x170c25ee acpi_get_next_object +EXPORT_SYMBOL vmlinux 0x170d1c34 blk_init_queue +EXPORT_SYMBOL vmlinux 0x17224d88 have_submounts +EXPORT_SYMBOL vmlinux 0x172ed4d7 __vmalloc +EXPORT_SYMBOL vmlinux 0x17a76e71 rb_first +EXPORT_SYMBOL vmlinux 0x17c85a66 radix_tree_tagged +EXPORT_SYMBOL vmlinux 0x17df17bc sysctl_tcp_ecn +EXPORT_SYMBOL vmlinux 0x181b6ff2 mempool_resize +EXPORT_SYMBOL vmlinux 0x183da72c dentry_open +EXPORT_SYMBOL vmlinux 0x183fa88b mempool_alloc_slab +EXPORT_SYMBOL vmlinux 0x184c3fd0 dev_get_by_flags +EXPORT_SYMBOL vmlinux 0x185219bf swiotlb_free_coherent +EXPORT_SYMBOL vmlinux 0x186172e6 mapping_tagged +EXPORT_SYMBOL vmlinux 0x18673690 input_get_keycode +EXPORT_SYMBOL vmlinux 0x1885ea88 sock_alloc_send_skb +EXPORT_SYMBOL vmlinux 0x18993d08 setup_arg_pages +EXPORT_SYMBOL vmlinux 0x189b6bac memory_read_from_buffer +EXPORT_SYMBOL vmlinux 0x18d53597 call_usermodehelper_exec +EXPORT_SYMBOL vmlinux 0x18f5188a key_put +EXPORT_SYMBOL vmlinux 0x19134ac1 proc_create_data +EXPORT_SYMBOL vmlinux 0x19391763 iov_iter_fault_in_readable +EXPORT_SYMBOL vmlinux 0x1972f370 xfrm_unregister_km +EXPORT_SYMBOL vmlinux 0x1985ed3c prepare_to_wait_exclusive +EXPORT_SYMBOL vmlinux 0x199ed0cd net_disable_timestamp +EXPORT_SYMBOL vmlinux 0x19d5d20a acpi_walk_namespace +EXPORT_SYMBOL vmlinux 0x19f4b2a2 blk_queue_dma_alignment +EXPORT_SYMBOL vmlinux 0x1a1ab15d tty_mutex +EXPORT_SYMBOL vmlinux 0x1a2eb2f3 dec_zone_page_state +EXPORT_SYMBOL vmlinux 0x1a45cb6c acpi_disabled +EXPORT_SYMBOL vmlinux 0x1a75caa3 _read_lock +EXPORT_SYMBOL vmlinux 0x1a8a845e idle_nomwait +EXPORT_SYMBOL vmlinux 0x1a9669fa sock_sendmsg +EXPORT_SYMBOL vmlinux 0x1ac02507 sock_no_poll +EXPORT_SYMBOL vmlinux 0x1ace138d bitmap_allocate_region +EXPORT_SYMBOL vmlinux 0x1ae8d7dc param_set_invbool +EXPORT_SYMBOL vmlinux 0x1b015d25 bitmap_parselist +EXPORT_SYMBOL vmlinux 0x1b083e6c deregister_atm_ioctl +EXPORT_SYMBOL vmlinux 0x1b1384f6 kobject_add +EXPORT_SYMBOL vmlinux 0x1b19a0ea pci_scan_bridge +EXPORT_SYMBOL vmlinux 0x1b3813de simple_transaction_release +EXPORT_SYMBOL vmlinux 0x1b3b06b3 vm_insert_mixed +EXPORT_SYMBOL vmlinux 0x1b3b863c pci_set_consistent_dma_mask +EXPORT_SYMBOL vmlinux 0x1b3c678a gen_new_estimator +EXPORT_SYMBOL vmlinux 0x1b42c4de alloc_fcdev +EXPORT_SYMBOL vmlinux 0x1b47d602 netlink_broadcast +EXPORT_SYMBOL vmlinux 0x1b6314fd in_aton +EXPORT_SYMBOL vmlinux 0x1b818707 dmam_alloc_noncoherent +EXPORT_SYMBOL vmlinux 0x1b854087 __scm_send +EXPORT_SYMBOL vmlinux 0x1b89419f add_wait_queue_exclusive +EXPORT_SYMBOL vmlinux 0x1b9981cc set_irq_wake +EXPORT_SYMBOL vmlinux 0x1b9b306f generic_file_llseek +EXPORT_SYMBOL vmlinux 0x1baa9c86 node_to_cpumask_map +EXPORT_SYMBOL vmlinux 0x1bb00ebd tcp_v4_md5_hash_skb +EXPORT_SYMBOL vmlinux 0x1c102b40 register_quota_format +EXPORT_SYMBOL vmlinux 0x1c11f71e pnp_get_resource +EXPORT_SYMBOL vmlinux 0x1c37e16a input_allocate_device +EXPORT_SYMBOL vmlinux 0x1c39aeed generic_ro_fops +EXPORT_SYMBOL vmlinux 0x1c3e93ef tty_port_alloc_xmit_buf +EXPORT_SYMBOL vmlinux 0x1c4a113f seq_putc +EXPORT_SYMBOL vmlinux 0x1c5f1b98 pci_find_capability +EXPORT_SYMBOL vmlinux 0x1c678db9 bio_alloc_bioset +EXPORT_SYMBOL vmlinux 0x1c85a77a pcie_set_readrq +EXPORT_SYMBOL vmlinux 0x1c8fc816 add_disk +EXPORT_SYMBOL vmlinux 0x1cc6719a register_reboot_notifier +EXPORT_SYMBOL vmlinux 0x1ce4f76c skb_realloc_headroom +EXPORT_SYMBOL vmlinux 0x1cefe352 wait_for_completion +EXPORT_SYMBOL vmlinux 0x1cf3709f acpi_evaluate_integer +EXPORT_SYMBOL vmlinux 0x1cf422d5 set_pages_uc +EXPORT_SYMBOL vmlinux 0x1d219b78 inetdev_by_index +EXPORT_SYMBOL vmlinux 0x1d264e30 swiotlb_dma_mapping_error +EXPORT_SYMBOL vmlinux 0x1d31abfb sock_no_sendmsg +EXPORT_SYMBOL vmlinux 0x1d4c1dc0 vfs_permission +EXPORT_SYMBOL vmlinux 0x1d6a9f34 sb_min_blocksize +EXPORT_SYMBOL vmlinux 0x1d830520 cpu_possible_map +EXPORT_SYMBOL vmlinux 0x1d9cb13c ll_rw_block +EXPORT_SYMBOL vmlinux 0x1dadf9ea xfrm_input +EXPORT_SYMBOL vmlinux 0x1db7706b __copy_user_nocache +EXPORT_SYMBOL vmlinux 0x1db81d30 udp_proc_register +EXPORT_SYMBOL vmlinux 0x1dc36131 fb_destroy_modedb +EXPORT_SYMBOL vmlinux 0x1dd17996 filp_open +EXPORT_SYMBOL vmlinux 0x1dd571e6 fb_copy_cmap +EXPORT_SYMBOL vmlinux 0x1df89cae rtnetlink_put_metrics +EXPORT_SYMBOL vmlinux 0x1e142e48 arch_acpi_processor_init_pdc +EXPORT_SYMBOL vmlinux 0x1e1fc55f pci_map_rom +EXPORT_SYMBOL vmlinux 0x1e2f5175 agp_generic_destroy_page +EXPORT_SYMBOL vmlinux 0x1e6d26a8 strstr +EXPORT_SYMBOL vmlinux 0x1e73c367 init_special_inode +EXPORT_SYMBOL vmlinux 0x1e8d7b94 sysctl_ms_jiffies +EXPORT_SYMBOL vmlinux 0x1eaa5045 take_over_console +EXPORT_SYMBOL vmlinux 0x1edc77f8 kobject_set_name +EXPORT_SYMBOL vmlinux 0x1eddf0c3 iw_handler_get_thrspy +EXPORT_SYMBOL vmlinux 0x1ee873e6 compat_mc_setsockopt +EXPORT_SYMBOL vmlinux 0x1efe283f __cap_full_set +EXPORT_SYMBOL vmlinux 0x1f04966f complete_request_key +EXPORT_SYMBOL vmlinux 0x1f14f72f udp_sendmsg +EXPORT_SYMBOL vmlinux 0x1f27d6d7 _write_unlock +EXPORT_SYMBOL vmlinux 0x1f6b1fa6 uart_write_wakeup +EXPORT_SYMBOL vmlinux 0x20000329 simple_strtoul +EXPORT_SYMBOL vmlinux 0x2005e68a acpi_remove_fixed_event_handler +EXPORT_SYMBOL vmlinux 0x20092385 acpi_enter_sleep_state_s4bios +EXPORT_SYMBOL vmlinux 0x20106892 register_console +EXPORT_SYMBOL vmlinux 0x203e7022 pci_request_selected_regions +EXPORT_SYMBOL vmlinux 0x2064dbf0 ethtool_op_set_tx_ipv6_csum +EXPORT_SYMBOL vmlinux 0x20676a47 skb_truesize_bug +EXPORT_SYMBOL vmlinux 0x20770b05 eth_header_parse +EXPORT_SYMBOL vmlinux 0x208739f6 acpi_load_table +EXPORT_SYMBOL vmlinux 0x20b6eb79 nla_put +EXPORT_SYMBOL vmlinux 0x20c74d9f kobject_put +EXPORT_SYMBOL vmlinux 0x20c8fc33 pci_osc_control_set +EXPORT_SYMBOL vmlinux 0x20dfcb03 serio_unregister_driver +EXPORT_SYMBOL vmlinux 0x20eadeb6 ip_compute_csum +EXPORT_SYMBOL vmlinux 0x20ed07d4 input_open_device +EXPORT_SYMBOL vmlinux 0x20f9322a idr_pre_get +EXPORT_SYMBOL vmlinux 0x21033e88 pnp_disable_dev +EXPORT_SYMBOL vmlinux 0x2111b445 alloc_disk +EXPORT_SYMBOL vmlinux 0x21230e91 tty_schedule_flip +EXPORT_SYMBOL vmlinux 0x215ebd78 bitrev16 +EXPORT_SYMBOL vmlinux 0x21736ce5 call_usermodehelper_setup +EXPORT_SYMBOL vmlinux 0x21964e44 xfrm_register_mode +EXPORT_SYMBOL vmlinux 0x21e0ea22 acpi_get_id +EXPORT_SYMBOL vmlinux 0x21e5679c copy_user_generic +EXPORT_SYMBOL vmlinux 0x2224ea14 nf_unregister_hooks +EXPORT_SYMBOL vmlinux 0x22293822 nf_ip_checksum +EXPORT_SYMBOL vmlinux 0x222e7ce2 sysfs_streq +EXPORT_SYMBOL vmlinux 0x2253c959 kblockd_flush_work +EXPORT_SYMBOL vmlinux 0x226e86a9 audit_log +EXPORT_SYMBOL vmlinux 0x227f3fe1 udplite_prot +EXPORT_SYMBOL vmlinux 0x2288378f system_state +EXPORT_SYMBOL vmlinux 0x2288a618 tcp_disconnect +EXPORT_SYMBOL vmlinux 0x22a73912 __tcp_put_md5sig_pool +EXPORT_SYMBOL vmlinux 0x22b325d5 kd_mksound +EXPORT_SYMBOL vmlinux 0x22b6533b xfrm_sad_getinfo +EXPORT_SYMBOL vmlinux 0x22d400e1 vmalloc_to_page +EXPORT_SYMBOL vmlinux 0x22e9512e swiotlb_sync_sg_for_device +EXPORT_SYMBOL vmlinux 0x231f3a66 __kfifo_put +EXPORT_SYMBOL vmlinux 0x23269a13 strict_strtoul +EXPORT_SYMBOL vmlinux 0x23404bf8 pci_bus_read_config_dword +EXPORT_SYMBOL vmlinux 0x2341f72e __netdev_alloc_skb +EXPORT_SYMBOL vmlinux 0x234509f3 strncat +EXPORT_SYMBOL vmlinux 0x2360fc52 block_write_full_page +EXPORT_SYMBOL vmlinux 0x236c8c64 memcpy +EXPORT_SYMBOL vmlinux 0x238a48dc bdi_set_max_ratio +EXPORT_SYMBOL vmlinux 0x23a0aa7a sk_free +EXPORT_SYMBOL vmlinux 0x23a7a3bd maps_protect +EXPORT_SYMBOL vmlinux 0x23aab75e sock_map_fd +EXPORT_SYMBOL vmlinux 0x23b99e92 node_states +EXPORT_SYMBOL vmlinux 0x23f2d36f memparse +EXPORT_SYMBOL vmlinux 0x23fd3028 vmalloc_node +EXPORT_SYMBOL vmlinux 0x24428be5 strncpy_from_user +EXPORT_SYMBOL vmlinux 0x24457dc6 sockfd_lookup +EXPORT_SYMBOL vmlinux 0x2459bbcc console_set_on_cmdline +EXPORT_SYMBOL vmlinux 0x24609f0c vfs_rmdir +EXPORT_SYMBOL vmlinux 0x24866a7e inet_twsk_deschedule +EXPORT_SYMBOL vmlinux 0x24b6488b tcf_em_unregister +EXPORT_SYMBOL vmlinux 0x24c66c95 tcp_alloc_md5sig_pool +EXPORT_SYMBOL vmlinux 0x24fdac79 wake_bit_function +EXPORT_SYMBOL vmlinux 0x252b43d5 pci_bus_write_config_byte +EXPORT_SYMBOL vmlinux 0x25330040 inode_setattr +EXPORT_SYMBOL vmlinux 0x25552984 serial8250_register_port +EXPORT_SYMBOL vmlinux 0x2559df80 blk_queue_segment_boundary +EXPORT_SYMBOL vmlinux 0x25643d2c genl_unregister_ops +EXPORT_SYMBOL vmlinux 0x256887e1 warn_slowpath +EXPORT_SYMBOL vmlinux 0x25820c64 fs_overflowuid +EXPORT_SYMBOL vmlinux 0x258355b4 fb_find_best_mode +EXPORT_SYMBOL vmlinux 0x25d2e79e read_cache_page +EXPORT_SYMBOL vmlinux 0x25e62b68 kmem_cache_shrink +EXPORT_SYMBOL vmlinux 0x25ec1b28 strlen +EXPORT_SYMBOL vmlinux 0x263782b5 cancel_delayed_work_sync +EXPORT_SYMBOL vmlinux 0x2644a055 sk_stop_timer +EXPORT_SYMBOL vmlinux 0x26770333 ethtool_op_get_flags +EXPORT_SYMBOL vmlinux 0x2685c3d7 __sg_alloc_table +EXPORT_SYMBOL vmlinux 0x269240d6 pskb_expand_head +EXPORT_SYMBOL vmlinux 0x26a68573 mark_buffer_dirty_inode +EXPORT_SYMBOL vmlinux 0x26c41501 inode_set_bytes +EXPORT_SYMBOL vmlinux 0x26debcc9 km_policy_expired +EXPORT_SYMBOL vmlinux 0x26e76fb8 sysctl_udp_wmem_min +EXPORT_SYMBOL vmlinux 0x2704fe55 bmap +EXPORT_SYMBOL vmlinux 0x27250ebe mark_buffer_dirty +EXPORT_SYMBOL vmlinux 0x272d394e mtrr_del +EXPORT_SYMBOL vmlinux 0x272e7488 cond_resched_softirq +EXPORT_SYMBOL vmlinux 0x273f066e _write_unlock_irq +EXPORT_SYMBOL vmlinux 0x27475f90 skb_append +EXPORT_SYMBOL vmlinux 0x275ee2f2 skb_copy_and_csum_datagram_iovec +EXPORT_SYMBOL vmlinux 0x277d99db __next_cpu +EXPORT_SYMBOL vmlinux 0x27884fc0 __xfrm_state_destroy +EXPORT_SYMBOL vmlinux 0x279936a7 inet_addr_type +EXPORT_SYMBOL vmlinux 0x27a9a7eb ns_to_timespec +EXPORT_SYMBOL vmlinux 0x27bbf221 disable_irq_nosync +EXPORT_SYMBOL vmlinux 0x27c33efe csum_ipv6_magic +EXPORT_SYMBOL vmlinux 0x27c61ece qdisc_put_stab +EXPORT_SYMBOL vmlinux 0x27cefc17 read_cache_page_async +EXPORT_SYMBOL vmlinux 0x27e7f6d6 ip_xfrm_me_harder +EXPORT_SYMBOL vmlinux 0x280dafb6 blk_queue_resize_tags +EXPORT_SYMBOL vmlinux 0x2819d4a0 dquot_initialize +EXPORT_SYMBOL vmlinux 0x28288472 qdisc_reset +EXPORT_SYMBOL vmlinux 0x285373ff inet_bind +EXPORT_SYMBOL vmlinux 0x285ac517 strict_strtoll +EXPORT_SYMBOL vmlinux 0x2876a6d3 memcpy_toiovec +EXPORT_SYMBOL vmlinux 0x28d89ea3 serio_interrupt +EXPORT_SYMBOL vmlinux 0x28dcf25c udplite_hash +EXPORT_SYMBOL vmlinux 0x2904ae29 vfs_set_dqblk +EXPORT_SYMBOL vmlinux 0x2908596b xfrm_state_unregister_afinfo +EXPORT_SYMBOL vmlinux 0x295029a1 acpi_notifier_call_chain +EXPORT_SYMBOL vmlinux 0x2950d2a6 generic_listxattr +EXPORT_SYMBOL vmlinux 0x29537c9e alloc_chrdev_region +EXPORT_SYMBOL vmlinux 0x2991f2c0 tcp_v4_md5_do_add +EXPORT_SYMBOL vmlinux 0x2992a945 get_sb_pseudo +EXPORT_SYMBOL vmlinux 0x2995861b end_page_writeback +EXPORT_SYMBOL vmlinux 0x29bd4c46 __cap_init_eff_set +EXPORT_SYMBOL vmlinux 0x2a303d4d check_signature +EXPORT_SYMBOL vmlinux 0x2a322673 nf_register_queue_handler +EXPORT_SYMBOL vmlinux 0x2a8986ba thermal_cooling_device_unregister +EXPORT_SYMBOL vmlinux 0x2a8b5483 pci_do_scan_bus +EXPORT_SYMBOL vmlinux 0x2a90995c task_session_nr_ns +EXPORT_SYMBOL vmlinux 0x2a9f7d6e blk_queue_init_tags +EXPORT_SYMBOL vmlinux 0x2ae57c75 do_sync_write +EXPORT_SYMBOL vmlinux 0x2aeb2800 mempool_create_node +EXPORT_SYMBOL vmlinux 0x2aeb9531 blk_queue_find_tag +EXPORT_SYMBOL vmlinux 0x2b08273b path_put +EXPORT_SYMBOL vmlinux 0x2b0b412a pcibios_align_resource +EXPORT_SYMBOL vmlinux 0x2b12cb05 security_sk_classify_flow +EXPORT_SYMBOL vmlinux 0x2b2ac98d blk_rq_map_kern +EXPORT_SYMBOL vmlinux 0x2b367794 simple_set_mnt +EXPORT_SYMBOL vmlinux 0x2b627756 simple_dir_operations +EXPORT_SYMBOL vmlinux 0x2b690e69 __splice_from_pipe +EXPORT_SYMBOL vmlinux 0x2b6aac8c tcp_sockets_allocated +EXPORT_SYMBOL vmlinux 0x2b96cf54 generic_file_direct_write +EXPORT_SYMBOL vmlinux 0x2b9d2712 ioctl_by_bdev +EXPORT_SYMBOL vmlinux 0x2ba707a8 sysctl_tcp_low_latency +EXPORT_SYMBOL vmlinux 0x2bb55d6e acpi_remove_notify_handler +EXPORT_SYMBOL vmlinux 0x2bd23896 compat_nf_getsockopt +EXPORT_SYMBOL vmlinux 0x2be09893 _atomic_dec_and_lock +EXPORT_SYMBOL vmlinux 0x2be246ef find_vma +EXPORT_SYMBOL vmlinux 0x2bfeb410 acpi_get_handle +EXPORT_SYMBOL vmlinux 0x2c5749e6 acpi_clear_gpe +EXPORT_SYMBOL vmlinux 0x2c757e17 udp_flush_pending_frames +EXPORT_SYMBOL vmlinux 0x2c86c760 agp_allocate_memory +EXPORT_SYMBOL vmlinux 0x2cb5bd3d secpath_dup +EXPORT_SYMBOL vmlinux 0x2cc08b06 tcp_enter_memory_pressure +EXPORT_SYMBOL vmlinux 0x2cc2d52d vcc_hash +EXPORT_SYMBOL vmlinux 0x2cc2fd21 __lock_buffer +EXPORT_SYMBOL vmlinux 0x2cc6e9f0 udp_poll +EXPORT_SYMBOL vmlinux 0x2cd9e459 param_set_short +EXPORT_SYMBOL vmlinux 0x2cf190e3 request_irq +EXPORT_SYMBOL vmlinux 0x2cf3ff12 tcf_unregister_action +EXPORT_SYMBOL vmlinux 0x2d09b960 __xfrm_lookup +EXPORT_SYMBOL vmlinux 0x2d23a5cf skb_push +EXPORT_SYMBOL vmlinux 0x2d27770b lock_may_read +EXPORT_SYMBOL vmlinux 0x2d5528c9 sg_copy_to_buffer +EXPORT_SYMBOL vmlinux 0x2dac916d compat_tcp_getsockopt +EXPORT_SYMBOL vmlinux 0x2dba3dbc input_close_device +EXPORT_SYMBOL vmlinux 0x2dd16564 arch_register_cpu +EXPORT_SYMBOL vmlinux 0x2de9f66f param_get_long +EXPORT_SYMBOL vmlinux 0x2dedc4c2 acpi_format_exception +EXPORT_SYMBOL vmlinux 0x2def7f76 rtc_cmos_write +EXPORT_SYMBOL vmlinux 0x2e2ce9e0 sysctl_tcp_syncookies +EXPORT_SYMBOL vmlinux 0x2e36655e swiotlb_map_single_attrs +EXPORT_SYMBOL vmlinux 0x2e4a39f8 sysctl_udp_mem +EXPORT_SYMBOL vmlinux 0x2e6ffdd8 get_fs_type +EXPORT_SYMBOL vmlinux 0x2e9190a5 sock_no_recvmsg +EXPORT_SYMBOL vmlinux 0x2e92eb7c udp_lib_get_port +EXPORT_SYMBOL vmlinux 0x2e97a729 idr_remove +EXPORT_SYMBOL vmlinux 0x2eacf710 dmam_pool_create +EXPORT_SYMBOL vmlinux 0x2eb9a0e8 _read_lock_irq +EXPORT_SYMBOL vmlinux 0x2ec1186c find_task_by_pid_ns +EXPORT_SYMBOL vmlinux 0x2edd8d00 pci_bus_assign_resources +EXPORT_SYMBOL vmlinux 0x2efe1ac4 arch_debugfs_dir +EXPORT_SYMBOL vmlinux 0x2f7a90d0 rtnl_unicast +EXPORT_SYMBOL vmlinux 0x2fa5a500 memcmp +EXPORT_SYMBOL vmlinux 0x2ff063b5 acpi_get_name +EXPORT_SYMBOL vmlinux 0x2ff7efaa tcf_hash_new_index +EXPORT_SYMBOL vmlinux 0x3006782f bio_integrity_prep +EXPORT_SYMBOL vmlinux 0x3007ffbd neigh_table_init_no_netlink +EXPORT_SYMBOL vmlinux 0x301cdbff user_revoke +EXPORT_SYMBOL vmlinux 0x30226ddf agp_device_command +EXPORT_SYMBOL vmlinux 0x30299447 dget_locked +EXPORT_SYMBOL vmlinux 0x30321700 sg_miter_stop +EXPORT_SYMBOL vmlinux 0x304c2b86 blk_sync_queue +EXPORT_SYMBOL vmlinux 0x306bd3c3 vfs_fstat +EXPORT_SYMBOL vmlinux 0x30896043 __any_online_cpu +EXPORT_SYMBOL vmlinux 0x30896920 compat_mc_getsockopt +EXPORT_SYMBOL vmlinux 0x30a75973 register_atm_ioctl +EXPORT_SYMBOL vmlinux 0x30a94c37 pci_reenable_device +EXPORT_SYMBOL vmlinux 0x30c5ac52 pnp_unregister_driver +EXPORT_SYMBOL vmlinux 0x30de8b2e copy_io_context +EXPORT_SYMBOL vmlinux 0x30e74134 tty_termios_copy_hw +EXPORT_SYMBOL vmlinux 0x30fe83a7 pci_remove_bus +EXPORT_SYMBOL vmlinux 0x3116e6d3 bdi_destroy +EXPORT_SYMBOL vmlinux 0x311c659e ip_mc_inc_group +EXPORT_SYMBOL vmlinux 0x3132f872 load_nls +EXPORT_SYMBOL vmlinux 0x3145216f pci_dev_present +EXPORT_SYMBOL vmlinux 0x3147857d default_red +EXPORT_SYMBOL vmlinux 0x315172a6 blk_alloc_queue_node +EXPORT_SYMBOL vmlinux 0x31616d67 textsearch_find_continuous +EXPORT_SYMBOL vmlinux 0x31855bbe kernel_getpeername +EXPORT_SYMBOL vmlinux 0x31b31f5c csum_partial_copy_nocheck +EXPORT_SYMBOL vmlinux 0x31b331f3 sock_i_uid +EXPORT_SYMBOL vmlinux 0x31ccfb97 sb_has_dirty_inodes +EXPORT_SYMBOL vmlinux 0x31cdfefa __nla_reserve_nohdr +EXPORT_SYMBOL vmlinux 0x31ebadcd in_group_p +EXPORT_SYMBOL vmlinux 0x322d76d1 neigh_destroy +EXPORT_SYMBOL vmlinux 0x322fe5bb pci_release_region +EXPORT_SYMBOL vmlinux 0x324094ae kick_iocb +EXPORT_SYMBOL vmlinux 0x326ba0c4 km_report +EXPORT_SYMBOL vmlinux 0x326d5bcd blk_put_request +EXPORT_SYMBOL vmlinux 0x3285b00f neigh_event_ns +EXPORT_SYMBOL vmlinux 0x32b1b647 register_snap_client +EXPORT_SYMBOL vmlinux 0x32d01fec acpi_attach_data +EXPORT_SYMBOL vmlinux 0x32ee1827 pci_add_new_bus +EXPORT_SYMBOL vmlinux 0x32f87920 inet_frag_kill +EXPORT_SYMBOL vmlinux 0x330d556f gnet_stats_copy_app +EXPORT_SYMBOL vmlinux 0x33421241 tcp_child_process +EXPORT_SYMBOL vmlinux 0x3360a963 param_set_ulong +EXPORT_SYMBOL vmlinux 0x33675053 xfrm_bundle_ok +EXPORT_SYMBOL vmlinux 0x33705bf9 tty_port_init +EXPORT_SYMBOL vmlinux 0x33830488 put_disk +EXPORT_SYMBOL vmlinux 0x33ab317c ilookup5 +EXPORT_SYMBOL vmlinux 0x33b84f74 copy_page +EXPORT_SYMBOL vmlinux 0x33c40c98 __dev_get_by_index +EXPORT_SYMBOL vmlinux 0x33cda660 posix_acl_from_mode +EXPORT_SYMBOL vmlinux 0x33d92f9a prepare_to_wait +EXPORT_SYMBOL vmlinux 0x3421272c efi +EXPORT_SYMBOL vmlinux 0x344d4366 per_cpu__softnet_data +EXPORT_SYMBOL vmlinux 0x3456b45d tty_flip_buffer_push +EXPORT_SYMBOL vmlinux 0x3491f153 elv_queue_empty +EXPORT_SYMBOL vmlinux 0x349cba85 strchr +EXPORT_SYMBOL vmlinux 0x34aba257 generic_file_aio_write_nolock +EXPORT_SYMBOL vmlinux 0x34c1babf swiotlb_sync_sg_for_cpu +EXPORT_SYMBOL vmlinux 0x34faa7ac blk_queue_invalidate_tags +EXPORT_SYMBOL vmlinux 0x3509f037 pci_choose_state +EXPORT_SYMBOL vmlinux 0x3516e788 input_unregister_handle +EXPORT_SYMBOL vmlinux 0x352a325e inet_unregister_protosw +EXPORT_SYMBOL vmlinux 0x353cc2f1 tty_throttle +EXPORT_SYMBOL vmlinux 0x3544f184 tcp_read_sock +EXPORT_SYMBOL vmlinux 0x3573be36 agp_generic_type_to_mask_type +EXPORT_SYMBOL vmlinux 0x3580f9b6 dev_unicast_delete +EXPORT_SYMBOL vmlinux 0x35a07e32 vfs_stat +EXPORT_SYMBOL vmlinux 0x35b0650f vsnprintf +EXPORT_SYMBOL vmlinux 0x35c2ba9e refrigerator +EXPORT_SYMBOL vmlinux 0x360b1afe probe_irq_mask +EXPORT_SYMBOL vmlinux 0x36139a51 memcpy_fromiovec +EXPORT_SYMBOL vmlinux 0x362f045c node_data +EXPORT_SYMBOL vmlinux 0x363ad247 cap_set_effective +EXPORT_SYMBOL vmlinux 0x364e2dd2 neigh_ifdown +EXPORT_SYMBOL vmlinux 0x36509e1d block_page_mkwrite +EXPORT_SYMBOL vmlinux 0x3652cf8a __xfrm_policy_check +EXPORT_SYMBOL vmlinux 0x3656bf5a lock_kernel +EXPORT_SYMBOL vmlinux 0x365bcea3 d_alloc_anon +EXPORT_SYMBOL vmlinux 0x367478aa kmem_cache_destroy +EXPORT_SYMBOL vmlinux 0x36834ccb iw_handler_get_spy +EXPORT_SYMBOL vmlinux 0x3686c0fb pci_find_device +EXPORT_SYMBOL vmlinux 0x369a9322 nla_put_nohdr +EXPORT_SYMBOL vmlinux 0x36ba200b inode_sub_bytes +EXPORT_SYMBOL vmlinux 0x36f72945 ps2_sendbyte +EXPORT_SYMBOL vmlinux 0x3701a196 csum_partial_copy_to_user +EXPORT_SYMBOL vmlinux 0x370d6961 acpi_match_device_ids +EXPORT_SYMBOL vmlinux 0x372369ce generic_file_splice_write_nolock +EXPORT_SYMBOL vmlinux 0x372f8750 dev_mc_unsync +EXPORT_SYMBOL vmlinux 0x3740ff9d bio_put +EXPORT_SYMBOL vmlinux 0x3744cf36 vmalloc_to_pfn +EXPORT_SYMBOL vmlinux 0x375465a7 radix_tree_gang_lookup_tag_slot +EXPORT_SYMBOL vmlinux 0x37befc70 jiffies_to_msecs +EXPORT_SYMBOL vmlinux 0x37c373bf cfb_fillrect +EXPORT_SYMBOL vmlinux 0x37d555d1 vfs_statfs +EXPORT_SYMBOL vmlinux 0x37dbcf6b blk_queue_stack_limits +EXPORT_SYMBOL vmlinux 0x37df03da xfrm_state_lookup +EXPORT_SYMBOL vmlinux 0x3850337f swiotlb_unmap_single +EXPORT_SYMBOL vmlinux 0x385ee2d2 bio_integrity_endio +EXPORT_SYMBOL vmlinux 0x3861ac8b framebuffer_alloc +EXPORT_SYMBOL vmlinux 0x388efd63 tcp_proc_unregister +EXPORT_SYMBOL vmlinux 0x38b92846 llc_remove_pack +EXPORT_SYMBOL vmlinux 0x38bc4123 sock_register +EXPORT_SYMBOL vmlinux 0x38e8b52d d_delete +EXPORT_SYMBOL vmlinux 0x38f33bed dump_fpu +EXPORT_SYMBOL vmlinux 0x39170a6c acpi_check_resource_conflict +EXPORT_SYMBOL vmlinux 0x39291a03 tcf_hash_search +EXPORT_SYMBOL vmlinux 0x39415277 dev_alloc_skb +EXPORT_SYMBOL vmlinux 0x396d5ee8 input_free_device +EXPORT_SYMBOL vmlinux 0x3971dde8 unregister_binfmt +EXPORT_SYMBOL vmlinux 0x3980aac1 unregister_reboot_notifier +EXPORT_SYMBOL vmlinux 0x39b25ffb dma_sync_wait +EXPORT_SYMBOL vmlinux 0x39c16f1e release_firmware +EXPORT_SYMBOL vmlinux 0x39cd891a __down_write_trylock +EXPORT_SYMBOL vmlinux 0x3a1b195a __generic_unplug_device +EXPORT_SYMBOL vmlinux 0x3a2204c6 security_netlink_recv +EXPORT_SYMBOL vmlinux 0x3a539bfb inode_init_once +EXPORT_SYMBOL vmlinux 0x3a8f42fe pci_find_next_bus +EXPORT_SYMBOL vmlinux 0x3a9b6fb9 blk_unregister_region +EXPORT_SYMBOL vmlinux 0x3aa1dbcf _spin_unlock_bh +EXPORT_SYMBOL vmlinux 0x3aaea436 __dev_get_by_name +EXPORT_SYMBOL vmlinux 0x3ad9f179 __set_page_dirty_nobuffers +EXPORT_SYMBOL vmlinux 0x3b06bc64 pcim_iomap_table +EXPORT_SYMBOL vmlinux 0x3b241c39 pcie_port_service_unregister +EXPORT_SYMBOL vmlinux 0x3b2ddb19 lock_rename +EXPORT_SYMBOL vmlinux 0x3b3016d3 cpufreq_unregister_notifier +EXPORT_SYMBOL vmlinux 0x3b635e5d backlight_device_register +EXPORT_SYMBOL vmlinux 0x3b63a26b tty_insert_flip_string +EXPORT_SYMBOL vmlinux 0x3b67cbbf __init_rwsem +EXPORT_SYMBOL vmlinux 0x3b6839a6 ethtool_op_get_sg +EXPORT_SYMBOL vmlinux 0x3b9e0ae4 bdevname +EXPORT_SYMBOL vmlinux 0x3ba67189 fget +EXPORT_SYMBOL vmlinux 0x3bb00fd0 elv_add_request +EXPORT_SYMBOL vmlinux 0x3bcba798 gnet_stats_copy_queue +EXPORT_SYMBOL vmlinux 0x3bd1b1f6 msecs_to_jiffies +EXPORT_SYMBOL vmlinux 0x3bf2f65a agp_backend_acquire +EXPORT_SYMBOL vmlinux 0x3c10be47 security_inode_init_security +EXPORT_SYMBOL vmlinux 0x3c2c5af5 sprintf +EXPORT_SYMBOL vmlinux 0x3c40b192 __sk_mem_reclaim +EXPORT_SYMBOL vmlinux 0x3c43dcd7 seq_release_private +EXPORT_SYMBOL vmlinux 0x3c6ed352 posix_lock_file_wait +EXPORT_SYMBOL vmlinux 0x3c7227bf complete_all +EXPORT_SYMBOL vmlinux 0x3c7e58d4 ethtool_op_set_tso +EXPORT_SYMBOL vmlinux 0x3c821eea create_empty_buffers +EXPORT_SYMBOL vmlinux 0x3c958b39 unregister_framebuffer +EXPORT_SYMBOL vmlinux 0x3c96f2a7 inet_sock_destruct +EXPORT_SYMBOL vmlinux 0x3cb8a495 param_get_string +EXPORT_SYMBOL vmlinux 0x3cc0a3bb xfrm_spd_getinfo +EXPORT_SYMBOL vmlinux 0x3cc31e07 skb_abort_seq_read +EXPORT_SYMBOL vmlinux 0x3cda15d0 agp_generic_alloc_page +EXPORT_SYMBOL vmlinux 0x3ce4ca6f disable_irq +EXPORT_SYMBOL vmlinux 0x3cfdba79 __rta_fill +EXPORT_SYMBOL vmlinux 0x3d32d0d7 udp_prot +EXPORT_SYMBOL vmlinux 0x3d6f4f80 pci_save_state +EXPORT_SYMBOL vmlinux 0x3d808af7 lock_super +EXPORT_SYMBOL vmlinux 0x3d9ee9f0 clear_page +EXPORT_SYMBOL vmlinux 0x3da171f9 pci_mem_start +EXPORT_SYMBOL vmlinux 0x3da5eb6d kfifo_alloc +EXPORT_SYMBOL vmlinux 0x3db2e258 radix_tree_gang_lookup +EXPORT_SYMBOL vmlinux 0x3db4b13d simple_dir_inode_operations +EXPORT_SYMBOL vmlinux 0x3ddb50cc bio_integrity_alloc_bioset +EXPORT_SYMBOL vmlinux 0x3de3f7b5 fd_install +EXPORT_SYMBOL vmlinux 0x3e076c0f kernel_connect +EXPORT_SYMBOL vmlinux 0x3e1f073d wait_for_completion_timeout +EXPORT_SYMBOL vmlinux 0x3e219de6 try_wait_for_completion +EXPORT_SYMBOL vmlinux 0x3e2427a1 acpi_check_region +EXPORT_SYMBOL vmlinux 0x3e2a63fa sk_stream_kill_queues +EXPORT_SYMBOL vmlinux 0x3e2ae3a8 acpi_release_global_lock +EXPORT_SYMBOL vmlinux 0x3e427531 pnp_device_detach +EXPORT_SYMBOL vmlinux 0x3e45e9ff register_inetaddr_notifier +EXPORT_SYMBOL vmlinux 0x3e5f0bad __bforget +EXPORT_SYMBOL vmlinux 0x3e805830 page_readlink +EXPORT_SYMBOL vmlinux 0x3e9e57d5 d_validate +EXPORT_SYMBOL vmlinux 0x3ea31414 bio_add_page +EXPORT_SYMBOL vmlinux 0x3eac1bc2 udp_lib_setsockopt +EXPORT_SYMBOL vmlinux 0x3ed63055 zlib_inflateReset +EXPORT_SYMBOL vmlinux 0x3f0546a8 ioread32_rep +EXPORT_SYMBOL vmlinux 0x3f1899f1 up +EXPORT_SYMBOL vmlinux 0x3f4547a7 put_unused_fd +EXPORT_SYMBOL vmlinux 0x3f5111b8 block_truncate_page +EXPORT_SYMBOL vmlinux 0x3f57e84a inet_accept +EXPORT_SYMBOL vmlinux 0x3fa2fc00 fb_set_var +EXPORT_SYMBOL vmlinux 0x3fa913da strspn +EXPORT_SYMBOL vmlinux 0x3faa8457 pci_request_region +EXPORT_SYMBOL vmlinux 0x3fab766a blk_dump_rq_flags +EXPORT_SYMBOL vmlinux 0x3fbcddc3 netdev_compute_features +EXPORT_SYMBOL vmlinux 0x3fd35619 generic_splice_sendpage +EXPORT_SYMBOL vmlinux 0x3fec048f sg_next +EXPORT_SYMBOL vmlinux 0x3ff62317 local_bh_disable +EXPORT_SYMBOL vmlinux 0x401e998a blk_queue_update_dma_alignment +EXPORT_SYMBOL vmlinux 0x40413642 tcp_connect +EXPORT_SYMBOL vmlinux 0x405c1144 get_seconds +EXPORT_SYMBOL vmlinux 0x407bde66 __dst_free +EXPORT_SYMBOL vmlinux 0x4087cd1b blk_get_backing_dev_info +EXPORT_SYMBOL vmlinux 0x40958f9f vfs_get_dqblk +EXPORT_SYMBOL vmlinux 0x409873e3 tty_termios_baud_rate +EXPORT_SYMBOL vmlinux 0x40c5ca55 sk_common_release +EXPORT_SYMBOL vmlinux 0x40c89d46 acpi_get_table_by_index +EXPORT_SYMBOL vmlinux 0x40dd8c9f uart_get_baud_rate +EXPORT_SYMBOL vmlinux 0x40e2cad5 register_tcf_proto_ops +EXPORT_SYMBOL vmlinux 0x4108e69a fb_match_mode +EXPORT_SYMBOL vmlinux 0x41482d8b strndup_user +EXPORT_SYMBOL vmlinux 0x41711c46 seq_puts +EXPORT_SYMBOL vmlinux 0x4188d439 neigh_rand_reach_time +EXPORT_SYMBOL vmlinux 0x41a7c227 schedule_delayed_work +EXPORT_SYMBOL vmlinux 0x41a991d3 shrink_dcache_sb +EXPORT_SYMBOL vmlinux 0x41a9c68d _spin_trylock_bh +EXPORT_SYMBOL vmlinux 0x41b8942e add_to_page_cache_locked +EXPORT_SYMBOL vmlinux 0x41ccc474 security_req_classify_flow +EXPORT_SYMBOL vmlinux 0x4211c3c1 zlib_inflateInit2 +EXPORT_SYMBOL vmlinux 0x42224298 sscanf +EXPORT_SYMBOL vmlinux 0x422c05d0 acpi_get_data +EXPORT_SYMBOL vmlinux 0x42a084ea blk_cleanup_queue +EXPORT_SYMBOL vmlinux 0x42a4bdf2 in_egroup_p +EXPORT_SYMBOL vmlinux 0x42b40b63 tcp_v4_do_rcv +EXPORT_SYMBOL vmlinux 0x42ff8385 do_munmap +EXPORT_SYMBOL vmlinux 0x4302d0eb free_pages +EXPORT_SYMBOL vmlinux 0x4327f0d5 memset_io +EXPORT_SYMBOL vmlinux 0x43385ad9 acpi_pci_unregister_driver +EXPORT_SYMBOL vmlinux 0x433aa697 generic_readlink +EXPORT_SYMBOL vmlinux 0x434561d8 unregister_netdev +EXPORT_SYMBOL vmlinux 0x434fa55c release_console_sem +EXPORT_SYMBOL vmlinux 0x43570bcf tcf_generic_walker +EXPORT_SYMBOL vmlinux 0x4358aa14 end_buffer_write_sync +EXPORT_SYMBOL vmlinux 0x435b566d _spin_unlock +EXPORT_SYMBOL vmlinux 0x43698e39 skb_make_writable +EXPORT_SYMBOL vmlinux 0x436c2179 iowrite32 +EXPORT_SYMBOL vmlinux 0x438215a9 udp_proc_unregister +EXPORT_SYMBOL vmlinux 0x43916c6d generic_write_checks +EXPORT_SYMBOL vmlinux 0x4393e170 neigh_lookup +EXPORT_SYMBOL vmlinux 0x43bdd372 request_resource +EXPORT_SYMBOL vmlinux 0x43be8bf3 pci_prepare_to_sleep +EXPORT_SYMBOL vmlinux 0x43d4c9d1 blk_rq_unmap_user +EXPORT_SYMBOL vmlinux 0x43d66d3a unlock_new_inode +EXPORT_SYMBOL vmlinux 0x43eb56b7 new_inode +EXPORT_SYMBOL vmlinux 0x43ec913a put_cmsg +EXPORT_SYMBOL vmlinux 0x43ef8119 kmem_cache_alloc_node +EXPORT_SYMBOL vmlinux 0x43f49573 arp_broken_ops +EXPORT_SYMBOL vmlinux 0x44161c19 unregister_shrinker +EXPORT_SYMBOL vmlinux 0x44416efa seq_lseek +EXPORT_SYMBOL vmlinux 0x44455db6 find_get_pages_contig +EXPORT_SYMBOL vmlinux 0x444779c4 nla_find +EXPORT_SYMBOL vmlinux 0x4476ef7e register_chrdev +EXPORT_SYMBOL vmlinux 0x44aaf30f tsc_khz +EXPORT_SYMBOL vmlinux 0x44b911c3 rb_replace_node +EXPORT_SYMBOL vmlinux 0x44d560e3 init_level4_pgt +EXPORT_SYMBOL vmlinux 0x44f95e87 inode_double_unlock +EXPORT_SYMBOL vmlinux 0x4550ba8a register_cpu_notifier +EXPORT_SYMBOL vmlinux 0x455fd57d acpi_set_register +EXPORT_SYMBOL vmlinux 0x45704798 print_hex_dump_bytes +EXPORT_SYMBOL vmlinux 0x4572534c key_payload_reserve +EXPORT_SYMBOL vmlinux 0x457da49f d_rehash +EXPORT_SYMBOL vmlinux 0x457e7ce9 agp_find_bridge +EXPORT_SYMBOL vmlinux 0x45915126 serio_close +EXPORT_SYMBOL vmlinux 0x4592ea9e register_qdisc +EXPORT_SYMBOL vmlinux 0x45a79889 do_mmap_pgoff +EXPORT_SYMBOL vmlinux 0x45bb123e try_to_del_timer_sync +EXPORT_SYMBOL vmlinux 0x45d11c43 down_interruptible +EXPORT_SYMBOL vmlinux 0x45f4a3aa path_permission +EXPORT_SYMBOL vmlinux 0x462211c9 nf_log_register +EXPORT_SYMBOL vmlinux 0x463d9136 find_get_pages_tag +EXPORT_SYMBOL vmlinux 0x464b7070 cancel_dirty_page +EXPORT_SYMBOL vmlinux 0x466c14a7 __delay +EXPORT_SYMBOL vmlinux 0x468a7be7 kernel_setsockopt +EXPORT_SYMBOL vmlinux 0x469e57da blk_init_queue_node +EXPORT_SYMBOL vmlinux 0x46c47fb6 __node_distance +EXPORT_SYMBOL vmlinux 0x46f0a87c __mod_zone_page_state +EXPORT_SYMBOL vmlinux 0x46f53f77 dump_trace +EXPORT_SYMBOL vmlinux 0x47445f17 devm_free_irq +EXPORT_SYMBOL vmlinux 0x475100c2 inet_get_local_port_range +EXPORT_SYMBOL vmlinux 0x475f010b acpi_purge_cached_objects +EXPORT_SYMBOL vmlinux 0x475f05af acpi_set_firmware_waking_vector +EXPORT_SYMBOL vmlinux 0x47634d83 agp_enable +EXPORT_SYMBOL vmlinux 0x477c990d agp_alloc_bridge +EXPORT_SYMBOL vmlinux 0x478239cf follow_up +EXPORT_SYMBOL vmlinux 0x478d10b2 ht_destroy_irq +EXPORT_SYMBOL vmlinux 0x47939e0d __tasklet_hi_schedule +EXPORT_SYMBOL vmlinux 0x479c3c86 find_next_zero_bit +EXPORT_SYMBOL vmlinux 0x47c7a7d1 block_read_full_page +EXPORT_SYMBOL vmlinux 0x481cb9ab acpi_enter_sleep_state_prep +EXPORT_SYMBOL vmlinux 0x4822990e udp_lib_getsockopt +EXPORT_SYMBOL vmlinux 0x48389354 uart_add_one_port +EXPORT_SYMBOL vmlinux 0x483af8d0 pci_iomap +EXPORT_SYMBOL vmlinux 0x4859b8bb rtc_year_days +EXPORT_SYMBOL vmlinux 0x486a35df blk_rq_map_sg +EXPORT_SYMBOL vmlinux 0x486b6407 hweight64 +EXPORT_SYMBOL vmlinux 0x48732822 d_invalidate +EXPORT_SYMBOL vmlinux 0x48824c11 elv_rb_former_request +EXPORT_SYMBOL vmlinux 0x4895effc tcp_proc_register +EXPORT_SYMBOL vmlinux 0x48a8a9c4 swiotlb_sync_single_for_cpu +EXPORT_SYMBOL vmlinux 0x48df9556 put_page +EXPORT_SYMBOL vmlinux 0x48e209f0 rtnl_create_link +EXPORT_SYMBOL vmlinux 0x48fa6671 tcp_initialize_rcv_mss +EXPORT_SYMBOL vmlinux 0x492f53ce xfrm_unregister_type +EXPORT_SYMBOL vmlinux 0x493e25e1 udp_hash +EXPORT_SYMBOL vmlinux 0x495e1ee8 generic_unplug_device +EXPORT_SYMBOL vmlinux 0x49603fb8 security_sb_copy_data +EXPORT_SYMBOL vmlinux 0x496082ac blk_integrity_register +EXPORT_SYMBOL vmlinux 0x496d6048 __skb_checksum_complete +EXPORT_SYMBOL vmlinux 0x49ae7671 do_sync_read +EXPORT_SYMBOL vmlinux 0x49d86741 block_write_begin +EXPORT_SYMBOL vmlinux 0x49da9a9a _read_unlock_bh +EXPORT_SYMBOL vmlinux 0x49ed5cd7 get_write_access +EXPORT_SYMBOL vmlinux 0x49f3f92f set_pages_wb +EXPORT_SYMBOL vmlinux 0x4a1df70f tty_hung_up_p +EXPORT_SYMBOL vmlinux 0x4a23935a submit_bio +EXPORT_SYMBOL vmlinux 0x4a258355 eth_header_cache +EXPORT_SYMBOL vmlinux 0x4a358252 __bitmap_subset +EXPORT_SYMBOL vmlinux 0x4a6ae63e directly_mappable_cdev_bdi +EXPORT_SYMBOL vmlinux 0x4a7d3a35 neigh_create +EXPORT_SYMBOL vmlinux 0x4aea4349 start_tty +EXPORT_SYMBOL vmlinux 0x4b07e779 _spin_unlock_irqrestore +EXPORT_SYMBOL vmlinux 0x4b085dbf agp3_generic_configure +EXPORT_SYMBOL vmlinux 0x4b2f14b4 jiffies_to_timespec +EXPORT_SYMBOL vmlinux 0x4b41395e wait_on_sync_kiocb +EXPORT_SYMBOL vmlinux 0x4b5c47fe sock_queue_rcv_skb +EXPORT_SYMBOL vmlinux 0x4b77c0d1 tcf_hash_insert +EXPORT_SYMBOL vmlinux 0x4b8353a3 dma_pool_free +EXPORT_SYMBOL vmlinux 0x4b971ad2 sk_send_sigurg +EXPORT_SYMBOL vmlinux 0x4ba5baa0 load_gs_index +EXPORT_SYMBOL vmlinux 0x4bbc3e5f pm_flags +EXPORT_SYMBOL vmlinux 0x4bc7c776 acpi_lock_ac_dir +EXPORT_SYMBOL vmlinux 0x4bd30066 alloc_fddidev +EXPORT_SYMBOL vmlinux 0x4bd540dd agp_bind_memory +EXPORT_SYMBOL vmlinux 0x4bdf028e idr_find +EXPORT_SYMBOL vmlinux 0x4c10f276 blk_queue_start_tag +EXPORT_SYMBOL vmlinux 0x4c1182cb bitmap_scnprintf +EXPORT_SYMBOL vmlinux 0x4c15c799 prepare_binprm +EXPORT_SYMBOL vmlinux 0x4c3af445 __request_region +EXPORT_SYMBOL vmlinux 0x4c3fc4f9 kill_litter_super +EXPORT_SYMBOL vmlinux 0x4c4c956e nla_memcmp +EXPORT_SYMBOL vmlinux 0x4cbbd171 __bitmap_weight +EXPORT_SYMBOL vmlinux 0x4cf9a740 security_sb_clone_mnt_opts +EXPORT_SYMBOL vmlinux 0x4d0fc892 __set_page_dirty_buffers +EXPORT_SYMBOL vmlinux 0x4d392ff5 pci_dev_get +EXPORT_SYMBOL vmlinux 0x4d548b28 __getblk +EXPORT_SYMBOL vmlinux 0x4d82b657 __secpath_destroy +EXPORT_SYMBOL vmlinux 0x4db1e1d4 posix_acl_equiv_mode +EXPORT_SYMBOL vmlinux 0x4dc2a7bc truncate_inode_pages_range +EXPORT_SYMBOL vmlinux 0x4dda726b match_strlcpy +EXPORT_SYMBOL vmlinux 0x4ddc4b9f utf8_mbtowc +EXPORT_SYMBOL vmlinux 0x4df119fa __bitmap_parse +EXPORT_SYMBOL vmlinux 0x4df47e9f xfrm_state_flush +EXPORT_SYMBOL vmlinux 0x4e100f60 _spin_unlock_irq +EXPORT_SYMBOL vmlinux 0x4e3567f7 match_int +EXPORT_SYMBOL vmlinux 0x4e55331d blk_unplug +EXPORT_SYMBOL vmlinux 0x4e5dc447 skb_dequeue +EXPORT_SYMBOL vmlinux 0x4e6e8ea7 fg_console +EXPORT_SYMBOL vmlinux 0x4eab2647 mntput_no_expire +EXPORT_SYMBOL vmlinux 0x4ec0792a inet_csk_reset_keepalive_timer +EXPORT_SYMBOL vmlinux 0x4edd72f7 block_all_signals +EXPORT_SYMBOL vmlinux 0x4f0b1f30 dst_alloc +EXPORT_SYMBOL vmlinux 0x4f5438c1 idle_halt +EXPORT_SYMBOL vmlinux 0x4f7b02d4 tcp_make_synack +EXPORT_SYMBOL vmlinux 0x4fa75270 inet_frags_fini +EXPORT_SYMBOL vmlinux 0x4fcee107 __up_read +EXPORT_SYMBOL vmlinux 0x4fdee897 i8042_command +EXPORT_SYMBOL vmlinux 0x500aa5b1 kernel_getsockname +EXPORT_SYMBOL vmlinux 0x50211ee3 tcp_free_md5sig_pool +EXPORT_SYMBOL vmlinux 0x503a3efe pci_unmap_rom +EXPORT_SYMBOL vmlinux 0x503c8340 fifo_create_dflt +EXPORT_SYMBOL vmlinux 0x5065881a uart_suspend_port +EXPORT_SYMBOL vmlinux 0x5074e297 pneigh_enqueue +EXPORT_SYMBOL vmlinux 0x50b5cb2d idr_get_new_above +EXPORT_SYMBOL vmlinux 0x50ba769a kblockd_schedule_work +EXPORT_SYMBOL vmlinux 0x50e893e9 xfrm_find_acq +EXPORT_SYMBOL vmlinux 0x50e91ba1 llc_set_station_handler +EXPORT_SYMBOL vmlinux 0x5113b071 __breadahead +EXPORT_SYMBOL vmlinux 0x5118c382 secure_dccp_sequence_number +EXPORT_SYMBOL vmlinux 0x511a070e pnp_release_card_device +EXPORT_SYMBOL vmlinux 0x5190cbe9 lookup_bdev +EXPORT_SYMBOL vmlinux 0x51d12d4e acpi_pci_disabled +EXPORT_SYMBOL vmlinux 0x51d7a776 acpi_detach_data +EXPORT_SYMBOL vmlinux 0x52026cdf security_sb_parse_opts_str +EXPORT_SYMBOL vmlinux 0x5212317c pci_set_dma_seg_boundary +EXPORT_SYMBOL vmlinux 0x521d63ec wait_for_key_construction +EXPORT_SYMBOL vmlinux 0x522f5573 pv_irq_ops +EXPORT_SYMBOL vmlinux 0x5252f304 __memcpy_toio +EXPORT_SYMBOL vmlinux 0x52728747 blk_init_tags +EXPORT_SYMBOL vmlinux 0x52a58c24 ifla_policy +EXPORT_SYMBOL vmlinux 0x52cbba4c create_proc_entry +EXPORT_SYMBOL vmlinux 0x52d7b2fd llc_sap_list +EXPORT_SYMBOL vmlinux 0x52db29e7 release_sock +EXPORT_SYMBOL vmlinux 0x52fa20c8 xfrm_policy_register_afinfo +EXPORT_SYMBOL vmlinux 0x530b1e98 pm_suspend +EXPORT_SYMBOL vmlinux 0x532f2924 param_get_byte +EXPORT_SYMBOL vmlinux 0x53326531 mempool_alloc_pages +EXPORT_SYMBOL vmlinux 0x533f9e15 devm_request_irq +EXPORT_SYMBOL vmlinux 0x5343b657 pagevec_lookup_tag +EXPORT_SYMBOL vmlinux 0x5394eced boot_cpu_data +EXPORT_SYMBOL vmlinux 0x53c0767c sk_chk_filter +EXPORT_SYMBOL vmlinux 0x53c09bf4 sk_release_kernel +EXPORT_SYMBOL vmlinux 0x53c1bc6c sync_dirty_buffer +EXPORT_SYMBOL vmlinux 0x53ff09fb pci_find_parent_resource +EXPORT_SYMBOL vmlinux 0x54290dc9 nla_validate +EXPORT_SYMBOL vmlinux 0x542c818f netlink_rcv_skb +EXPORT_SYMBOL vmlinux 0x542f6a04 tcp_tso_segment +EXPORT_SYMBOL vmlinux 0x543affb5 per_cpu__kstat +EXPORT_SYMBOL vmlinux 0x54aea442 d_find_alias +EXPORT_SYMBOL vmlinux 0x54b81541 init_timer_deferrable +EXPORT_SYMBOL vmlinux 0x54c075b6 iw_handler_set_thrspy +EXPORT_SYMBOL vmlinux 0x54c6a6f1 inet_select_addr +EXPORT_SYMBOL vmlinux 0x54cc0bda devm_ioremap +EXPORT_SYMBOL vmlinux 0x54e6fcdd net_enable_timestamp +EXPORT_SYMBOL vmlinux 0x550f8ade groups_alloc +EXPORT_SYMBOL vmlinux 0x552600da fsync_bdev +EXPORT_SYMBOL vmlinux 0x552d8241 eth_rebuild_header +EXPORT_SYMBOL vmlinux 0x5594be03 bitmap_remap +EXPORT_SYMBOL vmlinux 0x55d05f19 unregister_8022_client +EXPORT_SYMBOL vmlinux 0x55f151fe cap_netlink_recv +EXPORT_SYMBOL vmlinux 0x5600904f fb_get_color_depth +EXPORT_SYMBOL vmlinux 0x5635a60a vmalloc_user +EXPORT_SYMBOL vmlinux 0x566eab07 compat_ip_setsockopt +EXPORT_SYMBOL vmlinux 0x5675ee96 compute_creds +EXPORT_SYMBOL vmlinux 0x56895db1 vfs_quota_on_path +EXPORT_SYMBOL vmlinux 0x56a1951c kset_unregister +EXPORT_SYMBOL vmlinux 0x56f494e0 smp_call_function +EXPORT_SYMBOL vmlinux 0x570b27bd bdev_read_only +EXPORT_SYMBOL vmlinux 0x570fcf65 inode_permission +EXPORT_SYMBOL vmlinux 0x5724935d page_zero_new_buffers +EXPORT_SYMBOL vmlinux 0x572e85d4 blk_lookup_devt +EXPORT_SYMBOL vmlinux 0x574108ef inet_release +EXPORT_SYMBOL vmlinux 0x5749cbab skb_queue_purge +EXPORT_SYMBOL vmlinux 0x5752f472 pci_bus_type +EXPORT_SYMBOL vmlinux 0x577cc638 mutex_unlock +EXPORT_SYMBOL vmlinux 0x5782e706 __kill_fasync +EXPORT_SYMBOL vmlinux 0x579b9ae6 dev_get_flags +EXPORT_SYMBOL vmlinux 0x57a0870a agp_generic_create_gatt_table +EXPORT_SYMBOL vmlinux 0x57a14a6e vfs_getattr +EXPORT_SYMBOL vmlinux 0x5810f6f2 put_io_context +EXPORT_SYMBOL vmlinux 0x5838f6c9 rtc_valid_tm +EXPORT_SYMBOL vmlinux 0x584738f9 rdmsr_safe_on_cpu +EXPORT_SYMBOL vmlinux 0x5857b225 ioread16_rep +EXPORT_SYMBOL vmlinux 0x58a332b7 compat_sock_get_timestampns +EXPORT_SYMBOL vmlinux 0x58c8d4f1 nf_register_hooks +EXPORT_SYMBOL vmlinux 0x59129563 dquot_release +EXPORT_SYMBOL vmlinux 0x59199cdc tcf_exts_dump +EXPORT_SYMBOL vmlinux 0x5926b831 proto_unregister +EXPORT_SYMBOL vmlinux 0x5934392b fb_register_client +EXPORT_SYMBOL vmlinux 0x594bf15b ioport_map +EXPORT_SYMBOL vmlinux 0x5967c1ba netpoll_send_udp +EXPORT_SYMBOL vmlinux 0x599453a0 pci_unregister_driver +EXPORT_SYMBOL vmlinux 0x59a6ff40 pnp_activate_dev +EXPORT_SYMBOL vmlinux 0x59a74381 fddi_type_trans +EXPORT_SYMBOL vmlinux 0x59c100e9 fail_migrate_page +EXPORT_SYMBOL vmlinux 0x59cf829e inode_double_lock +EXPORT_SYMBOL vmlinux 0x59d140d7 proc_dostring +EXPORT_SYMBOL vmlinux 0x59d696b6 register_module_notifier +EXPORT_SYMBOL vmlinux 0x59da3c6f pci_enable_device_io +EXPORT_SYMBOL vmlinux 0x59ef1f23 pci_fixup_device +EXPORT_SYMBOL vmlinux 0x5a34a45c __kmalloc +EXPORT_SYMBOL vmlinux 0x5a3a0b8b inet_del_protocol +EXPORT_SYMBOL vmlinux 0x5a4896a8 __put_user_2 +EXPORT_SYMBOL vmlinux 0x5a527d4b ip_mc_dec_group +EXPORT_SYMBOL vmlinux 0x5a5e7ea3 simple_read_from_buffer +EXPORT_SYMBOL vmlinux 0x5a62ed47 inode_get_bytes +EXPORT_SYMBOL vmlinux 0x5a69219f __up_write +EXPORT_SYMBOL vmlinux 0x5a744b86 netlink_set_nonroot +EXPORT_SYMBOL vmlinux 0x5a824c9b generic_fillattr +EXPORT_SYMBOL vmlinux 0x5ab65ae7 km_policy_notify +EXPORT_SYMBOL vmlinux 0x5ac376a5 acpi_install_fixed_event_handler +EXPORT_SYMBOL vmlinux 0x5ae46c42 sock_create_lite +EXPORT_SYMBOL vmlinux 0x5b0945b6 pnp_register_card_driver +EXPORT_SYMBOL vmlinux 0x5b10dbf8 noop_qdisc +EXPORT_SYMBOL vmlinux 0x5b51c6a7 acpi_walk_resources +EXPORT_SYMBOL vmlinux 0x5b97c5f8 bio_split +EXPORT_SYMBOL vmlinux 0x5bacdbbc netdev_bonding_change +EXPORT_SYMBOL vmlinux 0x5bae2eac acpi_extract_package +EXPORT_SYMBOL vmlinux 0x5bec44cb __down_write +EXPORT_SYMBOL vmlinux 0x5befbfd3 inet_dgram_ops +EXPORT_SYMBOL vmlinux 0x5bf98e14 dev_set_allmulti +EXPORT_SYMBOL vmlinux 0x5c137694 tcp_sync_mss +EXPORT_SYMBOL vmlinux 0x5c46b6fa posix_acl_chmod_masq +EXPORT_SYMBOL vmlinux 0x5c65d7f6 register_nls +EXPORT_SYMBOL vmlinux 0x5c9a6c03 swiotlb_map_sg_attrs +EXPORT_SYMBOL vmlinux 0x5ca0000d schedule_delayed_work_on +EXPORT_SYMBOL vmlinux 0x5cc8e015 iov_iter_single_seg_count +EXPORT_SYMBOL vmlinux 0x5d113035 vm_stat +EXPORT_SYMBOL vmlinux 0x5d1d43dd dquot_commit_info +EXPORT_SYMBOL vmlinux 0x5d44d6c5 dev_kfree_skb_irq +EXPORT_SYMBOL vmlinux 0x5d559449 acpi_lock_battery_dir +EXPORT_SYMBOL vmlinux 0x5d5666fd page_symlink_inode_operations +EXPORT_SYMBOL vmlinux 0x5d6d7f16 kernel_bind +EXPORT_SYMBOL vmlinux 0x5d7320b1 __blk_run_queue +EXPORT_SYMBOL vmlinux 0x5d73b5f8 km_waitq +EXPORT_SYMBOL vmlinux 0x5d8a25aa sock_no_setsockopt +EXPORT_SYMBOL vmlinux 0x5dbcfa4f boot_cpu_physical_apicid +EXPORT_SYMBOL vmlinux 0x5e0f7602 pcix_set_mmrbc +EXPORT_SYMBOL vmlinux 0x5e2f2632 tty_write_room +EXPORT_SYMBOL vmlinux 0x5e372f4b __inet6_lookup_established +EXPORT_SYMBOL vmlinux 0x5e57c206 compat_sock_get_timestamp +EXPORT_SYMBOL vmlinux 0x5e79ebec gen_replace_estimator +EXPORT_SYMBOL vmlinux 0x5e7f6a25 tcp_setsockopt +EXPORT_SYMBOL vmlinux 0x5e8867a8 bh_uptodate_or_lock +EXPORT_SYMBOL vmlinux 0x5e9f09df get_io_context +EXPORT_SYMBOL vmlinux 0x5ea520c5 tcp_select_initial_window +EXPORT_SYMBOL vmlinux 0x5ec07152 skb_free_datagram +EXPORT_SYMBOL vmlinux 0x5ed040b0 pm_set_vt_switch +EXPORT_SYMBOL vmlinux 0x5edd0762 bin2bcd +EXPORT_SYMBOL vmlinux 0x5ee22164 block_is_partially_uptodate +EXPORT_SYMBOL vmlinux 0x5ef7e27d __inc_zone_page_state +EXPORT_SYMBOL vmlinux 0x5f317c0b arp_create +EXPORT_SYMBOL vmlinux 0x5f5f8b03 alloc_pages_current +EXPORT_SYMBOL vmlinux 0x5f73ba75 bdget +EXPORT_SYMBOL vmlinux 0x5fcb26f7 seq_open +EXPORT_SYMBOL vmlinux 0x5ff42b08 acpi_video_get_capabilities +EXPORT_SYMBOL vmlinux 0x600683d3 do_unblank_screen +EXPORT_SYMBOL vmlinux 0x6037ae52 pcim_pin_device +EXPORT_SYMBOL vmlinux 0x60400b7f pv_lock_ops +EXPORT_SYMBOL vmlinux 0x60477b53 generic_delete_inode +EXPORT_SYMBOL vmlinux 0x60492806 ethtool_op_set_ufo +EXPORT_SYMBOL vmlinux 0x604d1c98 end_buffer_read_sync +EXPORT_SYMBOL vmlinux 0x6053ccbf pid_task +EXPORT_SYMBOL vmlinux 0x60593e57 inet_sendmsg +EXPORT_SYMBOL vmlinux 0x605bdba3 module_put +EXPORT_SYMBOL vmlinux 0x605c8bde radix_tree_delete +EXPORT_SYMBOL vmlinux 0x608c2831 warn_on_slowpath +EXPORT_SYMBOL vmlinux 0x609f1c7e synchronize_net +EXPORT_SYMBOL vmlinux 0x60a32ea9 pm_power_off +EXPORT_SYMBOL vmlinux 0x60cf0637 skb_append_datato_frags +EXPORT_SYMBOL vmlinux 0x60da7694 agp_generic_insert_memory +EXPORT_SYMBOL vmlinux 0x60facb3b netlink_unicast +EXPORT_SYMBOL vmlinux 0x60fdd212 sock_common_getsockopt +EXPORT_SYMBOL vmlinux 0x6111e1bc init_timer +EXPORT_SYMBOL vmlinux 0x611a6f34 netpoll_cleanup +EXPORT_SYMBOL vmlinux 0x612390ad netpoll_set_trap +EXPORT_SYMBOL vmlinux 0x6141dde5 km_new_mapping +EXPORT_SYMBOL vmlinux 0x61567f48 serio_open +EXPORT_SYMBOL vmlinux 0x6159c44d request_key_async +EXPORT_SYMBOL vmlinux 0x616e6349 vfs_quota_off +EXPORT_SYMBOL vmlinux 0x618d8299 set_notify_swap_entry_free +EXPORT_SYMBOL vmlinux 0x61a02066 simple_readpage +EXPORT_SYMBOL vmlinux 0x61b7b126 simple_strtoull +EXPORT_SYMBOL vmlinux 0x61c1c365 unregister_key_type +EXPORT_SYMBOL vmlinux 0x62049256 acpi_disable +EXPORT_SYMBOL vmlinux 0x6225f204 filp_close +EXPORT_SYMBOL vmlinux 0x6226ed77 register_netdevice +EXPORT_SYMBOL vmlinux 0x6237f6b5 acpi_enable_event +EXPORT_SYMBOL vmlinux 0x62737e1d sock_unregister +EXPORT_SYMBOL vmlinux 0x62748e70 acpi_set_current_resources +EXPORT_SYMBOL vmlinux 0x62827bec security_secctx_to_secid +EXPORT_SYMBOL vmlinux 0x62e7bc79 blk_start_queueing +EXPORT_SYMBOL vmlinux 0x6334052a xfrm4_rcv_encap +EXPORT_SYMBOL vmlinux 0x63499009 pci_assign_resource +EXPORT_SYMBOL vmlinux 0x6355bac4 dst_destroy +EXPORT_SYMBOL vmlinux 0x63694ce7 key_unlink +EXPORT_SYMBOL vmlinux 0x636a5691 acpi_register_ioapic +EXPORT_SYMBOL vmlinux 0x638675b4 swiotlb_sync_single_for_device +EXPORT_SYMBOL vmlinux 0x6397ca94 inet_stream_connect +EXPORT_SYMBOL vmlinux 0x63ba6312 skb_recv_datagram +EXPORT_SYMBOL vmlinux 0x63c56dc0 dev_unicast_add +EXPORT_SYMBOL vmlinux 0x63ecad53 register_netdevice_notifier +EXPORT_SYMBOL vmlinux 0x63ed4f65 ioremap_cache +EXPORT_SYMBOL vmlinux 0x63f1d58f request_key_async_with_auxdata +EXPORT_SYMBOL vmlinux 0x63fc232f strlen_user +EXPORT_SYMBOL vmlinux 0x6403e338 tcp_memory_pressure +EXPORT_SYMBOL vmlinux 0x6406156b skb_queue_head +EXPORT_SYMBOL vmlinux 0x640ae2c7 netpoll_setup +EXPORT_SYMBOL vmlinux 0x642e54ac __wake_up +EXPORT_SYMBOL vmlinux 0x643bfac1 find_task_by_pid_type_ns +EXPORT_SYMBOL vmlinux 0x644703ed sock_create_kern +EXPORT_SYMBOL vmlinux 0x644809c5 register_sysctl_paths +EXPORT_SYMBOL vmlinux 0x6451294b posix_acl_valid +EXPORT_SYMBOL vmlinux 0x6466a1e6 mempool_alloc +EXPORT_SYMBOL vmlinux 0x6478134c ec_burst_enable +EXPORT_SYMBOL vmlinux 0x6482dd65 pci_bus_size_bridges +EXPORT_SYMBOL vmlinux 0x6492cc6e sg_miter_next +EXPORT_SYMBOL vmlinux 0x64999478 congestion_wait +EXPORT_SYMBOL vmlinux 0x64cd5d16 init_waitqueue_head +EXPORT_SYMBOL vmlinux 0x64ea1189 tcf_em_tree_validate +EXPORT_SYMBOL vmlinux 0x650128e7 br_fdb_get_hook +EXPORT_SYMBOL vmlinux 0x650fb346 add_wait_queue +EXPORT_SYMBOL vmlinux 0x65408378 zlib_inflate_blob +EXPORT_SYMBOL vmlinux 0x65414e67 dev_valid_name +EXPORT_SYMBOL vmlinux 0x656b8dfc netif_device_attach +EXPORT_SYMBOL vmlinux 0x65930cce pcim_enable_device +EXPORT_SYMBOL vmlinux 0x6615b0e3 vfs_dq_transfer +EXPORT_SYMBOL vmlinux 0x665eba3d kernel_recvmsg +EXPORT_SYMBOL vmlinux 0x66895f4c blk_verify_command +EXPORT_SYMBOL vmlinux 0x668da8d5 zlib_inflateIncomp +EXPORT_SYMBOL vmlinux 0x66b57a38 elv_dispatch_sort +EXPORT_SYMBOL vmlinux 0x66c0a7f6 blk_queue_max_hw_segments +EXPORT_SYMBOL vmlinux 0x66cac0ec ether_setup +EXPORT_SYMBOL vmlinux 0x671c7d41 call_usermodehelper_stdinpipe +EXPORT_SYMBOL vmlinux 0x672144bd strlcpy +EXPORT_SYMBOL vmlinux 0x6729d3df __get_user_4 +EXPORT_SYMBOL vmlinux 0x673f815e agp_bridges +EXPORT_SYMBOL vmlinux 0x6768497e pcim_iomap_regions +EXPORT_SYMBOL vmlinux 0x6782a2e5 cdev_alloc +EXPORT_SYMBOL vmlinux 0x67a10240 k8_northbridges +EXPORT_SYMBOL vmlinux 0x67b27ec1 tty_std_termios +EXPORT_SYMBOL vmlinux 0x67bf331d seq_open_private +EXPORT_SYMBOL vmlinux 0x67dd338f kthread_bind +EXPORT_SYMBOL vmlinux 0x67e71b77 __mutex_init +EXPORT_SYMBOL vmlinux 0x6826e8f2 bdi_register_dev +EXPORT_SYMBOL vmlinux 0x684f5e71 textsearch_unregister +EXPORT_SYMBOL vmlinux 0x687c3f59 icmp_send +EXPORT_SYMBOL vmlinux 0x688421c6 agp_bridge +EXPORT_SYMBOL vmlinux 0x689e14de compat_ip_getsockopt +EXPORT_SYMBOL vmlinux 0x68c2eb30 sock_no_socketpair +EXPORT_SYMBOL vmlinux 0x6907d4e9 idr_for_each +EXPORT_SYMBOL vmlinux 0x69192b5a iommu_num_pages +EXPORT_SYMBOL vmlinux 0x6925ce73 tty_unthrottle +EXPORT_SYMBOL vmlinux 0x695f9ac9 bd_set_size +EXPORT_SYMBOL vmlinux 0x6971447a rtc_month_days +EXPORT_SYMBOL vmlinux 0x697353be fb_blank +EXPORT_SYMBOL vmlinux 0x697b066f simple_write_begin +EXPORT_SYMBOL vmlinux 0x698d17d4 cdev_init +EXPORT_SYMBOL vmlinux 0x69927dff try_acquire_console_sem +EXPORT_SYMBOL vmlinux 0x69a0ca7d iowrite16be +EXPORT_SYMBOL vmlinux 0x6a037cf1 mempool_kfree +EXPORT_SYMBOL vmlinux 0x6a300ae5 remove_arg_zero +EXPORT_SYMBOL vmlinux 0x6a38f31a iov_iter_copy_from_user_atomic +EXPORT_SYMBOL vmlinux 0x6a43f317 acpi_bus_register_driver +EXPORT_SYMBOL vmlinux 0x6a47571d __set_personality +EXPORT_SYMBOL vmlinux 0x6a5f98a0 ida_get_new_above +EXPORT_SYMBOL vmlinux 0x6a5fa363 sigprocmask +EXPORT_SYMBOL vmlinux 0x6a78d717 nf_ct_attach +EXPORT_SYMBOL vmlinux 0x6a9ca5db kobject_get +EXPORT_SYMBOL vmlinux 0x6aadbdb7 blk_run_queue +EXPORT_SYMBOL vmlinux 0x6acb973d iowrite32be +EXPORT_SYMBOL vmlinux 0x6ad276b6 handle_sysrq +EXPORT_SYMBOL vmlinux 0x6add5c9a dmi_find_device +EXPORT_SYMBOL vmlinux 0x6af37040 pnp_possible_config +EXPORT_SYMBOL vmlinux 0x6afb950f proc_symlink +EXPORT_SYMBOL vmlinux 0x6b08e390 kmem_ptr_validate +EXPORT_SYMBOL vmlinux 0x6b1b67d3 __bdevname +EXPORT_SYMBOL vmlinux 0x6b2dc060 dump_stack +EXPORT_SYMBOL vmlinux 0x6b4e5a52 radix_tree_lookup_slot +EXPORT_SYMBOL vmlinux 0x6b8e83e1 poll_initwait +EXPORT_SYMBOL vmlinux 0x6b9b88f3 sleep_on +EXPORT_SYMBOL vmlinux 0x6bad91c0 sock_get_timestamp +EXPORT_SYMBOL vmlinux 0x6bafbced mod_timer +EXPORT_SYMBOL vmlinux 0x6bc56c67 radix_tree_next_hole +EXPORT_SYMBOL vmlinux 0x6bdcfd99 qdisc_class_hash_remove +EXPORT_SYMBOL vmlinux 0x6be934dd sock_wfree +EXPORT_SYMBOL vmlinux 0x6c03ddfb skb_kill_datagram +EXPORT_SYMBOL vmlinux 0x6c1066f3 __page_cache_alloc +EXPORT_SYMBOL vmlinux 0x6c389761 acpi_bus_get_private_data +EXPORT_SYMBOL vmlinux 0x6c50a24c arp_xmit +EXPORT_SYMBOL vmlinux 0x6c59a8b8 mpage_writepage +EXPORT_SYMBOL vmlinux 0x6c61ce70 num_registered_fb +EXPORT_SYMBOL vmlinux 0x6c702af7 sysctl_udp_rmem_min +EXPORT_SYMBOL vmlinux 0x6c768fb0 bio_pair_release +EXPORT_SYMBOL vmlinux 0x6c9bda15 pci_bus_add_devices +EXPORT_SYMBOL vmlinux 0x6cbe7632 posix_acl_to_xattr +EXPORT_SYMBOL vmlinux 0x6cf1d262 con_is_bound +EXPORT_SYMBOL vmlinux 0x6d0da34c param_get_short +EXPORT_SYMBOL vmlinux 0x6d11e3fc vfs_readv +EXPORT_SYMBOL vmlinux 0x6d1ced27 vcc_sklist_lock +EXPORT_SYMBOL vmlinux 0x6d27ef64 __bitmap_empty +EXPORT_SYMBOL vmlinux 0x6d294e43 clock_t_to_jiffies +EXPORT_SYMBOL vmlinux 0x6d2dfc61 scsi_cmd_ioctl +EXPORT_SYMBOL vmlinux 0x6d2f7425 tcp_timewait_state_process +EXPORT_SYMBOL vmlinux 0x6d334118 __get_user_8 +EXPORT_SYMBOL vmlinux 0x6d340f64 tty_termios_input_baud_rate +EXPORT_SYMBOL vmlinux 0x6d47d90d groups_free +EXPORT_SYMBOL vmlinux 0x6d6a5315 sock_no_accept +EXPORT_SYMBOL vmlinux 0x6d86f138 register_binfmt +EXPORT_SYMBOL vmlinux 0x6d9e5438 generic_read_dir +EXPORT_SYMBOL vmlinux 0x6db2c5ed is_bad_inode +EXPORT_SYMBOL vmlinux 0x6dc0c24b complete_and_exit +EXPORT_SYMBOL vmlinux 0x6de6bf83 radix_tree_lookup +EXPORT_SYMBOL vmlinux 0x6debff71 dev_mc_add +EXPORT_SYMBOL vmlinux 0x6def2db2 half_md4_transform +EXPORT_SYMBOL vmlinux 0x6e07a54e acpi_get_gpe_status +EXPORT_SYMBOL vmlinux 0x6e1a4bbb udp_hash_lock +EXPORT_SYMBOL vmlinux 0x6e20eada dev_disable_lro +EXPORT_SYMBOL vmlinux 0x6e57a640 inet_proto_csum_replace4 +EXPORT_SYMBOL vmlinux 0x6e5c88b0 kobject_del +EXPORT_SYMBOL vmlinux 0x6e634265 __sk_dst_check +EXPORT_SYMBOL vmlinux 0x6e67679e arp_tbl +EXPORT_SYMBOL vmlinux 0x6e720ff2 rtnl_unlock +EXPORT_SYMBOL vmlinux 0x6e7f3879 d_instantiate_unique +EXPORT_SYMBOL vmlinux 0x6e9dd606 __symbol_put +EXPORT_SYMBOL vmlinux 0x6e9f7e97 iov_iter_copy_from_user +EXPORT_SYMBOL vmlinux 0x6ead242b cond_resched_lock +EXPORT_SYMBOL vmlinux 0x6ebd8306 skb_copy_datagram_from_iovec +EXPORT_SYMBOL vmlinux 0x6eda0328 remove_proc_entry +EXPORT_SYMBOL vmlinux 0x6ee24c32 zero_fill_bio +EXPORT_SYMBOL vmlinux 0x6eeb97e9 qdisc_destroy +EXPORT_SYMBOL vmlinux 0x6f2474eb elv_rb_add +EXPORT_SYMBOL vmlinux 0x6f2cf09b tcp_v4_syn_recv_sock +EXPORT_SYMBOL vmlinux 0x6f4b6a66 con_set_default_unimap +EXPORT_SYMBOL vmlinux 0x6f5d6ad7 __inet6_hash +EXPORT_SYMBOL vmlinux 0x6f7b9cf1 per_cpu__cpu_info +EXPORT_SYMBOL vmlinux 0x6f93e46e sock_no_ioctl +EXPORT_SYMBOL vmlinux 0x6fc4b239 netlink_ack +EXPORT_SYMBOL vmlinux 0x6fcb87a1 touch_softlockup_watchdog +EXPORT_SYMBOL vmlinux 0x7008a9b7 timespec_to_jiffies +EXPORT_SYMBOL vmlinux 0x7034d267 skb_prepare_seq_read +EXPORT_SYMBOL vmlinux 0x7054a3e4 request_dma +EXPORT_SYMBOL vmlinux 0x70830857 __invalidate_device +EXPORT_SYMBOL vmlinux 0x70d8ab82 acpi_acquire_global_lock +EXPORT_SYMBOL vmlinux 0x70f14d15 generic_write_end +EXPORT_SYMBOL vmlinux 0x70f540d1 tcp_parse_options +EXPORT_SYMBOL vmlinux 0x7129e5f8 hex_asc +EXPORT_SYMBOL vmlinux 0x712aa29b _spin_lock_irqsave +EXPORT_SYMBOL vmlinux 0x71342640 blk_queue_bounce +EXPORT_SYMBOL vmlinux 0x71356fba remove_wait_queue +EXPORT_SYMBOL vmlinux 0x7150811f __seq_open_private +EXPORT_SYMBOL vmlinux 0x7171121c overflowgid +EXPORT_SYMBOL vmlinux 0x71a50dbc register_blkdev +EXPORT_SYMBOL vmlinux 0x71c45313 remap_vmalloc_range +EXPORT_SYMBOL vmlinux 0x71f6eb38 sg_copy_from_buffer +EXPORT_SYMBOL vmlinux 0x72207ad0 elv_rb_latter_request +EXPORT_SYMBOL vmlinux 0x72270e35 do_gettimeofday +EXPORT_SYMBOL vmlinux 0x7242e96d strnchr +EXPORT_SYMBOL vmlinux 0x729ec54a __alloc_pages_internal +EXPORT_SYMBOL vmlinux 0x729feaa1 __wait_on_buffer +EXPORT_SYMBOL vmlinux 0x72a795bc write_cache_pages +EXPORT_SYMBOL vmlinux 0x72b243d4 free_dma +EXPORT_SYMBOL vmlinux 0x72b3cbd5 ipv4_specific +EXPORT_SYMBOL vmlinux 0x72bc4179 agp_copy_info +EXPORT_SYMBOL vmlinux 0x72bf2140 mtrr_add +EXPORT_SYMBOL vmlinux 0x72df78b4 bh_submit_read +EXPORT_SYMBOL vmlinux 0x72e87387 kernel_sock_ioctl +EXPORT_SYMBOL vmlinux 0x735a0bd5 native_io_delay +EXPORT_SYMBOL vmlinux 0x7389c9a8 acpi_bus_get_power +EXPORT_SYMBOL vmlinux 0x739ee22d gen_pool_add +EXPORT_SYMBOL vmlinux 0x73bc7f6a kill_fasync +EXPORT_SYMBOL vmlinux 0x73e2a595 __scm_destroy +EXPORT_SYMBOL vmlinux 0x740a1b95 reserve_evntsel_nmi +EXPORT_SYMBOL vmlinux 0x740a36e6 vfs_get_dqinfo +EXPORT_SYMBOL vmlinux 0x74202777 ioremap_prot +EXPORT_SYMBOL vmlinux 0x7456b0d0 unregister_qdisc +EXPORT_SYMBOL vmlinux 0x7485e15e unregister_chrdev_region +EXPORT_SYMBOL vmlinux 0x748caf40 down +EXPORT_SYMBOL vmlinux 0x74cc1cbe unregister_cpu_notifier +EXPORT_SYMBOL vmlinux 0x74cc238d current_kernel_time +EXPORT_SYMBOL vmlinux 0x74e48b14 blk_complete_request +EXPORT_SYMBOL vmlinux 0x74fcae6e remap_pfn_range +EXPORT_SYMBOL vmlinux 0x7538b132 agp_off +EXPORT_SYMBOL vmlinux 0x756e6992 strnicmp +EXPORT_SYMBOL vmlinux 0x75bdea12 iommu_area_alloc +EXPORT_SYMBOL vmlinux 0x75ea9531 key_negate_and_link +EXPORT_SYMBOL vmlinux 0x75f7d5de acpi_bus_get_status +EXPORT_SYMBOL vmlinux 0x760a0f4f yield +EXPORT_SYMBOL vmlinux 0x760b437a unregister_inetaddr_notifier +EXPORT_SYMBOL vmlinux 0x7632c515 __kfree_skb +EXPORT_SYMBOL vmlinux 0x765adb05 fb_class +EXPORT_SYMBOL vmlinux 0x767dd8fd acpi_get_irq_routing_table +EXPORT_SYMBOL vmlinux 0x767ddb02 set_memory_wc +EXPORT_SYMBOL vmlinux 0x7693cb26 __neigh_event_send +EXPORT_SYMBOL vmlinux 0x76a83290 netif_carrier_on +EXPORT_SYMBOL vmlinux 0x76bf656d __bitmap_shift_left +EXPORT_SYMBOL vmlinux 0x76d03c8a generic_setlease +EXPORT_SYMBOL vmlinux 0x76d3cd60 laptop_mode +EXPORT_SYMBOL vmlinux 0x76f3f8a5 num_k8_northbridges +EXPORT_SYMBOL vmlinux 0x7712d13c qdisc_watchdog_init +EXPORT_SYMBOL vmlinux 0x77449a9b elv_rq_merge_ok +EXPORT_SYMBOL vmlinux 0x77452c0a uart_remove_one_port +EXPORT_SYMBOL vmlinux 0x77489bd3 register_key_type +EXPORT_SYMBOL vmlinux 0x77a108df _write_unlock_irqrestore +EXPORT_SYMBOL vmlinux 0x77dd1ba8 blk_integrity_unregister +EXPORT_SYMBOL vmlinux 0x77eb5848 vfs_set_dqinfo +EXPORT_SYMBOL vmlinux 0x77ecac9f zlib_inflateEnd +EXPORT_SYMBOL vmlinux 0x77f53abc acpi_get_vendor_resource +EXPORT_SYMBOL vmlinux 0x781b3007 fb_validate_mode +EXPORT_SYMBOL vmlinux 0x782e226c skb_copy +EXPORT_SYMBOL vmlinux 0x785148a3 idr_destroy +EXPORT_SYMBOL vmlinux 0x786858b4 task_nice +EXPORT_SYMBOL vmlinux 0x7876648c sock_release +EXPORT_SYMBOL vmlinux 0x78a484c9 _read_unlock_irqrestore +EXPORT_SYMBOL vmlinux 0x78ae6073 init_net +EXPORT_SYMBOL vmlinux 0x78c44d93 xfrm_state_register_afinfo +EXPORT_SYMBOL vmlinux 0x78df6bd7 no_pci_devices +EXPORT_SYMBOL vmlinux 0x79002a41 neigh_connected_output +EXPORT_SYMBOL vmlinux 0x794c1398 dmi_check_system +EXPORT_SYMBOL vmlinux 0x794cacce sg_miter_start +EXPORT_SYMBOL vmlinux 0x79656409 cpu_online_map +EXPORT_SYMBOL vmlinux 0x799b0338 dev_driver_string +EXPORT_SYMBOL vmlinux 0x79aa04a2 get_random_bytes +EXPORT_SYMBOL vmlinux 0x79aa05a8 match_token +EXPORT_SYMBOL vmlinux 0x79b0144d close_bdev_excl +EXPORT_SYMBOL vmlinux 0x79ce1a0b try_to_free_buffers +EXPORT_SYMBOL vmlinux 0x79d78989 set_irq_chip +EXPORT_SYMBOL vmlinux 0x7a2a837d strict_strtol +EXPORT_SYMBOL vmlinux 0x7a36d6ca free_netdev +EXPORT_SYMBOL vmlinux 0x7a3e0db2 init_task +EXPORT_SYMBOL vmlinux 0x7a848702 _read_lock_irqsave +EXPORT_SYMBOL vmlinux 0x7aad16b2 alloc_etherdev_mq +EXPORT_SYMBOL vmlinux 0x7ab4b211 llc_mac_hdr_init +EXPORT_SYMBOL vmlinux 0x7abb01e6 dev_alloc_name +EXPORT_SYMBOL vmlinux 0x7ae26053 input_register_handler +EXPORT_SYMBOL vmlinux 0x7ae73de1 alloc_pages_exact +EXPORT_SYMBOL vmlinux 0x7aec9089 clear_user +EXPORT_SYMBOL vmlinux 0x7b0c84c4 acpi_remove_table_handler +EXPORT_SYMBOL vmlinux 0x7b52a859 wrmsr_safe_on_cpu +EXPORT_SYMBOL vmlinux 0x7b57e3db alloc_netdev_mq +EXPORT_SYMBOL vmlinux 0x7b759471 alloc_file +EXPORT_SYMBOL vmlinux 0x7b82c913 blk_queue_ordered +EXPORT_SYMBOL vmlinux 0x7b8f4c40 key_create_or_update +EXPORT_SYMBOL vmlinux 0x7bac9caf copy_strings_kernel +EXPORT_SYMBOL vmlinux 0x7bfd9907 agp_generic_free_gatt_table +EXPORT_SYMBOL vmlinux 0x7bff3be7 iov_iter_advance +EXPORT_SYMBOL vmlinux 0x7c14c409 skb_pull +EXPORT_SYMBOL vmlinux 0x7c21f7b4 bio_endio +EXPORT_SYMBOL vmlinux 0x7c3c7cf8 qdisc_class_hash_grow +EXPORT_SYMBOL vmlinux 0x7c46233a cpufreq_quick_get +EXPORT_SYMBOL vmlinux 0x7c60d66e getname +EXPORT_SYMBOL vmlinux 0x7c70d500 tcp_v4_md5_do_del +EXPORT_SYMBOL vmlinux 0x7c725bd8 __fatal_signal_pending +EXPORT_SYMBOL vmlinux 0x7c904ded unregister_module_notifier +EXPORT_SYMBOL vmlinux 0x7cb1ae69 cpu_down +EXPORT_SYMBOL vmlinux 0x7cb693b2 sock_setsockopt +EXPORT_SYMBOL vmlinux 0x7cd7e6e6 misc_deregister +EXPORT_SYMBOL vmlinux 0x7cdb981b ip_defrag +EXPORT_SYMBOL vmlinux 0x7d047e7e acpi_ut_exception +EXPORT_SYMBOL vmlinux 0x7d11c268 jiffies +EXPORT_SYMBOL vmlinux 0x7d64fdcf acpi_bus_start +EXPORT_SYMBOL vmlinux 0x7d698583 swiotlb_unmap_single_attrs +EXPORT_SYMBOL vmlinux 0x7d6e5a2e pci_set_power_state +EXPORT_SYMBOL vmlinux 0x7d84d232 sysctl_data +EXPORT_SYMBOL vmlinux 0x7d850612 utf8_mbstowcs +EXPORT_SYMBOL vmlinux 0x7d8e01cb do_splice_to +EXPORT_SYMBOL vmlinux 0x7d94f746 acpi_os_write_port +EXPORT_SYMBOL vmlinux 0x7da56a06 alloc_pci_dev +EXPORT_SYMBOL vmlinux 0x7dc8ef71 ilookup +EXPORT_SYMBOL vmlinux 0x7dcd35be blk_queue_merge_bvec +EXPORT_SYMBOL vmlinux 0x7dceceac capable +EXPORT_SYMBOL vmlinux 0x7dd2d084 ip_fragment +EXPORT_SYMBOL vmlinux 0x7ded3931 kill_pgrp +EXPORT_SYMBOL vmlinux 0x7e16c6db blk_requeue_request +EXPORT_SYMBOL vmlinux 0x7e25dbae pci_dev_put +EXPORT_SYMBOL vmlinux 0x7e3c84b8 ip_queue_xmit +EXPORT_SYMBOL vmlinux 0x7e8e9363 xfrm_nl +EXPORT_SYMBOL vmlinux 0x7e9a55ea xfrm_lookup +EXPORT_SYMBOL vmlinux 0x7e9ebb05 kernel_thread +EXPORT_SYMBOL vmlinux 0x7ebbe134 grab_cache_page_nowait +EXPORT_SYMBOL vmlinux 0x7ec9bfbc strncpy +EXPORT_SYMBOL vmlinux 0x7ecb5517 ps2_init +EXPORT_SYMBOL vmlinux 0x7ee91c1d _spin_trylock +EXPORT_SYMBOL vmlinux 0x7eeafd7c names_cachep +EXPORT_SYMBOL vmlinux 0x7ef92d6c ___pskb_trim +EXPORT_SYMBOL vmlinux 0x7efbe560 per_cpu__cpu_core_map +EXPORT_SYMBOL vmlinux 0x7f24de73 jiffies_to_usecs +EXPORT_SYMBOL vmlinux 0x7f293ce1 mark_page_accessed +EXPORT_SYMBOL vmlinux 0x7f3397b0 block_invalidatepage +EXPORT_SYMBOL vmlinux 0x7f60dd6e set_pages_nx +EXPORT_SYMBOL vmlinux 0x7f8723bd pcie_mch_quirk +EXPORT_SYMBOL vmlinux 0x7f9ca7d9 dentry_unhash +EXPORT_SYMBOL vmlinux 0x7fc4880f sync_inode +EXPORT_SYMBOL vmlinux 0x7fda79f0 d_prune_aliases +EXPORT_SYMBOL vmlinux 0x7fedbd8f console_stop +EXPORT_SYMBOL vmlinux 0x7ff17874 nf_getsockopt +EXPORT_SYMBOL vmlinux 0x7ff78ebe proc_doulongvec_ms_jiffies_minmax +EXPORT_SYMBOL vmlinux 0x80158208 sock_common_setsockopt +EXPORT_SYMBOL vmlinux 0x8022e7a7 dev_mc_sync +EXPORT_SYMBOL vmlinux 0x807af780 vfs_quota_sync +EXPORT_SYMBOL vmlinux 0x80f79a03 simple_rename +EXPORT_SYMBOL vmlinux 0x810fbf64 scm_fp_dup +EXPORT_SYMBOL vmlinux 0x814066cd find_lock_page +EXPORT_SYMBOL vmlinux 0x81409231 sock_i_ino +EXPORT_SYMBOL vmlinux 0x81472677 acpi_get_table +EXPORT_SYMBOL vmlinux 0x814e7730 nf_ct_destroy +EXPORT_SYMBOL vmlinux 0x815b5dd4 match_octal +EXPORT_SYMBOL vmlinux 0x815f2897 empty_zero_page +EXPORT_SYMBOL vmlinux 0x81be3fbc inet_ioctl +EXPORT_SYMBOL vmlinux 0x81c8f33e dma_async_memcpy_buf_to_pg +EXPORT_SYMBOL vmlinux 0x81df6172 skb_unlink +EXPORT_SYMBOL vmlinux 0x81e6b37f dmi_get_system_info +EXPORT_SYMBOL vmlinux 0x81ed6dbe pskb_copy +EXPORT_SYMBOL vmlinux 0x82072614 tasklet_kill +EXPORT_SYMBOL vmlinux 0x820d225f print_mac +EXPORT_SYMBOL vmlinux 0x8251bcc3 bitmap_release_region +EXPORT_SYMBOL vmlinux 0x828744bc make_EII_client +EXPORT_SYMBOL vmlinux 0x82a0aa6f bio_alloc +EXPORT_SYMBOL vmlinux 0x82a70d7d tty_name +EXPORT_SYMBOL vmlinux 0x82b40820 swiotlb_unmap_sg_attrs +EXPORT_SYMBOL vmlinux 0x82d53040 simple_pin_fs +EXPORT_SYMBOL vmlinux 0x82e9c083 csum_partial_copy_fromiovecend +EXPORT_SYMBOL vmlinux 0x8300c0db sock_no_bind +EXPORT_SYMBOL vmlinux 0x8317e20a completion_done +EXPORT_SYMBOL vmlinux 0x8344a050 posix_unblock_lock +EXPORT_SYMBOL vmlinux 0x8363c3d4 smp_call_function_mask +EXPORT_SYMBOL vmlinux 0x83800bfa kref_init +EXPORT_SYMBOL vmlinux 0x8381e9ce dev_getbyhwaddr +EXPORT_SYMBOL vmlinux 0x8395236c pci_dev_driver +EXPORT_SYMBOL vmlinux 0x83a476ce bitmap_scnlistprintf +EXPORT_SYMBOL vmlinux 0x84005c54 pcim_iounmap_regions +EXPORT_SYMBOL vmlinux 0x8408fe69 __serio_register_driver +EXPORT_SYMBOL vmlinux 0x84251ca9 f_setown +EXPORT_SYMBOL vmlinux 0x845fe06f nf_unregister_queue_handler +EXPORT_SYMBOL vmlinux 0x84d7f055 gnet_stats_start_copy_compat +EXPORT_SYMBOL vmlinux 0x8508869b current_fs_time +EXPORT_SYMBOL vmlinux 0x85348c80 ethtool_op_get_tso +EXPORT_SYMBOL vmlinux 0x8540ffeb xfrm_policy_byid +EXPORT_SYMBOL vmlinux 0x854427e6 udp_ioctl +EXPORT_SYMBOL vmlinux 0x85670f1d rtnl_is_locked +EXPORT_SYMBOL vmlinux 0x856ff879 ethtool_op_get_link +EXPORT_SYMBOL vmlinux 0x859b24ba acpi_is_video_device +EXPORT_SYMBOL vmlinux 0x859b768b bio_integrity_trim +EXPORT_SYMBOL vmlinux 0x85abc85f strncmp +EXPORT_SYMBOL vmlinux 0x85d1d0d5 path_lookup +EXPORT_SYMBOL vmlinux 0x85df9b6c strsep +EXPORT_SYMBOL vmlinux 0x8622fd49 xfrm_find_acq_byseq +EXPORT_SYMBOL vmlinux 0x8631f188 radix_tree_tag_set +EXPORT_SYMBOL vmlinux 0x863cb91a utf8_wcstombs +EXPORT_SYMBOL vmlinux 0x86612156 single_release +EXPORT_SYMBOL vmlinux 0x8664f62e cpufreq_update_policy +EXPORT_SYMBOL vmlinux 0x86713cd3 keyring_clear +EXPORT_SYMBOL vmlinux 0x8687e33e tcf_hash_create +EXPORT_SYMBOL vmlinux 0x868acba5 get_options +EXPORT_SYMBOL vmlinux 0x86a2ec10 blk_alloc_queue +EXPORT_SYMBOL vmlinux 0x86b1941b get_user_pages +EXPORT_SYMBOL vmlinux 0x86d8d8da audit_log_start +EXPORT_SYMBOL vmlinux 0x86fb9b05 bitmap_parse_user +EXPORT_SYMBOL vmlinux 0x87248639 destroy_EII_client +EXPORT_SYMBOL vmlinux 0x8727c879 genl_register_ops +EXPORT_SYMBOL vmlinux 0x8733e9a3 sleep_on_timeout +EXPORT_SYMBOL vmlinux 0x876dafc3 ec_write +EXPORT_SYMBOL vmlinux 0x8785725d param_set_charp +EXPORT_SYMBOL vmlinux 0x878615a0 swiotlb_map_sg +EXPORT_SYMBOL vmlinux 0x87888a99 locks_copy_lock +EXPORT_SYMBOL vmlinux 0x878ab3ce sysctl_tcp_adv_win_scale +EXPORT_SYMBOL vmlinux 0x8794e0ce __devm_release_region +EXPORT_SYMBOL vmlinux 0x87a750ac generic_block_bmap +EXPORT_SYMBOL vmlinux 0x87e05f3d sock_get_timestampns +EXPORT_SYMBOL vmlinux 0x87f0b4bd agp_generic_alloc_user +EXPORT_SYMBOL vmlinux 0x881039d0 zlib_inflate +EXPORT_SYMBOL vmlinux 0x881156d3 vfs_llseek +EXPORT_SYMBOL vmlinux 0x8850fd31 devm_ioremap_nocache +EXPORT_SYMBOL vmlinux 0x886ea253 swiotlb_alloc_coherent +EXPORT_SYMBOL vmlinux 0x88cbf4b6 nf_unregister_sockopt +EXPORT_SYMBOL vmlinux 0x8900fde6 wait_on_page_bit +EXPORT_SYMBOL vmlinux 0x89086584 sk_stream_write_space +EXPORT_SYMBOL vmlinux 0x892b26a0 set_memory_nx +EXPORT_SYMBOL vmlinux 0x894350bd tcp_v4_remember_stamp +EXPORT_SYMBOL vmlinux 0x894f1de9 ethtool_op_get_ufo +EXPORT_SYMBOL vmlinux 0x89503fd9 tcp_init_xmit_timers +EXPORT_SYMBOL vmlinux 0x8953bb27 del_timer +EXPORT_SYMBOL vmlinux 0x895469d3 pci_get_device +EXPORT_SYMBOL vmlinux 0x897473df mktime +EXPORT_SYMBOL vmlinux 0x898a713e tcf_exts_dump_stats +EXPORT_SYMBOL vmlinux 0x898b1fec mutex_trylock +EXPORT_SYMBOL vmlinux 0x89949018 down_timeout +EXPORT_SYMBOL vmlinux 0x89b232d1 sock_no_listen +EXPORT_SYMBOL vmlinux 0x89d5538d fb_pad_aligned_buffer +EXPORT_SYMBOL vmlinux 0x89d66811 build_ehash_secret +EXPORT_SYMBOL vmlinux 0x89e3ca41 kthread_stop +EXPORT_SYMBOL vmlinux 0x89ea052d vlan_ioctl_set +EXPORT_SYMBOL vmlinux 0x8a1a818f dev_get_by_index +EXPORT_SYMBOL vmlinux 0x8a3eabf0 __wait_on_bit +EXPORT_SYMBOL vmlinux 0x8a7d1c31 high_memory +EXPORT_SYMBOL vmlinux 0x8a90c927 bdi_unregister +EXPORT_SYMBOL vmlinux 0x8a90d932 allocate_resource +EXPORT_SYMBOL vmlinux 0x8a98232b vfs_path_lookup +EXPORT_SYMBOL vmlinux 0x8a99a016 mempool_free_slab +EXPORT_SYMBOL vmlinux 0x8aaf8654 mutex_lock +EXPORT_SYMBOL vmlinux 0x8ac40297 iommu_area_free +EXPORT_SYMBOL vmlinux 0x8af47b77 touch_atime +EXPORT_SYMBOL vmlinux 0x8b2ce3bb filemap_fdatawrite_range +EXPORT_SYMBOL vmlinux 0x8b2f862e sock_no_connect +EXPORT_SYMBOL vmlinux 0x8b35c568 atm_dev_register +EXPORT_SYMBOL vmlinux 0x8b35e873 sg_last +EXPORT_SYMBOL vmlinux 0x8b3ca835 cpu_present_map +EXPORT_SYMBOL vmlinux 0x8b50bd1c udp_memory_allocated +EXPORT_SYMBOL vmlinux 0x8b618d08 overflowuid +EXPORT_SYMBOL vmlinux 0x8b66bdbc uart_register_driver +EXPORT_SYMBOL vmlinux 0x8b7fe311 kmemdup +EXPORT_SYMBOL vmlinux 0x8b922c0f __strnlen_user +EXPORT_SYMBOL vmlinux 0x8b966b63 sn_rtc_cycles_per_second +EXPORT_SYMBOL vmlinux 0x8b96acd3 generic_file_open +EXPORT_SYMBOL vmlinux 0x8b989cf9 acpi_bus_can_wakeup +EXPORT_SYMBOL vmlinux 0x8bb2f3c8 ethtool_op_set_tx_hw_csum +EXPORT_SYMBOL vmlinux 0x8bb33e7d __release_region +EXPORT_SYMBOL vmlinux 0x8bfa0ced atm_init_aal5 +EXPORT_SYMBOL vmlinux 0x8c183cbe iowrite16 +EXPORT_SYMBOL vmlinux 0x8c5393c4 vfs_rename +EXPORT_SYMBOL vmlinux 0x8c5986da simple_release_fs +EXPORT_SYMBOL vmlinux 0x8c98f1c1 generic_cont_expand_simple +EXPORT_SYMBOL vmlinux 0x8cab4c47 bio_uncopy_user +EXPORT_SYMBOL vmlinux 0x8cb3fec3 nobh_write_begin +EXPORT_SYMBOL vmlinux 0x8cc79cab iowrite16_rep +EXPORT_SYMBOL vmlinux 0x8d3894f2 _ctype +EXPORT_SYMBOL vmlinux 0x8d4ab2f6 send_sig +EXPORT_SYMBOL vmlinux 0x8d551bef sysctl_tcp_rmem +EXPORT_SYMBOL vmlinux 0x8d6ac59e inet_stream_ops +EXPORT_SYMBOL vmlinux 0x8d7c30bf tcp_sendpage +EXPORT_SYMBOL vmlinux 0x8d8d96c6 acpi_get_sleep_type_data +EXPORT_SYMBOL vmlinux 0x8d8e7a97 tcp_ioctl +EXPORT_SYMBOL vmlinux 0x8db0c353 notify_change +EXPORT_SYMBOL vmlinux 0x8e002cda acpi_remove_gpe_block +EXPORT_SYMBOL vmlinux 0x8e0637ba i8253_lock +EXPORT_SYMBOL vmlinux 0x8e0b7743 ipv6_ext_hdr +EXPORT_SYMBOL vmlinux 0x8e3c9cc3 vprintk +EXPORT_SYMBOL vmlinux 0x8e449875 nla_append +EXPORT_SYMBOL vmlinux 0x8e63e42a ipv6_skip_exthdr +EXPORT_SYMBOL vmlinux 0x8e725985 nf_log_unregister_pf +EXPORT_SYMBOL vmlinux 0x8e930f4f unregister_tcf_proto_ops +EXPORT_SYMBOL vmlinux 0x8e98b8c5 __neigh_for_each_release +EXPORT_SYMBOL vmlinux 0x8e9f3161 uart_unregister_driver +EXPORT_SYMBOL vmlinux 0x8ee61ef0 cpufreq_gov_performance +EXPORT_SYMBOL vmlinux 0x8eef4aea should_remove_suid +EXPORT_SYMBOL vmlinux 0x8f031c95 xfrm_policy_alloc +EXPORT_SYMBOL vmlinux 0x8f1a10a4 __skb_checksum_complete_head +EXPORT_SYMBOL vmlinux 0x8f2b7e66 inet_sk_rebuild_header +EXPORT_SYMBOL vmlinux 0x8f39f14b dmam_free_noncoherent +EXPORT_SYMBOL vmlinux 0x8f400c5c kernel_sock_shutdown +EXPORT_SYMBOL vmlinux 0x8f6b7950 set_irq_data +EXPORT_SYMBOL vmlinux 0x8f6e7cd2 get_sb_nodev +EXPORT_SYMBOL vmlinux 0x8f7b895b make_bad_inode +EXPORT_SYMBOL vmlinux 0x8f84448d iget_locked +EXPORT_SYMBOL vmlinux 0x8f9c199c __get_user_2 +EXPORT_SYMBOL vmlinux 0x8fa0ed99 default_unplug_io_fn +EXPORT_SYMBOL vmlinux 0x90022b44 xfrm_policy_flush +EXPORT_SYMBOL vmlinux 0x90035333 secure_tcpv6_sequence_number +EXPORT_SYMBOL vmlinux 0x9015b5e0 generic_permission +EXPORT_SYMBOL vmlinux 0x90233375 input_release_device +EXPORT_SYMBOL vmlinux 0x9054927a input_register_device +EXPORT_SYMBOL vmlinux 0x9068a4d9 tcp_recvmsg +EXPORT_SYMBOL vmlinux 0x9070b3f2 ioport_resource +EXPORT_SYMBOL vmlinux 0x90a943ba nmi_active +EXPORT_SYMBOL vmlinux 0x90aa4adc unlock_page +EXPORT_SYMBOL vmlinux 0x90c96746 serio_rescan +EXPORT_SYMBOL vmlinux 0x90f2000c dev_get_by_name +EXPORT_SYMBOL vmlinux 0x9144a8e2 ec_burst_disable +EXPORT_SYMBOL vmlinux 0x91481982 __ratelimit +EXPORT_SYMBOL vmlinux 0x91607d95 set_memory_wb +EXPORT_SYMBOL vmlinux 0x917d3f3c sk_stream_wait_close +EXPORT_SYMBOL vmlinux 0x91a74ec3 registered_fb +EXPORT_SYMBOL vmlinux 0x91ca8959 acpi_get_register +EXPORT_SYMBOL vmlinux 0x91e03d25 filemap_write_and_wait +EXPORT_SYMBOL vmlinux 0x9211f26c tcf_em_tree_destroy +EXPORT_SYMBOL vmlinux 0x9212a1d7 pcix_get_max_mmrbc +EXPORT_SYMBOL vmlinux 0x92392cd9 iov_shorten +EXPORT_SYMBOL vmlinux 0x9252c8eb lock_sock_nested +EXPORT_SYMBOL vmlinux 0x92599728 dma_async_tx_descriptor_init +EXPORT_SYMBOL vmlinux 0x926cdff3 pci_enable_msix +EXPORT_SYMBOL vmlinux 0x927cf8df deny_write_access +EXPORT_SYMBOL vmlinux 0x927e989f gen_pool_alloc +EXPORT_SYMBOL vmlinux 0x92924f53 bio_integrity_alloc +EXPORT_SYMBOL vmlinux 0x92a1fee1 file_update_time +EXPORT_SYMBOL vmlinux 0x92cda47e skb_store_bits +EXPORT_SYMBOL vmlinux 0x92ea4ae4 crc32_le +EXPORT_SYMBOL vmlinux 0x92fe4055 pci_release_selected_regions +EXPORT_SYMBOL vmlinux 0x9305f8e6 cpufreq_get +EXPORT_SYMBOL vmlinux 0x931bba5a sock_kmalloc +EXPORT_SYMBOL vmlinux 0x93400cf1 input_set_keycode +EXPORT_SYMBOL vmlinux 0x936195d9 dev_add_pack +EXPORT_SYMBOL vmlinux 0x93a6e0b2 io_schedule +EXPORT_SYMBOL vmlinux 0x93afa72e vm_get_page_prot +EXPORT_SYMBOL vmlinux 0x93b8ef56 mutex_lock_interruptible +EXPORT_SYMBOL vmlinux 0x93bdc1cf dquot_transfer +EXPORT_SYMBOL vmlinux 0x93c69acf param_set_byte +EXPORT_SYMBOL vmlinux 0x93cbd1ec _spin_lock_bh +EXPORT_SYMBOL vmlinux 0x93ecfd0e tty_devnum +EXPORT_SYMBOL vmlinux 0x93fca811 __get_free_pages +EXPORT_SYMBOL vmlinux 0x93fdb82a init_file +EXPORT_SYMBOL vmlinux 0x93fff787 seq_release +EXPORT_SYMBOL vmlinux 0x940875ad tcp_v4_destroy_sock +EXPORT_SYMBOL vmlinux 0x940ec91b textsearch_register +EXPORT_SYMBOL vmlinux 0x943e868f ida_get_new +EXPORT_SYMBOL vmlinux 0x94439ad9 seq_read +EXPORT_SYMBOL vmlinux 0x94444edf tty_vhangup +EXPORT_SYMBOL vmlinux 0x944a5ea2 xfrm_prepare_input +EXPORT_SYMBOL vmlinux 0x945bc6a7 copy_from_user +EXPORT_SYMBOL vmlinux 0x945e5e54 d_alloc +EXPORT_SYMBOL vmlinux 0x9470a550 grab_cache_page_write_begin +EXPORT_SYMBOL vmlinux 0x94883ab2 gnet_stats_copy_rate_est +EXPORT_SYMBOL vmlinux 0x9492c2d3 agp_backend_release +EXPORT_SYMBOL vmlinux 0x94961283 vunmap +EXPORT_SYMBOL vmlinux 0x949fd41d __module_put_and_exit +EXPORT_SYMBOL vmlinux 0x94bd1d0c proc_dointvec_userhz_jiffies +EXPORT_SYMBOL vmlinux 0x94fcf08e bioset_create +EXPORT_SYMBOL vmlinux 0x95158526 ip_generic_getfrag +EXPORT_SYMBOL vmlinux 0x954488a4 syncookie_secret +EXPORT_SYMBOL vmlinux 0x9545af6d tasklet_init +EXPORT_SYMBOL vmlinux 0x954cbb26 vsprintf +EXPORT_SYMBOL vmlinux 0x95866011 do_SAK +EXPORT_SYMBOL vmlinux 0x95999216 tcp_shutdown +EXPORT_SYMBOL vmlinux 0x95a50df0 arp_send +EXPORT_SYMBOL vmlinux 0x95a568c1 freeze_bdev +EXPORT_SYMBOL vmlinux 0x95adf643 compat_nf_setsockopt +EXPORT_SYMBOL vmlinux 0x95ceb864 key_update +EXPORT_SYMBOL vmlinux 0x95dd999a gnet_stats_finish_copy +EXPORT_SYMBOL vmlinux 0x961c3a15 generic_file_readonly_mmap +EXPORT_SYMBOL vmlinux 0x962be501 redraw_screen +EXPORT_SYMBOL vmlinux 0x963bb6a1 pci_set_master +EXPORT_SYMBOL vmlinux 0x96481cc7 per_cpu__x86_cpu_to_apicid +EXPORT_SYMBOL vmlinux 0x965824c8 kmem_cache_name +EXPORT_SYMBOL vmlinux 0x96629d98 pci_get_bus_and_slot +EXPORT_SYMBOL vmlinux 0x9696d326 unregister_nls +EXPORT_SYMBOL vmlinux 0x96baac45 blk_register_region +EXPORT_SYMBOL vmlinux 0x96c7d23a wireless_send_event +EXPORT_SYMBOL vmlinux 0x96f33400 up_read +EXPORT_SYMBOL vmlinux 0x96fa4082 test_set_page_writeback +EXPORT_SYMBOL vmlinux 0x9703d98d blk_rq_append_bio +EXPORT_SYMBOL vmlinux 0x972d9a4d page_symlink +EXPORT_SYMBOL vmlinux 0x973873ab _spin_lock +EXPORT_SYMBOL vmlinux 0x974921ac agp_unbind_memory +EXPORT_SYMBOL vmlinux 0x9754ec10 radix_tree_preload +EXPORT_SYMBOL vmlinux 0x9788fb3f __dec_zone_page_state +EXPORT_SYMBOL vmlinux 0x97dc5dd3 neigh_changeaddr +EXPORT_SYMBOL vmlinux 0x97de0ddd acpi_install_gpe_block +EXPORT_SYMBOL vmlinux 0x9817d2ce xfrm_unregister_mode +EXPORT_SYMBOL vmlinux 0x981c5cbf sock_init_data +EXPORT_SYMBOL vmlinux 0x981e9721 security_sb_set_mnt_opts +EXPORT_SYMBOL vmlinux 0x984703c0 init_buffer +EXPORT_SYMBOL vmlinux 0x9865f54a cdev_del +EXPORT_SYMBOL vmlinux 0x986e6135 fb_pad_unaligned_buffer +EXPORT_SYMBOL vmlinux 0x988ed85d set_memory_x +EXPORT_SYMBOL vmlinux 0x98cb881e acpi_bus_get_device +EXPORT_SYMBOL vmlinux 0x990e54e4 unregister_filesystem +EXPORT_SYMBOL vmlinux 0x9994c0ca ps2_is_keyboard_id +EXPORT_SYMBOL vmlinux 0x999e8297 vfree +EXPORT_SYMBOL vmlinux 0x99aadb21 param_get_ulong +EXPORT_SYMBOL vmlinux 0x99bfbe39 get_unused_fd +EXPORT_SYMBOL vmlinux 0x99cdc86b sysctl_tcp_reordering +EXPORT_SYMBOL vmlinux 0x99ea12ce panic_blink +EXPORT_SYMBOL vmlinux 0x9a035c27 __napi_schedule +EXPORT_SYMBOL vmlinux 0x9a11afb1 dev_unicast_unsync +EXPORT_SYMBOL vmlinux 0x9a1dfd65 strpbrk +EXPORT_SYMBOL vmlinux 0x9a295b9b struct_module +EXPORT_SYMBOL vmlinux 0x9a58e3c2 pci_set_mwi +EXPORT_SYMBOL vmlinux 0x9a59a7cb bio_integrity_add_page +EXPORT_SYMBOL vmlinux 0x9a9985be percpu_counter_destroy +EXPORT_SYMBOL vmlinux 0x9ac30f38 blk_free_tags +EXPORT_SYMBOL vmlinux 0x9ad46346 sysctl_intvec +EXPORT_SYMBOL vmlinux 0x9af9829d vfs_symlink +EXPORT_SYMBOL vmlinux 0x9b025751 sk_run_filter +EXPORT_SYMBOL vmlinux 0x9b388444 get_zeroed_page +EXPORT_SYMBOL vmlinux 0x9b6408d6 gnet_stats_start_copy +EXPORT_SYMBOL vmlinux 0x9b877ffb netlink_kernel_create +EXPORT_SYMBOL vmlinux 0x9ba5dd6f generic_make_request +EXPORT_SYMBOL vmlinux 0x9ba7089d argv_split +EXPORT_SYMBOL vmlinux 0x9bbf70c7 ip_dev_find +EXPORT_SYMBOL vmlinux 0x9bc565c5 memcpy_fromiovecend +EXPORT_SYMBOL vmlinux 0x9bd7c1b6 follow_down +EXPORT_SYMBOL vmlinux 0x9be559a9 bio_integrity_clone +EXPORT_SYMBOL vmlinux 0x9c012508 fb_parse_edid +EXPORT_SYMBOL vmlinux 0x9c0ea3cd memscan +EXPORT_SYMBOL vmlinux 0x9c1bd24b blk_queue_max_segment_size +EXPORT_SYMBOL vmlinux 0x9c35f9b3 rtnl_notify +EXPORT_SYMBOL vmlinux 0x9c491f60 sg_alloc_table +EXPORT_SYMBOL vmlinux 0x9c4c5735 atm_dev_deregister +EXPORT_SYMBOL vmlinux 0x9c4df108 tcf_destroy_chain +EXPORT_SYMBOL vmlinux 0x9c7c1320 km_state_notify +EXPORT_SYMBOL vmlinux 0x9c8027bf __xfrm_decode_session +EXPORT_SYMBOL vmlinux 0x9c8e2966 mem_section +EXPORT_SYMBOL vmlinux 0x9c9dc702 km_state_expired +EXPORT_SYMBOL vmlinux 0x9ca95a0e sort +EXPORT_SYMBOL vmlinux 0x9cb96e92 qdisc_put_rtab +EXPORT_SYMBOL vmlinux 0x9cbbf787 kernel_sendpage +EXPORT_SYMBOL vmlinux 0x9ccb2622 finish_wait +EXPORT_SYMBOL vmlinux 0x9cd0e060 kfree_skb +EXPORT_SYMBOL vmlinux 0x9ceba535 dquot_free_inode +EXPORT_SYMBOL vmlinux 0x9ced38aa down_trylock +EXPORT_SYMBOL vmlinux 0x9d2441e5 sock_no_sendpage +EXPORT_SYMBOL vmlinux 0x9d33ef5e acpi_enable +EXPORT_SYMBOL vmlinux 0x9d3e75c1 sync_blockdev +EXPORT_SYMBOL vmlinux 0x9d4f5ac4 buffer_migrate_page +EXPORT_SYMBOL vmlinux 0x9d663c64 invalidate_inodes +EXPORT_SYMBOL vmlinux 0x9d711f1f percpu_counter_init +EXPORT_SYMBOL vmlinux 0x9d98f450 _cpu_pda +EXPORT_SYMBOL vmlinux 0x9da5612d uart_get_divisor +EXPORT_SYMBOL vmlinux 0x9db21624 hex_dump_to_buffer +EXPORT_SYMBOL vmlinux 0x9dd4d218 inet_register_protosw +EXPORT_SYMBOL vmlinux 0x9e00de31 tcp_v4_md5_lookup +EXPORT_SYMBOL vmlinux 0x9e05d1cc dev_remove_pack +EXPORT_SYMBOL vmlinux 0x9e0e3bf0 netif_rx_ni +EXPORT_SYMBOL vmlinux 0x9e2ffd96 dev_unicast_sync +EXPORT_SYMBOL vmlinux 0x9e535888 acpi_get_physical_device +EXPORT_SYMBOL vmlinux 0x9e64fbfe rtc_cmos_read +EXPORT_SYMBOL vmlinux 0x9e7d6bd0 __udelay +EXPORT_SYMBOL vmlinux 0x9ea0ad49 __sg_free_table +EXPORT_SYMBOL vmlinux 0x9ea23fad tcf_register_action +EXPORT_SYMBOL vmlinux 0x9ea28ec7 acpi_evaluate_object +EXPORT_SYMBOL vmlinux 0x9edbecae snprintf +EXPORT_SYMBOL vmlinux 0x9ee56ef6 tcp_simple_retransmit +EXPORT_SYMBOL vmlinux 0x9eecde16 do_brk +EXPORT_SYMBOL vmlinux 0x9ef749e2 unregister_chrdev +EXPORT_SYMBOL vmlinux 0x9f0e3bd3 eth_header +EXPORT_SYMBOL vmlinux 0x9f100139 jiffies_to_clock_t +EXPORT_SYMBOL vmlinux 0x9f17ad5f iw_handler_set_spy +EXPORT_SYMBOL vmlinux 0x9f26f470 generic_file_splice_write +EXPORT_SYMBOL vmlinux 0x9f2bdaac __bitmap_or +EXPORT_SYMBOL vmlinux 0x9f330c2f set_page_dirty +EXPORT_SYMBOL vmlinux 0x9f6b6587 inet_frags_exit_net +EXPORT_SYMBOL vmlinux 0x9f984513 strrchr +EXPORT_SYMBOL vmlinux 0x9fa274b4 dq_data_lock +EXPORT_SYMBOL vmlinux 0x9fa72993 skb_split +EXPORT_SYMBOL vmlinux 0x9fbbd002 __xfrm_route_forward +EXPORT_SYMBOL vmlinux 0x9feaf287 sonet_subtract_stats +EXPORT_SYMBOL vmlinux 0xa0243b4b neigh_resolve_output +EXPORT_SYMBOL vmlinux 0xa03523d5 security_unix_stream_connect +EXPORT_SYMBOL vmlinux 0xa04a01bd qdisc_class_hash_insert +EXPORT_SYMBOL vmlinux 0xa05c03df mempool_kmalloc +EXPORT_SYMBOL vmlinux 0xa0965fe2 unload_nls +EXPORT_SYMBOL vmlinux 0xa0b04675 vmalloc_32 +EXPORT_SYMBOL vmlinux 0xa0b685f0 save_mount_options +EXPORT_SYMBOL vmlinux 0xa0ceef51 out_of_line_wait_on_bit +EXPORT_SYMBOL vmlinux 0xa0fbac79 wake_up_bit +EXPORT_SYMBOL vmlinux 0xa108eb4d sysctl_optmem_max +EXPORT_SYMBOL vmlinux 0xa116268a tcf_exts_change +EXPORT_SYMBOL vmlinux 0xa120d33c tty_unregister_ldisc +EXPORT_SYMBOL vmlinux 0xa13366d2 generic_removexattr +EXPORT_SYMBOL vmlinux 0xa13798f8 printk_ratelimit +EXPORT_SYMBOL vmlinux 0xa13bd4ec __pskb_pull_tail +EXPORT_SYMBOL vmlinux 0xa15da336 filemap_fdatawait +EXPORT_SYMBOL vmlinux 0xa1a5bb0a km_query +EXPORT_SYMBOL vmlinux 0xa1b02665 dev_close +EXPORT_SYMBOL vmlinux 0xa1b759ce fb_add_videomode +EXPORT_SYMBOL vmlinux 0xa1c76e0a _cond_resched +EXPORT_SYMBOL vmlinux 0xa1c8761a input_set_capability +EXPORT_SYMBOL vmlinux 0xa1d5521d netpoll_poll +EXPORT_SYMBOL vmlinux 0xa20433ba inode_change_ok +EXPORT_SYMBOL vmlinux 0xa20ce1b8 net_msg_warn +EXPORT_SYMBOL vmlinux 0xa235943d vfs_link +EXPORT_SYMBOL vmlinux 0xa23ede36 check_disk_change +EXPORT_SYMBOL vmlinux 0xa2473147 xfrm_policy_unregister_afinfo +EXPORT_SYMBOL vmlinux 0xa27716ea request_firmware_nowait +EXPORT_SYMBOL vmlinux 0xa2a1e5c9 _write_lock_bh +EXPORT_SYMBOL vmlinux 0xa2a5fd77 inet_ehash_secret +EXPORT_SYMBOL vmlinux 0xa2a85e8e uart_update_timeout +EXPORT_SYMBOL vmlinux 0xa30e8206 qdisc_tree_decrease_qlen +EXPORT_SYMBOL vmlinux 0xa315bc7c call_usermodehelper_setkeys +EXPORT_SYMBOL vmlinux 0xa31f172d __copy_from_user_inatomic +EXPORT_SYMBOL vmlinux 0xa325e2fc no_llseek +EXPORT_SYMBOL vmlinux 0xa329f07e register_shrinker +EXPORT_SYMBOL vmlinux 0xa33f7c7c nla_strlcpy +EXPORT_SYMBOL vmlinux 0xa3420d61 __percpu_counter_sum +EXPORT_SYMBOL vmlinux 0xa34b076d tcf_action_dump_1 +EXPORT_SYMBOL vmlinux 0xa355a9b0 sock_no_shutdown +EXPORT_SYMBOL vmlinux 0xa35de80f ipv4_config +EXPORT_SYMBOL vmlinux 0xa3a5be95 memmove +EXPORT_SYMBOL vmlinux 0xa3a9aac6 dma_pool_destroy +EXPORT_SYMBOL vmlinux 0xa3bbcd80 acpi_set_gpe_type +EXPORT_SYMBOL vmlinux 0xa3c7a0b2 dcache_readdir +EXPORT_SYMBOL vmlinux 0xa3ca3814 seq_path +EXPORT_SYMBOL vmlinux 0xa3cc3268 blk_rq_map_user +EXPORT_SYMBOL vmlinux 0xa4155a53 nf_log_packet +EXPORT_SYMBOL vmlinux 0xa44072fc posix_acl_alloc +EXPORT_SYMBOL vmlinux 0xa44ad274 wait_for_completion_interruptible_timeout +EXPORT_SYMBOL vmlinux 0xa4501cd1 pnp_request_card_device +EXPORT_SYMBOL vmlinux 0xa49d2078 register_8022_client +EXPORT_SYMBOL vmlinux 0xa4b94fea iowrite8_rep +EXPORT_SYMBOL vmlinux 0xa4d4f0e6 global_cache_flush +EXPORT_SYMBOL vmlinux 0xa4df1151 kref_set +EXPORT_SYMBOL vmlinux 0xa4e41f0e acpi_root_dir +EXPORT_SYMBOL vmlinux 0xa51dd867 proc_dointvec_jiffies +EXPORT_SYMBOL vmlinux 0xa51e6c5f __netif_schedule +EXPORT_SYMBOL vmlinux 0xa53f9c7d xfrm4_prepare_output +EXPORT_SYMBOL vmlinux 0xa5423cc4 param_get_int +EXPORT_SYMBOL vmlinux 0xa5693df7 posix_acl_clone +EXPORT_SYMBOL vmlinux 0xa56f1315 mempool_free +EXPORT_SYMBOL vmlinux 0xa573763b kernel_read +EXPORT_SYMBOL vmlinux 0xa58b6804 nla_parse +EXPORT_SYMBOL vmlinux 0xa5922bb1 kfifo_init +EXPORT_SYMBOL vmlinux 0xa598e29c vesa_modes +EXPORT_SYMBOL vmlinux 0xa59affdc vfs_follow_link +EXPORT_SYMBOL vmlinux 0xa5adbe8c ida_destroy +EXPORT_SYMBOL vmlinux 0xa5ff222d mod_zone_page_state +EXPORT_SYMBOL vmlinux 0xa61bc856 inet_csk_clear_xmit_timers +EXPORT_SYMBOL vmlinux 0xa6205220 qdisc_watchdog_cancel +EXPORT_SYMBOL vmlinux 0xa6244c96 sk_alloc +EXPORT_SYMBOL vmlinux 0xa631435f tcp_rcv_established +EXPORT_SYMBOL vmlinux 0xa6462410 filemap_fdatawrite +EXPORT_SYMBOL vmlinux 0xa68124fa hweight8 +EXPORT_SYMBOL vmlinux 0xa681fe88 generate_random_uuid +EXPORT_SYMBOL vmlinux 0xa6b3b2a0 agp_generic_enable +EXPORT_SYMBOL vmlinux 0xa6dcc773 rb_insert_color +EXPORT_SYMBOL vmlinux 0xa703ecba generic_getxattr +EXPORT_SYMBOL vmlinux 0xa70fabbe release_evntsel_nmi +EXPORT_SYMBOL vmlinux 0xa729d6ad vcc_insert_socket +EXPORT_SYMBOL vmlinux 0xa7502f48 jiffies_to_timeval +EXPORT_SYMBOL vmlinux 0xa7816c27 bio_integrity_advance +EXPORT_SYMBOL vmlinux 0xa7924958 sk_stream_wait_memory +EXPORT_SYMBOL vmlinux 0xa7931d07 __ip_select_ident +EXPORT_SYMBOL vmlinux 0xa7c35c6b getnstimeofday +EXPORT_SYMBOL vmlinux 0xa7db6bc9 proc_dointvec +EXPORT_SYMBOL vmlinux 0xa80e59ae get_sb_bdev +EXPORT_SYMBOL vmlinux 0xa816c525 schedule_work_on +EXPORT_SYMBOL vmlinux 0xa822dae7 down_read +EXPORT_SYMBOL vmlinux 0xa8388473 d_lookup +EXPORT_SYMBOL vmlinux 0xa84da066 proc_doulongvec_minmax +EXPORT_SYMBOL vmlinux 0xa862e721 sk_wait_data +EXPORT_SYMBOL vmlinux 0xa86518a2 register_gifconf +EXPORT_SYMBOL vmlinux 0xa8655691 single_open +EXPORT_SYMBOL vmlinux 0xa867aa49 pagecache_write_begin +EXPORT_SYMBOL vmlinux 0xa86e3159 blk_queue_dma_pad +EXPORT_SYMBOL vmlinux 0xa87df9c7 skb_trim +EXPORT_SYMBOL vmlinux 0xa886a958 krealloc +EXPORT_SYMBOL vmlinux 0xa89fd057 blk_queue_update_dma_pad +EXPORT_SYMBOL vmlinux 0xa8b29083 linkwatch_fire_event +EXPORT_SYMBOL vmlinux 0xa8b57857 bio_integrity_get_tag +EXPORT_SYMBOL vmlinux 0xa8d3f4ea blk_rq_count_integrity_sg +EXPORT_SYMBOL vmlinux 0xa8eca3c1 vm_insert_page +EXPORT_SYMBOL vmlinux 0xa8f102af thermal_cooling_device_register +EXPORT_SYMBOL vmlinux 0xa8f30a16 fb_firmware_edid +EXPORT_SYMBOL vmlinux 0xa8fbf582 idr_replace +EXPORT_SYMBOL vmlinux 0xa8fef7bb security_unix_may_send +EXPORT_SYMBOL vmlinux 0xa916446b blk_stop_queue +EXPORT_SYMBOL vmlinux 0xa91726f5 pci_bus_alloc_resource +EXPORT_SYMBOL vmlinux 0xa91b5561 acpi_video_backlight_support +EXPORT_SYMBOL vmlinux 0xa925899a param_set_bool +EXPORT_SYMBOL vmlinux 0xa934eef1 remove_inode_hash +EXPORT_SYMBOL vmlinux 0xa937079d agp_free_page_array +EXPORT_SYMBOL vmlinux 0xa956b37e tcp_v4_connect +EXPORT_SYMBOL vmlinux 0xa9724f50 __skb_warn_lro_forwarding +EXPORT_SYMBOL vmlinux 0xa9be76e8 clocksource_register +EXPORT_SYMBOL vmlinux 0xa9e22b8d kmem_cache_alloc +EXPORT_SYMBOL vmlinux 0xa9e350bf request_firmware +EXPORT_SYMBOL vmlinux 0xa9fcf31d wait_for_completion_interruptible +EXPORT_SYMBOL vmlinux 0xaa024146 sonet_copy_stats +EXPORT_SYMBOL vmlinux 0xaa84a8ae acpi_processor_power_init_bm_check +EXPORT_SYMBOL vmlinux 0xaa8856bc bio_copy_user +EXPORT_SYMBOL vmlinux 0xaab06af8 _write_lock_irqsave +EXPORT_SYMBOL vmlinux 0xaae8ab0e acpi_bus_power_manageable +EXPORT_SYMBOL vmlinux 0xaaf61973 mpage_bio_submit +EXPORT_SYMBOL vmlinux 0xaafdc258 strcasecmp +EXPORT_SYMBOL vmlinux 0xaaffb9a5 acpi_bus_private_data_handler +EXPORT_SYMBOL vmlinux 0xab1737ae pci_bus_write_config_word +EXPORT_SYMBOL vmlinux 0xab471003 param_array_set +EXPORT_SYMBOL vmlinux 0xab565120 devm_ioport_map +EXPORT_SYMBOL vmlinux 0xab600421 probe_irq_off +EXPORT_SYMBOL vmlinux 0xab65ed80 set_memory_uc +EXPORT_SYMBOL vmlinux 0xab79bd21 nla_reserve +EXPORT_SYMBOL vmlinux 0xaba714af hippi_type_trans +EXPORT_SYMBOL vmlinux 0xabaa4b55 may_umount_tree +EXPORT_SYMBOL vmlinux 0xabd0c91c rtc_time_to_tm +EXPORT_SYMBOL vmlinux 0xabe85a21 idr_init +EXPORT_SYMBOL vmlinux 0xabeba1f0 security_task_getsecid +EXPORT_SYMBOL vmlinux 0xabebe3f1 truncate_inode_pages +EXPORT_SYMBOL vmlinux 0xabfbb4cf __elv_add_request +EXPORT_SYMBOL vmlinux 0xac0bbfa8 _proxy_pda +EXPORT_SYMBOL vmlinux 0xac0e5edd xfrm_state_walk +EXPORT_SYMBOL vmlinux 0xac338e1f thermal_zone_device_register +EXPORT_SYMBOL vmlinux 0xac383451 radix_tree_tag_clear +EXPORT_SYMBOL vmlinux 0xac3b3cee __bitmap_and +EXPORT_SYMBOL vmlinux 0xac5709f7 per_cpu__x86_cpu_to_node_map +EXPORT_SYMBOL vmlinux 0xac58ea5e acpi_unload_table_id +EXPORT_SYMBOL vmlinux 0xac7d6645 __locks_copy_lock +EXPORT_SYMBOL vmlinux 0xac815040 netif_carrier_off +EXPORT_SYMBOL vmlinux 0xac9695ff tc_classify_compat +EXPORT_SYMBOL vmlinux 0xacafd225 kernel_getsockopt +EXPORT_SYMBOL vmlinux 0xacc34c1f acpi_get_physical_pci_device +EXPORT_SYMBOL vmlinux 0xaccabc6a in4_pton +EXPORT_SYMBOL vmlinux 0xacd14477 kthread_create +EXPORT_SYMBOL vmlinux 0xace1e672 tc_classify +EXPORT_SYMBOL vmlinux 0xace78505 tcp_md5_hash_header +EXPORT_SYMBOL vmlinux 0xacf4d843 match_strdup +EXPORT_SYMBOL vmlinux 0xacf527d2 vfs_write +EXPORT_SYMBOL vmlinux 0xacf544f2 atm_charge +EXPORT_SYMBOL vmlinux 0xacfaed0d __vlan_hwaccel_rx +EXPORT_SYMBOL vmlinux 0xad0413d4 match_hex +EXPORT_SYMBOL vmlinux 0xad07fcc5 __first_cpu +EXPORT_SYMBOL vmlinux 0xad13c689 acpi_os_execute +EXPORT_SYMBOL vmlinux 0xad25fb12 __memcpy +EXPORT_SYMBOL vmlinux 0xad445bcf inet_add_protocol +EXPORT_SYMBOL vmlinux 0xad8de1b3 acpi_remove_address_space_handler +EXPORT_SYMBOL vmlinux 0xad90a0ff compat_sock_common_setsockopt +EXPORT_SYMBOL vmlinux 0xada5eeae tty_driver_flush_buffer +EXPORT_SYMBOL vmlinux 0xadaa2657 cpufreq_register_notifier +EXPORT_SYMBOL vmlinux 0xadf83898 xfrm_register_type +EXPORT_SYMBOL vmlinux 0xadffd6f8 generic_file_aio_write +EXPORT_SYMBOL vmlinux 0xae060059 __inode_dir_notify +EXPORT_SYMBOL vmlinux 0xae07f306 unregister_sysctl_table +EXPORT_SYMBOL vmlinux 0xae1548b4 swiotlb_unmap_sg +EXPORT_SYMBOL vmlinux 0xae207c01 skb_clone +EXPORT_SYMBOL vmlinux 0xae5f915c nf_afinfo +EXPORT_SYMBOL vmlinux 0xaef7237f task_pid_nr_ns +EXPORT_SYMBOL vmlinux 0xaf089f66 ps2_drain +EXPORT_SYMBOL vmlinux 0xaf50d12d task_pgrp_nr_ns +EXPORT_SYMBOL vmlinux 0xaf52c2d3 iommu_bio_merge +EXPORT_SYMBOL vmlinux 0xaf5e8a24 tcf_exts_validate +EXPORT_SYMBOL vmlinux 0xafa8c531 bio_integrity_set_tag +EXPORT_SYMBOL vmlinux 0xafe82e10 strcspn +EXPORT_SYMBOL vmlinux 0xb024cb4b uart_resume_port +EXPORT_SYMBOL vmlinux 0xb04ea8f0 agp_rebind_memory +EXPORT_SYMBOL vmlinux 0xb051909f ida_init +EXPORT_SYMBOL vmlinux 0xb064614f datagram_poll +EXPORT_SYMBOL vmlinux 0xb0778156 neigh_parms_release +EXPORT_SYMBOL vmlinux 0xb07dfb3d acpi_remove_gpe_handler +EXPORT_SYMBOL vmlinux 0xb08d1b9f atm_dev_lookup +EXPORT_SYMBOL vmlinux 0xb0b68e5a inet_getname +EXPORT_SYMBOL vmlinux 0xb0b847ac __bitmap_full +EXPORT_SYMBOL vmlinux 0xb0e10781 get_option +EXPORT_SYMBOL vmlinux 0xb0e3a128 bio_phys_segments +EXPORT_SYMBOL vmlinux 0xb0fbe2e9 pci_try_set_mwi +EXPORT_SYMBOL vmlinux 0xb116807f vfs_lstat +EXPORT_SYMBOL vmlinux 0xb11fa1ce strlcat +EXPORT_SYMBOL vmlinux 0xb121390a probe_irq_on +EXPORT_SYMBOL vmlinux 0xb1645a2e sg_free_table +EXPORT_SYMBOL vmlinux 0xb18e02c3 radix_tree_gang_lookup_tag +EXPORT_SYMBOL vmlinux 0xb1911bd4 blk_queue_make_request +EXPORT_SYMBOL vmlinux 0xb19760c3 bitmap_onto +EXPORT_SYMBOL vmlinux 0xb1a0aa11 skb_insert +EXPORT_SYMBOL vmlinux 0xb1acfd47 kset_register +EXPORT_SYMBOL vmlinux 0xb1c3a01a oops_in_progress +EXPORT_SYMBOL vmlinux 0xb1cf4100 get_super +EXPORT_SYMBOL vmlinux 0xb1cfad22 rdmsr_on_cpu +EXPORT_SYMBOL vmlinux 0xb1e591f3 fb_pan_display +EXPORT_SYMBOL vmlinux 0xb1f975aa unlock_kernel +EXPORT_SYMBOL vmlinux 0xb2017c1d per_cpu__x86_bios_cpu_apicid +EXPORT_SYMBOL vmlinux 0xb21e9ddb pci_enable_device +EXPORT_SYMBOL vmlinux 0xb2581b7d tty_register_device +EXPORT_SYMBOL vmlinux 0xb2607cfa __break_lease +EXPORT_SYMBOL vmlinux 0xb26665db bio_add_pc_page +EXPORT_SYMBOL vmlinux 0xb2be638a dma_chan_cleanup +EXPORT_SYMBOL vmlinux 0xb2e0fbac nf_register_hook +EXPORT_SYMBOL vmlinux 0xb2e85462 netdev_class_remove_file +EXPORT_SYMBOL vmlinux 0xb2f529e4 tr_type_trans +EXPORT_SYMBOL vmlinux 0xb2fd5ceb __put_user_4 +EXPORT_SYMBOL vmlinux 0xb3205415 wait_for_completion_killable +EXPORT_SYMBOL vmlinux 0xb3284531 acpi_dbg_layer +EXPORT_SYMBOL vmlinux 0xb3318ded __down_read_trylock +EXPORT_SYMBOL vmlinux 0xb34d4c2e acpi_terminate +EXPORT_SYMBOL vmlinux 0xb352177e find_first_bit +EXPORT_SYMBOL vmlinux 0xb3692eb4 ioremap_wc +EXPORT_SYMBOL vmlinux 0xb3a307c6 si_meminfo +EXPORT_SYMBOL vmlinux 0xb3b5de37 llc_add_pack +EXPORT_SYMBOL vmlinux 0xb3ff1f69 free_pages_exact +EXPORT_SYMBOL vmlinux 0xb423dba1 console_blanked +EXPORT_SYMBOL vmlinux 0xb4390f9a mcount +EXPORT_SYMBOL vmlinux 0xb43a83e2 dcache_dir_lseek +EXPORT_SYMBOL vmlinux 0xb45b24f6 k8_nb_ids +EXPORT_SYMBOL vmlinux 0xb47ee7ad sock_no_getsockopt +EXPORT_SYMBOL vmlinux 0xb494e82a br_fdb_put_hook +EXPORT_SYMBOL vmlinux 0xb4ca9447 __kfifo_get +EXPORT_SYMBOL vmlinux 0xb4cbb490 bio_copy_kern +EXPORT_SYMBOL vmlinux 0xb4d9569c dma_pool_create +EXPORT_SYMBOL vmlinux 0xb501bd1a alloc_buffer_head +EXPORT_SYMBOL vmlinux 0xb5044271 vsscanf +EXPORT_SYMBOL vmlinux 0xb512290f __dev_remove_pack +EXPORT_SYMBOL vmlinux 0xb52c5efb __skb_recv_datagram +EXPORT_SYMBOL vmlinux 0xb54533f7 usecs_to_jiffies +EXPORT_SYMBOL vmlinux 0xb5814df1 update_region +EXPORT_SYMBOL vmlinux 0xb58e9a61 unregister_netdevice +EXPORT_SYMBOL vmlinux 0xb5a459dc unregister_blkdev +EXPORT_SYMBOL vmlinux 0xb5aa81b4 blk_plug_device_unlocked +EXPORT_SYMBOL vmlinux 0xb5bed5db skb_checksum_help +EXPORT_SYMBOL vmlinux 0xb5d52c27 ec_transaction +EXPORT_SYMBOL vmlinux 0xb60e34a8 nla_memcpy +EXPORT_SYMBOL vmlinux 0xb6244511 sg_init_one +EXPORT_SYMBOL vmlinux 0xb6381b3d vcc_release_async +EXPORT_SYMBOL vmlinux 0xb63f65c8 generic_setxattr +EXPORT_SYMBOL vmlinux 0xb66d6534 dquot_free_space +EXPORT_SYMBOL vmlinux 0xb678366f int_sqrt +EXPORT_SYMBOL vmlinux 0xb6841ee7 set_bdi_congested +EXPORT_SYMBOL vmlinux 0xb6a61a86 qdisc_get_rtab +EXPORT_SYMBOL vmlinux 0xb6ba8bc6 pci_select_bars +EXPORT_SYMBOL vmlinux 0xb6bc274e sk_stream_error +EXPORT_SYMBOL vmlinux 0xb6be8aa5 d_genocide +EXPORT_SYMBOL vmlinux 0xb6cb110e send_sig_info +EXPORT_SYMBOL vmlinux 0xb6cbe886 acpi_get_node +EXPORT_SYMBOL vmlinux 0xb6e227aa rtc_lock +EXPORT_SYMBOL vmlinux 0xb6eefc18 swiotlb_dma_supported +EXPORT_SYMBOL vmlinux 0xb714a981 console_print +EXPORT_SYMBOL vmlinux 0xb715680b fib_default_rule_add +EXPORT_SYMBOL vmlinux 0xb7161553 xrlim_allow +EXPORT_SYMBOL vmlinux 0xb7555f12 timeval_to_jiffies +EXPORT_SYMBOL vmlinux 0xb758b225 acpi_disable_event +EXPORT_SYMBOL vmlinux 0xb79eacec scm_detach_fds +EXPORT_SYMBOL vmlinux 0xb7a6d97e simple_getattr +EXPORT_SYMBOL vmlinux 0xb7b61aa7 bio_unmap_user +EXPORT_SYMBOL vmlinux 0xb7ee3f25 inet_frag_destroy +EXPORT_SYMBOL vmlinux 0xb84e75b1 thaw_bdev +EXPORT_SYMBOL vmlinux 0xb86e4ab9 random32 +EXPORT_SYMBOL vmlinux 0xb89af9bf srandom32 +EXPORT_SYMBOL vmlinux 0xb8a334e5 blk_queue_prep_rq +EXPORT_SYMBOL vmlinux 0xb8b5abe2 pci_bus_read_config_byte +EXPORT_SYMBOL vmlinux 0xb8e7ce2c __put_user_8 +EXPORT_SYMBOL vmlinux 0xb8fd8461 vfs_dq_drop +EXPORT_SYMBOL vmlinux 0xb9032354 tcp_md5_hash_skb_data +EXPORT_SYMBOL vmlinux 0xb945a45f kill_pid +EXPORT_SYMBOL vmlinux 0xb9805b0c down_read_trylock +EXPORT_SYMBOL vmlinux 0xb98a0185 rtc_tm_to_time +EXPORT_SYMBOL vmlinux 0xb9c74bf1 gen_kill_estimator +EXPORT_SYMBOL vmlinux 0xb9fd2205 add_efi_memmap +EXPORT_SYMBOL vmlinux 0xba1b271c sync_page_range_nolock +EXPORT_SYMBOL vmlinux 0xba2d8594 ec_read +EXPORT_SYMBOL vmlinux 0xba49389e kill_anon_super +EXPORT_SYMBOL vmlinux 0xba497f13 loops_per_jiffy +EXPORT_SYMBOL vmlinux 0xba542af2 kernel_listen +EXPORT_SYMBOL vmlinux 0xbaa2782a kstrndup +EXPORT_SYMBOL vmlinux 0xbac311b7 simple_write_end +EXPORT_SYMBOL vmlinux 0xbaf75a4d xfrm_state_delete_tunnel +EXPORT_SYMBOL vmlinux 0xbb167766 fb_var_to_videomode +EXPORT_SYMBOL vmlinux 0xbb189cad disallow_signal +EXPORT_SYMBOL vmlinux 0xbb200c6a ethtool_op_set_sg +EXPORT_SYMBOL vmlinux 0xbb2e9409 bfifo_qdisc_ops +EXPORT_SYMBOL vmlinux 0xbb5b62df dev_kfree_skb_any +EXPORT_SYMBOL vmlinux 0xbb5d343d xfrm_get_acqseq +EXPORT_SYMBOL vmlinux 0xbb83bd29 xfrm_cfg_mutex +EXPORT_SYMBOL vmlinux 0xbbc8e804 param_set_ushort +EXPORT_SYMBOL vmlinux 0xbbe058e9 dev_queue_xmit +EXPORT_SYMBOL vmlinux 0xbc03317f neigh_seq_start +EXPORT_SYMBOL vmlinux 0xbc0b7719 sock_wake_async +EXPORT_SYMBOL vmlinux 0xbca0d6f8 set_bh_page +EXPORT_SYMBOL vmlinux 0xbca183c4 kill_block_super +EXPORT_SYMBOL vmlinux 0xbcc308bb strnlen_user +EXPORT_SYMBOL vmlinux 0xbccbb49c idr_remove_all +EXPORT_SYMBOL vmlinux 0xbcd1d393 user_path_at +EXPORT_SYMBOL vmlinux 0xbcdc28fd udp_disconnect +EXPORT_SYMBOL vmlinux 0xbcf148cf inet_frag_evictor +EXPORT_SYMBOL vmlinux 0xbd2db4cb simple_fill_super +EXPORT_SYMBOL vmlinux 0xbdaf5b07 acpi_os_read_port +EXPORT_SYMBOL vmlinux 0xbde1535c __dev_getfirstbyhwtype +EXPORT_SYMBOL vmlinux 0xbe4784e8 clear_inode +EXPORT_SYMBOL vmlinux 0xbe4901ee agp_flush_chipset +EXPORT_SYMBOL vmlinux 0xbe499d81 copy_to_user +EXPORT_SYMBOL vmlinux 0xbea85dc6 tty_chars_in_buffer +EXPORT_SYMBOL vmlinux 0xbea8fa39 unregister_con_driver +EXPORT_SYMBOL vmlinux 0xbebe5996 locks_init_lock +EXPORT_SYMBOL vmlinux 0xbecdce74 ida_pre_get +EXPORT_SYMBOL vmlinux 0xbedc3503 acpi_bus_add +EXPORT_SYMBOL vmlinux 0xbee14701 qdisc_create_dflt +EXPORT_SYMBOL vmlinux 0xbee2ab20 mnt_unpin +EXPORT_SYMBOL vmlinux 0xbee332b9 block_prepare_write +EXPORT_SYMBOL vmlinux 0xbef43296 console_conditional_schedule +EXPORT_SYMBOL vmlinux 0xbefee397 acpi_get_object_info +EXPORT_SYMBOL vmlinux 0xbf1a686e unlock_super +EXPORT_SYMBOL vmlinux 0xbf2f030d skb_copy_expand +EXPORT_SYMBOL vmlinux 0xbf7fd2f5 schedule_timeout_killable +EXPORT_SYMBOL vmlinux 0xbf9bcc8d __cap_empty_set +EXPORT_SYMBOL vmlinux 0xbfa3d14f skb_put +EXPORT_SYMBOL vmlinux 0xbfaa8891 tcf_exts_destroy +EXPORT_SYMBOL vmlinux 0xbfbaaed7 thermal_zone_bind_cooling_device +EXPORT_SYMBOL vmlinux 0xbfc177bc iowrite32_rep +EXPORT_SYMBOL vmlinux 0xbfc62d50 iget_failed +EXPORT_SYMBOL vmlinux 0xbfe0ee26 flush_old_exec +EXPORT_SYMBOL vmlinux 0xbfe4e38f blk_rq_map_integrity_sg +EXPORT_SYMBOL vmlinux 0xbfe8828f nla_reserve_nohdr +EXPORT_SYMBOL vmlinux 0xc003c637 __strncpy_from_user +EXPORT_SYMBOL vmlinux 0xc00efd44 fb_show_logo +EXPORT_SYMBOL vmlinux 0xc0222c20 fifo_set_limit +EXPORT_SYMBOL vmlinux 0xc045ad4e timespec_trunc +EXPORT_SYMBOL vmlinux 0xc0580937 rb_erase +EXPORT_SYMBOL vmlinux 0xc079de2d netdev_features_change +EXPORT_SYMBOL vmlinux 0xc07cfe86 bio_integrity_split +EXPORT_SYMBOL vmlinux 0xc07d43ae acpi_evaluate_reference +EXPORT_SYMBOL vmlinux 0xc082ba2f try_to_release_page +EXPORT_SYMBOL vmlinux 0xc09651d9 crc32_be +EXPORT_SYMBOL vmlinux 0xc0a3d105 find_next_bit +EXPORT_SYMBOL vmlinux 0xc0ed93b3 dquot_acquire +EXPORT_SYMBOL vmlinux 0xc12264ac pci_release_regions +EXPORT_SYMBOL vmlinux 0xc13d7e4c __downgrade_write +EXPORT_SYMBOL vmlinux 0xc1652095 fb_set_cmap +EXPORT_SYMBOL vmlinux 0xc18a0dac __page_symlink +EXPORT_SYMBOL vmlinux 0xc1efbe5b textsearch_prepare +EXPORT_SYMBOL vmlinux 0xc1ffcf58 llc_sap_close +EXPORT_SYMBOL vmlinux 0xc21c407b arp_find +EXPORT_SYMBOL vmlinux 0xc2424641 agp3_generic_cleanup +EXPORT_SYMBOL vmlinux 0xc24883b4 pcim_iomap_regions_request_all +EXPORT_SYMBOL vmlinux 0xc254af48 dcache_lock +EXPORT_SYMBOL vmlinux 0xc256e762 __bitmap_equal +EXPORT_SYMBOL vmlinux 0xc2781502 wake_up_process +EXPORT_SYMBOL vmlinux 0xc278b27c generic_file_splice_read +EXPORT_SYMBOL vmlinux 0xc2e587d1 reset_devices +EXPORT_SYMBOL vmlinux 0xc2f40cdf write_inode_now +EXPORT_SYMBOL vmlinux 0xc3057c76 con_copy_unimap +EXPORT_SYMBOL vmlinux 0xc319af63 blk_recount_segments +EXPORT_SYMBOL vmlinux 0xc321369f sb_set_blocksize +EXPORT_SYMBOL vmlinux 0xc32473c8 dev_set_mac_address +EXPORT_SYMBOL vmlinux 0xc32d8d4b fput +EXPORT_SYMBOL vmlinux 0xc33f6f4c on_each_cpu +EXPORT_SYMBOL vmlinux 0xc3696aa9 pnp_is_active +EXPORT_SYMBOL vmlinux 0xc3771761 blkdev_put +EXPORT_SYMBOL vmlinux 0xc38e5923 udp_stats_in6 +EXPORT_SYMBOL vmlinux 0xc38fd85c compat_tcp_setsockopt +EXPORT_SYMBOL vmlinux 0xc3aaf0a9 __put_user_1 +EXPORT_SYMBOL vmlinux 0xc3d40060 free_task +EXPORT_SYMBOL vmlinux 0xc3fb92c4 register_sysctl_table +EXPORT_SYMBOL vmlinux 0xc402cc99 register_acpi_notifier +EXPORT_SYMBOL vmlinux 0xc406f6b2 drop_super +EXPORT_SYMBOL vmlinux 0xc415b30d agp3_generic_tlbflush +EXPORT_SYMBOL vmlinux 0xc449f381 pci_get_subsys +EXPORT_SYMBOL vmlinux 0xc45da5fb elv_next_request +EXPORT_SYMBOL vmlinux 0xc4626d9c get_empty_filp +EXPORT_SYMBOL vmlinux 0xc468f0c5 pcix_get_mmrbc +EXPORT_SYMBOL vmlinux 0xc48554ad proc_mkdir +EXPORT_SYMBOL vmlinux 0xc489da34 dma_ops +EXPORT_SYMBOL vmlinux 0xc499ae1e kstrdup +EXPORT_SYMBOL vmlinux 0xc4ad39b1 posix_lock_file +EXPORT_SYMBOL vmlinux 0xc4bc539a ethtool_op_get_tx_csum +EXPORT_SYMBOL vmlinux 0xc4c62b1c dst_discard +EXPORT_SYMBOL vmlinux 0xc4d489e9 up_write +EXPORT_SYMBOL vmlinux 0xc52f5714 fb_videomode_to_var +EXPORT_SYMBOL vmlinux 0xc53c882d idr_get_new +EXPORT_SYMBOL vmlinux 0xc54a356f register_sysrq_key +EXPORT_SYMBOL vmlinux 0xc5534d64 ioread16 +EXPORT_SYMBOL vmlinux 0xc558530d profile_pc +EXPORT_SYMBOL vmlinux 0xc55f7dc7 _write_trylock +EXPORT_SYMBOL vmlinux 0xc56e67a3 tcf_action_exec +EXPORT_SYMBOL vmlinux 0xc590ad35 __tcf_em_tree_match +EXPORT_SYMBOL vmlinux 0xc5b20fd1 bd_claim +EXPORT_SYMBOL vmlinux 0xc5bb1696 serio_reconnect +EXPORT_SYMBOL vmlinux 0xc5d9c46c agp_try_unsupported_boot +EXPORT_SYMBOL vmlinux 0xc5e29365 pci_clear_mwi +EXPORT_SYMBOL vmlinux 0xc5f22bdb blkdev_issue_flush +EXPORT_SYMBOL vmlinux 0xc5fc7576 netdev_rx_csum_fault +EXPORT_SYMBOL vmlinux 0xc6038fd8 open_bdev_excl +EXPORT_SYMBOL vmlinux 0xc62d6dfa redirty_page_for_writepage +EXPORT_SYMBOL vmlinux 0xc64975c7 ip_route_output_key +EXPORT_SYMBOL vmlinux 0xc65abeb7 agp3_generic_sizes +EXPORT_SYMBOL vmlinux 0xc678d274 sk_filter +EXPORT_SYMBOL vmlinux 0xc67b57c6 pci_target_state +EXPORT_SYMBOL vmlinux 0xc694b653 unlock_buffer +EXPORT_SYMBOL vmlinux 0xc6a02ad5 mnt_pin +EXPORT_SYMBOL vmlinux 0xc6b83c26 inet_csk_destroy_sock +EXPORT_SYMBOL vmlinux 0xc6d088f7 filemap_fault +EXPORT_SYMBOL vmlinux 0xc6d61f51 misc_register +EXPORT_SYMBOL vmlinux 0xc7014d25 bio_hw_segments +EXPORT_SYMBOL vmlinux 0xc7208c3a serial8250_resume_port +EXPORT_SYMBOL vmlinux 0xc740c64a memchr +EXPORT_SYMBOL vmlinux 0xc7566ca4 unregister_sysrq_key +EXPORT_SYMBOL vmlinux 0xc769046f iput +EXPORT_SYMBOL vmlinux 0xc7a24d76 sysfs_format_mac +EXPORT_SYMBOL vmlinux 0xc7a4fbed rtnl_lock +EXPORT_SYMBOL vmlinux 0xc7ba0fff n_tty_ioctl +EXPORT_SYMBOL vmlinux 0xc7ca1dfc __ht_create_irq +EXPORT_SYMBOL vmlinux 0xc7cf4b56 genl_sock +EXPORT_SYMBOL vmlinux 0xc7e75829 agp_generic_mask_memory +EXPORT_SYMBOL vmlinux 0xc80e481f tty_hangup +EXPORT_SYMBOL vmlinux 0xc81ff710 neigh_parms_alloc +EXPORT_SYMBOL vmlinux 0xc84edb59 stop_tty +EXPORT_SYMBOL vmlinux 0xc852bba7 lookup_one_len +EXPORT_SYMBOL vmlinux 0xc867ecab ip_getsockopt +EXPORT_SYMBOL vmlinux 0xc8785ecd inode_needs_sync +EXPORT_SYMBOL vmlinux 0xc897c382 sg_init_table +EXPORT_SYMBOL vmlinux 0xc8b57c27 autoremove_wake_function +EXPORT_SYMBOL vmlinux 0xc8ca3e25 acpi_get_child +EXPORT_SYMBOL vmlinux 0xc8d368ef fb_get_mode +EXPORT_SYMBOL vmlinux 0xc8e94ef8 key_validate +EXPORT_SYMBOL vmlinux 0xc909cd70 bio_integrity_free +EXPORT_SYMBOL vmlinux 0xc92b8d9b netif_device_detach +EXPORT_SYMBOL vmlinux 0xc9437ede __down_write_nested +EXPORT_SYMBOL vmlinux 0xc959ae92 vfs_readdir +EXPORT_SYMBOL vmlinux 0xc967ebf6 __blockdev_direct_IO +EXPORT_SYMBOL vmlinux 0xc998d641 icmp_err_convert +EXPORT_SYMBOL vmlinux 0xc9ab2eef acpi_os_wait_events_complete +EXPORT_SYMBOL vmlinux 0xc9c0cd17 gnet_stats_copy_basic +EXPORT_SYMBOL vmlinux 0xc9c220dd netlink_change_ngroups +EXPORT_SYMBOL vmlinux 0xc9cc7b0f devm_iounmap +EXPORT_SYMBOL vmlinux 0xc9e0f778 blk_queue_softirq_done +EXPORT_SYMBOL vmlinux 0xc9e8a187 set_pages_x +EXPORT_SYMBOL vmlinux 0xca18ccae unlock_rename +EXPORT_SYMBOL vmlinux 0xca366851 __xfrm_state_delete +EXPORT_SYMBOL vmlinux 0xca37ea9d kernel_accept +EXPORT_SYMBOL vmlinux 0xca74bea6 vfs_mknod +EXPORT_SYMBOL vmlinux 0xca831be3 dma_async_memcpy_buf_to_buf +EXPORT_SYMBOL vmlinux 0xca8abced request_key_with_auxdata +EXPORT_SYMBOL vmlinux 0xca8acc78 acpi_dbg_level +EXPORT_SYMBOL vmlinux 0xcaa64048 cpu_sysdev_class +EXPORT_SYMBOL vmlinux 0xcaaa075a tcp_mtup_init +EXPORT_SYMBOL vmlinux 0xcaaf9d43 swiotlb_map_single +EXPORT_SYMBOL vmlinux 0xcaec63a7 simple_sync_file +EXPORT_SYMBOL vmlinux 0xcb26ccb2 xfrm_input_resume +EXPORT_SYMBOL vmlinux 0xcb32da10 param_set_int +EXPORT_SYMBOL vmlinux 0xcb36487c br_handle_frame_hook +EXPORT_SYMBOL vmlinux 0xcb6beb40 hweight32 +EXPORT_SYMBOL vmlinux 0xcb7131fb fb_get_options +EXPORT_SYMBOL vmlinux 0xcb733bf2 acpi_bus_set_power +EXPORT_SYMBOL vmlinux 0xcbc3c814 skb_copy_and_csum_dev +EXPORT_SYMBOL vmlinux 0xcbd938d3 bio_init +EXPORT_SYMBOL vmlinux 0xcbe4271e unregister_quota_format +EXPORT_SYMBOL vmlinux 0xcc07af75 strnlen +EXPORT_SYMBOL vmlinux 0xcc248d26 serial8250_suspend_port +EXPORT_SYMBOL vmlinux 0xcc36f32e fb_unregister_client +EXPORT_SYMBOL vmlinux 0xcc5005fe msleep_interruptible +EXPORT_SYMBOL vmlinux 0xcc51ee50 dma_spin_lock +EXPORT_SYMBOL vmlinux 0xcc523f61 sysctl_jiffies +EXPORT_SYMBOL vmlinux 0xcc7f8443 pnp_start_dev +EXPORT_SYMBOL vmlinux 0xcc7fa952 local_bh_enable_ip +EXPORT_SYMBOL vmlinux 0xcc9237ea pci_remove_behind_bridge +EXPORT_SYMBOL vmlinux 0xccedf984 neigh_update +EXPORT_SYMBOL vmlinux 0xcd30312e kmem_cache_free +EXPORT_SYMBOL vmlinux 0xcd4e0970 dquot_alloc_space +EXPORT_SYMBOL vmlinux 0xcd513a23 set_page_dirty_lock +EXPORT_SYMBOL vmlinux 0xcd6e79cd netdev_set_master +EXPORT_SYMBOL vmlinux 0xcdbb2c66 dcache_dir_close +EXPORT_SYMBOL vmlinux 0xcdc80919 generic_file_mmap +EXPORT_SYMBOL vmlinux 0xce36ded6 sysctl_tcp_mem +EXPORT_SYMBOL vmlinux 0xce4904a4 acpi_leave_sleep_state +EXPORT_SYMBOL vmlinux 0xce5ac24f zlib_inflate_workspacesize +EXPORT_SYMBOL vmlinux 0xce61e785 generic_show_options +EXPORT_SYMBOL vmlinux 0xcea71318 netlink_clear_multicast_users +EXPORT_SYMBOL vmlinux 0xcedfeaac netdev_class_create_file +EXPORT_SYMBOL vmlinux 0xcefcd99a serial8250_unregister_port +EXPORT_SYMBOL vmlinux 0xcf047c83 acpi_disable_gpe +EXPORT_SYMBOL vmlinux 0xcf08ce0d unmap_mapping_range +EXPORT_SYMBOL vmlinux 0xcf170545 skb_find_text +EXPORT_SYMBOL vmlinux 0xcf728d24 d_splice_alias +EXPORT_SYMBOL vmlinux 0xcf86be54 vc_cons +EXPORT_SYMBOL vmlinux 0xcfadd723 __percpu_counter_add +EXPORT_SYMBOL vmlinux 0xcfba4121 xfrm_state_update +EXPORT_SYMBOL vmlinux 0xcfc6c603 key_alloc +EXPORT_SYMBOL vmlinux 0xcfd3018e set_normalized_timespec +EXPORT_SYMBOL vmlinux 0xcfd8a794 __lock_page +EXPORT_SYMBOL vmlinux 0xcfe0bd64 __free_pages +EXPORT_SYMBOL vmlinux 0xd000610a pagevec_lookup +EXPORT_SYMBOL vmlinux 0xd0181f4f __bitmap_xor +EXPORT_SYMBOL vmlinux 0xd021b5ee __find_get_block +EXPORT_SYMBOL vmlinux 0xd02cc869 __bitmap_andnot +EXPORT_SYMBOL vmlinux 0xd02db6fa textsearch_destroy +EXPORT_SYMBOL vmlinux 0xd046763e __pagevec_lru_add +EXPORT_SYMBOL vmlinux 0xd0696d67 xfrm_user_policy +EXPORT_SYMBOL vmlinux 0xd08197fa acpi_load_tables +EXPORT_SYMBOL vmlinux 0xd0ee38b8 schedule_timeout_uninterruptible +EXPORT_SYMBOL vmlinux 0xd0fef3b2 agp_free_key +EXPORT_SYMBOL vmlinux 0xd1042f4b vm_insert_pfn +EXPORT_SYMBOL vmlinux 0xd10496aa input_register_handle +EXPORT_SYMBOL vmlinux 0xd104eec7 bio_free +EXPORT_SYMBOL vmlinux 0xd1472061 acpi_pci_register_driver +EXPORT_SYMBOL vmlinux 0xd153a550 blk_queue_end_tag +EXPORT_SYMBOL vmlinux 0xd18b6eb2 acpi_unmap_lsapic +EXPORT_SYMBOL vmlinux 0xd19bb294 acpi_install_address_space_handler +EXPORT_SYMBOL vmlinux 0xd19c7f38 ht_create_irq +EXPORT_SYMBOL vmlinux 0xd1efb33a give_up_console +EXPORT_SYMBOL vmlinux 0xd1f6c5f3 smp_num_siblings +EXPORT_SYMBOL vmlinux 0xd1f91bcd dev_base_lock +EXPORT_SYMBOL vmlinux 0xd21101fe dma_async_client_unregister +EXPORT_SYMBOL vmlinux 0xd21645d8 __bio_clone +EXPORT_SYMBOL vmlinux 0xd251d7b0 security_socket_getpeersec_dgram +EXPORT_SYMBOL vmlinux 0xd2555f19 jiffies_64_to_clock_t +EXPORT_SYMBOL vmlinux 0xd255c07c default_llseek +EXPORT_SYMBOL vmlinux 0xd255efdf end_queued_request +EXPORT_SYMBOL vmlinux 0xd25d4f74 console_blank_hook +EXPORT_SYMBOL vmlinux 0xd267d42c down_killable +EXPORT_SYMBOL vmlinux 0xd2812d23 tcp_close +EXPORT_SYMBOL vmlinux 0xd2965f6f kthread_should_stop +EXPORT_SYMBOL vmlinux 0xd29f3bd6 force_sig +EXPORT_SYMBOL vmlinux 0xd2b39dd4 agp_free_memory +EXPORT_SYMBOL vmlinux 0xd2d746c4 input_inject_event +EXPORT_SYMBOL vmlinux 0xd334386b block_write_end +EXPORT_SYMBOL vmlinux 0xd34f0c62 gen_pool_create +EXPORT_SYMBOL vmlinux 0xd351abb1 inc_zone_page_state +EXPORT_SYMBOL vmlinux 0xd357cc57 set_device_ro +EXPORT_SYMBOL vmlinux 0xd36f5997 proto_register +EXPORT_SYMBOL vmlinux 0xd37b5e86 bdi_register +EXPORT_SYMBOL vmlinux 0xd3951da4 acpi_resource_to_address64 +EXPORT_SYMBOL vmlinux 0xd3d0fe73 __mpage_writepage +EXPORT_SYMBOL vmlinux 0xd3f4c3bb nobh_writepage +EXPORT_SYMBOL vmlinux 0xd3f74cf1 interruptible_sleep_on_timeout +EXPORT_SYMBOL vmlinux 0xd42b7232 _write_unlock_bh +EXPORT_SYMBOL vmlinux 0xd42c3a7b inet_csk_delete_keepalive_timer +EXPORT_SYMBOL vmlinux 0xd46c157a tty_set_operations +EXPORT_SYMBOL vmlinux 0xd4a84ef9 __pagevec_release +EXPORT_SYMBOL vmlinux 0xd4bfa570 xfrm4_rcv +EXPORT_SYMBOL vmlinux 0xd4d5e73c generic_file_llseek_unlocked +EXPORT_SYMBOL vmlinux 0xd4db002c __serio_register_port +EXPORT_SYMBOL vmlinux 0xd4e39c1a inet_csk_init_xmit_timers +EXPORT_SYMBOL vmlinux 0xd50e9f86 ethtool_op_set_flags +EXPORT_SYMBOL vmlinux 0xd513e29e eth_type_trans +EXPORT_SYMBOL vmlinux 0xd51a6652 ps2_command +EXPORT_SYMBOL vmlinux 0xd51bb9d0 tcp_v4_conn_request +EXPORT_SYMBOL vmlinux 0xd53f3e5c input_unregister_device +EXPORT_SYMBOL vmlinux 0xd568308e __devm_request_region +EXPORT_SYMBOL vmlinux 0xd56d2013 nf_unregister_hook +EXPORT_SYMBOL vmlinux 0xd5797488 kobject_init +EXPORT_SYMBOL vmlinux 0xd57a4443 invalidate_mapping_pages +EXPORT_SYMBOL vmlinux 0xd5b037e1 kref_put +EXPORT_SYMBOL vmlinux 0xd5d47347 netif_receive_skb +EXPORT_SYMBOL vmlinux 0xd5dc42e5 proc_dointvec_ms_jiffies +EXPORT_SYMBOL vmlinux 0xd6035d05 do_settimeofday +EXPORT_SYMBOL vmlinux 0xd60d7af4 ida_remove +EXPORT_SYMBOL vmlinux 0xd62c833f schedule_timeout +EXPORT_SYMBOL vmlinux 0xd647f526 vc_resize +EXPORT_SYMBOL vmlinux 0xd69688b5 d_alloc_name +EXPORT_SYMBOL vmlinux 0xd6a78d08 smp_call_function_single +EXPORT_SYMBOL vmlinux 0xd6b33026 cpu_khz +EXPORT_SYMBOL vmlinux 0xd6ee688f vmalloc +EXPORT_SYMBOL vmlinux 0xd6f3b1a7 xfrm_policy_insert +EXPORT_SYMBOL vmlinux 0xd6f7ab50 sock_no_getname +EXPORT_SYMBOL vmlinux 0xd70af353 dma_async_client_register +EXPORT_SYMBOL vmlinux 0xd7504317 dcache_dir_open +EXPORT_SYMBOL vmlinux 0xd7504f39 blk_queue_max_phys_segments +EXPORT_SYMBOL vmlinux 0xd760aa26 pcim_iomap +EXPORT_SYMBOL vmlinux 0xd79b5a02 allow_signal +EXPORT_SYMBOL vmlinux 0xd7a6fafa panic_notifier_list +EXPORT_SYMBOL vmlinux 0xd7bc5729 vfs_quota_on_mount +EXPORT_SYMBOL vmlinux 0xd7d211ed xfrm_policy_walk +EXPORT_SYMBOL vmlinux 0xd7da2336 vfs_readlink +EXPORT_SYMBOL vmlinux 0xd7dd777b reserve_perfctr_nmi +EXPORT_SYMBOL vmlinux 0xd7f09e60 nf_reinject +EXPORT_SYMBOL vmlinux 0xd80fe15e netdev_boot_setup_check +EXPORT_SYMBOL vmlinux 0xd85e4496 skb_checksum +EXPORT_SYMBOL vmlinux 0xd88f695a __mod_timer +EXPORT_SYMBOL vmlinux 0xd89da37f movable_zone +EXPORT_SYMBOL vmlinux 0xd8b3f247 elv_dispatch_add_tail +EXPORT_SYMBOL vmlinux 0xd8e484f0 register_chrdev_region +EXPORT_SYMBOL vmlinux 0xd903ac70 inet_shutdown +EXPORT_SYMBOL vmlinux 0xd9091363 acpi_install_notify_handler +EXPORT_SYMBOL vmlinux 0xd93315e9 input_event +EXPORT_SYMBOL vmlinux 0xd9449590 dev_mc_delete +EXPORT_SYMBOL vmlinux 0xd972ed41 netlink_kernel_release +EXPORT_SYMBOL vmlinux 0xd981c191 lease_modify +EXPORT_SYMBOL vmlinux 0xd985dc99 mempool_free_pages +EXPORT_SYMBOL vmlinux 0xd9941836 __brelse +EXPORT_SYMBOL vmlinux 0xd9a365b3 blk_rq_init +EXPORT_SYMBOL vmlinux 0xd9a79ade netpoll_parse_options +EXPORT_SYMBOL vmlinux 0xd9b7c442 balance_dirty_pages_ratelimited_nr +EXPORT_SYMBOL vmlinux 0xd9e543d5 neigh_sysctl_unregister +EXPORT_SYMBOL vmlinux 0xd9f2a87a generic_shutdown_super +EXPORT_SYMBOL vmlinux 0xda0a6b0e acpi_map_lsapic +EXPORT_SYMBOL vmlinux 0xda136780 serio_unregister_child_port +EXPORT_SYMBOL vmlinux 0xda1a7335 kasprintf +EXPORT_SYMBOL vmlinux 0xda2b8ace agp_generic_free_by_type +EXPORT_SYMBOL vmlinux 0xda4629e4 radix_tree_insert +EXPORT_SYMBOL vmlinux 0xda4ad484 iunique +EXPORT_SYMBOL vmlinux 0xda72fe1a acpi_check_mem_region +EXPORT_SYMBOL vmlinux 0xda73a1d0 __check_region +EXPORT_SYMBOL vmlinux 0xda7ca6cb fb_mode_is_equal +EXPORT_SYMBOL vmlinux 0xda8af7ad fb_find_nearest_mode +EXPORT_SYMBOL vmlinux 0xda928914 nmi_watchdog +EXPORT_SYMBOL vmlinux 0xdaa98ff4 pfifo_qdisc_ops +EXPORT_SYMBOL vmlinux 0xdaafff7f rtnl_set_sk_err +EXPORT_SYMBOL vmlinux 0xdac3e5a2 xfrm_state_delete +EXPORT_SYMBOL vmlinux 0xdae0dc74 dma_alloc_coherent +EXPORT_SYMBOL vmlinux 0xdaedc84e simple_rmdir +EXPORT_SYMBOL vmlinux 0xdb347ebb get_agp_version +EXPORT_SYMBOL vmlinux 0xdb66b165 aio_put_req +EXPORT_SYMBOL vmlinux 0xdb7c30be pnp_register_driver +EXPORT_SYMBOL vmlinux 0xdbcd416e sysctl_ip_nonlocal_bind +EXPORT_SYMBOL vmlinux 0xdbd1d593 qdisc_calculate_pkt_len +EXPORT_SYMBOL vmlinux 0xdc04fbfa mark_buffer_async_write +EXPORT_SYMBOL vmlinux 0xdc14eda7 pci_pci_problems +EXPORT_SYMBOL vmlinux 0xdc2adb35 add_taint +EXPORT_SYMBOL vmlinux 0xdc3eaf70 iomem_resource +EXPORT_SYMBOL vmlinux 0xdc40932b generic_file_aio_read +EXPORT_SYMBOL vmlinux 0xdc43a9c8 daemonize +EXPORT_SYMBOL vmlinux 0xdc68bbd4 sync_page_range +EXPORT_SYMBOL vmlinux 0xdc873a70 screen_info +EXPORT_SYMBOL vmlinux 0xdc9e8d46 xfrm_register_km +EXPORT_SYMBOL vmlinux 0xdcb0349b sys_close +EXPORT_SYMBOL vmlinux 0xdcbd16b6 read_cache_pages +EXPORT_SYMBOL vmlinux 0xdcc74817 simple_link +EXPORT_SYMBOL vmlinux 0xdcda205a acpi_bus_unregister_driver +EXPORT_SYMBOL vmlinux 0xdcdd40ff pci_request_regions +EXPORT_SYMBOL vmlinux 0xdd0ebf56 set_anon_super +EXPORT_SYMBOL vmlinux 0xdd135e5d cfb_imageblit +EXPORT_SYMBOL vmlinux 0xdd47b644 input_flush_device +EXPORT_SYMBOL vmlinux 0xdd62b45d find_task_by_vpid +EXPORT_SYMBOL vmlinux 0xdd72f76b blk_insert_request +EXPORT_SYMBOL vmlinux 0xddc09646 dma_supported +EXPORT_SYMBOL vmlinux 0xddc1ac11 bioset_integrity_free +EXPORT_SYMBOL vmlinux 0xddedf5ab skb_under_panic +EXPORT_SYMBOL vmlinux 0xde0bdcff memset +EXPORT_SYMBOL vmlinux 0xde4129b3 blk_queue_max_sectors +EXPORT_SYMBOL vmlinux 0xde5c08e2 fb_get_buffer_offset +EXPORT_SYMBOL vmlinux 0xde682433 pci_scan_single_device +EXPORT_SYMBOL vmlinux 0xde72b41d pci_bus_find_capability +EXPORT_SYMBOL vmlinux 0xde75b689 set_irq_type +EXPORT_SYMBOL vmlinux 0xde90ac48 pci_bus_read_config_word +EXPORT_SYMBOL vmlinux 0xde9360ba totalram_pages +EXPORT_SYMBOL vmlinux 0xde9b17ed agp3_generic_fetch_size +EXPORT_SYMBOL vmlinux 0xde9f91ab __insert_inode_hash +EXPORT_SYMBOL vmlinux 0xdea915db generic_file_buffered_write +EXPORT_SYMBOL vmlinux 0xdebe4d9d get_sb_single +EXPORT_SYMBOL vmlinux 0xdf0da3cc acpi_get_devices +EXPORT_SYMBOL vmlinux 0xdf2a62ca pci_remove_bus_device +EXPORT_SYMBOL vmlinux 0xdf60cc27 __print_symbol +EXPORT_SYMBOL vmlinux 0xdf8c695a __ndelay +EXPORT_SYMBOL vmlinux 0xdf929370 fs_overflowgid +EXPORT_SYMBOL vmlinux 0xdfab3516 agp_collect_device_status +EXPORT_SYMBOL vmlinux 0xe00fb238 release_resource +EXPORT_SYMBOL vmlinux 0xe012292d vmtruncate +EXPORT_SYMBOL vmlinux 0xe061deae tty_check_change +EXPORT_SYMBOL vmlinux 0xe075d6eb iter_div_u64_rem +EXPORT_SYMBOL vmlinux 0xe085650d bdi_init +EXPORT_SYMBOL vmlinux 0xe09f7a59 nf_setsockopt +EXPORT_SYMBOL vmlinux 0xe0ac8bd2 acpi_bus_generate_netlink_event +EXPORT_SYMBOL vmlinux 0xe0b13336 argv_free +EXPORT_SYMBOL vmlinux 0xe0b5502d adjust_resource +EXPORT_SYMBOL vmlinux 0xe0d625aa pci_setup_cardbus +EXPORT_SYMBOL vmlinux 0xe0d8d25b blk_queue_free_tags +EXPORT_SYMBOL vmlinux 0xe0fbbb15 I_BDEV +EXPORT_SYMBOL vmlinux 0xe113bbbc csum_partial +EXPORT_SYMBOL vmlinux 0xe13cd8a7 dmi_name_in_vendors +EXPORT_SYMBOL vmlinux 0xe1761617 security_inet_conn_request +EXPORT_SYMBOL vmlinux 0xe1a03c63 tcf_em_tree_dump +EXPORT_SYMBOL vmlinux 0xe1b19e8a audit_log_end +EXPORT_SYMBOL vmlinux 0xe1fa05f0 agp_generic_remove_memory +EXPORT_SYMBOL vmlinux 0xe1fe8cae sock_wmalloc +EXPORT_SYMBOL vmlinux 0xe20aa063 clear_page_dirty_for_io +EXPORT_SYMBOL vmlinux 0xe20d59ab pnp_stop_dev +EXPORT_SYMBOL vmlinux 0xe20ff39c tcp_prot +EXPORT_SYMBOL vmlinux 0xe22604f4 may_umount +EXPORT_SYMBOL vmlinux 0xe24050c7 scnprintf +EXPORT_SYMBOL vmlinux 0xe24d3a97 jiffies_64 +EXPORT_SYMBOL vmlinux 0xe24d5a02 ip_cmsg_recv +EXPORT_SYMBOL vmlinux 0xe26b1fe7 read_dev_sector +EXPORT_SYMBOL vmlinux 0xe2a17e0f dmam_alloc_coherent +EXPORT_SYMBOL vmlinux 0xe2b89662 xfrm_dst_ifdown +EXPORT_SYMBOL vmlinux 0xe2c8a6f4 inet_dev_addr_type +EXPORT_SYMBOL vmlinux 0xe2d5255a strcmp +EXPORT_SYMBOL vmlinux 0xe302ce6c cont_write_begin +EXPORT_SYMBOL vmlinux 0xe33e3dca kmem_cache_size +EXPORT_SYMBOL vmlinux 0xe33f2f86 get_disk +EXPORT_SYMBOL vmlinux 0xe351633f genl_register_family +EXPORT_SYMBOL vmlinux 0xe38ed5d1 skb_over_panic +EXPORT_SYMBOL vmlinux 0xe3a334d3 __nla_put_nohdr +EXPORT_SYMBOL vmlinux 0xe3b0192b vscnprintf +EXPORT_SYMBOL vmlinux 0xe3beb57f dma_async_memcpy_pg_to_pg +EXPORT_SYMBOL vmlinux 0xe3f09148 neigh_compat_output +EXPORT_SYMBOL vmlinux 0xe3fbe148 acpi_install_table_handler +EXPORT_SYMBOL vmlinux 0xe40af88d pci_disable_msi +EXPORT_SYMBOL vmlinux 0xe414d795 dquot_drop +EXPORT_SYMBOL vmlinux 0xe43617f7 acpi_gbl_FADT +EXPORT_SYMBOL vmlinux 0xe4488a99 sk_dst_check +EXPORT_SYMBOL vmlinux 0xe44928c2 flock_lock_file_wait +EXPORT_SYMBOL vmlinux 0xe456bd3a complete +EXPORT_SYMBOL vmlinux 0xe45a1e90 vfs_create +EXPORT_SYMBOL vmlinux 0xe4781db5 sock_kfree_s +EXPORT_SYMBOL vmlinux 0xe484e35f ioread32 +EXPORT_SYMBOL vmlinux 0xe4870354 _read_trylock +EXPORT_SYMBOL vmlinux 0xe4c1df3e _read_lock_bh +EXPORT_SYMBOL vmlinux 0xe4c37a71 blk_get_request +EXPORT_SYMBOL vmlinux 0xe5122890 flow_cache_genid +EXPORT_SYMBOL vmlinux 0xe523ad75 synchronize_irq +EXPORT_SYMBOL vmlinux 0xe52947e7 __phys_addr +EXPORT_SYMBOL vmlinux 0xe52bed82 unbind_con_driver +EXPORT_SYMBOL vmlinux 0xe538f6df elv_rb_find +EXPORT_SYMBOL vmlinux 0xe543e1fd splice_direct_to_actor +EXPORT_SYMBOL vmlinux 0xe55484ce neigh_seq_stop +EXPORT_SYMBOL vmlinux 0xe55704ab nf_hooks +EXPORT_SYMBOL vmlinux 0xe57878a1 in6_pton +EXPORT_SYMBOL vmlinux 0xe5867808 dlci_ioctl_set +EXPORT_SYMBOL vmlinux 0xe5ba71a2 __f_setown +EXPORT_SYMBOL vmlinux 0xe5c78a99 do_blank_screen +EXPORT_SYMBOL vmlinux 0xe694cc8a set_current_groups +EXPORT_SYMBOL vmlinux 0xe69ca86a __pci_register_driver +EXPORT_SYMBOL vmlinux 0xe69f63ff d_path +EXPORT_SYMBOL vmlinux 0xe6c2053d pci_get_slot +EXPORT_SYMBOL vmlinux 0xe6ce2e19 file_fsync +EXPORT_SYMBOL vmlinux 0xe6df4c74 dma_pool_alloc +EXPORT_SYMBOL vmlinux 0xe6ebe162 skb_copy_bits +EXPORT_SYMBOL vmlinux 0xe6fb18a3 ip_ct_attach +EXPORT_SYMBOL vmlinux 0xe6fbe430 can_do_mlock +EXPORT_SYMBOL vmlinux 0xe716baed acpi_unregister_ioapic +EXPORT_SYMBOL vmlinux 0xe7177e73 end_request +EXPORT_SYMBOL vmlinux 0xe7537902 brioctl_set +EXPORT_SYMBOL vmlinux 0xe775b220 mpage_writepages +EXPORT_SYMBOL vmlinux 0xe78effae tcp_check_req +EXPORT_SYMBOL vmlinux 0xe7a43b61 bio_clone +EXPORT_SYMBOL vmlinux 0xe7bfcb3c dst_release +EXPORT_SYMBOL vmlinux 0xe7d0a9a0 nf_log_unregister +EXPORT_SYMBOL vmlinux 0xe7d4daac seq_list_next +EXPORT_SYMBOL vmlinux 0xe80ce219 sysctl_tcp_dma_copybreak +EXPORT_SYMBOL vmlinux 0xe8104dbe input_grab_device +EXPORT_SYMBOL vmlinux 0xe8116e08 __kmalloc_node +EXPORT_SYMBOL vmlinux 0xe81a4746 call_usermodehelper_pipe +EXPORT_SYMBOL vmlinux 0xe820304e mpage_readpage +EXPORT_SYMBOL vmlinux 0xe8259d6c qdisc_watchdog_schedule +EXPORT_SYMBOL vmlinux 0xe8315025 netlink_dump_start +EXPORT_SYMBOL vmlinux 0xe8583614 posix_acl_from_xattr +EXPORT_SYMBOL vmlinux 0xe89a3b39 inode_add_bytes +EXPORT_SYMBOL vmlinux 0xe8a12d11 shrink_dcache_parent +EXPORT_SYMBOL vmlinux 0xe8a26983 ip_mc_join_group +EXPORT_SYMBOL vmlinux 0xe8c35ee7 simple_transaction_get +EXPORT_SYMBOL vmlinux 0xe8cc2910 dev_open +EXPORT_SYMBOL vmlinux 0xe8cd902e hweight16 +EXPORT_SYMBOL vmlinux 0xe910b532 del_timer_sync +EXPORT_SYMBOL vmlinux 0xe911a2c1 __mark_inode_dirty +EXPORT_SYMBOL vmlinux 0xe914e41e strcpy +EXPORT_SYMBOL vmlinux 0xe9456a5a sysctl_xfrm_aevent_rseqth +EXPORT_SYMBOL vmlinux 0xe997667b wrmsr_on_cpu +EXPORT_SYMBOL vmlinux 0xe9cdba0c inet_listen +EXPORT_SYMBOL vmlinux 0xe9e9bd42 key_task_permission +EXPORT_SYMBOL vmlinux 0xe9f44cb5 pci_enable_device_mem +EXPORT_SYMBOL vmlinux 0xea0fafac write_one_page +EXPORT_SYMBOL vmlinux 0xea10655a __bitmap_intersects +EXPORT_SYMBOL vmlinux 0xea147363 printk +EXPORT_SYMBOL vmlinux 0xea3ddc95 vfs_read +EXPORT_SYMBOL vmlinux 0xea44461f key_type_keyring +EXPORT_SYMBOL vmlinux 0xea69a8a6 kernel_sendmsg +EXPORT_SYMBOL vmlinux 0xea6fcdaa genl_unregister_family +EXPORT_SYMBOL vmlinux 0xea757d9e inet_frags_init +EXPORT_SYMBOL vmlinux 0xea8636c6 xfrm_stateonly_find +EXPORT_SYMBOL vmlinux 0xead58fb9 print_hex_dump +EXPORT_SYMBOL vmlinux 0xeae3dfd6 __const_udelay +EXPORT_SYMBOL vmlinux 0xeaf31a69 sock_create +EXPORT_SYMBOL vmlinux 0xeb1fabf6 interruptible_sleep_on +EXPORT_SYMBOL vmlinux 0xeb228272 posix_acl_create_masq +EXPORT_SYMBOL vmlinux 0xeb395084 param_get_invbool +EXPORT_SYMBOL vmlinux 0xeb4c5c40 netpoll_print_options +EXPORT_SYMBOL vmlinux 0xeb57136e __bread +EXPORT_SYMBOL vmlinux 0xeb7710ca pv_mmu_ops +EXPORT_SYMBOL vmlinux 0xeb879792 tcp_poll +EXPORT_SYMBOL vmlinux 0xeb8f54b3 strstrip +EXPORT_SYMBOL vmlinux 0xebbc1f62 cpufreq_get_policy +EXPORT_SYMBOL vmlinux 0xebbf1dba strncasecmp +EXPORT_SYMBOL vmlinux 0xebd273a6 strict_strtoull +EXPORT_SYMBOL vmlinux 0xec39a70d xfrm_policy_delete +EXPORT_SYMBOL vmlinux 0xec4a2113 dev_getfirstbyhwtype +EXPORT_SYMBOL vmlinux 0xec7744af xfrm_state_lookup_byaddr +EXPORT_SYMBOL vmlinux 0xec860422 bioset_free +EXPORT_SYMBOL vmlinux 0xec8a79c2 do_splice_from +EXPORT_SYMBOL vmlinux 0xecb3f10d pci_bus_write_config_dword +EXPORT_SYMBOL vmlinux 0xecde1418 _spin_lock_irq +EXPORT_SYMBOL vmlinux 0xecf65ffe audit_log_format +EXPORT_SYMBOL vmlinux 0xed933491 llc_build_and_send_ui_pkt +EXPORT_SYMBOL vmlinux 0xedbaee5e nla_strcmp +EXPORT_SYMBOL vmlinux 0xedc03953 iounmap +EXPORT_SYMBOL vmlinux 0xedd14538 param_get_uint +EXPORT_SYMBOL vmlinux 0xee007bf5 vfs_unlink +EXPORT_SYMBOL vmlinux 0xee019f0b atm_alloc_charge +EXPORT_SYMBOL vmlinux 0xee2d0fc7 _local_bh_enable +EXPORT_SYMBOL vmlinux 0xee4cf46e dev_set_promiscuity +EXPORT_SYMBOL vmlinux 0xee60c909 compat_sock_common_getsockopt +EXPORT_SYMBOL vmlinux 0xee668708 page_follow_link_light +EXPORT_SYMBOL vmlinux 0xee6718a0 fb_set_suspend +EXPORT_SYMBOL vmlinux 0xee7eb9e1 pnp_platform_devices +EXPORT_SYMBOL vmlinux 0xee9c3dd7 pneigh_lookup +EXPORT_SYMBOL vmlinux 0xeea2e5f2 ip_mc_rejoin_group +EXPORT_SYMBOL vmlinux 0xeea9dbaf bitmap_bitremap +EXPORT_SYMBOL vmlinux 0xeeb1717c param_array_get +EXPORT_SYMBOL vmlinux 0xeec0352f neigh_for_each +EXPORT_SYMBOL vmlinux 0xeec45628 page_put_link +EXPORT_SYMBOL vmlinux 0xeecaea22 down_write_trylock +EXPORT_SYMBOL vmlinux 0xeed022bd console_start +EXPORT_SYMBOL vmlinux 0xeefc3673 task_tgid_nr_ns +EXPORT_SYMBOL vmlinux 0xef0d2fff sk_reset_timer +EXPORT_SYMBOL vmlinux 0xef488713 tcp_md5_hash_key +EXPORT_SYMBOL vmlinux 0xef4f7783 pci_pme_capable +EXPORT_SYMBOL vmlinux 0xef5a5e81 simple_unlink +EXPORT_SYMBOL vmlinux 0xef9aedfc boot_option_idle_override +EXPORT_SYMBOL vmlinux 0xefdd70ce security_secid_to_secctx +EXPORT_SYMBOL vmlinux 0xefe099c3 acpi_get_event_status +EXPORT_SYMBOL vmlinux 0xeff3237e del_gendisk +EXPORT_SYMBOL vmlinux 0xeff62008 pci_restore_state +EXPORT_SYMBOL vmlinux 0xf0009fee put_pages_list +EXPORT_SYMBOL vmlinux 0xf03cae64 posix_acl_permission +EXPORT_SYMBOL vmlinux 0xf03f6857 unregister_console +EXPORT_SYMBOL vmlinux 0xf060a8ac generic_writepages +EXPORT_SYMBOL vmlinux 0xf065f629 ioread16be +EXPORT_SYMBOL vmlinux 0xf092cfdb igrab +EXPORT_SYMBOL vmlinux 0xf0a51f91 serio_unregister_port +EXPORT_SYMBOL vmlinux 0xf0b57c68 param_set_long +EXPORT_SYMBOL vmlinux 0xf0f1246c kvasprintf +EXPORT_SYMBOL vmlinux 0xf10681dc open_by_devnum +EXPORT_SYMBOL vmlinux 0xf10de535 ioread8 +EXPORT_SYMBOL vmlinux 0xf11543ff find_first_zero_bit +EXPORT_SYMBOL vmlinux 0xf116d4b5 copy_in_user +EXPORT_SYMBOL vmlinux 0xf1331904 generic_osync_inode +EXPORT_SYMBOL vmlinux 0xf13772f5 set_disk_ro +EXPORT_SYMBOL vmlinux 0xf13a402f tty_unregister_device +EXPORT_SYMBOL vmlinux 0xf1470748 acpi_bus_generate_proc_event +EXPORT_SYMBOL vmlinux 0xf162fe2d sysctl_xfrm_aevent_etime +EXPORT_SYMBOL vmlinux 0xf16afa2f register_con_driver +EXPORT_SYMBOL vmlinux 0xf174ed48 acquire_console_sem +EXPORT_SYMBOL vmlinux 0xf17bb80c simple_transaction_read +EXPORT_SYMBOL vmlinux 0xf18bcd33 find_get_page +EXPORT_SYMBOL vmlinux 0xf195c682 fb_invert_cmaps +EXPORT_SYMBOL vmlinux 0xf1aba93a pci_enable_wake +EXPORT_SYMBOL vmlinux 0xf1c6a746 d_move +EXPORT_SYMBOL vmlinux 0xf1c91e9d set_binfmt +EXPORT_SYMBOL vmlinux 0xf1cecbda nobh_write_end +EXPORT_SYMBOL vmlinux 0xf1d4329b cdev_add +EXPORT_SYMBOL vmlinux 0xf1d98b34 neigh_table_init +EXPORT_SYMBOL vmlinux 0xf1dc9939 simple_empty +EXPORT_SYMBOL vmlinux 0xf1e98c74 avenrun +EXPORT_SYMBOL vmlinux 0xf20dabd8 free_irq +EXPORT_SYMBOL vmlinux 0xf2126d75 dma_async_device_register +EXPORT_SYMBOL vmlinux 0xf225158b skb_copy_datagram_iovec +EXPORT_SYMBOL vmlinux 0xf230200b blk_start_queue +EXPORT_SYMBOL vmlinux 0xf246de13 tcf_hash_destroy +EXPORT_SYMBOL vmlinux 0xf2997713 tty_termios_hw_change +EXPORT_SYMBOL vmlinux 0xf2a6d2bf xfrm_policy_count +EXPORT_SYMBOL vmlinux 0xf2afa595 param_get_charp +EXPORT_SYMBOL vmlinux 0xf2b4b9be vfs_dq_quota_on_remount +EXPORT_SYMBOL vmlinux 0xf2c9786e put_filp +EXPORT_SYMBOL vmlinux 0xf3045cde unregister_exec_domain +EXPORT_SYMBOL vmlinux 0xf313da4e sha_transform +EXPORT_SYMBOL vmlinux 0xf3341268 __clear_user +EXPORT_SYMBOL vmlinux 0xf335e5f8 netif_rx +EXPORT_SYMBOL vmlinux 0xf338d4c3 netlink_unregister_notifier +EXPORT_SYMBOL vmlinux 0xf34236da pci_disable_device +EXPORT_SYMBOL vmlinux 0xf34242f8 tty_insert_flip_string_flags +EXPORT_SYMBOL vmlinux 0xf3431eb9 vfs_quota_on +EXPORT_SYMBOL vmlinux 0xf346231f seq_list_start_head +EXPORT_SYMBOL vmlinux 0xf35e7ab3 bd_release +EXPORT_SYMBOL vmlinux 0xf3652ceb set_blocksize +EXPORT_SYMBOL vmlinux 0xf373278b dquot_commit +EXPORT_SYMBOL vmlinux 0xf3b30b6d locks_remove_posix +EXPORT_SYMBOL vmlinux 0xf3bf0bce __bitmap_complement +EXPORT_SYMBOL vmlinux 0xf3ecd8e7 xfrm_state_add +EXPORT_SYMBOL vmlinux 0xf40545ff d_instantiate +EXPORT_SYMBOL vmlinux 0xf4236e3b agp_put_bridge +EXPORT_SYMBOL vmlinux 0xf42ae8c8 ilookup5_nowait +EXPORT_SYMBOL vmlinux 0xf441ac43 ioread8_rep +EXPORT_SYMBOL vmlinux 0xf47d47e0 acpi_enable_gpe +EXPORT_SYMBOL vmlinux 0xf49bc67a atm_pcr_goal +EXPORT_SYMBOL vmlinux 0xf4a5c213 avail_to_resrv_perfctr_nmi_bit +EXPORT_SYMBOL vmlinux 0xf4f14de6 rtnl_trylock +EXPORT_SYMBOL vmlinux 0xf4f28009 iget5_locked +EXPORT_SYMBOL vmlinux 0xf4f52f93 dqstats +EXPORT_SYMBOL vmlinux 0xf4f8cddd ps2_handle_response +EXPORT_SYMBOL vmlinux 0xf50f4340 alloc_trdev +EXPORT_SYMBOL vmlinux 0xf5120315 ip_setsockopt +EXPORT_SYMBOL vmlinux 0xf5143170 ip_route_me_harder +EXPORT_SYMBOL vmlinux 0xf51ae235 touch_nmi_watchdog +EXPORT_SYMBOL vmlinux 0xf528dfde sock_recvmsg +EXPORT_SYMBOL vmlinux 0xf53d4c26 qdisc_class_hash_destroy +EXPORT_SYMBOL vmlinux 0xf58f4c88 __nla_put +EXPORT_SYMBOL vmlinux 0xf5a73bf9 pci_enable_msi +EXPORT_SYMBOL vmlinux 0xf5ce9811 tcp_memory_allocated +EXPORT_SYMBOL vmlinux 0xf5f0b7cd pci_set_dma_max_seg_size +EXPORT_SYMBOL vmlinux 0xf5f38475 thermal_zone_device_unregister +EXPORT_SYMBOL vmlinux 0xf61f6666 dmam_pool_destroy +EXPORT_SYMBOL vmlinux 0xf63b2fe7 backlight_device_unregister +EXPORT_SYMBOL vmlinux 0xf63e1c82 tcp_getsockopt +EXPORT_SYMBOL vmlinux 0xf666cbb3 __memcpy_fromio +EXPORT_SYMBOL vmlinux 0xf676f27c pci_find_bus +EXPORT_SYMBOL vmlinux 0xf6b7689b find_or_create_page +EXPORT_SYMBOL vmlinux 0xf6bb4729 color_table +EXPORT_SYMBOL vmlinux 0xf6cdb69b key_revoke +EXPORT_SYMBOL vmlinux 0xf6ebc03b net_ratelimit +EXPORT_SYMBOL vmlinux 0xf708c0a3 aio_complete +EXPORT_SYMBOL vmlinux 0xf7439a94 skb_gso_segment +EXPORT_SYMBOL vmlinux 0xf749534a gen_pool_free +EXPORT_SYMBOL vmlinux 0xf7665d17 dev_load +EXPORT_SYMBOL vmlinux 0xf76b5983 sock_common_recvmsg +EXPORT_SYMBOL vmlinux 0xf78a07a6 tcp_splice_read +EXPORT_SYMBOL vmlinux 0xf78d04ab netlink_register_notifier +EXPORT_SYMBOL vmlinux 0xf791ca2c tty_unregister_driver +EXPORT_SYMBOL vmlinux 0xf7c7ad11 deactivate_super +EXPORT_SYMBOL vmlinux 0xf7caa6ed inet_dgram_connect +EXPORT_SYMBOL vmlinux 0xf7d17bb9 bio_map_kern +EXPORT_SYMBOL vmlinux 0xf7dfff37 tcp_sendmsg +EXPORT_SYMBOL vmlinux 0xf80d9017 dma_free_coherent +EXPORT_SYMBOL vmlinux 0xf81512da locks_mandatory_area +EXPORT_SYMBOL vmlinux 0xf82786f0 sget +EXPORT_SYMBOL vmlinux 0xf82abc1d isa_dma_bridge_buggy +EXPORT_SYMBOL vmlinux 0xf82e3d47 acpi_initialize_objects +EXPORT_SYMBOL vmlinux 0xf82f1109 utf8_wctomb +EXPORT_SYMBOL vmlinux 0xf8814f73 rb_last +EXPORT_SYMBOL vmlinux 0xf88e0ee2 acpi_get_table_header +EXPORT_SYMBOL vmlinux 0xf88f5be6 security_d_instantiate +EXPORT_SYMBOL vmlinux 0xf890fe7f pm_idle +EXPORT_SYMBOL vmlinux 0xf89843f9 schedule_work +EXPORT_SYMBOL vmlinux 0xf8aa47ae mutex_lock_killable +EXPORT_SYMBOL vmlinux 0xf8b30e93 mempool_create +EXPORT_SYMBOL vmlinux 0xf8cf9ee5 abort_exclusive_wait +EXPORT_SYMBOL vmlinux 0xf8cfff29 tty_get_baud_rate +EXPORT_SYMBOL vmlinux 0xf8d42c80 set_trace_device +EXPORT_SYMBOL vmlinux 0xf8e126c9 blk_execute_rq +EXPORT_SYMBOL vmlinux 0xf8eecb79 __nla_reserve +EXPORT_SYMBOL vmlinux 0xf9163729 xfrm_policy_destroy +EXPORT_SYMBOL vmlinux 0xf943f0de seq_escape +EXPORT_SYMBOL vmlinux 0xf97a76a6 pv_cpu_ops +EXPORT_SYMBOL vmlinux 0xf9a482f9 msleep +EXPORT_SYMBOL vmlinux 0xf9fbc29a put_tty_driver +EXPORT_SYMBOL vmlinux 0xfa0564fc __wait_on_bit_lock +EXPORT_SYMBOL vmlinux 0xfa19c69e pci_scan_bus_parented +EXPORT_SYMBOL vmlinux 0xfa5283cb input_unregister_handler +EXPORT_SYMBOL vmlinux 0xfa6ee97a pci_get_class +EXPORT_SYMBOL vmlinux 0xfa842fdc down_write +EXPORT_SYMBOL vmlinux 0xfa935760 __sk_mem_schedule +EXPORT_SYMBOL vmlinux 0xfaaee3ce tty_register_driver +EXPORT_SYMBOL vmlinux 0xfab96681 load_nls_default +EXPORT_SYMBOL vmlinux 0xfae600b6 is_container_init +EXPORT_SYMBOL vmlinux 0xfaf98462 bitrev32 +EXPORT_SYMBOL vmlinux 0xfb0443fb acpi_get_parent +EXPORT_SYMBOL vmlinux 0xfb0cf2e9 touch_all_softlockup_watchdogs +EXPORT_SYMBOL vmlinux 0xfb6af58d recalc_sigpending +EXPORT_SYMBOL vmlinux 0xfba0c2e0 llc_sap_list_lock +EXPORT_SYMBOL vmlinux 0xfbb469ed acpi_unlock_battery_dir +EXPORT_SYMBOL vmlinux 0xfbbad7ad vfs_writev +EXPORT_SYMBOL vmlinux 0xfbdec3ba sk_receive_skb +EXPORT_SYMBOL vmlinux 0xfbed20d8 ioremap_nocache +EXPORT_SYMBOL vmlinux 0xfbf5c747 framebuffer_release +EXPORT_SYMBOL vmlinux 0xfbf92453 param_get_bool +EXPORT_SYMBOL vmlinux 0xfc02b7ad sysctl_tcp_wmem +EXPORT_SYMBOL vmlinux 0xfc1106ae alloc_hippi_dev +EXPORT_SYMBOL vmlinux 0xfc383907 pcim_iounmap +EXPORT_SYMBOL vmlinux 0xfc39e32f ioport_unmap +EXPORT_SYMBOL vmlinux 0xfc52c08c pcie_get_readrq +EXPORT_SYMBOL vmlinux 0xfc8b429c devm_ioport_unmap +EXPORT_SYMBOL vmlinux 0xfc8f9de2 path_get +EXPORT_SYMBOL vmlinux 0xfc94e4e8 dquot_alloc_inode +EXPORT_SYMBOL vmlinux 0xfc959bbc __lookup_hash +EXPORT_SYMBOL vmlinux 0xfcaa04a0 out_of_line_wait_on_bit_lock +EXPORT_SYMBOL vmlinux 0xfcb5e850 xfrm_state_check_expire +EXPORT_SYMBOL vmlinux 0xfcb97d2f pnp_device_attach +EXPORT_SYMBOL vmlinux 0xfcdd8cf6 param_get_ushort +EXPORT_SYMBOL vmlinux 0xfcec0987 enable_irq +EXPORT_SYMBOL vmlinux 0xfcfa03ff fb_videomode_to_modelist +EXPORT_SYMBOL vmlinux 0xfd12c14a call_usermodehelper_setcleanup +EXPORT_SYMBOL vmlinux 0xfd1c92a8 per_cpu____irq_regs +EXPORT_SYMBOL vmlinux 0xfd1ee432 pci_find_slot +EXPORT_SYMBOL vmlinux 0xfd98879a rb_next +EXPORT_SYMBOL vmlinux 0xfd99bf71 in_dev_finish_destroy +EXPORT_SYMBOL vmlinux 0xfdb9b629 ioread32be +EXPORT_SYMBOL vmlinux 0xfde2145a boot_tvec_bases +EXPORT_SYMBOL vmlinux 0xfdf2d800 pci_pme_active +EXPORT_SYMBOL vmlinux 0xfe047ce6 acpi_enter_sleep_state +EXPORT_SYMBOL vmlinux 0xfe0f5e62 request_key +EXPORT_SYMBOL vmlinux 0xfe144965 search_binary_handler +EXPORT_SYMBOL vmlinux 0xfe26fc7c nr_node_ids +EXPORT_SYMBOL vmlinux 0xfe3543fb block_sync_page +EXPORT_SYMBOL vmlinux 0xfe392bcd generic_segment_checks +EXPORT_SYMBOL vmlinux 0xfe4bf321 simple_prepare_write +EXPORT_SYMBOL vmlinux 0xfe5d4bb2 sys_tz +EXPORT_SYMBOL vmlinux 0xfe769456 unregister_netdevice_notifier +EXPORT_SYMBOL vmlinux 0xfe7c4287 nr_cpu_ids +EXPORT_SYMBOL vmlinux 0xfea24a29 blk_integrity_compare +EXPORT_SYMBOL vmlinux 0xfec3c2f2 bcd2bin +EXPORT_SYMBOL vmlinux 0xfedd35fc console_suspend_enabled +EXPORT_SYMBOL vmlinux 0xff1e9dd8 seq_list_start +EXPORT_SYMBOL vmlinux 0xff1f2cf8 vfs_mkdir +EXPORT_SYMBOL vmlinux 0xff6878cf fb_default_cmap +EXPORT_SYMBOL vmlinux 0xff708fd3 mempool_destroy +EXPORT_SYMBOL vmlinux 0xff9ca065 fb_edid_to_monspecs +EXPORT_SYMBOL vmlinux 0xffafdc5c _read_unlock_irq +EXPORT_SYMBOL vmlinux 0xffd563f2 netdev_state_change +EXPORT_SYMBOL vmlinux 0xffd5a395 default_wake_function +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x00aaf935 kvm_disable_tdp +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x02f5beff kvm_release_page_clean +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x03024463 kvm_read_guest_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x063882d2 emulate_instruction +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x07b248b1 kvm_set_memory_region +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x094ac8f4 kvm_get_pfn +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x0b644f75 kvm_get_cs_db_l_bits +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x0d2a52b7 kvm_emulate_halt +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x0e0f57b7 kvm_lmsw +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x0fc5bd2d kvm_vcpu_init +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x12d1b23b kvm_release_pfn_clean +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x16b0f339 kvm_set_cr3 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x1cb40c6a kvm_init +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x1e4580bb kvm_release_pfn_dirty +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x2322e039 kvm_set_pfn_accessed +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x258ba34e kvm_load_guest_fpu +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x25a64765 kvm_lapic_set_tpr +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x27046576 kvm_exit +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x2860368e kvm_task_switch +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x28982f9e load_pdptrs +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x317f9e6b kvm_enable_efer_bits +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x3259bae0 emulator_write_emulated +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x32770619 kvm_put_guest_fpu +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x3c18bdce kvm_mmu_unprotect_page_virt +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x41e427f1 kvm_resched +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x480f7919 kvm_mmu_page_fault +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x4a7cbe69 is_error_pfn +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x51700a43 kvm_set_page_dirty +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x543ca756 kvm_read_guest +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x54db764b kvm_mmu_load +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x551c950e kvm_vcpu_uninit +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x56df6293 kvm_timer_intr_post +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x58553d8c is_error_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x5a5264b0 kvm_emulate_pio +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x5cbf8c7a gfn_to_hva +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x60affbca kvm_set_cr0 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x61ab18b1 kvm_set_cr4 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x6263cc8d emulator_read_std +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x62a63d3c kvm_set_cr8 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x69a08865 kvm_cpu_get_interrupt +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x6a711094 kvm_clear_guest +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x6cdf6b6e kvm_set_apic_base +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8010d66e kvm_lapic_get_base +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x80fae6d5 gfn_to_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8be69d74 kvm_clear_guest_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8c6b4891 kvm_create_lapic +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8ce4f3ab kvm_enable_tdp +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8e7f9b47 segment_base +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0x8fb12e44 kvm_lapic_reset +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xa361bc65 kvm_set_pfn_dirty +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xb130cd02 kvm_get_kvm +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xb296a7ec kvm_inject_nmi +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xba5a40d1 kvm_get_msr_common +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbcd62c8c kvm_put_kvm +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbcec10aa kvm_cpu_has_interrupt +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbd377dc9 kvm_mmu_set_nonpresent_ptes +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbd86163a kvm_handle_fault_on_reboot +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xbd94103b kvm_mmu_set_base_ptes +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xc04e7e70 kvm_lapic_find_highest_irr +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xc11fb845 kvm_lapic_enabled +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xc20bbcdf kvm_is_visible_gfn +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xc4f2a713 kvm_set_msr_common +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xc8cb24fb gfn_to_pfn +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xcd231ca7 fx_init +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xcea10f4a kvm_get_apic_base +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd0b2727a kvm_mmu_set_mask_ptes +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd291c548 kvm_queue_exception +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd296def9 kvm_is_error_hva +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd2f1fa51 kvm_emulate_hypercall +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd632aa8e kvm_queue_exception_e +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xd893b928 kvm_inject_pending_timer_irqs +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xdbb79092 kvm_emulate_pio_string +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xdc7e4739 kvm_get_cr8 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xddf46322 kvm_write_guest_page +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xdf095746 kvm_report_emulation_failure +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xea089346 kvm_lapic_get_cr8 +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xed4f60fb kvm_release_page_dirty +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xee72f347 kvm_mmu_reset_context +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xf0b1ff70 __kvm_set_memory_region +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xf2ae219d kvm_vcpu_cache +EXPORT_SYMBOL_GPL arch/x86/kvm/kvm 0xfa5d1b13 kvm_emulate_cpuid +EXPORT_SYMBOL_GPL crypto/aead 0x4349aca8 aead_geniv_exit +EXPORT_SYMBOL_GPL crypto/aead 0x4b91e559 aead_geniv_alloc +EXPORT_SYMBOL_GPL crypto/aead 0x6a1abce3 crypto_nivaead_type +EXPORT_SYMBOL_GPL crypto/aead 0x77417b3d crypto_aead_setauthsize +EXPORT_SYMBOL_GPL crypto/aead 0x9a69805e crypto_alloc_aead +EXPORT_SYMBOL_GPL crypto/aead 0x9d23fc1a aead_geniv_free +EXPORT_SYMBOL_GPL crypto/aead 0xced86b9a aead_geniv_init +EXPORT_SYMBOL_GPL crypto/aead 0xe09cb8f7 crypto_grab_aead +EXPORT_SYMBOL_GPL crypto/aead 0xe6839bae crypto_aead_type +EXPORT_SYMBOL_GPL crypto/aes_generic 0x1381bf2d crypto_ft_tab +EXPORT_SYMBOL_GPL crypto/aes_generic 0x22894d94 crypto_il_tab +EXPORT_SYMBOL_GPL crypto/aes_generic 0x465dc396 crypto_aes_set_key +EXPORT_SYMBOL_GPL crypto/aes_generic 0x5f943003 crypto_it_tab +EXPORT_SYMBOL_GPL crypto/aes_generic 0x5fe743de crypto_aes_expand_key +EXPORT_SYMBOL_GPL crypto/aes_generic 0x6e9cc2ba crypto_fl_tab +EXPORT_SYMBOL_GPL crypto/async_tx/async_memcpy 0x8e73562f async_memcpy +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0x46c982af __async_tx_find_channel +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0x6093049c async_tx_quiesce +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0x6b4a6db2 async_tx_issue_pending_all +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0xa1f43ed1 dma_wait_for_async_tx +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0xaf83023a async_tx_run_dependencies +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0xde7b5108 async_tx_submit +EXPORT_SYMBOL_GPL crypto/async_tx/async_tx 0xfec58724 async_trigger_callback +EXPORT_SYMBOL_GPL crypto/async_tx/async_xor 0xe1b70046 async_xor +EXPORT_SYMBOL_GPL crypto/async_tx/async_xor 0xf4136bf0 async_xor_zero_sum +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x01410703 blkcipher_walk_virt +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x0787fb98 crypto_ablkcipher_type +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x0a206bca blkcipher_walk_virt_block +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x0ebc9dbc skcipher_geniv_free +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x1c35cb76 crypto_alloc_ablkcipher +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x2bbc05cc skcipher_geniv_exit +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x54ccea79 skcipher_geniv_init +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x713e14b2 blkcipher_walk_phys +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0x9227a3a7 crypto_blkcipher_type +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0xacc49a94 skcipher_geniv_alloc +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0xc0a800fd crypto_grab_skcipher +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0xd088ccd5 blkcipher_walk_done +EXPORT_SYMBOL_GPL crypto/crypto_blkcipher 0xd628b5e5 crypto_givcipher_type +EXPORT_SYMBOL_GPL crypto/des_generic 0xcfd9a2c0 des_ekey +EXPORT_SYMBOL_GPL crypto/twofish_common 0x97065ba1 twofish_setkey +EXPORT_SYMBOL_GPL drivers/acpi/dock 0x100c48a2 unregister_dock_notifier +EXPORT_SYMBOL_GPL drivers/acpi/dock 0x2611fbee register_hotplug_dock_device +EXPORT_SYMBOL_GPL drivers/acpi/dock 0x318920b1 register_dock_notifier +EXPORT_SYMBOL_GPL drivers/acpi/dock 0xbd506a46 unregister_hotplug_dock_device +EXPORT_SYMBOL_GPL drivers/acpi/dock 0xcc6ab305 is_dock_device +EXPORT_SYMBOL_GPL drivers/acpi/sbshc 0x0ad5c33f acpi_smbus_register_callback +EXPORT_SYMBOL_GPL drivers/acpi/sbshc 0x158c2ad0 acpi_smbus_unregister_callback +EXPORT_SYMBOL_GPL drivers/acpi/sbshc 0x526b867a acpi_smbus_read +EXPORT_SYMBOL_GPL drivers/acpi/sbshc 0xb3d5e527 acpi_smbus_write +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0x3ecf6cfc wmi_install_notify_handler +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0x561c634a wmi_evaluate_method +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0x876d29f1 wmi_get_event_data +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0xb5a6ebe2 wmi_remove_notify_handler +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0xc9d4d6d1 wmi_has_guid +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0xda29f8b0 wmi_set_block +EXPORT_SYMBOL_GPL drivers/acpi/wmi 0xfb882fb7 wmi_query_block +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0067df75 ata_tf_from_fis +EXPORT_SYMBOL_GPL drivers/ata/libata 0x00ebcb5d ata_id_string +EXPORT_SYMBOL_GPL drivers/ata/libata 0x011ef430 ata_acpi_stm +EXPORT_SYMBOL_GPL drivers/ata/libata 0x01973548 sata_scr_read +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0305fee1 ata_eh_thaw_port +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0307dd01 ata_sff_data_xfer +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0313ef6a ata_sff_host_intr +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0354bfd7 ata_acpi_gtm +EXPORT_SYMBOL_GPL drivers/ata/libata 0x03e3686c ata_timing_cycle2mode +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0531dcb8 ata_dev_classify +EXPORT_SYMBOL_GPL drivers/ata/libata 0x08068987 ata_port_abort +EXPORT_SYMBOL_GPL drivers/ata/libata 0x087a8d5d ata_scsi_queuecmd +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0961bd88 ata_sff_dma_pause +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0a3b59b3 sata_pmp_error_handler +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0b0b6a20 ata_port_freeze +EXPORT_SYMBOL_GPL drivers/ata/libata 0x0ed51578 ata_sff_port_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0x116a9a26 ata_bus_reset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x12188e2a ata_dev_disable +EXPORT_SYMBOL_GPL drivers/ata/libata 0x17337e16 ata_host_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0x17f0bb9d sata_set_spd +EXPORT_SYMBOL_GPL drivers/ata/libata 0x1aebf2c7 ata_bmdma_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0x1ba12c30 ata_pci_device_do_resume +EXPORT_SYMBOL_GPL drivers/ata/libata 0x26995bd7 ata_sg_init +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2a2b63df ata_link_abort +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2a9e5c44 sata_link_debounce +EXPORT_SYMBOL_GPL drivers/ata/libata 0x2d09a4e1 ata_sff_postreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x35e5fa4d ata_host_resume +EXPORT_SYMBOL_GPL drivers/ata/libata 0x39962572 sata_link_resume +EXPORT_SYMBOL_GPL drivers/ata/libata 0x3b047baf ata_sff_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x3b58e833 ata_pci_bmdma_clear_simplex +EXPORT_SYMBOL_GPL drivers/ata/libata 0x3bedc4f6 ata_port_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0x3e9a3e67 ata_sff_exec_command +EXPORT_SYMBOL_GPL drivers/ata/libata 0x40370180 ata_bmdma_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x40af0dec ata_xfer_mode2mask +EXPORT_SYMBOL_GPL drivers/ata/libata 0x42cc525a ata_do_dev_read_id +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4340b201 ata_cable_80wire +EXPORT_SYMBOL_GPL drivers/ata/libata 0x43f56e82 ata_xfer_mode2shift +EXPORT_SYMBOL_GPL drivers/ata/libata 0x456d3236 ata_sff_irq_on +EXPORT_SYMBOL_GPL drivers/ata/libata 0x479f6fca ata_bmdma_status +EXPORT_SYMBOL_GPL drivers/ata/libata 0x48487e8a ata_sff_irq_clear +EXPORT_SYMBOL_GPL drivers/ata/libata 0x485c9bca ata_cable_40wire +EXPORT_SYMBOL_GPL drivers/ata/libata 0x48fa3b0f ata_host_register +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4af6c5b5 ata_sff_softreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4c1e047c ata_sff_dumb_qc_prep +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4c5bd8f8 ata_pci_sff_init_host +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4d472010 dev_attr_em_message +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4fb4573e ata_sff_tf_read +EXPORT_SYMBOL_GPL drivers/ata/libata 0x4fdc945d sata_deb_timing_normal +EXPORT_SYMBOL_GPL drivers/ata/libata 0x505308a9 ata_sff_data_xfer_noirq +EXPORT_SYMBOL_GPL drivers/ata/libata 0x53385ca5 sata_pmp_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x54a6c777 ata_qc_complete_multiple +EXPORT_SYMBOL_GPL drivers/ata/libata 0x55b07061 ata_dev_pair +EXPORT_SYMBOL_GPL drivers/ata/libata 0x565cf554 ata_sff_wait_ready +EXPORT_SYMBOL_GPL drivers/ata/libata 0x57a01a88 ata_base_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x58d9ba49 dev_attr_sw_activity +EXPORT_SYMBOL_GPL drivers/ata/libata 0x5e0de9f4 ata_host_init +EXPORT_SYMBOL_GPL drivers/ata/libata 0x5e644061 pci_test_config_bits +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6008bc3a ata_host_suspend +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6253cb98 ata_pci_device_do_suspend +EXPORT_SYMBOL_GPL drivers/ata/libata 0x63465ed1 ata_dummy_port_info +EXPORT_SYMBOL_GPL drivers/ata/libata 0x65382e96 ata_cable_sata +EXPORT_SYMBOL_GPL drivers/ata/libata 0x678fc2c4 ata_cable_unknown +EXPORT_SYMBOL_GPL drivers/ata/libata 0x697bfae9 sata_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x69d04571 ata_sff_qc_prep +EXPORT_SYMBOL_GPL drivers/ata/libata 0x69e9a2cb ata_scsi_slave_config +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6b0026b7 ata_sas_slave_configure +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6b24551c ata_pci_device_suspend +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6be44d3f ata_bmdma_mode_filter +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6c71ac01 ata_sff_tf_load +EXPORT_SYMBOL_GPL drivers/ata/libata 0x6e87847c __ata_ehi_push_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0x707ff1bb ata_xfer_mask2mode +EXPORT_SYMBOL_GPL drivers/ata/libata 0x73a48b4a ata_sff_std_ports +EXPORT_SYMBOL_GPL drivers/ata/libata 0x743a165e ata_pack_xfermask +EXPORT_SYMBOL_GPL drivers/ata/libata 0x74d0df6e ata_do_eh +EXPORT_SYMBOL_GPL drivers/ata/libata 0x76888917 ata_sff_thaw +EXPORT_SYMBOL_GPL drivers/ata/libata 0x795d982a sata_link_hardreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7b8b56b0 sata_scr_write +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7c003354 ata_link_online +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7c1512e6 ata_wait_after_reset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x7fc8140a ata_sas_queuecmd +EXPORT_SYMBOL_GPL drivers/ata/libata 0x806b8a72 sata_scr_valid +EXPORT_SYMBOL_GPL drivers/ata/libata 0x821660b2 ata_scsi_simulate +EXPORT_SYMBOL_GPL drivers/ata/libata 0x82753eb1 ata_host_alloc +EXPORT_SYMBOL_GPL drivers/ata/libata 0x863c4db0 ata_dummy_port_ops +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8b752ac1 ata_tf_to_fis +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8d5904c2 ata_eh_analyze_ncq_error +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8d721ca7 ata_sff_hsm_move +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8d874dcc ata_sff_busy_sleep +EXPORT_SYMBOL_GPL drivers/ata/libata 0x8e141dca sata_async_notification +EXPORT_SYMBOL_GPL drivers/ata/libata 0x92bc23c1 ata_host_alloc_pinfo +EXPORT_SYMBOL_GPL drivers/ata/libata 0x9374bbb1 ata_sas_port_init +EXPORT_SYMBOL_GPL drivers/ata/libata 0x93ec66b2 ata_port_pbar_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0x94723b31 ata_std_postreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x94a68723 ata_scsi_slave_destroy +EXPORT_SYMBOL_GPL drivers/ata/libata 0x94dc62d2 ata_scsi_ioctl +EXPORT_SYMBOL_GPL drivers/ata/libata 0x95cf5fc8 ata_sff_dev_classify +EXPORT_SYMBOL_GPL drivers/ata/libata 0x96bd7b68 ata_sff_wait_after_reset +EXPORT_SYMBOL_GPL drivers/ata/libata 0x9711dc34 ata_eh_qc_retry +EXPORT_SYMBOL_GPL drivers/ata/libata 0x98de957a ata_std_qc_defer +EXPORT_SYMBOL_GPL drivers/ata/libata 0x99061e99 ata_link_offline +EXPORT_SYMBOL_GPL drivers/ata/libata 0x991e0ffd ata_qc_complete +EXPORT_SYMBOL_GPL drivers/ata/libata 0x997ce746 ata_port_disable +EXPORT_SYMBOL_GPL drivers/ata/libata 0x99b54994 ata_std_error_handler +EXPORT_SYMBOL_GPL drivers/ata/libata 0xa1f6a4db dev_attr_em_message_type +EXPORT_SYMBOL_GPL drivers/ata/libata 0xa23b73fe ata_bmdma_stop +EXPORT_SYMBOL_GPL drivers/ata/libata 0xa5aa403e ata_host_activate +EXPORT_SYMBOL_GPL drivers/ata/libata 0xa7bd2b96 ata_pci_sff_init_one +EXPORT_SYMBOL_GPL drivers/ata/libata 0xab641028 ata_port_probe +EXPORT_SYMBOL_GPL drivers/ata/libata 0xac751708 ata_sff_check_status +EXPORT_SYMBOL_GPL drivers/ata/libata 0xacff8938 ata_timing_compute +EXPORT_SYMBOL_GPL drivers/ata/libata 0xb4bcbe38 ata_eh_qc_complete +EXPORT_SYMBOL_GPL drivers/ata/libata 0xb4eaefe9 ata_acpi_gtm_xfermask +EXPORT_SYMBOL_GPL drivers/ata/libata 0xb6aeb661 ata_id_c_string +EXPORT_SYMBOL_GPL drivers/ata/libata 0xb93b40af ata_sas_port_destroy +EXPORT_SYMBOL_GPL drivers/ata/libata 0xba45b767 ata_eh_freeze_port +EXPORT_SYMBOL_GPL drivers/ata/libata 0xbad6e1d9 ata_port_schedule_eh +EXPORT_SYMBOL_GPL drivers/ata/libata 0xbdc7441b ata_pci_remove_one +EXPORT_SYMBOL_GPL drivers/ata/libata 0xbe1887e4 ata_unpack_xfermask +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc06ff638 ata_cable_ignore +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc12abf59 ata_acpi_cbl_80wire +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc428068d sata_deb_timing_long +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc48b7ccf ata_mode_string +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc673e23e ata_scsi_change_queue_depth +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc7dd1c38 ata_sas_port_stop +EXPORT_SYMBOL_GPL drivers/ata/libata 0xc8a3eff5 ata_sas_port_alloc +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcaab1ea9 sata_pmp_qc_defer_cmd_switch +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcba82ad8 ata_sff_freeze +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcc6c1f53 ata_ehi_push_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0xccc50bf7 ata_sff_qc_issue +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcccfb2fa sata_deb_timing_hotplug +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcfb08673 ata_sff_prereset +EXPORT_SYMBOL_GPL drivers/ata/libata 0xcfd74d4c ata_std_bios_param +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd327d0c5 ata_bmdma_setup +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd65b9c99 ata_sff_qc_fill_rtf +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd6749301 sata_sff_hardreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd6c93ea8 ata_sff_pause +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd6fe8800 ata_sff_dev_select +EXPORT_SYMBOL_GPL drivers/ata/libata 0xd84cd7f4 ata_timing_find_mode +EXPORT_SYMBOL_GPL drivers/ata/libata 0xde8e9e43 ata_noop_qc_prep +EXPORT_SYMBOL_GPL drivers/ata/libata 0xdec397fb sata_std_hardreset +EXPORT_SYMBOL_GPL drivers/ata/libata 0xdf3022b2 ata_sff_interrupt +EXPORT_SYMBOL_GPL drivers/ata/libata 0xdf3c3b0e ata_sff_error_handler +EXPORT_SYMBOL_GPL drivers/ata/libata 0xe49ff3b0 ata_wait_register +EXPORT_SYMBOL_GPL drivers/ata/libata 0xe90c20ab ata_pci_bmdma_init +EXPORT_SYMBOL_GPL drivers/ata/libata 0xea418e0f atapi_cmd_type +EXPORT_SYMBOL_GPL drivers/ata/libata 0xea6c6ca2 ata_pci_device_resume +EXPORT_SYMBOL_GPL drivers/ata/libata 0xecfebf3b sata_scr_write_flush +EXPORT_SYMBOL_GPL drivers/ata/libata 0xee93726e ata_ehi_clear_desc +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf3b2b521 dev_attr_link_power_management_policy +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf3d5cc13 ata_timing_merge +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf4b3c1ac ata_pio_need_iordy +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf7d0b479 ata_pci_sff_activate_host +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf85e5c94 ata_std_prereset +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf8f3a0fb ata_ratelimit +EXPORT_SYMBOL_GPL drivers/ata/libata 0xf9ca3160 ata_id_xfermask +EXPORT_SYMBOL_GPL drivers/ata/libata 0xfb78f7b7 ata_sas_port_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0xfb95bef7 ata_sff_post_internal_cmd +EXPORT_SYMBOL_GPL drivers/ata/libata 0xfda093f8 ata_do_set_mode +EXPORT_SYMBOL_GPL drivers/ata/libata 0xfdac3214 ata_port_start +EXPORT_SYMBOL_GPL drivers/ata/libata 0xfe9eb576 ata_host_detach +EXPORT_SYMBOL_GPL drivers/ata/libata 0xff1eecac ata_pci_sff_prepare_host +EXPORT_SYMBOL_GPL drivers/ata/pata_sis 0x304d063b sis_info133_for_sata +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x02ff9464 cfag12864b_isinited +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x0ecb2e5d cfag12864b_disable +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x305dc3c6 cfag12864b_isenabled +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x3389f926 cfag12864b_enable +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0x9522a342 cfag12864b_getrate +EXPORT_SYMBOL_GPL drivers/auxdisplay/cfag12864b 0xc48e9d95 cfag12864b_buffer +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0x14102f23 ks0108_displaystate +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0x48a70518 ks0108_writedata +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0x4f506333 ks0108_startline +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0x6edae968 ks0108_isinited +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0xbf4774db ks0108_writecontrol +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0xedde6df2 ks0108_page +EXPORT_SYMBOL_GPL drivers/auxdisplay/ks0108 0xfee8ef7b ks0108_address +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x024ad1e1 tpm_gen_interrupt +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x1d10417d tpm_read +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x222ea86a tpm_show_caps +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x236f8e63 tpm_remove_hardware +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x2664a4cb tpm_show_pcrs +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x41dbca80 tpm_store_cancel +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x516c00a0 tpm_pm_suspend +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x540ebd33 tpm_calc_ordinal_duration +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x61a30e27 tpm_show_caps_1_2 +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x78850807 tpm_show_owned +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x7a9cb235 tpm_register_hardware +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x9ddd53f1 tpm_pm_resume +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0x9e5f3947 tpm_open +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xa103f875 tpm_show_active +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xa1b0b89e tpm_show_pubek +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xad0dde48 tpm_release +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xbed53e39 tpm_show_enabled +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xcab9d8f4 tpm_get_timeouts +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xd25fa700 tpm_show_temp_deactivated +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xd9ce073d tpm_continue_selftest +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm 0xff5e9eab tpm_write +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm_bios 0xbedb48ef tpm_bios_log_setup +EXPORT_SYMBOL_GPL drivers/char/tpm/tpm_bios 0xfb33319c tpm_bios_log_teardown +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x01b354b4 cpufreq_frequency_table_target +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x2f47d8c7 cpufreq_frequency_get_table +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x3361319f cpufreq_frequency_table_cpuinfo +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x706b3a33 cpufreq_frequency_table_get_attr +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x7ae1ae8e cpufreq_frequency_table_put_attr +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0x7bc780a5 cpufreq_frequency_table_verify +EXPORT_SYMBOL_GPL drivers/cpufreq/freq_table 0xa861f3b5 cpufreq_freq_attr_scaling_available_freqs +EXPORT_SYMBOL_GPL drivers/dca/dca 0x05b3551e unregister_dca_provider +EXPORT_SYMBOL_GPL drivers/dca/dca 0x2cd03ed5 register_dca_provider +EXPORT_SYMBOL_GPL drivers/dca/dca 0x2e471f01 dca_register_notify +EXPORT_SYMBOL_GPL drivers/dca/dca 0x31a2c8df dca_get_tag +EXPORT_SYMBOL_GPL drivers/dca/dca 0x4324d628 dca3_get_tag +EXPORT_SYMBOL_GPL drivers/dca/dca 0x48ac0971 dca_add_requester +EXPORT_SYMBOL_GPL drivers/dca/dca 0x652621dc dca_remove_requester +EXPORT_SYMBOL_GPL drivers/dca/dca 0x8006c614 dca_unregister_notify +EXPORT_SYMBOL_GPL drivers/dca/dca 0xc58266af alloc_dca_provider +EXPORT_SYMBOL_GPL drivers/dca/dca 0xda71046d free_dca_provider +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x0211c6c4 edac_device_handle_ce +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x029073b9 edac_mc_del_mc +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x04ac8ef6 edac_mc_handle_ce +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x0b717549 edac_pci_add_device +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x20855591 edac_pci_reset_delay_period +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x247407cd edac_mc_handle_ue_no_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x2700b0b5 edac_device_del_device +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x2ed57370 edac_mc_find_csrow_by_page +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x4012f69c edac_mc_add_mc +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x4169a4a8 edac_pci_del_device +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x6aaff303 edac_pci_handle_pe +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x77e2a1ee edac_pci_free_ctl_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0x8e6064b6 edac_device_free_ctl_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xa1f3248e edac_device_add_device +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xa225e666 edac_pci_release_generic_ctl +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xa35a8855 edac_mc_alloc +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xa96e048d edac_mc_handle_ue +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xbfd242cb edac_pci_create_generic_ctl +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xc72e08bf edac_device_handle_ue +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xc873c147 edac_mc_handle_ce_no_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xcd62b43a edac_mc_free +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xd7165fb2 edac_pci_handle_npe +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xe40115ea edac_device_alloc_ctl_info +EXPORT_SYMBOL_GPL drivers/edac/edac_core 0xe651ceba edac_pci_alloc_ctl_info +EXPORT_SYMBOL_GPL drivers/hid/hid 0x2b368f3c hidinput_connect +EXPORT_SYMBOL_GPL drivers/hid/hid 0x2f05ae23 hid_free_device +EXPORT_SYMBOL_GPL drivers/hid/hid 0x33486e06 hidinput_report_event +EXPORT_SYMBOL_GPL drivers/hid/hid 0x37acefd2 hidinput_disconnect +EXPORT_SYMBOL_GPL drivers/hid/hid 0x3baf0797 hid_output_report +EXPORT_SYMBOL_GPL drivers/hid/hid 0x4ed56b91 hidraw_report_event +EXPORT_SYMBOL_GPL drivers/hid/hid 0x556844c8 hidraw_disconnect +EXPORT_SYMBOL_GPL drivers/hid/hid 0x63c366d8 hid_input_report +EXPORT_SYMBOL_GPL drivers/hid/hid 0x98d1847c hidraw_connect +EXPORT_SYMBOL_GPL drivers/hid/hid 0xc29c9390 hid_set_field +EXPORT_SYMBOL_GPL drivers/hid/hid 0xe9b1cb71 hid_parse_report +EXPORT_SYMBOL_GPL drivers/hid/hid 0xfbdf75db hidinput_find_field +EXPORT_SYMBOL_GPL drivers/hid/usbhid/usbhid 0x01fd453e usbhid_lookup_quirk +EXPORT_SYMBOL_GPL drivers/hid/usbhid/usbhid 0x4e57751b hiddev_hid_event +EXPORT_SYMBOL_GPL drivers/i2c/busses/i2c-nforce2 0x68e4534f nforce2_smbus +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0x3a8ec298 i2c_new_device +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0x3fc26e45 i2c_unregister_device +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0x55cbe224 i2c_new_probed_device +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0x6bcc220c i2c_add_numbered_adapter +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0x9f55c9ab i2c_new_dummy +EXPORT_SYMBOL_GPL drivers/i2c/i2c-core 0xa55b9ad7 i2c_bus_type +EXPORT_SYMBOL_GPL drivers/ieee1394/ieee1394 0x08829f7c hpsb_config_rom_ip1394_add +EXPORT_SYMBOL_GPL drivers/ieee1394/ieee1394 0x79e9f1b3 hpsb_config_rom_ip1394_remove +EXPORT_SYMBOL_GPL drivers/ieee1394/ieee1394 0xec8d18cf hpsb_disable_irm +EXPORT_SYMBOL_GPL drivers/infiniband/hw/ipath/ib_ipath 0x1514b2b2 ipath_debug +EXPORT_SYMBOL_GPL drivers/input/ff-memless 0xc609debe input_ff_create_memless +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x1368b328 wm97xx_reg_write +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x1b2eca97 wm97xx_config_gpio +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x233d4fbb wm97xx_get_gpio +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x2863c918 wm97xx_register_mach_ops +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x2d77d280 wm9713_codec +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x3d8e92d4 wm97xx_set_suspend_mode +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0x73bd2ad7 wm97xx_reg_read +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xc73a95e4 wm97xx_unregister_mach_ops +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xcad15329 wm97xx_read_aux_adc +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xe1ddd21e wm9712_codec +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xec16e71d wm97xx_set_gpio +EXPORT_SYMBOL_GPL drivers/input/touchscreen/wm97xx-ts 0xfc63cf44 wm9705_codec +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x205d2222 gigaset_initcs +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x2c0979ce gigaset_dbg_buffer +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x32522fb6 gigaset_stop +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x454aa44f gigaset_debuglevel +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x491e3ff5 gigaset_m10x_send_skb +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x4cc52616 gigaset_freedriver +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x73785ae7 gigaset_handle_modem_response +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x7dabdf52 gigaset_initdriver +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x958ceda9 gigaset_fill_inbuf +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x9a558944 gigaset_blockdriver +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x9ab916c7 gigaset_m10x_input +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0x9b1b1ff4 gigaset_start +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0xa6ff5bf9 gigaset_skb_sent +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0xc0f41444 gigaset_if_receive +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0xdf14a9e7 gigaset_freecs +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0xe1813396 gigaset_add_event +EXPORT_SYMBOL_GPL drivers/isdn/gigaset/gigaset 0xfc8e8650 gigaset_shutdown +EXPORT_SYMBOL_GPL drivers/leds/led-class 0x3dbc6938 led_classdev_unregister +EXPORT_SYMBOL_GPL drivers/leds/led-class 0x606f5703 led_classdev_resume +EXPORT_SYMBOL_GPL drivers/leds/led-class 0x748348da led_classdev_suspend +EXPORT_SYMBOL_GPL drivers/leds/led-class 0x96910d35 led_classdev_register +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0x3c6370f3 dm_send_uevents +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0x4f7bb9d8 dm_path_uevent +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0x55694df2 dm_set_device_limits +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0xb668dbbc dm_put +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0xb692a533 dm_device_name +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0xdb0d3221 dm_disk +EXPORT_SYMBOL_GPL drivers/md/dm-mod 0xfca7d597 dm_noflush_suspending +EXPORT_SYMBOL_GPL drivers/md/dm-multipath 0xcf1c0ddf dm_unregister_path_selector +EXPORT_SYMBOL_GPL drivers/md/dm-multipath 0xfa6eec39 dm_register_path_selector +EXPORT_SYMBOL_GPL drivers/md/md-mod 0x87a8c3e7 sync_page_io +EXPORT_SYMBOL_GPL drivers/md/md-mod 0x9cf27e45 md_allow_write +EXPORT_SYMBOL_GPL drivers/md/md-mod 0xda0a124e md_do_sync +EXPORT_SYMBOL_GPL drivers/md/md-mod 0xf5686100 md_new_event +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x04662e0f ir_codes_fusionhdtv_mce +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x07e92917 ir_codes_avermedia_a16d +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x083661f9 ir_codes_avertv_303 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x088631b9 ir_codes_behold +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x1cb148f5 ir_extract_bits +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x2456e513 ir_decode_pulsedistance +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x24e377fe ir_input_init +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x2a4852cc ir_codes_dntv_live_dvb_t +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x2af1a608 ir_codes_proteus_2309 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x3811daea ir_codes_manli +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x43c89ef4 ir_decode_biphase +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x45b08f68 ir_codes_pinnacle_grey +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x4740e7a3 ir_codes_empty +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x4ea698a2 ir_codes_purpletv +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x55338dda ir_codes_pixelview_new +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x589cad50 ir_codes_apac_viewcomp +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x5db13554 ir_codes_encore_enltv +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6606596a ir_rc5_timer_keyup +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6adc476d ir_codes_powercolor_real_angel +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6aefdbea ir_codes_npgtech +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6b87c69d ir_codes_iodata_bctv7e +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6d6511e7 ir_dump_samples +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x6e2a1870 ir_codes_adstech_dvb_t_pci +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x7277973d ir_codes_pctv_sedna +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x75e89cc3 ir_codes_flydvb +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x772a30a2 ir_codes_nebula +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x85d37490 ir_codes_dntv_live_dvbt_pro +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x89cc1189 ir_codes_winfast +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x902a3cd2 ir_codes_hauppauge_new +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x933d0bb3 ir_codes_msi_tvanywhere +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x9451e232 ir_codes_behold_columbus +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0x96470cab ir_codes_cinergy +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xaf13fcc6 ir_input_keydown +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xb1f4eb35 ir_codes_avermedia_dvbt +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xb6cd4666 ir_codes_eztv +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xbb08d146 ir_codes_msi_tvanywhere_plus +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xbdce6594 ir_codes_tt_1500 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xc1fea0c1 ir_codes_pv951 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xc42bd037 ir_codes_budget_ci_old +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xc6c5a7a1 ir_codes_em_terratec +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xc78b14a1 ir_input_nokey +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xd1e0258a ir_codes_flyvideo +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xd55e6891 ir_codes_gotview7135 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xd9c7f010 ir_codes_rc5_tv +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xdaa041ad ir_codes_cinergy_1400 +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xdfcf23df ir_codes_norwood +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xee2f5e0e ir_codes_pinnacle_pctv_hd +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xf07533a1 ir_codes_videomate_tv_pvr +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xf0fc9374 ir_codes_avermedia +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xf2b421aa ir_codes_genius_tvgo_a11mce +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xf4f7a4d6 ir_rc5_timer_end +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xfa177653 ir_codes_pixelview +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xfb981300 ir_codes_pinnacle_color +EXPORT_SYMBOL_GPL drivers/media/common/ir-common 0xfc54a5cd ir_codes_asus_pc39 +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x068e1889 saa7146_vmalloc_build_pgtable +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x2faf04d1 saa7146_setgpio +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x4fadb1a7 saa7146_pgtable_build_single +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x632146c4 saa7146_unregister_extension +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x63ceb9bc saa7146_wait_for_debi_done +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0x6fe17b76 saa7146_register_extension +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xb06a5ed9 saa7146_vfree_destroy_pgtable +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xb9c9c1b8 saa7146_pgtable_alloc +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xc492699f saa7146_pgtable_free +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xc98faf20 saa7146_devices_lock +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xcf683cf2 saa7146_devices +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xe3cd9b5c saa7146_debug +EXPORT_SYMBOL_GPL drivers/media/common/saa7146 0xeee0e0a8 saa7146_i2c_adapter_prepare +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0x17f322ae saa7146_stop_preview +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0x19e196af saa7146_vv_release +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0x6ef11cf2 saa7146_start_preview +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0xad80744a saa7146_unregister_device +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0xebe801c4 saa7146_register_device +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0xedc5af33 saa7146_set_hps_source_and_sync +EXPORT_SYMBOL_GPL drivers/media/common/saa7146_vv 0xf6510ecc saa7146_vv_init +EXPORT_SYMBOL_GPL drivers/media/common/tuners/mt20xx 0xe3dd8aa9 microtune_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/mxl5007t 0xe6481d8d mxl5007t_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda18271 0xaae45236 tda18271_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda827x 0x6b3c58f1 tda827x_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda8290 0x30770c39 tda829x_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda8290 0x789dde6b tda829x_probe +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tda9887 0x05e3a63f tda9887_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tea5761 0x5b4cae5a tea5761_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tea5761 0xd69cd675 tea5761_autodetection +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tea5767 0x1168221c tea5767_attach +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tea5767 0x5f216f77 tea5767_autodetection +EXPORT_SYMBOL_GPL drivers/media/common/tuners/tuner-simple 0x37b331e5 simple_tuner_attach +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x0d53fad0 ttpci_budget_set_video_port +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x25582062 ttpci_budget_deinit +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x400e1c98 ttpci_budget_irq10_handler +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x618745aa ttpci_budget_init_hooks +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x74f51b31 ttpci_budget_debiwrite +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x7948c222 budget_debug +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0x890031ac ttpci_budget_debiread +EXPORT_SYMBOL_GPL drivers/media/dvb/ttpci/budget-core 0xa9fad84e ttpci_budget_init +EXPORT_SYMBOL_GPL drivers/media/video/compat_ioctl32 0xe316f053 v4l_compat_ioctl32 +EXPORT_SYMBOL_GPL drivers/media/video/cx88/cx88xx 0xf951856b cx88_setup_xc3028 +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0x098e7072 em28xx_audio_analog_set +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0x8295897f em28xx_uninit_isoc +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0xd22c24eb em28xx_tuner_callback +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0xd3e55506 em28xx_init_isoc +EXPORT_SYMBOL_GPL drivers/media/video/em28xx/em28xx 0xd44fe1bf em28xx_set_mode +EXPORT_SYMBOL_GPL drivers/media/video/saa7134/saa7134 0x012f6f7d saa7134_g_ctrl_internal +EXPORT_SYMBOL_GPL drivers/media/video/saa7134/saa7134 0x52ba89c3 saa7134_queryctrl +EXPORT_SYMBOL_GPL drivers/media/video/saa7134/saa7134 0x5cd16c3c saa7134_ts_qops +EXPORT_SYMBOL_GPL drivers/media/video/saa7134/saa7134 0xde2faa55 saa7134_s_ctrl_internal +EXPORT_SYMBOL_GPL drivers/media/video/v4l2-int-device 0x297e992a v4l2_int_device_unregister +EXPORT_SYMBOL_GPL drivers/media/video/v4l2-int-device 0xd14620db v4l2_int_device_register +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x0147f284 videobuf_streamoff +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x01d93f07 videobuf_streamon +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x048943e3 videobuf_dqbuf +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x0a36a8eb videobuf_waiton +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x0ec912c4 videobuf_mmap_setup +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x47a6070d videobuf_querybuf +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x48bdf8f4 videobuf_read_stop +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x4d0d87ca videobuf_next_field +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x6394f1c4 videobuf_read_stream +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x6dac653f videobuf_poll_stream +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x757351a9 videobuf_queue_core_init +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x78b1bfbf videobuf_cgmbuf +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x7acfeb44 videobuf_iolock +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x7e981702 videobuf_reqbufs +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x82d92a95 videobuf_stop +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x833ef841 videobuf_queue_cancel +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0x8870f8fd videobuf_read_one +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xb480814e videobuf_queue_to_vmalloc +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xb4ec507a videobuf_mmap_free +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xc25559fd videobuf_qbuf +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xc439d02d videobuf_queue_is_busy +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xce49e3be videobuf_alloc +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xd0f64433 __videobuf_mmap_setup +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xee15411e videobuf_mmap_mapper +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-core 0xf6661fe2 videobuf_read_start +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-contig 0x382a226c videobuf_dma_contig_free +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-contig 0x9f72cb47 videobuf_queue_dma_contig_init +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-contig 0xd85c1198 videobuf_to_dma_contig +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x0346f558 videobuf_sg_dma_unmap +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x0e097414 videobuf_queue_sg_init +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x1788d15b videobuf_dma_sync +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x25776fca videobuf_dma_unmap +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x48dbf1aa videobuf_dma_map +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x585f1480 videobuf_sg_dma_map +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x669b0dc6 videobuf_to_dma +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x6f09d8e2 videobuf_dma_init +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x8ab4c971 videobuf_dma_free +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x8edb5815 videobuf_dma_init_kernel +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0x933dfb43 videobuf_vmalloc_to_sg +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0xa38faed2 videobuf_sg_alloc +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0xc887f37e videobuf_dma_init_overlay +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-dma-sg 0xf782dcfa videobuf_dma_init_user +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-vmalloc 0x619868bd videobuf_vmalloc_free +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-vmalloc 0xcb49bf72 videobuf_queue_vmalloc_init +EXPORT_SYMBOL_GPL drivers/media/video/videobuf-vmalloc 0xe4b983da videobuf_to_vmalloc +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0x18d2ca57 sm501_unit_power +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0x7248c01b sm501_set_clock +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0xbb6de885 sm501_find_clock +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0xe02bdb6b sm501_modify_reg +EXPORT_SYMBOL_GPL drivers/mfd/sm501 0xe65eab65 sm501_misc_control +EXPORT_SYMBOL_GPL drivers/misc/eeprom_93cx6 0x2df115d4 eeprom_93cx6_multiread +EXPORT_SYMBOL_GPL drivers/misc/eeprom_93cx6 0x63d14d2f eeprom_93cx6_read +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0x58a17c64 enclosure_remove_device +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0x6c13472f enclosure_add_device +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0x958b1da4 enclosure_register +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0x9ab6f7fd enclosure_component_register +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0xc1339762 enclosure_find +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0xd359f806 enclosure_unregister +EXPORT_SYMBOL_GPL drivers/misc/enclosure 0xf342e30f enclosure_for_each_device +EXPORT_SYMBOL_GPL drivers/misc/sgi-gru/gru 0x2293c8e0 gru_get_next_message +EXPORT_SYMBOL_GPL drivers/misc/sgi-gru/gru 0x5927a880 gru_send_message_gpa +EXPORT_SYMBOL_GPL drivers/misc/sgi-gru/gru 0x7e83f3fc gru_free_message +EXPORT_SYMBOL_GPL drivers/misc/sgi-gru/gru 0x81b3b8e3 gru_create_message_queue +EXPORT_SYMBOL_GPL drivers/misc/sgi-gru/gru 0x9c7283a1 gru_copy_gpa +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0x345c9217 xpc_disconnect +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0x39046c7a xpc_clear_interface +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0x43a01eea xpc_registrations +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0x6285dfe8 xp_cpu_to_nasid +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0x64ba5017 xp_pa +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0x76e36d39 xp_region_size +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0x9823adb0 xpc_set_interface +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0x9acd8cf8 xpc_interface +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0xba3694f3 xp_remote_memcpy +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0xead4f7fe xp_max_npartitions +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0xf3b47f67 xp_partition_id +EXPORT_SYMBOL_GPL drivers/misc/sgi-xp/xp 0xfe709b6c xpc_connect +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x087544d1 sdio_enable_func +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x2081c271 sdio_writeb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x376aaa75 sdio_align_size +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x414514e7 sdio_f0_writeb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x4415d799 sdio_disable_func +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x45644fe8 sdio_readw +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x58300c38 sdio_readl +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x6e0d3070 sdio_memcpy_toio +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x6e88a923 sdio_writel +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x6fd87903 sdio_unregister_driver +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x70d16bd7 sdio_release_irq +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x7a3e67bb sdio_memcpy_fromio +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x823d9e9a sdio_f0_readb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x8960d10e sdio_release_host +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x8a227a24 sdio_register_driver +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0x9b619be5 sdio_writesb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xa610d65e sdio_readsb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xa9cc833a sdio_claim_host +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xc714568c sdio_writew +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xcbc04550 sdio_claim_irq +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xea785e12 sdio_readb +EXPORT_SYMBOL_GPL drivers/mmc/core/mmc_core 0xff74c9e5 sdio_set_block_size +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0x0b1f39ae sdhci_suspend_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0x51b669e0 sdhci_resume_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0x5ef184df sdhci_add_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0x6a739170 sdhci_free_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0xa2fd7a61 sdhci_remove_host +EXPORT_SYMBOL_GPL drivers/mmc/host/sdhci 0xabd4a035 sdhci_alloc_host +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0001 0x57390696 cfi_cmdset_0001 +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0001 0xa574bdcb cfi_cmdset_0200 +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0001 0xce7d7f1a cfi_cmdset_0003 +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0002 0x82df43dc cfi_cmdset_0002 +EXPORT_SYMBOL_GPL drivers/mtd/chips/cfi_cmdset_0020 0xff0cb122 cfi_cmdset_0020 +EXPORT_SYMBOL_GPL drivers/mtd/devices/doc2000 0x68a62f65 DoC2k_init +EXPORT_SYMBOL_GPL drivers/mtd/devices/doc2001 0x92b52cc0 DoCMil_init +EXPORT_SYMBOL_GPL drivers/mtd/devices/doc2001plus 0xf4b38d40 DoCMilPlus_init +EXPORT_SYMBOL_GPL drivers/mtd/devices/docecc 0x45937659 doc_decode_ecc +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x06e946cf put_mtd_device +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x305bbcd3 mtd_table +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x49cc76d0 deregister_mtd_parser +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x4d55e2cb get_mtd_device_nm +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x5aa5d30b unregister_mtd_user +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x5dd108f7 del_mtd_device +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x97b3d01a register_mtd_user +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0x9a150064 parse_mtd_partitions +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xaac99e1c mtd_erase_callback +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xb4981eda default_mtd_writev +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xc23c70d9 register_mtd_parser +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xcd69cdb4 add_mtd_device +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xecbcf900 kill_mtd_super +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xee3d2e5a get_mtd_device +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xeff64be1 mtd_table_mutex +EXPORT_SYMBOL_GPL drivers/mtd/mtd 0xf467e47a get_sb_mtd +EXPORT_SYMBOL_GPL drivers/mtd/mtd_blkdevs 0x9ae8761b del_mtd_blktrans_dev +EXPORT_SYMBOL_GPL drivers/mtd/mtd_blkdevs 0xa317ae44 deregister_mtd_blktrans +EXPORT_SYMBOL_GPL drivers/mtd/mtd_blkdevs 0xb8f3d62d add_mtd_blktrans_dev +EXPORT_SYMBOL_GPL drivers/mtd/mtd_blkdevs 0xd6f37562 register_mtd_blktrans +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0x5ec3a233 nand_wait_ready +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0x9f9b582a nand_scan +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0xa7bbffe0 nand_scan_tail +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0xae791bab nand_scan_ident +EXPORT_SYMBOL_GPL drivers/mtd/nand/nand 0xbcfce9c5 nand_release +EXPORT_SYMBOL_GPL drivers/mtd/onenand/onenand 0x0323ef35 onenand_release +EXPORT_SYMBOL_GPL drivers/mtd/onenand/onenand 0x07b79c74 onenand_scan +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x01a2b2fd ubi_open_volume +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x3b336589 ubi_leb_write +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x42801d20 ubi_sync +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x4f2bdf92 ubi_get_volume_info +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x5885ca05 ubi_close_volume +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x73296454 ubi_is_mapped +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x7f3f14d3 ubi_leb_erase +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0x8c9549f8 ubi_leb_map +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xbc505df4 ubi_get_device_info +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xc18853b5 ubi_leb_change +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xd5a972db ubi_leb_read +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xd858699a ubi_leb_unmap +EXPORT_SYMBOL_GPL drivers/mtd/ubi/ubi 0xfe96383e ubi_open_volume_nm +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x010d8ce4 mlx4_cq_modify +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x0b537f8b mlx4_CLOSE_PORT +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x181a0565 mlx4_free_hwq_res +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x1c6fc717 mlx4_mtt_init +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x1d446d71 mlx4_qp_modify +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x23e9bb54 mlx4_fmr_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x2a45b47f mlx4_srq_arm +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x2be82087 mlx4_srq_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x378c5be5 mlx4_cq_resize +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x382df159 mlx4_buf_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x3ff35ec7 mlx4_srq_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x4b608888 mlx4_map_phys_fmr +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x4ce0b3d7 mlx4_cq_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x4f374ab5 mlx4_srq_query +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x51905ba0 mlx4_SYNC_TPT +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x51cad764 mlx4_fmr_unmap +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x53b279de mlx4_buf_write_mtt +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x5539058a mlx4_alloc_hwq_res +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x5a35efa4 mlx4_pd_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x629799b1 mlx4_mr_enable +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x65675603 mlx4_fmr_enable +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x68817f39 mlx4_qp_query +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x688e38e9 mlx4_uar_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x73c823aa mlx4_mtt_addr +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x7892ca3b mlx4_multicast_detach +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x8265350f mlx4_pd_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x82e97ece mlx4_qp_remove +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0x8c32de27 mlx4_write_mtt +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xa6fc5e1f __mlx4_cmd +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xb327fbc8 mlx4_db_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xb59c6d9b mlx4_buf_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xb7663a4e mlx4_register_interface +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xbaaaff31 mlx4_mtt_cleanup +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xbbc28468 mlx4_fmr_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xbfcd1b47 mlx4_uar_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xbfd56320 mlx4_free_cmd_mailbox +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xc048f4ab mlx4_cq_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xc228bc16 mlx4_qp_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xc29809cf mlx4_alloc_cmd_mailbox +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xc94cf72b mlx4_db_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xd0709200 mlx4_INIT_PORT +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xdb8ebd86 mlx4_mr_free +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xde3317b1 mlx4_qp_alloc +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xe30641f3 mlx4_multicast_attach +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xea6077c6 mlx4_qp_to_ready +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xed747120 mlx4_unregister_interface +EXPORT_SYMBOL_GPL drivers/net/mlx4/mlx4_core 0xf0bb0ffb mlx4_mr_alloc +EXPORT_SYMBOL_GPL drivers/net/usb/cdc_ether 0xb7f8fe0a usbnet_generic_cdc_bind +EXPORT_SYMBOL_GPL drivers/net/usb/cdc_ether 0xc7d58706 usbnet_cdc_unbind +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0x67e35cb7 rndis_status +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0x740827c3 rndis_tx_fixup +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0x7645e1e5 generic_rndis_bind +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0xeedd3fc9 rndis_rx_fixup +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0xf72a6883 rndis_unbind +EXPORT_SYMBOL_GPL drivers/net/usb/rndis_host 0xff9d13d1 rndis_command +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x211c2589 usbnet_set_msglevel +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x3d9152e3 usbnet_get_link +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x423dbf9f usbnet_unlink_rx_urbs +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x4d9d426f usbnet_get_endpoints +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x59e07c0d usbnet_suspend +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x5a05000f usbnet_disconnect +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x62056718 usbnet_get_drvinfo +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x7023cfa9 usbnet_get_settings +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x7478ffad usbnet_get_msglevel +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0x96037c38 usbnet_skb_return +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xb1f07be1 usbnet_resume +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xbed2856d usbnet_nway_reset +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xd53e25c7 usbnet_defer_kevent +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xdd224854 usbnet_set_settings +EXPORT_SYMBOL_GPL drivers/net/usb/usbnet 0xf63e1931 usbnet_probe +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x0602cac1 lbs_suspend +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x0be023ae lbs_stop_card +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x0c5e40b5 lbs_cmd_802_11_rate_adapt_rateset +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x26e5dbfe lbs_host_sleep_cfg +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x308d94ad lbs_cmd_copyback +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x3e29ed5a lbs_process_rxed_packet +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x6eb01a31 lbs_queue_event +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x8c064947 lbs_start_card +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0x930757d9 lbs_resume +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xb226c912 lbs_remove_card +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xb4b18159 lbs_send_tx_feedback +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xc22b6817 lbs_add_card +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xdce69e6a lbs_notify_command_response +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xf64277de lbs_debug +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xf82859bd __lbs_cmd +EXPORT_SYMBOL_GPL drivers/net/wireless/libertas/libertas 0xf9d8db24 lbs_host_to_card_done +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0x00690516 p54_parse_firmware +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0x61ecb650 p54_free_common +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0xa1d75bf5 p54_parse_eeprom +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0xaa748adb p54_fill_eeprom_readback +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0xc9d7c699 p54_init_common +EXPORT_SYMBOL_GPL drivers/net/wireless/p54/p54common 0xe4a2f9a1 p54_rx +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x06b59e86 rt2x00mac_config_interface +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x1b2801ca rt2x00mac_stop +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x2c9b4cd4 rt2x00mac_remove_interface +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x2e3997c4 rt2x00lib_probe_dev +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x4883e94c rt2x00queue_get_entry +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x4bb9fb2e rt2x00lib_txdone +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x6dcceb49 rt2x00queue_map_txskb +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x7e62024b rt2x00queue_get_queue +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x84073a85 rt2x00mac_configure_filter +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x856a1fe7 rt2x00mac_bss_info_changed +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x87c7abe0 rt2x00mac_conf_tx +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x938b4d39 rt2x00mac_get_tx_stats +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x95025ccc rt2x00lib_remove_dev +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0x9ef624c5 rt2x00lib_beacondone +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xa2ebdded rt2x00mac_add_interface +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xa3254a77 rt2x00mac_config +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xb5fbd062 rt2x00mac_get_stats +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xbea33e90 rt2x00mac_tx +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xd1891627 rt2x00lib_resume +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xd1a465e1 rt2x00mac_start +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xdcb88b1f rt2x00lib_rxdone +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00lib 0xe922f4d8 rt2x00lib_suspend +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0x6abb08f2 rt2x00pci_resume +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0x7ce519f8 rt2x00pci_uninitialize +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0xacae4409 rt2x00pci_suspend +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0xb168c3a4 rt2x00pci_rxdone +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0xb630272c rt2x00pci_write_tx_data +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0xd44a2ac8 rt2x00pci_remove +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0xf21fe1a4 rt2x00pci_initialize +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00pci 0xf3863960 rt2x00pci_probe +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x0867b6e4 rt2x00usb_vendor_request_buff +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x0f7cac3e rt2x00usb_vendor_req_buff_lock +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x168bea10 rt2x00usb_resume +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x2ed8a663 rt2x00usb_suspend +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x4354593c rt2x00usb_probe +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x4ca1ca20 rt2x00usb_initialize +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x54d52da6 rt2x00usb_vendor_request +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x5e52134f rt2x00usb_init_rxentry +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x81117fe1 rt2x00usb_kick_tx_queue +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x8fb60349 rt2x00usb_uninitialize +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0x9e45c57c rt2x00usb_vendor_request_large_buff +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0xa834c04a rt2x00usb_disable_radio +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0xb68cb2fc rt2x00usb_write_tx_data +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0xc337fe6d rt2x00usb_disconnect +EXPORT_SYMBOL_GPL drivers/net/wireless/rt2x00/rt2x00usb 0xf904f32d rt2x00usb_init_txentry +EXPORT_SYMBOL_GPL drivers/pci/hotplug/acpiphp 0x999ed3b7 acpiphp_register_attention +EXPORT_SYMBOL_GPL drivers/pci/hotplug/acpiphp 0xda0d631d acpiphp_unregister_attention +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x1ad3b491 acpi_root_bridge +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x6a8441be cpci_hp_start +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x7e21a060 cpci_hp_unregister_bus +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x7e68536d cpci_hp_register_controller +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x7f2100fc cpci_hp_register_bus +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0x94ef4d05 cpci_hp_stop +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0xa291d1fd pci_hp_register +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0xb97116e5 cpci_hp_unregister_controller +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0xcd7791b0 pci_hp_deregister +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0xd1fb62f2 pci_hp_change_slot_info +EXPORT_SYMBOL_GPL drivers/pci/hotplug/pci_hotplug 0xf7e825f6 acpi_get_hp_params_from_firmware +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x001b18a4 scsi_register_device_handler +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x041d97ad scsi_dh_detach +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x09552a8a scsi_unregister_device_handler +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x593a36c2 scsi_dh_handler_exist +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x7c4c5379 scsi_dh_attach +EXPORT_SYMBOL_GPL drivers/scsi/device_handler/scsi_dh 0x99f7a5d2 scsi_dh_activate +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x0233f349 iscsi_pool_init +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x05241ec2 iscsi_prep_unsolicit_data_pdu +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x07c121c7 iscsi_conn_teardown +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x1540b5ba iscsi_suspend_tx +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x273c202d __iscsi_complete_pdu +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x2929000e iscsi_change_queue_depth +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x30c35bca iscsi_conn_stop +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x319775bb iscsi_conn_setup +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x41ba1d14 iscsi_pool_free +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x4381d090 iscsi_conn_get_param +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x451fe9b8 iscsi_set_param +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x48a82dfd iscsi_requeue_task +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x5253a7de iscsi_session_recovery_timedout +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x54d9c43f iscsi_itt_to_ctask +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x59a97db7 iscsi_eh_host_reset +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x66cb48b2 iscsi_conn_start +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x6c105266 iscsi_complete_pdu +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x804425a3 iscsi_put_task +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x817b1759 iscsi_session_setup +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x893d14d4 iscsi_host_set_param +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x8c38a498 iscsi_queuecommand +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x8ec64c9d iscsi_verify_itt +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x8f12f0c1 iscsi_conn_bind +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x9a7d19eb iscsi_host_remove +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0x9b587b20 iscsi_host_free +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xa274dd8c iscsi_eh_abort +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xa766ed6f __iscsi_get_task +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xbbeaba73 iscsi_eh_device_reset +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xcbd676b2 iscsi_update_cmdsn +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xcd3e4a8e iscsi_conn_failure +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xdf30c3c2 iscsi_host_alloc +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xe54aca86 iscsi_host_get_param +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xeabdc1e0 iscsi_session_get_param +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xec6c6806 iscsi_session_teardown +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xede66f4b iscsi_host_add +EXPORT_SYMBOL_GPL drivers/scsi/libiscsi 0xf8f1595d iscsi_conn_send_pdu +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x0cc78f4d sas_queuecommand +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x0d072f2d sas_ssp_task_response +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x10232a42 sas_domain_attach_transport +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x1e23c474 sas_slave_destroy +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x222c0f70 sas_change_queue_type +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x2736fc1e sas_task_abort +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x27a57fb3 sas_register_ha +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x3c43b881 sas_domain_release_transport +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x3fc9e71d sas_phy_reset +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x4cb284d9 sas_find_local_phy +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x597dcd69 __sas_task_abort +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x60ccefd5 sas_bios_param +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x64b445e2 sas_phy_enable +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x725daf1b sas_slave_configure +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x74ccd3b2 sas_unregister_ha +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x8da178a8 sas_target_alloc +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x9649f0e8 sas_request_addr +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0x9a7908e2 sas_ioctl +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xb8dac1e7 sas_eh_device_reset_handler +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xce2dc861 sas_change_queue_depth +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xd43b03cd sas_slave_alloc +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xea0a613a sas_eh_bus_reset_handler +EXPORT_SYMBOL_GPL drivers/scsi/libsas/libsas 0xef8d2ad7 sas_target_destroy +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x06609f3a srp_iu_put +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x10ddf03e srp_target_free +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x1b2800c1 srp_transfer_data +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x2bff6332 srp_cmd_queue +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x5d8e8e07 srp_iu_get +EXPORT_SYMBOL_GPL drivers/scsi/libsrp 0x8a91fd35 srp_target_alloc +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x08cb47fd sdev_evt_send +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x26c90ea4 scsi_eh_get_sense +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x35d8c94a sdev_evt_alloc +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x4a3a42e1 scsi_target_block +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x4fa8ece7 scsi_mode_select +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x56116358 scsi_nl_sock +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x7653d91c scsi_eh_ready_devs +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x7e275ea8 scsi_complete_async_scans +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x9778bcd4 scsi_schedule_eh +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x9c871012 scsi_target_unblock +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0x9faf413a __scsi_get_command +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xca85a3b6 scsi_internal_device_block +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xcc67b080 scsi_queue_work +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xd30001e5 scsi_flush_work +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xd7b43cf3 scsi_execute_async +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xd9982753 sdev_evt_send_simple +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xda723572 scsi_bus_type +EXPORT_SYMBOL_GPL drivers/scsi/scsi_mod 0xe0697a22 scsi_internal_device_unblock +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x05472d63 scsi_tgt_it_nexus_destroy +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x1db6d800 scsi_host_put_command +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x3630babd scsi_tgt_cmd_to_host +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0x5715dde4 scsi_tgt_tsk_mgmt_request +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0xaa32ff1c scsi_tgt_queue_command +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0xe915977b scsi_tgt_alloc_queue +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0xf43be2f1 scsi_host_get_command +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0xf681e4b3 scsi_tgt_free_queue +EXPORT_SYMBOL_GPL drivers/scsi/scsi_tgt 0xfa7386ea scsi_tgt_it_nexus_create +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x093d7688 iscsi_destroy_conn +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x1614df41 iscsi_unblock_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x16b462f0 iscsi_create_conn +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x1746b105 iscsi_session_chkready +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x1c150793 iscsi_recv_pdu +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x2bd25c9c iscsi_host_for_each_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x35eede99 iscsi_block_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x3be8ce1c iscsi_conn_error +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x5654144d iscsi_destroy_endpoint +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x5862fb33 iscsi_free_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x5ef140e2 iscsi_add_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x6404128c iscsi_lookup_endpoint +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x6710016b iscsi_session_event +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0x9c467c74 iscsi_unregister_transport +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xa700d665 iscsi_create_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xb993b082 iscsi_register_transport +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xba210d2a iscsi_scan_finished +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xc7779819 iscsi_destroy_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xce0b3ac5 iscsi_alloc_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xe41ce3c2 iscsi_create_endpoint +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_iscsi 0xfe84db82 iscsi_remove_session +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_spi 0x0ef06974 spi_populate_ppr_msg +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_spi 0xa0c71dac spi_populate_sync_msg +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_spi 0xcffa2aff spi_populate_width_msg +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0x18af8164 srp_rport_del +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0x26c894ef srp_remove_host +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0x3d4c9026 srp_attach_transport +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0x60902ef3 srp_rport_add +EXPORT_SYMBOL_GPL drivers/scsi/scsi_transport_srp 0xa2f1c184 srp_release_transport +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0x6f3c57e1 spi_bitbang_cleanup +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0x89f022c2 spi_bitbang_stop +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0x9fce090a spi_bitbang_start +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0xa7370f75 spi_bitbang_setup +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0xc3f248d3 spi_bitbang_setup_transfer +EXPORT_SYMBOL_GPL drivers/spi/spi_bitbang 0xe97b9576 spi_bitbang_transfer +EXPORT_SYMBOL_GPL drivers/uio/uio 0x4bbc499c __uio_register_device +EXPORT_SYMBOL_GPL drivers/uio/uio 0xa3ebfd18 uio_event_notify +EXPORT_SYMBOL_GPL drivers/uio/uio 0xae627116 uio_unregister_device +EXPORT_SYMBOL_GPL drivers/usb/atm/usbatm 0xa7940c6c usbatm_usb_probe +EXPORT_SYMBOL_GPL drivers/usb/atm/usbatm 0xb1b3e2dd usbatm_usb_disconnect +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x04b31971 usb_control_msg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x0603e884 usb_get_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x089ccbdf usb_driver_claim_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x12c69986 usb_hcd_poll_rh_status +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x1341f38e usb_autopm_set_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x19a304ba usb_disabled +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x22de98fe usb_sg_wait +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x23b19a43 usb_driver_release_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x249d0af1 usb_unlink_anchored_urbs +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x25fd518f usb_put_dev +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x27268665 usb_kill_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x2d1f9df1 usb_clear_halt +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x32e1339c usb_autopm_get_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x3be89d3c usb_register_notify +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x41fbf3d6 usb_hcd_platform_shutdown +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x492ff4af usb_add_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x495d102b usb_match_id +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x49e5cf8a usb_driver_set_configuration +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x4ecf7c7f usb_hcd_link_urb_to_ep +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x54f9109d usb_reset_configuration +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x58641d9e usb_sg_init +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x589bfc75 usb_hcd_pci_suspend +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x5b14da51 usb_register_dev +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x5b740637 usb_register_driver +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x5cb54918 usb_buffer_map_sg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x62288a57 usb_deregister +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x632f5ca0 usb_root_hub_lost_power +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x654683ff usb_get_status +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x6592183e usb_alloc_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x6d23dcdd usb_hub_tt_clear_buffer +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x6dce94bf usb_bus_list_lock +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x6e8f64c5 usb_create_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x71f99dc2 usb_altnum_to_altsetting +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x7395578c usb_buffer_alloc +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x7628f57e usb_get_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x7668d003 usb_hcd_pci_shutdown +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x7e64181d usb_calc_bus_time +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x81a9edf9 usb_reset_device +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x862774b6 usb_hcd_pci_resume +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x8cebbc73 usb_bulk_msg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x92e32f66 usb_free_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x9924c496 __usb_get_extra_descriptor +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x9bed64ee usb_set_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x9e1fd331 usb_anchor_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0x9fc0634a usb_init_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xa626fee8 usb_buffer_unmap_sg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xaaee8705 usb_ifnum_to_if +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xab199f8c usb_put_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xace5c0fc usb_bus_list +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xade031bf usb_hcd_giveback_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xaff72bb4 usb_sg_cancel +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xb15128b5 usb_mon_register +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xb3ce9211 usb_unlink_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xbb182a0e usb_buffer_free +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xbbff46f6 usb_hcd_pci_remove +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xbc3a242f usb_wait_anchor_empty_timeout +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xbef55551 usb_get_intf +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xc17515d7 usb_hcds_loaded +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xc4424d9b usb_lock_device_for_reset +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xcbc33b99 usb_put_intf +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xd319881d usb_unanchor_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xd4da3526 usb_get_dev +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xd5e589b1 usb_interrupt_msg +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xd7f5dffa usb_get_current_frame_number +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xd8fb7f09 usb_hcd_pci_probe +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xde40722e usb_string +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xdedfe3dc usb_get_descriptor +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xe3875d2a usb_kill_anchored_urbs +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xe3d614c4 usb_find_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xe532d7e9 usb_ep0_reinit +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xe66bec8d usb_hc_died +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xe9587909 usb_unregister_notify +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xe98f1d47 usb_submit_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xea4105dc usb_remove_hcd +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xed0690a5 ehci_cf_port_reset_rwsem +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xed2564f8 usb_register_device_driver +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xee35c2f1 usb_autopm_put_interface +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xef727bff usb_deregister_dev +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xf204d5f1 usb_hcd_check_unlink_urb +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xf2056555 usb_hcd_resume_root_hub +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xf2a2aa20 usb_match_one_id +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xf45fbbef usb_store_new_id +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xf57d1a34 usb_hcd_unlink_urb_from_ep +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xf7f8191f usb_deregister_device_driver +EXPORT_SYMBOL_GPL drivers/usb/core/usbcore 0xfed11ed1 usb_mon_deregister +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x3061f110 usb_ftdi_elan_read_pcimem +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x44c13e92 usb_ftdi_elan_edset_input +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x6f296360 usb_ftdi_elan_write_pcimem +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x72f3e4ed usb_ftdi_elan_edset_empty +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x8ded87d6 usb_ftdi_elan_edset_flush +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0x8f911794 usb_ftdi_elan_edset_output +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0xc02312d9 usb_ftdi_elan_edset_single +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0xc936506e ftdi_elan_gone_away +EXPORT_SYMBOL_GPL drivers/usb/misc/ftdi-elan 0xd0dc6ad9 usb_ftdi_elan_edset_setup +EXPORT_SYMBOL_GPL drivers/usb/misc/phidget 0x87f7008c phidget_class +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x29ab785c ezusb_set_reset +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x46d40d7d usb_serial_deregister +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x4e978d1a ezusb_writememory +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x5506d797 usb_serial_generic_read_bulk_callback +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x55fb9d96 usb_serial_port_softint +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x62669c33 usb_serial_generic_write_bulk_callback +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x78347ba4 usb_serial_probe +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0x792e9157 usb_serial_generic_open +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0xa6aa71fd usb_serial_register +EXPORT_SYMBOL_GPL drivers/usb/serial/usbserial 0xff6a9fc7 usb_serial_disconnect +EXPORT_SYMBOL_GPL drivers/usb/storage/libusual 0x3edad223 usb_usual_clear_present +EXPORT_SYMBOL_GPL drivers/usb/storage/libusual 0x89d4dbaf usb_usual_check_type +EXPORT_SYMBOL_GPL drivers/usb/storage/libusual 0xcd9991a9 usb_usual_set_present +EXPORT_SYMBOL_GPL drivers/usb/storage/libusual 0xde134c69 storage_usb_ids +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x0cc52025 ili9320_resume +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x2b0b68b5 ili9320_write_regs +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x344cea0c ili9320_probe_spi +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0x74c92c2e ili9320_shutdown +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0xa294dcd6 ili9320_suspend +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0xa4cbb9ed ili9320_remove +EXPORT_SYMBOL_GPL drivers/video/backlight/ili9320 0xd24038c1 ili9320_write +EXPORT_SYMBOL_GPL drivers/video/fb_ddc 0xd210409e fb_ddc_read +EXPORT_SYMBOL_GPL drivers/video/fb_sys_fops 0x7ac492ca fb_sys_read +EXPORT_SYMBOL_GPL drivers/video/fb_sys_fops 0xeaab9611 fb_sys_write +EXPORT_SYMBOL_GPL drivers/video/sis/sisfb 0x05bbce99 sis_free_new +EXPORT_SYMBOL_GPL drivers/video/sis/sisfb 0x54862ef8 sis_malloc_new +EXPORT_SYMBOL_GPL drivers/video/vermilion/vmlfb 0x016e6c20 vmlfb_unregister_subsys +EXPORT_SYMBOL_GPL drivers/video/vermilion/vmlfb 0x90c018c6 vmlfb_register_subsys +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0x0f191ab7 register_virtio_device +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0x16f5900f virtio_check_driver_offered_feature +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0x7aaa1838 unregister_virtio_device +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0xa9973f03 register_virtio_driver +EXPORT_SYMBOL_GPL drivers/virtio/virtio 0xbab696b5 unregister_virtio_driver +EXPORT_SYMBOL_GPL drivers/virtio/virtio_ring 0x03c4687d vring_interrupt +EXPORT_SYMBOL_GPL drivers/virtio/virtio_ring 0x11a51fb2 vring_transport_features +EXPORT_SYMBOL_GPL drivers/virtio/virtio_ring 0xaf7c0454 vring_del_virtqueue +EXPORT_SYMBOL_GPL drivers/virtio/virtio_ring 0xc0e0aa23 vring_new_virtqueue +EXPORT_SYMBOL_GPL drivers/w1/wire 0x225e421c w1_write_block +EXPORT_SYMBOL_GPL drivers/w1/wire 0x6af5326e w1_reset_select_slave +EXPORT_SYMBOL_GPL drivers/w1/wire 0x7c2f2afb w1_calc_crc8 +EXPORT_SYMBOL_GPL drivers/w1/wire 0x82b56f84 w1_write_8 +EXPORT_SYMBOL_GPL drivers/w1/wire 0xcf6a6b2d w1_reset_bus +EXPORT_SYMBOL_GPL drivers/w1/wire 0xda0c6759 w1_read_block +EXPORT_SYMBOL_GPL fs/dlm/dlm 0x9321df95 dlm_lock +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xb1d92a2b dlm_posix_lock +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xc641235b dlm_posix_get +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xcf9f3328 dlm_release_lockspace +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xdc583c08 dlm_unlock +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xdcdd95e9 dlm_posix_unlock +EXPORT_SYMBOL_GPL fs/dlm/dlm 0xdf3c14de dlm_new_lockspace +EXPORT_SYMBOL_GPL fs/exportfs/exportfs 0xb4f9166a exportfs_decode_fh +EXPORT_SYMBOL_GPL fs/exportfs/exportfs 0xf3bebb4b exportfs_encode_fh +EXPORT_SYMBOL_GPL fs/fat/fat 0x103c4fc2 fat_scan +EXPORT_SYMBOL_GPL fs/fat/fat 0x192777b3 fat_fill_super +EXPORT_SYMBOL_GPL fs/fat/fat 0x2f141b3f fat_sync_inode +EXPORT_SYMBOL_GPL fs/fat/fat 0x3490ba95 fat_search_long +EXPORT_SYMBOL_GPL fs/fat/fat 0x3d8e2ab0 fat_free_clusters +EXPORT_SYMBOL_GPL fs/fat/fat 0x4ece8c97 fat_fs_panic +EXPORT_SYMBOL_GPL fs/fat/fat 0x6f7139df fat_setattr +EXPORT_SYMBOL_GPL fs/fat/fat 0x72dcb9e0 fat_detach +EXPORT_SYMBOL_GPL fs/fat/fat 0x7a600b46 fat_build_inode +EXPORT_SYMBOL_GPL fs/fat/fat 0x9230234b fat_attach +EXPORT_SYMBOL_GPL fs/fat/fat 0x97715a93 fat_alloc_new_dir +EXPORT_SYMBOL_GPL fs/fat/fat 0xa79bf4a6 fat_flush_inodes +EXPORT_SYMBOL_GPL fs/fat/fat 0xaeb55307 fat_remove_entries +EXPORT_SYMBOL_GPL fs/fat/fat 0xaf45fa26 fat_getattr +EXPORT_SYMBOL_GPL fs/fat/fat 0xb68ea16d fat_date_unix2dos +EXPORT_SYMBOL_GPL fs/fat/fat 0xe8d15566 fat_get_dotdot_entry +EXPORT_SYMBOL_GPL fs/fat/fat 0xed264ddb fat_dir_empty +EXPORT_SYMBOL_GPL fs/fat/fat 0xfbaf9238 fat_add_entries +EXPORT_SYMBOL_GPL fs/gfs2/gfs2 0x4c739163 gfs2_unregister_lockproto +EXPORT_SYMBOL_GPL fs/gfs2/gfs2 0x7b0bd18c gfs2_register_lockproto +EXPORT_SYMBOL_GPL fs/lockd/lockd 0x104c1c6d nlmclnt_proc +EXPORT_SYMBOL_GPL fs/lockd/lockd 0x1a618932 nlmsvc_unlock_all_by_ip +EXPORT_SYMBOL_GPL fs/lockd/lockd 0x26b35026 nlmclnt_init +EXPORT_SYMBOL_GPL fs/lockd/lockd 0xd0a90c03 nlmsvc_unlock_all_by_sb +EXPORT_SYMBOL_GPL fs/lockd/lockd 0xe0e4f75d nlmclnt_done +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x1b89c6ee o2hb_fill_node_map +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x1d747ce3 o2hb_check_node_heartbeating +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x35ac10b1 o2hb_unregister_callback +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x36418553 o2net_send_message +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x4900035b o2hb_stop_all_regions +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x51eb6c7f o2hb_setup_callback +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x521e0726 o2net_send_message_vec +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x81a17396 mlog_and_bits +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0x9b4682fc o2nm_get_node_by_num +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xa216f565 o2nm_get_node_by_ip +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xa82a8645 o2nm_this_node +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xa87bc9e7 o2nm_configured_node_map +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xae808bac o2net_register_handler +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xb469169a o2hb_register_callback +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xbaeb4700 o2hb_check_node_heartbeating_from_callback +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xd4eacdf8 o2nm_node_put +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xd60f2c6c o2hb_check_local_node_heartbeating +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xebf297a9 o2nm_node_get +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xf1a5611d o2net_unregister_handler_list +EXPORT_SYMBOL_GPL fs/ocfs2/cluster/ocfs2_nodemanager 0xf56c2017 mlog_not_bits +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0x0ea641be dlm_unregister_domain +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0x37d19a24 dlmunlock +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0x7a1211f8 dlm_setup_eviction_cb +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0x8f1a26a7 dlm_register_domain +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xcbc0b1f5 dlm_print_one_lock +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xd7ba575e dlm_errmsg +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xd8fa57a6 dlm_unregister_eviction_cb +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xf93f3dab dlm_register_eviction_cb +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xfb86b96f dlm_errname +EXPORT_SYMBOL_GPL fs/ocfs2/dlm/ocfs2_dlm 0xfbbc0b03 dlmlock +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x0562c415 ocfs2_cluster_this_node +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x0a831369 ocfs2_stack_glue_unregister +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x0e27f909 ocfs2_dlm_lock +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x21db5b88 ocfs2_cluster_disconnect +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x4a1f6fe9 ocfs2_cluster_connect +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x4d3af7fa ocfs2_cluster_hangup +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x81c85a68 ocfs2_dlm_lock_status +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x91fab465 ocfs2_dlm_lvb +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x9456503c ocfs2_stack_glue_register +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0x963932a3 ocfs2_stack_glue_set_locking_protocol +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0xa7d5c1c0 ocfs2_dlm_unlock +EXPORT_SYMBOL_GPL fs/ocfs2/ocfs2_stackglue 0xd066711e ocfs2_dlm_dump_lksb +EXPORT_SYMBOL_GPL lib/lzo/lzo_compress 0x2e1d43cf lzo1x_1_compress +EXPORT_SYMBOL_GPL lib/lzo/lzo_decompress 0x2a1538ca lzo1x_decompress_safe +EXPORT_SYMBOL_GPL lib/reed_solomon/reed_solomon 0x300d7e57 free_rs +EXPORT_SYMBOL_GPL lib/reed_solomon/reed_solomon 0x6fbb3bd9 init_rs_non_canonical +EXPORT_SYMBOL_GPL lib/reed_solomon/reed_solomon 0xabda1e2e decode_rs16 +EXPORT_SYMBOL_GPL lib/reed_solomon/reed_solomon 0xb050f329 init_rs +EXPORT_SYMBOL_GPL net/802/garp 0x1732d7a6 garp_uninit_applicant +EXPORT_SYMBOL_GPL net/802/garp 0x6c6fb931 garp_unregister_application +EXPORT_SYMBOL_GPL net/802/garp 0x7aaed301 garp_init_applicant +EXPORT_SYMBOL_GPL net/802/garp 0x7dc508c1 garp_request_leave +EXPORT_SYMBOL_GPL net/802/garp 0x8046363f garp_register_application +EXPORT_SYMBOL_GPL net/802/garp 0xfffbc4f8 garp_request_join +EXPORT_SYMBOL_GPL net/802/stp 0x737325e8 stp_proto_unregister +EXPORT_SYMBOL_GPL net/802/stp 0xc8750db9 stp_proto_register +EXPORT_SYMBOL_GPL net/ax25/ax25 0x5c9d67d9 ax25_register_pid +EXPORT_SYMBOL_GPL net/ax25/ax25 0xac93ae05 ax25_bcast +EXPORT_SYMBOL_GPL net/ax25/ax25 0xaeb7451e ax25_defaddr +EXPORT_SYMBOL_GPL net/bluetooth/bluetooth 0x1f82cc3e bt_class +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x0836683b tfrc_rx_hist_sample_rtt +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x09c5ed3c tfrc_tx_hist_purge +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x0a487ea5 tfrc_calc_x +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x106fe6d3 tfrc_tx_hist_rtt +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x197c78bd tfrc_rx_handle_loss +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x43c58bad tfrc_rx_hist_duplicate +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x54d1745f tfrc_lh_interval_add +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x69ec5731 tfrc_tx_hist_add +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x6c252d29 tfrc_calc_x_reverse_lookup +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x902206f0 tfrc_lh_cleanup +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0x92285650 tfrc_rx_hist_alloc +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0xc612a5b6 tfrc_rx_hist_purge +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0xdebbee6c tfrc_lh_update_i_mean +EXPORT_SYMBOL_GPL net/dccp/ccids/lib/dccp_tfrc_lib 0xe405007b tfrc_rx_hist_add_packet +EXPORT_SYMBOL_GPL net/dccp/dccp 0x05fdd0e9 ccid_register +EXPORT_SYMBOL_GPL net/dccp/dccp 0x0c5c6d38 dccp_insert_option_timestamp +EXPORT_SYMBOL_GPL net/dccp/dccp 0x0df4f650 dccp_destroy_sock +EXPORT_SYMBOL_GPL net/dccp/dccp 0x118a40b3 dccp_ctl_make_reset +EXPORT_SYMBOL_GPL net/dccp/dccp 0x121668a2 dccp_send_sync +EXPORT_SYMBOL_GPL net/dccp/dccp 0x187b9cbe dccp_init_sock +EXPORT_SYMBOL_GPL net/dccp/dccp 0x1d99d49a dccp_timestamp +EXPORT_SYMBOL_GPL net/dccp/dccp 0x1ed10c32 ccid_hc_rx_new +EXPORT_SYMBOL_GPL net/dccp/dccp 0x2e701182 dccp_feat_change_recv +EXPORT_SYMBOL_GPL net/dccp/dccp 0x353bbc5a dccp_send_ack +EXPORT_SYMBOL_GPL net/dccp/dccp 0x3b3c0b1b dccp_feat_clean +EXPORT_SYMBOL_GPL net/dccp/dccp 0x43b7a411 dccp_feat_clone +EXPORT_SYMBOL_GPL net/dccp/dccp 0x44b950e8 dccp_shutdown +EXPORT_SYMBOL_GPL net/dccp/dccp 0x458c3ad3 dccp_connect +EXPORT_SYMBOL_GPL net/dccp/dccp 0x48a72555 inet_dccp_listen +EXPORT_SYMBOL_GPL net/dccp/dccp 0x557553c6 dccp_rcv_established +EXPORT_SYMBOL_GPL net/dccp/dccp 0x56ea266a dccp_state_name +EXPORT_SYMBOL_GPL net/dccp/dccp 0x5cb34c26 dccp_recvmsg +EXPORT_SYMBOL_GPL net/dccp/dccp 0x5eaebc49 dccp_parse_options +EXPORT_SYMBOL_GPL net/dccp/dccp 0x626d8bee dccp_getsockopt +EXPORT_SYMBOL_GPL net/dccp/dccp 0x6eeb0630 dccp_check_req +EXPORT_SYMBOL_GPL net/dccp/dccp 0x7e26f141 ccid_hc_rx_delete +EXPORT_SYMBOL_GPL net/dccp/dccp 0x86be7924 dccp_packet_name +EXPORT_SYMBOL_GPL net/dccp/dccp 0x883a2664 dccp_death_row +EXPORT_SYMBOL_GPL net/dccp/dccp 0x8995dab1 ccid_unregister +EXPORT_SYMBOL_GPL net/dccp/dccp 0x8b0fd41d compat_dccp_getsockopt +EXPORT_SYMBOL_GPL net/dccp/dccp 0x8b7d8caf dccp_statistics +EXPORT_SYMBOL_GPL net/dccp/dccp 0x8bc3d9f1 dccp_sendmsg +EXPORT_SYMBOL_GPL net/dccp/dccp 0x8be3e2da ccid_hc_tx_new +EXPORT_SYMBOL_GPL net/dccp/dccp 0x9373d9ec dccp_set_state +EXPORT_SYMBOL_GPL net/dccp/dccp 0x985e865f ccid_hc_tx_delete +EXPORT_SYMBOL_GPL net/dccp/dccp 0x9d6a3846 dccp_orphan_count +EXPORT_SYMBOL_GPL net/dccp/dccp 0x9ec71ae0 dccp_done +EXPORT_SYMBOL_GPL net/dccp/dccp 0xac864a97 dccp_rcv_state_process +EXPORT_SYMBOL_GPL net/dccp/dccp 0xb8fbb2ae dccp_poll +EXPORT_SYMBOL_GPL net/dccp/dccp 0xbc7b3869 dccp_disconnect +EXPORT_SYMBOL_GPL net/dccp/dccp 0xbc89e7d0 dccp_reqsk_send_ack +EXPORT_SYMBOL_GPL net/dccp/dccp 0xbe4cf010 dccp_feat_init +EXPORT_SYMBOL_GPL net/dccp/dccp 0xbf6b58ba dccp_feat_change +EXPORT_SYMBOL_GPL net/dccp/dccp 0xc2b9ca8c dccp_feat_confirm_recv +EXPORT_SYMBOL_GPL net/dccp/dccp 0xc3e72880 dccp_ioctl +EXPORT_SYMBOL_GPL net/dccp/dccp 0xcffaa78b dccp_make_response +EXPORT_SYMBOL_GPL net/dccp/dccp 0xd2ae3de8 dccp_sample_rtt +EXPORT_SYMBOL_GPL net/dccp/dccp 0xd67f0865 ccid_new +EXPORT_SYMBOL_GPL net/dccp/dccp 0xd6b4ead9 dccp_hashinfo +EXPORT_SYMBOL_GPL net/dccp/dccp 0xdf3a1ccd dccp_setsockopt +EXPORT_SYMBOL_GPL net/dccp/dccp 0xe72cf73d dccp_insert_option_elapsed_time +EXPORT_SYMBOL_GPL net/dccp/dccp 0xeebb6978 dccp_insert_option +EXPORT_SYMBOL_GPL net/dccp/dccp 0xf051e4b5 dccp_create_openreq_child +EXPORT_SYMBOL_GPL net/dccp/dccp 0xf2cbfacc dccp_sync_mss +EXPORT_SYMBOL_GPL net/dccp/dccp 0xfa2748e6 dccp_child_process +EXPORT_SYMBOL_GPL net/dccp/dccp 0xfd33e862 dccp_close +EXPORT_SYMBOL_GPL net/dccp/dccp 0xfd6b57b4 dccp_reqsk_init +EXPORT_SYMBOL_GPL net/dccp/dccp 0xfe8d1c8c compat_dccp_setsockopt +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0x171c7b98 dccp_v4_send_check +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0x23b032d7 dccp_invalid_packet +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0x3909f626 dccp_v4_do_rcv +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0x5353e8ee dccp_v4_request_recv_sock +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0xa90603c1 dccp_v4_conn_request +EXPORT_SYMBOL_GPL net/dccp/dccp_ipv4 0xc685998c dccp_v4_connect +EXPORT_SYMBOL_GPL net/ieee80211/ieee80211 0x2cf5fff3 ieee80211_rx_any +EXPORT_SYMBOL_GPL net/ipv4/ipvs/ip_vs 0xe6476b4a net_vs_ctl_path +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_conntrack_ipv4 0x06d3fe28 nf_nat_seq_adjust_hook +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_conntrack_ipv4 0x6d40a921 need_ipv4_conntrack +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x07ae60b6 nf_nat_proto_in_range +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x2aff4511 nf_nat_proto_find_get +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x408193a5 nf_nat_icmp_reply_translation +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x59c3072f nf_nat_proto_unique_tuple +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x935dbd25 nf_nat_proto_range_to_nlattr +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0x94a08134 nf_nat_proto_nlattr_to_range +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0xb1920cb7 nf_nat_packet +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat 0xb267d194 nf_nat_proto_put +EXPORT_SYMBOL_GPL net/ipv4/netfilter/nf_nat_proto_gre 0x636b12c8 nf_nat_need_gre +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0x2c6ce25c tcp_vegas_pkts_acked +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0x3a729979 tcp_vegas_get_info +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0x5065cc4c tcp_vegas_init +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0xb082db43 tcp_vegas_cwnd_event +EXPORT_SYMBOL_GPL net/ipv4/tcp_vegas 0xe6491e34 tcp_vegas_state +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x01270b43 ip6_dst_lookup +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x04548cb8 ipv6_find_tlv +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x08a3e5d1 net_ipv6_ctl_path +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x0c9befb5 inet6_sk_rebuild_header +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x13fa6972 ip6_local_out +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x2048c2fa fl6_sock_lookup +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x21ca859b inet6_csk_bind_conflict +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x2268702f ipv6_dup_options +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x4bb58ec5 inet6_csk_reqsk_queue_hash_add +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x55f91c50 ip6_dst_blackhole +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x6f1c1030 inet6_csk_addr2sockaddr +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x821c54aa ipv6_opt_accepted +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0x86831cd2 inet6_csk_xmit +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0xb07c3e94 inet6_destroy_sock +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0xd33c27ea ip6_sk_dst_lookup +EXPORT_SYMBOL_GPL net/ipv6/ipv6 0xf679fde4 inet6_csk_search_req +EXPORT_SYMBOL_GPL net/mac80211/mac80211 0x4eddb345 ieee80211_iterate_active_interfaces +EXPORT_SYMBOL_GPL net/mac80211/mac80211 0x9d2e76d0 ieee80211_iterate_active_interfaces_atomic +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x041013fd nf_conntrack_lock +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x045072cd nf_ct_port_nla_policy +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x0ea4f6dc nf_ct_iterate_cleanup +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x1283d711 nf_ct_expect_unregister_notifier +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x15c10b0b nf_conntrack_unregister_notifier +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x17c9367e nf_conntrack_helper_register +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x1d5b1ae1 nf_conntrack_l4proto_udp4 +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x248d7f93 nf_conntrack_alloc +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x25e649f2 nf_ct_log_invalid +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x2b9580cb nf_conntrack_flush +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x2e5d2cce nf_ct_expect_find_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x2f6d7863 nf_conntrack_l4proto_udp6 +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x3609de81 nf_conntrack_count +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x36bf1b41 nf_conntrack_l3proto_generic +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x38630158 nf_conntrack_tuple_taken +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x38c9440b nf_ct_extend_register +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x3f5b1415 nf_ct_port_nlattr_to_tuple +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x40387ccf __nf_ct_event_cache_init +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x4fa2388b nf_conntrack_l4proto_tcp6 +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x5bc88365 __nf_conntrack_helper_find_byname +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x5fde0387 nf_ct_expect_put +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6030839d nf_ct_port_tuple_to_nlattr +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x624149a9 nf_ct_l3protos +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x64e7eef0 __nf_ct_helper_find +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x684e889c __nf_ct_expect_find +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x68a94ae4 nf_conntrack_l3proto_register +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x68d269aa nf_ct_expect_related +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6add762d nf_conntrack_in +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6c02f72a nf_ct_l4proto_put +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6cd91ee0 per_cpu__nf_conntrack_ecache +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6e224a7a need_conntrack +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x6eedbc99 nf_ct_l3proto_put +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x700d1765 seq_print_acct +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x72836f4a nf_conntrack_free +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x77aadb54 nf_conntrack_alter_reply +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x78f9b710 nf_ct_l3proto_try_module_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x79ca2e53 nf_ct_expect_chain +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x7d945a09 nf_conntrack_l4proto_tcp4 +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x85fe2cee nf_ct_expect_alloc +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x892e8797 nf_conntrack_l3proto_unregister +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x8ffe7e89 nf_conntrack_htable_size +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x90ff6c9f nf_ct_invert_tuplepr +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0x9b38b540 nf_ct_get_tuple +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xa6f62ec0 nf_conntrack_set_hashsize +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xa869cd8c nf_conntrack_l4proto_register +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xaa072598 nf_conntrack_l4proto_unregister +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xaa7f735f __nf_conntrack_confirm +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xace98352 nf_conntrack_hash +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xad36f24b nf_ct_get_tuplepr +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xaf57e66f nf_ct_extend_unregister +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xb602c57e nf_ct_l3proto_module_put +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xb6f9a8a5 nf_ct_invert_tuple +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xb76accc2 __nf_conntrack_find +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xb9e30797 nf_ct_acct +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xbc887e16 nf_ct_expect_register_notifier +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xbe3f2939 nf_conntrack_checksum +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc044befe nf_ct_free_hashtable +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc18ac88d nf_ct_expect_hsize +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc35a7a3e nf_conntrack_chain +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc6bfe9ba __nf_ct_l4proto_find +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc7b64d79 nf_conntrack_hash_insert +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc86cbcbb nf_ct_expect_init +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xc97799ba __nf_ct_refresh_acct +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xcbf7fd2a nf_conntrack_register_notifier +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd22893c1 nf_ct_unlink_expect +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd46e3724 __nf_ct_kill_acct +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd50a96a2 nf_ct_alloc_hashtable +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd553c300 nf_ct_l3proto_find_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd7c683c4 nf_conntrack_find_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xd9efb053 nf_ct_deliver_cached_events +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xe3e83b8a nf_ct_l4proto_find_get +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xe3eda4b2 nf_ct_helper_ext_add +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xec8beba6 nf_ct_expect_hash +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xf25a47a0 nf_conntrack_tcp_update +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xf398fab4 nf_ct_unexpect_related +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xf6a2087d print_tuple +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xf9ae81a1 nf_conntrack_max +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xfa169dac nf_conntrack_untracked +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xfb839673 nf_ct_remove_expectations +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack 0xfdfcd327 nf_conntrack_helper_unregister +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_amanda 0x1e7f07ca nf_nat_amanda_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_ftp 0xe3696262 nf_nat_ftp_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x14ee4acf set_sig_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x264c0cf3 get_h225_addr +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x4a815505 nat_q931_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x627dbfb0 nat_callforwarding_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x838b3d14 nat_t120_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0x9475943e set_ras_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0xb51a4a7d nat_rtp_rtcp_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0xb671f98e nat_h245_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0xb8d77f64 set_h245_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_h323 0xfbc09389 set_h225_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_irc 0x9b561981 nf_nat_irc_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_pptp 0x24362528 nf_nat_pptp_hook_outbound +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_pptp 0x2d788e10 nf_nat_pptp_hook_inbound +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_pptp 0x60a1a957 nf_nat_pptp_hook_expectfn +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_pptp 0x907404bf nf_nat_pptp_hook_exp_gre +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_proto_gre 0x05f8e58c nf_ct_gre_keymap_destroy +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_proto_gre 0x6f59d77c nf_ct_gre_keymap_add +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x02d1acc2 nf_nat_sdp_addr_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x13169b79 ct_sip_parse_request +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x25646c96 nf_nat_sdp_session_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x3c2058a6 ct_sip_parse_numerical_param +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x5333cb69 ct_sip_parse_header_uri +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x5343611e ct_sip_get_sdp_header +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x56ad8f6e ct_sip_parse_address_param +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x63547df4 nf_nat_sip_expect_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x66d73f0f nf_nat_sip_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0x69dc74f6 nf_nat_sdp_port_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0xed35ddfc nf_nat_sdp_media_hook +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_sip 0xf8b610ea ct_sip_get_header +EXPORT_SYMBOL_GPL net/netfilter/nf_conntrack_tftp 0x2949c4d4 nf_nat_tftp_hook +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0x3d3ad67f nfnetlink_subsys_unregister +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0x4753d0eb nfnetlink_unicast +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0xb978a6ce nfnetlink_subsys_register +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0xcc82c49d nfnetlink_send +EXPORT_SYMBOL_GPL net/netfilter/nfnetlink 0xeca95329 nfnetlink_has_listeners +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x2f32d4da xt_compat_lock +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x3b083e81 xt_compat_match_from_user +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x3cf5a35b xt_compat_match_to_user +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x3d619fea xt_unregister_table +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x50d7f1aa xt_compat_calc_jump +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x59c179ae xt_compat_target_from_user +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x6239c30f xt_compat_add_offset +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x63f05053 xt_find_revision +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x696109ee xt_compat_flush_offsets +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x6b86ebc8 xt_register_table +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x6c6c2b4d xt_compat_target_offset +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x6e835ca6 xt_request_find_target +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x822d2e96 xt_compat_target_to_user +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x86267b21 xt_check_target +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x86945c5e xt_table_unlock +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x8a3d4708 xt_compat_match_offset +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x911b586d xt_find_table_lock +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x955cccf3 xt_proto_fini +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0x9e30bcb3 xt_proto_init +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0xcfddc8ad xt_replace_table +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0xe53911a2 xt_compat_unlock +EXPORT_SYMBOL_GPL net/netfilter/x_tables 0xf6cf112d xt_check_match +EXPORT_SYMBOL_GPL net/netfilter/xt_RATEEST 0xc177bee0 xt_rateest_put +EXPORT_SYMBOL_GPL net/netfilter/xt_RATEEST 0xdb8418cc xt_rateest_lookup +EXPORT_SYMBOL_GPL net/rfkill/rfkill 0x83b2e956 register_rfkill_notifier +EXPORT_SYMBOL_GPL net/rfkill/rfkill 0x86c722f8 rfkill_epo +EXPORT_SYMBOL_GPL net/rfkill/rfkill 0xa6f4320d unregister_rfkill_notifier +EXPORT_SYMBOL_GPL net/rxrpc/af-rxrpc 0x2e916274 rxrpc_register_security +EXPORT_SYMBOL_GPL net/rxrpc/af-rxrpc 0xaf3b7cb4 rxrpc_unregister_security +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x05f78c2e svc_create_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x0ceead61 rpc_create +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x0df5cadc rpc_call_sync +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x17388b0f xprt_reserve_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x2578af4e xdr_skb_read_bits +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x25929dac rpcauth_register +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x2aa17774 rpc_free_iostats +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x2ad94124 rpc_sleep_on +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x2ea46c1d rpc_force_rebind +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x2eff00c1 rpc_call_null +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x31a89d59 rpc_debug +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x341cd07e xprt_unregister_transport +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x37f8f7f5 rpcauth_init_cred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x39d221b1 rpcb_getport_async +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x3f935f05 svc_xprt_enqueue +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x4571f263 rpc_peeraddr +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x481c9745 rpc_bind_new_program +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x48605515 rpc_restart_call +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x49dbc863 rpc_alloc_iostats +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x51a58a69 rpc_shutdown_client +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x53445f68 nlm_debug +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x53d073fc rpc_put_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x54d53105 svc_max_payload +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x550547a3 rpc_destroy_wait_queue +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x5b2f5a98 rpc_peeraddr2str +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x5bd26000 rpc_proc_unregister +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x616922a1 xprt_release_rqst_cong +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x6392642b rpc_malloc +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x65336dcb rpc_wake_up_queued_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x65a0509e svc_reg_xprt_class +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x69186c7d xprt_wait_for_buffer_space +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x6addd3d0 xprt_complete_rqst +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x6c5304c5 rpcb_getport_sync +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x6cd718ba rpcauth_unregister +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x712b860f rpc_setbufsize +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x78f8d2f8 xprt_write_space +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7938578d xprt_release_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x79b58f7a svc_addsock +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x79fd30ee rpcauth_lookup_credcache +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7ca553fa xprt_lookup_rqst +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7ce3014a xprt_set_retrans_timeout_rtt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7d59fa3f svc_xprt_init +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x7de53067 rpc_init_rtt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x80cf6fa9 rpc_print_iostats +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x814cf549 xprt_set_retrans_timeout_def +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x81f87a1e rpcauth_init_credcache +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x85edb45b rpc_delay +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x90d8a820 rpc_max_payload +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x96e0214a rpc_call_start +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x97014523 rpc_killall_tasks +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x97c4f07b rpc_wake_up_next +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0x97f7ebcd rpc_clone_client +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xa5e4b04b xprt_adjust_cwnd +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xa727fa86 svc_close_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xab7d314d svc_xprt_names +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xab8e3367 csum_partial_copy_to_xdr +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xac92f899 svc_xprt_copy_addrs +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xad55c221 rpcauth_create +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xaf5bf6ef nfs_debug +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xb387b246 rpc_wake_up_status +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xb46e2f62 rpc_lookup_cred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xbae9b026 svc_find_xprt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xbf9d1b96 nfsd_debug +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xbfc3b992 rpc_lookup_machine_cred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xc12435e3 rpc_calc_rto +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xc7079d4c rpcauth_destroy_credcache +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xc7859fe1 xprt_update_rtt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xccb88495 xprt_reserve_xprt_cong +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xce115853 xprt_disconnect_done +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xd385a9c8 svc_print_addr +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xd82c728e rpc_init_wait_queue +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xda284d03 xdr_partial_copy_from_skb +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xe14fc829 put_rpccred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xe1bed8fe rpc_run_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xe242e6df rpc_proc_register +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xe59331fd xprt_register_transport +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xe667e62c xprt_release_xprt_cong +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xe6bacec1 rpc_exit_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xedd1ba52 rpc_wake_up +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xeeacab69 rpc_update_rtt +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xf5a1f3af __rpc_wait_for_completion_task +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xf66ab2aa svc_xprt_put +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xf9d1164c rpc_free +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xfa3a4b4b rpc_call_async +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xfd981ce3 svc_unreg_xprt_class +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xfe03371e xprt_wake_pending_tasks +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xffa315be rpcauth_generic_bind_cred +EXPORT_SYMBOL_GPL net/sunrpc/sunrpc 0xffe933d0 svc_xprt_received +EXPORT_SYMBOL_GPL net/xfrm/xfrm_ipcomp 0x395dc9a4 ipcomp_input +EXPORT_SYMBOL_GPL net/xfrm/xfrm_ipcomp 0x7c2cbe80 ipcomp_destroy +EXPORT_SYMBOL_GPL net/xfrm/xfrm_ipcomp 0xabddec04 ipcomp_output +EXPORT_SYMBOL_GPL net/xfrm/xfrm_ipcomp 0xcb39961c ipcomp_init_state +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x02289ecc snd_soc_dai_set_fmt +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x0698e603 snd_soc_dapm_new_controls +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x07e7f965 dapm_reg_event +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x0a8f8409 snd_soc_cnew +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x2a013c49 snd_soc_info_enum_ext +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x39ffdb73 snd_soc_dapm_add_routes +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x3d119574 snd_soc_new_pcms +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x405bcb81 snd_soc_dai_set_tdm_slot +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x4191620a snd_soc_dai_set_clkdiv +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x490c2bc2 snd_soc_get_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x494d70c1 snd_soc_put_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x4f68e9c8 snd_soc_info_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x509c6497 snd_soc_register_card +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x57aefd84 snd_soc_info_volsw_2r +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x5ccb8e6d snd_soc_dapm_get_pin_status +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x6122104b snd_soc_free_ac97_codec +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x61474fa0 snd_soc_new_ac97_codec +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x65bfe6e0 snd_soc_dapm_get_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x65febde3 snd_soc_dapm_put_enum_double +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x713f6f16 snd_soc_dapm_free +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x7f57be48 snd_soc_dai_digital_mute +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x80669a9d snd_soc_dapm_connect_input +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x81c7a388 snd_soc_dapm_put_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x88051adb snd_soc_info_volsw_ext +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x9555313b snd_soc_dapm_new_control +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x9770750c snd_soc_info_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0x9a510dfe snd_soc_get_volsw_2r +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xa4664f78 snd_soc_dapm_enable_pin +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xaec75bb9 snd_soc_info_volsw_s8 +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xb49d5df6 snd_soc_test_bits +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xb76622ca snd_soc_dapm_stream_event +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xb770e1c2 snd_soc_put_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xbb15872b snd_soc_dapm_disable_pin +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xbc66bc25 snd_soc_dai_set_pll +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xbe288b70 snd_soc_put_volsw_s8 +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xc0662ed3 snd_soc_update_bits +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xc2c02849 snd_soc_get_volsw_s8 +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xc76d13c8 snd_soc_free_pcms +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xd4e3733e snd_soc_dapm_get_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xd6d7177e snd_soc_dapm_sync +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xe2543174 snd_soc_get_volsw +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xe5c5661b snd_soc_set_runtime_hwparams +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xe6b9aec7 snd_soc_put_volsw_2r +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xede5360a snd_soc_dai_set_tristate +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xf5c726e0 snd_soc_dai_set_sysclk +EXPORT_SYMBOL_GPL sound/soc/snd-soc-core 0xf8566a36 snd_soc_dapm_new_widgets +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0x0d93d0e1 tlsf_create_memory_pool +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0x1584fdb9 tlsf_destroy_memory_pool +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0x2c383ca4 tlsf_calloc +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0x54064cb9 tlsf_get_used_size +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0x60d233a6 tlsf_malloc +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0xbe77d1fe tlsf_get_total_size +EXPORT_SYMBOL_GPL ubuntu/compcache/tlsf 0xe6acc368 tlsf_free +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x02500586 thinkpad_ec_unlock +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x0dc7484e thinkpad_ec_try_read_row +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x2552d213 thinkpad_ec_lock +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x3dbfef12 thinkpad_ec_read_row +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0x8dbbd831 thinkpad_ec_invalidate +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0xa3042743 thinkpad_ec_prefetch_row +EXPORT_SYMBOL_GPL ubuntu/misc/thinkpad_ec 0xfb5aa917 thinkpad_ec_try_lock +EXPORT_SYMBOL_GPL vmlinux 0x00566d8f inotify_get_cookie +EXPORT_SYMBOL_GPL vmlinux 0x006d7cad srcu_batches_completed +EXPORT_SYMBOL_GPL vmlinux 0x009ea0e5 sk_setup_caps +EXPORT_SYMBOL_GPL vmlinux 0x00b8ecf8 __iowrite32_copy +EXPORT_SYMBOL_GPL vmlinux 0x01848a8e local_apic_timer_c2_ok +EXPORT_SYMBOL_GPL vmlinux 0x01a4ea6d unregister_die_notifier +EXPORT_SYMBOL_GPL vmlinux 0x01e1a8de kgdb_breakpoint +EXPORT_SYMBOL_GPL vmlinux 0x028e6f97 __blocking_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x02a9ac14 user_update +EXPORT_SYMBOL_GPL vmlinux 0x02aaeb73 inotify_init +EXPORT_SYMBOL_GPL vmlinux 0x02ccea56 lock_policy_rwsem_write +EXPORT_SYMBOL_GPL vmlinux 0x0343bdf1 __i2c_board_list +EXPORT_SYMBOL_GPL vmlinux 0x0359f82a blk_end_request_callback +EXPORT_SYMBOL_GPL vmlinux 0x0375c1b8 generic_fh_to_parent +EXPORT_SYMBOL_GPL vmlinux 0x03dc0992 rtnl_kill_links +EXPORT_SYMBOL_GPL vmlinux 0x03fe2cca flush_work +EXPORT_SYMBOL_GPL vmlinux 0x0427901f transport_add_device +EXPORT_SYMBOL_GPL vmlinux 0x0447d159 raw_seq_stop +EXPORT_SYMBOL_GPL vmlinux 0x04486e88 rcu_batches_completed +EXPORT_SYMBOL_GPL vmlinux 0x04566c7f init_srcu_struct +EXPORT_SYMBOL_GPL vmlinux 0x047c1883 __inet_lookup_established +EXPORT_SYMBOL_GPL vmlinux 0x04c3f2c1 gnttab_empty_grant_references +EXPORT_SYMBOL_GPL vmlinux 0x04e628cd leds_list_lock +EXPORT_SYMBOL_GPL vmlinux 0x04ea8706 __iowrite64_copy +EXPORT_SYMBOL_GPL vmlinux 0x054e550b kernel_halt +EXPORT_SYMBOL_GPL vmlinux 0x05b0e01d input_ff_upload +EXPORT_SYMBOL_GPL vmlinux 0x05e1f291 vfs_cancel_lock +EXPORT_SYMBOL_GPL vmlinux 0x05e835d3 klist_node_attached +EXPORT_SYMBOL_GPL vmlinux 0x060833f0 input_class +EXPORT_SYMBOL_GPL vmlinux 0x0611d011 vfs_test_lock +EXPORT_SYMBOL_GPL vmlinux 0x064db9a5 mark_mounts_for_expiry +EXPORT_SYMBOL_GPL vmlinux 0x06bcd220 xenbus_unregister_driver +EXPORT_SYMBOL_GPL vmlinux 0x06d222f8 device_resume +EXPORT_SYMBOL_GPL vmlinux 0x06f64229 tty_get_pgrp +EXPORT_SYMBOL_GPL vmlinux 0x074a3aab device_initialize +EXPORT_SYMBOL_GPL vmlinux 0x074d8299 k_handler +EXPORT_SYMBOL_GPL vmlinux 0x07a708b2 pci_find_next_ht_capability +EXPORT_SYMBOL_GPL vmlinux 0x07b52e38 rtnl_unregister +EXPORT_SYMBOL_GPL vmlinux 0x07ff4aea xenbus_scanf +EXPORT_SYMBOL_GPL vmlinux 0x085ef4b4 inotify_remove_watch_locked +EXPORT_SYMBOL_GPL vmlinux 0x0871083f sysdev_class_unregister +EXPORT_SYMBOL_GPL vmlinux 0x08a3fe89 spi_new_device +EXPORT_SYMBOL_GPL vmlinux 0x091eb9b4 round_jiffies +EXPORT_SYMBOL_GPL vmlinux 0x09b5fba5 user_instantiate +EXPORT_SYMBOL_GPL vmlinux 0x0a1cfb74 blk_set_cmd_filter_defaults +EXPORT_SYMBOL_GPL vmlinux 0x0a264f8c cpufreq_register_driver +EXPORT_SYMBOL_GPL vmlinux 0x0aebf5b5 get_cpu_sysdev +EXPORT_SYMBOL_GPL vmlinux 0x0b34024c bdi_writeout_inc +EXPORT_SYMBOL_GPL vmlinux 0x0b42ff5b bus_rescan_devices +EXPORT_SYMBOL_GPL vmlinux 0x0b5e484c tty_ldisc_deref +EXPORT_SYMBOL_GPL vmlinux 0x0bc151e5 klist_init +EXPORT_SYMBOL_GPL vmlinux 0x0bfa774b fs_kobj +EXPORT_SYMBOL_GPL vmlinux 0x0c17e274 xfrm_aalg_get_byid +EXPORT_SYMBOL_GPL vmlinux 0x0c2de216 xfrm_inner_extract_output +EXPORT_SYMBOL_GPL vmlinux 0x0c4717f7 srcu_init_notifier_head +EXPORT_SYMBOL_GPL vmlinux 0x0cb8753f vlan_dev_vlan_id +EXPORT_SYMBOL_GPL vmlinux 0x0d20656a class_unregister +EXPORT_SYMBOL_GPL vmlinux 0x0d5ce501 attribute_container_find_class_device +EXPORT_SYMBOL_GPL vmlinux 0x0d9a47e7 simple_attr_release +EXPORT_SYMBOL_GPL vmlinux 0x0de6697e led_trigger_unregister +EXPORT_SYMBOL_GPL vmlinux 0x0ec210b8 xen_start_info +EXPORT_SYMBOL_GPL vmlinux 0x0ef84c65 hrtimer_start +EXPORT_SYMBOL_GPL vmlinux 0x0f1ee23a blkdev_driver_ioctl +EXPORT_SYMBOL_GPL vmlinux 0x0f48167d crypto_register_instance +EXPORT_SYMBOL_GPL vmlinux 0x0fe2d570 xenbus_directory +EXPORT_SYMBOL_GPL vmlinux 0x0ff8687d rtc_device_register +EXPORT_SYMBOL_GPL vmlinux 0x0ff8bb3f map_vm_area +EXPORT_SYMBOL_GPL vmlinux 0x10421ec3 get_task_mm +EXPORT_SYMBOL_GPL vmlinux 0x1050bc52 hrtimer_init +EXPORT_SYMBOL_GPL vmlinux 0x107db31d xenbus_free_evtchn +EXPORT_SYMBOL_GPL vmlinux 0x10aced1e __xenbus_register_frontend +EXPORT_SYMBOL_GPL vmlinux 0x10b10ab3 pci_find_ext_capability +EXPORT_SYMBOL_GPL vmlinux 0x11a2a943 tty_perform_flush +EXPORT_SYMBOL_GPL vmlinux 0x11fcdf4d device_for_each_child +EXPORT_SYMBOL_GPL vmlinux 0x1239a941 sock_prot_inuse_get +EXPORT_SYMBOL_GPL vmlinux 0x124f2056 crypto_get_attr_type +EXPORT_SYMBOL_GPL vmlinux 0x1251d30f call_rcu +EXPORT_SYMBOL_GPL vmlinux 0x12e285ec is_uv_system +EXPORT_SYMBOL_GPL vmlinux 0x1352e336 xfrm_output +EXPORT_SYMBOL_GPL vmlinux 0x138b472b __percpu_alloc_mask +EXPORT_SYMBOL_GPL vmlinux 0x13b2a946 register_keyboard_notifier +EXPORT_SYMBOL_GPL vmlinux 0x145eebd0 device_power_up +EXPORT_SYMBOL_GPL vmlinux 0x146bee29 spi_register_master +EXPORT_SYMBOL_GPL vmlinux 0x149db923 selinux_string_to_sid +EXPORT_SYMBOL_GPL vmlinux 0x14d5425d bus_find_device_by_name +EXPORT_SYMBOL_GPL vmlinux 0x14e367f8 debugfs_create_file +EXPORT_SYMBOL_GPL vmlinux 0x1534ba7a bus_unregister +EXPORT_SYMBOL_GPL vmlinux 0x1598dc9d unregister_netevent_notifier +EXPORT_SYMBOL_GPL vmlinux 0x1598ef3e devres_close_group +EXPORT_SYMBOL_GPL vmlinux 0x15b0606e e820_any_mapped +EXPORT_SYMBOL_GPL vmlinux 0x163958ff mmput +EXPORT_SYMBOL_GPL vmlinux 0x166b6ad5 spi_bus_type +EXPORT_SYMBOL_GPL vmlinux 0x16a2ff76 rt_mutex_lock_interruptible +EXPORT_SYMBOL_GPL vmlinux 0x16a5b4c8 key_type_user +EXPORT_SYMBOL_GPL vmlinux 0x16b6e800 driver_remove_file +EXPORT_SYMBOL_GPL vmlinux 0x17ff49b4 save_stack_trace_tsk +EXPORT_SYMBOL_GPL vmlinux 0x1808b560 blk_queue_dma_drain +EXPORT_SYMBOL_GPL vmlinux 0x187551b2 spi_write_then_read +EXPORT_SYMBOL_GPL vmlinux 0x1878f62b edac_err_assert +EXPORT_SYMBOL_GPL vmlinux 0x18d53420 kgdb_register_io_module +EXPORT_SYMBOL_GPL vmlinux 0x18e24ff8 vfs_listxattr +EXPORT_SYMBOL_GPL vmlinux 0x18f83fab gnttab_grant_foreign_access_ref +EXPORT_SYMBOL_GPL vmlinux 0x18fa5171 inet_csk_get_port +EXPORT_SYMBOL_GPL vmlinux 0x1906cdee elv_unregister +EXPORT_SYMBOL_GPL vmlinux 0x1a10607f unregister_jprobes +EXPORT_SYMBOL_GPL vmlinux 0x1a7b9c47 relay_close +EXPORT_SYMBOL_GPL vmlinux 0x1a938737 atomic_notifier_chain_register +EXPORT_SYMBOL_GPL vmlinux 0x1acda5b2 atomic_notifier_chain_unregister +EXPORT_SYMBOL_GPL vmlinux 0x1b9aca3f jprobe_return +EXPORT_SYMBOL_GPL vmlinux 0x1c49acfe inet_csk_compat_setsockopt +EXPORT_SYMBOL_GPL vmlinux 0x1c5e06b3 inotify_add_watch +EXPORT_SYMBOL_GPL vmlinux 0x1c995eea get_user_pages_fast +EXPORT_SYMBOL_GPL vmlinux 0x1c99ba30 mnt_drop_write +EXPORT_SYMBOL_GPL vmlinux 0x1cac9211 get_driver +EXPORT_SYMBOL_GPL vmlinux 0x1d0d4070 crypto_init_spawn +EXPORT_SYMBOL_GPL vmlinux 0x1dd70100 dmi_walk +EXPORT_SYMBOL_GPL vmlinux 0x1ddf95ba sysdev_show_int +EXPORT_SYMBOL_GPL vmlinux 0x1e053cb0 kobject_rename +EXPORT_SYMBOL_GPL vmlinux 0x1e53dfd2 inotify_init_watch +EXPORT_SYMBOL_GPL vmlinux 0x1e698d14 debugfs_create_u64 +EXPORT_SYMBOL_GPL vmlinux 0x1e7bbcb3 kernel_restart +EXPORT_SYMBOL_GPL vmlinux 0x1eb9516e round_jiffies_relative +EXPORT_SYMBOL_GPL vmlinux 0x1ebae765 spi_sync +EXPORT_SYMBOL_GPL vmlinux 0x1f0b31b2 disk_round_stats +EXPORT_SYMBOL_GPL vmlinux 0x1f5c95f5 platform_device_put +EXPORT_SYMBOL_GPL vmlinux 0x1f68581f debugfs_create_symlink +EXPORT_SYMBOL_GPL vmlinux 0x1f6be5f2 tcp_twsk_unique +EXPORT_SYMBOL_GPL vmlinux 0x1f8ec1b3 acpi_get_pci_rootbridge_handle +EXPORT_SYMBOL_GPL vmlinux 0x1f9a0fbf hpet_unregister_irq_handler +EXPORT_SYMBOL_GPL vmlinux 0x1f9f2a01 inet_twsk_purge +EXPORT_SYMBOL_GPL vmlinux 0x1fcece42 inet_twdr_twcal_tick +EXPORT_SYMBOL_GPL vmlinux 0x20123563 tty_prepare_flip_string_flags +EXPORT_SYMBOL_GPL vmlinux 0x203bf9d1 sysctl_pathname +EXPORT_SYMBOL_GPL vmlinux 0x20577ea2 xfrm_ealg_get_byidx +EXPORT_SYMBOL_GPL vmlinux 0x2074c42e bus_register_notifier +EXPORT_SYMBOL_GPL vmlinux 0x20b82470 hpet_register_irq_handler +EXPORT_SYMBOL_GPL vmlinux 0x20bc3470 orderly_poweroff +EXPORT_SYMBOL_GPL vmlinux 0x217ac1b2 inet_csk_clone +EXPORT_SYMBOL_GPL vmlinux 0x217ef29a kill_pid_info_as_uid +EXPORT_SYMBOL_GPL vmlinux 0x21f9011b transport_class_register +EXPORT_SYMBOL_GPL vmlinux 0x21ff4e3f sysfs_remove_bin_file +EXPORT_SYMBOL_GPL vmlinux 0x2240d211 unregister_jprobe +EXPORT_SYMBOL_GPL vmlinux 0x22472bf4 xfrm_calg_get_byid +EXPORT_SYMBOL_GPL vmlinux 0x226f4e93 transport_setup_device +EXPORT_SYMBOL_GPL vmlinux 0x2296c00d crypto_attr_u32 +EXPORT_SYMBOL_GPL vmlinux 0x22a4c758 class_create_file +EXPORT_SYMBOL_GPL vmlinux 0x22bce646 debugfs_create_u8 +EXPORT_SYMBOL_GPL vmlinux 0x2305365b register_pernet_subsys +EXPORT_SYMBOL_GPL vmlinux 0x23864ce7 cpuset_mem_spread_node +EXPORT_SYMBOL_GPL vmlinux 0x23bbb214 devres_remove +EXPORT_SYMBOL_GPL vmlinux 0x23d18c07 __ip_route_output_key +EXPORT_SYMBOL_GPL vmlinux 0x23ecc82d tcp_twsk_destructor +EXPORT_SYMBOL_GPL vmlinux 0x24196ba2 init_uts_ns +EXPORT_SYMBOL_GPL vmlinux 0x24241f10 inotify_inode_queue_event +EXPORT_SYMBOL_GPL vmlinux 0x2447533c ktime_get_real +EXPORT_SYMBOL_GPL vmlinux 0x24c7698a xenbus_write +EXPORT_SYMBOL_GPL vmlinux 0x24e74b12 blk_trace_startstop +EXPORT_SYMBOL_GPL vmlinux 0x24eb7e32 leds_list +EXPORT_SYMBOL_GPL vmlinux 0x2502a974 pci_find_next_capability +EXPORT_SYMBOL_GPL vmlinux 0x2545c170 unregister_xenbus_watch +EXPORT_SYMBOL_GPL vmlinux 0x257e29cf spi_register_driver +EXPORT_SYMBOL_GPL vmlinux 0x2580d986 sched_setscheduler +EXPORT_SYMBOL_GPL vmlinux 0x25f141e7 driver_find_device +EXPORT_SYMBOL_GPL vmlinux 0x261ea931 debugfs_remove_recursive +EXPORT_SYMBOL_GPL vmlinux 0x26a7ca85 debugfs_rename +EXPORT_SYMBOL_GPL vmlinux 0x2714c98c klist_del +EXPORT_SYMBOL_GPL vmlinux 0x27bd158c unregister_pernet_gen_device +EXPORT_SYMBOL_GPL vmlinux 0x28088f0f pv_time_ops +EXPORT_SYMBOL_GPL vmlinux 0x28a2a498 debugfs_create_x8 +EXPORT_SYMBOL_GPL vmlinux 0x28d664ff __raw_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x28e23139 xfrm_probe_algs +EXPORT_SYMBOL_GPL vmlinux 0x28ff5fd3 blk_trace_remove +EXPORT_SYMBOL_GPL vmlinux 0x297c604e uhci_reset_hc +EXPORT_SYMBOL_GPL vmlinux 0x29e23aa7 rtc_irq_unregister +EXPORT_SYMBOL_GPL vmlinux 0x2a2cd7ba rtc_irq_set_freq +EXPORT_SYMBOL_GPL vmlinux 0x2a678a13 __suspend_report_result +EXPORT_SYMBOL_GPL vmlinux 0x2b24e4a0 uv_blade_info +EXPORT_SYMBOL_GPL vmlinux 0x2b3e8dfb platform_device_alloc +EXPORT_SYMBOL_GPL vmlinux 0x2b9f8e23 nf_net_ipv4_netfilter_sysctl_path +EXPORT_SYMBOL_GPL vmlinux 0x2bc15c10 inotify_inode_is_dead +EXPORT_SYMBOL_GPL vmlinux 0x2c16ed76 xfrm_calg_get_byname +EXPORT_SYMBOL_GPL vmlinux 0x2c639fad bd_claim_by_disk +EXPORT_SYMBOL_GPL vmlinux 0x2cc9feb2 queue_delayed_work_on +EXPORT_SYMBOL_GPL vmlinux 0x2cf2bf8b rtnl_link_unregister +EXPORT_SYMBOL_GPL vmlinux 0x2d088e2b led_trigger_set +EXPORT_SYMBOL_GPL vmlinux 0x2d59c954 edac_handlers +EXPORT_SYMBOL_GPL vmlinux 0x2d9f2ce3 sched_clock_idle_wakeup_event +EXPORT_SYMBOL_GPL vmlinux 0x2daba87c __inet_lookup_listener +EXPORT_SYMBOL_GPL vmlinux 0x2e3db831 sock_prot_inuse_add +EXPORT_SYMBOL_GPL vmlinux 0x2e6e7aee smp_ops +EXPORT_SYMBOL_GPL vmlinux 0x2eafd72f sysdev_unregister +EXPORT_SYMBOL_GPL vmlinux 0x2ec92012 scatterwalk_copychunks +EXPORT_SYMBOL_GPL vmlinux 0x2f1d6c37 led_trigger_show +EXPORT_SYMBOL_GPL vmlinux 0x2fe94ced xenbus_grant_ring +EXPORT_SYMBOL_GPL vmlinux 0x30ec9492 dev_set_name +EXPORT_SYMBOL_GPL vmlinux 0x316d56cd register_net_sysctl_rotable +EXPORT_SYMBOL_GPL vmlinux 0x3232c63c inet_twsk_put +EXPORT_SYMBOL_GPL vmlinux 0x324c274e lookup_create +EXPORT_SYMBOL_GPL vmlinux 0x325e677c gnttab_grant_foreign_transfer_ref +EXPORT_SYMBOL_GPL vmlinux 0x32674a70 tty_ldisc_ref +EXPORT_SYMBOL_GPL vmlinux 0x329d2333 crypto_spawn_tfm +EXPORT_SYMBOL_GPL vmlinux 0x33b6e752 acpi_ec_remove_query_handler +EXPORT_SYMBOL_GPL vmlinux 0x33f4cd16 sysfs_create_bin_file +EXPORT_SYMBOL_GPL vmlinux 0x3403a5b3 inotify_find_watch +EXPORT_SYMBOL_GPL vmlinux 0x3441c3d6 gpio_set_value_cansleep +EXPORT_SYMBOL_GPL vmlinux 0x344a986d rt_mutex_timed_lock +EXPORT_SYMBOL_GPL vmlinux 0x352ab1b9 fb_deferred_io_open +EXPORT_SYMBOL_GPL vmlinux 0x35ba78ac user_match +EXPORT_SYMBOL_GPL vmlinux 0x35d8cb4a debugfs_create_u32 +EXPORT_SYMBOL_GPL vmlinux 0x3613a502 crypto_tfm_in_queue +EXPORT_SYMBOL_GPL vmlinux 0x361e2bcc save_stack_trace +EXPORT_SYMBOL_GPL vmlinux 0x3621a014 sysdev_show_ulong +EXPORT_SYMBOL_GPL vmlinux 0x362e23ec call_rcu_bh +EXPORT_SYMBOL_GPL vmlinux 0x365a7222 xattr_getsecurity +EXPORT_SYMBOL_GPL vmlinux 0x36d36f09 register_kretprobes +EXPORT_SYMBOL_GPL vmlinux 0x36fa3f8c relay_reset +EXPORT_SYMBOL_GPL vmlinux 0x370be381 securityfs_remove +EXPORT_SYMBOL_GPL vmlinux 0x37a5f246 kernel_kobj +EXPORT_SYMBOL_GPL vmlinux 0x37afac06 xfrm_audit_state_add +EXPORT_SYMBOL_GPL vmlinux 0x3895233b srcu_notifier_chain_unregister +EXPORT_SYMBOL_GPL vmlinux 0x38973c6d generic_sync_sb_inodes +EXPORT_SYMBOL_GPL vmlinux 0x38ebeb63 tcp_reno_cong_avoid +EXPORT_SYMBOL_GPL vmlinux 0x38fc47e5 platform_get_irq +EXPORT_SYMBOL_GPL vmlinux 0x39b2e814 pci_restore_msi_state +EXPORT_SYMBOL_GPL vmlinux 0x39b87751 put_inotify_watch +EXPORT_SYMBOL_GPL vmlinux 0x3a311560 unregister_kprobes +EXPORT_SYMBOL_GPL vmlinux 0x3a7bdbf8 sysdev_remove_file +EXPORT_SYMBOL_GPL vmlinux 0x3a7f8b86 __local_bh_enable +EXPORT_SYMBOL_GPL vmlinux 0x3a865912 sysdev_create_file +EXPORT_SYMBOL_GPL vmlinux 0x3b1446fb platform_device_register +EXPORT_SYMBOL_GPL vmlinux 0x3b1d7e44 cpuidle_disable_device +EXPORT_SYMBOL_GPL vmlinux 0x3b4ec75d platform_get_resource_byname +EXPORT_SYMBOL_GPL vmlinux 0x3bc12515 class_find_device +EXPORT_SYMBOL_GPL vmlinux 0x3bc13dac devres_remove_group +EXPORT_SYMBOL_GPL vmlinux 0x3be7af02 get_max_files +EXPORT_SYMBOL_GPL vmlinux 0x3c942368 profile_event_unregister +EXPORT_SYMBOL_GPL vmlinux 0x3cd06035 add_input_randomness +EXPORT_SYMBOL_GPL vmlinux 0x3cfedb3f register_pm_notifier +EXPORT_SYMBOL_GPL vmlinux 0x3d29867d per_cpu__gdt_page +EXPORT_SYMBOL_GPL vmlinux 0x3d5f392d acpi_os_unmap_memory +EXPORT_SYMBOL_GPL vmlinux 0x3d7ea99a gnttab_grant_foreign_transfer +EXPORT_SYMBOL_GPL vmlinux 0x3d86deb4 class_remove_file +EXPORT_SYMBOL_GPL vmlinux 0x3e31a810 platform_add_devices +EXPORT_SYMBOL_GPL vmlinux 0x3eb8ea3e sk_clone +EXPORT_SYMBOL_GPL vmlinux 0x3ee3bb7c xfrm_audit_policy_add +EXPORT_SYMBOL_GPL vmlinux 0x3efb35c9 get_online_cpus +EXPORT_SYMBOL_GPL vmlinux 0x3f238101 dcookie_register +EXPORT_SYMBOL_GPL vmlinux 0x3f6bef12 security_inode_permission +EXPORT_SYMBOL_GPL vmlinux 0x3f84d4c9 gnttab_release_grant_reference +EXPORT_SYMBOL_GPL vmlinux 0x3f8d883a swiotlb_sync_single_range_for_cpu +EXPORT_SYMBOL_GPL vmlinux 0x3ff8fafd rtc_device_unregister +EXPORT_SYMBOL_GPL vmlinux 0x40d30f24 generic_drop_inode +EXPORT_SYMBOL_GPL vmlinux 0x412902aa copy_fs_struct +EXPORT_SYMBOL_GPL vmlinux 0x4133a719 tcp_register_congestion_control +EXPORT_SYMBOL_GPL vmlinux 0x41f3cc90 xfrm_aalg_get_byname +EXPORT_SYMBOL_GPL vmlinux 0x4241dc2c pciserial_resume_ports +EXPORT_SYMBOL_GPL vmlinux 0x424acc6d scatterwalk_done +EXPORT_SYMBOL_GPL vmlinux 0x425508d3 stop_machine +EXPORT_SYMBOL_GPL vmlinux 0x432969ec devm_kzalloc +EXPORT_SYMBOL_GPL vmlinux 0x432fd7f6 __gpio_set_value +EXPORT_SYMBOL_GPL vmlinux 0x43e0164a hvc_instantiate +EXPORT_SYMBOL_GPL vmlinux 0x449086a3 tty_wakeup +EXPORT_SYMBOL_GPL vmlinux 0x44a65d5c lock_policy_rwsem_read +EXPORT_SYMBOL_GPL vmlinux 0x44bc6fde skb_pull_rcsum +EXPORT_SYMBOL_GPL vmlinux 0x454a14a4 transport_remove_device +EXPORT_SYMBOL_GPL vmlinux 0x456804e0 debugfs_create_blob +EXPORT_SYMBOL_GPL vmlinux 0x456d7b79 cpufreq_unregister_governor +EXPORT_SYMBOL_GPL vmlinux 0x457594fa crypto_alg_list +EXPORT_SYMBOL_GPL vmlinux 0x45bf1ff3 crypto_inc +EXPORT_SYMBOL_GPL vmlinux 0x45c9f3e5 xenbus_map_ring_valloc +EXPORT_SYMBOL_GPL vmlinux 0x45d14bdf hypercall_page +EXPORT_SYMBOL_GPL vmlinux 0x460f31aa rodata_test_data +EXPORT_SYMBOL_GPL vmlinux 0x4619d2b5 xfrm_audit_state_replay_overflow +EXPORT_SYMBOL_GPL vmlinux 0x465d28ae xenbus_bind_evtchn +EXPORT_SYMBOL_GPL vmlinux 0x46b9a6c3 tcp_get_info +EXPORT_SYMBOL_GPL vmlinux 0x46ced5b5 inet_csk_listen_start +EXPORT_SYMBOL_GPL vmlinux 0x46e26e4c securityfs_create_file +EXPORT_SYMBOL_GPL vmlinux 0x46e9125d agp_add_bridge +EXPORT_SYMBOL_GPL vmlinux 0x47229b5c gpio_request +EXPORT_SYMBOL_GPL vmlinux 0x47821d95 destroy_workqueue +EXPORT_SYMBOL_GPL vmlinux 0x47ee26a7 find_get_pid +EXPORT_SYMBOL_GPL vmlinux 0x48bbc799 __mmu_notifier_register +EXPORT_SYMBOL_GPL vmlinux 0x48fb5d48 __sock_recv_timestamp +EXPORT_SYMBOL_GPL vmlinux 0x499043d3 crypto_init_queue +EXPORT_SYMBOL_GPL vmlinux 0x49f266fc crypto_drop_spawn +EXPORT_SYMBOL_GPL vmlinux 0x4a11a4fb bind_virq_to_irqhandler +EXPORT_SYMBOL_GPL vmlinux 0x4a7e30d9 marker_probe_unregister_private_data +EXPORT_SYMBOL_GPL vmlinux 0x4a8173d0 acpi_bus_trim +EXPORT_SYMBOL_GPL vmlinux 0x4ab25168 spi_add_device +EXPORT_SYMBOL_GPL vmlinux 0x4ae33030 drop_file_write_access +EXPORT_SYMBOL_GPL vmlinux 0x4aeaf238 anon_transport_class_unregister +EXPORT_SYMBOL_GPL vmlinux 0x4b600bf5 skb_segment +EXPORT_SYMBOL_GPL vmlinux 0x4b762828 start_thread +EXPORT_SYMBOL_GPL vmlinux 0x4bc83227 sysdev_class_register +EXPORT_SYMBOL_GPL vmlinux 0x4c6ed311 bus_for_each_drv +EXPORT_SYMBOL_GPL vmlinux 0x4c759827 byte_rev_table +EXPORT_SYMBOL_GPL vmlinux 0x4cb409fb single_release_net +EXPORT_SYMBOL_GPL vmlinux 0x4db3ad1c crypto_dequeue_request +EXPORT_SYMBOL_GPL vmlinux 0x4eb0d47f tcp_reno_ssthresh +EXPORT_SYMBOL_GPL vmlinux 0x4ec45440 inotify_destroy +EXPORT_SYMBOL_GPL vmlinux 0x4ec6a70b device_create +EXPORT_SYMBOL_GPL vmlinux 0x4f1bc946 register_net_sysctl_table +EXPORT_SYMBOL_GPL vmlinux 0x4f2198f8 __inet_inherit_port +EXPORT_SYMBOL_GPL vmlinux 0x4f56118a kobject_uevent +EXPORT_SYMBOL_GPL vmlinux 0x4f6d609d blk_rq_cur_bytes +EXPORT_SYMBOL_GPL vmlinux 0x5083fccb tcp_slow_start +EXPORT_SYMBOL_GPL vmlinux 0x509f8eaa page_mkclean +EXPORT_SYMBOL_GPL vmlinux 0x50b319ce cpu_bit_bitmap +EXPORT_SYMBOL_GPL vmlinux 0x50b67174 xfrm_ealg_get_byid +EXPORT_SYMBOL_GPL vmlinux 0x50e7193a __i2c_first_dynamic_bus_num +EXPORT_SYMBOL_GPL vmlinux 0x50fbb319 tty_ldisc_ref_wait +EXPORT_SYMBOL_GPL vmlinux 0x5122801a register_kretprobe +EXPORT_SYMBOL_GPL vmlinux 0x518c2fc6 hpet_rtc_dropped_irq +EXPORT_SYMBOL_GPL vmlinux 0x51a4c094 unregister_kprobe +EXPORT_SYMBOL_GPL vmlinux 0x51dd6488 xfrm_aalg_get_byidx +EXPORT_SYMBOL_GPL vmlinux 0x52d111ea pm_qos_update_requirement +EXPORT_SYMBOL_GPL vmlinux 0x531daa18 tty_buffer_request_room +EXPORT_SYMBOL_GPL vmlinux 0x53565c65 xenbus_watch_pathfmt +EXPORT_SYMBOL_GPL vmlinux 0x53986488 register_die_notifier +EXPORT_SYMBOL_GPL vmlinux 0x53c2d13a platform_get_resource +EXPORT_SYMBOL_GPL vmlinux 0x53d36086 blk_end_request +EXPORT_SYMBOL_GPL vmlinux 0x543f4547 free_vm_area +EXPORT_SYMBOL_GPL vmlinux 0x547dd35a __rtnl_register +EXPORT_SYMBOL_GPL vmlinux 0x54e14341 relay_open +EXPORT_SYMBOL_GPL vmlinux 0x5525e708 tcp_death_row +EXPORT_SYMBOL_GPL vmlinux 0x55526907 xen_features +EXPORT_SYMBOL_GPL vmlinux 0x56398615 mark_tsc_unstable +EXPORT_SYMBOL_GPL vmlinux 0x5641485b tty_termios_encode_baud_rate +EXPORT_SYMBOL_GPL vmlinux 0x573f13b0 screen_glyph +EXPORT_SYMBOL_GPL vmlinux 0x575c5f94 execute_in_process_context +EXPORT_SYMBOL_GPL vmlinux 0x5779d445 xenbus_exists +EXPORT_SYMBOL_GPL vmlinux 0x579e0bf5 rtnl_unregister_all +EXPORT_SYMBOL_GPL vmlinux 0x579e79cf xfrm_output_resume +EXPORT_SYMBOL_GPL vmlinux 0x58013efe class_interface_register +EXPORT_SYMBOL_GPL vmlinux 0x58842224 uart_console_write +EXPORT_SYMBOL_GPL vmlinux 0x595cbe8f driver_add_kobj +EXPORT_SYMBOL_GPL vmlinux 0x597f3bc3 marker_get_private_data +EXPORT_SYMBOL_GPL vmlinux 0x59930a88 fib_rules_register +EXPORT_SYMBOL_GPL vmlinux 0x59f99611 uhci_check_and_reset_hc +EXPORT_SYMBOL_GPL vmlinux 0x5a1ebda4 unregister_net_sysctl_table +EXPORT_SYMBOL_GPL vmlinux 0x5a2b1b67 gnttab_free_grant_reference +EXPORT_SYMBOL_GPL vmlinux 0x5a8e4a9d skb_to_sgvec +EXPORT_SYMBOL_GPL vmlinux 0x5af03a28 gnttab_claim_grant_reference +EXPORT_SYMBOL_GPL vmlinux 0x5b392b04 hrtimer_try_to_cancel +EXPORT_SYMBOL_GPL vmlinux 0x5b4317cf crypto_mod_get +EXPORT_SYMBOL_GPL vmlinux 0x5b5ff40b power_supply_changed +EXPORT_SYMBOL_GPL vmlinux 0x5bb44a32 klist_add_head +EXPORT_SYMBOL_GPL vmlinux 0x5bfc03c3 unregister_keyboard_notifier +EXPORT_SYMBOL_GPL vmlinux 0x5cfcf0f1 percpu_free +EXPORT_SYMBOL_GPL vmlinux 0x5d0f6f57 kbd_table +EXPORT_SYMBOL_GPL vmlinux 0x5d366dec gnttab_cancel_free_callback +EXPORT_SYMBOL_GPL vmlinux 0x5d679e21 inet_csk_compat_getsockopt +EXPORT_SYMBOL_GPL vmlinux 0x5d730e7b raw_notifier_chain_unregister +EXPORT_SYMBOL_GPL vmlinux 0x5dade1a9 blk_execute_rq_nowait +EXPORT_SYMBOL_GPL vmlinux 0x5dd67618 register_netevent_notifier +EXPORT_SYMBOL_GPL vmlinux 0x5e916cdb platform_bus +EXPORT_SYMBOL_GPL vmlinux 0x5eb05848 raw_seq_next +EXPORT_SYMBOL_GPL vmlinux 0x5f10e819 attribute_container_classdev_to_container +EXPORT_SYMBOL_GPL vmlinux 0x5f2da8c4 check_tsc_unstable +EXPORT_SYMBOL_GPL vmlinux 0x5f408bac klist_next +EXPORT_SYMBOL_GPL vmlinux 0x5fe069c2 unregister_pernet_device +EXPORT_SYMBOL_GPL vmlinux 0x5fea940b hrtimer_forward +EXPORT_SYMBOL_GPL vmlinux 0x604068c7 fsstack_copy_inode_size +EXPORT_SYMBOL_GPL vmlinux 0x606d7398 xenbus_dev_fatal +EXPORT_SYMBOL_GPL vmlinux 0x6091797f synchronize_rcu +EXPORT_SYMBOL_GPL vmlinux 0x60a13e90 rcu_barrier +EXPORT_SYMBOL_GPL vmlinux 0x60aff99f xenbus_frontend_closed +EXPORT_SYMBOL_GPL vmlinux 0x61dcd665 tcp_done +EXPORT_SYMBOL_GPL vmlinux 0x62843a48 class_interface_unregister +EXPORT_SYMBOL_GPL vmlinux 0x629637b6 platform_driver_probe +EXPORT_SYMBOL_GPL vmlinux 0x6313ab08 rtc_class_open +EXPORT_SYMBOL_GPL vmlinux 0x631a9974 ip_local_out +EXPORT_SYMBOL_GPL vmlinux 0x639e12dc tcp_unregister_congestion_control +EXPORT_SYMBOL_GPL vmlinux 0x63ae27d6 add_nops +EXPORT_SYMBOL_GPL vmlinux 0x6485d13c devres_add +EXPORT_SYMBOL_GPL vmlinux 0x64e563e9 inet_twsk_alloc +EXPORT_SYMBOL_GPL vmlinux 0x657fd497 do_sync_mapping_range +EXPORT_SYMBOL_GPL vmlinux 0x65ccb6f0 call_netevent_notifiers +EXPORT_SYMBOL_GPL vmlinux 0x65d6d0f0 gpio_direction_input +EXPORT_SYMBOL_GPL vmlinux 0x65ee75c3 tty_find_polling_driver +EXPORT_SYMBOL_GPL vmlinux 0x6610ad99 synchronize_srcu +EXPORT_SYMBOL_GPL vmlinux 0x661601de sprint_symbol +EXPORT_SYMBOL_GPL vmlinux 0x6644e04f sysfs_add_file_to_group +EXPORT_SYMBOL_GPL vmlinux 0x664d14f7 platform_device_del +EXPORT_SYMBOL_GPL vmlinux 0x66b2a859 nr_free_buffer_pages +EXPORT_SYMBOL_GPL vmlinux 0x66d87d38 symbol_put_addr +EXPORT_SYMBOL_GPL vmlinux 0x6738b621 fib_rules_lookup +EXPORT_SYMBOL_GPL vmlinux 0x67955ce6 profile_hits +EXPORT_SYMBOL_GPL vmlinux 0x6834cc83 klist_add_after +EXPORT_SYMBOL_GPL vmlinux 0x686c703f xfrm_count_auth_supported +EXPORT_SYMBOL_GPL vmlinux 0x688df66c rtc_read_alarm +EXPORT_SYMBOL_GPL vmlinux 0x6892088c unregister_pm_notifier +EXPORT_SYMBOL_GPL vmlinux 0x689822cc devm_kfree +EXPORT_SYMBOL_GPL vmlinux 0x691884ef pv_apic_ops +EXPORT_SYMBOL_GPL vmlinux 0x697ee61b uart_set_options +EXPORT_SYMBOL_GPL vmlinux 0x6b07a368 klist_add_before +EXPORT_SYMBOL_GPL vmlinux 0x6b10495b devres_alloc +EXPORT_SYMBOL_GPL vmlinux 0x6b31b660 xfrm_audit_state_icvfail +EXPORT_SYMBOL_GPL vmlinux 0x6b9178b3 xenbus_strstate +EXPORT_SYMBOL_GPL vmlinux 0x6b93bf60 inet_twdr_twkill_work +EXPORT_SYMBOL_GPL vmlinux 0x6be62dfd probe_kernel_read +EXPORT_SYMBOL_GPL vmlinux 0x6bfd1ba9 pciserial_suspend_ports +EXPORT_SYMBOL_GPL vmlinux 0x6c02fc7c inet_hash_connect +EXPORT_SYMBOL_GPL vmlinux 0x6c11059b __srcu_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x6c49c4f2 clockevents_notify +EXPORT_SYMBOL_GPL vmlinux 0x6c82e92f x86_bios_freq_base +EXPORT_SYMBOL_GPL vmlinux 0x6c8d5ae8 __gpio_get_value +EXPORT_SYMBOL_GPL vmlinux 0x6cb6b12f put_device +EXPORT_SYMBOL_GPL vmlinux 0x6d27432b crypto_hash_walk_done +EXPORT_SYMBOL_GPL vmlinux 0x6d4299ea fnotify_change +EXPORT_SYMBOL_GPL vmlinux 0x6d5b11f4 attribute_container_register +EXPORT_SYMBOL_GPL vmlinux 0x6d629bc0 ip_route_output_flow +EXPORT_SYMBOL_GPL vmlinux 0x6e58ddf0 gnttab_end_foreign_transfer_ref +EXPORT_SYMBOL_GPL vmlinux 0x6ebb0a57 kobject_uevent_env +EXPORT_SYMBOL_GPL vmlinux 0x6f11b038 inet_unhash +EXPORT_SYMBOL_GPL vmlinux 0x6f211436 xenbus_unmap_ring_vfree +EXPORT_SYMBOL_GPL vmlinux 0x6f893983 register_pernet_gen_device +EXPORT_SYMBOL_GPL vmlinux 0x6f9c2efe marker_probe_cb +EXPORT_SYMBOL_GPL vmlinux 0x6ffb5b60 klist_add_tail +EXPORT_SYMBOL_GPL vmlinux 0x70075cb1 led_trigger_remove +EXPORT_SYMBOL_GPL vmlinux 0x702a6e6a init_pid_ns +EXPORT_SYMBOL_GPL vmlinux 0x7037d79d k8_flush_garts +EXPORT_SYMBOL_GPL vmlinux 0x71c8bc95 kgdb_unregister_io_module +EXPORT_SYMBOL_GPL vmlinux 0x71cea111 put_driver +EXPORT_SYMBOL_GPL vmlinux 0x72598bb0 init_user_ns +EXPORT_SYMBOL_GPL vmlinux 0x7278d328 all_vm_events +EXPORT_SYMBOL_GPL vmlinux 0x731433ee unregister_timer_hook +EXPORT_SYMBOL_GPL vmlinux 0x73201149 klist_iter_init_node +EXPORT_SYMBOL_GPL vmlinux 0x7342836e pci_disable_pcie_error_reporting +EXPORT_SYMBOL_GPL vmlinux 0x73b1f76d do_posix_clock_nosettime +EXPORT_SYMBOL_GPL vmlinux 0x74544739 rt_mutex_unlock +EXPORT_SYMBOL_GPL vmlinux 0x7489ac58 driver_unregister +EXPORT_SYMBOL_GPL vmlinux 0x74abdafa task_handoff_register +EXPORT_SYMBOL_GPL vmlinux 0x74d61a4d get_dcookie +EXPORT_SYMBOL_GPL vmlinux 0x7521afb6 leave_mm +EXPORT_SYMBOL_GPL vmlinux 0x75ce259a sysdev_class_remove_file +EXPORT_SYMBOL_GPL vmlinux 0x75e8f3c3 crypto_register_notifier +EXPORT_SYMBOL_GPL vmlinux 0x7612c257 crypto_hash_type +EXPORT_SYMBOL_GPL vmlinux 0x762d809c net_assign_generic +EXPORT_SYMBOL_GPL vmlinux 0x76a679c3 rtnl_put_cacheinfo +EXPORT_SYMBOL_GPL vmlinux 0x76ada266 tcp_is_cwnd_limited +EXPORT_SYMBOL_GPL vmlinux 0x7712771a unbind_from_irqhandler +EXPORT_SYMBOL_GPL vmlinux 0x77620316 device_find_child +EXPORT_SYMBOL_GPL vmlinux 0x77954ed4 nf_register_afinfo +EXPORT_SYMBOL_GPL vmlinux 0x78fa77c7 sysdev_store_int +EXPORT_SYMBOL_GPL vmlinux 0x79115873 crypto_unregister_alg +EXPORT_SYMBOL_GPL vmlinux 0x7927d8a8 raw_hash_sk +EXPORT_SYMBOL_GPL vmlinux 0x7a0c257c bus_create_file +EXPORT_SYMBOL_GPL vmlinux 0x7a393193 crypto_alg_mod_lookup +EXPORT_SYMBOL_GPL vmlinux 0x7a4c1438 pv_info +EXPORT_SYMBOL_GPL vmlinux 0x7ac10ebc uv_node_to_blade +EXPORT_SYMBOL_GPL vmlinux 0x7b1d544d edac_handler_set +EXPORT_SYMBOL_GPL vmlinux 0x7b20543f vfs_setlease +EXPORT_SYMBOL_GPL vmlinux 0x7b47588d debugfs_create_u16 +EXPORT_SYMBOL_GPL vmlinux 0x7b6cbb67 device_create_file +EXPORT_SYMBOL_GPL vmlinux 0x7c07d61c pskb_put +EXPORT_SYMBOL_GPL vmlinux 0x7c52826e fib_rules_cleanup_ops +EXPORT_SYMBOL_GPL vmlinux 0x7c6b16b1 platform_device_add_resources +EXPORT_SYMBOL_GPL vmlinux 0x7c6d7605 blocking_notifier_chain_unregister +EXPORT_SYMBOL_GPL vmlinux 0x7c7e692d alloc_page_buffers +EXPORT_SYMBOL_GPL vmlinux 0x7d62cc28 pci_create_slot +EXPORT_SYMBOL_GPL vmlinux 0x7da8d037 marker_probe_register +EXPORT_SYMBOL_GPL vmlinux 0x7dc5d0b6 crypto_unregister_notifier +EXPORT_SYMBOL_GPL vmlinux 0x7ded3f1d inet_csk_reqsk_queue_prune +EXPORT_SYMBOL_GPL vmlinux 0x7e59a2d0 xenbus_alloc_evtchn +EXPORT_SYMBOL_GPL vmlinux 0x7e8633c9 get_inotify_watch +EXPORT_SYMBOL_GPL vmlinux 0x7ec83ccc fsstack_copy_attr_all +EXPORT_SYMBOL_GPL vmlinux 0x7f0aac9d sysfs_create_link +EXPORT_SYMBOL_GPL vmlinux 0x7f19a9bf spi_unregister_master +EXPORT_SYMBOL_GPL vmlinux 0x7f19c836 unlock_policy_rwsem_write +EXPORT_SYMBOL_GPL vmlinux 0x7f27564e fb_deferred_io_cleanup +EXPORT_SYMBOL_GPL vmlinux 0x7fc3c90d rtc_set_alarm +EXPORT_SYMBOL_GPL vmlinux 0x7ff10ccf raw_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x8039d043 selinux_secmark_relabel_packet_permission +EXPORT_SYMBOL_GPL vmlinux 0x8088d5ba led_trigger_set_default +EXPORT_SYMBOL_GPL vmlinux 0x80eac2a6 device_attach +EXPORT_SYMBOL_GPL vmlinux 0x80ee55c3 selinux_secmark_refcount_inc +EXPORT_SYMBOL_GPL vmlinux 0x80f9fb84 sysfs_create_file +EXPORT_SYMBOL_GPL vmlinux 0x81cdc540 mnt_want_write +EXPORT_SYMBOL_GPL vmlinux 0x81e6fa78 bus_get_kset +EXPORT_SYMBOL_GPL vmlinux 0x8226642f __gpio_cansleep +EXPORT_SYMBOL_GPL vmlinux 0x823a47a1 crypto_register_template +EXPORT_SYMBOL_GPL vmlinux 0x826360fd do_posix_clock_nonanosleep +EXPORT_SYMBOL_GPL vmlinux 0x829f0d2f skb_partial_csum_set +EXPORT_SYMBOL_GPL vmlinux 0x82af6582 platform_driver_register +EXPORT_SYMBOL_GPL vmlinux 0x82bfaee4 tty_prepare_flip_string +EXPORT_SYMBOL_GPL vmlinux 0x82cd19f3 register_xenstore_notifier +EXPORT_SYMBOL_GPL vmlinux 0x82d46785 inotify_dentry_parent_queue_event +EXPORT_SYMBOL_GPL vmlinux 0x82d79b51 sysctl_vfs_cache_pressure +EXPORT_SYMBOL_GPL vmlinux 0x82f776b7 gpio_export +EXPORT_SYMBOL_GPL vmlinux 0x8315abb2 raw_seq_start +EXPORT_SYMBOL_GPL vmlinux 0x835074f5 rtnl_register +EXPORT_SYMBOL_GPL vmlinux 0x83640498 crypto_mod_put +EXPORT_SYMBOL_GPL vmlinux 0x836a6f89 xfrm_audit_state_notfound +EXPORT_SYMBOL_GPL vmlinux 0x83afa919 register_pernet_device +EXPORT_SYMBOL_GPL vmlinux 0x83e40b1f cpufreq_cpu_get +EXPORT_SYMBOL_GPL vmlinux 0x83f5d687 sysdev_driver_register +EXPORT_SYMBOL_GPL vmlinux 0x83f6b2d2 dma_get_required_mask +EXPORT_SYMBOL_GPL vmlinux 0x84869be8 fb_deferred_io_fsync +EXPORT_SYMBOL_GPL vmlinux 0x85a750bf __blk_add_trace +EXPORT_SYMBOL_GPL vmlinux 0x85c10896 rcu_batches_completed_bh +EXPORT_SYMBOL_GPL vmlinux 0x85c15f9c __blk_put_request +EXPORT_SYMBOL_GPL vmlinux 0x85d7edfd hpet_set_periodic_freq +EXPORT_SYMBOL_GPL vmlinux 0x85d86844 kobject_init_and_add +EXPORT_SYMBOL_GPL vmlinux 0x85e5a3db ktime_get_ts +EXPORT_SYMBOL_GPL vmlinux 0x860e76a9 crypto_ahash_type +EXPORT_SYMBOL_GPL vmlinux 0x861cc2cc proc_net_mkdir +EXPORT_SYMBOL_GPL vmlinux 0x863f0092 __cpufreq_driver_getavg +EXPORT_SYMBOL_GPL vmlinux 0x86623fd7 notify_remote_via_irq +EXPORT_SYMBOL_GPL vmlinux 0x868784cb __symbol_get +EXPORT_SYMBOL_GPL vmlinux 0x8694affa relay_file_operations +EXPORT_SYMBOL_GPL vmlinux 0x86a51007 gnttab_end_foreign_transfer +EXPORT_SYMBOL_GPL vmlinux 0x86b1667d hwrng_unregister +EXPORT_SYMBOL_GPL vmlinux 0x871a9910 register_kprobes +EXPORT_SYMBOL_GPL vmlinux 0x873fbaea edac_atomic_assert_error +EXPORT_SYMBOL_GPL vmlinux 0x87754115 raw_notifier_chain_register +EXPORT_SYMBOL_GPL vmlinux 0x87f2cf3a blocking_notifier_chain_cond_register +EXPORT_SYMBOL_GPL vmlinux 0x880b189a __atomic_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x8810ad5e crypto_xor +EXPORT_SYMBOL_GPL vmlinux 0x885142a6 nf_net_netfilter_sysctl_path +EXPORT_SYMBOL_GPL vmlinux 0x887d2576 __crypto_alg_lookup +EXPORT_SYMBOL_GPL vmlinux 0x88f0db24 cancel_work_sync +EXPORT_SYMBOL_GPL vmlinux 0x89165e6e blk_trace_setup +EXPORT_SYMBOL_GPL vmlinux 0x891bf7e9 cpufreq_register_governor +EXPORT_SYMBOL_GPL vmlinux 0x89a81636 transport_configure_device +EXPORT_SYMBOL_GPL vmlinux 0x89bae393 platform_bus_type +EXPORT_SYMBOL_GPL vmlinux 0x89e3642e rtc_read_time +EXPORT_SYMBOL_GPL vmlinux 0x8a625087 pci_unblock_user_cfg_access +EXPORT_SYMBOL_GPL vmlinux 0x8a8ff62f vlan_dev_real_dev +EXPORT_SYMBOL_GPL vmlinux 0x8abed13d xfrm_aead_get_byname +EXPORT_SYMBOL_GPL vmlinux 0x8ac15e85 inotify_rm_watch +EXPORT_SYMBOL_GPL vmlinux 0x8b0f003d device_schedule_callback_owner +EXPORT_SYMBOL_GPL vmlinux 0x8b4f208e do_kern_mount +EXPORT_SYMBOL_GPL vmlinux 0x8b65ecc8 platform_driver_unregister +EXPORT_SYMBOL_GPL vmlinux 0x8b81d720 xenbus_switch_state +EXPORT_SYMBOL_GPL vmlinux 0x8b9200fd lookup_address +EXPORT_SYMBOL_GPL vmlinux 0x8c06a108 xenbus_transaction_start +EXPORT_SYMBOL_GPL vmlinux 0x8c38074a unregister_xenstore_notifier +EXPORT_SYMBOL_GPL vmlinux 0x8d4c2bb7 inet6_lookup_listener +EXPORT_SYMBOL_GPL vmlinux 0x8d4c2fdf flush_workqueue +EXPORT_SYMBOL_GPL vmlinux 0x8ddf68a7 inotify_rm_wd +EXPORT_SYMBOL_GPL vmlinux 0x8eb58c6e __wake_up_sync +EXPORT_SYMBOL_GPL vmlinux 0x8ee53b1e inverse_translate +EXPORT_SYMBOL_GPL vmlinux 0x8ef4891e device_remove_bin_file +EXPORT_SYMBOL_GPL vmlinux 0x8f6cee77 __round_jiffies_relative +EXPORT_SYMBOL_GPL vmlinux 0x8f6d851c __mmdrop +EXPORT_SYMBOL_GPL vmlinux 0x8fdc8162 netlink_has_listeners +EXPORT_SYMBOL_GPL vmlinux 0x9009602a acpi_bus_get_ejd +EXPORT_SYMBOL_GPL vmlinux 0x906b805e srcu_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x90a1004a crypto_has_alg +EXPORT_SYMBOL_GPL vmlinux 0x90bfc439 pci_intx +EXPORT_SYMBOL_GPL vmlinux 0x90c738bc elv_register +EXPORT_SYMBOL_GPL vmlinux 0x90e24811 preempt_notifier_unregister +EXPORT_SYMBOL_GPL vmlinux 0x90f94ef8 led_trigger_unregister_simple +EXPORT_SYMBOL_GPL vmlinux 0x9159b9d6 profile_event_register +EXPORT_SYMBOL_GPL vmlinux 0x917445dc power_supply_unregister +EXPORT_SYMBOL_GPL vmlinux 0x9192b8fe gpiochip_remove +EXPORT_SYMBOL_GPL vmlinux 0x91dacaa2 acpi_processor_ffh_cstate_probe +EXPORT_SYMBOL_GPL vmlinux 0x91e83a09 rtc_irq_set_state +EXPORT_SYMBOL_GPL vmlinux 0x91fd4fb8 device_rename +EXPORT_SYMBOL_GPL vmlinux 0x92183295 crypto_chain +EXPORT_SYMBOL_GPL vmlinux 0x92238352 led_trigger_store +EXPORT_SYMBOL_GPL vmlinux 0x9241c3ee device_power_down +EXPORT_SYMBOL_GPL vmlinux 0x92445aee hrtimer_get_res +EXPORT_SYMBOL_GPL vmlinux 0x924f366e exit_fs +EXPORT_SYMBOL_GPL vmlinux 0x92fb217b dcookie_unregister +EXPORT_SYMBOL_GPL vmlinux 0x9388c53b tcp_init_congestion_ops +EXPORT_SYMBOL_GPL vmlinux 0x93a2fc0f tty_encode_baud_rate +EXPORT_SYMBOL_GPL vmlinux 0x93d2422d snmp_mib_free +EXPORT_SYMBOL_GPL vmlinux 0x93e4a8a0 simple_attr_open +EXPORT_SYMBOL_GPL vmlinux 0x942c1704 cleanup_srcu_struct +EXPORT_SYMBOL_GPL vmlinux 0x94822b45 inet_diag_unregister +EXPORT_SYMBOL_GPL vmlinux 0x94d742f6 pcie_port_bus_type +EXPORT_SYMBOL_GPL vmlinux 0x952664c5 do_exit +EXPORT_SYMBOL_GPL vmlinux 0x9552df38 device_create_vargs +EXPORT_SYMBOL_GPL vmlinux 0x956a91ba gpio_get_value_cansleep +EXPORT_SYMBOL_GPL vmlinux 0x9577271c hpet_rtc_interrupt +EXPORT_SYMBOL_GPL vmlinux 0x95d2a718 crypto_enqueue_request +EXPORT_SYMBOL_GPL vmlinux 0x961a8cd3 unlock_policy_rwsem_read +EXPORT_SYMBOL_GPL vmlinux 0x964d5c39 acpi_os_map_memory +EXPORT_SYMBOL_GPL vmlinux 0x966d7352 transport_destroy_device +EXPORT_SYMBOL_GPL vmlinux 0x967fda38 rtc_class_close +EXPORT_SYMBOL_GPL vmlinux 0x96cbcf31 pm_qos_add_notifier +EXPORT_SYMBOL_GPL vmlinux 0x97028da3 led_trigger_register +EXPORT_SYMBOL_GPL vmlinux 0x976fbcbd tcp_reno_min_cwnd +EXPORT_SYMBOL_GPL vmlinux 0x9795720e bus_get_device_klist +EXPORT_SYMBOL_GPL vmlinux 0x981ad70f inet6_lookup +EXPORT_SYMBOL_GPL vmlinux 0x9833bc0c hvc_kick +EXPORT_SYMBOL_GPL vmlinux 0x98531f95 xfrm_audit_state_notfound_simple +EXPORT_SYMBOL_GPL vmlinux 0x988b642c device_unregister +EXPORT_SYMBOL_GPL vmlinux 0x995d1071 prof_on +EXPORT_SYMBOL_GPL vmlinux 0x999a0c6a input_ff_erase +EXPORT_SYMBOL_GPL vmlinux 0x9a11a0fc crypto_attr_alg_name +EXPORT_SYMBOL_GPL vmlinux 0x9a398f5c xfrm_ealg_get_byname +EXPORT_SYMBOL_GPL vmlinux 0x9a69acf9 tty_mode_ioctl +EXPORT_SYMBOL_GPL vmlinux 0x9b1220e6 blk_rq_bytes +EXPORT_SYMBOL_GPL vmlinux 0x9ba0501e unregister_vt_notifier +EXPORT_SYMBOL_GPL vmlinux 0x9bdf1586 proc_net_fops_create +EXPORT_SYMBOL_GPL vmlinux 0x9bfc99ee simple_attr_read +EXPORT_SYMBOL_GPL vmlinux 0x9c7b96cf vfs_removexattr +EXPORT_SYMBOL_GPL vmlinux 0x9cb8037b xfrm_count_enc_supported +EXPORT_SYMBOL_GPL vmlinux 0x9d06688b register_xenbus_watch +EXPORT_SYMBOL_GPL vmlinux 0x9d3850e1 gnttab_alloc_grant_references +EXPORT_SYMBOL_GPL vmlinux 0x9de44396 anon_inode_getfd +EXPORT_SYMBOL_GPL vmlinux 0x9de6c874 inet_csk_bind_conflict +EXPORT_SYMBOL_GPL vmlinux 0x9e25bfa6 fb_bl_default_curve +EXPORT_SYMBOL_GPL vmlinux 0x9e711ad2 pm_qos_requirement +EXPORT_SYMBOL_GPL vmlinux 0x9e7d3442 xenbus_resume +EXPORT_SYMBOL_GPL vmlinux 0x9e9662ab user_describe +EXPORT_SYMBOL_GPL vmlinux 0x9f51582e pci_find_ht_capability +EXPORT_SYMBOL_GPL vmlinux 0x9fce80db fb_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0x9fcf7653 pci_bus_add_device +EXPORT_SYMBOL_GPL vmlinux 0x9ff9b2bd rtnl_link_register +EXPORT_SYMBOL_GPL vmlinux 0xa0255440 net_ipv4_ctl_path +EXPORT_SYMBOL_GPL vmlinux 0xa06724b2 default_backing_dev_info +EXPORT_SYMBOL_GPL vmlinux 0xa09fdf59 sysfs_notify +EXPORT_SYMBOL_GPL vmlinux 0xa0a612a0 device_del +EXPORT_SYMBOL_GPL vmlinux 0xa0c30548 debugfs_create_dir +EXPORT_SYMBOL_GPL vmlinux 0xa10360ff kern_mount_data +EXPORT_SYMBOL_GPL vmlinux 0xa1596d98 acpi_processor_ffh_cstate_enter +EXPORT_SYMBOL_GPL vmlinux 0xa1eea7bc cpuidle_register_device +EXPORT_SYMBOL_GPL vmlinux 0xa1f90571 platform_device_add +EXPORT_SYMBOL_GPL vmlinux 0xa2c03841 bind_evtchn_to_irqhandler +EXPORT_SYMBOL_GPL vmlinux 0xa2e67f08 acpi_bus_generate_proc_event4 +EXPORT_SYMBOL_GPL vmlinux 0xa2f1e19f class_for_each_device +EXPORT_SYMBOL_GPL vmlinux 0xa306d6fc relay_buf_full +EXPORT_SYMBOL_GPL vmlinux 0xa313b981 generic_fh_to_dentry +EXPORT_SYMBOL_GPL vmlinux 0xa3165bd4 tty_ldisc_flush +EXPORT_SYMBOL_GPL vmlinux 0xa3499aec get_device +EXPORT_SYMBOL_GPL vmlinux 0xa353fffc xenbus_rm +EXPORT_SYMBOL_GPL vmlinux 0xa37b3022 blkdev_ioctl +EXPORT_SYMBOL_GPL vmlinux 0xa3f560c1 skb_cow_data +EXPORT_SYMBOL_GPL vmlinux 0xa3fc96f0 marker_probe_cb_noarg +EXPORT_SYMBOL_GPL vmlinux 0xa452c297 hpet_mask_rtc_irq_bit +EXPORT_SYMBOL_GPL vmlinux 0xa47145a5 nf_unregister_afinfo +EXPORT_SYMBOL_GPL vmlinux 0xa4d58669 math_state_restore +EXPORT_SYMBOL_GPL vmlinux 0xa4f1c318 set_cpus_allowed_ptr +EXPORT_SYMBOL_GPL vmlinux 0xa557d46f crypto_larval_lookup +EXPORT_SYMBOL_GPL vmlinux 0xa5622624 power_supply_register +EXPORT_SYMBOL_GPL vmlinux 0xa5bf5c3e pm_qos_add_requirement +EXPORT_SYMBOL_GPL vmlinux 0xa5c36cec inotify_unmount_inodes +EXPORT_SYMBOL_GPL vmlinux 0xa694453e preempt_notifier_register +EXPORT_SYMBOL_GPL vmlinux 0xa7235bb8 input_ff_create +EXPORT_SYMBOL_GPL vmlinux 0xa7fcb6ef inet_csk_route_req +EXPORT_SYMBOL_GPL vmlinux 0xa815dda5 gpiochip_add +EXPORT_SYMBOL_GPL vmlinux 0xa878c628 __audit_inode_child +EXPORT_SYMBOL_GPL vmlinux 0xa8f59416 gpio_direction_output +EXPORT_SYMBOL_GPL vmlinux 0xa9126bff hpet_set_rtc_irq_bit +EXPORT_SYMBOL_GPL vmlinux 0xa963f49c tcp_orphan_count +EXPORT_SYMBOL_GPL vmlinux 0xa97310db __inet_twsk_hashdance +EXPORT_SYMBOL_GPL vmlinux 0xa9c530b8 unregister_oom_notifier +EXPORT_SYMBOL_GPL vmlinux 0xaa429881 sysfs_update_group +EXPORT_SYMBOL_GPL vmlinux 0xaa86cfb5 uv_possible_blades +EXPORT_SYMBOL_GPL vmlinux 0xaa8c4696 cpu_clock +EXPORT_SYMBOL_GPL vmlinux 0xaa9aa97a queue_work_on +EXPORT_SYMBOL_GPL vmlinux 0xaad399dc __get_vm_area +EXPORT_SYMBOL_GPL vmlinux 0xab01acbe gnttab_request_free_callback +EXPORT_SYMBOL_GPL vmlinux 0xab398839 pci_cleanup_aer_uncorrect_error_status +EXPORT_SYMBOL_GPL vmlinux 0xabc28976 force_evtchn_callback +EXPORT_SYMBOL_GPL vmlinux 0xabe9e854 put_pid +EXPORT_SYMBOL_GPL vmlinux 0xac1ee37d sysdev_store_ulong +EXPORT_SYMBOL_GPL vmlinux 0xacc19485 ibft_addr +EXPORT_SYMBOL_GPL vmlinux 0xacd03c8c rtc_set_time +EXPORT_SYMBOL_GPL vmlinux 0xad096363 xenbus_printf +EXPORT_SYMBOL_GPL vmlinux 0xad63a24e per_cpu____uv_hub_info +EXPORT_SYMBOL_GPL vmlinux 0xae0c87ee pm_qos_remove_notifier +EXPORT_SYMBOL_GPL vmlinux 0xaec245ed sysdev_driver_unregister +EXPORT_SYMBOL_GPL vmlinux 0xaf35b9db driver_create_file +EXPORT_SYMBOL_GPL vmlinux 0xafae3c4b pci_stop_bus_device +EXPORT_SYMBOL_GPL vmlinux 0xafdfa5ff platform_get_irq_byname +EXPORT_SYMBOL_GPL vmlinux 0xafe3ca88 crypto_attr_alg +EXPORT_SYMBOL_GPL vmlinux 0xb0889179 swiotlb_sync_single_range_for_device +EXPORT_SYMBOL_GPL vmlinux 0xb10d55bc cn_netlink_send +EXPORT_SYMBOL_GPL vmlinux 0xb120ab95 klist_remove +EXPORT_SYMBOL_GPL vmlinux 0xb1acbcce rcu_barrier_sched +EXPORT_SYMBOL_GPL vmlinux 0xb2196033 gpiochip_is_requested +EXPORT_SYMBOL_GPL vmlinux 0xb221ee72 pci_destroy_slot +EXPORT_SYMBOL_GPL vmlinux 0xb252fbdd agp_remove_bridge +EXPORT_SYMBOL_GPL vmlinux 0xb27005f5 device_suspend +EXPORT_SYMBOL_GPL vmlinux 0xb2b10979 debugfs_create_x32 +EXPORT_SYMBOL_GPL vmlinux 0xb3253ed9 hpet_rtc_timer_init +EXPORT_SYMBOL_GPL vmlinux 0xb37474a4 power_supply_class +EXPORT_SYMBOL_GPL vmlinux 0xb3a0bd63 inet6_hash_connect +EXPORT_SYMBOL_GPL vmlinux 0xb3c6720c __rtnl_link_register +EXPORT_SYMBOL_GPL vmlinux 0xb3e0b0f0 devres_release_group +EXPORT_SYMBOL_GPL vmlinux 0xb46c54ab hwmon_device_unregister +EXPORT_SYMBOL_GPL vmlinux 0xb4e14553 gnttab_query_foreign_access +EXPORT_SYMBOL_GPL vmlinux 0xb4ea7cf7 kgdb_connected +EXPORT_SYMBOL_GPL vmlinux 0xb51cd6a6 device_create_bin_file +EXPORT_SYMBOL_GPL vmlinux 0xb51fbd64 edac_op_state +EXPORT_SYMBOL_GPL vmlinux 0xb53ae573 cpu_idle_wait +EXPORT_SYMBOL_GPL vmlinux 0xb5c18a16 device_release_driver +EXPORT_SYMBOL_GPL vmlinux 0xb612444d snmp_mib_init +EXPORT_SYMBOL_GPL vmlinux 0xb61c5c63 platform_device_register_simple +EXPORT_SYMBOL_GPL vmlinux 0xb6230f1f gnttab_grant_foreign_access +EXPORT_SYMBOL_GPL vmlinux 0xb63550f5 __i2c_board_lock +EXPORT_SYMBOL_GPL vmlinux 0xb65091b3 selinux_secmark_refcount_dec +EXPORT_SYMBOL_GPL vmlinux 0xb6d0eace mmu_notifier_unregister +EXPORT_SYMBOL_GPL vmlinux 0xb6e62bbb __class_register +EXPORT_SYMBOL_GPL vmlinux 0xb7014595 __trace_note_message +EXPORT_SYMBOL_GPL vmlinux 0xb7104dbb cpufreq_driver_target +EXPORT_SYMBOL_GPL vmlinux 0xb7a70397 d_materialise_unique +EXPORT_SYMBOL_GPL vmlinux 0xb7b443de sysfs_remove_group +EXPORT_SYMBOL_GPL vmlinux 0xb7d7c12e hpet_set_alarm_time +EXPORT_SYMBOL_GPL vmlinux 0xb903674c scatterwalk_map_and_copy +EXPORT_SYMBOL_GPL vmlinux 0xb9291bc2 sysfs_remove_file +EXPORT_SYMBOL_GPL vmlinux 0xb9761b49 alloc_vm_area +EXPORT_SYMBOL_GPL vmlinux 0xb97e6c02 anon_transport_class_register +EXPORT_SYMBOL_GPL vmlinux 0xb99d5837 xenbus_read +EXPORT_SYMBOL_GPL vmlinux 0xb9eb3aa9 add_uevent_var +EXPORT_SYMBOL_GPL vmlinux 0xb9edd4f8 apply_to_page_range +EXPORT_SYMBOL_GPL vmlinux 0xba4de1dd sysfs_create_group +EXPORT_SYMBOL_GPL vmlinux 0xba8352af audit_log_vformat +EXPORT_SYMBOL_GPL vmlinux 0xbb29f2cf vfs_setxattr +EXPORT_SYMBOL_GPL vmlinux 0xbb7295b5 power_supply_am_i_supplied +EXPORT_SYMBOL_GPL vmlinux 0xbbb98859 edid_info +EXPORT_SYMBOL_GPL vmlinux 0xbbc9a768 relay_subbufs_consumed +EXPORT_SYMBOL_GPL vmlinux 0xbbd1e034 device_register +EXPORT_SYMBOL_GPL vmlinux 0xbc089f3b __class_create +EXPORT_SYMBOL_GPL vmlinux 0xbd0f4a30 inet_csk_search_req +EXPORT_SYMBOL_GPL vmlinux 0xbe7ef09b pci_set_pcie_reset_state +EXPORT_SYMBOL_GPL vmlinux 0xbf00a09b spi_busnum_to_master +EXPORT_SYMBOL_GPL vmlinux 0xbf74eb20 probe_kernel_write +EXPORT_SYMBOL_GPL vmlinux 0xc08015b1 cpuidle_unregister_device +EXPORT_SYMBOL_GPL vmlinux 0xc097eb8e hrtimer_get_remaining +EXPORT_SYMBOL_GPL vmlinux 0xc0ce6b54 cpuidle_unregister_driver +EXPORT_SYMBOL_GPL vmlinux 0xc11038d0 inotify_find_update_watch +EXPORT_SYMBOL_GPL vmlinux 0xc1133988 led_trigger_event +EXPORT_SYMBOL_GPL vmlinux 0xc1184bc8 sysfs_remove_file_from_group +EXPORT_SYMBOL_GPL vmlinux 0xc1285beb tty_put_char +EXPORT_SYMBOL_GPL vmlinux 0xc18ad2c1 devres_find +EXPORT_SYMBOL_GPL vmlinux 0xc1f351d3 unregister_kretprobes +EXPORT_SYMBOL_GPL vmlinux 0xc226b1e1 crypto_hash_walk_first +EXPORT_SYMBOL_GPL vmlinux 0xc26351f8 bind_evtchn_to_irq +EXPORT_SYMBOL_GPL vmlinux 0xc26aba23 firmware_kobj +EXPORT_SYMBOL_GPL vmlinux 0xc2945138 bus_remove_file +EXPORT_SYMBOL_GPL vmlinux 0xc2c93e67 fib_rules_unregister +EXPORT_SYMBOL_GPL vmlinux 0xc34efe27 snmp_fold_field +EXPORT_SYMBOL_GPL vmlinux 0xc427a823 crypto_larval_kill +EXPORT_SYMBOL_GPL vmlinux 0xc42f2f94 xenbus_read_driver_state +EXPORT_SYMBOL_GPL vmlinux 0xc4ddecd7 cpufreq_cpu_put +EXPORT_SYMBOL_GPL vmlinux 0xc509bb71 crypto_unregister_template +EXPORT_SYMBOL_GPL vmlinux 0xc512626a __supported_pte_mask +EXPORT_SYMBOL_GPL vmlinux 0xc5397da6 xenbus_mkdir +EXPORT_SYMBOL_GPL vmlinux 0xc5b4e65b hvc_poll +EXPORT_SYMBOL_GPL vmlinux 0xc625cc57 inet_csk_addr2sockaddr +EXPORT_SYMBOL_GPL vmlinux 0xc647dabc rt_mutex_trylock +EXPORT_SYMBOL_GPL vmlinux 0xc68976a8 spi_alloc_device +EXPORT_SYMBOL_GPL vmlinux 0xc7592c31 pci_find_aer_capability +EXPORT_SYMBOL_GPL vmlinux 0xc7ec11f6 atomic_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0xc7f603ba ip_build_and_send_pkt +EXPORT_SYMBOL_GPL vmlinux 0xc81be572 kobject_create_and_add +EXPORT_SYMBOL_GPL vmlinux 0xc81d40a6 hrtimer_cancel +EXPORT_SYMBOL_GPL vmlinux 0xc87c1f84 ktime_get +EXPORT_SYMBOL_GPL vmlinux 0xc87e487a sched_clock_idle_sleep_event +EXPORT_SYMBOL_GPL vmlinux 0xc8d563aa inet_twsk_schedule +EXPORT_SYMBOL_GPL vmlinux 0xc9561772 fb_destroy_modelist +EXPORT_SYMBOL_GPL vmlinux 0xc9878077 vfs_getxattr +EXPORT_SYMBOL_GPL vmlinux 0xc9b50daf get_current_tty +EXPORT_SYMBOL_GPL vmlinux 0xca81ea9a xenbus_transaction_end +EXPORT_SYMBOL_GPL vmlinux 0xcabe04de cpuidle_resume_and_unlock +EXPORT_SYMBOL_GPL vmlinux 0xcb131356 proc_net_remove +EXPORT_SYMBOL_GPL vmlinux 0xcbd7a5ee inet_csk_listen_stop +EXPORT_SYMBOL_GPL vmlinux 0xcbf20127 klist_iter_init +EXPORT_SYMBOL_GPL vmlinux 0xcc018d9c register_kprobe +EXPORT_SYMBOL_GPL vmlinux 0xcc1f1c3d inet_twdr_hangman +EXPORT_SYMBOL_GPL vmlinux 0xcc55902e posix_timer_event +EXPORT_SYMBOL_GPL vmlinux 0xcd80211d invalidate_inode_pages2 +EXPORT_SYMBOL_GPL vmlinux 0xcda73000 devres_open_group +EXPORT_SYMBOL_GPL vmlinux 0xcde9679b cpuidle_register_driver +EXPORT_SYMBOL_GPL vmlinux 0xcf024a73 console_drivers +EXPORT_SYMBOL_GPL vmlinux 0xcf7335a4 relay_switch_subbuf +EXPORT_SYMBOL_GPL vmlinux 0xcf982013 __pneigh_lookup +EXPORT_SYMBOL_GPL vmlinux 0xcfcc83ad register_vt_notifier +EXPORT_SYMBOL_GPL vmlinux 0xcffad590 seq_open_net +EXPORT_SYMBOL_GPL vmlinux 0xd027a07d marker_probe_unregister +EXPORT_SYMBOL_GPL vmlinux 0xd03c7700 secure_ipv4_port_ephemeral +EXPORT_SYMBOL_GPL vmlinux 0xd0674f85 rtc_irq_register +EXPORT_SYMBOL_GPL vmlinux 0xd0764ae2 crypto_alloc_instance +EXPORT_SYMBOL_GPL vmlinux 0xd0c05159 emergency_restart +EXPORT_SYMBOL_GPL vmlinux 0xd10c15cd pci_scan_child_bus +EXPORT_SYMBOL_GPL vmlinux 0xd162f18a find_pid_ns +EXPORT_SYMBOL_GPL vmlinux 0xd16712f3 crypto_check_attr_type +EXPORT_SYMBOL_GPL vmlinux 0xd1ee0737 device_add +EXPORT_SYMBOL_GPL vmlinux 0xd34003a7 find_vpid +EXPORT_SYMBOL_GPL vmlinux 0xd3b19ecd rt_mutex_lock +EXPORT_SYMBOL_GPL vmlinux 0xd3b78da3 xenbus_suspend_cancel +EXPORT_SYMBOL_GPL vmlinux 0xd3ef4639 transport_class_unregister +EXPORT_SYMBOL_GPL vmlinux 0xd44bcdb7 unregister_kretprobe +EXPORT_SYMBOL_GPL vmlinux 0xd51036aa nf_unregister_queue_handlers +EXPORT_SYMBOL_GPL vmlinux 0xd516bffd platform_device_add_data +EXPORT_SYMBOL_GPL vmlinux 0xd63bfaf6 raw_unhash_sk +EXPORT_SYMBOL_GPL vmlinux 0xd6a51ac1 debugfs_remove +EXPORT_SYMBOL_GPL vmlinux 0xd6feefa5 agp_num_entries +EXPORT_SYMBOL_GPL vmlinux 0xd7d79132 put_online_cpus +EXPORT_SYMBOL_GPL vmlinux 0xd82f8964 devres_get +EXPORT_SYMBOL_GPL vmlinux 0xd869cc44 securityfs_create_dir +EXPORT_SYMBOL_GPL vmlinux 0xd9042fa8 scatterwalk_map +EXPORT_SYMBOL_GPL vmlinux 0xd9f8681a attribute_container_unregister +EXPORT_SYMBOL_GPL vmlinux 0xda680a07 fb_deferred_io_init +EXPORT_SYMBOL_GPL vmlinux 0xda77b6fe seq_release_net +EXPORT_SYMBOL_GPL vmlinux 0xdaaa88c2 hwmon_device_register +EXPORT_SYMBOL_GPL vmlinux 0xdab73ce8 vfs_kern_mount +EXPORT_SYMBOL_GPL vmlinux 0xdac7687b queue_work +EXPORT_SYMBOL_GPL vmlinux 0xdaf4dfb3 fb_mode_option +EXPORT_SYMBOL_GPL vmlinux 0xdb2558e7 inet_diag_register +EXPORT_SYMBOL_GPL vmlinux 0xdbee78fe spi_alloc_master +EXPORT_SYMBOL_GPL vmlinux 0xdc1f8f2e register_timer_hook +EXPORT_SYMBOL_GPL vmlinux 0xdc4c337d simple_attr_write +EXPORT_SYMBOL_GPL vmlinux 0xdc6d7696 __inet_hash_nolisten +EXPORT_SYMBOL_GPL vmlinux 0xdc9fdf45 kset_create_and_add +EXPORT_SYMBOL_GPL vmlinux 0xdcf56e9a zap_vma_ptes +EXPORT_SYMBOL_GPL vmlinux 0xdd4e1073 mmu_notifier_register +EXPORT_SYMBOL_GPL vmlinux 0xdd5c4942 srcu_notifier_chain_register +EXPORT_SYMBOL_GPL vmlinux 0xddb6d1c1 bus_register +EXPORT_SYMBOL_GPL vmlinux 0xddf7e7f7 raw_seq_open +EXPORT_SYMBOL_GPL vmlinux 0xde7ed175 device_destroy +EXPORT_SYMBOL_GPL vmlinux 0xdebc3bc7 sysfs_chmod_file +EXPORT_SYMBOL_GPL vmlinux 0xdf3c19ec cn_add_callback +EXPORT_SYMBOL_GPL vmlinux 0xdf78d42b xfrm_audit_state_delete +EXPORT_SYMBOL_GPL vmlinux 0xdf814e95 macvlan_handle_frame_hook +EXPORT_SYMBOL_GPL vmlinux 0xe089cfcc agp_memory_reserved +EXPORT_SYMBOL_GPL vmlinux 0xe0b4a4e5 rtc_update_irq +EXPORT_SYMBOL_GPL vmlinux 0xe24ff917 blocking_notifier_chain_register +EXPORT_SYMBOL_GPL vmlinux 0xe295c0ff is_hpet_enabled +EXPORT_SYMBOL_GPL vmlinux 0xe2dbd55a led_trigger_register_simple +EXPORT_SYMBOL_GPL vmlinux 0xe2e3f4a1 pci_slots_kset +EXPORT_SYMBOL_GPL vmlinux 0xe34c1ef8 debugfs_create_bool +EXPORT_SYMBOL_GPL vmlinux 0xe3ddc593 dnotify_parent +EXPORT_SYMBOL_GPL vmlinux 0xe3e07cda tcp_set_state +EXPORT_SYMBOL_GPL vmlinux 0xe3e7ba4a user_read +EXPORT_SYMBOL_GPL vmlinux 0xe48d5eac acpi_ec_add_query_handler +EXPORT_SYMBOL_GPL vmlinux 0xe513afc0 cache_k8_northbridges +EXPORT_SYMBOL_GPL vmlinux 0xe530071c pm_qos_remove_requirement +EXPORT_SYMBOL_GPL vmlinux 0xe57963a0 platform_device_unregister +EXPORT_SYMBOL_GPL vmlinux 0xe5e62a34 hvc_alloc +EXPORT_SYMBOL_GPL vmlinux 0xe61a6d2f gpio_unexport +EXPORT_SYMBOL_GPL vmlinux 0xe6488b47 cpufreq_notify_transition +EXPORT_SYMBOL_GPL vmlinux 0xe66df9c8 driver_register +EXPORT_SYMBOL_GPL vmlinux 0xe674a5cb srcu_read_lock +EXPORT_SYMBOL_GPL vmlinux 0xe75eedf8 crypto_lookup_template +EXPORT_SYMBOL_GPL vmlinux 0xe7671836 file_ra_state_init +EXPORT_SYMBOL_GPL vmlinux 0xe7de7122 device_reprobe +EXPORT_SYMBOL_GPL vmlinux 0xe7fa47ad srcu_read_unlock +EXPORT_SYMBOL_GPL vmlinux 0xe81af31a crypto_alg_sem +EXPORT_SYMBOL_GPL vmlinux 0xe83aafab mm_kobj +EXPORT_SYMBOL_GPL vmlinux 0xe8f9dfaf uv_cpu_to_blade +EXPORT_SYMBOL_GPL vmlinux 0xe9251b2c __crypto_alloc_tfm +EXPORT_SYMBOL_GPL vmlinux 0xe93e49c3 devres_free +EXPORT_SYMBOL_GPL vmlinux 0xe9468b9f input_ff_event +EXPORT_SYMBOL_GPL vmlinux 0xe992f29f sysfs_remove_link +EXPORT_SYMBOL_GPL vmlinux 0xe9ccaa26 sg_scsi_ioctl +EXPORT_SYMBOL_GPL vmlinux 0xe9dd844d bus_unregister_notifier +EXPORT_SYMBOL_GPL vmlinux 0xe9f5cc25 inet_ctl_sock_create +EXPORT_SYMBOL_GPL vmlinux 0xea065e01 task_handoff_unregister +EXPORT_SYMBOL_GPL vmlinux 0xea3b5fb7 vfs_lock_file +EXPORT_SYMBOL_GPL vmlinux 0xeab35970 single_open_net +EXPORT_SYMBOL_GPL vmlinux 0xeafe4181 page_cache_async_readahead +EXPORT_SYMBOL_GPL vmlinux 0xeafe7cca rtc_set_mmss +EXPORT_SYMBOL_GPL vmlinux 0xeb257fdd __blk_end_request +EXPORT_SYMBOL_GPL vmlinux 0xeb27d352 pci_update_slot_number +EXPORT_SYMBOL_GPL vmlinux 0xeb2fc492 skb_icv_walk +EXPORT_SYMBOL_GPL vmlinux 0xeb864b6e bus_for_each_dev +EXPORT_SYMBOL_GPL vmlinux 0xec24ad24 audit_log_untrustedstring +EXPORT_SYMBOL_GPL vmlinux 0xec2d8616 blk_end_bidi_request +EXPORT_SYMBOL_GPL vmlinux 0xecf8c328 xenbus_watch_path +EXPORT_SYMBOL_GPL vmlinux 0xed05aef7 xenbus_map_ring +EXPORT_SYMBOL_GPL vmlinux 0xed2b349d xenbus_unmap_ring +EXPORT_SYMBOL_GPL vmlinux 0xed48ee29 pciserial_init_ports +EXPORT_SYMBOL_GPL vmlinux 0xed835714 input_ff_destroy +EXPORT_SYMBOL_GPL vmlinux 0xed907658 devres_destroy +EXPORT_SYMBOL_GPL vmlinux 0xedbc6f67 gnttab_end_foreign_access +EXPORT_SYMBOL_GPL vmlinux 0xeecd1984 invalidate_inode_pages2_range +EXPORT_SYMBOL_GPL vmlinux 0xef67109f pci_bus_max_busnr +EXPORT_SYMBOL_GPL vmlinux 0xef9af54a __cpufreq_driver_target +EXPORT_SYMBOL_GPL vmlinux 0xefecadf7 device_remove_file +EXPORT_SYMBOL_GPL vmlinux 0xf0809b34 driver_for_each_device +EXPORT_SYMBOL_GPL vmlinux 0xf1516b93 page_cache_sync_readahead +EXPORT_SYMBOL_GPL vmlinux 0xf184d189 kernel_power_off +EXPORT_SYMBOL_GPL vmlinux 0xf1d411c8 audit_log_d_path +EXPORT_SYMBOL_GPL vmlinux 0xf1d928c3 class_destroy +EXPORT_SYMBOL_GPL vmlinux 0xf259eb08 driver_find +EXPORT_SYMBOL_GPL vmlinux 0xf2bace93 lookup_instantiate_filp +EXPORT_SYMBOL_GPL vmlinux 0xf2d0061b __rt_mutex_init +EXPORT_SYMBOL_GPL vmlinux 0xf2fca922 uart_parse_options +EXPORT_SYMBOL_GPL vmlinux 0xf31f2249 cpufreq_unregister_driver +EXPORT_SYMBOL_GPL vmlinux 0xf36a4c7f relay_flush +EXPORT_SYMBOL_GPL vmlinux 0xf3a6af55 register_jprobes +EXPORT_SYMBOL_GPL vmlinux 0xf45c203b crypto_alloc_base +EXPORT_SYMBOL_GPL vmlinux 0xf499fdb2 rcu_barrier_bh +EXPORT_SYMBOL_GPL vmlinux 0xf4aebdc3 xenbus_suspend +EXPORT_SYMBOL_GPL vmlinux 0xf4b77513 pid_vnr +EXPORT_SYMBOL_GPL vmlinux 0xf515ce1a crypto_free_tfm +EXPORT_SYMBOL_GPL vmlinux 0xf553318d cpuidle_pause_and_lock +EXPORT_SYMBOL_GPL vmlinux 0xf5945bac gnttab_free_grant_references +EXPORT_SYMBOL_GPL vmlinux 0xf5a691cd invalidate_bh_lrus +EXPORT_SYMBOL_GPL vmlinux 0xf5d148a1 user_destroy +EXPORT_SYMBOL_GPL vmlinux 0xf67ae112 bus_find_device +EXPORT_SYMBOL_GPL vmlinux 0xf6bcbd73 hwrng_register +EXPORT_SYMBOL_GPL vmlinux 0xf6ef1000 crypto_shoot_alg +EXPORT_SYMBOL_GPL vmlinux 0xf7016530 xenbus_gather +EXPORT_SYMBOL_GPL vmlinux 0xf72b3f8c inet_hash +EXPORT_SYMBOL_GPL vmlinux 0xf7427c4c register_jprobe +EXPORT_SYMBOL_GPL vmlinux 0xf7584904 bd_release_from_disk +EXPORT_SYMBOL_GPL vmlinux 0xf79ce51a pci_enable_pcie_error_reporting +EXPORT_SYMBOL_GPL vmlinux 0xf7be7f23 cpuidle_enable_device +EXPORT_SYMBOL_GPL vmlinux 0xf7f64d38 device_bind_driver +EXPORT_SYMBOL_GPL vmlinux 0xf840a220 driver_attach +EXPORT_SYMBOL_GPL vmlinux 0xf8802492 print_stack_trace +EXPORT_SYMBOL_GPL vmlinux 0xf8c3423d __mnt_is_readonly +EXPORT_SYMBOL_GPL vmlinux 0xf8d12d24 do_add_mount +EXPORT_SYMBOL_GPL vmlinux 0xf8df02fc crypto_register_alg +EXPORT_SYMBOL_GPL vmlinux 0xf917cf16 queue_delayed_work +EXPORT_SYMBOL_GPL vmlinux 0xf97c4aae klist_iter_exit +EXPORT_SYMBOL_GPL vmlinux 0xf984ccd1 __create_workqueue_key +EXPORT_SYMBOL_GPL vmlinux 0xf9a054b5 __round_jiffies +EXPORT_SYMBOL_GPL vmlinux 0xf9b0bb5f __rtnl_link_unregister +EXPORT_SYMBOL_GPL vmlinux 0xfa073338 inet_csk_reqsk_queue_hash_add +EXPORT_SYMBOL_GPL vmlinux 0xfa1f4662 scatterwalk_start +EXPORT_SYMBOL_GPL vmlinux 0xfb72ff5c xenbus_dev_error +EXPORT_SYMBOL_GPL vmlinux 0xfb8840d3 register_posix_clock +EXPORT_SYMBOL_GPL vmlinux 0xfbc016de blocking_notifier_call_chain +EXPORT_SYMBOL_GPL vmlinux 0xfbf9be5d register_oom_notifier +EXPORT_SYMBOL_GPL vmlinux 0xfc2e9abe debugfs_create_x16 +EXPORT_SYMBOL_GPL vmlinux 0xfc992a43 device_move +EXPORT_SYMBOL_GPL vmlinux 0xfd29ca8f dequeue_signal +EXPORT_SYMBOL_GPL vmlinux 0xfd51b281 gnttab_end_foreign_access_ref +EXPORT_SYMBOL_GPL vmlinux 0xfd6bbdaa security_inode_setattr +EXPORT_SYMBOL_GPL vmlinux 0xfd721947 sysdev_register +EXPORT_SYMBOL_GPL vmlinux 0xfde0b92c crypto_larval_error +EXPORT_SYMBOL_GPL vmlinux 0xfdf7fcbf kobject_get_path +EXPORT_SYMBOL_GPL vmlinux 0xfe727411 get_phys_to_machine +EXPORT_SYMBOL_GPL vmlinux 0xfe990052 gpio_free +EXPORT_SYMBOL_GPL vmlinux 0xfe9b10de pciserial_remove_ports +EXPORT_SYMBOL_GPL vmlinux 0xfea1e8a3 pci_block_user_cfg_access +EXPORT_SYMBOL_GPL vmlinux 0xfecbff96 __mark_empty_function +EXPORT_SYMBOL_GPL vmlinux 0xfed3b909 xfrm_audit_policy_delete +EXPORT_SYMBOL_GPL vmlinux 0xfeeeb3c7 skb_morph +EXPORT_SYMBOL_GPL vmlinux 0xff4af680 unregister_pernet_subsys +EXPORT_SYMBOL_GPL vmlinux 0xff5a8cfe cn_del_callback +EXPORT_SYMBOL_GPL vmlinux 0xff793790 sysdev_class_create_file +EXPORT_SYMBOL_GPL vmlinux 0xff94a4ba rt_mutex_destroy +EXPORT_SYMBOL_GPL vmlinux 0xffeceb70 sysfs_schedule_callback +EXPORT_UNUSED_SYMBOL vmlinux 0x00000000 init_mm --- linux-2.6.27.orig/debian/abi/2.6.27-14.39/amd64/generic.modules +++ linux-2.6.27/debian/abi/2.6.27-14.39/amd64/generic.modules @@ -0,0 +1,2072 @@ +3c359 +3c574_cs +3c589_cs +3c59x +3w-9xxx +3w-xxxx +6pack +8021q +8139cp +8139too +8390 +9p +9pnet +9pnet_virtio +a100u2w +a3d +aacraid +abituguru +abituguru3 +abyss +ac +ac97_bus +acecad +acenic +acer-wmi +acpi-cpufreq +acpiphp +acpiphp_ibm +acquirewdt +act200l-sir +act_gact +act_ipt +actisys-sir +act_mirred +act_nat +act_pedit +act_police +act_simple +acx +ad1848 +ad7414 +ad7418 +adcxx +adfs +adi +adm1021 +adm1025 +adm1026 +adm1029 +adm1031 +adm8211 +adm9240 +ads7828 +ads7846 +adt7470 +adt7473 +adutux +adv7170 +adv7175 +advansys +advantechwdt +aead +aedsp16 +aes_generic +aes-x86_64 +affs +af_key +af_packet +af-rxrpc +ah4 +ah6 +ahci +aic79xx +aic7xxx +aic94xx +aiptek +aircable +airo +airo_cs +alauda +ali-ircc +alim1535_wdt +alim7101_wdt +ambassador +amd76xrom +amd8111e +amd-rng +analog +anubis +aoe +appledisplay +appleir +applesmc +appletalk +appletouch +applicom +ar7part +arc4 +arcfb +arcmsr +arcnet +arc-rawmode +arc-rimi +ark3116 +arkfb +arptable_filter +arp_tables +arpt_mangle +asb100 +asix +asus-laptop +async_memcpy +async_tx +async_xor +at24 +at25 +at76_usb +ata_generic +ata_piix +aten +ath9k +ati_remote +ati_remote2 +atl1 +atl1e +atl2 +atlas_btns +atmel +atmel_cs +atmel_pci +atmtcp +atp +atp870u +atxp1 +aty128fb +atyfb +au0828 +au8522 +aufs +authenc +auth_rpcgss +autofs +autofs4 +av5100 +avma1_cs +avm_cs +ax25 +axnet_cs +b1 +b1dma +b1pci +b1pcmcia +b2c2-flexcop +b2c2-flexcop-pci +b2c2-flexcop-usb +b43 +b43legacy +b44 +bas_gigaset +battery +bay +baycom_par +baycom_ser_fdx +baycom_ser_hdx +bcm203x +bcm3510 +bcm5974 +befs +belkin_sa +berry_charge +bfs +bfusb +binfmt_misc +bitblit +block2mtd +blowfish +bluecard_cs +bluetooth +bnep +bnx2 +bnx2x +bonding +bpa10x +bpck +bpqether +br2684 +bridge +broadcom +bsd_comp +bt3c_cs +bt819 +bt856 +bt878 +btcx-risc +btsdio +bttv +btuart_cs +btusb +budget +budget-av +budget-ci +budget-core +budget-patch +BusLogic +button +bw-qcam +c4 +c67x00 +cafe_ccic +cafe_nand +camellia +capi +capidrv +capifs +capmode +carminefb +cassini +cast5 +cast6 +catc +cbc +cciss +ccm +cdc-acm +cdc_ether +cdc_subset +cdc-wdm +cdrom +cfag12864b +cfag12864bfb +cfg80211 +cfi_cmdset_0001 +cfi_cmdset_0002 +cfi_cmdset_0020 +cfi_probe +cfi_util +ch +ch341 +chipreg +cicada +cifs +cinergyT2 +cirrusfb +ck804xrom +cls_basic +cls_fw +cls_route +cls_rsvp +cls_rsvp6 +cls_tcindex +cls_u32 +cm4000_cs +cm4040_cs +cmtp +cobra +coda +com20020 +com20020_cs +com20020-pci +com90io +com90xx +comm +commandir +compal-laptop +compat_ioctl32 +compcache +configfs +container +coretemp +corgi_bl +cp2101 +cpcihp_generic +cpcihp_zt5550 +cpia +cpia2 +cpia_pp +cpia_usb +cpqarray +cpu5wdt +cpufreq_conservative +cpufreq_ondemand +cpufreq_powersave +cpufreq_stats +cpufreq_userspace +cpuid +c-qcam +cr_bllcd +crc16 +crc32c +crc7 +crc-ccitt +crc-itu-t +crc-t10dif +crvml +cryptd +crypto_blkcipher +cryptoloop +crypto_null +cs5345 +cs53l32a +ct82c710 +ctr +cts +cx18 +cx22700 +cx22702 +cx2341x +cx23885 +cx24110 +cx24123 +cx25840 +cx8800 +cx8802 +cx88-alsa +cx88-blackbird +cx88-dvb +cx88-vp3054-i2c +cx88xx +cxacru +cxgb +cxgb3 +cyber2000fb +cyberjack +cyclades +cyclomx +cycx_drv +cypress_cy7c63 +cypress_m8 +cytherm +DAC960 +davicom +db9 +dc395x +dca +dccp +dccp_ccid2 +dccp_ccid3 +dccp_diag +dccp_ipv4 +dccp_ipv6 +dccp_probe +dccp_tfrc_lib +dcdbas +de2104x +de4x5 +de600 +de620 +decnet +deflate +defxx +dell_rbu +des_generic +dib0070 +dib3000mb +dib3000mc +dib7000m +dib7000p +dibx000_common +digi_acceleport +dilnetpc +diskonchip +display +divacapi +divadidd +diva_idi +diva_mnt +divas +dlci +dlm +dm9601 +dm-bbr +dm-crypt +dme1737 +dmfe +dm-log +dm-loop +dm-mem-cache +dm-message +dm-mirror +dm-mod +dm-multipath +dm-raid4-5 +dm-region_hash +dm-round-robin +dm-snapshot +dmx3191d +dm-zero +dn_rtmsg +doc2000 +doc2001 +doc2001plus +docecc +dock +docprobe +dpc7146 +dpt_i2o +drbd +drm +drx397xD +ds1621 +ds1682 +ds2482 +ds2490 +ds2760_battery +dsbr100 +dscc4 +dss1_divert +dst +dst_ca +dstr +dtl1_cs +dummy +dv1394 +dvb-bt8xx +dvb-core +dvb-pll +dvb-ttpci +dvb-ttusb-budget +dvb-usb +dvb-usb-a800 +dvb-usb-af9005 +dvb-usb-af9005-remote +dvb-usb-anysee +dvb-usb-au6610 +dvb-usb-cxusb +dvb-usb-dib0700 +dvb-usb-dibusb-common +dvb-usb-dibusb-mb +dvb-usb-dibusb-mc +dvb-usb-digitv +dvb-usb-dtt200u +dvb-usb-dw2102 +dvb-usb-gl861 +dvb-usb-gp8psk +dvb-usb-m920x +dvb-usb-nova-t-usb2 +dvb-usb-opera +dvb-usb-ttusb2 +dvb-usb-umt-010 +dvb-usb-vp702x +dvb-usb-vp7045 +e100 +e1000 +e1000e +e752x_edac +eata +ebt_802_3 +ebtable_broute +ebtable_filter +ebtable_nat +ebtables +ebt_among +ebt_arp +ebt_arpreply +ebt_dnat +ebt_ip +ebt_ip6 +ebt_limit +ebt_log +ebt_mark +ebt_mark_m +ebt_nflog +ebt_pkttype +ebt_redirect +ebt_snat +ebt_stp +ebt_ulog +ebt_vlan +ecb +econet +ecryptfs +edac_core +eeepc-laptop +eepro100 +eeprom +eeprom_93cx6 +efs +ehci-hcd +elo +elsa_cs +em28xx +em28xx-alsa +em28xx-dvb +em_cmp +emi26 +emi62 +em_meta +em_nbyte +empeg +em_text +emu10k1-gp +em_u32 +enclosure +eni +epat +epca +epia +epic100 +eql +esb2rom +esi-sir +esp4 +esp6 +et131x +et61x251 +eth1394 +eurotechwdt +evbug +evdev +exportfs +ext2 +ext3 +ext4dev +f71805f +f71882fg +f75375s +fakephp +fan +farsync +fat +faulty +fbcon +fb_ddc +fb_sys_fops +fcrypt +fdomain +fdomain_cs +fealnx +ff-memless +firestream +fit2 +fit3 +floppy +fm801-gp +fmvj18x_cs +font +forcedeth +fore_200e +freevxfs +freq_table +friq +frpw +fsam7400 +fscher +fschmd +fscpos +ftdi-elan +ftdi_sio +ftl +fujitsu-laptop +fujitsu_ts +funsoft +fuse +g450_pll +gadgetfs +gamecon +gameport +garmin_gps +garp +g_cdc +gcm +gdth +generic_serial +gen_probe +g_ether +gf128mul +gf2k +g_file_storage +gfs +gfs2 +gigaset +girbil-sir +gl518sm +gl520sm +gl620a +gnbd +gpio_keys +gpio_mouse +grip +grip_mp +gru +g_serial +gspca_conex +gspca_etoms +gspca_main +gspca_mars +gspca_ov519 +gspca_pac207 +gspca_pac7311 +gspca_sonixb +gspca_sonixj +gspca_spca500 +gspca_spca501 +gspca_spca505 +gspca_spca506 +gspca_spca508 +gspca_spca561 +gspca_stk014 +gspca_sunplus +gspca_t613 +gspca_tv8532 +gspca_vc032x +gspca_zc3xx +gtco +guillemot +gunze +gx1fb +gxfb +g_zero +hamachi +hangcheck-timer +hci_uart +hci_vhci +hdaps +hdlc +hdlc_cisco +hdlcdrv +hdlc_fr +hdlc_ppp +hdlc_raw +hdlc_raw_eth +hdlc_x25 +he +heci +hecubafb +hermes +hexium_gemini +hexium_orion +hfc4s8s_l1 +hfcmulti +hfcpci +hfc_usb +hfs +hfsplus +hgafb +hid +hidp +hifn_795x +hisax +hisax_fcpcipnp +hisax_isac +hisax_st5481 +horizon +hostap +hostap_cs +hostap_pci +hostap_plx +hp100 +hp4x +hpfs +hpilo +hptiop +hp-wmi +hso +htc-pasic3 +hwmon-vid +hysdn +i2c-algo-bit +i2c-algo-pca +i2c-algo-pcf +i2c-ali1535 +i2c-ali1563 +i2c-ali15x3 +i2c-amd756 +i2c-amd756-s4882 +i2c-amd8111 +i2c-core +i2c-dev +i2c-gpio +i2c-i801 +i2c-isch +i2c-matroxfb +i2c-nforce2 +i2c-nforce2-s4985 +i2c-ocores +i2c-parport +i2c-parport-light +i2c-pca-platform +i2c-piix4 +i2c-simtec +i2c-sis5595 +i2c-sis630 +i2c-sis96x +i2c-stub +i2c-taos-evm +i2c-tiny-usb +i2c-via +i2c-viapro +i2c-voodoo3 +i2o_block +i2o_bus +i2o_config +i2o_core +i2o_proc +i2o_scsi +i3000_edac +i5000_edac +i5100_edac +i5k_amb +i6300esb +i810 +i82092 +i82975x_edac +i830 +i8k +i915 +ia32_aout +ib700wdt +ib_addr +ib_cm +ib_core +ib_ipath +ib_ipoib +ib_iser +ib_mad +ibmaem +ibmasm +ibmasr +ibmcam +ibmpex +ib_mthca +ib_sa +ib_srp +ib_ucm +ib_umad +ib_uverbs +ichxrom +icplus +idmouse +idt77252 +ieee1394 +ieee80211 +ieee80211_crypt +ieee80211_crypt_ccmp +ieee80211_crypt_tkip +ieee80211_crypt_wep +ifb +iforce +igb +ili9320 +imm +inet_lro +inexio +inftl +initio +input-polldev +intel-agp +intelfb +intel_menlow +intel-rng +intel_vr_nor +interact +ioatdma +ioc4 +io_edgeport +io_ti +iowarrior +ip2 +ip6_queue +ip6table_filter +ip6table_mangle +ip6table_raw +ip6_tables +ip6table_security +ip6t_ah +ip6t_eui64 +ip6t_frag +ip6t_hbh +ip6t_HL +ip6t_hl +ip6t_ipv6header +ip6t_LOG +ip6t_mh +ip6t_REJECT +ip6t_rt +ip6_tunnel +ipaq +ipcomp +ipcomp6 +ipddp +ipg +ip_gre +iphase +ipip +ipmi_devintf +ipmi_msghandler +ipmi_poweroff +ipmi_si +ipmi_watchdog +ip_queue +ipr +ips +iptable_filter +iptable_mangle +iptable_nat +iptable_raw +ip_tables +iptable_security +ipt_addrtype +ipt_ah +ipt_CLUSTERIP +ipt_ECN +ipt_ecn +ipt_LOG +ipt_MASQUERADE +ipt_NETMAP +ipt_recent +ipt_REDIRECT +ipt_REJECT +ipt_TTL +ipt_ttl +ipt_ULOG +ipv6 +ip_vs +ip_vs_dh +ip_vs_ftp +ip_vs_lblc +ip_vs_lblcr +ip_vs_lc +ip_vs_nq +ip_vs_rr +ip_vs_sed +ip_vs_sh +ip_vs_wlc +ip_vs_wrr +ipw +ipw2100 +ipw2200 +ipwireless +ipx +ircomm +ir-common +ircomm-tty +irda +irda-usb +ir-kbd-i2c +irlan +irnet +irtty-sir +iscsi_ibft +iscsi_tcp +iscsi_trgt +isdn +isdn_bsdcomp +isdnhdlc +isight_firmware +isl6405 +isl6421 +isofs +isp116x-hcd +isp1760 +it87 +it8712f_wdt +iTCO_vendor_support +iTCO_wdt +itd1000 +ivtv +ivtvfb +iw_c2 +iw_cm +iw_cxgb3 +iwl3945 +iwlagn +iwlcore +ixgb +ixgbe +ixj +ixj_pcmcia +jbd +jbd2 +jedec_probe +jffs2 +jfs +joydev +joydump +jsm +k8temp +kafs +kahlua +kaweth +kbic +kbtab +kernelcapi +keyspan +keyspan_pda +keyspan_remote +khazad +kingsun-sir +kl5kusb105 +kobil_sct +konicawc +ks0108 +ks0127 +ks959-sir +ksdazzle-sir +ktti +kvm +kvm-amd +kvm-intel +kyrofb +l1oip +l2cap +l440gx +l64781 +lanai +lapb +lapbether +lcd +ldusb +lec +led-class +leds-gpio +leds-pca9532 +leds-pca955x +ledtrig-default-on +ledtrig-heartbeat +ledtrig-timer +legousbtower +lgdt330x +libata +libcrc32c +libertas +libertas_cs +libertas_sdio +libiscsi +libphy +libsas +libsrp +libusual +lightning +linear +lirc_atiusb +lirc_bt829 +lirc_cmdir +lirc_dev +lirc_i2c +lirc_igorplugusb +lirc_imon +lirc_it87 +lirc_mceusb +lirc_mceusb2 +lirc_pvr150 +lirc_sasem +lirc_serial +lirc_serial_igor +lirc_sir +lirc_streamzap +lirc_ttusbir +litelink-sir +lkkbd +llc2 +lm63 +lm70 +lm75 +lm77 +lm78 +lm80 +lm83 +lm85 +lm87 +lm90 +lm92 +lm93 +lmc +lmpcm_usb +lnbp21 +lockd +lock_dlm +loop +lp +lpfc +lrw +ltv350qv +lxfb +lxt +lzo +lzo_compress +lzo_decompress +m25p80 +m52790 +ma600-sir +mac80211 +machzwd +macmodes +macvlan +magellan +map_absent +map_funcs +map_ram +map_rom +marvell +matroxfb_accel +matroxfb_base +matroxfb_crtc2 +matroxfb_DAC1064 +matroxfb_g450 +matroxfb_maven +matroxfb_misc +matroxfb_Ti3026 +matrox_w1 +max1619 +max6650 +max6875 +max7301 +max732x +mbcache +mbp_nvidia_bl +mcp2120-sir +mcp23s08 +mcs7780 +mcs7830 +mct_u232 +md4 +mdc800 +mdio-bitbang +md-mod +megaraid +megaraid_mbox +megaraid_mm +megaraid_sas +meye +mga +michael_mic +microcode +microtek +mii +minix +mISDN_core +mISDN_dsp +mk712 +mkiss +mlx4_core +mlx4_ib +mmc_block +mmc_core +mmc_spi +mos7720 +mos7840 +moto_modem +moxa +mpoa +mptbase +mptctl +mptfc +mptlan +mptsas +mptscsih +mptspi +mpu401 +msdos +msi-laptop +msp3400 +msr +mt2060 +mt20xx +mt2131 +mt2266 +mt312 +mt352 +mt9m001 +mt9v022 +mtd +mtd_blkdevs +mtdblock +mtdblock_ro +mtdchar +mtdconcat +mtd_dataflash +mtdoops +mtdram +mtouch +multipath +mwave +mxb +mxl5005s +mxl5007t +mxser +myri10ge +nand +nand_ecc +nand_ids +nandsim +natsemi +navman +nbd +ncpfs +ndiswrapper +ne2k-pci +neofb +net1080 +net2280 +netconsole +netrom +netsc520 +nettel +netwave_cs +netxen_nic +newtonkbd +nf_conntrack +nf_conntrack_amanda +nf_conntrack_ftp +nf_conntrack_h323 +nf_conntrack_ipv4 +nf_conntrack_ipv6 +nf_conntrack_irc +nf_conntrack_netbios_ns +nf_conntrack_netlink +nf_conntrack_pptp +nf_conntrack_proto_gre +nf_conntrack_proto_sctp +nf_conntrack_proto_udplite +nf_conntrack_sip +nf_conntrack_tftp +nf_nat +nf_nat_amanda +nf_nat_ftp +nf_nat_h323 +nf_nat_irc +nf_nat_pptp +nf_nat_proto_gre +nf_nat_proto_sctp +nf_nat_proto_udplite +nf_nat_sip +nf_nat_snmp_basic +nf_nat_tftp +nfnetlink +nfnetlink_log +nfnetlink_queue +nfs +nfs_acl +nfsd +nftl +n_hdlc +niu +nls_ascii +nls_cp1250 +nls_cp1251 +nls_cp1255 +nls_cp437 +nls_cp737 +nls_cp775 +nls_cp850 +nls_cp852 +nls_cp855 +nls_cp857 +nls_cp860 +nls_cp861 +nls_cp862 +nls_cp863 +nls_cp864 +nls_cp865 +nls_cp866 +nls_cp869 +nls_cp874 +nls_cp932 +nls_cp936 +nls_cp949 +nls_cp950 +nls_euc-jp +nls_iso8859-1 +nls_iso8859-13 +nls_iso8859-14 +nls_iso8859-15 +nls_iso8859-2 +nls_iso8859-3 +nls_iso8859-4 +nls_iso8859-5 +nls_iso8859-6 +nls_iso8859-7 +nls_iso8859-9 +nls_koi8-r +nls_koi8-ru +nls_koi8-u +nls_utf8 +nmclan_cs +nozomi +n_r3964 +ns558 +ns83820 +nsc_gpio +nsc-ircc +ntfs +nvidiafb +nvram +nxt200x +nxt6000 +ocfs2 +ocfs2_dlm +ocfs2_dlmfs +ocfs2_nodemanager +ocfs2_stackglue +ocfs2_stack_o2cb +ocfs2_stack_user +ohci1394 +ohci-hcd +old_belkin-sir +olympic +omfs +omninet +on20 +on26 +onenand +onenand_sim +opl3 +oprofile +option +or51132 +or51211 +orinoco +orinoco_cs +orinoco_nortel +orinoco_pci +orinoco_plx +orinoco_tmd +osst +oti6858 +output +ov511 +ov511_decomp +ov518_decomp +ov7670 +ovcamchip +p54common +p54pci +p54usb +p80211 +p8023 +paride +parkbd +parport +parport_ax88796 +parport_cs +parport_pc +parport_serial +pas2 +pata_acpi +pata_ali +pata_amd +pata_artop +pata_atiixp +pata_cmd64x +pata_cs5520 +pata_cs5530 +pata_efar +pata_hpt366 +pata_hpt37x +pata_hpt3x3 +pata_it8213 +pata_it821x +pata_jmicron +pata_marvell +pata_mpiix +pata_netcell +pata_ninja32 +pata_ns87410 +pata_ns87415 +pata_oldpiix +pata_pcmcia +pata_pdc2027x +pata_pdc202xx_old +pata_rz1000 +pata_sch +pata_serverworks +pata_sil680 +pata_sis +pata_sl82c105 +pata_triflex +pata_via +pbe5 +pc300 +pc87360 +pc8736x_gpio +pc87413_wdt +pc87427 +pca953x +pcbc +pcd +pcf857x +pcf8591 +pci +pci200syn +pciehp +pci_hotplug +pcilynx +pcips2 +pci_slot +pcmcia +pcmcia_core +pcnet32 +pcnet_cs +pcspkr +pcwd_pci +pcwd_usb +pd +pd6729 +pda_power +pdc_adma +pegasus +penmount +pf +pg +phantom +phidget +phidgetkit +phidgetmotorcontrol +phidgetservo +phonedev +phram +physmap +pktcdvd +pktgen +pl2303 +platform_lcd +plat_nand +plat-ram +plip +plusb +pluto2 +pm2fb +pm3fb +pmc551 +powermate +powernow-k8 +ppa +ppdev +ppp_async +ppp_deflate +ppp_generic +ppp_mppe +pppoatm +pppoe +pppol2tp +pppox +ppp_synctty +prism2_usb +prism54 +processor +progear_bl +psmouse +pss +pt +pvrusb2 +pwc +qla1280 +qla2xxx +qla3xxx +qla4xxx +qlogic_cs +qlogicfas408 +qnx4 +qsemi +qt1010 +quickcam +quickcam_messenger +quota_v1 +quota_v2 +r128 +r8169 +r8a66597-hcd +radeon +radeonfb +radio-gemtek-pci +radio-maestro +radio-maxiradio +radio-si470x +raid0 +raid1 +raid10 +raid456 +raid_class +raw +raw1394 +ray_cs +rdma_cm +rdma_ucm +redboot +reed_solomon +reiserfs +rfc1051 +rfc1201 +rfcomm +rfd_ftl +rfkill +rfkill-input +ricoh_mmc +rio +rio500 +riscom8 +rivafb +rmd128 +rmd160 +rmd256 +rmd320 +rndis_host +rndis_wlan +rocket +romfs +rose +rpcsec_gss_krb5 +rpcsec_gss_spkm3 +rrunner +rsrc_nonstatic +rt2400pci +rt2500pci +rt2500usb +rt2x00lib +rt2x00pci +rt2x00usb +rt61pci +rt73usb +rtc-ds1305 +rtc-ds1307 +rtc-ds1374 +rtc-ds1553 +rtc-ds1672 +rtc-ds1742 +rtc-fm3130 +rtc-isl1208 +rtc-m41t80 +rtc-m41t94 +rtc-m48t59 +rtc-m48t86 +rtc-max6900 +rtc-max6902 +rtc-pcf8563 +rtc-pcf8583 +rtc-rs5c348 +rtc-rs5c372 +rtc-stk17ta8 +rtc-test +rtc-v3020 +rtc-x1205 +rtl8150 +rtl8180 +rtl8187 +rxkad +s1d13xxxfb +s2255drv +s2io +s3fb +s5h1409 +s5h1411 +s5h1420 +saa5246a +saa5249 +saa6588 +saa6752hs +saa7110 +saa7111 +saa7114 +saa7115 +saa7127 +saa7134 +saa7134-alsa +saa7134-dvb +saa7134-empress +saa7146 +saa7146_vv +saa717x +saa7185 +safe_serial +salsa20_generic +salsa20-x86_64 +sata_inic162x +sata_mv +sata_nv +sata_promise +sata_qstor +sata_sil +sata_sil24 +sata_sis +sata_svw +sata_sx4 +sata_uli +sata_via +sata_vsc +savage +savagefb +sb +sb1000 +sbc60xxwdt +sbc8360 +sbc_epx_c3 +sbc_gxx +sb_lib +sbni +sbp2 +sbs +sbshc +sc1200wdt +sc520cdp +sc520_wdt +sc92031 +scb2_flash +sch_atm +sch_cbq +sch_dsmark +sch_gred +sch_hfsc +sch_htb +sch_ingress +sch_netem +sch_prio +sch_red +sch_sfq +sch_tbf +sch_teql +sco +scsi_debug +scsi_dh +scsi_dh_alua +scsi_dh_emc +scsi_dh_hp_sw +scsi_dh_rdac +scsi_mod +scsi_tgt +scsi_transport_fc +scsi_transport_iscsi +scsi_transport_sas +scsi_transport_spi +scsi_transport_srp +scsi_wait_scan +sctp +sdhci +sdhci-pci +sdio_uart +sd_mod +sdricoh_cs +se401 +sedlbauer_cs +seed +seqiv +ser_gigaset +serial_cs +serio_raw +sermouse +serpent +serport +ses +sfc +sg +sha1_generic +sha256_generic +sha512_generic +sh_mobile_ceu_camera +shpchp +sidewinder +sierra +sir-dev +sis +sis190 +sis5595 +sis900 +sis-agp +sisfb +sisusbvga +sit +skfp +skge +sky2 +sl811_cs +sl811-hcd +slhc +slip +slram +sm501 +sm501fb +smbfs +smc91c92_cs +sms1xxx +smsc +smsc37b787_wdt +smsc47b397 +smsc47m1 +smsc47m192 +smsc-ircc2 +sn9c102 +snd +snd-ac97-codec +snd-ad1889 +snd-ak4114 +snd-ak4117 +snd-ak4xxx-adda +snd-ali5451 +snd-als300 +snd-als4000 +snd-atiixp +snd-atiixp-modem +snd-au8810 +snd-au8820 +snd-au8830 +snd-aw2 +snd-azt3328 +snd-bt87x +snd-bt-sco +snd-ca0106 +snd-cmipci +snd-cs4281 +snd-cs46xx +snd-cs5530 +snd-cs8427 +snd-darla20 +snd-darla24 +snd-dummy +snd-echo3g +snd-emu10k1 +snd-emu10k1-synth +snd-emu10k1x +snd-emux-synth +snd-ens1370 +snd-ens1371 +snd-es1938 +snd-es1968 +snd-fm801 +snd-gina20 +snd-gina24 +snd-hda-intel +snd-hdsp +snd-hdspm +snd-hifier +snd-hwdep +snd-i2c +snd-ice1712 +snd-ice1724 +snd-ice17xx-ak4xxx +snd-indigo +snd-indigodj +snd-indigoio +snd-intel8x0 +snd-intel8x0m +snd-korg1212 +snd-layla20 +snd-layla24 +snd-maestro3 +snd-mia +snd-mixart +snd-mixer-oss +snd-mona +snd-mpu401 +snd-mpu401-uart +snd-mtpav +snd-mts64 +snd-nm256 +snd-opl3-lib +snd-opl3-synth +snd-oxygen +snd-oxygen-lib +snd-page-alloc +snd-pcm +snd-pcm-oss +snd-pcsp +snd-pcxhr +snd-pdaudiocf +snd-portman2x4 +snd-pt2258 +snd-rawmidi +snd-riptide +snd-rme32 +snd-rme96 +snd-rme9652 +snd-sb16-dsp +snd-sb-common +snd-seq +snd-seq-device +snd-seq-dummy +snd-seq-midi +snd-seq-midi-emul +snd-seq-midi-event +snd-seq-oss +snd-seq-virmidi +snd-serial-u16550 +snd-soc-core +snd-sonicvibes +snd-tea575x-tuner +snd-timer +snd-trident +snd-usb-audio +snd-usb-caiaq +snd-usb-lib +snd-usb-usx2y +snd-util-mem +snd-via82xx +snd-via82xx-modem +snd-virmidi +snd-virtuoso +snd-vx222 +snd-vx-lib +snd-vxpocket +snd-ymfpci +soc_camera +soc_camera_platform +softcursor +softdog +sony-laptop +sound +soundcore +sound_firmware +sp8870 +sp887x +spaceball +spaceorb +spcp8x5 +specialix +spectrum_cs +speedtch +spi_bitbang +spi_butterfly +spidev +spi_lm70llp +squashfs +sr_mod +ssb +sscape +ssfdc +sstfb +st +starfire +stex +stinger +stir4200 +stkwebcam +stowaway +stp +stradis +strip +stv0297 +stv0299 +stv680 +sundance +sungem +sungem_phy +sunhme +suni +sunkbd +sunrpc +svcrdma +svgalib +sx +sx8 +sym53c500_cs +sym53c8xx +synclink +synclink_cs +synclink_gt +synclinkmp +syncppp +syscopyarea +sysfillrect +sysimgblt +sysv +t1pci +tcp_bic +tcp_highspeed +tcp_htcp +tcp_hybla +tcp_illinois +tcp_lp +tcp_probe +tcp_scalable +tcp_vegas +tcp_veno +tcp_westwood +tcp_yeah +tcrypt +tda10021 +tda10023 +tda10048 +tda1004x +tda10086 +tda18271 +tda7432 +tda8083 +tda826x +tda827x +tda8290 +tda9840 +tda9875 +tda9887 +tdfx +tdfxfb +tea +tea5761 +tea5767 +tea6415c +tea6420 +tehuti +tekram-sir +teles_cs +tg3 +tgr192 +thermal +thinkpad_acpi +thinkpad_ec +thmc50 +tifm_7xx1 +tifm_core +tifm_sd +tileblit +tipc +ti_usb_3410_5052 +tlan +tlclk +tle62x0 +tlsf +tmdc +tms380tr +tmscsim +tmspci +toshiba_acpi +touchit213 +touchright +touchwin +tpm +tpm_atmel +tpm_bios +tpm_infineon +tpm_nsc +tpm_tis +tps65010 +tp_smapi +trancevibrator +tridentfb +trix +ts5500_flash +ts_bm +ts_fsm +ts_kmp +tsl2550 +ttpci-eeprom +ttusb_dec +ttusbdecfe +tua6100 +tulip +tun +tuner +tuner-3036 +tuner-simple +tuner-types +tuner-xc2028 +tunnel4 +tunnel6 +turbografx +tvaudio +tveeprom +tvp5150 +twidjoy +twofish +twofish_common +twofish-x86_64 +typhoon +u132-hcd +uart401 +uart6850 +ub +ubi +ubifs +ucb1400_ts +udf +ueagle-atm +ufs +uhci-hcd +uinput +uio +uio_cif +uio_pdrv +uio_pdrv_genirq +uio_smx +uli526x +ultracam +umem +unionfs +upd64031a +upd64083 +uPD98402 +usb8xxx +usbatm +usbcore +usb_debug +usb_gigaset +usbhid +usbkbd +usblcd +usbled +usblp +usbmon +usbmouse +usbnet +usbserial +usb-storage +usbtouchscreen +usbvideo +usbvision +uss720 +uvcvideo +uvesafb +v4l1-compat +v4l2-common +v4l2-int-device +ves1820 +ves1x93 +vesafb +veth +vfat +vga16fb +vgastate +vgg2432a4 +via +via686a +via-agp +via_chrome9 +via-ircc +via-rhine +via-velocity +vicam +video +video1394 +videobuf-core +videobuf-dma-contig +videobuf-dma-sg +videobuf-dvb +videobuf-vmalloc +videocodec +videodev +virtio +virtio_balloon +virtio_blk +virtio_console +virtio_net +virtio_pci +virtio_ring +virtio-rng +visor +vitesse +vivi +vlsi_ir +v_midi +vmlfb +vp27smpx +vpx3220 +vsxxxaa +vt1211 +vt8231 +vt8623fb +w1_ds2433 +w1_ds2760 +w1-gpio +w1_smem +w1_therm +w83627ehf +w83627hf +w83627hf_wdt +w83697hf_wdt +w83781d +w83791d +w83792d +w83793 +w83877f_wdt +w83977af_ir +w83977f_wdt +w83l785ts +w83l786ng +w9966 +w9968cf +wacom +wafer5823wdt +wanrouter +wanxl +warrior +wavelan_cs +wbsd +wdt_pci +whiteheat +winbond-840 +wire +wl3501_cs +wm8739 +wm8775 +wm97xx-ts +wmi +wp512 +x25 +x25_asy +xc5000 +xcbc +xen-blkfront +xen-fbfront +xen-kbdfront +xen-netfront +xfrm4_mode_beet +xfrm4_mode_transport +xfrm4_mode_tunnel +xfrm4_tunnel +xfrm6_mode_beet +xfrm6_mode_ro +xfrm6_mode_transport +xfrm6_mode_tunnel +xfrm6_tunnel +xfrm_ipcomp +xfrm_user +xfs +xirc2ps_cs +xircom_cb +xor +xp +xpad +xpc +xpnet +xprtrdma +x_tables +xt_CLASSIFY +xt_comment +xt_connbytes +xt_connlimit +xt_CONNMARK +xt_connmark +xt_CONNSECMARK +xt_conntrack +xt_dccp +xt_DSCP +xt_dscp +xt_esp +xt_hashlimit +xt_helper +xt_iprange +xtkbd +xt_length +xt_limit +xt_mac +xt_MARK +xt_mark +xt_multiport +xt_NFLOG +xt_NFQUEUE +xt_NOTRACK +xt_owner +xt_physdev +xt_pkttype +xt_policy +xt_quota +xt_RATEEST +xt_rateest +xt_realm +xts +xt_sctp +xt_SECMARK +xt_state +xt_statistic +xt_string +xt_TCPMSS +xt_tcpmss +xt_tcpudp +xt_time +xt_TRACE +xt_u32 +xusbatm +yam +yealink +yellowfin +yenta_socket +zatm +zaurus +zc0301 +zd1201 +zd1211rw +zhenhua +zl10353 +zlib_deflate +zr36016 +zr36050 +zr36060 +zr36067 +zr364xx --- linux-2.6.27.orig/debian/abi/2.6.27-14.39/amd64/server.modules +++ linux-2.6.27/debian/abi/2.6.27-14.39/amd64/server.modules @@ -0,0 +1,2072 @@ +3c359 +3c574_cs +3c589_cs +3c59x +3w-9xxx +3w-xxxx +6pack +8021q +8139cp +8139too +8390 +9p +9pnet +9pnet_virtio +a100u2w +a3d +aacraid +abituguru +abituguru3 +abyss +ac +ac97_bus +acecad +acenic +acer-wmi +acpi-cpufreq +acpiphp +acpiphp_ibm +acquirewdt +act200l-sir +act_gact +act_ipt +actisys-sir +act_mirred +act_nat +act_pedit +act_police +act_simple +acx +ad1848 +ad7414 +ad7418 +adcxx +adfs +adi +adm1021 +adm1025 +adm1026 +adm1029 +adm1031 +adm8211 +adm9240 +ads7828 +ads7846 +adt7470 +adt7473 +adutux +adv7170 +adv7175 +advansys +advantechwdt +aead +aedsp16 +aes_generic +aes-x86_64 +affs +af_key +af_packet +af-rxrpc +ah4 +ah6 +ahci +aic79xx +aic7xxx +aic94xx +aiptek +aircable +airo +airo_cs +alauda +ali-ircc +alim1535_wdt +alim7101_wdt +ambassador +amd76xrom +amd8111e +amd-rng +analog +anubis +aoe +appledisplay +appleir +applesmc +appletalk +appletouch +applicom +ar7part +arc4 +arcfb +arcmsr +arcnet +arc-rawmode +arc-rimi +ark3116 +arkfb +arptable_filter +arp_tables +arpt_mangle +asb100 +asix +asus-laptop +async_memcpy +async_tx +async_xor +at24 +at25 +at76_usb +ata_generic +ata_piix +aten +ath9k +ati_remote +ati_remote2 +atl1 +atl1e +atl2 +atlas_btns +atmel +atmel_cs +atmel_pci +atmtcp +atp +atp870u +atxp1 +aty128fb +atyfb +au0828 +au8522 +aufs +authenc +auth_rpcgss +autofs +autofs4 +av5100 +avma1_cs +avm_cs +ax25 +axnet_cs +b1 +b1dma +b1pci +b1pcmcia +b2c2-flexcop +b2c2-flexcop-pci +b2c2-flexcop-usb +b43 +b43legacy +b44 +bas_gigaset +battery +bay +baycom_par +baycom_ser_fdx +baycom_ser_hdx +bcm203x +bcm3510 +bcm5974 +befs +belkin_sa +berry_charge +bfs +bfusb +binfmt_misc +bitblit +block2mtd +blowfish +bluecard_cs +bluetooth +bnep +bnx2 +bnx2x +bonding +bpa10x +bpck +bpqether +br2684 +bridge +broadcom +bsd_comp +bt3c_cs +bt819 +bt856 +bt878 +btcx-risc +btsdio +bttv +btuart_cs +btusb +budget +budget-av +budget-ci +budget-core +budget-patch +BusLogic +button +bw-qcam +c4 +c67x00 +cafe_ccic +cafe_nand +camellia +capi +capidrv +capifs +capmode +carminefb +cassini +cast5 +cast6 +catc +cbc +cciss +ccm +cdc-acm +cdc_ether +cdc_subset +cdc-wdm +cdrom +cfag12864b +cfag12864bfb +cfg80211 +cfi_cmdset_0001 +cfi_cmdset_0002 +cfi_cmdset_0020 +cfi_probe +cfi_util +ch +ch341 +chipreg +cicada +cifs +cinergyT2 +cirrusfb +ck804xrom +cls_basic +cls_fw +cls_route +cls_rsvp +cls_rsvp6 +cls_tcindex +cls_u32 +cm4000_cs +cm4040_cs +cmtp +cobra +coda +com20020 +com20020_cs +com20020-pci +com90io +com90xx +comm +commandir +compal-laptop +compat_ioctl32 +compcache +configfs +container +coretemp +corgi_bl +cp2101 +cpcihp_generic +cpcihp_zt5550 +cpia +cpia2 +cpia_pp +cpia_usb +cpqarray +cpu5wdt +cpufreq_conservative +cpufreq_ondemand +cpufreq_powersave +cpufreq_stats +cpufreq_userspace +cpuid +c-qcam +cr_bllcd +crc16 +crc32c +crc7 +crc-ccitt +crc-itu-t +crc-t10dif +crvml +cryptd +crypto_blkcipher +cryptoloop +crypto_null +cs5345 +cs53l32a +ct82c710 +ctr +cts +cx18 +cx22700 +cx22702 +cx2341x +cx23885 +cx24110 +cx24123 +cx25840 +cx8800 +cx8802 +cx88-alsa +cx88-blackbird +cx88-dvb +cx88-vp3054-i2c +cx88xx +cxacru +cxgb +cxgb3 +cyber2000fb +cyberjack +cyclades +cyclomx +cycx_drv +cypress_cy7c63 +cypress_m8 +cytherm +DAC960 +davicom +db9 +dc395x +dca +dccp +dccp_ccid2 +dccp_ccid3 +dccp_diag +dccp_ipv4 +dccp_ipv6 +dccp_probe +dccp_tfrc_lib +dcdbas +de2104x +de4x5 +de600 +de620 +decnet +deflate +defxx +dell_rbu +des_generic +dib0070 +dib3000mb +dib3000mc +dib7000m +dib7000p +dibx000_common +digi_acceleport +dilnetpc +diskonchip +display +divacapi +divadidd +diva_idi +diva_mnt +divas +dlci +dlm +dm9601 +dm-bbr +dm-crypt +dme1737 +dmfe +dm-log +dm-loop +dm-mem-cache +dm-message +dm-mirror +dm-mod +dm-multipath +dm-raid4-5 +dm-region_hash +dm-round-robin +dm-snapshot +dmx3191d +dm-zero +dn_rtmsg +doc2000 +doc2001 +doc2001plus +docecc +dock +docprobe +dpc7146 +dpt_i2o +drbd +drm +drx397xD +ds1621 +ds1682 +ds2482 +ds2490 +ds2760_battery +dsbr100 +dscc4 +dss1_divert +dst +dst_ca +dstr +dtl1_cs +dummy +dv1394 +dvb-bt8xx +dvb-core +dvb-pll +dvb-ttpci +dvb-ttusb-budget +dvb-usb +dvb-usb-a800 +dvb-usb-af9005 +dvb-usb-af9005-remote +dvb-usb-anysee +dvb-usb-au6610 +dvb-usb-cxusb +dvb-usb-dib0700 +dvb-usb-dibusb-common +dvb-usb-dibusb-mb +dvb-usb-dibusb-mc +dvb-usb-digitv +dvb-usb-dtt200u +dvb-usb-dw2102 +dvb-usb-gl861 +dvb-usb-gp8psk +dvb-usb-m920x +dvb-usb-nova-t-usb2 +dvb-usb-opera +dvb-usb-ttusb2 +dvb-usb-umt-010 +dvb-usb-vp702x +dvb-usb-vp7045 +e100 +e1000 +e1000e +e752x_edac +eata +ebt_802_3 +ebtable_broute +ebtable_filter +ebtable_nat +ebtables +ebt_among +ebt_arp +ebt_arpreply +ebt_dnat +ebt_ip +ebt_ip6 +ebt_limit +ebt_log +ebt_mark +ebt_mark_m +ebt_nflog +ebt_pkttype +ebt_redirect +ebt_snat +ebt_stp +ebt_ulog +ebt_vlan +ecb +econet +ecryptfs +edac_core +eeepc-laptop +eepro100 +eeprom +eeprom_93cx6 +efs +ehci-hcd +elo +elsa_cs +em28xx +em28xx-alsa +em28xx-dvb +em_cmp +emi26 +emi62 +em_meta +em_nbyte +empeg +em_text +emu10k1-gp +em_u32 +enclosure +eni +epat +epca +epia +epic100 +eql +esb2rom +esi-sir +esp4 +esp6 +et131x +et61x251 +eth1394 +eurotechwdt +evbug +evdev +exportfs +ext2 +ext3 +ext4dev +f71805f +f71882fg +f75375s +fakephp +fan +farsync +fat +faulty +fbcon +fb_ddc +fb_sys_fops +fcrypt +fdomain +fdomain_cs +fealnx +ff-memless +firestream +fit2 +fit3 +floppy +fm801-gp +fmvj18x_cs +font +forcedeth +fore_200e +freevxfs +freq_table +friq +frpw +fsam7400 +fscher +fschmd +fscpos +ftdi-elan +ftdi_sio +ftl +fujitsu-laptop +fujitsu_ts +funsoft +fuse +g450_pll +gadgetfs +gamecon +gameport +garmin_gps +garp +g_cdc +gcm +gdth +generic_serial +gen_probe +g_ether +gf128mul +gf2k +g_file_storage +gfs +gfs2 +gigaset +girbil-sir +gl518sm +gl520sm +gl620a +gnbd +gpio_keys +gpio_mouse +grip +grip_mp +gru +g_serial +gspca_conex +gspca_etoms +gspca_main +gspca_mars +gspca_ov519 +gspca_pac207 +gspca_pac7311 +gspca_sonixb +gspca_sonixj +gspca_spca500 +gspca_spca501 +gspca_spca505 +gspca_spca506 +gspca_spca508 +gspca_spca561 +gspca_stk014 +gspca_sunplus +gspca_t613 +gspca_tv8532 +gspca_vc032x +gspca_zc3xx +gtco +guillemot +gunze +gx1fb +gxfb +g_zero +hamachi +hangcheck-timer +hci_uart +hci_vhci +hdaps +hdlc +hdlc_cisco +hdlcdrv +hdlc_fr +hdlc_ppp +hdlc_raw +hdlc_raw_eth +hdlc_x25 +he +heci +hecubafb +hermes +hexium_gemini +hexium_orion +hfc4s8s_l1 +hfcmulti +hfcpci +hfc_usb +hfs +hfsplus +hgafb +hid +hidp +hifn_795x +hisax +hisax_fcpcipnp +hisax_isac +hisax_st5481 +horizon +hostap +hostap_cs +hostap_pci +hostap_plx +hp100 +hp4x +hpfs +hpilo +hptiop +hp-wmi +hso +htc-pasic3 +hwmon-vid +hysdn +i2c-algo-bit +i2c-algo-pca +i2c-algo-pcf +i2c-ali1535 +i2c-ali1563 +i2c-ali15x3 +i2c-amd756 +i2c-amd756-s4882 +i2c-amd8111 +i2c-core +i2c-dev +i2c-gpio +i2c-i801 +i2c-isch +i2c-matroxfb +i2c-nforce2 +i2c-nforce2-s4985 +i2c-ocores +i2c-parport +i2c-parport-light +i2c-pca-platform +i2c-piix4 +i2c-simtec +i2c-sis5595 +i2c-sis630 +i2c-sis96x +i2c-stub +i2c-taos-evm +i2c-tiny-usb +i2c-via +i2c-viapro +i2c-voodoo3 +i2o_block +i2o_bus +i2o_config +i2o_core +i2o_proc +i2o_scsi +i3000_edac +i5000_edac +i5100_edac +i5k_amb +i6300esb +i810 +i82092 +i82975x_edac +i830 +i8k +i915 +ia32_aout +ib700wdt +ib_addr +ib_cm +ib_core +ib_ipath +ib_ipoib +ib_iser +ib_mad +ibmaem +ibmasm +ibmasr +ibmcam +ibmpex +ib_mthca +ib_sa +ib_srp +ib_ucm +ib_umad +ib_uverbs +ichxrom +icplus +idmouse +idt77252 +ieee1394 +ieee80211 +ieee80211_crypt +ieee80211_crypt_ccmp +ieee80211_crypt_tkip +ieee80211_crypt_wep +ifb +iforce +igb +ili9320 +imm +inet_lro +inexio +inftl +initio +input-polldev +intel-agp +intelfb +intel_menlow +intel-rng +intel_vr_nor +interact +ioatdma +ioc4 +io_edgeport +io_ti +iowarrior +ip2 +ip6_queue +ip6table_filter +ip6table_mangle +ip6table_raw +ip6_tables +ip6table_security +ip6t_ah +ip6t_eui64 +ip6t_frag +ip6t_hbh +ip6t_HL +ip6t_hl +ip6t_ipv6header +ip6t_LOG +ip6t_mh +ip6t_REJECT +ip6t_rt +ip6_tunnel +ipaq +ipcomp +ipcomp6 +ipddp +ipg +ip_gre +iphase +ipip +ipmi_devintf +ipmi_msghandler +ipmi_poweroff +ipmi_si +ipmi_watchdog +ip_queue +ipr +ips +iptable_filter +iptable_mangle +iptable_nat +iptable_raw +ip_tables +iptable_security +ipt_addrtype +ipt_ah +ipt_CLUSTERIP +ipt_ECN +ipt_ecn +ipt_LOG +ipt_MASQUERADE +ipt_NETMAP +ipt_recent +ipt_REDIRECT +ipt_REJECT +ipt_TTL +ipt_ttl +ipt_ULOG +ipv6 +ip_vs +ip_vs_dh +ip_vs_ftp +ip_vs_lblc +ip_vs_lblcr +ip_vs_lc +ip_vs_nq +ip_vs_rr +ip_vs_sed +ip_vs_sh +ip_vs_wlc +ip_vs_wrr +ipw +ipw2100 +ipw2200 +ipwireless +ipx +ircomm +ir-common +ircomm-tty +irda +irda-usb +ir-kbd-i2c +irlan +irnet +irtty-sir +iscsi_ibft +iscsi_tcp +iscsi_trgt +isdn +isdn_bsdcomp +isdnhdlc +isight_firmware +isl6405 +isl6421 +isofs +isp116x-hcd +isp1760 +it87 +it8712f_wdt +iTCO_vendor_support +iTCO_wdt +itd1000 +ivtv +ivtvfb +iw_c2 +iw_cm +iw_cxgb3 +iwl3945 +iwlagn +iwlcore +ixgb +ixgbe +ixj +ixj_pcmcia +jbd +jbd2 +jedec_probe +jffs2 +jfs +joydev +joydump +jsm +k8temp +kafs +kahlua +kaweth +kbic +kbtab +kernelcapi +keyspan +keyspan_pda +keyspan_remote +khazad +kingsun-sir +kl5kusb105 +kobil_sct +konicawc +ks0108 +ks0127 +ks959-sir +ksdazzle-sir +ktti +kvm +kvm-amd +kvm-intel +kyrofb +l1oip +l2cap +l440gx +l64781 +lanai +lapb +lapbether +lcd +ldusb +lec +led-class +leds-gpio +leds-pca9532 +leds-pca955x +ledtrig-default-on +ledtrig-heartbeat +ledtrig-timer +legousbtower +lgdt330x +libata +libcrc32c +libertas +libertas_cs +libertas_sdio +libiscsi +libphy +libsas +libsrp +libusual +lightning +linear +lirc_atiusb +lirc_bt829 +lirc_cmdir +lirc_dev +lirc_i2c +lirc_igorplugusb +lirc_imon +lirc_it87 +lirc_mceusb +lirc_mceusb2 +lirc_pvr150 +lirc_sasem +lirc_serial +lirc_serial_igor +lirc_sir +lirc_streamzap +lirc_ttusbir +litelink-sir +lkkbd +llc2 +lm63 +lm70 +lm75 +lm77 +lm78 +lm80 +lm83 +lm85 +lm87 +lm90 +lm92 +lm93 +lmc +lmpcm_usb +lnbp21 +lockd +lock_dlm +loop +lp +lpfc +lrw +ltv350qv +lxfb +lxt +lzo +lzo_compress +lzo_decompress +m25p80 +m52790 +ma600-sir +mac80211 +machzwd +macmodes +macvlan +magellan +map_absent +map_funcs +map_ram +map_rom +marvell +matroxfb_accel +matroxfb_base +matroxfb_crtc2 +matroxfb_DAC1064 +matroxfb_g450 +matroxfb_maven +matroxfb_misc +matroxfb_Ti3026 +matrox_w1 +max1619 +max6650 +max6875 +max7301 +max732x +mbcache +mbp_nvidia_bl +mcp2120-sir +mcp23s08 +mcs7780 +mcs7830 +mct_u232 +md4 +mdc800 +mdio-bitbang +md-mod +megaraid +megaraid_mbox +megaraid_mm +megaraid_sas +meye +mga +michael_mic +microcode +microtek +mii +minix +mISDN_core +mISDN_dsp +mk712 +mkiss +mlx4_core +mlx4_ib +mmc_block +mmc_core +mmc_spi +mos7720 +mos7840 +moto_modem +moxa +mpoa +mptbase +mptctl +mptfc +mptlan +mptsas +mptscsih +mptspi +mpu401 +msdos +msi-laptop +msp3400 +msr +mt2060 +mt20xx +mt2131 +mt2266 +mt312 +mt352 +mt9m001 +mt9v022 +mtd +mtd_blkdevs +mtdblock +mtdblock_ro +mtdchar +mtdconcat +mtd_dataflash +mtdoops +mtdram +mtouch +multipath +mwave +mxb +mxl5005s +mxl5007t +mxser +myri10ge +nand +nand_ecc +nand_ids +nandsim +natsemi +navman +nbd +ncpfs +ndiswrapper +ne2k-pci +neofb +net1080 +net2280 +netconsole +netrom +netsc520 +nettel +netwave_cs +netxen_nic +newtonkbd +nf_conntrack +nf_conntrack_amanda +nf_conntrack_ftp +nf_conntrack_h323 +nf_conntrack_ipv4 +nf_conntrack_ipv6 +nf_conntrack_irc +nf_conntrack_netbios_ns +nf_conntrack_netlink +nf_conntrack_pptp +nf_conntrack_proto_gre +nf_conntrack_proto_sctp +nf_conntrack_proto_udplite +nf_conntrack_sip +nf_conntrack_tftp +nf_nat +nf_nat_amanda +nf_nat_ftp +nf_nat_h323 +nf_nat_irc +nf_nat_pptp +nf_nat_proto_gre +nf_nat_proto_sctp +nf_nat_proto_udplite +nf_nat_sip +nf_nat_snmp_basic +nf_nat_tftp +nfnetlink +nfnetlink_log +nfnetlink_queue +nfs +nfs_acl +nfsd +nftl +n_hdlc +niu +nls_ascii +nls_cp1250 +nls_cp1251 +nls_cp1255 +nls_cp437 +nls_cp737 +nls_cp775 +nls_cp850 +nls_cp852 +nls_cp855 +nls_cp857 +nls_cp860 +nls_cp861 +nls_cp862 +nls_cp863 +nls_cp864 +nls_cp865 +nls_cp866 +nls_cp869 +nls_cp874 +nls_cp932 +nls_cp936 +nls_cp949 +nls_cp950 +nls_euc-jp +nls_iso8859-1 +nls_iso8859-13 +nls_iso8859-14 +nls_iso8859-15 +nls_iso8859-2 +nls_iso8859-3 +nls_iso8859-4 +nls_iso8859-5 +nls_iso8859-6 +nls_iso8859-7 +nls_iso8859-9 +nls_koi8-r +nls_koi8-ru +nls_koi8-u +nls_utf8 +nmclan_cs +nozomi +n_r3964 +ns558 +ns83820 +nsc_gpio +nsc-ircc +ntfs +nvidiafb +nvram +nxt200x +nxt6000 +ocfs2 +ocfs2_dlm +ocfs2_dlmfs +ocfs2_nodemanager +ocfs2_stackglue +ocfs2_stack_o2cb +ocfs2_stack_user +ohci1394 +ohci-hcd +old_belkin-sir +olympic +omfs +omninet +on20 +on26 +onenand +onenand_sim +opl3 +oprofile +option +or51132 +or51211 +orinoco +orinoco_cs +orinoco_nortel +orinoco_pci +orinoco_plx +orinoco_tmd +osst +oti6858 +output +ov511 +ov511_decomp +ov518_decomp +ov7670 +ovcamchip +p54common +p54pci +p54usb +p80211 +p8023 +paride +parkbd +parport +parport_ax88796 +parport_cs +parport_pc +parport_serial +pas2 +pata_acpi +pata_ali +pata_amd +pata_artop +pata_atiixp +pata_cmd64x +pata_cs5520 +pata_cs5530 +pata_efar +pata_hpt366 +pata_hpt37x +pata_hpt3x3 +pata_it8213 +pata_it821x +pata_jmicron +pata_marvell +pata_mpiix +pata_netcell +pata_ninja32 +pata_ns87410 +pata_ns87415 +pata_oldpiix +pata_pcmcia +pata_pdc2027x +pata_pdc202xx_old +pata_rz1000 +pata_sch +pata_serverworks +pata_sil680 +pata_sis +pata_sl82c105 +pata_triflex +pata_via +pbe5 +pc300 +pc87360 +pc8736x_gpio +pc87413_wdt +pc87427 +pca953x +pcbc +pcd +pcf857x +pcf8591 +pci +pci200syn +pciehp +pci_hotplug +pcilynx +pcips2 +pci_slot +pcmcia +pcmcia_core +pcnet32 +pcnet_cs +pcspkr +pcwd_pci +pcwd_usb +pd +pd6729 +pda_power +pdc_adma +pegasus +penmount +pf +pg +phantom +phidget +phidgetkit +phidgetmotorcontrol +phidgetservo +phonedev +phram +physmap +pktcdvd +pktgen +pl2303 +platform_lcd +plat_nand +plat-ram +plip +plusb +pluto2 +pm2fb +pm3fb +pmc551 +powermate +powernow-k8 +ppa +ppdev +ppp_async +ppp_deflate +ppp_generic +ppp_mppe +pppoatm +pppoe +pppol2tp +pppox +ppp_synctty +prism2_usb +prism54 +processor +progear_bl +psmouse +pss +pt +pvrusb2 +pwc +qla1280 +qla2xxx +qla3xxx +qla4xxx +qlogic_cs +qlogicfas408 +qnx4 +qsemi +qt1010 +quickcam +quickcam_messenger +quota_v1 +quota_v2 +r128 +r8169 +r8a66597-hcd +radeon +radeonfb +radio-gemtek-pci +radio-maestro +radio-maxiradio +radio-si470x +raid0 +raid1 +raid10 +raid456 +raid_class +raw +raw1394 +ray_cs +rdma_cm +rdma_ucm +redboot +reed_solomon +reiserfs +rfc1051 +rfc1201 +rfcomm +rfd_ftl +rfkill +rfkill-input +ricoh_mmc +rio +rio500 +riscom8 +rivafb +rmd128 +rmd160 +rmd256 +rmd320 +rndis_host +rndis_wlan +rocket +romfs +rose +rpcsec_gss_krb5 +rpcsec_gss_spkm3 +rrunner +rsrc_nonstatic +rt2400pci +rt2500pci +rt2500usb +rt2x00lib +rt2x00pci +rt2x00usb +rt61pci +rt73usb +rtc-ds1305 +rtc-ds1307 +rtc-ds1374 +rtc-ds1553 +rtc-ds1672 +rtc-ds1742 +rtc-fm3130 +rtc-isl1208 +rtc-m41t80 +rtc-m41t94 +rtc-m48t59 +rtc-m48t86 +rtc-max6900 +rtc-max6902 +rtc-pcf8563 +rtc-pcf8583 +rtc-rs5c348 +rtc-rs5c372 +rtc-stk17ta8 +rtc-test +rtc-v3020 +rtc-x1205 +rtl8150 +rtl8180 +rtl8187 +rxkad +s1d13xxxfb +s2255drv +s2io +s3fb +s5h1409 +s5h1411 +s5h1420 +saa5246a +saa5249 +saa6588 +saa6752hs +saa7110 +saa7111 +saa7114 +saa7115 +saa7127 +saa7134 +saa7134-alsa +saa7134-dvb +saa7134-empress +saa7146 +saa7146_vv +saa717x +saa7185 +safe_serial +salsa20_generic +salsa20-x86_64 +sata_inic162x +sata_mv +sata_nv +sata_promise +sata_qstor +sata_sil +sata_sil24 +sata_sis +sata_svw +sata_sx4 +sata_uli +sata_via +sata_vsc +savage +savagefb +sb +sb1000 +sbc60xxwdt +sbc8360 +sbc_epx_c3 +sbc_gxx +sb_lib +sbni +sbp2 +sbs +sbshc +sc1200wdt +sc520cdp +sc520_wdt +sc92031 +scb2_flash +sch_atm +sch_cbq +sch_dsmark +sch_gred +sch_hfsc +sch_htb +sch_ingress +sch_netem +sch_prio +sch_red +sch_sfq +sch_tbf +sch_teql +sco +scsi_debug +scsi_dh +scsi_dh_alua +scsi_dh_emc +scsi_dh_hp_sw +scsi_dh_rdac +scsi_mod +scsi_tgt +scsi_transport_fc +scsi_transport_iscsi +scsi_transport_sas +scsi_transport_spi +scsi_transport_srp +scsi_wait_scan +sctp +sdhci +sdhci-pci +sdio_uart +sd_mod +sdricoh_cs +se401 +sedlbauer_cs +seed +seqiv +ser_gigaset +serial_cs +serio_raw +sermouse +serpent +serport +ses +sfc +sg +sha1_generic +sha256_generic +sha512_generic +sh_mobile_ceu_camera +shpchp +sidewinder +sierra +sir-dev +sis +sis190 +sis5595 +sis900 +sis-agp +sisfb +sisusbvga +sit +skfp +skge +sky2 +sl811_cs +sl811-hcd +slhc +slip +slram +sm501 +sm501fb +smbfs +smc91c92_cs +sms1xxx +smsc +smsc37b787_wdt +smsc47b397 +smsc47m1 +smsc47m192 +smsc-ircc2 +sn9c102 +snd +snd-ac97-codec +snd-ad1889 +snd-ak4114 +snd-ak4117 +snd-ak4xxx-adda +snd-ali5451 +snd-als300 +snd-als4000 +snd-atiixp +snd-atiixp-modem +snd-au8810 +snd-au8820 +snd-au8830 +snd-aw2 +snd-azt3328 +snd-bt87x +snd-bt-sco +snd-ca0106 +snd-cmipci +snd-cs4281 +snd-cs46xx +snd-cs5530 +snd-cs8427 +snd-darla20 +snd-darla24 +snd-dummy +snd-echo3g +snd-emu10k1 +snd-emu10k1-synth +snd-emu10k1x +snd-emux-synth +snd-ens1370 +snd-ens1371 +snd-es1938 +snd-es1968 +snd-fm801 +snd-gina20 +snd-gina24 +snd-hda-intel +snd-hdsp +snd-hdspm +snd-hifier +snd-hwdep +snd-i2c +snd-ice1712 +snd-ice1724 +snd-ice17xx-ak4xxx +snd-indigo +snd-indigodj +snd-indigoio +snd-intel8x0 +snd-intel8x0m +snd-korg1212 +snd-layla20 +snd-layla24 +snd-maestro3 +snd-mia +snd-mixart +snd-mixer-oss +snd-mona +snd-mpu401 +snd-mpu401-uart +snd-mtpav +snd-mts64 +snd-nm256 +snd-opl3-lib +snd-opl3-synth +snd-oxygen +snd-oxygen-lib +snd-page-alloc +snd-pcm +snd-pcm-oss +snd-pcsp +snd-pcxhr +snd-pdaudiocf +snd-portman2x4 +snd-pt2258 +snd-rawmidi +snd-riptide +snd-rme32 +snd-rme96 +snd-rme9652 +snd-sb16-dsp +snd-sb-common +snd-seq +snd-seq-device +snd-seq-dummy +snd-seq-midi +snd-seq-midi-emul +snd-seq-midi-event +snd-seq-oss +snd-seq-virmidi +snd-serial-u16550 +snd-soc-core +snd-sonicvibes +snd-tea575x-tuner +snd-timer +snd-trident +snd-usb-audio +snd-usb-caiaq +snd-usb-lib +snd-usb-usx2y +snd-util-mem +snd-via82xx +snd-via82xx-modem +snd-virmidi +snd-virtuoso +snd-vx222 +snd-vx-lib +snd-vxpocket +snd-ymfpci +soc_camera +soc_camera_platform +softcursor +softdog +sony-laptop +sound +soundcore +sound_firmware +sp8870 +sp887x +spaceball +spaceorb +spcp8x5 +specialix +spectrum_cs +speedtch +spi_bitbang +spi_butterfly +spidev +spi_lm70llp +squashfs +sr_mod +ssb +sscape +ssfdc +sstfb +st +starfire +stex +stinger +stir4200 +stkwebcam +stowaway +stp +stradis +strip +stv0297 +stv0299 +stv680 +sundance +sungem +sungem_phy +sunhme +suni +sunkbd +sunrpc +svcrdma +svgalib +sx +sx8 +sym53c500_cs +sym53c8xx +synclink +synclink_cs +synclink_gt +synclinkmp +syncppp +syscopyarea +sysfillrect +sysimgblt +sysv +t1pci +tcp_bic +tcp_highspeed +tcp_htcp +tcp_hybla +tcp_illinois +tcp_lp +tcp_probe +tcp_scalable +tcp_vegas +tcp_veno +tcp_westwood +tcp_yeah +tcrypt +tda10021 +tda10023 +tda10048 +tda1004x +tda10086 +tda18271 +tda7432 +tda8083 +tda826x +tda827x +tda8290 +tda9840 +tda9875 +tda9887 +tdfx +tdfxfb +tea +tea5761 +tea5767 +tea6415c +tea6420 +tehuti +tekram-sir +teles_cs +tg3 +tgr192 +thermal +thinkpad_acpi +thinkpad_ec +thmc50 +tifm_7xx1 +tifm_core +tifm_sd +tileblit +tipc +ti_usb_3410_5052 +tlan +tlclk +tle62x0 +tlsf +tmdc +tms380tr +tmscsim +tmspci +toshiba_acpi +touchit213 +touchright +touchwin +tpm +tpm_atmel +tpm_bios +tpm_infineon +tpm_nsc +tpm_tis +tps65010 +tp_smapi +trancevibrator +tridentfb +trix +ts5500_flash +ts_bm +ts_fsm +ts_kmp +tsl2550 +ttpci-eeprom +ttusb_dec +ttusbdecfe +tua6100 +tulip +tun +tuner +tuner-3036 +tuner-simple +tuner-types +tuner-xc2028 +tunnel4 +tunnel6 +turbografx +tvaudio +tveeprom +tvp5150 +twidjoy +twofish +twofish_common +twofish-x86_64 +typhoon +u132-hcd +uart401 +uart6850 +ub +ubi +ubifs +ucb1400_ts +udf +ueagle-atm +ufs +uhci-hcd +uinput +uio +uio_cif +uio_pdrv +uio_pdrv_genirq +uio_smx +uli526x +ultracam +umem +unionfs +upd64031a +upd64083 +uPD98402 +usb8xxx +usbatm +usbcore +usb_debug +usb_gigaset +usbhid +usbkbd +usblcd +usbled +usblp +usbmon +usbmouse +usbnet +usbserial +usb-storage +usbtouchscreen +usbvideo +usbvision +uss720 +uvcvideo +uvesafb +v4l1-compat +v4l2-common +v4l2-int-device +ves1820 +ves1x93 +vesafb +veth +vfat +vga16fb +vgastate +vgg2432a4 +via +via686a +via-agp +via_chrome9 +via-ircc +via-rhine +via-velocity +vicam +video +video1394 +videobuf-core +videobuf-dma-contig +videobuf-dma-sg +videobuf-dvb +videobuf-vmalloc +videocodec +videodev +virtio +virtio_balloon +virtio_blk +virtio_console +virtio_net +virtio_pci +virtio_ring +virtio-rng +visor +vitesse +vivi +vlsi_ir +v_midi +vmlfb +vp27smpx +vpx3220 +vsxxxaa +vt1211 +vt8231 +vt8623fb +w1_ds2433 +w1_ds2760 +w1-gpio +w1_smem +w1_therm +w83627ehf +w83627hf +w83627hf_wdt +w83697hf_wdt +w83781d +w83791d +w83792d +w83793 +w83877f_wdt +w83977af_ir +w83977f_wdt +w83l785ts +w83l786ng +w9966 +w9968cf +wacom +wafer5823wdt +wanrouter +wanxl +warrior +wavelan_cs +wbsd +wdt_pci +whiteheat +winbond-840 +wire +wl3501_cs +wm8739 +wm8775 +wm97xx-ts +wmi +wp512 +x25 +x25_asy +xc5000 +xcbc +xen-blkfront +xen-fbfront +xen-kbdfront +xen-netfront +xfrm4_mode_beet +xfrm4_mode_transport +xfrm4_mode_tunnel +xfrm4_tunnel +xfrm6_mode_beet +xfrm6_mode_ro +xfrm6_mode_transport +xfrm6_mode_tunnel +xfrm6_tunnel +xfrm_ipcomp +xfrm_user +xfs +xirc2ps_cs +xircom_cb +xor +xp +xpad +xpc +xpnet +xprtrdma +x_tables +xt_CLASSIFY +xt_comment +xt_connbytes +xt_connlimit +xt_CONNMARK +xt_connmark +xt_CONNSECMARK +xt_conntrack +xt_dccp +xt_DSCP +xt_dscp +xt_esp +xt_hashlimit +xt_helper +xt_iprange +xtkbd +xt_length +xt_limit +xt_mac +xt_MARK +xt_mark +xt_multiport +xt_NFLOG +xt_NFQUEUE +xt_NOTRACK +xt_owner +xt_physdev +xt_pkttype +xt_policy +xt_quota +xt_RATEEST +xt_rateest +xt_realm +xts +xt_sctp +xt_SECMARK +xt_state +xt_statistic +xt_string +xt_TCPMSS +xt_tcpmss +xt_tcpudp +xt_time +xt_TRACE +xt_u32 +xusbatm +yam +yealink +yellowfin +yenta_socket +zatm +zaurus +zc0301 +zd1201 +zd1211rw +zhenhua +zl10353 +zlib_deflate +zr36016 +zr36050 +zr36060 +zr36067 +zr364xx --- linux-2.6.27.orig/debian/tests/README +++ linux-2.6.27/debian/tests/README @@ -0,0 +1,21 @@ +Scripts placed in this directory get called one at a time by run-parts(8). +The scripts are expected to perform some sort of sanity checks on the +finished build. Scripts will be called once for each flavour. + +Some environment variables are exported to make life a little easier: + +DPKG_ARCH : The dpkg architecture (e.g. "amd64") +KERN_ARCH : The kernel architecture (e.g. "x86_64") +FLAVOUR : The specific flavour for this run (e.g. "generic") +VERSION : The full version of this build (e.g. 2.6.22-1) +REVISION : The exact revision of this build (e.g. 1.3) +PREV_REVISION : The revision prior to this one +ABI_NUM : The specific ABI number for this build (e.g. 2) +PREV_ABI_NUM : The previous ABI number. Can be the same as ABI_NUM. +BUILD_DIR : The directory where this build took place +INSTALL_DIR : The directory where the package is prepared +SOURCE_DIR : Where the main kernel source is + +Scripts are expected to have a zero exit status when no problems occur, +and non-zero when an error occurs that should stop the build. Scripts +should print whatever info they deem needed to deduce the problem. --- linux-2.6.27.orig/debian/tests/check-aliases +++ linux-2.6.27/debian/tests/check-aliases @@ -0,0 +1,24 @@ +#!/usr/bin/perl -w + +my %map; + +print "Checking for dupe aliases in $ENV{'FLAVOUR'}...\n"; + +$aliases = + "$ENV{'INSTALL_DIR'}/lib/modules/$ENV{'VERSION'}-$ENV{'FLAVOUR'}/modules.alias"; + +open(ALIASES, "< $aliases") or die "Could not open $aliases"; + +while () { + chomp; + my ($junk, $alias, $module) = split; + + if (defined($map{$alias})) { + printf("%s %20s / %-20s : %s \n", ("$map{$alias}" eq "$module") + ? "INT" : " ", $map{$alias}, $module, $alias); + } else { + $map{$alias} = $module; + } +} + +exit(0); --- linux-2.6.27.orig/debian/commit-templates/patch +++ linux-2.6.27/debian/commit-templates/patch @@ -0,0 +1,26 @@ +# Ubuntu commit template. +# +# NOTE: This gets reformatted for debian/changelog +# +# The initial UBUNTU is a flag that this is an Ubuntu commit. It will be +# referenced to the Author in the debian/changelog entry. +# +# The text following is the short message that will be placed in the +# changelog. Extra text on the following lines will be ignored, but left +# in the git commit. Lines with # will be ignored in the commit. +# +# OriginalAuthor allows for alternate attribution. +# +# OriginalLocation allows for a URL or description of where the patch came +# from. +# +# BugLink is an URL to a Malone bug. +# +# Ignore: yes will keep this commit from showing up in the changelog. +# +UBUNTU: +# OriginalAuthor: +# OriginalLocation: +# BugLink: # +# Ignore: yes +# Other text below here. --- linux-2.6.27.orig/debian/commit-templates/sauce-patch +++ linux-2.6.27/debian/commit-templates/sauce-patch @@ -0,0 +1,37 @@ +# Ubuntu commit template. +# +# NOTE: This gets reformatted for debian/changelog +# +# +# SAUCE refers to the fact that this patch might not go upstream, but we need to +# carry it to successive releases. In most cases you DONOT want to use this +# template. +# +# An example of a SAUCE patch is the ACPI DSDT-in-initramfs patch which has been +# refused upstream, but still provides useful functionality to users with broken +# BIOSes. +# +#------------------------------------------------------------------------- +# +# The initial UBUNTU is a flag that this is an Ubuntu commit. It will be +# referenced to the Author in the debian/changelog entry. +# +# The text following is the short message that will be placed in the +# changelog. Extra text on the following lines will be ignored, but left +# in the git commit. Lines with # will be ignored in the commit. +# +# OriginalAuthor allows for alternate attribution. +# +# OriginalLocation allows for a URL or description of where the patch came +# from. +# +# BugLink is an URL to a Malone bug. +# +# Ignore: yes will keep this commit from showing up in the changelog. +# +UBUNTU: SAUCE: +# OriginalAuthor: +# OriginalLocation: +# BugLink: +# Ignore: yes +# Other text below here. --- linux-2.6.27.orig/debian/commit-templates/bumpabi +++ linux-2.6.27/debian/commit-templates/bumpabi @@ -0,0 +1,2 @@ +UBUNTU: Bump ABI +Ignore: yes --- linux-2.6.27.orig/debian/commit-templates/missing-modules +++ linux-2.6.27/debian/commit-templates/missing-modules @@ -0,0 +1,2 @@ +UBUNTU: build/modules: Add modules that have intentionally gone missing +Ignore: yes --- linux-2.6.27.orig/debian/commit-templates/external-driver +++ linux-2.6.27/debian/commit-templates/external-driver @@ -0,0 +1,19 @@ +# Ubuntu external driver commit. +# +# NOTE: This gets reformatted for README.Ubuntu-External-Drivers and +# debian/changelog. +# +# This is only needed when a driver is added, updated or removed. It is +# not needed when patches or fixes are applied to the driver. If the +# driver is being removed, add the line: +# +# Removing: yes +# +# to the commit, and you can remove all other tags (except UBUNTU:). +# +UBUNTU: +ExternalDriver: +Description: +Url: +Mask: +Version: --- linux-2.6.27.orig/debian/commit-templates/newrelease +++ linux-2.6.27/debian/commit-templates/newrelease @@ -0,0 +1,2 @@ +UBUNTU: Start new release +Ignore: yes --- linux-2.6.27.orig/debian/commit-templates/update-configs +++ linux-2.6.27/debian/commit-templates/update-configs @@ -0,0 +1,9 @@ +UBUNTU: Updating configs +# +# This template is used for commit messages that don't need to +# show up in debian/changelog. Administrative stuff like config +# updates, ABI bumps, etc. Setting 'Ignore: yes' prevents +# 'debian/rules insertchanges' from inserting this commit meesage +# as a changelog entry. +# +Ignore: yes --- linux-2.6.27.orig/debian/control-scripts/prerm +++ linux-2.6.27/debian/control-scripts/prerm @@ -0,0 +1,294 @@ +#! /usr/bin/perl +# -*- Mode: Perl -*- +# image.prerm --- +# Author : root ( root@melkor.pilgrim.umass.edu ) +# Created On : Fri May 17 03:28:59 1996 +# Created On Node : melkor.pilgrim.umass.edu +# Last Modified By : Manoj Srivastava +# Last Modified On : Sat Aug 5 13:14:17 2006 +# Last Machine Used: glaurung.internal.golden-gryphon.com +# Update Count : 85 +# Status : Unknown, Use with caution! +# HISTORY : +# Description : +# +# +# $Id: image.prerm,v 1.22 2003/10/07 16:24:20 srivasta Exp $ +# +# +#use strict; + +$|=1; +# Predefined values: +my $version = "=V"; +my $link_in_boot = ""; # Should be empty, mostly +my $no_symlink = ""; # Should be empty, mostly +my $reverse_symlink = ""; # Should be empty, mostly +my $do_symlinks = "Yes"; # target machine defined +my $do_boot_enable = "Yes"; # target machine defined +my $do_bootfloppy = "Yes"; # target machine defined +my $do_bootloader = "Yes"; # target machine defined +my $move_image = ''; # target machine defined +my $kimage = "=K"; # Should be empty, mostly +my $loader = "=L"; # lilo, silo, quik, palo, vmelilo, or nettrom +my $image_dir = "/boot"; # where the image is located +my $clobber_modules = ''; # target machine defined +my $initrd = "YES"; # initrd kernel +my $use_hard_links = ''; # hardlinks do not wirk across fs boundaries +my $postinst_hook = ''; #Normally we do not +my $postrm_hook = ''; #Normally we do not +my $preinst_hook = ''; #Normally we do not +my $prerm_hook = ''; #Normally we do not +my $minimal_swap = ''; # Do not swap symlinks +my $ignore_depmod_err = ''; # normally we do not +my $relink_build_link = 'YES'; # There is no harm in checking the link +my $force_build_link = ''; # There is no harm in checking the link +my $kernel_arch = "=B"; +my $ramdisk = "/usr/sbin/update-initramfs"; +my $package_name = "linux-image-$version"; + +my $Loader = "NoLOADER"; # +$Loader = "LILO" if $loader =~ /^lilo/io; +$Loader = "SILO" if $loader =~ /^silo/io; +$Loader = "QUIK" if $loader =~ /^quik/io; +$Loader = "yaboot" if $loader =~ /^yaboot/io; +$Loader = "PALO" if $loader =~ /^palo/io; +$Loader = "NETTROM" if $loader =~ /^nettrom/io; +$Loader = "VMELILO" if $loader =~ /^vmelilo/io; +$Loader = "ZIPL" if $loader =~ /^zipl/io; +$Loader = "ELILO" if $loader =~ /^elilo/io; + + +# This should not point to /tmp, because of security risks. +my $temp_file_name = "/var/log/$loader" . "_log.$$"; + +#known variables +my $image_dest = "/"; +my $realimageloc = "/$image_dir/"; +my $have_conffile = ""; +my $CONF_LOC = '/etc/kernel-img.conf'; +my $relative_links = ''; +my $silent_loader = ''; +my $warn_reboot = 'Yes'; # Warn that we are installing a version of + # the kernel we are running + +# remove multiple leading slashes; make sure there is at least one. +$realimageloc =~ s|^/*|/|o; +$realimageloc =~ s|/+|/|o; + +my $DEBUG = 0; + +# Variables used +my $image=''; +my $ret=0; +my $seen=''; +my $answer=''; +my $running = ''; +my $WouldInvalidate = 0; + +if ($ARGV[0] && ($ARGV[0] =~ /remove/ || $ARGV[0] =~ /upgrade/)) { + if (-l "/usr/doc/linux-image-$version") { + unlink "/usr/doc/linux-image-$version"; + } +} + +# Ignore all invocations uxcept when called on to remove +exit 0 unless ($ARGV[0] && $ARGV[0] =~ /remove/) ; + +# Paranoid check to make sure that the correct value is put in there +if (! $kimage) { $kimage = "vmlinuz";} # Hmm. empty +elsif ($kimage =~ m/^b?zImage$/o) { $kimage = "vmlinuz";} # these produce vmlinuz +elsif ($kimage =~ m/^[iI]mage$/o) { my $nop = $kimage; } +elsif ($kimage =~ m/^vmlinux$/o) { my $nop = $kimage; } +else { $kimage = "vmlinuz";} # Default + +if (-r "$CONF_LOC" && -f "$CONF_LOC" ) { + if (open(CONF, "$CONF_LOC")) { + while () { + chomp; + s/\#.*$//g; + next if /^\s*$/; + + $do_symlink = "" if /^\s*do_symlinks\s*=\s*(no|false|0)\s*$/ig; + $no_symlink = "" if /^\s*no_symlinks\s*=\s*(no|false|0)\s*$/ig; + $reverse_symlink = "" if /^\s*reverse_symlinks\s*=\s*(no|false|0)\s*$/ig; + $link_in_boot = "" if /^\s*image_in_boot\s*=\s*(no|false|0)\s*$/ig; + $link_in_boot = "" if /^\s*link_in_boot\s*=\s*(no|false|0)\s*$/ig; + $move_image = "" if /^\s*move_image\s*=\s*(no|false|0)\s*$/ig; + $clobber_modules = '' if /^\s*clobber_modules\s*=\s*(no|false|0)\s*$/ig; + $do_boot_enable = '' if /^\s*do_boot_enable\s*=\s*(no|false|0)\s*$/ig; + $do_bootfloppy = '' if /^\s*do_bootfloppy\s*=\s*(no|false|0)\s*$/ig; + $relative_links = '' if /^\s*relative_links \s*=\s*(no|false|0)\s*$/ig; + $do_bootloader = '' if /^\s*do_bootloader\s*=\s*(no|false|0)\s*$/ig; + $do_initrd = '' if /^\s*do_initrd\s*=\s*(no|false|0)\s*$/ig; + $use_hard_links = '' if /^\s*use_hard_links\s*=\s*(no|false|0)\s*$/ig; + $silent_loader = '' if /^\s*silent_loader\s*=\s*(no|false|0)\s*$/ig; + $warn_reboot = '' if /^\s*warn_reboot\s*=\s*(no|false|0)\s*$/ig; + $minimal_swap = '' if /^\s*minimal_swap\s*=\s*(no|false|0)\s*$/ig; + $ignore_depmod_err = '' if /^\s*ignore_depmod_err\s*=\s*(no|false|0)\s*$/ig; + $relink_build_link = '' if /^\s*relink_build_link\s*=\s*(no|false|0)\s*$/ig; + $force_build_link = '' if /^\s*force_build_link\s*=\s*(no|false|0)\s*$/ig; + + + $do_symlink = "Yes" if /^\s*do_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $no_symlink = "Yes" if /^\s*no_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $reverse_symlink = "Yes" if /^\s*reverse_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $link_in_boot = "Yes" if /^\s*image_in_boot\s*=\s*(yes|true|1)\s*$/ig; + $link_in_boot = "Yes" if /^\s*link_in_boot\s*=\s*(yes|true|1)\s*$/ig; + $move_image = "Yes" if /^\s*move_image\s*=\s*(yes|true|1)\s*$/ig; + $clobber_modules = "Yes" if /^\s*clobber_modules\s*=\s*(yes|true|1)\s*$/ig; + $do_boot_enable = "Yes" if /^\s*do_boot_enable\s*=\s*(yes|true|1)\s*$/ig; + $do_bootfloppy = "Yes" if /^\s*do_bootfloppy\s*=\s*(yes|true|1)\s*$/ig; + $do_bootloader = "Yes" if /^\s*do_bootloader\s*=\s*(yes|true|1)\s*$/ig; + $relative_links = "Yes" if /^\s*relative_links\s*=\s*(yes|true|1)\s*$/ig; + $do_initrd = "Yes" if /^\s*do_initrd\s*=\s*(yes|true|1)\s*$/ig; + $use_hard_links = "Yes" if /^\s*use_hard_links\s*=\s*(yes|true|1)\s*$/ig; + $silent_loader = 'Yes' if /^\s*silent_loader\s*=\s*(yes|true|1)\s*$/ig; + $warn_reboot = 'Yes' if /^\s*warn_reboot\s*=\s*(yes|true|1)\s*$/ig; + $minimal_swap = 'Yes' if /^\s*minimal_swap\s*=\s*(yes|true|1)\s*$/ig; + $ignore_depmod_err = 'Yes' if /^\s*ignore_depmod_err\s*=\s*(yes|true|1)\s*$/ig; + $relink_build_link = 'Yes' if /^\s*relink_build_link\s*=\s*(yes|true|1)\s*$/ig; + $force_build_link = 'Yes' if /^\s*force_build_link\s*=\s*(yes|true|1)\s*$/ig; + + $image_dest = "$1" if /^\s*image_dest\s*=\s*(\S+)/ig; + $postinst_hook = "$1" if /^\s*postinst_hook\s*=\s*(\S+)/ig; + $postrm_hook = "$1" if /^\s*postrm_hook\s*=\s*(\S+)/ig; + $preinst_hook = "$1" if /^\s*preinst_hook\s*=\s*(\S+)/ig; + $prerm_hook = "$1" if /^\s*prerm_hook\s*=\s*(\S+)/ig; + $ramdisk = "$1" if /^\s*ramdisk\s*=\s*(.+)$/ig; + } + close CONF; + $have_conffile = "Yes"; + } +} + + +$ENV{KERNEL_ARCH}=$kernel_arch if $kernel_arch; + +#check to see if we are trying to remove a running kernel +# if so we abort right now. +chop($running=`uname -r`); +if ($running eq $version) { + print STDERR "WARN: Proceeding with removing running kernel image.\n"; +} + +#Now, they have an alternate kernel which they are currently running + +# This is just us being nice to lilo users. + +chdir("/") or die "could not chdir to /:$!\n"; + +if (-f "/etc/$loader.conf") { #I know, could be a link, but .. + open (LILO, "/etc/$loader.conf") || &success(); # this is not critical + while () { + chop; + s/\#.*//; # nix the comments + next unless /^\s*image\s*=\s(\S+)/o; + $image = $1; + if ($image && -e $image) { + while (defined($image) && -l $image) { + $image = readlink ($image); + } + if (defined($image) && -e $image) { + $WouldInvalidate |= $image =~ /$kimage-$version/; + } + else { + &success(); # invalid $loader.conf file + } + } + else { + &success(); # invalid $loader.conf file + } + } + close (LILO); + if ($WouldInvalidate) { + print STFERR "WARN: Proceeding with removing running kernel image.\n"; + &success(); + } +} + + +# set the env var stem +$ENV{'STEM'} = "linux"; + +sub exec_script { + my $type = shift; + my $script = shift; + print STDERR "Running $type hook script $script.\n"; + system ("$script $version $realimageloc$kimage-$version") && + print STDERR "User $type hook script [$script] "; + if ($?) { + if ($? == -1) { + print STDERR "failed to execute: $!\n"; + } + elsif ($? & 127) { + printf STDERR "died with signal %d, %s coredump\n", + ($? & 127), ($? & 128) ? 'with' : 'without'; + } + else { + printf STDERR "exited with value %d\n", $? >> 8; + } + exit $? >> 8; + } +} +sub run_hook { + my $type = shift; + my $script = shift; + if ($script =~ m,^/,) { + # Full path provided for the hook script + if (-x "$script") { + &exec_script($type,$script); + } + else { + die "The provided $type hook script [$script] could not be run.\n"; + } + } + else { + # Look for it in a safe path + for my $path ('/bin', '/sbin', '/usr/bin', '/usr/sbin') { + if (-x "$path/$script") { + &exec_script($type, "$path/$script"); + return 0; + } + } + # No luck + print STDERR "Could not find $type hook script [$script].\n"; + die "Looked in: '/bin', '/sbin', '/usr/bin', '/usr/sbin'\n"; + } +} + + +## Run user hook script here, if any +if (-x "$prerm_hook") { + &run_hook("prerm", $prerm_hook); +} +if (-d "/etc/kernel/prerm.d") { + print STDERR "Examining /etc/kernel/prerm.d.\n"; + system ("run-parts --verbose --exit-on-error --arg=$version " . + "--arg=$realimageloc$kimage-$version /etc/kernel/prerm.d") && + die "Failed to process /etc/kernel/prerm.d"; +} +if (-d "/etc/kernel/prerm.d/$version") { + print STDERR "Examining /etc/kernel/prerm.d/$version.\n"; + system ("run-parts --verbose --exit-on-error --arg=$version" . + " --arg=$realimageloc$kimage-$version " . + "/etc/kernel/prerm.d/$version") && + die "Failed to process /etc/kernel/prerm.d/$version"; +} + +sub success () { + -f "/lib/modules/$version/modules.dep" && + unlink "/lib/modules/$version/modules.dep"; + exit 0; +} + + + +&success(); +exit 0; +__END__ + + + + + --- linux-2.6.27.orig/debian/control-scripts/postinst +++ linux-2.6.27/debian/control-scripts/postinst @@ -0,0 +1,1087 @@ +#! /usr/bin/perl +# OriginalAuthor : Manoj Srivastava ( srivasta@pilgrim.umass.edu ) +# +# Customized for Ubuntu by: Ben Collins + +#use strict; #for debugging +use Cwd 'abs_path'; + +$|=1; + +# Predefined values: +my $version = "=V"; +my $link_in_boot = ""; # Should be empty, mostly +my $no_symlink = ""; # Should be empty, mostly +my $reverse_symlink = ""; # Should be empty, mostly +my $do_symlink = "Yes"; # target machine defined +my $do_boot_enable = "Yes"; # target machine defined +my $do_bootfloppy = "Yes"; # target machine defined +my $do_bootloader = "Yes"; # target machine defined +my $move_image = ''; # target machine defined +my $kimage = "=K"; # Should be empty, mostly +my $loader = "=L"; # lilo, silo, quik, palo, vmelilo, nettrom, arcboot or delo +my $image_dir = "/boot"; # where the image is located +my $clobber_modules = ''; # target machine defined +my $relative_links = ""; # target machine defined +my $initrd = "YES"; # initrd kernel +my $do_initrd = ''; # Normally we do not +my $use_hard_links = ''; # hardlinks do not work across fs boundaries +my $postinst_hook = ''; #Normally we do not +my $postrm_hook = ''; #Normally we do not +my $preinst_hook = ''; #Normally we do not +my $prerm_hook = ''; #Normally we do not +my $minimal_swap = ''; # Do not swap symlinks +my $ignore_depmod_err = ''; # normally we do not +my $kernel_arch = "=B"; +my $ramdisk = "/usr/sbin/update-initramfs"; # List of tools to create initial ram fs. +my $notifier = "/usr/share/update-notifier/notify-reboot-required"; +my $package_name = "linux-image-$version"; +my $explicit_do_loader = 'Yes'; + +my $Loader = "NoLOADER"; # +$Loader = "LILO" if $loader =~ /^lilo/io; +$Loader = "SILO" if $loader =~ /^silo/io; +$Loader = "QUIK" if $loader =~ /^quik/io; +$Loader = "yaboot" if $loader =~ /^yaboot/io; +$Loader = "PALO" if $loader =~ /^palo/io; +$Loader = "NETTROM" if $loader =~ /^nettrom/io; +$Loader = "VMELILO" if $loader =~ /^vmelilo/io; +$Loader = "ZIPL" if $loader =~ /^zipl/io; +$Loader = "ELILO" if $loader =~ /^elilo/io; +$Loader = "ARCBOOT" if $loader =~ /^arcboot/io; +$Loader = "DELO" if $loader =~ /^delo/io; + +# This should not point to /tmp, because of security risks. +my $temp_file_name = "/var/log/$loader" . "_log.$$"; + +#known variables +my $image_dest = "/"; +my $realimageloc = "/$image_dir/"; +my $have_conffile = ""; +my $silent_modules = ''; +my $silent_loader = ''; +my $warn_reboot = 'Yes'; # Warn that we are installing a version of + # the kernel we are running + +my $modules_base = '/lib/modules'; +my $CONF_LOC = '/etc/kernel-img.conf'; + +# Ignore all invocations except when called on to configure. +exit 0 unless $ARGV[0] =~ /configure/; + +my $DEBUG = 0; + +# Do some preliminary sanity checks here to ensure we actually have an +# valid image dir +chdir('/') or die "could not chdir to /:$!\n"; +die "Internal Error: ($image_dir) is not a directory!\n" + unless -d $image_dir; + +# remove multiple leading slashes; make sure there is at least one. +$realimageloc =~ s|^/*|/|o; +$realimageloc =~ s|/+|/|o; +die "Internal Error: ($realimageloc) is not a directory!\n" + unless -d $realimageloc; + +if (-r "$CONF_LOC" && -f "$CONF_LOC" ) { + if (open(CONF, "$CONF_LOC")) { + while () { + chomp; + s/\#.*$//g; + next if /^\s*$/; + + $do_symlink = "" if /^\s*do_symlinks\s*=\s*(no|false|0)\s*$/ig; + $no_symlink = "" if /^\s*no_symlinks\s*=\s*(no|false|0)\s*$/ig; + $reverse_symlink = "" if /^\s*reverse_symlink\s*=\s*(no|false|0)\s*$/ig; + $link_in_boot = "" if /^\s*image_in_boot\s*=\s*(no|false|0)\s*$/ig; + $link_in_boot = "" if /^\s*link_in_boot\s*=\s*(no|false|0)\s*$/ig; + $move_image = "" if /^\s*move_image\s*=\s*(no|false|0)\s*$/ig; + $clobber_modules = '' if /^\s*clobber_modules\s*=\s*(no|false|0)\s*$/ig; + $do_boot_enable = '' if /^\s*do_boot_enable\s*=\s*(no|false|0)\s*$/ig; + $do_bootfloppy = '' if /^\s*do_bootfloppy\s*=\s*(no|false|0)\s*$/ig; + $relative_links = '' if /^\s*relative_links \s*=\s*(no|false|0)\s*$/ig; + $do_bootloader = '' if /^\s*do_bootloader\s*=\s*(no|false|0)\s*$/ig; + $explicit_do_loader = '' if /^\s*do_bootloader\s*=\s*(no|false|0)\s*$/ig; + $do_initrd = '' if /^\s*do_initrd\s*=\s*(no|false|0)\s*$/ig; + $use_hard_links = '' if /^\s*use_hard_links\s*=\s*(no|false|0)\s*$/ig; + $silent_modules = '' if /^\s*silent_modules\s*=\s*(no|false|0)\s*$/ig; + $silent_loader = '' if /^\s*silent_loader\s*=\s*(no|false|0)\s*$/ig; + $warn_reboot = '' if /^\s*warn_reboot\s*=\s*(no|false|0)\s*$/ig; + $minimal_swap = '' if /^\s*minimal_swap\s*=\s*(no|false|0)\s*$/ig; + $ignore_depmod_err = '' if /^\s*ignore_depmod_err\s*=\s*(no|false|0)\s*$/ig; + + $do_symlink = "Yes" if /^\s*do_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $no_symlink = "Yes" if /^\s*no_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $reverse_symlink = "Yes" if /^\s*reverse_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $link_in_boot = "Yes" if /^\s*image_in_boot\s*=\s*(yes|true|1)\s*$/ig; + $link_in_boot = "Yes" if /^\s*link_in_boot\s*=\s*(yes|true|1)\s*$/ig; + $move_image = "Yes" if /^\s*move_image\s*=\s*(yes|true|1)\s*$/ig; + $clobber_modules = "Yes" if /^\s*clobber_modules\s*=\s*(yes|true|1)\s*$/ig; + $do_boot_enable = "Yes" if /^\s*do_boot_enable\s*=\s*(yes|true|1)\s*$/ig; + $do_bootfloppy = "Yes" if /^\s*do_bootfloppy\s*=\s*(yes|true|1)\s*$/ig; + $do_bootloader = "Yes" if /^\s*do_bootloader\s*=\s*(yes|true|1)\s*$/ig; + $explicit_do_loader = "YES" if /^\s*do_bootloader\s*=\s*(yes|true|1)\s*$/ig; + $relative_links = "Yes" if /^\s*relative_links\s*=\s*(yes|true|1)\s*$/ig; + $do_initrd = "Yes" if /^\s*do_initrd\s*=\s*(yes|true|1)\s*$/ig; + $use_hard_links = "Yes" if /^\s*use_hard_links\s*=\s*(yes|true|1)\s*$/ig; + $silent_modules = 'Yes' if /^\s*silent_modules\s*=\s*(yes|true|1)\s*$/ig; + $silent_loader = 'Yes' if /^\s*silent_loader\s*=\s*(yes|true|1)\s*$/ig; + $warn_reboot = 'Yes' if /^\s*warn_reboot\s*=\s*(yes|true|1)\s*$/ig; + $minimal_swap = 'Yes' if /^\s*minimal_swap\s*=\s*(yes|true|1)\s*$/ig; + $ignore_depmod_err = 'Yes' if /^\s*ignore_depmod_err\s*=\s*(yes|true|1)\s*$/ig; + + $image_dest = "$1" if /^\s*image_dest\s*=\s*(\S+)/ig; + $postinst_hook = "$1" if /^\s*postinst_hook\s*=\s*(\S+)/ig; + $postrm_hook = "$1" if /^\s*postrm_hook\s*=\s*(\S+)/ig; + $preinst_hook = "$1" if /^\s*preinst_hook\s*=\s*(\S+)/ig; + $prerm_hook = "$1" if /^\s*prerm_hook\s*=\s*(\S+)/ig; + $ramdisk = "$1" if /^\s*ramdisk\s*=\s*(.+)$/ig; + } + close CONF; + $have_conffile = "Yes"; + } +} + + + +# For some versions of kernel-package, we had this warning in the +# postinst, but the rules did not really interpolate the value in. +# Here is a sanity check. +my $pattern = "=" . "I"; +$initrd=~ s/^$pattern$//; + +if ($link_in_boot) { + $image_dest = "/$image_dir/"; # same as realimageloc +} + +# Tack on at least one trainling / +$image_dest = "$image_dest/"; +$image_dest =~ s|^/*|/|o; +$image_dest =~ s|/+$|/|o; + +if (! -d "$image_dest") { + die "Expected Image Destination dir ($image_dest) to be a valid directory!\n"; +} + +# sanity +if (!($do_bootfloppy || $do_bootloader)) { + $do_boot_enable = ''; +} +if ($do_symlink && $no_symlink) { + warn "Both do_symlinks and no_symlinks options enabled; disabling no_symlinks\n"; + $no_symlink = 0; +} + +# most of our work is done in $image_dest (nominally /) +chdir("$image_dest") or die "could not chdir to $image_dest:$!\n"; + +# Paranoid check to make sure that the correct value is put in there +if (! $kimage) { $kimage = "vmlinuz"; } # Hmm. empty +elsif ($kimage =~ m/^b?zImage$/o) { $kimage = "vmlinuz"; } # these produce vmlinuz +elsif ($kimage =~ m/^[iI]mage$/o) { my $nop = $kimage; } +elsif ($kimage =~ m/^vmlinux$/o) { my $nop = $kimage; } +else { $kimage = "vmlinuz"; } # Default + +$ENV{KERNEL_ARCH}=$kernel_arch if $kernel_arch; + + +die "Internal Error: Could not find image (" . $realimageloc + . "$kimage-$version)\n" unless -e $realimageloc + . "$kimage-$version"; + +# search for the boot loader in the path +my $loader_exec; +($loader_exec = $loader) =~ s|.*/||; +my ($loaderloc) = grep -x, map "$_/$loader_exec", + map { length($_) ? $_ : "." } split /:/, $ENV{PATH}; + + +###################################################################### +###################################################################### +########### Test whether a relative symlinkwould be OK ####### +###################################################################### +###################################################################### +sub test_relative { + my %params = @_; + my $cwd; + + die "Internal Error: Missing Required paramater 'Old Dir' " + unless $params{'Old Dir'}; + die "Internal Error: Missing Required paramater New Dir' " + unless $params{'New Dir'}; + + + die "Internal Error: No such dir $params{'Old Dir'} " + unless -d $params{'Old Dir'}; + die "Internal Error: No such dir $params{'New Dir'} " + unless -d $params{'New Dir'}; + + warn "Test relative: testing $params{'Old Dir'} -> $params{'New Dir'}" + if $DEBUG; + chomp($cwd = `pwd`); + chdir ($params{'New Dir'}) or die "Could not chdir to $params{'New Dir'}:$!"; + my $ok = 0; + $params{'Old Dir'} =~ s|^/*||o; + if (-d $params{'Old Dir'} ) { + if (defined $params{'Test File'}) { + if (-e $params{'Old Dir'} . $params{'Test File'}) { + $ok = 1; + } + } else { + $ok = 1; # well, backward compatibility + } + } + chdir ($cwd) or die "Could not chdir to $params{'New Dir'}:$!"; + return $ok; +} + +###################################################################### +###################################################################### +############ +###################################################################### +###################################################################### +# sub CanonicalizePath { +# my $path = join '/', @_; +# my @work = split '/', $path; +# my @out; +# my $is_absolute; + +# if (@work && $work[0] eq "") { +# $is_absolute = 1; shift @work; +# } + +# while (@work) { +# my $seg = shift @work; +# if ($seg eq "." || $seg eq "") { +# } +# elsif ($seg eq "..") { +# if (@out && $out[-1] ne "..") { +# pop @out; +# } +# else { +# # Leading "..", or "../..", etc. +# push @out, $seg; +# } +# } +# else { +# push @out, $seg; +# } +# } + +# unshift @out, "" if $is_absolute; +# return join('/', @out); +# } +###################################################################### +###################################################################### +############ +###################################################################### +###################################################################### + +sub spath { + my %params = @_; + + die "Missing Required paramater 'Old'" unless $params{'Old'}; + die "Missing Required paramater 'New'" unless $params{'New'}; + + my @olddir = split '/', `readlink -q -m $params{'Old'}`; + my @newdir = split '/', `readlink -q -m $params{'New'}`; + my @outdir = @olddir; + + my $out = ''; + my $i; + for ($i = 0; $i <= $#olddir && $i <= $#newdir; $i++) { + $out++ if ($olddir[$i] ne $newdir[$i]); + shift @outdir unless $out; + unshift @outdir, ".." if $out; + } + if ($#newdir > $#olddir) { + for ($i=0; $i < $#newdir; $i++) { + unshift @outdir, ".."; + } + } + return join ('/', @outdir); +} +###################################################################### +###################################################################### +############ +###################################################################### +###################################################################### + + +# This routine actually moves the kernel image +# From: $realimageloc/$kimage-$version (/boot/vmlinuz-2.6.12) +# To: $image_dest/$kimage-$version (/vmlinuz-2.6.12) +# Note that the image is moved to a versioned destination, but ordinary +# symlinks we create otherwise are not normally versioned +sub really_move_image { + my $src_dir = $_[0]; + my $target = $_[1]; + my $dest_dir = $_[2]; + + warn "Really move image: src_dir=$src_dir, target=$target,\n destdir=$dest_dir" + if $DEBUG; + if (-e "$target") { + # we should be in dir $dest_dir == $image_dest /, normally + rename("$target", "$target.$$") || + die "failed to move " . $dest_dir . "$target:$!"; + warn "mv $target $target.$$" if $DEBUG; + } + warn "mv -f $src_dir$target $target" if $DEBUG; + my $ret = system("mv -f " . $src_dir . "$target " . + " $target"); + if ($ret) { + die("Failed to move " . $src_dir . "$target to " + . $dest_dir . "$target.\n"); + } + # Ok, now we may clobber the previous .old files + if (-e "$target.$$") { + rename("$target.$$", "$target.old") || + die "failed to move " . $dest_dir . "$target:$!"; + warn "mv $target.$$ $target " if $DEBUG; + } +} + +# Normally called after really_move_image; and only called if we asked for +# reversed link this routine reverses the symbolic link that is notmally +# created. Since the real kernel image has been moved over to +# $image_dest/$kimage-$version. So, this routine links +# From: $image_dest/$kimage-$version (/vmlinuz-2.6.12) +# To: $realimageloc/$kimage-$version (/boot/vmlinuz-2.6.12) +sub really_reverse_link { + my $src_dir = $_[0]; + my $link_name = $_[1]; + my $dest_dir = $_[2]; + warn "Really reverse link: src_dir=$src_dir, link name=$link_name\n" . + "\tdestdir=$dest_dir" if $DEBUG; + + my $Old = $dest_dir; + if (test_relative ('Old Dir' => $Old, 'New Dir' => $src_dir, + 'Test File' => "$link_name")) { + $Old =~ s|^/*||o; + } + # Special case is they are in the same dir + my $rel_path = spath('Old' => "$Old", 'New' => "$src_dir" ); + $Old ="" if $rel_path =~ m/^\s*$/o; + + if ($use_hard_links =~ m/YES/i) { + link($Old . "$link_name", $src_dir . "$link_name") || + die("Failed to symbolic-link " . $dest_dir . "$link_name to " . $src_dir + . "$link_name .\n"); + warn "ln " . $Old . "$link_name " . $src_dir . "$link_name" if $DEBUG; + } + else { + symlink($Old . "$link_name", $src_dir . "$link_name") || + die("Failed to link " . $dest_dir . "$link_name to " . $src_dir . + "$link_name .\n"); + warn "ln -s " . $Old . "$link_name " . $src_dir . "$link_name" if $DEBUG; + } +} + +# This routine is invoked if there is a symbolic link in place +# in $image_dest/$kimage -- so a symlink exists in the destination. +# What we are trying to determine is if we need to move the symbolic link over +# to the the .old location +sub move_p { + my $kimage = $_[0]; # Name of the symbolic link + my $image_dest = $_[1]; # The directory the links goes into + my $image_name = $_[2]; + my $src_dir = $_[3]; + my $force_move = 0; + warn "Move?: kimage=$kimage, image_dest=$image_dest, \n" . + "\timage_name=$image_name, src_dir=$src_dir" if $DEBUG; + + if ($no_symlink || $reverse_symlink) { + # we do not want links, yet we have a symbolic link here! + warn "found a symbolic link in " . $image_dest . "$kimage \n" . + "even though no_symlink is defined\n" if $no_symlink; + warn "found a symbolic link in " . $image_dest . "$kimage \n" . + "even though reverse_symlink is defined\n" if $reverse_symlink; + # make sure we change this state of affairs + $force_move = 1; + return $force_move; + } + + warn "DEBUG: OK. We found symlink, and we should have a symlink here.\n" + if $DEBUG; + my $vmlinuz_target = readlink "$kimage"; + my $real_target = ''; + my $target = `readlink -q -m "${realimageloc}${kimage-$version}"`; + $real_target = abs_path($vmlinuz_target) if defined($vmlinuz_target); + + if (!defined($vmlinuz_target) || ! -f "$real_target") { + # what, a dangling symlink? + warn "The link " . $image_dest . "$kimage is a dangling link" . + "to $real_target\n"; + $force_move = 1; + return $force_move; + } + + + warn "DEBUG: The link $kimage points to ($vmlinuz_target)\n" if $DEBUG; + warn "DEBUG: ($vmlinuz_target) is really ($real_target)\n" if $DEBUG; + my $cwd; + chomp ($cwd=`pwd`); + if ($vmlinuz_target !~ m|^/|o) { + $vmlinuz_target = $cwd . "/" . $vmlinuz_target; + $vmlinuz_target =~ s|/+|/|o; + } + $vmlinuz_target = `readlink -q -m $vmlinuz_target`; + + if ("$vmlinuz_target" ne "$target") { + warn "DEBUG: We need to handle this.\n" if $DEBUG; + if ($minimal_swap) { + warn "DEBUG: Minimal swap.\n" if $DEBUG; + if (-l "$kimage.old") { + warn "DEBUG: There is an old link at $kimage.old\n" if $DEBUG; + my $old_target = readlink "$kimage.old"; + my $real_old_target = ''; + $real_old_target=abs_path($old_target) if defined ($old_target); + + if ($real_old_target && -f "$real_old_target") { + if ($old_target !~ m|^/|o) { + $old_target = $cwd . "/" . $old_target; + $old_target =~ s|/+|/|o; + } + $old_target = `readlink -q -m $old_target`; + if ("$old_target" ne "$target") { + $force_move = 1; + warn "DEBUG: Old link ($old_target) does not point to us ($target)\n" + if $DEBUG; + } + else { # The .old points to the current + warn "$kimage.old --> $target -- doing nothing"; + $force_move = 0; + } + } + else { + warn "DEBUG: Well, the old link does not exist -- so we move\n" + if $DEBUG; + $force_move = 1; + } + } + else { + warn "DEBUG: No .old link -- OK to move\n" + if $DEBUG; + $force_move = 1; + } + } + else { + warn "DEBUG: ok, minimal swap is no-- so we move.\n" + if $DEBUG; + $force_move = 1; + } + } + else { # already have proper link + warn "$kimage($vmlinuz_target) points to $target ($real_target) -- doing nothing"; + $force_move = 0; + } + return $force_move; +} + + +# This routine moves the symbolic link around (/vmlinuz -> /vmlinuz.old) +# It pays attention to whether we should the fact whether we should be using +# hard links or not. +sub really_move_link { + my $kimage = $_[0]; # Name of the symbolic link + my $image_dest = $_[1]; # The directory the links goes into + my $image_name = $_[2]; + my $src_dir = $_[3]; + warn "really_move_link: kimage=$kimage, image_dest=$image_dest\n" . + "\t image_name=$image_name, src_dir=$src_dir" if $DEBUG; + + # don't clobber $kimage.old quite yet + rename("$kimage", "$kimage.$$") || + die "failed to move " . $image_dest . "$kimage:$!"; + warn "mv $kimage $kimage.$$" if $DEBUG; + my $Old = $src_dir; + my $cwd; + + chomp($cwd=`pwd`); + if (test_relative ('Old Dir' => $Old, 'New Dir' => $cwd, + 'Test File' => "$image_name")) { + $Old =~ s|^/*||o; + } + # Special case is they are in the same dir + my $rel_path = spath('Old' => "$Old", 'New' => "$cwd" ); + $Old ="" if $rel_path =~ m/^\s*$/o; + + if ($use_hard_links =~ m/YES/i) { + warn "ln ${Old}${image_name} $kimage" if $DEBUG; + if (! link("${Old}${image_name}", "$kimage")) { + rename("$kimage.$$", "$kimage"); + die("Failed to link ${Old}${image_name} to " . + "${image_dest}${kimage}.\n"); + } + } + else { + warn "ln -s ${Old}${image_name} $kimage" if $DEBUG; + if (! symlink("${Old}${image_name}", "$kimage")) { + rename("$kimage.$$", "$kimage"); + die("Failed to symbolic-link ${Old}${image_name} to " . + "${image_dest}${kimage}.\n"); + } + } + + # Ok, now we may clobber the previous .old file + if (-l "$kimage.old" || ! -e "$kimage.old" ) { + rename("$kimage.$$", "$kimage.old"); + warn "mv $kimage.$$ $kimage.old" if $DEBUG; + } + else { + warn "$kimage.old is not a symlink, not clobbering\n"; + warn "rm $kimage.$$"; + unlink "$kimage.$$" if $DEBUG; + } +} + +# This routine handles a request to do symlinks, but there is no +# symlink file already there. Either we are supposed to use copy, or we are +# installing on a pristine system, or the user does not want symbolic links at +# all. We use a configuration file to tell the last two cases apart, creating +# a config file if needed. +sub handle_missing_link { + my $kimage = $_[0]; # Name of the symbolic link + my $image_dest = $_[1]; # The directory the links goes into + my $image_name = $_[2]; + my $src_dir = $_[3]; + warn "handle_missing_link: kimage=$kimage, image_dest=$image_dest\n" . + "\t image_name=$image_name, src_dir=$src_dir" if $DEBUG; + + if ($no_symlink) { + warn "cp -a --backup=t $realimageloc$image_name $kimage" if $DEBUG; + my $ret = system("cp -a --backup=t " . $realimageloc . + "$image_name " . " $kimage"); + if ($ret) { + die("Failed to copy " . $realimageloc . "$image_name to " + . $image_dest . "$kimage .\n"); + } + } + elsif ($reverse_symlink) { + warn "mv -f $realimageloc$image_name $kimage" if $DEBUG; + my $ret = system("mv -f " . $realimageloc . "$image_name " + . "$kimage"); + if ($ret) { + die("Failed to move " . $realimageloc . "$image_name to " + . $image_dest . "$kimage .\n"); + } + } + else { + if (! $have_conffile) { + my $ret; + my $answer=''; + $do_symlink = "Yes"; + + if (open(CONF, ">$CONF_LOC")) { + print CONF "# Kernel Image management overrides\n"; + print CONF "# See kernel-img.conf(5) for details\n"; + if ($loader =~ /palo/i) { + print CONF "link_in_boot = Yes\n"; + print CONF "do_symlinks = Yes\n"; + print CONF "relative_links = Yes\n"; + print CONF "do_bootloader = No\n"; + } else { + print CONF "do_symlinks = $do_symlink\n"; + } + close CONF; + } + $have_conffile = "Yes"; + } + } + + if (! $no_symlink && $do_symlink =~ /Yes/i) { + my $Old = $realimageloc; + my $New = $image_dest; + my $Name = "$image_name"; + my $Link_Dest = "$kimage"; + + if ($reverse_symlink) { + $Old = $image_dest; + $New = $realimageloc; + $Name = "$kimage"; + $Link_Dest = $realimageloc . "$image_name"; + } + if (test_relative ('Old Dir' => $Old, + 'New Dir' => $New, + 'Test File' => $Name)) { + $Old =~ s|^/*||o; + } + # Special case is they are in the same dir + my $rel_path = spath('Old' => "$Old", 'New' => "$New" ); + $Old ="" if $rel_path =~ m/^\s*$/o; + + symlink($Old . "$Name", "$Link_Dest") || + die("Failed to symbolic-link ${Old}$Name to $Link_Dest.\n"); + warn "ln -s ${Old}$Name $Link_Dest" if $DEBUG; + + } +} + +# This routine handles the rest of the cases, where the user has requested +# non-traditional handling, like using cp, or reverse symlinks, or hard links. +sub handle_non_symlinks { + my $kimage = $_[0]; # Name of the symbolic link + my $image_dest = $_[1]; # The directory the links goes into + my $image_name = $_[2]; + my $src_dir = $_[3]; + warn "handle_non_link: kimage=$kimage, image_dest=$image_dest\n" . + "\t image_name=$image_name, src_dir=$src_dir" if $DEBUG; + + # Save the current image. We do this in all four cases + rename("$kimage", "$kimage.$$") || + die "failed to move " . $image_dest . "$kimage:$!"; + warn "mv $kimage $kimage.$$" if $DEBUG; + + ##,#### + # case One + #`#### + if ($no_symlink) { + # Maybe /$image_dest is on a dos system? + warn "cp -a --backup=t $realimageloc$image_name $kimage" if $DEBUG; + my $ret = system("cp -a --backup=t " . $realimageloc + . "$image_name " . "$kimage"); + if ($ret) { + if (-e "$kimage.$$") { + rename("$kimage.$$", "$kimage"); + warn "mv $kimage.$$ $kimage" if $DEBUG; + } + die("Failed to copy " . $realimageloc . "$image_name to " + . $image_dest . "$kimage .\n"); + } + } + ##,#### + # case Two + #`#### + elsif ($reverse_symlink) { # Maybe /$image_dest is on a dos system? + warn "mv -f $realimageloc$image_name $kimage" if $DEBUG; + my $ret = system("mv -f " . $realimageloc . "$image_name " + . $image_dest . "$kimage"); + if ($ret) { + if (-e "$kimage.$$") { + rename("$kimage.$$", "$kimage"); + warn "mv $kimage.$$ $kimage" if $DEBUG; + } + die("Failed to move " . $realimageloc . "$image_name to " + . $image_dest . "$kimage .\n"); + } + my $Old = $image_dest; + if (test_relative ('Old Dir' => $Old, 'New Dir' => $realimageloc, + 'Test File' => "$kimage")) { + $Old =~ s|^/*||o; + } + # Special case is they are in the same dir + my $rel_path = spath('Old' => "$Old", 'New' => "$realimageloc" ); + $Old ="" if $rel_path =~ m/^\s*$/o; + + if ($use_hard_links =~ m/YES/i) { + warn "ln " . $Old . "$kimage " . $realimageloc . "$image_name" if $DEBUG; + if (! link($Old . "$kimage", $realimageloc . "$image_name")) { + warn "Could not link " . $image_dest . + "$kimage to $image_name :$!"; + } + } + else { + warn "ln -s " . $Old . "$kimage " . $realimageloc . "$image_name" if $DEBUG; + if (! symlink($Old . "$kimage", $realimageloc . "$image_name")) { + warn "Could not symlink " . $image_dest . + "$kimage to $image_name :$!"; + } + } + } + ##,#### + # case Three + #`#### + elsif ($use_hard_links =~ m/YES/i ) { + # Ok then. this ought to be a hard link, and hence fair game + # don't clobber $kimage.old quite yet + my $Old = $realimageloc; + my $cwd; + chomp($cwd=`pwd`); + if (test_relative ('Old Dir' => $Old, 'New Dir' => $cwd, + 'Test File' => "$image_name")) { + $Old =~ s|^/*||o; + } + # Special case is they are in the same dir + my $rel_path = spath('Old' => "$Old", 'New' => "$cwd" ); + $Old ="" if $rel_path =~ m/^\s*$/o; + + warn "ln " . $Old . "$image_name " . "$kimage" if $DEBUG; + if (! link($Old . "$image_name", "$kimage")) { + warn "mv $kimage.$$ $kimage" if $DEBUG; + rename("$kimage.$$", "$kimage"); + die("Failed to link " . $realimageloc . "$image_name to " + . $image_dest . "$kimage .\n"); + } + } + ##,#### + # case Four + #`#### + else { + # We just use cp + warn "cp -a --backup=t $realimageloc$image_name $kimage" if $DEBUG; + my $ret = system("cp -a --backup=t " . $realimageloc + . "$image_name " . "$kimage"); + if ($ret) { + if (-e "$kimage.$$") { + warn "mv $kimage.$$ $kimage" if $DEBUG; + rename("$kimage.$$", "$kimage"); + } + die("Failed to copy " . $realimageloc . "$image_name to " + . $image_dest . "$kimage .\n"); + } + } + # Ok, now we may clobber the previous .old file + warn "mv $kimage.$$ $kimage.old if -e $kimage.$$" if $DEBUG; + rename("$kimage.$$", "$kimage.old") if -e "$kimage.$$"; +} + +# This routine is responsible for setting up the symbolic links +# So, the actual kernel image lives in +# $realimageloc/$image_name (/boot/vmlinuz-2.6.12). +# This routine creates symbolic links in $image_dest/$kimage (/vmlinuz) +sub image_magic { + my $kimage = $_[0]; # Name of the symbolic link + my $image_dest = $_[1]; # The directory the links goes into + my $image_name = "$kimage-$version"; + my $src_dir = $realimageloc; + warn "image_magic: kimage=$kimage, image_dest=$image_dest\n" . + "\t image_name=$image_name, src_dir=$src_dir" if $DEBUG; + + # Well, in any case, if the destination (the symlink we are trying + # to create) is a directory, we should do nothing, except throw a + # diagnostic. + if (-d "$kimage" ) { + die ("Hmm. $kimage is a directory, which I did not expect. I am\n" . + "trying to create a symbolic link with that name linked to \n" . + "$image_dest . Since a directory exists here, my assumptions \n" . + "are way off, and I am aborting.\n" ); + exit (3); + } + + if ($move_image) { # Maybe $image_dest is in on dos, or something? + # source dir, link name, dest dir + really_move_image( $realimageloc, $image_name, $image_dest); + really_reverse_link($realimageloc, $image_name, $image_dest) + if $reverse_symlink; + return; + } + + if (-l "$kimage") { # There is a symbolic link + warn "DEBUG: There is a symlink for $kimage\n" if $DEBUG; + my $force_move = move_p($kimage, $image_dest, $image_name, $src_dir); + + if ($force_move) { + really_move_link($kimage, $image_dest, $image_name, $src_dir); + } + } + elsif (! -e "$kimage") { + # Hmm. Pristine system? How can that be? Installing from scratch? + # Or maybe the user does not want a symbolic link here. + # Possibly they do not want a link here. (we should be in / + # here[$image_dest, really] + handle_missing_link($kimage, $image_dest, $image_name, $src_dir); + } + elsif (-e "$kimage" ) { + # OK, $kimage exists -- but is not a link + handle_non_symlinks($kimage, $image_dest, $image_name, $src_dir); + } +} + +###################################################################### +###################################################################### +###################################################################### +###################################################################### + +# We may not have any modules installed +if ( -d "$modules_base/$version" ) { + print STDERR "Running depmod.\n"; + my $ret = system("depmod -a $version"); + if ($ret) { + print STDERR "Failed to run depmod\n"; + exit(1); + } +} + + + +sub find_initrd_tool { + my $hostversion = shift; + my $version = shift; + print STDERR "Finding valid ramdisk creators.\n"; + my @ramdisks = + grep { + my $args = + "$_ " . + "--supported-host-version=$hostversion " . + "--supported-target-version=$version " . + "1>/dev/null 2>&1" + ; + system($args) == 0; + } + split (/[:,\s]+/, $ramdisk); +} + +# The initrd symlink should probably be in the same dir that the +# symlinks are in +if ($initrd) { + my $success = 0; + + # Update-initramfs is called slightly different than mkinitrd and + # mkinitramfs. XXX It should really be made compatible with this stuff + # some how. + my $upgrading = 1; + if (! defined $ARGV[1] || ! $ARGV[1] || $ARGV[1] =~ m//og) { + $upgrading = 0; + } + my $ret = system("$ramdisk " . ($upgrading ? "-u" : "-c") . " -k " . $version . " >&2"); + $success = 1 unless $ret; + die "Failed to create initrd image.\n" unless $success; + if (! defined $ARGV[1] || ! $ARGV[1] || $ARGV[1] =~ m//og) { + image_magic("initrd.img", $image_dest); + } + else { + if (! -e "initrd.img") { + handle_missing_link("initrd.img", $image_dest, "initrd.img-$version", + $realimageloc); + } + else { + print STDERR + "Not updating initrd symbolic links since we are being updated/reinstalled \n"; + print STDERR + "($ARGV[1] was configured last, according to dpkg)\n"; + } + } + + if ($initrd && -l "initrd" ) { + unlink "initrd"; + } + + if ($initrd && -l "$image_dir/initrd" && ! $link_in_boot) { + unlink "$image_dir/initrd"; + } +} +else { # Not making an initrd emage + if (-l "initrd.img") { + # Ooh, last image was an initrd image? in any case, we should move it. + my $target = readlink "initrd.img"; + my $real_target = ''; + $real_target = abs_path($target) if defined ($target); + + if (!defined($target) || ! -f "$real_target") { + # Eh. dangling link. can safely be removed. + unlink("initrd.img"); + } else { + if (-l "initrd.img.old" || ! -e "initrd.img.old" ) { + rename("initrd.img", "initrd.img.old"); + } else { + warn "initrd.img.old is not a symlink, not clobbering\n"; + unlink("initrd.img"); + } + } + } +} + +# Warn of a reboot +if (-x $notifier) { + system($notifier); +} + +# Let programs know not to hibernate if the kernel that would be used for +# resume-from-hibernate is likely to differ from the currently running kernel. +system("mountpoint -q /var/run"); +if ($? eq 0) { + system("touch /var/run/do-not-hibernate"); +} + +# Only change the symlinks if we are not being upgraded +if (! defined $ARGV[1] || ! $ARGV[1] || $ARGV[1] =~ m//og) { + image_magic($kimage, $image_dest); +} +else { + if (! -e "$kimage") { + handle_missing_link($kimage, $image_dest, "$kimage-$version", + $realimageloc); + } + else { + print STDERR + "Not updating image symbolic links since we are being updated/reinstalled \n"; + print STDERR + "($ARGV[1] was configured last, according to dpkg)\n"; + } +} + +# We used to have System.* files in / +if (-e "/System.map" || -e "/System.old") { + unlink '/System.map' if -e '/System.map'; + unlink '/System.old' if -e '/System.old'; +} + +# creating some info about kernel and initrd +if ($DEBUG) { + my $ksize=sprintf("%.0f",(stat($realimageloc . + "$kimage-$version"))[7]/1024)."kB"; + my $initrdsize=''; + if ($initrd) { + $initrdsize=sprintf("%.0f",(stat($realimageloc . + "initrd.img-$version"))[7]/1024)."kB"; + } + + print STDERR <<"EOMSG"; +A new kernel image has been installed at $realimageloc$kimage-$version + (Size: $ksize) + +Symbolic links, unless otherwise specified, can be found in $image_dest + +EOMSG + ; + + if ($initrd) { + print STDERR <<"EOMSGA"; + + Initial rootdisk image: ${realimageloc}initrd.img-$version (Size: $initrdsize) +EOMSGA + ; + } +} + +# set the env var stem +$ENV{'STEM'} = "linux"; +sub exec_script { + my $type = shift; + my $script = shift; + print STDERR "Running $type hook script $script.\n"; + system ("$script $version $realimageloc$kimage-$version") && + print STDERR "User $type hook script [$script] "; + if ($?) { + if ($? == -1) { + print STDERR "failed to execute: $!\n"; + } + elsif ($? & 127) { + printf STDERR "died with signal %d, %s coredump\n", + ($? & 127), ($? & 128) ? 'with' : 'without'; + } + else { + printf STDERR "exited with value %d\n", $? >> 8; + } + exit $? >> 8; + } +} +sub run_hook { + my $type = shift; + my $script = shift; + if ($script =~ m,^/,) { + # Full path provided for the hook script + if (-x "$script") { + &exec_script($type,$script); + } + else { + die "The provided $type hook script [$script] could not be run.\n"; + } + } + else { + # Look for it in a safe path + for my $path ('/bin', '/sbin', '/usr/bin', '/usr/sbin') { + if (-x "$path/$script") { + &exec_script($type, "$path/$script"); + return 0; + } + } + # No luck + print STDERR "Could not find $type hook script [$script].\n"; + die "Looked in: '/bin', '/sbin', '/usr/bin', '/usr/sbin'\n"; + } +} + +## Run user hook script here, if any +if ($postinst_hook) { + &run_hook("postinst", $postinst_hook); +} + +if (-d "/etc/kernel/postinst.d") { + print STDERR "Examining /etc/kernel/postinst.d.\n"; + system ("run-parts --verbose --exit-on-error --arg=$version " . + "--arg=$realimageloc$kimage-$version " . + "/etc/kernel/postinst.d") && + die "Failed to process /etc/kernel/postinst.d"; +} + +if (-d "/etc/kernel/postinst.d/$version") { + print STDERR "Examining /etc/kernel/postinst.d/$version.\n"; + system ("run-parts --verbose --exit-on-error --arg=$version " . + "--arg=$realimageloc$kimage-$version " . + "/etc/kernel/postinst.d/$version") && + die "Failed to process /etc/kernel/postinst.d/$version"; +} + +LOADER: { + last unless $do_boot_enable; # Exit if explicitly asked to + + last if $loader =~ /silo/i; # SILO does not have to be executed. + last if $loader =~ /yaboot/i; # yaboot does not have to be executed. + last if $loader =~ /milo/i; # MILO does not have to be executed. + last if $loader =~ /nettrom/i; # NETTROM does not have to be executed. + last if $loader =~ /arcboot/i; # ARCBOOT does not have to be executed. + last if $loader =~ /delo/i; # DELO does not have to be executed. + last if $loader =~ /quik/i; # maintainer asked quik invocation to be ignored + + last unless $loaderloc; + last unless -x $loaderloc; + last unless $do_bootloader; + + if (-T "/etc/$loader.conf") { + # Trust and use the existing lilo.conf. + print STDERR "You already have a $Loader configuration in /etc/$loader.conf\n"; + my $ret = &run_lilo(); + exit $ret if $ret; + } +} + + +sub run_lilo (){ + my $ret; + # Try and figure out if the user really wants lilo to be run -- + # since the default is to run the boot laoder, which is ! grub -- but + # the user may be using grub now, and not changed the default. + + # So, if the user has explicitly asked for the loader to be run, or + # if there is no postinst hook, or if there is no grub installed -- + # we are OK. Or else, we ask. + if ($explicit_do_loader || (! ($postinst_hook && -x '/usr/sbin/grub'))) { + print STDERR "Running boot loader as requested\n"; + } else { + print STDERR "Ok, not running $loader\n"; + } + if ($loader =~ /^lilo/io or $loader =~ /vmelilo/io) { + print STDERR "Testing $loader.conf ... \n"; + unlink $temp_file_name; # security + $ret = system("$loaderloc -t >$temp_file_name 2>&1"); + if ($ret) { + print STDERR "Boot loader test failed\n"; + return $ret; + } + unlink "$temp_file_name"; + print STDERR "Testing successful.\n"; + print STDERR "Installing the "; + print STDERR "partition " if $loader =~ /^lilo/io; + print STDERR "boot sector... \n"; + } + + print STDERR "Running $loaderloc ... \n"; + if ($loader =~ /^elilo/io) { + $ret = system("$loaderloc 2>&1 | tee $temp_file_name"); + } else { + $ret = system("$loaderloc >$temp_file_name 2>&1"); + } + if ($ret) { + print STDERR "Boot loader failed to run\n"; + return $ret; + } + unlink $temp_file_name; + print STDERR "Installation successful.\n"; + return 0; +} + +exit 0; + +__END__ + --- linux-2.6.27.orig/debian/control-scripts/preinst +++ linux-2.6.27/debian/control-scripts/preinst @@ -0,0 +1,299 @@ +#! /usr/bin/perl +# -*- Mode: Cperl -*- +# image.preinst --- +# Author : Manoj Srivastava ( srivasta@tiamat.datasync.com ) +# Created On : Sun Jun 14 03:38:02 1998 +# Created On Node : tiamat.datasync.com +# Last Modified By : Manoj Srivastava +# Last Modified On : Sun Sep 24 14:04:42 2006 +# Last Machine Used: glaurung.internal.golden-gryphon.com +# Update Count : 99 +# Status : Unknown, Use with caution! +# HISTORY : +# Description : +# +# + +# +#use strict; #for debugging + +use Debconf::Client::ConfModule qw(:all); +version('2.0'); +my $capb=capb("backup"); + +$|=1; + +# Predefined values: +my $version = "=V"; +my $link_in_boot = ""; # Should be empty, mostly +my $no_symlink = ""; # Should be empty, mostly +my $reverse_symlink = ""; # Should be empty, mostly +my $do_symlink = "Yes"; # target machine defined +my $do_boot_enable = "Yes"; # target machine defined +my $do_bootfloppy = "Yes"; # target machine defined +my $do_bootloader = "Yes"; # target machine defined +my $move_image = ''; # target machine defined +my $kimage = "=K"; # Should be empty, mostly +my $loader = "=L"; # lilo, silo, quik, palo, vmelilo, nettrom + # or elilo +my $image_dir = "/boot"; # where the image is located +my $initrd = "YES"; # initrd kernel +my $use_hard_links = ''; # hardlinks do not wirk across fs boundaries +my $postinst_hook = ''; #Normally we do not +my $postrm_hook = ''; #Normally we do not +my $preinst_hook = ''; #Normally we do not +my $prerm_hook = ''; #Normally we do not +my $minimal_swap = ''; # Do not swap symlinks +my $ignore_depmod_err = ''; # normally we do not +my $relink_src_link = 'YES'; # There is no harm in checking the link +my $relink_build_link = 'YES'; # There is no harm in checking the link +my $force_build_link = ''; # There is no harm in checking the link +my $kernel_arch = "=B"; +my $ramdisk = "/usr/sbin/update-initramfs"; # List of tools to create initial ram fs. +my $package_name = "linux-image-$version"; + +my $Loader = "NoLOADER"; # +$Loader = "LILO" if $loader =~ /^lilo/io; +$Loader = "SILO" if $loader =~ /^silo/io; +$Loader = "QUIK" if $loader =~ /^quik/io; +$Loader = "yaboot" if $loader =~ /^yaboot/io; +$Loader = "PALO" if $loader =~ /^palo/io; +$Loader = "NETTROM" if $loader =~ /^nettrom/io; +$Loader = "VMELILO" if $loader =~ /^vmelilo/io; +$Loader = "ZIPL" if $loader =~ /^zipl/io; +$Loader = "ELILO" if $loader =~ /^elilo/io; + + +#known variables +my @boilerplate = (); +my @silotemplate = (); +my @quiktemplate = (); +my @palotemplate = (); +my @vmelilotemplate = (); +my $bootdevice = ''; +my $rootdevice = ''; +my $rootdisk = ''; +my $rootpartition = ''; +my $image_dest = "/"; +my $realimageloc = "/$image_dir/"; +my $have_conffile = ""; +my $CONF_LOC = '/etc/kernel-img.conf'; +my $relative_links = ''; +my $silent_loader = ''; +my $warn_reboot = ''; # Warn that we are installing a version of + # the kernel we are running + +my $modules_base = '/lib/modules'; + +die "Pre inst Internal error. Aborting." unless $version; + +exit 0 if $ARGV[0] =~ /abort-upgrade/; +exit 1 unless $ARGV[0] =~ /(install|upgrade)/; + +# remove multiple leading slashes; make sure there is at least one. +$realimageloc =~ s|^/*|/|o; +$realimageloc =~ s|/+|/|o; + +if (-r "$CONF_LOC" && -f "$CONF_LOC" ) { + if (open(CONF, "$CONF_LOC")) { + while () { + chomp; + s/\#.*$//g; + next if /^\s*$/; + + $do_symlink = "" if /^\s*do_symlinks\s*=\s*(no|false|0)\s*$/ig; + $no_symlink = "" if /^\s*no_symlinks\s*=\s*(no|false|0)\s*$/ig; + $reverse_symlink = "" if /^\s*reverse_symlinks\s*=\s*(no|false|0)\s*$/ig; + $link_in_boot = "" if /^\s*image_in_boot\s*=\s*(no|false|0)\s*$/ig; + $link_in_boot = "" if /^\s*link_in_boot\s*=\s*(no|false|0)\s*$/ig; + $move_image = "" if /^\s*move_image\s*=\s*(no|false|0)\s*$/ig; + $do_boot_enable = '' if /^\s*do_boot_enable\s*=\s*(no|false|0)\s*$/ig; + $do_bootfloppy = '' if /^\s*do_bootfloppy\s*=\s*(no|false|0)\s*$/ig; + $do_bootloader = '' if /^\s*do_bootloader\s*=\s*(no|false|0)\s*$/ig; + $relative_links = '' if /^\s*relative_links \s*=\s*(no|false|0)\s*$/ig; + $use_hard_links = '' if /^\s*use_hard_links\s*=\s*(no|false|0)\s*$/ig; + $silent_loader = '' if /^\s*silent_loader\s*=\s*(no|false|0)\s*$/ig; + $warn_reboot = '' if /^\s*warn_reboot\s*=\s*(no|false|0)\s*$/ig; + $minimal_swap = '' if /^\s*minimal_swap\s*=\s*(no|false|0)\s*$/ig; + $ignore_depmod_err = '' if /^\s*ignore_depmod_err\s*=\s*(no|false|0)\s*$/ig; + $relink_src_link = '' if /^\s*relink_src_link\s*=\s*(no|false|0)\s*$/ig; + $relink_build_link = '' if /^\s*relink_build_link\s*=\s*(no|false|0)\s*$/ig; + $force_build_link = '' if /^\s*force_build_link\s*=\s*(no|false|0)\s*$/ig; + + $do_symlink = "Yes" if /^\s*do_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $no_symlink = "Yes" if /^\s*no_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $reverse_symlink = "Yes" if /^\s*reverse_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $link_in_boot = "Yes" if /^\s*image_in_boot\s*=\s*(yes|true|1)\s*$/ig; + $link_in_boot = "Yes" if /^\s*link_in_boot\s*=\s*(yes|true|1)\s*$/ig; + $move_image = "Yes" if /^\s*move_image\s*=\s*(yes|true|1)\s*$/ig; + $do_boot_enable = "Yes" if /^\s*do_boot_enable\s*=\s*(yes|true|1)\s*$/ig; + $do_bootfloppy = "Yes" if /^\s*do_bootfloppy\s*=\s*(yes|true|1)\s*$/ig; + $do_bootloader = "Yes" if /^\s*do_bootloader\s*=\s*(yes|true|1)\s*$/ig; + $relative_links = "Yes" if /^\s*relative_links\s*=\s*(yes|true|1)\s*$/ig; + $use_hard_links = "Yes" if /^\s*use_hard_links\s*=\s*(yes|true|1)\s*$/ig; + $silent_loader = 'Yes' if /^\s*silent_loader\s*=\s*(yes|true|1)\s*$/ig; + $warn_reboot = 'Yes' if /^\s*warn_reboot\s*=\s*(yes|true|1)\s*$/ig; + $minimal_swap = 'Yes' if /^\s*minimal_swap\s*=\s*(yes|true|1)\s*$/ig; + $ignore_depmod_err = 'Yes' if /^\s*ignore_depmod_err\s*=\s*(yes|true|1)\s*$/ig; + $relink_src_link = 'Yes' if /^\s*relink_src_link\s*=\s*(yes|true|1)\s*$/ig; + $relink_build_link = 'Yes' if /^\s*relink_build_link\s*=\s*(yes|true|1)\s*$/ig; + $force_build_link = 'Yes' if /^\s*force_build_link\s*=\s*(yes|true|1)\s*$/ig; + + $image_dest = "$1" if /^\s*image_dest\s*=\s*(\S+)/ig; + $postinst_hook = "$1" if /^\s*postinst_hook\s*=\s*(\S+)/ig; + $postrm_hook = "$1" if /^\s*postrm_hook\s*=\s*(\S+)/ig; + $preinst_hook = "$1" if /^\s*preinst_hook\s*=\s*(\S+)/ig; + $prerm_hook = "$1" if /^\s*prerm_hook\s*=\s*(\S+)/ig; + $ramdisk = "$1" if /^\s*ramdisk\s*=\s*(.+)$/ig; + } + close CONF; + $have_conffile = "Yes"; + $have_conffile = "Yes"; # stop perl complaining + } +} + +$ENV{KERNEL_ARCH}=$kernel_arch if $kernel_arch; + +# About to upgrade this package from version $2 TO THIS VERSION. +# "prerm upgrade" has already been called for the old version of +# this package. + +sub find_initrd_tool { + my $hostversion = shift; + my $version = shift; + my @ramdisks = + grep { + my $args = + "$_ " . + "--supported-host-version=$hostversion " . + "--supported-target-version=$version " . + "1>/dev/null 2>&1" + ; + system($args) == 0; + } + split (/[:,\s]+/, $ramdisk); +} + +sub check { + my $version = shift; + my $lib_modules="$modules_base/$version"; + my $message = ''; + + if (-d "$lib_modules") { + opendir(DIR, $lib_modules) || die "canā€™t opendir $lib_modules: $!"; + my @children = readdir(DIR); + if ($#children > 1) { + my @dirs = grep { -d "$lib_modules/$_" } @children; + if ($#dirs > 1) { # we have subdirs + my $dir_message=''; + for my $dir (@dirs) { + if ($dir =~/kernel$/) { + $dir_message="An older install was detected.\n"; + } + else { + $dir_message="Module sub-directories were detected.\n" + unless $dir_message; + } + } + $message += $dir_message if $dir_message; + } + + my @links = grep { -l "$lib_modules/$_" } @children; + if ($#links > -1) { + my $links_message = ''; + for my $link (@links) { + next if ($link =~ /^build$/); + next if ($link =~ /^source$/); + $links_message = "Symbolic links were detected in $modules_base/$version.\n"; + } + $message += $links_message if $links_message; + } + my @files = grep { -f "$lib_modules/$_" } @children; + $message += "Additional files also exist in $modules_base/$version.\n" + if ($#files > -1); + } + } + else { $message .= "$lib_modules does not exist. ";} + return $message; +} + +if (-d "$modules_base/$version") { + my $errors=check($version); + warn "Info:\n$errors\n" if $errors; +} + +# set the env var stem +$ENV{'STEM'} = "linux"; + +sub exec_script { + my $type = shift; + my $script = shift; + print STDERR "Running $type hook script $script.\n"; + system ("$script $version $realimageloc$kimage-$version") && + print STDERR "User $type hook script [$script] "; + if ($?) { + if ($? == -1) { + print STDERR "failed to execute: $!\n"; + } + elsif ($? & 127) { + printf STDERR "died with signal %d, %s coredump\n", + ($? & 127), ($? & 128) ? 'with' : 'without'; + } + else { + printf STDERR "exited with value %d\n", $? >> 8; + } + exit $? >> 8; + } +} +sub run_hook { + my $type = shift; + my $script = shift; + if ($script =~ m,^/,) { + # Full path provided for the hook script + if (-x "$script") { + &exec_script($type,$script); + } + else { + die "The provided $type hook script [$script] could not be run.\n"; + } + } + else { + # Look for it in a safe path + for my $path ('/bin', '/sbin', '/usr/bin', '/usr/sbin') { + if (-x "$path/$script") { + &exec_script($type, "$path/$script"); + return 0; + } + } + # No luck + print STDERR "Could not find $type hook script [$script].\n"; + die "Looked in: '/bin', '/sbin', '/usr/bin', '/usr/sbin'\n"; + } +} + + +## Run user hook script here, if any +if (-x "$preinst_hook") { + &run_hook("preinst", $preinst_hook); +} +if (-d "/etc/kernel/preinst.d") { + print STDERR "Examining /etc/kernel/preinst.d/\n"; + system ("run-parts --verbose --exit-on-error --arg=$version" . + " --arg=$realimageloc$kimage-$version" . + " /etc/kernel/preinst.d") && + die "Failed to process /etc/kernel/preinst.d"; +} +if (-d "/etc/kernel/preinst.d/$version") { + print STDERR "Examining /etc/kernel/preinst.d/$version.\n"; + system ("run-parts --verbose --exit-on-error --arg=$version" . + " --arg=$realimageloc$kimage-$version" . + " /etc/kernel/preinst.d/$version") && + die "Failed to process /etc/kernel/preinst.d/$version"; +} +print STDERR "Done.\n"; + +exit 0; + +__END__ + + --- linux-2.6.27.orig/debian/control-scripts/headers-postinst +++ linux-2.6.27/debian/control-scripts/headers-postinst @@ -0,0 +1,126 @@ +#!/usr/bin/perl +# -*- Mode: Cperl -*- +# debian.postinst --- +# Author : Manoj Srivastava ( srivasta@pilgrim.umass.edu ) +# Created On : Sat Apr 27 05:42:43 1996 +# Created On Node : melkor.pilgrim.umass.edu +# Last Modified By : Manoj Srivastava +# Last Modified On : Sat Aug 5 13:20:22 2006 +# Last Machine Used: glaurung.internal.golden-gryphon.com +# Update Count : 45 +# Status : Unknown, Use with caution! +# HISTORY : +# Description : +# +# +# +# arch-tag: 1c716174-2f0a-476d-a626-a1322e62503a +# + + +$|=1; + +# Predefined values: +my $version = "=V"; +my $kimage = "=K"; +my $package_name = "linux-image-$version"; + + +# Ignore all invocations uxcept when called on to configure. +exit 0 unless ($ARGV[0] && $ARGV[0] =~ /configure/); + +#known variables +my $image_dest = "/"; +my $realimageloc = "/boot/"; +my $silent_modules = ''; +my $modules_base = '/lib/modules'; +my $CONF_LOC = '/etc/kernel-img.conf'; +# remove multiple leading slashes; make sure there is at least one. +$realimageloc =~ s|^/*|/|o; +$realimageloc =~ s|/+|/|o; + +chdir '/usr/src' or die "Could not chdir to /usr/src:$!"; + +if (-r "$CONF_LOC" && -f "$CONF_LOC" ) { + if (open(CONF, "$CONF_LOC")) { + while () { + chomp; + s/\#.*$//g; + next if /^\s*$/; + + $header_postinst_hook = "$1" if /^\s*header_postinst_hook\s*=\s*(\S+)/ig; + } + close CONF; + } +} + +sub exec_script { + my $type = shift; + my $script = shift; + print STDERR "Running $type hook script $script.\n"; + system ("$script $version $realimageloc$kimage-$version") && + print STDERR "User $type hook script [$script] "; + if ($?) { + if ($? == -1) { + print STDERR "failed to execute: $!\n"; + } + elsif ($? & 127) { + printf STDERR "died with signal %d, %s coredump\n", + ($? & 127), ($? & 128) ? 'with' : 'without'; + } + else { + printf STDERR "exited with value %d\n", $? >> 8; + } + exit $? >> 8; + } +} +sub run_hook { + my $type = shift; + my $script = shift; + if ($script =~ m,^/,) { + # Full path provided for the hook script + if (-x "$script") { + &exec_script($type,$script); + } + else { + die "The provided $type hook script [$script] could not be run.\n"; + } + } + else { + # Look for it in a safe path + for my $path ('/bin', '/sbin', '/usr/bin', '/usr/sbin') { + if (-x "$path/$script") { + &exec_script($type, "$path/$script"); + return 0; + } + } + # No luck + print STDERR "Could not find $type hook script [$script].\n"; + die "Looked in: '/bin', '/sbin', '/usr/bin', '/usr/sbin'\n"; + } +} + +## Run user hook script here, if any +if (-x "$header_postinst_hook") { + &run_hook("postinst", $header_postinst_hook); +} + +if (-d "/etc/kernel/header_postinst.d") { + print STDERR "Examining /etc/kernel/header_postinst.d.\n"; + system ("run-parts --verbose --exit-on-error --arg=$version " . + "--arg=$realimageloc$kimage-$version " . + "/etc/kernel/header_postinst.d") && + die "Failed to process /etc/kernel/header_postinst.d"; +} + +if (-d "/etc/kernel/header_postinst.d/$version") { + print STDERR "Examining /etc/kernel/header_postinst.d/$version.\n"; + system ("run-parts --verbose --exit-on-error --arg=$version " . + "--arg=$realimageloc$kimage-$version " . + "/etc/kernel/header_postinst.d/$version") && + die "Failed to process /etc/kernel/header_postinst.d/$version"; +} + +exit 0; + +__END__ --- linux-2.6.27.orig/debian/control-scripts/postrm +++ linux-2.6.27/debian/control-scripts/postrm @@ -0,0 +1,376 @@ +#! /usr/bin/perl +# -*- Mode: Cperl -*- +# image.postrm --- +# Author : Manoj Srivastava ( srivasta@glaurung.green-gryphon.com ) +# Created On : Sat May 15 11:05:13 1999 +# Created On Node : glaurung.green-gryphon.com +# Last Modified By : Manoj Srivastava +# Last Modified On : Wed Sep 13 11:26:19 2006 +# Last Machine Used: glaurung.internal.golden-gryphon.com +# Update Count : 57 +# Status : Unknown, Use with caution! +# HISTORY : +# Description : +# +# $Id: image.postrm,v 1.31 2003/10/07 16:24:20 srivasta Exp $ +# + + +# +#use strict; #for debugging +use Cwd 'abs_path'; + +$|=1; + +# Predefined values: +my $version = "=V"; +my $link_in_boot = ""; # Should be empty, mostly +my $no_symlink = ""; # Should be empty, mostly +my $reverse_symlink = ""; # Should be empty, mostly +my $do_symlink = "Yes"; # target machine defined +my $do_boot_enable = "Yes"; # target machine defined +my $do_bootfloppy = "Yes"; # target machine defined +my $do_bootloader = "Yes"; # target machine defined +my $move_image = ''; # target machine defined +my $kimage = "=K"; # Should be empty, mostly +my $loader = "=L"; # lilo, silo, quik, palo, vmelilo, or nettrom +my $image_dir = "/boot"; # where the image is located +my $clobber_modules = ''; # target machine defined +my $initrd = "YES"; # initrd kernel +my $do_initrd = ''; # Normally, we don't +my $warn_initrd = 'YES'; # Normally we do +my $use_hard_links = ''; # hardlinks do not work across fs boundaries +my $postinst_hook = ''; #Normally we do not +my $postrm_hook = ''; #Normally we do not +my $preinst_hook = ''; #Normally we do not +my $prerm_hook = ''; #Normally we do not +my $minimal_swap = ''; # Do not swap symlinks +my $ignore_depmod_err = ''; # normally we do not +my $relink_build_link = 'YES'; # There is no harm in checking the link +my $force_build_link = ''; # we shall not create a dangling link +my $kernel_arch = "=B"; +my $ramdisk = "/usr/sbin/update-initramfs"; +my $package_name = "linux-image-$version"; + +my $Loader = "NoLOADER"; # +$Loader = "LILO" if $loader =~ /^lilo/io; +$Loader = "SILO" if $loader =~ /^silo/io; +$Loader = "QUIK" if $loader =~ /^quik/io; +$Loader = "yaboot" if $loader =~ /^yaboot/io; +$Loader = "PALO" if $loader =~ /^palo/io; +$Loader = "NETTROM" if $loader =~ /^nettrom/io; +$Loader = "VMELILO" if $loader =~ /^vmelilo/io; +$Loader = "ZIPL" if $loader =~ /^zipl/io; +$Loader = "ELILO" if $loader =~ /^elilo/io; + + +# This should not point to /tmp, because of security risks. +my $temp_file_name = "/var/log/$loader" . "_log.$$"; + +#known variables +my @boilerplate = (); +my @silotemplate = (); +my @quiktemplate = (); +my @palotemplate = (); +my @vmelilotemplate = (); +my $bootdevice = ''; +my $rootdevice = ''; +my $rootdisk = ''; +my $rootpartition = ''; +my $image_dest = "/"; +my $realimageloc = "/$image_dir/"; +my $have_conffile = ""; +my $CONF_LOC = '/etc/kernel-img.conf'; +my $relative_links = ''; +my $silent_modules = ''; +my $silent_loader = ''; +my $warn_reboot = 'Yes'; # Warn that we are installing a version of + # the kernel we are running + +chdir('/') or die "could not chdir to /:$!\n"; +# remove multiple leading slashes; make sure there is at least one. +$realimageloc =~ s|^/*|/|o; +$realimageloc =~ s|/+|/|o; + + +if (-r "$CONF_LOC" && -f "$CONF_LOC" ) { + if (open(CONF, "$CONF_LOC")) { + while () { + chomp; + s/\#.*$//g; + next if /^\s*$/; + + $do_symlink = "" if /^\s*do_symlinks\s*=\s*(no|false|0)\s*$/ig; + $no_symlink = "" if /^\s*no_symlinks\s*=\s*(no|false|0)\s*$/ig; + $reverse_symlink = "" if /^\s*reverse_symlinks\s*=\s*(no|false|0)\s*$/ig; + $link_in_boot = "" if /^\s*image_in_boot\s*=\s*(no|false|0)\s*$/ig; + $link_in_boot = "" if /^\s*link_in_boot\s*=\s*(no|false|0)\s*$/ig; + $move_image = "" if /^\s*move_image\s*=\s*(no|false|0)\s*$/ig; + $clobber_modules = '' if /^\s*clobber_modules\s*=\s*(no|false|0)\s*$/ig; + $do_boot_enable = '' if /^\s*do_boot_enable\s*=\s*(no|false|0)\s*$/ig; + $do_bootfloppy = '' if /^\s*do_bootfloppy\s*=\s*(no|false|0)\s*$/ig; + $relative_links = '' if /^\s*relative_links \s*=\s*(no|false|0)\s*$/ig; + $do_bootloader = '' if /^\s*do_bootloader\s*=\s*(no|false|0)\s*$/ig; + $do_initrd = '' if /^\s*do_initrd\s*=\s*(no|false|0)\s*$/ig; + $warn_initrd = '' if /^\s*warn_initrd\s*=\s*(no|false|0)\s*$/ig; + $use_hard_links = '' if /^\s*use_hard_links\s*=\s*(no|false|0)\s*$/ig; + $silent_modules = '' if /^\s*silent_modules\s*=\s*(no|false|0)\s*$/ig; + $silent_loader = '' if /^\s*silent_loader\s*=\s*(no|false|0)\s*$/ig; + $warn_reboot = '' if /^\s*warn_reboot\s*=\s*(no|false|0)\s*$/ig; + $minimal_swap = '' if /^\s*minimal_swap\s*=\s*(no|false|0)\s*$/ig; + $ignore_depmod_err = '' if /^\s*ignore_depmod_err\s*=\s*(no|false|0)\s*$/ig; + $relink_build_link = '' if /^\s*relink_build_link\s*=\s*(no|false|0)\s*$/ig; + $force_build_link = '' if /^\s*force_build_link\s*=\s*(no|false|0)\s*$/ig; + + $do_symlink = "Yes" if /^\s*do_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $no_symlink = "Yes" if /^\s*no_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $reverse_symlink = "Yes" if /^\s*reverse_symlinks\s*=\s*(yes|true|1)\s*$/ig; + $link_in_boot = "Yes" if /^\s*image_in_boot\s*=\s*(yes|true|1)\s*$/ig; + $link_in_boot = "Yes" if /^\s*link_in_boot\s*=\s*(yes|true|1)\s*$/ig; + $move_image = "Yes" if /^\s*move_image\s*=\s*(yes|true|1)\s*$/ig; + $clobber_modules = "Yes" if /^\s*clobber_modules\s*=\s*(yes|true|1)\s*$/ig; + $do_boot_enable = "Yes" if /^\s*do_boot_enable\s*=\s*(yes|true|1)\s*$/ig; + $do_bootfloppy = "Yes" if /^\s*do_bootfloppy\s*=\s*(yes|true|1)\s*$/ig; + $do_bootloader = "Yes" if /^\s*do_bootloader\s*=\s*(yes|true|1)\s*$/ig; + $relative_links = "Yes" if /^\s*relative_links\s*=\s*(yes|true|1)\s*$/ig; + $do_initrd = "Yes" if /^\s*do_initrd\s*=\s*(yes|true|1)\s*$/ig; + $warn_initrd = "Yes" if /^\s*warn_initrd\s*=\s*(yes|true|1)\s*$/ig; + $use_hard_links = "Yes" if /^\s*use_hard_links\s*=\s*(yes|true|1)\s*$/ig; + $silent_modules = 'Yes' if /^\s*silent_modules\s*=\s*(yes|true|1)\s*$/ig; + $silent_loader = 'Yes' if /^\s*silent_loader\s*=\s*(yes|true|1)\s*$/ig; + $warn_reboot = 'Yes' if /^\s*warn_reboot\s*=\s*(yes|true|1)\s*$/ig; + $minimal_swap = 'Yes' if /^\s*minimal_swap\s*=\s*(yes|true|1)\s*$/ig; + $ignore_depmod_err = 'Yes' if /^\s*ignore_depmod_err\s*=\s*(yes|true|1)\s*$/ig; + $relink_build_link = 'Yes' if /^\s*relink_build_link\s*=\s*(yes|true|1)\s*$/ig; + $force_build_link = 'Yes' if /^\s*force_build_link\s*=\s*(yes|true|1)\s*$/ig; + + $image_dest = "$1" if /^\s*image_dest\s*=\s*(\S+)/ig; + $postinst_hook = "$1" if /^\s*postinst_hook\s*=\s*(\S+)/ig; + $postrm_hook = "$1" if /^\s*postrm_hook\s*=\s*(\S+)/ig; + $preinst_hook = "$1" if /^\s*preinst_hook\s*=\s*(\S+)/ig; + $prerm_hook = "$1" if /^\s*prerm_hook\s*=\s*(\S+)/ig; + $ramdisk = "$1" if /^\s*ramdisk\s*=\s*(.+)$/ig; + } + close CONF; + $have_conffile = "Yes"; + } +} + +if ($link_in_boot) { + $image_dest = "/$image_dir/"; + $image_dest =~ s|^/*|/|o; +} + +$image_dest = "$image_dest/"; +$image_dest =~ s|/+$|/|o; + +# The destdir may be gone by now. +if (-d "$image_dest") { + chdir("$image_dest") or die "could not chdir to $image_dest:$!\n"; +} + +# Paranoid check to make sure that the correct value is put in there +if (! $kimage) {$kimage = "vmlinuz"} # Hmm. empty +elsif ($kimage =~ m/^b?zImage$/o) {$kimage = "vmlinuz"} # these produce vmlinuz +elsif ($kimage =~ m/^[iI]mage$/o) { my $nop = $kimage;} +elsif ($kimage =~ m/^vmlinux$/o) { my $nop = $kimage;} +else {$kimage = "vmlinuz"} # default + +$ENV{KERNEL_ARCH}=$kernel_arch if $kernel_arch; + + +###################################################################### +###################################################################### +############ +###################################################################### +###################################################################### +sub remove_sym_link { + my $bad_image = $_[0]; + + warn "Removing symbolic link $bad_image \n"; + if ($loader =~ /lilo/i) + { + warn "Unless you used the optional flag in lilo, \n"; + } + warn " you may need to re-run your boot loader" . ($loader ? "[$loader]":"") + . "\n"; + # Remove the dangling link + unlink "$bad_image"; +} + +###################################################################### +###################################################################### +############ +###################################################################### +###################################################################### +sub CanonicalizePath { + my $path = join '/', @_; + my @work = split '/', $path; + my @out; + my $is_absolute; + + if (@work && $work[0] eq "") { $is_absolute = 1; shift @work; } + + while (@work) { + my $seg = shift @work; + if ($seg eq "." || $seg eq "") { + } elsif ($seg eq "..") { + if (@out && $out[-1] ne "..") { + pop @out; + } else { + # Leading "..", or "../..", etc. + push @out, $seg; + } + } else { + push @out, $seg; + } + } + + unshift @out, "" if $is_absolute; + return join('/', @out); +} + +###################################################################### +###################################################################### +############ +###################################################################### +###################################################################### +# This removes dangling symlinks. What do we do about hard links? Surely a +# something with the nane $image_dest . "$kimage" ought not to be left behind? +sub image_magic { + my $kimage = $_[0]; + my $image_dest = $_[1]; + + if (-l "$kimage") { + # There is a symbolic link + my $force_move = 0; + my $vmlinuz_target = readlink "$kimage"; + my $real_target = ''; + $real_target = abs_path($vmlinuz_target) if defined ($vmlinuz_target); + if (!defined($vmlinuz_target) || ! -f "$real_target") { + # what, a dangling symlink? + warn "The link " . $image_dest . "$kimage is a damaged link\n"; + # Remove the dangling link + &remove_sym_link("$kimage"); + } + else { + my $canonical_target = CanonicalizePath("$vmlinuz_target"); + if (! -e $canonical_target) { + warn "The link " . $image_dest . "$kimage is a dangling link\n"; + &remove_sym_link("$kimage"); + } + } + } +} + +# set the env var stem +$ENV{'STEM'} = "linux"; + +sub exec_script { + my $type = shift; + my $script = shift; + print STDERR "Running $type hook script $script.\n"; + system ("$script $version $realimageloc$kimage-$version") && + print STDERR "User $type hook script [$script] "; + if ($?) { + if ($? == -1) { + print STDERR "failed to execute: $!\n"; + } + elsif ($? & 127) { + printf STDERR "died with signal %d, %s coredump\n", + ($? & 127), ($? & 128) ? 'with' : 'without'; + } + else { + printf STDERR "exited with value %d\n", $? >> 8; + } + } +} +sub run_hook { + my $type = shift; + my $script = shift; + if ($script =~ m,^/,) { + # Full path provided for the hook script + if (-x "$script") { + &exec_script($type,$script); + } + else { + warn "The provided $type hook script [$script] could not be run.\n"; + } + } + else { + # Look for it in a safe path + for my $path ('/bin', '/sbin', '/usr/bin', '/usr/sbin') { + if (-x "$path/$script") { + &exec_script($type, "$path/$script"); + return 0; + } + } + # No luck + print STDERR "Could not find $type hook script [$script].\n"; + warn "Looked in: '/bin', '/sbin', '/usr/bin', '/usr/sbin'\n"; + } +} + +## Run user hook script here, if any +if ($postrm_hook) { + &run_hook("postrm", $postrm_hook); +} +if (-d "/etc/kernel/postrm.d") { + warn "Examining /etc/kernel/postrm.d .\n"; + system ("run-parts --verbose --exit-on-error --arg=$version " . + "--arg=$realimageloc$kimage-$version " . + "/etc/kernel/postrm.d") && + die "Failed to process /etc/kernel/postrm.d"; +} +if (-d "/etc/kernel/postrm.d/$version") { + warn "Examining /etc/kernel/postrm.d/$version .\n"; + system ("run-parts --verbose --exit-on-error --arg=$version " . + "--arg=$realimageloc$kimage-$version " . + "/etc/kernel/postrm.d/$version") && + die "Failed to process /etc/kernel/postrm.d/$version"; +} + +# check and remove damaged and dangling symlinks +if ($ARGV[0] !~ /upgrade/) { + system("$ramdisk -d -k " . $version . " > /dev/null 2>&1"); + if (-f $realimageloc . "initrd.img-$version.bak") { + unlink $realimageloc . "initrd.img-$version.bak"; + } + image_magic($kimage, $image_dest); + image_magic($kimage . ".old", $image_dest); + image_magic("initrd.img", $image_dest) if $initrd; + image_magic("initrd.img.old", $image_dest) if $initrd; +} + + +# Ignore all invocations except when called on to purge. +exit 0 unless $ARGV[0] =~ /purge/; + +my @files_to_remove = qw{ + modules.dep modules.isapnpmap modules.pcimap + modules.usbmap modules.parportmap + modules.generic_string modules.ieee1394map + modules.ieee1394map modules.pnpbiosmap + modules.alias modules.ccwmap modules.inputmap + modules.symbols build source modules.ofmap + }; + +foreach my $extra_file (@files_to_remove) { + if (-f "/lib/modules/$version/$extra_file") { + unlink "/lib/modules/$version/$extra_file"; + } +} + +if (-d "/lib/modules/$version" ) { + system ("rmdir", "/lib/modules/$version"); +} + +exit 0; + +__END__ + + + + + + --- linux-2.6.27.orig/debian/d-i/kernel-versions.in +++ linux-2.6.27/debian/d-i/kernel-versions.in @@ -0,0 +1,4 @@ +# arch version flavour installedname suffix bdep +amd64 PKGVER-ABINUM generic PKGVER-ABINUM-generic - + +i386 PKGVER-ABINUM generic PKGVER-ABINUM-generic - --- linux-2.6.27.orig/debian/d-i/package-list +++ linux-2.6.27/debian/d-i/package-list @@ -0,0 +1,168 @@ +Package: acpi-modules +Depends: kernel-image +Priority: standard +Description: Support for ACPI + +Package: fat-modules +Depends: kernel-image +Priority: standard +Description: FAT filesystem support + This includes Windows FAT and VFAT support. + +Package: fb-modules +Depends: kernel-image +Priority: standard +Description: Framebuffer modules + +Package: firewire-core-modules +Depends: kernel-image, storage-core-modules +Priority: standard +Description: Firewire (IEEE-1394) Support + +Package: floppy-modules +Depends: kernel-image +Priority: standard +Description: Floppy driver support + +Package: fs-core-modules +Depends: kernel-image +Priority: standard +Provides: ext2-modules, ext3-modules, jfs-modules, reiserfs-modules, xfs-modules +Description: Base filesystem modules + This includes ext2, ext3, jfs, reiserfs and xfs. + +Package: fs-secondary-modules +Depends: kernel-image, fat-modules +Priority: standard +Provides: ntfs-modules, hfs-modules +Description: Extra filesystem modules + This includes support for Windows NTFS and MacOS HFS/HFSPlus + +Package: input-modules +Depends: kernel-image, usb-modules +Priority: standard +Description: Support for various input methods + +Package: ipv6-modules +Depends: kernel-image +Priority: standard +Description: Support for IPv6 networking + +Package: irda-modules +Depends: kernel-image, nic-shared-modules +Priority: standard +Description: Support for Infrared protocols + +Package: md-modules +Depends: kernel-image +Priority: standard +Description: Multi-device support (raid, device-mapper, lvm) + +Package: nic-modules +Depends: kernel-image, nic-shared-modules, virtio-modules +Priority: standard +Description: Network interface support + +Package: nic-pcmcia-modules +Depends: kernel-image, nic-shared-modules, nic-modules +Priority: standard +Description: PCMCIA network interface support + +Package: nic-usb-modules +Depends: kernel-image, nic-shared-modules, usb-modules +Priority: standard +Description: USB network interface support + +Package: parport-modules +Depends: kernel-image +Priority: standard +Description: Parallel port support + +Package: pata-modules +Depends: kernel-image, storage-core-modules +Priority: standard +Description: PATA support modules + +Package: pcmcia-modules +Depends: kernel-image +Priority: standard +Description: PCMCIA Modules + +Package: pcmcia-storage-modules +Depends: kernel-image, scsi-modules +Priority: standard +Description: PCMCIA storage support + +Package: plip-modules +Depends: kernel-image, nic-shared-modules, parport-modules +Priority: standard +Description: PLIP (parallel port) networking support + +Package: ppp-modules +Depends: kernel-image, nic-shared-modules, serial-modules +Priority: standard +Description: PPP (serial port) networking support + +Package: sata-modules +Depends: kernel-image, storage-core-modules +Priority: standard +Description: SATA storage support + +Package: scsi-modules +Depends: kernel-image, storage-core-modules +Priority: standard +Description: SCSI storage support + +Package: serial-modules +Depends: kernel-image +Priority: standard +Description: Serial port support + +Package: storage-core-modules +Depends: kernel-image +Priority: standard +Provides: loop-modules +Description: Core storage support + Includes core SCSI, LibATA, USB-Storage. Also includes related block + devices for CD, Disk and Tape medium (and IDE Floppy). + +Package: usb-modules +Depends: kernel-image, storage-core-modules +Priority: standard +Description: Core USB support + +Package: nfs-modules +Priority: standard +Depends: kernel-image +Description: NFS filesystem drivers + Includes the NFS client driver, and supporting modules. + +Package: block-modules +Priority: standard +Depends: kernel-image, storage-core-modules, parport-modules, virtio-modules +Description: Block storage devices + This package contains the block storage devices, including DAC960 and + paraide. + +Package: message-modules +Priority: standard +Depends: kernel-image, storage-core-modules, scsi-modules +Description: Fusion and i2o storage modules + This package containes the fusion and i2o storage modules. + +Package: crypto-modules +Priority: extra +Depends: kernel-image +Description: crypto modules + This package contains crypto modules. + +Package: virtio-modules +Priority: standard +Depends: kernel-image +Description: VirtIO Modules + Includes modules for VirtIO (virtual machine, generally kvm guests) + +Package: socket-modules +Depends: kernel-image +Priority: standard +Description: Unix socket support --- linux-2.6.27.orig/debian/d-i/kernel-versions +++ linux-2.6.27/debian/d-i/kernel-versions @@ -0,0 +1,4 @@ +# arch version flavour installedname suffix bdep +amd64 2.6.27-14 generic 2.6.27-14-generic - + +i386 2.6.27-14 generic 2.6.27-14-generic - --- linux-2.6.27.orig/debian/d-i/modules/pcmcia-storage-modules +++ linux-2.6.27/debian/d-i/modules/pcmcia-storage-modules @@ -0,0 +1,6 @@ +pata_pcmcia +qlogic_cs +fdomain_cs +aha152x_cs ? +nsp_cs ? +sym53c500_cs --- linux-2.6.27.orig/debian/d-i/modules/floppy-modules +++ linux-2.6.27/debian/d-i/modules/floppy-modules @@ -0,0 +1 @@ +floppy --- linux-2.6.27.orig/debian/d-i/modules/nic-shared-modules +++ linux-2.6.27/debian/d-i/modules/nic-shared-modules @@ -0,0 +1,21 @@ +# PHY +8390 +mii + +# CRC modules +crc-ccitt +crc-itu-t + +# mac80211 stuff +mac80211 +cfg80211 + +# rt2x00 lib (since rt2x00 is split across usb/pci/cb +rt2x00lib + +# Wireless 802.11 modules +ieee80211 +ieee80211_crypt +ieee80211_crypt_ccmp +ieee80211_crypt_tkip +ieee80211_crypt_wep --- linux-2.6.27.orig/debian/d-i/modules/fat-modules +++ linux-2.6.27/debian/d-i/modules/fat-modules @@ -0,0 +1,7 @@ +fat +vfat + +# Supporting modules ? +nls_cp437 ? +nls_iso8859-1 ? +nls_utf8 ? --- linux-2.6.27.orig/debian/d-i/modules/crypto-modules +++ linux-2.6.27/debian/d-i/modules/crypto-modules @@ -0,0 +1,7 @@ +aes_generic +blowfish +twofish +serpent +sha256_generic +cbc +crc32c --- linux-2.6.27.orig/debian/d-i/modules/usb-modules +++ linux-2.6.27/debian/d-i/modules/usb-modules @@ -0,0 +1,10 @@ +ehci-hcd +isp116x-hcd +isp1760 +ohci-hcd +r8a66597-hcd +sl811_cs +sl811-hcd +u132-hcd +uhci-hcd +usbserial --- linux-2.6.27.orig/debian/d-i/modules/socket-modules +++ linux-2.6.27/debian/d-i/modules/socket-modules @@ -0,0 +1 @@ +af_packet --- linux-2.6.27.orig/debian/d-i/modules/nic-pcmcia-modules +++ linux-2.6.27/debian/d-i/modules/nic-pcmcia-modules @@ -0,0 +1,19 @@ +3c574_cs ? +3c589_cs ? +airo_cs ? +atmel_cs ? +axnet_cs ? +com20020_cs ? +fmvj18x_cs ? +ibmtr_cs ? +netwave_cs ? +nmclan_cs ? +orinoco_cs ? +pcnet_cs ? +ray_cs ? +smc91c92_cs ? +wavelan_cs ? +wl3501_cs ? +xirc2ps_cs ? +xircom_cb ? +xircom_tulip_cb ? --- linux-2.6.27.orig/debian/d-i/modules/virtio-modules +++ linux-2.6.27/debian/d-i/modules/virtio-modules @@ -0,0 +1,4 @@ +virtio_balloon +virtio_pci +virtio_ring ? +virtio-rng --- linux-2.6.27.orig/debian/d-i/modules/serial-modules +++ linux-2.6.27/debian/d-i/modules/serial-modules @@ -0,0 +1,3 @@ +generic_serial +serial_cs +synclink_cs --- linux-2.6.27.orig/debian/d-i/modules/pcmcia-modules +++ linux-2.6.27/debian/d-i/modules/pcmcia-modules @@ -0,0 +1,8 @@ +i82092 +i82365 ? +pcmcia +pcmcia_core +pd6729 +rsrc_nonstatic +tcic ? +yenta_socket --- linux-2.6.27.orig/debian/d-i/modules/fs-core-modules +++ linux-2.6.27/debian/d-i/modules/fs-core-modules @@ -0,0 +1,5 @@ +ext2 +ext3 +jfs +reiserfs +xfs --- linux-2.6.27.orig/debian/d-i/modules/nic-modules +++ linux-2.6.27/debian/d-i/modules/nic-modules @@ -0,0 +1,150 @@ +3c359 ? +3c501 ? +3c503 ? +3c505 ? +3c507 ? +3c509 ? +3c515 ? +3c523 ? +3c527 ? +3c59x ? +8139cp ? +8139too ? +82596 ? +abyss ? +ac3200 ? +adm8211 ? +airo ? +airport ? +amd8111e ? +arc4 ? +arcnet ? +arc-rawmode ? +arc-rimi ? +arlan ? +at1700 ? +atl1 ? +atl1e ? +atl2 ? +atmel ? +atmel_pci ? +b44 ? +bcm43xx ? +bcm43xx-mac80211 ? +bmac ? +bnx2 ? +bonding ? +cassini ? +com20020 ? +com20020-pci ? +com90io ? +com90xx ? +cs89x0 ? +de2104x ? +de4x5 ? +de600 ? +de620 ? +defxx ? +depca ? +dl2k ? +dmfe ? +dummy ? +e100 ? +e1000 ? +e1000e ? +e2100 ? +eepro ? +eepro100 ? +eexpress ? +epic100 ? +eql ? +es3210 ? +eth16i ? +ewrk3 ? +fealnx ? +forcedeth ? +igb ? +ps3_gelic ? +hamachi ? +hermes ? +hp ? +hp100 ? +hp-plus ? +ibmtr ? +ipddp ? +ipw2100 ? +ipw2200 ? +ipw3945 ? +ixgb ? +lance ? +lanstreamer ? +lasi_82596 ? +lne390 ? +lp486e ? +mace ? +mv643xx_eth ? +myri_sbus ? +natsemi ? +ne ? +ne2 ? +ne2k-pci ? +ne3210 ? +netconsole ? +ni5010 ? +ni52 ? +ni65 ? +niu ? +ns83820 ? +olympic ? +orinoco ? +orinoco_pci ? +orinoco_plx ? +orinoco_tmd ? +pcnet32 ? +prism54 ? +r8169 ? +rate_control ? +rfc1051 ? +rfc1201 ? +rrunner ? +rt2400 ? +rt2500 ? +rt61pci ? +s2io ? +shaper ? +sis190 ? +sis900 ? +spidernet ? +skfp ? +skge ? +sk98lin ? +sky2 ? +smc9194 ? +smc-ultra ? +smc-ultra32 ? +starfire ? +strip ? +sunbmac ? +sundance ? +sungem ? +sungem_phy ? +sunhme ? +sunlance ? +sunqe ? +sunvnet ? +tg3 ? +tlan ? +tms380tr ? +tmspci ? +tulip ? +tun ? +typhoon ? +uli526x ? +via-rhine ? +via-velocity ? +virtio_net ? +wavelan ? +wd ? +winbond-840 ? +yellowfin ? +znet ? --- linux-2.6.27.orig/debian/d-i/modules/scsi-modules +++ linux-2.6.27/debian/d-i/modules/scsi-modules @@ -0,0 +1,113 @@ +# SCSI +raid_class ? +scsi_transport_spi ? +scsi_transport_fc ? +scsi_transport_iscsi ? +scsi_transport_sas ? +iscsi_tcp ? +libiscsi ? +amiga7xx ? +a3000 ? +a2091 ? +gvp11 ? +mvme147 ? +sgiwd93 ? +cyberstorm ? +cyberstormII ? +blz2060 ? +blz1230 ? +fastlane ? +oktagon_esp_mod ? +atari_scsi ? +mac_scsi ? +mac_esp ? +sun3_scsi ? +mvme16x ? +bvme6000 ? +sim710 ? +advansys ? +psi240i ? +BusLogic ? +dpt_i2o ? +u14-34f ? +ultrastor ? +aha152x ? +aha1542 ? +aha1740 ? +aic7xxx_old ? +ips ? +fd_mcs ? +fdomain ? +in2000 ? +g_NCR5380 ? +g_NCR5380_mmio ? +NCR53c406a ? +NCR_D700 ? +NCR_Q720_mod ? +sym53c416 ? +qlogicfas408 ? +qla1280 ? +pas16 ? +seagate ? +seagate ? +t128 ? +dmx3191d ? +dtc ? +zalon7xx ? +eata_pio ? +wd7000 ? +mca_53c9x ? +ibmmca ? +eata ? +dc395x ? +tmscsim ? +megaraid ? +atp870u ? +esp ? +gdth ? +initio ? +a100u2w ? +qlogicpti ? +ide-scsi ? +mesh ? +mac53c94 ? +pluto ? +dec_esp ? +3w-xxxx ? +3w-9xxx ? +ppa ? +imm ? +jazz_esp ? +sun3x_esp ? +fcal ? +lasi700 ? +nsp32 ? +ipr ? +hptiop ? +stex ? +osst ? +sg ? +ch ? +scsi_debug ? +aacraid ? +aic7xxx ? +aic79xx ? +aic94xx ? +arcmsr ? +acornscsi_mod ? +arxescsi ? +cumana_1 ? +cumana_2 ? +ecoscsi ? +oak ? +powertec ? +eesox ? +ibmvscsic ? +libsas ? +lpfc ? +megaraid_mm ? +megaraid_mbox ? +megaraid_sas ? +qla2xxx ? +sym53c8xx ? +qla4xxx ? --- linux-2.6.27.orig/debian/d-i/modules/storage-core-modules +++ linux-2.6.27/debian/d-i/modules/storage-core-modules @@ -0,0 +1,17 @@ +# Core stacks +libata +scsi_mod +usbcore +usb-storage + +# Block level +cdrom +sd_mod +sr_mod + +# Loop modules +loop +cryptoloop + +# Needs to be here for better cdrom initrd layout +isofs --- linux-2.6.27.orig/debian/d-i/modules/acpi-modules +++ linux-2.6.27/debian/d-i/modules/acpi-modules @@ -0,0 +1,2 @@ +fan +thermal --- linux-2.6.27.orig/debian/d-i/modules/firewire-core-modules +++ linux-2.6.27/debian/d-i/modules/firewire-core-modules @@ -0,0 +1,4 @@ +ieee1394 +ohci1394 +sbp2 +eth1394 --- linux-2.6.27.orig/debian/d-i/modules/plip-modules +++ linux-2.6.27/debian/d-i/modules/plip-modules @@ -0,0 +1 @@ +plip --- linux-2.6.27.orig/debian/d-i/modules/message-modules +++ linux-2.6.27/debian/d-i/modules/message-modules @@ -0,0 +1,13 @@ +mptbase +mptctl +mptfc +mptlan +mptsas +mptscsih +mptspi +i2o_block +i2o_bus +i2o_config +i2o_core +i2o_proc +i2o_scsi --- linux-2.6.27.orig/debian/d-i/modules/nic-usb-modules +++ linux-2.6.27/debian/d-i/modules/nic-usb-modules @@ -0,0 +1,11 @@ +catc ? +kaweth ? +pegasus ? +prism2_usb ? +rtl8150 ? +usbnet ? +zd1211rw ? +zd1201 ? +rt2500usb ? +rt73usb ? +rt2570 ? --- linux-2.6.27.orig/debian/d-i/modules/fb-modules +++ linux-2.6.27/debian/d-i/modules/fb-modules @@ -0,0 +1,3 @@ +fbcon +vesafb +vga16fb --- linux-2.6.27.orig/debian/d-i/modules/parport-modules +++ linux-2.6.27/debian/d-i/modules/parport-modules @@ -0,0 +1,2 @@ +parport +parport_pc --- linux-2.6.27.orig/debian/d-i/modules/md-modules +++ linux-2.6.27/debian/d-i/modules/md-modules @@ -0,0 +1,22 @@ +dm-crypt +dm-log +dm-mirror +dm-mod +dm-multipath +dm-raid4-5 +dm-round-robin +dm-snapshot +dm-zero +faulty +linear +md-mod +multipath +raid0 +raid1 +raid10 +raid456 + +# Extras +dm-raid4-5 +dm-loop +dm-bbr --- linux-2.6.27.orig/debian/d-i/modules/ipv6-modules +++ linux-2.6.27/debian/d-i/modules/ipv6-modules @@ -0,0 +1 @@ +ipv6 --- linux-2.6.27.orig/debian/d-i/modules/ppp-modules +++ linux-2.6.27/debian/d-i/modules/ppp-modules @@ -0,0 +1,8 @@ +ppp_async +ppp_deflate +ppp_generic +ppp_mppe +pppoe +pppox +ppp_synctty +syncppp --- linux-2.6.27.orig/debian/d-i/modules/pata-modules +++ linux-2.6.27/debian/d-i/modules/pata-modules @@ -0,0 +1,32 @@ +ata_generic +pata_acpi +pata_ali +pata_amd +pata_artop +pata_atiixp +pata_cmd64x +pata_cs5520 +pata_cs5530 +pata_efar +pata_hpt366 +pata_hpt37x +pata_hpt3x3 +pata_it8213 +pata_it821x +pata_jmicron +pata_marvell +pata_mpiix +pata_netcell +pata_ninja32 +pata_ns87410 +pata_ns87415 +pata_oldpiix +pata_pdc2027x +pata_pdc202xx_old +pata_rz1000 +pata_sch +pata_serverworks +pata_sil680 +pata_sl82c105 +pata_triflex +pata_via --- linux-2.6.27.orig/debian/d-i/modules/block-modules +++ linux-2.6.27/debian/d-i/modules/block-modules @@ -0,0 +1,31 @@ +aoe +aten +bpck +bpck6 ? +cciss +comm +cpqarray +DAC960 +dstr +epat +epia +fit2 +fit3 +friq +frpw +kbic +ktti +nbd +on20 +on26 +paride +pcd +pd +pf +pg +pktcdvd +pt +sx8 +ub +umem +virtio_blk ? --- linux-2.6.27.orig/debian/d-i/modules/input-modules +++ linux-2.6.27/debian/d-i/modules/input-modules @@ -0,0 +1,2 @@ +usbhid +usbkbd --- linux-2.6.27.orig/debian/d-i/modules/nfs-modules +++ linux-2.6.27/debian/d-i/modules/nfs-modules @@ -0,0 +1,4 @@ +nfs +nfs_acl +lockd +sunrpc --- linux-2.6.27.orig/debian/d-i/modules/fs-secondary-modules +++ linux-2.6.27/debian/d-i/modules/fs-secondary-modules @@ -0,0 +1,4 @@ +fuse +ntfs +hfs +hfsplus --- linux-2.6.27.orig/debian/d-i/modules/irda-modules +++ linux-2.6.27/debian/d-i/modules/irda-modules @@ -0,0 +1,30 @@ +act200l-sir +actisys-sir +ali-ircc +donauboe ? +esi-sir +girbil-sir +ircomm +ircomm-tty +irda +irda-usb +irlan +irnet +irport ? +irtty-sir +kingsun-sir +ks959-sir +ksdazzle-sir +litelink-sir +ma600-sir +mcp2120-sir +mcs7780 +nsc-ircc +old_belkin-sir +sir-dev +smsc-ircc2 +stir4200 +tekram-sir +via-ircc +vlsi_ir +w83977af_ir --- linux-2.6.27.orig/debian/d-i/modules/sata-modules +++ linux-2.6.27/debian/d-i/modules/sata-modules @@ -0,0 +1,19 @@ +# Rerquired by sata_sis +pata_sis + +ahci +ata_piix +pdc_adma +sata_inic162x +sata_mv +sata_nv +sata_promise +sata_qstor +sata_sil +sata_sil24 +sata_sis +sata_svw +sata_sx4 +sata_uli +sata_via +sata_vsc --- linux-2.6.27.orig/debian/rules.d/5-udebs.mk +++ linux-2.6.27/debian/rules.d/5-udebs.mk @@ -0,0 +1,27 @@ +binary-udebs: binary-debs debian/control + dh_testdir + dh_testroot + + # unpack the kernels into a temporary directory + mkdir -p debian/d-i-${arch} + + imagelist=$$(cat kernel-versions | grep ^${arch} | awk '{print $$4}') && \ + for i in $$imagelist; do \ + dpkg -x $$(ls ../linux-image-$$i\_$(release)-$(revision)_${arch}.deb) \ + debian/d-i-${arch}; \ + /sbin/depmod -b debian/d-i-${arch} $$i; \ + done + + touch ignore-dups + export SOURCEDIR=debian/d-i-${arch} && \ + kernel-wedge install-files && \ + kernel-wedge check + + # Build just the udebs + dilist=$$(dh_listpackages -s | grep "\-di$$") && \ + [ -z "$dilist" ] || \ + for i in $$dilist; do \ + dh_fixperms -p$$i; \ + dh_gencontrol -p$$i; \ + dh_builddeb -p$$i; \ + done --- linux-2.6.27.orig/debian/rules.d/amd64.mk +++ linux-2.6.27/debian/rules.d/amd64.mk @@ -0,0 +1,12 @@ +build_arch = x86_64 +header_arch = $(build_arch) +asm_link = x86 +defconfig = defconfig +flavours = generic server +build_image = bzImage +kernel_file = arch/$(build_arch)/boot/bzImage +install_file = vmlinuz + +server_sub = virtual + +loader = grub --- linux-2.6.27.orig/debian/rules.d/3-binary-indep.mk +++ linux-2.6.27/debian/rules.d/3-binary-indep.mk @@ -0,0 +1,85 @@ +build-indep: + +docpkg = linux-doc-$(release) +docdir = $(CURDIR)/debian/$(docpkg)/usr/share/doc/$(docpkg) +install-doc: + dh_testdir + dh_testroot + dh_clean -k -p$(docpkg) + + install -d $(docdir) + + # First the html docs. We skip these for autobuilds + if [ -z "$(AUTOBUILD) nobuild" ]; then \ + install -d $(docdir)/linux-doc-tmp; \ + $(kmake) O=$(docdir)/linux-doc-tmp htmldocs; \ + mv $(docdir)/linux-doc-tmp/Documentation/DocBook \ + $(docdir)/html; \ + rm -rf $(docdir)/linux-doc-tmp; \ + fi + + # Copy the rest + cp -a Documentation/* $(docdir) + rm -rf $(docdir)/DocBook + +indep_hdrpkg = linux-headers-$(abi_release) +indep_hdrdir = $(CURDIR)/debian/$(indep_hdrpkg)/usr/src/$(indep_hdrpkg) +install-headers: + dh_testdir + dh_testroot + dh_clean -k -p$(indep_hdrpkg) + + install -d $(indep_hdrdir) + find . -path './debian/*' -prune -o -path './include/*' -prune \ + -o -path './scripts/*' -prune -o -type f \ + \( -name 'Makefile*' -o -name 'Kconfig*' -o -name 'Kbuild*' -o \ + -name '*.sh' -o -name '*.pl' -o -name '*.lds' \) \ + -print | cpio -pd --preserve-modification-time $(indep_hdrdir) + cp -a drivers/media/dvb/dvb-core/*.h $(indep_hdrdir)/drivers/media/dvb/dvb-core + cp -a drivers/media/video/*.h $(indep_hdrdir)/drivers/media/video + cp -a drivers/media/dvb/frontends/*.h $(indep_hdrdir)/drivers/media/dvb/frontends + cp -a scripts include $(indep_hdrdir) + +srcpkg = linux-source-$(release) +srcdir = $(CURDIR)/debian/$(srcpkg)/usr/src/$(srcpkg) +install-source: + dh_testdir + dh_testroot + dh_clean -k -p$(srcpkg) + + install -d $(srcdir) + find . -path './debian/*' -prune -o \ + -path './.*' -prune -o -print | \ + cpio -pd --preserve-modification-time $(srcdir) + (cd $(srcdir)/..; tar cf - $(srcpkg)) | bzip2 -9c > \ + $(srcdir).tar.bz2 + rm -rf $(srcdir) + +install-indep: install-headers install-doc install-source + +# This is just to make it easy to call manually. Normally done in +# binary-indep target during builds. +binary-headers: install-headers + dh_testdir + dh_testroot + dh_installchangelogs -p$(indep_hdrpkg) + dh_installdocs -p$(indep_hdrpkg) + dh_compress -p$(indep_hdrpkg) + dh_fixperms -p$(indep_hdrpkg) + dh_installdeb -p$(indep_hdrpkg) + dh_gencontrol -p$(indep_hdrpkg) + dh_md5sums -p$(indep_hdrpkg) + dh_builddeb -p$(indep_hdrpkg) + +binary-indep: install-indep + dh_testdir + dh_testroot + + dh_installchangelogs -i + dh_installdocs -i + dh_compress -i + dh_fixperms -i + dh_installdeb -i + dh_gencontrol -i + dh_md5sums -i + dh_builddeb -i --- linux-2.6.27.orig/debian/rules.d/4-checks.mk +++ linux-2.6.27/debian/rules.d/4-checks.mk @@ -0,0 +1,26 @@ +# Check ABI for package against last release (if not same abinum) +abi-%: $(abidir)/% + @# Empty for make to be happy +$(abidir)/%: $(stampdir)/stamp-build-% + install -d $(abidir) + sed -e 's/^\(.\+\)[[:space:]]\+\(.\+\)[[:space:]]\(.\+\)$$/\3 \2 \1/' \ + $(builddir)/build-$*/Module.symvers | sort > $@ + +abi-check-%: $(abidir)/% + @perl -f debian/scripts/abi-check "$*" "$(prev_abinum)" "$(abinum)" \ + "$(prev_abidir)" "$(abidir)" "$(skipabi)" + +# Check the module list against the last release (always) +module-%: $(abidir)/%.modules + @# Empty for make to be happy +$(abidir)/%.modules: $(stampdir)/stamp-build-% + install -d $(abidir) + find $(builddir)/build-$*/ -name \*.ko | \ + sed -e 's/.*\/\([^\/]*\)\.ko/\1/' | sort > $@ + +module-check-%: $(abidir)/%.modules + @perl -f debian/scripts/module-check "$*" \ + "$(prev_abidir)" "$(abidir)" $(skipmodule) + +checks-%: abi-check-% module-check-% + @# Will be calling more stuff later --- linux-2.6.27.orig/debian/rules.d/0-common-vars.mk +++ linux-2.6.27/debian/rules.d/0-common-vars.mk @@ -0,0 +1,97 @@ +# Get some version info +stub=linux + +release := $(shell sed -n '1s/^.*(\(.*\)-.*).*$$/\1/p' debian/changelog) +revisions := $(shell sed -n 's/^$(stub)\ .*($(release)-\(.*\)).*$$/\1/p' debian/changelog | tac) +revision ?= $(word $(words $(revisions)),$(revisions)) +prev_revisions := $(filter-out $(revision),0.0 $(revisions)) +prev_revision := $(word $(words $(prev_revisions)),$(prev_revisions)) + +# This is an internally used mechanism for the daily kernel builds. It +# creates packages who's ABI is suffixed with a minimal representation of +# the current git HEAD sha. If .git/HEAD is not present, then it uses the +# uuidgen program, +# +# AUTOBUILD can also be used by anyone wanting to build a custom kernel +# image, or rebuild the entire set of Ubuntu packages using custom patches +# or configs. +AUTOBUILD= + +# +# This is a way to support some external variables. A good example is +# a local setup for ccache and distcc See LOCAL_ENV_CC and +# LOCAL_ENV_DISTCC_HOSTS in the definition of kmake. +# For example: +# LOCAL_ENV_CC="ccache distcc" +# LOCAL_ENV_DISTCC_HOSTS="localhost 10.0.2.5 10.0.2.221" +# +-include $(CURDIR)/../.intrepid-env + +ifneq ($(AUTOBUILD),) +skipabi = true +skipmodule = true +skipdbg = true +gitver=$(shell if test -f .git/HEAD; then cat .git/HEAD; else uuidgen; fi) +gitverpre=$(shell echo $(gitver) | cut -b -3) +gitverpost=$(shell echo $(gitver) | cut -b 38-40) +abi_suffix = -$(gitverpre)$(gitverpost) +endif + +ifneq ($(NOKERNLOG),) +ubuntu_log_opts += --no-kern-log +endif +ifneq ($(PRINTSHAS),) +ubuntu_log_opts += --print-shas +endif + +ifeq ($(wildcard /CurrentlyBuilding),) +skipdbg=true +endif + +abinum := $(shell echo $(revision) | sed -e 's/\..*//')$(abi_suffix) +prev_abinum := $(shell echo $(prev_revision) | sed -e 's/\..*//')$(abi_suffix) + +abi_release := $(release)-$(abinum) + +# We force the sublevel to be exactly what we want. The actual source may +# be an in development git tree. We want to force it here instead of +# committing changes to the top level Makefile +SUBLEVEL := $(shell echo $(release) | awk -F. '{print $$3}') + +arch := $(shell dpkg-architecture -qDEB_HOST_ARCH) +abidir := $(CURDIR)/debian/abi/$(release)-$(revision)/$(arch) +prev_abidir := $(CURDIR)/debian/abi/$(release)-$(prev_revision)/$(arch) +confdir := $(CURDIR)/debian/config/$(arch) +builddir := $(CURDIR)/debian/build +stampdir := $(CURDIR)/debian/stamps + +# Support parallel= in DEB_BUILD_OPTIONS (see #209008) +COMMA=, +DEB_BUILD_OPTIONS_PARA = $(subst parallel=,,$(filter parallel=%,$(subst $(COMMA), ,$(DEB_BUILD_OPTIONS)))) +ifneq (,$(DEB_BUILD_OPTIONS_PARA)) + CONCURRENCY_LEVEL := $(DEB_BUILD_OPTIONS_PARA) +endif + +ifeq ($(CONCURRENCY_LEVEL),) + # Check the environment + CONCURRENCY_LEVEL := $(shell echo $$CONCURRENCY_LEVEL) + # No? Check if this is on a buildd + ifeq ($(CONCURRENCY_LEVEL),) + ifeq ($(wildcard /CurrentlyBuilding),) + CONCURRENCY_LEVEL := $(shell expr `getconf _NPROCESSORS_ONLN` \* 1) + endif + endif + # Oh hell, give 'em one + ifeq ($(CONCURRENCY_LEVEL),) + CONCURRENCY_LEVEL := 1 + endif +endif + +conc_level = -j$(CONCURRENCY_LEVEL) + +# target_flavour is filled in for each step +kmake = make ARCH=$(build_arch) EXTRAVERSION=-$(abinum)-$(target_flavour) \ + CONFIG_DEBUG_SECTION_MISMATCH=y SUBLEVEL=$(SUBLEVEL) +ifneq ($(LOCAL_ENV_CC),) +kmake += CC=$(LOCAL_ENV_CC) DISTCC_HOSTS=$(LOCAL_ENV_DISTCC_HOSTS) +endif --- linux-2.6.27.orig/debian/rules.d/2-binary-arch.mk +++ linux-2.6.27/debian/rules.d/2-binary-arch.mk @@ -0,0 +1,278 @@ +# We don't want make removing intermediary stamps +.SECONDARY : + +# Prepare the out-of-tree build directory + +prepare-%: $(stampdir)/stamp-prepare-% + @# Empty for make to be happy +$(stampdir)/stamp-prepare-%: target_flavour = $* +$(stampdir)/stamp-prepare-%: $(confdir)/config $(confdir)/config.% + @echo "Preparing $*..." + install -d $(builddir)/build-$* + touch $(builddir)/build-$*/ubuntu-build + cat $^ | sed -e 's/.*CONFIG_VERSION_SIGNATURE.*/CONFIG_VERSION_SIGNATURE="Ubuntu $(release)-$(revision)-$*"/' > $(builddir)/build-$*/.config + find $(builddir)/build-$* -name "*.ko" | xargs rm -f + $(kmake) O=$(builddir)/build-$* silentoldconfig prepare scripts + touch $@ + + +# Do the actual build, including image and modules +build-%: $(stampdir)/stamp-build-% + @# Empty for make to be happy +$(stampdir)/stamp-build-%: target_flavour = $* +$(stampdir)/stamp-build-%: $(stampdir)/stamp-prepare-% + @echo "Building $*..." + $(kmake) O=$(builddir)/build-$* $(conc_level) $(build_image) + $(kmake) O=$(builddir)/build-$* $(conc_level) modules + @touch $@ + +# Install the finished build +install-%: pkgdir = $(CURDIR)/debian/linux-image-$(abi_release)-$* +install-%: dbgpkgdir = $(CURDIR)/debian/linux-image-debug-$(abi_release)-$* +install-%: basepkg = linux-headers-$(abi_release) +install-%: hdrdir = $(CURDIR)/debian/$(basepkg)-$*/usr/src/$(basepkg)-$* +install-%: target_flavour = $* +install-%: $(stampdir)/stamp-build-% checks-% + dh_testdir + dh_testroot + dh_clean -k -plinux-image-$(abi_release)-$* + dh_clean -k -plinux-headers-$(abi_release)-$* + dh_clean -k -plinux-image-debug-$(abi_release)-$* + + # The main image + install -m644 -D $(builddir)/build-$*/$(kernel_file) \ + $(pkgdir)/boot/$(install_file)-$(abi_release)-$* + + install -m644 $(builddir)/build-$*/.config \ + $(pkgdir)/boot/config-$(abi_release)-$* + install -m644 $(abidir)/$* \ + $(pkgdir)/boot/abi-$(abi_release)-$* + install -m644 $(builddir)/build-$*/System.map \ + $(pkgdir)/boot/System.map-$(abi_release)-$* + makedumpfile -g $(pkgdir)/boot/vmcoreinfo-$(abi_release)-$* \ + -x $(builddir)/build-$*/vmlinux + + $(kmake) O=$(builddir)/build-$* modules_install \ + INSTALL_MOD_STRIP=1 INSTALL_MOD_PATH=$(pkgdir)/ \ + INSTALL_FW_PATH=$(pkgdir)/lib/firmware/$(abi_release)-$* + + makedumpfile -g $(pkgdir)/boot/vmcoreinfo-$(abi_release)-$* \ + -x $(builddir)/build-$*/vmlinux + rm -f $(pkgdir)/lib/modules/$(abi_release)-$*/build + rm -f $(pkgdir)/lib/modules/$(abi_release)-$*/source + + # Some initramfs-tools specific modules + install -d $(pkgdir)/lib/modules/$(abi_release)-$*/initrd + if [ -f $(pkgdir)/lib/modules/$(abi_release)-$*/kernel/drivers/video/vesafb.ko ]; then\ + ln -f $(pkgdir)/lib/modules/$(abi_release)-$*/kernel/drivers/video/vesafb.ko \ + $(pkgdir)/lib/modules/$(abi_release)-$*/initrd/; \ + fi + + # Now the image scripts + install -d $(pkgdir)/DEBIAN + for script in postinst postrm preinst prerm; do \ + sed -e 's/=V/$(abi_release)-$*/g' -e 's/=K/$(install_file)/g' \ + -e 's/=L/$(loader)/g' -e 's@=B@$(build_arch)@g' \ + debian/control-scripts/$$script > $(pkgdir)/DEBIAN/$$script; \ + chmod 755 $(pkgdir)/DEBIAN/$$script; \ + done + +ifneq ($(skipsub),true) + @set -e; for sub in $($(*)_sub); do \ + TO=$$sub FROM=$* ABI_RELEASE=$(abi_release) $(SHELL) \ + debian/scripts/sub-flavour; \ + /sbin/depmod -b debian/linux-image-$(abi_release)-$$sub \ + -ea -F debian/linux-image-$(abi_release)-$$sub/boot/System.map-$(abi_release)-$* \ + $(abi_release)-$*; \ + install -d debian/linux-image-$(abi_release)-$$sub/DEBIAN; \ + for script in postinst postrm preinst prerm; do \ + sed -e 's/=V/$(abi_release)-$*/g' \ + -e 's/=K/$(install_file)/g' \ + -e 's/=L/$(loader)/g' \ + -e 's@=B@$(build_arch)@g' \ + debian/control-scripts/$$script > \ + debian/linux-image-$(abi_release)-$$sub/DEBIAN/$$script;\ + chmod 755 debian/linux-image-$(abi_release)-$$sub/DEBIAN/$$script;\ + done; \ + done +endif + +ifneq ($(skipdbg),true) + # Debug image is simple + install -m644 -D $(builddir)/build-$*/vmlinux \ + $(dbgpkgdir)/usr/lib/debug/boot/vmlinux-$(abi_release)-$* + $(kmake) O=$(builddir)/build-$* modules_install \ + INSTALL_MOD_PATH=$(dbgpkgdir)/usr/lib/debug + rm -f $(dbgpkgdir)/usr/lib/debug/lib/modules/$(abi_release)-$*/build + rm -f $(dbgpkgdir)/usr/lib/debug/lib/modules/$(abi_release)-$*/source + rm -f $(dbgpkgdir)/usr/lib/debug/lib/modules/$(abi_release)-$*/modules.* + rm -fr $(dbgpkgdir)/usr/lib/debug/lib/firmware +endif + + # The flavour specific headers image + # TODO: Would be nice if we didn't have to dupe the original builddir + install -d -m755 $(hdrdir) + cat $(builddir)/build-$*/.config | \ + sed -e 's/.*CONFIG_DEBUG_INFO=.*/# CONFIG_DEBUG_INFO is not set/g' > \ + $(hdrdir)/.config + chmod 644 $(hdrdir)/.config + $(kmake) O=$(hdrdir) silentoldconfig prepare scripts + # We'll symlink this stuff + rm -f $(hdrdir)/Makefile + rm -rf $(hdrdir)/include2 + # Script to symlink everything up + $(SHELL) debian/scripts/link-headers "$(hdrdir)" "$(basepkg)" "$*" + # Setup the proper asm symlink + rm -f $(hdrdir)/include/asm + ln -s asm-$(asm_link) $(hdrdir)/include/asm + # The build symlink + install -d debian/$(basepkg)-$*/lib/modules/$(abi_release)-$* + ln -s /usr/src/$(basepkg)-$* \ + debian/$(basepkg)-$*/lib/modules/$(abi_release)-$*/build + # And finally the symvers + install -m644 $(builddir)/build-$*/Module.symvers \ + $(hdrdir)/Module.symvers + + # Now the header scripts + install -d $(CURDIR)/debian/$(basepkg)-$*/DEBIAN + for script in postinst; do \ + sed -e 's/=V/$(abi_release)-$*/g' -e 's/=K/$(install_file)/g' \ + debian/control-scripts/headers-$$script > \ + $(CURDIR)/debian/$(basepkg)-$*/DEBIAN/$$script; \ + chmod 755 $(CURDIR)/debian/$(basepkg)-$*/DEBIAN/$$script; \ + done + + # At the end of the package prep, call the tests + DPKG_ARCH="$(arch)" KERN_ARCH="$(build_arch)" FLAVOUR="$*" \ + VERSION="$(abi_release)" REVISION="$(revision)" \ + PREV_REVISION="$(prev_revision)" ABI_NUM="$(abinum)" \ + PREV_ABI_NUM="$(prev_abinum)" BUILD_DIR="$(builddir)/build-$*" \ + INSTALL_DIR="$(pkgdir)" SOURCE_DIR="$(CURDIR)" \ + run-parts -v debian/tests + + # + # Remove files which are generated at installation by postinst. + # + rm -f $(pkgdir)/lib/modules/$(abi_release)-$*/modules.* + +headers_tmp := $(CURDIR)/debian/tmp-headers +headers_dir := $(CURDIR)/debian/linux-libc-dev + +hmake := $(MAKE) -C $(CURDIR) O=$(headers_tmp) SUBLEVEL=$(SUBLEVEL) \ + EXTRAVERSION=-$(abinum) INSTALL_HDR_PATH=$(headers_tmp)/install \ + SHELL="$(SHELL)" ARCH=$(header_arch) + +install-arch-headers: + dh_testdir + dh_testroot + dh_clean -k -plinux-libc-dev + + rm -rf $(headers_tmp) + install -d $(headers_tmp) $(headers_dir)/usr/include/ + + $(hmake) $(defconfig) + mv $(headers_tmp)/.config $(headers_tmp)/.config.old + sed -e 's/^# \(CONFIG_MODVERSIONS\) is not set$$/\1=y/' \ + -e 's/.*CONFIG_LOCALVERSION_AUTO.*/# CONFIG_LOCALVERSION_AUTO is not set/' \ + $(headers_tmp)/.config.old > $(headers_tmp)/.config + $(hmake) silentoldconfig + $(hmake) headers_install + + mv $(headers_tmp)/install/include/asm* \ + $(headers_dir)/usr/include/ + mv $(headers_tmp)/install/include/linux \ + $(headers_dir)/usr/include/ + + rm -rf $(headers_tmp) + +binary-arch-headers: install-arch-headers + dh_testdir + dh_testroot + + dh_installchangelogs -plinux-libc-dev + dh_installdocs -plinux-libc-dev + dh_compress -plinux-libc-dev + dh_fixperms -plinux-libc-dev + dh_installdeb -plinux-libc-dev + dh_gencontrol -plinux-libc-dev + dh_md5sums -plinux-libc-dev + dh_builddeb -plinux-libc-dev + +binary-%: pkgimg = linux-image-$(abi_release)-$* +binary-%: pkghdr = linux-headers-$(abi_release)-$* +binary-%: dbgpkg = linux-image-debug-$(abi_release)-$* +binary-%: install-% + dh_testdir + dh_testroot + + dh_installchangelogs -p$(pkgimg) + dh_installdocs -p$(pkgimg) + dh_compress -p$(pkgimg) + dh_fixperms -p$(pkgimg) + dh_installdeb -p$(pkgimg) + dh_gencontrol -p$(pkgimg) + dh_md5sums -p$(pkgimg) + dh_builddeb -p$(pkgimg) -- -Zbzip2 -z9 + + dh_installchangelogs -p$(pkghdr) + dh_installdocs -p$(pkghdr) + dh_compress -p$(pkghdr) + dh_fixperms -p$(pkghdr) + dh_shlibdeps -p$(pkghdr) + dh_installdeb -p$(pkghdr) + dh_gencontrol -p$(pkghdr) + dh_md5sums -p$(pkghdr) + dh_builddeb -p$(pkghdr) + +ifneq ($(skipsub),true) + @set -e; for sub in $($(*)_sub); do \ + pkg=linux-image-$(abi_release)-$$sub; \ + dh_installchangelogs -p$$pkg; \ + dh_installdocs -p$$pkg; \ + dh_compress -p$$pkg; \ + dh_fixperms -p$$pkg; \ + dh_shlibdeps -p$$pkg; \ + dh_installdeb -p$$pkg; \ + dh_gencontrol -p$$pkg; \ + dh_md5sums -p$$pkg; \ + dh_builddeb -p$$pkg; \ + done +endif + +ifneq ($(skipdbg),true) + dh_installchangelogs -p$(dbgpkg) + dh_installdocs -p$(dbgpkg) + dh_compress -p$(dbgpkg) + dh_fixperms -p$(dbgpkg) + dh_installdeb -p$(dbgpkg) + dh_gencontrol -p$(dbgpkg) + dh_md5sums -p$(dbgpkg) + dh_builddeb -p$(dbgpkg) + + # Hokay...here's where we do a little twiddling... + # Renaming the debug package prevents it from getting into + # the primary archive, and therefore prevents this very large + # package from being mirrored. It is instead, through some + # archive admin hackery, copied to http://ddebs.ubuntu.com. + # + mv ../$(dbgpkg)_$(release)-$(revision)_$(arch).deb \ + ../$(dbgpkg)_$(release)-$(revision)_$(arch).ddeb + grep -v '^$(dbgpkg)_.*$$' debian/files > debian/files.new + mv debian/files.new debian/files + # Now, the package wont get into the archive, but it will get put + # into the debug system. +endif + +$(stampdir)/stamp-flavours: + @echo $(flavours) > $@ + +binary-debs: $(stampdir)/stamp-flavours $(addprefix binary-,$(flavours)) \ + binary-arch-headers + +build-arch: $(addprefix build-,$(flavours)) + +binary-arch-deps = binary-debs +ifeq ($(AUTOBUILD),) +binary-arch-deps += binary-udebs +endif +binary-arch: $(binary-arch-deps) --- linux-2.6.27.orig/debian/rules.d/i386.mk +++ linux-2.6.27/debian/rules.d/i386.mk @@ -0,0 +1,12 @@ +build_arch = i386 +header_arch = x86_64 +asm_link = x86 +defconfig = defconfig +flavours = generic server +build_image = bzImage +kernel_file = arch/$(build_arch)/boot/bzImage +install_file = vmlinuz + +server_sub = virtual + +loader = grub --- linux-2.6.27.orig/debian/rules.d/1-maintainer.mk +++ linux-2.6.27/debian/rules.d/1-maintainer.mk @@ -0,0 +1,104 @@ +# The following targets are for the maintainer only! do no run if you don't +# know what they do. + +.PHONY: printenv updateconfigs printchanges insertchanges startnewrelease diffupstream help + +help: + @echo "These are the targets in addition to the normal debian ones:" + @echo + @echo " printenv : Print some variables used in the build" + @echo + @echo " updateconfigs : Update debian/config/*" + @echo + @echo " editconfigs : Update debian/config/* interactively" + @echo + @echo " printchanges : Print the current changelog entries (from git)" + @echo + @echo " insertchanges : Insert current changelog entries (from git)" + @echo + @echo " startnewrelease : Start a new changelog set" + @echo + @echo " diffupstream : Diff stock kernel code against upstream (git)" + @echo + @echo " help : If you are kernel hacking, you need the professional" + @echo " version of this" + @echo + @echo "Environment variables:" + @echo + @echo " NOKERNLOG : Do not add upstream kernel commits to changelog" + @echo " CONCURRENCY_LEVEL=X" + @echo " : Use -jX for kernel compile" + @echo " PRINTSHAS : Include SHAs for commits in changelog" + +ARCH_CONFIGS=i386 amd64 + +updateconfigs: + dh_testdir + @for arch in $(ARCH_CONFIGS); do \ + $(SHELL) debian/scripts/misc/oldconfig $$arch; \ + done + rm -rf build + +editconfigs: + dh_testdir + @for arch in $(ARCH_CONFIGS); do \ + $(SHELL) debian/scripts/misc/doconfig $$arch; \ + done + rm -rf build + +printenv: + dh_testdir + @echo "release = $(release)" + @echo "revisions = $(revisions)" + @echo "revision = $(revision)" + @echo "prev_revisions = $(prev_revisions)" + @echo "prev_revision = $(prev_revision)" + @echo "abinum = $(abinum)" + @echo "gitver = $(gitver)" + @echo "flavours = $(flavours)" + @echo "skipabi = $(skipabi)" + @echo "skipmodule = $(skipmodule)" + @echo "skipdbg = $(skipdbg)" + @echo "ubuntu_log_opts = $(ubuntu_log_opts)" +ifneq ($(SUBLEVEL),) + @echo "SUBLEVEL = $(SUBLEVEL)" +endif + @echo "CONCURRENCY_LEVEL = $(CONCURRENCY_LEVEL)" + +printchanges: + @git-log Ubuntu-$(release)-$(prev_revision)..HEAD | \ + perl -w -f debian/scripts/misc/git-ubuntu-log $(ubuntu_log_opts) + +insertchanges: + @perl -w -f debian/scripts/misc/insert-changes.pl + +diffupstream: + @git-diff-tree -p refs/remotes/linux-2.6/master..HEAD $(shell ls | grep -vE '^(ubuntu|debian|\.git.*)') + +startnewrelease: + dh_testdir + @nextminor=$(shell expr `echo $(revision) | awk -F. '{print $$2}'` + 1); \ + now="$(shell date -R)"; \ + echo "Creating new changelog set for $(abi_release).$$nextminor..."; \ + echo -e "$(stub) ($(abi_release).$$nextminor) UNRELEASED; urgency=low\n" > debian/changelog.new; \ + echo " CHANGELOG: Do not edit directly. Autogenerated at release." >> \ + debian/changelog.new; \ + echo " CHANGELOG: Use the printchanges target to see the curent changes." \ + >> debian/changelog.new; \ + echo " CHANGELOG: Use the insertchanges target to create the final log." \ + >> debian/changelog.new; \ + echo -e "\n -- $$DEBFULLNAME <$$DEBEMAIL> $$now\n" >> \ + debian/changelog.new ; \ + cat debian/changelog >> debian/changelog.new; \ + mv debian/changelog.new debian/changelog +# +# If $(ppa_file) exists, then only the standard flavours are built for PPA, e.g., +# 386, 386-generic, and amd64-generic. +# +prepare-ppa: + @echo Execute debian/scripts/misc/prepare-ppa-source to prepare an upload + @echo for a PPA build. You must do this outside of debian/rules since it cannot + @echo nest. + +print-ppa-file-name: + @echo $(ppa_file) --- linux-2.6.27.orig/debian/scripts/abi-check +++ linux-2.6.27/debian/scripts/abi-check @@ -0,0 +1,202 @@ +#!/usr/bin/perl -w + +my $flavour = shift; +my $prev_abinum = shift; +my $abinum = shift; +my $prev_abidir = shift; +my $abidir = shift; +my $skipabi = shift; + +my $fail_exit = 1; +my $EE = "EE:"; +my $errors = 0; + +my $count; + +print "II: Checking ABI for $flavour...\n"; + +if (-f "$prev_abidir/ignore" + or -f "$prev_abidir/$flavour.ignore" or "$skipabi" eq "true") { + print "WW: Explicitly asked to ignore ABI, running in no-fail mode\n"; + $fail_exit = 0; + $EE = "WW:"; +} + +if ($prev_abinum != $abinum) { + print "II: Different ABI's, running in no-fail mode\n"; + $fail_exit = 0; + $EE = "WW:"; +} + +if (not -f "$abidir/$flavour" or not -f "$prev_abidir/$flavour") { + print "EE: Previous or current ABI file missing!\n"; + print " $abidir/$flavour\n" if not -f "$abidir/$flavour"; + print " $prev_abidir/$flavour\n" if not -f "$prev_abidir/$flavour"; + # Always fail here. This is bad + exit(1); +} + +my %symbols; +my %symbols_ignore; +my %modules_ignore; +my %module_syms; + +# See if we have any ignores +my $ignore = 0; +print " Reading symbols/modules to ignore..."; + +for $file ("$prev_abidir/../blacklist", "$prev_abidir/../../perm-blacklist") { + if (-f $file) { + open(IGNORE, "< $file") or + die "Could not open $file"; + while () { + chomp; + if ($_ =~ m/M: (.*)/) { + $modules_ignore{$1} = 1; + } else { + $symbols_ignore{$_} = 1; + } + $ignore++; + } + close(IGNORE); + } +} +print "read $ignore symbols/modules.\n"; + +sub is_ignored($$) { + my ($mod, $sym) = @_; + + die "Missing module name in is_ignored()" if not defined($mod); + die "Missing symbol name in is_ignored()" if not defined($sym); + + if (defined($symbols_ignore{$sym}) or defined($modules_ignore{$mod})) { + return 1; + } + return 0; +} + +# Read new syms first +print " Reading new symbols ($abinum)..."; +$count = 0; +open(NEW, "< $abidir/$flavour") or + die "Could not open $abidir/$flavour"; +while () { + chomp; + m/^(EXPORT_.+)\s(.+)\s(0x[0-9a-f]+)\s(.+)$/; + $symbols{$4}{'type'} = $1; + $symbols{$4}{'loc'} = $2; + $symbols{$4}{'hash'} = $3; + $module_syms{$2} = 0; + $count++; +} +close(NEW); +print "read $count symbols.\n"; + +# Now the old symbols, checking for missing ones +print " Reading old symbols ($prev_abinum)..."; +$count = 0; +open(OLD, "< $prev_abidir/$flavour") or + die "Could not open $prev_abidir/$flavour"; +while () { + chomp; + m/^(EXPORT_.+)\s(.+)\s(0x[0-9a-f]+)\s(.+)$/; + $symbols{$4}{'old_type'} = $1; + $symbols{$4}{'old_loc'} = $2; + $symbols{$4}{'old_hash'} = $3; + $count++; +} +close(OLD); + +print "read $count symbols.\n"; + +print "II: Checking for missing symbols in new ABI..."; +$count = 0; +foreach $sym (keys(%symbols)) { + if (!defined($symbols{$sym}{'type'})) { + print "\n" if not $count; + printf(" MISS : %s%s\n", $sym, + is_ignored($symbols{$sym}{'old_loc'}, $sym) ? " (ignored)" : ""); + $count++ if !is_ignored($symbols{$sym}{'old_loc'}, $sym); + } +} +print " " if $count; +print "found $count missing symbols\n"; +if ($count) { + print "$EE Symbols gone missing (what did you do!?!)\n"; + $errors++; +} + + +print "II: Checking for new symbols in new ABI..."; +$count = 0; +foreach $sym (keys(%symbols)) { + if (!defined($symbols{$sym}{'old_type'})) { + print "\n" if not $count; + print " NEW : $sym\n"; + $count++; + } +} +print " " if $count; +print "found $count new symbols\n"; +if ($count and $prev_abinum == $abinum) { + print "WW: Found new symbols within same ABI. Not recommended\n"; +} + +print "II: Checking for changes to ABI...\n"; +$count = 0; +my $moved = 0; +my $changed_type = 0; +my $changed_hash = 0; +foreach $sym (keys(%symbols)) { + if (!defined($symbols{$sym}{'old_type'}) or + !defined($symbols{$sym}{'type'})) { + next; + } + + # Changes in location don't hurt us, but log it anyway + if ($symbols{$sym}{'loc'} ne $symbols{$sym}{'old_loc'}) { + printf(" MOVE : %-40s : %s => %s\n", $sym, $symbols{$sym}{'old_loc'}, + $symbols{$sym}{'loc'}); + $moved++; + } + + # Changes to export type are only bad if new type isn't + # EXPORT_SYMBOL. Changing things to GPL are bad. + if ($symbols{$sym}{'type'} ne $symbols{$sym}{'old_type'}) { + printf(" TYPE : %-40s : %s => %s%s\n", $sym, $symbols{$sym}{'old_type'}. + $symbols{$sym}{'type'}, is_ignored($symbols{$sym}{'loc'}, $sym) + ? " (ignored)" : ""); + $changed_type++ if $symbols{$sym}{'type'} ne "EXPORT_SYMBOL" + and !is_ignored($symbols{$sym}{'loc'}, $sym); + } + + # Changes to the hash are always bad + if ($symbols{$sym}{'hash'} ne $symbols{$sym}{'old_hash'}) { + printf(" HASH : %-40s : %s => %s%s\n", $sym, $symbols{$sym}{'old_hash'}, + $symbols{$sym}{'hash'}, is_ignored($symbols{$sym}{'loc'}, $sym) + ? " (ignored)" : ""); + $changed_hash++ if !is_ignored($symbols{$sym}{'loc'}, $sym); + $module_syms{$symbols{$sym}{'loc'}}++; + } +} + +print "WW: $moved symbols changed location\n" if $moved; +print "$EE $changed_type symbols changed export type and weren't ignored\n" if $changed_type; +print "$EE $changed_hash symbols changed hash and weren't ignored\n" if $changed_hash; + +$errors++ if $changed_hash or $changed_type; +if ($changed_hash) { + print "II: Module hash change summary...\n"; + foreach $mod (sort { $module_syms{$b} <=> $module_syms{$a} } keys %module_syms) { + next if ! $module_syms{$mod}; + printf(" %-40s: %d\n", $mod, $module_syms{$mod}); + } +} + +print "II: Done\n"; + +if ($errors) { + exit($fail_exit); +} else { + exit(0); +} --- linux-2.6.27.orig/debian/scripts/control-create +++ linux-2.6.27/debian/scripts/control-create @@ -0,0 +1,23 @@ +#!/bin/bash + +vars=$1 + +. $vars + +if [ "$is_sub" = "" ]; then + flavour=$(basename $vars | sed 's/.*\.//') + stub=debian/control.d/flavour-control.stub +else + flavour=$(basename $vars .vars) + stub=debian/sub-flavours/control.stub +fi + +cat $stub | grep -v '^#' | sed \ + -e "s#FLAVOUR#$flavour#g" \ + -e "s#DESC#$desc#g" \ + -e "s#ARCH#$arch#g" \ + -e "s#SUPPORTED#$supported#g" \ + -e "s#TARGET#$target#g" \ + -e "s#BOOTLOADER#$bootloader#g" \ + -e "s#=PROVIDES=#$provides#g" \ + -e "s#=CONFLICTS=#$conflicts#g" --- linux-2.6.27.orig/debian/scripts/module-check +++ linux-2.6.27/debian/scripts/module-check @@ -0,0 +1,119 @@ +#!/usr/bin/perl -w + +$flavour = shift; +$prev_abidir = shift; +$abidir = shift; +$skipmodule = shift; + +print "II: Checking modules for $flavour..."; + +if (-f "$prev_abidir/ignore.modules" + or -f "$prev_abidir/$flavour.ignore.modules") { + print "explicitly ignoring modules\n"; + exit(0); +} + +if (not -f "$abidir/$flavour.modules" or not -f + "$prev_abidir/$flavour.modules") { + print "previous or current modules file missing!\n"; + print " $abidir/$flavour.modules\n"; + print " $prev_abidir/$flavour.modules\n"; + if (defined($skipmodule)) { + exit(0); + } else { + exit(1); + } +} + +print "\n"; + +my %modules; +my %modules_ignore; +my $missing = 0; +my $new = 0; +my $errors = 0; + +# See if we have any ignores +if (-f "$prev_abidir/../modules.ignore") { + my $ignore = 0; + open(IGNORE, "< $prev_abidir/../modules.ignore") or + die "Could not open $prev_abidir/../modules.ignore"; + print " reading modules to ignore..."; + while () { + chomp; + $modules_ignore{$_} = 1; + $ignore++; + } + close(IGNORE); + print "read $ignore modules.\n"; +} + +# Read new modules first +print " reading new modules..."; +$new_count = 0; +open(NEW, "< $abidir/$flavour.modules") or + die "Could not open $abidir/$flavour.modules"; +while () { + chomp; + $modules{$_} = 1; + $new_count++; +} +close(NEW); +print "read $new_count modules.\n"; + +# Now the old modules, checking for missing ones +print " reading old modules..."; +$old_count = 0; +open(OLD, "< $prev_abidir/$flavour.modules") or + die "Could not open $prev_abidir/$flavour.modules"; +while () { + chomp; + if (not defined($modules{$_})) { + print "\n" if not $missing; + $missing++; + if (not defined($modules_ignore{$_})) { + print " MISS: $_\n"; + $errors++; + } else { + print " MISS: $_ (ignored)\n"; + } + } else { + $modules{$_}++; + } + $old_count++; +} +close(OLD); +# Check for new modules +foreach $mod (keys(%modules)) { + if ($modules{$mod} < 2) { + print "\n" if not $missing and not $new; + print " NEW : $mod\n"; + $new++; + } +} +if ($new or $missing) { + print " read $old_count modules : new($new) missing($missing)\n"; +} else { + print "read $old_count modules.\n"; +} + + +# Let's see where we stand... +if ($errors) { + if (defined($skipmodule)) { + print "WW: Explicitly asked to ignore failures (probably not good)\n"; + } else { + print "EE: Missing modules (start begging for mercy)\n"; + exit 1 + } +} + +if ($new) { + print "II: New modules (you've been busy, wipe the poop off your nose)\n"; +} else { + print "II: No new modules (hope you're happy, slacker)\n"; +} + +print "II: Done\n"; + +exit(0); --- linux-2.6.27.orig/debian/scripts/sub-flavour +++ linux-2.6.27/debian/scripts/sub-flavour @@ -0,0 +1,30 @@ +#!/bin/bash -e + + + +echo "SUB_PROCESS $FROM => $TO" + +export from_pkg="linux-image-$ABI_RELEASE-$FROM" +export to_pkg="linux-image-$ABI_RELEASE-$TO" + +from_moddir="debian/$from_pkg/lib/modules/$ABI_RELEASE-$FROM" +to_moddir="debian/$to_pkg/lib/modules/$ABI_RELEASE-$FROM" + +install -d "debian/$to_pkg/boot" +install -m644 debian/$from_pkg/boot/{vmlinuz,System.map}-$ABI_RELEASE-$FROM \ + debian/$to_pkg/boot/ + +cat debian/sub-flavours/$TO.list | while read line; do + (cd debian/$from_pkg/lib/modules/$ABI_RELEASE-$FROM/kernel; + eval find $line -name '*.ko'); +done | while read mod; do + echo "SUB_INST $mod" + grep "^/lib/modules/$ABI_RELEASE-$FROM/kernel/$mod:" \ + $from_moddir/modules.dep | sed -e 's/://' -e 's/ /\n/g' | \ + while read m; do + test -f debian/$to_pkg/$m && continue + echo "SUB_INST $mod" + install -D -m644 debian/$from_pkg/$m \ + debian/$to_pkg/$m + done +done --- linux-2.6.27.orig/debian/scripts/link-headers +++ linux-2.6.27/debian/scripts/link-headers @@ -0,0 +1,40 @@ +#!/bin/bash -e + +hdrdir="$1" +symdir="$2" +flavour="$3" + +echo "Symlinking and copying headers for $flavour..." + +excludes='( -path ./debian -prune -o -path ./.git ) -prune -o' + +( +find . $excludes -type f \ + \( -name 'Makefile*' -o -name 'Kconfig*' -o -name 'Kbuild*' -o \ + -name '*.sh' -o -name '*.pl' -o -name '*.lds' \) -print +find ./include ./scripts -name .gitignore -prune -o -type f -print +find ./include -mindepth 1 -maxdepth 1 $excludes -type d -print +) | ( +while read file; do + dir=$file + lastdir=$file + + if [ -f "$hdrdir/$file" ]; then + continue + fi + + while [ ! -e "$hdrdir/$dir" -a ! -L "$hdrdir/$dir" ]; do + lastdir=$dir + dir=`dirname $dir` + done + # If the last item to exist is a symlink we assume all is good + if [ ! -L "$hdrdir/$dir" ]; then + # Turns things like "./foo" into "../" + deref="`echo -n $lastdir | sed -e 's/^\.//' -e's,/[^/]*,../,g'`" + item="`echo -n $lastdir | sed -e 's/^\.\///'`" + ln -s $deref$symdir/$item $hdrdir/$item + fi +done +) + +exit --- linux-2.6.27.orig/debian/scripts/misc/prepare-ppa-source +++ linux-2.6.27/debian/scripts/misc/prepare-ppa-source @@ -0,0 +1,106 @@ +#!/bin/sh +# +# This script prepares a source upload for a PPA build. +# +LAST_UPLOAD=../last-ppa-upload +LAST_GIT_CHANGELOG=../last_git_changelog +LAST_PPA_CHANGELOG=../last_ppa_changelog +PPA_FILE="`make --no-print-directory -f debian/rules print-ppa-file-name`" + +if [ "$1" = "scrub" ] +then + SCRUB=1 +fi + +# +# The identity of the git committer must be known. +# +if [ ! -z "$GIT_AUTHOR_NAME" ] && [ ! -z "$GIT_AUTHOR_EMAIL" ] +then + SIGNER_NAME="$GIT_AUTHOR_NAME" + SIGNER_EMAIL="$GIT_AUTHOR_EMAIL" +elif [ ! -z "$GIT_COMMITTER_NAME" ] && [ ! -z "$GIT_COMMITTER_EMAIL" ] +then + SIGNER_NAME="$GIT_COMMITTER_NAME" + SIGNER_EMAIL="$GIT_COMMITTER_EMAIL" +else + echo Error: Unknown committer. + exit 1 +fi + +# +# git current and cleanup. +# +git checkout -f +git ls-files --others | xargs rm -rf + +# +# Don't bother if the repo hasn't changed since the last upload. +# +if [ ! -f ${LAST_UPLOAD} ] +then + touch ${LAST_UPLOAD} +fi +git log|head -n 1|sed 's/commit //' > ${LAST_UPLOAD}.tmp +if cmp ${LAST_UPLOAD} ${LAST_UPLOAD}.tmp > /dev/null +then + rm -f ${LAST_UPLOAD}.tmp + echo No upload needed. + exit 0 +fi +mv ${LAST_UPLOAD}.tmp ${LAST_UPLOAD} + +# +# The git HEAD can change without anyone updating the debian/changelog. +# However, if the changelog version is updated, then we want to work +# forward from that version. +# +cp debian/changelog changelog.sav +if [ -f ${LAST_GIT_CHANGELOG} ] && [ -f ${LAST_PPA_CHANGELOG} ] +then + # + # If the changelog has not changed, then work forward from the + # last daily build version. + # + if cmp ${LAST_GIT_CHANGELOG} debian/changelog > /dev/null + then + cp ${LAST_PPA_CHANGELOG} debian/changelog + fi +fi +mv changelog.sav ${LAST_GIT_CHANGELOG} + +# +# Notify the build scripts that this is a PPA build. +# +cp -v ${LAST_UPLOAD} ${PPA_FILE} + +# +# In order to sign the package you must override the first signer's changelog entry. +# +export DEBEMAIL="$SIGNER_EMAIL" +export DEBFULLNAME="$SIGNER_NAME" +DEBCHANGE_COMMENT="PPA Upload from git HEAD `cat ${LAST_UPLOAD}`" +debchange --increment --preserve "${DEBCHANGE_COMMENT}" +if ! head -n 1 debian/changelog | grep ubuntu > /dev/null +then + echo debchange did not work. + exit 1 +fi + +# +# Make sure the third changelog field says hardy. +# +sed -i 's/) .*;/) hardy;/1' debian/changelog + +# +# Make sure the next daily build works forward from this version if the git +# changelog has not changed. +# +cp debian/changelog ${LAST_PPA_CHANGELOG} + +rm -rf ../linux* include/config .config +dpkg-buildpackage -S -sa -rfakeroot -I.git -I.gitignore -i'\.git.*' + +rm -f ${PPA_FILE} +exit 0 + --- linux-2.6.27.orig/debian/scripts/misc/git-ubuntu-log +++ linux-2.6.27/debian/scripts/misc/git-ubuntu-log @@ -0,0 +1,243 @@ +#!/usr/bin/perl -w + +use strict; +use Text::Wrap; + +my $kernel_auth = "Upstream Kernel Changes"; + +my (%map, @reverts); +my $pstate = 1; +my $no_kern_log = 0; +my $print_shas = 0; +my $first_print = 1; + +while (@ARGV) { + my $opt = $ARGV[0]; + shift; + if ($opt eq "--no-kern-log") { + $no_kern_log = 1; + } elsif ($opt eq "--print-shas") { + $print_shas = 1; + } else { + print STDERR "Unknown options: $opt\n"; + exit(1); + } +} + +sub check_reverts($) { + my ($entry) = @_; + my ($check); + + foreach $check (reverse @reverts) { + my $desc = "Revert \"" . $entry->{'desc'} . "\""; + if ($check->{'desc'} eq $desc) { + @reverts = grep($_->{'desc'} ne $desc, @reverts); + return 1; + } + } + + return 0; +} + +sub add_entry($) { + my ($entry) = @_; + my $key = $entry->{'author'}; + + # store description in array, in email->{desc list} map + if (exists $map{$key}) { + # grab ref + my $obj = $map{$key}; + + # add desc to array + push(@$obj, $entry); + } else { + # create new array, containing 1 item + my @arr = ($entry); + + # store ref to array + $map{$key} = \@arr; + } +} + +sub shortlog_entry($$$$$) { + my ($name, $desc, $bug, $cve, $commit) = @_; + my $entry; + + $desc =~ s#/pub/scm/linux/kernel/git/#/.../#g; + $desc =~ s#\[PATCH\] ##g; + + $desc =~ s#^\s*##g; + $desc =~ s# *UBUNTU: ##g; + + $entry->{'desc'} = $desc; + if ($bug ne '') { + $entry->{'bugno'} = $bug; + } + $entry->{'cve'} = $cve; + $entry->{'commit'} = $commit; + $entry->{'author'} = $name; + + if ($desc =~ /^Revert "/) { + push(@reverts, $entry); + return; + } + + return if check_reverts($entry); + + add_entry($entry); +} + +# sort comparison function +sub by_name($$) { + my ($a, $b) = @_; + + uc($a) cmp uc($b); +} + +sub shortlog_output { + my ($obj, $key, $entry); + + foreach $key (sort by_name keys %map) { + next if $key eq $kernel_auth and $no_kern_log; + + print "\n" unless $first_print; + $first_print = 0; + + # output author + printf " [ %s ]\n\n", $key; + + # output author's 1-line summaries + $obj = $map{$key}; + foreach $entry (reverse @$obj) { + print wrap(" * ", " ", $entry->{'desc'}) . "\n"; + # For non upstream changes, add other info. + if ($key ne $kernel_auth) { + if ($print_shas) { + print " - GIT-SHA " . $entry->{'commit'} . + "\n"; + } + } + if (defined($entry->{'bugno'})) { + print " - LP: #" . $entry->{'bugno'} . "\n"; + } + if (defined($entry->{'cve'})) { + print " - " . $entry->{'cve'} . "\n"; + } + } + } +} + +sub changelog_input { + my ($author, $desc, $commit, $entry, $cve); + + while () { + # get commit + if ($pstate == 1) { + next unless /^commit (.*)/; + + $commit = $1; + + $pstate++; + } + + # get author and email + elsif ($pstate == 2) { + my ($email); + + next unless /^[Aa]uthor:?\s*(.*?)\s*<(.*)>/; + + $author = $1; + $email = $2; + $desc = undef; + $cve = undef; + + # cset author fixups + if (!$author) { + $author = $email; + } + $pstate++; + } + + # skip to blank line + elsif ($pstate == 3) { + next unless /^\s*$/; + $pstate++; + } + + # skip to non-blank line + elsif ($pstate == 4) { + next unless /^\s*?(.*)/; + my $ignore = 0; + my $bug = undef; + my %bugz = (); + my $k; + + # skip lines that are obviously not + # a 1-line cset description + next if /^\s*From: /; + + chomp; + $desc = $1; + + if ($desc =~ /^ *(Revert "|)UBUNTU:/) { + while () { + $ignore = 1 if /^ *Ignore: yes/i; + if (/^ *Bug: *(#|)(.*)/i) { + foreach $k (split('(,|)*\s*#', $2)) { + $bugz{$k} = 1 if (($k ne '') and ($k =~ /[0-9]+/)); + } + } + elsif (/^ *BugLink: *http.*:\/\/.*\/([0-9]+)/i) { + $bugz{$1} = 1; + } + elsif (/^ *(CVE-.*)/) { + $cve = $1 + } + last if /^commit /; + } + } else { + $author = $kernel_auth; + $ignore = 1 if $desc =~ /Merge /; + while () { + if (/^ *Bug: *(#|)(.*)/i) { + foreach $k (split('(,|)*\s*#', $2)) { + $bugz{$k} = 1 if (($k ne '') and ($k =~ /[0-9]+/)); + } + } + elsif (/^ *BugLink: *http.*:\/\/.*\/([0-9]+)/i) { + $bugz{$1} = 1; + } + elsif (/^ *(CVE-.*)/) { + $cve = $1 + } + last if /^commit /; + } + } + + $bug = join(", #", keys(%bugz)); + if (!$ignore) { + &shortlog_entry($author, $desc, $bug, + $cve, $commit, 0); + } + + $pstate = 1; + if ($_ && /^commit (.*)/) { + $commit = $1; + $pstate++; + } + } + + else { + die "invalid parse state $pstate"; + } + } + + foreach $entry (@reverts) { + add_entry($entry); + } +} + +&changelog_input; +&shortlog_output; + +exit(0); --- linux-2.6.27.orig/debian/scripts/misc/oldconfig +++ linux-2.6.27/debian/scripts/misc/oldconfig @@ -0,0 +1,63 @@ +#!/bin/bash + +# We have to be in the top level kernel source directory +if [ ! -f MAINTAINERS ] || [ ! -f Makefile ]; then + echo "This does not appear to be the kernel source directory." 1>&2 + exit 1 +fi + + +# One arg, and that's it. Just pass an architecture +if [ $# -ne 1 ]; then + echo "Usage: $0 " 1>&2 + exit 1 +fi + +arch="$1" + +case "$arch" in + amd64) kernarch="x86_64" ;; + *) kernarch="$arch" ;; +esac + +confdir="`pwd`/debian/config/$arch" +bindir="`pwd`/debian/scripts/misc" + +# Make sure the architecture exists +if [ ! -d $confdir ]; then + echo "Could not find config directory for $arch" 1>&2 + exit 1 +fi + +echo "Processing $arch ($kernarch) ... " + +configs=$(cd $confdir && ls config.*) + +if [ -f $confdir/config ]; then + for config in $configs; do + case $config in + *) + cat $confdir/config >> $confdir/$config + ;; + esac + done + rm -f $confdir/config +fi + +test -d build || mkdir build +cd build +for config in $configs; do + echo "Running silentoldconfig for $config ... " + + cat $confdir/$config > .config + + make -C ../ O=`pwd` silentoldconfig ARCH=$kernarch + + cat .config > $confdir/$config +done +cd .. + +echo "Running splitconfig.pl ... " +echo + +(cd $confdir ; $bindir/splitconfig.pl) --- linux-2.6.27.orig/debian/scripts/misc/splitconfig.pl +++ linux-2.6.27/debian/scripts/misc/splitconfig.pl @@ -0,0 +1,110 @@ +#!/usr/bin/perl -w + +%configs = (); +%common = (); + +print "Reading config's ...\n"; + +opendir(DIR, "."); + +while (defined($config = readdir(DIR))) { + # Only config.* + next if $config !~ /^config\..*/; + # Nothing that is disabled, or remnant + next if $config =~ /.*\.(default|disabled|stub)$/; + # Server config's are standalone + #next if $config =~ /config.server-.*/; + + %{$configs{$config}} = (); + + print " processing $config ... "; + + open(CONFIG, "< $config"); + + while () { + /^#*\s*CONFIG_(\w+)[\s=](.*)$/ or next; + + ${$configs{$config}}{$1} = $2; + + $common{$1} = $2; + } + + close(CONFIG); + + print "done.\n"; +} + +closedir(DIR); + +print "\n"; + +print "Merging lists ... \n"; + +for $config (keys(%configs)) { + my %options = %{$configs{$config}}; + + print " processing $config ... "; + + for $key (keys(%common)) { + next if not defined $common{$key}; + + # If we don't have the common option, then it isn't + # common. If we do have that option, it must have the same + # value (this is where the old split.py was broken). It + # also did the common check while it was parsing files, so + # that there were cases where a non-common option was in + # common anyway (ordering). + if (not defined($options{$key})) { + undef $common{$key}; + } elsif ($common{$key} ne $options{$key}) { + undef $common{$key}; + } + } + + print "done.\n"; +} + +print "\n"; + +print "Creating common config ... "; + +open(COMMON, "> config"); +print COMMON "#\n# Common config options automatically generated by splitconfig.pl\n#\n"; + +for $key (sort(keys(%common))) { + next if not defined $common{$key}; + + if ($common{$key} eq "is not set") { + print COMMON "# CONFIG_$key is not set\n"; + } else { + print COMMON "CONFIG_$key=$common{$key}\n"; + } +} +close(COMMON); + +print "done.\n\n"; + +print "Creating stub configs ...\n"; + +for $config (keys(%configs)) { + my %options = %{$configs{$config}}; + + print " processing $config ... "; + + open(STUB, "> $config"); + print STUB "#\n# Config options for $config automatically generated by splitconfig.pl\n#\n"; + + for $key (sort(keys(%options))) { + next if defined $common{$key}; + + if ($options{$key} eq "is not set") { + print STUB "# CONFIG_$key is not set\n"; + } else { + print STUB "CONFIG_$key=$options{$key}\n"; + } + } + + close(STUB); + + print "done.\n"; +} --- linux-2.6.27.orig/debian/scripts/misc/doconfig +++ linux-2.6.27/debian/scripts/misc/doconfig @@ -0,0 +1,64 @@ +#!/bin/bash + +# We have to be in the top level kernel source directory +if [ ! -f MAINTAINERS ] || [ ! -f Makefile ]; then + echo "This does not appear to be the kernel source directory." 1>&2 + exit 1 +fi + + +# One arg, and that's it. Just pass an architecture +if [ $# -ne 1 ]; then + echo "Usage: $0 " 1>&2 + exit 1 +fi + +arch="$1" + +case "$arch" in + amd64) kernarch="x86_64" ;; + *) kernarch="$arch" ;; +esac + +confdir="`pwd`/debian/config/$arch" +bindir="`pwd`/debian/scripts/misc" + +# Make sure the architecture exists +if [ ! -d $confdir ]; then + echo "Could not find config directory for $arch" 1>&2 + exit 1 +fi + +echo "Processing $arch ($kernarch) ... " + +configs=$(cd $confdir && ls config.*) + +if [ -f $confdir/config ]; then + for config in $configs; do + case $config in + *) + cat $confdir/config >> $confdir/$config + ;; + esac + done + rm -f $confdir/config +fi + +test -d build || mkdir build +cd build +for config in $configs; do + + cat $confdir/$config > .config + + echo About to configure $arch $config + read + make -C ../ O=`pwd` ARCH=$kernarch menuconfig + + cat .config > $confdir/$config +done +cd .. + +echo "Running splitconfig.pl ... " +echo + +(cd $confdir ; $bindir/splitconfig.pl) --- linux-2.6.27.orig/debian/scripts/misc/ppa-cron-job +++ linux-2.6.27/debian/scripts/misc/ppa-cron-job @@ -0,0 +1,47 @@ +#!/bin/sh + +# +# Use this script as a template for the daily kernel build cron job. +# You should copy it somewhere outside of the git tree 'cause the whole +# git tree gets removed and recreated. +# +KNAME=intrepid +DAILY_BUILD_DIR=${KBDIR:=${HOME}/${KNAME}} +KERNEL_GIT_REPO=${KREPO:=/srv/kernel.ubuntu.com/git/ubuntu/ubuntu-${KNAME}.git} + +# +# Nothing works unless there is a dput configuration. +# +if [ ! -f ${HOME}/.dput.cf ] +then + echo No dput configuration. + exit 1 +fi + +if [ ! -d ${DAILY_BUILD_DIR} ] +then + rm -rf ${DAILY_BUILD_DIR} + mkdir -p ${DAILY_BUILD_DIR} +fi + +# +# Start with a fresh repo. +# +cd ${DAILY_BUILD_DIR} +rm -rf ubuntu-${KNAME} +git clone ${KERNEL_GIT_REPO} + +# +# Remember that the success of prepare-ppa depends on +# this user account having an un-passworded GPG key. +# Otherwise it requires user intervention, e.g., a +# user must enter the GPG key password. +# +rm -f *.changes +(cd ubuntu-${KNAME}; debian/scripts/misc/prepare-ppa-source) + +find . -maxdepth 1 -type f -name "*.changes" | while read f +do + echo dput my-ppa $f +done + --- linux-2.6.27.orig/debian/scripts/misc/insert-changes.pl +++ linux-2.6.27/debian/scripts/misc/insert-changes.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl -w + +system("make -s -f debian/rules printchanges > debian/changes"); + +open(CHANGELOG, "< debian/changelog") or die "Cannot open changelog"; +open(CHANGES, "< debian/changes") or die "Cannot open new changes"; +open(NEW, "> debian/changelog.new") or die "Cannot open new changelog"; + +$printed = 0; + +while () { + if (/^ CHANGELOG: /) { + next if $printed; + + while () { + print NEW; + } + + $printed = 1; + } else { + print NEW; + } +} + +close(NEW); +close(CHANGES); +close(CHANGELOG); + +rename("debian/changelog.new", "debian/changelog"); +unlink("debian/changes"); --- linux-2.6.27.orig/debian/scripts/misc/getabis +++ linux-2.6.27/debian/scripts/misc/getabis @@ -0,0 +1,82 @@ +#!/bin/bash + +if [ "$#" != "2" ]; then + echo "Usage: $0 " 1>&2 + exit 1 +fi + +ver=$1 +revision=$2 +abi=$(echo $revision | awk -F. '{print $1}') + +verabi=$ver-$abi +verfull=$ver-$revision + +repo="http://archive.ubuntu.com/ubuntu/pool/main/l" +repo_ports="http://ports.ubuntu.com/ubuntu-ports/pool/main/l" +repo_uni="http://archive.ubuntu.com/ubuntu/pool/universe/l" + +WGET="wget --quiet -c" + +abidir="`pwd`/debian/abi/$verfull" +tmpdir="`pwd`/abi-tmp-$verfull" +origdir="`pwd`" + +test -d $tmpdir || mkdir $tmpdir + +getall() { + arch=$1 + shift + + mkdir -p $abidir/$arch + + for sub in $@; do + if [ -f $abidir/$arch/$sub ]; then + echo "Exists: $sub" + continue + fi + echo -n "Fetching $sub..." + filename=linux-image-${verabi}-${sub}_${verfull}_${arch}.deb + cd $tmpdir + if ! [ -f $filename ]; then + $WGET $repo/linux/$filename + fi + if ! [ -f $filename ]; then + $WGET $repo_ports/linux/$filename + fi + if ! [ -f $filename ]; then + $WGET $repo_uni/linux/$filename + fi + if [ "$?" = "0" ]; then + echo -n "extracting..." + dpkg-deb --extract $filename tmp + if [ -f tmp/boot/abi-* ]; then + mv tmp/boot/abi-* $abidir/$arch/$sub + else + echo -n "NO ABI FILE..." + fi + (cd tmp; find lib/modules/$verabi-$sub/kernel -name '*.ko') | \ + sed -e 's/.*\/\([^\/]*\)\.ko/\1/' | sort > \ + $abidir/$arch/$sub.modules + rm -rf tmp $filename + echo "done." + else + echo "FAILED." + fi + cd $origdir + done +} + +# MAIN + +# Setup abi directory +mkdir -p $abidir +echo $abi > $abidir/abiname + +# NOTE: The flavours are hardcoded, because they may have changed from the +# current build. + +getall amd64 generic server +getall i386 generic server + +rmdir $tmpdir --- linux-2.6.27.orig/debian/scripts/misc/retag +++ linux-2.6.27/debian/scripts/misc/retag @@ -0,0 +1,34 @@ +#!/usr/bin/perl -w + +open(TAGS, "git-tag -l |") or die "Could not get list of tags"; +@tags = ; +close(TAGS); + +open(LOGS, "git-log --pretty=short |") or die "ERROR: Calling git-log"; +my $commit = ""; + +while () { + my $origtag; + + if (m|^commit (.*)$|) { + $commit = $1; + next; + } + + m|\s*UBUNTU: (Ubuntu-2\.6\..*)| or next; + + $tag = $1; + + ($origtag) = grep(/^$tag.orig$/, @tags); + + if (!defined($origtag)) { + print "I: Adding original tag for $tag\n"; + system("git-tag -m $tag $tag.orig $tag"); + } + + print "I: Tagging $tag => $commit\n"; + + system("git-tag -f -m $tag $tag $commit"); +} + +close(LOGS); --- linux-2.6.27.orig/debian/config/i386/config.generic +++ linux-2.6.27/debian/config/i386/config.generic @@ -0,0 +1,26 @@ +# +# Config options for config.generic automatically generated by splitconfig.pl +# +CONFIG_DCA=m +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_DMADEVICES=y +# CONFIG_DMATEST is not set +CONFIG_DMA_ENGINE=y +CONFIG_HIGHMEM4G=y +# CONFIG_HIGHMEM64G is not set +CONFIG_HZ=250 +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +CONFIG_INTEL_IOATDMA=m +# CONFIG_LGUEST is not set +# CONFIG_LGUEST_GUEST is not set +CONFIG_M586=y +# CONFIG_M686 is not set +CONFIG_NET_DMA=y +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y +# CONFIG_RESOURCES_64BIT is not set +CONFIG_X86_ALIGNMENT_16=y +CONFIG_X86_F00F_BUG=y --- linux-2.6.27.orig/debian/config/i386/config.server +++ linux-2.6.27/debian/config/i386/config.server @@ -0,0 +1,33 @@ +# +# Config options for config.server automatically generated by splitconfig.pl +# +# CONFIG_DEFAULT_CFQ is not set +CONFIG_DEFAULT_DEADLINE=y +CONFIG_DEFAULT_IOSCHED="deadline" +# CONFIG_HIGHMEM4G is not set +CONFIG_HIGHMEM64G=y +CONFIG_HVC_IRQ=y +CONFIG_HVC_XEN=y +CONFIG_HZ=100 +CONFIG_HZ_100=y +# CONFIG_HZ_250 is not set +CONFIG_I2O_EXT_ADAPTEC_DMA64=y +# CONFIG_M586 is not set +CONFIG_M686=y +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_RESOURCES_64BIT=y +CONFIG_X86_CMOV=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_DEBUGCTLMSR=y +CONFIG_X86_PAE=y +CONFIG_X86_TSC=y +CONFIG_X86_USE_PPRO_CHECKSUM=y +CONFIG_XEN=y +CONFIG_XEN_BALLOON=y +CONFIG_XEN_BLKDEV_FRONTEND=m +CONFIG_XEN_FBDEV_FRONTEND=m +CONFIG_XEN_KBDDEV_FRONTEND=m +CONFIG_XEN_MAX_DOMAIN_MEMORY=8 +CONFIG_XEN_NETDEV_FRONTEND=m +CONFIG_XEN_SCRUB_PAGES=y --- linux-2.6.27.orig/debian/config/i386/config +++ linux-2.6.27/debian/config/i386/config @@ -0,0 +1,3720 @@ +# +# Common config options automatically generated by splitconfig.pl +# +CONFIG_3C359=m +CONFIG_3C515=m +# CONFIG_4KSTACKS is not set +CONFIG_60XX_WDT=m +# CONFIG_64BIT is not set +CONFIG_6PACK=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_8129=y +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_9P_FS=m +CONFIG_ABYSS=m +CONFIG_AC3200=m +CONFIG_AC97_BUS=m +# CONFIG_ACCESSIBILITY is not set +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_ACER_WMI=m +CONFIG_ACORN_PARTITION=y +# CONFIG_ACORN_PARTITION_ADFS is not set +# CONFIG_ACORN_PARTITION_CUMANA is not set +# CONFIG_ACORN_PARTITION_EESOX is not set +CONFIG_ACORN_PARTITION_ICS=y +# CONFIG_ACORN_PARTITION_POWERTEC is not set +CONFIG_ACORN_PARTITION_RISCIX=y +CONFIG_ACPI=y +CONFIG_ACPI_AC=m +# CONFIG_ACPI_ASUS is not set +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BAY=m +CONFIG_ACPI_BLACKLIST_YEAR=2000 +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_CONTAINER=m +# CONFIG_ACPI_CUSTOM_DSDT is not set +CONFIG_ACPI_CUSTOM_DSDT_FILE="" +CONFIG_ACPI_CUSTOM_DSDT_INITRD=y +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_DOCK=m +CONFIG_ACPI_EC=y +CONFIG_ACPI_FAN=m +CONFIG_ACPI_HOTPLUG_CPU=y +CONFIG_ACPI_PCI_SLOT=m +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PROCESSOR=m +CONFIG_ACPI_PROCFS=y +CONFIG_ACPI_PROCFS_POWER=y +CONFIG_ACPI_PROC_EVENT=y +CONFIG_ACPI_SBS=m +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_SYSFS_POWER=y +CONFIG_ACPI_SYSTEM=y +CONFIG_ACPI_THERMAL=m +CONFIG_ACPI_TOSHIBA=m +CONFIG_ACPI_VIDEO=m +CONFIG_ACPI_WMI=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ACT200L_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_ADAPTEC_STARFIRE=m +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set +CONFIG_ADM8211=m +CONFIG_ADVANTECH_WDT=m +CONFIG_AEDSP16_MSS=y +# CONFIG_AEDSP16_SBPRO is not set +CONFIG_AFFS_FS=m +# CONFIG_AFS_DEBUG is not set +CONFIG_AFS_FS=m +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +CONFIG_AGP=m +CONFIG_AGP_ALI=m +CONFIG_AGP_AMD=m +CONFIG_AGP_AMD64=m +CONFIG_AGP_ATI=m +CONFIG_AGP_EFFICEON=m +CONFIG_AGP_INTEL=m +CONFIG_AGP_NVIDIA=m +CONFIG_AGP_SIS=m +CONFIG_AGP_SWORKS=m +CONFIG_AGP_VIA=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_DEBUG_ENABLE=y +CONFIG_AIC79XX_DEBUG_MASK=0 +CONFIG_AIC79XX_REG_PRETTY_PRINT=y +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_DEBUG_ENABLE=y +CONFIG_AIC7XXX_DEBUG_MASK=0 +CONFIG_AIC7XXX_REG_PRETTY_PRINT=y +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC94XX_DEBUG is not set +CONFIG_AIRO=m +CONFIG_AIRO_CS=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_ALI_FIR=m +CONFIG_AMD8111_ETH=m +CONFIG_AMIGA_PARTITION=y +CONFIG_ANON_INODES=y +CONFIG_APM=m +# CONFIG_APM_ALLOW_INTS is not set +# CONFIG_APM_CPU_IDLE is not set +# CONFIG_APM_DISPLAY_BLANK is not set +# CONFIG_APM_DO_ENABLE is not set +# CONFIG_APM_IGNORE_USER_SUSPEND is not set +# CONFIG_APM_REAL_MODE_POWER_OFF is not set +CONFIG_APPLICOM=m +CONFIG_APRICOT=m +CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig" +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_DEFAULT_IDLE=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SUPPORTS_AOUT=y +CONFIG_ARCH_SUPPORTS_MSI=y +CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y +CONFIG_ARCNET=m +CONFIG_ARCNET_1051=m +CONFIG_ARCNET_1201=m +CONFIG_ARCNET_CAP=m +CONFIG_ARCNET_COM20020=m +CONFIG_ARCNET_COM20020_CS=m +CONFIG_ARCNET_COM20020_ISA=m +CONFIG_ARCNET_COM20020_PCI=m +CONFIG_ARCNET_COM90xx=m +CONFIG_ARCNET_COM90xxIO=m +CONFIG_ARCNET_RAW=m +CONFIG_ARCNET_RIM_I=m +CONFIG_ARLAN=m +# CONFIG_ARPD is not set +CONFIG_ASK_IP_FIB_HASH=y +CONFIG_ASUS_LAPTOP=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_AT1700=m +CONFIG_AT24=m +CONFIG_ATA=m +CONFIG_ATALK=m +CONFIG_ATARI_PARTITION=y +CONFIG_ATA_ACPI=y +CONFIG_ATA_GENERIC=m +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_ATA_OVER_ETH=m +CONFIG_ATA_PIIX=m +CONFIG_ATA_SFF=y +# CONFIG_ATH5K is not set +CONFIG_ATH9K=m +CONFIG_ATL1=m +CONFIG_ATL1E=m +CONFIG_ATL2=m +CONFIG_ATM=y +CONFIG_ATMEL=m +CONFIG_ATM_AMBASSADOR=m +# CONFIG_ATM_AMBASSADOR_DEBUG is not set +CONFIG_ATM_BR2684=m +# CONFIG_ATM_BR2684_IPFILTER is not set +CONFIG_ATM_CLIP=y +# CONFIG_ATM_CLIP_NO_ICMP is not set +CONFIG_ATM_DRIVERS=y +# CONFIG_ATM_DUMMY is not set +CONFIG_ATM_ENI=m +# CONFIG_ATM_ENI_DEBUG is not set +# CONFIG_ATM_ENI_TUNE_BURST is not set +CONFIG_ATM_FIRESTREAM=m +CONFIG_ATM_FORE200E=m +CONFIG_ATM_FORE200E_DEBUG=0 +CONFIG_ATM_FORE200E_TX_RETRY=16 +# CONFIG_ATM_FORE200E_USE_TASKLET is not set +CONFIG_ATM_HE=m +CONFIG_ATM_HE_USE_SUNI=y +CONFIG_ATM_HORIZON=m +# CONFIG_ATM_HORIZON_DEBUG is not set +CONFIG_ATM_IA=m +# CONFIG_ATM_IA_DEBUG is not set +CONFIG_ATM_IDT77252=m +# CONFIG_ATM_IDT77252_DEBUG is not set +# CONFIG_ATM_IDT77252_RCV_ALL is not set +CONFIG_ATM_IDT77252_USE_SUNI=y +CONFIG_ATM_LANAI=m +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_NICSTAR=m +# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set +# CONFIG_ATM_NICSTAR_USE_SUNI is not set +CONFIG_ATM_TCP=m +CONFIG_ATM_ZATM=m +# CONFIG_ATM_ZATM_DEBUG is not set +CONFIG_ATP=m +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +# CONFIG_AUDIT_ARCH is not set +CONFIG_AUDIT_GENERIC=y +CONFIG_AUDIT_TREE=y +CONFIG_AUFS=m +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +CONFIG_AUFS_BRANCH_MAX_127=y +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +# CONFIG_AUFS_BRANCH_MAX_511 is not set +CONFIG_AUFS_BR_NFS=y +CONFIG_AUFS_BR_XFS=y +# CONFIG_AUFS_COMPAT is not set +# CONFIG_AUFS_DEBUG is not set +CONFIG_AUFS_DENY_WRITE_ACCESS_PATCH=y +# CONFIG_AUFS_DLGT is not set +CONFIG_AUFS_EXPORT=y +# CONFIG_AUFS_FSYNC_SUPER_PATCH is not set +CONFIG_AUFS_HINOTIFY=y +CONFIG_AUFS_HIN_OR_DLGT=y +CONFIG_AUFS_HIN_OR_FUSE=y +CONFIG_AUFS_LHASH_PATCH=y +CONFIG_AUFS_PUT_FILP_PATCH=y +# CONFIG_AUFS_ROBR is not set +CONFIG_AUFS_RR_SQUASHFS=y +CONFIG_AUFS_SEC_PERM_PATCH=y +CONFIG_AUFS_SHWH=y +CONFIG_AUFS_SPLICE_PATCH=y +CONFIG_AUFS_STAT=y +# CONFIG_AUFS_UNIONFS22_PATCH is not set +# CONFIG_AUFS_UNIONFS23_PATCH is not set +# CONFIG_AUFS_WORKAROUND_FUSE is not set +CONFIG_AUTOFS4_FS=m +CONFIG_AUTOFS_FS=m +CONFIG_AUXDISPLAY=y +CONFIG_AVERATEC_5100P=m +CONFIG_AX25=m +CONFIG_AX25_DAMA_SLAVE=y +CONFIG_B43=m +CONFIG_B43LEGACY=m +CONFIG_B43LEGACY_DEBUG=y +CONFIG_B43LEGACY_DMA=y +CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y +# CONFIG_B43LEGACY_DMA_MODE is not set +CONFIG_B43LEGACY_LEDS=y +CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y +CONFIG_B43LEGACY_PCI_AUTOSELECT=y +CONFIG_B43LEGACY_PIO=y +# CONFIG_B43LEGACY_PIO_MODE is not set +CONFIG_B43LEGACY_RFKILL=y +# CONFIG_B43_DEBUG is not set +CONFIG_B43_LEDS=y +CONFIG_B43_PCICORE_AUTOSELECT=y +CONFIG_B43_PCI_AUTOSELECT=y +# CONFIG_B43_PCMCIA is not set +CONFIG_B43_RFKILL=y +CONFIG_B44=m +CONFIG_B44_PCI=y +CONFIG_B44_PCICORE_AUTOSELECT=y +CONFIG_B44_PCI_AUTOSELECT=y +CONFIG_BACKLIGHT_CARILLO_RANCH=m +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CORGI=m +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_MBP_NVIDIA=m +CONFIG_BACKLIGHT_PROGEAR=m +# CONFIG_BACKTRACE_SELF_TEST is not set +CONFIG_BASE_FULL=y +CONFIG_BASE_SMALL=0 +CONFIG_BATTERY_DS2760=m +CONFIG_BATTERY_OLPC=m +CONFIG_BAYCOM_EPP=m +CONFIG_BAYCOM_PAR=m +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BEFS_FS=m +CONFIG_BFS_FS=m +CONFIG_BINFMT_AOUT=m +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +CONFIG_BITREVERSE=y +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_DEV=y +CONFIG_BLK_DEV_3W_XXXX_RAID=m +# CONFIG_BLK_DEV_BSG is not set +CONFIG_BLK_DEV_COMPCACHE=m +# CONFIG_BLK_DEV_COMPCACHE_DEBUG is not set +# CONFIG_BLK_DEV_COMPCACHE_STATS is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_DM=m +CONFIG_BLK_DEV_DM_BBR=m +CONFIG_BLK_DEV_DRBD=m +CONFIG_BLK_DEV_FD=m +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_MD=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_BLK_DEV_SD=m +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_BLK_DEV_SX8=m +CONFIG_BLK_DEV_UB=m +CONFIG_BLK_DEV_UMEM=m +# CONFIG_BLK_DEV_XD is not set +# CONFIG_BLK_DEV_XIP is not set +CONFIG_BLOCK=y +CONFIG_BNX2=m +CONFIG_BNX2X=m +CONFIG_BONDING=m +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_BOUNCE=y +CONFIG_BPQETHER=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_IP6=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_NFLOG=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_NETFILTER=y +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BROADCOM_PHY=m +CONFIG_BSD_DISKLABEL=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_BT=m +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIBTUSB=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIVHCI=m +CONFIG_BT_HIDP=m +CONFIG_BT_L2CAP=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_SCO=m +CONFIG_BUG=y +CONFIG_C101=m +# CONFIG_CAN is not set +CONFIG_CAN_PM_TRACE=y +CONFIG_CAPI_AVM=y +CONFIG_CAPI_EICON=y +CONFIG_CAPI_TRACE=y +CONFIG_CARDBUS=y +CONFIG_CARDMAN_4000=m +CONFIG_CARDMAN_4040=m +# CONFIG_CARMINE_DRAM_CUSTOM is not set +CONFIG_CASSINI=m +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +CONFIG_CFAG12864B=m +CONFIG_CFAG12864B_RATE=20 +CONFIG_CFG80211=m +CONFIG_CGROUPS=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_DEBUG is not set +# CONFIG_CGROUP_DEVICE is not set +CONFIG_CGROUP_MEM_RES_CTLR=y +CONFIG_CGROUP_NS=y +CONFIG_CGROUP_SCHED=y +CONFIG_CHECK_SIGNATURE=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T3=m +CONFIG_CHR_DEV_OSST=m +CONFIG_CHR_DEV_SCH=m +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_ST=m +CONFIG_CICADA_PHY=m +CONFIG_CIFS=m +# CONFIG_CIFS_DEBUG2 is not set +CONFIG_CIFS_DFS_UPCALL=y +CONFIG_CIFS_EXPERIMENTAL=y +# CONFIG_CIFS_STATS is not set +CONFIG_CIFS_UPCALL=y +CONFIG_CIFS_WEAK_PW_HASH=y +# CONFIG_CIFS_XATTR is not set +CONFIG_CISS_SCSI_TAPE=y +CONFIG_CLASSIC_RCU=y +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_CLS_U32_MARK=y +# CONFIG_CLS_U32_PERF is not set +CONFIG_CODA_FS=m +CONFIG_COMPAL_LAPTOP=m +# CONFIG_COMPAT_BRK is not set +# CONFIG_COMPAT_VDSO is not set +CONFIG_COMPUTONE=m +CONFIG_CONFIGFS_FS=m +CONFIG_CONNECTOR=y +CONFIG_CONSOLE_POLL=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_CONTEXT_SWITCH_TRACER=y +# CONFIG_COPS is not set +CONFIG_COSA=m +# CONFIG_CPA_DEBUG is not set +CONFIG_CPU5_WDT=m +CONFIG_CPUSETS=y +CONFIG_CPU_FREQ=y +# CONFIG_CPU_FREQ_DEBUG is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_STAT=m +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_TABLE=m +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CRAMFS=y +CONFIG_CRASH_DUMP=y +CONFIG_CRC16=m +CONFIG_CRC32=y +CONFIG_CRC7=m +CONFIG_CRC_CCITT=m +CONFIG_CRC_ITU_T=m +CONFIG_CRC_T10DIF=m +CONFIG_CRYPTO=y +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_AES_586=m +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_CTR=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_DEV_GEODE=m +CONFIG_CRYPTO_DEV_HIFN_795X=m +CONFIG_CRYPTO_DEV_HIFN_795X_RNG=y +CONFIG_CRYPTO_DEV_PADLOCK=y +CONFIG_CRYPTO_DEV_PADLOCK_AES=m +CONFIG_CRYPTO_DEV_PADLOCK_SHA=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_GCM=m +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_LZO=m +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_RMD128=m +CONFIG_CRYPTO_RMD160=m +CONFIG_CRYPTO_RMD256=m +CONFIG_CRYPTO_RMD320=m +CONFIG_CRYPTO_SALSA20=m +CONFIG_CRYPTO_SALSA20_586=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SEQIV=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_586=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_XTS=m +CONFIG_CS5535_GPIO=m +CONFIG_CS89x0=m +CONFIG_CYCLADES=m +CONFIG_CYCLADES_SYNC=m +CONFIG_CYCLOMX_X25=y +# CONFIG_CYZ_INTR is not set +# CONFIG_DAB is not set +CONFIG_DAVICOM_PHY=m +CONFIG_DCDBAS=m +CONFIG_DE2104X=m +CONFIG_DE4X5=m +CONFIG_DE600=m +CONFIG_DE620=m +# CONFIG_DEBUG_BOOT_PARAMS is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_DRIVER is not set +CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +CONFIG_DEBUG_MEMORY_INIT=y +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_NX_TEST is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_DEBUG_RODATA=y +# CONFIG_DEBUG_RODATA_TEST is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +CONFIG_DECNET=m +CONFIG_DECNET_NF_GRABULATOR=m +# CONFIG_DECNET_ROUTER is not set +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_BIC is not set +CONFIG_DEFAULT_CUBIC=y +# CONFIG_DEFAULT_HTCP is not set +CONFIG_DEFAULT_IO_DELAY_TYPE=1 +# CONFIG_DEFAULT_NOOP is not set +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_WESTWOOD is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_DEFXX=m +# CONFIG_DEFXX_MMIO is not set +CONFIG_DELL_RBU=m +CONFIG_DEPCA=m +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_DEVKMEM is not set +CONFIG_DEVPORT=y +CONFIG_DEV_APPLETALK=m +CONFIG_DE_AOC=y +CONFIG_DIGIEPCA=m +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_DISPLAY_SUPPORT=m +# CONFIG_DL2K is not set +CONFIG_DLCI=m +CONFIG_DLCI_MAX=8 +CONFIG_DLM=m +# CONFIG_DLM_DEBUG is not set +CONFIG_DM9102=m +CONFIG_DMI=y +CONFIG_DMIID=y +CONFIG_DM_CRYPT=m +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_DELAY is not set +CONFIG_DM_LOOP=m +CONFIG_DM_MIRROR=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_RAID45=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_UEVENT=y +CONFIG_DM_ZERO=m +CONFIG_DNOTIFY=y +CONFIG_DONGLE=y +CONFIG_DOUBLEFAULT=y +CONFIG_DRM=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_I915=m +CONFIG_DRM_MGA=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_SAVAGE=m +CONFIG_DRM_SIS=m +CONFIG_DRM_TDFX=m +CONFIG_DRM_VIA=m +CONFIG_DRM_VIA_CHROME9=m +CONFIG_DS1682=m +CONFIG_DSCC4=m +CONFIG_DSCC4_PCISYNC=y +CONFIG_DSCC4_PCI_RST=y +CONFIG_DTLK=m +CONFIG_DUMMY=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_DVB_AU8522=m +CONFIG_DVB_AV7110=m +# CONFIG_DVB_AV7110_FIRMWARE is not set +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_B2C2_FLEXCOP=m +# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_BT8XX=m +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_CORE=m +CONFIG_DVB_BUDGET_PATCH=m +CONFIG_DVB_CAPTURE_DRIVERS=y +CONFIG_DVB_CINERGYT2=m +# CONFIG_DVB_CINERGYT2_TUNING is not set +CONFIG_DVB_CORE=m +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24123=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m +CONFIG_DVB_DRX397XD=m +# CONFIG_DVB_FE_CUSTOMISE is not set +CONFIG_DVB_ISL6405=m +CONFIG_DVB_ISL6421=m +CONFIG_DVB_L64781=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_LNBP21=m +CONFIG_DVB_MT312=m +CONFIG_DVB_MT352=m +CONFIG_DVB_NXT200X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_PLL=m +CONFIG_DVB_PLUTO2=m +CONFIG_DVB_S5H1409=m +CONFIG_DVB_S5H1411=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_SIANO_SMS1XXX=m +CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS=y +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_STV0297=m +CONFIG_DVB_STV0299=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_TDA10023=m +CONFIG_DVB_TDA10048=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_TDA10086=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_DVB_TUA6100=m +CONFIG_DVB_TUNER_DIB0070=m +CONFIG_DVB_TUNER_ITD1000=m +CONFIG_DVB_USB=m +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_USB_ANYSEE=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_CXUSB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_DIBUSB_MB=m +# CONFIG_DVB_USB_DIBUSB_MB_FAULTY is not set +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_DW2102=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_VES1820=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_ZL10353=m +CONFIG_E100=m +CONFIG_E1000=m +CONFIG_E1000E=m +# CONFIG_E1000E_ENABLED is not set +# CONFIG_E1000E_NEW is not set +# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set +CONFIG_E2100=m +CONFIG_EARLY_PRINTK=y +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_ECRYPT_FS=m +CONFIG_EDAC=y +CONFIG_EDAC_AMD76X=m +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_E752X=m +CONFIG_EDAC_E7XXX=m +CONFIG_EDAC_I3000=m +CONFIG_EDAC_I5000=m +CONFIG_EDAC_I5100=m +CONFIG_EDAC_I82860=m +CONFIG_EDAC_I82875P=m +CONFIG_EDAC_I82975X=m +CONFIG_EDAC_MM_EDAC=m +CONFIG_EDAC_R82600=m +CONFIG_EDD=y +CONFIG_EDD_OFF=y +CONFIG_EEEPC_LAPTOP=m +CONFIG_EEPRO100=m +CONFIG_EEPROM_93CX6=m +CONFIG_EEXPRESS=m +CONFIG_EEXPRESS_PRO=m +CONFIG_EFI=y +CONFIG_EFI_PARTITION=y +CONFIG_EFI_VARS=y +CONFIG_EFS_FS=m +CONFIG_EISA=y +CONFIG_EISA_NAMES=y +CONFIG_EISA_PCI_EISA=y +CONFIG_EISA_VIRTUAL_ROOT=y +CONFIG_EISA_VLB_PRIMING=y +CONFIG_EL1=m +CONFIG_EL16=m +CONFIG_EL2=m +CONFIG_EL3=m +CONFIG_ELF_CORE=y +CONFIG_ELMC=m +CONFIG_ELMC_II=m +CONFIG_ELPLUS=m +# CONFIG_EMBEDDED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENC28J60 is not set +CONFIG_ENCLOSURE_SERVICES=m +CONFIG_EPIC100=m +CONFIG_EPOLL=y +CONFIG_EQUALIZER=m +CONFIG_ES3210=m +CONFIG_ESI_DONGLE=m +CONFIG_ESPSERIAL=m +CONFIG_ETH16I=m +CONFIG_EUROTECH_WDT=m +CONFIG_EVENTFD=y +CONFIG_EWRK3=m +CONFIG_EXPERIMENTAL=y +CONFIG_EXPORTFS=m +CONFIG_EXT2_FS=m +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT4DEV_FS=m +CONFIG_EXT4DEV_FS_POSIX_ACL=y +CONFIG_EXT4DEV_FS_SECURITY=y +CONFIG_EXT4DEV_FS_XATTR=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_FARSYNC=m +CONFIG_FAST_CMPXCHG_LOCAL=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_FS=m +# CONFIG_FAULT_INJECTION is not set +CONFIG_FB=y +CONFIG_FB_3DFX=m +# CONFIG_FB_3DFX_ACCEL is not set +CONFIG_FB_ARC=m +CONFIG_FB_ARK=m +CONFIG_FB_ASILIANT=y +CONFIG_FB_ATY=m +CONFIG_FB_ATY128=m +CONFIG_FB_ATY128_BACKLIGHT=y +CONFIG_FB_ATY_BACKLIGHT=y +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GENERIC_LCD=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_BACKLIGHT=y +CONFIG_FB_CARILLO_RANCH=m +CONFIG_FB_CARMINE=m +CONFIG_FB_CARMINE_DRAM_EVAL=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_CIRRUS=m +CONFIG_FB_CYBER2000=m +CONFIG_FB_CYBLA=m +CONFIG_FB_DDC=m +CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_EFI=y +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_GEODE=y +CONFIG_FB_GEODE_GX=m +CONFIG_FB_GEODE_GX1=m +CONFIG_FB_GEODE_LX=m +CONFIG_FB_HECUBA=m +CONFIG_FB_HGA=m +# CONFIG_FB_HGA_ACCEL is not set +CONFIG_FB_I810=m +# CONFIG_FB_I810_GTF is not set +CONFIG_FB_IMAC=y +CONFIG_FB_IMSTT=y +CONFIG_FB_INTEL=m +# CONFIG_FB_INTEL_DEBUG is not set +CONFIG_FB_INTEL_I2C=y +CONFIG_FB_KYRO=m +CONFIG_FB_LE80578=m +# CONFIG_FB_MACMODES is not set +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_G=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MULTIHEAD=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_N411=m +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_NVIDIA=m +CONFIG_FB_NVIDIA_BACKLIGHT=y +# CONFIG_FB_NVIDIA_DEBUG is not set +CONFIG_FB_NVIDIA_I2C=y +CONFIG_FB_PM2=m +CONFIG_FB_PM2_FIFO_DISCONNECT=y +CONFIG_FB_PM3=m +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_BACKLIGHT=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RIVA=m +CONFIG_FB_RIVA_BACKLIGHT=y +# CONFIG_FB_RIVA_DEBUG is not set +CONFIG_FB_RIVA_I2C=y +CONFIG_FB_S1D13XXX=m +CONFIG_FB_S3=m +CONFIG_FB_SAVAGE=m +CONFIG_FB_SAVAGE_ACCEL=y +CONFIG_FB_SAVAGE_I2C=y +CONFIG_FB_SIS=m +CONFIG_FB_SIS_300=y +CONFIG_FB_SIS_315=y +CONFIG_FB_SM501=m +CONFIG_FB_SVGALIB=m +CONFIG_FB_SYS_COPYAREA=m +CONFIG_FB_SYS_FILLRECT=m +CONFIG_FB_SYS_FOPS=m +CONFIG_FB_SYS_IMAGEBLIT=m +CONFIG_FB_TILEBLITTING=y +CONFIG_FB_TRIDENT=m +# CONFIG_FB_TRIDENT_ACCEL is not set +CONFIG_FB_UVESA=m +CONFIG_FB_VESA=m +CONFIG_FB_VGA16=m +# CONFIG_FB_VIRTUAL is not set +CONFIG_FB_VOODOO1=m +CONFIG_FB_VT8623=m +CONFIG_FDDI=y +CONFIG_FEALNX=m +CONFIG_FIB_RULES=y +# CONFIG_FIREWIRE is not set +CONFIG_FIRMWARE_EDID=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FLATMEM=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_8x8=y +CONFIG_FORCEDETH=m +# CONFIG_FORCEDETH_NAPI is not set +CONFIG_FRAMEBUFFER_CONSOLE=m +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FRAME_POINTER=y +CONFIG_FRAME_WARN=1024 +CONFIG_FSAM7400=m +CONFIG_FS_MBCACHE=m +CONFIG_FS_POSIX_ACL=y +CONFIG_FS_UNIONFS=m +CONFIG_FTL=m +CONFIG_FTRACE=y +# CONFIG_FTRACE_STARTUP_TEST is not set +CONFIG_FUJITSU_LAPTOP=m +# CONFIG_FUJITSU_LAPTOP_DEBUG is not set +CONFIG_FUSE_FS=m +CONFIG_FUSION=y +CONFIG_FUSION_CTL=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_LAN=m +CONFIG_FUSION_LOGGING=y +CONFIG_FUSION_MAX_SGE=128 +CONFIG_FUSION_SAS=m +CONFIG_FUSION_SPI=m +CONFIG_FUTEX=y +CONFIG_FW_LOADER=y +CONFIG_GACT_PROB=y +CONFIG_GAMEPORT=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GARP=m +CONFIG_GENERIC_ACL=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_GENERIC_CMOS_UPDATE=y +# CONFIG_GENERIC_CPU is not set +CONFIG_GENERIC_FIND_FIRST_BIT=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_ISA_DMA=y +# CONFIG_GENERIC_LOCKBREAK is not set +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_TIME=y +# CONFIG_GENERIC_TIME_VSYSCALL is not set +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_DLM=m +CONFIG_GFS_FS=m +CONFIG_GIGASET_BASE=m +# CONFIG_GIGASET_DEBUG is not set +CONFIG_GIGASET_M101=m +CONFIG_GIGASET_M105=m +# CONFIG_GIGASET_UNDOCREQ is not set +CONFIG_GIRBIL_DONGLE=m +CONFIG_GNBD=m +CONFIG_GPIOLIB=y +CONFIG_GPIO_MAX7301=m +CONFIG_GPIO_MAX732X=m +CONFIG_GPIO_MCP23S08=m +CONFIG_GPIO_PCA953X=m +CONFIG_GPIO_PCF857X=m +CONFIG_GPIO_SYSFS=y +CONFIG_GROUP_SCHED=y +CONFIG_HAMACHI=m +CONFIG_HAMRADIO=y +CONFIG_HANGCHECK_TIMER=m +CONFIG_HAPPYMEAL=m +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_HAVE_ARCH_TRACEHOOK is not set +# CONFIG_HAVE_CLK is not set +# CONFIG_HAVE_CPUMASK_OF_CPU_MAP is not set +# CONFIG_HAVE_DMA_ATTRS is not set +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_IDE=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_KVM=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y +CONFIG_HDLC=m +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m +CONFIG_HDLC_RAW=m +CONFIG_HDLC_RAW_ETH=m +CONFIG_HDLC_X25=m +# CONFIG_HEADERS_CHECK is not set +CONFIG_HECI=m +CONFIG_HERMES=m +CONFIG_HFSPLUS_FS=m +CONFIG_HFS_FS=m +CONFIG_HIBERNATION=y +CONFIG_HID=m +CONFIG_HIDRAW=y +# CONFIG_HID_DEBUG is not set +# CONFIG_HID_FF is not set +CONFIG_HID_SUPPORT=y +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_HIPPI=y +CONFIG_HISAX_16_0=y +CONFIG_HISAX_16_3=y +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_ASUSCOM=y +CONFIG_HISAX_AVM_A1=y +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_BKM_A4T=y +# CONFIG_HISAX_DEBUG is not set +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_ENTERNOW_PCI=y +CONFIG_HISAX_EURO=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HDLC=y +CONFIG_HISAX_HFC4S8S=m +CONFIG_HISAX_HFCS=y +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_HSTSAPHIR=y +CONFIG_HISAX_ISURF=y +CONFIG_HISAX_IX1MICROR2=y +CONFIG_HISAX_MAX_CARDS=8 +CONFIG_HISAX_MIC=y +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_NICCY=y +# CONFIG_HISAX_NO_KEYPAD is not set +# CONFIG_HISAX_NO_LLC is not set +# CONFIG_HISAX_NO_SENDCOMPLETE is not set +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_SPORTSTER=y +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_TELEINT=y +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_TELES_CS=m +CONFIG_HISAX_W6692=y +CONFIG_HOSTAP=m +CONFIG_HOSTAP_CS=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PCI=m +CONFIG_HOSTAP_PLX=m +CONFIG_HOSTESS_SV11=m +CONFIG_HOTPLUG=y +CONFIG_HOTPLUG_CPU=y +CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI_ACPI=m +CONFIG_HOTPLUG_PCI_ACPI_IBM=m +CONFIG_HOTPLUG_PCI_COMPAQ=m +CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM=y +CONFIG_HOTPLUG_PCI_CPCI=y +CONFIG_HOTPLUG_PCI_CPCI_GENERIC=m +CONFIG_HOTPLUG_PCI_CPCI_ZT5550=m +CONFIG_HOTPLUG_PCI_FAKE=m +CONFIG_HOTPLUG_PCI_IBM=m +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_HOTPLUG_PCI_SHPC=m +CONFIG_HP100=m +CONFIG_HPET=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_HPET_MMAP=y +CONFIG_HPET_TIMER=y +CONFIG_HPFS_FS=m +CONFIG_HPLAN=m +CONFIG_HPLAN_PLUS=m +CONFIG_HP_ILO=m +# CONFIG_HP_WATCHDOG is not set +CONFIG_HP_WMI=m +CONFIG_HTC_PASIC3=m +CONFIG_HT_IRQ=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_HVC_DRIVER=y +CONFIG_HWMON=y +# CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_HWMON_VID=m +CONFIG_HW_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_AMD=m +CONFIG_HW_RANDOM_GEODE=m +CONFIG_HW_RANDOM_INTEL=m +CONFIG_HW_RANDOM_VIA=m +CONFIG_HW_RANDOM_VIRTIO=m +CONFIG_HYSDN=m +CONFIG_HYSDN_CAPI=y +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_300 is not set +CONFIG_I2C=m +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCA=m +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD756_S4882=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=m +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set +# CONFIG_I2C_DEBUG_CORE is not set +CONFIG_I2C_GPIO=m +# CONFIG_I2C_HELPER_AUTO is not set +CONFIG_I2C_I801=m +CONFIG_I2C_ISCH=m +CONFIG_I2C_NFORCE2=m +CONFIG_I2C_NFORCE2_S4985=m +CONFIG_I2C_OCORES=m +CONFIG_I2C_PARPORT=m +CONFIG_I2C_PARPORT_LIGHT=m +CONFIG_I2C_PCA_ISA=m +CONFIG_I2C_PCA_PLATFORM=m +CONFIG_I2C_PIIX4=m +CONFIG_I2C_SIMTEC=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_STUB=m +CONFIG_I2C_TAOS_EVM=m +CONFIG_I2C_TINY_USB=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m +CONFIG_I2O=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_BUS=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y +CONFIG_I2O_PROC=m +CONFIG_I2O_SCSI=m +CONFIG_I6300ESB_WDT=m +CONFIG_I82092=m +CONFIG_I82365=m +CONFIG_I8K=m +CONFIG_IB700_WDT=m +CONFIG_IBMASR=m +CONFIG_IBMLANA=m +CONFIG_IBMLS=m +# CONFIG_IBMMCA_SCSI_DEV_RESET is not set +CONFIG_IBMMCA_SCSI_ORDER_STANDARD=y +CONFIG_IBMOL=m +CONFIG_IBMTR=m +CONFIG_IBM_ASM=m +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +CONFIG_ICPLUS_PHY=m +# CONFIG_IDE is not set +CONFIG_IEEE1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_ETH1394_ROM_ENTRY=y +CONFIG_IEEE1394_OHCI1394=m +CONFIG_IEEE1394_PCILYNX=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE80211=m +CONFIG_IEEE80211_CRYPT_CCMP=m +CONFIG_IEEE80211_CRYPT_TKIP=m +CONFIG_IEEE80211_CRYPT_WEP=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IFB=m +CONFIG_IGB=m +# CONFIG_IGB_LRO is not set +# CONFIG_IKCONFIG is not set +CONFIG_INET=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET_AH=m +CONFIG_INET_DCCP_DIAG=m +CONFIG_INET_DIAG=y +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_LRO=m +CONFIG_INET_TCP_DIAG=y +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_AMSO1100=m +CONFIG_INFINIBAND_AMSO1100_DEBUG=y +CONFIG_INFINIBAND_CXGB3=m +# CONFIG_INFINIBAND_CXGB3_DEBUG is not set +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_CM=y +CONFIG_INFINIBAND_IPOIB_DEBUG=y +# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set +CONFIG_INFINIBAND_ISER=m +CONFIG_INFINIBAND_MTHCA=m +CONFIG_INFINIBAND_MTHCA_DEBUG=y +# CONFIG_INFINIBAND_NES is not set +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_MEM=y +CONFIG_INFTL=m +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_INPUT=y +CONFIG_INPUT_ACERHK=m +# CONFIG_INPUT_APANEL is not set +CONFIG_INPUT_ATI_REMOTE=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_ATLAS_BTNS=m +CONFIG_INPUT_EVBUG=m +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_FF_MEMLESS=m +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYBOARD=y +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_MOUSE=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_PCSPKR=m +CONFIG_INPUT_POLLDEV=m +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_UINPUT=m +CONFIG_INPUT_WISTRON_BTNS=m +CONFIG_INPUT_YEALINK=m +CONFIG_INTEL_MENLOW=m +# CONFIG_IOMMU_HELPER is not set +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_CFQ=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_NOOP=y +# CONFIG_IO_DELAY_0X80 is not set +CONFIG_IO_DELAY_0XED=y +# CONFIG_IO_DELAY_NONE is not set +CONFIG_IO_DELAY_TYPE_0X80=0 +CONFIG_IO_DELAY_TYPE_0XED=1 +CONFIG_IO_DELAY_TYPE_NONE=3 +CONFIG_IO_DELAY_TYPE_UDELAY=2 +# CONFIG_IO_DELAY_UDELAY is not set +CONFIG_IP1000=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_SECURITY=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IPC_NS=y +CONFIG_IPDDP=m +CONFIG_IPDDP_DECAP=y +CONFIG_IPDDP_ENCAP=y +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_POWEROFF=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPPP_FILTER=y +CONFIG_IPV6=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_MROUTE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +CONFIG_IPV6_PRIVACY=y +# CONFIG_IPV6_ROUTER_PREF is not set +CONFIG_IPV6_SIT=m +# CONFIG_IPV6_SUBTREES is not set +CONFIG_IPV6_TUNNEL=m +CONFIG_IPW2100=m +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +CONFIG_IPW2200=m +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +CONFIG_IPW2200_RADIOTAP=y +CONFIG_IPWIRELESS=m +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_DCCP=m +CONFIG_IP_DCCP_ACKVEC=y +CONFIG_IP_DCCP_CCID2=m +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=m +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_CCID3_RTO=100 +# CONFIG_IP_DCCP_DEBUG is not set +CONFIG_IP_DCCP_TFRC_LIB=m +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_SECURITY=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_IP_PNP is not set +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_SCTP=m +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_FTP=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_NQ=m +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_TAB_BITS=12 +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_WRR=m +CONFIG_IRCOMM=m +CONFIG_IRDA=m +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_DEBUG=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_ULTRA=y +CONFIG_IRLAN=m +CONFIG_IRNET=m +# CONFIG_IRQBALANCE is not set +# CONFIG_IRQSOFF_TRACER is not set +CONFIG_IRTTY_SIR=m +CONFIG_ISA=y +CONFIG_ISAPNP=y +CONFIG_ISA_DMA_API=y +CONFIG_ISCSI_IBFT=m +CONFIG_ISCSI_IBFT_FIND=y +CONFIG_ISCSI_TCP=m +CONFIG_ISDN=y +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIDRV=m +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_MAINT=m +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVERSION=m +CONFIG_ISDN_DRV_ACT2000=m +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m +CONFIG_ISDN_DRV_AVMB1_B1ISA=m +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_C4=m +CONFIG_ISDN_DRV_AVMB1_T1ISA=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_ISDN_DRV_GIGASET=m +CONFIG_ISDN_DRV_HISAX=m +CONFIG_ISDN_DRV_ICN=m +CONFIG_ISDN_DRV_PCBIT=m +CONFIG_ISDN_DRV_SC=m +CONFIG_ISDN_I4L=m +CONFIG_ISDN_MPP=y +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_BSDCOMP=m +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_TTY_FAX=y +CONFIG_ISDN_X25=y +# CONFIG_ISI is not set +CONFIG_ISO9660_FS=m +CONFIG_IT8712F_WDT=m +CONFIG_ITCO_VENDOR_SUPPORT=y +CONFIG_ITCO_WDT=m +CONFIG_IWL3945=m +# CONFIG_IWL3945_DEBUG is not set +CONFIG_IWL3945_LEDS=y +CONFIG_IWL3945_RFKILL=y +CONFIG_IWL3945_SPECTRUM_MEASUREMENT=y +CONFIG_IWL4965=y +CONFIG_IWL5000=y +CONFIG_IWLAGN=m +CONFIG_IWLAGN_LEDS=y +CONFIG_IWLAGN_SPECTRUM_MEASUREMENT=y +CONFIG_IWLCORE=m +CONFIG_IWLWIFI=m +# CONFIG_IWLWIFI_DEBUG is not set +CONFIG_IWLWIFI_LEDS=y +CONFIG_IWLWIFI_RFKILL=y +CONFIG_IXGB=m +CONFIG_IXGBE=m +CONFIG_JBD=m +CONFIG_JBD2=m +# CONFIG_JBD2_DEBUG is not set +# CONFIG_JBD_DEBUG is not set +CONFIG_JFFS2_CMODE_FAVOURLZO=y +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_SUMMARY is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFS_DEBUG is not set +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +CONFIG_JFS_STATISTICS=y +CONFIG_JOLIET=y +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_ZHENHUA=m +CONFIG_K8_NB=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_KARMA_PARTITION=y +CONFIG_KEXEC=y +CONFIG_KEXEC_JUMP=y +CONFIG_KEYBOARD_ATKBD=y +CONFIG_KEYBOARD_GPIO=m +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_NEWTON=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_KEYBOARD_SUNKBD=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +CONFIG_KGDB=y +CONFIG_KGDB_SERIAL_CONSOLE=y +# CONFIG_KGDB_TESTS is not set +CONFIG_KINGSUN_DONGLE=m +CONFIG_KMOD=y +CONFIG_KPROBES=y +# CONFIG_KPROBES_SANITY_TEST is not set +CONFIG_KRETPROBES=y +CONFIG_KS0108=m +CONFIG_KS0108_DELAY=2 +CONFIG_KS0108_PORT=0x378 +CONFIG_KS959_DONGLE=m +CONFIG_KSDAZZLE_DONGLE=m +CONFIG_KTIME_SCALAR=y +CONFIG_KVM=m +CONFIG_KVM_AMD=m +CONFIG_KVM_CLOCK=y +CONFIG_KVM_GUEST=y +CONFIG_KVM_INTEL=m +# CONFIG_KVM_TRACE is not set +CONFIG_LANCE=m +CONFIG_LANMEDIA=m +CONFIG_LAPB=m +CONFIG_LAPBETHER=m +CONFIG_LATENCYTOP=y +CONFIG_LBD=y +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_ILI9320=m +CONFIG_LCD_LTV350QV=m +CONFIG_LCD_PLATFORM=m +CONFIG_LCD_VGG2432A4=m +# CONFIG_LDM_DEBUG is not set +CONFIG_LDM_PARTITION=y +CONFIG_LEDS_CLASS=m +# CONFIG_LEDS_CLEVO_MAIL is not set +CONFIG_LEDS_GPIO=m +CONFIG_LEDS_NET48XX=m +CONFIG_LEDS_PCA9532=m +CONFIG_LEDS_PCA955X=m +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=m +CONFIG_LEDS_TRIGGER_HEARTBEAT=m +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_WRAP=m +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LIBCRC32C=m +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_CS=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_LIBERTAS_SDIO=m +CONFIG_LIBERTAS_USB=m +CONFIG_LIRC_ATIUSB=m +CONFIG_LIRC_BT829=m +CONFIG_LIRC_CMDIR=m +CONFIG_LIRC_DEV=m +# CONFIG_LIRC_GPIO is not set +CONFIG_LIRC_I2C=m +CONFIG_LIRC_IGORPLUGUSB=m +CONFIG_LIRC_IMON=m +CONFIG_LIRC_IT87=m +CONFIG_LIRC_MCEUSB=m +CONFIG_LIRC_MCEUSB2=m +# CONFIG_LIRC_PARALLEL is not set +CONFIG_LIRC_PVR150=m +CONFIG_LIRC_SASEM=m +CONFIG_LIRC_SERIAL=m +CONFIG_LIRC_SERIAL_IGOR=m +CONFIG_LIRC_SIR=m +CONFIG_LIRC_STREAMZAP=m +CONFIG_LIRC_TTUSBIR=m +CONFIG_LITELINK_DONGLE=m +# CONFIG_LKDTM is not set +CONFIG_LLC=y +CONFIG_LLC2=m +CONFIG_LMPCM_USB=m +CONFIG_LNE390=m +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_LOCKD=m +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_LOCKD_V4=y +CONFIG_LOCK_KERNEL=y +# CONFIG_LOCK_STAT is not set +# CONFIG_LOGO is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LP486E=m +# CONFIG_LP_CONSOLE is not set +CONFIG_LSF=y +CONFIG_LTPC=m +CONFIG_LXT_PHY=m +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m +CONFIG_M25PXX_USE_FAST_READ=y +# CONFIG_M386 is not set +# CONFIG_M486 is not set +# CONFIG_M586MMX is not set +# CONFIG_M586TSC is not set +CONFIG_MA600_DONGLE=m +CONFIG_MAC80211=m +CONFIG_MAC80211_DEBUGFS=y +# CONFIG_MAC80211_DEBUG_MENU is not set +# CONFIG_MAC80211_HWSIM is not set +CONFIG_MAC80211_LEDS=y +CONFIG_MAC80211_MESH=y +CONFIG_MAC80211_RC_DEFAULT="pid" +CONFIG_MAC80211_RC_DEFAULT_PID=y +CONFIG_MAC80211_RC_PID=y +CONFIG_MACHZ_WDT=m +CONFIG_MACINTOSH_DRIVERS=y +CONFIG_MACVLAN=m +CONFIG_MAC_EMUMOUSEBTN=y +CONFIG_MAC_PARTITION=y +CONFIG_MADGEMC=m +CONFIG_MAGIC_SYSRQ=y +CONFIG_MARKERS=y +CONFIG_MARVELL_PHY=m +# CONFIG_MATH_EMULATION is not set +CONFIG_MAX_RAW_DEVS=256 +CONFIG_MCA=y +CONFIG_MCA_LEGACY=y +# CONFIG_MCA_PROC_FS is not set +# CONFIG_MCORE2 is not set +CONFIG_MCP2120_DONGLE=m +# CONFIG_MCRUSOE is not set +CONFIG_MCS_FIR=m +# CONFIG_MCYRIXIII is not set +CONFIG_MD=y +CONFIG_MDA_CONSOLE=m +CONFIG_MDIO_BITBANG=m +CONFIG_MD_FAULTY=m +CONFIG_MD_LINEAR=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +CONFIG_MD_RAID5_RESHAPE=y +CONFIG_MEDIA_ATTACH=y +CONFIG_MEDIA_TUNER=m +# CONFIG_MEDIA_TUNER_CUSTOMIZE is not set +CONFIG_MEDIA_TUNER_MT2060=m +CONFIG_MEDIA_TUNER_MT20XX=m +CONFIG_MEDIA_TUNER_MT2131=m +CONFIG_MEDIA_TUNER_MT2266=m +CONFIG_MEDIA_TUNER_MXL5005S=m +CONFIG_MEDIA_TUNER_MXL5007T=m +CONFIG_MEDIA_TUNER_QT1010=m +CONFIG_MEDIA_TUNER_SIMPLE=m +CONFIG_MEDIA_TUNER_TDA18271=m +CONFIG_MEDIA_TUNER_TDA827X=m +CONFIG_MEDIA_TUNER_TDA8290=m +CONFIG_MEDIA_TUNER_TDA9887=m +CONFIG_MEDIA_TUNER_TEA5761=m +CONFIG_MEDIA_TUNER_TEA5767=m +CONFIG_MEDIA_TUNER_XC2028=m +CONFIG_MEDIA_TUNER_XC5000=m +# CONFIG_MEFFICEON is not set +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_SAS=m +# CONFIG_MEMSTICK is not set +# CONFIG_MEMTEST is not set +# CONFIG_MFD_CORE is not set +CONFIG_MFD_SM501=m +# CONFIG_MFD_SM501_GPIO is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MGEODEGX1 is not set +# CONFIG_MGEODE_LX is not set +CONFIG_MICROCODE=m +CONFIG_MICROCODE_OLD_INTERFACE=y +CONFIG_MII=m +CONFIG_MINIX_FS=m +CONFIG_MINIX_SUBPARTITION=y +CONFIG_MISC_DEVICES=y +CONFIG_MISDN=m +CONFIG_MISDN_DSP=m +CONFIG_MISDN_HFCMULTI=m +CONFIG_MISDN_HFCPCI=m +CONFIG_MISDN_L1OIP=m +CONFIG_MIXCOMWD=m +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +CONFIG_MKISS=m +CONFIG_MLX4_CORE=m +CONFIG_MLX4_DEBUG=y +CONFIG_MLX4_INFINIBAND=m +CONFIG_MMC=m +CONFIG_MMC_BLOCK=m +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_RICOH_MMC=m +CONFIG_MMC_SDHCI=m +CONFIG_MMC_SDHCI_PCI=m +CONFIG_MMC_SDRICOH_CS=m +# CONFIG_MMC_TEST is not set +CONFIG_MMC_TIFM_SD=m +# CONFIG_MMC_UNSAFE_RESUME is not set +CONFIG_MMC_WBSD=m +# CONFIG_MMIOTRACE is not set +CONFIG_MMU=y +CONFIG_MMU_NOTIFIER=y +CONFIG_MM_OWNER=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MOUSE_APPLETOUCH=m +# CONFIG_MOUSE_ATIXL is not set +CONFIG_MOUSE_BCM5974=m +CONFIG_MOUSE_GPIO=m +CONFIG_MOUSE_INPORT=m +CONFIG_MOUSE_LOGIBM=m +CONFIG_MOUSE_PC110PAD=m +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_PS2_TRACKPOINT=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_MOXA_INTELLIO=m +CONFIG_MOXA_SMARTIO=m +# CONFIG_MPENTIUM4 is not set +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPSC is not set +CONFIG_MSDOS_FS=m +CONFIG_MSDOS_PARTITION=y +CONFIG_MSI_LAPTOP=m +CONFIG_MSNDCLAS_INIT_FILE="/etc/sound/msndinit.bin" +CONFIG_MSNDCLAS_PERM_FILE="/etc/sound/msndperm.bin" +CONFIG_MSNDPIN_INIT_FILE="/etc/sound/pndspini.bin" +CONFIG_MSNDPIN_PERM_FILE="/etc/sound/pndsperm.bin" +CONFIG_MT9M001_PCA9536_SWITCH=y +CONFIG_MT9V022_PCA9536_SWITCH=y +CONFIG_MTD=m +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTD_ABSENT=m +CONFIG_MTD_ALAUDA=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_AR7_PARTS=m +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK2MTD=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_MTD_CFI=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_CFI_UTIL=m +CONFIG_MTD_CHAR=m +CONFIG_MTD_CK804XROM=m +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_CONCAT=m +CONFIG_MTD_DATAFLASH=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_DILNETPC=m +CONFIG_MTD_DILNETPC_BOOTSIZE=0x80000 +CONFIG_MTD_DOC2000=m +CONFIG_MTD_DOC2001=m +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCECC=m +CONFIG_MTD_DOCPROBE=m +CONFIG_MTD_DOCPROBE_ADDRESS=0 +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_ESB2ROM=m +CONFIG_MTD_GEN_PROBE=m +CONFIG_MTD_ICHXROM=m +CONFIG_MTD_INTEL_VR_NOR=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_L440GX=m +CONFIG_MTD_M25P80=m +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +CONFIG_MTD_MTDRAM=m +CONFIG_MTD_NAND=m +CONFIG_MTD_NAND_CAFE=m +CONFIG_MTD_NAND_CS553X=m +CONFIG_MTD_NAND_DISKONCHIP=m +# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set +CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0 +# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND_IDS=m +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +CONFIG_MTD_NAND_NANDSIM=m +CONFIG_MTD_NAND_PLATFORM=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_NETSC520=m +CONFIG_MTD_NETtel=m +CONFIG_MTD_ONENAND=m +CONFIG_MTD_ONENAND_2X_PROGRAM=y +# CONFIG_MTD_ONENAND_OTP is not set +CONFIG_MTD_ONENAND_SIM=m +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +CONFIG_MTD_OOPS=m +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_PCI=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +CONFIG_MTD_PHYSMAP_LEN=0x4000000 +CONFIG_MTD_PHYSMAP_START=0x8000000 +CONFIG_MTD_PLATRAM=m +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +CONFIG_MTD_RAM=m +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +CONFIG_MTD_REDBOOT_PARTS=m +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +CONFIG_MTD_ROM=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_SCB2_FLASH=m +CONFIG_MTD_SCx200_DOCFLASH=m +CONFIG_MTD_SLRAM=m +CONFIG_MTD_TS5500=m +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_BEB_RESERVE=1 +# CONFIG_MTD_UBI_DEBUG is not set +CONFIG_MTD_UBI_GLUEBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTRR=y +CONFIG_MTRR_SANITIZER=y +CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=0 +CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1 +# CONFIG_MVIAC3_2 is not set +# CONFIG_MVIAC7 is not set +CONFIG_MWAVE=m +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MWINCHIPC6 is not set +CONFIG_MYRI10GE=m +CONFIG_N2=m +CONFIG_NAMESPACES=y +CONFIG_NATSEMI=m +CONFIG_NCPFS_EXTRAS=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_PACKET_SIGNING=y +# CONFIG_NCPFS_SMALLDOS is not set +CONFIG_NCPFS_STRONG=y +CONFIG_NCP_FS=m +CONFIG_NDISWRAPPER=m +CONFIG_NE2000=m +CONFIG_NE2K_PCI=m +CONFIG_NE2_MCA=m +CONFIG_NE3210=m +CONFIG_NET=y +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETDEVICES=y +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_OWNER=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_RATEEST=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_RATEEST=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETLABEL=y +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NETROM=m +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NETWORK_SECMARK=y +CONFIG_NETXEN_NIC=m +CONFIG_NET_9P=m +# CONFIG_NET_9P_DEBUG is not set +CONFIG_NET_9P_VIRTIO=m +CONFIG_NET_ACT_GACT=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_CLS=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_BASIC=m +# CONFIG_NET_CLS_FLOW is not set +CONFIG_NET_CLS_FW=m +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_DCCPPROBE=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_ET131X=m +CONFIG_NET_ETHERNET=y +CONFIG_NET_FC=y +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_NET_IPIP=m +CONFIG_NET_ISA=y +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_NET_PCI=y +CONFIG_NET_PCMCIA=y +CONFIG_NET_PKTGEN=m +CONFIG_NET_POCKET=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_NET_SB1000=m +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_ATM=m +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_FIFO=y +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_TCPPROBE=m +CONFIG_NET_TULIP=y +CONFIG_NET_VENDOR_3COM=y +CONFIG_NET_VENDOR_RACAL=y +CONFIG_NET_VENDOR_SMC=y +CONFIG_NEW_LEDS=y +CONFIG_NFSD=m +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFS_ACL_SUPPORT=m +CONFIG_NFS_COMMON=y +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_NF_CONNTRACK_SANE is not set +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_ACCT=y +CONFIG_NF_CT_NETLINK=m +# CONFIG_NF_CT_PROTO_DCCP is not set +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_NAT=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_PROTO_GRE=m +CONFIG_NF_NAT_PROTO_SCTP=m +CONFIG_NF_NAT_PROTO_UDPLITE=m +CONFIG_NF_NAT_SIP=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_NAT_TFTP=m +CONFIG_NI52=m +CONFIG_NI65=m +CONFIG_NIU=m +CONFIG_NL80211=y +CONFIG_NLS=y +CONFIG_NLS_ASCII=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m +# CONFIG_NOHIGHMEM is not set +CONFIG_NORTEL_HERMES=m +CONFIG_NOZOMI=m +CONFIG_NO_HZ=y +CONFIG_NR_CPUS=64 +CONFIG_NS83820=m +CONFIG_NSC_FIR=m +CONFIG_NSC_GPIO=m +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_FS=m +# CONFIG_NTFS_RW is not set +CONFIG_NVRAM=m +CONFIG_N_HDLC=m +# CONFIG_OCFS2_DEBUG_FS is not set +CONFIG_OCFS2_DEBUG_MASKLOG=y +CONFIG_OCFS2_FS=m +CONFIG_OCFS2_FS_O2CB=m +CONFIG_OCFS2_FS_STATS=y +CONFIG_OCFS2_FS_USERSPACE_CLUSTER=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_OLPC=y +CONFIG_OMFS_FS=m +CONFIG_OPROFILE=m +CONFIG_OPTIMIZE_INLINING=y +CONFIG_OSF_PARTITION=y +CONFIG_P54_COMMON=m +CONFIG_P54_PCI=m +CONFIG_P54_USB=m +CONFIG_P80211=m +CONFIG_PACKARDBELL_E5=m +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PARAVIRT=y +CONFIG_PARAVIRT_CLOCK=y +# CONFIG_PARAVIRT_DEBUG is not set +CONFIG_PARAVIRT_GUEST=y +CONFIG_PARIDE=m +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_BPCK6=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_EPAT=m +# CONFIG_PARIDE_EPATC8 is not set +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PG=m +CONFIG_PARIDE_PT=m +CONFIG_PARPORT=m +CONFIG_PARPORT_1284=y +CONFIG_PARPORT_AX88796=m +# CONFIG_PARPORT_GSC is not set +CONFIG_PARPORT_NOT_PC=y +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_FIFO=y +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_SERIAL=m +CONFIG_PARTITION_ADVANCED=y +CONFIG_PATA_ACPI=m +CONFIG_PATA_ALI=m +CONFIG_PATA_AMD=m +CONFIG_PATA_ARTOP=m +CONFIG_PATA_ATIIXP=m +# CONFIG_PATA_CMD640_PCI is not set +CONFIG_PATA_CMD64X=m +CONFIG_PATA_CS5520=m +CONFIG_PATA_CS5530=m +CONFIG_PATA_CS5535=m +CONFIG_PATA_CS5536=m +# CONFIG_PATA_CYPRESS is not set +CONFIG_PATA_EFAR=m +CONFIG_PATA_HPT366=m +CONFIG_PATA_HPT37X=m +# CONFIG_PATA_HPT3X2N is not set +CONFIG_PATA_HPT3X3=m +# CONFIG_PATA_HPT3X3_DMA is not set +# CONFIG_PATA_ISAPNP is not set +CONFIG_PATA_IT8213=m +CONFIG_PATA_IT821X=m +CONFIG_PATA_JMICRON=m +CONFIG_PATA_LEGACY=m +CONFIG_PATA_MARVELL=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_NETCELL=m +CONFIG_PATA_NINJA32=m +CONFIG_PATA_NS87410=m +CONFIG_PATA_NS87415=m +CONFIG_PATA_OLDPIIX=m +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +CONFIG_PATA_PCMCIA=m +CONFIG_PATA_PDC2027X=m +CONFIG_PATA_PDC_OLD=m +CONFIG_PATA_QDI=m +# CONFIG_PATA_RADISYS is not set +CONFIG_PATA_RZ1000=m +# CONFIG_PATA_SC1200 is not set +CONFIG_PATA_SCH=m +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_VIA=m +CONFIG_PATA_WINBOND=m +CONFIG_PATA_WINBOND_VLB=m +CONFIG_PC300=m +# CONFIG_PC300TOO is not set +# CONFIG_PC300_MLPPP is not set +CONFIG_PC8736x_GPIO=m +CONFIG_PC87413_WDT=m +CONFIG_PCCARD=m +CONFIG_PCCARD_NONSTATIC=m +CONFIG_PCI=y +CONFIG_PCI200SYN=m +CONFIG_PCIEAER=y +# CONFIG_PCIEASPM is not set +CONFIG_PCIEPORTBUS=y +CONFIG_PCIPCWATCHDOG=m +CONFIG_PCI_ATMEL=m +CONFIG_PCI_BIOS=y +# CONFIG_PCI_DEBUG is not set +CONFIG_PCI_DIRECT=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_GOANY=y +# CONFIG_PCI_GOBIOS is not set +# CONFIG_PCI_GODIRECT is not set +# CONFIG_PCI_GOMMCONFIG is not set +# CONFIG_PCI_GOOLPC is not set +CONFIG_PCI_HERMES=m +CONFIG_PCI_LEGACY=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_MSI=y +CONFIG_PCI_OLPC=y +CONFIG_PCMCIA=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_PCMCIA_AXNET=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_HERMES=m +CONFIG_PCMCIA_IBMTR=m +CONFIG_PCMCIA_IOCTL=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_NETWAVE=m +CONFIG_PCMCIA_NINJA_SCSI=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_PROBE=y +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_RAYCS=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_SPECTRUM=m +CONFIG_PCMCIA_SYM53C500=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_WL3501=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_PCNET32=m +CONFIG_PCSPKR_PLATFORM=y +CONFIG_PCWATCHDOG=m +CONFIG_PD6729=m +CONFIG_PDA_POWER=m +CONFIG_PDC_ADMA=m +CONFIG_PHANTOM=m +CONFIG_PHONE=m +CONFIG_PHONE_IXJ=m +CONFIG_PHONE_IXJ_PCMCIA=m +CONFIG_PHYLIB=m +CONFIG_PHYSICAL_ALIGN=0x100000 +CONFIG_PHYSICAL_START=0x100000 +# CONFIG_PID_NS is not set +CONFIG_PLIP=m +CONFIG_PLIST=y +CONFIG_PLX_HERMES=m +CONFIG_PM=y +CONFIG_PM_DEBUG=y +CONFIG_PM_DISABLE_CONSOLE=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_STD_PARTITION="" +CONFIG_PM_TEST_SUSPEND=y +CONFIG_PM_TRACE=y +CONFIG_PM_TRACE_RTC=y +# CONFIG_PM_VERBOSE is not set +CONFIG_PNP=y +CONFIG_PNPACPI=y +CONFIG_PNPBIOS=y +CONFIG_PNPBIOS_PROC_FS=y +# CONFIG_PNP_DEBUG is not set +CONFIG_POSIX_MQUEUE=y +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_PPDEV=m +CONFIG_PPP=m +CONFIG_PPPOATM=m +CONFIG_PPPOE=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_SYNC_TTY=m +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_NOTIFIERS=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_PRINTER=m +CONFIG_PRINTK=y +CONFIG_PRINTK_TIME=y +CONFIG_PRINT_QUOTA_WARNING=y +CONFIG_PRISM2_USB=m +CONFIG_PRISM54=m +CONFIG_PROC_EVENTS=y +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_PROC_PID_CPUSET=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_VMCORE=y +CONFIG_PROFILING=y +CONFIG_PROTEON=m +# CONFIG_PROVE_LOCKING is not set +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +# CONFIG_PSS_HAVE_BOOT is not set +CONFIG_PSS_MIXER=y +CONFIG_QC_USB=m +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_QLA3XXX=m +CONFIG_QNX4FS_FS=m +CONFIG_QSEMI_PHY=m +CONFIG_QUOTA=y +CONFIG_QUOTACTL=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_R3964=m +# CONFIG_R6040 is not set +CONFIG_R8169=m +CONFIG_R8169_VLAN=y +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_AZTECH=m +CONFIG_RADIO_CADET=m +CONFIG_RADIO_GEMTEK=m +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_SF16FMR2=m +CONFIG_RADIO_TERRATEC=m +CONFIG_RADIO_TRUST=m +CONFIG_RADIO_TYPHOON=m +CONFIG_RADIO_TYPHOON_PROC_FS=y +CONFIG_RADIO_ZOLTRIX=m +CONFIG_RAID_ATTRS=m +CONFIG_RAW_DRIVER=m +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_REALTEK_PHY is not set +CONFIG_REED_SOLOMON=m +CONFIG_REED_SOLOMON_DEC16=y +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_FS=m +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_REISERFS_FS_XATTR=y +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_RELAY=y +CONFIG_RELOCATABLE=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_RFD_FTL=m +CONFIG_RFKILL=m +CONFIG_RFKILL_INPUT=m +CONFIG_RFKILL_LEDS=y +CONFIG_RIO=m +# CONFIG_RIO_OLDPCI is not set +CONFIG_RISCOM8=m +CONFIG_ROADRUNNER=m +# CONFIG_ROADRUNNER_LARGE_RINGS is not set +CONFIG_ROCKETPORT=m +CONFIG_ROMFS_FS=m +CONFIG_ROSE=m +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_RPCSEC_GSS_SPKM3=m +CONFIG_RT2400PCI=m +CONFIG_RT2400PCI_LEDS=y +CONFIG_RT2400PCI_RFKILL=y +CONFIG_RT2500PCI=m +CONFIG_RT2500PCI_LEDS=y +CONFIG_RT2500PCI_RFKILL=y +CONFIG_RT2500USB=m +CONFIG_RT2500USB_LEDS=y +CONFIG_RT2X00=m +# CONFIG_RT2X00_DEBUG is not set +CONFIG_RT2X00_LIB=m +# CONFIG_RT2X00_LIB_DEBUGFS is not set +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_LEDS=y +CONFIG_RT2X00_LIB_PCI=m +CONFIG_RT2X00_LIB_RFKILL=y +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT61PCI=m +CONFIG_RT61PCI_LEDS=y +CONFIG_RT61PCI_RFKILL=y +CONFIG_RT73USB=m +CONFIG_RT73USB_LEDS=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_DRV_CMOS=y +CONFIG_RTC_DRV_DS1305=m +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1374=m +# CONFIG_RTC_DRV_DS1511 is not set +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_DS1672=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_FM3130=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_M41T80=m +CONFIG_RTC_DRV_M41T80_WDT=y +CONFIG_RTC_DRV_M41T94=m +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_MAX6900=m +CONFIG_RTC_DRV_MAX6902=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +# CONFIG_RTC_DRV_R9701 is not set +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_RS5C372=m +# CONFIG_RTC_DRV_S35390A is not set +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_TEST=m +CONFIG_RTC_DRV_V3020=m +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=y +CONFIG_RTL8180=m +CONFIG_RTL8187=m +CONFIG_RT_GROUP_SCHED=y +CONFIG_RT_MUTEXES=y +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_RXKAD=m +CONFIG_S2IO=m +# CONFIG_SAMPLES is not set +CONFIG_SATA_AHCI=m +CONFIG_SATA_INIC162X=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_SATA_PMP=y +CONFIG_SATA_PROMISE=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIL24=m +CONFIG_SATA_SIS=m +CONFIG_SATA_SVW=m +CONFIG_SATA_SX4=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +CONFIG_SBC7240_WDT=m +CONFIG_SBC8360_WDT=m +CONFIG_SBC_EPX_C3_WATCHDOG=m +CONFIG_SBNI=m +# CONFIG_SBNI_MULTILINE is not set +CONFIG_SC1200_WDT=m +CONFIG_SC520_WDT=m +CONFIG_SC6600=y +CONFIG_SC6600_CDROM=4 +CONFIG_SC6600_CDROMBASE=0 +CONFIG_SC6600_JOY=y +CONFIG_SC92031=m +CONFIG_SCC=m +# CONFIG_SCC_DELAY is not set +# CONFIG_SCC_TRXECHO is not set +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_HRTICK=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_SCHED_SMT=y +# CONFIG_SCHED_TRACER is not set +CONFIG_SCSI=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_7000FASST=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_AHA152X=m +CONFIG_SCSI_AHA1542=m +CONFIG_SCSI_AHA1740=m +CONFIG_SCSI_AIC79XX=m +CONFIG_SCSI_AIC7XXX=m +# CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_SCSI_AIC94XX=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_ARCMSR_AER=y +CONFIG_SCSI_BUSLOGIC=m +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_DC395x=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_DH=m +CONFIG_SCSI_DH_ALUA=m +CONFIG_SCSI_DH_EMC=m +CONFIG_SCSI_DH_HP_SW=m +CONFIG_SCSI_DH_RDAC=m +CONFIG_SCSI_DMA=y +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_DPT_I2O=m +CONFIG_SCSI_DTC3280=m +CONFIG_SCSI_EATA=m +CONFIG_SCSI_EATA_LINKED_COMMANDS=y +CONFIG_SCSI_EATA_MAX_TAGS=16 +CONFIG_SCSI_EATA_TAGGED_QUEUE=y +CONFIG_SCSI_ENCLOSURE=m +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_FC_TGT_ATTRS=y +CONFIG_SCSI_FD_MCS=m +# CONFIG_SCSI_FLASHPOINT is not set +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +CONFIG_SCSI_GENERIC_NCR5380=m +CONFIG_SCSI_GENERIC_NCR5380_MMIO=m +CONFIG_SCSI_GENERIC_NCR53C400=y +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_IBMMCA=m +CONFIG_SCSI_IMM=m +CONFIG_SCSI_IN2000=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_DUMP is not set +# CONFIG_SCSI_IPR_TRACE is not set +CONFIG_SCSI_IPS=m +CONFIG_SCSI_ISCSITARGET=m +CONFIG_SCSI_ISCSI_ATTRS=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_LOWLEVEL=y +CONFIG_SCSI_LOWLEVEL_PCMCIA=y +CONFIG_SCSI_LPFC=m +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_MVSAS is not set +CONFIG_SCSI_NCR53C406A=m +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4 +CONFIG_SCSI_NCR53C8XX_SYNC=5 +CONFIG_SCSI_NCR_D700=m +CONFIG_SCSI_NCR_Q720=m +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_NSP32=m +CONFIG_SCSI_PAS16=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_PROC_FS=y +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLOGIC_FAS=m +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_HOST_SMP=y +CONFIG_SCSI_SAS_LIBSAS=m +# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_SIM710=m +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_SRP=m +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C416=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_T128=m +CONFIG_SCSI_TGT=m +CONFIG_SCSI_U14_34F=m +CONFIG_SCSI_U14_34F_LINKED_COMMANDS=y +CONFIG_SCSI_U14_34F_MAX_TAGS=8 +CONFIG_SCSI_U14_34F_TAGGED_QUEUE=y +CONFIG_SCSI_ULTRASTOR=m +CONFIG_SCSI_WAIT_SCAN=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCx200=m +CONFIG_SCx200HR_TIMER=m +CONFIG_SCx200_ACB=m +CONFIG_SCx200_GPIO=m +CONFIG_SCx200_I2C=m +CONFIG_SCx200_I2C_SCL=12 +CONFIG_SCx200_I2C_SDA=13 +CONFIG_SCx200_WDT=m +CONFIG_SDIO_UART=m +CONFIG_SDLA=m +CONFIG_SEALEVEL_4021=m +CONFIG_SECCOMP=y +CONFIG_SECURITY=y +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 +CONFIG_SECURITY_APPARMOR_DISABLE=y +CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0 +CONFIG_SECURITY_FILE_CAPABILITIES=y +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0 +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_DISABLE=y +# CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT is not set +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +CONFIG_SECURITY_SMACK=y +CONFIG_SEEQ8005=m +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SENSORS_ABITUGURU=m +CONFIG_SENSORS_ABITUGURU3=m +CONFIG_SENSORS_AD7414=m +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADCXX=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADS7828=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_ADT7473=m +CONFIG_SENSORS_APPLESMC=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_CORETEMP=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_FSCHMD=m +CONFIG_SENSORS_FSCPOS=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_HDAPS=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_IBMAEM=m +CONFIG_SENSORS_IBMPEX=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_K8TEMP=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_MAX6875=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_SIS5595=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_TSL2550=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83L786NG=m +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_ACCENT=m +CONFIG_SERIAL_8250_BOCA=m +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_CS=m +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_EXAR_ST16C554=m +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_FOURPORT=m +CONFIG_SERIAL_8250_HUB6=m +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_MCA=m +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_PNP=y +CONFIG_SERIAL_8250_RSA=y +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_JSM=m +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_SERIO=y +CONFIG_SERIO_CT82C710=m +CONFIG_SERIO_I8042=y +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_PCIPS2=m +CONFIG_SERIO_RAW=m +CONFIG_SERIO_SERPORT=m +CONFIG_SFC=m +CONFIG_SGI_IOC4=m +CONFIG_SGI_PARTITION=y +CONFIG_SHMEM=y +CONFIG_SIGMATEL_FIR=m +CONFIG_SIGNALFD=y +CONFIG_SIS190=m +CONFIG_SIS900=m +CONFIG_SKFP=m +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKISA=m +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SLAB is not set +CONFIG_SLABINFO=y +CONFIG_SLHC=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_MODE_SLIP6=y +CONFIG_SLIP_SMART=y +# CONFIG_SLOB is not set +CONFIG_SLUB=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_SMC9194=m +CONFIG_SMCTR=m +CONFIG_SMC_IRCC_FIR=m +CONFIG_SMP=y +CONFIG_SMSC37B787_WDT=m +CONFIG_SMSC_PHY=m +CONFIG_SND=m +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_AC97_POWER_SAVE=y +CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0 +CONFIG_SND_AD1816A=m +CONFIG_SND_AD1848=m +CONFIG_SND_AD1848_LIB=m +CONFIG_SND_AD1889=m +CONFIG_SND_ADLIB=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ALS100=m +CONFIG_SND_ALS300=m +CONFIG_SND_ALS4000=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_ATIIXP_MODEM=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AW2=m +CONFIG_SND_AZT2320=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +# CONFIG_SND_BT87X_OVERCLOCK is not set +CONFIG_SND_BTSCO=m +CONFIG_SND_CA0106=m +CONFIG_SND_CMI8330=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_CS4231=m +CONFIG_SND_CS4231_LIB=m +CONFIG_SND_CS4232=m +CONFIG_SND_CS4236=m +CONFIG_SND_CS4281=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS5530=m +CONFIG_SND_CS5535AUDIO=m +CONFIG_SND_DARLA20=m +CONFIG_SND_DARLA24=m +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DRIVERS=y +CONFIG_SND_DT019X=m +CONFIG_SND_DUMMY=m +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_ECHO3G=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_EMU10K1X=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1688=m +CONFIG_SND_ES18XX=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_ES968=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X=m +CONFIG_SND_FM801_TEA575X_BOOL=y +CONFIG_SND_GINA20=m +CONFIG_SND_GINA24=m +CONFIG_SND_GUSCLASSIC=m +CONFIG_SND_GUSEXTREME=m +CONFIG_SND_GUSMAX=m +CONFIG_SND_HDA_CODEC_ANALOG=y +CONFIG_SND_HDA_CODEC_ATIHDMI=y +CONFIG_SND_HDA_CODEC_CMEDIA=y +CONFIG_SND_HDA_CODEC_CONEXANT=y +CONFIG_SND_HDA_CODEC_REALTEK=y +CONFIG_SND_HDA_CODEC_SI3054=y +CONFIG_SND_HDA_CODEC_SIGMATEL=y +CONFIG_SND_HDA_CODEC_VIA=y +CONFIG_SND_HDA_GENERIC=y +# CONFIG_SND_HDA_HWDEP is not set +CONFIG_SND_HDA_INTEL=m +CONFIG_SND_HDA_POWER_SAVE=y +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +CONFIG_SND_HDSP=m +CONFIG_SND_HDSPM=m +CONFIG_SND_HIFIER=m +CONFIG_SND_HWDEP=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INDIGO=m +CONFIG_SND_INDIGODJ=m +CONFIG_SND_INDIGOIO=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_INTERWAVE=m +CONFIG_SND_INTERWAVE_STB=m +CONFIG_SND_ISA=y +CONFIG_SND_KORG1212=m +CONFIG_SND_LAYLA20=m +CONFIG_SND_LAYLA24=m +CONFIG_SND_MAESTRO3=m +CONFIG_SND_MIA=m +CONFIG_SND_MIRO=m +CONFIG_SND_MIXART=m +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_MONA=m +CONFIG_SND_MPU401=m +CONFIG_SND_MPU401_UART=m +CONFIG_SND_MTPAV=m +CONFIG_SND_MTS64=m +CONFIG_SND_NM256=m +CONFIG_SND_OPL3SA2=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_OPL4_LIB=m +CONFIG_SND_OPTI92X_AD1848=m +CONFIG_SND_OPTI92X_CS4231=m +CONFIG_SND_OPTI93X=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_OXYGEN=m +CONFIG_SND_OXYGEN_LIB=m +CONFIG_SND_PCI=y +CONFIG_SND_PCM=m +CONFIG_SND_PCMCIA=y +CONFIG_SND_PCM_OSS=m +CONFIG_SND_PCM_OSS_PLUGINS=y +CONFIG_SND_PCSP=m +CONFIG_SND_PCXHR=m +CONFIG_SND_PDAUDIOCF=m +CONFIG_SND_PORTMAN2X4=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_RIPTIDE=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_SB16=m +CONFIG_SND_SB16_CSP=y +CONFIG_SND_SB16_DSP=m +CONFIG_SND_SB8=m +CONFIG_SND_SB8_DSP=m +CONFIG_SND_SBAWE=m +CONFIG_SND_SB_COMMON=m +CONFIG_SND_SC6000=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_SERIAL_U16550=m +CONFIG_SND_SGALAXY=m +CONFIG_SND_SIS7019=m +CONFIG_SND_SOC=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_SPI=y +CONFIG_SND_SSCAPE=m +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_TIMER=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y +CONFIG_SND_USB_USX2Y=m +# CONFIG_SND_VERBOSE_PRINTK is not set +CONFIG_SND_VERBOSE_PROCFS=y +CONFIG_SND_VIA82XX=m +CONFIG_SND_VIA82XX_MODEM=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_VIRTUOSO=m +CONFIG_SND_VMASTER=y +CONFIG_SND_VX222=m +CONFIG_SND_VXPOCKET=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_WAVEFRONT=m +CONFIG_SND_WAVEFRONT_FIRMWARE_IN_KERNEL=y +CONFIG_SND_YMFPCI=m +CONFIG_SOC_CAMERA=m +CONFIG_SOC_CAMERA_MT9M001=m +CONFIG_SOC_CAMERA_MT9V022=m +CONFIG_SOC_CAMERA_PLATFORM=m +CONFIG_SOFT_WATCHDOG=m +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_SONYPI=m +CONFIG_SONYPI_COMPAT=y +CONFIG_SONY_LAPTOP=m +CONFIG_SOUND=m +CONFIG_SOUND_AEDSP16=m +CONFIG_SOUND_DMAP=y +CONFIG_SOUND_KAHLUA=m +CONFIG_SOUND_MPU401=m +CONFIG_SOUND_MSNDCLAS=m +CONFIG_SOUND_MSNDPIN=m +CONFIG_SOUND_MSS=m +CONFIG_SOUND_OSS=m +CONFIG_SOUND_PAS=m +CONFIG_SOUND_PRIME=m +CONFIG_SOUND_PSS=m +CONFIG_SOUND_SB=m +CONFIG_SOUND_SSCAPE=m +# CONFIG_SOUND_TRACEINIT is not set +CONFIG_SOUND_TRIX=m +CONFIG_SOUND_UART6850=m +CONFIG_SOUND_VMIDI=m +CONFIG_SOUND_YM3812=m +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_SPARSEMEM_STATIC=y +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +CONFIG_SPECIALIX=m +CONFIG_SPI=y +CONFIG_SPI_AT25=m +CONFIG_SPI_BITBANG=m +CONFIG_SPI_BUTTERFLY=m +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_LM70_LLP=m +CONFIG_SPI_MASTER=y +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_TLE62X0=m +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_SQUASHFS=m +# CONFIG_SQUASHFS_EMBEDDED is not set +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +CONFIG_SSB=m +CONFIG_SSB_B43_PCI_BRIDGE=y +# CONFIG_SSB_DEBUG is not set +CONFIG_SSB_DRIVER_PCICORE=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +# CONFIG_SSB_PCMCIAHOST is not set +CONFIG_SSB_PCMCIAHOST_POSSIBLE=y +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB_SPROM=y +CONFIG_SSFDC=m +CONFIG_STACKTRACE=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_STALDRV=y +# CONFIG_STANDALONE is not set +CONFIG_STOP_MACHINE=y +CONFIG_STP=m +CONFIG_STRICT_DEVMEM=y +CONFIG_STRIP=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_SUNGEM=m +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_SUNRPC_XPRT_RDMA=m +CONFIG_SUN_PARTITION=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_SWAP=y +CONFIG_SX=m +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_SYNCLINK_CS=m +CONFIG_SYNCLINK_GT=m +CONFIG_SYN_COOKIES=y +CONFIG_SYSCTL=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_SYSFS=y +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_SYSPROF_TRACER is not set +CONFIG_SYSV68_PARTITION=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_SYSV_FS=m +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_WACOM=m +CONFIG_TASKSTATS=y +# CONFIG_TASK_DELAY_ACCT is not set +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASK_XACCT=y +CONFIG_TC1100_WMI=m +CONFIG_TCG_ATMEL=m +CONFIG_TCG_INFINEON=m +CONFIG_TCG_NSC=m +CONFIG_TCG_TIS=m +CONFIG_TCG_TPM=m +CONFIG_TCIC=m +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=y +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_ILLINOIS=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_VEGAS=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_MD5SIG=y +CONFIG_TEHUTI=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_TELCLOCK=m +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_TEXTSEARCH_KMP=m +CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y +CONFIG_THINKPAD_ACPI=m +CONFIG_THINKPAD_ACPI_BAY=y +# CONFIG_THINKPAD_ACPI_DEBUG is not set +CONFIG_THINKPAD_ACPI_HOTKEY_POLL=y +CONFIG_THINKPAD_ACPI_VIDEO=y +CONFIG_TICK_ONESHOT=y +CONFIG_TIFM_7XX1=m +CONFIG_TIFM_CORE=m +CONFIG_TIGON3=m +CONFIG_TIMERFD=y +CONFIG_TIMER_STATS=y +# CONFIG_TINY_SHMEM is not set +CONFIG_TIPC=m +# CONFIG_TIPC_ADVANCED is not set +# CONFIG_TIPC_DEBUG is not set +CONFIG_TLAN=m +CONFIG_TLSF=m +# CONFIG_TLSF_DEBUG is not set +# CONFIG_TLSF_STATS is not set +# CONFIG_TLSUP is not set +CONFIG_TMD_HERMES=m +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMS380TR=m +CONFIG_TMSPCI=m +# CONFIG_TOIM3232_DONGLE is not set +# CONFIG_TOSHIBA is not set +CONFIG_TOSHIBA_FIR=m +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_FUJITSU=m +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_TOUCHSCREEN_HTCPEN=m +CONFIG_TOUCHSCREEN_INEXIO=m +CONFIG_TOUCHSCREEN_MK712=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +CONFIG_TOUCHSCREEN_TOUCHIT213=m +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_UCB1400=m +CONFIG_TOUCHSCREEN_USB_3M=y +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y +CONFIG_TOUCHSCREEN_USB_EGALAX=y +CONFIG_TOUCHSCREEN_USB_ETURBO=y +CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y +CONFIG_TOUCHSCREEN_USB_GOTOP=y +CONFIG_TOUCHSCREEN_USB_GUNZE=y +CONFIG_TOUCHSCREEN_USB_IDEALTEK=y +CONFIG_TOUCHSCREEN_USB_IRTOUCH=y +CONFIG_TOUCHSCREEN_USB_ITM=y +CONFIG_TOUCHSCREEN_USB_PANJIT=y +CONFIG_TOUCHSCREEN_WM9705=y +CONFIG_TOUCHSCREEN_WM9712=y +CONFIG_TOUCHSCREEN_WM9713=y +CONFIG_TOUCHSCREEN_WM97XX=m +CONFIG_TPS65010=m +CONFIG_TP_SMAPI=m +CONFIG_TP_SMAPI_EC=m +CONFIG_TR=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TRACING=y +CONFIG_TTPCI_EEPROM=m +CONFIG_TULIP=m +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_NAPI is not set +CONFIG_TUN=m +CONFIG_TUNER_3036=m +CONFIG_TYPHOON=m +CONFIG_UBIFS_FS=m +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +# CONFIG_UBIFS_FS_DEBUG is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_XATTR=y +CONFIG_UBIFS_FS_ZLIB=y +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_UFS_DEBUG is not set +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set +CONFIG_UID16=y +CONFIG_UIO=m +CONFIG_UIO_CIF=m +CONFIG_UIO_PDRV=m +CONFIG_UIO_PDRV_GENIRQ=m +CONFIG_UIO_SMX=m +CONFIG_ULI526X=m +CONFIG_ULTRA=m +CONFIG_ULTRA32=m +CONFIG_ULTRAMCA=m +CONFIG_ULTRIX_PARTITION=y +CONFIG_UNIX=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_UNUSED_SYMBOLS=y +CONFIG_USB=m +CONFIG_USBPCWATCHDOG=m +CONFIG_USB_ACM=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_APPLEIR=m +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARMLINUX=y +CONFIG_USB_ATM=m +CONFIG_USB_BELKIN=y +CONFIG_USB_BERRY_CHARGE=m +CONFIG_USB_C67X00_HCD=m +CONFIG_USB_CATC=m +CONFIG_USB_CDC_COMPOSITE=m +CONFIG_USB_CXACRU=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +# CONFIG_USB_DEBUG is not set +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +CONFIG_USB_DSBR=m +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EMI26=m +CONFIG_USB_EMI62=m +CONFIG_USB_EPSON2888=y +CONFIG_USB_ET61X251=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_EZUSB=y +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_FTDI_ELAN=m +CONFIG_USB_GADGET=m +CONFIG_USB_GADGETFS=m +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_GADGET_DUMMY_HCD is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_MUSB_HDRC is not set +CONFIG_USB_GADGET_NET2280=y +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_PXA25X is not set +# CONFIG_USB_GADGET_PXA27X is not set +# CONFIG_USB_GADGET_S3C2410 is not set +CONFIG_USB_GADGET_SELECTED=y +CONFIG_USB_GSPCA=m +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_SERIAL=m +CONFIG_USB_HID=m +CONFIG_USB_HIDDEV=y +CONFIG_USB_HIDINPUT_POWERBOOK=y +CONFIG_USB_HSO=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_IOWARRIOR=m +CONFIG_USB_IRDA=m +CONFIG_USB_ISIGHTFW=m +CONFIG_USB_ISP116X_HCD=m +CONFIG_USB_ISP1760_HCD=m +CONFIG_USB_KAWETH=m +CONFIG_USB_KBD=m +CONFIG_USB_KC2190=y +CONFIG_USB_KONICAWC=m +CONFIG_USB_LCD=m +CONFIG_USB_LD=m +CONFIG_USB_LED=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +# CONFIG_USB_MIDI_GADGET is not set +CONFIG_USB_MON=y +CONFIG_USB_MOUSE=m +CONFIG_USB_NET2280=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_NET_RNDIS_WLAN=m +CONFIG_USB_NET_ZAURUS=m +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OV511 is not set +CONFIG_USB_OV511_NEW=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_PHIDGET=m +CONFIG_USB_PHIDGETKIT=m +CONFIG_USB_PHIDGETMOTORCONTROL=m +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_PRINTER=m +CONFIG_USB_PWC=m +# CONFIG_USB_PWC_DEBUG is not set +CONFIG_USB_QUICKCAM_MESSENGER=m +CONFIG_USB_R8A66597_HCD=m +CONFIG_USB_RIO500=m +CONFIG_USB_RTL8150=m +CONFIG_USB_S2255=m +CONFIG_USB_SE401=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_CP2101=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_FUNSOFT=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_HP4X=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IPW=m +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_IUU is not set +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_MOTOROLA=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_SAFE=m +# CONFIG_USB_SERIAL_SAFE_PADDED is not set +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_SPCP8X5=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SI470X=m +CONFIG_USB_SISUSBVGA=m +# CONFIG_USB_SISUSBVGA_CON is not set +CONFIG_USB_SL811_CS=m +CONFIG_USB_SL811_HCD=m +CONFIG_USB_SN9C102=m +CONFIG_USB_SPEEDTOUCH=m +CONFIG_USB_STKWEBCAM=m +CONFIG_USB_STORAGE=m +CONFIG_USB_STORAGE_ALAUDA=y +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +CONFIG_USB_STORAGE_DATAFAB=y +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_KARMA=y +# CONFIG_USB_STORAGE_ONETOUCH is not set +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STV680=m +CONFIG_USB_SUPPORT=y +CONFIG_USB_SUSPEND=y +# CONFIG_USB_TEST is not set +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_U132_HCD=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_UHCI_HCD=m +CONFIG_USB_USBNET=m +CONFIG_USB_USS720=m +CONFIG_USB_VICAM=m +CONFIG_USB_VIDEO_CLASS=m +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +CONFIG_USB_W9968CF=m +CONFIG_USB_WDM=m +CONFIG_USB_XUSBATM=m +CONFIG_USB_ZC0301=m +CONFIG_USB_ZD1201=m +CONFIG_USB_ZERO=m +CONFIG_USB_ZR364XX=m +# CONFIG_USER_NS is not set +# CONFIG_USER_SCHED is not set +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_UTS_NS=y +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VERSION_SIGNATURE="" +CONFIG_VETH=m +CONFIG_VFAT_FS=m +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +CONFIG_VGASTATE=m +CONFIG_VGA_CONSOLE=y +CONFIG_VIA_FIR=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_VELOCITY=m +CONFIG_VIDEOBUF_DMA_CONTIG=m +CONFIG_VIDEOBUF_DMA_SG=m +CONFIG_VIDEOBUF_DVB=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_ALLOW_V4L1=y +CONFIG_VIDEO_AU0828=m +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_BT848_DVB=y +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_VIDEO_CAPTURE_DRIVERS=y +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA2=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_CS5345=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_CX18=m +CONFIG_VIDEO_CX2341X=m +CONFIG_VIDEO_CX23885=m +CONFIG_VIDEO_CX25840=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_ALSA=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_VP3054=m +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_DPC=m +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_EM28XX_ALSA=m +CONFIG_VIDEO_EM28XX_DVB=m +CONFIG_VIDEO_FB_IVTV=m +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_IR=m +CONFIG_VIDEO_IR_I2C=m +CONFIG_VIDEO_IVTV=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_M52790=m +CONFIG_VIDEO_MEDIA=m +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_MSP3400=m +CONFIG_VIDEO_MXB=m +CONFIG_VIDEO_OUTPUT_CONTROL=m +CONFIG_VIDEO_OV7670=m +CONFIG_VIDEO_OVCAMCHIP=m +CONFIG_VIDEO_PMS=m +CONFIG_VIDEO_PVRUSB2=m +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_PVRUSB2_DVB=y +CONFIG_VIDEO_PVRUSB2_SYSFS=y +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_VIDEO_SAA6588=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_SAA7111=m +CONFIG_VIDEO_SAA7114=m +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_ALSA=m +CONFIG_VIDEO_SAA7134_DVB=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_SAA717X=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_SELECT=y +CONFIG_VIDEO_SH_MOBILE_CEU=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TDA9875=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_TUNER=m +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m +CONFIG_VIDEO_USBVIDEO=m +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_V4L1=m +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=m +CONFIG_VIDEO_V4L2_COMMON=m +CONFIG_VIDEO_VIVI=m +CONFIG_VIDEO_VP27SMPX=m +CONFIG_VIDEO_VPX3220=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_WM8775=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_AVS6EYES=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_ZORAN_ZR36060=m +CONFIG_VIRTIO=m +CONFIG_VIRTIO_BALLOON=m +CONFIG_VIRTIO_BLK=m +CONFIG_VIRTIO_CONSOLE=m +CONFIG_VIRTIO_NET=m +CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_RING=m +CONFIG_VIRTUALIZATION=y +CONFIG_VIRT_TO_BUS=y +CONFIG_VITESSE_PHY=m +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_VLSI_FIR=m +CONFIG_VM86=y +CONFIG_VMI=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_VORTEX=m +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_VXFS_FS=m +CONFIG_W1=m +CONFIG_W1_CON=y +CONFIG_W1_MASTER_DS2482=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_GPIO=m +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_SLAVE_DS2433=m +# CONFIG_W1_SLAVE_DS2433_CRC is not set +CONFIG_W1_SLAVE_DS2760=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_THERM=m +CONFIG_W83627HF_WDT=m +CONFIG_W83697HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_W83977F_WDT=m +CONFIG_WAFER_WDT=m +CONFIG_WAN=y +CONFIG_WANXL=m +CONFIG_WAN_ROUTER=m +CONFIG_WAN_ROUTER_DRIVERS=m +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +CONFIG_WAVELAN=m +CONFIG_WD80x3=m +CONFIG_WDT=m +CONFIG_WDTPCI=m +CONFIG_WDT_501=y +CONFIG_WDT_501_PCI=y +CONFIG_WINBOND_840=m +CONFIG_WINBOND_FIR=m +CONFIG_WIRELESS_ACX=m +CONFIG_WIRELESS_AT76=m +CONFIG_WIRELESS_EXT=y +CONFIG_WIRELESS_EXT_SYSFS=y +CONFIG_WLAN_80211=y +CONFIG_WLAN_PRE80211=y +CONFIG_X25=m +CONFIG_X25_ASY=m +CONFIG_X86=y +CONFIG_X86_32=y +CONFIG_X86_32_SMP=y +# CONFIG_X86_64 is not set +CONFIG_X86_ACPI_CPUFREQ=m +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +CONFIG_X86_APM_BOOT=y +CONFIG_X86_BIOS_REBOOT=y +CONFIG_X86_BSWAP=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_CPU=y +CONFIG_X86_CPUFREQ_NFORCE2=m +CONFIG_X86_CPUID=m +# CONFIG_X86_ELAN is not set +# CONFIG_X86_E_POWERSAVER is not set +CONFIG_X86_FIND_SMP_CONFIG=y +CONFIG_X86_GENERIC=y +# CONFIG_X86_GENERICARCH is not set +CONFIG_X86_GX_SUSPMOD=m +CONFIG_X86_HT=y +CONFIG_X86_INTEL_USERCOPY=y +CONFIG_X86_INVLPG=y +CONFIG_X86_IO_APIC=y +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_LONGHAUL=m +CONFIG_X86_LONGRUN=m +# CONFIG_X86_MCE is not set +CONFIG_X86_MINIMUM_CPU_FAMILY=4 +CONFIG_X86_MPPARSE=y +CONFIG_X86_MSR=m +CONFIG_X86_P4_CLOCKMOD=m +# CONFIG_X86_PAT is not set +CONFIG_X86_PC=y +CONFIG_X86_PM_TIMER=y +CONFIG_X86_POPAD_OK=y +CONFIG_X86_POWERNOW_K6=m +CONFIG_X86_POWERNOW_K7=m +CONFIG_X86_POWERNOW_K7_ACPI=y +CONFIG_X86_POWERNOW_K8=m +CONFIG_X86_POWERNOW_K8_ACPI=y +CONFIG_X86_PPRO_FENCE=y +# CONFIG_X86_PTDUMP is not set +# CONFIG_X86_RDC321X is not set +CONFIG_X86_REBOOTFIXUPS=y +CONFIG_X86_RESERVE_LOW_64K=y +CONFIG_X86_SMP=y +CONFIG_X86_SPEEDSTEP_CENTRINO=m +CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y +CONFIG_X86_SPEEDSTEP_ICH=m +CONFIG_X86_SPEEDSTEP_LIB=m +CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK=y +CONFIG_X86_SPEEDSTEP_SMI=m +CONFIG_X86_TRAMPOLINE=y +# CONFIG_X86_VERBOSE_BOOTUP is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_VSMP is not set +CONFIG_X86_WP_WORKS_OK=y +CONFIG_X86_XADD=y +CONFIG_XEN_SAVE_RESTORE=y +CONFIG_XFRM=y +CONFIG_XFRM_IPCOMP=m +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_XFRM_SUB_POLICY is not set +CONFIG_XFRM_USER=m +# CONFIG_XFS_DEBUG is not set +CONFIG_XFS_FS=m +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_QUOTA=y +CONFIG_XFS_RT=y +CONFIG_XOR_BLOCKS=m +CONFIG_YAM=m +CONFIG_YELLOWFIN=m +CONFIG_YENTA=m +CONFIG_YENTA_ENE_TUNE=y +CONFIG_YENTA_O2=y +CONFIG_YENTA_RICOH=y +CONFIG_YENTA_TI=y +CONFIG_YENTA_TOSHIBA=y +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +CONFIG_ZISOFS=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZNET=m +CONFIG_ZONE_DMA=y +# CONFIG_ZONE_DMA32 is not set +CONFIG_ZONE_DMA_FLAG=1 --- linux-2.6.27.orig/debian/config/amd64/config.generic +++ linux-2.6.27/debian/config/amd64/config.generic @@ -0,0 +1,11 @@ +# +# Config options for config.generic automatically generated by splitconfig.pl +# +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_HZ=250 +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y --- linux-2.6.27.orig/debian/config/amd64/config.server +++ linux-2.6.27/debian/config/amd64/config.server @@ -0,0 +1,11 @@ +# +# Config options for config.server automatically generated by splitconfig.pl +# +# CONFIG_DEFAULT_CFQ is not set +CONFIG_DEFAULT_DEADLINE=y +CONFIG_DEFAULT_IOSCHED="deadline" +CONFIG_HZ=100 +CONFIG_HZ_100=y +# CONFIG_HZ_250 is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set --- linux-2.6.27.orig/debian/config/amd64/config +++ linux-2.6.27/debian/config/amd64/config @@ -0,0 +1,3470 @@ +# +# Common config options automatically generated by splitconfig.pl +# +CONFIG_3C359=m +CONFIG_60XX_WDT=m +CONFIG_64BIT=y +CONFIG_6PACK=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_8129=y +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_9P_FS=m +CONFIG_ABYSS=m +CONFIG_AC97_BUS=m +# CONFIG_ACCESSIBILITY is not set +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_ACER_WMI=m +CONFIG_ACORN_PARTITION=y +# CONFIG_ACORN_PARTITION_ADFS is not set +# CONFIG_ACORN_PARTITION_CUMANA is not set +# CONFIG_ACORN_PARTITION_EESOX is not set +CONFIG_ACORN_PARTITION_ICS=y +# CONFIG_ACORN_PARTITION_POWERTEC is not set +CONFIG_ACORN_PARTITION_RISCIX=y +CONFIG_ACPI=y +CONFIG_ACPI_AC=m +# CONFIG_ACPI_ASUS is not set +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BAY=m +CONFIG_ACPI_BLACKLIST_YEAR=0 +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_CONTAINER=m +# CONFIG_ACPI_CUSTOM_DSDT is not set +CONFIG_ACPI_CUSTOM_DSDT_FILE="" +CONFIG_ACPI_CUSTOM_DSDT_INITRD=y +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_DOCK=m +CONFIG_ACPI_EC=y +CONFIG_ACPI_FAN=m +CONFIG_ACPI_HOTPLUG_CPU=y +CONFIG_ACPI_NUMA=y +CONFIG_ACPI_PCI_SLOT=m +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PROCESSOR=m +CONFIG_ACPI_PROCFS=y +CONFIG_ACPI_PROCFS_POWER=y +CONFIG_ACPI_PROC_EVENT=y +CONFIG_ACPI_SBS=m +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_SYSFS_POWER=y +CONFIG_ACPI_SYSTEM=y +CONFIG_ACPI_THERMAL=m +CONFIG_ACPI_TOSHIBA=m +CONFIG_ACPI_VIDEO=m +CONFIG_ACPI_WMI=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ACT200L_DONGLE=m +CONFIG_ACTISYS_DONGLE=m +CONFIG_ADAPTEC_STARFIRE=m +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set +CONFIG_ADM8211=m +CONFIG_ADVANTECH_WDT=m +CONFIG_AEDSP16_MSS=y +# CONFIG_AEDSP16_SBPRO is not set +CONFIG_AFFS_FS=m +# CONFIG_AFS_DEBUG is not set +CONFIG_AFS_FS=m +CONFIG_AF_RXRPC=m +# CONFIG_AF_RXRPC_DEBUG is not set +CONFIG_AGP=y +CONFIG_AGP_AMD64=y +CONFIG_AGP_INTEL=m +CONFIG_AGP_SIS=m +CONFIG_AGP_VIA=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_DEBUG_ENABLE=y +CONFIG_AIC79XX_DEBUG_MASK=0 +CONFIG_AIC79XX_REG_PRETTY_PRINT=y +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_DEBUG_ENABLE=y +CONFIG_AIC7XXX_DEBUG_MASK=0 +CONFIG_AIC7XXX_REG_PRETTY_PRINT=y +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC94XX_DEBUG is not set +CONFIG_AIRO=m +CONFIG_AIRO_CS=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_ALI_FIR=m +CONFIG_AMD8111_ETH=m +CONFIG_AMD_IOMMU=y +CONFIG_AMIGA_PARTITION=y +CONFIG_ANON_INODES=y +CONFIG_APPLICOM=m +CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig" +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_DEFAULT_IDLE=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_HIBERNATION_HEADER=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SUPPORTS_AOUT=y +CONFIG_ARCH_SUPPORTS_MSI=y +CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y +CONFIG_ARCNET=m +CONFIG_ARCNET_1051=m +CONFIG_ARCNET_1201=m +CONFIG_ARCNET_CAP=m +CONFIG_ARCNET_COM20020=m +CONFIG_ARCNET_COM20020_CS=m +CONFIG_ARCNET_COM20020_PCI=m +CONFIG_ARCNET_COM90xx=m +CONFIG_ARCNET_COM90xxIO=m +CONFIG_ARCNET_RAW=m +CONFIG_ARCNET_RIM_I=m +# CONFIG_ARPD is not set +CONFIG_ASK_IP_FIB_HASH=y +CONFIG_ASUS_LAPTOP=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_AT24=m +CONFIG_ATA=m +CONFIG_ATALK=m +CONFIG_ATARI_PARTITION=y +CONFIG_ATA_ACPI=y +CONFIG_ATA_GENERIC=m +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_ATA_OVER_ETH=m +CONFIG_ATA_PIIX=m +CONFIG_ATA_SFF=y +# CONFIG_ATH5K is not set +CONFIG_ATH9K=m +CONFIG_ATL1=m +CONFIG_ATL1E=m +CONFIG_ATL2=m +CONFIG_ATM=y +CONFIG_ATMEL=m +CONFIG_ATM_AMBASSADOR=m +# CONFIG_ATM_AMBASSADOR_DEBUG is not set +CONFIG_ATM_BR2684=m +# CONFIG_ATM_BR2684_IPFILTER is not set +CONFIG_ATM_CLIP=y +# CONFIG_ATM_CLIP_NO_ICMP is not set +CONFIG_ATM_DRIVERS=y +# CONFIG_ATM_DUMMY is not set +CONFIG_ATM_ENI=m +# CONFIG_ATM_ENI_DEBUG is not set +# CONFIG_ATM_ENI_TUNE_BURST is not set +CONFIG_ATM_FIRESTREAM=m +CONFIG_ATM_FORE200E=m +CONFIG_ATM_FORE200E_DEBUG=0 +CONFIG_ATM_FORE200E_TX_RETRY=16 +# CONFIG_ATM_FORE200E_USE_TASKLET is not set +CONFIG_ATM_HE=m +CONFIG_ATM_HE_USE_SUNI=y +CONFIG_ATM_HORIZON=m +# CONFIG_ATM_HORIZON_DEBUG is not set +CONFIG_ATM_IA=m +# CONFIG_ATM_IA_DEBUG is not set +CONFIG_ATM_IDT77252=m +# CONFIG_ATM_IDT77252_DEBUG is not set +# CONFIG_ATM_IDT77252_RCV_ALL is not set +CONFIG_ATM_IDT77252_USE_SUNI=y +CONFIG_ATM_LANAI=m +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_TCP=m +CONFIG_ATM_ZATM=m +# CONFIG_ATM_ZATM_DEBUG is not set +CONFIG_ATP=m +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_ARCH=y +CONFIG_AUDIT_TREE=y +CONFIG_AUFS=m +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +CONFIG_AUFS_BRANCH_MAX_127=y +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +# CONFIG_AUFS_BRANCH_MAX_511 is not set +CONFIG_AUFS_BR_NFS=y +CONFIG_AUFS_BR_XFS=y +# CONFIG_AUFS_COMPAT is not set +# CONFIG_AUFS_DEBUG is not set +CONFIG_AUFS_DENY_WRITE_ACCESS_PATCH=y +# CONFIG_AUFS_DLGT is not set +CONFIG_AUFS_EXPORT=y +# CONFIG_AUFS_FSYNC_SUPER_PATCH is not set +CONFIG_AUFS_HINOTIFY=y +CONFIG_AUFS_HIN_OR_DLGT=y +CONFIG_AUFS_HIN_OR_FUSE=y +CONFIG_AUFS_INO_T_64=y +CONFIG_AUFS_LHASH_PATCH=y +CONFIG_AUFS_PUT_FILP_PATCH=y +# CONFIG_AUFS_ROBR is not set +CONFIG_AUFS_RR_SQUASHFS=y +CONFIG_AUFS_SEC_PERM_PATCH=y +CONFIG_AUFS_SHWH=y +CONFIG_AUFS_SPLICE_PATCH=y +CONFIG_AUFS_STAT=y +# CONFIG_AUFS_UNIONFS22_PATCH is not set +# CONFIG_AUFS_UNIONFS23_PATCH is not set +# CONFIG_AUFS_WORKAROUND_FUSE is not set +CONFIG_AUTOFS4_FS=m +CONFIG_AUTOFS_FS=m +CONFIG_AUXDISPLAY=y +CONFIG_AVERATEC_5100P=m +CONFIG_AX25=m +CONFIG_AX25_DAMA_SLAVE=y +CONFIG_B43=m +CONFIG_B43LEGACY=m +CONFIG_B43LEGACY_DEBUG=y +CONFIG_B43LEGACY_DMA=y +CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y +# CONFIG_B43LEGACY_DMA_MODE is not set +CONFIG_B43LEGACY_LEDS=y +CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y +CONFIG_B43LEGACY_PCI_AUTOSELECT=y +CONFIG_B43LEGACY_PIO=y +# CONFIG_B43LEGACY_PIO_MODE is not set +CONFIG_B43LEGACY_RFKILL=y +# CONFIG_B43_DEBUG is not set +CONFIG_B43_LEDS=y +CONFIG_B43_PCICORE_AUTOSELECT=y +CONFIG_B43_PCI_AUTOSELECT=y +# CONFIG_B43_PCMCIA is not set +CONFIG_B43_RFKILL=y +CONFIG_B44=m +CONFIG_B44_PCI=y +CONFIG_B44_PCICORE_AUTOSELECT=y +CONFIG_B44_PCI_AUTOSELECT=y +CONFIG_BACKLIGHT_CARILLO_RANCH=m +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CORGI=m +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_MBP_NVIDIA=m +CONFIG_BACKLIGHT_PROGEAR=m +# CONFIG_BACKTRACE_SELF_TEST is not set +CONFIG_BASE_FULL=y +CONFIG_BASE_SMALL=0 +CONFIG_BATTERY_DS2760=m +CONFIG_BAYCOM_PAR=m +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BEFS_FS=m +CONFIG_BFS_FS=m +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +CONFIG_BITREVERSE=y +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_BLK_CPQ_DA=m +CONFIG_BLK_DEV=y +CONFIG_BLK_DEV_3W_XXXX_RAID=m +# CONFIG_BLK_DEV_BSG is not set +CONFIG_BLK_DEV_COMPCACHE=m +# CONFIG_BLK_DEV_COMPCACHE_DEBUG is not set +# CONFIG_BLK_DEV_COMPCACHE_STATS is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_DM=m +CONFIG_BLK_DEV_DM_BBR=m +CONFIG_BLK_DEV_DRBD=m +CONFIG_BLK_DEV_FD=m +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_MD=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_BLK_DEV_SD=m +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_BLK_DEV_SX8=m +CONFIG_BLK_DEV_UB=m +CONFIG_BLK_DEV_UMEM=m +# CONFIG_BLK_DEV_XIP is not set +CONFIG_BLOCK=y +CONFIG_BLOCK_COMPAT=y +CONFIG_BNX2=m +CONFIG_BNX2X=m +CONFIG_BONDING=m +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_BOUNCE=y +CONFIG_BPQETHER=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_IP6=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_NFLOG=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_NETFILTER=y +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BROADCOM_PHY=m +CONFIG_BSD_DISKLABEL=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_BT=m +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIBTUART=m +CONFIG_BT_HCIBTUSB=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIVHCI=m +CONFIG_BT_HIDP=m +CONFIG_BT_L2CAP=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_SCO=m +CONFIG_BUG=y +CONFIG_CALGARY_IOMMU=y +CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT=y +# CONFIG_CAN is not set +CONFIG_CAN_PM_TRACE=y +CONFIG_CAPI_AVM=y +CONFIG_CAPI_EICON=y +CONFIG_CAPI_TRACE=y +CONFIG_CARDBUS=y +CONFIG_CARDMAN_4000=m +CONFIG_CARDMAN_4040=m +# CONFIG_CARMINE_DRAM_CUSTOM is not set +CONFIG_CASSINI=m +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +CONFIG_CFAG12864B=m +CONFIG_CFAG12864B_RATE=20 +CONFIG_CFG80211=m +CONFIG_CGROUPS=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_DEBUG is not set +# CONFIG_CGROUP_DEVICE is not set +CONFIG_CGROUP_MEM_RES_CTLR=y +CONFIG_CGROUP_NS=y +CONFIG_CGROUP_SCHED=y +CONFIG_CHECK_SIGNATURE=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T3=m +CONFIG_CHR_DEV_OSST=m +CONFIG_CHR_DEV_SCH=m +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_ST=m +CONFIG_CICADA_PHY=m +CONFIG_CIFS=m +# CONFIG_CIFS_DEBUG2 is not set +CONFIG_CIFS_DFS_UPCALL=y +CONFIG_CIFS_EXPERIMENTAL=y +# CONFIG_CIFS_STATS is not set +CONFIG_CIFS_UPCALL=y +CONFIG_CIFS_WEAK_PW_HASH=y +# CONFIG_CIFS_XATTR is not set +CONFIG_CISS_SCSI_TAPE=y +CONFIG_CLASSIC_RCU=y +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_CLS_U32_MARK=y +# CONFIG_CLS_U32_PERF is not set +CONFIG_CODA_FS=m +CONFIG_COMPAL_LAPTOP=m +CONFIG_COMPAT=y +CONFIG_COMPAT_BINFMT_ELF=y +# CONFIG_COMPAT_BRK is not set +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +# CONFIG_COMPAT_VDSO is not set +CONFIG_COMPUTONE=m +CONFIG_CONFIGFS_FS=m +CONFIG_CONNECTOR=y +CONFIG_CONSOLE_POLL=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_CONTEXT_SWITCH_TRACER=y +# CONFIG_CPA_DEBUG is not set +CONFIG_CPU5_WDT=m +CONFIG_CPUSETS=y +CONFIG_CPU_FREQ=y +# CONFIG_CPU_FREQ_DEBUG is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_CPU_FREQ_GOV_ONDEMAND=m +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_STAT=m +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_TABLE=m +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CRAMFS=y +CONFIG_CRASH_DUMP=y +CONFIG_CRC16=m +CONFIG_CRC32=y +CONFIG_CRC7=m +CONFIG_CRC_CCITT=m +CONFIG_CRC_ITU_T=m +CONFIG_CRC_T10DIF=m +CONFIG_CRYPTO=y +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_AES_X86_64=m +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_CTR=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_DEV_HIFN_795X=m +CONFIG_CRYPTO_DEV_HIFN_795X_RNG=y +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_GCM=m +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_LZO=m +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_RMD128=m +CONFIG_CRYPTO_RMD160=m +CONFIG_CRYPTO_RMD256=m +CONFIG_CRYPTO_RMD320=m +CONFIG_CRYPTO_SALSA20=m +CONFIG_CRYPTO_SALSA20_X86_64=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SEQIV=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_TWOFISH_X86_64=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_XTS=m +CONFIG_CYCLADES=m +CONFIG_CYCLADES_SYNC=m +CONFIG_CYCLOMX_X25=y +# CONFIG_CYZ_INTR is not set +# CONFIG_DAB is not set +CONFIG_DAVICOM_PHY=m +CONFIG_DCA=m +CONFIG_DCDBAS=m +CONFIG_DE2104X=m +CONFIG_DE4X5=m +CONFIG_DE600=m +CONFIG_DE620=m +# CONFIG_DEBUG_BOOT_PARAMS is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_DRIVER is not set +CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +CONFIG_DEBUG_MEMORY_INIT=y +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_NX_TEST is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_DEBUG_RODATA=y +# CONFIG_DEBUG_RODATA_TEST is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +CONFIG_DECNET=m +CONFIG_DECNET_NF_GRABULATOR=m +# CONFIG_DECNET_ROUTER is not set +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_BIC is not set +CONFIG_DEFAULT_CUBIC=y +# CONFIG_DEFAULT_HTCP is not set +CONFIG_DEFAULT_IO_DELAY_TYPE=1 +# CONFIG_DEFAULT_NOOP is not set +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_DEFAULT_VEGAS is not set +# CONFIG_DEFAULT_WESTWOOD is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_DEFXX=m +# CONFIG_DEFXX_MMIO is not set +CONFIG_DELL_RBU=m +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_DEVKMEM is not set +CONFIG_DEVPORT=y +CONFIG_DEV_APPLETALK=m +CONFIG_DE_AOC=y +CONFIG_DIGIEPCA=m +# CONFIG_DIRECT_GBPAGES is not set +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_DISPLAY_SUPPORT=m +# CONFIG_DL2K is not set +CONFIG_DLCI=m +CONFIG_DLCI_MAX=8 +CONFIG_DLM=m +# CONFIG_DLM_DEBUG is not set +CONFIG_DM9102=m +CONFIG_DMADEVICES=y +# CONFIG_DMAR is not set +# CONFIG_DMATEST is not set +CONFIG_DMA_ENGINE=y +CONFIG_DMI=y +CONFIG_DMIID=y +CONFIG_DM_CRYPT=m +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_DELAY is not set +CONFIG_DM_LOOP=m +CONFIG_DM_MIRROR=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_RAID45=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_UEVENT=y +CONFIG_DM_ZERO=m +CONFIG_DNOTIFY=y +CONFIG_DONGLE=y +CONFIG_DRM=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_I915=m +CONFIG_DRM_MGA=m +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_SAVAGE=m +CONFIG_DRM_SIS=m +CONFIG_DRM_TDFX=m +CONFIG_DRM_VIA=m +CONFIG_DRM_VIA_CHROME9=m +CONFIG_DS1682=m +CONFIG_DSCC4=m +CONFIG_DSCC4_PCISYNC=y +CONFIG_DSCC4_PCI_RST=y +CONFIG_DUMMY=m +CONFIG_DUMMY_CONSOLE=y +CONFIG_DVB_AU8522=m +CONFIG_DVB_AV7110=m +# CONFIG_DVB_AV7110_FIRMWARE is not set +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_B2C2_FLEXCOP=m +# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_BT8XX=m +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_CORE=m +CONFIG_DVB_BUDGET_PATCH=m +CONFIG_DVB_CAPTURE_DRIVERS=y +CONFIG_DVB_CINERGYT2=m +# CONFIG_DVB_CINERGYT2_TUNING is not set +CONFIG_DVB_CORE=m +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24123=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m +CONFIG_DVB_DRX397XD=m +# CONFIG_DVB_FE_CUSTOMISE is not set +CONFIG_DVB_ISL6405=m +CONFIG_DVB_ISL6421=m +CONFIG_DVB_L64781=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_LNBP21=m +CONFIG_DVB_MT312=m +CONFIG_DVB_MT352=m +CONFIG_DVB_NXT200X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_PLL=m +CONFIG_DVB_PLUTO2=m +CONFIG_DVB_S5H1409=m +CONFIG_DVB_S5H1411=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_SIANO_SMS1XXX=m +CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS=y +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_STV0297=m +CONFIG_DVB_STV0299=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_TDA10023=m +CONFIG_DVB_TDA10048=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_TDA10086=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_DVB_TUA6100=m +CONFIG_DVB_TUNER_DIB0070=m +CONFIG_DVB_TUNER_ITD1000=m +CONFIG_DVB_USB=m +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_USB_ANYSEE=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_CXUSB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_DIBUSB_MB=m +# CONFIG_DVB_USB_DIBUSB_MB_FAULTY is not set +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_DW2102=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_VES1820=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_ZL10353=m +CONFIG_E100=m +CONFIG_E1000=m +CONFIG_E1000E=m +# CONFIG_E1000E_ENABLED is not set +# CONFIG_E1000E_NEW is not set +# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set +CONFIG_EARLY_PRINTK=y +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_ECRYPT_FS=m +CONFIG_EDAC=y +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_E752X=m +CONFIG_EDAC_I3000=m +CONFIG_EDAC_I5000=m +CONFIG_EDAC_I5100=m +CONFIG_EDAC_I82975X=m +CONFIG_EDAC_MM_EDAC=m +CONFIG_EDD=y +CONFIG_EDD_OFF=y +CONFIG_EEEPC_LAPTOP=m +CONFIG_EEPRO100=m +CONFIG_EEPROM_93CX6=m +CONFIG_EFI=y +CONFIG_EFI_PARTITION=y +CONFIG_EFI_VARS=y +CONFIG_EFS_FS=m +CONFIG_ELF_CORE=y +# CONFIG_EMBEDDED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENC28J60 is not set +CONFIG_ENCLOSURE_SERVICES=m +CONFIG_EPIC100=m +CONFIG_EPOLL=y +CONFIG_EQUALIZER=m +CONFIG_ESI_DONGLE=m +CONFIG_EUROTECH_WDT=m +CONFIG_EVENTFD=y +CONFIG_EXPERIMENTAL=y +CONFIG_EXPORTFS=m +CONFIG_EXT2_FS=m +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT4DEV_FS=m +CONFIG_EXT4DEV_FS_POSIX_ACL=y +CONFIG_EXT4DEV_FS_SECURITY=y +CONFIG_EXT4DEV_FS_XATTR=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_FARSYNC=m +CONFIG_FAST_CMPXCHG_LOCAL=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_FS=m +# CONFIG_FAULT_INJECTION is not set +CONFIG_FB=y +CONFIG_FB_3DFX=m +# CONFIG_FB_3DFX_ACCEL is not set +CONFIG_FB_ARC=m +CONFIG_FB_ARK=m +CONFIG_FB_ASILIANT=y +CONFIG_FB_ATY=m +CONFIG_FB_ATY128=m +CONFIG_FB_ATY128_BACKLIGHT=y +CONFIG_FB_ATY_BACKLIGHT=y +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GENERIC_LCD=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_BACKLIGHT=y +CONFIG_FB_CARILLO_RANCH=m +CONFIG_FB_CARMINE=m +CONFIG_FB_CARMINE_DRAM_EVAL=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_CIRRUS=m +CONFIG_FB_CYBER2000=m +CONFIG_FB_DDC=m +CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_EFI=y +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_GEODE=y +CONFIG_FB_GEODE_GX=m +CONFIG_FB_GEODE_GX1=m +CONFIG_FB_GEODE_LX=m +CONFIG_FB_HECUBA=m +CONFIG_FB_HGA=m +# CONFIG_FB_HGA_ACCEL is not set +CONFIG_FB_IMAC=y +CONFIG_FB_IMSTT=y +CONFIG_FB_INTEL=m +# CONFIG_FB_INTEL_DEBUG is not set +CONFIG_FB_INTEL_I2C=y +CONFIG_FB_KYRO=m +CONFIG_FB_LE80578=m +# CONFIG_FB_MACMODES is not set +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_G=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MULTIHEAD=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_N411=m +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_NVIDIA=m +CONFIG_FB_NVIDIA_BACKLIGHT=y +# CONFIG_FB_NVIDIA_DEBUG is not set +CONFIG_FB_NVIDIA_I2C=y +CONFIG_FB_PM2=m +CONFIG_FB_PM2_FIFO_DISCONNECT=y +CONFIG_FB_PM3=m +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_BACKLIGHT=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RIVA=m +CONFIG_FB_RIVA_BACKLIGHT=y +# CONFIG_FB_RIVA_DEBUG is not set +CONFIG_FB_RIVA_I2C=y +CONFIG_FB_S1D13XXX=m +CONFIG_FB_S3=m +CONFIG_FB_SAVAGE=m +CONFIG_FB_SAVAGE_ACCEL=y +CONFIG_FB_SAVAGE_I2C=y +CONFIG_FB_SIS=m +CONFIG_FB_SIS_300=y +CONFIG_FB_SIS_315=y +CONFIG_FB_SM501=m +CONFIG_FB_SVGALIB=m +CONFIG_FB_SYS_COPYAREA=m +CONFIG_FB_SYS_FILLRECT=m +CONFIG_FB_SYS_FOPS=m +CONFIG_FB_SYS_IMAGEBLIT=m +CONFIG_FB_TILEBLITTING=y +CONFIG_FB_TRIDENT=m +# CONFIG_FB_TRIDENT_ACCEL is not set +CONFIG_FB_UVESA=m +CONFIG_FB_VESA=m +CONFIG_FB_VGA16=m +# CONFIG_FB_VIRTUAL is not set +CONFIG_FB_VOODOO1=m +CONFIG_FB_VT8623=m +CONFIG_FDDI=y +CONFIG_FEALNX=m +CONFIG_FIB_RULES=y +# CONFIG_FIREWIRE is not set +CONFIG_FIRMWARE_EDID=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_FIX_EARLYCON_MEM=y +# CONFIG_FLATMEM_MANUAL is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_8x8=y +CONFIG_FORCEDETH=m +# CONFIG_FORCEDETH_NAPI is not set +CONFIG_FRAMEBUFFER_CONSOLE=m +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FRAME_POINTER=y +CONFIG_FRAME_WARN=2048 +CONFIG_FSAM7400=m +CONFIG_FS_MBCACHE=m +CONFIG_FS_POSIX_ACL=y +CONFIG_FS_UNIONFS=m +CONFIG_FTL=m +CONFIG_FTRACE=y +# CONFIG_FTRACE_STARTUP_TEST is not set +CONFIG_FUJITSU_LAPTOP=m +# CONFIG_FUJITSU_LAPTOP_DEBUG is not set +CONFIG_FUSE_FS=m +CONFIG_FUSION=y +CONFIG_FUSION_CTL=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_LAN=m +CONFIG_FUSION_LOGGING=y +CONFIG_FUSION_MAX_SGE=128 +CONFIG_FUSION_SAS=m +CONFIG_FUSION_SPI=m +CONFIG_FUTEX=y +CONFIG_FW_LOADER=y +CONFIG_GACT_PROB=y +CONFIG_GAMEPORT=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GARP=m +CONFIG_GART_IOMMU=y +CONFIG_GENERIC_ACL=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_GENERIC_CPU=y +CONFIG_GENERIC_FIND_FIRST_BIT=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_ISA_DMA=y +# CONFIG_GENERIC_LOCKBREAK is not set +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_DLM=m +CONFIG_GFS_FS=m +CONFIG_GIGASET_BASE=m +# CONFIG_GIGASET_DEBUG is not set +CONFIG_GIGASET_M101=m +CONFIG_GIGASET_M105=m +# CONFIG_GIGASET_UNDOCREQ is not set +CONFIG_GIRBIL_DONGLE=m +CONFIG_GNBD=m +CONFIG_GPIOLIB=y +CONFIG_GPIO_MAX7301=m +CONFIG_GPIO_MAX732X=m +CONFIG_GPIO_MCP23S08=m +CONFIG_GPIO_PCA953X=m +CONFIG_GPIO_PCF857X=m +CONFIG_GPIO_SYSFS=y +CONFIG_GROUP_SCHED=y +CONFIG_HAMACHI=m +CONFIG_HAMRADIO=y +CONFIG_HANGCHECK_TIMER=m +CONFIG_HAPPYMEAL=m +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_HAVE_ARCH_TRACEHOOK is not set +# CONFIG_HAVE_CLK is not set +CONFIG_HAVE_CPUMASK_OF_CPU_MAP=y +# CONFIG_HAVE_DMA_ATTRS is not set +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE=y +# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set +CONFIG_HAVE_IDE=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_KVM=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y +CONFIG_HDLC=m +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m +CONFIG_HDLC_RAW=m +CONFIG_HDLC_RAW_ETH=m +CONFIG_HDLC_X25=m +# CONFIG_HEADERS_CHECK is not set +CONFIG_HECI=m +CONFIG_HERMES=m +CONFIG_HFSPLUS_FS=m +CONFIG_HFS_FS=m +CONFIG_HIBERNATION=y +CONFIG_HID=m +CONFIG_HIDRAW=y +# CONFIG_HID_DEBUG is not set +# CONFIG_HID_FF is not set +CONFIG_HID_SUPPORT=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_HIPPI=y +CONFIG_HISAX_16_3=y +CONFIG_HISAX_1TR6=y +CONFIG_HISAX_AVM_A1_CS=m +CONFIG_HISAX_AVM_A1_PCMCIA=y +CONFIG_HISAX_BKM_A4T=y +# CONFIG_HISAX_DEBUG is not set +CONFIG_HISAX_DIEHLDIVA=y +CONFIG_HISAX_ELSA=y +CONFIG_HISAX_ELSA_CS=m +CONFIG_HISAX_ENTERNOW_PCI=y +CONFIG_HISAX_EURO=y +CONFIG_HISAX_FRITZPCI=y +CONFIG_HISAX_FRITZ_PCIPNP=m +CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HDLC=y +CONFIG_HISAX_HFC4S8S=m +CONFIG_HISAX_HFCUSB=m +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_HFC_SX=y +CONFIG_HISAX_MAX_CARDS=8 +CONFIG_HISAX_NETJET=y +CONFIG_HISAX_NETJET_U=y +CONFIG_HISAX_NI1=y +CONFIG_HISAX_NICCY=y +# CONFIG_HISAX_NO_KEYPAD is not set +# CONFIG_HISAX_NO_LLC is not set +# CONFIG_HISAX_NO_SENDCOMPLETE is not set +CONFIG_HISAX_S0BOX=y +CONFIG_HISAX_SCT_QUADRO=y +CONFIG_HISAX_SEDLBAUER=y +CONFIG_HISAX_SEDLBAUER_CS=m +CONFIG_HISAX_ST5481=m +CONFIG_HISAX_TELESPCI=y +CONFIG_HISAX_TELES_CS=m +CONFIG_HISAX_W6692=y +CONFIG_HOSTAP=m +CONFIG_HOSTAP_CS=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PCI=m +CONFIG_HOSTAP_PLX=m +CONFIG_HOTPLUG=y +CONFIG_HOTPLUG_CPU=y +CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI_ACPI=m +CONFIG_HOTPLUG_PCI_ACPI_IBM=m +CONFIG_HOTPLUG_PCI_CPCI=y +CONFIG_HOTPLUG_PCI_CPCI_GENERIC=m +CONFIG_HOTPLUG_PCI_CPCI_ZT5550=m +CONFIG_HOTPLUG_PCI_FAKE=m +CONFIG_HOTPLUG_PCI_PCIE=m +CONFIG_HOTPLUG_PCI_SHPC=m +CONFIG_HP100=m +CONFIG_HPET=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_HPET_MMAP=y +CONFIG_HPET_TIMER=y +CONFIG_HPFS_FS=m +CONFIG_HP_ILO=m +# CONFIG_HP_WATCHDOG is not set +CONFIG_HP_WMI=m +CONFIG_HTC_PASIC3=m +CONFIG_HT_IRQ=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_HVC_DRIVER=y +CONFIG_HVC_IRQ=y +CONFIG_HVC_XEN=y +CONFIG_HWMON=y +# CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_HWMON_VID=m +CONFIG_HW_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_AMD=m +CONFIG_HW_RANDOM_INTEL=m +CONFIG_HW_RANDOM_VIRTIO=m +CONFIG_HYSDN=m +CONFIG_HYSDN_CAPI=y +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_300 is not set +CONFIG_I2C=m +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCA=m +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD756_S4882=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=m +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set +# CONFIG_I2C_DEBUG_CORE is not set +CONFIG_I2C_GPIO=m +# CONFIG_I2C_HELPER_AUTO is not set +CONFIG_I2C_I801=m +CONFIG_I2C_ISCH=m +CONFIG_I2C_NFORCE2=m +CONFIG_I2C_NFORCE2_S4985=m +CONFIG_I2C_OCORES=m +CONFIG_I2C_PARPORT=m +CONFIG_I2C_PARPORT_LIGHT=m +CONFIG_I2C_PCA_PLATFORM=m +CONFIG_I2C_PIIX4=m +CONFIG_I2C_SIMTEC=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_STUB=m +CONFIG_I2C_TAOS_EVM=m +CONFIG_I2C_TINY_USB=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_VOODOO3=m +CONFIG_I2O=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_BUS=m +CONFIG_I2O_CONFIG=m +CONFIG_I2O_CONFIG_OLD_IOCTL=y +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_EXT_ADAPTEC_DMA64=y +CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y +CONFIG_I2O_PROC=m +CONFIG_I2O_SCSI=m +CONFIG_I6300ESB_WDT=m +CONFIG_I82092=m +CONFIG_I8K=m +CONFIG_IA32_AOUT=m +CONFIG_IA32_EMULATION=y +CONFIG_IB700_WDT=m +CONFIG_IBMASR=m +CONFIG_IBMOL=m +CONFIG_IBM_ASM=m +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +CONFIG_ICPLUS_PHY=m +# CONFIG_IDE is not set +CONFIG_IEEE1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_ETH1394_ROM_ENTRY=y +CONFIG_IEEE1394_OHCI1394=m +CONFIG_IEEE1394_PCILYNX=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE80211=m +CONFIG_IEEE80211_CRYPT_CCMP=m +CONFIG_IEEE80211_CRYPT_TKIP=m +CONFIG_IEEE80211_CRYPT_WEP=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IFB=m +CONFIG_IGB=m +# CONFIG_IGB_LRO is not set +# CONFIG_IKCONFIG is not set +CONFIG_INET=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET_AH=m +CONFIG_INET_DCCP_DIAG=m +CONFIG_INET_DIAG=y +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_LRO=m +CONFIG_INET_TCP_DIAG=y +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_AMSO1100=m +CONFIG_INFINIBAND_AMSO1100_DEBUG=y +CONFIG_INFINIBAND_CXGB3=m +# CONFIG_INFINIBAND_CXGB3_DEBUG is not set +CONFIG_INFINIBAND_IPATH=m +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_CM=y +CONFIG_INFINIBAND_IPOIB_DEBUG=y +# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set +CONFIG_INFINIBAND_ISER=m +CONFIG_INFINIBAND_MTHCA=m +CONFIG_INFINIBAND_MTHCA_DEBUG=y +# CONFIG_INFINIBAND_NES is not set +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_MEM=y +CONFIG_INFTL=m +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_INPUT=y +# CONFIG_INPUT_APANEL is not set +CONFIG_INPUT_ATI_REMOTE=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_ATLAS_BTNS=m +CONFIG_INPUT_EVBUG=m +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_FF_MEMLESS=m +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_KEYBOARD=y +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_MOUSE=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_PCSPKR=m +CONFIG_INPUT_POLLDEV=m +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_TABLET=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_UINPUT=m +CONFIG_INPUT_YEALINK=m +CONFIG_INTEL_IOATDMA=m +CONFIG_INTEL_MENLOW=m +# CONFIG_IOMMU_DEBUG is not set +CONFIG_IOMMU_HELPER=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_CFQ=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_NOOP=y +# CONFIG_IO_DELAY_0X80 is not set +CONFIG_IO_DELAY_0XED=y +# CONFIG_IO_DELAY_NONE is not set +CONFIG_IO_DELAY_TYPE_0X80=0 +CONFIG_IO_DELAY_TYPE_0XED=1 +CONFIG_IO_DELAY_TYPE_NONE=3 +CONFIG_IO_DELAY_TYPE_UDELAY=2 +# CONFIG_IO_DELAY_UDELAY is not set +CONFIG_IP1000=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_SECURITY=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IPC_NS=y +CONFIG_IPDDP=m +CONFIG_IPDDP_DECAP=y +CONFIG_IPDDP_ENCAP=y +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_POWEROFF=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPPP_FILTER=y +CONFIG_IPV6=m +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_MROUTE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +CONFIG_IPV6_PRIVACY=y +# CONFIG_IPV6_ROUTER_PREF is not set +CONFIG_IPV6_SIT=m +# CONFIG_IPV6_SUBTREES is not set +CONFIG_IPV6_TUNNEL=m +CONFIG_IPW2100=m +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +CONFIG_IPW2200=m +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +CONFIG_IPW2200_RADIOTAP=y +CONFIG_IPWIRELESS=m +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_DCCP=m +CONFIG_IP_DCCP_ACKVEC=y +CONFIG_IP_DCCP_CCID2=m +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=m +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_CCID3_RTO=100 +# CONFIG_IP_DCCP_DEBUG is not set +CONFIG_IP_DCCP_TFRC_LIB=m +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_SECURITY=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_IP_PNP is not set +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_SCTP=m +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_FTP=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_NQ=m +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_TAB_BITS=12 +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_WRR=m +CONFIG_IRCOMM=m +CONFIG_IRDA=m +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_DEBUG=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_ULTRA=y +CONFIG_IRLAN=m +CONFIG_IRNET=m +# CONFIG_IRQSOFF_TRACER is not set +CONFIG_IRTTY_SIR=m +CONFIG_ISA_DMA_API=y +CONFIG_ISCSI_IBFT=m +CONFIG_ISCSI_IBFT_FIND=y +CONFIG_ISCSI_TCP=m +CONFIG_ISDN=y +CONFIG_ISDN_AUDIO=y +CONFIG_ISDN_CAPI=m +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_CAPIDRV=m +CONFIG_ISDN_CAPI_CAPIFS=m +CONFIG_ISDN_CAPI_CAPIFS_BOOL=y +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_MAINT=m +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVERSION=m +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_C4=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y +CONFIG_ISDN_DRV_GIGASET=m +CONFIG_ISDN_DRV_HISAX=m +CONFIG_ISDN_I4L=m +CONFIG_ISDN_MPP=y +CONFIG_ISDN_PPP=y +CONFIG_ISDN_PPP_BSDCOMP=m +CONFIG_ISDN_PPP_VJ=y +CONFIG_ISDN_TTY_FAX=y +CONFIG_ISDN_X25=y +# CONFIG_ISI is not set +CONFIG_ISO9660_FS=m +CONFIG_IT8712F_WDT=m +CONFIG_ITCO_VENDOR_SUPPORT=y +CONFIG_ITCO_WDT=m +CONFIG_IWL3945=m +# CONFIG_IWL3945_DEBUG is not set +CONFIG_IWL3945_LEDS=y +CONFIG_IWL3945_RFKILL=y +CONFIG_IWL3945_SPECTRUM_MEASUREMENT=y +CONFIG_IWL4965=y +CONFIG_IWL5000=y +CONFIG_IWLAGN=m +CONFIG_IWLAGN_LEDS=y +CONFIG_IWLAGN_SPECTRUM_MEASUREMENT=y +CONFIG_IWLCORE=m +CONFIG_IWLWIFI=m +# CONFIG_IWLWIFI_DEBUG is not set +CONFIG_IWLWIFI_LEDS=y +CONFIG_IWLWIFI_RFKILL=y +CONFIG_IXGB=m +CONFIG_IXGBE=m +CONFIG_JBD=m +CONFIG_JBD2=m +# CONFIG_JBD2_DEBUG is not set +# CONFIG_JBD_DEBUG is not set +CONFIG_JFFS2_CMODE_FAVOURLZO=y +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_SUMMARY is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFS_DEBUG is not set +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +CONFIG_JFS_STATISTICS=y +CONFIG_JOLIET=y +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_232=y +CONFIG_JOYSTICK_IFORCE_USB=y +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_ZHENHUA=m +CONFIG_K8_NB=y +CONFIG_K8_NUMA=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_KARMA_PARTITION=y +CONFIG_KEXEC=y +CONFIG_KEYBOARD_ATKBD=y +CONFIG_KEYBOARD_GPIO=m +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_NEWTON=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_KEYBOARD_SUNKBD=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +CONFIG_KGDB=y +CONFIG_KGDB_SERIAL_CONSOLE=y +# CONFIG_KGDB_TESTS is not set +CONFIG_KINGSUN_DONGLE=m +CONFIG_KMOD=y +CONFIG_KPROBES=y +# CONFIG_KPROBES_SANITY_TEST is not set +CONFIG_KRETPROBES=y +CONFIG_KS0108=m +CONFIG_KS0108_DELAY=2 +CONFIG_KS0108_PORT=0x378 +CONFIG_KS959_DONGLE=m +CONFIG_KSDAZZLE_DONGLE=m +# CONFIG_KTIME_SCALAR is not set +CONFIG_KVM=m +CONFIG_KVM_AMD=m +CONFIG_KVM_CLOCK=y +CONFIG_KVM_GUEST=y +CONFIG_KVM_INTEL=m +# CONFIG_KVM_TRACE is not set +CONFIG_LANMEDIA=m +CONFIG_LAPB=m +CONFIG_LAPBETHER=m +CONFIG_LATENCYTOP=y +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_ILI9320=m +CONFIG_LCD_LTV350QV=m +CONFIG_LCD_PLATFORM=m +CONFIG_LCD_VGG2432A4=m +# CONFIG_LDM_DEBUG is not set +CONFIG_LDM_PARTITION=y +CONFIG_LEDS_CLASS=m +# CONFIG_LEDS_CLEVO_MAIL is not set +CONFIG_LEDS_GPIO=m +CONFIG_LEDS_PCA9532=m +CONFIG_LEDS_PCA955X=m +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=m +CONFIG_LEDS_TRIGGER_HEARTBEAT=m +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LIBCRC32C=m +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_CS=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_LIBERTAS_SDIO=m +CONFIG_LIBERTAS_USB=m +CONFIG_LIRC_ATIUSB=m +CONFIG_LIRC_BT829=m +CONFIG_LIRC_CMDIR=m +CONFIG_LIRC_DEV=m +# CONFIG_LIRC_GPIO is not set +CONFIG_LIRC_I2C=m +CONFIG_LIRC_IGORPLUGUSB=m +CONFIG_LIRC_IMON=m +CONFIG_LIRC_IT87=m +CONFIG_LIRC_MCEUSB=m +CONFIG_LIRC_MCEUSB2=m +# CONFIG_LIRC_PARALLEL is not set +CONFIG_LIRC_PVR150=m +CONFIG_LIRC_SASEM=m +CONFIG_LIRC_SERIAL=m +CONFIG_LIRC_SERIAL_IGOR=m +CONFIG_LIRC_SIR=m +CONFIG_LIRC_STREAMZAP=m +CONFIG_LIRC_TTUSBIR=m +CONFIG_LITELINK_DONGLE=m +# CONFIG_LKDTM is not set +CONFIG_LLC=y +CONFIG_LLC2=m +CONFIG_LMPCM_USB=m +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_LOCKD=m +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_LOCKD_V4=y +CONFIG_LOCK_KERNEL=y +# CONFIG_LOCK_STAT is not set +# CONFIG_LOGO is not set +CONFIG_LOG_BUF_SHIFT=17 +# CONFIG_LP_CONSOLE is not set +CONFIG_LXT_PHY=m +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m +CONFIG_M25PXX_USE_FAST_READ=y +# CONFIG_M386 is not set +# CONFIG_M486 is not set +# CONFIG_M586 is not set +# CONFIG_M586MMX is not set +# CONFIG_M586TSC is not set +# CONFIG_M686 is not set +CONFIG_MA600_DONGLE=m +CONFIG_MAC80211=m +CONFIG_MAC80211_DEBUGFS=y +# CONFIG_MAC80211_DEBUG_MENU is not set +# CONFIG_MAC80211_HWSIM is not set +CONFIG_MAC80211_LEDS=y +CONFIG_MAC80211_MESH=y +CONFIG_MAC80211_RC_DEFAULT="pid" +CONFIG_MAC80211_RC_DEFAULT_PID=y +CONFIG_MAC80211_RC_PID=y +CONFIG_MACHZ_WDT=m +CONFIG_MACINTOSH_DRIVERS=y +CONFIG_MACVLAN=m +CONFIG_MAC_EMUMOUSEBTN=y +CONFIG_MAC_PARTITION=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MARKERS=y +CONFIG_MARVELL_PHY=m +CONFIG_MAX_RAW_DEVS=256 +# CONFIG_MCORE2 is not set +CONFIG_MCP2120_DONGLE=m +# CONFIG_MCRUSOE is not set +CONFIG_MCS_FIR=m +# CONFIG_MCYRIXIII is not set +CONFIG_MD=y +CONFIG_MDIO_BITBANG=m +CONFIG_MD_FAULTY=m +CONFIG_MD_LINEAR=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +CONFIG_MD_RAID5_RESHAPE=y +CONFIG_MEDIA_ATTACH=y +CONFIG_MEDIA_TUNER=m +# CONFIG_MEDIA_TUNER_CUSTOMIZE is not set +CONFIG_MEDIA_TUNER_MT2060=m +CONFIG_MEDIA_TUNER_MT20XX=m +CONFIG_MEDIA_TUNER_MT2131=m +CONFIG_MEDIA_TUNER_MT2266=m +CONFIG_MEDIA_TUNER_MXL5005S=m +CONFIG_MEDIA_TUNER_MXL5007T=m +CONFIG_MEDIA_TUNER_QT1010=m +CONFIG_MEDIA_TUNER_SIMPLE=m +CONFIG_MEDIA_TUNER_TDA18271=m +CONFIG_MEDIA_TUNER_TDA827X=m +CONFIG_MEDIA_TUNER_TDA8290=m +CONFIG_MEDIA_TUNER_TDA9887=m +CONFIG_MEDIA_TUNER_TEA5761=m +CONFIG_MEDIA_TUNER_TEA5767=m +CONFIG_MEDIA_TUNER_XC2028=m +CONFIG_MEDIA_TUNER_XC5000=m +# CONFIG_MEFFICEON is not set +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_SAS=m +# CONFIG_MEMSTICK is not set +# CONFIG_MEMTEST is not set +# CONFIG_MFD_CORE is not set +CONFIG_MFD_SM501=m +# CONFIG_MFD_SM501_GPIO is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MGEODEGX1 is not set +# CONFIG_MGEODE_LX is not set +CONFIG_MICROCODE=m +CONFIG_MICROCODE_OLD_INTERFACE=y +CONFIG_MIGRATION=y +CONFIG_MII=m +CONFIG_MINIX_FS=m +CONFIG_MINIX_SUBPARTITION=y +CONFIG_MISC_DEVICES=y +CONFIG_MISDN=m +CONFIG_MISDN_DSP=m +CONFIG_MISDN_HFCMULTI=m +CONFIG_MISDN_HFCPCI=m +CONFIG_MISDN_L1OIP=m +# CONFIG_MK6 is not set +# CONFIG_MK7 is not set +# CONFIG_MK8 is not set +CONFIG_MKISS=m +CONFIG_MLX4_CORE=m +CONFIG_MLX4_DEBUG=y +CONFIG_MLX4_INFINIBAND=m +CONFIG_MMC=m +CONFIG_MMC_BLOCK=m +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_RICOH_MMC=m +CONFIG_MMC_SDHCI=m +CONFIG_MMC_SDHCI_PCI=m +CONFIG_MMC_SDRICOH_CS=m +CONFIG_MMC_SPI=m +# CONFIG_MMC_TEST is not set +CONFIG_MMC_TIFM_SD=m +# CONFIG_MMC_UNSAFE_RESUME is not set +CONFIG_MMC_WBSD=m +# CONFIG_MMIOTRACE is not set +CONFIG_MMU=y +CONFIG_MMU_NOTIFIER=y +CONFIG_MM_OWNER=y +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MOUSE_APPLETOUCH=m +CONFIG_MOUSE_BCM5974=m +CONFIG_MOUSE_GPIO=m +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_PS2_TRACKPOINT=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_VSXXXAA=m +CONFIG_MOXA_INTELLIO=m +CONFIG_MOXA_SMARTIO=m +# CONFIG_MPENTIUM4 is not set +# CONFIG_MPENTIUMII is not set +# CONFIG_MPENTIUMIII is not set +# CONFIG_MPENTIUMM is not set +# CONFIG_MPSC is not set +CONFIG_MSDOS_FS=m +CONFIG_MSDOS_PARTITION=y +CONFIG_MSI_LAPTOP=m +CONFIG_MT9M001_PCA9536_SWITCH=y +CONFIG_MT9V022_PCA9536_SWITCH=y +CONFIG_MTD=m +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTD_ABSENT=m +CONFIG_MTD_ALAUDA=m +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_AR7_PARTS=m +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK2MTD=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_MTD_CFI=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_CFI_UTIL=m +CONFIG_MTD_CHAR=m +CONFIG_MTD_CK804XROM=m +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_CONCAT=m +CONFIG_MTD_DATAFLASH=m +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_DILNETPC=m +CONFIG_MTD_DILNETPC_BOOTSIZE=0x80000 +CONFIG_MTD_DOC2000=m +CONFIG_MTD_DOC2001=m +CONFIG_MTD_DOC2001PLUS=m +CONFIG_MTD_DOCECC=m +CONFIG_MTD_DOCPROBE=m +CONFIG_MTD_DOCPROBE_ADDRESS=0 +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_ESB2ROM=m +CONFIG_MTD_GEN_PROBE=m +CONFIG_MTD_ICHXROM=m +CONFIG_MTD_INTEL_VR_NOR=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_L440GX=m +CONFIG_MTD_M25P80=m +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +CONFIG_MTD_MTDRAM=m +CONFIG_MTD_NAND=m +CONFIG_MTD_NAND_CAFE=m +CONFIG_MTD_NAND_DISKONCHIP=m +# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set +CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0 +# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND_IDS=m +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +CONFIG_MTD_NAND_NANDSIM=m +CONFIG_MTD_NAND_PLATFORM=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +CONFIG_MTD_NETSC520=m +CONFIG_MTD_NETtel=m +CONFIG_MTD_ONENAND=m +CONFIG_MTD_ONENAND_2X_PROGRAM=y +# CONFIG_MTD_ONENAND_OTP is not set +CONFIG_MTD_ONENAND_SIM=m +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +CONFIG_MTD_OOPS=m +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_PCI=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +CONFIG_MTD_PHYSMAP_LEN=0x4000000 +CONFIG_MTD_PHYSMAP_START=0x8000000 +CONFIG_MTD_PLATRAM=m +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +CONFIG_MTD_RAM=m +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +CONFIG_MTD_REDBOOT_PARTS=m +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +CONFIG_MTD_ROM=m +CONFIG_MTD_SBC_GXX=m +CONFIG_MTD_SC520CDP=m +CONFIG_MTD_SCB2_FLASH=m +CONFIG_MTD_SLRAM=m +CONFIG_MTD_TS5500=m +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_BEB_RESERVE=1 +# CONFIG_MTD_UBI_DEBUG is not set +CONFIG_MTD_UBI_GLUEBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTRR=y +CONFIG_MTRR_SANITIZER=y +CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=0 +CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1 +# CONFIG_MVIAC3_2 is not set +# CONFIG_MVIAC7 is not set +CONFIG_MWAVE=m +# CONFIG_MWINCHIP2 is not set +# CONFIG_MWINCHIP3D is not set +# CONFIG_MWINCHIPC6 is not set +CONFIG_MYRI10GE=m +CONFIG_NAMESPACES=y +CONFIG_NATSEMI=m +CONFIG_NCPFS_EXTRAS=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_PACKET_SIGNING=y +# CONFIG_NCPFS_SMALLDOS is not set +CONFIG_NCPFS_STRONG=y +CONFIG_NCP_FS=m +CONFIG_NDISWRAPPER=m +CONFIG_NE2K_PCI=m +CONFIG_NEED_MULTIPLE_NODES=y +CONFIG_NET=y +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETDEVICES=y +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_XTABLES=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_OWNER=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_RATEEST=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_RATEEST=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETLABEL=y +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NETROM=m +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NETWORK_SECMARK=y +CONFIG_NETXEN_NIC=m +CONFIG_NET_9P=m +# CONFIG_NET_9P_DEBUG is not set +CONFIG_NET_9P_VIRTIO=m +CONFIG_NET_ACT_GACT=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_CLS=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_BASIC=m +# CONFIG_NET_CLS_FLOW is not set +CONFIG_NET_CLS_FW=m +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_DCCPPROBE=m +CONFIG_NET_DMA=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_ET131X=m +CONFIG_NET_ETHERNET=y +CONFIG_NET_FC=y +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_NET_IPIP=m +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_NET_PCI=y +CONFIG_NET_PCMCIA=y +CONFIG_NET_PKTGEN=m +CONFIG_NET_POCKET=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_NET_SB1000=m +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_ATM=m +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_FIFO=y +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_TCPPROBE=m +CONFIG_NET_TULIP=y +CONFIG_NET_VENDOR_3COM=y +CONFIG_NEW_LEDS=y +CONFIG_NFSD=m +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFS_ACL_SUPPORT=m +CONFIG_NFS_COMMON=y +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_NF_CONNTRACK_SANE is not set +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_ACCT=y +CONFIG_NF_CT_NETLINK=m +# CONFIG_NF_CT_PROTO_DCCP is not set +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_NAT=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_H323=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_PROTO_GRE=m +CONFIG_NF_NAT_PROTO_SCTP=m +CONFIG_NF_NAT_PROTO_UDPLITE=m +CONFIG_NF_NAT_SIP=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_NAT_TFTP=m +CONFIG_NIU=m +CONFIG_NL80211=y +CONFIG_NLS=y +CONFIG_NLS_ASCII=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m +CONFIG_NODES_SHIFT=6 +CONFIG_NODES_SPAN_OTHER_NODES=y +CONFIG_NORTEL_HERMES=m +CONFIG_NOZOMI=m +CONFIG_NO_HZ=y +CONFIG_NR_CPUS=64 +CONFIG_NS83820=m +CONFIG_NSC_FIR=m +CONFIG_NSC_GPIO=m +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_FS=m +# CONFIG_NTFS_RW is not set +CONFIG_NUMA=y +# CONFIG_NUMA_EMU is not set +CONFIG_NVRAM=m +CONFIG_N_HDLC=m +# CONFIG_OCFS2_DEBUG_FS is not set +CONFIG_OCFS2_DEBUG_MASKLOG=y +CONFIG_OCFS2_FS=m +CONFIG_OCFS2_FS_O2CB=m +CONFIG_OCFS2_FS_STATS=y +CONFIG_OCFS2_FS_USERSPACE_CLUSTER=m +CONFIG_OLD_BELKIN_DONGLE=m +CONFIG_OMFS_FS=m +CONFIG_OPROFILE=m +CONFIG_OPTIMIZE_INLINING=y +CONFIG_OSF_PARTITION=y +CONFIG_P54_COMMON=m +CONFIG_P54_PCI=m +CONFIG_P54_USB=m +CONFIG_P80211=m +CONFIG_PACKARDBELL_E5=m +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_PARAVIRT=y +CONFIG_PARAVIRT_CLOCK=y +# CONFIG_PARAVIRT_DEBUG is not set +CONFIG_PARAVIRT_GUEST=y +CONFIG_PARIDE=m +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_EPAT=m +# CONFIG_PARIDE_EPATC8 is not set +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PG=m +CONFIG_PARIDE_PT=m +CONFIG_PARPORT=m +CONFIG_PARPORT_1284=y +CONFIG_PARPORT_AX88796=m +# CONFIG_PARPORT_GSC is not set +CONFIG_PARPORT_NOT_PC=y +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_FIFO=y +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_SERIAL=m +CONFIG_PARTITION_ADVANCED=y +CONFIG_PATA_ACPI=m +CONFIG_PATA_ALI=m +CONFIG_PATA_AMD=m +CONFIG_PATA_ARTOP=m +CONFIG_PATA_ATIIXP=m +# CONFIG_PATA_CMD640_PCI is not set +CONFIG_PATA_CMD64X=m +CONFIG_PATA_CS5520=m +CONFIG_PATA_CS5530=m +# CONFIG_PATA_CYPRESS is not set +CONFIG_PATA_EFAR=m +CONFIG_PATA_HPT366=m +CONFIG_PATA_HPT37X=m +# CONFIG_PATA_HPT3X2N is not set +CONFIG_PATA_HPT3X3=m +# CONFIG_PATA_HPT3X3_DMA is not set +CONFIG_PATA_IT8213=m +CONFIG_PATA_IT821X=m +CONFIG_PATA_JMICRON=m +CONFIG_PATA_MARVELL=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_NETCELL=m +CONFIG_PATA_NINJA32=m +CONFIG_PATA_NS87410=m +CONFIG_PATA_NS87415=m +CONFIG_PATA_OLDPIIX=m +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +CONFIG_PATA_PCMCIA=m +CONFIG_PATA_PDC2027X=m +CONFIG_PATA_PDC_OLD=m +# CONFIG_PATA_RADISYS is not set +CONFIG_PATA_RZ1000=m +# CONFIG_PATA_SC1200 is not set +CONFIG_PATA_SCH=m +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_VIA=m +CONFIG_PATA_WINBOND=m +CONFIG_PC300=m +# CONFIG_PC300TOO is not set +# CONFIG_PC300_MLPPP is not set +CONFIG_PC8736x_GPIO=m +CONFIG_PC87413_WDT=m +CONFIG_PCCARD=m +CONFIG_PCCARD_NONSTATIC=m +CONFIG_PCI=y +CONFIG_PCI200SYN=m +CONFIG_PCIEAER=y +# CONFIG_PCIEASPM is not set +CONFIG_PCIEPORTBUS=y +CONFIG_PCIPCWATCHDOG=m +CONFIG_PCI_ATMEL=m +# CONFIG_PCI_DEBUG is not set +CONFIG_PCI_DIRECT=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_HERMES=m +CONFIG_PCI_LEGACY=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_MSI=y +CONFIG_PCMCIA=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_PCMCIA_AXNET=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_HERMES=m +CONFIG_PCMCIA_IOCTL=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_NETWAVE=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_RAYCS=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_SPECTRUM=m +CONFIG_PCMCIA_SYM53C500=m +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_WL3501=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_PCNET32=m +CONFIG_PCSPKR_PLATFORM=y +CONFIG_PD6729=m +CONFIG_PDA_POWER=m +CONFIG_PDC_ADMA=m +CONFIG_PHANTOM=m +CONFIG_PHONE=m +CONFIG_PHONE_IXJ=m +CONFIG_PHONE_IXJ_PCMCIA=m +CONFIG_PHYLIB=m +CONFIG_PHYSICAL_ALIGN=0x200000 +CONFIG_PHYSICAL_START=0x200000 +# CONFIG_PID_NS is not set +CONFIG_PLIP=m +CONFIG_PLIST=y +CONFIG_PLX_HERMES=m +CONFIG_PM=y +CONFIG_PM_DEBUG=y +CONFIG_PM_DISABLE_CONSOLE=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_STD_PARTITION="" +CONFIG_PM_TEST_SUSPEND=y +CONFIG_PM_TRACE=y +CONFIG_PM_TRACE_RTC=y +# CONFIG_PM_VERBOSE is not set +CONFIG_PNP=y +CONFIG_PNPACPI=y +# CONFIG_PNP_DEBUG is not set +CONFIG_POSIX_MQUEUE=y +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_PPDEV=m +CONFIG_PPP=m +CONFIG_PPPOATM=m +CONFIG_PPPOE=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_SYNC_TTY=m +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_NOTIFIERS=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_PRINTER=m +CONFIG_PRINTK=y +CONFIG_PRINTK_TIME=y +CONFIG_PRINT_QUOTA_WARNING=y +CONFIG_PRISM2_USB=m +CONFIG_PRISM54=m +CONFIG_PROC_EVENTS=y +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_PROC_PID_CPUSET=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_VMCORE=y +CONFIG_PROFILING=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +# CONFIG_PSS_HAVE_BOOT is not set +CONFIG_PSS_MIXER=y +CONFIG_QC_USB=m +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_QLA3XXX=m +CONFIG_QNX4FS_FS=m +CONFIG_QSEMI_PHY=m +CONFIG_QUOTA=y +CONFIG_QUOTACTL=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_R3964=m +# CONFIG_R6040 is not set +CONFIG_R8169=m +CONFIG_R8169_VLAN=y +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_GEMTEK_PCI=m +CONFIG_RADIO_MAESTRO=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RAID_ATTRS=m +CONFIG_RAW_DRIVER=m +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_REALTEK_PHY is not set +CONFIG_REED_SOLOMON=m +CONFIG_REED_SOLOMON_DEC16=y +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_FS=m +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_REISERFS_FS_XATTR=y +# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_RELAY=y +CONFIG_RELOCATABLE=y +CONFIG_RESOURCES_64BIT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_RFD_FTL=m +CONFIG_RFKILL=m +CONFIG_RFKILL_INPUT=m +CONFIG_RFKILL_LEDS=y +CONFIG_RIO=m +# CONFIG_RIO_OLDPCI is not set +CONFIG_RISCOM8=m +CONFIG_ROADRUNNER=m +# CONFIG_ROADRUNNER_LARGE_RINGS is not set +CONFIG_ROCKETPORT=m +CONFIG_ROMFS_FS=m +CONFIG_ROSE=m +CONFIG_RPCSEC_GSS_KRB5=m +CONFIG_RPCSEC_GSS_SPKM3=m +CONFIG_RT2400PCI=m +CONFIG_RT2400PCI_LEDS=y +CONFIG_RT2400PCI_RFKILL=y +CONFIG_RT2500PCI=m +CONFIG_RT2500PCI_LEDS=y +CONFIG_RT2500PCI_RFKILL=y +CONFIG_RT2500USB=m +CONFIG_RT2500USB_LEDS=y +CONFIG_RT2X00=m +# CONFIG_RT2X00_DEBUG is not set +CONFIG_RT2X00_LIB=m +# CONFIG_RT2X00_LIB_DEBUGFS is not set +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_LEDS=y +CONFIG_RT2X00_LIB_PCI=m +CONFIG_RT2X00_LIB_RFKILL=y +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT61PCI=m +CONFIG_RT61PCI_LEDS=y +CONFIG_RT61PCI_RFKILL=y +CONFIG_RT73USB=m +CONFIG_RT73USB_LEDS=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_DRV_CMOS=y +CONFIG_RTC_DRV_DS1305=m +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1374=m +# CONFIG_RTC_DRV_DS1511 is not set +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_DS1672=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_FM3130=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_M41T80=m +CONFIG_RTC_DRV_M41T80_WDT=y +CONFIG_RTC_DRV_M41T94=m +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_MAX6900=m +CONFIG_RTC_DRV_MAX6902=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +# CONFIG_RTC_DRV_R9701 is not set +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_RS5C372=m +# CONFIG_RTC_DRV_S35390A is not set +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_TEST=m +CONFIG_RTC_DRV_V3020=m +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=y +CONFIG_RTL8180=m +CONFIG_RTL8187=m +CONFIG_RT_GROUP_SCHED=y +CONFIG_RT_MUTEXES=y +# CONFIG_RT_MUTEX_TESTER is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_RXKAD=m +CONFIG_S2IO=m +# CONFIG_SAMPLES is not set +CONFIG_SATA_AHCI=m +CONFIG_SATA_INIC162X=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_SATA_PMP=y +CONFIG_SATA_PROMISE=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIL24=m +CONFIG_SATA_SIS=m +CONFIG_SATA_SVW=m +CONFIG_SATA_SX4=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +CONFIG_SBC8360_WDT=m +CONFIG_SBC_EPX_C3_WATCHDOG=m +CONFIG_SBNI=m +# CONFIG_SBNI_MULTILINE is not set +CONFIG_SC1200_WDT=m +CONFIG_SC520_WDT=m +CONFIG_SC6600=y +CONFIG_SC6600_CDROM=4 +CONFIG_SC6600_CDROMBASE=0 +CONFIG_SC6600_JOY=y +CONFIG_SC92031=m +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_HRTICK=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_SMT is not set +# CONFIG_SCHED_TRACER is not set +CONFIG_SCSI=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_AIC79XX=m +CONFIG_SCSI_AIC7XXX=m +# CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_SCSI_AIC94XX=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_ARCMSR_AER=y +CONFIG_SCSI_BUSLOGIC=m +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_DC390T=m +CONFIG_SCSI_DC395x=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_DH=m +CONFIG_SCSI_DH_ALUA=m +CONFIG_SCSI_DH_EMC=m +CONFIG_SCSI_DH_HP_SW=m +CONFIG_SCSI_DH_RDAC=m +CONFIG_SCSI_DMA=y +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_DPT_I2O=m +CONFIG_SCSI_EATA=m +CONFIG_SCSI_EATA_LINKED_COMMANDS=y +CONFIG_SCSI_EATA_MAX_TAGS=16 +CONFIG_SCSI_EATA_TAGGED_QUEUE=y +CONFIG_SCSI_ENCLOSURE=m +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_FC_TGT_ATTRS=y +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_GDTH=m +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_IMM=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_DUMP is not set +# CONFIG_SCSI_IPR_TRACE is not set +CONFIG_SCSI_IPS=m +CONFIG_SCSI_ISCSITARGET=m +CONFIG_SCSI_ISCSI_ATTRS=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_LOWLEVEL=y +CONFIG_SCSI_LOWLEVEL_PCMCIA=y +CONFIG_SCSI_LPFC=m +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_MVSAS is not set +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PPA=m +CONFIG_SCSI_PROC_FS=y +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_HOST_SMP=y +CONFIG_SCSI_SAS_LIBSAS=m +# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_SRP=m +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_TGT=m +CONFIG_SCSI_WAIT_SCAN=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SDIO_UART=m +CONFIG_SECCOMP=y +CONFIG_SECURITY=y +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 +CONFIG_SECURITY_APPARMOR_DISABLE=y +CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0 +CONFIG_SECURITY_FILE_CAPABILITIES=y +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0 +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_DISABLE=y +# CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT is not set +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +CONFIG_SECURITY_SMACK=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SENSORS_ABITUGURU=m +CONFIG_SENSORS_ABITUGURU3=m +CONFIG_SENSORS_AD7414=m +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADCXX=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADS7828=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_ADT7473=m +CONFIG_SENSORS_APPLESMC=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_CORETEMP=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_FSCHER=m +CONFIG_SENSORS_FSCHMD=m +CONFIG_SENSORS_FSCPOS=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_HDAPS=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_IBMAEM=m +CONFIG_SENSORS_IBMPEX=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_K8TEMP=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_MAX6875=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_SIS5595=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_TSL2550=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83L786NG=m +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_CS=m +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_PNP=y +CONFIG_SERIAL_8250_RSA=y +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_JSM=m +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_SERIO=y +CONFIG_SERIO_CT82C710=m +CONFIG_SERIO_I8042=y +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_PCIPS2=m +CONFIG_SERIO_RAW=m +CONFIG_SERIO_SERPORT=m +CONFIG_SFC=m +CONFIG_SGI_GRU=m +# CONFIG_SGI_GRU_DEBUG is not set +CONFIG_SGI_IOC4=m +CONFIG_SGI_PARTITION=y +CONFIG_SGI_XP=m +CONFIG_SHMEM=y +CONFIG_SIGMATEL_FIR=m +CONFIG_SIGNALFD=y +CONFIG_SIS190=m +CONFIG_SIS900=m +CONFIG_SKFP=m +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SLAB is not set +CONFIG_SLABINFO=y +CONFIG_SLHC=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_MODE_SLIP6=y +CONFIG_SLIP_SMART=y +# CONFIG_SLOB is not set +CONFIG_SLUB=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_SMC_IRCC_FIR=m +CONFIG_SMP=y +CONFIG_SMSC37B787_WDT=m +CONFIG_SMSC_PHY=m +CONFIG_SND=m +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_AC97_POWER_SAVE=y +CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0 +CONFIG_SND_AD1889=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ALS300=m +CONFIG_SND_ALS4000=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_ATIIXP_MODEM=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AW2=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +# CONFIG_SND_BT87X_OVERCLOCK is not set +CONFIG_SND_BTSCO=m +CONFIG_SND_CA0106=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_CS4281=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CS5530=m +CONFIG_SND_DARLA20=m +CONFIG_SND_DARLA24=m +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DRIVERS=y +CONFIG_SND_DUMMY=m +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_ECHO3G=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_EMU10K1X=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X=m +CONFIG_SND_FM801_TEA575X_BOOL=y +CONFIG_SND_GINA20=m +CONFIG_SND_GINA24=m +CONFIG_SND_HDA_CODEC_ANALOG=y +CONFIG_SND_HDA_CODEC_ATIHDMI=y +CONFIG_SND_HDA_CODEC_CMEDIA=y +CONFIG_SND_HDA_CODEC_CONEXANT=y +CONFIG_SND_HDA_CODEC_REALTEK=y +CONFIG_SND_HDA_CODEC_SI3054=y +CONFIG_SND_HDA_CODEC_SIGMATEL=y +CONFIG_SND_HDA_CODEC_VIA=y +CONFIG_SND_HDA_GENERIC=y +# CONFIG_SND_HDA_HWDEP is not set +CONFIG_SND_HDA_INTEL=m +CONFIG_SND_HDA_POWER_SAVE=y +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +CONFIG_SND_HDSP=m +CONFIG_SND_HDSPM=m +CONFIG_SND_HIFIER=m +CONFIG_SND_HWDEP=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INDIGO=m +CONFIG_SND_INDIGODJ=m +CONFIG_SND_INDIGOIO=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_KORG1212=m +CONFIG_SND_LAYLA20=m +CONFIG_SND_LAYLA24=m +CONFIG_SND_MAESTRO3=m +CONFIG_SND_MIA=m +CONFIG_SND_MIXART=m +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_MONA=m +CONFIG_SND_MPU401=m +CONFIG_SND_MPU401_UART=m +CONFIG_SND_MTPAV=m +CONFIG_SND_MTS64=m +CONFIG_SND_NM256=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_OXYGEN=m +CONFIG_SND_OXYGEN_LIB=m +CONFIG_SND_PCI=y +CONFIG_SND_PCM=m +CONFIG_SND_PCMCIA=y +CONFIG_SND_PCM_OSS=m +CONFIG_SND_PCM_OSS_PLUGINS=y +CONFIG_SND_PCSP=m +CONFIG_SND_PCXHR=m +CONFIG_SND_PDAUDIOCF=m +CONFIG_SND_PORTMAN2X4=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_RIPTIDE=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_SB16_DSP=m +CONFIG_SND_SB_COMMON=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_SERIAL_U16550=m +CONFIG_SND_SOC=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_SPI=y +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_TIMER=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y +CONFIG_SND_USB_USX2Y=m +# CONFIG_SND_VERBOSE_PRINTK is not set +CONFIG_SND_VERBOSE_PROCFS=y +CONFIG_SND_VIA82XX=m +CONFIG_SND_VIA82XX_MODEM=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_VIRTUOSO=m +CONFIG_SND_VMASTER=y +CONFIG_SND_VX222=m +CONFIG_SND_VXPOCKET=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_YMFPCI=m +CONFIG_SOC_CAMERA=m +CONFIG_SOC_CAMERA_MT9M001=m +CONFIG_SOC_CAMERA_MT9V022=m +CONFIG_SOC_CAMERA_PLATFORM=m +CONFIG_SOFT_WATCHDOG=m +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_SONYPI_COMPAT=y +CONFIG_SONY_LAPTOP=m +CONFIG_SOUND=m +CONFIG_SOUND_AEDSP16=m +CONFIG_SOUND_DMAP=y +CONFIG_SOUND_KAHLUA=m +CONFIG_SOUND_MPU401=m +CONFIG_SOUND_MSS=m +CONFIG_SOUND_OSS=m +CONFIG_SOUND_PAS=m +CONFIG_SOUND_PRIME=m +CONFIG_SOUND_PSS=m +CONFIG_SOUND_SB=m +CONFIG_SOUND_SSCAPE=m +# CONFIG_SOUND_TRACEINIT is not set +CONFIG_SOUND_TRIX=m +CONFIG_SOUND_UART6850=m +CONFIG_SOUND_VMIDI=m +CONFIG_SOUND_YM3812=m +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_MANUAL=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPECIALIX=m +CONFIG_SPI=y +CONFIG_SPI_AT25=m +CONFIG_SPI_BITBANG=m +CONFIG_SPI_BUTTERFLY=m +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_LM70_LLP=m +CONFIG_SPI_MASTER=y +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_TLE62X0=m +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_SQUASHFS=m +# CONFIG_SQUASHFS_EMBEDDED is not set +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +CONFIG_SSB=m +CONFIG_SSB_B43_PCI_BRIDGE=y +# CONFIG_SSB_DEBUG is not set +CONFIG_SSB_DRIVER_PCICORE=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +# CONFIG_SSB_PCMCIAHOST is not set +CONFIG_SSB_PCMCIAHOST_POSSIBLE=y +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB_SPROM=y +CONFIG_SSFDC=m +CONFIG_STACKTRACE=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_STALDRV=y +# CONFIG_STANDALONE is not set +CONFIG_STOP_MACHINE=y +CONFIG_STP=m +CONFIG_STRICT_DEVMEM=y +CONFIG_STRIP=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_SUNGEM=m +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_SUNRPC_XPRT_RDMA=m +CONFIG_SUN_PARTITION=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_SWAP=y +CONFIG_SWIOTLB=y +CONFIG_SX=m +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_SYNCLINK_CS=m +CONFIG_SYNCLINK_GT=m +CONFIG_SYN_COOKIES=y +CONFIG_SYSCTL=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_SYSFS=y +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_SYSPROF_TRACER is not set +CONFIG_SYSV68_PARTITION=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_COMPAT=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_SYSV_FS=m +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_WACOM=m +CONFIG_TASKSTATS=y +# CONFIG_TASK_DELAY_ACCT is not set +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASK_XACCT=y +CONFIG_TCG_ATMEL=m +CONFIG_TCG_INFINEON=m +CONFIG_TCG_NSC=m +CONFIG_TCG_TIS=m +CONFIG_TCG_TPM=m +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=y +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_ILLINOIS=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_VEGAS=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_MD5SIG=y +CONFIG_TEHUTI=m +CONFIG_TEKRAM_DONGLE=m +CONFIG_TELCLOCK=m +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_TEXTSEARCH_KMP=m +CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y +CONFIG_THINKPAD_ACPI=m +CONFIG_THINKPAD_ACPI_BAY=y +# CONFIG_THINKPAD_ACPI_DEBUG is not set +CONFIG_THINKPAD_ACPI_HOTKEY_POLL=y +CONFIG_THINKPAD_ACPI_VIDEO=y +CONFIG_TICK_ONESHOT=y +CONFIG_TIFM_7XX1=m +CONFIG_TIFM_CORE=m +CONFIG_TIGON3=m +CONFIG_TIMERFD=y +CONFIG_TIMER_STATS=y +# CONFIG_TINY_SHMEM is not set +CONFIG_TIPC=m +# CONFIG_TIPC_ADVANCED is not set +# CONFIG_TIPC_DEBUG is not set +CONFIG_TLAN=m +CONFIG_TLSF=m +# CONFIG_TLSF_DEBUG is not set +# CONFIG_TLSF_STATS is not set +# CONFIG_TLSUP is not set +CONFIG_TMD_HERMES=m +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMS380TR=m +CONFIG_TMSPCI=m +# CONFIG_TOIM3232_DONGLE is not set +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_FUJITSU=m +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_TOUCHSCREEN_INEXIO=m +CONFIG_TOUCHSCREEN_MK712=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +CONFIG_TOUCHSCREEN_TOUCHIT213=m +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_UCB1400=m +CONFIG_TOUCHSCREEN_USB_3M=y +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y +CONFIG_TOUCHSCREEN_USB_EGALAX=y +CONFIG_TOUCHSCREEN_USB_ETURBO=y +CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y +CONFIG_TOUCHSCREEN_USB_GOTOP=y +CONFIG_TOUCHSCREEN_USB_GUNZE=y +CONFIG_TOUCHSCREEN_USB_IDEALTEK=y +CONFIG_TOUCHSCREEN_USB_IRTOUCH=y +CONFIG_TOUCHSCREEN_USB_ITM=y +CONFIG_TOUCHSCREEN_USB_PANJIT=y +CONFIG_TOUCHSCREEN_WM9705=y +CONFIG_TOUCHSCREEN_WM9712=y +CONFIG_TOUCHSCREEN_WM9713=y +CONFIG_TOUCHSCREEN_WM97XX=m +CONFIG_TPS65010=m +CONFIG_TP_SMAPI=m +CONFIG_TP_SMAPI_EC=m +CONFIG_TR=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TRACING=y +CONFIG_TTPCI_EEPROM=m +CONFIG_TULIP=m +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_NAPI is not set +CONFIG_TUN=m +CONFIG_TUNER_3036=m +CONFIG_TYPHOON=m +CONFIG_UBIFS_FS=m +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +# CONFIG_UBIFS_FS_DEBUG is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_XATTR=y +CONFIG_UBIFS_FS_ZLIB=y +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_UFS_DEBUG is not set +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set +CONFIG_UID16=y +CONFIG_UIO=m +CONFIG_UIO_CIF=m +CONFIG_UIO_PDRV=m +CONFIG_UIO_PDRV_GENIRQ=m +CONFIG_UIO_SMX=m +CONFIG_ULI526X=m +CONFIG_ULTRIX_PARTITION=y +CONFIG_UNIX=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_UNUSED_SYMBOLS=y +CONFIG_USB=m +CONFIG_USBPCWATCHDOG=m +CONFIG_USB_ACM=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_APPLEIR=m +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARMLINUX=y +CONFIG_USB_ATM=m +CONFIG_USB_BELKIN=y +CONFIG_USB_BERRY_CHARGE=m +CONFIG_USB_C67X00_HCD=m +CONFIG_USB_CATC=m +CONFIG_USB_CDC_COMPOSITE=m +CONFIG_USB_CXACRU=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +# CONFIG_USB_DEBUG is not set +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +CONFIG_USB_DSBR=m +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EMI26=m +CONFIG_USB_EMI62=m +CONFIG_USB_EPSON2888=y +CONFIG_USB_ET61X251=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_EZUSB=y +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_FTDI_ELAN=m +CONFIG_USB_GADGET=m +CONFIG_USB_GADGETFS=m +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_GADGET_DUMMY_HCD is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_MUSB_HDRC is not set +CONFIG_USB_GADGET_NET2280=y +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_PXA25X is not set +# CONFIG_USB_GADGET_PXA27X is not set +# CONFIG_USB_GADGET_S3C2410 is not set +CONFIG_USB_GADGET_SELECTED=y +CONFIG_USB_GSPCA=m +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_SERIAL=m +CONFIG_USB_HID=m +CONFIG_USB_HIDDEV=y +CONFIG_USB_HIDINPUT_POWERBOOK=y +CONFIG_USB_HSO=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_IOWARRIOR=m +CONFIG_USB_IRDA=m +CONFIG_USB_ISIGHTFW=m +CONFIG_USB_ISP116X_HCD=m +CONFIG_USB_ISP1760_HCD=m +CONFIG_USB_KAWETH=m +CONFIG_USB_KBD=m +CONFIG_USB_KC2190=y +CONFIG_USB_KONICAWC=m +CONFIG_USB_LCD=m +CONFIG_USB_LD=m +CONFIG_USB_LED=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LIBUSUAL=y +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +# CONFIG_USB_MIDI_GADGET is not set +CONFIG_USB_MON=y +CONFIG_USB_MOUSE=m +CONFIG_USB_NET2280=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_NET_RNDIS_WLAN=m +CONFIG_USB_NET_ZAURUS=m +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OV511 is not set +CONFIG_USB_OV511_NEW=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_PHIDGET=m +CONFIG_USB_PHIDGETKIT=m +CONFIG_USB_PHIDGETMOTORCONTROL=m +CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_PRINTER=m +CONFIG_USB_PWC=m +# CONFIG_USB_PWC_DEBUG is not set +CONFIG_USB_QUICKCAM_MESSENGER=m +CONFIG_USB_R8A66597_HCD=m +CONFIG_USB_RIO500=m +CONFIG_USB_RTL8150=m +CONFIG_USB_S2255=m +CONFIG_USB_SE401=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_CP2101=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_FUNSOFT=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_HP4X=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IPW=m +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_IUU is not set +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_MOTOROLA=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_SAFE=m +# CONFIG_USB_SERIAL_SAFE_PADDED is not set +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_SPCP8X5=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SI470X=m +CONFIG_USB_SISUSBVGA=m +# CONFIG_USB_SISUSBVGA_CON is not set +CONFIG_USB_SL811_CS=m +CONFIG_USB_SL811_HCD=m +CONFIG_USB_SN9C102=m +CONFIG_USB_SPEEDTOUCH=m +CONFIG_USB_STKWEBCAM=m +CONFIG_USB_STORAGE=m +CONFIG_USB_STORAGE_ALAUDA=y +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +CONFIG_USB_STORAGE_DATAFAB=y +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_KARMA=y +# CONFIG_USB_STORAGE_ONETOUCH is not set +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STV680=m +CONFIG_USB_SUPPORT=y +CONFIG_USB_SUSPEND=y +# CONFIG_USB_TEST is not set +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_U132_HCD=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_UHCI_HCD=m +CONFIG_USB_USBNET=m +CONFIG_USB_USS720=m +CONFIG_USB_VICAM=m +CONFIG_USB_VIDEO_CLASS=m +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +CONFIG_USB_W9968CF=m +CONFIG_USB_WDM=m +CONFIG_USB_XUSBATM=m +CONFIG_USB_ZC0301=m +CONFIG_USB_ZD1201=m +CONFIG_USB_ZERO=m +CONFIG_USB_ZR364XX=m +# CONFIG_USER_NS is not set +# CONFIG_USER_SCHED is not set +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_UTS_NS=y +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VERSION_SIGNATURE="" +CONFIG_VETH=m +CONFIG_VFAT_FS=m +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +CONFIG_VGASTATE=m +CONFIG_VGA_CONSOLE=y +CONFIG_VIA_FIR=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_VELOCITY=m +CONFIG_VIDEOBUF_DMA_CONTIG=m +CONFIG_VIDEOBUF_DMA_SG=m +CONFIG_VIDEOBUF_DVB=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_ALLOW_V4L1=y +CONFIG_VIDEO_AU0828=m +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_BT848_DVB=y +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_VIDEO_CAPTURE_DRIVERS=y +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA2=m +CONFIG_VIDEO_CPIA_PP=m +CONFIG_VIDEO_CPIA_USB=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_CS5345=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_CX18=m +CONFIG_VIDEO_CX2341X=m +CONFIG_VIDEO_CX23885=m +CONFIG_VIDEO_CX25840=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_ALSA=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_VP3054=m +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_DPC=m +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_EM28XX_ALSA=m +CONFIG_VIDEO_EM28XX_DVB=m +CONFIG_VIDEO_FB_IVTV=m +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_IR=m +CONFIG_VIDEO_IR_I2C=m +CONFIG_VIDEO_IVTV=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_M52790=m +CONFIG_VIDEO_MEDIA=m +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_MSP3400=m +CONFIG_VIDEO_MXB=m +CONFIG_VIDEO_OUTPUT_CONTROL=m +CONFIG_VIDEO_OV7670=m +CONFIG_VIDEO_OVCAMCHIP=m +CONFIG_VIDEO_PVRUSB2=m +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_PVRUSB2_DVB=y +CONFIG_VIDEO_PVRUSB2_SYSFS=y +CONFIG_VIDEO_SAA5246A=m +CONFIG_VIDEO_SAA5249=m +CONFIG_VIDEO_SAA6588=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_SAA7111=m +CONFIG_VIDEO_SAA7114=m +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_ALSA=m +CONFIG_VIDEO_SAA7134_DVB=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_VIDEO_SAA717X=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_SELECT=y +CONFIG_VIDEO_SH_MOBILE_CEU=m +CONFIG_VIDEO_STRADIS=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TDA9875=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_TUNER=m +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m +CONFIG_VIDEO_USBVIDEO=m +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_V4L1=m +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_VIDEO_V4L2=m +CONFIG_VIDEO_V4L2_COMMON=m +CONFIG_VIDEO_VIVI=m +CONFIG_VIDEO_VP27SMPX=m +CONFIG_VIDEO_VPX3220=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_WM8775=m +CONFIG_VIDEO_ZORAN=m +CONFIG_VIDEO_ZORAN_AVS6EYES=m +CONFIG_VIDEO_ZORAN_BUZ=m +CONFIG_VIDEO_ZORAN_DC10=m +CONFIG_VIDEO_ZORAN_DC30=m +CONFIG_VIDEO_ZORAN_LML33=m +CONFIG_VIDEO_ZORAN_LML33R10=m +CONFIG_VIDEO_ZORAN_ZR36060=m +CONFIG_VIRTIO=m +CONFIG_VIRTIO_BALLOON=m +CONFIG_VIRTIO_BLK=m +CONFIG_VIRTIO_CONSOLE=m +CONFIG_VIRTIO_NET=m +CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_RING=m +CONFIG_VIRTUALIZATION=y +CONFIG_VIRT_TO_BUS=y +CONFIG_VITESSE_PHY=m +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_VLSI_FIR=m +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_VORTEX=m +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_VXFS_FS=m +CONFIG_W1=m +CONFIG_W1_CON=y +CONFIG_W1_MASTER_DS2482=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_GPIO=m +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_SLAVE_DS2433=m +# CONFIG_W1_SLAVE_DS2433_CRC is not set +CONFIG_W1_SLAVE_DS2760=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_THERM=m +CONFIG_W83627HF_WDT=m +CONFIG_W83697HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_W83977F_WDT=m +CONFIG_WAFER_WDT=m +CONFIG_WAN=y +CONFIG_WANXL=m +CONFIG_WAN_ROUTER=m +CONFIG_WAN_ROUTER_DRIVERS=m +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +CONFIG_WDTPCI=m +CONFIG_WDT_501_PCI=y +CONFIG_WINBOND_840=m +CONFIG_WINBOND_FIR=m +CONFIG_WIRELESS_ACX=m +CONFIG_WIRELESS_AT76=m +CONFIG_WIRELESS_EXT=y +CONFIG_WIRELESS_EXT_SYSFS=y +CONFIG_WLAN_80211=y +CONFIG_WLAN_PRE80211=y +CONFIG_X25=m +CONFIG_X25_ASY=m +CONFIG_X86=y +# CONFIG_X86_32 is not set +CONFIG_X86_64=y +CONFIG_X86_64_ACPI_NUMA=y +CONFIG_X86_64_SMP=y +CONFIG_X86_ACPI_CPUFREQ=m +# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set +CONFIG_X86_BIOS_REBOOT=y +CONFIG_X86_CMOV=y +CONFIG_X86_CMPXCHG=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CPU=y +CONFIG_X86_CPUID=m +CONFIG_X86_DEBUGCTLMSR=y +# CONFIG_X86_ELAN is not set +CONFIG_X86_FIND_SMP_CONFIG=y +# CONFIG_X86_GENERICARCH is not set +CONFIG_X86_HT=y +CONFIG_X86_INTERNODE_CACHE_BYTES=128 +CONFIG_X86_IO_APIC=y +CONFIG_X86_L1_CACHE_BYTES=128 +CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_MCE=y +CONFIG_X86_MCE_AMD=y +CONFIG_X86_MCE_INTEL=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_MPPARSE=y +CONFIG_X86_MSR=m +# CONFIG_X86_P4_CLOCKMOD is not set +# CONFIG_X86_PAT is not set +CONFIG_X86_PC=y +CONFIG_X86_PM_TIMER=y +CONFIG_X86_POWERNOW_K8=m +CONFIG_X86_POWERNOW_K8_ACPI=y +# CONFIG_X86_PTDUMP is not set +CONFIG_X86_RESERVE_LOW_64K=y +CONFIG_X86_SMP=y +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_SPEEDSTEP_LIB is not set +CONFIG_X86_TRAMPOLINE=y +CONFIG_X86_TSC=y +# CONFIG_X86_VERBOSE_BOOTUP is not set +# CONFIG_X86_VOYAGER is not set +# CONFIG_X86_VSMP is not set +CONFIG_X86_WP_WORKS_OK=y +CONFIG_XEN=y +CONFIG_XEN_BALLOON=y +CONFIG_XEN_BLKDEV_FRONTEND=m +CONFIG_XEN_FBDEV_FRONTEND=m +CONFIG_XEN_KBDDEV_FRONTEND=m +CONFIG_XEN_MAX_DOMAIN_MEMORY=32 +CONFIG_XEN_NETDEV_FRONTEND=m +CONFIG_XEN_SAVE_RESTORE=y +CONFIG_XEN_SCRUB_PAGES=y +CONFIG_XFRM=y +CONFIG_XFRM_IPCOMP=m +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_XFRM_SUB_POLICY is not set +CONFIG_XFRM_USER=m +# CONFIG_XFS_DEBUG is not set +CONFIG_XFS_FS=m +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_QUOTA=y +CONFIG_XFS_RT=y +CONFIG_XOR_BLOCKS=m +CONFIG_YAM=m +CONFIG_YELLOWFIN=m +CONFIG_YENTA=m +CONFIG_YENTA_ENE_TUNE=y +CONFIG_YENTA_O2=y +CONFIG_YENTA_RICOH=y +CONFIG_YENTA_TI=y +CONFIG_YENTA_TOSHIBA=y +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +CONFIG_ZISOFS=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZONE_DMA=y +CONFIG_ZONE_DMA32=y +CONFIG_ZONE_DMA_FLAG=1 --- linux-2.6.27.orig/scripts/kernel-doc +++ linux-2.6.27/scripts/kernel-doc @@ -1758,6 +1758,40 @@ $state = 0; } +sub syscall_munge() { + my $void = 0; + + $prototype =~ s@[\r\n\t]+@ @gos; # strip newlines/CR's/tabs +## if ($prototype =~ m/SYSCALL_DEFINE0\s*\(\s*(a-zA-Z0-9_)*\s*\)/) { + if ($prototype =~ m/SYSCALL_DEFINE0/) { + $void = 1; +## $prototype = "long sys_$1(void)"; + } + + $prototype =~ s/SYSCALL_DEFINE.*\(/long sys_/; # fix return type & func name + if ($prototype =~ m/long (sys_.*?),/) { + $prototype =~ s/,/\(/; + } elsif ($void) { + $prototype =~ s/\)/\(void\)/; + } + + # now delete all of the odd-number commas in $prototype + # so that arg types & arg names don't have a comma between them + my $count = 0; + my $len = length($prototype); + if ($void) { + $len = 0; # skip the for-loop + } + for (my $ix = 0; $ix < $len; $ix++) { + if (substr($prototype, $ix, 1) eq ',') { + $count++; + if ($count % 2 == 1) { + substr($prototype, $ix, 1) = ' '; + } + } + } +} + sub process_state3_function($$) { my $x = shift; my $file = shift; @@ -1774,7 +1808,10 @@ $prototype =~ s@/\*.*?\*/@@gos; # strip comments. $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's. $prototype =~ s@^\s+@@gos; # strip leading spaces - dump_function($prototype,$file); + if ($prototype =~ /SYSCALL_DEFINE/) { + syscall_munge(); + } + dump_function($prototype, $file); reset_state(); } } --- linux-2.6.27.orig/scripts/package/builddeb +++ linux-2.6.27/scripts/package/builddeb @@ -15,15 +15,18 @@ version=$KERNELRELEASE revision=`cat .version` tmpdir="$objtree/debian/tmp" +fwdir="$objtree/debian/fwtmp" packagename=linux-$version +fwpackagename=linux-firmware-image if [ "$ARCH" == "um" ] ; then packagename=user-mode-linux-$version fi # Setup the directory structure -rm -rf "$tmpdir" +rm -rf "$tmpdir" "$fwdir" mkdir -p "$tmpdir/DEBIAN" "$tmpdir/lib" "$tmpdir/boot" +mkdir -p "$fwdir/DEBIAN" "$fwdir/lib" if [ "$ARCH" == "um" ] ; then mkdir -p "$tmpdir/usr/lib/uml/modules/$version" "$tmpdir/usr/share/doc/$packagename" "$tmpdir/usr/bin" fi @@ -107,6 +110,7 @@ Package: $packagename Provides: kernel-image-$version, linux-image-$version +Suggests: $fwpackagename Architecture: any Description: Linux kernel, version $version This package contains the Linux kernel, modules and corresponding other @@ -118,8 +122,24 @@ chown -R root:root "$tmpdir" chmod -R go-w "$tmpdir" +# Do we have firmware? Move it out of the way and build it into a package. +if [ -e "$tmpdir/lib/firmware" ]; then + mv "$tmpdir/lib/firmware" "$fwdir/lib/" + + cat <> debian/control + +Package: $fwpackagename +Architecture: all +Description: Linux kernel firmware, version $version + This package contains firmware from the Linux kernel, version $version +EOF + + dpkg-gencontrol -isp -p$fwpackagename -P"$fwdir" + dpkg --build "$fwdir" .. +fi + # Perform the final magic -dpkg-gencontrol -isp +dpkg-gencontrol -isp -p$packagename dpkg --build "$tmpdir" .. exit 0 --- linux-2.6.27.orig/scripts/package/mkspec +++ linux-2.6.27/scripts/package/mkspec @@ -64,8 +64,10 @@ echo "%install" echo "%ifarch ia64" echo 'mkdir -p $RPM_BUILD_ROOT/boot/efi $RPM_BUILD_ROOT/lib/modules' +echo 'mkdir -p $RPM_BUILD_ROOT/lib/firmware' echo "%else" echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib/modules' +echo 'mkdir -p $RPM_BUILD_ROOT/lib/firmware' echo "%endif" echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{_smp_mflags} modules_install' @@ -92,5 +94,6 @@ echo '%defattr (-, root, root)' echo "%dir /lib/modules" echo "/lib/modules/$KERNELRELEASE" +echo "/lib/firmware" echo "/boot/*" echo "" --- linux-2.6.27.orig/net/socket.c +++ linux-2.6.27/net/socket.c @@ -695,7 +695,7 @@ if (more) flags |= MSG_MORE; - return sock->ops->sendpage(sock, page, offset, size, flags); + return kernel_sendpage(sock, page, offset, size, flags); } static ssize_t sock_splice_read(struct file *file, loff_t *ppos, @@ -1216,7 +1216,7 @@ return __sock_create(&init_net, family, type, protocol, res, 1); } -asmlinkage long sys_socket(int family, int type, int protocol) +SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) { int retval; struct socket *sock; @@ -1257,8 +1257,8 @@ * Create a pair of connected sockets. */ -asmlinkage long sys_socketpair(int family, int type, int protocol, - int __user *usockvec) +SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, + int __user *, usockvec) { struct socket *sock1, *sock2; int fd1, fd2, err; @@ -1365,7 +1365,7 @@ * the protocol layer (having also checked the address is ok). */ -asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen) +SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen) { struct socket *sock; struct sockaddr_storage address; @@ -1394,7 +1394,7 @@ * ready for listening. */ -asmlinkage long sys_listen(int fd, int backlog) +SYSCALL_DEFINE2(listen, int, fd, int, backlog) { struct socket *sock; int err, fput_needed; @@ -1567,8 +1567,8 @@ #endif #endif -asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, - int __user *upeer_addrlen) +SYSCALL_DEFINE3(accept, int, fd, struct sockaddr __user *, upeer_sockaddr, + int __user *, upeer_addrlen) { return do_accept(fd, upeer_sockaddr, upeer_addrlen, 0); } @@ -1585,8 +1585,8 @@ * include the -EINPROGRESS status for such sockets. */ -asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, - int addrlen) +SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr, + int, addrlen) { struct socket *sock; struct sockaddr_storage address; @@ -1617,8 +1617,8 @@ * name to user space. */ -asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, - int __user *usockaddr_len) +SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr, + int __user *, usockaddr_len) { struct socket *sock; struct sockaddr_storage address; @@ -1648,8 +1648,8 @@ * name to user space. */ -asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr, - int __user *usockaddr_len) +SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr, + int __user *, usockaddr_len) { struct socket *sock; struct sockaddr_storage address; @@ -1680,9 +1680,9 @@ * the protocol. */ -asmlinkage long sys_sendto(int fd, void __user *buff, size_t len, - unsigned flags, struct sockaddr __user *addr, - int addr_len) +SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, + unsigned, flags, struct sockaddr __user *, addr, + int, addr_len) { struct socket *sock; struct sockaddr_storage address; @@ -1725,7 +1725,8 @@ * Send a datagram down a socket. */ -asmlinkage long sys_send(int fd, void __user *buff, size_t len, unsigned flags) +SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len, + unsigned, flags) { return sys_sendto(fd, buff, len, flags, NULL, 0); } @@ -1736,9 +1737,9 @@ * sender address from kernel to user space. */ -asmlinkage long sys_recvfrom(int fd, void __user *ubuf, size_t size, - unsigned flags, struct sockaddr __user *addr, - int __user *addr_len) +SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size, + unsigned, flags, struct sockaddr __user *, addr, + int __user *, addr_len) { struct socket *sock; struct iovec iov; @@ -1790,8 +1791,8 @@ * to pass the user mode parameter for the protocols to sort out. */ -asmlinkage long sys_setsockopt(int fd, int level, int optname, - char __user *optval, int optlen) +SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname, + char __user *, optval, int, optlen) { int err, fput_needed; struct socket *sock; @@ -1824,8 +1825,8 @@ * to pass a user mode parameter for the protocols to sort out. */ -asmlinkage long sys_getsockopt(int fd, int level, int optname, - char __user *optval, int __user *optlen) +SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname, + char __user *, optval, int __user *, optlen) { int err, fput_needed; struct socket *sock; @@ -1854,7 +1855,7 @@ * Shutdown a socket. */ -asmlinkage long sys_shutdown(int fd, int how) +SYSCALL_DEFINE2(shutdown, int, fd, int, how) { int err, fput_needed; struct socket *sock; @@ -1880,7 +1881,7 @@ * BSD sendmsg interface */ -asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) +SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags) { struct compat_msghdr __user *msg_compat = (struct compat_msghdr __user *)msg; @@ -1986,8 +1987,8 @@ * BSD recvmsg interface */ -asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, - unsigned int flags) +SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg, + unsigned int, flags) { struct compat_msghdr __user *msg_compat = (struct compat_msghdr __user *)msg; @@ -2110,7 +2111,7 @@ * it is set by the callees. */ -asmlinkage long sys_socketcall(int call, unsigned long __user *args) +SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args) { unsigned long a[6]; unsigned long a0, a1; --- linux-2.6.27.orig/net/bluetooth/hidp/core.c +++ linux-2.6.27/net/bluetooth/hidp/core.c @@ -684,6 +684,10 @@ } hidp_blacklist[] = { /* Apple wireless Mighty Mouse */ { 0x05ac, 0x030c, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL }, + /* Apple Wireless Keyboard */ + { 0x05ac, 0x022c, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN }, + { 0x05ac, 0x022d, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, + { 0x05ac, 0x022e, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN }, { } /* Terminating entry */ }; --- linux-2.6.27.orig/net/sunrpc/auth_generic.c +++ linux-2.6.27/net/sunrpc/auth_generic.c @@ -133,13 +133,29 @@ generic_match(struct auth_cred *acred, struct rpc_cred *cred, int flags) { struct generic_cred *gcred = container_of(cred, struct generic_cred, gc_base); + int i; if (gcred->acred.uid != acred->uid || gcred->acred.gid != acred->gid || - gcred->acred.group_info != acred->group_info || gcred->acred.machine_cred != acred->machine_cred) - return 0; + goto out_nomatch; + + /* Optimisation in the case where pointers are identical... */ + if (gcred->acred.group_info == acred->group_info) + goto out_match; + + /* Slow path... */ + if (gcred->acred.group_info->ngroups != acred->group_info->ngroups) + goto out_nomatch; + for (i = 0; i < gcred->acred.group_info->ngroups; i++) { + if (GROUP_AT(gcred->acred.group_info, i) != + GROUP_AT(acred->group_info, i)) + goto out_nomatch; + } +out_match: return 1; +out_nomatch: + return 0; } void __init rpc_init_generic_auth(void) --- linux-2.6.27.orig/net/sunrpc/svcsock.c +++ linux-2.6.27/net/sunrpc/svcsock.c @@ -1171,7 +1171,11 @@ else if (so->state > SS_UNCONNECTED) err = -EISCONN; else { - svsk = svc_setup_socket(serv, so, &err, SVC_SOCK_DEFAULTS); + if (!try_module_get(THIS_MODULE)) + err = -ENOENT; + else + svsk = svc_setup_socket(serv, so, &err, + SVC_SOCK_DEFAULTS); if (svsk) { struct sockaddr_storage addr; struct sockaddr *sin = (struct sockaddr *)&addr; @@ -1184,7 +1188,8 @@ spin_unlock_bh(&serv->sv_lock); svc_xprt_received(&svsk->sk_xprt); err = 0; - } + } else + module_put(THIS_MODULE); } if (err) { sockfd_put(so); --- linux-2.6.27.orig/net/sunrpc/rpcb_clnt.c +++ linux-2.6.27/net/sunrpc/rpcb_clnt.c @@ -469,6 +469,28 @@ return rpc_run_task(&task_setup_data); } +/* + * In the case where rpc clients have been cloned, we want to make + * sure that we use the program number/version etc of the actual + * owner of the xprt. To do so, we walk back up the tree of parents + * to find whoever created the transport and/or whoever has the + * autobind flag set. + */ +static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt) +{ + struct rpc_clnt *parent = clnt->cl_parent; + + while (parent != clnt) { + if (parent->cl_xprt != clnt->cl_xprt) + break; + if (clnt->cl_autobind) + break; + clnt = parent; + parent = parent->cl_parent; + } + return clnt; +} + /** * rpcb_getport_async - obtain the port for a given RPC service on a given host * @task: task that is waiting for portmapper request @@ -478,10 +500,10 @@ */ void rpcb_getport_async(struct rpc_task *task) { - struct rpc_clnt *clnt = task->tk_client; + struct rpc_clnt *clnt; struct rpc_procinfo *proc; u32 bind_version; - struct rpc_xprt *xprt = task->tk_xprt; + struct rpc_xprt *xprt; struct rpc_clnt *rpcb_clnt; static struct rpcbind_args *map; struct rpc_task *child; @@ -490,13 +512,13 @@ size_t salen; int status; + clnt = rpcb_find_transport_owner(task->tk_client); + xprt = clnt->cl_xprt; + dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", task->tk_pid, __func__, clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot); - /* Autobind on cloned rpc clients is discouraged */ - BUG_ON(clnt->cl_parent != clnt); - /* Put self on the wait queue to ensure we get notified if * some other task is already attempting to bind the port */ rpc_sleep_on(&xprt->binding, task, NULL); @@ -558,7 +580,7 @@ status = -ENOMEM; dprintk("RPC: %5u %s: no memory available\n", task->tk_pid, __func__); - goto bailout_nofree; + goto bailout_release_client; } map->r_prog = clnt->cl_prog; map->r_vers = clnt->cl_vers; @@ -578,11 +600,13 @@ task->tk_pid, __func__); return; } - rpc_put_task(child); - task->tk_xprt->stat.bind_count++; + xprt->stat.bind_count++; + rpc_put_task(child); return; +bailout_release_client: + rpc_release_client(rpcb_clnt); bailout_nofree: rpcb_wake_rpcbind_waiters(xprt, status); task->tk_status = status; --- linux-2.6.27.orig/net/mac80211/tx.c +++ linux-2.6.27/net/mac80211/tx.c @@ -1335,8 +1335,10 @@ if (is_multicast_ether_addr(hdr->addr3)) memcpy(hdr->addr1, hdr->addr3, ETH_ALEN); else - if (mesh_nexthop_lookup(skb, odev)) + if (mesh_nexthop_lookup(skb, odev)) { + dev_put(odev); return 0; + } if (memcmp(odev->dev_addr, hdr->addr4, ETH_ALEN) != 0) IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.sta, fwded_frames); --- linux-2.6.27.orig/net/mac80211/debugfs_netdev.c +++ linux-2.6.27/net/mac80211/debugfs_netdev.c @@ -537,6 +537,7 @@ { struct net_device *dev = ndev; struct dentry *dir; + struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; char buf[10+IFNAMSIZ]; @@ -549,10 +550,19 @@ if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) return 0; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); + /* + * Do not use IEEE80211_DEV_TO_SUB_IF because that + * BUG_ONs for the master netdev which we need to + * handle here. + */ + sdata = netdev_priv(dev); - sprintf(buf, "netdev:%s", dev->name); dir = sdata->debugfsdir; + + if (!dir) + return 0; + + sprintf(buf, "netdev:%s", dev->name); if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs " "dir to %s\n", buf); --- linux-2.6.27.orig/net/mac80211/wext.c +++ linux-2.6.27/net/mac80211/wext.c @@ -804,7 +804,7 @@ * configure it here */ if (local->ops->set_frag_threshold) - local->ops->set_frag_threshold( + return local->ops->set_frag_threshold( local_to_hw(local), local->fragmentation_threshold); --- linux-2.6.27.orig/net/mac80211/debugfs_sta.c +++ linux-2.6.27/net/mac80211/debugfs_sta.c @@ -200,7 +200,7 @@ /* toggle Rx aggregation command */ tid_num = tid_num - 100; if (tid_static_rx[tid_num] == 1) { - strcpy(state, "off "); + strcpy(state, "off"); ieee80211_sta_stop_rx_ba_session(dev, da, tid_num, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); sta->ampdu_mlme.tid_state_rx[tid_num] |= --- linux-2.6.27.orig/net/can/bcm.c +++ linux-2.6.27/net/can/bcm.c @@ -64,10 +64,11 @@ #define BCM_CAN_DLC_MASK 0x0F /* clean private flags in can_dlc by masking */ /* get best masking value for can_rx_register() for a given single can_id */ -#define REGMASK(id) ((id & CAN_RTR_FLAG) | ((id & CAN_EFF_FLAG) ? \ - (CAN_EFF_MASK | CAN_EFF_FLAG) : CAN_SFF_MASK)) +#define REGMASK(id) ((id & CAN_EFF_FLAG) ? \ + (CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG) : \ + (CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG)) -#define CAN_BCM_VERSION "20080415" +#define CAN_BCM_VERSION CAN_VERSION static __initdata const char banner[] = KERN_INFO "can: broadcast manager protocol (rev " CAN_BCM_VERSION ")\n"; --- linux-2.6.27.orig/net/can/af_can.c +++ linux-2.6.27/net/can/af_can.c @@ -319,23 +319,52 @@ return n ? d : NULL; } +/** + * find_rcv_list - determine optimal filterlist inside device filter struct + * @can_id: pointer to CAN identifier of a given can_filter + * @mask: pointer to CAN mask of a given can_filter + * @d: pointer to the device filter struct + * + * Description: + * Returns the optimal filterlist to reduce the filter handling in the + * receive path. This function is called by service functions that need + * to register or unregister a can_filter in the filter lists. + * + * A filter matches in general, when + * + * & mask == can_id & mask + * + * so every bit set in the mask (even CAN_EFF_FLAG, CAN_RTR_FLAG) describe + * relevant bits for the filter. + * + * The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can + * filter for error frames (CAN_ERR_FLAG bit set in mask). For error frames + * there is a special filterlist and a special rx path filter handling. + * + * Return: + * Pointer to optimal filterlist for the given can_id/mask pair. + * Constistency checked mask. + * Reduced can_id to have a preprocessed filter compare value. + */ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask, struct dev_rcv_lists *d) { canid_t inv = *can_id & CAN_INV_FILTER; /* save flag before masking */ - /* filter error frames */ + /* filter for error frames in extra filterlist */ if (*mask & CAN_ERR_FLAG) { - /* clear CAN_ERR_FLAG in list entry */ + /* clear CAN_ERR_FLAG in filter entry */ *mask &= CAN_ERR_MASK; return &d->rx[RX_ERR]; } - /* ensure valid values in can_mask */ - if (*mask & CAN_EFF_FLAG) - *mask &= (CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG); - else - *mask &= (CAN_SFF_MASK | CAN_RTR_FLAG); + /* with cleared CAN_ERR_FLAG we have a simple mask/value filterpair */ + +#define CAN_EFF_RTR_FLAGS (CAN_EFF_FLAG | CAN_RTR_FLAG) + + /* ensure valid values in can_mask for 'SFF only' frame filtering */ + if ((*mask & CAN_EFF_FLAG) && !(*can_id & CAN_EFF_FLAG)) + *mask &= (CAN_SFF_MASK | CAN_EFF_RTR_FLAGS); /* reduce condition testing at receive time */ *can_id &= *mask; @@ -348,15 +377,19 @@ if (!(*mask)) return &d->rx[RX_ALL]; - /* use extra filterset for the subscription of exactly *ONE* can_id */ - if (*can_id & CAN_EFF_FLAG) { - if (*mask == (CAN_EFF_MASK | CAN_EFF_FLAG)) { - /* RFC: a use-case for hash-tables in the future? */ - return &d->rx[RX_EFF]; + /* extra filterlists for the subscription of a single non-RTR can_id */ + if (((*mask & CAN_EFF_RTR_FLAGS) == CAN_EFF_RTR_FLAGS) + && !(*can_id & CAN_RTR_FLAG)) { + + if (*can_id & CAN_EFF_FLAG) { + if (*mask == (CAN_EFF_MASK | CAN_EFF_RTR_FLAGS)) { + /* RFC: a future use-case for hash-tables? */ + return &d->rx[RX_EFF]; + } + } else { + if (*mask == (CAN_SFF_MASK | CAN_EFF_RTR_FLAGS)) + return &d->rx_sff[*can_id]; } - } else { - if (*mask == CAN_SFF_MASK) - return &d->rx_sff[*can_id]; } /* default: filter via can_id/can_mask */ @@ -589,7 +622,10 @@ } } - /* check CAN_ID specific entries */ + /* check filterlists for single non-RTR can_ids */ + if (can_id & CAN_RTR_FLAG) + return matches; + if (can_id & CAN_EFF_FLAG) { hlist_for_each_entry_rcu(r, n, &d->rx[RX_EFF], list) { if (r->can_id == can_id) { --- linux-2.6.27.orig/net/atm/svc.c +++ linux-2.6.27/net/atm/svc.c @@ -293,7 +293,10 @@ error = -EINVAL; goto out; } - vcc_insert_socket(sk); + if (test_bit(ATM_VF_LISTEN, &vcc->flags)) { + error = -EADDRINUSE; + goto out; + } set_bit(ATM_VF_WAITING, &vcc->flags); prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local); @@ -307,6 +310,7 @@ goto out; } set_bit(ATM_VF_LISTEN,&vcc->flags); + vcc_insert_socket(sk); sk->sk_max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT; error = -sk->sk_err; out: --- linux-2.6.27.orig/net/key/af_key.c +++ linux-2.6.27/net/key/af_key.c @@ -2051,7 +2051,6 @@ req_size += socklen * 2; } else { size -= 2*socklen; - socklen = 0; } rq = (void*)skb_put(skb, req_size); pol->sadb_x_policy_len += req_size/8; --- linux-2.6.27.orig/net/ipv4/udp.c +++ linux-2.6.27/net/ipv4/udp.c @@ -302,7 +302,7 @@ return result; } -static inline struct sock *udp_v4_mcast_next(struct sock *sk, +static inline struct sock *udp_v4_mcast_next(struct net *net, struct sock *sk, __be16 loc_port, __be32 loc_addr, __be16 rmt_port, __be32 rmt_addr, int dif) @@ -314,7 +314,8 @@ sk_for_each_from(s, node) { struct inet_sock *inet = inet_sk(s); - if (s->sk_hash != hnum || + if (!net_eq(sock_net(s), net) || + s->sk_hash != hnum || (inet->daddr && inet->daddr != rmt_addr) || (inet->dport != rmt_port && inet->dport) || (inet->rcv_saddr && inet->rcv_saddr != loc_addr) || @@ -958,9 +959,11 @@ if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) { /* Note that an ENOMEM error is charged twice */ - if (rc == -ENOMEM) + if (rc == -ENOMEM) { UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS, is_udplite); + atomic_inc(&sk->sk_drops); + } goto drop; } @@ -1097,15 +1100,16 @@ read_lock(&udp_hash_lock); sk = sk_head(&udptable[udp_hashfn(net, ntohs(uh->dest))]); dif = skb->dev->ifindex; - sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); + sk = udp_v4_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); if (sk) { struct sock *sknext = NULL; do { struct sk_buff *skb1 = skb; - sknext = udp_v4_mcast_next(sk_next(sk), uh->dest, daddr, - uh->source, saddr, dif); + sknext = udp_v4_mcast_next(net, sk_next(sk), uh->dest, + daddr, uh->source, saddr, + dif); if (sknext) skb1 = skb_clone(skb, GFP_ATOMIC); @@ -1170,7 +1174,7 @@ int proto) { struct sock *sk; - struct udphdr *uh = udp_hdr(skb); + struct udphdr *uh; unsigned short ulen; struct rtable *rt = (struct rtable*)skb->dst; __be32 saddr = ip_hdr(skb)->saddr; @@ -1183,6 +1187,7 @@ if (!pskb_may_pull(skb, sizeof(struct udphdr))) goto drop; /* No space for header. */ + uh = udp_hdr(skb); ulen = ntohs(uh->len); if (ulen > skb->len) goto short_packet; --- linux-2.6.27.orig/net/ipv4/proc.c +++ linux-2.6.27/net/ipv4/proc.c @@ -237,43 +237,45 @@ SNMP_MIB_SENTINEL }; +static void icmpmsg_put_line(struct seq_file *seq, unsigned long *vals, + unsigned short *type, int count) +{ + int j; + + if (count) { + seq_printf(seq, "\nIcmpMsg:"); + for (j = 0; j < count; ++j) + seq_printf(seq, " %sType%u", + type[j] & 0x100 ? "Out" : "In", + type[j] & 0xff); + seq_printf(seq, "\nIcmpMsg:"); + for (j = 0; j < count; ++j) + seq_printf(seq, " %lu", vals[j]); + } +} + static void icmpmsg_put(struct seq_file *seq) { #define PERLINE 16 - int j, i, count; - static int out[PERLINE]; + int i, count; + unsigned short type[PERLINE]; + unsigned long vals[PERLINE], val; struct net *net = seq->private; count = 0; for (i = 0; i < ICMPMSG_MIB_MAX; i++) { - - if (snmp_fold_field((void **) net->mib.icmpmsg_statistics, i)) - out[count++] = i; - if (count < PERLINE) - continue; - - seq_printf(seq, "\nIcmpMsg:"); - for (j = 0; j < PERLINE; ++j) - seq_printf(seq, " %sType%u", i & 0x100 ? "Out" : "In", - i & 0xff); - seq_printf(seq, "\nIcmpMsg: "); - for (j = 0; j < PERLINE; ++j) - seq_printf(seq, " %lu", - snmp_fold_field((void **) net->mib.icmpmsg_statistics, - out[j])); - seq_putc(seq, '\n'); - } - if (count) { - seq_printf(seq, "\nIcmpMsg:"); - for (j = 0; j < count; ++j) - seq_printf(seq, " %sType%u", out[j] & 0x100 ? "Out" : - "In", out[j] & 0xff); - seq_printf(seq, "\nIcmpMsg:"); - for (j = 0; j < count; ++j) - seq_printf(seq, " %lu", snmp_fold_field((void **) - net->mib.icmpmsg_statistics, out[j])); + val = snmp_fold_field((void **) net->mib.icmpmsg_statistics, i); + if (val) { + type[count] = i; + vals[count++] = val; + } + if (count == PERLINE) { + icmpmsg_put_line(seq, vals, type, count); + count = 0; + } } + icmpmsg_put_line(seq, vals, type, count); #undef PERLINE } --- linux-2.6.27.orig/net/ipv4/ipconfig.c +++ linux-2.6.27/net/ipv4/ipconfig.c @@ -1272,6 +1272,9 @@ static int __init ip_auto_config(void) { __be32 addr; +#ifdef IPCONFIG_DYNAMIC + int retries = CONF_OPEN_RETRIES; +#endif #ifdef CONFIG_PROC_FS proc_net_fops_create(&init_net, "pnp", S_IRUGO, &pnp_seq_fops); @@ -1308,9 +1311,6 @@ #endif ic_first_dev->next) { #ifdef IPCONFIG_DYNAMIC - - int retries = CONF_OPEN_RETRIES; - if (ic_dynamic() < 0) { ic_close_devs(); --- linux-2.6.27.orig/net/ipv4/tcp.c +++ linux-2.6.27/net/ipv4/tcp.c @@ -518,8 +518,13 @@ unsigned int offset, size_t len) { struct tcp_splice_state *tss = rd_desc->arg.data; + int ret; - return skb_splice_bits(skb, offset, tss->pipe, tss->len, tss->flags); + ret = skb_splice_bits(skb, offset, tss->pipe, min(rd_desc->count, len), + tss->flags); + if (ret > 0) + rd_desc->count -= ret; + return ret; } static int __tcp_splice_read(struct sock *sk, struct tcp_splice_state *tss) @@ -527,6 +532,7 @@ /* Store TCP splice context information in read_descriptor_t. */ read_descriptor_t rd_desc = { .arg.data = tss, + .count = tss->len, }; return tcp_read_sock(sk, &rd_desc, tcp_splice_data_recv); @@ -576,10 +582,6 @@ else if (!ret) { if (spliced) break; - if (flags & SPLICE_F_NONBLOCK) { - ret = -EAGAIN; - break; - } if (sock_flag(sk, SOCK_DONE)) break; if (sk->sk_err) { @@ -597,6 +599,10 @@ ret = -ENOTCONN; break; } + if (flags & SPLICE_F_NONBLOCK) { + ret = -EAGAIN; + break; + } if (!timeo) { ret = -EAGAIN; break; @@ -611,11 +617,13 @@ tss.len -= ret; spliced += ret; + if (!timeo) + break; release_sock(sk); lock_sock(sk); if (sk->sk_err || sk->sk_state == TCP_CLOSE || - (sk->sk_shutdown & RCV_SHUTDOWN) || !timeo || + (sk->sk_shutdown & RCV_SHUTDOWN) || signal_pending(current)) break; } --- linux-2.6.27.orig/net/ipv4/tcp_output.c +++ linux-2.6.27/net/ipv4/tcp_output.c @@ -357,6 +357,17 @@ __u32 tsval, tsecr; /* need to include OPTION_TS */ }; +/* Beware: Something in the Internet is very sensitive to the ordering of + * TCP options, we learned this through the hard way, so be careful here. + * Luckily we can at least blame others for their non-compliance but from + * inter-operatibility perspective it seems that we're somewhat stuck with + * the ordering which we have been using if we want to keep working with + * those broken things (not that it currently hurts anybody as there isn't + * particular reason why the ordering would need to be changed). + * + * At least SACK_PERM as the first option is known to lead to a disaster + * (but it may well be that other scenarios fail similarly). + */ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, const struct tcp_out_options *opts, __u8 **md5_hash) { @@ -371,6 +382,12 @@ *md5_hash = NULL; } + if (unlikely(opts->mss)) { + *ptr++ = htonl((TCPOPT_MSS << 24) | + (TCPOLEN_MSS << 16) | + opts->mss); + } + if (likely(OPTION_TS & opts->options)) { if (unlikely(OPTION_SACK_ADVERTISE & opts->options)) { *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | @@ -387,12 +404,6 @@ *ptr++ = htonl(opts->tsecr); } - if (unlikely(opts->mss)) { - *ptr++ = htonl((TCPOPT_MSS << 24) | - (TCPOLEN_MSS << 16) | - opts->mss); - } - if (unlikely(OPTION_SACK_ADVERTISE & opts->options && !(OPTION_TS & opts->options))) { *ptr++ = htonl((TCPOPT_NOP << 24) | @@ -2266,6 +2277,11 @@ } memset(&opts, 0, sizeof(opts)); +#ifdef CONFIG_SYN_COOKIES + if (unlikely(req->cookie_ts)) + TCP_SKB_CB(skb)->when = cookie_init_timestamp(req); + else +#endif TCP_SKB_CB(skb)->when = tcp_time_stamp; tcp_header_size = tcp_synack_options(sk, req, dst_metric(dst, RTAX_ADVMSS), @@ -2292,11 +2308,6 @@ /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ th->window = htons(min(req->rcv_wnd, 65535U)); -#ifdef CONFIG_SYN_COOKIES - if (unlikely(req->cookie_ts)) - TCP_SKB_CB(skb)->when = cookie_init_timestamp(req); - else -#endif tcp_options_write((__be32 *)(th + 1), tp, &opts, &md5_hash_location); th->doff = (tcp_header_size >> 2); TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS); --- linux-2.6.27.orig/net/ipv4/netfilter/nf_nat_snmp_basic.c +++ linux-2.6.27/net/ipv4/netfilter/nf_nat_snmp_basic.c @@ -742,6 +742,7 @@ *obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC); if (*obj == NULL) { + kfree(p); kfree(id); if (net_ratelimit()) printk("OOM in bsalg (%d)\n", __LINE__); --- linux-2.6.27.orig/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ linux-2.6.27/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -150,10 +150,12 @@ const struct net_device *out, int (*okfn)(struct sk_buff *)) { +#if !defined(CONFIG_NF_NAT) && !defined(CONFIG_NF_NAT_MODULE) /* Previously seen (loopback)? Ignore. Do this before fragment check. */ if (skb->nfct) return NF_ACCEPT; +#endif /* Gather fragments. */ if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) { --- linux-2.6.27.orig/net/core/scm.c +++ linux-2.6.27/net/core/scm.c @@ -75,6 +75,7 @@ if (!fpl) return -ENOMEM; *fplp = fpl; + INIT_LIST_HEAD(&fpl->list); fpl->count = 0; } fpp = &fpl->fp[fpl->count]; @@ -106,9 +107,25 @@ if (fpl) { scm->fp = NULL; - for (i=fpl->count-1; i>=0; i--) - fput(fpl->fp[i]); - kfree(fpl); + if (current->scm_work_list) { + list_add_tail(&fpl->list, current->scm_work_list); + } else { + LIST_HEAD(work_list); + + current->scm_work_list = &work_list; + + list_add(&fpl->list, &work_list); + while (!list_empty(&work_list)) { + fpl = list_first_entry(&work_list, struct scm_fp_list, list); + + list_del(&fpl->list); + for (i=fpl->count-1; i>=0; i--) + fput(fpl->fp[i]); + kfree(fpl); + } + + current->scm_work_list = NULL; + } } } @@ -284,6 +301,7 @@ new_fpl = kmalloc(sizeof(*fpl), GFP_KERNEL); if (new_fpl) { + INIT_LIST_HEAD(&new_fpl->list); for (i=fpl->count-1; i>=0; i--) get_file(fpl->fp[i]); memcpy(new_fpl, fpl, sizeof(*fpl)); --- linux-2.6.27.orig/net/core/skbuff.c +++ linux-2.6.27/net/core/skbuff.c @@ -73,17 +73,13 @@ static void sock_pipe_buf_release(struct pipe_inode_info *pipe, struct pipe_buffer *buf) { - struct sk_buff *skb = (struct sk_buff *) buf->private; - - kfree_skb(skb); + put_page(buf->page); } static void sock_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf) { - struct sk_buff *skb = (struct sk_buff *) buf->private; - - skb_get(skb); + get_page(buf->page); } static int sock_pipe_buf_steal(struct pipe_inode_info *pipe, @@ -1262,9 +1258,19 @@ */ static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i) { - struct sk_buff *skb = (struct sk_buff *) spd->partial[i].private; + put_page(spd->pages[i]); +} - kfree_skb(skb); +static inline struct page *linear_to_page(struct page *page, unsigned int len, + unsigned int offset) +{ + struct page *p = alloc_pages(GFP_KERNEL, 0); + + if (!p) + return NULL; + memcpy(page_address(p) + offset, page_address(page) + offset, len); + + return p; } /* @@ -1272,16 +1278,23 @@ */ static inline int spd_fill_page(struct splice_pipe_desc *spd, struct page *page, unsigned int len, unsigned int offset, - struct sk_buff *skb) + struct sk_buff *skb, int linear) { if (unlikely(spd->nr_pages == PIPE_BUFFERS)) return 1; + if (linear) { + page = linear_to_page(page, len, offset); + if (!page) + return 1; + } else + get_page(page); + spd->pages[spd->nr_pages] = page; spd->partial[spd->nr_pages].len = len; spd->partial[spd->nr_pages].offset = offset; - spd->partial[spd->nr_pages].private = (unsigned long) skb_get(skb); spd->nr_pages++; + return 0; } @@ -1297,7 +1310,7 @@ static inline int __splice_segment(struct page *page, unsigned int poff, unsigned int plen, unsigned int *off, unsigned int *len, struct sk_buff *skb, - struct splice_pipe_desc *spd) + struct splice_pipe_desc *spd, int linear) { if (!*len) return 1; @@ -1320,7 +1333,7 @@ /* the linear region may spread across several pages */ flen = min_t(unsigned int, flen, PAGE_SIZE - poff); - if (spd_fill_page(spd, page, flen, poff, skb)) + if (spd_fill_page(spd, page, flen, poff, skb, linear)) return 1; __segment_seek(&page, &poff, &plen, flen); @@ -1347,7 +1360,7 @@ if (__splice_segment(virt_to_page(skb->data), (unsigned long) skb->data & (PAGE_SIZE - 1), skb_headlen(skb), - offset, len, skb, spd)) + offset, len, skb, spd, 1)) return 1; /* @@ -1357,7 +1370,7 @@ const skb_frag_t *f = &skb_shinfo(skb)->frags[seg]; if (__splice_segment(f->page, f->page_offset, f->size, - offset, len, skb, spd)) + offset, len, skb, spd, 0)) return 1; } @@ -1370,7 +1383,7 @@ * the frag list, if such a thing exists. We'd probably need to recurse to * handle that cleanly. */ -int skb_splice_bits(struct sk_buff *__skb, unsigned int offset, +int skb_splice_bits(struct sk_buff *skb, unsigned int offset, struct pipe_inode_info *pipe, unsigned int tlen, unsigned int flags) { @@ -1383,16 +1396,6 @@ .ops = &sock_pipe_buf_ops, .spd_release = sock_spd_release, }; - struct sk_buff *skb; - - /* - * I'd love to avoid the clone here, but tcp_read_sock() - * ignores reference counts and unconditonally kills the sk_buff - * on return from the actor. - */ - skb = skb_clone(__skb, GFP_KERNEL); - if (unlikely(!skb)) - return -ENOMEM; /* * __skb_splice_bits() only fails if the output has no room left, @@ -1416,15 +1419,9 @@ } done: - /* - * drop our reference to the clone, the pipe consumption will - * drop the rest. - */ - kfree_skb(skb); - if (spd.nr_pages) { + struct sock *sk = skb->sk; int ret; - struct sock *sk = __skb->sk; /* * Drop the socket lock, otherwise we have reverse @@ -2001,10 +1998,10 @@ return 0; next_skb: - block_limit = skb_headlen(st->cur_skb); + block_limit = skb_headlen(st->cur_skb) + st->stepped_offset; if (abs_offset < block_limit) { - *data = st->cur_skb->data + abs_offset; + *data = st->cur_skb->data + (abs_offset - st->stepped_offset); return block_limit - abs_offset; } @@ -2039,13 +2036,14 @@ st->frag_data = NULL; } - if (st->cur_skb->next) { - st->cur_skb = st->cur_skb->next; + if (st->root_skb == st->cur_skb && + skb_shinfo(st->root_skb)->frag_list) { + st->cur_skb = skb_shinfo(st->root_skb)->frag_list; st->frag_idx = 0; goto next_skb; - } else if (st->root_skb == st->cur_skb && - skb_shinfo(st->root_skb)->frag_list) { - st->cur_skb = skb_shinfo(st->root_skb)->frag_list; + } else if (st->cur_skb->next) { + st->cur_skb = st->cur_skb->next; + st->frag_idx = 0; goto next_skb; } --- linux-2.6.27.orig/net/core/dev.c +++ linux-2.6.27/net/core/dev.c @@ -2187,6 +2187,9 @@ int ret = NET_RX_DROP; __be16 type; + if (skb->vlan_tci && vlan_hwaccel_do_receive(skb)) + return NET_RX_SUCCESS; + /* if we've gotten here through NAPI, check netpoll */ if (netpoll_receive_skb(skb)) return NET_RX_DROP; @@ -3990,7 +3993,7 @@ dev->features &= ~NETIF_F_TSO; } if (dev->features & NETIF_F_UFO) { - if (!(dev->features & NETIF_F_HW_CSUM)) { + if (!(dev->features & NETIF_F_GEN_CSUM)) { printk(KERN_ERR "%s: Dropping NETIF_F_UFO since no " "NETIF_F_HW_CSUM feature.\n", dev->name); --- linux-2.6.27.orig/net/core/sock.c +++ linux-2.6.27/net/core/sock.c @@ -695,6 +695,8 @@ if (len < 0) return -EINVAL; + v.val = 0; + switch(optname) { case SO_DEBUG: v.val = sock_flag(sk, SOCK_DBG); --- linux-2.6.27.orig/net/rfkill/rfkill.c +++ linux-2.6.27/net/rfkill/rfkill.c @@ -117,6 +117,7 @@ static void notify_rfkill_state_change(struct rfkill *rfkill) { + rfkill_led_trigger(rfkill, rfkill->state); blocking_notifier_call_chain(&rfkill_notifier_list, RFKILL_STATE_CHANGED, rfkill); @@ -204,10 +205,8 @@ rfkill->state = state; } - if (force || rfkill->state != oldstate) { - rfkill_led_trigger(rfkill, rfkill->state); + if (force || rfkill->state != oldstate) notify_rfkill_state_change(rfkill); - } return retval; } --- linux-2.6.27.orig/net/rose/af_rose.c +++ linux-2.6.27/net/rose/af_rose.c @@ -1120,6 +1120,10 @@ /* Build a packet */ SOCK_DEBUG(sk, "ROSE: sendto: building packet.\n"); + /* Sanity check the packet size */ + if (len > 65535) + return -EMSGSIZE; + size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN; if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) --- linux-2.6.27.orig/net/packet/af_packet.c +++ linux-2.6.27/net/packet/af_packet.c @@ -77,6 +77,7 @@ #include #include #include +#include #ifdef CONFIG_INET #include @@ -175,6 +176,7 @@ #endif struct packet_type prot_hook; spinlock_t bind_lock; + struct mutex pg_vec_lock; unsigned int running:1, /* prot_hook is attached*/ auxdata:1, origdev:1; @@ -220,13 +222,13 @@ h.raw = po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size); switch (po->tp_version) { case TPACKET_V1: - if (status != h.h1->tp_status ? TP_STATUS_USER : - TP_STATUS_KERNEL) + if (status != (h.h1->tp_status ? TP_STATUS_USER : + TP_STATUS_KERNEL)) return NULL; break; case TPACKET_V2: - if (status != h.h2->tp_status ? TP_STATUS_USER : - TP_STATUS_KERNEL) + if (status != (h.h2->tp_status ? TP_STATUS_USER : + TP_STATUS_KERNEL)) return NULL; break; } @@ -1068,6 +1070,7 @@ */ spin_lock_init(&po->bind_lock); + mutex_init(&po->pg_vec_lock); po->prot_hook.func = packet_rcv; if (sock->type == SOCK_PACKET) @@ -1863,6 +1866,7 @@ synchronize_net(); err = -EBUSY; + mutex_lock(&po->pg_vec_lock); if (closing || atomic_read(&po->mapped) == 0) { err = 0; #define XC(a, b) ({ __typeof__ ((a)) __t; __t = (a); (a) = (b); __t; }) @@ -1884,6 +1888,7 @@ if (atomic_read(&po->mapped)) printk(KERN_DEBUG "packet_mmap: vma is busy: %d\n", atomic_read(&po->mapped)); } + mutex_unlock(&po->pg_vec_lock); spin_lock(&po->bind_lock); if (was_running && !po->running) { @@ -1916,7 +1921,7 @@ size = vma->vm_end - vma->vm_start; - lock_sock(sk); + mutex_lock(&po->pg_vec_lock); if (po->pg_vec == NULL) goto out; if (size != po->pg_vec_len*po->pg_vec_pages*PAGE_SIZE) @@ -1939,7 +1944,7 @@ err = 0; out: - release_sock(sk); + mutex_unlock(&po->pg_vec_lock); return err; } #endif --- linux-2.6.27.orig/net/netfilter/xt_iprange.c +++ linux-2.6.27/net/netfilter/xt_iprange.c @@ -67,7 +67,7 @@ if (info->flags & IPRANGE_SRC) { m = ntohl(iph->saddr) < ntohl(info->src_min.ip); m |= ntohl(iph->saddr) > ntohl(info->src_max.ip); - m ^= info->flags & IPRANGE_SRC_INV; + m ^= !!(info->flags & IPRANGE_SRC_INV); if (m) { pr_debug("src IP " NIPQUAD_FMT " NOT in range %s" NIPQUAD_FMT "-" NIPQUAD_FMT "\n", @@ -81,7 +81,7 @@ if (info->flags & IPRANGE_DST) { m = ntohl(iph->daddr) < ntohl(info->dst_min.ip); m |= ntohl(iph->daddr) > ntohl(info->dst_max.ip); - m ^= info->flags & IPRANGE_DST_INV; + m ^= !!(info->flags & IPRANGE_DST_INV); if (m) { pr_debug("dst IP " NIPQUAD_FMT " NOT in range %s" NIPQUAD_FMT "-" NIPQUAD_FMT "\n", @@ -123,14 +123,14 @@ if (info->flags & IPRANGE_SRC) { m = iprange_ipv6_sub(&iph->saddr, &info->src_min.in6) < 0; m |= iprange_ipv6_sub(&iph->saddr, &info->src_max.in6) > 0; - m ^= info->flags & IPRANGE_SRC_INV; + m ^= !!(info->flags & IPRANGE_SRC_INV); if (m) return false; } if (info->flags & IPRANGE_DST) { m = iprange_ipv6_sub(&iph->daddr, &info->dst_min.in6) < 0; m |= iprange_ipv6_sub(&iph->daddr, &info->dst_max.in6) > 0; - m ^= info->flags & IPRANGE_DST_INV; + m ^= !!(info->flags & IPRANGE_DST_INV); if (m) return false; } --- linux-2.6.27.orig/net/netfilter/xt_sctp.c +++ linux-2.6.27/net/netfilter/xt_sctp.c @@ -105,7 +105,7 @@ switch (chunk_match_type) { case SCTP_CHUNK_MATCH_ALL: - return SCTP_CHUNKMAP_IS_CLEAR(info->chunkmap); + return SCTP_CHUNKMAP_IS_CLEAR(chunkmapcopy); case SCTP_CHUNK_MATCH_ANY: return false; case SCTP_CHUNK_MATCH_ONLY: --- linux-2.6.27.orig/net/8021q/vlan_core.c +++ linux-2.6.27/net/8021q/vlan_core.c @@ -3,11 +3,20 @@ #include #include "vlan.h" +struct vlan_hwaccel_cb { + struct net_device *dev; +}; + +static inline struct vlan_hwaccel_cb *vlan_hwaccel_cb(struct sk_buff *skb) +{ + return (struct vlan_hwaccel_cb *)skb->cb; +} + /* VLAN rx hw acceleration helper. This acts like netif_{rx,receive_skb}(). */ int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, u16 vlan_tci, int polling) { - struct net_device_stats *stats; + struct vlan_hwaccel_cb *cb = vlan_hwaccel_cb(skb); if (skb_bond_should_drop(skb)) { dev_kfree_skb_any(skb); @@ -15,23 +24,35 @@ } skb->vlan_tci = vlan_tci; + cb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK); + + return (polling ? netif_receive_skb(skb) : netif_rx(skb)); +} +EXPORT_SYMBOL(__vlan_hwaccel_rx); + +int vlan_hwaccel_do_receive(struct sk_buff *skb) +{ + struct vlan_hwaccel_cb *cb = vlan_hwaccel_cb(skb); + struct net_device *dev = cb->dev; + struct net_device_stats *stats; + netif_nit_deliver(skb); - skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK); - if (skb->dev == NULL) { - dev_kfree_skb_any(skb); - /* Not NET_RX_DROP, this is not being dropped - * due to congestion. */ - return NET_RX_SUCCESS; + if (dev == NULL) { + kfree_skb(skb); + return -1; } - skb->dev->last_rx = jiffies; + + skb->dev = dev; + skb->priority = vlan_get_ingress_priority(dev, skb->vlan_tci); skb->vlan_tci = 0; - stats = &skb->dev->stats; + dev->last_rx = jiffies; + + stats = &dev->stats; stats->rx_packets++; stats->rx_bytes += skb->len; - skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci); switch (skb->pkt_type) { case PACKET_BROADCAST: break; @@ -43,13 +64,12 @@ * This allows the VLAN to have a different MAC than the * underlying device, and still route correctly. */ if (!compare_ether_addr(eth_hdr(skb)->h_dest, - skb->dev->dev_addr)) + dev->dev_addr)) skb->pkt_type = PACKET_HOST; break; }; - return (polling ? netif_receive_skb(skb) : netif_rx(skb)); + return 0; } -EXPORT_SYMBOL(__vlan_hwaccel_rx); struct net_device *vlan_dev_real_dev(const struct net_device *dev) { --- linux-2.6.27.orig/net/x25/af_x25.c +++ linux-2.6.27/net/x25/af_x25.c @@ -1037,6 +1037,12 @@ sx25.sx25_addr = x25->dest_addr; } + /* Sanity check the packet size */ + if (len > 65535) { + rc = -EMSGSIZE; + goto out; + } + SOCK_DEBUG(sk, "x25_sendmsg: sendto: Addresses built.\n"); /* Build a packet */ --- linux-2.6.27.orig/net/sched/cls_u32.c +++ linux-2.6.27/net/sched/cls_u32.c @@ -637,8 +637,9 @@ break; n->next = *ins; - wmb(); + tcf_tree_lock(tp); *ins = n; + tcf_tree_unlock(tp); *arg = (unsigned long)n; return 0; --- linux-2.6.27.orig/net/sched/sch_generic.c +++ linux-2.6.27/net/sched/sch_generic.c @@ -319,6 +319,7 @@ static struct netdev_queue noop_netdev_queue = { .qdisc = &noop_qdisc, + .qdisc_sleeping = &noop_qdisc, }; struct Qdisc noop_qdisc = { @@ -344,6 +345,7 @@ static struct Qdisc noqueue_qdisc; static struct netdev_queue noqueue_netdev_queue = { .qdisc = &noqueue_qdisc, + .qdisc_sleeping = &noqueue_qdisc, }; static struct Qdisc noqueue_qdisc = { --- linux-2.6.27.orig/net/sched/sch_htb.c +++ linux-2.6.27/net/sched/sch_htb.c @@ -924,6 +924,7 @@ } } sch->qstats.overlimits++; + qdisc_watchdog_cancel(&q->watchdog); qdisc_watchdog_schedule(&q->watchdog, next_event); fin: return skb; --- linux-2.6.27.orig/net/sctp/input.c +++ linux-2.6.27/net/sctp/input.c @@ -249,6 +249,19 @@ */ sctp_bh_lock_sock(sk); + if (sk != rcvr->sk) { + /* Our cached sk is different from the rcvr->sk. This is + * because migrate()/accept() may have moved the association + * to a new socket and released all the sockets. So now we + * are holding a lock on the old socket while the user may + * be doing something with the new socket. Switch our veiw + * of the current sk. + */ + sctp_bh_unlock_sock(sk); + sk = rcvr->sk; + sctp_bh_lock_sock(sk); + } + if (sock_owned_by_user(sk)) { SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_BACKLOG); sctp_add_backlog(sk, skb); --- linux-2.6.27.orig/net/sctp/outqueue.c +++ linux-2.6.27/net/sctp/outqueue.c @@ -929,7 +929,6 @@ } /* Finally, transmit new packets. */ - start_timer = 0; while ((chunk = sctp_outq_dequeue_data(q)) != NULL) { /* RFC 2960 6.5 Every DATA chunk MUST carry a valid * stream identifier. @@ -1028,7 +1027,7 @@ list_add_tail(&chunk->transmitted_list, &transport->transmitted); - sctp_transport_reset_timers(transport, start_timer-1); + sctp_transport_reset_timers(transport, 0); q->empty = 0; --- linux-2.6.27.orig/net/sctp/sm_statefuns.c +++ linux-2.6.27/net/sctp/sm_statefuns.c @@ -3635,6 +3635,7 @@ { struct sctp_chunk *chunk = arg; struct sctp_fwdtsn_hdr *fwdtsn_hdr; + struct sctp_fwdtsn_skip *skip; __u16 len; __u32 tsn; @@ -3664,6 +3665,12 @@ if (sctp_tsnmap_check(&asoc->peer.tsn_map, tsn) < 0) goto discard_noforce; + /* Silently discard the chunk if stream-id is not valid */ + sctp_walk_fwdtsn(skip, chunk) { + if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams) + goto discard_noforce; + } + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn)); if (len > sizeof(struct sctp_fwdtsn_hdr)) sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN, @@ -3695,6 +3702,7 @@ { struct sctp_chunk *chunk = arg; struct sctp_fwdtsn_hdr *fwdtsn_hdr; + struct sctp_fwdtsn_skip *skip; __u16 len; __u32 tsn; @@ -3724,6 +3732,12 @@ if (sctp_tsnmap_check(&asoc->peer.tsn_map, tsn) < 0) goto gen_shutdown; + /* Silently discard the chunk if stream-id is not valid */ + sctp_walk_fwdtsn(skip, chunk) { + if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams) + goto gen_shutdown; + } + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn)); if (len > sizeof(struct sctp_fwdtsn_hdr)) sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN, --- linux-2.6.27.orig/net/sctp/output.c +++ linux-2.6.27/net/sctp/output.c @@ -324,14 +324,16 @@ switch (chunk->chunk_hdr->type) { case SCTP_CID_DATA: retval = sctp_packet_append_data(packet, chunk); + if (SCTP_XMIT_OK != retval) + goto finish; /* Disallow SACK bundling after DATA. */ packet->has_sack = 1; /* Disallow AUTH bundling after DATA */ packet->has_auth = 1; /* Let it be knows that packet has DATA in it */ packet->has_data = 1; - if (SCTP_XMIT_OK != retval) - goto finish; + /* timestamp the chunk for rtx purposes */ + chunk->sent_at = jiffies; break; case SCTP_CID_COOKIE_ECHO: packet->has_cookie_echo = 1; @@ -470,7 +472,6 @@ } else chunk->resent = 1; - chunk->sent_at = jiffies; has_data = 1; } --- linux-2.6.27.orig/net/unix/af_unix.c +++ linux-2.6.27/net/unix/af_unix.c @@ -827,7 +827,8 @@ err = mnt_want_write(nd.path.mnt); if (err) goto out_mknod_dput; - err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, 0); + err = vfs_mknod(nd.path.dentry->d_inode, dentry, nd.path.mnt, + mode, 0); mnt_drop_write(nd.path.mnt); if (err) goto out_mknod_dput; @@ -1300,14 +1301,23 @@ sock_wfree(skb); } -static void unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) +static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) { int i; + + /* + * Need to duplicate file references for the sake of garbage + * collection. Otherwise a socket in the fps might become a + * candidate for GC while the skb is not yet queued. + */ + UNIXCB(skb).fp = scm_fp_dup(scm->fp); + if (!UNIXCB(skb).fp) + return -ENOMEM; + for (i=scm->fp->count-1; i>=0; i--) unix_inflight(scm->fp->fp[i]); - UNIXCB(skb).fp = scm->fp; skb->destructor = unix_destruct_fds; - scm->fp = NULL; + return 0; } /* @@ -1332,6 +1342,7 @@ if (NULL == siocb->scm) siocb->scm = &tmp_scm; + wait_for_unix_gc(); err = scm_send(sock, msg, siocb->scm); if (err < 0) return err; @@ -1366,8 +1377,11 @@ goto out; memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); - if (siocb->scm->fp) - unix_attach_fds(siocb->scm, skb); + if (siocb->scm->fp) { + err = unix_attach_fds(siocb->scm, skb); + if (err) + goto out_free; + } unix_get_secdata(siocb->scm, skb); skb_reset_transport_header(skb); @@ -1479,6 +1493,7 @@ if (NULL == siocb->scm) siocb->scm = &tmp_scm; + wait_for_unix_gc(); err = scm_send(sock, msg, siocb->scm); if (err < 0) return err; @@ -1536,8 +1551,13 @@ size = min_t(int, size, skb_tailroom(skb)); memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); - if (siocb->scm->fp) - unix_attach_fds(siocb->scm, skb); + if (siocb->scm->fp) { + err = unix_attach_fds(siocb->scm, skb); + if (err) { + kfree_skb(skb); + goto out_err; + } + } if ((err = memcpy_fromiovec(skb_put(skb,size), msg->msg_iov, size)) != 0) { kfree_skb(skb); @@ -2211,7 +2231,7 @@ #endif error = 0; out: - return 0; + return error; } static void unix_net_exit(struct net *net) --- linux-2.6.27.orig/net/unix/garbage.c +++ linux-2.6.27/net/unix/garbage.c @@ -80,6 +80,7 @@ #include #include #include +#include #include #include @@ -91,6 +92,7 @@ static LIST_HEAD(gc_inflight_list); static LIST_HEAD(gc_candidates); static DEFINE_SPINLOCK(unix_gc_lock); +static DECLARE_WAIT_QUEUE_HEAD(unix_gc_wait); unsigned int unix_tot_inflight; @@ -186,8 +188,17 @@ */ struct sock *sk = unix_get_socket(*fp++); if (sk) { - hit = true; - func(unix_sk(sk)); + struct unix_sock *u = unix_sk(sk); + + /* + * Ignore non-candidates, they could + * have been added to the queues after + * starting the garbage collection + */ + if (u->gc_candidate) { + hit = true; + func(u); + } } } if (hit && hitlist != NULL) { @@ -249,24 +260,29 @@ { atomic_long_inc(&u->inflight); /* - * If this is still a candidate, move it to the end of the - * list, so that it's checked even if it was already passed - * over + * If this still might be part of a cycle, move it to the end + * of the list, so that it's checked even if it was already + * passed over */ - if (u->gc_candidate) + if (u->gc_maybe_cycle) list_move_tail(&u->link, &gc_candidates); } -/* The external entry point: unix_gc() */ +static bool gc_in_progress = false; -void unix_gc(void) +void wait_for_unix_gc(void) { - static bool gc_in_progress = false; + wait_event(unix_gc_wait, gc_in_progress == false); +} +/* The external entry point: unix_gc() */ +void unix_gc(void) +{ struct unix_sock *u; struct unix_sock *next; struct sk_buff_head hitlist; struct list_head cursor; + LIST_HEAD(not_cycle_list); spin_lock(&unix_gc_lock); @@ -282,10 +298,14 @@ * * Holding unix_gc_lock will protect these candidates from * being detached, and hence from gaining an external - * reference. This also means, that since there are no - * possible receivers, the receive queues of these sockets are - * static during the GC, even though the dequeue is done - * before the detach without atomicity guarantees. + * reference. Since there are no possible receivers, all + * buffers currently on the candidates' queues stay there + * during the garbage collection. + * + * We also know that no new candidate can be added onto the + * receive queues. Other, non candidate sockets _can_ be + * added to queue, so we must make sure only to touch + * candidates. */ list_for_each_entry_safe(u, next, &gc_inflight_list, link) { long total_refs; @@ -299,6 +319,7 @@ if (total_refs == inflight_refs) { list_move_tail(&u->link, &gc_candidates); u->gc_candidate = 1; + u->gc_maybe_cycle = 1; } } @@ -325,14 +346,24 @@ list_move(&cursor, &u->link); if (atomic_long_read(&u->inflight) > 0) { - list_move_tail(&u->link, &gc_inflight_list); - u->gc_candidate = 0; + list_move_tail(&u->link, ¬_cycle_list); + u->gc_maybe_cycle = 0; scan_children(&u->sk, inc_inflight_move_tail, NULL); } } list_del(&cursor); /* + * not_cycle_list contains those sockets which do not make up a + * cycle. Restore these to the inflight list. + */ + while (!list_empty(¬_cycle_list)) { + u = list_entry(not_cycle_list.next, struct unix_sock, link); + u->gc_candidate = 0; + list_move_tail(&u->link, &gc_inflight_list); + } + + /* * Now gc_candidates contains only garbage. Restore original * inflight counters for these as well, and remove the skbuffs * which are creating the cycle(s). @@ -351,6 +382,7 @@ /* All candidates should have been detached by now. */ BUG_ON(!list_empty(&gc_candidates)); gc_in_progress = false; + wake_up(&unix_gc_wait); out: spin_unlock(&unix_gc_lock); --- linux-2.6.27.orig/net/netrom/af_netrom.c +++ linux-2.6.27/net/netrom/af_netrom.c @@ -1082,7 +1082,13 @@ SOCK_DEBUG(sk, "NET/ROM: sendto: Addresses built.\n"); - /* Build a packet */ + /* Build a packet - the conventional user limit is 236 bytes. We can + do ludicrously large NetROM frames but must not overflow */ + if (len > 65536) { + err = -EMSGSIZE; + goto out; + } + SOCK_DEBUG(sk, "NET/ROM: sendto: building packet.\n"); size = len + NR_NETWORK_LEN + NR_TRANSPORT_LEN; --- linux-2.6.27.orig/net/ipv6/udp.c +++ linux-2.6.27/net/ipv6/udp.c @@ -313,7 +313,7 @@ return -1; } -static struct sock *udp_v6_mcast_next(struct sock *sk, +static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, __be16 loc_port, struct in6_addr *loc_addr, __be16 rmt_port, struct in6_addr *rmt_addr, int dif) @@ -325,7 +325,7 @@ sk_for_each_from(s, node) { struct inet_sock *inet = inet_sk(s); - if (sock_net(s) != sock_net(sk)) + if (!net_eq(sock_net(s), net)) continue; if (s->sk_hash == num && s->sk_family == PF_INET6) { @@ -368,14 +368,14 @@ read_lock(&udp_hash_lock); sk = sk_head(&udptable[udp_hashfn(net, ntohs(uh->dest))]); dif = inet6_iif(skb); - sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); + sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); if (!sk) { kfree_skb(skb); goto out; } sk2 = sk; - while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr, + while ((sk2 = udp_v6_mcast_next(net, sk_next(sk2), uh->dest, daddr, uh->source, saddr, dif))) { struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); if (buff) { --- linux-2.6.27.orig/net/ipv6/ip6_flowlabel.c +++ linux-2.6.27/net/ipv6/ip6_flowlabel.c @@ -323,17 +323,21 @@ fl_create(struct net *net, struct in6_flowlabel_req *freq, char __user *optval, int optlen, int *err_p) { - struct ip6_flowlabel *fl; + struct ip6_flowlabel *fl = NULL; int olen; int addr_type; int err; + olen = optlen - CMSG_ALIGN(sizeof(*freq)); + err = -EINVAL; + if (olen > 64 * 1024) + goto done; + err = -ENOMEM; fl = kzalloc(sizeof(*fl), GFP_KERNEL); if (fl == NULL) goto done; - olen = optlen - CMSG_ALIGN(sizeof(*freq)); if (olen > 0) { struct msghdr msg; struct flowi flowi; --- linux-2.6.27.orig/net/ipv6/ip6_output.c +++ linux-2.6.27/net/ipv6/ip6_output.c @@ -1091,6 +1091,18 @@ return err; } +static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src, + gfp_t gfp) +{ + return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL; +} + +static inline struct ipv6_rt_hdr *ip6_rthdr_dup(struct ipv6_rt_hdr *src, + gfp_t gfp) +{ + return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL; +} + int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), void *from, int length, int transhdrlen, @@ -1116,17 +1128,37 @@ * setup for corking */ if (opt) { - if (np->cork.opt == NULL) { - np->cork.opt = kmalloc(opt->tot_len, - sk->sk_allocation); - if (unlikely(np->cork.opt == NULL)) - return -ENOBUFS; - } else if (np->cork.opt->tot_len < opt->tot_len) { - printk(KERN_DEBUG "ip6_append_data: invalid option length\n"); + if (WARN_ON(np->cork.opt)) return -EINVAL; - } - memcpy(np->cork.opt, opt, opt->tot_len); - inet->cork.flags |= IPCORK_OPT; + + np->cork.opt = kmalloc(opt->tot_len, sk->sk_allocation); + if (unlikely(np->cork.opt == NULL)) + return -ENOBUFS; + + np->cork.opt->tot_len = opt->tot_len; + np->cork.opt->opt_flen = opt->opt_flen; + np->cork.opt->opt_nflen = opt->opt_nflen; + + np->cork.opt->dst0opt = ip6_opt_dup(opt->dst0opt, + sk->sk_allocation); + if (opt->dst0opt && !np->cork.opt->dst0opt) + return -ENOBUFS; + + np->cork.opt->dst1opt = ip6_opt_dup(opt->dst1opt, + sk->sk_allocation); + if (opt->dst1opt && !np->cork.opt->dst1opt) + return -ENOBUFS; + + np->cork.opt->hopopt = ip6_opt_dup(opt->hopopt, + sk->sk_allocation); + if (opt->hopopt && !np->cork.opt->hopopt) + return -ENOBUFS; + + np->cork.opt->srcrt = ip6_rthdr_dup(opt->srcrt, + sk->sk_allocation); + if (opt->srcrt && !np->cork.opt->srcrt) + return -ENOBUFS; + /* need source address above miyazawa*/ } dst_hold(&rt->u.dst); @@ -1153,8 +1185,7 @@ } else { rt = (struct rt6_info *)inet->cork.dst; fl = &inet->cork.fl; - if (inet->cork.flags & IPCORK_OPT) - opt = np->cork.opt; + opt = np->cork.opt; transhdrlen = 0; exthdrlen = 0; mtu = inet->cork.fragsize; @@ -1393,9 +1424,15 @@ static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np) { - inet->cork.flags &= ~IPCORK_OPT; - kfree(np->cork.opt); - np->cork.opt = NULL; + if (np->cork.opt) { + kfree(np->cork.opt->dst0opt); + kfree(np->cork.opt->dst1opt); + kfree(np->cork.opt->hopopt); + kfree(np->cork.opt->srcrt); + kfree(np->cork.opt); + np->cork.opt = NULL; + } + if (inet->cork.dst) { dst_release(inet->cork.dst); inet->cork.dst = NULL; --- linux-2.6.27.orig/net/ipv6/inet6_hashtables.c +++ linux-2.6.27/net/ipv6/inet6_hashtables.c @@ -210,11 +210,11 @@ if (twp != NULL) { *twp = tw; - NET_INC_STATS_BH(twsk_net(tw), LINUX_MIB_TIMEWAITRECYCLED); + NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED); } else if (tw != NULL) { /* Silly. Should hash-dance instead... */ inet_twsk_deschedule(tw, death_row); - NET_INC_STATS_BH(twsk_net(tw), LINUX_MIB_TIMEWAITRECYCLED); + NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED); inet_twsk_put(tw); } --- linux-2.6.27.orig/net/ipv6/tcp_ipv6.c +++ linux-2.6.27/net/ipv6/tcp_ipv6.c @@ -1087,7 +1087,7 @@ *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); *topt++ = htonl(tcp_time_stamp); - *topt = htonl(ts); + *topt++ = htonl(ts); } #ifdef CONFIG_TCP_MD5SIG --- linux-2.6.27.orig/net/ipv6/ip6_fib.c +++ linux-2.6.27/net/ipv6/ip6_fib.c @@ -298,6 +298,10 @@ struct fib6_walker_t *w = (void*)cb->args[2]; if (w) { + if (cb->args[4]) { + cb->args[4] = 0; + fib6_walker_unlink(w); + } cb->args[2] = 0; kfree(w); } @@ -330,15 +334,12 @@ read_lock_bh(&table->tb6_lock); res = fib6_walk_continue(w); read_unlock_bh(&table->tb6_lock); - if (res != 0) { - if (res < 0) - fib6_walker_unlink(w); - goto end; + if (res <= 0) { + fib6_walker_unlink(w); + cb->args[4] = 0; } - fib6_walker_unlink(w); - cb->args[4] = 0; } -end: + return res; } --- linux-2.6.27.orig/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ linux-2.6.27/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -49,8 +49,8 @@ static const u_int8_t invmap[] = { [ICMPV6_ECHO_REQUEST - 128] = ICMPV6_ECHO_REPLY + 1, [ICMPV6_ECHO_REPLY - 128] = ICMPV6_ECHO_REQUEST + 1, - [ICMPV6_NI_QUERY - 128] = ICMPV6_NI_QUERY + 1, - [ICMPV6_NI_REPLY - 128] = ICMPV6_NI_REPLY +1 + [ICMPV6_NI_QUERY - 128] = ICMPV6_NI_REPLY + 1, + [ICMPV6_NI_REPLY - 128] = ICMPV6_NI_QUERY +1 }; static bool icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple, --- linux-2.6.27.orig/kernel/fork.c +++ linux-2.6.27/kernel/fork.c @@ -313,17 +313,20 @@ file = tmp->vm_file; if (file) { struct inode *inode = file->f_path.dentry->d_inode; + struct address_space *mapping = file->f_mapping; + get_file(file); if (tmp->vm_flags & VM_DENYWRITE) atomic_dec(&inode->i_writecount); - - /* insert tmp into the share list, just after mpnt */ - spin_lock(&file->f_mapping->i_mmap_lock); + spin_lock(&mapping->i_mmap_lock); + if (tmp->vm_flags & VM_SHARED) + mapping->i_mmap_writable++; tmp->vm_truncate_count = mpnt->vm_truncate_count; - flush_dcache_mmap_lock(file->f_mapping); + flush_dcache_mmap_lock(mapping); + /* insert tmp into the share list, just after mpnt */ vma_prio_tree_add(tmp, mpnt); - flush_dcache_mmap_unlock(file->f_mapping); - spin_unlock(&file->f_mapping->i_mmap_lock); + flush_dcache_mmap_unlock(mapping); + spin_unlock(&mapping->i_mmap_lock); } /* @@ -862,7 +865,7 @@ clear_freeze_flag(p); } -asmlinkage long sys_set_tid_address(int __user *tidptr) +SYSCALL_DEFINE1(set_tid_address, int __user *, tidptr) { current->clear_child_tid = tidptr; @@ -1134,10 +1137,6 @@ #endif clear_all_latency_tracing(p); - /* Our parent execution domain becomes current domain - These must match for thread signalling to apply */ - p->parent_exec_id = p->self_exec_id; - /* ok, now we should be set up.. */ p->exit_signal = (clone_flags & CLONE_THREAD) ? -1 : (clone_flags & CSIGNAL); p->pdeath_signal = 0; @@ -1175,10 +1174,13 @@ set_task_cpu(p, smp_processor_id()); /* CLONE_PARENT re-uses the old parent */ - if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) + if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) { p->real_parent = current->real_parent; - else + p->parent_exec_id = current->parent_exec_id; + } else { p->real_parent = current; + p->parent_exec_id = current->self_exec_id; + } spin_lock(¤t->sighand->siglock); @@ -1558,7 +1560,7 @@ * constructed. Here we are modifying the current, active, * task_struct. */ -asmlinkage long sys_unshare(unsigned long unshare_flags) +SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) { int err = 0; struct fs_struct *fs, *new_fs = NULL; --- linux-2.6.27.orig/kernel/wait.c +++ linux-2.6.27/kernel/wait.c @@ -101,6 +101,15 @@ } EXPORT_SYMBOL(prepare_to_wait_exclusive); +/* + * finish_wait - clean up after waiting in a queue + * @q: waitqueue waited on + * @wait: wait descriptor + * + * Sets current thread back to running state and removes + * the wait descriptor from the given waitqueue if still + * queued. + */ void finish_wait(wait_queue_head_t *q, wait_queue_t *wait) { unsigned long flags; @@ -127,6 +136,39 @@ } EXPORT_SYMBOL(finish_wait); +/* + * abort_exclusive_wait - abort exclusive waiting in a queue + * @q: waitqueue waited on + * @wait: wait descriptor + * @state: runstate of the waiter to be woken + * @key: key to identify a wait bit queue or %NULL + * + * Sets current thread back to running state and removes + * the wait descriptor from the given waitqueue if still + * queued. + * + * Wakes up the next waiter if the caller is concurrently + * woken up through the queue. + * + * This prevents waiter starvation where an exclusive waiter + * aborts and is woken up concurrently and noone wakes up + * the next waiter. + */ +void abort_exclusive_wait(wait_queue_head_t *q, wait_queue_t *wait, + unsigned int mode, void *key) +{ + unsigned long flags; + + __set_current_state(TASK_RUNNING); + spin_lock_irqsave(&q->lock, flags); + if (!list_empty(&wait->task_list)) + list_del_init(&wait->task_list); + else if (waitqueue_active(q)) + __wake_up_common(q, mode, 1, 0, key); + spin_unlock_irqrestore(&q->lock, flags); +} +EXPORT_SYMBOL(abort_exclusive_wait); + int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key) { int ret = default_wake_function(wait, mode, sync, key); @@ -187,17 +229,20 @@ __wait_on_bit_lock(wait_queue_head_t *wq, struct wait_bit_queue *q, int (*action)(void *), unsigned mode) { - int ret = 0; - do { + int ret; + prepare_to_wait_exclusive(wq, &q->wait, mode); - if (test_bit(q->key.bit_nr, q->key.flags)) { - if ((ret = (*action)(q->key.flags))) - break; - } + if (!test_bit(q->key.bit_nr, q->key.flags)) + continue; + ret = action(q->key.flags); + if (!ret) + continue; + abort_exclusive_wait(wq, &q->wait, mode, &q->key); + return ret; } while (test_and_set_bit(q->key.bit_nr, q->key.flags)); finish_wait(wq, &q->wait); - return ret; + return 0; } EXPORT_SYMBOL(__wait_on_bit_lock); --- linux-2.6.27.orig/kernel/audit.c +++ linux-2.6.27/kernel/audit.c @@ -1231,8 +1231,7 @@ * will be called a second time. Currently, we assume that a printk * can't format message larger than 1024 bytes, so we don't either. */ -static void audit_log_vformat(struct audit_buffer *ab, const char *fmt, - va_list args) +void audit_log_vformat(struct audit_buffer *ab, const char *fmt, va_list args) { int len, avail; struct sk_buff *skb; @@ -1506,3 +1505,6 @@ EXPORT_SYMBOL(audit_log_end); EXPORT_SYMBOL(audit_log_format); EXPORT_SYMBOL(audit_log); +EXPORT_SYMBOL_GPL(audit_log_vformat); +EXPORT_SYMBOL_GPL(audit_log_untrustedstring); +EXPORT_SYMBOL_GPL(audit_log_d_path); --- linux-2.6.27.orig/kernel/timer.c +++ linux-2.6.27/kernel/timer.c @@ -1074,7 +1074,7 @@ * For backwards compatibility? This can be done in libc so Alpha * and all newer ports shouldn't need it. */ -asmlinkage unsigned long sys_alarm(unsigned int seconds) +SYSCALL_DEFINE1(alarm, unsigned int, seconds) { return alarm_setitimer(seconds); } @@ -1097,7 +1097,7 @@ * * This is SMP safe as current->tgid does not change. */ -asmlinkage long sys_getpid(void) +SYSCALL_DEFINE0(getpid) { return task_tgid_vnr(current); } @@ -1108,7 +1108,7 @@ * value of ->real_parent under rcu_read_lock(), see * release_task()->call_rcu(delayed_put_task_struct). */ -asmlinkage long sys_getppid(void) +SYSCALL_DEFINE0(getppid) { int pid; @@ -1119,25 +1119,25 @@ return pid; } -asmlinkage long sys_getuid(void) +SYSCALL_DEFINE0(getuid) { /* Only we change this so SMP safe */ return current->uid; } -asmlinkage long sys_geteuid(void) +SYSCALL_DEFINE0(geteuid) { /* Only we change this so SMP safe */ return current->euid; } -asmlinkage long sys_getgid(void) +SYSCALL_DEFINE0(getgid) { /* Only we change this so SMP safe */ return current->gid; } -asmlinkage long sys_getegid(void) +SYSCALL_DEFINE0(getegid) { /* Only we change this so SMP safe */ return current->egid; @@ -1253,7 +1253,7 @@ EXPORT_SYMBOL(schedule_timeout_uninterruptible); /* Thread ID - the internal kernel "pid" */ -asmlinkage long sys_gettid(void) +SYSCALL_DEFINE0(gettid) { return task_pid_vnr(current); } @@ -1345,7 +1345,7 @@ return 0; } -asmlinkage long sys_sysinfo(struct sysinfo __user *info) +SYSCALL_DEFINE1(sysinfo, struct sysinfo __user *, info) { struct sysinfo val; --- linux-2.6.27.orig/kernel/futex.c +++ linux-2.6.27/kernel/futex.c @@ -1797,9 +1797,8 @@ * @head: pointer to the list-head * @len: length of the list-head, as userspace expects */ -asmlinkage long -sys_set_robust_list(struct robust_list_head __user *head, - size_t len) +SYSCALL_DEFINE2(set_robust_list, struct robust_list_head __user *, head, + size_t, len) { if (!futex_cmpxchg_enabled) return -ENOSYS; @@ -1820,9 +1819,9 @@ * @head_ptr: pointer to a list-head pointer, the kernel fills it in * @len_ptr: pointer to a length field, the kernel fills in the header size */ -asmlinkage long -sys_get_robust_list(int pid, struct robust_list_head __user * __user *head_ptr, - size_t __user *len_ptr) +SYSCALL_DEFINE3(get_robust_list, int, pid, + struct robust_list_head __user * __user *, head_ptr, + size_t __user *, len_ptr) { struct robust_list_head __user *head; unsigned long ret; @@ -2036,9 +2035,9 @@ } -asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val, - struct timespec __user *utime, u32 __user *uaddr2, - u32 val3) +SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val, + struct timespec __user *, utime, u32 __user *, uaddr2, + u32, val3) { struct timespec ts; ktime_t t, *tp = NULL; --- linux-2.6.27.orig/kernel/kexec.c +++ linux-2.6.27/kernel/kexec.c @@ -933,9 +933,8 @@ static DEFINE_MUTEX(kexec_mutex); -asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, - struct kexec_segment __user *segments, - unsigned long flags) +SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, + struct kexec_segment __user *, segments, unsigned long, flags) { struct kimage **dest_image, *image; int result; --- linux-2.6.27.orig/kernel/sys.c +++ linux-2.6.27/kernel/sys.c @@ -137,7 +137,7 @@ return error; } -asmlinkage long sys_setpriority(int which, int who, int niceval) +SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval) { struct task_struct *g, *p; struct user_struct *user; @@ -201,7 +201,7 @@ * has been offset by 20 (ie it returns 40..1 instead of -20..19) * to stay compatible. */ -asmlinkage long sys_getpriority(int which, int who) +SYSCALL_DEFINE2(getpriority, int, which, int, who) { struct task_struct *g, *p; struct user_struct *user; @@ -347,7 +347,8 @@ * * reboot doesn't sync: do that yourself before calling this. */ -asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user * arg) +SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, + void __user *, arg) { char buffer[256]; @@ -470,7 +471,7 @@ * SMP: There are not races, the GIDs are checked only by filesystem * operations (as far as semantic preservation is concerned). */ -asmlinkage long sys_setregid(gid_t rgid, gid_t egid) +SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) { int old_rgid = current->gid; int old_egid = current->egid; @@ -519,7 +520,7 @@ * * SMP: Same implicit races as above. */ -asmlinkage long sys_setgid(gid_t gid) +SYSCALL_DEFINE1(setgid, gid_t, gid) { int old_egid = current->egid; int retval; @@ -589,7 +590,7 @@ * 100% compatible with BSD. A program which uses just setuid() will be * 100% compatible with POSIX with saved IDs. */ -asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) +SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) { int old_ruid, old_euid, old_suid, new_ruid, new_euid; int retval; @@ -651,7 +652,7 @@ * will allow a root program to temporarily drop privileges and be able to * regain them by swapping the real and effective uid. */ -asmlinkage long sys_setuid(uid_t uid) +SYSCALL_DEFINE1(setuid, uid_t, uid) { int old_euid = current->euid; int old_ruid, old_suid, new_suid; @@ -690,7 +691,7 @@ * This function implements a generic ability to update ruid, euid, * and suid. This allows you to implement the 4.4 compatible seteuid(). */ -asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) +SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) { int old_ruid = current->uid; int old_euid = current->euid; @@ -733,7 +734,7 @@ return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES); } -asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid) +SYSCALL_DEFINE3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __user *, suid) { int retval; @@ -747,7 +748,7 @@ /* * Same as above, but for rgid, egid, sgid. */ -asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) +SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) { int retval; @@ -784,7 +785,7 @@ return 0; } -asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid) +SYSCALL_DEFINE3(getresgid, gid_t __user *, rgid, gid_t __user *, egid, gid_t __user *, sgid) { int retval; @@ -802,7 +803,7 @@ * whatever uid it wants to). It normally shadows "euid", except when * explicitly set by setfsuid() or for access.. */ -asmlinkage long sys_setfsuid(uid_t uid) +SYSCALL_DEFINE1(setfsuid, uid_t, uid) { int old_fsuid; @@ -831,7 +832,7 @@ /* * Samma pĆ„ svenska.. */ -asmlinkage long sys_setfsgid(gid_t gid) +SYSCALL_DEFINE1(setfsgid, gid_t, gid) { int old_fsgid; @@ -853,7 +854,7 @@ return old_fsgid; } -asmlinkage long sys_times(struct tms __user * tbuf) +SYSCALL_DEFINE1(times, struct tms __user *, tbuf) { /* * In the SMP world we might just be unlucky and have one of @@ -903,7 +904,7 @@ * Auch. Had to add the 'did_exec' flag to conform completely to POSIX. * LBT 04.03.94 */ -asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) +SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid) { struct task_struct *p; struct task_struct *group_leader = current->group_leader; @@ -974,7 +975,7 @@ return err; } -asmlinkage long sys_getpgid(pid_t pid) +SYSCALL_DEFINE1(getpgid, pid_t, pid) { struct task_struct *p; struct pid *grp; @@ -1004,14 +1005,14 @@ #ifdef __ARCH_WANT_SYS_GETPGRP -asmlinkage long sys_getpgrp(void) +SYSCALL_DEFINE0(getpgrp) { return sys_getpgid(0); } #endif -asmlinkage long sys_getsid(pid_t pid) +SYSCALL_DEFINE1(getsid, pid_t, pid) { struct task_struct *p; struct pid *sid; @@ -1039,7 +1040,7 @@ return retval; } -asmlinkage long sys_setsid(void) +SYSCALL_DEFINE0(setsid) { struct task_struct *group_leader = current->group_leader; struct pid *sid = task_pid(group_leader); @@ -1245,7 +1246,7 @@ EXPORT_SYMBOL(set_current_groups); -asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist) +SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t __user *, grouplist) { int i = 0; @@ -1278,7 +1279,7 @@ * without another task interfering. */ -asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist) +SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist) { struct group_info *group_info; int retval; @@ -1328,7 +1329,7 @@ DECLARE_RWSEM(uts_sem); -asmlinkage long sys_newuname(struct new_utsname __user * name) +SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) { int errno = 0; @@ -1339,7 +1340,7 @@ return errno; } -asmlinkage long sys_sethostname(char __user *name, int len) +SYSCALL_DEFINE2(sethostname, char __user *, name, int, len) { int errno; char tmp[__NEW_UTS_LEN]; @@ -1361,7 +1362,7 @@ #ifdef __ARCH_WANT_SYS_GETHOSTNAME -asmlinkage long sys_gethostname(char __user *name, int len) +SYSCALL_DEFINE2(gethostname, char __user *, name, int, len) { int i, errno; @@ -1384,7 +1385,7 @@ * Only setdomainname; getdomainname can be implemented by calling * uname() */ -asmlinkage long sys_setdomainname(char __user *name, int len) +SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len) { int errno; char tmp[__NEW_UTS_LEN]; @@ -1405,7 +1406,7 @@ return errno; } -asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit __user *rlim) +SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim) { if (resource >= RLIM_NLIMITS) return -EINVAL; @@ -1424,7 +1425,8 @@ * Back compatibility for getrlimit. Needed for some apps. */ -asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit __user *rlim) +SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource, + struct rlimit __user *, rlim) { struct rlimit x; if (resource >= RLIM_NLIMITS) @@ -1442,7 +1444,7 @@ #endif -asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim) +SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim) { struct rlimit new_rlim, *old_rlim; unsigned long it_prof_secs; @@ -1618,7 +1620,7 @@ return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0; } -asmlinkage long sys_getrusage(int who, struct rusage __user *ru) +SYSCALL_DEFINE2(getrusage, int, who, struct rusage __user *, ru) { if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN && who != RUSAGE_THREAD) @@ -1626,14 +1628,14 @@ return getrusage(current, who, ru); } -asmlinkage long sys_umask(int mask) +SYSCALL_DEFINE1(umask, int, mask) { mask = xchg(¤t->fs->umask, mask & S_IRWXUGO); return mask; } -asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5) +SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, + unsigned long, arg4, unsigned long, arg5) { long error = 0; @@ -1734,8 +1736,8 @@ return error; } -asmlinkage long sys_getcpu(unsigned __user *cpup, unsigned __user *nodep, - struct getcpu_cache __user *unused) +SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep, + struct getcpu_cache __user *, unused) { int err = 0; int cpu = raw_smp_processor_id(); --- linux-2.6.27.orig/kernel/exec_domain.c +++ linux-2.6.27/kernel/exec_domain.c @@ -188,8 +188,7 @@ return (len); } -asmlinkage long -sys_personality(u_long personality) +SYSCALL_DEFINE1(personality, u_long, personality) { u_long old = current->personality; --- linux-2.6.27.orig/kernel/sys_ni.c +++ linux-2.6.27/kernel/sys_ni.c @@ -125,6 +125,7 @@ cond_syscall(sys_vm86); cond_syscall(compat_sys_ipc); cond_syscall(compat_sys_sysctl); +cond_syscall(sys_syslog); /* arch-specific weak syscall entries */ cond_syscall(sys_pciconfig_read); --- linux-2.6.27.orig/kernel/relay.c +++ linux-2.6.27/kernel/relay.c @@ -664,8 +664,10 @@ mutex_lock(&relay_channels_mutex); /* Is chan already set up? */ - if (unlikely(chan->has_base_filename)) + if (unlikely(chan->has_base_filename)) { + mutex_unlock(&relay_channels_mutex); return -EEXIST; + } chan->has_base_filename = 1; chan->parent = parent; curr_cpu = get_cpu(); --- linux-2.6.27.orig/kernel/time.c +++ linux-2.6.27/kernel/time.c @@ -59,7 +59,7 @@ * why not move it into the appropriate arch directory (for those * architectures that need it). */ -asmlinkage long sys_time(time_t __user * tloc) +SYSCALL_DEFINE1(time, time_t __user *, tloc) { time_t i = get_seconds(); @@ -77,7 +77,7 @@ * architectures that need it). */ -asmlinkage long sys_stime(time_t __user *tptr) +SYSCALL_DEFINE1(stime, time_t __user *, tptr) { struct timespec tv; int err; @@ -97,8 +97,8 @@ #endif /* __ARCH_WANT_SYS_TIME */ -asmlinkage long sys_gettimeofday(struct timeval __user *tv, - struct timezone __user *tz) +SYSCALL_DEFINE2(gettimeofday, struct timeval __user *, tv, + struct timezone __user *, tz) { if (likely(tv != NULL)) { struct timeval ktv; @@ -182,8 +182,8 @@ return 0; } -asmlinkage long sys_settimeofday(struct timeval __user *tv, - struct timezone __user *tz) +SYSCALL_DEFINE2(settimeofday, struct timeval __user *, tv, + struct timezone __user *, tz) { struct timeval user_tv; struct timespec new_ts; @@ -203,7 +203,7 @@ return do_sys_settimeofday(tv ? &new_ts : NULL, tz ? &new_tz : NULL); } -asmlinkage long sys_adjtimex(struct timex __user *txc_p) +SYSCALL_DEFINE1(adjtimex, struct timex __user *, txc_p) { struct timex txc; /* Local copy of parameter */ int ret; --- linux-2.6.27.orig/kernel/sched_features.h +++ linux-2.6.27/kernel/sched_features.h @@ -5,7 +5,7 @@ SCHED_FEAT(AFFINE_WAKEUPS, 1) SCHED_FEAT(CACHE_HOT_BUDDY, 1) SCHED_FEAT(SYNC_WAKEUPS, 1) -SCHED_FEAT(HRTICK, 1) +SCHED_FEAT(HRTICK, 0) SCHED_FEAT(DOUBLE_TICK, 0) SCHED_FEAT(ASYM_GRAN, 1) SCHED_FEAT(LB_BIAS, 1) --- linux-2.6.27.orig/kernel/exit.c +++ linux-2.6.27/kernel/exit.c @@ -938,8 +938,7 @@ */ if (tsk->exit_signal != SIGCHLD && !task_detached(tsk) && (tsk->parent_exec_id != tsk->real_parent->self_exec_id || - tsk->self_exec_id != tsk->parent_exec_id) && - !capable(CAP_KILL)) + tsk->self_exec_id != tsk->parent_exec_id)) tsk->exit_signal = SIGCHLD; signal = tracehook_notify_death(tsk, &cookie, group_dead); @@ -1145,7 +1144,7 @@ EXPORT_SYMBOL(complete_and_exit); -asmlinkage long sys_exit(int error_code) +SYSCALL_DEFINE1(exit, int, error_code) { do_exit((error_code&0xff)<<8); } @@ -1186,9 +1185,11 @@ * wait4()-ing process will get the correct exit code - even if this * thread is not the thread group leader. */ -asmlinkage void sys_exit_group(int error_code) +SYSCALL_DEFINE1(exit_group, int, error_code) { do_group_exit((error_code & 0xff) << 8); + /* NOTREACHED */ + return 0; } static struct pid *task_pid_type(struct task_struct *task, enum pid_type type) @@ -1749,9 +1750,8 @@ return retval; } -asmlinkage long sys_waitid(int which, pid_t upid, - struct siginfo __user *infop, int options, - struct rusage __user *ru) +SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *, + infop, int, options, struct rusage __user *, ru) { struct pid *pid = NULL; enum pid_type type; @@ -1790,8 +1790,8 @@ return ret; } -asmlinkage long sys_wait4(pid_t upid, int __user *stat_addr, - int options, struct rusage __user *ru) +SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr, + int, options, struct rusage __user *, ru) { struct pid *pid = NULL; enum pid_type type; @@ -1828,7 +1828,7 @@ * sys_waitpid() remains for compatibility. waitpid() should be * implemented by calling sys_wait4() from libc.a. */ -asmlinkage long sys_waitpid(pid_t pid, int __user *stat_addr, int options) +SYSCALL_DEFINE3(waitpid, pid_t, pid, int __user *, stat_addr, int, options) { return sys_wait4(pid, stat_addr, options, NULL); } --- linux-2.6.27.orig/kernel/hrtimer.c +++ linux-2.6.27/kernel/hrtimer.c @@ -1560,8 +1560,8 @@ return ret; } -asmlinkage long -sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp) +SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp, + struct timespec __user *, rmtp) { struct timespec tu; --- linux-2.6.27.orig/kernel/sysctl.c +++ linux-2.6.27/kernel/sysctl.c @@ -179,6 +179,9 @@ #ifdef CONFIG_INOTIFY_USER extern struct ctl_table inotify_table[]; #endif +#ifdef CONFIG_EPOLL +extern struct ctl_table epoll_table[]; +#endif #ifdef HAVE_ARCH_PICK_MMAP_LAYOUT int sysctl_legacy_va_layout; @@ -1313,6 +1316,13 @@ .child = inotify_table, }, #endif +#ifdef CONFIG_EPOLL + { + .procname = "epoll", + .mode = 0555, + .child = epoll_table, + }, +#endif #endif { .ctl_name = KERN_SETUID_DUMPABLE, @@ -1506,6 +1516,33 @@ spin_unlock(&sysctl_lock); } +char *sysctl_pathname(struct ctl_table *table, char *buffer, int buflen) +{ + if (buflen < 1) + return NULL; + buffer += --buflen; + *buffer = '\0'; + + while (table) { + int namelen = strlen(table->procname); + + if (buflen < namelen + 1) + return NULL; + buflen -= namelen + 1; + buffer -= namelen; + memcpy(buffer, table->procname, namelen); + *--buffer = '/'; + table = table->parent; + } + if (buflen < 4) + return NULL; + buffer -= 4; + memcpy(buffer, "/sys", 4); + + return buffer; +} +EXPORT_SYMBOL_GPL(sysctl_pathname); + #ifdef CONFIG_SYSCTL_SYSCALL /* Perform the actual read/write of a sysctl table entry. */ static int do_sysctl_strategy(struct ctl_table_root *root, @@ -1604,7 +1641,7 @@ return error; } -asmlinkage long sys_sysctl(struct __sysctl_args __user *args) +SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args) { struct __sysctl_args tmp; int error; @@ -2915,7 +2952,7 @@ #else /* CONFIG_SYSCTL_SYSCALL */ -asmlinkage long sys_sysctl(struct __sysctl_args __user *args) +SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args) { struct __sysctl_args tmp; int error; --- linux-2.6.27.orig/kernel/sched_stats.h +++ linux-2.6.27/kernel/sched_stats.h @@ -9,7 +9,7 @@ static int show_schedstat(struct seq_file *seq, void *v) { int cpu; - int mask_len = NR_CPUS/32 * 9; + int mask_len = (NR_CPUS/32 + 1) * 9; char *mask_str = kmalloc(mask_len, GFP_KERNEL); if (mask_str == NULL) --- linux-2.6.27.orig/kernel/Makefile +++ linux-2.6.27/kernel/Makefile @@ -11,8 +11,6 @@ hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \ notifier.o ksysfs.o pm_qos_params.o sched_clock.o -CFLAGS_REMOVE_sched.o = -mno-spe - ifdef CONFIG_FTRACE # Do not trace debug files and internal ftrace files CFLAGS_REMOVE_lockdep.o = -pg @@ -21,7 +19,7 @@ CFLAGS_REMOVE_rtmutex-debug.o = -pg CFLAGS_REMOVE_cgroup-debug.o = -pg CFLAGS_REMOVE_sched_clock.o = -pg -CFLAGS_REMOVE_sched.o = -mno-spe -pg +CFLAGS_REMOVE_sched.o = -pg endif obj-$(CONFIG_PROFILING) += profile.o --- linux-2.6.27.orig/kernel/cgroup.c +++ linux-2.6.27/kernel/cgroup.c @@ -2045,10 +2045,13 @@ struct cgroup *cgrp; struct cgroup_iter it; struct task_struct *tsk; + /* - * Validate dentry by checking the superblock operations + * Validate dentry by checking the superblock operations, + * and make sure it's a directory. */ - if (dentry->d_sb->s_op != &cgroup_ops) + if (dentry->d_sb->s_op != &cgroup_ops || + !S_ISDIR(dentry->d_inode->i_mode)) goto err; ret = 0; @@ -2443,7 +2446,6 @@ list_del(&cgrp->sibling); spin_lock(&cgrp->dentry->d_lock); d = dget(cgrp->dentry); - cgrp->dentry = NULL; spin_unlock(&d->d_lock); cgroup_d_remove_dir(d); @@ -2883,7 +2885,11 @@ parent = task_cgroup(tsk, subsys->subsys_id); /* Pin the hierarchy */ - atomic_inc(&parent->root->sb->s_active); + if (!atomic_inc_not_zero(&parent->root->sb->s_active)) { + /* We race with the final deactivate_super() */ + mutex_unlock(&cgroup_mutex); + return 0; + } /* Keep the cgroup alive */ get_css_set(cg); @@ -2905,7 +2911,7 @@ } /* Create the cgroup directory, which also creates the cgroup */ - ret = vfs_mkdir(inode, dentry, S_IFDIR | 0755); + ret = vfs_mkdir(inode, dentry, NULL, S_IFDIR | 0755); child = __d_cgrp(dentry); dput(dentry); if (ret) { --- linux-2.6.27.orig/kernel/module.c +++ linux-2.6.27/kernel/module.c @@ -715,8 +715,8 @@ mutex_lock(&module_mutex); } -asmlinkage long -sys_delete_module(const char __user *name_user, unsigned int flags) +SYSCALL_DEFINE2(delete_module, const char __user *, name_user, + unsigned int, flags) { struct module *mod; char name[MODULE_NAME_LEN]; @@ -1173,7 +1173,7 @@ while (i-- > 0) sysfs_remove_bin_file(notes_attrs->dir, ¬es_attrs->attrs[i]); - kobject_del(notes_attrs->dir); + kobject_put(notes_attrs->dir); } kfree(notes_attrs); } @@ -2257,10 +2257,8 @@ } /* This is where the real work happens */ -asmlinkage long -sys_init_module(void __user *umod, - unsigned long len, - const char __user *uargs) +SYSCALL_DEFINE3(init_module, void __user *, umod, + unsigned long, len, const char __user *, uargs) { struct module *mod; int ret = 0; --- linux-2.6.27.orig/kernel/ptrace.c +++ linux-2.6.27/kernel/ptrace.c @@ -545,7 +545,7 @@ #define arch_ptrace_attach(child) do { } while (0) #endif -asmlinkage long sys_ptrace(long request, long pid, long addr, long data) +SYSCALL_DEFINE4(ptrace, long, request, long, pid, long, addr, long, data) { struct task_struct *child; long ret; --- linux-2.6.27.orig/kernel/itimer.c +++ linux-2.6.27/kernel/itimer.c @@ -109,7 +109,7 @@ return 0; } -asmlinkage long sys_getitimer(int which, struct itimerval __user *value) +SYSCALL_DEFINE2(getitimer, int, which, struct itimerval __user *, value) { int error = -EFAULT; struct itimerval get_buffer; @@ -273,9 +273,8 @@ return it_old.it_value.tv_sec; } -asmlinkage long sys_setitimer(int which, - struct itimerval __user *value, - struct itimerval __user *ovalue) +SYSCALL_DEFINE3(setitimer, int, which, struct itimerval __user *, value, + struct itimerval __user *, ovalue) { struct itimerval set_buffer, get_buffer; int error; --- linux-2.6.27.orig/kernel/seccomp.c +++ linux-2.6.27/kernel/seccomp.c @@ -8,6 +8,7 @@ #include #include +#include /* #define SECCOMP_DEBUG 1 */ #define NR_SECCOMP_MODES 1 @@ -22,7 +23,7 @@ 0, /* null terminated */ }; -#ifdef TIF_32BIT +#ifdef CONFIG_COMPAT static int mode1_syscalls_32[] = { __NR_seccomp_read_32, __NR_seccomp_write_32, __NR_seccomp_exit_32, __NR_seccomp_sigreturn_32, 0, /* null terminated */ @@ -37,8 +38,8 @@ switch (mode) { case 1: syscall = mode1_syscalls; -#ifdef TIF_32BIT - if (test_thread_flag(TIF_32BIT)) +#ifdef CONFIG_COMPAT + if (is_compat_task()) syscall = mode1_syscalls_32; #endif do { --- linux-2.6.27.orig/kernel/sched_rt.c +++ linux-2.6.27/kernel/sched_rt.c @@ -102,12 +102,12 @@ static void sched_rt_rq_enqueue(struct rt_rq *rt_rq) { + struct task_struct *curr = rq_of_rt_rq(rt_rq)->curr; struct sched_rt_entity *rt_se = rt_rq->rt_se; - if (rt_se && !on_rt_rq(rt_se) && rt_rq->rt_nr_running) { - struct task_struct *curr = rq_of_rt_rq(rt_rq)->curr; - - enqueue_rt_entity(rt_se); + if (rt_rq->rt_nr_running) { + if (rt_se && !on_rt_rq(rt_se)) + enqueue_rt_entity(rt_se); if (rt_rq->highest_prio < curr->prio) resched_task(curr); } --- linux-2.6.27.orig/kernel/audit_tree.c +++ linux-2.6.27/kernel/audit_tree.c @@ -24,6 +24,7 @@ struct list_head trees; /* with root here */ int dead; int count; + atomic_long_t refs; struct rcu_head head; struct node { struct list_head list; @@ -56,7 +57,8 @@ * tree is refcounted; one reference for "some rules on rules_list refer to * it", one for each chunk with pointer to it. * - * chunk is refcounted by embedded inotify_watch. + * chunk is refcounted by embedded inotify_watch + .refs (non-zero refcount + * of watch contributes 1 to .refs). * * node.index allows to get from node.list to containing chunk. * MSB of that sucker is stolen to mark taggings that we might have to @@ -121,6 +123,7 @@ INIT_LIST_HEAD(&chunk->hash); INIT_LIST_HEAD(&chunk->trees); chunk->count = count; + atomic_long_set(&chunk->refs, 1); for (i = 0; i < count; i++) { INIT_LIST_HEAD(&chunk->owners[i].list); chunk->owners[i].index = i; @@ -129,9 +132,8 @@ return chunk; } -static void __free_chunk(struct rcu_head *rcu) +static void free_chunk(struct audit_chunk *chunk) { - struct audit_chunk *chunk = container_of(rcu, struct audit_chunk, head); int i; for (i = 0; i < chunk->count; i++) { @@ -141,14 +143,16 @@ kfree(chunk); } -static inline void free_chunk(struct audit_chunk *chunk) +void audit_put_chunk(struct audit_chunk *chunk) { - call_rcu(&chunk->head, __free_chunk); + if (atomic_long_dec_and_test(&chunk->refs)) + free_chunk(chunk); } -void audit_put_chunk(struct audit_chunk *chunk) +static void __put_chunk(struct rcu_head *rcu) { - put_inotify_watch(&chunk->watch); + struct audit_chunk *chunk = container_of(rcu, struct audit_chunk, head); + audit_put_chunk(chunk); } enum {HASH_SIZE = 128}; @@ -176,7 +180,7 @@ list_for_each_entry_rcu(p, list, hash) { if (p->watch.inode == inode) { - get_inotify_watch(&p->watch); + atomic_long_inc(&p->refs); return p; } } @@ -194,17 +198,49 @@ /* tagging and untagging inodes with trees */ -static void untag_chunk(struct audit_chunk *chunk, struct node *p) +static struct audit_chunk *find_chunk(struct node *p) +{ + int index = p->index & ~(1U<<31); + p -= index; + return container_of(p, struct audit_chunk, owners[0]); +} + +static void untag_chunk(struct node *p) { + struct audit_chunk *chunk = find_chunk(p); struct audit_chunk *new; struct audit_tree *owner; int size = chunk->count - 1; int i, j; + if (!pin_inotify_watch(&chunk->watch)) { + /* + * Filesystem is shutting down; all watches are getting + * evicted, just take it off the node list for this + * tree and let the eviction logics take care of the + * rest. + */ + owner = p->owner; + if (owner->root == chunk) { + list_del_init(&owner->same_root); + owner->root = NULL; + } + list_del_init(&p->list); + p->owner = NULL; + put_tree(owner); + return; + } + + spin_unlock(&hash_lock); + + /* + * pin_inotify_watch() succeeded, so the watch won't go away + * from under us. + */ mutex_lock(&chunk->watch.inode->inotify_mutex); if (chunk->dead) { mutex_unlock(&chunk->watch.inode->inotify_mutex); - return; + goto out; } owner = p->owner; @@ -221,7 +257,7 @@ inotify_evict_watch(&chunk->watch); mutex_unlock(&chunk->watch.inode->inotify_mutex); put_inotify_watch(&chunk->watch); - return; + goto out; } new = alloc_chunk(size); @@ -263,7 +299,7 @@ inotify_evict_watch(&chunk->watch); mutex_unlock(&chunk->watch.inode->inotify_mutex); put_inotify_watch(&chunk->watch); - return; + goto out; Fallback: // do the best we can @@ -277,6 +313,9 @@ put_tree(owner); spin_unlock(&hash_lock); mutex_unlock(&chunk->watch.inode->inotify_mutex); +out: + unpin_inotify_watch(&chunk->watch); + spin_lock(&hash_lock); } static int create_chunk(struct inode *inode, struct audit_tree *tree) @@ -387,13 +426,6 @@ return 0; } -static struct audit_chunk *find_chunk(struct node *p) -{ - int index = p->index & ~(1U<<31); - p -= index; - return container_of(p, struct audit_chunk, owners[0]); -} - static void kill_rules(struct audit_tree *tree) { struct audit_krule *rule, *next; @@ -431,17 +463,10 @@ spin_lock(&hash_lock); while (!list_empty(&victim->chunks)) { struct node *p; - struct audit_chunk *chunk; p = list_entry(victim->chunks.next, struct node, list); - chunk = find_chunk(p); - get_inotify_watch(&chunk->watch); - spin_unlock(&hash_lock); - - untag_chunk(chunk, p); - put_inotify_watch(&chunk->watch); - spin_lock(&hash_lock); + untag_chunk(p); } spin_unlock(&hash_lock); put_tree(victim); @@ -469,7 +494,6 @@ while (!list_empty(&tree->chunks)) { struct node *node; - struct audit_chunk *chunk; node = list_entry(tree->chunks.next, struct node, list); @@ -477,14 +501,7 @@ if (!(node->index & (1U<<31))) break; - chunk = find_chunk(node); - get_inotify_watch(&chunk->watch); - spin_unlock(&hash_lock); - - untag_chunk(chunk, node); - - put_inotify_watch(&chunk->watch); - spin_lock(&hash_lock); + untag_chunk(node); } if (!tree->root && !tree->goner) { tree->goner = 1; @@ -878,7 +895,7 @@ static void destroy_watch(struct inotify_watch *watch) { struct audit_chunk *chunk = container_of(watch, struct audit_chunk, watch); - free_chunk(chunk); + call_rcu(&chunk->head, __put_chunk); } static const struct inotify_operations rtree_inotify_ops = { --- linux-2.6.27.orig/kernel/cpuset.c +++ linux-2.6.27/kernel/cpuset.c @@ -587,7 +587,6 @@ int ndoms; /* number of sched domains in result */ int nslot; /* next empty doms[] cpumask_t slot */ - ndoms = 0; doms = NULL; dattr = NULL; csa = NULL; @@ -674,10 +673,8 @@ * Convert to and populate cpu masks. */ doms = kmalloc(ndoms * sizeof(cpumask_t), GFP_KERNEL); - if (!doms) { - ndoms = 0; + if (!doms) goto done; - } /* * The rest of the code, including the scheduler, can deal with @@ -732,6 +729,13 @@ done: kfree(csa); + /* + * Fallback to the default domain if kmalloc() failed. + * See comments in partition_sched_domains(). + */ + if (doms == NULL) + ndoms = 1; + *domains = doms; *attributes = dattr; return ndoms; --- linux-2.6.27.orig/kernel/acct.c +++ linux-2.6.27/kernel/acct.c @@ -277,7 +277,7 @@ * should be written. If the filename is NULL, accounting will be * shutdown. */ -asmlinkage long sys_acct(const char __user *name) +SYSCALL_DEFINE1(acct, const char __user *, name) { int error; --- linux-2.6.27.orig/kernel/signal.c +++ linux-2.6.27/kernel/signal.c @@ -1141,7 +1141,8 @@ struct task_struct * p; for_each_process(p) { - if (p->pid > 1 && !same_thread_group(p, current)) { + if (task_pid_vnr(p) > 1 && + !same_thread_group(p, current)) { int err = group_send_sig_info(sig, info, p); ++count; if (err != -EPERM) @@ -1936,7 +1937,7 @@ * System call entry points. */ -asmlinkage long sys_restart_syscall(void) +SYSCALL_DEFINE0(restart_syscall) { struct restart_block *restart = ¤t_thread_info()->restart_block; return restart->fn(restart); @@ -1989,8 +1990,8 @@ return error; } -asmlinkage long -sys_rt_sigprocmask(int how, sigset_t __user *set, sigset_t __user *oset, size_t sigsetsize) +SYSCALL_DEFINE4(rt_sigprocmask, int, how, sigset_t __user *, set, + sigset_t __user *, oset, size_t, sigsetsize) { int error = -EINVAL; sigset_t old_set, new_set; @@ -2049,8 +2050,7 @@ return error; } -asmlinkage long -sys_rt_sigpending(sigset_t __user *set, size_t sigsetsize) +SYSCALL_DEFINE2(rt_sigpending, sigset_t __user *, set, size_t, sigsetsize) { return do_sigpending(set, sigsetsize); } @@ -2121,11 +2121,9 @@ #endif -asmlinkage long -sys_rt_sigtimedwait(const sigset_t __user *uthese, - siginfo_t __user *uinfo, - const struct timespec __user *uts, - size_t sigsetsize) +SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese, + siginfo_t __user *, uinfo, const struct timespec __user *, uts, + size_t, sigsetsize) { int ret, sig; sigset_t these; @@ -2198,8 +2196,7 @@ return ret; } -asmlinkage long -sys_kill(pid_t pid, int sig) +SYSCALL_DEFINE2(kill, pid_t, pid, int, sig) { struct siginfo info; @@ -2258,7 +2255,7 @@ * exists but it's not belonging to the target process anymore. This * method solves the problem of threads exiting and PIDs getting reused. */ -asmlinkage long sys_tgkill(pid_t tgid, pid_t pid, int sig) +SYSCALL_DEFINE3(tgkill, pid_t, tgid, pid_t, pid, int, sig) { /* This is only valid for single tasks */ if (pid <= 0 || tgid <= 0) @@ -2270,8 +2267,7 @@ /* * Send a signal to only one task, even if it's a CLONE_THREAD task. */ -asmlinkage long -sys_tkill(pid_t pid, int sig) +SYSCALL_DEFINE2(tkill, pid_t, pid, int, sig) { /* This is only valid for single tasks */ if (pid <= 0) @@ -2280,8 +2276,8 @@ return do_tkill(0, pid, sig); } -asmlinkage long -sys_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t __user *uinfo) +SYSCALL_DEFINE3(rt_sigqueueinfo, pid_t, pid, int, sig, + siginfo_t __user *, uinfo) { siginfo_t info; @@ -2409,8 +2405,7 @@ #ifdef __ARCH_WANT_SYS_SIGPENDING -asmlinkage long -sys_sigpending(old_sigset_t __user *set) +SYSCALL_DEFINE1(sigpending, old_sigset_t __user *, set) { return do_sigpending(set, sizeof(*set)); } @@ -2421,8 +2416,8 @@ /* Some platforms have their own version with special arguments others support only sys_rt_sigprocmask. */ -asmlinkage long -sys_sigprocmask(int how, old_sigset_t __user *set, old_sigset_t __user *oset) +SYSCALL_DEFINE3(sigprocmask, int, how, old_sigset_t __user *, set, + old_sigset_t __user *, oset) { int error; old_sigset_t old_set, new_set; @@ -2472,11 +2467,10 @@ #endif /* __ARCH_WANT_SYS_SIGPROCMASK */ #ifdef __ARCH_WANT_SYS_RT_SIGACTION -asmlinkage long -sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - size_t sigsetsize) +SYSCALL_DEFINE4(rt_sigaction, int, sig, + const struct sigaction __user *, act, + struct sigaction __user *, oact, + size_t, sigsetsize) { struct k_sigaction new_sa, old_sa; int ret = -EINVAL; @@ -2506,15 +2500,13 @@ /* * For backwards compatibility. Functionality superseded by sigprocmask. */ -asmlinkage long -sys_sgetmask(void) +SYSCALL_DEFINE0(sgetmask) { /* SMP safe */ return current->blocked.sig[0]; } -asmlinkage long -sys_ssetmask(int newmask) +SYSCALL_DEFINE1(ssetmask, int, newmask) { int old; @@ -2534,8 +2526,7 @@ /* * For backwards compatibility. Functionality superseded by sigaction. */ -asmlinkage unsigned long -sys_signal(int sig, __sighandler_t handler) +SYSCALL_DEFINE2(signal, int, sig, __sighandler_t, handler) { struct k_sigaction new_sa, old_sa; int ret; @@ -2552,8 +2543,7 @@ #ifdef __ARCH_WANT_SYS_PAUSE -asmlinkage long -sys_pause(void) +SYSCALL_DEFINE0(pause) { current->state = TASK_INTERRUPTIBLE; schedule(); @@ -2563,7 +2553,7 @@ #endif #ifdef __ARCH_WANT_SYS_RT_SIGSUSPEND -asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) +SYSCALL_DEFINE2(rt_sigsuspend, sigset_t __user *, unewset, size_t, sigsetsize) { sigset_t newset; --- linux-2.6.27.orig/kernel/printk.c +++ linux-2.6.27/kernel/printk.c @@ -421,7 +421,7 @@ return error; } -asmlinkage long sys_syslog(int type, char __user *buf, int len) +SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) { return do_syslog(type, buf, len); } @@ -782,11 +782,6 @@ #else -asmlinkage long sys_syslog(int type, char __user *buf, int len) -{ - return -ENOSYS; -} - static void call_console_drivers(unsigned start, unsigned end) { } --- linux-2.6.27.orig/kernel/posix-timers.c +++ linux-2.6.27/kernel/posix-timers.c @@ -463,10 +463,9 @@ /* Create a POSIX.1b interval timer. */ -asmlinkage long -sys_timer_create(const clockid_t which_clock, - struct sigevent __user *timer_event_spec, - timer_t __user * created_timer_id) +SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock, + struct sigevent __user *, timer_event_spec, + timer_t __user *, created_timer_id) { int error = 0; struct k_itimer *new_timer = NULL; @@ -682,8 +681,8 @@ } /* Get the time remaining on a POSIX.1b interval timer. */ -asmlinkage long -sys_timer_gettime(timer_t timer_id, struct itimerspec __user *setting) +SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, + struct itimerspec __user *, setting) { struct k_itimer *timr; struct itimerspec cur_setting; @@ -712,8 +711,7 @@ * the call back to do_schedule_next_timer(). So all we need to do is * to pick up the frozen overrun. */ -asmlinkage long -sys_timer_getoverrun(timer_t timer_id) +SYSCALL_DEFINE1(timer_getoverrun, timer_t, timer_id) { struct k_itimer *timr; int overrun; @@ -783,10 +781,9 @@ } /* Set a POSIX.1b interval timer */ -asmlinkage long -sys_timer_settime(timer_t timer_id, int flags, - const struct itimerspec __user *new_setting, - struct itimerspec __user *old_setting) +SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, + const struct itimerspec __user *, new_setting, + struct itimerspec __user *, old_setting) { struct k_itimer *timr; struct itimerspec new_spec, old_spec; @@ -839,8 +836,7 @@ } /* Delete a POSIX.1b interval timer. */ -asmlinkage long -sys_timer_delete(timer_t timer_id) +SYSCALL_DEFINE1(timer_delete, timer_t, timer_id) { struct k_itimer *timer; unsigned long flags; @@ -930,8 +926,8 @@ } EXPORT_SYMBOL_GPL(do_posix_clock_nonanosleep); -asmlinkage long sys_clock_settime(const clockid_t which_clock, - const struct timespec __user *tp) +SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, + const struct timespec __user *, tp) { struct timespec new_tp; @@ -943,8 +939,8 @@ return CLOCK_DISPATCH(which_clock, clock_set, (which_clock, &new_tp)); } -asmlinkage long -sys_clock_gettime(const clockid_t which_clock, struct timespec __user *tp) +SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, + struct timespec __user *,tp) { struct timespec kernel_tp; int error; @@ -960,8 +956,8 @@ } -asmlinkage long -sys_clock_getres(const clockid_t which_clock, struct timespec __user *tp) +SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, + struct timespec __user *, tp) { struct timespec rtn_tp; int error; @@ -990,10 +986,9 @@ which_clock); } -asmlinkage long -sys_clock_nanosleep(const clockid_t which_clock, int flags, - const struct timespec __user *rqtp, - struct timespec __user *rmtp) +SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, + const struct timespec __user *, rqtp, + struct timespec __user *, rmtp) { struct timespec t; --- linux-2.6.27.orig/kernel/sched.c +++ linux-2.6.27/kernel/sched.c @@ -4556,8 +4556,8 @@ * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns * zero in this (rare) case, and we handle it by continuing to scan the queue. */ -static void __wake_up_common(wait_queue_head_t *q, unsigned int mode, - int nr_exclusive, int sync, void *key) +void __wake_up_common(wait_queue_head_t *q, unsigned int mode, + int nr_exclusive, int sync, void *key) { wait_queue_t *curr, *next; @@ -4942,7 +4942,7 @@ * sys_setpriority is a more generic, but much slower function that * does similar things. */ -asmlinkage long sys_nice(int increment) +SYSCALL_DEFINE1(nice, int, increment) { long nice, retval; @@ -5233,8 +5233,8 @@ * @policy: new policy. * @param: structure containing the new RT priority. */ -asmlinkage long -sys_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param) +SYSCALL_DEFINE3(sched_setscheduler, pid_t, pid, int, policy, + struct sched_param __user *, param) { /* negative values for policy are not valid */ if (policy < 0) @@ -5248,7 +5248,7 @@ * @pid: the pid in question. * @param: structure containing the new RT priority. */ -asmlinkage long sys_sched_setparam(pid_t pid, struct sched_param __user *param) +SYSCALL_DEFINE2(sched_setparam, pid_t, pid, struct sched_param __user *, param) { return do_sched_setscheduler(pid, -1, param); } @@ -5257,7 +5257,7 @@ * sys_sched_getscheduler - get the policy (scheduling class) of a thread * @pid: the pid in question. */ -asmlinkage long sys_sched_getscheduler(pid_t pid) +SYSCALL_DEFINE1(sched_getscheduler, pid_t, pid) { struct task_struct *p; int retval; @@ -5282,7 +5282,7 @@ * @pid: the pid in question. * @param: structure containing the RT priority. */ -asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param __user *param) +SYSCALL_DEFINE2(sched_getparam, pid_t, pid, struct sched_param __user *, param) { struct sched_param lp; struct task_struct *p; @@ -5390,8 +5390,8 @@ * @len: length in bytes of the bitmask pointed to by user_mask_ptr * @user_mask_ptr: user-space pointer to the new cpu mask */ -asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len, - unsigned long __user *user_mask_ptr) +SYSCALL_DEFINE3(sched_setaffinity, pid_t, pid, unsigned int, len, + unsigned long __user *, user_mask_ptr) { cpumask_t new_mask; int retval; @@ -5435,8 +5435,8 @@ * @len: length in bytes of the bitmask pointed to by user_mask_ptr * @user_mask_ptr: user-space pointer to hold the current cpu mask */ -asmlinkage long sys_sched_getaffinity(pid_t pid, unsigned int len, - unsigned long __user *user_mask_ptr) +SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len, + unsigned long __user *, user_mask_ptr) { int ret; cpumask_t mask; @@ -5460,7 +5460,7 @@ * This function yields the current CPU to other tasks. If there are no * other threads running on this CPU then this function will return. */ -asmlinkage long sys_sched_yield(void) +SYSCALL_DEFINE0(sched_yield) { struct rq *rq = this_rq_lock(); @@ -5601,7 +5601,7 @@ * this syscall returns the maximum rt_priority that can be used * by a given scheduling class. */ -asmlinkage long sys_sched_get_priority_max(int policy) +SYSCALL_DEFINE1(sched_get_priority_max, int, policy) { int ret = -EINVAL; @@ -5626,7 +5626,7 @@ * this syscall returns the minimum rt_priority that can be used * by a given scheduling class. */ -asmlinkage long sys_sched_get_priority_min(int policy) +SYSCALL_DEFINE1(sched_get_priority_min, int, policy) { int ret = -EINVAL; @@ -5651,8 +5651,8 @@ * this syscall writes the default timeslice value of a given process * into the user-space timespec buffer. A value of '0' means infinity. */ -asmlinkage -long sys_sched_rr_get_interval(pid_t pid, struct timespec __user *interval) +SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid, + struct timespec __user *, interval) { struct task_struct *p; unsigned int time_slice; @@ -6500,7 +6500,9 @@ req = list_entry(rq->migration_queue.next, struct migration_req, list); list_del_init(&req->list); + spin_unlock_irq(&rq->lock); complete(&req->done); + spin_lock_irq(&rq->lock); } spin_unlock_irq(&rq->lock); break; @@ -6802,15 +6804,17 @@ struct sched_domain *tmp; /* Remove the sched domains which do not contribute to scheduling. */ - for (tmp = sd; tmp; tmp = tmp->parent) { + for (tmp = sd; tmp; ) { struct sched_domain *parent = tmp->parent; if (!parent) break; + if (sd_parent_degenerate(tmp, parent)) { tmp->parent = parent->parent; if (parent->parent) parent->parent->child = tmp; - } + } else + tmp = tmp->parent; } if (sd && sd_degenerate(sd)) { @@ -7692,13 +7696,14 @@ * * The passed in 'doms_new' should be kmalloc'd. This routine takes * ownership of it and will kfree it when done with it. If the caller - * failed the kmalloc call, then it can pass in doms_new == NULL, - * and partition_sched_domains() will fallback to the single partition - * 'fallback_doms', it also forces the domains to be rebuilt. - * - * If doms_new==NULL it will be replaced with cpu_online_map. - * ndoms_new==0 is a special case for destroying existing domains. - * It will not create the default domain. + * failed the kmalloc call, then it can pass in doms_new == NULL && + * ndoms_new == 1, and partition_sched_domains() will fallback to + * the single partition 'fallback_doms', it also forces the domains + * to be rebuilt. + * + * If doms_new == NULL it will be replaced with cpu_online_map. + * ndoms_new == 0 is a special case for destroying existing domains, + * and it will not create the default domain. * * Call with hotplug lock held */ --- linux-2.6.27.orig/kernel/auditfilter.c +++ linux-2.6.27/kernel/auditfilter.c @@ -1094,8 +1094,8 @@ list_for_each_entry_safe(p, n, in_list, ilist) { list_del(&p->ilist); inotify_rm_watch(audit_ih, &p->wdata); - /* the put matching the get in audit_do_del_rule() */ - put_inotify_watch(&p->wdata); + /* the unpin matching the pin in audit_do_del_rule() */ + unpin_inotify_watch(&p->wdata); } } @@ -1389,9 +1389,13 @@ /* Put parent on the inotify un-registration * list. Grab a reference before releasing * audit_filter_mutex, to be released in - * audit_inotify_unregister(). */ - list_add(&parent->ilist, &inotify_list); - get_inotify_watch(&parent->wdata); + * audit_inotify_unregister(). + * If filesystem is going away, just leave + * the sucker alone, eviction will take + * care of it. + */ + if (pin_inotify_watch(&parent->wdata)) + list_add(&parent->ilist, &inotify_list); } } } --- linux-2.6.27.orig/kernel/sched_clock.c +++ linux-2.6.27/kernel/sched_clock.c @@ -124,7 +124,7 @@ clock = scd->tick_gtod + delta; min_clock = wrap_max(scd->tick_gtod, scd->clock); - max_clock = scd->tick_gtod + TICK_NSEC; + max_clock = wrap_max(scd->clock, scd->tick_gtod + TICK_NSEC); clock = wrap_max(clock, min_clock); clock = wrap_min(clock, max_clock); @@ -227,6 +227,9 @@ */ void sched_clock_idle_wakeup_event(u64 delta_ns) { + if (timekeeping_suspended) + return; + sched_clock_tick(); touch_softlockup_watchdog(); } --- linux-2.6.27.orig/kernel/uid16.c +++ linux-2.6.27/kernel/uid16.c @@ -17,7 +17,7 @@ #include -asmlinkage long sys_chown16(const char __user * filename, old_uid_t user, old_gid_t group) +SYSCALL_DEFINE3(chown16, const char __user *, filename, old_uid_t, user, old_gid_t, group) { long ret = sys_chown(filename, low2highuid(user), low2highgid(group)); /* avoid REGPARM breakage on x86: */ @@ -25,7 +25,7 @@ return ret; } -asmlinkage long sys_lchown16(const char __user * filename, old_uid_t user, old_gid_t group) +SYSCALL_DEFINE3(lchown16, const char __user *, filename, old_uid_t, user, old_gid_t, group) { long ret = sys_lchown(filename, low2highuid(user), low2highgid(group)); /* avoid REGPARM breakage on x86: */ @@ -33,7 +33,7 @@ return ret; } -asmlinkage long sys_fchown16(unsigned int fd, old_uid_t user, old_gid_t group) +SYSCALL_DEFINE3(fchown16, unsigned int, fd, old_uid_t, user, old_gid_t, group) { long ret = sys_fchown(fd, low2highuid(user), low2highgid(group)); /* avoid REGPARM breakage on x86: */ @@ -41,7 +41,7 @@ return ret; } -asmlinkage long sys_setregid16(old_gid_t rgid, old_gid_t egid) +SYSCALL_DEFINE2(setregid16, old_gid_t, rgid, old_gid_t, egid) { long ret = sys_setregid(low2highgid(rgid), low2highgid(egid)); /* avoid REGPARM breakage on x86: */ @@ -49,7 +49,7 @@ return ret; } -asmlinkage long sys_setgid16(old_gid_t gid) +SYSCALL_DEFINE1(setgid16, old_gid_t, gid) { long ret = sys_setgid(low2highgid(gid)); /* avoid REGPARM breakage on x86: */ @@ -57,7 +57,7 @@ return ret; } -asmlinkage long sys_setreuid16(old_uid_t ruid, old_uid_t euid) +SYSCALL_DEFINE2(setreuid16, old_uid_t, ruid, old_uid_t, euid) { long ret = sys_setreuid(low2highuid(ruid), low2highuid(euid)); /* avoid REGPARM breakage on x86: */ @@ -65,7 +65,7 @@ return ret; } -asmlinkage long sys_setuid16(old_uid_t uid) +SYSCALL_DEFINE1(setuid16, old_uid_t, uid) { long ret = sys_setuid(low2highuid(uid)); /* avoid REGPARM breakage on x86: */ @@ -73,7 +73,7 @@ return ret; } -asmlinkage long sys_setresuid16(old_uid_t ruid, old_uid_t euid, old_uid_t suid) +SYSCALL_DEFINE3(setresuid16, old_uid_t, ruid, old_uid_t, euid, old_uid_t, suid) { long ret = sys_setresuid(low2highuid(ruid), low2highuid(euid), low2highuid(suid)); @@ -82,7 +82,7 @@ return ret; } -asmlinkage long sys_getresuid16(old_uid_t __user *ruid, old_uid_t __user *euid, old_uid_t __user *suid) +SYSCALL_DEFINE3(getresuid16, old_uid_t __user *, ruid, old_uid_t __user *, euid, old_uid_t __user *, suid) { int retval; @@ -93,7 +93,7 @@ return retval; } -asmlinkage long sys_setresgid16(old_gid_t rgid, old_gid_t egid, old_gid_t sgid) +SYSCALL_DEFINE3(setresgid16, old_gid_t, rgid, old_gid_t, egid, old_gid_t, sgid) { long ret = sys_setresgid(low2highgid(rgid), low2highgid(egid), low2highgid(sgid)); @@ -102,7 +102,8 @@ return ret; } -asmlinkage long sys_getresgid16(old_gid_t __user *rgid, old_gid_t __user *egid, old_gid_t __user *sgid) + +SYSCALL_DEFINE3(getresgid16, old_gid_t __user *, rgid, old_gid_t __user *, egid, old_gid_t __user *, sgid) { int retval; @@ -113,7 +114,7 @@ return retval; } -asmlinkage long sys_setfsuid16(old_uid_t uid) +SYSCALL_DEFINE1(setfsuid16, old_uid_t, uid) { long ret = sys_setfsuid(low2highuid(uid)); /* avoid REGPARM breakage on x86: */ @@ -121,7 +122,7 @@ return ret; } -asmlinkage long sys_setfsgid16(old_gid_t gid) +SYSCALL_DEFINE1(setfsgid16, old_gid_t, gid) { long ret = sys_setfsgid(low2highgid(gid)); /* avoid REGPARM breakage on x86: */ @@ -159,7 +160,7 @@ return 0; } -asmlinkage long sys_getgroups16(int gidsetsize, old_gid_t __user *grouplist) +SYSCALL_DEFINE2(getgroups16, int, gidsetsize, old_gid_t __user *, grouplist) { int i = 0; @@ -183,7 +184,7 @@ return i; } -asmlinkage long sys_setgroups16(int gidsetsize, old_gid_t __user *grouplist) +SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist) { struct group_info *group_info; int retval; @@ -208,22 +209,22 @@ return retval; } -asmlinkage long sys_getuid16(void) +SYSCALL_DEFINE0(getuid16) { return high2lowuid(current->uid); } -asmlinkage long sys_geteuid16(void) +SYSCALL_DEFINE0(geteuid16) { return high2lowuid(current->euid); } -asmlinkage long sys_getgid16(void) +SYSCALL_DEFINE0(getgid16) { return high2lowgid(current->gid); } -asmlinkage long sys_getegid16(void) +SYSCALL_DEFINE0(getegid16) { return high2lowgid(current->egid); } --- linux-2.6.27.orig/kernel/capability.c +++ linux-2.6.27/kernel/capability.c @@ -348,7 +348,7 @@ * * Returns 0 on success and < 0 on error. */ -asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr) +SYSCALL_DEFINE2(capget, cap_user_header_t, header, cap_user_data_t, dataptr) { int ret = 0; pid_t pid; @@ -425,7 +425,7 @@ * * Returns 0 on success and < 0 on error. */ -asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) +SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data) { struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S]; unsigned i, tocopy; --- linux-2.6.27.orig/kernel/irq/chip.c +++ linux-2.6.27/kernel/irq/chip.c @@ -78,6 +78,7 @@ desc->chip_data = NULL; desc->handle_irq = handle_bad_irq; desc->chip = &no_irq_chip; + desc->name = NULL; spin_unlock_irqrestore(&desc->lock, flags); } --- linux-2.6.27.orig/kernel/time/timekeeping.c +++ linux-2.6.27/kernel/time/timekeeping.c @@ -46,6 +46,9 @@ struct timespec wall_to_monotonic __attribute__ ((aligned (16))); static unsigned long total_sleep_time; /* seconds */ +/* flag for if timekeeping is suspended */ +int __read_mostly timekeeping_suspended; + static struct timespec xtime_cache __attribute__ ((aligned (16))); void update_xtime_cache(u64 nsec) { @@ -58,27 +61,23 @@ #ifdef CONFIG_GENERIC_TIME /** - * __get_nsec_offset - Returns nanoseconds since last call to periodic_hook + * clocksource_forward_now - update clock to the current time * - * private function, must hold xtime_lock lock when being - * called. Returns the number of nanoseconds since the - * last call to update_wall_time() (adjusted by NTP scaling) + * Forward the current clock to update its state since the last call to + * update_wall_time(). This is useful before significant clock changes, + * as it avoids having to deal with this time offset explicitly. */ -static inline s64 __get_nsec_offset(void) +static void clocksource_forward_now(void) { cycle_t cycle_now, cycle_delta; - s64 ns_offset; + s64 nsec; - /* read clocksource: */ cycle_now = clocksource_read(clock); - - /* calculate the delta since the last update_wall_time: */ cycle_delta = (cycle_now - clock->cycle_last) & clock->mask; + clock->cycle_last = cycle_now; - /* convert to nanoseconds: */ - ns_offset = cyc2ns(clock, cycle_delta); - - return ns_offset; + nsec = cyc2ns(clock, cycle_delta); + timespec_add_ns(&xtime, nsec); } /** @@ -89,14 +88,25 @@ */ void getnstimeofday(struct timespec *ts) { + cycle_t cycle_now, cycle_delta; unsigned long seq; s64 nsecs; + WARN_ON(timekeeping_suspended); + do { seq = read_seqbegin(&xtime_lock); *ts = xtime; - nsecs = __get_nsec_offset(); + + /* read clocksource: */ + cycle_now = clocksource_read(clock); + + /* calculate the delta since the last update_wall_time: */ + cycle_delta = (cycle_now - clock->cycle_last) & clock->mask; + + /* convert to nanoseconds: */ + nsecs = cyc2ns(clock, cycle_delta); } while (read_seqretry(&xtime_lock, seq)); @@ -129,22 +139,22 @@ */ int do_settimeofday(struct timespec *tv) { + struct timespec ts_delta; unsigned long flags; - time_t wtm_sec, sec = tv->tv_sec; - long wtm_nsec, nsec = tv->tv_nsec; if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) return -EINVAL; write_seqlock_irqsave(&xtime_lock, flags); - nsec -= __get_nsec_offset(); + clocksource_forward_now(); - wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); - wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); + ts_delta.tv_sec = tv->tv_sec - xtime.tv_sec; + ts_delta.tv_nsec = tv->tv_nsec - xtime.tv_nsec; + wall_to_monotonic = timespec_sub(wall_to_monotonic, ts_delta); + + xtime = *tv; - set_normalized_timespec(&xtime, sec, nsec); - set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); update_xtime_cache(0); clock->error = 0; @@ -170,22 +180,17 @@ static void change_clocksource(void) { struct clocksource *new; - cycle_t now; - u64 nsec; new = clocksource_get_next(); if (clock == new) return; - new->cycle_last = 0; - now = clocksource_read(new); - nsec = __get_nsec_offset(); - timespec_add_ns(&xtime, nsec); + clocksource_forward_now(); clock = new; - clock->cycle_last = now; - + clock->cycle_last = 0; + clock->cycle_last = clocksource_read(new); clock->error = 0; clock->xtime_nsec = 0; clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH); @@ -200,8 +205,8 @@ */ } #else +static inline void clocksource_forward_now(void) { } static inline void change_clocksource(void) { } -static inline s64 __get_nsec_offset(void) { return 0; } #endif /** @@ -261,12 +266,8 @@ write_sequnlock_irqrestore(&xtime_lock, flags); } -/* flag for if timekeeping is suspended */ -static int timekeeping_suspended; /* time in seconds when suspend began */ static unsigned long timekeeping_suspend_time; -/* xtime offset when we went into suspend */ -static s64 timekeeping_suspend_nsecs; /** * timekeeping_resume - Resumes the generic timekeeping subsystem. @@ -292,8 +293,6 @@ wall_to_monotonic.tv_sec -= sleep_length; total_sleep_time += sleep_length; } - /* Make sure that we have the correct xtime reference */ - timespec_add_ns(&xtime, timekeeping_suspend_nsecs); update_xtime_cache(0); /* re-base the last cycle value */ clock->cycle_last = 0; @@ -319,8 +318,7 @@ timekeeping_suspend_time = read_persistent_clock(); write_seqlock_irqsave(&xtime_lock, flags); - /* Get the current xtime offset */ - timekeeping_suspend_nsecs = __get_nsec_offset(); + clocksource_forward_now(); timekeeping_suspended = 1; write_sequnlock_irqrestore(&xtime_lock, flags); @@ -461,10 +459,10 @@ */ while (offset >= clock->cycle_interval) { /* accumulate one interval */ - clock->xtime_nsec += clock->xtime_interval; - clock->cycle_last += clock->cycle_interval; offset -= clock->cycle_interval; + clock->cycle_last += clock->cycle_interval; + clock->xtime_nsec += clock->xtime_interval; if (clock->xtime_nsec >= (u64)NSEC_PER_SEC << clock->shift) { clock->xtime_nsec -= (u64)NSEC_PER_SEC << clock->shift; xtime.tv_sec++; --- linux-2.6.27.orig/kernel/trace/Kconfig +++ linux-2.6.27/kernel/trace/Kconfig @@ -103,7 +103,8 @@ all switching of tasks. config DYNAMIC_FTRACE - bool "enable/disable ftrace tracepoints dynamically" + bool "enable/disable ftrace tracepoints dynamically (BROKEN)" + depends on BROKEN depends on FTRACE depends on HAVE_DYNAMIC_FTRACE default y --- linux-2.6.27.orig/kernel/power/Kconfig +++ linux-2.6.27/kernel/power/Kconfig @@ -116,6 +116,21 @@ Turning OFF this setting is NOT recommended! If in doubt, say Y. +config PM_DISABLE_CONSOLE + bool "Disable Power Management messing with the active console" + depends on PM + default n + ---help--- + By default, PM will take over the active console (generally, this means + switching to the console when suspending from X). This can at times cause + problems, especially if userspace suspend scripts try to do things with + the console before or after suspending (e.g. calling vbestate). + + To work around this, enable this option so that PM will not handle the + console. + + If unsure, say N. + config HIBERNATION bool "Hibernation (aka 'suspend to disk')" depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE --- linux-2.6.27.orig/kernel/power/console.c +++ linux-2.6.27/kernel/power/console.c @@ -33,6 +33,7 @@ int pm_prepare_console(void) { +#ifndef CONFIG_PM_DISABLE_CONSOLE acquire_console_sem(); if (disable_vt_switch) { @@ -66,11 +67,13 @@ } orig_kmsg = kmsg_redirect; kmsg_redirect = SUSPEND_CONSOLE; +#endif return 0; } void pm_restore_console(void) { +#ifndef CONFIG_PM_DISABLE_CONSOLE acquire_console_sem(); if (disable_vt_switch) { release_console_sem(); @@ -79,5 +82,6 @@ set_console(orig_fgconsole); release_console_sem(); kmsg_redirect = orig_kmsg; +#endif } #endif --- linux-2.6.27.orig/ubuntu/Kconfig +++ linux-2.6.27/ubuntu/Kconfig @@ -0,0 +1,25 @@ +menu "Ubuntu Supplied Third-Party Device Drivers" + +source "ubuntu/drbd/Kconfig" +source "ubuntu/iscsitarget/Kconfig" +source "ubuntu/squashfs/Kconfig" +source "ubuntu/aufs/Kconfig" +source "ubuntu/atl2/Kconfig" +source "ubuntu/et131x/Kconfig" +source "ubuntu/dm-raid4-5/Kconfig" +source "ubuntu/dm-loop/Kconfig" +source "ubuntu/ndiswrapper/Kconfig" +source "ubuntu/compcache/Kconfig" +source "ubuntu/misc/Kconfig" +source "ubuntu/heci/Kconfig" +source "ubuntu/qc-usb/Kconfig" +source "ubuntu/e1000e/Kconfig" +source "ubuntu/rfkill/Kconfig" +source "ubuntu/via_chrome9/Kconfig" +source "ubuntu/unionfs/Kconfig" +source "ubuntu/lirc/Kconfig" +source "ubuntu/gnbd/Kconfig" +source "ubuntu/gfs/Kconfig" +source "ubuntu/tlsup/Kconfig" + +endmenu --- linux-2.6.27.orig/ubuntu/Makefile +++ linux-2.6.27/ubuntu/Makefile @@ -0,0 +1,28 @@ +# +# Makefile for the Linux kernel ubuntu supplied third-party device drivers. +# + +obj-$(CONFIG_BLK_DEV_DRBD) += drbd/ +obj-$(CONFIG_SCSI_ISCSITARGET) += iscsitarget/ +obj-$(CONFIG_SQUASHFS) += squashfs/ +obj-$(CONFIG_AUFS) += aufs/ +obj-$(CONFIG_ATL2) += atl2/ +obj-$(CONFIG_NET_ET131X) += et131x/ +obj-$(CONFIG_DM_RAID45) += dm-raid4-5/ +obj-$(CONFIG_DM_LOOP) += dm-loop/ +obj-$(CONFIG_NDISWRAPPER) += ndiswrapper/ +obj-$(CONFIG_TLSF) += compcache/ +obj-$(CONFIG_HECI) += heci/ +obj-$(CONFIG_QC_USB) += qc-usb/ +obj-$(CONFIG_E1000E_NEW) += e1000e/ +obj-$(CONFIG_DRM_VIA_CHROME9) += via_chrome9/ +obj-$(CONFIG_FS_UNIONFS) += unionfs/ +obj-$(CONFIG_LIRC_DEV) += lirc/ +obj-$(CONFIG_GNBD) += gnbd/ +obj-$(CONFIG_GFS_FS) += gfs/ +obj-$(CONFIG_TLSUP) += tlsup/ + +obj-m += misc/ rfkill/ + +# This is a stupid trick to get kbuild to create ubuntu/built-in.o +obj- += foo.o --- linux-2.6.27.orig/ubuntu/via_chrome9/via_chrome9_3d_reg.h +++ linux-2.6.27/ubuntu/via_chrome9/via_chrome9_3d_reg.h @@ -0,0 +1,398 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * (including the next paragraph) shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VIA_CHROME9_3D_REG_H +#define VIA_CHROME9_3D_REG_H + +#include + +#define GetMMIORegister(base, offset) \ + (*(volatile unsigned int *)(void *)(((unsigned char *)(base)) + \ + (offset))) +#define SetMMIORegister(base, offset, val) \ + (*(volatile unsigned int *)(void *)(((unsigned char *)(base)) + \ + (offset)) = (val)) + +#define GetMMIORegisterU8(base, offset) \ + (*(volatile unsigned char *)(void *)(((unsigned char *)(base)) + \ + (offset))) +#define SetMMIORegisterU8(base, offset, val) \ + (*(volatile unsigned char *)(void *)(((unsigned char *)(base)) + \ + (offset)) = (val)) + +#define BCI_SEND(bci, value) (*(bci)++ = (unsigned long)(value)) +#define BCI_SET_STREAM_REGISTER(bci_base, bci_index, reg_value) \ +do { \ + unsigned long cmd; \ + \ + cmd = (0x90000000 \ + | (1<<16) /* stream processor register */ \ + | (bci_index & 0x3FFC)); /* MMIO register address */ \ + BCI_SEND(bci_base, cmd); \ + BCI_SEND(bci_base, reg_value); \ + } while (0) + +/* Command Header Type */ + +#define INV_AGPHeader0 0xFE000000 +#define INV_AGPHeader1 0xFE010000 +#define INV_AGPHeader2 0xFE020000 +#define INV_AGPHeader3 0xFE030000 +#define INV_AGPHeader4 0xFE040000 +#define INV_AGPHeader5 0xFE050000 +#define INV_AGPHeader6 0xFE060000 +#define INV_AGPHeader7 0xFE070000 +#define INV_AGPHeader82 0xFE820000 +#define INV_AGPHeader_MASK 0xFFFF0000 + +/*send pause address of AGP ring command buffer via_chrome9 this IO port*/ +#define INV_REG_PCIPAUSE 0x294 +#define INV_REG_PCIPAUSE_ENABLE 0x4 + +#define INV_CMDBUF_THRESHOLD (8) +#define INV_QW_PAUSE_ALIGN 0x40 + +/* Transmission IO Space*/ +#define INV_REG_CR_TRANS 0x041C +#define INV_REG_CR_BEGIN 0x0420 +#define INV_REG_CR_END 0x0438 + +#define INV_REG_3D_TRANS 0x043C +#define INV_REG_3D_BEGIN 0x0440 +#define INV_REG_3D_END 0x06FC +#define INV_REG_23D_WAIT 0x326C +/*3D / 2D ID Control (Only For Group A)*/ +#define INV_REG_2D3D_ID_CTRL 0x060 + + +/* Engine Status */ + +#define INV_RB_ENG_STATUS 0x0400 +#define INV_ENG_BUSY_HQV0 0x00040000 +#define INV_ENG_BUSY_HQV1 0x00020000 +#define INV_ENG_BUSY_CR 0x00000010 +#define INV_ENG_BUSY_MPEG 0x00000008 +#define INV_ENG_BUSY_VQ 0x00000004 +#define INV_ENG_BUSY_2D 0x00000002 +#define INV_ENG_BUSY_3D 0x00001FE1 +#define INV_ENG_BUSY_ALL \ + (INV_ENG_BUSY_2D | INV_ENG_BUSY_3D | INV_ENG_BUSY_CR) + +/* Command Queue Status*/ +#define INV_RB_VQ_STATUS 0x0448 +#define INV_VQ_FULL 0x40000000 + +/* AGP command buffer pointer current position*/ +#define INV_RB_AGPCMD_CURRADDR 0x043C + +/* AGP command buffer status*/ +#define INV_RB_AGPCMD_STATUS 0x0444 +#define INV_AGPCMD_InPause 0x80000000 + +/*AGP command buffer pause address*/ +#define INV_RB_AGPCMD_PAUSEADDR 0x045C + +/*AGP command buffer jump address*/ +#define INV_RB_AGPCMD_JUMPADDR 0x0460 + +/*AGP command buffer start address*/ +#define INV_RB_AGPCMD_STARTADDR 0x0464 + + +/* Constants */ +#define NUMBER_OF_EVENT_TAGS 1024 +#define NUMBER_OF_APERTURES_CLB 16 + +/* Register definition */ +#define HW_SHADOW_ADDR 0x8520 +#define HW_GARTTABLE_ADDR 0x8540 + +#define INV_HSWFlag_DBGMASK 0x00000FFF +#define INV_HSWFlag_ENCODEMASK 0x007FFFF0 +#define INV_HSWFlag_ADDRSHFT 8 +#define INV_HSWFlag_DECODEMASK \ + (INV_HSWFlag_ENCODEMASK << INV_HSWFlag_ADDRSHFT) +#define INV_HSWFlag_ADDR_ENCODE(x) 0xCC000000 +#define INV_HSWFlag_ADDR_DECODE(x) \ + (((unsigned int)x & INV_HSWFlag_DECODEMASK) >> INV_HSWFlag_ADDRSHFT) + + +#define INV_SubA_HAGPBstL 0x60000000 +#define INV_SubA_HAGPBstH 0x61000000 +#define INV_SubA_HAGPBendL 0x62000000 +#define INV_SubA_HAGPBendH 0x63000000 +#define INV_SubA_HAGPBpL 0x64000000 +#define INV_SubA_HAGPBpID 0x65000000 +#define INV_HAGPBpID_PAUSE 0x00000000 +#define INV_HAGPBpID_JUMP 0x00000100 +#define INV_HAGPBpID_STOP 0x00000200 + +#define INV_HAGPBpH_MASK 0x000000FF +#define INV_HAGPBpH_SHFT 0 + +#define INV_SubA_HAGPBjumpL 0x66000000 +#define INV_SubA_HAGPBjumpH 0x67000000 +#define INV_HAGPBjumpH_MASK 0x000000FF +#define INV_HAGPBjumpH_SHFT 0 + +#define INV_SubA_HFthRCM 0x68000000 +#define INV_HFthRCM_MASK 0x003F0000 +#define INV_HFthRCM_SHFT 16 +#define INV_HFthRCM_8 0x00080000 +#define INV_HFthRCM_10 0x000A0000 +#define INV_HFthRCM_18 0x00120000 +#define INV_HFthRCM_24 0x00180000 +#define INV_HFthRCM_32 0x00200000 + +#define INV_HAGPBClear 0x00000008 + +#define INV_HRSTTrig_RestoreAGP 0x00000004 +#define INV_HRSTTrig_RestoreAll 0x00000002 +#define INV_HAGPBTrig 0x00000001 + +#define INV_ParaSubType_MASK 0xff000000 +#define INV_ParaType_MASK 0x00ff0000 +#define INV_ParaOS_MASK 0x0000ff00 +#define INV_ParaAdr_MASK 0x000000ff +#define INV_ParaSubType_SHIFT 24 +#define INV_ParaType_SHIFT 16 +#define INV_ParaOS_SHIFT 8 +#define INV_ParaAdr_SHIFT 0 + +#define INV_ParaType_Vdata 0x00000000 +#define INV_ParaType_Attr 0x00010000 +#define INV_ParaType_Tex 0x00020000 +#define INV_ParaType_Pal 0x00030000 +#define INV_ParaType_FVF 0x00040000 +#define INV_ParaType_PreCR 0x00100000 +#define INV_ParaType_CR 0x00110000 +#define INV_ParaType_Cfg 0x00fe0000 +#define INV_ParaType_Dummy 0x00300000 + +#define INV_HWBasL_MASK 0x00FFFFFF +#define INV_HWBasH_MASK 0xFF000000 +#define INV_HWBasH_SHFT 24 +#define INV_HWBasL(x) ((unsigned int)(x) & INV_HWBasL_MASK) +#define INV_HWBasH(x) ((unsigned int)(x) >> INV_HWBasH_SHFT) +#define INV_HWBas256(x) ((unsigned int)(x) >> 8) +#define INV_HWPit32(x) ((unsigned int)(x) >> 5) + +/* Read Back Register Setting */ +#define INV_SubA_HSetRBGID 0x02000000 +#define INV_HSetRBGID_CR 0x00000000 +#define INV_HSetRBGID_FE 0x00000001 +#define INV_HSetRBGID_PE 0x00000002 +#define INV_HSetRBGID_RC 0x00000003 +#define INV_HSetRBGID_PS 0x00000004 +#define INV_HSetRBGID_XE 0x00000005 +#define INV_HSetRBGID_BE 0x00000006 + + +struct drm_clb_event_tag_info { + unsigned int *linear_address; + unsigned int *event_tag_linear_address; + int usage[NUMBER_OF_EVENT_TAGS]; + unsigned int pid[NUMBER_OF_EVENT_TAGS]; +}; + +static inline int IS_AGPHEADER_INV(unsigned int data) +{ + switch (data & INV_AGPHeader_MASK) { + case INV_AGPHeader0: + case INV_AGPHeader1: + case INV_AGPHeader2: + case INV_AGPHeader3: + case INV_AGPHeader4: + case INV_AGPHeader5: + case INV_AGPHeader6: + case INV_AGPHeader7: + return TRUE; + default: + return FALSE; + } +} + +/* Header0: 2D */ +#define ADDCmdHeader0_INVI(pCmd, dwCount) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader0; \ + *(pCmd)++ = (dwCount); \ + *(pCmd)++ = 0; \ + *(pCmd)++ = (unsigned int)INV_HSWFlag_ADDR_ENCODE(pCmd); \ +} + +/* Header1: 2D */ +#define ADDCmdHeader1_INVI(pCmd, dwAddr, dwCount) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader1 | (dwAddr); \ + *(pCmd)++ = (dwCount); \ + *(pCmd)++ = 0; \ + *(pCmd)++ = (unsigned int)INV_HSWFlag_ADDR_ENCODE(pCmd); \ +} + +/* Header2: CR/3D */ +#define ADDCmdHeader2_INVI(pCmd, dwAddr, dwType) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader2 | ((dwAddr)+4); \ + *(pCmd)++ = (dwAddr); \ + *(pCmd)++ = (dwType); \ + *(pCmd)++ = (unsigned int)INV_HSWFlag_ADDR_ENCODE(pCmd); \ +} + +/* Header2: CR/3D with SW Flag */ +#define ADDCmdHeader2_SWFlag_INVI(pCmd, dwAddr, dwType, dwSWFlag) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader2 | ((dwAddr)+4); \ + *(pCmd)++ = (dwAddr); \ + *(pCmd)++ = (dwType); \ + *(pCmd)++ = (dwSWFlag); \ +} + + +/* Header3: 3D */ +#define ADDCmdHeader3_INVI(pCmd, dwType, dwStart, dwCount) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader3 | INV_REG_3D_TRANS; \ + *(pCmd)++ = (dwCount); \ + *(pCmd)++ = (dwType) | ((dwStart) & 0xFFFF); \ + *(pCmd)++ = (unsigned int)INV_HSWFlag_ADDR_ENCODE(pCmd); \ +} + +/* Header3: 3D with SW Flag */ +#define ADDCmdHeader3_SWFlag_INVI(pCmd, dwType, dwStart, dwSWFlag, dwCount) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader3 | INV_REG_3D_TRANS; \ + *(pCmd)++ = (dwCount); \ + *(pCmd)++ = (dwType) | ((dwStart) & 0xFFFF); \ + *(pCmd)++ = (dwSWFlag); \ +} + +/* Header4: DVD */ +#define ADDCmdHeader4_INVI(pCmd, dwAddr, dwCount, id) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader4 | (dwAddr); \ + *(pCmd)++ = (dwCount); \ + *(pCmd)++ = (id); \ + *(pCmd)++ = 0; \ +} + +/* Header5: DVD */ +#define ADDCmdHeader5_INVI(pCmd, dwQWcount, id) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader5; \ + *(pCmd)++ = (dwQWcount); \ + *(pCmd)++ = (id); \ + *(pCmd)++ = 0; \ +} + +/* Header6: DEBUG */ +#define ADDCmdHeader6_INVI(pCmd) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader6; \ + *(pCmd)++ = 0; \ + *(pCmd)++ = 0; \ + *(pCmd)++ = 0; \ +} + +/* Header7: DMA */ +#define ADDCmdHeader7_INVI(pCmd, dwQWcount, id) \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader7; \ + *(pCmd)++ = (dwQWcount); \ + *(pCmd)++ = (id); \ + *(pCmd)++ = 0; \ +} + +/* Header82: Branch buffer */ +#define ADDCmdHeader82_INVI(pCmd, dwAddr, dwType); \ +{ \ + /* 4 unsigned int align, insert NULL Command for padding */ \ + while (((unsigned long *)(pCmd)) & 0xF) { \ + *(pCmd)++ = 0xCC000000; \ + } \ + *(pCmd)++ = INV_AGPHeader82 | ((dwAddr)+4); \ + *(pCmd)++ = (dwAddr); \ + *(pCmd)++ = (dwType); \ + *(pCmd)++ = 0xCC000000; \ +} + + +#define ADD2DCmd_INVI(pCmd, dwAddr, dwCmd) \ +{ \ + *(pCmd)++ = (dwAddr); \ + *(pCmd)++ = (dwCmd); \ +} + +#define ADDCmdData_INVI(pCmd, dwCmd) *(pCmd)++ = (dwCmd) + +#define ADDCmdDataStream_INVI(pCmdBuf, pCmd, dwCount) \ +{ \ + memcpy((pCmdBuf), (pCmd), ((dwCount)<<2)); \ + (pCmdBuf) += (dwCount); \ +} + +#endif --- linux-2.6.27.orig/ubuntu/via_chrome9/via_chrome9_drm.h +++ linux-2.6.27/ubuntu/via_chrome9/via_chrome9_drm.h @@ -0,0 +1,423 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * (including the next paragraph) shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _VIA_CHROME9_DRM_H_ +#define _VIA_CHROME9_DRM_H_ + +/* WARNING: These defines must be the same as what the Xserver uses. + * if you change them, you must change the defines in the Xserver. + */ + +#ifndef _VIA_CHROME9_DEFINES_ +#define _VIA_CHROME9_DEFINES_ + +#ifndef __KERNEL__ +#include "via_drmclient.h" +#endif + +#define VIA_CHROME9_NR_SAREA_CLIPRECTS 8 +#define VIA_CHROME9_NR_XVMC_PORTS 10 +#define VIA_CHROME9_NR_XVMC_LOCKS 5 +#define VIA_CHROME9_MAX_CACHELINE_SIZE 64 +#define XVMCLOCKPTR(saPriv,lockNo) \ + ((volatile struct drm_hw_lock *) \ + (((((unsigned long) (saPriv)->XvMCLockArea) + \ + (VIA_CHROME9_MAX_CACHELINE_SIZE - 1)) & \ + ~(VIA_CHROME9_MAX_CACHELINE_SIZE - 1)) + \ + VIA_CHROME9_MAX_CACHELINE_SIZE*(lockNo))) + +/* Each region is a minimum of 64k, and there are at most 64 of them. + */ +#define VIA_CHROME9_NR_TEX_REGIONS 64 +#define VIA_CHROME9_LOG_MIN_TEX_REGION_SIZE 16 +#endif + +#define VIA_CHROME9_UPLOAD_TEX0IMAGE 0x1 /* handled clientside */ +#define VIA_CHROME9_UPLOAD_TEX1IMAGE 0x2 /* handled clientside */ +#define VIA_CHROME9_UPLOAD_CTX 0x4 +#define VIA_CHROME9_UPLOAD_BUFFERS 0x8 +#define VIA_CHROME9_UPLOAD_TEX0 0x10 +#define VIA_CHROME9_UPLOAD_TEX1 0x20 +#define VIA_CHROME9_UPLOAD_CLIPRECTS 0x40 +#define VIA_CHROME9_UPLOAD_ALL 0xff + +/* VIA_CHROME9 specific ioctls */ +#define DRM_VIA_CHROME9_ALLOCMEM 0x00 +#define DRM_VIA_CHROME9_FREEMEM 0x01 +#define DRM_VIA_CHROME9_FREE 0x02 +#define DRM_VIA_CHROME9_ALLOCATE_EVENT_TAG 0x03 +#define DRM_VIA_CHROME9_FREE_EVENT_TAG 0x04 +#define DRM_VIA_CHROME9_ALLOCATE_APERTURE 0x05 +#define DRM_VIA_CHROME9_FREE_APERTURE 0x06 +#define DRM_VIA_CHROME9_ALLOCATE_VIDEO_MEM 0x07 +#define DRM_VIA_CHROME9_FREE_VIDEO_MEM 0x08 +#define DRM_VIA_CHROME9_WAIT_CHIP_IDLE 0x09 +#define DRM_VIA_CHROME9_PROCESS_EXIT 0x0A +#define DRM_VIA_CHROME9_RESTORE_PRIMARY 0x0B +#define DRM_VIA_CHROME9_FLUSH_CACHE 0x0C +#define DRM_VIA_CHROME9_INIT 0x0D +#define DRM_VIA_CHROME9_FLUSH 0x0E +#define DRM_VIA_CHROME9_CHECKVIDMEMSIZE 0x0F +#define DRM_VIA_CHROME9_PCIEMEMCTRL 0x10 +#define DRM_VIA_CHROME9_AUTH_MAGIC 0x11 + +#define DRM_IOCTL_VIA_CHROME9_INIT \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_INIT, \ + struct drm_via_chrome9_init) +#define DRM_IOCTL_VIA_CHROME9_FLUSH \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FLUSH, \ + struct drm_via_chrome9_flush) +#define DRM_IOCTL_VIA_CHROME9_FREE \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FREE, int) +#define DRM_IOCTL_VIA_CHROME9_ALLOCATE_EVENT_TAG \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_ALLOCATE_EVENT_TAG, \ + struct drm_event_via_chrome9_tag) +#define DRM_IOCTL_VIA_CHROME9_FREE_EVENT_TAG \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FREE_EVENT_TAG, \ + struct drm_event_via_chrome9_tag) +#define DRM_IOCTL_VIA_CHROME9_ALLOCATE_APERTURE \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_ALLOCATE_APERTURE, \ + struct drm_via_chrome9_aperture) +#define DRM_IOCTL_VIA_CHROME9_FREE_APERTURE \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FREE_APERTURE, \ + struct drm_via_chrome9_aperture) +#define DRM_IOCTL_VIA_CHROME9_ALLOCATE_VIDEO_MEM \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_ALLOCATE_VIDEO_MEM, \ + struct drm_via_chrome9_memory_alloc) +#define DRM_IOCTL_VIA_CHROME9_FREE_VIDEO_MEM \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FREE_VIDEO_MEM, \ + struct drm_via_chrome9_memory_alloc) +#define DRM_IOCTL_VIA_CHROME9_WAIT_CHIP_IDLE \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_WAIT_CHIP_IDLE, int) +#define DRM_IOCTL_VIA_CHROME9_PROCESS_EXIT \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_PROCESS_EXIT, int) +#define DRM_IOCTL_VIA_CHROME9_RESTORE_PRIMARY \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_RESTORE_PRIMARY, int) +#define DRM_IOCTL_VIA_CHROME9_FLUSH_CACHE \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FLUSH_CACHE, int) +#define DRM_IOCTL_VIA_CHROME9_ALLOCMEM \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_ALLOCMEM, int) +#define DRM_IOCTL_VIA_CHROME9_FREEMEM \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FREEMEM, int) +#define DRM_IOCTL_VIA_CHROME9_CHECK_VIDMEM_SIZE \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_CHECKVIDMEMSIZE, \ + struct drm_via_chrome9_memory_alloc) +#define DRM_IOCTL_VIA_CHROME9_PCIEMEMCTRL \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_PCIEMEMCTRL,\ + drm_via_chrome9_pciemem_ctrl_t) +#define DRM_IOCTL_VIA_CHROME9_AUTH_MAGIC \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_AUTH_MAGIC, drm_auth_t) + +enum S3GCHIPIDS { + CHIP_UNKNOWN = -1, + CHIP_CMODEL, /*Model for any chip. */ + CHIP_CLB, /*Columbia */ + CHIP_DST, /*Destination */ + CHIP_CSR, /*Castlerock */ + CHIP_INV, /*Innovation (H3) */ + CHIP_H5, /*Innovation (H5) */ + CHIP_H5S1, /*Innovation (H5S1) */ + CHIP_H6S2, /*Innovation (H6S2) */ + CHIP_CMS, /*Columbia MS */ + CHIP_METRO, /*Metropolis */ + CHIP_MANHATTAN, /*manhattan */ + CHIP_MATRIX, /*matrix */ + CHIP_EVO, /*change for GCC 4.1 -add- 07.02.12*/ + CHIP_H6S1, /*Innovation (H6S1)*/ + CHIP_DST2, /*Destination-2 */ + CHIP_LAST /*Maximum number of chips supported. */ +}; + +enum VIA_CHROME9CHIPBUS { + CHIP_PCI, + CHIP_AGP, + CHIP_PCIE +}; + +struct drm_via_chrome9_init { + enum { + VIA_CHROME9_INIT = 0x01, + VIA_CHROME9_CLEANUP = 0x02 + } func; + int chip_agp; + int chip_index; + int chip_sub_index; + int usec_timeout; + unsigned int sarea_priv_offset; + unsigned int fb_cpp; + unsigned int front_offset; + unsigned int back_offset; + unsigned int depth_offset; + unsigned int mmio_handle; + unsigned int dma_handle; + unsigned int fb_handle; + unsigned int front_handle; + unsigned int back_handle; + unsigned int depth_handle; + + unsigned int fb_tex_offset; + unsigned int fb_tex_size; + + unsigned int agp_tex_size; + unsigned int agp_tex_handle; + unsigned int shadow_size; + unsigned int shadow_handle; + unsigned int garttable_size; + unsigned int garttable_offset; + unsigned long available_fb_size; + unsigned long fb_base_address; + unsigned int DMA_size; + unsigned long DMA_phys_address; + enum { + AGP_RING_BUFFER, + AGP_DOUBLE_BUFFER, + AGP_DISABLED + } agp_type; + unsigned int hostBlt_handle; +}; + +enum dma_cmd_type { + flush_bci = 0, + flush_bci_and_wait, + dma_kickoff, + flush_dma_buffer, + flush_dma_and_wait +}; + +struct drm_via_chrome9_flush { + enum dma_cmd_type dma_cmd_type; + /* command buffer index */ + int cmd_idx; + /* command buffer offset */ + int cmd_offset; + /* command dword size,command always from beginning */ + int cmd_size; + /* if use dma kick off,it is dma kick off command */ + unsigned long dma_kickoff[2]; + /* user mode DMA buffer pointer */ + unsigned int *usermode_dma_buf; +}; + +struct event_value { + int event_low; + int event_high; +}; + +struct drm_via_chrome9_event_tag { + unsigned int event_size; /* event tag size */ + int event_offset; /* event tag id */ + struct event_value last_sent_event_value; + struct event_value current_event_value; + int query_mask0; + int query_mask1; + int query_Id1; +}; + +/* Indices into buf.Setup where various bits of state are mirrored per + * context and per buffer. These can be fired at the card as a unit, + * or in a piecewise fashion as required. + */ + +#define VIA_CHROME9_TEX_SETUP_SIZE 8 + +/* Flags for clear ioctl + */ +#define VIA_CHROME9_FRONT 0x1 +#define VIA_CHROME9_BACK 0x2 +#define VIA_CHROME9_DEPTH 0x4 +#define VIA_CHROME9_STENCIL 0x8 +#define VIA_CHROME9_MEM_VIDEO 0 /* matches drm constant */ +#define VIA_CHROME9_MEM_AGP 1 /* matches drm constant */ +#define VIA_CHROME9_MEM_SYSTEM 2 +#define VIA_CHROME9_MEM_MIXED 3 +#define VIA_CHROME9_MEM_UNKNOWN 4 + +struct drm_via_chrome9_agp { + uint32_t offset; + uint32_t size; +}; + +struct drm_via_chrome9_fb { + uint32_t offset; + uint32_t size; +}; + +struct drm_via_chrome9_mem { + uint32_t context; + uint32_t type; + uint32_t size; + unsigned long index; + unsigned long offset; +}; + +struct drm_via_chrome9_aperture { + /*IN: The frame buffer offset of the surface. */ + int surface_offset; + /*IN: Surface pitch in byte, */ + int pitch; + /*IN: Surface width in pixel */ + int width; + /*IN: Surface height in pixel */ + int height; + /*IN: Surface color format, Columbia has more color formats */ + int color_format; + /*IN: Rotation degrees, only for Columbia */ + int rotation_degree; + /*IN Is the PCIE Video, for MATRIX support NONLOCAL Aperture */ + int isPCIEVIDEO; + /*IN: Is the surface tilled, only for Columbia */ + int is_tiled; + /*IN: Only allocate apertur, not hardware setup. */ + int allocate_only; + /* OUT: linear address for aperture */ + unsigned int *aperture_linear_address; + /*OUT: The pitch of the aperture,for CPU write not for GE */ + int aperture_pitch; + /*OUT: The index of the aperture */ + int aperture_handle; + int apertureID; + /* always =0xAAAAAAAA */ + /* Aligned surface's width(in pixel) */ + int width_aligned; + /* Aligned surface's height(in pixel) */ + int height_aligned; +}; + +/* + Some fileds of this data structure has no meaning now since + we have managed heap based on mechanism provided by DRM + Remain what it was to keep consistent with 3D driver interface. +*/ +struct drm_via_chrome9_memory_alloc { + enum { + memory_heap_video = 0, + memory_heap_agp, + memory_heap_pcie_video, + memory_heap_pcie, + max_memory_heaps + } heap_type; + struct { + void *lpL1Node; + unsigned int alcL1Tag; + unsigned int usageCount; + unsigned int dwVersion; + unsigned int dwResHandle; + unsigned int dwProcessID; + } heap_info; + unsigned int flags; + unsigned int size; + unsigned int physaddress; + unsigned int offset; + unsigned int align; + void *linearaddress; +}; + +struct drm_via_chrome9_dma_init { + enum { + VIA_CHROME9_INIT_DMA = 0x01, + VIA_CHROME9_CLEANUP_DMA = 0x02, + VIA_CHROME9_DMA_INITIALIZED = 0x03 + } func; + + unsigned long offset; + unsigned long size; + unsigned long reg_pause_addr; +}; + +struct drm_via_chrome9_cmdbuffer { + char __user *buf; + unsigned long size; +}; + +/* Warning: If you change the SAREA structure you must change the Xserver + * structure as well */ + +struct drm_via_chrome9_tex_region { + unsigned char next, prev; /* indices to form a circular LRU */ + unsigned char inUse; /* owned by a client, or free? */ + int age; /* tracked by clients to update local LRU's */ +}; + +struct drm_via_chrome9_sarea { + int page_flip; + int current_page; + unsigned int req_drawable;/* the X drawable id */ + unsigned int req_draw_buffer;/* VIA_CHROME9_FRONT or VIA_CHROME9_BACK */ + /* Last context that uploaded state */ + int ctx_owner; +}; + +struct drm_via_chrome9_cmdbuf_size { + enum { + VIA_CHROME9_CMDBUF_SPACE = 0x01, + VIA_CHROME9_CMDBUF_LAG = 0x02 + } func; + int wait; + uint32_t size; +}; + +struct drm_via_chrome9_DMA_manager { + unsigned int *addr_linear; + unsigned int DMASize; + unsigned int bDMAAgp; + unsigned int LastIssuedEventTag; + unsigned int *pBeg; + unsigned int *pInUseByHW; + unsigned int **ppInUseByHW; + unsigned int *pInUseBySW; + unsigned int *pFree; + unsigned int *pEnd; + + unsigned long pPhysical; + unsigned int MaxKickoffSize; +}; + +extern int via_chrome9_ioctl_wait_chip_idle(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_init(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_allocate_event_tag(struct drm_device + *dev, void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_free_event_tag(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int via_chrome9_driver_load(struct drm_device *dev, + unsigned long chipset); +extern int via_chrome9_driver_unload(struct drm_device *dev); +extern int via_chrome9_ioctl_process_exit(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_restore_primary(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int via_chrome9_drm_resume(struct pci_dev *dev); +extern int via_chrome9_drm_suspend(struct pci_dev *dev, + pm_message_t state); +extern void __via_chrome9ke_udelay(unsigned long usecs); +extern void via_chrome9_lastclose(struct drm_device *dev); +extern void via_chrome9_preclose(struct drm_device *dev, + struct drm_file *file_priv); +extern int via_chrome9_is_agp(struct drm_device *dev); + + +#endif /* _VIA_CHROME9_DRM_H_ */ --- linux-2.6.27.orig/ubuntu/via_chrome9/via_chrome9_drv.h +++ linux-2.6.27/ubuntu/via_chrome9/via_chrome9_drv.h @@ -0,0 +1,145 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * (including the next paragraph) shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _VIA_CHROME9_DRV_H_ +#define _VIA_CHROME9_DRV_H_ + +#include +#define DRIVER_AUTHOR "Various" + +#define DRIVER_NAME "via_chrome9_chrome9" +#define DRIVER_DESC "VIA_CHROME9 Unichrome / Pro" +#define DRIVER_DATE "20080415" + +#define DRIVER_MAJOR 2 +#define DRIVER_MINOR 11 +#define DRIVER_PATCHLEVEL 1 + +#define via_chrome9_PCI_BUF_SIZE 60000 +#define via_chrome9_FIRE_BUF_SIZE 1024 +#define via_chrome9_NUM_IRQS 4 + +#define MAX_MEMORY_HEAPS 4 +#define NUMBER_OF_APERTURES 32 + +/*typedef struct drm_via_chrome9_shadow_map drm_via_chrome9_shadow_map_t;*/ +struct drm_via_chrome9_shadow_map { + struct drm_map *shadow; + unsigned int shadow_size; + unsigned int *shadow_handle; +}; + +/*typedef struct drm_via_chrome9_pagetable_map + *drm_via_chrome9_pagetable_map_t; + */ +struct drm_via_chrome9_pagetable_map { + unsigned int pagetable_offset; + unsigned int pagetable_size; + unsigned int *pagetable_handle; + unsigned int mmt_register; +}; + +/*typedef struct drm_via_chrome9_private drm_via_chrome9_private_t;*/ +struct drm_via_chrome9_private { + int chip_agp; + int chip_index; + int chip_sub_index; + + unsigned long front_offset; + unsigned long back_offset; + unsigned long depth_offset; + unsigned long fb_base_address; + unsigned long available_fb_size; + int usec_timeout; + int max_apertures; + struct drm_sman sman; + unsigned int alignment; + /* bit[31]:0:indicate no alignment needed,1:indicate + alignment needed and size is bit[0:30]*/ + + struct drm_map *sarea; + struct drm_via_chrome9_sarea *sarea_priv; + + struct drm_map *mmio; + struct drm_map *hostBlt; + struct drm_map *fb; + struct drm_map *front; + struct drm_map *back; + struct drm_map *depth; + struct drm_map *agp_tex; + unsigned int agp_size; + unsigned int agp_offset; + + struct semaphore *drm_s3g_sem; + + struct drm_via_chrome9_shadow_map shadow_map; + struct drm_via_chrome9_pagetable_map pagetable_map; + + char *bci; + + int aperture_usage[NUMBER_OF_APERTURES]; + void *event_tag_info; + + /* DMA buffer manager */ + void *dma_manager; + /* Indicate agp/pcie heap initialization flag */ + int agp_initialized; + /* Indicate video heap initialization flag */ + int vram_initialized; + + unsigned long pcie_vmalloc_addr; + + /* pointer to device information */ + void *dev; + /* if agp init fail, go ahead and force dri use PCI*/ + enum { + DRM_AGP_RING_BUFFER, + DRM_AGP_DOUBLE_BUFFER, + DRM_AGP_DISABLED + } drm_agp_type; + /*end*/ + + unsigned long *bci_buffer; + unsigned long pcie_vmalloc_nocache; +}; + + +enum via_chrome9_family { + VIA_CHROME9_OTHER = 0, /* Baseline */ + VIA_CHROME9_PRO_GROUP_A,/* Another video engine and DMA commands */ + VIA_CHROME9_DX9_0, + VIA_CHROME9_PCIE_GROUP +}; + +/* VIA_CHROME9 MMIO register access */ +#define VIA_CHROME9_BASE ((dev_priv->mmio)) + +#define VIA_CHROME9_READ(reg) DRM_READ32(VIA_CHROME9_BASE, reg) +#define VIA_CHROME9_WRITE(reg, val) DRM_WRITE32(VIA_CHROME9_BASE, reg, val) +#define VIA_CHROME9_READ8(reg) DRM_READ8(VIA_CHROME9_BASE, reg) +#define VIA_CHROME9_WRITE8(reg, val) DRM_WRITE8(VIA_CHROME9_BASE, reg, val) + +#endif --- linux-2.6.27.orig/ubuntu/via_chrome9/Kconfig +++ linux-2.6.27/ubuntu/via_chrome9/Kconfig @@ -0,0 +1,6 @@ +config DRM_VIA_CHROME9 + tristate "Via unichrome9 video cards" + depends on DRM + help + Choose this option if you have a Via unichrome9 or compatible video + chipset. If M is selected the module will be called via_chrome9. --- linux-2.6.27.orig/ubuntu/via_chrome9/via_chrome9_mm.c +++ linux-2.6.27/ubuntu/via_chrome9/via_chrome9_mm.c @@ -0,0 +1,388 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * (including the next paragraph) shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include "via_chrome9_drm.h" +#include "via_chrome9_drv.h" +#include +#include "via_chrome9_mm.h" + +#define VIA_CHROME9_MM_GRANULARITY 4 +#define VIA_CHROME9_MM_GRANULARITY_MASK ((1 << VIA_CHROME9_MM_GRANULARITY) - 1) + + +int via_chrome9_map_init(struct drm_device *dev, + struct drm_via_chrome9_init *init) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *)dev->dev_private; + + dev_priv->sarea = drm_getsarea(dev); + if (!dev_priv->sarea) { + DRM_ERROR("could not find sarea!\n"); + goto error; + } + dev_priv->sarea_priv = + (struct drm_via_chrome9_sarea *)((unsigned char *)dev_priv-> + sarea->handle + init->sarea_priv_offset); + + dev_priv->fb = drm_core_findmap(dev, init->fb_handle); + if (!dev_priv->fb) { + DRM_ERROR("could not find framebuffer!\n"); + goto error; + } + /* Frame buffer physical base address */ + dev_priv->fb_base_address = init->fb_base_address; + + if (init->shadow_size) { + /* find apg shadow region mappings */ + dev_priv->shadow_map.shadow = drm_core_findmap(dev, init-> + shadow_handle); + if (!dev_priv->shadow_map.shadow) { + DRM_ERROR("could not shadow map!\n"); + goto error; + } + dev_priv->shadow_map.shadow_size = init->shadow_size; + dev_priv->shadow_map.shadow_handle = (unsigned int *)dev_priv-> + shadow_map.shadow->handle; + init->shadow_handle = dev_priv->shadow_map.shadow->offset; + } + if (init->agp_tex_size && init->chip_agp != CHIP_PCIE) { + /* find apg texture buffer mappings */ + dev_priv->agp_tex = drm_core_findmap(dev, init->agp_tex_handle); + dev_priv->agp_size = init->agp_tex_size; + dev_priv->agp_offset = init->agp_tex_handle; + if (!dev_priv->agp_tex) { + DRM_ERROR("could not find agp texture map !\n"); + goto error; + } + } + /* find mmio/dma mappings */ + dev_priv->mmio = drm_core_findmap(dev, init->mmio_handle); + if (!dev_priv->mmio) { + DRM_ERROR("failed to find mmio region!\n"); + goto error; + } + + dev_priv->hostBlt = drm_core_findmap(dev, init->hostBlt_handle); + if (!dev_priv->hostBlt) { + DRM_ERROR("failed to find host bitblt region!\n"); + goto error; + } + + dev_priv->drm_agp_type = init->agp_type; + if (init->agp_type != AGP_DISABLED && init->chip_agp != CHIP_PCIE) { + dev->agp_buffer_map = drm_core_findmap(dev, init->dma_handle); + if (!dev->agp_buffer_map) { + DRM_ERROR("failed to find dma buffer region!\n"); + goto error; + } + } + + dev_priv->bci = (char *)dev_priv->mmio->handle + 0x10000; + + return 0; + +error: + /* do cleanup here, refine_later */ + return (-EINVAL); +} + +int via_chrome9_heap_management_init(struct drm_device *dev, + struct drm_via_chrome9_init *init) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + int ret = 0; + + /* video memory management. range: 0 ---- video_whole_size */ + mutex_lock(&dev->struct_mutex); + ret = drm_sman_set_range(&dev_priv->sman, VIA_CHROME9_MEM_VIDEO, + 0, dev_priv->available_fb_size >> VIA_CHROME9_MM_GRANULARITY); + if (ret) { + DRM_ERROR("VRAM memory manager initialization ******ERROR\ + !******\n"); + mutex_unlock(&dev->struct_mutex); + goto error; + } + dev_priv->vram_initialized = 1; + /* agp/pcie heap management. + note:because agp is contradict with pcie, so only one is enough + for managing both of them.*/ + init->agp_type = dev_priv->drm_agp_type; + if (init->agp_type != AGP_DISABLED && dev_priv->agp_size) { + ret = drm_sman_set_range(&dev_priv->sman, VIA_CHROME9_MEM_AGP, + 0, dev_priv->agp_size >> VIA_CHROME9_MM_GRANULARITY); + if (ret) { + DRM_ERROR("AGP/PCIE memory manager initialization ******ERROR\ + !******\n"); + mutex_unlock(&dev->struct_mutex); + goto error; + } + dev_priv->agp_initialized = 1; + } + mutex_unlock(&dev->struct_mutex); + return 0; + +error: + /* Do error recover here, refine_later */ + return -EINVAL; +} + + +void via_chrome9_memory_destroy_heap(struct drm_device *dev, + struct drm_via_chrome9_private *dev_priv) +{ + mutex_lock(&dev->struct_mutex); + drm_sman_cleanup(&dev_priv->sman); + dev_priv->vram_initialized = 0; + dev_priv->agp_initialized = 0; + mutex_unlock(&dev->struct_mutex); +} + +void via_chrome9_reclaim_buffers_locked(struct drm_device *dev, + struct drm_file *file_priv) +{ + return; +} + +int via_chrome9_ioctl_allocate_aperture(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + return 0; +} + +int via_chrome9_ioctl_free_aperture(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + return 0; +} + + +/* Allocate memory from DRM module for video playing */ +int via_chrome9_ioctl_allocate_mem_base(struct drm_device *dev, +void *data, struct drm_file *file_priv) +{ + struct drm_via_chrome9_mem *mem = data; + struct drm_memblock_item *item; + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + unsigned long tmpSize = 0, offset = 0, alignment = 0; + /* modify heap_type to agp for pcie, since we treat pcie/agp heap + no difference in heap management */ + if (mem->type == memory_heap_pcie) { + if (dev_priv->chip_agp != CHIP_PCIE) { + DRM_ERROR( + "User want to alloc memory from pcie heap but via_chrome9.ko\ + has no this heap exist.******ERROR******\n"); + return -EINVAL; + } + mem->type = memory_heap_agp; + } + + if (mem->type > VIA_CHROME9_MEM_AGP) { + DRM_ERROR("Unknown memory type allocation\n"); + return -EINVAL; + } + mutex_lock(&dev->struct_mutex); + if (0 == ((mem->type == VIA_CHROME9_MEM_VIDEO) ? + dev_priv->vram_initialized : dev_priv->agp_initialized)) { + DRM_ERROR("Attempt to allocate from uninitialized\ + memory manager.\n"); + mutex_unlock(&dev->struct_mutex); + return -EINVAL; + } + tmpSize = (mem->size + VIA_CHROME9_MM_GRANULARITY_MASK) >> + VIA_CHROME9_MM_GRANULARITY; + mem->size = tmpSize << VIA_CHROME9_MM_GRANULARITY; + alignment = (dev_priv->alignment & 0x80000000) ? dev_priv-> + alignment & 0x7FFFFFFF:0; + alignment /= (1 << VIA_CHROME9_MM_GRANULARITY); + item = drm_sman_alloc(&dev_priv->sman, mem->type, tmpSize, alignment, + (unsigned long)file_priv); + mutex_unlock(&dev->struct_mutex); + /* alloc failed */ + if (!item) { + DRM_ERROR("Allocate memory failed ******ERROR******.\n"); + return -ENOMEM; + } + /* Till here every thing is ok, we check the memory type allocated + and return appropriate value to user mode Here the value return to + user is very difficult to operate. BE CAREFULLY!!! */ + /* offset is used by user mode ap to calculate the virtual address + which is used to access the memory allocated */ + mem->index = item->user_hash.key; + offset = item->mm->offset(item->mm, item->mm_info) << + VIA_CHROME9_MM_GRANULARITY; + switch (mem->type) { + case VIA_CHROME9_MEM_VIDEO: + mem->offset = offset + dev_priv->back_offset; + break; + case VIA_CHROME9_MEM_AGP: + /* return different value to user according to the chip type */ + if (dev_priv->chip_agp == CHIP_PCIE) { + mem->offset = offset + + ((struct drm_via_chrome9_DMA_manager *)dev_priv-> + dma_manager)->DMASize * sizeof(unsigned long); + } else { + mem->offset = offset; + } + break; + default: + /* Strange thing happen! Faint. Code bug! */ + DRM_ERROR("Enter here is impossible ******\ + ERROR******.\n"); + return -EINVAL; + } + /*DONE. Need we call function copy_to_user ?NO. We can't even + touch user's space.But we are lucky, since kernel drm:drm_ioctl + will to the job for us. */ + return 0; +} + +/* Allocate video/AGP/PCIE memory from heap management */ +int via_chrome9_ioctl_allocate_mem_wrapper(struct drm_device + *dev, void *data, struct drm_file *file_priv) +{ + struct drm_via_chrome9_memory_alloc *memory_alloc = + (struct drm_via_chrome9_memory_alloc *)data; + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + struct drm_via_chrome9_mem mem; + + mem.size = memory_alloc->size; + mem.type = memory_alloc->heap_type; + dev_priv->alignment = memory_alloc->align | 0x80000000; + if (via_chrome9_ioctl_allocate_mem_base(dev, &mem, file_priv)) { + DRM_ERROR("Allocate memory error!.\n"); + return -ENOMEM; + } + dev_priv->alignment = 0; + /* Till here every thing is ok, we check the memory type allocated and + return appropriate value to user mode Here the value return to user is + very difficult to operate. BE CAREFULLY!!!*/ + /* offset is used by user mode ap to calculate the virtual address + which is used to access the memory allocated */ + memory_alloc->offset = mem.offset; + memory_alloc->heap_info.lpL1Node = (void *)mem.index; + memory_alloc->size = mem.size; + switch (memory_alloc->heap_type) { + case VIA_CHROME9_MEM_VIDEO: + memory_alloc->physaddress = memory_alloc->offset + + dev_priv->fb_base_address; + memory_alloc->linearaddress = (void *)memory_alloc->physaddress; + break; + case VIA_CHROME9_MEM_AGP: + /* return different value to user according to the chip type */ + if (dev_priv->chip_agp == CHIP_PCIE) { + memory_alloc->physaddress = memory_alloc->offset; + memory_alloc->linearaddress = (void *)memory_alloc-> + physaddress; + } else { + memory_alloc->physaddress = dev->agp->base + + memory_alloc->offset + + ((struct drm_via_chrome9_DMA_manager *) + dev_priv->dma_manager)->DMASize * sizeof(unsigned long); + memory_alloc->linearaddress = + (void *)memory_alloc->physaddress; + } + break; + default: + /* Strange thing happen! Faint. Code bug! */ + DRM_ERROR("Enter here is impossible ******ERROR******.\n"); + return -EINVAL; + } + return 0; +} + +int via_chrome9_ioctl_free_mem_wrapper(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_via_chrome9_memory_alloc *memory_alloc = data; + struct drm_via_chrome9_mem mem; + + mem.index = (unsigned long)memory_alloc->heap_info.lpL1Node; + if (via_chrome9_ioctl_freemem_base(dev, &mem, file_priv)) { + DRM_ERROR("function free_mem_wrapper error.\n"); + return -EINVAL; + } + + return 0; +} + +int via_chrome9_ioctl_freemem_base(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_via_chrome9_private *dev_priv = dev->dev_private; + struct drm_via_chrome9_mem *mem = data; + int ret; + + mutex_lock(&dev->struct_mutex); + ret = drm_sman_free_key(&dev_priv->sman, mem->index); + mutex_unlock(&dev->struct_mutex); + DRM_DEBUG("free = 0x%lx\n", mem->index); + + return ret; +} + +int via_chrome9_ioctl_check_vidmem_size(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + return 0; +} + +int via_chrome9_ioctl_pciemem_ctrl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + int result = 0; + struct drm_via_chrome9_private *dev_priv = dev->dev_private; + struct drm_via_chrome9_pciemem_ctrl *pcie_memory_ctrl = data; + switch (pcie_memory_ctrl->ctrl_type) { + case pciemem_copy_from_user: + result = copy_from_user((void *)( + dev_priv->pcie_vmalloc_nocache+ + pcie_memory_ctrl->pcieoffset), + pcie_memory_ctrl->usermode_data, + pcie_memory_ctrl->size); + break; + case pciemem_copy_to_user: + result = copy_to_user(pcie_memory_ctrl->usermode_data, + (void *)(dev_priv->pcie_vmalloc_nocache+ + pcie_memory_ctrl->pcieoffset), + pcie_memory_ctrl->size); + break; + case pciemem_memset: + memset((void *)(dev_priv->pcie_vmalloc_nocache + + pcie_memory_ctrl->pcieoffset), + pcie_memory_ctrl->memsetdata, + pcie_memory_ctrl->size); + break; + default: + break; + } + return 0; +} --- linux-2.6.27.orig/ubuntu/via_chrome9/Makefile +++ linux-2.6.27/ubuntu/via_chrome9/Makefile @@ -0,0 +1,3 @@ +via_chrome9-objs := via_chrome9_drv.o via_chrome9_drm.o via_chrome9_mm.o via_chrome9_dma.o + +obj-$(CONFIG_DRM_VIA_CHROME9) += via_chrome9.o --- linux-2.6.27.orig/ubuntu/via_chrome9/via_chrome9_dma.c +++ linux-2.6.27/ubuntu/via_chrome9/via_chrome9_dma.c @@ -0,0 +1,1147 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * (including the next paragraph) shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include "via_chrome9_drm.h" +#include "via_chrome9_drv.h" +#include "via_chrome9_3d_reg.h" +#include "via_chrome9_dma.h" + +#define NULLCOMMANDNUMBER 256 +unsigned int NULL_COMMAND_INV[4] = + { 0xCC000000, 0xCD000000, 0xCE000000, 0xCF000000 }; + +void +via_chrome9ke_assert(int a) +{ +} + +unsigned int +ProtectSizeValue(unsigned int size) +{ + unsigned int i; + for (i = 0; i < 8; i++) + if ((size > (1 << (i + 12))) + && (size <= (1 << (i + 13)))) + return (i + 1); + return 0; +} + +static unsigned int +InitPCIEGART(struct drm_via_chrome9_private *dev_priv) +{ + unsigned int *pGARTTable; + unsigned int i, entries, GARTOffset; + unsigned char sr6a, sr6b, sr6c, sr6f, sr7b; + + if (!dev_priv->pagetable_map.pagetable_size) + return 0; + + entries = dev_priv->pagetable_map.pagetable_size / sizeof(unsigned int); + + pGARTTable = + ioremap_nocache(dev_priv->fb_base_address + + dev_priv->pagetable_map.pagetable_offset, + dev_priv->pagetable_map.pagetable_size); + if (pGARTTable) + dev_priv->pagetable_map.pagetable_handle = pGARTTable; + else + return 0; + + /*set gart table base */ + GARTOffset = dev_priv->pagetable_map.pagetable_offset; + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c &= (~0x80); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + sr6a = (unsigned char) ((GARTOffset & 0xff000) >> 12); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6a); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6a); + + sr6b = (unsigned char) ((GARTOffset & 0xff00000) >> 20); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6b); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6b); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c |= ((unsigned char) ((GARTOffset >> 28) & 0x01)); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x7b); + sr7b = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr7b &= (~0x0f); + sr7b |= ProtectSizeValue(dev_priv->pagetable_map.pagetable_size); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr7b); + + for (i = 0; i < entries; i++) + writel(0x80000000, pGARTTable + i); + /*flush */ + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6f); + do { + sr6f = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + } + while (sr6f & 0x80) + ; + + sr6f |= 0x80; + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6f); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c |= 0x80; + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + return 1; +} + + +static unsigned int * +AllocAndBindPCIEMemory(struct drm_via_chrome9_private *dev_priv, + unsigned int size, unsigned int offset) +{ + unsigned int *addrlinear; + unsigned int *pGARTTable; + unsigned int entries, alignedoffset, i; + unsigned char sr6c, sr6f; + + if (!size) + return NULL; + + entries = (size + PAGE_SIZE - 1) / PAGE_SIZE; + alignedoffset = (offset + PAGE_SIZE - 1) / PAGE_SIZE; + + if ((entries + alignedoffset) > + (dev_priv->pagetable_map.pagetable_size / sizeof(unsigned int))) + return NULL; + + addrlinear = + __vmalloc(entries * PAGE_SIZE, GFP_KERNEL | __GFP_HIGHMEM, + PAGE_KERNEL_NOCACHE); + + if (!addrlinear) + return NULL; + + pGARTTable = dev_priv->pagetable_map.pagetable_handle; + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c &= (~0x80); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6f); + do { + sr6f = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + } + while (sr6f & 0x80) + ; + + for (i = 0; i < entries; i++) + writel(page_to_pfn + (vmalloc_to_page((void *) addrlinear + PAGE_SIZE * i)) & + 0x3fffffff, pGARTTable + i + alignedoffset); + + sr6f |= 0x80; + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6f); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c |= 0x80; + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + return addrlinear; + +} + +void +SetAGPDoubleCmd_inv(struct drm_device *dev) +{ + /* we now don't use double buffer */ + return; +} + +void +SetAGPRingCmdRegs_inv(struct drm_device *dev) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = + (struct drm_via_chrome9_DMA_manager *) dev_priv->dma_manager; + unsigned int AGPBufLinearBase = 0, AGPBufPhysicalBase = 0; + unsigned long *pFree; + unsigned int dwStart, dwEnd, dwPause, AGPCurrAddr, AGPCurStat, CurrAGP; + unsigned int dwReg60, dwReg61, dwReg62, dwReg63, + dwReg64, dwReg65, dwJump; + + lpcmDMAManager->pFree = lpcmDMAManager->pBeg; + + AGPBufLinearBase = (unsigned int) lpcmDMAManager->addr_linear; + AGPBufPhysicalBase = + (dev_priv->chip_agp == + CHIP_PCIE) ? 0 : (unsigned int) dev->agp->base + + lpcmDMAManager->pPhysical; + /*add shadow offset */ + + CurrAGP = + GetMMIORegister(dev_priv->mmio->handle, INV_RB_AGPCMD_CURRADDR); + AGPCurStat = + GetMMIORegister(dev_priv->mmio->handle, INV_RB_AGPCMD_STATUS); + + if (AGPCurStat & INV_AGPCMD_InPause) { + AGPCurrAddr = + GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + pFree = (unsigned long *) (AGPBufLinearBase + AGPCurrAddr - + AGPBufPhysicalBase); + ADDCmdHeader2_INVI(pFree, INV_REG_CR_TRANS, INV_ParaType_Dummy); + if (dev_priv->chip_sub_index == CHIP_H6S2) + do { + ADDCmdData_INVI(pFree, 0xCCCCCCC0); + ADDCmdData_INVI(pFree, 0xDDD00000); + } + while ((u32)((unsigned int) pFree) & 0x7f) + ; + /*for 8*128bit aligned */ + else + do { + ADDCmdData_INVI(pFree, 0xCCCCCCC0); + ADDCmdData_INVI(pFree, 0xDDD00000); + } + while ((u32) ((unsigned int) pFree) & 0x1f) + ; + /*for 256bit aligned */ + dwPause = + (u32) (((unsigned int) pFree) - AGPBufLinearBase + + AGPBufPhysicalBase - 16); + + dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause); + dwReg65 = + INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | + INV_HAGPBpID_STOP; + + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, + INV_ParaType_PreCR); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + dwReg64); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + dwReg65); + + while ((GetMMIORegister + (dev_priv->mmio->handle, + INV_RB_ENG_STATUS) & INV_ENG_BUSY_ALL)); + } + dwStart = + (u32) ((unsigned int) lpcmDMAManager->pBeg - AGPBufLinearBase + + AGPBufPhysicalBase); + dwEnd = (u32) ((unsigned int) lpcmDMAManager->pEnd - AGPBufLinearBase + + AGPBufPhysicalBase); + + lpcmDMAManager->pFree = lpcmDMAManager->pBeg; + if (dev_priv->chip_sub_index == CHIP_H6S2) { + ADDCmdHeader2_INVI(lpcmDMAManager->pFree, INV_REG_CR_TRANS, + INV_ParaType_Dummy); + do { + ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC0); + ADDCmdData_INVI(lpcmDMAManager->pFree, 0xDDD00000); + } + while ((u32)((unsigned long *) lpcmDMAManager->pFree) & 0x7f) + ; + } + dwJump = 0xFFFFFFF0; + dwPause = + (u32)(((unsigned int) lpcmDMAManager->pFree) - + 16 - AGPBufLinearBase + AGPBufPhysicalBase); + + DRM_DEBUG("dwStart = %08x, dwEnd = %08x, dwPause = %08x\n", dwStart, + dwEnd, dwPause); + + dwReg60 = INV_SubA_HAGPBstL | INV_HWBasL(dwStart); + dwReg61 = INV_SubA_HAGPBstH | INV_HWBasH(dwStart); + dwReg62 = INV_SubA_HAGPBendL | INV_HWBasL(dwEnd); + dwReg63 = INV_SubA_HAGPBendH | INV_HWBasH(dwEnd); + dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause); + dwReg65 = INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | INV_HAGPBpID_PAUSE; + + if (dev_priv->chip_sub_index == CHIP_H6S2) + dwReg60 |= 0x01; + + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, + INV_ParaType_PreCR); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg60); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg61); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg62); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg63); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg64); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg65); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + INV_SubA_HAGPBjumpL | INV_HWBasL(dwJump)); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + INV_SubA_HAGPBjumpH | INV_HWBasH(dwJump)); + + /* Trigger AGP cycle */ + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + INV_SubA_HFthRCM | INV_HFthRCM_10 | INV_HAGPBTrig); + + /*for debug */ + CurrAGP = + GetMMIORegister(dev_priv->mmio->handle, INV_RB_AGPCMD_CURRADDR); + + lpcmDMAManager->pInUseBySW = lpcmDMAManager->pFree; +} + +/* Do hw intialization and determine whether to use dma or mmio to +talk with hw */ +int +via_chrome9_hw_init(struct drm_device *dev, + struct drm_via_chrome9_init *init) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + unsigned retval = 0; + unsigned int *pGARTTable, *addrlinear = NULL; + int pages; + struct drm_clb_event_tag_info *event_tag_info; + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = NULL; + + if (init->chip_agp == CHIP_PCIE) { + dev_priv->pagetable_map.pagetable_offset = + init->garttable_offset; + dev_priv->pagetable_map.pagetable_size = init->garttable_size; + dev_priv->agp_size = init->agp_tex_size; + /*Henry :prepare for PCIE texture buffer */ + } else { + dev_priv->pagetable_map.pagetable_offset = 0; + dev_priv->pagetable_map.pagetable_size = 0; + } + + dev_priv->dma_manager = + kmalloc(sizeof(struct drm_via_chrome9_DMA_manager), GFP_KERNEL); + if (!dev_priv->dma_manager) { + DRM_ERROR("could not allocate system for dma_manager!\n"); + return -ENOMEM; + } + + lpcmDMAManager = + (struct drm_via_chrome9_DMA_manager *) dev_priv->dma_manager; + ((struct drm_via_chrome9_DMA_manager *) + dev_priv->dma_manager)->DMASize = init->DMA_size; + ((struct drm_via_chrome9_DMA_manager *) + dev_priv->dma_manager)->pPhysical = init->DMA_phys_address; + + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, 0x00110000); + if (dev_priv->chip_sub_index == CHIP_H6S2) { + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + 0x06000000); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + 0x07100000); + } else { + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + 0x02000000); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + 0x03100000); + } + + /* Specify fence command read back ID */ + /* Default the read back ID is CR */ + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, + INV_ParaType_PreCR); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + INV_SubA_HSetRBGID | INV_HSetRBGID_CR); + + DRM_DEBUG("begin to init\n"); + + if (dev_priv->chip_sub_index == CHIP_H6S2) { + dev_priv->pcie_vmalloc_nocache = 0; + if (dev_priv->pagetable_map.pagetable_size) + retval = InitPCIEGART(dev_priv); + + if (retval && dev_priv->drm_agp_type != DRM_AGP_DISABLED) { + addrlinear = + AllocAndBindPCIEMemory(dev_priv, + lpcmDMAManager->DMASize + + dev_priv->agp_size, 0); + if (addrlinear) { + dev_priv->pcie_vmalloc_nocache = (unsigned long) + addrlinear; + } else { + dev_priv->bci_buffer = + vmalloc(MAX_BCI_BUFFER_SIZE); + dev_priv->drm_agp_type = DRM_AGP_DISABLED; + } + } else { + dev_priv->bci_buffer = vmalloc(MAX_BCI_BUFFER_SIZE); + dev_priv->drm_agp_type = DRM_AGP_DISABLED; + } + } else { + if (dev_priv->drm_agp_type != DRM_AGP_DISABLED) { + pGARTTable = NULL; + addrlinear = (unsigned int *) + ioremap(dev->agp->base + + lpcmDMAManager->pPhysical, + lpcmDMAManager->DMASize); + dev_priv->bci_buffer = NULL; + } else { + dev_priv->bci_buffer = vmalloc(MAX_BCI_BUFFER_SIZE); + /*Homer, BCI path always use this block of memory8 */ + } + } + + /*till here we have known whether support dma or not */ + pages = dev->sg->pages; + event_tag_info = vmalloc(sizeof(struct drm_clb_event_tag_info)); + memset(event_tag_info, 0, sizeof(struct drm_clb_event_tag_info)); + if (!event_tag_info) + return DRM_ERROR(" event_tag_info allocate error!"); + + /* aligned to 16k alignment */ + event_tag_info->linear_address = + (int + *) (((unsigned int) dev_priv->shadow_map.shadow_handle + + 0x3fff) & 0xffffc000); + event_tag_info->event_tag_linear_address = + event_tag_info->linear_address + 3; + dev_priv->event_tag_info = (void *) event_tag_info; + dev_priv->max_apertures = NUMBER_OF_APERTURES_CLB; + + /* Initialize DMA data structure */ + lpcmDMAManager->DMASize /= sizeof(unsigned int); + lpcmDMAManager->pBeg = addrlinear; + lpcmDMAManager->pFree = lpcmDMAManager->pBeg; + lpcmDMAManager->pInUseBySW = lpcmDMAManager->pBeg; + lpcmDMAManager->pInUseByHW = lpcmDMAManager->pBeg; + lpcmDMAManager->LastIssuedEventTag = (unsigned int) (unsigned long *) + lpcmDMAManager->pBeg; + lpcmDMAManager->ppInUseByHW = + (unsigned int **) ((char *) (dev_priv->mmio->handle) + + INV_RB_AGPCMD_CURRADDR); + lpcmDMAManager->bDMAAgp = dev_priv->chip_agp; + lpcmDMAManager->addr_linear = (unsigned int *) addrlinear; + + if (dev_priv->drm_agp_type == DRM_AGP_DOUBLE_BUFFER) { + lpcmDMAManager->MaxKickoffSize = lpcmDMAManager->DMASize >> 1; + lpcmDMAManager->pEnd = + lpcmDMAManager->addr_linear + + (lpcmDMAManager->DMASize >> 1) - 1; + SetAGPDoubleCmd_inv(dev); + if (dev_priv->chip_sub_index == CHIP_H6S2) { + DRM_INFO("DMA buffer initialized finished. "); + DRM_INFO("Use PCIE Double Buffer type!\n"); + DRM_INFO("Total PCIE DMA buffer size = %8d bytes. \n", + lpcmDMAManager->DMASize << 2); + } else { + DRM_INFO("DMA buffer initialized finished. "); + DRM_INFO("Use AGP Double Buffer type!\n"); + DRM_INFO("Total AGP DMA buffer size = %8d bytes. \n", + lpcmDMAManager->DMASize << 2); + } + } else if (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER) { + lpcmDMAManager->MaxKickoffSize = lpcmDMAManager->DMASize; + lpcmDMAManager->pEnd = + lpcmDMAManager->addr_linear + lpcmDMAManager->DMASize; + SetAGPRingCmdRegs_inv(dev); + if (dev_priv->chip_sub_index == CHIP_H6S2) { + DRM_INFO("DMA buffer initialized finished. \n"); + DRM_INFO("Use PCIE Ring Buffer type!"); + DRM_INFO("Total PCIE DMA buffer size = %8d bytes. \n", + lpcmDMAManager->DMASize << 2); + } else { + DRM_INFO("DMA buffer initialized finished. "); + DRM_INFO("Use AGP Ring Buffer type!\n"); + DRM_INFO("Total AGP DMA buffer size = %8d bytes. \n", + lpcmDMAManager->DMASize << 2); + } + } else if (dev_priv->drm_agp_type == DRM_AGP_DISABLED) { + lpcmDMAManager->MaxKickoffSize = 0x0; + if (dev_priv->chip_sub_index == CHIP_H6S2) + DRM_INFO("PCIE init failed! Use PCI\n"); + else + DRM_INFO("AGP init failed! Use PCI\n"); + } + return 0; +} + +static void +kickoff_bci_inv(struct drm_via_chrome9_private *dev_priv, + struct drm_via_chrome9_flush *dma_info) +{ + u32 HdType, dwQWCount, i, dwCount, Addr1, Addr2, SWPointer, + SWPointerEnd; + unsigned long *pCmdData; + int result; + + /*pCmdData = __s3gke_vmalloc(dma_info->cmd_size<<2); */ + pCmdData = dev_priv->bci_buffer; + + if (!pCmdData) + return; + + result = copy_from_user((int *) pCmdData, dma_info->usermode_dma_buf, + dma_info->cmd_size << 2); + + SWPointer = 0; + SWPointerEnd = (u32) dma_info->cmd_size; + while (SWPointer < SWPointerEnd) { + HdType = pCmdData[SWPointer] & INV_AGPHeader_MASK; + switch (HdType) { + case INV_AGPHeader0: + case INV_AGPHeader5: + dwQWCount = pCmdData[SWPointer + 1]; + SWPointer += 4; + + for (i = 0; i < dwQWCount; i++) { + SetMMIORegister(dev_priv->mmio->handle, + pCmdData[SWPointer], + pCmdData[SWPointer + 1]); + SWPointer += 2; + } + break; + + case INV_AGPHeader1: + dwCount = pCmdData[SWPointer + 1]; + Addr1 = 0x0; + SWPointer += 4; /* skip 128-bit. */ + + for (; dwCount > 0; dwCount--, SWPointer++, + Addr1 += 4) { + SetMMIORegister(dev_priv->hostBlt->handle, + Addr1, pCmdData[SWPointer]); + } + break; + + case INV_AGPHeader4: + dwCount = pCmdData[SWPointer + 1]; + Addr1 = pCmdData[SWPointer] & 0x0000FFFF; + SWPointer += 4; /* skip 128-bit. */ + + for (; dwCount > 0; dwCount--, SWPointer++) + SetMMIORegister(dev_priv->mmio->handle, Addr1, + pCmdData[SWPointer]); + break; + + case INV_AGPHeader2: + Addr1 = pCmdData[SWPointer + 1] & 0xFFFF; + Addr2 = pCmdData[SWPointer] & 0xFFFF; + + /* Write first data (either ParaType or whatever) to + Addr1 */ + SetMMIORegister(dev_priv->mmio->handle, Addr1, + pCmdData[SWPointer + 2]); + SWPointer += 4; + + /* The following data are all written to Addr2, + until another header is met */ + while (!IS_AGPHEADER_INV(pCmdData[SWPointer]) + && (SWPointer < SWPointerEnd)) { + SetMMIORegister(dev_priv->mmio->handle, Addr2, + pCmdData[SWPointer]); + SWPointer++; + } + break; + + case INV_AGPHeader3: + Addr1 = pCmdData[SWPointer] & 0xFFFF; + Addr2 = Addr1 + 4; + dwCount = pCmdData[SWPointer + 1]; + + /* Write first data (either ParaType or whatever) to + Addr1 */ + SetMMIORegister(dev_priv->mmio->handle, Addr1, + pCmdData[SWPointer + 2]); + SWPointer += 4; + + for (i = 0; i < dwCount; i++) { + SetMMIORegister(dev_priv->mmio->handle, Addr2, + pCmdData[SWPointer]); + SWPointer++; + } + break; + + case INV_AGPHeader6: + break; + + case INV_AGPHeader7: + break; + + default: + SWPointer += 4; /* Advance to next header */ + } + + SWPointer = (SWPointer + 3) & ~3; + } +} + +void +kickoff_dma_db_inv(struct drm_device *dev) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = + dev_priv->dma_manager; + + u32 BufferSize = (u32) (lpcmDMAManager->pFree - lpcmDMAManager->pBeg); + + unsigned int AGPBufLinearBase = + (unsigned int) lpcmDMAManager->addr_linear; + unsigned int AGPBufPhysicalBase = + (unsigned int) dev->agp->base + lpcmDMAManager->pPhysical; + /*add shadow offset */ + + unsigned int dwStart, dwEnd, dwPause; + unsigned int dwReg60, dwReg61, dwReg62, dwReg63, dwReg64, dwReg65; + unsigned int CR_Status; + + if (BufferSize == 0) + return; + + /* 256-bit alignment of AGP pause address */ + if ((u32) ((unsigned long *) lpcmDMAManager->pFree) & 0x1f) { + ADDCmdHeader2_INVI(lpcmDMAManager->pFree, INV_REG_CR_TRANS, + INV_ParaType_Dummy); + do { + ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC0); + ADDCmdData_INVI(lpcmDMAManager->pFree, 0xDDD00000); + } + while (((unsigned int) lpcmDMAManager->pFree) & 0x1f) + ; + } + + dwStart = + (u32) (unsigned long *)lpcmDMAManager->pBeg - + AGPBufLinearBase + AGPBufPhysicalBase; + dwEnd = (u32) (unsigned long *)lpcmDMAManager->pEnd - + AGPBufLinearBase + AGPBufPhysicalBase; + dwPause = + (u32)(unsigned long *)lpcmDMAManager->pFree - + AGPBufLinearBase + AGPBufPhysicalBase - 4; + + dwReg60 = INV_SubA_HAGPBstL | INV_HWBasL(dwStart); + dwReg61 = INV_SubA_HAGPBstH | INV_HWBasH(dwStart); + dwReg62 = INV_SubA_HAGPBendL | INV_HWBasL(dwEnd); + dwReg63 = INV_SubA_HAGPBendH | INV_HWBasH(dwEnd); + dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause); + dwReg65 = INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | INV_HAGPBpID_STOP; + + /* wait CR idle */ + CR_Status = GetMMIORegister(dev_priv->mmio->handle, INV_RB_ENG_STATUS); + while (CR_Status & INV_ENG_BUSY_CR) + CR_Status = + GetMMIORegister(dev_priv->mmio->handle, + INV_RB_ENG_STATUS); + + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, + INV_ParaType_PreCR); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg60); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg61); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg62); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg63); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg64); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg65); + + /* Trigger AGP cycle */ + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + INV_SubA_HFthRCM | INV_HFthRCM_10 | INV_HAGPBTrig); + + if (lpcmDMAManager->pBeg == lpcmDMAManager->addr_linear) { + /* The second AGP command buffer */ + lpcmDMAManager->pBeg = + lpcmDMAManager->addr_linear + + (lpcmDMAManager->DMASize >> 2); + lpcmDMAManager->pEnd = + lpcmDMAManager->addr_linear + lpcmDMAManager->DMASize; + lpcmDMAManager->pFree = lpcmDMAManager->pBeg; + } else { + /* The first AGP command buffer */ + lpcmDMAManager->pBeg = lpcmDMAManager->addr_linear; + lpcmDMAManager->pEnd = + lpcmDMAManager->addr_linear + + (lpcmDMAManager->DMASize / 2) - 1; + lpcmDMAManager->pFree = lpcmDMAManager->pBeg; + } + CR_Status = GetMMIORegister(dev_priv->mmio->handle, INV_RB_ENG_STATUS); +} + + +void +kickoff_dma_ring_inv(struct drm_device *dev) +{ + unsigned int dwPause, dwReg64, dwReg65; + + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = + dev_priv->dma_manager; + + unsigned int AGPBufLinearBase = + (unsigned int) lpcmDMAManager->addr_linear; + unsigned int AGPBufPhysicalBase = + (dev_priv->chip_agp == + CHIP_PCIE) ? 0 : (unsigned int) dev->agp->base + + lpcmDMAManager->pPhysical; + /*add shadow offset */ + + /* 256-bit alignment of AGP pause address */ + if (dev_priv->chip_sub_index == CHIP_H6S2) { + if ((u32) + ((unsigned long *) lpcmDMAManager->pFree) & 0x7f) { + ADDCmdHeader2_INVI(lpcmDMAManager->pFree, + INV_REG_CR_TRANS, + INV_ParaType_Dummy); + do { + ADDCmdData_INVI(lpcmDMAManager->pFree, + 0xCCCCCCC0); + ADDCmdData_INVI(lpcmDMAManager->pFree, + 0xDDD00000); + } + while ((u32)((unsigned long *) lpcmDMAManager->pFree) & + 0x7f) + ; + } + } else { + if ((u32) + ((unsigned long *) lpcmDMAManager->pFree) & 0x1f) { + ADDCmdHeader2_INVI(lpcmDMAManager->pFree, + INV_REG_CR_TRANS, + INV_ParaType_Dummy); + do { + ADDCmdData_INVI(lpcmDMAManager->pFree, + 0xCCCCCCC0); + ADDCmdData_INVI(lpcmDMAManager->pFree, + 0xDDD00000); + } + while ((u32)((unsigned long *) lpcmDMAManager->pFree) & + 0x1f) + ; + } + } + + + dwPause = (u32) ((unsigned long *) lpcmDMAManager->pFree) + - AGPBufLinearBase + AGPBufPhysicalBase - 16; + + dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause); + dwReg65 = INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | INV_HAGPBpID_PAUSE; + + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, + INV_ParaType_PreCR); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg64); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg65); + + lpcmDMAManager->pInUseBySW = lpcmDMAManager->pFree; +} + +static int +waitchipidle_inv(struct drm_via_chrome9_private *dev_priv) +{ + unsigned int count = 50000; + unsigned int eng_status; + unsigned int engine_busy; + + do { + eng_status = + GetMMIORegister(dev_priv->mmio->handle, + INV_RB_ENG_STATUS); + engine_busy = eng_status & INV_ENG_BUSY_ALL; + count--; + } + while (engine_busy && count) + ; + if (count && engine_busy == 0) + return 0; + return -1; +} + +void +get_space_db_inv(struct drm_device *dev, + struct cmd_get_space *lpcmGetSpaceData) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = + dev_priv->dma_manager; + + unsigned int dwRequestSize = lpcmGetSpaceData->dwRequestSize; + if (dwRequestSize > lpcmDMAManager->MaxKickoffSize) { + DRM_INFO("too big DMA buffer request!!!\n"); + via_chrome9ke_assert(0); + *lpcmGetSpaceData->pCmdData = (unsigned int) NULL; + return; + } + + if ((lpcmDMAManager->pFree + dwRequestSize) > + (lpcmDMAManager->pEnd - INV_CMDBUF_THRESHOLD * 2)) + kickoff_dma_db_inv(dev); + + *lpcmGetSpaceData->pCmdData = (unsigned int) lpcmDMAManager->pFree; +} + +void +RewindRingAGP_inv(struct drm_device *dev) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = + dev_priv->dma_manager; + + unsigned int AGPBufLinearBase = + (unsigned int) lpcmDMAManager->addr_linear; + unsigned int AGPBufPhysicalBase = + (dev_priv->chip_agp == + CHIP_PCIE) ? 0 : (unsigned int) dev->agp->base + + lpcmDMAManager->pPhysical; + /*add shadow offset */ + + unsigned int dwPause, dwJump; + unsigned int dwReg66, dwReg67; + unsigned int dwReg64, dwReg65; + + ADDCmdHeader2_INVI(lpcmDMAManager->pFree, INV_REG_CR_TRANS, + INV_ParaType_Dummy); + ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC7); + if (dev_priv->chip_sub_index == CHIP_H6S2) + while ((unsigned int) lpcmDMAManager->pFree & 0x7F) + ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC7); + else + while ((unsigned int) lpcmDMAManager->pFree & 0x1F) + ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC7); + dwJump = ((u32) ((unsigned long *) lpcmDMAManager->pFree)) + - AGPBufLinearBase + AGPBufPhysicalBase - 16; + + lpcmDMAManager->pFree = lpcmDMAManager->pBeg; + + dwPause = ((u32) ((unsigned long *) lpcmDMAManager->pFree)) + - AGPBufLinearBase + AGPBufPhysicalBase - 16; + + dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause); + dwReg65 = INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | INV_HAGPBpID_PAUSE; + + dwReg66 = INV_SubA_HAGPBjumpL | INV_HWBasL(dwJump); + dwReg67 = INV_SubA_HAGPBjumpH | INV_HWBasH(dwJump); + + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, + INV_ParaType_PreCR); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg66); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg67); + + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg64); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg65); + lpcmDMAManager->pInUseBySW = lpcmDMAManager->pFree; +} + + +void +get_space_ring_inv(struct drm_device *dev, + struct cmd_get_space *lpcmGetSpaceData) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = + dev_priv->dma_manager; + unsigned int dwUnFlushed; + unsigned int dwRequestSize = lpcmGetSpaceData->dwRequestSize; + + unsigned int AGPBufLinearBase = + (unsigned int) lpcmDMAManager->addr_linear; + unsigned int AGPBufPhysicalBase = + (dev_priv->chip_agp == + CHIP_PCIE) ? 0 : (unsigned int) dev->agp->base + + lpcmDMAManager->pPhysical; + /*add shadow offset */ + u32 BufStart, BufEnd, CurSW, CurHW, NextSW, BoundaryCheck; + + dwUnFlushed = + (unsigned int) (lpcmDMAManager->pFree - lpcmDMAManager->pBeg); + /*default bEnableModuleSwitch is on for metro,is off for rest */ + /*cmHW_Module_Switch is context-wide variable which is enough for 2d/3d + switch in a context. */ + /*But we must keep the dma buffer being wrapped head and tail by 3d cmds + when it is kicked off to kernel mode. */ + /*Get DMA Space (If requested, or no BCI space and BCI not forced. */ + + if (dwRequestSize > lpcmDMAManager->MaxKickoffSize) { + DRM_INFO("too big DMA buffer request!!!\n"); + via_chrome9ke_assert(0); + *lpcmGetSpaceData->pCmdData = 0; + return; + } + + if (dwUnFlushed + dwRequestSize > lpcmDMAManager->MaxKickoffSize) + kickoff_dma_ring_inv(dev); + + BufStart = + (u32)((unsigned int) lpcmDMAManager->pBeg) - AGPBufLinearBase + + AGPBufPhysicalBase; + BufEnd = (u32)((unsigned int) lpcmDMAManager->pEnd) - AGPBufLinearBase + + AGPBufPhysicalBase; + dwRequestSize = lpcmGetSpaceData->dwRequestSize << 2; + NextSW = (u32) ((unsigned int) lpcmDMAManager->pFree) + dwRequestSize + + INV_CMDBUF_THRESHOLD * 8 - AGPBufLinearBase + + AGPBufPhysicalBase; + + CurSW = (u32)((unsigned int) lpcmDMAManager->pFree) - AGPBufLinearBase + + AGPBufPhysicalBase; + CurHW = GetMMIORegister(dev_priv->mmio->handle, INV_RB_AGPCMD_CURRADDR); + + if (NextSW >= BufEnd) { + kickoff_dma_ring_inv(dev); + CurSW = (u32) ((unsigned int) lpcmDMAManager->pFree) - + AGPBufLinearBase + AGPBufPhysicalBase; + /* make sure the last rewind is completed */ + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + while (CurHW > CurSW) + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + /* Sometime the value read from HW is unreliable, + so need double confirm. */ + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + while (CurHW > CurSW) + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + BoundaryCheck = + BufStart + dwRequestSize + INV_QW_PAUSE_ALIGN * 16; + if (BoundaryCheck >= BufEnd) + /* If an empty command buffer can't hold + the request data. */ + via_chrome9ke_assert(0); + else { + /* We need to guarntee the new commands have no chance + to override the unexected commands or wait until there + is no unexecuted commands in agp buffer */ + if (CurSW <= BoundaryCheck) { + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + while (CurHW < CurSW) + CurHW = GetMMIORegister( + dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + /*Sometime the value read from HW is unreliable, + so need double confirm. */ + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + while (CurHW < CurSW) { + CurHW = GetMMIORegister( + dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + } + RewindRingAGP_inv(dev); + CurSW = (u32) ((unsigned long *) + lpcmDMAManager->pFree) - + AGPBufLinearBase + AGPBufPhysicalBase; + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + /* Waiting until hw pointer jump to start + and hw pointer will */ + /* equal to sw pointer */ + while (CurHW != CurSW) { + CurHW = GetMMIORegister( + dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + } + } else { + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + + while (CurHW <= BoundaryCheck) { + CurHW = GetMMIORegister( + dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + } + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + /* Sometime the value read from HW is + unreliable, so need double confirm. */ + while (CurHW <= BoundaryCheck) { + CurHW = GetMMIORegister( + dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + } + RewindRingAGP_inv(dev); + } + } + } else { + /* no need to rewind Ensure unexecuted agp commands will + not be override by new + agp commands */ + CurSW = (u32) ((unsigned int) lpcmDMAManager->pFree) - + AGPBufLinearBase + AGPBufPhysicalBase; + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + + while ((CurHW > CurSW) && (CurHW <= NextSW)) + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + + /* Sometime the value read from HW is unreliable, + so need double confirm. */ + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + while ((CurHW > CurSW) && (CurHW <= NextSW)) + CurHW = GetMMIORegister(dev_priv->mmio->handle, + INV_RB_AGPCMD_CURRADDR); + } + /*return the space handle */ + *lpcmGetSpaceData->pCmdData = (unsigned int) lpcmDMAManager->pFree; +} + +void +release_space_inv(struct drm_device *dev, + struct cmd_release_space *lpcmReleaseSpaceData) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = + dev_priv->dma_manager; + unsigned int dwReleaseSize = lpcmReleaseSpaceData->dwReleaseSize; + int i = 0; + + lpcmDMAManager->pFree += dwReleaseSize; + + /* aligned address */ + while (((unsigned int) lpcmDMAManager->pFree) & 0xF) { + /* not in 4 unsigned ints (16 Bytes) align address, + insert NULL Commands */ + *lpcmDMAManager->pFree++ = NULL_COMMAND_INV[i & 0x3]; + i++; + } + + if ((dev_priv->chip_sub_index == CHIP_H5) + && (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER)) { + ADDCmdHeader2_INVI(lpcmDMAManager->pFree, INV_REG_CR_TRANS, + INV_ParaType_Dummy); + for (i = 0; i < NULLCOMMANDNUMBER; i++) + ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCC000000); + } +} + +int +via_chrome9_ioctl_flush(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_via_chrome9_flush *dma_info = data; + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + int ret = 0; + int result = 0; + struct cmd_get_space getspace; + struct cmd_release_space releasespace; + volatile unsigned long *pCmdData = NULL; + + switch (dma_info->dma_cmd_type) { + /* Copy DMA buffer to BCI command buffer */ + case flush_bci: + case flush_bci_and_wait: + if (dma_info->cmd_size <= 0) + return 0; + if (dma_info->cmd_size > MAX_BCI_BUFFER_SIZE) { + DRM_INFO("too big BCI space request!!!\n"); + return 0; + } + + kickoff_bci_inv(dev_priv, dma_info); + waitchipidle_inv(dev_priv); + break; + /* Use DRM DMA buffer manager to kick off DMA directly */ + case dma_kickoff: + break; + + /* Copy user mode DMA buffer to kernel DMA buffer, + then kick off DMA */ + case flush_dma_buffer: + case flush_dma_and_wait: + if (dma_info->cmd_size <= 0) + return 0; + + getspace.dwRequestSize = dma_info->cmd_size; + if ((dev_priv->chip_sub_index == CHIP_H5) + && (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER)) + getspace.dwRequestSize += (NULLCOMMANDNUMBER + 4); + /*henry:Patch for VT3293 agp ring buffer stability */ + getspace.pCmdData = (unsigned int *) &pCmdData; + + if (dev_priv->drm_agp_type == DRM_AGP_DOUBLE_BUFFER) + get_space_db_inv(dev, &getspace); + else if (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER) + get_space_ring_inv(dev, &getspace); + + if (pCmdData) { + /*copy data from userspace to kernel-dma-agp buffer */ + result = copy_from_user((int *) + pCmdData, + dma_info->usermode_dma_buf, + dma_info->cmd_size << 2); + releasespace.dwReleaseSize = dma_info->cmd_size; + release_space_inv(dev, &releasespace); + + if (dev_priv->drm_agp_type == DRM_AGP_DOUBLE_BUFFER) + kickoff_dma_db_inv(dev); + else if (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER) + kickoff_dma_ring_inv(dev); + + if (dma_info->dma_cmd_type == flush_dma_and_wait) + waitchipidle_inv(dev_priv); + } else { + DRM_INFO("No enough DMA space"); + ret = -ENOMEM; + } + break; + + default: + DRM_INFO("Invalid DMA buffer type"); + ret = -EINVAL; + break; + } + return ret; +} + +int +via_chrome9_ioctl_free(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return 0; +} + +int +via_chrome9_ioctl_wait_chip_idle(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + + waitchipidle_inv(dev_priv); + /* maybe_bug here, do we always return 0 */ + return 0; +} + +int +via_chrome9_ioctl_flush_cache(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return 0; +} --- linux-2.6.27.orig/ubuntu/via_chrome9/via_chrome9_drv.c +++ linux-2.6.27/ubuntu/via_chrome9/via_chrome9_drv.c @@ -0,0 +1,160 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * (including the next paragraph) shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include "via_chrome9_drm.h" +#include "via_chrome9_drv.h" +#include "via_chrome9_dma.h" +#include "via_chrome9_mm.h" + +#include + +#define via_chrome9DRV_PCI_IDS \ + {0x1106, 0x3225, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_CHROME9_DX9_0}, \ + {0x1106, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1106, 0x1122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_CHROME9_PCIE_GROUP},\ + {0, 0, 0} + +static int dri_library_name(struct drm_device *dev, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "via_chrome9"); +} + +int via_chrome9_drm_authmagic(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return 0; +} + +struct drm_ioctl_desc via_chrome9_ioctls[] = { + DRM_IOCTL_DEF(DRM_VIA_CHROME9_INIT, via_chrome9_ioctl_init, + DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),/* via_chrome9_map.c*/ + DRM_IOCTL_DEF(DRM_VIA_CHROME9_FLUSH, via_chrome9_ioctl_flush, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_FREE, via_chrome9_ioctl_free, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_ALLOCATE_EVENT_TAG, + via_chrome9_ioctl_allocate_event_tag, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_FREE_EVENT_TAG, + via_chrome9_ioctl_free_event_tag, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_ALLOCATE_APERTURE, + via_chrome9_ioctl_allocate_aperture, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_FREE_APERTURE, + via_chrome9_ioctl_free_aperture, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_ALLOCATE_VIDEO_MEM, + via_chrome9_ioctl_allocate_mem_wrapper, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_FREE_VIDEO_MEM, + via_chrome9_ioctl_free_mem_wrapper, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_WAIT_CHIP_IDLE, + via_chrome9_ioctl_wait_chip_idle, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_PROCESS_EXIT, + via_chrome9_ioctl_process_exit, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_RESTORE_PRIMARY, + via_chrome9_ioctl_restore_primary, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_FLUSH_CACHE, + via_chrome9_ioctl_flush_cache, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_ALLOCMEM, + via_chrome9_ioctl_allocate_mem_base, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_FREEMEM, + via_chrome9_ioctl_freemem_base, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_CHECKVIDMEMSIZE, + via_chrome9_ioctl_check_vidmem_size, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_PCIEMEMCTRL, + via_chrome9_ioctl_pciemem_ctrl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CHROME9_AUTH_MAGIC, via_chrome9_drm_authmagic, 0) +}; + +int via_chrome9_max_ioctl = DRM_ARRAY_SIZE(via_chrome9_ioctls); + +static struct pci_device_id pciidlist[] = { + via_chrome9DRV_PCI_IDS +}; + +int via_chrome9_driver_open(struct drm_device *dev, + struct drm_file *priv) +{ + priv->authenticated = 1; + return 0; +} + +static struct drm_driver driver = { + .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | + DRIVER_HAVE_DMA | DRIVER_FB_DMA | DRIVER_USE_MTRR, + .open = via_chrome9_driver_open, + .load = via_chrome9_driver_load, + .unload = via_chrome9_driver_unload, + .device_is_agp = via_chrome9_is_agp, + .dri_library_name = dri_library_name, + .reclaim_buffers = drm_core_reclaim_buffers, + .reclaim_buffers_locked = NULL, + .reclaim_buffers_idlelocked = via_chrome9_reclaim_buffers_locked, + .lastclose = via_chrome9_lastclose, + .preclose = via_chrome9_preclose, + .get_map_ofs = drm_core_get_map_ofs, + .get_reg_ofs = drm_core_get_reg_ofs, + .ioctls = via_chrome9_ioctls, + .fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .ioctl = drm_ioctl, + .mmap = drm_mmap, + .poll = drm_poll, + .fasync = drm_fasync, + }, + .pci_driver = { + .name = DRIVER_NAME, + .id_table = pciidlist, + .resume = via_chrome9_drm_resume, + .suspend = via_chrome9_drm_suspend, + }, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, +}; + +static int __init via_chrome9_init(void) +{ + driver.num_ioctls = via_chrome9_max_ioctl; + driver.dev_priv_size = sizeof(struct drm_via_chrome9_private); + return drm_init(&driver); +} + +static void __exit via_chrome9_exit(void) +{ + drm_exit(&driver); +} + +module_init(via_chrome9_init); +module_exit(via_chrome9_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL and additional rights"); --- linux-2.6.27.orig/ubuntu/via_chrome9/via_chrome9_drm.c +++ linux-2.6.27/ubuntu/via_chrome9/via_chrome9_drm.c @@ -0,0 +1,993 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * (including the next paragraph) shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include +#include "via_chrome9_drm.h" +#include "via_chrome9_drv.h" +#include "via_chrome9_mm.h" +#include "via_chrome9_dma.h" +#include "via_chrome9_3d_reg.h" + +#define VIA_CHROME9DRM_VIDEO_STARTADDRESS_ALIGNMENT 10 + + +void __via_chrome9ke_udelay(unsigned long usecs) +{ + unsigned long start; + unsigned long stop; + unsigned long period; + unsigned long wait_period; + struct timespec tval; + +#ifdef NDELAY_LIMIT +#define UDELAY_LIMIT (NDELAY_LIMIT/1000) /* supposed to be 10 msec */ +#else +#define UDELAY_LIMIT (10000) /* 10 msec */ +#endif + + if (usecs > UDELAY_LIMIT) { + start = jiffies; + tval.tv_sec = usecs / 1000000; + tval.tv_nsec = (usecs - tval.tv_sec * 1000000) * 1000; + wait_period = timespec_to_jiffies(&tval); + do { + stop = jiffies; + + if (stop < start) + period = ((unsigned long)-1 - start) + stop + 1; + else + period = stop - start; + + } while (period < wait_period); + } else + udelay(usecs); /* delay value might get checked once again */ +} + +int via_chrome9_ioctl_process_exit(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return 0; +} + +int via_chrome9_ioctl_restore_primary(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + return 0; +} + +void Initialize3DEngine(struct drm_via_chrome9_private *dev_priv) +{ + int i; + unsigned int StageOfTexture; + + if (dev_priv->chip_sub_index == CHIP_H5 || + dev_priv->chip_sub_index == CHIP_H5S1) { + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + 0x00010000); + + for (i = 0; i <= 0x8A; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (unsigned int) i << 24); + } + + /* Initial Texture Stage Setting*/ + for (StageOfTexture = 0; StageOfTexture < 0xf; + StageOfTexture++) { + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00020000 | 0x00000000 | + (StageOfTexture & 0xf)<<24)); + /* *((unsigned int volatile*)(pMapIOPort+HC_REG_TRANS_SET)) = + (0x00020000 | HC_ParaSubType_Tex0 | (StageOfTexture & + 0xf)<<24);*/ + for (i = 0 ; i <= 0x30 ; i++) { + /* *((unsigned int volatile*)(pMapIOPort+ + HC_REG_Hpara0)) = ((unsigned int) i << 24);*/ + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (unsigned int) i << 24); + } + } + + /* Initial Texture Sampler Setting*/ + for (StageOfTexture = 0; StageOfTexture < 0xf; + StageOfTexture++) { + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00020000 | 0x00020000 | + (StageOfTexture & 0xf)<<24)); + /* *((unsigned int volatile*)(pMapIOPort+ + HC_REG_TRANS_SET)) = (0x00020000 | 0x00020000 | + ( StageOfTexture & 0xf)<<24);*/ + for (i = 0 ; i <= 0x30 ; i++) { + /* *((unsigned int volatile*)(pMapIOPort+ + HC_REG_Hpara0)) = ((unsigned int) i << 24);*/ + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (unsigned int) i << 24); + } + } + + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00020000 | 0xfe000000)); + /* *((unsigned int volatile*)(pMapIOPort+HC_REG_TRANS_SET)) = + (0x00020000 | HC_ParaSubType_TexGen);*/ + for (i = 0 ; i <= 0x13 ; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (unsigned int) i << 24); + /* *((unsigned int volatile*)(pMapIOPort+ + HC_REG_Hpara0)) = ((unsigned int) i << 24);*/ + } + + /* Initial Gamma Table Setting*/ + /* Initial Gamma Table Setting*/ + /* 5 + 4 = 9 (12) dwords*/ + /* sRGB texture is not directly support by H3 hardware. + We have to set the deGamma table for texture sampling.*/ + + /* degamma table*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x15000000)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (0x40000000 | (30 << 20) | (15 << 10) | (5))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((119 << 20) | (81 << 10) | (52))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((283 << 20) | (219 << 10) | (165))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((535 << 20) | (441 << 10) | (357))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((119 << 20) | (884 << 20) | (757 << 10) | + (640))); + + /* gamma table*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x17000000)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (0x40000000 | (13 << 20) | (13 << 10) | (13))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (0x40000000 | (26 << 20) | (26 << 10) | (26))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (0x40000000 | (39 << 20) | (39 << 10) | (39))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((51 << 20) | (51 << 10) | (51))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((71 << 20) | (71 << 10) | (71))); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (87 << 20) | (87 << 10) | (87)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (113 << 20) | (113 << 10) | (113)); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (135 << 20) | (135 << 10) | (135)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (170 << 20) | (170 << 10) | (170)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (199 << 20) | (199 << 10) | (199)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (246 << 20) | (246 << 10) | (246)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (284 << 20) | (284 << 10) | (284)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (317 << 20) | (317 << 10) | (317)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (347 << 20) | (347 << 10) | (347)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (373 << 20) | (373 << 10) | (373)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (398 << 20) | (398 << 10) | (398)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (442 << 20) | (442 << 10) | (442)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (481 << 20) | (481 << 10) | (481)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (517 << 20) | (517 << 10) | (517)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (550 << 20) | (550 << 10) | (550)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (609 << 20) | (609 << 10) | (609)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (662 << 20) | (662 << 10) | (662)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (709 << 20) | (709 << 10) | (709)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (753 << 20) | (753 << 10) | (753)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (794 << 20) | (794 << 10) | (794)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (832 << 20) | (832 << 10) | (832)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (868 << 20) | (868 << 10) | (868)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (902 << 20) | (902 << 10) | (902)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (934 << 20) | (934 << 10) | (934)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (966 << 20) | (966 << 10) | (966)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (996 << 20) | (996 << 10) | (996)); + + + /* + For Interrupt Restore only All types of write through + regsiters should be write header data to hardware at + least before it can restore. H/W will automatically + record the header to write through state buffer for + resture usage. + By Jaren: + HParaType = 8'h03, HParaSubType = 8'h00 + 8'h11 + 8'h12 + 8'h14 + 8'h15 + 8'h17 + HParaSubType 8'h12, 8'h15 is initialized. + [HWLimit] + 1. All these write through registers can't be partial + update. + 2. All these write through must be AGP command + 16 entries : 4 128-bit data */ + + /* Initialize INV_ParaSubType_TexPal */ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x00000000)); + for (i = 0; i < 16; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x00000000); + } + + /* Initialize INV_ParaSubType_4X4Cof */ + /* 32 entries : 8 128-bit data */ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x11000000)); + for (i = 0; i < 32; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x00000000); + } + + /* Initialize INV_ParaSubType_StipPal */ + /* 5 entries : 2 128-bit data */ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x14000000)); + for (i = 0; i < (5+3); i++) { + SetMMIORegister(dev_priv->mmio->handle, + 0x440, 0x00000000); + } + + /* primitive setting & vertex format*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00040000 | 0x14000000)); + for (i = 0; i < 52; i++) { + SetMMIORegister(dev_priv->mmio->handle, + 0x440, ((unsigned int) i << 24)); + } + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + 0x00fe0000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x4000840f); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x47000400); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x44000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x46000000); + + /* setting Misconfig*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + 0x00fe0000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x00001004); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0800004b); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0a000049); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0b0000fb); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0c000001); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0d0000cb); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0e000009); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x10000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x110000ff); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x12000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x130000db); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x14000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x15000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x16000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x17000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x18000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x19000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x20000000); + } else if (dev_priv->chip_sub_index == CHIP_H6S2) { + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + 0x00010000); + for (i = 0; i <= 0x9A; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (unsigned int) i << 24); + } + + /* Initial Texture Stage Setting*/ + for (StageOfTexture = 0; StageOfTexture <= 0xf; + StageOfTexture++) { + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00020000 | 0x00000000 | + (StageOfTexture & 0xf)<<24)); + /* *((unsigned int volatile*)(pMapIOPort+ + HC_REG_TRANS_SET)) = + (0x00020000 | HC_ParaSubType_Tex0 | + (StageOfTexture & 0xf)<<24);*/ + for (i = 0 ; i <= 0x30 ; i++) { + /* *((unsigned int volatile*)(pMapIOPort+ + HC_REG_Hpara0)) =((unsigned int) i << 24);*/ + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (unsigned int) i << 24); + } + } + + /* Initial Texture Sampler Setting*/ + for (StageOfTexture = 0; StageOfTexture <= 0xf; + StageOfTexture++) { + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00020000 | 0x20000000 | + (StageOfTexture & 0xf)<<24)); + /* *((unsigned int volatile*)(pMapIOPort+ + HC_REG_TRANS_SET)) =(0x00020000 | 0x00020000 | + ( StageOfTexture & 0xf)<<24);*/ + for (i = 0 ; i <= 0x36 ; i++) { + /* *((unsigned int volatile*)(pMapIOPort+ + HC_REG_Hpara0)) =((unsigned int) i << 24);*/ + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (unsigned int) i << 24); + } + } + + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00020000 | 0xfe000000)); + for (i = 0 ; i <= 0x13 ; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (unsigned int) i << 24); + /* *((unsigned int volatile*)(pMapIOPort+ + HC_REG_Hpara0)) =((unsigned int) i << 24);*/ + } + + /* Initial Gamma Table Setting*/ + /* Initial Gamma Table Setting*/ + /* 5 + 4 = 9 (12) dwords*/ + /* sRGB texture is not directly support by + H3 hardware.*/ + /* We have to set the deGamma table for texture + sampling.*/ + + /* degamma table*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x15000000)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (0x40000000 | (30 << 20) | (15 << 10) | (5))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((119 << 20) | (81 << 10) | (52))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((283 << 20) | (219 << 10) | (165))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((535 << 20) | (441 << 10) | (357))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((119 << 20) | (884 << 20) | (757 << 10) + | (640))); + + /* gamma table*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x17000000)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (0x40000000 | (13 << 20) | (13 << 10) | (13))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (0x40000000 | (26 << 20) | (26 << 10) | (26))); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (0x40000000 | (39 << 20) | (39 << 10) | (39))); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, ((51 << 20) | (51 << 10) | (51))); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, ((71 << 20) | (71 << 10) | (71))); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (87 << 20) | (87 << 10) | (87)); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (113 << 20) | (113 << 10) | (113)); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (135 << 20) | (135 << 10) | (135)); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (170 << 20) | (170 << 10) | (170)); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (199 << 20) | (199 << 10) | (199)); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (246 << 20) | (246 << 10) | (246)); + SetMMIORegister(dev_priv->mmio->handle, + 0x440, (284 << 20) | (284 << 10) | (284)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (317 << 20) | (317 << 10) | (317)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (347 << 20) | (347 << 10) | (347)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (373 << 20) | (373 << 10) | (373)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (398 << 20) | (398 << 10) | (398)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (442 << 20) | (442 << 10) | (442)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (481 << 20) | (481 << 10) | (481)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (517 << 20) | (517 << 10) | (517)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (550 << 20) | (550 << 10) | (550)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (609 << 20) | (609 << 10) | (609)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (662 << 20) | (662 << 10) | (662)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (709 << 20) | (709 << 10) | (709)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (753 << 20) | (753 << 10) | (753)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (794 << 20) | (794 << 10) | (794)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (832 << 20) | (832 << 10) | (832)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (868 << 20) | (868 << 10) | (868)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (902 << 20) | (902 << 10) | (902)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (934 << 20) | (934 << 10) | (934)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (966 << 20) | (966 << 10) | (966)); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + (996 << 20) | (996 << 10) | (996)); + + + /* For Interrupt Restore only + All types of write through regsiters should be write + header data to hardware at least before it can restore. + H/W will automatically record the header to write + through state buffer for restureusage. + By Jaren: + HParaType = 8'h03, HParaSubType = 8'h00 + 8'h11 + 8'h12 + 8'h14 + 8'h15 + 8'h17 + HParaSubType 8'h12, 8'h15 is initialized. + [HWLimit] + 1. All these write through registers can't be partial + update. + 2. All these write through must be AGP command + 16 entries : 4 128-bit data */ + + /* Initialize INV_ParaSubType_TexPal */ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x00000000)); + for (i = 0; i < 16; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x00000000); + } + + /* Initialize INV_ParaSubType_4X4Cof */ + /* 32 entries : 8 128-bit data */ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x11000000)); + for (i = 0; i < 32; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x00000000); + } + + /* Initialize INV_ParaSubType_StipPal */ + /* 5 entries : 2 128-bit data */ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00030000 | 0x14000000)); + for (i = 0; i < (5+3); i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x00000000); + } + + /* primitive setting & vertex format*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00040000)); + for (i = 0; i <= 0x62; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((unsigned int) i << 24)); + } + + /*ParaType 0xFE - Configure and Misc Setting*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00fe0000)); + for (i = 0; i <= 0x47; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((unsigned int) i << 24)); + } + /*ParaType 0x11 - Frame Buffer Auto-Swapping and + Command Regulator Misc*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + (0x00110000)); + for (i = 0; i <= 0x20; i++) { + SetMMIORegister(dev_priv->mmio->handle, 0x440, + ((unsigned int) i << 24)); + } + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + 0x00fe0000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x4000840f); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x47000404); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x44000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x46000005); + + /* setting Misconfig*/ + SetMMIORegister(dev_priv->mmio->handle, 0x43C, + 0x00fe0000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x00001004); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x08000249); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0a0002c9); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0b0002fb); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0c000000); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0d0002cb); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x0e000009); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x10000049); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x110002ff); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x12000008); + SetMMIORegister(dev_priv->mmio->handle, 0x440, + 0x130002db); + } +} + +int via_chrome9_drm_resume(struct pci_dev *pci) +{ + struct drm_device *dev = (struct drm_device *)pci_get_drvdata(pci); + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *)dev->dev_private; + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = + dev_priv->dma_manager; + + Initialize3DEngine(dev_priv); + + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, 0x00110000); + if (dev_priv->chip_sub_index == CHIP_H6S2) { + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + 0x06000000); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + 0x07100000); + } else{ + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + 0x02000000); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + 0x03100000); + } + + + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, + INV_ParaType_PreCR); + SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, + INV_SubA_HSetRBGID | INV_HSetRBGID_CR); + + if (dev_priv->chip_sub_index == CHIP_H6S2) { + unsigned int *pGARTTable; + unsigned int i, entries, GARTOffset; + unsigned char sr6a, sr6b, sr6c, sr6f, sr7b; + unsigned int *addrlinear; + unsigned int size, alignedoffset; + + entries = dev_priv->pagetable_map.pagetable_size / + sizeof(unsigned int); + pGARTTable = dev_priv->pagetable_map.pagetable_handle; + + GARTOffset = dev_priv->pagetable_map.pagetable_offset; + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c &= (~0x80); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + sr6a = (unsigned char)((GARTOffset & 0xff000) >> 12); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6a); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6a); + + sr6b = (unsigned char)((GARTOffset & 0xff00000) >> 20); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6b); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6b); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c |= ((unsigned char)((GARTOffset >> 28) & 0x01)); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x7b); + sr7b = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr7b &= (~0x0f); + sr7b |= ProtectSizeValue(dev_priv-> + pagetable_map.pagetable_size); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr7b); + + for (i = 0; i < entries; i++) + writel(0x80000000, pGARTTable+i); + + /*flush*/ + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6f); + do { + sr6f = GetMMIORegisterU8(dev_priv->mmio->handle, + 0x83c5); + } while (sr6f & 0x80); + + sr6f |= 0x80; + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6f); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c |= 0x80; + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + size = lpcmDMAManager->DMASize * sizeof(unsigned int) + + dev_priv->agp_size; + alignedoffset = 0; + entries = (size + PAGE_SIZE - 1) / PAGE_SIZE; + addrlinear = (unsigned int *)dev_priv->pcie_vmalloc_nocache; + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c &= (~0x80); + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6f); + do { + sr6f = GetMMIORegisterU8(dev_priv->mmio->handle, + 0x83c5); + } while (sr6f & 0x80); + + for (i = 0; i < entries; i++) + writel(page_to_pfn(vmalloc_to_page((void *)addrlinear + + PAGE_SIZE * i)) & 0x3fffffff, pGARTTable+ + i+alignedoffset); + + sr6f |= 0x80; + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6f); + + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); + sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); + sr6c |= 0x80; + SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); + + } + + if (dev_priv->drm_agp_type == DRM_AGP_DOUBLE_BUFFER) + SetAGPDoubleCmd_inv(dev); + else if (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER) + SetAGPRingCmdRegs_inv(dev); + return 0; +} + +int via_chrome9_drm_suspend(struct pci_dev *dev, + pm_message_t state) +{ + return 0; +} + +int via_chrome9_driver_load(struct drm_device *dev, + unsigned long chipset) +{ + struct drm_via_chrome9_private *dev_priv; + int ret = 0; + static int associate; + + if (!associate) { + pci_set_drvdata(dev->pdev, dev); + dev->pdev->driver = &dev->driver->pci_driver; + associate = 1; + } + + dev->counters += 4; + dev->types[6] = _DRM_STAT_IRQ; + dev->types[7] = _DRM_STAT_PRIMARY; + dev->types[8] = _DRM_STAT_SECONDARY; + dev->types[9] = _DRM_STAT_DMA; + + dev_priv = drm_calloc(1, sizeof(struct drm_via_chrome9_private), + DRM_MEM_DRIVER); + if (dev_priv == NULL) + return -ENOMEM; + + /* Clear */ + memset(dev_priv, 0, sizeof(struct drm_via_chrome9_private)); + + dev_priv->dev = dev; + dev->dev_private = (void *)dev_priv; + + dev_priv->chip_index = chipset; + + ret = drm_sman_init(&dev_priv->sman, 2, 12, 8); + if (ret) + drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + return ret; +} + +int via_chrome9_driver_unload(struct drm_device *dev) +{ + struct drm_via_chrome9_private *dev_priv = dev->dev_private; + + drm_sman_takedown(&dev_priv->sman); + + drm_free(dev_priv, sizeof(struct drm_via_chrome9_private), + DRM_MEM_DRIVER); + + return 0; +} + +static int via_chrome9_initialize(struct drm_device *dev, + struct drm_via_chrome9_init *init) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *)dev->dev_private; + + dev_priv->chip_agp = init->chip_agp; + dev_priv->chip_index = init->chip_index; + dev_priv->chip_sub_index = init->chip_sub_index; + + dev_priv->usec_timeout = init->usec_timeout; + dev_priv->front_offset = init->front_offset; + dev_priv->back_offset = init->back_offset >> + VIA_CHROME9DRM_VIDEO_STARTADDRESS_ALIGNMENT << + VIA_CHROME9DRM_VIDEO_STARTADDRESS_ALIGNMENT; + dev_priv->available_fb_size = init->available_fb_size - + (init->available_fb_size % + (1 << VIA_CHROME9DRM_VIDEO_STARTADDRESS_ALIGNMENT)); + dev_priv->depth_offset = init->depth_offset; + + /* Find all the map added first, doing this is necessary to + intialize hw */ + if (via_chrome9_map_init(dev, init)) { + DRM_ERROR("function via_chrome9_map_init ERROR !\n"); + goto error; + } + + /* Necessary information has been gathered for initialize hw */ + if (via_chrome9_hw_init(dev, init)) { + DRM_ERROR("function via_chrome9_hw_init ERROR !\n"); + goto error; + } + + /* After hw intialization, we have kown whether to use agp + or to use pcie for texture */ + if (via_chrome9_heap_management_init(dev, init)) { + DRM_ERROR("function \ + via_chrome9_heap_management_init ERROR !\n"); + goto error; + } + + return 0; + +error: + /* all the error recover has been processed in relevant function, + so here just return error */ + return -EINVAL; +} + +static void via_chrome9_cleanup(struct drm_device *dev, + struct drm_via_chrome9_init *init) +{ + struct drm_via_chrome9_DMA_manager *lpcmDMAManager = NULL; + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *)dev->dev_private; + DRM_DEBUG("function via_chrome9_cleanup run!\n"); + + if (!dev_priv) + return ; + + lpcmDMAManager = + (struct drm_via_chrome9_DMA_manager *)dev_priv->dma_manager; + if (dev_priv->pcie_vmalloc_nocache) { + vfree((void *)dev_priv->pcie_vmalloc_nocache); + dev_priv->pcie_vmalloc_nocache = 0; + if (lpcmDMAManager) + lpcmDMAManager->addr_linear = NULL; + } + + if (dev_priv->pagetable_map.pagetable_handle) { + iounmap(dev_priv->pagetable_map.pagetable_handle); + dev_priv->pagetable_map.pagetable_handle = NULL; + } + + if (lpcmDMAManager && lpcmDMAManager->addr_linear) { + iounmap(lpcmDMAManager->addr_linear); + lpcmDMAManager->addr_linear = NULL; + } + + kfree(lpcmDMAManager); + dev_priv->dma_manager = NULL; + + if (dev_priv->event_tag_info) { + vfree(dev_priv->event_tag_info); + dev_priv->event_tag_info = NULL; + } + + if (dev_priv->bci_buffer) { + vfree(dev_priv->bci_buffer); + dev_priv->bci_buffer = NULL; + } + + via_chrome9_memory_destroy_heap(dev, dev_priv); +} + +/* +Do almost everything intialize here,include: +1.intialize all addmaps in private data structure +2.intialize memory heap management for video agp/pcie +3.intialize hw for dma(pcie/agp) function + +Note:all this function will dispatch into relevant function +*/ +int via_chrome9_ioctl_init(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_via_chrome9_init *init = (struct drm_via_chrome9_init *)data; + + switch (init->func) { + case VIA_CHROME9_INIT: + if (via_chrome9_initialize(dev, init)) { + DRM_ERROR("function via_chrome9_initialize error\n"); + return -1; + } + break; + + case VIA_CHROME9_CLEANUP: + via_chrome9_cleanup(dev, init); + break; + + default: + return -1; + } + + return 0; +} + +int via_chrome9_ioctl_allocate_event_tag(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_via_chrome9_event_tag *event_tag = data; + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *)dev->dev_private; + struct drm_clb_event_tag_info *event_tag_info = + dev_priv->event_tag_info; + unsigned int *event_addr = 0, i = 0; + + for (i = 0; i < NUMBER_OF_EVENT_TAGS; i++) { + if (!event_tag_info->usage[i]) + break; + } + + if (i < NUMBER_OF_EVENT_TAGS) { + event_tag_info->usage[i] = 1; + event_tag->event_offset = i; + event_tag->last_sent_event_value.event_low = 0; + event_tag->current_event_value.event_low = 0; + event_addr = event_tag_info->linear_address + + event_tag->event_offset * 4; + *event_addr = 0; + return 0; + } else { + return -7; + } + + return 0; +} + +int via_chrome9_ioctl_free_event_tag(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *)dev->dev_private; + struct drm_clb_event_tag_info *event_tag_info = + dev_priv->event_tag_info; + struct drm_via_chrome9_event_tag *event_tag = data; + + event_tag_info->usage[event_tag->event_offset] = 0; + return 0; +} + +void via_chrome9_lastclose(struct drm_device *dev) +{ + via_chrome9_cleanup(dev, 0); + return ; +} + +static int via_chrome9_do_wait_vblank(struct drm_via_chrome9_private + *dev_priv) +{ + int i; + + for (i = 0; i < dev_priv->usec_timeout; i++) { + VIA_CHROME9_WRITE8(0x83d4, 0x34); + if ((VIA_CHROME9_READ8(0x83d5)) & 0x8) + return 0; + __via_chrome9ke_udelay(1); + } + + return (-1); +} + +void via_chrome9_preclose(struct drm_device *dev, struct drm_file *file_priv) +{ + struct drm_via_chrome9_private *dev_priv = + (struct drm_via_chrome9_private *) dev->dev_private; + struct drm_via_chrome9_sarea *sarea_priv = NULL; + + if (!dev_priv) + return ; + + sarea_priv = dev_priv->sarea_priv; + if (!sarea_priv) + return ; + + if ((sarea_priv->page_flip == 1) && + (sarea_priv->current_page != VIA_CHROME9_FRONT)) { + volatile unsigned long *bci_base; + if (via_chrome9_do_wait_vblank(dev_priv)) + return; + + bci_base = (volatile unsigned long *)(dev_priv->bci); + + BCI_SET_STREAM_REGISTER(bci_base, 0x81c4, 0xc0000000); + BCI_SET_STREAM_REGISTER(bci_base, 0x81c0, + dev_priv->front_offset); + BCI_SEND(bci_base, 0x64000000);/* wait vsync */ + + sarea_priv->current_page = VIA_CHROME9_FRONT; + } +} + +int via_chrome9_is_agp(struct drm_device *dev) +{ + /* filter out pcie group which has no AGP device */ + if (dev->pci_device == 0x1122) { + dev->driver->driver_features &= + ~(DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_REQUIRE_AGP); + return 0; + } + return 1; +} + --- linux-2.6.27.orig/ubuntu/via_chrome9/via_chrome9_mm.h +++ linux-2.6.27/ubuntu/via_chrome9/via_chrome9_mm.h @@ -0,0 +1,67 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * (including the next paragraph) shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _VIA_CHROME9_MM_H_ +#define _VIA_CHROME9_MM_H_ +struct drm_via_chrome9_pciemem_ctrl { + enum { + pciemem_copy_from_user = 0, + pciemem_copy_to_user, + pciemem_memset, + } ctrl_type; + unsigned int pcieoffset; + unsigned int size;/*in Byte*/ + unsigned char memsetdata;/*for memset*/ + void *usermode_data;/*user mode data pointer*/ +}; + +extern int via_chrome9_map_init(struct drm_device *dev, + struct drm_via_chrome9_init *init); +extern int via_chrome9_heap_management_init(struct drm_device + *dev, struct drm_via_chrome9_init *init); +extern void via_chrome9_memory_destroy_heap(struct drm_device + *dev, struct drm_via_chrome9_private *dev_priv); +extern int via_chrome9_ioctl_check_vidmem_size(struct drm_device + *dev, void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_pciemem_ctrl(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_allocate_aperture(struct drm_device + *dev, void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_free_aperture(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_allocate_mem_base(struct drm_device + *dev, void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_allocate_mem_wrapper( + struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_freemem_base(struct drm_device + *dev, void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_free_mem_wrapper(struct drm_device + *dev, void *data, struct drm_file *file_priv); +extern void via_chrome9_reclaim_buffers_locked(struct drm_device + *dev, struct drm_file *file_priv); + +#endif + --- linux-2.6.27.orig/ubuntu/via_chrome9/via_chrome9_dma.h +++ linux-2.6.27/ubuntu/via_chrome9/via_chrome9_dma.h @@ -0,0 +1,68 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * (including the next paragraph) shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _VIA_CHROME9_DMA_H_ +#define _VIA_CHROME9_DMA_H_ + +#define MAX_BCI_BUFFER_SIZE 16*1024*1024 + +enum cmd_request_type { + CM_REQUEST_BCI, + CM_REQUEST_DMA, + CM_REQUEST_RB, + CM_REQUEST_RB_FORCED_DMA, + CM_REQUEST_NOTAVAILABLE +}; + +struct cmd_get_space { + unsigned int dwRequestSize; + enum cmd_request_type hint; + volatile unsigned int *pCmdData; +}; + +struct cmd_release_space { + unsigned int dwReleaseSize; +}; + +extern int via_chrome9_hw_init(struct drm_device *dev, + struct drm_via_chrome9_init *init); +extern int via_chrome9_ioctl_flush(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int via_chrome9_ioctl_free(struct drm_device *dev, void *data, + struct drm_file *file_prev); +extern int via_chrome9_ioctl_wait_chip_idle(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_flush_cache(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int via_chrome9_ioctl_flush(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int via_chrome9_ioctl_free(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern unsigned int ProtectSizeValue(unsigned int size); +extern void SetAGPDoubleCmd_inv(struct drm_device *dev); +extern void SetAGPRingCmdRegs_inv(struct drm_device *dev); + +#endif --- linux-2.6.27.orig/ubuntu/e1000e/kcompat.c +++ linux-2.6.27/ubuntu/e1000e/kcompat.c @@ -0,0 +1,318 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + + + +#ifdef DRIVER_E1000E +#include "e1000.h" +#endif + + + + +#include "kcompat.h" + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13) ) + +/**************************************/ +/* PCI DMA MAPPING */ + +#if defined(CONFIG_HIGHMEM) + +#ifndef PCI_DRAM_OFFSET +#define PCI_DRAM_OFFSET 0 +#endif + +u64 +_kc_pci_map_page(struct pci_dev *dev, struct page *page, unsigned long offset, + size_t size, int direction) +{ + return (((u64) (page - mem_map) << PAGE_SHIFT) + offset + + PCI_DRAM_OFFSET); +} + +#else /* CONFIG_HIGHMEM */ + +u64 +_kc_pci_map_page(struct pci_dev *dev, struct page *page, unsigned long offset, + size_t size, int direction) +{ + return pci_map_single(dev, (void *)page_address(page) + offset, size, + direction); +} + +#endif /* CONFIG_HIGHMEM */ + +void +_kc_pci_unmap_page(struct pci_dev *dev, u64 dma_addr, size_t size, + int direction) +{ + return pci_unmap_single(dev, dma_addr, size, direction); +} + +#endif /* 2.4.13 => 2.4.3 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) ) + +/**************************************/ +/* PCI DRIVER API */ + +int +_kc_pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask) +{ + if (!pci_dma_supported(dev, mask)) + return -EIO; + dev->dma_mask = mask; + return 0; +} + +int +_kc_pci_request_regions(struct pci_dev *dev, char *res_name) +{ + int i; + + for (i = 0; i < 6; i++) { + if (pci_resource_len(dev, i) == 0) + continue; + + if (pci_resource_flags(dev, i) & IORESOURCE_IO) { + if (!request_region(pci_resource_start(dev, i), pci_resource_len(dev, i), res_name)) { + pci_release_regions(dev); + return -EBUSY; + } + } else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) { + if (!request_mem_region(pci_resource_start(dev, i), pci_resource_len(dev, i), res_name)) { + pci_release_regions(dev); + return -EBUSY; + } + } + } + return 0; +} + +void +_kc_pci_release_regions(struct pci_dev *dev) +{ + int i; + + for (i = 0; i < 6; i++) { + if (pci_resource_len(dev, i) == 0) + continue; + + if (pci_resource_flags(dev, i) & IORESOURCE_IO) + release_region(pci_resource_start(dev, i), pci_resource_len(dev, i)); + + else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) + release_mem_region(pci_resource_start(dev, i), pci_resource_len(dev, i)); + } +} + +/**************************************/ +/* NETWORK DRIVER API */ + +struct net_device * +_kc_alloc_etherdev(int sizeof_priv) +{ + struct net_device *dev; + int alloc_size; + + alloc_size = sizeof(*dev) + sizeof_priv + IFNAMSIZ + 31; + dev = kmalloc(alloc_size, GFP_KERNEL); + if (!dev) + return NULL; + memset(dev, 0, alloc_size); + + if (sizeof_priv) + dev->priv = (void *) (((unsigned long)(dev + 1) + 31) & ~31); + dev->name[0] = '\0'; + ether_setup(dev); + + return dev; +} + +int +_kc_is_valid_ether_addr(u8 *addr) +{ + const char zaddr[6] = { 0, }; + + return !(addr[0] & 1) && memcmp(addr, zaddr, 6); +} + +#endif /* 2.4.3 => 2.4.0 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,6) ) + +int +_kc_pci_set_power_state(struct pci_dev *dev, int state) +{ + return 0; +} + +int +_kc_pci_save_state(struct pci_dev *dev, u32 *buffer) +{ + return 0; +} + +int +_kc_pci_restore_state(struct pci_dev *pdev, u32 *buffer) +{ + return 0; +} + +int +_kc_pci_enable_wake(struct pci_dev *pdev, u32 state, int enable) +{ + return 0; +} + +#endif /* 2.4.6 => 2.4.3 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ) +void _kc_skb_fill_page_desc(struct sk_buff *skb, int i, struct page *page, + int off, int size) +{ + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + frag->page = page; + frag->page_offset = off; + frag->size = size; + skb_shinfo(skb)->nr_frags = i + 1; +} + +/* + * Original Copyright: + * find_next_bit.c: fallback find next bit implementation + * + * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +/** + * find_next_bit - find the next set bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ +unsigned long find_next_bit(const unsigned long *addr, unsigned long size, + unsigned long offset) +{ + const unsigned long *p = addr + BITOP_WORD(offset); + unsigned long result = offset & ~(BITS_PER_LONG-1); + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset %= BITS_PER_LONG; + if (offset) { + tmp = *(p++); + tmp &= (~0UL << offset); + if (size < BITS_PER_LONG) + goto found_first; + if (tmp) + goto found_middle; + size -= BITS_PER_LONG; + result += BITS_PER_LONG; + } + while (size & ~(BITS_PER_LONG-1)) { + if ((tmp = *(p++))) + goto found_middle; + result += BITS_PER_LONG; + size -= BITS_PER_LONG; + } + if (!size) + return result; + tmp = *p; + +found_first: + tmp &= (~0UL >> (BITS_PER_LONG - size)); + if (tmp == 0UL) /* Are any bits set? */ + return result + size; /* Nope. */ +found_middle: + return result + ffs(tmp); +} + +#endif /* 2.6.0 => 2.4.6 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) ) +void *_kc_kzalloc(size_t size, int flags) +{ + void *ret = kmalloc(size, flags); + if (ret) + memset(ret, 0, size); + return ret; +} +#endif /* <= 2.6.13 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ) +struct sk_buff *_kc_netdev_alloc_skb(struct net_device *dev, + unsigned int length) +{ + /* 16 == NET_PAD_SKB */ + struct sk_buff *skb; + skb = alloc_skb(length + 16, GFP_ATOMIC); + if (likely(skb != NULL)) { + skb_reserve(skb, 16); + skb->dev = dev; + } + return skb; +} +#endif /* <= 2.6.17 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) ) +#endif /* < 2.6.23 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ) +#ifdef NAPI +int __kc_adapter_clean(struct net_device *netdev, int *budget) +{ + int work_done; + int work_to_do = min(*budget, netdev->quota); + struct adapter_struct *adapter = netdev_priv(netdev); +#ifdef DRIVER_E1000E + struct napi_struct *napi = &adapter->napi; +#else + struct napi_struct *napi = &adapter->rx_ring[0].napi; +#endif + + work_done = napi->poll(napi, work_to_do); + *budget -= work_done; + netdev->quota -= work_done; + return work_done ? 1 : 0; +} +#endif /* NAPI */ +#endif /* <= 2.6.24 */ + --- linux-2.6.27.orig/ubuntu/e1000e/e1000_82571.c +++ linux-2.6.27/ubuntu/e1000e/e1000_82571.c @@ -0,0 +1,1538 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* e1000_82571 + * e1000_82572 + * e1000_82573 + * e1000_82574 + */ + +#include "e1000_hw.h" + +static s32 e1000_init_phy_params_82571(struct e1000_hw *hw); +static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw); +static s32 e1000_init_mac_params_82571(struct e1000_hw *hw); +static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw); +static void e1000_release_nvm_82571(struct e1000_hw *hw); +static s32 e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data); +static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw); +static s32 e1000_validate_nvm_checksum_82571(struct e1000_hw *hw); +static s32 e1000_get_cfg_done_82571(struct e1000_hw *hw); +static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, + bool active); +static s32 e1000_reset_hw_82571(struct e1000_hw *hw); +static s32 e1000_init_hw_82571(struct e1000_hw *hw); +static void e1000_clear_vfta_82571(struct e1000_hw *hw); +static bool e1000_check_mng_mode_82574(struct e1000_hw *hw); +static s32 e1000_led_on_82574(struct e1000_hw *hw); +static void e1000_update_mc_addr_list_82571(struct e1000_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count, + u32 rar_used_count, u32 rar_count); +static s32 e1000_setup_link_82571(struct e1000_hw *hw); +static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw); +static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw); +static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data); +static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw); +static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw); +static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw); +static s32 e1000_get_phy_id_82571(struct e1000_hw *hw); +static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw); +static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw); +static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data); +static s32 e1000_read_mac_addr_82571(struct e1000_hw *hw); +static void e1000_power_down_phy_copper_82571(struct e1000_hw *hw); + +struct e1000_dev_spec_82571 { + bool laa_is_present; +}; + +/** + * e1000_init_phy_params_82571 - Init PHY func ptrs. + * @hw: pointer to the HW structure + * + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_init_phy_params_82571"); + + if (hw->phy.media_type != e1000_media_type_copper) { + phy->type = e1000_phy_none; + goto out; + } + + phy->addr = 1; + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; + phy->reset_delay_us = 100; + + phy->ops.acquire = e1000_get_hw_semaphore_82571; + phy->ops.check_polarity = e1000_check_polarity_igp; + phy->ops.check_reset_block = e1000_check_reset_block_generic; + phy->ops.release = e1000_put_hw_semaphore_82571; + phy->ops.reset = e1000_phy_hw_reset_generic; + phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_82571; + phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_generic; + phy->ops.power_up = e1000_power_up_phy_copper; + phy->ops.power_down = e1000_power_down_phy_copper_82571; + + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + phy->type = e1000_phy_igp_2; + phy->ops.get_cfg_done = e1000_get_cfg_done_82571; + phy->ops.get_info = e1000_get_phy_info_igp; + phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp; + phy->ops.get_cable_length = e1000_get_cable_length_igp_2; + phy->ops.read_reg = e1000_read_phy_reg_igp; + phy->ops.write_reg = e1000_write_phy_reg_igp; + + /* This uses above function pointers */ + ret_val = e1000_get_phy_id_82571(hw); + + /* Verify PHY ID */ + if (phy->id != IGP01E1000_I_PHY_ID) { + ret_val = -E1000_ERR_PHY; + goto out; + } + break; + case e1000_82573: + phy->type = e1000_phy_m88; + phy->ops.get_cfg_done = e1000_get_cfg_done_generic; + phy->ops.get_info = e1000_get_phy_info_m88; + phy->ops.commit = e1000_phy_sw_reset_generic; + phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88; + phy->ops.get_cable_length = e1000_get_cable_length_m88; + phy->ops.read_reg = e1000_read_phy_reg_m88; + phy->ops.write_reg = e1000_write_phy_reg_m88; + + /* This uses above function pointers */ + ret_val = e1000_get_phy_id_82571(hw); + + /* Verify PHY ID */ + if (phy->id != M88E1111_I_PHY_ID) { + ret_val = -E1000_ERR_PHY; + DEBUGOUT1("PHY ID unknown: type = 0x%08x\n", phy->id); + goto out; + } + break; + case e1000_82574: + phy->type = e1000_phy_bm; + phy->ops.get_cfg_done = e1000_get_cfg_done_generic; + phy->ops.get_info = e1000_get_phy_info_m88; + phy->ops.commit = e1000_phy_sw_reset_generic; + phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88; + phy->ops.get_cable_length = e1000_get_cable_length_m88; + phy->ops.read_reg = e1000_read_phy_reg_bm2; + phy->ops.write_reg = e1000_write_phy_reg_bm2; + + /* This uses above function pointers */ + ret_val = e1000_get_phy_id_82571(hw); + /* Verify PHY ID */ + if (phy->id != BME1000_E_PHY_ID_R2) { + ret_val = -E1000_ERR_PHY; + DEBUGOUT1("PHY ID unknown: type = 0x%08x\n", phy->id); + goto out; + } + break; + default: + ret_val = -E1000_ERR_PHY; + goto out; + break; + } + +out: + return ret_val; +} + +/** + * e1000_init_nvm_params_82571 - Init NVM func ptrs. + * @hw: pointer to the HW structure + * + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 eecd = E1000_READ_REG(hw, E1000_EECD); + u16 size; + + DEBUGFUNC("e1000_init_nvm_params_82571"); + + nvm->opcode_bits = 8; + nvm->delay_usec = 1; + switch (nvm->override) { + case e1000_nvm_override_spi_large: + nvm->page_size = 32; + nvm->address_bits = 16; + break; + case e1000_nvm_override_spi_small: + nvm->page_size = 8; + nvm->address_bits = 8; + break; + default: + nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8; + nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8; + break; + } + + switch (hw->mac.type) { + case e1000_82573: + case e1000_82574: + if (((eecd >> 15) & 0x3) == 0x3) { + nvm->type = e1000_nvm_flash_hw; + nvm->word_size = 2048; + /* + * Autonomous Flash update bit must be cleared due + * to Flash update issue. + */ + eecd &= ~E1000_EECD_AUPDEN; + E1000_WRITE_REG(hw, E1000_EECD, eecd); + break; + } + /* Fall Through */ + default: + nvm->type = e1000_nvm_eeprom_spi; + size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >> + E1000_EECD_SIZE_EX_SHIFT); + /* + * Added to a constant, "size" becomes the left-shift value + * for setting word_size. + */ + size += NVM_WORD_SIZE_BASE_SHIFT; + + /* EEPROM access above 16k is unsupported */ + if (size > 14) + size = 14; + nvm->word_size = 1 << size; + break; + } + + /* Function Pointers */ + nvm->ops.acquire = e1000_acquire_nvm_82571; + nvm->ops.read = e1000_read_nvm_eerd; + nvm->ops.release = e1000_release_nvm_82571; + nvm->ops.update = e1000_update_nvm_checksum_82571; + nvm->ops.validate = e1000_validate_nvm_checksum_82571; + nvm->ops.valid_led_default = e1000_valid_led_default_82571; + nvm->ops.write = e1000_write_nvm_82571; + + return E1000_SUCCESS; +} + +/** + * e1000_init_mac_params_82571 - Init MAC func ptrs. + * @hw: pointer to the HW structure + * + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_mac_params_82571(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_init_mac_params_82571"); + + /* Set media type */ + switch (hw->device_id) { + case E1000_DEV_ID_82571EB_FIBER: + case E1000_DEV_ID_82572EI_FIBER: + case E1000_DEV_ID_82571EB_QUAD_FIBER: + hw->phy.media_type = e1000_media_type_fiber; + break; + case E1000_DEV_ID_82571EB_SERDES: + case E1000_DEV_ID_82571EB_SERDES_DUAL: + case E1000_DEV_ID_82571EB_SERDES_QUAD: + case E1000_DEV_ID_82572EI_SERDES: + hw->phy.media_type = e1000_media_type_internal_serdes; + break; + default: + hw->phy.media_type = e1000_media_type_copper; + break; + } + + /* Set mta register count */ + mac->mta_reg_count = 128; + /* Set rar entry count */ + mac->rar_entry_count = E1000_RAR_ENTRIES; + /* Set if part includes ASF firmware */ + mac->asf_firmware_present = true; + /* Set if manageability features are enabled. */ + mac->arc_subsystem_valid = + (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK) + ? true : false; + + /* Function pointers */ + + /* bus type/speed/width */ + mac->ops.get_bus_info = e1000_get_bus_info_pcie_generic; + /* reset */ + mac->ops.reset_hw = e1000_reset_hw_82571; + /* hw initialization */ + mac->ops.init_hw = e1000_init_hw_82571; + /* link setup */ + mac->ops.setup_link = e1000_setup_link_82571; + /* physical interface link setup */ + mac->ops.setup_physical_interface = + (hw->phy.media_type == e1000_media_type_copper) + ? e1000_setup_copper_link_82571 + : e1000_setup_fiber_serdes_link_82571; + /* check for link */ + switch (hw->phy.media_type) { + case e1000_media_type_copper: + mac->ops.check_for_link = e1000_check_for_copper_link_generic; + break; + case e1000_media_type_fiber: + mac->ops.check_for_link = e1000_check_for_fiber_link_generic; + break; + case e1000_media_type_internal_serdes: + mac->ops.check_for_link = e1000_check_for_serdes_link_generic; + break; + default: + ret_val = -E1000_ERR_CONFIG; + goto out; + break; + } + /* check management mode */ + switch (hw->mac.type) { + case e1000_82574: + mac->ops.check_mng_mode = e1000_check_mng_mode_82574; + break; + default: + mac->ops.check_mng_mode = e1000_check_mng_mode_generic; + break; + } + /* multicast address update */ + mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_82571; + /* writing VFTA */ + mac->ops.write_vfta = e1000_write_vfta_generic; + /* clearing VFTA */ + mac->ops.clear_vfta = e1000_clear_vfta_82571; + /* setting MTA */ + mac->ops.mta_set = e1000_mta_set_generic; + /* read mac address */ + mac->ops.read_mac_addr = e1000_read_mac_addr_82571; + /* blink LED */ + mac->ops.blink_led = e1000_blink_led_generic; + /* setup LED */ + mac->ops.setup_led = e1000_setup_led_generic; + /* cleanup LED */ + mac->ops.cleanup_led = e1000_cleanup_led_generic; + /* turn on/off LED */ + switch (hw->mac.type) { + case e1000_82574: + mac->ops.led_on = e1000_led_on_82574; + break; + default: + mac->ops.led_on = e1000_led_on_generic; + break; + } + mac->ops.led_off = e1000_led_off_generic; + /* remove device */ + mac->ops.remove_device = e1000_remove_device_generic; + /* clear hardware counters */ + mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82571; + /* link info */ + mac->ops.get_link_up_info = + (hw->phy.media_type == e1000_media_type_copper) + ? e1000_get_speed_and_duplex_copper_generic + : e1000_get_speed_and_duplex_fiber_serdes_generic; + + hw->dev_spec_size = sizeof(struct e1000_dev_spec_82571); + + /* Device-specific structure allocation */ + ret_val = e1000_alloc_zeroed_dev_spec_struct(hw, hw->dev_spec_size); + +out: + return ret_val; +} + +/** + * e1000_init_function_pointers_82571 - Init func ptrs. + * @hw: pointer to the HW structure + * + * The only function explicitly called by the api module to initialize + * all function pointers and parameters. + **/ +void e1000_init_function_pointers_82571(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_init_function_pointers_82571"); + + e1000_init_mac_ops_generic(hw); + e1000_init_nvm_ops_generic(hw); + hw->mac.ops.init_params = e1000_init_mac_params_82571; + hw->nvm.ops.init_params = e1000_init_nvm_params_82571; + hw->phy.ops.init_params = e1000_init_phy_params_82571; +} + +/** + * e1000_get_phy_id_82571 - Retrieve the PHY ID and revision + * @hw: pointer to the HW structure + * + * Reads the PHY registers and stores the PHY ID and possibly the PHY + * revision in the hardware structure. + **/ +static s32 e1000_get_phy_id_82571(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = E1000_SUCCESS; + u16 phy_id = 0; + + DEBUGFUNC("e1000_get_phy_id_82571"); + + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + /* + * The 82571 firmware may still be configuring the PHY. + * In this case, we cannot access the PHY until the + * configuration is done. So we explicitly set the + * PHY ID. + */ + phy->id = IGP01E1000_I_PHY_ID; + break; + case e1000_82573: + ret_val = e1000_get_phy_id(hw); + break; + case e1000_82574: + ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id); + if (ret_val) + goto out; + + phy->id = (u32)(phy_id << 16); + usec_delay(20); + ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id); + if (ret_val) + goto out; + + phy->id |= (u32)(phy_id); + phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); + break; + default: + ret_val = -E1000_ERR_PHY; + break; + } + +out: + return ret_val; +} + +/** + * e1000_get_hw_semaphore_82571 - Acquire hardware semaphore + * @hw: pointer to the HW structure + * + * Acquire the HW semaphore to access the PHY or NVM + **/ +static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) +{ + u32 swsm; + s32 ret_val = E1000_SUCCESS; + s32 timeout = hw->nvm.word_size + 1; + s32 i = 0; + + DEBUGFUNC("e1000_get_hw_semaphore_82571"); + + /* Get the FW semaphore. */ + for (i = 0; i < timeout; i++) { + swsm = E1000_READ_REG(hw, E1000_SWSM); + E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI); + + /* Semaphore acquired if bit latched */ + if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI) + break; + + usec_delay(50); + } + + if (i == timeout) { + /* Release semaphores */ + e1000_put_hw_semaphore_generic(hw); + DEBUGOUT("Driver can't access the NVM\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_put_hw_semaphore_82571 - Release hardware semaphore + * @hw: pointer to the HW structure + * + * Release hardware semaphore used to access the PHY or NVM + **/ +static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw) +{ + u32 swsm; + + DEBUGFUNC("e1000_put_hw_semaphore_82571"); + + swsm = E1000_READ_REG(hw, E1000_SWSM); + + swsm &= ~E1000_SWSM_SWESMBI; + + E1000_WRITE_REG(hw, E1000_SWSM, swsm); +} + +/** + * e1000_acquire_nvm_82571 - Request for access to the EEPROM + * @hw: pointer to the HW structure + * + * To gain access to the EEPROM, first we must obtain a hardware semaphore. + * Then for non-82573 hardware, set the EEPROM access request bit and wait + * for EEPROM access grant bit. If the access grant bit is not set, release + * hardware semaphore. + **/ +static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw) +{ + s32 ret_val; + + DEBUGFUNC("e1000_acquire_nvm_82571"); + + ret_val = e1000_get_hw_semaphore_82571(hw); + if (ret_val) + goto out; + + if (hw->mac.type != e1000_82573 && hw->mac.type != e1000_82574) + ret_val = e1000_acquire_nvm_generic(hw); + + if (ret_val) + e1000_put_hw_semaphore_82571(hw); + +out: + return ret_val; +} + +/** + * e1000_release_nvm_82571 - Release exclusive access to EEPROM + * @hw: pointer to the HW structure + * + * Stop any current commands to the EEPROM and clear the EEPROM request bit. + **/ +static void e1000_release_nvm_82571(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_release_nvm_82571"); + + e1000_release_nvm_generic(hw); + e1000_put_hw_semaphore_82571(hw); +} + +/** + * e1000_write_nvm_82571 - Write to EEPROM using appropriate interface + * @hw: pointer to the HW structure + * @offset: offset within the EEPROM to be written to + * @words: number of words to write + * @data: 16 bit word(s) to be written to the EEPROM + * + * For non-82573 silicon, write data to EEPROM at offset using SPI interface. + * + * If e1000_update_nvm_checksum is not called after this function, the + * EEPROM will most likely contain an invalid checksum. + **/ +static s32 e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_write_nvm_82571"); + + switch (hw->mac.type) { + case e1000_82573: + case e1000_82574: + ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data); + break; + case e1000_82571: + case e1000_82572: + ret_val = e1000_write_nvm_spi(hw, offset, words, data); + break; + default: + ret_val = -E1000_ERR_NVM; + break; + } + + return ret_val; +} + +/** + * e1000_update_nvm_checksum_82571 - Update EEPROM checksum + * @hw: pointer to the HW structure + * + * Updates the EEPROM checksum by reading/adding each word of the EEPROM + * up to the checksum. Then calculates the EEPROM checksum and writes the + * value to the EEPROM. + **/ +static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw) +{ + u32 eecd; + s32 ret_val; + u16 i; + + DEBUGFUNC("e1000_update_nvm_checksum_82571"); + + ret_val = e1000_update_nvm_checksum_generic(hw); + if (ret_val) + goto out; + + /* + * If our nvm is an EEPROM, then we're done + * otherwise, commit the checksum to the flash NVM. + */ + if (hw->nvm.type != e1000_nvm_flash_hw) + goto out; + + /* Check for pending operations. */ + for (i = 0; i < E1000_FLASH_UPDATES; i++) { + msec_delay(1); + if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_FLUPD) == 0) + break; + } + + if (i == E1000_FLASH_UPDATES) { + ret_val = -E1000_ERR_NVM; + goto out; + } + + /* Reset the firmware if using STM opcode. */ + if ((E1000_READ_REG(hw, E1000_FLOP) & 0xFF00) == E1000_STM_OPCODE) { + /* + * The enabling of and the actual reset must be done + * in two write cycles. + */ + E1000_WRITE_REG(hw, E1000_HICR, E1000_HICR_FW_RESET_ENABLE); + E1000_WRITE_FLUSH(hw); + E1000_WRITE_REG(hw, E1000_HICR, E1000_HICR_FW_RESET); + } + + /* Commit the write to flash */ + eecd = E1000_READ_REG(hw, E1000_EECD) | E1000_EECD_FLUPD; + E1000_WRITE_REG(hw, E1000_EECD, eecd); + + for (i = 0; i < E1000_FLASH_UPDATES; i++) { + msec_delay(1); + if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_FLUPD) == 0) + break; + } + + if (i == E1000_FLASH_UPDATES) { + ret_val = -E1000_ERR_NVM; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_validate_nvm_checksum_82571 - Validate EEPROM checksum + * @hw: pointer to the HW structure + * + * Calculates the EEPROM checksum by reading/adding each word of the EEPROM + * and then verifies that the sum of the EEPROM is equal to 0xBABA. + **/ +static s32 e1000_validate_nvm_checksum_82571(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_validate_nvm_checksum_82571"); + + if (hw->nvm.type == e1000_nvm_flash_hw) + e1000_fix_nvm_checksum_82571(hw); + + return e1000_validate_nvm_checksum_generic(hw); +} + +/** + * e1000_write_nvm_eewr_82571 - Write to EEPROM for 82573 silicon + * @hw: pointer to the HW structure + * @offset: offset within the EEPROM to be written to + * @words: number of words to write + * @data: 16 bit word(s) to be written to the EEPROM + * + * After checking for invalid values, poll the EEPROM to ensure the previous + * command has completed before trying to write the next word. After write + * poll for completion. + * + * If e1000_update_nvm_checksum is not called after this function, the + * EEPROM will most likely contain an invalid checksum. + **/ +static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 i, eewr = 0; + s32 ret_val = 0; + + DEBUGFUNC("e1000_write_nvm_eewr_82571"); + + /* + * A check for invalid values: offset too large, too many words, + * and not enough words. + */ + if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || + (words == 0)) { + DEBUGOUT("nvm parameter(s) out of bounds\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + + for (i = 0; i < words; i++) { + eewr = (data[i] << E1000_NVM_RW_REG_DATA) | + ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) | + E1000_NVM_RW_REG_START; + + ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE); + if (ret_val) + break; + + E1000_WRITE_REG(hw, E1000_EEWR, eewr); + + ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE); + if (ret_val) + break; + } + +out: + return ret_val; +} + +/** + * e1000_get_cfg_done_82571 - Poll for configuration done + * @hw: pointer to the HW structure + * + * Reads the management control register for the config done bit to be set. + **/ +static s32 e1000_get_cfg_done_82571(struct e1000_hw *hw) +{ + s32 timeout = PHY_CFG_TIMEOUT; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_get_cfg_done_82571"); + + while (timeout) { + if (E1000_READ_REG(hw, E1000_EEMNGCTL) & E1000_NVM_CFG_DONE_PORT_0) + break; + msec_delay(1); + timeout--; + } + if (!timeout) { + DEBUGOUT("MNG configuration cycle has not completed.\n"); + ret_val = -E1000_ERR_RESET; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_set_d0_lplu_state_82571 - Set Low Power Linkup D0 state + * @hw: pointer to the HW structure + * @active: true to enable LPLU, false to disable + * + * Sets the LPLU D0 state according to the active flag. When activating LPLU + * this function also disables smart speed and vice versa. LPLU will not be + * activated unless the device autonegotiation advertisement meets standards + * of either 10 or 10/100 or 10/100/1000 at all duplexes. This is a function + * pointer entry point only called by PHY setup routines. + **/ +static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = E1000_SUCCESS; + u16 data; + + DEBUGFUNC("e1000_set_d0_lplu_state_82571"); + + if (!(phy->ops.read_reg)) + goto out; + + ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data); + if (ret_val) + goto out; + + if (active) { + data |= IGP02E1000_PM_D0_LPLU; + ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT, + data); + if (ret_val) + goto out; + + /* When LPLU is enabled, we should disable SmartSpeed */ + ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + &data); + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + goto out; + } else { + data &= ~IGP02E1000_PM_D0_LPLU; + ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT, + data); + /* + * LPLU and SmartSpeed are mutually exclusive. LPLU is used + * during Dx states where the power conservation is most + * important. During driver activity we should enable + * SmartSpeed, so performance is maintained. + */ + if (phy->smart_speed == e1000_smart_speed_on) { + ret_val = phy->ops.read_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + goto out; + + data |= IGP01E1000_PSCFR_SMART_SPEED; + ret_val = phy->ops.write_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + goto out; + } else if (phy->smart_speed == e1000_smart_speed_off) { + ret_val = phy->ops.read_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + goto out; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = phy->ops.write_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + goto out; + } + } + +out: + return ret_val; +} + +/** + * e1000_reset_hw_82571 - Reset hardware + * @hw: pointer to the HW structure + * + * This resets the hardware into a known state. This is a + * function pointer entry point called by the api module. + **/ +static s32 e1000_reset_hw_82571(struct e1000_hw *hw) +{ + u32 ctrl, extcnf_ctrl, ctrl_ext, icr; + s32 ret_val; + u16 i = 0; + + DEBUGFUNC("e1000_reset_hw_82571"); + + /* + * Prevent the PCI-E bus from sticking if there is no TLP connection + * on the last TLP read/write transaction when MAC is reset. + */ + ret_val = e1000_disable_pcie_master_generic(hw); + if (ret_val) { + DEBUGOUT("PCI-E Master disable polling has failed.\n"); + } + + DEBUGOUT("Masking off all interrupts\n"); + E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); + + E1000_WRITE_REG(hw, E1000_RCTL, 0); + E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP); + E1000_WRITE_FLUSH(hw); + + msec_delay(10); + + /* + * Must acquire the MDIO ownership before MAC reset. + * Ownership defaults to firmware after a reset. + */ + if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { + extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; + + do { + E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); + extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + + if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP) + break; + + extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; + + msec_delay(2); + i++; + } while (i < MDIO_OWNERSHIP_TIMEOUT); + } + + ctrl = E1000_READ_REG(hw, E1000_CTRL); + + DEBUGOUT("Issuing a global reset to MAC\n"); + E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST); + + if (hw->nvm.type == e1000_nvm_flash_hw) { + usec_delay(10); + ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_EE_RST; + E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); + E1000_WRITE_FLUSH(hw); + } + + ret_val = e1000_get_auto_rd_done_generic(hw); + if (ret_val) + /* We don't want to continue accessing MAC registers. */ + goto out; + + /* + * Phy configuration from NVM just starts after EECD_AUTO_RD is set. + * Need to wait for Phy configuration completion before accessing + * NVM and Phy. + */ + if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) + msec_delay(25); + + /* Clear any pending interrupt events. */ + E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); + icr = E1000_READ_REG(hw, E1000_ICR); + + if (!(e1000_check_alt_mac_addr_generic(hw))) + e1000_set_laa_state_82571(hw, true); + +out: + return ret_val; +} + +/** + * e1000_init_hw_82571 - Initialize hardware + * @hw: pointer to the HW structure + * + * This inits the hardware readying it for operation. + **/ +static s32 e1000_init_hw_82571(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 reg_data; + s32 ret_val; + u16 i, rar_count = mac->rar_entry_count; + + DEBUGFUNC("e1000_init_hw_82571"); + + e1000_initialize_hw_bits_82571(hw); + + /* Initialize identification LED */ + ret_val = e1000_id_led_init_generic(hw); + if (ret_val) { + DEBUGOUT("Error initializing identification LED\n"); + /* This is not fatal and we should not stop init due to this */ + } + + /* Disabling VLAN filtering */ + DEBUGOUT("Initializing the IEEE VLAN\n"); + mac->ops.clear_vfta(hw); + + /* Setup the receive address. */ + /* + * If, however, a locally administered address was assigned to the + * 82571, we must reserve a RAR for it to work around an issue where + * resetting one port will reload the MAC on the other port. + */ + if (e1000_get_laa_state_82571(hw)) + rar_count--; + e1000_init_rx_addrs_generic(hw, rar_count); + + /* Zero out the Multicast HASH table */ + DEBUGOUT("Zeroing the MTA\n"); + for (i = 0; i < mac->mta_reg_count; i++) + E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); + + /* Setup link and flow control */ + ret_val = mac->ops.setup_link(hw); + + /* Set the transmit descriptor write-back policy */ + reg_data = E1000_READ_REG(hw, E1000_TXDCTL(0)); + reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB | + E1000_TXDCTL_COUNT_DESC; + E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg_data); + + /* ...for both queues. */ + if (mac->type != e1000_82573 && mac->type != e1000_82574) { + reg_data = E1000_READ_REG(hw, E1000_TXDCTL(1)); + reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB | + E1000_TXDCTL_COUNT_DESC; + E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg_data); + } else { + e1000_enable_tx_pkt_filtering_generic(hw); + reg_data = E1000_READ_REG(hw, E1000_GCR); + reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX; + E1000_WRITE_REG(hw, E1000_GCR, reg_data); + } + + /* + * Clear all of the statistics registers (clear on read). It is + * important that we do this after we have tried to establish link + * because the symbol error count will increment wildly if there + * is no link. + */ + e1000_clear_hw_cntrs_82571(hw); + + return ret_val; +} + +/** + * e1000_initialize_hw_bits_82571 - Initialize hardware-dependent bits + * @hw: pointer to the HW structure + * + * Initializes required hardware-dependent bits needed for normal operation. + **/ +static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw) +{ + u32 reg; + + DEBUGFUNC("e1000_initialize_hw_bits_82571"); + + if (hw->mac.disable_hw_init_bits) + goto out; + + /* Transmit Descriptor Control 0 */ + reg = E1000_READ_REG(hw, E1000_TXDCTL(0)); + reg |= (1 << 22); + E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg); + + /* Transmit Descriptor Control 1 */ + reg = E1000_READ_REG(hw, E1000_TXDCTL(1)); + reg |= (1 << 22); + E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg); + + /* Transmit Arbitration Control 0 */ + reg = E1000_READ_REG(hw, E1000_TARC(0)); + reg &= ~(0xF << 27); /* 30:27 */ + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + reg |= (1 << 23) | (1 << 24) | (1 << 25) | (1 << 26); + break; + default: + break; + } + E1000_WRITE_REG(hw, E1000_TARC(0), reg); + + /* Transmit Arbitration Control 1 */ + reg = E1000_READ_REG(hw, E1000_TARC(1)); + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + reg &= ~((1 << 29) | (1 << 30)); + reg |= (1 << 22) | (1 << 24) | (1 << 25) | (1 << 26); + if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR) + reg &= ~(1 << 28); + else + reg |= (1 << 28); + E1000_WRITE_REG(hw, E1000_TARC(1), reg); + break; + default: + break; + } + + /* Device Control */ + if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { + reg = E1000_READ_REG(hw, E1000_CTRL); + reg &= ~(1 << 29); + E1000_WRITE_REG(hw, E1000_CTRL, reg); + } + + /* Extended Device Control */ + if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { + reg = E1000_READ_REG(hw, E1000_CTRL_EXT); + reg &= ~(1 << 23); + reg |= (1 << 22); + E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg); + } + + /* PCI-Ex Control Register */ + if (hw->mac.type == e1000_82574) { + reg = E1000_READ_REG(hw, E1000_GCR); + reg |= (1 << 22); + E1000_WRITE_REG(hw, E1000_GCR, reg); + } + +out: + return; +} + +/** + * e1000_clear_vfta_82571 - Clear VLAN filter table + * @hw: pointer to the HW structure + * + * Clears the register array which contains the VLAN filter table by + * setting all the values to 0. + **/ +static void e1000_clear_vfta_82571(struct e1000_hw *hw) +{ + u32 offset; + u32 vfta_value = 0; + u32 vfta_offset = 0; + u32 vfta_bit_in_reg = 0; + + DEBUGFUNC("e1000_clear_vfta_82571"); + + if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { + if (hw->mng_cookie.vlan_id != 0) { + /* + * The VFTA is a 4096b bit-field, each identifying + * a single VLAN ID. The following operations + * determine which 32b entry (i.e. offset) into the + * array we want to set the VLAN ID (i.e. bit) of + * the manageability unit. + */ + vfta_offset = (hw->mng_cookie.vlan_id >> + E1000_VFTA_ENTRY_SHIFT) & + E1000_VFTA_ENTRY_MASK; + vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id & + E1000_VFTA_ENTRY_BIT_SHIFT_MASK); + } + } + for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { + /* + * If the offset we want to clear is the same offset of the + * manageability VLAN ID, then clear all bits except that of + * the manageability unit. + */ + vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0; + E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, vfta_value); + E1000_WRITE_FLUSH(hw); + } +} + +/** + * e1000_check_mng_mode_82574 - Check manageability is enabled + * @hw: pointer to the HW structure + * + * Reads the NVM Initialization Control Word 2 and returns true + * (>0) if any manageability is enabled, else false (0). + **/ +static bool e1000_check_mng_mode_82574(struct e1000_hw *hw) +{ + u16 data; + + DEBUGFUNC("e1000_check_mng_mode_82574"); + + hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &data); + return ((data & E1000_NVM_INIT_CTRL2_MNGM) != 0); +} + +/** + * e1000_led_on_82574 - Turn LED on + * @hw: pointer to the HW structure + * + * Turn LED on. + **/ +static s32 e1000_led_on_82574(struct e1000_hw *hw) +{ + u32 ctrl; + u32 i; + + DEBUGFUNC("e1000_led_on_82574"); + + ctrl = hw->mac.ledctl_mode2; + if (!(E1000_STATUS_LU & E1000_READ_REG(hw, E1000_STATUS))) { + /* + * If no link, then turn LED on by setting the invert bit + * for each LED that's "on" (0x0E) in ledctl_mode2. + */ + for (i = 0; i < 4; i++) + if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) == + E1000_LEDCTL_MODE_LED_ON) + ctrl |= (E1000_LEDCTL_LED0_IVRT << (i * 8)); + } + E1000_WRITE_REG(hw, E1000_LEDCTL, ctrl); + + return E1000_SUCCESS; +} + +/** + * e1000_update_mc_addr_list_82571 - Update Multicast addresses + * @hw: pointer to the HW structure + * @mc_addr_list: array of multicast addresses to program + * @mc_addr_count: number of multicast addresses to program + * @rar_used_count: the first RAR register free to program + * @rar_count: total number of supported Receive Address Registers + * + * Updates the Receive Address Registers and Multicast Table Array. + * The caller must have a packed mc_addr_list of multicast addresses. + * The parameter rar_count will usually be hw->mac.rar_entry_count + * unless there are workarounds that change this. + **/ +static void e1000_update_mc_addr_list_82571(struct e1000_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count, + u32 rar_used_count, u32 rar_count) +{ + DEBUGFUNC("e1000_update_mc_addr_list_82571"); + + if (e1000_get_laa_state_82571(hw)) + rar_count--; + + e1000_update_mc_addr_list_generic(hw, mc_addr_list, mc_addr_count, + rar_used_count, rar_count); +} + +/** + * e1000_setup_link_82571 - Setup flow control and link settings + * @hw: pointer to the HW structure + * + * Determines which flow control settings to use, then configures flow + * control. Calls the appropriate media-specific link configuration + * function. Assuming the adapter has a valid link partner, a valid link + * should be established. Assumes the hardware has previously been reset + * and the transmitter and receiver are not enabled. + **/ +static s32 e1000_setup_link_82571(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_setup_link_82571"); + + /* + * 82573 does not have a word in the NVM to determine + * the default flow control setting, so we explicitly + * set it to full. + */ + if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) && + hw->fc.type == e1000_fc_default) + hw->fc.type = e1000_fc_full; + + return e1000_setup_link_generic(hw); +} + +/** + * e1000_setup_copper_link_82571 - Configure copper link settings + * @hw: pointer to the HW structure + * + * Configures the link for auto-neg or forced speed and duplex. Then we check + * for link, once link is established calls to configure collision distance + * and flow control are called. + **/ +static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw) +{ + u32 ctrl, led_ctrl; + s32 ret_val; + + DEBUGFUNC("e1000_setup_copper_link_82571"); + + ctrl = E1000_READ_REG(hw, E1000_CTRL); + ctrl |= E1000_CTRL_SLU; + ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + E1000_WRITE_REG(hw, E1000_CTRL, ctrl); + + switch (hw->phy.type) { + case e1000_phy_m88: + case e1000_phy_bm: + ret_val = e1000_copper_link_setup_m88(hw); + break; + case e1000_phy_igp_2: + ret_val = e1000_copper_link_setup_igp(hw); + /* Setup activity LED */ + led_ctrl = E1000_READ_REG(hw, E1000_LEDCTL); + led_ctrl &= IGP_ACTIVITY_LED_MASK; + led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); + E1000_WRITE_REG(hw, E1000_LEDCTL, led_ctrl); + break; + default: + ret_val = -E1000_ERR_PHY; + break; + } + + if (ret_val) + goto out; + + ret_val = e1000_setup_copper_link_generic(hw); + +out: + return ret_val; +} + +/** + * e1000_setup_fiber_serdes_link_82571 - Setup link for fiber/serdes + * @hw: pointer to the HW structure + * + * Configures collision distance and flow control for fiber and serdes links. + * Upon successful setup, poll for link. + **/ +static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_setup_fiber_serdes_link_82571"); + + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + /* + * If SerDes loopback mode is entered, there is no form + * of reset to take the adapter out of that mode. So we + * have to explicitly take the adapter out of loopback + * mode. This prevents drivers from twiddling their thumbs + * if another tool failed to take it out of loopback mode. + */ + E1000_WRITE_REG(hw, E1000_SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK); + break; + default: + break; + } + + return e1000_setup_fiber_serdes_link_generic(hw); +} + +/** + * e1000_valid_led_default_82571 - Verify a valid default LED config + * @hw: pointer to the HW structure + * @data: pointer to the NVM (EEPROM) + * + * Read the EEPROM for the current default LED configuration. If the + * LED configuration is not valid, set to a valid LED configuration. + **/ +static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data) +{ + s32 ret_val; + + DEBUGFUNC("e1000_valid_led_default_82571"); + + ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + + if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) && + *data == ID_LED_RESERVED_F746) + *data = ID_LED_DEFAULT_82573; + else if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) + *data = ID_LED_DEFAULT; +out: + return ret_val; +} + +/** + * e1000_get_laa_state_82571 - Get locally administered address state + * @hw: pointer to the HW structure + * + * Retrieve and return the current locally administered address state. + **/ +bool e1000_get_laa_state_82571(struct e1000_hw *hw) +{ + struct e1000_dev_spec_82571 *dev_spec; + bool state = false; + + DEBUGFUNC("e1000_get_laa_state_82571"); + + if (hw->mac.type != e1000_82571) + goto out; + + dev_spec = (struct e1000_dev_spec_82571 *)hw->dev_spec; + + state = dev_spec->laa_is_present; + +out: + return state; +} + +/** + * e1000_set_laa_state_82571 - Set locally administered address state + * @hw: pointer to the HW structure + * @state: enable/disable locally administered address + * + * Enable/Disable the current locally administered address state. + **/ +void e1000_set_laa_state_82571(struct e1000_hw *hw, bool state) +{ + struct e1000_dev_spec_82571 *dev_spec; + + DEBUGFUNC("e1000_set_laa_state_82571"); + + if (hw->mac.type != e1000_82571) + goto out; + + dev_spec = (struct e1000_dev_spec_82571 *)hw->dev_spec; + + dev_spec->laa_is_present = state; + + /* If workaround is activated... */ + if (state) { + /* + * Hold a copy of the LAA in RAR[14] This is done so that + * between the time RAR[0] gets clobbered and the time it + * gets fixed, the actual LAA is in one of the RARs and no + * incoming packets directed to this port are dropped. + * Eventually the LAA will be in RAR[0] and RAR[14]. + */ + e1000_rar_set_generic(hw, hw->mac.addr, + hw->mac.rar_entry_count - 1); + } + +out: + return; +} + +/** + * e1000_fix_nvm_checksum_82571 - Fix EEPROM checksum + * @hw: pointer to the HW structure + * + * Verifies that the EEPROM has completed the update. After updating the + * EEPROM, we need to check bit 15 in work 0x23 for the checksum fix. If + * the checksum fix is not implemented, we need to set the bit and update + * the checksum. Otherwise, if bit 15 is set and the checksum is incorrect, + * we need to return bad checksum. + **/ +static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + s32 ret_val = E1000_SUCCESS; + u16 data; + + DEBUGFUNC("e1000_fix_nvm_checksum_82571"); + + if (nvm->type != e1000_nvm_flash_hw) + goto out; + + /* + * Check bit 4 of word 10h. If it is 0, firmware is done updating + * 10h-12h. Checksum may need to be fixed. + */ + ret_val = nvm->ops.read(hw, 0x10, 1, &data); + if (ret_val) + goto out; + + if (!(data & 0x10)) { + /* + * Read 0x23 and check bit 15. This bit is a 1 + * when the checksum has already been fixed. If + * the checksum is still wrong and this bit is a + * 1, we need to return bad checksum. Otherwise, + * we need to set this bit to a 1 and update the + * checksum. + */ + ret_val = nvm->ops.read(hw, 0x23, 1, &data); + if (ret_val) + goto out; + + if (!(data & 0x8000)) { + data |= 0x8000; + ret_val = nvm->ops.write(hw, 0x23, 1, &data); + if (ret_val) + goto out; + ret_val = nvm->ops.update(hw); + } + } + +out: + return ret_val; +} + +/** + * e1000_read_mac_addr_82571 - Read device MAC address + * @hw: pointer to the HW structure + **/ +static s32 e1000_read_mac_addr_82571(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_read_mac_addr_82571"); + if (e1000_check_alt_mac_addr_generic(hw)) + ret_val = e1000_read_mac_addr_generic(hw); + + return ret_val; +} + +/** + * e1000_power_down_phy_copper_82571 - Remove link during PHY power down + * @hw: pointer to the HW structure + * + * In the case of a PHY power down to save power, or to turn off link during a + * driver unload, or wake on lan is not enabled, remove the link. + **/ +static void e1000_power_down_phy_copper_82571(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + struct e1000_mac_info *mac = &hw->mac; + + if (!(phy->ops.check_reset_block)) + return; + + /* If the management interface is not enabled, then power down */ + if (!(mac->ops.check_mng_mode(hw) || phy->ops.check_reset_block(hw))) + e1000_power_down_phy_copper(hw); + + return; +} + +/** + * e1000_clear_hw_cntrs_82571 - Clear device specific hardware counters + * @hw: pointer to the HW structure + * + * Clears the hardware counters by reading the counter registers. + **/ +static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw) +{ + volatile u32 temp; + + DEBUGFUNC("e1000_clear_hw_cntrs_82571"); + + e1000_clear_hw_cntrs_base_generic(hw); + temp = E1000_READ_REG(hw, E1000_PRC64); + temp = E1000_READ_REG(hw, E1000_PRC127); + temp = E1000_READ_REG(hw, E1000_PRC255); + temp = E1000_READ_REG(hw, E1000_PRC511); + temp = E1000_READ_REG(hw, E1000_PRC1023); + temp = E1000_READ_REG(hw, E1000_PRC1522); + temp = E1000_READ_REG(hw, E1000_PTC64); + temp = E1000_READ_REG(hw, E1000_PTC127); + temp = E1000_READ_REG(hw, E1000_PTC255); + temp = E1000_READ_REG(hw, E1000_PTC511); + temp = E1000_READ_REG(hw, E1000_PTC1023); + temp = E1000_READ_REG(hw, E1000_PTC1522); + + temp = E1000_READ_REG(hw, E1000_ALGNERRC); + temp = E1000_READ_REG(hw, E1000_RXERRC); + temp = E1000_READ_REG(hw, E1000_TNCRS); + temp = E1000_READ_REG(hw, E1000_CEXTERR); + temp = E1000_READ_REG(hw, E1000_TSCTC); + temp = E1000_READ_REG(hw, E1000_TSCTFC); + + temp = E1000_READ_REG(hw, E1000_MGTPRC); + temp = E1000_READ_REG(hw, E1000_MGTPDC); + temp = E1000_READ_REG(hw, E1000_MGTPTC); + + temp = E1000_READ_REG(hw, E1000_IAC); + temp = E1000_READ_REG(hw, E1000_ICRXOC); + + temp = E1000_READ_REG(hw, E1000_ICRXPTC); + temp = E1000_READ_REG(hw, E1000_ICRXATC); + temp = E1000_READ_REG(hw, E1000_ICTXPTC); + temp = E1000_READ_REG(hw, E1000_ICTXATC); + temp = E1000_READ_REG(hw, E1000_ICTXQEC); + temp = E1000_READ_REG(hw, E1000_ICTXQMTC); + temp = E1000_READ_REG(hw, E1000_ICRXDMTC); +} --- linux-2.6.27.orig/ubuntu/e1000e/ethtool.c +++ linux-2.6.27/ubuntu/e1000e/ethtool.c @@ -0,0 +1,2002 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* ethtool support for e1000 */ + +#include +#ifdef SIOCETHTOOL +#include +#include +#include + +#include "e1000.h" +#ifdef NETIF_F_HW_VLAN_TX +#include +#endif + +#ifdef ETHTOOL_OPS_COMPAT +#include "kcompat_ethtool.c" +#endif + +struct e1000_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \ + offsetof(struct e1000_adapter, m) +static const struct e1000_stats e1000_gstrings_stats[] = { + { "rx_packets", E1000_STAT(stats.gprc) }, + { "tx_packets", E1000_STAT(stats.gptc) }, + { "rx_bytes", E1000_STAT(stats.gorc) }, + { "tx_bytes", E1000_STAT(stats.gotc) }, + { "rx_broadcast", E1000_STAT(stats.bprc) }, + { "tx_broadcast", E1000_STAT(stats.bptc) }, + { "rx_multicast", E1000_STAT(stats.mprc) }, + { "tx_multicast", E1000_STAT(stats.mptc) }, + { "rx_errors", E1000_STAT(net_stats.rx_errors) }, + { "tx_errors", E1000_STAT(net_stats.tx_errors) }, + { "tx_dropped", E1000_STAT(net_stats.tx_dropped) }, + { "multicast", E1000_STAT(stats.mprc) }, + { "collisions", E1000_STAT(stats.colc) }, + { "rx_length_errors", E1000_STAT(net_stats.rx_length_errors) }, + { "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) }, + { "rx_crc_errors", E1000_STAT(stats.crcerrs) }, + { "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) }, + { "rx_no_buffer_count", E1000_STAT(stats.rnbc) }, + { "rx_missed_errors", E1000_STAT(stats.mpc) }, + { "tx_aborted_errors", E1000_STAT(stats.ecol) }, + { "tx_carrier_errors", E1000_STAT(stats.tncrs) }, + { "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) }, + { "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) }, + { "tx_window_errors", E1000_STAT(stats.latecol) }, + { "tx_abort_late_coll", E1000_STAT(stats.latecol) }, + { "tx_deferred_ok", E1000_STAT(stats.dc) }, + { "tx_single_coll_ok", E1000_STAT(stats.scc) }, + { "tx_multi_coll_ok", E1000_STAT(stats.mcc) }, + { "tx_timeout_count", E1000_STAT(tx_timeout_count) }, + { "tx_restart_queue", E1000_STAT(restart_queue) }, + { "rx_long_length_errors", E1000_STAT(stats.roc) }, + { "rx_short_length_errors", E1000_STAT(stats.ruc) }, + { "rx_align_errors", E1000_STAT(stats.algnerrc) }, + { "tx_tcp_seg_good", E1000_STAT(stats.tsctc) }, + { "tx_tcp_seg_failed", E1000_STAT(stats.tsctfc) }, + { "rx_flow_control_xon", E1000_STAT(stats.xonrxc) }, + { "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) }, + { "tx_flow_control_xon", E1000_STAT(stats.xontxc) }, + { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) }, + { "rx_long_byte_count", E1000_STAT(stats.gorc) }, + { "rx_csum_offload_good", E1000_STAT(hw_csum_good) }, + { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }, + { "rx_header_split", E1000_STAT(rx_hdr_split) }, + { "alloc_rx_buff_failed", E1000_STAT(alloc_rx_buff_failed) }, + { "tx_smbus", E1000_STAT(stats.mgptc) }, + { "rx_smbus", E1000_STAT(stats.mgprc) }, + { "dropped_smbus", E1000_STAT(stats.mgpdc) }, + { "rx_dma_failed", E1000_STAT(rx_dma_failed) }, + { "tx_dma_failed", E1000_STAT(tx_dma_failed) }, +}; + +#define E1000_GLOBAL_STATS_LEN \ + sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) +#define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN) +static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = { + "Register test (offline)", "Eeprom test (offline)", + "Interrupt test (offline)", "Loopback test (offline)", + "Link test (on/offline)" +}; +#define E1000_TEST_LEN ARRAY_SIZE(e1000_gstrings_test) + +static int e1000_get_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 status; + + if (hw->phy.media_type == e1000_media_type_copper) { + + ecmd->supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_TP); + if (hw->phy.type == e1000_phy_ife) + ecmd->supported &= ~SUPPORTED_1000baseT_Full; + ecmd->advertising = ADVERTISED_TP; + + if (hw->mac.autoneg == 1) { + ecmd->advertising |= ADVERTISED_Autoneg; + /* the e1000 autoneg seems to match ethtool nicely */ + ecmd->advertising |= hw->phy.autoneg_advertised; + } + + ecmd->port = PORT_TP; + ecmd->phy_address = hw->phy.addr; + ecmd->transceiver = XCVR_INTERNAL; + + } else { + ecmd->supported = (SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg); + + ecmd->advertising = (ADVERTISED_1000baseT_Full | + ADVERTISED_FIBRE | + ADVERTISED_Autoneg); + + ecmd->port = PORT_FIBRE; + ecmd->transceiver = XCVR_EXTERNAL; + } + + status = er32(STATUS); + if (status & E1000_STATUS_LU) { + if (status & E1000_STATUS_SPEED_1000) + ecmd->speed = 1000; + else if (status & E1000_STATUS_SPEED_100) + ecmd->speed = 100; + else + ecmd->speed = 10; + + if (status & E1000_STATUS_FD) + ecmd->duplex = DUPLEX_FULL; + else + ecmd->duplex = DUPLEX_HALF; + } else { + ecmd->speed = -1; + ecmd->duplex = -1; + } + + ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) || + hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE; + return 0; +} + +static u32 e1000_get_link(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 status; + + status = er32(STATUS); + return (status & E1000_STATUS_LU); +} + +static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) +{ + struct e1000_mac_info *mac = &adapter->hw.mac; + + mac->autoneg = 0; + + /* Fiber NICs only allow 1000 gbps Full duplex */ + if ((adapter->hw.phy.media_type == e1000_media_type_fiber) && + spddplx != (SPEED_1000 + DUPLEX_FULL)) { + e_err("Unsupported Speed/Duplex configuration\n"); + return -EINVAL; + } + + switch (spddplx) { + case SPEED_10 + DUPLEX_HALF: + mac->forced_speed_duplex = ADVERTISE_10_HALF; + break; + case SPEED_10 + DUPLEX_FULL: + mac->forced_speed_duplex = ADVERTISE_10_FULL; + break; + case SPEED_100 + DUPLEX_HALF: + mac->forced_speed_duplex = ADVERTISE_100_HALF; + break; + case SPEED_100 + DUPLEX_FULL: + mac->forced_speed_duplex = ADVERTISE_100_FULL; + break; + case SPEED_1000 + DUPLEX_FULL: + mac->autoneg = 1; + adapter->hw.phy.autoneg_advertised = ADVERTISE_1000_FULL; + break; + case SPEED_1000 + DUPLEX_HALF: /* not supported */ + default: + e_err("Unsupported Speed/Duplex configuration\n"); + return -EINVAL; + } + return 0; +} + +static int e1000_set_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + /* + * When SoL/IDER sessions are active, autoneg/speed/duplex + * cannot be changed + */ + if (hw->phy.ops.check_reset_block && + hw->phy.ops.check_reset_block(&adapter->hw)) { + e_err("Cannot change link characteristics when SoL/IDER" + " is active.\n"); + return -EINVAL; + } + + while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) + msleep(1); + + if (ecmd->autoneg == AUTONEG_ENABLE) { + hw->mac.autoneg = 1; + if (hw->phy.media_type == e1000_media_type_fiber) + hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full | + ADVERTISED_FIBRE | + ADVERTISED_Autoneg; + else + hw->phy.autoneg_advertised = ecmd->advertising | + ADVERTISED_TP | + ADVERTISED_Autoneg; + ecmd->advertising = hw->phy.autoneg_advertised; + if (adapter->fc_autoneg) + hw->fc.original_type = e1000_fc_default; + } else { + if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { + clear_bit(__E1000_RESETTING, &adapter->state); + return -EINVAL; + } + } + + /* reset the link */ + + if (netif_running(adapter->netdev)) { + e1000_down(adapter); + e1000_up(adapter); + } else { + e1000_reset(adapter); + } + + clear_bit(__E1000_RESETTING, &adapter->state); + return 0; +} + +static void e1000_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + pause->autoneg = + (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); + + if (hw->fc.type == e1000_fc_rx_pause) { + pause->rx_pause = 1; + } else if (hw->fc.type == e1000_fc_tx_pause) { + pause->tx_pause = 1; + } else if (hw->fc.type == e1000_fc_full) { + pause->rx_pause = 1; + pause->tx_pause = 1; + } +} + +static int e1000_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + int retval = 0; + + adapter->fc_autoneg = pause->autoneg; + + while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) + msleep(1); + + if (pause->rx_pause && pause->tx_pause) + hw->fc.type = e1000_fc_full; + else if (pause->rx_pause && !pause->tx_pause) + hw->fc.type = e1000_fc_rx_pause; + else if (!pause->rx_pause && pause->tx_pause) + hw->fc.type = e1000_fc_tx_pause; + else if (!pause->rx_pause && !pause->tx_pause) + hw->fc.type = e1000_fc_none; + + hw->fc.original_type = hw->fc.type; + + if (adapter->fc_autoneg == AUTONEG_ENABLE) { + hw->fc.type = e1000_fc_default; + if (netif_running(adapter->netdev)) { + e1000_down(adapter); + e1000_up(adapter); + } else { + e1000_reset(adapter); + } + } else { + retval = ((hw->phy.media_type == e1000_media_type_fiber) ? + hw->mac.ops.setup_link(hw) : + e1000_force_mac_fc_generic(hw)); + } + + clear_bit(__E1000_RESETTING, &adapter->state); + return retval; +} + +static u32 e1000_get_rx_csum(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + return (adapter->flags & FLAG_RX_CSUM_ENABLED); +} + +static int e1000_set_rx_csum(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if (data) + adapter->flags |= FLAG_RX_CSUM_ENABLED; + else + adapter->flags &= ~FLAG_RX_CSUM_ENABLED; + + if (netif_running(netdev)) + e1000_reinit_locked(adapter); + else + e1000_reset(adapter); + return 0; +} + +static u32 e1000_get_tx_csum(struct net_device *netdev) +{ + return ((netdev->features & NETIF_F_HW_CSUM) != 0); +} + +static int e1000_set_tx_csum(struct net_device *netdev, u32 data) +{ + if (data) + netdev->features |= NETIF_F_HW_CSUM; + else + netdev->features &= ~NETIF_F_HW_CSUM; + + return 0; +} + +#ifdef NETIF_F_TSO +static int e1000_set_tso(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + int i; + struct net_device *v_netdev; + + if (data) { + netdev->features |= NETIF_F_TSO; +#ifdef NETIF_F_TSO6 + netdev->features |= NETIF_F_TSO6; +#endif + } else { + netdev->features &= ~NETIF_F_TSO; +#ifdef NETIF_F_TSO6 + netdev->features &= ~NETIF_F_TSO6; +#endif +#ifdef NETIF_F_HW_VLAN_TX + /* disable TSO on all VLANs if they're present */ + if (!adapter->vlgrp) + goto tso_out; + for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { + v_netdev = vlan_group_get_device(adapter->vlgrp, i); + if (!v_netdev) + continue; + + v_netdev->features &= ~NETIF_F_TSO; +#ifdef NETIF_F_TSO6 + v_netdev->features &= ~NETIF_F_TSO6; +#endif + vlan_group_set_device(adapter->vlgrp, i, v_netdev); + } +#endif + } + +tso_out: + e_info("TSO is %s\n", data ? "Enabled" : "Disabled"); + adapter->flags |= FLAG_TSO_FORCE; + return 0; +} +#endif + +static u32 e1000_get_msglevel(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + return adapter->msg_enable; +} + +static void e1000_set_msglevel(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + adapter->msg_enable = data; +} + +static int e1000_get_regs_len(struct net_device *netdev) +{ +#define E1000_REGS_LEN 32 /* overestimate */ + return E1000_REGS_LEN * sizeof(u32); +} + +static void e1000_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *p) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 *regs_buff = p; + u16 phy_data; + u8 revision_id; + + memset(p, 0, E1000_REGS_LEN * sizeof(u32)); + + pci_read_config_byte(adapter->pdev, PCI_REVISION_ID, &revision_id); + + regs->version = (1 << 24) | (revision_id << 16) | adapter->pdev->device; + + regs_buff[0] = er32(CTRL); + regs_buff[1] = er32(STATUS); + + regs_buff[2] = er32(RCTL); + regs_buff[3] = er32(RDLEN(0)); + regs_buff[4] = er32(RDH(0)); + regs_buff[5] = er32(RDT(0)); + regs_buff[6] = er32(RDTR); + + regs_buff[7] = er32(TCTL); + regs_buff[8] = er32(TDLEN(0)); + regs_buff[9] = er32(TDH(0)); + regs_buff[10] = er32(TDT(0)); + regs_buff[11] = er32(TIDV); + + regs_buff[12] = adapter->hw.phy.type; /* PHY type (IGP=1, M88=0) */ + if (hw->phy.type == e1000_phy_m88) { + hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); + regs_buff[13] = (u32)phy_data; /* cable length */ + regs_buff[14] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + regs_buff[15] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + regs_buff[16] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + regs_buff[17] = (u32)phy_data; /* extended 10bt distance */ + regs_buff[18] = regs_buff[13]; /* cable polarity */ + regs_buff[19] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + regs_buff[20] = regs_buff[17]; /* polarity correction */ + /* phy receive errors */ + regs_buff[22] = adapter->phy_stats.receive_errors; + regs_buff[23] = regs_buff[13]; /* mdix mode */ + } + regs_buff[21] = adapter->phy_stats.idle_errors; /* phy idle errors */ + hw->phy.ops.read_reg(hw, PHY_1000T_STATUS, &phy_data); + regs_buff[24] = (u32)phy_data; /* phy local receiver status */ + regs_buff[25] = regs_buff[24]; /* phy remote receiver status */ +} + +static int e1000_get_eeprom_len(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + return adapter->hw.nvm.word_size * 2; +} + +static int e1000_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u16 *eeprom_buff; + int first_word; + int last_word; + int ret_val = 0; + u16 i; + + if (eeprom->len == 0) + return -EINVAL; + + eeprom->magic = adapter->pdev->vendor | (adapter->pdev->device << 16); + + first_word = eeprom->offset >> 1; + last_word = (eeprom->offset + eeprom->len - 1) >> 1; + + eeprom_buff = kmalloc(sizeof(u16) * + (last_word - first_word + 1), GFP_KERNEL); + if (!eeprom_buff) + return -ENOMEM; + + if (hw->nvm.type == e1000_nvm_eeprom_spi) { + ret_val = hw->nvm.ops.read(hw, first_word, + last_word - first_word + 1, + eeprom_buff); + } else { + for (i = 0; i < last_word - first_word + 1; i++) { + ret_val = hw->nvm.ops.read(hw, first_word + i, 1, + &eeprom_buff[i]); + if (ret_val) + break; + } + } + + /* Device's eeprom is always little-endian, word addressable */ + for (i = 0; i < last_word - first_word + 1; i++) + le16_to_cpus(&eeprom_buff[i]); + + memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len); + kfree(eeprom_buff); + + return ret_val; +} + +static int e1000_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u16 *eeprom_buff; + void *ptr; + int max_len; + int first_word; + int last_word; + int ret_val = 0; + u16 i; + + if (eeprom->len == 0) + return -EOPNOTSUPP; + + if (eeprom->magic != (adapter->pdev->vendor | (adapter->pdev->device << 16))) + return -EFAULT; + + max_len = hw->nvm.word_size * 2; + + first_word = eeprom->offset >> 1; + last_word = (eeprom->offset + eeprom->len - 1) >> 1; + eeprom_buff = kmalloc(max_len, GFP_KERNEL); + if (!eeprom_buff) + return -ENOMEM; + + ptr = (void *)eeprom_buff; + + if (eeprom->offset & 1) { + /* need read/modify/write of first changed EEPROM word */ + /* only the second byte of the word is being modified */ + ret_val = hw->nvm.ops.read(hw, first_word, 1, &eeprom_buff[0]); + ptr++; + } + if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) + /* need read/modify/write of last changed EEPROM word */ + /* only the first byte of the word is being modified */ + ret_val = hw->nvm.ops.read(hw, last_word, 1, + &eeprom_buff[last_word - first_word]); + + /* Device's eeprom is always little-endian, word addressable */ + for (i = 0; i < last_word - first_word + 1; i++) + le16_to_cpus(&eeprom_buff[i]); + + memcpy(ptr, bytes, eeprom->len); + + for (i = 0; i < last_word - first_word + 1; i++) + eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]); + + ret_val = hw->nvm.ops.write(hw, first_word, last_word - first_word + 1, + eeprom_buff); + + /* + * Update the checksum over the first part of the EEPROM if needed + * and flush shadow RAM for 82573 controllers + */ + if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG) || + (hw->mac.type == e1000_82574) || + (hw->mac.type == e1000_82573))) + hw->nvm.ops.update(hw); + + kfree(eeprom_buff); + return ret_val; +} + +static void e1000_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + char firmware_version[32]; + u16 eeprom_data; + + strncpy(drvinfo->driver, e1000e_driver_name, 32); + strncpy(drvinfo->version, e1000e_driver_version, 32); + + /* + * EEPROM image version # is reported as firmware version # for + * PCI-E controllers + */ + hw->nvm.ops.read(&adapter->hw, 5, 1, &eeprom_data); + sprintf(firmware_version, "%d.%d-%d", + (eeprom_data & 0xF000) >> 12, + (eeprom_data & 0x0FF0) >> 4, + eeprom_data & 0x000F); + + strncpy(drvinfo->fw_version, firmware_version, 32); + strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); + drvinfo->regdump_len = e1000_get_regs_len(netdev); + drvinfo->eedump_len = e1000_get_eeprom_len(netdev); +} + +static void e1000_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_ring *rx_ring = adapter->rx_ring; + + ring->rx_max_pending = E1000_MAX_RXD; + ring->tx_max_pending = E1000_MAX_TXD; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rx_ring->count; + ring->tx_pending = tx_ring->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; +} + +static int e1000_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_ring *tx_ring, *tx_old; + struct e1000_ring *rx_ring, *rx_old; + int err; + + if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) + return -EINVAL; + + while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) + msleep(1); + + if (netif_running(adapter->netdev)) + e1000_down(adapter); + + tx_old = adapter->tx_ring; + rx_old = adapter->rx_ring; + + err = -ENOMEM; + tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); + if (!tx_ring) + goto err_alloc_tx; + /* + * use a memcpy to save any previously configured + * items like napi structs from having to be + * reinitialized + */ + memcpy(tx_ring, tx_old, sizeof(struct e1000_ring)); + + rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); + if (!rx_ring) + goto err_alloc_rx; + memcpy(rx_ring, rx_old, sizeof(struct e1000_ring)); + + adapter->tx_ring = tx_ring; + adapter->rx_ring = rx_ring; + + rx_ring->count = max(ring->rx_pending, (u32)E1000_MIN_RXD); + rx_ring->count = min(rx_ring->count, (u32)(E1000_MAX_RXD)); + rx_ring->count = ALIGN(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE); + + tx_ring->count = max(ring->tx_pending, (u32)E1000_MIN_TXD); + tx_ring->count = min(tx_ring->count, (u32)(E1000_MAX_TXD)); + tx_ring->count = ALIGN(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE); + + if (netif_running(adapter->netdev)) { + /* Try to get new resources before deleting old */ + err = e1000_setup_rx_resources(adapter); + if (err) + goto err_setup_rx; + err = e1000_setup_tx_resources(adapter); + if (err) + goto err_setup_tx; + + /* + * restore the old in order to free it, + * then add in the new + */ + adapter->rx_ring = rx_old; + adapter->tx_ring = tx_old; + e1000_free_rx_resources(adapter); + e1000_free_tx_resources(adapter); + kfree(tx_old); + kfree(rx_old); + adapter->rx_ring = rx_ring; + adapter->tx_ring = tx_ring; + err = e1000_up(adapter); + if (err) + goto err_setup; + } + + clear_bit(__E1000_RESETTING, &adapter->state); + return 0; +err_setup_tx: + e1000_free_rx_resources(adapter); +err_setup_rx: + adapter->rx_ring = rx_old; + adapter->tx_ring = tx_old; + kfree(rx_ring); +err_alloc_rx: + kfree(tx_ring); +err_alloc_tx: + e1000_up(adapter); +err_setup: + clear_bit(__E1000_RESETTING, &adapter->state); + return err; +} + +static bool reg_pattern_test(struct e1000_adapter *adapter, u64 *data, + int reg, int offset, u32 mask, u32 write) +{ + u32 pat, val; + static const u32 test[] = + {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; + for (pat = 0; pat < ARRAY_SIZE(test); pat++) { + E1000_WRITE_REG_ARRAY(&adapter->hw, reg, offset, + (test[pat] & write)); + val = E1000_READ_REG_ARRAY(&adapter->hw, reg, offset); + if (val != (test[pat] & write & mask)) { + e_err("pattern test reg %04X failed: got " + "0x%08X expected 0x%08X\n", + reg + offset, + val, (test[pat] & write & mask)); + *data = reg; + return 1; + } + } + return 0; +} + +static bool reg_set_and_check(struct e1000_adapter *adapter, u64 *data, + int reg, u32 mask, u32 write) +{ + u32 val; + __ew32(&adapter->hw, reg, write & mask); + val = __er32(&adapter->hw, reg); + if ((write & mask) != (val & mask)) { + e_err("set/check reg %04X test failed: got 0x%08X" + "expected 0x%08X\n", reg, (val & mask), (write & mask)); + *data = reg; + return 1; + } + return 0; +} +#define REG_PATTERN_TEST_ARRAY(reg, offset, mask, write) \ + do { \ + if (reg_pattern_test(adapter, data, reg, offset, mask, write)) \ + return 1; \ + } while (0) +#define REG_PATTERN_TEST(reg, mask, write) \ + REG_PATTERN_TEST_ARRAY(reg, 0, mask, write) + +#define REG_SET_AND_CHECK(reg, mask, write) \ + do { \ + if (reg_set_and_check(adapter, data, reg, mask, write)) \ + return 1; \ + } while (0) + +static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_mac_info *mac = &adapter->hw.mac; + u32 value; + u32 before; + u32 after; + u32 i; + u32 toggle; + + /* + * The status register is Read Only, so a write should fail. + * Some bits that get toggled are ignored. + */ + switch (mac->type) { + /* there are several bits on newer hardware that are r/w */ + case e1000_82571: + case e1000_82572: + case e1000_80003es2lan: + toggle = 0x7FFFF3FF; + break; + case e1000_82573: + case e1000_82574: + case e1000_ich8lan: + case e1000_ich9lan: + case e1000_ich10lan: + toggle = 0x7FFFF033; + break; + default: + toggle = 0xFFFFF833; + break; + } + + before = er32(STATUS); + value = (er32(STATUS) & toggle); + ew32(STATUS, toggle); + after = er32(STATUS) & toggle; + if (value != after) { + e_err("failed STATUS register test got: " + "0x%08X expected: 0x%08X\n", after, value); + *data = 1; + return 1; + } + /* restore previous status */ + ew32(STATUS, before); + + if (!(adapter->flags & FLAG_IS_ICH)) { + REG_PATTERN_TEST(E1000_FCAL, 0xFFFFFFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_FCAH, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_FCT, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_VET, 0x0000FFFF, 0xFFFFFFFF); + } + + REG_PATTERN_TEST(E1000_RDTR, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_RDBAH(0), 0xFFFFFFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_RDLEN(0), 0x000FFF80, 0x000FFFFF); + REG_PATTERN_TEST(E1000_RDH(0), 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(E1000_RDT(0), 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(E1000_FCRTH, 0x0000FFF8, 0x0000FFF8); + REG_PATTERN_TEST(E1000_FCTTV, 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(E1000_TIPG, 0x3FFFFFFF, 0x3FFFFFFF); + REG_PATTERN_TEST(E1000_TDBAH(0), 0xFFFFFFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_TDLEN(0), 0x000FFF80, 0x000FFFFF); + + REG_SET_AND_CHECK(E1000_RCTL, 0xFFFFFFFF, 0x00000000); + + before = ((adapter->flags & FLAG_IS_ICH) ? 0x06C3B33E : 0x06DFB3FE); + REG_SET_AND_CHECK(E1000_RCTL, before, 0x003FFFFB); + REG_SET_AND_CHECK(E1000_TCTL, 0xFFFFFFFF, 0x00000000); + + REG_SET_AND_CHECK(E1000_RCTL, before, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_RDBAL(0), 0xFFFFFFF0, 0xFFFFFFFF); + if (!(adapter->flags & FLAG_IS_ICH)) + REG_PATTERN_TEST(E1000_TXCW, 0xC000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(E1000_TDBAL(0), 0xFFFFFFF0, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF); + for (i = 0; i < mac->rar_entry_count; i++) + REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), + ((mac->type == e1000_ich10lan) ? + 0x8007FFFF : 0x8003FFFF), + 0xFFFFFFFF); + + for (i = 0; i < mac->mta_reg_count; i++) + REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF); + + *data = 0; + return 0; +} + +static int e1000_eeprom_test(struct e1000_adapter *adapter, u64 *data) +{ + struct e1000_hw *hw = &adapter->hw; + u16 temp; + u16 checksum = 0; + u16 i; + + *data = 0; + /* Read and add up the contents of the EEPROM */ + for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { + if ((hw->nvm.ops.read(&adapter->hw, i, 1, &temp)) < 0) { + *data = 1; + break; + } + checksum += temp; + } + + /* If Checksum is not Correct return error else test passed */ + if ((checksum != (u16) NVM_SUM) && !(*data)) + *data = 2; + + return *data; +} + +static irqreturn_t e1000_test_intr(int irq, void *data) +{ + struct net_device *netdev = (struct net_device *) data; + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + adapter->test_icr |= er32(ICR); + + return IRQ_HANDLED; +} + +static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) +{ + struct net_device *netdev = adapter->netdev; + struct e1000_hw *hw = &adapter->hw; + u32 mask; + u32 shared_int = 1; + u32 irq = adapter->pdev->irq; + int i; +#ifdef CONFIG_E1000E_MSIX + int ret_val = 0; + int int_mode = E1000E_INT_MODE_LEGACY; +#endif + + *data = 0; + + /* NOTE: we don't test MSI/MSI-X interrupts here, yet */ +#ifdef CONFIG_E1000E_MSIX + if (adapter->int_mode == E1000E_INT_MODE_MSIX) { + int_mode = adapter->int_mode; + e1000_reset_interrupt_capability(adapter); + adapter->int_mode = E1000E_INT_MODE_LEGACY; + e1000_set_interrupt_capability(adapter); + } +#endif + /* Hook up test interrupt handler just for this test */ + if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name, + netdev)) { + shared_int = 0; + } else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED, + netdev->name, netdev)) { + *data = 1; +#ifdef CONFIG_E1000E_MSIX + ret_val = -1; + goto out; +#else + return -1; +#endif + } + e_info("testing %s interrupt\n", (shared_int ? "shared" : "unshared")); + + /* Disable all the interrupts */ + ew32(IMC, 0xFFFFFFFF); + msleep(10); + + /* Test each interrupt */ + for (i = 0; i < 10; i++) { + /* Interrupt to test */ + mask = 1 << i; + + if (adapter->flags & FLAG_IS_ICH) { + switch (mask) { + case E1000_ICR_RXSEQ: + continue; + case 0x00000100: + if (adapter->hw.mac.type == e1000_ich8lan || + adapter->hw.mac.type == e1000_ich9lan) + continue; + break; + default: + break; + } + } + + if (!shared_int) { + /* + * Disable the interrupt to be reported in + * the cause register and then force the same + * interrupt and see if one gets posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + ew32(IMC, mask); + ew32(ICS, mask); + msleep(10); + + if (adapter->test_icr & mask) { + *data = 3; + break; + } + } + + /* + * Enable the interrupt to be reported in + * the cause register and then force the same + * interrupt and see if one gets posted. If + * an interrupt was not posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + ew32(IMS, mask); + ew32(ICS, mask); + msleep(10); + + if (!(adapter->test_icr & mask)) { + *data = 4; + break; + } + + if (!shared_int) { + /* + * Disable the other interrupts to be reported in + * the cause register and then force the other + * interrupts and see if any get posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + ew32(IMC, ~mask & 0x00007FFF); + ew32(ICS, ~mask & 0x00007FFF); + msleep(10); + + if (adapter->test_icr) { + *data = 5; + break; + } + } + } + + /* Disable all the interrupts */ + ew32(IMC, 0xFFFFFFFF); + msleep(10); + + /* Unhook test interrupt handler */ + free_irq(irq, netdev); + +#ifdef CONFIG_E1000E_MSIX +out: + if (int_mode == E1000E_INT_MODE_MSIX) { + e1000_reset_interrupt_capability(adapter); + adapter->int_mode = int_mode; + e1000_set_interrupt_capability(adapter); + } + + return ret_val; +#else + return *data; +#endif +} + +static void e1000_free_desc_rings(struct e1000_adapter *adapter) +{ + struct e1000_ring *tx_ring = &adapter->test_tx_ring; + struct e1000_ring *rx_ring = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + int i; + + if (tx_ring->desc && tx_ring->buffer_info) { + for (i = 0; i < tx_ring->count; i++) { + if (tx_ring->buffer_info[i].dma) + pci_unmap_single(pdev, + tx_ring->buffer_info[i].dma, + tx_ring->buffer_info[i].length, + PCI_DMA_TODEVICE); + if (tx_ring->buffer_info[i].skb) + dev_kfree_skb(tx_ring->buffer_info[i].skb); + } + } + + if (rx_ring->desc && rx_ring->buffer_info) { + for (i = 0; i < rx_ring->count; i++) { + if (rx_ring->buffer_info[i].dma) + pci_unmap_single(pdev, + rx_ring->buffer_info[i].dma, + 2048, PCI_DMA_FROMDEVICE); + if (rx_ring->buffer_info[i].skb) + dev_kfree_skb(rx_ring->buffer_info[i].skb); + } + } + + if (tx_ring->desc) { + dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc, + tx_ring->dma); + tx_ring->desc = NULL; + } + if (rx_ring->desc) { + dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc, + rx_ring->dma); + rx_ring->desc = NULL; + } + + kfree(tx_ring->buffer_info); + tx_ring->buffer_info = NULL; + kfree(rx_ring->buffer_info); + rx_ring->buffer_info = NULL; +} + +static int e1000_setup_desc_rings(struct e1000_adapter *adapter) +{ + struct e1000_ring *tx_ring = &adapter->test_tx_ring; + struct e1000_ring *rx_ring = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + struct e1000_hw *hw = &adapter->hw; + u32 rctl; + int i; + int ret_val; + + /* Setup Tx descriptor ring and Tx buffers */ + + if (!tx_ring->count) + tx_ring->count = E1000_DEFAULT_TXD; + + if (!(tx_ring->buffer_info = kcalloc(tx_ring->count, + sizeof(struct e1000_buffer), + GFP_KERNEL))) { + ret_val = 1; + goto err_nomem; + } + + tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc); + tx_ring->size = ALIGN(tx_ring->size, 4096); + tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size, + &tx_ring->dma, GFP_KERNEL); + if (!tx_ring->desc) { + ret_val = 2; + goto err_nomem; + } + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + + ew32(TDBAL(0), ((u64) tx_ring->dma & 0x00000000FFFFFFFF)); + ew32(TDBAH(0), ((u64) tx_ring->dma >> 32)); + ew32(TDLEN(0), tx_ring->count * sizeof(struct e1000_tx_desc)); + ew32(TDH(0), 0); + ew32(TDT(0), 0); + ew32(TCTL, E1000_TCTL_PSP | E1000_TCTL_EN | E1000_TCTL_MULR | + E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT | + E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT); + + for (i = 0; i < tx_ring->count; i++) { + struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*tx_ring, i); + struct sk_buff *skb; + unsigned int skb_size = 1024; + + skb = alloc_skb(skb_size, GFP_KERNEL); + if (!skb) { + ret_val = 3; + goto err_nomem; + } + skb_put(skb, skb_size); + tx_ring->buffer_info[i].skb = skb; + tx_ring->buffer_info[i].length = skb->len; + tx_ring->buffer_info[i].dma = + pci_map_single(pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, tx_ring->buffer_info[i].dma)) { + ret_val = 4; + goto err_nomem; + } + tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma); + tx_desc->lower.data = cpu_to_le32(skb->len); + tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP | + E1000_TXD_CMD_IFCS | + E1000_TXD_CMD_RS); + tx_desc->upper.data = 0; + } + + /* Setup Rx descriptor ring and Rx buffers */ + + if (!rx_ring->count) + rx_ring->count = E1000_DEFAULT_RXD; + + if (!(rx_ring->buffer_info = kcalloc(rx_ring->count, + sizeof(struct e1000_buffer), + GFP_KERNEL))) { + ret_val = 5; + goto err_nomem; + } + + rx_ring->size = rx_ring->count * sizeof(struct e1000_rx_desc); + rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size, + &rx_ring->dma, GFP_KERNEL); + if (!rx_ring->desc) { + ret_val = 6; + goto err_nomem; + } + rx_ring->next_to_use = 0; + rx_ring->next_to_clean = 0; + + rctl = er32(RCTL); + ew32(RCTL, rctl & ~E1000_RCTL_EN); + ew32(RDBAL(0), ((u64) rx_ring->dma & 0xFFFFFFFF)); + ew32(RDBAH(0), ((u64) rx_ring->dma >> 32)); + ew32(RDLEN(0), rx_ring->size); + ew32(RDH(0), 0); + ew32(RDT(0), 0); + rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 | + E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_LPE | + E1000_RCTL_SBP | E1000_RCTL_SECRC | + E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | + (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); + ew32(RCTL, rctl); + + for (i = 0; i < rx_ring->count; i++) { + struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rx_ring, i); + struct sk_buff *skb; + + skb = alloc_skb(2048 + NET_IP_ALIGN, GFP_KERNEL); + if (!skb) { + ret_val = 7; + goto err_nomem; + } + skb_reserve(skb, NET_IP_ALIGN); + rx_ring->buffer_info[i].skb = skb; + rx_ring->buffer_info[i].dma = + pci_map_single(pdev, skb->data, 2048, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(pdev, rx_ring->buffer_info[i].dma)) { + ret_val = 8; + goto err_nomem; + } + rx_desc->buffer_addr = + cpu_to_le64(rx_ring->buffer_info[i].dma); + memset(skb->data, 0x00, skb->len); + } + + return 0; + +err_nomem: + e1000_free_desc_rings(adapter); + return ret_val; +} + +static void e1000_phy_disable_receiver(struct e1000_adapter *adapter) +{ + /* Write out to PHY registers 29 and 30 to disable the Receiver. */ + adapter->hw.phy.ops.write_reg(&adapter->hw, 29, 0x001F); + adapter->hw.phy.ops.write_reg(&adapter->hw, 30, 0x8FFC); + adapter->hw.phy.ops.write_reg(&adapter->hw, 29, 0x001A); + adapter->hw.phy.ops.write_reg(&adapter->hw, 30, 0x8FF0); +} + +static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl_reg = 0; + u32 stat_reg = 0; + u16 phy_reg = 0; + + hw->mac.autoneg = 0; + + if (hw->phy.type == e1000_phy_m88) { + /* Auto-MDI/MDIX Off */ + hw->phy.ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); + /* reset to update Auto-MDI/MDIX */ + hw->phy.ops.write_reg(hw, PHY_CONTROL, 0x9140); + /* autoneg off */ + hw->phy.ops.write_reg(hw, PHY_CONTROL, 0x8140); + } else if (hw->phy.type == e1000_phy_gg82563) + hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CC); + + ctrl_reg = er32(CTRL); + + switch (hw->phy.type) { + case e1000_phy_ife: + /* force 100, set loopback */ + hw->phy.ops.write_reg(hw, PHY_CONTROL, 0x6100); + + /* Now set up the MAC to the same speed/duplex as the PHY. */ + ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ + ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ + E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ + E1000_CTRL_SPD_100 |/* Force Speed to 100 */ + E1000_CTRL_FD); /* Force Duplex to FULL */ + break; + case e1000_phy_bm: + /* Set Default MAC Interface speed to 1GB */ + hw->phy.ops.read_reg(hw, PHY_REG(2, 21), &phy_reg); + phy_reg &= ~0x0007; + phy_reg |= 0x006; + hw->phy.ops.write_reg(hw, PHY_REG(2, 21), phy_reg); + /* Assert SW reset for above settings to take effect */ + hw->phy.ops.commit(hw); + mdelay(1); + /* Force Full Duplex */ + hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &phy_reg); + hw->phy.ops.write_reg(hw, PHY_REG(769, 16), phy_reg | 0x000C); + /* Set Link Up (in force link) */ + hw->phy.ops.read_reg(hw, PHY_REG(776, 16), &phy_reg); + hw->phy.ops.write_reg(hw, PHY_REG(776, 16), phy_reg | 0x0040); + /* Force Link */ + hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &phy_reg); + hw->phy.ops.write_reg(hw, PHY_REG(769, 16), phy_reg | 0x0040); + /* Set Early Link Enable */ + hw->phy.ops.read_reg(hw, PHY_REG(769, 20), &phy_reg); + hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg | 0x0400); + /* fall through */ + default: + /* force 1000, set loopback */ + hw->phy.ops.write_reg(hw, PHY_CONTROL, 0x4140); + mdelay(250); + + /* Now set up the MAC to the same speed/duplex as the PHY. */ + ctrl_reg = er32(CTRL); + ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ + ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ + E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ + E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */ + E1000_CTRL_FD); /* Force Duplex to FULL */ + + if (adapter->flags & FLAG_IS_ICH) + ctrl_reg |= E1000_CTRL_SLU; /* Set Link Up */ + } + + if (hw->phy.media_type == e1000_media_type_copper && + hw->phy.type == e1000_phy_m88) { + ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */ + } else { + /* + * Set the ILOS bit on the fiber Nic if half duplex link is + * detected. + */ + stat_reg = er32(STATUS); + if ((stat_reg & E1000_STATUS_FD) == 0) + ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); + } + + ew32(CTRL, ctrl_reg); + + /* + * Disable the receiver on the PHY so when a cable is plugged in, the + * PHY does not begin to autoneg when a cable is reconnected to the NIC. + */ + if (hw->phy.type == e1000_phy_m88) + e1000_phy_disable_receiver(adapter); + + udelay(500); + + return 0; +} + +static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl = er32(CTRL); + int link = 0; + + /* special requirements for 82571/82572 fiber adapters */ + + /* + * jump through hoops to make sure link is up because serdes + * link is hardwired up + */ + ctrl |= E1000_CTRL_SLU; + ew32(CTRL, ctrl); + + /* disable autoneg */ + ctrl = er32(TXCW); + ctrl &= ~(1 << 31); + ew32(TXCW, ctrl); + + link = (er32(STATUS) & E1000_STATUS_LU); + + if (!link) { + /* set invert loss of signal */ + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_ILOS; + ew32(CTRL, ctrl); + } + + /* + * special write to serdes control register to enable SerDes analog + * loopback + */ +#define E1000_SERDES_LB_ON 0x410 + ew32(SCTL, E1000_SERDES_LB_ON); + msleep(10); + + return 0; +} + +/* only call this for fiber/serdes connections to es2lan */ +static int e1000_set_es2lan_mac_loopback(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrlext = er32(CTRL_EXT); + u32 ctrl = er32(CTRL); + + /* + * save CTRL_EXT to restore later, reuse an empty variable (unused + * on mac_type 80003es2lan) + */ + adapter->tx_fifo_head = ctrlext; + + /* clear the serdes mode bits, putting the device into mac loopback */ + ctrlext &= ~E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES; + ew32(CTRL_EXT, ctrlext); + + /* force speed to 1000/FD, link up */ + ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | + E1000_CTRL_SPD_1000 | E1000_CTRL_FD); + ew32(CTRL, ctrl); + + /* set mac loopback */ + ctrl = er32(RCTL); + ctrl |= E1000_RCTL_LBM_MAC; + ew32(RCTL, ctrl); + + /* set testing mode parameters (no need to reset later) */ +#define KMRNCTRLSTA_OPMODE (0x1F << 16) +#define KMRNCTRLSTA_OPMODE_1GB_FD_GMII 0x0582 + ew32(KMRNCTRLSTA, + (KMRNCTRLSTA_OPMODE | KMRNCTRLSTA_OPMODE_1GB_FD_GMII)); + + return 0; +} + +static int e1000_setup_loopback_test(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 rctl; + + if (hw->phy.media_type == e1000_media_type_fiber || + hw->phy.media_type == e1000_media_type_internal_serdes) { + switch (hw->mac.type) { + case e1000_80003es2lan: + return e1000_set_es2lan_mac_loopback(adapter); + break; + case e1000_82571: + case e1000_82572: + return e1000_set_82571_fiber_loopback(adapter); + break; + default: + rctl = er32(RCTL); + rctl |= E1000_RCTL_LBM_TCVR; + ew32(RCTL, rctl); + return 0; + } + } else if (hw->phy.media_type == e1000_media_type_copper) { + return e1000_integrated_phy_loopback(adapter); + } + + return 7; +} + +static void e1000_loopback_cleanup(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 rctl; + u16 phy_reg; + + rctl = er32(RCTL); + rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); + ew32(RCTL, rctl); + + switch (hw->mac.type) { + case e1000_80003es2lan: + if (hw->phy.media_type == e1000_media_type_fiber || + hw->phy.media_type == e1000_media_type_internal_serdes) { + /* restore CTRL_EXT, stealing space from tx_fifo_head */ + ew32(CTRL_EXT, adapter->tx_fifo_head); + adapter->tx_fifo_head = 0; + } + /* fall through */ + case e1000_82571: + case e1000_82572: + if (hw->phy.media_type == e1000_media_type_fiber || + hw->phy.media_type == e1000_media_type_internal_serdes) { +#define E1000_SERDES_LB_OFF 0x400 + ew32(SCTL, E1000_SERDES_LB_OFF); + msleep(10); + break; + } + /* Fall Through */ + default: + hw->mac.autoneg = 1; + if (hw->phy.type == e1000_phy_gg82563) + hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, + 0x180); + if(hw->phy.ops.read_reg) + hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_reg); + if (phy_reg & MII_CR_LOOPBACK) { + phy_reg &= ~MII_CR_LOOPBACK; + hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_reg); + if (hw->phy.ops.commit) + hw->phy.ops.commit(hw); + } + break; + } +} + +static void e1000_create_lbtest_frame(struct sk_buff *skb, + unsigned int frame_size) +{ + memset(skb->data, 0xFF, frame_size); + frame_size &= ~1; + memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1); + memset(&skb->data[frame_size / 2 + 10], 0xBE, 1); + memset(&skb->data[frame_size / 2 + 12], 0xAF, 1); +} + +static int e1000_check_lbtest_frame(struct sk_buff *skb, + unsigned int frame_size) +{ + frame_size &= ~1; + if (*(skb->data + 3) == 0xFF) + if ((*(skb->data + frame_size / 2 + 10) == 0xBE) && + (*(skb->data + frame_size / 2 + 12) == 0xAF)) + return 0; + return 13; +} + +static int e1000_run_loopback_test(struct e1000_adapter *adapter) +{ + struct e1000_ring *tx_ring = &adapter->test_tx_ring; + struct e1000_ring *rx_ring = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + struct e1000_hw *hw = &adapter->hw; + int i, j, k, l; + int lc; + int good_cnt; + int ret_val = 0; + unsigned long time; + + ew32(RDT(0), rx_ring->count - 1); + + /* + * Calculate the loop count based on the largest descriptor ring + * The idea is to wrap the largest ring a number of times using 64 + * send/receive pairs during each loop + */ + + if (rx_ring->count <= tx_ring->count) + lc = ((tx_ring->count / 64) * 2) + 1; + else + lc = ((rx_ring->count / 64) * 2) + 1; + + k = 0; + l = 0; + for (j = 0; j <= lc; j++) { /* loop count loop */ + for (i = 0; i < 64; i++) { /* send the packets */ + e1000_create_lbtest_frame(tx_ring->buffer_info[k].skb, + 1024); + pci_dma_sync_single_for_device(pdev, + tx_ring->buffer_info[k].dma, + tx_ring->buffer_info[k].length, + PCI_DMA_TODEVICE); + k++; + if (k == tx_ring->count) + k = 0; + } + ew32(TDT(0), k); + msleep(200); + time = jiffies; /* set the start time for the receive */ + good_cnt = 0; + do { /* receive the sent packets */ + pci_dma_sync_single_for_cpu(pdev, + rx_ring->buffer_info[l].dma, 2048, + PCI_DMA_FROMDEVICE); + + ret_val = e1000_check_lbtest_frame( + rx_ring->buffer_info[l].skb, 1024); + if (!ret_val) + good_cnt++; + l++; + if (l == rx_ring->count) + l = 0; + /* + * time + 20 msecs (200 msecs on 2.4) is more than + * enough time to complete the receives, if it's + * exceeded, break and error off + */ + } while ((good_cnt < 64) && !time_after(jiffies, time + 20)); + if (good_cnt != 64) { + ret_val = 13; /* ret_val is the same as mis-compare */ + break; + } + if (jiffies >= (time + 20)) { + ret_val = 14; /* error code for time out error */ + break; + } + } /* end loop count loop */ + return ret_val; +} + +static int e1000_loopback_test(struct e1000_adapter *adapter, u64 *data) +{ + struct e1000_hw *hw = &adapter->hw; + /* + * PHY loopback cannot be performed if SoL/IDER + * sessions are active + */ + if (hw->phy.ops.check_reset_block && + hw->phy.ops.check_reset_block(&adapter->hw)) { + e_err("Cannot do PHY loopback test when SoL/IDER is active.\n"); + *data = 0; + goto out; + } + + *data = e1000_setup_desc_rings(adapter); + if (*data) + goto out; + + *data = e1000_setup_loopback_test(adapter); + if (*data) + goto err_loopback; + + *data = e1000_run_loopback_test(adapter); + e1000_loopback_cleanup(adapter); + +err_loopback: + e1000_free_desc_rings(adapter); +out: + return *data; +} + +static int e1000_link_test(struct e1000_adapter *adapter, u64 *data) +{ + struct e1000_hw *hw = &adapter->hw; + + *data = 0; + if (hw->phy.media_type == e1000_media_type_internal_serdes) { + int i = 0; + hw->mac.serdes_has_link = 0; + + /* + * On some blade server designs, link establishment + * could take as long as 2-3 minutes + */ + do { + hw->mac.ops.check_for_link(hw); + if (hw->mac.serdes_has_link) + return *data; + msleep(20); + } while (i++ < 3750); + + *data = 1; + } else { + hw->mac.ops.check_for_link(hw); + if (hw->mac.autoneg) + msleep(4000); + + if (!(er32(STATUS) & + E1000_STATUS_LU)) + *data = 1; + } + return *data; +} + +static int e1000_get_self_test_count(struct net_device *netdev) +{ + return E1000_TEST_LEN; +} + +static int e1000_get_stats_count(struct net_device *netdev) +{ + return E1000_STATS_LEN; +} + +static void e1000_diag_test(struct net_device *netdev, + struct ethtool_test *eth_test, u64 *data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + u16 autoneg_advertised; + u8 forced_speed_duplex; + u8 autoneg; + bool if_running = netif_running(netdev); + + set_bit(__E1000_TESTING, &adapter->state); + if (eth_test->flags == ETH_TEST_FL_OFFLINE) { + /* Offline tests */ + + /* save speed, duplex, autoneg settings */ + autoneg_advertised = adapter->hw.phy.autoneg_advertised; + forced_speed_duplex = adapter->hw.mac.forced_speed_duplex; + autoneg = adapter->hw.mac.autoneg; + + e_info("offline testing starting\n"); + + /* + * Link test performed before hardware reset so autoneg doesn't + * interfere with test result + */ + if (e1000_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + if (if_running) + /* indicate we're in test mode */ + dev_close(netdev); + else + e1000_reset(adapter); + + if (e1000_reg_test(adapter, &data[0])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + e1000_reset(adapter); + if (e1000_eeprom_test(adapter, &data[1])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + e1000_reset(adapter); + if (e1000_intr_test(adapter, &data[2])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + e1000_reset(adapter); + /* make sure the phy is powered up */ + e1000_power_up_phy(&adapter->hw); + if (e1000_loopback_test(adapter, &data[3])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + /* restore speed, duplex, autoneg settings */ + adapter->hw.phy.autoneg_advertised = autoneg_advertised; + adapter->hw.mac.forced_speed_duplex = forced_speed_duplex; + adapter->hw.mac.autoneg = autoneg; + + /* force this routine to wait until autoneg complete/timeout */ + adapter->hw.phy.autoneg_wait_to_complete = 1; + e1000_reset(adapter); + adapter->hw.phy.autoneg_wait_to_complete = 0; + + clear_bit(__E1000_TESTING, &adapter->state); + if (if_running) + dev_open(netdev); + } else { + e_info("online testing starting\n"); + /* Online tests */ + if (e1000_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + /* Online tests aren't run; pass by default */ + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + + clear_bit(__E1000_TESTING, &adapter->state); + } + msleep_interruptible(4 * 1000); +} + +static void e1000_get_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + wol->supported = 0; + wol->wolopts = 0; + + if (!(adapter->flags & FLAG_HAS_WOL)) + return; + + wol->supported = WAKE_UCAST | WAKE_MCAST | + WAKE_BCAST | WAKE_MAGIC | + WAKE_PHY | WAKE_ARP; + + /* apply any specific unsupported masks here */ + if (adapter->flags & FLAG_NO_WAKE_UCAST) { + wol->supported &= ~WAKE_UCAST; + + if (adapter->wol & E1000_WUFC_EX) + e_err("Interface does not support directed (unicast)" + " frame wake-up packets\n"); + } + + if (adapter->wol & E1000_WUFC_EX) + wol->wolopts |= WAKE_UCAST; + if (adapter->wol & E1000_WUFC_MC) + wol->wolopts |= WAKE_MCAST; + if (adapter->wol & E1000_WUFC_BC) + wol->wolopts |= WAKE_BCAST; + if (adapter->wol & E1000_WUFC_MAG) + wol->wolopts |= WAKE_MAGIC; + if (adapter->wol & E1000_WUFC_LNKC) + wol->wolopts |= WAKE_PHY; + if (adapter->wol & E1000_WUFC_ARP) + wol->wolopts |= WAKE_ARP; +} + +static int e1000_set_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if (wol->wolopts & WAKE_MAGICSECURE) + return -EOPNOTSUPP; + + if (!(adapter->flags & FLAG_HAS_WOL)) + return wol->wolopts ? -EOPNOTSUPP : 0; + + /* these settings will always override what we currently have */ + adapter->wol = 0; + + if (wol->wolopts & WAKE_UCAST) + adapter->wol |= E1000_WUFC_EX; + if (wol->wolopts & WAKE_MCAST) + adapter->wol |= E1000_WUFC_MC; + if (wol->wolopts & WAKE_BCAST) + adapter->wol |= E1000_WUFC_BC; + if (wol->wolopts & WAKE_MAGIC) + adapter->wol |= E1000_WUFC_MAG; + if (wol->wolopts & WAKE_PHY) + adapter->wol |= E1000_WUFC_LNKC; + if (wol->wolopts & WAKE_ARP) + adapter->wol |= E1000_WUFC_ARP; + + return 0; +} + +/* toggle LED 4 times per second = 2 "blinks" per second */ +#define E1000_ID_INTERVAL (HZ/4) + +/* bit defines for adapter->led_status */ +#define E1000_LED_ON 0 + +static void e1000_led_blink_callback(unsigned long data) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) data; + + if (test_and_change_bit(E1000_LED_ON, &adapter->led_status)) + adapter->hw.mac.ops.led_off(&adapter->hw); + else + adapter->hw.mac.ops.led_on(&adapter->hw); + + mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL); +} + +static int e1000_phys_id(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + if (!data) + data = INT_MAX; + + if ((hw->phy.type == e1000_phy_ife) || + (hw->mac.type == e1000_82574)) { + if (!adapter->blink_timer.function) { + init_timer(&adapter->blink_timer); + adapter->blink_timer.function = + e1000_led_blink_callback; + adapter->blink_timer.data = (unsigned long) adapter; + } + mod_timer(&adapter->blink_timer, jiffies); + msleep_interruptible(data * 1000); + del_timer_sync(&adapter->blink_timer); + if (hw->phy.type == e1000_phy_ife) + hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, + 0); + } else { + hw->mac.ops.blink_led(hw); + msleep_interruptible(data * 1000); + } + + hw->mac.ops.led_off(hw); + clear_bit(E1000_LED_ON, &adapter->led_status); + hw->mac.ops.cleanup_led(hw); + + return 0; +} + +static int e1000_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if (adapter->itr_setting <= 3) + ec->rx_coalesce_usecs = adapter->itr_setting; + else + ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting; + + ec->stats_block_coalesce_usecs = adapter->stats_freq_us; + + return 0; +} + +static int e1000_set_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + if ((ec->rx_coalesce_usecs > E1000_MAX_ITR_USECS) || + ((ec->rx_coalesce_usecs > 3) && + (ec->rx_coalesce_usecs < E1000_MIN_ITR_USECS)) || + (ec->rx_coalesce_usecs == 2) || + (ec->stats_block_coalesce_usecs > (10 * 1000000))) + return -EINVAL; + + adapter->stats_freq_us = ec->stats_block_coalesce_usecs; + + if (ec->rx_coalesce_usecs <= 3) { + adapter->itr = 20000; + adapter->itr_setting = ec->rx_coalesce_usecs; + } else { + adapter->itr = (1000000 / ec->rx_coalesce_usecs); + adapter->itr_setting = adapter->itr & ~3; + } + + if (adapter->itr_setting != 0) + ew32(ITR, 1000000000 / (adapter->itr * 256)); + else + ew32(ITR, 0); + + return 0; +} + +static int e1000_nway_reset(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + if (netif_running(netdev)) + e1000_reinit_locked(adapter); + return 0; +} + +static void e1000_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, + u64 *data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + int i; + + e1000_update_stats(adapter); + for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { + char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset; + data[i] = (e1000_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? *(u64 *)p : *(u32 *)p; + } +} + +static void e1000_get_strings(struct net_device *netdev, u32 stringset, + u8 *data) +{ + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_TEST: + memcpy(data, *e1000_gstrings_test, sizeof(e1000_gstrings_test)); + break; + case ETH_SS_STATS: + for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { + memcpy(p, e1000_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + } +} + +static const struct ethtool_ops e1000_ethtool_ops = { + .get_settings = e1000_get_settings, + .set_settings = e1000_set_settings, + .get_drvinfo = e1000_get_drvinfo, + .get_regs_len = e1000_get_regs_len, + .get_regs = e1000_get_regs, + .get_wol = e1000_get_wol, + .set_wol = e1000_set_wol, + .get_msglevel = e1000_get_msglevel, + .set_msglevel = e1000_set_msglevel, + .nway_reset = e1000_nway_reset, + .get_link = e1000_get_link, + .get_eeprom_len = e1000_get_eeprom_len, + .get_eeprom = e1000_get_eeprom, + .set_eeprom = e1000_set_eeprom, + .get_ringparam = e1000_get_ringparam, + .set_ringparam = e1000_set_ringparam, + .get_pauseparam = e1000_get_pauseparam, + .set_pauseparam = e1000_set_pauseparam, + .get_rx_csum = e1000_get_rx_csum, + .set_rx_csum = e1000_set_rx_csum, + .get_tx_csum = e1000_get_tx_csum, + .set_tx_csum = e1000_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, +#ifdef NETIF_F_TSO + .get_tso = ethtool_op_get_tso, + .set_tso = e1000_set_tso, +#endif + .self_test = e1000_diag_test, + .get_strings = e1000_get_strings, + .phys_id = e1000_phys_id, + .get_ethtool_stats = e1000_get_ethtool_stats, + .self_test_count = e1000_get_self_test_count, + .get_stats_count = e1000_get_stats_count, + .get_coalesce = e1000_get_coalesce, + .set_coalesce = e1000_set_coalesce, +}; + +void e1000_set_ethtool_ops(struct net_device *netdev) +{ + /* have to "undeclare" const on this struct to remove warnings */ + SET_ETHTOOL_OPS(netdev, (struct ethtool_ops *)&e1000_ethtool_ops); +} +#endif /* SIOCETHTOOL */ --- linux-2.6.27.orig/ubuntu/e1000e/e1000_manage.h +++ linux-2.6.27/ubuntu/e1000e/e1000_manage.h @@ -0,0 +1,82 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_MANAGE_H_ +#define _E1000_MANAGE_H_ + +bool e1000_check_mng_mode_generic(struct e1000_hw *hw); +bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw); +s32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw); +s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer, + u16 length, u16 offset, u8 *sum); +s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw, + struct e1000_host_mng_command_header *hdr); +s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, + u8 *buffer, u16 length); +bool e1000_enable_mng_pass_thru(struct e1000_hw *hw); + +typedef enum { + e1000_mng_mode_none = 0, + e1000_mng_mode_asf, + e1000_mng_mode_pt, + e1000_mng_mode_ipmi, + e1000_mng_mode_host_if_only +} e1000_mng_mode; + +#define E1000_FACTPS_MNGCG 0x20000000 + +#define E1000_FWSM_MODE_MASK 0xE +#define E1000_FWSM_MODE_SHIFT 1 + +#define E1000_MNG_IAMT_MODE 0x3 +#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10 +#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0 +#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10 +#define E1000_MNG_DHCP_TX_PAYLOAD_CMD 64 +#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1 +#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2 + +#define E1000_VFTA_ENTRY_SHIFT 5 +#define E1000_VFTA_ENTRY_MASK 0x7F +#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F + +#define E1000_HI_MAX_BLOCK_BYTE_LENGTH 1792 /* Num of bytes in range */ +#define E1000_HI_MAX_BLOCK_DWORD_LENGTH 448 /* Num of dwords in range */ +#define E1000_HI_COMMAND_TIMEOUT 500 /* Process HI command limit */ + +#define E1000_HICR_EN 0x01 /* Enable bit - RO */ +/* Driver sets this bit when done to put command in RAM */ +#define E1000_HICR_C 0x02 +#define E1000_HICR_SV 0x04 /* Status Validity */ +#define E1000_HICR_FW_RESET_ENABLE 0x40 +#define E1000_HICR_FW_RESET 0x80 + +/* Intel(R) Active Management Technology signature */ +#define E1000_IAMT_SIGNATURE 0x544D4149 + +#endif --- linux-2.6.27.orig/ubuntu/e1000e/param.c +++ linux-2.6.27/ubuntu/e1000e/param.c @@ -0,0 +1,447 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include + +#include "e1000.h" + +/* + * This is the only thing that needs to be changed to adjust the + * maximum number of ports that the driver can manage. + */ + +#define E1000_MAX_NIC 32 + +#define OPTION_UNSET -1 +#define OPTION_DISABLED 0 +#define OPTION_ENABLED 1 + +#define COPYBREAK_DEFAULT 256 +unsigned int copybreak = COPYBREAK_DEFAULT; +module_param(copybreak, uint, 0644); +MODULE_PARM_DESC(copybreak, + "Maximum size of packet that is copied to a new buffer on receive"); + +/* + * All parameters are treated the same, as an integer array of values. + * This macro just reduces the need to repeat the same declaration code + * over and over (plus this helps to avoid typo bugs). + */ + +#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET } +#ifndef module_param_array +/* Module Parameters are always initialized to -1, so that the driver + * can tell the difference between no user specified value or the + * user asking for the default value. + * The true default values are loaded in when e1000_check_options is called. + * + * This is a GCC extension to ANSI C. + * See the item "Labeled Elements in Initializers" in the section + * "Extensions to the C Language Family" of the GCC documentation. + */ +#define E1000_PARAM(X, desc) \ + static const int __devinitdata X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \ + static unsigned int num_##X; \ + MODULE_PARM(X, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); \ + MODULE_PARM_DESC(X, desc); +#else +#define E1000_PARAM(X, desc) \ + static int __devinitdata X[E1000_MAX_NIC+1] \ + = E1000_PARAM_INIT; \ + static unsigned int num_##X; \ + module_param_array_named(X, X, int, &num_##X, 0); \ + MODULE_PARM_DESC(X, desc); +#endif + +/* + * Transmit Interrupt Delay in units of 1.024 microseconds + * Tx interrupt delay needs to typically be set to something non zero + * + * Valid Range: 0-65535 + */ +E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay"); +#define DEFAULT_TIDV 8 +#define MAX_TXDELAY 0xFFFF +#define MIN_TXDELAY 0 + +/* + * Transmit Absolute Interrupt Delay in units of 1.024 microseconds + * + * Valid Range: 0-65535 + */ +E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay"); +#define DEFAULT_TADV 32 +#define MAX_TXABSDELAY 0xFFFF +#define MIN_TXABSDELAY 0 + +/* + * Receive Interrupt Delay in units of 1.024 microseconds + * hardware will likely hang if you set this to anything but zero. + * + * Valid Range: 0-65535 + */ +E1000_PARAM(RxIntDelay, "Receive Interrupt Delay"); +#define DEFAULT_RDTR 0 +#define MAX_RXDELAY 0xFFFF +#define MIN_RXDELAY 0 + +/* + * Receive Absolute Interrupt Delay in units of 1.024 microseconds + * + * Valid Range: 0-65535 + */ +E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay"); +#define DEFAULT_RADV 8 +#define MAX_RXABSDELAY 0xFFFF +#define MIN_RXABSDELAY 0 + +/* + * Interrupt Throttle Rate (interrupts/sec) + * + * Valid Range: 100-100000 (0=off, 1=dynamic, 3=dynamic conservative) + */ +E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate"); +#define DEFAULT_ITR 3 +#define MAX_ITR 100000 +#define MIN_ITR 100 + +#ifdef CONFIG_E1000E_MSIX +/* IntMode (Interrupt Mode) + * + * Valid Range: 0 - 2 + * + * Default Value: 2 (MSI-X) + */ +E1000_PARAM(IntMode, "Interrupt Mode"); +#define MAX_INTMODE 2 +#define MIN_INTMODE 0 + +#endif /* CONFIG_E1000E_MSIX */ +/* + * Enable Smart Power Down of the PHY + * + * Valid Range: 0, 1 + * + * Default Value: 0 (disabled) + */ +E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down"); + +/* + * Enable Kumeran Lock Loss workaround + * + * Valid Range: 0, 1 + * + * Default Value: 1 (enabled) + */ +E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround"); + +struct e1000_option { + enum { enable_option, range_option, list_option } type; + const char *name; + const char *err; + int def; + union { + struct { /* range_option info */ + int min; + int max; + } r; + struct { /* list_option info */ + int nr; + struct e1000_opt_list { int i; char *str; } *p; + } l; + } arg; +}; + +static int __devinit e1000_validate_option(unsigned int *value, + const struct e1000_option *opt, + struct e1000_adapter *adapter) +{ + if (*value == OPTION_UNSET) { + *value = opt->def; + return 0; + } + + switch (opt->type) { + case enable_option: + switch (*value) { + case OPTION_ENABLED: + e_info("%s Enabled\n", opt->name); + return 0; + case OPTION_DISABLED: + e_info("%s Disabled\n", opt->name); + return 0; + } + break; + case range_option: + if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) { + e_info("%s set to %i\n", opt->name, *value); + return 0; + } + break; + case list_option: { + int i; + struct e1000_opt_list *ent; + + for (i = 0; i < opt->arg.l.nr; i++) { + ent = &opt->arg.l.p[i]; + if (*value == ent->i) { + if (ent->str[0] != '\0') + e_info("%s\n", ent->str); + return 0; + } + } + } + break; + default: + BUG(); + } + + e_info("Invalid %s value specified (%i) %s\n", opt->name, *value, + opt->err); + *value = opt->def; + return -1; +} + +/** + * e1000_check_options - Range Checking for Command Line Parameters + * @adapter: board private structure + * + * This routine checks all command line parameters for valid user + * input. If an invalid value is given, or if no user specified + * value exists, a default value is used. The final value is stored + * in a variable in the adapter structure. + **/ +void __devinit e1000_check_options(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + int bd = adapter->bd_number; + + if (bd >= E1000_MAX_NIC) { + e_notice("Warning: no configuration for board #%i\n", bd); + e_notice("Using defaults for all values\n"); + } + + { /* Transmit Interrupt Delay */ + const struct e1000_option opt = { + .type = range_option, + .name = "Transmit Interrupt Delay", + .err = "using default of " + __MODULE_STRING(DEFAULT_TIDV), + .def = DEFAULT_TIDV, + .arg = { .r = { .min = MIN_TXDELAY, + .max = MAX_TXDELAY } } + }; + + if (num_TxIntDelay > bd) { + adapter->tx_int_delay = TxIntDelay[bd]; + e1000_validate_option(&adapter->tx_int_delay, &opt, + adapter); + } else { + adapter->tx_int_delay = opt.def; + } + } + { /* Transmit Absolute Interrupt Delay */ + const struct e1000_option opt = { + .type = range_option, + .name = "Transmit Absolute Interrupt Delay", + .err = "using default of " + __MODULE_STRING(DEFAULT_TADV), + .def = DEFAULT_TADV, + .arg = { .r = { .min = MIN_TXABSDELAY, + .max = MAX_TXABSDELAY } } + }; + + if (num_TxAbsIntDelay > bd) { + adapter->tx_abs_int_delay = TxAbsIntDelay[bd]; + e1000_validate_option(&adapter->tx_abs_int_delay, &opt, + adapter); + } else { + adapter->tx_abs_int_delay = opt.def; + } + } + { /* Receive Interrupt Delay */ + struct e1000_option opt = { + .type = range_option, + .name = "Receive Interrupt Delay", + .err = "using default of " + __MODULE_STRING(DEFAULT_RDTR), + .def = DEFAULT_RDTR, + .arg = { .r = { .min = MIN_RXDELAY, + .max = MAX_RXDELAY } } + }; + + /* + * modify min and default if 82573 for slow ping w/a, + * a value greater than 8 needs to be set for RDTR + */ + if (adapter->flags & FLAG_HAS_ASPM) { + opt.def = 32; + opt.arg.r.min = 8; + } + + if (num_RxIntDelay > bd) { + adapter->rx_int_delay = RxIntDelay[bd]; + e1000_validate_option(&adapter->rx_int_delay, &opt, + adapter); + } else { + adapter->rx_int_delay = opt.def; + } + } + { /* Receive Absolute Interrupt Delay */ + const struct e1000_option opt = { + .type = range_option, + .name = "Receive Absolute Interrupt Delay", + .err = "using default of " + __MODULE_STRING(DEFAULT_RADV), + .def = DEFAULT_RADV, + .arg = { .r = { .min = MIN_RXABSDELAY, + .max = MAX_RXABSDELAY } } + }; + + if (num_RxAbsIntDelay > bd) { + adapter->rx_abs_int_delay = RxAbsIntDelay[bd]; + e1000_validate_option(&adapter->rx_abs_int_delay, &opt, + adapter); + } else { + adapter->rx_abs_int_delay = opt.def; + } + } + { /* Interrupt Throttling Rate */ + const struct e1000_option opt = { + .type = range_option, + .name = "Interrupt Throttling Rate (ints/sec)", + .err = "using default of " + __MODULE_STRING(DEFAULT_ITR), + .def = DEFAULT_ITR, + .arg = { .r = { .min = MIN_ITR, + .max = MAX_ITR } } + }; + + if (num_InterruptThrottleRate > bd) { + adapter->itr = InterruptThrottleRate[bd]; + switch (adapter->itr) { + case 0: + e_info("%s turned off\n", opt.name); + break; + case 1: + e_info("%s set to dynamic mode\n", opt.name); + adapter->itr_setting = adapter->itr; + adapter->itr = 20000; + break; + case 3: + e_info("%s set to dynamic conservative mode\n", + opt.name); + adapter->itr_setting = adapter->itr; + adapter->itr = 20000; + break; + default: + /* + * Save the setting, because the dynamic bits + * change itr. + */ + if (e1000_validate_option(&adapter->itr, &opt, + adapter) && + (adapter->itr == 3)) { + /* + * In case of invalid user value, + * default to conservative mode. + */ + adapter->itr_setting = adapter->itr; + adapter->itr = 20000; + } else { + /* + * Clear the lower two bits because + * they are used as control. + */ + adapter->itr_setting = + adapter->itr & ~3; + } + break; + } + } else { + adapter->itr_setting = opt.def; + adapter->itr = 20000; + } + } +#ifdef CONFIG_E1000E_MSIX + { /* Interrupt Mode */ + struct e1000_option opt = { + .type = range_option, + .name = "Interrupt Mode", + .err = "defaulting to 2 (MSI-X)", + .def = E1000E_INT_MODE_MSIX, + .arg = { .r = { .min = MIN_INTMODE, + .max = MAX_INTMODE }} + }; + + if (num_IntMode > bd) { + unsigned int int_mode = IntMode[bd]; + e1000_validate_option(&int_mode, &opt, adapter); + adapter->int_mode = int_mode; + } else { + adapter->int_mode = opt.def; + } + } +#endif /* CONFIG_E1000E_MSIX */ + { /* Smart Power Down */ + const struct e1000_option opt = { + .type = enable_option, + .name = "PHY Smart Power Down", + .err = "defaulting to Disabled", + .def = OPTION_DISABLED + }; + + if (num_SmartPowerDownEnable > bd) { + unsigned int spd = SmartPowerDownEnable[bd]; + e1000_validate_option(&spd, &opt, adapter); + if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) + && spd) + adapter->flags |= FLAG_SMART_POWER_DOWN; + } + } + { /* Kumeran Lock Loss Workaround */ + const struct e1000_option opt = { + .type = enable_option, + .name = "Kumeran Lock Loss Workaround", + .err = "defaulting to Enabled", + .def = OPTION_ENABLED + }; + + if (num_KumeranLockLoss > bd) { + unsigned int kmrn_lock_loss = KumeranLockLoss[bd]; + e1000_validate_option(&kmrn_lock_loss, &opt, adapter); + if (hw->mac.type == e1000_ich8lan) + e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, + kmrn_lock_loss); + } else { + if (hw->mac.type == e1000_ich8lan) + e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, + opt.def); + } + } +} --- linux-2.6.27.orig/ubuntu/e1000e/e1000_manage.c +++ linux-2.6.27/ubuntu/e1000e/e1000_manage.c @@ -0,0 +1,383 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include "e1000_hw.h" + +static u8 e1000_calculate_checksum(u8 *buffer, u32 length); + +/** + * e1000_calculate_checksum - Calculate checksum for buffer + * @buffer: pointer to EEPROM + * @length: size of EEPROM to calculate a checksum for + * + * Calculates the checksum for some buffer on a specified length. The + * checksum calculated is returned. + **/ +static u8 e1000_calculate_checksum(u8 *buffer, u32 length) +{ + u32 i; + u8 sum = 0; + + DEBUGFUNC("e1000_calculate_checksum"); + + if (!buffer) + return 0; + + for (i = 0; i < length; i++) + sum += buffer[i]; + + return (u8) (0 - sum); +} + +/** + * e1000_mng_enable_host_if_generic - Checks host interface is enabled + * @hw: pointer to the HW structure + * + * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND + * + * This function checks whether the HOST IF is enabled for command operation + * and also checks whether the previous command is completed. It busy waits + * in case of previous command is not completed. + **/ +s32 e1000_mng_enable_host_if_generic(struct e1000_hw * hw) +{ + u32 hicr; + s32 ret_val = E1000_SUCCESS; + u8 i; + + DEBUGFUNC("e1000_mng_enable_host_if_generic"); + + /* Check that the host interface is enabled. */ + hicr = E1000_READ_REG(hw, E1000_HICR); + if ((hicr & E1000_HICR_EN) == 0) { + DEBUGOUT("E1000_HOST_EN bit disabled.\n"); + ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND; + goto out; + } + /* check the previous command is completed */ + for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) { + hicr = E1000_READ_REG(hw, E1000_HICR); + if (!(hicr & E1000_HICR_C)) + break; + msec_delay_irq(1); + } + + if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) { + DEBUGOUT("Previous command timeout failed .\n"); + ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_check_mng_mode_generic - Generic check management mode + * @hw: pointer to the HW structure + * + * Reads the firmware semaphore register and returns true (>0) if + * manageability is enabled, else false (0). + **/ +bool e1000_check_mng_mode_generic(struct e1000_hw *hw) +{ + u32 fwsm; + + DEBUGFUNC("e1000_check_mng_mode_generic"); + + fwsm = E1000_READ_REG(hw, E1000_FWSM); + + return ((fwsm & E1000_FWSM_MODE_MASK) == + (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)); +} + +/** + * e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on TX + * @hw: pointer to the HW structure + * + * Enables packet filtering on transmit packets if manageability is enabled + * and host interface is enabled. + **/ +bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw) +{ + struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie; + u32 *buffer = (u32 *)&hw->mng_cookie; + u32 offset; + s32 ret_val, hdr_csum, csum; + u8 i, len; + bool tx_filter = true; + + DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic"); + + /* No manageability, no filtering */ + if (!hw->mac.ops.check_mng_mode(hw)) { + tx_filter = false; + goto out; + } + + /* + * If we can't read from the host interface for whatever + * reason, disable filtering. + */ + ret_val = hw->mac.ops.mng_enable_host_if(hw); + if (ret_val != E1000_SUCCESS) { + tx_filter = false; + goto out; + } + + /* Read in the header. Length and offset are in dwords. */ + len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2; + offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2; + for (i = 0; i < len; i++) { + *(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw, + E1000_HOST_IF, + offset + i); + } + hdr_csum = hdr->checksum; + hdr->checksum = 0; + csum = e1000_calculate_checksum((u8 *)hdr, + E1000_MNG_DHCP_COOKIE_LENGTH); + /* + * If either the checksums or signature don't match, then + * the cookie area isn't considered valid, in which case we + * take the safe route of assuming Tx filtering is enabled. + */ + if (hdr_csum != csum) + goto out; + if (hdr->signature != E1000_IAMT_SIGNATURE) + goto out; + + /* Cookie area is valid, make the final check for filtering. */ + if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) + tx_filter = false; + +out: + hw->mac.tx_pkt_filtering = tx_filter; + return tx_filter; +} + +/** + * e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface + * @hw: pointer to the HW structure + * @buffer: pointer to the host interface + * @length: size of the buffer + * + * Writes the DHCP information to the host interface. + **/ +s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw * hw, u8 *buffer, + u16 length) +{ + struct e1000_host_mng_command_header hdr; + s32 ret_val; + u32 hicr; + + DEBUGFUNC("e1000_mng_write_dhcp_info_generic"); + + hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD; + hdr.command_length = length; + hdr.reserved1 = 0; + hdr.reserved2 = 0; + hdr.checksum = 0; + + /* Enable the host interface */ + ret_val = hw->mac.ops.mng_enable_host_if(hw); + if (ret_val) + goto out; + + /* Populate the host interface with the contents of "buffer". */ + ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length, + sizeof(hdr), &(hdr.checksum)); + if (ret_val) + goto out; + + /* Write the manageability command header */ + ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr); + if (ret_val) + goto out; + + /* Tell the ARC a new command is pending. */ + hicr = E1000_READ_REG(hw, E1000_HICR); + E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C); + +out: + return ret_val; +} + +/** + * e1000_mng_write_cmd_header_generic - Writes manageability command header + * @hw: pointer to the HW structure + * @hdr: pointer to the host interface command header + * + * Writes the command header after does the checksum calculation. + **/ +s32 e1000_mng_write_cmd_header_generic(struct e1000_hw * hw, + struct e1000_host_mng_command_header * hdr) +{ + u16 i, length = sizeof(struct e1000_host_mng_command_header); + + DEBUGFUNC("e1000_mng_write_cmd_header_generic"); + + /* Write the whole command header structure with new checksum. */ + + hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length); + + length >>= 2; + /* Write the relevant command block into the ram area. */ + for (i = 0; i < length; i++) { + E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i, + *((u32 *) hdr + i)); + E1000_WRITE_FLUSH(hw); + } + + return E1000_SUCCESS; +} + +/** + * e1000_mng_host_if_write_generic - Write to the manageability host interface + * @hw: pointer to the HW structure + * @buffer: pointer to the host interface buffer + * @length: size of the buffer + * @offset: location in the buffer to write to + * @sum: sum of the data (not checksum) + * + * This function writes the buffer content at the offset given on the host if. + * It also does alignment considerations to do the writes in most efficient + * way. Also fills up the sum of the buffer in *buffer parameter. + **/ +s32 e1000_mng_host_if_write_generic(struct e1000_hw * hw, u8 *buffer, + u16 length, u16 offset, u8 *sum) +{ + u8 *tmp; + u8 *bufptr = buffer; + u32 data = 0; + s32 ret_val = E1000_SUCCESS; + u16 remaining, i, j, prev_bytes; + + DEBUGFUNC("e1000_mng_host_if_write_generic"); + + /* sum = only sum of the data and it is not checksum */ + + if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) { + ret_val = -E1000_ERR_PARAM; + goto out; + } + + tmp = (u8 *)&data; + prev_bytes = offset & 0x3; + offset >>= 2; + + if (prev_bytes) { + data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset); + for (j = prev_bytes; j < sizeof(u32); j++) { + *(tmp + j) = *bufptr++; + *sum += *(tmp + j); + } + E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data); + length -= j - prev_bytes; + offset++; + } + + remaining = length & 0x3; + length -= remaining; + + /* Calculate length in DWORDs */ + length >>= 2; + + /* + * The device driver writes the relevant command block into the + * ram area. + */ + for (i = 0; i < length; i++) { + for (j = 0; j < sizeof(u32); j++) { + *(tmp + j) = *bufptr++; + *sum += *(tmp + j); + } + + E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data); + } + if (remaining) { + for (j = 0; j < sizeof(u32); j++) { + if (j < remaining) + *(tmp + j) = *bufptr++; + else + *(tmp + j) = 0; + + *sum += *(tmp + j); + } + E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data); + } + +out: + return ret_val; +} + +/** + * e1000_enable_mng_pass_thru - Enable processing of ARP's + * @hw: pointer to the HW structure + * + * Verifies the hardware needs to allow ARPs to be processed by the host. + **/ +bool e1000_enable_mng_pass_thru(struct e1000_hw *hw) +{ + u32 manc; + u32 fwsm, factps; + bool ret_val = false; + + DEBUGFUNC("e1000_enable_mng_pass_thru"); + + if (!hw->mac.asf_firmware_present) + goto out; + + manc = E1000_READ_REG(hw, E1000_MANC); + + if (!(manc & E1000_MANC_RCV_TCO_EN) || + !(manc & E1000_MANC_EN_MAC_ADDR_FILTER)) + goto out; + + if (hw->mac.arc_subsystem_valid) { + fwsm = E1000_READ_REG(hw, E1000_FWSM); + factps = E1000_READ_REG(hw, E1000_FACTPS); + + if (!(factps & E1000_FACTPS_MNGCG) && + ((fwsm & E1000_FWSM_MODE_MASK) == + (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) { + ret_val = true; + goto out; + } + } else { + if ((manc & E1000_MANC_SMBUS_EN) && + !(manc & E1000_MANC_ASF_EN)) { + ret_val = true; + goto out; + } + } + +out: + return ret_val; +} + --- linux-2.6.27.orig/ubuntu/e1000e/netdev.c +++ linux-2.6.27/ubuntu/e1000e/netdev.c @@ -0,0 +1,5636 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef NETIF_F_TSO +#include +#ifdef NETIF_F_TSO6 +#include +#endif +#endif +#include +#include +#include + +#include "e1000.h" + +#ifdef CONFIG_E1000E_NAPI +#define DRV_NAPI "-NAPI" +#else +#define DRV_NAPI +#endif + +#define DRV_DEBUG + +#define DRV_VERSION "0.4.1.7" DRV_NAPI DRV_DEBUG +char e1000e_driver_name[] = "e1000e"; +const char e1000e_driver_version[] = DRV_VERSION; + +static s32 e1000_get_variants_82571(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + static int global_quad_port_a; /* global port a indication */ + struct pci_dev *pdev = adapter->pdev; + u16 eeprom_data = 0; + int is_port_b = er32(STATUS) & E1000_STATUS_FUNC_1; + + /* tag quad port adapters first, it's used below */ + switch (pdev->device) { + case E1000_DEV_ID_82571EB_QUAD_COPPER: + case E1000_DEV_ID_82571EB_QUAD_FIBER: + case E1000_DEV_ID_82571EB_QUAD_COPPER_LP: + case E1000_DEV_ID_82571PT_QUAD_COPPER: + adapter->flags |= FLAG_IS_QUAD_PORT; + /* mark the first port */ + if (global_quad_port_a == 0) + adapter->flags |= FLAG_IS_QUAD_PORT_A; + /* Reset for multiple quad port adapters */ + global_quad_port_a++; + if (global_quad_port_a == 4) + global_quad_port_a = 0; + break; + default: + break; + } + + switch (adapter->hw.mac.type) { + case e1000_82571: + /* these dual ports don't have WoL on port B at all */ + if (((pdev->device == E1000_DEV_ID_82571EB_FIBER) || + (pdev->device == E1000_DEV_ID_82571EB_SERDES) || + (pdev->device == E1000_DEV_ID_82571EB_COPPER)) && + (is_port_b)) + adapter->flags &= ~FLAG_HAS_WOL; + /* quad ports only support WoL on port A */ + if (adapter->flags & FLAG_IS_QUAD_PORT && + (!(adapter->flags & FLAG_IS_QUAD_PORT_A))) + adapter->flags &= ~FLAG_HAS_WOL; + /* Does not support WoL on any port */ + if (pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD) + adapter->flags &= ~FLAG_HAS_WOL; + break; + + case e1000_82573: + if (pdev->device == E1000_DEV_ID_82573L) { + adapter->hw.nvm.ops.read(&adapter->hw, NVM_INIT_3GIO_3, + 1, &eeprom_data); + if (!(eeprom_data & NVM_WORD1A_ASPM_MASK)) + adapter->flags |= FLAG_HAS_JUMBO_FRAMES; + } + break; + + default: + break; + } + + return 0; +} + +static struct e1000_info e1000_82571_info = { + .mac = e1000_82571, + .flags = FLAG_HAS_HW_VLAN_FILTER + | FLAG_HAS_JUMBO_FRAMES + | FLAG_HAS_WOL + | FLAG_APME_IN_CTRL3 + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_SMART_POWER_DOWN + | FLAG_RESET_OVERWRITES_LAA /* errata */ + | FLAG_TARC_SPEED_MODE_BIT /* errata */ + | FLAG_APME_CHECK_PORT_B, + .pba = 38, + .init_ops = e1000_init_function_pointers_82571, + .get_variants = e1000_get_variants_82571, +}; + +static struct e1000_info e1000_82572_info = { + .mac = e1000_82572, + .flags = FLAG_HAS_HW_VLAN_FILTER + | FLAG_HAS_JUMBO_FRAMES + | FLAG_HAS_WOL + | FLAG_APME_IN_CTRL3 + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_TARC_SPEED_MODE_BIT, /* errata */ + .pba = 38, + .init_ops = e1000_init_function_pointers_82571, + .get_variants = e1000_get_variants_82571, +}; + +static struct e1000_info e1000_82573_info = { + .mac = e1000_82573, + .flags = FLAG_HAS_HW_VLAN_FILTER + | FLAG_HAS_WOL + | FLAG_APME_IN_CTRL3 + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_SMART_POWER_DOWN + | FLAG_HAS_AMT + | FLAG_HAS_ASPM + | FLAG_HAS_ERT + | FLAG_HAS_SWSM_ON_LOAD, + .pba = 20, + .init_ops = e1000_init_function_pointers_82571, + .get_variants = e1000_get_variants_82571, +}; + +static struct e1000_info e1000_82574_info = { + .mac = e1000_82574, + .flags = FLAG_HAS_HW_VLAN_FILTER +#ifdef CONFIG_E1000E_MSIX + | FLAG_HAS_MSIX +#endif + | FLAG_HAS_JUMBO_FRAMES + | FLAG_HAS_WOL + | FLAG_APME_IN_CTRL3 + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_SMART_POWER_DOWN + | FLAG_HAS_AMT + | FLAG_HAS_ASPM + | FLAG_HAS_CTRLEXT_ON_LOAD, + .pba = 20, + .init_ops = e1000_init_function_pointers_82571, + .get_variants = e1000_get_variants_82571, +}; + +static struct e1000_info e1000_es2_info = { + .mac = e1000_80003es2lan, + .flags = FLAG_HAS_HW_VLAN_FILTER + | FLAG_HAS_JUMBO_FRAMES + | FLAG_HAS_WOL + | FLAG_APME_IN_CTRL3 + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_RX_NEEDS_RESTART /* errata */ + | FLAG_TARC_SET_BIT_ZERO /* errata */ + | FLAG_APME_CHECK_PORT_B + | FLAG_DISABLE_FC_PAUSE_TIME /* errata */ + | FLAG_TIPG_MEDIUM_FOR_80003ESLAN, + .pba = 38, + .init_ops = e1000_init_function_pointers_80003es2lan, + .get_variants = NULL, +}; + +static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) +{ + if (adapter->hw.phy.type == e1000_phy_ife) + adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES; + + if ((adapter->hw.mac.type == e1000_ich8lan) && + (adapter->hw.phy.type == e1000_phy_igp_3)) + adapter->flags |= FLAG_LSC_GIG_SPEED_DROP; + + return 0; +} + +static struct e1000_info e1000_ich8_info = { + .mac = e1000_ich8lan, + .flags = FLAG_HAS_WOL + | FLAG_IS_ICH + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_AMT + | FLAG_HAS_FLASH + | FLAG_APME_IN_WUC, + .pba = 8, + .init_ops = e1000_init_function_pointers_ich8lan, + .get_variants = e1000_get_variants_ich8lan, +}; + +static struct e1000_info e1000_ich9_info = { + .mac = e1000_ich9lan, + .flags = FLAG_HAS_JUMBO_FRAMES + | FLAG_IS_ICH + | FLAG_HAS_WOL + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_AMT + | FLAG_HAS_ERT + | FLAG_HAS_FLASH + | FLAG_APME_IN_WUC, + .pba = 10, + .init_ops = e1000_init_function_pointers_ich8lan, + .get_variants = e1000_get_variants_ich8lan, +}; + +static struct e1000_info e1000_ich10_info = { + .mac = e1000_ich10lan, + .flags = FLAG_HAS_JUMBO_FRAMES + | FLAG_IS_ICH + | FLAG_HAS_WOL + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_AMT + | FLAG_HAS_ERT + | FLAG_HAS_FLASH + | FLAG_APME_IN_WUC, + .pba = 10, + .init_ops = e1000_init_function_pointers_ich8lan, + .get_variants = e1000_get_variants_ich8lan, +}; + +static const struct e1000_info *e1000_info_tbl[] = { + [board_82571] = &e1000_82571_info, + [board_82572] = &e1000_82572_info, + [board_82573] = &e1000_82573_info, + [board_82574] = &e1000_82574_info, + [board_80003es2lan] = &e1000_es2_info, + [board_ich8lan] = &e1000_ich8_info, + [board_ich9lan] = &e1000_ich9_info, + [board_ich10lan] = &e1000_ich10_info, +}; + + +void e1000_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value) +{ + struct e1000_adapter *adapter = hw->back; + + pci_read_config_word(adapter->pdev, reg, value); +} + +s32 e1000_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value) +{ + struct e1000_adapter *adapter = hw->back; + u16 cap_offset; + + cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); + if (!cap_offset) + return -E1000_ERR_CONFIG; + + pci_read_config_word(adapter->pdev, cap_offset + reg, value); + + return E1000_SUCCESS; +} + +s32 e1000_alloc_zeroed_dev_spec_struct(struct e1000_hw *hw, u32 size) +{ + hw->dev_spec = kzalloc(size, GFP_KERNEL); + + if (!hw->dev_spec) + return -ENOMEM; + + return E1000_SUCCESS; +} + +void e1000_free_dev_spec_struct(struct e1000_hw *hw) +{ + if (!hw->dev_spec) + return; + + kfree(hw->dev_spec); +} + +/** + * e1000_desc_unused - calculate if we have unused descriptors + **/ +static int e1000_desc_unused(struct e1000_ring *ring) +{ + if (ring->next_to_clean > ring->next_to_use) + return ring->next_to_clean - ring->next_to_use - 1; + + return ring->count + ring->next_to_clean - ring->next_to_use - 1; +} + +/** + * e1000_receive_skb - helper function to handle Rx indications + * @adapter: board private structure + * @status: descriptor status field as written by hardware + * @vlan: descriptor vlan field as written by hardware (no le/be conversion) + * @skb: pointer to sk_buff to be indicated to stack + **/ +static void e1000_receive_skb(struct e1000_adapter *adapter, + struct net_device *netdev, + struct sk_buff *skb, + u8 status, u16 vlan) +{ + skb->protocol = eth_type_trans(skb, netdev); + +#ifdef CONFIG_E1000E_NAPI + if (adapter->vlgrp && (status & E1000_RXD_STAT_VP)) + vlan_hwaccel_receive_skb(skb, adapter->vlgrp, + le16_to_cpu(vlan) & + E1000_RXD_SPC_VLAN_MASK); + else + netif_receive_skb(skb); +#else + if (adapter->vlgrp && (status & E1000_RXD_STAT_VP)) + vlan_hwaccel_rx(skb, adapter->vlgrp, + le16_to_cpu(vlan) & E1000_RXD_SPC_VLAN_MASK); + else + netif_rx(skb); +#endif + + netdev->last_rx = jiffies; +} + +/** + * e1000_rx_checksum - Receive Checksum Offload for 82543 + * @adapter: board private structure + * @status_err: receive descriptor status and error fields + * @csum: receive descriptor csum field + * @sk_buff: socket buffer with received data + **/ +static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err, + u32 csum, struct sk_buff *skb) +{ + u16 status = (u16)status_err; + u8 errors = (u8)(status_err >> 24); + skb->ip_summed = CHECKSUM_NONE; + + /* Ignore Checksum bit is set */ + if (status & E1000_RXD_STAT_IXSM) + return; + /* TCP/UDP checksum error bit is set */ + if (errors & E1000_RXD_ERR_TCPE) { + /* let the stack verify checksum errors */ + adapter->hw_csum_err++; + return; + } + + /* TCP/UDP Checksum has not been calculated */ + if (!(status & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS))) + return; + + /* It must be a TCP or UDP packet with a valid checksum */ + if (status & E1000_RXD_STAT_TCPCS) { + /* TCP checksum is good */ + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else { + /* + * IP fragment with UDP payload + * Hardware complements the payload checksum, so we undo it + * and then put the value in host order for further stack use. + */ + csum = ntohl(csum ^ 0xFFFF); + skb->csum = csum; + skb->ip_summed = CHECKSUM_COMPLETE; + } + adapter->hw_csum_good++; +} + +/** + * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended + * @adapter: address of board private structure + **/ +static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, + int cleaned_count) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_rx_desc *rx_desc; + struct e1000_buffer *buffer_info; + struct sk_buff *skb; + unsigned int i; + unsigned int bufsz = adapter->rx_buffer_len + NET_IP_ALIGN; + + i = rx_ring->next_to_use; + buffer_info = &rx_ring->buffer_info[i]; + + while (cleaned_count--) { + skb = buffer_info->skb; + if (skb) { + skb_trim(skb, 0); + goto map_skb; + } + + skb = netdev_alloc_skb(netdev, bufsz); + if (!skb) { + /* Better luck next round */ + adapter->alloc_rx_buff_failed++; + break; + } + + /* + * Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, NET_IP_ALIGN); + + buffer_info->skb = skb; +map_skb: + buffer_info->dma = pci_map_single(pdev, skb->data, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(pdev, buffer_info->dma)) { + dev_err(&pdev->dev, "RX DMA map failed\n"); + adapter->rx_dma_failed++; + break; + } + + rx_desc = E1000_RX_DESC(*rx_ring, i); + rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); + + i++; + if (i == rx_ring->count) + i = 0; + buffer_info = &rx_ring->buffer_info[i]; + } + + if (rx_ring->next_to_use != i) { + rx_ring->next_to_use = i; + if (i-- == 0) + i = (rx_ring->count - 1); + + /* + * Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). + */ + wmb(); + writel(i, adapter->hw.hw_addr + rx_ring->tail); + } +} + +/** + * e1000_alloc_rx_buffers_ps - Replace used receive buffers; packet split + * @adapter: address of board private structure + **/ +static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, + int cleaned_count) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + union e1000_rx_desc_packet_split *rx_desc; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_buffer *buffer_info; + struct e1000_ps_page *ps_page; + struct sk_buff *skb; + unsigned int i, j; + + i = rx_ring->next_to_use; + buffer_info = &rx_ring->buffer_info[i]; + + while (cleaned_count--) { + rx_desc = E1000_RX_DESC_PS(*rx_ring, i); + + for (j = 0; j < PS_PAGE_BUFFERS; j++) { + ps_page = &buffer_info->ps_pages[j]; + if (j >= adapter->rx_ps_pages) { + /* all unused desc entries get hw null ptr */ + rx_desc->read.buffer_addr[j+1] = ~0; + continue; + } + if (!ps_page->page) { + ps_page->page = alloc_page(GFP_ATOMIC); + if (!ps_page->page) { + adapter->alloc_rx_buff_failed++; + goto no_buffers; + } + ps_page->dma = pci_map_page(pdev, + ps_page->page, + 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(pdev, ps_page->dma)) { + dev_err(&adapter->pdev->dev, + "RX DMA page map failed\n"); + adapter->rx_dma_failed++; + goto no_buffers; + } + } + /* + * Refresh the desc even if buffer_addrs + * didn't change because each write-back + * erases this info. + */ + rx_desc->read.buffer_addr[j+1] = + cpu_to_le64(ps_page->dma); + } + + skb = netdev_alloc_skb(netdev, + adapter->rx_ps_bsize0 + NET_IP_ALIGN); + + if (!skb) { + adapter->alloc_rx_buff_failed++; + break; + } + + /* + * Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, NET_IP_ALIGN); + + buffer_info->skb = skb; + buffer_info->dma = pci_map_single(pdev, skb->data, + adapter->rx_ps_bsize0, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(pdev, buffer_info->dma)) { + dev_err(&pdev->dev, "RX DMA map failed\n"); + adapter->rx_dma_failed++; + /* cleanup skb */ + dev_kfree_skb_any(skb); + buffer_info->skb = NULL; + break; + } + + rx_desc->read.buffer_addr[0] = cpu_to_le64(buffer_info->dma); + + i++; + if (i == rx_ring->count) + i = 0; + buffer_info = &rx_ring->buffer_info[i]; + } + +no_buffers: + if (rx_ring->next_to_use != i) { + rx_ring->next_to_use = i; + + if (!(i--)) + i = (rx_ring->count - 1); + + /* + * Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). + */ + wmb(); + /* + * Hardware increments by 16 bytes, but packet split + * descriptors are 32 bytes...so we increment tail + * twice as much. + */ + writel(i<<1, adapter->hw.hw_addr + rx_ring->tail); + } +} + +#ifdef CONFIG_E1000E_NAPI +/** + * e1000_alloc_jumbo_rx_buffers - Replace used jumbo receive buffers + * @adapter: address of board private structure + * @rx_ring: pointer to receive ring structure + * @cleaned_count: number of buffers to allocate this pass + **/ + +static void e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter, + int cleaned_count) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_rx_desc *rx_desc; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_buffer *buffer_info; + struct sk_buff *skb; + unsigned int i; + unsigned int bufsz = 256 - + 16 /* for skb_reserve */ - + NET_IP_ALIGN; + + i = rx_ring->next_to_use; + buffer_info = &rx_ring->buffer_info[i]; + + while (cleaned_count--) { + skb = buffer_info->skb; + if (skb) { + skb_trim(skb, 0); + goto check_page; + } + + skb = netdev_alloc_skb(netdev, bufsz); + if (unlikely(!skb)) { + /* Better luck next round */ + adapter->alloc_rx_buff_failed++; + break; + } + + /* Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, NET_IP_ALIGN); + + buffer_info->skb = skb; +check_page: + /* allocate a new page if necessary */ + if (!buffer_info->page) { + buffer_info->page = alloc_page(GFP_ATOMIC); + if (unlikely(!buffer_info->page)) { + adapter->alloc_rx_buff_failed++; + break; + } + } + + if (!buffer_info->dma) + buffer_info->dma = pci_map_page(pdev, + buffer_info->page, 0, + PAGE_SIZE, + PCI_DMA_FROMDEVICE); + + rx_desc = E1000_RX_DESC(*rx_ring, i); + rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); + + if (unlikely(++i == rx_ring->count)) + i = 0; + buffer_info = &rx_ring->buffer_info[i]; + } + + if (likely(rx_ring->next_to_use != i)) { + rx_ring->next_to_use = i; + if (unlikely(i-- == 0)) + i = (rx_ring->count - 1); + + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). */ + wmb(); + writel(i, adapter->hw.hw_addr + rx_ring->tail); + } +} +#endif /* CONFIG_E1000E_NAPI */ + +/** + * e1000_clean_rx_irq - Send received data up the network stack; legacy + * @adapter: board private structure + * + * the return value indicates whether actual cleaning was done, there + * is no guarantee that everything was cleaned + **/ +#ifdef CONFIG_E1000E_NAPI +static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, + int *work_done, int work_to_do) +#else +static bool e1000_clean_rx_irq(struct e1000_adapter *adapter) +#endif +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_rx_desc *rx_desc, *next_rxd; + struct e1000_buffer *buffer_info, *next_buffer; + u32 length; + unsigned int i; + int cleaned_count = 0; + bool cleaned = 0; + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + + i = rx_ring->next_to_clean; + rx_desc = E1000_RX_DESC(*rx_ring, i); + buffer_info = &rx_ring->buffer_info[i]; + + while (rx_desc->status & E1000_RXD_STAT_DD) { + struct sk_buff *skb; + u8 status; + +#ifdef CONFIG_E1000E_NAPI + if (*work_done >= work_to_do) + break; + (*work_done)++; +#endif + + status = rx_desc->status; + skb = buffer_info->skb; + buffer_info->skb = NULL; + + prefetch(skb->data - NET_IP_ALIGN); + + i++; + if (i == rx_ring->count) + i = 0; + next_rxd = E1000_RX_DESC(*rx_ring, i); + prefetch(next_rxd); + + next_buffer = &rx_ring->buffer_info[i]; + + cleaned = 1; + cleaned_count++; + pci_unmap_single(pdev, + buffer_info->dma, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + + length = le16_to_cpu(rx_desc->length); + + /* !EOP means multiple descriptors were used to store a single + * packet, also make sure the frame isn't just CRC only */ + if (!(status & E1000_RXD_STAT_EOP) || (length <= 4)) { + /* All receives must fit into a single buffer */ + e_dbg("Receive packet consumed multiple buffers\n"); + /* recycle */ + buffer_info->skb = skb; + goto next_desc; + } + + if (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { + /* recycle */ + buffer_info->skb = skb; + goto next_desc; + } + + total_rx_bytes += length; + total_rx_packets++; + + /* + * code added for copybreak, this should improve + * performance for small packets with large amounts + * of reassembly being done in the stack + */ + if (length < copybreak) { + struct sk_buff *new_skb = + netdev_alloc_skb(netdev, length + NET_IP_ALIGN); + if (new_skb) { + skb_reserve(new_skb, NET_IP_ALIGN); + skb_copy_to_linear_data_offset(new_skb, + -NET_IP_ALIGN, + (skb->data - + NET_IP_ALIGN), + (length + + NET_IP_ALIGN)); + /* save the skb in buffer_info as good */ + buffer_info->skb = skb; + skb = new_skb; + } + /* else just continue with the old one */ + } + /* end copybreak code */ + skb_put(skb, length); + + /* Receive Checksum Offload */ + e1000_rx_checksum(adapter, + (u32)(status) | + ((u32)(rx_desc->errors) << 24), + le16_to_cpu(rx_desc->csum), skb); + + e1000_receive_skb(adapter, netdev, skb,status,rx_desc->special); + +next_desc: + rx_desc->status = 0; + + /* return some buffers to hardware, one at a time is too slow */ + if (cleaned_count >= E1000_RX_BUFFER_WRITE) { + adapter->alloc_rx_buf(adapter, cleaned_count); + cleaned_count = 0; + } + + /* use prefetched values */ + rx_desc = next_rxd; + buffer_info = next_buffer; + } + rx_ring->next_to_clean = i; + + cleaned_count = e1000_desc_unused(rx_ring); + if (cleaned_count) + adapter->alloc_rx_buf(adapter, cleaned_count); + + adapter->total_rx_packets += total_rx_packets; + adapter->total_rx_bytes += total_rx_bytes; + adapter->net_stats.rx_bytes += total_rx_bytes; + adapter->net_stats.rx_packets += total_rx_packets; + return cleaned; +} + +static void e1000_put_txbuf(struct e1000_adapter *adapter, + struct e1000_buffer *buffer_info) +{ + if (buffer_info->dma) { + pci_unmap_page(adapter->pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_TODEVICE); + buffer_info->dma = 0; + } + if (buffer_info->skb) { + dev_kfree_skb_any(buffer_info->skb); + buffer_info->skb = NULL; + } +} + +static void e1000_print_tx_hang(struct e1000_adapter *adapter) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + unsigned int i = tx_ring->next_to_clean; + unsigned int eop = tx_ring->buffer_info[i].next_to_watch; + struct e1000_tx_desc *eop_desc = E1000_TX_DESC(*tx_ring, eop); + + /* detected Tx unit hang */ + e_err("Detected Tx Unit Hang:\n" + " TDH <%x>\n" + " TDT <%x>\n" + " next_to_use <%x>\n" + " next_to_clean <%x>\n" + "buffer_info[next_to_clean]:\n" + " time_stamp <%lx>\n" + " next_to_watch <%x>\n" + " jiffies <%lx>\n" + " next_to_watch.status <%x>\n", + readl(adapter->hw.hw_addr + tx_ring->head), + readl(adapter->hw.hw_addr + tx_ring->tail), + tx_ring->next_to_use, + tx_ring->next_to_clean, + tx_ring->buffer_info[eop].time_stamp, + eop, + jiffies, + eop_desc->upper.fields.status); +} + +/** + * @e1000_alloc_ring - allocate memory for a ring structure + **/ +static int e1000_alloc_ring_dma(struct e1000_adapter *adapter, + struct e1000_ring *ring) +{ + struct pci_dev *pdev = adapter->pdev; + + ring->desc = dma_alloc_coherent(&pdev->dev, ring->size, &ring->dma, + GFP_KERNEL); + if (!ring->desc) + return -ENOMEM; + + return 0; +} + +/** + * e1000e_setup_tx_resources - allocate Tx resources (Descriptors) + * @adapter: board private structure + * + * Return 0 on success, negative on failure + **/ +int e1000_setup_tx_resources(struct e1000_adapter *adapter) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + int err = -ENOMEM, size; + + size = sizeof(struct e1000_buffer) * tx_ring->count; + tx_ring->buffer_info = vmalloc(size); + if (!tx_ring->buffer_info) + goto err; + memset(tx_ring->buffer_info, 0, size); + + /* round up to nearest 4K */ + tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc); + tx_ring->size = ALIGN(tx_ring->size, 4096); + + err = e1000_alloc_ring_dma(adapter, tx_ring); + if (err) + goto err; + + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + spin_lock_init(&adapter->tx_queue_lock); + + return 0; +err: + vfree(tx_ring->buffer_info); + e_err("Unable to allocate memory for the transmit descriptor ring\n"); + return err; +} + +/** + * e1000e_setup_rx_resources - allocate Rx resources (Descriptors) + * @adapter: board private structure + * + * Returns 0 on success, negative on failure + **/ +int e1000_setup_rx_resources(struct e1000_adapter *adapter) +{ + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_buffer *buffer_info; + int i, size, desc_len, err = -ENOMEM; + + size = sizeof(struct e1000_buffer) * rx_ring->count; + rx_ring->buffer_info = vmalloc(size); + if (!rx_ring->buffer_info) + goto err; + memset(rx_ring->buffer_info, 0, size); + + for (i = 0; i < rx_ring->count; i++) { + buffer_info = &rx_ring->buffer_info[i]; + buffer_info->ps_pages = kcalloc(PS_PAGE_BUFFERS, + sizeof(struct e1000_ps_page), + GFP_KERNEL); + if (!buffer_info->ps_pages) + goto err_pages; + } + + desc_len = sizeof(union e1000_rx_desc_packet_split); + + /* Round up to nearest 4K */ + rx_ring->size = rx_ring->count * desc_len; + rx_ring->size = ALIGN(rx_ring->size, 4096); + + err = e1000_alloc_ring_dma(adapter, rx_ring); + if (err) + goto err_pages; + + rx_ring->next_to_clean = 0; + rx_ring->next_to_use = 0; + rx_ring->rx_skb_top = NULL; + + return 0; + +err_pages: + for (i = 0; i < rx_ring->count; i++) { + buffer_info = &rx_ring->buffer_info[i]; + kfree(buffer_info->ps_pages); + } +err: + vfree(rx_ring->buffer_info); + e_err("Unable to allocate memory for the transmit descriptor ring\n"); + return err; +} + +/** + * e1000_clean_tx_ring - Free Tx Buffers + * @adapter: board private structure + **/ +static void e1000_clean_tx_ring(struct e1000_adapter *adapter) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_buffer *buffer_info; + unsigned long size; + unsigned int i; + + for (i = 0; i < tx_ring->count; i++) { + buffer_info = &tx_ring->buffer_info[i]; + e1000_put_txbuf(adapter, buffer_info); + } + + size = sizeof(struct e1000_buffer) * tx_ring->count; + memset(tx_ring->buffer_info, 0, size); + + memset(tx_ring->desc, 0, tx_ring->size); + + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + + writel(0, adapter->hw.hw_addr + tx_ring->head); + writel(0, adapter->hw.hw_addr + tx_ring->tail); +} + +/** + * e1000_free_tx_resources - Free Tx Resources per Queue + * @adapter: board private structure + * + * Free all transmit software resources + **/ +void e1000_free_tx_resources(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *tx_ring = adapter->tx_ring; + + e1000_clean_tx_ring(adapter); + + vfree(tx_ring->buffer_info); + tx_ring->buffer_info = NULL; + + dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc, + tx_ring->dma); + tx_ring->desc = NULL; +} + +/** + * e1000_clean_rx_irq_ps - Send received data up the network stack; packet split + * @adapter: board private structure + * + * the return value indicates whether actual cleaning was done, there + * is no guarantee that everything was cleaned + **/ +#ifdef CONFIG_E1000E_NAPI +static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, + int *work_done, int work_to_do) +#else +static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter) +#endif +{ + union e1000_rx_desc_packet_split *rx_desc, *next_rxd; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_buffer *buffer_info, *next_buffer; + struct e1000_ps_page *ps_page; + struct sk_buff *skb; + unsigned int i, j; + u32 length, staterr; + int cleaned_count = 0; + bool cleaned = 0; + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + + i = rx_ring->next_to_clean; + rx_desc = E1000_RX_DESC_PS(*rx_ring, i); + staterr = le32_to_cpu(rx_desc->wb.middle.status_error); + buffer_info = &rx_ring->buffer_info[i]; + + while (staterr & E1000_RXD_STAT_DD) { +#ifdef CONFIG_E1000E_NAPI + if (*work_done >= work_to_do) + break; + (*work_done)++; +#endif + skb = buffer_info->skb; + + /* in the packet split case this is header only */ + prefetch(skb->data - NET_IP_ALIGN); + + i++; + if (i == rx_ring->count) + i = 0; + next_rxd = E1000_RX_DESC_PS(*rx_ring, i); + prefetch(next_rxd); + + next_buffer = &rx_ring->buffer_info[i]; + + cleaned = 1; + cleaned_count++; + pci_unmap_single(pdev, buffer_info->dma, + adapter->rx_ps_bsize0, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + + if (!(staterr & E1000_RXD_STAT_EOP)) { + e_dbg("Packet Split buffers didn't pick up the full" + " packet\n"); + dev_kfree_skb_irq(skb); + goto next_desc; + } + + if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) { + dev_kfree_skb_irq(skb); + goto next_desc; + } + + length = le16_to_cpu(rx_desc->wb.middle.length0); + + if (!length) { + e_dbg("Last part of the packet spanning multiple" + " descriptors\n"); + dev_kfree_skb_irq(skb); + goto next_desc; + } + + /* Good Receive */ + skb_put(skb, length); + +#ifdef CONFIG_E1000E_NAPI + { + /* + * this looks ugly, but it seems compiler issues make it + * more efficient than reusing j + */ + int l1 = le16_to_cpu(rx_desc->wb.upper.length[0]); + + /* + * page alloc/put takes too long and effects small packet + * throughput, so unsplit small packets and save the alloc/put + * only valid in softirq (napi) context to call kmap_* + */ + if (l1 && (l1 <= copybreak) && + ((length + l1) <= adapter->rx_ps_bsize0)) { + u8 *vaddr; + + ps_page = &buffer_info->ps_pages[0]; + + /* + * there is no documentation about how to call + * kmap_atomic, so we can't hold the mapping + * very long + */ + pci_dma_sync_single_for_cpu(pdev, ps_page->dma, + PAGE_SIZE, PCI_DMA_FROMDEVICE); + vaddr = kmap_atomic(ps_page->page, KM_SKB_DATA_SOFTIRQ); + memcpy(skb_tail_pointer(skb), vaddr, l1); + kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ); + pci_dma_sync_single_for_device(pdev, ps_page->dma, + PAGE_SIZE, PCI_DMA_FROMDEVICE); + + skb_put(skb, l1); + goto copydone; + } /* if */ + } +#endif + + for (j = 0; j < PS_PAGE_BUFFERS; j++) { + length = le16_to_cpu(rx_desc->wb.upper.length[j]); + if (!length) + break; + + ps_page = &buffer_info->ps_pages[j]; + pci_unmap_page(pdev, ps_page->dma, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + ps_page->dma = 0; + skb_fill_page_desc(skb, j, ps_page->page, 0, length); + ps_page->page = NULL; + skb->len += length; + skb->data_len += length; + skb->truesize += length; + } + +#ifdef CONFIG_E1000E_NAPI +copydone: +#endif + total_rx_bytes += skb->len; + total_rx_packets++; + + e1000_rx_checksum(adapter, staterr, le16_to_cpu( + rx_desc->wb.lower.hi_dword.csum_ip.csum), skb); + + if (rx_desc->wb.upper.header_status & + cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP)) + adapter->rx_hdr_split++; + + e1000_receive_skb(adapter, netdev, skb, + staterr, rx_desc->wb.middle.vlan); + +next_desc: + rx_desc->wb.middle.status_error &= cpu_to_le32(~0xFF); + buffer_info->skb = NULL; + + /* return some buffers to hardware, one at a time is too slow */ + if (cleaned_count >= E1000_RX_BUFFER_WRITE) { + adapter->alloc_rx_buf(adapter, cleaned_count); + cleaned_count = 0; + } + + /* use prefetched values */ + rx_desc = next_rxd; + buffer_info = next_buffer; + + staterr = le32_to_cpu(rx_desc->wb.middle.status_error); + } + rx_ring->next_to_clean = i; + + cleaned_count = e1000_desc_unused(rx_ring); + if (cleaned_count) + adapter->alloc_rx_buf(adapter, cleaned_count); + + adapter->total_rx_packets += total_rx_packets; + adapter->total_rx_bytes += total_rx_bytes; + adapter->net_stats.rx_bytes += total_rx_bytes; + adapter->net_stats.rx_packets += total_rx_packets; + return cleaned; +} + +#ifdef CONFIG_E1000E_NAPI +/* NOTE: these new jumbo frame routines rely on NAPI because of the + * pskb_may_pull call, which eventually must call kmap_atomic which you cannot + * call from hard irq context */ + +/** + * e1000_consume_page - helper function + **/ +static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb, + u16 length) +{ + bi->page = NULL; + skb->len += length; + skb->data_len += length; + skb->truesize += length; +} + +/** + * e1000_clean_jumbo_rx_irq - Send received data up the network stack; legacy + * @adapter: board private structure + * + * the return value indicates whether actual cleaning was done, there + * is no guarantee that everything was cleaned + **/ + +static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter, + int *work_done, int work_to_do) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_rx_desc *rx_desc, *next_rxd; + struct e1000_buffer *buffer_info, *next_buffer; + u32 length; + unsigned int i; + int cleaned_count = 0; + bool cleaned = FALSE; + unsigned int total_rx_bytes=0, total_rx_packets=0; + + i = rx_ring->next_to_clean; + rx_desc = E1000_RX_DESC(*rx_ring, i); + buffer_info = &rx_ring->buffer_info[i]; + + while (rx_desc->status & E1000_RXD_STAT_DD) { + struct sk_buff *skb; + u8 status; + + if (*work_done >= work_to_do) + break; + (*work_done)++; + + status = rx_desc->status; + skb = buffer_info->skb; + buffer_info->skb = NULL; + + ++i; + if (i == rx_ring->count) + i = 0; + next_rxd = E1000_RX_DESC(*rx_ring, i); + prefetch(next_rxd); + + next_buffer = &rx_ring->buffer_info[i]; + + cleaned = TRUE; + cleaned_count++; + pci_unmap_page(pdev, buffer_info->dma, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + + length = le16_to_cpu(rx_desc->length); + + /* errors is only valid for DD + EOP descriptors */ + if (unlikely((status & E1000_RXD_STAT_EOP) && + (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK))) { + /* recycle both page and skb */ + buffer_info->skb = skb; + /* an error means any chain goes out the window + * too */ + if (rx_ring->rx_skb_top) + dev_kfree_skb(rx_ring->rx_skb_top); + rx_ring->rx_skb_top = NULL; + goto next_desc; + } + +#define rxtop rx_ring->rx_skb_top + if (!(status & E1000_RXD_STAT_EOP)) { + /* this descriptor is only the beginning (or middle) */ + if (!rxtop) { + /* this is the beginning of a chain */ + rxtop = skb; + skb_fill_page_desc(rxtop, 0, buffer_info->page, + 0, length); + } else { + /* this is the middle of a chain */ + skb_fill_page_desc(rxtop, + skb_shinfo(rxtop)->nr_frags, + buffer_info->page, 0, length); + /* re-use the skb, only consumed the page */ + buffer_info->skb = skb; + } + e1000_consume_page(buffer_info, rxtop, length); + goto next_desc; + } else { + if (rxtop) { + /* end of the chain */ + skb_fill_page_desc(rxtop, + skb_shinfo(rxtop)->nr_frags, + buffer_info->page, 0, length); + /* re-use the current skb, we only consumed the + * page */ + buffer_info->skb = skb; + skb = rxtop; + rxtop = NULL; + e1000_consume_page(buffer_info, skb, length); + } else { + /* no chain, got EOP, this buf is the packet + * copybreak to save the put_page/alloc_page */ + if (length <= copybreak && + skb_tailroom(skb) >= length) { + u8 *vaddr; + vaddr = kmap_atomic(buffer_info->page, + KM_SKB_DATA_SOFTIRQ); + memcpy(skb_tail_pointer(skb), vaddr, + length); + kunmap_atomic(vaddr, + KM_SKB_DATA_SOFTIRQ); + /* re-use the page, so don't erase + * buffer_info->page */ + skb_put(skb, length); + } else { + skb_fill_page_desc(skb, 0, + buffer_info->page, 0, + length); + e1000_consume_page(buffer_info, skb, + length); + } + } + } + + /* Receive Checksum Offload XXX recompute due to CRC strip? */ + e1000_rx_checksum(adapter, + (u32)(status) | + ((u32)(rx_desc->errors) << 24), + le16_to_cpu(rx_desc->csum), skb); + + /* probably a little skewed due to removing CRC */ + total_rx_bytes += skb->len; + total_rx_packets++; + + /* eth type trans needs skb->data to point to something */ + if (!pskb_may_pull(skb, ETH_HLEN)) { + e_err("pskb_may_pull failed.\n"); + dev_kfree_skb(skb); + goto next_desc; + } + + e1000_receive_skb(adapter, netdev, skb, status, + rx_desc->special); + +next_desc: + rx_desc->status = 0; + + /* return some buffers to hardware, one at a time is too slow */ + if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) { + adapter->alloc_rx_buf(adapter, cleaned_count); + cleaned_count = 0; + } + + /* use prefetched values */ + rx_desc = next_rxd; + buffer_info = next_buffer; + } + rx_ring->next_to_clean = i; + + cleaned_count = e1000_desc_unused(rx_ring); + if (cleaned_count) + adapter->alloc_rx_buf(adapter, cleaned_count); + + adapter->total_rx_packets += total_rx_packets; + adapter->total_rx_bytes += total_rx_bytes; + adapter->net_stats.rx_bytes += total_rx_bytes; + adapter->net_stats.rx_packets += total_rx_packets; + return cleaned; +} +#endif /* CONFIG_E1000E_NAPI */ + +/** + * e1000_clean_rx_ring - Free Rx Buffers per Queue + * @adapter: board private structure + **/ +static void e1000_clean_rx_ring(struct e1000_adapter *adapter) +{ + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_buffer *buffer_info; + struct e1000_ps_page *ps_page; + struct pci_dev *pdev = adapter->pdev; + unsigned int i, j; + + /* Free all the Rx ring sk_buffs */ + for (i = 0; i < rx_ring->count; i++) { + buffer_info = &rx_ring->buffer_info[i]; + if (buffer_info->dma) { + if (adapter->clean_rx == e1000_clean_rx_irq) + pci_unmap_single(pdev, buffer_info->dma, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); +#ifdef CONFIG_E1000E_NAPI + else if (adapter->clean_rx == e1000_clean_jumbo_rx_irq) + pci_unmap_page(pdev, buffer_info->dma, + PAGE_SIZE, + PCI_DMA_FROMDEVICE); +#endif + else if (adapter->clean_rx == e1000_clean_rx_irq_ps) + pci_unmap_single(pdev, buffer_info->dma, + adapter->rx_ps_bsize0, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + } + + if (buffer_info->page) { + put_page(buffer_info->page); + buffer_info->page = NULL; + } + + if (buffer_info->skb) { + dev_kfree_skb(buffer_info->skb); + buffer_info->skb = NULL; + } + + for (j = 0; j < PS_PAGE_BUFFERS; j++) { + ps_page = &buffer_info->ps_pages[j]; + if (!ps_page->page) + break; + pci_unmap_page(pdev, ps_page->dma, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + ps_page->dma = 0; + put_page(ps_page->page); + ps_page->page = NULL; + } + } + +#ifdef CONFIG_E1000E_NAPI + /* there also may be some cached data from a chained receive */ + if (rx_ring->rx_skb_top) { + dev_kfree_skb(rx_ring->rx_skb_top); + rx_ring->rx_skb_top = NULL; + } +#endif + + /* Zero out the descriptor ring */ + memset(rx_ring->desc, 0, rx_ring->size); + + rx_ring->next_to_clean = 0; + rx_ring->next_to_use = 0; + + writel(0, adapter->hw.hw_addr + rx_ring->head); + writel(0, adapter->hw.hw_addr + rx_ring->tail); +} + +/** + * e1000_free_rx_resources - Free Rx Resources + * @adapter: board private structure + * + * Free all receive software resources + **/ + +void e1000_free_rx_resources(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *rx_ring = adapter->rx_ring; + int i; + + e1000_clean_rx_ring(adapter); + + for (i = 0; i < rx_ring->count; i++) { + kfree(rx_ring->buffer_info[i].ps_pages); + } + + vfree(rx_ring->buffer_info); + rx_ring->buffer_info = NULL; + + dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc, + rx_ring->dma); + rx_ring->desc = NULL; +} + +/** + * e1000_update_itr - update the dynamic ITR value based on statistics + * @adapter: pointer to adapter + * @itr_setting: current adapter->itr + * @packets: the number of packets during this measurement interval + * @bytes: the number of bytes during this measurement interval + * + * Stores a new ITR value based on packets and byte + * counts during the last interrupt. The advantage of per interrupt + * computation is faster updates and more accurate ITR for the current + * traffic pattern. Constants in this function were computed + * based on theoretical maximum wire speed and thresholds were set based + * on testing data as well as attempting to minimize response time + * while increasing bulk throughput. This functionality is controlled + * by the InterruptThrottleRate module parameter. + **/ +static unsigned int e1000_update_itr(struct e1000_adapter *adapter, + u16 itr_setting, int packets, + int bytes) +{ + unsigned int retval = itr_setting; + + if (packets == 0) + goto update_itr_done; + + switch (itr_setting) { + case lowest_latency: + /* handle TSO and jumbo frames */ + if (bytes/packets > 8000) + retval = bulk_latency; + else if ((packets < 5) && (bytes > 512)) { + retval = low_latency; + } + break; + case low_latency: /* 50 usec aka 20000 ints/s */ + if (bytes > 10000) { + /* this if handles the TSO accounting */ + if (bytes/packets > 8000) { + retval = bulk_latency; + } else if ((packets < 10) || ((bytes/packets) > 1200)) { + retval = bulk_latency; + } else if ((packets > 35)) { + retval = lowest_latency; + } + } else if (bytes/packets > 2000) { + retval = bulk_latency; + } else if (packets <= 2 && bytes < 512) { + retval = lowest_latency; + } + break; + case bulk_latency: /* 250 usec aka 4000 ints/s */ + if (bytes > 25000) { + if (packets > 35) { + retval = low_latency; + } + } else if (bytes < 6000) { + retval = low_latency; + } + break; + } + +update_itr_done: + return retval; +} + +static void e1000_set_itr(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u16 current_itr; + u32 new_itr = adapter->itr; + + /* for non-gigabit speeds, just fix the interrupt rate at 4000 */ + if (adapter->link_speed != SPEED_1000) { + current_itr = 0; + new_itr = 4000; + goto set_itr_now; + } + + adapter->tx_itr = e1000_update_itr(adapter, + adapter->tx_itr, + adapter->total_tx_packets, + adapter->total_tx_bytes); + /* conservative mode (itr 3) eliminates the lowest_latency setting */ + if (adapter->itr_setting == 3 && adapter->tx_itr == lowest_latency) + adapter->tx_itr = low_latency; + + adapter->rx_itr = e1000_update_itr(adapter, + adapter->rx_itr, + adapter->total_rx_packets, + adapter->total_rx_bytes); + /* conservative mode (itr 3) eliminates the lowest_latency setting */ + if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency) + adapter->rx_itr = low_latency; + + current_itr = max(adapter->rx_itr, adapter->tx_itr); + + switch (current_itr) { + /* counts and packets in update_itr are dependent on these numbers */ + case lowest_latency: + new_itr = 70000; + break; + case low_latency: + new_itr = 20000; /* aka hwitr = ~200 */ + break; + case bulk_latency: + new_itr = 4000; + break; + default: + break; + } + +set_itr_now: + if (new_itr != adapter->itr) { + /* + * this attempts to bias the interrupt rate towards Bulk + * by adding intermediate steps when interrupt rate is + * increasing + */ + new_itr = new_itr > adapter->itr ? + min(adapter->itr + (new_itr >> 2), new_itr) : + new_itr; + adapter->itr = new_itr; +#ifdef CONFIG_E1000E_MSIX + adapter->rx_ring->itr_val = new_itr; + if (adapter->msix_entries) + adapter->rx_ring->set_itr = 1; + else +#endif + ew32(ITR, 1000000000 / (new_itr * 256)); + } +} + +/** + * e1000_clean_tx_irq - Reclaim resources after transmit completes + * @adapter: board private structure + * + * the return value indicates if there is more work to do (later) + **/ +static bool e1000_clean_tx_irq(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct e1000_hw *hw = &adapter->hw; + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_tx_desc *tx_desc, *eop_desc; + struct e1000_buffer *buffer_info; + unsigned int i, eop; + bool cleaned = 0, retval = 1; + unsigned int total_tx_bytes = 0, total_tx_packets = 0; + + i = tx_ring->next_to_clean; + eop = tx_ring->buffer_info[i].next_to_watch; + eop_desc = E1000_TX_DESC(*tx_ring, eop); + + while (eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { + for (cleaned = 0; !cleaned; ) { + tx_desc = E1000_TX_DESC(*tx_ring, i); + buffer_info = &tx_ring->buffer_info[i]; + cleaned = (i == eop); + + if (cleaned) { + struct sk_buff *skb = buffer_info->skb; +#ifdef NETIF_F_TSO + unsigned int segs, bytecount; + segs = skb_shinfo(skb)->gso_segs ?: 1; + /* multiply data chunks by size of headers */ + bytecount = ((segs - 1) * skb_headlen(skb)) + + skb->len; + total_tx_packets += segs; + total_tx_bytes += bytecount; +#else + total_tx_packets++; + total_tx_bytes += skb->len; +#endif + } + + e1000_put_txbuf(adapter, buffer_info); + tx_desc->upper.data = 0; + + i++; + if (i == tx_ring->count) + i = 0; +#ifdef CONFIG_E1000E_NAPI + if (total_tx_packets >= tx_ring->count) { + retval = 0; + goto done_cleaning; + } +#endif + } + + eop = tx_ring->buffer_info[i].next_to_watch; + eop_desc = E1000_TX_DESC(*tx_ring, eop); + } + +#ifdef CONFIG_E1000E_NAPI +done_cleaning: +#endif + tx_ring->next_to_clean = i; + +#define TX_WAKE_THRESHOLD 32 + if (cleaned && netif_carrier_ok(netdev) && + e1000_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD) { + /* + * Make sure that anybody stopping the queue after this + * sees the new next_to_clean. + */ + smp_mb(); + + if (netif_queue_stopped(netdev) && + !(test_bit(__E1000_DOWN, &adapter->state))) { + netif_wake_queue(netdev); + ++adapter->restart_queue; + } + } + + if (adapter->detect_tx_hung) { + /* + * Detect a transmit hang in hardware, this serializes the + * check with the clearing of time_stamp and movement of i + */ + adapter->detect_tx_hung = 0; + if (tx_ring->buffer_info[eop].dma && + time_after(jiffies, tx_ring->buffer_info[eop].time_stamp + + (adapter->tx_timeout_factor * HZ)) + && !(er32(STATUS) & E1000_STATUS_TXOFF)) { + e1000_print_tx_hang(adapter); + netif_stop_queue(netdev); + } + } + adapter->total_tx_bytes += total_tx_bytes; + adapter->total_tx_packets += total_tx_packets; + adapter->net_stats.tx_bytes += total_tx_bytes; + adapter->net_stats.tx_packets += total_tx_packets; + return retval; +} + +/** + * e1000_intr_msi - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + **/ +static irqreturn_t e1000_intr_msi(int irq, void *data) +{ + struct net_device *netdev = data; + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; +#ifndef CONFIG_E1000E_NAPI + int i; +#endif + /* read ICR disables interrupts using IAM */ + u32 icr = er32(ICR); + + if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + hw->mac.get_link_status = 1; + /* + * ICH8 workaround-- Call gig speed drop workaround on cable + * disconnect (LSC) before accessing any PHY registers + */ + if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) && + (!(er32(STATUS) & E1000_STATUS_LU))) + e1000_gig_downshift_workaround_ich8lan(hw); + + /* + * 80003ES2LAN workaround-- For packet buffer work-around on + * link down event; disable receives here in the ISR and reset + * adapter in watchdog + */ + if (netif_carrier_ok(netdev) && + adapter->flags & FLAG_RX_NEEDS_RESTART) { + /* disable receives */ + u32 rctl = er32(RCTL); + ew32(RCTL, rctl & ~E1000_RCTL_EN); + adapter->flags |= FLAG_RX_RESTART_NOW; + } + /* guard against interrupt when we're going down */ + if (!test_bit(__E1000_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); + } + +#ifdef CONFIG_E1000E_NAPI + if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + adapter->total_tx_bytes = 0; + adapter->total_tx_packets = 0; + adapter->total_rx_bytes = 0; + adapter->total_rx_packets = 0; + __netif_rx_schedule(netdev, &adapter->napi); + } +#else + adapter->total_tx_bytes = 0; + adapter->total_rx_bytes = 0; + adapter->total_tx_packets = 0; + adapter->total_rx_packets = 0; + + for (i = 0; i < E1000_MAX_INTR; i++) { + int rx_cleaned = adapter->clean_rx(adapter); + int tx_cleaned_complete = e1000_clean_tx_irq(adapter); + if (!rx_cleaned && tx_cleaned_complete) + break; + } + + if (likely(adapter->itr_setting & 3)) + e1000_set_itr(adapter); +#endif /* CONFIG_E1000E_NAPI */ + + return IRQ_HANDLED; +} + +/** + * e1000_intr - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + **/ +static irqreturn_t e1000_intr(int irq, void *data) +{ + struct net_device *netdev = data; + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; +#ifndef CONFIG_E1000E_NAPI + int i; + int rx_cleaned, tx_cleaned_complete; +#endif + u32 rctl, icr = er32(ICR); + + if (!icr) + return IRQ_NONE; /* Not our interrupt */ + +#ifdef CONFIG_E1000E_NAPI + /* + * IMS will not auto-mask if INT_ASSERTED is not set, and if it is + * not set, then the adapter didn't send an interrupt + */ + if (!(icr & E1000_ICR_INT_ASSERTED)) + return IRQ_NONE; + +#endif /* CONFIG_E1000E_NAPI */ + if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + hw->mac.get_link_status = 1; + /* + * ICH8 workaround-- Call gig speed drop workaround on cable + * disconnect (LSC) before accessing any PHY registers + */ + if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) && + (!(er32(STATUS) & E1000_STATUS_LU))) + e1000_gig_downshift_workaround_ich8lan(hw); + + /* + * 80003ES2LAN workaround-- + * For packet buffer work-around on link down event; + * disable receives here in the ISR and + * reset adapter in watchdog + */ + if (netif_carrier_ok(netdev) && + (adapter->flags & FLAG_RX_NEEDS_RESTART)) { + /* disable receives */ + rctl = er32(RCTL); + ew32(RCTL, rctl & ~E1000_RCTL_EN); + adapter->flags |= FLAG_RX_RESTART_NOW; + } + /* guard against interrupt when we're going down */ + if (!test_bit(__E1000_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); + } + +#ifdef CONFIG_E1000E_NAPI + if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + adapter->total_tx_bytes = 0; + adapter->total_tx_packets = 0; + adapter->total_rx_bytes = 0; + adapter->total_rx_packets = 0; + __netif_rx_schedule(netdev, &adapter->napi); + } +#else + adapter->total_tx_bytes = 0; + adapter->total_rx_bytes = 0; + adapter->total_tx_packets = 0; + adapter->total_rx_packets = 0; + + for (i = 0; i < E1000_MAX_INTR; i++) { + rx_cleaned = adapter->clean_rx(adapter); + tx_cleaned_complete = e1000_clean_tx_irq(adapter); + if (!rx_cleaned && tx_cleaned_complete) + break; + } + + if (likely(adapter->itr_setting & 3)) + e1000_set_itr(adapter); +#endif /* CONFIG_E1000E_NAPI */ + + return IRQ_HANDLED; +} + +#ifdef CONFIG_E1000E_MSIX +static irqreturn_t e1000_msix_other(int irq, void *data) +{ + struct net_device *netdev = data; + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 icr = er32(ICR); + + if (!(icr & E1000_ICR_INT_ASSERTED)) + { + ew32(IMS, E1000_IMS_OTHER); + return IRQ_NONE; + } + + if (icr & adapter->eiac_mask) + ew32(ICS, (icr & adapter->eiac_mask)); + + if (icr & E1000_ICR_OTHER) { + if (!(icr & E1000_ICR_LSC)) + goto no_link_interrupt; + hw->mac.get_link_status = 1; + /* guard against interrupt when we're going down */ + if (!test_bit(__E1000_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); + } + +no_link_interrupt: + ew32(IMS, E1000_IMS_LSC | E1000_IMS_OTHER); + + return IRQ_HANDLED; +} + + +#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER +static irqreturn_t e1000_intr_msix_tx(int irq, void *data) +{ + struct net_device *netdev = data; + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + struct e1000_ring *tx_ring = adapter->tx_ring; + + + adapter->total_tx_bytes = 0; + adapter->total_tx_packets = 0; + + if (!e1000_clean_tx_irq(adapter)) + /* Ring was not completely cleaned, so fire another interrupt */ + ew32(ICS, tx_ring->ims_val); + + return IRQ_HANDLED; +} + +#endif /* CONFIG_E1000E_SEPARATE_TX_HANDLER */ +static irqreturn_t e1000_intr_msix_rx(int irq, void *data) +{ + struct net_device *netdev = data; + struct e1000_adapter *adapter = netdev_priv(netdev); +#ifndef CONFIG_E1000E_NAPI + int i; + struct e1000_hw *hw = &adapter->hw; +#endif + + /* Write the ITR value calculated at the end of the + * previous interrupt. + */ + if (adapter->rx_ring->set_itr) { + writel(1000000000 / (adapter->rx_ring->itr_val * 256), + adapter->hw.hw_addr + adapter->rx_ring->itr_register); + adapter->rx_ring->set_itr = 0; + } + +#ifdef CONFIG_E1000E_NAPI + if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + adapter->total_rx_bytes = 0; + adapter->total_rx_packets = 0; +#ifndef CONFIG_E1000E_SEPARATE_TX_HANDLER + adapter->total_tx_bytes = 0; + adapter->total_tx_packets = 0; +#endif /* CONFIG_E1000E_SEPARATE_TX_HANDLER */ + __netif_rx_schedule(netdev, &adapter->napi); + } +#else + adapter->total_rx_bytes = 0; + adapter->total_rx_packets = 0; +#ifndef CONFIG_E1000E_SEPARATE_TX_HANDLER + adapter->total_tx_bytes = 0; + adapter->total_tx_packets = 0; +#endif + + for (i = 0; i < E1000_MAX_INTR; i++) { + int rx_cleaned = adapter->clean_rx(adapter); +#ifndef CONFIG_E1000E_SEPARATE_TX_HANDLER + int tx_cleaned_complete = e1000_clean_tx_irq(adapter); + if (!rx_cleaned && tx_cleaned_complete) +#else + if (!rx_cleaned) +#endif + goto out; + } + /* If we got here, the ring was not completely cleaned, + * so fire another interrupt. + */ + ew32(ICS, adapter->rx_ring->ims_val); + +out: +#endif /* CONFIG_E1000E_NAPI */ + return IRQ_HANDLED; +} + +/** + * e1000_configure_msix - Configure MSI-X hardware + * + * e1000_configure_msix sets up the hardware to properly + * generate MSI-X interrupts. + **/ +static void e1000_configure_msix(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_ring *tx_ring = adapter->tx_ring; + int vector = 0; + u32 ctrl_ext, ivar = 0; + + adapter->eiac_mask = 0; + + /* Workaround issue with spurious interrupts on 82574 in MSI-X mode */ + if (hw->mac.type == e1000_82574) { + u32 rfctl = er32(RFCTL); + rfctl |= E1000_RFCTL_ACK_DIS; + ew32(RFCTL, rfctl); + } + +#define E1000_IVAR_INT_ALLOC_VALID 0x8 + /* Configure Rx vector */ + rx_ring->ims_val = E1000_IMS_RXQ0; + adapter->eiac_mask |= rx_ring->ims_val; + if (rx_ring->itr_val) + writel(1000000000 / (rx_ring->itr_val * 256), + hw->hw_addr + rx_ring->itr_register); + else + writel(1, hw->hw_addr + rx_ring->itr_register); + ivar = E1000_IVAR_INT_ALLOC_VALID | vector; + + /* Configure Tx vector */ + tx_ring->ims_val = E1000_IMS_TXQ0; +#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER + vector++; + if (tx_ring->itr_val) + writel(1000000000 / (tx_ring->itr_val * 256), + hw->hw_addr + tx_ring->itr_register); + else + writel(1, hw->hw_addr + tx_ring->itr_register); +#else + rx_ring->ims_val |= tx_ring->ims_val; +#endif + adapter->eiac_mask |= tx_ring->ims_val; + ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 8); + + /* set vector for Other Causes, e.g. link changes */ + vector++; + ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 16); + if (rx_ring->itr_val) + writel(1000000000 / (rx_ring->itr_val * 256), + hw->hw_addr + E1000_EITR_82574(vector)); + else + writel(1, hw->hw_addr + E1000_EITR_82574(vector)); + + /* Cause Tx interrupts on every write back */ + ivar |= (1 << 31); + + ew32(IVAR, ivar); + + /* enable MSI-X PBA support */ + ctrl_ext = er32(CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_PBA_CLR; + + /* Auto-Mask Other interrupts upon ICR read */ + ew32(IAM, ~E1000_EIAC_MASK_82574 | E1000_IMS_OTHER); + ctrl_ext |= E1000_CTRL_EXT_EIAME; + ew32(CTRL_EXT, ctrl_ext); + e1e_flush(); +} + +void e1000_reset_interrupt_capability(struct e1000_adapter *adapter) +{ + if (adapter->msix_entries) { + pci_disable_msix(adapter->pdev); + kfree(adapter->msix_entries); + adapter->msix_entries = NULL; + } else if (adapter->flags & FLAG_MSI_ENABLED) { + pci_disable_msi(adapter->pdev); + adapter->flags &= ~FLAG_MSI_ENABLED; + } + + return; +} + +/** + * e1000_set_interrupt_capability - set MSI or MSI-X if supported + * + * Attempt to configure interrupts using the best available + * capabilities of the hardware and kernel. + **/ +void e1000_set_interrupt_capability(struct e1000_adapter *adapter) +{ + int err; + int numvecs, i; + + + switch (adapter->int_mode) { + case E1000E_INT_MODE_MSIX: + if (adapter->flags & FLAG_HAS_MSIX) { +#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER + numvecs = 3; /* RxQ0, TxQ0 and other */ +#else + numvecs = 2; /* RxQ0/TxQ0 and other */ +#endif + adapter->msix_entries = kcalloc(numvecs, + sizeof(struct msix_entry), + GFP_KERNEL); + if (adapter->msix_entries) { + for (i=0; i < numvecs; i++) + adapter->msix_entries[i].entry = i; + + err = pci_enable_msix(adapter->pdev, + adapter->msix_entries, + numvecs); + if (err == 0) + return; + } + /* MSI-X failed, so fall through and try MSI */ + e_err("Failed to initialize MSI-X interrupts. " + "Falling back to MSI interrupts.\n"); + e1000_reset_interrupt_capability(adapter); + } + adapter->int_mode = E1000E_INT_MODE_MSI; + /* Fall through */ + case E1000E_INT_MODE_MSI: + if (!pci_enable_msi(adapter->pdev)) { + adapter->flags |= FLAG_MSI_ENABLED; + } else { + adapter->int_mode = E1000E_INT_MODE_LEGACY; + e_err("Failed to initialize MSI interrupts. Falling " + "back to legacy interrupts.\n"); + } + /* Fall through */ + case E1000E_INT_MODE_LEGACY: + /* Don't do anything; this is the system default */ + break; + } + + return; +} + +/** + * e1000_request_msix - Initialize MSI-X interrupts + * + * e1000_request_msix allocates MSI-X vectors and requests interrupts from the + * kernel. + **/ +static int e1000_request_msix(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int err = 0, vector = 0; + + if (strlen(netdev->name) < (IFNAMSIZ - 5)) +#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER + sprintf(adapter->rx_ring->name, "%s-rx0", netdev->name); +#else + sprintf(adapter->rx_ring->name, "%s-Q0", netdev->name); +#endif + else + memcpy(adapter->rx_ring->name, netdev->name, IFNAMSIZ); + err = request_irq(adapter->msix_entries[vector].vector, + &e1000_intr_msix_rx, 0, adapter->rx_ring->name, + netdev); + if (err) + goto out; + adapter->rx_ring->itr_register = E1000_EITR_82574(vector); + adapter->rx_ring->itr_val = adapter->itr; + vector++; + +#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER + if (strlen(netdev->name) < (IFNAMSIZ - 5)) + sprintf(adapter->tx_ring->name, "%s-tx0", netdev->name); + else + memcpy(adapter->tx_ring->name, netdev->name, IFNAMSIZ); + err = request_irq(adapter->msix_entries[vector].vector, + &e1000_intr_msix_tx, 0, adapter->tx_ring->name, + netdev); + if (err) + goto out; + adapter->tx_ring->itr_register = E1000_EITR_82574(vector); + adapter->tx_ring->itr_val = adapter->itr; + vector++; + +#endif /* CONFIG_E1000E_SEPARATE_TX_HANDLER */ + err = request_irq(adapter->msix_entries[vector].vector, + &e1000_msix_other, 0, netdev->name, netdev); + if (err) + goto out; + + e1000_configure_msix(adapter); + return 0; +out: + return err; +} + +#endif /* CONFIG_E1000E_MSIX */ +/** + * e1000_alloc_queues - Allocate memory for all rings + * @adapter: board private structure to initialize + **/ +static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter) +{ + adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); + if (!adapter->tx_ring) + goto err; + + adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); + if (!adapter->rx_ring) + goto err; + + return 0; +err: + e_err("Unable to allocate memory for queues\n"); + kfree(adapter->rx_ring); + kfree(adapter->tx_ring); + return -ENOMEM; +} + +/** + * e1000_request_irq - initialize interrupts + * + * Attempts to configure interrupts using the best available + * capabilities of the hardware and kernel. + **/ +static int e1000_request_irq(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int err; +#ifdef CONFIG_E1000E_MSIX + + if (adapter->msix_entries) { + err = e1000_request_msix(adapter); + if (!err) + return err; + /* fall back to MSI */ + e1000_reset_interrupt_capability(adapter); + adapter->int_mode = E1000E_INT_MODE_MSI; + e1000_set_interrupt_capability(adapter); + } + if (adapter->flags & FLAG_MSI_ENABLED) { + err = request_irq(adapter->pdev->irq, &e1000_intr_msi, 0, + netdev->name, netdev); + if (!err) + return err; + + /* fall back to legacy interrupt */ + e1000_reset_interrupt_capability(adapter); + adapter->int_mode = E1000E_INT_MODE_LEGACY; + } + + err = request_irq(adapter->pdev->irq, &e1000_intr, IRQF_SHARED, + netdev->name, netdev); + if (err) + e_err("Unable to allocate interrupt, Error: %d\n", err); +#else + int irq_flags = IRQF_SHARED; + + if (!(adapter->flags & FLAG_MSI_TEST_FAILED)) { + err = pci_enable_msi(adapter->pdev); + if (!err) { + adapter->flags |= FLAG_MSI_ENABLED; + irq_flags = 0; + } + } + + err = request_irq(adapter->pdev->irq, + ((adapter->flags & FLAG_MSI_ENABLED) ? + &e1000_intr_msi : &e1000_intr), + irq_flags, netdev->name, netdev); + if (err) { + if (adapter->flags & FLAG_MSI_ENABLED) { + pci_disable_msi(adapter->pdev); + adapter->flags &= ~FLAG_MSI_ENABLED; + } + e_err("Unable to allocate interrupt, Error: %d\n", err); + } +#endif /* CONFIG_E1000E_MSIX */ + + return err; +} + +static void e1000_free_irq(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + +#ifdef CONFIG_E1000E_MSIX + if (adapter->msix_entries) { + int vector = 0; + + free_irq(adapter->msix_entries[vector].vector, netdev); + vector++; + +#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER + free_irq(adapter->msix_entries[vector].vector, netdev); + vector++; + +#endif + /* Other Causes interrupt vector */ + free_irq(adapter->msix_entries[vector].vector, netdev); + return; + } + +#endif /* CONFIG_E1000E_MSIX */ + free_irq(adapter->pdev->irq, netdev); +#ifndef CONFIG_E1000E_MSIX + if (adapter->flags & FLAG_MSI_ENABLED) { + pci_disable_msi(adapter->pdev); + adapter->flags &= ~FLAG_MSI_ENABLED; + } +#endif +} + +/** + * e1000_irq_disable - Mask off interrupt generation on the NIC + **/ +static void e1000_irq_disable(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + ew32(IMC, ~0); +#ifdef CONFIG_E1000E_MSIX + if (adapter->msix_entries) { + ew32(EIAC_82574, 0); + } +#endif /* CONFIG_E1000E_MSIX */ + e1e_flush(); + synchronize_irq(adapter->pdev->irq); +} + +/** + * e1000_irq_enable - Enable default interrupt generation settings + **/ +static void e1000_irq_enable(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; +#ifdef CONFIG_E1000E_MSIX + + if (adapter->msix_entries) { + ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574); + ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC); + } else { + ew32(IMS, IMS_ENABLE_MASK); + } +#else + ew32(IMS, IMS_ENABLE_MASK); +#endif /* CONFIG_E1000E_MSIX */ +} + +/** + * e1000_get_hw_control - get control of the h/w from f/w + * @adapter: address of board private structure + * + * e1000_get_hw_control sets {CTRL_EXT|SWSM}:DRV_LOAD bit. + * For ASF and Pass Through versions of f/w this means that + * the driver is loaded. For AMT version (only with 82573) + * of the f/w this means that the network i/f is open. + **/ +static void e1000_get_hw_control(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl_ext; + u32 swsm; + + /* Let firmware know the driver has taken over */ + if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) { + swsm = er32(SWSM); + ew32(SWSM, swsm | E1000_SWSM_DRV_LOAD); + } else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) { + ctrl_ext = er32(CTRL_EXT); + ew32(CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); + } +} + +/** + * e1000_release_hw_control - release control of the h/w to f/w + * @adapter: address of board private structure + * + * e1000_release_hw_control resets {CTRL_EXT|SWSM}:DRV_LOAD bit. + * For ASF and Pass Through versions of f/w this means that the + * driver is no longer loaded. For AMT version (only with 82573) i + * of the f/w this means that the network i/f is closed. + * + **/ +static void e1000_release_hw_control(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl_ext; + u32 swsm; + + /* Let firmware taken over control of h/w */ + if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) { + swsm = er32(SWSM); + ew32(SWSM, swsm & ~E1000_SWSM_DRV_LOAD); + } else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) { + ctrl_ext = er32(CTRL_EXT); + ew32(CTRL_EXT, ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); + } +} + +#ifdef CONFIG_E1000E_NAPI +/** + * e1000_poll - NAPI Rx polling callback + * @napi: struct associated with this polling callback + * @budget: amount of packets driver is allowed to process this poll + **/ +static int e1000_poll(struct napi_struct *napi, int budget) +{ + struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, + napi); + struct net_device *netdev = adapter->netdev; + int tx_clean_complete = 1, work_done = 0; +#ifdef CONFIG_E1000E_MSIX + struct e1000_hw *hw = &adapter->hw; + + if (adapter->msix_entries && + !(adapter->rx_ring->ims_val & adapter->tx_ring->ims_val)) + goto clean_rx; + +#endif + /* + * e1000_poll is called per-cpu. This lock protects + * tx_ring from being cleaned by multiple cpus + * simultaneously. A failure obtaining the lock means + * tx_ring is currently being cleaned anyway. + */ + if (spin_trylock(&adapter->tx_queue_lock)) { + tx_clean_complete &= e1000_clean_tx_irq(adapter); + spin_unlock(&adapter->tx_queue_lock); + } + +#ifdef CONFIG_E1000E_MSIX +clean_rx: +#endif + adapter->clean_rx(adapter, &work_done, budget); + + /* If Tx completed and all Rx work done, exit the polling mode */ + if ((tx_clean_complete && (work_done == 0)) || !netif_running(netdev)) { + netif_rx_complete(netdev, napi); + if (adapter->itr_setting & 3) + e1000_set_itr(adapter); + if (!test_bit(__E1000_DOWN, &adapter->state)) { +#ifdef CONFIG_E1000E_MSIX + if (adapter->msix_entries) + ew32(IMS, adapter->rx_ring->ims_val); + else +#endif + e1000_irq_enable(adapter); + } + return 0; + } + + if (!tx_clean_complete) + work_done = budget; + + return work_done; +} + +#endif /* CONFIG_E1000E_NAPI */ +static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 vfta, index; + struct net_device *v_netdev; + + /* don't update vlan cookie if already programmed */ + if ((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && + (vid == adapter->mng_vlan_id)) + return; + /* add VID to filter table */ + index = (vid >> 5) & 0x7F; + vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index); + vfta |= (1 << (vid & 0x1F)); + if (hw->mac.ops.write_vfta) + hw->mac.ops.write_vfta(hw, index, vfta); + /* + * Copy feature flags from netdev to the vlan netdev for this vid. + * This allows things like TSO to bubble down to our vlan device. + */ + v_netdev = vlan_group_get_device(adapter->vlgrp, vid); + v_netdev->features |= adapter->netdev->features; + vlan_group_set_device(adapter->vlgrp, vid, v_netdev); +} + +static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 vfta, index; + + if (!test_bit(__E1000_DOWN, &adapter->state)) + e1000_irq_disable(adapter); + vlan_group_set_device(adapter->vlgrp, vid, NULL); + if (!test_bit(__E1000_DOWN, &adapter->state)) + e1000_irq_enable(adapter); + + if ((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && + (vid == adapter->mng_vlan_id)) { + /* release control to f/w */ + e1000_release_hw_control(adapter); + return; + } + + /* remove VID from filter table */ + index = (vid >> 5) & 0x7F; + vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index); + vfta &= ~(1 << (vid & 0x1F)); + if (hw->mac.ops.write_vfta) + hw->mac.ops.write_vfta(hw, index, vfta); +} + +static void e1000_update_mng_vlan(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + u16 vid = adapter->hw.mng_cookie.vlan_id; + u16 old_vid = adapter->mng_vlan_id; + + if (!adapter->vlgrp) + return; + + if (!vlan_group_get_device(adapter->vlgrp, vid)) { + adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; + if (adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) { + e1000_vlan_rx_add_vid(netdev, vid); + adapter->mng_vlan_id = vid; + } + + if ((old_vid != (u16)E1000_MNG_VLAN_NONE) && + (vid != old_vid) && + !vlan_group_get_device(adapter->vlgrp, old_vid)) + e1000_vlan_rx_kill_vid(netdev, old_vid); + } else { + adapter->mng_vlan_id = vid; + } +} + + +static void e1000_vlan_rx_register(struct net_device *netdev, + struct vlan_group *grp) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 ctrl, rctl; + + if (!test_bit(__E1000_DOWN, &adapter->state)) + e1000_irq_disable(adapter); + adapter->vlgrp = grp; + + if (grp) { + /* enable VLAN tag insert/strip */ + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_VME; + ew32(CTRL, ctrl); + + if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { + /* enable VLAN receive filtering */ + rctl = er32(RCTL); + rctl |= E1000_RCTL_VFE; + rctl &= ~E1000_RCTL_CFIEN; + ew32(RCTL, rctl); + e1000_update_mng_vlan(adapter); + } + } else { + /* disable VLAN tag insert/strip */ + ctrl = er32(CTRL); + ctrl &= ~E1000_CTRL_VME; + ew32(CTRL, ctrl); + + if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { + /* disable VLAN filtering */ + rctl = er32(RCTL); + rctl &= ~E1000_RCTL_VFE; + ew32(RCTL, rctl); + if (adapter->mng_vlan_id != + (u16)E1000_MNG_VLAN_NONE) { + e1000_vlan_rx_kill_vid(netdev, + adapter->mng_vlan_id); + adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; + } + } + } + + if (!test_bit(__E1000_DOWN, &adapter->state)) + e1000_irq_enable(adapter); +} + +static void e1000_restore_vlan(struct e1000_adapter *adapter) +{ + u16 vid; + + e1000_vlan_rx_register(adapter->netdev, adapter->vlgrp); + + if (!adapter->vlgrp) + return; + + for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { + if (!vlan_group_get_device(adapter->vlgrp, vid)) + continue; + e1000_vlan_rx_add_vid(adapter->netdev, vid); + } +} + +static void e1000_init_manageability(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 manc, manc2h; + + if (!(adapter->flags & FLAG_MNG_PT_ENABLED)) + return; + + manc = er32(MANC); + + /* + * enable receiving management packets to the host. this will probably + * generate destination unreachable messages from the host OS, but + * the packets will be handled on SMBUS + */ + manc |= E1000_MANC_EN_MNG2HOST; + manc2h = er32(MANC2H); +#define E1000_MNG2HOST_PORT_623 (1 << 5) +#define E1000_MNG2HOST_PORT_664 (1 << 6) + manc2h |= E1000_MNG2HOST_PORT_623; + manc2h |= E1000_MNG2HOST_PORT_664; + ew32(MANC2H, manc2h); + ew32(MANC, manc); +} + +/** + * e1000_configure_tx - Configure 8254x Transmit Unit after Reset + * @adapter: board private structure + * + * Configure the Tx unit of the MAC after a reset. + **/ +static void e1000_configure_tx(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_ring *tx_ring = adapter->tx_ring; + u64 tdba; + u32 tdlen, tctl, tipg, tarc; + u32 ipgr1, ipgr2; + + /* Setup the HW Tx Head and Tail descriptor pointers */ + tdba = tx_ring->dma; + tdlen = tx_ring->count * sizeof(struct e1000_tx_desc); + ew32(TDBAL(0), (tdba & DMA_32BIT_MASK)); + ew32(TDBAH(0), (tdba >> 32)); + ew32(TDLEN(0), tdlen); + ew32(TDH(0), 0); + ew32(TDT(0), 0); + tx_ring->head = E1000_TDH(0); + tx_ring->tail = E1000_TDT(0); + + /* Set the default values for the Tx Inter Packet Gap timer */ + tipg = DEFAULT_82543_TIPG_IPGT_COPPER; /* 8 */ + ipgr1 = DEFAULT_82543_TIPG_IPGR1; /* 8 */ + ipgr2 = DEFAULT_82543_TIPG_IPGR2; /* 6 */ + + if (adapter->flags & FLAG_TIPG_MEDIUM_FOR_80003ESLAN) + ipgr2 = DEFAULT_80003ES2LAN_TIPG_IPGR2; /* 7 */ + + tipg |= ipgr1 << E1000_TIPG_IPGR1_SHIFT; + tipg |= ipgr2 << E1000_TIPG_IPGR2_SHIFT; + ew32(TIPG, tipg); + + /* Set the Tx Interrupt Delay register */ + ew32(TIDV, adapter->tx_int_delay); + /* Tx irq moderation */ + ew32(TADV, adapter->tx_abs_int_delay); + + /* Program the Transmit Control Register */ + tctl = er32(TCTL); + tctl &= ~E1000_TCTL_CT; + tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC | + (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); + + if (adapter->flags & FLAG_TARC_SPEED_MODE_BIT) { + tarc = er32(TARC(0)); + /* + * set the speed mode bit, we'll clear it if we're not at + * gigabit link later + */ +#define SPEED_MODE_BIT (1 << 21) + tarc |= SPEED_MODE_BIT; + ew32(TARC(0), tarc); + } + + /* errata: program both queues to unweighted RR */ + if (adapter->flags & FLAG_TARC_SET_BIT_ZERO) { + tarc = er32(TARC(0)); + tarc |= 1; + ew32(TARC(0), tarc); + tarc = er32(TARC(1)); + tarc |= 1; + ew32(TARC(1), tarc); + } + + hw->mac.ops.config_collision_dist(hw); + + /* Setup Transmit Descriptor Settings for eop descriptor */ + adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS; + + /* only set IDE if we are delaying interrupts using the timers */ + if (adapter->tx_int_delay) + adapter->txd_cmd |= E1000_TXD_CMD_IDE; + + /* enable Report Status bit */ + adapter->txd_cmd |= E1000_TXD_CMD_RS; + + ew32(TCTL, tctl); + + adapter->tx_queue_len = adapter->netdev->tx_queue_len; +} + +/** + * e1000_setup_rctl - configure the receive control registers + * @adapter: Board private structure + **/ +#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \ + (((S) & (PAGE_SIZE - 1)) ? 1 : 0)) +static void e1000_setup_rctl(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 rctl, rfctl; + u32 psrctl = 0; + u32 pages = 0; + + /* Program MC offset vector base */ + rctl = er32(RCTL); + rctl &= ~(3 << E1000_RCTL_MO_SHIFT); + rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | + E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | + (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); + + /* Do not Store bad packets */ + rctl &= ~E1000_RCTL_SBP; + + /* Enable Long Packet receive */ + if (adapter->netdev->mtu <= ETH_DATA_LEN) + rctl &= ~E1000_RCTL_LPE; + else + rctl |= E1000_RCTL_LPE; + + /* Enable hardware CRC frame stripping */ + rctl |= E1000_RCTL_SECRC; + + /* Setup buffer sizes */ + rctl &= ~E1000_RCTL_SZ_4096; + rctl |= E1000_RCTL_BSEX; + switch (adapter->rx_buffer_len) { + case 256: + rctl |= E1000_RCTL_SZ_256; + rctl &= ~E1000_RCTL_BSEX; + break; + case 512: + rctl |= E1000_RCTL_SZ_512; + rctl &= ~E1000_RCTL_BSEX; + break; + case 1024: + rctl |= E1000_RCTL_SZ_1024; + rctl &= ~E1000_RCTL_BSEX; + break; + case 2048: + default: + rctl |= E1000_RCTL_SZ_2048; + rctl &= ~E1000_RCTL_BSEX; + break; + case 4096: + rctl |= E1000_RCTL_SZ_4096; + break; + case 8192: + rctl |= E1000_RCTL_SZ_8192; + break; + case 16384: + rctl |= E1000_RCTL_SZ_16384; + break; + } + + /* + * 82571 and greater support packet-split where the protocol + * header is placed in skb->data and the packet data is + * placed in pages hanging off of skb_shinfo(skb)->nr_frags. + * In the case of a non-split, skb->data is linearly filled, + * followed by the page buffers. Therefore, skb->data is + * sized to hold the largest protocol header. + * + * allocations using alloc_page take too long for regular MTU + * so only enable packet split for jumbo frames + * + * Using pages when the page size is greater than 16k wastes + * a lot of memory, since we allocate 3 pages at all times + * per packet. + */ + pages = PAGE_USE_COUNT(adapter->netdev->mtu); + if (!(adapter->flags & FLAG_IS_ICH) && (pages <= 3) && + (PAGE_SIZE <= 16384) && (rctl & E1000_RCTL_LPE)) + adapter->rx_ps_pages = pages; + else + adapter->rx_ps_pages = 0; + + if (adapter->rx_ps_pages) { + /* Configure extra packet-split registers */ + rfctl = er32(RFCTL); + rfctl |= E1000_RFCTL_EXTEN; + /* + * disable packet split support for IPv6 extension headers, + * because some malformed IPv6 headers can hang the Rx + */ + rfctl |= (E1000_RFCTL_IPV6_EX_DIS | + E1000_RFCTL_NEW_IPV6_EXT_DIS); + + ew32(RFCTL, rfctl); + + /* Enable Packet split descriptors */ + rctl |= E1000_RCTL_DTYP_PS; + + psrctl |= adapter->rx_ps_bsize0 >> + E1000_PSRCTL_BSIZE0_SHIFT; + + switch (adapter->rx_ps_pages) { + case 3: + psrctl |= PAGE_SIZE << + E1000_PSRCTL_BSIZE3_SHIFT; + case 2: + psrctl |= PAGE_SIZE << + E1000_PSRCTL_BSIZE2_SHIFT; + case 1: + psrctl |= PAGE_SIZE >> + E1000_PSRCTL_BSIZE1_SHIFT; + break; + } + + ew32(PSRCTL, psrctl); + } + + ew32(RCTL, rctl); + /* just started the receive unit, no need to restart */ + adapter->flags &= ~FLAG_RX_RESTART_NOW; +} + +/** + * e1000_configure_rx - Configure Receive Unit after Reset + * @adapter: board private structure + * + * Configure the Rx unit of the MAC after a reset. + **/ +static void e1000_configure_rx(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_ring *rx_ring = adapter->rx_ring; + u64 rdba; + u32 rdlen, rctl, rxcsum, ctrl_ext; + + if (adapter->rx_ps_pages) { + /* this is a 32 byte descriptor */ + rdlen = rx_ring->count * + sizeof(union e1000_rx_desc_packet_split); + adapter->clean_rx = e1000_clean_rx_irq_ps; + adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps; +#ifdef CONFIG_E1000E_NAPI + } else if (adapter->netdev->mtu > ETH_FRAME_LEN + ETH_FCS_LEN) { + rdlen = rx_ring->count * sizeof(struct e1000_rx_desc); + adapter->clean_rx = e1000_clean_jumbo_rx_irq; + adapter->alloc_rx_buf = e1000_alloc_jumbo_rx_buffers; +#endif + } else { + rdlen = rx_ring->count * sizeof(struct e1000_rx_desc); + adapter->clean_rx = e1000_clean_rx_irq; + adapter->alloc_rx_buf = e1000_alloc_rx_buffers; + } + + /* disable receives while setting up the descriptors */ + rctl = er32(RCTL); + ew32(RCTL, rctl & ~E1000_RCTL_EN); + e1e_flush(); + msleep(10); + + /* set the Receive Delay Timer Register */ + ew32(RDTR, adapter->rx_int_delay); + + /* irq moderation */ + ew32(RADV, adapter->rx_abs_int_delay); + if (adapter->itr_setting != 0) + ew32(ITR, 1000000000 / (adapter->itr * 256)); + + ctrl_ext = er32(CTRL_EXT); + /* Reset delay timers after every interrupt */ + ctrl_ext |= E1000_CTRL_EXT_INT_TIMER_CLR; +#ifdef CONFIG_E1000E_NAPI + /* Auto-Mask interrupts upon ICR access */ + ctrl_ext |= E1000_CTRL_EXT_IAME; + ew32(IAM, 0xffffffff); +#endif + ew32(CTRL_EXT, ctrl_ext); + e1e_flush(); + + /* + * Setup the HW Rx Head and Tail Descriptor Pointers and + * the Base and Length of the Rx Descriptor Ring + */ + rdba = rx_ring->dma; + ew32(RDBAL(0), (rdba & DMA_32BIT_MASK)); + ew32(RDBAH(0), (rdba >> 32)); + ew32(RDLEN(0), rdlen); + ew32(RDH(0), 0); + ew32(RDT(0), 0); + rx_ring->head = E1000_RDH(0); + rx_ring->tail = E1000_RDT(0); + + /* Enable Receive Checksum Offload for TCP and UDP */ + rxcsum = er32(RXCSUM); + if (adapter->flags & FLAG_RX_CSUM_ENABLED) { + rxcsum |= E1000_RXCSUM_TUOFL; + + /* + * IPv4 payload checksum for UDP fragments must be + * used in conjunction with packet-split. + */ + if (adapter->rx_ps_pages) + rxcsum |= E1000_RXCSUM_IPPCSE; + } else { + rxcsum &= ~E1000_RXCSUM_TUOFL; + /* no need to clear IPPCSE as it defaults to 0 */ + } + ew32(RXCSUM, rxcsum); + + /* + * Enable early receives on supported devices, only takes effect when + * packet size is equal or larger than the specified value (in 8 byte + * units), e.g. using jumbo frames when setting to E1000_ERT_2048 + */ + if ((adapter->flags & FLAG_HAS_ERT) && + (adapter->netdev->mtu > ETH_DATA_LEN)) { + u32 rxdctl = er32(RXDCTL(0)); + ew32(RXDCTL(0), rxdctl | 0x3); + ew32(ERT, E1000_ERT_2048 | (1 << 13)); + /* + * With jumbo frames and early-receive enabled, excessive + * C4->C2 latencies result in dropped transactions. + */ + pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, + e1000e_driver_name, 55); + } else { + pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, + e1000e_driver_name, + PM_QOS_DEFAULT_VALUE); + } + + /* Enable Receives */ + ew32(RCTL, rctl); +} + +/** + * e1000_set_multi - Multicast and Promiscuous mode set + * @netdev: network interface device structure + * + * The set_multi entry point is called whenever the multicast address + * list or the network interface flags are updated. This routine is + * responsible for configuring the hardware for proper multicast, + * promiscuous mode, and all-multi behavior. + **/ +static void e1000_set_multi(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + struct e1000_mac_info *mac = &hw->mac; + struct dev_mc_list *mc_ptr; + u8 *mta_list; + u32 rctl; + int i; + + /* Check for Promiscuous and All Multicast modes */ + + rctl = er32(RCTL); + + if (netdev->flags & IFF_PROMISC) { + rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); + } else if (netdev->flags & IFF_ALLMULTI) { + rctl |= E1000_RCTL_MPE; + rctl &= ~E1000_RCTL_UPE; + } else { + rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); + } + + ew32(RCTL, rctl); + + if (netdev->mc_count) { + mta_list = kmalloc(netdev->mc_count * 6, GFP_ATOMIC); + if (!mta_list) + return; + + /* prepare a packed array of only addresses. */ + mc_ptr = netdev->mc_list; + + for (i = 0; i < netdev->mc_count; i++) { + if (!mc_ptr) + break; + memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, + ETH_ALEN); + mc_ptr = mc_ptr->next; + } + + hw->mac.ops.update_mc_addr_list(hw, mta_list, i, 1, + mac->rar_entry_count); + kfree(mta_list); + } else { + /* + * if we're called from probe, we might not have + * anything to do here, so clear out the list + */ + hw->mac.ops.update_mc_addr_list(hw, NULL, 0, 1, + mac->rar_entry_count); + } +} + +/** + * e1000_configure - configure the hardware for Rx and Tx + * @adapter: private board structure + **/ +static void e1000_configure(struct e1000_adapter *adapter) +{ + e1000_set_multi(adapter->netdev); + + e1000_restore_vlan(adapter); + e1000_init_manageability(adapter); + + e1000_configure_tx(adapter); + e1000_setup_rctl(adapter); + e1000_configure_rx(adapter); + adapter->alloc_rx_buf(adapter, e1000_desc_unused(adapter->rx_ring)); +} + +/** + * e1000e_reset - bring the hardware into a known good state + * + * This function boots the hardware and enables some settings that + * require a configuration cycle of the hardware - those cannot be + * set/changed during runtime. After reset the device needs to be + * properly configured for Rx, Tx etc. + */ +void e1000_reset(struct e1000_adapter *adapter) +{ + struct e1000_mac_info *mac = &adapter->hw.mac; + struct e1000_fc_info *fc = &adapter->hw.fc; + struct e1000_hw *hw = &adapter->hw; + u32 tx_space, min_tx_space, min_rx_space; + u32 pba = adapter->pba; + u16 hwm; + + /* reset Packet Buffer Allocation to default */ + ew32(PBA, pba); + + if (adapter->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN ) { + /* + * To maintain wire speed transmits, the Tx FIFO should be + * large enough to accommodate two full transmit packets, + * rounded up to the next 1KB and expressed in KB. Likewise, + * the Rx FIFO should be large enough to accommodate at least + * one full receive packet and is similarly rounded up and + * expressed in KB. + */ + pba = er32(PBA); + /* upper 16 bits has Tx packet buffer allocation size in KB */ + tx_space = pba >> 16; + /* lower 16 bits has Rx packet buffer allocation size in KB */ + pba &= 0xffff; + /* + * the Tx fifo also stores 16 bytes of information about the tx + * but don't include ethernet FCS because hardware appends it + */ + min_tx_space = (adapter->max_frame_size + + sizeof(struct e1000_tx_desc) - + ETH_FCS_LEN) * 2; + min_tx_space = ALIGN(min_tx_space, 1024); + min_tx_space >>= 10; + /* software strips receive CRC, so leave room for it */ + min_rx_space = adapter->max_frame_size; + min_rx_space = ALIGN(min_rx_space, 1024); + min_rx_space >>= 10; + + /* + * If current Tx allocation is less than the min Tx FIFO size, + * and the min Tx FIFO size is less than the current Rx FIFO + * allocation, take space away from current Rx allocation + */ + if ((tx_space < min_tx_space) && + ((min_tx_space - tx_space) < pba)) { + pba -= min_tx_space - tx_space; + + /* + * if short on Rx space, Rx wins and must trump tx + * adjustment or use Early Receive if available + */ + if ((pba < min_rx_space) && + (!(adapter->flags & FLAG_HAS_ERT))) + /* ERT enabled in e1000_configure_rx */ + pba = min_rx_space; + } + + ew32(PBA, pba); + } + + + /* + * flow control settings + * + * The high water mark must be low enough to fit one full frame + * (or the size used for early receive) above it in the Rx FIFO. + * Set it to the lower of: + * - 90% of the Rx FIFO size, and + * - the full Rx FIFO size minus the early receive size (for parts + * with ERT support assuming ERT set to E1000_ERT_2048), or + * - the full Rx FIFO size minus one full frame + */ + if (adapter->flags & FLAG_HAS_ERT) + hwm = min(((pba << 10) * 9 / 10), + ((pba << 10) - (E1000_ERT_2048 << 3))); + else + hwm = min(((pba << 10) * 9 / 10), + ((pba << 10) - adapter->max_frame_size)); + + fc->high_water = hwm & 0xFFF8; /* 8-byte granularity */ + fc->low_water = fc->high_water - 8; + + if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME) + fc->pause_time = 0xFFFF; + else + fc->pause_time = E1000_FC_PAUSE_TIME; + fc->send_xon = 1; + fc->type = fc->original_type; + + /* Allow time for pending master requests to run */ + mac->ops.reset_hw(hw); + + /* + * For parts with AMT enabled, let the firmware know + * that the network interface is in control + */ + if (adapter->flags & FLAG_HAS_AMT) + e1000_get_hw_control(adapter); + + ew32(WUC, 0); + + if (mac->ops.init_hw(hw)) + e_err("Hardware Error\n"); + + e1000_update_mng_vlan(adapter); + + /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */ + ew32(VET, ETH_P_8021Q); + + e1000_reset_adaptive_generic(hw); + + if (!hw->phy.ops.get_info) + return; + + hw->phy.ops.get_info(hw); + + if (!(adapter->flags & FLAG_SMART_POWER_DOWN)) { + u16 phy_data = 0; + /* + * speed up time to link by disabling smart power down, ignore + * the return value of this function because there is nothing + * different we would do if it failed + */ + hw->phy.ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data); + phy_data &= ~IGP02E1000_PM_SPD; + hw->phy.ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data); + } +} + +int e1000_up(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + /* hardware has been reset, we need to reload some things */ + e1000_configure(adapter); + + clear_bit(__E1000_DOWN, &adapter->state); + +#ifdef CONFIG_E1000E_NAPI + napi_enable(&adapter->napi); +#endif +#ifdef CONFIG_E1000E_MSIX + if (adapter->msix_entries) + e1000_configure_msix(adapter); +#endif /* CONFIG_E1000E_MSIX */ + e1000_irq_enable(adapter); + + /* fire a link change interrupt to start the watchdog */ + ew32(ICS, E1000_ICS_LSC); + return 0; +} + +void e1000_down(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct e1000_hw *hw = &adapter->hw; + u32 tctl, rctl; + + /* + * signal that we're down so the interrupt handler does not + * reschedule our watchdog timer + */ + set_bit(__E1000_DOWN, &adapter->state); + + /* disable receives in the hardware */ + rctl = er32(RCTL); + ew32(RCTL, rctl & ~E1000_RCTL_EN); + /* flush and sleep below */ + + netif_stop_queue(netdev); + + /* disable transmits in the hardware */ + tctl = er32(TCTL); + tctl &= ~E1000_TCTL_EN; + ew32(TCTL, tctl); + /* flush both disables and wait for them to finish */ + e1e_flush(); + msleep(10); + +#ifdef CONFIG_E1000E_NAPI + napi_disable(&adapter->napi); +#endif + + e1000_irq_disable(adapter); + + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_info_timer); + + netdev->tx_queue_len = adapter->tx_queue_len; + netif_carrier_off(netdev); + adapter->link_speed = 0; + adapter->link_duplex = 0; + + e1000_reset(adapter); + e1000_clean_tx_ring(adapter); + e1000_clean_rx_ring(adapter); + + /* + * TODO: for power management, we could drop the link and + * pci_disable_device here. + */ +} + +void e1000_reinit_locked(struct e1000_adapter *adapter) +{ + might_sleep(); + while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) + msleep(1); + e1000_down(adapter); + e1000_up(adapter); + clear_bit(__E1000_RESETTING, &adapter->state); +} + +/** + * e1000_sw_init - Initialize general software structures (struct e1000_adapter) + * @adapter: board private structure to initialize + * + * e1000_sw_init initializes the Adapter private data structure. + * Fields are initialized based on PCI device information and + * OS network device settings (MTU size). + **/ +static int __devinit e1000_sw_init(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + s32 rc; + + adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN; + adapter->rx_ps_bsize0 = 128; + adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; + adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; + + /* Set various function pointers */ + adapter->ei->init_ops(&adapter->hw); + + rc = adapter->hw.mac.ops.init_params(&adapter->hw); + if (rc) + return rc; + + rc = adapter->hw.nvm.ops.init_params(&adapter->hw); + if (rc) + return rc; + + rc = adapter->hw.phy.ops.init_params(&adapter->hw); + if (rc) + return rc; + +#ifdef CONFIG_E1000E_MSIX + e1000_set_interrupt_capability(adapter); + +#endif /* CONFIG_E1000E_MSIX */ + if (e1000_alloc_queues(adapter)) + return -ENOMEM; + + spin_lock_init(&adapter->tx_queue_lock); + + /* Explicitly disable IRQ since the NIC can be in any state. */ + e1000_irq_disable(adapter); + + spin_lock_init(&adapter->stats_lock); + + set_bit(__E1000_DOWN, &adapter->state); + return 0; +} + +/** + * e1000_intr_msi_test - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + **/ +static irqreturn_t e1000_intr_msi_test(int irq, void *data) +{ + struct net_device *netdev = data; + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 icr = er32(ICR); + + e_dbg("icr is %08X\n", icr); + if (icr & E1000_ICR_RXSEQ) { + adapter->flags &= ~FLAG_MSI_TEST_FAILED; + wmb(); + } + + return IRQ_HANDLED; +} + +/** + * e1000_test_msi_interrupt - Returns 0 for successful test + * @adapter: board private struct + * + * code flow taken from tg3.c + **/ +static int e1000_test_msi_interrupt(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct e1000_hw *hw = &adapter->hw; + int err; + + /* poll_enable hasn't been called yet, so don't need disable */ + /* clear any pending events */ + er32(ICR); + + /* free the real vector and request a test handler */ + e1000_free_irq(adapter); +#ifdef CONFIG_E1000E_MSIX + e1000_reset_interrupt_capability(adapter); +#endif + + /* Assume that the test fails, if it succeeds then the test + * MSI irq handler will unset this flag */ + adapter->flags |= FLAG_MSI_TEST_FAILED; + + err = pci_enable_msi(adapter->pdev); + if (err) + goto msi_test_failed; + + err = request_irq(adapter->pdev->irq, &e1000_intr_msi_test, 0, + netdev->name, netdev); + if (err) { + pci_disable_msi(adapter->pdev); + goto msi_test_failed; + } + + wmb(); + + e1000_irq_enable(adapter); + + /* fire an unusual interrupt on the test handler */ + ew32(ICS, E1000_ICS_RXSEQ); + e1e_flush(); + msleep(50); + + e1000_irq_disable(adapter); + + rmb(); + + if (adapter->flags & FLAG_MSI_TEST_FAILED) { +#ifdef CONFIG_E1000E_MSIX + adapter->int_mode = E1000E_INT_MODE_LEGACY; +#endif + err = -EIO; + e_info("MSI interrupt test failed!\n"); + } + + free_irq(adapter->pdev->irq, netdev); + pci_disable_msi(adapter->pdev); + + if (err == -EIO) + goto msi_test_failed; + + /* okay so the test worked, restore settings */ + e_dbg("MSI interrupt test succeeded!\n"); +msi_test_failed: +#ifdef CONFIG_E1000E_MSIX + e1000_set_interrupt_capability(adapter); +#else + /* restore the original vector, even if it failed */ +#endif + e1000_request_irq(adapter); + return err; +} + +/** + * e1000_test_msi - Returns 0 if MSI test succeeds or INTx mode is restored + * @adapter: board private struct + * + * code flow taken from tg3.c, called with e1000 interrupts disabled. + **/ +static int e1000_test_msi(struct e1000_adapter *adapter) +{ + int err; + u16 pci_cmd; + + if (!(adapter->flags & FLAG_MSI_ENABLED)) + return 0; + + /* disable SERR in case the MSI write causes a master abort */ + pci_read_config_word(adapter->pdev, PCI_COMMAND, &pci_cmd); + pci_write_config_word(adapter->pdev, PCI_COMMAND, + pci_cmd & ~PCI_COMMAND_SERR); + + err = e1000_test_msi_interrupt(adapter); + + /* restore previous setting of command word */ + pci_write_config_word(adapter->pdev, PCI_COMMAND, pci_cmd); + + /* success ! */ + if (!err) + return 0; + + /* EIO means MSI test failed */ + if (err != -EIO) + return err; + + /* back to INTx mode */ + e_warn("MSI interrupt test failed, using legacy interrupt.\n"); + + e1000_free_irq(adapter); + + err = e1000_request_irq(adapter); + + return err; +} + +/** + * e1000_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + **/ +static int e1000_open(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + int err; + + /* disallow open during test */ + if (test_bit(__E1000_TESTING, &adapter->state)) + return -EBUSY; + + /* allocate transmit descriptors */ + err = e1000_setup_tx_resources(adapter); + if (err) + goto err_setup_tx; + + /* allocate receive descriptors */ + err = e1000_setup_rx_resources(adapter); + if (err) + goto err_setup_rx; + + e1000_power_up_phy(hw); + + adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; + if ((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN)) + e1000_update_mng_vlan(adapter); + + /* + * If AMT is enabled, let the firmware know that the network + * interface is now open + */ + if (adapter->flags & FLAG_HAS_AMT) + e1000_get_hw_control(adapter); + + /* + * before we allocate an interrupt, we must be ready to handle it. + * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt + * as soon as we call pci_request_irq, so we have to setup our + * clean_rx handler before we do so. + */ + e1000_configure(adapter); + + err = e1000_request_irq(adapter); + if (err) + goto err_req_irq; + + /* + * Work around PCIe errata with MSI interrupts causing some chipsets to + * ignore e1000e MSI messages, which means we need to test our MSI + * interrupt now + */ +#ifdef CONFIG_E1000E_MSIX + if (adapter->int_mode != E1000E_INT_MODE_LEGACY) +#endif + { + err = e1000_test_msi(adapter); + if (err) { + e_err("Interrupt allocation failed\n"); + goto err_req_irq; + } + } + + /* From here on the code is the same as e1000_up() */ + clear_bit(__E1000_DOWN, &adapter->state); + +#ifdef CONFIG_E1000E_NAPI + napi_enable(&adapter->napi); +#endif + + e1000_irq_enable(adapter); + + /* fire a link status change interrupt to start the watchdog */ + ew32(ICS, E1000_ICS_LSC); + + return 0; + +err_req_irq: + e1000_release_hw_control(adapter); + if (!adapter->wol && hw->phy.ops.power_down) + hw->phy.ops.power_down(hw); + e1000_free_rx_resources(adapter); +err_setup_rx: + e1000_free_tx_resources(adapter); +err_setup_tx: + e1000_reset(adapter); + + return err; +} + +/** + * e1000_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the drivers control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + **/ +static int e1000_close(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + WARN_ON(test_bit(__E1000_RESETTING, &adapter->state)); + e1000_down(adapter); + if (!adapter->wol && hw->phy.ops.power_down) + hw->phy.ops.power_down(hw); + e1000_free_irq(adapter); + + e1000_free_tx_resources(adapter); + e1000_free_rx_resources(adapter); + + /* + * kill manageability vlan ID if supported, but not if a vlan with + * the same ID is registered on the host OS (let 8021q kill it) + */ + if ((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && + !(adapter->vlgrp && + vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id))) + e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); + + /* + * If AMT is enabled, let the firmware know that the network + * interface is now closed + */ + if (adapter->flags & FLAG_HAS_AMT) + e1000_release_hw_control(adapter); + + return 0; +} +/** + * e1000_set_mac - Change the Ethernet Address of the NIC + * @netdev: network interface device structure + * @p: pointer to an address structure + * + * Returns 0 on success, negative on failure + **/ +static int e1000_set_mac(struct net_device *netdev, void *p) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len); + + adapter->hw.mac.ops.rar_set(&adapter->hw, adapter->hw.mac.addr, 0); + + if (adapter->flags & FLAG_RESET_OVERWRITES_LAA) { + /* activate the work around */ + e1000_set_laa_state_82571(&adapter->hw, 1); + + /* + * Hold a copy of the LAA in RAR[14] This is done so that + * between the time RAR[0] gets clobbered and the time it + * gets fixed (in e1000_watchdog), the actual LAA is in one + * of the RARs and no incoming packets directed to this port + * are dropped. Eventually the LAA will be in RAR[0] and + * RAR[14] + */ + adapter->hw.mac.ops.rar_set(&adapter->hw, adapter->hw.mac.addr, + adapter->hw.mac.rar_entry_count - 1); + } + + return 0; +} + +/** + * Need to wait a few seconds after link up to get diagnostic information from + * the phy + **/ +static void e1000_update_phy_info(unsigned long data) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) data; + if (adapter->hw.phy.ops.get_info) + adapter->hw.phy.ops.get_info(&adapter->hw); +} + +/** + * e1000_update_stats - Update the board statistics counters + * @adapter: board private structure + **/ +void e1000_update_stats(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; +#ifdef HAVE_PCI_ERS + struct pci_dev *pdev = adapter->pdev; +#endif + unsigned long irq_flags; + u16 phy_tmp; + +#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF + + /* + * Prevent stats update while adapter is being reset, or if the pci + * connection is down. + */ + if (adapter->link_speed == 0) + return; +#ifdef HAVE_PCI_ERS + if (pci_channel_offline(pdev)) + return; +#endif + + spin_lock_irqsave(&adapter->stats_lock, irq_flags); + + /* + * these counters are modified from e1000_adjust_tbi_stats, + * called from the interrupt context, so they must only + * be written while holding adapter->stats_lock + */ + + adapter->stats.crcerrs += er32(CRCERRS); + adapter->stats.gprc += er32(GPRC); + adapter->stats.gorc += er32(GORCL); + er32(GORCH); /* Clear gorc */ + adapter->stats.bprc += er32(BPRC); + adapter->stats.mprc += er32(MPRC); + adapter->stats.roc += er32(ROC); + + adapter->stats.mpc += er32(MPC); + adapter->stats.scc += er32(SCC); + adapter->stats.ecol += er32(ECOL); + adapter->stats.mcc += er32(MCC); + adapter->stats.latecol += er32(LATECOL); + adapter->stats.dc += er32(DC); + adapter->stats.xonrxc += er32(XONRXC); + adapter->stats.xontxc += er32(XONTXC); + adapter->stats.xoffrxc += er32(XOFFRXC); + adapter->stats.xofftxc += er32(XOFFTXC); + adapter->stats.gptc += er32(GPTC); + adapter->stats.gotc += er32(GOTCL); + er32(GOTCH); /* Clear gotc */ + adapter->stats.rnbc += er32(RNBC); + adapter->stats.ruc += er32(RUC); + + adapter->stats.mptc += er32(MPTC); + adapter->stats.bptc += er32(BPTC); + + /* used for adaptive IFS */ + + hw->mac.tx_packet_delta = er32(TPT); + adapter->stats.tpt += hw->mac.tx_packet_delta; + hw->mac.collision_delta = er32(COLC); + adapter->stats.colc += hw->mac.collision_delta; + + adapter->stats.algnerrc += er32(ALGNERRC); + adapter->stats.rxerrc += er32(RXERRC); + if (hw->mac.type != e1000_82574) + adapter->stats.tncrs += er32(TNCRS); + adapter->stats.cexterr += er32(CEXTERR); + adapter->stats.tsctc += er32(TSCTC); + adapter->stats.tsctfc += er32(TSCTFC); + + /* Fill out the OS statistics structure */ + adapter->net_stats.multicast = adapter->stats.mprc; + adapter->net_stats.collisions = adapter->stats.colc; + + /* Rx Errors */ + + /* + * RLEC on some newer hardware can be incorrect so build + * our own version based on RUC and ROC + */ + adapter->net_stats.rx_errors = adapter->stats.rxerrc + + adapter->stats.crcerrs + adapter->stats.algnerrc + + adapter->stats.ruc + adapter->stats.roc + + adapter->stats.cexterr; + adapter->net_stats.rx_length_errors = adapter->stats.ruc + + adapter->stats.roc; + adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; + adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc; + adapter->net_stats.rx_missed_errors = adapter->stats.mpc; + + /* Tx Errors */ + adapter->net_stats.tx_errors = adapter->stats.ecol + + adapter->stats.latecol; + adapter->net_stats.tx_aborted_errors = adapter->stats.ecol; + adapter->net_stats.tx_window_errors = adapter->stats.latecol; + adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs; + + /* Tx Dropped needs to be maintained elsewhere */ + + /* Phy Stats */ + if (hw->phy.media_type == e1000_media_type_copper) { + if ((adapter->link_speed == SPEED_1000) && + (!hw->phy.ops.read_reg(hw, PHY_1000T_STATUS, &phy_tmp))) { + phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK; + adapter->phy_stats.idle_errors += phy_tmp; + } + } + + /* Management Stats */ + adapter->stats.mgptc += er32(MGTPTC); + adapter->stats.mgprc += er32(MGTPRC); + adapter->stats.mgpdc += er32(MGTPDC); + + spin_unlock_irqrestore(&adapter->stats_lock, irq_flags); +} + +#ifdef SIOCGMIIPHY +/** + * e1000_phy_read_status - Update the PHY register status snapshot + * @adapter: board private structure + **/ +static void e1000_phy_read_status(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_phy_regs *phy = &adapter->phy_regs; + int ret_val; + unsigned long irq_flags; + + + spin_lock_irqsave(&adapter->stats_lock, irq_flags); + + if ((er32(STATUS) & E1000_STATUS_LU) && + (adapter->hw.phy.media_type == e1000_media_type_copper)) { + ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy->bmcr); + ret_val |= hw->phy.ops.read_reg(hw, PHY_STATUS, &phy->bmsr); + ret_val |= hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV, + &phy->advertise); + ret_val |= hw->phy.ops.read_reg(hw, PHY_LP_ABILITY, &phy->lpa); + ret_val |= hw->phy.ops.read_reg(hw, PHY_AUTONEG_EXP, + &phy->expansion); + ret_val |= hw->phy.ops.read_reg(hw, PHY_1000T_CTRL, + &phy->ctrl1000); + ret_val |= hw->phy.ops.read_reg(hw, PHY_1000T_STATUS, + &phy->stat1000); + ret_val |= hw->phy.ops.read_reg(hw, PHY_EXT_STATUS, + &phy->estatus); + if (ret_val) + e_warn("Error reading PHY register\n"); + } else { + /* + * Do not read PHY registers if link is not up + * Set values to typical power-on defaults + */ + phy->bmcr = (BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_FULLDPLX); + phy->bmsr = (BMSR_100FULL | BMSR_100HALF | BMSR_10FULL | + BMSR_10HALF | BMSR_ESTATEN | BMSR_ANEGCAPABLE | + BMSR_ERCAP); + phy->advertise = (ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP | + ADVERTISE_ALL | ADVERTISE_CSMA); + phy->lpa = 0; + phy->expansion = EXPANSION_ENABLENPAGE; + phy->ctrl1000 = ADVERTISE_1000FULL; + phy->stat1000 = 0; + phy->estatus = (ESTATUS_1000_TFULL | ESTATUS_1000_THALF); + } + + spin_unlock_irqrestore(&adapter->stats_lock, irq_flags); +} + +#endif /* SIOCGMIIPHY */ +static void e1000_print_link_info(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl = er32(CTRL); + + e_info("Link is Up %d Mbps %s, Flow Control: %s\n", + adapter->link_speed, + (adapter->link_duplex == FULL_DUPLEX) ? + "Full Duplex" : "Half Duplex", + ((ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE)) ? + "RX/TX" : + ((ctrl & E1000_CTRL_RFCE) ? "RX" : + ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" ))); +} + +static bool e1000_has_link(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + bool link_active = 0; + s32 ret_val = 0; + + /* + * get_link_status is set on LSC (link status) interrupt or + * Rx sequence error interrupt. get_link_status will stay + * false until the check_for_link establishes link + * for copper adapters ONLY + */ + switch (hw->phy.media_type) { + case e1000_media_type_copper: + if (hw->mac.get_link_status) { + ret_val = hw->mac.ops.check_for_link(hw); + link_active = !hw->mac.get_link_status; + } else { + link_active = 1; + } + break; + case e1000_media_type_fiber: + ret_val = hw->mac.ops.check_for_link(hw); + link_active = !!(er32(STATUS) & E1000_STATUS_LU); + break; + case e1000_media_type_internal_serdes: + ret_val = hw->mac.ops.check_for_link(hw); + link_active = adapter->hw.mac.serdes_has_link; + break; + default: + case e1000_media_type_unknown: + break; + } + + if ((ret_val == E1000_ERR_PHY) && (hw->phy.type == e1000_phy_igp_3) && + (er32(CTRL) & E1000_PHY_CTRL_GBE_DISABLE)) { + /* See e1000_kmrn_lock_loss_workaround_ich8lan() */ + e_info("Gigabit has been disabled, downgrading speed\n"); + } + + return link_active; +} + +static void e1000e_enable_receives(struct e1000_adapter *adapter) +{ + /* make sure the receive unit is started */ + if ((adapter->flags & FLAG_RX_NEEDS_RESTART) && + (adapter->flags & FLAG_RX_RESTART_NOW)) { + struct e1000_hw *hw = &adapter->hw; + u32 rctl = er32(RCTL); + ew32(RCTL, rctl | E1000_RCTL_EN); + adapter->flags &= ~FLAG_RX_RESTART_NOW; + } +} + +/** + * e1000_watchdog - Timer Call-back + * @data: pointer to adapter cast into an unsigned long + **/ +static void e1000_watchdog(unsigned long data) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) data; + + /* Do the rest outside of interrupt context */ + schedule_work(&adapter->watchdog_task); + + /* TODO: make this use queue_delayed_work() */ +} + +static void e1000_watchdog_task(struct work_struct *work) +{ + struct e1000_adapter *adapter = container_of(work, + struct e1000_adapter, watchdog_task); + struct net_device *netdev = adapter->netdev; + struct e1000_mac_info *mac = &adapter->hw.mac; + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_hw *hw = &adapter->hw; + u32 link, tctl; + int tx_pending = 0; + unsigned long timer_val; + + link = e1000_has_link(adapter); + if ((netif_carrier_ok(netdev)) && link) { + e1000e_enable_receives(adapter); + goto link_up; + } + + if ((e1000_enable_tx_pkt_filtering_generic(hw)) && + (adapter->mng_vlan_id != adapter->hw.mng_cookie.vlan_id)) + e1000_update_mng_vlan(adapter); + + if (link) { + if (!netif_carrier_ok(netdev)) { + bool txb2b = 1; +#ifdef SIOCGMIIPHY + /* update snapshot of PHY registers on LSC */ + e1000_phy_read_status(adapter); +#endif + mac->ops.get_link_up_info(&adapter->hw, + &adapter->link_speed, + &adapter->link_duplex); + e1000_print_link_info(adapter); + + /* + * On supported PHYs, check for duplex mismatch only + * if link has autonegotiated at 10/100 half + */ + if ((hw->phy.type == e1000_phy_igp_3 || + hw->phy.type == e1000_phy_bm) && + (hw->mac.autoneg == TRUE) && + (adapter->link_speed == SPEED_10 || + adapter->link_speed == SPEED_100) && + (adapter->link_duplex == HALF_DUPLEX)) { + u16 autoneg_exp; + + hw->phy.ops.read_reg(hw, PHY_AUTONEG_EXP, + &autoneg_exp); + + if (!(autoneg_exp & NWAY_ER_LP_NWAY_CAPS)) + e_info("Autonegotiated half duplex but" + " link partner cannot autoneg. " + " Try forcing full duplex if " + "link gets many collisions."); + } + + /* + * tweak tx_queue_len according to speed/duplex + * and adjust the timeout factor + */ + netdev->tx_queue_len = adapter->tx_queue_len; + adapter->tx_timeout_factor = 1; + switch (adapter->link_speed) { + case SPEED_10: + txb2b = 0; + netdev->tx_queue_len = 10; + adapter->tx_timeout_factor = 16; + break; + case SPEED_100: + txb2b = 0; + netdev->tx_queue_len = 100; + /* maybe add some timeout factor ? */ + break; + } + + /* + * workaround: re-program speed mode bit after + * link-up event + */ + if ((adapter->flags & FLAG_TARC_SPEED_MODE_BIT) && + !txb2b) { + u32 tarc0; + tarc0 = er32(TARC(0)); + tarc0 &= ~SPEED_MODE_BIT; + ew32(TARC(0), tarc0); + } + +#ifdef NETIF_F_TSO + /* + * disable TSO for pcie and 10/100 speeds, to avoid + * some hardware issues + */ + if (!(adapter->flags & FLAG_TSO_FORCE)) { + switch (adapter->link_speed) { + case SPEED_10: + case SPEED_100: + e_info("10/100 speed: disabling TSO\n"); + netdev->features &= ~NETIF_F_TSO; +#ifdef NETIF_F_TSO6 + netdev->features &= ~NETIF_F_TSO6; +#endif + break; + case SPEED_1000: + netdev->features |= NETIF_F_TSO; +#ifdef NETIF_F_TSO6 + netdev->features |= NETIF_F_TSO6; +#endif + break; + default: + /* oops */ + break; + } + } +#endif + + /* + * enable transmits in the hardware, need to do this + * after setting TARC(0) + */ + tctl = er32(TCTL); + tctl |= E1000_TCTL_EN; + ew32(TCTL, tctl); + + netif_carrier_on(netdev); + netif_wake_queue(netdev); + } + } else { + if (netif_carrier_ok(netdev)) { + adapter->link_speed = 0; + adapter->link_duplex = 0; + e_info("Link is Down\n"); + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + if (adapter->flags & FLAG_RX_NEEDS_RESTART) + schedule_work(&adapter->reset_task); + } + } + +link_up: + e1000_update_stats(adapter); + + mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old; + adapter->tpt_old = adapter->stats.tpt; + mac->collision_delta = adapter->stats.colc - adapter->colc_old; + adapter->colc_old = adapter->stats.colc; + + adapter->gorc = adapter->stats.gorc - adapter->gorc_old; + adapter->gorc_old = adapter->stats.gorc; + adapter->gotc = adapter->stats.gotc - adapter->gotc_old; + adapter->gotc_old = adapter->stats.gotc; + + e1000_update_adaptive_generic(&adapter->hw); + + if (!netif_carrier_ok(netdev)) { + tx_pending = (e1000_desc_unused(tx_ring) + 1 < + tx_ring->count); + if (tx_pending) { + /* + * We've lost link, so the controller stops DMA, + * but we've got queued Tx work that's never going + * to get done, so reset controller to flush Tx. + * (Do the reset outside of interrupt context). + */ + adapter->tx_timeout_count++; + schedule_work(&adapter->reset_task); + } + } + + /* Cause software interrupt to ensure Rx ring is cleaned */ +#ifdef CONFIG_E1000E_MSIX + if (adapter->msix_entries) + ew32(ICS, adapter->rx_ring->ims_val); + else +#endif + ew32(ICS, E1000_ICS_RXDMT0); + + /* Force detection of hung controller every watchdog period */ + adapter->detect_tx_hung = 1; + + /* + * With 82571 controllers, LAA may be overwritten due to controller + * reset from the other port. Set the appropriate LAA in RAR[0] + */ + if (e1000_get_laa_state_82571(hw)) + hw->mac.ops.rar_set(hw, adapter->hw.mac.addr, 0); + + /* Reset the timer */ + if (!test_bit(__E1000_DOWN, &adapter->state)) { + timer_val = jiffies + usecs_to_jiffies(adapter->stats_freq_us); + if (adapter->stats_freq_us > 1000000) + timer_val = round_jiffies(timer_val); + mod_timer(&adapter->watchdog_timer, timer_val); + } +} + +#define E1000_TX_FLAGS_CSUM 0x00000001 +#define E1000_TX_FLAGS_VLAN 0x00000002 +#define E1000_TX_FLAGS_TSO 0x00000004 +#define E1000_TX_FLAGS_IPV4 0x00000008 +#define E1000_TX_FLAGS_VLAN_MASK 0xffff0000 +#define E1000_TX_FLAGS_VLAN_SHIFT 16 + +static int e1000_tso(struct e1000_adapter *adapter, + struct sk_buff *skb) +{ +#ifdef NETIF_F_TSO + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_context_desc *context_desc; + struct e1000_buffer *buffer_info; + unsigned int i; + u32 cmd_length = 0; + u16 ipcse = 0, tucse, mss; + u8 ipcss, ipcso, tucss, tucso, hdr_len; + int err; + + if (!skb_is_gso(skb)) + return 0; + + if (skb_header_cloned(skb)) { + err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); + if (err) + return err; + } + + hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + mss = skb_shinfo(skb)->gso_size; + if (skb->protocol == htons(ETH_P_IP)) { + struct iphdr *iph = ip_hdr(skb); + iph->tot_len = 0; + iph->check = 0; + tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, + iph->daddr, 0, + IPPROTO_TCP, + 0); + cmd_length = E1000_TXD_CMD_IP; + ipcse = skb_transport_offset(skb) - 1; +#ifdef NETIF_F_TSO6 + } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) { + ipv6_hdr(skb)->payload_len = 0; + tcp_hdr(skb)->check = + ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + 0, IPPROTO_TCP, 0); + ipcse = 0; +#endif + } + ipcss = skb_network_offset(skb); + ipcso = (void *)&(ip_hdr(skb)->check) - (void *)skb->data; + tucss = skb_transport_offset(skb); + tucso = (void *)&(tcp_hdr(skb)->check) - (void *)skb->data; + tucse = 0; + + cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | + E1000_TXD_CMD_TCP | (skb->len - (hdr_len))); + + i = tx_ring->next_to_use; + context_desc = E1000_CONTEXT_DESC(*tx_ring, i); + buffer_info = &tx_ring->buffer_info[i]; + + context_desc->lower_setup.ip_fields.ipcss = ipcss; + context_desc->lower_setup.ip_fields.ipcso = ipcso; + context_desc->lower_setup.ip_fields.ipcse = cpu_to_le16(ipcse); + context_desc->upper_setup.tcp_fields.tucss = tucss; + context_desc->upper_setup.tcp_fields.tucso = tucso; + context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse); + context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss); + context_desc->tcp_seg_setup.fields.hdr_len = hdr_len; + context_desc->cmd_and_length = cpu_to_le32(cmd_length); + + buffer_info->time_stamp = jiffies; + buffer_info->next_to_watch = i; + + i++; + if (i == tx_ring->count) + i = 0; + tx_ring->next_to_use = i; + + return 1; +#else + return 0; +#endif +} + +static bool e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_context_desc *context_desc; + struct e1000_buffer *buffer_info; + unsigned int i; + u8 css; + u32 cmd_len = E1000_TXD_CMD_DEXT; + + if (skb->ip_summed != CHECKSUM_PARTIAL) + return 0; + + switch (skb->protocol) { + case __constant_htons(ETH_P_IP): + if (ip_hdr(skb)->protocol == IPPROTO_TCP) + cmd_len |= E1000_TXD_CMD_TCP; + break; + case __constant_htons(ETH_P_IPV6): + /* XXX not handling all IPV6 headers */ + if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) + cmd_len |= E1000_TXD_CMD_TCP; + break; + default: + if (unlikely(net_ratelimit())) + e_warn("checksum_partial proto=%x!\n", skb->protocol); + break; + } + + css = skb_transport_offset(skb); + + i = tx_ring->next_to_use; + buffer_info = &tx_ring->buffer_info[i]; + context_desc = E1000_CONTEXT_DESC(*tx_ring, i); + + context_desc->lower_setup.ip_config = 0; + context_desc->upper_setup.tcp_fields.tucss = css; + context_desc->upper_setup.tcp_fields.tucso = css + skb->csum_offset; + context_desc->upper_setup.tcp_fields.tucse = 0; + context_desc->tcp_seg_setup.data = 0; + context_desc->cmd_and_length = cpu_to_le32(cmd_len); + + buffer_info->time_stamp = jiffies; + buffer_info->next_to_watch = i; + + i++; + if (i == tx_ring->count) + i = 0; + tx_ring->next_to_use = i; + + return 1; +} + +#define E1000_MAX_PER_TXD 8192 +#define E1000_MAX_TXD_PWR 12 + +static int e1000_tx_map(struct e1000_adapter *adapter, + struct sk_buff *skb, unsigned int first, + unsigned int max_per_txd, unsigned int nr_frags, + unsigned int mss) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_buffer *buffer_info; + unsigned int len = skb->len - skb->data_len; + unsigned int offset = 0, size, count = 0, i; + unsigned int f; + + i = tx_ring->next_to_use; + + while (len) { + buffer_info = &tx_ring->buffer_info[i]; + size = min(len, max_per_txd); + + buffer_info->length = size; + /* set time_stamp *before* dma to help avoid a possible race */ + buffer_info->time_stamp = jiffies; + buffer_info->dma = + pci_map_single(adapter->pdev, + skb->data + offset, + size, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(adapter->pdev, buffer_info->dma)) { + dev_err(&adapter->pdev->dev, "TX DMA map failed\n"); + adapter->tx_dma_failed++; + return -1; + } + buffer_info->next_to_watch = i; + + len -= size; + offset += size; + count++; + i++; + if (i == tx_ring->count) + i = 0; + } + + for (f = 0; f < nr_frags; f++) { + struct skb_frag_struct *frag; + + frag = &skb_shinfo(skb)->frags[f]; + len = frag->size; + offset = frag->page_offset; + + while (len) { + buffer_info = &tx_ring->buffer_info[i]; + size = min(len, max_per_txd); + + buffer_info->length = size; + buffer_info->time_stamp = jiffies; + buffer_info->dma = + pci_map_page(adapter->pdev, + frag->page, + offset, + size, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(adapter->pdev, buffer_info->dma)) { + dev_err(&adapter->pdev->dev, + "TX DMA page map failed\n"); + adapter->tx_dma_failed++; + return -1; + } + + buffer_info->next_to_watch = i; + + len -= size; + offset += size; + count++; + + i++; + if (i == tx_ring->count) + i = 0; + } + } + + if (i == 0) + i = tx_ring->count - 1; + else + i--; + + tx_ring->buffer_info[i].skb = skb; + tx_ring->buffer_info[first].next_to_watch = i; + + return count; +} + +static void e1000_tx_queue(struct e1000_adapter *adapter, + int tx_flags, int count) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_tx_desc *tx_desc = NULL; + struct e1000_buffer *buffer_info; + u32 txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; + unsigned int i; + + if (tx_flags & E1000_TX_FLAGS_TSO) { + txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D | + E1000_TXD_CMD_TSE; + txd_upper |= E1000_TXD_POPTS_TXSM << 8; + + if (tx_flags & E1000_TX_FLAGS_IPV4) + txd_upper |= E1000_TXD_POPTS_IXSM << 8; + } + + if (tx_flags & E1000_TX_FLAGS_CSUM) { + txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; + txd_upper |= E1000_TXD_POPTS_TXSM << 8; + } + + if (tx_flags & E1000_TX_FLAGS_VLAN) { + txd_lower |= E1000_TXD_CMD_VLE; + txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK); + } + + i = tx_ring->next_to_use; + + while (count--) { + buffer_info = &tx_ring->buffer_info[i]; + tx_desc = E1000_TX_DESC(*tx_ring, i); + tx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); + tx_desc->lower.data = + cpu_to_le32(txd_lower | buffer_info->length); + tx_desc->upper.data = cpu_to_le32(txd_upper); + + i++; + if (i == tx_ring->count) + i = 0; + } + + tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd); + + /* + * Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). + */ + wmb(); + + tx_ring->next_to_use = i; + writel(i, adapter->hw.hw_addr + tx_ring->tail); + /* + * we need this if more than one processor can write to our tail + * at a time, it synchronizes IO on IA64/Altix systems + */ + mmiowb(); +} + +#define MINIMUM_DHCP_PACKET_SIZE 282 +static int e1000_transfer_dhcp_info(struct e1000_adapter *adapter, + struct sk_buff *skb) +{ + struct e1000_hw *hw = &adapter->hw; + u16 length, offset; + + if (vlan_tx_tag_present(skb)) { + if (!((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) + && (adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN))) + return 0; + } + + if (skb->len <= MINIMUM_DHCP_PACKET_SIZE) + return 0; + + if (((struct ethhdr *) skb->data)->h_proto != htons(ETH_P_IP)) + return 0; + + { + const struct iphdr *ip = (struct iphdr *)((u8 *)skb->data+14); + struct udphdr *udp; + + if (ip->protocol != IPPROTO_UDP) + return 0; + + udp = (struct udphdr *)((u8 *)ip + (ip->ihl << 2)); + if (ntohs(udp->dest) != 67) + return 0; + + offset = (u8 *)udp + 8 - skb->data; + length = skb->len - offset; + return e1000_mng_write_dhcp_info_generic(hw, (u8 *)udp + 8, + length); + } + + return 0; +} + +static int __e1000_maybe_stop_tx(struct net_device *netdev, int size) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + netif_stop_queue(netdev); + /* + * Herbert's original patch had: + * smp_mb__after_netif_stop_queue(); + * but since that doesn't exist yet, just open code it. + */ + smp_mb(); + + /* + * We need to check again in a case another CPU has just + * made room available. + */ + if (e1000_desc_unused(adapter->tx_ring) < size) + return -EBUSY; + + /* A reprieve! */ + netif_start_queue(netdev); + ++adapter->restart_queue; + return 0; +} + +static int e1000_maybe_stop_tx(struct net_device *netdev, int size) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if (e1000_desc_unused(adapter->tx_ring) >= size) + return 0; + return __e1000_maybe_stop_tx(netdev, size); +} + +#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) +static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_ring *tx_ring = adapter->tx_ring; + unsigned int first; + unsigned int max_per_txd = E1000_MAX_PER_TXD; + unsigned int max_txd_pwr = E1000_MAX_TXD_PWR; + unsigned int tx_flags = 0; + unsigned int len = skb->len - skb->data_len; +#ifdef NETIF_F_LLTX + unsigned long irq_flags; +#endif + unsigned int nr_frags; + unsigned int mss = 0; + int count = 0; + int tso; + unsigned int f; + + if (test_bit(__E1000_DOWN, &adapter->state)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + if (skb->len <= 0) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + +#ifdef NETIF_F_TSO + mss = skb_shinfo(skb)->gso_size; + /* + * The controller does a simple calculation to + * make sure there is enough room in the FIFO before + * initiating the DMA for each buffer. The calc is: + * 4 = ceil(buffer len/mss). To make sure we don't + * overrun the FIFO, adjust the max buffer len if mss + * drops. + */ + if (mss) { + u8 hdr_len; + max_per_txd = min(mss << 2, max_per_txd); + max_txd_pwr = fls(max_per_txd) - 1; + + /* + * TSO Workaround for 82571/2/3 Controllers -- if skb->data + * points to just header, pull a few bytes of payload from + * frags into skb->data + */ + hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + /* + * we do this workaround for ES2LAN, but it is un-necessary, + * avoiding it could save a lot of cycles + */ + if (skb->data_len && (hdr_len == len)) { + unsigned int pull_size; + + pull_size = min((unsigned int)4, skb->data_len); + if (!__pskb_pull_tail(skb, pull_size)) { + e_err("__pskb_pull_tail failed.\n"); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + len = skb->len - skb->data_len; + } + } + + /* reserve a descriptor for the offload context */ + if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL)) + count++; + count++; +#else + if (skb->ip_summed == CHECKSUM_PARTIAL) + count++; +#endif + + count += TXD_USE_COUNT(len, max_txd_pwr); + + nr_frags = skb_shinfo(skb)->nr_frags; + for (f = 0; f < nr_frags; f++) + count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size, + max_txd_pwr); + + if (adapter->hw.mac.tx_pkt_filtering) + e1000_transfer_dhcp_info(adapter, skb); + +#ifdef NETIF_F_LLTX + if (!spin_trylock_irqsave(&adapter->tx_queue_lock, irq_flags)) + /* Collision - tell upper layer to requeue */ + return NETDEV_TX_LOCKED; +#endif + + /* + * need: count + 2 desc gap to keep tail from touching + * head, otherwise try next time + */ + if (e1000_maybe_stop_tx(netdev, count + 2)) { +#ifdef NETIF_F_LLTX + spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags); +#endif + return NETDEV_TX_BUSY; + } + + if (adapter->vlgrp && vlan_tx_tag_present(skb)) { + tx_flags |= E1000_TX_FLAGS_VLAN; + tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); + } + + first = tx_ring->next_to_use; + + tso = e1000_tso(adapter, skb); + if (unlikely(tso < 0)) { + dev_kfree_skb_any(skb); +#ifdef NETIF_F_LLTX + spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags); +#endif + return NETDEV_TX_OK; + } + + if (tso) + tx_flags |= E1000_TX_FLAGS_TSO; + else if (e1000_tx_csum(adapter, skb)) + tx_flags |= E1000_TX_FLAGS_CSUM; + + /* + * Old method was to assume IPv4 packet by default if TSO was enabled. + * 82571 hardware supports TSO capabilities for IPv6 as well... + * no longer assume, we must. + */ + if (skb->protocol == htons(ETH_P_IP)) + tx_flags |= E1000_TX_FLAGS_IPV4; + + count = e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss); + if (unlikely(count < 0)) { + /* handle pci_map_single() error in e1000_tx_map */ + dev_kfree_skb_any(skb); +#ifdef NETIF_F_LLTX + spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags); +#endif + return NETDEV_TX_OK; + } + + e1000_tx_queue(adapter, tx_flags, count); + + netdev->trans_start = jiffies; + + /* Make sure there is space in the ring for the next send. */ + e1000_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 2); + +#ifdef NETIF_F_LLTX + spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags); +#endif + return NETDEV_TX_OK; +} + +/** + * e1000_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + **/ +static void e1000_tx_timeout(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + /* Do the reset outside of interrupt context */ + adapter->tx_timeout_count++; + schedule_work(&adapter->reset_task); +} + +static void e1000_reset_task(struct work_struct *work) +{ + struct e1000_adapter *adapter; + adapter = container_of(work, struct e1000_adapter, reset_task); + + e1000_reinit_locked(adapter); +} + +/** + * e1000_get_stats - Get System Network Statistics + * @netdev: network interface device structure + * + * Returns the address of the device statistics structure. + * The statistics are actually updated from the timer callback. + **/ +static struct net_device_stats *e1000_get_stats(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + /* only return the current stats */ + return &adapter->net_stats; +} + +/** + * e1000_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + **/ +static int e1000_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; + + if ((new_mtu < 68) || (max_frame > MAX_JUMBO_FRAME_SIZE)) { + e_err("Invalid MTU setting\n"); + return -EINVAL; + } + + /* Jumbo frame size limits */ + if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) { + if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) { + e_err("Jumbo Frames not supported.\n"); + return -EINVAL; + } + } + +#define MAX_STD_JUMBO_FRAME_SIZE 9234 + if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) { + e_err("MTU > 9216 not supported.\n"); + return -EINVAL; + } + + while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) + msleep(1); + /* e1000_down has a dependency on max_frame_size */ + adapter->max_frame_size = max_frame; + if (netif_running(netdev)) + e1000_down(adapter); + + /* + * NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN + * means we reserve 2 more, this pushes us to allocate from the next + * larger slab size. + * i.e. RXBUFFER_2048 --> size-4096 slab + * However with the new *_jumbo_rx* routines, jumbo receives will use + * fragmented skbs + */ + + if (max_frame <= 256) + adapter->rx_buffer_len = 256; + else if (max_frame <= 512) + adapter->rx_buffer_len = 512; + else if (max_frame <= 1024) + adapter->rx_buffer_len = 1024; + else if (max_frame <= 2048) + adapter->rx_buffer_len = 2048; +#ifdef CONFIG_E1000E_NAPI + else + adapter->rx_buffer_len = 4096; +#else + else if (max_frame <= 4096) + adapter->rx_buffer_len = 4096; + else if (max_frame <= 8192) + adapter->rx_buffer_len = 8192; + else if (max_frame <= 16384) + adapter->rx_buffer_len = 16384; +#endif + + /* adjust allocation if LPE protects us, and we aren't using SBP */ + if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN) || + (max_frame == ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN)) + adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN + + ETH_FCS_LEN; + + e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu); + netdev->mtu = new_mtu; + + if (netif_running(netdev)) + e1000_up(adapter); + else + e1000_reset(adapter); + + clear_bit(__E1000_RESETTING, &adapter->state); + + return 0; +} + +static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, + int cmd) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct mii_ioctl_data *data = if_mii(ifr); + + if (adapter->hw.phy.media_type != e1000_media_type_copper) + return -EOPNOTSUPP; + + switch (cmd) { + case SIOCGMIIPHY: + data->phy_id = adapter->hw.phy.addr; + break; + case SIOCGMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + switch (data->reg_num & 0x1F) { + case MII_BMCR: + data->val_out = adapter->phy_regs.bmcr; + break; + case MII_BMSR: + data->val_out = adapter->phy_regs.bmsr; + break; + case MII_PHYSID1: + data->val_out = (adapter->hw.phy.id >> 16); + break; + case MII_PHYSID2: + data->val_out = (adapter->hw.phy.id & 0xFFFF); + break; + case MII_ADVERTISE: + data->val_out = adapter->phy_regs.advertise; + break; + case MII_LPA: + data->val_out = adapter->phy_regs.lpa; + break; + case MII_EXPANSION: + data->val_out = adapter->phy_regs.expansion; + break; + case MII_CTRL1000: + data->val_out = adapter->phy_regs.ctrl1000; + break; + case MII_STAT1000: + data->val_out = adapter->phy_regs.stat1000; + break; + case MII_ESTATUS: + data->val_out = adapter->phy_regs.estatus; + break; + default: + return -EIO; + } + break; + case SIOCSMIIREG: + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + return e1000_mii_ioctl(netdev, ifr, cmd); +#ifdef ETHTOOL_OPS_COMPAT + case SIOCETHTOOL: + return ethtool_ioctl(ifr); +#endif + default: + return -EOPNOTSUPP; + } +} + +static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 ctrl, ctrl_ext, rctl, status; + u32 wufc = adapter->wol; + int retval = 0; + + netif_device_detach(netdev); + + if (netif_running(netdev)) { + WARN_ON(test_bit(__E1000_RESETTING, &adapter->state)); + e1000_down(adapter); + e1000_free_irq(adapter); + } + +#ifdef CONFIG_PM + retval = pci_save_state(pdev); + if (retval) + return retval; +#endif + + status = er32(STATUS); + if (status & E1000_STATUS_LU) + wufc &= ~E1000_WUFC_LNKC; + + if (wufc) { + e1000_setup_rctl(adapter); + e1000_set_multi(netdev); + + /* turn on all-multi mode if wake on multicast is enabled */ + if (wufc & E1000_WUFC_MC) { + rctl = er32(RCTL); + rctl |= E1000_RCTL_MPE; + ew32(RCTL, rctl); + } + + ctrl = er32(CTRL); + /* advertise wake from D3Cold */ + #define E1000_CTRL_ADVD3WUC 0x00100000 + /* phy power management enable */ + #define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000 + ctrl |= E1000_CTRL_ADVD3WUC | + E1000_CTRL_EN_PHY_PWR_MGMT; + ew32(CTRL, ctrl); + + if (adapter->hw.phy.media_type == e1000_media_type_fiber || + adapter->hw.phy.media_type == e1000_media_type_internal_serdes) { + /* keep the laser running in D3 */ + ctrl_ext = er32(CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA; + ew32(CTRL_EXT, ctrl_ext); + } + + if (adapter->flags & FLAG_IS_ICH) + e1000_disable_gig_wol_ich8lan(&adapter->hw); + + /* Allow time for pending master requests to run */ + e1000_disable_pcie_master_generic(&adapter->hw); + + ew32(WUC, E1000_WUC_PME_EN); + ew32(WUFC, wufc); + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); + } else { + ew32(WUC, 0); + ew32(WUFC, 0); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + } + + /* make sure adapter isn't asleep if manageability is enabled */ + if (adapter->flags & FLAG_MNG_PT_ENABLED) { + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); + } + + if (adapter->hw.phy.type == e1000_phy_igp_3) + e1000_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw); + + /* + * Release control of h/w to f/w. If f/w is AMT enabled, this + * would have already happened in close and is redundant. + */ + e1000_release_hw_control(adapter); + + pci_disable_device(pdev); + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +#ifdef CONFIG_PM +static int e1000_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 err; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, + "Cannot enable PCI device from suspend\n"); + return err; + } + + pci_set_master(pdev); + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + if (netif_running(netdev)) { + err = e1000_request_irq(adapter); + if (err) + return err; + } + + e1000_power_up_phy(hw); + e1000_reset(adapter); + ew32(WUS, ~0); + + e1000_init_manageability(adapter); + + if (netif_running(netdev)) + e1000_up(adapter); + + netif_device_attach(netdev); + + /* + * If the controller has AMT, do not set DRV_LOAD until the interface + * is up. For all other cases, let the f/w know that the h/w is now + * under the control of the driver. + */ + if (!(adapter->flags & FLAG_HAS_AMT)) + e1000_get_hw_control(adapter); + + return 0; +} +#endif /* CONFIG_PM */ + +#ifndef USE_REBOOT_NOTIFIER +static void e1000_shutdown(struct pci_dev *pdev) +{ + e1000_suspend(pdev, PMSG_SUSPEND); +} +#else +static struct pci_driver e1000_driver; +static int e1000_notify_reboot(struct notifier_block *nb, unsigned long event, + void *ptr) +{ + struct pci_dev *pdev = NULL; + + switch (event) { + case SYS_DOWN: + case SYS_HALT: + case SYS_POWER_OFF: + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) { + if (pci_dev_driver(pdev) == &e1000_driver) + e1000_suspend(pdev, PMSG_SUSPEND); + } + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block e1000_notifier_reboot = { + .notifier_call = e1000_notify_reboot, + .next = NULL, + .priority = 0 +}; +#endif + +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ +static void e1000_netpoll(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + disable_irq(adapter->pdev->irq); + e1000_intr(adapter->pdev->irq, netdev); + + e1000_clean_tx_irq(adapter); +#ifndef CONFIG_E1000E_NAPI + adapter->clean_rx(adapter); +#endif + + enable_irq(adapter->pdev->irq); +} +#endif + +#ifdef HAVE_PCI_ERS +/** + * e1000_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci connection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + */ +static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + + netif_device_detach(netdev); + + if (netif_running(netdev)) + e1000_down(adapter); + pci_disable_device(pdev); + + /* Request a slot slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * e1000_io_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. Implementation + * resembles the first-half of the e1000_resume routine. + */ +static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + if (pci_enable_device(pdev)) { + dev_err(&pdev->dev, + "Cannot re-enable PCI device after reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + pci_set_master(pdev); + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + e1000_reset(adapter); + ew32(WUS, ~0); + + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * e1000_io_resume - called when traffic can start flowing again. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells us that + * its OK to resume normal operation. Implementation resembles the + * second-half of the e1000_resume routine. + */ +static void e1000_io_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + + e1000_init_manageability(adapter); + + if (netif_running(netdev)) { + if (e1000_up(adapter)) { + dev_err(&pdev->dev, + "can't bring device back up after reset\n"); + return; + } + } + + netif_device_attach(netdev); + + /* + * If the controller has AMT, do not set DRV_LOAD until the interface + * is up. For all other cases, let the f/w know that the h/w is now + * under the control of the driver. + */ + if (!(adapter->flags & FLAG_HAS_AMT)) + e1000_get_hw_control(adapter); + +} +#endif /* HAVE_PCI_ERS */ + +static void e1000_print_device_info(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + u32 pba_num; + + /* print bus type/speed/width info */ + e_info("(PCI Express:2.5GB/s:%s) %02x:%02x:%02x:%02x:%02x:%02x\n", + /* bus width */ + ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" : + "Width x1"), + /* MAC address */ + netdev->dev_addr[0], netdev->dev_addr[1], + netdev->dev_addr[2], netdev->dev_addr[3], + netdev->dev_addr[4], netdev->dev_addr[5]); + e_info("Intel(R) PRO/%s Network Connection\n", + (hw->phy.type == e1000_phy_ife) ? "10/100" : "1000"); + e1000_read_pba_num_generic(hw, &pba_num); + e_info("MAC: %d, PHY: %d, PBA No: %06x-%03x\n", + hw->mac.type, hw->phy.type, + (pba_num >> 8), (pba_num & 0xff)); +} + +/** + * e1000_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in e1000e_pci_tbl + * + * Returns 0 on success, negative on failure + * + * e1000_probe initializes an adapter identified by a pci_dev structure. + * The OS initialization, configuring of the adapter private structure, + * and a hardware reset occur. + **/ +static int __devinit e1000_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct e1000_adapter *adapter; + struct e1000_hw *hw; + const struct e1000_info *ei = e1000_info_tbl[ent->driver_data]; + + static int cards_found; + int i, err, pci_using_dac; + u16 eeprom_data = 0; + u16 eeprom_apme_mask = E1000_EEPROM_APME; + + err = pci_enable_device(pdev); + if (err) + return err; + + pci_using_dac = 0; + err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); + if (!err) { + err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + if (!err) + pci_using_dac = 1; + } else { + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + err = pci_set_consistent_dma_mask(pdev, + DMA_32BIT_MASK); + if (err) { + printk(KERN_ERR "%s: No usable DMA " + "configuration, aborting\n", + pci_name(pdev)); + goto err_dma; + } + } + } + + err = pci_request_regions(pdev, e1000e_driver_name); + if (err) + goto err_pci_reg; + + pci_set_master(pdev); + + err = -ENOMEM; + netdev = alloc_etherdev(sizeof(struct e1000_adapter)); + if (!netdev) + goto err_alloc_etherdev; + + SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &pdev->dev); + + pci_set_drvdata(pdev, netdev); + adapter = netdev_priv(netdev); + hw = &adapter->hw; + adapter->netdev = netdev; + adapter->pdev = pdev; + adapter->ei = ei; + adapter->pba = ei->pba; + adapter->flags = ei->flags; + adapter->hw.back = adapter; + adapter->hw.mac.type = ei->mac; + adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1; + adapter->stats_freq_us = 2 * 1000000; /* default watchdog timer 2sec */ + + /* PCI config space info */ + + hw->vendor_id = pdev->vendor; + hw->device_id = pdev->device; + hw->subsystem_vendor_id = pdev->subsystem_vendor; + hw->subsystem_device_id = pdev->subsystem_device; + + pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); + pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word); + + err = -EIO; + adapter->hw.hw_addr = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (!adapter->hw.hw_addr) + goto err_ioremap; + + if ((adapter->flags & FLAG_HAS_FLASH) && + (pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) { + adapter->hw.flash_address = ioremap(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); + if (!adapter->hw.flash_address) + goto err_flashmap; + + /* Now that we're sure NV RAM is mappable, unmap it until needed. */ + iounmap(adapter->hw.flash_address); + adapter->hw.flash_address = NULL; + spin_lock_init(&adapter->hw.flash_address_map_lock); + } + + adapter->bd_number = cards_found++; + + e1000_check_options(adapter); + + /* setup adapter struct */ + err = e1000_sw_init(adapter); + if (err) + goto err_sw_init; + + if (ei->get_variants) { + err = ei->get_variants(adapter); + if (err) + goto err_hw_init; + } + + /* construct the net_device struct */ + netdev->open = &e1000_open; + netdev->stop = &e1000_close; + netdev->hard_start_xmit = &e1000_xmit_frame; + netdev->get_stats = &e1000_get_stats; + netdev->set_multicast_list = &e1000_set_multi; + netdev->set_mac_address = &e1000_set_mac; + netdev->change_mtu = &e1000_change_mtu; + netdev->do_ioctl = &e1000_ioctl; + e1000_set_ethtool_ops(netdev); + netdev->tx_timeout = &e1000_tx_timeout; + netdev->watchdog_timeo = 5 * HZ; +#ifdef CONFIG_E1000E_NAPI + netif_napi_add(netdev, &adapter->napi, e1000_poll, 64); +#endif + netdev->vlan_rx_register = e1000_vlan_rx_register; + netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid; + netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid; +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = e1000_netpoll; +#endif + strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); + + hw->mac.ops.get_bus_info(&adapter->hw); + + adapter->hw.phy.autoneg_wait_to_complete = 0; + + /* Copper options */ + if (adapter->hw.phy.media_type == e1000_media_type_copper) { + adapter->hw.phy.mdix = AUTO_ALL_MODES; + adapter->hw.phy.disable_polarity_correction = 0; + adapter->hw.phy.ms_type = e1000_ms_hw_default; + } + + if (hw->phy.ops.check_reset_block && + hw->phy.ops.check_reset_block(hw)) + e_info("PHY reset is blocked due to SOL/IDER session.\n"); + + netdev->features = NETIF_F_SG | + NETIF_F_HW_CSUM | + NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_RX; + + if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) + netdev->features |= NETIF_F_HW_VLAN_FILTER; + +#ifdef NETIF_F_TSO + netdev->features |= NETIF_F_TSO; +#ifdef NETIF_F_TSO6 + netdev->features |= NETIF_F_TSO6; +#endif +#endif + + if (pci_using_dac) + netdev->features |= NETIF_F_HIGHDMA; + +#ifdef NETIF_F_LLTX + /* + * We should not be using LLTX anymore, but we are still Tx faster with + * it. + */ + netdev->features |= NETIF_F_LLTX; +#endif + + if (e1000_enable_mng_pass_thru(&adapter->hw)) + adapter->flags |= FLAG_MNG_PT_ENABLED; + + /* + * before reading the NVM, reset the controller to + * put the device in a known good starting state + */ + adapter->hw.mac.ops.reset_hw(&adapter->hw); + + /* + * systems with ASPM and others may see the checksum fail on the first + * attempt. Let's give it a few tries + */ + for (i = 0;; i++) { + if (hw->nvm.ops.validate(hw) >= 0) + break; + if (i == 2) { + e_err("The NVM Checksum Is Not Valid\n"); + err = -EIO; + goto err_eeprom; + } + } + + /* copy the MAC address out of the NVM */ + if (e1000_read_mac_addr(&adapter->hw)) + e_err("NVM Read Error while reading MAC address\n"); + + memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len); +#ifdef ETHTOOL_GPERMADDR + memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len); + + if (!is_valid_ether_addr(netdev->perm_addr)) { +#else + if (!is_valid_ether_addr(netdev->dev_addr)) { +#endif + e_err("Invalid MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", + netdev->dev_addr[0], netdev->dev_addr[1], + netdev->dev_addr[2], netdev->dev_addr[3], + netdev->dev_addr[4], netdev->dev_addr[5]); + err = -EIO; + goto err_eeprom; + } + + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &e1000_watchdog; + adapter->watchdog_timer.data = (unsigned long) adapter; + + init_timer(&adapter->phy_info_timer); + adapter->phy_info_timer.function = &e1000_update_phy_info; + adapter->phy_info_timer.data = (unsigned long) adapter; + + INIT_WORK(&adapter->reset_task, e1000_reset_task); + INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task); + + /* Initialize link parameters. User can change them with ethtool */ + adapter->hw.mac.autoneg = 1; + adapter->fc_autoneg = 1; + adapter->hw.fc.original_type = e1000_fc_default; + adapter->hw.fc.type = e1000_fc_default; + adapter->hw.phy.autoneg_advertised = 0x2f; + + /* ring size defaults */ + adapter->rx_ring->count = 256; + adapter->tx_ring->count = 256; + + /* + * Initial Wake on LAN setting - If APM wake is enabled in + * the EEPROM, enable the ACPI Magic Packet filter + */ + if (adapter->flags & FLAG_APME_IN_WUC) { + /* APME bit in EEPROM is mapped to WUC.APME */ + eeprom_data = er32(WUC); + eeprom_apme_mask = E1000_WUC_APME; + } else if (adapter->flags & FLAG_APME_IN_CTRL3) { + if (adapter->flags & FLAG_APME_CHECK_PORT_B && + (adapter->hw.bus.func == 1)) + hw->nvm.ops.read(&adapter->hw, NVM_INIT_CONTROL3_PORT_B, + 1, &eeprom_data); + else + hw->nvm.ops.read(&adapter->hw, NVM_INIT_CONTROL3_PORT_A, + 1, &eeprom_data); + } + + /* fetch WoL from EEPROM */ + if (eeprom_data & eeprom_apme_mask) + adapter->eeprom_wol |= E1000_WUFC_MAG; + + /* + * now that we have the eeprom settings, apply the special cases + * where the eeprom may be wrong or the board simply won't support + * wake on lan on a particular port + */ + if (!(adapter->flags & FLAG_HAS_WOL)) + adapter->eeprom_wol = 0; + + /* initialize the wol settings based on the eeprom settings */ + adapter->wol = adapter->eeprom_wol; + + /* reset the hardware with the new settings */ + e1000_reset(adapter); + + /* + * If the controller has AMT, do not set DRV_LOAD until the interface + * is up. For all other cases, let the f/w know that the h/w is now + * under the control of the driver. + */ + if (!(adapter->flags & FLAG_HAS_AMT)) + e1000_get_hw_control(adapter); + + /* tell the stack to leave us alone until e1000_open() is called */ + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + strcpy(netdev->name, "eth%d"); + err = register_netdev(netdev); + if (err) + goto err_register; + + e1000_print_device_info(adapter); + + return 0; + +err_register: + if (!(adapter->flags & FLAG_HAS_AMT)) + e1000_release_hw_control(adapter); +err_eeprom: + if (hw->phy.ops.check_reset_block && + !hw->phy.ops.check_reset_block(hw)) + hw->phy.ops.reset(hw); +err_hw_init: + hw->mac.ops.remove_device(&adapter->hw); + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); +err_sw_init: + if (adapter->hw.flash_address) + iounmap(adapter->hw.flash_address); +err_flashmap: + iounmap(adapter->hw.hw_addr); +err_ioremap: + free_netdev(netdev); +err_alloc_etherdev: + pci_release_regions(pdev); +err_pci_reg: +err_dma: + pci_disable_device(pdev); + return err; +} + +/** + * e1000_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * e1000_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. The could be caused by a + * Hot-Plug event, or because the driver is going to be removed from + * memory. + **/ +static void __devexit e1000_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + /* + * flush_scheduled work may reschedule our watchdog task, so + * explicitly disable watchdog tasks from being rescheduled + */ + set_bit(__E1000_DOWN, &adapter->state); + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_info_timer); + + flush_scheduled_work(); + + /* + * Release control of h/w to f/w. If f/w is AMT enabled, this + * would have already happened in close and is redundant. + */ + e1000_release_hw_control(adapter); + + unregister_netdev(netdev); + + if (hw->phy.ops.check_reset_block && + !hw->phy.ops.check_reset_block(hw)) + hw->phy.ops.reset(hw); + +#ifdef CONFIG_E1000E_MSIX + e1000_reset_interrupt_capability(adapter); +#endif /* CONFIG_E1000E_MSIX */ + hw->mac.ops.remove_device(&adapter->hw); + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + + iounmap(adapter->hw.hw_addr); + if (adapter->hw.flash_address) + iounmap(adapter->hw.flash_address); + pci_release_regions(pdev); + + free_netdev(netdev); + + pci_disable_device(pdev); +} + +#ifdef HAVE_PCI_ERS +/* PCI Error Recovery (ERS) */ +static struct pci_error_handlers e1000_err_handler = { + .error_detected = e1000_io_error_detected, + .slot_reset = e1000_io_slot_reset, + .resume = e1000_io_resume, +}; +#endif + +static struct pci_device_id e1000e_pci_tbl[] = { + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER_LP), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_FIBER), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES_DUAL), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES_QUAD), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571PT_QUAD_COPPER), board_82571 }, + + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI), board_82572 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_COPPER), board_82572 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_FIBER), board_82572 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_SERDES), board_82572 }, + + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E), board_82573 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E_IAMT), board_82573 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573L), board_82573 }, + + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82574L), board_82574 }, + + { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_DPT), + board_80003es2lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_SPT), + board_80003es2lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_DPT), + board_80003es2lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_SPT), + board_80003es2lan }, + + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_G), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_GT), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_AMT), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_C), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M_AMT), board_ich8lan }, + + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_G), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_GT), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_AMT), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_C), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_BM), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_AMT), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_V), board_ich9lan }, + + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LM), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LF), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_V), board_ich9lan }, + + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LM), board_ich10lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LF), board_ich10lan }, + + { } /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, e1000e_pci_tbl); + +/* PCI Device API Driver */ +static struct pci_driver e1000_driver = { + .name = e1000e_driver_name, + .id_table = e1000e_pci_tbl, + .probe = e1000_probe, + .remove = __devexit_p(e1000_remove), +#ifdef CONFIG_PM + /* Power Management Hooks */ + .suspend = e1000_suspend, + .resume = e1000_resume, +#endif +#ifndef USE_REBOOT_NOTIFIER + .shutdown = e1000_shutdown, +#endif +#ifdef HAVE_PCI_ERS + .err_handler = &e1000_err_handler +#endif +}; + +/** + * e1000_init_module - Driver Registration Routine + * + * e1000_init_module is the first routine called when the driver is + * loaded. All it does is register with the PCI subsystem. + **/ +static int __init e1000_init_module(void) +{ + int ret; + printk(KERN_INFO "%s: Intel(R) PRO/1000 Network Driver - %s\n", + e1000e_driver_name, e1000e_driver_version); + printk(KERN_INFO "%s: Copyright (c) 1999-2008 Intel Corporation.\n", + e1000e_driver_name); + ret = pci_register_driver(&e1000_driver); + pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, e1000e_driver_name, + PM_QOS_DEFAULT_VALUE); +#ifdef USE_REBOOT_NOTIFIER + if (ret >= 0) + register_reboot_notifier(&e1000_notifier_reboot); +#endif + + return ret; +} +module_init(e1000_init_module); + +/** + * e1000_exit_module - Driver Exit Cleanup Routine + * + * e1000_exit_module is called just before the driver is removed + * from memory. + **/ +static void __exit e1000_exit_module(void) +{ +#ifdef USE_REBOOT_NOTIFIER + unregister_reboot_notifier(&e1000_notifier_reboot); +#endif + pci_unregister_driver(&e1000_driver); + pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, e1000e_driver_name); +} +module_exit(e1000_exit_module); + + +MODULE_AUTHOR("Intel Corporation, "); +MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +/* netdev.c */ --- linux-2.6.27.orig/ubuntu/e1000e/e1000_80003es2lan.h +++ linux-2.6.27/ubuntu/e1000e/e1000_80003es2lan.h @@ -0,0 +1,95 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_80003ES2LAN_H_ +#define _E1000_80003ES2LAN_H_ + +#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL 0x00 +#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL 0x02 +#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL 0x10 +#define E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE 0x1F + +#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS 0x0008 +#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS 0x0800 +#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING 0x0010 + +#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004 +#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000 +#define E1000_KMRNCTRLSTA_OPMODE_E_IDLE 0x2000 + +#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */ +#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000 + +#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN 0x8 +#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN 0x9 + +/* GG82563 PHY Specific Status Register (Page 0, Register 16 */ +#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE 0x0002 /* 1=Reversal Disabled */ +#define GG82563_PSCR_CROSSOVER_MODE_MASK 0x0060 +#define GG82563_PSCR_CROSSOVER_MODE_MDI 0x0000 /* 00=Manual MDI */ +#define GG82563_PSCR_CROSSOVER_MODE_MDIX 0x0020 /* 01=Manual MDIX */ +#define GG82563_PSCR_CROSSOVER_MODE_AUTO 0x0060 /* 11=Auto crossover */ + +/* PHY Specific Control Register 2 (Page 0, Register 26) */ +#define GG82563_PSCR2_REVERSE_AUTO_NEG 0x2000 + /* 1=Reverse Auto-Negotiation */ + +/* MAC Specific Control Register (Page 2, Register 21) */ +/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */ +#define GG82563_MSCR_TX_CLK_MASK 0x0007 +#define GG82563_MSCR_TX_CLK_10MBPS_2_5 0x0004 +#define GG82563_MSCR_TX_CLK_100MBPS_25 0x0005 +#define GG82563_MSCR_TX_CLK_1000MBPS_2_5 0x0006 +#define GG82563_MSCR_TX_CLK_1000MBPS_25 0x0007 + +#define GG82563_MSCR_ASSERT_CRS_ON_TX 0x0010 /* 1=Assert */ + +/* DSP Distance Register (Page 5, Register 26) */ +/* + * 0 = <50M + * 1 = 50-80M + * 2 = 80-100M + * 3 = 110-140M + * 4 = >140M + */ +#define GG82563_DSPD_CABLE_LENGTH 0x0007 + +/* Kumeran Mode Control Register (Page 193, Register 16) */ +#define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800 + +/* Max number of times Kumeran read/write should be validated */ +#define GG82563_MAX_KMRN_RETRY 0x5 + +/* Power Management Control Register (Page 193, Register 20) */ +#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001 + /* 1=Enable SERDES Electrical Idle */ + +/* In-Band Control Register (Page 194, Register 18) */ +#define GG82563_ICR_DIS_PADDING 0x0010 /* Disable Padding */ + +#endif --- linux-2.6.27.orig/ubuntu/e1000e/Kconfig +++ linux-2.6.27/ubuntu/e1000e/Kconfig @@ -0,0 +1,22 @@ +config E1000E_NEW + tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support" + depends on PCI && (!SPARC32 || BROKEN) && !E1000E + default m + ---help--- + This driver supports the PCI-Express Intel(R) PRO/1000 gigabit + ethernet family of adapters. For PCI or PCI-X e1000 adapters, + use the regular e1000 driver For more information on how to + identify your adapter, go to the Adapter & Driver ID Guide at: + + + + For general information and support, go to the Intel support + website at: + + + + To compile this driver as a module, choose M here. The module + will be called e1000e. + +config E1000E_ENABLED + def_bool E1000E_NEW != n --- linux-2.6.27.orig/ubuntu/e1000e/kcompat.h +++ linux-2.6.27/ubuntu/e1000e/kcompat.h @@ -0,0 +1,1612 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _KCOMPAT_H_ +#define _KCOMPAT_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* NAPI enable/disable flags here */ + +#ifdef DRIVER_E1000E +#define CONFIG_E1000E_NAPI +#define NAPI +#endif + +#ifdef _E1000_H_ +#ifdef CONFIG_E1000_NAPI +#define NAPI +#endif +#ifdef E1000_NAPI +#undef NAPI +#define NAPI +#endif +#ifdef E1000E_NAPI +#undef NAPI +#define NAPI +#endif +#ifdef E1000_NO_NAPI +#undef NAPI +#endif +#ifdef E1000E_NO_NAPI +#undef NAPI +#endif +#endif + + + + + + +#ifdef DRIVER_E1000E +#define adapter_struct e1000_adapter +#define CONFIG_E1000E_MSIX +#endif + + + + +/* and finally set defines so that the code sees the changes */ +#ifdef NAPI +#ifndef CONFIG_E1000_NAPI +#define CONFIG_E1000_NAPI +#endif +#ifndef CONFIG_E1000E_NAPI +#define CONFIG_E1000E_NAPI +#endif +#else +#undef CONFIG_E1000_NAPI +#undef CONFIG_E1000E_NAPI +#undef CONFIG_IXGB_NAPI +#endif + +/* packet split disable/enable */ +#ifdef DISABLE_PACKET_SPLIT +#undef CONFIG_E1000_DISABLE_PACKET_SPLIT +#define CONFIG_E1000_DISABLE_PACKET_SPLIT +#undef CONFIG_IGB_DISABLE_PACKET_SPLIT +#define CONFIG_IGB_DISABLE_PACKET_SPLIT +#endif + +/* MSI compatibility code for all kernels and drivers */ +#ifdef DISABLE_PCI_MSI +#undef CONFIG_PCI_MSI +#endif +#ifndef CONFIG_PCI_MSI +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) ) +struct msix_entry { + u16 vector; /* kernel uses to write allocated vector */ + u16 entry; /* driver uses to specify entry, OS writes */ +}; +#endif +#define pci_enable_msi(a) -ENOTSUPP +#define pci_disable_msi(a) do {} while (0) +#define pci_enable_msix(a, b, c) -ENOTSUPP +#define pci_disable_msix(a) do {} while (0) +#define msi_remove_pci_irq_vectors(a) do {} while (0) +#endif /* CONFIG_PCI_MSI */ +#ifdef DISABLE_PM +#undef CONFIG_PM +#endif + +#ifdef DISABLE_NET_POLL_CONTROLLER +#undef CONFIG_NET_POLL_CONTROLLER +#endif + +#ifndef PMSG_SUSPEND +#define PMSG_SUSPEND 3 +#endif + +/* generic boolean compatibility */ +#undef TRUE +#undef FALSE +#define TRUE true +#define FALSE false +#ifdef GCC_VERSION +#if ( GCC_VERSION < 3000 ) +#define _Bool char +#endif +#endif +#ifndef bool +#define bool _Bool +#define true 1 +#define false 0 +#endif + + +#ifndef module_param +#define module_param(v,t,p) MODULE_PARM(v, "i"); +#endif + +#ifndef DMA_64BIT_MASK +#define DMA_64BIT_MASK 0xffffffffffffffffULL +#endif + +#ifndef DMA_32BIT_MASK +#define DMA_32BIT_MASK 0x00000000ffffffffULL +#endif + +#ifndef PCI_CAP_ID_EXP +#define PCI_CAP_ID_EXP 0x10 +#endif + +#ifndef mmiowb +#ifdef CONFIG_IA64 +#define mmiowb() asm volatile ("mf.a" ::: "memory") +#else +#define mmiowb() +#endif +#endif + +#ifndef IRQ_HANDLED +#define irqreturn_t void +#define IRQ_HANDLED +#define IRQ_NONE +#endif + +#ifndef SET_NETDEV_DEV +#define SET_NETDEV_DEV(net, pdev) +#endif + +#ifndef HAVE_FREE_NETDEV +#define free_netdev(x) kfree(x) +#endif + +#ifdef HAVE_POLL_CONTROLLER +#define CONFIG_NET_POLL_CONTROLLER +#endif + +#ifndef NETDEV_TX_OK +#define NETDEV_TX_OK 0 +#endif + +#ifndef NETDEV_TX_BUSY +#define NETDEV_TX_BUSY 1 +#endif + +#ifndef NETDEV_TX_LOCKED +#define NETDEV_TX_LOCKED -1 +#endif + +#ifndef SKB_DATAREF_SHIFT +/* if we do not have the infrastructure to detect if skb_header is cloned + just return false in all cases */ +#define skb_header_cloned(x) 0 +#endif + +#ifndef NETIF_F_GSO +#define gso_size tso_size +#define gso_segs tso_segs +#endif + +#ifndef CHECKSUM_PARTIAL +#define CHECKSUM_PARTIAL CHECKSUM_HW +#define CHECKSUM_COMPLETE CHECKSUM_HW +#endif + +#ifndef __read_mostly +#define __read_mostly +#endif + +#ifndef HAVE_NETIF_MSG +#define HAVE_NETIF_MSG 1 +enum { + NETIF_MSG_DRV = 0x0001, + NETIF_MSG_PROBE = 0x0002, + NETIF_MSG_LINK = 0x0004, + NETIF_MSG_TIMER = 0x0008, + NETIF_MSG_IFDOWN = 0x0010, + NETIF_MSG_IFUP = 0x0020, + NETIF_MSG_RX_ERR = 0x0040, + NETIF_MSG_TX_ERR = 0x0080, + NETIF_MSG_TX_QUEUED = 0x0100, + NETIF_MSG_INTR = 0x0200, + NETIF_MSG_TX_DONE = 0x0400, + NETIF_MSG_RX_STATUS = 0x0800, + NETIF_MSG_PKTDATA = 0x1000, + NETIF_MSG_HW = 0x2000, + NETIF_MSG_WOL = 0x4000, +}; + +#else +#define NETIF_MSG_HW 0x2000 +#define NETIF_MSG_WOL 0x4000 +#endif /* HAVE_NETIF_MSG */ + +#ifndef MII_RESV1 +#define MII_RESV1 0x17 /* Reserved... */ +#endif + +#ifndef unlikely +#define unlikely(_x) _x +#define likely(_x) _x +#endif + +#ifndef WARN_ON +#define WARN_ON(x) +#endif + +#ifndef PCI_DEVICE +#define PCI_DEVICE(vend,dev) \ + .vendor = (vend), .device = (dev), \ + .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID +#endif + +#ifndef num_online_cpus +#define num_online_cpus() smp_num_cpus +#endif + +#ifndef _LINUX_RANDOM_H +#include +#endif + +#ifndef DECLARE_BITMAP +#ifndef BITS_TO_LONGS +#define BITS_TO_LONGS(bits) (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) +#endif +#define DECLARE_BITMAP(name,bits) long name[BITS_TO_LONGS(bits)] +#endif + +#ifndef VLAN_HLEN +#define VLAN_HLEN 4 +#endif + +#ifndef VLAN_ETH_HLEN +#define VLAN_ETH_HLEN 18 +#endif + +#ifndef VLAN_ETH_FRAME_LEN +#define VLAN_ETH_FRAME_LEN 1518 +#endif + +#ifndef DCA_GET_TAG_TWO_ARGS +#define dca3_get_tag(a,b) dca_get_tag(b) +#endif + + +/*****************************************************************************/ +/* Installations with ethtool version without eeprom, adapter id, or statistics + * support */ + +#ifndef ETH_GSTRING_LEN +#define ETH_GSTRING_LEN 32 +#endif + +#ifndef ETHTOOL_GSTATS +#define ETHTOOL_GSTATS 0x1d +#undef ethtool_drvinfo +#define ethtool_drvinfo k_ethtool_drvinfo +struct k_ethtool_drvinfo { + u32 cmd; + char driver[32]; + char version[32]; + char fw_version[32]; + char bus_info[32]; + char reserved1[32]; + char reserved2[16]; + u32 n_stats; + u32 testinfo_len; + u32 eedump_len; + u32 regdump_len; +}; + +struct ethtool_stats { + u32 cmd; + u32 n_stats; + u64 data[0]; +}; +#endif /* ETHTOOL_GSTATS */ + +#ifndef ETHTOOL_PHYS_ID +#define ETHTOOL_PHYS_ID 0x1c +#endif /* ETHTOOL_PHYS_ID */ + +#ifndef ETHTOOL_GSTRINGS +#define ETHTOOL_GSTRINGS 0x1b +enum ethtool_stringset { + ETH_SS_TEST = 0, + ETH_SS_STATS, +}; +struct ethtool_gstrings { + u32 cmd; /* ETHTOOL_GSTRINGS */ + u32 string_set; /* string set id e.c. ETH_SS_TEST, etc*/ + u32 len; /* number of strings in the string set */ + u8 data[0]; +}; +#endif /* ETHTOOL_GSTRINGS */ + +#ifndef ETHTOOL_TEST +#define ETHTOOL_TEST 0x1a +enum ethtool_test_flags { + ETH_TEST_FL_OFFLINE = (1 << 0), + ETH_TEST_FL_FAILED = (1 << 1), +}; +struct ethtool_test { + u32 cmd; + u32 flags; + u32 reserved; + u32 len; + u64 data[0]; +}; +#endif /* ETHTOOL_TEST */ + +#ifndef ETHTOOL_GEEPROM +#define ETHTOOL_GEEPROM 0xb +#undef ETHTOOL_GREGS +struct ethtool_eeprom { + u32 cmd; + u32 magic; + u32 offset; + u32 len; + u8 data[0]; +}; + +struct ethtool_value { + u32 cmd; + u32 data; +}; +#endif /* ETHTOOL_GEEPROM */ + +#ifndef ETHTOOL_GLINK +#define ETHTOOL_GLINK 0xa +#endif /* ETHTOOL_GLINK */ + +#ifndef ETHTOOL_GREGS +#define ETHTOOL_GREGS 0x00000004 /* Get NIC registers */ +#define ethtool_regs _kc_ethtool_regs +/* for passing big chunks of data */ +struct _kc_ethtool_regs { + u32 cmd; + u32 version; /* driver-specific, indicates different chips/revs */ + u32 len; /* bytes */ + u8 data[0]; +}; +#endif /* ETHTOOL_GREGS */ + +#ifndef ETHTOOL_GMSGLVL +#define ETHTOOL_GMSGLVL 0x00000007 /* Get driver message level */ +#endif +#ifndef ETHTOOL_SMSGLVL +#define ETHTOOL_SMSGLVL 0x00000008 /* Set driver msg level, priv. */ +#endif +#ifndef ETHTOOL_NWAY_RST +#define ETHTOOL_NWAY_RST 0x00000009 /* Restart autonegotiation, priv */ +#endif +#ifndef ETHTOOL_GLINK +#define ETHTOOL_GLINK 0x0000000a /* Get link status */ +#endif +#ifndef ETHTOOL_GEEPROM +#define ETHTOOL_GEEPROM 0x0000000b /* Get EEPROM data */ +#endif +#ifndef ETHTOOL_SEEPROM +#define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data */ +#endif +#ifndef ETHTOOL_GCOALESCE +#define ETHTOOL_GCOALESCE 0x0000000e /* Get coalesce config */ +/* for configuring coalescing parameters of chip */ +#define ethtool_coalesce _kc_ethtool_coalesce +struct _kc_ethtool_coalesce { + u32 cmd; /* ETHTOOL_{G,S}COALESCE */ + + /* How many usecs to delay an RX interrupt after + * a packet arrives. If 0, only rx_max_coalesced_frames + * is used. + */ + u32 rx_coalesce_usecs; + + /* How many packets to delay an RX interrupt after + * a packet arrives. If 0, only rx_coalesce_usecs is + * used. It is illegal to set both usecs and max frames + * to zero as this would cause RX interrupts to never be + * generated. + */ + u32 rx_max_coalesced_frames; + + /* Same as above two parameters, except that these values + * apply while an IRQ is being serviced by the host. Not + * all cards support this feature and the values are ignored + * in that case. + */ + u32 rx_coalesce_usecs_irq; + u32 rx_max_coalesced_frames_irq; + + /* How many usecs to delay a TX interrupt after + * a packet is sent. If 0, only tx_max_coalesced_frames + * is used. + */ + u32 tx_coalesce_usecs; + + /* How many packets to delay a TX interrupt after + * a packet is sent. If 0, only tx_coalesce_usecs is + * used. It is illegal to set both usecs and max frames + * to zero as this would cause TX interrupts to never be + * generated. + */ + u32 tx_max_coalesced_frames; + + /* Same as above two parameters, except that these values + * apply while an IRQ is being serviced by the host. Not + * all cards support this feature and the values are ignored + * in that case. + */ + u32 tx_coalesce_usecs_irq; + u32 tx_max_coalesced_frames_irq; + + /* How many usecs to delay in-memory statistics + * block updates. Some drivers do not have an in-memory + * statistic block, and in such cases this value is ignored. + * This value must not be zero. + */ + u32 stats_block_coalesce_usecs; + + /* Adaptive RX/TX coalescing is an algorithm implemented by + * some drivers to improve latency under low packet rates and + * improve throughput under high packet rates. Some drivers + * only implement one of RX or TX adaptive coalescing. Anything + * not implemented by the driver causes these values to be + * silently ignored. + */ + u32 use_adaptive_rx_coalesce; + u32 use_adaptive_tx_coalesce; + + /* When the packet rate (measured in packets per second) + * is below pkt_rate_low, the {rx,tx}_*_low parameters are + * used. + */ + u32 pkt_rate_low; + u32 rx_coalesce_usecs_low; + u32 rx_max_coalesced_frames_low; + u32 tx_coalesce_usecs_low; + u32 tx_max_coalesced_frames_low; + + /* When the packet rate is below pkt_rate_high but above + * pkt_rate_low (both measured in packets per second) the + * normal {rx,tx}_* coalescing parameters are used. + */ + + /* When the packet rate is (measured in packets per second) + * is above pkt_rate_high, the {rx,tx}_*_high parameters are + * used. + */ + u32 pkt_rate_high; + u32 rx_coalesce_usecs_high; + u32 rx_max_coalesced_frames_high; + u32 tx_coalesce_usecs_high; + u32 tx_max_coalesced_frames_high; + + /* How often to do adaptive coalescing packet rate sampling, + * measured in seconds. Must not be zero. + */ + u32 rate_sample_interval; +}; +#endif /* ETHTOOL_GCOALESCE */ + +#ifndef ETHTOOL_SCOALESCE +#define ETHTOOL_SCOALESCE 0x0000000f /* Set coalesce config. */ +#endif +#ifndef ETHTOOL_GRINGPARAM +#define ETHTOOL_GRINGPARAM 0x00000010 /* Get ring parameters */ +/* for configuring RX/TX ring parameters */ +#define ethtool_ringparam _kc_ethtool_ringparam +struct _kc_ethtool_ringparam { + u32 cmd; /* ETHTOOL_{G,S}RINGPARAM */ + + /* Read only attributes. These indicate the maximum number + * of pending RX/TX ring entries the driver will allow the + * user to set. + */ + u32 rx_max_pending; + u32 rx_mini_max_pending; + u32 rx_jumbo_max_pending; + u32 tx_max_pending; + + /* Values changeable by the user. The valid values are + * in the range 1 to the "*_max_pending" counterpart above. + */ + u32 rx_pending; + u32 rx_mini_pending; + u32 rx_jumbo_pending; + u32 tx_pending; +}; +#endif /* ETHTOOL_GRINGPARAM */ + +#ifndef ETHTOOL_SRINGPARAM +#define ETHTOOL_SRINGPARAM 0x00000011 /* Set ring parameters, priv. */ +#endif +#ifndef ETHTOOL_GPAUSEPARAM +#define ETHTOOL_GPAUSEPARAM 0x00000012 /* Get pause parameters */ +/* for configuring link flow control parameters */ +#define ethtool_pauseparam _kc_ethtool_pauseparam +struct _kc_ethtool_pauseparam { + u32 cmd; /* ETHTOOL_{G,S}PAUSEPARAM */ + + /* If the link is being auto-negotiated (via ethtool_cmd.autoneg + * being true) the user may set 'autoneg' here non-zero to have the + * pause parameters be auto-negotiated too. In such a case, the + * {rx,tx}_pause values below determine what capabilities are + * advertised. + * + * If 'autoneg' is zero or the link is not being auto-negotiated, + * then {rx,tx}_pause force the driver to use/not-use pause + * flow control. + */ + u32 autoneg; + u32 rx_pause; + u32 tx_pause; +}; +#endif /* ETHTOOL_GPAUSEPARAM */ + +#ifndef ETHTOOL_SPAUSEPARAM +#define ETHTOOL_SPAUSEPARAM 0x00000013 /* Set pause parameters. */ +#endif +#ifndef ETHTOOL_GRXCSUM +#define ETHTOOL_GRXCSUM 0x00000014 /* Get RX hw csum enable (ethtool_value) */ +#endif +#ifndef ETHTOOL_SRXCSUM +#define ETHTOOL_SRXCSUM 0x00000015 /* Set RX hw csum enable (ethtool_value) */ +#endif +#ifndef ETHTOOL_GTXCSUM +#define ETHTOOL_GTXCSUM 0x00000016 /* Get TX hw csum enable (ethtool_value) */ +#endif +#ifndef ETHTOOL_STXCSUM +#define ETHTOOL_STXCSUM 0x00000017 /* Set TX hw csum enable (ethtool_value) */ +#endif +#ifndef ETHTOOL_GSG +#define ETHTOOL_GSG 0x00000018 /* Get scatter-gather enable + * (ethtool_value) */ +#endif +#ifndef ETHTOOL_SSG +#define ETHTOOL_SSG 0x00000019 /* Set scatter-gather enable + * (ethtool_value). */ +#endif +#ifndef ETHTOOL_TEST +#define ETHTOOL_TEST 0x0000001a /* execute NIC self-test, priv. */ +#endif +#ifndef ETHTOOL_GSTRINGS +#define ETHTOOL_GSTRINGS 0x0000001b /* get specified string set */ +#endif +#ifndef ETHTOOL_PHYS_ID +#define ETHTOOL_PHYS_ID 0x0000001c /* identify the NIC */ +#endif +#ifndef ETHTOOL_GSTATS +#define ETHTOOL_GSTATS 0x0000001d /* get NIC-specific statistics */ +#endif +#ifndef ETHTOOL_GTSO +#define ETHTOOL_GTSO 0x0000001e /* Get TSO enable (ethtool_value) */ +#endif +#ifndef ETHTOOL_STSO +#define ETHTOOL_STSO 0x0000001f /* Set TSO enable (ethtool_value) */ +#endif + +#ifndef ETHTOOL_BUSINFO_LEN +#define ETHTOOL_BUSINFO_LEN 32 +#endif + +/*****************************************************************************/ +/* 2.4.3 => 2.4.0 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) ) + +/**************************************/ +/* PCI DRIVER API */ + +#ifndef pci_set_dma_mask +#define pci_set_dma_mask _kc_pci_set_dma_mask +extern int _kc_pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask); +#endif + +#ifndef pci_request_regions +#define pci_request_regions _kc_pci_request_regions +extern int _kc_pci_request_regions(struct pci_dev *pdev, char *res_name); +#endif + +#ifndef pci_release_regions +#define pci_release_regions _kc_pci_release_regions +extern void _kc_pci_release_regions(struct pci_dev *pdev); +#endif + +/**************************************/ +/* NETWORK DRIVER API */ + +#ifndef alloc_etherdev +#define alloc_etherdev _kc_alloc_etherdev +extern struct net_device * _kc_alloc_etherdev(int sizeof_priv); +#endif + +#ifndef is_valid_ether_addr +#define is_valid_ether_addr _kc_is_valid_ether_addr +extern int _kc_is_valid_ether_addr(u8 *addr); +#endif + +/**************************************/ +/* MISCELLANEOUS */ + +#ifndef INIT_TQUEUE +#define INIT_TQUEUE(_tq, _routine, _data) \ + do { \ + INIT_LIST_HEAD(&(_tq)->list); \ + (_tq)->sync = 0; \ + (_tq)->routine = _routine; \ + (_tq)->data = _data; \ + } while (0) +#endif + +#endif /* 2.4.3 => 2.4.0 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,5) ) +/* Generic MII registers. */ +#define MII_BMCR 0x00 /* Basic mode control register */ +#define MII_BMSR 0x01 /* Basic mode status register */ +#define MII_PHYSID1 0x02 /* PHYS ID 1 */ +#define MII_PHYSID2 0x03 /* PHYS ID 2 */ +#define MII_ADVERTISE 0x04 /* Advertisement control reg */ +#define MII_LPA 0x05 /* Link partner ability reg */ +#define MII_EXPANSION 0x06 /* Expansion register */ +/* Basic mode control register. */ +#define BMCR_FULLDPLX 0x0100 /* Full duplex */ +#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */ +/* Basic mode status register. */ +#define BMSR_ERCAP 0x0001 /* Ext-reg capability */ +#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */ +#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */ +#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */ +#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */ +#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */ +/* Advertisement control register. */ +#define ADVERTISE_CSMA 0x0001 /* Only selector supported */ +#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ +#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ +#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ +#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ +#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \ + ADVERTISE_100HALF | ADVERTISE_100FULL) +/* Expansion register for auto-negotiation. */ +#define EXPANSION_ENABLENPAGE 0x0004 /* This enables npage words */ +#endif + +/*****************************************************************************/ +/* 2.4.6 => 2.4.3 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,6) ) + +#ifndef pci_set_power_state +#define pci_set_power_state _kc_pci_set_power_state +extern int _kc_pci_set_power_state(struct pci_dev *dev, int state); +#endif + +#ifndef pci_save_state +#define pci_save_state _kc_pci_save_state +extern int _kc_pci_save_state(struct pci_dev *dev, u32 *buffer); +#endif + +#ifndef pci_restore_state +#define pci_restore_state _kc_pci_restore_state +extern int _kc_pci_restore_state(struct pci_dev *pdev, u32 *buffer); +#endif + +#ifndef pci_enable_wake +#define pci_enable_wake _kc_pci_enable_wake +extern int _kc_pci_enable_wake(struct pci_dev *pdev, u32 state, int enable); +#endif + +#ifndef pci_disable_device +#define pci_disable_device _kc_pci_disable_device +extern void _kc_pci_disable_device(struct pci_dev *pdev); +#endif + +/* PCI PM entry point syntax changed, so don't support suspend/resume */ +#undef CONFIG_PM + +#endif /* 2.4.6 => 2.4.3 */ + +#ifndef HAVE_PCI_SET_MWI +#define pci_set_mwi(X) pci_write_config_word(X, \ + PCI_COMMAND, adapter->hw.bus.pci_cmd_word | \ + PCI_COMMAND_INVALIDATE); +#define pci_clear_mwi(X) pci_write_config_word(X, \ + PCI_COMMAND, adapter->hw.bus.pci_cmd_word & \ + ~PCI_COMMAND_INVALIDATE); +#endif + +/*****************************************************************************/ +/* 2.4.10 => 2.4.9 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) ) + +/**************************************/ +/* MODULE API */ + +#ifndef MODULE_LICENSE + #define MODULE_LICENSE(X) +#endif + +/**************************************/ +/* OTHER */ + +#undef min +#define min(x,y) ({ \ + const typeof(x) _x = (x); \ + const typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x < _y ? _x : _y; }) + +#undef max +#define max(x,y) ({ \ + const typeof(x) _x = (x); \ + const typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x > _y ? _x : _y; }) + +#ifndef list_for_each_safe +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) +#endif + +#endif /* 2.4.10 -> 2.4.6 */ + + +/*****************************************************************************/ +/* 2.4.13 => 2.4.10 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13) ) + +/**************************************/ +/* PCI DMA MAPPING */ + +#ifndef virt_to_page + #define virt_to_page(v) (mem_map + (virt_to_phys(v) >> PAGE_SHIFT)) +#endif + +#ifndef pci_map_page +#define pci_map_page _kc_pci_map_page +extern u64 _kc_pci_map_page(struct pci_dev *dev, struct page *page, unsigned long offset, size_t size, int direction); +#endif + +#ifndef pci_unmap_page +#define pci_unmap_page _kc_pci_unmap_page +extern void _kc_pci_unmap_page(struct pci_dev *dev, u64 dma_addr, size_t size, int direction); +#endif + +/* pci_set_dma_mask takes dma_addr_t, which is only 32-bits prior to 2.4.13 */ + +#undef DMA_32BIT_MASK +#define DMA_32BIT_MASK 0xffffffff +#undef DMA_64BIT_MASK +#define DMA_64BIT_MASK 0xffffffff + +/**************************************/ +/* OTHER */ + +#ifndef cpu_relax +#define cpu_relax() rep_nop() +#endif + +#endif /* 2.4.13 => 2.4.10 */ + +/*****************************************************************************/ +/* 2.4.17 => 2.4.12 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,17) ) + +#ifndef __devexit_p + #define __devexit_p(x) &(x) +#endif + +#endif /* 2.4.17 => 2.4.13 */ + +/*****************************************************************************/ +/* 2.4.20 => 2.4.19 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20) ) + +/* we won't support NAPI on less than 2.4.20 */ +#ifdef NAPI +#undef CONFIG_E1000_NAPI +#undef CONFIG_E1000E_NAPI +#undef CONFIG_IXGB_NAPI +#endif + +#endif /* 2.4.20 => 2.4.19 */ +/*****************************************************************************/ +/* 2.4.22 => 2.4.17 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,22) ) +#define pci_name(x) ((x)->slot_name) +#endif + +/*****************************************************************************/ +/* 2.4.22 => 2.4.17 */ + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,22) ) +#endif + +/*****************************************************************************/ +/*****************************************************************************/ +/* 2.4.23 => 2.4.22 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23) ) +/*****************************************************************************/ +#ifdef NAPI +#ifndef netif_poll_disable +#define netif_poll_disable(x) _kc_netif_poll_disable(x) +static inline void _kc_netif_poll_disable(struct net_device *netdev) +{ + while (test_and_set_bit(__LINK_STATE_RX_SCHED, &netdev->state)) { + /* No hurry */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } +} +#endif + +#ifndef netif_poll_enable +#define netif_poll_enable(x) _kc_netif_poll_enable(x) +static inline void _kc_netif_poll_enable(struct net_device *netdev) +{ + clear_bit(__LINK_STATE_RX_SCHED, &netdev->state); +} +#endif +#endif /* NAPI */ +#ifndef netif_tx_disable +#define netif_tx_disable(x) _kc_netif_tx_disable(x) +static inline void _kc_netif_tx_disable(struct net_device *dev) +{ + spin_lock_bh(&dev->xmit_lock); + netif_stop_queue(dev); + spin_unlock_bh(&dev->xmit_lock); +} +#endif +#endif /* 2.4.23 => 2.4.22 */ + +/*****************************************************************************/ +/* 2.6.4 => 2.6.0 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,25) || \ + ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) ) ) +#define ETHTOOL_OPS_COMPAT +#endif /* 2.6.4 => 2.6.0 */ + +/*****************************************************************************/ +/* 2.5.71 => 2.4.x */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,5,71) ) +#include +#define sk_protocol protocol + +#define pci_get_device pci_find_device +#endif /* 2.5.70 => 2.4.x */ + +/*****************************************************************************/ +/* < 2.4.27 or 2.6.0 <= 2.6.5 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27) || \ + ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5) ) ) + +#ifndef netif_msg_init +#define netif_msg_init _kc_netif_msg_init +static inline u32 _kc_netif_msg_init(int debug_value, int default_msg_enable_bits) +{ + /* use default */ + if (debug_value < 0 || debug_value >= (sizeof(u32) * 8)) + return default_msg_enable_bits; + if (debug_value == 0) /* no output */ + return 0; + /* set low N bits */ + return (1 << debug_value) -1; +} +#endif + +#endif /* < 2.4.27 or 2.6.0 <= 2.6.5 */ +/*****************************************************************************/ +#if (( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27) ) || \ + (( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) ) && \ + ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3) ))) +#define netdev_priv(x) x->priv +#endif + +/*****************************************************************************/ +/* <= 2.5.0 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ) +#undef pci_register_driver +#define pci_register_driver pci_module_init + +#define dev_err(__unused_dev, format, arg...) \ + printk(KERN_ERR "%s: " format, pci_name(adapter->pdev) , ## arg) + +/* hlist_* code - double linked lists */ +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; +} + +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = NULL; + n->pprev = NULL; +} + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + +static inline int hlist_empty(const struct hlist_head *h) +{ + return !h->first; +} +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +static inline void INIT_HLIST_NODE(struct hlist_node *h) +{ + h->next = NULL; + h->pprev = NULL; +} +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) + +/* we ignore GFP here */ +#define dma_alloc_coherent(dv, sz, dma, gfp) \ + pci_alloc_consistent(pdev, (sz), (dma)) +#define dma_free_coherent(dv, sz, addr, dma_addr) \ + pci_free_consistent(pdev, (sz), (addr), (dma_addr)) + +#ifndef might_sleep +#define might_sleep() +#endif + +#endif /* <= 2.5.0 */ + +/*****************************************************************************/ +/* 2.5.28 => 2.4.23 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,5,28) ) + +static inline void _kc_synchronize_irq(void) +{ + synchronize_irq(); +} +#undef synchronize_irq +#define synchronize_irq(X) _kc_synchronize_irq() + +#include +#define work_struct tq_struct +#undef INIT_WORK +#define INIT_WORK(a,b) INIT_TQUEUE(a,(void (*)(void *))b,a) +#undef container_of +#define container_of list_entry +#define schedule_work schedule_task +#define flush_scheduled_work flush_scheduled_tasks + +#endif /* 2.5.28 => 2.4.17 */ + +/*****************************************************************************/ +/* 2.6.0 => 2.5.28 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ) +#define MODULE_INFO(version, _version) +#ifndef CONFIG_E1000_DISABLE_PACKET_SPLIT +#define CONFIG_E1000_DISABLE_PACKET_SPLIT 1 +#endif +#ifndef CONFIG_IGB_DISABLE_PACKET_SPLIT +#define CONFIG_IGB_DISABLE_PACKET_SPLIT 1 +#endif + +#define pci_set_consistent_dma_mask(dev,mask) 1 + +#undef dev_put +#define dev_put(dev) __dev_put(dev) + +#ifndef skb_fill_page_desc +#define skb_fill_page_desc _kc_skb_fill_page_desc +extern void _kc_skb_fill_page_desc(struct sk_buff *skb, int i, struct page *page, int off, int size); +#endif + +#ifndef pci_dma_mapping_error +#define pci_dma_mapping_error _kc_pci_dma_mapping_error +static inline int _kc_pci_dma_mapping_error(dma_addr_t dma_addr) +{ + return dma_addr == 0; +} +#endif + +#undef ALIGN +#define ALIGN(x,a) (((x)+(a)-1)&~((a)-1)) + +/* find_first_bit and find_next bit are not defined for most + * 2.4 kernels (except for the redhat 2.4.21 kernels + */ +#include +#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) +#undef find_next_bit +#define find_next_bit _kc_find_next_bit +extern unsigned long _kc_find_next_bit(const unsigned long *addr, + unsigned long size, + unsigned long offset); +#define find_first_bit(addr, size) find_next_bit((addr), (size), 0) + +#endif /* 2.6.0 => 2.5.28 */ + +/*****************************************************************************/ +/* 2.6.4 => 2.6.0 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) ) +#define MODULE_VERSION(_version) MODULE_INFO(version, _version) +#endif /* 2.6.4 => 2.6.0 */ + +/*****************************************************************************/ +/* 2.6.5 => 2.6.0 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5) ) +#define pci_dma_sync_single_for_cpu pci_dma_sync_single +#define pci_dma_sync_single_for_device pci_dma_sync_single_for_cpu +#endif /* 2.6.5 => 2.6.0 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6) ) +/* taken from 2.6 include/linux/bitmap.h */ +#undef bitmap_zero +#define bitmap_zero _kc_bitmap_zero +static inline void _kc_bitmap_zero(unsigned long *dst, int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = 0UL; + else { + int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); + memset(dst, 0, len); + } +} +#endif /* < 2.6.6 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7) ) +#undef if_mii +#define if_mii _kc_if_mii +static inline struct mii_ioctl_data *_kc_if_mii(struct ifreq *rq) +{ + return (struct mii_ioctl_data *) &rq->ifr_ifru; +} +#endif /* < 2.6.7 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) ) +#define msleep(x) do { set_current_state(TASK_UNINTERRUPTIBLE); \ + schedule_timeout((x * HZ)/1000 + 2); \ + } while (0) + +#endif /* < 2.6.8 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)) +#include +#define __iomem + +#ifndef kcalloc +#define kcalloc(n, size, flags) _kc_kzalloc(((n) * (size)), flags) +extern void *_kc_kzalloc(size_t size, int flags); +#endif +#define MSEC_PER_SEC 1000L +static inline unsigned int _kc_jiffies_to_msecs(const unsigned long j) +{ +#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ) + return (MSEC_PER_SEC / HZ) * j; +#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC) + return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC); +#else + return (j * MSEC_PER_SEC) / HZ; +#endif +} +static inline unsigned long _kc_msecs_to_jiffies(const unsigned int m) +{ + if (m > _kc_jiffies_to_msecs(MAX_JIFFY_OFFSET)) + return MAX_JIFFY_OFFSET; +#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ) + return (m + (MSEC_PER_SEC / HZ) - 1) / (MSEC_PER_SEC / HZ); +#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC) + return m * (HZ / MSEC_PER_SEC); +#else + return (m * HZ + MSEC_PER_SEC - 1) / MSEC_PER_SEC; +#endif +} + +#define msleep_interruptible _kc_msleep_interruptible +static inline unsigned long _kc_msleep_interruptible(unsigned int msecs) +{ + unsigned long timeout = _kc_msecs_to_jiffies(msecs) + 1; + + while (timeout && !signal_pending(current)) { + __set_current_state(TASK_INTERRUPTIBLE); + timeout = schedule_timeout(timeout); + } + return _kc_jiffies_to_msecs(timeout); +} + +/* Basic mode control register. */ +#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */ +#endif /* < 2.6.9 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,6) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) ) +#ifdef pci_save_state +#undef pci_save_state +#endif +#define pci_save_state(X) { \ + int i; \ + if (adapter->pci_state) { \ + for (i = 0; i < 16; i++) { \ + pci_read_config_dword((X), \ + i * 4, \ + &adapter->pci_state[i]); \ + } \ + } \ +} + +#ifdef pci_restore_state +#undef pci_restore_state +#endif +#define pci_restore_state(X) { \ + int i; \ + if (adapter->pci_state) { \ + for (i = 0; i < 16; i++) { \ + pci_write_config_dword((X), \ + i * 4, \ + adapter->pci_state[i]); \ + } \ + } else { \ + for (i = 0; i < 6; i++) { \ + pci_write_config_dword((X), \ + PCI_BASE_ADDRESS_0 + (i * 4), \ + (X)->resource[i].start); \ + } \ + } \ +} +#endif /* 2.4.6 <= x < 2.6.10 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) ) +#ifdef module_param_array_named +#undef module_param_array_named +#define module_param_array_named(name, array, type, nump, perm) \ + static struct kparam_array __param_arr_##name \ + = { ARRAY_SIZE(array), nump, param_set_##type, param_get_##type, \ + sizeof(array[0]), array }; \ + module_param_call(name, param_array_set, param_array_get, \ + &__param_arr_##name, perm) +#endif /* module_param_array_named */ +#endif /* < 2.6.10 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) ) +#define PCI_D0 0 +#define PCI_D1 1 +#define PCI_D2 2 +#define PCI_D3hot 3 +#define PCI_D3cold 4 +#define pci_choose_state(pdev,state) state +#define PMSG_SUSPEND 3 + +#undef NETIF_F_LLTX + +#ifndef ARCH_HAS_PREFETCH +#define prefetch(X) +#endif + +#ifndef NET_IP_ALIGN +#define NET_IP_ALIGN 2 +#endif + +#define KC_USEC_PER_SEC 1000000L +#define usecs_to_jiffies _kc_usecs_to_jiffies +static inline unsigned int _kc_jiffies_to_usecs(const unsigned long j) +{ +#if HZ <= KC_USEC_PER_SEC && !(KC_USEC_PER_SEC % HZ) + return (KC_USEC_PER_SEC / HZ) * j; +#elif HZ > KC_USEC_PER_SEC && !(HZ % KC_USEC_PER_SEC) + return (j + (HZ / KC_USEC_PER_SEC) - 1)/(HZ / KC_USEC_PER_SEC); +#else + return (j * KC_USEC_PER_SEC) / HZ; +#endif +} +static inline unsigned long _kc_usecs_to_jiffies(const unsigned int m) +{ + if (m > _kc_jiffies_to_usecs(MAX_JIFFY_OFFSET)) + return MAX_JIFFY_OFFSET; +#if HZ <= KC_USEC_PER_SEC && !(KC_USEC_PER_SEC % HZ) + return (m + (KC_USEC_PER_SEC / HZ) - 1) / (KC_USEC_PER_SEC / HZ); +#elif HZ > KC_USEC_PER_SEC && !(HZ % KC_USEC_PER_SEC) + return m * (HZ / KC_USEC_PER_SEC); +#else + return (m * HZ + KC_USEC_PER_SEC - 1) / KC_USEC_PER_SEC; +#endif +} +#endif /* < 2.6.11 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) ) +#include +#define USE_REBOOT_NOTIFIER + +/* Generic MII registers. */ +#define MII_CTRL1000 0x09 /* 1000BASE-T control */ +#define MII_STAT1000 0x0a /* 1000BASE-T status */ +/* Advertisement control register. */ +#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ +#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymmetric pause */ +/* 1000BASE-T Control register */ +#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */ +#endif + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) ) +#define pm_message_t u32 +#ifndef kzalloc +#define kzalloc _kc_kzalloc +extern void *_kc_kzalloc(size_t size, int flags); +#endif + +/* Generic MII registers. */ +#define MII_ESTATUS 0x0f /* Extended Status */ +/* Basic mode status register. */ +#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */ +/* Extended status register. */ +#define ESTATUS_1000_TFULL 0x2000 /* Can do 1000BT Full */ +#define ESTATUS_1000_THALF 0x1000 /* Can do 1000BT Half */ +#endif + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) ) +#undef HAVE_PCI_ERS +#else /* 2.6.16 and above */ +#undef HAVE_PCI_ERS +#define HAVE_PCI_ERS +#endif + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ) + +#ifndef IRQF_PROBE_SHARED +#ifdef SA_PROBEIRQ +#define IRQF_PROBE_SHARED SA_PROBEIRQ +#else +#define IRQF_PROBE_SHARED 0 +#endif +#endif + +#ifndef IRQF_SHARED +#define IRQF_SHARED SA_SHIRQ +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +#ifndef netdev_alloc_skb +#define netdev_alloc_skb _kc_netdev_alloc_skb +extern struct sk_buff *_kc_netdev_alloc_skb(struct net_device *dev, + unsigned int length); +#endif + +#ifndef skb_is_gso +#ifdef NETIF_F_TSO +#define skb_is_gso _kc_skb_is_gso +static inline int _kc_skb_is_gso(const struct sk_buff *skb) +{ + return skb_shinfo(skb)->gso_size; +} +#else +#define skb_is_gso(a) 0 +#endif +#endif + +#endif /* < 2.6.18 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) ) + +#ifndef DIV_ROUND_UP +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) +#endif + +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ) +#ifndef RHEL_RELEASE_CODE +#define RHEL_RELEASE_CODE 0 +#endif +#ifndef RHEL_RELEASE_VERSION +#define RHEL_RELEASE_VERSION(a,b) 0 +#endif +#if (!(( RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(4,4) ) && ( RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,0) ) || ( RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(5,0) ))) +typedef irqreturn_t (*irq_handler_t)(int, void*, struct pt_regs *); +#endif +typedef irqreturn_t (*new_handler_t)(int, void*); +static inline irqreturn_t _kc_request_irq(unsigned int irq, new_handler_t handler, unsigned long flags, const char *devname, void *dev_id) +#else /* 2.4.x */ +typedef void (*irq_handler_t)(int, void*, struct pt_regs *); +typedef void (*new_handler_t)(int, void*); +static inline int _kc_request_irq(unsigned int irq, new_handler_t handler, unsigned long flags, const char *devname, void *dev_id) +#endif +{ + irq_handler_t new_handler = (irq_handler_t) handler; + return request_irq(irq, new_handler, flags, devname, dev_id); +} + +#undef request_irq +#define request_irq(irq, handler, flags, devname, dev_id) _kc_request_irq((irq), (handler), (flags), (devname), (dev_id)) + +#define irq_handler_t new_handler_t + +/* pci_restore_state and pci_save_state handles MSI/PCIE from 2.6.19 */ +#define PCIE_CONFIG_SPACE_LEN 256 +#define PCI_CONFIG_SPACE_LEN 64 +#define PCIE_LINK_STATUS 0x12 +#ifdef DRIVER_E1000E +#define pci_config_space_ich8lan() { \ + if (adapter->flags & FLAG_IS_ICH) \ + size = PCIE_CONFIG_SPACE_LEN; \ +} +#else +#define pci_config_space_ich8lan() +#endif +#undef pci_save_state +#define pci_save_state(pdev) _kc_pci_save_state(adapter) +#define _kc_pci_save_state(adapter) 0; { \ + int size = PCI_CONFIG_SPACE_LEN, i; \ + u16 pcie_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_EXP); \ + u16 pcie_link_status; \ + \ + if (pcie_cap_offset) { \ + if (!pci_read_config_word(pdev, pcie_cap_offset + PCIE_LINK_STATUS, \ + &pcie_link_status)) \ + size = PCIE_CONFIG_SPACE_LEN; \ + } \ + pci_config_space_ich8lan(); \ + WARN_ON(adapter->config_space != NULL); \ + adapter->config_space = kmalloc(size, GFP_KERNEL); \ + if (!adapter->config_space) { \ + printk(KERN_ERR "Out of memory in pci_save_state\n"); \ + return -ENOMEM; \ + } \ + for (i = 0; i < (size / 4); i++) \ + pci_read_config_dword(pdev, i * 4, &adapter->config_space[i]); \ +} +#undef pci_restore_state +#define pci_restore_state(pdev) _kc_pci_restore_state(adapter) +#define _kc_pci_restore_state(adapter) { \ + int size = PCI_CONFIG_SPACE_LEN, i; \ + u16 pcie_cap_offset; \ + u16 pcie_link_status; \ + \ + if (adapter->config_space != NULL) { \ + pcie_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_EXP); \ + if (pcie_cap_offset) { \ + if (!pci_read_config_word(pdev, pcie_cap_offset + PCIE_LINK_STATUS, \ + &pcie_link_status)) \ + size = PCIE_CONFIG_SPACE_LEN; \ + } \ + pci_config_space_ich8lan(); \ + for (i = 0; i < (size / 4); i++) \ + pci_write_config_dword(pdev, i * 4, adapter->config_space[i]); \ + kfree(adapter->config_space); \ + adapter->config_space = NULL; \ + } \ +} + +#endif /* < 2.6.19 */ +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ) +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28) ) +#undef INIT_WORK +#define INIT_WORK(_work, _func) \ +do { \ + INIT_LIST_HEAD(&(_work)->entry); \ + (_work)->pending = 0; \ + (_work)->func = (void (*)(void *))_func; \ + (_work)->data = _work; \ + init_timer(&(_work)->timer); \ +} while (0) +#endif + +#ifndef PCI_VDEVICE +#define PCI_VDEVICE(ven, dev) \ + PCI_VENDOR_ID_##ven, (dev), \ + PCI_ANY_ID, PCI_ANY_ID, 0, 0 +#endif + +#ifndef round_jiffies +#define round_jiffies(x) x +#endif + +#define csum_offset csum + +#endif /* < 2.6.20 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) ) +#define vlan_group_get_device(vg, id) (vg->vlan_devices[id]) +#define vlan_group_set_device(vg, id, dev) if (vg) vg->vlan_devices[id] = dev; +#define pci_channel_offline(pdev) (pdev->error_state && \ + pdev->error_state != pci_channel_io_normal) +#endif /* < 2.6.21 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) ) +#define tcp_hdr(skb) (skb->h.th) +#define tcp_hdrlen(skb) (skb->h.th->doff << 2) +#define skb_transport_offset(skb) (skb->h.raw - skb->data) +#define skb_transport_header(skb) (skb->h.raw) +#define ipv6_hdr(skb) (skb->nh.ipv6h) +#define ip_hdr(skb) (skb->nh.iph) +#define skb_network_offset(skb) (skb->nh.raw - skb->data) +#define skb_network_header(skb) (skb->nh.raw) +#define skb_tail_pointer(skb) skb->tail +#define skb_copy_to_linear_data_offset(skb, offset, from, len) \ + memcpy(skb->data + offset, from, len) +#define skb_network_header_len(skb) (skb->h.raw - skb->nh.raw) +#define pci_register_driver pci_module_init +#define skb_mac_header(skb) skb->mac.raw + +#ifdef NETIF_F_MULTI_QUEUE +#ifndef alloc_etherdev_mq +#define alloc_etherdev_mq(_a, _b) alloc_etherdev(_a) +#endif +#endif /* NETIF_F_MULTI_QUEUE */ + +#ifndef ETH_FCS_LEN +#define ETH_FCS_LEN 4 +#endif +#endif /* < 2.6.22 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) ) +#undef ETHTOOL_GPERMADDR +#undef SET_MODULE_OWNER +#define SET_MODULE_OWNER(dev) do { } while (0) +#endif /* > 2.6.22 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ) +/* NAPI API changes in 2.6.24 break everything */ +struct napi_struct { + /* used to look up the real NAPI polling routine */ + int (*poll)(struct napi_struct *, int); + int weight; +}; +#ifdef NAPI +extern int __kc_adapter_clean(struct net_device *, int *); +#define netif_rx_complete(netdev, napi) netif_rx_complete(netdev) +#define netif_rx_schedule_prep(netdev, napi) netif_rx_schedule_prep(netdev) +#define netif_rx_schedule(netdev, napi) netif_rx_schedule(netdev) +#define __netif_rx_schedule(netdev, napi) __netif_rx_schedule(netdev) +#define napi_enable(napi) netif_poll_enable(adapter->netdev) +#define napi_disable(napi) netif_poll_disable(adapter->netdev) +#define netif_napi_add(_netdev, _napi, _poll, _weight) \ + do { \ + struct napi_struct *__napi = _napi; \ + _netdev->poll = &(__kc_adapter_clean); \ + _netdev->weight = (_weight); \ + __napi->poll = &(_poll); \ + __napi->weight = (_weight); \ + netif_poll_disable(_netdev); \ + } while (0) +#else /* NAPI */ +#define netif_napi_add(_netdev, _napi, _poll, _weight) \ + do { \ + struct napi_struct *__napi = _napi; \ + _netdev->poll = &(_poll); \ + _netdev->weight = (_weight); \ + __napi->poll = &(_poll); \ + __napi->weight = (_weight); \ + } while (0) +#endif /* NAPI */ + +#undef dev_get_by_name +#define dev_get_by_name(_a, _b) dev_get_by_name(_b) +#define __netif_subqueue_stopped(_a, _b) netif_subqueue_stopped(_a, _b) +#endif /* < 2.6.24 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24) ) +#include +#endif /* > 2.6.24 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) ) +#define PM_QOS_CPU_DMA_LATENCY 1 + +#if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) ) +#include +#define PM_QOS_DEFAULT_VALUE INFINITE_LATENCY +#define pm_qos_add_requirement(pm_qos_class, name, value) \ + set_acceptable_latency(name, value) +#define pm_qos_remove_requirement(pm_qos_class, name) \ + remove_acceptable_latency(name) +#define pm_qos_update_requirement(pm_qos_class, name, value) \ + modify_acceptable_latency(name, value) +#else +#define PM_QOS_DEFAULT_VALUE -1 +#define pm_qos_add_requirement(pm_qos_class, name, value) +#define pm_qos_remove_requirement(pm_qos_class, name) +#define pm_qos_update_requirement(pm_qos_class, name, value) { \ + if (value != PM_QOS_DEFAULT_VALUE) { \ + printk(KERN_WARNING "%s: unable to set PM QoS requirement\n", \ + pci_name(adapter->pdev)); \ + } \ +} +#endif /* > 2.6.18 */ + +#endif /* < 2.6.25 */ + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) ) +#endif /* < 2.6.26 */ + +#ifndef NETIF_F_MULTI_QUEUE +#define NETIF_F_MULTI_QUEUE 0 +#define netif_is_multiqueue(a) 0 +#define netif_stop_subqueue(a, b) +#define netif_wake_subqueue(a, b) +#define netif_start_subqueue(a, b) +#endif /* NETIF_F_MULTI_QUEUE */ + +#endif /* _KCOMPAT_H_ */ --- linux-2.6.27.orig/ubuntu/e1000e/e1000_osdep.h +++ linux-2.6.27/ubuntu/e1000e/e1000_osdep.h @@ -0,0 +1,116 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + + +/* glue for the OS-dependent part of e1000 + * includes register access macros + */ + +#ifndef _E1000_OSDEP_H_ +#define _E1000_OSDEP_H_ + +#include +#include +#include +#include + +#include "kcompat.h" + +#define usec_delay(x) udelay(x) +#ifndef msec_delay +#define msec_delay(x) do { if(in_interrupt()) { \ + /* Don't sleep in interrupt context! */ \ + BUG(); \ + } else { \ + msleep(x); \ + } } while (0) + +/* Some workarounds require millisecond delays and are run during interrupt + * context. Most notably, when establishing link, the phy may need tweaking + * but cannot process phy register reads/writes faster than millisecond + * intervals...and we establish link due to a "link status change" interrupt. + */ +#define msec_delay_irq(x) mdelay(x) +#endif + +#define PCI_COMMAND_REGISTER PCI_COMMAND +#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE +#define ETH_ADDR_LEN ETH_ALEN + + +#define DEBUGOUT(S) +#define DEBUGOUT1(S, A...) + +#define DEBUGFUNC(F) DEBUGOUT(F "\n") +#define DEBUGOUT2 DEBUGOUT1 +#define DEBUGOUT3 DEBUGOUT2 +#define DEBUGOUT7 DEBUGOUT3 + +#define E1000_WRITE_REG(a, reg, value) ( \ + writel((value), ((a)->hw_addr + reg))) + +#define E1000_READ_REG(a, reg) (readl((a)->hw_addr + reg)) + +#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \ + writel((value), ((a)->hw_addr + reg + ((offset) << 2)))) + +#define E1000_READ_REG_ARRAY(a, reg, offset) ( \ + readl((a)->hw_addr + reg + ((offset) << 2))) + +#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY +#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY + +#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \ + writew((value), ((a)->hw_addr + reg + ((offset) << 1)))) + +#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \ + readw((a)->hw_addr + reg + ((offset) << 1))) + +#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \ + writeb((value), ((a)->hw_addr + reg + (offset)))) + +#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \ + readb((a)->hw_addr + reg + (offset))) + +#define E1000_WRITE_REG_IO(a, reg, offset) do { \ + outl(reg, ((a)->io_base)); \ + outl(offset, ((a)->io_base + 4)); } while(0) + +#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, E1000_STATUS) + +#define E1000_WRITE_FLASH_REG(a, reg, value) ( \ + writel((value), ((a)->flash_address + reg))) + +#define E1000_WRITE_FLASH_REG16(a, reg, value) ( \ + writew((value), ((a)->flash_address + reg))) + +#define E1000_READ_FLASH_REG(a, reg) (readl((a)->flash_address + reg)) + +#define E1000_READ_FLASH_REG16(a, reg) (readw((a)->flash_address + reg)) + +#endif /* _E1000_OSDEP_H_ */ --- linux-2.6.27.orig/ubuntu/e1000e/e1000_nvm.h +++ linux-2.6.27/ubuntu/e1000e/e1000_nvm.h @@ -0,0 +1,58 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_NVM_H_ +#define _E1000_NVM_H_ + +void e1000_init_nvm_ops_generic(struct e1000_hw *hw); +s32 e1000_acquire_nvm_generic(struct e1000_hw *hw); + +s32 e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg); +s32 e1000_read_mac_addr_generic(struct e1000_hw *hw); +s32 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num); +s32 e1000_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); +s32 e1000_read_nvm_microwire(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data); +s32 e1000_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data); +s32 e1000_valid_led_default_generic(struct e1000_hw *hw, u16 *data); +s32 e1000_validate_nvm_checksum_generic(struct e1000_hw *hw); +s32 e1000_write_nvm_eewr(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data); +s32 e1000_write_nvm_microwire(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data); +s32 e1000_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data); +s32 e1000_update_nvm_checksum_generic(struct e1000_hw *hw); +void e1000_stop_nvm(struct e1000_hw *hw); +void e1000_release_nvm_generic(struct e1000_hw *hw); +void e1000_reload_nvm_generic(struct e1000_hw *hw); + +#define E1000_STM_OPCODE 0xDB00 + +#endif --- linux-2.6.27.orig/ubuntu/e1000e/e1000_phy.h +++ linux-2.6.27/ubuntu/e1000e/e1000_phy.h @@ -0,0 +1,190 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_PHY_H_ +#define _E1000_PHY_H_ + +typedef enum { + e1000_ms_hw_default = 0, + e1000_ms_force_master, + e1000_ms_force_slave, + e1000_ms_auto +} e1000_ms_type; + +typedef enum { + e1000_smart_speed_default = 0, + e1000_smart_speed_on, + e1000_smart_speed_off +} e1000_smart_speed; + +void e1000_init_phy_ops_generic(struct e1000_hw *hw); +s32 e1000_check_downshift_generic(struct e1000_hw *hw); +s32 e1000_check_polarity_m88(struct e1000_hw *hw); +s32 e1000_check_polarity_igp(struct e1000_hw *hw); +s32 e1000_check_reset_block_generic(struct e1000_hw *hw); +s32 e1000_copper_link_autoneg(struct e1000_hw *hw); +s32 e1000_copper_link_setup_igp(struct e1000_hw *hw); +s32 e1000_copper_link_setup_m88(struct e1000_hw *hw); +s32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw); +s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw); +s32 e1000_get_cable_length_m88(struct e1000_hw *hw); +s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw); +s32 e1000_get_cfg_done_generic(struct e1000_hw *hw); +s32 e1000_get_phy_id(struct e1000_hw *hw); +s32 e1000_get_phy_info_igp(struct e1000_hw *hw); +s32 e1000_get_phy_info_m88(struct e1000_hw *hw); +s32 e1000_phy_sw_reset_generic(struct e1000_hw *hw); +void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl); +s32 e1000_phy_hw_reset_generic(struct e1000_hw *hw); +s32 e1000_phy_reset_dsp_generic(struct e1000_hw *hw); +s32 e1000_phy_setup_autoneg(struct e1000_hw *hw); +s32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data); +s32 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data); +s32 e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data); +s32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active); +s32 e1000_setup_copper_link_generic(struct e1000_hw *hw); +s32 e1000_wait_autoneg_generic(struct e1000_hw *hw); +s32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data); +s32 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data); +s32 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data); +s32 e1000_phy_reset_dsp(struct e1000_hw *hw); +s32 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, + u32 usec_interval, bool *success); +s32 e1000_phy_init_script_igp3(struct e1000_hw *hw); +e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id); +s32 e1000_determine_phy_address(struct e1000_hw* hw); +s32 e1000_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data); +s32 e1000_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data); +s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data, + bool read); +s32 e1000_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data); +s32 e1000_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data); +void e1000_power_up_phy_copper(struct e1000_hw *hw); +void e1000_power_down_phy_copper(struct e1000_hw *hw); +s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); +s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); + +#define E1000_MAX_PHY_ADDR 4 + +/* IGP01E1000 Specific Registers */ +#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */ +#define IGP01E1000_PHY_PORT_STATUS 0x11 /* Status */ +#define IGP01E1000_PHY_PORT_CTRL 0x12 /* Control */ +#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health */ +#define IGP01E1000_GMII_FIFO 0x14 /* GMII FIFO */ +#define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality */ +#define IGP02E1000_PHY_POWER_MGMT 0x19 /* Power Management */ +#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* Page Select */ +#define BM_PHY_PAGE_SELECT 22 /* Page Select for BM */ +#define IGP_PAGE_SHIFT 5 +#define PHY_REG_MASK 0x1F + +#define BM_WUC_PAGE 800 +#define BM_WUC_ADDRESS_OPCODE 0x11 +#define BM_WUC_DATA_OPCODE 0x12 +#define BM_WUC_ENABLE_PAGE 769 +#define BM_WUC_ENABLE_REG 17 +#define BM_WUC_ENABLE_BIT (1 << 2) +#define BM_WUC_HOST_WU_BIT (1 << 4) + +/* BM PHY Copper Specific Control 1 */ +#define BM_CS_CTRL1 16 +#define BM_CS_CTRL1_ENERGY_DETECT 0x0300 /* Enable Energy Detect */ + +/* BM PHY Copper Specific States */ +#define BM_CS_STATUS 17 +#define BM_CS_STATUS_ENERGY_DETECT 0x0010 /* Energy Detect Status */ + +#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4 +#define IGP01E1000_PHY_POLARITY_MASK 0x0078 + +#define IGP01E1000_PSCR_AUTO_MDIX 0x1000 +#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0=MDI, 1=MDIX */ + +#define IGP01E1000_PSCFR_SMART_SPEED 0x0080 + +/* Enable flexible speed on link-up */ +#define IGP01E1000_GMII_FLEX_SPD 0x0010 +#define IGP01E1000_GMII_SPD 0x0020 /* Enable SPD */ + +#define IGP02E1000_PM_SPD 0x0001 /* Smart Power Down */ +#define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */ +#define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */ + +#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000 + +#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002 +#define IGP01E1000_PSSR_MDIX 0x0008 +#define IGP01E1000_PSSR_SPEED_MASK 0xC000 +#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000 + +#define IGP02E1000_PHY_CHANNEL_NUM 4 +#define IGP02E1000_PHY_AGC_A 0x11B1 +#define IGP02E1000_PHY_AGC_B 0x12B1 +#define IGP02E1000_PHY_AGC_C 0x14B1 +#define IGP02E1000_PHY_AGC_D 0x18B1 + +#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Course - 15:13, Fine - 12:9 */ +#define IGP02E1000_AGC_LENGTH_MASK 0x7F +#define IGP02E1000_AGC_RANGE 15 + +#define IGP03E1000_PHY_MISC_CTRL 0x1B +#define IGP03E1000_PHY_MISC_DUPLEX_MANUAL_SET 0x1000 /* Manually Set Duplex */ + +#define E1000_CABLE_LENGTH_UNDEFINED 0xFF + +#define E1000_KMRNCTRLSTA_OFFSET 0x001F0000 +#define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16 +#define E1000_KMRNCTRLSTA_REN 0x00200000 +#define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */ +#define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */ + +#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 +#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */ +#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */ +#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control */ + +/* IFE PHY Extended Status Control */ +#define IFE_PESC_POLARITY_REVERSED 0x0100 + +/* IFE PHY Special Control */ +#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010 +#define IFE_PSC_FORCE_POLARITY 0x0020 +#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100 + +/* IFE PHY Special Control and LED Control */ +#define IFE_PSCL_PROBE_MODE 0x0020 +#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */ +#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */ + +/* IFE PHY MDIX Control */ +#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */ +#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDI-X, 0=force MDI */ +#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */ + +#endif --- linux-2.6.27.orig/ubuntu/e1000e/e1000_80003es2lan.c +++ linux-2.6.27/ubuntu/e1000e/e1000_80003es2lan.c @@ -0,0 +1,1419 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* e1000_80003es2lan + */ + +#include "e1000_hw.h" + +static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw); +static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw); +static s32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw); +static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw); +static void e1000_release_phy_80003es2lan(struct e1000_hw *hw); +static s32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw); +static void e1000_release_nvm_80003es2lan(struct e1000_hw *hw); +static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, + u32 offset, + u16 *data); +static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, + u32 offset, + u16 data); +static s32 e1000_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data); +static s32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw); +static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw); +static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw); +static s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed, + u16 *duplex); +static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw); +static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw); +static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw); +static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw); +static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask); +static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex); +static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw); +static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw); +static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw); +static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask); +static s32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw); +static void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw); + +/* + * A table for the GG82563 cable length where the range is defined + * with a lower bound at "index" and the upper bound at + * "index + 5". + */ +static const u16 e1000_gg82563_cable_length_table[] = + { 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF }; +#define GG82563_CABLE_LENGTH_TABLE_SIZE \ + (sizeof(e1000_gg82563_cable_length_table) / \ + sizeof(e1000_gg82563_cable_length_table[0])) + +/** + * e1000_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs. + * @hw: pointer to the HW structure + * + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_init_phy_params_80003es2lan"); + + if (hw->phy.media_type != e1000_media_type_copper) { + phy->type = e1000_phy_none; + goto out; + } else { + phy->ops.power_up = e1000_power_up_phy_copper; + phy->ops.power_down = e1000_power_down_phy_copper_80003es2lan; + } + + phy->addr = 1; + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; + phy->reset_delay_us = 100; + phy->type = e1000_phy_gg82563; + + phy->ops.acquire = e1000_acquire_phy_80003es2lan; + phy->ops.check_polarity = e1000_check_polarity_m88; + phy->ops.check_reset_block = e1000_check_reset_block_generic; + phy->ops.commit = e1000_phy_sw_reset_generic; + phy->ops.get_cfg_done = e1000_get_cfg_done_80003es2lan; + phy->ops.get_info = e1000_get_phy_info_m88; + phy->ops.release = e1000_release_phy_80003es2lan; + phy->ops.reset = e1000_phy_hw_reset_generic; + phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_generic; + + phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_80003es2lan; + phy->ops.get_cable_length = e1000_get_cable_length_80003es2lan; + phy->ops.read_reg = e1000_read_phy_reg_gg82563_80003es2lan; + phy->ops.write_reg = e1000_write_phy_reg_gg82563_80003es2lan; + + /* This can only be done after all function pointers are setup. */ + ret_val = e1000_get_phy_id(hw); + + /* Verify phy id */ + if (phy->id != GG82563_E_PHY_ID) { + ret_val = -E1000_ERR_PHY; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_init_nvm_params_80003es2lan - Init ESB2 NVM func ptrs. + * @hw: pointer to the HW structure + * + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 eecd = E1000_READ_REG(hw, E1000_EECD); + u16 size; + + DEBUGFUNC("e1000_init_nvm_params_80003es2lan"); + + nvm->opcode_bits = 8; + nvm->delay_usec = 1; + switch (nvm->override) { + case e1000_nvm_override_spi_large: + nvm->page_size = 32; + nvm->address_bits = 16; + break; + case e1000_nvm_override_spi_small: + nvm->page_size = 8; + nvm->address_bits = 8; + break; + default: + nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8; + nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8; + break; + } + + nvm->type = e1000_nvm_eeprom_spi; + + size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >> + E1000_EECD_SIZE_EX_SHIFT); + + /* + * Added to a constant, "size" becomes the left-shift value + * for setting word_size. + */ + size += NVM_WORD_SIZE_BASE_SHIFT; + + /* EEPROM access above 16k is unsupported */ + if (size > 14) + size = 14; + nvm->word_size = 1 << size; + + /* Function Pointers */ + nvm->ops.acquire = e1000_acquire_nvm_80003es2lan; + nvm->ops.read = e1000_read_nvm_eerd; + nvm->ops.release = e1000_release_nvm_80003es2lan; + nvm->ops.update = e1000_update_nvm_checksum_generic; + nvm->ops.valid_led_default = e1000_valid_led_default_generic; + nvm->ops.validate = e1000_validate_nvm_checksum_generic; + nvm->ops.write = e1000_write_nvm_80003es2lan; + + return E1000_SUCCESS; +} + +/** + * e1000_init_mac_params_80003es2lan - Init ESB2 MAC func ptrs. + * @hw: pointer to the HW structure + * + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_init_mac_params_80003es2lan"); + + /* Set media type */ + switch (hw->device_id) { + case E1000_DEV_ID_80003ES2LAN_SERDES_DPT: + hw->phy.media_type = e1000_media_type_internal_serdes; + break; + default: + hw->phy.media_type = e1000_media_type_copper; + break; + } + + /* Set mta register count */ + mac->mta_reg_count = 128; + /* Set rar entry count */ + mac->rar_entry_count = E1000_RAR_ENTRIES; + /* Set if part includes ASF firmware */ + mac->asf_firmware_present = true; + /* Set if manageability features are enabled. */ + mac->arc_subsystem_valid = + (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK) + ? true : false; + + /* Function pointers */ + + /* bus type/speed/width */ + mac->ops.get_bus_info = e1000_get_bus_info_pcie_generic; + /* reset */ + mac->ops.reset_hw = e1000_reset_hw_80003es2lan; + /* hw initialization */ + mac->ops.init_hw = e1000_init_hw_80003es2lan; + /* link setup */ + mac->ops.setup_link = e1000_setup_link_generic; + /* physical interface link setup */ + mac->ops.setup_physical_interface = + (hw->phy.media_type == e1000_media_type_copper) + ? e1000_setup_copper_link_80003es2lan + : e1000_setup_fiber_serdes_link_generic; + /* check for link */ + switch (hw->phy.media_type) { + case e1000_media_type_copper: + mac->ops.check_for_link = e1000_check_for_copper_link_generic; + break; + case e1000_media_type_fiber: + mac->ops.check_for_link = e1000_check_for_fiber_link_generic; + break; + case e1000_media_type_internal_serdes: + mac->ops.check_for_link = e1000_check_for_serdes_link_generic; + break; + default: + ret_val = -E1000_ERR_CONFIG; + goto out; + break; + } + /* check management mode */ + mac->ops.check_mng_mode = e1000_check_mng_mode_generic; + /* multicast address update */ + mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; + /* writing VFTA */ + mac->ops.write_vfta = e1000_write_vfta_generic; + /* clearing VFTA */ + mac->ops.clear_vfta = e1000_clear_vfta_generic; + /* setting MTA */ + mac->ops.mta_set = e1000_mta_set_generic; + /* read mac address */ + mac->ops.read_mac_addr = e1000_read_mac_addr_80003es2lan; + /* blink LED */ + mac->ops.blink_led = e1000_blink_led_generic; + /* setup LED */ + mac->ops.setup_led = e1000_setup_led_generic; + /* cleanup LED */ + mac->ops.cleanup_led = e1000_cleanup_led_generic; + /* turn on/off LED */ + mac->ops.led_on = e1000_led_on_generic; + mac->ops.led_off = e1000_led_off_generic; + /* remove device */ + mac->ops.remove_device = e1000_remove_device_generic; + /* clear hardware counters */ + mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_80003es2lan; + /* link info */ + mac->ops.get_link_up_info = e1000_get_link_up_info_80003es2lan; + +out: + return ret_val; +} + +/** + * e1000_init_function_pointers_80003es2lan - Init ESB2 func ptrs. + * @hw: pointer to the HW structure + * + * The only function explicitly called by the api module to initialize + * all function pointers and parameters. + **/ +void e1000_init_function_pointers_80003es2lan(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_init_function_pointers_80003es2lan"); + + e1000_init_mac_ops_generic(hw); + e1000_init_nvm_ops_generic(hw); + hw->mac.ops.init_params = e1000_init_mac_params_80003es2lan; + hw->nvm.ops.init_params = e1000_init_nvm_params_80003es2lan; + hw->phy.ops.init_params = e1000_init_phy_params_80003es2lan; +} + +/** + * e1000_acquire_phy_80003es2lan - Acquire rights to access PHY + * @hw: pointer to the HW structure + * + * A wrapper to acquire access rights to the correct PHY. This is a + * function pointer entry point called by the api module. + **/ +static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw) +{ + u16 mask; + + DEBUGFUNC("e1000_acquire_phy_80003es2lan"); + + mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; + mask |= E1000_SWFW_CSR_SM; + + return e1000_acquire_swfw_sync_80003es2lan(hw, mask); +} + +/** + * e1000_release_phy_80003es2lan - Release rights to access PHY + * @hw: pointer to the HW structure + * + * A wrapper to release access rights to the correct PHY. This is a + * function pointer entry point called by the api module. + **/ +static void e1000_release_phy_80003es2lan(struct e1000_hw *hw) +{ + u16 mask; + + DEBUGFUNC("e1000_release_phy_80003es2lan"); + + mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; + mask |= E1000_SWFW_CSR_SM; + + e1000_release_swfw_sync_80003es2lan(hw, mask); +} + +/** + * e1000_acquire_nvm_80003es2lan - Acquire rights to access NVM + * @hw: pointer to the HW structure + * + * Acquire the semaphore to access the EEPROM. This is a function + * pointer entry point called by the api module. + **/ +static s32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw) +{ + s32 ret_val; + + DEBUGFUNC("e1000_acquire_nvm_80003es2lan"); + + ret_val = e1000_acquire_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM); + if (ret_val) + goto out; + + ret_val = e1000_acquire_nvm_generic(hw); + + if (ret_val) + e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM); + +out: + return ret_val; +} + +/** + * e1000_release_nvm_80003es2lan - Relinquish rights to access NVM + * @hw: pointer to the HW structure + * + * Release the semaphore used to access the EEPROM. This is a + * function pointer entry point called by the api module. + **/ +static void e1000_release_nvm_80003es2lan(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_release_nvm_80003es2lan"); + + e1000_release_nvm_generic(hw); + e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM); +} + +/** + * e1000_acquire_swfw_sync_80003es2lan - Acquire SW/FW semaphore + * @hw: pointer to the HW structure + * @mask: specifies which semaphore to acquire + * + * Acquire the SW/FW semaphore to access the PHY or NVM. The mask + * will also specify which port we're acquiring the lock for. + **/ +static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask) +{ + u32 swfw_sync; + u32 swmask = mask; + u32 fwmask = mask << 16; + s32 ret_val = E1000_SUCCESS; + s32 i = 0, timeout = 200; + + DEBUGFUNC("e1000_acquire_swfw_sync_80003es2lan"); + + while (i < timeout) { + if (e1000_get_hw_semaphore_generic(hw)) { + ret_val = -E1000_ERR_SWFW_SYNC; + goto out; + } + + swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC); + if (!(swfw_sync & (fwmask | swmask))) + break; + + /* + * Firmware currently using resource (fwmask) + * or other software thread using resource (swmask) + */ + e1000_put_hw_semaphore_generic(hw); + msec_delay_irq(5); + i++; + } + + if (i == timeout) { + DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n"); + ret_val = -E1000_ERR_SWFW_SYNC; + goto out; + } + + swfw_sync |= swmask; + E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync); + + e1000_put_hw_semaphore_generic(hw); + +out: + return ret_val; +} + +/** + * e1000_release_swfw_sync_80003es2lan - Release SW/FW semaphore + * @hw: pointer to the HW structure + * @mask: specifies which semaphore to acquire + * + * Release the SW/FW semaphore used to access the PHY or NVM. The mask + * will also specify which port we're releasing the lock for. + **/ +static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask) +{ + u32 swfw_sync; + + DEBUGFUNC("e1000_release_swfw_sync_80003es2lan"); + + while (e1000_get_hw_semaphore_generic(hw) != E1000_SUCCESS); + /* Empty */ + + swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC); + swfw_sync &= ~mask; + E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync); + + e1000_put_hw_semaphore_generic(hw); +} + +/** + * e1000_read_phy_reg_gg82563_80003es2lan - Read GG82563 PHY register + * @hw: pointer to the HW structure + * @offset: offset of the register to read + * @data: pointer to the data returned from the operation + * + * Read the GG82563 PHY register. This is a function pointer entry + * point called by the api module. + **/ +static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, + u32 offset, u16 *data) +{ + s32 ret_val; + u32 page_select; + u16 temp; + + DEBUGFUNC("e1000_read_phy_reg_gg82563_80003es2lan"); + + ret_val = e1000_acquire_phy_80003es2lan(hw); + if (ret_val) + goto out; + + /* Select Configuration Page */ + if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) { + page_select = GG82563_PHY_PAGE_SELECT; + } else { + /* + * Use Alternative Page Select register to access + * registers 30 and 31 + */ + page_select = GG82563_PHY_PAGE_SELECT_ALT; + } + + temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT); + ret_val = e1000_write_phy_reg_mdic(hw, page_select, temp); + if (ret_val) { + e1000_release_phy_80003es2lan(hw); + goto out; + } + + /* + * The "ready" bit in the MDIC register may be incorrectly set + * before the device has completed the "Page Select" MDI + * transaction. So we wait 200us after each MDI command... + */ + usec_delay(200); + + /* ...and verify the command was successful. */ + ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp); + + if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { + ret_val = -E1000_ERR_PHY; + e1000_release_phy_80003es2lan(hw); + goto out; + } + + usec_delay(200); + + ret_val = e1000_read_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + usec_delay(200); + e1000_release_phy_80003es2lan(hw); + +out: + return ret_val; +} + +/** + * e1000_write_phy_reg_gg82563_80003es2lan - Write GG82563 PHY register + * @hw: pointer to the HW structure + * @offset: offset of the register to read + * @data: value to write to the register + * + * Write to the GG82563 PHY register. This is a function pointer entry + * point called by the api module. + **/ +static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, + u32 offset, u16 data) +{ + s32 ret_val; + u32 page_select; + u16 temp; + + DEBUGFUNC("e1000_write_phy_reg_gg82563_80003es2lan"); + + ret_val = e1000_acquire_phy_80003es2lan(hw); + if (ret_val) + goto out; + + /* Select Configuration Page */ + if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) { + page_select = GG82563_PHY_PAGE_SELECT; + } else { + /* + * Use Alternative Page Select register to access + * registers 30 and 31 + */ + page_select = GG82563_PHY_PAGE_SELECT_ALT; + } + + temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT); + ret_val = e1000_write_phy_reg_mdic(hw, page_select, temp); + if (ret_val) { + e1000_release_phy_80003es2lan(hw); + goto out; + } + + + /* + * The "ready" bit in the MDIC register may be incorrectly set + * before the device has completed the "Page Select" MDI + * transaction. So we wait 200us after each MDI command... + */ + usec_delay(200); + + /* ...and verify the command was successful. */ + ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp); + + if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { + ret_val = -E1000_ERR_PHY; + e1000_release_phy_80003es2lan(hw); + goto out; + } + + usec_delay(200); + + ret_val = e1000_write_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + usec_delay(200); + e1000_release_phy_80003es2lan(hw); + +out: + return ret_val; +} + +/** + * e1000_write_nvm_80003es2lan - Write to ESB2 NVM + * @hw: pointer to the HW structure + * @offset: offset of the register to read + * @words: number of words to write + * @data: buffer of data to write to the NVM + * + * Write "words" of data to the ESB2 NVM. This is a function + * pointer entry point called by the api module. + **/ +static s32 e1000_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data) +{ + DEBUGFUNC("e1000_write_nvm_80003es2lan"); + + return e1000_write_nvm_spi(hw, offset, words, data); +} + +/** + * e1000_get_cfg_done_80003es2lan - Wait for configuration to complete + * @hw: pointer to the HW structure + * + * Wait a specific amount of time for manageability processes to complete. + * This is a function pointer entry point called by the phy module. + **/ +static s32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw) +{ + s32 timeout = PHY_CFG_TIMEOUT; + s32 ret_val = E1000_SUCCESS; + u32 mask = E1000_NVM_CFG_DONE_PORT_0; + + DEBUGFUNC("e1000_get_cfg_done_80003es2lan"); + + if (hw->bus.func == 1) + mask = E1000_NVM_CFG_DONE_PORT_1; + + while (timeout) { + if (E1000_READ_REG(hw, E1000_EEMNGCTL) & mask) + break; + msec_delay(1); + timeout--; + } + if (!timeout) { + DEBUGOUT("MNG configuration cycle has not completed.\n"); + ret_val = -E1000_ERR_RESET; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_phy_force_speed_duplex_80003es2lan - Force PHY speed and duplex + * @hw: pointer to the HW structure + * + * Force the speed and duplex settings onto the PHY. This is a + * function pointer entry point called by the phy module. + **/ +static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 phy_data; + bool link; + + DEBUGFUNC("e1000_phy_force_speed_duplex_80003es2lan"); + + if (!(hw->phy.ops.read_reg)) + goto out; + + /* + * Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI + * forced whenever speed and duplex are forced. + */ + ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + goto out; + + phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_AUTO; + ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL, phy_data); + if (ret_val) + goto out; + + DEBUGOUT1("GG82563 PSCR: %X\n", phy_data); + + ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_data); + if (ret_val) + goto out; + + e1000_phy_force_speed_duplex_setup(hw, &phy_data); + + /* Reset the phy to commit changes. */ + phy_data |= MII_CR_RESET; + + ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_data); + if (ret_val) + goto out; + + usec_delay(1); + + if (hw->phy.autoneg_wait_to_complete) { + DEBUGOUT("Waiting for forced speed/duplex link " + "on GG82563 phy.\n"); + + ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT, + 100000, &link); + if (ret_val) + goto out; + + if (!link) { + /* + * We didn't get link. + * Reset the DSP and cross our fingers. + */ + ret_val = e1000_phy_reset_dsp_generic(hw); + if (ret_val) + goto out; + } + + /* Try once more */ + ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT, + 100000, &link); + if (ret_val) + goto out; + } + + ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, &phy_data); + if (ret_val) + goto out; + + /* + * Resetting the phy means we need to verify the TX_CLK corresponds + * to the link speed. 10Mbps -> 2.5MHz, else 25MHz. + */ + phy_data &= ~GG82563_MSCR_TX_CLK_MASK; + if (hw->mac.forced_speed_duplex & E1000_ALL_10_SPEED) + phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5; + else + phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25; + + /* + * In addition, we must re-enable CRS on Tx for both half and full + * duplex. + */ + phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX; + ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, phy_data); + +out: + return ret_val; +} + +/** + * e1000_get_cable_length_80003es2lan - Set approximate cable length + * @hw: pointer to the HW structure + * + * Find the approximate cable length as measured by the GG82563 PHY. + * This is a function pointer entry point called by the phy module. + **/ +static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = E1000_SUCCESS; + u16 phy_data, index; + + DEBUGFUNC("e1000_get_cable_length_80003es2lan"); + + if (!(hw->phy.ops.read_reg)) + goto out; + + ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_DSP_DISTANCE, &phy_data); + if (ret_val) + goto out; + + index = phy_data & GG82563_DSPD_CABLE_LENGTH; + phy->min_cable_length = e1000_gg82563_cable_length_table[index]; + phy->max_cable_length = e1000_gg82563_cable_length_table[index+5]; + + phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; + +out: + return ret_val; +} + +/** + * e1000_get_link_up_info_80003es2lan - Report speed and duplex + * @hw: pointer to the HW structure + * @speed: pointer to speed buffer + * @duplex: pointer to duplex buffer + * + * Retrieve the current speed and duplex configuration. + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed, + u16 *duplex) +{ + s32 ret_val; + + DEBUGFUNC("e1000_get_link_up_info_80003es2lan"); + + if (hw->phy.media_type == e1000_media_type_copper) { + ret_val = e1000_get_speed_and_duplex_copper_generic(hw, + speed, + duplex); + if (ret_val) + goto out; + if (*speed == SPEED_1000) + ret_val = e1000_cfg_kmrn_1000_80003es2lan(hw); + else + ret_val = e1000_cfg_kmrn_10_100_80003es2lan(hw, + *duplex); + } else { + ret_val = e1000_get_speed_and_duplex_fiber_serdes_generic(hw, + speed, + duplex); + } + +out: + return ret_val; +} + +/** + * e1000_reset_hw_80003es2lan - Reset the ESB2 controller + * @hw: pointer to the HW structure + * + * Perform a global reset to the ESB2 controller. + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw) +{ + u32 ctrl, icr; + s32 ret_val; + + DEBUGFUNC("e1000_reset_hw_80003es2lan"); + + /* + * Prevent the PCI-E bus from sticking if there is no TLP connection + * on the last TLP read/write transaction when MAC is reset. + */ + ret_val = e1000_disable_pcie_master_generic(hw); + if (ret_val) { + DEBUGOUT("PCI-E Master disable polling has failed.\n"); + } + + DEBUGOUT("Masking off all interrupts\n"); + E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); + + E1000_WRITE_REG(hw, E1000_RCTL, 0); + E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP); + E1000_WRITE_FLUSH(hw); + + msec_delay(10); + + ctrl = E1000_READ_REG(hw, E1000_CTRL); + + DEBUGOUT("Issuing a global reset to MAC\n"); + E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST); + + ret_val = e1000_get_auto_rd_done_generic(hw); + if (ret_val) + /* We don't want to continue accessing MAC registers. */ + goto out; + + /* Clear any pending interrupt events. */ + E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); + icr = E1000_READ_REG(hw, E1000_ICR); + + e1000_check_alt_mac_addr_generic(hw); + +out: + return ret_val; +} + +/** + * e1000_init_hw_80003es2lan - Initialize the ESB2 controller + * @hw: pointer to the HW structure + * + * Initialize the hw bits, LED, VFTA, MTA, link and hw counters. + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 reg_data; + s32 ret_val; + u16 i; + + DEBUGFUNC("e1000_init_hw_80003es2lan"); + + e1000_initialize_hw_bits_80003es2lan(hw); + + /* Initialize identification LED */ + ret_val = e1000_id_led_init_generic(hw); + if (ret_val) { + DEBUGOUT("Error initializing identification LED\n"); + /* This is not fatal and we should not stop init due to this */ + } + + /* Disabling VLAN filtering */ + DEBUGOUT("Initializing the IEEE VLAN\n"); + mac->ops.clear_vfta(hw); + + /* Setup the receive address. */ + e1000_init_rx_addrs_generic(hw, mac->rar_entry_count); + + /* Zero out the Multicast HASH table */ + DEBUGOUT("Zeroing the MTA\n"); + for (i = 0; i < mac->mta_reg_count; i++) + E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); + + /* Setup link and flow control */ + ret_val = mac->ops.setup_link(hw); + + /* Set the transmit descriptor write-back policy */ + reg_data = E1000_READ_REG(hw, E1000_TXDCTL(0)); + reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC; + E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg_data); + + /* ...for both queues. */ + reg_data = E1000_READ_REG(hw, E1000_TXDCTL(1)); + reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC; + E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg_data); + + /* Enable retransmit on late collisions */ + reg_data = E1000_READ_REG(hw, E1000_TCTL); + reg_data |= E1000_TCTL_RTLC; + E1000_WRITE_REG(hw, E1000_TCTL, reg_data); + + /* Configure Gigabit Carry Extend Padding */ + reg_data = E1000_READ_REG(hw, E1000_TCTL_EXT); + reg_data &= ~E1000_TCTL_EXT_GCEX_MASK; + reg_data |= DEFAULT_TCTL_EXT_GCEX_80003ES2LAN; + E1000_WRITE_REG(hw, E1000_TCTL_EXT, reg_data); + + /* Configure Transmit Inter-Packet Gap */ + reg_data = E1000_READ_REG(hw, E1000_TIPG); + reg_data &= ~E1000_TIPG_IPGT_MASK; + reg_data |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN; + E1000_WRITE_REG(hw, E1000_TIPG, reg_data); + + reg_data = E1000_READ_REG_ARRAY(hw, E1000_FFLT, 0x0001); + reg_data &= ~0x00100000; + E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data); + + /* + * Clear all of the statistics registers (clear on read). It is + * important that we do this after we have tried to establish link + * because the symbol error count will increment wildly if there + * is no link. + */ + e1000_clear_hw_cntrs_80003es2lan(hw); + + return ret_val; +} + +/** + * e1000_initialize_hw_bits_80003es2lan - Init hw bits of ESB2 + * @hw: pointer to the HW structure + * + * Initializes required hardware-dependent bits needed for normal operation. + **/ +static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw) +{ + u32 reg; + + DEBUGFUNC("e1000_initialize_hw_bits_80003es2lan"); + + if (hw->mac.disable_hw_init_bits) + goto out; + + /* Transmit Descriptor Control 0 */ + reg = E1000_READ_REG(hw, E1000_TXDCTL(0)); + reg |= (1 << 22); + E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg); + + /* Transmit Descriptor Control 1 */ + reg = E1000_READ_REG(hw, E1000_TXDCTL(1)); + reg |= (1 << 22); + E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg); + + /* Transmit Arbitration Control 0 */ + reg = E1000_READ_REG(hw, E1000_TARC(0)); + reg &= ~(0xF << 27); /* 30:27 */ + if (hw->phy.media_type != e1000_media_type_copper) + reg &= ~(1 << 20); + E1000_WRITE_REG(hw, E1000_TARC(0), reg); + + /* Transmit Arbitration Control 1 */ + reg = E1000_READ_REG(hw, E1000_TARC(1)); + if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR) + reg &= ~(1 << 28); + else + reg |= (1 << 28); + E1000_WRITE_REG(hw, E1000_TARC(1), reg); + +out: + return; +} + +/** + * e1000_copper_link_setup_gg82563_80003es2lan - Configure GG82563 Link + * @hw: pointer to the HW structure + * + * Setup some GG82563 PHY registers for obtaining link + **/ +static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u32 ctrl_ext; + u32 i = 0; + u16 data, data2; + + DEBUGFUNC("e1000_copper_link_setup_gg82563_80003es2lan"); + + if (!phy->reset_disable) { + ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, + &data); + if (ret_val) + goto out; + + data |= GG82563_MSCR_ASSERT_CRS_ON_TX; + /* Use 25MHz for both link down and 1000Base-T for Tx clock. */ + data |= GG82563_MSCR_TX_CLK_1000MBPS_25; + + ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, + data); + if (ret_val) + goto out; + + /* + * Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds + * 1 - MDI mode + * 2 - MDI-X mode + * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) + */ + ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_SPEC_CTRL, &data); + if (ret_val) + goto out; + + data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK; + + switch (phy->mdix) { + case 1: + data |= GG82563_PSCR_CROSSOVER_MODE_MDI; + break; + case 2: + data |= GG82563_PSCR_CROSSOVER_MODE_MDIX; + break; + case 0: + default: + data |= GG82563_PSCR_CROSSOVER_MODE_AUTO; + break; + } + + /* + * Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled + */ + data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE; + if (phy->disable_polarity_correction) + data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE; + + ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL, data); + if (ret_val) + goto out; + + /* SW Reset the PHY so all changes take effect */ + ret_val = hw->phy.ops.commit(hw); + if (ret_val) { + DEBUGOUT("Error Resetting the PHY\n"); + goto out; + } + + } + + /* Bypass Rx and Tx FIFO's */ + ret_val = e1000_write_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL, + E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS | + E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS); + if (ret_val) + goto out; + + ret_val = e1000_read_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE, + &data); + if (ret_val) + goto out; + data |= E1000_KMRNCTRLSTA_OPMODE_E_IDLE; + ret_val = e1000_write_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE, + data); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_SPEC_CTRL_2, &data); + if (ret_val) + goto out; + + data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG; + ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL_2, data); + if (ret_val) + goto out; + + ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); + ctrl_ext &= ~(E1000_CTRL_EXT_LINK_MODE_MASK); + E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); + + ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_PWR_MGMT_CTRL, &data); + if (ret_val) + goto out; + + /* + * Do not init these registers when the HW is in IAMT mode, since the + * firmware will have already initialized them. We only initialize + * them if the HW is not in IAMT mode. + */ + if (!(hw->mac.ops.check_mng_mode(hw))) { + /* Enable Electrical Idle on the PHY */ + data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE; + ret_val = hw->phy.ops.write_reg(hw, + GG82563_PHY_PWR_MGMT_CTRL, + data); + if (ret_val) + goto out; + + do { + ret_val = hw->phy.ops.read_reg(hw, + GG82563_PHY_KMRN_MODE_CTRL, + &data); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.read_reg(hw, + GG82563_PHY_KMRN_MODE_CTRL, + &data2); + if (ret_val) + goto out; + i++; + } while ((data != data2) && (i < GG82563_MAX_KMRN_RETRY)); + + data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; + ret_val = hw->phy.ops.write_reg(hw, + GG82563_PHY_KMRN_MODE_CTRL, + data); + + if (ret_val) + goto out; + } + + /* + * Workaround: Disable padding in Kumeran interface in the MAC + * and in the PHY to avoid CRC errors. + */ + ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_INBAND_CTRL, &data); + if (ret_val) + goto out; + + data |= GG82563_ICR_DIS_PADDING; + ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_INBAND_CTRL, data); + if (ret_val) + goto out; + +out: + return ret_val; +} + +/** + * e1000_setup_copper_link_80003es2lan - Setup Copper Link for ESB2 + * @hw: pointer to the HW structure + * + * Essentially a wrapper for setting up all things "copper" related. + * This is a function pointer entry point called by the mac module. + **/ +static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw) +{ + u32 ctrl; + s32 ret_val; + u16 reg_data; + + DEBUGFUNC("e1000_setup_copper_link_80003es2lan"); + + ctrl = E1000_READ_REG(hw, E1000_CTRL); + ctrl |= E1000_CTRL_SLU; + ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + E1000_WRITE_REG(hw, E1000_CTRL, ctrl); + + /* + * Set the mac to wait the maximum time between each + * iteration and increase the max iterations when + * polling the phy; this fixes erroneous timeouts at 10Mbps. + */ + ret_val = e1000_write_kmrn_reg_generic(hw, GG82563_REG(0x34, 4), + 0xFFFF); + if (ret_val) + goto out; + ret_val = e1000_read_kmrn_reg_generic(hw, GG82563_REG(0x34, 9), + ®_data); + if (ret_val) + goto out; + reg_data |= 0x3F; + ret_val = e1000_write_kmrn_reg_generic(hw, GG82563_REG(0x34, 9), + reg_data); + if (ret_val) + goto out; + ret_val = e1000_read_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_OFFSET_INB_CTRL, + ®_data); + if (ret_val) + goto out; + reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING; + ret_val = e1000_write_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_OFFSET_INB_CTRL, + reg_data); + if (ret_val) + goto out; + + ret_val = e1000_copper_link_setup_gg82563_80003es2lan(hw); + if (ret_val) + goto out; + + ret_val = e1000_setup_copper_link_generic(hw); + +out: + return ret_val; +} + +/** + * e1000_cfg_kmrn_10_100_80003es2lan - Apply "quirks" for 10/100 operation + * @hw: pointer to the HW structure + * @duplex: current duplex setting + * + * Configure the KMRN interface by applying last minute quirks for + * 10/100 operation. + **/ +static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex) +{ + s32 ret_val = E1000_SUCCESS; + u32 tipg; + u32 i = 0; + u16 reg_data, reg_data2; + + DEBUGFUNC("e1000_configure_kmrn_for_10_100"); + + reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT; + ret_val = e1000_write_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, + reg_data); + if (ret_val) + goto out; + + /* Configure Transmit Inter-Packet Gap */ + tipg = E1000_READ_REG(hw, E1000_TIPG); + tipg &= ~E1000_TIPG_IPGT_MASK; + tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN; + E1000_WRITE_REG(hw, E1000_TIPG, tipg); + + + do { + ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, + ®_data); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, + ®_data2); + if (ret_val) + goto out; + i++; + } while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY)); + + if (duplex == HALF_DUPLEX) + reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER; + else + reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; + + ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data); + +out: + return ret_val; +} + +/** + * e1000_cfg_kmrn_1000_80003es2lan - Apply "quirks" for gigabit operation + * @hw: pointer to the HW structure + * + * Configure the KMRN interface by applying last minute quirks for + * gigabit operation. + **/ +static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 reg_data, reg_data2; + u32 tipg; + u32 i = 0; + + DEBUGFUNC("e1000_configure_kmrn_for_1000"); + + reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT; + ret_val = e1000_write_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, + reg_data); + if (ret_val) + goto out; + + /* Configure Transmit Inter-Packet Gap */ + tipg = E1000_READ_REG(hw, E1000_TIPG); + tipg &= ~E1000_TIPG_IPGT_MASK; + tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN; + E1000_WRITE_REG(hw, E1000_TIPG, tipg); + + + do { + ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, + ®_data); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, + ®_data2); + if (ret_val) + goto out; + i++; + } while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY)); + + reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; + ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data); + +out: + return ret_val; +} + +/** + * e1000_read_mac_addr_80003es2lan - Read device MAC address + * @hw: pointer to the HW structure + **/ +static s32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_read_mac_addr_80003es2lan"); + if (e1000_check_alt_mac_addr_generic(hw)) + ret_val = e1000_read_mac_addr_generic(hw); + + return ret_val; +} + +/** + * e1000_power_down_phy_copper_80003es2lan - Remove link during PHY power down + * @hw: pointer to the HW structure + * + * In the case of a PHY power down to save power, or to turn off link during a + * driver unload, or wake on lan is not enabled, remove the link. + **/ +static void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw) +{ + /* If the management interface is not enabled, then power down */ + if (!(hw->mac.ops.check_mng_mode(hw) || + hw->phy.ops.check_reset_block(hw))) + e1000_power_down_phy_copper(hw); + + return; +} + +/** + * e1000_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters + * @hw: pointer to the HW structure + * + * Clears the hardware counters by reading the counter registers. + **/ +static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw) +{ + volatile u32 temp; + + DEBUGFUNC("e1000_clear_hw_cntrs_80003es2lan"); + + e1000_clear_hw_cntrs_base_generic(hw); + + temp = E1000_READ_REG(hw, E1000_PRC64); + temp = E1000_READ_REG(hw, E1000_PRC127); + temp = E1000_READ_REG(hw, E1000_PRC255); + temp = E1000_READ_REG(hw, E1000_PRC511); + temp = E1000_READ_REG(hw, E1000_PRC1023); + temp = E1000_READ_REG(hw, E1000_PRC1522); + temp = E1000_READ_REG(hw, E1000_PTC64); + temp = E1000_READ_REG(hw, E1000_PTC127); + temp = E1000_READ_REG(hw, E1000_PTC255); + temp = E1000_READ_REG(hw, E1000_PTC511); + temp = E1000_READ_REG(hw, E1000_PTC1023); + temp = E1000_READ_REG(hw, E1000_PTC1522); + + temp = E1000_READ_REG(hw, E1000_ALGNERRC); + temp = E1000_READ_REG(hw, E1000_RXERRC); + temp = E1000_READ_REG(hw, E1000_TNCRS); + temp = E1000_READ_REG(hw, E1000_CEXTERR); + temp = E1000_READ_REG(hw, E1000_TSCTC); + temp = E1000_READ_REG(hw, E1000_TSCTFC); + + temp = E1000_READ_REG(hw, E1000_MGTPRC); + temp = E1000_READ_REG(hw, E1000_MGTPDC); + temp = E1000_READ_REG(hw, E1000_MGTPTC); + + temp = E1000_READ_REG(hw, E1000_IAC); + temp = E1000_READ_REG(hw, E1000_ICRXOC); + + temp = E1000_READ_REG(hw, E1000_ICRXPTC); + temp = E1000_READ_REG(hw, E1000_ICRXATC); + temp = E1000_READ_REG(hw, E1000_ICTXPTC); + temp = E1000_READ_REG(hw, E1000_ICTXATC); + temp = E1000_READ_REG(hw, E1000_ICTXQEC); + temp = E1000_READ_REG(hw, E1000_ICTXQMTC); + temp = E1000_READ_REG(hw, E1000_ICRXDMTC); +} --- linux-2.6.27.orig/ubuntu/e1000e/Makefile +++ linux-2.6.27/ubuntu/e1000e/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_E1000E_NEW) += e1000e.o + +e1000e-objs := netdev.o ethtool.o param.o e1000_82571.o e1000_ich8lan.o \ + e1000_80003es2lan.o e1000_mac.o e1000_nvm.o e1000_phy.o e1000_manage.o \ + kcompat.o --- linux-2.6.27.orig/ubuntu/e1000e/e1000_hw.h +++ linux-2.6.27/ubuntu/e1000e/e1000_hw.h @@ -0,0 +1,674 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_HW_H_ +#define _E1000_HW_H_ + +#include "e1000_osdep.h" +#include "e1000_regs.h" +#include "e1000_defines.h" + +struct e1000_hw; + +#define E1000_DEV_ID_82571EB_COPPER 0x105E +#define E1000_DEV_ID_82571EB_FIBER 0x105F +#define E1000_DEV_ID_82571EB_SERDES 0x1060 +#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9 +#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA +#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4 +#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5 +#define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5 +#define E1000_DEV_ID_82571EB_QUAD_COPPER_LP 0x10BC +#define E1000_DEV_ID_82572EI_COPPER 0x107D +#define E1000_DEV_ID_82572EI_FIBER 0x107E +#define E1000_DEV_ID_82572EI_SERDES 0x107F +#define E1000_DEV_ID_82572EI 0x10B9 +#define E1000_DEV_ID_82573E 0x108B +#define E1000_DEV_ID_82573E_IAMT 0x108C +#define E1000_DEV_ID_82573L 0x109A +#define E1000_DEV_ID_82574L 0x10D3 +#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096 +#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098 +#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA +#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB +#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049 +#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A +#define E1000_DEV_ID_ICH8_IGP_C 0x104B +#define E1000_DEV_ID_ICH8_IFE 0x104C +#define E1000_DEV_ID_ICH8_IFE_GT 0x10C4 +#define E1000_DEV_ID_ICH8_IFE_G 0x10C5 +#define E1000_DEV_ID_ICH8_IGP_M 0x104D +#define E1000_DEV_ID_ICH9_IGP_M 0x10BF +#define E1000_DEV_ID_ICH9_IGP_M_AMT 0x10F5 +#define E1000_DEV_ID_ICH9_IGP_M_V 0x10CB +#define E1000_DEV_ID_ICH9_IGP_AMT 0x10BD +#define E1000_DEV_ID_ICH9_BM 0x10E5 +#define E1000_DEV_ID_ICH9_IGP_C 0x294C +#define E1000_DEV_ID_ICH9_IFE 0x10C0 +#define E1000_DEV_ID_ICH9_IFE_GT 0x10C3 +#define E1000_DEV_ID_ICH9_IFE_G 0x10C2 +#define E1000_DEV_ID_ICH10_R_BM_LM 0x10CC +#define E1000_DEV_ID_ICH10_R_BM_LF 0x10CD +#define E1000_DEV_ID_ICH10_R_BM_V 0x10CE +#define E1000_DEV_ID_ICH10_D_BM_LM 0x10DE +#define E1000_DEV_ID_ICH10_D_BM_LF 0x10DF + +#define E1000_REVISION_0 0 +#define E1000_REVISION_1 1 +#define E1000_REVISION_2 2 +#define E1000_REVISION_3 3 +#define E1000_REVISION_4 4 + +#define E1000_FUNC_0 0 +#define E1000_FUNC_1 1 + +typedef enum { + e1000_undefined = 0, + e1000_82571, + e1000_82572, + e1000_82573, + e1000_82574, + e1000_80003es2lan, + e1000_ich8lan, + e1000_ich9lan, + e1000_ich10lan, + e1000_num_macs /* List is 1-based, so subtract 1 for true count. */ +} e1000_mac_type; + +typedef enum { + e1000_media_type_unknown = 0, + e1000_media_type_copper = 1, + e1000_media_type_fiber = 2, + e1000_media_type_internal_serdes = 3, + e1000_num_media_types +} e1000_media_type; + +typedef enum { + e1000_nvm_unknown = 0, + e1000_nvm_none, + e1000_nvm_eeprom_spi, + e1000_nvm_eeprom_microwire, + e1000_nvm_flash_hw, + e1000_nvm_flash_sw +} e1000_nvm_type; + +typedef enum { + e1000_nvm_override_none = 0, + e1000_nvm_override_spi_small, + e1000_nvm_override_spi_large, + e1000_nvm_override_microwire_small, + e1000_nvm_override_microwire_large +} e1000_nvm_override; + +typedef enum { + e1000_phy_unknown = 0, + e1000_phy_none, + e1000_phy_m88, + e1000_phy_igp, + e1000_phy_igp_2, + e1000_phy_gg82563, + e1000_phy_igp_3, + e1000_phy_ife, + e1000_phy_bm, +} e1000_phy_type; + +typedef enum { + e1000_bus_type_unknown = 0, + e1000_bus_type_pci, + e1000_bus_type_pcix, + e1000_bus_type_pci_express, + e1000_bus_type_reserved +} e1000_bus_type; + +typedef enum { + e1000_bus_speed_unknown = 0, + e1000_bus_speed_33, + e1000_bus_speed_66, + e1000_bus_speed_100, + e1000_bus_speed_120, + e1000_bus_speed_133, + e1000_bus_speed_2500, + e1000_bus_speed_5000, + e1000_bus_speed_reserved +} e1000_bus_speed; + +typedef enum { + e1000_bus_width_unknown = 0, + e1000_bus_width_pcie_x1, + e1000_bus_width_pcie_x2, + e1000_bus_width_pcie_x4 = 4, + e1000_bus_width_pcie_x8 = 8, + e1000_bus_width_32, + e1000_bus_width_64, + e1000_bus_width_reserved +} e1000_bus_width; + +typedef enum { + e1000_1000t_rx_status_not_ok = 0, + e1000_1000t_rx_status_ok, + e1000_1000t_rx_status_undefined = 0xFF +} e1000_1000t_rx_status; + +typedef enum { + e1000_rev_polarity_normal = 0, + e1000_rev_polarity_reversed, + e1000_rev_polarity_undefined = 0xFF +} e1000_rev_polarity; + +typedef enum { + e1000_fc_none = 0, + e1000_fc_rx_pause, + e1000_fc_tx_pause, + e1000_fc_full, + e1000_fc_default = 0xFF +} e1000_fc_type; + + +/* Receive Descriptor */ +struct e1000_rx_desc { + u64 buffer_addr; /* Address of the descriptor's data buffer */ + u16 length; /* Length of data DMAed into data buffer */ + u16 csum; /* Packet checksum */ + u8 status; /* Descriptor status */ + u8 errors; /* Descriptor Errors */ + u16 special; +}; + +/* Receive Descriptor - Extended */ +union e1000_rx_desc_extended { + struct { + u64 buffer_addr; + u64 reserved; + } read; + struct { + struct { + u32 mrq; /* Multiple Rx Queues */ + union { + u32 rss; /* RSS Hash */ + struct { + u16 ip_id; /* IP id */ + u16 csum; /* Packet Checksum */ + } csum_ip; + } hi_dword; + } lower; + struct { + u32 status_error; /* ext status/error */ + u16 length; + u16 vlan; /* VLAN tag */ + } upper; + } wb; /* writeback */ +}; + +#define MAX_PS_BUFFERS 4 +/* Receive Descriptor - Packet Split */ +union e1000_rx_desc_packet_split { + struct { + /* one buffer for protocol header(s), three data buffers */ + u64 buffer_addr[MAX_PS_BUFFERS]; + } read; + struct { + struct { + u32 mrq; /* Multiple Rx Queues */ + union { + u32 rss; /* RSS Hash */ + struct { + u16 ip_id; /* IP id */ + u16 csum; /* Packet Checksum */ + } csum_ip; + } hi_dword; + } lower; + struct { + u32 status_error; /* ext status/error */ + u16 length0; /* length of buffer 0 */ + u16 vlan; /* VLAN tag */ + } middle; + struct { + u16 header_status; + u16 length[3]; /* length of buffers 1-3 */ + } upper; + u64 reserved; + } wb; /* writeback */ +}; + +/* Transmit Descriptor */ +struct e1000_tx_desc { + u64 buffer_addr; /* Address of the descriptor's data buffer */ + union { + u32 data; + struct { + u16 length; /* Data buffer length */ + u8 cso; /* Checksum offset */ + u8 cmd; /* Descriptor control */ + } flags; + } lower; + union { + u32 data; + struct { + u8 status; /* Descriptor status */ + u8 css; /* Checksum start */ + u16 special; + } fields; + } upper; +}; + +/* Offload Context Descriptor */ +struct e1000_context_desc { + union { + u32 ip_config; + struct { + u8 ipcss; /* IP checksum start */ + u8 ipcso; /* IP checksum offset */ + u16 ipcse; /* IP checksum end */ + } ip_fields; + } lower_setup; + union { + u32 tcp_config; + struct { + u8 tucss; /* TCP checksum start */ + u8 tucso; /* TCP checksum offset */ + u16 tucse; /* TCP checksum end */ + } tcp_fields; + } upper_setup; + u32 cmd_and_length; + union { + u32 data; + struct { + u8 status; /* Descriptor status */ + u8 hdr_len; /* Header length */ + u16 mss; /* Maximum segment size */ + } fields; + } tcp_seg_setup; +}; + +/* Offload data descriptor */ +struct e1000_data_desc { + u64 buffer_addr; /* Address of the descriptor's buffer address */ + union { + u32 data; + struct { + u16 length; /* Data buffer length */ + u8 typ_len_ext; + u8 cmd; + } flags; + } lower; + union { + u32 data; + struct { + u8 status; /* Descriptor status */ + u8 popts; /* Packet Options */ + u16 special; + } fields; + } upper; +}; + +/* Statistics counters collected by the MAC */ +struct e1000_hw_stats { + u64 crcerrs; + u64 algnerrc; + u64 symerrs; + u64 rxerrc; + u64 mpc; + u64 scc; + u64 ecol; + u64 mcc; + u64 latecol; + u64 colc; + u64 dc; + u64 tncrs; + u64 sec; + u64 cexterr; + u64 rlec; + u64 xonrxc; + u64 xontxc; + u64 xoffrxc; + u64 xofftxc; + u64 fcruc; + u64 prc64; + u64 prc127; + u64 prc255; + u64 prc511; + u64 prc1023; + u64 prc1522; + u64 gprc; + u64 bprc; + u64 mprc; + u64 gptc; + u64 gorc; + u64 gotc; + u64 rnbc; + u64 ruc; + u64 rfc; + u64 roc; + u64 rjc; + u64 mgprc; + u64 mgpdc; + u64 mgptc; + u64 tor; + u64 tot; + u64 tpr; + u64 tpt; + u64 ptc64; + u64 ptc127; + u64 ptc255; + u64 ptc511; + u64 ptc1023; + u64 ptc1522; + u64 mptc; + u64 bptc; + u64 tsctc; + u64 tsctfc; + u64 iac; + u64 icrxptc; + u64 icrxatc; + u64 ictxptc; + u64 ictxatc; + u64 ictxqec; + u64 ictxqmtc; + u64 icrxdmtc; + u64 icrxoc; + u64 cbtmpc; + u64 htdpmc; + u64 cbrdpc; + u64 cbrmpc; + u64 rpthc; + u64 hgptc; + u64 htcbdpc; + u64 hgorc; + u64 hgotc; + u64 lenerrs; + u64 scvpc; + u64 hrmpc; +}; + +struct e1000_phy_stats { + u32 idle_errors; + u32 receive_errors; +}; + +struct e1000_host_mng_dhcp_cookie { + u32 signature; + u8 status; + u8 reserved0; + u16 vlan_id; + u32 reserved1; + u16 reserved2; + u8 reserved3; + u8 checksum; +}; + +/* Host Interface "Rev 1" */ +struct e1000_host_command_header { + u8 command_id; + u8 command_length; + u8 command_options; + u8 checksum; +}; + +#define E1000_HI_MAX_DATA_LENGTH 252 +struct e1000_host_command_info { + struct e1000_host_command_header command_header; + u8 command_data[E1000_HI_MAX_DATA_LENGTH]; +}; + +/* Host Interface "Rev 2" */ +struct e1000_host_mng_command_header { + u8 command_id; + u8 checksum; + u16 reserved1; + u16 reserved2; + u16 command_length; +}; + +#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8 +struct e1000_host_mng_command_info { + struct e1000_host_mng_command_header command_header; + u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH]; +}; + +#include "e1000_mac.h" +#include "e1000_phy.h" +#include "e1000_nvm.h" +#include "e1000_manage.h" + +struct e1000_mac_operations { + /* Function pointers for the MAC. */ + s32 (*init_params)(struct e1000_hw *); + s32 (*blink_led)(struct e1000_hw *); + s32 (*check_for_link)(struct e1000_hw *); + bool (*check_mng_mode)(struct e1000_hw *hw); + s32 (*cleanup_led)(struct e1000_hw *); + void (*clear_hw_cntrs)(struct e1000_hw *); + void (*clear_vfta)(struct e1000_hw *); + s32 (*get_bus_info)(struct e1000_hw *); + s32 (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *); + s32 (*led_on)(struct e1000_hw *); + s32 (*led_off)(struct e1000_hw *); + void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32, u32, + u32); + void (*remove_device)(struct e1000_hw *); + s32 (*reset_hw)(struct e1000_hw *); + s32 (*init_hw)(struct e1000_hw *); + s32 (*setup_link)(struct e1000_hw *); + s32 (*setup_physical_interface)(struct e1000_hw *); + s32 (*setup_led)(struct e1000_hw *); + void (*write_vfta)(struct e1000_hw *, u32, u32); + void (*mta_set)(struct e1000_hw *, u32); + void (*config_collision_dist)(struct e1000_hw*); + void (*rar_set)(struct e1000_hw*, u8*, u32); + s32 (*read_mac_addr)(struct e1000_hw*); + s32 (*validate_mdi_setting)(struct e1000_hw*); + s32 (*mng_host_if_write)(struct e1000_hw*, u8*, u16, u16, u8*); + s32 (*mng_write_cmd_header)(struct e1000_hw *hw, + struct e1000_host_mng_command_header*); + s32 (*mng_enable_host_if)(struct e1000_hw*); + s32 (*wait_autoneg)(struct e1000_hw*); +}; + +struct e1000_phy_operations { + s32 (*init_params)(struct e1000_hw *); + s32 (*acquire)(struct e1000_hw *); + s32 (*check_polarity)(struct e1000_hw *); + s32 (*check_reset_block)(struct e1000_hw *); + s32 (*commit)(struct e1000_hw *); + s32 (*force_speed_duplex)(struct e1000_hw *); + s32 (*get_cfg_done)(struct e1000_hw *hw); + s32 (*get_cable_length)(struct e1000_hw *); + s32 (*get_info)(struct e1000_hw *); + s32 (*read_reg)(struct e1000_hw *, u32, u16 *); + void (*release)(struct e1000_hw *); + s32 (*reset)(struct e1000_hw *); + s32 (*set_d0_lplu_state)(struct e1000_hw *, bool); + s32 (*set_d3_lplu_state)(struct e1000_hw *, bool); + s32 (*write_reg)(struct e1000_hw *, u32, u16); + void (*power_up)(struct e1000_hw *); + void (*power_down)(struct e1000_hw *); +}; + +struct e1000_nvm_operations { + s32 (*init_params)(struct e1000_hw *); + s32 (*acquire)(struct e1000_hw *); + s32 (*read)(struct e1000_hw *, u16, u16, u16 *); + void (*release)(struct e1000_hw *); + void (*reload)(struct e1000_hw *); + s32 (*update)(struct e1000_hw *); + s32 (*valid_led_default)(struct e1000_hw *, u16 *); + s32 (*validate)(struct e1000_hw *); + s32 (*write)(struct e1000_hw *, u16, u16, u16 *); +}; + +struct e1000_mac_info { + struct e1000_mac_operations ops; + u8 addr[6]; + u8 perm_addr[6]; + + e1000_mac_type type; + + u32 collision_delta; + u32 ledctl_default; + u32 ledctl_mode1; + u32 ledctl_mode2; + u32 mc_filter_type; + u32 tx_packet_delta; + u32 txcw; + + u16 current_ifs_val; + u16 ifs_max_val; + u16 ifs_min_val; + u16 ifs_ratio; + u16 ifs_step_size; + u16 mta_reg_count; + u16 rar_entry_count; + + u8 forced_speed_duplex; + + bool adaptive_ifs; + bool arc_subsystem_valid; + bool asf_firmware_present; + bool autoneg; + bool autoneg_failed; + bool disable_av; + bool disable_hw_init_bits; + bool get_link_status; + bool ifs_params_forced; + bool in_ifs_mode; + bool report_tx_early; + bool serdes_has_link; + bool tx_pkt_filtering; +}; + +struct e1000_phy_info { + struct e1000_phy_operations ops; + e1000_phy_type type; + + e1000_1000t_rx_status local_rx; + e1000_1000t_rx_status remote_rx; + e1000_ms_type ms_type; + e1000_ms_type original_ms_type; + e1000_rev_polarity cable_polarity; + e1000_smart_speed smart_speed; + + u32 addr; + u32 id; + u32 reset_delay_us; /* in usec */ + u32 revision; + + e1000_media_type media_type; + + u16 autoneg_advertised; + u16 autoneg_mask; + u16 cable_length; + u16 max_cable_length; + u16 min_cable_length; + + u8 mdix; + + bool disable_polarity_correction; + bool is_mdix; + bool polarity_correction; + bool reset_disable; + bool speed_downgraded; + bool autoneg_wait_to_complete; +}; + +struct e1000_nvm_info { + struct e1000_nvm_operations ops; + e1000_nvm_type type; + e1000_nvm_override override; + + u32 flash_bank_size; + u32 flash_base_addr; + u32 semaphore_delay; + + u16 word_size; + u16 delay_usec; + u16 address_bits; + u16 opcode_bits; + u16 page_size; +}; + +struct e1000_bus_info { + e1000_bus_type type; + e1000_bus_speed speed; + e1000_bus_width width; + + u32 snoop; + + u16 func; + u16 pci_cmd_word; +}; + +struct e1000_fc_info { + u32 high_water; /* Flow control high-water mark */ + u32 low_water; /* Flow control low-water mark */ + u16 pause_time; /* Flow control pause timer */ + bool send_xon; /* Flow control send XON */ + bool strict_ieee; /* Strict IEEE mode */ + e1000_fc_type type; /* Type of flow control */ + e1000_fc_type original_type; +}; + +struct e1000_hw { + void *back; + void *dev_spec; + + u8 __iomem *hw_addr; + u8 __iomem *flash_address; + unsigned long io_base; + + /* Protect access to NV RAM mapping */ + spinlock_t flash_address_map_lock; + u32 flash_address_map_cnt; + + struct e1000_mac_info mac; + struct e1000_fc_info fc; + struct e1000_phy_info phy; + struct e1000_nvm_info nvm; + struct e1000_bus_info bus; + struct e1000_host_mng_dhcp_cookie mng_cookie; + + u32 dev_spec_size; + + u16 device_id; + u16 subsystem_vendor_id; + u16 subsystem_device_id; + u16 vendor_id; + + u8 revision_id; +}; + +#include "e1000_82571.h" +#include "e1000_80003es2lan.h" +#include "e1000_ich8lan.h" + +/* These functions must be implemented by drivers */ +s32 e1000_alloc_zeroed_dev_spec_struct(struct e1000_hw *hw, u32 size); +s32 e1000_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value); +void e1000_free_dev_spec_struct(struct e1000_hw *hw); +void e1000_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value); + +#endif --- linux-2.6.27.orig/ubuntu/e1000e/e1000_82571.h +++ linux-2.6.27/ubuntu/e1000e/e1000_82571.h @@ -0,0 +1,53 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_82571_H_ +#define _E1000_82571_H_ + +#define ID_LED_RESERVED_F746 0xF746 +#define ID_LED_DEFAULT_82573 ((ID_LED_DEF1_DEF2 << 12) | \ + (ID_LED_OFF1_ON2 << 8) | \ + (ID_LED_DEF1_DEF2 << 4) | \ + (ID_LED_DEF1_DEF2)) + +#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000 + +/* Intr Throttling - RW */ +#define E1000_EITR_82574(_n) (0x000E8 + (0x4 * (_n))) + +#define E1000_EIAC_82574 0x000DC /* Ext. Interrupt Auto Clear - RW */ +#define E1000_EIAC_MASK_82574 0x01F00000 + +#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */ + +#define E1000_RXCFGL 0x0B634 /* TimeSync Rx EtherType & Msg Type Reg - RW */ + +bool e1000_get_laa_state_82571(struct e1000_hw *hw); +void e1000_set_laa_state_82571(struct e1000_hw *hw, bool state); + +#endif --- linux-2.6.27.orig/ubuntu/e1000e/e1000_regs.h +++ linux-2.6.27/ubuntu/e1000e/e1000_regs.h @@ -0,0 +1,310 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_REGS_H_ +#define _E1000_REGS_H_ + +#define E1000_CTRL 0x00000 /* Device Control - RW */ +#define E1000_CTRL_DUP 0x00004 /* Device Control Duplicate (Shadow) - RW */ +#define E1000_STATUS 0x00008 /* Device Status - RO */ +#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ +#define E1000_EERD 0x00014 /* EEPROM Read - RW */ +#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ +#define E1000_FLA 0x0001C /* Flash Access - RW */ +#define E1000_MDIC 0x00020 /* MDI Control - RW */ +#define E1000_SCTL 0x00024 /* SerDes Control - RW */ +#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ +#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ +#define E1000_FEXTNVM 0x00028 /* Future Extended NVM - RW */ +#define E1000_FCT 0x00030 /* Flow Control Type - RW */ +#define E1000_CONNSW 0x00034 /* Copper/Fiber switch control - RW */ +#define E1000_VET 0x00038 /* VLAN Ether Type - RW */ +#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */ +#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */ +#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */ +#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */ +#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ +#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ +#define E1000_IVAR 0x000E4 /* Interrupt Vector Allocation Register - RW */ +#define E1000_RCTL 0x00100 /* Rx Control - RW */ +#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ +#define E1000_TXCW 0x00178 /* Tx Configuration Word - RW */ +#define E1000_RXCW 0x00180 /* Rx Configuration Word - RO */ +#define E1000_EICR 0x01580 /* Ext. Interrupt Cause Read - R/clr */ +#define E1000_EITR(_n) (0x01680 + (0x4 * (_n))) +#define E1000_EICS 0x01520 /* Ext. Interrupt Cause Set - W0 */ +#define E1000_EIMS 0x01524 /* Ext. Interrupt Mask Set/Read - RW */ +#define E1000_EIMC 0x01528 /* Ext. Interrupt Mask Clear - WO */ +#define E1000_EIAC 0x0152C /* Ext. Interrupt Auto Clear - RW */ +#define E1000_EIAM 0x01530 /* Ext. Interrupt Ack Auto Clear Mask - RW */ +#define E1000_TCTL 0x00400 /* Tx Control - RW */ +#define E1000_TCTL_EXT 0x00404 /* Extended Tx Control - RW */ +#define E1000_TIPG 0x00410 /* Tx Inter-packet gap -RW */ +#define E1000_TBT 0x00448 /* Tx Burst Timer - RW */ +#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */ +#define E1000_LEDCTL 0x00E00 /* LED Control - RW */ +#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */ +#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */ +#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */ +#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */ +#define E1000_PBS 0x01008 /* Packet Buffer Size */ +#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */ +#define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */ +#define E1000_FLASHT 0x01028 /* FLASH Timer Register */ +#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */ +#define E1000_FLSWCTL 0x01030 /* FLASH control register */ +#define E1000_FLSWDATA 0x01034 /* FLASH data register */ +#define E1000_FLSWCNT 0x01038 /* FLASH Access Counter */ +#define E1000_FLOP 0x0103C /* FLASH Opcode Register */ +#define E1000_I2CCMD 0x01028 /* SFPI2C Command Register - RW */ +#define E1000_I2CPARAMS 0x0102C /* SFPI2C Parameters Register - RW */ +#define E1000_WDSTP 0x01040 /* Watchdog Setup - RW */ +#define E1000_SWDSTS 0x01044 /* SW Device Status - RW */ +#define E1000_FRTIMER 0x01048 /* Free Running Timer - RW */ +#define E1000_TCPTIMER 0x0104C /* TCP Timer - RW */ +#define E1000_ERT 0x02008 /* Early Rx Threshold - RW */ +#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */ +#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */ +#define E1000_PSRCTL 0x02170 /* Packet Split Receive Control - RW */ +#define E1000_RDFPCQ(_n) (0x02430 + (0x4 * (_n))) +#define E1000_PBRTH 0x02458 /* PB Rx Arbitration Threshold - RW */ +#define E1000_FCRTV 0x02460 /* Flow Control Refresh Timer Value - RW */ +/* Split and Replication Rx Control - RW */ +#define E1000_RDPUMB 0x025CC /* DMA Rx Descriptor uC Mailbox - RW */ +#define E1000_RDPUAD 0x025D0 /* DMA Rx Descriptor uC Addr Command - RW */ +#define E1000_RDPUWD 0x025D4 /* DMA Rx Descriptor uC Data Write - RW */ +#define E1000_RDPURD 0x025D8 /* DMA Rx Descriptor uC Data Read - RW */ +#define E1000_RDPUCTL 0x025DC /* DMA Rx Descriptor uC Control - RW */ +#define E1000_RDTR 0x02820 /* Rx Delay Timer - RW */ +#define E1000_RADV 0x0282C /* Rx Interrupt Absolute Delay Timer - RW */ +/* + * Convenience macros + * + * Note: "_n" is the queue number of the register to be written to. + * + * Example usage: + * E1000_RDBAL_REG(current_rx_queue) + */ +#define E1000_RDBAL(_n) ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : (0x0C000 + ((_n) * 0x40))) +#define E1000_RDBAH(_n) ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : (0x0C004 + ((_n) * 0x40))) +#define E1000_RDLEN(_n) ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : (0x0C008 + ((_n) * 0x40))) +#define E1000_SRRCTL(_n) ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : (0x0C00C + ((_n) * 0x40))) +#define E1000_RDH(_n) ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : (0x0C010 + ((_n) * 0x40))) +#define E1000_RDT(_n) ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : (0x0C018 + ((_n) * 0x40))) +#define E1000_RXDCTL(_n) ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : (0x0C028 + ((_n) * 0x40))) +#define E1000_TDBAL(_n) ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : (0x0E000 + ((_n) * 0x40))) +#define E1000_TDBAH(_n) ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : (0x0E004 + ((_n) * 0x40))) +#define E1000_TDLEN(_n) ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : (0x0E008 + ((_n) * 0x40))) +#define E1000_TDH(_n) ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : (0x0E010 + ((_n) * 0x40))) +#define E1000_TDT(_n) ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : (0x0E018 + ((_n) * 0x40))) +#define E1000_TXDCTL(_n) ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : (0x0E028 + ((_n) * 0x40))) +#define E1000_TARC(_n) (0x03840 + (_n << 8)) +#define E1000_DCA_TXCTRL(_n) (0x03814 + (_n << 8)) +#define E1000_DCA_RXCTRL(_n) (0x02814 + (_n << 8)) +#define E1000_TDWBAL(_n) ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) : (0x0E038 + ((_n) * 0x40))) +#define E1000_TDWBAH(_n) ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) : (0x0E03C + ((_n) * 0x40))) +#define E1000_RSRPD 0x02C00 /* Rx Small Packet Detect - RW */ +#define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */ +#define E1000_TXDMAC 0x03000 /* Tx DMA Control - RW */ +#define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */ +#define E1000_PSRTYPE(_i) (0x05480 + ((_i) * 4)) +#define E1000_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : (0x054E0 + ((_i - 16) * 8))) +#define E1000_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : (0x054E4 + ((_i - 16) * 8))) +#define E1000_IP4AT_REG(_i) (0x05840 + ((_i) * 8)) +#define E1000_IP6AT_REG(_i) (0x05880 + ((_i) * 4)) +#define E1000_WUPM_REG(_i) (0x05A00 + ((_i) * 4)) +#define E1000_FFMT_REG(_i) (0x09000 + ((_i) * 8)) +#define E1000_FFVT_REG(_i) (0x09800 + ((_i) * 8)) +#define E1000_FFLT_REG(_i) (0x05F00 + ((_i) * 8)) +#define E1000_TDFH 0x03410 /* Tx Data FIFO Head - RW */ +#define E1000_TDFT 0x03418 /* Tx Data FIFO Tail - RW */ +#define E1000_TDFHS 0x03420 /* Tx Data FIFO Head Saved - RW */ +#define E1000_TDFTS 0x03428 /* Tx Data FIFO Tail Saved - RW */ +#define E1000_TDFPC 0x03430 /* Tx Data FIFO Packet Count - RW */ +#define E1000_TDPUMB 0x0357C /* DMA Tx Descriptor uC Mail Box - RW */ +#define E1000_TDPUAD 0x03580 /* DMA Tx Descriptor uC Addr Command - RW */ +#define E1000_TDPUWD 0x03584 /* DMA Tx Descriptor uC Data Write - RW */ +#define E1000_TDPURD 0x03588 /* DMA Tx Descriptor uC Data Read - RW */ +#define E1000_TDPUCTL 0x0358C /* DMA Tx Descriptor uC Control - RW */ +#define E1000_DTXCTL 0x03590 /* DMA Tx Control - RW */ +#define E1000_TIDV 0x03820 /* Tx Interrupt Delay Value - RW */ +#define E1000_TADV 0x0382C /* Tx Interrupt Absolute Delay Val - RW */ +#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */ +#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */ +#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ +#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ +#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */ +#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */ +#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */ +#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */ +#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */ +#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */ +#define E1000_COLC 0x04028 /* Collision Count - R/clr */ +#define E1000_DC 0x04030 /* Defer Count - R/clr */ +#define E1000_TNCRS 0x04034 /* Tx-No CRS - R/clr */ +#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */ +#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */ +#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */ +#define E1000_XONRXC 0x04048 /* XON Rx Count - R/clr */ +#define E1000_XONTXC 0x0404C /* XON Tx Count - R/clr */ +#define E1000_XOFFRXC 0x04050 /* XOFF Rx Count - R/clr */ +#define E1000_XOFFTXC 0x04054 /* XOFF Tx Count - R/clr */ +#define E1000_FCRUC 0x04058 /* Flow Control Rx Unsupported Count- R/clr */ +#define E1000_PRC64 0x0405C /* Packets Rx (64 bytes) - R/clr */ +#define E1000_PRC127 0x04060 /* Packets Rx (65-127 bytes) - R/clr */ +#define E1000_PRC255 0x04064 /* Packets Rx (128-255 bytes) - R/clr */ +#define E1000_PRC511 0x04068 /* Packets Rx (255-511 bytes) - R/clr */ +#define E1000_PRC1023 0x0406C /* Packets Rx (512-1023 bytes) - R/clr */ +#define E1000_PRC1522 0x04070 /* Packets Rx (1024-1522 bytes) - R/clr */ +#define E1000_GPRC 0x04074 /* Good Packets Rx Count - R/clr */ +#define E1000_BPRC 0x04078 /* Broadcast Packets Rx Count - R/clr */ +#define E1000_MPRC 0x0407C /* Multicast Packets Rx Count - R/clr */ +#define E1000_GPTC 0x04080 /* Good Packets Tx Count - R/clr */ +#define E1000_GORCL 0x04088 /* Good Octets Rx Count Low - R/clr */ +#define E1000_GORCH 0x0408C /* Good Octets Rx Count High - R/clr */ +#define E1000_GOTCL 0x04090 /* Good Octets Tx Count Low - R/clr */ +#define E1000_GOTCH 0x04094 /* Good Octets Tx Count High - R/clr */ +#define E1000_RNBC 0x040A0 /* Rx No Buffers Count - R/clr */ +#define E1000_RUC 0x040A4 /* Rx Undersize Count - R/clr */ +#define E1000_RFC 0x040A8 /* Rx Fragment Count - R/clr */ +#define E1000_ROC 0x040AC /* Rx Oversize Count - R/clr */ +#define E1000_RJC 0x040B0 /* Rx Jabber Count - R/clr */ +#define E1000_MGTPRC 0x040B4 /* Management Packets Rx Count - R/clr */ +#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */ +#define E1000_MGTPTC 0x040BC /* Management Packets Tx Count - R/clr */ +#define E1000_TORL 0x040C0 /* Total Octets Rx Low - R/clr */ +#define E1000_TORH 0x040C4 /* Total Octets Rx High - R/clr */ +#define E1000_TOTL 0x040C8 /* Total Octets Tx Low - R/clr */ +#define E1000_TOTH 0x040CC /* Total Octets Tx High - R/clr */ +#define E1000_TPR 0x040D0 /* Total Packets Rx - R/clr */ +#define E1000_TPT 0x040D4 /* Total Packets Tx - R/clr */ +#define E1000_PTC64 0x040D8 /* Packets Tx (64 bytes) - R/clr */ +#define E1000_PTC127 0x040DC /* Packets Tx (65-127 bytes) - R/clr */ +#define E1000_PTC255 0x040E0 /* Packets Tx (128-255 bytes) - R/clr */ +#define E1000_PTC511 0x040E4 /* Packets Tx (256-511 bytes) - R/clr */ +#define E1000_PTC1023 0x040E8 /* Packets Tx (512-1023 bytes) - R/clr */ +#define E1000_PTC1522 0x040EC /* Packets Tx (1024-1522 Bytes) - R/clr */ +#define E1000_MPTC 0x040F0 /* Multicast Packets Tx Count - R/clr */ +#define E1000_BPTC 0x040F4 /* Broadcast Packets Tx Count - R/clr */ +#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context Tx - R/clr */ +#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context Tx Fail - R/clr */ +#define E1000_IAC 0x04100 /* Interrupt Assertion Count */ +#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Packet Timer Expire Count */ +#define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Absolute Timer Expire Count */ +#define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Packet Timer Expire Count */ +#define E1000_ICTXATC 0x04110 /* Interrupt Cause Tx Absolute Timer Expire Count */ +#define E1000_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */ +#define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Minimum Threshold Count */ +#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */ +#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */ + +#define E1000_PCS_CFG0 0x04200 /* PCS Configuration 0 - RW */ +#define E1000_PCS_LCTL 0x04208 /* PCS Link Control - RW */ +#define E1000_PCS_LSTAT 0x0420C /* PCS Link Status - RO */ +#define E1000_CBTMPC 0x0402C /* Circuit Breaker Tx Packet Count */ +#define E1000_HTDPMC 0x0403C /* Host Transmit Discarded Packets */ +#define E1000_CBRDPC 0x04044 /* Circuit Breaker Rx Dropped Count */ +#define E1000_CBRMPC 0x040FC /* Circuit Breaker Rx Packet Count */ +#define E1000_RPTHC 0x04104 /* Rx Packets To Host */ +#define E1000_HGPTC 0x04118 /* Host Good Packets Tx Count */ +#define E1000_HTCBDPC 0x04124 /* Host Tx Circuit Breaker Dropped Count */ +#define E1000_HGORCL 0x04128 /* Host Good Octets Received Count Low */ +#define E1000_HGORCH 0x0412C /* Host Good Octets Received Count High */ +#define E1000_HGOTCL 0x04130 /* Host Good Octets Transmit Count Low */ +#define E1000_HGOTCH 0x04134 /* Host Good Octets Transmit Count High */ +#define E1000_LENERRS 0x04138 /* Length Errors Count */ +#define E1000_SCVPC 0x04228 /* SerDes/SGMII Code Violation Pkt Count */ +#define E1000_HRMPC 0x0A018 /* Header Redirection Missed Packet Count */ +#define E1000_PCS_ANADV 0x04218 /* AN advertisement - RW */ +#define E1000_PCS_LPAB 0x0421C /* Link Partner Ability - RW */ +#define E1000_PCS_NPTX 0x04220 /* AN Next Page Transmit - RW */ +#define E1000_PCS_LPABNP 0x04224 /* Link Partner Ability Next Page - RW */ +#define E1000_1GSTAT_RCV 0x04228 /* 1GSTAT Code Violation Packet Count - RW */ +#define E1000_RXCSUM 0x05000 /* Rx Checksum Control - RW */ +#define E1000_RLPML 0x05004 /* Rx Long Packet Max Length */ +#define E1000_RFCTL 0x05008 /* Receive Filter Control*/ +#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ +#define E1000_RA 0x05400 /* Receive Address - RW Array */ +#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */ +#define E1000_VMD_CTL 0x0581C /* VMDq Control - RW */ +#define E1000_VFQA0 0x0B000 /* VLAN Filter Queue Array 0 - RW Array */ +#define E1000_VFQA1 0x0B200 /* VLAN Filter Queue Array 1 - RW Array */ +#define E1000_WUC 0x05800 /* Wakeup Control - RW */ +#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */ +#define E1000_WUS 0x05810 /* Wakeup Status - RO */ +#define E1000_MANC 0x05820 /* Management Control - RW */ +#define E1000_IPAV 0x05838 /* IP Address Valid - RW */ +#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */ +#define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */ +#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */ +#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */ +#define E1000_PBACL 0x05B68 /* MSIx PBA Clear - Read/Write 1's to clear */ +#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */ +#define E1000_HOST_IF 0x08800 /* Host Interface */ +#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */ +#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */ + +#define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */ +#define E1000_MDPHYA 0x0003C /* PHY address - RW */ +#define E1000_MANC2H 0x05860 /* Management Control To Host - RW */ +#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */ +#define E1000_CCMCTL 0x05B48 /* CCM Control Register */ +#define E1000_GIOCTL 0x05B44 /* GIO Analog Control Register */ +#define E1000_SCCTL 0x05B4C /* PCIc PLL Configuration Register */ +#define E1000_GCR 0x05B00 /* PCI-Ex Control */ +#define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */ +#define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */ +#define E1000_GSCL_3 0x05B18 /* PCI-Ex Statistic Control #3 */ +#define E1000_GSCL_4 0x05B1C /* PCI-Ex Statistic Control #4 */ +#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */ +#define E1000_SWSM 0x05B50 /* SW Semaphore */ +#define E1000_FWSM 0x05B54 /* FW Semaphore */ +#define E1000_DCA_ID 0x05B70 /* DCA Requester ID Information - RO */ +#define E1000_DCA_CTRL 0x05B74 /* DCA Control - RW */ +#define E1000_FFLT_DBG 0x05F04 /* Debug Register */ +#define E1000_HICR 0x08F00 /* Host Interface Control */ + +/* RSS registers */ +#define E1000_CPUVEC 0x02C10 /* CPU Vector Register - RW */ +#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */ +#define E1000_IMIR(_i) (0x05A80 + ((_i) * 4)) /* Immediate Interrupt */ +#define E1000_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* Immediate Interrupt Ext*/ +#define E1000_IMIRVP 0x05AC0 /* Immediate Interrupt Rx VLAN Priority - RW */ +#define E1000_MSIXBM(_i) (0x01600 + ((_i) * 4)) /* MSI-X Allocation Register (_i) - RW */ +#define E1000_MSIXTADD(_i) (0x0C000 + ((_i) * 0x10)) /* MSI-X Table entry addr low reg 0 - RW */ +#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10)) /* MSI-X Table entry addr upper reg 0 - RW */ +#define E1000_MSIXTMSG(_i) (0x0C008 + ((_i) * 0x10)) /* MSI-X Table entry message reg 0 - RW */ +#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10)) /* MSI-X Table entry vector ctrl reg 0 - RW */ +#define E1000_MSIXPBA 0x0E000 /* MSI-X Pending bit array */ +#define E1000_RETA(_i) (0x05C00 + ((_i) * 4)) /* Redirection Table - RW Array */ +#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW Array */ +#define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */ +#define E1000_RSSIR 0x05868 /* RSS Interrupt Request */ +#define E1000_RXMTRL 0x0B634 /* Time sync Rx EtherType and Message Type - RW */ +#define E1000_RXUDP 0x0B638 /* Time Sync Rx UDP Port - RW */ +#endif --- linux-2.6.27.orig/ubuntu/e1000e/e1000_nvm.c +++ linux-2.6.27/ubuntu/e1000e/e1000_nvm.c @@ -0,0 +1,875 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include "e1000_hw.h" + +/** + * e1000_init_nvm_ops_generic - Initialize NVM function pointers + * @hw: pointer to the HW structure + * + * Setups up the function pointers to no-op functions + **/ +void e1000_init_nvm_ops_generic(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + DEBUGFUNC("e1000_init_nvm_ops_generic"); + + /* Initialize function pointers */ + nvm->ops.reload = e1000_reload_nvm_generic; +} + +/** + * e1000_raise_eec_clk - Raise EEPROM clock + * @hw: pointer to the HW structure + * @eecd: pointer to the EEPROM + * + * Enable/Raise the EEPROM clock bit. + **/ +static void e1000_raise_eec_clk(struct e1000_hw *hw, u32 *eecd) +{ + *eecd = *eecd | E1000_EECD_SK; + E1000_WRITE_REG(hw, E1000_EECD, *eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(hw->nvm.delay_usec); +} + +/** + * e1000_lower_eec_clk - Lower EEPROM clock + * @hw: pointer to the HW structure + * @eecd: pointer to the EEPROM + * + * Clear/Lower the EEPROM clock bit. + **/ +static void e1000_lower_eec_clk(struct e1000_hw *hw, u32 *eecd) +{ + *eecd = *eecd & ~E1000_EECD_SK; + E1000_WRITE_REG(hw, E1000_EECD, *eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(hw->nvm.delay_usec); +} + +/** + * e1000_shift_out_eec_bits - Shift data bits our to the EEPROM + * @hw: pointer to the HW structure + * @data: data to send to the EEPROM + * @count: number of bits to shift out + * + * We need to shift 'count' bits out to the EEPROM. So, the value in the + * "data" parameter will be shifted out to the EEPROM one bit at a time. + * In order to do this, "data" must be broken down into bits. + **/ +static void e1000_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 eecd = E1000_READ_REG(hw, E1000_EECD); + u32 mask; + + DEBUGFUNC("e1000_shift_out_eec_bits"); + + mask = 0x01 << (count - 1); + if (nvm->type == e1000_nvm_eeprom_microwire) + eecd &= ~E1000_EECD_DO; + else if (nvm->type == e1000_nvm_eeprom_spi) + eecd |= E1000_EECD_DO; + + do { + eecd &= ~E1000_EECD_DI; + + if (data & mask) + eecd |= E1000_EECD_DI; + + E1000_WRITE_REG(hw, E1000_EECD, eecd); + E1000_WRITE_FLUSH(hw); + + usec_delay(nvm->delay_usec); + + e1000_raise_eec_clk(hw, &eecd); + e1000_lower_eec_clk(hw, &eecd); + + mask >>= 1; + } while (mask); + + eecd &= ~E1000_EECD_DI; + E1000_WRITE_REG(hw, E1000_EECD, eecd); +} + +/** + * e1000_shift_in_eec_bits - Shift data bits in from the EEPROM + * @hw: pointer to the HW structure + * @count: number of bits to shift in + * + * In order to read a register from the EEPROM, we need to shift 'count' bits + * in from the EEPROM. Bits are "shifted in" by raising the clock input to + * the EEPROM (setting the SK bit), and then reading the value of the data out + * "DO" bit. During this "shifting in" process the data in "DI" bit should + * always be clear. + **/ +static u16 e1000_shift_in_eec_bits(struct e1000_hw *hw, u16 count) +{ + u32 eecd; + u32 i; + u16 data; + + DEBUGFUNC("e1000_shift_in_eec_bits"); + + eecd = E1000_READ_REG(hw, E1000_EECD); + + eecd &= ~(E1000_EECD_DO | E1000_EECD_DI); + data = 0; + + for (i = 0; i < count; i++) { + data <<= 1; + e1000_raise_eec_clk(hw, &eecd); + + eecd = E1000_READ_REG(hw, E1000_EECD); + + eecd &= ~E1000_EECD_DI; + if (eecd & E1000_EECD_DO) + data |= 1; + + e1000_lower_eec_clk(hw, &eecd); + } + + return data; +} + +/** + * e1000_poll_eerd_eewr_done - Poll for EEPROM read/write completion + * @hw: pointer to the HW structure + * @ee_reg: EEPROM flag for polling + * + * Polls the EEPROM status bit for either read or write completion based + * upon the value of 'ee_reg'. + **/ +s32 e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg) +{ + u32 attempts = 100000; + u32 i, reg = 0; + s32 ret_val = -E1000_ERR_NVM; + + DEBUGFUNC("e1000_poll_eerd_eewr_done"); + + for (i = 0; i < attempts; i++) { + if (ee_reg == E1000_NVM_POLL_READ) + reg = E1000_READ_REG(hw, E1000_EERD); + else + reg = E1000_READ_REG(hw, E1000_EEWR); + + if (reg & E1000_NVM_RW_REG_DONE) { + ret_val = E1000_SUCCESS; + break; + } + + usec_delay(5); + } + + return ret_val; +} + +/** + * e1000_acquire_nvm_generic - Generic request for access to EEPROM + * @hw: pointer to the HW structure + * + * Set the EEPROM access request bit and wait for EEPROM access grant bit. + * Return successful if access grant bit set, else clear the request for + * EEPROM access and return -E1000_ERR_NVM (-1). + **/ +s32 e1000_acquire_nvm_generic(struct e1000_hw *hw) +{ + u32 eecd = E1000_READ_REG(hw, E1000_EECD); + s32 timeout = E1000_NVM_GRANT_ATTEMPTS; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_acquire_nvm_generic"); + + E1000_WRITE_REG(hw, E1000_EECD, eecd | E1000_EECD_REQ); + eecd = E1000_READ_REG(hw, E1000_EECD); + + while (timeout) { + if (eecd & E1000_EECD_GNT) + break; + usec_delay(5); + eecd = E1000_READ_REG(hw, E1000_EECD); + timeout--; + } + + if (!timeout) { + eecd &= ~E1000_EECD_REQ; + E1000_WRITE_REG(hw, E1000_EECD, eecd); + DEBUGOUT("Could not acquire NVM grant\n"); + ret_val = -E1000_ERR_NVM; + } + + return ret_val; +} + +/** + * e1000_standby_nvm - Return EEPROM to standby state + * @hw: pointer to the HW structure + * + * Return the EEPROM to a standby state. + **/ +static void e1000_standby_nvm(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 eecd = E1000_READ_REG(hw, E1000_EECD); + + DEBUGFUNC("e1000_standby_nvm"); + + if (nvm->type == e1000_nvm_eeprom_microwire) { + eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); + E1000_WRITE_REG(hw, E1000_EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(nvm->delay_usec); + + e1000_raise_eec_clk(hw, &eecd); + + /* Select EEPROM */ + eecd |= E1000_EECD_CS; + E1000_WRITE_REG(hw, E1000_EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(nvm->delay_usec); + + e1000_lower_eec_clk(hw, &eecd); + } else if (nvm->type == e1000_nvm_eeprom_spi) { + /* Toggle CS to flush commands */ + eecd |= E1000_EECD_CS; + E1000_WRITE_REG(hw, E1000_EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(nvm->delay_usec); + eecd &= ~E1000_EECD_CS; + E1000_WRITE_REG(hw, E1000_EECD, eecd); + E1000_WRITE_FLUSH(hw); + usec_delay(nvm->delay_usec); + } +} + +/** + * e1000_stop_nvm - Terminate EEPROM command + * @hw: pointer to the HW structure + * + * Terminates the current command by inverting the EEPROM's chip select pin. + **/ +void e1000_stop_nvm(struct e1000_hw *hw) +{ + u32 eecd; + + DEBUGFUNC("e1000_stop_nvm"); + + eecd = E1000_READ_REG(hw, E1000_EECD); + if (hw->nvm.type == e1000_nvm_eeprom_spi) { + /* Pull CS high */ + eecd |= E1000_EECD_CS; + e1000_lower_eec_clk(hw, &eecd); + } else if (hw->nvm.type == e1000_nvm_eeprom_microwire) { + /* CS on Microwire is active-high */ + eecd &= ~(E1000_EECD_CS | E1000_EECD_DI); + E1000_WRITE_REG(hw, E1000_EECD, eecd); + e1000_raise_eec_clk(hw, &eecd); + e1000_lower_eec_clk(hw, &eecd); + } +} + +/** + * e1000_release_nvm_generic - Release exclusive access to EEPROM + * @hw: pointer to the HW structure + * + * Stop any current commands to the EEPROM and clear the EEPROM request bit. + **/ +void e1000_release_nvm_generic(struct e1000_hw *hw) +{ + u32 eecd; + + DEBUGFUNC("e1000_release_nvm_generic"); + + e1000_stop_nvm(hw); + + eecd = E1000_READ_REG(hw, E1000_EECD); + eecd &= ~E1000_EECD_REQ; + E1000_WRITE_REG(hw, E1000_EECD, eecd); +} + +/** + * e1000_ready_nvm_eeprom - Prepares EEPROM for read/write + * @hw: pointer to the HW structure + * + * Setups the EEPROM for reading and writing. + **/ +static s32 e1000_ready_nvm_eeprom(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 eecd = E1000_READ_REG(hw, E1000_EECD); + s32 ret_val = E1000_SUCCESS; + u16 timeout = 0; + u8 spi_stat_reg; + + DEBUGFUNC("e1000_ready_nvm_eeprom"); + + if (nvm->type == e1000_nvm_eeprom_microwire) { + /* Clear SK and DI */ + eecd &= ~(E1000_EECD_DI | E1000_EECD_SK); + E1000_WRITE_REG(hw, E1000_EECD, eecd); + /* Set CS */ + eecd |= E1000_EECD_CS; + E1000_WRITE_REG(hw, E1000_EECD, eecd); + } else if (nvm->type == e1000_nvm_eeprom_spi) { + /* Clear SK and CS */ + eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); + E1000_WRITE_REG(hw, E1000_EECD, eecd); + usec_delay(1); + timeout = NVM_MAX_RETRY_SPI; + + /* + * Read "Status Register" repeatedly until the LSB is cleared. + * The EEPROM will signal that the command has been completed + * by clearing bit 0 of the internal status register. If it's + * not cleared within 'timeout', then error out. + */ + while (timeout) { + e1000_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI, + hw->nvm.opcode_bits); + spi_stat_reg = (u8)e1000_shift_in_eec_bits(hw, 8); + if (!(spi_stat_reg & NVM_STATUS_RDY_SPI)) + break; + + usec_delay(5); + e1000_standby_nvm(hw); + timeout--; + } + + if (!timeout) { + DEBUGOUT("SPI NVM Status error\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + } + +out: + return ret_val; +} + +/** + * e1000_read_nvm_spi - Read EEPROM's using SPI + * @hw: pointer to the HW structure + * @offset: offset of word in the EEPROM to read + * @words: number of words to read + * @data: word read from the EEPROM + * + * Reads a 16 bit word from the EEPROM. + **/ +s32 e1000_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 i = 0; + s32 ret_val; + u16 word_in; + u8 read_opcode = NVM_READ_OPCODE_SPI; + + DEBUGFUNC("e1000_read_nvm_spi"); + + /* + * A check for invalid values: offset too large, too many words, + * and not enough words. + */ + if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || + (words == 0)) { + DEBUGOUT("nvm parameter(s) out of bounds\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + + ret_val = nvm->ops.acquire(hw); + if (ret_val) + goto out; + + ret_val = e1000_ready_nvm_eeprom(hw); + if (ret_val) + goto release; + + e1000_standby_nvm(hw); + + if ((nvm->address_bits == 8) && (offset >= 128)) + read_opcode |= NVM_A8_OPCODE_SPI; + + /* Send the READ command (opcode + addr) */ + e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits); + e1000_shift_out_eec_bits(hw, (u16)(offset*2), nvm->address_bits); + + /* + * Read the data. SPI NVMs increment the address with each byte + * read and will roll over if reading beyond the end. This allows + * us to read the whole NVM from any offset + */ + for (i = 0; i < words; i++) { + word_in = e1000_shift_in_eec_bits(hw, 16); + data[i] = (word_in >> 8) | (word_in << 8); + } + +release: + nvm->ops.release(hw); + +out: + return ret_val; +} + +/** + * e1000_read_nvm_microwire - Reads EEPROM's using microwire + * @hw: pointer to the HW structure + * @offset: offset of word in the EEPROM to read + * @words: number of words to read + * @data: word read from the EEPROM + * + * Reads a 16 bit word from the EEPROM. + **/ +s32 e1000_read_nvm_microwire(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 i = 0; + s32 ret_val; + u8 read_opcode = NVM_READ_OPCODE_MICROWIRE; + + DEBUGFUNC("e1000_read_nvm_microwire"); + + /* + * A check for invalid values: offset too large, too many words, + * and not enough words. + */ + if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || + (words == 0)) { + DEBUGOUT("nvm parameter(s) out of bounds\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + + ret_val = nvm->ops.acquire(hw); + if (ret_val) + goto out; + + ret_val = e1000_ready_nvm_eeprom(hw); + if (ret_val) + goto release; + + for (i = 0; i < words; i++) { + /* Send the READ command (opcode + addr) */ + e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits); + e1000_shift_out_eec_bits(hw, (u16)(offset + i), + nvm->address_bits); + + /* + * Read the data. For microwire, each word requires the + * overhead of setup and tear-down. + */ + data[i] = e1000_shift_in_eec_bits(hw, 16); + e1000_standby_nvm(hw); + } + +release: + nvm->ops.release(hw); + +out: + return ret_val; +} + +/** + * e1000_read_nvm_eerd - Reads EEPROM using EERD register + * @hw: pointer to the HW structure + * @offset: offset of word in the EEPROM to read + * @words: number of words to read + * @data: word read from the EEPROM + * + * Reads a 16 bit word from the EEPROM using the EERD register. + **/ +s32 e1000_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 i, eerd = 0; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_read_nvm_eerd"); + + /* + * A check for invalid values: offset too large, too many words, + * too many words for the offset, and not enough words. + */ + if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || + (words == 0)) { + DEBUGOUT("nvm parameter(s) out of bounds\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + + for (i = 0; i < words; i++) { + eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) + + E1000_NVM_RW_REG_START; + + E1000_WRITE_REG(hw, E1000_EERD, eerd); + ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ); + if (ret_val) + break; + + data[i] = (E1000_READ_REG(hw, E1000_EERD) >> + E1000_NVM_RW_REG_DATA); + } + +out: + return ret_val; +} + +/** + * e1000_write_nvm_spi - Write to EEPROM using SPI + * @hw: pointer to the HW structure + * @offset: offset within the EEPROM to be written to + * @words: number of words to write + * @data: 16 bit word(s) to be written to the EEPROM + * + * Writes data to EEPROM at offset using SPI interface. + * + * If e1000_update_nvm_checksum is not called after this function , the + * EEPROM will most likely contain an invalid checksum. + **/ +s32 e1000_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + s32 ret_val; + u16 widx = 0; + + DEBUGFUNC("e1000_write_nvm_spi"); + + /* + * A check for invalid values: offset too large, too many words, + * and not enough words. + */ + if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || + (words == 0)) { + DEBUGOUT("nvm parameter(s) out of bounds\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + + ret_val = nvm->ops.acquire(hw); + if (ret_val) + goto out; + + while (widx < words) { + u8 write_opcode = NVM_WRITE_OPCODE_SPI; + + ret_val = e1000_ready_nvm_eeprom(hw); + if (ret_val) + goto release; + + e1000_standby_nvm(hw); + + /* Send the WRITE ENABLE command (8 bit opcode) */ + e1000_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI, + nvm->opcode_bits); + + e1000_standby_nvm(hw); + + /* + * Some SPI eeproms use the 8th address bit embedded in the + * opcode + */ + if ((nvm->address_bits == 8) && (offset >= 128)) + write_opcode |= NVM_A8_OPCODE_SPI; + + /* Send the Write command (8-bit opcode + addr) */ + e1000_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits); + e1000_shift_out_eec_bits(hw, (u16)((offset + widx) * 2), + nvm->address_bits); + + /* Loop to allow for up to whole page write of eeprom */ + while (widx < words) { + u16 word_out = data[widx]; + word_out = (word_out >> 8) | (word_out << 8); + e1000_shift_out_eec_bits(hw, word_out, 16); + widx++; + + if ((((offset + widx) * 2) % nvm->page_size) == 0) { + e1000_standby_nvm(hw); + break; + } + } + } + + msec_delay(nvm->semaphore_delay); +release: + nvm->ops.release(hw); + +out: + return ret_val; +} + +/** + * e1000_write_nvm_microwire - Writes EEPROM using microwire + * @hw: pointer to the HW structure + * @offset: offset within the EEPROM to be written to + * @words: number of words to write + * @data: 16 bit word(s) to be written to the EEPROM + * + * Writes data to EEPROM at offset using microwire interface. + * + * If e1000_update_nvm_checksum is not called after this function , the + * EEPROM will most likely contain an invalid checksum. + **/ +s32 e1000_write_nvm_microwire(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + s32 ret_val; + u32 eecd; + u16 words_written = 0; + u16 widx = 0; + + DEBUGFUNC("e1000_write_nvm_microwire"); + + /* + * A check for invalid values: offset too large, too many words, + * and not enough words. + */ + if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || + (words == 0)) { + DEBUGOUT("nvm parameter(s) out of bounds\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + + ret_val = nvm->ops.acquire(hw); + if (ret_val) + goto out; + + ret_val = e1000_ready_nvm_eeprom(hw); + if (ret_val) + goto release; + + e1000_shift_out_eec_bits(hw, NVM_EWEN_OPCODE_MICROWIRE, + (u16)(nvm->opcode_bits + 2)); + + e1000_shift_out_eec_bits(hw, 0, (u16)(nvm->address_bits - 2)); + + e1000_standby_nvm(hw); + + while (words_written < words) { + e1000_shift_out_eec_bits(hw, NVM_WRITE_OPCODE_MICROWIRE, + nvm->opcode_bits); + + e1000_shift_out_eec_bits(hw, (u16)(offset + words_written), + nvm->address_bits); + + e1000_shift_out_eec_bits(hw, data[words_written], 16); + + e1000_standby_nvm(hw); + + for (widx = 0; widx < 200; widx++) { + eecd = E1000_READ_REG(hw, E1000_EECD); + if (eecd & E1000_EECD_DO) + break; + usec_delay(50); + } + + if (widx == 200) { + DEBUGOUT("NVM Write did not complete\n"); + ret_val = -E1000_ERR_NVM; + goto release; + } + + e1000_standby_nvm(hw); + + words_written++; + } + + e1000_shift_out_eec_bits(hw, NVM_EWDS_OPCODE_MICROWIRE, + (u16)(nvm->opcode_bits + 2)); + + e1000_shift_out_eec_bits(hw, 0, (u16)(nvm->address_bits - 2)); + +release: + nvm->ops.release(hw); + +out: + return ret_val; +} + +/** + * e1000_read_pba_num_generic - Read device part number + * @hw: pointer to the HW structure + * @pba_num: pointer to device part number + * + * Reads the product board assembly (PBA) number from the EEPROM and stores + * the value in pba_num. + **/ +s32 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num) +{ + s32 ret_val; + u16 nvm_data; + + DEBUGFUNC("e1000_read_pba_num_generic"); + + ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + *pba_num = (u32)(nvm_data << 16); + + ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &nvm_data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + *pba_num |= nvm_data; + +out: + return ret_val; +} + +/** + * e1000_read_mac_addr_generic - Read device MAC address + * @hw: pointer to the HW structure + * + * Reads the device MAC address from the EEPROM and stores the value. + * Since devices with two ports use the same EEPROM, we increment the + * last bit in the MAC address for the second port. + **/ +s32 e1000_read_mac_addr_generic(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 offset, nvm_data, i; + + DEBUGFUNC("e1000_read_mac_addr"); + + for (i = 0; i < ETH_ADDR_LEN; i += 2) { + offset = i >> 1; + ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF); + hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8); + } + + /* Flip last bit of mac address if we're on second port */ + if (hw->bus.func == E1000_FUNC_1) + hw->mac.perm_addr[5] ^= 1; + + for (i = 0; i < ETH_ADDR_LEN; i++) + hw->mac.addr[i] = hw->mac.perm_addr[i]; + +out: + return ret_val; +} + +/** + * e1000_validate_nvm_checksum_generic - Validate EEPROM checksum + * @hw: pointer to the HW structure + * + * Calculates the EEPROM checksum by reading/adding each word of the EEPROM + * and then verifies that the sum of the EEPROM is equal to 0xBABA. + **/ +s32 e1000_validate_nvm_checksum_generic(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 checksum = 0; + u16 i, nvm_data; + + DEBUGFUNC("e1000_validate_nvm_checksum_generic"); + + for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { + ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + checksum += nvm_data; + } + + if (checksum != (u16) NVM_SUM) { + DEBUGOUT("NVM Checksum Invalid\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_update_nvm_checksum_generic - Update EEPROM checksum + * @hw: pointer to the HW structure + * + * Updates the EEPROM checksum by reading/adding each word of the EEPROM + * up to the checksum. Then calculates the EEPROM checksum and writes the + * value to the EEPROM. + **/ +s32 e1000_update_nvm_checksum_generic(struct e1000_hw *hw) +{ + s32 ret_val; + u16 checksum = 0; + u16 i, nvm_data; + + DEBUGFUNC("e1000_update_nvm_checksum"); + + for (i = 0; i < NVM_CHECKSUM_REG; i++) { + ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data); + if (ret_val) { + DEBUGOUT("NVM Read Error while updating checksum.\n"); + goto out; + } + checksum += nvm_data; + } + checksum = (u16) NVM_SUM - checksum; + ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum); + if (ret_val) { + DEBUGOUT("NVM Write Error while updating checksum.\n"); + } + +out: + return ret_val; +} + +/** + * e1000_reload_nvm_generic - Reloads EEPROM + * @hw: pointer to the HW structure + * + * Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the + * extended control register. + **/ +void e1000_reload_nvm_generic(struct e1000_hw *hw) +{ + u32 ctrl_ext; + + DEBUGFUNC("e1000_reload_nvm_generic"); + + usec_delay(10); + ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_EE_RST; + E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); + E1000_WRITE_FLUSH(hw); +} + --- linux-2.6.27.orig/ubuntu/e1000e/e1000_phy.c +++ linux-2.6.27/ubuntu/e1000e/e1000_phy.c @@ -0,0 +1,2489 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include "e1000_hw.h" + +static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg); +/* Cable length tables */ +static const u16 e1000_m88_cable_length_table[] = + { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED }; +#define M88E1000_CABLE_LENGTH_TABLE_SIZE \ + (sizeof(e1000_m88_cable_length_table) / \ + sizeof(e1000_m88_cable_length_table[0])) + +static const u16 e1000_igp_2_cable_length_table[] = + { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, + 0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41, + 6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61, + 21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82, + 40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104, + 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, + 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124, + 104, 109, 114, 118, 121, 124}; +#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \ + (sizeof(e1000_igp_2_cable_length_table) / \ + sizeof(e1000_igp_2_cable_length_table[0])) + +/** + * e1000_check_reset_block_generic - Check if PHY reset is blocked + * @hw: pointer to the HW structure + * + * Read the PHY management control register and check whether a PHY reset + * is blocked. If a reset is not blocked return E1000_SUCCESS, otherwise + * return E1000_BLK_PHY_RESET (12). + **/ +s32 e1000_check_reset_block_generic(struct e1000_hw *hw) +{ + u32 manc; + + DEBUGFUNC("e1000_check_reset_block"); + + manc = E1000_READ_REG(hw, E1000_MANC); + + return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ? + E1000_BLK_PHY_RESET : E1000_SUCCESS; +} + +/** + * e1000_get_phy_id - Retrieve the PHY ID and revision + * @hw: pointer to the HW structure + * + * Reads the PHY registers and stores the PHY ID and possibly the PHY + * revision in the hardware structure. + **/ +s32 e1000_get_phy_id(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = E1000_SUCCESS; + u16 phy_id; + + DEBUGFUNC("e1000_get_phy_id"); + + if (!(phy->ops.read_reg)) + goto out; + + ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id); + if (ret_val) + goto out; + + phy->id = (u32)(phy_id << 16); + usec_delay(20); + ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id); + if (ret_val) + goto out; + + phy->id |= (u32)(phy_id & PHY_REVISION_MASK); + phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); + +out: + return ret_val; +} + +/** + * e1000_phy_reset_dsp_generic - Reset PHY DSP + * @hw: pointer to the HW structure + * + * Reset the digital signal processor. + **/ +s32 e1000_phy_reset_dsp_generic(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_phy_reset_dsp_generic"); + + if (!(hw->phy.ops.write_reg)) + goto out; + + ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0); + +out: + return ret_val; +} + +/** + * e1000_read_phy_reg_mdic - Read MDI control register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Reads the MDI control register in the PHY at offset and stores the + * information read to data. + **/ +s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 i, mdic = 0; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_read_phy_reg_mdic"); + + /* + * Set up Op-code, Phy Address, and register offset in the MDI + * Control register. The MAC will take care of interfacing with the + * PHY to retrieve the desired data. + */ + mdic = ((offset << E1000_MDIC_REG_SHIFT) | + (phy->addr << E1000_MDIC_PHY_SHIFT) | + (E1000_MDIC_OP_READ)); + + E1000_WRITE_REG(hw, E1000_MDIC, mdic); + + /* + * Poll the ready bit to see if the MDI read completed + * Increasing the time out as testing showed failures with + * the lower time out + */ + for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) { + usec_delay(50); + mdic = E1000_READ_REG(hw, E1000_MDIC); + if (mdic & E1000_MDIC_READY) + break; + } + if (!(mdic & E1000_MDIC_READY)) { + DEBUGOUT("MDI Read did not complete\n"); + ret_val = -E1000_ERR_PHY; + goto out; + } + if (mdic & E1000_MDIC_ERROR) { + DEBUGOUT("MDI Error\n"); + ret_val = -E1000_ERR_PHY; + goto out; + } + *data = (u16) mdic; + +out: + return ret_val; +} + +/** + * e1000_write_phy_reg_mdic - Write MDI control register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write to register at offset + * + * Writes data to MDI control register in the PHY at offset. + **/ +s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 i, mdic = 0; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_write_phy_reg_mdic"); + + /* + * Set up Op-code, Phy Address, and register offset in the MDI + * Control register. The MAC will take care of interfacing with the + * PHY to retrieve the desired data. + */ + mdic = (((u32)data) | + (offset << E1000_MDIC_REG_SHIFT) | + (phy->addr << E1000_MDIC_PHY_SHIFT) | + (E1000_MDIC_OP_WRITE)); + + E1000_WRITE_REG(hw, E1000_MDIC, mdic); + + /* + * Poll the ready bit to see if the MDI read completed + * Increasing the time out as testing showed failures with + * the lower time out + */ + for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) { + usec_delay(50); + mdic = E1000_READ_REG(hw, E1000_MDIC); + if (mdic & E1000_MDIC_READY) + break; + } + if (!(mdic & E1000_MDIC_READY)) { + DEBUGOUT("MDI Write did not complete\n"); + ret_val = -E1000_ERR_PHY; + goto out; + } + if (mdic & E1000_MDIC_ERROR) { + DEBUGOUT("MDI Error\n"); + ret_val = -E1000_ERR_PHY; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_read_phy_reg_m88 - Read m88 PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore, if necessary, then reads the PHY register at offset + * and storing the retrieved information in data. Release any acquired + * semaphores before exiting. + **/ +s32 e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data) +{ + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_read_phy_reg_m88"); + + if (!(hw->phy.ops.acquire)) + goto out; + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + ret_val = e1000_read_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + hw->phy.ops.release(hw); + +out: + return ret_val; +} + +/** + * e1000_write_phy_reg_m88 - Write m88 PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore, if necessary, then writes the data to PHY register + * at the offset. Release any acquired semaphores before exiting. + **/ +s32 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data) +{ + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_write_phy_reg_m88"); + + if (!(hw->phy.ops.acquire)) + goto out; + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + ret_val = e1000_write_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + hw->phy.ops.release(hw); + +out: + return ret_val; +} + +/** + * e1000_read_phy_reg_igp - Read igp PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore, if necessary, then reads the PHY register at offset + * and storing the retrieved information in data. Release any acquired + * semaphores before exiting. + **/ +s32 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data) +{ + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_read_phy_reg_igp"); + + if (!(hw->phy.ops.acquire)) + goto out; + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + if (offset > MAX_PHY_MULTI_PAGE_REG) { + ret_val = e1000_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (u16)offset); + if (ret_val) { + hw->phy.ops.release(hw); + goto out; + } + } + + ret_val = e1000_read_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + hw->phy.ops.release(hw); + +out: + return ret_val; +} + +/** + * e1000_write_phy_reg_igp - Write igp PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore, if necessary, then writes the data to PHY register + * at the offset. Release any acquired semaphores before exiting. + **/ +s32 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data) +{ + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_write_phy_reg_igp"); + + if (!(hw->phy.ops.acquire)) + goto out; + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + if (offset > MAX_PHY_MULTI_PAGE_REG) { + ret_val = e1000_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (u16)offset); + if (ret_val) { + hw->phy.ops.release(hw); + goto out; + } + } + + ret_val = e1000_write_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + hw->phy.ops.release(hw); + +out: + return ret_val; +} + +/** + * e1000_read_kmrn_reg_generic - Read kumeran register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore, if necessary. Then reads the PHY register at offset + * using the kumeran interface. The information retrieved is stored in data. + * Release any acquired semaphores before exiting. + **/ +s32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data) +{ + u32 kmrnctrlsta; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_read_kmrn_reg_generic"); + + if (!(hw->phy.ops.acquire)) + goto out; + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & + E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN; + E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta); + + usec_delay(2); + + kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA); + *data = (u16)kmrnctrlsta; + + hw->phy.ops.release(hw); + +out: + return ret_val; +} + +/** + * e1000_write_kmrn_reg_generic - Write kumeran register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore, if necessary. Then write the data to PHY register + * at the offset using the kumeran interface. Release any acquired semaphores + * before exiting. + **/ +s32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data) +{ + u32 kmrnctrlsta; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_write_kmrn_reg_generic"); + + if (!(hw->phy.ops.acquire)) + goto out; + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & + E1000_KMRNCTRLSTA_OFFSET) | data; + E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta); + + usec_delay(2); + hw->phy.ops.release(hw); + +out: + return ret_val; +} + +/** + * e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link + * @hw: pointer to the HW structure + * + * Sets up MDI/MDI-X and polarity for m88 PHY's. If necessary, transmit clock + * and downshift values are set also. + **/ +s32 e1000_copper_link_setup_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + + DEBUGFUNC("e1000_copper_link_setup_m88"); + + if (phy->reset_disable) { + ret_val = E1000_SUCCESS; + goto out; + } + + /* Enable CRS on TX. This must be set for half-duplex operation. */ + ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + goto out; + + /* For newer PHYs this bit is downshift enable */ + if (phy->type == e1000_phy_m88) + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + + /* + * Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds + * 1 - MDI mode + * 2 - MDI-X mode + * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) + */ + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + + switch (phy->mdix) { + case 1: + phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE; + break; + case 2: + phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE; + break; + case 3: + phy_data |= M88E1000_PSCR_AUTO_X_1000T; + break; + case 0: + default: + phy_data |= M88E1000_PSCR_AUTO_X_MODE; + break; + } + + /* + * Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled + */ + phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; + if (phy->disable_polarity_correction == 1) + phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; + + /* Enable downshift on BM (disabled by default) */ + if (phy->type == e1000_phy_bm) + phy_data |= BME1000_PSCR_ENABLE_DOWNSHIFT; + + ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); + if (ret_val) + goto out; + + if ((phy->type == e1000_phy_m88) && + (phy->revision < E1000_REVISION_4) && + (phy->id != BME1000_E_PHY_ID_R2)) { + /* + * Force TX_CLK in the Extended PHY Specific Control Register + * to 25MHz clock. + */ + ret_val = phy->ops.read_reg(hw, + M88E1000_EXT_PHY_SPEC_CTRL, + &phy_data); + if (ret_val) + goto out; + + phy_data |= M88E1000_EPSCR_TX_CLK_25; + + if ((phy->revision == E1000_REVISION_2) && + (phy->id == M88E1111_I_PHY_ID)) { + /* 82573L PHY - set the downshift counter to 5x. */ + phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK; + phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X; + } else { + /* Configure Master and Slave downshift values */ + phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | + M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); + phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | + M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); + } + ret_val = phy->ops.write_reg(hw, + M88E1000_EXT_PHY_SPEC_CTRL, + phy_data); + if (ret_val) + goto out; + } + + if ((phy->type == e1000_phy_bm) && (phy->id == BME1000_E_PHY_ID_R2)) { + /* Set PHY page 0, register 29 to 0x0003 */ + ret_val = phy->ops.write_reg(hw, 29, 0x0003); + if (ret_val) + goto out; + + /* Set PHY page 0, register 30 to 0x0000 */ + ret_val = phy->ops.write_reg(hw, 30, 0x0000); + if (ret_val) + goto out; + } + + /* Commit the changes. */ + ret_val = phy->ops.commit(hw); + if (ret_val) { + DEBUGOUT("Error committing the PHY changes\n"); + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_copper_link_setup_igp - Setup igp PHY's for copper link + * @hw: pointer to the HW structure + * + * Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for + * igp PHY's. + **/ +s32 e1000_copper_link_setup_igp(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + + DEBUGFUNC("e1000_copper_link_setup_igp"); + + if (phy->reset_disable) { + ret_val = E1000_SUCCESS; + goto out; + } + + ret_val = hw->phy.ops.reset(hw); + if (ret_val) { + DEBUGOUT("Error resetting the PHY.\n"); + goto out; + } + + /* + * Wait 100ms for MAC to configure PHY from NVM settings, to avoid + * timeout issues when LFS is enabled. + */ + msec_delay(100); + + /* + * The NVM settings will configure LPLU in D3 for + * non-IGP1 PHYs. + */ + if (phy->type == e1000_phy_igp) { + /* disable lplu d3 during driver init */ + ret_val = hw->phy.ops.set_d3_lplu_state(hw, false); + if (ret_val) { + DEBUGOUT("Error Disabling LPLU D3\n"); + goto out; + } + } + + /* disable lplu d0 during driver init */ + if (hw->phy.ops.set_d0_lplu_state) { + ret_val = hw->phy.ops.set_d0_lplu_state(hw, false); + if (ret_val) { + DEBUGOUT("Error Disabling LPLU D0\n"); + goto out; + } + } + /* Configure mdi-mdix settings */ + ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data); + if (ret_val) + goto out; + + data &= ~IGP01E1000_PSCR_AUTO_MDIX; + + switch (phy->mdix) { + case 1: + data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; + break; + case 2: + data |= IGP01E1000_PSCR_FORCE_MDI_MDIX; + break; + case 0: + default: + data |= IGP01E1000_PSCR_AUTO_MDIX; + break; + } + ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, data); + if (ret_val) + goto out; + + /* set auto-master slave resolution settings */ + if (hw->mac.autoneg) { + /* + * when autonegotiation advertisement is only 1000Mbps then we + * should disable SmartSpeed and enable Auto MasterSlave + * resolution as hardware default. + */ + if (phy->autoneg_advertised == ADVERTISE_1000_FULL) { + /* Disable SmartSpeed */ + ret_val = phy->ops.read_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + goto out; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = phy->ops.write_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + goto out; + + /* Set auto Master/Slave resolution process */ + ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data); + if (ret_val) + goto out; + + data &= ~CR_1000T_MS_ENABLE; + ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data); + if (ret_val) + goto out; + } + + ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data); + if (ret_val) + goto out; + + /* load defaults for future use */ + phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ? + ((data & CR_1000T_MS_VALUE) ? + e1000_ms_force_master : + e1000_ms_force_slave) : + e1000_ms_auto; + + switch (phy->ms_type) { + case e1000_ms_force_master: + data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE); + break; + case e1000_ms_force_slave: + data |= CR_1000T_MS_ENABLE; + data &= ~(CR_1000T_MS_VALUE); + break; + case e1000_ms_auto: + data &= ~CR_1000T_MS_ENABLE; + default: + break; + } + ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data); + if (ret_val) + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_copper_link_autoneg - Setup/Enable autoneg for copper link + * @hw: pointer to the HW structure + * + * Performs initial bounds checking on autoneg advertisement parameter, then + * configure to advertise the full capability. Setup the PHY to autoneg + * and restart the negotiation process between the link partner. If + * autoneg_wait_to_complete, then wait for autoneg to complete before exiting. + **/ +s32 e1000_copper_link_autoneg(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_ctrl; + + DEBUGFUNC("e1000_copper_link_autoneg"); + + /* + * Perform some bounds checking on the autoneg advertisement + * parameter. + */ + phy->autoneg_advertised &= phy->autoneg_mask; + + /* + * If autoneg_advertised is zero, we assume it was not defaulted + * by the calling code so we set to advertise full capability. + */ + if (phy->autoneg_advertised == 0) + phy->autoneg_advertised = phy->autoneg_mask; + + DEBUGOUT("Reconfiguring auto-neg advertisement params\n"); + ret_val = e1000_phy_setup_autoneg(hw); + if (ret_val) { + DEBUGOUT("Error Setting up Auto-Negotiation\n"); + goto out; + } + DEBUGOUT("Restarting Auto-Neg\n"); + + /* + * Restart auto-negotiation by setting the Auto Neg Enable bit and + * the Auto Neg Restart bit in the PHY control register. + */ + ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl); + if (ret_val) + goto out; + + phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); + ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl); + if (ret_val) + goto out; + + /* + * Does the user want to wait for Auto-Neg to complete here, or + * check at a later time (for example, callback routine). + */ + if (phy->autoneg_wait_to_complete) { + ret_val = hw->mac.ops.wait_autoneg(hw); + if (ret_val) { + DEBUGOUT("Error while waiting for " + "autoneg to complete\n"); + goto out; + } + } + + hw->mac.get_link_status = true; + +out: + return ret_val; +} + +/** + * e1000_phy_setup_autoneg - Configure PHY for auto-negotiation + * @hw: pointer to the HW structure + * + * Reads the MII auto-neg advertisement register and/or the 1000T control + * register and if the PHY is already setup for auto-negotiation, then + * return successful. Otherwise, setup advertisement and flow control to + * the appropriate values for the wanted auto-negotiation. + **/ +s32 e1000_phy_setup_autoneg(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 mii_autoneg_adv_reg; + u16 mii_1000t_ctrl_reg = 0; + + DEBUGFUNC("e1000_phy_setup_autoneg"); + + phy->autoneg_advertised &= phy->autoneg_mask; + + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg); + if (ret_val) + goto out; + + if (phy->autoneg_mask & ADVERTISE_1000_FULL) { + /* Read the MII 1000Base-T Control Register (Address 9). */ + ret_val = phy->ops.read_reg(hw, + PHY_1000T_CTRL, + &mii_1000t_ctrl_reg); + if (ret_val) + goto out; + } + + /* + * Need to parse both autoneg_advertised and fc and set up + * the appropriate PHY registers. First we will parse for + * autoneg_advertised software override. Since we can advertise + * a plethora of combinations, we need to check each bit + * individually. + */ + + /* + * First we clear all the 10/100 mb speed bits in the Auto-Neg + * Advertisement Register (Address 4) and the 1000 mb speed bits in + * the 1000Base-T Control Register (Address 9). + */ + mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS | + NWAY_AR_100TX_HD_CAPS | + NWAY_AR_10T_FD_CAPS | + NWAY_AR_10T_HD_CAPS); + mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS); + + DEBUGOUT1("autoneg_advertised %x\n", phy->autoneg_advertised); + + /* Do we want to advertise 10 Mb Half Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_10_HALF) { + DEBUGOUT("Advertise 10mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; + } + + /* Do we want to advertise 10 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_10_FULL) { + DEBUGOUT("Advertise 10mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; + } + + /* Do we want to advertise 100 Mb Half Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_100_HALF) { + DEBUGOUT("Advertise 100mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; + } + + /* Do we want to advertise 100 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_100_FULL) { + DEBUGOUT("Advertise 100mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; + } + + /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ + if (phy->autoneg_advertised & ADVERTISE_1000_HALF) { + DEBUGOUT("Advertise 1000mb Half duplex request denied!\n"); + } + + /* Do we want to advertise 1000 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_1000_FULL) { + DEBUGOUT("Advertise 1000mb Full duplex\n"); + mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; + } + + /* + * Check for a software override of the flow control settings, and + * setup the PHY advertisement registers accordingly. If + * auto-negotiation is enabled, then software will have to set the + * "PAUSE" bits to the correct value in the Auto-Negotiation + * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto- + * negotiation. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * but we do not support receiving pause frames). + * 3: Both Rx and Tx flow control (symmetric) are enabled. + * other: No software override. The flow control configuration + * in the EEPROM is used. + */ + switch (hw->fc.type) { + case e1000_fc_none: + /* + * Flow control (Rx & Tx) is completely disabled by a + * software over-ride. + */ + mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case e1000_fc_rx_pause: + /* + * Rx Flow control is enabled, and Tx Flow control is + * disabled, by a software over-ride. + * + * Since there really isn't a way to advertise that we are + * capable of Rx Pause ONLY, we will advertise that we + * support both symmetric and asymmetric Rx PAUSE. Later + * (in e1000_config_fc_after_link_up) we will disable the + * hw's ability to send PAUSE frames. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case e1000_fc_tx_pause: + /* + * Tx Flow control is enabled, and Rx Flow control is + * disabled, by a software over-ride. + */ + mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR; + mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE; + break; + case e1000_fc_full: + /* + * Flow control (both Rx and Tx) is enabled by a software + * over-ride. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + default: + DEBUGOUT("Flow control param set incorrectly\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg); + if (ret_val) + goto out; + + DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); + + if (phy->autoneg_mask & ADVERTISE_1000_FULL) { + ret_val = phy->ops.write_reg(hw, + PHY_1000T_CTRL, + mii_1000t_ctrl_reg); + if (ret_val) + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_setup_copper_link_generic - Configure copper link settings + * @hw: pointer to the HW structure + * + * Calls the appropriate function to configure the link for auto-neg or forced + * speed and duplex. Then we check for link, once link is established calls + * to configure collision distance and flow control are called. If link is + * not established, we return -E1000_ERR_PHY (-2). + **/ +s32 e1000_setup_copper_link_generic(struct e1000_hw *hw) +{ + s32 ret_val; + bool link; + + DEBUGFUNC("e1000_setup_copper_link_generic"); + + if (hw->mac.autoneg) { + /* + * Setup autoneg and flow control advertisement and perform + * autonegotiation. + */ + ret_val = e1000_copper_link_autoneg(hw); + if (ret_val) + goto out; + } else { + /* + * PHY will be set to 10H, 10F, 100H or 100F + * depending on user settings. + */ + DEBUGOUT("Forcing Speed and Duplex\n"); + ret_val = hw->phy.ops.force_speed_duplex(hw); + if (ret_val) { + DEBUGOUT("Error Forcing Speed and Duplex\n"); + goto out; + } + } + + /* + * Check link status. Wait up to 100 microseconds for link to become + * valid. + */ + ret_val = e1000_phy_has_link_generic(hw, + COPPER_LINK_UP_LIMIT, + 10, + &link); + if (ret_val) + goto out; + + if (link) { + DEBUGOUT("Valid link established!!!\n"); + e1000_config_collision_dist_generic(hw); + ret_val = e1000_config_fc_after_link_up_generic(hw); + } else { + DEBUGOUT("Unable to establish link!!!\n"); + } + +out: + return ret_val; +} + +/** + * e1000_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY + * @hw: pointer to the HW structure + * + * Calls the PHY setup function to force speed and duplex. Clears the + * auto-crossover to force MDI manually. Waits for link and returns + * successful if link up is successful, else -E1000_ERR_PHY (-2). + **/ +s32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + bool link; + + DEBUGFUNC("e1000_phy_force_speed_duplex_igp"); + + ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data); + if (ret_val) + goto out; + + e1000_phy_force_speed_duplex_setup(hw, &phy_data); + + ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data); + if (ret_val) + goto out; + + /* + * Clear Auto-Crossover to force MDI manually. IGP requires MDI + * forced whenever speed and duplex are forced. + */ + ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data); + if (ret_val) + goto out; + + phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX; + phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; + + ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data); + if (ret_val) + goto out; + + DEBUGOUT1("IGP PSCR: %X\n", phy_data); + + usec_delay(1); + + if (phy->autoneg_wait_to_complete) { + DEBUGOUT("Waiting for forced speed/duplex link on IGP phy.\n"); + + ret_val = e1000_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + goto out; + + if (!link) { + DEBUGOUT("Link taking longer than expected.\n"); + } + + /* Try once more */ + ret_val = e1000_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY + * @hw: pointer to the HW structure + * + * Calls the PHY setup function to force speed and duplex. Clears the + * auto-crossover to force MDI manually. Resets the PHY to commit the + * changes. If time expires while waiting for link up, we reset the DSP. + * After reset, TX_CLK and CRS on Tx must be set. Return successful upon + * successful completion, else return corresponding error code. + **/ +s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + bool link; + + DEBUGFUNC("e1000_phy_force_speed_duplex_m88"); + + /* + * Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI + * forced whenever speed and duplex are forced. + */ + ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + goto out; + + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); + if (ret_val) + goto out; + + DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data); + + ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data); + if (ret_val) + goto out; + + e1000_phy_force_speed_duplex_setup(hw, &phy_data); + + /* Reset the phy to commit changes. */ + phy_data |= MII_CR_RESET; + + ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data); + if (ret_val) + goto out; + + usec_delay(1); + + if (phy->autoneg_wait_to_complete) { + DEBUGOUT("Waiting for forced speed/duplex link on M88 phy.\n"); + + ret_val = e1000_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + goto out; + + if (!link) { + /* + * We didn't get link. + * Reset the DSP and cross our fingers. + */ + ret_val = phy->ops.write_reg(hw, + M88E1000_PHY_PAGE_SELECT, + 0x001d); + if (ret_val) + goto out; + ret_val = e1000_phy_reset_dsp_generic(hw); + if (ret_val) + goto out; + } + + /* Try once more */ + ret_val = e1000_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + goto out; + } + + ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + goto out; + + /* + * Resetting the phy means we need to re-force TX_CLK in the + * Extended PHY Specific Control Register to 25MHz clock from + * the reset value of 2.5MHz. + */ + phy_data |= M88E1000_EPSCR_TX_CLK_25; + ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); + if (ret_val) + goto out; + + /* + * In addition, we must re-enable CRS on Tx for both half and full + * duplex. + */ + ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + goto out; + + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); + +out: + return ret_val; +} + +/** + * e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex + * @hw: pointer to the HW structure + * @phy_ctrl: pointer to current value of PHY_CONTROL + * + * Forces speed and duplex on the PHY by doing the following: disable flow + * control, force speed/duplex on the MAC, disable auto speed detection, + * disable auto-negotiation, configure duplex, configure speed, configure + * the collision distance, write configuration to CTRL register. The + * caller must write to the PHY_CONTROL register for these settings to + * take affect. + **/ +void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 ctrl; + + DEBUGFUNC("e1000_phy_force_speed_duplex_setup"); + + /* Turn off flow control when forcing speed/duplex */ + hw->fc.type = e1000_fc_none; + + /* Force speed/duplex on the mac */ + ctrl = E1000_READ_REG(hw, E1000_CTRL); + ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + ctrl &= ~E1000_CTRL_SPD_SEL; + + /* Disable Auto Speed Detection */ + ctrl &= ~E1000_CTRL_ASDE; + + /* Disable autoneg on the phy */ + *phy_ctrl &= ~MII_CR_AUTO_NEG_EN; + + /* Forcing Full or Half Duplex? */ + if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) { + ctrl &= ~E1000_CTRL_FD; + *phy_ctrl &= ~MII_CR_FULL_DUPLEX; + DEBUGOUT("Half Duplex\n"); + } else { + ctrl |= E1000_CTRL_FD; + *phy_ctrl |= MII_CR_FULL_DUPLEX; + DEBUGOUT("Full Duplex\n"); + } + + /* Forcing 10mb or 100mb? */ + if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) { + ctrl |= E1000_CTRL_SPD_100; + *phy_ctrl |= MII_CR_SPEED_100; + *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10); + DEBUGOUT("Forcing 100mb\n"); + } else { + ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + *phy_ctrl |= MII_CR_SPEED_10; + *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100); + DEBUGOUT("Forcing 10mb\n"); + } + + e1000_config_collision_dist_generic(hw); + + E1000_WRITE_REG(hw, E1000_CTRL, ctrl); +} + +/** + * e1000_set_d3_lplu_state_generic - Sets low power link up state for D3 + * @hw: pointer to the HW structure + * @active: boolean used to enable/disable lplu + * + * Success returns 0, Failure returns 1 + * + * The low power link up (lplu) state is set to the power management level D3 + * and SmartSpeed is disabled when active is true, else clear lplu for D3 + * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU + * is used during Dx states where the power conservation is most important. + * During driver activity, SmartSpeed should be enabled so performance is + * maintained. + **/ +s32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = E1000_SUCCESS; + u16 data; + + DEBUGFUNC("e1000_set_d3_lplu_state_generic"); + + if (!(hw->phy.ops.read_reg)) + goto out; + + ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data); + if (ret_val) + goto out; + + if (!active) { + data &= ~IGP02E1000_PM_D3_LPLU; + ret_val = phy->ops.write_reg(hw, + IGP02E1000_PHY_POWER_MGMT, + data); + if (ret_val) + goto out; + /* + * LPLU and SmartSpeed are mutually exclusive. LPLU is used + * during Dx states where the power conservation is most + * important. During driver activity we should enable + * SmartSpeed, so performance is maintained. + */ + if (phy->smart_speed == e1000_smart_speed_on) { + ret_val = phy->ops.read_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + goto out; + + data |= IGP01E1000_PSCFR_SMART_SPEED; + ret_val = phy->ops.write_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + goto out; + } else if (phy->smart_speed == e1000_smart_speed_off) { + ret_val = phy->ops.read_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + goto out; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = phy->ops.write_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + goto out; + } + } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || + (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || + (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { + data |= IGP02E1000_PM_D3_LPLU; + ret_val = phy->ops.write_reg(hw, + IGP02E1000_PHY_POWER_MGMT, + data); + if (ret_val) + goto out; + + /* When LPLU is enabled, we should disable SmartSpeed */ + ret_val = phy->ops.read_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + goto out; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = phy->ops.write_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + } + +out: + return ret_val; +} + +/** + * e1000_check_downshift_generic - Checks whether a downshift in speed occurred + * @hw: pointer to the HW structure + * + * Success returns 0, Failure returns 1 + * + * A downshift is detected by querying the PHY link health. + **/ +s32 e1000_check_downshift_generic(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, offset, mask; + + DEBUGFUNC("e1000_check_downshift_generic"); + + switch (phy->type) { + case e1000_phy_m88: + case e1000_phy_gg82563: + case e1000_phy_bm: + offset = M88E1000_PHY_SPEC_STATUS; + mask = M88E1000_PSSR_DOWNSHIFT; + break; + case e1000_phy_igp_2: + case e1000_phy_igp: + case e1000_phy_igp_3: + offset = IGP01E1000_PHY_LINK_HEALTH; + mask = IGP01E1000_PLHR_SS_DOWNGRADE; + break; + default: + /* speed downshift not supported */ + phy->speed_downgraded = false; + ret_val = E1000_SUCCESS; + goto out; + } + + ret_val = phy->ops.read_reg(hw, offset, &phy_data); + + if (!ret_val) + phy->speed_downgraded = (phy_data & mask) ? true : false; + +out: + return ret_val; +} + +/** + * e1000_check_polarity_m88 - Checks the polarity. + * @hw: pointer to the HW structure + * + * Success returns 0, Failure returns -E1000_ERR_PHY (-2) + * + * Polarity is determined based on the PHY specific status register. + **/ +s32 e1000_check_polarity_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + + DEBUGFUNC("e1000_check_polarity_m88"); + + ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &data); + + if (!ret_val) + phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + + return ret_val; +} + +/** + * e1000_check_polarity_igp - Checks the polarity. + * @hw: pointer to the HW structure + * + * Success returns 0, Failure returns -E1000_ERR_PHY (-2) + * + * Polarity is determined based on the PHY port status register, and the + * current speed (since there is no polarity at 100Mbps). + **/ +s32 e1000_check_polarity_igp(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data, offset, mask; + + DEBUGFUNC("e1000_check_polarity_igp"); + + /* + * Polarity is determined based on the speed of + * our connection. + */ + ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data); + if (ret_val) + goto out; + + if ((data & IGP01E1000_PSSR_SPEED_MASK) == + IGP01E1000_PSSR_SPEED_1000MBPS) { + offset = IGP01E1000_PHY_PCS_INIT_REG; + mask = IGP01E1000_PHY_POLARITY_MASK; + } else { + /* + * This really only applies to 10Mbps since + * there is no polarity for 100Mbps (always 0). + */ + offset = IGP01E1000_PHY_PORT_STATUS; + mask = IGP01E1000_PSSR_POLARITY_REVERSED; + } + + ret_val = phy->ops.read_reg(hw, offset, &data); + + if (!ret_val) + phy->cable_polarity = (data & mask) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + +out: + return ret_val; +} + +/** + * e1000_wait_autoneg_generic - Wait for auto-neg completion + * @hw: pointer to the HW structure + * + * Waits for auto-negotiation to complete or for the auto-negotiation time + * limit to expire, which ever happens first. + **/ +s32 e1000_wait_autoneg_generic(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 i, phy_status; + + DEBUGFUNC("e1000_wait_autoneg_generic"); + + if (!(hw->phy.ops.read_reg)) + return E1000_SUCCESS; + + /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */ + for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) { + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + if (phy_status & MII_SR_AUTONEG_COMPLETE) + break; + msec_delay(100); + } + + /* + * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation + * has completed. + */ + return ret_val; +} + +/** + * e1000_phy_has_link_generic - Polls PHY for link + * @hw: pointer to the HW structure + * @iterations: number of times to poll for link + * @usec_interval: delay between polling attempts + * @success: pointer to whether polling was successful or not + * + * Polls the PHY status register for link, 'iterations' number of times. + **/ +s32 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, + u32 usec_interval, bool *success) +{ + s32 ret_val = E1000_SUCCESS; + u16 i, phy_status; + + DEBUGFUNC("e1000_phy_has_link_generic"); + + if (!(hw->phy.ops.read_reg)) + return E1000_SUCCESS; + + for (i = 0; i < iterations; i++) { + /* + * Some PHYs require the PHY_STATUS register to be read + * twice due to the link bit being sticky. No harm doing + * it across the board. + */ + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + if (phy_status & MII_SR_LINK_STATUS) + break; + if (usec_interval >= 1000) + msec_delay_irq(usec_interval/1000); + else + usec_delay(usec_interval); + } + + *success = (i < iterations) ? true : false; + + return ret_val; +} + +/** + * e1000_get_cable_length_m88 - Determine cable length for m88 PHY + * @hw: pointer to the HW structure + * + * Reads the PHY specific status register to retrieve the cable length + * information. The cable length is determined by averaging the minimum and + * maximum values to get the "average" cable length. The m88 PHY has four + * possible cable length values, which are: + * Register Value Cable Length + * 0 < 50 meters + * 1 50 - 80 meters + * 2 80 - 110 meters + * 3 110 - 140 meters + * 4 > 140 meters + **/ +s32 e1000_get_cable_length_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, index; + + DEBUGFUNC("e1000_get_cable_length_m88"); + + ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); + if (ret_val) + goto out; + + index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> + M88E1000_PSSR_CABLE_LENGTH_SHIFT; + phy->min_cable_length = e1000_m88_cable_length_table[index]; + phy->max_cable_length = e1000_m88_cable_length_table[index+1]; + + phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; + +out: + return ret_val; +} + +/** + * e1000_get_cable_length_igp_2 - Determine cable length for igp2 PHY + * @hw: pointer to the HW structure + * + * The automatic gain control (agc) normalizes the amplitude of the + * received signal, adjusting for the attenuation produced by the + * cable. By reading the AGC registers, which represent the + * combination of coarse and fine gain value, the value can be put + * into a lookup table to obtain the approximate cable length + * for each channel. + **/ +s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = E1000_SUCCESS; + u16 phy_data, i, agc_value = 0; + u16 cur_agc_index, max_agc_index = 0; + u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1; + u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = + {IGP02E1000_PHY_AGC_A, + IGP02E1000_PHY_AGC_B, + IGP02E1000_PHY_AGC_C, + IGP02E1000_PHY_AGC_D}; + + DEBUGFUNC("e1000_get_cable_length_igp_2"); + + /* Read the AGC registers for all channels */ + for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) { + ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &phy_data); + if (ret_val) + goto out; + + /* + * Getting bits 15:9, which represent the combination of + * coarse and fine gain values. The result is a number + * that can be put into the lookup table to obtain the + * approximate cable length. + */ + cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) & + IGP02E1000_AGC_LENGTH_MASK; + + /* Array index bound check. */ + if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) || + (cur_agc_index == 0)) { + ret_val = -E1000_ERR_PHY; + goto out; + } + + /* Remove min & max AGC values from calculation. */ + if (e1000_igp_2_cable_length_table[min_agc_index] > + e1000_igp_2_cable_length_table[cur_agc_index]) + min_agc_index = cur_agc_index; + if (e1000_igp_2_cable_length_table[max_agc_index] < + e1000_igp_2_cable_length_table[cur_agc_index]) + max_agc_index = cur_agc_index; + + agc_value += e1000_igp_2_cable_length_table[cur_agc_index]; + } + + agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] + + e1000_igp_2_cable_length_table[max_agc_index]); + agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2); + + /* Calculate cable length with the error range of +/- 10 meters. */ + phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ? + (agc_value - IGP02E1000_AGC_RANGE) : 0; + phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE; + + phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; + +out: + return ret_val; +} + +/** + * e1000_get_phy_info_m88 - Retrieve PHY information + * @hw: pointer to the HW structure + * + * Valid for only copper links. Read the PHY status register (sticky read) + * to verify that link is up. Read the PHY special control register to + * determine the polarity and 10base-T extended distance. Read the PHY + * special status register to determine MDI/MDIx and current speed. If + * speed is 1000, then determine cable length, local and remote receiver. + **/ +s32 e1000_get_phy_info_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + bool link; + + DEBUGFUNC("e1000_get_phy_info_m88"); + + if (hw->phy.media_type != e1000_media_type_copper) { + DEBUGOUT("Phy info is only valid for copper media\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + goto out; + + if (!link) { + DEBUGOUT("Phy info is only valid if link is up\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + goto out; + + phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) + ? true + : false; + + ret_val = e1000_check_polarity_m88(hw); + if (ret_val) + goto out; + + ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); + if (ret_val) + goto out; + + phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false; + + if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) { + ret_val = hw->phy.ops.get_cable_length(hw); + if (ret_val) + goto out; + + ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data); + if (ret_val) + goto out; + + phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + + phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + } else { + /* Set values to "undefined" */ + phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; + phy->local_rx = e1000_1000t_rx_status_undefined; + phy->remote_rx = e1000_1000t_rx_status_undefined; + } + +out: + return ret_val; +} + +/** + * e1000_get_phy_info_igp - Retrieve igp PHY information + * @hw: pointer to the HW structure + * + * Read PHY status to determine if link is up. If link is up, then + * set/determine 10base-T extended distance and polarity correction. Read + * PHY port status to determine MDI/MDIx and speed. Based on the speed, + * determine on the cable length, local and remote receiver. + **/ +s32 e1000_get_phy_info_igp(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + bool link; + + DEBUGFUNC("e1000_get_phy_info_igp"); + + ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + goto out; + + if (!link) { + DEBUGOUT("Phy info is only valid if link is up\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + phy->polarity_correction = true; + + ret_val = e1000_check_polarity_igp(hw); + if (ret_val) + goto out; + + ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data); + if (ret_val) + goto out; + + phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false; + + if ((data & IGP01E1000_PSSR_SPEED_MASK) == + IGP01E1000_PSSR_SPEED_1000MBPS) { + ret_val = hw->phy.ops.get_cable_length(hw); + if (ret_val) + goto out; + + ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data); + if (ret_val) + goto out; + + phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + + phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + } else { + phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; + phy->local_rx = e1000_1000t_rx_status_undefined; + phy->remote_rx = e1000_1000t_rx_status_undefined; + } + +out: + return ret_val; +} + +/** + * e1000_phy_sw_reset_generic - PHY software reset + * @hw: pointer to the HW structure + * + * Does a software reset of the PHY by reading the PHY control register and + * setting/write the control register reset bit to the PHY. + **/ +s32 e1000_phy_sw_reset_generic(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 phy_ctrl; + + DEBUGFUNC("e1000_phy_sw_reset_generic"); + + if (!(hw->phy.ops.read_reg)) + goto out; + + ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_ctrl); + if (ret_val) + goto out; + + phy_ctrl |= MII_CR_RESET; + ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_ctrl); + if (ret_val) + goto out; + + usec_delay(1); + +out: + return ret_val; +} + +/** + * e1000_phy_hw_reset_generic - PHY hardware reset + * @hw: pointer to the HW structure + * + * Verify the reset block is not blocking us from resetting. Acquire + * semaphore (if necessary) and read/set/write the device control reset + * bit in the PHY. Wait the appropriate delay time for the device to + * reset and release the semaphore (if necessary). + **/ +s32 e1000_phy_hw_reset_generic(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = E1000_SUCCESS; + u32 ctrl; + + DEBUGFUNC("e1000_phy_hw_reset_generic"); + + ret_val = phy->ops.check_reset_block(hw); + if (ret_val) { + ret_val = E1000_SUCCESS; + goto out; + } + + ret_val = phy->ops.acquire(hw); + if (ret_val) + goto out; + + ctrl = E1000_READ_REG(hw, E1000_CTRL); + E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST); + E1000_WRITE_FLUSH(hw); + + usec_delay(phy->reset_delay_us); + + E1000_WRITE_REG(hw, E1000_CTRL, ctrl); + E1000_WRITE_FLUSH(hw); + + usec_delay(150); + + phy->ops.release(hw); + + ret_val = phy->ops.get_cfg_done(hw); + +out: + return ret_val; +} + +/** + * e1000_get_cfg_done_generic - Generic configuration done + * @hw: pointer to the HW structure + * + * Generic function to wait 10 milli-seconds for configuration to complete + * and return success. + **/ +s32 e1000_get_cfg_done_generic(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_get_cfg_done_generic"); + + msec_delay_irq(10); + + return E1000_SUCCESS; +} + +/** + * e1000_phy_init_script_igp3 - Inits the IGP3 PHY + * @hw: pointer to the HW structure + * + * Initializes a Intel Gigabit PHY3 when an EEPROM is not present. + **/ +s32 e1000_phy_init_script_igp3(struct e1000_hw *hw) +{ + DEBUGOUT("Running IGP 3 PHY init script\n"); + + /* PHY init IGP 3 */ + /* Enable rise/fall, 10-mode work in class-A */ + hw->phy.ops.write_reg(hw, 0x2F5B, 0x9018); + /* Remove all caps from Replica path filter */ + hw->phy.ops.write_reg(hw, 0x2F52, 0x0000); + /* Bias trimming for ADC, AFE and Driver (Default) */ + hw->phy.ops.write_reg(hw, 0x2FB1, 0x8B24); + /* Increase Hybrid poly bias */ + hw->phy.ops.write_reg(hw, 0x2FB2, 0xF8F0); + /* Add 4% to Tx amplitude in Gig mode */ + hw->phy.ops.write_reg(hw, 0x2010, 0x10B0); + /* Disable trimming (TTT) */ + hw->phy.ops.write_reg(hw, 0x2011, 0x0000); + /* Poly DC correction to 94.6% + 2% for all channels */ + hw->phy.ops.write_reg(hw, 0x20DD, 0x249A); + /* ABS DC correction to 95.9% */ + hw->phy.ops.write_reg(hw, 0x20DE, 0x00D3); + /* BG temp curve trim */ + hw->phy.ops.write_reg(hw, 0x28B4, 0x04CE); + /* Increasing ADC OPAMP stage 1 currents to max */ + hw->phy.ops.write_reg(hw, 0x2F70, 0x29E4); + /* Force 1000 ( required for enabling PHY regs configuration) */ + hw->phy.ops.write_reg(hw, 0x0000, 0x0140); + /* Set upd_freq to 6 */ + hw->phy.ops.write_reg(hw, 0x1F30, 0x1606); + /* Disable NPDFE */ + hw->phy.ops.write_reg(hw, 0x1F31, 0xB814); + /* Disable adaptive fixed FFE (Default) */ + hw->phy.ops.write_reg(hw, 0x1F35, 0x002A); + /* Enable FFE hysteresis */ + hw->phy.ops.write_reg(hw, 0x1F3E, 0x0067); + /* Fixed FFE for short cable lengths */ + hw->phy.ops.write_reg(hw, 0x1F54, 0x0065); + /* Fixed FFE for medium cable lengths */ + hw->phy.ops.write_reg(hw, 0x1F55, 0x002A); + /* Fixed FFE for long cable lengths */ + hw->phy.ops.write_reg(hw, 0x1F56, 0x002A); + /* Enable Adaptive Clip Threshold */ + hw->phy.ops.write_reg(hw, 0x1F72, 0x3FB0); + /* AHT reset limit to 1 */ + hw->phy.ops.write_reg(hw, 0x1F76, 0xC0FF); + /* Set AHT master delay to 127 msec */ + hw->phy.ops.write_reg(hw, 0x1F77, 0x1DEC); + /* Set scan bits for AHT */ + hw->phy.ops.write_reg(hw, 0x1F78, 0xF9EF); + /* Set AHT Preset bits */ + hw->phy.ops.write_reg(hw, 0x1F79, 0x0210); + /* Change integ_factor of channel A to 3 */ + hw->phy.ops.write_reg(hw, 0x1895, 0x0003); + /* Change prop_factor of channels BCD to 8 */ + hw->phy.ops.write_reg(hw, 0x1796, 0x0008); + /* Change cg_icount + enable integbp for channels BCD */ + hw->phy.ops.write_reg(hw, 0x1798, 0xD008); + /* + * Change cg_icount + enable integbp + change prop_factor_master + * to 8 for channel A + */ + hw->phy.ops.write_reg(hw, 0x1898, 0xD918); + /* Disable AHT in Slave mode on channel A */ + hw->phy.ops.write_reg(hw, 0x187A, 0x0800); + /* + * Enable LPLU and disable AN to 1000 in non-D0a states, + * Enable SPD+B2B + */ + hw->phy.ops.write_reg(hw, 0x0019, 0x008D); + /* Enable restart AN on an1000_dis change */ + hw->phy.ops.write_reg(hw, 0x001B, 0x2080); + /* Enable wh_fifo read clock in 10/100 modes */ + hw->phy.ops.write_reg(hw, 0x0014, 0x0045); + /* Restart AN, Speed selection is 1000 */ + hw->phy.ops.write_reg(hw, 0x0000, 0x1340); + + return E1000_SUCCESS; +} + +/** + * e1000_get_phy_type_from_id - Get PHY type from id + * @phy_id: phy_id read from the phy + * + * Returns the phy type from the id. + **/ +e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id) +{ + e1000_phy_type phy_type = e1000_phy_unknown; + + switch (phy_id) { + case M88E1000_I_PHY_ID: + case M88E1000_E_PHY_ID: + case M88E1111_I_PHY_ID: + case M88E1011_I_PHY_ID: + phy_type = e1000_phy_m88; + break; + case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */ + phy_type = e1000_phy_igp_2; + break; + case GG82563_E_PHY_ID: + phy_type = e1000_phy_gg82563; + break; + case IGP03E1000_E_PHY_ID: + phy_type = e1000_phy_igp_3; + break; + case IFE_E_PHY_ID: + case IFE_PLUS_E_PHY_ID: + case IFE_C_E_PHY_ID: + phy_type = e1000_phy_ife; + break; + case BME1000_E_PHY_ID: + case BME1000_E_PHY_ID_R2: + phy_type = e1000_phy_bm; + break; + default: + phy_type = e1000_phy_unknown; + break; + } + return phy_type; +} + +/** + * e1000_determine_phy_address - Determines PHY address. + * @hw: pointer to the HW structure + * + * This uses a trial and error method to loop through possible PHY + * addresses. It tests each by reading the PHY ID registers and + * checking for a match. + **/ +s32 e1000_determine_phy_address(struct e1000_hw* hw) +{ + s32 ret_val = -E1000_ERR_PHY_TYPE; + u32 phy_addr= 0; + u32 i; + e1000_phy_type phy_type = e1000_phy_unknown; + + for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) { + hw->phy.addr = phy_addr; + i = 0; + + do { + e1000_get_phy_id(hw); + phy_type = e1000_get_phy_type_from_id(hw->phy.id); + + /* + * If phy_type is valid, break - we found our + * PHY address + */ + if (phy_type != e1000_phy_unknown) { + ret_val = E1000_SUCCESS; + goto out; + } + msec_delay(1); + i++; + } while (i < 10); + } + +out: + return ret_val; +} + +/** + * e1000_get_phy_addr_for_bm_page - Retrieve PHY page address + * @page: page to access + * + * Returns the phy address for the page requested. + **/ +static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg) +{ + u32 phy_addr = 2; + + if ((page >= 768) || (page == 0 && reg == 25) || (reg == 31)) + phy_addr = 1; + + return phy_addr; +} + +/** + * e1000_write_phy_reg_bm - Write BM PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore, if necessary, then writes the data to PHY register + * at the offset. Release any acquired semaphores before exiting. + **/ +s32 e1000_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data) +{ + s32 ret_val; + u32 page_select = 0; + u32 page = offset >> IGP_PAGE_SHIFT; + u32 page_shift = 0; + + DEBUGFUNC("e1000_write_phy_reg_bm"); + + /* Page 800 works differently than the rest so it has its own func */ + if (page == BM_WUC_PAGE) { + ret_val = e1000_access_phy_wakeup_reg_bm(hw, + offset, &data, false); + goto out; + } + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset); + + if (offset > MAX_PHY_MULTI_PAGE_REG) { + /* + * Page select is register 31 for phy address 1 and 22 for + * phy address 2 and 3. Page select is shifted only for + * phy address 1. + */ + if (hw->phy.addr == 1) { + page_shift = IGP_PAGE_SHIFT; + page_select = IGP01E1000_PHY_PAGE_SELECT; + } else { + page_shift = 0; + page_select = BM_PHY_PAGE_SELECT; + } + + /* Page is shifted left, PHY expects (page x 32) */ + ret_val = e1000_write_phy_reg_mdic(hw, page_select, + (page << page_shift)); + if (ret_val) { + hw->phy.ops.release(hw); + goto out; + } + } + + ret_val = e1000_write_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + hw->phy.ops.release(hw); + +out: + return ret_val; +} + +/** + * e1000_read_phy_reg_bm - Read BM PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore, if necessary, then reads the PHY register at offset + * and storing the retrieved information in data. Release any acquired + * semaphores before exiting. + **/ +s32 e1000_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data) +{ + s32 ret_val; + u32 page_select = 0; + u32 page = offset >> IGP_PAGE_SHIFT; + u32 page_shift = 0; + + DEBUGFUNC("e1000_read_phy_reg_bm"); + + /* Page 800 works differently than the rest so it has its own func */ + if (page == BM_WUC_PAGE) { + ret_val = e1000_access_phy_wakeup_reg_bm(hw, + offset, data, true); + goto out; + } + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset); + + if (offset > MAX_PHY_MULTI_PAGE_REG) { + /* + * Page select is register 31 for phy address 1 and 22 for + * phy address 2 and 3. Page select is shifted only for + * phy address 1. + */ + if (hw->phy.addr == 1) { + page_shift = IGP_PAGE_SHIFT; + page_select = IGP01E1000_PHY_PAGE_SELECT; + } else { + page_shift = 0; + page_select = BM_PHY_PAGE_SELECT; + } + + /* Page is shifted left, PHY expects (page x 32) */ + ret_val = e1000_write_phy_reg_mdic(hw, page_select, + (page << page_shift)); + if (ret_val) { + hw->phy.ops.release(hw); + goto out; + } + } + + ret_val = e1000_read_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + hw->phy.ops.release(hw); + +out: + return ret_val; +} + +/** + * e1000_read_phy_reg_bm2 - Read BM PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore, if necessary, then reads the PHY register at offset + * and storing the retrieved information in data. Release any acquired + * semaphores before exiting. + **/ +s32 e1000_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data) +{ + s32 ret_val; + u16 page = (u16)(offset >> IGP_PAGE_SHIFT); + + DEBUGFUNC("e1000_write_phy_reg_bm2"); + + /* Page 800 works differently than the rest so it has its own func */ + if (page == BM_WUC_PAGE) { + ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data, + true); + goto out; + } + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + hw->phy.addr = 1; + + if (offset > MAX_PHY_MULTI_PAGE_REG) { + + /* Page is shifted left, PHY expects (page x 32) */ + ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT, + page); + + if (ret_val) { + hw->phy.ops.release(hw); + goto out; + } + } + + ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, + data); + hw->phy.ops.release(hw); + +out: + return ret_val; +} + +/** + * e1000_write_phy_reg_bm2 - Write BM PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore, if necessary, then writes the data to PHY register + * at the offset. Release any acquired semaphores before exiting. + **/ +s32 e1000_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data) +{ + s32 ret_val; + u16 page = (u16)(offset >> IGP_PAGE_SHIFT); + + DEBUGFUNC("e1000_write_phy_reg_bm2"); + + /* Page 800 works differently than the rest so it has its own func */ + if (page == BM_WUC_PAGE) { + ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data, + false); + goto out; + } + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + hw->phy.addr = 1; + + if (offset > MAX_PHY_MULTI_PAGE_REG) { + /* Page is shifted left, PHY expects (page x 32) */ + ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT, + page); + + if (ret_val) { + hw->phy.ops.release(hw); + goto out; + } + } + + ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, + data); + + hw->phy.ops.release(hw); + +out: + return ret_val; +} + +/** + * e1000_access_phy_wakeup_reg_bm - Read BM PHY wakeup register + * @hw: pointer to the HW structure + * @offset: register offset to be read or written + * @data: pointer to the data to read or write + * @read: determines if operation is read or write + * + * Acquires semaphore, if necessary, then reads the PHY register at offset + * and storing the retrieved information in data. Release any acquired + * semaphores before exiting. Note that procedure to read the wakeup + * registers are different. It works as such: + * 1) Set page 769, register 17, bit 2 = 1 + * 2) Set page to 800 for host (801 if we were manageability) + * 3) Write the address using the address opcode (0x11) + * 4) Read or write the data using the data opcode (0x12) + * 5) Restore 769_17.2 to its original value + **/ +s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, + u32 offset, u16 *data, bool read) +{ + s32 ret_val; + u16 reg = ((u16)offset); + u16 phy_reg = 0; + u8 phy_acquired = 1; + + DEBUGFUNC("e1000_read_phy_wakeup_reg_bm"); + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) { + DEBUGOUT("Could not acquire PHY\n"); + phy_acquired = 0; + goto out; + } + + /* All operations in this function are phy address 1 */ + hw->phy.addr = 1; + + /* Set page 769 */ + e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, + (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT)); + + ret_val = e1000_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg); + if (ret_val) { + DEBUGOUT("Could not read PHY page 769\n"); + goto out; + } + + /* First clear bit 4 to avoid a power state change */ + phy_reg &= ~(BM_WUC_HOST_WU_BIT); + ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg); + if (ret_val) { + DEBUGOUT("Could not clear PHY page 769 bit 4\n"); + goto out; + } + + /* Write bit 2 = 1, and clear bit 4 to 769_17 */ + ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, + phy_reg | BM_WUC_ENABLE_BIT); + if (ret_val) { + DEBUGOUT("Could not write PHY page 769 bit 2\n"); + goto out; + } + + /* Select page 800 */ + ret_val = e1000_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (BM_WUC_PAGE << IGP_PAGE_SHIFT)); + + /* Write the page 800 offset value using opcode 0x11 */ + ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ADDRESS_OPCODE, reg); + if (ret_val) { + DEBUGOUT("Could not write address opcode to page 800\n"); + goto out; + } + + if (read) { + /* Read the page 800 value using opcode 0x12 */ + ret_val = e1000_read_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE, + data); + } else { + /* Read the page 800 value using opcode 0x12 */ + ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE, + *data); + } + + if (ret_val) { + DEBUGOUT("Could not read data value from page 800\n"); + goto out; + } + + /* + * Restore 769_17.2 to its original value + * Set page 769 + */ + e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, + (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT)); + + /* Clear 769_17.2 */ + ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg); + if (ret_val) { + DEBUGOUT("Could not clear PHY page 769 bit 2\n"); + goto out; + } + +out: + if (phy_acquired == 1) + hw->phy.ops.release(hw); + return ret_val; +} + +/** + * e1000_power_up_phy_copper - Restore copper link in case of PHY power down + * @hw: pointer to the HW structure + * + * In the case of a PHY power down to save power, or to turn off link during a + * driver unload, or wake on lan is not enabled, restore the link to previous + * settings. + **/ +void e1000_power_up_phy_copper(struct e1000_hw *hw) +{ + u16 mii_reg = 0; + + /* The PHY will retain its settings across a power down/up cycle */ + hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); + mii_reg &= ~MII_CR_POWER_DOWN; + hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); +} + +/** + * e1000_power_down_phy_copper - Restore copper link in case of PHY power down + * @hw: pointer to the HW structure + * + * In the case of a PHY power down to save power, or to turn off link during a + * driver unload, or wake on lan is not enabled, restore the link to previous + * settings. + **/ +void e1000_power_down_phy_copper(struct e1000_hw *hw) +{ + u16 mii_reg = 0; + + /* The PHY will retain its settings across a power down/up cycle */ + hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); + mii_reg |= MII_CR_POWER_DOWN; + hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); + msec_delay(1); +} --- linux-2.6.27.orig/ubuntu/e1000e/e1000_ich8lan.h +++ linux-2.6.27/ubuntu/e1000e/e1000_ich8lan.h @@ -0,0 +1,128 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_ICH8LAN_H_ +#define _E1000_ICH8LAN_H_ + +#define ICH_FLASH_GFPREG 0x0000 +#define ICH_FLASH_HSFSTS 0x0004 +#define ICH_FLASH_HSFCTL 0x0006 +#define ICH_FLASH_FADDR 0x0008 +#define ICH_FLASH_FDATA0 0x0010 + +#define ICH_FLASH_READ_COMMAND_TIMEOUT 500 +#define ICH_FLASH_WRITE_COMMAND_TIMEOUT 500 +#define ICH_FLASH_ERASE_COMMAND_TIMEOUT 3000000 +#define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF +#define ICH_FLASH_CYCLE_REPEAT_COUNT 10 + +#define ICH_CYCLE_READ 0 +#define ICH_CYCLE_WRITE 2 +#define ICH_CYCLE_ERASE 3 + +#define FLASH_GFPREG_BASE_MASK 0x1FFF +#define FLASH_SECTOR_ADDR_SHIFT 12 + +#define E1000_SHADOW_RAM_WORDS 2048 + +#define ICH_FLASH_SEG_SIZE_256 256 +#define ICH_FLASH_SEG_SIZE_4K 4096 +#define ICH_FLASH_SEG_SIZE_8K 8192 +#define ICH_FLASH_SEG_SIZE_64K 65536 +#define ICH_FLASH_SECTOR_SIZE 4096 + +#define ICH_FLASH_REG_MAPSIZE 0x00A0 + +#define E1000_ICH_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI Reset */ +#define E1000_ICH_FWSM_DISSW 0x10000000 /* FW Disables SW Writes */ +/* FW established a valid mode */ +#define E1000_ICH_FWSM_FW_VALID 0x00008000 + +#define E1000_ICH_MNG_IAMT_MODE 0x2 + +#define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \ + (ID_LED_DEF1_OFF2 << 8) | \ + (ID_LED_DEF1_ON2 << 4) | \ + (ID_LED_DEF1_DEF2)) + +#define E1000_ICH_NVM_SIG_WORD 0x13 +#define E1000_ICH_NVM_SIG_MASK 0xC000 + +#define E1000_ICH8_LAN_INIT_TIMEOUT 1500 + +#define E1000_FEXTNVM_SW_CONFIG 1 +#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M */ + +#define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL + +#define E1000_ICH_RAR_ENTRIES 7 + +#define PHY_PAGE_SHIFT 5 +#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \ + ((reg) & MAX_PHY_REG_ADDRESS)) +#define IGP3_KMRN_DIAG PHY_REG(770, 19) /* KMRN Diagnostic */ +#define IGP3_VR_CTRL PHY_REG(776, 18) /* Voltage Regulator Control */ +#define IGP3_CAPABILITY PHY_REG(776, 19) /* Capability */ +#define IGP3_PM_CTRL PHY_REG(769, 20) /* Power Management Control */ + +#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS 0x0002 +#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300 +#define IGP3_VR_CTRL_MODE_SHUTDOWN 0x0200 +#define IGP3_PM_CTRL_FORCE_PWR_DOWN 0x0020 + +/* + * Additional interrupts need to be handled for ICH family: + * DSW = The FW changed the status of the DISSW bit in FWSM + * PHYINT = The LAN connected device generates an interrupt + * EPRST = Manageability reset event + */ +#define IMS_ICH_ENABLE_MASK (\ + E1000_IMS_DSW | \ + E1000_IMS_PHYINT | \ + E1000_IMS_EPRST) + +/* Additional interrupt register bit definitions */ +#define E1000_ICR_LSECPNC 0x00004000 /* PN threshold - client */ +#define E1000_IMS_LSECPNC E1000_ICR_LSECPNC /* PN threshold - client */ +#define E1000_ICS_LSECPNC E1000_ICR_LSECPNC /* PN threshold - client */ + +/* Security Processing bit Indication */ +#define E1000_RXDEXT_LINKSEC_STATUS_LSECH 0x01000000 +#define E1000_RXDEXT_LINKSEC_ERROR_BIT_MASK 0x60000000 +#define E1000_RXDEXT_LINKSEC_ERROR_NO_SA_MATCH 0x20000000 +#define E1000_RXDEXT_LINKSEC_ERROR_REPLAY_ERROR 0x40000000 +#define E1000_RXDEXT_LINKSEC_ERROR_BAD_SIG 0x60000000 + + +void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, + bool state); +void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); +void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw); +void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw); + +#endif --- linux-2.6.27.orig/ubuntu/e1000e/kcompat_ethtool.c +++ linux-2.6.27/ubuntu/e1000e/kcompat_ethtool.c @@ -0,0 +1,1169 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* + * net/core/ethtool.c - Ethtool ioctl handler + * Copyright (c) 2003 Matthew Wilcox + * + * This file is where we call all the ethtool_ops commands to get + * the information ethtool needs. We fall back to calling do_ioctl() + * for drivers which haven't been converted to ethtool_ops yet. + * + * It's GPL, stupid. + * + * Modification by sfeldma@pobox.com to work as backward compat + * solution for pre-ethtool_ops kernels. + * - copied struct ethtool_ops from ethtool.h + * - defined SET_ETHTOOL_OPS + * - put in some #ifndef NETIF_F_xxx wrappers + * - changes refs to dev->ethtool_ops to ethtool_ops + * - changed dev_ethtool to ethtool_ioctl + * - remove EXPORT_SYMBOL()s + * - added _kc_ prefix in built-in ethtool_op_xxx ops. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "kcompat.h" + +#undef SUPPORTED_10000baseT_Full +#define SUPPORTED_10000baseT_Full (1 << 12) +#undef ADVERTISED_10000baseT_Full +#define ADVERTISED_10000baseT_Full (1 << 12) +#undef SPEED_10000 +#define SPEED_10000 10000 + +#undef ethtool_ops +#define ethtool_ops _kc_ethtool_ops + +struct _kc_ethtool_ops { + int (*get_settings)(struct net_device *, struct ethtool_cmd *); + int (*set_settings)(struct net_device *, struct ethtool_cmd *); + void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *); + int (*get_regs_len)(struct net_device *); + void (*get_regs)(struct net_device *, struct ethtool_regs *, void *); + void (*get_wol)(struct net_device *, struct ethtool_wolinfo *); + int (*set_wol)(struct net_device *, struct ethtool_wolinfo *); + u32 (*get_msglevel)(struct net_device *); + void (*set_msglevel)(struct net_device *, u32); + int (*nway_reset)(struct net_device *); + u32 (*get_link)(struct net_device *); + int (*get_eeprom_len)(struct net_device *); + int (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); + int (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); + int (*get_coalesce)(struct net_device *, struct ethtool_coalesce *); + int (*set_coalesce)(struct net_device *, struct ethtool_coalesce *); + void (*get_ringparam)(struct net_device *, struct ethtool_ringparam *); + int (*set_ringparam)(struct net_device *, struct ethtool_ringparam *); + void (*get_pauseparam)(struct net_device *, + struct ethtool_pauseparam*); + int (*set_pauseparam)(struct net_device *, + struct ethtool_pauseparam*); + u32 (*get_rx_csum)(struct net_device *); + int (*set_rx_csum)(struct net_device *, u32); + u32 (*get_tx_csum)(struct net_device *); + int (*set_tx_csum)(struct net_device *, u32); + u32 (*get_sg)(struct net_device *); + int (*set_sg)(struct net_device *, u32); + u32 (*get_tso)(struct net_device *); + int (*set_tso)(struct net_device *, u32); + int (*self_test_count)(struct net_device *); + void (*self_test)(struct net_device *, struct ethtool_test *, u64 *); + void (*get_strings)(struct net_device *, u32 stringset, u8 *); + int (*phys_id)(struct net_device *, u32); + int (*get_stats_count)(struct net_device *); + void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, + u64 *); +} *ethtool_ops = NULL; + +#undef SET_ETHTOOL_OPS +#define SET_ETHTOOL_OPS(netdev, ops) (ethtool_ops = (ops)) + +/* + * Some useful ethtool_ops methods that are device independent. If we find that + * all drivers want to do the same thing here, we can turn these into dev_() + * function calls. + */ + +#undef ethtool_op_get_link +#define ethtool_op_get_link _kc_ethtool_op_get_link +u32 _kc_ethtool_op_get_link(struct net_device *dev) +{ + return netif_carrier_ok(dev) ? 1 : 0; +} + +#undef ethtool_op_get_tx_csum +#define ethtool_op_get_tx_csum _kc_ethtool_op_get_tx_csum +u32 _kc_ethtool_op_get_tx_csum(struct net_device *dev) +{ +#ifdef NETIF_F_IP_CSUM + return (dev->features & NETIF_F_IP_CSUM) != 0; +#else + return 0; +#endif +} + +#undef ethtool_op_set_tx_csum +#define ethtool_op_set_tx_csum _kc_ethtool_op_set_tx_csum +int _kc_ethtool_op_set_tx_csum(struct net_device *dev, u32 data) +{ +#ifdef NETIF_F_IP_CSUM + if (data) +#ifdef NETIF_F_IPV6_CSUM + dev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); + else + dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); +#else + dev->features |= NETIF_F_IP_CSUM; + else + dev->features &= ~NETIF_F_IP_CSUM; +#endif +#endif + + return 0; +} + +#undef ethtool_op_get_sg +#define ethtool_op_get_sg _kc_ethtool_op_get_sg +u32 _kc_ethtool_op_get_sg(struct net_device *dev) +{ +#ifdef NETIF_F_SG + return (dev->features & NETIF_F_SG) != 0; +#else + return 0; +#endif +} + +#undef ethtool_op_set_sg +#define ethtool_op_set_sg _kc_ethtool_op_set_sg +int _kc_ethtool_op_set_sg(struct net_device *dev, u32 data) +{ +#ifdef NETIF_F_SG + if (data) + dev->features |= NETIF_F_SG; + else + dev->features &= ~NETIF_F_SG; +#endif + + return 0; +} + +#undef ethtool_op_get_tso +#define ethtool_op_get_tso _kc_ethtool_op_get_tso +u32 _kc_ethtool_op_get_tso(struct net_device *dev) +{ +#ifdef NETIF_F_TSO + return (dev->features & NETIF_F_TSO) != 0; +#else + return 0; +#endif +} + +#undef ethtool_op_set_tso +#define ethtool_op_set_tso _kc_ethtool_op_set_tso +int _kc_ethtool_op_set_tso(struct net_device *dev, u32 data) +{ +#ifdef NETIF_F_TSO + if (data) + dev->features |= NETIF_F_TSO; + else + dev->features &= ~NETIF_F_TSO; +#endif + + return 0; +} + +/* Handlers for each ethtool command */ + +static int ethtool_get_settings(struct net_device *dev, void *useraddr) +{ + struct ethtool_cmd cmd = { ETHTOOL_GSET }; + int err; + + if (!ethtool_ops->get_settings) + return -EOPNOTSUPP; + + err = ethtool_ops->get_settings(dev, &cmd); + if (err < 0) + return err; + + if (copy_to_user(useraddr, &cmd, sizeof(cmd))) + return -EFAULT; + return 0; +} + +static int ethtool_set_settings(struct net_device *dev, void *useraddr) +{ + struct ethtool_cmd cmd; + + if (!ethtool_ops->set_settings) + return -EOPNOTSUPP; + + if (copy_from_user(&cmd, useraddr, sizeof(cmd))) + return -EFAULT; + + return ethtool_ops->set_settings(dev, &cmd); +} + +static int ethtool_get_drvinfo(struct net_device *dev, void *useraddr) +{ + struct ethtool_drvinfo info; + struct ethtool_ops *ops = ethtool_ops; + + if (!ops->get_drvinfo) + return -EOPNOTSUPP; + + memset(&info, 0, sizeof(info)); + info.cmd = ETHTOOL_GDRVINFO; + ops->get_drvinfo(dev, &info); + + if (ops->self_test_count) + info.testinfo_len = ops->self_test_count(dev); + if (ops->get_stats_count) + info.n_stats = ops->get_stats_count(dev); + if (ops->get_regs_len) + info.regdump_len = ops->get_regs_len(dev); + if (ops->get_eeprom_len) + info.eedump_len = ops->get_eeprom_len(dev); + + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; +} + +static int ethtool_get_regs(struct net_device *dev, char *useraddr) +{ + struct ethtool_regs regs; + struct ethtool_ops *ops = ethtool_ops; + void *regbuf; + int reglen, ret; + + if (!ops->get_regs || !ops->get_regs_len) + return -EOPNOTSUPP; + + if (copy_from_user(®s, useraddr, sizeof(regs))) + return -EFAULT; + + reglen = ops->get_regs_len(dev); + if (regs.len > reglen) + regs.len = reglen; + + regbuf = kmalloc(reglen, GFP_USER); + if (!regbuf) + return -ENOMEM; + + ops->get_regs(dev, ®s, regbuf); + + ret = -EFAULT; + if (copy_to_user(useraddr, ®s, sizeof(regs))) + goto out; + useraddr += offsetof(struct ethtool_regs, data); + if (copy_to_user(useraddr, regbuf, reglen)) + goto out; + ret = 0; + +out: + kfree(regbuf); + return ret; +} + +static int ethtool_get_wol(struct net_device *dev, char *useraddr) +{ + struct ethtool_wolinfo wol = { ETHTOOL_GWOL }; + + if (!ethtool_ops->get_wol) + return -EOPNOTSUPP; + + ethtool_ops->get_wol(dev, &wol); + + if (copy_to_user(useraddr, &wol, sizeof(wol))) + return -EFAULT; + return 0; +} + +static int ethtool_set_wol(struct net_device *dev, char *useraddr) +{ + struct ethtool_wolinfo wol; + + if (!ethtool_ops->set_wol) + return -EOPNOTSUPP; + + if (copy_from_user(&wol, useraddr, sizeof(wol))) + return -EFAULT; + + return ethtool_ops->set_wol(dev, &wol); +} + +static int ethtool_get_msglevel(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata = { ETHTOOL_GMSGLVL }; + + if (!ethtool_ops->get_msglevel) + return -EOPNOTSUPP; + + edata.data = ethtool_ops->get_msglevel(dev); + + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; +} + +static int ethtool_set_msglevel(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata; + + if (!ethtool_ops->set_msglevel) + return -EOPNOTSUPP; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + ethtool_ops->set_msglevel(dev, edata.data); + return 0; +} + +static int ethtool_nway_reset(struct net_device *dev) +{ + if (!ethtool_ops->nway_reset) + return -EOPNOTSUPP; + + return ethtool_ops->nway_reset(dev); +} + +static int ethtool_get_link(struct net_device *dev, void *useraddr) +{ + struct ethtool_value edata = { ETHTOOL_GLINK }; + + if (!ethtool_ops->get_link) + return -EOPNOTSUPP; + + edata.data = ethtool_ops->get_link(dev); + + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; +} + +static int ethtool_get_eeprom(struct net_device *dev, void *useraddr) +{ + struct ethtool_eeprom eeprom; + struct ethtool_ops *ops = ethtool_ops; + u8 *data; + int ret; + + if (!ops->get_eeprom || !ops->get_eeprom_len) + return -EOPNOTSUPP; + + if (copy_from_user(&eeprom, useraddr, sizeof(eeprom))) + return -EFAULT; + + /* Check for wrap and zero */ + if (eeprom.offset + eeprom.len <= eeprom.offset) + return -EINVAL; + + /* Check for exceeding total eeprom len */ + if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev)) + return -EINVAL; + + data = kmalloc(eeprom.len, GFP_USER); + if (!data) + return -ENOMEM; + + ret = -EFAULT; + if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len)) + goto out; + + ret = ops->get_eeprom(dev, &eeprom, data); + if (ret) + goto out; + + ret = -EFAULT; + if (copy_to_user(useraddr, &eeprom, sizeof(eeprom))) + goto out; + if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len)) + goto out; + ret = 0; + +out: + kfree(data); + return ret; +} + +static int ethtool_set_eeprom(struct net_device *dev, void *useraddr) +{ + struct ethtool_eeprom eeprom; + struct ethtool_ops *ops = ethtool_ops; + u8 *data; + int ret; + + if (!ops->set_eeprom || !ops->get_eeprom_len) + return -EOPNOTSUPP; + + if (copy_from_user(&eeprom, useraddr, sizeof(eeprom))) + return -EFAULT; + + /* Check for wrap and zero */ + if (eeprom.offset + eeprom.len <= eeprom.offset) + return -EINVAL; + + /* Check for exceeding total eeprom len */ + if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev)) + return -EINVAL; + + data = kmalloc(eeprom.len, GFP_USER); + if (!data) + return -ENOMEM; + + ret = -EFAULT; + if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len)) + goto out; + + ret = ops->set_eeprom(dev, &eeprom, data); + if (ret) + goto out; + + if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len)) + ret = -EFAULT; + +out: + kfree(data); + return ret; +} + +static int ethtool_get_coalesce(struct net_device *dev, void *useraddr) +{ + struct ethtool_coalesce coalesce = { ETHTOOL_GCOALESCE }; + + if (!ethtool_ops->get_coalesce) + return -EOPNOTSUPP; + + ethtool_ops->get_coalesce(dev, &coalesce); + + if (copy_to_user(useraddr, &coalesce, sizeof(coalesce))) + return -EFAULT; + return 0; +} + +static int ethtool_set_coalesce(struct net_device *dev, void *useraddr) +{ + struct ethtool_coalesce coalesce; + + if (!ethtool_ops->get_coalesce) + return -EOPNOTSUPP; + + if (copy_from_user(&coalesce, useraddr, sizeof(coalesce))) + return -EFAULT; + + return ethtool_ops->set_coalesce(dev, &coalesce); +} + +static int ethtool_get_ringparam(struct net_device *dev, void *useraddr) +{ + struct ethtool_ringparam ringparam = { ETHTOOL_GRINGPARAM }; + + if (!ethtool_ops->get_ringparam) + return -EOPNOTSUPP; + + ethtool_ops->get_ringparam(dev, &ringparam); + + if (copy_to_user(useraddr, &ringparam, sizeof(ringparam))) + return -EFAULT; + return 0; +} + +static int ethtool_set_ringparam(struct net_device *dev, void *useraddr) +{ + struct ethtool_ringparam ringparam; + + if (!ethtool_ops->get_ringparam) + return -EOPNOTSUPP; + + if (copy_from_user(&ringparam, useraddr, sizeof(ringparam))) + return -EFAULT; + + return ethtool_ops->set_ringparam(dev, &ringparam); +} + +static int ethtool_get_pauseparam(struct net_device *dev, void *useraddr) +{ + struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM }; + + if (!ethtool_ops->get_pauseparam) + return -EOPNOTSUPP; + + ethtool_ops->get_pauseparam(dev, &pauseparam); + + if (copy_to_user(useraddr, &pauseparam, sizeof(pauseparam))) + return -EFAULT; + return 0; +} + +static int ethtool_set_pauseparam(struct net_device *dev, void *useraddr) +{ + struct ethtool_pauseparam pauseparam; + + if (!ethtool_ops->get_pauseparam) + return -EOPNOTSUPP; + + if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam))) + return -EFAULT; + + return ethtool_ops->set_pauseparam(dev, &pauseparam); +} + +static int ethtool_get_rx_csum(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata = { ETHTOOL_GRXCSUM }; + + if (!ethtool_ops->get_rx_csum) + return -EOPNOTSUPP; + + edata.data = ethtool_ops->get_rx_csum(dev); + + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; +} + +static int ethtool_set_rx_csum(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata; + + if (!ethtool_ops->set_rx_csum) + return -EOPNOTSUPP; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + ethtool_ops->set_rx_csum(dev, edata.data); + return 0; +} + +static int ethtool_get_tx_csum(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata = { ETHTOOL_GTXCSUM }; + + if (!ethtool_ops->get_tx_csum) + return -EOPNOTSUPP; + + edata.data = ethtool_ops->get_tx_csum(dev); + + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; +} + +static int ethtool_set_tx_csum(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata; + + if (!ethtool_ops->set_tx_csum) + return -EOPNOTSUPP; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + return ethtool_ops->set_tx_csum(dev, edata.data); +} + +static int ethtool_get_sg(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata = { ETHTOOL_GSG }; + + if (!ethtool_ops->get_sg) + return -EOPNOTSUPP; + + edata.data = ethtool_ops->get_sg(dev); + + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; +} + +static int ethtool_set_sg(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata; + + if (!ethtool_ops->set_sg) + return -EOPNOTSUPP; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + return ethtool_ops->set_sg(dev, edata.data); +} + +static int ethtool_get_tso(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata = { ETHTOOL_GTSO }; + + if (!ethtool_ops->get_tso) + return -EOPNOTSUPP; + + edata.data = ethtool_ops->get_tso(dev); + + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; +} + +static int ethtool_set_tso(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata; + + if (!ethtool_ops->set_tso) + return -EOPNOTSUPP; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + return ethtool_ops->set_tso(dev, edata.data); +} + +static int ethtool_self_test(struct net_device *dev, char *useraddr) +{ + struct ethtool_test test; + struct ethtool_ops *ops = ethtool_ops; + u64 *data; + int ret; + + if (!ops->self_test || !ops->self_test_count) + return -EOPNOTSUPP; + + if (copy_from_user(&test, useraddr, sizeof(test))) + return -EFAULT; + + test.len = ops->self_test_count(dev); + data = kmalloc(test.len * sizeof(u64), GFP_USER); + if (!data) + return -ENOMEM; + + ops->self_test(dev, &test, data); + + ret = -EFAULT; + if (copy_to_user(useraddr, &test, sizeof(test))) + goto out; + useraddr += sizeof(test); + if (copy_to_user(useraddr, data, test.len * sizeof(u64))) + goto out; + ret = 0; + +out: + kfree(data); + return ret; +} + +static int ethtool_get_strings(struct net_device *dev, void *useraddr) +{ + struct ethtool_gstrings gstrings; + struct ethtool_ops *ops = ethtool_ops; + u8 *data; + int ret; + + if (!ops->get_strings) + return -EOPNOTSUPP; + + if (copy_from_user(&gstrings, useraddr, sizeof(gstrings))) + return -EFAULT; + + switch (gstrings.string_set) { + case ETH_SS_TEST: + if (!ops->self_test_count) + return -EOPNOTSUPP; + gstrings.len = ops->self_test_count(dev); + break; + case ETH_SS_STATS: + if (!ops->get_stats_count) + return -EOPNOTSUPP; + gstrings.len = ops->get_stats_count(dev); + break; + default: + return -EINVAL; + } + + data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER); + if (!data) + return -ENOMEM; + + ops->get_strings(dev, gstrings.string_set, data); + + ret = -EFAULT; + if (copy_to_user(useraddr, &gstrings, sizeof(gstrings))) + goto out; + useraddr += sizeof(gstrings); + if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN)) + goto out; + ret = 0; + +out: + kfree(data); + return ret; +} + +static int ethtool_phys_id(struct net_device *dev, void *useraddr) +{ + struct ethtool_value id; + + if (!ethtool_ops->phys_id) + return -EOPNOTSUPP; + + if (copy_from_user(&id, useraddr, sizeof(id))) + return -EFAULT; + + return ethtool_ops->phys_id(dev, id.data); +} + +static int ethtool_get_stats(struct net_device *dev, void *useraddr) +{ + struct ethtool_stats stats; + struct ethtool_ops *ops = ethtool_ops; + u64 *data; + int ret; + + if (!ops->get_ethtool_stats || !ops->get_stats_count) + return -EOPNOTSUPP; + + if (copy_from_user(&stats, useraddr, sizeof(stats))) + return -EFAULT; + + stats.n_stats = ops->get_stats_count(dev); + data = kmalloc(stats.n_stats * sizeof(u64), GFP_USER); + if (!data) + return -ENOMEM; + + ops->get_ethtool_stats(dev, &stats, data); + + ret = -EFAULT; + if (copy_to_user(useraddr, &stats, sizeof(stats))) + goto out; + useraddr += sizeof(stats); + if (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64))) + goto out; + ret = 0; + +out: + kfree(data); + return ret; +} + +/* The main entry point in this file. Called from net/core/dev.c */ + +#define ETHTOOL_OPS_COMPAT +int ethtool_ioctl(struct ifreq *ifr) +{ + struct net_device *dev = __dev_get_by_name(ifr->ifr_name); + void *useraddr = (void *) ifr->ifr_data; + u32 ethcmd; + + /* + * XXX: This can be pushed down into the ethtool_* handlers that + * need it. Keep existing behavior for the moment. + */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (!dev || !netif_device_present(dev)) + return -ENODEV; + + if (copy_from_user(ðcmd, useraddr, sizeof (ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GSET: + return ethtool_get_settings(dev, useraddr); + case ETHTOOL_SSET: + return ethtool_set_settings(dev, useraddr); + case ETHTOOL_GDRVINFO: + return ethtool_get_drvinfo(dev, useraddr); + case ETHTOOL_GREGS: + return ethtool_get_regs(dev, useraddr); + case ETHTOOL_GWOL: + return ethtool_get_wol(dev, useraddr); + case ETHTOOL_SWOL: + return ethtool_set_wol(dev, useraddr); + case ETHTOOL_GMSGLVL: + return ethtool_get_msglevel(dev, useraddr); + case ETHTOOL_SMSGLVL: + return ethtool_set_msglevel(dev, useraddr); + case ETHTOOL_NWAY_RST: + return ethtool_nway_reset(dev); + case ETHTOOL_GLINK: + return ethtool_get_link(dev, useraddr); + case ETHTOOL_GEEPROM: + return ethtool_get_eeprom(dev, useraddr); + case ETHTOOL_SEEPROM: + return ethtool_set_eeprom(dev, useraddr); + case ETHTOOL_GCOALESCE: + return ethtool_get_coalesce(dev, useraddr); + case ETHTOOL_SCOALESCE: + return ethtool_set_coalesce(dev, useraddr); + case ETHTOOL_GRINGPARAM: + return ethtool_get_ringparam(dev, useraddr); + case ETHTOOL_SRINGPARAM: + return ethtool_set_ringparam(dev, useraddr); + case ETHTOOL_GPAUSEPARAM: + return ethtool_get_pauseparam(dev, useraddr); + case ETHTOOL_SPAUSEPARAM: + return ethtool_set_pauseparam(dev, useraddr); + case ETHTOOL_GRXCSUM: + return ethtool_get_rx_csum(dev, useraddr); + case ETHTOOL_SRXCSUM: + return ethtool_set_rx_csum(dev, useraddr); + case ETHTOOL_GTXCSUM: + return ethtool_get_tx_csum(dev, useraddr); + case ETHTOOL_STXCSUM: + return ethtool_set_tx_csum(dev, useraddr); + case ETHTOOL_GSG: + return ethtool_get_sg(dev, useraddr); + case ETHTOOL_SSG: + return ethtool_set_sg(dev, useraddr); + case ETHTOOL_GTSO: + return ethtool_get_tso(dev, useraddr); + case ETHTOOL_STSO: + return ethtool_set_tso(dev, useraddr); + case ETHTOOL_TEST: + return ethtool_self_test(dev, useraddr); + case ETHTOOL_GSTRINGS: + return ethtool_get_strings(dev, useraddr); + case ETHTOOL_PHYS_ID: + return ethtool_phys_id(dev, useraddr); + case ETHTOOL_GSTATS: + return ethtool_get_stats(dev, useraddr); + default: + return -EOPNOTSUPP; + } + + return -EOPNOTSUPP; +} + +#define mii_if_info _kc_mii_if_info +struct _kc_mii_if_info { + int phy_id; + int advertising; + int phy_id_mask; + int reg_num_mask; + + unsigned int full_duplex : 1; /* is full duplex? */ + unsigned int force_media : 1; /* is autoneg. disabled? */ + + struct net_device *dev; + int (*mdio_read) (struct net_device *dev, int phy_id, int location); + void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val); +}; + +struct ethtool_cmd; +struct mii_ioctl_data; + +#undef mii_link_ok +#define mii_link_ok _kc_mii_link_ok +#undef mii_nway_restart +#define mii_nway_restart _kc_mii_nway_restart +#undef mii_ethtool_gset +#define mii_ethtool_gset _kc_mii_ethtool_gset +#undef mii_ethtool_sset +#define mii_ethtool_sset _kc_mii_ethtool_sset +#undef mii_check_link +#define mii_check_link _kc_mii_check_link +#undef generic_mii_ioctl +#define generic_mii_ioctl _kc_generic_mii_ioctl +extern int _kc_mii_link_ok (struct mii_if_info *mii); +extern int _kc_mii_nway_restart (struct mii_if_info *mii); +extern int _kc_mii_ethtool_gset(struct mii_if_info *mii, + struct ethtool_cmd *ecmd); +extern int _kc_mii_ethtool_sset(struct mii_if_info *mii, + struct ethtool_cmd *ecmd); +extern void _kc_mii_check_link (struct mii_if_info *mii); +extern int _kc_generic_mii_ioctl(struct mii_if_info *mii_if, + struct mii_ioctl_data *mii_data, int cmd, + unsigned int *duplex_changed); + + +struct _kc_pci_dev_ext { + struct pci_dev *dev; + void *pci_drvdata; + struct pci_driver *driver; +}; + +struct _kc_net_dev_ext { + struct net_device *dev; + unsigned int carrier; +}; + + +/**************************************/ +/* mii support */ + +int _kc_mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) +{ + struct net_device *dev = mii->dev; + u32 advert, bmcr, lpa, nego; + + ecmd->supported = + (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | + SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); + + /* only supports twisted-pair */ + ecmd->port = PORT_MII; + + /* only supports internal transceiver */ + ecmd->transceiver = XCVR_INTERNAL; + + /* this isn't fully supported at higher layers */ + ecmd->phy_address = mii->phy_id; + + ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII; + advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE); + if (advert & ADVERTISE_10HALF) + ecmd->advertising |= ADVERTISED_10baseT_Half; + if (advert & ADVERTISE_10FULL) + ecmd->advertising |= ADVERTISED_10baseT_Full; + if (advert & ADVERTISE_100HALF) + ecmd->advertising |= ADVERTISED_100baseT_Half; + if (advert & ADVERTISE_100FULL) + ecmd->advertising |= ADVERTISED_100baseT_Full; + + bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); + lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA); + if (bmcr & BMCR_ANENABLE) { + ecmd->advertising |= ADVERTISED_Autoneg; + ecmd->autoneg = AUTONEG_ENABLE; + + nego = mii_nway_result(advert & lpa); + if (nego == LPA_100FULL || nego == LPA_100HALF) + ecmd->speed = SPEED_100; + else + ecmd->speed = SPEED_10; + if (nego == LPA_100FULL || nego == LPA_10FULL) { + ecmd->duplex = DUPLEX_FULL; + mii->full_duplex = 1; + } else { + ecmd->duplex = DUPLEX_HALF; + mii->full_duplex = 0; + } + } else { + ecmd->autoneg = AUTONEG_DISABLE; + + ecmd->speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10; + ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; + } + + /* ignore maxtxpkt, maxrxpkt for now */ + + return 0; +} + +int _kc_mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) +{ + struct net_device *dev = mii->dev; + + if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100) + return -EINVAL; + if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) + return -EINVAL; + if (ecmd->port != PORT_MII) + return -EINVAL; + if (ecmd->transceiver != XCVR_INTERNAL) + return -EINVAL; + if (ecmd->phy_address != mii->phy_id) + return -EINVAL; + if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE) + return -EINVAL; + + /* ignore supported, maxtxpkt, maxrxpkt */ + + if (ecmd->autoneg == AUTONEG_ENABLE) { + u32 bmcr, advert, tmp; + + if ((ecmd->advertising & (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full)) == 0) + return -EINVAL; + + /* advertise only what has been requested */ + advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE); + tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4); + if (ADVERTISED_10baseT_Half) + tmp |= ADVERTISE_10HALF; + if (ADVERTISED_10baseT_Full) + tmp |= ADVERTISE_10FULL; + if (ADVERTISED_100baseT_Half) + tmp |= ADVERTISE_100HALF; + if (ADVERTISED_100baseT_Full) + tmp |= ADVERTISE_100FULL; + if (advert != tmp) { + mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp); + mii->advertising = tmp; + } + + /* turn on autonegotiation, and force a renegotiate */ + bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); + bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); + mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr); + + mii->force_media = 0; + } else { + u32 bmcr, tmp; + + /* turn off auto negotiation, set speed and duplexity */ + bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); + tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX); + if (ecmd->speed == SPEED_100) + tmp |= BMCR_SPEED100; + if (ecmd->duplex == DUPLEX_FULL) { + tmp |= BMCR_FULLDPLX; + mii->full_duplex = 1; + } else + mii->full_duplex = 0; + if (bmcr != tmp) + mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp); + + mii->force_media = 1; + } + return 0; +} + +int _kc_mii_link_ok (struct mii_if_info *mii) +{ + /* first, a dummy read, needed to latch some MII phys */ + mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); + if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS) + return 1; + return 0; +} + +int _kc_mii_nway_restart (struct mii_if_info *mii) +{ + int bmcr; + int r = -EINVAL; + + /* if autoneg is off, it's an error */ + bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR); + + if (bmcr & BMCR_ANENABLE) { + bmcr |= BMCR_ANRESTART; + mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr); + r = 0; + } + + return r; +} + +void _kc_mii_check_link (struct mii_if_info *mii) +{ + int cur_link = mii_link_ok(mii); + int prev_link = netif_carrier_ok(mii->dev); + + if (cur_link && !prev_link) + netif_carrier_on(mii->dev); + else if (prev_link && !cur_link) + netif_carrier_off(mii->dev); +} + +int _kc_generic_mii_ioctl(struct mii_if_info *mii_if, + struct mii_ioctl_data *mii_data, int cmd, + unsigned int *duplex_chg_out) +{ + int rc = 0; + unsigned int duplex_changed = 0; + + if (duplex_chg_out) + *duplex_chg_out = 0; + + mii_data->phy_id &= mii_if->phy_id_mask; + mii_data->reg_num &= mii_if->reg_num_mask; + + switch(cmd) { + case SIOCDEVPRIVATE: /* binary compat, remove in 2.5 */ + case SIOCGMIIPHY: + mii_data->phy_id = mii_if->phy_id; + /* fall through */ + + case SIOCDEVPRIVATE + 1:/* binary compat, remove in 2.5 */ + case SIOCGMIIREG: + mii_data->val_out = + mii_if->mdio_read(mii_if->dev, mii_data->phy_id, + mii_data->reg_num); + break; + + case SIOCDEVPRIVATE + 2:/* binary compat, remove in 2.5 */ + case SIOCSMIIREG: { + u16 val = mii_data->val_in; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (mii_data->phy_id == mii_if->phy_id) { + switch(mii_data->reg_num) { + case MII_BMCR: { + unsigned int new_duplex = 0; + if (val & (BMCR_RESET|BMCR_ANENABLE)) + mii_if->force_media = 0; + else + mii_if->force_media = 1; + if (mii_if->force_media && + (val & BMCR_FULLDPLX)) + new_duplex = 1; + if (mii_if->full_duplex != new_duplex) { + duplex_changed = 1; + mii_if->full_duplex = new_duplex; + } + break; + } + case MII_ADVERTISE: + mii_if->advertising = val; + break; + default: + /* do nothing */ + break; + } + } + + mii_if->mdio_write(mii_if->dev, mii_data->phy_id, + mii_data->reg_num, val); + break; + } + + default: + rc = -EOPNOTSUPP; + break; + } + + if ((rc == 0) && (duplex_chg_out) && (duplex_changed)) + *duplex_chg_out = 1; + + return rc; +} + --- linux-2.6.27.orig/ubuntu/e1000e/e1000_mac.h +++ linux-2.6.27/ubuntu/e1000e/e1000_mac.h @@ -0,0 +1,86 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_MAC_H_ +#define _E1000_MAC_H_ + +/* + * Functions that should not be called directly from drivers but can be used + * by other files in this 'shared code' + */ +void e1000_init_mac_ops_generic(struct e1000_hw *hw); +s32 e1000_blink_led_generic(struct e1000_hw *hw); +s32 e1000_check_for_copper_link_generic(struct e1000_hw *hw); +s32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw); +s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw); +s32 e1000_cleanup_led_generic(struct e1000_hw *hw); +s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw); +s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw); +s32 e1000_disable_pcie_master_generic(struct e1000_hw *hw); +s32 e1000_force_mac_fc_generic(struct e1000_hw *hw); +s32 e1000_get_auto_rd_done_generic(struct e1000_hw *hw); +s32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw); +s32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw); +s32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed, + u16 *duplex); +s32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw, + u16 *speed, u16 *duplex); +s32 e1000_id_led_init_generic(struct e1000_hw *hw); +s32 e1000_led_on_generic(struct e1000_hw *hw); +s32 e1000_led_off_generic(struct e1000_hw *hw); +void e1000_update_mc_addr_list_generic(struct e1000_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count, + u32 rar_used_count, u32 rar_count); +s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw); +s32 e1000_set_default_fc_generic(struct e1000_hw *hw); +s32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw); +s32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw); +s32 e1000_setup_led_generic(struct e1000_hw *hw); +s32 e1000_setup_link_generic(struct e1000_hw *hw); +s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw); +s32 e1000_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, u32 reg, + u32 offset, u8 data); + +u32 e1000_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr); + +void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw); +void e1000_clear_vfta_generic(struct e1000_hw *hw); +void e1000_config_collision_dist_generic(struct e1000_hw *hw); +void e1000_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count); +void e1000_mta_set_generic(struct e1000_hw *hw, u32 hash_value); +void e1000_pcix_mmrbc_workaround_generic(struct e1000_hw *hw); +void e1000_put_hw_semaphore_generic(struct e1000_hw *hw); +void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index); +s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw); +void e1000_remove_device_generic(struct e1000_hw *hw); +void e1000_reset_adaptive_generic(struct e1000_hw *hw); +void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop); +void e1000_update_adaptive_generic(struct e1000_hw *hw); +void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value); + +#endif --- linux-2.6.27.orig/ubuntu/e1000e/e1000_defines.h +++ linux-2.6.27/ubuntu/e1000e/e1000_defines.h @@ -0,0 +1,1435 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_DEFINES_H_ +#define _E1000_DEFINES_H_ + +/* Number of Transmit and Receive Descriptors must be a multiple of 8 */ +#define REQ_TX_DESCRIPTOR_MULTIPLE 8 +#define REQ_RX_DESCRIPTOR_MULTIPLE 8 + +/* Definitions for power management and wakeup registers */ +/* Wake Up Control */ +#define E1000_WUC_APME 0x00000001 /* APM Enable */ +#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ +#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */ +#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */ +#define E1000_WUC_LSCWE 0x00000010 /* Link Status wake up enable */ +#define E1000_WUC_LSCWO 0x00000020 /* Link Status wake up override */ +#define E1000_WUC_SPM 0x80000000 /* Enable SPM */ +#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */ + +/* Wake Up Filter Control */ +#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ +#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ +#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ +#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */ +#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ +#define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */ +#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */ +#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */ +#define E1000_WUFC_IGNORE_TCO_BM 0x00000800 /* Ignore WakeOn TCO packets */ +#define E1000_WUFC_FLX0_BM 0x00001000 /* Flexible Filter 0 Enable */ +#define E1000_WUFC_FLX1_BM 0x00002000 /* Flexible Filter 1 Enable */ +#define E1000_WUFC_FLX2_BM 0x00004000 /* Flexible Filter 2 Enable */ +#define E1000_WUFC_FLX3_BM 0x00008000 /* Flexible Filter 3 Enable */ +#define E1000_WUFC_IGNORE_TCO 0x00008000 /* Ignore WakeOn TCO packets */ +#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */ +#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */ +#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */ +#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */ +#define E1000_WUFC_ALL_FILTERS_BM 0x0000F0FF /* Mask for all wakeup filters */ +#define E1000_WUFC_FLX_OFFSET_BM 12 /* Offset to the Flexible Filters bits */ +#define E1000_WUFC_FLX_FILTERS_BM 0x0000F000 /* Mask for the 4 flexible filters */ +#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */ +#define E1000_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */ +#define E1000_WUFC_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */ + +/* Wake Up Status */ +#define E1000_WUS_LNKC E1000_WUFC_LNKC +#define E1000_WUS_MAG E1000_WUFC_MAG +#define E1000_WUS_EX E1000_WUFC_EX +#define E1000_WUS_MC E1000_WUFC_MC +#define E1000_WUS_BC E1000_WUFC_BC +#define E1000_WUS_ARP E1000_WUFC_ARP +#define E1000_WUS_IPV4 E1000_WUFC_IPV4 +#define E1000_WUS_IPV6 E1000_WUFC_IPV6 +#define E1000_WUS_FLX0_BM E1000_WUFC_FLX0_BM +#define E1000_WUS_FLX1_BM E1000_WUFC_FLX1_BM +#define E1000_WUS_FLX2_BM E1000_WUFC_FLX2_BM +#define E1000_WUS_FLX3_BM E1000_WUFC_FLX3_BM +#define E1000_WUS_FLX_FILTERS_BM E1000_WUFC_FLX_FILTERS_BM +#define E1000_WUS_FLX0 E1000_WUFC_FLX0 +#define E1000_WUS_FLX1 E1000_WUFC_FLX1 +#define E1000_WUS_FLX2 E1000_WUFC_FLX2 +#define E1000_WUS_FLX3 E1000_WUFC_FLX3 +#define E1000_WUS_FLX_FILTERS E1000_WUFC_FLX_FILTERS + +/* Wake Up Packet Length */ +#define E1000_WUPL_LENGTH_MASK 0x0FFF /* Only the lower 12 bits are valid */ + +/* Four Flexible Filters are supported */ +#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4 + +/* Each Flexible Filter is at most 128 (0x80) bytes in length */ +#define E1000_FLEXIBLE_FILTER_SIZE_MAX 128 + +#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX +#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX +#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX + +/* Extended Device Control */ +#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */ +#define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */ +#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN +#define E1000_CTRL_EXT_GPI2_EN 0x00000004 /* Maps SDP6 to GPI2 */ +#define E1000_CTRL_EXT_GPI3_EN 0x00000008 /* Maps SDP7 to GPI3 */ +/* Reserved (bits 4,5) in >= 82575 */ +#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Definable Pin 4 */ +#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Definable Pin 5 */ +#define E1000_CTRL_EXT_PHY_INT E1000_CTRL_EXT_SDP5_DATA +#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Definable Pin 6 */ +#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Definable Pin 7 */ +/* SDP 4/5 (bits 8,9) are reserved in >= 82575 */ +#define E1000_CTRL_EXT_SDP4_DIR 0x00000100 /* Direction of SDP4 0=in 1=out */ +#define E1000_CTRL_EXT_SDP5_DIR 0x00000200 /* Direction of SDP5 0=in 1=out */ +#define E1000_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */ +#define E1000_CTRL_EXT_SDP7_DIR 0x00000800 /* Direction of SDP7 0=in 1=out */ +#define E1000_CTRL_EXT_ASDCHK 0x00001000 /* Initiate an ASD sequence */ +#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ +#define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */ +#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */ +#define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */ +#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 +#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000 +#define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000 +#define E1000_CTRL_EXT_LINK_MODE_KMRN 0x00000000 +#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000 +#define E1000_CTRL_EXT_LINK_MODE_PCIX_SERDES 0x00800000 +#define E1000_CTRL_EXT_LINK_MODE_SGMII 0x00800000 +#define E1000_CTRL_EXT_EIAME 0x01000000 +#define E1000_CTRL_EXT_IRCA 0x00000001 +#define E1000_CTRL_EXT_WR_WMARK_MASK 0x03000000 +#define E1000_CTRL_EXT_WR_WMARK_256 0x00000000 +#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000 +#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000 +#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000 +#define E1000_CTRL_EXT_CANC 0x04000000 /* Interrupt delay cancellation */ +#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ +/* IAME enable bit (27) was removed in >= 82575 */ +#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */ +#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */ +#define E1000_CRTL_EXT_PB_PAREN 0x01000000 /* packet buffer parity error detection enabled */ +#define E1000_CTRL_EXT_DF_PAREN 0x02000000 /* descriptor FIFO parity error detection enable */ +#define E1000_CTRL_EXT_GHOST_PAREN 0x40000000 +#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */ +#define E1000_CTRL_EXT_LSECCK 0x00001000 +#define E1000_I2CCMD_REG_ADDR_SHIFT 16 +#define E1000_I2CCMD_REG_ADDR 0x00FF0000 +#define E1000_I2CCMD_PHY_ADDR_SHIFT 24 +#define E1000_I2CCMD_PHY_ADDR 0x07000000 +#define E1000_I2CCMD_OPCODE_READ 0x08000000 +#define E1000_I2CCMD_OPCODE_WRITE 0x00000000 +#define E1000_I2CCMD_RESET 0x10000000 +#define E1000_I2CCMD_READY 0x20000000 +#define E1000_I2CCMD_INTERRUPT_ENA 0x40000000 +#define E1000_I2CCMD_ERROR 0x80000000 +#define E1000_MAX_SGMII_PHY_REG_ADDR 255 +#define E1000_I2CCMD_PHY_TIMEOUT 200 + +/* Receive Descriptor bit definitions */ +#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ +#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */ +#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */ +#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ +#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */ +#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ +#define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ +#define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */ +#define E1000_RXD_STAT_CRCV 0x100 /* Speculative CRC Valid */ +#define E1000_RXD_STAT_IPIDV 0x200 /* IP identification valid */ +#define E1000_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */ +#define E1000_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */ +#define E1000_RXD_STAT_ACK 0x8000 /* ACK Packet indication */ +#define E1000_RXD_ERR_CE 0x01 /* CRC Error */ +#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */ +#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */ +#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */ +#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */ +#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */ +#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */ +#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ +#define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */ +#define E1000_RXD_SPC_PRI_SHIFT 13 +#define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */ +#define E1000_RXD_SPC_CFI_SHIFT 12 + +#define E1000_RXDEXT_STATERR_CE 0x01000000 +#define E1000_RXDEXT_STATERR_SE 0x02000000 +#define E1000_RXDEXT_STATERR_SEQ 0x04000000 +#define E1000_RXDEXT_STATERR_CXE 0x10000000 +#define E1000_RXDEXT_STATERR_TCPE 0x20000000 +#define E1000_RXDEXT_STATERR_IPE 0x40000000 +#define E1000_RXDEXT_STATERR_RXE 0x80000000 + +#define E1000_RXDEXT_LSECH 0x01000000 +#define E1000_RXDEXT_LSECE_MASK 0x60000000 +#define E1000_RXDEXT_LSECE_NO_ERROR 0x00000000 +#define E1000_RXDEXT_LSECE_NO_SA_MATCH 0x20000000 +#define E1000_RXDEXT_LSECE_REPLAY_DETECT 0x40000000 +#define E1000_RXDEXT_LSECE_BAD_SIG 0x60000000 + +/* mask to determine if packets should be dropped due to frame errors */ +#define E1000_RXD_ERR_FRAME_ERR_MASK ( \ + E1000_RXD_ERR_CE | \ + E1000_RXD_ERR_SE | \ + E1000_RXD_ERR_SEQ | \ + E1000_RXD_ERR_CXE | \ + E1000_RXD_ERR_RXE) + +/* Same mask, but for extended and packet split descriptors */ +#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \ + E1000_RXDEXT_STATERR_CE | \ + E1000_RXDEXT_STATERR_SE | \ + E1000_RXDEXT_STATERR_SEQ | \ + E1000_RXDEXT_STATERR_CXE | \ + E1000_RXDEXT_STATERR_RXE) + +#define E1000_MRQC_ENABLE_MASK 0x00000007 +#define E1000_MRQC_ENABLE_RSS_2Q 0x00000001 +#define E1000_MRQC_ENABLE_RSS_INT 0x00000004 +#define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000 +#define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000 +#define E1000_MRQC_RSS_FIELD_IPV4 0x00020000 +#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000 +#define E1000_MRQC_RSS_FIELD_IPV6_EX 0x00080000 +#define E1000_MRQC_RSS_FIELD_IPV6 0x00100000 +#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00200000 + +#define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000 +#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF + +/* Management Control */ +#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */ +#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */ +#define E1000_MANC_R_ON_FORCE 0x00000004 /* Reset on Force TCO - RO */ +#define E1000_MANC_RMCP_EN 0x00000100 /* Enable RCMP 026Fh Filtering */ +#define E1000_MANC_0298_EN 0x00000200 /* Enable RCMP 0298h Filtering */ +#define E1000_MANC_IPV4_EN 0x00000400 /* Enable IPv4 */ +#define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */ +#define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */ +#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */ +/* Enable Neighbor Discovery Filtering */ +#define E1000_MANC_NEIGHBOR_EN 0x00004000 +#define E1000_MANC_ARP_RES_EN 0x00008000 /* Enable ARP response Filtering */ +#define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */ +#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ +#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */ +#define E1000_MANC_RCV_ALL 0x00080000 /* Receive All Enabled */ +#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */ +/* Enable MAC address filtering */ +#define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000 +/* Enable MNG packets to host memory */ +#define E1000_MANC_EN_MNG2HOST 0x00200000 +/* Enable IP address filtering */ +#define E1000_MANC_EN_IP_ADDR_FILTER 0x00400000 +#define E1000_MANC_EN_XSUM_FILTER 0x00800000 /* Enable checksum filtering */ +#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */ +#define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */ +#define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */ +#define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */ +#define E1000_MANC_SMB_DATA_IN 0x08000000 /* SMBus Data In */ +#define E1000_MANC_SMB_DATA_OUT 0x10000000 /* SMBus Data Out */ +#define E1000_MANC_SMB_CLK_OUT 0x20000000 /* SMBus Clock Out */ + +#define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */ +#define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */ + +/* Receive Control */ +#define E1000_RCTL_RST 0x00000001 /* Software reset */ +#define E1000_RCTL_EN 0x00000002 /* enable */ +#define E1000_RCTL_SBP 0x00000004 /* store bad packet */ +#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */ +#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */ +#define E1000_RCTL_LPE 0x00000020 /* long packet enable */ +#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ +#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ +#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */ +#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ +#define E1000_RCTL_DTYP_MASK 0x00000C00 /* Descriptor type mask */ +#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */ +#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ +#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min threshold size */ +#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min threshold size */ +#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ +#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */ +#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */ +#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */ +#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ +#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */ +#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ +#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ +#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ +#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ +#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ +#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ +#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ +#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ +#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ +#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ +#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ +#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ +#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ +#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ +#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ +#define E1000_RCTL_FLXBUF_MASK 0x78000000 /* Flexible buffer size */ +#define E1000_RCTL_FLXBUF_SHIFT 27 /* Flexible buffer shift */ + +/* + * Use byte values for the following shift parameters + * Usage: + * psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) & + * E1000_PSRCTL_BSIZE0_MASK) | + * ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) & + * E1000_PSRCTL_BSIZE1_MASK) | + * ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) & + * E1000_PSRCTL_BSIZE2_MASK) | + * ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |; + * E1000_PSRCTL_BSIZE3_MASK)) + * where value0 = [128..16256], default=256 + * value1 = [1024..64512], default=4096 + * value2 = [0..64512], default=4096 + * value3 = [0..64512], default=0 + */ + +#define E1000_PSRCTL_BSIZE0_MASK 0x0000007F +#define E1000_PSRCTL_BSIZE1_MASK 0x00003F00 +#define E1000_PSRCTL_BSIZE2_MASK 0x003F0000 +#define E1000_PSRCTL_BSIZE3_MASK 0x3F000000 + +#define E1000_PSRCTL_BSIZE0_SHIFT 7 /* Shift _right_ 7 */ +#define E1000_PSRCTL_BSIZE1_SHIFT 2 /* Shift _right_ 2 */ +#define E1000_PSRCTL_BSIZE2_SHIFT 6 /* Shift _left_ 6 */ +#define E1000_PSRCTL_BSIZE3_SHIFT 14 /* Shift _left_ 14 */ + +/* SWFW_SYNC Definitions */ +#define E1000_SWFW_EEP_SM 0x1 +#define E1000_SWFW_PHY0_SM 0x2 +#define E1000_SWFW_PHY1_SM 0x4 +#define E1000_SWFW_CSR_SM 0x8 + +/* FACTPS Definitions */ +#define E1000_FACTPS_LFS 0x40000000 /* LAN Function Select */ +/* Device Control */ +#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ +#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */ +#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */ +#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */ +#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */ +#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */ +#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */ +#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */ +#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ +#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */ +#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */ +#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */ +#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */ +#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */ +#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */ +#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ +#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ +#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */ +#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */ +#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through PHYRST_N pin */ +#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */ +#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ +#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ +#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ +#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */ +#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */ +#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */ +#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */ +#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */ +#define E1000_CTRL_RST 0x04000000 /* Global reset */ +#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ +#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ +#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */ +#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ +#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ +#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to manageability engine */ +#define E1000_CTRL_I2C_ENA 0x02000000 /* I2C enable */ + +/* Bit definitions for the Management Data IO (MDIO) and Management Data + * Clock (MDC) pins in the Device Control Register. + */ +#define E1000_CTRL_PHY_RESET_DIR E1000_CTRL_SWDPIO0 +#define E1000_CTRL_PHY_RESET E1000_CTRL_SWDPIN0 +#define E1000_CTRL_MDIO_DIR E1000_CTRL_SWDPIO2 +#define E1000_CTRL_MDIO E1000_CTRL_SWDPIN2 +#define E1000_CTRL_MDC_DIR E1000_CTRL_SWDPIO3 +#define E1000_CTRL_MDC E1000_CTRL_SWDPIN3 +#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR +#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA + +#define E1000_CONNSW_ENRGSRC 0x4 +#define E1000_PCS_CFG_PCS_EN 8 +#define E1000_PCS_LCTL_FLV_LINK_UP 1 +#define E1000_PCS_LCTL_FSV_10 0 +#define E1000_PCS_LCTL_FSV_100 2 +#define E1000_PCS_LCTL_FSV_1000 4 +#define E1000_PCS_LCTL_FDV_FULL 8 +#define E1000_PCS_LCTL_FSD 0x10 +#define E1000_PCS_LCTL_FORCE_LINK 0x20 +#define E1000_PCS_LCTL_LOW_LINK_LATCH 0x40 +#define E1000_PCS_LCTL_AN_ENABLE 0x10000 +#define E1000_PCS_LCTL_AN_RESTART 0x20000 +#define E1000_PCS_LCTL_AN_TIMEOUT 0x40000 +#define E1000_PCS_LCTL_AN_SGMII_BYPASS 0x80000 +#define E1000_PCS_LCTL_AN_SGMII_TRIGGER 0x100000 +#define E1000_PCS_LCTL_FAST_LINK_TIMER 0x1000000 +#define E1000_PCS_LCTL_LINK_OK_FIX 0x2000000 +#define E1000_PCS_LCTL_CRS_ON_NI 0x4000000 +#define E1000_ENABLE_SERDES_LOOPBACK 0x0410 + +#define E1000_PCS_LSTS_LINK_OK 1 +#define E1000_PCS_LSTS_SPEED_10 0 +#define E1000_PCS_LSTS_SPEED_100 2 +#define E1000_PCS_LSTS_SPEED_1000 4 +#define E1000_PCS_LSTS_DUPLEX_FULL 8 +#define E1000_PCS_LSTS_SYNK_OK 0x10 +#define E1000_PCS_LSTS_AN_COMPLETE 0x10000 +#define E1000_PCS_LSTS_AN_PAGE_RX 0x20000 +#define E1000_PCS_LSTS_AN_TIMED_OUT 0x40000 +#define E1000_PCS_LSTS_AN_REMOTE_FAULT 0x80000 +#define E1000_PCS_LSTS_AN_ERROR_RWS 0x100000 + +/* Device Status */ +#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ +#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ +#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */ +#define E1000_STATUS_FUNC_SHIFT 2 +#define E1000_STATUS_FUNC_0 0x00000000 /* Function 0 */ +#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */ +#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */ +#define E1000_STATUS_TBIMODE 0x00000020 /* TBI mode */ +#define E1000_STATUS_SPEED_MASK 0x000000C0 +#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */ +#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ +#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ +#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion by NVM */ +#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */ +#define E1000_STATUS_DOCK_CI 0x00000800 /* Change in Dock/Undock state. Clear on write '0'. */ +#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */ +#define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */ +#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */ +#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */ +#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */ +#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */ +#define E1000_STATUS_BMC_SKU_0 0x00100000 /* BMC USB redirect disabled */ +#define E1000_STATUS_BMC_SKU_1 0x00200000 /* BMC SRAM disabled */ +#define E1000_STATUS_BMC_SKU_2 0x00400000 /* BMC SDRAM disabled */ +#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */ +#define E1000_STATUS_BMC_LITE 0x01000000 /* BMC external code execution disabled */ +#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */ +#define E1000_STATUS_FUSE_8 0x04000000 +#define E1000_STATUS_FUSE_9 0x08000000 +#define E1000_STATUS_SERDES0_DIS 0x10000000 /* SERDES disabled on port 0 */ +#define E1000_STATUS_SERDES1_DIS 0x20000000 /* SERDES disabled on port 1 */ + +/* Constants used to interpret the masked PCI-X bus speed. */ +#define E1000_STATUS_PCIX_SPEED_66 0x00000000 /* PCI-X bus speed 50-66 MHz */ +#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */ +#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /* PCI-X bus speed 100-133 MHz */ + +#define SPEED_10 10 +#define SPEED_100 100 +#define SPEED_1000 1000 +#define HALF_DUPLEX 1 +#define FULL_DUPLEX 2 + +#define PHY_FORCE_TIME 20 + +#define ADVERTISE_10_HALF 0x0001 +#define ADVERTISE_10_FULL 0x0002 +#define ADVERTISE_100_HALF 0x0004 +#define ADVERTISE_100_FULL 0x0008 +#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */ +#define ADVERTISE_1000_FULL 0x0020 + +/* 1000/H is not supported, nor spec-compliant. */ +#define E1000_ALL_SPEED_DUPLEX ( ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ + ADVERTISE_100_HALF | ADVERTISE_100_FULL | \ + ADVERTISE_1000_FULL) +#define E1000_ALL_NOT_GIG ( ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ + ADVERTISE_100_HALF | ADVERTISE_100_FULL) +#define E1000_ALL_100_SPEED (ADVERTISE_100_HALF | ADVERTISE_100_FULL) +#define E1000_ALL_10_SPEED (ADVERTISE_10_HALF | ADVERTISE_10_FULL) +#define E1000_ALL_FULL_DUPLEX (ADVERTISE_10_FULL | ADVERTISE_100_FULL | \ + ADVERTISE_1000_FULL) +#define E1000_ALL_HALF_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_100_HALF) + +#define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX + +/* LED Control */ +#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F +#define E1000_LEDCTL_LED0_MODE_SHIFT 0 +#define E1000_LEDCTL_LED0_BLINK_RATE 0x00000020 +#define E1000_LEDCTL_LED0_IVRT 0x00000040 +#define E1000_LEDCTL_LED0_BLINK 0x00000080 +#define E1000_LEDCTL_LED1_MODE_MASK 0x00000F00 +#define E1000_LEDCTL_LED1_MODE_SHIFT 8 +#define E1000_LEDCTL_LED1_BLINK_RATE 0x00002000 +#define E1000_LEDCTL_LED1_IVRT 0x00004000 +#define E1000_LEDCTL_LED1_BLINK 0x00008000 +#define E1000_LEDCTL_LED2_MODE_MASK 0x000F0000 +#define E1000_LEDCTL_LED2_MODE_SHIFT 16 +#define E1000_LEDCTL_LED2_BLINK_RATE 0x00200000 +#define E1000_LEDCTL_LED2_IVRT 0x00400000 +#define E1000_LEDCTL_LED2_BLINK 0x00800000 +#define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000 +#define E1000_LEDCTL_LED3_MODE_SHIFT 24 +#define E1000_LEDCTL_LED3_BLINK_RATE 0x20000000 +#define E1000_LEDCTL_LED3_IVRT 0x40000000 +#define E1000_LEDCTL_LED3_BLINK 0x80000000 + +#define E1000_LEDCTL_MODE_LINK_10_1000 0x0 +#define E1000_LEDCTL_MODE_LINK_100_1000 0x1 +#define E1000_LEDCTL_MODE_LINK_UP 0x2 +#define E1000_LEDCTL_MODE_ACTIVITY 0x3 +#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4 +#define E1000_LEDCTL_MODE_LINK_10 0x5 +#define E1000_LEDCTL_MODE_LINK_100 0x6 +#define E1000_LEDCTL_MODE_LINK_1000 0x7 +#define E1000_LEDCTL_MODE_PCIX_MODE 0x8 +#define E1000_LEDCTL_MODE_FULL_DUPLEX 0x9 +#define E1000_LEDCTL_MODE_COLLISION 0xA +#define E1000_LEDCTL_MODE_BUS_SPEED 0xB +#define E1000_LEDCTL_MODE_BUS_SIZE 0xC +#define E1000_LEDCTL_MODE_PAUSED 0xD +#define E1000_LEDCTL_MODE_LED_ON 0xE +#define E1000_LEDCTL_MODE_LED_OFF 0xF + +/* Transmit Descriptor bit definitions */ +#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */ +#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */ +#define E1000_TXD_POPTS_SHIFT 8 /* POPTS shift */ +#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ +#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ +#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */ +#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */ +#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ +#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ +#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ +#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ +#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ +#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ +#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */ +#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */ +#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */ +#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */ +#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ +#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ +#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ +/* Extended desc bits for Linksec and timesync */ +#define E1000_TXD_CMD_LINKSEC 0x10000000 /* Apply LinkSec on packet */ +#define E1000_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */ + +/* Transmit Control */ +#define E1000_TCTL_RST 0x00000001 /* software reset */ +#define E1000_TCTL_EN 0x00000002 /* enable tx */ +#define E1000_TCTL_BCE 0x00000004 /* busy check enable */ +#define E1000_TCTL_PSP 0x00000008 /* pad short packets */ +#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */ +#define E1000_TCTL_COLD 0x003ff000 /* collision distance */ +#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */ +#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */ +#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ +#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */ +#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */ + +/* Transmit Arbitration Count */ +#define E1000_TARC0_ENABLE 0x00000400 /* Enable Tx Queue 0 */ + +/* SerDes Control */ +#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400 + +/* Receive Checksum Control */ +#define E1000_RXCSUM_PCSS_MASK 0x000000FF /* Packet Checksum Start */ +#define E1000_RXCSUM_IPOFL 0x00000100 /* IPv4 checksum offload */ +#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */ +#define E1000_RXCSUM_IPV6OFL 0x00000400 /* IPv6 checksum offload */ +#define E1000_RXCSUM_CRCOFL 0x00000800 /* CRC32 offload enable */ +#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ +#define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */ + +/* Header split receive */ +#define E1000_RFCTL_ISCSI_DIS 0x00000001 +#define E1000_RFCTL_ISCSI_DWC_MASK 0x0000003E +#define E1000_RFCTL_ISCSI_DWC_SHIFT 1 +#define E1000_RFCTL_NFSW_DIS 0x00000040 +#define E1000_RFCTL_NFSR_DIS 0x00000080 +#define E1000_RFCTL_NFS_VER_MASK 0x00000300 +#define E1000_RFCTL_NFS_VER_SHIFT 8 +#define E1000_RFCTL_IPV6_DIS 0x00000400 +#define E1000_RFCTL_IPV6_XSUM_DIS 0x00000800 +#define E1000_RFCTL_ACK_DIS 0x00001000 +#define E1000_RFCTL_ACKD_DIS 0x00002000 +#define E1000_RFCTL_IPFRSP_DIS 0x00004000 +#define E1000_RFCTL_EXTEN 0x00008000 +#define E1000_RFCTL_IPV6_EX_DIS 0x00010000 +#define E1000_RFCTL_NEW_IPV6_EXT_DIS 0x00020000 + +/* Collision related configuration parameters */ +#define E1000_COLLISION_THRESHOLD 15 +#define E1000_CT_SHIFT 4 +#define E1000_COLLISION_DISTANCE 63 +#define E1000_COLD_SHIFT 12 + +/* Default values for the transmit IPG register */ +#define DEFAULT_82543_TIPG_IPGT_FIBER 9 +#define DEFAULT_82543_TIPG_IPGT_COPPER 8 + +#define E1000_TIPG_IPGT_MASK 0x000003FF +#define E1000_TIPG_IPGR1_MASK 0x000FFC00 +#define E1000_TIPG_IPGR2_MASK 0x3FF00000 + +#define DEFAULT_82543_TIPG_IPGR1 8 +#define E1000_TIPG_IPGR1_SHIFT 10 + +#define DEFAULT_82543_TIPG_IPGR2 6 +#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7 +#define E1000_TIPG_IPGR2_SHIFT 20 + +/* Ethertype field values */ +#define ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.3ac packet */ + +#define ETHERNET_FCS_SIZE 4 +#define MAX_JUMBO_FRAME_SIZE 0x3F00 + +/* Extended Configuration Control and Size */ +#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020 +#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001 +#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020 +#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000 +#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16 +#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK 0x0FFF0000 +#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT 16 + +#define E1000_PHY_CTRL_SPD_EN 0x00000001 +#define E1000_PHY_CTRL_D0A_LPLU 0x00000002 +#define E1000_PHY_CTRL_NOND0A_LPLU 0x00000004 +#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008 +#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040 + +#define E1000_KABGTXD_BGSQLBIAS 0x00050000 + +/* PBA constants */ +#define E1000_PBA_6K 0x0006 /* 6KB */ +#define E1000_PBA_8K 0x0008 /* 8KB */ +#define E1000_PBA_12K 0x000C /* 12KB */ +#define E1000_PBA_16K 0x0010 /* 16KB */ +#define E1000_PBA_20K 0x0014 +#define E1000_PBA_22K 0x0016 +#define E1000_PBA_24K 0x0018 +#define E1000_PBA_30K 0x001E +#define E1000_PBA_32K 0x0020 +#define E1000_PBA_34K 0x0022 +#define E1000_PBA_38K 0x0026 +#define E1000_PBA_40K 0x0028 +#define E1000_PBA_48K 0x0030 /* 48KB */ +#define E1000_PBA_64K 0x0040 /* 64KB */ + +#define E1000_PBS_16K E1000_PBA_16K +#define E1000_PBS_24K E1000_PBA_24K + +#define IFS_MAX 80 +#define IFS_MIN 40 +#define IFS_RATIO 4 +#define IFS_STEP 10 +#define MIN_NUM_XMITS 1000 + +/* SW Semaphore Register */ +#define E1000_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ +#define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ +#define E1000_SWSM_WMNG 0x00000004 /* Wake MNG Clock */ +#define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ + +/* Interrupt Cause Read */ +#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ +#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */ +#define E1000_ICR_LSC 0x00000004 /* Link Status Change */ +#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */ +#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ +#define E1000_ICR_RXO 0x00000040 /* rx overrun */ +#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ +#define E1000_ICR_VMMB 0x00000100 /* VM MB event */ +#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */ +#define E1000_ICR_RXCFG 0x00000400 /* Rx /c/ ordered set */ +#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */ +#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */ +#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */ +#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */ +#define E1000_ICR_TXD_LOW 0x00008000 +#define E1000_ICR_SRPD 0x00010000 +#define E1000_ICR_ACK 0x00020000 /* Receive Ack frame */ +#define E1000_ICR_MNG 0x00040000 /* Manageability event */ +#define E1000_ICR_DOCK 0x00080000 /* Dock/Undock */ +#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */ +#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* queue 0 Rx descriptor FIFO parity error */ +#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* queue 0 Tx descriptor FIFO parity error */ +#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity error */ +#define E1000_ICR_PB_PAR 0x00800000 /* packet buffer parity error */ +#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */ +#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */ +#define E1000_ICR_ALL_PARITY 0x03F00000 /* all parity error bits */ +#define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW bit in the FWSM */ +#define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates an interrupt */ +#define E1000_ICR_EPRST 0x00100000 /* ME hardware reset occurs */ +#define E1000_ICR_RXQ0 0x00100000 /* Rx Queue 0 Interrupt */ +#define E1000_ICR_RXQ1 0x00200000 /* Rx Queue 1 Interrupt */ +#define E1000_ICR_TXQ0 0x00400000 /* Tx Queue 0 Interrupt */ +#define E1000_ICR_TXQ1 0x00800000 /* Tx Queue 1 Interrupt */ +#define E1000_ICR_OTHER 0x01000000 /* Other Interrupts */ + +/* Extended Interrupt Cause Read */ +#define E1000_EICR_RX_QUEUE0 0x00000001 /* Rx Queue 0 Interrupt */ +#define E1000_EICR_RX_QUEUE1 0x00000002 /* Rx Queue 1 Interrupt */ +#define E1000_EICR_RX_QUEUE2 0x00000004 /* Rx Queue 2 Interrupt */ +#define E1000_EICR_RX_QUEUE3 0x00000008 /* Rx Queue 3 Interrupt */ +#define E1000_EICR_TX_QUEUE0 0x00000100 /* Tx Queue 0 Interrupt */ +#define E1000_EICR_TX_QUEUE1 0x00000200 /* Tx Queue 1 Interrupt */ +#define E1000_EICR_TX_QUEUE2 0x00000400 /* Tx Queue 2 Interrupt */ +#define E1000_EICR_TX_QUEUE3 0x00000800 /* Tx Queue 3 Interrupt */ +#define E1000_EICR_TCP_TIMER 0x40000000 /* TCP Timer */ +#define E1000_EICR_OTHER 0x80000000 /* Interrupt Cause Active */ +/* TCP Timer */ +#define E1000_TCPTIMER_KS 0x00000100 /* KickStart */ +#define E1000_TCPTIMER_COUNT_ENABLE 0x00000200 /* Count Enable */ +#define E1000_TCPTIMER_COUNT_FINISH 0x00000400 /* Count finish */ +#define E1000_TCPTIMER_LOOP 0x00000800 /* Loop */ + +/* + * This defines the bits that are set in the Interrupt Mask + * Set/Read Register. Each bit is documented below: + * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) + * o RXSEQ = Receive Sequence Error + */ +#define POLL_IMS_ENABLE_MASK ( \ + E1000_IMS_RXDMT0 | \ + E1000_IMS_RXSEQ) + +/* + * This defines the bits that are set in the Interrupt Mask + * Set/Read Register. Each bit is documented below: + * o RXT0 = Receiver Timer Interrupt (ring 0) + * o TXDW = Transmit Descriptor Written Back + * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) + * o RXSEQ = Receive Sequence Error + * o LSC = Link Status Change + */ +#define IMS_ENABLE_MASK ( \ + E1000_IMS_RXT0 | \ + E1000_IMS_TXDW | \ + E1000_IMS_RXDMT0 | \ + E1000_IMS_RXSEQ | \ + E1000_IMS_LSC) + +/* Interrupt Mask Set */ +#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* Rx /c/ ordered set */ +#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ +#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW +#define E1000_IMS_SRPD E1000_ICR_SRPD +#define E1000_IMS_ACK E1000_ICR_ACK /* Receive Ack frame */ +#define E1000_IMS_MNG E1000_ICR_MNG /* Manageability event */ +#define E1000_IMS_DOCK E1000_ICR_DOCK /* Dock/Undock */ +#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */ +#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */ +#define E1000_IMS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */ +#define E1000_IMS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ +#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ +#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ +#define E1000_IMS_DSW E1000_ICR_DSW +#define E1000_IMS_PHYINT E1000_ICR_PHYINT +#define E1000_IMS_EPRST E1000_ICR_EPRST +#define E1000_IMS_RXQ0 E1000_ICR_RXQ0 /* Rx Queue 0 Interrupt */ +#define E1000_IMS_RXQ1 E1000_ICR_RXQ1 /* Rx Queue 1 Interrupt */ +#define E1000_IMS_TXQ0 E1000_ICR_TXQ0 /* Tx Queue 0 Interrupt */ +#define E1000_IMS_TXQ1 E1000_ICR_TXQ1 /* Tx Queue 1 Interrupt */ +#define E1000_IMS_OTHER E1000_ICR_OTHER /* Other Interrupts */ + +/* Extended Interrupt Mask Set */ +#define E1000_EIMS_RX_QUEUE0 E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */ +#define E1000_EIMS_RX_QUEUE1 E1000_EICR_RX_QUEUE1 /* Rx Queue 1 Interrupt */ +#define E1000_EIMS_RX_QUEUE2 E1000_EICR_RX_QUEUE2 /* Rx Queue 2 Interrupt */ +#define E1000_EIMS_RX_QUEUE3 E1000_EICR_RX_QUEUE3 /* Rx Queue 3 Interrupt */ +#define E1000_EIMS_TX_QUEUE0 E1000_EICR_TX_QUEUE0 /* Tx Queue 0 Interrupt */ +#define E1000_EIMS_TX_QUEUE1 E1000_EICR_TX_QUEUE1 /* Tx Queue 1 Interrupt */ +#define E1000_EIMS_TX_QUEUE2 E1000_EICR_TX_QUEUE2 /* Tx Queue 2 Interrupt */ +#define E1000_EIMS_TX_QUEUE3 E1000_EICR_TX_QUEUE3 /* Tx Queue 3 Interrupt */ +#define E1000_EIMS_TCP_TIMER E1000_EICR_TCP_TIMER /* TCP Timer */ +#define E1000_EIMS_OTHER E1000_EICR_OTHER /* Interrupt Cause Active */ + +/* Interrupt Cause Set */ +#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* Rx /c/ ordered set */ +#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ +#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW +#define E1000_ICS_SRPD E1000_ICR_SRPD +#define E1000_ICS_ACK E1000_ICR_ACK /* Receive Ack frame */ +#define E1000_ICS_MNG E1000_ICR_MNG /* Manageability event */ +#define E1000_ICS_DOCK E1000_ICR_DOCK /* Dock/Undock */ +#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */ +#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */ +#define E1000_ICS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */ +#define E1000_ICS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ +#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ +#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ +#define E1000_ICS_DSW E1000_ICR_DSW +#define E1000_ICS_PHYINT E1000_ICR_PHYINT +#define E1000_ICS_EPRST E1000_ICR_EPRST + +/* Extended Interrupt Cause Set */ +#define E1000_EICS_RX_QUEUE0 E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */ +#define E1000_EICS_RX_QUEUE1 E1000_EICR_RX_QUEUE1 /* Rx Queue 1 Interrupt */ +#define E1000_EICS_RX_QUEUE2 E1000_EICR_RX_QUEUE2 /* Rx Queue 2 Interrupt */ +#define E1000_EICS_RX_QUEUE3 E1000_EICR_RX_QUEUE3 /* Rx Queue 3 Interrupt */ +#define E1000_EICS_TX_QUEUE0 E1000_EICR_TX_QUEUE0 /* Tx Queue 0 Interrupt */ +#define E1000_EICS_TX_QUEUE1 E1000_EICR_TX_QUEUE1 /* Tx Queue 1 Interrupt */ +#define E1000_EICS_TX_QUEUE2 E1000_EICR_TX_QUEUE2 /* Tx Queue 2 Interrupt */ +#define E1000_EICS_TX_QUEUE3 E1000_EICR_TX_QUEUE3 /* Tx Queue 3 Interrupt */ +#define E1000_EICS_TCP_TIMER E1000_EICR_TCP_TIMER /* TCP Timer */ +#define E1000_EICS_OTHER E1000_EICR_OTHER /* Interrupt Cause Active */ + +/* Transmit Descriptor Control */ +#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */ +#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */ +#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */ +#define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */ +#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */ +#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */ +#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */ +/* Enable the counting of descriptors still to be processed. */ +#define E1000_TXDCTL_COUNT_DESC 0x00400000 + +/* Flow Control Constants */ +#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001 +#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100 +#define FLOW_CONTROL_TYPE 0x8808 + +/* 802.1q VLAN Packet Size */ +#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMA'd) */ +#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ + +/* Receive Address */ +/* + * Number of high/low register pairs in the RAR. The RAR (Receive Address + * Registers) holds the directed and multicast addresses that we monitor. + * Technically, we have 16 spots. However, we reserve one of these spots + * (RAR[15]) for our directed address used by controllers with + * manageability enabled, allowing us room for 15 multicast addresses. + */ +#define E1000_RAR_ENTRIES 15 +#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */ + +/* Error Codes */ +#define E1000_SUCCESS 0 +#define E1000_ERR_NVM 1 +#define E1000_ERR_PHY 2 +#define E1000_ERR_CONFIG 3 +#define E1000_ERR_PARAM 4 +#define E1000_ERR_MAC_INIT 5 +#define E1000_ERR_PHY_TYPE 6 +#define E1000_ERR_RESET 9 +#define E1000_ERR_MASTER_REQUESTS_PENDING 10 +#define E1000_ERR_HOST_INTERFACE_COMMAND 11 +#define E1000_BLK_PHY_RESET 12 +#define E1000_ERR_SWFW_SYNC 13 +#define E1000_NOT_IMPLEMENTED 14 + +/* Loop limit on how long we wait for auto-negotiation to complete */ +#define FIBER_LINK_UP_LIMIT 50 +#define COPPER_LINK_UP_LIMIT 10 +#define PHY_AUTO_NEG_LIMIT 45 +#define PHY_FORCE_LIMIT 20 +/* Number of 100 microseconds we wait for PCI Express master disable */ +#define MASTER_DISABLE_TIMEOUT 800 +/* Number of milliseconds we wait for PHY configuration done after MAC reset */ +#define PHY_CFG_TIMEOUT 100 +/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */ +#define MDIO_OWNERSHIP_TIMEOUT 10 +/* Number of milliseconds for NVM auto read done after MAC reset. */ +#define AUTO_READ_DONE_TIMEOUT 10 + +/* Flow Control */ +#define E1000_FCRTH_RTH 0x0000FFF8 /* Mask Bits[15:3] for RTH */ +#define E1000_FCRTH_XFCE 0x80000000 /* External Flow Control Enable */ +#define E1000_FCRTL_RTL 0x0000FFF8 /* Mask Bits[15:3] for RTL */ +#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ + +/* Transmit Configuration Word */ +#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */ +#define E1000_TXCW_HD 0x00000040 /* TXCW half duplex */ +#define E1000_TXCW_PAUSE 0x00000080 /* TXCW sym pause request */ +#define E1000_TXCW_ASM_DIR 0x00000100 /* TXCW astm pause direction */ +#define E1000_TXCW_PAUSE_MASK 0x00000180 /* TXCW pause request mask */ +#define E1000_TXCW_RF 0x00003000 /* TXCW remote fault */ +#define E1000_TXCW_NP 0x00008000 /* TXCW next page */ +#define E1000_TXCW_CW 0x0000ffff /* TxConfigWord mask */ +#define E1000_TXCW_TXC 0x40000000 /* Transmit Config control */ +#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */ + +/* Receive Configuration Word */ +#define E1000_RXCW_CW 0x0000ffff /* RxConfigWord mask */ +#define E1000_RXCW_NC 0x04000000 /* Receive config no carrier */ +#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */ +#define E1000_RXCW_CC 0x10000000 /* Receive config change */ +#define E1000_RXCW_C 0x20000000 /* Receive config */ +#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */ +#define E1000_RXCW_ANC 0x80000000 /* Auto-neg complete */ + +/* PCI Express Control */ +#define E1000_GCR_RXD_NO_SNOOP 0x00000001 +#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002 +#define E1000_GCR_RXDSCR_NO_SNOOP 0x00000004 +#define E1000_GCR_TXD_NO_SNOOP 0x00000008 +#define E1000_GCR_TXDSCW_NO_SNOOP 0x00000010 +#define E1000_GCR_TXDSCR_NO_SNOOP 0x00000020 + +#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP | \ + E1000_GCR_RXDSCW_NO_SNOOP | \ + E1000_GCR_RXDSCR_NO_SNOOP | \ + E1000_GCR_TXD_NO_SNOOP | \ + E1000_GCR_TXDSCW_NO_SNOOP | \ + E1000_GCR_TXDSCR_NO_SNOOP) + +/* PHY Control Register */ +#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ +#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ +#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ +#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ +#define MII_CR_POWER_DOWN 0x0800 /* Power down */ +#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ +#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ +#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ +#define MII_CR_SPEED_1000 0x0040 +#define MII_CR_SPEED_100 0x2000 +#define MII_CR_SPEED_10 0x0000 + +/* PHY Status Register */ +#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ +#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ +#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ +#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ +#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ +#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ +#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ +#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ +#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ +#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ +#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ +#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ +#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ +#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ +#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ + +/* Autoneg Advertisement Register */ +#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */ +#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ +#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ +#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ +#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ +#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */ +#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */ +#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ +#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */ +#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */ + +/* Link Partner Ability Register (Base Page) */ +#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */ +#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */ +#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */ +#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */ +#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */ +#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */ +#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ +#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ +#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */ +#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */ +#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */ + +/* Autoneg Expansion Register */ +#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */ +#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */ +#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */ +#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */ +#define NWAY_ER_PAR_DETECT_FAULT 0x0010 /* LP is 100TX Full Duplex Capable */ + +/* 1000BASE-T Control Register */ +#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */ +#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ +#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ +#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */ + /* 0=DTE device */ +#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */ + /* 0=Configure PHY as Slave */ +#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */ + /* 0=Automatic Master/Slave config */ +#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ +#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */ +#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */ +#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */ +#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */ + +/* 1000BASE-T Status Register */ +#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */ +#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */ +#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */ +#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */ +#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ +#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ +#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local Tx is Master, 0=Slave */ +#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */ + +#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5 + +/* PHY 1000 MII Register/Bit Definitions */ +/* PHY Registers defined by IEEE */ +#define PHY_CONTROL 0x00 /* Control Register */ +#define PHY_STATUS 0x01 /* Status Register */ +#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ +#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ +#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ +#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ +#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */ +#define PHY_NEXT_PAGE_TX 0x07 /* Next Page Tx */ +#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */ +#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ +#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ +#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */ + +/* NVM Control */ +#define E1000_EECD_SK 0x00000001 /* NVM Clock */ +#define E1000_EECD_CS 0x00000002 /* NVM Chip Select */ +#define E1000_EECD_DI 0x00000004 /* NVM Data In */ +#define E1000_EECD_DO 0x00000008 /* NVM Data Out */ +#define E1000_EECD_FWE_MASK 0x00000030 +#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */ +#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */ +#define E1000_EECD_FWE_SHIFT 4 +#define E1000_EECD_REQ 0x00000040 /* NVM Access Request */ +#define E1000_EECD_GNT 0x00000080 /* NVM Access Grant */ +#define E1000_EECD_PRES 0x00000100 /* NVM Present */ +#define E1000_EECD_SIZE 0x00000200 /* NVM Size (0=64 word 1=256 word) */ +/* NVM Addressing bits based on type 0=small, 1=large */ +#define E1000_EECD_ADDR_BITS 0x00000400 +#define E1000_EECD_TYPE 0x00002000 /* NVM Type (1-SPI, 0-Microwire) */ +#define E1000_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */ +#define E1000_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */ +#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */ +#define E1000_EECD_SIZE_EX_SHIFT 11 +#define E1000_EECD_NVADDS 0x00018000 /* NVM Address Size */ +#define E1000_EECD_SELSHAD 0x00020000 /* Select Shadow RAM */ +#define E1000_EECD_INITSRAM 0x00040000 /* Initialize Shadow RAM */ +#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */ +#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */ +#define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */ +#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */ +#define E1000_EECD_SECVAL_SHIFT 22 + +#define E1000_NVM_SWDPIN0 0x0001 /* SWDPIN 0 NVM Value */ +#define E1000_NVM_LED_LOGIC 0x0020 /* Led Logic Word */ +#define E1000_NVM_RW_REG_DATA 16 /* Offset to data in NVM read/write registers */ +#define E1000_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */ +#define E1000_NVM_RW_REG_START 1 /* Start operation */ +#define E1000_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */ +#define E1000_NVM_POLL_WRITE 1 /* Flag for polling for write complete */ +#define E1000_NVM_POLL_READ 0 /* Flag for polling for read complete */ +#define E1000_FLASH_UPDATES 2000 + +/* NVM Word Offsets */ +#define NVM_COMPAT 0x0003 +#define NVM_ID_LED_SETTINGS 0x0004 +#define NVM_VERSION 0x0005 +#define NVM_SERDES_AMPLITUDE 0x0006 /* For SERDES output amplitude adjustment. */ +#define NVM_PHY_CLASS_WORD 0x0007 +#define NVM_INIT_CONTROL1_REG 0x000A +#define NVM_INIT_CONTROL2_REG 0x000F +#define NVM_SWDEF_PINS_CTRL_PORT_1 0x0010 +#define NVM_INIT_CONTROL3_PORT_B 0x0014 +#define NVM_INIT_3GIO_3 0x001A +#define NVM_SWDEF_PINS_CTRL_PORT_0 0x0020 +#define NVM_INIT_CONTROL3_PORT_A 0x0024 +#define NVM_CFG 0x0012 +#define NVM_FLASH_VERSION 0x0032 +#define NVM_ALT_MAC_ADDR_PTR 0x0037 +#define NVM_CHECKSUM_REG 0x003F + +#define E1000_NVM_CFG_DONE_PORT_0 0x40000 /* MNG config cycle done */ +#define E1000_NVM_CFG_DONE_PORT_1 0x80000 /* ...for second port */ + +/* Mask bits for fields in Word 0x0f of the NVM */ +#define NVM_WORD0F_PAUSE_MASK 0x3000 +#define NVM_WORD0F_PAUSE 0x1000 +#define NVM_WORD0F_ASM_DIR 0x2000 +#define NVM_WORD0F_ANE 0x0800 +#define NVM_WORD0F_SWPDIO_EXT_MASK 0x00F0 +#define NVM_WORD0F_LPLU 0x0001 + +/* Mask bits for fields in Word 0x1a of the NVM */ +#define NVM_WORD1A_ASPM_MASK 0x000C + +/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */ +#define NVM_SUM 0xBABA + +#define NVM_MAC_ADDR_OFFSET 0 +#define NVM_PBA_OFFSET_0 8 +#define NVM_PBA_OFFSET_1 9 +#define NVM_RESERVED_WORD 0xFFFF +#define NVM_PHY_CLASS_A 0x8000 +#define NVM_SERDES_AMPLITUDE_MASK 0x000F +#define NVM_SIZE_MASK 0x1C00 +#define NVM_SIZE_SHIFT 10 +#define NVM_WORD_SIZE_BASE_SHIFT 6 +#define NVM_SWDPIO_EXT_SHIFT 4 + +/* NVM Commands - Microwire */ +#define NVM_READ_OPCODE_MICROWIRE 0x6 /* NVM read opcode */ +#define NVM_WRITE_OPCODE_MICROWIRE 0x5 /* NVM write opcode */ +#define NVM_ERASE_OPCODE_MICROWIRE 0x7 /* NVM erase opcode */ +#define NVM_EWEN_OPCODE_MICROWIRE 0x13 /* NVM erase/write enable */ +#define NVM_EWDS_OPCODE_MICROWIRE 0x10 /* NVM erase/write disable */ + +/* NVM Commands - SPI */ +#define NVM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */ +#define NVM_READ_OPCODE_SPI 0x03 /* NVM read opcode */ +#define NVM_WRITE_OPCODE_SPI 0x02 /* NVM write opcode */ +#define NVM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */ +#define NVM_WREN_OPCODE_SPI 0x06 /* NVM set Write Enable latch */ +#define NVM_WRDI_OPCODE_SPI 0x04 /* NVM reset Write Enable latch */ +#define NVM_RDSR_OPCODE_SPI 0x05 /* NVM read Status register */ +#define NVM_WRSR_OPCODE_SPI 0x01 /* NVM write Status register */ + +/* SPI NVM Status Register */ +#define NVM_STATUS_RDY_SPI 0x01 +#define NVM_STATUS_WEN_SPI 0x02 +#define NVM_STATUS_BP0_SPI 0x04 +#define NVM_STATUS_BP1_SPI 0x08 +#define NVM_STATUS_WPEN_SPI 0x80 + +/* Word definitions for ID LED Settings */ +#define ID_LED_RESERVED_0000 0x0000 +#define ID_LED_RESERVED_FFFF 0xFFFF +#define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \ + (ID_LED_OFF1_OFF2 << 8) | \ + (ID_LED_DEF1_DEF2 << 4) | \ + (ID_LED_DEF1_DEF2)) +#define ID_LED_DEF1_DEF2 0x1 +#define ID_LED_DEF1_ON2 0x2 +#define ID_LED_DEF1_OFF2 0x3 +#define ID_LED_ON1_DEF2 0x4 +#define ID_LED_ON1_ON2 0x5 +#define ID_LED_ON1_OFF2 0x6 +#define ID_LED_OFF1_DEF2 0x7 +#define ID_LED_OFF1_ON2 0x8 +#define ID_LED_OFF1_OFF2 0x9 + +#define IGP_ACTIVITY_LED_MASK 0xFFFFF0FF +#define IGP_ACTIVITY_LED_ENABLE 0x0300 +#define IGP_LED3_MODE 0x07000000 + +/* PCI/PCI-X/PCI-EX Config space */ +#define PCIX_COMMAND_REGISTER 0xE6 +#define PCIX_STATUS_REGISTER_LO 0xE8 +#define PCIX_STATUS_REGISTER_HI 0xEA +#define PCI_HEADER_TYPE_REGISTER 0x0E +#define PCIE_LINK_STATUS 0x12 + +#define PCIX_COMMAND_MMRBC_MASK 0x000C +#define PCIX_COMMAND_MMRBC_SHIFT 0x2 +#define PCIX_STATUS_HI_MMRBC_MASK 0x0060 +#define PCIX_STATUS_HI_MMRBC_SHIFT 0x5 +#define PCIX_STATUS_HI_MMRBC_4K 0x3 +#define PCIX_STATUS_HI_MMRBC_2K 0x2 +#define PCIX_STATUS_LO_FUNC_MASK 0x7 +#define PCI_HEADER_TYPE_MULTIFUNC 0x80 +#define PCIE_LINK_WIDTH_MASK 0x3F0 +#define PCIE_LINK_WIDTH_SHIFT 4 + +#ifndef ETH_ADDR_LEN +#define ETH_ADDR_LEN 6 +#endif + +#define PHY_REVISION_MASK 0xFFFFFFF0 +#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ +#define MAX_PHY_MULTI_PAGE_REG 0xF + +/* Bit definitions for valid PHY IDs. */ +/* + * I = Integrated + * E = External + */ +#define M88E1000_E_PHY_ID 0x01410C50 +#define M88E1000_I_PHY_ID 0x01410C30 +#define M88E1011_I_PHY_ID 0x01410C20 +#define IGP01E1000_I_PHY_ID 0x02A80380 +#define M88E1011_I_REV_4 0x04 +#define M88E1111_I_PHY_ID 0x01410CC0 +#define GG82563_E_PHY_ID 0x01410CA0 +#define IGP03E1000_E_PHY_ID 0x02A80390 +#define IFE_E_PHY_ID 0x02A80330 +#define IFE_PLUS_E_PHY_ID 0x02A80320 +#define IFE_C_E_PHY_ID 0x02A80310 +#define BME1000_E_PHY_ID 0x01410CB0 +#define BME1000_E_PHY_ID_R2 0x01410CB1 +#define M88_VENDOR 0x0141 + +/* M88E1000 Specific Registers */ +#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ +#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */ +#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */ +#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */ +#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ +#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */ + +#define M88E1000_PHY_EXT_CTRL 0x1A /* PHY extend control register */ +#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */ +#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */ +#define M88E1000_PHY_VCO_REG_BIT8 0x100 /* Bits 8 & 11 are adjusted for */ +#define M88E1000_PHY_VCO_REG_BIT11 0x800 /* improved BER performance */ + +/* M88E1000 PHY Specific Control Register */ +#define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ +#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */ +#define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */ +/* 1=CLK125 low, 0=CLK125 toggling */ +#define M88E1000_PSCR_CLK125_DISABLE 0x0010 +#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */ + /* Manual MDI configuration */ +#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ +/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */ +#define M88E1000_PSCR_AUTO_X_1000T 0x0040 +/* Auto crossover enabled all speeds */ +#define M88E1000_PSCR_AUTO_X_MODE 0x0060 +/* + * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold + * 0=Normal 10BASE-T Rx Threshold + */ +#define M88E1000_PSCR_EN_10BT_EXT_DIST 0x0080 +/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */ +#define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100 +#define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */ +#define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */ +#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */ + +/* M88E1000 PHY Specific Status Register */ +#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */ +#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */ +#define M88E1000_PSSR_DOWNSHIFT 0x0020 /* 1=Downshifted */ +#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */ +/* + * 0 = <50M + * 1 = 50-80M + * 2 = 80-110M + * 3 = 110-140M + * 4 = >140M + */ +#define M88E1000_PSSR_CABLE_LENGTH 0x0380 +#define M88E1000_PSSR_LINK 0x0400 /* 1=Link up, 0=Link down */ +#define M88E1000_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */ +#define M88E1000_PSSR_PAGE_RCVD 0x1000 /* 1=Page received */ +#define M88E1000_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */ +#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ +#define M88E1000_PSSR_10MBS 0x0000 /* 00=10Mbs */ +#define M88E1000_PSSR_100MBS 0x4000 /* 01=100Mbs */ +#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ + +#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7 + +/* M88E1000 Extended PHY Specific Control Register */ +#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */ +/* + * 1 = Lost lock detect enabled. + * Will assert lost lock and bring + * link down if idle not seen + * within 1ms in 1000BASE-T + */ +#define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000 +/* + * Number of times we will attempt to autonegotiate before downshifting if we + * are the master + */ +#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00 +#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000 +#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X 0x0400 +#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X 0x0800 +#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X 0x0C00 +/* + * Number of times we will attempt to autonegotiate before downshifting if we + * are the slave + */ +#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK 0x0300 +#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS 0x0000 +#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100 +#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X 0x0200 +#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X 0x0300 +#define M88E1000_EPSCR_TX_CLK_2_5 0x0060 /* 2.5 MHz TX_CLK */ +#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ +#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */ + +/* M88EC018 Rev 2 specific DownShift settings */ +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X 0x0000 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X 0x0200 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X 0x0400 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X 0x0600 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X 0x0A00 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X 0x0C00 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X 0x0E00 + +/* BME1000 PHY Specific Control Register */ +#define BME1000_PSCR_ENABLE_DOWNSHIFT 0x0800 /* 1 = enable downshift */ + +/* + * Bits... + * 15-5: page + * 4-0: register offset + */ +#define GG82563_PAGE_SHIFT 5 +#define GG82563_REG(page, reg) \ + (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS)) +#define GG82563_MIN_ALT_REG 30 + +/* GG82563 Specific Registers */ +#define GG82563_PHY_SPEC_CTRL \ + GG82563_REG(0, 16) /* PHY Specific Control */ +#define GG82563_PHY_SPEC_STATUS \ + GG82563_REG(0, 17) /* PHY Specific Status */ +#define GG82563_PHY_INT_ENABLE \ + GG82563_REG(0, 18) /* Interrupt Enable */ +#define GG82563_PHY_SPEC_STATUS_2 \ + GG82563_REG(0, 19) /* PHY Specific Status 2 */ +#define GG82563_PHY_RX_ERR_CNTR \ + GG82563_REG(0, 21) /* Receive Error Counter */ +#define GG82563_PHY_PAGE_SELECT \ + GG82563_REG(0, 22) /* Page Select */ +#define GG82563_PHY_SPEC_CTRL_2 \ + GG82563_REG(0, 26) /* PHY Specific Control 2 */ +#define GG82563_PHY_PAGE_SELECT_ALT \ + GG82563_REG(0, 29) /* Alternate Page Select */ +#define GG82563_PHY_TEST_CLK_CTRL \ + GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */ + +#define GG82563_PHY_MAC_SPEC_CTRL \ + GG82563_REG(2, 21) /* MAC Specific Control Register */ +#define GG82563_PHY_MAC_SPEC_CTRL_2 \ + GG82563_REG(2, 26) /* MAC Specific Control 2 */ + +#define GG82563_PHY_DSP_DISTANCE \ + GG82563_REG(5, 26) /* DSP Distance */ + +/* Page 193 - Port Control Registers */ +#define GG82563_PHY_KMRN_MODE_CTRL \ + GG82563_REG(193, 16) /* Kumeran Mode Control */ +#define GG82563_PHY_PORT_RESET \ + GG82563_REG(193, 17) /* Port Reset */ +#define GG82563_PHY_REVISION_ID \ + GG82563_REG(193, 18) /* Revision ID */ +#define GG82563_PHY_DEVICE_ID \ + GG82563_REG(193, 19) /* Device ID */ +#define GG82563_PHY_PWR_MGMT_CTRL \ + GG82563_REG(193, 20) /* Power Management Control */ +#define GG82563_PHY_RATE_ADAPT_CTRL \ + GG82563_REG(193, 25) /* Rate Adaptation Control */ + +/* Page 194 - KMRN Registers */ +#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \ + GG82563_REG(194, 16) /* FIFO's Control/Status */ +#define GG82563_PHY_KMRN_CTRL \ + GG82563_REG(194, 17) /* Control */ +#define GG82563_PHY_INBAND_CTRL \ + GG82563_REG(194, 18) /* Inband Control */ +#define GG82563_PHY_KMRN_DIAGNOSTIC \ + GG82563_REG(194, 19) /* Diagnostic */ +#define GG82563_PHY_ACK_TIMEOUTS \ + GG82563_REG(194, 20) /* Acknowledge Timeouts */ +#define GG82563_PHY_ADV_ABILITY \ + GG82563_REG(194, 21) /* Advertised Ability */ +#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \ + GG82563_REG(194, 23) /* Link Partner Advertised Ability */ +#define GG82563_PHY_ADV_NEXT_PAGE \ + GG82563_REG(194, 24) /* Advertised Next Page */ +#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \ + GG82563_REG(194, 25) /* Link Partner Advertised Next page */ +#define GG82563_PHY_KMRN_MISC \ + GG82563_REG(194, 26) /* Misc. */ + +/* MDI Control */ +#define E1000_MDIC_DATA_MASK 0x0000FFFF +#define E1000_MDIC_REG_MASK 0x001F0000 +#define E1000_MDIC_REG_SHIFT 16 +#define E1000_MDIC_PHY_MASK 0x03E00000 +#define E1000_MDIC_PHY_SHIFT 21 +#define E1000_MDIC_OP_WRITE 0x04000000 +#define E1000_MDIC_OP_READ 0x08000000 +#define E1000_MDIC_READY 0x10000000 +#define E1000_MDIC_INT_EN 0x20000000 +#define E1000_MDIC_ERROR 0x40000000 + +/* SerDes Control */ +#define E1000_GEN_CTL_READY 0x80000000 +#define E1000_GEN_CTL_ADDRESS_SHIFT 8 +#define E1000_GEN_POLL_TIMEOUT 640 + +#endif --- linux-2.6.27.orig/ubuntu/e1000e/e1000_mac.c +++ linux-2.6.27/ubuntu/e1000e/e1000_mac.c @@ -0,0 +1,1968 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include "e1000_hw.h" + +/** + * e1000_init_mac_ops_generic - Initialize MAC function pointers + * @hw: pointer to the HW structure + * + * Setups up the function pointers to no-op functions + **/ +void e1000_init_mac_ops_generic(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + DEBUGFUNC("e1000_init_mac_ops_generic"); + + /* General Setup */ + mac->ops.read_mac_addr = e1000_read_mac_addr_generic; + mac->ops.remove_device = e1000_remove_device_generic; + mac->ops.config_collision_dist = e1000_config_collision_dist_generic; + /* LINK */ + mac->ops.wait_autoneg = e1000_wait_autoneg_generic; + /* Management */ + mac->ops.mng_host_if_write = e1000_mng_host_if_write_generic; + mac->ops.mng_write_cmd_header = e1000_mng_write_cmd_header_generic; + mac->ops.mng_enable_host_if = e1000_mng_enable_host_if_generic; + /* VLAN, MC, etc. */ + mac->ops.rar_set = e1000_rar_set_generic; + mac->ops.validate_mdi_setting = e1000_validate_mdi_setting_generic; +} + +/** + * e1000_remove_device_generic - Free device specific structure + * @hw: pointer to the HW structure + * + * If a device specific structure was allocated, this function will + * free it. + **/ +void e1000_remove_device_generic(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_remove_device_generic"); + + /* Freeing the dev_spec member of e1000_hw structure */ + e1000_free_dev_spec_struct(hw); +} + +/** + * e1000_get_bus_info_pcie_generic - Get PCIe bus information + * @hw: pointer to the HW structure + * + * Determines and stores the system bus information for a particular + * network interface. The following bus information is determined and stored: + * bus speed, bus width, type (PCIe), and PCIe function. + **/ +s32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw) +{ + struct e1000_bus_info *bus = &hw->bus; + s32 ret_val; + u32 status; + u16 pcie_link_status, pci_header_type; + + DEBUGFUNC("e1000_get_bus_info_pcie_generic"); + + bus->type = e1000_bus_type_pci_express; + bus->speed = e1000_bus_speed_2500; + + ret_val = e1000_read_pcie_cap_reg(hw, + PCIE_LINK_STATUS, + &pcie_link_status); + if (ret_val) + bus->width = e1000_bus_width_unknown; + else + bus->width = (e1000_bus_width)((pcie_link_status & + PCIE_LINK_WIDTH_MASK) >> + PCIE_LINK_WIDTH_SHIFT); + + e1000_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type); + if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) { + status = E1000_READ_REG(hw, E1000_STATUS); + bus->func = (status & E1000_STATUS_FUNC_MASK) + >> E1000_STATUS_FUNC_SHIFT; + } else { + bus->func = 0; + } + + return E1000_SUCCESS; +} + +/** + * e1000_clear_vfta_generic - Clear VLAN filter table + * @hw: pointer to the HW structure + * + * Clears the register array which contains the VLAN filter table by + * setting all the values to 0. + **/ +void e1000_clear_vfta_generic(struct e1000_hw *hw) +{ + u32 offset; + + DEBUGFUNC("e1000_clear_vfta_generic"); + + for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { + E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0); + E1000_WRITE_FLUSH(hw); + } +} + +/** + * e1000_write_vfta_generic - Write value to VLAN filter table + * @hw: pointer to the HW structure + * @offset: register offset in VLAN filter table + * @value: register value written to VLAN filter table + * + * Writes value at the given offset in the register array which stores + * the VLAN filter table. + **/ +void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value) +{ + DEBUGFUNC("e1000_write_vfta_generic"); + + E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value); + E1000_WRITE_FLUSH(hw); +} + +/** + * e1000_init_rx_addrs_generic - Initialize receive address's + * @hw: pointer to the HW structure + * @rar_count: receive address registers + * + * Setups the receive address registers by setting the base receive address + * register to the devices MAC address and clearing all the other receive + * address registers to 0. + **/ +void e1000_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count) +{ + u32 i; + + DEBUGFUNC("e1000_init_rx_addrs_generic"); + + /* Setup the receive address */ + DEBUGOUT("Programming MAC Address into RAR[0]\n"); + + hw->mac.ops.rar_set(hw, hw->mac.addr, 0); + + /* Zero out the other (rar_entry_count - 1) receive addresses */ + DEBUGOUT1("Clearing RAR[1-%u]\n", rar_count-1); + for (i = 1; i < rar_count; i++) { + E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1), 0); + E1000_WRITE_FLUSH(hw); + E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((i << 1) + 1), 0); + E1000_WRITE_FLUSH(hw); + } +} + +/** + * e1000_check_alt_mac_addr_generic - Check for alternate MAC addr + * @hw: pointer to the HW structure + * + * Checks the nvm for an alternate MAC address. An alternate MAC address + * can be setup by pre-boot software and must be treated like a permanent + * address and must override the actual permanent MAC address. If an + * alternate MAC address is found it is saved in the hw struct and + * programmed into RAR0 and the function returns success, otherwise the + * function returns an error. + **/ +s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw) +{ + u32 i; + s32 ret_val = E1000_SUCCESS; + u16 offset, nvm_alt_mac_addr_offset, nvm_data; + u8 alt_mac_addr[ETH_ADDR_LEN]; + + DEBUGFUNC("e1000_check_alt_mac_addr_generic"); + + ret_val = hw->nvm.ops.read(hw, NVM_ALT_MAC_ADDR_PTR, 1, + &nvm_alt_mac_addr_offset); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + + if (nvm_alt_mac_addr_offset == 0xFFFF) { + ret_val = -(E1000_NOT_IMPLEMENTED); + goto out; + } + + if (hw->bus.func == E1000_FUNC_1) + nvm_alt_mac_addr_offset += ETH_ADDR_LEN/sizeof(u16); + + for (i = 0; i < ETH_ADDR_LEN; i += 2) { + offset = nvm_alt_mac_addr_offset + (i >> 1); + ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + + alt_mac_addr[i] = (u8)(nvm_data & 0xFF); + alt_mac_addr[i + 1] = (u8)(nvm_data >> 8); + } + + /* if multicast bit is set, the alternate address will not be used */ + if (alt_mac_addr[0] & 0x01) { + ret_val = -(E1000_NOT_IMPLEMENTED); + goto out; + } + + for (i = 0; i < ETH_ADDR_LEN; i++) + hw->mac.addr[i] = hw->mac.perm_addr[i] = alt_mac_addr[i]; + + hw->mac.ops.rar_set(hw, hw->mac.perm_addr, 0); + +out: + return ret_val; +} + +/** + * e1000_rar_set_generic - Set receive address register + * @hw: pointer to the HW structure + * @addr: pointer to the receive address + * @index: receive address array register + * + * Sets the receive address array register at index to the address passed + * in by addr. + **/ +void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index) +{ + u32 rar_low, rar_high; + + DEBUGFUNC("e1000_rar_set_generic"); + + /* + * HW expects these in little endian so we reverse the byte order + * from network order (big endian) to little endian + */ + rar_low = ((u32) addr[0] | + ((u32) addr[1] << 8) | + ((u32) addr[2] << 16) | ((u32) addr[3] << 24)); + + rar_high = ((u32) addr[4] | ((u32) addr[5] << 8)); + + /* If MAC address zero, no need to set the AV bit */ + if (rar_low || rar_high) { + if (!hw->mac.disable_av) + rar_high |= E1000_RAH_AV; + } + + E1000_WRITE_REG(hw, E1000_RAL(index), rar_low); + E1000_WRITE_REG(hw, E1000_RAH(index), rar_high); +} + +/** + * e1000_mta_set_generic - Set multicast filter table address + * @hw: pointer to the HW structure + * @hash_value: determines the MTA register and bit to set + * + * The multicast table address is a register array of 32-bit registers. + * The hash_value is used to determine what register the bit is in, the + * current value is read, the new bit is OR'd in and the new value is + * written back into the register. + **/ +void e1000_mta_set_generic(struct e1000_hw *hw, u32 hash_value) +{ + u32 hash_bit, hash_reg, mta; + + DEBUGFUNC("e1000_mta_set_generic"); + /* + * The MTA is a register array of 32-bit registers. It is + * treated like an array of (32*mta_reg_count) bits. We want to + * set bit BitArray[hash_value]. So we figure out what register + * the bit is in, read it, OR in the new bit, then write + * back the new value. The (hw->mac.mta_reg_count - 1) serves as a + * mask to bits 31:5 of the hash value which gives us the + * register we're modifying. The hash bit within that register + * is determined by the lower 5 bits of the hash value. + */ + hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); + hash_bit = hash_value & 0x1F; + + mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg); + + mta |= (1 << hash_bit); + + E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta); + E1000_WRITE_FLUSH(hw); +} + +/** + * e1000_update_mc_addr_list_generic - Update Multicast addresses + * @hw: pointer to the HW structure + * @mc_addr_list: array of multicast addresses to program + * @mc_addr_count: number of multicast addresses to program + * @rar_used_count: the first RAR register free to program + * @rar_count: total number of supported Receive Address Registers + * + * Updates the Receive Address Registers and Multicast Table Array. + * The caller must have a packed mc_addr_list of multicast addresses. + * The parameter rar_count will usually be hw->mac.rar_entry_count + * unless there are workarounds that change this. + **/ +void e1000_update_mc_addr_list_generic(struct e1000_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count, + u32 rar_used_count, u32 rar_count) +{ + u32 hash_value; + u32 i; + + DEBUGFUNC("e1000_update_mc_addr_list_generic"); + + /* + * Load the first set of multicast addresses into the exact + * filters (RAR). If there are not enough to fill the RAR + * array, clear the filters. + */ + for (i = rar_used_count; i < rar_count; i++) { + if (mc_addr_count) { + hw->mac.ops.rar_set(hw, mc_addr_list, i); + mc_addr_count--; + mc_addr_list += ETH_ADDR_LEN; + } else { + E1000_WRITE_REG_ARRAY(hw, E1000_RA, i << 1, 0); + E1000_WRITE_FLUSH(hw); + E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1) + 1, 0); + E1000_WRITE_FLUSH(hw); + } + } + + /* Clear the old settings from the MTA */ + DEBUGOUT("Clearing MTA\n"); + for (i = 0; i < hw->mac.mta_reg_count; i++) { + E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); + E1000_WRITE_FLUSH(hw); + } + + /* Load any remaining multicast addresses into the hash table. */ + for (; mc_addr_count > 0; mc_addr_count--) { + hash_value = e1000_hash_mc_addr_generic(hw, mc_addr_list); + DEBUGOUT1("Hash value = 0x%03X\n", hash_value); + hw->mac.ops.mta_set(hw, hash_value); + mc_addr_list += ETH_ADDR_LEN; + } +} + +/** + * e1000_hash_mc_addr_generic - Generate a multicast hash value + * @hw: pointer to the HW structure + * @mc_addr: pointer to a multicast address + * + * Generates a multicast address hash value which is used to determine + * the multicast filter table array address and new table value. See + * e1000_mta_set_generic() + **/ +u32 e1000_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr) +{ + u32 hash_value, hash_mask; + u8 bit_shift = 0; + + DEBUGFUNC("e1000_hash_mc_addr_generic"); + + /* Register count multiplied by bits per register */ + hash_mask = (hw->mac.mta_reg_count * 32) - 1; + + /* + * For a mc_filter_type of 0, bit_shift is the number of left-shifts + * where 0xFF would still fall within the hash mask. + */ + while (hash_mask >> bit_shift != 0xFF) + bit_shift++; + + /* + * The portion of the address that is used for the hash table + * is determined by the mc_filter_type setting. + * The algorithm is such that there is a total of 8 bits of shifting. + * The bit_shift for a mc_filter_type of 0 represents the number of + * left-shifts where the MSB of mc_addr[5] would still fall within + * the hash_mask. Case 0 does this exactly. Since there are a total + * of 8 bits of shifting, then mc_addr[4] will shift right the + * remaining number of bits. Thus 8 - bit_shift. The rest of the + * cases are a variation of this algorithm...essentially raising the + * number of bits to shift mc_addr[5] left, while still keeping the + * 8-bit shifting total. + * + * For example, given the following Destination MAC Address and an + * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask), + * we can see that the bit_shift for case 0 is 4. These are the hash + * values resulting from each mc_filter_type... + * [0] [1] [2] [3] [4] [5] + * 01 AA 00 12 34 56 + * LSB MSB + * + * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563 + * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6 + * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163 + * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634 + */ + switch (hw->mac.mc_filter_type) { + default: + case 0: + break; + case 1: + bit_shift += 1; + break; + case 2: + bit_shift += 2; + break; + case 3: + bit_shift += 4; + break; + } + + hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) | + (((u16) mc_addr[5]) << bit_shift))); + + return hash_value; +} + +/** + * e1000_clear_hw_cntrs_base_generic - Clear base hardware counters + * @hw: pointer to the HW structure + * + * Clears the base hardware counters by reading the counter registers. + **/ +void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw) +{ + volatile u32 temp; + + DEBUGFUNC("e1000_clear_hw_cntrs_base_generic"); + + temp = E1000_READ_REG(hw, E1000_CRCERRS); + temp = E1000_READ_REG(hw, E1000_SYMERRS); + temp = E1000_READ_REG(hw, E1000_MPC); + temp = E1000_READ_REG(hw, E1000_SCC); + temp = E1000_READ_REG(hw, E1000_ECOL); + temp = E1000_READ_REG(hw, E1000_MCC); + temp = E1000_READ_REG(hw, E1000_LATECOL); + temp = E1000_READ_REG(hw, E1000_COLC); + temp = E1000_READ_REG(hw, E1000_DC); + temp = E1000_READ_REG(hw, E1000_SEC); + temp = E1000_READ_REG(hw, E1000_RLEC); + temp = E1000_READ_REG(hw, E1000_XONRXC); + temp = E1000_READ_REG(hw, E1000_XONTXC); + temp = E1000_READ_REG(hw, E1000_XOFFRXC); + temp = E1000_READ_REG(hw, E1000_XOFFTXC); + temp = E1000_READ_REG(hw, E1000_FCRUC); + temp = E1000_READ_REG(hw, E1000_GPRC); + temp = E1000_READ_REG(hw, E1000_BPRC); + temp = E1000_READ_REG(hw, E1000_MPRC); + temp = E1000_READ_REG(hw, E1000_GPTC); + temp = E1000_READ_REG(hw, E1000_GORCL); + temp = E1000_READ_REG(hw, E1000_GORCH); + temp = E1000_READ_REG(hw, E1000_GOTCL); + temp = E1000_READ_REG(hw, E1000_GOTCH); + temp = E1000_READ_REG(hw, E1000_RNBC); + temp = E1000_READ_REG(hw, E1000_RUC); + temp = E1000_READ_REG(hw, E1000_RFC); + temp = E1000_READ_REG(hw, E1000_ROC); + temp = E1000_READ_REG(hw, E1000_RJC); + temp = E1000_READ_REG(hw, E1000_TORL); + temp = E1000_READ_REG(hw, E1000_TORH); + temp = E1000_READ_REG(hw, E1000_TOTL); + temp = E1000_READ_REG(hw, E1000_TOTH); + temp = E1000_READ_REG(hw, E1000_TPR); + temp = E1000_READ_REG(hw, E1000_TPT); + temp = E1000_READ_REG(hw, E1000_MPTC); + temp = E1000_READ_REG(hw, E1000_BPTC); +} + +/** + * e1000_check_for_copper_link_generic - Check for link (Copper) + * @hw: pointer to the HW structure + * + * Checks to see of the link status of the hardware has changed. If a + * change in link status has been detected, then we read the PHY registers + * to get the current speed/duplex if link exists. + **/ +s32 e1000_check_for_copper_link_generic(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + bool link; + + DEBUGFUNC("e1000_check_for_copper_link"); + + /* + * We only want to go out to the PHY registers to see if Auto-Neg + * has completed and/or if our link status has changed. The + * get_link_status flag is set upon receiving a Link Status + * Change or Rx Sequence Error interrupt. + */ + if (!mac->get_link_status) { + ret_val = E1000_SUCCESS; + goto out; + } + + /* + * First we want to see if the MII Status Register reports + * link. If so, then we want to get the current speed/duplex + * of the PHY. + */ + ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + goto out; + + if (!link) + goto out; /* No link detected */ + + mac->get_link_status = false; + + /* + * Check if there was DownShift, must be checked + * immediately after link-up + */ + e1000_check_downshift_generic(hw); + + /* + * If we are forcing speed/duplex, then we simply return since + * we have already determined whether we have link or not. + */ + if (!mac->autoneg) { + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + /* + * Auto-Neg is enabled. Auto Speed Detection takes care + * of MAC speed/duplex configuration. So we only need to + * configure Collision Distance in the MAC. + */ + e1000_config_collision_dist_generic(hw); + + /* + * Configure Flow Control now that Auto-Neg has completed. + * First, we need to restore the desired flow control + * settings because we may have had to re-autoneg with a + * different link partner. + */ + ret_val = e1000_config_fc_after_link_up_generic(hw); + if (ret_val) { + DEBUGOUT("Error configuring flow control\n"); + } + +out: + return ret_val; +} + +/** + * e1000_check_for_fiber_link_generic - Check for link (Fiber) + * @hw: pointer to the HW structure + * + * Checks for link up on the hardware. If link is not up and we have + * a signal, then we need to force link up. + **/ +s32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 rxcw; + u32 ctrl; + u32 status; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_check_for_fiber_link_generic"); + + ctrl = E1000_READ_REG(hw, E1000_CTRL); + status = E1000_READ_REG(hw, E1000_STATUS); + rxcw = E1000_READ_REG(hw, E1000_RXCW); + + /* + * If we don't have link (auto-negotiation failed or link partner + * cannot auto-negotiate), the cable is plugged in (we have signal), + * and our link partner is not trying to auto-negotiate with us (we + * are receiving idles or data), we need to force link up. We also + * need to give auto-negotiation time to complete, in case the cable + * was just plugged in. The autoneg_failed flag does this. + */ + /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */ + if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) && + (!(rxcw & E1000_RXCW_C))) { + if (mac->autoneg_failed == 0) { + mac->autoneg_failed = 1; + goto out; + } + DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n"); + + /* Disable auto-negotiation in the TXCW register */ + E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE)); + + /* Force link-up and also force full-duplex. */ + ctrl = E1000_READ_REG(hw, E1000_CTRL); + ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); + E1000_WRITE_REG(hw, E1000_CTRL, ctrl); + + /* Configure Flow Control after forcing link up. */ + ret_val = e1000_config_fc_after_link_up_generic(hw); + if (ret_val) { + DEBUGOUT("Error configuring flow control\n"); + goto out; + } + } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) { + /* + * If we are forcing link and we are receiving /C/ ordered + * sets, re-enable auto-negotiation in the TXCW register + * and disable forced link in the Device Control register + * in an attempt to auto-negotiate with our link partner. + */ + DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n"); + E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw); + E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU)); + + mac->serdes_has_link = true; + } + +out: + return ret_val; +} + +/** + * e1000_check_for_serdes_link_generic - Check for link (Serdes) + * @hw: pointer to the HW structure + * + * Checks for link up on the hardware. If link is not up and we have + * a signal, then we need to force link up. + **/ +s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 rxcw; + u32 ctrl; + u32 status; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_check_for_serdes_link_generic"); + + ctrl = E1000_READ_REG(hw, E1000_CTRL); + status = E1000_READ_REG(hw, E1000_STATUS); + rxcw = E1000_READ_REG(hw, E1000_RXCW); + + /* + * If we don't have link (auto-negotiation failed or link partner + * cannot auto-negotiate), and our link partner is not trying to + * auto-negotiate with us (we are receiving idles or data), + * we need to force link up. We also need to give auto-negotiation + * time to complete. + */ + /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */ + if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) { + if (mac->autoneg_failed == 0) { + mac->autoneg_failed = 1; + goto out; + } + DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n"); + + /* Disable auto-negotiation in the TXCW register */ + E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE)); + + /* Force link-up and also force full-duplex. */ + ctrl = E1000_READ_REG(hw, E1000_CTRL); + ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); + E1000_WRITE_REG(hw, E1000_CTRL, ctrl); + + /* Configure Flow Control after forcing link up. */ + ret_val = e1000_config_fc_after_link_up_generic(hw); + if (ret_val) { + DEBUGOUT("Error configuring flow control\n"); + goto out; + } + } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) { + /* + * If we are forcing link and we are receiving /C/ ordered + * sets, re-enable auto-negotiation in the TXCW register + * and disable forced link in the Device Control register + * in an attempt to auto-negotiate with our link partner. + */ + DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n"); + E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw); + E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU)); + + mac->serdes_has_link = true; + } else if (!(E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW))) { + /* + * If we force link for non-auto-negotiation switch, check + * link status based on MAC synchronization for internal + * serdes media type. + */ + /* SYNCH bit and IV bit are sticky. */ + usec_delay(10); + if (E1000_RXCW_SYNCH & E1000_READ_REG(hw, E1000_RXCW)) { + if (!(rxcw & E1000_RXCW_IV)) { + mac->serdes_has_link = true; + DEBUGOUT("SERDES: Link is up.\n"); + } + } else { + mac->serdes_has_link = false; + DEBUGOUT("SERDES: Link is down.\n"); + } + } + + if (E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW)) { + status = E1000_READ_REG(hw, E1000_STATUS); + mac->serdes_has_link = (status & E1000_STATUS_LU) + ? true + : false; + } + +out: + return ret_val; +} + +/** + * e1000_setup_link_generic - Setup flow control and link settings + * @hw: pointer to the HW structure + * + * Determines which flow control settings to use, then configures flow + * control. Calls the appropriate media-specific link configuration + * function. Assuming the adapter has a valid link partner, a valid link + * should be established. Assumes the hardware has previously been reset + * and the transmitter and receiver are not enabled. + **/ +s32 e1000_setup_link_generic(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_setup_link_generic"); + + /* + * In the case of the phy reset being blocked, we already have a link. + * We do not need to set it up again. + */ + if (hw->phy.ops.check_reset_block) + if (hw->phy.ops.check_reset_block(hw)) + goto out; + + /* + * If flow control is set to default, set flow control based on + * the EEPROM flow control settings. + */ + if (hw->fc.type == e1000_fc_default) { + ret_val = e1000_set_default_fc_generic(hw); + if (ret_val) + goto out; + } + + /* + * We want to save off the original Flow Control configuration just + * in case we get disconnected and then reconnected into a different + * hub or switch with different Flow Control capabilities. + */ + hw->fc.original_type = hw->fc.type; + + DEBUGOUT1("After fix-ups FlowControl is now = %x\n", hw->fc.type); + + /* Call the necessary media_type subroutine to configure the link. */ + ret_val = hw->mac.ops.setup_physical_interface(hw); + if (ret_val) + goto out; + + /* + * Initialize the flow control address, type, and PAUSE timer + * registers to their default values. This is done even if flow + * control is disabled, because it does not hurt anything to + * initialize these registers. + */ + DEBUGOUT("Initializing the Flow Control address, type and timer regs\n"); + E1000_WRITE_REG(hw, E1000_FCT, FLOW_CONTROL_TYPE); + E1000_WRITE_REG(hw, E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH); + E1000_WRITE_REG(hw, E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW); + + E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time); + + ret_val = e1000_set_fc_watermarks_generic(hw); + +out: + return ret_val; +} + +/** + * e1000_setup_fiber_serdes_link_generic - Setup link for fiber/serdes + * @hw: pointer to the HW structure + * + * Configures collision distance and flow control for fiber and serdes + * links. Upon successful setup, poll for link. + **/ +s32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw) +{ + u32 ctrl; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_setup_fiber_serdes_link_generic"); + + ctrl = E1000_READ_REG(hw, E1000_CTRL); + + /* Take the link out of reset */ + ctrl &= ~E1000_CTRL_LRST; + + e1000_config_collision_dist_generic(hw); + + ret_val = e1000_commit_fc_settings_generic(hw); + if (ret_val) + goto out; + + /* + * Since auto-negotiation is enabled, take the link out of reset (the + * link will be in reset, because we previously reset the chip). This + * will restart auto-negotiation. If auto-negotiation is successful + * then the link-up status bit will be set and the flow control enable + * bits (RFCE and TFCE) will be set according to their negotiated value. + */ + DEBUGOUT("Auto-negotiation enabled\n"); + + E1000_WRITE_REG(hw, E1000_CTRL, ctrl); + E1000_WRITE_FLUSH(hw); + msec_delay(1); + + /* + * For these adapters, the SW definable pin 1 is set when the optics + * detect a signal. If we have a signal, then poll for a "Link-Up" + * indication. + */ + if (hw->phy.media_type == e1000_media_type_internal_serdes || + (E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_SWDPIN1)) { + ret_val = e1000_poll_fiber_serdes_link_generic(hw); + } else { + DEBUGOUT("No signal detected\n"); + } + +out: + return ret_val; +} + +/** + * e1000_config_collision_dist_generic - Configure collision distance + * @hw: pointer to the HW structure + * + * Configures the collision distance to the default value and is used + * during link setup. Currently no func pointer exists and all + * implementations are handled in the generic version of this function. + **/ +void e1000_config_collision_dist_generic(struct e1000_hw *hw) +{ + u32 tctl; + + DEBUGFUNC("e1000_config_collision_dist_generic"); + + tctl = E1000_READ_REG(hw, E1000_TCTL); + + tctl &= ~E1000_TCTL_COLD; + tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT; + + E1000_WRITE_REG(hw, E1000_TCTL, tctl); + E1000_WRITE_FLUSH(hw); +} + +/** + * e1000_poll_fiber_serdes_link_generic - Poll for link up + * @hw: pointer to the HW structure + * + * Polls for link up by reading the status register, if link fails to come + * up with auto-negotiation, then the link is forced if a signal is detected. + **/ +s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 i, status; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_poll_fiber_serdes_link_generic"); + + /* + * If we have a signal (the cable is plugged in, or assumed true for + * serdes media) then poll for a "Link-Up" indication in the Device + * Status Register. Time-out if a link isn't seen in 500 milliseconds + * seconds (Auto-negotiation should complete in less than 500 + * milliseconds even if the other end is doing it in SW). + */ + for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) { + msec_delay(10); + status = E1000_READ_REG(hw, E1000_STATUS); + if (status & E1000_STATUS_LU) + break; + } + if (i == FIBER_LINK_UP_LIMIT) { + DEBUGOUT("Never got a valid link from auto-neg!!!\n"); + mac->autoneg_failed = 1; + /* + * AutoNeg failed to achieve a link, so we'll call + * mac->check_for_link. This routine will force the + * link up if we detect a signal. This will allow us to + * communicate with non-autonegotiating link partners. + */ + ret_val = hw->mac.ops.check_for_link(hw); + if (ret_val) { + DEBUGOUT("Error while checking for link\n"); + goto out; + } + mac->autoneg_failed = 0; + } else { + mac->autoneg_failed = 0; + DEBUGOUT("Valid Link Found\n"); + } + +out: + return ret_val; +} + +/** + * e1000_commit_fc_settings_generic - Configure flow control + * @hw: pointer to the HW structure + * + * Write the flow control settings to the Transmit Config Word Register (TXCW) + * base on the flow control settings in e1000_mac_info. + **/ +s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 txcw; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_commit_fc_settings_generic"); + + /* + * Check for a software override of the flow control settings, and + * setup the device accordingly. If auto-negotiation is enabled, then + * software will have to set the "PAUSE" bits to the correct value in + * the Transmit Config Word Register (TXCW) and re-start auto- + * negotiation. However, if auto-negotiation is disabled, then + * software will have to manually configure the two flow control enable + * bits in the CTRL register. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames, + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames but we + * do not support receiving pause frames). + * 3: Both Rx and Tx flow control (symmetric) are enabled. + */ + switch (hw->fc.type) { + case e1000_fc_none: + /* Flow control completely disabled by a software over-ride. */ + txcw = (E1000_TXCW_ANE | E1000_TXCW_FD); + break; + case e1000_fc_rx_pause: + /* + * Rx Flow control is enabled and Tx Flow control is disabled + * by a software over-ride. Since there really isn't a way to + * advertise that we are capable of Rx Pause ONLY, we will + * advertise that we support both symmetric and asymmetric RX + * PAUSE. Later, we will disable the adapter's ability to send + * PAUSE frames. + */ + txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); + break; + case e1000_fc_tx_pause: + /* + * Tx Flow control is enabled, and Rx Flow control is disabled, + * by a software over-ride. + */ + txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR); + break; + case e1000_fc_full: + /* + * Flow control (both Rx and Tx) is enabled by a software + * over-ride. + */ + txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); + break; + default: + DEBUGOUT("Flow control param set incorrectly\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + break; + } + + E1000_WRITE_REG(hw, E1000_TXCW, txcw); + mac->txcw = txcw; + +out: + return ret_val; +} + +/** + * e1000_set_fc_watermarks_generic - Set flow control high/low watermarks + * @hw: pointer to the HW structure + * + * Sets the flow control high/low threshold (watermark) registers. If + * flow control XON frame transmission is enabled, then set XON frame + * transmission as well. + **/ +s32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u32 fcrtl = 0, fcrth = 0; + + DEBUGFUNC("e1000_set_fc_watermarks_generic"); + + /* + * Set the flow control receive threshold registers. Normally, + * these registers will be set to a default threshold that may be + * adjusted later by the driver's runtime code. However, if the + * ability to transmit pause frames is not enabled, then these + * registers will be set to 0. + */ + if (hw->fc.type & e1000_fc_tx_pause) { + /* + * We need to set up the Receive Threshold high and low water + * marks as well as (optionally) enabling the transmission of + * XON frames. + */ + fcrtl = hw->fc.low_water; + if (hw->fc.send_xon) + fcrtl |= E1000_FCRTL_XONE; + + fcrth = hw->fc.high_water; + } + E1000_WRITE_REG(hw, E1000_FCRTL, fcrtl); + E1000_WRITE_REG(hw, E1000_FCRTH, fcrth); + + return ret_val; +} + +/** + * e1000_set_default_fc_generic - Set flow control default values + * @hw: pointer to the HW structure + * + * Read the EEPROM for the default values for flow control and store the + * values. + **/ +s32 e1000_set_default_fc_generic(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 nvm_data; + + DEBUGFUNC("e1000_set_default_fc_generic"); + + /* + * Read and store word 0x0F of the EEPROM. This word contains bits + * that determine the hardware's default PAUSE (flow control) mode, + * a bit that determines whether the HW defaults to enabling or + * disabling auto-negotiation, and the direction of the + * SW defined pins. If there is no SW over-ride of the flow + * control setting, then the variable hw->fc will + * be initialized based on a value in the EEPROM. + */ + ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data); + + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + + if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0) + hw->fc.type = e1000_fc_none; + else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == + NVM_WORD0F_ASM_DIR) + hw->fc.type = e1000_fc_tx_pause; + else + hw->fc.type = e1000_fc_full; + +out: + return ret_val; +} + +/** + * e1000_force_mac_fc_generic - Force the MAC's flow control settings + * @hw: pointer to the HW structure + * + * Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the + * device control register to reflect the adapter settings. TFCE and RFCE + * need to be explicitly set by software when a copper PHY is used because + * autonegotiation is managed by the PHY rather than the MAC. Software must + * also configure these bits when link is forced on a fiber connection. + **/ +s32 e1000_force_mac_fc_generic(struct e1000_hw *hw) +{ + u32 ctrl; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_force_mac_fc_generic"); + + ctrl = E1000_READ_REG(hw, E1000_CTRL); + + /* + * Because we didn't get link via the internal auto-negotiation + * mechanism (we either forced link or we got link via PHY + * auto-neg), we have to manually enable/disable transmit an + * receive flow control. + * + * The "Case" statement below enables/disable flow control + * according to the "hw->fc.type" parameter. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause + * frames but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * frames but we do not receive pause frames). + * 3: Both Rx and Tx flow control (symmetric) is enabled. + * other: No other values should be possible at this point. + */ + DEBUGOUT1("hw->fc.type = %u\n", hw->fc.type); + + switch (hw->fc.type) { + case e1000_fc_none: + ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); + break; + case e1000_fc_rx_pause: + ctrl &= (~E1000_CTRL_TFCE); + ctrl |= E1000_CTRL_RFCE; + break; + case e1000_fc_tx_pause: + ctrl &= (~E1000_CTRL_RFCE); + ctrl |= E1000_CTRL_TFCE; + break; + case e1000_fc_full: + ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE); + break; + default: + DEBUGOUT("Flow control param set incorrectly\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + E1000_WRITE_REG(hw, E1000_CTRL, ctrl); + +out: + return ret_val; +} + +/** + * e1000_config_fc_after_link_up_generic - Configures flow control after link + * @hw: pointer to the HW structure + * + * Checks the status of auto-negotiation after link up to ensure that the + * speed and duplex were not forced. If the link needed to be forced, then + * flow control needs to be forced also. If auto-negotiation is enabled + * and did not fail, then we configure flow control based on our link + * partner. + **/ +s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = E1000_SUCCESS; + u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg; + u16 speed, duplex; + + DEBUGFUNC("e1000_config_fc_after_link_up_generic"); + + /* + * Check for the case where we have fiber media and auto-neg failed + * so we had to force link. In this case, we need to force the + * configuration of the MAC to match the "fc" parameter. + */ + if (mac->autoneg_failed) { + if (hw->phy.media_type == e1000_media_type_fiber || + hw->phy.media_type == e1000_media_type_internal_serdes) + ret_val = e1000_force_mac_fc_generic(hw); + } else { + if (hw->phy.media_type == e1000_media_type_copper) + ret_val = e1000_force_mac_fc_generic(hw); + } + + if (ret_val) { + DEBUGOUT("Error forcing flow control settings\n"); + goto out; + } + + /* + * Check for the case where we have copper media and auto-neg is + * enabled. In this case, we need to check and see if Auto-Neg + * has completed, and if so, how the PHY and link partner has + * flow control configured. + */ + if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) { + /* + * Read the MII Status Register and check to see if AutoNeg + * has completed. We read this twice because this reg has + * some "sticky" (latched) bits. + */ + ret_val = phy->ops.read_reg(hw, PHY_STATUS, &mii_status_reg); + if (ret_val) + goto out; + ret_val = phy->ops.read_reg(hw, PHY_STATUS, &mii_status_reg); + if (ret_val) + goto out; + + if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { + DEBUGOUT("Copper PHY and Auto Neg " + "has not completed.\n"); + goto out; + } + + /* + * The AutoNeg process has completed, so we now need to + * read both the Auto Negotiation Advertisement + * Register (Address 4) and the Auto_Negotiation Base + * Page Ability Register (Address 5) to determine how + * flow control was negotiated. + */ + ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, + &mii_nway_adv_reg); + if (ret_val) + goto out; + ret_val = phy->ops.read_reg(hw, PHY_LP_ABILITY, + &mii_nway_lp_ability_reg); + if (ret_val) + goto out; + + /* + * Two bits in the Auto Negotiation Advertisement Register + * (Address 4) and two bits in the Auto Negotiation Base + * Page Ability Register (Address 5) determine flow control + * for both the PHY and the link partner. The following + * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, + * 1999, describes these PAUSE resolution bits and how flow + * control is determined based upon these settings. + * NOTE: DC = Don't Care + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution + *-------|---------|-------|---------|-------------------- + * 0 | 0 | DC | DC | e1000_fc_none + * 0 | 1 | 0 | DC | e1000_fc_none + * 0 | 1 | 1 | 0 | e1000_fc_none + * 0 | 1 | 1 | 1 | e1000_fc_tx_pause + * 1 | 0 | 0 | DC | e1000_fc_none + * 1 | DC | 1 | DC | e1000_fc_full + * 1 | 1 | 0 | 0 | e1000_fc_none + * 1 | 1 | 0 | 1 | e1000_fc_rx_pause + * + * Are both PAUSE bits set to 1? If so, this implies + * Symmetric Flow Control is enabled at both ends. The + * ASM_DIR bits are irrelevant per the spec. + * + * For Symmetric Flow Control: + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | DC | 1 | DC | E1000_fc_full + * + */ + if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { + /* + * Now we need to check if the user selected Rx ONLY + * of pause frames. In this case, we had to advertise + * FULL flow control because we could not advertise RX + * ONLY. Hence, we must now check to see if we need to + * turn OFF the TRANSMISSION of PAUSE frames. + */ + if (hw->fc.original_type == e1000_fc_full) { + hw->fc.type = e1000_fc_full; + DEBUGOUT("Flow Control = FULL.\r\n"); + } else { + hw->fc.type = e1000_fc_rx_pause; + DEBUGOUT("Flow Control = " + "RX PAUSE frames only.\r\n"); + } + } + /* + * For receiving PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 0 | 1 | 1 | 1 | e1000_fc_tx_pause + */ + else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + hw->fc.type = e1000_fc_tx_pause; + DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n"); + } + /* + * For transmitting PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | 1 | 0 | 1 | e1000_fc_rx_pause + */ + else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + hw->fc.type = e1000_fc_rx_pause; + DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); + } else { + /* + * Per the IEEE spec, at this point flow control + * should be disabled. + */ + hw->fc.type = e1000_fc_none; + DEBUGOUT("Flow Control = NONE.\r\n"); + } + + /* + * Now we need to do one last check... If we auto- + * negotiated to HALF DUPLEX, flow control should not be + * enabled per IEEE 802.3 spec. + */ + ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex); + if (ret_val) { + DEBUGOUT("Error getting link speed and duplex\n"); + goto out; + } + + if (duplex == HALF_DUPLEX) + hw->fc.type = e1000_fc_none; + + /* + * Now we call a subroutine to actually force the MAC + * controller to use the correct flow control settings. + */ + ret_val = e1000_force_mac_fc_generic(hw); + if (ret_val) { + DEBUGOUT("Error forcing flow control settings\n"); + goto out; + } + } + +out: + return ret_val; +} + +/** + * e1000_get_speed_and_duplex_copper_generic - Retrieve current speed/duplex + * @hw: pointer to the HW structure + * @speed: stores the current speed + * @duplex: stores the current duplex + * + * Read the status register for the current speed/duplex and store the current + * speed and duplex for copper connections. + **/ +s32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed, + u16 *duplex) +{ + u32 status; + + DEBUGFUNC("e1000_get_speed_and_duplex_copper_generic"); + + status = E1000_READ_REG(hw, E1000_STATUS); + if (status & E1000_STATUS_SPEED_1000) { + *speed = SPEED_1000; + DEBUGOUT("1000 Mbs, "); + } else if (status & E1000_STATUS_SPEED_100) { + *speed = SPEED_100; + DEBUGOUT("100 Mbs, "); + } else { + *speed = SPEED_10; + DEBUGOUT("10 Mbs, "); + } + + if (status & E1000_STATUS_FD) { + *duplex = FULL_DUPLEX; + DEBUGOUT("Full Duplex\n"); + } else { + *duplex = HALF_DUPLEX; + DEBUGOUT("Half Duplex\n"); + } + + return E1000_SUCCESS; +} + +/** + * e1000_get_speed_and_duplex_fiber_generic - Retrieve current speed/duplex + * @hw: pointer to the HW structure + * @speed: stores the current speed + * @duplex: stores the current duplex + * + * Sets the speed and duplex to gigabit full duplex (the only possible option) + * for fiber/serdes links. + **/ +s32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw, + u16 *speed, u16 *duplex) +{ + DEBUGFUNC("e1000_get_speed_and_duplex_fiber_serdes_generic"); + + *speed = SPEED_1000; + *duplex = FULL_DUPLEX; + + return E1000_SUCCESS; +} + +/** + * e1000_get_hw_semaphore_generic - Acquire hardware semaphore + * @hw: pointer to the HW structure + * + * Acquire the HW semaphore to access the PHY or NVM + **/ +s32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw) +{ + u32 swsm; + s32 ret_val = E1000_SUCCESS; + s32 timeout = hw->nvm.word_size + 1; + s32 i = 0; + + DEBUGFUNC("e1000_get_hw_semaphore_generic"); + + /* Get the SW semaphore */ + while (i < timeout) { + swsm = E1000_READ_REG(hw, E1000_SWSM); + if (!(swsm & E1000_SWSM_SMBI)) + break; + + usec_delay(50); + i++; + } + + if (i == timeout) { + DEBUGOUT("Driver can't access device - SMBI bit is set.\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + + /* Get the FW semaphore. */ + for (i = 0; i < timeout; i++) { + swsm = E1000_READ_REG(hw, E1000_SWSM); + E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI); + + /* Semaphore acquired if bit latched */ + if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI) + break; + + usec_delay(50); + } + + if (i == timeout) { + /* Release semaphores */ + e1000_put_hw_semaphore_generic(hw); + DEBUGOUT("Driver can't access the NVM\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_put_hw_semaphore_generic - Release hardware semaphore + * @hw: pointer to the HW structure + * + * Release hardware semaphore used to access the PHY or NVM + **/ +void e1000_put_hw_semaphore_generic(struct e1000_hw *hw) +{ + u32 swsm; + + DEBUGFUNC("e1000_put_hw_semaphore_generic"); + + swsm = E1000_READ_REG(hw, E1000_SWSM); + + swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); + + E1000_WRITE_REG(hw, E1000_SWSM, swsm); +} + +/** + * e1000_get_auto_rd_done_generic - Check for auto read completion + * @hw: pointer to the HW structure + * + * Check EEPROM for Auto Read done bit. + **/ +s32 e1000_get_auto_rd_done_generic(struct e1000_hw *hw) +{ + s32 i = 0; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_get_auto_rd_done_generic"); + + while (i < AUTO_READ_DONE_TIMEOUT) { + if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_AUTO_RD) + break; + msec_delay(1); + i++; + } + + if (i == AUTO_READ_DONE_TIMEOUT) { + DEBUGOUT("Auto read by HW from NVM has not completed.\n"); + ret_val = -E1000_ERR_RESET; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_valid_led_default_generic - Verify a valid default LED config + * @hw: pointer to the HW structure + * @data: pointer to the NVM (EEPROM) + * + * Read the EEPROM for the current default LED configuration. If the + * LED configuration is not valid, set to a valid LED configuration. + **/ +s32 e1000_valid_led_default_generic(struct e1000_hw *hw, u16 *data) +{ + s32 ret_val; + + DEBUGFUNC("e1000_valid_led_default_generic"); + + ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + + if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) + *data = ID_LED_DEFAULT; + +out: + return ret_val; +} + +/** + * e1000_id_led_init_generic - + * @hw: pointer to the HW structure + * + **/ +s32 e1000_id_led_init_generic(struct e1000_hw * hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + const u32 ledctl_mask = 0x000000FF; + const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON; + const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF; + u16 data, i, temp; + const u16 led_mask = 0x0F; + + DEBUGFUNC("e1000_id_led_init_generic"); + + ret_val = hw->nvm.ops.valid_led_default(hw, &data); + if (ret_val) + goto out; + + mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL); + mac->ledctl_mode1 = mac->ledctl_default; + mac->ledctl_mode2 = mac->ledctl_default; + + for (i = 0; i < 4; i++) { + temp = (data >> (i << 2)) & led_mask; + switch (temp) { + case ID_LED_ON1_DEF2: + case ID_LED_ON1_ON2: + case ID_LED_ON1_OFF2: + mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); + mac->ledctl_mode1 |= ledctl_on << (i << 3); + break; + case ID_LED_OFF1_DEF2: + case ID_LED_OFF1_ON2: + case ID_LED_OFF1_OFF2: + mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); + mac->ledctl_mode1 |= ledctl_off << (i << 3); + break; + default: + /* Do nothing */ + break; + } + switch (temp) { + case ID_LED_DEF1_ON2: + case ID_LED_ON1_ON2: + case ID_LED_OFF1_ON2: + mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); + mac->ledctl_mode2 |= ledctl_on << (i << 3); + break; + case ID_LED_DEF1_OFF2: + case ID_LED_ON1_OFF2: + case ID_LED_OFF1_OFF2: + mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); + mac->ledctl_mode2 |= ledctl_off << (i << 3); + break; + default: + /* Do nothing */ + break; + } + } + +out: + return ret_val; +} + +/** + * e1000_setup_led_generic - Configures SW controllable LED + * @hw: pointer to the HW structure + * + * This prepares the SW controllable LED for use and saves the current state + * of the LED so it can be later restored. + **/ +s32 e1000_setup_led_generic(struct e1000_hw *hw) +{ + u32 ledctl; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_setup_led_generic"); + + if (hw->mac.ops.setup_led != e1000_setup_led_generic) { + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + if (hw->phy.media_type == e1000_media_type_fiber) { + ledctl = E1000_READ_REG(hw, E1000_LEDCTL); + hw->mac.ledctl_default = ledctl; + /* Turn off LED0 */ + ledctl &= ~(E1000_LEDCTL_LED0_IVRT | + E1000_LEDCTL_LED0_BLINK | + E1000_LEDCTL_LED0_MODE_MASK); + ledctl |= (E1000_LEDCTL_MODE_LED_OFF << + E1000_LEDCTL_LED0_MODE_SHIFT); + E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl); + } else if (hw->phy.media_type == e1000_media_type_copper) { + E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1); + } + +out: + return ret_val; +} + +/** + * e1000_cleanup_led_generic - Set LED config to default operation + * @hw: pointer to the HW structure + * + * Remove the current LED configuration and set the LED configuration + * to the default value, saved from the EEPROM. + **/ +s32 e1000_cleanup_led_generic(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_cleanup_led_generic"); + + if (hw->mac.ops.cleanup_led != e1000_cleanup_led_generic) { + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default); + +out: + return ret_val; +} + +/** + * e1000_blink_led_generic - Blink LED + * @hw: pointer to the HW structure + * + * Blink the LEDs which are set to be on. + **/ +s32 e1000_blink_led_generic(struct e1000_hw *hw) +{ + u32 ledctl_blink = 0; + u32 i; + + DEBUGFUNC("e1000_blink_led_generic"); + + if (hw->phy.media_type == e1000_media_type_fiber) { + /* always blink LED0 for PCI-E fiber */ + ledctl_blink = E1000_LEDCTL_LED0_BLINK | + (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT); + } else { + /* + * set the blink bit for each LED that's "on" (0x0E) + * in ledctl_mode2 + */ + ledctl_blink = hw->mac.ledctl_mode2; + for (i = 0; i < 4; i++) + if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) == + E1000_LEDCTL_MODE_LED_ON) + ledctl_blink |= (E1000_LEDCTL_LED0_BLINK << + (i * 8)); + } + + E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl_blink); + + return E1000_SUCCESS; +} + +/** + * e1000_led_on_generic - Turn LED on + * @hw: pointer to the HW structure + * + * Turn LED on. + **/ +s32 e1000_led_on_generic(struct e1000_hw *hw) +{ + u32 ctrl; + + DEBUGFUNC("e1000_led_on_generic"); + + switch (hw->phy.media_type) { + case e1000_media_type_fiber: + ctrl = E1000_READ_REG(hw, E1000_CTRL); + ctrl &= ~E1000_CTRL_SWDPIN0; + ctrl |= E1000_CTRL_SWDPIO0; + E1000_WRITE_REG(hw, E1000_CTRL, ctrl); + break; + case e1000_media_type_copper: + E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2); + break; + default: + break; + } + + return E1000_SUCCESS; +} + +/** + * e1000_led_off_generic - Turn LED off + * @hw: pointer to the HW structure + * + * Turn LED off. + **/ +s32 e1000_led_off_generic(struct e1000_hw *hw) +{ + u32 ctrl; + + DEBUGFUNC("e1000_led_off_generic"); + + switch (hw->phy.media_type) { + case e1000_media_type_fiber: + ctrl = E1000_READ_REG(hw, E1000_CTRL); + ctrl |= E1000_CTRL_SWDPIN0; + ctrl |= E1000_CTRL_SWDPIO0; + E1000_WRITE_REG(hw, E1000_CTRL, ctrl); + break; + case e1000_media_type_copper: + E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1); + break; + default: + break; + } + + return E1000_SUCCESS; +} + +/** + * e1000_set_pcie_no_snoop_generic - Set PCI-express capabilities + * @hw: pointer to the HW structure + * @no_snoop: bitmap of snoop events + * + * Set the PCI-express register to snoop for events enabled in 'no_snoop'. + **/ +void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop) +{ + u32 gcr; + + DEBUGFUNC("e1000_set_pcie_no_snoop_generic"); + + if (hw->bus.type != e1000_bus_type_pci_express) + goto out; + + if (no_snoop) { + gcr = E1000_READ_REG(hw, E1000_GCR); + gcr &= ~(PCIE_NO_SNOOP_ALL); + gcr |= no_snoop; + E1000_WRITE_REG(hw, E1000_GCR, gcr); + } +out: + return; +} + +/** + * e1000_disable_pcie_master_generic - Disables PCI-express master access + * @hw: pointer to the HW structure + * + * Returns 0 (E1000_SUCCESS) if successful, else returns -10 + * (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused + * the master requests to be disabled. + * + * Disables PCI-Express master access and verifies there are no pending + * requests. + **/ +s32 e1000_disable_pcie_master_generic(struct e1000_hw *hw) +{ + u32 ctrl; + s32 timeout = MASTER_DISABLE_TIMEOUT; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_disable_pcie_master_generic"); + + if (hw->bus.type != e1000_bus_type_pci_express) + goto out; + + ctrl = E1000_READ_REG(hw, E1000_CTRL); + ctrl |= E1000_CTRL_GIO_MASTER_DISABLE; + E1000_WRITE_REG(hw, E1000_CTRL, ctrl); + + while (timeout) { + if (!(E1000_READ_REG(hw, E1000_STATUS) & + E1000_STATUS_GIO_MASTER_ENABLE)) + break; + usec_delay(100); + timeout--; + } + + if (!timeout) { + DEBUGOUT("Master requests are pending.\n"); + ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_reset_adaptive_generic - Reset Adaptive Interframe Spacing + * @hw: pointer to the HW structure + * + * Reset the Adaptive Interframe Spacing throttle to default values. + **/ +void e1000_reset_adaptive_generic(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + + DEBUGFUNC("e1000_reset_adaptive_generic"); + + if (!mac->adaptive_ifs) { + DEBUGOUT("Not in Adaptive IFS mode!\n"); + goto out; + } + + if (!mac->ifs_params_forced) { + mac->current_ifs_val = 0; + mac->ifs_min_val = IFS_MIN; + mac->ifs_max_val = IFS_MAX; + mac->ifs_step_size = IFS_STEP; + mac->ifs_ratio = IFS_RATIO; + } + + mac->in_ifs_mode = false; + E1000_WRITE_REG(hw, E1000_AIT, 0); +out: + return; +} + +/** + * e1000_update_adaptive_generic - Update Adaptive Interframe Spacing + * @hw: pointer to the HW structure + * + * Update the Adaptive Interframe Spacing Throttle value based on the + * time between transmitted packets and time between collisions. + **/ +void e1000_update_adaptive_generic(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + + DEBUGFUNC("e1000_update_adaptive_generic"); + + if (!mac->adaptive_ifs) { + DEBUGOUT("Not in Adaptive IFS mode!\n"); + goto out; + } + + if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) { + if (mac->tx_packet_delta > MIN_NUM_XMITS) { + mac->in_ifs_mode = true; + if (mac->current_ifs_val < mac->ifs_max_val) { + if (!mac->current_ifs_val) + mac->current_ifs_val = mac->ifs_min_val; + else + mac->current_ifs_val += + mac->ifs_step_size; + E1000_WRITE_REG(hw, E1000_AIT, mac->current_ifs_val); + } + } + } else { + if (mac->in_ifs_mode && + (mac->tx_packet_delta <= MIN_NUM_XMITS)) { + mac->current_ifs_val = 0; + mac->in_ifs_mode = false; + E1000_WRITE_REG(hw, E1000_AIT, 0); + } + } +out: + return; +} + +/** + * e1000_validate_mdi_setting_generic - Verify MDI/MDIx settings + * @hw: pointer to the HW structure + * + * Verify that when not using auto-negotiation that MDI/MDIx is correctly + * set, which is forced to MDI mode only. + **/ +s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_validate_mdi_setting_generic"); + + if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) { + DEBUGOUT("Invalid MDI setting detected\n"); + hw->phy.mdix = 1; + ret_val = -E1000_ERR_CONFIG; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_write_8bit_ctrl_reg_generic - Write a 8bit CTRL register + * @hw: pointer to the HW structure + * @reg: 32bit register offset such as E1000_SCTL + * @offset: register offset to write to + * @data: data to write at register offset + * + * Writes an address/data control type register. There are several of these + * and they all have the format address << 8 | data and bit 31 is polled for + * completion. + **/ +s32 e1000_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, u32 reg, + u32 offset, u8 data) +{ + u32 i, regvalue = 0; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_write_8bit_ctrl_reg_generic"); + + /* Set up the address and data */ + regvalue = ((u32)data) | (offset << E1000_GEN_CTL_ADDRESS_SHIFT); + E1000_WRITE_REG(hw, reg, regvalue); + + /* Poll the ready bit to see if the MDI read completed */ + for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) { + usec_delay(5); + regvalue = E1000_READ_REG(hw, reg); + if (regvalue & E1000_GEN_CTL_READY) + break; + } + if (!(regvalue & E1000_GEN_CTL_READY)) { + DEBUGOUT1("Reg %08x did not indicate ready\n", reg); + ret_val = -E1000_ERR_PHY; + goto out; + } + +out: + return ret_val; +} --- linux-2.6.27.orig/ubuntu/e1000e/e1000.h +++ linux-2.6.27/ubuntu/e1000e/e1000.h @@ -0,0 +1,444 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* Linux PRO/1000 Ethernet Driver main header file */ + +#ifndef _E1000_H_ +#define _E1000_H_ + +#include +#include +#include +#include + +#include "kcompat.h" + +#include "e1000_hw.h" + +struct e1000_info; + +#define e_printk(level, adapter, format, arg...) \ + printk(level "%s: %s: " format, pci_name(adapter->pdev), \ + (strchr(adapter->netdev->name, '%') ? "" : \ + adapter->netdev->name), ## arg) + +#define e_dbg(format, arg...) do { (void)(adapter); } while (0) + +#define e_err(format, arg...) \ + e_printk(KERN_ERR, adapter, format, ## arg) +#define e_info(format, arg...) \ + e_printk(KERN_INFO, adapter, format, ## arg) +#define e_warn(format, arg...) \ + e_printk(KERN_WARNING, adapter, format, ## arg) +#define e_notice(format, arg...) \ + e_printk(KERN_NOTICE, adapter, format, ## arg) + + +#ifdef CONFIG_E1000E_MSIX +/* Interrupt modes, as used by the IntMode paramter */ +#define E1000E_INT_MODE_LEGACY 0 +#define E1000E_INT_MODE_MSI 1 +#define E1000E_INT_MODE_MSIX 2 + +#endif /* CONFIG_E1000E_MSIX */ + +#define E1000_MAX_INTR 10 + +/* Tx/Rx descriptor defines */ +#define E1000_DEFAULT_TXD 256 +#define E1000_MAX_TXD 4096 +#define E1000_MIN_TXD 80 + +#define E1000_DEFAULT_RXD 256 +#define E1000_MAX_RXD 4096 +#define E1000_MIN_RXD 80 + +#define E1000_MIN_ITR_USECS 10 /* 100000 irq/sec */ +#define E1000_MAX_ITR_USECS 10000 /* 100 irq/sec */ + +/* Early Receive defines */ +#define E1000_ERT_2048 0x100 + +#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */ + +/* How many Tx Descriptors do we need to call netif_wake_queue ? */ +/* How many Rx Buffers do we bundle into one write to the hardware ? */ +#define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */ + +#define AUTO_ALL_MODES 0 +#define E1000_EEPROM_APME 0x0400 + +#define E1000_MNG_VLAN_NONE (-1) + +/* Number of packet split data buffers (not including the header buffer) */ +#define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 1) + +enum e1000_boards { + board_82571, + board_82572, + board_82573, + board_82574, + board_80003es2lan, + board_ich8lan, + board_ich9lan, + board_ich10lan, +}; + +struct e1000_queue_stats { + u64 packets; + u64 bytes; +}; + +struct e1000_ps_page { + struct page *page; + u64 dma; /* must be u64 - written to hw */ +}; + +/* + * wrappers around a pointer to a socket buffer, + * so a DMA handle can be stored along with the buffer + */ +struct e1000_buffer { + dma_addr_t dma; + struct sk_buff *skb; + union { + /* Tx */ + struct { + unsigned long time_stamp; + u16 length; + u16 next_to_watch; + }; + /* Rx */ + /* arrays of page information for packet split */ + struct e1000_ps_page *ps_pages; + }; + struct page *page; +}; + +struct e1000_ring { + void *desc; /* pointer to ring memory */ + dma_addr_t dma; /* phys address of ring */ + unsigned int size; /* length of ring in bytes */ + unsigned int count; /* number of desc. in ring */ + + u16 next_to_use; + u16 next_to_clean; + + u16 head; + u16 tail; + + /* array of buffer information structs */ + struct e1000_buffer *buffer_info; + +#ifdef CONFIG_E1000E_MSIX + char name[IFNAMSIZ + 5]; + u32 ims_val; + u32 itr_val; + u16 itr_register; + int set_itr; + +#endif /* CONFIG_E1000E_MSIX */ + struct sk_buff *rx_skb_top; + + struct e1000_queue_stats stats; +}; + +#ifdef SIOCGMIIPHY +/* PHY register snapshot values */ +struct e1000_phy_regs { + u16 bmcr; /* basic mode control register */ + u16 bmsr; /* basic mode status register */ + u16 advertise; /* auto-negotiation advertisement */ + u16 lpa; /* link partner ability register */ + u16 expansion; /* auto-negotiation expansion reg */ + u16 ctrl1000; /* 1000BASE-T control register */ + u16 stat1000; /* 1000BASE-T status register */ + u16 estatus; /* extended status register */ +}; +#endif + +/* board specific private data structure */ +struct e1000_adapter { + struct timer_list watchdog_timer; + struct timer_list phy_info_timer; + struct timer_list blink_timer; + + struct work_struct reset_task; + struct work_struct watchdog_task; + + const struct e1000_info *ei; + + struct vlan_group *vlgrp; + u32 bd_number; + u32 rx_buffer_len; + u16 mng_vlan_id; + u16 link_speed; + u16 link_duplex; + + spinlock_t tx_queue_lock; /* prevent concurrent tail updates */ + + /* track device up/down/testing state */ + unsigned long state; + + /* Interrupt Throttle Rate */ + u32 itr; + u32 itr_setting; + u16 tx_itr; + u16 rx_itr; + + /* + * Tx + */ + struct e1000_ring *tx_ring /* One per active queue */ + ____cacheline_aligned_in_smp; + +#ifdef CONFIG_E1000E_NAPI + struct napi_struct napi; +#endif + + unsigned long tx_queue_len; + unsigned int restart_queue; + u32 txd_cmd; + + bool detect_tx_hung; + u8 tx_timeout_factor; + + u32 tx_int_delay; + u32 tx_abs_int_delay; + + unsigned int total_tx_bytes; + unsigned int total_tx_packets; + unsigned int total_rx_bytes; + unsigned int total_rx_packets; + + /* Tx stats */ + u64 tpt_old; + u64 colc_old; + u32 gotc; + u64 gotc_old; + u32 tx_timeout_count; + u32 tx_fifo_head; + u32 tx_head_addr; + u32 tx_fifo_size; + u32 tx_dma_failed; + + /* + * Rx + */ +#ifdef CONFIG_E1000E_NAPI + bool (*clean_rx) (struct e1000_adapter *adapter, + int *work_done, int work_to_do) + ____cacheline_aligned_in_smp; +#else + bool (*clean_rx) (struct e1000_adapter *adapter) + ____cacheline_aligned_in_smp; +#endif + void (*alloc_rx_buf) (struct e1000_adapter *adapter, + int cleaned_count); + struct e1000_ring *rx_ring; + + u32 rx_int_delay; + u32 rx_abs_int_delay; + + /* Rx stats */ + u64 hw_csum_err; + u64 hw_csum_good; + u64 rx_hdr_split; + u32 gorc; + u64 gorc_old; + u32 alloc_rx_buff_failed; + u32 rx_dma_failed; + + unsigned int rx_ps_pages; + u16 rx_ps_bsize0; + u32 max_frame_size; + u32 min_frame_size; + + /* OS defined structs */ + struct net_device *netdev; + struct pci_dev *pdev; + struct net_device_stats net_stats; + spinlock_t stats_lock; /* prevent concurrent stats updates */ + + /* structs defined in e1000_hw.h */ + struct e1000_hw hw; + + struct e1000_hw_stats stats; + struct e1000_phy_info phy_info; + struct e1000_phy_stats phy_stats; + +#ifdef SIOCGMIIPHY + /* Snapshot of PHY registers */ + struct e1000_phy_regs phy_regs; +#endif + + struct e1000_ring test_tx_ring; + struct e1000_ring test_rx_ring; + u32 test_icr; + + u32 msg_enable; +#ifdef CONFIG_E1000E_MSIX + struct msix_entry *msix_entries; + int int_mode; + u32 eiac_mask; +#endif /* CONFIG_E1000E_MSIX */ + + u32 eeprom_wol; + u32 wol; + u32 pba; + + bool fc_autoneg; + + unsigned long led_status; + + unsigned int flags; + u32 *config_space; + u32 stats_freq_us; /* stats update freq (microseconds) */ +}; + +struct e1000_info { + e1000_mac_type mac; + unsigned int flags; + u32 pba; + void (*init_ops)(struct e1000_hw *); + s32 (*get_variants)(struct e1000_adapter *); +}; + +/* hardware capability, feature, and workaround flags */ +#define FLAG_HAS_AMT (1 << 0) +#define FLAG_HAS_FLASH (1 << 1) +#define FLAG_HAS_HW_VLAN_FILTER (1 << 2) +#define FLAG_HAS_WOL (1 << 3) +#define FLAG_HAS_ERT (1 << 4) +#define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5) +#define FLAG_HAS_SWSM_ON_LOAD (1 << 6) +#define FLAG_HAS_JUMBO_FRAMES (1 << 7) +#define FLAG_HAS_ASPM (1 << 8) +#define FLAG_IS_ICH (1 << 9) +#define FLAG_HAS_MSIX (1 << 10) +#define FLAG_HAS_SMART_POWER_DOWN (1 << 11) +#define FLAG_IS_QUAD_PORT_A (1 << 12) +#define FLAG_IS_QUAD_PORT (1 << 13) +#define FLAG_TIPG_MEDIUM_FOR_80003ESLAN (1 << 14) +#define FLAG_APME_IN_WUC (1 << 15) +#define FLAG_APME_IN_CTRL3 (1 << 16) +#define FLAG_APME_CHECK_PORT_B (1 << 17) +#define FLAG_DISABLE_FC_PAUSE_TIME (1 << 18) +#define FLAG_NO_WAKE_UCAST (1 << 19) +#define FLAG_MNG_PT_ENABLED (1 << 20) +#define FLAG_RESET_OVERWRITES_LAA (1 << 21) +#define FLAG_TARC_SPEED_MODE_BIT (1 << 22) +#define FLAG_TARC_SET_BIT_ZERO (1 << 23) +#define FLAG_RX_NEEDS_RESTART (1 << 24) +#define FLAG_LSC_GIG_SPEED_DROP (1 << 25) +#define FLAG_SMART_POWER_DOWN (1 << 26) +#define FLAG_MSI_ENABLED (1 << 27) +#define FLAG_RX_CSUM_ENABLED (1 << 28) +#define FLAG_TSO_FORCE (1 << 29) +#define FLAG_MSI_TEST_FAILED (1 << 30) +#define FLAG_RX_RESTART_NOW (1 << 31) + + +#define E1000_RX_DESC_PS(R, i) \ + (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) +#define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i])) +#define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc) +#define E1000_TX_DESC(R, i) E1000_GET_DESC(R, i, e1000_tx_desc) +#define E1000_CONTEXT_DESC(R, i) E1000_GET_DESC(R, i, e1000_context_desc) + +enum e1000_state_t { + __E1000_TESTING, + __E1000_RESETTING, + __E1000_DOWN +}; + +enum latency_range { + lowest_latency = 0, + low_latency = 1, + bulk_latency = 2, + latency_invalid = 255 +}; + +extern char e1000e_driver_name[]; +extern const char e1000e_driver_version[]; + +extern void e1000_check_options(struct e1000_adapter *adapter); +extern void e1000_set_ethtool_ops(struct net_device *netdev); +#ifdef ETHTOOL_OPS_COMPAT +extern int ethtool_ioctl(struct ifreq *ifr); +#endif + +extern int e1000_up(struct e1000_adapter *adapter); +extern void e1000_down(struct e1000_adapter *adapter); +extern void e1000_reinit_locked(struct e1000_adapter *adapter); +extern void e1000_reset(struct e1000_adapter *adapter); +extern int e1000_setup_rx_resources(struct e1000_adapter *adapter); +extern int e1000_setup_tx_resources(struct e1000_adapter *adapter); +extern void e1000_free_rx_resources(struct e1000_adapter *adapter); +extern void e1000_free_tx_resources(struct e1000_adapter *adapter); +extern void e1000_update_stats(struct e1000_adapter *adapter); +#ifdef CONFIG_E1000E_MSIX +extern void e1000_set_interrupt_capability(struct e1000_adapter *adapter); +extern void e1000_reset_interrupt_capability(struct e1000_adapter *adapter); +#endif + +extern unsigned int copybreak; + +static inline u32 __er32(struct e1000_hw *hw, unsigned long reg) +{ + return readl(hw->hw_addr + reg); +} + +static inline void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val) +{ + writel(val, hw->hw_addr + reg); +} +#define er32(reg) E1000_READ_REG(hw, E1000_##reg) +#define ew32(reg,val) E1000_WRITE_REG(hw, E1000_##reg, (val)) +#define e1e_flush() er32(STATUS) + +extern void e1000_init_function_pointers_82571(struct e1000_hw *hw); +extern void e1000_init_function_pointers_80003es2lan(struct e1000_hw *hw); +extern void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw); + +static inline s32 e1000_read_mac_addr(struct e1000_hw *hw) +{ + if (hw->mac.ops.read_mac_addr) + return hw->mac.ops.read_mac_addr(hw); + + return e1000_read_mac_addr_generic(hw); +} + +static inline void e1000_power_up_phy(struct e1000_hw *hw) +{ + if(hw->phy.ops.power_up) + hw->phy.ops.power_up(hw); + hw->mac.ops.setup_link(hw); +} + +#endif /* _E1000_H_ */ --- linux-2.6.27.orig/ubuntu/e1000e/BOM +++ linux-2.6.27/ubuntu/e1000e/BOM @@ -0,0 +1,7 @@ +Downloaded from: http://sourceforge.net/project/showfiles.php?group_id=42302 +Current Version: 0.4.7.1 +Comments: + +Changed Kconfig option to E1000E_NEW. Disabled in-kernel driver. Make sure +to also include E1000E_ENABLED config option, since it will alter some +things in e1000 driver (we want that). --- linux-2.6.27.orig/ubuntu/e1000e/e1000_ich8lan.c +++ linux-2.6.27/ubuntu/e1000e/e1000_ich8lan.c @@ -0,0 +1,2798 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* e1000_ich8lan + * e1000_ich9lan + */ + +#include "e1000.h" + +static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw); +static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw); +static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw); +static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw); +static void e1000_release_swflag_ich8lan(struct e1000_hw *hw); +static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw); +static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw); +static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw); +static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw); +static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw); +static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw); +static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, + bool active); +static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, + bool active); +static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data); +static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data); +static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw); +static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw); +static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, + u16 *data); +static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw); +static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw); +static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw); +static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw); +static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw); +static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, + u16 *speed, u16 *duplex); +static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw); +static s32 e1000_led_on_ich8lan(struct e1000_hw *hw); +static s32 e1000_led_off_ich8lan(struct e1000_hw *hw); +static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw); +static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank); +static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout); +static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw); +static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw); +static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw); +static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw); +static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, + u32 offset, u8* data); +static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, + u8 size, u16* data); +static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, + u32 offset, u16 *data); +static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, + u32 offset, u8 byte); +static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, + u32 offset, u8 data); +static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, + u8 size, u16 data); +static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw); +static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw); + +/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ +/* Offset 04h HSFSTS */ +union ich8_hws_flash_status { + struct ich8_hsfsts { + u16 flcdone :1; /* bit 0 Flash Cycle Done */ + u16 flcerr :1; /* bit 1 Flash Cycle Error */ + u16 dael :1; /* bit 2 Direct Access error Log */ + u16 berasesz :2; /* bit 4:3 Sector Erase Size */ + u16 flcinprog :1; /* bit 5 flash cycle in Progress */ + u16 reserved1 :2; /* bit 13:6 Reserved */ + u16 reserved2 :6; /* bit 13:6 Reserved */ + u16 fldesvalid :1; /* bit 14 Flash Descriptor Valid */ + u16 flockdn :1; /* bit 15 Flash Config Lock-Down */ + } hsf_status; + u16 regval; +}; + +/* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */ +/* Offset 06h FLCTL */ +union ich8_hws_flash_ctrl { + struct ich8_hsflctl { + u16 flcgo :1; /* 0 Flash Cycle Go */ + u16 flcycle :2; /* 2:1 Flash Cycle */ + u16 reserved :5; /* 7:3 Reserved */ + u16 fldbcount :2; /* 9:8 Flash Data Byte Count */ + u16 flockdn :6; /* 15:10 Reserved */ + } hsf_ctrl; + u16 regval; +}; + +/* ICH Flash Region Access Permissions */ +union ich8_hws_flash_regacc { + struct ich8_flracc { + u32 grra :8; /* 0:7 GbE region Read Access */ + u32 grwa :8; /* 8:15 GbE region Write Access */ + u32 gmrag :8; /* 23:16 GbE Master Read Access Grant */ + u32 gmwag :8; /* 31:24 GbE Master Write Access Grant */ + } hsf_flregacc; + u16 regval; +}; + +struct e1000_shadow_ram { + u16 value; + bool modified; +}; + +struct e1000_dev_spec_ich8lan { + bool kmrn_lock_loss_workaround_enabled; + struct e1000_shadow_ram shadow_ram[E1000_SHADOW_RAM_WORDS]; +}; + +/* + * NV RAM mapping can get nested, so keep track of the mapping depth. + */ +static int e1000e_map_nvram(struct e1000_hw *hw) +{ + int ret_val = E1000_SUCCESS; + struct e1000_adapter *adapter = hw->back; + + spin_lock(&hw->flash_address_map_lock); + + hw->flash_address_map_cnt++; + + if (hw->flash_address_map_cnt==1) { + BUG_ON(adapter->hw.flash_address); + WARN_ON(irqs_disabled()); + adapter->hw.flash_address = ioremap(pci_resource_start(adapter->pdev, 1), + pci_resource_len(adapter->pdev, 1)); + if (!adapter->hw.flash_address) { + hw->flash_address_map_cnt--; + ret_val = -E1000_ERR_NVM; + } + } + + spin_unlock(&hw->flash_address_map_lock); + + return ret_val; +} + +static void e1000e_unmap_nvram(struct e1000_hw *hw) +{ + struct e1000_adapter *adapter = hw->back; + + spin_lock(&hw->flash_address_map_lock); + + BUG_ON(!hw->flash_address_map_cnt); + + hw->flash_address_map_cnt--; + + if (hw->flash_address_map_cnt==0) { + BUG_ON(!adapter->hw.flash_address); + WARN_ON(irqs_disabled()); + iounmap(adapter->hw.flash_address); + adapter->hw.flash_address = NULL; + } + + spin_unlock(&hw->flash_address_map_lock); +} + +/** + * e1000_init_phy_params_ich8lan - Initialize PHY function pointers + * @hw: pointer to the HW structure + * + * Initialize family-specific PHY parameters and function pointers. + **/ +static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = E1000_SUCCESS; + u16 i = 0; + + DEBUGFUNC("e1000_init_phy_params_ich8lan"); + + phy->addr = 1; + phy->reset_delay_us = 100; + + phy->ops.acquire = e1000_acquire_swflag_ich8lan; + phy->ops.check_polarity = e1000_check_polarity_ife_ich8lan; + phy->ops.check_reset_block = e1000_check_reset_block_ich8lan; + phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ich8lan; + phy->ops.get_cable_length = e1000_get_cable_length_igp_2; + phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan; + phy->ops.get_info = e1000_get_phy_info_ich8lan; + phy->ops.read_reg = e1000_read_phy_reg_igp; + phy->ops.release = e1000_release_swflag_ich8lan; + phy->ops.reset = e1000_phy_hw_reset_ich8lan; + phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan; + phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan; + phy->ops.write_reg = e1000_write_phy_reg_igp; + phy->ops.power_up = e1000_power_up_phy_copper; + phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; + + /* + * We may need to do this twice - once for IGP and if that fails, + * we'll set BM func pointers and try again + */ + ret_val = e1000_determine_phy_address(hw); + if (ret_val) { + phy->ops.write_reg = e1000_write_phy_reg_bm; + phy->ops.read_reg = e1000_read_phy_reg_bm; + ret_val = e1000_determine_phy_address(hw); + if (ret_val) { + DEBUGOUT("Cannot determine PHY address. Erroring out\n"); + goto out; + } + } + + phy->id = 0; + while ((e1000_phy_unknown == e1000_get_phy_type_from_id(phy->id)) && + (i++ < 100)) { + msec_delay(1); + ret_val = e1000_get_phy_id(hw); + if (ret_val) + goto out; + } + + /* Verify phy id */ + switch (phy->id) { + case IGP03E1000_E_PHY_ID: + phy->type = e1000_phy_igp_3; + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; + break; + case IFE_E_PHY_ID: + case IFE_PLUS_E_PHY_ID: + case IFE_C_E_PHY_ID: + phy->type = e1000_phy_ife; + phy->autoneg_mask = E1000_ALL_NOT_GIG; + break; + case BME1000_E_PHY_ID: + phy->type = e1000_phy_bm; + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; + phy->ops.read_reg = e1000_read_phy_reg_bm; + phy->ops.write_reg = e1000_write_phy_reg_bm; + phy->ops.commit = e1000_phy_sw_reset_generic; + break; + default: + ret_val = -E1000_ERR_PHY; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_init_nvm_params_ich8lan - Initialize NVM function pointers + * @hw: pointer to the HW structure + * + * Initialize family-specific NVM parameters and function + * pointers. + **/ +static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + struct e1000_dev_spec_ich8lan *dev_spec; + u32 gfpreg, sector_base_addr, sector_end_addr; + s32 ret_val = E1000_SUCCESS; + u16 i; + + DEBUGFUNC("e1000_init_nvm_params_ich8lan"); + + /* Can't read flash registers if the register set isn't mapped. */ + ret_val = e1000e_map_nvram(hw); + if (ret_val) { + DEBUGOUT("ERROR: Flash registers not mapped\n"); + return -E1000_ERR_CONFIG; + } + + nvm->type = e1000_nvm_flash_sw; + + gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG); + + /* + * sector_X_addr is a "sector"-aligned address (4096 bytes) + * Add 1 to sector_end_addr since this sector is included in + * the overall size. + */ + sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK; + sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1; + + /* flash_base_addr is byte-aligned */ + nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT; + + /* + * find total size of the NVM, then cut in half since the total + * size represents two separate NVM banks. + */ + nvm->flash_bank_size = (sector_end_addr - sector_base_addr) + << FLASH_SECTOR_ADDR_SHIFT; + nvm->flash_bank_size /= 2; + /* Adjust to word count */ + nvm->flash_bank_size /= sizeof(u16); + + nvm->word_size = E1000_SHADOW_RAM_WORDS; + + dev_spec = (struct e1000_dev_spec_ich8lan *)hw->dev_spec; + + if (!dev_spec) { + DEBUGOUT("dev_spec pointer is set to NULL.\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + /* Clear shadow ram */ + for (i = 0; i < nvm->word_size; i++) { + dev_spec->shadow_ram[i].modified = false; + dev_spec->shadow_ram[i].value = 0xFFFF; + } + + /* Function Pointers */ + nvm->ops.acquire = e1000_acquire_swflag_ich8lan; + nvm->ops.read = e1000_read_nvm_ich8lan; + nvm->ops.release = e1000_release_swflag_ich8lan; + nvm->ops.update = e1000_update_nvm_checksum_ich8lan; + nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan; + nvm->ops.validate = e1000_validate_nvm_checksum_ich8lan; + nvm->ops.write = e1000_write_nvm_ich8lan; + +out: + e1000e_unmap_nvram(hw); + return ret_val; +} + +/** + * e1000_init_mac_params_ich8lan - Initialize MAC function pointers + * @hw: pointer to the HW structure + * + * Initialize family-specific MAC parameters and function + * pointers. + **/ +static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_init_mac_params_ich8lan"); + + /* Set media type function pointer */ + hw->phy.media_type = e1000_media_type_copper; + + /* Set mta register count */ + mac->mta_reg_count = 32; + /* Set rar entry count */ + mac->rar_entry_count = E1000_ICH_RAR_ENTRIES; + if (mac->type == e1000_ich8lan) + mac->rar_entry_count--; + /* Set if part includes ASF firmware */ + mac->asf_firmware_present = true; + /* Set if manageability features are enabled. */ + mac->arc_subsystem_valid = true; + + /* Function pointers */ + + /* bus type/speed/width */ + mac->ops.get_bus_info = e1000_get_bus_info_ich8lan; + /* reset */ + mac->ops.reset_hw = e1000_reset_hw_ich8lan; + /* hw initialization */ + mac->ops.init_hw = e1000_init_hw_ich8lan; + /* link setup */ + mac->ops.setup_link = e1000_setup_link_ich8lan; + /* physical interface setup */ + mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan; + /* check for link */ + mac->ops.check_for_link = e1000_check_for_copper_link_generic; + /* check management mode */ + mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan; + /* link info */ + mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan; + /* multicast address update */ + mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; + /* setting MTA */ + mac->ops.mta_set = e1000_mta_set_generic; + /* blink LED */ + mac->ops.blink_led = e1000_blink_led_generic; + /* setup LED */ + mac->ops.setup_led = e1000_setup_led_generic; + /* cleanup LED */ + mac->ops.cleanup_led = e1000_cleanup_led_ich8lan; + /* turn on/off LED */ + mac->ops.led_on = e1000_led_on_ich8lan; + mac->ops.led_off = e1000_led_off_ich8lan; + /* remove device */ + mac->ops.remove_device = e1000_remove_device_generic; + /* clear hardware counters */ + mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan; + + hw->dev_spec_size = sizeof(struct e1000_dev_spec_ich8lan); + + /* Device-specific structure allocation */ + ret_val = e1000_alloc_zeroed_dev_spec_struct(hw, hw->dev_spec_size); + if (ret_val) + goto out; + + /* Enable PCS Lock-loss workaround for ICH8 */ + if (mac->type == e1000_ich8lan) + e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, true); + + +out: + return ret_val; +} + +/** + * e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers + * @hw: pointer to the HW structure + * + * Initialize family-specific function pointers for PHY, MAC, and NVM. + **/ +void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_init_function_pointers_ich8lan"); + + e1000_init_mac_ops_generic(hw); + e1000_init_nvm_ops_generic(hw); + hw->mac.ops.init_params = e1000_init_mac_params_ich8lan; + hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan; + hw->phy.ops.init_params = e1000_init_phy_params_ich8lan; +} + +/** + * e1000_acquire_swflag_ich8lan - Acquire software control flag + * @hw: pointer to the HW structure + * + * Acquires the software control flag for performing NVM and PHY + * operations. This is a function pointer entry point only called by + * read/write routines for the PHY and NVM parts. + **/ +static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) +{ + u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_acquire_swflag_ich8lan"); + + while (timeout) { + extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; + E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); + + extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) + break; + msec_delay_irq(1); + timeout--; + } + + if (!timeout) { + DEBUGOUT("FW or HW has locked the resource for too long.\n"); + extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; + E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_release_swflag_ich8lan - Release software control flag + * @hw: pointer to the HW structure + * + * Releases the software control flag for performing NVM and PHY operations. + * This is a function pointer entry point only called by read/write + * routines for the PHY and NVM parts. + **/ +static void e1000_release_swflag_ich8lan(struct e1000_hw *hw) +{ + u32 extcnf_ctrl; + + DEBUGFUNC("e1000_release_swflag_ich8lan"); + + extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; + E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); + + return; +} + +/** + * e1000_check_mng_mode_ich8lan - Checks management mode + * @hw: pointer to the HW structure + * + * This checks if the adapter has manageability enabled. + * This is a function pointer entry point only called by read/write + * routines for the PHY and NVM parts. + **/ +static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw) +{ + u32 fwsm; + + DEBUGFUNC("e1000_check_mng_mode_ich8lan"); + + fwsm = E1000_READ_REG(hw, E1000_FWSM); + + return ((fwsm & E1000_FWSM_MODE_MASK) == + (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)); +} + +/** + * e1000_check_reset_block_ich8lan - Check if PHY reset is blocked + * @hw: pointer to the HW structure + * + * Checks if firmware is blocking the reset of the PHY. + * This is a function pointer entry point only called by + * reset routines. + **/ +static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw) +{ + u32 fwsm; + + DEBUGFUNC("e1000_check_reset_block_ich8lan"); + + fwsm = E1000_READ_REG(hw, E1000_FWSM); + + return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? E1000_SUCCESS + : E1000_BLK_PHY_RESET; +} + +/** + * e1000_phy_force_speed_duplex_ich8lan - Force PHY speed & duplex + * @hw: pointer to the HW structure + * + * Forces the speed and duplex settings of the PHY. + * This is a function pointer entry point only called by + * PHY setup routines. + **/ +static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + bool link; + + DEBUGFUNC("e1000_phy_force_speed_duplex_ich8lan"); + + if (phy->type != e1000_phy_ife) { + ret_val = e1000_phy_force_speed_duplex_igp(hw); + goto out; + } + + ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data); + if (ret_val) + goto out; + + e1000_phy_force_speed_duplex_setup(hw, &data); + + ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data); + if (ret_val) + goto out; + + /* Disable MDI-X support for 10/100 */ + ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data); + if (ret_val) + goto out; + + data &= ~IFE_PMC_AUTO_MDIX; + data &= ~IFE_PMC_FORCE_MDIX; + + ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data); + if (ret_val) + goto out; + + DEBUGOUT1("IFE PMC: %X\n", data); + + usec_delay(1); + + if (phy->autoneg_wait_to_complete) { + DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n"); + + ret_val = e1000_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + goto out; + + if (!link) { + DEBUGOUT("Link taking longer than expected.\n"); + } + + /* Try once more */ + ret_val = e1000_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_phy_hw_reset_ich8lan - Performs a PHY reset + * @hw: pointer to the HW structure + * + * Resets the PHY + * This is a function pointer entry point called by drivers + * or other shared routines. + **/ +static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + struct e1000_nvm_info *nvm = &hw->nvm; + u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask; + s32 ret_val; + u16 loop = E1000_ICH8_LAN_INIT_TIMEOUT; + u16 word_addr, reg_data, reg_addr, phy_page = 0; + + DEBUGFUNC("e1000_phy_hw_reset_ich8lan"); + + ret_val = e1000_phy_hw_reset_generic(hw); + if (ret_val) + goto out; + + /* + * Initialize the PHY from the NVM on ICH platforms. This + * is needed due to an issue where the NVM configuration is + * not properly autoloaded after power transitions. + * Therefore, after each PHY reset, we will load the + * configuration data out of the NVM manually. + */ + if (hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) { + /* Check if SW needs configure the PHY */ + if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) || + (hw->device_id == E1000_DEV_ID_ICH8_IGP_M)) + sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; + else + sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; + + data = E1000_READ_REG(hw, E1000_FEXTNVM); + if (!(data & sw_cfg_mask)) + goto out; + + /* Wait for basic configuration completes before proceeding*/ + do { + data = E1000_READ_REG(hw, E1000_STATUS); + data &= E1000_STATUS_LAN_INIT_DONE; + usec_delay(100); + } while ((!data) && --loop); + + /* + * If basic configuration is incomplete before the above loop + * count reaches 0, loading the configuration from NVM will + * leave the PHY in a bad state possibly resulting in no link. + */ + if (loop == 0) { + DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n"); + } + + /* Clear the Init Done bit for the next init event */ + data = E1000_READ_REG(hw, E1000_STATUS); + data &= ~E1000_STATUS_LAN_INIT_DONE; + E1000_WRITE_REG(hw, E1000_STATUS, data); + + /* + * Make sure HW does not configure LCD from PHY + * extended configuration before SW configuration + */ + data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) + goto out; + + cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE); + cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; + cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT; + if (!cnf_size) + goto out; + + cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; + cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; + + /* + * Configure LCD from extended configuration + * region. + */ + + /* cnf_base_addr is in DWORD */ + word_addr = (u16)(cnf_base_addr << 1); + + for (i = 0; i < cnf_size; i++) { + ret_val = nvm->ops.read(hw, + (word_addr + i * 2), + 1, + ®_data); + if (ret_val) + goto out; + + ret_val = nvm->ops.read(hw, + (word_addr + i * 2 + 1), + 1, + ®_addr); + if (ret_val) + goto out; + + /* Save off the PHY page for future writes. */ + if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) { + phy_page = reg_data; + continue; + } + + reg_addr |= phy_page; + + ret_val = phy->ops.write_reg(hw, + (u32)reg_addr, + reg_data); + if (ret_val) + goto out; + } + } + +out: + return ret_val; +} + +/** + * e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info + * @hw: pointer to the HW structure + * + * Wrapper for calling the get_phy_info routines for the appropriate phy type. + * This is a function pointer entry point called by drivers + * or other shared routines. + **/ +static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val = -E1000_ERR_PHY_TYPE; + + DEBUGFUNC("e1000_get_phy_info_ich8lan"); + + switch (hw->phy.type) { + case e1000_phy_ife: + ret_val = e1000_get_phy_info_ife_ich8lan(hw); + break; + case e1000_phy_igp_3: + case e1000_phy_bm: + ret_val = e1000_get_phy_info_igp(hw); + break; + default: + break; + } + + return ret_val; +} + +/** + * e1000_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states + * @hw: pointer to the HW structure + * + * Populates "phy" structure with various feature states. + * This function is only called by other family-specific + * routines. + **/ +static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + bool link; + + DEBUGFUNC("e1000_get_phy_info_ife_ich8lan"); + + ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + goto out; + + if (!link) { + DEBUGOUT("Phy info is only valid if link is up\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + ret_val = phy->ops.read_reg(hw, IFE_PHY_SPECIAL_CONTROL, &data); + if (ret_val) + goto out; + phy->polarity_correction = (data & IFE_PSC_AUTO_POLARITY_DISABLE) + ? false : true; + + if (phy->polarity_correction) { + ret_val = e1000_check_polarity_ife_ich8lan(hw); + if (ret_val) + goto out; + } else { + /* Polarity is forced */ + phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + } + + ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data); + if (ret_val) + goto out; + + phy->is_mdix = (data & IFE_PMC_MDIX_STATUS) ? true : false; + + /* The following parameters are undefined for 10/100 operation. */ + phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; + phy->local_rx = e1000_1000t_rx_status_undefined; + phy->remote_rx = e1000_1000t_rx_status_undefined; + +out: + return ret_val; +} + +/** + * e1000_check_polarity_ife_ich8lan - Check cable polarity for IFE PHY + * @hw: pointer to the HW structure + * + * Polarity is determined on the polarity reversal feature being enabled. + * This function is only called by other family-specific + * routines. + **/ +static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, offset, mask; + + DEBUGFUNC("e1000_check_polarity_ife_ich8lan"); + + /* + * Polarity is determined based on the reversal feature + * being enabled. + */ + if (phy->polarity_correction) { + offset = IFE_PHY_EXTENDED_STATUS_CONTROL; + mask = IFE_PESC_POLARITY_REVERSED; + } else { + offset = IFE_PHY_SPECIAL_CONTROL; + mask = IFE_PSC_FORCE_POLARITY; + } + + ret_val = phy->ops.read_reg(hw, offset, &phy_data); + + if (!ret_val) + phy->cable_polarity = (phy_data & mask) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + + return ret_val; +} + +/** + * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state + * @hw: pointer to the HW structure + * @active: true to enable LPLU, false to disable + * + * Sets the LPLU D0 state according to the active flag. When + * activating LPLU this function also disables smart speed + * and vice versa. LPLU will not be activated unless the + * device autonegotiation advertisement meets standards of + * either 10 or 10/100 or 10/100/1000 at all duplexes. + * This is a function pointer entry point only called by + * PHY setup routines. + **/ +static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, + bool active) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 phy_ctrl; + s32 ret_val = E1000_SUCCESS; + u16 data; + + DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan"); + + if (phy->type == e1000_phy_ife) + goto out; + + phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); + + if (active) { + phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU; + E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); + + /* + * Call gig speed drop workaround on LPLU before accessing + * any PHY registers + */ + if ((hw->mac.type == e1000_ich8lan) && + (hw->phy.type == e1000_phy_igp_3)) + e1000_gig_downshift_workaround_ich8lan(hw); + + /* When LPLU is enabled, we should disable SmartSpeed */ + ret_val = phy->ops.read_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = phy->ops.write_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + goto out; + } else { + phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU; + E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); + + /* + * LPLU and SmartSpeed are mutually exclusive. LPLU is used + * during Dx states where the power conservation is most + * important. During driver activity we should enable + * SmartSpeed, so performance is maintained. + */ + if (phy->smart_speed == e1000_smart_speed_on) { + ret_val = phy->ops.read_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + goto out; + + data |= IGP01E1000_PSCFR_SMART_SPEED; + ret_val = phy->ops.write_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + goto out; + } else if (phy->smart_speed == e1000_smart_speed_off) { + ret_val = phy->ops.read_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + goto out; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = phy->ops.write_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + goto out; + } + } + +out: + return ret_val; +} + +/** + * e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state + * @hw: pointer to the HW structure + * @active: true to enable LPLU, false to disable + * + * Sets the LPLU D3 state according to the active flag. When + * activating LPLU this function also disables smart speed + * and vice versa. LPLU will not be activated unless the + * device autonegotiation advertisement meets standards of + * either 10 or 10/100 or 10/100/1000 at all duplexes. + * This is a function pointer entry point only called by + * PHY setup routines. + **/ +static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, + bool active) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 phy_ctrl; + s32 ret_val = E1000_SUCCESS; + u16 data; + + DEBUGFUNC("e1000_set_d3_lplu_state_ich8lan"); + + phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); + + if (!active) { + phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU; + E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); + /* + * LPLU and SmartSpeed are mutually exclusive. LPLU is used + * during Dx states where the power conservation is most + * important. During driver activity we should enable + * SmartSpeed, so performance is maintained. + */ + if (phy->smart_speed == e1000_smart_speed_on) { + ret_val = phy->ops.read_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + goto out; + + data |= IGP01E1000_PSCFR_SMART_SPEED; + ret_val = phy->ops.write_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + goto out; + } else if (phy->smart_speed == e1000_smart_speed_off) { + ret_val = phy->ops.read_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + goto out; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = phy->ops.write_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + goto out; + } + } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || + (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || + (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { + phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU; + E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); + + /* + * Call gig speed drop workaround on LPLU before accessing + * any PHY registers + */ + if ((hw->mac.type == e1000_ich8lan) && + (hw->phy.type == e1000_phy_igp_3)) + e1000_gig_downshift_workaround_ich8lan(hw); + + /* When LPLU is enabled, we should disable SmartSpeed */ + ret_val = phy->ops.read_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + goto out; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = phy->ops.write_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + } + +out: + return ret_val; +} + +/** + * e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1 + * @hw: pointer to the HW structure + * @bank: pointer to the variable that returns the active bank + * + * Reads signature byte from the NVM using the flash access registers. + **/ +static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) +{ + s32 ret_val = E1000_SUCCESS; + struct e1000_nvm_info *nvm = &hw->nvm; + /* flash bank size is in words */ + u32 bank1_offset = nvm->flash_bank_size * sizeof(u16); + u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1; + u8 bank_high_byte = 0; + + if (hw->mac.type != e1000_ich10lan) { + if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_SEC1VAL) + *bank = 1; + else + *bank = 0; + } else if (hw->dev_spec != NULL) { + /* + * Make sure the signature for bank 0 is valid, + * if not check for bank1 + */ + e1000_read_flash_byte_ich8lan(hw, act_offset, &bank_high_byte); + if ((bank_high_byte & 0xC0) == 0x80) { + *bank = 0; + } else { + /* + * find if segment 1 is valid by verifying + * bit 15:14 = 10b in word 0x13 + */ + e1000_read_flash_byte_ich8lan(hw, + act_offset + bank1_offset, + &bank_high_byte); + + /* bank1 has a valid signature equivalent to SEC1V */ + if ((bank_high_byte & 0xC0) == 0x80) { + *bank = 1; + } else { + DEBUGOUT("ERROR: EEPROM not present\n"); + ret_val = -E1000_ERR_NVM; + } + } + } else { + DEBUGOUT("DEV SPEC is NULL\n"); + ret_val = -E1000_ERR_NVM; + } + + return ret_val; +} + +/** + * e1000_read_nvm_ich8lan - Read word(s) from the NVM + * @hw: pointer to the HW structure + * @offset: The offset (in bytes) of the word(s) to read. + * @words: Size of data to read in words + * @data: Pointer to the word(s) to read at offset. + * + * Reads a word(s) from the NVM using the flash access registers. + **/ +static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + struct e1000_dev_spec_ich8lan *dev_spec; + u32 act_offset; + s32 ret_val = E1000_SUCCESS; + u32 bank = 0; + u16 i, word; + + DEBUGFUNC("e1000_read_nvm_ich8lan"); + + dev_spec = (struct e1000_dev_spec_ich8lan *)hw->dev_spec; + + if (!dev_spec) { + DEBUGOUT("dev_spec pointer is set to NULL.\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || + (words == 0)) { + DEBUGOUT("nvm parameter(s) out of bounds\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + + ret_val = nvm->ops.acquire(hw); + if (ret_val) + goto out; + + ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); + if (ret_val != E1000_SUCCESS) + goto out; + + act_offset = (bank) ? nvm->flash_bank_size : 0; + act_offset += offset; + + for (i = 0; i < words; i++) { + if ((dev_spec->shadow_ram) && + (dev_spec->shadow_ram[offset+i].modified)) { + data[i] = dev_spec->shadow_ram[offset+i].value; + } else { + ret_val = e1000_read_flash_word_ich8lan(hw, + act_offset + i, + &word); + if (ret_val) + break; + data[i] = word; + } + } + + nvm->ops.release(hw); + +out: + return ret_val; +} + +/** + * e1000_flash_cycle_init_ich8lan - Initialize flash + * @hw: pointer to the HW structure + * + * This function does initial flash setup so that a new read/write/erase cycle + * can be started. + **/ +static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw) +{ + union ich8_hws_flash_status hsfsts; + s32 ret_val = -E1000_ERR_NVM; + s32 i = 0; + + DEBUGFUNC("e1000_flash_cycle_init_ich8lan"); + + ret_val = e1000e_map_nvram(hw); + if (ret_val) { + DEBUGOUT("ERROR: Flash registers not mapped\n"); + return ret_val; + } + + hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); + + /* Check if the flash descriptor is valid */ + if (hsfsts.hsf_status.fldesvalid == 0) { + DEBUGOUT("Flash descriptor invalid. " + "SW Sequencing must be used."); + goto out; + } + + /* Clear FCERR and DAEL in hw status by writing 1 */ + hsfsts.hsf_status.flcerr = 1; + hsfsts.hsf_status.dael = 1; + + E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval); + + /* + * Either we should have a hardware SPI cycle in progress + * bit to check against, in order to start a new cycle or + * FDONE bit should be changed in the hardware so that it + * is 1 after hardware reset, which can then be used as an + * indication whether a cycle is in progress or has been + * completed. + */ + + if (hsfsts.hsf_status.flcinprog == 0) { + /* + * There is no cycle running at present, + * so we can start a cycle. + * Begin by setting Flash Cycle Done. + */ + hsfsts.hsf_status.flcdone = 1; + E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval); + ret_val = E1000_SUCCESS; + } else { + /* + * Otherwise poll for sometime so the current + * cycle has a chance to end before giving up. + */ + for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) { + hsfsts.regval = E1000_READ_FLASH_REG16(hw, + ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcinprog == 0) { + ret_val = E1000_SUCCESS; + break; + } + usec_delay(1); + } + if (ret_val == E1000_SUCCESS) { + /* + * Successful in waiting for previous cycle to timeout, + * now set the Flash Cycle Done. + */ + hsfsts.hsf_status.flcdone = 1; + E1000_WRITE_FLASH_REG16(hw, + ICH_FLASH_HSFSTS, + hsfsts.regval); + } else { + DEBUGOUT("Flash controller busy, cannot get access"); + } + } + +out: + e1000e_unmap_nvram(hw); + return ret_val; +} + +/** + * e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase) + * @hw: pointer to the HW structure + * @timeout: maximum time to wait for completion + * + * This function starts a flash cycle and waits for its completion. + **/ +static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout) +{ + union ich8_hws_flash_ctrl hsflctl; + union ich8_hws_flash_status hsfsts; + s32 ret_val = -E1000_ERR_NVM; + u32 i = 0; + + DEBUGFUNC("e1000_flash_cycle_ich8lan"); + + ret_val = e1000e_map_nvram(hw); + if (ret_val) { + DEBUGOUT("ERROR: Flash registers not mapped\n"); + return ret_val; + } + + /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ + hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); + hsflctl.hsf_ctrl.flcgo = 1; + E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval); + + /* wait till FDONE bit is set to 1 */ + do { + hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcdone == 1) + break; + usec_delay(1); + } while (i++ < timeout); + + if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) + ret_val = E1000_SUCCESS; + + e1000e_unmap_nvram(hw); + + return ret_val; +} + +/** + * e1000_read_flash_word_ich8lan - Read word from flash + * @hw: pointer to the HW structure + * @offset: offset to data location + * @data: pointer to the location for storing the data + * + * Reads the flash word at offset into data. Offset is converted + * to bytes before read. + **/ +static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset, + u16 *data) +{ + s32 ret_val; + + DEBUGFUNC("e1000_read_flash_word_ich8lan"); + + if (!data) { + ret_val = -E1000_ERR_NVM; + goto out; + } + + /* Must convert offset into bytes. */ + offset <<= 1; + + ret_val = e1000_read_flash_data_ich8lan(hw, offset, 2, data); + +out: + return ret_val; +} + +/** + * e1000_read_flash_byte_ich8lan - Read byte from flash + * @hw: pointer to the HW structure + * @offset: The offset of the byte to read. + * @data: Pointer to a byte to store the value read. + * + * Reads a single byte from the NVM using the flash access registers. + **/ +static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, + u8* data) +{ + s32 ret_val = E1000_SUCCESS; + u16 word = 0; + + ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word); + if (ret_val) + goto out; + + *data = (u8)word; + +out: + return ret_val; +} + +/** + * e1000_read_flash_data_ich8lan - Read byte or word from NVM + * @hw: pointer to the HW structure + * @offset: The offset (in bytes) of the byte or word to read. + * @size: Size of data to read, 1=byte 2=word + * @data: Pointer to the word to store the value read. + * + * Reads a byte or word from the NVM using the flash access registers. + **/ +static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, + u8 size, u16* data) +{ + union ich8_hws_flash_status hsfsts; + union ich8_hws_flash_ctrl hsflctl; + u32 flash_linear_addr; + u32 flash_data = 0; + s32 ret_val = -E1000_ERR_NVM; + u8 count = 0; + + DEBUGFUNC("e1000_read_flash_data_ich8lan"); + + ret_val = e1000e_map_nvram(hw); + if (ret_val) { + DEBUGOUT("ERROR: Flash registers not mapped\n"); + return ret_val; + } + + if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK) + goto out; + + flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) + + hw->nvm.flash_base_addr; + + do { + usec_delay(1); + /* Steps */ + ret_val = e1000_flash_cycle_init_ich8lan(hw); + if (ret_val != E1000_SUCCESS) + break; + + hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); + /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ + hsflctl.hsf_ctrl.fldbcount = size - 1; + hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; + E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval); + + E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr); + + ret_val = e1000_flash_cycle_ich8lan(hw, + ICH_FLASH_READ_COMMAND_TIMEOUT); + + /* + * Check if FCERR is set to 1, if set to 1, clear it + * and try the whole sequence a few more times, else + * read in (shift in) the Flash Data0, the order is + * least significant byte first msb to lsb + */ + if (ret_val == E1000_SUCCESS) { + flash_data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0); + if (size == 1) { + *data = (u8)(flash_data & 0x000000FF); + } else if (size == 2) { + *data = (u16)(flash_data & 0x0000FFFF); + } + break; + } else { + /* + * If we've gotten here, then things are probably + * completely hosed, but if the error condition is + * detected, it won't hurt to give it another try... + * ICH_FLASH_CYCLE_REPEAT_COUNT times. + */ + hsfsts.regval = E1000_READ_FLASH_REG16(hw, + ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcerr == 1) { + /* Repeat for some time before giving up. */ + continue; + } else if (hsfsts.hsf_status.flcdone == 0) { + DEBUGOUT("Timeout error - flash cycle " + "did not complete."); + break; + } + } + } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); + +out: + e1000e_unmap_nvram(hw); + return ret_val; +} + +/** + * e1000_write_nvm_ich8lan - Write word(s) to the NVM + * @hw: pointer to the HW structure + * @offset: The offset (in bytes) of the word(s) to write. + * @words: Size of data to write in words + * @data: Pointer to the word(s) to write at offset. + * + * Writes a byte or word to the NVM using the flash access registers. + **/ +static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + struct e1000_dev_spec_ich8lan *dev_spec; + s32 ret_val = E1000_SUCCESS; + u16 i; + + DEBUGFUNC("e1000_write_nvm_ich8lan"); + + dev_spec = (struct e1000_dev_spec_ich8lan *)hw->dev_spec; + + if (!dev_spec) { + DEBUGOUT("dev_spec pointer is set to NULL.\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || + (words == 0)) { + DEBUGOUT("nvm parameter(s) out of bounds\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + + ret_val = nvm->ops.acquire(hw); + if (ret_val) + goto out; + + for (i = 0; i < words; i++) { + dev_spec->shadow_ram[offset+i].modified = true; + dev_spec->shadow_ram[offset+i].value = data[i]; + } + + nvm->ops.release(hw); + +out: + return ret_val; +} + +/** + * e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM + * @hw: pointer to the HW structure + * + * The NVM checksum is updated by calling the generic update_nvm_checksum, + * which writes the checksum to the shadow ram. The changes in the shadow + * ram are then committed to the EEPROM by processing each bank at a time + * checking for the modified bit and writing only the pending changes. + * After a successful commit, the shadow ram is cleared and is ready for + * future writes. + **/ +static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + struct e1000_dev_spec_ich8lan *dev_spec; + u32 i, act_offset, new_bank_offset, old_bank_offset, bank; + s32 ret_val; + u16 data; + + DEBUGFUNC("e1000_update_nvm_checksum_ich8lan"); + + dev_spec = (struct e1000_dev_spec_ich8lan *)hw->dev_spec; + + ret_val = e1000_update_nvm_checksum_generic(hw); + if (ret_val) + goto out; + + if (nvm->type != e1000_nvm_flash_sw) + goto out; + + ret_val = nvm->ops.acquire(hw); + if (ret_val) + goto out; + + /* + * We're writing to the opposite bank so if we're on bank 1, + * write to bank 0 etc. We also need to erase the segment that + * is going to be written + */ + ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); + if (ret_val != E1000_SUCCESS) + goto out; + + if (bank == 0) { + new_bank_offset = nvm->flash_bank_size; + old_bank_offset = 0; + e1000_erase_flash_bank_ich8lan(hw, 1); + } else { + old_bank_offset = nvm->flash_bank_size; + new_bank_offset = 0; + e1000_erase_flash_bank_ich8lan(hw, 0); + } + + for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { + /* + * Determine whether to write the value stored + * in the other NVM bank or a modified value stored + * in the shadow RAM + */ + if (dev_spec->shadow_ram[i].modified) { + data = dev_spec->shadow_ram[i].value; + } else { + e1000_read_flash_word_ich8lan(hw, + i + old_bank_offset, + &data); + } + + /* + * If the word is 0x13, then make sure the signature bits + * (15:14) are 11b until the commit has completed. + * This will allow us to write 10b which indicates the + * signature is valid. We want to do this after the write + * has completed so that we don't mark the segment valid + * while the write is still in progress + */ + if (i == E1000_ICH_NVM_SIG_WORD) + data |= E1000_ICH_NVM_SIG_MASK; + + /* Convert offset to bytes. */ + act_offset = (i + new_bank_offset) << 1; + + usec_delay(100); + /* Write the bytes to the new bank. */ + ret_val = e1000_retry_write_flash_byte_ich8lan(hw, + act_offset, + (u8)data); + if (ret_val) + break; + + usec_delay(100); + ret_val = e1000_retry_write_flash_byte_ich8lan(hw, + act_offset + 1, + (u8)(data >> 8)); + if (ret_val) + break; + } + + /* + * Don't bother writing the segment valid bits if sector + * programming failed. + */ + if (ret_val) { + DEBUGOUT("Flash commit failed.\n"); + nvm->ops.release(hw); + goto out; + } + + /* + * Finally validate the new segment by setting bit 15:14 + * to 10b in word 0x13 , this can be done without an + * erase as well since these bits are 11 to start with + * and we need to change bit 14 to 0b + */ + act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; + e1000_read_flash_word_ich8lan(hw, act_offset, &data); + data &= 0xBFFF; + ret_val = e1000_retry_write_flash_byte_ich8lan(hw, + act_offset * 2 + 1, + (u8)(data >> 8)); + if (ret_val) { + nvm->ops.release(hw); + goto out; + } + + /* + * And invalidate the previously valid segment by setting + * its signature word (0x13) high_byte to 0b. This can be + * done without an erase because flash erase sets all bits + * to 1's. We can write 1's to 0's without an erase + */ + act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1; + ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0); + if (ret_val) { + nvm->ops.release(hw); + goto out; + } + + /* Great! Everything worked, we can now clear the cached entries. */ + for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { + dev_spec->shadow_ram[i].modified = false; + dev_spec->shadow_ram[i].value = 0xFFFF; + } + + nvm->ops.release(hw); + + /* + * Reload the EEPROM, or else modifications will not appear + * until after the next adapter reset. + */ + nvm->ops.reload(hw); + msec_delay(10); + +out: + return ret_val; +} + +/** + * e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum + * @hw: pointer to the HW structure + * + * Check to see if checksum needs to be fixed by reading bit 6 in word 0x19. + * If the bit is 0, that the EEPROM had been modified, but the checksum was + * not calculated, in which case we need to calculate the checksum and set + * bit 6. + **/ +static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 data; + + DEBUGFUNC("e1000_validate_nvm_checksum_ich8lan"); + + /* + * Read 0x19 and check bit 6. If this bit is 0, the checksum + * needs to be fixed. This bit is an indication that the NVM + * was prepared by OEM software and did not calculate the + * checksum...a likely scenario. + */ + ret_val = hw->nvm.ops.read(hw, 0x19, 1, &data); + if (ret_val) + goto out; + + if ((data & 0x40) == 0) { + data |= 0x40; + ret_val = hw->nvm.ops.write(hw, 0x19, 1, &data); + if (ret_val) + goto out; + ret_val = hw->nvm.ops.update(hw); + if (ret_val) + goto out; + } + + ret_val = e1000_validate_nvm_checksum_generic(hw); + +out: + return ret_val; +} + +/** + * e1000_write_flash_data_ich8lan - Writes bytes to the NVM + * @hw: pointer to the HW structure + * @offset: The offset (in bytes) of the byte/word to read. + * @size: Size of data to read, 1=byte 2=word + * @data: The byte(s) to write to the NVM. + * + * Writes one/two bytes to the NVM using the flash access registers. + **/ +static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, + u8 size, u16 data) +{ + union ich8_hws_flash_status hsfsts; + union ich8_hws_flash_ctrl hsflctl; + u32 flash_linear_addr; + u32 flash_data = 0; + s32 ret_val = -E1000_ERR_NVM; + u8 count = 0; + + DEBUGFUNC("e1000_write_ich8_data"); + + ret_val = e1000e_map_nvram(hw); + if (ret_val) { + DEBUGOUT("ERROR: Flash registers not mapped\n"); + return ret_val; + } + + if (size < 1 || size > 2 || data > size * 0xff || + offset > ICH_FLASH_LINEAR_ADDR_MASK) + goto out; + + flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) + + hw->nvm.flash_base_addr; + + do { + usec_delay(1); + /* Steps */ + ret_val = e1000_flash_cycle_init_ich8lan(hw); + if (ret_val != E1000_SUCCESS) + break; + + hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); + /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ + hsflctl.hsf_ctrl.fldbcount = size -1; + hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE; + E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval); + + E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr); + + if (size == 1) + flash_data = (u32)data & 0x00FF; + else + flash_data = (u32)data; + + E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, flash_data); + + /* + * check if FCERR is set to 1 , if set to 1, clear it + * and try the whole sequence a few more times else done + */ + ret_val = e1000_flash_cycle_ich8lan(hw, + ICH_FLASH_WRITE_COMMAND_TIMEOUT); + if (ret_val == E1000_SUCCESS) { + break; + } else { + /* + * If we're here, then things are most likely + * completely hosed, but if the error condition + * is detected, it won't hurt to give it another + * try...ICH_FLASH_CYCLE_REPEAT_COUNT times. + */ + hsfsts.regval = E1000_READ_FLASH_REG16(hw, + ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcerr == 1) { + /* Repeat for some time before giving up. */ + continue; + } else if (hsfsts.hsf_status.flcdone == 0) { + DEBUGOUT("Timeout error - flash cycle " + "did not complete."); + break; + } + } + } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); + +out: + e1000e_unmap_nvram(hw); + return ret_val; +} + +/** + * e1000_write_flash_byte_ich8lan - Write a single byte to NVM + * @hw: pointer to the HW structure + * @offset: The index of the byte to read. + * @data: The byte to write to the NVM. + * + * Writes a single byte to the NVM using the flash access registers. + **/ +static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, + u8 data) +{ + u16 word = (u16)data; + + DEBUGFUNC("e1000_write_flash_byte_ich8lan"); + + return e1000_write_flash_data_ich8lan(hw, offset, 1, word); +} + +/** + * e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM + * @hw: pointer to the HW structure + * @offset: The offset of the byte to write. + * @byte: The byte to write to the NVM. + * + * Writes a single byte to the NVM using the flash access registers. + * Goes through a retry algorithm before giving up. + **/ +static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, + u32 offset, u8 byte) +{ + s32 ret_val; + u16 program_retries; + + DEBUGFUNC("e1000_retry_write_flash_byte_ich8lan"); + + ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte); + if (ret_val == E1000_SUCCESS) + goto out; + + for (program_retries = 0; program_retries < 100; program_retries++) { + DEBUGOUT2("Retrying Byte %2.2X at offset %u\n", byte, offset); + usec_delay(100); + ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte); + if (ret_val == E1000_SUCCESS) + break; + } + if (program_retries == 100) { + ret_val = -E1000_ERR_NVM; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM + * @hw: pointer to the HW structure + * @bank: 0 for first bank, 1 for second bank, etc. + * + * Erases the bank specified. Each bank is a 4k block. Banks are 0 based. + * bank N is 4096 * N + flash_reg_addr. + **/ +static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + union ich8_hws_flash_status hsfsts; + union ich8_hws_flash_ctrl hsflctl; + u32 flash_linear_addr; + /* bank size is in 16bit words - adjust to bytes */ + u32 flash_bank_size = nvm->flash_bank_size * 2; + s32 ret_val = E1000_SUCCESS; + s32 count = 0; + s32 j, iteration, sector_size; + + DEBUGFUNC("e1000_erase_flash_bank_ich8lan"); + + ret_val = e1000e_map_nvram(hw); + if (ret_val) { + DEBUGOUT("ERROR: Flash registers not mapped\n"); + return ret_val; + } + + hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); + + /* + * Determine HW Sector size: Read BERASE bits of hw flash status + * register + * 00: The Hw sector is 256 bytes, hence we need to erase 16 + * consecutive sectors. The start index for the nth Hw sector + * can be calculated as = bank * 4096 + n * 256 + * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector. + * The start index for the nth Hw sector can be calculated + * as = bank * 4096 + * 10: The Hw sector is 8K bytes, nth sector = bank * 8192 + * (ich9 only, otherwise error condition) + * 11: The Hw sector is 64K bytes, nth sector = bank * 65536 + */ + switch (hsfsts.hsf_status.berasesz) { + case 0: + /* Hw sector size 256 */ + sector_size = ICH_FLASH_SEG_SIZE_256; + iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256; + break; + case 1: + sector_size = ICH_FLASH_SEG_SIZE_4K; + iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_4K; + break; + case 2: + if (hw->mac.type == e1000_ich9lan) { + sector_size = ICH_FLASH_SEG_SIZE_8K; + iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_8K; + } else { + ret_val = -E1000_ERR_NVM; + goto out; + } + break; + case 3: + sector_size = ICH_FLASH_SEG_SIZE_64K; + iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_64K; + break; + default: + ret_val = -E1000_ERR_NVM; + goto out; + } + + /* Start with the base address, then add the sector offset. */ + flash_linear_addr = hw->nvm.flash_base_addr; + flash_linear_addr += (bank) ? (sector_size * iteration) : 0; + + for (j = 0; j < iteration ; j++) { + do { + /* Steps */ + ret_val = e1000_flash_cycle_init_ich8lan(hw); + if (ret_val) + goto out; + + /* + * Write a value 11 (block Erase) in Flash + * Cycle field in hw flash control + */ + hsflctl.regval = E1000_READ_FLASH_REG16(hw, + ICH_FLASH_HSFCTL); + hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE; + E1000_WRITE_FLASH_REG16(hw, + ICH_FLASH_HSFCTL, + hsflctl.regval); + + /* + * Write the last 24 bits of an index within the + * block into Flash Linear address field in Flash + * Address. + */ + flash_linear_addr += (j * sector_size); + E1000_WRITE_FLASH_REG(hw, + ICH_FLASH_FADDR, + flash_linear_addr); + + ret_val = e1000_flash_cycle_ich8lan(hw, + ICH_FLASH_ERASE_COMMAND_TIMEOUT); + if (ret_val == E1000_SUCCESS) { + break; + } else { + /* + * Check if FCERR is set to 1. If 1, + * clear it and try the whole sequence + * a few more times else Done + */ + hsfsts.regval = E1000_READ_FLASH_REG16(hw, + ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcerr == 1) { + /* + * repeat for some time before + * giving up + */ + continue; + } else if (hsfsts.hsf_status.flcdone == 0) + goto out; + } + } while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT); + } + +out: + e1000e_unmap_nvram(hw); + return ret_val; +} + +/** + * e1000_valid_led_default_ich8lan - Set the default LED settings + * @hw: pointer to the HW structure + * @data: Pointer to the LED settings + * + * Reads the LED default settings from the NVM to data. If the NVM LED + * settings is all 0's or F's, set the LED default to a valid LED default + * setting. + **/ +static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data) +{ + s32 ret_val; + + DEBUGFUNC("e1000_valid_led_default_ich8lan"); + + ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + + if (*data == ID_LED_RESERVED_0000 || + *data == ID_LED_RESERVED_FFFF) + *data = ID_LED_DEFAULT_ICH8LAN; + +out: + return ret_val; +} + +/** + * e1000_get_bus_info_ich8lan - Get/Set the bus type and width + * @hw: pointer to the HW structure + * + * ICH8 use the PCI Express bus, but does not contain a PCI Express Capability + * register, so the the bus width is hard coded. + **/ +static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw) +{ + struct e1000_bus_info *bus = &hw->bus; + s32 ret_val; + + DEBUGFUNC("e1000_get_bus_info_ich8lan"); + + ret_val = e1000_get_bus_info_pcie_generic(hw); + + /* + * ICH devices are "PCI Express"-ish. They have + * a configuration space, but do not contain + * PCI Express Capability registers, so bus width + * must be hardcoded. + */ + if (bus->width == e1000_bus_width_unknown) + bus->width = e1000_bus_width_pcie_x1; + + return ret_val; +} + +/** + * e1000_reset_hw_ich8lan - Reset the hardware + * @hw: pointer to the HW structure + * + * Does a full reset of the hardware which includes a reset of the PHY and + * MAC. + **/ +static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) +{ + u32 ctrl, icr, kab; + s32 ret_val; + + DEBUGFUNC("e1000_reset_hw_ich8lan"); + + /* + * Prevent the PCI-E bus from sticking if there is no TLP connection + * on the last TLP read/write transaction when MAC is reset. + */ + ret_val = e1000_disable_pcie_master_generic(hw); + if (ret_val) { + DEBUGOUT("PCI-E Master disable polling has failed.\n"); + } + + DEBUGOUT("Masking off all interrupts\n"); + E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); + + /* + * Disable the Transmit and Receive units. Then delay to allow + * any pending transactions to complete before we hit the MAC + * with the global reset. + */ + E1000_WRITE_REG(hw, E1000_RCTL, 0); + E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP); + E1000_WRITE_FLUSH(hw); + + msec_delay(10); + + /* Workaround for ICH8 bit corruption issue in FIFO memory */ + if (hw->mac.type == e1000_ich8lan) { + /* Set Tx and Rx buffer allocation to 8k apiece. */ + E1000_WRITE_REG(hw, E1000_PBA, E1000_PBA_8K); + /* Set Packet Buffer Size to 16k. */ + E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K); + } + + ctrl = E1000_READ_REG(hw, E1000_CTRL); + + if (!hw->phy.ops.check_reset_block(hw) && !hw->phy.reset_disable) { + /* + * PHY HW reset requires MAC CORE reset at the same + * time to make sure the interface between MAC and the + * external PHY is reset. + */ + ctrl |= E1000_CTRL_PHY_RST; + } + ret_val = e1000_acquire_swflag_ich8lan(hw); + DEBUGOUT("Issuing a global reset to ich8lan"); + E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST)); + msec_delay(20); + + ret_val = e1000_get_auto_rd_done_generic(hw); + if (ret_val) { + /* + * When auto config read does not complete, do not + * return with an error. This can happen in situations + * where there is no eeprom and prevents getting link. + */ + DEBUGOUT("Auto Read Done did not complete\n"); + } + + E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); + icr = E1000_READ_REG(hw, E1000_ICR); + + kab = E1000_READ_REG(hw, E1000_KABGTXD); + kab |= E1000_KABGTXD_BGSQLBIAS; + E1000_WRITE_REG(hw, E1000_KABGTXD, kab); + + return ret_val; +} + +/** + * e1000_init_hw_ich8lan - Initialize the hardware + * @hw: pointer to the HW structure + * + * Prepares the hardware for transmit and receive by doing the following: + * - initialize hardware bits + * - initialize LED identification + * - setup receive address registers + * - setup flow control + * - setup transmit descriptors + * - clear statistics + **/ +static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 ctrl_ext, txdctl, snoop; + s32 ret_val; + u16 i; + + DEBUGFUNC("e1000_init_hw_ich8lan"); + + e1000_initialize_hw_bits_ich8lan(hw); + + /* Initialize identification LED */ + ret_val = e1000_id_led_init_generic(hw); + if (ret_val) { + DEBUGOUT("Error initializing identification LED\n"); + /* This is not fatal and we should not stop init due to this */ + } + + /* Setup the receive address. */ + e1000_init_rx_addrs_generic(hw, mac->rar_entry_count); + + /* Zero out the Multicast HASH table */ + DEBUGOUT("Zeroing the MTA\n"); + for (i = 0; i < mac->mta_reg_count; i++) + E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); + + /* Setup link and flow control */ + ret_val = mac->ops.setup_link(hw); + + /* Set the transmit descriptor write-back policy for both queues */ + txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0)); + txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB; + txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) | + E1000_TXDCTL_MAX_TX_DESC_PREFETCH; + E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl); + txdctl = E1000_READ_REG(hw, E1000_TXDCTL(1)); + txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB; + txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) | + E1000_TXDCTL_MAX_TX_DESC_PREFETCH; + E1000_WRITE_REG(hw, E1000_TXDCTL(1), txdctl); + + /* + * ICH8 has opposite polarity of no_snoop bits. + * By default, we should use snoop behavior. + */ + if (mac->type == e1000_ich8lan) + snoop = PCIE_ICH8_SNOOP_ALL; + else + snoop = (u32)~(PCIE_NO_SNOOP_ALL); + e1000_set_pcie_no_snoop_generic(hw, snoop); + + ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_RO_DIS; + E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); + + /* + * Clear all of the statistics registers (clear on read). It is + * important that we do this after we have tried to establish link + * because the symbol error count will increment wildly if there + * is no link. + */ + e1000_clear_hw_cntrs_ich8lan(hw); + + return ret_val; +} +/** + * e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits + * @hw: pointer to the HW structure + * + * Sets/Clears required hardware bits necessary for correctly setting up the + * hardware for transmit and receive. + **/ +static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw) +{ + u32 reg; + + DEBUGFUNC("e1000_initialize_hw_bits_ich8lan"); + + if (hw->mac.disable_hw_init_bits) + goto out; + + /* Extended Device Control */ + reg = E1000_READ_REG(hw, E1000_CTRL_EXT); + reg |= (1 << 22); + E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg); + + /* Transmit Descriptor Control 0 */ + reg = E1000_READ_REG(hw, E1000_TXDCTL(0)); + reg |= (1 << 22); + E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg); + + /* Transmit Descriptor Control 1 */ + reg = E1000_READ_REG(hw, E1000_TXDCTL(1)); + reg |= (1 << 22); + E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg); + + /* Transmit Arbitration Control 0 */ + reg = E1000_READ_REG(hw, E1000_TARC(0)); + if (hw->mac.type == e1000_ich8lan) + reg |= (1 << 28) | (1 << 29); + reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27); + E1000_WRITE_REG(hw, E1000_TARC(0), reg); + + /* Transmit Arbitration Control 1 */ + reg = E1000_READ_REG(hw, E1000_TARC(1)); + if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR) + reg &= ~(1 << 28); + else + reg |= (1 << 28); + reg |= (1 << 24) | (1 << 26) | (1 << 30); + E1000_WRITE_REG(hw, E1000_TARC(1), reg); + + /* Device Status */ + if (hw->mac.type == e1000_ich8lan) { + reg = E1000_READ_REG(hw, E1000_STATUS); + reg &= ~(1 << 31); + E1000_WRITE_REG(hw, E1000_STATUS, reg); + } + +out: + return; +} + +/** + * e1000_setup_link_ich8lan - Setup flow control and link settings + * @hw: pointer to the HW structure + * + * Determines which flow control settings to use, then configures flow + * control. Calls the appropriate media-specific link configuration + * function. Assuming the adapter has a valid link partner, a valid link + * should be established. Assumes the hardware has previously been reset + * and the transmitter and receiver are not enabled. + **/ +static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_setup_link_ich8lan"); + + if (hw->phy.ops.check_reset_block(hw)) + goto out; + + /* + * ICH parts do not have a word in the NVM to determine + * the default flow control setting, so we explicitly + * set it to full. + */ + if (hw->fc.type == e1000_fc_default) + hw->fc.type = e1000_fc_full; + + hw->fc.original_type = hw->fc.type; + + DEBUGOUT1("After fix-ups FlowControl is now = %x\n", hw->fc.type); + + /* Continue to configure the copper link. */ + ret_val = hw->mac.ops.setup_physical_interface(hw); + if (ret_val) + goto out; + + E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time); + + ret_val = e1000_set_fc_watermarks_generic(hw); + +out: + return ret_val; +} + +/** + * e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface + * @hw: pointer to the HW structure + * + * Configures the kumeran interface to the PHY to wait the appropriate time + * when polling the PHY, then call the generic setup_copper_link to finish + * configuring the copper link. + **/ +static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw) +{ + u32 ctrl; + s32 ret_val; + u16 reg_data; + + DEBUGFUNC("e1000_setup_copper_link_ich8lan"); + + ctrl = E1000_READ_REG(hw, E1000_CTRL); + ctrl |= E1000_CTRL_SLU; + ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + E1000_WRITE_REG(hw, E1000_CTRL, ctrl); + + /* + * Set the mac to wait the maximum time between each iteration + * and increase the max iterations when polling the phy; + * this fixes erroneous timeouts at 10Mbps. + */ + ret_val = e1000_write_kmrn_reg_generic(hw, GG82563_REG(0x34, 4), + 0xFFFF); + if (ret_val) + goto out; + ret_val = e1000_read_kmrn_reg_generic(hw, GG82563_REG(0x34, 9), + ®_data); + if (ret_val) + goto out; + reg_data |= 0x3F; + ret_val = e1000_write_kmrn_reg_generic(hw, GG82563_REG(0x34, 9), + reg_data); + if (ret_val) + goto out; + + if (hw->phy.type == e1000_phy_igp_3) { + ret_val = e1000_copper_link_setup_igp(hw); + if (ret_val) + goto out; + } else if (hw->phy.type == e1000_phy_bm) { + ret_val = e1000_copper_link_setup_m88(hw); + if (ret_val) + goto out; + } + + if (hw->phy.type == e1000_phy_ife) { + ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, + ®_data); + if (ret_val) + goto out; + + reg_data &= ~IFE_PMC_AUTO_MDIX; + + switch (hw->phy.mdix) { + case 1: + reg_data &= ~IFE_PMC_FORCE_MDIX; + break; + case 2: + reg_data |= IFE_PMC_FORCE_MDIX; + break; + case 0: + default: + reg_data |= IFE_PMC_AUTO_MDIX; + break; + } + ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, + reg_data); + if (ret_val) + goto out; + } + ret_val = e1000_setup_copper_link_generic(hw); + +out: + return ret_val; +} + +/** + * e1000_get_link_up_info_ich8lan - Get current link speed and duplex + * @hw: pointer to the HW structure + * @speed: pointer to store current link speed + * @duplex: pointer to store the current link duplex + * + * Calls the generic get_speed_and_duplex to retrieve the current link + * information and then calls the Kumeran lock loss workaround for links at + * gigabit speeds. + **/ +static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed, + u16 *duplex) +{ + s32 ret_val; + + DEBUGFUNC("e1000_get_link_up_info_ich8lan"); + + ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex); + if (ret_val) + goto out; + + if ((hw->mac.type == e1000_ich8lan) && + (hw->phy.type == e1000_phy_igp_3) && + (*speed == SPEED_1000)) { + ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw); + } + +out: + return ret_val; +} + +/** + * e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround + * @hw: pointer to the HW structure + * + * Work-around for 82566 Kumeran PCS lock loss: + * On link status change (i.e. PCI reset, speed change) and link is up and + * speed is gigabit- + * 0) if workaround is optionally disabled do nothing + * 1) wait 1ms for Kumeran link to come up + * 2) check Kumeran Diagnostic register PCS lock loss bit + * 3) if not set the link is locked (all is good), otherwise... + * 4) reset the PHY + * 5) repeat up to 10 times + * Note: this is only called for IGP3 copper when speed is 1gb. + **/ +static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw) +{ + struct e1000_dev_spec_ich8lan *dev_spec; + u32 phy_ctrl; + s32 ret_val = E1000_SUCCESS; + u16 i, data; + bool link; + + DEBUGFUNC("e1000_kmrn_lock_loss_workaround_ich8lan"); + + dev_spec = (struct e1000_dev_spec_ich8lan *)hw->dev_spec; + + if (!dev_spec) { + DEBUGOUT("dev_spec pointer is set to NULL.\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + if (!(dev_spec->kmrn_lock_loss_workaround_enabled)) + goto out; + + /* + * Make sure link is up before proceeding. If not just return. + * Attempting this while link is negotiating fouled up link + * stability + */ + ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); + if (!link) { + ret_val = E1000_SUCCESS; + goto out; + } + + for (i = 0; i < 10; i++) { + /* read once to clear */ + ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data); + if (ret_val) + goto out; + /* and again to get new status */ + ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data); + if (ret_val) + goto out; + + /* check for PCS lock */ + if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) { + ret_val = E1000_SUCCESS; + goto out; + } + + /* Issue PHY reset */ + hw->phy.ops.reset(hw); + msec_delay_irq(5); + } + /* Disable GigE link negotiation */ + phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); + phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE | + E1000_PHY_CTRL_NOND0A_GBE_DISABLE); + E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); + + /* + * Call gig speed drop workaround on Gig disable before accessing + * any PHY registers + */ + e1000_gig_downshift_workaround_ich8lan(hw); + + /* unable to acquire PCS lock */ + ret_val = -E1000_ERR_PHY; + +out: + return ret_val; +} + +/** + * e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state + * @hw: pointer to the HW structure + * @state: boolean value used to set the current Kumeran workaround state + * + * If ICH8, set the current Kumeran workaround state (enabled - true + * /disabled - false). + **/ +void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, + bool state) +{ + struct e1000_dev_spec_ich8lan *dev_spec; + + DEBUGFUNC("e1000_set_kmrn_lock_loss_workaround_ich8lan"); + + if (hw->mac.type != e1000_ich8lan) { + DEBUGOUT("Workaround applies to ICH8 only.\n"); + goto out; + } + + dev_spec = (struct e1000_dev_spec_ich8lan *)hw->dev_spec; + + if (!dev_spec) { + DEBUGOUT("dev_spec pointer is set to NULL.\n"); + goto out; + } + + dev_spec->kmrn_lock_loss_workaround_enabled = state; + +out: + return; +} + +/** + * e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3 + * @hw: pointer to the HW structure + * + * Workaround for 82566 power-down on D3 entry: + * 1) disable gigabit link + * 2) write VR power-down enable + * 3) read it back + * Continue if successful, else issue LCD reset and repeat + **/ +void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw) +{ + u32 reg; + u16 data; + u8 retry = 0; + + DEBUGFUNC("e1000_igp3_phy_powerdown_workaround_ich8lan"); + + if (hw->phy.type != e1000_phy_igp_3) + goto out; + + /* Try the workaround twice (if needed) */ + do { + /* Disable link */ + reg = E1000_READ_REG(hw, E1000_PHY_CTRL); + reg |= (E1000_PHY_CTRL_GBE_DISABLE | + E1000_PHY_CTRL_NOND0A_GBE_DISABLE); + E1000_WRITE_REG(hw, E1000_PHY_CTRL, reg); + + /* + * Call gig speed drop workaround on Gig disable before + * accessing any PHY registers + */ + if (hw->mac.type == e1000_ich8lan) + e1000_gig_downshift_workaround_ich8lan(hw); + + /* Write VR power-down enable */ + hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data); + data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; + hw->phy.ops.write_reg(hw, + IGP3_VR_CTRL, + data | IGP3_VR_CTRL_MODE_SHUTDOWN); + + /* Read it back and test */ + hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data); + data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; + if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry) + break; + + /* Issue PHY reset and repeat at most one more time */ + reg = E1000_READ_REG(hw, E1000_CTRL); + E1000_WRITE_REG(hw, E1000_CTRL, reg | E1000_CTRL_PHY_RST); + retry++; + } while (retry); + +out: + return; +} + +/** + * e1000_gig_downshift_workaround_ich8lan - WoL from S5 stops working + * @hw: pointer to the HW structure + * + * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC), + * LPLU, Gig disable, MDIC PHY reset): + * 1) Set Kumeran Near-end loopback + * 2) Clear Kumeran Near-end loopback + * Should only be called for ICH8[m] devices with IGP_3 Phy. + **/ +void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 reg_data; + + DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan"); + + if ((hw->mac.type != e1000_ich8lan) || + (hw->phy.type != e1000_phy_igp_3)) + goto out; + + ret_val = e1000_read_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, + ®_data); + if (ret_val) + goto out; + reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK; + ret_val = e1000_write_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_DIAG_OFFSET, + reg_data); + if (ret_val) + goto out; + reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK; + ret_val = e1000_write_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_DIAG_OFFSET, + reg_data); +out: + return; +} + +/** + * e1000_disable_gig_wol_ich8lan - disable gig during WoL + * @hw: pointer to the HW structure + * + * During S0 to Sx transition, it is possible the link remains at gig + * instead of negotiating to a lower speed. Before going to Sx, set + * 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation + * to a lower speed. + * + * Should only be called for ICH9 and ICH10 devices. + **/ +void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw) +{ + u32 phy_ctrl; + + if ((hw->mac.type == e1000_ich10lan) || + (hw->mac.type == e1000_ich9lan)) { + phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); + phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | + E1000_PHY_CTRL_GBE_DISABLE; + E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); + } + + return; +} + +/** + * e1000_cleanup_led_ich8lan - Restore the default LED operation + * @hw: pointer to the HW structure + * + * Return the LED back to the default configuration. + **/ +static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_cleanup_led_ich8lan"); + + if (hw->phy.type == e1000_phy_ife) + ret_val = hw->phy.ops.write_reg(hw, + IFE_PHY_SPECIAL_CONTROL_LED, + 0); + else + E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default); + + return ret_val; +} + +/** + * e1000_led_on_ich8lan - Turn LEDs on + * @hw: pointer to the HW structure + * + * Turn on the LEDs. + **/ +static s32 e1000_led_on_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_led_on_ich8lan"); + + if (hw->phy.type == e1000_phy_ife) + ret_val = hw->phy.ops.write_reg(hw, + IFE_PHY_SPECIAL_CONTROL_LED, + (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON)); + else + E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2); + + return ret_val; +} + +/** + * e1000_led_off_ich8lan - Turn LEDs off + * @hw: pointer to the HW structure + * + * Turn off the LEDs. + **/ +static s32 e1000_led_off_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_led_off_ich8lan"); + + if (hw->phy.type == e1000_phy_ife) + ret_val = hw->phy.ops.write_reg(hw, + IFE_PHY_SPECIAL_CONTROL_LED, + (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF)); + else + E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1); + + return ret_val; +} + +/** + * e1000_get_cfg_done_ich8lan - Read config done bit + * @hw: pointer to the HW structure + * + * Read the management control register for the config done bit for + * completion status. NOTE: silicon which is EEPROM-less will fail trying + * to read the config done bit, so an error is *ONLY* logged and returns + * E1000_SUCCESS. If we were to return with error, EEPROM-less silicon + * would not be able to be reset or change link. + **/ +static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u32 bank = 0; + + e1000_get_cfg_done_generic(hw); + + /* If EEPROM is not marked present, init the IGP 3 PHY manually */ + if (hw->mac.type != e1000_ich10lan) { + if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) && + (hw->phy.type == e1000_phy_igp_3)) { + e1000_phy_init_script_igp3(hw); + } + } else { + if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) { + /* Maybe we should do a basic Boazman config */ + DEBUGOUT("EEPROM not present\n"); + ret_val = -E1000_ERR_CONFIG; + } + } + + return ret_val; +} + +/** + * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down + * @hw: pointer to the HW structure + * + * In the case of a PHY power down to save power, or to turn off link during a + * driver unload, or wake on lan is not enabled, remove the link. + **/ +static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + struct e1000_mac_info *mac = &hw->mac; + + /* If the management interface is not enabled, then power down */ + if (!(mac->ops.check_mng_mode(hw) || phy->ops.check_reset_block(hw))) + e1000_power_down_phy_copper(hw); + + return; +} + +/** + * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters + * @hw: pointer to the HW structure + * + * Clears hardware counters specific to the silicon family and calls + * clear_hw_cntrs_generic to clear all general purpose counters. + **/ +static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) +{ + volatile u32 temp; + + DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan"); + + e1000_clear_hw_cntrs_base_generic(hw); + + temp = E1000_READ_REG(hw, E1000_ALGNERRC); + temp = E1000_READ_REG(hw, E1000_RXERRC); + temp = E1000_READ_REG(hw, E1000_TNCRS); + temp = E1000_READ_REG(hw, E1000_CEXTERR); + temp = E1000_READ_REG(hw, E1000_TSCTC); + temp = E1000_READ_REG(hw, E1000_TSCTFC); + + temp = E1000_READ_REG(hw, E1000_MGTPRC); + temp = E1000_READ_REG(hw, E1000_MGTPDC); + temp = E1000_READ_REG(hw, E1000_MGTPTC); + + temp = E1000_READ_REG(hw, E1000_IAC); + temp = E1000_READ_REG(hw, E1000_ICRXOC); +} + --- linux-2.6.27.orig/ubuntu/drbd/drbd_worker.c +++ linux-2.6.27/ubuntu/drbd/drbd_worker.c @@ -0,0 +1,1322 @@ +/* +-*- linux-c -*- + drbd_worker.c + Kernel module for 2.6.x Kernels + + This file is part of DRBD by Philipp Reisner and Lars Ellenberg. + + Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. + Copyright (C) 1999-2008, Philipp Reisner . + Copyright (C) 2002-2008, Lars Ellenberg . + + drbd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + drbd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with drbd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LINUX_SCATTERLIST_H +#include +#endif + +#include +#include "drbd_int.h" +#include "drbd_req.h" + +/* defined here: + drbd_md_io_complete + drbd_endio_write_sec + drbd_endio_read_sec + drbd_endio_pri + + * more endio handlers: + atodb_endio in drbd_actlog.c + drbd_bm_async_io_complete in drbd_bitmap.c + + * For all these callbacks, note the follwing: + * The callbacks will be called in irq context by the IDE drivers, + * and in Softirqs/Tasklets/BH context by the SCSI drivers. + * Try to get the locking right :) + * + */ + +/* used for synchronous meta data and bitmap IO + * submitted by drbd_md_sync_page_io() + */ +BIO_ENDIO_TYPE drbd_md_io_complete BIO_ENDIO_ARGS(struct bio *bio, int error) +{ + struct drbd_md_io *md_io; + + BIO_ENDIO_FN_START; + + /* error parameter ignored: + * drbd_md_sync_page_io explicitly tests bio_uptodate(bio); */ + + md_io = (struct drbd_md_io *)bio->bi_private; + + md_io->error = error; + + dump_internal_bio("Md", md_io->mdev, bio, 1); + + complete(&md_io->event); + + BIO_ENDIO_FN_RETURN; +} + +/* reads on behalf of the partner, + * "submitted" by the receiver + */ +BIO_ENDIO_TYPE drbd_endio_read_sec BIO_ENDIO_ARGS(struct bio *bio, int error) __releases(local) +{ + unsigned long flags = 0; + struct Tl_epoch_entry *e = NULL; + struct drbd_conf *mdev; + int uptodate = bio_flagged(bio, BIO_UPTODATE); + + e = bio->bi_private; + mdev = e->mdev; + + BIO_ENDIO_FN_START; + if (!error && !uptodate) { + /* strange behaviour of some lower level drivers... + * fail the request by clearing the uptodate flag, + * but do not return any error?! + * do we want to DRBD_WARN() on this? */ + error = -EIO; + } + + D_ASSERT(e->block_id != ID_VACANT); + + dump_internal_bio("Sec", mdev, bio, 1); + + spin_lock_irqsave(&mdev->req_lock, flags); + mdev->read_cnt += e->size >> 9; + list_del(&e->w.list); + if (list_empty(&mdev->read_ee)) wake_up(&mdev->ee_wait); + spin_unlock_irqrestore(&mdev->req_lock, flags); + + drbd_chk_io_error(mdev, error, FALSE); + drbd_queue_work(&mdev->data.work, &e->w); + dec_local(mdev); + + MTRACE(TraceTypeEE, TraceLvlAll, + INFO("Moved EE (READ) to worker sec=%llus size=%u ee=%p\n", + (unsigned long long)e->sector, e->size, e); + ); + BIO_ENDIO_FN_RETURN; +} + +/* writes on behalf of the partner, or resync writes, + * "submitted" by the receiver. + */ +BIO_ENDIO_TYPE drbd_endio_write_sec BIO_ENDIO_ARGS(struct bio *bio, int error) __releases(local) +{ + unsigned long flags = 0; + struct Tl_epoch_entry *e = NULL; + struct drbd_conf *mdev; + sector_t e_sector; + int do_wake; + int is_syncer_req; + int do_al_complete_io; + int uptodate = bio_flagged(bio, BIO_UPTODATE); + + e = bio->bi_private; + mdev = e->mdev; + + BIO_ENDIO_FN_START; + if (!error && !uptodate) { + /* strange behaviour of some lower level drivers... + * fail the request by clearing the uptodate flag, + * but do not return any error?! + * do we want to DRBD_WARN() on this? */ + error = -EIO; + } + + D_ASSERT(e->block_id != ID_VACANT); + + dump_internal_bio("Sec", mdev, bio, 1); + + spin_lock_irqsave(&mdev->req_lock, flags); + mdev->writ_cnt += e->size >> 9; + is_syncer_req = is_syncer_block_id(e->block_id); + + /* after we moved e to done_ee, + * we may no longer access it, + * it may be freed/reused already! + * (as soon as we release the req_lock) */ + e_sector = e->sector; + do_al_complete_io = e->flags & EE_CALL_AL_COMPLETE_IO; + + list_del(&e->w.list); /* has been on active_ee or sync_ee */ + list_add_tail(&e->w.list, &mdev->done_ee); + + MTRACE(TraceTypeEE, TraceLvlAll, + INFO("Moved EE (WRITE) to done_ee sec=%llus size=%u ee=%p\n", + (unsigned long long)e->sector, e->size, e); + ); + + /* No hlist_del_init(&e->colision) here, we did not send the Ack yet, + * neither did we wake possibly waiting conflicting requests. + * done from "drbd_process_done_ee" within the appropriate w.cb + * (e_end_block/e_end_resync_block) or from _drbd_clear_done_ee */ + + if (!is_syncer_req) + mdev->epoch_size++; + + do_wake = is_syncer_req + ? list_empty(&mdev->sync_ee) + : list_empty(&mdev->active_ee); + + if (error) + __drbd_chk_io_error(mdev, FALSE); + spin_unlock_irqrestore(&mdev->req_lock, flags); + + if (is_syncer_req) + drbd_rs_complete_io(mdev, e_sector); + + if (do_wake) + wake_up(&mdev->ee_wait); + + if (do_al_complete_io) + drbd_al_complete_io(mdev, e_sector); + + wake_asender(mdev); + dec_local(mdev); + + BIO_ENDIO_FN_RETURN; +} + +/* read, readA or write requests on Primary comming from drbd_make_request + */ +BIO_ENDIO_TYPE drbd_endio_pri BIO_ENDIO_ARGS(struct bio *bio, int error) +{ + unsigned long flags; + struct drbd_request *req = bio->bi_private; + struct drbd_conf *mdev = req->mdev; + enum drbd_req_event what; + int uptodate = bio_flagged(bio, BIO_UPTODATE); + + BIO_ENDIO_FN_START; + if (!error && !uptodate) { + /* strange behaviour of some lower level drivers... + * fail the request by clearing the uptodate flag, + * but do not return any error?! + * do we want to DRBD_WARN() on this? */ + error = -EIO; + } + + dump_internal_bio("Pri", mdev, bio, 1); + + /* to avoid recursion in _req_mod */ + what = error + ? (bio_data_dir(bio) == WRITE) + ? write_completed_with_error + : read_completed_with_error + : completed_ok; + spin_lock_irqsave(&mdev->req_lock, flags); + _req_mod(req, what, error); + spin_unlock_irqrestore(&mdev->req_lock, flags); + + BIO_ENDIO_FN_RETURN; +} + +int w_io_error(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +{ + struct drbd_request *req = (struct drbd_request *)w; + int ok; + + /* FIXME send a "set_out_of_sync" packet to the peer + * in the PassOn case... + * in the Detach (or Panic) case, we (try to) send + * a "we are diskless" param packet anyways, and the peer + * will then set the FullSync bit in the meta data ... + */ + /* NOTE: mdev->bc can be NULL by the time we get here! */ + /* D_ASSERT(mdev->bc->dc.on_io_error != PassOn); */ + + /* the only way this callback is scheduled is from _req_may_be_done, + * when it is done and had a local write error, see comments there */ + drbd_req_free(req); + + ok = drbd_io_error(mdev, FALSE); + if (unlikely(!ok)) ERR("Sending in w_io_error() failed\n"); + return ok; +} + +int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +{ + struct drbd_request *req = (struct drbd_request *)w; + + /* FIXME this is ugly. we should not detach for read io-error, + * but try to WRITE the DataReply to the failed location, + * to give the disk the chance to relocate that block */ + drbd_io_error(mdev,FALSE); /* tries to schedule a detach and notifies peer */ + + spin_lock_irq(&mdev->req_lock); + if ( cancel || + mdev->state.conn < Connected || + mdev->state.pdsk <= Inconsistent ) { + _req_mod(req, send_canceled, 0); /* FIXME freeze? ... */ + spin_unlock_irq(&mdev->req_lock); + drbd_khelper(mdev, "pri-on-incon-degr"); /* FIXME REALLY? */ + ALERT("WE ARE LOST. Local IO failure, no peer.\n"); + return 1; + } + spin_unlock_irq(&mdev->req_lock); + + return w_send_read_req(mdev, w, 0); +} + +int w_resync_inactive(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +{ + ERR_IF(cancel) return 1; + ERR("resync inactive, but callback triggered??\n"); + return 1; /* Simply ignore this! */ +} + +STATIC void drbd_csum(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio *bio, void *digest) +{ + struct hash_desc desc; + struct scatterlist sg; + struct bio_vec *bvec; + int i; + + desc.tfm=tfm; + desc.flags=0; + + sg_init_table(&sg, 1); + crypto_hash_init(&desc); + + __bio_for_each_segment(bvec, bio, i, 0) { + sg_set_page(&sg, bvec->bv_page, bvec->bv_len, bvec->bv_offset); + crypto_hash_update(&desc, &sg, sg.length); + } + crypto_hash_final(&desc, digest); +} + +int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work* w,int cancel); + + +void resync_timer_fn(unsigned long data) +{ + unsigned long flags; + struct drbd_conf *mdev = (struct drbd_conf *) data; + int queue; + + spin_lock_irqsave(&mdev->req_lock, flags); + + if (likely(!test_and_clear_bit(STOP_SYNC_TIMER, &mdev->flags))) { + queue = 1; + if(mdev->state.conn == VerifyS ) { + mdev->resync_work.cb = w_make_ov_request; + } else mdev->resync_work.cb = w_make_resync_request; + } else { + queue = 0; + mdev->resync_work.cb = w_resync_inactive; + } + + spin_unlock_irqrestore(&mdev->req_lock, flags); + + /* harmless race: list_empty outside data.work.q_lock */ + if (list_empty(&mdev->resync_work.list) && queue) + drbd_queue_work(&mdev->data.work, &mdev->resync_work); +} + +#define SLEEP_TIME (HZ/10) + +int w_make_resync_request(struct drbd_conf *mdev, + struct drbd_work *w, int cancel) +{ + unsigned long bit; + sector_t sector; + const sector_t capacity = drbd_get_capacity(mdev->this_bdev); + int max_segment_size = mdev->rq_queue->max_segment_size; + int number, i, size; + int align; + + PARANOIA_BUG_ON(w != &mdev->resync_work); + + if (unlikely(cancel)) return 1; + + if (unlikely(mdev->state.conn < Connected)) { + ERR("Confused in w_make_resync_request()! cstate < Connected"); + return 0; + } + + if (mdev->state.conn != SyncTarget) + ERR("%s in w_make_resync_request\n", + conns_to_name(mdev->state.conn)); + + if (!inc_local(mdev)) { + /* Since we only need to access mdev->rsync a + inc_local_if_state(mdev,Failed) would be sufficient, but + to continue resync with a broken disk makes no sense at + all */ + ERR("Disk broke down during resync!\n"); + mdev->resync_work.cb = w_resync_inactive; + return 1; + } + /* All goto requeses have to happend after this block: inc_local() */ + + number = SLEEP_TIME*mdev->sync_conf.rate / ((BM_BLOCK_SIZE/1024)*HZ); + + if (atomic_read(&mdev->rs_pending_cnt) > number) + goto requeue; + number -= atomic_read(&mdev->rs_pending_cnt); + + for (i = 0; i < number; i++) { +next_sector: + size = BM_BLOCK_SIZE; + /* as of now, we are the only user of drbd_bm_find_next */ + bit = drbd_bm_find_next(mdev); + + if (bit == -1UL) { + /* FIXME either test_and_set some bit, + * or make this the _only_ place that is allowed + * to assign w_resync_inactive! */ + mdev->resync_work.cb = w_resync_inactive; + dec_local(mdev); + return 1; + } + + sector = BM_BIT_TO_SECT(bit); + + if (drbd_try_rs_begin_io(mdev, sector)) { + drbd_bm_set_find(mdev, bit); + goto requeue; + } + + if (unlikely(drbd_bm_test_bit(mdev, bit) == 0 )) { + drbd_rs_complete_io(mdev, sector); + goto next_sector; + } + +#if DRBD_MAX_SEGMENT_SIZE > BM_BLOCK_SIZE + /* try to find some adjacent bits. + * we stop if we have already the maximum req size. + * + * Aditionally always align bigger requests, in order to + * be prepared for all stripe sizes of software RAIDs. + * + * we _do_ care about the agreed-uppon q->max_segment_size + * here, as splitting up the requests on the other side is more + * difficult. the consequence is, that on lvm and md and other + * "indirect" devices, this is dead code, since + * q->max_segment_size will be PAGE_SIZE. + */ + align = 1; + for (;;) { + if (size + BM_BLOCK_SIZE > max_segment_size) + break; + + /* Be always aligned */ + if (sector & ((1<<(align+3))-1) ) + break; + + /* do not cross extent boundaries */ + if (( (bit+1) & BM_BLOCKS_PER_BM_EXT_MASK ) == 0) + break; + /* now, is it actually dirty, after all? + * caution, drbd_bm_test_bit is tri-state for some + * obscure reason; ( b == 0 ) would get the out-of-band + * only accidentally right because of the "oddly sized" + * adjustment below */ + if ( drbd_bm_test_bit(mdev, bit+1) != 1 ) + break; + bit++; + size += BM_BLOCK_SIZE; + if ( (BM_BLOCK_SIZE< BM_BLOCK_SIZE) + drbd_bm_set_find(mdev, bit+1); +#endif + + /* adjust very last sectors, in case we are oddly sized */ + if (sector + (size>>9) > capacity) + size = (capacity-sector)<<9; + inc_rs_pending(mdev); + if (!drbd_send_drequest(mdev, RSDataRequest, + sector, size, ID_SYNCER)) { + ERR("drbd_send_drequest() failed, aborting...\n"); + dec_rs_pending(mdev); + dec_local(mdev); + return 0; + } + } + + if (drbd_bm_rs_done(mdev)) { + /* last syncer _request_ was sent, + * but the RSDataReply not yet received. sync will end (and + * next sync group will resume), as soon as we receive the last + * resync data block, and the last bit is cleared. + * until then resync "work" is "inactive" ... + */ + mdev->resync_work.cb = w_resync_inactive; + dec_local(mdev); + return 1; + } + + requeue: + mod_timer(&mdev->resync_timer, jiffies + SLEEP_TIME); + dec_local(mdev); + return 1; +} + +int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work* w,int cancel) +{ + int number,i,size; + sector_t sector; + const sector_t capacity = drbd_get_capacity(mdev->this_bdev); + + if(unlikely(cancel)) return 1; + + if (unlikely(mdev->state.conn < Connected)) { + ERR("Confused in w_make_ov_request()! cstate < Connected"); + return 0; + } + + number = SLEEP_TIME*mdev->sync_conf.rate / ((BM_BLOCK_SIZE/1024)*HZ); + if (atomic_read(&mdev->rs_pending_cnt)>number) { + goto requeue; + } + number -= atomic_read(&mdev->rs_pending_cnt); + + sector = mdev->ov_position; + for(i=0;iov_position = sector; + goto requeue; + } + + if (sector + (size>>9) > capacity) size = (capacity-sector)<<9; + + inc_rs_pending(mdev); + if(!drbd_send_ov_request(mdev, sector, size)) { + dec_rs_pending(mdev); + return 0; + } + sector += BM_SECT_PER_BIT; + if(sector >= capacity) { + mdev->resync_work.cb = w_resync_inactive; + + return 1; + } + } + mdev->ov_position = sector; + + requeue: + mod_timer(&mdev->resync_timer, jiffies + SLEEP_TIME); + return 1; +} + + +int w_ov_finished(struct drbd_conf *mdev, struct drbd_work* w,int cancel) +{ + kfree(w); + ov_oos_print(mdev); + drbd_resync_finished(mdev); + + return 1; +} + +STATIC int w_resync_finished(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +{ + kfree(w); + + drbd_resync_finished(mdev); + + return 1; +} + +int drbd_resync_finished(struct drbd_conf *mdev) +{ + unsigned long db,dt,dbdt; + union drbd_state_t os, ns; + struct drbd_work *w; + int art = 0; + + /* Remove all elements from the resync LRU. Since future actions + * might set bits in the (main) bitmap, then the entries in the + * resync LRU would be wrong. */ + if (drbd_rs_del_all(mdev)) { + /* In case this is not possible now, most probabely because + * there are RSDataReply Packets lingering on the worker's + * queue (or even the read operations for those packets + * is not finished by now). Retry in 100ms. */ + + drbd_kick_lo(mdev); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 10); + w = kmalloc(sizeof(struct drbd_work), GFP_ATOMIC); + if (w) { + w->cb = w_resync_finished; + drbd_queue_work(&mdev->data.work, w); + return 1; + } + ERR("Warn failed to drbd_rs_del_all() and to kmalloc(w).\n"); + } + + dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ; + if (dt <= 0) + dt = 1; + db = mdev->rs_total; + dbdt = Bit2KB(db/dt); + mdev->rs_paused /= HZ; + + if (!inc_local(mdev)) + goto out; + + spin_lock_irq(&mdev->req_lock); + os = mdev->state; + + /* This protects us against multiple calls (that can happen in the presence + of application IO), and against connectivity loss just before we arrive here. */ + if (os.conn <= Connected) + goto out_unlock; + + ns = os; + ns.conn = Connected; + + INFO("%s done (total %lu sec; paused %lu sec; %lu K/sec)\n", + (os.conn == VerifyS || os.conn == VerifyT) ? + "Online verify ": "Resync", + dt + mdev->rs_paused, mdev->rs_paused, dbdt); + + if (os.conn == VerifyS || os.conn == VerifyT) { + if (drbd_bm_total_weight(mdev)) { + ALERT("Online verify found %lu %dk block out of sync!\n", + drbd_bm_total_weight(mdev),BM_BLOCK_SIZE/1024); + drbd_khelper(mdev,"out-of-sync"); + } + } else { + D_ASSERT((drbd_bm_total_weight(mdev)-mdev->rs_failed) == 0); + } + + if (mdev->rs_failed) { + INFO(" %lu failed blocks\n", mdev->rs_failed); + + if (os.conn == SyncTarget || os.conn == PausedSyncT) { + ns.disk = Inconsistent; + ns.pdsk = UpToDate; + } else { + ns.disk = UpToDate; + ns.pdsk = Inconsistent; + } + } else { + ns.disk = UpToDate; + ns.pdsk = UpToDate; + + if (os.conn == SyncTarget || os.conn == PausedSyncT) { + if (mdev->p_uuid) { + int i; + for (i = Bitmap ; i <= History_end ; i++) + _drbd_uuid_set(mdev, i, mdev->p_uuid[i]); + drbd_uuid_set(mdev, Bitmap, mdev->bc->md.uuid[Current]); + _drbd_uuid_set(mdev, Current, mdev->p_uuid[Current]); + } else { + ERR("mdev->p_uuid is NULL! BUG\n"); + } + } + + drbd_uuid_set_bm(mdev, 0UL); + + if (mdev->p_uuid) { + /* Now the two UUID sets are equal, update what we + * know of the peer. */ + int i; + for (i = Current ; i <= History_end ; i++) + mdev->p_uuid[i] = mdev->bc->md.uuid[i]; + } + } + + art = os.conn == SyncTarget || os.conn == PausedSyncT; + + _drbd_set_state(mdev, ns, ChgStateVerbose, NULL); + out_unlock: + spin_unlock_irq(&mdev->req_lock); + dec_local(mdev); + out: + mdev->rs_total = 0; + mdev->rs_failed = 0; + mdev->rs_paused = 0; + + if (test_and_clear_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags)) { + DRBD_WARN("Writing the whole bitmap, due to failed kmalloc\n"); + drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL); + } + + drbd_bm_recount_bits(mdev); + + if (art) + drbd_khelper(mdev, "after-resync-target"); + + return 1; +} + +/** + * w_e_end_data_req: Send the answer (DataReply) in response to a DataRequest. + */ +int w_e_end_data_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +{ + struct Tl_epoch_entry *e = (struct Tl_epoch_entry *)w; + int ok; + + if (unlikely(cancel)) { + drbd_free_ee(mdev, e); + dec_unacked(mdev); + return 1; + } + + if (likely(drbd_bio_uptodate(e->private_bio))) { + ok = drbd_send_block(mdev, DataReply, e); + } else { + if (DRBD_ratelimit(5*HZ, 5)) + ERR("Sending NegDReply. sector=%llus.\n", + (unsigned long long)e->sector); + + ok = drbd_send_ack(mdev, NegDReply, e); + + /* FIXME we should not detach for read io-errors, in particular + * not now: when the peer asked us for our data, we are likely + * the only remaining disk... */ + drbd_io_error(mdev, FALSE); + } + + dec_unacked(mdev); + + spin_lock_irq(&mdev->req_lock); + if (drbd_bio_has_active_page(e->private_bio)) { + /* This might happen if sendpage() has not finished */ + list_add_tail(&e->w.list, &mdev->net_ee); + } else { + drbd_free_ee(mdev, e); + } + spin_unlock_irq(&mdev->req_lock); + + if (unlikely(!ok)) ERR("drbd_send_block() failed\n"); + return ok; +} + +/** + * w_e_end_rsdata_req: Send the answer (RSDataReply) to a RSDataRequest. + */ +int w_e_end_rsdata_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +{ + struct Tl_epoch_entry *e = (struct Tl_epoch_entry *)w; + int ok; + + if (unlikely(cancel)) { + drbd_free_ee(mdev, e); + dec_unacked(mdev); + return 1; + } + + if (inc_local_if_state(mdev, Failed)) { + drbd_rs_complete_io(mdev, e->sector); + dec_local(mdev); + } + + if (likely(drbd_bio_uptodate(e->private_bio))) { + if (likely( mdev->state.pdsk >= Inconsistent )) { + inc_rs_pending(mdev); + ok = drbd_send_block(mdev, RSDataReply, e); + } else { + if (DRBD_ratelimit(5*HZ, 5)) + ERR("Not sending RSDataReply, " + "partner DISKLESS!\n"); + ok = 1; + } + } else { + if (DRBD_ratelimit(5*HZ, 5)) + ERR("Sending NegRSDReply. sector %llus.\n", + (unsigned long long)e->sector); + + ok = drbd_send_ack(mdev, NegRSDReply, e); + + drbd_io_error(mdev, FALSE); + + /* update resync data with failure */ + drbd_rs_failed_io(mdev, e->sector, e->size); + } + + dec_unacked(mdev); + + spin_lock_irq(&mdev->req_lock); + if (drbd_bio_has_active_page(e->private_bio)) { + /* This might happen if sendpage() has not finished */ + list_add_tail(&e->w.list, &mdev->net_ee); + } else { + drbd_free_ee(mdev, e); + } + spin_unlock_irq(&mdev->req_lock); + + if (unlikely(!ok)) ERR("drbd_send_block() failed\n"); + return ok; +} + + +int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +{ + struct Tl_epoch_entry *e = (struct Tl_epoch_entry*)w; + int digest_size; + void *digest; + int ok=1; + + if(unlikely(cancel)) { + drbd_free_ee(mdev,e); + dec_unacked(mdev); + return 1; + } + + if(likely(drbd_bio_uptodate(e->private_bio))) { + digest_size = crypto_hash_digestsize(mdev->verify_tfm); + digest = kmalloc(digest_size,GFP_KERNEL); + if(digest) { + drbd_csum(mdev,mdev->verify_tfm,e->private_bio,digest); + ok = drbd_send_drequest_csum(mdev, e->sector, e->size, + digest, digest_size, OVReply); + if (ok) inc_rs_pending(mdev); + kfree(digest); + } + } + + dec_unacked(mdev); + + spin_lock_irq(&mdev->req_lock); + drbd_free_ee(mdev,e); + spin_unlock_irq(&mdev->req_lock); + + return ok; +} + +void drbd_ov_oos_found(struct drbd_conf *mdev, sector_t sector, int size) +{ + if (mdev->ov_last_oos_start + mdev->ov_last_oos_size == sector) { + mdev->ov_last_oos_size += size>>9; + } else { + mdev->ov_last_oos_start = sector; + mdev->ov_last_oos_size = size>>9; + } + drbd_set_out_of_sync(mdev, sector, size); + set_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags); +} + +int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +{ + struct Tl_epoch_entry *e = (struct Tl_epoch_entry*)w; + struct digest_info *di; + int digest_size; + void *digest; + int ok,eq=0; + + if(unlikely(cancel)) { + drbd_free_ee(mdev,e); + dec_unacked(mdev); + return 1; + } + + /* after "cancel", because after drbd_disconnect/drbd_rs_cancel_all + * the resync lru has been cleaned up already */ + drbd_rs_complete_io(mdev,e->sector); + + di = (struct digest_info *)(unsigned long)e->block_id; + + if(likely(drbd_bio_uptodate(e->private_bio))) { + digest_size = crypto_hash_digestsize(mdev->verify_tfm); + digest = kmalloc(digest_size,GFP_KERNEL); + if(digest) { + drbd_csum(mdev, mdev->verify_tfm, e->private_bio, digest); + + D_ASSERT(digest_size == di->digest_size); + eq = !memcmp(digest, di->digest, digest_size); + kfree(digest); + } + } else { + ok=drbd_send_ack(mdev,NegRSDReply,e); + if (DRBD_ratelimit(5*HZ,5)) + ERR("Sending NegDReply. I guess it gets messy.\n"); + drbd_io_error(mdev, FALSE); + } + + dec_unacked(mdev); + + kfree(di); + + if (!eq) drbd_ov_oos_found(mdev,e->sector,e->size); + else ov_oos_print(mdev); + + ok = drbd_send_ack_ex(mdev,OVResult,e->sector,e->size, + eq ? ID_IN_SYNC : ID_OUT_OF_SYNC); + + spin_lock_irq(&mdev->req_lock); + drbd_free_ee(mdev,e); + spin_unlock_irq(&mdev->req_lock); + + if( --mdev->ov_left == 0 ) { + ov_oos_print(mdev); + drbd_resync_finished(mdev); + } + + return ok; +} + + +int w_prev_work_done(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +{ + clear_bit(WORK_PENDING, &mdev->flags); + wake_up(&mdev->misc_wait); + return 1; +} + +int w_send_barrier(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +{ + struct drbd_barrier *b = (struct drbd_barrier *)w; + struct Drbd_Barrier_Packet *p = &mdev->data.sbuf.Barrier; + int ok = 1; + + /* really avoid racing with tl_clear. w.cb may have been referenced + * just before it was reassigned and requeued, so double check that. + * actually, this race was harmless, since we only try to send the + * barrier packet here, and otherwise do nothing with the object. + * but compare with the head of w_clear_epoch */ + spin_lock_irq(&mdev->req_lock); + if (w->cb != w_send_barrier || mdev->state.conn < Connected) + cancel = 1; + spin_unlock_irq(&mdev->req_lock); + if (cancel) + return 1; + + if (!drbd_get_data_sock(mdev)) + return 0; + p->barrier = b->br_number; + /* inc_ap_pending was done where this was queued. + * dec_ap_pending will be done in got_BarrierAck + * or (on connection loss) in w_clear_epoch. */ + ok = _drbd_send_cmd(mdev, mdev->data.socket, Barrier, + (struct Drbd_Header *)p, sizeof(*p), 0); + drbd_put_data_sock(mdev); + + return ok; +} + +int w_send_write_hint(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +{ + if (cancel) + return 1; + return drbd_send_short_cmd(mdev, UnplugRemote); +} + +/** + * w_send_dblock: Send a mirrored write request. + */ +int w_send_dblock(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +{ + struct drbd_request *req = (struct drbd_request *)w; + int ok; + + if (unlikely(cancel)) { + req_mod(req, send_canceled, 0); + return 1; + } + + ok = drbd_send_dblock(mdev, req); + req_mod(req, ok ? handed_over_to_network : send_failed, 0); + + return ok; +} + +/** + * w_send_read_req: Send a read requests. + */ +int w_send_read_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +{ + struct drbd_request *req = (struct drbd_request *)w; + int ok; + + if (unlikely(cancel)) { + req_mod(req, send_canceled, 0); + return 1; + } + + ok = drbd_send_drequest(mdev, DataRequest, req->sector, req->size, + (unsigned long)req); + + if (ok) { + req_mod(req, handed_over_to_network, 0); + } else { + /* ?? we set Timeout or BrokenPipe in drbd_send() */ + if (mdev->state.conn >= Connected) + drbd_force_state(mdev, NS(conn, NetworkFailure)); + /* req_mod(req, send_failed); we should not fail it here, + * we might have to "freeze" on disconnect. + * handled by req_mod(req, connection_lost_while_pending); + * in drbd_fail_pending_reads soon enough. */ + } + + return ok; +} + +STATIC void drbd_global_lock(void) __acquires(drbd_global_lock) +{ + struct drbd_conf *mdev; + int i; + + __acquire(drbd_global_lock); + local_irq_disable(); + for (i = 0; i < minor_count; i++) { + mdev = minor_to_mdev(i); + if (!mdev) + continue; + spin_lock(&mdev->req_lock); + __release(&mdev->req_lock); /* annihilate the spin_lock's annotation here */ + } +} + +STATIC void drbd_global_unlock(void) __releases(drbd_global_lock) +{ + struct drbd_conf *mdev; + int i; + + for (i = 0; i < minor_count; i++) { + mdev = minor_to_mdev(i); + if (!mdev) + continue; + __acquire(&mdev->req_lock); + spin_unlock(&mdev->req_lock); + } + local_irq_enable(); + __release(drbd_global_lock); +} + +STATIC int _drbd_may_sync_now(struct drbd_conf *mdev) +{ + struct drbd_conf *odev = mdev; + + while (1) { + if (odev->sync_conf.after == -1) + return 1; + odev = minor_to_mdev(odev->sync_conf.after); + ERR_IF(!odev) return 1; + if ( (odev->state.conn >= SyncSource && + odev->state.conn <= PausedSyncT) || + odev->state.aftr_isp || odev->state.peer_isp || + odev->state.user_isp ) return 0; + } +} + +/** + * _drbd_pause_after: + * Finds all devices that may not resync now, and causes them to + * pause their resynchronisation. + * Called from process context only ( ioctl and after_state_ch ). + */ +STATIC int _drbd_pause_after(struct drbd_conf *mdev) +{ + struct drbd_conf *odev; + int i, rv = 0; + + for (i = 0; i < minor_count; i++) { + odev = minor_to_mdev(i); + if (!odev) + continue; + if (odev->state.conn == StandAlone && odev->state.disk == Diskless) + continue; + if (!_drbd_may_sync_now(odev)) + rv |= ( _drbd_set_state(_NS(odev, aftr_isp, 1), ChgStateHard, NULL) + != SS_NothingToDo ) ; + } + + return rv; +} + +/** + * _drbd_resume_next: + * Finds all devices that can resume resynchronisation + * process, and causes them to resume. + * Called from process context only ( ioctl and worker ). + */ +STATIC int _drbd_resume_next(struct drbd_conf *mdev) +{ + struct drbd_conf *odev; + int i, rv = 0; + + for (i = 0; i < minor_count; i++) { + odev = minor_to_mdev(i); + if (!odev) + continue; + if (odev->state.aftr_isp) { + if (_drbd_may_sync_now(odev)) + rv |= (_drbd_set_state(_NS(odev, aftr_isp, 0), + ChgStateHard, NULL) + != SS_NothingToDo) ; + } + } + return rv; +} + +void resume_next_sg(struct drbd_conf *mdev) +{ + drbd_global_lock(); + _drbd_resume_next(mdev); + drbd_global_unlock(); +} + +void suspend_other_sg(struct drbd_conf *mdev) +{ + drbd_global_lock(); + _drbd_pause_after(mdev); + drbd_global_unlock(); +} + +void drbd_alter_sa(struct drbd_conf *mdev, int na) +{ + int changes; + + drbd_global_lock(); + mdev->sync_conf.after = na; + + do { + changes = _drbd_pause_after(mdev); + changes |= _drbd_resume_next(mdev); + } while (changes); + + drbd_global_unlock(); +} + +/** + * drbd_start_resync: + * @side: Either SyncSource or SyncTarget + * Start the resync process. Called from process context only, + * either ioctl or drbd_receiver. + * Note, this function might bring you directly into one of the + * PausedSync* states. + */ +void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) +{ + union drbd_state_t ns; + int r; + + MTRACE(TraceTypeResync, TraceLvlSummary, + INFO("Resync starting: side=%s\n", + side == SyncTarget?"SyncTarget":"SyncSource"); + ); + + drbd_bm_recount_bits(mdev); + + /* In case a previous resync run was aborted by an IO error... */ + drbd_rs_cancel_all(mdev); + + if (side == SyncTarget) { + /* Since application IO was locked out during WFBitMapT and + WFSyncUUID we are still unmodified. Before going to SyncTarget + we check that we might make the data inconsistent. */ + r = drbd_khelper(mdev, "before-resync-target"); + r = (r >> 8) & 0xff; + if (r > 0) { + INFO("before-resync-target handler returned %d, " + "dropping connection.\n", r); + drbd_force_state(mdev, NS(conn, Disconnecting)); + return; + } + } + + drbd_state_lock(mdev); + + if (!inc_local_if_state(mdev, Negotiating)) { + drbd_state_unlock(mdev); + return; + } + + if (side == SyncTarget) { + drbd_bm_reset_find(mdev); + } else /* side == SyncSource */ { + u64 uuid; + + get_random_bytes(&uuid, sizeof(u64)); + drbd_uuid_set(mdev, Bitmap, uuid); + drbd_send_sync_uuid(mdev, uuid); + + D_ASSERT(mdev->state.disk == UpToDate); + } + + drbd_global_lock(); + ns = mdev->state; + + ns.aftr_isp = !_drbd_may_sync_now(mdev); + + ns.conn = side; + + if (side == SyncTarget) + ns.disk = Inconsistent; + else /* side == SyncSource */ + ns.pdsk = Inconsistent; + + r = _drbd_set_state(mdev, ns, ChgStateVerbose, NULL); + ns = mdev->state; + + if (ns.conn < Connected) + r = SS_UnknownError; + + if (r == SS_Success) { + mdev->rs_total = + mdev->rs_mark_left = drbd_bm_total_weight(mdev); + mdev->rs_failed = 0; + mdev->rs_paused = 0; + mdev->rs_start = + mdev->rs_mark_time = jiffies; + _drbd_pause_after(mdev); + } + drbd_global_unlock(); + drbd_state_unlock(mdev); + dec_local(mdev); + + if (r == SS_Success) { + INFO("Began resync as %s (will sync %lu KB [%lu bits set]).\n", + conns_to_name(ns.conn), + (unsigned long) mdev->rs_total << (BM_BLOCK_SIZE_B-10), + (unsigned long) mdev->rs_total); + + if (mdev->rs_total == 0) { + drbd_resync_finished(mdev); + return; + } + + if (ns.conn == SyncTarget) { + D_ASSERT(!test_bit(STOP_SYNC_TIMER, &mdev->flags)); + mod_timer(&mdev->resync_timer, jiffies); + } + + drbd_md_sync(mdev); + } +} + +int drbd_worker(struct Drbd_thread *thi) +{ + struct drbd_conf *mdev = thi->mdev; + struct drbd_work *w = NULL; + LIST_HEAD(work_list); + int intr = 0, i; + + sprintf(current->comm, "drbd%d_worker", mdev_to_minor(mdev)); + set_cpus_allowed(current, drbd_calc_cpu_mask(mdev)); + + while (get_t_state(thi) == Running) { + + if (down_trylock(&mdev->data.work.s)) { + down(&mdev->data.mutex); + if (mdev->data.socket) + drbd_tcp_flush(mdev->data.socket); + up(&mdev->data.mutex); + + intr = down_interruptible(&mdev->data.work.s); + + down(&mdev->data.mutex); + if (mdev->data.socket) + drbd_tcp_cork(mdev->data.socket); + up(&mdev->data.mutex); + } + + if (intr) { + D_ASSERT(intr == -EINTR); + flush_signals(current); + ERR_IF (get_t_state(thi) == Running) + continue; + break; + } + + if (get_t_state(thi) != Running) break; + /* With this break, we have done a down() but not consumed + the entry from the list. The cleanup code takes care of + this... */ + + w = NULL; + spin_lock_irq(&mdev->data.work.q_lock); + ERR_IF(list_empty(&mdev->data.work.q)) { + /* something terribly wrong in our logic. + * we were able to down() the semaphore, + * but the list is empty... doh. + * + * what is the best thing to do now? + * try again from scratch, restarting the receiver, + * asender, whatnot? could break even more ugly, + * e.g. when we are primary, but no good local data. + * + * I'll try to get away just starting over this loop. + */ + spin_unlock_irq(&mdev->data.work.q_lock); + continue; + } + w = list_entry(mdev->data.work.q.next, struct drbd_work, list); + list_del_init(&w->list); + spin_unlock_irq(&mdev->data.work.q_lock); + + if (!w->cb(mdev, w, mdev->state.conn < Connected )) { + /* DRBD_WARN("worker: a callback failed! \n"); */ + if (mdev->state.conn >= Connected) + drbd_force_state(mdev, + NS(conn, NetworkFailure)); + } + } + + spin_lock_irq(&mdev->data.work.q_lock); + i = 0; + while (!list_empty(&mdev->data.work.q)) { + list_splice_init(&mdev->data.work.q, &work_list); + spin_unlock_irq(&mdev->data.work.q_lock); + + while (!list_empty(&work_list)) { + w = list_entry(work_list.next, struct drbd_work, list); + list_del_init(&w->list); + w->cb(mdev, w, 1); + i++; /* dead debugging code */ + } + + spin_lock_irq(&mdev->data.work.q_lock); + } + sema_init(&mdev->data.work.s, 0); + /* DANGEROUS race: if someone did queue his work within the spinlock, + * but up() ed outside the spinlock, we could get an up() on the + * semaphore without corresponding list entry. + * So don't do that. + */ + spin_unlock_irq(&mdev->data.work.q_lock); + /* FIXME verify that there absolutely can not be any more work + * on the queue now... + * if so, the comment above is no longer true, but historic + * from the times when the worker did not live as long as the + * device.. */ + + D_ASSERT(mdev->state.disk == Diskless && mdev->state.conn == StandAlone); + drbd_mdev_cleanup(mdev); + + INFO("worker terminated\n"); + + return 0; +} --- linux-2.6.27.orig/ubuntu/drbd/drbd_buildtag.c +++ linux-2.6.27/ubuntu/drbd/drbd_buildtag.c @@ -0,0 +1,7 @@ +/* automatically generated. DO NOT EDIT. */ +#include +const char * drbd_buildtag(void) +{ + return "GIT-hash: 3e69822d3bb4920a8c1bfdf7d647169eba7d2eb4" + " build by phil@fat-tyre, 2008-05-30 12:59:17"; +} --- linux-2.6.27.orig/ubuntu/drbd/drbd_nl.c +++ linux-2.6.27/ubuntu/drbd/drbd_nl.c @@ -0,0 +1,2197 @@ +/* +-*- linux-c -*- + drbd_nl.c + Kernel module for 2.6.x Kernels + + This file is part of DRBD by Philipp Reisner and Lars Ellenberg. + + Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. + Copyright (C) 1999-2008, Philipp Reisner . + Copyright (C) 2002-2008, Lars Ellenberg . + + drbd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + drbd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with drbd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#include +#include +#include +#include +#include /* for fsync_bdev */ +#include +#include +#include +#include +#include +#include + +#include "drbd_int.h" +#include +#include + +/* see get_sb_bdev and bd_claim */ +static char *drbd_m_holder = "Hands off! this is DRBD's meta data device."; + +/* Generate the tag_list to struct functions */ +#define NL_PACKET(name, number, fields) \ +STATIC int name ## _from_tags (struct drbd_conf *mdev, \ + unsigned short *tags, struct name *arg) \ +{ \ + int tag; \ + int dlen; \ + \ + while ( (tag = *tags++) != TT_END ) { \ + dlen = *tags++; \ + switch ( tag_number(tag) ) { \ + fields \ + default: \ + if (tag & T_MANDATORY) { \ + ERR("Unknown tag: %d\n", tag_number(tag)); \ + return 0; \ + } \ + } \ + tags = (unsigned short *)((char *)tags + dlen); \ + } \ + return 1; \ +} +#define NL_INTEGER(pn, pr, member) \ + case pn: /* D_ASSERT( tag_type(tag) == TT_INTEGER ); */ \ + arg->member = *(int *)(tags); \ + break; +#define NL_INT64(pn, pr, member) \ + case pn: /* D_ASSERT( tag_type(tag) == TT_INT64 ); */ \ + arg->member = *(u64 *)(tags); \ + break; +#define NL_BIT(pn, pr, member) \ + case pn: /* D_ASSERT( tag_type(tag) == TT_BIT ); */ \ + arg->member = *(char *)(tags) ? 1 : 0; \ + break; +#define NL_STRING(pn, pr, member, len) \ + case pn: /* D_ASSERT( tag_type(tag) == TT_STRING ); */ \ + arg->member ## _len = dlen; \ + memcpy(arg->member, tags, min_t(size_t, dlen, len)); \ + break; +#include "linux/drbd_nl.h" + +// Generate the struct to tag_list functions +#define NL_PACKET(name, number, fields) \ +STATIC unsigned short* \ +name ## _to_tags (struct drbd_conf *mdev, \ + struct name *arg, unsigned short *tags) \ +{ \ + fields \ + return tags; \ +} + +#define NL_INTEGER(pn, pr, member) \ + *tags++ = pn | pr | TT_INTEGER; \ + *tags++ = sizeof(int); \ + *(int *)tags = arg->member; \ + tags = (unsigned short *)((char *)tags+sizeof(int)); +#define NL_INT64(pn, pr, member) \ + *tags++ = pn | pr | TT_INT64; \ + *tags++ = sizeof(u64); \ + *(u64 *)tags = arg->member; \ + tags = (unsigned short *)((char *)tags+sizeof(u64)); +#define NL_BIT(pn, pr, member) \ + *tags++ = pn | pr | TT_BIT; \ + *tags++ = sizeof(char); \ + *(char *)tags = arg->member; \ + tags = (unsigned short *)((char *)tags+sizeof(char)); +#define NL_STRING(pn, pr, member, len) \ + *tags++ = pn | pr | TT_STRING; \ + *tags++ = arg->member ## _len; \ + memcpy(tags, arg->member, arg->member ## _len); \ + tags = (unsigned short *)((char *)tags + arg->member ## _len); +#include "linux/drbd_nl.h" + +void drbd_bcast_ev_helper(struct drbd_conf *mdev, char *helper_name); +void drbd_nl_send_reply(struct cn_msg *, int); + +STATIC char *nl_packet_name(int packet_type) +{ +/* Generate packet type strings */ +#define NL_PACKET(name, number, fields) \ + [ P_ ## name ] = # name, +#define NL_INTEGER Argh! +#define NL_BIT Argh! +#define NL_INT64 Argh! +#define NL_STRING Argh! + + static char *nl_tag_name[P_nl_after_last_packet] = { +#include "linux/drbd_nl.h" + }; + + return (packet_type < sizeof(nl_tag_name)/sizeof(nl_tag_name[0])) ? + nl_tag_name[packet_type] : "*Unknown*"; +} + +STATIC void nl_trace_packet(void *data) +{ + struct cn_msg *req = data; + struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req *)req->data; + + printk(KERN_INFO "drbd%d: " + "Netlink: << %s (%d) - seq: %x, ack: %x, len: %x\n", + nlp->drbd_minor, + nl_packet_name(nlp->packet_type), + nlp->packet_type, + req->seq, req->ack, req->len); +} + +STATIC void nl_trace_reply(void *data) +{ + struct cn_msg *req = data; + struct drbd_nl_cfg_reply *nlp = (struct drbd_nl_cfg_reply *)req->data; + + printk(KERN_INFO "drbd%d: " + "Netlink: >> %s (%d) - seq: %x, ack: %x, len: %x\n", + nlp->minor, + nlp->packet_type == P_nl_after_last_packet? + "Empty-Reply" : nl_packet_name(nlp->packet_type), + nlp->packet_type, + req->seq, req->ack, req->len); +} + +int drbd_khelper(struct drbd_conf *mdev, char *cmd) +{ + char mb[12]; + char *argv[] = {usermode_helper, cmd, mb, NULL }; + static char *envp[] = { "HOME=/", + "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", + NULL }; + + snprintf(mb, 12, "minor-%d", mdev_to_minor(mdev)); + + INFO("helper command: %s %s\n", usermode_helper, cmd); + + drbd_bcast_ev_helper(mdev, cmd); + return call_usermodehelper(usermode_helper, argv, envp, 1); +} + +enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev) +{ + char *ex_to_string; + int r; + enum drbd_disk_state nps; + enum fencing_policy fp; + + D_ASSERT(mdev->state.pdsk == DUnknown); + + if (inc_local_if_state(mdev, Consistent)) { + fp = mdev->bc->dc.fencing; + dec_local(mdev); + } else { + DRBD_WARN("Not outdating peer, I'm not even Consistent myself.\n"); + return mdev->state.pdsk; + } + + if (fp == Stonith) + _drbd_request_state(mdev, NS(susp,1), ChgWaitComplete); + + r = drbd_khelper(mdev, "outdate-peer"); + + switch ((r>>8) & 0xff) { + case 3: /* peer is inconsistent */ + ex_to_string = "peer is inconsistent or worse"; + nps = Inconsistent; + break; + case 4: + ex_to_string = "peer is outdated"; + nps = Outdated; + break; + case 5: /* peer was down, we will(have) create(d) a new UUID anyways... */ + /* If we would be more strict, we would return DUnknown here. */ + ex_to_string = "peer is unreachable, assumed to be dead"; + nps = Outdated; + break; + case 6: /* Peer is primary, voluntarily outdate myself. + * This is useful when an unconnected Secondary is asked to + * become Primary, but findes the other peer being active. */ + ex_to_string = "peer is active"; + DRBD_WARN("Peer is primary, outdating myself.\n"); + nps = DUnknown; + _drbd_request_state(mdev, NS(disk, Outdated), ChgWaitComplete); + break; + case 7: + if (fp != Stonith) + ERR("outdate-peer() = 7 && fencing != Stonith !!!\n"); + ex_to_string = "peer was stonithed"; + nps = Outdated; + break; + default: + /* The script is broken ... */ + nps = DUnknown; + ERR("outdate-peer helper broken, returned %d\n", (r>>8)&0xff); + return nps; + } + + INFO("outdate-peer helper returned %d (%s)\n", + (r>>8) & 0xff, ex_to_string); + return nps; +} + + +int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) +{ + const int max_tries = 4; + int r = 0; + int try = 0; + int forced = 0; + union drbd_state_t mask, val; + enum drbd_disk_state nps; + + if (new_role == Primary) + request_ping(mdev); /* Detect a dead peer ASAP */ + + mutex_lock(&mdev->state_mutex); + + mask.i = 0; mask.role = role_mask; + val.i = 0; val.role = new_role; + + while (try++ < max_tries) { + r = _drbd_request_state(mdev, mask, val, ChgWaitComplete); + + /* in case we first succeeded to outdate, + * but now suddenly could establish a connection */ + if (r == SS_CW_FailedByPeer && mask.pdsk != 0) { + val.pdsk = 0; + mask.pdsk = 0; + continue; + } + + if( r == SS_NoUpToDateDisk && force && + ( mdev->state.disk == Inconsistent || + mdev->state.disk == Outdated ) ) { + mask.disk = disk_mask; + val.disk = UpToDate; + forced = 1; + continue; + } + + if ( r == SS_NoUpToDateDisk && + mdev->state.disk == Consistent ) { + D_ASSERT(mdev->state.pdsk == DUnknown); + nps = drbd_try_outdate_peer(mdev); + + if (nps == Outdated) { + val.disk = UpToDate; + mask.disk = disk_mask; + } + + val.pdsk = nps; + mask.pdsk = disk_mask; + + continue; + } + + if (r == SS_NothingToDo) + goto fail; + if (r == SS_PrimaryNOP) { + nps = drbd_try_outdate_peer(mdev); + + if (force && nps > Outdated) { + DRBD_WARN("Forced into split brain situation!\n"); + nps = Outdated; + } + + mask.pdsk = disk_mask; + val.pdsk = nps; + + continue; + } + if (r == SS_TwoPrimaries) { + /* Maybe the peer is detected as dead very soon... + retry at most once more in this case. */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout((mdev->net_conf->ping_timeo+1)*HZ/10); + if (try < max_tries) + try = max_tries -1; + continue; + } + if (r < SS_Success) { + r = _drbd_request_state(mdev, mask, val, + ChgStateVerbose + ChgWaitComplete); + if (r < SS_Success) + goto fail; + } + break; + } + + if (forced) + DRBD_WARN("Forced to consider local data as UpToDate!\n"); + + fsync_bdev(mdev->this_bdev); + + /* Wait until nothing is on the fly :) */ + wait_event(mdev->misc_wait, atomic_read(&mdev->ap_pending_cnt) == 0); + + /* FIXME RACE here: if our direct user is not using bd_claim (i.e. + * not a filesystem) since cstate might still be >= Connected, new + * ap requests may come in and increase ap_pending_cnt again! + * but that means someone is misusing DRBD... + * */ + + if (new_role == Secondary) { + set_disk_ro(mdev->vdisk, TRUE ); + if (inc_local(mdev)) { + mdev->bc->md.uuid[Current] &= ~(u64)1; + dec_local(mdev); + } + } else { + if (inc_net(mdev)) { + mdev->net_conf->want_lose = 0; + dec_net(mdev); + } + set_disk_ro(mdev->vdisk, FALSE ); + if (inc_local(mdev)) { + if ( ((mdev->state.conn < Connected || + mdev->state.pdsk <= Failed) + && mdev->bc->md.uuid[Bitmap] == 0) || forced) + drbd_uuid_new_current(mdev); + + mdev->bc->md.uuid[Current] |= (u64)1; + dec_local(mdev); + } + } + + if ((new_role == Secondary) && inc_local(mdev) ) + { + drbd_al_to_on_disk_bm(mdev); + dec_local(mdev); + } + + if (mdev->state.conn >= WFReportParams) { + /* if this was forced, we should consider sync */ + if (forced) + drbd_send_uuids(mdev); + drbd_send_state(mdev); + } + + drbd_md_sync(mdev); + + fail: + mutex_unlock(&mdev->state_mutex); + return r; +} + + +STATIC int drbd_nl_primary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + struct primary primary_args; + + memset(&primary_args, 0, sizeof(struct primary)); + if (!primary_from_tags(mdev, nlp->tag_list, &primary_args)) { + reply->ret_code = UnknownMandatoryTag; + return 0; + } + + reply->ret_code = + drbd_set_role(mdev, Primary, primary_args.overwrite_peer); + + return 0; +} + +STATIC int drbd_nl_secondary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + reply->ret_code = drbd_set_role(mdev, Secondary, 0); + + return 0; +} + +/* initializes the md.*_offset members, so we are able to find + * the on disk meta data */ +STATIC void drbd_md_set_sector_offsets(struct drbd_conf *mdev, + struct drbd_backing_dev *bdev) +{ + sector_t md_size_sect = 0; + switch (bdev->dc.meta_dev_idx) { + default: + /* v07 style fixed size indexed meta data */ + bdev->md.md_size_sect = MD_RESERVED_SECT; + bdev->md.md_offset = drbd_md_ss__(mdev, bdev); + bdev->md.al_offset = MD_AL_OFFSET; + bdev->md.bm_offset = MD_BM_OFFSET; + break; + case DRBD_MD_INDEX_FLEX_EXT: + /* just occupy the full device; unit: sectors */ + bdev->md.md_size_sect = drbd_get_capacity(bdev->md_bdev); + bdev->md.md_offset = 0; + bdev->md.al_offset = MD_AL_OFFSET; + bdev->md.bm_offset = MD_BM_OFFSET; + break; + case DRBD_MD_INDEX_INTERNAL: + case DRBD_MD_INDEX_FLEX_INT: + bdev->md.md_offset = drbd_md_ss__(mdev, bdev); + /* al size is still fixed */ + bdev->md.al_offset = -MD_AL_MAX_SIZE; + /* LGE FIXME max size check missing. */ + /* we need (slightly less than) ~ this much bitmap sectors: */ + md_size_sect = drbd_get_capacity(bdev->backing_bdev); + md_size_sect = ALIGN(md_size_sect, BM_SECT_PER_EXT); + md_size_sect = BM_SECT_TO_EXT(md_size_sect); + md_size_sect = ALIGN(md_size_sect, 8); + + /* plus the "drbd meta data super block", + * and the activity log; */ + md_size_sect += MD_BM_OFFSET; + + bdev->md.md_size_sect = md_size_sect; + /* bitmap offset is adjusted by 'super' block size */ + bdev->md.bm_offset = -md_size_sect + MD_AL_OFFSET; + break; + } +} + +char *ppsize(char *buf, unsigned long long size) +{ + /* Needs 9 bytes at max. */ + static char units[] = { 'K', 'M', 'G', 'T', 'P', 'E' }; + int base = 0; + while (size >= 10000 ) { + /* shift + round */ + size = (size >> 10) + !!(size & (1<<9)); + base++; + } + sprintf(buf, "%lu %cB", (long)size, units[base]); + + return buf; +} + +/** + * drbd_determin_dev_size: + * Evaluates all constraints and sets our correct device size. + * Negative return values indicate errors. 0 and positive values + * indicate success. + * You should call drbd_md_sync() after calling this function. + */ +enum determin_dev_size_enum drbd_determin_dev_size(struct drbd_conf *mdev) __must_hold(local) +{ + sector_t prev_first_sect, prev_size; /* previous meta location */ + sector_t la_size; + sector_t size; + char ppb[10]; + + int md_moved, la_size_changed; + enum determin_dev_size_enum rv=unchanged; + + wait_event(mdev->al_wait, lc_try_lock(mdev->act_log)); + + prev_first_sect = drbd_md_first_sector(mdev->bc); + prev_size = mdev->bc->md.md_size_sect; + la_size = mdev->bc->md.la_size_sect; + + /* TODO: should only be some assert here, not (re)init... */ + drbd_md_set_sector_offsets(mdev, mdev->bc); + + size = drbd_new_dev_size(mdev, mdev->bc); + + if ( drbd_get_capacity(mdev->this_bdev) != size || + drbd_bm_capacity(mdev) != size ) { + int err; + err = drbd_bm_resize(mdev, size); + if (unlikely(err)) { + /* currently there is only one error: ENOMEM! */ + size = drbd_bm_capacity(mdev)>>1; + if (size == 0) { + ERR("OUT OF MEMORY! " + "Could not allocate bitmap! "); + } else { + /* FIXME this is problematic, + * if we in fact are smaller now! */ + ERR("BM resizing failed. " + "Leaving size unchanged at size = %lu KB\n", + (unsigned long)size); + } + rv = dev_size_error; + } + /* racy, see comments above. */ + drbd_set_my_capacity(mdev, size); + mdev->bc->md.la_size_sect = size; + INFO("size = %s (%llu KB)\n", ppsize(ppb, size>>1), + (unsigned long long)size>>1); + } + if (rv == dev_size_error) + goto out; + + la_size_changed = (la_size != mdev->bc->md.la_size_sect); + + /* LGE: flexible device size!! is this the right thing to test? */ + md_moved = prev_first_sect != drbd_md_first_sector(mdev->bc) + || prev_size != mdev->bc->md.md_size_sect; + + if (md_moved) { + DRBD_WARN("Moving meta-data.\n"); + /* assert: (flexible) internal meta data */ + } + + if (la_size_changed || md_moved) { + drbd_al_shrink(mdev); /* All extents inactive. */ + INFO("Writing the whole bitmap, size changed\n"); + rv = drbd_bitmap_io(mdev, &drbd_bm_write); + drbd_md_mark_dirty(mdev); + } + + if (size > la_size) rv = grew; + if (size < la_size) rv = shrunk; +out: + lc_unlock(mdev->act_log); + wake_up(&mdev->al_wait); + + return rv; +} + +sector_t +drbd_new_dev_size(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) +{ + sector_t p_size = mdev->p_size; /* partner's disk size. */ + sector_t la_size = bdev->md.la_size_sect; /* last agreed size. */ + sector_t m_size; /* my size */ + sector_t u_size = bdev->dc.disk_size; /* size requested by user. */ + sector_t size = 0; + + m_size = drbd_get_max_capacity(bdev); + + if (p_size && m_size) { + size = min_t(sector_t, p_size, m_size); + } else { + if (la_size) { + size = la_size; + if (m_size && m_size < size) + size = m_size; + if (p_size && p_size < size) + size = p_size; + } else { + if (m_size) + size = m_size; + if (p_size) + size = p_size; + } + } + + if (size == 0) + ERR("Both nodes diskless!\n"); + + if (u_size) { + if (u_size > size) + ERR("Requested disk size is too big (%lu > %lu)\n", + (unsigned long)u_size>>1, (unsigned long)size>>1); + else + size = u_size; + } + + return size; +} + +/** + * drbd_check_al_size: + * checks that the al lru is of requested size, and if neccessary tries to + * allocate a new one. returns -EBUSY if current al lru is still used, + * -ENOMEM when allocation failed, and 0 on success. You should call + * drbd_md_sync() after you called this function. + */ +STATIC int drbd_check_al_size(struct drbd_conf *mdev) +{ + struct lru_cache *n, *t; + struct lc_element *e; + unsigned int in_use; + int i; + + ERR_IF(mdev->sync_conf.al_extents < 7) + mdev->sync_conf.al_extents = 127; + + if ( mdev->act_log && + mdev->act_log->nr_elements == mdev->sync_conf.al_extents ) + return 0; + + in_use = 0; + t = mdev->act_log; + n = lc_alloc("act_log", mdev->sync_conf.al_extents, + sizeof(struct lc_element), mdev); + + if (n == NULL) { + ERR("Cannot allocate act_log lru!\n"); + return -ENOMEM; + } + spin_lock_irq(&mdev->al_lock); + if (t) { + for (i = 0; i < t->nr_elements; i++) { + e = lc_entry(t, i); + if (e->refcnt) + ERR("refcnt(%d)==%d\n", + e->lc_number, e->refcnt); + in_use += e->refcnt; + } + } + if (!in_use) + mdev->act_log = n; + spin_unlock_irq(&mdev->al_lock); + if (in_use) { + ERR("Activity log still in use!\n"); + lc_free(n); + return -EBUSY; + } else { + if (t) + lc_free(t); + } + drbd_md_mark_dirty(mdev); /* we changed mdev->act_log->nr_elemens */ + return 0; +} + +void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_seg_s) __must_hold(local) +{ + struct request_queue * const q = mdev->rq_queue; + struct request_queue * const b = mdev->bc->backing_bdev->bd_disk->queue; + /* unsigned int old_max_seg_s = q->max_segment_size; */ + int max_segments = mdev->bc->dc.max_bio_bvecs; + + if (b->merge_bvec_fn && !mdev->bc->dc.use_bmbv) + max_seg_s = PAGE_SIZE; + + max_seg_s = min(b->max_sectors * b->hardsect_size, max_seg_s); + + MTRACE(TraceTypeRq, TraceLvlSummary, + DUMPI(b->max_sectors); + DUMPI(b->max_phys_segments); + DUMPI(b->max_hw_segments); + DUMPI(b->max_segment_size); + DUMPI(b->hardsect_size); + DUMPI(b->seg_boundary_mask); + ); + + q->max_sectors = max_seg_s >> 9; + if (max_segments) { + q->max_phys_segments = max_segments; + q->max_hw_segments = max_segments; + } else { + q->max_phys_segments = MAX_PHYS_SEGMENTS; + q->max_hw_segments = MAX_HW_SEGMENTS; + } + q->max_segment_size = max_seg_s; + q->hardsect_size = 512; + q->seg_boundary_mask = PAGE_SIZE-1; + blk_queue_stack_limits(q, b); + + /* KERNEL BUG. in ll_rw_blk.c ?? + * t->max_segment_size = min(t->max_segment_size,b->max_segment_size); + * should be + * t->max_segment_size = min_not_zero(...,...) + * workaround here: */ + if (q->max_segment_size == 0) + q->max_segment_size = max_seg_s; + + MTRACE(TraceTypeRq, TraceLvlSummary, + DUMPI(q->max_sectors); + DUMPI(q->max_phys_segments); + DUMPI(q->max_hw_segments); + DUMPI(q->max_segment_size); + DUMPI(q->hardsect_size); + DUMPI(q->seg_boundary_mask); + ); + + if (b->merge_bvec_fn) + DRBD_WARN("Backing device's merge_bvec_fn() = %p\n", + b->merge_bvec_fn); + INFO("max_segment_size ( = BIO size ) = %u\n", q->max_segment_size); + + if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) { + INFO("Adjusting my ra_pages to backing device's (%lu -> %lu)\n", + q->backing_dev_info.ra_pages, + b->backing_dev_info.ra_pages); + q->backing_dev_info.ra_pages = b->backing_dev_info.ra_pages; + } +} + +/* does always return 0; + * interesting return code is in reply->ret_code */ +STATIC int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + enum ret_codes retcode; + struct drbd_backing_dev *nbc = NULL; /* new_backing_conf */ + struct inode *inode, *inode2; + struct lru_cache *resync_lru = NULL; + union drbd_state_t ns, os; + int rv, ntries = 0; + + /* if you want to reconfigure, please tear down first */ + if (mdev->state.disk > Diskless) { + retcode = HaveDiskConfig; + goto fail; + } + + /* + * We may have gotten here very quickly from a detach. Wait for a bit + * then fail. + */ + while (1) { + __no_warn(local, nbc = mdev->bc; ); + if (nbc == NULL) + break; + if (ntries++ >= 5) { + DRBD_WARN("drbd_nl_disk_conf: mdev->bc not NULL.\n"); + retcode = HaveDiskConfig; + goto fail; + } + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/10); + } + + nbc = kmalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL); + if (!nbc) { + retcode = KMallocFailed; + goto fail; + } + + if ( !(nlp->flags & DRBD_NL_SET_DEFAULTS) && inc_local(mdev) ) { + memcpy(&nbc->dc, &mdev->bc->dc, sizeof(struct disk_conf)); + dec_local(mdev); + } else { + memset(&nbc->dc, 0, sizeof(struct disk_conf)); + nbc->dc.disk_size = DRBD_DISK_SIZE_SECT_DEF; + nbc->dc.on_io_error = DRBD_ON_IO_ERROR_DEF; + nbc->dc.fencing = DRBD_FENCING_DEF; + nbc->dc.max_bio_bvecs= DRBD_MAX_BIO_BVECS_DEF; + } + + if (!disk_conf_from_tags(mdev, nlp->tag_list, &nbc->dc)) { + retcode = UnknownMandatoryTag; + goto fail; + } + + nbc->lo_file = NULL; + nbc->md_file = NULL; + + if (nbc->dc.meta_dev_idx < DRBD_MD_INDEX_FLEX_INT) { + retcode = LDMDInvalid; + goto fail; + } + + nbc->lo_file = filp_open(nbc->dc.backing_dev, O_RDWR, 0); + if (IS_ERR(nbc->lo_file)) { + ERR("open(\"%s\") failed with %ld\n", nbc->dc.backing_dev, + PTR_ERR(nbc->lo_file)); + nbc->lo_file = NULL; + retcode = LDNameInvalid; + goto fail; + } + + inode = nbc->lo_file->f_dentry->d_inode; + + if (!S_ISBLK(inode->i_mode)) { + retcode = LDNoBlockDev; + goto fail; + } + + nbc->md_file = filp_open(nbc->dc.meta_dev, O_RDWR, 0); + if (IS_ERR(nbc->md_file)) { + ERR("open(\"%s\") failed with %ld\n", nbc->dc.meta_dev, + PTR_ERR(nbc->md_file)); + nbc->md_file = NULL; + retcode = MDNameInvalid; + goto fail; + } + + inode2 = nbc->md_file->f_dentry->d_inode; + + if (!S_ISBLK(inode2->i_mode)) { + retcode = MDNoBlockDev; + goto fail; + } + + nbc->backing_bdev = inode->i_bdev; + if (bd_claim(nbc->backing_bdev, mdev)) { + printk(KERN_ERR "drbd: bd_claim(%p,%p); failed [%p;%p;%u]\n", + nbc->backing_bdev, mdev, + nbc->backing_bdev->bd_holder, + nbc->backing_bdev->bd_contains->bd_holder, + nbc->backing_bdev->bd_holders); + retcode = LDMounted; + goto fail; + } + + resync_lru = lc_alloc("resync", 61, sizeof(struct bm_extent), mdev); + if (!resync_lru) { + retcode = KMallocFailed; + goto fail; + } + + if (!mdev->bitmap) { + if(drbd_bm_init(mdev)) { + retcode = KMallocFailed; + goto fail; + } + } + + nbc->md_bdev = inode2->i_bdev; + if (bd_claim(nbc->md_bdev, + (nbc->dc.meta_dev_idx == DRBD_MD_INDEX_INTERNAL || + nbc->dc.meta_dev_idx == DRBD_MD_INDEX_FLEX_INT) ? + (void *)mdev : (void *) drbd_m_holder )) { + retcode = MDMounted; + goto release_bdev_fail; + } + + if ( (nbc->backing_bdev == nbc->md_bdev) != + (nbc->dc.meta_dev_idx == DRBD_MD_INDEX_INTERNAL || + nbc->dc.meta_dev_idx == DRBD_MD_INDEX_FLEX_INT) ) { + retcode = LDMDInvalid; + goto release_bdev2_fail; + } + + if ((drbd_get_capacity(nbc->backing_bdev)) < nbc->dc.disk_size) { + retcode = LDDeviceTooSmall; + goto release_bdev2_fail; + } + +/* TODO check whether backing device size is within plausible limits */ + + /* Make sure the new disk is big enough + * (we may currently be Primary with no local disk...) */ + if (drbd_get_capacity(nbc->backing_bdev) < + drbd_get_capacity(mdev->this_bdev) ) { + retcode = LDDeviceTooSmall; + goto release_bdev2_fail; + } + + nbc->known_size = drbd_get_capacity(nbc->backing_bdev); + + retcode = _drbd_request_state(mdev, NS(disk, Attaching), ChgStateVerbose); + if (retcode < SS_Success ) + goto release_bdev2_fail; + + if (!inc_local_if_state(mdev, Attaching)) { + goto force_diskless; + } + + drbd_thread_start(&mdev->worker); + drbd_md_set_sector_offsets(mdev, nbc); + + retcode = drbd_md_read(mdev, nbc); + if (retcode != NoError) + goto force_diskless_dec; + + if (mdev->state.conn < Connected && + mdev->state.role == Primary && + (mdev->ed_uuid & ~((u64)1)) != (nbc->md.uuid[Current] & ~((u64)1))) { + ERR("Can only attach to data with current UUID=%016llX\n", + (unsigned long long)mdev->ed_uuid); + retcode = DataOfWrongCurrent; + goto force_diskless_dec; + } + + /* Since we are diskless, fix the AL first... */ + if (drbd_check_al_size(mdev)) { + retcode = KMallocFailed; + goto force_diskless_dec; + } + + /* Prevent shrinking of consistent devices ! */ + if (drbd_md_test_flag(nbc, MDF_Consistent) && + drbd_new_dev_size(mdev, nbc) < nbc->md.la_size_sect) { + retcode = LDDeviceTooSmall; + goto force_diskless_dec; + } + + if (!drbd_al_read_log(mdev, nbc)) { + retcode = MDIOError; + goto force_diskless_dec; + } + + /* Reset the "barriers don't work" bits here, then force meta data to + * be written, to ensure we determine if barriers are supported. */ + if (nbc->dc.no_disk_flush) + set_bit(LL_DEV_NO_FLUSH, &mdev->flags); + else + clear_bit(LL_DEV_NO_FLUSH, &mdev->flags); + + if (nbc->dc.no_md_flush) + set_bit(MD_NO_BARRIER, &mdev->flags); + else + clear_bit(MD_NO_BARRIER, &mdev->flags); + + /* Point of no return reached. + * Devices and memory are no longer released by error cleanup below. + * now mdev takes over responsibility, and the state engine should + * clean it up somewhere. */ + D_ASSERT(mdev->bc == NULL); + mdev->bc = nbc; + mdev->resync = resync_lru; + nbc = NULL; + resync_lru = NULL; + + if (drbd_md_test_flag(mdev->bc, MDF_PrimaryInd)) + set_bit(CRASHED_PRIMARY, &mdev->flags); + else + clear_bit(CRASHED_PRIMARY, &mdev->flags); + + mdev->send_cnt = 0; + mdev->recv_cnt = 0; + mdev->read_cnt = 0; + mdev->writ_cnt = 0; + + drbd_setup_queue_param(mdev, DRBD_MAX_SEGMENT_SIZE); + /* + * FIXME currently broken. + * drbd_set_recv_tcq(mdev, + * drbd_queue_order_type(mdev)==QUEUE_ORDERED_TAG); + */ + + /* If I am currently not Primary, + * but meta data primary indicator is set, + * I just now recover from a hard crash, + * and have been Primary before that crash. + * + * Now, if I had no connection before that crash + * (have been degraded Primary), chances are that + * I won't find my peer now either. + * + * In that case, and _only_ in that case, + * we use the degr-wfc-timeout instead of the default, + * so we can automatically recover from a crash of a + * degraded but active "cluster" after a certain timeout. + */ + clear_bit(USE_DEGR_WFC_T, &mdev->flags); + if ( mdev->state.role != Primary && + drbd_md_test_flag(mdev->bc, MDF_PrimaryInd) && + !drbd_md_test_flag(mdev->bc, MDF_ConnectedInd) ) + set_bit(USE_DEGR_WFC_T, &mdev->flags); + + if (drbd_determin_dev_size(mdev) == dev_size_error) { + retcode = VMallocFailed; + goto force_diskless_dec; + } + + if (drbd_md_test_flag(mdev->bc, MDF_FullSync)) { + INFO("Assuming that all blocks are out of sync " + "(aka FullSync)\n"); + if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write)) { + retcode = MDIOError; + goto force_diskless_dec; + } + } else { + if (drbd_bitmap_io(mdev, &drbd_bm_read) < 0) { + retcode = MDIOError; + goto force_diskless_dec; + } + } + + if (test_bit(CRASHED_PRIMARY, &mdev->flags)) { + drbd_al_apply_to_bm(mdev); + drbd_al_to_on_disk_bm(mdev); + } + /* else { + FIXME wipe out on disk al! + } */ + + spin_lock_irq(&mdev->req_lock); + os = mdev->state; + ns.i = os.i; + /* If MDF_Consistent is not set go into inconsistent state, + otherwise investige MDF_WasUpToDate... + If MDF_WasUpToDate is not set go into Outdated disk state, + otherwise into Consistent state. + */ + if (drbd_md_test_flag(mdev->bc, MDF_Consistent)) { + if (drbd_md_test_flag(mdev->bc, MDF_WasUpToDate)) + ns.disk = Consistent; + else + ns.disk = Outdated; + } else { + ns.disk = Inconsistent; + } + + if (drbd_md_test_flag(mdev->bc, MDF_PeerOutDated)) + ns.pdsk = Outdated; + + if ( ns.disk == Consistent && + ( ns.pdsk == Outdated || mdev->bc->dc.fencing == DontCare ) ) + ns.disk = UpToDate; + + /* All tests on MDF_PrimaryInd, MDF_ConnectedInd, + MDF_Consistent and MDF_WasUpToDate must happen before + this point, because drbd_request_state() modifies these + flags. */ + + /* In case we are Connected postpone any desicion on the new disk + state after the negotiation phase. */ + if (mdev->state.conn == Connected) { + mdev->new_state_tmp.i = ns.i; + ns.i = os.i; + ns.disk = Negotiating; + } + + rv = _drbd_set_state(mdev, ns, ChgStateVerbose, NULL); + ns = mdev->state; + spin_unlock_irq(&mdev->req_lock); + + if (rv < SS_Success) + goto force_diskless_dec; + + if(mdev->state.role == Primary) mdev->bc->md.uuid[Current] |= (u64)1; + else mdev->bc->md.uuid[Current] &= ~(u64)1; + + drbd_md_mark_dirty(mdev); + drbd_md_sync(mdev); + + dec_local(mdev); + reply->ret_code = retcode; + return 0; + + force_diskless_dec: + dec_local(mdev); + force_diskless: + drbd_force_state(mdev, NS(disk, Diskless)); + drbd_md_sync(mdev); + release_bdev2_fail: + if (nbc) + bd_release(nbc->md_bdev); + release_bdev_fail: + if (nbc) + bd_release(nbc->backing_bdev); + fail: + if (nbc) { + if (nbc->lo_file) + fput(nbc->lo_file); + if (nbc->md_file) + fput(nbc->md_file); + kfree(nbc); + } + if (resync_lru) + lc_free(resync_lru); + + reply->ret_code = retcode; + return 0; +} + +STATIC int drbd_nl_detach(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + fsync_bdev(mdev->this_bdev); + reply->ret_code = drbd_request_state(mdev, NS(disk, Diskless)); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/20); /* 50ms; Time for worker to finally terminate */ + + return 0; +} + +#define HMAC_NAME_L 20 + +STATIC int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + int i, ns; + enum ret_codes retcode; + struct net_conf *new_conf = NULL; + struct crypto_hash *tfm = NULL; + struct crypto_hash *integrity_w_tfm = NULL; + struct crypto_hash *integrity_r_tfm = NULL; + struct hlist_head *new_tl_hash = NULL; + struct hlist_head *new_ee_hash = NULL; + struct drbd_conf *odev; + char hmac_name[HMAC_NAME_L]; + void *int_dig_out = NULL; + void *int_dig_in = NULL; + void *int_dig_vv = NULL; + + if (mdev->state.conn > StandAlone) { + retcode = HaveNetConfig; + goto fail; + } + + new_conf = kmalloc(sizeof(struct net_conf), GFP_KERNEL); + if (!new_conf) { + retcode = KMallocFailed; + goto fail; + } + + if ( !(nlp->flags & DRBD_NL_SET_DEFAULTS) && inc_net(mdev)) { + memcpy(new_conf, mdev->net_conf, sizeof(struct net_conf)); + dec_net(mdev); + } else { + memset(new_conf, 0, sizeof(struct net_conf)); + new_conf->timeout = DRBD_TIMEOUT_DEF; + new_conf->try_connect_int = DRBD_CONNECT_INT_DEF; + new_conf->ping_int = DRBD_PING_INT_DEF; + new_conf->max_epoch_size = DRBD_MAX_EPOCH_SIZE_DEF; + new_conf->max_buffers = DRBD_MAX_BUFFERS_DEF; + new_conf->unplug_watermark = DRBD_UNPLUG_WATERMARK_DEF; + new_conf->sndbuf_size = DRBD_SNDBUF_SIZE_DEF; + new_conf->ko_count = DRBD_KO_COUNT_DEF; + new_conf->after_sb_0p = DRBD_AFTER_SB_0P_DEF; + new_conf->after_sb_1p = DRBD_AFTER_SB_1P_DEF; + new_conf->after_sb_2p = DRBD_AFTER_SB_2P_DEF; + new_conf->want_lose = 0; + new_conf->two_primaries = 0; + new_conf->wire_protocol = DRBD_PROT_C; + new_conf->ping_timeo = DRBD_PING_TIMEO_DEF; + new_conf->rr_conflict = DRBD_RR_CONFLICT_DEF; + } + + if (!net_conf_from_tags(mdev, nlp->tag_list, new_conf)) { + retcode = UnknownMandatoryTag; + goto fail; + } + + if (new_conf->two_primaries + && (new_conf->wire_protocol != DRBD_PROT_C)) { + retcode = ProtocolCRequired; + goto fail; + }; + + if (mdev->state.role == Primary && new_conf->want_lose) { + retcode = DiscardNotAllowed; + goto fail; + } + +#define M_ADDR(A) (((struct sockaddr_in *)&A->my_addr)->sin_addr.s_addr) +#define M_PORT(A) (((struct sockaddr_in *)&A->my_addr)->sin_port) +#define O_ADDR(A) (((struct sockaddr_in *)&A->peer_addr)->sin_addr.s_addr) +#define O_PORT(A) (((struct sockaddr_in *)&A->peer_addr)->sin_port) + retcode = NoError; + for (i = 0; i < minor_count; i++) { + odev = minor_to_mdev(i); + if (!odev || odev == mdev) + continue; + if ( inc_net(odev)) { + if ( M_ADDR(new_conf) == M_ADDR(odev->net_conf) && + M_PORT(new_conf) == M_PORT(odev->net_conf) ) + retcode = LAAlreadyInUse; + + if (O_ADDR(new_conf) == O_ADDR(odev->net_conf) && + O_PORT(new_conf) == O_PORT(odev->net_conf) ) + retcode = OAAlreadyInUse; + + dec_net(odev); + if (retcode != NoError) + goto fail; + } + } +#undef M_ADDR +#undef M_PORT +#undef O_ADDR +#undef O_PORT + + if (new_conf->cram_hmac_alg[0] != 0) { + snprintf(hmac_name, HMAC_NAME_L, "hmac(%s)", + new_conf->cram_hmac_alg); + tfm = crypto_alloc_hash(hmac_name, 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) { + tfm = NULL; + retcode = CRAMAlgNotAvail; + goto fail; + } + + if (crypto_tfm_alg_type(crypto_hash_tfm(tfm)) + != CRYPTO_ALG_TYPE_HASH) { + retcode = CRAMAlgNotDigest; + goto fail; + } + } + + if (new_conf->integrity_alg[0]) { + integrity_w_tfm = crypto_alloc_hash(new_conf->integrity_alg, 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(integrity_w_tfm)) { + integrity_w_tfm = NULL; + retcode=IntegrityAlgNotAvail; + goto fail; + } + + if (crypto_tfm_alg_type(crypto_hash_tfm(integrity_w_tfm)) != CRYPTO_ALG_TYPE_DIGEST) { + retcode=IntegrityAlgNotDigest; + goto fail; + } + + integrity_r_tfm = crypto_alloc_hash(new_conf->integrity_alg, 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(integrity_r_tfm)) { + integrity_r_tfm = NULL; + retcode=IntegrityAlgNotAvail; + goto fail; + } + } + + ns = new_conf->max_epoch_size/8; + if (mdev->tl_hash_s != ns) { + new_tl_hash = kzalloc(ns*sizeof(void *), GFP_KERNEL); + if (!new_tl_hash) { + retcode = KMallocFailed; + goto fail; + } + } + + ns = new_conf->max_buffers/8; + if (new_conf->two_primaries && ( mdev->ee_hash_s != ns ) ) { + new_ee_hash = kzalloc(ns*sizeof(void *), GFP_KERNEL); + if (!new_ee_hash) { + retcode = KMallocFailed; + goto fail; + } + } + + ((char *)new_conf->shared_secret)[SHARED_SECRET_MAX-1] = 0; + +#if 0 + /* for the connection loss logic in drbd_recv + * I _need_ the resulting timeo in jiffies to be + * non-zero and different + * + * XXX maybe rather store the value scaled to jiffies? + * Note: MAX_SCHEDULE_TIMEOUT/HZ*HZ != MAX_SCHEDULE_TIMEOUT + * and HZ > 10; which is unlikely to change... + * Thus, if interrupted by a signal, + * sock_{send,recv}msg returns -EINTR, + * if the timeout expires, -EAGAIN. + */ + /* unlikely: someone disabled the timeouts ... + * just put some huge values in there. */ + if (!new_conf->ping_int) + new_conf->ping_int = MAX_SCHEDULE_TIMEOUT/HZ; + if (!new_conf->timeout) + new_conf->timeout = MAX_SCHEDULE_TIMEOUT/HZ*10; + if (new_conf->ping_int*10 < new_conf->timeout) + new_conf->timeout = new_conf->ping_int*10/6; + if (new_conf->ping_int*10 == new_conf->timeout) + new_conf->ping_int = new_conf->ping_int+1; +#endif + + if (integrity_w_tfm) { + i = crypto_hash_digestsize(integrity_w_tfm); + int_dig_out = kmalloc(i, GFP_KERNEL); + if (!int_dig_out) { + retcode = KMallocFailed; + goto fail; + } + int_dig_in = kmalloc(i, GFP_KERNEL); + if (!int_dig_in) { + retcode = KMallocFailed; + goto fail; + } + int_dig_vv = kmalloc(i, GFP_KERNEL); + if (!int_dig_vv) { + retcode = KMallocFailed; + goto fail; + } + } + + if (!mdev->bitmap) { + if(drbd_bm_init(mdev)) { + retcode = KMallocFailed; + goto fail; + } + } + + D_ASSERT(mdev->net_conf == NULL); + mdev->net_conf = new_conf; + + mdev->send_cnt = 0; + mdev->recv_cnt = 0; + + if (new_tl_hash) { + kfree(mdev->tl_hash); + mdev->tl_hash_s = mdev->net_conf->max_epoch_size/8; + mdev->tl_hash = new_tl_hash; + } + + if (new_ee_hash) { + kfree(mdev->ee_hash); + mdev->ee_hash_s = mdev->net_conf->max_buffers/8; + mdev->ee_hash = new_ee_hash; + } + + crypto_free_hash(mdev->cram_hmac_tfm); + mdev->cram_hmac_tfm = tfm; + + crypto_free_hash(mdev->integrity_w_tfm); + mdev->integrity_w_tfm = integrity_w_tfm; + + crypto_free_hash(mdev->integrity_r_tfm); + mdev->integrity_r_tfm = integrity_r_tfm; + + kfree(mdev->int_dig_out); + kfree(mdev->int_dig_in); + kfree(mdev->int_dig_vv); + mdev->int_dig_out=int_dig_out; + mdev->int_dig_in=int_dig_in; + mdev->int_dig_vv=int_dig_vv; + + retcode = _drbd_request_state(mdev, NS(conn, Unconnected), ChgStateVerbose); + if (retcode >= SS_Success) + drbd_thread_start(&mdev->worker); + + reply->ret_code = retcode; + return 0; + +fail: + kfree(int_dig_out); + kfree(int_dig_in); + kfree(int_dig_vv); + crypto_free_hash(tfm); + crypto_free_hash(integrity_w_tfm); + crypto_free_hash(integrity_r_tfm); + kfree(new_tl_hash); + kfree(new_ee_hash); + kfree(new_conf); + + reply->ret_code = retcode; + return 0; +} + +STATIC int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + int retcode; + + retcode = _drbd_request_state(mdev, NS(conn, Disconnecting), ChgOrdered); + + if (retcode == SS_NothingToDo) + goto done; + else if (retcode == SS_AlreadyStandAlone) + goto done; + else if (retcode == SS_PrimaryNOP) { + /* Our statche checking code wants to see the peer outdated. */ + retcode = drbd_request_state(mdev, NS2(conn, Disconnecting, + pdsk, Outdated)); + } else if (retcode == SS_CW_FailedByPeer) { + /* The peer probabely wants to see us outdated. */ + retcode = _drbd_request_state(mdev, NS2(conn, Disconnecting, + disk, Outdated), + ChgOrdered); + if (retcode == SS_IsDiskLess || retcode == SS_LowerThanOutdated) { + drbd_force_state(mdev, NS(conn, Disconnecting)); + retcode = SS_Success; + } + + } + + if (retcode < SS_Success) + goto fail; + + if (wait_event_interruptible(mdev->state_wait, + mdev->state.conn != Disconnecting) ) { + /* Do not test for mdev->state.conn == StandAlone, since + someone else might connect us in the mean time! */ + retcode = GotSignal; + goto fail; + } + + done: + retcode = NoError; + fail: + drbd_md_sync(mdev); + reply->ret_code = retcode; + return 0; +} + +void resync_after_online_grow(struct drbd_conf *mdev) +{ + int iass; /* I am sync source */ + + INFO("Resync of new storage after online grow\n"); + if (mdev->state.role != mdev->state.peer) + iass = (mdev->state.role == Primary); + else + iass = test_bit(DISCARD_CONCURRENT,&mdev->flags); + + if (iass) + drbd_start_resync(mdev,SyncSource); + else + drbd_request_state(mdev,NS(conn,WFSyncUUID)); +} + +STATIC int drbd_nl_resize(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + struct resize rs; + int retcode = NoError; + int ldsc = 0; /* local disk size changed */ + enum determin_dev_size_enum dd; + + memset(&rs, 0, sizeof(struct resize)); + if (!resize_from_tags(mdev, nlp->tag_list, &rs)) { + retcode = UnknownMandatoryTag; + goto fail; + } + + if (mdev->state.conn > Connected) { + retcode = NoResizeDuringResync; + goto fail; + } + + if ( mdev->state.role == Secondary && + mdev->state.peer == Secondary) { + retcode = APrimaryNodeNeeded; + goto fail; + } + + if (!inc_local(mdev)) { + retcode = HaveNoDiskConfig; + goto fail; + } + + if (mdev->bc->known_size != drbd_get_capacity(mdev->bc->backing_bdev)) { + mdev->bc->known_size = drbd_get_capacity(mdev->bc->backing_bdev); + ldsc = 1; + } + + mdev->bc->dc.disk_size = (sector_t)rs.resize_size; + dd = drbd_determin_dev_size(mdev); + drbd_md_sync(mdev); + dec_local(mdev); + if (dd == dev_size_error) { + retcode = VMallocFailed; + goto fail; + } + + if (mdev->state.conn == Connected && ( dd != unchanged || ldsc) ) { + drbd_send_uuids(mdev); + drbd_send_sizes(mdev); + if (dd == grew) + resync_after_online_grow(mdev); + } + + fail: + reply->ret_code = retcode; + return 0; +} + +STATIC int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + int retcode = NoError; + struct syncer_conf sc; + struct drbd_conf *odev; + int err; + struct crypto_hash *verify_tfm = NULL, *old_verify_tfm = NULL; + int ovr; /* online verify running */ + cpumask_t n_cpu_mask = CPU_MASK_NONE; + + memcpy(&sc, &mdev->sync_conf, sizeof(struct syncer_conf)); + + if (nlp->flags & DRBD_NL_SET_DEFAULTS) { + memset(&sc, 0, sizeof(struct syncer_conf)); + sc.rate = DRBD_RATE_DEF; + sc.after = DRBD_AFTER_DEF; + sc.al_extents = DRBD_AL_EXTENTS_DEF; + } + + if (!syncer_conf_from_tags(mdev, nlp->tag_list, &sc)) { + retcode = UnknownMandatoryTag; + goto fail; + } + + if (sc.after != -1) { + if ( sc.after < -1 || minor_to_mdev(sc.after) == NULL ) { + retcode = SyncAfterInvalid; + goto fail; + } + odev = minor_to_mdev(sc.after); /* check against loops in */ + while (1) { + if (odev == mdev) { + retcode = SyncAfterCycle; + goto fail; + } + if (odev->sync_conf.after == -1) + break; /* no cycles. */ + odev = minor_to_mdev(odev->sync_conf.after); + } + } + + ovr = (mdev->state.conn == VerifyS || mdev->state.conn == VerifyT); + + if (ovr) { + if (strcmp(sc.verify_alg, mdev->sync_conf.verify_alg)) { + retcode = VERIFYIsRunning; + goto fail; + } + } + + if (!ovr && sc.verify_alg[0]) { + verify_tfm = crypto_alloc_hash(sc.verify_alg, 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(verify_tfm)) { + verify_tfm = NULL; + retcode=VERIFYAlgNotAvail; + goto fail; + } + + if (crypto_tfm_alg_type(crypto_hash_tfm(verify_tfm)) != CRYPTO_ALG_TYPE_DIGEST) { + retcode=VERIFYAlgNotDigest; + goto fail; + } + } + + if (sc.cpu_mask[0] != 0) { + err = __bitmap_parse(sc.cpu_mask, 32, 0, (unsigned long *)&n_cpu_mask, NR_CPUS); + if (err) { + DRBD_WARN("__bitmap_parse() failed with %d\n", err); + retcode = CPUMaskParseFailed; + goto fail; + } + } + + ERR_IF (sc.rate < 1) sc.rate = 1; + ERR_IF (sc.al_extents < 7) sc.al_extents = 127; /* arbitrary minimum */ +#define AL_MAX ((MD_AL_MAX_SIZE-1) * AL_EXTENTS_PT) + if (sc.al_extents > AL_MAX) { + ERR("sc.al_extents > %d\n", AL_MAX); + sc.al_extents = AL_MAX; + } +#undef AL_MAX + + spin_lock(&mdev->peer_seq_lock); + /* lock against receive_SyncParam() */ + mdev->sync_conf = sc; + if (!ovr) { + old_verify_tfm = mdev->verify_tfm; + mdev->verify_tfm = verify_tfm; + verify_tfm = NULL; + } + spin_unlock(&mdev->peer_seq_lock); + + crypto_free_hash(old_verify_tfm); + + if (inc_local(mdev)) { + wait_event(mdev->al_wait, lc_try_lock(mdev->act_log)); + drbd_al_shrink(mdev); + err = drbd_check_al_size(mdev); + lc_unlock(mdev->act_log); + wake_up(&mdev->al_wait); + + dec_local(mdev); + drbd_md_sync(mdev); + + if (err) { + retcode = KMallocFailed; + goto fail; + } + } + + if (mdev->state.conn >= Connected) + drbd_send_sync_param(mdev, &sc); + + drbd_alter_sa(mdev, sc.after); + + if (!cpus_equal(mdev->cpu_mask, n_cpu_mask)) { + mdev->cpu_mask = n_cpu_mask; + n_cpu_mask = drbd_calc_cpu_mask(mdev); + drbd_thread_set_cpu(&mdev->receiver, n_cpu_mask); + drbd_thread_set_cpu(&mdev->worker, n_cpu_mask); + drbd_thread_set_cpu(&mdev->asender, n_cpu_mask); + } + +fail: + crypto_free_hash(verify_tfm); + reply->ret_code = retcode; + return 0; +} + +STATIC int drbd_nl_invalidate(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + int retcode; + + retcode = _drbd_request_state(mdev, NS(conn, StartingSyncT), ChgOrdered); + + if (retcode < SS_Success && retcode != SS_NeedConnection) + retcode = drbd_request_state(mdev, NS(conn, StartingSyncT)); + + while (retcode == SS_NeedConnection) { + spin_lock_irq(&mdev->req_lock); + if (mdev->state.conn < Connected) + retcode = _drbd_set_state(_NS(mdev, disk, Inconsistent), ChgStateVerbose, NULL); + spin_unlock_irq(&mdev->req_lock); + + if (retcode != SS_NeedConnection) + break; + + retcode = drbd_request_state(mdev, NS(conn, StartingSyncT)); + } + + reply->ret_code = retcode; + return 0; +} + +STATIC int drbd_nl_invalidate_peer(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + + reply->ret_code = drbd_request_state(mdev, NS(conn, StartingSyncS)); + + return 0; +} + +STATIC int drbd_nl_pause_sync(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + int retcode = NoError; + + if (drbd_request_state(mdev, NS(user_isp, 1)) == SS_NothingToDo) + retcode = PauseFlagAlreadySet; + + reply->ret_code = retcode; + return 0; +} + +STATIC int drbd_nl_resume_sync(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + int retcode = NoError; + + if (drbd_request_state(mdev, NS(user_isp, 0)) == SS_NothingToDo) + retcode = PauseFlagAlreadyClear; + + reply->ret_code = retcode; + return 0; +} + +STATIC int drbd_nl_suspend_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + reply->ret_code = drbd_request_state(mdev, NS(susp, 1)); + + return 0; +} + +STATIC int drbd_nl_resume_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + reply->ret_code = drbd_request_state(mdev, NS(susp, 0)); + return 0; +} + +STATIC int drbd_nl_outdate(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + reply->ret_code = drbd_request_state(mdev, NS(disk, Outdated)); + return 0; +} + +STATIC int drbd_nl_get_config(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + unsigned short *tl; + + tl = reply->tag_list; + + if (inc_local(mdev)) { + tl = disk_conf_to_tags(mdev, &mdev->bc->dc, tl); + dec_local(mdev); + } + + if (inc_net(mdev)) { + tl = net_conf_to_tags(mdev, mdev->net_conf, tl); + dec_net(mdev); + } + tl = syncer_conf_to_tags(mdev, &mdev->sync_conf, tl); + + *tl++ = TT_END; /* Close the tag list */ + + return (int)((char *)tl - (char *)reply->tag_list); +} + +STATIC int drbd_nl_get_state(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + unsigned short *tl; + + tl = reply->tag_list; + + tl = get_state_to_tags(mdev, (struct get_state *)&mdev->state, tl); + *tl++ = TT_END; /* Close the tag list */ + + return (int)((char *)tl - (char *)reply->tag_list); +} + +STATIC int drbd_nl_get_uuids(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + unsigned short *tl; + + tl = reply->tag_list; + + if (inc_local(mdev)) { + /* This is a hand crafted add tag ;) */ + *tl++ = T_uuids; + *tl++ = UUID_SIZE*sizeof(u64); + memcpy(tl, mdev->bc->md.uuid, UUID_SIZE*sizeof(u64)); + tl = (unsigned short *)((char *)tl + UUID_SIZE*sizeof(u64)); + *tl++ = T_uuids_flags; + *tl++ = sizeof(int); + memcpy(tl, &mdev->bc->md.flags, sizeof(int)); + tl = (unsigned short *)((char *)tl + sizeof(int)); + dec_local(mdev); + } + *tl++ = TT_END; /* Close the tag list */ + + return (int)((char *)tl - (char *)reply->tag_list); +} + + +STATIC int drbd_nl_get_timeout_flag(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + unsigned short *tl; + + tl = reply->tag_list; + + /* This is a hand crafted add tag ;) */ + *tl++ = T_use_degraded; + *tl++ = sizeof(char); + *((char *)tl) = test_bit(USE_DEGR_WFC_T, &mdev->flags) ? 1 : 0 ; + tl = (unsigned short *)((char *)tl + sizeof(char)); + *tl++ = TT_END; + + return (int)((char *)tl - (char *)reply->tag_list); +} + +STATIC int drbd_nl_start_ov(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, + struct drbd_nl_cfg_reply *reply) +{ + reply->ret_code = drbd_request_state(mdev,NS(conn,VerifyS)); + + return 0; +} + + +STATIC struct drbd_conf *ensure_mdev(struct drbd_nl_cfg_req *nlp) +{ + struct drbd_conf *mdev; + + mdev = minor_to_mdev(nlp->drbd_minor); + + if (!mdev && (nlp->flags & DRBD_NL_CREATE_DEVICE)) { + mdev = drbd_new_device(nlp->drbd_minor); + + spin_lock_irq(&drbd_pp_lock); + if (minor_table[nlp->drbd_minor] == NULL) { + minor_table[nlp->drbd_minor] = mdev; + mdev = NULL; + } + spin_unlock_irq(&drbd_pp_lock); + + if (mdev) { + kfree(mdev->app_reads_hash); + if (mdev->md_io_page) + __free_page(mdev->md_io_page); + kfree(mdev); + mdev = NULL; + } + + mdev = minor_to_mdev(nlp->drbd_minor); + } + + return mdev; +} + +struct cn_handler_struct { + int (*function)(struct drbd_conf *, + struct drbd_nl_cfg_req *, + struct drbd_nl_cfg_reply* ); + int reply_body_size; +}; + +static struct cn_handler_struct cnd_table[] = { + [ P_primary ] = { &drbd_nl_primary, 0 }, + [ P_secondary ] = { &drbd_nl_secondary, 0 }, + [ P_disk_conf ] = { &drbd_nl_disk_conf, 0 }, + [ P_detach ] = { &drbd_nl_detach, 0 }, + [ P_net_conf ] = { &drbd_nl_net_conf, 0 }, + [ P_disconnect ] = { &drbd_nl_disconnect, 0 }, + [ P_resize ] = { &drbd_nl_resize, 0 }, + [ P_syncer_conf ] = { &drbd_nl_syncer_conf, 0 }, + [ P_invalidate ] = { &drbd_nl_invalidate, 0 }, + [ P_invalidate_peer ] = { &drbd_nl_invalidate_peer, 0 }, + [ P_pause_sync ] = { &drbd_nl_pause_sync, 0 }, + [ P_resume_sync ] = { &drbd_nl_resume_sync, 0 }, + [ P_suspend_io ] = { &drbd_nl_suspend_io, 0 }, + [ P_resume_io ] = { &drbd_nl_resume_io, 0 }, + [ P_outdate ] = { &drbd_nl_outdate, 0 }, + [ P_get_config ] = { &drbd_nl_get_config, + sizeof(struct syncer_conf_tag_len_struct) + + sizeof(struct disk_conf_tag_len_struct) + + sizeof(struct net_conf_tag_len_struct) }, + [ P_get_state ] = { &drbd_nl_get_state, + sizeof(struct get_state_tag_len_struct) }, + [ P_get_uuids ] = { &drbd_nl_get_uuids, + sizeof(struct get_uuids_tag_len_struct) }, + [ P_get_timeout_flag ] = + { &drbd_nl_get_timeout_flag, + sizeof(struct get_timeout_flag_tag_len_struct)}, + [ P_start_ov ] = { &drbd_nl_start_ov, 0 }, +}; + +STATIC void drbd_connector_callback(void *data) +{ + struct cn_msg *req = data; + struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req *)req->data; + struct cn_handler_struct *cm; + struct cn_msg *cn_reply; + struct drbd_nl_cfg_reply *reply; + struct drbd_conf *mdev; + int retcode, rr; + int reply_size = sizeof(struct cn_msg) + + sizeof(struct drbd_nl_cfg_reply) + + sizeof(short int); + + if (!try_module_get(THIS_MODULE)) { + printk(KERN_ERR "drbd: try_module_get() failed!\n"); + return; + } + + mdev = ensure_mdev(nlp); + if (!mdev) { + retcode = MinorNotKnown; + goto fail; + } + + TRACE(TraceTypeNl, TraceLvlSummary, nl_trace_packet(data);); + + if (nlp->packet_type >= P_nl_after_last_packet) { + retcode = UnknownNetLinkPacket; + goto fail; + } + + cm = cnd_table + nlp->packet_type; + reply_size += cm->reply_body_size; + + cn_reply = kmalloc(reply_size, GFP_KERNEL); + if (!cn_reply) { + retcode = KMallocFailed; + goto fail; + } + reply = (struct drbd_nl_cfg_reply *) cn_reply->data; + + reply->packet_type = + cm->reply_body_size ? nlp->packet_type : P_nl_after_last_packet; + reply->minor = nlp->drbd_minor; + reply->ret_code = NoError; /* Might by modified by cm->function. */ + /* reply->tag_list; might be modified by cm->fucntion. */ + + rr = cm->function(mdev, nlp, reply); + + cn_reply->id = req->id; + cn_reply->seq = req->seq; + cn_reply->ack = req->ack + 1; + cn_reply->len = sizeof(struct drbd_nl_cfg_reply) + rr; + cn_reply->flags = 0; + + TRACE(TraceTypeNl, TraceLvlSummary, nl_trace_reply(cn_reply);); + + rr = cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL); + if (rr && rr != -ESRCH) + printk(KERN_INFO "drbd: cn_netlink_send()=%d\n", rr); + + kfree(cn_reply); + module_put(THIS_MODULE); + return; + fail: + drbd_nl_send_reply(req, retcode); + module_put(THIS_MODULE); +} + +static atomic_t drbd_nl_seq = ATOMIC_INIT(2); /* two. */ + +static inline unsigned short * +__tl_add_blob(unsigned short *tl, enum drbd_tags tag, const void *data, + int len, int nul_terminated) +{ + int l = tag_descriptions[tag_number(tag)].max_len; + l = (len < l) ? len : l; + *tl++ = tag; + *tl++ = len; + memcpy(tl, data, len); + /* TODO + * maybe we need to add some padding to the data stream. + * otherwise we may get strange effects on architectures + * that require certain data types to be strictly aligned, + * because now the next "unsigned short" may be misaligned. */ + tl = (unsigned short*)((char*)tl + len); + if (nul_terminated) + *((char*)tl - 1) = 0; + return tl; +} + +static inline unsigned short * +tl_add_blob(unsigned short *tl, enum drbd_tags tag, const void *data, int len) +{ + return __tl_add_blob(tl, tag, data, len, 0); +} + +static inline unsigned short * +tl_add_str(unsigned short *tl, enum drbd_tags tag, const char *str) +{ + return __tl_add_blob(tl, tag, str, strlen(str)+1, 0); +} + +static inline unsigned short * +tl_add_int(unsigned short *tl, enum drbd_tags tag, const void *val) +{ + switch(tag_type(tag)) { + case TT_INTEGER: + *tl++ = tag; + *tl++ = sizeof(int); + *(int*)tl = *(int*)val; + tl = (unsigned short*)((char*)tl+sizeof(int)); + break; + case TT_INT64: + *tl++ = tag; + *tl++ = sizeof(u64); + *(u64*)tl = *(u64*)val; + tl = (unsigned short*)((char*)tl+sizeof(u64)); + break; + default: + /* someone did something stupid. */ + ; + } + return tl; +} + +void drbd_bcast_state(struct drbd_conf *mdev, union drbd_state_t state) +{ + char buffer[sizeof(struct cn_msg)+ + sizeof(struct drbd_nl_cfg_reply)+ + sizeof(struct get_state_tag_len_struct)+ + sizeof(short int)]; + struct cn_msg *cn_reply = (struct cn_msg *) buffer; + struct drbd_nl_cfg_reply *reply = + (struct drbd_nl_cfg_reply *)cn_reply->data; + unsigned short *tl = reply->tag_list; + + /* DRBD_WARN("drbd_bcast_state() got called\n"); */ + + tl = get_state_to_tags(mdev, (struct get_state *)&state, tl); + *tl++ = TT_END; /* Close the tag list */ + + cn_reply->id.idx = CN_IDX_DRBD; + cn_reply->id.val = CN_VAL_DRBD; + + cn_reply->seq = atomic_add_return(1, &drbd_nl_seq); + cn_reply->ack = 0; /* not used here. */ + cn_reply->len = sizeof(struct drbd_nl_cfg_reply) + + (int)((char *)tl - (char *)reply->tag_list); + cn_reply->flags = 0; + + reply->packet_type = P_get_state; + reply->minor = mdev_to_minor(mdev); + reply->ret_code = NoError; + + TRACE(TraceTypeNl, TraceLvlSummary, nl_trace_reply(cn_reply);); + + cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL); +} + +void drbd_bcast_ev_helper(struct drbd_conf *mdev, char *helper_name) +{ + char buffer[sizeof(struct cn_msg)+ + sizeof(struct drbd_nl_cfg_reply)+ + sizeof(struct call_helper_tag_len_struct)+ + sizeof(short int)]; + struct cn_msg *cn_reply = (struct cn_msg *) buffer; + struct drbd_nl_cfg_reply *reply = + (struct drbd_nl_cfg_reply *)cn_reply->data; + unsigned short *tl = reply->tag_list; + int str_len; + + /* DRBD_WARN("drbd_bcast_state() got called\n"); */ + + str_len = strlen(helper_name)+1; + *tl++ = T_helper; + *tl++ = str_len; + memcpy(tl, helper_name, str_len); + tl = (unsigned short *)((char *)tl + str_len); + *tl++ = TT_END; /* Close the tag list */ + + cn_reply->id.idx = CN_IDX_DRBD; + cn_reply->id.val = CN_VAL_DRBD; + + cn_reply->seq = atomic_add_return(1, &drbd_nl_seq); + cn_reply->ack = 0; /* not used here. */ + cn_reply->len = sizeof(struct drbd_nl_cfg_reply) + + (int)((char *)tl - (char *)reply->tag_list); + cn_reply->flags = 0; + + reply->packet_type = P_call_helper; + reply->minor = mdev_to_minor(mdev); + reply->ret_code = NoError; + + TRACE(TraceTypeNl, TraceLvlSummary, nl_trace_reply(cn_reply);); + + cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL); +} + +void drbd_bcast_ee(struct drbd_conf *mdev, + const char *reason, const int dgs, + const char* seen_hash, const char* calc_hash, + const struct Tl_epoch_entry* e) +{ + struct cn_msg *cn_reply; + struct drbd_nl_cfg_reply *reply; + struct bio_vec *bvec; + unsigned short *tl; + int i; + + if (!e) + return; + if (!reason || !reason[0]) + return; + + /* aparently we have to memcpy twice, first to prepare the data for the + * struct cn_msg, then within cn_netlink_send from the cn_msg to the + * netlink skb. */ + cn_reply = kmalloc( + sizeof(struct cn_msg)+ + sizeof(struct drbd_nl_cfg_reply)+ + sizeof(struct dump_ee_tag_len_struct)+ + sizeof(short int) + , GFP_KERNEL); + + if (!cn_reply) { + ERR("could not kmalloc buffer for drbd_bcast_ee, sector %llu, size %u\n", + (unsigned long long)e->sector, e->size); + return; + } + + reply = (struct drbd_nl_cfg_reply*)cn_reply->data; + tl = reply->tag_list; + + tl = tl_add_str(tl, T_dump_ee_reason, reason); + tl = tl_add_blob(tl, T_seen_digest, seen_hash, dgs); + tl = tl_add_blob(tl, T_calc_digest, calc_hash, dgs); + tl = tl_add_int(tl, T_ee_sector, &e->sector); + tl = tl_add_int(tl, T_ee_block_id, &e->block_id); + + *tl++ = T_ee_data; + *tl++ = e->size; + + __bio_for_each_segment(bvec, e->private_bio, i, 0) { + void *d = kmap(bvec->bv_page); + memcpy(tl, d + bvec->bv_offset, bvec->bv_len); + kunmap(bvec->bv_page); + tl=(unsigned short*)((char*)tl + bvec->bv_len); + } + *tl++ = TT_END; /* Close the tag list */ + + cn_reply->id.idx = CN_IDX_DRBD; + cn_reply->id.val = CN_VAL_DRBD; + + cn_reply->seq = atomic_add_return(1,&drbd_nl_seq); + cn_reply->ack = 0; // not used here. + cn_reply->len = sizeof(struct drbd_nl_cfg_reply) + + (int)((char*)tl - (char*)reply->tag_list); + cn_reply->flags = 0; + + reply->packet_type = P_dump_ee; + reply->minor = mdev_to_minor(mdev); + reply->ret_code = NoError; + + TRACE(TraceTypeNl, TraceLvlSummary, nl_trace_reply(cn_reply);); + + cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL); + kfree(cn_reply); +} + +void drbd_bcast_sync_progress(struct drbd_conf *mdev) +{ + char buffer[sizeof(struct cn_msg)+ + sizeof(struct drbd_nl_cfg_reply)+ + sizeof(struct sync_progress_tag_len_struct)+ + sizeof(short int)]; + struct cn_msg *cn_reply = (struct cn_msg *) buffer; + struct drbd_nl_cfg_reply *reply = + (struct drbd_nl_cfg_reply *)cn_reply->data; + unsigned short *tl = reply->tag_list; + unsigned long rs_left; + unsigned int res; + + /* no local ref, no bitmap, no syncer progress, no broadcast. */ + if (!inc_local(mdev)) + return; + drbd_get_syncer_progress(mdev, &rs_left, &res); + dec_local(mdev); + + *tl++ = T_sync_progress; + *tl++ = sizeof(int); + memcpy(tl, &res, sizeof(int)); + tl = (unsigned short *)((char *)tl + sizeof(int)); + *tl++ = TT_END; /* Close the tag list */ + + cn_reply->id.idx = CN_IDX_DRBD; + cn_reply->id.val = CN_VAL_DRBD; + + cn_reply->seq = atomic_add_return(1, &drbd_nl_seq); + cn_reply->ack = 0; /* not used here. */ + cn_reply->len = sizeof(struct drbd_nl_cfg_reply) + + (int)((char *)tl - (char *)reply->tag_list); + cn_reply->flags = 0; + + reply->packet_type = P_sync_progress; + reply->minor = mdev_to_minor(mdev); + reply->ret_code = NoError; + + TRACE(TraceTypeNl, TraceLvlSummary, nl_trace_reply(cn_reply);); + + cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL); +} + +int __init drbd_nl_init(void) +{ + static struct cb_id cn_id_drbd = { CN_IDX_DRBD, CN_VAL_DRBD }; + int err; + + err = cn_add_callback(&cn_id_drbd, "cn_drbd", &drbd_connector_callback); + if (err) { + printk(KERN_ERR "drbd: cn_drbd failed to register\n"); + return err; + } + + return 0; +} + +void drbd_nl_cleanup(void) +{ + static struct cb_id cn_id_drbd = { CN_IDX_DRBD, CN_VAL_DRBD }; + + cn_del_callback(&cn_id_drbd); +} + +void drbd_nl_send_reply( struct cn_msg *req, + int ret_code) +{ + char buffer[sizeof(struct cn_msg)+sizeof(struct drbd_nl_cfg_reply)]; + struct cn_msg *cn_reply = (struct cn_msg *) buffer; + struct drbd_nl_cfg_reply *reply = + (struct drbd_nl_cfg_reply *)cn_reply->data; + int rr; + + cn_reply->id = req->id; + + cn_reply->seq = req->seq; + cn_reply->ack = req->ack + 1; + cn_reply->len = sizeof(struct drbd_nl_cfg_reply); + cn_reply->flags = 0; + + reply->minor = ((struct drbd_nl_cfg_req *)req->data)->drbd_minor; + reply->ret_code = ret_code; + + TRACE(TraceTypeNl, TraceLvlSummary, nl_trace_reply(cn_reply);); + + rr = cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL); + if (rr && rr != -ESRCH) + printk(KERN_INFO "drbd: cn_netlink_send()=%d\n", rr); +} + --- linux-2.6.27.orig/ubuntu/drbd/drbd_bitmap.c +++ linux-2.6.27/ubuntu/drbd/drbd_bitmap.c @@ -0,0 +1,1004 @@ +/* +-*- linux-c -*- + drbd_bitmap.c + Kernel module for 2.6.x Kernels + + This file is part of DRBD by Philipp Reisner and Lars Ellenberg. + + Copyright (C) 2004-2008, LINBIT Information Technologies GmbH. + Copyright (C) 2004-2008, Philipp Reisner . + Copyright (C) 2004-2008, Lars Ellenberg . + + drbd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + drbd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with drbd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include "drbd_int.h" + +/* OPAQUE outside this file! + * interface defined in drbd_int.h + + * convetion: + * function name drbd_bm_... => used elsewhere, "public". + * function name bm_... => internal to implementation, "private". + + * Note that since find_first_bit returns int, at the current granularity of + * the bitmap (4KB per byte), this implementation "only" supports up to + * 1<<(32+12) == 16 TB... + * other shortcomings in the meta data area may reduce this even further. + * + * we will eventually change the implementation to not allways hold the full + * bitmap in memory, but only some 'lru_cache' of the on disk bitmap. + + * THINK + * I'm not yet sure whether this file should be bits only, + * or wether I want it to do all the sector<->bit calculation in here. + */ + +/* + * NOTE + * Access to the *bm is protected by bm_lock. + * It is safe to read the other members within the lock. + * + * drbd_bm_set_bits is called from bio_endio callbacks, + * We may be called with irq already disabled, + * so we need spin_lock_irqsave(). + * FIXME + * for performance reasons, when we _know_ we have irq disabled, we should + * probably introduce some _in_irq variants, so we know to only spin_lock(). + * + * FIXME + * Actually you need to serialize all resize operations. + * but then, resize is a drbd state change, and it should be serialized + * already. Unfortunately it is not (yet), so two concurrent resizes, like + * attach storage (drbdsetup) and receive the peers size (drbd receiver) + * may eventually blow things up. + * Therefore, + * you may only change the other members when holding + * the bm_change mutex _and_ the bm_lock. + * thus reading them holding either is safe. + * this is sort of overkill, but I rather do it right + * than have two resize operations interfere somewhen. + */ +struct drbd_bitmap { + unsigned long *bm; + spinlock_t bm_lock; + /* WARNING unsigned long bm_fo and friends: + * 32bit number of bit offset is just enough for 512 MB bitmap. + * it will blow up if we make the bitmap bigger... + * not that it makes much sense to have a bitmap that large, + * rather change the granularity to 16k or 64k or something. + * (that implies other problems, however...) + */ + unsigned long bm_fo; /* next offset for drbd_bm_find_next */ + unsigned long bm_set; /* nr of set bits; THINK maybe atomic_t? */ + unsigned long bm_bits; + size_t bm_words; + sector_t bm_dev_capacity; + struct semaphore bm_change; /* serializes resize operations */ + + atomic_t bm_async_io; + wait_queue_head_t bm_io_wait; + + unsigned long bm_flags; + + /* debugging aid, in case we are still racy somewhere */ + unsigned long bm_line; + char *bm_file; +}; + +/* definition of bits in bm_flags */ +#define BM_LOCKED 0 +#define BM_MD_IO_ERROR (BITS_PER_LONG-1) /* 31? 63? */ + +void __drbd_bm_lock(struct drbd_conf *mdev, char *file, int line) +{ + struct drbd_bitmap *b = mdev->bitmap; + + spin_lock_irq(&b->bm_lock); + if (!__test_and_set_bit(BM_LOCKED,&b->bm_flags)) { + b->bm_file = file; + b->bm_line = line; + } else if (DRBD_ratelimit(5*HZ,5)) { + ERR("%s:%d: bitmap already locked by %s:%lu\n", + file, line, b->bm_file,b->bm_line); + /* + dump_stack(); + ERR("This is no oops, but debug stack trace only.\n"); + ERR("If you get this often, or in reproducable situations, " + "notify \n"); + */ + } + spin_unlock_irq(&b->bm_lock); +} + +void drbd_bm_unlock(struct drbd_conf *mdev) +{ + struct drbd_bitmap *b = mdev->bitmap; + spin_lock_irq(&b->bm_lock); + if (!__test_and_clear_bit(BM_LOCKED,&mdev->bitmap->bm_flags)) { + ERR("bitmap not locked in bm_unlock\n"); + } else { + /* FIXME if we got a "is already locked" previously, + * we unlock here even though we actually MUST NOT do so... */ + b->bm_file = NULL; + b->bm_line = -1; + } + spin_unlock_irq(&b->bm_lock); +} + +#if DUMP_MD >= 3 +/* debugging aid */ +void bm_end_info(struct drbd_conf *mdev, const char *where) +{ + struct drbd_bitmap *b = mdev->bitmap; + size_t w = (b->bm_bits-1) >> LN2_BPL; + + INFO("%s: bm_set=%lu\n", where, b->bm_set); + INFO("bm[%d]=0x%lX\n", w, b->bm[w]); + w++; + + if (w < b->bm_words) { + D_ASSERT(w == b->bm_words -1); + INFO("bm[%d]=0x%lX\n", w, b->bm[w]); + } +} +#else +#define bm_end_info(ignored...) ((void)(0)) +#endif + +/* long word offset of _bitmap_ sector */ +#define S2W(s) ((s)<<(BM_EXT_SIZE_B-BM_BLOCK_SIZE_B-LN2_BPL)) + +/* + * actually most functions herein should take a struct drbd_bitmap*, not a + * struct drbd_conf*, but for the debug macros I like to have the mdev around + * to be able to report device specific. + */ + +/* FIXME TODO sometimes I use "int offset" as index into the bitmap. + * since we currently are LIMITED to (128<<11)-64-8 sectors of bitmap, + * this is ok [as long as we dont run on a 24 bit arch :)]. + * But it is NOT strictly ok. + */ + +/* + * called on driver init only. TODO call when a device is created. + * allocates the drbd_bitmap, and stores it in mdev->bitmap. + */ +int drbd_bm_init(struct drbd_conf *mdev) +{ + struct drbd_bitmap *b = mdev->bitmap; + WARN_ON(b != NULL); + b = kzalloc(sizeof(struct drbd_bitmap), GFP_KERNEL); + if (!b) + return -ENOMEM; + spin_lock_init(&b->bm_lock); + init_MUTEX(&b->bm_change); + init_waitqueue_head(&b->bm_io_wait); + + mdev->bitmap = b; + + return 0; +} + +sector_t drbd_bm_capacity(struct drbd_conf *mdev) +{ + ERR_IF(!mdev->bitmap) return 0; + return mdev->bitmap->bm_dev_capacity; +} + +/* called on driver unload. TODO: call when a device is destroyed. + */ +void drbd_bm_cleanup(struct drbd_conf *mdev) +{ + ERR_IF (!mdev->bitmap) return; + /* FIXME I think we should explicitly change the device size to zero + * before this... + * + WARN_ON(mdev->bitmap->bm); + */ + vfree(mdev->bitmap->bm); + kfree(mdev->bitmap); + mdev->bitmap = NULL; +} + +/* + * since (b->bm_bits % BITS_PER_LONG) != 0, + * this masks out the remaining bits. + * Rerturns the number of bits cleared. + */ +STATIC int bm_clear_surplus(struct drbd_bitmap *b) +{ + const unsigned long mask = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) -1; + size_t w = b->bm_bits >> LN2_BPL; + int cleared = 0; + + if (w < b->bm_words) { + cleared = hweight_long(b->bm[w] & ~mask); + b->bm[w++] &= mask; + } + + if (w < b->bm_words) { + cleared += hweight_long(b->bm[w]); + b->bm[w++] = 0; + } + + return cleared; +} + +STATIC void bm_set_surplus(struct drbd_bitmap *b) +{ + const unsigned long mask = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) -1; + size_t w = b->bm_bits >> LN2_BPL; + + if (w < b->bm_words) + b->bm[w++] |= ~mask; + + if (w < b->bm_words) + b->bm[w++] = ~(0UL); +} + +STATIC unsigned long __bm_count_bits(struct drbd_bitmap *b, const int swap_endian) +{ + unsigned long *bm = b->bm; + unsigned long *ep = b->bm + b->bm_words; + unsigned long bits = 0; + + while ( bm < ep ) { +#ifndef __LITTLE_ENDIAN + if (swap_endian) *bm = lel_to_cpu(*bm); +#endif + bits += hweight_long(*bm++); + } + + return bits; +} + +static inline unsigned long bm_count_bits(struct drbd_bitmap *b) +{ + return __bm_count_bits(b,0); +} + +static inline unsigned long bm_count_bits_swap_endian(struct drbd_bitmap *b) +{ + return __bm_count_bits(b,1); +} + + +void _drbd_bm_recount_bits(struct drbd_conf *mdev, char* file, int line) +{ + struct drbd_bitmap *b = mdev->bitmap; + unsigned long flags, bits; + + ERR_IF(!b) return; + + spin_lock_irqsave(&b->bm_lock, flags); + bits = bm_count_bits(b); + if (bits != b->bm_set) { + ERR("bm_set was %lu, corrected to %lu. %s:%d\n", + b->bm_set, bits, file, line); + b->bm_set = bits; + } + spin_unlock_irqrestore(&b->bm_lock, flags); +} + +#define BM_SECTORS_PER_BIT (BM_BLOCK_SIZE/512) + +/* + * make sure the bitmap has enough room for the attached storage, + * if neccessary, resize. + * called whenever we may have changed the device size. + * returns -ENOMEM if we could not allocate enough memory, 0 on success. + * In case this is actually a resize, we copy the old bitmap into the new one. + * Otherwise, the bitmap is initiallized to all bits set. + */ +int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity) +{ + struct drbd_bitmap *b = mdev->bitmap; + unsigned long bits, bytes, words, *nbm, *obm = NULL; + int err = 0, growing; + + ERR_IF(!b) return -ENOMEM; + + ERR_IF (down_trylock(&b->bm_change)) { + down(&b->bm_change); + } + + INFO("drbd_bm_resize called with capacity == %llu\n", + (unsigned long long)capacity); + + if (capacity == b->bm_dev_capacity) + goto out; + + if (capacity == 0) { + spin_lock_irq(&b->bm_lock); + obm = b->bm; + b->bm = NULL; + b->bm_fo = + b->bm_set = + b->bm_bits = + b->bm_words = + b->bm_dev_capacity = 0; + spin_unlock_irq(&b->bm_lock); + goto free_obm; + } else { + bits = BM_SECT_TO_BIT(ALIGN(capacity, BM_SECTORS_PER_BIT)); + + /* if we would use + words = ALIGN(bits,BITS_PER_LONG) >> LN2_BPL; + a 32bit host could present the wrong number of words + to a 64bit host. + */ + words = ALIGN(bits, 64) >> LN2_BPL; + + if (inc_local(mdev)) { + D_ASSERT((u64)bits <= (((u64)mdev->bc->md.md_size_sect-MD_BM_OFFSET) << 12)); + dec_local(mdev); + } + + if (words == b->bm_words) { + /* optimize: capacity has changed, + * but only within one long word worth of bits. + * just update the bm_dev_capacity and bm_bits members. + */ + spin_lock_irq(&b->bm_lock); + b->bm_bits = bits; + b->bm_dev_capacity = capacity; + b->bm_set -= bm_clear_surplus(b); + bm_end_info(mdev, __FUNCTION__ ); + spin_unlock_irq(&b->bm_lock); + goto out; + } else { + /* one extra long to catch off by one errors */ + bytes = (words+1)*sizeof(long); + nbm = vmalloc(bytes); + if (!nbm) { + ERR("bitmap: failed to vmalloc %lu bytes\n", + bytes); + err = -ENOMEM; + goto out; + } + } + spin_lock_irq(&b->bm_lock); + obm = b->bm; + /* brgs. move several MB within spinlock... + * FIXME this should go into userspace! */ + if (obm) { + bm_set_surplus(b); + D_ASSERT(b->bm[b->bm_words] == DRBD_MAGIC); + memcpy(nbm, obm, min_t(size_t, b->bm_words, words) + *sizeof(long)); + } + growing = words > b->bm_words; + if (growing) { + /* set all newly allocated bits + * start at -1, just to be sure. */ + memset( nbm + (b->bm_words?:1)-1 , 0xff, + (words - ((b->bm_words?:1)-1)) * sizeof(long) ); + b->bm_set += bits - b->bm_bits; + } + nbm[words] = DRBD_MAGIC; + b->bm = nbm; + b->bm_bits = bits; + b->bm_words = words; + b->bm_dev_capacity = capacity; + bm_clear_surplus(b); + if (!growing) + b->bm_set = bm_count_bits(b); + bm_end_info(mdev, __FUNCTION__ ); + spin_unlock_irq(&b->bm_lock); + INFO("resync bitmap: bits=%lu words=%lu\n", bits, words); + } + free_obm: + vfree(obm); /* vfree(NULL) is noop */ + out: + up(&b->bm_change); + return err; +} + +/* inherently racy: + * if not protected by other means, return value may be out of date when + * leaving this function... + * we still need to lock it, since it is important that this returns + * bm_set == 0 precisely. + * + * maybe bm_set should be atomic_t ? + */ +unsigned long drbd_bm_total_weight(struct drbd_conf *mdev) +{ + struct drbd_bitmap *b = mdev->bitmap; + unsigned long s; + unsigned long flags; + + ERR_IF(!b) return 0; + + spin_lock_irqsave(&b->bm_lock, flags); + s = b->bm_set; + spin_unlock_irqrestore(&b->bm_lock, flags); + + return s; +} + +size_t drbd_bm_words(struct drbd_conf *mdev) +{ + struct drbd_bitmap *b = mdev->bitmap; + ERR_IF(!b) return 0; + return b->bm_words; +} + +unsigned long drbd_bm_bits(struct drbd_conf *mdev) +{ + struct drbd_bitmap *b = mdev->bitmap; + ERR_IF(!b) return 0; + + return b->bm_bits; +} + + +/* merge number words from buffer into the bitmap starting at offset. + * buffer[i] is expected to be little endian unsigned long. + */ +void drbd_bm_merge_lel( struct drbd_conf *mdev, size_t offset, size_t number, + unsigned long *buffer ) +{ + struct drbd_bitmap *b = mdev->bitmap; + unsigned long *bm; + unsigned long word, bits; + size_t n = number; + + if (number == 0) + return; + ERR_IF(!b) return; + ERR_IF(!b->bm) return; + WARN_ON(offset >= b->bm_words); + WARN_ON(offset+number > b->bm_words); + WARN_ON(number > PAGE_SIZE/sizeof(long)); + + spin_lock_irq(&b->bm_lock); + bm = b->bm + offset; + while (n--) { + bits = hweight_long(*bm); + word = *bm | lel_to_cpu(*buffer++); + *bm++ = word; + b->bm_set += hweight_long(word) - bits; + } + /* with 32bit <-> 64bit cross-platform connect + * this is only correct for current usage, + * where we _know_ that we are 64 bit aligned, + * and know that this function is used in this way, too... + */ + if (offset+number == b->bm_words) { + b->bm_set -= bm_clear_surplus(b); + bm_end_info(mdev, __FUNCTION__ ); + } + spin_unlock_irq(&b->bm_lock); +} + +/* copy number words from the bitmap starting at offset into the buffer. + * buffer[i] will be little endian unsigned long. + */ +void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, size_t number, + unsigned long *buffer ) +{ + struct drbd_bitmap *b = mdev->bitmap; + unsigned long *bm; + + if (number == 0) + return; + ERR_IF(!b) return; + ERR_IF(!b->bm) return; + if ( (offset >= b->bm_words) || + (offset+number > b->bm_words) || + (number > PAGE_SIZE/sizeof(long)) || + (number <= 0) ) { + /* yes, there is "%z", but that gives compiler warnings... */ + ERR("offset=%lu number=%lu bm_words=%lu\n", + (unsigned long) offset, + (unsigned long) number, + (unsigned long) b->bm_words); + return; + } + + spin_lock_irq(&b->bm_lock); + bm = b->bm + offset; + while (number--) *buffer++ = cpu_to_lel(*bm++); + spin_unlock_irq(&b->bm_lock); +} + +/* set all bits in the bitmap */ +void drbd_bm_set_all(struct drbd_conf *mdev) +{ + struct drbd_bitmap *b = mdev->bitmap; + ERR_IF(!b) return; + ERR_IF(!b->bm) return; + + spin_lock_irq(&b->bm_lock); + memset(b->bm, 0xff, b->bm_words*sizeof(long)); + bm_clear_surplus(b); + b->bm_set = b->bm_bits; + spin_unlock_irq(&b->bm_lock); +} + +static BIO_ENDIO_TYPE bm_async_io_complete BIO_ENDIO_ARGS(struct bio *bio, int error) +{ + struct drbd_bitmap *b = bio->bi_private; + int uptodate = bio_flagged(bio, BIO_UPTODATE); + + BIO_ENDIO_FN_START; + /* strange behaviour of some lower level drivers... + * fail the request by clearing the uptodate flag, + * but do not return any error?! + * do we want to DRBD_WARN() on this? */ + if (!error && !uptodate) + error = -EIO; + + if (error) { + /* doh. what now? + * for now, set all bits, and flag MD_IO_ERROR + */ + /* FIXME kmap_atomic memset etc. pp. */ + __set_bit(BM_MD_IO_ERROR, &b->bm_flags); + } + if (atomic_dec_and_test(&b->bm_async_io)) + wake_up(&b->bm_io_wait); + + bio_put(bio); + + BIO_ENDIO_FN_RETURN; +} + +STATIC void bm_page_io_async(struct drbd_conf *mdev, struct drbd_bitmap *b, int page_nr, int rw) __must_hold(local) +{ + /* we are process context. we always get a bio */ + /* THINK: do we need GFP_NOIO here? */ + struct bio *bio = bio_alloc(GFP_KERNEL, 1); + struct page *page = vmalloc_to_page((char *)(b->bm) + + (PAGE_SIZE*page_nr)); + unsigned int len; + sector_t on_disk_sector = + mdev->bc->md.md_offset + mdev->bc->md.bm_offset; + on_disk_sector += ((sector_t)page_nr) << (PAGE_SHIFT-9); + + /* this might happen with very small + * flexible external meta data device */ + len = min_t(unsigned int, PAGE_SIZE, + (drbd_md_last_sector(mdev->bc) - on_disk_sector + 1)<<9); + + D_DUMPLU(on_disk_sector); + D_DUMPI(len); + + bio->bi_bdev = mdev->bc->md_bdev; + bio->bi_sector = on_disk_sector; + bio_add_page(bio, page, len, 0); + bio->bi_private = b; + bio->bi_end_io = bm_async_io_complete; + + if (FAULT_ACTIVE(mdev, (rw&WRITE)?DRBD_FAULT_MD_WR:DRBD_FAULT_MD_RD)) { + bio->bi_rw |= rw; + bio_endio(bio, -EIO); + } else { + submit_bio(rw, bio); + } +} + +# if defined(__LITTLE_ENDIAN) + /* nothing to do, on disk == in memory */ +# define bm_cpu_to_lel(x) ((void)0) +# else +void bm_cpu_to_lel(struct drbd_bitmap *b) +{ + /* need to cpu_to_lel all the pages ... + * this may be optimized by using + * cpu_to_lel(-1) == -1 and cpu_to_lel(0) == 0; + * the following is still not optimal, but better than nothing */ + const unsigned long *end = b->bm+b->bm_words; + unsigned long *bm; + if (b->bm_set == 0) { + /* no page at all; avoid swap if all is 0 */ + return; + } else if (b->bm_set == b->bm_bits) { + /* only the last words */ + bm = end-2; + } else { + /* all pages */ + bm = b->bm; + } + for (; bm < end; bm++) + *bm = cpu_to_lel(*bm); +} +# endif +/* lel_to_cpu == cpu_to_lel */ +# define bm_lel_to_cpu(x) bm_cpu_to_lel(x) + +/* + * bm_rw: read/write the whole bitmap from/to its on disk location. + */ +STATIC int bm_rw(struct drbd_conf *mdev, int rw) __must_hold(local) +{ + struct drbd_bitmap *b = mdev->bitmap; + /* sector_t sector; */ + int bm_words, num_pages, i; + unsigned long now; + char ppb[10]; + int err = 0; + + bm_words = drbd_bm_words(mdev); + num_pages = (bm_words*sizeof(long) + PAGE_SIZE-1) >> PAGE_SHIFT; + + /* OK, I manipulate the bitmap low level, + * and I expect to be the exclusive user. + * If not, I am really in a bad mood... + * to catch such bugs early, make all people who want to access the + * bitmap while I read/write it dereference a NULL pointer :-> + */ + mdev->bitmap = NULL; + + /* on disk bitmap is little endian */ + if (rw == WRITE) + bm_cpu_to_lel(b); + + now = jiffies; + atomic_set(&b->bm_async_io, num_pages); + __clear_bit(BM_MD_IO_ERROR, &b->bm_flags); + + /* let the layers below us try to merge these bios... */ + for (i = 0; i < num_pages; i++) + bm_page_io_async(mdev, b, i, rw); + + drbd_blk_run_queue(bdev_get_queue(mdev->bc->md_bdev)); + wait_event(b->bm_io_wait, atomic_read(&b->bm_async_io) == 0); + INFO("%s of bitmap took %lu jiffies\n", + rw == READ ? "reading" : "writing", jiffies - now); + + if (test_bit(BM_MD_IO_ERROR, &b->bm_flags)) { + ALERT("we had at least one MD IO ERROR during bitmap IO\n"); + drbd_chk_io_error(mdev, 1, TRUE); + drbd_io_error(mdev, TRUE); + err = -EIO; + } + + now = jiffies; + if (rw == WRITE) { + /* swap back endianness */ + bm_lel_to_cpu(b); + /* flush bitmap to stable storage */ + if (!test_bit(MD_NO_BARRIER,&mdev->flags)) + blkdev_issue_flush(mdev->bc->md_bdev, NULL); + } else /* rw == READ */ { + /* just read, if neccessary adjust endianness */ + b->bm_set = bm_count_bits_swap_endian(b); + INFO("recounting of set bits took additional %lu jiffies\n", + jiffies - now); + } + now = b->bm_set; + + /* ok, done, + * now it is visible again + */ + + mdev->bitmap = b; + + INFO("%s (%lu bits) marked out-of-sync by on disk bit-map.\n", + ppsize(ppb, now << (BM_BLOCK_SIZE_B-10)), now); + + return err; +} + +/** + * drbd_bm_read: Read the whole bitmap from its on disk location. + * + * currently only called from "drbd_nl_disk_conf" + */ +int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local) +{ + struct drbd_bitmap *b = mdev->bitmap; + int err = 0; + + if (b->bm) { + /* bitmap size > 0 */ + err = bm_rw(mdev, READ); + + if (err == 0) + b->bm[b->bm_words] = DRBD_MAGIC; + } + + return err; +} + +/** + * drbd_bm_write: Write the whole bitmap to its on disk location. + * + * called at various occasions. + */ +int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local) +{ + return bm_rw(mdev, WRITE); +} + +/** + * drbd_bm_write_sect: Writes a 512 byte piece of the bitmap to its + * on disk location. On disk bitmap is little endian. + * + * @enr: The _sector_ offset from the start of the bitmap. + * + */ +int drbd_bm_write_sect(struct drbd_conf *mdev, unsigned long enr) __must_hold(local) +{ + sector_t on_disk_sector = enr + mdev->bc->md.md_offset + + mdev->bc->md.bm_offset; + int bm_words, num_words, offset; + int err = 0; + + down(&mdev->md_io_mutex); + bm_words = drbd_bm_words(mdev); + offset = S2W(enr); /* word offset into bitmap */ + num_words = min(S2W(1), bm_words - offset); +#if DUMP_MD >= 3 + INFO("write_sect: sector=%lu offset=%u num_words=%u\n", + enr, offset, num_words); +#endif + if (num_words < S2W(1)) + memset(page_address(mdev->md_io_page), 0, MD_HARDSECT); + drbd_bm_get_lel( mdev, offset, num_words, + page_address(mdev->md_io_page) ); + if (!drbd_md_sync_page_io(mdev, mdev->bc, on_disk_sector, WRITE)) { + int i; + err = -EIO; + ERR( "IO ERROR writing bitmap sector %lu " + "(meta-disk sector %llus)\n", + enr, (unsigned long long)on_disk_sector ); + drbd_chk_io_error(mdev, 1, TRUE); + drbd_io_error(mdev, TRUE); + for (i = 0; i < AL_EXT_PER_BM_SECT; i++) + drbd_bm_ALe_set_all(mdev, enr*AL_EXT_PER_BM_SECT+i); + } + mdev->bm_writ_cnt++; + up(&mdev->md_io_mutex); + return err; +} + +void drbd_bm_reset_find(struct drbd_conf *mdev) +{ + struct drbd_bitmap *b = mdev->bitmap; + + ERR_IF(!b) return; + + spin_lock_irq(&b->bm_lock); + b->bm_fo = 0; + spin_unlock_irq(&b->bm_lock); + +} + +/* NOTE + * find_first_bit returns int, we return unsigned long. + * should not make much difference anyways, but ... + * this returns a bit number, NOT a sector! + */ +unsigned long drbd_bm_find_next(struct drbd_conf *mdev) +{ + struct drbd_bitmap *b = mdev->bitmap; + unsigned long i = -1UL; + + ERR_IF(!b) return i; + ERR_IF(!b->bm) return i; + + spin_lock_irq(&b->bm_lock); + if (b->bm_fo < b->bm_bits) + i = find_next_bit(b->bm, b->bm_bits, b->bm_fo); + else if (b->bm_fo > b->bm_bits) + ERR("bm_fo=%lu bm_bits=%lu\n", b->bm_fo, b->bm_bits); + + if (i >= b->bm_bits) { + i = -1UL; + /* leave b->bm_fo unchanged. */ + } else { + b->bm_fo = i+1; + } + spin_unlock_irq(&b->bm_lock); + return i; +} + +void drbd_bm_set_find(struct drbd_conf *mdev, unsigned long i) +{ + struct drbd_bitmap *b = mdev->bitmap; + + spin_lock_irq(&b->bm_lock); + + b->bm_fo = min_t(unsigned long, i, b->bm_bits); + + spin_unlock_irq(&b->bm_lock); +} + + +int drbd_bm_rs_done(struct drbd_conf *mdev) +{ + return (mdev->bitmap->bm_fo >= mdev->bitmap->bm_bits); +} + +/* returns number of bits actually changed. + * for val != 0, we change 0 -> 1, return code positiv + * for val == 0, we change 1 -> 0, return code negative + * wants bitnr, not sector */ +static int bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, + const unsigned long e, int val) +{ + unsigned long flags; + struct drbd_bitmap *b = mdev->bitmap; + unsigned long bitnr; + int c = 0; + ERR_IF(!b) return 1; + ERR_IF(!b->bm) return 1; + + spin_lock_irqsave(&b->bm_lock,flags); + for (bitnr = s; bitnr <= e; bitnr++) { + ERR_IF (bitnr >= b->bm_bits) { + ERR("bitnr=%lu bm_bits=%lu\n", bitnr, b->bm_bits); + } else { + if (val) + c += (0 == __test_and_set_bit(bitnr, b->bm)); + else + c -= (0 != __test_and_clear_bit(bitnr, b->bm)); + } + } + b->bm_set += c; + spin_unlock_irqrestore(&b->bm_lock, flags); + return c; +} + +/* returns number of bits changed 0 -> 1 */ +int drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e) +{ + return bm_change_bits_to(mdev, s, e, 1); +} + +/* returns number of bits changed 1 -> 0 */ +int drbd_bm_clear_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e) +{ + return -bm_change_bits_to(mdev, s, e, 0); +} + +/* returns bit state + * wants bitnr, NOT sector. + * inherently racy... area needs to be locked by means of {al,rs}_lru + * 1 ... bit set + * 0 ... bit not set + * -1 ... first out of bounds access, stop testing for bits! + */ +int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr) +{ + unsigned long flags; + struct drbd_bitmap *b = mdev->bitmap; + int i; + ERR_IF(!b) return 0; + ERR_IF(!b->bm) return 0; + + spin_lock_irqsave(&b->bm_lock, flags); + if (bitnr < b->bm_bits) { + i = test_bit(bitnr, b->bm) ? 1 : 0; + } else if (bitnr == b->bm_bits) { + i = -1; + } else { /* (bitnr > b->bm_bits) */ + ERR("bitnr=%lu > bm_bits=%lu\n", bitnr, b->bm_bits); + i = 0; + } + + spin_unlock_irqrestore(&b->bm_lock, flags); + return i; +} + +/* returns number of bits set */ +int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e) +{ + unsigned long flags; + struct drbd_bitmap *b = mdev->bitmap; + unsigned long bitnr; + int c = 0; + + /* If this is called without a bitmap, that is a bug. But just to be + * robust in case we screwed up elsewhere, in that case pretend there + * was one dirty bit in the requested area, so we won't try to do a + * local read there (no bitmap probably implies no disk) */ + ERR_IF(!b) return 1; + ERR_IF(!b->bm) return 1; + + spin_lock_irqsave(&b->bm_lock,flags); + for (bitnr = s; bitnr <=e; bitnr++) { + ERR_IF (bitnr >= b->bm_bits) { + ERR("bitnr=%lu bm_bits=%lu\n",bitnr, b->bm_bits); + } else { + c += (0 != test_bit(bitnr, b->bm)); + } + } + spin_unlock_irqrestore(&b->bm_lock,flags); + return c; +} + + +/* inherently racy... + * return value may be already out-of-date when this function returns. + * but the general usage is that this is only use during a cstate when bits are + * only cleared, not set, and typically only care for the case when the return + * value is zero, or we already "locked" this "bitmap extent" by other means. + * + * enr is bm-extent number, since we chose to name one sector (512 bytes) + * worth of the bitmap a "bitmap extent". + * + * TODO + * I think since we use it like a reference count, we should use the real + * reference count of some bitmap extent element from some lru instead... + * + */ +int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr) +{ + struct drbd_bitmap *b = mdev->bitmap; + int count, s, e; + unsigned long flags; + + ERR_IF(!b) return 0; + ERR_IF(!b->bm) return 0; + spin_lock_irqsave(&b->bm_lock, flags); + + s = S2W(enr); + e = min((size_t)S2W(enr+1), b->bm_words); + count = 0; + if (s < b->bm_words) { + const unsigned long *w = b->bm+s; + int n = e-s; + while (n--) count += hweight_long(*w++); + } else { + ERR("start offset (%d) too large in drbd_bm_e_weight\n", s); + } + spin_unlock_irqrestore(&b->bm_lock, flags); +#if DUMP_MD >= 3 + INFO("enr=%lu weight=%d e=%d s=%d\n", enr, count, e, s); +#endif + return count; +} + +/* set all bits covered by the AL-extent al_enr */ +unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, unsigned long al_enr) +{ + struct drbd_bitmap *b = mdev->bitmap; + unsigned long weight; + int count, s, e; + ERR_IF(!b) return 0; + ERR_IF(!b->bm) return 0; + + spin_lock_irq(&b->bm_lock); + weight = b->bm_set; + + s = al_enr * BM_WORDS_PER_AL_EXT; + e = min_t(size_t, s + BM_WORDS_PER_AL_EXT, b->bm_words); + count = 0; + if (s < b->bm_words) { + const unsigned long *w = b->bm+s; + int n = e-s; + while (n--) count += hweight_long(*w++); + n = e-s; + memset(b->bm+s, -1, n*sizeof(long)); + b->bm_set += n*BITS_PER_LONG - count; + if (e == b->bm_words) + b->bm_set -= bm_clear_surplus(b); + } else { + ERR("start offset (%d) too large in drbd_bm_ALe_set_all\n", s); + } + weight = b->bm_set - weight; + spin_unlock_irq(&b->bm_lock); + return weight; +} --- linux-2.6.27.orig/ubuntu/drbd/Kconfig +++ linux-2.6.27/ubuntu/drbd/Kconfig @@ -0,0 +1,32 @@ +# +# DRBD device driver configuration +# +config BLK_DEV_DRBD + tristate "DRBD Distributed Replicated Block Device support" + select INET + select PROC_FS + select CONNECTOR + select CRYPTO + select CRYPTO_HMAC + ---help--- + DRBD is a block device which is designed to build high availability + clusters. This is done by mirroring a whole block device via (a + dedicated) network. You could see it as a network RAID 1. + + Each minor device has a state, which can be 'primary' or 'secondary'. + On the node with the primary device the application is supposed to + run and to access the device (/dev/drbdX). Every write is sent to the + local 'lower level block device' and via network to the node with the + device in 'secondary' state. + The secondary device simply writes the data to its lower level block + device. Currently no read-balancing via the network is done. + + DRBD can also be used with "shared-disk semantics" (primary-primary), + even though it is a "shared-nothing cluster". You'd need to use a + cluster file system on top of that for cache coherency. + + DRBD management is done through user-space tools. + For automatic failover you need a cluster manager (e.g. heartbeat). + See also: http://www.drbd.org/, http://www.linux-ha.org + + If unsure, say N. --- linux-2.6.27.orig/ubuntu/drbd/drbd_main.c +++ linux-2.6.27/ubuntu/drbd/drbd_main.c @@ -0,0 +1,3752 @@ +/* +-*- Linux-c -*- + drbd.c + Kernel module for 2.6.x Kernels + + This file is part of DRBD by Philipp Reisner and Lars Ellenberg. + + Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. + Copyright (C) 1999-2008, Philipp Reisner . + Copyright (C) 2002-2008, Lars Ellenberg . + + drbd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + drbd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with drbd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define __KERNEL_SYSCALLS__ +#include +#include + +#include +#include +#include "drbd_int.h" +#include "drbd_req.h" /* only for _req_mod in tl_release and tl_clear */ + +struct after_state_chg_work { + struct drbd_work w; + union drbd_state_t os; + union drbd_state_t ns; + enum chg_state_flags flags; + struct completion *done; +}; + +int drbdd_init(struct Drbd_thread *); +int drbd_worker(struct Drbd_thread *); +int drbd_asender(struct Drbd_thread *); + +int drbd_init(void); +int drbd_open(struct inode *inode, struct file *file); +int drbd_close(struct inode *inode, struct file *file); +int w_after_state_ch(struct drbd_conf *mdev, struct drbd_work *w, int unused); +static void after_state_ch(struct drbd_conf *mdev, union drbd_state_t os, + union drbd_state_t ns, enum chg_state_flags flags); +int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused); +void md_sync_timer_fn(unsigned long data); + +MODULE_AUTHOR("Philipp Reisner , " + "Lars Ellenberg "); +MODULE_DESCRIPTION("drbd - Distributed Replicated Block Device v" REL_VERSION); +MODULE_LICENSE("GPL"); +MODULE_PARM_DESC(minor_count, "Maximum number of drbd devices (1-255)"); +MODULE_ALIAS_BLOCKDEV_MAJOR(DRBD_MAJOR); + +#include +/* allow_open_on_secondary */ +MODULE_PARM_DESC(allow_oos, "DONT USE!"); +/* thanks to these macros, if compiled into the kernel (not-module), + * this becomes the boot parameter drbd.minor_count */ +module_param(minor_count, int,0444); +module_param(allow_oos, bool,0); + +#ifdef DRBD_ENABLE_FAULTS +int enable_faults; +int fault_rate; +static int fault_count; +int fault_devs; +/* bitmap of enabled faults */ +module_param(enable_faults, int, 0664); +/* fault rate % value - applies to all enabled faults */ +module_param(fault_rate, int, 0664); +/* count of faults inserted */ +module_param(fault_count, int, 0664); +/* bitmap of devices to insert faults on */ +module_param(fault_devs, int, 0644); +#endif + +/* module parameter, defined */ +int minor_count = 32; +int allow_oos; + +#ifdef ENABLE_DYNAMIC_TRACE +int trace_type; /* Bitmap of trace types to enable */ +int trace_level; /* Current trace level */ +int trace_devs; /* Bitmap of devices to trace */ +int proc_details; /* Detail level in proc drbd*/ + +module_param(trace_level, int, 0644); +module_param(trace_type, int, 0644); +module_param(trace_devs, int, 0644); +module_param(proc_details, int, 0644); +#endif + +/* Module parameter for setting the user mode helper program + * to run. Default is /sbin/drbdadm */ +char usermode_helper[80] = "/sbin/drbdadm"; + +module_param_string(usermode_helper, usermode_helper, sizeof(usermode_helper), 0644); + +/* in 2.6.x, our device mapping and config info contains our virtual gendisks + * as member "struct gendisk *vdisk;" + */ +struct drbd_conf **minor_table; + +struct kmem_cache *drbd_request_cache; +struct kmem_cache *drbd_ee_cache; +mempool_t *drbd_request_mempool; +mempool_t *drbd_ee_mempool; + +/* I do not use a standard mempool, because: + 1) I want to hand out the preallocated objects first. + 2) I want to be able to interrupt sleeping allocation with a signal. + Note: This is a single linked list, the next pointer is the private + member of struct page. + */ +struct page *drbd_pp_pool; +spinlock_t drbd_pp_lock; +int drbd_pp_vacant; +wait_queue_head_t drbd_pp_wait; + +STATIC struct block_device_operations drbd_ops = { + .owner = THIS_MODULE, + .open = drbd_open, + .release = drbd_close, +}; + +#define ARRY_SIZE(A) (sizeof(A)/sizeof(A[0])) + +#ifdef __CHECKER__ +/* When checking with sparse, and this is an inline function, sparse will + give tons of false positives. When this is a real functions sparse works. + */ +int _inc_local_if_state(struct drbd_conf* mdev, enum drbd_disk_state mins) +{ + int io_allowed; + + atomic_inc(&mdev->local_cnt); + io_allowed = (mdev->state.disk >= mins ); + if( !io_allowed ) { + if(atomic_dec_and_test(&mdev->local_cnt)) + wake_up(&mdev->misc_wait); + } + return io_allowed; +} + +#endif + +/************************* The transfer log start */ +STATIC int tl_init(struct drbd_conf *mdev) +{ + struct drbd_barrier *b; + + b = kmalloc(sizeof(struct drbd_barrier), GFP_KERNEL); + if (!b) + return 0; + INIT_LIST_HEAD(&b->requests); + INIT_LIST_HEAD(&b->w.list); + b->next = NULL; + b->br_number = 4711; + b->n_req = 0; + b->w.cb = NULL; /* if this is != NULL, we need to dec_ap_pending in tl_clear */ + + mdev->oldest_barrier = b; + mdev->newest_barrier = b; + + mdev->tl_hash = NULL; + mdev->tl_hash_s = 0; + + return 1; +} + +STATIC void tl_cleanup(struct drbd_conf *mdev) +{ + D_ASSERT(mdev->oldest_barrier == mdev->newest_barrier); + kfree(mdev->oldest_barrier); + kfree(mdev->unused_spare_barrier); + kfree(mdev->tl_hash); + mdev->tl_hash_s = 0; +} + +/** + * _tl_add_barrier: Adds a barrier to the TL. + */ +void _tl_add_barrier(struct drbd_conf *mdev, struct drbd_barrier *new) +{ + struct drbd_barrier *newest_before; + + INIT_LIST_HEAD(&new->requests); + INIT_LIST_HEAD(&new->w.list); + new->w.cb = NULL; /* if this is != NULL, we need to dec_ap_pending in tl_clear */ + new->next = NULL; + new->n_req = 0; + + newest_before = mdev->newest_barrier; + /* never send a barrier number == 0, because that is special-cased + * when using TCQ for our write ordering code */ + new->br_number = (newest_before->br_number+1) ?: 1; + if (mdev->newest_barrier != new) { + mdev->newest_barrier->next = new; + mdev->newest_barrier = new; + } +} + +/* when we receive a barrier ack */ +void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr, + unsigned int set_size) +{ + struct drbd_barrier *b, *nob; /* next old barrier */ + struct list_head *le, *tle; + struct drbd_request *r; + + spin_lock_irq(&mdev->req_lock); + + b = mdev->oldest_barrier; + + /* Clean up list of requests processed during current epoch */ + list_for_each_safe(le, tle, &b->requests) { + r = list_entry(le, struct drbd_request, tl_requests); + _req_mod(r, barrier_acked, 0); + } + list_del(&b->requests); + /* There could be requests on the list waiting for completion + of the write to the local disk, to avoid corruptions of + slab's data structures we have to remove the lists head */ + + D_ASSERT(b->br_number == barrier_nr); + D_ASSERT(b->n_req == set_size); + +#if 1 + if (b->br_number != barrier_nr) { + DUMPI(b->br_number); + DUMPI(barrier_nr); + } + if (b->n_req != set_size) { + DUMPI(b->n_req); + DUMPI(set_size); + } +#endif + + nob = b->next; + if (test_and_clear_bit(CREATE_BARRIER, &mdev->flags)) { + _tl_add_barrier(mdev, b); + if (nob) + mdev->oldest_barrier = nob; + /* if nob == NULL b was the only barrier, and becomes the new + barrer. Threfore mdev->oldest_barrier points already to b */ + } else { + D_ASSERT(nob != NULL); + mdev->oldest_barrier = nob; + kfree(b); + } + + spin_unlock_irq(&mdev->req_lock); +} + + +/* called by drbd_disconnect (exiting receiver thread) + * or from some after_state_ch */ +void tl_clear(struct drbd_conf *mdev) +{ + struct drbd_barrier *b, *tmp; + + DRBD_WARN("tl_clear()\n"); + + spin_lock_irq(&mdev->req_lock); + + b = mdev->oldest_barrier; + while ( b ) { + struct list_head *le, *tle; + struct drbd_request *r; + + list_for_each_safe(le, tle, &b->requests) { + r = list_entry(le, struct drbd_request, tl_requests); + _req_mod(r, connection_lost_while_pending, 0); + } + tmp = b->next; + + /* there could still be requests on that ring list, + * in case local io is still pending */ + list_del(&b->requests); + + /* dec_ap_pending corresponding to queue_barrier. + * the newest barrier may not have been queued yet, + * in which case w.cb is still NULL. */ + if (b->w.cb != NULL) + dec_ap_pending(mdev); + + if (b == mdev->newest_barrier) { + /* recycle, but reinit! */ + D_ASSERT(tmp == NULL); + INIT_LIST_HEAD(&b->requests); + INIT_LIST_HEAD(&b->w.list); + b->w.cb = NULL; + b->br_number = 4711; + b->n_req = 0; + + mdev->oldest_barrier = b; + break; + } + kfree(b); + b = tmp; + } + D_ASSERT(mdev->newest_barrier == mdev->oldest_barrier); + D_ASSERT(mdev->newest_barrier->br_number == 4711); + + /* ensure bit indicating barrier is required is clear */ + clear_bit(CREATE_BARRIER, &mdev->flags); + + spin_unlock_irq(&mdev->req_lock); +} + +/** + * drbd_io_error: Handles the on_io_error setting, should be called in the + * unlikely(!drbd_bio_uptodate(e->bio)) case from kernel thread context. + * See also drbd_chk_io_error + * + * NOTE: we set ourselves FAILED here if on_io_error is Detach or Panic OR + * if the forcedetach flag is set. This flag is set when failures + * occur writing the meta data portion of the disk as they are + * not recoverable. We also try to write the "need full sync bit" here + * anyways. This is to make sure that you get a resynchronisation of + * the full device the next time you connect. + */ +int drbd_io_error(struct drbd_conf *mdev, int forcedetach) +{ + enum io_error_handler eh; + unsigned long flags; + int send; + int ok = 1; + + eh = PassOn; + if (inc_local_if_state(mdev, Failed)) { + eh = mdev->bc->dc.on_io_error; + dec_local(mdev); + } + + if (!forcedetach && eh == PassOn) + return 1; + + spin_lock_irqsave(&mdev->req_lock, flags); + send = (mdev->state.disk == Failed); + if (send) + _drbd_set_state(_NS(mdev, disk, Diskless), ChgStateHard, NULL); + spin_unlock_irqrestore(&mdev->req_lock, flags); + + if (!send) + return ok; + + if (mdev->state.conn >= Connected) { + ok = drbd_send_state(mdev); + if (ok) DRBD_WARN("Notified peer that my disk is broken.\n"); + else ERR("Sending state in drbd_io_error() failed\n"); + } + + /* Make sure we try to flush meta-data to disk - we come + * in here because of a local disk error so it might fail + * but we still need to try -- both because the error might + * be in the data portion of the disk and because we need + * to ensure the md-sync-timer is stopped if running. */ + drbd_md_sync(mdev); + + /* Releasing the backing device is done in after_state_ch() */ + + if (eh == CallIOEHelper) + drbd_khelper(mdev, "local-io-error"); + + return ok; +} + +/** + * cl_wide_st_chg: + * Returns TRUE if this state change should be preformed as a cluster wide + * transaction. Of course it returns 0 as soon as the connection is lost. + */ +STATIC int cl_wide_st_chg(struct drbd_conf *mdev, + union drbd_state_t os, union drbd_state_t ns) +{ + return ( os.conn >= Connected && ns.conn >= Connected && + ( ( os.role != Primary && ns.role == Primary ) || + ( os.conn != StartingSyncT && ns.conn == StartingSyncT ) || + ( os.conn != StartingSyncS && ns.conn == StartingSyncS ) || + ( os.disk != Diskless && ns.disk == Diskless ) ) ) || + (os.conn >= Connected && ns.conn == Disconnecting) || + (os.conn == Connected && ns.conn == VerifyS); +} + +int drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f, + union drbd_state_t mask, union drbd_state_t val) +{ + unsigned long flags; + union drbd_state_t os, ns; + int rv; + + spin_lock_irqsave(&mdev->req_lock, flags); + os = mdev->state; + ns.i = (os.i & ~mask.i) | val.i; + rv = _drbd_set_state(mdev, ns, f, NULL); + ns = mdev->state; + spin_unlock_irqrestore(&mdev->req_lock, flags); + + return rv; +} + +void drbd_force_state(struct drbd_conf *mdev, + union drbd_state_t mask, union drbd_state_t val) +{ + drbd_change_state(mdev, ChgStateHard, mask, val); +} + +int is_valid_state(struct drbd_conf *mdev, union drbd_state_t ns); +int is_valid_state_transition(struct drbd_conf *, + union drbd_state_t, union drbd_state_t); +int drbd_send_state_req(struct drbd_conf *, + union drbd_state_t, union drbd_state_t); + +STATIC enum set_st_err _req_st_cond(struct drbd_conf *mdev, + union drbd_state_t mask, union drbd_state_t val) +{ + union drbd_state_t os, ns; + unsigned long flags; + int rv; + + if (test_and_clear_bit(CL_ST_CHG_SUCCESS, &mdev->flags)) + return SS_CW_Success; + + if (test_and_clear_bit(CL_ST_CHG_FAIL, &mdev->flags)) + return SS_CW_FailedByPeer; + + rv = 0; + spin_lock_irqsave(&mdev->req_lock, flags); + os = mdev->state; + ns.i = (os.i & ~mask.i) | val.i; + if ( !cl_wide_st_chg(mdev, os, ns) ) rv = SS_CW_NoNeed; + if (!rv) { + rv = is_valid_state(mdev, ns); + if (rv == SS_Success) { + rv = is_valid_state_transition(mdev, ns, os); + if (rv == SS_Success) + rv = 0; /* cont waiting, otherwise fail. */ + } + } + spin_unlock_irqrestore(&mdev->req_lock, flags); + + return rv; +} + +/** + * _drbd_request_state: + * This function is the most gracefull way to change state. For some state + * transition this function even does a cluster wide transaction. + * It has a cousin named drbd_request_state(), which is always verbose. + */ +STATIC int drbd_req_state(struct drbd_conf *mdev, + union drbd_state_t mask, union drbd_state_t val, + enum chg_state_flags f) +{ + struct completion done; + unsigned long flags; + union drbd_state_t os, ns; + int rv; + + init_completion(&done); + + if (f & ChgSerialize) + mutex_lock(&mdev->state_mutex); + + spin_lock_irqsave(&mdev->req_lock,flags); + os = mdev->state; + ns.i = (os.i & ~mask.i) | val.i; + + if (cl_wide_st_chg(mdev, os, ns)) { + rv = is_valid_state(mdev, ns); + if (rv == SS_Success) + rv = is_valid_state_transition(mdev, ns, os); + spin_unlock_irqrestore(&mdev->req_lock, flags); + + if (rv < SS_Success) { + if (f & ChgStateVerbose) + print_st_err(mdev, os, ns, rv); + goto abort; + } + + drbd_state_lock(mdev); + if ( !drbd_send_state_req(mdev, mask, val) ) { + drbd_state_unlock(mdev); + rv = SS_CW_FailedByPeer; + if (f & ChgStateVerbose) + print_st_err(mdev, os, ns, rv); + goto abort; + } + + wait_event(mdev->state_wait, + (rv = _req_st_cond(mdev, mask, val))); + + if (rv < SS_Success) { + /* nearly dead code. */ + drbd_state_unlock(mdev); + if (f & ChgStateVerbose) + print_st_err(mdev, os, ns, rv); + goto abort; + } + spin_lock_irqsave(&mdev->req_lock, flags); + os = mdev->state; + ns.i = (os.i & ~mask.i) | val.i; + rv = _drbd_set_state(mdev, ns, f, &done); + drbd_state_unlock(mdev); + } else { + rv = _drbd_set_state(mdev, ns, f, &done); + } + + spin_unlock_irqrestore(&mdev->req_lock, flags); + + if (f & ChgWaitComplete && rv == SS_Success) { + D_ASSERT(current != mdev->worker.task); + wait_for_completion(&done); + } + + abort: + if (f & ChgSerialize) + mutex_unlock(&mdev->state_mutex); + + return rv; +} + +/** + * _drbd_request_state: + * This function is the most gracefull way to change state. For some state + * transition this function even does a cluster wide transaction. + * It has a cousin named drbd_request_state(), which is always verbose. + */ +int _drbd_request_state(struct drbd_conf *mdev, union drbd_state_t mask, + union drbd_state_t val, enum chg_state_flags f) +{ + int rv; + + wait_event(mdev->state_wait, + (rv = drbd_req_state(mdev, mask, val, f)) != SS_InTransientState); + + return rv; +} + + +STATIC void print_st(struct drbd_conf *mdev, char *name, union drbd_state_t ns) +{ + ERR(" %s = { cs:%s st:%s/%s ds:%s/%s %c%c%c%c }\n", + name, + conns_to_name(ns.conn), + roles_to_name(ns.role), + roles_to_name(ns.peer), + disks_to_name(ns.disk), + disks_to_name(ns.pdsk), + ns.susp ? 's' : 'r', + ns.aftr_isp ? 'a' : '-', + ns.peer_isp ? 'p' : '-', + ns.user_isp ? 'u' : '-' + ); +} + +void print_st_err(struct drbd_conf *mdev, + union drbd_state_t os, union drbd_state_t ns, int err) +{ + if (err == SS_InTransientState) + return; + ERR("State change failed: %s\n", set_st_err_name(err)); + print_st(mdev, " state", os); + print_st(mdev, "wanted", ns); +} + + +#define peers_to_name roles_to_name +#define pdsks_to_name disks_to_name + +#define susps_to_name(A) ( (A) ? "1" : "0" ) +#define aftr_isps_to_name(A) ( (A) ? "1" : "0" ) +#define peer_isps_to_name(A) ( (A) ? "1" : "0" ) +#define user_isps_to_name(A) ( (A) ? "1" : "0" ) + +#define PSC(A) \ + ({ if (ns.A != os.A) { \ + pbp += sprintf(pbp, #A "( %s -> %s ) ", \ + A##s_to_name(os.A), \ + A##s_to_name(ns.A)); \ + } }) + +int is_valid_state(struct drbd_conf *mdev, union drbd_state_t ns) +{ + /* See drbd_state_sw_errors in drbd_strings.c */ + + enum fencing_policy fp; + int rv = SS_Success; + + fp = DontCare; + if (inc_local(mdev)) { + fp = mdev->bc->dc.fencing; + dec_local(mdev); + } + + if (inc_net(mdev)) { + if ( !mdev->net_conf->two_primaries && + ns.role == Primary && ns.peer == Primary ) + rv = SS_TwoPrimaries; + dec_net(mdev); + } + + if (rv <= 0) + /* already found a reason to abort */; + else if (ns.role == Secondary && mdev->open_cnt) + rv = SS_DeviceInUse; + + else if ( ns.role == Primary && ns.conn < Connected && + ns.disk < UpToDate ) rv = SS_NoUpToDateDisk; + + else if ( fp >= Resource && + ns.role == Primary && ns.conn < Connected && + ns.pdsk >= DUnknown ) rv = SS_PrimaryNOP; + + else if ( ns.role == Primary && ns.disk <= Inconsistent && + ns.pdsk <= Inconsistent ) rv = SS_NoUpToDateDisk; + + else if ( ns.conn > Connected && + ns.disk < UpToDate && ns.pdsk < UpToDate ) + rv = SS_BothInconsistent; + + else if ( ns.conn > Connected && + (ns.disk == Diskless || ns.pdsk == Diskless ) ) + rv = SS_SyncingDiskless; + + else if ( (ns.conn == Connected || + ns.conn == WFBitMapS || + ns.conn == SyncSource || + ns.conn == PausedSyncS) && + ns.disk == Outdated ) rv = SS_ConnectedOutdates; + + else if( (ns.conn == VerifyS || + ns.conn == VerifyT) && + (mdev->sync_conf.verify_alg[0] == 0)) rv=SS_NoVerifyAlg; + + else if( (ns.conn == VerifyS || + ns.conn == VerifyT) && + mdev->agreed_pro_version < 88) rv = SS_NotSupported; + + return rv; +} + +int is_valid_state_transition(struct drbd_conf *mdev, + union drbd_state_t ns, union drbd_state_t os) +{ + int rv = SS_Success; + + if ( (ns.conn == StartingSyncT || ns.conn == StartingSyncS ) && + os.conn > Connected) rv = SS_ResyncRunning; + + if (ns.conn == Disconnecting && os.conn == StandAlone) + rv = SS_AlreadyStandAlone; + + if (ns.disk > Attaching && os.disk == Diskless) + rv = SS_IsDiskLess; + + if ( ns.conn == WFConnection && os.conn < Unconnected ) + rv=SS_NoNetConfig; + + if ( ns.disk == Outdated && os.disk < Outdated && os.disk != Attaching) + rv=SS_LowerThanOutdated; + + if (ns.conn == Disconnecting && os.conn == Unconnected) + rv = SS_InTransientState; + + if (ns.conn == os.conn && ns.conn == WFReportParams) + rv = SS_InTransientState; + + if( (ns.conn == VerifyS || ns.conn == VerifyT) && os.conn < Connected ) + rv=SS_NeedConnection; + + if ((ns.conn == VerifyS || ns.conn == VerifyT) && + ns.conn != os.conn && os.conn > Connected) + rv = SS_ResyncRunning; + + if ((ns.conn == StartingSyncS || ns.conn == StartingSyncT) && + os.conn < Connected) + rv = SS_NeedConnection; + + return rv; +} + +int _drbd_set_state(struct drbd_conf *mdev, + union drbd_state_t ns, enum chg_state_flags flags, + struct completion *done) +{ + union drbd_state_t os; + int rv = SS_Success; + int warn_sync_abort = 0; + enum fencing_policy fp; + struct after_state_chg_work* ascw; + + MUST_HOLD(&mdev->req_lock); + + os = mdev->state; + + fp = DontCare; + if (inc_local(mdev)) { + fp = mdev->bc->dc.fencing; + dec_local(mdev); + } + + /* Early state sanitising. */ + + /* Dissalow Network errors to configure a device's network part */ + if ( (ns.conn >= Timeout && ns.conn <= TearDown ) && + os.conn <= Disconnecting ) + ns.conn = os.conn; + + /* After a network error (+TearDown) only Unconnected can follow */ + if (os.conn >= Timeout && os.conn <= TearDown && ns.conn != Unconnected) + ns.conn = os.conn; + + /* After Disconnecting only StandAlone may follow */ + if (os.conn == Disconnecting && ns.conn != StandAlone) + ns.conn = os.conn; + + if (ns.conn < Connected) { + ns.peer_isp = 0; + ns.peer = Unknown; + if ( ns.pdsk > DUnknown || + ns.pdsk < Inconsistent ) ns.pdsk = DUnknown; + } + + if (ns.conn <= Disconnecting && ns.disk == Diskless) + ns.pdsk = DUnknown; + + if (os.conn > Connected && ns.conn > Connected && + (ns.disk <= Failed || ns.pdsk <= Failed )) { + warn_sync_abort = 1; + ns.conn = Connected; + } + + if (ns.conn != os.conn && ns.conn >= Connected && + (ns.disk == Consistent || ns.disk == Outdated)) { + switch(ns.conn) { + case WFBitMapT: + case PausedSyncT: + ns.disk = Outdated; + break; + case Connected: + case WFBitMapS: + case SyncSource: + case PausedSyncS: + ns.disk = UpToDate; + break; + case SyncTarget: + ns.disk = Inconsistent; + DRBD_WARN("Implicit set disk state Inconsistent!\n"); + break; + } + if (os.disk == Outdated && ns.disk == UpToDate) + DRBD_WARN("Implicit set disk from Outdate to UpToDate\n"); + } + + if (ns.conn != os.conn && ns.conn >= Connected && + (ns.pdsk == Consistent || ns.pdsk == Outdated)) { + switch(ns.conn) { + case Connected: + case WFBitMapT: + case PausedSyncT: + case SyncTarget: + ns.pdsk = UpToDate; + break; + case WFBitMapS: + case PausedSyncS: + ns.pdsk = Outdated; + break; + case SyncSource: + ns.pdsk = Inconsistent; + DRBD_WARN("Implicit set pdsk Inconsistent!\n"); + break; + } + if (os.pdsk == Outdated && ns.pdsk == UpToDate) + DRBD_WARN("Implicit set pdsk from Outdate to UpToDate\n"); + } + + /* Connection breaks down before we finished "Negotiating" */ + if (ns.conn < Connected && ns.disk == Negotiating && + inc_local_if_state(mdev, Negotiating)) { + if (mdev->ed_uuid == mdev->bc->md.uuid[Current]) { + ns.disk = mdev->new_state_tmp.disk; + ns.pdsk = mdev->new_state_tmp.pdsk; + } else { + ALERT("Connection lost while negotiating, no data!\n"); + ns.disk = Diskless; + ns.pdsk = DUnknown; + } + dec_local(mdev); + } + + if (fp == Stonith && + (ns.role == Primary && + ns.conn < Connected && + ns.pdsk > Outdated)) + ns.susp = 1; + + if (ns.aftr_isp || ns.peer_isp || ns.user_isp) { + if (ns.conn == SyncSource) + ns.conn = PausedSyncS; + if (ns.conn == SyncTarget) + ns.conn = PausedSyncT; + } else { + if (ns.conn == PausedSyncS) + ns.conn = SyncSource; + if (ns.conn == PausedSyncT) + ns.conn = SyncTarget; + } + + if (ns.i == os.i) + return SS_NothingToDo; + + if ( !(flags & ChgStateHard) ) { + /* pre-state-change checks ; only look at ns */ + /* See drbd_state_sw_errors in drbd_strings.c */ + + rv = is_valid_state(mdev, ns); + if (rv < SS_Success) { + /* If the old state was illegal as well, then let + this happen...*/ + + if ( is_valid_state(mdev, os) == rv ) { + ERR("Considering state change from bad state. " + "Error would be: '%s'\n", + set_st_err_name(rv)); + print_st(mdev, "old", os); + print_st(mdev, "new", ns); + rv = is_valid_state_transition(mdev,ns,os); + } + } else + rv = is_valid_state_transition(mdev, ns, os); + } + + if (rv < SS_Success) { + if (flags & ChgStateVerbose) + print_st_err(mdev, os, ns, rv); + return rv; + } + + if (warn_sync_abort) + DRBD_WARN("Resync aborted.\n"); + +#if DUMP_MD >= 2 + { + char *pbp, pb[300]; + pbp = pb; + *pbp = 0; + PSC(role); + PSC(peer); + PSC(conn); + PSC(disk); + PSC(pdsk); + PSC(susp); + PSC(aftr_isp); + PSC(peer_isp); + PSC(user_isp); + INFO("%s\n", pb); + } +#endif + + mdev->state.i = ns.i; + wake_up(&mdev->misc_wait); + wake_up(&mdev->state_wait); + + /** post-state-change actions **/ + if (os.conn >= SyncSource && ns.conn <= Connected) { + set_bit(STOP_SYNC_TIMER, &mdev->flags); + mod_timer(&mdev->resync_timer, jiffies); + } + + if ( (os.conn == PausedSyncT || os.conn == PausedSyncS) && + (ns.conn == SyncTarget || ns.conn == SyncSource) ) { + INFO("Syncer continues.\n"); + mdev->rs_paused += (long)jiffies-(long)mdev->rs_mark_time; + if (ns.conn == SyncTarget) { + if (!test_and_clear_bit(STOP_SYNC_TIMER,&mdev->flags)) { + mod_timer(&mdev->resync_timer,jiffies); + } + /* This if (!test_bit) is only needed for the case + that a device that has ceased to used its timer, + i.e. it is already in drbd_resync_finished() gets + paused and resumed. */ + } + } + + if ( (os.conn == SyncTarget || os.conn == SyncSource) && + (ns.conn == PausedSyncT || ns.conn == PausedSyncS) ) { + INFO("Resync suspended\n"); + mdev->rs_mark_time = jiffies; + if (ns.conn == PausedSyncT) + set_bit(STOP_SYNC_TIMER, &mdev->flags); + } + + if (os.conn == Connected && + (ns.conn == VerifyS || ns.conn == VerifyT )) { + mdev->ov_position = 0; + mdev->ov_left = + mdev->rs_total = + mdev->rs_mark_left = drbd_bm_bits(mdev); + mdev->rs_start = + mdev->rs_mark_time = jiffies; + mdev->ov_last_oos_size = 0; + mdev->ov_last_oos_start = 0; + if(ns.conn == VerifyS) { + mod_timer(&mdev->resync_timer,jiffies); + } + } + + if(inc_local(mdev)) { + u32 mdf = mdev->bc->md.flags & ~(MDF_Consistent|MDF_PrimaryInd| + MDF_ConnectedInd|MDF_WasUpToDate| + MDF_PeerOutDated ); + if (test_bit(CRASHED_PRIMARY,&mdev->flags) || + mdev->state.role == Primary || + ( mdev->state.pdsk < Inconsistent && + mdev->state.peer == Primary ) ) mdf |= MDF_PrimaryInd; + if (mdev->state.conn > WFReportParams) mdf |= MDF_ConnectedInd; + if (mdev->state.disk > Inconsistent) mdf |= MDF_Consistent; + if (mdev->state.disk > Outdated) mdf |= MDF_WasUpToDate; + if (mdev->state.pdsk <= Outdated && + mdev->state.pdsk >= Inconsistent) mdf |= MDF_PeerOutDated; + if( mdf != mdev->bc->md.flags) { + mdev->bc->md.flags = mdf; + drbd_md_mark_dirty(mdev); + } + if (os.disk < Consistent && ns.disk >= Consistent) + drbd_set_ed_uuid(mdev, mdev->bc->md.uuid[Current]); + dec_local(mdev); + } + + /* Peer was forced UpToDate & Primary, consider to resync */ + if (os.disk == Inconsistent && os.pdsk == Inconsistent && + os.peer == Secondary && ns.peer == Primary) + set_bit(CONSIDER_RESYNC, &mdev->flags); + + /* Receiver should clean up itself */ + if (os.conn != Disconnecting && ns.conn == Disconnecting) + drbd_thread_stop_nowait(&mdev->receiver); + + /* Now the receiver finished cleaning up itself, it should die */ + if (os.conn != StandAlone && ns.conn == StandAlone) + drbd_thread_stop_nowait(&mdev->receiver); + + /* Upon network failure, we need to restart the receiver. */ + if (os.conn > TearDown && + ns.conn <= TearDown && ns.conn >= Timeout) + drbd_thread_restart_nowait(&mdev->receiver); + + ascw = kmalloc(sizeof(*ascw), GFP_ATOMIC); + if (ascw) { + ascw->os = os; + ascw->ns = ns; + ascw->flags = flags; + ascw->w.cb = w_after_state_ch; + ascw->done = done; + drbd_queue_work(&mdev->data.work, &ascw->w); + } else { + DRBD_WARN("Could not kmalloc an ascw\n"); + } + + return rv; +} + +int w_after_state_ch(struct drbd_conf *mdev, struct drbd_work *w, int unused) +{ + struct after_state_chg_work *ascw; + + ascw = (struct after_state_chg_work *) w; + after_state_ch(mdev, ascw->os, ascw->ns, ascw->flags); + if (ascw->flags & ChgWaitComplete) { + D_ASSERT(ascw->done != NULL); + complete(ascw->done); + } + kfree(ascw); + + return 1; +} + +static void abw_start_sync(struct drbd_conf *mdev, int rv) +{ + if (rv) { + ERR("Writing the bitmap failed not starting resync.\n"); + _drbd_request_state(mdev, NS(conn, Connected), ChgStateVerbose); + return; + } + + switch (mdev->state.conn) { + case StartingSyncT: + _drbd_request_state(mdev, NS(conn, WFSyncUUID), ChgStateVerbose); + break; + case StartingSyncS: + drbd_start_resync(mdev, SyncSource); + break; + } +} + +static void after_state_ch(struct drbd_conf *mdev, union drbd_state_t os, + union drbd_state_t ns, enum chg_state_flags flags) +{ + enum fencing_policy fp; + + if ( (os.conn != Connected && ns.conn == Connected) ) { + clear_bit(CRASHED_PRIMARY, &mdev->flags); + if (mdev->p_uuid) + mdev->p_uuid[UUID_FLAGS] &= ~((u64)2); + } + + fp = DontCare; + if (inc_local(mdev)) { + fp = mdev->bc->dc.fencing; + dec_local(mdev); + } + + /* Inform userspace about the change... */ + drbd_bcast_state(mdev, ns); + + /* Here we have the actions that are performed after a + state change. This function might sleep */ + + if (fp == Stonith && ns.susp) { + /* case1: The outdate peer handler is successfull: + * case2: The connection was established again: */ + if ( (os.pdsk > Outdated && ns.pdsk <= Outdated) || + (os.conn < Connected && ns.conn >= Connected) ) { + tl_clear(mdev); + spin_lock_irq(&mdev->req_lock); + _drbd_set_state(_NS(mdev, susp, 0), ChgStateVerbose, NULL); + spin_unlock_irq(&mdev->req_lock); + } + } + /* Do not change the order of the if above and below... */ + if (os.conn != WFBitMapS && ns.conn == WFBitMapS) + drbd_queue_bitmap_io(mdev, &drbd_send_bitmap, NULL); + + /* Lost contact to peer's copy of the data */ + if ( (os.pdsk >= Inconsistent && + os.pdsk != DUnknown && + os.pdsk != Outdated) + && (ns.pdsk < Inconsistent || + ns.pdsk == DUnknown || + ns.pdsk == Outdated) ) { + kfree(mdev->p_uuid); + mdev->p_uuid = NULL; + if (inc_local(mdev)) { + /* generate new uuid, unless we did already */ + if (ns.role == Primary && + mdev->bc->md.uuid[Bitmap] == 0) + drbd_uuid_new_current(mdev); + if (ns.peer == Primary) { + /* Note: The condition ns.peer == Primary implies + that we are connected. Otherwise it would + be ns.peer == Unknown. */ + /* A FullSync is required after a + primary detached from its disk! */ + _drbd_uuid_new_current(mdev); + drbd_send_uuids(mdev); + } + dec_local(mdev); + } + } + + if (ns.pdsk < Inconsistent && inc_local(mdev)) { + if (ns.peer == Primary && mdev->bc->md.uuid[Bitmap] == 0) { + /* Diskless Peer becomes primary */ + if (os.peer == Secondary) + drbd_uuid_new_current(mdev); + + /* Got connected to diskless, primary peer */ + if (os.peer == Unknown) + _drbd_uuid_new_current(mdev); + } + + /* Diskless Peer becomes secondary */ + if (os.peer == Primary && ns.peer == Secondary) + drbd_al_to_on_disk_bm(mdev); + dec_local(mdev); + } + + /* Last part of the attaching process ... */ + if ( ns.conn >= Connected && + os.disk == Attaching && ns.disk == Negotiating ) { + kfree(mdev->p_uuid); /* We expect to receive up-to-date UUIDs soon. */ + mdev->p_uuid = NULL; /* ...to not use the old ones in the mean time */ + drbd_send_sizes(mdev); /* to start sync... */ + drbd_send_uuids(mdev); + drbd_send_state(mdev); + } + + /* We want to pause/continue resync, tell peer. */ + if ( ns.conn >= Connected && + (( os.aftr_isp != ns.aftr_isp ) || + ( os.user_isp != ns.user_isp )) ) + drbd_send_state(mdev); + + /* In case one of the isp bits got set, suspend other devices. */ + if ( ( !os.aftr_isp && !os.peer_isp && !os.user_isp) && + ( ns.aftr_isp || ns.peer_isp || ns.user_isp) ) + suspend_other_sg(mdev); + + /* Make sure the peer gets informed about eventual state + changes (ISP bits) while we were in WFReportParams. */ + if (os.conn == WFReportParams && ns.conn >= Connected) { + drbd_send_state(mdev); + } + + /* We are in the progress to start a full sync... */ + if ( ( os.conn != StartingSyncT && ns.conn == StartingSyncT ) || + ( os.conn != StartingSyncS && ns.conn == StartingSyncS ) ) { + INFO("Queueing bitmap io: about to start a forced full sync\n"); + drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, &abw_start_sync); + } + + /* We are invalidating our self... */ + if ( os.conn < Connected && ns.conn < Connected && + os.disk > Inconsistent && ns.disk == Inconsistent ) { + INFO("Queueing bitmap io: invalidate forced full sync\n"); + drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL); + } + + if (os.disk > Diskless && ns.disk == Diskless) { + /* since inc_local() only works as long as disk>=Inconsistent, + and it is Diskless here, local_cnt can only go down, it can + not increase... It will reach zero */ + wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt)); + + lc_free(mdev->resync); + mdev->resync = NULL; + lc_free(mdev->act_log); + mdev->act_log = NULL; + __no_warn(local, drbd_free_bc(mdev->bc);); + wmb(); /* see begin of drbd_nl_disk_conf() */ + __no_warn(local, mdev->bc = NULL;); + } + + /* A resync finished or aborted, wake paused devices... */ + if ( (os.conn > Connected && ns.conn <= Connected) || + (os.peer_isp && !ns.peer_isp) || + (os.user_isp && !ns.user_isp) ) + resume_next_sg(mdev); + + /* Upon network connection, we need to start the received */ + if (os.conn == StandAlone && ns.conn == Unconnected) + drbd_thread_start(&mdev->receiver); + + /* Terminate worker thread if we are unconfigured - it will be + restarted as needed... */ + if (ns.disk == Diskless && ns.conn == StandAlone) + drbd_thread_stop_nowait(&mdev->worker); + + drbd_md_sync(mdev); +} + + +STATIC int drbd_thread_setup(void *arg) +{ + struct Drbd_thread *thi = (struct Drbd_thread *) arg; + struct drbd_conf *mdev = thi->mdev; + int retval; + + daemonize("drbd_thread"); + D_ASSERT(get_t_state(thi) == Running); + D_ASSERT(thi->task == NULL); + spin_lock(&thi->t_lock); + thi->task = current; + smp_mb(); + spin_unlock(&thi->t_lock); + complete(&thi->startstop); /* notify: thi->task is set. */ + + while (1) { + retval = thi->function(thi); + if (get_t_state(thi) != Restarting) break; + thi->t_state = Running; + } + + mutex_lock(&thi->task_mutex); + spin_lock(&thi->t_lock); + thi->task = NULL; + thi->t_state = None; + smp_mb(); + spin_unlock(&thi->t_lock); + mutex_unlock(&thi->task_mutex); + + /* THINK maybe two different completions? */ + complete(&thi->startstop); /* notify: thi->task unset. */ + + INFO("Terminating %s thread\n", + thi == &mdev->receiver ? "receiver" : + thi == &mdev->asender ? "asender" : + thi == &mdev->worker ? "worker" : "NONSENSE"); + + // Release mod reference taken when thread was started + module_put(THIS_MODULE); + return retval; +} + +STATIC void drbd_thread_init(struct drbd_conf *mdev, struct Drbd_thread *thi, + int (*func) (struct Drbd_thread *)) +{ + spin_lock_init(&thi->t_lock); + thi->task = NULL; + thi->t_state = None; + thi->function = func; + thi->mdev = mdev; + mutex_init(&thi->task_mutex); +} + +int drbd_thread_start(struct Drbd_thread *thi) +{ + int pid; + struct drbd_conf *mdev = thi->mdev; + + spin_lock(&thi->t_lock); + + if (thi->t_state == None) { + INFO("Starting %s thread (from %s [%d])\n", + thi == &mdev->receiver ? "receiver" : + thi == &mdev->asender ? "asender" : + thi == &mdev->worker ? "worker" : "NONSENSE", + current->comm, current->pid); + + /* Get ref on module for thread - this is released when thread exits */ + if (!try_module_get(THIS_MODULE)) { + ERR("Failed to get module reference in drbd_thread_start\n"); + spin_unlock(&thi->t_lock); + return FALSE; + } + + init_completion(&thi->startstop); + D_ASSERT(thi->task == NULL); + thi->t_state = Running; + spin_unlock(&thi->t_lock); + flush_signals(current); /* otherw. may get -ERESTARTNOINTR */ + + /* FIXME rewrite to use kthread interface */ + pid = kernel_thread(drbd_thread_setup, (void *) thi, CLONE_FS); + if (pid < 0) { + ERR("Couldn't start thread (%d)\n", pid); + + module_put(THIS_MODULE); + return FALSE; + } + /* waits until thi->task is set */ + wait_for_completion(&thi->startstop); + D_ASSERT(thi->task); + D_ASSERT(get_t_state(thi) == Running); + } else { + spin_unlock(&thi->t_lock); + } + + return TRUE; +} + + +void _drbd_thread_stop(struct Drbd_thread *thi, int restart, int wait) +{ + struct drbd_conf *mdev = thi->mdev; + enum Drbd_thread_state ns = restart ? Restarting : Exiting; + + spin_lock(&thi->t_lock); + + /* INFO("drbd_thread_stop: %s [%d]: %s %d -> %d; %d\n", + current->comm, current->pid, + thi->task ? thi->task->comm : "NULL", thi->t_state, ns, wait); */ + + if (thi->t_state == None) { + spin_unlock(&thi->t_lock); + if (restart) + drbd_thread_start(thi); + return; + } + + if (thi->t_state != ns) { + if (thi->task == NULL) { + spin_unlock(&thi->t_lock); + return; + } + + thi->t_state = ns; + smp_mb(); + if (thi->task != current) { + if (wait) + init_completion(&thi->startstop); + force_sig(DRBD_SIGKILL, thi->task); + } else + D_ASSERT(!wait); + } + spin_unlock(&thi->t_lock); + + if (wait) { + D_ASSERT(thi->task != current); + wait_for_completion(&thi->startstop); + spin_lock(&thi->t_lock); + D_ASSERT(thi->task == NULL); + D_ASSERT(thi->t_state == None); + spin_unlock(&thi->t_lock); + } +} + +#ifdef CONFIG_SMP +/** + * drbd_calc_cpu_mask: Generates CPU masks, sprad over all CPUs. + * Forces all threads of a device onto the same CPU. This is benificial for + * DRBD's performance. May be overwritten by user's configuration. + */ +cpumask_t drbd_calc_cpu_mask(struct drbd_conf *mdev) +{ + int sv, cpu; + cpumask_t av_cpu_m; + + if (cpus_weight(mdev->cpu_mask)) + return mdev->cpu_mask; + + av_cpu_m = cpu_online_map; + sv = mdev_to_minor(mdev) % cpus_weight(av_cpu_m); + + for_each_cpu_mask(cpu, av_cpu_m) { + if (sv-- == 0) + return cpumask_of_cpu(cpu); + } + + /* some kernel versions "forget" to add the (cpumask_t) typecast + * to that macro, which results in "parse error before '{'" ;-> */ + return (cpumask_t) CPU_MASK_ALL; /* Never reached. */ +} + +void drbd_thread_set_cpu(struct Drbd_thread *thi, cpumask_t cpu_mask) +{ + struct task_struct *p; + + mutex_lock(&thi->task_mutex); + p = thi->task; + if (p) set_cpus_allowed(p, cpu_mask); + mutex_unlock(&thi->task_mutex); +} + +#endif + +/* the appropriate socket mutex must be held already */ +int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, + enum Drbd_Packet_Cmd cmd, struct Drbd_Header *h, + size_t size, unsigned msg_flags) +{ + int sent, ok; + + ERR_IF(!h) return FALSE; + ERR_IF(!size) return FALSE; + + h->magic = BE_DRBD_MAGIC; + h->command = cpu_to_be16(cmd); + h->length = cpu_to_be16(size-sizeof(struct Drbd_Header)); + + dump_packet(mdev, sock, 0, (void *)h, __FILE__, __LINE__); + sent = drbd_send(mdev, sock, h, size, msg_flags); + + ok = ( sent == size ); + if (!ok) + ERR("short sent %s size=%d sent=%d\n", + cmdname(cmd), (int)size, sent); + return ok; +} + +/* don't pass the socket. we may only look at it + * when we hold the appropriate socket mutex. + */ +int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, + enum Drbd_Packet_Cmd cmd, struct Drbd_Header *h, size_t size) +{ + int ok = 0; + struct socket *sock; + + if (use_data_socket) { + down(&mdev->data.mutex); + sock = mdev->data.socket; + } else { + down(&mdev->meta.mutex); + sock = mdev->meta.socket; + } + + /* drbd_disconnect() could have called drbd_free_sock() + * while we were waiting in down()... */ + if (likely(sock != NULL)) + ok = _drbd_send_cmd(mdev, sock, cmd, h, size, 0); + + if (use_data_socket) + up(&mdev->data.mutex); + else + up(&mdev->meta.mutex); + return ok; +} + +int drbd_send_cmd2(struct drbd_conf *mdev, enum Drbd_Packet_Cmd cmd, char *data, + size_t size) +{ + struct Drbd_Header h; + int ok; + + h.magic = BE_DRBD_MAGIC; + h.command = cpu_to_be16(cmd); + h.length = cpu_to_be16(size); + + if (!drbd_get_data_sock(mdev)) + return 0; + + dump_packet(mdev, mdev->data.socket, 0, (void *)&h, __FILE__, __LINE__); + + ok = ( sizeof(h) == + drbd_send(mdev, mdev->data.socket, &h, sizeof(h), 0) ); + ok = ok && ( size == + drbd_send(mdev, mdev->data.socket, data, size, 0) ); + + drbd_put_data_sock(mdev); + + return ok; +} + +int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc) +{ + struct Drbd_SyncParam_Packet *p; + int size, rv; + + size = sizeof(struct Drbd_SyncParam_Packet); + + if (mdev->agreed_pro_version >= 88) + size += strlen(mdev->sync_conf.verify_alg) + 1; + + p = kmalloc(size, GFP_KERNEL); + if (p == NULL) + return 0; + + p->rate = cpu_to_be32(sc->rate); + + if (mdev->agreed_pro_version >= 88) + strcpy(p->online_verify_alg,mdev->sync_conf.verify_alg); + + rv = drbd_send_cmd(mdev, USE_DATA_SOCKET, SyncParam, + (struct Drbd_Header *)p, size); + kfree(p); + return rv; +} + +int drbd_send_protocol(struct drbd_conf *mdev) +{ + struct Drbd_Protocol_Packet *p; + int size,rv; + + size = sizeof(struct Drbd_Protocol_Packet); + + if (mdev->agreed_pro_version >= 87) + size += strlen(mdev->net_conf->integrity_alg) + 1; + + if ((p = kmalloc(size, GFP_KERNEL)) == NULL) + return 0; + + p->protocol = cpu_to_be32(mdev->net_conf->wire_protocol); + p->after_sb_0p = cpu_to_be32(mdev->net_conf->after_sb_0p); + p->after_sb_1p = cpu_to_be32(mdev->net_conf->after_sb_1p); + p->after_sb_2p = cpu_to_be32(mdev->net_conf->after_sb_2p); + p->want_lose = cpu_to_be32(mdev->net_conf->want_lose); + p->two_primaries = cpu_to_be32(mdev->net_conf->two_primaries); + + if (mdev->agreed_pro_version >= 87) + strcpy(p->integrity_alg, mdev->net_conf->integrity_alg); + + rv = drbd_send_cmd(mdev, USE_DATA_SOCKET, ReportProtocol, + (struct Drbd_Header *)p, size); + kfree(p); + return rv; +} + +int drbd_send_uuids(struct drbd_conf *mdev) +{ + struct Drbd_GenCnt_Packet p; + int i; + + u64 uuid_flags = 0; + + if (!inc_local_if_state(mdev, Negotiating)) + return 1; + + /* FIXME howto handle diskless ? */ + for (i = Current; i < UUID_SIZE; i++) + p.uuid[i] = mdev->bc ? cpu_to_be64(mdev->bc->md.uuid[i]) : 0; + + mdev->comm_bm_set = drbd_bm_total_weight(mdev); + p.uuid[UUID_SIZE] = cpu_to_be64(mdev->comm_bm_set); + uuid_flags |= mdev->net_conf->want_lose ? 1 : 0; + uuid_flags |= test_bit(CRASHED_PRIMARY, &mdev->flags) ? 2 : 0; + uuid_flags |= mdev->new_state_tmp.disk == Inconsistent ? 4 : 0; + p.uuid[UUID_FLAGS] = cpu_to_be64(uuid_flags); + + dec_local(mdev); + + return drbd_send_cmd(mdev, USE_DATA_SOCKET, ReportUUIDs, + (struct Drbd_Header*)&p, sizeof(p)); +} + +int drbd_send_sync_uuid(struct drbd_conf *mdev, u64 val) +{ + struct Drbd_SyncUUID_Packet p; + + p.uuid = cpu_to_be64(val); + + return drbd_send_cmd(mdev, USE_DATA_SOCKET, ReportSyncUUID, + (struct Drbd_Header *)&p, sizeof(p)); +} + +int drbd_send_sizes(struct drbd_conf *mdev) +{ + struct Drbd_Sizes_Packet p; + sector_t d_size, u_size; + int q_order_type; + int ok; + + if (inc_local_if_state(mdev, Negotiating)) { + D_ASSERT(mdev->bc->backing_bdev); + d_size = drbd_get_max_capacity(mdev->bc); + u_size = mdev->bc->dc.disk_size; + q_order_type = drbd_queue_order_type(mdev); + p.queue_order_type = cpu_to_be32(drbd_queue_order_type(mdev)); + dec_local(mdev); + } else { + d_size = 0; + u_size = 0; + q_order_type = QUEUE_ORDERED_NONE; + } + + p.d_size = cpu_to_be64(d_size); + p.u_size = cpu_to_be64(u_size); + p.c_size = cpu_to_be64(drbd_get_capacity(mdev->this_bdev)); + p.max_segment_size = cpu_to_be32(mdev->rq_queue->max_segment_size); + p.queue_order_type = cpu_to_be32(q_order_type); + + ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, ReportSizes, + (struct Drbd_Header *)&p, sizeof(p)); + return ok; +} + +/** + * drbd_send_state: + * Informs the peer about our state. Only call it when + * mdev->state.conn >= Connected (I.e. you may not call it while in + * WFReportParams. Though there is one valid and necessary exception, + * drbd_connect() calls drbd_send_state() while in it WFReportParams. + */ +int drbd_send_state(struct drbd_conf *mdev) +{ + struct socket *sock; + struct Drbd_State_Packet p; + int ok = 0; + + /* Grab state lock so we wont send state if we're in the middle + * of a cluster wide state change on another thread */ + drbd_state_lock(mdev); + + down(&mdev->data.mutex); + + p.state = cpu_to_be32(mdev->state.i); /* Within the send mutex */ + sock = mdev->data.socket; + + if (likely(sock != NULL)) { + ok = _drbd_send_cmd(mdev, sock, ReportState, + (struct Drbd_Header*)&p, sizeof(p), 0); + } + + up(&mdev->data.mutex); + + drbd_state_unlock(mdev); + return ok; +} + +int drbd_send_state_req(struct drbd_conf *mdev, + union drbd_state_t mask, union drbd_state_t val) +{ + struct Drbd_Req_State_Packet p; + + p.mask = cpu_to_be32(mask.i); + p.val = cpu_to_be32(val.i); + + return drbd_send_cmd(mdev, USE_DATA_SOCKET, StateChgRequest, + (struct Drbd_Header *)&p, sizeof(p)); +} + +int drbd_send_sr_reply(struct drbd_conf *mdev, int retcode) +{ + struct Drbd_RqS_Reply_Packet p; + + p.retcode = cpu_to_be32(retcode); + + return drbd_send_cmd(mdev, USE_META_SOCKET, StateChgReply, + (struct Drbd_Header *)&p, sizeof(p)); +} + + +/* See the comment at receive_bitmap() */ +int _drbd_send_bitmap(struct drbd_conf *mdev) +{ + int want; + int ok = TRUE; + int bm_i = 0; + size_t bm_words, num_words; + unsigned long *buffer; + struct Drbd_Header *p; + + ERR_IF(!mdev->bitmap) return FALSE; + + bm_words = drbd_bm_words(mdev); + p = vmalloc(PAGE_SIZE); /* sleeps. cannot fail. */ + buffer = (unsigned long *)p->payload; + + if (inc_local(mdev)) { + if (drbd_md_test_flag(mdev->bc,MDF_FullSync)) { + INFO("Writing the whole bitmap, MDF_FullSync was set.\n"); + drbd_bm_set_all(mdev); + if (drbd_bm_write(mdev)) { + /* write_bm did fail! Leave full sync flag set in Meta Data + * but otherwise process as per normal - need to tell other + * side that a full resync is required! */ + ERR("Failed to write bitmap to disk!\n"); + } + else { + drbd_md_clear_flag(mdev,MDF_FullSync); + drbd_md_sync(mdev); + } + } + dec_local(mdev); + } + + /* + * maybe TODO use some simple compression scheme, nowadays there are + * some such algorithms in the kernel anyways. + */ + do { + num_words = min_t(size_t, BM_PACKET_WORDS, bm_words-bm_i ); + want = num_words * sizeof(long); + if (want) + drbd_bm_get_lel(mdev, bm_i, num_words, buffer); + ok = _drbd_send_cmd(mdev, mdev->data.socket, ReportBitMap, + p, sizeof(*p) + want, 0); + bm_i += num_words; + } while (ok && want); + + vfree(p); + return ok; +} + +int drbd_send_bitmap(struct drbd_conf *mdev) +{ + int err; + + if (!drbd_get_data_sock(mdev)) + return -1; + err = !_drbd_send_bitmap(mdev); + drbd_put_data_sock(mdev); + return err; +} + +int drbd_send_b_ack(struct drbd_conf *mdev, u32 barrier_nr, u32 set_size) +{ + int ok; + struct Drbd_BarrierAck_Packet p; + + p.barrier = barrier_nr; + p.set_size = cpu_to_be32(set_size); + + ok = drbd_send_cmd(mdev, USE_META_SOCKET, BarrierAck, + (struct Drbd_Header *)&p, sizeof(p)); + return ok; +} + +/** + * _drbd_send_ack: + * This helper function expects the sector and block_id parameter already + * in big endian! + */ +STATIC int _drbd_send_ack(struct drbd_conf *mdev, enum Drbd_Packet_Cmd cmd, + u64 sector, + u32 blksize, + u64 block_id) +{ + int ok; + struct Drbd_BlockAck_Packet p; + + p.sector = sector; + p.block_id = block_id; + p.blksize = blksize; + p.seq_num = cpu_to_be32(atomic_add_return(1, &mdev->packet_seq)); + + if (!mdev->meta.socket || mdev->state.conn < Connected) + return FALSE; + ok = drbd_send_cmd(mdev, USE_META_SOCKET, cmd, + (struct Drbd_Header *)&p, sizeof(p)); + return ok; +} + +int drbd_send_ack_dp(struct drbd_conf *mdev, enum Drbd_Packet_Cmd cmd, + struct Drbd_Data_Packet *dp) +{ + const int header_size = sizeof(struct Drbd_Data_Packet) + - sizeof(struct Drbd_Header); + int data_size = ((struct Drbd_Header *)dp)->length - header_size; + + return _drbd_send_ack(mdev, cmd, dp->sector, cpu_to_be32(data_size), + dp->block_id); +} + +int drbd_send_ack_rp(struct drbd_conf *mdev, enum Drbd_Packet_Cmd cmd, + struct Drbd_BlockRequest_Packet *rp) +{ + return _drbd_send_ack(mdev, cmd, rp->sector, rp->blksize, rp->block_id); +} + +int drbd_send_ack(struct drbd_conf *mdev, + enum Drbd_Packet_Cmd cmd, struct Tl_epoch_entry *e) +{ + return _drbd_send_ack(mdev, cmd, + cpu_to_be64(e->sector), + cpu_to_be32(e->size), + e->block_id); +} + +int drbd_send_ack_ex(struct drbd_conf *mdev, enum Drbd_Packet_Cmd cmd, + sector_t sector, int blksize, u64 block_id) +{ + /* This function misuses the block_id field to signal if the blocks + are is sync or not. */ + return _drbd_send_ack(mdev,cmd, + cpu_to_be64(sector), + cpu_to_be32(blksize), + cpu_to_be64(block_id)); +} + + +int drbd_send_drequest(struct drbd_conf *mdev, int cmd, + sector_t sector, int size, u64 block_id) +{ + int ok; + struct Drbd_BlockRequest_Packet p; + + p.sector = cpu_to_be64(sector); + p.block_id = block_id; + p.blksize = cpu_to_be32(size); + + /* FIXME BIO_RW_SYNC ? */ + + ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, cmd, + (struct Drbd_Header *)&p, sizeof(p)); + return ok; +} + + +int drbd_send_drequest_csum(struct drbd_conf *mdev, + sector_t sector,int size, + void *digest, int digest_size, + enum Drbd_Packet_Cmd cmd) +{ + int ok; + struct Drbd_BlockRequest_Packet p; + + p.sector = cpu_to_be64(sector); + p.block_id = BE_DRBD_MAGIC + 0xbeef; + p.blksize = cpu_to_be32(size); + + p.head.magic = BE_DRBD_MAGIC; + p.head.command = cpu_to_be16(cmd); + p.head.length = cpu_to_be16( sizeof(p)-sizeof(struct Drbd_Header) + digest_size ); + + down(&mdev->data.mutex); + + ok = ( sizeof(p) == drbd_send(mdev,mdev->data.socket,&p,sizeof(p),0) ); + ok = ok&& ( digest_size == drbd_send(mdev,mdev->data.socket,digest,digest_size,0) ); + + up(&mdev->data.mutex); + + return ok; +} + +int drbd_send_ov_request(struct drbd_conf *mdev,sector_t sector,int size) +{ + int ok; + struct Drbd_BlockRequest_Packet p; + + p.sector = cpu_to_be64(sector); + p.block_id = BE_DRBD_MAGIC + 0xbabe; + p.blksize = cpu_to_be32(size); + + ok = drbd_send_cmd(mdev,USE_DATA_SOCKET, OVRequest, + (struct Drbd_Header*)&p,sizeof(p)); + return ok; +} + + +/* called on sndtimeo + * returns FALSE if we should retry, + * TRUE if we think connection is dead + */ +STATIC int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket *sock) +{ + int drop_it; + /* long elapsed = (long)(jiffies - mdev->last_received); */ + /* DUMPLU(elapsed); // elapsed ignored for now. */ + + drop_it = mdev->meta.socket == sock + || !mdev->asender.task + || get_t_state(&mdev->asender) != Running + || mdev->state.conn < Connected; + + if (drop_it) + return TRUE; + + drop_it = !--mdev->ko_count; + if (!drop_it) { + ERR("[%s/%d] sock_sendmsg time expired, ko = %u\n", + current->comm, current->pid, mdev->ko_count); + request_ping(mdev); + } + + return drop_it; /* && (mdev->state == Primary) */; +} + +/* The idea of sendpage seems to be to put some kind of reference + * to the page into the skb, and to hand it over to the NIC. In + * this process get_page() gets called. + * + * As soon as the page was really sent over the network put_page() + * gets called by some part of the network layer. [ NIC driver? ] + * + * [ get_page() / put_page() increment/decrement the count. If count + * reaches 0 the page will be freed. ] + * + * This works nicely with pages from FSs. + * But this means that in protocol A we might signal IO completion too early! + * + * In order not to corrupt data during a resync we must make sure + * that we do not reuse our own buffer pages (EEs) to early, therefore + * we have the net_ee list. + * + * XFS seems to have problems, still, it submits pages with page_count == 0! + * As a workaround, we disable sendpage on pages + * with page_count == 0 or PageSlab. + */ +STATIC int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page, + int offset, size_t size) +{ + int ret; + ret = drbd_send(mdev, mdev->data.socket, kmap(page) + offset, size, 0); + kunmap(page); + return ret; +} + +int _drbd_send_page(struct drbd_conf *mdev, struct page *page, + int offset, size_t size) +{ + mm_segment_t oldfs = get_fs(); + int sent, ok; + int len = size; + +#ifdef SHOW_SENDPAGE_USAGE + unsigned long now = jiffies; + static unsigned long total; + static unsigned long fallback; + static unsigned long last_rep; + + /* report statistics every hour, + * if we had at least one fallback. + */ + ++total; + if (fallback && time_before(last_rep+3600*HZ, now)) { + last_rep = now; + printk(KERN_INFO "drbd: sendpage() omitted: %lu/%lu\n", + fallback, total); + } +#endif + + /* PARANOIA. if this ever triggers, + * something in the layers above us is really kaputt. + *one roundtrip later: + * doh. it triggered. so XFS _IS_ really kaputt ... + * oh well... + */ + if ( (page_count(page) < 1) || PageSlab(page) ) { + /* e.g. XFS meta- & log-data is in slab pages, which have a + * page_count of 0 and/or have PageSlab() set... + */ +#ifdef SHOW_SENDPAGE_USAGE + ++fallback; +#endif + sent = _drbd_no_send_page(mdev, page, offset, size); + if (likely(sent > 0)) len -= sent; + goto out; + } + + set_fs(KERNEL_DS); + do { + sent = mdev->data.socket->ops->sendpage(mdev->data.socket, page, + offset, len, + MSG_NOSIGNAL); + if (sent == -EAGAIN) { + if (we_should_drop_the_connection(mdev, + mdev->data.socket)) + break; + else + continue; + } + if (sent <= 0) { + DRBD_WARN("%s: size=%d len=%d sent=%d\n", + __func__, (int)size, len, sent); + break; + } + len -= sent; + offset += sent; + /* FIXME test "last_received" ... */ + } while (len > 0 /* THINK && mdev->cstate >= Connected*/); + set_fs(oldfs); + +out: + ok = (len == 0); + if (likely(ok)) + mdev->send_cnt += size>>9; + return ok; +} + +static inline int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio) +{ + struct bio_vec *bvec; + int i; + __bio_for_each_segment(bvec, bio, i, 0) { + if (!_drbd_no_send_page(mdev, bvec->bv_page, + bvec->bv_offset, bvec->bv_len)) + return 0; + } + return 1; +} + +static inline int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio) +{ + struct bio_vec *bvec; + int i; + __bio_for_each_segment(bvec, bio, i, 0) { + if (!_drbd_send_page(mdev, bvec->bv_page, + bvec->bv_offset, bvec->bv_len)) + return 0; + } + + return 1; +} + +/* Used to send write requests + * Primary -> Peer (Data) + */ +int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) +{ + int ok = 1; + struct Drbd_Data_Packet p; + unsigned int dp_flags = 0; + void *dgb; + int dgs; + + if (!drbd_get_data_sock(mdev)) + return 0; + + dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_w_tfm) ? + crypto_hash_digestsize(mdev->integrity_w_tfm) : 0; + + p.head.magic = BE_DRBD_MAGIC; + p.head.command = cpu_to_be16(Data); + p.head.length = cpu_to_be16( sizeof(p) + -sizeof(struct Drbd_Header)+dgs+req->size); + + p.sector = cpu_to_be64(req->sector); + p.block_id = (unsigned long)req; + p.seq_num = cpu_to_be32( req->seq_num = + atomic_add_return(1, &mdev->packet_seq) ); + dp_flags = 0; + + /* NOTE: no need to check if barriers supported here as we would + * not pass the test in make_request_common in that case + */ + if (bio_barrier(req->master_bio)) + dp_flags |= DP_HARDBARRIER; + if (bio_sync(req->master_bio)) + dp_flags |= DP_RW_SYNC; + if (mdev->state.conn >= SyncSource && + mdev->state.conn <= PausedSyncT) + dp_flags |= DP_MAY_SET_IN_SYNC; + + p.dp_flags = cpu_to_be32(dp_flags); + dump_packet(mdev, mdev->data.socket, 0, (void *)&p, __FILE__, __LINE__); + set_bit(UNPLUG_REMOTE, &mdev->flags); + ok = (sizeof(p) == + drbd_send(mdev, mdev->data.socket, &p, sizeof(p), MSG_MORE)); + if (ok && dgs) { + dgb = mdev->int_dig_out; + drbd_csum(mdev, mdev->integrity_w_tfm, req->master_bio, dgb); + ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, MSG_MORE); + } + if (ok) { + if (mdev->net_conf->wire_protocol == DRBD_PROT_A) + ok = _drbd_send_bio(mdev, req->master_bio); + else + ok = _drbd_send_zc_bio(mdev, req->master_bio); + } + + drbd_put_data_sock(mdev); + return ok; +} + +/* answer packet, used to send data back for read requests: + * Peer -> (diskless) Primary (DataReply) + * SyncSource -> SyncTarget (RSDataReply) + */ +int drbd_send_block(struct drbd_conf *mdev, enum Drbd_Packet_Cmd cmd, + struct Tl_epoch_entry *e) +{ + int ok; + struct Drbd_Data_Packet p; + void *dgb; + int dgs; + + dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_w_tfm) ? + crypto_hash_digestsize(mdev->integrity_w_tfm) : 0; + + p.head.magic = BE_DRBD_MAGIC; + p.head.command = cpu_to_be16(cmd); + p.head.length = cpu_to_be16( sizeof(p) + -sizeof(struct Drbd_Header) + dgs + e->size); + + p.sector = cpu_to_be64(e->sector); + p.block_id = e->block_id; + /* p.seq_num = 0; No sequence numbers here.. */ + + /* Only called by our kernel thread. + * This one may be interupted by DRBD_SIG and/or DRBD_SIGKILL + * in response to ioctl or module unload. + */ + if (!drbd_get_data_sock(mdev)) + return 0; + + dump_packet(mdev, mdev->data.socket, 0, (void *)&p, __FILE__, __LINE__); + ok = sizeof(p) == drbd_send(mdev, mdev->data.socket, &p, + sizeof(p), MSG_MORE); + if (ok && dgs) { + dgb = mdev->int_dig_out; + drbd_csum(mdev, mdev->integrity_w_tfm, e->private_bio, dgb); + ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, MSG_MORE); + } + if (ok) + ok = _drbd_send_zc_bio(mdev, e->private_bio); + + drbd_put_data_sock(mdev); + return ok; +} + +/* + drbd_send distinguishes two cases: + + Packets sent via the data socket "sock" + and packets sent via the meta data socket "msock" + + sock msock + -----------------+-------------------------+------------------------------ + timeout conf.timeout / 2 conf.timeout / 2 + timeout action send a ping via msock Abort communication + and close all sockets +*/ + +/* + * you must have down()ed the appropriate [m]sock_mutex elsewhere! + */ +int drbd_send(struct drbd_conf *mdev, struct socket *sock, + void *buf, size_t size, unsigned msg_flags) +{ +#if !HAVE_KERNEL_SENDMSG + mm_segment_t oldfs; + struct iovec iov; +#else + struct kvec iov; +#endif + struct msghdr msg; + int rv, sent = 0; + + if (!sock) + return -1000; + + /* THINK if (signal_pending) return ... ? */ + + iov.iov_base = buf; + iov.iov_len = size; + + msg.msg_name = NULL; + msg.msg_namelen = 0; +#if !HAVE_KERNEL_SENDMSG + msg.msg_iov = &iov; + msg.msg_iovlen = 1; +#endif + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = msg_flags | MSG_NOSIGNAL; + +#if !HAVE_KERNEL_SENDMSG + oldfs = get_fs(); + set_fs(KERNEL_DS); +#endif + + if (sock == mdev->data.socket) + mdev->ko_count = mdev->net_conf->ko_count; + do { + /* STRANGE + * tcp_sendmsg does _not_ use its size parameter at all ? + * + * -EAGAIN on timeout, -EINTR on signal. + */ +/* THINK + * do we need to block DRBD_SIG if sock == &meta.socket ?? + * otherwise wake_asender() might interrupt some send_*Ack ! + */ +#if !HAVE_KERNEL_SENDMSG + rv = sock_sendmsg(sock, &msg, iov.iov_len ); +#else + rv = kernel_sendmsg(sock, &msg, &iov, 1, size); +#endif + if (rv == -EAGAIN) { + if (we_should_drop_the_connection(mdev, sock)) + break; + else + continue; + } + D_ASSERT(rv != 0); + if (rv == -EINTR) { +#if 0 + /* FIXME this happens all the time. + * we don't care for now! + * eventually this should be sorted out be the proper + * use of the SIGNAL_ASENDER bit... */ + if (DRBD_ratelimit(5*HZ, 5)) { + DBG("Got a signal in drbd_send(,%c,)!\n", + sock == mdev->meta.socket ? 'm' : 's'); + /* dump_stack(); */ + } +#endif + flush_signals(current); + rv = 0; + } + if (rv < 0) + break; + sent += rv; + iov.iov_base += rv; + iov.iov_len -= rv; + } while (sent < size); + +#if !HAVE_KERNEL_SENDMSG + set_fs(oldfs); +#endif + + if (rv <= 0) { + if (rv != -EAGAIN) { + ERR("%s_sendmsg returned %d\n", + sock == mdev->meta.socket ? "msock" : "sock", + rv); + drbd_force_state(mdev, NS(conn, BrokenPipe)); + } else + drbd_force_state(mdev, NS(conn, Timeout)); + } + + return sent; +} + +int drbd_open(struct inode *inode, struct file *file) +{ + struct drbd_conf *mdev; + unsigned long flags; + int rv = 0; + + mdev = minor_to_mdev(MINOR(inode->i_rdev)); + if (!mdev) + return -ENODEV; + + spin_lock_irqsave(&mdev->req_lock, flags); + /* to have a stable mdev->state.role + * and no race with updating open_cnt */ + + if (mdev->state.role != Primary) { + if (file->f_mode & FMODE_WRITE) + rv = -EROFS; + else if (!allow_oos) + rv = -EMEDIUMTYPE; + } + + if (!rv) + mdev->open_cnt++; + spin_unlock_irqrestore(&mdev->req_lock, flags); + + return rv; +} + +int drbd_close(struct inode *inode, struct file *file) +{ + /* do not use *file (May be NULL, in case of a unmount :-) */ + struct drbd_conf *mdev; + + mdev = minor_to_mdev(MINOR(inode->i_rdev)); + if (!mdev) + return -ENODEV; + + /* + printk(KERN_ERR "drbd: close(inode=%p,file=%p)" + "current=%p,minor=%d,wc=%d\n", inode, file, current, minor, + inode->i_writecount); + */ + + mdev->open_cnt--; + + return 0; +} + +STATIC void drbd_unplug_fn(struct request_queue *q) +{ + struct drbd_conf *mdev = q->queuedata; + + MTRACE(TraceTypeUnplug, TraceLvlSummary, + INFO("got unplugged ap_bio_count=%d\n", + atomic_read(&mdev->ap_bio_cnt)); + ); + + /* unplug FIRST */ + spin_lock_irq(q->queue_lock); + blk_remove_plug(q); + spin_unlock_irq(q->queue_lock); + + /* only if connected */ + spin_lock_irq(&mdev->req_lock); + if (mdev->state.pdsk >= Inconsistent && mdev->state.conn >= Connected) { + D_ASSERT(mdev->state.role == Primary); + if (test_and_clear_bit(UNPLUG_REMOTE, &mdev->flags)) { + /* add to the data.work queue, + * unless already queued. + * XXX this might be a good addition to drbd_queue_work + * anyways, to detect "double queuing" ... */ + if (list_empty(&mdev->unplug_work.list)) + drbd_queue_work(&mdev->data.work, + &mdev->unplug_work); + } + } + spin_unlock_irq(&mdev->req_lock); + + if (mdev->state.disk >= Inconsistent) + drbd_kick_lo(mdev); +} + +STATIC void drbd_set_defaults(struct drbd_conf *mdev) +{ + mdev->sync_conf.after = DRBD_AFTER_DEF; + mdev->sync_conf.rate = DRBD_RATE_DEF; + mdev->sync_conf.al_extents = DRBD_AL_EXTENTS_DEF; + mdev->state = (union drbd_state_t) { + { Secondary, Unknown, StandAlone, Diskless, DUnknown, 0 } }; +} + +void drbd_init_set_defaults(struct drbd_conf *mdev) +{ + /* the memset(,0,) did most of this. + * note: only assignments, no allocation in here */ + +#ifdef PARANOIA + SET_MDEV_MAGIC(mdev); +#endif + + drbd_set_defaults(mdev); + + /* for now, we do NOT yet support it, + * even though we start some framework + * to eventually support barriers */ + set_bit(NO_BARRIER_SUPP, &mdev->flags); + + atomic_set(&mdev->ap_bio_cnt, 0); + atomic_set(&mdev->ap_pending_cnt, 0); + atomic_set(&mdev->rs_pending_cnt, 0); + atomic_set(&mdev->unacked_cnt, 0); + atomic_set(&mdev->local_cnt, 0); + atomic_set(&mdev->net_cnt, 0); + atomic_set(&mdev->packet_seq, 0); + atomic_set(&mdev->pp_in_use, 0); + + init_MUTEX(&mdev->md_io_mutex); + init_MUTEX(&mdev->data.mutex); + init_MUTEX(&mdev->meta.mutex); + sema_init(&mdev->data.work.s, 0); + sema_init(&mdev->meta.work.s, 0); + mutex_init(&mdev->state_mutex); + + spin_lock_init(&mdev->data.work.q_lock); + spin_lock_init(&mdev->meta.work.q_lock); + + spin_lock_init(&mdev->al_lock); + spin_lock_init(&mdev->req_lock); + spin_lock_init(&mdev->peer_seq_lock); + + INIT_LIST_HEAD(&mdev->active_ee); + INIT_LIST_HEAD(&mdev->sync_ee); + INIT_LIST_HEAD(&mdev->done_ee); + INIT_LIST_HEAD(&mdev->read_ee); + INIT_LIST_HEAD(&mdev->net_ee); + INIT_LIST_HEAD(&mdev->resync_reads); + INIT_LIST_HEAD(&mdev->data.work.q); + INIT_LIST_HEAD(&mdev->meta.work.q); + INIT_LIST_HEAD(&mdev->resync_work.list); + INIT_LIST_HEAD(&mdev->unplug_work.list); + INIT_LIST_HEAD(&mdev->md_sync_work.list); + mdev->resync_work.cb = w_resync_inactive; + mdev->unplug_work.cb = w_send_write_hint; + mdev->md_sync_work.cb = w_md_sync; + init_timer(&mdev->resync_timer); + init_timer(&mdev->md_sync_timer); + mdev->resync_timer.function = resync_timer_fn; + mdev->resync_timer.data = (unsigned long) mdev; + mdev->md_sync_timer.function = md_sync_timer_fn; + mdev->md_sync_timer.data = (unsigned long) mdev; + + init_waitqueue_head(&mdev->misc_wait); + init_waitqueue_head(&mdev->state_wait); + init_waitqueue_head(&mdev->ee_wait); + init_waitqueue_head(&mdev->al_wait); + init_waitqueue_head(&mdev->seq_wait); + + drbd_thread_init(mdev, &mdev->receiver, drbdd_init); + drbd_thread_init(mdev, &mdev->worker, drbd_worker); + drbd_thread_init(mdev, &mdev->asender, drbd_asender); + + mdev->agreed_pro_version = PRO_VERSION_MAX; + +#ifdef __arch_um__ + INFO("mdev = 0x%p\n", mdev); +#endif + mdev->resync_wenr = LC_FREE; +} + +void drbd_mdev_cleanup(struct drbd_conf *mdev) +{ + /* I'd like to cleanup completely, and memset(,0,) it. + * but I'd have to reinit it. + * FIXME: do the right thing... + */ + + /* list of things that may still + * hold data of the previous config + + * act_log ** re-initialized in set_disk + * on_io_error + + * al_tr_cycle ** re-initialized in ... FIXME?? + * al_tr_number + * al_tr_pos + + * backing_bdev ** re-initialized in drbd_free_ll_dev + * lo_file + * md_bdev + * md_file + * md_index + + * ko_count ** re-initialized in set_net + + * last_received ** currently ignored + + * mbds_id ** re-initialized in ... FIXME?? + + * resync ** re-initialized in ... FIXME?? + + *** no re-init necessary (?) *** + * md_io_page + * this_bdev + + * vdisk ? + + * rq_queue ** FIXME ASSERT ?? + * newest_barrier + * oldest_barrier + */ + + D_ASSERT(mdev->receiver.t_state == None); + + if (mdev->verify_tfm) { + crypto_free_hash(mdev->verify_tfm); + mdev->verify_tfm=NULL; + } + /* no need to lock it, I'm the only thread alive */ + if (mdev->epoch_size != 0) + ERR("epoch_size:%d\n", mdev->epoch_size); + mdev->al_writ_cnt = + mdev->bm_writ_cnt = + mdev->read_cnt = + mdev->recv_cnt = + mdev->send_cnt = + mdev->writ_cnt = + mdev->p_size = + mdev->rs_start = + mdev->rs_total = + mdev->rs_failed = + mdev->rs_mark_left = + mdev->rs_mark_time = 0; + D_ASSERT(mdev->net_conf == NULL); + drbd_set_my_capacity(mdev, 0); + drbd_bm_resize(mdev, 0); + drbd_bm_cleanup(mdev); + + /* just in case */ + drbd_free_resources(mdev); + + /* + * currently we drbd_init_ee only on module load, so + * we may do drbd_release_ee only on module unload! + */ + D_ASSERT(list_empty(&mdev->active_ee)); + D_ASSERT(list_empty(&mdev->sync_ee)); + D_ASSERT(list_empty(&mdev->done_ee)); + D_ASSERT(list_empty(&mdev->read_ee)); + D_ASSERT(list_empty(&mdev->net_ee)); + D_ASSERT(list_empty(&mdev->resync_reads)); + D_ASSERT(list_empty(&mdev->data.work.q)); + D_ASSERT(list_empty(&mdev->meta.work.q)); + D_ASSERT(list_empty(&mdev->resync_work.list)); + D_ASSERT(list_empty(&mdev->unplug_work.list)); + +} + + +STATIC void drbd_destroy_mempools(void) +{ + struct page *page; + + while (drbd_pp_pool) { + page = drbd_pp_pool; + drbd_pp_pool = (struct page *)page_private(page); + __free_page(page); + drbd_pp_vacant--; + } + + /* D_ASSERT(atomic_read(&drbd_pp_vacant)==0); */ + + if (drbd_ee_mempool) + mempool_destroy(drbd_ee_mempool); + if (drbd_request_mempool) + mempool_destroy(drbd_request_mempool); + if (drbd_ee_cache) + kmem_cache_destroy(drbd_ee_cache); + if (drbd_request_cache) + kmem_cache_destroy(drbd_request_cache); + + drbd_ee_mempool = NULL; + drbd_request_mempool = NULL; + drbd_ee_cache = NULL; + drbd_request_cache = NULL; + + return; +} + +STATIC int drbd_create_mempools(void) +{ + struct page *page; + const int number = (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE) * minor_count; + int i; + + /* prepare our caches and mempools */ + drbd_request_mempool = NULL; + drbd_ee_cache = NULL; + drbd_request_cache = NULL; + drbd_pp_pool = NULL; + + /* caches */ + drbd_request_cache = kmem_cache_create( + "drbd_req_cache", sizeof(struct drbd_request), 0, 0, NULL); + if (drbd_request_cache == NULL) + goto Enomem; + + drbd_ee_cache = kmem_cache_create( + "drbd_ee_cache", sizeof(struct Tl_epoch_entry), 0, 0, NULL); + if (drbd_ee_cache == NULL) + goto Enomem; + + /* mempools */ + drbd_request_mempool = mempool_create( number, + mempool_alloc_slab, mempool_free_slab, drbd_request_cache); + if (drbd_request_mempool == NULL) + goto Enomem; + + drbd_ee_mempool = mempool_create( number, + mempool_alloc_slab, mempool_free_slab, drbd_ee_cache); + if (drbd_request_mempool == NULL) + goto Enomem; + + /* drbd's page pool */ + spin_lock_init(&drbd_pp_lock); + + for (i = 0; i < number; i++) { + page = alloc_page(GFP_HIGHUSER); + if (!page) + goto Enomem; + set_page_private(page, (unsigned long)drbd_pp_pool); + drbd_pp_pool = page; + } + drbd_pp_vacant = number; + + return 0; + +Enomem: + drbd_destroy_mempools(); /* in case we allocated some */ + return -ENOMEM; +} + +STATIC int drbd_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + /* just so we have it. you never know what interessting things we + * might want to do here some day... + */ + + return NOTIFY_DONE; +} + +STATIC struct notifier_block drbd_notifier = { + .notifier_call = drbd_notify_sys, +}; + + +STATIC void drbd_cleanup(void) +{ + int i, rr; + + unregister_reboot_notifier(&drbd_notifier); + + drbd_nl_cleanup(); + + if (minor_table) { + if (drbd_proc) { + remove_proc_entry("drbd", NULL); + drbd_proc = NULL; + } + i = minor_count; + while (i--) { + struct drbd_conf *mdev = minor_to_mdev(i); + struct gendisk **disk = &mdev->vdisk; + struct request_queue **q = &mdev->rq_queue; + + if (!mdev) + continue; + drbd_free_resources(mdev); + + if (*disk) { + del_gendisk(*disk); + put_disk(*disk); + *disk = NULL; + } + if (*q) + blk_cleanup_queue(*q); + *q = NULL; + + D_ASSERT(mdev->open_cnt == 0); + if (mdev->this_bdev) + bdput(mdev->this_bdev); + + tl_cleanup(mdev); + if (mdev->resync) + lc_free(mdev->resync); + + rr = drbd_release_ee(mdev, &mdev->active_ee); + if (rr) + ERR("%d EEs in active list found!\n", rr); + + rr = drbd_release_ee(mdev, &mdev->sync_ee); + if (rr) + ERR("%d EEs in sync list found!\n", rr); + + rr = drbd_release_ee(mdev, &mdev->read_ee); + if (rr) + ERR("%d EEs in read list found!\n", rr); + + rr = drbd_release_ee(mdev, &mdev->done_ee); + if (rr) + ERR("%d EEs in done list found!\n", rr); + + rr = drbd_release_ee(mdev, &mdev->net_ee); + if (rr) + ERR("%d EEs in net list found!\n", rr); + + ERR_IF (!list_empty(&mdev->data.work.q)) { + struct list_head *lp; + list_for_each(lp, &mdev->data.work.q) { + DUMPP(lp); + } + }; + + if (mdev->md_io_page) + __free_page(mdev->md_io_page); + + if (mdev->md_io_tmpp) + __free_page(mdev->md_io_tmpp); + + if (mdev->act_log) + lc_free(mdev->act_log); + + kfree(mdev->ee_hash); + mdev->ee_hash_s = 0; + mdev->ee_hash = NULL; + + kfree(mdev->tl_hash); + mdev->tl_hash_s = 0; + mdev->tl_hash = NULL; + + kfree(mdev->app_reads_hash); + mdev->app_reads_hash = NULL; + + kfree(mdev->p_uuid); + mdev->p_uuid = NULL; + + kfree(mdev->int_dig_out); + kfree(mdev->int_dig_in); + kfree(mdev->int_dig_vv); + } + drbd_destroy_mempools(); + } + + kfree(minor_table); + + drbd_unregister_blkdev(DRBD_MAJOR, "drbd"); + + printk(KERN_INFO "drbd: module cleanup done.\n"); +} + +struct drbd_conf *drbd_new_device(int minor) +{ + struct drbd_conf *mdev = NULL; + struct gendisk *disk; + struct request_queue *q; + + mdev = kzalloc(sizeof(struct drbd_conf), GFP_KERNEL); + if (!mdev) + goto Enomem; + + mdev->minor = minor; + + drbd_init_set_defaults(mdev); + + q = blk_alloc_queue(GFP_KERNEL); + if (!q) + goto Enomem; + mdev->rq_queue = q; + q->queuedata = mdev; + q->max_segment_size = DRBD_MAX_SEGMENT_SIZE; + + disk = alloc_disk(1); + if (!disk) + goto Enomem; + mdev->vdisk = disk; + + set_disk_ro( disk, TRUE ); + + disk->queue = q; + disk->major = DRBD_MAJOR; + disk->first_minor = minor; + disk->fops = &drbd_ops; + sprintf(disk->disk_name, "drbd%d", minor); + disk->private_data = mdev; + add_disk(disk); + + mdev->this_bdev = bdget(MKDEV(DRBD_MAJOR, minor)); + /* we have no partitions. we contain only ourselves. */ + mdev->this_bdev->bd_contains = mdev->this_bdev; + + blk_queue_make_request(q, drbd_make_request_26); + blk_queue_merge_bvec(q, drbd_merge_bvec); + q->queue_lock = &mdev->req_lock; /* needed since we use */ + /* plugging on a queue, that actually has no requests! */ + q->unplug_fn = drbd_unplug_fn; + + mdev->md_io_page = alloc_page(GFP_KERNEL); + if (!mdev->md_io_page) + goto Enomem; + + if (!tl_init(mdev)) goto Enomem; + + mdev->app_reads_hash = kzalloc(APP_R_HSIZE*sizeof(void *), GFP_KERNEL); + if (!mdev->app_reads_hash) + goto Enomem; + + return mdev; + + Enomem: + if (mdev) { + kfree(mdev->app_reads_hash); + if (mdev->md_io_page) + __free_page(mdev->md_io_page); + kfree(mdev); + } + return NULL; +} + +int __init drbd_init(void) +{ + int err; + +#ifdef __arch_um__ + printk(KERN_INFO "drbd_module = 0x%p core = 0x%p\n", + THIS_MODULE, THIS_MODULE->module_core); +#endif + + /* FIXME should be a compile time assert */ + if (sizeof(struct Drbd_HandShake_Packet) != 80) { + printk(KERN_ERR + "drbd: never change the size or layout " + "of the HandShake packet.\n"); + return -EINVAL; + } + + if (1 > minor_count || minor_count > 255) { + printk(KERN_ERR + "drbd: invalid minor_count (%d)\n", minor_count); +#ifdef MODULE + return -EINVAL; +#else + minor_count = 8; +#endif + } + + err = drbd_nl_init(); + if (err) + return err; + + err = register_blkdev(DRBD_MAJOR, "drbd"); + if (err) { + printk(KERN_ERR + "drbd: unable to register block device major %d\n", + DRBD_MAJOR); + return err; + } + + register_reboot_notifier(&drbd_notifier); + + /* + * allocate all necessary structs + */ + err = -ENOMEM; + + init_waitqueue_head(&drbd_pp_wait); + + minor_table = kzalloc(sizeof(struct drbd_conf *)*minor_count, + GFP_KERNEL); + if (!minor_table) + goto Enomem; + + err = drbd_create_mempools(); + if (err) + goto Enomem; + +#if CONFIG_PROC_FS + /* + * register with procfs + */ + drbd_proc = proc_create("drbd", S_IFREG | S_IRUGO , NULL, &drbd_proc_fops); + + if (!drbd_proc) { + printk(KERN_ERR "drbd: unable to register proc file\n"); + goto Enomem; + } + + drbd_proc->owner = THIS_MODULE; +#else +# error "Currently drbd depends on the proc file system (CONFIG_PROC_FS)" +#endif + + printk(KERN_INFO "drbd: initialised. " + "Version: " REL_VERSION " (api:%d/proto:%d-%d)\n", + API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX); + printk(KERN_INFO "drbd: %s\n", drbd_buildtag()); + printk(KERN_INFO "drbd: registered as block device major %d\n", + DRBD_MAJOR); + printk(KERN_INFO "drbd: minor_table @ 0x%p\n", minor_table); + + return 0; /* Success! */ + +Enomem: + drbd_cleanup(); + if (err == -ENOMEM) + /* currently always the case */ + printk(KERN_ERR "drbd: ran out of memory\n"); + else + printk(KERN_ERR "drbd: initialization failure\n"); + return err; +} + +void drbd_free_bc(struct drbd_backing_dev *bc) +{ + if (bc == NULL) + return; + + bd_release(bc->backing_bdev); + bd_release(bc->md_bdev); + + fput(bc->lo_file); + fput(bc->md_file); + + kfree(bc); +} + +void drbd_free_sock(struct drbd_conf *mdev) +{ + if (mdev->data.socket) { + sock_release(mdev->data.socket); + mdev->data.socket = NULL; + } + if (mdev->meta.socket) { + sock_release(mdev->meta.socket); + mdev->meta.socket = NULL; + } +} + + +void drbd_free_resources(struct drbd_conf *mdev) +{ + crypto_free_hash(mdev->cram_hmac_tfm); + mdev->cram_hmac_tfm = NULL; + crypto_free_hash(mdev->integrity_w_tfm); + mdev->integrity_w_tfm=NULL; + crypto_free_hash(mdev->integrity_r_tfm); + mdev->integrity_r_tfm=NULL; + drbd_free_sock(mdev); + __no_warn(local, + drbd_free_bc(mdev->bc); + mdev->bc = NULL;); +} + +/*********************************/ +/* meta data management */ + +struct meta_data_on_disk { + u64 la_size; /* last agreed size. */ + u64 uuid[UUID_SIZE]; /* UUIDs. */ + u64 device_uuid; + u64 reserved_u64_1; + u32 flags; /* MDF */ + u32 magic; + u32 md_size_sect; + u32 al_offset; /* offset to this block */ + u32 al_nr_extents; /* important for restoring the AL */ + /* `-- act_log->nr_elements <-- sync_conf.al_extents */ + u32 bm_offset; /* offset to the bitmap, from here */ + u32 bm_bytes_per_bit; /* BM_BLOCK_SIZE */ + u32 reserved_u32[4]; + +} __attribute((packed)); + +/** + * drbd_md_sync: + * Writes the meta data super block if the MD_DIRTY flag bit is set. + */ +void drbd_md_sync(struct drbd_conf *mdev) +{ + struct meta_data_on_disk *buffer; + sector_t sector; + int i; + + if (!test_and_clear_bit(MD_DIRTY, &mdev->flags)) return; + del_timer(&mdev->md_sync_timer); + + /* We use here Failed and not Attaching because we try to write + * metadata even if we detach due to a disk failure! */ + if (!inc_local_if_state(mdev, Failed)) return; + + INFO("Writing meta data super block now.\n"); + + down(&mdev->md_io_mutex); + buffer = (struct meta_data_on_disk *)page_address(mdev->md_io_page); + memset(buffer, 0, 512); + + buffer->la_size = cpu_to_be64(drbd_get_capacity(mdev->this_bdev)); + for (i = Current; i < UUID_SIZE; i++) + buffer->uuid[i] = cpu_to_be64(mdev->bc->md.uuid[i]); + buffer->flags = cpu_to_be32(mdev->bc->md.flags); + buffer->magic = cpu_to_be32(DRBD_MD_MAGIC); + + buffer->md_size_sect = cpu_to_be32(mdev->bc->md.md_size_sect); + buffer->al_offset = cpu_to_be32(mdev->bc->md.al_offset); + buffer->al_nr_extents = cpu_to_be32(mdev->act_log->nr_elements); + buffer->bm_bytes_per_bit = cpu_to_be32(BM_BLOCK_SIZE); + buffer->device_uuid = cpu_to_be64(mdev->bc->md.device_uuid); + + buffer->bm_offset = cpu_to_be32(mdev->bc->md.bm_offset); + + D_ASSERT(drbd_md_ss__(mdev, mdev->bc) == mdev->bc->md.md_offset); + sector = mdev->bc->md.md_offset; + + if (drbd_md_sync_page_io(mdev, mdev->bc, sector, WRITE)) { + clear_bit(MD_DIRTY, &mdev->flags); + } else { + /* this was a try anyways ... */ + ERR("meta data update failed!\n"); + + drbd_chk_io_error(mdev, 1, TRUE); + drbd_io_error(mdev, TRUE); + } + + /* Update mdev->bc->md.la_size_sect, + * since we updated it on metadata. */ + mdev->bc->md.la_size_sect = drbd_get_capacity(mdev->this_bdev); + + up(&mdev->md_io_mutex); + dec_local(mdev); +} + +/** + * drbd_md_read: + * @bdev: describes the backing storage and the meta-data storage + * Reads the meta data from bdev. Return 0 (NoError) on success, and an + * enum ret_codes in case something goes wrong. + * Currently only: MDIOError, MDInvalid. + */ +int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) +{ + struct meta_data_on_disk *buffer; + int i, rv = NoError; + + if (!inc_local_if_state(mdev, Attaching)) return MDIOError; + + down(&mdev->md_io_mutex); + buffer = (struct meta_data_on_disk *)page_address(mdev->md_io_page); + + if (!drbd_md_sync_page_io(mdev, bdev, bdev->md.md_offset, READ)) { + /* NOTE: cant do normal error processing here as this is + called BEFORE disk is attached */ + ERR("Error while reading metadata.\n"); + rv = MDIOError; + goto err; + } + + if (be32_to_cpu(buffer->magic) != DRBD_MD_MAGIC) { + ERR("Error while reading metadata, magic not found.\n"); + rv = MDInvalid; + goto err; + } + if (be32_to_cpu(buffer->al_offset) != bdev->md.al_offset) { + ERR("unexpected al_offset: %d (expected %d)\n", + be32_to_cpu(buffer->al_offset), bdev->md.al_offset); + rv = MDInvalid; + goto err; + } + if (be32_to_cpu(buffer->bm_offset) != bdev->md.bm_offset) { + ERR("unexpected bm_offset: %d (expected %d)\n", + be32_to_cpu(buffer->bm_offset), bdev->md.bm_offset); + rv = MDInvalid; + goto err; + } + if (be32_to_cpu(buffer->md_size_sect) != bdev->md.md_size_sect) { + ERR("unexpected md_size: %u (expected %u)\n", + be32_to_cpu(buffer->md_size_sect), bdev->md.md_size_sect); + rv = MDInvalid; + goto err; + } + + if (be32_to_cpu(buffer->bm_bytes_per_bit) != BM_BLOCK_SIZE) { + ERR("unexpected bm_bytes_per_bit: %u (expected %u)\n", + be32_to_cpu(buffer->bm_bytes_per_bit), BM_BLOCK_SIZE); + rv = MDInvalid; + goto err; + } + + bdev->md.la_size_sect = be64_to_cpu(buffer->la_size); + for (i = Current; i < UUID_SIZE; i++) + bdev->md.uuid[i] = be64_to_cpu(buffer->uuid[i]); + bdev->md.flags = be32_to_cpu(buffer->flags); + mdev->sync_conf.al_extents = be32_to_cpu(buffer->al_nr_extents); + bdev->md.device_uuid = be64_to_cpu(buffer->device_uuid); + + if (mdev->sync_conf.al_extents < 7) + mdev->sync_conf.al_extents = 127; + /* FIXME if this ever happens when reading meta data, + * it possibly screws up reading of the activity log? + */ + + err: + up(&mdev->md_io_mutex); + dec_local(mdev); + + return rv; +} + +/** + * drbd_md_mark_dirty: + * Call this function if you change enything that should be written to + * the meta-data super block. This function sets MD_DIRTY, and starts a + * timer that ensures that within five seconds you have to call drbd_md_sync(). + */ +void drbd_md_mark_dirty(struct drbd_conf *mdev) +{ + set_bit(MD_DIRTY, &mdev->flags); + mod_timer(&mdev->md_sync_timer, jiffies + 5*HZ ); +} + + +STATIC void drbd_uuid_move_history(struct drbd_conf *mdev) __must_hold(local) +{ + int i; + + for ( i = History_start ; i < History_end ; i++ ) { + mdev->bc->md.uuid[i+1] = mdev->bc->md.uuid[i]; + + MTRACE(TraceTypeUuid, TraceLvlAll, + drbd_print_uuid(mdev, i+1); + ); + } +} + +void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) +{ + if (idx == Current) { + if (mdev->state.role == Primary) + val |= 1; + else + val &= ~((u64)1); + + drbd_set_ed_uuid(mdev, val); + } + + mdev->bc->md.uuid[idx] = val; + + MTRACE(TraceTypeUuid, TraceLvlSummary, + drbd_print_uuid(mdev, idx); + ); + + drbd_md_mark_dirty(mdev); +} + + +void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) +{ + if (mdev->bc->md.uuid[idx]) { + drbd_uuid_move_history(mdev); + mdev->bc->md.uuid[History_start] = mdev->bc->md.uuid[idx]; + MTRACE(TraceTypeUuid, TraceLvlMetrics, + drbd_print_uuid(mdev, History_start); + ); + } + _drbd_uuid_set(mdev, idx, val); +} + +/** + * _drbd_uuid_new_current: + * Creates a new current UUID, but does NOT rotate the old current + * UUID into the bitmap slot (but into history). This causes a full + * sync upon next connect. Aditionally the full sync is also requested + * by the FullSync bit. + */ +void _drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local) +{ + u64 uuid; + + /* Actually a seperate bit names DisklessPeer, would be + the right thing. But for now the FullSync bit is a + working substitute, to avoid repetitive generating + of new current UUIDs in case we loose connection + and reconnect in a loop. */ + if (mdev->bc->md.flags & MDF_FullSync) return; + INFO("Creating new current UUID [no BitMap]\n"); + get_random_bytes(&uuid, sizeof(u64)); + drbd_uuid_set(mdev, Current, uuid); + drbd_md_set_flag(mdev, MDF_FullSync); +} + +/** + * drbd_uuid_new_current: + * Creates a new current UUID, and rotates the old current UUID into + * the bitmap slot. Causes an incremental resync upon next connect. + */ +void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local) +{ + u64 val; + + INFO("Creating new current UUID\n"); + D_ASSERT(mdev->bc->md.uuid[Bitmap] == 0); + mdev->bc->md.uuid[Bitmap] = mdev->bc->md.uuid[Current]; + MTRACE(TraceTypeUuid, TraceLvlMetrics, + drbd_print_uuid(mdev, Bitmap); + ); + + get_random_bytes(&val, sizeof(u64)); + _drbd_uuid_set(mdev, Current, val); +} + +void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local) +{ + if (mdev->bc->md.uuid[Bitmap] == 0 && val == 0) + return; + + if (val == 0) { + drbd_uuid_move_history(mdev); + mdev->bc->md.uuid[History_start] = mdev->bc->md.uuid[Bitmap]; + mdev->bc->md.uuid[Bitmap] = 0; + + MTRACE(TraceTypeUuid, TraceLvlMetrics, + drbd_print_uuid(mdev, History_start); + drbd_print_uuid(mdev, Bitmap); + ); + } else { + if (mdev->bc->md.uuid[Bitmap]) + DRBD_WARN("bm UUID already set"); + + mdev->bc->md.uuid[Bitmap] = val; + mdev->bc->md.uuid[Bitmap] &= ~((u64)1); + + MTRACE(TraceTypeUuid, TraceLvlMetrics, + drbd_print_uuid(mdev, Bitmap); + ); + } + drbd_md_mark_dirty(mdev); +} + +/** + * drbd_bmio_set_n_write: + * Is an io_fn for drbd_queue_bitmap_io() or drbd_bitmap_io() that sets + * all bits in the bitmap and writes the whole bitmap to stable storage. + */ +int drbd_bmio_set_n_write(struct drbd_conf *mdev) +{ + int rv = -EIO; + + if (inc_local_if_state(mdev, Attaching)) { + drbd_md_set_flag(mdev, MDF_FullSync); + drbd_md_sync(mdev); + drbd_bm_set_all(mdev); + + rv = drbd_bm_write(mdev); + + if (!rv) { + drbd_md_clear_flag(mdev, MDF_FullSync); + drbd_md_sync(mdev); + } + + dec_local(mdev); + } + + return rv; +} + +STATIC int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused) +{ + struct bm_io_work *work = (struct bm_io_work *)w; + int rv; + + D_ASSERT(atomic_read(&mdev->ap_bio_cnt)==0); + + drbd_bm_lock(mdev); + rv = work->io_fn(mdev); + drbd_bm_unlock(mdev); + + clear_bit(BITMAP_IO, &mdev->flags); + wake_up(&mdev->misc_wait); + + if (work->done) work->done(mdev, rv); + + return 1; +} + +/** + * drbd_queue_bitmap_io: + * Queues an IO operation on the whole bitmap. + * While IO on the bitmap happens we freeze appliation IO thus we ensure + * that drbd_set_out_of_sync() can not be called. This function might be + * called from the worker thread and other contexts. + */ +void drbd_queue_bitmap_io(struct drbd_conf *mdev, + int (*io_fn)(struct drbd_conf *), + void (*done)(struct drbd_conf *, int)) +{ + unsigned long flags; + + D_ASSERT(!test_bit(BITMAP_IO, &mdev->flags)); + + mdev->bm_io_work.w.cb = w_bitmap_io; + mdev->bm_io_work.io_fn = io_fn; + mdev->bm_io_work.done = done; + + spin_lock_irqsave(&mdev->req_lock, flags); + clear_bit(BITMAP_IO_QUEUED, &mdev->flags); + set_bit(BITMAP_IO, &mdev->flags); + if (atomic_read(&mdev->ap_bio_cnt) == 0) { + set_bit(BITMAP_IO_QUEUED, &mdev->flags); + drbd_queue_work(&mdev->data.work, &mdev->bm_io_work.w); + } + spin_unlock_irqrestore(&mdev->req_lock, flags); +} + +/** + * drbd_bitmap_io: + * Does an IO operation on the bitmap, freezing application IO while that + * IO operations runs. This functions might not be called from the context + * of the worker thread. + */ +int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *)) +{ + int rv; + + D_ASSERT(current != mdev->worker.task); + D_ASSERT(!test_bit(BITMAP_IO, &mdev->flags)); + + set_bit(BITMAP_IO_QUEUED, &mdev->flags); + set_bit(BITMAP_IO, &mdev->flags); + wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt)); + + drbd_bm_lock(mdev); + rv = io_fn(mdev); + drbd_bm_unlock(mdev); + + clear_bit(BITMAP_IO, &mdev->flags); + wake_up(&mdev->misc_wait); + + return rv; +} + +void drbd_md_set_flag(struct drbd_conf *mdev, int flag) __must_hold(local) +{ + MUST_HOLD(mdev->req_lock); + if ( (mdev->bc->md.flags & flag) != flag) { + drbd_md_mark_dirty(mdev); + mdev->bc->md.flags |= flag; + } +} + +void drbd_md_clear_flag(struct drbd_conf *mdev, int flag) __must_hold(local) +{ + MUST_HOLD(mdev->req_lock); + if ( (mdev->bc->md.flags & flag) != 0 ) { + drbd_md_mark_dirty(mdev); + mdev->bc->md.flags &= ~flag; + } +} +int drbd_md_test_flag(struct drbd_backing_dev *bdev, int flag) +{ + return ((bdev->md.flags & flag) != 0); +} + +void md_sync_timer_fn(unsigned long data) +{ + struct drbd_conf *mdev = (struct drbd_conf *) data; + + drbd_queue_work_front(&mdev->data.work, &mdev->md_sync_work); +} + +int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused) +{ + DRBD_WARN("md_sync_timer expired! Worker calls drbd_md_sync().\n"); + drbd_md_sync(mdev); + + return 1; +} + +#ifdef DRBD_ENABLE_FAULTS +/* Fault insertion support including random number generator shamelessly + * stolen from kernel/rcutorture.c */ +struct fault_random_state { + unsigned long state; + unsigned long count; +}; + +#define FAULT_RANDOM_MULT 39916801 /* prime */ +#define FAULT_RANDOM_ADD 479001701 /* prime */ +#define FAULT_RANDOM_REFRESH 10000 + +/* + * Crude but fast random-number generator. Uses a linear congruential + * generator, with occasional help from get_random_bytes(). + */ +STATIC unsigned long +_drbd_fault_random(struct fault_random_state *rsp) +{ + long refresh; + + if (--rsp->count < 0) { + get_random_bytes(&refresh, sizeof(refresh)); + rsp->state += refresh; + rsp->count = FAULT_RANDOM_REFRESH; + } + rsp->state = rsp->state * FAULT_RANDOM_MULT + FAULT_RANDOM_ADD; + return swahw32(rsp->state); +} + +STATIC char * +_drbd_fault_str(unsigned int type) { + static char *_faults[] = { + "Meta-data write", + "Meta-data read", + "Resync write", + "Resync read", + "Data write", + "Data read", + "Data read ahead", + }; + + return (type < DRBD_FAULT_MAX)? _faults[type] : "**Unknown**"; +} + +unsigned int +_drbd_insert_fault(struct drbd_conf *mdev, unsigned int type) +{ + static struct fault_random_state rrs = {0, 0}; + + unsigned int ret = ( + (fault_devs == 0 || + ((1 << mdev_to_minor(mdev)) & fault_devs) != 0) && + (((_drbd_fault_random(&rrs) % 100) + 1) <= fault_rate)); + + if (ret) { + fault_count++; + + if (printk_ratelimit()) + DRBD_WARN("***Simulating %s failure\n", + _drbd_fault_str(type)); + } + + return ret; +} +#endif + +#ifdef ENABLE_DYNAMIC_TRACE + +STATIC char *_drbd_uuid_str(unsigned int idx) +{ + static char *uuid_str[] = { + "Current", + "Bitmap", + "History_start", + "History_end", + "UUID_SIZE", + "UUID_FLAGS", + }; + + return (idx < EXT_UUID_SIZE) ? uuid_str[idx] : "*Unknown UUID index*"; +} + +/* Pretty print a UUID value */ +void drbd_print_uuid(struct drbd_conf *mdev, unsigned int idx) __must_hold(local) +{ + INFO(" uuid[%s] now %016llX\n", + _drbd_uuid_str(idx), mdev->bc->md.uuid[idx]); +} + + +/* + * + * drbd_print_buffer + * + * This routine dumps binary data to the debugging output. Can be + * called at interrupt level. + * + * Arguments: + * + * prefix - String is output at the beginning of each line output + * flags - Control operation of the routine. Currently defined + * Flags are: + * DBGPRINT_BUFFADDR; if set, each line starts with the + * virtual address of the line being outupt. If clear, + * each line starts with the offset from the beginning + * of the buffer. + * size - Indicates the size of each entry in the buffer. Supported + * values are sizeof(char), sizeof(short) and sizeof(int) + * buffer - Start address of buffer + * buffer_va - Virtual address of start of buffer (normally the same + * as Buffer, but having it separate allows it to hold + * file address for example) + * length - length of buffer + * + */ +void +drbd_print_buffer(const char *prefix, unsigned int flags, int size, + const void *buffer, const void *buffer_va, + unsigned int length) + +#define LINE_SIZE 16 +#define LINE_ENTRIES (int)(LINE_SIZE/size) +{ + const unsigned char *pstart; + const unsigned char *pstart_va; + const unsigned char *pend; + char bytes_str[LINE_SIZE*3+8], ascii_str[LINE_SIZE+8]; + char *pbytes = bytes_str, *pascii = ascii_str; + int offset = 0; + long sizemask; + int field_width; + int index; + const unsigned char *pend_str; + const unsigned char *p; + int count; + + /* verify size parameter */ + if (size != sizeof(char) && + size != sizeof(short) && + size != sizeof(int)) { + printk(KERN_DEBUG "drbd_print_buffer: " + "ERROR invalid size %d\n", size); + return; + } + + sizemask = size-1; + field_width = size*2; + + /* Adjust start/end to be on appropriate boundary for size */ + buffer = (const char *)((long)buffer & ~sizemask); + pend = (const unsigned char *) + (((long)buffer + length + sizemask) & ~sizemask); + + if (flags & DBGPRINT_BUFFADDR) { + /* Move start back to nearest multiple of line size, + * if printing address. This results in nicely formatted output + * with addresses being on line size (16) byte boundaries */ + pstart = (const unsigned char *)((long)buffer & ~(LINE_SIZE-1)); + } else { + pstart = (const unsigned char *)buffer; + } + + /* Set value of start VA to print if addresses asked for */ + pstart_va = (const unsigned char *)buffer_va + - ((const unsigned char *)buffer-pstart); + + /* Calculate end position to nicely align right hand side */ + pend_str = pstart + (((pend-pstart) + LINE_SIZE-1) & ~(LINE_SIZE-1)); + + /* Init strings */ + *pbytes = *pascii = '\0'; + + /* Start at beginning of first line */ + p = pstart; + count = 0; + + while (p < pend_str) { + if (p < (const unsigned char *)buffer || p >= pend) { + /* Before start of buffer or after end- print spaces */ + pbytes += sprintf(pbytes, "%*c ", field_width, ' '); + pascii += sprintf(pascii, "%*c", size, ' '); + p += size; + } else { + /* Add hex and ascii to strings */ + int val; + switch (size) { + default: + case 1: + val = *(unsigned char *)p; + break; + case 2: + val = *(unsigned short *)p; + break; + case 4: + val = *(unsigned int *)p; + break; + } + + pbytes += sprintf(pbytes, "%0*x ", field_width, val); + + for (index = size; index; index--) { + *pascii++ = isprint(*p) ? *p : '.'; + p++; + } + } + + count++; + + if (count == LINE_ENTRIES || p >= pend_str) { + /* Null terminate and print record */ + *pascii = '\0'; + printk(KERN_DEBUG "%s%8.8lx: %*s|%*s|\n", + prefix, + (flags & DBGPRINT_BUFFADDR) + ? (long)pstart_va : (long)offset, + LINE_ENTRIES*(field_width+1), bytes_str, + LINE_SIZE, ascii_str); + + /* Move onto next line */ + pstart_va += (p-pstart); + pstart = p; + count = 0; + offset += LINE_SIZE; + + /* Re-init strings */ + pbytes = bytes_str; + pascii = ascii_str; + *pbytes = *pascii = '\0'; + } + } +} + +#define PSM(A) \ +do { \ + if (mask.A) { \ + int i = snprintf(p, len, " " #A "( %s )", \ + A##s_to_name(val.A)); \ + if (i >= len) \ + return op; \ + p += i; \ + len -= i; \ + } \ +} while (0) + +STATIC char *dump_st(char *p, int len, union drbd_state_t mask, union drbd_state_t val) +{ + char *op = p; + *p = '\0'; + PSM(role); + PSM(peer); + PSM(conn); + PSM(disk); + PSM(pdsk); + + return op; +} + +#define INFOP(fmt, args...) \ +do { \ + if (trace_level >= TraceLvlAll) { \ + INFO("%s:%d: %s [%d] %s %s " fmt , \ + file, line, current->comm, current->pid, \ + sockname, recv?"<<<":">>>", \ + ## args ); \ + } \ + else { \ + INFO("%s %s " fmt, sockname, \ + recv?"<<<":">>>", \ + ## args ); \ + } \ +} while (0) + +STATIC char *_dump_block_id(u64 block_id, char *buff) +{ + if (is_syncer_block_id(block_id)) + strcpy(buff, "SyncerId"); + else + sprintf(buff, "%llx", block_id); + + return buff; +} + +void +_dump_packet(struct drbd_conf *mdev, struct socket *sock, + int recv, union Drbd_Polymorph_Packet *p, char *file, int line) +{ + char *sockname = sock == mdev->meta.socket ? "meta" : "data"; + int cmd = (recv == 2) ? p->head.command : be16_to_cpu(p->head.command); + char tmp[300]; + union drbd_state_t m, v; + + switch (cmd) { + case HandShake: + INFOP("%s (protocol %u-%u)\n", cmdname(cmd), + be32_to_cpu(p->HandShake.protocol_min), + be32_to_cpu(p->HandShake.protocol_max)); + break; + + case ReportBitMap: /* don't report this */ + break; + + case Data: + INFOP("%s (sector %llus, id %s, seq %u, f %x)\n", cmdname(cmd), + (unsigned long long)be64_to_cpu(p->Data.sector), + _dump_block_id(p->Data.block_id, tmp), + be32_to_cpu(p->Data.seq_num), + be32_to_cpu(p->Data.dp_flags) + ); + break; + + case DataReply: + case RSDataReply: + INFOP("%s (sector %llus, id %s)\n", cmdname(cmd), + (unsigned long long)be64_to_cpu(p->Data.sector), + _dump_block_id(p->Data.block_id, tmp) + ); + break; + + case RecvAck: + case WriteAck: + case RSWriteAck: + case DiscardAck: + case NegAck: + case NegRSDReply: + INFOP("%s (sector %llus, size %u, id %s, seq %u)\n", + cmdname(cmd), + (long long)be64_to_cpu(p->BlockAck.sector), + be32_to_cpu(p->BlockAck.blksize), + _dump_block_id(p->BlockAck.block_id, tmp), + be32_to_cpu(p->BlockAck.seq_num) + ); + break; + + case DataRequest: + case RSDataRequest: + INFOP("%s (sector %llus, size %u, id %s)\n", cmdname(cmd), + (long long)be64_to_cpu(p->BlockRequest.sector), + be32_to_cpu(p->BlockRequest.blksize), + _dump_block_id(p->BlockRequest.block_id, tmp) + ); + break; + + case Barrier: + case BarrierAck: + INFOP("%s (barrier %u)\n", cmdname(cmd), p->Barrier.barrier); + break; + + case ReportUUIDs: + INFOP("%s Curr:%016llX, Bitmap:%016llX, " + "HisSt:%016llX, HisEnd:%016llX\n", + cmdname(cmd), + be64_to_cpu(p->GenCnt.uuid[Current]), + be64_to_cpu(p->GenCnt.uuid[Bitmap]), + be64_to_cpu(p->GenCnt.uuid[History_start]), + be64_to_cpu(p->GenCnt.uuid[History_end])); + break; + + case ReportSizes: + INFOP("%s (d %lluMiB, u %lluMiB, c %lldMiB, " + "max bio %x, q order %x)\n", + cmdname(cmd), + (long long)(be64_to_cpu(p->Sizes.d_size)>>(20-9)), + (long long)(be64_to_cpu(p->Sizes.u_size)>>(20-9)), + (long long)(be64_to_cpu(p->Sizes.c_size)>>(20-9)), + be32_to_cpu(p->Sizes.max_segment_size), + be32_to_cpu(p->Sizes.queue_order_type)); + break; + + case ReportState: + v.i = be32_to_cpu(p->State.state); + m.i = 0xffffffff; + dump_st(tmp, sizeof(tmp), m, v); + INFOP("%s (s %x {%s})\n", cmdname(cmd), v.i, tmp); + break; + + case StateChgRequest: + m.i = be32_to_cpu(p->ReqState.mask); + v.i = be32_to_cpu(p->ReqState.val); + dump_st(tmp, sizeof(tmp), m, v); + INFOP("%s (m %x v %x {%s})\n", cmdname(cmd), m.i, v.i, tmp); + break; + + case StateChgReply: + INFOP("%s (ret %x)\n", cmdname(cmd), + be32_to_cpu(p->RqSReply.retcode)); + break; + + case Ping: + case PingAck: + /* + * Dont trace pings at summary level + */ + if (trace_level < TraceLvlAll) + break; + /* fall through... */ + default: + INFOP("%s (%u)\n", cmdname(cmd), cmd); + break; + } +} + +/* Debug routine to dump info about bio */ + +void _dump_bio(const char *pfx, struct drbd_conf *mdev, struct bio *bio, int complete) +{ +#ifdef CONFIG_LBD +#define SECTOR_FORMAT "%Lx" +#else +#define SECTOR_FORMAT "%lx" +#endif +#define SECTOR_SHIFT 9 + + unsigned long lowaddr = (unsigned long)(bio->bi_sector << SECTOR_SHIFT); + char *faddr = (char *)(lowaddr); + struct bio_vec *bvec; + int segno; + + const int rw = bio->bi_rw; + const int biorw = (rw & (RW_MASK|RWA_MASK)); + const int biobarrier = (rw & (1<>>", + pfx, + biorw==WRITE?"Write":"Read", + biobarrier?":B":"", + biosync?":S":"", + bio, + complete? (drbd_bio_uptodate(bio)? "Success, ":"Failed, ") : "", + bio->bi_sector << SECTOR_SHIFT, + bio->bi_size); + + if (trace_level >= TraceLvlMetrics && + ((biorw == WRITE) ^ complete) ) { + printk(KERN_DEBUG " ind page offset length\n"); + __bio_for_each_segment(bvec, bio, segno, 0) { + printk(KERN_DEBUG " [%d] %p %8.8x %8.8x\n", segno, + bvec->bv_page, bvec->bv_offset, bvec->bv_len); + + if (trace_level >= TraceLvlAll) { + char *bvec_buf; + unsigned long flags; + + bvec_buf = bvec_kmap_irq(bvec, &flags); + + drbd_print_buffer(" ", DBGPRINT_BUFFADDR, 1, + bvec_buf, + faddr, + (bvec->bv_len <= 0x80) + ? bvec->bv_len : 0x80); + + bvec_kunmap_irq(bvec_buf, &flags); + + if (bvec->bv_len > 0x40) + printk(KERN_DEBUG " ....\n"); + + faddr += bvec->bv_len; + } + } + } +} +#endif + +module_init(drbd_init) +module_exit(drbd_cleanup) --- linux-2.6.27.orig/ubuntu/drbd/drbd_int.h +++ linux-2.6.27/ubuntu/drbd/drbd_int.h @@ -0,0 +1,2130 @@ +/* + drbd_int.h + Kernel module for 2.6.x Kernels + + This file is part of DRBD by Philipp Reisner and Lars Ellenberg. + + Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. + Copyright (C) 1999-2008, Philipp Reisner . + Copyright (C) 2002-2008, Lars Ellenberg . + + drbd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + drbd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with drbd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef _DRBD_INT_H +#define _DRBD_INT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lru_cache.h" + +#ifdef __CHECKER__ +# define __protected_by(x) __attribute__((require_context(x,1,999,"rdwr"))) +# define __protected_read_by(x) __attribute__((require_context(x,1,999,"read"))) +# define __protected_write_by(x) __attribute__((require_context(x,1,999,"write"))) +# define __must_hold(x) __attribute__((context(x,1,1), require_context(x,1,999,"call"))) +#else +# define __protected_by(x) +# define __protected_read_by(x) +# define __protected_write_by(x) +# define __must_hold(x) +#endif + +#define __no_warn(lock, stmt) do { __acquire(lock); stmt; __release(lock); } while (0) + +/* Compatibility for older kernels */ +#ifndef __acquires +# ifdef __CHECKER__ +# define __acquires(x) __attribute__((context(x,0,1))) +# define __releases(x) __attribute__((context(x,1,0))) +# define __acquire(x) __context__(x,1) +# define __release(x) __context__(x,-1) +# define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0) +# else +# define __acquires(x) +# define __releases(x) +# define __acquire(x) (void)0 +# define __release(x) (void)0 +# define __cond_lock(x,c) (c) +# endif +#endif + +/* module parameter, defined in drbd_main.c */ +extern int minor_count; +extern int allow_oos; + +#ifdef DRBD_ENABLE_FAULTS +extern int enable_faults; +extern int fault_rate; +extern int fault_devs; +#endif + +extern char usermode_helper[]; + +#include +#ifndef DRBD_MAJOR +# define DRBD_MAJOR 147 +#endif + +#include +#include + +// XXX do we need this? +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +/* I don't remember why XCPU ... + * This is used to wake the asender, + * and to interrupt sending the sending task + * on disconnect. + */ +#define DRBD_SIG SIGXCPU + +/* This is used to stop/restart our threads. + * Cannot use SIGTERM nor SIGKILL, since these + * are sent out by init on runlevel changes + * I choose SIGHUP for now. + * + * FIXME btw, we should register some reboot notifier. + */ +#define DRBD_SIGKILL SIGHUP + +/* All EEs on the free list should have ID_VACANT (== 0) + * freshly allocated EEs get !ID_VACANT (== 1) + * so if it says "cannot dereference null pointer at adress 0x00000001", + * it is most likely one of these :( */ + +#define ID_IN_SYNC (4711ULL) +#define ID_OUT_OF_SYNC (4712ULL) + +#define ID_SYNCER (-1ULL) +#define ID_VACANT 0 +#define is_syncer_block_id(id) ((id) == ID_SYNCER) + +struct drbd_conf; + +#ifdef DBG_ALL_SYMBOLS +# define STATIC +#else +# define STATIC static +#endif + +#ifdef PARANOIA +# define PARANOIA_BUG_ON(x) BUG_ON(x) +#else +# define PARANOIA_BUG_ON(x) +#endif + +/* + * Some Message Macros + *************************/ + +/* handy macro: DUMPP(somepointer) */ +#define DUMPP(A) ERR( #A " = %p in %s:%d\n", (A), __FILE__, __LINE__); +#define DUMPLU(A) ERR( #A " = %lu in %s:%d\n", (unsigned long)(A), __FILE__, __LINE__); +#define DUMPLLU(A) ERR( #A " = %llu in %s:%d\n", (unsigned long long)(A), __FILE__, __LINE__); +#define DUMPLX(A) ERR( #A " = %lx in %s:%d\n", (A), __FILE__, __LINE__); +#define DUMPI(A) ERR( #A " = %d in %s:%d\n", (int)(A), __FILE__, __LINE__); + +#define DUMPST(A) DUMPLLU((unsigned long long)(A)) + +#if 0 +#define D_DUMPP(A) DUMPP(A) +#define D_DUMPLU(A) DUMPLU(A) +#define D_DUMPLLU(A) DUMPLLU(A) +#define D_DUMPLX(A) DUMPLX(A) +#define D_DUMPI(A) DUMPI(A) +#else +#define D_DUMPP(A) +#define D_DUMPLU(A) +#define D_DUMPLLU(A) +#define D_DUMPLX(A) +#define D_DUMPI(A) +#endif + +/* Info: do not remove the spaces around the "," before ## + * Otherwise this is not portable from gcc-2.95 to gcc-3.3 */ +#define PRINTK(level, fmt, args...) \ + printk(level "drbd%d: " fmt, \ + mdev->minor , ##args) + +#define ALERT(fmt, args...) PRINTK(KERN_ALERT, fmt , ##args) +#define ERR(fmt, args...) PRINTK(KERN_ERR, fmt , ##args) +#define DRBD_WARN(fmt, args...) PRINTK(KERN_WARNING, fmt , ##args) +#define INFO(fmt, args...) PRINTK(KERN_INFO, fmt , ##args) +#define DBG(fmt, args...) PRINTK(KERN_DEBUG, fmt , ##args) + +/* see kernel/printk.c:printk_ratelimit + * macro, so it is easy do have independend rate limits at different locations + * "initializer element not constant ..." with kernel 2.4 :( + * so I initialize toks to something large + */ +#define DRBD_ratelimit(ratelimit_jiffies, ratelimit_burst) \ +({ \ + int __ret; \ + static unsigned long toks = 0x80000000UL; \ + static unsigned long last_msg; \ + static int missed; \ + unsigned long now = jiffies; \ + toks += now - last_msg; \ + last_msg = now; \ + if (toks > (ratelimit_burst * ratelimit_jiffies)) \ + toks = ratelimit_burst * ratelimit_jiffies; \ + if (toks >= ratelimit_jiffies) { \ + int lost = missed; \ + missed = 0; \ + toks -= ratelimit_jiffies; \ + if (lost) \ + DRBD_WARN("%d messages suppressed in %s:%d.\n", \ + lost , __FILE__ , __LINE__ ); \ + __ret = 1; \ + } else { \ + missed++; \ + __ret = 0; \ + } \ + __ret; \ +}) + + +#ifdef DBG_ASSERTS +extern void drbd_assert_breakpoint(struct drbd_conf *, char *, char *, int ); +# define D_ASSERT(exp) if (!(exp)) \ + drbd_assert_breakpoint(mdev, #exp, __FILE__, __LINE__) +#else +# define D_ASSERT(exp) if (!(exp)) \ + ERR("ASSERT( " #exp " ) in %s:%d\n", __FILE__, __LINE__) +#endif +#define ERR_IF(exp) if (({ \ + int _b = (exp)!=0; \ + if (_b) ERR("%s: (%s) in %s:%d\n", \ + __func__, #exp, __FILE__,__LINE__); \ + _b; \ + })) + +/* Defines to control fault insertion */ +enum { + DRBD_FAULT_MD_WR = 0, /* meta data write */ + DRBD_FAULT_MD_RD, /* read */ + DRBD_FAULT_RS_WR, /* resync */ + DRBD_FAULT_RS_RD, + DRBD_FAULT_DT_WR, /* data */ + DRBD_FAULT_DT_RD, + DRBD_FAULT_DT_RA, /* data read ahead */ + + DRBD_FAULT_MAX, +}; + +#ifdef DRBD_ENABLE_FAULTS +extern unsigned int +_drbd_insert_fault(struct drbd_conf *mdev, unsigned int type); +static inline int +drbd_insert_fault(struct drbd_conf *mdev, unsigned int type) { + return (fault_rate && + (enable_faults & (1< +/* integer division, round _UP_ to the next integer */ +#define div_ceil(A, B) ( (A)/(B) + ((A)%(B) ? 1 : 0) ) +/* usual integer division */ +#define div_floor(A, B) ( (A)/(B) ) + +/* + * Compatibility Section + *************************/ + +#define LOCK_SIGMASK(task, flags) spin_lock_irqsave(&task->sighand->siglock, flags) +#define UNLOCK_SIGMASK(task, flags) spin_unlock_irqrestore(&task->sighand->siglock, flags) +#define RECALC_SIGPENDING() recalc_sigpending(); + +#if defined(DBG_SPINLOCKS) && defined(__SMP__) +# define MUST_HOLD(lock) if (!spin_is_locked(lock)) { ERR("Not holding lock! in %s\n", __FUNCTION__ ); } +#else +# define MUST_HOLD(lock) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8) +# define HAVE_KERNEL_SENDMSG 1 +#else +# define HAVE_KERNEL_SENDMSG 0 +#endif + + +/* + * our structs + *************************/ + +#define SET_MDEV_MAGIC(x) \ + ({ typecheck(struct drbd_conf*, x); \ + (x)->magic = (long)(x) ^ DRBD_MAGIC; }) +#define IS_VALID_MDEV(x) \ + ( typecheck(struct drbd_conf*, x) && \ + ((x) ? (((x)->magic ^ DRBD_MAGIC) == (long)(x)):0)) + +/* drbd_meta-data.c (still in drbd_main.c) */ +/* 4th incarnation of the disk layout. */ +#define DRBD_MD_MAGIC (DRBD_MAGIC+4) + +extern struct drbd_conf **minor_table; + +/*** + * on the wire + *********************************************************************/ + +enum Drbd_Packet_Cmd { + Data, + DataReply, /* Response to DataRequest */ + RSDataReply, /* Response to RSDataRequest */ + Barrier, + ReportBitMap, + BecomeSyncTarget, + BecomeSyncSource, + UnplugRemote, /* Used at various times to hint the peer */ + DataRequest, /* Used to ask for a data block */ + RSDataRequest, /* Used to ask for a data block for resync */ + SyncParam, + ReportProtocol, + ReportUUIDs, + ReportSizes, + ReportState, + ReportSyncUUID, + AuthChallenge, + AuthResponse, + StateChgRequest, + + FIRST_ASENDER_CMD, + Ping = FIRST_ASENDER_CMD, + PingAck, + RecvAck, /* Used in protocol B */ + WriteAck, /* Used in protocol C */ + RSWriteAck, /* Is a WriteAck, additionally call set_in_sync(). */ + DiscardAck, /* Used in proto C, two-primaries conflict detection */ + NegAck, /* Sent if local disk is unusable */ + NegDReply, /* Local disk is broken... */ + NegRSDReply, /* Local disk is broken... */ + BarrierAck, + StateChgReply, + LAST_ASENDER_CMD = StateChgReply, + + OVRequest, + OVReply, + OVResult, // Exception to the FIRST/LAST ASENDER_CMD + + MAX_CMD, + MayIgnore = 0x100, /* Flag to test if (cmd > MayIgnore) ... */ + MAX_OPT_CMD, + + /* FIXME + * to get a more useful error message with drbd-8 <-> drbd 0.7.x, + * these could be reimplemented as special case of HandShake. */ + HandShakeM = 0xfff1, /* First Packet on the MetaSock */ + HandShakeS = 0xfff2, /* First Packet on the Socket */ + + HandShake = 0xfffe /* FIXED for the next century! */ +}; + +static inline const char *cmdname(enum Drbd_Packet_Cmd cmd) +{ + /* THINK may need to become several global tables + * when we want to support more than + * one PRO_VERSION */ + static const char *cmdnames[] = { + [Data] = "Data", + [DataReply] = "DataReply", + [RSDataReply] = "RSDataReply", + [Barrier] = "Barrier", + [ReportBitMap] = "ReportBitMap", + [BecomeSyncTarget] = "BecomeSyncTarget", + [BecomeSyncSource] = "BecomeSyncSource", + [UnplugRemote] = "UnplugRemote", + [DataRequest] = "DataRequest", + [RSDataRequest] = "RSDataRequest", + [SyncParam] = "SyncParam", + [ReportProtocol] = "ReportProtocol", + [ReportUUIDs] = "ReportUUIDs", + [ReportSizes] = "ReportSizes", + [ReportState] = "ReportState", + [ReportSyncUUID] = "ReportSyncUUID", + [AuthChallenge] = "AuthChallenge", + [AuthResponse] = "AuthResponse", + [Ping] = "Ping", + [PingAck] = "PingAck", + [RecvAck] = "RecvAck", + [WriteAck] = "WriteAck", + [RSWriteAck] = "RSWriteAck", + [DiscardAck] = "DiscardAck", + [NegAck] = "NegAck", + [NegDReply] = "NegDReply", + [NegRSDReply] = "NegRSDReply", + [BarrierAck] = "BarrierAck", + [StateChgRequest] = "StateChgRequest", + [StateChgReply] = "StateChgReply", + [OVRequest] = "OVRequest", + [OVReply] = "OVReply", + [OVResult] = "OVResult", + }; + + if (Data > cmd || cmd >= MAX_CMD) { + switch (cmd) { + case HandShakeM: + return "HandShakeM"; + break; + case HandShakeS: + return "HandShakeS"; + break; + case HandShake: + return "HandShake"; + break; + default: + return "Unknown"; + break; + } + } + return cmdnames[cmd]; +} + + +/* This is the layout for a packet on the wire. + * The byteorder is the network byte order. + * (except block_id and barrier fields. + * these are pointers to local structs + * and have no relevance for the partner, + * which just echoes them as received.) + * + * NOTE that the payload starts at a long aligned offset, + * regardless of 32 or 64 bit arch! + */ +struct Drbd_Header { + u32 magic; + u16 command; + u16 length; /* bytes of data after this header */ + char payload[0]; +} __attribute((packed)); +/* 8 bytes. packet FIXED for the next century! */ + +/* + * short commands, packets without payload, plain Drbd_Header: + * Ping + * PingAck + * BecomeSyncTarget + * BecomeSyncSource + * UnplugRemote + */ + +/* + * commands with out-of-struct payload: + * ReportBitMap (no additional fields) + * Data, DataReply (see Drbd_Data_Packet) + */ + +#define DP_HARDBARRIER 1 +#define DP_RW_SYNC 2 +#define DP_MAY_SET_IN_SYNC 4 + +struct Drbd_Data_Packet { + struct Drbd_Header head; + u64 sector; /* 64 bits sector number */ + u64 block_id; /* to identify the request in protocol B&C */ + u32 seq_num; + u32 dp_flags; +} __attribute((packed)); + +/* + * commands which share a struct: + * Drbd_BlockAck_Packet: + * RecvAck (proto B), WriteAck (proto C), + * DiscardAck (proto C, two-primaries conflict detection) + * Drbd_BlockRequest_Packet: + * DataRequest, RSDataRequest + */ +struct Drbd_BlockAck_Packet { + struct Drbd_Header head; + u64 sector; + u64 block_id; + u32 blksize; + u32 seq_num; +} __attribute((packed)); + + +struct Drbd_BlockRequest_Packet { + struct Drbd_Header head; + u64 sector; + u64 block_id; + u32 blksize; + u32 pad; /* to multiple of 8 Byte */ +} __attribute((packed)); + +/* + * commands with their own struct for additional fields: + * HandShake + * Barrier + * BarrierAck + * SyncParam + * ReportParams + */ + +struct Drbd_HandShake_Packet { + struct Drbd_Header head; /* 8 bytes */ + u32 protocol_min; + u32 feature_flags; + u32 protocol_max; + + /* should be more than enough for future enhancements + * for now, feature_flags and the reserverd array shall be zero. + */ + + u32 _pad; + u64 reserverd[7]; +} __attribute((packed)); +/* 80 bytes, FIXED for the next century */ + +struct Drbd_Barrier_Packet { + struct Drbd_Header head; + u32 barrier; /* barrier number _handle_ only */ + u32 pad; /* to multiple of 8 Byte */ +} __attribute((packed)); + +struct Drbd_BarrierAck_Packet { + struct Drbd_Header head; + u32 barrier; + u32 set_size; +} __attribute((packed)); + +struct Drbd_SyncParam_Packet { + struct Drbd_Header head; + u32 rate; + + /* Since protocol version 88 and higher. */ + char online_verify_alg[0]; +} __attribute((packed)); + +struct Drbd_Protocol_Packet { + struct Drbd_Header head; + u32 protocol; + u32 after_sb_0p; + u32 after_sb_1p; + u32 after_sb_2p; + u32 want_lose; + u32 two_primaries; + + /* Since protocol version 87 and higher. */ + char integrity_alg[0]; + +} __attribute((packed)); + +struct Drbd_GenCnt_Packet { + struct Drbd_Header head; + u64 uuid[EXT_UUID_SIZE]; +} __attribute((packed)); + +struct Drbd_SyncUUID_Packet { + struct Drbd_Header head; + u64 uuid; +} __attribute((packed)); + +struct Drbd_Sizes_Packet { + struct Drbd_Header head; + u64 d_size; /* size of disk */ + u64 u_size; /* user requested size */ + u64 c_size; /* current exported size */ + u32 max_segment_size; /* Maximal size of a BIO */ + u32 queue_order_type; +} __attribute((packed)); + +struct Drbd_State_Packet { + struct Drbd_Header head; + u32 state; +} __attribute((packed)); + +struct Drbd_Req_State_Packet { + struct Drbd_Header head; + u32 mask; + u32 val; +} __attribute((packed)); + +struct Drbd_RqS_Reply_Packet { + struct Drbd_Header head; + u32 retcode; +} __attribute((packed)); + +struct Drbd06_Parameter_P { + u64 size; + u32 state; + u32 blksize; + u32 protocol; + u32 version; + u32 gen_cnt[5]; + u32 bit_map_gen[5]; +} __attribute((packed)); + +struct Drbd_Discard_Packet { + struct Drbd_Header head; + u64 block_id; + u32 seq_num; + u32 pad; +} __attribute((packed)); + +union Drbd_Polymorph_Packet { + struct Drbd_Header head; + struct Drbd_HandShake_Packet HandShake; + struct Drbd_Data_Packet Data; + struct Drbd_BlockAck_Packet BlockAck; + struct Drbd_Barrier_Packet Barrier; + struct Drbd_BarrierAck_Packet BarrierAck; + struct Drbd_SyncParam_Packet SyncParam; + struct Drbd_Protocol_Packet Protocol; + struct Drbd_Sizes_Packet Sizes; + struct Drbd_GenCnt_Packet GenCnt; + struct Drbd_State_Packet State; + struct Drbd_Req_State_Packet ReqState; + struct Drbd_RqS_Reply_Packet RqSReply; + struct Drbd_BlockRequest_Packet BlockRequest; +} __attribute((packed)); + +/**********************************************************************/ +enum Drbd_thread_state { + None, + Running, + Exiting, + Restarting +}; + +struct Drbd_thread { + spinlock_t t_lock; + struct task_struct *task; + struct completion startstop; + enum Drbd_thread_state t_state; + int (*function) (struct Drbd_thread *); + struct drbd_conf *mdev; + struct mutex task_mutex; +}; + +static inline enum Drbd_thread_state get_t_state(struct Drbd_thread *thi) +{ + /* THINK testing the t_state seems to be uncritical in all cases + * (but thread_{start,stop}), so we can read it *without* the lock. + * --lge */ + + smp_rmb(); + return thi->t_state; +} + + +/* + * Having this as the first member of a struct provides sort of "inheritance". + * "derived" structs can be "drbd_queue_work()"ed. + * The callback should know and cast back to the descendant struct. + * drbd_request and Tl_epoch_entry are descendants of drbd_work. + */ +struct drbd_work; +typedef int (*drbd_work_cb)(struct drbd_conf *, struct drbd_work *, int cancel); +struct drbd_work { + struct list_head list; + drbd_work_cb cb; +}; + +struct drbd_barrier; +struct drbd_request { + struct drbd_work w; + struct drbd_conf *mdev; + struct bio *private_bio; + struct hlist_node colision; + sector_t sector; + unsigned int size; + unsigned int epoch; /* barrier_nr */ + + /* barrier_nr: used to check on "completion" whether this req was in + * the current epoch, and we therefore have to close it, + * starting a new epoch... + */ + + /* up to here, the struct layout is identical to Tl_epoch_entry; + * we might be able to use that to our advantage... */ + + struct list_head tl_requests; /* ring list in the transfer log */ + struct bio *master_bio; /* master bio pointer */ + unsigned long rq_state; /* see comments above _req_mod() */ + int seq_num; + unsigned long start_time; +}; + +struct drbd_barrier { + struct drbd_work w; + struct list_head requests; /* requests before */ + struct drbd_barrier *next; /* pointer to the next barrier */ + unsigned int br_number; /* the barriers identifier. */ + int n_req; /* number of requests attached before this barrier */ +}; + +struct drbd_request; + +/* These Tl_epoch_entries may be in one of 6 lists: + active_ee .. data packet being written + sync_ee .. syncer block being written + done_ee .. block written, need to send WriteAck + read_ee .. [RS]DataRequest being read +*/ + +struct Tl_epoch_entry { + struct drbd_work w; + struct drbd_conf *mdev; + struct bio *private_bio; + struct hlist_node colision; + sector_t sector; + unsigned int size; + unsigned int barrier_nr; + + /* up to here, the struct layout is identical to drbd_request; + * we might be able to use that to our advantage... */ + + unsigned int barrier_nr2; + /* If we issue the bio with BIO_RW_BARRIER we have to + send a barrier ACK before we send the ACK to this + write. We store the barrier number in here. + In case the barrier after this write has been coalesced + as well, we set it's barrier_nr into barrier_nr2 */ + + unsigned int flags; + u64 block_id; +}; + +struct digest_info { + int digest_size; + void *digest; +}; + +/* ee flag bits */ +enum { + __EE_CALL_AL_COMPLETE_IO, + __EE_CONFLICT_PENDING, + __EE_MAY_SET_IN_SYNC, +}; +#define EE_CALL_AL_COMPLETE_IO (1<<__EE_CALL_AL_COMPLETE_IO) +#define EE_CONFLICT_PENDING (1<<__EE_CONFLICT_PENDING) +#define EE_MAY_SET_IN_SYNC (1<<__EE_MAY_SET_IN_SYNC) + +/* global flag bits */ +enum { + CREATE_BARRIER, /* next Data is preceeded by a Barrier */ + SIGNAL_ASENDER, /* whether asender wants to be interrupted */ + SEND_PING, /* whether asender should send a ping asap */ + WRITE_ACK_PENDING, /* so BarrierAck won't overtake WriteAck */ + WORK_PENDING, /* completion flag for drbd_disconnect */ + STOP_SYNC_TIMER, /* tell timer to cancel itself */ + UNPLUG_QUEUED, /* only relevant with kernel 2.4 */ + UNPLUG_REMOTE, /* sending a "UnplugRemote" could help */ + MD_DIRTY, /* current uuids and flags not yet on disk */ + DISCARD_CONCURRENT, /* Set on one node, cleared on the peer! */ + USE_DEGR_WFC_T, /* degr-wfc-timeout instead of wfc-timeout. */ + CLUSTER_ST_CHANGE, /* Cluster wide state change going on... */ + CL_ST_CHG_SUCCESS, + CL_ST_CHG_FAIL, + CRASHED_PRIMARY, /* This node was a crashed primary. + * Gets cleared when the state.conn + * goes into Connected state. */ + WRITE_BM_AFTER_RESYNC, /* A kmalloc() during resync failed */ + NO_BARRIER_SUPP, /* underlying block device doesn't implement barriers */ + CONSIDER_RESYNC, + + LL_DEV_NO_FLUSH, /* blkdev_issue_flush does not work, + so don't even try */ + MD_NO_BARRIER, /* meta data device does not support barriers, + so don't even try */ + BITMAP_IO, /* Let user IO drain */ + BITMAP_IO_QUEUED, /* Started bitmap IO */ +}; + +struct drbd_bitmap; /* opaque for drbd_conf */ + +/* TODO sort members for performance + * MAYBE group them further */ + +/* THINK maybe we actually want to use the default "event/%s" worker threads + * or similar in linux 2.6, which uses per cpu data and threads. + * + * To be general, this might need a spin_lock member. + * For now, please use the mdev->req_lock to protect list_head, + * see drbd_queue_work below. + */ +struct drbd_work_queue { + struct list_head q; + struct semaphore s; /* producers up it, worker down()s it */ + spinlock_t q_lock; /* to protect the list. */ +}; + +/* If Philipp agrees, we remove the "mutex", and make_request will only + * (throttle on "queue full" condition and) queue it to the worker thread... + * which then is free to do whatever is needed, and has exclusive send access + * to the data socket ... + */ +struct drbd_socket { + struct drbd_work_queue work; + struct semaphore mutex; + struct socket *socket; + /* this way we get our + * send/receive buffers off the stack */ + union Drbd_Polymorph_Packet sbuf; + union Drbd_Polymorph_Packet rbuf; +}; + +struct drbd_md { + u64 md_offset; /* sector offset to 'super' block */ + + u64 la_size_sect; /* last agreed size, unit sectors */ + u64 uuid[UUID_SIZE]; + u64 device_uuid; + u32 flags; + u32 md_size_sect; + + s32 al_offset; /* signed relative sector offset to al area */ + s32 bm_offset; /* signed relative sector offset to bitmap */ + + /* u32 al_nr_extents; important for restoring the AL + * is stored into sync_conf.al_extents, which in turn + * gets applied to act_log->nr_elements + */ +}; + +// for sync_conf and other types... +#define NL_PACKET(name, number, fields) struct name { fields }; +#define NL_INTEGER(pn,pr,member) int member; +#define NL_INT64(pn,pr,member) __u64 member; +#define NL_BIT(pn,pr,member) unsigned member : 1; +#define NL_STRING(pn,pr,member,len) unsigned char member[len]; int member ## _len; +#include "linux/drbd_nl.h" + +struct drbd_backing_dev { + struct block_device *backing_bdev; + struct block_device *md_bdev; + struct file *lo_file; + struct file *md_file; + struct drbd_md md; + struct disk_conf dc; /* The user provided config... */ + sector_t known_size; +}; + +struct drbd_md_io { + struct drbd_conf *mdev; + struct completion event; + int error; +}; + +struct bm_io_work { + struct drbd_work w; + int (*io_fn)(struct drbd_conf *mdev); + void (*done)(struct drbd_conf *mdev, int rv); +}; + +struct drbd_conf { +#ifdef PARANOIA + long magic; +#endif + /* things that are stored as / read from meta data on disk */ + unsigned long flags; + + /* configured by drbdsetup */ + struct net_conf *net_conf; /* protected by inc_net() and dec_net() */ + struct syncer_conf sync_conf; + struct drbd_backing_dev *bc __protected_by(local); + + sector_t p_size; /* partner's disk size */ + struct request_queue *rq_queue; + struct block_device *this_bdev; + struct gendisk *vdisk; + + struct drbd_socket data; /* data/barrier/cstate/parameter packets */ + struct drbd_socket meta; /* ping/ack (metadata) packets */ + int agreed_pro_version; /* actually used protocol version */ + unsigned long last_received; /* in jiffies, either socket */ + unsigned int ko_count; + struct drbd_work resync_work, + unplug_work, + md_sync_work; + struct timer_list resync_timer; + struct timer_list md_sync_timer; + + /* Used after attach while negotiating new disk state. */ + union drbd_state_t new_state_tmp; + + union drbd_state_t state; + wait_queue_head_t misc_wait; + wait_queue_head_t state_wait; /* upon each state change. */ + unsigned int send_cnt; + unsigned int recv_cnt; + unsigned int read_cnt; + unsigned int writ_cnt; + unsigned int al_writ_cnt; + unsigned int bm_writ_cnt; + atomic_t ap_bio_cnt; /* Requests we need to complete */ + atomic_t ap_pending_cnt; /* AP data packets on the wire, ack expected */ + atomic_t rs_pending_cnt; /* RS request/data packets on the wire */ + atomic_t unacked_cnt; /* Need to send replys for */ + atomic_t local_cnt; /* Waiting for local completion */ + atomic_t net_cnt; /* Users of net_conf */ + spinlock_t req_lock; + struct drbd_barrier *unused_spare_barrier; /* for pre-allocation */ + struct drbd_barrier *newest_barrier; + struct drbd_barrier *oldest_barrier; + struct hlist_head *tl_hash; + unsigned int tl_hash_s; + + /* blocks to sync in this run [unit BM_BLOCK_SIZE] */ + unsigned long rs_total; + /* number of sync IOs that failed in this run */ + unsigned long rs_failed; + /* Syncer's start time [unit jiffies] */ + unsigned long rs_start; + /* cumulated time in PausedSyncX state [unit jiffies] */ + unsigned long rs_paused; + /* block not up-to-date at mark [unit BM_BLOCK_SIZE] */ + unsigned long rs_mark_left; + /* marks's time [unit jiffies] */ + unsigned long rs_mark_time; + + sector_t ov_position; + sector_t ov_last_oos_start; /* Start sector of out of sync range */ + sector_t ov_last_oos_size; /* size of out-of-sync range in sectors */ + unsigned long ov_left; + struct crypto_hash *verify_tfm; + + struct Drbd_thread receiver; + struct Drbd_thread worker; + struct Drbd_thread asender; + struct drbd_bitmap *bitmap; + + /* Used to track operations of resync... */ + struct lru_cache *resync; + /* Number of locked elements in resync LRU */ + unsigned int resync_locked; + /* resync extent number waiting for application requests */ + unsigned int resync_wenr; + + int open_cnt; + u64 *p_uuid; + /* FIXME clean comments, restructure so it is more obvious which + * members are protected by what */ + unsigned int epoch_size; + struct list_head active_ee; /* IO in progress */ + struct list_head sync_ee; /* IO in progress */ + struct list_head done_ee; /* send ack */ + struct list_head read_ee; /* IO in progress */ + struct list_head net_ee; /* zero-copy network send in progress */ + struct hlist_head *ee_hash; /* is proteced by req_lock! */ + unsigned int ee_hash_s; + + /* this one is protected by ee_lock, single thread */ + struct Tl_epoch_entry *last_write_w_barrier; + + int next_barrier_nr; + struct hlist_head *app_reads_hash; /* is proteced by req_lock */ + struct list_head resync_reads; + atomic_t pp_in_use; + wait_queue_head_t ee_wait; + struct page *md_io_page; /* one page buffer for md_io */ + struct page *md_io_tmpp; /* for hardsect != 512 [s390 only?] */ + struct semaphore md_io_mutex; /* protects the md_io_buffer */ + spinlock_t al_lock; + wait_queue_head_t al_wait; + struct lru_cache *act_log; /* activity log */ + unsigned int al_tr_number; + int al_tr_cycle; + int al_tr_pos; /* position of the next transaction in the journal */ + struct crypto_hash *cram_hmac_tfm; + struct crypto_hash *integrity_w_tfm; /* to be used by the worker thread */ + struct crypto_hash *integrity_r_tfm; /* to be used by the receiver thread */ + void *int_dig_out; + void *int_dig_in; + void *int_dig_vv; + wait_queue_head_t seq_wait; + atomic_t packet_seq; + unsigned int peer_seq; + spinlock_t peer_seq_lock; + int minor; + unsigned long comm_bm_set; /* communicated number of set bits. */ + cpumask_t cpu_mask; + struct bm_io_work bm_io_work; + u64 ed_uuid; /* UUID of the exposed data */ + struct mutex state_mutex; +}; + +static inline struct drbd_conf *minor_to_mdev(int minor) +{ + struct drbd_conf *mdev; + + mdev = minor < minor_count ? minor_table[minor] : NULL; + + return mdev; +} + +static inline int mdev_to_minor(struct drbd_conf *mdev) +{ + return mdev->minor; +} + +/* returns 1 if it was successfull, + * returns 0 if there was no data socket. + * so wherever you are going to use the data.socket, e.g. do + * if (!drbd_get_data_sock(mdev)) + * return 0; + * CODE(); + * drbd_put_data_sock(mdev); + */ +static inline int drbd_get_data_sock(struct drbd_conf *mdev) +{ + down(&mdev->data.mutex); + /* drbd_disconnect() could have called drbd_free_sock() + * while we were waiting in down()... */ + if (unlikely(mdev->data.socket == NULL)) { + up(&mdev->data.mutex); + return 0; + } + return 1; +} + +static inline void drbd_put_data_sock(struct drbd_conf *mdev) +{ + up(&mdev->data.mutex); +} + +/* + * function declarations + *************************/ + +/* drbd_main.c */ + +enum chg_state_flags { + ChgStateHard = 1, + ChgStateVerbose = 2, + ChgWaitComplete = 4, + ChgSerialize = 8, + ChgOrdered = ChgWaitComplete + ChgSerialize, +}; + +extern void drbd_init_set_defaults(struct drbd_conf *mdev); +extern int drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f, + union drbd_state_t mask, union drbd_state_t val); +extern void drbd_force_state(struct drbd_conf *, union drbd_state_t, + union drbd_state_t); +extern int _drbd_request_state(struct drbd_conf *, union drbd_state_t, + union drbd_state_t, enum chg_state_flags); +extern int _drbd_set_state(struct drbd_conf *, union drbd_state_t, + enum chg_state_flags, struct completion *done); +extern void print_st_err(struct drbd_conf *, union drbd_state_t, + union drbd_state_t, int ); +extern int drbd_thread_start(struct Drbd_thread *thi); +extern void _drbd_thread_stop(struct Drbd_thread *thi, int restart, int wait); +#ifdef CONFIG_SMP +extern void drbd_thread_set_cpu(struct Drbd_thread *thi, cpumask_t cpu_mask); +extern cpumask_t drbd_calc_cpu_mask(struct drbd_conf *mdev); +#else +#define drbd_thread_set_cpu(A,B) ({}) +#define drbd_calc_cpu_mask(A) CPU_MASK_ALL +#endif +extern void drbd_free_resources(struct drbd_conf *mdev); +extern void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr, + unsigned int set_size); +extern void tl_clear(struct drbd_conf *mdev); +extern void _tl_add_barrier(struct drbd_conf *, struct drbd_barrier *); +extern void drbd_free_sock(struct drbd_conf *mdev); +extern int drbd_send(struct drbd_conf *mdev, struct socket *sock, + void *buf, size_t size, unsigned msg_flags); +extern int drbd_send_protocol(struct drbd_conf *mdev); +extern int _drbd_send_uuids(struct drbd_conf *mdev); +extern int drbd_send_uuids(struct drbd_conf *mdev); +extern int drbd_send_sync_uuid(struct drbd_conf *mdev, u64 val); +extern int drbd_send_sizes(struct drbd_conf *mdev); +extern int _drbd_send_state(struct drbd_conf *mdev); +extern int drbd_send_state(struct drbd_conf *mdev); +extern int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, + enum Drbd_Packet_Cmd cmd, struct Drbd_Header *h, + size_t size, unsigned msg_flags); +#define USE_DATA_SOCKET 1 +#define USE_META_SOCKET 0 +extern int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket, + enum Drbd_Packet_Cmd cmd, struct Drbd_Header *h, + size_t size); +extern int drbd_send_cmd2(struct drbd_conf *mdev, enum Drbd_Packet_Cmd cmd, + char *data, size_t size); +extern int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc); +extern int drbd_send_b_ack(struct drbd_conf *mdev, u32 barrier_nr, + u32 set_size); +extern int drbd_send_ack(struct drbd_conf *mdev, enum Drbd_Packet_Cmd cmd, + struct Tl_epoch_entry *e); +extern int drbd_send_ack_rp(struct drbd_conf *mdev, enum Drbd_Packet_Cmd cmd, + struct Drbd_BlockRequest_Packet *rp); +extern int drbd_send_ack_dp(struct drbd_conf *mdev, enum Drbd_Packet_Cmd cmd, + struct Drbd_Data_Packet *dp); +extern int drbd_send_ack_ex(struct drbd_conf *mdev, enum Drbd_Packet_Cmd cmd, + sector_t sector, int blksize, u64 block_id); +extern int _drbd_send_page(struct drbd_conf *mdev, struct page *page, + int offset, size_t size); +extern int drbd_send_block(struct drbd_conf *mdev, enum Drbd_Packet_Cmd cmd, + struct Tl_epoch_entry *e); +extern int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req); +extern int _drbd_send_barrier(struct drbd_conf *mdev, + struct drbd_barrier *barrier); +extern int drbd_send_drequest(struct drbd_conf *mdev, int cmd, + sector_t sector, int size, u64 block_id); +extern int drbd_send_drequest_csum(struct drbd_conf *mdev, + sector_t sector,int size, + void *digest, int digest_size, + enum Drbd_Packet_Cmd cmd); +extern int drbd_send_ov_request(struct drbd_conf *mdev,sector_t sector,int size); + +extern int drbd_send_bitmap(struct drbd_conf *mdev); +extern int _drbd_send_bitmap(struct drbd_conf *mdev); +extern int drbd_send_sr_reply(struct drbd_conf *mdev, int retcode); +extern void drbd_free_bc(struct drbd_backing_dev *bc); +extern int drbd_io_error(struct drbd_conf *mdev, int forcedetach); +extern void drbd_mdev_cleanup(struct drbd_conf *mdev); + +/* drbd_meta-data.c (still in drbd_main.c) */ +extern void drbd_md_sync(struct drbd_conf *mdev); +extern int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev); +/* maybe define them below as inline? */ +extern void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local); +extern void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local); +extern void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local); +extern void _drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local); +extern void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local); +extern void drbd_md_set_flag(struct drbd_conf *mdev, int flags) __must_hold(local); +extern void drbd_md_clear_flag(struct drbd_conf *mdev, int flags)__must_hold(local); +extern int drbd_md_test_flag(struct drbd_backing_dev *, int); +extern void drbd_md_mark_dirty(struct drbd_conf *mdev); +extern void drbd_queue_bitmap_io(struct drbd_conf *mdev, + int (*io_fn)(struct drbd_conf *), + void (*done)(struct drbd_conf *, int)); +extern int drbd_bmio_set_n_write(struct drbd_conf *mdev); +extern int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *)); + + +/* Meta data layout + We reserve a 128MB Block (4k aligned) + * either at the end of the backing device + * or on a seperate meta data device. */ + +#define MD_RESERVED_SECT ( 128LU << 11 ) /* 128 MB, unit sectors */ +/* The following numbers are sectors */ +#define MD_AL_OFFSET 8 /* 8 Sectors after start of meta area */ +#define MD_AL_MAX_SIZE 64 /* = 32 kb LOG ~ 3776 extents ~ 14 GB Storage */ +/* Allows up to about 3.8TB */ +#define MD_BM_OFFSET (MD_AL_OFFSET + MD_AL_MAX_SIZE) + +/* Since the smalles IO unit is usually 512 byte */ +#define MD_HARDSECT_B 9 +#define MD_HARDSECT (1< we need 32 KB bitmap. + * Bit 0 ==> local node thinks this block is binary identical on both nodes + * Bit 1 ==> local node thinks this block needs to be synced. + */ + +#define BM_BLOCK_SIZE_B 12 /* 4k per bit */ +#define BM_BLOCK_SIZE (1<>(BM_BLOCK_SIZE_B-9)) +#define BM_BIT_TO_SECT(x) ((sector_t)(x)<<(BM_BLOCK_SIZE_B-9)) +#define BM_SECT_PER_BIT BM_BIT_TO_SECT(1) + +/* bit to represented kilo byte conversion */ +#define Bit2KB(bits) ((bits)<<(BM_BLOCK_SIZE_B-10)) + +/* in which _bitmap_ extent (resp. sector) the bit for a certain + * _storage_ sector is located in */ +#define BM_SECT_TO_EXT(x) ((x)>>(BM_EXT_SIZE_B-9)) + +/* who much _storage_ sectors we have per bitmap sector */ +#define BM_SECT_PER_EXT (1ULL << (BM_EXT_SIZE_B-9)) + +/* in one sector of the bitmap, we have this many activity_log extents. */ +#define AL_EXT_PER_BM_SECT (1 << (BM_EXT_SIZE_B - AL_EXTENT_SIZE_B) ) +#define BM_WORDS_PER_AL_EXT (1 << (AL_EXTENT_SIZE_B-BM_BLOCK_SIZE_B-LN2_BPL)) + + +#define BM_BLOCKS_PER_BM_EXT_B ( BM_EXT_SIZE_B - BM_BLOCK_SIZE_B ) +#define BM_BLOCKS_PER_BM_EXT_MASK ( (1<= level) && (type & trace_type)); +} +static inline int +is_mdev_trace(struct drbd_conf *mdev, unsigned int type, unsigned int level) { + return (is_trace(type, level) && + ( ( 1 << mdev_to_minor(mdev)) & trace_devs)); +} + +#define MTRACE(type, lvl, code...) \ +do { \ + if (unlikely(is_mdev_trace(mdev, type, lvl))) { \ + code \ + } \ +} while (0) + +#define TRACE(type, lvl, code...) \ +do { \ + if (unlikely(is_trace(type, lvl))) { \ + code \ + } \ +} while (0) + +/* Buffer printing support + * dbg_print_flags: used for Flags arg to drbd_print_buffer + * - DBGPRINT_BUFFADDR; if set, each line starts with the + * virtual address of the line being output. If clear, + * each line starts with the offset from the beginning + * of the buffer. */ +enum dbg_print_flags { + DBGPRINT_BUFFADDR = 0x0001, +}; + +extern void drbd_print_uuid(struct drbd_conf *mdev, unsigned int idx); + +extern void drbd_print_buffer(const char *prefix, unsigned int flags, int size, + const void *buffer, const void *buffer_va, + unsigned int length); + +/* Bio printing support */ +extern void _dump_bio(const char *pfx, struct drbd_conf *mdev, struct bio *bio, int complete); + +static inline void dump_bio(struct drbd_conf *mdev, + struct bio *bio, int complete) +{ + MTRACE(TraceTypeRq, TraceLvlSummary, + _dump_bio("Rq", mdev, bio, complete); + ); +} + +static inline void dump_internal_bio(const char *pfx, struct drbd_conf *mdev, struct bio *bio, int complete) { + MTRACE(TraceTypeIntRq,TraceLvlSummary, + _dump_bio(pfx, mdev, bio, complete); + ); +} + +/* Packet dumping support */ +extern void _dump_packet(struct drbd_conf *mdev, struct socket *sock, + int recv, union Drbd_Polymorph_Packet *p, + char *file, int line); + +static inline void +dump_packet(struct drbd_conf *mdev, struct socket *sock, + int recv, union Drbd_Polymorph_Packet *p, char *file, int line) +{ + MTRACE(TraceTypePacket, TraceLvlSummary, + _dump_packet(mdev, sock, recv, p, file, line); + ); +} + +#else + +#define MTRACE(ignored...) ((void)0) +#define TRACE(ignored...) ((void)0) + +#define dump_bio(ignored...) ((void)0) +#define dump_internal_bio(ignored...) ((void)0) +#define dump_packet(ignored...) ((void)0) +#endif + +/* drbd_req */ +extern int drbd_make_request_26(struct request_queue *q, struct bio *bio); +extern int drbd_read_remote(struct drbd_conf *mdev, struct drbd_request *req); +extern int drbd_merge_bvec(struct request_queue *, struct bvec_merge_data *bvm, struct bio_vec *); +extern int is_valid_ar_handle(struct drbd_request *, sector_t); + + +/* drbd_nl.c */ +extern char *ppsize(char *buf, unsigned long long size); +extern sector_t drbd_new_dev_size(struct drbd_conf *, + struct drbd_backing_dev *); +enum determin_dev_size_enum { dev_size_error = -1, unchanged = 0, shrunk = 1, grew = 2 }; +extern enum determin_dev_size_enum drbd_determin_dev_size(struct drbd_conf *) __must_hold(local); +extern void resync_after_online_grow(struct drbd_conf *); +extern void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int) __must_hold(local); +extern int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, + int force); +extern int drbd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev); +extern long drbd_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg); +extern int drbd_khelper(struct drbd_conf *mdev, char *cmd); + +/* drbd_worker.c */ +extern int drbd_worker(struct Drbd_thread *thi); +extern void drbd_alter_sa(struct drbd_conf *mdev, int na); +extern void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side); +extern void resume_next_sg(struct drbd_conf *mdev); +extern void suspend_other_sg(struct drbd_conf *mdev); +extern int drbd_resync_finished(struct drbd_conf *mdev); +/* maybe rather drbd_main.c ? */ +extern int drbd_md_sync_page_io(struct drbd_conf *mdev, + struct drbd_backing_dev *bdev, sector_t sector, int rw); +extern void drbd_ov_oos_found(struct drbd_conf*, sector_t, int); + +static inline void ov_oos_print(struct drbd_conf *mdev) +{ + if (mdev->ov_last_oos_size) { + ERR("Out of sync: start=%llu, size=%lu (sectors)\n", + (unsigned long long)mdev->ov_last_oos_start, + (unsigned long)mdev->ov_last_oos_size); + } + mdev->ov_last_oos_size=0; +} + + +void drbd_csum(struct drbd_conf *, struct crypto_hash *, struct bio *, void *); +/* worker callbacks */ +extern int w_req_cancel_conflict(struct drbd_conf *, struct drbd_work *, int); +extern int w_read_retry_remote(struct drbd_conf *, struct drbd_work *, int); +extern int w_e_end_data_req(struct drbd_conf *, struct drbd_work *, int); +extern int w_e_end_rsdata_req(struct drbd_conf *, struct drbd_work *, int); +extern int w_e_end_ov_reply(struct drbd_conf *, struct drbd_work *, int); +extern int w_e_end_ov_req(struct drbd_conf *, struct drbd_work *, int); +extern int w_ov_finished(struct drbd_conf *, struct drbd_work *, int); +extern int w_resync_inactive(struct drbd_conf *, struct drbd_work *, int); +extern int w_resume_next_sg(struct drbd_conf *, struct drbd_work *, int); +extern int w_io_error(struct drbd_conf *, struct drbd_work *, int); +extern int w_send_write_hint(struct drbd_conf *, struct drbd_work *, int); +extern int w_make_resync_request(struct drbd_conf *, struct drbd_work *, int); +extern int w_send_dblock(struct drbd_conf *, struct drbd_work *, int); +extern int w_send_barrier(struct drbd_conf *, struct drbd_work *, int); +extern int w_send_read_req(struct drbd_conf *, struct drbd_work *, int); +extern int w_prev_work_done(struct drbd_conf *, struct drbd_work *, int); + +extern void resync_timer_fn(unsigned long data); + +/* drbd_receiver.c */ +extern int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list); +extern struct Tl_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, + u64 id, + sector_t sector, + unsigned int data_size, + gfp_t gfp_mask) __must_hold(local); +extern void drbd_free_ee(struct drbd_conf *mdev, struct Tl_epoch_entry *e); +extern void drbd_wait_ee_list_empty(struct drbd_conf *mdev, + struct list_head *head); +extern void _drbd_wait_ee_list_empty(struct drbd_conf *mdev, + struct list_head *head); +extern void drbd_set_recv_tcq(struct drbd_conf *mdev, int tcq_enabled); +extern void _drbd_clear_done_ee(struct drbd_conf *mdev); + +static inline void drbd_tcp_cork(struct socket *sock) +{ + int __user val = 1; + tcp_setsockopt(sock->sk, SOL_TCP, TCP_CORK, (char __user *)&val, sizeof(val) ); +} + +static inline void drbd_tcp_flush(struct socket *sock) +{ + int __user val = 0; + tcp_setsockopt(sock->sk, SOL_TCP, TCP_CORK, (char __user *)&val, sizeof(val) ); +} + +/* drbd_proc.c */ +extern struct proc_dir_entry *drbd_proc; +extern struct file_operations drbd_proc_fops; +extern const char *conns_to_name(enum drbd_conns s); +extern const char *roles_to_name(enum drbd_role s); + +/* drbd_actlog.c */ +extern void drbd_al_begin_io(struct drbd_conf *mdev, sector_t sector); +extern void drbd_al_complete_io(struct drbd_conf *mdev, sector_t sector); +extern void drbd_rs_complete_io(struct drbd_conf *mdev, sector_t sector); +extern int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector); +extern int drbd_try_rs_begin_io(struct drbd_conf *mdev, sector_t sector); +extern void drbd_rs_cancel_all(struct drbd_conf *mdev); +extern int drbd_rs_del_all(struct drbd_conf *mdev); +extern void drbd_rs_failed_io(struct drbd_conf *mdev, + sector_t sector, int size); +extern int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *); +extern void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, + int size, const char *file, const unsigned int line); +#define drbd_set_in_sync(mdev, sector, size) \ + __drbd_set_in_sync(mdev, sector, size, __FILE__, __LINE__ ) +extern void __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, + int size, const char *file, const unsigned int line); +#define drbd_set_out_of_sync(mdev, sector, size) \ + __drbd_set_out_of_sync(mdev, sector, size, __FILE__, __LINE__ ) +extern void drbd_al_apply_to_bm(struct drbd_conf *mdev); +extern void drbd_al_to_on_disk_bm(struct drbd_conf *mdev); +extern void drbd_al_shrink(struct drbd_conf *mdev); + + +/* drbd_nl.c */ + +void drbd_nl_cleanup(void); +int __init drbd_nl_init(void); +void drbd_bcast_state(struct drbd_conf *mdev, union drbd_state_t); +void drbd_bcast_sync_progress(struct drbd_conf *mdev); +void drbd_bcast_ee(struct drbd_conf *mdev, + const char *reason, const int dgs, + const char* seen_hash, const char* calc_hash, + const struct Tl_epoch_entry* e); + +/* + * inline helper functions + *************************/ + +#define peer_mask role_mask +#define pdsk_mask disk_mask +#define susp_mask 1 +#define user_isp_mask 1 +#define aftr_isp_mask 1 + +#define NS(T, S) \ + ({ union drbd_state_t mask; mask.i = 0; mask.T = T##_mask; mask; }), \ + ({ union drbd_state_t val; val.i = 0; val.T = (S); val; }) +#define NS2(T1, S1, T2, S2) \ + ({ union drbd_state_t mask; mask.i = 0; mask.T1 = T1##_mask; \ + mask.T2 = T2##_mask; mask; }), \ + ({ union drbd_state_t val; val.i = 0; val.T1 = (S1); \ + val.T2 = (S2); val; }) +#define NS3(T1, S1, T2, S2, T3, S3) \ + ({ union drbd_state_t mask; mask.i = 0; mask.T1 = T1##_mask; \ + mask.T2 = T2##_mask; mask.T3 = T3##_mask; mask; }), \ + ({ union drbd_state_t val; val.i = 0; val.T1 = (S1); \ + val.T2 = (S2); val.T3 = (S3); val; }) + +#define _NS(D, T, S) \ + D, ({ union drbd_state_t __ns; __ns.i = D->state.i; __ns.T = (S); __ns; }) +#define _NS2(D, T1, S1, T2, S2) \ + D, ({ union drbd_state_t __ns; __ns.i = D->state.i; __ns.T1 = (S1); \ + __ns.T2 = (S2); __ns; }) +#define _NS3(D, T1, S1, T2, S2, T3, S3) \ + D, ({ union drbd_state_t __ns; __ns.i = D->state.i; __ns.T1 = (S1); \ + __ns.T2 = (S2); __ns.T3 = (S3); __ns; }) + +static inline void drbd_state_lock(struct drbd_conf *mdev) +{ + wait_event(mdev->misc_wait, + !test_and_set_bit(CLUSTER_ST_CHANGE, &mdev->flags)); +} + +static inline void drbd_state_unlock(struct drbd_conf *mdev) +{ + clear_bit(CLUSTER_ST_CHANGE, &mdev->flags); + wake_up(&mdev->misc_wait); +} + +static inline int drbd_request_state(struct drbd_conf *mdev, + union drbd_state_t mask, + union drbd_state_t val) +{ + return _drbd_request_state(mdev, mask, val, ChgStateVerbose + ChgOrdered); +} + +/** + * drbd_chk_io_error: Handles the on_io_error setting, should be called from + * all io completion handlers. See also drbd_io_error(). + */ +static inline void __drbd_chk_io_error(struct drbd_conf *mdev, int forcedetach) +{ + switch (mdev->bc->dc.on_io_error) { + case PassOn: /* FIXME would this be better named "Ignore"? */ + if (!forcedetach) { + if (printk_ratelimit()) + ERR("Local IO failed. Passing error on...\n"); + break; + } + /* NOTE fall through to detach case if forcedetach set */ + case Detach: + case CallIOEHelper: + if (mdev->state.disk > Failed) { + _drbd_set_state(_NS(mdev, disk, Failed), ChgStateHard, NULL); + ERR("Local IO failed. Detaching...\n"); + } + break; + } +} + +static inline void drbd_chk_io_error(struct drbd_conf *mdev, + int error, int forcedetach) +{ + if (error) { + unsigned long flags; + spin_lock_irqsave(&mdev->req_lock, flags); + __drbd_chk_io_error(mdev, forcedetach); + spin_unlock_irqrestore(&mdev->req_lock, flags); + } +} + +static inline int semaphore_is_locked(struct semaphore *s) +{ + if (!down_trylock(s)) { + up(s); + return 0; + } + return 1; +} + +/* Returns the first sector number of our meta data, + * which, for internal meta data, happens to be the maximum capacity + * we could agree upon with our peer + */ +static inline sector_t drbd_md_first_sector(struct drbd_backing_dev *bdev) +{ + switch (bdev->dc.meta_dev_idx) { + case DRBD_MD_INDEX_INTERNAL: + case DRBD_MD_INDEX_FLEX_INT: + return bdev->md.md_offset + bdev->md.bm_offset; + case DRBD_MD_INDEX_FLEX_EXT: + default: + return bdev->md.md_offset; + } +} + +/* returns the last sector number of our meta data, + * to be able to catch out of band md access */ +static inline sector_t drbd_md_last_sector(struct drbd_backing_dev *bdev) +{ + switch (bdev->dc.meta_dev_idx) { + case DRBD_MD_INDEX_INTERNAL: + case DRBD_MD_INDEX_FLEX_INT: + return bdev->md.md_offset + MD_AL_OFFSET -1; + case DRBD_MD_INDEX_FLEX_EXT: + default: + return bdev->md.md_offset + bdev->md.md_size_sect; + } +} + +/* returns the capacity we announce to out peer */ +static inline sector_t drbd_get_max_capacity(struct drbd_backing_dev *bdev) +{ + switch (bdev->dc.meta_dev_idx) { + case DRBD_MD_INDEX_INTERNAL: + case DRBD_MD_INDEX_FLEX_INT: + return drbd_get_capacity(bdev->backing_bdev) + ? drbd_md_first_sector(bdev) + : 0; + case DRBD_MD_INDEX_FLEX_EXT: + default: + return drbd_get_capacity(bdev->backing_bdev); + } +} + +/* returns the sector number of our meta data 'super' block */ +static inline sector_t drbd_md_ss__(struct drbd_conf *mdev, + struct drbd_backing_dev *bdev) +{ + switch (bdev->dc.meta_dev_idx) { + default: /* external, some index */ + return MD_RESERVED_SECT * bdev->dc.meta_dev_idx; + case DRBD_MD_INDEX_INTERNAL: + /* with drbd08, internal meta data is always "flexible" */ + case DRBD_MD_INDEX_FLEX_INT: + /* sizeof(struct md_on_disk_07) == 4k + * position: last 4k aligned block of 4k size */ + if (!bdev->backing_bdev) { + if (DRBD_ratelimit(5*HZ, 5)) { + ERR("bdev->backing_bdev==NULL\n"); + dump_stack(); + } + return 0; + } + return (drbd_get_capacity(bdev->backing_bdev) & ~7ULL) + - MD_AL_OFFSET; + case DRBD_MD_INDEX_FLEX_EXT: + return 0; + } +} + +static inline void +_drbd_queue_work(struct drbd_work_queue *q, struct drbd_work *w) +{ + list_add_tail(&w->list, &q->q); + up(&q->s); +} + +static inline void +drbd_queue_work_front(struct drbd_work_queue *q, struct drbd_work *w) +{ + unsigned long flags; + spin_lock_irqsave(&q->q_lock, flags); + list_add(&w->list, &q->q); + up(&q->s); /* within the spinlock, + see comment near end of drbd_worker() */ + spin_unlock_irqrestore(&q->q_lock, flags); +} + +static inline void +drbd_queue_work(struct drbd_work_queue *q, struct drbd_work *w) +{ + unsigned long flags; + spin_lock_irqsave(&q->q_lock, flags); + list_add_tail(&w->list, &q->q); + up(&q->s); /* within the spinlock, + see comment near end of drbd_worker() */ + spin_unlock_irqrestore(&q->q_lock, flags); +} + +static inline void wake_asender(struct drbd_conf *mdev) +{ + if (test_bit(SIGNAL_ASENDER, &mdev->flags)) + force_sig(DRBD_SIG, mdev->asender.task); +} + +static inline void request_ping(struct drbd_conf *mdev) +{ + set_bit(SEND_PING, &mdev->flags); + wake_asender(mdev); +} + +static inline int drbd_send_short_cmd(struct drbd_conf *mdev, + enum Drbd_Packet_Cmd cmd) +{ + struct Drbd_Header h; + return drbd_send_cmd(mdev, USE_DATA_SOCKET, cmd, &h, sizeof(h)); +} + +static inline int drbd_send_ping(struct drbd_conf *mdev) +{ + struct Drbd_Header h; + return drbd_send_cmd(mdev, USE_META_SOCKET, Ping, &h, sizeof(h)); +} + +static inline int drbd_send_ping_ack(struct drbd_conf *mdev) +{ + struct Drbd_Header h; + return drbd_send_cmd(mdev, USE_META_SOCKET, PingAck, &h, sizeof(h)); +} + +static inline void drbd_thread_stop(struct Drbd_thread *thi) +{ + _drbd_thread_stop(thi, FALSE, TRUE); +} + +static inline void drbd_thread_stop_nowait(struct Drbd_thread *thi) +{ + _drbd_thread_stop(thi, FALSE, FALSE); +} + +static inline void drbd_thread_restart_nowait(struct Drbd_thread *thi) +{ + _drbd_thread_stop(thi, TRUE, FALSE); +} + +/* counts how many answer packets packets we expect from our peer, + * for either explicit application requests, + * or implicit barrier packets as necessary. + * increased: + * w_send_barrier + * _req_mod(req, queue_for_net_write or queue_for_net_read); + * it is much easier and equally valid to count what we queue for the + * worker, even before it actually was queued or send. + * (drbd_make_request_common; recovery path on read io-error) + * decreased: + * got_BarrierAck (respective tl_clear, tl_clear_barrier) + * _req_mod(req, data_received) + * [from receive_DataReply] + * _req_mod(req, write_acked_by_peer or recv_acked_by_peer or neg_acked) + * [from got_BlockAck (WriteAck, RecvAck)] + * FIXME + * for some reason it is NOT decreased in got_NegAck, + * but in the resulting cleanup code from report_params. + * we should try to remember the reason for that... + * _req_mod(req, send_failed or send_canceled) + * _req_mod(req, connection_lost_while_pending) + * [from tl_clear_barrier] + */ +static inline void inc_ap_pending(struct drbd_conf *mdev) +{ + atomic_inc(&mdev->ap_pending_cnt); +} + +#define ERR_IF_CNT_IS_NEGATIVE(which) \ + if (atomic_read(&mdev->which) < 0) \ + ERR("in %s:%d: " #which " = %d < 0 !\n", \ + __func__ , __LINE__ , \ + atomic_read(&mdev->which)) + +#define dec_ap_pending(mdev) do { \ + typecheck(struct drbd_conf *, mdev); \ + if (atomic_dec_and_test(&mdev->ap_pending_cnt)) \ + wake_up(&mdev->misc_wait); \ + ERR_IF_CNT_IS_NEGATIVE(ap_pending_cnt); } while (0) + +/* counts how many resync-related answers we still expect from the peer + * increase decrease + * SyncTarget sends RSDataRequest (and expects RSDataReply) + * SyncSource sends RSDataReply (and expects WriteAck whith ID_SYNCER) + * (or NegAck with ID_SYNCER) + */ +static inline void inc_rs_pending(struct drbd_conf *mdev) +{ + atomic_inc(&mdev->rs_pending_cnt); +} + +#define dec_rs_pending(mdev) do { \ + typecheck(struct drbd_conf *, mdev); \ + atomic_dec(&mdev->rs_pending_cnt); \ + ERR_IF_CNT_IS_NEGATIVE(rs_pending_cnt); } while (0) + +/* counts how many answers we still need to send to the peer. + * increased on + * receive_Data unless protocol A; + * we need to send a RecvAck (proto B) + * or WriteAck (proto C) + * receive_RSDataReply (recv_resync_read) we need to send a WriteAck + * receive_DataRequest (receive_RSDataRequest) we need to send back Data + * receive_Barrier_* we need to send a BarrierAck + */ +static inline void inc_unacked(struct drbd_conf *mdev) +{ + atomic_inc(&mdev->unacked_cnt); +} + +#define dec_unacked(mdev) do { \ + typecheck(struct drbd_conf *, mdev); \ + atomic_dec(&mdev->unacked_cnt); \ + ERR_IF_CNT_IS_NEGATIVE(unacked_cnt); } while (0) + +#define sub_unacked(mdev, n) do { \ + typecheck(struct drbd_conf *, mdev); \ + atomic_sub(n, &mdev->unacked_cnt); \ + ERR_IF_CNT_IS_NEGATIVE(unacked_cnt); } while (0) + + +static inline void dec_net(struct drbd_conf *mdev) +{ + if (atomic_dec_and_test(&mdev->net_cnt)) + wake_up(&mdev->misc_wait); +} + +/** + * inc_net: Returns TRUE when it is ok to access mdev->net_conf. You + * should call dec_net() when finished looking at mdev->net_conf. + */ +static inline int inc_net(struct drbd_conf *mdev) +{ + int have_net_conf; + + atomic_inc(&mdev->net_cnt); + have_net_conf = mdev->state.conn >= Unconnected; + if (!have_net_conf) + dec_net(mdev); + return have_net_conf; +} + +/** + * inc_local: Returns TRUE when local IO is possible. If it returns + * TRUE you should call dec_local() after IO is completed. + */ +#define inc_local_if_state(M,MINS) __cond_lock(local, _inc_local_if_state(M,MINS)) +#define inc_local(M) __cond_lock(local, _inc_local_if_state(M,Inconsistent)) + +static inline void dec_local(struct drbd_conf *mdev) +{ + __release(local); + if (atomic_dec_and_test(&mdev->local_cnt)) + wake_up(&mdev->misc_wait); + D_ASSERT(atomic_read(&mdev->local_cnt) >= 0); +} + +#ifndef __CHECKER__ +static inline int _inc_local_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins) +{ + int io_allowed; + + atomic_inc(&mdev->local_cnt); + io_allowed = (mdev->state.disk >= mins ); + if (!io_allowed) + dec_local(mdev); + return io_allowed; +} +#else +extern int _inc_local_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins); +#endif + +/* you must have an "inc_local" reference */ +static inline void drbd_get_syncer_progress(struct drbd_conf *mdev, + unsigned long *bits_left, unsigned int *per_mil_done) +{ + /* + * this is to break it at compile time when we change that + * (we may feel 4TB maximum storage per drbd is not enough) + */ + typecheck(unsigned long, mdev->rs_total); + + /* note: both rs_total and rs_left are in bits, i.e. in + * units of BM_BLOCK_SIZE. + * for the percentage, we don't care. */ + + *bits_left = drbd_bm_total_weight(mdev) - mdev->rs_failed; + /* >> 10 to prevent overflow, + * +1 to prevent division by zero */ + if (*bits_left > mdev->rs_total) { + /* doh. maybe a logic bug somewhere. + * may also be just a race condition + * between this and a disconnect during sync. + * for now, just prevent in-kernel buffer overflow. + */ + smp_rmb(); + DRBD_WARN("cs:%s rs_left=%lu > rs_total=%lu (rs_failed %lu)\n", + conns_to_name(mdev->state.conn), + *bits_left, mdev->rs_total, mdev->rs_failed); + *per_mil_done = 0; + } else { + /* make sure the calculation happens in long context */ + unsigned long tmp = 1000UL - + (*bits_left >> 10)*1000UL + / ((mdev->rs_total >> 10) + 1UL); + *per_mil_done = tmp; + } +} + + +/* this throttles on-the-fly application requests + * according to max_buffers settings; + * maybe re-implement using semaphores? */ +static inline int drbd_get_max_buffers(struct drbd_conf *mdev) +{ + int mxb = 1000000; /* arbitrary limit on open requests */ + if (inc_net(mdev)) { + mxb = mdev->net_conf->max_buffers; + dec_net(mdev); + } + return mxb; +} + +static inline int __inc_ap_bio_cond(struct drbd_conf *mdev) +{ + const unsigned int cs = mdev->state.conn; + const unsigned int ds = mdev->state.disk; + int mxb = drbd_get_max_buffers(mdev); + if (mdev->state.susp) + return 0; + /* to avoid deadlock or bitmap corruption, we need to lock out + * application io during attaching and bitmap exchange */ + if (Attaching <= ds && ds <= Negotiating) + return 0; + if (cs == WFBitMapS || cs == WFBitMapT || cs == WFReportParams || cs == WFSyncUUID) + return 0; + + /* since some older kernels don't have atomic_add_unless, + * and we are within the spinlock anyways, we have this workaround. */ + if (atomic_read(&mdev->ap_bio_cnt) > mxb) + return 0; + if (test_bit(BITMAP_IO, &mdev->flags)) + return 0; + atomic_inc(&mdev->ap_bio_cnt); + return 1; +} + +/* I'd like to use wait_event_lock_irq, + * but I'm not sure when it got introduced, + * and not sure when it has 3 or 4 arguments */ +static inline void inc_ap_bio(struct drbd_conf *mdev) +{ + /* compare with after_state_ch, + * os.conn != WFBitMapS && ns.conn == WFBitMapS */ + DEFINE_WAIT(wait); + + /* we wait here + * as long as the device is suspended + * until the bitmap is no longer on the fly during connection + * handshake as long as we would exeed the max_buffer limit. + * + * to avoid races with the reconnect code, + * we need to atomic_inc within the spinlock. */ + + spin_lock_irq(&mdev->req_lock); + while (!__inc_ap_bio_cond(mdev)) { + prepare_to_wait(&mdev->misc_wait, &wait, TASK_UNINTERRUPTIBLE); + spin_unlock_irq(&mdev->req_lock); + schedule(); + finish_wait(&mdev->misc_wait, &wait); + spin_lock_irq(&mdev->req_lock); + } + spin_unlock_irq(&mdev->req_lock); +} + +static inline void dec_ap_bio(struct drbd_conf *mdev) +{ + int mxb = drbd_get_max_buffers(mdev); + int ap_bio = atomic_dec_return(&mdev->ap_bio_cnt); + + D_ASSERT(ap_bio >= 0); + if (ap_bio < mxb) + wake_up(&mdev->misc_wait); + if (ap_bio == 0 && test_bit(BITMAP_IO, &mdev->flags)) { + if (!test_and_set_bit(BITMAP_IO_QUEUED, &mdev->flags)) + drbd_queue_work(&mdev->data.work, &mdev->bm_io_work.w); + } +} + +static inline void drbd_set_ed_uuid(struct drbd_conf *mdev, u64 val) +{ + mdev->ed_uuid = val; + + MTRACE(TraceTypeUuid,TraceLvlMetrics, + INFO(" exposed data uuid now %016llX\n",val); + ); +} + +static inline int seq_cmp(u32 a, u32 b) +{ + /* we assume wrap around at 32bit. + * for wrap around at 24bit (old atomic_t), + * we'd have to + * a <<= 8; b <<= 8; + */ + return ((s32)(a) - (s32)(b)); +} +#define seq_lt(a, b) (seq_cmp((a), (b)) < 0) +#define seq_gt(a, b) (seq_cmp((a), (b)) > 0) +#define seq_ge(a, b) (seq_cmp((a), (b)) >= 0) +#define seq_le(a, b) (seq_cmp((a), (b)) <= 0) +/* CAUTION: please no side effects in arguments! */ +#define seq_max(a, b) ((u32)(seq_gt((a), (b)) ? (a) : (b))) + +static inline void update_peer_seq(struct drbd_conf *mdev, unsigned int new_seq) +{ + unsigned int m; + spin_lock(&mdev->peer_seq_lock); + m = seq_max(mdev->peer_seq, new_seq); + mdev->peer_seq = m; + spin_unlock(&mdev->peer_seq_lock); + if (m == new_seq) + wake_up(&mdev->seq_wait); +} + +static inline int drbd_queue_order_type(struct drbd_conf *mdev) +{ + /* sorry, we currently have no working implementation + * of distributed TCQ stuff */ +#ifndef QUEUE_ORDERED_NONE +#define QUEUE_ORDERED_NONE 0 +#endif + return QUEUE_ORDERED_NONE; +} + +/* + * FIXME investigate what makes most sense: + * a) blk_run_queue(q); + * + * b) struct backing_dev_info *bdi; + * b1) bdi = &q->backing_dev_info; + * b2) bdi = mdev->bc->backing_bdev->bd_inode->i_mapping->backing_dev_info; + * blk_run_backing_dev(bdi,NULL); + * + * c) generic_unplug(q) ? __generic_unplug(q) ? + * + * d) q->unplug_fn(q), which is what all the drivers/md/ stuff uses... + * + */ +static inline void drbd_blk_run_queue(struct request_queue *q) +{ + if (q && q->unplug_fn) + q->unplug_fn(q); +} + +static inline void drbd_kick_lo(struct drbd_conf *mdev) +{ + if (inc_local(mdev)) { + drbd_blk_run_queue(bdev_get_queue(mdev->bc->backing_bdev)); + dec_local(mdev); + } +} +#endif --- linux-2.6.27.orig/ubuntu/drbd/drbd_proc.c +++ linux-2.6.27/ubuntu/drbd/drbd_proc.c @@ -0,0 +1,257 @@ +/* +-*- linux-c -*- + drbd_proc.c + Kernel module for 2.6.x Kernels + + This file is part of DRBD by Philipp Reisner and Lars Ellenberg. + + Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. + Copyright (C) 1999-2008, Philipp Reisner . + Copyright (C) 2002-2008, Lars Ellenberg . + + drbd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + drbd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with drbd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "drbd_int.h" +#include "lru_cache.h" /* for lc_sprintf_stats */ + +int drbd_proc_open(struct inode *inode, struct file *file); + + +struct proc_dir_entry *drbd_proc; +struct file_operations drbd_proc_fops = { + .owner = THIS_MODULE, + .open = drbd_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + + +/*lge + * progress bars shamelessly adapted from driver/md/md.c + * output looks like + * [=====>..............] 33.5% (23456/123456) + * finish: 2:20:20 speed: 6,345 (6,456) K/sec + */ +STATIC void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) +{ + unsigned long db, dt, dbdt, rt, rs_left; + unsigned int res; + int i, x, y; + + drbd_get_syncer_progress(mdev, &rs_left, &res); + + x = res/50; + y = 20-x; + seq_printf(seq, "\t["); + for (i = 1; i < x; i++) + seq_printf(seq, "="); + seq_printf(seq, ">"); + for (i = 0; i < y; i++) + seq_printf(seq, "."); + seq_printf(seq, "] "); + + seq_printf(seq, "sync'ed:%3u.%u%% ", res / 10, res % 10); + /* if more than 1 GB display in MB */ + if (mdev->rs_total > 0x100000L) + seq_printf(seq, "(%lu/%lu)M\n\t", + (unsigned long) Bit2KB(rs_left) >> 10, + (unsigned long) Bit2KB(mdev->rs_total) >> 10 ); + else + seq_printf(seq, "(%lu/%lu)K\n\t", + (unsigned long) Bit2KB(rs_left), + (unsigned long) Bit2KB(mdev->rs_total) ); + + /* see drivers/md/md.c + * We do not want to overflow, so the order of operands and + * the * 100 / 100 trick are important. We do a +1 to be + * safe against division by zero. We only estimate anyway. + * + * dt: time from mark until now + * db: blocks written from mark until now + * rt: remaining time + */ + dt = (jiffies - mdev->rs_mark_time) / HZ; + + if (dt > 20) { + /* if we made no update to rs_mark_time for too long, + * we are stalled. show that. */ + seq_printf(seq, "stalled\n"); + return; + } + + if (!dt) + dt++; + db = mdev->rs_mark_left - rs_left; + rt = (dt * (rs_left / (db/100+1)))/100; /* seconds */ + + seq_printf(seq, "finish: %lu:%02lu:%02lu", + rt / 3600, (rt % 3600) / 60, rt % 60); + + /* current speed average over (SYNC_MARKS * SYNC_MARK_STEP) jiffies */ + dbdt = Bit2KB(db/dt); + if (dbdt > 1000) + seq_printf(seq, " speed: %ld,%03ld", + dbdt/1000, dbdt % 1000); + else + seq_printf(seq, " speed: %ld", dbdt); + + /* mean speed since syncer started + * we do account for PausedSync periods */ + dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ; + if (dt <= 0) + dt = 1; + db = mdev->rs_total - rs_left; + dbdt = Bit2KB(db/dt); + if (dbdt > 1000) + seq_printf(seq, " (%ld,%03ld)", + dbdt/1000, dbdt % 1000); + else + seq_printf(seq, " (%ld)", dbdt); + + seq_printf(seq, " K/sec\n"); +} + +#ifdef ENABLE_DYNAMIC_TRACE +STATIC void resync_dump_detail(struct seq_file *seq, struct lc_element *e) +{ + struct bm_extent *bme = (struct bm_extent *)e; + + seq_printf(seq, "%5d %s %s\n", bme->rs_left, + bme->flags & BME_NO_WRITES ? "NO_WRITES" : "---------", + bme->flags & BME_LOCKED ? "LOCKED" : "------" + ); +} +#endif + +STATIC int drbd_seq_show(struct seq_file *seq, void *v) +{ + int i, hole = 0; + const char *sn; + struct drbd_conf *mdev; + + seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n", + API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX, drbd_buildtag()); + + /* + cs .. connection state + st .. node state (local/remote) + ld .. local data consistentency + ns .. network send + nr .. network receive + dw .. disk write + dr .. disk read + pe .. pending (waiting for ack) + ua .. unack'd (still need to send ack) + al .. access log write count + */ + + for (i = 0; i < minor_count; i++) { + mdev = minor_to_mdev(i); + if (!mdev) { + hole = 1; + continue; + } + if (hole) { + hole = 0; + seq_printf( seq, "\n"); + } + + sn = conns_to_name(mdev->state.conn); + + if ( mdev->state.conn == StandAlone && + mdev->state.disk == Diskless) { + seq_printf( seq, "%2d: cs:Unconfigured\n", i); + } else { + seq_printf( seq, + "%2d: cs:%s st:%s/%s ds:%s/%s %c %c%c%c%c\n" + " ns:%u nr:%u dw:%u dr:%u al:%u bm:%u " + "lo:%d pe:%d ua:%d ap:%d", + i, sn, + roles_to_name(mdev->state.role), + roles_to_name(mdev->state.peer), + disks_to_name(mdev->state.disk), + disks_to_name(mdev->state.pdsk), + (mdev->net_conf == NULL ? ' ' : + (mdev->net_conf->wire_protocol - DRBD_PROT_A+'A')), + mdev->state.susp ? 's' : 'r', + mdev->state.aftr_isp ? 'a' : '-', + mdev->state.peer_isp ? 'p' : '-', + mdev->state.user_isp ? 'u' : '-', + mdev->send_cnt/2, + mdev->recv_cnt/2, + mdev->writ_cnt/2, + mdev->read_cnt/2, + mdev->al_writ_cnt, + mdev->bm_writ_cnt, + atomic_read(&mdev->local_cnt), + atomic_read(&mdev->ap_pending_cnt) + + atomic_read(&mdev->rs_pending_cnt), + atomic_read(&mdev->unacked_cnt), + atomic_read(&mdev->ap_bio_cnt) + ); + seq_printf(seq, " oos:%lu\n", + drbd_bm_total_weight(mdev) << (BM_BLOCK_SIZE_B - 10)); + } + if ( mdev->state.conn == SyncSource || + mdev->state.conn == SyncTarget ) + drbd_syncer_progress(mdev, seq); + + if ( mdev->state.conn == VerifyS || + mdev->state.conn == VerifyT ) { + seq_printf(seq,"\t%3d%% %lu/%lu\n", + (int)((mdev->rs_total-mdev->ov_left) / + (mdev->rs_total/100+1)), + mdev->rs_total - mdev->ov_left, + mdev->rs_total); + } + +#ifdef ENABLE_DYNAMIC_TRACE + if (proc_details >= 1 && inc_local_if_state(mdev, Failed)) { + lc_printf_stats(seq, mdev->resync); + lc_printf_stats(seq, mdev->act_log); + dec_local(mdev); + } + + if (proc_details >= 2) { + if (mdev->resync) { + lc_dump(mdev->resync, seq, "rs_left", + resync_dump_detail); + } + } +#endif + } + + return 0; +} + +int drbd_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, drbd_seq_show, PDE(inode)->data); +} + +/* PROC FS stuff end */ --- linux-2.6.27.orig/ubuntu/drbd/drbd_strings.c +++ linux-2.6.27/ubuntu/drbd/drbd_strings.c @@ -0,0 +1,116 @@ +/* + drbd.h + Kernel module for 2.6.x Kernels + + This file is part of DRBD by Philipp Reisner and Lars Ellenberg. + + Copyright (C) 2003-2008, LINBIT Information Technologies GmbH. + Copyright (C) 2003-2008, Philipp Reisner . + Copyright (C) 2003-2008, Lars Ellenberg . + + drbd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + drbd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with drbd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include + +static const char *drbd_conn_s_names[] = { + [StandAlone] = "StandAlone", + [Disconnecting] = "Disconnecting", + [Unconnected] = "Unconnected", + [Timeout] = "Timeout", + [BrokenPipe] = "BrokenPipe", + [NetworkFailure] = "NetworkFailure", + [ProtocolError] = "ProtocolError", + [WFConnection] = "WFConnection", + [WFReportParams] = "WFReportParams", + [TearDown] = "TearDown", + [Connected] = "Connected", + [StartingSyncS] = "StartingSyncS", + [StartingSyncT] = "StartingSyncT", + [WFBitMapS] = "WFBitMapS", + [WFBitMapT] = "WFBitMapT", + [WFSyncUUID] = "WFSyncUUID", + [SyncSource] = "SyncSource", + [SyncTarget] = "SyncTarget", + [VerifyS] = "VerifyS", + [VerifyT] = "VerifyT", + [PausedSyncS] = "PausedSyncS", + [PausedSyncT] = "PausedSyncT" +}; + +static const char *drbd_role_s_names[] = { + [Primary] = "Primary", + [Secondary] = "Secondary", + [Unknown] = "Unknown" +}; + +static const char *drbd_disk_s_names[] = { + [Diskless] = "Diskless", + [Attaching] = "Attaching", + [Failed] = "Failed", + [Negotiating] = "Negotiating", + [Inconsistent] = "Inconsistent", + [Outdated] = "Outdated", + [DUnknown] = "DUnknown", + [Consistent] = "Consistent", + [UpToDate] = "UpToDate", +}; + +static const char *drbd_state_sw_errors[] = { + [-SS_TwoPrimaries] = "Multiple primaries not allowed by config", + [-SS_NoUpToDateDisk] = + "Refusing to be Primary without at least one UpToDate disk", + [-SS_BothInconsistent] = "Refusing to be inconsistent on both nodes", + [-SS_SyncingDiskless] = "Refusing to be syncing and diskless", + [-SS_ConnectedOutdates] = "Refusing to be Outdated while Connected", + [-SS_PrimaryNOP] = "Refusing to be Primary while peer is not outdated", + [-SS_ResyncRunning] = "Can not start OV/resync since it is already active", + [-SS_AlreadyStandAlone] = "Can not disconnect a StandAlone device", + [-SS_CW_FailedByPeer] = "State changed was refused by peer node", + [-SS_IsDiskLess] = + "Device is diskless, the requesed operation requires a disk", + [-SS_DeviceInUse] = "Device is held open by someone", + [-SS_NoNetConfig] = "Have no net/connection configuration", + [-SS_NoVerifyAlg] = "Need a verify algorithm to start online verify", + [-SS_NeedConnection] = "Need a connection to start verify or resync", + [-SS_NotSupported] = "Peer does not support protocol", + [-SS_LowerThanOutdated] = "Disk state is lower than outdated", + [-SS_InTransientState] = "In transient state, retry after next state change", + [-SS_ConcurrentStChg] = "Concurrent state changes detected and aborted", +}; + +const char *conns_to_name(enum drbd_conns s) +{ + /* enums are unsigned... */ + return s > PausedSyncT ? "TOO_LARGE" : drbd_conn_s_names[s]; +} + +const char *roles_to_name(enum drbd_role s) +{ + return s > Secondary ? "TOO_LARGE" : drbd_role_s_names[s]; +} + +const char *disks_to_name(enum drbd_disk_state s) +{ + return s > UpToDate ? "TOO_LARGE" : drbd_disk_s_names[s]; +} + +const char *set_st_err_name(enum set_st_err err) +{ + return err < SS_NotSupported ? "TOO_SMALL" : + err > SS_TwoPrimaries ? "TOO_LARGE" + : drbd_state_sw_errors[-err]; +} --- linux-2.6.27.orig/ubuntu/drbd/drbd_receiver.c +++ linux-2.6.27/ubuntu/drbd/drbd_receiver.c @@ -0,0 +1,3652 @@ +/* +-*- linux-c -*- + drbd_receiver.c + Kernel module for 2.6.x Kernels + + This file is part of DRBD by Philipp Reisner and Lars Ellenberg. + + Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. + Copyright (C) 1999-2008, Philipp Reisner . + Copyright (C) 2002-2008, Lars Ellenberg . + + drbd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + drbd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with drbd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define __KERNEL_SYSCALLS__ +#include +#include +#include +#ifdef HAVE_LINUX_SCATTERLIST_H +#include +#endif +#include +#include "drbd_int.h" +#include "drbd_req.h" + +#ifdef DBG_ASSERTS +void drbd_assert_breakpoint(struct drbd_conf *mdev, char *exp, + char *file, int line) +{ + ERR("ASSERT( %s ) in %s:%d\n", exp, file, line); +} +#endif + +#define GFP_TRY ( __GFP_HIGHMEM | __GFP_NOWARN ) + +/** + * drbd_bp_alloc: Returns a page. Fails only if a signal comes in. + */ +STATIC struct page *drbd_pp_alloc(struct drbd_conf *mdev, gfp_t gfp_mask) +{ + unsigned long flags = 0; + struct page *page; + DEFINE_WAIT(wait); + + /* FIXME Add some usefull watermark again to "kick_lo", if pages get + * used up too quickly. The watermark that had been in place here did + * not make sense. + */ + + spin_lock_irqsave(&drbd_pp_lock, flags); + /* This lock needs to lock out irq because we might call drbd_pp_free() + from IRQ context. + FIXME but why irq _save_ ? + this is only called from drbd_alloc_ee, + and that is strictly process context! */ + page = drbd_pp_pool; + if (page) { + drbd_pp_pool = (struct page *)page_private(page); + set_page_private(page, 0); /* just to be polite */ + drbd_pp_vacant--; + } + spin_unlock_irqrestore(&drbd_pp_lock, flags); + if (page) + goto got_page; + + drbd_kick_lo(mdev); + + for (;;) { + prepare_to_wait(&drbd_pp_wait, &wait, TASK_INTERRUPTIBLE); + + /* try the pool again, maybe the drbd_kick_lo set some free */ + spin_lock_irqsave(&drbd_pp_lock, flags); + page = drbd_pp_pool; + if (page) { + drbd_pp_pool = (struct page *)page_private(page); + drbd_pp_vacant--; + } + spin_unlock_irqrestore(&drbd_pp_lock, flags); + + if (page) + break; + + /* hm. pool was empty. try to allocate from kernel. + * don't wait, if none is available, though. + */ + if (atomic_read(&mdev->pp_in_use) + < mdev->net_conf->max_buffers) { + page = alloc_page(GFP_TRY); + if (page) + break; + } + + /* doh. still no page. + * either used up the configured maximum number, + * or we are low on memory. + * wait for someone to return a page into the pool. + * unless, of course, someone signalled us. + */ + if (signal_pending(current)) { + DRBD_WARN("drbd_pp_alloc interrupted!\n"); + finish_wait(&drbd_pp_wait, &wait); + return NULL; + } + drbd_kick_lo(mdev); + schedule(); + } + finish_wait(&drbd_pp_wait, &wait); + + got_page: + atomic_inc(&mdev->pp_in_use); + return page; +} + +STATIC void drbd_pp_free(struct drbd_conf *mdev, struct page *page) +{ + unsigned long flags = 0; + int free_it; + + spin_lock_irqsave(&drbd_pp_lock, flags); + if (drbd_pp_vacant > (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE)*minor_count) { + free_it = 1; + } else { + set_page_private(page, (unsigned long)drbd_pp_pool); + drbd_pp_pool = page; + drbd_pp_vacant++; + free_it = 0; + } + spin_unlock_irqrestore(&drbd_pp_lock, flags); + + atomic_dec(&mdev->pp_in_use); + + if (free_it) + __free_page(page); + + /* + * FIXME + * typically there are no waiters. + * we should try to avoid any unnecessary call to wake_up. + */ + wake_up(&drbd_pp_wait); +} + +/* +You need to hold the req_lock: + drbd_free_ee() + _drbd_wait_ee_list_empty() + +You must not have the req_lock: + drbd_alloc_ee() + drbd_init_ee() + drbd_release_ee() + drbd_ee_fix_bhs() + drbd_process_done_ee() + drbd_clear_done_ee() + drbd_wait_ee_list_empty() +*/ + +struct Tl_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, + u64 id, + sector_t sector, + unsigned int data_size, + gfp_t gfp_mask) __must_hold(local) +{ + struct request_queue *q; + struct Tl_epoch_entry *e; + struct bio_vec *bvec; + struct page *page; + struct bio *bio; + unsigned int ds; + int i; + + e = mempool_alloc(drbd_ee_mempool, gfp_mask); + if (!e) { + ERR("alloc_ee: Allocation of an EE failed\n"); + return NULL; + } + + bio = bio_alloc(GFP_KERNEL, div_ceil(data_size, PAGE_SIZE)); + if (!bio) { + ERR("alloc_ee: Allocation of a bio failed\n"); + goto fail1; + } + + bio->bi_bdev = mdev->bc->backing_bdev; + bio->bi_sector = sector; + + ds = data_size; + while (ds) { + page = drbd_pp_alloc(mdev, gfp_mask); + if (!page) { + ERR("alloc_ee: Allocation of a page failed\n"); + goto fail2; + } + if (!bio_add_page(bio, page, min_t(int, ds, PAGE_SIZE), 0)) { + drbd_pp_free(mdev, page); + ERR("alloc_ee: bio_add_page(s=%llu," + "data_size=%u,ds=%u) failed\n", + (unsigned long long)sector, data_size, ds); + + q = bdev_get_queue(bio->bi_bdev); + if (q->merge_bvec_fn) { + struct bvec_merge_data bvm = { + .bi_bdev = bio->bi_bdev, + .bi_sector = bio->bi_sector, + .bi_size = bio->bi_size, + .bi_rw = bio->bi_rw, + }; + ERR("merge_bvec_fn() = %d\n", + q->merge_bvec_fn(q, &bvm, + &bio->bi_io_vec[bio->bi_vcnt])); + } + + /* dump more of the bio. */ + DUMPI(bio->bi_max_vecs); + DUMPI(bio->bi_vcnt); + DUMPI(bio->bi_size); + DUMPI(bio->bi_phys_segments); + DUMPI(bio->bi_hw_segments); + + goto fail2; + break; + } + ds -= min_t(int, ds, PAGE_SIZE); + } + + D_ASSERT( data_size == bio->bi_size); + + bio->bi_private = e; + e->mdev = mdev; + e->sector = sector; + e->size = bio->bi_size; + + e->private_bio = bio; + e->block_id = id; + INIT_HLIST_NODE(&e->colision); + e->barrier_nr = 0; + e->barrier_nr2 = 0; + e->flags = 0; + + MTRACE(TraceTypeEE, TraceLvlAll, + INFO("allocated EE sec=%llus size=%u ee=%p\n", + (unsigned long long)sector, data_size, e); + ); + + return e; + + fail2: + __bio_for_each_segment(bvec, bio, i, 0) { + drbd_pp_free(mdev, bvec->bv_page); + } + bio_put(bio); + fail1: + mempool_free(e, drbd_ee_mempool); + + return NULL; +} + +void drbd_free_ee(struct drbd_conf *mdev, struct Tl_epoch_entry *e) +{ + struct bio *bio = e->private_bio; + struct bio_vec *bvec; + int i; + + MTRACE(TraceTypeEE, TraceLvlAll, + INFO("Free EE sec=%llus size=%u ee=%p\n", + (unsigned long long)e->sector, e->size, e); + ); + + __bio_for_each_segment(bvec, bio, i, 0) { + drbd_pp_free(mdev, bvec->bv_page); + } + + bio_put(bio); + + D_ASSERT(hlist_unhashed(&e->colision)); + + mempool_free(e, drbd_ee_mempool); +} + +/* currently on module unload only */ +int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list) +{ + int count = 0; + struct Tl_epoch_entry *e; + struct list_head *le; + + spin_lock_irq(&mdev->req_lock); + while (!list_empty(list)) { + le = list->next; + list_del(le); + e = list_entry(le, struct Tl_epoch_entry, w.list); + drbd_free_ee(mdev, e); + count++; + } + spin_unlock_irq(&mdev->req_lock); + + return count; +} + + +STATIC void reclaim_net_ee(struct drbd_conf *mdev) +{ + struct Tl_epoch_entry *e; + struct list_head *le, *tle; + + /* The EEs are always appended to the end of the list. Since + they are sent in order over the wire, they have to finish + in order. As soon as we see the first not finished we can + stop to examine the list... */ + + list_for_each_safe(le, tle, &mdev->net_ee) { + e = list_entry(le, struct Tl_epoch_entry, w.list); + if ( drbd_bio_has_active_page(e->private_bio) ) break; + list_del(le); + drbd_free_ee(mdev, e); + } +} + + +/* + * This function is called from _asender only_ + * but see also comments in _req_mod(,barrier_acked) + * and receive_Barrier_no_tcq. + * + * Move entries from net_ee to done_ee, if ready. + * Grab done_ee, call all callbacks, free the entries. + * The callbacks typically send out ACKs. + */ +STATIC int drbd_process_done_ee(struct drbd_conf *mdev) +{ + LIST_HEAD(work_list); + struct Tl_epoch_entry *e, *t; + int ok = 1; + int do_clear_bit = test_bit(WRITE_ACK_PENDING, &mdev->flags); + + spin_lock_irq(&mdev->req_lock); + reclaim_net_ee(mdev); + list_splice_init(&mdev->done_ee, &work_list); + spin_unlock_irq(&mdev->req_lock); + + /* possible callbacks here: + * e_end_block, and e_end_resync_block, e_send_discard_ack. + * all ignore the last argument. + */ + list_for_each_entry_safe(e, t, &work_list, w.list) { + MTRACE(TraceTypeEE, TraceLvlAll, + INFO("Process EE on done_ee sec=%llus size=%u ee=%p\n", + (unsigned long long)e->sector, e->size, e); + ); + /* list_del not necessary, next/prev members not touched */ + if (e->w.cb(mdev, &e->w, 0) == 0) ok = 0; + drbd_free_ee(mdev, e); + } + if (do_clear_bit) + clear_bit(WRITE_ACK_PENDING, &mdev->flags); + wake_up(&mdev->ee_wait); + + return ok; +} + + + +/* clean-up helper for drbd_disconnect */ +void _drbd_clear_done_ee(struct drbd_conf *mdev) +{ + struct list_head *le; + struct Tl_epoch_entry *e; + int n = 0; + + MUST_HOLD(&mdev->req_lock); + + reclaim_net_ee(mdev); + + while (!list_empty(&mdev->done_ee)) { + le = mdev->done_ee.next; + list_del(le); + e = list_entry(le, struct Tl_epoch_entry, w.list); + if (mdev->net_conf->wire_protocol == DRBD_PROT_C + || is_syncer_block_id(e->block_id)) + ++n; + + if (!hlist_unhashed(&e->colision)) hlist_del_init(&e->colision); + drbd_free_ee(mdev, e); + } + + sub_unacked(mdev, n); +} + +void _drbd_wait_ee_list_empty(struct drbd_conf *mdev, struct list_head *head) +{ + DEFINE_WAIT(wait); + MUST_HOLD(&mdev->req_lock); + + /* avoids spin_lock/unlock + * and calling prepare_to_wait in the fast path */ + while (!list_empty(head)) { + prepare_to_wait(&mdev->ee_wait, &wait, TASK_UNINTERRUPTIBLE); + spin_unlock_irq(&mdev->req_lock); + drbd_kick_lo(mdev); + schedule(); + finish_wait(&mdev->ee_wait, &wait); + spin_lock_irq(&mdev->req_lock); + } +} + +void drbd_wait_ee_list_empty(struct drbd_conf *mdev, struct list_head *head) +{ + spin_lock_irq(&mdev->req_lock); + _drbd_wait_ee_list_empty(mdev, head); + spin_unlock_irq(&mdev->req_lock); +} + +STATIC struct socket *drbd_accept(struct drbd_conf *mdev, struct socket *sock) +{ + struct socket *newsock; + int err = 0; + + err = sock->ops->listen(sock, 5); + if (err) + goto out; + + if (sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &newsock)) + goto out; + + newsock->type = sock->type; + newsock->ops = sock->ops; + + err = newsock->ops->accept(sock, newsock, 0); + if (err < 0) + goto out_release; + + return newsock; + +out_release: + sock_release(newsock); +out: + if (err != -EAGAIN && err != -EINTR) + ERR("accept failed! %d\n", err); + return NULL; +} + +STATIC int drbd_recv_short(struct drbd_conf *mdev, struct socket *sock, + void *buf, size_t size, int flags) +{ + mm_segment_t oldfs; + struct kvec iov = { + .iov_base = buf, + .iov_len = size, + }; + struct msghdr msg = { + .msg_iovlen = 1, + .msg_iov = (struct iovec *)&iov, + .msg_flags = (flags ? flags : MSG_WAITALL | MSG_NOSIGNAL) + }; + int rv; + + oldfs = get_fs(); + set_fs(KERNEL_DS); + rv = sock_recvmsg(sock, &msg, size, msg.msg_flags); + set_fs(oldfs); + + return rv; +} + +STATIC int drbd_recv(struct drbd_conf *mdev, void *buf, size_t size) +{ + mm_segment_t oldfs; + struct kvec iov = { + .iov_base = buf, + .iov_len = size, + }; + struct msghdr msg = { + .msg_iovlen = 1, + .msg_iov = (struct iovec *)&iov, + .msg_flags = MSG_WAITALL | MSG_NOSIGNAL + }; + int rv; + + oldfs = get_fs(); + set_fs(KERNEL_DS); + + for (;;) { + rv = sock_recvmsg(mdev->data.socket, &msg, size, msg.msg_flags); + if (rv == size) + break; + + /* Note: + * ECONNRESET other side closed the connection + * ERESTARTSYS (on sock) we got a signal + */ + + if (rv < 0) { + if (rv == -ECONNRESET) + INFO("sock was reset by peer\n"); + else if (rv != -ERESTARTSYS) + ERR("sock_recvmsg returned %d\n", rv); + break; + } else if (rv == 0) { + INFO("sock was shut down by peer\n"); + break; + } else { + /* signal came in, or peer/link went down, + * after we read a partial message + */ + /* D_ASSERT(signal_pending(current)); */ + break; + } + }; + + set_fs(oldfs); + + if (rv != size) + drbd_force_state(mdev, NS(conn, BrokenPipe)); + + return rv; +} + +STATIC struct socket *drbd_try_connect(struct drbd_conf *mdev) +{ + int err; + struct socket *sock; + struct sockaddr_in src_in; + + if (!inc_net(mdev)) return NULL; + + err = sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); + if (err) { + dec_net(mdev); + ERR("sock_creat(..)=%d\n", err); + return NULL; + } + + sock->sk->sk_rcvtimeo = + sock->sk->sk_sndtimeo = mdev->net_conf->try_connect_int*HZ; + + /* explicitly bind to the configured IP as source IP + * for the outgoing connections. + * This is needed for multihomed hosts and to be + * able to use lo: interfaces for drbd. + * Make sure to use 0 as portnumber, so linux selects + * a free one dynamically. + */ + memcpy(&src_in, &(mdev->net_conf->my_addr), sizeof(struct sockaddr_in)); + src_in.sin_port = 0; + + err = sock->ops->bind(sock, + (struct sockaddr *) &src_in, + sizeof(struct sockaddr_in)); + if (err) { + ERR("Unable to bind source sock (%d)\n", err); + sock_release(sock); + sock = NULL; + dec_net(mdev); + return sock; + } + + err = sock->ops->connect(sock, + (struct sockaddr *)mdev->net_conf->peer_addr, + mdev->net_conf->peer_addr_len, 0); + + if (err) { + sock_release(sock); + sock = NULL; + } + + dec_net(mdev); + return sock; +} + +STATIC struct socket *drbd_wait_for_connect(struct drbd_conf *mdev) +{ + int err; + struct socket *sock, *sock2; + + if (!inc_net(mdev)) return NULL; + + err = sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock2); + if (err) { + dec_net(mdev); + ERR("sock_creat(..)=%d\n", err); + return NULL; + } + + sock2->sk->sk_reuse = 1; /* SO_REUSEADDR */ + sock2->sk->sk_rcvtimeo = + sock2->sk->sk_sndtimeo = mdev->net_conf->try_connect_int*HZ; + + err = sock2->ops->bind(sock2, + (struct sockaddr *) mdev->net_conf->my_addr, + mdev->net_conf->my_addr_len); + dec_net(mdev); + + if (err) { + ERR("Unable to bind sock2 (%d)\n", err); + sock_release(sock2); + drbd_force_state(mdev, NS(conn, Disconnecting)); + return NULL; + } + + sock = drbd_accept(mdev, sock2); + sock_release(sock2); + + return sock; +} + +int drbd_do_handshake(struct drbd_conf *mdev); +int drbd_do_auth(struct drbd_conf *mdev); + +STATIC int drbd_send_fp(struct drbd_conf *mdev, + struct socket *sock, enum Drbd_Packet_Cmd cmd) +{ + struct Drbd_Header *h = (struct Drbd_Header *) &mdev->data.sbuf.head; + + return _drbd_send_cmd(mdev, sock, cmd, h, sizeof(*h), 0); +} + +STATIC enum Drbd_Packet_Cmd drbd_recv_fp(struct drbd_conf *mdev, struct socket *sock) +{ + struct Drbd_Header *h = (struct Drbd_Header *) &mdev->data.sbuf.head; + int rr; + + rr = drbd_recv_short(mdev, sock, h, sizeof(*h), 0); + + if (rr == sizeof(*h) && h->magic == BE_DRBD_MAGIC) + return be16_to_cpu(h->command); + + return 0xffff; +} + +/** + * drbd_socket_okay: + * Tests if the connection behind the socket still exists. If not it frees + * the socket. + */ +STATIC int drbd_socket_okay(struct drbd_conf *mdev, struct socket **sock) +{ + int rr; + char tb[4]; + + rr = drbd_recv_short(mdev, *sock, tb, 4, MSG_DONTWAIT | MSG_PEEK); + + if (rr > 0 || rr == -EAGAIN) { + return TRUE; + } else { + sock_release(*sock); + *sock = NULL; + return FALSE; + } +} + +/* + * return values: + * 1 yess, we have a valid connection + * 0 oops, did not work out, please try again + * -1 peer talks different language, + * no point in trying again, please go standalone. + * -2 We do not have a network config... + */ +STATIC int drbd_connect(struct drbd_conf *mdev) +{ + struct socket *s, *sock, *msock; + int try, h, ok; + + D_ASSERT(!mdev->data.socket); + + if (test_and_clear_bit(CREATE_BARRIER, &mdev->flags)) + ERR("CREATE_BARRIER flag was set in drbd_connect - now cleared!\n"); + + if (drbd_request_state(mdev, NS(conn, WFConnection)) < SS_Success ) + return -2; + + clear_bit(DISCARD_CONCURRENT, &mdev->flags); + + sock = NULL; + msock = NULL; + + do { + for (try = 0;;) { + /* 3 tries, this should take less than a second! */ + s = drbd_try_connect(mdev); + if (s || ++try >= 3) + break; + /* give the other side time to call bind() & listen() */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 10); + } + + if (s) { + if (!sock) { + drbd_send_fp(mdev, s, HandShakeS); + sock = s; + s = NULL; + } else if (!msock) { + drbd_send_fp(mdev, s, HandShakeM); + msock = s; + s = NULL; + } else { + ERR("Logic error in drbd_connect()\n"); + return -1; + } + } + + if (sock && msock) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 10); + ok = drbd_socket_okay(mdev, &sock); + ok = drbd_socket_okay(mdev, &msock) && ok; + if (ok) break; + } + + s = drbd_wait_for_connect(mdev); + if (s) { + switch (drbd_recv_fp(mdev, s)) { + case HandShakeS: + if (sock) + sock_release(sock); + sock = s; + break; + case HandShakeM: + if (msock) + sock_release(msock); + msock = s; + set_bit(DISCARD_CONCURRENT, &mdev->flags); + break; + default: + DRBD_WARN("Error receiving initial packet\n"); + sock_release(s); + } + } + + if (mdev->state.conn <= Disconnecting) + return -1; + if (signal_pending(current)) { + flush_signals(current); + smp_rmb(); + if (get_t_state(&mdev->receiver) == Exiting) { + if (sock) + sock_release(sock); + if (msock) + sock_release(msock); + return -1; + } + } + + if (sock && msock) { + ok = drbd_socket_okay(mdev, &sock); + ok = drbd_socket_okay(mdev, &msock) && ok; + if (ok) break; + } + } while (1); + + msock->sk->sk_reuse = 1; /* SO_REUSEADDR */ + sock->sk->sk_reuse = 1; /* SO_REUSEADDR */ + + sock->sk->sk_allocation = GFP_NOIO; + msock->sk->sk_allocation = GFP_NOIO; + + sock->sk->sk_priority = TC_PRIO_BULK; + /* FIXME fold to limits. should be done in drbd_ioctl */ + sock->sk->sk_sndbuf = mdev->net_conf->sndbuf_size; + sock->sk->sk_rcvbuf = mdev->net_conf->sndbuf_size; + /* NOT YET ... + * sock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10; + * sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; + * first set it to the HandShake timeout, wich is hardcoded for now: */ + sock->sk->sk_sndtimeo = + sock->sk->sk_rcvtimeo = 2*HZ; + sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK | SOCK_RCVBUF_LOCK; + + msock->sk->sk_priority = TC_PRIO_INTERACTIVE; + msock->sk->sk_sndbuf = 2*32767; + msock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10; + msock->sk->sk_rcvtimeo = mdev->net_conf->ping_int*HZ; + + mdev->data.socket = sock; + mdev->meta.socket = msock; + mdev->last_received = jiffies; + + D_ASSERT(mdev->asender.task == NULL); + + h = drbd_do_handshake(mdev); + if (h <= 0) + return h; + + if (mdev->cram_hmac_tfm) { + /* drbd_request_state(mdev, NS(conn, WFAuth)); */ + if (!drbd_do_auth(mdev)) { + ERR("Authentication of peer failed\n"); + return -1; + } + } + + if (drbd_request_state(mdev, NS(conn, WFReportParams)) < SS_Success) + return 0; + + sock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10; + sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; + + atomic_set(&mdev->packet_seq, 0); + mdev->peer_seq = 0; + + drbd_thread_start(&mdev->asender); + + drbd_send_protocol(mdev); + drbd_send_sync_param(mdev, &mdev->sync_conf); + drbd_send_sizes(mdev); + drbd_send_uuids(mdev); + drbd_send_state(mdev); + clear_bit(USE_DEGR_WFC_T, &mdev->flags); + + return 1; +} + +STATIC int drbd_recv_header(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + int r; + + r = drbd_recv(mdev, h, sizeof(*h)); + + if (unlikely( r != sizeof(*h) )) { + ERR("short read expecting header on sock: r=%d\n", r); + return FALSE; + }; + h->command = be16_to_cpu(h->command); + h->length = be16_to_cpu(h->length); + if (unlikely( h->magic != BE_DRBD_MAGIC )) { + ERR("magic?? on data m: 0x%lx c: %d l: %d\n", + (long)be32_to_cpu(h->magic), + h->command, h->length); + return FALSE; + } + mdev->last_received = jiffies; + + return TRUE; +} + +STATIC int receive_Barrier_no_tcq(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + int rv; + int epoch_size; + struct Drbd_Barrier_Packet *p = (struct Drbd_Barrier_Packet *)h; + + ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE; + + rv = drbd_recv(mdev, h->payload, h->length); + ERR_IF(rv != h->length) return FALSE; + + inc_unacked(mdev); + + if (mdev->net_conf->wire_protocol != DRBD_PROT_C) + drbd_kick_lo(mdev); + + spin_lock_irq(&mdev->req_lock); + _drbd_wait_ee_list_empty(mdev, &mdev->active_ee); + epoch_size = mdev->epoch_size; + mdev->epoch_size = 0; + spin_unlock_irq(&mdev->req_lock); + + /* BarrierAck may imply that the corresponding extent is dropped from + * the activity log, which means it would not be resynced in case the + * Primary crashes now. + * Just waiting for write_completion is not enough, + * better flush to make sure it is all on stable storage. */ + if (!test_bit(LL_DEV_NO_FLUSH, &mdev->flags) && inc_local(mdev)) { + rv = blkdev_issue_flush(mdev->bc->backing_bdev, NULL); + dec_local(mdev); + if (rv == -EOPNOTSUPP) /* don't try again */ + set_bit(LL_DEV_NO_FLUSH, &mdev->flags); + if (rv) + ERR("local disk flush failed with status %d\n",rv); + } + + /* FIXME CAUTION! receiver thread sending via msock. + * to make sure this BarrierAck will not be received before the asender + * had a chance to send all the write acks corresponding to this epoch, + * wait_for that bit to clear... */ + set_bit(WRITE_ACK_PENDING, &mdev->flags); + wake_asender(mdev); + rv = wait_event_interruptible(mdev->ee_wait, + !test_bit(WRITE_ACK_PENDING, &mdev->flags)); + + if (rv == 0 && mdev->state.conn >= Connected) + rv = drbd_send_b_ack(mdev, p->barrier, epoch_size); + else + rv = 0; + dec_unacked(mdev); + + return rv; +} + +/* used from receive_RSDataReply (recv_resync_read) + * and from receive_Data */ +STATIC struct Tl_epoch_entry * +read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __must_hold(local) +{ + struct Tl_epoch_entry *e; + struct bio_vec *bvec; + struct page *page; + struct bio *bio; + int dgs, ds, i, rr; + void *dig_in = mdev->int_dig_in; + void *dig_vv = mdev->int_dig_vv; + + dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_r_tfm) ? + crypto_hash_digestsize(mdev->integrity_r_tfm) : 0; + + if (dgs) { + rr = drbd_recv(mdev, dig_in, dgs); + if (rr != dgs) { + DRBD_WARN("short read receiving data digest: read %d expected %d\n", + rr, dgs); + return NULL; + } + } + + data_size -= dgs; + + ERR_IF(data_size & 0x1ff) return NULL; + ERR_IF(data_size > DRBD_MAX_SEGMENT_SIZE) return NULL; + + e = drbd_alloc_ee(mdev, id, sector, data_size, GFP_KERNEL); + if (!e) + return NULL; + bio = e->private_bio; + ds = data_size; + bio_for_each_segment(bvec, bio, i) { + page = bvec->bv_page; + rr = drbd_recv(mdev, kmap(page), min_t(int, ds, PAGE_SIZE)); + kunmap(page); + if ( rr != min_t(int, ds, PAGE_SIZE) ) { + drbd_free_ee(mdev, e); + DRBD_WARN("short read receiving data: read %d expected %d\n", + rr, min_t(int, ds, PAGE_SIZE)); + return NULL; + } + ds -= rr; + } + + if (dgs) { + drbd_csum(mdev, mdev->integrity_r_tfm, bio, dig_vv); + if (memcmp(dig_in,dig_vv,dgs)) { + ERR("Digest integrity check FAILED.\n"); + drbd_bcast_ee(mdev, "digest failed", + dgs, dig_in, dig_vv, e); + drbd_free_ee(mdev, e); + return NULL; + } + } + mdev->recv_cnt += data_size>>9; + return e; +} + +/* drbd_drain_block() just takes a data block + * out of the socket input buffer, and discards it. + */ +STATIC int drbd_drain_block(struct drbd_conf *mdev, int data_size) +{ + struct page *page; + int rr, rv = 1; + void *data; + + page = drbd_pp_alloc(mdev, GFP_KERNEL); + + data = kmap(page); + while (data_size) { + rr = drbd_recv(mdev, data, min_t(int, data_size, PAGE_SIZE)); + if ( rr != min_t(int, data_size, PAGE_SIZE) ) { + rv = 0; + DRBD_WARN("short read receiving data: read %d expected %d\n", + rr, min_t(int, data_size, PAGE_SIZE)); + break; + } + data_size -= rr; + } + kunmap(page); + drbd_pp_free(mdev, page); + return rv; +} + +/* kick lower level device, if we have more than (arbitrary number) + * reference counts on it, which typically are locally submitted io + * requests. don't use unacked_cnt, so we speed up proto A and B, too. */ +static void maybe_kick_lo(struct drbd_conf *mdev) +{ + /* FIXME hysteresis ?? */ + if (atomic_read(&mdev->local_cnt) >= mdev->net_conf->unplug_watermark) + drbd_kick_lo(mdev); +} + +STATIC int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, + sector_t sector, int data_size) +{ + struct bio_vec *bvec; + struct bio *bio; + int dgs, rr, i, expect; + void *dig_in = mdev->int_dig_in; + void *dig_vv = mdev->int_dig_vv; + + dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_r_tfm) ? + crypto_hash_digestsize(mdev->integrity_r_tfm) : 0; + + if (dgs) { + rr = drbd_recv(mdev, dig_in, dgs); + if (rr != dgs) { + DRBD_WARN("short read receiving data reply digest: read %d expected %d\n", + rr, dgs); + return 0; + } + } + + data_size -= dgs; + + bio = req->master_bio; + D_ASSERT( sector == bio->bi_sector ); + + bio_for_each_segment(bvec, bio, i) { + expect = min_t(int, data_size, bvec->bv_len); + rr = drbd_recv(mdev, + kmap(bvec->bv_page)+bvec->bv_offset, + expect); + kunmap(bvec->bv_page); + if (rr != expect) { + DRBD_WARN("short read receiving data reply: " + "read %d expected %d\n", + rr, expect); + return 0; + } + data_size -= rr; + } + + if (dgs) { + drbd_csum(mdev, mdev->integrity_r_tfm, bio, dig_vv); + if (memcmp(dig_in,dig_vv,dgs)) { + ERR("Digest integrity check FAILED. Broken NICs?\n"); + return 0; + } + } + + D_ASSERT(data_size == 0); + /* FIXME recv_cnt accounting ?? */ + return 1; +} + +/* e_end_resync_block() is called via + * drbd_process_done_ee() by asender only */ +STATIC int e_end_resync_block(struct drbd_conf *mdev, struct drbd_work *w, int unused) +{ + struct Tl_epoch_entry *e = (struct Tl_epoch_entry *)w; + sector_t sector = e->sector; + int ok; + + D_ASSERT(hlist_unhashed(&e->colision)); + + if (likely( drbd_bio_uptodate(e->private_bio) )) { + drbd_set_in_sync(mdev, sector, e->size); + ok = drbd_send_ack(mdev, RSWriteAck, e); + } else { + /* Record failure to sync */ + drbd_rs_failed_io(mdev, sector, e->size); + + ok = drbd_send_ack(mdev, NegAck, e); + ok &= drbd_io_error(mdev, FALSE); + } + dec_unacked(mdev); + + return ok; +} + +STATIC int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_size) __releases(local) +{ + struct Tl_epoch_entry *e; + + e = read_in_block(mdev, ID_SYNCER, sector, data_size); + if (!e) { + dec_local(mdev); + return FALSE; + } + + dec_rs_pending(mdev); + + e->private_bio->bi_end_io = drbd_endio_write_sec; + e->private_bio->bi_rw = WRITE; + e->w.cb = e_end_resync_block; + + inc_unacked(mdev); + /* corresponding dec_unacked() in e_end_resync_block() + * respective _drbd_clear_done_ee */ + + spin_lock_irq(&mdev->req_lock); + list_add(&e->w.list, &mdev->sync_ee); + spin_unlock_irq(&mdev->req_lock); + + MTRACE(TraceTypeEE, TraceLvlAll, + INFO("submit EE (RS)WRITE sec=%llus size=%u ee=%p\n", + (unsigned long long)e->sector, e->size, e); + ); + dump_internal_bio("Sec", mdev, e->private_bio, 0); + drbd_generic_make_request(mdev, DRBD_FAULT_RS_WR, e->private_bio); + /* accounting done in endio */ + + maybe_kick_lo(mdev); + return TRUE; +} + +STATIC int receive_DataReply(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + struct drbd_request *req; + sector_t sector; + unsigned int header_size, data_size; + int ok; + struct Drbd_Data_Packet *p = (struct Drbd_Data_Packet *)h; + + header_size = sizeof(*p) - sizeof(*h); + data_size = h->length - header_size; + + /* I expect a block to be a multiple of 512 byte, + * and no more than DRBD_MAX_SEGMENT_SIZE. + * is this too restrictive? */ + ERR_IF(data_size == 0) return FALSE; + + if (drbd_recv(mdev, h->payload, header_size) != header_size) + return FALSE; + + sector = be64_to_cpu(p->sector); + + spin_lock_irq(&mdev->req_lock); + req = _ar_id_to_req(mdev, p->block_id, sector); + spin_unlock_irq(&mdev->req_lock); + if (unlikely(!req)) { + ERR("Got a corrupt block_id/sector pair(1).\n"); + return FALSE; + } + + /* hlist_del(&req->colision) is done in _req_may_be_done, to avoid + * special casing it there for the various failure cases. + * still no race with drbd_fail_pending_reads */ + ok = recv_dless_read(mdev, req, sector, data_size); + + if (ok) + req_mod(req, data_received, 0); + /* else: nothing. handled from drbd_disconnect... + * I don't think we may complete this just yet + * in case we are "on-disconnect: freeze" */ + + return ok; +} + +STATIC int receive_RSDataReply(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + sector_t sector; + unsigned int header_size, data_size; + int ok; + struct Drbd_Data_Packet *p = (struct Drbd_Data_Packet *)h; + + header_size = sizeof(*p) - sizeof(*h); + data_size = h->length - header_size; + + if (drbd_recv(mdev, h->payload, header_size) != header_size) + return FALSE; + + sector = be64_to_cpu(p->sector); + D_ASSERT(p->block_id == ID_SYNCER); + + if (inc_local(mdev)) { + /* data is submitted to disk within recv_resync_read. + * corresponding dec_local done below on error, + * or in drbd_endio_write_sec. */ + /* FIXME paranoia: + * verify that the corresponding bit is set. + * in case we are Primary SyncTarget, + * verify there are no pending write request to that area. + */ + ok = recv_resync_read(mdev, sector, data_size); + } else { + if (DRBD_ratelimit(5*HZ, 5)) + ERR("Can not write resync data to local disk.\n"); + + ok = drbd_drain_block(mdev, data_size); + + drbd_send_ack_dp(mdev, NegAck, p); + } + + return ok; +} + +/* e_end_block() is called via drbd_process_done_ee(). + * this means this function only runs in the asender thread + * + * for a broken example implementation of the TCQ barrier version of + * e_end_block see older revisions... + */ +STATIC int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int unused) +{ + struct Tl_epoch_entry *e = (struct Tl_epoch_entry *)w; + sector_t sector = e->sector; + /* unsigned int epoch_size; */ + int ok = 1, pcmd; + + if (mdev->net_conf->wire_protocol == DRBD_PROT_C) { + if (likely(drbd_bio_uptodate(e->private_bio))) { + pcmd = (mdev->state.conn >= SyncSource && + mdev->state.conn <= PausedSyncT && + e->flags & EE_MAY_SET_IN_SYNC) ? + RSWriteAck : WriteAck; + ok &= drbd_send_ack(mdev, pcmd, e); + if (pcmd == RSWriteAck) + drbd_set_in_sync(mdev, sector, e->size); + } else { + /* FIXME I think we should send a NegAck regardless of + * which protocol is in effect. + * In which case we would need to make sure that any + * NegAck is sent. Basically that means that + * drbd_process_done_ee may not list_del() the ee + * before this callback did run... + * maybe even move the list_del(e) in here... */ + ok = drbd_send_ack(mdev, NegAck, e); + ok &= drbd_io_error(mdev, FALSE); + /* we expect it to be marked out of sync anyways... + * maybe assert this? */ + } + dec_unacked(mdev); + } else if (unlikely(!drbd_bio_uptodate(e->private_bio))) { + ok = drbd_io_error(mdev, FALSE); + } + + /* we delete from the conflict detection hash _after_ we sent out the + * WriteAck / NegAck, to get the sequence number right. */ + if (mdev->net_conf->two_primaries) { + spin_lock_irq(&mdev->req_lock); + D_ASSERT(!hlist_unhashed(&e->colision)); + hlist_del_init(&e->colision); + spin_unlock_irq(&mdev->req_lock); + } else { + D_ASSERT(hlist_unhashed(&e->colision)); + } + + return ok; +} + +STATIC int e_send_discard_ack(struct drbd_conf *mdev, struct drbd_work *w, int unused) +{ + struct Tl_epoch_entry *e = (struct Tl_epoch_entry *)w; + int ok = 1; + + D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C); + ok = drbd_send_ack(mdev, DiscardAck, e); + + spin_lock_irq(&mdev->req_lock); + D_ASSERT(!hlist_unhashed(&e->colision)); + hlist_del_init(&e->colision); + spin_unlock_irq(&mdev->req_lock); + + dec_unacked(mdev); + + return ok; +} + +/* Called from receive_Data. + * Synchronize packets on sock with packets on msock. + * + * This is here so even when a Data packet traveling via sock overtook an Ack + * packet traveling on msock, they are still processed in the order they have + * been sent. + * + * Note: we don't care for Ack packets overtaking Data packets. + * + * In case packet_seq is larger than mdev->peer_seq number, there are + * outstanding packets on the msock. We wait for them to arrive. + * In case we are the logically next packet, we update mdev->peer_seq + * ourselves. Correctly handles 32bit wrap around. + * FIXME verify that atomic_t guarantees 32bit wrap around, + * otherwise we have to play tricks with << ... + * + * Assume we have a 10 GBit connection, that is about 1<<30 byte per second, + * about 1<<21 sectors per second. So "worst" case, we have 1<<3 == 8 seconds + * for the 24bit wrap (historical atomic_t guarantee on some archs), and we have + * 1<<9 == 512 seconds aka ages for the 32bit wrap around... + * + * returns 0 if we may process the packet, + * -ERESTARTSYS if we were interrupted (by disconnect signal). */ +static int drbd_wait_peer_seq(struct drbd_conf *mdev, const u32 packet_seq) +{ + DEFINE_WAIT(wait); + int ret = 0; + spin_lock(&mdev->peer_seq_lock); + for (;;) { + prepare_to_wait(&mdev->seq_wait, &wait, TASK_INTERRUPTIBLE); + if (seq_le(packet_seq, mdev->peer_seq+1)) + break; + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + spin_unlock(&mdev->peer_seq_lock); + schedule(); + spin_lock(&mdev->peer_seq_lock); + } + finish_wait(&mdev->seq_wait, &wait); + if (mdev->peer_seq+1 == packet_seq) + mdev->peer_seq++; + spin_unlock(&mdev->peer_seq_lock); + return ret; +} + +/* mirrored write */ +STATIC int receive_Data(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + sector_t sector; + struct Tl_epoch_entry *e; + struct Drbd_Data_Packet *p = (struct Drbd_Data_Packet *)h; + int header_size, data_size; + int rw = WRITE; + unsigned int barrier_nr = 0; + unsigned int epoch_size = 0; + u32 dp_flags; + + /* FIXME merge this code dups into some helper function */ + header_size = sizeof(*p) - sizeof(*h); + data_size = h->length - header_size; + + ERR_IF(data_size == 0) return FALSE; + + if (drbd_recv(mdev, h->payload, header_size) != header_size) + return FALSE; + + if (!inc_local(mdev)) { + /* data is submitted to disk at the end of this function. + * corresponding dec_local done either below (on error), + * or in drbd_endio_write_sec. */ + if (DRBD_ratelimit(5*HZ, 5)) + ERR("Can not write mirrored data block " + "to local disk.\n"); + spin_lock(&mdev->peer_seq_lock); + if (mdev->peer_seq+1 == be32_to_cpu(p->seq_num)) + mdev->peer_seq++; + spin_unlock(&mdev->peer_seq_lock); + + drbd_send_ack_dp(mdev, NegAck, p); + mdev->epoch_size++; /* spin lock ? */ + return drbd_drain_block(mdev, data_size); + } + + sector = be64_to_cpu(p->sector); + e = read_in_block(mdev, p->block_id, sector, data_size); + if (!e) { + dec_local(mdev); + return FALSE; + } + + e->private_bio->bi_end_io = drbd_endio_write_sec; + e->private_bio->bi_rw = WRITE; + e->w.cb = e_end_block; + + dp_flags = be32_to_cpu(p->dp_flags); + if (dp_flags & DP_HARDBARRIER) + rw |= (1<flags |= EE_MAY_SET_IN_SYNC; + + /* I'm the receiver, I do hold a net_cnt reference. */ + if (!mdev->net_conf->two_primaries) { + spin_lock_irq(&mdev->req_lock); + } else { + /* don't get the req_lock yet, + * we may sleep in drbd_wait_peer_seq */ + const int size = e->size; + const int discard = test_bit(DISCARD_CONCURRENT, &mdev->flags); + DEFINE_WAIT(wait); + struct drbd_request *i; + struct hlist_node *n; + struct hlist_head *slot; + int first; + + D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C); + BUG_ON(mdev->ee_hash == NULL); + BUG_ON(mdev->tl_hash == NULL); + + /* conflict detection and handling: + * 1. wait on the sequence number, + * in case this data packet overtook ACK packets. + * 2. check our hash tables for conflicting requests. + * we only need to walk the tl_hash, since an ee can not + * have a conflict with an other ee: on the submitting + * node, the corresponding req had already been conflicting, + * and a conflicting req is never sent. + * + * Note: for two_primaries, we are protocol C, + * so there cannot be any request that is DONE + * but still on the transfer log. + * + * unconditionally add to the ee_hash. + * + * if no conflicting request is found: + * submit. + * + * if any conflicting request is found + * that has not yet been acked, + * AND I have the "discard concurrent writes" flag: + * queue (via done_ee) the DiscardAck; OUT. + * + * if any conflicting request is found: + * block the receiver, waiting on misc_wait + * until no more conflicting requests are there, + * or we get interrupted (disconnect). + * + * we do not just write after local io completion of those + * requests, but only after req is done completely, i.e. + * we wait for the DiscardAck to arrive! + * + * then proceed normally, i.e. submit. + */ + if (drbd_wait_peer_seq(mdev, be32_to_cpu(p->seq_num))) + goto out_interrupted; + + spin_lock_irq(&mdev->req_lock); + + hlist_add_head(&e->colision, ee_hash_slot(mdev, sector)); + +#define OVERLAPS overlaps(i->sector, i->size, sector, size) + slot = tl_hash_slot(mdev, sector); + first = 1; + for (;;) { + int have_unacked = 0; + int have_conflict = 0; + prepare_to_wait(&mdev->misc_wait, &wait, + TASK_INTERRUPTIBLE); + hlist_for_each_entry(i, n, slot, colision) { + if (OVERLAPS) { + /* only ALERT on first iteration, + * we may be woken up early... */ + if (first) + ALERT("%s[%u] Concurrent local write detected!" + " new: %llus +%u; pending: %llus +%u\n", + current->comm, current->pid, + (unsigned long long)sector, size, + (unsigned long long)i->sector, i->size); + if (i->rq_state & RQ_NET_PENDING) + ++have_unacked; + ++have_conflict; + } + } +#undef OVERLAPS + if (!have_conflict) + break; + + /* Discard Ack only for the _first_ iteration */ + if (first && discard && have_unacked) { + ALERT("Concurrent write! [DISCARD BY FLAG] sec=%llus\n", + (unsigned long long)sector); + inc_unacked(mdev); + mdev->epoch_size++; + e->w.cb = e_send_discard_ack; + list_add_tail(&e->w.list, &mdev->done_ee); + + spin_unlock_irq(&mdev->req_lock); + + /* we could probably send that DiscardAck ourselves, + * but I don't like the receiver using the msock */ + + dec_local(mdev); + wake_asender(mdev); + finish_wait(&mdev->misc_wait, &wait); + return TRUE; + } + + if (signal_pending(current)) { + hlist_del_init(&e->colision); + + spin_unlock_irq(&mdev->req_lock); + + finish_wait(&mdev->misc_wait, &wait); + goto out_interrupted; + } + + spin_unlock_irq(&mdev->req_lock); + if (first) { + first = 0; + ALERT("Concurrent write! [W AFTERWARDS] " + "sec=%llus\n", (unsigned long long)sector); + } else if (discard) { + /* we had none on the first iteration. + * there must be none now. */ + D_ASSERT(have_unacked == 0); + } + schedule(); + spin_lock_irq(&mdev->req_lock); + } + finish_wait(&mdev->misc_wait, &wait); + } + + /* when using TCQ: + * note that, when using tagged command queuing, we may + * have more than one reorder domain "active" at a time. + * + * THINK: + * do we have any guarantees that we get the completion + * events of the different reorder domains in order? + * or does the api only "guarantee" that the events + * _happened_ in order, but eventually the completion + * callbacks are shuffeled again? + * + * note that I wonder about the order in which the + * callbacks are run, I am reasonable confident that the + * actual completion happens in order. + * + * - can it happen that the tagged write completion is + * called even though not all of the writes before it + * have run their completion callback? + * - can it happen that some completion callback of some + * write after the tagged one is run, even though the + * callback of the tagged one itself is still pending? + * + * if this can happen, we either need to drop our "debug + * assertion" about the epoch size and just trust our code + * and the layers below us (nah, won't do that). + * + * or we need to replace the "active_ee" list by some sort + * of "transfer log" on the receiving side, too, which + * uses epoch counters per reorder domain. + */ + + /* when using tcq: + * if we got a barrier packet before, but at that time the active_ee + * was not yet empty, we just "remembered" this barrier request. + * + * if this is the first data packet since that barrier, maybe meanwhile + * all previously active writes have been completed? + * if so, send the b_ack right now + * (though, maybe rather move it into the e_end_block callback, + * where it would be sent as soon as possible). + * + * otherwise, tag the write with the barrier number, so it + * will trigger the b_ack before its own ack. + */ + if (mdev->next_barrier_nr) { + /* only when using TCQ */ + if (list_empty(&mdev->active_ee)) { + barrier_nr = mdev->next_barrier_nr; + epoch_size = mdev->epoch_size; + mdev->epoch_size = 0; + } else { + e->barrier_nr = mdev->next_barrier_nr; + } + rw |= (1<next_barrier_nr = 0; + } + list_add(&e->w.list, &mdev->active_ee); + spin_unlock_irq(&mdev->req_lock); + + if (barrier_nr) { + /* only when using TCQ + * maybe rather move it into the e_end_block callback, + * where it would be sent as soon as possible). + */ + (void)drbd_send_b_ack(mdev, + cpu_to_be32(barrier_nr), epoch_size); + } + + switch (mdev->net_conf->wire_protocol) { + case DRBD_PROT_C: + inc_unacked(mdev); + /* corresponding dec_unacked() in e_end_block() + * respective _drbd_clear_done_ee */ + break; + case DRBD_PROT_B: + /* I really don't like it that the receiver thread + * sends on the msock, but anyways */ + drbd_send_ack(mdev, RecvAck, e); + break; + case DRBD_PROT_A: + /* nothing to do */ + break; + } + + if (mdev->state.pdsk == Diskless) { + /* In case we have the only disk of the cluster, */ + drbd_set_out_of_sync(mdev, e->sector, e->size); + e->flags |= EE_CALL_AL_COMPLETE_IO; + drbd_al_begin_io(mdev, e->sector); + } + + MTRACE(TraceTypeEE, TraceLvlAll, + INFO("submit EE (DATA)WRITE sec=%llus size=%u ee=%p\n", + (unsigned long long)e->sector, e->size, e); + ); + /* FIXME drbd_al_begin_io in case we have two primaries... */ + e->private_bio->bi_rw = rw; + dump_internal_bio("Sec", mdev, e->private_bio, 0); + drbd_generic_make_request(mdev, DRBD_FAULT_DT_WR, e->private_bio); + /* accounting done in endio */ + + maybe_kick_lo(mdev); + return TRUE; + +out_interrupted: + /* yes, the epoch_size now is imbalanced. + * but we drop the connection anyways, so we don't have a chance to + * receive a barrier... atomic_inc(&mdev->epoch_size); */ + dec_local(mdev); + drbd_free_ee(mdev, e); + return FALSE; +} + +STATIC int receive_DataRequest(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + sector_t sector; + const sector_t capacity = drbd_get_capacity(mdev->this_bdev); + struct Tl_epoch_entry *e; + struct digest_info *di; + int size,digest_size; + unsigned int fault_type; + struct Drbd_BlockRequest_Packet *p = + (struct Drbd_BlockRequest_Packet *)h; + const int brps = sizeof(*p)-sizeof(*h); + + if (drbd_recv(mdev, h->payload, brps) != brps) + return FALSE; + + sector = be64_to_cpu(p->sector); + size = be32_to_cpu(p->blksize); + + if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) { + ERR("%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__, + (unsigned long long)sector, size); + return FALSE; + } + if ( sector + (size>>9) > capacity) { + ERR("%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__, + (unsigned long long)sector, size); + return FALSE; + } + + if (!inc_local_if_state(mdev, UpToDate)) { + if (DRBD_ratelimit(5*HZ, 5)) + ERR("Can not satisfy peer's read request, " + "no local data.\n"); + drbd_send_ack_rp(mdev, h->command == DataRequest ? NegDReply : + NegRSDReply , p); + return TRUE; + } + + e = drbd_alloc_ee(mdev, p->block_id, sector, size, GFP_KERNEL); + if (!e) { + dec_local(mdev); + return FALSE; + } + + /* FIXME actually, it could be a READA originating from the peer, + * also it could have set some flags (e.g. BIO_RW_SYNC) ... */ + e->private_bio->bi_rw = READ; + e->private_bio->bi_end_io = drbd_endio_read_sec; + + switch (h->command) { + case DataRequest: + e->w.cb = w_e_end_data_req; + fault_type = DRBD_FAULT_DT_RD; + break; + case RSDataRequest: + e->w.cb = w_e_end_rsdata_req; + fault_type = DRBD_FAULT_RS_RD; + /* Eventually this should become asynchrously. Currently it + * blocks the whole receiver just to delay the reading of a + * resync data block. + * the drbd_work_queue mechanism is made for this... + */ + if (!drbd_rs_begin_io(mdev, sector)) { + /* we have been interrupted, + * probably connection lost! */ + D_ASSERT(signal_pending(current)); + dec_local(mdev); + drbd_free_ee(mdev, e); + return 0; + } + break; + + case OVReply: + fault_type = DRBD_FAULT_RS_RD; + digest_size = h->length - brps ; + di = kmalloc(sizeof(*di) + digest_size ,GFP_KERNEL); + if(!di) { + dec_local(mdev); + drbd_free_ee(mdev,e); + return 0; + } + + di->digest_size = digest_size; + di->digest = (((char *)di)+sizeof(struct digest_info)); + + if (drbd_recv(mdev, di->digest, digest_size) != digest_size) { + dec_local(mdev); + drbd_free_ee(mdev,e); + kfree(di); + return FALSE; + } + + e->block_id = (u64)(unsigned long)di; + e->w.cb = w_e_end_ov_reply; + dec_rs_pending(mdev); + break; + + case OVRequest: + e->w.cb = w_e_end_ov_req; + fault_type = DRBD_FAULT_RS_RD; + /* Eventually this should become asynchrously. Currently it + * blocks the whole receiver just to delay the reading of a + * resync data block. + * the drbd_work_queue mechanism is made for this... + */ + if (!drbd_rs_begin_io(mdev,sector)) { + /* we have been interrupted, + * probably connection lost! */ + D_ASSERT(signal_pending(current)); + dec_local(mdev); + drbd_free_ee(mdev,e); + return 0; + } + break; + + + default:; /* avoid compiler warning */ + ERR("unexpected command (%s) in receive_DataRequest\n", + cmdname(h->command)); + fault_type = DRBD_FAULT_MAX; + } + + spin_lock_irq(&mdev->req_lock); + list_add(&e->w.list, &mdev->read_ee); + spin_unlock_irq(&mdev->req_lock); + + inc_unacked(mdev); + + MTRACE(TraceTypeEE, TraceLvlAll, + INFO("submit EE READ sec=%llus size=%u ee=%p\n", + (unsigned long long)e->sector, e->size, e); + ); + + dump_internal_bio("Sec", mdev, e->private_bio, 0); + drbd_generic_make_request(mdev, fault_type, e->private_bio); + maybe_kick_lo(mdev); + + return TRUE; +} + +STATIC int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local) +{ + int self, peer, rv = -100; + unsigned long ch_self, ch_peer; + + self = mdev->bc->md.uuid[Bitmap] & 1; + peer = mdev->p_uuid[Bitmap] & 1; + + ch_peer = mdev->p_uuid[UUID_SIZE]; + ch_self = mdev->comm_bm_set; + + switch ( mdev->net_conf->after_sb_0p ) { + case Consensus: + case DiscardSecondary: + case CallHelper: + ERR("Configuration error.\n"); + break; + case Disconnect: + break; + case DiscardYoungerPri: + if (self == 0 && peer == 1) { rv = -1; break; } + if (self == 1 && peer == 0) { rv = 1; break; } + /* Else fall through to one of the other strategies... */ + case DiscardOlderPri: + if (self == 0 && peer == 1) { rv = 1; break; } + if (self == 1 && peer == 0) { rv = -1; break; } + /* Else fall through to one of the other strategies... */ + DRBD_WARN("Discard younger/older primary did not found a decision\n" + "Using discard-least-changes instead\n"); + case DiscardZeroChg: + if (ch_peer == 0 && ch_self == 0) { + rv = test_bit(DISCARD_CONCURRENT, &mdev->flags) + ? -1 : 1; + break; + } else { + if (ch_peer == 0) { rv = 1; break; } + if (ch_self == 0) { rv = -1; break; } + } + if (mdev->net_conf->after_sb_0p == DiscardZeroChg) + break; + case DiscardLeastChg: + if ( ch_self < ch_peer ) + rv = -1; + else if (ch_self > ch_peer) + rv = 1; + else /* ( ch_self == ch_peer ) */ + /* Well, then use something else. */ + rv = test_bit(DISCARD_CONCURRENT, &mdev->flags) + ? -1 : 1; + break; + case DiscardLocal: + rv = -1; + break; + case DiscardRemote: + rv = 1; + } + + return rv; +} + +STATIC int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local) +{ + int self, peer, hg, rv = -100; + + self = mdev->bc->md.uuid[Bitmap] & 1; + peer = mdev->p_uuid[Bitmap] & 1; + + switch ( mdev->net_conf->after_sb_1p ) { + case DiscardYoungerPri: + case DiscardOlderPri: + case DiscardLeastChg: + case DiscardLocal: + case DiscardRemote: + ERR("Configuration error.\n"); + break; + case Disconnect: + break; + case Consensus: + hg = drbd_asb_recover_0p(mdev); + if (hg == -1 && mdev->state.role == Secondary) + rv = hg; + if (hg == 1 && mdev->state.role == Primary) + rv = hg; + break; + case Violently: + rv = drbd_asb_recover_0p(mdev); + break; + case DiscardSecondary: + return mdev->state.role == Primary ? 1 : -1; + case CallHelper: + hg = drbd_asb_recover_0p(mdev); + if (hg == -1 && mdev->state.role == Primary) { + self = drbd_set_role(mdev, Secondary, 0); + if (self != SS_Success) { + drbd_khelper(mdev, "pri-lost-after-sb"); + } else { + DRBD_WARN("Sucessfully gave up primary role.\n"); + rv = hg; + } + } else + rv = hg; + } + + return rv; +} + +STATIC int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local) +{ + int self, peer, hg, rv = -100; + + self = mdev->bc->md.uuid[Bitmap] & 1; + peer = mdev->p_uuid[Bitmap] & 1; + + switch ( mdev->net_conf->after_sb_2p ) { + case DiscardYoungerPri: + case DiscardOlderPri: + case DiscardLeastChg: + case DiscardLocal: + case DiscardRemote: + case Consensus: + case DiscardSecondary: + ERR("Configuration error.\n"); + break; + case Violently: + rv = drbd_asb_recover_0p(mdev); + break; + case Disconnect: + break; + case CallHelper: + hg = drbd_asb_recover_0p(mdev); + if (hg == -1) { + self = drbd_set_role(mdev, Secondary, 0); + if (self != SS_Success) { + drbd_khelper(mdev, "pri-lost-after-sb"); + } else { + DRBD_WARN("Sucessfully gave up primary role.\n"); + rv = hg; + } + } else + rv = hg; + } + + return rv; +} + +STATIC void drbd_uuid_dump(struct drbd_conf *mdev, char *text, u64 *uuid) +{ + INFO("%s %016llX:%016llX:%016llX:%016llX\n", + text, + uuid[Current], + uuid[Bitmap], + uuid[History_start], + uuid[History_end]); +} + +/* + 100 after split brain try auto recover + 2 SyncSource set BitMap + 1 SyncSource use BitMap + 0 no Sync + -1 SyncTarget use BitMap + -2 SyncTarget set BitMap + -100 after split brain, disconnect +-1000 unrelated data + */ +STATIC int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(local) +{ + u64 self, peer; + int i, j; + + self = mdev->bc->md.uuid[Current] & ~((u64)1); + peer = mdev->p_uuid[Current] & ~((u64)1); + + *rule_nr = 1; + if (self == UUID_JUST_CREATED && + peer == UUID_JUST_CREATED) return 0; + + *rule_nr = 2; + if ( (self == UUID_JUST_CREATED || self == (u64)0) && + peer != UUID_JUST_CREATED) return -2; + + *rule_nr = 3; + if ( self != UUID_JUST_CREATED && + (peer == UUID_JUST_CREATED || peer == (u64)0) ) return 2; + + *rule_nr = 4; + if (self == peer) { /* Common power [off|failure] */ + int rct, dc; /* roles at crash time */ + + rct = (test_bit(CRASHED_PRIMARY, &mdev->flags) ? 1 : 0) + + ( mdev->p_uuid[UUID_FLAGS] & 2 ); + /* lowest bit is set when we were primary, + * next bit (weight 2) is set when peer was primary */ + + MTRACE(TraceTypeUuid, TraceLvlMetrics, DUMPI(rct); ); + + switch (rct) { + case 0: /* !self_pri && !peer_pri */ return 0; + case 1: /* self_pri && !peer_pri */ return 1; + case 2: /* !self_pri && peer_pri */ return -1; + case 3: /* self_pri && peer_pri */ + dc = test_bit(DISCARD_CONCURRENT, &mdev->flags); + MTRACE(TraceTypeUuid, TraceLvlMetrics, DUMPI(dc); ); + return dc ? -1 : 1; + } + } + + *rule_nr = 5; + peer = mdev->p_uuid[Bitmap] & ~((u64)1); + if (self == peer) + return -1; + + *rule_nr = 6; + for ( i = History_start ; i <= History_end ; i++ ) { + peer = mdev->p_uuid[i] & ~((u64)1); + if (self == peer) + return -2; + } + + *rule_nr = 7; + self = mdev->bc->md.uuid[Bitmap] & ~((u64)1); + peer = mdev->p_uuid[Current] & ~((u64)1); + if (self == peer) + return 1; + + *rule_nr = 8; + for ( i = History_start ; i <= History_end ; i++ ) { + self = mdev->bc->md.uuid[i] & ~((u64)1); + if (self == peer) + return 2; + } + + *rule_nr = 9; + self = mdev->bc->md.uuid[Bitmap] & ~((u64)1); + peer = mdev->p_uuid[Bitmap] & ~((u64)1); + if (self == peer && self != ((u64)0) ) return 100; + + *rule_nr = 10; + for ( i = History_start ; i <= History_end ; i++ ) { + self = mdev->p_uuid[i] & ~((u64)1); + for ( j = History_start ; j <= History_end ; j++ ) { + peer = mdev->p_uuid[j] & ~((u64)1); + if (self == peer) + return -100; + } + } + + return -1000; +} + +/* drbd_sync_handshake() returns the new conn state on success, or + conn_mask (-1) on failure. + */ +STATIC enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_role peer_role, + enum drbd_disk_state peer_disk) __must_hold(local) +{ + int hg, rule_nr; + enum drbd_conns rv = conn_mask; + enum drbd_disk_state mydisk; + + mydisk = mdev->state.disk; + if (mydisk == Negotiating) + mydisk = mdev->new_state_tmp.disk; + + hg = drbd_uuid_compare(mdev, &rule_nr); + + MTRACE(TraceTypeUuid, TraceLvlSummary, + INFO("drbd_sync_handshake:\n"); + drbd_uuid_dump(mdev, "self", mdev->bc->md.uuid); + drbd_uuid_dump(mdev, "peer", mdev->p_uuid); + INFO("uuid_compare()=%d by rule %d\n", hg, rule_nr); + ); + + if (hg == -1000) { + ALERT("Unrelated data, aborting!\n"); + return conn_mask; + } + + if ( (mydisk == Inconsistent && peer_disk > Inconsistent) || + (peer_disk == Inconsistent && mydisk > Inconsistent) ) { + int f = (hg == -100) || abs(hg) == 2; + hg = mydisk > Inconsistent ? 1 : -1; + if (f) + hg = hg*2; + INFO("Becoming sync %s due to disk states.\n", + hg > 0 ? "source" : "target"); + } + + if (hg == 100 || (hg == -100 && mdev->net_conf->always_asbp) ) { + int pcount = (mdev->state.role == Primary) + + (peer_role == Primary); + int forced = (hg == -100); + + switch (pcount) { + case 0: + hg = drbd_asb_recover_0p(mdev); + break; + case 1: + hg = drbd_asb_recover_1p(mdev); + break; + case 2: + hg = drbd_asb_recover_2p(mdev); + break; + } + if ( abs(hg) < 100 ) { + DRBD_WARN("Split-Brain detected, %d primaries, " + "automatically solved. Sync from %s node\n", + pcount, (hg < 0) ? "peer":"this"); + if (forced) { + DRBD_WARN("Doing a full sync, since" + " UUIDs where ambiguous.\n"); + drbd_uuid_dump(mdev, "self", mdev->bc->md.uuid); + drbd_uuid_dump(mdev, "peer", mdev->p_uuid); + hg = hg*2; + } + } + } + + if (hg == -100) { + if (mdev->net_conf->want_lose && !(mdev->p_uuid[UUID_FLAGS]&1)) + hg = -1; + if (!mdev->net_conf->want_lose && (mdev->p_uuid[UUID_FLAGS]&1)) + hg = 1; + + if ( abs(hg) < 100 ) + DRBD_WARN("Split-Brain detected, manually solved. " + "Sync from %s node\n", + (hg < 0) ? "peer":"this"); + } + + if (hg == -100) { + ALERT("Split-Brain detected, dropping connection!\n"); + drbd_uuid_dump(mdev, "self", mdev->bc->md.uuid); + drbd_uuid_dump(mdev, "peer", mdev->p_uuid); + drbd_khelper(mdev, "split-brain"); + return conn_mask; + } + + if (hg > 0 && mydisk <= Inconsistent) { + ERR("I shall become SyncSource, but I am inconsistent!\n"); + return conn_mask; + } + + if (hg < 0 && /* by intention we do not use mydisk here. */ + mdev->state.role == Primary && mdev->state.disk >= Consistent ) { + switch (mdev->net_conf->rr_conflict) { + case CallHelper: + drbd_khelper(mdev, "pri-lost"); + /* fall through */ + case Disconnect: + ERR("I shall become SyncTarget, but I am primary!\n"); + return conn_mask; + case Violently: + DRBD_WARN("Becoming SyncTarget, violating the stable-data" + "assumption\n"); + } + } + + if (abs(hg) >= 2) { + INFO("Writing the whole bitmap, full sync required after drbd_sync_handshake.\n"); + if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write)) + return conn_mask; + } + + if (hg > 0) { /* become sync source. */ + rv = WFBitMapS; + } else if (hg < 0) { /* become sync target */ + rv = WFBitMapT; + } else { + rv = Connected; + if (drbd_bm_total_weight(mdev)) { + INFO("No resync, but %lu bits in bitmap!\n", + drbd_bm_total_weight(mdev)); + } + } + + drbd_bm_recount_bits(mdev); + + return rv; +} + +/* returns 1 if invalid */ +STATIC int cmp_after_sb(enum after_sb_handler peer, enum after_sb_handler self) +{ + /* DiscardRemote - DiscardLocal is valid */ + if ( (peer == DiscardRemote && self == DiscardLocal) || + (self == DiscardRemote && peer == DiscardLocal) ) return 0; + + /* any other things with DiscardRemote or DiscardLocal are invalid */ + if ( peer == DiscardRemote || peer == DiscardLocal || + self == DiscardRemote || self == DiscardLocal ) return 1; + + /* everything else is valid if they are equal on both sides. */ + if (peer == self) + return 0; + + /* everything es is invalid. */ + return 1; +} + +STATIC int receive_protocol(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + struct Drbd_Protocol_Packet *p = (struct Drbd_Protocol_Packet *)h; + int header_size, data_size; + int p_proto, p_after_sb_0p, p_after_sb_1p, p_after_sb_2p; + int p_want_lose, p_two_primaries; + char p_integrity_alg[SHARED_SECRET_MAX]; + + header_size = sizeof(*p) - sizeof(*h); + data_size = h->length - header_size; + + if (drbd_recv(mdev, h->payload, header_size) != header_size) + return FALSE; + + p_proto = be32_to_cpu(p->protocol); + p_after_sb_0p = be32_to_cpu(p->after_sb_0p); + p_after_sb_1p = be32_to_cpu(p->after_sb_1p); + p_after_sb_2p = be32_to_cpu(p->after_sb_2p); + p_want_lose = be32_to_cpu(p->want_lose); + p_two_primaries = be32_to_cpu(p->two_primaries); + + if (p_proto != mdev->net_conf->wire_protocol) { + ERR("incompatible communication protocols\n"); + goto disconnect; + } + + if ( cmp_after_sb(p_after_sb_0p, mdev->net_conf->after_sb_0p) ) { + ERR("incompatible after-sb-0pri settings\n"); + goto disconnect; + } + + if ( cmp_after_sb(p_after_sb_1p, mdev->net_conf->after_sb_1p) ) { + ERR("incompatible after-sb-1pri settings\n"); + goto disconnect; + } + + if ( cmp_after_sb(p_after_sb_2p, mdev->net_conf->after_sb_2p) ) { + ERR("incompatible after-sb-2pri settings\n"); + goto disconnect; + } + + if (p_want_lose && mdev->net_conf->want_lose) { + ERR("both sides have the 'want_lose' flag set\n"); + goto disconnect; + } + + if (p_two_primaries != mdev->net_conf->two_primaries) { + ERR("incompatible setting of the two-primaries options\n"); + goto disconnect; + } + + if (mdev->agreed_pro_version >= 87) { + unsigned char *my_alg = mdev->net_conf->integrity_alg; + + if (drbd_recv(mdev, p_integrity_alg, data_size) != data_size) + return FALSE; + + p_integrity_alg[SHARED_SECRET_MAX-1] = 0; + if (strcmp(p_integrity_alg, my_alg)) { + ERR("incompatible setting of the data-integrity-alg\n"); + goto disconnect; + } + INFO("data-integrity-alg: %s\n", + my_alg[0] ? my_alg : (unsigned char *)""); + } + + return TRUE; + +disconnect: + drbd_force_state(mdev, NS(conn, Disconnecting)); + return FALSE; +} + +STATIC int receive_SyncParam(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + int ok = TRUE; + struct Drbd_SyncParam_Packet *p = (struct Drbd_SyncParam_Packet *)h; + int header_size, data_size; + char p_verify_alg[SHARED_SECRET_MAX]; + struct crypto_hash *verify_tfm = NULL, *old_verify_tfm; + + header_size = sizeof(*p) - sizeof(*h); + data_size = h->length - header_size; + + if (drbd_recv(mdev, h->payload, header_size) != header_size) + return FALSE; + + mdev->sync_conf.rate = be32_to_cpu(p->rate); + + if (mdev->agreed_pro_version >= 88) { + + if (drbd_recv(mdev, p_verify_alg, data_size) != data_size) + return FALSE; + + p_verify_alg[SHARED_SECRET_MAX-1] = 0; + if (strcpy(mdev->sync_conf.verify_alg, p_verify_alg)) { + if (strlen(p_verify_alg)) { + verify_tfm = crypto_alloc_hash(p_verify_alg, 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(verify_tfm)) { + ERR("Can not allocate \"%s\" as verify-alg\n", + p_verify_alg); + return FALSE; + } + + if (crypto_tfm_alg_type(crypto_hash_tfm(verify_tfm)) != + CRYPTO_ALG_TYPE_DIGEST) { + crypto_free_hash(verify_tfm); + ERR("\"%s\" is not a digest (verify-alg)\n", + p_verify_alg); + return FALSE; + } + } + + spin_lock(&mdev->peer_seq_lock); + /* lock against drbd_nl_syncer_conf() */ + strcpy(mdev->sync_conf.verify_alg, p_verify_alg); + mdev->sync_conf.verify_alg_len = strlen(p_verify_alg) + 1; + old_verify_tfm = mdev->verify_tfm; + mdev->verify_tfm = verify_tfm; + spin_unlock(&mdev->peer_seq_lock); + + crypto_free_hash(old_verify_tfm); + } + } + + return ok; +} + +STATIC void drbd_setup_order_type(struct drbd_conf *mdev, int peer) +{ + /* sorry, we currently have no working implementation + * of distributed TCQ */ +} + +/* warn if the arguments differ by more than 12.5% */ +static void warn_if_differ_considerably(struct drbd_conf *mdev, + const char *s, sector_t a, sector_t b) +{ + sector_t d; + if (a == 0 || b == 0) + return; + d = (a > b) ? (a - b) : (b - a); + if ( d > (a>>3) || d > (b>>3)) + DRBD_WARN("Considerable difference in %s: %llus vs. %llus\n", s, + (unsigned long long)a, (unsigned long long)b); +} + +STATIC int receive_sizes(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + struct Drbd_Sizes_Packet *p = (struct Drbd_Sizes_Packet *)h; + enum determin_dev_size_enum dd = unchanged; + unsigned int max_seg_s; + sector_t p_size, p_usize, my_usize; + int ldsc = 0; /* local disk size changed */ + enum drbd_conns nconn; + + ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE; + if (drbd_recv(mdev, h->payload, h->length) != h->length) + return FALSE; + + p_size = be64_to_cpu(p->d_size); + p_usize = be64_to_cpu(p->u_size); + + if (p_size == 0 && mdev->state.disk == Diskless) { + ERR("some backing storage is needed\n"); + drbd_force_state(mdev, NS(conn, Disconnecting)); + return FALSE; + } + + /* just store the peer's disk size for now. + * we still need to figure out wether we accept that. */ + mdev->p_size = p_size; + +#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r)) + if (inc_local(mdev)) { + warn_if_differ_considerably(mdev, "lower level device sizes", + p_size, drbd_get_capacity(mdev->bc->backing_bdev)); + warn_if_differ_considerably(mdev, "user requested size", + p_usize, mdev->bc->dc.disk_size); + + /* if this is the first connect, or an otherwise expected + * param exchange, choose the minimum */ + if (mdev->state.conn == WFReportParams) + p_usize = min_not_zero((sector_t)mdev->bc->dc.disk_size, + p_usize); + + my_usize = mdev->bc->dc.disk_size; + + if (mdev->bc->dc.disk_size != p_usize) { + mdev->bc->dc.disk_size = p_usize; + INFO("Peer sets u_size to %lu sectors\n", + (unsigned long)mdev->bc->dc.disk_size); + } + + /* Never shrink a device with usable data during connect. + But allow online shrinking if we are connected. */ + if (drbd_new_dev_size(mdev, mdev->bc) < + drbd_get_capacity(mdev->this_bdev) && + mdev->state.disk >= Outdated && + mdev->state.conn < Connected ) { + ERR("The peer's disk size is too small!\n"); + drbd_force_state(mdev, NS(conn, Disconnecting)); + mdev->bc->dc.disk_size = my_usize; + dec_local(mdev); + return FALSE; + } + dec_local(mdev); + } +#undef min_not_zero + + if (inc_local(mdev)) { + dd = drbd_determin_dev_size(mdev); + dec_local(mdev); + if (dd == dev_size_error) return FALSE; + drbd_md_sync(mdev); + } else { + /* I am diskless, need to accept the peer's size. */ + drbd_set_my_capacity(mdev, p_size); + } + + if (mdev->p_uuid && mdev->state.conn <= Connected && inc_local(mdev)) { + nconn = drbd_sync_handshake(mdev, + mdev->state.peer, mdev->state.pdsk); + dec_local(mdev); + + if (nconn == conn_mask) { + drbd_force_state(mdev, NS(conn, Disconnecting)); + return FALSE; + } + + if (drbd_request_state(mdev, NS(conn, nconn)) < SS_Success) { + drbd_force_state(mdev, NS(conn, Disconnecting)); + return FALSE; + } + } + + if (inc_local(mdev)) { + if (mdev->bc->known_size != drbd_get_capacity(mdev->bc->backing_bdev)) { + mdev->bc->known_size = drbd_get_capacity(mdev->bc->backing_bdev); + ldsc = 1; + } + + max_seg_s = be32_to_cpu(p->max_segment_size); + if (max_seg_s != mdev->rq_queue->max_segment_size) + drbd_setup_queue_param(mdev, max_seg_s); + + drbd_setup_order_type(mdev, be32_to_cpu(p->queue_order_type)); + dec_local(mdev); + } + + if (mdev->state.conn > WFReportParams) { + if ( be64_to_cpu(p->c_size) != + drbd_get_capacity(mdev->this_bdev) || ldsc ) { + /* we have different sizes, probabely peer + * needs to know my new size... */ + drbd_send_sizes(mdev); + } + if (dd == grew && mdev->state.conn == Connected && + mdev->state.pdsk >= Inconsistent && + mdev->state.disk >= Inconsistent) { + /* With disk >= Inconsistent we take care to not get + here during an attach while we are connected. */ + resync_after_online_grow(mdev); + } + } + + return TRUE; +} + +STATIC int receive_uuids(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + struct Drbd_GenCnt_Packet *p = (struct Drbd_GenCnt_Packet *)h; + u64 *p_uuid; + int i; + + ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE; + if (drbd_recv(mdev, h->payload, h->length) != h->length) + return FALSE; + + p_uuid = kmalloc(sizeof(u64)*EXT_UUID_SIZE, GFP_KERNEL); + + for (i = Current; i < EXT_UUID_SIZE; i++) + p_uuid[i] = be64_to_cpu(p->uuid[i]); + + kfree(mdev->p_uuid); + mdev->p_uuid = p_uuid; + + if (mdev->state.conn < Connected && + mdev->state.disk < Outdated && + mdev->state.role == Primary && + (mdev->ed_uuid & ~((u64)1)) != (p_uuid[Current] & ~((u64)1))) { + ERR("Can only connect to data with current UUID=%016llX\n", + (unsigned long long)mdev->ed_uuid); + drbd_force_state(mdev,NS(conn,Disconnecting)); + return FALSE; + } + + if (mdev->state.conn >= Connected && mdev->state.disk < Inconsistent) + drbd_set_ed_uuid(mdev, p_uuid[Current]); + + return TRUE; +} + +/** + * convert_state: + * Switches the view of the state. + */ +STATIC union drbd_state_t convert_state(union drbd_state_t ps) +{ + union drbd_state_t ms; + + static enum drbd_conns c_tab[] = { + [Connected] = Connected, + + [StartingSyncS] = StartingSyncT, + [StartingSyncT] = StartingSyncS, + [Disconnecting] = TearDown, /* NetworkFailure, */ + [VerifyS] = VerifyT, + [conn_mask] = conn_mask, + }; + + ms.i = ps.i; + + ms.conn = c_tab[ps.conn]; + ms.peer = ps.role; + ms.role = ps.peer; + ms.pdsk = ps.disk; + ms.disk = ps.pdsk; + ms.peer_isp = ( ps.aftr_isp | ps.user_isp ); + + return ms; +} + +STATIC int receive_req_state(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + struct Drbd_Req_State_Packet *p = (struct Drbd_Req_State_Packet *)h; + union drbd_state_t mask, val; + int rv; + + ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE; + if (drbd_recv(mdev, h->payload, h->length) != h->length) + return FALSE; + + mask.i = be32_to_cpu(p->mask); + val.i = be32_to_cpu(p->val); + + if (test_bit(DISCARD_CONCURRENT, &mdev->flags) && + test_bit(CLUSTER_ST_CHANGE, &mdev->flags)) { + drbd_send_sr_reply(mdev, SS_ConcurrentStChg); + return TRUE; + } + + mask = convert_state(mask); + val = convert_state(val); + + rv = drbd_change_state(mdev, ChgStateVerbose, mask, val); + + drbd_send_sr_reply(mdev,rv); + drbd_md_sync(mdev); + + return TRUE; +} + +STATIC int receive_state(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + struct Drbd_State_Packet *p = (struct Drbd_State_Packet *)h; + enum drbd_conns nconn, oconn; + union drbd_state_t ns, peer_state; + enum drbd_disk_state real_peer_disk; + int rv; + + ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) + return FALSE; + + if (drbd_recv(mdev, h->payload, h->length) != h->length) + return FALSE; + + peer_state.i = be32_to_cpu(p->state); + + real_peer_disk = peer_state.disk; + if (peer_state.disk == Negotiating) { + real_peer_disk = mdev->p_uuid[UUID_FLAGS] & 4 ? Inconsistent : Consistent; + INFO("real peer disk state = %s\n", disks_to_name(real_peer_disk)); + } + + spin_lock_irq(&mdev->req_lock); + retry: + oconn = nconn = mdev->state.conn; + spin_unlock_irq(&mdev->req_lock); + + if (nconn == WFReportParams) + nconn = Connected; + + if (mdev->p_uuid && peer_state.disk >= Negotiating && + inc_local_if_state(mdev, Negotiating) ) { + int cr; /* consider resync */ + + cr = (oconn < Connected); + cr |= (oconn == Connected && + (peer_state.disk == Negotiating || + mdev->state.disk == Negotiating)); + cr |= test_bit(CONSIDER_RESYNC, &mdev->flags); /* peer forced */ + cr |= (oconn == Connected && peer_state.conn > Connected); + + if (cr) nconn=drbd_sync_handshake(mdev, peer_state.role, real_peer_disk); + + dec_local(mdev); + if (nconn == conn_mask) { + if (mdev->state.disk == Negotiating) { + drbd_force_state(mdev, NS(disk, Diskless)); + nconn = Connected; + } else if (peer_state.disk == Negotiating) { + ERR("Disk attach process on the peer node was aborted.\n"); + peer_state.disk = Diskless; + } else { + D_ASSERT(oconn == WFReportParams); + drbd_force_state(mdev, NS(conn, Disconnecting)); + return FALSE; + } + } + } + + spin_lock_irq(&mdev->req_lock); + if (mdev->state.conn != oconn) + goto retry; + clear_bit(CONSIDER_RESYNC, &mdev->flags); + ns.i = mdev->state.i; + ns.conn = nconn; + ns.peer = peer_state.role; + ns.pdsk = real_peer_disk; + ns.peer_isp = ( peer_state.aftr_isp | peer_state.user_isp ); + if ((nconn == Connected || nconn == WFBitMapS) && ns.disk == Negotiating) + ns.disk = mdev->new_state_tmp.disk; + rv = _drbd_set_state(mdev, ns, ChgStateVerbose | ChgStateHard, NULL); + ns = mdev->state; + spin_unlock_irq(&mdev->req_lock); + + if (rv < SS_Success) { + drbd_force_state(mdev, NS(conn, Disconnecting)); + return FALSE; + } + + if (oconn > WFReportParams ) { + if (nconn > Connected && peer_state.conn <= Connected) { + // we want resync, peer has not yet decided to sync... + drbd_send_uuids(mdev); + drbd_send_state(mdev); + } + else if (nconn == Connected && peer_state.disk == Negotiating) { + // peer is waiting for us to respond... + drbd_send_state(mdev); + } + } + + mdev->net_conf->want_lose = 0; + + /* FIXME assertion for (gencounts do not diverge) */ + drbd_md_sync(mdev); /* update connected indicator, la_size, ... */ + + return TRUE; +} + +STATIC int receive_sync_uuid(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + struct Drbd_SyncUUID_Packet *p = (struct Drbd_SyncUUID_Packet *)h; + + wait_event( mdev->misc_wait, + mdev->state.conn < Connected || + mdev->state.conn == WFSyncUUID); + + /* D_ASSERT( mdev->state.conn == WFSyncUUID ); */ + + ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE; + if (drbd_recv(mdev, h->payload, h->length) != h->length) + return FALSE; + + /* Here the _drbd_uuid_ functions are right, current should + _not_ be rotated into the history */ + if (inc_local_if_state(mdev, Negotiating)) { + _drbd_uuid_set(mdev, Current,be64_to_cpu(p->uuid)); + _drbd_uuid_set(mdev, Bitmap, 0UL); + + drbd_start_resync(mdev, SyncTarget); + + dec_local(mdev); + } else + ERR("Ignoring SyncUUID packet!\n"); + + return TRUE; +} + +/* Since we are processing the bitfild from lower addresses to higher, + it does not matter if the process it in 32 bit chunks or 64 bit + chunks as long as it is little endian. (Understand it as byte stream, + beginning with the lowest byte...) If we would use big endian + we would need to process it from the highest address to the lowest, + in order to be agnostic to the 32 vs 64 bits issue. + + returns 0 on failure, 1 if we suceessfully received it. */ +STATIC int receive_bitmap(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + size_t bm_words, bm_i, want, num_words; + unsigned long *buffer; + int ok = FALSE; + + wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt)); + + drbd_bm_lock(mdev); + + bm_words = drbd_bm_words(mdev); + bm_i = 0; + buffer = vmalloc(BM_PACKET_WORDS*sizeof(long)); + + while (1) { + num_words = min_t(size_t, BM_PACKET_WORDS, bm_words-bm_i ); + want = num_words * sizeof(long); + ERR_IF(want != h->length) goto out; + if (want == 0) + break; + if (drbd_recv(mdev, buffer, want) != want) + goto out; + + drbd_bm_merge_lel(mdev, bm_i, num_words, buffer); + bm_i += num_words; + + if (!drbd_recv_header(mdev, h)) + goto out; + D_ASSERT(h->command == ReportBitMap); + } + + if (mdev->state.conn == WFBitMapS) { + drbd_start_resync(mdev, SyncSource); + } else if (mdev->state.conn == WFBitMapT) { + ok = !drbd_send_bitmap(mdev); + if (!ok) goto out; + ok = drbd_request_state(mdev, NS(conn, WFSyncUUID)); + D_ASSERT( ok == SS_Success ); + } else { + ERR("unexpected cstate (%s) in receive_bitmap\n", + conns_to_name(mdev->state.conn)); + } + + ok = TRUE; + out: + drbd_bm_unlock(mdev); + vfree(buffer); + return ok; +} + +STATIC int receive_skip(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + /* TODO zero copy sink :) */ + static char sink[128]; + int size, want, r; + + DRBD_WARN("skipping unknown optional packet type %d, l: %d!\n", + h->command, h->length ); + + size = h->length; + while (size > 0) { + want = min_t(int, size, sizeof(sink)); + r = drbd_recv(mdev, sink, want); + ERR_IF(r < 0) break; + size -= r; + } + return (size == 0); +} + +STATIC int receive_UnplugRemote(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + if (mdev->state.disk >= Inconsistent) + drbd_kick_lo(mdev); + return TRUE; /* cannot fail. */ +} + +typedef int (*drbd_cmd_handler_f)(struct drbd_conf *, struct Drbd_Header *); + +static drbd_cmd_handler_f drbd_default_handler[] = { + [Data] = receive_Data, + [DataReply] = receive_DataReply, + [RSDataReply] = receive_RSDataReply, + [Barrier] = receive_Barrier_no_tcq, + [ReportBitMap] = receive_bitmap, + [UnplugRemote] = receive_UnplugRemote, + [DataRequest] = receive_DataRequest, + [RSDataRequest] = receive_DataRequest, + [SyncParam] = receive_SyncParam, + [ReportProtocol] = receive_protocol, + [ReportUUIDs] = receive_uuids, + [ReportSizes] = receive_sizes, + [ReportState] = receive_state, + [StateChgRequest] = receive_req_state, + [ReportSyncUUID] = receive_sync_uuid, + [OVRequest] = receive_DataRequest, + [OVReply] = receive_DataRequest, + /* anything missing from this table is in + * the asender_tbl, see get_asender_cmd */ + [MAX_CMD] = NULL, +}; + +static drbd_cmd_handler_f *drbd_cmd_handler = drbd_default_handler; +static drbd_cmd_handler_f *drbd_opt_cmd_handler; + +STATIC void drbdd(struct drbd_conf *mdev) +{ + drbd_cmd_handler_f handler; + struct Drbd_Header *header = &mdev->data.rbuf.head; + + while (get_t_state(&mdev->receiver) == Running) { + if (!drbd_recv_header(mdev, header)) + break; + + if (header->command < MAX_CMD) + handler = drbd_cmd_handler[header->command]; + else if (MayIgnore < header->command + && header->command < MAX_OPT_CMD) + handler = drbd_opt_cmd_handler[header->command-MayIgnore]; + else if (header->command > MAX_OPT_CMD) + handler = receive_skip; + else + handler = NULL; + + if (unlikely(!handler)) { + ERR("unknown packet type %d, l: %d!\n", + header->command, header->length); + drbd_force_state(mdev, NS(conn, ProtocolError)); + break; + } + if (unlikely(!handler(mdev, header))) { + ERR("error receiving %s, l: %d!\n", + cmdname(header->command), header->length); + drbd_force_state(mdev, NS(conn, ProtocolError)); + break; + } + + dump_packet(mdev, mdev->data.socket, 2, &mdev->data.rbuf, + __FILE__, __LINE__); + } +} + +/* FIXME how should freeze-io be handled? */ +STATIC void drbd_fail_pending_reads(struct drbd_conf *mdev) +{ + struct hlist_head *slot; + struct hlist_node *n; + struct drbd_request *req; + struct list_head *le; + LIST_HEAD(workset); + int i; + + /* + * Application READ requests + */ + spin_lock_irq(&mdev->req_lock); + for (i = 0; i < APP_R_HSIZE; i++) { + slot = mdev->app_reads_hash+i; + hlist_for_each_entry(req, n, slot, colision) { + list_add(&req->w.list, &workset); + } + } + memset(mdev->app_reads_hash, 0, APP_R_HSIZE*sizeof(void *)); + + while (!list_empty(&workset)) { + le = workset.next; + req = list_entry(le, struct drbd_request, w.list); + list_del(le); + + _req_mod(req, connection_lost_while_pending, 0); + } + spin_unlock_irq(&mdev->req_lock); +} + +STATIC void drbd_disconnect(struct drbd_conf *mdev) +{ + struct drbd_work prev_work_done; + enum fencing_policy fp; + union drbd_state_t os, ns; + int rv = SS_UnknownError; + + D_ASSERT(mdev->state.conn < Connected); + if (mdev->state.conn == StandAlone) return; + /* FIXME verify that: + * the state change magic prevents us from becoming >= Connected again + * while we are still cleaning up. + */ + + /* asender does not clean up anything. it must not interfere, either */ + drbd_thread_stop(&mdev->asender); + + down(&mdev->data.mutex); + drbd_free_sock(mdev); + up(&mdev->data.mutex); + + spin_lock_irq(&mdev->req_lock); + _drbd_wait_ee_list_empty(mdev, &mdev->active_ee); + _drbd_wait_ee_list_empty(mdev, &mdev->sync_ee); + _drbd_clear_done_ee(mdev); + _drbd_wait_ee_list_empty(mdev, &mdev->read_ee); + reclaim_net_ee(mdev); + spin_unlock_irq(&mdev->req_lock); + + /* FIXME: fail pending reads? + * when we are configured for freeze io, + * we could retry them once we un-freeze. */ + drbd_fail_pending_reads(mdev); + + /* We do not have data structures that would allow us to + * get the rs_pending_cnt down to 0 again. + * * On SyncTarget we do not have any data structures describing + * the pending RSDataRequest's we have sent. + * * On SyncSource there is no data structure that tracks + * the RSDataReply blocks that we sent to the SyncTarget. + * And no, it is not the sum of the reference counts in the + * resync_LRU. The resync_LRU tracks the whole operation including + * the disk-IO, while the rs_pending_cnt only tracks the blocks + * on the fly. */ + drbd_rs_cancel_all(mdev); + mdev->rs_total = 0; + mdev->rs_failed = 0; + atomic_set(&mdev->rs_pending_cnt, 0); + wake_up(&mdev->misc_wait); + + /* make sure syncer is stopped and w_resume_next_sg queued */ + del_timer_sync(&mdev->resync_timer); + set_bit(STOP_SYNC_TIMER, &mdev->flags); + resync_timer_fn((unsigned long)mdev); + + /* wait for all w_e_end_data_req, w_e_end_rsdata_req, w_send_barrier, + * w_make_resync_request etc. which may still be on the worker queue + * to be "canceled" */ + set_bit(WORK_PENDING, &mdev->flags); + prev_work_done.cb = w_prev_work_done; + drbd_queue_work(&mdev->data.work, &prev_work_done); + wait_event(mdev->misc_wait, !test_bit(WORK_PENDING, &mdev->flags)); + + kfree(mdev->p_uuid); + mdev->p_uuid = NULL; + + /* queue cleanup for the worker. + * FIXME this should go into after_state_ch */ + if (!mdev->state.susp) + tl_clear(mdev); + + INFO("Connection closed\n"); + + drbd_md_sync(mdev); + + fp = DontCare; + if (inc_local(mdev)) { + fp = mdev->bc->dc.fencing; + dec_local(mdev); + } + + if (mdev->state.role == Primary) { + if (fp >= Resource && mdev->state.pdsk >= DUnknown) { + enum drbd_disk_state nps = drbd_try_outdate_peer(mdev); + drbd_request_state(mdev, NS(pdsk, nps)); + } + } + + spin_lock_irq(&mdev->req_lock); + os = mdev->state; + if (os.conn >= Unconnected) { + /* Do not restart in case we are Disconnecting */ + ns = os; + ns.conn = Unconnected; + rv = _drbd_set_state(mdev, ns, ChgStateVerbose, NULL); + } + spin_unlock_irq(&mdev->req_lock); + + if (os.conn == Disconnecting) { + wait_event( mdev->misc_wait, atomic_read(&mdev->net_cnt) == 0 ); + + kfree(mdev->ee_hash); + mdev->ee_hash = NULL; + mdev->ee_hash_s = 0; + + kfree(mdev->tl_hash); + mdev->tl_hash = NULL; + mdev->tl_hash_s = 0; + + crypto_free_hash(mdev->cram_hmac_tfm); + mdev->cram_hmac_tfm = NULL; + + kfree(mdev->net_conf); + mdev->net_conf = NULL; + drbd_request_state(mdev, NS(conn, StandAlone)); + } + + /* they do trigger all the time. + * hm. why won't tcp release the page references, + * we already released the socket!? + D_ASSERT(atomic_read(&mdev->pp_in_use) == 0); + D_ASSERT(list_empty(&mdev->net_ee)); + */ + D_ASSERT(list_empty(&mdev->read_ee)); + D_ASSERT(list_empty(&mdev->active_ee)); + D_ASSERT(list_empty(&mdev->sync_ee)); + D_ASSERT(list_empty(&mdev->done_ee)); + + /* ok, no more ee's on the fly, it is safe to reset the epoch_size */ + mdev->epoch_size = 0; +} + +/* + * We support PRO_VERSION_MIN to PRO_VERSION_MAX. The protocol version + * we can agree on is stored in agreed_pro_version. + * + * feature flags and the reserved array should be enough room for future + * enhancements of the handshake protocol, and possible plugins... + * + * for now, they are expected to be zero, but ignored. + */ +STATIC int drbd_send_handshake(struct drbd_conf *mdev) +{ + /* ASSERT current == mdev->receiver ... */ + struct Drbd_HandShake_Packet *p = &mdev->data.sbuf.HandShake; + int ok; + + if (down_interruptible(&mdev->data.mutex)) { + ERR("interrupted during initial handshake\n"); + return 0; /* interrupted. not ok. */ + } + /* FIXME do we need to verify this here? */ + if (mdev->data.socket == NULL) { + up(&mdev->data.mutex); + return 0; + } + + memset(p, 0, sizeof(*p)); + p->protocol_min = cpu_to_be32(PRO_VERSION_MIN); + p->protocol_max = cpu_to_be32(PRO_VERSION_MAX); + ok = _drbd_send_cmd( mdev, mdev->data.socket, HandShake, + (struct Drbd_Header *)p, sizeof(*p), 0 ); + up(&mdev->data.mutex); + return ok; +} + +/* + * return values: + * 1 yess, we have a valid connection + * 0 oops, did not work out, please try again + * -1 peer talks different language, + * no point in trying again, please go standalone. + */ +int drbd_do_handshake(struct drbd_conf *mdev) +{ + /* ASSERT current == mdev->receiver ... */ + struct Drbd_HandShake_Packet *p = &mdev->data.rbuf.HandShake; + const int expect = sizeof(struct Drbd_HandShake_Packet) + -sizeof(struct Drbd_Header); + int rv; + + rv = drbd_send_handshake(mdev); + if (!rv) + return 0; + + rv = drbd_recv_header(mdev, &p->head); + if (!rv) + return 0; + + if (p->head.command != HandShake) { + ERR( "expected HandShake packet, received: %s (0x%04x)\n", + cmdname(p->head.command), p->head.command ); + return -1; + } + + if (p->head.length != expect) { + ERR( "expected HandShake length: %u, received: %u\n", + expect, p->head.length ); + return -1; + } + + rv = drbd_recv(mdev, &p->head.payload, expect); + + if (rv != expect) { + ERR("short read receiving handshake packet: l=%u\n", rv); + return 0; + } + + dump_packet(mdev, mdev->data.socket, 2, &mdev->data.rbuf, + __FILE__, __LINE__); + + p->protocol_min = be32_to_cpu(p->protocol_min); + p->protocol_max = be32_to_cpu(p->protocol_max); + if(p->protocol_max == 0) p->protocol_max = p->protocol_min; + + if (PRO_VERSION_MAX < p->protocol_min ) goto incompat; + if (PRO_VERSION_MIN > p->protocol_max ) goto incompat; + + mdev->agreed_pro_version = min_t(int,PRO_VERSION_MAX,p->protocol_max); + + INFO("Handshake successful: " + "Agreed network protocol version %d\n", mdev->agreed_pro_version); + + return 1; + + incompat: + ERR("incompatible DRBD dialects: " + "I support %d-%d, peer supports %d-%d\n", + PRO_VERSION_MIN,PRO_VERSION_MAX, + p->protocol_min, p->protocol_max); + return -1; +} + +#if !defined(CONFIG_CRYPTO_HMAC) && !defined(CONFIG_CRYPTO_HMAC_MODULE) +int drbd_do_auth(struct drbd_conf *mdev) +{ + ERR( "This kernel was build without CONFIG_CRYPTO_HMAC.\n"); + ERR( "You need to disable 'cram-hmac-alg' in drbd.conf.\n"); + return 0; +} +#else +#define CHALLENGE_LEN 64 +int drbd_do_auth(struct drbd_conf *mdev) +{ + char my_challenge[CHALLENGE_LEN]; /* 64 Bytes... */ + struct scatterlist sg; + char *response = NULL; + char *right_response = NULL; + char *peers_ch = NULL; + struct Drbd_Header p; + unsigned int key_len = strlen(mdev->net_conf->shared_secret); + unsigned int resp_size; + struct hash_desc desc; + int rv; + + desc.tfm = mdev->cram_hmac_tfm; + desc.flags = 0; + + rv = crypto_hash_setkey(mdev->cram_hmac_tfm, + (u8 *)mdev->net_conf->shared_secret, key_len); + if (rv) { + ERR("crypto_hash_setkey() failed with %d\n", rv); + rv = 0; + goto fail; + } + + get_random_bytes(my_challenge, CHALLENGE_LEN); + + rv = drbd_send_cmd2(mdev, AuthChallenge, my_challenge, CHALLENGE_LEN); + if (!rv) + goto fail; + + rv = drbd_recv_header(mdev, &p); + if (!rv) + goto fail; + + if (p.command != AuthChallenge) { + ERR( "expected AuthChallenge packet, received: %s (0x%04x)\n", + cmdname(p.command), p.command ); + rv = 0; + goto fail; + } + + if (p.length > CHALLENGE_LEN*2) { + ERR( "expected AuthChallenge payload too big.\n"); + rv = 0; + goto fail; + } + + peers_ch = kmalloc(p.length, GFP_KERNEL); + if (peers_ch == NULL) { + ERR("kmalloc of peers_ch failed\n"); + rv = 0; + goto fail; + } + + rv = drbd_recv(mdev, peers_ch, p.length); + + if (rv != p.length) { + ERR("short read AuthChallenge: l=%u\n", rv); + rv = 0; + goto fail; + } + + resp_size = crypto_hash_digestsize(mdev->cram_hmac_tfm); + response = kmalloc(resp_size, GFP_KERNEL); + if (response == NULL) { + ERR("kmalloc of response failed\n"); + rv = 0; + goto fail; + } + + sg_init_table(&sg, 1); + sg_set_buf(&sg, peers_ch, p.length); + + rv = crypto_hash_digest(&desc, &sg, sg.length, response); + if (rv) { + ERR( "crypto_hash_digest() failed with %d\n", rv); + rv = 0; + goto fail; + } + + rv = drbd_send_cmd2(mdev, AuthResponse, response, resp_size); + if (!rv) + goto fail; + + rv = drbd_recv_header(mdev, &p); + if (!rv) + goto fail; + + if (p.command != AuthResponse) { + ERR( "expected AuthResponse packet, received: %s (0x%04x)\n", + cmdname(p.command), p.command ); + rv = 0; + goto fail; + } + + if (p.length != resp_size) { + ERR( "expected AuthResponse payload of wrong size\n" ); + rv = 0; + goto fail; + } + + rv = drbd_recv(mdev, response , resp_size); + + if (rv != resp_size) { + ERR("short read receiving AuthResponse: l=%u\n", rv); + rv = 0; + goto fail; + } + + right_response = kmalloc(resp_size, GFP_KERNEL); + if (response == NULL) { + ERR("kmalloc of right_response failed\n"); + rv = 0; + goto fail; + } + + sg_set_buf(&sg, my_challenge, CHALLENGE_LEN); + + rv = crypto_hash_digest(&desc, &sg, sg.length, right_response); + if (rv) { + ERR( "crypto_hash_digest() failed with %d\n", rv); + rv = 0; + goto fail; + } + + rv = !memcmp(response, right_response, resp_size); + + if (rv) + INFO("Peer authenticated using %d bytes of '%s' HMAC\n", + resp_size, mdev->net_conf->cram_hmac_alg); + + fail: + kfree(peers_ch); + kfree(response); + kfree(right_response); + + return rv; +} +#endif + +STATIC int drbdd_init(struct Drbd_thread *thi) +{ + struct drbd_conf *mdev = thi->mdev; + int minor = mdev_to_minor(mdev); + int h; + + sprintf(current->comm, "drbd%d_receiver", minor); + set_cpus_allowed(current, drbd_calc_cpu_mask(mdev)); + INFO("receiver (re)started\n"); + + do { + h = drbd_connect(mdev); + if (h == 0) { + drbd_disconnect(mdev); + schedule_timeout(HZ); + } + if (h == -1) { + DRBD_WARN("Discarding network configuration.\n"); + drbd_force_state(mdev, NS(conn, Disconnecting)); + } + } while ( h == 0 ); + + if (h > 0) { + if (inc_net(mdev)) { + drbdd(mdev); + dec_net(mdev); + } + } + + drbd_disconnect(mdev); + + /* Ensure that the thread state fits to our connection state. */ + if (mdev->state.conn == Unconnected) { + ERR_IF( mdev->receiver.t_state != Restarting ) + drbd_thread_restart_nowait(&mdev->receiver); + } else if (mdev->state.conn == StandAlone) { + ERR_IF( mdev->receiver.t_state != Exiting ) + drbd_thread_stop_nowait(&mdev->receiver); + } + + INFO("receiver terminated\n"); + return 0; +} + +/* ********* acknowledge sender ******** */ + +STATIC int got_RqSReply(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + struct Drbd_RqS_Reply_Packet *p = (struct Drbd_RqS_Reply_Packet *)h; + + int retcode = be32_to_cpu(p->retcode); + + if (retcode >= SS_Success) { + set_bit(CL_ST_CHG_SUCCESS, &mdev->flags); + } else { + set_bit(CL_ST_CHG_FAIL, &mdev->flags); + ERR("Requested state change failed by peer: %s\n", + set_st_err_name(retcode)); + } + wake_up(&mdev->state_wait); + + return TRUE; +} + +STATIC int got_Ping(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + return drbd_send_ping_ack(mdev); + +} + +STATIC int got_PingAck(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + /* restore idle timeout */ + mdev->meta.socket->sk->sk_rcvtimeo = mdev->net_conf->ping_int*HZ; + + return TRUE; +} + +STATIC int got_BlockAck(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + struct drbd_request *req; + struct Drbd_BlockAck_Packet *p = (struct Drbd_BlockAck_Packet *)h; + sector_t sector = be64_to_cpu(p->sector); + int blksize = be32_to_cpu(p->blksize); + + update_peer_seq(mdev, be32_to_cpu(p->seq_num)); + + if ( is_syncer_block_id(p->block_id)) { + drbd_set_in_sync(mdev, sector, blksize); + dec_rs_pending(mdev); + } else { + spin_lock_irq(&mdev->req_lock); + req = _ack_id_to_req(mdev, p->block_id, sector); + + if (unlikely(!req)) { + spin_unlock_irq(&mdev->req_lock); + ERR("Got a corrupt block_id/sector pair(2).\n"); + return FALSE; + } + + switch (be16_to_cpu(h->command)) { + case RSWriteAck: + D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C); + _req_mod(req, write_acked_by_peer_and_sis, 0); + break; + case WriteAck: + D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C); + _req_mod(req, write_acked_by_peer, 0); + break; + case RecvAck: + D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_B); + _req_mod(req, recv_acked_by_peer, 0); + break; + case DiscardAck: + D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C); + ALERT("Got DiscardAck packet %llus +%u!" + " DRBD is not a random data generator!\n", + (unsigned long long)req->sector, req->size); + _req_mod(req, conflict_discarded_by_peer, 0); + break; + default: + D_ASSERT(0); + } + spin_unlock_irq(&mdev->req_lock); + } + /* dec_ap_pending is handled within _req_mod */ + + return TRUE; +} + +STATIC int got_NegAck(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + struct Drbd_BlockAck_Packet *p = (struct Drbd_BlockAck_Packet *)h; + sector_t sector = be64_to_cpu(p->sector); + struct drbd_request *req; + + if (DRBD_ratelimit(5*HZ, 5)) + DRBD_WARN("Got NegAck packet. Peer is in troubles?\n"); + + update_peer_seq(mdev, be32_to_cpu(p->seq_num)); + + if (is_syncer_block_id(p->block_id)) { + int size = be32_to_cpu(p->blksize); + + dec_rs_pending(mdev); + + drbd_rs_failed_io(mdev, sector, size); + } else { + spin_lock_irq(&mdev->req_lock); + req = _ack_id_to_req(mdev, p->block_id, sector); + + if (unlikely(!req)) { + spin_unlock_irq(&mdev->req_lock); + ERR("Got a corrupt block_id/sector pair(2).\n"); + return FALSE; + } + + _req_mod(req, neg_acked, 0); + spin_unlock_irq(&mdev->req_lock); + } + + return TRUE; +} + +STATIC int got_NegDReply(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + struct drbd_request *req; + struct Drbd_BlockAck_Packet *p = (struct Drbd_BlockAck_Packet *)h; + sector_t sector = be64_to_cpu(p->sector); + + spin_lock_irq(&mdev->req_lock); + req = _ar_id_to_req(mdev, p->block_id, sector); + if (unlikely(!req)) { + spin_unlock_irq(&mdev->req_lock); + ERR("Got a corrupt block_id/sector pair(3).\n"); + return FALSE; + } + + /* FIXME explicitly warn if protocol != C */ + + ERR("Got NegDReply; Sector %llus, len %u; Fail original request.\n", + (unsigned long long)sector, be32_to_cpu(p->blksize)); + + _req_mod(req, neg_acked, 0); + spin_unlock_irq(&mdev->req_lock); + + /* "ugly and wrong" but what can we do !? */ + drbd_khelper(mdev, "pri-on-incon-degr"); + + return TRUE; +} + +STATIC int got_NegRSDReply(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + sector_t sector; + int size; + struct Drbd_BlockAck_Packet *p = (struct Drbd_BlockAck_Packet *)h; + + sector = be64_to_cpu(p->sector); + size = be32_to_cpu(p->blksize); + D_ASSERT(p->block_id == ID_SYNCER); + + dec_rs_pending(mdev); + + if (inc_local_if_state(mdev, Failed)) { + drbd_rs_complete_io(mdev, sector); + drbd_rs_failed_io(mdev, sector, size); + dec_local(mdev); + } + + return TRUE; +} + +STATIC int got_BarrierAck(struct drbd_conf *mdev, struct Drbd_Header *h) +{ + struct Drbd_BarrierAck_Packet *p = (struct Drbd_BarrierAck_Packet *)h; + + tl_release(mdev, p->barrier, be32_to_cpu(p->set_size)); + dec_ap_pending(mdev); + + return TRUE; +} + + +STATIC int got_OVResult(struct drbd_conf *mdev, struct Drbd_Header* h) +{ + struct Drbd_BlockAck_Packet *p = (struct Drbd_BlockAck_Packet*)h; + struct drbd_work* w; + sector_t sector; + int size; + + sector = be64_to_cpu(p->sector); + size = be32_to_cpu(p->blksize); + + if (be64_to_cpu(p->block_id) == ID_OUT_OF_SYNC) { + drbd_ov_oos_found(mdev, sector, size); + } else ov_oos_print(mdev); + + drbd_rs_complete_io(mdev, sector); + dec_rs_pending(mdev); + + if (--mdev->ov_left == 0) { + w = kmalloc(sizeof(w), GFP_KERNEL); + if (w) { + w->cb = w_ov_finished; + drbd_queue_work_front(&mdev->data.work, w); + } else { + ERR("kmalloc(w) failed."); + drbd_resync_finished(mdev); + } + } + return TRUE; +} + + +struct asender_cmd { + size_t pkt_size; + int (*process)(struct drbd_conf *mdev, struct Drbd_Header *h); +}; + +static struct asender_cmd* get_asender_cmd(int cmd) +{ + static struct asender_cmd asender_tbl[] = { + /* anything missing from this table is in + * the drbd_cmd_handler (drbd_default_handler) table, + * see the beginning of drbdd() */ + [Ping] = { sizeof(struct Drbd_Header), got_Ping }, + [PingAck] = { sizeof(struct Drbd_Header), got_PingAck }, + [RecvAck] = { sizeof(struct Drbd_BlockAck_Packet), got_BlockAck }, + [WriteAck] = { sizeof(struct Drbd_BlockAck_Packet), got_BlockAck }, + [RSWriteAck] = { sizeof(struct Drbd_BlockAck_Packet), got_BlockAck }, + [DiscardAck] = { sizeof(struct Drbd_BlockAck_Packet), got_BlockAck }, + [NegAck] = { sizeof(struct Drbd_BlockAck_Packet), got_NegAck }, + [NegDReply] = + { sizeof(struct Drbd_BlockAck_Packet), got_NegDReply }, + [NegRSDReply] = + { sizeof(struct Drbd_BlockAck_Packet), got_NegRSDReply}, + [OVResult] = { sizeof(struct Drbd_BlockAck_Packet), got_OVResult }, + + [BarrierAck] = + { sizeof(struct Drbd_BarrierAck_Packet), got_BarrierAck }, + [StateChgReply] = + { sizeof(struct Drbd_RqS_Reply_Packet), got_RqSReply }, + }; + if (cmd == OVResult) + return &asender_tbl[cmd]; + if (cmd < FIRST_ASENDER_CMD) + return NULL; + if (cmd > LAST_ASENDER_CMD) + return NULL; + return &asender_tbl[cmd]; +} + +STATIC int drbd_asender(struct Drbd_thread *thi) +{ + struct drbd_conf *mdev = thi->mdev; + struct Drbd_Header *h = &mdev->meta.rbuf.head; + struct asender_cmd *cmd = NULL; + + int rv,len; + void *buf = h; + int received = 0; + int expect = sizeof(struct Drbd_Header); + int empty; + + sprintf(current->comm, "drbd%d_asender", mdev_to_minor(mdev)); + + current->policy = SCHED_RR; /* Make this a realtime task! */ + current->rt_priority = 2; /* more important than all other tasks */ + + set_cpus_allowed(current, drbd_calc_cpu_mask(mdev)); + + while (get_t_state(thi) == Running) { + if (test_and_clear_bit(SEND_PING, &mdev->flags)) { + ERR_IF(!drbd_send_ping(mdev)) goto reconnect; + mdev->meta.socket->sk->sk_rcvtimeo = + mdev->net_conf->ping_timeo*HZ/10; + } + + while (1) { + if (!drbd_process_done_ee(mdev)) { + ERR("process_done_ee() = NOT_OK\n"); + goto reconnect; + } + set_bit(SIGNAL_ASENDER, &mdev->flags); + spin_lock_irq(&mdev->req_lock); + empty = list_empty(&mdev->done_ee); + spin_unlock_irq(&mdev->req_lock); + if (empty && !test_bit(WRITE_ACK_PENDING, &mdev->flags)) + break; + clear_bit(SIGNAL_ASENDER, &mdev->flags); + flush_signals(current); + } + drbd_tcp_flush(mdev->meta.socket); + + rv = drbd_recv_short(mdev, mdev->meta.socket, + buf, expect-received, 0); + clear_bit(SIGNAL_ASENDER, &mdev->flags); + + flush_signals(current); + + drbd_tcp_cork(mdev->meta.socket); + + /* Note: + * -EINTR (on meta) we got a signal + * -EAGAIN (on meta) rcvtimeo expired + * -ECONNRESET other side closed the connection + * -ERESTARTSYS (on data) we got a signal + * rv < 0 other than above: unexpected error! + * rv == expected: full header or command + * rv < expected: "woken" by signal during receive + * rv == 0 : "connection shut down by peer" + */ + if (likely(rv > 0)) { + received += rv; + buf += rv; + } else if (rv == 0) { + ERR("meta connection shut down by peer.\n"); + goto reconnect; + } else if (rv == -EAGAIN) { + if ( mdev->meta.socket->sk->sk_rcvtimeo == + mdev->net_conf->ping_timeo*HZ/10 ) { + ERR("PingAck did not arrive in time.\n"); + goto reconnect; + } + set_bit(SEND_PING, &mdev->flags); + continue; + } else if (rv == -EINTR) { + continue; + } else { + ERR("sock_recvmsg returned %d\n", rv); + goto reconnect; + } + + if (received == expect && cmd == NULL ) { + if (unlikely( h->magic != BE_DRBD_MAGIC )) { + ERR("magic?? on meta m: 0x%lx c: %d l: %d\n", + (long)be32_to_cpu(h->magic), + h->command, h->length); + goto reconnect; + } + cmd = get_asender_cmd(be16_to_cpu(h->command)); + len = be16_to_cpu(h->length); + if (unlikely(cmd == NULL)) { + ERR("unknown command?? on meta m: 0x%lx c: %d l: %d\n", + (long)be32_to_cpu(h->magic), + h->command, h->length); + goto disconnect; + } + expect = cmd->pkt_size; + ERR_IF(len != expect-sizeof(struct Drbd_Header)) { + dump_packet(mdev,mdev->meta.socket,1,(void*)h, __FILE__, __LINE__); + DUMPI(expect); + goto reconnect; + } + } + if (received == expect) { + D_ASSERT(cmd != NULL); + dump_packet(mdev,mdev->meta.socket,1,(void*)h, __FILE__, __LINE__); + if (!cmd->process(mdev,h)) goto reconnect; + + buf = h; + received = 0; + expect = sizeof(struct Drbd_Header); + cmd = NULL; + } + } + + if (0) { + reconnect: + drbd_force_state(mdev,NS(conn, NetworkFailure)); + } + if (0) { + disconnect: + drbd_force_state(mdev,NS(conn, Disconnecting)); + } + clear_bit(SIGNAL_ASENDER, &mdev->flags); + + D_ASSERT(mdev->state.conn < Connected); + INFO("asender terminated\n"); + + return 0; +} --- linux-2.6.27.orig/ubuntu/drbd/drbd_wrappers.h +++ linux-2.6.27/ubuntu/drbd/drbd_wrappers.h @@ -0,0 +1,442 @@ +#include + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +# error "use a 2.6 kernel, please" +#endif + + +/* struct page has a union in 2.6.15 ... + * an anonymous union and struct since 2.6.16 + * or in fc5 "2.6.15" */ +#include +#ifndef page_private +# define page_private(page) ((page)->private) +# define set_page_private(page, v) ((page)->private = (v)) +#endif + +/* see get_sb_bdev and bd_claim */ +extern char *drbd_sec_holder; + +static inline sector_t drbd_get_hardsect(struct block_device *bdev) +{ + return bdev->bd_disk->queue->hardsect_size; +} + +/* Returns the number of 512 byte sectors of the device */ +static inline sector_t drbd_get_capacity(struct block_device *bdev) +{ + /* return bdev ? get_capacity(bdev->bd_disk) : 0; */ + return bdev ? bdev->bd_inode->i_size >> 9 : 0; +} + +/* sets the number of 512 byte sectors of our virtual device */ +static inline void drbd_set_my_capacity(struct drbd_conf *mdev, + sector_t size) +{ + /* set_capacity(mdev->this_bdev->bd_disk, size); */ + set_capacity(mdev->vdisk, size); + mdev->this_bdev->bd_inode->i_size = (loff_t)size << 9; +} + +#define drbd_bio_uptodate(bio) bio_flagged(bio, BIO_UPTODATE) + +static inline int drbd_bio_has_active_page(struct bio *bio) +{ + struct bio_vec *bvec; + int i; + + __bio_for_each_segment(bvec, bio, i, 0) { + if (page_count(bvec->bv_page) > 1) return 1; + } + + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) +/* Before Linux-2.6.24 bie_endio() had the size of the bio as second argument. + See 6712ecf8f648118c3363c142196418f89a510b90 */ +#define bio_endio(B,E) bio_endio(B, (B)->bi_size, E) +#define BIO_ENDIO_TYPE int +#define BIO_ENDIO_ARGS(b,e) (b, unsigned int bytes_done, e) +#define BIO_ENDIO_FN_START if (bio->bi_size) return 1 +#define BIO_ENDIO_FN_RETURN return 0 +#else +#define BIO_ENDIO_TYPE void +#define BIO_ENDIO_ARGS(b,e) (b,e) +#define BIO_ENDIO_FN_START while(0) {} +#define BIO_ENDIO_FN_RETURN return +#endif + +// bi_end_io handlers +extern BIO_ENDIO_TYPE drbd_md_io_complete BIO_ENDIO_ARGS(struct bio *bio, int error); +extern BIO_ENDIO_TYPE drbd_endio_read_sec BIO_ENDIO_ARGS(struct bio *bio, int error); +extern BIO_ENDIO_TYPE drbd_endio_write_sec BIO_ENDIO_ARGS(struct bio *bio, int error); +extern BIO_ENDIO_TYPE drbd_endio_pri BIO_ENDIO_ARGS(struct bio *bio, int error); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) +/* Before 2.6.23 (with 20c2df83d25c6a95affe6157a4c9cac4cf5ffaac) kmem_cache_create had a + ctor and a dtor */ +#define kmem_cache_create(N,S,A,F,C) kmem_cache_create(N,S,A,F,C,NULL) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) +static inline void sg_set_page(struct scatterlist *sg, struct page *page, + unsigned int len, unsigned int offset) +{ + sg->page = page; + sg->offset = offset; + sg->length = len; +} + +#define sg_init_table(S,N) ({}) + +#ifdef NEED_SG_SET_BUF +static inline void sg_set_buf(struct scatterlist *sg, const void *buf, + unsigned int buflen) +{ + sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf)); +} +#endif + +#endif + +/* + * used to submit our private bio + */ +static inline void drbd_generic_make_request(struct drbd_conf *mdev, + int fault_type, struct bio *bio) +{ + __release(local); + if (!bio->bi_bdev) { + printk(KERN_ERR "drbd%d: drbd_generic_make_request: " + "bio->bi_bdev == NULL\n", + mdev_to_minor(mdev)); + dump_stack(); + bio_endio(bio, -ENODEV); + return; + } + + if (FAULT_ACTIVE(mdev, fault_type)) + bio_endio(bio, -EIO); + else + generic_make_request(bio); +} + +static inline void drbd_plug_device(struct drbd_conf *mdev) +{ + struct request_queue *q; + q = bdev_get_queue(mdev->this_bdev); + + spin_lock_irq(q->queue_lock); + +/* XXX the check on !blk_queue_plugged is redundant, + * implicitly checked in blk_plug_device */ + + if (!blk_queue_plugged(q)) { + blk_plug_device(q); + del_timer(&q->unplug_timer); + /* unplugging should not happen automatically... */ + } + spin_unlock_irq(q->queue_lock); +} + +#ifdef DEFINE_SOCK_CREATE_KERN +#define sock_create_kern sock_create +#endif + +#ifdef USE_KMEM_CACHE_S +#define kmem_cache kmem_cache_s +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) +static inline void drbd_unregister_blkdev(unsigned int major, const char *name) +{ + int ret = unregister_blkdev(major,name); + if (ret) + printk(KERN_ERR "drbd: unregister of device failed\n"); +} +#else +#define drbd_unregister_blkdev unregister_blkdev +#endif + +#ifdef NEED_BACKPORT_OF_ATOMIC_ADD + +#if defined(__x86_64__) + +static __inline__ int atomic_add_return(int i, atomic_t *v) +{ + int __i = i; + __asm__ __volatile__( + LOCK_PREFIX "xaddl %0, %1;" + :"=r"(i) + :"m"(v->counter), "0"(i)); + return i + __i; +} + +static __inline__ int atomic_sub_return(int i, atomic_t *v) +{ + return atomic_add_return(-i,v); +} + +#define atomic_inc_return(v) (atomic_add_return(1,v)) +#define atomic_dec_return(v) (atomic_sub_return(1,v)) + +#elif defined(__i386__) || defined(__arch_um__) + +static __inline__ int atomic_add_return(int i, atomic_t *v) +{ + int __i; +#ifdef CONFIG_M386 + unsigned long flags; + if(unlikely(boot_cpu_data.x86==3)) + goto no_xadd; +#endif + /* Modern 486+ processor */ + __i = i; + __asm__ __volatile__( + LOCK_PREFIX "xaddl %0, %1;" + :"=r"(i) + :"m"(v->counter), "0"(i)); + return i + __i; + +#ifdef CONFIG_M386 +no_xadd: /* Legacy 386 processor */ + local_irq_save(flags); + __i = atomic_read(v); + atomic_set(v, i + __i); + local_irq_restore(flags); + return i + __i; +#endif +} + +static __inline__ int atomic_sub_return(int i, atomic_t *v) +{ + return atomic_add_return(-i,v); +} + +#define atomic_inc_return(v) (atomic_add_return(1,v)) +#define atomic_dec_return(v) (atomic_sub_return(1,v)) + +#else +# error "You need to copy/past atomic_inc_return()/atomic_dec_return() here" +# error "for your architecture. (Hint: Kernels after 2.6.10 have those" +# error "by default! Using a later kernel might be less effort!)" +#endif + +#endif + +#if !defined(CRYPTO_ALG_ASYNC) +/* With Linux-2.6.19 the crypto API changed! */ +/* This is not a generic backport of the new api, it just implements + the corner case of "hmac(xxx)". */ + +#define CRYPTO_ALG_ASYNC 4711 +#define CRYPTO_ALG_TYPE_HASH CRYPTO_ALG_TYPE_DIGEST + +struct crypto_hash { + struct crypto_tfm *base; + const u8 *key; + int keylen; +}; + +struct hash_desc { + struct crypto_hash *tfm; + u32 flags; +}; + +static inline struct crypto_hash * +crypto_alloc_hash(char *alg_name, u32 type, u32 mask) +{ + struct crypto_hash *ch; + char *closing_bracket; + + // "hmac(xxx)" is in alg_name we need that xxx. + closing_bracket = strchr(alg_name,')'); + if(!closing_bracket) { + ch = kmalloc(sizeof(struct crypto_hash),GFP_KERNEL); + if(!ch) return ERR_PTR(-ENOMEM); + ch->base = crypto_alloc_tfm(alg_name, 0); + if (ch->base == NULL) { + kfree(ch); + return ERR_PTR(-ENOMEM); + } + return ch; + } + if(closing_bracket-alg_name < 6) return ERR_PTR(-ENOENT); + + ch = kmalloc(sizeof(struct crypto_hash),GFP_KERNEL); + if(!ch) return ERR_PTR(-ENOMEM); + + *closing_bracket = 0; + ch->base = crypto_alloc_tfm(alg_name + 5, 0); + *closing_bracket = ')'; + + if (ch->base == NULL) { + kfree(ch); + return ERR_PTR(-ENOMEM); + } + + return ch; +} + +static inline int +crypto_hash_setkey(struct crypto_hash *hash,const u8 *key,unsigned int keylen) +{ + hash->key = key; + hash->keylen = keylen; + + return 0; +} + +static inline int +crypto_hash_digest(struct hash_desc *desc, struct scatterlist *sg, + unsigned int nbytes, u8 *out) +{ + + crypto_hmac(desc->tfm->base, (u8*)desc->tfm->key, + &desc->tfm->keylen, sg, 1 /* ! */ , out); + /* ! this is not generic. Would need to convert nbytes -> nsg */ + + return 0; +} + +static inline void crypto_free_hash(struct crypto_hash *tfm) +{ + if (!tfm) return; + crypto_free_tfm(tfm->base); + kfree(tfm); +} + +static inline unsigned int crypto_hash_digestsize(struct crypto_hash *tfm) +{ + return crypto_tfm_alg_digestsize(tfm->base); +} + +static inline struct crypto_tfm *crypto_hash_tfm(struct crypto_hash *tfm) +{ + return tfm->base; +} + +static inline int crypto_hash_init(struct hash_desc *desc) +{ + crypto_digest_init(desc->tfm->base); + return 0; +} + +static inline int crypto_hash_update(struct hash_desc *desc, + struct scatterlist *sg, + unsigned int nbytes) +{ + crypto_digest_update(desc->tfm->base,sg,1 /* ! */ ); + /* ! this is not generic. Would need to convert nbytes -> nsg */ + + return 0; +} + +static inline int crypto_hash_final(struct hash_desc *desc, u8 *out) +{ + crypto_digest_final(desc->tfm->base, out); + return 0; +} + +#endif + +#ifdef NEED_BACKPORT_OF_KZALLOC +static inline void *kzalloc(size_t size, int flags) +{ + void *rv = kmalloc(size,flags); + if(rv) memset(rv,0,size); + + return rv; +} +#endif + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +#define __bitmap_parse(BUF, BUFLEN, ISUSR, MASKP, NMASK) \ + backport_bitmap_parse(BUF, BUFLEN, ISUSR, MASKP, NMASK) + +#define CHUNKSZ 32 +#define nbits_to_hold_value(val) fls(val) +#define unhex(c) (isdigit(c) ? (c - '0') : (toupper(c) - 'A' + 10)) + +static inline int backport_bitmap_parse(const char *buf, unsigned int buflen, + int is_user, unsigned long *maskp, + int nmaskbits) +{ + int c, old_c, totaldigits, ndigits, nchunks, nbits; + u32 chunk; + const char __user *ubuf = buf; + + bitmap_zero(maskp, nmaskbits); + + nchunks = nbits = totaldigits = c = 0; + do { + chunk = ndigits = 0; + + /* Get the next chunk of the bitmap */ + while (buflen) { + old_c = c; + if (is_user) { + if (__get_user(c, ubuf++)) + return -EFAULT; + } + else + c = *buf++; + buflen--; + if (isspace(c)) + continue; + + /* + * If the last character was a space and the current + * character isn't '\0', we've got embedded whitespace. + * This is a no-no, so throw an error. + */ + if (totaldigits && c && isspace(old_c)) + return -EINVAL; + + /* A '\0' or a ',' signal the end of the chunk */ + if (c == '\0' || c == ',') + break; + + if (!isxdigit(c)) + return -EINVAL; + + /* + * Make sure there are at least 4 free bits in 'chunk'. + * If not, this hexdigit will overflow 'chunk', so + * throw an error. + */ + if (chunk & ~((1UL << (CHUNKSZ - 4)) - 1)) + return -EOVERFLOW; + + chunk = (chunk << 4) | unhex(c); + ndigits++; totaldigits++; + } + if (ndigits == 0) + return -EINVAL; + if (nchunks == 0 && chunk == 0) + continue; + + bitmap_shift_left(maskp, maskp, CHUNKSZ, nmaskbits); + *maskp |= chunk; + nchunks++; + nbits += (nchunks == 1) ? nbits_to_hold_value(chunk) : CHUNKSZ; + if (nbits > nmaskbits) + return -EOVERFLOW; + } while (buflen && c == ','); + + return 0; +} +#endif + +#ifndef __CHECKER__ +# undef __cond_lock +# define __cond_lock(x,c) (c) +#endif + +#ifndef KERNEL_HAS_GFP_T +#define KERNEL_HAS_GFP_T +typedef unsigned gfp_t; +#endif --- linux-2.6.27.orig/ubuntu/drbd/drbd_req.c +++ linux-2.6.27/ubuntu/drbd/drbd_req.c @@ -0,0 +1,1274 @@ +/* +-*- linux-c -*- + drbd_req.c + Kernel module for 2.6.x Kernels + + This file is part of DRBD by Philipp Reisner and Lars Ellenberg. + + Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. + Copyright (C) 1999-2008, Philipp Reisner . + Copyright (C) 2002-2008, Lars Ellenberg . + + drbd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + drbd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with drbd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#include +#include + +#include +#include +#include "drbd_int.h" +#include "drbd_req.h" + +/* outside of the ifdef + * because of the _print_rq_state(,FIXME) in barrier_acked */ +STATIC void _print_rq_state(struct drbd_request *req, const char *txt) +{ + const unsigned long s = req->rq_state; + struct drbd_conf *mdev = req->mdev; + const int rw = (req->master_bio == NULL || + bio_data_dir(req->master_bio) == WRITE) ? + 'W' : 'R'; + + INFO("%s %p %c L%c%c%cN%c%c%c%c%c %u (%llus +%u) %s\n", + txt, req, rw, + s & RQ_LOCAL_PENDING ? 'p' : '-', + s & RQ_LOCAL_COMPLETED ? 'c' : '-', + s & RQ_LOCAL_OK ? 'o' : '-', + s & RQ_NET_PENDING ? 'p' : '-', + s & RQ_NET_QUEUED ? 'q' : '-', + s & RQ_NET_SENT ? 's' : '-', + s & RQ_NET_DONE ? 'd' : '-', + s & RQ_NET_OK ? 'o' : '-', + req->epoch, + (unsigned long long)req->sector, + req->size, + conns_to_name(mdev->state.conn)); +} + +/* #define VERBOSE_REQUEST_CODE */ +#if defined(VERBOSE_REQUEST_CODE) || defined(ENABLE_DYNAMIC_TRACE) +STATIC void _print_req_mod(struct drbd_request *req, enum drbd_req_event what) +{ + struct drbd_conf *mdev = req->mdev; + const int rw = (req->master_bio == NULL || + bio_data_dir(req->master_bio) == WRITE) ? + 'W' : 'R'; + + static const char *rq_event_names[] = { + [created] = "created", + [to_be_send] = "to_be_send", + [to_be_submitted] = "to_be_submitted", + [queue_for_net_write] = "queue_for_net_write", + [queue_for_net_read] = "queue_for_net_read", + [send_canceled] = "send_canceled", + [send_failed] = "send_failed", + [handed_over_to_network] = "handed_over_to_network", + [connection_lost_while_pending] = + "connection_lost_while_pending", + [recv_acked_by_peer] = "recv_acked_by_peer", + [write_acked_by_peer] = "write_acked_by_peer", + [neg_acked] = "neg_acked", + [conflict_discarded_by_peer] = "conflict_discarded_by_peer", + [barrier_acked] = "barrier_acked", + [data_received] = "data_received", + [read_completed_with_error] = "read_completed_with_error", + [write_completed_with_error] = "write_completed_with_error", + [completed_ok] = "completed_ok", + }; + + INFO("_req_mod(%p %c ,%s)\n", req, rw, rq_event_names[what]); +} + +# ifdef ENABLE_DYNAMIC_TRACE +# define print_rq_state(R, T) \ + MTRACE(TraceTypeRq, TraceLvlMetrics, _print_rq_state(R, T);) +# define print_req_mod(T, W) \ + MTRACE(TraceTypeRq, TraceLvlMetrics, _print_req_mod(T, W);) +# else +# define print_rq_state(R, T) _print_rq_state(R, T) +# define print_req_mod(T, W) _print_req_mod(T, W) +# endif + +#else +#define print_rq_state(R, T) +#define print_req_mod(T, W) +#endif + +/* We only support diskstats for 2.6.16 and up. + * see also commit commit a362357b6cd62643d4dda3b152639303d78473da + * Author: Jens Axboe + * Date: Tue Nov 1 09:26:16 2005 +0100 + * [BLOCK] Unify the seperate read/write io stat fields into arrays */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) +#define _drbd_start_io_acct(...) do {} while (0) +#define _drbd_end_io_acct(...) do {} while (0) +#else + +/* Update disk stats at start of I/O request */ +static inline void _drbd_start_io_acct(struct drbd_conf *mdev, struct drbd_request *req, struct bio *bio) +{ + const int rw = bio_data_dir(bio); + + MUST_HOLD(&mdev->req_lock) + __disk_stat_inc(mdev->vdisk, ios[rw]); + __disk_stat_add(mdev->vdisk, sectors[rw], bio_sectors(bio)); + disk_round_stats(mdev->vdisk); + mdev->vdisk->in_flight++; +} + +/* Update disk stats when completing request upwards */ +static inline void _drbd_end_io_acct(struct drbd_conf *mdev, struct drbd_request *req) +{ + int rw = bio_data_dir(req->master_bio); + unsigned long duration = jiffies - req->start_time; + + MUST_HOLD(&mdev->req_lock) + __disk_stat_add(mdev->vdisk, ticks[rw], duration); + disk_round_stats(mdev->vdisk); + mdev->vdisk->in_flight--; +} + +#endif + +static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const int rw) +{ + const unsigned long s = req->rq_state; + /* if it was a write, we may have to set the corresponding + * bit(s) out-of-sync first. If it had a local part, we need to + * release the reference to the activity log. */ + if (rw == WRITE) { + /* remove it from the transfer log. + * well, only if it had been there in the first + * place... if it had not (local only or conflicting + * and never sent), it should still be "empty" as + * initialised in drbd_req_new(), so we can list_del() it + * here unconditionally */ + list_del(&req->tl_requests); + /* Set out-of-sync unless both OK flags are set + * (local only or remote failed). + * Other places where we set out-of-sync: + * READ with local io-error */ + if (!(s & RQ_NET_OK) || !(s & RQ_LOCAL_OK)) + drbd_set_out_of_sync(mdev, req->sector, req->size); + + if ((s & RQ_NET_OK) && (s & RQ_LOCAL_OK) && (s & RQ_NET_SIS)) + drbd_set_in_sync(mdev, req->sector, req->size); + + /* one might be tempted to move the drbd_al_complete_io + * to the local io completion callback drbd_endio_pri. + * but, if this was a mirror write, we may only + * drbd_al_complete_io after this is RQ_NET_DONE, + * otherwise the extent could be dropped from the al + * before it has actually been written on the peer. + * if we crash before our peer knows about the request, + * but after the extent has been dropped from the al, + * we would forget to resync the corresponding extent. + */ + if (s & RQ_LOCAL_MASK) { + if (inc_local_if_state(mdev, Failed)) { + drbd_al_complete_io(mdev, req->sector); + dec_local(mdev); + } else { + DRBD_WARN("Should have called drbd_al_complete_io(, %llu), " + "but my Disk seems to have failed :(\n", + (unsigned long long) req->sector); + } + } + } + + /* if it was a local io error, we want to notify our + * peer about that, and see if we need to + * detach the disk and stuff. + * to avoid allocating some special work + * struct, reuse the request. */ + + /* THINK + * why do we do this not when we detect the error, + * but delay it until it is "done", i.e. possibly + * until the next barrier ack? */ + + if (rw == WRITE && + (( s & RQ_LOCAL_MASK) && !(s & RQ_LOCAL_OK))) { + if (!(req->w.list.next == LIST_POISON1 || + list_empty(&req->w.list))) { + /* DEBUG ASSERT only; if this triggers, we + * probably corrupt the worker list here */ + DUMPP(req->w.list.next); + DUMPP(req->w.list.prev); + } + req->w.cb = w_io_error; + drbd_queue_work(&mdev->data.work, &req->w); + /* drbd_req_free() is done in w_io_error */ + } else { + drbd_req_free(req); + } +} + +static void queue_barrier(struct drbd_conf *mdev) +{ + struct drbd_barrier *b; + + /* We are within the req_lock. Once we queued the barrier for sending, + * we set the CREATE_BARRIER bit. It is cleared as soon as a new + * barrier/epoch object is added. This is the only place this bit is + * set. It indicates that the barrier for this epoch is already queued, + * and no new epoch has been created yet. */ + if (test_bit(CREATE_BARRIER, &mdev->flags)) + return; + + b = mdev->newest_barrier; + b->w.cb = w_send_barrier; + /* inc_ap_pending done here, so we won't + * get imbalanced on connection loss. + * dec_ap_pending will be done in got_BarrierAck + * or (on connection loss) in tl_clear. */ + inc_ap_pending(mdev); + drbd_queue_work(&mdev->data.work, &b->w); + set_bit(CREATE_BARRIER, &mdev->flags); +} + +static void _about_to_complete_local_write(struct drbd_conf *mdev, + struct drbd_request *req) +{ + const unsigned long s = req->rq_state; + struct drbd_request *i; + struct Tl_epoch_entry *e; + struct hlist_node *n; + struct hlist_head *slot; + + /* before we can signal completion to the upper layers, + * we may need to close the current epoch */ + if (mdev->state.conn >= Connected && + req->epoch == mdev->newest_barrier->br_number) + queue_barrier(mdev); + + /* we need to do the conflict detection stuff, + * if we have the ee_hash (two_primaries) and + * this has been on the network */ + if ((s & RQ_NET_DONE) && mdev->ee_hash != NULL) { + const sector_t sector = req->sector; + const int size = req->size; + + /* ASSERT: + * there must be no conflicting requests, since + * they must have been failed on the spot */ +#define OVERLAPS overlaps(sector, size, i->sector, i->size) + slot = tl_hash_slot(mdev, sector); + hlist_for_each_entry(i, n, slot, colision) { + if (OVERLAPS) { + ALERT("LOGIC BUG: completed: %p %llus +%u; " + "other: %p %llus +%u\n", + req, (unsigned long long)sector, size, + i, (unsigned long long)i->sector, i->size); + } + } + + /* maybe "wake" those conflicting epoch entries + * that wait for this request to finish. + * + * currently, there can be only _one_ such ee + * (well, or some more, which would be pending + * DiscardAck not yet sent by the asender...), + * since we block the receiver thread upon the + * first conflict detection, which will wait on + * misc_wait. maybe we want to assert that? + * + * anyways, if we found one, + * we just have to do a wake_up. */ +#undef OVERLAPS +#define OVERLAPS overlaps(sector, size, e->sector, e->size) + slot = ee_hash_slot(mdev, req->sector); + hlist_for_each_entry(e, n, slot, colision) { + if (OVERLAPS) { + wake_up(&mdev->misc_wait); + break; + } + } + } +#undef OVERLAPS +} + +static void _complete_master_bio(struct drbd_conf *mdev, + struct drbd_request *req, int error) +{ + dump_bio(mdev, req->master_bio, 1); + bio_endio(req->master_bio, error); + req->master_bio = NULL; + dec_ap_bio(mdev); +} + +void _req_may_be_done(struct drbd_request *req, int error) +{ + const unsigned long s = req->rq_state; + struct drbd_conf *mdev = req->mdev; + int rw; + + print_rq_state(req, "_req_may_be_done"); + MUST_HOLD(&mdev->req_lock) + + /* we must not complete the master bio, while it is + * still being processed by _drbd_send_zc_bio (drbd_send_dblock) + * not yet acknowledged by the peer + * not yet completed by the local io subsystem + * these flags may get cleared in any order by + * the worker, + * the receiver, + * the bio_endio completion callbacks. + */ + if (s & RQ_NET_QUEUED) + return; + if (s & RQ_NET_PENDING) + return; + if (s & RQ_LOCAL_PENDING) + return; + + if (req->master_bio) { + /* this is data_received (remote read) + * or protocol C WriteAck + * or protocol B RecvAck + * or protocol A "handed_over_to_network" (SendAck) + * or canceled or failed, + * or killed from the transfer log due to connection loss. + */ + + /* + * figure out whether to report success or failure. + * + * report success when at least one of the operations suceeded. + * or, to put the other way, + * only report failure, when both operations failed. + * + * what to do about the failures is handled elsewhere. + * what we need to do here is just: complete the master_bio. + */ + int ok = (s & RQ_LOCAL_OK) || (s & RQ_NET_OK); + rw = bio_data_dir(req->master_bio); + + /* remove the request from the conflict detection + * respective block_id verification hash */ + if (!hlist_unhashed(&req->colision)) + hlist_del(&req->colision); + else + D_ASSERT((s & RQ_NET_MASK) == 0); + + /* for writes we need to do some extra housekeeping */ + if (rw == WRITE) + _about_to_complete_local_write(mdev, req); + + /* FIXME not yet implemented... + * in case we got "suspended" (on_disconnect: freeze io) + * we may not yet complete the request... + * though, this is probably best handled elsewhere by not + * walking the transfer log until "unfreeze", so we won't end + * up here anyways during the freeze ... + * then again, if it is a READ, it is not in the TL at all. + * is it still leagal to complete a READ during freeze? */ + + /* Update disk stats */ + _drbd_end_io_acct(mdev, req); + + _complete_master_bio(mdev,req, + ok ? 0 : ( error ? error : -EIO ) ); + } else { + /* only WRITE requests can end up here without a master_bio */ + rw = WRITE; + } + + if ((s & RQ_NET_MASK) == 0 || (s & RQ_NET_DONE)) { + /* this is disconnected (local only) operation, + * or protocol C WriteAck, + * or protocol A or B BarrierAck, + * or killed from the transfer log due to connection loss. */ + _req_is_done(mdev, req, rw); + } + /* else: network part and not DONE yet. that is + * protocol A or B, barrier ack still pending... */ +} + +/* + * checks whether there was an overlapping request + * or ee already registered. + * + * if so, return 1, in which case this request is completed on the spot, + * without ever being submitted or send. + * + * return 0 if it is ok to submit this request. + * + * NOTE: + * paranoia: assume something above us is broken, and issues different write + * requests for the same block simultaneously... + * + * To ensure these won't be reordered differently on both nodes, resulting in + * diverging data sets, we discard the later one(s). Not that this is supposed + * to happen, but this is the rationale why we also have to check for + * conflicting requests with local origin, and why we have to do so regardless + * of whether we allowed multiple primaries. + * + * BTW, in case we only have one primary, the ee_hash is empty anyways, and the + * second hlist_for_each_entry becomes a noop. This is even simpler than to + * grab a reference on the net_conf, and check for the two_primaries flag... + */ +STATIC int _req_conflicts(struct drbd_request *req) +{ + struct drbd_conf *mdev = req->mdev; + const sector_t sector = req->sector; + const int size = req->size; + struct drbd_request *i; + struct Tl_epoch_entry *e; + struct hlist_node *n; + struct hlist_head *slot; + + MUST_HOLD(&mdev->req_lock); + D_ASSERT(hlist_unhashed(&req->colision)); + + /* FIXME should this inc_net/dec_net + * rather be done in drbd_make_request_common? */ + if (!inc_net(mdev)) + return 0; + + /* BUG_ON */ + ERR_IF (mdev->tl_hash_s == 0) + goto out_no_conflict; + BUG_ON(mdev->tl_hash == NULL); + +#define OVERLAPS overlaps(i->sector, i->size, sector, size) + slot = tl_hash_slot(mdev, sector); + hlist_for_each_entry(i, n, slot, colision) { + if (OVERLAPS) { + ALERT("%s[%u] Concurrent local write detected! " + "[DISCARD L] new: %llus +%u; " + "pending: %llus +%u\n", + current->comm, current->pid, + (unsigned long long)sector, size, + (unsigned long long)i->sector, i->size); + goto out_conflict; + } + } + + if (mdev->ee_hash_s) { + /* now, check for overlapping requests with remote origin */ + BUG_ON(mdev->ee_hash == NULL); +#undef OVERLAPS +#define OVERLAPS overlaps(e->sector, e->size, sector, size) + slot = ee_hash_slot(mdev, sector); + hlist_for_each_entry(e, n, slot, colision) { + if (OVERLAPS) { + ALERT("%s[%u] Concurrent remote write detected!" + " [DISCARD L] new: %llus +%u; " + "pending: %llus +%u\n", + current->comm, current->pid, + (unsigned long long)sector, size, + (unsigned long long)e->sector, e->size); + goto out_conflict; + } + } + } +#undef OVERLAPS + +out_no_conflict: + /* this is like it should be, and what we expected. + * our users do behave after all... */ + dec_net(mdev); + return 0; + +out_conflict: + dec_net(mdev); + return 1; +} + +/* obviously this could be coded as many single functions + * instead of one huge switch, + * or by putting the code directly in the respective locations + * (as it has been before). + * + * but having it this way + * enforces that it is all in this one place, where it is easier to audit, + * it makes it obvious that whatever "event" "happens" to a request should + * happen "atomically" within the req_lock, + * and it enforces that we have to think in a very structured manner + * about the "events" that may happen to a request during its life time ... + * + * Though I think it is likely that we break this again into many + * static inline void _req_mod_ ## what (req) ... + */ +void _req_mod(struct drbd_request *req, enum drbd_req_event what, int error) +{ + struct drbd_conf *mdev = req->mdev; + MUST_HOLD(&mdev->req_lock); + + if (error && (bio_rw(req->master_bio) != READA)) + ERR("got an _req_mod() errno of %d\n", error); + + print_req_mod(req, what); + + switch (what) { + default: + ERR("LOGIC BUG in %s:%u\n", __FILE__ , __LINE__ ); + return; + + /* does not happen... + * initialization done in drbd_req_new + case created: + break; + */ + + case to_be_send: /* via network */ + /* reached via drbd_make_request_common + * and from FIXME w_read_retry_remote */ + D_ASSERT(!(req->rq_state & RQ_NET_MASK)); + req->rq_state |= RQ_NET_PENDING; + inc_ap_pending(mdev); + break; + + case to_be_submitted: /* locally */ + /* reached via drbd_make_request_common */ + D_ASSERT(!(req->rq_state & RQ_LOCAL_MASK)); + req->rq_state |= RQ_LOCAL_PENDING; + break; + + /* FIXME these *_completed_* are basically the same. + * can probably be merged with some if (what == xy) */ + + case completed_ok: + if (bio_data_dir(req->private_bio) == WRITE) + mdev->writ_cnt += req->size>>9; + else + mdev->read_cnt += req->size>>9; + + bio_put(req->private_bio); + req->private_bio = NULL; + + req->rq_state |= (RQ_LOCAL_COMPLETED|RQ_LOCAL_OK); + req->rq_state &= ~RQ_LOCAL_PENDING; + + _req_may_be_done(req, error); + dec_local(mdev); + break; + + case write_completed_with_error: + req->rq_state |= RQ_LOCAL_COMPLETED; + req->rq_state &= ~RQ_LOCAL_PENDING; + + bio_put(req->private_bio); + req->private_bio = NULL; + ALERT("Local WRITE failed sec=%llus size=%u\n", + (unsigned long long)req->sector, req->size); + /* and now: check how to handle local io error. + * FIXME see comment below in read_completed_with_error */ + __drbd_chk_io_error(mdev, FALSE); + _req_may_be_done(req, error); + dec_local(mdev); + break; + + case read_completed_with_error: + if (bio_rw(req->master_bio) != READA) + drbd_set_out_of_sync(mdev, req->sector, req->size); + + req->rq_state |= RQ_LOCAL_COMPLETED; + req->rq_state &= ~RQ_LOCAL_PENDING; + + bio_put(req->private_bio); + req->private_bio = NULL; + if (bio_rw(req->master_bio) == READA) { + /* it is legal to fail READA */ + _req_may_be_done(req, error); + dec_local(mdev); + break; + } + /* else */ + ALERT("Local READ failed sec=%llus size=%u\n", + (unsigned long long)req->sector, req->size); + /* _req_mod(req,to_be_send); oops, recursion in static inline */ + D_ASSERT(!(req->rq_state & RQ_NET_MASK)); + req->rq_state |= RQ_NET_PENDING; + inc_ap_pending(mdev); + + /* and now: check how to handle local io error. + * + * FIXME we should not handle WRITE and READ io errors + * the same. When we retry the READ, and then write + * the answer, that might suceed because modern drives + * would relocate the sectors. We'd need to keep our + * private bio then, and round the offset and size so + * we get back enough data to be able to clear the bits again. + */ + __drbd_chk_io_error(mdev, FALSE); + dec_local(mdev); + /* NOTE: if we have no connection, + * or know the peer has no good data either, + * then we don't actually need to "queue_for_net_read", + * but we do so anyways, since the drbd_io_error() + * and the potential state change to "Diskless" + * needs to be done from process context */ + + /* fall through: _req_mod(req,queue_for_net_read); */ + + case queue_for_net_read: + /* READ or READA, and + * no local disk, + * or target area marked as invalid, + * or just got an io-error. */ + /* from drbd_make_request_common + * or from bio_endio during read io-error recovery */ + + /* so we can verify the handle in the answer packet + * corresponding hlist_del is in _req_may_be_done() */ + hlist_add_head(&req->colision, ar_hash_slot(mdev, req->sector)); + + set_bit(UNPLUG_REMOTE, &mdev->flags); /* why? */ + + D_ASSERT(req->rq_state & RQ_NET_PENDING); + req->rq_state |= RQ_NET_QUEUED; + req->w.cb = (req->rq_state & RQ_LOCAL_MASK) + ? w_read_retry_remote + : w_send_read_req; + drbd_queue_work(&mdev->data.work, &req->w); + break; + + case queue_for_net_write: + /* assert something? */ + /* from drbd_make_request_common only */ + + hlist_add_head(&req->colision, tl_hash_slot(mdev, req->sector)); + /* corresponding hlist_del is in _req_may_be_done() */ + + /* NOTE + * In case the req ended up on the transfer log before being + * queued on the worker, it could lead to this request being + * missed during cleanup after connection loss. + * So we have to do both operations here, + * within the same lock that protects the transfer log. + * + * _req_add_to_epoch(req); this has to be after the + * _maybe_start_new_epoch(req); which happened in + * drbd_make_request_common, because we now may set the bit + * again ourselves to close the current epoch. + * + * Add req to the (now) current epoch (barrier). */ + + /* see drbd_make_request_common, + * just after it grabs the req_lock */ + D_ASSERT(test_bit(CREATE_BARRIER, &mdev->flags) == 0); + + req->epoch = mdev->newest_barrier->br_number; + list_add_tail(&req->tl_requests, + &mdev->newest_barrier->requests); + + /* increment size of current epoch */ + mdev->newest_barrier->n_req++; + + /* queue work item to send data */ + D_ASSERT(req->rq_state & RQ_NET_PENDING); + req->rq_state |= RQ_NET_QUEUED; + req->w.cb = w_send_dblock; + drbd_queue_work(&mdev->data.work, &req->w); + + /* close the epoch, in case it outgrew the limit */ + if (mdev->newest_barrier->n_req >= mdev->net_conf->max_epoch_size) + queue_barrier(mdev); + + break; + + /* FIXME + * to implement freeze-io, + * we may not finish the request just yet. + */ + case send_canceled: + /* may be a write, may be a remote read */ + if (req->rq_state & RQ_NET_PENDING) dec_ap_pending(mdev); + req->rq_state &= ~(RQ_NET_OK|RQ_NET_PENDING); + /* fall through */ + case send_failed: + /* real cleanup will be done from tl_clear. just update flags + * so it is no longer marked as on the worker queue */ + req->rq_state &= ~RQ_NET_QUEUED; + /* if we did it right, tl_clear should be scheduled only after + * this, so this should not be necessary! */ + _req_may_be_done(req, error); + break; + + case handed_over_to_network: + /* assert something? */ + if ( bio_data_dir(req->master_bio) == WRITE && + mdev->net_conf->wire_protocol == DRBD_PROT_A ) { + /* this is what is dangerous about protocol A: + * pretend it was sucessfully written on the peer. + * FIXME in case we get a local io-error in + * protocol != C, we might want to defer comletion + * until we get the barrier ack, and send a NegAck + * in case the other node had an io-error, too... + * That way we would at least not report "success" + * if it was not written at all. */ + if (req->rq_state & RQ_NET_PENDING) { + dec_ap_pending(mdev); + req->rq_state &= ~RQ_NET_PENDING; + req->rq_state |= RQ_NET_OK; + } /* else: neg-ack was faster... */ + /* it is still not yet RQ_NET_DONE until the + * corresponding epoch barrier got acked as well, + * so we know what to dirty on connection loss */ + } + req->rq_state &= ~RQ_NET_QUEUED; + req->rq_state |= RQ_NET_SENT; + /* because _drbd_send_zc_bio could sleep, and may want to + * dereference the bio even after the "write_acked_by_peer" and + * "completed_ok" events came in, once we return from + * _drbd_send_zc_bio (drbd_send_dblock), we have to check + * whether it is done already, and end it. */ + _req_may_be_done(req, error); + break; + + case connection_lost_while_pending: + /* transfer log cleanup after connection loss */ + /* assert something? */ + if (req->rq_state & RQ_NET_PENDING) + dec_ap_pending(mdev); + req->rq_state &= ~(RQ_NET_OK|RQ_NET_PENDING); + req->rq_state |= RQ_NET_DONE; + /* if it is still queued, we may not complete it here. + * it will be canceled soon. + * FIXME we should change the code so this can not happen. */ + if (!(req->rq_state & RQ_NET_QUEUED)) + _req_may_be_done(req, error); + break; + + case write_acked_by_peer_and_sis: + req->rq_state |= RQ_NET_SIS; + case conflict_discarded_by_peer: + /* for discarded conflicting writes of multiple primarys, + * there is no need to keep anything in the tl, potential + * node crashes are covered by the activity log. */ + req->rq_state |= RQ_NET_DONE; + /* fall through */ + case write_acked_by_peer: + /* protocol C; successfully written on peer. + * Nothing to do here. + * We want to keep the tl in place for all protocols, to cater + * for volatile write-back caches on lower level devices. + * + * A barrier request is expected to have forced all prior + * requests onto stable storage, so completion of a barrier + * request could set NET_DONE right here, and not wait for the + * BarrierAck, but that is an unecessary optimisation. */ + + /* this makes it effectively the same as for: */ + case recv_acked_by_peer: + /* protocol B; pretends to be sucessfully written on peer. + * see also notes above in handed_over_to_network about + * protocol != C */ + req->rq_state |= RQ_NET_OK; + D_ASSERT(req->rq_state & RQ_NET_PENDING); + dec_ap_pending(mdev); + req->rq_state &= ~RQ_NET_PENDING; + _req_may_be_done(req, error); + break; + + case neg_acked: + /* assert something? */ + if (req->rq_state & RQ_NET_PENDING) + dec_ap_pending(mdev); + req->rq_state &= ~(RQ_NET_OK|RQ_NET_PENDING); + /* FIXME THINK! is it DONE now, or is it not? */ + req->rq_state |= RQ_NET_DONE; + _req_may_be_done(req, error); + /* else: done by handed_over_to_network */ + break; + + case barrier_acked: + if (req->rq_state & RQ_NET_PENDING) { + /* barrier came in before all requests have been acked. + * this is bad, because if the connection is lost now, + * we won't be able to clean them up... */ + _print_rq_state(req, + "FIXME (barrier_acked but pending)"); + } + D_ASSERT(req->rq_state & RQ_NET_SENT); + req->rq_state |= RQ_NET_DONE; + _req_may_be_done(req, error); + break; + + case data_received: + D_ASSERT(req->rq_state & RQ_NET_PENDING); + dec_ap_pending(mdev); + req->rq_state &= ~RQ_NET_PENDING; + req->rq_state |= (RQ_NET_OK|RQ_NET_DONE); + _req_may_be_done(req, error); + break; + }; +} + +/* we may do a local read if: + * - we are consistent (of course), + * - or we are generally inconsistent, + * BUT we are still/already IN SYNC for this area. + * since size may be bigger than BM_BLOCK_SIZE, + * we may need to check several bits. + */ +STATIC int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int size) +{ + unsigned long sbnr, ebnr; + sector_t esector, nr_sectors; + + if (mdev->state.disk == UpToDate) + return 1; + if (mdev->state.disk >= Outdated) + return 0; + if (mdev->state.disk < Inconsistent) + return 0; + /* state.disk == Inconsistent We will have a look at the BitMap */ + nr_sectors = drbd_get_capacity(mdev->this_bdev); + esector = sector + (size>>9) -1; + + D_ASSERT(sector < nr_sectors); + D_ASSERT(esector < nr_sectors); + + sbnr = BM_SECT_TO_BIT(sector); + ebnr = BM_SECT_TO_BIT(esector); + + return (0 == drbd_bm_count_bits(mdev, sbnr, ebnr)); +} + +/* + * general note: + * looking at the state (conn, disk, susp, pdsk) outside of the spinlock that + * protects the state changes is inherently racy. + * + * FIXME verify this rationale why we may do so anyways: + * + * I think it "should" be like this: + * as soon as we have a "ap_bio_cnt" reference we may test for "bad" states, + * because the transition from "bad" to "good" states may only happen while no + * application request is on the fly, so once we are positive about a "bad" + * state, we know it won't get better during the lifetime of this request. + * + * In case we think we are ok, but "asynchronously" some interrupt or other + * thread marks some operation as impossible, we are still ok, since we would + * just try anyways, and then see that it does not work there and then. + */ + +STATIC int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio) +{ + const int rw = bio_rw(bio); + const int size = bio->bi_size; + const sector_t sector = bio->bi_sector; + struct drbd_barrier *b = NULL; + struct drbd_request *req; + int local, remote; + int err = -EIO; + + /* allocate outside of all locks; get a "reference count" (ap_bio_cnt) + * to avoid races with the disconnect/reconnect code. */ + inc_ap_bio(mdev); + req = drbd_req_new(mdev, bio); + if (!req) { + dec_ap_bio(mdev); + /* only pass the error to the upper layers. + * if user cannot handle io errors, thats not our business. */ + ERR("could not kmalloc() req\n"); + bio_endio(bio, -ENOMEM); + return 0; + } + + dump_bio(mdev, bio, 0); + + local = inc_local(mdev); + if (!local) { + bio_put(req->private_bio); /* or we get a bio leak */ + req->private_bio = NULL; + } + if (rw == WRITE) { + remote = 1; + } else { + /* READ || READA */ + if (local) { + if (!drbd_may_do_local_read(mdev, sector, size)) { + /* we could kick the syncer to + * sync this extent asap, wait for + * it, then continue locally. + * Or just issue the request remotely. + */ + /* FIXME + * I think we have a RACE here. We request + * something from the peer, then later some + * write starts ... and finished *before* + * the answer to the read comes in, because + * the ACK for the WRITE goes over + * meta-socket ... + * Maybe we need to properly lock reads + * against the syncer, too. But if we have + * some user issuing writes on an area that + * he has pending reads on, _he_ is really + * broke anyways, and would get "undefined + * results" on _any_ io stack, even just the + * local io stack. + */ + + local = 0; + bio_put(req->private_bio); + req->private_bio = NULL; + dec_local(mdev); + } + } + remote = !local && mdev->state.pdsk >= UpToDate; + } + + /* If we have a disk, but a READA request is mapped to remote, + * we are Primary, Inconsistent, SyncTarget. + * Just fail that READA request right here. + * + * THINK: maybe fail all READA when not local? + * or make this configurable... + * if network is slow, READA won't do any good. + */ + if (rw == READA && mdev->state.disk >= Inconsistent && !local) { + err = -EWOULDBLOCK; + goto fail_and_free_req; + } + + /* For WRITES going to the local disk, grab a reference on the target + * extent. This waits for any resync activity in the corresponding + * resync extent to finish, and, if necessary, pulls in the target + * extent into the activity log, which involves further disk io because + * of transactional on-disk meta data updates. */ + if (rw == WRITE && local) + drbd_al_begin_io(mdev, sector); + + remote = remote && (mdev->state.pdsk == UpToDate || + ( mdev->state.pdsk == Inconsistent && + mdev->state.conn >= Connected ) ); + + if (!(local || remote)) { + ERR("IO ERROR: neither local nor remote disk\n"); + goto fail_and_free_req; + } + + /* For WRITE request, we have to make sure that we have an + * unused_spare_barrier, in case we need to start a new epoch. + * I try to be smart and avoid to pre-allocate always "just in case", + * but there is a race between testing the bit and pointer outside the + * spinlock, and grabbing the spinlock. + * if we lost that race, we retry. */ + if (rw == WRITE && remote && + mdev->unused_spare_barrier == NULL && + test_bit(CREATE_BARRIER, &mdev->flags)) { +allocate_barrier: + b = kmalloc(sizeof(struct drbd_barrier), GFP_NOIO); + if (!b) { + ERR("Failed to alloc barrier.\n"); + err = -ENOMEM; + goto fail_and_free_req; + } + } + + /* GOOD, everything prepared, grab the spin_lock */ + spin_lock_irq(&mdev->req_lock); + + /* FIXME race with drbd_disconnect and tl_clear? */ + if (remote) { + remote = (mdev->state.pdsk == UpToDate || + ( mdev->state.pdsk == Inconsistent && + mdev->state.conn >= Connected ) ); + if (!remote) + DRBD_WARN("lost connection while grabbing the req_lock!\n"); + if (!(local || remote)) { + ERR("IO ERROR: neither local nor remote disk\n"); + spin_unlock_irq(&mdev->req_lock); + goto fail_and_free_req; + } + } + + if (b && mdev->unused_spare_barrier == NULL) { + mdev->unused_spare_barrier = b; + b = NULL; + } + if (rw == WRITE && remote && + mdev->unused_spare_barrier == NULL && + test_bit(CREATE_BARRIER, &mdev->flags)) { + /* someone closed the current epoch + * while we were grabbing the spinlock */ + spin_unlock_irq(&mdev->req_lock); + goto allocate_barrier; + } + + + /* Update disk stats */ + _drbd_start_io_acct(mdev, req, bio); + + /* _maybe_start_new_epoch(mdev); + * If we need to generate a write barrier packet, we have to add the + * new epoch (barrier) object, and queue the barrier packet for sending, + * and queue the req's data after it _within the same lock_, otherwise + * we have race conditions were the reorder domains could be mixed up. + * + * Even read requests may start a new epoch and queue the corresponding + * barrier packet. To get the write ordering right, we only have to + * make sure that, if this is a write request and it triggered a + * barrier packet, this request is queued within the same spinlock. */ + if (remote && mdev->unused_spare_barrier && + test_and_clear_bit(CREATE_BARRIER, &mdev->flags)) { + _tl_add_barrier(mdev, mdev->unused_spare_barrier); + mdev->unused_spare_barrier = NULL; + } else { + D_ASSERT(!(remote && rw == WRITE && + test_bit(CREATE_BARRIER, &mdev->flags))); + } + + /* NOTE + * Actually, 'local' may be wrong here already, since we may have failed + * to write to the meta data, and may become wrong anytime because of + * local io-error for some other request, which would lead to us + * "detaching" the local disk. + * + * 'remote' may become wrong any time because the network could fail. + * + * This is a harmless race condition, though, since it is handled + * correctly at the appropriate places; so it just deferres the failure + * of the respective operation. + */ + + /* mark them early for readability. + * this just sets some state flags. */ + if (remote) + _req_mod(req, to_be_send, 0); + if (local) + _req_mod(req, to_be_submitted, 0); + + /* check this request on the colison detection hash tables. + * if we have a conflict, just complete it here. + * THINK do we want to check reads, too? (I don't think so...) */ + if (rw == WRITE && _req_conflicts(req)) { + /* this is a conflicting request. + * even though it may have been only _partially_ + * overlapping with one of the currently pending requests, + * without even submitting or sending it, we will + * pretend that it was successfully served right now. + */ + if (local) { + bio_put(req->private_bio); + req->private_bio = NULL; + drbd_al_complete_io(mdev, req->sector); + dec_local(mdev); + local = 0; + } + if (remote) + dec_ap_pending(mdev); + _drbd_end_io_acct(mdev, req); + /* THINK: do we want to fail it (-EIO), or pretend success? */ + bio_endio(req->master_bio, 0); + req->master_bio = NULL; + dec_ap_bio(mdev); + drbd_req_free(req); + remote = 0; + } + + /* NOTE remote first: to get the concurrent write detection right, + * we must register the request before start of local IO. */ + if (remote) { + /* either WRITE and Connected, + * or READ, and no local disk, + * or READ, but not in sync. + */ + if (rw == WRITE) + _req_mod(req, queue_for_net_write, 0); + else + _req_mod(req, queue_for_net_read, 0); + } + spin_unlock_irq(&mdev->req_lock); + kfree(b); /* if someone else has beaten us to it... */ + + if (local) { + req->private_bio->bi_bdev = mdev->bc->backing_bdev; + + dump_internal_bio("Pri", mdev, req->private_bio, 0); + + if (FAULT_ACTIVE(mdev, rw==WRITE ? DRBD_FAULT_DT_WR : + (rw==READ ? DRBD_FAULT_DT_RD : + DRBD_FAULT_DT_RA) )) + bio_endio(req->private_bio, -EIO); + else + generic_make_request(req->private_bio); + } + + /* we need to plug ALWAYS since we possibly need to kick lo_dev. + * we plug after submit, so we won't miss an unplug event */ + drbd_plug_device(mdev); + + return 0; + +fail_and_free_req: + kfree(b); + bio_endio(bio, err); + drbd_req_free(req); + return 0; +} + +/* helper function for drbd_make_request + * if we can determine just by the mdev (state) that this request will fail, + * return 1 + * otherwise return 0 + */ +static int drbd_fail_request_early(struct drbd_conf *mdev, int is_write) +{ + /* Unconfigured */ + if (mdev->state.conn == Disconnecting && + mdev->state.disk == Diskless) + return 1; + + if (mdev->state.role != Primary && + ( !allow_oos || is_write) ) { + if (DRBD_ratelimit(5*HZ, 5)) { + ERR("Process %s[%u] tried to %s; " + "since we are not in Primary state, " + "we cannot allow this\n", + current->comm, current->pid, + is_write ? "WRITE" : "READ"); + } + return 1; + } + + /* + * Paranoia: we might have been primary, but sync target, or + * even diskless, then lost the connection. + * This should have been handled (panic? suspend?) somehwere + * else. But maybe it was not, so check again here. + * Caution: as long as we do not have a read/write lock on mdev, + * to serialize state changes, this is racy, since we may lose + * the connection *after* we test for the cstate. + */ + if ( mdev->state.disk < UpToDate && + mdev->state.conn < Connected) { + if (DRBD_ratelimit(5*HZ, 5)) + ERR("Sorry, I have no access to good data anymore.\n"); + /* + * FIXME suspend, loop waiting on cstate wait? + */ + return 1; + } + + return 0; +} + +int drbd_make_request_26(struct request_queue *q, struct bio *bio) +{ + unsigned int s_enr, e_enr; + struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata; + + if (drbd_fail_request_early(mdev, bio_data_dir(bio) & WRITE)) { + bio_endio(bio, -EPERM); + return 0; + } + + /* Reject barrier requests if we know the underlying device does + * not support them. + * XXX: Need to get this info from peer as well some how so we + * XXX: reject if EITHER side/data/metadata area does not support them. + * + * because of those XXX, this is not yet enabled, + * i.e. in drbd_init_set_defaults we set the NO_BARRIER_SUPP bit. + */ + if (unlikely(bio_barrier(bio) && test_bit(NO_BARRIER_SUPP, &mdev->flags))) { + /* DRBD_WARN("Rejecting barrier request as underlying device does not support\n"); */ + bio_endio(bio, -EOPNOTSUPP); + return 0; + } + + /* + * what we "blindly" assume: + */ + D_ASSERT(bio->bi_size > 0); + D_ASSERT( (bio->bi_size & 0x1ff) == 0); + D_ASSERT(bio->bi_idx == 0); + + /* to make some things easier, force allignment of requests within the + * granularity of our hash tables */ + s_enr = bio->bi_sector >> HT_SHIFT; + e_enr = (bio->bi_sector+(bio->bi_size>>9)-1) >> HT_SHIFT; + + if (unlikely(s_enr != e_enr)) { + if (bio->bi_vcnt != 1 || bio->bi_idx != 0) { + /* rather error out here than BUG in bio_split */ + ERR("bio would need to, but cannot, be split: " + "(vcnt=%u,idx=%u,size=%u,sector=%llu)\n", + bio->bi_vcnt, bio->bi_idx, bio->bi_size, + (unsigned long long)bio->bi_sector); + bio_endio(bio, -EINVAL); + return 0; + } else { + /* This bio crosses some boundary, so we have to split it. */ + struct bio_pair *bp; + /* works for the "do not cross hash slot boundaries" case + * e.g. sector 262269, size 4096 + * s_enr = 262269 >> 6 = 4097 + * e_enr = (262269+8-1) >> 6 = 4098 + * HT_SHIFT = 6 + * sps = 64, mask = 63 + * first_sectors = 64 - (262269 & 63) = 3 + */ + const sector_t sect = bio->bi_sector; + const int sps = 1<bio1); + drbd_make_request_26(q, &bp->bio2); + bio_pair_release(bp); + return 0; + } + } + + return drbd_make_request_common(mdev,bio); +} + +/* This is called by bio_add_page(). With this function we reduce + * the number of BIOs that span over multiple DRBD_MAX_SEGMENT_SIZEs + * units (was AL_EXTENTs). + * + * we do the calculation within the lower 32bit of the byte offsets, + * since we don't care for actual offset, but only check whether it + * would cross "activity log extent" boundaries. + * + * As long as the BIO is emtpy we have to allow at least one bvec, + * regardless of size and offset. so the resulting bio may still + * cross extent boundaries. those are dealt with (bio_split) in + * drbd_make_request_26. + */ +int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec) +{ + struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata; + unsigned int bio_offset = + (unsigned int)bvm->bi_sector << 9; /* 32 bit */ + unsigned int bio_size = bvm->bi_size; + int limit, backing_limit; + + limit = DRBD_MAX_SEGMENT_SIZE + - ((bio_offset & (DRBD_MAX_SEGMENT_SIZE-1)) + bio_size); + if (limit < 0) + limit = 0; + if (bio_size == 0) { + if (limit <= bvec->bv_len) + limit = bvec->bv_len; + } else if (limit && inc_local(mdev)) { + struct request_queue * const b = + mdev->bc->backing_bdev->bd_disk->queue; + if (b->merge_bvec_fn && mdev->bc->dc.use_bmbv) { + backing_limit = b->merge_bvec_fn(b, bvm, bvec); + limit = min(limit, backing_limit); + } + dec_local(mdev); + } + return limit; +} --- linux-2.6.27.orig/ubuntu/drbd/Makefile +++ linux-2.6.27/ubuntu/drbd/Makefile @@ -0,0 +1,7 @@ +drbd-objs := drbd_buildtag.o drbd_bitmap.o drbd_proc.o \ + drbd_worker.o drbd_receiver.o drbd_req.o drbd_actlog.o \ + lru_cache.o drbd_main.o drbd_strings.o drbd_nl.o + +EXTRA_CFLAGS += -I$(src) + +obj-$(CONFIG_BLK_DEV_DRBD) += drbd.o --- linux-2.6.27.orig/ubuntu/drbd/drbd_actlog.c +++ linux-2.6.27/ubuntu/drbd/drbd_actlog.c @@ -0,0 +1,1510 @@ +/* +-*- linux-c -*- + drbd_actlog.c + Kernel module for 2.6.x Kernels + + This file is part of DRBD by Philipp Reisner and Lars Ellenberg. + + Copyright (C) 2003-2008, LINBIT Information Technologies GmbH. + Copyright (C) 2003-2008, Philipp Reisner . + Copyright (C) 2003-2008, Lars Ellenberg . + + drbd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + drbd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with drbd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#include +#include +#include "drbd_int.h" + +/* This is what I like so much about the linux kernel: + * if you have a close look, you can almost always reuse code by someone else + * ;) + * this is mostly from drivers/md/md.c + */ +STATIC int _drbd_md_sync_page_io(struct drbd_conf *mdev, + struct drbd_backing_dev *bdev, + struct page *page, sector_t sector, + int rw, int size) +{ + struct bio *bio; + struct drbd_md_io md_io; + int ok; + + md_io.mdev = mdev; + init_completion(&md_io.event); + md_io.error = 0; + + if (rw == WRITE && !test_bit(MD_NO_BARRIER, &mdev->flags)) + rw |= (1<bi_bdev = bdev->md_bdev; + bio->bi_sector = sector; + ok = (bio_add_page(bio, page, size, 0) == size); + if (!ok) + goto out; + bio->bi_private = &md_io; + bio->bi_end_io = drbd_md_io_complete; + bio->bi_rw = rw; + + dump_internal_bio("Md", mdev, bio, 0); + + if (FAULT_ACTIVE(mdev, (rw & WRITE)? DRBD_FAULT_MD_WR:DRBD_FAULT_MD_RD)) + bio_endio(bio, -EIO); + else + submit_bio(rw, bio); + wait_for_completion(&md_io.event); + ok = bio_flagged(bio, BIO_UPTODATE); + + /* check for unsupported barrier op */ + if (unlikely(md_io.error == -EOPNOTSUPP && bio_barrier(bio))) { + /* Try again with no barrier */ + DRBD_WARN("Barriers not supported on meta data device - disabling\n"); + set_bit(MD_NO_BARRIER,&mdev->flags); + rw &= ~(1 << BIO_RW_BARRIER); + bio_put(bio); + goto retry; + } + out: + bio_put(bio); + return ok; +} + +int drbd_md_sync_page_io(struct drbd_conf *mdev, struct drbd_backing_dev *bdev, + sector_t sector, int rw) +{ + int hardsect, mask, ok; + int offset = 0; + struct page *iop = mdev->md_io_page; + + D_ASSERT(semaphore_is_locked(&mdev->md_io_mutex)); + + if (!bdev->md_bdev) { + if (DRBD_ratelimit(5*HZ, 5)) { + ERR("bdev->md_bdev==NULL\n"); + dump_stack(); + } + return 0; + } + + hardsect = drbd_get_hardsect(bdev->md_bdev); + if (hardsect == 0) + hardsect = MD_HARDSECT; + + /* in case hardsect != 512 [ s390 only? ] */ + if (hardsect != MD_HARDSECT) { + if (!mdev->md_io_tmpp) { + struct page *page = alloc_page(GFP_NOIO); + if (!page) + return 0; + + DRBD_WARN("Meta data's bdev hardsect = %d != %d\n", + hardsect, MD_HARDSECT); + DRBD_WARN("Workaround engaged (has performace impact).\n"); + + mdev->md_io_tmpp = page; + } + + mask = ( hardsect / MD_HARDSECT ) - 1; + D_ASSERT( mask == 1 || mask == 3 || mask == 7 ); + D_ASSERT( hardsect == (mask+1) * MD_HARDSECT ); + offset = sector & mask; + sector = sector & ~mask; + iop = mdev->md_io_tmpp; + + if (rw == WRITE) { + void *p = page_address(mdev->md_io_page); + void *hp = page_address(mdev->md_io_tmpp); + + ok = _drbd_md_sync_page_io(mdev, bdev, iop, + sector, READ, hardsect); + + if (unlikely(!ok)) { + ERR("drbd_md_sync_page_io(,%llus," + "READ [hardsect!=512]) failed!\n", + (unsigned long long)sector); + return 0; + } + + memcpy(hp + offset*MD_HARDSECT , p, MD_HARDSECT); + } + } + +#if DUMP_MD >= 3 + INFO("%s [%d]:%s(,%llus,%s)\n", + current->comm, current->pid, __func__, + (unsigned long long)sector, rw ? "WRITE" : "READ"); +#endif + + if (sector < drbd_md_first_sector(bdev) || + sector > drbd_md_last_sector(bdev)) + ALERT("%s [%d]:%s(,%llus,%s) out of range md access!\n", + current->comm, current->pid, __func__, + (unsigned long long)sector, rw ? "WRITE" : "READ"); + + ok = _drbd_md_sync_page_io(mdev, bdev, iop, sector, rw, hardsect); + if (unlikely(!ok)) { + ERR("drbd_md_sync_page_io(,%llus,%s) failed!\n", + (unsigned long long)sector, rw ? "WRITE" : "READ"); + return 0; + } + + if (hardsect != MD_HARDSECT && rw == READ) { + void *p = page_address(mdev->md_io_page); + void *hp = page_address(mdev->md_io_tmpp); + + memcpy(p, hp + offset*MD_HARDSECT, MD_HARDSECT); + } + + return ok; +} + +/* I do not believe that all storage medias can guarantee atomic + * 512 byte write operations. When the journal is read, only + * transactions with correct xor_sums are considered. + * sizeof() = 512 byte */ +struct __attribute__((packed)) al_transaction { + u32 magic; + u32 tr_number; + /* u32 tr_generation; TODO */ + struct __attribute__((packed)) { + u32 pos; + u32 extent; } updates[1 + AL_EXTENTS_PT]; + u32 xor_sum; +}; + +struct update_odbm_work { + struct drbd_work w; + unsigned int enr; +}; + +struct update_al_work { + struct drbd_work w; + struct lc_element *al_ext; + struct completion event; + unsigned int enr; + /* if old_enr != LC_FREE, write corresponding bitmap sector, too */ + unsigned int old_enr; +}; + +int w_al_write_transaction(struct drbd_conf *, struct drbd_work *, int); + +static inline +struct lc_element *_al_get(struct drbd_conf *mdev, unsigned int enr) +{ + struct lc_element *al_ext; + struct bm_extent *bm_ext; + unsigned long al_flags = 0; + + spin_lock_irq(&mdev->al_lock); + bm_ext = (struct bm_extent *) + lc_find(mdev->resync, enr/AL_EXT_PER_BM_SECT); + if (unlikely(bm_ext != NULL)) { + if (test_bit(BME_NO_WRITES, &bm_ext->flags)) { + spin_unlock_irq(&mdev->al_lock); + return NULL; + } + } + al_ext = lc_get(mdev->act_log, enr); + al_flags = mdev->act_log->flags; + spin_unlock_irq(&mdev->al_lock); + + /* + if (!al_ext) { + if (al_flags & LC_STARVING) + DRBD_WARN("Have to wait for LRU element (AL too small?)\n"); + if (al_flags & LC_DIRTY) + DRBD_WARN("Ongoing AL update (AL device too slow?)\n"); + } + */ + + return al_ext; +} + +/* FIXME + * this should be able to return failure when meta data update has failed. + */ +void drbd_al_begin_io(struct drbd_conf *mdev, sector_t sector) +{ + unsigned int enr = (sector >> (AL_EXTENT_SIZE_B-9)); + struct lc_element *al_ext; + struct update_al_work al_work; + + D_ASSERT(atomic_read(&mdev->local_cnt) > 0); + + MTRACE(TraceTypeALExts, TraceLvlMetrics, + INFO("al_begin_io( sec=%llus (al_enr=%u) (rs_enr=%d) )\n", + (unsigned long long) sector, enr, + (int)BM_SECT_TO_EXT(sector)); + ); + + wait_event(mdev->al_wait, (al_ext = _al_get(mdev, enr)) ); + + if (al_ext->lc_number != enr) { + /* drbd_al_write_transaction(mdev,al_ext,enr); + generic_make_request() are serialized on the + current->bio_tail list now. Therefore we have + to deligate writing something to AL to the + worker thread. */ + init_completion(&al_work.event); + al_work.al_ext = al_ext; + al_work.enr = enr; + al_work.old_enr = al_ext->lc_number; + al_work.w.cb = w_al_write_transaction; + drbd_queue_work_front(&mdev->data.work, &al_work.w); + wait_for_completion(&al_work.event); + + mdev->al_writ_cnt++; + + /* + DUMPI(al_ext->lc_number); + DUMPI(mdev->act_log->new_number); + */ + spin_lock_irq(&mdev->al_lock); + lc_changed(mdev->act_log, al_ext); + spin_unlock_irq(&mdev->al_lock); + wake_up(&mdev->al_wait); + } +} + +void drbd_al_complete_io(struct drbd_conf *mdev, sector_t sector) +{ + unsigned int enr = (sector >> (AL_EXTENT_SIZE_B-9)); + struct lc_element *extent; + unsigned long flags; + + MTRACE(TraceTypeALExts, TraceLvlMetrics, + INFO("al_complete_io( sec=%llus (al_enr=%u) (rs_enr=%d) )\n", + (unsigned long long) sector, enr, + (int)BM_SECT_TO_EXT(sector)); + ); + + spin_lock_irqsave(&mdev->al_lock, flags); + + extent = lc_find(mdev->act_log, enr); + + if (!extent) { + spin_unlock_irqrestore(&mdev->al_lock, flags); + ERR("al_complete_io() called on inactive extent %u\n", enr); + return; + } + + if (lc_put(mdev->act_log, extent) == 0) + wake_up(&mdev->al_wait); + + spin_unlock_irqrestore(&mdev->al_lock, flags); +} + +int +w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused) +{ + struct update_al_work *aw = (struct update_al_work*)w; + struct lc_element *updated = aw->al_ext; + const unsigned int new_enr = aw->enr; + const unsigned int evicted = aw->old_enr; + + struct al_transaction* buffer; + sector_t sector; + int i,n,mx; + unsigned int extent_nr; + u32 xor_sum=0; + + if (!inc_local(mdev)) { + ERR("inc_local() failed in w_al_write_transaction\n"); + complete(&((struct update_al_work*)w)->event); + return 1; + } + /* do we have to do a bitmap write, first? + * TODO reduce maximum latency: + * submit both bios, then wait for both, + * instead of doing two synchronous sector writes. */ + if (mdev->state.conn < Connected && evicted != LC_FREE) + drbd_bm_write_sect(mdev, evicted/AL_EXT_PER_BM_SECT); + + down(&mdev->md_io_mutex); /* protects md_io_buffer, al_tr_cycle, ... */ + buffer = (struct al_transaction *)page_address(mdev->md_io_page); + + buffer->magic = __constant_cpu_to_be32(DRBD_MAGIC); + buffer->tr_number = cpu_to_be32(mdev->al_tr_number); + + n = lc_index_of(mdev->act_log, updated); + + buffer->updates[0].pos = cpu_to_be32(n); + buffer->updates[0].extent = cpu_to_be32(new_enr); + + xor_sum ^= new_enr; + + mx = min_t(int, AL_EXTENTS_PT, + mdev->act_log->nr_elements - mdev->al_tr_cycle); + for (i = 0; i < mx; i++) { + extent_nr = lc_entry(mdev->act_log, + mdev->al_tr_cycle+i)->lc_number; + buffer->updates[i+1].pos = cpu_to_be32(mdev->al_tr_cycle+i); + buffer->updates[i+1].extent = cpu_to_be32(extent_nr); + xor_sum ^= extent_nr; + } + for (; i < AL_EXTENTS_PT; i++) { + buffer->updates[i+1].pos = __constant_cpu_to_be32(-1); + buffer->updates[i+1].extent = __constant_cpu_to_be32(LC_FREE); + xor_sum ^= LC_FREE; + } + mdev->al_tr_cycle += AL_EXTENTS_PT; + if (mdev->al_tr_cycle >= mdev->act_log->nr_elements) + mdev->al_tr_cycle = 0; + + buffer->xor_sum = cpu_to_be32(xor_sum); + + sector = mdev->bc->md.md_offset + + mdev->bc->md.al_offset + mdev->al_tr_pos; + + if (!drbd_md_sync_page_io(mdev, mdev->bc, sector, WRITE)) { + drbd_chk_io_error(mdev, 1, TRUE); + drbd_io_error(mdev, TRUE); + } + + if (++mdev->al_tr_pos > + div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT)) + mdev->al_tr_pos = 0; + + D_ASSERT(mdev->al_tr_pos < MD_AL_MAX_SIZE); + mdev->al_tr_number++; + + up(&mdev->md_io_mutex); + + complete(&((struct update_al_work *)w)->event); + dec_local(mdev); + + return 1; +} + +/** + * drbd_al_read_tr: Reads a single transaction record form the + * on disk activity log. + * Returns -1 on IO error, 0 on checksum error and 1 if it is a valid + * record. + */ +STATIC int drbd_al_read_tr(struct drbd_conf *mdev, + struct drbd_backing_dev *bdev, + struct al_transaction *b, + int index) +{ + sector_t sector; + int rv, i; + u32 xor_sum = 0; + + sector = bdev->md.md_offset + bdev->md.al_offset + index; + + /* Dont process error normally, + * as this is done before disk is atached! */ + if (!drbd_md_sync_page_io(mdev, bdev, sector, READ)) + return -1; + + rv = ( be32_to_cpu(b->magic) == DRBD_MAGIC ); + + for (i = 0; i < AL_EXTENTS_PT+1; i++) + xor_sum ^= be32_to_cpu(b->updates[i].extent); + rv &= (xor_sum == be32_to_cpu(b->xor_sum)); + + return rv; +} + +/** + * drbd_al_read_log: Restores the activity log from its on disk + * representation. Returns 1 on success, returns 0 when + * reading the log failed due to IO errors. + */ +int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) +{ + struct al_transaction *buffer; + int i; + int rv; + int mx; + int cnr; + int active_extents = 0; + int transactions = 0; + int overflow = 0; + int from = -1; + int to = -1; + u32 from_tnr = -1; + u32 to_tnr = 0; + + mx = div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT); + + /* lock out all other meta data io for now, + * and make sure the page is mapped. + */ + down(&mdev->md_io_mutex); + buffer = page_address(mdev->md_io_page); + + /* Find the valid transaction in the log */ + for (i = 0; i <= mx; i++) { + rv = drbd_al_read_tr(mdev, bdev, buffer, i); + if (rv == 0) + continue; + if (rv == -1) { + up(&mdev->md_io_mutex); + return 0; + } + cnr = be32_to_cpu(buffer->tr_number); + /* INFO("index %d valid tnr=%d\n",i,cnr); */ + + if (cnr == -1) + overflow = 1; + + if (cnr < from_tnr && !overflow) { + from = i; + from_tnr = cnr; + } + if (cnr > to_tnr) { + to = i; + to_tnr = cnr; + } + } + + if (from == -1 || to == -1) { + DRBD_WARN("No usable activity log found.\n"); + + up(&mdev->md_io_mutex); + return 1; + } + + /* Read the valid transactions. + * INFO("Reading from %d to %d.\n",from,to); */ + i = from; + while (1) { + int j, pos; + unsigned int extent_nr; + unsigned int trn; + + rv = drbd_al_read_tr(mdev, bdev, buffer, i); + ERR_IF(rv == 0) goto cancel; + if (rv == -1) { + up(&mdev->md_io_mutex); + return 0; + } + + trn = be32_to_cpu(buffer->tr_number); + + spin_lock_irq(&mdev->al_lock); + + /* This loop runs backwards because in the cyclic + elements there might be an old version of the + updated element (in slot 0). So the element in slot 0 + can overwrite old versions. */ + for (j = AL_EXTENTS_PT; j >= 0; j--) { + pos = be32_to_cpu(buffer->updates[j].pos); + extent_nr = be32_to_cpu(buffer->updates[j].extent); + + if (extent_nr == LC_FREE) + continue; + + lc_set(mdev->act_log, extent_nr, pos); + active_extents++; + } + spin_unlock_irq(&mdev->al_lock); + + transactions++; + +cancel: + if (i == to) + break; + i++; + if (i > mx) + i = 0; + } + + mdev->al_tr_number = to_tnr+1; + mdev->al_tr_pos = to; + if (++mdev->al_tr_pos > + div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT)) + mdev->al_tr_pos = 0; + + /* ok, we are done with it */ + up(&mdev->md_io_mutex); + + INFO("Found %d transactions (%d active extents) in activity log.\n", + transactions, active_extents); + + return 1; +} + +struct drbd_atodb_wait { + atomic_t count; + struct completion io_done; + struct drbd_conf *mdev; + int error; +}; + +STATIC BIO_ENDIO_TYPE atodb_endio BIO_ENDIO_ARGS(struct bio *bio, int error) +{ + struct drbd_atodb_wait *wc = bio->bi_private; + struct drbd_conf *mdev = wc->mdev; + struct page *page; + int uptodate = bio_flagged(bio, BIO_UPTODATE); + + BIO_ENDIO_FN_START; + /* strange behaviour of some lower level drivers... + * fail the request by clearing the uptodate flag, + * but do not return any error?! + * do we want to DRBD_WARN() on this? */ + if (!error && !uptodate) + error = -EIO; + + /* corresponding drbd_io_error is in drbd_al_to_on_disk_bm */ + drbd_chk_io_error(mdev, error, TRUE); + if (error && wc->error == 0) + wc->error = error; + + if (atomic_dec_and_test(&wc->count)) + complete(&wc->io_done); + + page = bio->bi_io_vec[0].bv_page; + put_page(page); + bio_put(bio); + mdev->bm_writ_cnt++; + dec_local(mdev); + + BIO_ENDIO_FN_RETURN; +} + +#define S2W(s) ((s)<<(BM_EXT_SIZE_B-BM_BLOCK_SIZE_B-LN2_BPL)) +/* activity log to on disk bitmap -- prepare bio unless that sector + * is already covered by previously prepared bios */ +STATIC int atodb_prepare_unless_covered(struct drbd_conf *mdev, + struct bio **bios, + unsigned int enr, + struct drbd_atodb_wait *wc) __must_hold(local) +{ + struct bio *bio; + struct page *page; + sector_t on_disk_sector = enr + mdev->bc->md.md_offset + + mdev->bc->md.bm_offset; + unsigned int page_offset = PAGE_SIZE; + int offset; + int i = 0; + int err = -ENOMEM; + + /* Check if that enr is already covered by an already created bio. + * Caution, bios[] is not NULL terminated, + * but only initialized to all NULL. + * For completely scattered activity log, + * the last invocation iterates over all bios, + * and finds the last NULL entry. + */ + while ( (bio = bios[i]) ) { + if (bio->bi_sector == on_disk_sector) + return 0; + i++; + } + /* bios[i] == NULL, the next not yet used slot */ + + bio = bio_alloc(GFP_KERNEL, 1); + if (bio == NULL) + return -ENOMEM; + + if (i > 0) { + const struct bio_vec *prev_bv = bios[i-1]->bi_io_vec; + page_offset = prev_bv->bv_offset + prev_bv->bv_len; + page = prev_bv->bv_page; + } + if (page_offset == PAGE_SIZE) { + page = alloc_page(__GFP_HIGHMEM); + if (page == NULL) + goto out_bio_put; + page_offset = 0; + } else { + get_page(page); + } + + offset = S2W(enr); + drbd_bm_get_lel( mdev, offset, + min_t(size_t, S2W(1), drbd_bm_words(mdev) - offset), + kmap(page) + page_offset ); + kunmap(page); + + bio->bi_private = wc; + bio->bi_end_io = atodb_endio; + bio->bi_bdev = mdev->bc->md_bdev; + bio->bi_sector = on_disk_sector; + + if (bio_add_page(bio, page, MD_HARDSECT, page_offset) != MD_HARDSECT) + goto out_put_page; + + atomic_inc(&wc->count); + /* we already know that we may do this... + * inc_local_if_state(mdev,Attaching); + * just get the extra reference, so that the local_cnt reflects + * the number of pending IO requests DRBD at its backing device. + */ + atomic_inc(&mdev->local_cnt); + + bios[i] = bio; + + return 0; + +out_put_page: + err = -EINVAL; + put_page(page); +out_bio_put: + bio_put(bio); + return err; +} + +/** + * drbd_al_to_on_disk_bm: + * Writes the areas of the bitmap which are covered by the AL. + * called when we detach (unconfigure) local storage, + * or when we go from Primary to Secondary state. + */ +void drbd_al_to_on_disk_bm(struct drbd_conf *mdev) +{ + int i, nr_elements; + unsigned int enr; + struct bio **bios; + struct drbd_atodb_wait wc; + + ERR_IF (!inc_local_if_state(mdev, Attaching)) + return; /* sorry, I don't have any act_log etc... */ + + wait_event(mdev->al_wait, lc_try_lock(mdev->act_log)); + + nr_elements = mdev->act_log->nr_elements; + + bios = kzalloc(sizeof(struct bio *) * nr_elements, GFP_KERNEL); + if (!bios) + goto submit_one_by_one; + + atomic_set(&wc.count, 0); + init_completion(&wc.io_done); + wc.mdev = mdev; + wc.error = 0; + + for (i = 0; i < nr_elements; i++) { + enr = lc_entry(mdev->act_log, i)->lc_number; + if (enr == LC_FREE) + continue; + /* next statement also does atomic_inc wc.count and local_cnt */ + if (atodb_prepare_unless_covered(mdev, bios, + enr/AL_EXT_PER_BM_SECT, + &wc)) + goto free_bios_submit_one_by_one; + } + + /* unneccessary optimization? */ + lc_unlock(mdev->act_log); + wake_up(&mdev->al_wait); + + /* all prepared, submit them */ + for (i = 0; i < nr_elements; i++) { + if (bios[i] == NULL) + break; + if (FAULT_ACTIVE( mdev, DRBD_FAULT_MD_WR )) { + bios[i]->bi_rw = WRITE; + bio_endio(bios[i], -EIO); + } else { + submit_bio(WRITE, bios[i]); + } + } + + drbd_blk_run_queue(bdev_get_queue(mdev->bc->md_bdev)); + + /* In case we did not submit a single IO do not wait for + * them to complete. ( Because we would wait forever here. ) + * + * In case we had IOs and they are already complete, there + * is not point in waiting anyways. + * Therefore this if () ... */ + if (atomic_read(&wc.count)) { + wait_for_completion(&wc.io_done); + /* flush bitmap to stable storage */ + if (!test_bit(MD_NO_BARRIER, &mdev->flags)) + blkdev_issue_flush(mdev->bc->md_bdev, NULL); + } + + dec_local(mdev); + + if (wc.error) + drbd_io_error(mdev, TRUE); + kfree(bios); + return; + + free_bios_submit_one_by_one: + /* free everything by calling the endio callback directly. */ + for (i = 0; i < nr_elements && bios[i]; i++) + bio_endio(bios[i], 0); + + kfree(bios); + + submit_one_by_one: + DRBD_WARN("Using the slow drbd_al_to_on_disk_bm()\n"); + + for (i = 0; i < mdev->act_log->nr_elements; i++) { + enr = lc_entry(mdev->act_log, i)->lc_number; + if (enr == LC_FREE) + continue; + /* Really slow: if we have al-extents 16..19 active, + * sector 4 will be written four times! Synchronous! */ + drbd_bm_write_sect(mdev, enr/AL_EXT_PER_BM_SECT ); + } + + lc_unlock(mdev->act_log); + wake_up(&mdev->al_wait); + dec_local(mdev); +} + +/** + * drbd_al_apply_to_bm: Sets the bits in the bitmap that are described + * by the active extents of the AL. + */ +void drbd_al_apply_to_bm(struct drbd_conf *mdev) +{ + unsigned int enr; + unsigned long add = 0; + char ppb[10]; + int i; + + wait_event(mdev->al_wait, lc_try_lock(mdev->act_log)); + + for (i = 0; i < mdev->act_log->nr_elements; i++) { + enr = lc_entry(mdev->act_log, i)->lc_number; + if (enr == LC_FREE) + continue; + add += drbd_bm_ALe_set_all(mdev, enr); + } + + lc_unlock(mdev->act_log); + wake_up(&mdev->al_wait); + + INFO("Marked additional %s as out-of-sync based on AL.\n", + ppsize(ppb, Bit2KB(add))); +} + +static inline int _try_lc_del(struct drbd_conf *mdev, struct lc_element *al_ext) +{ + int rv; + + spin_lock_irq(&mdev->al_lock); + rv = (al_ext->refcnt == 0); + if (likely(rv)) lc_del(mdev->act_log, al_ext); + spin_unlock_irq(&mdev->al_lock); + + MTRACE(TraceTypeALExts,TraceLvlMetrics, + if(unlikely(!rv)) + INFO("Waiting for extent in drbd_al_shrink()\n"); + ); + + return rv; +} + +/** + * drbd_al_shrink: Removes all active extents form the AL. (but does not + * write any transactions) + * You need to lock mdev->act_log with lc_try_lock() / lc_unlock() + */ +void drbd_al_shrink(struct drbd_conf *mdev) +{ + struct lc_element *al_ext; + int i; + + D_ASSERT( test_bit(__LC_DIRTY, &mdev->act_log->flags) ); + + for (i = 0; i < mdev->act_log->nr_elements; i++) { + al_ext = lc_entry(mdev->act_log, i); + if (al_ext->lc_number == LC_FREE) + continue; + wait_event(mdev->al_wait, _try_lc_del(mdev, al_ext)); + } + + wake_up(&mdev->al_wait); +} + +STATIC int w_update_odbm(struct drbd_conf *mdev, struct drbd_work *w, int unused) +{ + struct update_odbm_work *udw = (struct update_odbm_work *)w; + + if (!inc_local(mdev)) { + if (DRBD_ratelimit(5*HZ, 5)) + DRBD_WARN("Can not update on disk bitmap, local IO disabled.\n"); + return 1; + } + + drbd_bm_write_sect(mdev, udw->enr ); + dec_local(mdev); + + kfree(udw); + + if (drbd_bm_total_weight(mdev) <= mdev->rs_failed) { + switch (mdev->state.conn) { + case SyncSource: case SyncTarget: + case PausedSyncS: case PausedSyncT: + drbd_resync_finished(mdev); + default: /* nothing to do */; + } + } + drbd_bcast_sync_progress(mdev); + + return 1; +} + + +/* ATTENTION. The AL's extents are 4MB each, while the extents in the + * resync LRU-cache are 16MB each. + * The caller of this function has to hold an inc_local() reference. + * + * TODO will be obsoleted once we have a caching lru of the on disk bitmap + */ +STATIC void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector, + int count, int success) +{ + struct bm_extent *ext; + struct update_odbm_work *udw; + + unsigned int enr; + + MUST_HOLD(&mdev->al_lock); + D_ASSERT(atomic_read(&mdev->local_cnt)); + + /* I simply assume that a sector/size pair never crosses + * a 16 MB extent border. (Currently this is true...) */ + enr = BM_SECT_TO_EXT(sector); + + ext = (struct bm_extent *) lc_get(mdev->resync, enr); + if (ext) { + if (ext->lce.lc_number == enr) { + if (success) + ext->rs_left -= count; + else + ext->rs_failed += count; + if (ext->rs_left < ext->rs_failed) { + ERR("BAD! sector=%llus enr=%u rs_left=%d " + "rs_failed=%d count=%d\n", + (unsigned long long)sector, + ext->lce.lc_number, ext->rs_left, + ext->rs_failed, count); + dump_stack(); + /* FIXME brrrgs. should never happen! */ + lc_put(mdev->resync, &ext->lce); + drbd_force_state(mdev, NS(conn, Disconnecting)); + return; + } + } else { + /* Normally this element should be in the cache, + * since drbd_rs_begin_io() pulled it already in. + * + * But maybe an application write finished, and we set + * something in outside the resync lru_cache in sync. + */ + int rs_left = drbd_bm_e_weight(mdev, enr); + if (ext->flags != 0) { + DRBD_WARN("changing resync lce: %d[%u;%02lx]" + " -> %d[%u;00]\n", + ext->lce.lc_number, ext->rs_left, + ext->flags, enr, rs_left); + ext->flags = 0; + } + if (ext->rs_failed) { + DRBD_WARN("Kicking resync_lru element enr=%u " + "out with rs_failed=%d\n", + ext->lce.lc_number, ext->rs_failed); + set_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags); + } + ext->rs_left = rs_left; + ext->rs_failed = success ? 0 : count; + lc_changed(mdev->resync, &ext->lce); + } + lc_put(mdev->resync, &ext->lce); + /* no race, we are within the al_lock! */ + + if (ext->rs_left == ext->rs_failed) { + ext->rs_failed = 0; + + udw = kmalloc(sizeof(*udw), GFP_ATOMIC); + if (udw) { + udw->enr = ext->lce.lc_number; + udw->w.cb = w_update_odbm; + drbd_queue_work_front(&mdev->data.work, &udw->w); + } else { + DRBD_WARN("Could not kmalloc an udw\n"); + set_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags); + } + } + } else { + ERR("lc_get() failed! locked=%d/%d flags=%lu\n", + mdev->resync_locked, + mdev->resync->nr_elements, + mdev->resync->flags); + } +} + +/* clear the bit corresponding to the piece of storage in question: + * size byte of data starting from sector. Only clear a bits of the affected + * one ore more _aligned_ BM_BLOCK_SIZE blocks. + * + * called by worker on SyncTarget and receiver on SyncSource. + * + */ +void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size, + const char *file, const unsigned int line) +{ + /* Is called from worker and receiver context _only_ */ + unsigned long sbnr, ebnr, lbnr; + unsigned long count = 0; + sector_t esector, nr_sectors; + int wake_up = 0; + unsigned long flags; + + if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) { + ERR("drbd_set_in_sync: sector=%llus size=%d nonsense!\n", + (unsigned long long)sector, size); + return; + } + nr_sectors = drbd_get_capacity(mdev->this_bdev); + esector = sector + (size>>9) -1; + + ERR_IF(sector >= nr_sectors) return; + ERR_IF(esector >= nr_sectors) esector = (nr_sectors-1); + + lbnr = BM_SECT_TO_BIT(nr_sectors-1); + + /* we clear it (in sync). + * round up start sector, round down end sector. we make sure we only + * clear full, alligned, BM_BLOCK_SIZE (4K) blocks */ + if (unlikely(esector < BM_SECT_PER_BIT-1)) + return; + if (unlikely(esector == (nr_sectors-1))) + ebnr = lbnr; + else + ebnr = BM_SECT_TO_BIT(esector - (BM_SECT_PER_BIT-1)); + sbnr = BM_SECT_TO_BIT(sector + BM_SECT_PER_BIT-1); + + MTRACE(TraceTypeResync, TraceLvlMetrics, + INFO("drbd_set_in_sync: sector=%llus size=%u sbnr=%lu ebnr=%lu\n", + (unsigned long long)sector, size, sbnr, ebnr); + ); + + if (sbnr > ebnr) + return; + + /* + * ok, (capacity & 7) != 0 sometimes, but who cares... + * we count rs_{total,left} in bits, not sectors. + */ + spin_lock_irqsave(&mdev->al_lock, flags); + count = drbd_bm_clear_bits(mdev, sbnr, ebnr); + if (count) { + /* we need the lock for drbd_try_clear_on_disk_bm */ + if (jiffies - mdev->rs_mark_time > HZ*10) { + /* should be roling marks, + * but we estimate only anyways. */ + if ( mdev->rs_mark_left != drbd_bm_total_weight(mdev) && + mdev->state.conn != PausedSyncT && + mdev->state.conn != PausedSyncS ) { + mdev->rs_mark_time = jiffies; + mdev->rs_mark_left = drbd_bm_total_weight(mdev); + } + } + if (inc_local(mdev)) { + drbd_try_clear_on_disk_bm(mdev, sector, count, TRUE); + dec_local(mdev); + } + /* just wake_up unconditional now, various lc_chaged(), + * lc_put() in drbd_try_clear_on_disk_bm(). */ + wake_up = 1; + } + spin_unlock_irqrestore(&mdev->al_lock, flags); + if (wake_up) + wake_up(&mdev->al_wait); +} + +/* + * this is intended to set one request worth of data out of sync. + * affects at least 1 bit, + * and at most 1+DRBD_MAX_SEGMENT_SIZE/BM_BLOCK_SIZE bits. + * + * called by tl_clear and drbd_send_dblock (==drbd_make_request). + * so this can be _any_ process. + */ +void __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size, + const char *file, const unsigned int line) +{ + unsigned long sbnr, ebnr, lbnr, flags; + sector_t esector, nr_sectors; + unsigned int enr, count; + struct bm_extent* ext; + + if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) { + ERR("sector: %llus, size: %d\n", + (unsigned long long)sector, size); + return; + } + + if (!inc_local(mdev)) + return; /* no disk, no metadata, no bitmap to set bits in */ + + nr_sectors = drbd_get_capacity(mdev->this_bdev); + esector = sector + (size>>9) -1; + + ERR_IF(sector >= nr_sectors) + goto out; + ERR_IF(esector >= nr_sectors) + esector = (nr_sectors-1); + + lbnr = BM_SECT_TO_BIT(nr_sectors-1); + + /* we set it out of sync, + * we do not need to round anything here */ + sbnr = BM_SECT_TO_BIT(sector); + ebnr = BM_SECT_TO_BIT(esector); + + MTRACE(TraceTypeResync, TraceLvlMetrics, + INFO("drbd_set_out_of_sync: sector=%llus size=%u " + "sbnr=%lu ebnr=%lu\n", + (unsigned long long)sector, size, sbnr, ebnr); + ); + + /* ok, (capacity & 7) != 0 sometimes, but who cares... + * we count rs_{total,left} in bits, not sectors. */ + spin_lock_irqsave(&mdev->al_lock, flags); + count = drbd_bm_set_bits(mdev, sbnr, ebnr); + + enr = BM_SECT_TO_EXT(sector); + ext = (struct bm_extent *) lc_find(mdev->resync, enr); + if (ext) + ext->rs_left += count; + spin_unlock_irqrestore(&mdev->al_lock, flags); + +out: + dec_local(mdev); +} + +static inline +struct bm_extent *_bme_get(struct drbd_conf *mdev, unsigned int enr) +{ + struct bm_extent *bm_ext; + int wakeup = 0; + unsigned long rs_flags; + + spin_lock_irq(&mdev->al_lock); + if (mdev->resync_locked > mdev->resync->nr_elements/2) { + spin_unlock_irq(&mdev->al_lock); + return NULL; + } + bm_ext = (struct bm_extent *) lc_get(mdev->resync, enr); + if (bm_ext) { + if (bm_ext->lce.lc_number != enr) { + bm_ext->rs_left = drbd_bm_e_weight(mdev, enr); + bm_ext->rs_failed = 0; + lc_changed(mdev->resync, (struct lc_element *)bm_ext); + wakeup = 1; + } + if (bm_ext->lce.refcnt == 1) + mdev->resync_locked++; + set_bit(BME_NO_WRITES, &bm_ext->flags); + } + rs_flags = mdev->resync->flags; + spin_unlock_irq(&mdev->al_lock); + if (wakeup) + wake_up(&mdev->al_wait); + + if (!bm_ext) { + if (rs_flags & LC_STARVING) + DRBD_WARN("Have to wait for element" + " (resync LRU too small?)\n"); + BUG_ON(rs_flags & LC_DIRTY); + } + + return bm_ext; +} + +static inline int _is_in_al(struct drbd_conf *mdev, unsigned int enr) +{ + struct lc_element *al_ext; + int rv = 0; + + spin_lock_irq(&mdev->al_lock); + if (unlikely(enr == mdev->act_log->new_number)) rv = 1; + else { + al_ext = lc_find(mdev->act_log, enr); + if (al_ext) { + if (al_ext->refcnt) + rv = 1; + } + } + spin_unlock_irq(&mdev->al_lock); + + /* + if (unlikely(rv)) { + INFO("Delaying sync read until app's write is done\n"); + } + */ + return rv; +} + +/** + * drbd_rs_begin_io: Gets an extent in the resync LRU cache and sets it + * to BME_LOCKED. + * + * @sector: The sector number + * + * sleeps on al_wait. + * returns 1 if successful. + * returns 0 if interrupted. + */ +int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector) +{ + unsigned int enr = BM_SECT_TO_EXT(sector); + struct bm_extent *bm_ext; + int i, sig; + + MTRACE(TraceTypeResync, TraceLvlAll, + INFO("drbd_rs_begin_io: sector=%llus (rs_end=%d)\n", + (unsigned long long)sector, enr); + ); + + sig = wait_event_interruptible( mdev->al_wait, + (bm_ext = _bme_get(mdev, enr)) ); + if (sig) + return 0; + + if (test_bit(BME_LOCKED, &bm_ext->flags)) return 1; + + for (i = 0; i < AL_EXT_PER_BM_SECT; i++) { + sig = wait_event_interruptible( mdev->al_wait, + !_is_in_al(mdev, enr*AL_EXT_PER_BM_SECT+i) ); + if (sig) { + spin_lock_irq(&mdev->al_lock); + if ( lc_put(mdev->resync, &bm_ext->lce) == 0 ) { + clear_bit(BME_NO_WRITES, &bm_ext->flags); + mdev->resync_locked--; + wake_up(&mdev->al_wait); + } + spin_unlock_irq(&mdev->al_lock); + return 0; + } + } + + set_bit(BME_LOCKED, &bm_ext->flags); + + return 1; +} + +/** + * drbd_try_rs_begin_io: Gets an extent in the resync LRU cache, sets it + * to BME_NO_WRITES, then tries to set it to BME_LOCKED. + * + * @sector: The sector number + * + * does not sleep. + * returns zero if we could set BME_LOCKED and can proceed, + * -EAGAIN if we need to try again. + */ +int drbd_try_rs_begin_io(struct drbd_conf *mdev, sector_t sector) +{ + unsigned int enr = BM_SECT_TO_EXT(sector); + const unsigned int al_enr = enr*AL_EXT_PER_BM_SECT; + struct bm_extent *bm_ext; + int i; + + MTRACE(TraceTypeResync, TraceLvlAll, + INFO("drbd_try_rs_begin_io: sector=%llus\n", + (unsigned long long)sector); + ); + + spin_lock_irq(&mdev->al_lock); + if (mdev->resync_wenr != LC_FREE && mdev->resync_wenr != enr) { + /* in case you have very heavy scattered io, it may + * stall the syncer undefined if we giveup the ref count + * when we try again and requeue. + * + * if we don't give up the refcount, but the next time + * we are scheduled this extent has been "synced" by new + * application writes, we'd miss the lc_put on the + * extent we keept the refcount on. + * so we remembered which extent we had to try agin, and + * if the next requested one is something else, we do + * the lc_put here... + * we also have to wake_up + */ + MTRACE(TraceTypeResync, TraceLvlAll, + INFO("dropping %u, aparently got 'synced' " + "by application io\n", mdev->resync_wenr); + ); + bm_ext = (struct bm_extent *) + lc_find(mdev->resync, mdev->resync_wenr); + if (bm_ext) { + D_ASSERT(!test_bit(BME_LOCKED, &bm_ext->flags)); + D_ASSERT(test_bit(BME_NO_WRITES, &bm_ext->flags)); + clear_bit(BME_NO_WRITES, &bm_ext->flags); + mdev->resync_wenr = LC_FREE; + if (lc_put(mdev->resync, &bm_ext->lce) == 0) + mdev->resync_locked--; + wake_up(&mdev->al_wait); + } else { + ALERT("LOGIC BUG\n"); + } + } + bm_ext = (struct bm_extent *)lc_try_get(mdev->resync, enr); + if (bm_ext) { + if (test_bit(BME_LOCKED, &bm_ext->flags)) + goto proceed; + if (!test_and_set_bit(BME_NO_WRITES, &bm_ext->flags)) { + mdev->resync_locked++; + } else { + /* we did set the BME_NO_WRITES, + * but then could not set BME_LOCKED, + * so we tried again. + * drop the extra reference. */ + MTRACE(TraceTypeResync, TraceLvlAll, + INFO("dropping extra reference on %u\n", enr); + ); + bm_ext->lce.refcnt--; + D_ASSERT(bm_ext->lce.refcnt > 0); + } + goto check_al; + } else { + if (mdev->resync_locked > mdev->resync->nr_elements-3) { + MTRACE(TraceTypeResync, TraceLvlAll, + INFO("resync_locked = %u!\n", mdev->resync_locked); + ); + goto try_again; + } + bm_ext = (struct bm_extent *)lc_get(mdev->resync, enr); + if (!bm_ext) { + const unsigned long rs_flags = mdev->resync->flags; + if (rs_flags & LC_STARVING) + DRBD_WARN("Have to wait for element" + " (resync LRU too small?)\n"); + BUG_ON(rs_flags & LC_DIRTY); + goto try_again; + } + if (bm_ext->lce.lc_number != enr) { + bm_ext->rs_left = drbd_bm_e_weight(mdev, enr); + bm_ext->rs_failed = 0; + lc_changed(mdev->resync, (struct lc_element *)bm_ext); + wake_up(&mdev->al_wait); + D_ASSERT(test_bit(BME_LOCKED, &bm_ext->flags) == 0); + } + set_bit(BME_NO_WRITES, &bm_ext->flags); + D_ASSERT(bm_ext->lce.refcnt == 1); + mdev->resync_locked++; + goto check_al; + } +check_al: + MTRACE(TraceTypeResync, TraceLvlAll, + INFO("checking al for %u\n", enr); + ); + for (i = 0; i < AL_EXT_PER_BM_SECT; i++) { + if (unlikely(al_enr+i == mdev->act_log->new_number)) + goto try_again; + if (lc_is_used(mdev->act_log, al_enr+i)) + goto try_again; + } + set_bit(BME_LOCKED, &bm_ext->flags); +proceed: + mdev->resync_wenr = LC_FREE; + spin_unlock_irq(&mdev->al_lock); + return 0; + +try_again: + MTRACE(TraceTypeResync, TraceLvlAll, + INFO("need to try again for %u\n", enr); + ); + if (bm_ext) + mdev->resync_wenr = enr; + spin_unlock_irq(&mdev->al_lock); + return -EAGAIN; +} + +void drbd_rs_complete_io(struct drbd_conf *mdev, sector_t sector) +{ + unsigned int enr = BM_SECT_TO_EXT(sector); + struct bm_extent *bm_ext; + unsigned long flags; + + MTRACE(TraceTypeResync, TraceLvlAll, + INFO("drbd_rs_complete_io: sector=%llus (rs_enr=%d)\n", + (long long)sector, enr); + ); + + spin_lock_irqsave(&mdev->al_lock, flags); + bm_ext = (struct bm_extent *) lc_find(mdev->resync, enr); + if (!bm_ext) { + spin_unlock_irqrestore(&mdev->al_lock, flags); + ERR("drbd_rs_complete_io() called, but extent not found\n"); + return; + } + + if (bm_ext->lce.refcnt == 0) { + spin_unlock_irqrestore(&mdev->al_lock, flags); + ERR("drbd_rs_complete_io(,%llu [=%u]) called, " + "but refcnt is 0!?\n", + (unsigned long long)sector, enr); + return; + } + + if ( lc_put(mdev->resync, (struct lc_element *)bm_ext) == 0 ) { + clear_bit(BME_LOCKED, &bm_ext->flags); + clear_bit(BME_NO_WRITES, &bm_ext->flags); + mdev->resync_locked--; + wake_up(&mdev->al_wait); + } + + spin_unlock_irqrestore(&mdev->al_lock, flags); +} + +/** + * drbd_rs_cancel_all: Removes extents from the resync LRU. Even + * if they are BME_LOCKED. + */ +void drbd_rs_cancel_all(struct drbd_conf *mdev) +{ + MTRACE(TraceTypeResync, TraceLvlMetrics, + INFO("drbd_rs_cancel_all\n"); + ); + + spin_lock_irq(&mdev->al_lock); + + if (inc_local_if_state(mdev,Failed)) { /* Makes sure ->resync is there. */ + lc_reset(mdev->resync); + dec_local(mdev); + } + mdev->resync_locked = 0; + mdev->resync_wenr = LC_FREE; + spin_unlock_irq(&mdev->al_lock); + wake_up(&mdev->al_wait); +} + +/** + * drbd_rs_del_all: Gracefully remove all extents from the resync LRU. + * there may be still a reference hold by someone. In that case this function + * returns -EAGAIN. + * In case all elements got removed it returns zero. + */ +int drbd_rs_del_all(struct drbd_conf *mdev) +{ + struct bm_extent *bm_ext; + int i; + + MTRACE(TraceTypeResync, TraceLvlMetrics, + INFO("drbd_rs_del_all\n"); + ); + + spin_lock_irq(&mdev->al_lock); + + if (inc_local_if_state(mdev, Failed)) { + /* ok, ->resync is there. */ + for (i = 0; i < mdev->resync->nr_elements; i++) { + bm_ext = (struct bm_extent *) lc_entry(mdev->resync, i); + if (bm_ext->lce.lc_number == LC_FREE) + continue; + if (bm_ext->lce.lc_number == mdev->resync_wenr) { + INFO("dropping %u in drbd_rs_del_all, aparently" + " got 'synced' by application io\n", + mdev->resync_wenr); + D_ASSERT(!test_bit(BME_LOCKED, &bm_ext->flags)); + D_ASSERT(test_bit(BME_NO_WRITES, &bm_ext->flags)); + clear_bit(BME_NO_WRITES, &bm_ext->flags); + mdev->resync_wenr = LC_FREE; + lc_put(mdev->resync, &bm_ext->lce); + } + if (bm_ext->lce.refcnt != 0) { + INFO("Retrying drbd_rs_del_all() later. " + "refcnt=%d\n", bm_ext->lce.refcnt); + dec_local(mdev); + spin_unlock_irq(&mdev->al_lock); + return -EAGAIN; + } + D_ASSERT(!test_bit(BME_LOCKED, &bm_ext->flags)); + D_ASSERT(!test_bit(BME_NO_WRITES, &bm_ext->flags)); + lc_del(mdev->resync, &bm_ext->lce); + } + D_ASSERT(mdev->resync->used == 0); + dec_local(mdev); + } + spin_unlock_irq(&mdev->al_lock); + + return 0; +} + +/* Record information on a failure to resync the specified blocks + * + * called on SyncTarget when resync write fails or NegRSDReply received + * + */ +void drbd_rs_failed_io(struct drbd_conf *mdev, sector_t sector, int size) +{ + /* Is called from worker and receiver context _only_ */ + unsigned long sbnr, ebnr, lbnr; + unsigned long count; + sector_t esector, nr_sectors; + int wake_up = 0; + + MTRACE(TraceTypeResync, TraceLvlSummary, + INFO("drbd_rs_failed_io: sector=%llus, size=%u\n", + (unsigned long long)sector, size); + ); + + if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) { + ERR("drbd_rs_failed_io: sector=%llus size=%d nonsense!\n", + (unsigned long long)sector, size); + return; + } + nr_sectors = drbd_get_capacity(mdev->this_bdev); + esector = sector + (size>>9) -1; + + ERR_IF(sector >= nr_sectors) return; + ERR_IF(esector >= nr_sectors) esector = (nr_sectors-1); + + lbnr = BM_SECT_TO_BIT(nr_sectors-1); + + /* + * round up start sector, round down end sector. we make sure we only + * handle full, alligned, BM_BLOCK_SIZE (4K) blocks */ + if (unlikely(esector < BM_SECT_PER_BIT-1)) + return; + if (unlikely(esector == (nr_sectors-1))) + ebnr = lbnr; + else + ebnr = BM_SECT_TO_BIT(esector - (BM_SECT_PER_BIT-1)); + sbnr = BM_SECT_TO_BIT(sector + BM_SECT_PER_BIT-1); + + if (sbnr > ebnr) + return; + + /* + * ok, (capacity & 7) != 0 sometimes, but who cares... + * we count rs_{total,left} in bits, not sectors. + */ + spin_lock_irq(&mdev->al_lock); + count = drbd_bm_count_bits(mdev, sbnr, ebnr); + if (count) { + mdev->rs_failed += count; + + if (inc_local(mdev)) { + drbd_try_clear_on_disk_bm(mdev, sector, count, FALSE); + dec_local(mdev); + } + + /* just wake_up unconditional now, various lc_chaged(), + * lc_put() in drbd_try_clear_on_disk_bm(). */ + wake_up = 1; + } + spin_unlock_irq(&mdev->al_lock); + if (wake_up) + wake_up(&mdev->al_wait); +} --- linux-2.6.27.orig/ubuntu/drbd/lru_cache.c +++ linux-2.6.27/ubuntu/drbd/lru_cache.c @@ -0,0 +1,398 @@ +/* +-*- linux-c -*- + lru_cache.c + Kernel module for 2.6.x Kernels + + This file is part of DRBD by Philipp Reisner and Lars Ellenberg. + + Copyright (C) 2003-2008, LINBIT Information Technologies GmbH. + Copyright (C) 2003-2008, Philipp Reisner . + Copyright (C) 2003-2008, Lars Ellenberg . + + drbd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + drbd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with drbd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#include +#include +#include /* for memset */ +#include /* for seq_printf */ +#include "lru_cache.h" + +#define STATIC static + +/* this is developers aid only! */ +#define PARANOIA_ENTRY() BUG_ON(test_and_set_bit(__LC_PARANOIA, &lc->flags)) +#define PARANOIA_LEAVE() do { clear_bit(__LC_PARANOIA, &lc->flags); smp_mb__after_clear_bit(); } while (0) +#define RETURN(x...) do { PARANOIA_LEAVE(); return x ; } while (0) + +static inline size_t size_of_lc(unsigned int e_count, size_t e_size) +{ + return sizeof(struct lru_cache) + + e_count * (e_size + sizeof(struct hlist_head)); +} + +static inline void lc_init(struct lru_cache *lc, + const size_t bytes, const char *name, + const unsigned int e_count, const size_t e_size, + void *private_p) +{ + struct lc_element *e; + unsigned int i; + + memset(lc, 0, bytes); + INIT_LIST_HEAD(&lc->in_use); + INIT_LIST_HEAD(&lc->lru); + INIT_LIST_HEAD(&lc->free); + lc->element_size = e_size; + lc->nr_elements = e_count; + lc->new_number = -1; + lc->lc_private = private_p; + lc->name = name; + for (i = 0; i < e_count; i++) { + e = lc_entry(lc, i); + e->lc_number = LC_FREE; + list_add(&e->list, &lc->free); + // memset(,0,) did the rest of init for us + } +} + +/** + * lc_alloc: allocates memory for @e_count objects of @e_size bytes plus the + * struct lru_cache, and the hash table slots. + * returns pointer to a newly initialized lru_cache object with said parameters. + */ +struct lru_cache *lc_alloc(const char *name, unsigned int e_count, + size_t e_size, void *private_p) +{ + struct lru_cache *lc; + size_t bytes; + + BUG_ON(!e_count); + e_size = max(sizeof(struct lc_element),e_size); + bytes = size_of_lc(e_count, e_size); + lc = vmalloc(bytes); + if (lc) + lc_init(lc, bytes, name, e_count, e_size, private_p); + return lc; +} + +/** + * lc_free: Frees memory allocated by lc_alloc. + * @lc: The lru_cache object + */ +void lc_free(struct lru_cache *lc) +{ + vfree(lc); +} + +/** + * lc_reset: does a full reset for @lc and the hash table slots. + * It is roughly the equivalent of re-allocating a fresh lru_cache object, + * basically a short cut to lc_free(lc); lc = lc_alloc(...); + */ +void lc_reset(struct lru_cache *lc) +{ + lc_init(lc, size_of_lc(lc->nr_elements, lc->element_size), lc->name, + lc->nr_elements, lc->element_size, lc->lc_private); +} + +size_t lc_printf_stats(struct seq_file *seq, struct lru_cache* lc) +{ + /* NOTE: + * total calls to lc_get are + * (starving + hits + misses) + * misses include "dirty" count (update from an other thread in + * progress) and "changed", when this in fact lead to an successful + * update of the cache. + */ + return seq_printf(seq, "\t%s: used:%u/%u " + "hits:%lu misses:%lu starving:%lu dirty:%lu changed:%lu\n", + lc->name, lc->used, lc->nr_elements, + lc->hits, lc->misses, lc->starving, lc->dirty, lc->changed); +} + +static unsigned int lc_hash_fn(struct lru_cache *lc, unsigned int enr) +{ + return enr % lc->nr_elements; +} + + +/** + * lc_find: Returns the pointer to an element, if the element is present + * in the hash table. In case it is not this function returns NULL. + * @lc: The lru_cache object + * @enr: element number + */ +struct lc_element *lc_find(struct lru_cache *lc, unsigned int enr) +{ + struct hlist_node *n; + struct lc_element *e; + + BUG_ON(!lc); + BUG_ON(!lc->nr_elements); + hlist_for_each_entry(e, n, lc->slot + lc_hash_fn(lc, enr), colision) { + if (e->lc_number == enr) + return e; + } + return NULL; +} + +STATIC struct lc_element *lc_evict(struct lru_cache *lc) +{ + struct list_head *n; + struct lc_element *e; + + if (list_empty(&lc->lru)) return NULL; + + n = lc->lru.prev; + e = list_entry(n, struct lc_element, list); + + list_del(&e->list); + hlist_del(&e->colision); + return e; +} + +/** + * lc_del: Removes an element from the cache (and therefore adds the + * element's storage to the free list) + * + * @lc: The lru_cache object + * @e: The element to remove + */ +void lc_del(struct lru_cache *lc, struct lc_element *e) +{ + /* FIXME what to do with refcnt != 0 ? */ + PARANOIA_ENTRY(); + BUG_ON(e->refcnt); + list_del(&e->list); + hlist_del_init(&e->colision); + e->lc_number = LC_FREE; + e->refcnt = 0; + list_add(&e->list, &lc->free); + RETURN(); +} + +STATIC struct lc_element *lc_get_unused_element(struct lru_cache *lc) +{ + struct list_head *n; + + if (list_empty(&lc->free)) return lc_evict(lc); + + n = lc->free.next; + list_del(n); + return list_entry(n, struct lc_element, list); +} + +STATIC int lc_unused_element_available(struct lru_cache *lc) +{ + if (!list_empty(&lc->free)) return 1; /* something on the free list */ + if (!list_empty(&lc->lru)) return 1; /* something to evict */ + + return 0; +} + + +/** + * lc_get: Finds an element in the cache, increases its usage count, + * "touches" and returns it. + * In case the requested number is not present, it needs to be added to the + * cache. Therefore it is possible that an other element becomes eviced from + * the cache. In either case, the user is notified so he is able to e.g. keep + * a persistent log of the cache changes, and therefore the objects in use. + * + * Return values: + * NULL if the requested element number was not in the cache, and no unused + * element could be recycled + * pointer to the element with the REQUESTED element number + * In this case, it can be used right away + * + * pointer to an UNUSED element with some different element number. + * In this case, the cache is marked dirty, and the returned element + * pointer is removed from the lru list and hash collision chains. + * The user now should do whatever houskeeping is necessary. Then he + * needs to call lc_element_changed(lc,element_pointer), to finish the + * change. + * + * NOTE: The user needs to check the lc_number on EACH use, so he recognizes + * any cache set change. + * + * @lc: The lru_cache object + * @enr: element number + */ +struct lc_element *lc_get(struct lru_cache *lc, unsigned int enr) +{ + struct lc_element *e; + + BUG_ON(!lc); + BUG_ON(!lc->nr_elements); + + PARANOIA_ENTRY(); + if (lc->flags & LC_STARVING) { + ++lc->starving; + RETURN(NULL); + } + + e = lc_find(lc, enr); + if (e) { + ++lc->hits; + if (e->refcnt++ == 0) + lc->used++; + list_move(&e->list, &lc->in_use); /* Not evictable... */ + RETURN(e); + } + + ++lc->misses; + + /* In case there is nothing available and we can not kick out + * the LRU element, we have to wait ... + */ + if (!lc_unused_element_available(lc)) { + __set_bit(__LC_STARVING, &lc->flags); + RETURN(NULL); + } + + /* it was not present in the cache, find an unused element, + * which then is replaced. + * we need to update the cache; serialize on lc->flags & LC_DIRTY + */ + if (test_and_set_bit(__LC_DIRTY, &lc->flags)) { + ++lc->dirty; + RETURN(NULL); + } + + e = lc_get_unused_element(lc); + BUG_ON(!e); + + clear_bit(__LC_STARVING, &lc->flags); + BUG_ON(++e->refcnt != 1); + lc->used++; + + lc->changing_element = e; + lc->new_number = enr; + + RETURN(e); +} + +/* similar to lc_get, + * but only gets a new reference on an existing element. + * you either get the requested element, or NULL. + */ +struct lc_element *lc_try_get(struct lru_cache *lc, unsigned int enr) +{ + struct lc_element *e; + + BUG_ON(!lc); + BUG_ON(!lc->nr_elements); + + PARANOIA_ENTRY(); + if (lc->flags & LC_STARVING) { + ++lc->starving; + RETURN(NULL); + } + + e = lc_find(lc, enr); + if (e) { + ++lc->hits; + if (e->refcnt++ == 0) + lc->used++; + list_move(&e->list, &lc->in_use); /* Not evictable... */ + } + RETURN(e); +} + +void lc_changed(struct lru_cache *lc, struct lc_element *e) +{ + PARANOIA_ENTRY(); + BUG_ON(e != lc->changing_element); + ++lc->changed; + e->lc_number = lc->new_number; + list_add(&e->list, &lc->in_use); + hlist_add_head(&e->colision, + lc->slot + lc_hash_fn(lc, lc->new_number)); + lc->changing_element = NULL; + lc->new_number = -1; + clear_bit(__LC_DIRTY, &lc->flags); + smp_mb__after_clear_bit(); + PARANOIA_LEAVE(); +} + + +unsigned int lc_put(struct lru_cache *lc, struct lc_element *e) +{ + BUG_ON(!lc); + BUG_ON(!lc->nr_elements); + BUG_ON(!e); + + PARANOIA_ENTRY(); + BUG_ON(e->refcnt == 0); + BUG_ON(e == lc->changing_element); + if (--e->refcnt == 0) { + /* move it to the front of LRU. */ + list_move(&e->list, &lc->lru); + lc->used--; + clear_bit(__LC_STARVING, &lc->flags); + smp_mb__after_clear_bit(); + } + RETURN(e->refcnt); +} + + +/** + * lc_set: Sets an element in the cache. You might use this function to + * setup the cache. It is expected that the elements are properly initialized. + * @lc: The lru_cache object + * @enr: element number + * @index: The elements' position in the cache + */ +void lc_set(struct lru_cache *lc, unsigned int enr, int index) +{ + struct lc_element *e; + + if (index < 0 || index >= lc->nr_elements) + return; + + e = lc_entry(lc, index); + e->lc_number = enr; + + hlist_del_init(&e->colision); + hlist_add_head( &e->colision, lc->slot + lc_hash_fn(lc, enr) ); + list_move(&e->list, e->refcnt ? &lc->in_use : &lc->lru); +} + +/** + * lc_dump: Dump a complete LRU cache to seq in textual form. + */ +void lc_dump(struct lru_cache *lc, struct seq_file *seq, char *utext, + void (*detail) (struct seq_file *, struct lc_element *) ) +{ + unsigned int nr_elements = lc->nr_elements; + struct lc_element *e; + int i; + + seq_printf(seq, "\tnn: lc_number refcnt %s\n ", utext); + for (i = 0; i < nr_elements; i++) { + e = lc_entry(lc, i); + if (e->lc_number == LC_FREE) { + seq_printf(seq, "\t%2d: FREE\n", i ); + } else { + seq_printf(seq, "\t%2d: %4u %4u ", i, + e->lc_number, + e->refcnt ); + detail(seq, e); + } + } +} + --- linux-2.6.27.orig/ubuntu/drbd/lru_cache.h +++ linux-2.6.27/ubuntu/drbd/lru_cache.h @@ -0,0 +1,149 @@ +/* +-*- linux-c -*- + lru_cache.c + Kernel module for 2.6.x Kernels + + This file is part of DRBD by Philipp Reisner and Lars Ellenberg. + + Copyright (C) 2003-2008, LINBIT Information Technologies GmbH. + Copyright (C) 2003-2008, Philipp Reisner . + Copyright (C) 2003-2008, Lars Ellenberg . + + drbd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + drbd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with drbd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +/* + * The lru_cache describes a big set of objects that are addressed + * by an index number (=lc_number). Only a small fraction of this set + * is present in the cache. + * (You set the size of the cache during lc_alloc) + * Once created, the api consists of + * lc_find(,nr) -- finds the object with the given number, if present + * lc_get(,nr) -- finds the object and increases the usage count + * if not present, actions are taken to make sure that + * the cache is updated, the user is notified of this by a callback. + * Return value is NULL in this case. + * As soon as the user informs the cache that it has been updated, + * the next lc_get on that very object number will be successfull. + * lc_put(,lc_element*) + * -- decreases the usage count of this object, and returns the new value. + * + * NOTE: It is the USERS responsibility + * to make sure that calls do not happen concurrently. + */ + +#ifndef LRU_CACHE_H +#define LRU_CACHE_H + +#include +#ifndef HLIST_HEAD_INIT +# include "hlist.h" +#endif + +#include + +/* FIXME + * I want these structs opaque outside of lru_cache.c + */ + +struct lc_element { + struct hlist_node colision; + struct list_head list; /* LRU list or free list */ + unsigned int refcnt; + unsigned int lc_number; +}; + +struct lru_cache { + struct list_head lru; + struct list_head free; + struct list_head in_use; + size_t element_size; + unsigned int nr_elements; + unsigned int new_number; + + /* here may or may not be a pad... */ + + unsigned int used; + unsigned long flags; + unsigned long hits, misses, starving, dirty, changed; + struct lc_element *changing_element; /* just for paranoia */ + + void *lc_private; + const char *name; + + struct hlist_head slot[0]; + /* hash colision chains here, then element storage. */ +}; + + +/* flag-bits for lru_cache */ +enum { + __LC_PARANOIA, + __LC_DIRTY, + __LC_STARVING, +}; +#define LC_PARANOIA (1<<__LC_PARANOIA) +#define LC_DIRTY (1<<__LC_DIRTY) +#define LC_STARVING (1<<__LC_STARVING) + +extern struct lru_cache *lc_alloc(const char *name, unsigned int e_count, + size_t e_size, void *private_p); +extern void lc_reset(struct lru_cache *lc); +extern void lc_free(struct lru_cache *lc); +extern void lc_set(struct lru_cache *lc, unsigned int enr, int index); +extern void lc_del(struct lru_cache *lc, struct lc_element *element); + +extern struct lc_element *lc_try_get(struct lru_cache *lc, unsigned int enr); +extern struct lc_element *lc_find(struct lru_cache *lc, unsigned int enr); +extern struct lc_element *lc_get(struct lru_cache *lc, unsigned int enr); +extern unsigned int lc_put(struct lru_cache *lc, struct lc_element *e); +extern void lc_changed(struct lru_cache *lc, struct lc_element *e); + +struct seq_file; +extern size_t lc_printf_stats(struct seq_file *seq, struct lru_cache *lc); + +void lc_dump(struct lru_cache *lc, struct seq_file *seq, char *utext, + void (*detail) (struct seq_file *, struct lc_element *) ); + +/* This can be used to stop lc_get from changing the set of active elements. + * Note that the reference counts and order on the lru list may still change. + * returns true if we aquired the lock. + */ +static inline int lc_try_lock(struct lru_cache *lc) +{ + return !test_and_set_bit(__LC_DIRTY, &lc->flags); +} + +static inline void lc_unlock(struct lru_cache *lc) +{ + clear_bit(__LC_DIRTY, &lc->flags); + smp_mb__after_clear_bit(); +} + +static inline int lc_is_used(struct lru_cache *lc, unsigned int enr) +{ + struct lc_element *e = lc_find(lc, enr); + return (e && e->refcnt); +} + +#define LC_FREE (-1U) + +#define lc_e_base(lc) ((char *) ( (lc)->slot + (lc)->nr_elements ) ) +#define lc_entry(lc, i) ((struct lc_element *) \ + (lc_e_base(lc) + (i)*(lc)->element_size)) +#define lc_index_of(lc, e) (((char *)(e) - lc_e_base(lc))/(lc)->element_size) + +#endif --- linux-2.6.27.orig/ubuntu/drbd/drbd_req.h +++ linux-2.6.27/ubuntu/drbd/drbd_req.h @@ -0,0 +1,333 @@ +/* + drbd_req.h + Kernel module for 2.6.x Kernels + + This file is part of DRBD by Philipp Reisner and Lars Ellenberg. + + Copyright (C) 2006-2008, LINBIT Information Technologies GmbH. + Copyright (C) 2006-2008, Lars Ellenberg . + Copyright (C) 2006-2008, Philipp Reisner . + + DRBD is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + DRBD is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with drbd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _DRBD_REQ_H +#define _DRBD_REQ_H + +#include +#include + +#include +#include +#include "drbd_int.h" + +/* The request callbacks will be called in irq context by the IDE drivers, + and in Softirqs/Tasklets/BH context by the SCSI drivers, + and by the receiver and worker in kernel-thread context. + Try to get the locking right :) */ + +/* + * Objects of type struct drbd_request do only exist on a Primary node, and are + * associated with IO requests originating from the block layer above us. + * + * There are quite a few things that may happen to a drbd request + * during its lifetime. + * + * It will be created. + * It will be marked with the intention to be + * submitted to local disk and/or + * send via the network. + * + * It has to be placed on the transfer log and other housekeeping lists, + * In case we have a network connection. + * FIXME I believe that for consistency we should place even READ requests + * on these lists, so we can moan when we detect that the other node is + * writing to an area that we currently read from (when this happens, our + * users are broken). + * + * It may be identified as a concurrent (write) request + * and be handled accordingly. + * + * It may me handed over to the local disk subsystem. + * It may be completed by the local disk subsystem, + * either sucessfully or with io-error. + * In case it is a READ request, and it failed locally, + * it may be retried remotely. + * + * It may be queued for sending. + * It may be handed over to the network stack, + * which may fail. + * It may be acknowledged by the "peer" according to the wire_protocol in use. + * this may be a negative ack. + * It may receive a faked ack when the network connection is lost and the + * transfer log is cleaned up. + * Sending may be canceled due to network connection loss. + * When it finally has outlived its time, + * corresponding dirty bits in the resync-bitmap may be cleared or set, + * it will be destroyed, + * and completion will be signalled to the originator, + * with or without "success". + * + * See also documentation/drbd-request-state-overview.dot + * (dot -Tps2 documentation/drbd-request-state-overview.dot | display -) + */ + +enum drbd_req_event { + created, + to_be_send, + to_be_submitted, + + /* XXX yes, now I am inconsistent... + * these two are not "events" but "actions" + * oh, well... */ + queue_for_net_write, + queue_for_net_read, + + send_canceled, + send_failed, + handed_over_to_network, + connection_lost_while_pending, + recv_acked_by_peer, + write_acked_by_peer, + write_acked_by_peer_and_sis, /* and set_in_sync */ + conflict_discarded_by_peer, + neg_acked, + barrier_acked, /* in protocol A and B */ + data_received, /* (remote read) */ + + read_completed_with_error, + write_completed_with_error, + completed_ok, +}; + +/* encoding of request states for now. we don't actually need that many bits. + * we don't need to do atomic bit operations either, since most of the time we + * need to look at the connection state and/or manipulate some lists at the + * same time, so we should hold the request lock anyways. + */ +enum drbd_req_state_bits { + /* 210 + * 000: no local possible + * 001: to be submitted + * UNUSED, we could map: 011: submitted, completion still pending + * 110: completed ok + * 010: completed with error + */ + __RQ_LOCAL_PENDING, + __RQ_LOCAL_COMPLETED, + __RQ_LOCAL_OK, + + /* 76543 + * 00000: no network possible + * 00001: to be send + * 00011: to be send, on worker queue + * 00101: sent, expecting recv_ack (B) or write_ack (C) + * 11101: sent, + * recv_ack (B) or implicit "ack" (A), + * still waiting for the barrier ack. + * master_bio may already be completed and invalidated. + * 11100: write_acked (C), + * data_received (for remote read, any protocol) + * or finally the barrier ack has arrived (B,A)... + * request can be freed + * 01100: neg-acked (write, protocol C) + * or neg-d-acked (read, any protocol) + * or killed from the transfer log + * during cleanup after connection loss + * request can be freed + * 01000: canceled or send failed... + * request can be freed + */ + + /* if "SENT" is not set, yet, this can still fail or be canceled. + * if "SENT" is set already, we still wait for an Ack packet. + * when cleared, the master_bio may be completed. + * in (B,A) the request object may still linger on the transaction log + * until the corresponding barrier ack comes in */ + __RQ_NET_PENDING, + + /* If it is QUEUED, and it is a WRITE, it is also registered in the + * transfer log. Currently we need this flag to avoid conflicts between + * worker canceling the request and tl_clear_barrier killing it from + * transfer log. We should restructure the code so this conflict does + * no longer occur. */ + __RQ_NET_QUEUED, + + /* well, actually only "handed over to the network stack". + * + * TODO can potentially be dropped because of the similar meaning + * of RQ_NET_SENT and ~RQ_NET_QUEUED. + * however it is not exactly the same. before we drop it + * we must ensure that we can tell a request with network part + * from a request without, regardless of what happens to it. */ + __RQ_NET_SENT, + + /* when set, the request may be freed (if RQ_NET_QUEUED is clear). + * in (C) this happens when WriteAck is received, + * in (B,A) when the corresponding BarrierAck is received */ + __RQ_NET_DONE, + + /* whether or not we know (C) or pretend (B,A) that the write + * was successfully written on the peer. + */ + __RQ_NET_OK, + + /* peer called drbd_set_in_sync() for this write */ + __RQ_NET_SIS, + + /* keep this last, its for the RQ_NET_MASK */ + __RQ_NET_MAX, +}; + +#define RQ_LOCAL_PENDING (1UL << __RQ_LOCAL_PENDING) +#define RQ_LOCAL_COMPLETED (1UL << __RQ_LOCAL_COMPLETED) +#define RQ_LOCAL_OK (1UL << __RQ_LOCAL_OK) + +#define RQ_LOCAL_MASK ((RQ_LOCAL_OK << 1)-1) /* 0x07 */ + +#define RQ_NET_PENDING (1UL << __RQ_NET_PENDING) +#define RQ_NET_QUEUED (1UL << __RQ_NET_QUEUED) +#define RQ_NET_SENT (1UL << __RQ_NET_SENT) +#define RQ_NET_DONE (1UL << __RQ_NET_DONE) +#define RQ_NET_OK (1UL << __RQ_NET_OK) +#define RQ_NET_SIS (1UL << __RQ_NET_SIS) + +/* 0x1f8 */ +#define RQ_NET_MASK (((1UL << __RQ_NET_MAX)-1) & ~RQ_LOCAL_MASK) + +/* epoch entries */ +static inline +struct hlist_head *ee_hash_slot(struct drbd_conf *mdev, sector_t sector) +{ + BUG_ON(mdev->ee_hash_s == 0); + return mdev->ee_hash + + ((unsigned int)(sector>>HT_SHIFT) % mdev->ee_hash_s); +} + +/* transfer log (drbd_request objects) */ +static inline +struct hlist_head *tl_hash_slot(struct drbd_conf *mdev, sector_t sector) +{ + BUG_ON(mdev->tl_hash_s == 0); + return mdev->tl_hash + + ((unsigned int)(sector>>HT_SHIFT) % mdev->tl_hash_s); +} + +/* when we receive the ACK for a write request, + * verify that we actually know about it */ +static inline struct drbd_request *_ack_id_to_req(struct drbd_conf *mdev, + u64 id, sector_t sector) +{ + struct hlist_head *slot = tl_hash_slot(mdev, sector); + struct hlist_node *n; + struct drbd_request *req; + + hlist_for_each_entry(req, n, slot, colision) { + if ((unsigned long)req == (unsigned long)id) + { + if (req->sector != sector) { + ERR("_ack_id_to_req: found req %p but it has " + "wrong sector (%llus versus %llus)\n", req, + (unsigned long long)req->sector, + (unsigned long long)sector); + break; + } + return req; + } + } + ERR("_ack_id_to_req: failed to find req %p, sector %llus in list\n", + (void *)(unsigned long)id, (unsigned long long)sector); + return NULL; +} + +/* application reads (drbd_request objects) */ +static struct hlist_head *ar_hash_slot(struct drbd_conf *mdev, sector_t sector) +{ + return mdev->app_reads_hash + + ((unsigned int)(sector) % APP_R_HSIZE); +} + +/* when we receive the answer for a read request, + * verify that we actually know about it */ +static inline struct drbd_request *_ar_id_to_req(struct drbd_conf *mdev, + u64 id, sector_t sector) +{ + struct hlist_head *slot = ar_hash_slot(mdev, sector); + struct hlist_node *n; + struct drbd_request *req; + + hlist_for_each_entry(req, n, slot, colision) { + if ((unsigned long)req == (unsigned long)id) + { + D_ASSERT(req->sector == sector); + return req; + } + } + return NULL; +} + +static inline struct drbd_request *drbd_req_new(struct drbd_conf *mdev, + struct bio *bio_src) +{ + struct bio *bio; + struct drbd_request *req = + mempool_alloc(drbd_request_mempool, GFP_NOIO); + if (likely(req)) { + bio = bio_clone(bio_src, GFP_NOIO); /* XXX cannot fail?? */ + + req->rq_state = 0; + req->mdev = mdev; + req->master_bio = bio_src; + req->private_bio = bio; + req->epoch = 0; + req->sector = bio->bi_sector; + req->size = bio->bi_size; + req->start_time = jiffies; + INIT_HLIST_NODE(&req->colision); + INIT_LIST_HEAD(&req->tl_requests); + + bio->bi_private = req; + bio->bi_end_io = drbd_endio_pri; + bio->bi_next = NULL; + } + return req; +} + +static inline void drbd_req_free(struct drbd_request *req) +{ + mempool_free(req, drbd_request_mempool); +} + +static inline int overlaps(sector_t s1, int l1, sector_t s2, int l2) +{ + return !( ( s1 + (l1>>9) <= s2 ) || ( s1 >= s2 + (l2>>9) ) ); +} + +/* aparently too large to be inlined... + * moved to drbd_req.c */ +extern void _req_may_be_done(struct drbd_request *req, int error); +extern void _req_mod(struct drbd_request *req, + enum drbd_req_event what, int error); + +/* If you need it irqsave, do it your self! */ +static inline void req_mod(struct drbd_request *req, + enum drbd_req_event what, int error) +{ + struct drbd_conf *mdev = req->mdev; + spin_lock_irq(&mdev->req_lock); + _req_mod(req, what, error); + spin_unlock_irq(&mdev->req_lock); +} +#endif --- linux-2.6.27.orig/ubuntu/drbd/BOM +++ linux-2.6.27/ubuntu/drbd/BOM @@ -0,0 +1,2 @@ +Downloaded from: http://oss.linbit.com/drbd/ +Current Version: 8.2.6 --- linux-2.6.27.orig/ubuntu/drbd/linux/drbd_tag_magic.h +++ linux-2.6.27/ubuntu/drbd/linux/drbd_tag_magic.h @@ -0,0 +1,83 @@ +#ifndef DRBD_TAG_MAGIC_H +#define DRBD_TAG_MAGIC_H + +#define TT_END 0 +#define TT_REMOVED 0xE000 + +/* declare packet_type enums */ +enum packet_types { +#define NL_PACKET(name, number, fields) P_ ## name = number, +#define NL_INTEGER(pn, pr, member) +#define NL_INT64(pn, pr, member) +#define NL_BIT(pn, pr, member) +#define NL_STRING(pn, pr, member, len) +#include "drbd_nl.h" + P_nl_after_last_packet, +}; + +/* These struct are used to deduce the size of the tag lists: */ +#define NL_PACKET(name, number, fields) \ + struct name ## _tag_len_struct { fields }; +#define NL_INTEGER(pn, pr, member) \ + int member; int tag_and_len ## member; +#define NL_INT64(pn, pr, member) \ + __u64 member; int tag_and_len ## member; +#define NL_BIT(pn, pr, member) \ + unsigned char member : 1; int tag_and_len ## member; +#define NL_STRING(pn, pr, member, len) \ + unsigned char member[len]; int member ## _len; \ + int tag_and_len ## member; +#include "linux/drbd_nl.h" + +/* declate tag-list-sizes */ +static const int tag_list_sizes[] = { +#define NL_PACKET(name, number, fields) 2 fields , +#define NL_INTEGER(pn, pr, member) + 4 + 4 +#define NL_INT64(pn, pr, member) + 4 + 8 +#define NL_BIT(pn, pr, member) + 4 + 1 +#define NL_STRING(pn, pr, member, len) + 4 + (len) +#include "drbd_nl.h" +}; + +/* The two highest bits are used for the tag type */ +#define TT_MASK 0xC000 +#define TT_INTEGER 0x0000 +#define TT_INT64 0x4000 +#define TT_BIT 0x8000 +#define TT_STRING 0xC000 +/* The next bit indicates if processing of the tag is mandatory */ +#define T_MANDATORY 0x2000 +#define T_MAY_IGNORE 0x0000 +#define TN_MASK 0x1fff +/* The remaining 13 bits are used to enumerate the tags */ + +#define tag_type(T) ((T) & TT_MASK) +#define tag_number(T) ((T) & TN_MASK) + +/* declare tag enums */ +#define NL_PACKET(name, number, fields) fields +enum drbd_tags { +#define NL_INTEGER(pn, pr, member) T_ ## member = pn | TT_INTEGER | pr , +#define NL_INT64(pn, pr, member) T_ ## member = pn | TT_INT64 | pr , +#define NL_BIT(pn, pr, member) T_ ## member = pn | TT_BIT | pr , +#define NL_STRING(pn, pr, member, len) T_ ## member = pn | TT_STRING | pr , +#include "drbd_nl.h" +}; + +struct tag { + const char *name; + int type_n_flags; + int max_len; +}; + +/* declare tag names */ +#define NL_PACKET(name, number, fields) fields +static const struct tag tag_descriptions[] = { +#define NL_INTEGER(pn, pr, member) [ pn ] = { #member, TT_INTEGER | pr, sizeof(int) }, +#define NL_INT64(pn, pr, member) [ pn ] = { #member, TT_INT64 | pr, sizeof(__u64) }, +#define NL_BIT(pn, pr, member) [ pn ] = { #member, TT_BIT | pr, sizeof(int) }, +#define NL_STRING(pn, pr, member, len) [ pn ] = { #member, TT_STRING | pr, (len) }, +#include "drbd_nl.h" +}; + +#endif --- linux-2.6.27.orig/ubuntu/drbd/linux/drbd_limits.h +++ linux-2.6.27/ubuntu/drbd/linux/drbd_limits.h @@ -0,0 +1,128 @@ +/* + drbd_limits.h + This file is part of DRBD by Philipp Reisner and Lars Ellenberg. +*/ + +/* + * Our current limitations. + * Some of them are hard limits, + * some of them are arbitrary range limits, that make it easier to provide + * feedback about nonsense settings for certain configurable values. + */ + +#ifndef DRBD_LIMITS_H +#define DRBD_LIMITS_H 1 + +#define DEBUG_RANGE_CHECK 0 + +#define DRBD_MINOR_COUNT_MIN 1 +#define DRBD_MINOR_COUNT_MAX 255 + +#define DRBD_DIALOG_REFRESH_MIN 0 +#define DRBD_DIALOG_REFRESH_MAX 600 + +/* valid port number */ +#define DRBD_PORT_MIN 1 +#define DRBD_PORT_MAX 0xffff + +/* startup { */ + /* if you want more than 3.4 days, disable */ +#define DRBD_WFC_TIMEOUT_MIN 0 +#define DRBD_WFC_TIMEOUT_MAX 300000 +#define DRBD_WFC_TIMEOUT_DEF 0 + +#define DRBD_DEGR_WFC_TIMEOUT_MIN 0 +#define DRBD_DEGR_WFC_TIMEOUT_MAX 300000 +#define DRBD_DEGR_WFC_TIMEOUT_DEF 60 + +/* }*/ + +/* net { */ + /* timeout, unit centi seconds + * more than one minute timeout is not usefull */ +#define DRBD_TIMEOUT_MIN 1 +#define DRBD_TIMEOUT_MAX 600 +#define DRBD_TIMEOUT_DEF 60 /* 6 seconds */ + + /* active connection retries when WFConnection */ +#define DRBD_CONNECT_INT_MIN 1 +#define DRBD_CONNECT_INT_MAX 120 +#define DRBD_CONNECT_INT_DEF 10 /* seconds */ + + /* keep-alive probes when idle */ +#define DRBD_PING_INT_MIN 1 +#define DRBD_PING_INT_MAX 120 +#define DRBD_PING_INT_DEF 10 + + /* timeout for the ping packets.*/ +#define DRBD_PING_TIMEO_MIN 1 +#define DRBD_PING_TIMEO_MAX 100 +#define DRBD_PING_TIMEO_DEF 5 + + /* max number of write requests between write barriers */ +#define DRBD_MAX_EPOCH_SIZE_MIN 1 +#define DRBD_MAX_EPOCH_SIZE_MAX 20000 +#define DRBD_MAX_EPOCH_SIZE_DEF 2048 + + /* I don't think that a tcp send buffer of more than 10M is usefull */ +#define DRBD_SNDBUF_SIZE_MIN 1 +#define DRBD_SNDBUF_SIZE_MAX 10000000 +#define DRBD_SNDBUF_SIZE_DEF (2*65535) + + /* @4k PageSize -> 128kB - 512MB */ +#define DRBD_MAX_BUFFERS_MIN 32 +#define DRBD_MAX_BUFFERS_MAX 131072 +#define DRBD_MAX_BUFFERS_DEF 2048 + + /* @4k PageSize -> 4kB - 512MB */ +#define DRBD_UNPLUG_WATERMARK_MIN 1 +#define DRBD_UNPLUG_WATERMARK_MAX 131072 +#define DRBD_UNPLUG_WATERMARK_DEF (DRBD_MAX_BUFFERS_DEF/16) + + /* 0 is disabled. + * 200 should be more than enough even for very short timeouts */ +#define DRBD_KO_COUNT_MIN 0 +#define DRBD_KO_COUNT_MAX 200 +#define DRBD_KO_COUNT_DEF 0 +/* } */ + +/* syncer { */ + /* FIXME allow rate to be zero? */ +#define DRBD_RATE_MIN 1 +#define DRBD_RATE_MAX 700000 +#define DRBD_RATE_DEF 250 /* kb/second */ + + /* less than 7 would hit performance unneccessarily. + * 3833 is the largest prime that still does fit + * into 64 sectors of activity log */ +#define DRBD_AL_EXTENTS_MIN 7 +#define DRBD_AL_EXTENTS_MAX 3833 +#define DRBD_AL_EXTENTS_DEF 127 + +#define DRBD_AFTER_MIN -1 +#define DRBD_AFTER_MAX 255 +#define DRBD_AFTER_DEF -1 + +/* } */ + +/* drbdsetup XY resize -d Z + * you are free to reduce the device size to nothing, if you want to. + * but more than 3998G are currently not possible */ +/* DRBD_MAX_SECTORS */ +#define DRBD_DISK_SIZE_SECT_MIN 0 +#define DRBD_DISK_SIZE_SECT_MAX ((128LLU*1024*2 - 72)*512LLU*8*8) +#define DRBD_DISK_SIZE_SECT_DEF 0 /* = disabled = no user size... */ + +#define DRBD_ON_IO_ERROR_DEF PassOn +#define DRBD_FENCING_DEF DontCare +#define DRBD_AFTER_SB_0P_DEF Disconnect +#define DRBD_AFTER_SB_1P_DEF Disconnect +#define DRBD_AFTER_SB_2P_DEF Disconnect +#define DRBD_RR_CONFLICT_DEF Disconnect + +#define DRBD_MAX_BIO_BVECS_MIN 0 +#define DRBD_MAX_BIO_BVECS_MAX 128 +#define DRBD_MAX_BIO_BVECS_DEF 0 + +#undef RANGE +#endif --- linux-2.6.27.orig/ubuntu/drbd/linux/drbd_config.h +++ linux-2.6.27/ubuntu/drbd/linux/drbd_config.h @@ -0,0 +1,89 @@ +/* + drbd_config.h + DRBD's compile time configuration. + + drbd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + drbd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with drbd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef DRBD_CONFIG_H +#define DRBD_CONFIG_H + +extern const char *drbd_buildtag(void); + +#define REL_VERSION "8.2.6" +#define API_VERSION 88 +#define PRO_VERSION_MIN 86 +#define PRO_VERSION_MAX 88 + +#ifndef __CHECKER__ /* for a sparse run, we need all STATICs */ +#define DBG_ALL_SYMBOLS /* no static functs, improves quality of OOPS traces */ +#endif + +/* drbd_assert_breakpoint() function +#define DBG_ASSERTS + */ + +/* Dump all cstate changes */ +#define DUMP_MD 2 + +/* some extra checks +#define PARANOIA + */ + +/* Dump every hour the usage / not usage of zero copy IO */ +/* #define SHOW_SENDPAGE_USAGE */ + +/* Define this to enable dynamic tracing controlled by module parameters + * at run time. This enables ALL use of dynamic tracing including packet + * and bio dumping, etc */ +#define ENABLE_DYNAMIC_TRACE + +/* You can disable the use of the sendpage() call (= zero copy IO) + * If you have the feeling that this might be the cause for troubles. +#define DRBD_DISABLE_SENDPAGE + */ + +/* Enable fault insertion code */ +#define DRBD_ENABLE_FAULTS + +/* RedHat's 2.6.9 kernels have the gfp_t type. Mainline has this feature + * since 2.6.16. If you build for RedHat enable the line below. */ +#define KERNEL_HAS_GFP_T + +/* kernel.org has atomic_add_return since 2.6.10. some vendor kernels + * have it backported, though. Others don't. */ +//#define NEED_BACKPORT_OF_ATOMIC_ADD + +/* 2.6.something has deprecated kmem_cache_t + * some older still use it. + * some have it defined as struct kmem_cache_s, some as struct kmem_cache */ +//#define USE_KMEM_CACHE_S + +/* 2.6.something has sock_create_kern (SE-linux security context stuff) + * some older distribution kernels don't. */ +//#define DEFINE_SOCK_CREATE_KERN + +/* in older kernels (vanilla < 2.6.16) struct netlink_skb_parms has a + * member called dst_groups. Later it is called dst_group (without 's'). */ +//#define DRBD_NL_DST_GROUPS + +/* in older kernels (vanilla < 2.6.14) is no kzalloc() */ +//#define NEED_BACKPORT_OF_KZALLOC + +// some vendor kernels have it, some don't +//#define NEED_SG_SET_BUF +#define HAVE_LINUX_SCATTERLIST_H + +#endif --- linux-2.6.27.orig/ubuntu/drbd/linux/drbd_nl.h +++ linux-2.6.27/ubuntu/drbd/linux/drbd_nl.h @@ -0,0 +1,123 @@ +/* + PAKET( name, + TYPE ( pn, pr, member ) + ... + ) + + You may never reissue one of the pn arguments +*/ + +#if !defined(NL_PACKET) || !defined(NL_STRING) || !defined(NL_INTEGER) || !defined(NL_BIT) || !defined(NL_INT64) +#error "The macros NL_PACKET, NL_STRING, NL_INTEGER, NL_INT64 and NL_BIT needs to be defined" +#endif + +NL_PACKET(primary, 1, + NL_BIT( 1, T_MAY_IGNORE, overwrite_peer) +) + +NL_PACKET(secondary, 2, ) + +NL_PACKET(disk_conf, 3, + NL_INT64( 2, T_MAY_IGNORE, disk_size) + NL_STRING( 3, T_MANDATORY, backing_dev, 128) + NL_STRING( 4, T_MANDATORY, meta_dev, 128) + NL_INTEGER( 5, T_MANDATORY, meta_dev_idx) + NL_INTEGER( 6, T_MAY_IGNORE, on_io_error) + NL_INTEGER( 7, T_MAY_IGNORE, fencing) + NL_BIT( 37, T_MAY_IGNORE, use_bmbv) + NL_BIT( 53, T_MAY_IGNORE, no_disk_flush) + NL_BIT( 54, T_MAY_IGNORE, no_md_flush) + /* 55 max_bio_size was available in 8.2.6rc2 */ + NL_INTEGER( 56, T_MAY_IGNORE, max_bio_bvecs) +) + +NL_PACKET(detach, 4, ) +NL_PACKET(net_conf, 5, + NL_STRING( 8, T_MANDATORY, my_addr, 128) + NL_STRING( 9, T_MANDATORY, peer_addr, 128) + NL_STRING( 10, T_MAY_IGNORE, shared_secret, SHARED_SECRET_MAX) + NL_STRING( 11, T_MAY_IGNORE, cram_hmac_alg, SHARED_SECRET_MAX) + NL_STRING( 44, T_MAY_IGNORE, integrity_alg, SHARED_SECRET_MAX) + NL_INTEGER( 14, T_MAY_IGNORE, timeout) + NL_INTEGER( 15, T_MANDATORY, wire_protocol) + NL_INTEGER( 16, T_MAY_IGNORE, try_connect_int) + NL_INTEGER( 17, T_MAY_IGNORE, ping_int) + NL_INTEGER( 18, T_MAY_IGNORE, max_epoch_size) + NL_INTEGER( 19, T_MAY_IGNORE, max_buffers) + NL_INTEGER( 20, T_MAY_IGNORE, unplug_watermark) + NL_INTEGER( 21, T_MAY_IGNORE, sndbuf_size) + NL_INTEGER( 22, T_MAY_IGNORE, ko_count) + NL_INTEGER( 24, T_MAY_IGNORE, after_sb_0p) + NL_INTEGER( 25, T_MAY_IGNORE, after_sb_1p) + NL_INTEGER( 26, T_MAY_IGNORE, after_sb_2p) + NL_INTEGER( 39, T_MAY_IGNORE, rr_conflict) + NL_INTEGER( 40, T_MAY_IGNORE, ping_timeo) + NL_BIT( 27, T_MAY_IGNORE, want_lose) + NL_BIT( 28, T_MAY_IGNORE, two_primaries) + NL_BIT( 41, T_MAY_IGNORE, always_asbp) +) + +NL_PACKET(disconnect, 6, ) + +NL_PACKET(resize, 7, + NL_INT64( 29, T_MAY_IGNORE, resize_size) +) + +NL_PACKET(syncer_conf, 8, + NL_INTEGER( 30, T_MAY_IGNORE, rate) + NL_INTEGER( 31, T_MAY_IGNORE, after) + NL_INTEGER( 32, T_MAY_IGNORE, al_extents) + NL_STRING( 52, T_MAY_IGNORE, verify_alg, SHARED_SECRET_MAX) + NL_STRING( 51, T_MAY_IGNORE, cpu_mask, 32) +) + +NL_PACKET(invalidate, 9, ) +NL_PACKET(invalidate_peer, 10, ) +NL_PACKET(pause_sync, 11, ) +NL_PACKET(resume_sync, 12, ) +NL_PACKET(suspend_io, 13, ) +NL_PACKET(resume_io, 14, ) +NL_PACKET(outdate, 15, ) +NL_PACKET(get_config, 16, ) +NL_PACKET(get_state, 17, + NL_INTEGER( 33, T_MAY_IGNORE, state_i) +) + +NL_PACKET(get_uuids, 18, + NL_STRING( 34, T_MAY_IGNORE, uuids, (UUID_SIZE*sizeof(__u64))) + NL_INTEGER( 35, T_MAY_IGNORE, uuids_flags) +) + +NL_PACKET(get_timeout_flag, 19, + NL_BIT( 36, T_MAY_IGNORE, use_degraded) +) + +NL_PACKET(call_helper, 20, + NL_STRING( 38, T_MAY_IGNORE, helper, 32) +) + +/* Tag nr 42 already allocated in drbd-8.1 development. + * Packet numbers 21 and 22 already in drbd-8.1 development. */ + +NL_PACKET(sync_progress, 23, + NL_INTEGER( 43, T_MAY_IGNORE, sync_progress) +) + +NL_PACKET(dump_ee, 24, + NL_STRING( 45, T_MAY_IGNORE, dump_ee_reason, 32) + NL_STRING( 46, T_MAY_IGNORE, seen_digest, SHARED_SECRET_MAX) + NL_STRING( 47, T_MAY_IGNORE, calc_digest, SHARED_SECRET_MAX) + NL_INT64( 48, T_MAY_IGNORE, ee_sector) + NL_INT64( 49, T_MAY_IGNORE, ee_block_id) + NL_STRING( 50, T_MAY_IGNORE, ee_data, 32 << 10) +) + +NL_PACKET(start_ov, 25, +) + +#undef NL_PACKET +#undef NL_INTEGER +#undef NL_INT64 +#undef NL_BIT +#undef NL_STRING + --- linux-2.6.27.orig/ubuntu/drbd/linux/drbd.h +++ linux-2.6.27/ubuntu/drbd/linux/drbd.h @@ -0,0 +1,355 @@ +/* + drbd.h + Kernel module for 2.6.x Kernels + + This file is part of DRBD by Philipp Reisner and Lars Ellenberg. + + Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. + Copyright (C) 2001-2008, Philipp Reisner . + Copyright (C) 2001-2008, Lars Ellenberg . + + drbd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + drbd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with drbd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ +#ifndef DRBD_H +#define DRBD_H +#include + +#include + +#ifdef __KERNEL__ +#include +#include +#else +#include +#include +#include + +/* Altough the Linux source code makes a difference between + generic endiness and the bitfields' endianess, there is no + architecture as of Linux-2.6.24-rc4 where the bitfileds' endianess + does not match the generic endianess. */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define __LITTLE_ENDIAN_BITFIELD +#elif __BYTE_ORDER == __BIG_ENDIAN +#define __BIG_ENDIAN_BITFIELD +#else +# error "sorry, weird endianness on this box" +#endif + +#endif + + +enum io_error_handler { + PassOn, /* FIXME should the better be named "Ignore"? */ + CallIOEHelper, + Detach +}; + +enum fencing_policy { + DontCare, + Resource, + Stonith +}; + +enum disconnect_handler { + Reconnect, + DropNetConf, + FreezeIO +}; + +enum after_sb_handler { + Disconnect, + DiscardYoungerPri, + DiscardOlderPri, + DiscardZeroChg, + DiscardLeastChg, + DiscardLocal, + DiscardRemote, + Consensus, + DiscardSecondary, + CallHelper, + Violently +}; + +/* KEEP the order, do not delete or insert! + * Or change the API_VERSION, too. */ +enum ret_codes { + RetCodeBase = 100, + NoError, /* 101 ... */ + LAAlreadyInUse, + OAAlreadyInUse, + LDNameInvalid, + MDNameInvalid, + LDAlreadyInUse, + LDNoBlockDev, + MDNoBlockDev, + LDOpenFailed, + MDOpenFailed, + LDDeviceTooSmall, + MDDeviceTooSmall, + LDNoConfig, + LDMounted, + MDMounted, + LDMDInvalid, + LDDeviceTooLarge, + MDIOError, + MDInvalid, + CRAMAlgNotAvail, + CRAMAlgNotDigest, + KMallocFailed, + DiscardNotAllowed, + HaveDiskConfig, + HaveNetConfig, + UnknownMandatoryTag, + MinorNotKnown, + StateNotAllowed, + GotSignal, /* EINTR */ + NoResizeDuringResync, + APrimaryNodeNeeded, + SyncAfterInvalid, + SyncAfterCycle, + PauseFlagAlreadySet, + PauseFlagAlreadyClear, + DiskLowerThanOutdated, /* obsolete, now SS_LowerThanOutdated */ + UnknownNetLinkPacket, + HaveNoDiskConfig, + ProtocolCRequired, + VMallocFailed, + IntegrityAlgNotAvail, + IntegrityAlgNotDigest, + CPUMaskParseFailed, + CSUMSAlgNotAvail, + CSUMSAlgNotDigest, + VERIFYAlgNotAvail, + VERIFYAlgNotDigest, + CSUMSResyncRunning, + VERIFYIsRunning, + DataOfWrongCurrent, + + /* insert new ones above this line */ + AfterLastRetCode, +}; + +#define DRBD_PROT_A 1 +#define DRBD_PROT_B 2 +#define DRBD_PROT_C 3 + +enum drbd_role { + Unknown = 0, + Primary = 1, /* role */ + Secondary = 2, /* role */ + role_mask = 3, +}; + +/* The order of these constants is important. + * The lower ones (=WFReportParams ==> There is a socket + * + * THINK + * Skipped should be < Connected, + * so writes on a Primary after Skipped sync are not mirrored either ? + */ +enum drbd_conns { + StandAlone, + Disconnecting, /* Temporal state on the way to StandAlone. */ + Unconnected, /* >= Unconnected -> inc_net() succeeds */ + + /* These temporal states are all used on the way + * from >= Connected to Unconnected. + * The 'disconnect reason' states + * I do not allow to change beween them. */ + Timeout, + BrokenPipe, + NetworkFailure, + ProtocolError, + TearDown, + + WFConnection, + WFReportParams, /* we have a socket */ + Connected, /* we have introduced each other */ + StartingSyncS, /* starting full sync by IOCTL. */ + StartingSyncT, /* stariing full sync by IOCTL. */ + WFBitMapS, + WFBitMapT, + WFSyncUUID, + + /* The distance between original state and pause + * state must be the same for source and target. (+2) + * All SyncStates are tested with this comparison + * xx >= SyncSource && xx <= PausedSyncT */ + SyncSource, + SyncTarget, + VerifyS, + VerifyT, + PausedSyncS, + PausedSyncT, + conn_mask = 31 +}; + +enum drbd_disk_state { + Diskless, + Attaching, /* In the process of reading the meta-data */ + Failed, /* Becomes Diskless as soon as we told it the peer */ + /* when >= Failed it is legal to access mdev->bc */ + Negotiating, /* Late attaching state, we need to talk to the peer */ + Inconsistent, + Outdated, + DUnknown, /* Only used for the peer, never for myself */ + Consistent, /* Might be Outdated, might be UpToDate ... */ + UpToDate, /* Only this disk state allows applications' IO ! */ + disk_mask = 15 +}; + +union drbd_state_t { +/* According to gcc's docs is the ... + * The order of allocation of bit-fields within a unit (C90 6.5.2.1, C99 6.7.2.1). + * Determined by ABI. + * pointed out by Maxim Uvarov q + * even though we transmit as "cpu_to_be32(state)", + * the offsets of the bitfields still need to be swapped + * on different endianess. + */ + struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + unsigned role : 2 ; /* 3/4 primary/secondary/unknown */ + unsigned peer : 2 ; /* 3/4 primary/secondary/unknown */ + unsigned conn : 5 ; /* 17/32 cstates */ + unsigned disk : 4 ; /* 8/16 from Diskless to UpToDate */ + unsigned pdsk : 4 ; /* 8/16 from Diskless to UpToDate */ + unsigned susp : 1 ; /* 2/2 IO suspended no/yes */ + unsigned aftr_isp : 1 ; /* isp .. imposed sync pause */ + unsigned peer_isp : 1 ; + unsigned user_isp : 1 ; + unsigned _pad : 11; /* 0 unused */ +#elif defined(__BIG_ENDIAN_BITFIELD) + unsigned _pad : 11; /* 0 unused */ + unsigned user_isp : 1 ; + unsigned peer_isp : 1 ; + unsigned aftr_isp : 1 ; /* isp .. imposed sync pause */ + unsigned susp : 1 ; /* 2/2 IO suspended no/yes */ + unsigned pdsk : 4 ; /* 8/16 from Diskless to UpToDate */ + unsigned disk : 4 ; /* 8/16 from Diskless to UpToDate */ + unsigned conn : 5 ; /* 17/32 cstates */ + unsigned peer : 2 ; /* 3/4 primary/secondary/unknown */ + unsigned role : 2 ; /* 3/4 primary/secondary/unknown */ +#else +# error "this endianess is not supported" +#endif + }; + unsigned int i; +}; + +enum set_st_err { + SS_CW_NoNeed = 4, + SS_CW_Success = 3, + SS_NothingToDo = 2, + SS_Success = 1, + SS_UnknownError = 0, /* Used to sleep longer in _drbd_request_state */ + SS_TwoPrimaries = -1, + SS_NoUpToDateDisk = -2, + SS_BothInconsistent = -4, + SS_SyncingDiskless = -5, + SS_ConnectedOutdates = -6, + SS_PrimaryNOP = -7, + SS_ResyncRunning = -8, + SS_AlreadyStandAlone = -9, + SS_CW_FailedByPeer = -10, + SS_IsDiskLess = -11, + SS_DeviceInUse = -12, + SS_NoNetConfig = -13, + SS_NoVerifyAlg = -14, /* drbd-8.2 only */ + SS_NeedConnection = -15, /* drbd-8.2 only */ + SS_LowerThanOutdated = -16, + SS_NotSupported = -17, /* drbd-8.2 only */ + SS_InTransientState = -18, /* Retry after the next state change */ + SS_ConcurrentStChg = -19, /* Concurrent cluster side state change! */ +}; + + +/* from drbd_strings.c */ +extern const char *conns_to_name(enum drbd_conns); +extern const char *roles_to_name(enum drbd_role); +extern const char *disks_to_name(enum drbd_disk_state); +extern const char *set_st_err_name(enum set_st_err); + +#ifndef BDEVNAME_SIZE +# define BDEVNAME_SIZE 32 +#endif + +#define SHARED_SECRET_MAX 64 + +enum MetaDataFlags { + __MDF_Consistent, + __MDF_PrimaryInd, + __MDF_ConnectedInd, + __MDF_FullSync, + __MDF_WasUpToDate, + __MDF_PeerOutDated /* or worse (e.g. invalid). */ +}; +#define MDF_Consistent (1<<__MDF_Consistent) +#define MDF_PrimaryInd (1<<__MDF_PrimaryInd) +#define MDF_ConnectedInd (1<<__MDF_ConnectedInd) +#define MDF_FullSync (1<<__MDF_FullSync) +#define MDF_WasUpToDate (1<<__MDF_WasUpToDate) +#define MDF_PeerOutDated (1<<__MDF_PeerOutDated) + +enum UuidIndex { + Current, + Bitmap, + History_start, + History_end, + UUID_SIZE, /* nl-packet: number of dirty bits */ + UUID_FLAGS, /* nl-packet: flags */ + EXT_UUID_SIZE /* Everything. */ +}; + +#define UUID_JUST_CREATED ((__u64)4) + +#define DRBD_MAGIC 0x83740267 +#define BE_DRBD_MAGIC __constant_cpu_to_be32(DRBD_MAGIC) + +/* these are of type "int" */ +#define DRBD_MD_INDEX_INTERNAL -1 +#define DRBD_MD_INDEX_FLEX_EXT -2 +#define DRBD_MD_INDEX_FLEX_INT -3 + +/* Start of the new netlink/connector stuff */ + +#define DRBD_NL_CREATE_DEVICE 0x01 +#define DRBD_NL_SET_DEFAULTS 0x02 + +/* The following line should be moved over to linux/connector.h + * when the time comes */ +//#define CN_IDX_DRBD 0x5 +//#define CN_VAL_DRBD 0x1 + +struct drbd_nl_cfg_req { + int packet_type; + int drbd_minor; + int flags; + unsigned short tag_list[]; +}; + +struct drbd_nl_cfg_reply { + int packet_type; + int minor; + int ret_code; /* enum ret_code or set_st_err_t */ + unsigned short tag_list[]; /* only used with get_* calls */ +}; + +#endif --- linux-2.6.27.orig/ubuntu/qc-usb/qc-pb0100.c +++ linux-2.6.27/ubuntu/qc-usb/qc-pb0100.c @@ -0,0 +1,377 @@ +/* Start of file */ + +/* {{{ [fold] Comments */ +/* + * qce-ga, linux V4L driver for the QuickCam Express and Dexxa QuickCam + * + * pb0100.c - PB0100 Sensor Implementation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +/* }}} */ + +#include "quickcam.h" + +/* I2C Address */ +#define PB_ADDR 0xBA + +/* {{{ [fold] I2C Registers */ +#define PB_IDENT 0x00 /* R0 Chip Version */ +#define PB_RSTART 0x01 /* R1 Row Window Start */ +#define PB_CSTART 0x02 /* R2 Column Window Start */ +#define PB_RWSIZE 0x03 /* R3 Row Window Size */ +#define PB_CWSIZE 0x04 /* R4 Column Window Size */ +#define PB_CFILLIN 0x05 /* R5 Column Fill-In */ +#define PB_VBL 0x06 /* R6 Vertical Blank Count */ +#define PB_CONTROL 0x07 /* R7 Control Mode */ +#define PB_FINTTIME 0x08 /* R8 Integration Time/Frame Unit Count */ +#define PB_RINTTIME 0x09 /* R9 Integration Time/Row Unit Count */ +#define PB_ROWSPEED 0x0A /* R10 Row Speed Control */ +#define PB_ABORTFRAME 0x0B /* R11 Abort Frame */ +/* #define PB_R12 0x0C R12 Reserved */ +#define PB_RESET 0x0D /* R13 Reset */ +#define PB_EXPGAIN 0x0E /* R14 Exposure Gain Command */ +#define PB_R15 0x0F /* R15 Expose0 */ +#define PB_R16 0x10 /* R16 Expose1 */ +#define PB_R17 0x11 /* R17 Expose2 */ +#define PB_R18 0x12 /* R18 Low0_DAC */ +#define PB_R19 0x13 /* R19 Low1_DAC */ +#define PB_R20 0x14 /* R20 Low2_DAC */ +#define PB_R21 0x15 /* R21 Threshold11 */ +#define PB_R22 0x16 /* R22 Threshold0x */ +#define PB_UPDATEINT 0x17 /* R23 Update Interval */ +#define PB_R24 0x18 /* R24 High_DAC */ +#define PB_R25 0x19 /* R25 Trans0H */ +#define PB_R26 0x1A /* R26 Trans1L */ +#define PB_R27 0x1B /* R27 Trans1H */ +#define PB_R28 0x1C /* R28 Trans2L */ +/* #define PB_R29 0x1D R29 Reserved */ +/* #define PB_R30 0x1E R30 Reserved */ +#define PB_R31 0x1F /* R31 Wait to Read */ +#define PB_PREADCTRL 0x20 /* R32 Pixel Read Control Mode */ +#define PB_R33 0x21 /* R33 IREF_VLN */ +#define PB_R34 0x22 /* R34 IREF_VLP */ +#define PB_R35 0x23 /* R35 IREF_VLN_INTEG */ +#define PB_R36 0x24 /* R36 IREF_MASTER */ +#define PB_R37 0x25 /* R37 IDACP */ +#define PB_R38 0x26 /* R38 IDACN */ +#define PB_R39 0x27 /* R39 DAC_Control_Reg */ +#define PB_R40 0x28 /* R40 VCL */ +#define PB_R41 0x29 /* R41 IREF_VLN_ADCIN */ +/* #define PB_R42 0x2A R42 Reserved */ +#define PB_G1GAIN 0x2B /* R43 Green 1 Gain */ +#define PB_BGAIN 0x2C /* R44 Blue Gain */ +#define PB_RGAIN 0x2D /* R45 Red Gain */ +#define PB_G2GAIN 0x2E /* R46 Green 2 Gain */ +#define PB_R47 0x2F /* R47 Dark Row Address */ +#define PB_R48 0x30 /* R48 Dark Row Options */ +/* #define PB_R49 0x31 R49 Reserved */ +#define PB_R50 0x32 /* R50 Image Test Data */ +#define PB_ADCMAXGAIN 0x33 /* R51 Maximum Gain */ +#define PB_ADCMINGAIN 0x34 /* R52 Minimum Gain */ +#define PB_ADCGLOBALGAIN 0x35 /* R53 Global Gain */ +#define PB_R54 0x36 /* R54 Maximum Frame */ +#define PB_R55 0x37 /* R55 Minimum Frame */ +/* #define PB_R56 0x38 R56 Reserved */ +#define PB_VOFFSET 0x39 /* R57 VOFFSET */ +#define PB_R58 0x3A /* R58 Snap-Shot Sequence Trigger */ +#define PB_ADCGAINH 0x3B /* R59 VREF_HI */ +#define PB_ADCGAINL 0x3C /* R60 VREF_LO */ +/* #define PB_R61 0x3D R61 Reserved */ +/* #define PB_R62 0x3E R62 Reserved */ +/* #define PB_R63 0x3F R63 Reserved */ +#define PB_R64 0x40 /* R64 Red/Blue Gain */ +#define PB_R65 0x41 /* R65 Green 2/Green 1 Gain */ +#define PB_R66 0x42 /* R66 VREF_HI/LO */ +#define PB_R67 0x43 /* R67 Integration Time/Row Unit Count */ +#define PB_R240 0xF0 /* R240 ADC Test */ +#define PB_R241 0xF1 /* R241 Chip Enable */ +/* #define PB_R242 0xF2 R242 Reserved */ +/* }}} */ + +#define I2C_SETW_CHECK(reg,val) if ((r = qc_i2c_setw(qc,(reg),(val)))<0) goto fail +#define STV_SET_CHECK(reg,val) if ((r = qc_stv_set(qc,(reg),(val)))<0) goto fail +#define STV_SETW_CHECK(reg,val) if ((r = qc_stv_setw(qc,(reg),(val)))<0) goto fail + +/* + * The spec file for the PB-0100 suggests the following for best quality + * images after the sensor has been reset : + * + * PB_ADCGAINL = R60 = 0x03 (3 dec) : sets low reference of ADC to produce good black level + * PB_PREADCTRL = R32 = 0x1400 (5120 dec) : Enables global gain changes through R53 + * PB_ADCMINGAIN = R52 = 0x10 (16 dec) : Sets the minimum gain for auto-exposure + * PB_ADCGLOBALGAIN = R53 = 0x10 (16 dec) : Sets the global gain + * PB_EXPGAIN = R14 = 0x11 (17 dec) : Sets the auto-exposure value + * PB_UPDATEINT = R23 = 0x02 (2 dec) : Sets the speed on auto-exposure routine + * PB_CFILLIN = R5 = 0x0E (14 dec) : Sets the frame rate + */ + +/* {{{ [fold] pb0100_init: Initialise parameters of PB100 sensor */ +static int pb0100_init(struct quickcam *qc) +{ + static const Bool natural = TRUE; /* Disable flicker control for natural lighting? */ + struct qc_sensor_data *sd = &qc->sensor_data; + int r; + + if (sd->compress) return -EINVAL; + sd->maxwidth = 360; + sd->maxheight = 288; /* Sensor has 296 rows but top 8 are opaque */ + if (sd->subsample) { + sd->maxwidth /= 2; + sd->maxheight /= 2; + } + sd->exposure = 0; + + STV_SET_CHECK(STV_REG00, 1); + STV_SET_CHECK(STV_SCAN_RATE, 0); + + /* Reset sensor */ + I2C_SETW_CHECK(PB_RESET, 1); + if ((r = qc_i2c_wait(qc))<0) goto fail; + I2C_SETW_CHECK(PB_RESET, 0); + if ((r = qc_i2c_wait(qc))<0) goto fail; + + /* Disable chip */ + I2C_SETW_CHECK(PB_CONTROL, BIT(5)|BIT(3)); + if ((r = qc_i2c_wait(qc))<0) goto fail; + + /* Gain stuff...*/ + I2C_SETW_CHECK(PB_PREADCTRL, BIT(12)|BIT(10)|BIT(6)); + I2C_SETW_CHECK(PB_ADCGLOBALGAIN, 12); + if ((r = qc_i2c_wait(qc))<0) goto fail; + + /* Set up auto-exposure */ + I2C_SETW_CHECK(PB_R28, 12); /* ADC VREF_HI new setting for a transition from the Expose1 to the Expose2 setting */ + I2C_SETW_CHECK(PB_ADCMAXGAIN, 180); /* gain max for autoexposure */ + I2C_SETW_CHECK(PB_ADCMINGAIN, 12); /* gain min for autoexposure */ + I2C_SETW_CHECK(PB_R54, 3); /* Maximum frame integration time (programmed into R8) allowed for auto-exposure routine */ + I2C_SETW_CHECK(PB_R55, 0); /* Minimum frame integration time (programmed into R8) allowed for auto-exposure routine */ + I2C_SETW_CHECK(PB_UPDATEINT, 1); + I2C_SETW_CHECK(PB_R15, 800); /* R15 Expose0 (maximum that auto-exposure may use) */ + I2C_SETW_CHECK(PB_R17, 10); /* R17 Expose2 (minimum that auto-exposure may use) */ + + if (qc->settings.adaptive) { + I2C_SETW_CHECK(PB_EXPGAIN, (natural?BIT(6):0)|BIT(4)|BIT(0)); + } else { + I2C_SETW_CHECK(PB_EXPGAIN, 0); + } + if ((r = qc_i2c_wait(qc))<0) goto fail; + + I2C_SETW_CHECK(PB_VOFFSET, 0); /* 0x14 */ + I2C_SETW_CHECK(PB_ADCGAINH, 11); /* 0x0D */ + I2C_SETW_CHECK(PB_ADCGAINL, 0); /* Set black level (important!) */ + + /* ??? */ + STV_SET_CHECK(STV_REG04, 0x07); + STV_SET_CHECK(STV_REG03, 0x45); + STV_SET_CHECK(STV_REG00, 0x11); + + /* Set mode */ + STV_SET_CHECK(STV_Y_CTRL, sd->subsample ? 2 : 1); /* 0x02: half, 0x01: full FIXME: this doesn't work! */ + STV_SET_CHECK(STV_X_CTRL, sd->subsample ? 6 : 0x0A); /* 0x06: Half, 0x0A: Full */ + + /* ISO-Size (0x27b: 635... why? - HDCS uses 847) */ + STV_SETW_CHECK(STV_ISO_SIZE, 847); + + /* Setup sensor window */ + I2C_SETW_CHECK(PB_RSTART, 0); + I2C_SETW_CHECK(PB_CSTART, 0); + I2C_SETW_CHECK(PB_RWSIZE, 240-1); /* 0xF7: 240 */ + I2C_SETW_CHECK(PB_CWSIZE, 320-1); /* 0x13F: 320 */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + + /* Scan rate? */ + STV_SET_CHECK(STV_SCAN_RATE, sd->subsample ? 0x10 : 0x20); /* larger -> slower */ + + /* Scan/timing for the sensor */ + I2C_SETW_CHECK(PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1)); + I2C_SETW_CHECK(PB_CFILLIN, 14); + I2C_SETW_CHECK(PB_VBL, 0); + I2C_SETW_CHECK(PB_FINTTIME, 0); + I2C_SETW_CHECK(PB_RINTTIME, 123); + if ((r = qc_i2c_wait(qc))<0) goto fail; + + STV_SET_CHECK(STV_REG01, 0xC2); + STV_SET_CHECK(STV_REG02, 0xB0); + +fail: return r; +} +/* }}} */ +/* {{{ [fold] pb0100_set_exposure() */ +static int pb0100_set_exposure(struct quickcam *qc, unsigned int val) +{ + int r; + struct qc_sensor_data *sd = &qc->sensor_data; + val >>= 7; + if (val==sd->exposure) return 0; + sd->exposure = val; + I2C_SETW_CHECK(PB_RINTTIME, val); /* R9 */ +fail: return r; +} +/* }}} */ +/* {{{ [fold] pb0100_set_gains() */ +static int pb0100_set_gains(struct quickcam *qc, u16 hue, u16 sat, u16 val) +{ + struct qc_sensor_data *sd = &qc->sensor_data; + unsigned int rgain, bgain, ggain; + int r; + qc_hsv2rgb(hue, sat, val, &rgain, &bgain, &ggain); + rgain >>= 8; /* After this the values are 0..255 */ + ggain >>= 8; + bgain >>= 8; + if (rgain==sd->rgain && ggain==sd->ggain && bgain==sd->bgain) return 0; + sd->rgain = rgain; + sd->ggain = ggain; + sd->bgain = bgain; + I2C_SETW_CHECK(PB_RGAIN, rgain); /* R43 */ + I2C_SETW_CHECK(PB_G1GAIN, ggain); /* R44 */ + I2C_SETW_CHECK(PB_G2GAIN, ggain); /* R45 */ + I2C_SETW_CHECK(PB_BGAIN, bgain); /* R46 */ +fail: return r; +} +/* }}} */ +/* {{{ [fold] pb0100_set_levels() */ +static int pb0100_set_levels(struct quickcam *qc, unsigned int exp, unsigned int gain, unsigned int hue, unsigned int sat) +{ + int r; + /* When automatic exposure control in Photobit is used, the exposure/gain + * registers shouldn't be touched. The sensor may update them only rarely + * and if they're changed they may be incorrect until the sensor updates + * the registers next time. + * FIXME: shouldn't qc-driver.c ensure this function isnt called when adaptive is used? + */ + if (qc->settings.adaptive) return 0; + if ((r = pb0100_set_exposure(qc, exp))<0) goto fail; + pb0100_set_gains(qc, hue, sat, gain); +fail: return r; +} +/* }}} */ +/* {{{ [fold] pb0100_set_target: Set target brightness for sensor autoexposure, val=0..65535 */ +static int pb0100_set_target(struct quickcam *qc, unsigned int val) +{ + struct qc_sensor_data *sd = &qc->sensor_data; + unsigned int totalpixels, brightpixels, darkpixels; + int r; + + val >>= 8; /* val = 0..255 (0-50% of bright pixels) */ + if (val==sd->exposure) return 0; + sd->exposure = val; + + /* Number of pixels counted by the sensor when subsampling the pixels. + * Slightly larger than the real value to avoid oscillation */ + totalpixels = sd->width * sd->height; + totalpixels = totalpixels/(8*8) + totalpixels/(64*64); + + brightpixels = (totalpixels * val) >> 8; + darkpixels = totalpixels - brightpixels; + I2C_SETW_CHECK(PB_R21, brightpixels); /* R21 */ + I2C_SETW_CHECK(PB_R22, darkpixels); /* R22 */ +fail: return r; +} +/* }}} */ +/* {{{ [fold] pb0100_set_size: Set window size */ +/* Window location and size are controlled by R1, R2, R3 and R4. + * The default size is CIF (352x288) with to right at (4,12) + * and bottom left at (355, 299) + * + * We try to ensure that the captured area is in the center of + * the camera purely because that's nicer. It would be better + * if the PB0100 sensor supported capture scaling! + * + * We do it in on step otherwise size change may take more + * than one frame (like xawtv who tests 64x48 and uses 352x288) + * 3072 = 64x48, 16896 = 352x48, 101376 = 352x288. + */ +static int pb0100_set_size(struct quickcam *qc, unsigned int w, unsigned int h) +{ + static const unsigned int originx = 0; /* First visible pixel */ + static const unsigned int originy = 8; + static const unsigned int maxwidth = 360; /* Visible sensor size */ + static const unsigned int maxheight = 288; + struct qc_sensor_data *sd = &qc->sensor_data; + int x, y; + int r; + + sd->width = w; + sd->height = h; + if (sd->subsample) { + w *= 2; + h *= 2; + } + x = (maxwidth - w)/2; /* Center image by computing upper-left corner */ + y = (maxheight - h)/2; + x = (x + originx) & ~1; /* Must be even to align to the Bayer pattern */ + y = (y + originy) & ~1; + I2C_SETW_CHECK(PB_RSTART, y); /* PB_RSTART = 12 + y */ + I2C_SETW_CHECK(PB_CSTART, x); /* PB_CSTART = 4 + x */ + I2C_SETW_CHECK(PB_RWSIZE, h - 1); /* PB_RWSIZE = h - 1 */ + I2C_SETW_CHECK(PB_CWSIZE, w - 1); /* PB_CWSIZE = w - 1 */ + + if (qc->settings.adaptive) { + /* The automatic exposure counts need to be recomputed when size is changed */ + x = sd->exposure << 8; + sd->exposure = -1; + if ((r = pb0100_set_target(qc, x))<0) goto fail; + } + + r = qc_i2c_wait(qc); +fail: return r; +} +/* }}} */ +/* {{{ [fold] pb0100_start: Start grabbing */ +static int pb0100_start(struct quickcam *qc) +{ + int r; + I2C_SETW_CHECK(PB_CONTROL, BIT(5)|BIT(3)|BIT(1)); + r = qc_i2c_wait(qc); +fail: return r; +} +/* }}} */ +/* {{{ [fold] pb0100_stop: Stop grabbing */ +static int pb0100_stop(struct quickcam *qc) +{ + int r; + I2C_SETW_CHECK(PB_ABORTFRAME, 1); + if ((r = qc_i2c_wait(qc))<0) goto fail; + I2C_SETW_CHECK(PB_CONTROL, BIT(5)|BIT(3)); /* Set bit 1 to zero */ + r = qc_i2c_wait(qc); +fail: return r; +} +/* }}} */ + +/* {{{ [fold] struct qc_sensor qc_sensor_pb0100 */ +const struct qc_sensor qc_sensor_pb0100 = { + name: "PB-0100/0101", + manufacturer: "Photobit", + init: pb0100_init, + start: pb0100_start, + stop: pb0100_stop, + set_size: pb0100_set_size, + set_levels: pb0100_set_levels, + set_target: pb0100_set_target, + /* Exposure and gain control information */ + autoexposure: TRUE, + /* Information needed to access the sensor via I2C */ + reg23: 1, + i2c_addr: PB_ADDR, + /* Identification information used for auto-detection */ + id_reg: PB_IDENT, + id: 0x64, + length_id: 2, +}; +/* }}} */ + +/* End of file */ --- linux-2.6.27.orig/ubuntu/qc-usb/qc-hdcs.c +++ linux-2.6.27/ubuntu/qc-usb/qc-hdcs.c @@ -0,0 +1,734 @@ +/* Start of file */ + +/* {{{ [fold] Comments */ +/* + * qc-usb, linux V4L driver for the Logitech QuickCam USB camera family + * + * qc-hdcs.c - HDCS Sensor Implementation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +/* }}} */ + +#include "quickcam.h" + +/* LSB bit of I2C or register address signifies write (0) or read (1) */ + +/* I2C Address */ +#define HDCS_ADDR (0x55<<1) + +/* {{{ [fold] I2C registers */ +/* I2C Registers common for both HDCS-1000/1100 and HDCS-1020 */ +#define HDCS_IDENT (0x00<<1) /* Identifications Register */ +#define HDCS_STATUS (0x01<<1) /* Status Register */ +#define HDCS_IMASK (0x02<<1) /* Interrupt Mask Register */ +#define HDCS_PCTRL (0x03<<1) /* Pad Control Register */ +#define HDCS_PDRV (0x04<<1) /* Pad Drive Control Register */ +#define HDCS_ICTRL (0x05<<1) /* Interface Control Register */ +#define HDCS_ITMG (0x06<<1) /* Interface Timing Register */ +#define HDCS_BFRAC (0x07<<1) /* Baud Fraction Register */ +#define HDCS_BRATE (0x08<<1) /* Baud Rate Register */ +#define HDCS_ADCCTRL (0x09<<1) /* ADC Control Register */ +#define HDCS_FWROW (0x0A<<1) /* First Window Row Register */ +#define HDCS_FWCOL (0x0B<<1) /* First Window Column Register */ +#define HDCS_LWROW (0x0C<<1) /* Last Window Row Register */ +#define HDCS_LWCOL (0x0D<<1) /* Last Window Column Register */ +#define HDCS_TCTRL (0x0E<<1) /* Timing Control Register */ +#define HDCS_ERECPGA (0x0F<<1) /* PGA Gain Register: Even Row, Even Column */ +#define HDCS_EROCPGA (0x10<<1) /* PGA Gain Register: Even Row, Odd Column */ +#define HDCS_ORECPGA (0x11<<1) /* PGA Gain Register: Odd Row, Even Column */ +#define HDCS_OROCPGA (0x12<<1) /* PGA Gain Register: Odd Row, Odd Column */ +#define HDCS_ROWEXPL (0x13<<1) /* Row Exposure Low Register */ +#define HDCS_ROWEXPH (0x14<<1) /* Row Exposure High Register */ + +/* I2C Registers only for HDCS-1000/1100 */ +#define HDCS00_SROWEXPL (0x15<<1) /* Sub-Row Exposure Low Register */ +#define HDCS00_SROWEXPH (0x16<<1) /* Sub-Row Exposure High Register */ +#define HDCS00_CONFIG (0x17<<1) /* Configuration Register */ +#define HDCS00_CONTROL (0x18<<1) /* Control Register */ + +/* I2C Registers only for HDCS-1020 */ +#define HDCS20_SROWEXP (0x15<<1) /* Sub-Row Exposure Register */ +#define HDCS20_ERROR (0x16<<1) /* Error Control Register */ +#define HDCS20_ITMG2 (0x17<<1) /* Interface Timing 2 Register */ +#define HDCS20_ICTRL2 (0x18<<1) /* Interface Control 2 Register */ +#define HDCS20_HBLANK (0x19<<1) /* Horizontal Blank Register */ +#define HDCS20_VBLANK (0x1A<<1) /* Vertical Blank Register */ +#define HDCS20_CONFIG (0x1B<<1) /* Configuration Register */ +#define HDCS20_CONTROL (0x1C<<1) /* Control Register */ +/* }}} */ + +#define IS_870(qc) (GET_PRODUCTID(qc)==0x870) +#define IS_1020(qc) ((qc)->sensor_data.sensor->flag != 0) +#define GET_CONTROL (IS_1020(qc) ? HDCS20_CONTROL : HDCS00_CONTROL) +#define GET_CONFIG (IS_1020(qc) ? HDCS20_CONFIG : HDCS00_CONFIG) + +#define I2C_SET_CHECK(reg,val) if ((r = qc_i2c_set(qc,(reg),(val)))<0) goto fail +#define STV_SET_CHECK(reg,val) if ((r = qc_stv_set(qc,(reg),(val)))<0) goto fail +#define STV_SETW_CHECK(reg,val) if ((r = qc_stv_setw(qc,(reg),(val)))<0) goto fail + +/* Enables experimental compressed mode, works with HDCS-1000/0x840, + mode derived from USB logs obtained from HDCS-1020/0x870 + (should give 640x480), not tested with HDCS-1020. + On HDCS-1000, gives 30 fps but data is in unknown format, + observed image width 163 bytes (how many pixels?). + Frame length appears to vary, typically 3300-4550 bytes. + (apparently quite simple, however). + Use this with DUMPDATA mode. */ +#define HDCS_COMPRESS 0 + +#if HDCS_COMPRESS +/* {{{ [fold] hdcs_compress_init(struct quickcam *qc, int flags) */ +static int hdcs_compress_init(struct quickcam *qc, int flags) +{ + int r; + + if (flags & 1) { + /************************************** Plugin camera **************************************/ + + STV_SET_CHECK(0x1440, 0x00); /* Turn on/off isochronous stream */ + // if ((r = qc_stv_getw(qc, 0xE00A)) != 0x0870) /* ProductId */ + // PDEBUG("Bad value 0x%02X in reg 0xE00A, should be 0x0870", r); + + STV_SET_CHECK(0x0423, 0x05); /* Unknown (sometimes 4, sometimes 5) */ + // Warning: I2C address 0xBA is invalid + // if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0) /* Identifications Register */ + // PDEBUG("error reading sensor reg HDCS_IDENT"); + // if ((r = qc_stv_get(qc, 0x0424)) != 0x0a) /* Successfully transmitted I2C commands */ + // PDEBUG("Bad value 0x%02X in reg 0x0424, should be 0x0a", r); + STV_SET_CHECK(0x0423, 0x04); /* Unknown (sometimes 4, sometimes 5) */ + + if ((r = qc_stv_get(qc, 0x1444)) != 0x10) /* ? */ + PDEBUG("Bad value 0x%02X in reg 0x1444, should be 0x10", r); + if ((r = qc_stv_get(qc, 0x1444)) != 0x10) /* ? */ + PDEBUG("Bad value 0x%02X in reg 0x1444, should be 0x10", r); + if ((r = qc_stv_get(qc, 0x1444)) != 0x10) /* ? */ + PDEBUG("Bad value 0x%02X in reg 0x1444, should be 0x10", r); + + STV_SET_CHECK(0x0423, 0x05); /* Unknown (sometimes 4, sometimes 5) */ + // Warning: I2C address 0x20 is invalid + // if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0) /* Identifications Register */ + // PDEBUG("error reading sensor reg HDCS_IDENT"); + // if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0) /* Identifications Register */ + // PDEBUG("error reading sensor reg HDCS_IDENT"); + // if ((r = qc_stv_get(qc, 0x0424)) != 0x0a) /* Successfully transmitted I2C commands */ + // PDEBUG("Bad value 0x%02X in reg 0x0424, should be 0x0a", r); + // Warning: I2C address 0x20 is invalid + // if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0) /* Identifications Register */ + // PDEBUG("error reading sensor reg HDCS_IDENT"); + // if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0) /* Identifications Register */ + // PDEBUG("error reading sensor reg HDCS_IDENT"); + // if ((r = qc_stv_get(qc, 0x0424)) != 0x0a) /* Successfully transmitted I2C commands */ + // PDEBUG("Bad value 0x%02X in reg 0x0424, should be 0x0a", r); + // Warning: I2C address 0x20 is invalid + // if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0) /* Identifications Register */ + // PDEBUG("error reading sensor reg HDCS_IDENT"); + // if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0) /* Identifications Register */ + // PDEBUG("error reading sensor reg HDCS_IDENT"); + // if ((r = qc_stv_get(qc, 0x0424)) != 0x0a) /* Successfully transmitted I2C commands */ + // PDEBUG("Bad value 0x%02X in reg 0x0424, should be 0x0a", r); + STV_SET_CHECK(0x0423, 0x04); /* Unknown (sometimes 4, sometimes 5) */ + STV_SET_CHECK(0x0423, 0x04); /* Unknown (sometimes 4, sometimes 5) */ + + // if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0) /* Identifications Register */ + // PDEBUG("error reading sensor reg HDCS_IDENT"); + // if ((r = qc_stv_get(qc, 0x0424)) != 0x02) /* Successfully transmitted I2C commands */ + // PDEBUG("Bad value 0x%02X in reg 0x0424, should be 0x02", r); + // if ((r = qc_stv_get(qc, 0x1410)) != 0x10) /* I2C area, first reg value */ + // PDEBUG("Bad value 0x%02X in reg 0x1410, should be 0x10", r); + + // if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0) /* Identifications Register */ + // PDEBUG("error reading sensor reg HDCS_IDENT"); + // if ((r = qc_stv_get(qc, 0x0424)) != 0x02) /* Successfully transmitted I2C commands */ + // PDEBUG("Bad value 0x%02X in reg 0x0424, should be 0x02", r); + // if ((r = qc_stv_get(qc, 0x1410)) != 0x10) /* I2C area, first reg value */ + // PDEBUG("Bad value 0x%02X in reg 0x1410, should be 0x10", r); + + STV_SET_CHECK(0x0423, 0x04); /* Unknown (sometimes 4, sometimes 5) */ + if ((r = qc_stv_get(qc, 0x0424)) != 0x02) /* Successfully transmitted I2C commands */ + PDEBUG("Bad value 0x%02X in reg 0x0424, should be 0x02", r); + STV_SET_CHECK(0x0423, 0x04); /* Unknown (sometimes 4, sometimes 5) */ + + // if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0) /* Identifications Register */ + // PDEBUG("error reading sensor reg HDCS_IDENT"); + // if ((r = qc_stv_get(qc, 0x0424)) != 0x02) /* Successfully transmitted I2C commands */ + // PDEBUG("Bad value 0x%02X in reg 0x0424, should be 0x02", r); + // if ((r = qc_stv_get(qc, 0x1410)) != 0x10) /* I2C area, first reg value */ + // PDEBUG("Bad value 0x%02X in reg 0x1410, should be 0x10", r); + + // if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0) /* Identifications Register */ + // PDEBUG("error reading sensor reg HDCS_IDENT"); + // if ((r = qc_stv_get(qc, 0x0424)) != 0x02) /* Successfully transmitted I2C commands */ + // PDEBUG("Bad value 0x%02X in reg 0x0424, should be 0x02", r); + // if ((r = qc_stv_get(qc, 0x1410)) != 0x10) /* I2C area, first reg value */ + // PDEBUG("Bad value 0x%02X in reg 0x1410, should be 0x10", r); + + STV_SET_CHECK(0x1500, 0x1D); /* ? */ + if ((r = qc_stv_get(qc, 0x1443)) != 0x00) /* Scan rate? */ + PDEBUG("Bad value 0x%02X in reg 0x1443, should be 0x00", r); + STV_SET_CHECK(0x1443, 0x01); /* Scan rate? */ + if ((r = qc_stv_get(qc, 0x1443)) != 0x01) /* Scan rate? */ + PDEBUG("Bad value 0x%02X in reg 0x1443, should be 0x01", r); + STV_SET_CHECK(0x1443, 0x00); /* Scan rate? */ + + I2C_SET_CHECK(HDCS_PCTRL, 0x63); /* Pad Control Register */ + I2C_SET_CHECK(HDCS_PDRV, 0x00); /* Pad Drive Control Register */ + I2C_SET_CHECK(GET_CONFIG, 0x08); /* Configuration Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + I2C_SET_CHECK(GET_CONTROL, 0x04); /* Control Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + I2C_SET_CHECK(GET_CONTROL, 0x00); /* Control Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + STV_SET_CHECK(0x1446, 0x00); /* ? */ + I2C_SET_CHECK(HDCS_PCTRL, 0x63); /* Pad Control Register */ + I2C_SET_CHECK(HDCS_PDRV, 0x00); /* Pad Drive Control Register */ + I2C_SET_CHECK(GET_CONFIG, 0x08); /* Configuration Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + if ((r = qc_stv_get(qc, 0x1445)) != 0x04) /* Turn LED on/off? */ + PDEBUG("Bad value 0x%02X in reg 0x1445, should be 0x04", r); + I2C_SET_CHECK(HDCS_ERECPGA, 0x3B); /* PGA Gain Register: Even Row, Even Column */ + I2C_SET_CHECK(HDCS_EROCPGA, 0x3B); /* PGA Gain Register: Even Row, Odd Column */ + I2C_SET_CHECK(HDCS_ORECPGA, 0x3B); /* PGA Gain Register: Odd Row, Even Column */ + I2C_SET_CHECK(HDCS_OROCPGA, 0x3B); /* PGA Gain Register: Odd Row, Odd Column */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + STV_SET_CHECK(0x1504, 0x07); /* ? */ + STV_SET_CHECK(0x1503, 0x45); /* ? */ + if ((r = qc_stv_get(qc, 0x1500)) != 0x1d) /* ? */ + PDEBUG("Bad value 0x%02X in reg 0x1500, should be 0x1d", r); + STV_SET_CHECK(0x1500, 0x1D); /* ? */ + // if ((r = qc_stv_getw(qc, 0xE00A)) != 0x0870) /* ProductId */ + // PDEBUG("Bad value 0x%02X in reg 0xE00A, should be 0x0870", r); + } + + if (flags & 2) { + /************************************** Start grabbing **************************************/ + + // if ((r = qc_stv_getw(qc, 0xE00A)) != 0x0870) /* ProductId */ + // PDEBUG("Bad value 0x%02X in reg 0xE00A, should be 0x0870", r); + STV_SET_CHECK(0x0423, 0x04); /* Unknown (sometimes 4, sometimes 5) */ + STV_SET_CHECK(0x1500, 0x1D); /* ? */ + I2C_SET_CHECK(HDCS_PCTRL, 0x63); /* Pad Control Register */ + I2C_SET_CHECK(HDCS_PDRV, 0x00); /* Pad Drive Control Register */ + I2C_SET_CHECK(GET_CONFIG, 0x08); /* Configuration Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + STV_SET_CHECK(0x15C3, 0x02); /* Y-Control, 1: 288 lines, 2: 144 lines */ + STV_SETW_CHECK(0x15C1, 0x027B); /* Max. ISO packet size */ + I2C_SET_CHECK(HDCS_FWROW, 0x00); /* First Window Row Register */ + I2C_SET_CHECK(HDCS_FWCOL, 0x0B); /* First Window Column Register */ + I2C_SET_CHECK(HDCS_LWROW, 0x3D); /* Last Window Row Register */ + I2C_SET_CHECK(HDCS_LWCOL, 0x5A); /* Last Window Column Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + STV_SET_CHECK(0x1680, 0x00); /* X-Control, 0xa: 352 columns, 6: 176 columns */ + I2C_SET_CHECK(HDCS_TCTRL, IS_1020(qc) ? 0xCB : 0x6B); /* Timing Control Register */ + I2C_SET_CHECK(HDCS_ICTRL, 0x00); /* Interface Control Register */ + I2C_SET_CHECK(HDCS_ITMG, 0x16); /* Interface Timing Register */ + if (IS_1020(qc)) I2C_SET_CHECK(HDCS20_HBLANK, 0xD6); /* Horizontal Blank Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + STV_SET_CHECK(0x1446, 0x00); /* ? */ + if ((r = qc_stv_get(qc, 0x1446)) != 0x00) /* ? */ + PDEBUG("Bad value 0x%02X in reg 0x1446, should be 0x00", r); + STV_SET_CHECK(0x1446, 0x00); /* ? */ + I2C_SET_CHECK(HDCS_ROWEXPL, 0x7B); /* Row Exposure Low Register */ + I2C_SET_CHECK(HDCS_ROWEXPH, 0x00); /* Row Exposure High Register */ + if (IS_1020(qc)) { + I2C_SET_CHECK(HDCS20_SROWEXP, 0x01); /* Sub-Row Exposure Register */ + } else { + I2C_SET_CHECK(HDCS00_SROWEXPL, 0x01<<2); + I2C_SET_CHECK(HDCS00_SROWEXPH, 0x00); + } + if ((r = qc_i2c_wait(qc))<0) goto fail; + STV_SET_CHECK(0x1501, 0xC2); /* ? */ + STV_SET_CHECK(0x1502, 0xB0); /* ? */ + I2C_SET_CHECK(HDCS_PCTRL, 0x63); /* Pad Control Register */ + I2C_SET_CHECK(HDCS_PDRV, 0x00); /* Pad Drive Control Register */ + I2C_SET_CHECK(GET_CONFIG, 0x08); /* Configuration Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + + /* Start isochronous streaming */ + I2C_SET_CHECK(GET_CONTROL, 0x04); /* Control Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + STV_SET_CHECK(0x1440, 0x01); /* Turn on/off isochronous stream */ + + if ((r = qc_stv_get(qc, 0x1445)) != 0x04) /* Turn LED on/off? */ + PDEBUG("Bad value 0x%02X in reg 0x1445, should be 0x04", r); + if ((r = qc_stv_get(qc, 0x1445)) != 0x04) /* Turn LED on/off? */ + PDEBUG("Bad value 0x%02X in reg 0x1445, should be 0x04", r); + if ((r = qc_stv_get(qc, 0x1445)) != 0x04) /* Turn LED on/off? */ + PDEBUG("Bad value 0x%02X in reg 0x1445, should be 0x04", r); + + /* Stop isochronous streaming */ + STV_SET_CHECK(0x1440, 0x00); /* Turn on/off isochronous stream */ + I2C_SET_CHECK(GET_CONTROL, 0x00); /* Control Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + + STV_SET_CHECK(0x0423, 0x04); /* Unknown (sometimes 4, sometimes 5) */ + STV_SET_CHECK(0x1500, 0x1D); /* ? */ + I2C_SET_CHECK(HDCS_PCTRL, 0x63); /* Pad Control Register */ + I2C_SET_CHECK(HDCS_PDRV, 0x00); /* Pad Drive Control Register */ + I2C_SET_CHECK(GET_CONFIG, 0x08); /* Configuration Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + STV_SET_CHECK(0x15C3, 0x02); /* Y-Control, 1: 288 lines, 2: 144 lines */ + STV_SETW_CHECK(0x15C1, 0x027B); /* Max. ISO packet size */ + I2C_SET_CHECK(HDCS_FWROW, 0x00); /* First Window Row Register */ + I2C_SET_CHECK(HDCS_FWCOL, 0x0B); /* First Window Column Register */ + I2C_SET_CHECK(HDCS_LWROW, 0x3D); /* Last Window Row Register */ + I2C_SET_CHECK(HDCS_LWCOL, 0x5A); /* Last Window Column Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + STV_SET_CHECK(0x1680, 0x00); /* X-Control, 0xa: 352 columns, 6: 176 columns */ + I2C_SET_CHECK(HDCS_TCTRL, IS_1020(qc) ? 0xCB : 0x6B); /* Timing Control Register */ + I2C_SET_CHECK(HDCS_ICTRL, 0x00); /* Interface Control Register */ + I2C_SET_CHECK(HDCS_ITMG, 0x16); /* Interface Timing Register */ + if (IS_1020(qc)) I2C_SET_CHECK(HDCS20_HBLANK, 0xD6); /* Horizontal Blank Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + STV_SET_CHECK(0x1446, 0x00); /* ? */ + if ((r = qc_stv_get(qc, 0x1446)) != 0x00) /* ? */ + PDEBUG("Bad value 0x%02X in reg 0x1446, should be 0x00", r); + STV_SET_CHECK(0x1446, 0x00); /* ? */ + I2C_SET_CHECK(HDCS_ROWEXPL, 0x7B); /* Row Exposure Low Register */ + I2C_SET_CHECK(HDCS_ROWEXPH, 0x00); /* Row Exposure High Register */ + if (IS_1020(qc)) { + I2C_SET_CHECK(HDCS20_SROWEXP, 0x01); /* Sub-Row Exposure Register */ + } else { + I2C_SET_CHECK(HDCS00_SROWEXPL, 0x01<<2); + I2C_SET_CHECK(HDCS00_SROWEXPH, 0x00); + } + if ((r = qc_i2c_wait(qc))<0) goto fail; + STV_SET_CHECK(0x1501, 0xC2); /* ? */ + STV_SET_CHECK(0x1502, 0xB0); /* ? */ + I2C_SET_CHECK(HDCS_PCTRL, 0x63); /* Pad Control Register */ + I2C_SET_CHECK(HDCS_PDRV, 0x00); /* Pad Drive Control Register */ + I2C_SET_CHECK(GET_CONFIG, 0x08); /* Configuration Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + + /* Start isochronous streaming */ + I2C_SET_CHECK(GET_CONTROL, 0x04); /* Control Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + if ((r = qc_stv_get(qc, 0x1445)) != 0x04) /* Turn LED on/off? */ + PDEBUG("Bad value 0x%02X in reg 0x1445, should be 0x04", r); + STV_SET_CHECK(0x1440, 0x01); /* Turn on/off isochronous stream */ + + /* Stop isochronous streaming */ + STV_SET_CHECK(0x1440, 0x00); /* Turn on/off isochronous stream */ + I2C_SET_CHECK(GET_CONTROL, 0x00); /* Control Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + + STV_SET_CHECK(0x0423, 0x04); /* Unknown (sometimes 4, sometimes 5) */ + STV_SET_CHECK(0x1500, 0x1D); /* ? */ + I2C_SET_CHECK(HDCS_PCTRL, 0x63); /* Pad Control Register */ + I2C_SET_CHECK(HDCS_PDRV, 0x00); /* Pad Drive Control Register */ + I2C_SET_CHECK(GET_CONFIG, 0x08); /* Configuration Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + STV_SET_CHECK(0x15C3, 0x02); /* Y-Control, 1: 288 lines, 2: 144 lines */ + STV_SETW_CHECK(0x15C1, 0x0230); /* Max. ISO packet size */ + I2C_SET_CHECK(HDCS_FWROW, 0x00); /* First Window Row Register */ + I2C_SET_CHECK(HDCS_FWCOL, 0x07); /* First Window Column Register */ + I2C_SET_CHECK(HDCS_LWROW, 0x49); /* Last Window Row Register */ + I2C_SET_CHECK(HDCS_LWCOL, 0x5E); /* Last Window Column Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + STV_SET_CHECK(0x1680, 0x00); /* X-Control, 0xa: 352 columns, 6: 176 columns */ + I2C_SET_CHECK(HDCS_TCTRL, IS_1020(qc) ? 0xCE : 0x6E); /* Timing Control Register */ + I2C_SET_CHECK(HDCS_ICTRL, 0x00); /* Interface Control Register */ + I2C_SET_CHECK(HDCS_ITMG, 0x16); /* Interface Timing Register */ + if (IS_1020(qc)) I2C_SET_CHECK(HDCS20_HBLANK, 0xCF); /* Horizontal Blank Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + STV_SET_CHECK(0x1446, 0x00); /* ? */ + if ((r = qc_stv_get(qc, 0x1446)) != 0x00) /* ? */ + PDEBUG("Bad value 0x%02X in reg 0x1446, should be 0x00", r); + STV_SET_CHECK(0x1446, 0x00); /* ? */ + I2C_SET_CHECK(HDCS_ROWEXPL, 0x62); /* Row Exposure Low Register */ + I2C_SET_CHECK(HDCS_ROWEXPH, 0x00); /* Row Exposure High Register */ + if (IS_1020(qc)) { + I2C_SET_CHECK(HDCS20_SROWEXP, 0x1A); /* Sub-Row Exposure Register */ + } else { + I2C_SET_CHECK(HDCS00_SROWEXPL, 0x1A<<2); + I2C_SET_CHECK(HDCS00_SROWEXPH, 0x00); + } + if ((r = qc_i2c_wait(qc))<0) goto fail; + STV_SET_CHECK(0x1501, 0xB6); /* ? */ + STV_SET_CHECK(0x1502, 0xA8); /* ? */ + I2C_SET_CHECK(HDCS_PCTRL, 0x63); /* Pad Control Register */ + I2C_SET_CHECK(HDCS_PDRV, 0x00); /* Pad Drive Control Register */ + I2C_SET_CHECK(GET_CONFIG, 0x08); /* Configuration Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + + /* Start isochronous streaming */ + I2C_SET_CHECK(GET_CONTROL, 0x04); /* Control Register */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + STV_SET_CHECK(0x1440, 0x01); /* Turn on/off isochronous stream */ + + if ((r = qc_stv_get(qc, 0x1445)) != 0x04) /* Turn LED on/off? */ + PDEBUG("Bad value 0x%02X in reg 0x1445, should be 0x04", r); + } + + return 0; +fail: return r; +} +/* }}} */ +#endif +/* {{{ [fold] hdcs_init: Initialise parameters (from Georg Acher's user module for hdcs sensor) */ +static int hdcs_init(struct quickcam *qc) +{ + struct qc_sensor_data *sd = &qc->sensor_data; + unsigned char control = GET_CONTROL; + unsigned char config = GET_CONFIG; + int r,tctrl,astrt,psmp; + + if (sd->compress) return -EINVAL; + sd->maxwidth = IS_1020(qc) ? 352 : 360; /* CIF */ + sd->maxheight = IS_1020(qc) ? 292 : 296; + if (sd->subsample) { + sd->maxwidth /= 2; /* QCIF */ + sd->maxheight /= 2; + } + if ((r = qc_i2c_break(qc))<0) goto fail; /* The following setting must go into same I2C packet */ +#if HDCS_COMPRESS +r = hdcs_compress_init(qc, 3); +qc_i2c_wait(qc); +qc_i2c_break(qc); +qc_stv_set(qc, 0x1440, 0x00); /* Turn on/off isochronous stream */ +qc_i2c_set(qc, GET_CONTROL, BIT(1)); /* Stop and enter sleep mode */ +qc_i2c_wait(qc); +if (r) PDEBUG("hdcs_compress_init(1) = %i", r); +return 0; +#endif + STV_SET_CHECK(STV_REG23, 0); + + /* Set the STV0602AA in STV0600 emulation mode */ + if (IS_870(qc)) STV_SET_CHECK(0x1446, 1); + + /* Reset the image sensor (keeping it to 1 is a problem) */ + I2C_SET_CHECK(control, 1); + if ((r = qc_i2c_wait(qc))<0) goto fail; + I2C_SET_CHECK(control, 0); + if ((r = qc_i2c_wait(qc))<0) goto fail; + + I2C_SET_CHECK(HDCS_STATUS, BIT(6)|BIT(5)|BIT(4)|BIT(3)|BIT(2)|BIT(1)); /* Clear status (writing 1 will clear the corresponding status bit) */ + + I2C_SET_CHECK(HDCS_IMASK, 0x00); /* Disable all interrupts */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + + STV_SET_CHECK(STV_REG00, 0x1D); + STV_SET_CHECK(STV_REG04, 0x07); + STV_SET_CHECK(STV_REG03, 0x95); + + STV_SET_CHECK(STV_REG23, 0); + + STV_SET_CHECK(STV_SCAN_RATE, 0x20); /* Larger -> slower */ + + STV_SETW_CHECK(STV_ISO_SIZE, 847); /* ISO-Size, 0x34F = 847 .. 0x284 = 644 */ + + /* Set mode */ + STV_SET_CHECK(STV_Y_CTRL, 0x01); /* 0x02: half, 0x01: full */ + STV_SET_CHECK(STV_X_CTRL, 0x0A); /* 0x06: half, 0x0A: full */ + + /* These are not good final values, which will be set in set_size */ + /* However, it looks like it's best to set some values at this point nevertheless */ + I2C_SET_CHECK(HDCS_FWROW, 0); /* Start at row 0 */ + I2C_SET_CHECK(HDCS_FWCOL, 0); /* Start at column 0 */ + I2C_SET_CHECK(HDCS_LWROW, 0x47); /* End at row 288 */ + I2C_SET_CHECK(HDCS_LWCOL, 0x57); /* End at column 352 */ + + /* 0x07 - 0x50 */ + astrt = 3; /* 0..3, doesn't seem to have any effect... hmm.. smaller is slower with subsampling */ + if (!IS_1020(qc)) { + /* HDCS-1000 (tctrl was 0x09, but caused some HDCS-1000 not to work) */ + /* Frame rate on HDCS-1000 0x46D:0x840 depending on PSMP: + * 4 = doesn't work at all + * 5 = 7.8 fps, + * 6 = 6.9 fps, + * 8 = 6.3 fps, + * 10 = 5.5 fps, + * 15 = 4.4 fps, + * 31 = 2.8 fps */ + /* Frame rate on HDCS-1000 0x46D:0x870 depending on PSMP: + * 15 = doesn't work at all + * 18 = doesn't work at all + * 19 = 7.3 fps + * 20 = 7.4 fps + * 21 = 7.4 fps + * 22 = 7.4 fps + * 24 = 6.3 fps + * 30 = 5.4 fps */ + psmp = IS_870(qc) ? 20 : 5; /* 4..31 (was 30, changed to 20) */ + tctrl = (astrt<<5) | psmp; + } else { + /* HDCS-1020 (tctrl was 0x7E, but causes slow frame rate on HDCS-1020) */ + /* Changed to 6 which should give 8.1 fps */ + psmp = 6; /* 4..31 (was 9, changed to 6 to improve fps */ + tctrl = (astrt<<6) | psmp; + } + I2C_SET_CHECK(HDCS_TCTRL, tctrl); /* Set PGA sample duration (was 0x7E for IS_870, but caused slow framerate with HDCS-1020) */ + + I2C_SET_CHECK(control, 0); /* FIXME:should not be anymore necessary (already done) */ + + I2C_SET_CHECK(HDCS_ROWEXPL, 0); + I2C_SET_CHECK(HDCS_ROWEXPH, 0); + if (IS_1020(qc)) { + I2C_SET_CHECK(HDCS20_SROWEXP, 0); + I2C_SET_CHECK(HDCS20_ERROR, BIT(0)|BIT(2)); /* Clear error conditions by writing 1 */ + } else { + I2C_SET_CHECK(HDCS00_SROWEXPL, 0); + I2C_SET_CHECK(HDCS00_SROWEXPH, 0); + } + if ((r = qc_i2c_wait(qc))<0) goto fail; + + STV_SET_CHECK(STV_REG01, 0xB5); + STV_SET_CHECK(STV_REG02, 0xA8); + + I2C_SET_CHECK(HDCS_PCTRL, BIT(6)|BIT(5)|BIT(1)|BIT(0)); + I2C_SET_CHECK(HDCS_PDRV, 0x00); + I2C_SET_CHECK(HDCS_ICTRL, (sd->subsample ? BIT(7) : 0) | BIT(5)); + I2C_SET_CHECK(HDCS_ITMG, BIT(4)|BIT(1)); + + /* CONFIG: Bit 3: continous frame capture, bit 2: stop when frame complete */ + I2C_SET_CHECK(config, (sd->subsample ? BIT(5) : 0) | BIT(3)); + I2C_SET_CHECK(HDCS_ADCCTRL, 10); /* ADC output resolution to 10 bits */ + if ((r = qc_i2c_wait(qc))<0) goto fail; +fail: return r; +} +/* }}} */ +/* {{{ [fold] hdcs_start: Start grabbing */ +static int hdcs_start(struct quickcam *qc) +{ + int r; +#if HDCS_COMPRESS +r = hdcs_compress_init(qc, 2); +qc_i2c_wait(qc); +if (r) PDEBUG("hdcs_compress_init(1) = %i", r); +return 0; +#endif + if ((r = qc_i2c_break(qc))<0) goto fail; + I2C_SET_CHECK(GET_CONTROL, BIT(2)); /* Run enable */ + if ((r = qc_i2c_break(qc))<0) goto fail; +fail: return r; +} +/* }}} */ +/* {{{ [fold] hdcs_stop: Stop grabbing */ +static int hdcs_stop(struct quickcam *qc) +{ + int r; + if ((r = qc_i2c_break(qc))<0) goto fail; + I2C_SET_CHECK(GET_CONTROL, BIT(1)); /* Stop and enter sleep mode */ + r = qc_i2c_wait(qc); +fail: return r; +} +/* }}} */ +/* {{{ [fold] hdcs_set_exposure: Set exposure time, val=0..65535 */ +static int hdcs_set_exposure(struct quickcam *qc, unsigned int val) +{ + struct qc_sensor_data *sd = &qc->sensor_data; + unsigned char control = GET_CONTROL; + unsigned int rowexp; /* rowexp,srowexp = 15 bits (0..32767) */ + unsigned int srowexp; /* sub-row exposure (smaller is brighter) */ + unsigned int max_srowexp; /* Maximum srowexp value + 1 */ + int r; + + /* Absolute black at srowexp=2672,width=360; 2616, width=352; 1896, width=256 for hdcs1000 */ + + if (val==sd->exposure) return 0; + sd->exposure = val; + val *= 16; /* 16 seems to be the smallest change that actually affects brightness */ + max_srowexp = sd->width*15/2 - 104 + 1; + srowexp = max_srowexp - (val % max_srowexp) - 1; + rowexp = val / max_srowexp; + if (qcdebug&QC_DEBUGCAMERA) PDEBUG("width=%i height=%i rowexp=%i srowexp=%i",sd->width,sd->height,rowexp,srowexp); + if ((r = qc_i2c_break(qc))<0) goto fail; /* The following setting must go into same I2C packet */ + I2C_SET_CHECK(control, 0); /* Stop grabbing */ + I2C_SET_CHECK(HDCS_ROWEXPL, rowexp & 0xFF); /* Number of rows to expose */ + I2C_SET_CHECK(HDCS_ROWEXPH, rowexp >> 8); + if (IS_1020(qc)) { + srowexp = 0; //FIXME:need formula to compute srowexp for HDCS1020! + srowexp >>= 2; /* Bits 0..1 are hardwired to 0 */ + I2C_SET_CHECK(HDCS20_SROWEXP, srowexp & 0xFF); /* Number of pixels to expose */ + } else { + I2C_SET_CHECK(HDCS00_SROWEXPL, srowexp & 0xFF); /* Number of pixels to expose */ + I2C_SET_CHECK(HDCS00_SROWEXPH, srowexp >> 8); + } + if (IS_1020(qc)) { + I2C_SET_CHECK(HDCS20_ERROR, BIT(0)); /* Reset exposure error flag */ + } else { + I2C_SET_CHECK(HDCS_STATUS, BIT(4)); /* Reset exposure error flag */ + } + I2C_SET_CHECK(control, BIT(2)); /* Restart grabbing */ + if ((r = qc_i2c_break(qc))<0) goto fail; +#if 0 + /* Warning: the code below will cause about 0.1 second delay and may cause lost frames */ + if (PARANOID) { + /* Check if the new exposure setting is valid */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + if (IS_1020(qc)) { + if ((r = qc_get_i2c(qc,qc->sensor_data.sensor, HDCS20_ERROR))<0) goto fail; + if (r & BIT(0)) PDEBUG("exposure error (1020)"); + } else { + if ((r = qc_get_i2c(qc,qc->sensor_data.sensor, HDCS_STATUS))<0) goto fail; + if (r & BIT(4)) PDEBUG("exposure error (1000)"); + } + } + if ((r = qc_i2c_wait(qc))<0) goto fail; +#endif + qc_frame_flush(qc); +fail: return (r<0) ? r : 0; +} +/* }}} */ +/* {{{ [fold] hdcs_set_gains: Set gains */ +static int hdcs_set_gains(struct quickcam *qc, unsigned int hue, unsigned int sat, unsigned int val) +{ + static const unsigned int min_gain = 8; + struct qc_sensor_data *sd = &qc->sensor_data; + unsigned int rgain, bgain, ggain; + int r; + qc_hsv2rgb(hue, sat, val, &rgain, &bgain, &ggain); + rgain >>= 8; /* After this the values are 0..255 */ + ggain >>= 8; + bgain >>= 8; + rgain = MAX(rgain, min_gain); /* Do not allow very small values, they cause bad (low-contrast) image */ + ggain = MAX(ggain, min_gain); + bgain = MAX(bgain, min_gain); + if (rgain==sd->rgain && ggain==sd->ggain && bgain==sd->bgain) return 0; + sd->rgain = rgain; + sd->ggain = ggain; + sd->bgain = bgain; + if (rgain > 127) rgain = rgain/2 | BIT(7); /* Bit 7 doubles the programmed values */ + if (ggain > 127) ggain = ggain/2 | BIT(7); /* Double programmed value if necessary */ + if (bgain > 127) bgain = bgain/2 | BIT(7); + if ((r = qc_i2c_break(qc))<0) goto fail; + I2C_SET_CHECK(HDCS_ERECPGA, ggain); + I2C_SET_CHECK(HDCS_EROCPGA, rgain); + I2C_SET_CHECK(HDCS_ORECPGA, bgain); + I2C_SET_CHECK(HDCS_OROCPGA, ggain); +fail: return r; +} +/* }}} */ +/* {{{ [fold] hdcs_set_levels() */ +static int hdcs_set_levels(struct quickcam *qc, unsigned int exp, unsigned int gain, unsigned int hue, unsigned int sat) +{ + int r = 0; +//#if !HDCS_COMPRESS + if ((r = hdcs_set_exposure(qc, gain))<0) goto fail; +//#endif + hdcs_set_gains(qc, hue, sat, exp); +fail: return r; +} +/* }}} */ +/* {{{ [fold] hdcs_set_size: Sets the size of the capture window */ +/* + * Sets the size (scaling) of the capture window. + * If subsample could return the image size we use subsample. + */ +static int hdcs_set_size(struct quickcam *qc, unsigned int width, unsigned int height) +{ + /* The datasheet doesn't seem to say this, but HDCS-1000 + * has visible windows size of 360x296 pixels, the first upper-left + * visible pixel is at 8,8. + * From Andrey's test image: looks like HDCS-1020 upper-left + * visible pixel is at 24,8 (y maybe even smaller?) and lower-right + * visible pixel at 375,299 (x maybe even larger?) + */ + unsigned int originx = IS_1020(qc) ? 24 : 8; /* First visible pixel */ + unsigned int maxwidth = IS_1020(qc) ? 352 : 360; /* Visible sensor size */ + unsigned int originy = 8; + unsigned int maxheight = IS_1020(qc) ? 292 : 296; + + unsigned char control = GET_CONTROL; + struct qc_sensor_data *sd = &qc->sensor_data; + int r; + unsigned int x, y; + +#if HDCS_COMPRESS + return 0; +#endif + if (sd->subsample) { + width *= 2; + height *= 2; + width = (width + 3)/4*4; /* Width must be multiple of 4 */ + height = (height + 3)/4*4; /* Height must be multiple of 4 */ + sd->width = width / 2; + sd->height = height / 2; /* The image sent will be subsampled by 2 */ + } else { + sd->width = width = (width + 3)/4*4; /* Width must be multiple of 4 */ + sd->height = height = (height + 3)/4*4; /* Height must be multiple of 4 */ + } + x = (maxwidth - width)/2; /* Center image by computing upper-left corner */ + y = (maxheight - height)/2; + width /= 4; + height /= 4; + x = (x + originx)/4; /* Must be multiple of 4 (low bits wired to 0) */ + y = (y + originy)/4; + + if ((r = qc_i2c_break(qc))<0) goto fail; + I2C_SET_CHECK(control, 0); /* Stop grabbing */ + I2C_SET_CHECK(HDCS_FWROW, y); + I2C_SET_CHECK(HDCS_FWCOL, x); + I2C_SET_CHECK(HDCS_LWROW, y+height-1); + I2C_SET_CHECK(HDCS_LWCOL, x+width-1); + I2C_SET_CHECK(control, BIT(2)); /* Restart grabbing */ + + /* The exposure timings need to be recomputed when size is changed */ + x = sd->exposure; + sd->exposure = -1; + if ((r = hdcs_set_exposure(qc, x))<0) goto fail; +fail: return r; +} +/* }}} */ + +/* {{{ [fold] struct qc_sensor qc_sensor_hdcs1000 */ +const struct qc_sensor qc_sensor_hdcs1000 = { + name: "HDCS-1000/1100", + manufacturer: "Hewlett Packard", + init: hdcs_init, + start: hdcs_start, + stop: hdcs_stop, + set_size: hdcs_set_size, + set_levels: hdcs_set_levels, + /* Exposure and gain control information */ + autoexposure: FALSE, + adapt_gainlow: 20, + adapt_gainhigh: 20000, + /* Information needed to access the sensor via I2C */ + reg23: 0, + i2c_addr: HDCS_ADDR, + /* Identification information used for auto-detection */ + id_reg: HDCS_IDENT | 1, + id: 0x08, + length_id: 1, + flag: 0, +}; +/* }}} */ +/* {{{ [fold] struct qc_sensor qc_sensor_hdcs1020 */ +const struct qc_sensor qc_sensor_hdcs1020 = { + name: "HDCS-1020", + manufacturer: "Agilent Technologies", + init: hdcs_init, + start: hdcs_start, + stop: hdcs_stop, + set_size: hdcs_set_size, + set_levels: hdcs_set_levels, + /* Exposure and gain control information */ + autoexposure: FALSE, + adapt_gainlow: 20, + adapt_gainhigh: 20000, + /* Information needed to access the sensor via I2C */ + reg23: 0, + i2c_addr: HDCS_ADDR, + /* Identification information used for auto-detection */ + id_reg: HDCS_IDENT | 1, + id: 0x10, + length_id: 1, + flag: 1, +}; +/* }}} */ + +/* End of file */ --- linux-2.6.27.orig/ubuntu/qc-usb/qc-mjpeg.c +++ linux-2.6.27/ubuntu/qc-usb/qc-mjpeg.c @@ -0,0 +1,1936 @@ +/* Start of file */ + +/* {{{ [fold] Comments */ +/* + * MJPEG decompression routines are from mpeg2dec, + * Copyright (C) 1999-2001 Aaron Holtzman + * Modified by Tuukka Toivonen and Jochen Hoenicke. + * + * Portions of this code are from the MPEG software simulation group + * idct implementation. This code will be replaced with a new + * implementation soon. + * + * The MJPEG routines are from mpeg2dec, a free MPEG-2 video stream decoder. + * + * mpeg2dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mpeg2dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* }}} */ + +#include "quickcam.h" + +#ifdef __KERNEL__ /* show.c will include this file directly into compilation for userspace */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#include +#else +#include +#endif +#endif /* __KERNEL__ */ + +#if COMPRESS +/* {{{ [fold] **** qc_mjpeg_yuv2rgb: MJPEG decoding: YUV to RGB conversion routines *************** */ + +/* {{{ [fold] Macros */ +#define MODE_RGB 1 +#define MODE_BGR 2 + +#define RGB(i) \ + U = pu[i]; \ + V = pv[i]; \ + r = md->table_rV[V]; \ + g = (void *)(((u8 *)md->table_gU[U]) + md->table_gV[V]);\ + b = md->table_bU[U]; + +#define DST1(i) \ + Y = py_1[2*i]; \ + dst_1[2*i] = r[Y] + g[Y] + b[Y]; \ + Y = py_1[2*i+1]; \ + dst_1[2*i+1] = r[Y] + g[Y] + b[Y]; + +#define DST2(i) \ + Y = py_2[2*i]; \ + dst_2[2*i] = r[Y] + g[Y] + b[Y]; \ + Y = py_2[2*i+1]; \ + dst_2[2*i+1] = r[Y] + g[Y] + b[Y]; + +#define DST1RGB(i) \ + Y = py_1[2*i]; \ + dst_1[6*i] = r[Y]; dst_1[6*i+1] = g[Y]; dst_1[6*i+2] = b[Y]; \ + Y = py_1[2*i+1]; \ + dst_1[6*i+3] = r[Y]; dst_1[6*i+4] = g[Y]; dst_1[6*i+5] = b[Y]; + +#define DST2RGB(i) \ + Y = py_2[2*i]; \ + dst_2[6*i] = r[Y]; dst_2[6*i+1] = g[Y]; dst_2[6*i+2] = b[Y]; \ + Y = py_2[2*i+1]; \ + dst_2[6*i+3] = r[Y]; dst_2[6*i+4] = g[Y]; dst_2[6*i+5] = b[Y]; + +#define DST1BGR(i) \ + Y = py_1[2*i]; \ + dst_1[6*i] = b[Y]; dst_1[6*i+1] = g[Y]; dst_1[6*i+2] = r[Y]; \ + Y = py_1[2*i+1]; \ + dst_1[6*i+3] = b[Y]; dst_1[6*i+4] = g[Y]; dst_1[6*i+5] = r[Y]; + +#define DST2BGR(i) \ + Y = py_2[2*i]; \ + dst_2[6*i] = b[Y]; dst_2[6*i+1] = g[Y]; dst_2[6*i+2] = r[Y]; \ + Y = py_2[2*i+1]; \ + dst_2[6*i+3] = b[Y]; dst_2[6*i+4] = g[Y]; dst_2[6*i+5] = r[Y]; +/* }}} */ + +/* {{{ [fold] qc_mjpeg_yuv2rgb_32() */ +static void qc_mjpeg_yuv2rgb_32(struct qc_mjpeg_data *md, u8 *py_1, u8 *py_2, u8 *pu, u8 *pv, + void *_dst_1, void *_dst_2, int width) +{ + int U, V, Y; + u32 *r, *g, *b; + u32 *dst_1, *dst_2; + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_yuv2rgb_32(md=%p, py_1=%p, py_2=%p, pu=%p, pv=%p, _dst_1=%p, _dst_2=%p, width=%i",md,py_1,py_2,pu,pv,_dst_1,_dst_2,width); + width >>= 3; + dst_1 = _dst_1; + dst_2 = _dst_2; + + do { + RGB(0); + DST1(0); + DST2(0); + + RGB(1); + DST2(1); + DST1(1); + + RGB(2); + DST1(2); + DST2(2); + + RGB(3); + DST2(3); + DST1(3); + + pu += 4; + pv += 4; + py_1 += 8; + py_2 += 8; + dst_1 += 8; + dst_2 += 8; + } while (--width); + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_yuv2rgb_32() done"); +} +/* }}} */ +/* {{{ [fold] qc_mjpeg_yuv2rgb_24rgb() */ +/* This is very near from the yuv2rgb_32 code */ +static void qc_mjpeg_yuv2rgb_24rgb(struct qc_mjpeg_data *md, u8 *py_1, u8 *py_2, u8 *pu, u8 *pv, + void *_dst_1, void *_dst_2, int width) +{ + int U, V, Y; + u8 *r, *g, *b; + u8 *dst_1, *dst_2; + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_yuv2rgb_24rgb(md=%p, py_1=%p, py_2=%p, pu=%p, pv=%p, _dst_1=%p, _dst_2=%p, width=%i",md,py_1,py_2,pu,pv,_dst_1,_dst_2,width); + + width >>= 3; + dst_1 = _dst_1; + dst_2 = _dst_2; + + do { + RGB(0); + DST1RGB(0); + DST2RGB(0); + + RGB(1); + DST2RGB(1); + DST1RGB(1); + + RGB(2); + DST1RGB(2); + DST2RGB(2); + + RGB(3); + DST2RGB(3); + DST1RGB(3); + + pu += 4; + pv += 4; + py_1 += 8; + py_2 += 8; + dst_1 += 24; + dst_2 += 24; + } while (--width); + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_yuv2rgb_24rgb() done"); +} +/* }}} */ +/* {{{ [fold] qc_mjpeg_yuv2rgb_24bgr() */ +/* only trivial mods from yuv2rgb_24rgb */ +static void qc_mjpeg_yuv2rgb_24bgr(struct qc_mjpeg_data *md, u8 *py_1, u8 *py_2, u8 *pu, u8 *pv, + void *_dst_1, void *_dst_2, int width) +{ + int U, V, Y; + u8 *r, *g, *b; + u8 *dst_1, *dst_2; + + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_yuv2rgb_24bgr(md=%p, py_1=%p, py_2=%p, pu=%p, pv=%p, _dst_1=%p, _dst_2=%p, width=%i",md,py_1,py_2,pu,pv,_dst_1,_dst_2,width); + width >>= 3; + dst_1 = _dst_1; + dst_2 = _dst_2; + + do { + RGB(0); + DST1BGR(0); + DST2BGR(0); + + RGB(1); + DST2BGR(1); + DST1BGR(1); + + RGB(2); + DST1BGR(2); + DST2BGR(2); + + RGB(3); + DST2BGR(3); + DST1BGR(3); + + pu += 4; + pv += 4; + py_1 += 8; + py_2 += 8; + dst_1 += 24; + dst_2 += 24; + } while (--width); + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_yuv2rgb_24bgr() done"); +} +/* }}} */ +/* {{{ [fold] qc_mjpeg_yuv2rgb_16() */ +/* This is exactly the same code as yuv2rgb_32 except for the types of */ +/* r, g, b, dst_1, dst_2 */ +static void qc_mjpeg_yuv2rgb_16(struct qc_mjpeg_data *md, u8 *py_1, u8 *py_2, u8 *pu, u8 *pv, + void *_dst_1, void *_dst_2, int width) +{ + int U, V, Y; + u16 *r, *g, *b; + u16 *dst_1, *dst_2; + + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_yuv2rgb_16(md=%p, py_1=%p, py_2=%p, pu=%p, pv=%p, _dst_1=%p, _dst_2=%p, width=%i",md,py_1,py_2,pu,pv,_dst_1,_dst_2,width); + width >>= 3; + dst_1 = _dst_1; + dst_2 = _dst_2; + + do { + RGB(0); + DST1(0); + DST2(0); + + RGB(1); + DST2(1); + DST1(1); + + RGB(2); + DST1(2); + DST2(2); + + RGB(3); + DST2(3); + DST1(3); + + pu += 4; + pv += 4; + py_1 += 8; + py_2 += 8; + dst_1 += 8; + dst_2 += 8; + } while (--width); + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_yuv2rgb_16() done"); +} +/* }}} */ +/* {{{ [fold] qc_mjpeg_yuv2rgb() */ +/* Convert YUV image to RGB */ +static void qc_mjpeg_yuv2rgb(struct qc_mjpeg_data *md, void *dst, u8 *py, u8 *pu, u8 *pv, + int width, int height, int rgb_stride, int y_stride, int uv_stride) +{ + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_yuv2rgb(md=%p, dst=%p, py=%p, pu=%p, pv=%p, width=%i, height=%i, rgb_stride=%i, y_stride=%i, uv_stride=%i",md,dst,py,pu,pv,width,height,rgb_stride,y_stride,uv_stride); + height >>= 1; + do { + md->yuv2rgb_func(md, py, py + y_stride, pu, pv, dst, ((u8 *)dst) + rgb_stride, width); + py += 2 * y_stride; + pu += uv_stride; + pv += uv_stride; + dst = ((u8 *)dst) + 2 * rgb_stride; + } while (--height); + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_yuv2rgb() done"); +} +/* }}} */ + +static const u32 matrix_coefficients = 6; +static const s32 Inverse_Table_6_9[8][4] = { + { 117504, 138453, 13954, 34903 }, /* 0: no sequence_display_extension */ + { 117504, 138453, 13954, 34903 }, /* 1: ITU-R Rec. 709 (1990) */ + { 104597, 132201, 25675, 53279 }, /* 2: unspecified */ + { 104597, 132201, 25675, 53279 }, /* 3: reserved */ + { 104448, 132798, 24759, 53109 }, /* 4: FCC */ + { 104597, 132201, 25675, 53279 }, /* 5: ITU-R Rec. 624-4 System B, G */ + { 104597, 132201, 25675, 53279 }, /* 6: SMPTE 170M */ + { 117579, 136230, 16907, 35559 } /* 7: SMPTE 240M (1987) */ +}; + +/* {{{ [fold] div_round(int dividend, int divisor) */ +static int div_round(int dividend, int divisor) +{ + if (dividend > 0) + return (dividend + (divisor>>1)) / divisor; + else + return -((-dividend + (divisor>>1)) / divisor); +} +/* }}} */ +/* {{{ [fold] qc_mjpeg_yuv2rgb_init(struct qc_mjpeg_data *md, int bpp, int mode) */ +/* Initialization of yuv2rgb routines. Return error code if failure */ +static inline int qc_mjpeg_yuv2rgb_init(struct qc_mjpeg_data *md, int bpp, int mode) +{ + static const int table_Y_size = 1024; + u8 *table_Y; + int i, ret = -ENOMEM; + int entry_size = 0; + void *table_r = NULL, *table_g = NULL, *table_b = NULL; + int crv = Inverse_Table_6_9[matrix_coefficients][0]; + int cbu = Inverse_Table_6_9[matrix_coefficients][1]; + int cgu = -Inverse_Table_6_9[matrix_coefficients][2]; + int cgv = -Inverse_Table_6_9[matrix_coefficients][3]; + u32 *table_32; + u16 *table_16; + u8 *table_8; + + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_yuv2rgb_init(md=%p, bpp=%i, mode=%i)",md,bpp,mode); + table_Y = kmalloc(table_Y_size,GFP_KERNEL); /* Allocate with kmalloc(), it might not fit into stack */ + if (table_Y==NULL) return -ENOMEM; + + for (i=0; i<1024; i++) { + int j; + j = (76309 * (i - 384 - 16) + 32768) >> 16; + j = (j < 0) ? 0 : ((j > 255) ? 255 : j); + table_Y[i] = j; + } + + switch (bpp) { + case 32: + md->yuv2rgb_func = qc_mjpeg_yuv2rgb_32; + table_32 = md->table = kmalloc((197 + 2*682 + 256 + 132) * sizeof(u32), GFP_KERNEL); /* 0..1948 x 4 */ + if (!md->table) goto fail; + entry_size = sizeof(u32); + table_r = table_32 + 197; /* R: -197..1751 */ + table_b = table_32 + 197 + 685; /* B: -882..1066 */ + table_g = table_32 + 197 + 2*682; /* G: -1561..387 */ + for (i=-197; i<256+197; i++) /* Ri = -197...452 */ + ((u32 *) table_r)[i] = table_Y[i+384] << ((mode==MODE_RGB) ? 16 : 0); + for (i=-132; i<256+132; i++) /* Gi = -132...387 */ + ((u32 *) table_g)[i] = table_Y[i+384] << 8; + for (i=-232; i<256+232; i++) /* Bi = -232...487 */ + ((u32 *) table_b)[i] = table_Y[i+384] << ((mode==MODE_RGB) ? 0 : 16); + break; + case 24: + md->yuv2rgb_func = (mode==MODE_RGB) ? qc_mjpeg_yuv2rgb_24rgb : qc_mjpeg_yuv2rgb_24bgr; + table_8 = md->table = kmalloc((256 + 2*232) * sizeof(u8), GFP_KERNEL); /* 0..719 x 1 */ + if (!md->table) goto fail; + entry_size = sizeof(u8); + table_r = table_g = table_b = table_8 + 232; /* -232..487 */ + for (i=-232; i<256+232; i++) /* i = -232..487 */ + ((u8 *)table_b)[i] = table_Y[i+384]; + break; + case 15: + case 16: + md->yuv2rgb_func = qc_mjpeg_yuv2rgb_16; + table_16 = md->table = kmalloc((197 + 2*682 + 256 + 132) * sizeof(u16), GFP_KERNEL); /* 0..1948 x 2 */ + if (!md->table) goto fail; + entry_size = sizeof(u16); + table_r = table_16 + 197; /* R: -197..1751 */ + table_b = table_16 + 197 + 685; /* B: -882..1066 */ + table_g = table_16 + 197 + 2*682; /* G: -1561..387 */ + for (i=-197; i<256+197; i++) { /* Ri = -197..452 */ + int j = table_Y[i+384] >> 3; + if (mode == MODE_RGB) j <<= ((bpp==16) ? 11 : 10); + ((u16 *)table_r)[i] = j; + } + for (i=-132; i<256+132; i++) { /* Gi = -132..387 */ + int j = table_Y[i+384] >> ((bpp==16) ? 2 : 3); + ((u16 *)table_g)[i] = j << 5; + } + for (i=-232; i<256+232; i++) { /* Bi = -232..487 */ + int j = table_Y[i+384] >> 3; + if (mode == MODE_BGR) j <<= ((bpp==16) ? 11 : 10); + ((u16 *)table_b)[i] = j; + } + break; + default: + PDEBUG("%i bpp not supported by yuv2rgb", bpp); + ret = -EINVAL; + goto fail; + } + for (i=0; i<256; i++) { + md->table_rV[i] = (((u8 *)table_r) + entry_size * div_round(crv * (i-128), 76309)); + md->table_gU[i] = (((u8 *)table_g) + entry_size * div_round(cgu * (i-128), 76309)); + md->table_gV[i] = entry_size * div_round(cgv * (i-128), 76309); + md->table_bU[i] = (((u8 *)table_b) + entry_size * div_round(cbu * (i-128), 76309)); + } + ret = 0; +fail: if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_yuv2rgb_init()=%i done", ret); + if (PARANOID) memset(table_Y, POISON_VAL, table_Y_size); + kfree(table_Y); + return ret; +} +/* }}} */ +/* {{{ [fold] qc_mjpeg_yuv2rgb_exit(struct qc_mjpeg_data *md) */ +static inline void qc_mjpeg_yuv2rgb_exit(struct qc_mjpeg_data *md) +{ + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_yuv2rgb_exit(md=%p)",md); + kfree(md->table); + POISON(md->table); + POISON(md->yuv2rgb_func); + POISON(md->table_rV); + POISON(md->table_gU); + POISON(md->table_bU); + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_yuv2rgb_exit() done"); +} +/* }}} */ + +/* }}} */ +/* {{{ [fold] **** qc_mjpeg_idct: MJPEG decoding: Inverse DCT routines ************************* */ +/**********************************************************/ +/* inverse two dimensional DCT, Chen-Wang algorithm */ +/* (cf. IEEE ASSP-32, pp. 803-816, Aug. 1984) */ +/* 32-bit integer arithmetic (8 bit coefficients) */ +/* 11 mults, 29 adds per DCT */ +/* sE, 18.8.91 */ +/**********************************************************/ +/* coefficients extended to 12 bit for IEEE1180-1990 */ +/* compliance sE, 2.1.94 */ +/**********************************************************/ + +/* this code assumes >> to be a two's-complement arithmetic */ +/* right shift: (-2)>>1 == -1 , (-3)>>1 == -2 */ + +#define W1 2841 /* 2048*sqrt (2)*cos (1*pi/16) */ +#define W2 2676 /* 2048*sqrt (2)*cos (2*pi/16) */ +#define W3 2408 /* 2048*sqrt (2)*cos (3*pi/16) */ +#define W5 1609 /* 2048*sqrt (2)*cos (5*pi/16) */ +#define W6 1108 /* 2048*sqrt (2)*cos (6*pi/16) */ +#define W7 565 /* 2048*sqrt (2)*cos (7*pi/16) */ + +/* {{{ [fold] qc_mjpeg_idct_row(s16 *block) */ +/* row (horizontal) IDCT + * + * 7 pi 1 + * dst[k] = sum c[l] * src[l] * cos ( -- * ( k + - ) * l ) + * l=0 8 2 + * + * where: c[0] = 128 + * c[1..7] = 128*sqrt (2) + */ +static void inline qc_mjpeg_idct_row(s16 *block) +{ + int x0, x1, x2, x3, x4, x5, x6, x7, x8; + + x1 = block[4] << 11; + x2 = block[6]; + x3 = block[2]; + x4 = block[1]; + x5 = block[7]; + x6 = block[5]; + x7 = block[3]; + + /* shortcut */ + if (! (x1 | x2 | x3 | x4 | x5 | x6 | x7)) { + block[0] = block[1] = block[2] = block[3] = block[4] = + block[5] = block[6] = block[7] = block[0]<<3; + return; + } + + x0 = (block[0] << 11) + 128; /* for proper rounding in the fourth stage */ + + /* first stage */ + x8 = W7 * (x4 + x5); + x4 = x8 + (W1 - W7) * x4; + x5 = x8 - (W1 + W7) * x5; + x8 = W3 * (x6 + x7); + x6 = x8 - (W3 - W5) * x6; + x7 = x8 - (W3 + W5) * x7; + + /* second stage */ + x8 = x0 + x1; + x0 -= x1; + x1 = W6 * (x3 + x2); + x2 = x1 - (W2 + W6) * x2; + x3 = x1 + (W2 - W6) * x3; + x1 = x4 + x6; + x4 -= x6; + x6 = x5 + x7; + x5 -= x7; + + /* third stage */ + x7 = x8 + x3; + x8 -= x3; + x3 = x0 + x2; + x0 -= x2; + x2 = (181 * (x4 + x5) + 128) >> 8; + x4 = (181 * (x4 - x5) + 128) >> 8; + + /* fourth stage */ + block[0] = (x7 + x1) >> 8; + block[1] = (x3 + x2) >> 8; + block[2] = (x0 + x4) >> 8; + block[3] = (x8 + x6) >> 8; + block[4] = (x8 - x6) >> 8; + block[5] = (x0 - x4) >> 8; + block[6] = (x3 - x2) >> 8; + block[7] = (x7 - x1) >> 8; +} +/* }}} */ +/* {{{ [fold] qc_mjpeg_idct_col(s16 *block) */ +/* column (vertical) IDCT + * + * 7 pi 1 + * dst[8*k] = sum c[l] * src[8*l] * cos ( -- * ( k + - ) * l ) + * l=0 8 2 + * + * where: c[0] = 1/1024 + * c[1..7] = (1/1024)*sqrt (2) + */ +static void inline qc_mjpeg_idct_col(s16 *block) +{ + int x0, x1, x2, x3, x4, x5, x6, x7, x8; + + /* shortcut */ + x1 = block [8*4] << 8; + x2 = block [8*6]; + x3 = block [8*2]; + x4 = block [8*1]; + x5 = block [8*7]; + x6 = block [8*5]; + x7 = block [8*3]; +#if 0 + if (! (x1 | x2 | x3 | x4 | x5 | x6 | x7 )) { + block[8*0] = block[8*1] = block[8*2] = block[8*3] = block[8*4] = + block[8*5] = block[8*6] = block[8*7] = (block[8*0] + 32) >> 6; + return; + } +#endif + x0 = (block[8*0] << 8) + 8192; + + /* first stage */ + x8 = W7 * (x4 + x5) + 4; + x4 = (x8 + (W1 - W7) * x4) >> 3; + x5 = (x8 - (W1 + W7) * x5) >> 3; + x8 = W3 * (x6 + x7) + 4; + x6 = (x8 - (W3 - W5) * x6) >> 3; + x7 = (x8 - (W3 + W5) * x7) >> 3; + + /* second stage */ + x8 = x0 + x1; + x0 -= x1; + x1 = W6 * (x3 + x2) + 4; + x2 = (x1 - (W2 + W6) * x2) >> 3; + x3 = (x1 + (W2 - W6) * x3) >> 3; + x1 = x4 + x6; + x4 -= x6; + x6 = x5 + x7; + x5 -= x7; + + /* third stage */ + x7 = x8 + x3; + x8 -= x3; + x3 = x0 + x2; + x0 -= x2; + x2 = (181 * (x4 + x5) + 128) >> 8; + x4 = (181 * (x4 - x5) + 128) >> 8; + + /* fourth stage */ + block[8*0] = (x7 + x1) >> 14; + block[8*1] = (x3 + x2) >> 14; + block[8*2] = (x0 + x4) >> 14; + block[8*3] = (x8 + x6) >> 14; + block[8*4] = (x8 - x6) >> 14; + block[8*5] = (x0 - x4) >> 14; + block[8*6] = (x3 - x2) >> 14; + block[8*7] = (x7 - x1) >> 14; +} +/* }}} */ +/* {{{ [fold] qc_mjpeg_idct(s16 *block, u8 *dest, int stride) */ +/* Inverse discrete cosine transform block, store result to dest */ +static void qc_mjpeg_idct(s16 *block, u8 *dest, int stride) +{ + int i; + + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_idct(block=%p,dest=%p,stride=%i)",block,dest,stride); + for (i=0; i<8; i++) qc_mjpeg_idct_row(block + 8*i); + for (i=0; i<8; i++) qc_mjpeg_idct_col(block + i); + i = 8; + do { + /* The original code used lookup-tables instead of explicit + * comparisons (as CLIP is doing here). However, sometimes + * the values pointed outside the LUT which caused problems + * in the kernel driver. Thus, the LUTs are removed here. */ + dest[0] = CLIP(block[0],0,255); + dest[1] = CLIP(block[1],0,255); + dest[2] = CLIP(block[2],0,255); + dest[3] = CLIP(block[3],0,255); + dest[4] = CLIP(block[4],0,255); + dest[5] = CLIP(block[5],0,255); + dest[6] = CLIP(block[6],0,255); + dest[7] = CLIP(block[7],0,255); + dest += stride; + block += 8; + } while (--i); +} +/* }}} */ + +/* }}} */ +/* {{{ [fold] **** MJPEG decoding: bitstream processing (structures and macros) * */ +/* the idea is taken from zlib, but the bits are ordered the other way, so + * I modified the code. + * Variables: + * p points to next unread byte in stream. + * k number of bits read but not processed. + * b contains the read but not processed bits in the k most significant bits. + */ +struct bitstream { + u32 b; + u8 *p; + u8 *end; + int k; +}; + +#define GETWORD(p) ((p)[0] << 8 | (p)[1]) +#define NEEDBITS(b,k,p) \ + do { \ + if ((k) > 0) { \ + (b) |= GETWORD(p) << (k); \ + (p) += 2; \ + (k) -= 16; \ + } \ + } while(0) +#define DUMPBITS(b,k,j) do { (k) += (j); (b) <<= (j); } while (0) +#define BITVALUE(b,j) ((b)>>(32-(j))) +/* }}} */ +/* {{{ [fold] **** qc_mjpeg_lvc: MJPEG decoding: variable length code decoding **************** */ + +/* {{{ [fold] u8 shiftTables[18][64] */ +static const u8 shiftTables[18][64] = { + {2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, + {2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 }, + {2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 }, + {2,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 }, + {2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 }, + {2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 }, + {2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 }, + {2,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 }, + {2,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6 }, + {2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 }, + {2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 }, + {2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 }, + {2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 }, + {2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 }, + {2,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 }, + {2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 }, + {2,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6 }, + {2,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 }, +}; +/* }}} */ +/* {{{ [fold] u8 shiftTblIndex[] */ +static const u8 shiftTblIndex[] = { + 8, 17, 8, 16, 7, 16, 7, 15, + 6, 15, 6, 14, 5, 14, 5, 13, + 4, 13, 4, 12, 3, 12, 3, 11, + 2, 11, 2, 10, 1, 9, 0, 9 +}; +/* }}} */ +/* {{{ [fold] s16 scaleTable[64] */ +static const s16 scaleTable[64] = { + 8192, 16704, 16704, 17733, 17032, 17733, 18204, 18081, + 18081, 18204, 18724, 18561, 19195, 18561, 18724, 19265, + 19091, 19704, 19704, 19091, 19265, 21406, 19642, 20267, + 20228, 20267, 19642, 21406, 22725, 21826, 20852, 20805, + 20805, 20852, 21826, 22725, 23170, 23170, 21406, 21399, + 21406, 23170, 23170, 24597, 23785, 22017, 22017, 23785, + 24597, 25250, 24464, 22653, 24464, 25250, 25971, 25171, + 25171, 25971, 26722, 27969, 26722, 29691, 29691, 31520 +}; +/* }}} */ +/* {{{ [fold] u8 scan_norm[64] */ +static const u8 scan_norm[64] = { /* Octals */ + 000, 001, 010, 020, 011, 002, 003, 012, + 021, 030, 040, 031, 022, 013, 004, 005, + 014, 023, 032, 041, 050, 060, 051, 042, + 033, 024, 015, 006, 007, 016, 025, 034, + 043, 052, 061, 070, 071, 062, 053, 044, + 035, 026, 017, 027, 036, 045, 054, 063, + 072, 073, 064, 055, 046, 037, 047, 056, + 065, 074, 075, 066, 057, 067, 076, 077 +}; +/* }}} */ +/* {{{ [fold] hufftable[960] */ +struct hufftable_entry { + s16 value; + u8 bits; + u8 skip; +}; +static const struct hufftable_entry hufftable[960] = { + /* first level entries */ + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { 1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { -1, 3, 1 }, + { 2, 4, 1 }, + { 2, 4, 1 }, + { 2, 4, 1 }, + { 2, 4, 1 }, + { 2, 4, 1 }, + { 2, 4, 1 }, + { 2, 4, 1 }, + { 2, 4, 1 }, + { 2, 4, 1 }, + { 2, 4, 1 }, + { 2, 4, 1 }, + { 2, 4, 1 }, + { 2, 4, 1 }, + { 2, 4, 1 }, + { 2, 4, 1 }, + { 2, 4, 1 }, + { -2, 4, 1 }, + { -2, 4, 1 }, + { -2, 4, 1 }, + { -2, 4, 1 }, + { -2, 4, 1 }, + { -2, 4, 1 }, + { -2, 4, 1 }, + { -2, 4, 1 }, + { -2, 4, 1 }, + { -2, 4, 1 }, + { -2, 4, 1 }, + { -2, 4, 1 }, + { -2, 4, 1 }, + { -2, 4, 1 }, + { -2, 4, 1 }, + { -2, 4, 1 }, + { 32767, 4, 255 }, + { 32767, 4, 255 }, + { 32767, 4, 255 }, + { 32767, 4, 255 }, + { 32767, 4, 255 }, + { 32767, 4, 255 }, + { 32767, 4, 255 }, + { 32767, 4, 255 }, + { 32767, 4, 255 }, + { 32767, 4, 255 }, + { 32767, 4, 255 }, + { 32767, 4, 255 }, + { 32767, 4, 255 }, + { 32767, 4, 255 }, + { 32767, 4, 255 }, + { 32767, 4, 255 }, + { 1, 5, 2 }, + { 1, 5, 2 }, + { 1, 5, 2 }, + { 1, 5, 2 }, + { 1, 5, 2 }, + { 1, 5, 2 }, + { 1, 5, 2 }, + { 1, 5, 2 }, + { -1, 5, 2 }, + { -1, 5, 2 }, + { -1, 5, 2 }, + { -1, 5, 2 }, + { -1, 5, 2 }, + { -1, 5, 2 }, + { -1, 5, 2 }, + { -1, 5, 2 }, + { 3, 5, 1 }, + { 3, 5, 1 }, + { 3, 5, 1 }, + { 3, 5, 1 }, + { 3, 5, 1 }, + { 3, 5, 1 }, + { 3, 5, 1 }, + { 3, 5, 1 }, + { -3, 5, 1 }, + { -3, 5, 1 }, + { -3, 5, 1 }, + { -3, 5, 1 }, + { -3, 5, 1 }, + { -3, 5, 1 }, + { -3, 5, 1 }, + { -3, 5, 1 }, + { 4, 5, 1 }, + { 4, 5, 1 }, + { 4, 5, 1 }, + { 4, 5, 1 }, + { 4, 5, 1 }, + { 4, 5, 1 }, + { 4, 5, 1 }, + { 4, 5, 1 }, + { -4, 5, 1 }, + { -4, 5, 1 }, + { -4, 5, 1 }, + { -4, 5, 1 }, + { -4, 5, 1 }, + { -4, 5, 1 }, + { -4, 5, 1 }, + { -4, 5, 1 }, + { 1, 6, 3 }, + { 1, 6, 3 }, + { 1, 6, 3 }, + { 1, 6, 3 }, + { -1, 6, 3 }, + { -1, 6, 3 }, + { -1, 6, 3 }, + { -1, 6, 3 }, + { 2, 6, 2 }, + { 2, 6, 2 }, + { 2, 6, 2 }, + { 2, 6, 2 }, + { -2, 6, 2 }, + { -2, 6, 2 }, + { -2, 6, 2 }, + { -2, 6, 2 }, + { 5, 6, 1 }, + { 5, 6, 1 }, + { 5, 6, 1 }, + { 5, 6, 1 }, + { -5, 6, 1 }, + { -5, 6, 1 }, + { -5, 6, 1 }, + { -5, 6, 1 }, + { 6, 6, 1 }, + { 6, 6, 1 }, + { 6, 6, 1 }, + { 6, 6, 1 }, + { -6, 6, 1 }, + { -6, 6, 1 }, + { -6, 6, 1 }, + { -6, 6, 1 }, + { 1, 7, 4 }, + { 1, 7, 4 }, + { -1, 7, 4 }, + { -1, 7, 4 }, + { 1, 7, 5 }, + { 1, 7, 5 }, + { -1, 7, 5 }, + { -1, 7, 5 }, + { 7, 7, 1 }, + { 7, 7, 1 }, + { -7, 7, 1 }, + { -7, 7, 1 }, + { 8, 7, 1 }, + { 8, 7, 1 }, + { -8, 7, 1 }, + { -8, 7, 1 }, + { 1, 8, 6 }, + { -1, 8, 6 }, + { 1, 8, 7 }, + { -1, 8, 7 }, + { 2, 8, 3 }, + { -2, 8, 3 }, + { 3, 8, 2 }, + { -3, 8, 2 }, + { 4, 8, 2 }, + { -4, 8, 2 }, + { 9, 8, 1 }, + { -9, 8, 1 }, + { 10, 8, 1 }, + { -10, 8, 1 }, + { 11, 8, 1 }, + { -11, 8, 1 }, + { 256, 9, 99 }, + { 258, 9, 99 }, + { 260, 9, 99 }, + { 262, 9, 99 }, + { 264, 9, 99 }, + { 266, 9, 99 }, + { 268, 9, 99 }, + { 270, 9, 99 }, + { 272, 9, 99 }, + { 274, 9, 99 }, + { 276, 9, 99 }, + { 278, 9, 99 }, + { 280, 9, 99 }, + { 282, 9, 99 }, + { 284, 9, 99 }, + { 286, 9, 99 }, + { 288, 10, 99 }, + { 292, 10, 99 }, + { 296, 10, 99 }, + { 300, 10, 99 }, + { 304, 10, 99 }, + { 308, 10, 99 }, + { 312, 10, 99 }, + { 316, 10, 99 }, + { 320, 11, 99 }, + { 328, 11, 99 }, + { 336, 12, 99 }, + { 352, 13, 99 }, + { 384, 13, 99 }, + { 416, 13, 99 }, + { 448, 16, 99 }, + { 704, 16, 99 }, + /* indirect entries */ + { 1, 9, 8 }, + { -1, 9, 8 }, + { 1, 9, 9 }, + { -1, 9, 9 }, + { 1, 9, 10 }, + { -1, 9, 10 }, + { 1, 9, 11 }, + { -1, 9, 11 }, + { 2, 9, 4 }, + { -2, 9, 4 }, + { 2, 9, 5 }, + { -2, 9, 5 }, + { 3, 9, 3 }, + { -3, 9, 3 }, + { 5, 9, 2 }, + { -5, 9, 2 }, + { 6, 9, 2 }, + { -6, 9, 2 }, + { 7, 9, 2 }, + { -7, 9, 2 }, + { 12, 9, 1 }, + { -12, 9, 1 }, + { 13, 9, 1 }, + { -13, 9, 1 }, + { 14, 9, 1 }, + { -14, 9, 1 }, + { 15, 9, 1 }, + { -15, 9, 1 }, + { 16, 9, 1 }, + { -16, 9, 1 }, + { 17, 9, 1 }, + { -17, 9, 1 }, + { 1, 10, 12 }, + { -1, 10, 12 }, + { 1, 10, 13 }, + { -1, 10, 13 }, + { 1, 10, 14 }, + { -1, 10, 14 }, + { 1, 10, 15 }, + { -1, 10, 15 }, + { 2, 10, 6 }, + { -2, 10, 6 }, + { 2, 10, 7 }, + { -2, 10, 7 }, + { 3, 10, 4 }, + { -3, 10, 4 }, + { 3, 10, 5 }, + { -3, 10, 5 }, + { 4, 10, 3 }, + { -4, 10, 3 }, + { 5, 10, 3 }, + { -5, 10, 3 }, + { 8, 10, 2 }, + { -8, 10, 2 }, + { 18, 10, 1 }, + { -18, 10, 1 }, + { 19, 10, 1 }, + { -19, 10, 1 }, + { 20, 10, 1 }, + { -20, 10, 1 }, + { 21, 10, 1 }, + { -21, 10, 1 }, + { 22, 10, 1 }, + { -22, 10, 1 }, + { 3, 11, 6 }, + { -3, 11, 6 }, + { 4, 11, 4 }, + { -4, 11, 4 }, + { 5, 11, 4 }, + { -5, 11, 4 }, + { 6, 11, 3 }, + { -6, 11, 3 }, + { 9, 11, 2 }, + { -9, 11, 2 }, + { 10, 11, 2 }, + { -10, 11, 2 }, + { 11, 11, 2 }, + { -11, 11, 2 }, + { 0, 11, 1 }, + { 0, 11, 2 }, + { 3, 12, 7 }, + { -3, 12, 7 }, + { 4, 12, 5 }, + { -4, 12, 5 }, + { 6, 12, 4 }, + { -6, 12, 4 }, + { 12, 12, 2 }, + { -12, 12, 2 }, + { 13, 12, 2 }, + { -13, 12, 2 }, + { 14, 12, 2 }, + { -14, 12, 2 }, + { 0, 12, 3 }, + { 0, 12, 4 }, + { 0, 12, 5 }, + { 0, 12, 6 }, + { 2, 13, 8 }, + { -2, 13, 8 }, + { 2, 13, 9 }, + { -2, 13, 9 }, + { 2, 13, 10 }, + { -2, 13, 10 }, + { 2, 13, 11 }, + { -2, 13, 11 }, + { 3, 13, 8 }, + { -3, 13, 8 }, + { 3, 13, 9 }, + { -3, 13, 9 }, + { 5, 13, 5 }, + { -5, 13, 5 }, + { 7, 13, 4 }, + { -7, 13, 4 }, + { 7, 13, 3 }, + { -7, 13, 3 }, + { 8, 13, 3 }, + { -8, 13, 3 }, + { 9, 13, 3 }, + { -9, 13, 3 }, + { 10, 13, 3 }, + { -10, 13, 3 }, + { 11, 13, 3 }, + { -11, 13, 3 }, + { 15, 13, 2 }, + { -15, 13, 2 }, + { 16, 13, 2 }, + { -16, 13, 2 }, + { 17, 13, 2 }, + { -17, 13, 2 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 0, 13, 7 }, + { 0, 13, 8 }, + { 0, 13, 9 }, + { 0, 13, 10 }, + { 0, 13, 11 }, + { 0, 13, 12 }, + { 0, 13, 13 }, + { 0, 13, 14 }, + { 0, 13, 15 }, + { 0, 13, 16 }, + { 0, 13, 17 }, + { 0, 13, 18 }, + { 0, 13, 19 }, + { 0, 13, 20 }, + { 0, 13, 21 }, + { 0, 13, 22 }, + { 0, 13, 23 }, + { 0, 13, 24 }, + { 0, 13, 25 }, + { 0, 13, 26 }, + { 0, 13, 27 }, + { 0, 13, 28 }, + { 0, 13, 29 }, + { 0, 13, 30 }, + { 0, 13, 31 }, + { 0, 13, 32 }, + { 0, 13, 33 }, + { 0, 13, 34 }, + { 0, 13, 35 }, + { 0, 13, 36 }, + { 0, 13, 37 }, + { 0, 13, 38 }, + { 0, 13, 39 }, + { 0, 13, 40 }, + { 0, 13, 41 }, + { 0, 13, 42 }, + { 0, 13, 43 }, + { 0, 13, 44 }, + { 0, 13, 45 }, + { 0, 13, 46 }, + { 0, 13, 47 }, + { 0, 13, 48 }, + { 0, 13, 49 }, + { 0, 13, 50 }, + { 0, 13, 51 }, + { 0, 13, 52 }, + { 0, 13, 53 }, + { 0, 13, 54 }, + { 0, 13, 55 }, + { 0, 13, 56 }, + { 0, 13, 57 }, + { 0, 13, 58 }, + { 0, 13, 59 }, + { 0, 13, 60 }, + { 0, 13, 61 }, + { 0, 13, 62 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 32767, 0, 255 }, + { 23, 16, 1 }, + { -23, 16, 1 }, + { 24, 16, 1 }, + { -24, 16, 1 }, + { 25, 16, 1 }, + { -25, 16, 1 }, + { 26, 16, 1 }, + { -26, 16, 1 }, + { 27, 16, 1 }, + { -27, 16, 1 }, + { 28, 16, 1 }, + { -28, 16, 1 }, + { 29, 16, 1 }, + { -29, 16, 1 }, + { 30, 16, 1 }, + { -30, 16, 1 }, + { 31, 16, 1 }, + { -31, 16, 1 }, + { 32, 16, 1 }, + { -32, 16, 1 }, + { 33, 16, 1 }, + { -33, 16, 1 }, + { 34, 16, 1 }, + { -34, 16, 1 }, + { 35, 16, 1 }, + { -35, 16, 1 }, + { 36, 16, 1 }, + { -36, 16, 1 }, + { 37, 16, 1 }, + { -37, 16, 1 }, + { 38, 16, 1 }, + { -38, 16, 1 }, + { 39, 16, 1 }, + { -39, 16, 1 }, + { 40, 16, 1 }, + { -40, 16, 1 }, + { 41, 16, 1 }, + { -41, 16, 1 }, + { 42, 16, 1 }, + { -42, 16, 1 }, + { 43, 16, 1 }, + { -43, 16, 1 }, + { 44, 16, 1 }, + { -44, 16, 1 }, + { 45, 16, 1 }, + { -45, 16, 1 }, + { 46, 16, 1 }, + { -46, 16, 1 }, + { 47, 16, 1 }, + { -47, 16, 1 }, + { 48, 16, 1 }, + { -48, 16, 1 }, + { 49, 16, 1 }, + { -49, 16, 1 }, + { 50, 16, 1 }, + { -50, 16, 1 }, + { 51, 16, 1 }, + { -51, 16, 1 }, + { 52, 16, 1 }, + { -52, 16, 1 }, + { 53, 16, 1 }, + { -53, 16, 1 }, + { 54, 16, 1 }, + { -54, 16, 1 }, + { 55, 16, 1 }, + { -55, 16, 1 }, + { 56, 16, 1 }, + { -56, 16, 1 }, + { 57, 16, 1 }, + { -57, 16, 1 }, + { 58, 16, 1 }, + { -58, 16, 1 }, + { 59, 16, 1 }, + { -59, 16, 1 }, + { 60, 16, 1 }, + { -60, 16, 1 }, + { 61, 16, 1 }, + { -61, 16, 1 }, + { 62, 16, 1 }, + { -62, 16, 1 }, + { 63, 16, 1 }, + { -63, 16, 1 }, + { 64, 16, 1 }, + { -64, 16, 1 }, + { 65, 16, 1 }, + { -65, 16, 1 }, + { 66, 16, 1 }, + { -66, 16, 1 }, + { 67, 16, 1 }, + { -67, 16, 1 }, + { 68, 16, 1 }, + { -68, 16, 1 }, + { 69, 16, 1 }, + { -69, 16, 1 }, + { 70, 16, 1 }, + { -70, 16, 1 }, + { 71, 16, 1 }, + { -71, 16, 1 }, + { 72, 16, 1 }, + { -72, 16, 1 }, + { 73, 16, 1 }, + { -73, 16, 1 }, + { 74, 16, 1 }, + { -74, 16, 1 }, + { 75, 16, 1 }, + { -75, 16, 1 }, + { 76, 16, 1 }, + { -76, 16, 1 }, + { 77, 16, 1 }, + { -77, 16, 1 }, + { 78, 16, 1 }, + { -78, 16, 1 }, + { 79, 16, 1 }, + { -79, 16, 1 }, + { 80, 16, 1 }, + { -80, 16, 1 }, + { 81, 16, 1 }, + { -81, 16, 1 }, + { 82, 16, 1 }, + { -82, 16, 1 }, + { 83, 16, 1 }, + { -83, 16, 1 }, + { 84, 16, 1 }, + { -84, 16, 1 }, + { 85, 16, 1 }, + { -85, 16, 1 }, + { 86, 16, 1 }, + { -86, 16, 1 }, + { 87, 16, 1 }, + { -87, 16, 1 }, + { 88, 16, 1 }, + { -88, 16, 1 }, + { 89, 16, 1 }, + { -89, 16, 1 }, + { 90, 16, 1 }, + { -90, 16, 1 }, + { 91, 16, 1 }, + { -91, 16, 1 }, + { 92, 16, 1 }, + { -92, 16, 1 }, + { 93, 16, 1 }, + { -93, 16, 1 }, + { 94, 16, 1 }, + { -94, 16, 1 }, + { 95, 16, 1 }, + { -95, 16, 1 }, + { 96, 16, 1 }, + { -96, 16, 1 }, + { 97, 16, 1 }, + { -97, 16, 1 }, + { 98, 16, 1 }, + { -98, 16, 1 }, + { 99, 16, 1 }, + { -99, 16, 1 }, + { 100, 16, 1 }, + { -100, 16, 1 }, + { 101, 16, 1 }, + { -101, 16, 1 }, + { 102, 16, 1 }, + { -102, 16, 1 }, + { 103, 16, 1 }, + { -103, 16, 1 }, + { 104, 16, 1 }, + { -104, 16, 1 }, + { 105, 16, 1 }, + { -105, 16, 1 }, + { 106, 16, 1 }, + { -106, 16, 1 }, + { 107, 16, 1 }, + { -107, 16, 1 }, + { 108, 16, 1 }, + { -108, 16, 1 }, + { 109, 16, 1 }, + { -109, 16, 1 }, + { 110, 16, 1 }, + { -110, 16, 1 }, + { 111, 16, 1 }, + { -111, 16, 1 }, + { 112, 16, 1 }, + { -112, 16, 1 }, + { 113, 16, 1 }, + { -113, 16, 1 }, + { 114, 16, 1 }, + { -114, 16, 1 }, + { 115, 16, 1 }, + { -115, 16, 1 }, + { 116, 16, 1 }, + { -116, 16, 1 }, + { 117, 16, 1 }, + { -117, 16, 1 }, + { 118, 16, 1 }, + { -118, 16, 1 }, + { 119, 16, 1 }, + { -119, 16, 1 }, + { 120, 16, 1 }, + { -120, 16, 1 }, + { 121, 16, 1 }, + { -121, 16, 1 }, + { 122, 16, 1 }, + { -122, 16, 1 }, + { 123, 16, 1 }, + { -123, 16, 1 }, + { 124, 16, 1 }, + { -124, 16, 1 }, + { 125, 16, 1 }, + { -125, 16, 1 }, + { 126, 16, 1 }, + { -126, 16, 1 }, + { 127, 16, 1 }, + { -127, 16, 1 }, + { 128, 16, 1 }, + { -128, 16, 1 }, + { 129, 16, 1 }, + { -129, 16, 1 }, + { 130, 16, 1 }, + { -130, 16, 1 }, + { 131, 16, 1 }, + { -131, 16, 1 }, + { 132, 16, 1 }, + { -132, 16, 1 }, + { 133, 16, 1 }, + { -133, 16, 1 }, + { 134, 16, 1 }, + { -134, 16, 1 }, + { 135, 16, 1 }, + { -135, 16, 1 }, + { 136, 16, 1 }, + { -136, 16, 1 }, + { 137, 16, 1 }, + { -137, 16, 1 }, + { 138, 16, 1 }, + { -138, 16, 1 }, + { 139, 16, 1 }, + { -139, 16, 1 }, + { 140, 16, 1 }, + { -140, 16, 1 }, + { 141, 16, 1 }, + { -141, 16, 1 }, + { 142, 16, 1 }, + { -142, 16, 1 }, + { 143, 16, 1 }, + { -143, 16, 1 }, + { 144, 16, 1 }, + { -144, 16, 1 }, + { 145, 16, 1 }, + { -145, 16, 1 }, + { 146, 16, 1 }, + { -146, 16, 1 }, + { 147, 16, 1 }, + { -147, 16, 1 }, + { 148, 16, 1 }, + { -148, 16, 1 }, + { 149, 16, 1 }, + { -149, 16, 1 }, + { 150, 16, 1 }, + { -150, 16, 1 }, + { 151, 16, 1 }, + { -151, 16, 1 }, + { 152, 16, 1 }, + { -152, 16, 1 }, + { 153, 16, 1 }, + { -153, 16, 1 }, + { 154, 16, 1 }, + { -154, 16, 1 }, + { 155, 16, 1 }, + { -155, 16, 1 }, + { 156, 16, 1 }, + { -156, 16, 1 }, + { 157, 16, 1 }, + { -157, 16, 1 }, + { 158, 16, 1 }, + { -158, 16, 1 }, + { 159, 16, 1 }, + { -159, 16, 1 }, + { 160, 16, 1 }, + { -160, 16, 1 }, + { 161, 16, 1 }, + { -161, 16, 1 }, + { 162, 16, 1 }, + { -162, 16, 1 }, + { 163, 16, 1 }, + { -163, 16, 1 }, + { 164, 16, 1 }, + { -164, 16, 1 }, + { 165, 16, 1 }, + { -165, 16, 1 }, + { 166, 16, 1 }, + { -166, 16, 1 }, + { 167, 16, 1 }, + { -167, 16, 1 }, + { 168, 16, 1 }, + { -168, 16, 1 }, + { 169, 16, 1 }, + { -169, 16, 1 }, + { 170, 16, 1 }, + { -170, 16, 1 }, + { 171, 16, 1 }, + { -171, 16, 1 }, + { 172, 16, 1 }, + { -172, 16, 1 }, + { 173, 16, 1 }, + { -173, 16, 1 }, + { 174, 16, 1 }, + { -174, 16, 1 }, + { 175, 16, 1 }, + { -175, 16, 1 }, + { 176, 16, 1 }, + { -176, 16, 1 }, + { 177, 16, 1 }, + { -177, 16, 1 }, + { 178, 16, 1 }, + { -178, 16, 1 }, + { 179, 16, 1 }, + { -179, 16, 1 }, + { 180, 16, 1 }, + { -180, 16, 1 }, + { 181, 16, 1 }, + { -181, 16, 1 }, + { 182, 16, 1 }, + { -182, 16, 1 }, + { 183, 16, 1 }, + { -183, 16, 1 }, + { 184, 16, 1 }, + { -184, 16, 1 }, + { 185, 16, 1 }, + { -185, 16, 1 }, + { 186, 16, 1 }, + { -186, 16, 1 }, + { 187, 16, 1 }, + { -187, 16, 1 }, + { 188, 16, 1 }, + { -188, 16, 1 }, + { 189, 16, 1 }, + { -189, 16, 1 }, + { 190, 16, 1 }, + { -190, 16, 1 }, + { 191, 16, 1 }, + { -191, 16, 1 }, + { 192, 16, 1 }, + { -192, 16, 1 }, + { 193, 16, 1 }, + { -193, 16, 1 }, + { 194, 16, 1 }, + { -194, 16, 1 }, + { 195, 16, 1 }, + { -195, 16, 1 }, + { 196, 16, 1 }, + { -196, 16, 1 }, + { 197, 16, 1 }, + { -197, 16, 1 }, + { 198, 16, 1 }, + { -198, 16, 1 }, + { 199, 16, 1 }, + { -199, 16, 1 }, + { 200, 16, 1 }, + { -200, 16, 1 }, + { 201, 16, 1 }, + { -201, 16, 1 }, + { 202, 16, 1 }, + { -202, 16, 1 }, + { 203, 16, 1 }, + { -203, 16, 1 }, + { 204, 16, 1 }, + { -204, 16, 1 }, + { 205, 16, 1 }, + { -205, 16, 1 }, + { 206, 16, 1 }, + { -206, 16, 1 }, + { 207, 16, 1 }, + { -207, 16, 1 }, + { 208, 16, 1 }, + { -208, 16, 1 }, + { 209, 16, 1 }, + { -209, 16, 1 }, + { 210, 16, 1 }, + { -210, 16, 1 }, + { 211, 16, 1 }, + { -211, 16, 1 }, + { 212, 16, 1 }, + { -212, 16, 1 }, + { 213, 16, 1 }, + { -213, 16, 1 }, + { 214, 16, 1 }, + { -214, 16, 1 }, + { 215, 16, 1 }, + { -215, 16, 1 }, + { 216, 16, 1 }, + { -216, 16, 1 }, + { 217, 16, 1 }, + { -217, 16, 1 }, + { 218, 16, 1 }, + { -218, 16, 1 }, + { 219, 16, 1 }, + { -219, 16, 1 }, + { 220, 16, 1 }, + { -220, 16, 1 }, + { 221, 16, 1 }, + { -221, 16, 1 }, + { 222, 16, 1 }, + { -222, 16, 1 }, + { 223, 16, 1 }, + { -223, 16, 1 }, + { 224, 16, 1 }, + { -224, 16, 1 }, + { 225, 16, 1 }, + { -225, 16, 1 }, + { 226, 16, 1 }, + { -226, 16, 1 }, + { 227, 16, 1 }, + { -227, 16, 1 }, + { 228, 16, 1 }, + { -228, 16, 1 }, + { 229, 16, 1 }, + { -229, 16, 1 }, + { 230, 16, 1 }, + { -230, 16, 1 }, + { 231, 16, 1 }, + { -231, 16, 1 }, + { 232, 16, 1 }, + { -232, 16, 1 }, + { 233, 16, 1 }, + { -233, 16, 1 }, + { 234, 16, 1 }, + { -234, 16, 1 }, + { 235, 16, 1 }, + { -235, 16, 1 }, + { 236, 16, 1 }, + { -236, 16, 1 }, + { 237, 16, 1 }, + { -237, 16, 1 }, + { 238, 16, 1 }, + { -238, 16, 1 }, + { 239, 16, 1 }, + { -239, 16, 1 }, + { 240, 16, 1 }, + { -240, 16, 1 }, + { 241, 16, 1 }, + { -241, 16, 1 }, + { 242, 16, 1 }, + { -242, 16, 1 }, + { 243, 16, 1 }, + { -243, 16, 1 }, + { 244, 16, 1 }, + { -244, 16, 1 }, + { 245, 16, 1 }, + { -245, 16, 1 }, + { 246, 16, 1 }, + { -246, 16, 1 }, + { 247, 16, 1 }, + { -247, 16, 1 }, + { 248, 16, 1 }, + { -248, 16, 1 }, + { 249, 16, 1 }, + { -249, 16, 1 }, + { 250, 16, 1 }, + { -250, 16, 1 }, + { 251, 16, 1 }, + { -251, 16, 1 }, + { 252, 16, 1 }, + { -252, 16, 1 }, + { 253, 16, 1 }, + { -253, 16, 1 }, + { 254, 16, 1 }, + { -254, 16, 1 }, + { 255, 16, 1 }, + { -255, 16, 1 } +}; +/* }}} */ +/* {{{ [fold] qc_mjpeg_lvc_decode_block(struct bitstream *bitsrc, s16 *output, int blockval) */ +static inline void qc_mjpeg_lvc_decode_block(struct bitstream *bitsrc, s16 *output, int blockval) +{ + u32 b; + u8 *p; + int k; + int value, skip, bits; + struct hufftable_entry entry; + int offset = 0; + const u8 *shiftPtr; + + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_lvc_decode_block(bitsrc=%p, output=%p, blockval=%i)", bitsrc, output, blockval); + b = bitsrc->b; + k = bitsrc->k; + p = bitsrc->p; + memset(output, 0, 64 * sizeof(s16)); + if (blockval!=7) PDEBUG("blockval=%i",blockval); + NEEDBITS(b,k,p); + shiftPtr = shiftTables[shiftTblIndex[2*blockval+BITVALUE(b,1)]]; + DUMPBITS(b,k,1); + value = BITVALUE(((signed)b),10); + DUMPBITS(b,k,10); + do { + value = ((value << shiftPtr[offset]) * scaleTable[offset]) >> 14; + output[scan_norm[offset]] = value; + NEEDBITS(b,k,p); + entry = hufftable[BITVALUE(b,8)]; + bits = entry.bits; + if (bits > 8) { + entry = hufftable[entry.value + ((b & 0x00ffffff) >> (32 - bits))]; + if (PARANOID && entry.bits!=bits) { + PDEBUG("entry.bits!=bits shouldn't happen"); + bits = entry.bits; + } + } + DUMPBITS(b,k,bits); + skip = entry.skip; + value = entry.value; + offset += skip; + } while (offset < 64); + bitsrc->b = b; + bitsrc->k = k; + bitsrc->p = p; + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_lvc_decode_block() exit"); +} +/* }}} */ + +/* {{{ [fold] struct blockorder */ +struct blockorder { + char widthPad; /* pad width to multiple of this */ + char heightPad; /* pad height to multiple of this */ + char uvWshift; /* shift width by this to get width of U/V image */ + char uvHshift; /* dito for height */ + char blockWidth[2]; /* width of a block for each pass*/ + char subblockCount[2]; /* number of sub block in a block for each pass */ + u32 subblockMap[2]; +}; +static const struct blockorder order_I420 = { + 32, 16, 1, 1, + { 32, 16 }, { 4, 4 }, + { 0x00, 0x90 } +}; +#if 0 +static const struct blockorder order_L422 = { + 16, 16, 1, 0, + { 16, 16 }, { 4, 4 }, + { 0x90, 0x90 } +}; + +static const struct blockorder order_L410 = { + 64, 16, 2, 1, + { 32, 64 }, { 4, 12 }, + { 0x00, 0x909000 } +}; +#endif +/* }}} */ +/* {{{ [fold] qc_mjpeg_lvc_decode() */ +/* Decode given compressed image to YUV image. Return error code if bad data */ +static int qc_mjpeg_lvc_decode(u8 *outY, u8 *outU, u8 *outV, + u8 *input, u32 length, unsigned int width, unsigned int height) +{ + struct bitstream stream; + const struct blockorder *blkorder; + + unsigned int blockx, blocky; + unsigned int pass, subblock, blockval = 0; + unsigned int blocknr = 0; + unsigned int uvWidth; + + s16 blockbuffer[64]; + + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_lvc_decode(outY=%p, outU=%p, outV=%p)", outY, outU, outV); + stream.b = 0; + stream.k = 16; + stream.p = input; + stream.end = input+length; + + blkorder = &order_I420; /* Select compression type */ + + uvWidth = (width >> blkorder->uvWshift); + + if ((width & (blkorder->widthPad - 1)) || (height & (blkorder->heightPad - 1))) { + PDEBUG("something's wrong"); + return -EILSEQ; + } + + for (blocky=0; blockyheightPad) { + for (pass = 0; pass < 2; pass++) { + int blockwidth = blkorder->blockWidth[pass]; + int subblockcount = blkorder->subblockCount[pass]; + u32 map = blkorder->subblockMap[pass]; + for (blockx=0; blockx stream.end) { + PDEBUG("p>stream.end"); + return -EILSEQ; + } + + blockval = BITVALUE(b, 4); + DUMPBITS(b,k,4); + stream.b = b; + stream.k = k; + stream.p = p; + } + qc_mjpeg_lvc_decode_block(&stream, blockbuffer, blockval); + blockbuffer[0] += 1024; + switch (subblkmap & 3) { + case 0: + qc_mjpeg_idct(blockbuffer, outY, width); + outY += 8; + break; + case 1: + qc_mjpeg_idct(blockbuffer, outU, uvWidth); + outU += 8; + break; + case 2: + qc_mjpeg_idct(blockbuffer, outV, uvWidth); + outV += 8; + break; + } + subblkmap >>= 2; + } /* for (subblock = 0; subblock < subblockcount; subblock++) */ + } /* for (blockx = 0; blockx < width; blockx += blockwidth) */ + outY += 7 * width; + if (map) { + outU += 7 * uvWidth; + outV += 7 * uvWidth; + } + } /* for (pass = 0; pass < 2; pass++) */ + + /* next block starts at next 4 byte boundary */ + stream.p -= (16 - stream.k) >> 3; /* push back unread bits */ + stream.p += (input - stream.p) & 3; + stream.k = 16; + stream.b = 0; + } /* for (blocky=0; blockyheightPad) */ + + if (stream.p != stream.end) { + PDEBUG("stream.p != stream.end"); + return -EILSEQ; + } + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_lvc_decode() done"); + return 0; +} +/* }}} */ + +/* }}} */ +/* {{{ [fold] **** qc_mjpeg: Motion JPEG decoding main routines *************************** */ + +static const int qc_mjpeg_width = 320; /* Size of the compressed image */ +static const int qc_mjpeg_height = 240; + +/* {{{ [fold] qc_mjpeg_decode() */ +/* Decode and uncompress given data, return error code if failure + * src = points to compressed bitstream data + * src_len = compressed data length in bytes + * dst = decompressed image will be stored here, size 320x240 x bytes per pixel (2-4) + */ +int qc_mjpeg_decode(struct qc_mjpeg_data *md, unsigned char *src, int src_len, unsigned char *dst) +{ + int r; + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_decode(src_len=%i,W=%i,H=%i,depth=%i)",src_len,qc_mjpeg_width,qc_mjpeg_height,md->depth); + IDEBUG_TEST(*md); + if (src_len >= 100000) { + PDEBUG("long frame, length=%i", src_len); + return -EILSEQ; + } + r = qc_mjpeg_lvc_decode(md->encY, md->encU, md->encV, src, src_len, qc_mjpeg_width, qc_mjpeg_height); + if (r<0) { + PRINTK(KERN_ERR,"frame corrupted, len=%i",src_len); + return r; + } + qc_mjpeg_yuv2rgb(md, dst, md->encY, md->encU, md->encV, + qc_mjpeg_width, qc_mjpeg_height, /* Image size */ + qc_mjpeg_width * ((md->depth+1)/8), /* RGB stride */ + qc_mjpeg_width, /* Y stride */ + qc_mjpeg_width/2); /* U and V stride */ + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_decode() done"); + return 0; +} +/* }}} */ +/* {{{ [fold] qc_mjpeg_init(struct qc_mjpeg_data *md, int depth, Bool tobgr) */ +/* Initialize Motion JPEG decompression. + * depth = bit depth of the decoded image, either 15=16,24 or 32 + * tobgr = use blue in the lowest address (red otherwise) + */ +int qc_mjpeg_init(struct qc_mjpeg_data *md, int depth, Bool tobgr) +{ + int r = -ENOMEM; + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_init(depth=%i)",depth); + md->depth = depth; + /* Temporary buffers used for decoding the image (FIXME:too big for stack?) */ + /* Note: originally this allocated one extra byte for encY/U/V. I removed that. */ + md->encY = kmalloc(qc_mjpeg_width*qc_mjpeg_height, GFP_KERNEL); + if (!md->encY) goto fail1; + md->encU = kmalloc(qc_mjpeg_width*qc_mjpeg_height/4, GFP_KERNEL); + if (!md->encU) goto fail2; + md->encV = kmalloc(qc_mjpeg_width*qc_mjpeg_height/4, GFP_KERNEL); + if (!md->encV) goto fail3; + if ((r=qc_mjpeg_yuv2rgb_init(md, depth, tobgr ? MODE_BGR : MODE_RGB))<0) goto fail4; + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_init() done"); + IDEBUG_INIT(*md); + return 0; + +fail4: kfree(md->encV); +fail3: kfree(md->encU); +fail2: kfree(md->encY); +fail1: PDEBUG("failed qc_mjpeg_init() = %i", r); + POISON(*md); + return r; +} +/* }}} */ +/* {{{ [fold] qc_mjpeg_exit(struct qc_mjpeg_data *md) */ +/* Free up resources allocated for image decompression */ +void qc_mjpeg_exit(struct qc_mjpeg_data *md) +{ + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_exit()"); + IDEBUG_TEST(*md); + qc_mjpeg_yuv2rgb_exit(md); + kfree(md->encV); + kfree(md->encU); + kfree(md->encY); + POISON(md->encV); + POISON(md->encU); + POISON(md->encY); + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_mjpeg_exit() done"); + IDEBUG_EXIT(*md); +} +/* }}} */ + +/* }}} */ + +#else /* COMPRESS=0 */ +int qc_mjpeg_decode(struct qc_mjpeg_data *md, unsigned char *src, int src_len, unsigned char *dst) { return -ENXIO; } +int qc_mjpeg_init(struct qc_mjpeg_data *md, int depth, Bool tobgr) { return -ENXIO; } +void qc_mjpeg_exit(struct qc_mjpeg_data *md) { } +#endif + +/* End of file */ --- linux-2.6.27.orig/ubuntu/qc-usb/qc-driver.c +++ linux-2.6.27/ubuntu/qc-usb/qc-driver.c @@ -0,0 +1,3410 @@ +/* Start of file */ + +/* {{{ [fold] Comments */ + +/* + * qc-usb, Logitech QuickCam video driver with V4L support + * Derived from qce-ga, linux V4L driver for the QuickCam Express and Dexxa QuickCam + * + * qc-driver.c - main driver part + * + * Copyright (C) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (C) 2002,2003 Tuukka Toivonen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* Cam variations of Logitech QuickCam: + P/N 861037: Sensor HDCS1000 ASIC STV0600 + P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 ("QuickCam Express") + P/N 861055: Sensor ST VV6410 ASIC STV0610 ("LEGO cam") + P/N 861075-0040: Sensor HDCS1000 ASIC + P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 (Dexxa WebCam USB) + P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 ("QuickCam Web") + + For any questions ask + qce-ga-devel@lists.sourceforge.net - about code + qce-ga-discussion@lists.sourceforge.net - about usage +*/ +/* }}} */ +/* {{{ [fold] Includes */ +#include "quickcam.h" + +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) +#include +#endif +#include + +#include "qc-memory.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +#include +#endif +/* }}} */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) +/* Make this a bit backwards compatible... hack hack... */ +#ifndef module_param +#define module_param(a, b, c) MODULE_PARM(a, "i") +#endif +#endif + +/* {{{ [fold] Module parameters */ +MODULE_PARM_DESC(qcdebug, "Sets the debug output (bitfield)"); +int qcdebug = DEBUGLEVEL; +module_param(qcdebug, int, 0444); + +MODULE_PARM_DESC(keepsettings, "Keep picture settings across one open to another (0-1)"); +static int keepsettings = 0; +module_param(keepsettings, int, 0444); + +MODULE_PARM_DESC(settle, "Maximum number of frames to wait picture brightness to settle (0-255)"); +static int settle = 0; +module_param(settle, int, 0444); + +/* Subsampling is used to allow higher scan rate with smaller images. */ +MODULE_PARM_DESC(subsample, "Sets subsampling (0-1)"); +static int subsample = 0; /* normal or sub-sample (sub-sample to increase the speed) */ +module_param(subsample, int, 0444); + +MODULE_PARM_DESC(compress, "Enable compressed mode (0-1)"); +static int compress = 0; /* Enable compressed mode if available (higher framerate) */ +module_param(compress, int, 0444); + +MODULE_PARM_DESC(frameskip, "How frequently capture frames (0-10)"); +static int frameskip = 0; +module_param(frameskip, int, 0444); + +MODULE_PARM_DESC(quality, "Sets the picture quality (0-5)"); +static int quality = 5; /* 5 = generalized adjustable Pei-Tam method */ +module_param(quality, int, 0444); + +MODULE_PARM_DESC(adaptive, "Automatic adaptive brightness control (0-1)"); +static int adaptive = 1; +module_param(adaptive, int, 0444); + +MODULE_PARM_DESC(equalize, "Equalize image (0-1)"); +static int equalize = 0; /* Disabled by default */ +module_param(equalize, int, 0444); + +MODULE_PARM_DESC(userlut, "Apply user-specified lookup-table (0-1)"); +static int userlut = 0; /* Disabled by default */ +module_param(userlut, int, 0444); + +MODULE_PARM_DESC(retryerrors, "Retry if image capture fails, otherwise return error code (0-1)"); +static int retryerrors = 1; /* Enabled by default */ +module_param(retryerrors, int, 0444); + +/* Bug in Xvideo(?): if the width is not divisible by 8 and Xvideo is used, the frame is shown wrongly */ +MODULE_PARM_DESC(compatible, "Enable workaround for bugs in application programs (bitfield)"); +static int compatible = 0; /* Disabled by default */ +module_param(compatible, int, 0444); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,5) +MODULE_PARM_DESC(video_nr, "Set videodevice number (/dev/videoX)"); +static int video_nr = -1; +module_param(video_nr, int, 0444); +/* video_nr option allows to specify a certain /dev/videoX device */ +/* (like /dev/video0 or /dev/video1 ...) */ +/* for autodetect first available use video_nr=-1 (defaultvalue) */ +#endif +/* }}} */ +/* {{{ [fold] Miscellaneous data */ +#ifndef MODULE_LICENSE /* Appeared in 2.4.10 */ +#ifdef MODULE +#define MODULE_LICENSE(license) \ +static const char __module_license[] __attribute__((section(".modinfo"))) = \ + "license=" license +#else +#define MODULE_LICENSE(license) +#endif +#endif + +MODULE_SUPPORTED_DEVICE("video"); +MODULE_DESCRIPTION("Logitech QuickCam USB driver"); +MODULE_AUTHOR("See README"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; + +static const int min_framewidth = 32; /* Minimum image size we allow delivering to user application */ +static const int min_frameheight = 32; + +static const char qc_proc_name[] = "video/quickcam"; +#define qc_name (&qc_proc_name[6]) + +static struct usb_device_id qc_device_table[] = { + { USB_DEVICE(0x046D, 0x0840) }, /* QuickCam Express */ + { USB_DEVICE(0x046D, 0x0850) }, /* LEGO cam / QuickCam Web */ + { USB_DEVICE(0x046D, 0x0870) }, /* Dexxa WebCam USB */ + { USB_DEVICE(0x046D, 0x08F6) }, /* Logitech QuickCam Messenger */ + { } +}; +MODULE_DEVICE_TABLE(usb, qc_device_table); + +extern const struct qc_sensor qc_sensor_pb0100; +extern const struct qc_sensor qc_sensor_hdcs1000; +extern const struct qc_sensor qc_sensor_hdcs1020; +extern const struct qc_sensor qc_sensor_vv6410; + +static const struct qc_sensor *sensors[] = { + &qc_sensor_hdcs1000, + &qc_sensor_hdcs1020, + &qc_sensor_pb0100, + &qc_sensor_vv6410, +}; + +static LIST_HEAD(quickcam_list); /* Linked list containing all QuickCams */ +static DECLARE_MUTEX(quickcam_list_lock); /* Always lock first quickcam_list_lock, then qc->lock */ + +/* Default values for user-specified lookup-table; may be overwritten by user */ +static unsigned char userlut_contents[QC_LUT_SIZE] = { + /* Red */ + 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, + 44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, + 71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, + 88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, + 134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, + 143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, + 152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, + 159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, + 167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, + 173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, + 180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, + 187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, + 192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, + 198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, + 204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, + 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, + 215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, + 220, 220, 221, 221, + + /* Green */ + 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, + 50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, + 79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, + 98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, + 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, + 150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, + 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, + 169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, + 177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, + 186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, + 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, + 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, + 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, + 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, + 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, + 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, + 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, + 239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, + 245, 245, 246, 246, + + /* Blue */ + 0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, + 55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, + 86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, + 107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, + 125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, + 152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, + 165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, + 176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, + 185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, + 194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, + 204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, + 212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, + 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, + 228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, + 235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, + 243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, + 249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255 +}; + +static void qc_usb_exit(struct quickcam *qc); +static int qc_capt_init(struct quickcam *qc); +static void qc_capt_exit(struct quickcam *qc); +static int qc_capt_get(struct quickcam *qc, unsigned char **frame); +static int qc_isoc_init(struct quickcam *qc); +static void qc_isoc_exit(struct quickcam *qc); +/* }}} */ + +/* {{{ [fold] **** Miscellaneous functions ************************************** */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) +/* {{{ [fold] usb_kill_urb(struct urb *urb) */ +/* Unlink URB synchronously (usb_unlink_urb may not be synchronous). + * Note: at this moment the URB completion handler must not resubmit the same URB. + */ +static void qc_usb_kill_urb(struct urb *urb) { + int r; + while ((r=usb_unlink_urb(urb)) == -EBUSY) { + /* The URB is not anymore linked (status!=-EINPROGRESS) but + * usb_unlink_urb() was asynchronous and URB's completion handler still will run */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout( (HZ/100)==0 ? 1 : HZ/100); + } + /* if (r!=-EBUSY), + * usb_unlink_urb() called synchronously the completion handler and + * there's no need to wait or anything else */ + if (r) PDEBUG("qc_usb_kill_urb(%p): r=%i", urb, r); +} +#undef usb_kill_urb +#define usb_kill_urb(urb) qc_usb_kill_urb(urb) +/* }}} */ +#endif +/* {{{ [fold] qc_usleep(long usec) */ +void qc_usleep(unsigned long usec) +{ + wait_queue_head_t wq; + init_waitqueue_head(&wq); + interruptible_sleep_on_timeout(&wq, usec*HZ/1000000); +} +/* }}} */ +/* {{{ [fold] int qc_get_i2c(struct quickcam *qc, const struct qc_sensor *sensor, int reg) */ +/* Read a sensor byte or word wide register value via STV0600 I2C bus + * qc_i2c_init() must be called first! + */ +int qc_get_i2c(struct quickcam *qc, const struct qc_sensor *sensor, int reg) +{ + struct usb_device *dev = qc->dev; + int ret; + + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_get_i2c(qc=%p,sensor=%p,reg=0x%04X)",qc,sensor,reg); + TEST_BUGR(dev==NULL); + if (sizeof(qc->dmabuf)<35) BUG(); + + /* We need here extra write to the STV register before reading the I2C register */ + /* Also wait until there are no pending control URB requests */ + if ((ret = qc_stv_set(qc, STV_REG23, sensor->reg23))<0) goto fail; + + memset(qc->dmabuf, 0, 35); + qc->dmabuf[0] = reg; + qc->dmabuf[0x20] = sensor->i2c_addr; + qc->dmabuf[0x21] = 0; /* 0+1 = 1 value, one byte or word wide register */ + qc->dmabuf[0x22] = 3; /* Read I2C register */ + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x04, + 0x40, + 0x1400, 0, /* Write I2C register address, 35 bytes */ + qc->dmabuf, 0x23, 3*HZ); + if (ret < 0) goto fail; + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + 0x04, + 0xC0, + 0x1410, 0, /* Read register contents from I2C, 1 or 2 bytes */ + qc->dmabuf, sensor->length_id, 3*HZ); + if (ret < 0) goto fail; + ret = qc->dmabuf[0]; + if (sensor->length_id>1) ret |= qc->dmabuf[1]<<8; /* Assume LSB is always first from data received via USB */ + if (qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_get_i2c(reg=0x%04X) = %04X", reg, ret); + return ret; + +fail: PDEBUG("qc_get_i2c failed, code=%i",ret); + return ret; +} +/* }}} */ +/* {{{ [fold] int qc_stv_set(struct quickcam *qc, unsigned short reg, unsigned char val) */ +/* + * Set one byte register in the STV-chip. qc_i2c_init() must be called first! + */ +int qc_stv_set(struct quickcam *qc, unsigned short reg, unsigned char val) +{ + int ret; + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_stv_set(qc=%p,reg=0x%04X,val=%u)",qc,(int)reg,(int)val); + TEST_BUGR(qc==NULL); + if (sizeof(qc->dmabuf)<1) BUG(); + qc_i2c_wait(qc); /* Wait until no pending commands from qc_i2c_* */ + qc->dmabuf[0] = val; + ret = usb_control_msg(qc->dev, usb_sndctrlpipe(qc->dev, 0), + 0x04, /* Request */ + 0x40, /* RequestType */ + reg, 0, /* Value, Index */ + qc->dmabuf, 1, 3*HZ); + if ((qcdebug&QC_DEBUGERRORS || qcdebug&QC_DEBUGLOGIC) && ret<0) PDEBUG("Failed qc_stv_set()=%i", ret); + if (ret<0) return ret; + return 0; +} +/* }}} */ +/* {{{ [fold] int qc_stv_get(struct quickcam *qc, unsigned short reg) */ +/* + * Read one byte register in the STV-chip. qc_i2c_init() must be called first! + * Return the unsigned register value or negative error code on error. + */ +int qc_stv_get(struct quickcam *qc, unsigned short reg) +{ + int ret; + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_stv_get(qc=%p,reg=0x%04X)",qc,(int)reg); + TEST_BUGR(qc==NULL); + if (sizeof(qc->dmabuf)<1) BUG(); + qc_i2c_wait(qc); /* Wait until no pending commands from qc_i2c_* */ + ret = usb_control_msg(qc->dev, usb_rcvctrlpipe(qc->dev, 0), + 0x04, /* Request */ + 0xC0, /* RequestType */ + reg, 0, /* Value, Index */ + qc->dmabuf, 1, 3*HZ); + if ((qcdebug&QC_DEBUGERRORS || qcdebug&QC_DEBUGLOGIC) && ret<0) PDEBUG("Failed qc_stv_get()=%i", ret); + if (ret<0) return ret; + if (qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_stv_get(reg=0x%04X)=%02X", reg, qc->dmabuf[0]); + return qc->dmabuf[0]; +} +/* }}} */ +/* {{{ [fold] int qc_stv_setw(struct quickcam *qc, unsigned short reg, unsigned short val) */ +/* + * Set two byte register in the STV-chip. qc_i2c_init() must be called first! + * "w" means either "word" or "wide", depending on your religion ;) + */ +int qc_stv_setw(struct quickcam *qc, unsigned short reg, unsigned short val) +{ + int ret; + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_stv_setw(qc=%p,reg=0x%04X,val=%i)",qc,(int)reg,(int)val); + TEST_BUGR(qc==NULL); + if (sizeof(qc->dmabuf)<2) BUG(); + qc_i2c_wait(qc); + qc->dmabuf[0] = val & 0xFF; + qc->dmabuf[1] = (val >> 8) & 0xFF; + ret = usb_control_msg(qc->dev, usb_sndctrlpipe(qc->dev, 0), + 0x04, + 0x40, + reg, 0, + qc->dmabuf, 2, 3*HZ); + if ((qcdebug&QC_DEBUGERRORS || qcdebug&QC_DEBUGLOGIC) && ret<0) PDEBUG("Failed qc_stv_setw()=%i", ret); + if (ret<0) return ret; + return 0; +} +/* }}} */ +/* {{{ [fold] void qc_hsv2rgb(s16 hue, u16 sat, u16 val, int *red, int *green, int *blue) */ +/* Convert HSI (hue, saturation, intensity) to RGB (red, green, blue). + * All input and output values are 0..65535. + * Hue is actually signed, so it is -32768..32767, but this is equivalent + * since it is the angle around full circle (0=Red, 21845=Green, 43690=Blue). + * Based on libgimp, converted to 16.16 fixed point by tuukkat. + */ +void qc_hsv2rgb(s16 hue, u16 sat, u16 val, int *red, int *green, int *blue) +{ + unsigned int segment, valsat; + signed int h = (u16)hue; + unsigned int s = (sat<32768) ? 0 : (sat-32768)*2; /* 32768 or less = no saturation */ + unsigned int v = val; /* value = intensity */ + unsigned int p; + +#if 1 /* Make common case more efficient */ + if (s == 0) { + *red = v; + *green = v; + *blue = v; + return; + } +#endif + segment = (h + 10923) & 0xFFFF; + segment = segment*3 >> 16; /* 0..2: 0=R, 1=G, 2=B */ + hue -= segment * 21845; /* -10923..10923 */ + h = hue; + h *= 3; + valsat = v*s >> 16; /* 0..65534 */ + p = v - valsat; + if (h>=0) { + unsigned int t = v - (valsat * (32769 - h) >> 15); + switch (segment) { + default: + PDEBUG("hsi2rgb: this can never happen!"); + case 0: /* R-> */ + *red = v; + *green = t; + *blue = p; + break; + case 1: /* G-> */ + *red = p; + *green = v; + *blue = t; + break; + case 2: /* B-> */ + *red = t; + *green = p; + *blue = v; + break; + } + } else { + unsigned int q = v - (valsat * (32769 + h) >> 15); + switch (segment) { + default: + PDEBUG("hsi2rgb: this can never happen!"); + case 0: /* ->R */ + *red = v; + *green = p; + *blue = q; + break; + case 1: /* ->G */ + *red = q; + *green = v; + *blue = p; + break; + case 2: /* ->B */ + *red = p; + *green = q; + *blue = v; + break; + } + } + //PDEBUG("hue=%i sat=%i val=%i segment=%i h=%i r=%i g=%i b=%i",hue,sat,val, segment,h, *red,*green,*blue); +} + +/* }}} */ +/* {{{ [fold] int qc_lock(struct quickcam *qc) */ +/* Takes a lock on quickcam_list_lock and verifies that the given qc is available */ +/* Returns 0 on success in which case the lock must be freed later or negative error code */ +static int qc_lock(struct quickcam *qc) +{ + struct quickcam *q; + + if (down_interruptible(&quickcam_list_lock)) return -ERESTARTSYS; + + /* Search for the device in the list of plugged quickcams (this prevents a race condition) */ + list_for_each_entry(q, &quickcam_list, list) { + if (q == qc) break; /* Found it? */ + } + if (q != qc) { + PDEBUG("can not find the device to open"); + up(&quickcam_list_lock); + return -ENODEV; + } + return 0; +} +/* }}} */ + +/* }}} */ +/* {{{ [fold] **** qc_i2c: I2C URB messaging routines (qc_i2c_*) ************* */ + +/* We have here a quite typical producer-consumer scheme: + * URB interrupt handler routine consumes i2c data, while + * kernel mode processes create more of it. + * Ref: Linux Device Drivers, Alessandro Rubini et al, 2nd edition, pg. 279 + * "Using Circular Buffers" + */ + +static const int qc_i2c_maxbufsize = 0x23; + +/* {{{ [fold] (private) qc_i2c_nextpacket(struct quickcam *qc) */ +/* Fill URB and submit it, if there are more data to send + * Consume data from "commands" array. May be called from interrupt context. + * Return standard error code. + */ +static int qc_i2c_nextpacket(struct quickcam *qc) +{ + struct qc_i2c_data *id = &qc->i2c_data; + struct urb *urb = id->urb; + u8 *tb = urb->transfer_buffer, flags; + struct usb_ctrlrequest *cr = (struct usb_ctrlrequest *)urb->setup_packet; + unsigned int newtail, length, regnum, i, j; + signed int r; + + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_i2c_nextpacket(quickcam=%p), tail=%i, head=%i, interrupt=%i",qc,id->tail,id->head,(int)in_interrupt()); + IDEBUG_TEST(*id); + + if (!qc->connected) { + /* Device was disconnected, cancel all pending packets and return */ + id->tail = id->head = id->newhead = 0; + id->packets = 0; + return -ENODEV; + } + + newtail = id->tail; /* First data to fetch */ + if (id->packets<=1 && newtail==id->head) { /* packets==0 or 1: no extra URB need to be scheduled */ + if (qcdebug&QC_DEBUGCONTROLURBS) PDEBUG("No more control URBs to send"); + r = 0; + goto nourbs; + } + if (id->packets<=1) { + /* Collect data from circular buffer to URB transfer buffer */ + /* Now id->tail!=id->head: there's at least one packet to send */ + TEST_BUGR(newtail==id->head); + id->packets = 1; + if (GET_PRODUCTID(qc)==0x0850) id->packets = 2; + regnum = 0x0400; + length = qc_i2c_maxbufsize; + + i = 0; /* Transfer buffer position */ + if (!(id->commands[newtail].flags & I2C_FLAG_WORD)) { + /* Normal byte-wide register write */ + if (qcdebug&QC_DEBUGCONTROLURBS) PDEBUG("Setting byte-wide registers"); + do { + tb[i] = id->commands[newtail].regnum; + tb[i+0x10] = id->commands[newtail].loval; + flags = id->commands[newtail].flags; + i++; + newtail = (newtail + 1) % I2C_MAXCOMMANDS; /* Next data to fetch */ + if (flags & I2C_FLAG_BREAK) break; /* Start new packet */ + if (newtail == id->head) break; /* No more data? */ + if (i > 0x0F) break; /* Transfer buffer full? */ + if (id->commands[newtail].flags & I2C_FLAG_WORD) break; + } while (TRUE); +/*if (flags&I2C_FLAG_BREAK) PDEBUG("breaking!!!!!!!!!!"); +{ +int mm; +for(mm=0;mmcommands[newtail].regnum; + tb[i*2+0x10] = id->commands[newtail].loval; + tb[i*2+0x11] = id->commands[newtail].hival; + flags = id->commands[newtail].flags; + i++; + newtail = (newtail + 1) % I2C_MAXCOMMANDS; /* Next data to fetch */ + if (flags & I2C_FLAG_BREAK) break; /* Start new packet */ + if (newtail == id->head) break; /* No more data? */ + if (i > 0x07) break; /* Transfer buffer full? */ + if (!(id->commands[newtail].flags & I2C_FLAG_WORD)) break; + } while (TRUE); + for (j=i*2; j<0x10; j++) tb[j+0x10] = 0; /* Zero out unused register values just to be sure */ + } + for (j=i; j<0x10; j++) tb[j] = 0; /* Zero out unused register addresses just to be sure */ + tb[0x20] = qc->sensor_data.sensor->i2c_addr; + tb[0x21] = i-1; /* Number of commands to send - 1 */ + tb[0x22] = 1; /* Write cmd, 03 would be read. */ + id->tail = newtail; + if (qcdebug&QC_DEBUGCONTROLURBS) PDEBUG("sending i2c packet, cmds=%i, reg0=%02X, val0=%02X",tb[0x21]+1,tb[0],tb[0x10]); + } else { + /* id->packets==2: send extra packet for QuickCam Web */ + if (qcdebug&QC_DEBUGCONTROLURBS) PDEBUG("sending finalization packet"); + id->packets = 1; + regnum = 0x1704; + length = 1; + tb[0] = 1; + } + urb->dev = qc->dev; /* 2.4.x zeroes urb->dev after submission */ + urb->pipe = usb_sndctrlpipe(qc->dev, 0); + urb->transfer_buffer_length = length; + cr->wValue = cpu_to_le16(regnum); + cr->wLength = cpu_to_le16(length); + r = usb_submit_urb(urb,GFP_ATOMIC); + CHECK_ERROR(r<0, nourbs, "Failed qc_i2c_nextpacket()=%i", r); + return 0; + +nourbs: id->packets = 0; /* No more URBs are scheduled */ + wake_up(&id->wq); //FIXME: race condition: now packets=0, so id could be freed and wake_up do oops + return r; +} +/* }}} */ +/* {{{ [fold] (private) qc_i2c_handler(struct urb *urb) */ +/* This is URB completion handler and is called in interrupt context. + * For each submitted URB, this function is guaranteed to be called exactly once. + * This function may not be called reentrantly for the same qc (should be ok, IRQs don't nest). + * It will resubmit the same URB, if + * - The previous URB completed without error + * - Camera is still connected (qc->connected == TRUE) + * - There is still commands to be sent in commands buffer or pid=0x850 and finalization packet is not yet sent. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void qc_i2c_handler(struct urb *urb, struct pt_regs *ptregs) +#else +static void qc_i2c_handler(struct urb *urb) +#endif +{ + struct quickcam *qc = urb->context; + + if (qcdebug&QC_DEBUGINTERRUPTS) PDEBUG("[INTR] qc_i2c_handler(urb=%p)",urb); + TEST_BUG(urb==NULL); + TEST_BUG(qc==NULL); + IDEBUG_TEST(qc->i2c_data); + if (urb->status<0) { + switch (urb->status) { + default: + /* Seen here: ECONNABORTED 103 Software caused connection abort */ + PRINTK(KERN_ERR,"Unhandled control URB error %i",urb->status); + case -EPROTO: /* Bitstuff error or unknown USB error */ + case -EILSEQ: /* CRC mismatch */ + case -ETIMEDOUT: /* Transfer timed out */ + case -EREMOTEIO: /* Short packet detected */ + case -EPIPE: /* Babble detect or endpoint stalled */ + /* We could try resubmitting the URB here */ + case -ENOENT: /* URB was unlinked */ + case -ENODEV: /* Device was removed */ + case -ECONNRESET: /* Asynchronous unlink, should not happen */ + PRINTK(KERN_ERR,"Control URB error %i",urb->status); + qc->i2c_data.packets = 0; /* Don't schedule more URBs */ + wake_up(&qc->i2c_data.wq); + return; + } + } + qc_i2c_nextpacket(qc); +} +/* }}} */ +/* {{{ [fold] qc_i2c_flush(struct quickcam *qc) */ +/* Allow all register settings set earlier to be scheduled and sent to camera */ +static int qc_i2c_flush(struct quickcam *qc) +{ + struct qc_i2c_data *id = &qc->i2c_data; + int r = 0; + + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_i2c_flush(quickcam=%p,regs=%i)",qc, + (id->newhead+I2C_MAXCOMMANDS-id->head)%I2C_MAXCOMMANDS); + IDEBUG_TEST(*id); + id->head = id->newhead; + if (id->packets==0) /* Schedule URB if there aren't any in progress */ + r = qc_i2c_nextpacket(qc); + return r; +} +/* }}} */ +/* {{{ [fold] qc_i2c_wait(struct quickcam *qc) */ +/* Wait until all previosly set registers are set or abort all transmissions + * and return error code. + * After this function returns, there will not be uncompleted I2C URBs. + */ +int qc_i2c_wait(struct quickcam *qc) +{ + struct qc_i2c_data *id = &qc->i2c_data; + int r; + + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_i2c_wait(quickcam=%p)",qc); + TEST_BUGR(in_interrupt()); + TEST_BUGR(qc==NULL); + IDEBUG_TEST(*id); + + if (!qc->connected) goto cancel; + r = qc_i2c_flush(qc); + if (r>=0) r = wait_event_interruptible(id->wq, id->packets==0); + if (r<0) goto cancel; + return 0; + +cancel: if (qcdebug&QC_DEBUGLOGIC) PDEBUG("Canceling pending URB %p, packets=%i", id->urb, id->packets); + PDEBUG("i2c_cancel: qc=%p, id=%p",qc,id); + PDEBUG("i2c_cancel: id->urb=%p", id->urb); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + if (qc->connected) { + PDEBUG("i2c_cancel: id->urb->dev=%p", id->urb->dev); + if (id->urb->dev!=NULL) { + PDEBUG("i2c_cancel: id->urb->dev->bus=%p", id->urb->dev->bus); + if (id->urb->dev->bus!=NULL) { + PDEBUG("i2c_cancel: id->urb->dev->bus->op=%p", id->urb->dev->bus->op); + //PDEBUG("id->urb->dev->bus->op->unlink=%p", id->urb->dev->bus->op->unlink); + } + } + } +#endif + /* Cancel URB if it is in progress or in completion handler */ + if (id->packets > 0) usb_kill_urb(id->urb); + TEST_BUGR_MSG(id->packets!=0, "i2c_wait: packets=%i", id->packets); + return 0; +} +/* }}} */ +/* {{{ [fold] (private) qc_i2c_set0(struct quickcam *qc, unsigned char regnum, unsigned char loval, unsigned char hival, int flags) */ +/* Called from qc_i2c_set and qc_i2c_setw, should not be called elsewhere */ +static int qc_i2c_set0(struct quickcam *qc, unsigned char regnum, unsigned char loval, unsigned char hival, int flags) +{ + struct qc_i2c_data *id = &qc->i2c_data; + unsigned int newhead; + signed int r; + + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_i2c_set0(quickcam=%p,reg=%02X,val=%02X%02X)",qc,regnum,hival,loval); + TEST_BUGR(qc==NULL); + IDEBUG_TEST(*id); + newhead = id->newhead; + id->commands[newhead].loval = loval; + id->commands[newhead].hival = hival; + id->commands[newhead].regnum = regnum; + id->commands[newhead].flags = flags; + newhead = (newhead + 1) % I2C_MAXCOMMANDS; + if (newhead == id->tail) { /* If buffer is full, wait until it's empty */ + if (qcdebug&QC_DEBUGCONTROLURBS) PDEBUG("i2c buffer is full, waiting"); + r = qc_i2c_wait(qc); + if (r<0) return r; + } + TEST_BUGR(newhead==id->tail); /* no i2c buffer space but nothing to send!!! */ + id->newhead = newhead; + return 0; +} +/* }}} */ +/* {{{ [fold] qc_i2c_set(struct quickcam *qc, unsigned char reg, unsigned char val) */ +/* Set an I2C register to desired value */ +/* (queue setting to be sent later when qc_i2c_flush() is called) */ +inline int qc_i2c_set(struct quickcam *qc, unsigned char reg, unsigned char val) +{ + return qc_i2c_set0(qc, reg, val, 0, 0); +} +/* }}} */ +/* {{{ [fold] qc_i2c_setw(struct quickcam *qc, unsigned char reg, unsigned short val) */ +/* Set a two-byte (word length) I2C register to desired value (queue setting to be sent later) */ +/* (queue setting to be sent later when qc_i2c_flush() is called) */ +inline int qc_i2c_setw(struct quickcam *qc, unsigned char reg, unsigned short val) +{ + return qc_i2c_set0(qc, reg, val & 0xFF, (val >> 8) & 0xFF, I2C_FLAG_WORD); +} +/* }}} */ +/* {{{ [fold] qc_i2c_break(struct quickcam *qc) */ +/* The next register written will be sent in another packet */ +int qc_i2c_break(struct quickcam *qc) +{ + struct qc_i2c_data *id = &qc->i2c_data; + unsigned int prevhead; + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_i2c_break(quickcam=%p)",qc); + TEST_BUGR(qc==NULL); + IDEBUG_TEST(*id); + /* We access an entry that may be already submitted and even finished */ + /* But it should not harm */ + prevhead = (id->newhead + I2C_MAXCOMMANDS - 1) % I2C_MAXCOMMANDS; + id->commands[prevhead].flags |= I2C_FLAG_BREAK; + barrier(); + return qc_i2c_flush(qc); +} +/* }}} */ +/* {{{ [fold] qc_i2c_init(struct quickcam *qc) */ +/* Initialize structures and hardware for I2C communication */ +static int qc_i2c_init(struct quickcam *qc) +{ + struct qc_i2c_data *id = &qc->i2c_data; + struct urb *urb; + struct usb_ctrlrequest *cr; + int r = -ENOMEM; + + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_i2c_init(quickcam=%p)",qc); + TEST_BUGR(qc==NULL); + + id->tail = id->head = id->newhead = 0; /* Next position to be filled and sent is 0 */ + id->packets = 0; + init_waitqueue_head(&id->wq); + + /* Allocate an URB and associated buffers and fill them */ + urb = id->urb = usb_alloc_urb(0,GFP_KERNEL); + if (!urb) goto fail1; + cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + urb->setup_packet = (unsigned char *)cr; + if (!cr) goto fail2; + urb->transfer_buffer = kmalloc(qc_i2c_maxbufsize*sizeof(u8), GFP_KERNEL); /* Allocate maximum ever needed */ + if (!urb->transfer_buffer) goto fail3; + urb->complete = qc_i2c_handler; + urb->context = qc; +#if (LINUX_VERSION_CODEtimeout = 3*HZ; /* 1 s */ +#endif + cr->bRequestType = 0x40; + cr->bRequest = 0x04; + cr->wIndex = 0; + IDEBUG_INIT(*id); + return 0; + +fail3: kfree(cr); +fail2: usb_free_urb(urb); + POISON(id->urb); +fail1: return r; +} +/* }}} */ +/* {{{ [fold] qc_i2c_exit(struct quickcam *qc) */ +/* Close messaging, free up memory, stop messaging */ +static void qc_i2c_exit(struct quickcam *qc) +{ + struct qc_i2c_data *id = &qc->i2c_data; + + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_i2c_exit(qc=%p)",qc); + TEST_BUG(qc==NULL); + qc_i2c_wait(qc); + kfree(id->urb->setup_packet); + kfree(id->urb->transfer_buffer); + POISON(id->urb->setup_packet); + POISON(id->urb->transfer_buffer); + usb_free_urb(id->urb); + IDEBUG_EXIT(*id); +} +/* }}} */ + +/* }}} */ +/* {{{ [fold] **** qc_proc: /proc interface *********************************** */ +#if HAVE_PROCFS + +static struct proc_dir_entry *qc_proc_entry = NULL; /* Initialization should not be necessary, but just in case... */ + +/* {{{ [fold] qc_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) */ +static inline const char *qc_proc_yesno(Bool b) +{ + return b ? "Yes" : "No"; +} + +static int qc_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + struct quickcam *qc = data; + char *out = page; + int len; + + if (qc_lock(qc) < 0) return 0; + + out += sprintf(out, "\tGeneral driver status\n"); + out += sprintf(out, "Driver version : %s\n", VERSION); + out += sprintf(out, "Kernel version : %s\n", UTS_RELEASE); + if (qc->dev!=NULL) { + out += sprintf(out, "Device Id : %04X:%04X\n", (int)GET_VENDORID(qc), (int)GET_PRODUCTID(qc)); + out += sprintf(out, "USB bus number : %i\n", qc->dev->bus->busnum); + } + out += sprintf(out, "Users : %i\n", qc->users); + out += sprintf(out, "Connected : %s\n", qc_proc_yesno(qc->connected)); + + out += sprintf(out, "\n\tPicture settings set by user\n"); + out += sprintf(out, "Brightness : %d\n", (int)qc->vpic.brightness); + out += sprintf(out, "Hue : %d\n", (int)qc->vpic.hue); + out += sprintf(out, "Color : %d\n", (int)qc->vpic.colour); + out += sprintf(out, "Contrast : %d\n", (int)qc->vpic.contrast); + out += sprintf(out, "Whiteness : %d\n", (int)qc->vpic.whiteness); + if (qc->users > 0) { + out += sprintf(out, "Depth : %d\n", (int)qc->vpic.depth); + out += sprintf(out, "Palette : %s\n", qc_fmt_getname(qc->vpic.palette)); + } + + if (qc->users > 0) { + out += sprintf(out, "\n\tOutput window\n"); + out += sprintf(out, "Width : %d\n", (int)qc->vwin.width); + out += sprintf(out, "Height : %d\n", (int)qc->vwin.height); + } + + out += sprintf(out, "\n\tSensor\n"); + out += sprintf(out, "Type : %s\n", qc->sensor_data.sensor->name); + out += sprintf(out, "Manufacturer : %s\n", qc->sensor_data.sensor->manufacturer); + if (qc->users > 0) { + out += sprintf(out, "Maximum width : %d\n", qc->sensor_data.maxwidth); + out += sprintf(out, "Maximum height : %d\n", qc->sensor_data.maxheight); + out += sprintf(out, "Current width : %d\n", qc->sensor_data.width); + out += sprintf(out, "Current height : %d\n", qc->sensor_data.height); + } + + out += sprintf(out, "\n\tI2C command stream\n"); + out += sprintf(out, "Scheduled packets: %d\n", qc->i2c_data.packets); + out += sprintf(out, "Packets on queue : %d\n", (I2C_MAXCOMMANDS + qc->i2c_data.head - qc->i2c_data.tail) % I2C_MAXCOMMANDS); + + if (qc->users > 0) { + out += sprintf(out, "\n\tIsochronous data stream\n"); + out += sprintf(out, "Stream enabled : %s\n", qc_proc_yesno(qc->isoc_data.streaming)); + out += sprintf(out, "Transfer errors : %d\n", qc->isoc_data.errorcount); + + out += sprintf(out, "\n\tFrame buffering\n"); + out += sprintf(out, "Frames on queue : %d\n", (FRAME_BUFFERS + qc->frame_data.head - qc->frame_data.tail) % FRAME_BUFFERS); + out += sprintf(out, "Capturing : %s\n", qc_proc_yesno(qc->stream_data.capturing)); + out += sprintf(out, "Waiting processes: %d\n", qc->frame_data.waiting); + } + + out += sprintf(out, "\n\tAutomatic exposure control\n"); + out += sprintf(out, "Picture intensity: %d\n", qc->adapt_data.oldmidvalue); + out += sprintf(out, "Exposure setting : %d\n", qc->adapt_data.exposure); + out += sprintf(out, "Gain setting : %d\n", qc->adapt_data.gain); + out += sprintf(out, "Delta value : %d\n", qc->adapt_data.olddelta); + out += sprintf(out, "Control algorithm: "); + switch (qc->adapt_data.controlalg) { + case EXPCONTROL_SATURATED: out += sprintf(out, "Saturated\n"); break; + case EXPCONTROL_NEWTON: out += sprintf(out, "Newton\n"); break; + case EXPCONTROL_FLOAT: out += sprintf(out, "Float\n"); break; + default: out += sprintf(out, "?\n"); break; + } + + out += sprintf(out, "\n\tDefault settings\n"); + out += sprintf(out, "Debug : 0x%02X\n", qcdebug); + out += sprintf(out, "Keep settings : %s\n", qc_proc_yesno(qc->settings.keepsettings)); + out += sprintf(out, "Settle max frames: %i\n", qc->settings.settle); + out += sprintf(out, "Subsampling : %s\n", qc_proc_yesno(qc->settings.subsample)); + out += sprintf(out, "Compress : %s\n", qc_proc_yesno(qc->settings.compress)); + out += sprintf(out, "Frame skipping : %i\n", qc->settings.frameskip); + out += sprintf(out, "Image quality : %i\n", qc->settings.quality); + out += sprintf(out, "Adaptive : %s\n", qc_proc_yesno(qc->settings.adaptive)); + out += sprintf(out, "Equalize : %s\n", qc_proc_yesno(qc->settings.equalize)); + out += sprintf(out, "User lookup-table: %s\n", qc_proc_yesno(qc->settings.userlut)); + out += sprintf(out, "Retryerrors : %s\n", qc_proc_yesno(qc->settings.retryerrors)); + out += sprintf(out, "Compatible 16x : %s\n", qc_proc_yesno(qc->settings.compat_16x)); + out += sprintf(out, "Compatible DblBuf: %s\n", qc_proc_yesno(qc->settings.compat_dblbuf)); + out += sprintf(out, "Compatible ToRgb : %s\n", qc_proc_yesno(qc->settings.compat_torgb)); + + up(&quickcam_list_lock); + + len = out - page; + len -= off; + if (len < count) { + *eof = 1; + if (len <= 0) return 0; + } else + len = count; + *start = page + off; + return len; +} +/* }}} */ +/* {{{ [fold] qc_proc_write(struct file *file, const char *buffer, unsigned long count, void *data) */ +static int qc_proc_write(struct file *file, const char *buffer, unsigned long count, void *data) +{ + /* we don't support this....yet? Might replace qcset some day */ + return -EINVAL; +} +/* }}} */ +/* {{{ [fold] qc_proc_create(struct quickcam *qc) */ +/* Called for each camera plugged in, create file containing information of the camera */ +static int qc_proc_create(struct quickcam *qc) +{ + char name[9]; + struct proc_dir_entry *entry; + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_proc_create(quickcam=%p)",qc); + TEST_BUGR(!qc); + qc->proc_entry = NULL; + if (qc_proc_entry==NULL) return -ENOTDIR; + sprintf(name, "video%d", qc->vdev.minor); + entry = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, qc_proc_entry); + if (!entry) { + PRINTK(KERN_WARNING,"Could not register procfs file entry"); + return -ENXIO; + } + entry->owner = THIS_MODULE; + entry->data = qc; + entry->read_proc = qc_proc_read; + entry->write_proc = qc_proc_write; + qc->proc_entry = entry; + return 0; +} +/* }}} */ +/* {{{ [fold] qc_proc_destroy(struct quickcam *qc) */ +/* qc_proc_destroy may be called after qc_proc_create for given quickcam even if it failed */ +static void qc_proc_destroy(struct quickcam *qc) +{ + char name[9]; + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_proc_destroy(quickcam=%p)",qc); + TEST_BUG(!qc); + if (!qc->proc_entry) return; + TEST_BUG(!qc_proc_entry); + sprintf(name, "video%d", qc->vdev.minor); + remove_proc_entry(name, qc_proc_entry); + POISON(qc->proc_entry); + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_proc_destroy() done"); +} +/* }}} */ +/* {{{ [fold] qc_proc_init(void) */ +/* Called when the driver is initially loaded, creates "/proc/video/quickcam" subdirectory */ +static int qc_proc_init(void) +{ + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_proc_init()"); + qc_proc_entry = create_proc_entry(qc_proc_name, S_IFDIR, NULL); /* Create /proc/video/quickcam */ + if (!qc_proc_entry) { + /* create_proc_entry failed, possibly because /proc/video is missing (patch by aceJacek ) */ + proc_mkdir("video", NULL); /* Might fail, if the directory already exists, but we don't care */ + qc_proc_entry = create_proc_entry(qc_proc_name, S_IFDIR, NULL); + if (!qc_proc_entry) { + PRINTK(KERN_WARNING,"Could not register procfs dir entry"); + return -ENXIO; + } + } + qc_proc_entry->owner = THIS_MODULE; + return 0; +} +/* }}} */ +/* {{{ [fold] qc_proc_exit(void) */ +/* Can be called after qc_proc_init() even if it has failed, in which case this does nothing */ +static void qc_proc_exit(void) +{ + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_proc_exit()"); + if (!qc_proc_entry) return; + remove_proc_entry(qc_proc_name, NULL); + POISON(qc_proc_entry); +} +/* }}} */ + +#else +static inline int qc_proc_create(struct quickcam *qc) { return 0; } +static inline void qc_proc_destroy(struct quickcam *qc) { } +static inline int qc_proc_init(void) { return 0; } +static inline void qc_proc_exit(void) { } +#endif /* HAVE_PROCFS */ +/* }}} */ +/* {{{ [fold] **** qc_adapt: Automatic exposure control ************************ */ + +#define MEASURE_ADAPT_DELAY 0 /* Measure adaptation delay, only for test purposes */ + +/* {{{ [fold] qc_adapt_init(struct quickcam *qc) */ +/* Initialize automatic exposure control structure. */ +static int qc_adapt_init(struct quickcam *qc) +{ + struct qc_adapt_data *ctrl = &qc->adapt_data; + ctrl->gain = 32768; + ctrl->olddelta = 4*256; /* best guess */ + ctrl->exposure = 32768; + ctrl->oldexposure = ctrl->exposure + 1; /* Slightly different for _issettled() */ + ctrl->midvaluesum = ctrl->oldmidvalue = 0; + ctrl->framecounter = 0; + ctrl->controlalg = EXPCONTROL_SATURATED; + IDEBUG_INIT(*ctrl); + return 0; +} +/* }}} */ +/* {{{ [fold] qc_adapt_exit(struct quickcam *qc) */ + +static inline void qc_adapt_exit(struct quickcam *qc) +{ +#ifdef DEBUG + struct qc_adapt_data *ctrl = &qc->adapt_data; + if (qcdebug&QC_DEBUGINIT) PDEBUG("qc_adapt_exit(ctrl=%p)",ctrl); + IDEBUG_EXIT(*ctrl); +#endif +} + +/* }}} */ +/* {{{ [fold] qc_adapt_reset(struct quickcam *qc) */ +/* Must be called each time just before starting video adaptation */ +static inline void qc_adapt_reset(struct quickcam *qc) +{ + IDEBUG_TEST(qc->adapt_data); + if (!qc->settings.keepsettings) { + IDEBUG_EXIT(qc->adapt_data); + qc_adapt_init(qc); + } +} +/* }}} */ +/* {{{ [fold] qc_adapt_hassettled(struct quickcam *qc) */ +/* Return TRUE if the image brightness has settled */ +static inline Bool qc_adapt_hassettled(struct quickcam *qc) +{ + struct qc_adapt_data *ctrl = &qc->adapt_data; + IDEBUG_TEST(*ctrl); + if (ctrl->framecounter != 0) return FALSE; +//PDEBUG("control=%i oldexp=%i exp=%i",ctrl->controlalg,ctrl->oldexposure,ctrl->exposure); + return ctrl->controlalg==EXPCONTROL_FLOAT || ctrl->oldexposure==ctrl->exposure; +} +/* }}} */ +/* {{{ [fold] qc_adapt(struct quickcam *qc, int midvalue, int target, int *ret_exposure, int *ret_gain) */ + +/* Set image exposure and gain so that computed midvalue approaches the target value. + * midvalue = average pixel intensity on image 0..255 + * target = user settable preferable intensity 0..255 + * *ret_exposure = the exposure value to use for the camera, 0..65535 + * *ret_gain = the gain to use for the camera, 0..65535. + */ +static void qc_adapt(struct quickcam *qc, int midvalue, int target, int *ret_exposure, int *ret_gain) +{ +#if !MEASURE_ADAPT_DELAY + struct qc_adapt_data *ctrl = &qc->adapt_data; + /* Here are some constant for controlling the adaptation algorithm. You may play with them. */ + static const int saturation_min = 32; /* (0-127) If midvalue is out of this range, image is */ + static const int saturation_max = 256 - 8; /* (128-255) considered saturated and no Newton is used */ + + static const int adaptation_min = 5; /* (0-128) For small variations, do not change exposure */ + + static const int delta_min = 256/2; /* (2-16*256) Minimum and maximum value for delta */ + static const int delta_max = 256*256; /* (4*256-1024*256) */ + + static const int dmidvalue_min = 400; /* (1-128) Minimum differences, under which delta estimation (FIXME:disabled by changing values very big) */ + static const int dexposure_min = 400; /* (1-32000) will not be done due to inaccuracies */ + + static const int delta_speed = 256; /* (0-256) How fast or slowly delta can change */ + static const int small_adapt = 4; /* (0-1024) When very near optimal, exposure change size */ + static const int underestimate = 16; /* (0-250) Underestimation, may prevent oscillation */ + static const int bestguess = 256/2; /* (2-1024*256) If delta can not be computed, guess this */ + static const int midvalueaccum = 2; /* (1-100) How many frames to use for midvalue averaging */ + static const int framedelay = 5; /* (0-8) How many frames there are before a new exposure setting in effect */ + /* With QuickCam Web: if set at frame #0, it will be in effect at frame #4; skip 3 frames #1,#2,#3 */ + /* -> should be 3 with QuickCam Web, but it oscillates, FIXME:why? Setting to 4 fixes this */ + static const int gainstep = 256; /* (0-32768) Amount to change gain at one step */ + static const int gainneeded = 10; /* (0-255) How eagerly to change brightness with gain */ + /* End of tunable constants */ + + int newexposure, delta=0; + int dexposure=0, dmidvalue=0; + int deviation=0; /* Deviation of actual brightness from target brightness */ + int smoothdelta=0; /* Final, smoothed, value of delta */ + + TEST_BUG(ctrl==NULL || ret_gain==NULL || ret_exposure==NULL); + IDEBUG_TEST(*ctrl); + + if (ctrl->framecounter >= framedelay) + ctrl->midvaluesum += midvalue; + ctrl->framecounter++; + if (ctrl->framecounter < framedelay+midvalueaccum) { + *ret_exposure = ctrl->exposure; + *ret_gain = ctrl->gain; + return; + } + + midvalue = ctrl->midvaluesum / midvalueaccum; + ctrl->framecounter = 0; + ctrl->midvaluesum = 0; + + if (ctrl->exposure >= qc->sensor_data.sensor->adapt_gainhigh && + ctrl->oldexposure >= qc->sensor_data.sensor->adapt_gainhigh && + target - ctrl->oldmidvalue > gainneeded && + target - midvalue > gainneeded) + { + /* Exposure is at maximum, but image is still too dark. Increase gain.*/ + ctrl->gain = ctrl->gain + ctrl->gain/2 + gainstep; + if (ctrl->gain > 65535) ctrl->gain = 65535; + if (qcdebug&QC_DEBUGADAPTATION) PDEBUG("increasing gain to %i", ctrl->gain); + } else + if (ctrl->exposure <= qc->sensor_data.sensor->adapt_gainlow && + ctrl->oldexposure <= qc->sensor_data.sensor->adapt_gainlow && + target - ctrl->oldmidvalue <= gainneeded && + target - midvalue <= gainneeded) + { + /* Decrease gain if unnecessarily high */ + ctrl->gain = ctrl->gain - ctrl->gain/2 - gainstep; + if (ctrl->gain < 0) ctrl->gain = 0; + if (qcdebug&QC_DEBUGADAPTATION) PDEBUG("decreasing gain to %i", ctrl->gain); + } + + if (ctrl->oldmidvaluecontrolalg = EXPCONTROL_SATURATED; + newexposure = ctrl->exposure * 2; + } else + if (ctrl->oldmidvalue>=saturation_max || midvalue>=saturation_max) { + /* Image is oversaturated, Newton method would give inaccurate results */ + if (qcdebug&QC_DEBUGADAPTATION) PDEBUG("Decreasing exposure"); + ctrl->controlalg = EXPCONTROL_SATURATED; + newexposure = ctrl->exposure / 2; + } else { + deviation = target - midvalue; + if (ABS(deviation) < adaptation_min) { + /* For small variations, adapt linearly */ + if (qcdebug&QC_DEBUGADAPTATION) PDEBUG("Small deviation %i",deviation); + ctrl->controlalg = EXPCONTROL_FLOAT; + newexposure = small_adapt * SGN(deviation) + ctrl->exposure; + } else { + /* Try using Newton method for estimating correct exposure value */ + ctrl->controlalg = EXPCONTROL_NEWTON; + dmidvalue = midvalue - ctrl->oldmidvalue; + dexposure = ctrl->exposure - ctrl->oldexposure; + if (ABS(dmidvalue) < dmidvalue_min || + ABS(dexposure) < dexposure_min || + SGN(dmidvalue) != SGN(dexposure)) + { + /* Can not estimate delta with Newton method, just guess */ + if (ctrl->olddelta < 2) { + if (qcdebug&QC_DEBUGADAPTATION) PDEBUG("Best guessing"); + smoothdelta = bestguess; + } else { + Bool cross = SGN(midvalue-target) != SGN(ctrl->oldmidvalue-target); + smoothdelta = cross ? (ctrl->olddelta / 2) : (ctrl->olddelta * 3 / 2); + if (qcdebug&QC_DEBUGADAPTATION) PDEBUG("Change more exposure, smoothdelta=%i",smoothdelta); + } + } else { + /* Everything is well, use here actual Newton method */ + delta = (256 - underestimate) * dexposure / dmidvalue; + smoothdelta = (delta_speed*delta + (256-delta_speed)*ctrl->olddelta) / 256; + if (qcdebug&QC_DEBUGADAPTATION) PDEBUG("Using Newton, delta=%i",delta); + } + } + /* Compute new exposure based on guessed/computed delta */ + smoothdelta = CLIP(smoothdelta, delta_min,delta_max); + dexposure = deviation * smoothdelta / 256; + /* Newton works linearly, but exposure/brightness are not linearly related */ + /* The following test fixes the worst deficiencies due to that (I hope) */ + if (-dexposure > ctrl->exposure/2) + dexposure = -ctrl->exposure/2; + newexposure = dexposure + ctrl->exposure; + ctrl->olddelta = smoothdelta; + } + + newexposure = CLIP(newexposure, 2,65535); + + if (qcdebug&QC_DEBUGADAPTATION) + PDEBUG("midval=%i dev=%i dmidv=%i dexp=%i smdelta=%i olddelta=%i newexp=%i gain=%i", + midvalue,deviation,dmidvalue,dexposure,smoothdelta,ctrl->olddelta,newexposure,ctrl->gain); + + ctrl->oldexposure = ctrl->exposure; + ctrl->exposure = newexposure; + ctrl->oldmidvalue = midvalue; + *ret_exposure = newexposure; + *ret_gain = ctrl->gain; +#else + /* This code is for measuring the delay between an exposure settings and until + * it becomes in effect. Only useful for developing the adaptation algorithm. */ + /* Some delays: when a setting is changed at frame number #0, + * it becomes in effect in frame xx for exposure gain + * QuickCam Web/0850/normal mode 4 4 + * QuickCam Web/0850/compressed mode 5 5 + * QuickCam Express/840 2 1-5 + * + */ + static int exp = 0; + static int gain = 0; + static const int changedel = 20; + static int state = 0; + static int framenum = 0; + PRINTK(KERN_CRIT,"Measuring: framenum=%i, midvalue=%i",framenum,midvalue); + if ((framenum%changedel)==0) { + switch (state) { + default: + case 0: + PRINTK(KERN_CRIT,"Measuring: set to black"); + exp = 0; + gain = 0; + break; + case 1: + PRINTK(KERN_CRIT,"Measuring: changing exposure"); + exp = 65535; + break; + case 2: + PRINTK(KERN_CRIT,"Measuring: changing gain"); + gain = 32535; + break; + } + state = ((state+1) % 3); + } + *ret_exposure = exp; + *ret_gain = gain; + framenum++; +#endif +} + +/* }}} */ + +/* }}} */ +/* {{{ [fold] **** qc_frame: Frame capturing functions ************************* */ + +/* From /usr/src/linux/Documentation/smp.tex: + * + Kernel mode process (e.g. system calls): + * - No other kernel mode processes may run simultaneously/pre-empt + * (kernel mode processes are atomic with respect to each other) + * (Does not hold for 2.6.x) + * - Exception is voluntary sleeping, in which case re-entry is allowed + * (Does not hold for 2.6.x) + * - Interrupts may pre-empt (but return to same process) + * (interrupts can be disabled if necessary) + * + Interrupt mode execution + * - Kernel mode process may not pre-empt/execute simultaneously + * - Other interrupts may pre-empt, however same interrupt is not nested + */ + +/* We have here a quite typical producer-consumer scheme: + * Interrupt routine produces more frame data, while + * kernel mode processes consume it + * Read: Linux Device Drivers, Alessandro Rubini et al, 2nd edition, pg. 279 + * "Using Circular Buffers" + */ + +/* Initialization and cleanup routines, called from kernel mode processes */ +/* {{{ [fold] qc_frame_init(struct quickcam *qc) */ +static int qc_frame_init(struct quickcam *qc) +{ + struct qc_frame_data *fd = &qc->frame_data; + int n; + + if (qcdebug&QC_DEBUGFRAME || qcdebug&QC_DEBUGINIT) PDEBUG("qc_frame_init(qc=%p)",qc); + TEST_BUGR(qc==NULL || fd==NULL); + TEST_BUGR(in_interrupt()); + fd->rawdatabuf = vmalloc(FRAME_DATASIZE * FRAME_BUFFERS); + if (!fd->rawdatabuf) return -ENOMEM; + memset(fd->rawdatabuf, 0, FRAME_DATASIZE * FRAME_BUFFERS); /* Never let user access random kernel data */ + fd->head = 0; /* First buffer to fill */ + fd->tail = 0; /* First buffer to get */ + spin_lock_init(&fd->tail_lock); + fd->tail_in_use= FALSE; + init_waitqueue_head(&fd->wq); + fd->waiting = 0; + fd->exiting = FALSE; + for (n=0; nbuffers[n].rawdatalen = 0; + fd->lost_frames = 0; + IDEBUG_INIT(*fd); + return 0; +} +/* }}} */ +/* {{{ [fold] qc_frame_exit(struct quickcam *qc) */ +/* This function must be called with qc->lock acquired + * (it may release it temporarily and sleep) */ +static void qc_frame_exit(struct quickcam *qc) +{ + struct qc_frame_data *fd = &qc->frame_data; +#if PARANOID + unsigned long startjiffy = jiffies; +#endif + if (qcdebug&QC_DEBUGFRAME || qcdebug&QC_DEBUGINIT) PDEBUG("qc_frame_exit(qc=%p,tail=%i,head=%i)",qc,fd->tail,fd->head); + TEST_BUG(in_interrupt()); + TEST_BUG(qc==NULL || fd==NULL); + fd->exiting = TRUE; + fd->maxrawdatalen = 0; /* Hopefully stops all ongoing captures, might need locking though */ + wake_up(&fd->wq); + if (qcdebug&QC_DEBUGFRAME) PDEBUG("waiting=%i",fd->waiting); + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(%p) in qc_frame_exit() : %i", qc, sem_getcount(&qc->lock)); + up(&qc->lock); /* The lock was down when entering this function */ + while (fd->waiting > 0) { + schedule(); +#if PARANOID + if (jiffies-startjiffy > 60*HZ) { + PRINTK(KERN_CRIT,"Wait queue never completing!! (waiting=%i)",fd->waiting); + break; + } +#endif + } + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("down(%p) in qc_frame_exit() : %i", qc, sem_getcount(&qc->lock)); + down(&qc->lock); + vfree(fd->rawdatabuf); + POISON(fd->rawdatabuf); + IDEBUG_EXIT(*fd); +} +/* }}} */ + +/* Consumer routines, called from kernel mode processes */ +/* {{{ [fold] qc_frame_get(struct quickcam *qc, unsigned char **buf) */ +/* Wait until next frame is ready and return the frame length + * and set buf to point to the frame. If error happens, + * return standard Linux negative error number. + * qc_frame_free() must be called after the frame is not needed anymore. + * qc->lock must be acquired when entering this routine + * (it may release it temporarily and sleep). + */ +static int qc_frame_get(struct quickcam *qc, unsigned char **buf) +{ + struct qc_frame_data *fd = &qc->frame_data; + int ret; + + TEST_BUGR(qc==NULL || fd==NULL || fd->tail_in_use); + TEST_BUGR(in_interrupt()); + IDEBUG_TEST(*fd); + + /* Wait until the next frame is available */ + if (qcdebug&QC_DEBUGFRAME) PDEBUG("qc_frame_get/consume(qc=%p,tail=%i,head=%i)",qc,fd->tail,fd->head); + fd->waiting++; + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(%p) in qc_frame_get() : %i", qc, sem_getcount(&qc->lock)); + up(&qc->lock); /* Release lock while waiting */ + + ret = wait_event_interruptible(fd->wq, fd->head!=fd->tail || fd->exiting); //FIXME:What if we get -ERESTARTSYS? + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("down(%p) in qc_frame_get() : %i", qc, sem_getcount(&qc->lock)); + down(&qc->lock); + if (!ret) { + if (!fd->exiting) { + unsigned int t; + unsigned long flags; + spin_lock_irqsave(&fd->tail_lock, flags); + fd->tail_in_use = TRUE; + t = fd->tail; + spin_unlock_irqrestore(&fd->tail_lock, flags); + if (qcdebug&QC_DEBUGFRAME) PDEBUG("qc_frame_get/consume(qc=%p,tail=%i,head=%i,tail->rawdatalen=%i), got frame",qc,t,fd->head,fd->buffers[t].rawdatalen); + *buf = fd->rawdatabuf + t*FRAME_DATASIZE; + ret = fd->buffers[t].rawdatalen; + } else { + ret = -ENODATA; + } + } + fd->waiting--; + fd->lost_frames = 0; + if (ret<0 && (qcdebug&(QC_DEBUGERRORS|QC_DEBUGFRAME))) PDEBUG("failed qc_frame_get()=%i",ret); + return ret; +} +/* }}} */ +/* {{{ [fold] qc_frame_free(struct quickcam *qc) */ +/* Free up the last frame returned from qc_frame_get() (it must be called first) */ +static inline void qc_frame_free(struct quickcam *qc) +{ + struct qc_frame_data *fd = &qc->frame_data; + unsigned long flags; + TEST_BUG(qc==NULL || fd==NULL); + TEST_BUG(in_interrupt()); + TEST_BUG(fd->head==fd->tail); /* The current fd->tail is not available to be freed! */ + IDEBUG_TEST(*fd); + if (qcdebug&QC_DEBUGFRAME) PDEBUG("qc_frame_free/consume(qc=%p,tail=%i,head=%i)",qc,fd->tail,fd->head); + /* Free up previous frame and advance to next */ + spin_lock_irqsave(&fd->tail_lock, flags); + fd->tail_in_use = FALSE; + fd->tail = (fd->tail + 1) % FRAME_BUFFERS; + spin_unlock_irqrestore(&fd->tail_lock, flags); +} +/* }}} */ +/* {{{ [fold] qc_frame_test(struct quickcam *qc) */ +/* Return TRUE if next frame is immediately available, FALSE otherwise. */ +static inline Bool qc_frame_test(struct quickcam *qc) +{ + struct qc_frame_data *fd = &qc->frame_data; + IDEBUG_TEST(*fd); + if (qcdebug&QC_DEBUGFRAME) PDEBUG("qc_frame_test/consume(qc=%p,tail=%i,head=%i)",qc,fd->tail,fd->head); + return fd->head != fd->tail; +} +/* }}} */ + +/* Producer routines, called from interrupt context */ +/* {{{ [fold] qc_frame_begin(struct quickcam *qc) */ +/* Begin capturing next frame from camera. If buffer is full, the frame will be lost */ +static void qc_frame_begin(struct quickcam *qc) +{ + struct qc_frame_data *fd = &qc->frame_data; + int framesize, h; + TEST_BUG(qc==NULL || fd==NULL); + IDEBUG_TEST(*fd); + if (qcdebug&QC_DEBUGFRAME) PDEBUG("qc_frame_begin/produce(qc=%p,tail=%i,head=%i)",qc,fd->tail,fd->head); + if (fd->exiting) return; + TEST_BUG(fd->rawdatabuf==NULL); + h = fd->head; + fd->buffers[h].rawdatalen = 0; + + /* Use sensor information to get the framesize (i.e. how much we expect to receive bytes per image) */ + /* FIXME: should compute data size differently in compressed mode */ + framesize = qc->sensor_data.width * qc->sensor_data.height; + fd->maxrawdatalen = MIN(framesize, FRAME_DATASIZE); +} +/* }}} */ +/* {{{ [fold] qc_frame_add(struct quickcam *qc, unsigned char *data, int datalen) */ +/* Store more data for a frame, return nonzero if too much data or other error */ +static int qc_frame_add(struct quickcam *qc, unsigned char *data, int datalen) +{ + struct qc_frame_data *fd = &qc->frame_data; + int h = fd->head; + int bytes; + + TEST_BUGR(qc==NULL || fd==NULL); + IDEBUG_TEST(*fd); + TEST_BUGR(fd->rawdatabuf==NULL); + if (fd->maxrawdatalen <= fd->buffers[h].rawdatalen) { + if (qcdebug&QC_DEBUGERRORS) PDEBUG("buffer disabled, maxrawdatalen=%i rawdatalen=%i datalen=%i",fd->maxrawdatalen,fd->buffers[h].rawdatalen, datalen); + return -EBUSY; + } + bytes = MIN(datalen, fd->maxrawdatalen - fd->buffers[h].rawdatalen); + memcpy(fd->rawdatabuf + h*FRAME_DATASIZE + fd->buffers[h].rawdatalen, data, bytes); + fd->buffers[h].rawdatalen += bytes; + if (bytes < datalen) { + if (qcdebug&QC_DEBUGERRORS) PRINTK(KERN_ERR,"out of buffer space by %i, maxrawdatalen=%i rawdatalen=%i datalen=%i", datalen-bytes,fd->maxrawdatalen,fd->buffers[h].rawdatalen, datalen); + return -ENOSPC; + } + return 0; +} +/* }}} */ +/* {{{ [fold] qc_frame_end(struct quickcam *qc) */ +/* Finished capturing most recent frame from camera */ +/* (may be premature end, in which case some data is missing) */ +static void qc_frame_end(struct quickcam *qc) +{ + static const int minrawdatalen = 32*32; /* If frame length is less than this many bytes, discard it */ + struct qc_frame_data *fd = &qc->frame_data; + unsigned int t, h; + unsigned long flags; + Bool lost_frame; + TEST_BUG(qc==NULL || fd==NULL); + h = fd->head; + if (qcdebug&QC_DEBUGFRAME) PDEBUG("qc_frame_end/produce(qc=%p,tail=%i,head=%i), got %i bytes",qc,fd->tail,h,fd->buffers[h].rawdatalen); + IDEBUG_TEST(*fd); + fd->maxrawdatalen = 0; /* Stop frame data capturing */ +#if DUMPDATA + PDEBUG("frame_end: got %i bytes", fd->buffers[h].rawdatalen); +#endif + if (fd->buffers[h].rawdatalen < minrawdatalen) { + /* No enough data in buffer, don't advance index */ + if (qcdebug&QC_DEBUGERRORS) PDEBUG("discarding frame with only %u bytes", fd->buffers[h].rawdatalen); + return; + } + h = (h + 1) % FRAME_BUFFERS; /* Select next frame buffer to fill */ + + lost_frame = FALSE; + spin_lock_irqsave(&fd->tail_lock, flags); + t = fd->tail; + if (t == h) { + lost_frame = TRUE; + /* FIXME: the below should work fine for two buffers, but not so well for more. It should be possible + * to drop oldest frame even when the current tail is in use. */ + if (fd->tail_in_use) { + /* Can not drop the oldest frame, it is in use. Drop the newest frame */ + h = (h + FRAME_BUFFERS - 1) % FRAME_BUFFERS; /* Decrease head by one back to the original */ + if (qcdebug&QC_DEBUGFRAME) PDEBUG("dropping newest frame"); + } else { + /* Drop the oldest frame */ + fd->tail = (t + 1) % FRAME_BUFFERS; /* Drop the oldest frame away */ + if (qcdebug&QC_DEBUGFRAME) PDEBUG("dropping oldest frame"); + } + } + spin_unlock_irqrestore(&fd->tail_lock, flags); + if (lost_frame) { + if (qcdebug&QC_DEBUGCOMMON || qcdebug&QC_DEBUGFRAME) PRINTK(KERN_NOTICE,"frame lost"); + fd->lost_frames++; + if (fd->lost_frames > 10) { + /* Here we should call qc_isoc_stop() to stop isochronous + * streaming since the application is clearly not reading frames at all. + * However, we are now in interrupt context but qc_isoc_stop() has + * to be in process context... so we can't do that. + * FIXME: add tasklet/bottomhalf/whatever needed to do it. + */ + if (qcdebug&QC_DEBUGFRAME) PDEBUG("too many lost frames: %i", fd->lost_frames); + } + } + fd->head = h; + wake_up(&fd->wq); +} +/* }}} */ +/* {{{ [fold] qc_frame_flush(struct quickcam *qc) */ +/* Reject the current data already captured into buffer and end frame */ +void qc_frame_flush(struct quickcam *qc) +{ + struct qc_frame_data *fd = &qc->frame_data; + unsigned int h = fd->head; + TEST_BUG(qc==NULL || fd==NULL); + IDEBUG_TEST(*fd); + if (qcdebug&QC_DEBUGFRAME) PDEBUG("qc_frame_flush/produce(qc=%p,tail=%i,head=%i), flush %i bytes",qc,fd->tail,h,fd->buffers[h].rawdatalen); + fd->buffers[h].rawdatalen = 0; /* Empty buffer */ + fd->maxrawdatalen = 0; /* Stop frame data capturing */ +} +/* }}} */ + +/* }}} */ +/* {{{ [fold] **** qc_stream: USB datastream processing functions *************** */ + +/* {{{ [fold] qc_stream_init(struct quickcam *qc) */ +/* Initialize datastream processing */ +static int qc_stream_init(struct quickcam *qc) +{ + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_stream_init(quickcam=%p)",qc); + qc->stream_data.capturing = FALSE; + qc->stream_data.frameskip = qc->settings.frameskip; + IDEBUG_INIT(qc->stream_data); + return 0; +} +/* }}} */ +/* {{{ [fold] qc_stream_exit(struct quickcam *qc) */ +/* Stop datastream processing, after this qc_stream_add should not be called */ +static void qc_stream_exit(struct quickcam *qc) +{ + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_stream_exit(quickcam=%p)",qc); + if (qc->stream_data.capturing) + qc_frame_end(qc); + IDEBUG_EXIT(qc->stream_data); +} +/* }}} */ +/* {{{ [fold] qc_stream_error(struct quickcam *qc) */ +/* This is called when there are data lost due to errors in the stream */ +static void qc_stream_error(struct quickcam *qc) +{ + /* Skip rest of data for this frame */ + if (qcdebug&QC_DEBUGERRORS) PDEBUG("qc_stream_error(qc=%p)", qc); + if (qc->stream_data.capturing) + qc_frame_end(qc); + IDEBUG_EXIT(qc->stream_data); + qc_stream_init(qc); +} +/* }}} */ +/* {{{ [fold] qc_stream_add(struct quickcam *qc, unsigned char *data, int datalen) */ +/* + * Analyse an USB packet of the data stream and store it appropriately. + * Each packet contains an integral number of chunks. Each chunk has + * 2-bytes identification, followed by 2-bytes that describe the chunk + * length. Known/guessed chunk identifications are: + * 8001/8005/C001/C005 - Begin new frame + * 8002/8006/C002/C006 - End frame + * 0200/4200 - Contains actual image data, bayer or compressed + * 0005 - 11 bytes of unknown data + * 0100 - 2 bytes of unknown data + * The 0005 and 0100 chunks seem to appear only in compressed stream. + * Return the amount of image data received or negative value on error. + */ +static int qc_stream_add(struct quickcam *qc, unsigned char *data, int datalen) +{ + struct qc_stream_data *sd = &qc->stream_data; + int id, len, error, totaldata = 0; + + IDEBUG_TEST(*sd); + while (datalen) { + if (datalen < 4) { + if (qcdebug&QC_DEBUGBITSTREAM) PRINTK(KERN_ERR,"missing chunk header"); + break; + } + id = (data[0]<<8) | data[1]; + len = (data[2]<<8) | data[3]; + data += 4; + datalen -= 4; + if (datalen < len) { + if (qcdebug&QC_DEBUGBITSTREAM) PRINTK(KERN_ERR,"missing chunk contents"); + break; + } + switch (id) { + case 0x8001: + case 0x8005: + case 0xC001: + case 0xC005: + /* Begin new frame, len should be zero */ + if (PARANOID && len!=0) PDEBUG("New frame: len!=0"); + if (sd->capturing) { + if (qcdebug&QC_DEBUGBITSTREAM) PDEBUG("Missing frame end mark in stream"); + qc_frame_end(qc); + } + sd->capturing = TRUE; + if (--sd->frameskip < 0) sd->frameskip = qc->settings.frameskip; + if (sd->frameskip==0) qc_frame_begin(qc); + break; + case 0x8002: + case 0x8006: + case 0xC002: + case 0xC006: + /* End frame, len should be zero */ + if (PARANOID && len!=0) PDEBUG("End frame: len!=0"); + if (sd->capturing) { + if (sd->frameskip==0) qc_frame_end(qc); + } else { + if (qcdebug&QC_DEBUGBITSTREAM) PDEBUG("Missing frame begin mark in stream"); + } + sd->capturing = FALSE; + break; + case 0x0200: + case 0x4200: + /* Image data */ + if (!sd->capturing && (qcdebug&QC_DEBUGBITSTREAM)) PDEBUG("Chunk of data outside frames!"); + if (sd->capturing && sd->frameskip==0) { + error = qc_frame_add(qc, data, len); + } else { + error = 0; + } + if (error) { + /* If qc_frame_add returns error, there is more data than the frame may have, + * in which case we assume stream is corrupted and skip rest packet */ + if (qcdebug&QC_DEBUGERRORS) PDEBUG("qc_frame_add error %i",error); + } else { + totaldata += len; + } + break; + case 0x0005: + /* Unknown chunk with 11 bytes of data, occurs just before end of each frame in compressed mode */ + if (len==11) break; + case 0x0100: + /* Unknown chunk with 2 bytes of data, occurs 2-3 times per USB interrupt */ + if (len==2) break; + default: + /* Unknown chunk */ + #ifdef DEBUG + if (qcdebug&QC_DEBUGBITSTREAM) { + static char dump[4*1024]; + char *dump_p = dump; + int i; + for (i=0; i= KERNEL_VERSION(2,6,0) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void qc_isoc_handler(struct urb *urb, struct pt_regs *ptregs) +#else +static void qc_isoc_handler(struct urb *urb) +#endif +{ + struct quickcam *qc; + int payload = 0; /* Amount of all data camera sent */ + int totaldata = 0; /* Amount of image data camera sent */ + int i; +#ifdef DEBUG + /* Check for nested interrupts, shouldn't happen */ + volatile static Bool in_progress = FALSE; + TEST_BUG(in_progress); + in_progress = TRUE; +#endif + + if (qcdebug&QC_DEBUGINTERRUPTS) PDEBUG("[INTR] qc_isoc_handler(urb=%p)",urb); + TEST_BUG(urb==NULL); + qc = urb->context; + TEST_BUG(qc==NULL); + IDEBUG_TEST(qc->isoc_data); + + if (!qc->connected || !qc->isoc_data.streaming) { + /* Camera was disconnected or isochronous stream just disabled--must not resubmit urb */ + PDEBUG("Ignoring isoc interrupt, dev=%p streaming=%i status=%i", qc->dev, qc->isoc_data.streaming, urb->status); + goto out; + } + + if (urb->status<0) { + qc->isoc_data.errorcount++; + switch (urb->status) { + case -EXDEV: /* Partially completed, look at individual frame status */ + break; + default: + /* Seen here: -EOVERFLOW (75): Value too large for defined data type */ + case -EPROTO: /* Bitstuff error or unknown USB error */ + case -EILSEQ: /* CRC mismatch */ + case -ETIMEDOUT: /* Transfer timed out */ + case -EREMOTEIO: /* Short packet detected */ + case -EPIPE: /* Babble detect or endpoint stalled */ + case -ECONNRESET: /* Asynchronous unlink, should not happen, but does with 2.6.x */ + if (qcdebug&QC_DEBUGERRORS) PRINTK(KERN_ERR,"isoc URB error %i, resubmitting",urb->status); + goto resubmit; + case -ESHUTDOWN: + case -ENOENT: /* URB was unlinked */ + case -ENODEV: /* Device was removed */ + if (qcdebug&QC_DEBUGERRORS) PRINTK(KERN_ERR,"isoc URB error %i, returning",urb->status); + goto out; + } + } + + for (i=0; inumber_of_packets; i++) { + if ((int)urb->iso_frame_desc[i].status<0) { /* Note that the cast to int MUST be here! */ + if (qcdebug&QC_DEBUGERRORS) PDEBUG("USB transfer error %i", urb->iso_frame_desc[i].status); + qc->isoc_data.errorcount++; + qc_stream_error(qc); + continue; + } + qc->isoc_data.errorcount = 0; + payload += urb->iso_frame_desc[i].actual_length; +#if PARANOID +{ +int xx = urb->iso_frame_desc[i].actual_length; +if (xx>2000) { +PDEBUG("i=%i status=%i transfer_buffer=%p transfer_buffer_length=%i actual_length=%i number_of_packets=%i", + i, urb->status, urb->transfer_buffer, urb->transfer_buffer_length, urb->actual_length, urb->number_of_packets); +PDEBUG("offset=%i length=%i actual_length=%i pstatus=%i", +urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].length, urb->iso_frame_desc[i].actual_length, urb->iso_frame_desc[i].status); +goto out; +} +} +#endif + totaldata += qc_stream_add(qc, urb->transfer_buffer + urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].actual_length); + } + if (qcdebug&QC_DEBUGBITSTREAM) PDEBUG("payload=%i totaldata=%i",payload,totaldata); + if (qcdebug&(QC_DEBUGBITSTREAM|QC_DEBUGERRORS)) if (payload==0) PDEBUG("USB interrupt, but no data received!"); +resubmit: + /* Resubmit URB */ + if (qc->isoc_data.errorcount < ISOC_PACKETS*ISOC_URBS*8) { + urb->dev = qc->dev; /* Required for 2.4.x */ + i = usb_submit_urb(urb,GFP_ATOMIC); + if (i) PDEBUG("failed to resubmit URB, code=%i, dev=%p",i,urb->dev); + } else { + PDEBUG("Too many errors, giving up"); + } +out: +#ifdef DEBUG + in_progress = FALSE; +#endif + return; +} +/* }}} */ +/* {{{ [fold] qc_isoc_start(struct quickcam *qc) */ +/* + * Start USB isochronous image transfer from camera to computer + * (Set USB camera interface and allocate URBs and submit them) + * Sensor must be initialized beforehand (qc_init_sensor) + */ +static int qc_isoc_start(struct quickcam *qc) +{ + struct qc_isoc_data *id = &qc->isoc_data; + int ret = -ENOMEM; /* Return value on error */ + struct urb *urb; + int i, b; + + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_isoc_start(qc=%p)",qc); + TEST_BUGR_MSG(qc==NULL || id==NULL, "qc||id==NULL"); + IDEBUG_TEST(*id); + + if (id->streaming) return 0; /* Already started */ + id->streaming = TRUE; + id->errorcount = 0; + + /* Allocate transfer buffer */ + id->buffer = kmalloc(ISOC_URBS * ISOC_PACKETS * ISOC_PACKET_SIZE, GFP_KERNEL); + CHECK_ERROR(!id->buffer, fail1, "Out of memory allocating id->buffer"); + + /* Allocate URBs, fill them, and put them in the URB array */ + for (b=0; burbs[b] = usb_alloc_urb(ISOC_PACKETS,GFP_KERNEL); /* Zeroes the allocated data up to iso_frame_desc[], *not* including the last! */ + CHECK_ERROR(!urb, fail2, "Out of memory allocating urbs"); + urb->dev = qc->dev; + urb->context = qc; + urb->pipe = usb_rcvisocpipe(qc->dev, QUICKCAM_ISOPIPE); + urb->transfer_flags = URB_ISO_ASAP; /* Leave URB_ASYNC_UNLINK clear and never call usb_unlink_urb() */ + urb->complete = qc_isoc_handler; + urb->number_of_packets = ISOC_PACKETS; + urb->transfer_buffer = id->buffer; + urb->transfer_buffer_length = ISOC_URBS * ISOC_PACKETS * ISOC_PACKET_SIZE; + urb->interval = 1; /* See Table 9-10 of the USB 1.1 specification */ + for (i=0; iiso_frame_desc[i].offset = b*ISOC_PACKETS*ISOC_PACKET_SIZE + i*ISOC_PACKET_SIZE; + urb->iso_frame_desc[i].length = ISOC_PACKET_SIZE; + } + } + + /* Alternate interface 3 is the biggest frame size */ + /* JFC use 1: but do not know why */ + /* QuickCam Web: Interface 0, alternate 1, endpoint 0x81 -tuukkat */ + qc_i2c_wait(qc); /* There must not be control URBs going when calling set_interface() */ + ret = usb_set_interface(qc->dev, qc->iface, 1); + CHECK_ERROR(ret<0, fail3, "set_interface failed"); + + /* Submit URBs */ + for (b=0; burbs[b],GFP_KERNEL); + CHECK_ERROR(ret<0, fail4, "submit urbs failed"); + } + + /* Tell camera to start sending data */ + ret = qc->sensor_data.sensor->start(qc); /* Start current frame */ + CHECK_ERROR(ret<0, fail5, "sensor_data.start failed"); + ret = qc_stv_set(qc, STV_ISO_ENABLE, 1); /* Start isochronous streaming */ + CHECK_ERROR(ret<0, fail6, "qc_stv_set() failed"); + return 0; + + /* Cleanup and return error code on failure */ +fail6: qc->sensor_data.sensor->stop(qc); /* stop current frame. */ +fail5: b = ISOC_URBS; +fail4: while (--b >= 0) usb_kill_urb(id->urbs[b]); + usb_set_interface(qc->dev, qc->iface, 0); /* Set packet size to 0 (Interface 0, alternate 0, endpoint 0x81 -tuukkat) */ +fail3: b = ISOC_URBS; +fail2: while (--b >= 0) usb_free_urb(id->urbs[b]); + kfree(id->buffer); +fail1: if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGERRORS) PDEBUG("failed qc_isoc_init()=%i",ret); + return ret; +} +/* }}} */ +/* {{{ [fold] qc_isoc_stop(struct quickcam *qc) */ +/* + * Stop USB isochronous image transfer from camera to computer + * (Tell camera to stop sending images, set idle USB interface and free URBs) + * There must be no more isochronous transfer interrupts after this returns + * nor any running handlers anymore. + */ +static void qc_isoc_stop(struct quickcam *qc) +{ + struct qc_isoc_data *id = &qc->isoc_data; + int b, r; + + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_isoc_stop(quickcam=%p)",qc); + TEST_BUG_MSG(qc==NULL || id==NULL, "qc||id==NULL"); + IDEBUG_TEST(*id); + + if (!id->streaming) return; /* Already stopped */ + if (qc->connected) { + if ((r=qc_stv_set(qc, STV_ISO_ENABLE, 0))<0) /* stop ISO-streaming. */ + PRINTK(KERN_ERR,"qc_stv_set error %i",r); + if ((r=qc->sensor_data.sensor->stop(qc))<0) /* stop current frame. */ + PRINTK(KERN_ERR,"sensor_data.stop error %i",r); + qc_i2c_wait(qc); /* When calling set_interface(), there must not be control URBs on way */ + if (usb_set_interface(qc->dev, qc->iface, 0) < 0) /* Set packet size to 0 (Interface 0, alternate 0, endpoint 0x81 -tuukkat) */ + PRINTK(KERN_ERR,"usb_set_interface error"); + } + id->streaming = FALSE; /* Ensure that no more isochronous URBs will be submitted from the interrupt handler */ + mb(); + for (b=0; bstatus = %i", b, id->urbs[b]->status); + usb_kill_urb(id->urbs[b]); + usb_free_urb(id->urbs[b]); + POISON(id->urbs[b]); + } + + kfree(id->buffer); + POISON(id->buffer); + return; +} +/* }}} */ +/* {{{ [fold] qc_isoc_init(struct quickcam *qc) */ +/* + * Initialize isochronous streaming functions + */ +static int qc_isoc_init(struct quickcam *qc) +{ + struct qc_isoc_data *id = &qc->isoc_data; + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_isoc_init(quickcam=%p)",qc); + TEST_BUGR_MSG(qc==NULL || id==NULL, "qc||id==NULL"); + IDEBUG_INIT(*id); + id->streaming = FALSE; + return 0; +} +/* }}} */ +/* {{{ [fold] qc_isoc_exit(struct quickcam *qc) */ +/* + * Uninitialize isochronous streaming functions + */ +static inline void qc_isoc_exit(struct quickcam *qc) +{ + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_isoc_exit(quickcam=%p)",qc); + qc_isoc_stop(qc); + IDEBUG_EXIT(qc->isoc_data); +} +/* }}} */ +/* {{{ [fold] Bool qc_isoc_streaming(struct quickcam *qc) */ +static inline Bool qc_isoc_streaming(struct quickcam *qc) +{ + struct qc_isoc_data *id = &qc->isoc_data; + + TEST_BUGR_MSG(qc==NULL || id==NULL, "qc||id==NULL"); + IDEBUG_TEST(*id); + return id->streaming; +} +/* }}} */ + +/* }}} */ +/* {{{ [fold] **** qc_sensor: Common routines for all sensors ******************* */ + +/* {{{ [fold] qc_sensor_setsize0(struct quickcam *qc, unsigned int width, unsigned int height) */ +/* Called when the application requests a specific image size. Should set the + * actual delivered image size to as close to the requested as possible. + * The image size, as delivered from the camera, can be also set to reduce + * required bandwidth, if possible, but it is not necessary. + * This is a private function to qc_sensor_*, other modules should use qc_sensor_setsize() + * If capt is TRUE, then qc_capt_get may be called (and qc_capt_init must be called before). + */ +static int qc_sensor_setsize0(struct quickcam *qc, unsigned int width, unsigned int height, Bool capt) +{ + unsigned char *f; + int r; + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_sensor_setsize(qc=%p,width=%i,height=%i)",qc,width,height); + TEST_BUGR_MSG(qc==NULL, "qc==NULL!"); + + if (width < min_framewidth || width > qc->sensor_data.maxwidth) return -EINVAL; + if (height < min_frameheight || height > qc->sensor_data.maxheight) return -EINVAL; + + /* Applications require, when using Xvideo extension, that the + * frame size is multiple of 8. This is a bug in apps or Xvideo. -tuukkat */ + if (qc->settings.compat_16x) { + width = (width /16)*16; + height = (height/16)*16; + } + /* Set the size only if changed */ + if (qc->vwin.width==width && qc->vwin.height==height) return 0; + + /* For HDCS-1000 we must wait for frame before setting size */ + if (capt) qc_capt_get(qc, &f); + + qc->sensor_data.width = width; /* The sensor-specific code may modify these if not suitable */ + qc->sensor_data.height = height; + if ((r = qc->sensor_data.sensor->set_size(qc, width, height))<0) { + PDEBUG("set_size sensor failed"); + return r; + } + + /* Set the closest size we can actually deliver to application */ + qc->vwin.width = width; + qc->vwin.height = height; + if ((r = qc_i2c_wait(qc))<0) return r; + qc_frame_flush(qc); + return 0; +} +/* }}} */ +/* {{{ [fold] qc_sensor_setsize(struct quickcam *qc, unsigned int width, unsigned int height) */ +/* Called when the application requests a specific image size. Should set the + * actual delivered image size to as close to the requested as possible. + * The image size, as delivered from the camera, can be also set to reduce + * required bandwidth, if possible, but it is not necessary. + * qc_isoc_init() and qc_capt_init() have to be called before this function. + */ +static inline int qc_sensor_setsize(struct quickcam *qc, unsigned int width, unsigned int height) +{ + int r; + r = qc_sensor_setsize0(qc, width, height, qc_isoc_streaming(qc)); + return r; +} +/* }}} */ +/* {{{ [fold] qc_sensor_init(struct quickcam *qc) */ +/* + * Initialise sensor. Initializes all data in qc->sensor which is common to all + * types of sensors and calls the sensor-specific initialization routine. + * The Photobit starts the pixel integration immediately after the reset. + * Note: must call qc_i2c_init() and qc_frame_init() before this function! + */ +static int qc_sensor_init(struct quickcam *qc) +{ + int r; + + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_init_sensor(qc=%p)",qc); + TEST_BUGR_MSG(qc==NULL, "qc==NULL!"); + + qc->sensor_data.width = -1; + qc->sensor_data.height = -1; + qc->sensor_data.exposure = -1; + qc->sensor_data.rgain = -1; + qc->sensor_data.ggain = -1; + qc->sensor_data.bgain = -1; + qc->sensor_data.subsample = qc->settings.subsample; + qc->sensor_data.compress = qc->settings.compress; + + if ((r = qc->sensor_data.sensor->init(qc))<0) goto fail; + if ((r = qc_stv_set(qc, STV_ISO_ENABLE, 0))<0) goto fail; /* Stop isochronous streaming */ + if ((r = qc->sensor_data.sensor->stop(qc))<0) goto fail; /* Stop current frame */ + + /* Set capture size */ + qc->vwin.width = 0; /* Set to illegal value (ensures resetting) */ + qc->vwin.height = 0; + if ((r = qc_sensor_setsize0(qc, qc->sensor_data.maxwidth, qc->sensor_data.maxheight, FALSE))<0) goto fail; + + /* Set brightness settings */ + if ((r = qc->sensor_data.sensor->set_levels(qc, qc->vpic.brightness, qc->vpic.contrast, qc->vpic.hue, qc->vpic.colour))<0) goto fail; + if (qc->sensor_data.sensor->set_target!=NULL) + if ((r = qc->sensor_data.sensor->set_target(qc, qc->vpic.brightness))<0) goto fail; + return 0; + +fail: PRINTK(KERN_ERR,"sensor initialization failed: %i",r); + return r; +} +/* }}} */ + +/* }}} */ +/* {{{ [fold] **** qc_capt: User image capturing functions ******************** */ + +/* {{{ [fold] qc_capt_get(struct quickcam *qc, unsigned char **frame) */ +/* Wait until next image is ready and return the image length in bytes + * and set "frame" to point to the image. If error happens, + * return standard Linux negative error number. The image will be in + * palette and size requested by the user (quickcam->vpic,vwin). + */ +static int qc_capt_get(struct quickcam *qc, unsigned char **frame) +{ + struct qc_capt_data *cd = &qc->capt_data; + unsigned char *rawdata=NULL; /* Raw data from camera */ + int rawdatalen; + int retrycount = qc->settings.retryerrors ? 8 : 0; + int settlecount = cd->settled ? 0 : qc->settings.settle; /* If the picture has already settled, do not wait for it again */ + int midvalue; + int r; + + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_capt_get(quickcam=%p)",qc); + IDEBUG_TEST(*cd); + if ((r = qc_isoc_start(qc))<0) goto fail; /* Start receiving data */ + + do { + r = qc_frame_get(qc, &rawdata); + if (r < 0) goto error; + rawdatalen = r; + r = qc_fmt_convert(qc, rawdata, rawdatalen, cd->frame, MAX_FRAME_SIZE, &midvalue); + if (r < 0) { + qc_frame_free(qc); + goto error; + } + + if (qc->vpic_pending) { + qc->vpic_pending = FALSE; + if (!qc->settings.adaptive) { + /* Set new values now */ + qc->sensor_data.sensor->set_levels(qc, qc->vpic.brightness, qc->vpic.contrast, qc->vpic.hue, qc->vpic.colour); + } else { + if (qc->sensor_data.sensor->set_target!=NULL) + qc->sensor_data.sensor->set_target(qc, qc->vpic.brightness); + } + } + + if (qc->settings.adaptive && !qc->sensor_data.sensor->autoexposure && r>=0 && midvalue>=0) { + int ex, gn; + qc_adapt(qc, midvalue, qc->vpic.brightness>>8, &ex, &gn); + qc->sensor_data.sensor->set_levels(qc, ex, gn, qc->vpic.hue, qc->vpic.colour); + } + qc_frame_free(qc); + + if (qc_adapt_hassettled(qc) || settlecount<=0) break; + settlecount--; + +error: if (r < 0) { + if (qcdebug&QC_DEBUGERRORS) PDEBUG("retrying failed qc_frame_get... rounds=%i", retrycount); + if (r==-ERESTARTSYS || retrycount<=0) break; + retrycount--; + } + qc_i2c_flush(qc); /* Send all pending I2C transfers */ + schedule(); + } while (TRUE); + if (r<0) goto fail; + qc_i2c_flush(qc); /* Send all pending I2C transfers */ + cd->settled = TRUE; + if (frame) *frame = cd->frame; + return r; + +fail: if (qcdebug&(QC_DEBUGERRORS|QC_DEBUGLOGIC)) PDEBUG("failed qc_capt_get()=%i", r); + return r; +} +/* }}} */ +/* {{{ [fold] qc_capt_frameaddr(struct quickcam *qc, unsigned char **frame) */ +/* Return size and address of the capture buffer that is suitable for mmapping, + * Standard Linux errno on error */ +static inline int qc_capt_frameaddr(struct quickcam *qc, unsigned char **frame) +{ + IDEBUG_TEST(qc->capt_data); + if (frame!=NULL) *frame = qc->capt_data.frame; + return MAX_FRAME_SIZE; +} +/* }}} */ +/* {{{ [fold] qc_capt_test(struct quickcam *qc) */ +/* Return TRUE if next image is immediately available, FALSE otherwise. + * Also starts streaming video from camera if not already done so. + * Before calling this function, qc_isoc_init() must be called first. */ +static inline Bool qc_capt_test(struct quickcam *qc) +{ + int e; + IDEBUG_TEST(qc->capt_data); + e = qc_isoc_start(qc); + if (qcdebug&QC_DEBUGERRORS && e<0) PDEBUG("qc_capt_test: qc_isoc_start failed"); + return qc_frame_test(qc); +} +/* }}} */ +/* {{{ [fold] qc_capt_init(struct quickcam *qc) */ +static int qc_capt_init(struct quickcam *qc) +{ + struct qc_capt_data *cd = &qc->capt_data; + int r; + + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_capt_init(quickcam=%p)",qc); + + cd->settled = !(qc->settings.settle>0 && qc->settings.adaptive); + + /* Allocate memory for the (mmappable) capture buffer */ + cd->frame = qc_mm_rvmalloc(MAX_FRAME_SIZE); + if (!cd->frame) { + PRINTK(KERN_ERR, "unable to allocate frame"); + r = -ENOMEM; + goto fail1; + } + + /* Initialize submodules */ + if ((r=qc_frame_init(qc))<0) goto fail2; /* Must be before sensor_init() */ + r = qc_sensor_init(qc); /* Start the sensor (must be after qc_i2c_init but before qc_adapt_init) */ + if (r<0 && qc->settings.compress) { + /* Sensor init failed with compression. Try again without compression */ + PRINTK(KERN_NOTICE, "sensor init failed, disabling compression"); + qc->settings.compress = 0; + r = qc_sensor_init(qc); + } + if (r<0) goto fail3; + if ((r=qc_stream_init(qc))<0) goto fail3; + if ((r=qc_fmt_init(qc))<0) goto fail4; + if ((r=qc_isoc_init(qc))<0) goto fail5; + IDEBUG_INIT(*cd); + return 0; + +fail5: qc_fmt_exit(qc); +fail4: qc_stream_exit(qc); +fail3: qc_frame_exit(qc); +fail2: qc_mm_rvfree(cd->frame, MAX_FRAME_SIZE); +fail1: PDEBUG("failed qc_capt_init()=%i",r); + return r; +} +/* }}} */ +/* {{{ [fold] qc_capt_exit(struct quickcam *qc) */ +static void qc_capt_exit(struct quickcam *qc) +{ + struct qc_capt_data *cd = &qc->capt_data; + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_capt_exit(quickcam=%p)",qc); + qc_isoc_exit(qc); + qc_fmt_exit(qc); + qc_stream_exit(qc); + qc_frame_exit(qc); + qc_mm_rvfree(cd->frame, MAX_FRAME_SIZE); + POISON(cd->frame); + IDEBUG_EXIT(*cd); +} +/* }}} */ + +/* }}} */ +/* {{{ [fold] **** qc_v4l: Start of Video 4 Linux API ************************ */ + +/* {{{ [fold] qc_v4l_poll(struct video_device *dev, struct file *file, poll_table *wait) */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static unsigned int qc_v4l_poll(struct file *file, poll_table *wait) +#else +static unsigned int qc_v4l_poll(struct video_device *dev, struct file *file, poll_table *wait) +#endif +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + struct video_device *dev = video_devdata(file); +#endif + struct quickcam *qc = (struct quickcam *)dev->priv; + struct qc_frame_data *fd = &qc->frame_data; + int mask; + + if (qcdebug&QC_DEBUGUSER) PDEBUG("qc_v4l_poll(dev=%p,file=%p,wait=%p)",dev,file,wait); + if (down_interruptible(&qc->lock)) return -ERESTARTSYS; + poll_wait(file, &fd->wq, wait); + mask = qc_capt_test(qc) ? (POLLIN | POLLRDNORM) : 0; + up(&qc->lock); + return mask; +} +/* }}} */ +/* {{{ [fold] qc_v4l_init(struct quickcam *qc) */ +/* Called when the device is opened */ +static int qc_v4l_init(struct quickcam *qc) +{ + int r, fps; + + if (!qc->settings.keepsettings) { + /* Reset brightness settings */ + qc->vpic.brightness = 32768; + qc->vpic.hue = 32768; + qc->vpic.colour = 32768; + qc->vpic.contrast = 32768; + qc->vpic.whiteness = 32768; + qc_adapt_reset(qc); /* qc_adapt_init() is called from qc_usb_init() */ + } + qc->vpic.palette = VIDEO_PALETTE_RGB24; + qc->vpic.depth = qc_fmt_getdepth(qc->vpic.palette); + qc->vpic_pending = FALSE; + + fps = qc->settings.subsample ? 30 : 8; /* May actually vary depending on image size */ + fps = qc->settings.compress ? 15 : fps; /* Actually 7.5 fps, but we must round it */ + qc->vwin.flags = fps << 16; /* Bits 22..16 contain framerate in Philips driver. We do the same. */ + + if ((r = qc_capt_init(qc))<0) goto fail; + return 0; + +fail: if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGERRORS) PDEBUG("failed qc_v4l_init()=%i",r); + return r; +} +/* }}} */ +/* {{{ [fold] qc_v4l_open(struct video_device *dev, int flags) */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static int qc_v4l_open(struct inode *inode, struct file *file) +#else +static int qc_v4l_open(struct video_device *dev, int flags) +#endif +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + struct video_device *dev = video_devdata(file); +#endif + struct quickcam *qc = dev->priv; + int r; + + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGUSER) PDEBUG("qc_v4l_open(qc=%p)", qc); +//PDEBUG("sleeping 10 sec..."); +//qc_usleep(1000000*10); +//PDEBUG("sleep done"); + // FIXME: if the module is tried to be unloaded at this point, + // v4l_close() and MOD_DEC_USE_COUNT will never be called + // According to "Linux Device drivers" pg.70, it's ok if called before sleeping? + // 2.2 will crash, 2.4 will hang and show "quickcam 1 (deleted)" if sleeping + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("MOD_INC_USE_COUNT in qc_v4l_open() : %i",GET_USE_COUNT(THIS_MODULE)); + MOD_INC_USE_COUNT; + + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("down_intr(quickcam_list) in qc_v4l_open() : %i", sem_getcount(&quickcam_list_lock)); + + r = qc_lock(qc); + if (r<0) goto fail1; + + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("down_intr(%p) in qc_v4l_open() : %i", qc, sem_getcount(&qc->lock)); + if (down_interruptible(&qc->lock)) { + r = -ERESTARTSYS; + goto fail2; + } + if (!qc->connected) { + r = -ENODEV; + goto fail3; + } + qc->users++; + PDEBUG("open users=%i", qc->users); + if (qc->users == 1) { + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("First user, initializing"); + if ((r = qc_v4l_init(qc))<0) goto fail4; + } + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(%p) in qc_v4l_open() : %i",qc, sem_getcount(&qc->lock)); + up(&qc->lock); + up(&quickcam_list_lock); + return 0; + +fail4: qc->users--; +fail3: if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(%p) in qc_v4l_open()=failed : %i",qc, sem_getcount(&qc->lock)); + up(&qc->lock); +fail2: if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(quickcam_list) in qc_v4l_open()=failed : %i", sem_getcount(&qc->lock)); + up(&quickcam_list_lock); +fail1: if (qcdebug&QC_DEBUGMUTEX) PDEBUG("MOD_DEC_USE_COUNT in qc_v4l_open() : %i",GET_USE_COUNT(THIS_MODULE)); + MOD_DEC_USE_COUNT; + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGERRORS) PDEBUG("failed qc_v4l_open()=%i",r); + return r; +} +/* }}} */ +/* {{{ [fold] qc_v4l_exit(struct quickcam *qc) */ +/* Release all resources allocated at qc_v4l_init() */ +static inline void qc_v4l_exit(struct quickcam *qc) +{ + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_v4l_cleanup(%p)", qc); + qc_capt_exit(qc); +} +/* }}} */ +/* {{{ [fold] qc_v4l_close(struct video_device *dev) */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static int qc_v4l_close(struct inode *inode, struct file *file) +#else +static void qc_v4l_close(struct video_device *dev) +#endif +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + struct video_device *dev = video_devdata(file); +#endif + struct quickcam *qc = (struct quickcam *)dev->priv; + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGUSER) PDEBUG("qc_v4l_close(dev=%p,qc=%p)",dev,qc); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + TEST_BUGR_MSG(qc==NULL, "qc==NULL"); +#else + TEST_BUG_MSG(qc==NULL, "qc==NULL"); +#endif + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("down(quickcam_list) in qc_v4l_close() : %i", sem_getcount(&quickcam_list_lock)); + down(&quickcam_list_lock); /* Can not interrupt, we must success */ + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("down(%p) in qc_v4l_close() : %i", qc, sem_getcount(&qc->lock)); + down(&qc->lock); /* Can not interrupt, we must success */ + qc->users--; + PDEBUG("close users=%i", qc->users); + if (qc->users == 0) { + /* No more users, device is deallocated */ + qc_v4l_exit(qc); + if (qc->dev == NULL) { /* Test qc->dev instead of qc->connected because disconnection routine sets the latter before locking camera */ + /* Camera was unplugged and freeing was postponed: free resources now here */ + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("Performing postponed free"); + qc_usb_exit(qc); + qc = NULL; + } + } + if (qc) { + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(%p) in qc_v4l_close() : %i", qc, sem_getcount(&qc->lock)); + up(&qc->lock); + } + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(quickcam_list) in qc_v4l_close() : %i", sem_getcount(&quickcam_list_lock)); + up(&quickcam_list_lock); + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("MOD_DEC_USE_COUNT in qc_v4l_close() : %i", GET_USE_COUNT(THIS_MODULE)); + MOD_DEC_USE_COUNT; + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("v4l_close() ok"); +#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,0) + return 0; +#endif +} +/* }}} */ +/* {{{ [fold] qc_v4l_read(struct video_device *dev, char *buf, unsigned long count, int noblock) */ +static ssize_t qc_v4l_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + struct video_device *dev = video_devdata(file); + int noblock = file->f_flags & O_NONBLOCK; +#endif + struct quickcam *qc = (struct quickcam *)dev->priv; + int frame_len; + unsigned char *frame; + long r = 0; + + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGUSER) + PDEBUG("qc_v4l_read(dev=%p,buf=%p,count=%li,noblock=%i,qc=%p)",dev,buf,(long)count,noblock,qc); + if (!qc || !buf) { + PDEBUG("qc_read: no video_device available or no buffer attached :( EFAULT"); + return -EFAULT; + } + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("down_intr(%p) in qc_v4l_read() : %i", qc, sem_getcount(&qc->lock)); + if (down_interruptible(&qc->lock)) return -ERESTARTSYS; + if (!qc->connected) { + r = -ENODEV; + goto fail; + } + if (noblock && !qc_capt_test(qc)) { + r = -EAGAIN; + goto fail; + } + frame_len = qc_capt_get(qc, &frame); + if (frame_len < 0) { + r = frame_len; + goto fail; + } + if (count > frame_len) count = frame_len; + if (copy_to_user(buf, frame, count)) { + r = -EFAULT; + goto fail; + } + r = count; + +fail: if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(%p) in qc_v4l_read() : %i", qc, sem_getcount(&qc->lock)); + up(&qc->lock); + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGERRORS) if (r<0) PDEBUG("failed qc_v4l_read()=%i", (int)r); + return r; +} +/* }}} */ +/* {{{ [fold] qc_v4l_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size) */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static int qc_v4l_mmap(struct file *file, struct vm_area_struct *vma) +#else +static int qc_v4l_mmap( +#if HAVE_VMA + struct vm_area_struct *vma, +#endif + struct video_device *dev, const char *start, unsigned long size) +#endif /* 2.6.x */ +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + struct video_device *dev = video_devdata(file); + const void *start = (void *)vma->vm_start; + unsigned long size = vma->vm_end - vma->vm_start; +#endif + struct quickcam *qc = (struct quickcam *)dev->priv; + unsigned char *frame; + int ret = 0, frame_size; +#if !HAVE_VMA && LINUX_VERSION_CODElock)); + if (down_interruptible(&qc->lock)) return -ERESTARTSYS; + if (!qc->connected) { ret = -ENODEV; goto fail; } + frame_size = qc_capt_frameaddr(qc, &frame); + if (frame_size<0) { ret = frame_size; goto fail; } /* Should never happen */ + ret = qc_mm_remap(vma, frame, frame_size, start, size); + +fail: if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(%p) in qc_v4l_mmap() : %i", qc, sem_getcount(&qc->lock)); + up(&qc->lock); + if (ret<0) if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGERRORS) PDEBUG("failed qc_v4l_mmap()=%i",ret); + return ret; +} +/* }}} */ +/* {{{ [fold] qc_v4l_ioctl(struct video_device *dev, unsigned int cmd, void *arg) */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static int qc_v4l_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +#else +static int qc_v4l_ioctl(struct video_device *dev, unsigned int cmd, void *argp) +#endif +{ + static const Bool ignore_channel = TRUE; /* RealProducer is reported to fail if driver doesn't accept channel change */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + struct video_device *dev = video_devdata(file); + void *argp = (void *)arg; +#endif + struct quickcam *qc = (struct quickcam *)dev->priv; + int i, retval = 0; + + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGUSER) PDEBUG("qc_v4l_ioctl(dev=%p,cmd=%u,arg=%p,qc=%p)",dev,cmd,argp,qc); + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("down_intr(%p) in qc_v4l_ioctl() : %i", qc, sem_getcount(&qc->lock)); + if (down_interruptible(&qc->lock)) return -ERESTARTSYS; + if (!qc->connected) { + retval = -ENODEV; + goto fail; + } + switch (cmd) { +/* {{{ [fold] VIDIOCGCAP: Capability query */ + case VIDIOCGCAP: /* Capability query */ + { + struct video_capability b; + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCGCAP"); + memset(&b, 0, sizeof(b)); + strcpy(b.name, "Logitech QuickCam USB"); /* Max 31 characters */ + b.type = qc->vdev.vfl_type; + b.channels = 1; + b.audios = 0; + b.maxwidth = qc->sensor_data.maxwidth; + b.maxheight = qc->sensor_data.maxheight; + if (qc->settings.compat_16x) { + b.maxwidth = (b.maxwidth /16)*16; + b.maxheight = (b.maxheight/16)*16; + } + b.minwidth = min_framewidth; + b.minheight = min_frameheight; + if (copy_to_user(argp, &b, sizeof(b))) retval = -EFAULT; + break; + } +/* }}} */ +/* {{{ [fold] VIDIOCGCHAN: Get properties of the specified channel */ + case VIDIOCGCHAN: /* Get properties of the specified channel */ + { + struct video_channel v; + if (copy_from_user(&v, argp, sizeof(v))) { + retval = -EFAULT; + break; + } + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCGCHAN channel:%i",v.channel); + if (!ignore_channel && v.channel != 0) { + retval = -EINVAL; + break; + } + v.flags = 0; + v.tuners = 0; + v.type = VIDEO_TYPE_CAMERA; + strcpy(v.name, "Camera"); + if (copy_to_user(argp, &v, sizeof(v))) retval = -EFAULT; + break; + } +/* }}} */ +/* {{{ [fold] VIDIOCSCHAN: Select channel to capture */ + case VIDIOCSCHAN: /* Select channel to capture */ + { + if (copy_from_user(&i, argp, sizeof(i))) { + retval = -EFAULT; + break; + } + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCSCHAN channel:%i",i); + if (!ignore_channel && i!=0) retval = -EINVAL; + break; + } +/* }}} */ +/* {{{ [fold] VIDIOCGPICT: Get image properties (brightness, palette, etc.) */ + case VIDIOCGPICT: /* Get image properties */ + { + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCGPICT"); + if (copy_to_user(argp, &qc->vpic, sizeof(qc->vpic))) retval = -EFAULT; + break; + } +/* }}} */ +/* {{{ [fold] VIDIOCSPICT: Set image properties */ + case VIDIOCSPICT: /* Set image properties */ + { + struct video_picture p; + if (copy_from_user(&p, argp, sizeof(p))) { + retval = -EFAULT; + break; + } + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCSPICT depth:%d palette:%s(%i) bright=%i",p.depth,qc_fmt_getname(p.palette),p.palette,p.brightness); + + if (p.palette != 0) { /* 0 = do not change palette */ + retval = qc_fmt_issupported(p.palette); + if (retval<0) break; + qc->vpic.palette = p.palette; + qc->vpic.depth = qc_fmt_getdepth(p.palette); + if (qc->vpic.depth != p.depth) PDEBUG("warning: palette depth mismatch"); + } + qc->vpic.brightness = p.brightness; + qc->vpic.hue = p.hue; + qc->vpic.colour = p.colour; + qc->vpic.contrast = p.contrast; + qc->vpic.whiteness = p.whiteness; /* Used for sharpness */ + qc->vpic_pending = TRUE; + break; + } +/* }}} */ +/* {{{ [fold] VIDIOCSWIN: Set capture area width and height */ + case VIDIOCSWIN: /* Set capture area width and height */ + { + struct video_window vw; + int fps; + if (copy_from_user(&vw, argp, sizeof(vw))) { + retval = -EFAULT; + break; + } + fps = (vw.flags>>16) & 0x3F; /* 6 bits for framerate */ + if (fps && ((qc->vwin.flags>>16)&0x3F)!=fps) { + PDEBUG("Application tries to change framerate"); + } + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCSWIN width:%i height:%i flags:%d clipcount:%d",vw.width,vw.height,vw.flags,vw.clipcount); + retval = qc_sensor_setsize(qc, vw.width, vw.height); + break; + } +/* }}} */ +/* {{{ [fold] VIDIOCGWIN: Get current capture area */ + case VIDIOCGWIN: /* Get current capture area */ + { + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCGWIN"); + if (copy_to_user(argp, &qc->vwin, sizeof(qc->vwin))) retval = -EFAULT; + break; + } +/* }}} */ +/* {{{ [fold] VIDIOCGMBUF: Get mmap buffer size and frame offsets */ + case VIDIOCGMBUF: /* Get mmap buffer size and frame offsets */ + { + struct video_mbuf vm; + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCGMBUF"); + memset(&vm, 0, sizeof(vm)); + vm.size = qc_capt_frameaddr(qc, NULL); + if (vm.size<0) { /* Negative value denotes error */ + retval = vm.size; + break; + } + vm.frames = 1; + vm.offsets[0] = 0; + if (qc->settings.compat_dblbuf) { + /* Really many applications are broken and don't work with a single buffer */ + vm.frames = 2; + vm.offsets[1] = 0; + } + if (copy_to_user(argp, &vm, sizeof(vm))) retval = -EFAULT; + break; + } +/* }}} */ +/* {{{ [fold] VIDIOCMCAPTURE: Start capturing specified frame in the mmap buffer with specified size */ + case VIDIOCMCAPTURE: /* Start capturing specified frame in the mmap buffer with specified size */ + { + struct video_mmap vm; + if (copy_from_user(&vm, argp, sizeof(vm))) { + retval = -EFAULT; + break; + } + /* Bug in V4L: sometimes it's called palette, sometimes format. We'll stick with palette */ + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCMCAPTURE frame:%d size:%dx%d palette:%s", vm.frame, vm.width, vm.height, qc_fmt_getname(vm.format)); + if (vm.frame!=0 && !(qc->settings.compat_dblbuf)) { + PRINTK(KERN_NOTICE,"Bug detected in user program, use qcset compat=dblbuf"); + retval = -EINVAL; + break; + } + if (vm.format!=0 && qc->vpic.palette!=vm.format) { /* 0 = do not change palette */ + retval = qc_fmt_issupported(vm.format); + if (retval) { + if (qcdebug&QC_DEBUGERRORS) PDEBUG("unsupported image format"); + break; + } + qc->vpic.palette = vm.format; + qc->vpic.depth = qc_fmt_getdepth(vm.format); + } + retval = qc_sensor_setsize(qc, vm.width, vm.height); + break; + } +/* }}} */ +/* {{{ [fold] VIDIOCSYNC: Wait until specified frame in the mmap buffer has been captured */ + case VIDIOCSYNC: /* Wait until specified frame in the mmap buffer has been captured */ + { + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCSYNC"); + retval = qc_capt_get(qc, NULL); + if (retval>0) retval = 0; + break; + } +/* }}} */ +/* {{{ [fold] VIDIOCGFBUF: Get currently used frame buffer parameters */ + case VIDIOCGFBUF: /* Get currently used frame buffer parameters */ + { + struct video_buffer vb; + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCGFBUF"); + memset(&vb, 0, sizeof(vb)); + if (copy_to_user(argp, &vb, sizeof(vb))) retval = -EFAULT; + break; + } +/* }}} */ +/* {{{ [fold] VIDIOCKEY: Undocumented? */ + case VIDIOCKEY: /* Undocumented? */ + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCKEY"); + retval = -EINVAL; + break; +/* }}} */ +/* {{{ [fold] VIDIOCCAPTURE: Activate overlay capturing directly to framebuffer */ + case VIDIOCCAPTURE: /* Activate overlay capturing directly to framebuffer */ + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCCAPTURE"); + retval = -EINVAL; + break; +/* }}} */ +/* {{{ [fold] VIDIOCSFBUF: Set frame buffer parameters for the capture card */ + case VIDIOCSFBUF: /* Set frame buffer parameters for the capture card */ + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCSFBUF"); + retval = -EINVAL; + break; +/* }}} */ +/* {{{ [fold] VIDIOCxTUNER: Get properties of the specified tuner / Select tuner to use */ + case VIDIOCGTUNER: /* Get properties of the specified tuner */ + case VIDIOCSTUNER: /* Select tuner to use */ + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCxTUNER"); + retval = -EINVAL; + break; +/* }}} */ +/* {{{ [fold] VIDIOCxFREQ: Get current tuner frequency / Set tuner frequency */ + case VIDIOCGFREQ: /* Get current tuner frequency */ + case VIDIOCSFREQ: /* Set tuner frequency */ + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCxFREQ"); + retval = -EINVAL; + break; +/* }}} */ +/* {{{ [fold] VIDIOCxAUDIO: Get/Set audio properties */ + case VIDIOCGAUDIO: /* Get audio properties */ + case VIDIOCSAUDIO: /* Set audio properties */ + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCxAUDIO"); + retval = -EINVAL; + break; +/* }}} */ + /********** Private IOCTLs ***********/ +/* {{{ [fold] VIDIOCQCxDEBUG: Sets/gets the qcdebug output (1,2,4,8,16,32) */ + case VIDIOCQCSDEBUG: /* Sets the qcdebug output (1,2,4,8,16,32) */ + if (get_user(qcdebug, (int *)argp)) { retval=-EFAULT; break; } + case VIDIOCQCGDEBUG: /* Gets the qcdebug output (1,2,4,8,16,32) */ + if (put_user(qcdebug, (int *)argp)) { retval=-EFAULT; break; } + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCxDEBUG"); + break; +/* }}} */ +/* {{{ [fold] VIDIOCQCxKEEPSETTINGS: Set/get keep gain settings across one open to another (0-1) */ + case VIDIOCQCSKEEPSETTINGS: /* Set keep gain settings across one open to another (0-1) */ + if (get_user(i, (int *)argp)) { retval=-EFAULT; break; } + qc->settings.keepsettings = i; + case VIDIOCQCGKEEPSETTINGS: /* Get keep gain settings across one open to another (0-1) */ + i = qc->settings.keepsettings; + if (put_user(i, (int *)argp)) { retval=-EFAULT; break; } + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCxKEEPSETTINGS"); + break; +/* }}} */ +/* {{{ [fold] VIDIOCQCxSETTLE: Set/get if we let image brightness to settle (0-1) */ + case VIDIOCQCSSETTLE: /* Set if we let image brightness to settle (0-1) */ + if (get_user(i, (int *)argp)) { retval=-EFAULT; break; } + qc->settings.settle = i; + case VIDIOCQCGSETTLE: /* Get if we let image brightness to settle (0-1) */ + i = qc->settings.settle; + if (put_user(i, (int *)argp)) { retval=-EFAULT; break; } + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCxSETTLE"); + break; +/* }}} */ +/* {{{ [fold] VIDIOCQCxSUBSAMPLE: Sets/gets the speed (0-1) */ + case VIDIOCQCSSUBSAMPLE: /* Sets the speed (0-1) */ + if (get_user(i, (int *)argp)) { retval=-EFAULT; break; } + qc->settings.subsample = i; + case VIDIOCQCGSUBSAMPLE: /* Gets the speed (0-1) */ + i = qc->settings.subsample; + if (put_user(i, (int *)argp)) { retval=-EFAULT; break; } + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCxSUBSAMPLE"); + break; +/* }}} */ +/* {{{ [fold] VIDIOCQCxCOMPRESS: Sets/gets the compression mode (0-1) */ + case VIDIOCQCSCOMPRESS: /* Sets the compression mode (0-1) */ + if (get_user(i, (int *)argp)) { retval=-EFAULT; break; } + qc->settings.compress = i; + case VIDIOCQCGCOMPRESS: /* Gets the compression mode (0-1) */ + i = qc->settings.compress; + if (put_user(i, (int *)argp)) { retval=-EFAULT; break; } + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCxCOMPRESS"); + break; +/* }}} */ +/* {{{ [fold] VIDIOCQCxFRAMESKIP: Set/get frame capture frequency (0-10) */ + case VIDIOCQCSFRAMESKIP: /* Set frame capture frequency (0-10) */ + if (get_user(i, (int *)argp)) { retval=-EFAULT; break; } + qc->settings.frameskip = i; + case VIDIOCQCGFRAMESKIP: /* Get frame capture frequency (0-10) */ + i = qc->settings.frameskip; + if (put_user(i, (int *)argp)) { retval=-EFAULT; break; } + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCxFRAMESKIP"); + break; +/* }}} */ +/* {{{ [fold] VIDIOCQCxQUALITY: Sets/gets the interpolation mode (0-2) */ + case VIDIOCQCSQUALITY: /* Sets the interpolation mode (0-5) */ + if (get_user(i, (int *)argp)) { retval=-EFAULT; break; } + qc->settings.quality = i; + case VIDIOCQCGQUALITY: /* Gets the interpolation mode (0-5) */ + i = qc->settings.quality; + if (put_user(i, (int *)argp)) { retval=-EFAULT; break; } + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCxQUALITY"); + break; +/* }}} */ +/* {{{ [fold] VIDIOCQCxADAPTIVE: Set/get automatic adaptive brightness control (0-1) */ + case VIDIOCQCSADAPTIVE: /* Set automatic adaptive brightness control (0-1) */ + if (get_user(i, (int *)argp)) { retval=-EFAULT; break; } + qc->settings.adaptive = i; + case VIDIOCQCGADAPTIVE: /* Get automatic adaptive brightness control (0-1) */ + i = qc->settings.adaptive; + if (put_user(i, (int *)argp)) { retval=-EFAULT; break; } + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCxADAPTIVE"); + break; +/* }}} */ +/* {{{ [fold] VIDIOCQCxEQUALIZE: Set/get equalize image (0-1) */ + case VIDIOCQCSEQUALIZE: /* Set equalize image (0-1) */ + if (get_user(i, (int *)argp)) { retval=-EFAULT; break; } + qc->settings.equalize = i; + case VIDIOCQCGEQUALIZE: /* Get equalize image (0-1) */ + i = qc->settings.equalize; + if (put_user(i, (int *)argp)) { retval=-EFAULT; break; } + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCxEQUALIZE"); + break; +/* }}} */ +/* {{{ [fold] VIDIOCQCxUSERLUT: Set/get user-specified lookup-table */ + case VIDIOCQCSUSERLUT: /* Set user-specified lookup-table [struct qc_userlut] */ + { + unsigned int flags; + retval = -EFAULT; + if (get_user(flags, &(((struct qc_userlut*)argp)->flags))) break; + if (flags & QC_USERLUT_DEFAULT) { + userlut = ((flags & QC_USERLUT_ENABLE) != 0); + } else { + qc->settings.userlut = ((flags & QC_USERLUT_ENABLE) != 0); + } + if (flags & QC_USERLUT_VALUES) { + for (i=0; ilut[i]))) break; + if (flags & QC_USERLUT_DEFAULT) { + userlut_contents[i] = p; + } else { + qc->fmt_data.userlut[i] = p; + } + } + if (i < QC_LUT_SIZE) break; + } + retval = 0; + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCSUSERLUT"); + break; + } + case VIDIOCQCGUSERLUT: /* Get user-specified lookup-table [struct qc_userlut] */ + { + unsigned int flags; + retval = -EFAULT; + if (get_user(flags, &(((struct qc_userlut*)argp)->flags))) break; + flags &= (~QC_USERLUT_ENABLE); + if ((flags & QC_USERLUT_DEFAULT) ? userlut : qc->settings.userlut) flags |= QC_USERLUT_ENABLE; + if (put_user(flags, &(((struct qc_userlut*)argp)->flags))) break; + if (flags & QC_USERLUT_VALUES) { + for (i=0; ifmt_data.userlut[i]; + } + if (put_user(p, &(((struct qc_userlut*)argp)->lut[i]))) break; + } + if (i < QC_LUT_SIZE) break; + } + retval = 0; + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCGUSERLUT"); + break; + } +/* }}} */ +/* {{{ [fold] VIDIOCQCxRETRYERRORS: Set/get if we retry when error happen in capture (0-1) */ + case VIDIOCQCSRETRYERRORS: /* Set if we retry when error happen in capture (0-1) */ + if (get_user(i, (int *)argp)) { retval=-EFAULT; break; } + qc->settings.retryerrors = i; + case VIDIOCQCGRETRYERRORS: /* Get if we retry when error happen in capture (0-1) */ + i = qc->settings.retryerrors; + if (put_user(i, (int *)argp)) { retval=-EFAULT; break; } + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCxRETRYERRORS"); + break; +/* }}} */ +/* {{{ [fold] VIDIOCQCxCOMPATIBLE: Set enable workaround for Xawtv/Motv bugs (0-1) */ + case VIDIOCQCSCOMPATIBLE: /* Set enable workaround for Xawtv/Motv bugs (0-1) */ + if (get_user(i, (int *)argp)) { retval=-EFAULT; break; } + qc->settings.compat_16x = (i & QC_COMPAT_16X) != 0; + qc->settings.compat_dblbuf = (i & QC_COMPAT_DBLBUF) != 0; + qc->settings.compat_torgb = (i & QC_COMPAT_TORGB) != 0; + case VIDIOCQCGCOMPATIBLE: /* Get enable workaround for Xawtv/Motv bugs (0-1) */ + i = ~(qc->settings.compat_16x -1) & QC_COMPAT_16X; + i |= ~(qc->settings.compat_dblbuf-1) & QC_COMPAT_DBLBUF; + i |= ~(qc->settings.compat_torgb -1) & QC_COMPAT_TORGB; + if (put_user(i, (int *)argp)) { retval=-EFAULT; break; } + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCxCOMPATIBLE"); + break; +/* }}} */ +/* {{{ [fold] VIDIOCQCxVIDEONR: Set videodevice number (/dev/videoX) */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,5) + case VIDIOCQCSVIDEONR: /* Set videodevice number (/dev/videoX) */ + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCSVIDEONR"); + retval = -EINVAL; /* Can not set after the module is loaded */ + break; + case VIDIOCQCGVIDEONR: /* Get videodevice number (/dev/videoX) */ + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCGVIDEONR"); + if (put_user(video_nr, (int *)argp)) { retval=-EFAULT; break; } + break; +#endif +/* }}} */ +/* {{{ [fold] VIDIOCQCxSTV: Read/write STV chip register value */ + /* Encoding: bits 31..16 of the int argument contain register value, 15..0 the reg number */ + case VIDIOCQCGSTV: /* Read STV chip register value */ + { + int reg, val; + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCQCGSTV"); + if (get_user(reg, (int *)argp)) { retval=-EFAULT; break; } + reg &= 0xFFFF; + val = qc_stv_get(qc, reg); + if (val<0) { retval=val; break; } + val = (val<<16) | reg; + if (put_user(val, (int *)argp)) { retval=-EFAULT; break; } + break; + } + case VIDIOCQCSSTV: /* Write STV chip register value */ + { + int regval; + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCQCSSTV"); + if (!capable(CAP_SYS_RAWIO)) { retval=-EPERM; break; } + if (get_user(regval, (int *)argp)) { retval=-EFAULT; break; } + retval = qc_stv_set(qc, regval & 0xFFFF, regval >> 16); + break; + } +/* }}} */ +/* {{{ [fold] VIDIOCQCxI2C: Read/write sensor chip register value via I2C */ + case VIDIOCQCGI2C: /* Read sensor chip register value via I2C */ + { + int reg, val; + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCQCGI2C"); + if (get_user(reg, (int *)argp)) { retval=-EFAULT; break; } + reg &= 0xFFFF; + val = qc_get_i2c(qc, qc->sensor_data.sensor, reg); + if (val<0) { retval=val; break; } + val = (val<<16) | reg; + if (put_user(val, (int *)argp)) { retval=-EFAULT; break; } + break; + } + case VIDIOCQCSI2C: /* Write sensor chip register value via I2C */ + { + int regval; + if (qcdebug&QC_DEBUGUSER) PDEBUG("VIDIOCQCSI2C"); + if (!capable(CAP_SYS_RAWIO)) { retval=-EPERM; break; } + if (get_user(regval, (int *)argp)) { retval=-EFAULT; break; } + retval = qc_i2c_set(qc, regval & 0xFFFF, regval >> 16); + if (retval<0) break; + retval = qc_i2c_wait(qc); + break; + } +/* }}} */ + default: + if (qcdebug&QC_DEBUGUSER) PDEBUG("Unknown IOCTL %08X",cmd); + retval = -ENOIOCTLCMD; + break; + } +fail: if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(%p) in qc_v4l_ioctl() : %i", qc, sem_getcount(&qc->lock)); + up(&qc->lock); + if (retval<0) if (qcdebug&(QC_DEBUGLOGIC|QC_DEBUGUSER|QC_DEBUGERRORS)) PDEBUG("failed qc_v4l_ioctl()=%i",retval); + return retval; +} +/* }}} */ +/* {{{ [fold] qc_v4l_write(struct video_device *dev, const char *buf, unsigned long count, int noblock) */ +#if LINUX_VERSION_CODE= KERNEL_VERSION(2,6,0) +static void qc_v4l_release(struct video_device *vfd) { } +static struct file_operations qc_v4l_fops = { + owner: THIS_MODULE, + open: qc_v4l_open, + release: qc_v4l_close, + read: qc_v4l_read, +// write: qc_v4l_write, + ioctl: qc_v4l_ioctl, + mmap: qc_v4l_mmap, + poll: qc_v4l_poll, +}; +#endif + +static struct video_device qc_v4l_template = { + name: "QuickCam USB", + minor: -1, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + release: qc_v4l_release, + fops: &qc_v4l_fops, +#else + initialize: NULL, + open: qc_v4l_open, + close: qc_v4l_close, + read: qc_v4l_read, + write: qc_v4l_write, + ioctl: qc_v4l_ioctl, + mmap: qc_v4l_mmap, + poll: qc_v4l_poll, +#endif +}; +/* }}} */ +/* {{{ [fold] **** qc_usb: Start of USB API ********************************** */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static int qc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +static void *qc_usb_probe(struct usb_device *dev, unsigned int iface, const struct usb_device_id *id); +#else +static void *qc_usb_probe(struct usb_device *dev, unsigned int iface); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static void qc_usb_disconnect(struct usb_interface *intf); +#else +static void qc_usb_disconnect(struct usb_device *dev, void *ptr); +#endif + +static struct usb_driver qc_usb_driver = { + name: qc_name, + probe: qc_usb_probe, + disconnect: qc_usb_disconnect, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) \ + && LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15) + owner: THIS_MODULE, +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + id_table: qc_device_table, +#endif +}; + +/* {{{ [fold] qc_usb_init(struct usb_device *dev, unsigned int ifacenum) */ +/* Detect sensor, initialize the quickcam structure, register V4L device, create /proc entry. + * Return pointer to the allocated quickcam structure or NULL on error. + * If there is some camera already open but disconnected, reuse the quickcam structure. */ +static struct quickcam *qc_usb_init(struct usb_device *usbdev, unsigned int ifacenum) +{ + struct quickcam *qc; + Bool reuse_qc; + int i, r = 0; + + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_usb_init(usbdev=%p)", usbdev); + if (PARANOID && usbdev==NULL) { PRINTK(KERN_CRIT,"usbdev==NULL"); return NULL; } + + /* Check if there is already a suitable quickcam struct that can be reused */ + reuse_qc = FALSE; + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("down_intr(quickcam_list_lock) in qc_usb_init() : %i", sem_getcount(&quickcam_list_lock)); + if (down_interruptible(&quickcam_list_lock)) return NULL; + list_for_each_entry(qc, &quickcam_list, list) { + if (qc->dev!=NULL) continue; /* quickcam_list_lock protects this test */ + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("down_intr(%p) in qc_usb_init() : %i",qc, sem_getcount(&qc->lock)); + if (down_interruptible(&qc->lock)) { + /* Failed to lock the camera. Move on in the list, skipping this camera */ + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("failed locking the camera %p in qc_usb_init() : %i",qc,sem_getcount(&qc->lock)); + continue; + } + if (qc->users<=0) { + PRINTK(KERN_NOTICE, "Unplugged unused camera detected!"); + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(%p) in qc_usb_init() : %i",qc, sem_getcount(&qc->lock)); + up(&qc->lock); + continue; + } + /* Found and locked unplugged but used camera */ + reuse_qc = TRUE; + break; + } + + if (reuse_qc) { + /* Reuse existing quickcam (which is already opened) */ + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("Reusing existing quickcam"); + if (PARANOID && qc->users<=0) PRINTK(KERN_CRIT, "Unplugged JUST closed camera detected!"); + qc_isoc_stop(qc); + qc_i2c_wait(qc); + qc_frame_flush(qc); + } else { + /* Allocate and initialize some members of the new qc */ + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("Allocating new quickcam"); + qc = kmalloc(sizeof(*qc), GFP_KERNEL); + CHECK_ERROR(qc==NULL, fail1, "couldn't kmalloc quickcam struct"); + memset(qc, 0, sizeof(*qc)); /* No garbage to user */ +PDEBUG("poisoning qc in qc_usb_init"); + POISON(*qc); + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("init down(%p) in qc_usb_init()", qc); +#ifdef CONFIG_PREEMPT_RT + init_MUTEX(&qc->lock); + down(&qc->lock); +#else + init_MUTEX_LOCKED(&qc->lock); +#endif + qc->users = 0; + if ((r=qc_i2c_init(qc))<0) goto fail2; + } + qc->dev = usbdev; + qc->iface = ifacenum; + qc->connected = TRUE; + + /* Probe for the sensor type */ + qc_i2c_wait(qc); /* Necessary before set_interface() */ + if ((r=usb_set_interface(usbdev, qc->iface, 0))<0) goto fail3; /* Set altsetting 0 */ + if ((r=qc_stv_set(qc, STV_ISO_ENABLE, 0))<0) goto fail3; /* Disable isochronous stream */ + for (i=0; iid_reg))<0) goto fail3; + r = (r >> (sensors[i]->length_id-1) * 8) & 0xFF; /* Get MSB of received value */ + if (qcdebug&QC_DEBUGCAMERA) PDEBUG("Probing %s: expecting %02X, got %02X", sensors[i]->name, sensors[i]->id, r); + if (r == sensors[i]->id) break; + } + if (i>=SIZE(sensors)) { + PRINTK(KERN_INFO,"unsupported sensor"); + goto fail3; + } + qc->sensor_data.sensor = sensors[i]; + PRINTK(KERN_INFO,"Sensor %s detected", sensors[i]->name); + + if ((r=qc_stv_set(qc, STV_ISO_ENABLE, 0))<0) goto fail3; /* Disable isochronous streaming */ + if ((r=qc_stv_set(qc, STV_REG23, 1))<0) goto fail3; + + if (!reuse_qc) { + /* Set default settings */ + qc->vpic.brightness = 32768; + qc->vpic.hue = 32768; + qc->vpic.colour = 32768; + qc->vpic.contrast = 32768; + qc->vpic.whiteness = 32768; /* Used for sharpness at quality=5 */ + qc->settings.keepsettings = keepsettings; + qc->settings.settle = settle; + qc->settings.subsample = subsample; + qc->settings.compress = compress; + qc->settings.frameskip = frameskip; + qc->settings.quality = quality; + qc->settings.adaptive = adaptive; + qc->settings.equalize = equalize; + qc->settings.userlut = userlut; + qc->settings.retryerrors = retryerrors; + qc->settings.compat_16x = compatible & QC_COMPAT_16X ? 1 : 0; + qc->settings.compat_dblbuf = compatible & QC_COMPAT_DBLBUF ? 1 : 0; + qc->settings.compat_torgb = compatible & QC_COMPAT_TORGB ? 1 : 0; + memcpy(&qc->fmt_data.userlut, userlut_contents, sizeof(qc->fmt_data.userlut)); + + /* Register V4L video device */ + memcpy(&qc->vdev, &qc_v4l_template, sizeof(qc_v4l_template)); + qc->vdev.priv = qc; + r = video_register_device(&qc->vdev, VFL_TYPE_GRABBER, video_nr); + if (r<0) goto fail3; + PRINTK(KERN_INFO, "Registered device: /dev/video%i", qc->vdev.minor); + if ((r=qc_adapt_init(qc))<0) goto fail4; + qc_proc_create(qc); /* Create /proc entry, ignore if it fails */ + list_add(&qc->list, &quickcam_list); + } + + if (reuse_qc && qc->frame_data.waiting>0) { + /* Restart capturing */ + int width = qc->vwin.width; + int height = qc->vwin.height; +//qc_usleep(1000000); + qc_isoc_stop(qc); + r = qc_sensor_init(qc); + r = qc_isoc_start(qc); + r = qc_sensor_setsize(qc, width, height); + /* Ignore return codes for now, if it fails, too bad, but shouldn't crash */ + /* FIXME: proper error handling */ + +/*qc_usleep(1000000); + qc_sensor_setsize(qc, width, height); +qc_usleep(1000000); + qc_sensor_setsize(qc, 32, 32); +qc_usleep(1000000); + qc_sensor_setsize(qc, width, height); +qc_usleep(1000000);*/ + +#if 0 +/* The following tries to initialize VV6410 really hard. still doesn't work */ +{ +int r,c; +for(c=0;c<10;c++) { +//r = qc_sensor_init(qc); +//PDEBUG("c=%i init=%i",c,r); +//r = qc_sensor_setsize(qc, width, height); +//PDEBUG("size=%i",r); +//r = usb_set_interface(qc->dev, qc->iface, 1); +//PDEBUG("set_interf=%i",r); +//r = qc->sensor_data.sensor->start(qc); /* Start current frame */ +//PDEBUG("start=%i",r); +//r = qc_stv_set(qc, STV_ISO_ENABLE, 1); +//PDEBUG("stv_set=%i",r); +//qc_isoc_stop(qc); +//qc_usleep(1000000); +//qc_isoc_start(qc); +//qc_usleep(1000000); +}} +#endif + } + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(%p) in qc_usb_init() : %i",qc, sem_getcount(&qc->lock)); + up(&qc->lock); + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(quickcam_list) in qc_usb_init() : %i", sem_getcount(&quickcam_list_lock)); + up(&quickcam_list_lock); + return qc; + +fail4: video_unregister_device(&qc->vdev); +fail3: if (!reuse_qc) qc_i2c_exit(qc); + qc->dev = NULL; + qc->connected = FALSE; + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(%p) in qc_usb_init()=failed : %i",qc, sem_getcount(&qc->lock)); + up(&qc->lock); +fail2: if (!reuse_qc) kfree(qc); +fail1: if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGERRORS) PDEBUG("failed qc_usb_init()=%i",r); + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(quickcam_list) in qc_usb_init()=failed : %i", sem_getcount(&quickcam_list_lock)); + up(&quickcam_list_lock); + return NULL; +} +/* }}} */ +/* FIXME: can usb_disconnect and usb_probe pre-empt other kernel mode processes? Assume no */ +/* {{{ [fold] qc_usb_probe(...) */ +/* Called when any USB device is connected, check if it is a supported camera */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static int qc_usb_probe(struct usb_interface *interface, const struct usb_device_id *id) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +static void *qc_usb_probe(struct usb_device *usbdev, unsigned int ifacenum, const struct usb_device_id *id) +#else /* 2.2.x */ +static void *qc_usb_probe(struct usb_device *usbdev, unsigned int ifacenum) +#endif +{ + struct quickcam *qc; + struct usb_interface_descriptor *ifacedesc; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + unsigned int ifacenum; + struct usb_device *usbdev = interface_to_usbdev(interface); + static const int ERROR_CODE = -ENODEV; +#else + static void * const ERROR_CODE = NULL; +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + /* Check if the device has a product number that we support */ + struct usb_device_id *i; + for (i=qc_device_table; i->idVendor; i++) { + if (usbdev->descriptor.idVendor == i->idVendor && + usbdev->descriptor.idProduct == i->idProduct) break; + } + if (!i->idVendor) return ERROR_CODE; +#endif + if (PARANOID && usbdev==NULL) { PRINTK(KERN_CRIT,"usbdev==NULL"); return ERROR_CODE; } + + /* We don't handle multi-config cameras */ + if (usbdev->descriptor.bNumConfigurations != 1) return ERROR_CODE; + + /* + * Checking vendor/product is not enough + * In case on QuickCam Web the audio is at class 1 and subclass 1/2. + * one /dev/dsp and one /dev/mixer + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + ifacedesc = &interface->altsetting[0].desc; + ifacenum = ifacedesc->bInterfaceNumber; +#else + ifacedesc = &usbdev->actconfig->interface[ifacenum].altsetting[0]; +#endif + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_usb_probe(usbdev=%p,ifacenum=%i)", usbdev, ifacenum); + if (PARANOID && ifacedesc->bInterfaceNumber!=ifacenum) PRINTK(KERN_CRIT,"bInterfaceNumber(%i)!=ifacenum(%i)!!",ifacedesc->bInterfaceNumber,ifacenum); + if (ifacedesc->bInterfaceClass != 0xFF) return ERROR_CODE; + if (ifacedesc->bInterfaceSubClass != 0xFF) return ERROR_CODE; + + /* We found a QuickCam */ + PRINTK(KERN_INFO,"QuickCam USB camera found (driver version %s)", VERSION); + PRINTK(KERN_INFO,"Kernel:%s bus:%i class:%02X subclass:%02X vendor:%04X product:%04X", + UTS_RELEASE, usbdev->bus->busnum, ifacedesc->bInterfaceClass, ifacedesc->bInterfaceSubClass, + usbdev->descriptor.idVendor, usbdev->descriptor.idProduct); + + /* The interface is claimed (bound) automatically to us when we return from this function (without error code) */ + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("MOD_INC_USE_COUNT in qc_usb_probe() : %i",GET_USE_COUNT(THIS_MODULE)); + MOD_INC_USE_COUNT; /* Increase count to 1, which locks the module--it can't be removed */ + qc = qc_usb_init(usbdev, ifacenum); + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("MOD_DEC_USE_COUNT in qc_usb_probe() : %i",GET_USE_COUNT(THIS_MODULE)); + MOD_DEC_USE_COUNT; /* Release lock: module can be now removed again */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + if (!qc) return ERROR_CODE; + usb_set_intfdata(interface, qc); /* FIXME: why? */ + return 0; +#else + return qc; +#endif +} +/* }}} */ +/* {{{ [fold] qc_usb_exit(struct quickcam *qc) */ +/* Free up resources allocated in qc_usb_init() when not needed anymore + * Note: quickcam_list_lock and qc->lock must be acquired before entering this function! + * qc may not be accessed after this function returns! + */ +static void qc_usb_exit(struct quickcam *qc) +{ + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_usb_exit(qc=%p)",qc); + TEST_BUG_MSG(qc==NULL, "qc==NULL"); + + qc_proc_destroy(qc); + qc_adapt_exit(qc); + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("video_unregister_device(%p)", &qc->vdev); + video_unregister_device(&qc->vdev); + qc_i2c_exit(qc); + list_del(&qc->list); +PDEBUG("poisoning qc in qc_usb_exit"); + POISON(*qc); + kfree(qc); + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_usb_exit() done"); +} +/* }}} */ +/* {{{ [fold] qc_usb_disconnect(...) */ +/* Called when the camera is disconnected. We might not free struct quickcam here, + * because the camera might be in use (open() called). In that case, the freeing is + * postponed to the last close() call. However, all submitted URBs must be unlinked. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static void qc_usb_disconnect(struct usb_interface *interface) +#else +static void qc_usb_disconnect(struct usb_device *usbdev, void *ptr) +#endif +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + struct quickcam *qc = usb_get_intfdata(interface); +#ifdef DEBUG + struct usb_device *usbdev = interface_to_usbdev(interface); +#endif +#else + struct quickcam *qc = (struct quickcam *)ptr; +#endif + + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_usb_disconnect(qc=%p)",qc); + TEST_BUG_MSG(qc==NULL, "qc==NULL in qc_usb_disconnect!"); + TEST_BUG_MSG(qc->dev==NULL || qc->connected==FALSE, "disconnecting disconnected device!!"); + TEST_BUG_MSG(usbdev!=qc->dev, "disconnecting not our device!!"); + + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("MOD_INC_USE_COUNT in qc_usb_disconnect() : %i",GET_USE_COUNT(THIS_MODULE)); + MOD_INC_USE_COUNT; /* Increase count to 1, which locks the module--it can't be removed */ + + /* + * When the camera is unplugged (maybe even when it is capturing), quickcam->connected is set to FALSE. + * All functions called from user mode and all _exit functions must check for this. + */ + qc->connected = FALSE; + + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("down(quickcam_list) in qc_usb_disconnect() : %i", sem_getcount(&quickcam_list_lock)); + down(&quickcam_list_lock); /* Also avoids race condition with open() */ + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("down(%p) in qc_usb_disconnect() : %i", qc, sem_getcount(&qc->lock)); + down(&qc->lock); /* Can not interrupt, we must success */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + usb_set_intfdata(interface, NULL); /* FIXME: why? */ +#endif + if (qc->users <= 0) { + /* Free resources */ + qc_usb_exit(qc); + } else { + /* Can not free resources if device is open: postpone to when it is closed */ + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("Disconnect while device open: postponing cleanup"); + qc_isoc_stop(qc); /* Unlink and free isochronous URBs */ + qc_i2c_wait(qc); /* Wait until there are no more I2C packets on way */ + qc->dev = NULL; /* Must be set to NULL only after interrupts are guaranteed to be disabled! */ + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(%p) in qc_usb_disconnect() : %i",qc, sem_getcount(&qc->lock)); + up(&qc->lock); + } + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(quickcam_list) in qc_usb_disconnect() : %i", sem_getcount(&quickcam_list_lock)); + up(&quickcam_list_lock); + if (qcdebug&QC_DEBUGMUTEX) PDEBUG("MOD_DEC_USE_COUNT in qc_usb_disconnect() : %i",GET_USE_COUNT(THIS_MODULE)); + MOD_DEC_USE_COUNT; /* Release lock--if device is not open, module can be now freed */ + /* The interface is released automatically when we return from this function */ +} +/* }}} */ + +/* }}} */ +/* {{{ [fold] **** qc: Start of module API ******************************* */ + +/* {{{ [fold] qc_init(void) */ +static int __init qc_init(void) +{ + int r; + if (qcdebug) PDEBUG("----------LOADING QUICKCAM MODULE------------"); + if (qcdebug) PDEBUG("struct quickcam size: %i", (int)sizeof(struct quickcam)); + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_init()"); + qc_proc_init(); /* Ignore if procfs entry creation fails */ + r = usb_register(&qc_usb_driver); + if (r<0) qc_proc_exit(); + if (r<0) if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGERRORS) PDEBUG("failed qc_init()=%i",r); + return r; +} +/* }}} */ +/* {{{ [fold] qc_exit(void) */ +static void __exit qc_exit(void) +{ + if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_exit()"); + usb_deregister(&qc_usb_driver); /* Will also call qc_usb_disconnect() if necessary */ + qc_proc_exit(); +} +/* }}} */ + +module_init(qc_init); +module_exit(qc_exit); +/* }}} */ + +/* End of file */ --- linux-2.6.27.orig/ubuntu/qc-usb/quickcam.h +++ linux-2.6.27/ubuntu/qc-usb/quickcam.h @@ -0,0 +1,585 @@ +#ifndef _LINUX_QUICKCAM_H +#define _LINUX_QUICKCAM_H + +/* {{{ [fold] SECTION: common definitions with userspace applications */ +#define QC_LUT_SIZE (3*256) /* Lookup table definition for equalization */ +#define QC_LUT_RED 0 +#define QC_LUT_GREEN 256 +#define QC_LUT_BLUE 512 + +struct qc_userlut { + unsigned int flags; +#define QC_USERLUT_DEFAULT 1 /* If set, change default settings or the current camera otherwise */ +#define QC_USERLUT_ENABLE 2 /* If set, enable user-specified LUT, or otherwise disable it */ +#define QC_USERLUT_VALUES 4 /* Load new (or store old) values into the lookup-table */ + unsigned char lut[QC_LUT_SIZE]; /* Lookup table to set or read */ +}; + +#define VIDEO_PALETTE_BAYER (('q'<<8) | 1) /* Grab video in raw Bayer format */ +#define VIDEO_PALETTE_MJPEG (('q'<<8) | 2) /* Grab video in compressed MJPEG format */ +#define VID_HARDWARE_QCAM_USB (('q'<<8) | 50) /* Device type */ + +/* Private IOCTL calls */ +#define QC_IOCTLBASE 220 /* Don't use same numbers as Philips driver */ +#define VIDIOCQCGDEBUG _IOR ('v',QC_IOCTLBASE+0, int) /* Gets the debug output, bitfield */ +#define VIDIOCQCSDEBUG _IOWR('v',QC_IOCTLBASE+0, int) /* Sets the debug output, bitfield */ +#define VIDIOCQCGKEEPSETTINGS _IOR ('v',QC_IOCTLBASE+1, int) /* Get keep picture settings across one open to another (0-1) */ +#define VIDIOCQCSKEEPSETTINGS _IOWR('v',QC_IOCTLBASE+1, int) /* Set keep picture settings across one open to another (0-1) */ +#define VIDIOCQCGSETTLE _IOR ('v',QC_IOCTLBASE+2, int) /* Get if we let image brightness settle (0-1) */ +#define VIDIOCQCSSETTLE _IOWR('v',QC_IOCTLBASE+2, int) /* Set if we let image brightness settle (0-1) */ +#define VIDIOCQCGSUBSAMPLE _IOR ('v',QC_IOCTLBASE+3, int) /* Gets the speed (0-1) */ +#define VIDIOCQCSSUBSAMPLE _IOWR('v',QC_IOCTLBASE+3, int) /* Sets the speed (0-1) */ +#define VIDIOCQCGCOMPRESS _IOR ('v',QC_IOCTLBASE+4, int) /* Gets the compression mode (0-1) */ +#define VIDIOCQCSCOMPRESS _IOWR('v',QC_IOCTLBASE+4, int) /* Sets the compression mode (0-1) */ +#define VIDIOCQCGFRAMESKIP _IOR ('v',QC_IOCTLBASE+5, int) /* Get frame capture frequency (0-10) */ +#define VIDIOCQCSFRAMESKIP _IOWR('v',QC_IOCTLBASE+5, int) /* Set frame capture frequency (0-10) */ +#define VIDIOCQCGQUALITY _IOR ('v',QC_IOCTLBASE+6, int) /* Gets the interpolation mode (0-2) */ +#define VIDIOCQCSQUALITY _IOWR('v',QC_IOCTLBASE+6, int) /* Sets the interpolation mode (0-2) */ +#define VIDIOCQCGADAPTIVE _IOR ('v',QC_IOCTLBASE+7, int) /* Get automatic adaptive brightness control (0-1) */ +#define VIDIOCQCSADAPTIVE _IOWR('v',QC_IOCTLBASE+7, int) /* Set automatic adaptive brightness control (0-1) */ +#define VIDIOCQCGEQUALIZE _IOR ('v',QC_IOCTLBASE+8, int) /* Get equalize image (0-1) */ +#define VIDIOCQCSEQUALIZE _IOWR('v',QC_IOCTLBASE+8, int) /* Set equalize image (0-1) */ +#define VIDIOCQCGRETRYERRORS _IOR ('v',QC_IOCTLBASE+9, int) /* Get if we retry when capture fails (0-1) */ +#define VIDIOCQCSRETRYERRORS _IOWR('v',QC_IOCTLBASE+9, int) /* Set if we retry when capture fails (0-1) */ +#define VIDIOCQCGCOMPATIBLE _IOR ('v',QC_IOCTLBASE+10,int) /* Get enable workaround for bugs, bitfield */ +#define VIDIOCQCSCOMPATIBLE _IOWR('v',QC_IOCTLBASE+10,int) /* Set enable workaround for bugs, bitfield */ +#define VIDIOCQCGVIDEONR _IOR ('v',QC_IOCTLBASE+11,int) /* Get videodevice number (/dev/videoX) */ +#define VIDIOCQCSVIDEONR _IOWR('v',QC_IOCTLBASE+11,int) /* Set videodevice number (/dev/videoX) */ +#define VIDIOCQCGUSERLUT _IOR ('v',QC_IOCTLBASE+12,struct qc_userlut) /* Get user-specified lookup-table correction */ +#define VIDIOCQCSUSERLUT _IOWR('v',QC_IOCTLBASE+12,struct qc_userlut) /* Set user-specified lookup-table correction */ + +#define VIDIOCQCGSTV _IOWR('v',QC_IOCTLBASE+20,int) /* Read STV chip register */ +#define VIDIOCQCSSTV _IOW ('v',QC_IOCTLBASE+20,int) /* Write STV chip register */ +#define VIDIOCQCGI2C _IOWR('v',QC_IOCTLBASE+21,int) /* Read I2C chip register */ +#define VIDIOCQCSI2C _IOW ('v',QC_IOCTLBASE+21,int) /* Write I2C chip register */ + +/* Debugging message choices */ +#define QC_DEBUGUSER (1<<0) /* Messages for interaction with user space (system calls) */ +#define QC_DEBUGCAMERA (1<<1) /* Messages for interaction with the camera */ +#define QC_DEBUGINIT (1<<2) /* Messages for each submodule initialization/deinit */ +#define QC_DEBUGLOGIC (1<<3) /* Messages for entering and failing important functions */ +#define QC_DEBUGERRORS (1<<4) /* Messages for all error conditions */ +#define QC_DEBUGADAPTATION (1<<5) /* Messages for automatic exposure control workings */ +#define QC_DEBUGCONTROLURBS (1<<6) /* Messages for sending I2C control messages via USB */ +#define QC_DEBUGBITSTREAM (1<<7) /* Messages for finding chunk codes from camera bitstream */ +#define QC_DEBUGINTERRUPTS (1<<8) /* Messages for each interrupt */ +#define QC_DEBUGMUTEX (1<<9) /* Messages for acquiring/releasing the mutex */ +#define QC_DEBUGCOMMON (1<<10) /* Messages for some common warnings */ +#define QC_DEBUGFRAME (1<<11) /* Messages related to producer-consumer in qc_frame_* functions */ +#define QC_DEBUGALL (~0) /* Messages for everything */ + +/* Compatibility choices */ +#define QC_COMPAT_16X (1<<0) +#define QC_COMPAT_DBLBUF (1<<1) +#define QC_COMPAT_TORGB (1<<2) /* Video4Linux API is buggy and doesn't specify byte order for RGB images */ +/* }}} */ + +#ifdef __KERNEL__ + +#include +#include + +#ifdef CONFIG_SMP +#define __SMP__ +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include +#endif +#endif + +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) +#include +#endif +#include +#include /* This is required for testing pte_offset_map */ +#include + +/* {{{ [fold] SECTION: user configuration */ +#define VERSION "QuickCam USB 0.6.6 $Date: 2006/11/04 08:38:14 $" +#ifndef COMPRESS +#define COMPRESS 1 /* 1=include compression support, 0=otherwise */ +#endif +#ifndef DEBUGLEVEL +#define DEBUGLEVEL QC_DEBUGCOMMON +#endif +#ifdef NDEBUG /* Enable debugging if DEBUG is defined; if (also) NDEBUG is defined, disable debugging */ +#undef DEBUG +#endif +//#define DEBUG /* Enable debug code */ +#ifdef DEBUG +#define PARANOID 1 /* Check consistency of driver state */ +#else +#define PARANOID 0 +#endif +/* Default (initial) values */ +#define DEFAULT_BGR TRUE /* Use BGR byte order by default (and torgb converts to RGB)? */ + +#define DUMPDATA 0 /* Dump data from camera to user, no conversion nor length checks (see show.c) */ +/* }}} */ +/* {{{ [fold] SECTION: general utility definitions and macros */ +#define FALSE 0 +#define TRUE (!FALSE) +typedef unsigned char Bool; +//#define BIT(x) (1<<(x)) +#define SIZE(a) (sizeof(a)/sizeof((a)[0])) +#define MAX(a,b) ((a)>(b)?(a):(b)) +#define MIN(a,b) ((a)<(b)?(a):(b)) +#define MAX3(a,b,c) (MAX(a,MAX(b,c))) +#define MIN3(a,b,c) (MIN(a,MIN(b,c))) +#define CLIP(a,low,high) MAX((low),MIN((high),(a))) +#define ABS(a) ((a)>0?(a):-(a)) +#define SGN(a) ((a)<0 ? -1 : ((a)>0 ? 1 : 0)) +#define CHECK_ERROR(cond,jump,msg,args...) if (cond) { PDEBUG(msg, ## args); goto jump; } +#define GET_VENDORID(qc) ((qc)->dev->descriptor.idVendor) +#define GET_PRODUCTID(qc) ((qc)->dev->descriptor.idProduct) +/* }}} */ +/* {{{ [fold] SECTION: compatibility */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) +#error "Too old kernel. At least Linux 2.2.18 is required." +#endif + +#if LINUX_VERSION_CODE==KERNEL_VERSION(2,4,19) || LINUX_VERSION_CODE==KERNEL_VERSION(2,4,20) +#warning "Kernels 2.4.19 and 2.4.20 are buggy! Be sure to install patch from:" +#warning "http://www.ee.oulu.fi/~tuukkat/quickcam/linux-2.4.20-videodevfix.patch" +#endif + +#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,5,0) && LINUX_VERSION_CODE=KERNEL_VERSION(2,7,0) +#warning "Unsupported kernel, may or may not work. Good luck!" +#endif + +#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,4,0) && defined(CONFIG_PROC_FS) +#define HAVE_PROCFS 1 /* FIXME: I don't think there's any reason to disable procfs with 2.2.x */ +#else +#define HAVE_PROCFS 0 +#warning "procfs support disabled" +#endif + +#ifndef HAVE_VMA +#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,5,3) || (defined(RED_HAT_LINUX_KERNEL) && defined(pte_offset_map)) +/* Some RedHat 9 2.4.x patched-to-death kernels need this too */ +#define HAVE_VMA 1 +#else +#define HAVE_VMA 0 +#endif +#endif + +#if HAVE_VMA && LINUX_VERSION_CODE=KERNEL_VERSION(2,6,0) +/* Things come and go... */ +/* Used only for debugging, so this could be actually removed if needed */ +#define sem_getcount(sem) atomic_read(&(sem)->count) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +static inline int qc_usb_submit_urb(struct urb *urb) { return usb_submit_urb(urb); } +static inline struct urb *qc_usb_alloc_urb(int packets) { return usb_alloc_urb(packets); } +#undef usb_submit_urb +#undef usb_alloc_urb +#define usb_submit_urb(u,f) qc_usb_submit_urb(u) +#define usb_alloc_urb(u,f) qc_usb_alloc_urb(u) +#define URB_ISO_ASAP USB_ISO_ASAP +#endif + +#ifndef list_for_each_entry +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +#undef MOD_INC_USE_COUNT +#undef MOD_DEC_USE_COUNT +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#define GET_USE_COUNT(module) 1 +#define EXPORT_NO_SYMBOLS +#endif + +/* }}} */ +/* {{{ [fold] SECTION: debugging */ +#undef PDEBUG /* undef it, just in case */ +#define POISON_VAL 0x5B + +#ifdef DEBUG + +#include +/* PDEBUG is rather heavyweight macro and should be used only for debugging--not for general messages */ +/* Based on timestamp by Roger Wolff */ +#define PDEBUG(fmt, args...) \ + do { \ + struct timeval __tv_val; \ + do_gettimeofday(&__tv_val); \ + printk(KERN_DEBUG "quickcam [%2ld.%06ld]: ", __tv_val.tv_sec%60, __tv_val.tv_usec); \ + printk(fmt, ## args); \ + printk("\n"); \ + } while(0) +#define IDEBUG_VAR char *idebug_var; +#define IDEBUG_INIT(x) do { \ + if ((x).idebug_var==((char*)&((x).idebug_var)) + 0xB967E57D) printk(KERN_CRIT __FILE__ ":%i: Init already done\n",__LINE__); \ + (x).idebug_var = ((char*)&((x).idebug_var)) + 0xB967E57D; \ +} while(0) +#define IDEBUG_TEST(x) do { \ + if ((x).idebug_var!=((char*)&((x).idebug_var)) + 0xB967E57D) printk(KERN_CRIT __FILE__ ":%i: Init missing\n",__LINE__); \ +} while(0) +#define IDEBUG_EXIT(x) do { \ + IDEBUG_TEST(x); \ + (x).idebug_var = NULL; \ + POISON(x); \ +} while(0) +#define IDEBUG_EXIT_NOPOISON(x) do { \ + IDEBUG_TEST(x); \ + (x).idebug_var = NULL; \ +} while(0) +#define TEST_BUG(condition) \ + do { \ + if ((condition)!=0) { \ + PDEBUG("Badness in %s at %s:%d", __FUNCTION__, __FILE__, __LINE__); \ + return; \ + } \ + } while (0) +#define TEST_BUGR(condition) \ + do { \ + if ((condition)!=0) { \ + PDEBUG("Badness in %s at %s:%d", __FUNCTION__, __FILE__, __LINE__); \ + return -EFAULT; \ + } \ + } while (0) +#define TEST_BUG_MSG(cond, fmt, args...) \ + do { \ + if ((cond)!=0) { \ + PDEBUG(fmt, ## args); \ + PDEBUG("Badness in %s at %s:%d", __FUNCTION__, __FILE__, __LINE__); \ + return; \ + } \ + } while (0) +#define TEST_BUGR_MSG(cond, fmt, args...) \ + do { \ + if ((cond)!=0) { \ + PDEBUG(fmt, ## args); \ + PDEBUG("Badness in %s at %s:%d", __FUNCTION__, __FILE__, __LINE__); \ + return -EFAULT; \ + } \ + } while (0) +#define POISON(obj) do { memset(&(obj),POISON_VAL,sizeof(obj)); } while(0) + +#else + +#define PDEBUG(fmt, args...) +#define IDEBUG_VAR +#define IDEBUG_INIT(x) +#define IDEBUG_TEST(x) +#define IDEBUG_EXIT(x) +#define IDEBUG_EXIT_NOPOISON(x) +#define TEST_BUG(x) +#define TEST_BUGR(x) +#define TEST_BUG_MSG(cond, fmt, args...) +#define TEST_BUGR_MSG(cond, fmt, args...) +#define POISON(obj) + +#endif /* DEBUG */ + +//gcc is buggy? This doesn't work +//#define PRINTK(lvl, fmt, args...) printk(lvl "quickcam: " fmt "\n", ## args) +#define PRINTK(lvl, fmt, args...) do { printk(lvl "quickcam: " fmt, ## args); printk("\n"); } while (0) +/* }}} */ +/* {{{ [fold] SECTION: hardware related stuff */ +#define QUICKCAM_ISOPIPE 0x81 + +/* Control register of the STV0600 ASIC */ +#define STV_ISO_ENABLE 0x1440 +#define STV_SCAN_RATE 0x1443 +#define STV_ISO_SIZE 0x15C1 +#define STV_Y_CTRL 0x15C3 +#define STV_X_CTRL 0x1680 +#define STV_REG00 0x1500 +#define STV_REG01 0x1501 +#define STV_REG02 0x1502 +#define STV_REG03 0x1503 +#define STV_REG04 0x1504 +#define STV_REG23 0x0423 + +/* Maximum frame size that any sensor can deliver */ +#define MAX_FRAME_WIDTH 360 +#define MAX_FRAME_HEIGHT 296 +/* }}} */ +/* {{{ [fold] SECTION: struct quickcam datatype and related values */ + +/* {{{ [fold] qc_sensor_data: Sensor related data (unique to each camera) */ +struct qc_sensor_data { + const struct qc_sensor *sensor; /* Autodetected when camera is plugged in */ + int maxwidth; /* Maximum size the sensor can deliver */ + int maxheight; + int width; /* Size delivered by the sensor (-1=unknown) */ + int height; + int exposure; /* Current exposure in effect (sensor-specific value, -1=unknown) */ + int rgain, ggain, bgain; /* Current gains in effect (sensor-specific values, -1=unknown) */ + unsigned int subsample : 1; /* Set into subsampling mode? */ + unsigned int compress : 1; /* Set into compressed mode? */ +}; +/* }}} */ +/* {{{ [fold] qc_i2c_data: I2C command queue for writing commands to camera */ +#define I2C_MAXCOMMANDS 16 /* Should be about 1-2 times the size of transfer buffer (=16) for maximum performance */ +#define I2C_FLAG_WORD BIT(0) /* Set if a 16-bit value is sent, otherwise 8-bit value */ +#define I2C_FLAG_BREAK BIT(1) /* Set if this is the last command in a packet */ +struct qc_i2c_data { + struct urb *urb; + struct { + u8 loval; + u8 hival; + u8 regnum; + u8 flags; + } commands[I2C_MAXCOMMANDS]; + /* 2=URB scheduled, need to schedule extra packet for QuickCam Web at completion */ + volatile int packets; /* 0=no URBs scheduled, 1=URB scheduled */ + volatile unsigned int newhead; /* Points to first free buffer position */ + volatile unsigned int head; /* Points to oldest command which was not yet flushed */ + volatile unsigned int tail; /* Points to next position which needs to be send, modified from interrupt */ + wait_queue_head_t wq; /* Woken up when all pending data is sent */ + IDEBUG_VAR +}; +/* }}} */ +/* {{{ [fold] qc_isoc_data: Isochronous transfer queue control data for reading from camera */ +#define ISOC_URBS 2 /* Number of URBs to use */ +#define ISOC_PACKETS 10 /* How many isochronous data packets per URB */ +#define ISOC_PACKET_SIZE 1023 /* Max size of one packet (shouldn't be hardcoded JFC was 960) */ +struct qc_isoc_data { + struct urb *urbs[ISOC_URBS]; + unsigned char *buffer; /* Isochronous data transfer buffers */ + int errorcount; + Bool streaming; /* TRUE if URBs are allocated and submitted */ + IDEBUG_VAR +}; +/* }}} */ +/* {{{ [fold] qc_stream_data: Camera data stream control data */ +struct qc_stream_data { + Bool capturing; /* Are we capturing data for a frame? */ + int frameskip; /* How frequently to capture frames? 0=each frame, 1=every other */ + IDEBUG_VAR +}; +/* }}} */ +/* {{{ [fold] qc_frame_data: Raw frame (bayer/mjpeg) buffers */ +#define FRAME_BUFFERS 2 /* We are double buffering */ +#define FRAME_DATASIZE (MAX_FRAME_WIDTH*MAX_FRAME_HEIGHT) /* About 101 kilobytes (assume that compressed frame is always smaller) */ +struct qc_frame_data { + struct { + int rawdatalen; /* Number of used bytes of this frame buffer */ + } buffers[FRAME_BUFFERS]; + unsigned char *rawdatabuf; /* vmalloc'd chunk containing the all raw frame data buffers concatenated */ + int maxrawdatalen; /* Maximum amount of data we are willing to accept in bytes, */ + /* zero indicates that we are not grabbing current frame (but just throwing data away) */ + volatile unsigned int head; /* The buffer to be captured next (empty or grabbing, if full, then whole buffer is full) */ + volatile unsigned int tail; /* The buffer to be consumed next (full, unless equals head, then it is empty/grabbing) */ + spinlock_t tail_lock; /* Protects tail changes */ + volatile Bool tail_in_use; /* TRUE, when consumer is processing the frame pointed to by tail */ + + wait_queue_head_t wq; /* Processes waiting for more data in the buffer */ + volatile int waiting; /* Number of processes waiting in the wait queues */ + volatile Bool exiting; /* Set to TRUE when we want to quit */ + volatile int lost_frames; /* Increased by one for every lost (non-captured by applications) frame, reset when a frame is captured */ + IDEBUG_VAR +}; +/* }}} */ +/* {{{ [fold] qc_mjpeg_data: MJPEG decoding data */ +struct qc_mjpeg_data { + int depth; /* Bits per pixel in the final RGB image: 16 or 24 */ + u8 *encV; /* Temporary buffers for holding YUV image data */ + u8 *encU; + u8 *encY; + /* yuv2rgb private data */ + void *table; + void *table_rV[256]; + void *table_gU[256]; + int table_gV[256]; + void *table_bU[256]; + void (*yuv2rgb_func)(struct qc_mjpeg_data *, u8 *, u8 *, u8 *, u8 *, void *, void *, int); + IDEBUG_VAR +}; +/* }}} */ +/* {{{ [fold] qc_fmt_data: Format conversion routines private data */ +struct qc_fmt_data { + unsigned char userlut[QC_LUT_SIZE]; /* User specified fixed look-up table, initialized when camera is plugged in */ + unsigned char lut[QC_LUT_SIZE]; /* Dynamically calculated LUT, for which userlut is applied to */ +#if COMPRESS + struct qc_mjpeg_data mjpeg_data; + Bool compress; /* Was compression subsystem initialized? */ +#endif + IDEBUG_VAR +}; +/* }}} */ +/* {{{ [fold] qc_capt_data: Formatted image capturing control data */ +/* qc_capt_data: Formatted image capturing control data. */ +#define MAX_FRAME_SIZE (MAX_FRAME_WIDTH*MAX_FRAME_HEIGHT*4) /* Video Size 356x292x4 bytes for 0RGB 32 bpp mode */ +struct qc_capt_data { + unsigned char *frame; /* Final image data buffer given to application, size MAX_FRAME_SIZE (mmappable) */ + Bool settled; /* Has the picture settled after last open? */ + IDEBUG_VAR +}; +/* }}} */ +/* {{{ [fold] qc_adapt_data: Automatic exposure control data */ +/* There are three different exposure control algorithms for different cases */ +struct qc_adapt_data { + int olddelta; + int oldmidvalue, midvaluesum; + int oldexposure, exposure; + int gain; + int framecounter; + enum { + EXPCONTROL_SATURATED, /* Picture is over/undersaturated, halve/double brightness */ + EXPCONTROL_NEWTON, /* Using Newton linear estimation */ + EXPCONTROL_FLOAT, /* Very near correct brightness, float exposure slightly */ + } controlalg; + IDEBUG_VAR +}; +/* }}} */ +/* {{{ [fold] qc_settings_data: User settings given by qcset or module parameters, initialized when camera is plugged in */ +struct qc_settings_data { + unsigned int keepsettings : 1; /* Keep all settings at each camera open (or reset most of them) */ + unsigned int subsample : 1; /* Normal or sub-sample (sub-sample to increase the speed) */ + unsigned int compress : 1; /* Enable compressed mode if available (higher framerate) */ + unsigned int frameskip : 4; /* How many frames to skip (higher=lower framerate) */ + unsigned int quality : 3; /* Quality of format conversion (higher=better but slower) */ + unsigned int adaptive : 1; /* Use automatic exposure control */ + unsigned int equalize : 1; /* Equalize images */ + unsigned int userlut : 1; /* Apply user-specified lookup-table */ + unsigned int retryerrors : 1; /* If errors happen when capturing an image, retry a few times? */ + unsigned int compat_16x : 1; /* Compatibility: force image size to multiple of 16 */ + unsigned int compat_dblbuf : 1; /* Compatibility: fake doublebuffering for applications */ + unsigned int compat_torgb : 1; /* Compatibility: use RGB data order, not BGR */ + unsigned int settle : 8; /* Maximum number of frames to wait image brightness to settle */ + /* Total: 25 bits */ +}; +/* }}} */ + +/* Main per-camera data structure, most important thing in whole driver */ +struct quickcam { + /* The following entries are initialized in qc_usb_init() when camera is plugged in */ + struct semaphore lock; /* Allow only one process to access quickcam at a time */ + struct list_head list; /* All cameras are in a doubly linked list */ + int users; /* User count (simultaneous open count) */ + struct usb_device *dev; /* USB device, set to NULL when camera disconnected and interrupts disabled */ + unsigned char iface; /* The interface number in the camera device we are bound to */ + Bool connected; /* Set to FALSE immediately when the camera is disconnected (even before interrupts are disabled) */ + struct video_device vdev; /* Used for registering the camera driver for Video4Linux */ + struct qc_settings_data settings; /* General user settings set with e.g. qcset */ +#if HAVE_PROCFS + struct proc_dir_entry *proc_entry; +#endif + /* The following entries are initialized in qc_v4l_init() when the camera device is opened */ + struct video_picture vpic; /* Contains the last values set by user (which is reported to user) */ + Bool vpic_pending; /* Settings in vpic were changed but are not yet in effect */ + struct video_window vwin; /* Contains the image size and position the user is expecting */ + + /* Private structures for each module, initialized in corresponding init-function */ + struct qc_i2c_data i2c_data; /* Filled when the camera is plugged in or driver loaded */ + struct qc_adapt_data adapt_data; /* Filled when the camera is plugged in or driver loaded */ + struct qc_sensor_data sensor_data; /* Mostly filled when the device is opened */ + struct qc_stream_data stream_data; /* Filled when the device is opened */ + struct qc_frame_data frame_data; /* Filled when the device is opened */ + struct qc_capt_data capt_data; /* Filled when the device is opened */ + struct qc_isoc_data isoc_data; /* Filled when the device is opened */ + struct qc_fmt_data fmt_data; /* Mostly filled when the device is opened, except for userlut */ + + u8 dmabuf[35]; /* Temporary buffer which may be used for DMA transfer */ +}; +/* }}} */ +/* {{{ [fold] SECTION: miscelleneous */ +/* Constant information related to a sensor type */ +struct qc_sensor { + char *name; + char *manufacturer; + int (*init)(struct quickcam *qc); /* Initialize sensor */ + int (*start)(struct quickcam *qc); /* Start sending image data */ + int (*stop)(struct quickcam *qc); /* Stop sending image data */ + int (*set_size)(struct quickcam *qc, unsigned int w, unsigned int h); /* Request camera to send the given image size */ + /* Set primary brightness value exp (usually exposure time) and HSV 0-65535 (usually gains) */ + int (*set_levels)(struct quickcam *qc, unsigned int exp, unsigned int gain, unsigned int hue, unsigned int sat); + int (*set_target)(struct quickcam *qc, unsigned int val); /* Set target brightness for sensor autoexposure 0-65535 */ + /* Exposure and gain control information */ + Bool autoexposure; /* Sensor has automatic exposure control */ + int adapt_gainlow; /* (0-65535) How eagerly to decrease gain when necessary */ + int adapt_gainhigh; /* (0-65535) How eagerly to increase gain when necessary */ + /* Information needed to access the sensor via I2C */ + int reg23; + unsigned char i2c_addr; + /* Identification information used for auto-detection */ + int id_reg; + unsigned char id; + int length_id; + int flag; /* May be used by sensor driver for private purposes */ +}; +/* }}} */ +/* {{{ [fold] SECTION: function prototypes */ +/* USB interface chip control */ +int qc_i2c_break(struct quickcam *qc); +int qc_i2c_wait(struct quickcam *qc); +int qc_i2c_set(struct quickcam *qc, unsigned char reg, unsigned char val); +int qc_i2c_setw(struct quickcam *qc, unsigned char reg, unsigned short val); + +int qc_stv_set(struct quickcam *qc, unsigned short reg, unsigned char val); +int qc_stv_setw(struct quickcam *qc, unsigned short reg, unsigned short val); +int qc_stv_get(struct quickcam *qc, unsigned short reg); + +/* Image format conversion routines */ +int qc_fmt_convert(struct quickcam *qc, unsigned char *src, unsigned int src_len, unsigned char *dst, unsigned int dst_len, int *midvalue); +int qc_fmt_issupported(int format); +const char *qc_fmt_getname(int format); +int qc_fmt_getdepth(int format); +int qc_fmt_init(struct quickcam *qc); +void qc_fmt_exit(struct quickcam *qc); + +int qc_mjpeg_decode(struct qc_mjpeg_data *md, unsigned char *src, int src_len, unsigned char *dst); +int qc_mjpeg_init(struct qc_mjpeg_data *md, int depth, Bool tobgr); +void qc_mjpeg_exit(struct qc_mjpeg_data *md); + +void qc_hsv2rgb(s16 hue, u16 sat, u16 val, int *red, int *green, int *blue); +int qc_get_i2c(struct quickcam *qc, const struct qc_sensor *sensor, int reg); +void qc_frame_flush(struct quickcam *qc); + +void qc_usleep(unsigned long usec); +extern int qcdebug; /* Driver debuglevel */ +/* }}} */ + +#endif /* __KERNEL__ */ + +#endif /* __LINUX_QUICKCAM_H */ --- linux-2.6.27.orig/ubuntu/qc-usb/qc-formats.c +++ linux-2.6.27/ubuntu/qc-usb/qc-formats.c @@ -0,0 +1,1545 @@ +/* Start of file */ + +/* {{{ [fold] Comments */ +/* + * qc-usb, linux V4L driver for the Logitech QuickCam family + * + * qc-formats.c - converts color formats + * + * Copyright (c) 2001 Jean-Frederic Clere (RGB->YUV conversion) + * 2001 Aaron Holtzman (YUV->RGB conversion, from mpeg2dec) + * 2003 Tuukka Toivonen (Bayer->RGB conversion) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +/* }}} */ + +#include "quickcam.h" +#include + +#ifndef v4l2_fourcc +/* Four-character-code (FOURCC) */ +#define v4l2_fourcc(a,b,c,d)\ + (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24)) +#endif + +/* {{{ [fold] **** qc_yuv: Start of RGB to YUV conversion functions ******************** */ + +/* {{{ [fold] qc_yuv_interp[256][8] */ +static signed short qc_yuv_interp[256][8] = { +{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0},{0,1,0,0,0,1,0,0},{0,1,0,0,0,1,-1,0}, +{1,2,0,0,-1,2,-1,0},{1,2,0,0,-1,2,-2,0},{1,3,0,-1,-1,3,-2,0},{2,3,0,-1,-2,3,-2,0}, +{2,4,0,-1,-2,4,-3,0},{2,5,1,-1,-2,4,-3,0},{2,5,1,-1,-3,5,-4,0},{3,6,1,-1,-3,5,-4,0}, +{3,6,1,-2,-3,6,-5,0},{3,7,1,-2,-4,6,-5,-1},{4,7,1,-2,-4,7,-5,-1},{4,8,1,-2,-4,7,-6,-1}, +{4,9,1,-2,-5,8,-6,-1},{5,9,1,-2,-5,8,-7,-1},{5,10,2,-3,-5,9,-7,-1},{5,10,2,-3,-6,9,-7,-1}, +{5,11,2,-3,-6,10,-8,-1},{6,11,2,-3,-6,10,-8,-1},{6,12,2,-3,-7,11,-9,-1},{6,13,2,-3,-7,11,-9,-1}, +{7,13,2,-4,-7,12,-10,-1},{7,14,2,-4,-8,12,-10,-2},{7,14,2,-4,-8,13,-10,-2},{8,15,3,-4,-8,13,-11,-2}, +{8,15,3,-4,-9,14,-11,-2},{8,16,3,-4,-9,14,-12,-2},{8,17,3,-5,-9,15,-12,-2},{9,17,3,-5,-10,15,-12,-2}, +{9,18,3,-5,-10,16,-13,-2},{9,18,3,-5,-10,16,-13,-2},{10,19,3,-5,-11,17,-14,-2},{10,19,3,-5,-11,17,-14,-2}, +{10,20,4,-6,-11,18,-15,-2},{11,20,4,-6,-12,18,-15,-3},{11,21,4,-6,-12,19,-15,-3},{11,22,4,-6,-12,19,-16,-3}, +{11,22,4,-6,-13,20,-16,-3},{12,23,4,-6,-13,20,-17,-3},{12,23,4,-7,-13,21,-17,-3},{12,24,4,-7,-14,21,-18,-3}, +{13,24,5,-7,-14,22,-18,-3},{13,25,5,-7,-14,22,-18,-3},{13,26,5,-7,-15,23,-19,-3},{14,26,5,-7,-15,23,-19,-3}, +{14,27,5,-8,-15,24,-20,-3},{14,27,5,-8,-16,24,-20,-3},{14,28,5,-8,-16,25,-20,-4},{15,28,5,-8,-16,25,-21,-4}, +{15,29,5,-8,-17,26,-21,-4},{15,30,6,-8,-17,26,-22,-4},{16,30,6,-9,-17,27,-22,-4},{16,31,6,-9,-18,27,-23,-4}, +{16,31,6,-9,-18,28,-23,-4},{17,32,6,-9,-18,28,-23,-4},{17,32,6,-9,-19,29,-24,-4},{17,33,6,-9,-19,29,-24,-4}, +{17,34,6,-10,-19,30,-25,-4},{18,34,6,-10,-20,30,-25,-4},{18,35,7,-10,-20,31,-25,-5},{18,35,7,-10,-20,31,-26,-5}, +{19,36,7,-10,-21,32,-26,-5},{19,36,7,-10,-21,32,-27,-5},{19,37,7,-11,-21,33,-27,-5},{20,37,7,-11,-22,33,-28,-5}, +{20,38,7,-11,-22,34,-28,-5},{20,39,7,-11,-22,34,-28,-5},{20,39,7,-11,-23,35,-29,-5},{21,40,8,-11,-23,35,-29,-5}, +{21,40,8,-12,-23,36,-30,-5},{21,41,8,-12,-24,36,-30,-5},{22,41,8,-12,-24,37,-30,-6},{22,42,8,-12,-24,37,-31,-6}, +{22,43,8,-12,-25,38,-31,-6},{23,43,8,-12,-25,38,-32,-6},{23,44,8,-13,-25,39,-32,-6},{23,44,9,-13,-26,39,-33,-6}, +{23,45,9,-13,-26,40,-33,-6},{24,45,9,-13,-26,40,-33,-6},{24,46,9,-13,-27,41,-34,-6},{24,47,9,-14,-27,41,-34,-6}, +{25,47,9,-14,-27,42,-35,-6},{25,48,9,-14,-28,42,-35,-6},{25,48,9,-14,-28,43,-36,-6},{26,49,9,-14,-28,43,-36,-7}, +{26,49,10,-14,-29,44,-36,-7},{26,50,10,-15,-29,44,-37,-7},{26,51,10,-15,-29,45,-37,-7},{27,51,10,-15,-30,45,-38,-7}, +{27,52,10,-15,-30,46,-38,-7},{27,52,10,-15,-30,46,-38,-7},{28,53,10,-15,-31,47,-39,-7},{28,53,10,-16,-31,47,-39,-7}, +{28,54,10,-16,-31,48,-40,-7},{29,54,11,-16,-32,48,-40,-7},{29,55,11,-16,-32,49,-41,-7},{29,56,11,-16,-32,49,-41,-8}, +{29,56,11,-16,-33,50,-41,-8},{30,57,11,-17,-33,50,-42,-8},{30,57,11,-17,-33,51,-42,-8},{30,58,11,-17,-34,51,-43,-8}, +{31,58,11,-17,-34,52,-43,-8},{31,59,11,-17,-34,52,-43,-8},{31,60,12,-17,-35,53,-44,-8},{31,60,12,-18,-35,53,-44,-8}, +{32,61,12,-18,-35,54,-45,-8},{32,61,12,-18,-36,54,-45,-8},{32,62,12,-18,-36,55,-46,-8},{33,62,12,-18,-36,55,-46,-9}, +{33,63,12,-18,-37,56,-46,-9},{33,64,12,-19,-37,56,-47,-9},{34,64,12,-19,-37,57,-47,-9},{34,65,13,-19,-38,57,-48,-9}, +{34,65,13,-19,-38,58,-48,-9},{34,66,13,-19,-38,58,-48,-9},{35,66,13,-19,-39,59,-49,-9},{35,67,13,-20,-39,59,-49,-9}, +{35,68,13,-20,-39,60,-50,-9},{36,68,13,-20,-40,60,-50,-9},{36,69,13,-20,-40,61,-51,-9},{36,69,14,-20,-40,61,-51,-9}, +{37,70,14,-20,-41,62,-51,-10},{37,70,14,-21,-41,62,-52,-10},{37,71,14,-21,-41,63,-52,-10},{37,72,14,-21,-42,63,-53,-10}, +{38,72,14,-21,-42,64,-53,-10},{38,73,14,-21,-42,64,-54,-10},{38,73,14,-21,-43,65,-54,-10},{39,74,14,-22,-43,65,-54,-10}, +{39,74,15,-22,-43,66,-55,-10},{39,75,15,-22,-44,66,-55,-10},{40,75,15,-22,-44,67,-56,-10},{40,76,15,-22,-44,67,-56,-10}, +{40,77,15,-22,-45,68,-56,-11},{40,77,15,-23,-45,68,-57,-11},{41,78,15,-23,-45,69,-57,-11},{41,78,15,-23,-46,69,-58,-11}, +{41,79,15,-23,-46,70,-58,-11},{42,79,16,-23,-46,70,-59,-11},{42,80,16,-23,-47,71,-59,-11},{42,81,16,-24,-47,71,-59,-11}, +{43,81,16,-24,-47,72,-60,-11},{43,82,16,-24,-48,72,-60,-11},{43,82,16,-24,-48,73,-61,-11},{43,83,16,-24,-48,73,-61,-11}, +{44,83,16,-24,-49,74,-61,-12},{44,84,16,-25,-49,74,-62,-12},{44,85,17,-25,-49,75,-62,-12},{45,85,17,-25,-50,75,-63,-12}, +{45,86,17,-25,-50,76,-63,-12},{45,86,17,-25,-50,76,-64,-12},{46,87,17,-25,-51,77,-64,-12},{46,87,17,-26,-51,77,-64,-12}, +{46,88,17,-26,-51,78,-65,-12},{46,89,17,-26,-52,78,-65,-12},{47,89,18,-26,-52,79,-66,-12},{47,90,18,-26,-52,79,-66,-12}, +{47,90,18,-26,-53,80,-66,-13},{48,91,18,-27,-53,80,-67,-13},{48,91,18,-27,-53,81,-67,-13},{48,92,18,-27,-54,81,-68,-13}, +{49,92,18,-27,-54,82,-68,-13},{49,93,18,-27,-54,82,-69,-13},{49,94,18,-28,-54,83,-69,-13},{49,94,19,-28,-55,83,-69,-13}, +{50,95,19,-28,-55,84,-70,-13},{50,95,19,-28,-55,84,-70,-13},{50,96,19,-28,-56,85,-71,-13},{51,96,19,-28,-56,85,-71,-13}, +{51,97,19,-29,-56,86,-72,-13},{51,98,19,-29,-57,86,-72,-14},{52,98,19,-29,-57,87,-72,-14},{52,99,19,-29,-57,87,-73,-14}, +{52,99,20,-29,-58,88,-73,-14},{52,100,20,-29,-58,88,-74,-14},{53,100,20,-30,-58,89,-74,-14},{53,101,20,-30,-59,89,-74,-14}, +{53,102,20,-30,-59,90,-75,-14},{54,102,20,-30,-59,90,-75,-14},{54,103,20,-30,-60,91,-76,-14},{54,103,20,-30,-60,91,-76,-14}, +{55,104,20,-31,-60,92,-77,-14},{55,104,21,-31,-61,92,-77,-15},{55,105,21,-31,-61,93,-77,-15},{55,106,21,-31,-61,93,-78,-15}, +{56,106,21,-31,-62,94,-78,-15},{56,107,21,-31,-62,94,-79,-15},{56,107,21,-32,-62,95,-79,-15},{57,108,21,-32,-63,95,-79,-15}, +{57,108,21,-32,-63,96,-80,-15},{57,109,22,-32,-63,96,-80,-15},{58,109,22,-32,-64,97,-81,-15},{58,110,22,-32,-64,97,-81,-15}, +{58,111,22,-33,-64,98,-82,-15},{58,111,22,-33,-65,98,-82,-16},{59,112,22,-33,-65,99,-82,-16},{59,112,22,-33,-65,99,-83,-16}, +{59,113,22,-33,-66,100,-83,-16},{60,113,22,-33,-66,100,-84,-16},{60,114,23,-34,-66,101,-84,-16},{60,115,23,-34,-67,101,-84,-16}, +{60,115,23,-34,-67,102,-85,-16},{61,116,23,-34,-67,102,-85,-16},{61,116,23,-34,-68,103,-86,-16},{61,117,23,-34,-68,103,-86,-16}, +{62,117,23,-35,-68,104,-87,-16},{62,118,23,-35,-69,104,-87,-16},{62,119,23,-35,-69,105,-87,-17},{63,119,24,-35,-69,105,-88,-17}, +{63,120,24,-35,-70,106,-88,-17},{63,120,24,-35,-70,106,-89,-17},{63,121,24,-36,-70,107,-89,-17},{64,121,24,-36,-71,107,-90,-17}, +{64,122,24,-36,-71,108,-90,-17},{64,123,24,-36,-71,108,-90,-17},{65,123,24,-36,-72,109,-91,-17},{65,124,24,-36,-72,109,-91,-17}, +{65,124,25,-37,-72,110,-92,-17},{66,125,25,-37,-73,110,-92,-17},{66,125,25,-37,-73,111,-92,-18},{66,126,25,-37,-73,111,-93,-18}, +{66,127,25,-37,-74,112,-93,-18},{67,127,25,-37,-74,112,-94,-18},{67,128,25,-38,-74,113,-94,-18},{67,128,25,-38,-75,113,-95,-18}, +{68,129,25,-38,-75,114,-95,-18},{68,129,26,-38,-75,114,-95,-18},{68,130,26,-38,-76,115,-96,-18},{69,130,26,-38,-76,115,-96,-18}, +{69,131,26,-39,-76,116,-97,-18},{69,132,26,-39,-77,116,-97,-18},{69,132,26,-39,-77,117,-97,-19},{70,133,26,-39,-77,117,-98,-19}, +{70,133,26,-39,-78,118,-98,-19},{70,134,27,-39,-78,118,-99,-19},{71,134,27,-40,-78,119,-99,-19},{71,135,27,-40,-79,119,-100,-19}, +{71,136,27,-40,-79,120,-100,-19},{72,136,27,-40,-79,120,-100,-19},{72,137,27,-40,-80,121,-101,-19},{72,137,27,-40,-80,121,-101,-19}, +{72,138,27,-41,-80,122,-102,-19},{73,138,27,-41,-81,122,-102,-19},{73,139,28,-41,-81,123,-103,-19},{73,140,28,-41,-81,123,-103,-20}, +{74,140,28,-41,-82,124,-103,-20},{74,141,28,-42,-82,124,-104,-20},{74,141,28,-42,-82,125,-104,-20},{75,142,28,-42,-83,125,-105,-20}, +{75,142,28,-42,-83,126,-105,-20},{75,143,28,-42,-83,126,-105,-20},{75,144,28,-42,-84,127,-106,-20},{76,144,29,-43,-84,127,-106,-20}}; +/* }}} */ + +/* {{{ [fold] qc_yuv_toplanar(unsigned char *rgb24frame, int length, int format) */ +/* + * Convert to planar formats + * The input is an YCbYCr format. + * Input: len : 2/3 maxi. + * | YUYV | free | + * | 2/3 | 1/3 | + * 1th conversion: + * | YY | free | U|V | + * | 1/3 | 1/3 | 1/3 | + * 2d conversion: + * | YY | U | V | free | + * | 1/3 | 1/6|1/6 | 1/3 | + * That the Y422P conversion. + */ +static int qc_yuv_toplanar(unsigned char *rgb24frame, int length, int format) +{ + unsigned char *ptr; + int n = 0, l = 0, i; + unsigned char *cr; + unsigned char *cb; + unsigned char *crptr, *cbptr; + int mode = 0; + + l = length/2; + switch(format) { + case VIDEO_PALETTE_YUV411P: + n = length/8; + mode = 1; + break; + case VIDEO_PALETTE_YUV422P: + n = length/4; + break; + } + + ptr = rgb24frame; + crptr = &rgb24frame[length]; + cr = crptr; + cbptr = &rgb24frame[length+n]; + cb = cbptr; + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_yuv_toplanar: %d (%d + 2 * %d)",length, l, n); + + /* separate Y , U and V */ + for (i=0; iscanlength = length/2+ (2 * n); + return length; +} +/* }}} */ +/* {{{ [fold] qc_yuv_rgb2yuv(unsigned char *rgb24frame, int length, int format) */ +/* + * Convert the RGB24 image to YUV422. + * return the size of the converted frame + */ +int qc_yuv_rgb2yuv(unsigned char *rgb24frame, int length, int format) +{ + int i; + int l; /* Data length */ + short Y; + short U; + short V; + unsigned char *ptr; + unsigned short w; + + //if (qcdebug&QC_DEBUGLOGIC)PDEBUG("qc_yuv_rgb2yuv(frame=%p,length=%i,palette=%s)",rgb24frame,length,qc_fmt_getname(format)); + ptr = rgb24frame; + l = 0; + + if (format==VIDEO_PALETTE_RGB32) { + /* we need to convert in reverse so as to not overwrite ourselves */ + for (ptr=ptr+length*4/3,i=length-3; i>=0; i-=3) { + *--ptr = 0; + *--ptr = (unsigned char) rgb24frame[i + 2]; + *--ptr = (unsigned char) rgb24frame[i + 1]; + *--ptr = (unsigned char) rgb24frame[i + 0]; + l += 4; + } + } else + for (i=0; i> 3))); + *ptr++ = (unsigned char) (w & 0xFF); + *ptr++ = (unsigned char) (w >> 8); + l += 2; + break; + case VIDEO_PALETTE_RGB555: + w = ((unsigned short) + ((unsigned short) (rgb24frame[i + 2] & 0xf8) << (10 - 3)) | + ((unsigned short) (rgb24frame[i + 1] & 0xf8) << (5 - 3)) | + ((unsigned short) (rgb24frame[i + 0] >> 3))); + *ptr++ = (unsigned char) (w & 0xFF); + *ptr++ = (unsigned char) (w >> 8); + l += 2; + break; + default: + *ptr++ = (219 * Y)/255 + 16; + l++; + *ptr = (112 * U)/127 + 128; /* Cb */ + ptr++; + l++; + *ptr = (112 * V)/127 + 128; /* Cr */ + ptr++; + l++; + } + } + if (format >= VIDEO_PALETTE_PLANAR) { + length = qc_yuv_toplanar(rgb24frame, l, format); + } else { + length = l; + } + return length; +} +/* }}} */ + +/* }}} */ +/* {{{ [fold] **** qc_imag: Start of image processing functions ************************** */ + +/* {{{ [fold] qc_imag_bayer_midvalue(char *bay, int bay_line, int columns, int rows) */ +/* Compute and return the average pixel intensity from the bayer data. + * The result can be used for automatic software exposure/gain control. + * bay = points to the bayer image data (upper left pixel is green) + * bay_line = bytes between the beginnings of two consecutive rows + * columns, rows = bayer image size (both must be even) + */ +static unsigned char qc_imag_bayer_midvalue(unsigned char *bay, int bay_line, + unsigned int columns, unsigned int rows) +{ + static const unsigned int stepsize = 8; /* Larger = faster and less accurate */ + unsigned char *cur_bay; + unsigned int sum = 0; + int column_cnt; + int row_cnt; + + /* Skip 1/4 of left, right, top, and bottom pixels (use only center pixels) */ + columns /= 2; + rows /= 2; + bay += rows/4*2*bay_line + columns/4*2; + + columns /= stepsize*2; + rows /= stepsize*2; + + row_cnt = rows; + do { + column_cnt = columns; + cur_bay = bay; + do { + sum += cur_bay[0] + cur_bay[1] + cur_bay[bay_line]; /* R + G + B */ + cur_bay += 2*stepsize; + } while (--column_cnt > 0); + bay += 2*stepsize*bay_line; + } while (--row_cnt > 0); + sum /= 3 * columns * rows; + return sum; +} +/* }}} */ +#if COMPRESS +/* {{{ [fold] qc_imag_rgb24_midvalue(char *rgb, int rgb_line, int columns, int rows) */ +/* Compute and return the average pixel intensity from the RGB/BGR24 data. + * The result can be used for automatic software exposure/gain control. + * rgb = points to the RGB image data + * rgb_line = bytes between the beginnings of two consecutive rows + * columns, rows = RGB image size + */ +static unsigned char qc_imag_rgb24_midvalue(unsigned char *rgb, int rgb_line, + unsigned int columns, unsigned int rows) +{ + static const unsigned int stepsize = 8; /* Larger = faster and less accurate */ + unsigned char *cur_rgb; + unsigned int sum = 0; + int column_cnt; + int row_cnt; + + /* Skip 1/4 of left, right, top, and bottom pixels (use only center pixels) */ + columns /= 2; + rows /= 2; + rgb += rows/2*rgb_line + columns/2*3; + + columns /= stepsize; + rows /= stepsize; + + row_cnt = rows; + do { + column_cnt = columns; + cur_rgb = rgb; + do { + sum += cur_rgb[0] + cur_rgb[1] + cur_rgb[2]; /* R + G + B */ + cur_rgb += 3*stepsize; + } while (--column_cnt > 0); + rgb += stepsize*rgb_line; + } while (--row_cnt > 0); + sum /= 3 * columns * rows; + return sum; +} +/* }}} */ +#endif +/* {{{ [fold] qc_imag_userlut(unsigned char (*userlut)[QC_LUT_SIZE], unsigned char (*lut)[QC_LUT_SIZE]) */ +/* Apply user-defined lookup-table to the given preinitialized lut */ +static inline void qc_imag_userlut(unsigned char (*userlut)[QC_LUT_SIZE], unsigned char (*lut)[QC_LUT_SIZE]) +{ + unsigned int i,p; + for (i=0; i<256; i++) { + p = (*lut)[QC_LUT_RED + i]; + p = (*userlut)[QC_LUT_RED + p]; + (*lut)[QC_LUT_RED + i] = p; + } + for (i=0; i<256; i++) { + p = (*lut)[QC_LUT_GREEN + i]; + p = (*userlut)[QC_LUT_GREEN + p]; + (*lut)[QC_LUT_GREEN + i] = p; + } + for (i=0; i<256; i++) { + p = (*lut)[QC_LUT_BLUE + i]; + p = (*userlut)[QC_LUT_BLUE + p]; + (*lut)[QC_LUT_BLUE + i] = p; + } +} +/* }}} */ +/* {{{ [fold] qc_imag_bayer_equalize(char *bay, int bay_line, int columns, int rows, char (*lut)[]) */ +/* Compute and fill a lookup table which will equalize the image. + * bay = points to the bayer image data (upper left pixel is green) + * bay_line = bytes between the beginnings of two consecutive rows + * columns, rows = bayer image size (both must be even) + * lut = lookup table to be filled, 3*256 char array + */ +static void qc_imag_bayer_equalize(unsigned char *bay, int bay_line, + unsigned int columns, unsigned int rows, unsigned char (*lut)[QC_LUT_SIZE]) +{ + static const unsigned int stepsize = 4; /* Larger = faster and less accurate */ + unsigned short red_cnt[256], green_cnt[256], blue_cnt[256]; /* FIXME: how much we can use stack? */ + unsigned int red_sum, green_sum, blue_sum; + unsigned int red_tot, green_tot, blue_tot; + unsigned char *cur_bay; + int i, column_cnt, row_cnt; + + memset(red_cnt, 0, sizeof(red_cnt)); + memset(green_cnt, 0, sizeof(green_cnt)); + memset(blue_cnt, 0, sizeof(blue_cnt)); + + columns /= 2*stepsize; + rows /= 2*stepsize; + + /* Compute histogram */ + row_cnt = rows; + do { + column_cnt = columns; + cur_bay = bay; + do { + green_cnt[cur_bay[0]]++; + red_cnt [cur_bay[1]]++; + blue_cnt [cur_bay[bay_line]]++; + green_cnt[cur_bay[bay_line+1]]++; + cur_bay += 2*stepsize; + } while (--column_cnt > 0); + bay += 2*stepsize*bay_line; + } while (--row_cnt > 0); + + /* Compute lookup table based on the histogram */ + red_tot = columns * rows; /* Total number of pixels of each primary color */ + green_tot = red_tot * 2; + blue_tot = red_tot; + red_sum = 0; + green_sum = 0; + blue_sum = 0; + for (i=0; i<256; i++) { + (*lut)[QC_LUT_RED + i] = 255 * red_sum / red_tot; + (*lut)[QC_LUT_GREEN + i] = 255 * green_sum / green_tot; + (*lut)[QC_LUT_BLUE + i] = 255 * blue_sum / blue_tot; + red_sum += red_cnt[i]; + green_sum += green_cnt[i]; + blue_sum += blue_cnt[i]; + } +} +/* }}} */ +/* {{{ [fold] qc_imag_bayer_lut(char *bay, int bay_line, int columns, int rows, char (*lut)[]) */ +/* Transform pixel values in a bayer image with a given lookup table. + * bay = points to the bayer image data (upper left pixel is green) + * bay_line = bytes between the beginnings of two consecutive rows + * columns, rows = bayer image size (both must be even) + * lut = lookup table to be used, 3*256 char array + */ +static void qc_imag_bayer_lut(unsigned char *bay, int bay_line, + unsigned int columns, unsigned int rows, unsigned char (*lut)[QC_LUT_SIZE]) +{ + unsigned char *cur_bay; + unsigned int total_columns; + + total_columns = columns / 2; /* Number of 2x2 bayer blocks */ + rows /= 2; + do { + columns = total_columns; + cur_bay = bay; + do { + cur_bay[0] = (*lut)[QC_LUT_GREEN + cur_bay[0]]; + cur_bay[1] = (*lut)[QC_LUT_RED + cur_bay[1]]; + cur_bay += 2; + } while (--columns); + bay += bay_line; + columns = total_columns; + cur_bay = bay; + do { + cur_bay[0] = (*lut)[QC_LUT_BLUE + cur_bay[0]]; + cur_bay[1] = (*lut)[QC_LUT_GREEN + cur_bay[1]]; + cur_bay += 2; + } while (--columns); + bay += bay_line; + } while (--rows); +} +/* }}} */ +/* {{{ [fold] qc_imag_writergb(void *addr, int bpp, unsigned char r, unsigned char g, unsigned char b) */ +/* Write RGB pixel value to the given address. + * addr = memory address, to which the pixel is written + * bpp = number of bytes in the pixel (should be 3 or 4) + * r, g, b = pixel component values to be written (red, green, blue) + * Looks horribly slow but the compiler should be able to inline optimize it. + */ +static inline void qc_imag_writergb(void *addr, int bpp, + unsigned char r, unsigned char g, unsigned char b) +{ + if (DEFAULT_BGR) { + /* Blue is first (in the lowest memory address */ + if (bpp==4) { +#if defined(__LITTLE_ENDIAN) + *(unsigned int *)addr = + (unsigned int)r << 16 | + (unsigned int)g << 8 | + (unsigned int)b; +#elif defined(__BIG_ENDIAN) + *(unsigned int *)addr = + (unsigned int)r << 8 | + (unsigned int)g << 16 | + (unsigned int)b << 24; +#else + unsigned char *addr2 = (unsigned char *)addr; + addr2[0] = b; + addr2[1] = g; + addr2[2] = r; + addr2[3] = 0; +#endif + } else { + unsigned char *addr2 = (unsigned char *)addr; + addr2[0] = b; + addr2[1] = g; + addr2[2] = r; + } + } else { + /* Red is first (in the lowest memory address */ + if (bpp==4) { +#if defined(__LITTLE_ENDIAN) + *(unsigned int *)addr = + (unsigned int)b << 16 | + (unsigned int)g << 8 | + (unsigned int)r; +#elif defined(__BIG_ENDIAN) + *(unsigned int *)addr = + (unsigned int)b << 8 | + (unsigned int)g << 16 | + (unsigned int)r << 24; +#else + unsigned char *addr2 = (unsigned char *)addr; + addr2[0] = r; + addr2[1] = g; + addr2[2] = b; + addr2[3] = 0; +#endif + } else { + unsigned char *addr2 = (unsigned char *)addr; + addr2[0] = r; + addr2[1] = g; + addr2[2] = b; + } + } +} +/* }}} */ + +/* + * Raw image data for Bayer-RGB-matrix: + * G R for even rows + * B G for odd rows + */ + +#if 0 +/* {{{ [fold] qc_imag_bay2rgb_noip(char *bay, int bay_line, char *rgb, int rgb_line, int columns, rows, bpp) */ +/* Convert bayer image to RGB image without using interpolation. + * bay = points to the bayer image data (upper left pixel is green) + * bay_line = bytes between the beginnings of two consecutive rows + * rgb = points to the rgb image data that is written + * rgb_line = bytes between the beginnings of two consecutive rows + * columns, rows = bayer image size (both must be even) + * bpp = number of bytes in each pixel in the RGB image (should be 3 or 4) + */ +/* Execution time: 2391747-2653574 clock cycles for CIF image (Pentium II) */ +/* Do NOT use this routine: cottnoip is faster with better image quality */ +static inline void qc_imag_bay2rgb_noip(unsigned char *bay, int bay_line, + unsigned char *rgb, int rgb_line, + int columns, int rows, int bpp) +{ + unsigned char *cur_bay, *cur_rgb; + int bay_line2, rgb_line2; + int total_columns; + + /* Process 2 lines and rows per each iteration */ + total_columns = columns >> 1; + rows >>= 1; + bay_line2 = 2*bay_line; + rgb_line2 = 2*rgb_line; + do { + cur_bay = bay; + cur_rgb = rgb; + columns = total_columns; + do { + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + cur_bay += 2; + cur_rgb += 2*bpp; + } while (--columns); + bay += bay_line2; + rgb += rgb_line2; + } while (--rows); +} +/* }}} */ +#endif +/* {{{ [fold] qc_imag_bay2rgb_horip(char *bay, int bay_line, char *rgb, int rgb_line, columns, rows, bpp) */ +/* Convert bayer image to RGB image using fast horizontal-only interpolation. + * bay = points to the bayer image data (upper left pixel is green) + * bay_line = bytes between the beginnings of two consecutive rows + * rgb = points to the rgb image data that is written + * rgb_line = bytes between the beginnings of two consecutive rows + * columns, rows = bayer image size (both must be even) + * bpp = number of bytes in each pixel in the RGB image (should be 3 or 4) + */ +/* Execution time: 2735776-3095322 clock cycles for CIF image (Pentium II) */ +/* Not recommended: ip seems to be somewhat faster, probably with better image quality. + * cott is quite much faster, but possibly with slightly worse image quality */ +static inline void qc_imag_bay2rgb_horip(unsigned char *bay, int bay_line, + unsigned char *rgb, int rgb_line, + unsigned int columns, unsigned int rows, int bpp) +{ + unsigned char *cur_bay, *cur_rgb; + int bay_line2, rgb_line2; + int total_columns; + unsigned char red, green, blue; + unsigned int column_cnt, row_cnt; + + /* Process 2 lines and rows per each iteration */ + total_columns = (columns-2) / 2; + row_cnt = rows / 2; + bay_line2 = 2*bay_line; + rgb_line2 = 2*rgb_line; + + do { + qc_imag_writergb(rgb+0, bpp, bay[1], bay[0], bay[bay_line]); + qc_imag_writergb(rgb+rgb_line, bpp, bay[1], bay[0], bay[bay_line]); + cur_bay = bay + 1; + cur_rgb = rgb + bpp; + column_cnt = total_columns; + do { + green = ((unsigned int)cur_bay[-1]+cur_bay[1]) / 2; + blue = ((unsigned int)cur_bay[bay_line-1]+cur_bay[bay_line+1]) / 2; + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[0], green, blue); + red = ((unsigned int)cur_bay[0]+cur_bay[2]) / 2; + qc_imag_writergb(cur_rgb+bpp, bpp, red, cur_bay[1], cur_bay[bay_line+1]); + green = ((unsigned int)cur_bay[bay_line]+cur_bay[bay_line+2]) / 2; + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[0], cur_bay[bay_line], blue); + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, red, cur_bay[1], cur_bay[bay_line+1]); + cur_bay += 2; + cur_rgb += 2*bpp; + } while (--column_cnt); + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[0], cur_bay[-1], cur_bay[bay_line-1]); + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[0], cur_bay[bay_line], cur_bay[bay_line-1]); + bay += bay_line2; + rgb += rgb_line2; + } while (--row_cnt); +} +/* }}} */ +/* {{{ [fold] qc_imag_bay2rgb_ip(char *bay, int bay_line, char *rgb, int rgb_line, columns, rows, bpp) */ +/* Convert bayer image to RGB image using full (slow) linear interpolation. + * bay = points to the bayer image data (upper left pixel is green) + * bay_line = bytes between the beginnings of two consecutive rows + * rgb = points to the rgb image data that is written + * rgb_line = bytes between the beginnings of two consecutive rows + * columns, rows = bayer image size (both must be even) + * bpp = number of bytes in each pixel in the RGB image (should be 3 or 4) + */ +/* Execution time: 2714077-2827455 clock cycles for CIF image (Pentium II) */ +static inline void qc_imag_bay2rgb_ip(unsigned char *bay, int bay_line, + unsigned char *rgb, int rgb_line, + unsigned int columns, unsigned int rows, int bpp) +{ + unsigned char *cur_bay, *cur_rgb; + int bay_line2, rgb_line2; + int total_columns; + unsigned char red, green, blue; + unsigned int column_cnt, row_cnt; + + /* Process 2 rows and columns each iteration */ + total_columns = (columns-2) / 2; + row_cnt = (rows-2) / 2; + bay_line2 = 2*bay_line; + rgb_line2 = 2*rgb_line; + + /* First scanline is handled here as a special case */ + qc_imag_writergb(rgb, bpp, bay[1], bay[0], bay[bay_line]); + cur_bay = bay + 1; + cur_rgb = rgb + bpp; + column_cnt = total_columns; + do { + green = ((unsigned int)cur_bay[-1] + cur_bay[1] + cur_bay[bay_line]) / 3; + blue = ((unsigned int)cur_bay[bay_line-1] + cur_bay[bay_line+1]) / 2; + qc_imag_writergb(cur_rgb, bpp, cur_bay[0], green, blue); + red = ((unsigned int)cur_bay[0] + cur_bay[2]) / 2; + qc_imag_writergb(cur_rgb+bpp, bpp, red, cur_bay[1], cur_bay[bay_line+1]); + cur_bay += 2; + cur_rgb += 2*bpp; + } while (--column_cnt); + green = ((unsigned int)cur_bay[-1] + cur_bay[bay_line]) / 2; + qc_imag_writergb(cur_rgb, bpp, cur_bay[0], green, cur_bay[bay_line-1]); + + /* Process here all other scanlines except first and last */ + bay += bay_line; + rgb += rgb_line; + do { + red = ((unsigned int)bay[-bay_line+1] + bay[bay_line+1]) / 2; + green = ((unsigned int)bay[-bay_line] + bay[1] + bay[bay_line]) / 3; + qc_imag_writergb(rgb+0, bpp, red, green, bay[0]); + blue = ((unsigned int)bay[0] + bay[bay_line2]) / 2; + qc_imag_writergb(rgb+rgb_line, bpp, bay[bay_line+1], bay[bay_line], blue); + cur_bay = bay + 1; + cur_rgb = rgb + bpp; + column_cnt = total_columns; + do { + red = ((unsigned int)cur_bay[-bay_line]+cur_bay[bay_line]) / 2; + blue = ((unsigned int)cur_bay[-1]+cur_bay[1]) / 2; + qc_imag_writergb(cur_rgb+0, bpp, red, cur_bay[0], blue); + red = ((unsigned int)cur_bay[-bay_line]+cur_bay[-bay_line+2]+cur_bay[bay_line]+cur_bay[bay_line+2]) / 4; + green = ((unsigned int)cur_bay[0]+cur_bay[2]+cur_bay[-bay_line+1]+cur_bay[bay_line+1]) / 4; + qc_imag_writergb(cur_rgb+bpp, bpp, red, green, cur_bay[1]); + green = ((unsigned int)cur_bay[0]+cur_bay[bay_line2]+cur_bay[bay_line-1]+cur_bay[bay_line+1]) / 4; + blue = ((unsigned int)cur_bay[-1]+cur_bay[1]+cur_bay[bay_line2-1]+cur_bay[bay_line2+1]) / 4; + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[bay_line], green, blue); + red = ((unsigned int)cur_bay[bay_line]+cur_bay[bay_line+2]) / 2; + blue = ((unsigned int)cur_bay[1]+cur_bay[bay_line2+1]) / 2; + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, red, cur_bay[bay_line+1], blue); + cur_bay += 2; + cur_rgb += 2*bpp; + } while (--column_cnt); + red = ((unsigned int)cur_bay[-bay_line] + cur_bay[bay_line]) / 2; + qc_imag_writergb(cur_rgb, bpp, red, cur_bay[0], cur_bay[-1]); + green = ((unsigned int)cur_bay[0] + cur_bay[bay_line-1] + cur_bay[bay_line2]) / 3; + blue = ((unsigned int)cur_bay[-1] + cur_bay[bay_line2-1]) / 2; + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[bay_line], green, blue); + bay += bay_line2; + rgb += rgb_line2; + } while (--row_cnt); + + /* Last scanline is handled here as a special case */ + green = ((unsigned int)bay[-bay_line] + bay[1]) / 2; + qc_imag_writergb(rgb, bpp, bay[-bay_line+1], green, bay[0]); + cur_bay = bay + 1; + cur_rgb = rgb + bpp; + column_cnt = total_columns; + do { + blue = ((unsigned int)cur_bay[-1] + cur_bay[1]) / 2; + qc_imag_writergb(cur_rgb, bpp, cur_bay[-bay_line], cur_bay[0], blue); + red = ((unsigned int)cur_bay[-bay_line] + cur_bay[-bay_line+2]) / 2; + green = ((unsigned int)cur_bay[0] + cur_bay[-bay_line+1] + cur_bay[2]) / 3; + qc_imag_writergb(cur_rgb+bpp, bpp, red, green, cur_bay[1]); + cur_bay += 2; + cur_rgb += 2*bpp; + } while (--column_cnt); + qc_imag_writergb(cur_rgb, bpp, cur_bay[-bay_line], cur_bay[0], cur_bay[-1]); +} +/* }}} */ +/* {{{ [fold] qc_imag_bay2rgb_cott(unsigned char *bay, int bay_line, unsigned char *rgb, int rgb_line, int columns, int rows, int bpp) */ +/* Convert bayer image to RGB image using 0.5 displaced light linear interpolation. + * bay = points to the bayer image data (upper left pixel is green) + * bay_line = bytes between the beginnings of two consecutive rows + * rgb = points to the rgb image data that is written + * rgb_line = bytes between the beginnings of two consecutive rows + * columns, rows = bayer image size (both must be even) + * bpp = number of bytes in each pixel in the RGB image (should be 3 or 4) + */ +/* Execution time: 2167685 clock cycles for CIF image (Pentium II) */ +/* Original idea for this routine from Cagdas Ogut */ +static inline void qc_imag_bay2rgb_cott(unsigned char *bay, int bay_line, + unsigned char *rgb, int rgb_line, + int columns, int rows, int bpp) +{ + unsigned char *cur_bay, *cur_rgb; + int bay_line2, rgb_line2; + int total_columns; + + /* Process 2 lines and rows per each iteration, but process the last row and column separately */ + total_columns = (columns>>1) - 1; + rows = (rows>>1) - 1; + bay_line2 = 2*bay_line; + rgb_line2 = 2*rgb_line; + do { + cur_bay = bay; + cur_rgb = rgb; + columns = total_columns; + do { + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[1], ((unsigned int)cur_bay[0] + cur_bay[bay_line+1]) /2, cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], ((unsigned int)cur_bay[2] + cur_bay[bay_line+1]) /2, cur_bay[bay_line+2]); + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[bay_line2+1], ((unsigned int)cur_bay[bay_line2] + cur_bay[bay_line+1]) /2, cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, cur_bay[bay_line2+1], ((unsigned int)cur_bay[bay_line2+2] + cur_bay[bay_line+1])/2, cur_bay[bay_line+2]); + cur_bay += 2; + cur_rgb += 2*bpp; + } while (--columns); + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[1], ((unsigned int)cur_bay[0] + cur_bay[bay_line+1])/2, cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[bay_line2+1], ((unsigned int)cur_bay[bay_line2] + cur_bay[bay_line+1])/2, cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, cur_bay[bay_line2+1], cur_bay[bay_line+1], cur_bay[bay_line]); + bay += bay_line2; + rgb += rgb_line2; + } while (--rows); + /* Last scanline handled here as special case */ + cur_bay = bay; + cur_rgb = rgb; + columns = total_columns; + do { + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[1], ((unsigned int)cur_bay[0] + cur_bay[bay_line+1])/2, cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], ((unsigned int)cur_bay[2] + cur_bay[bay_line+1])/2, cur_bay[bay_line+2]); + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line+2]); + cur_bay += 2; + cur_rgb += 2*bpp; + } while (--columns); + /* Last lower-right pixel is handled here as special case */ + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[1], ((unsigned int)cur_bay[0] + cur_bay[bay_line+1])/2, cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); +} +/* }}} */ +/* {{{ [fold] qc_imag_bay2rgb_cottnoip(unsigned char *bay, int bay_line, unsigned char *rgb, int rgb_line, int columns, int rows, int bpp) */ +/* Convert bayer image to RGB image using 0.5 displaced nearest neighbor. + * bay = points to the bayer image data (upper left pixel is green) + * bay_line = bytes between the beginnings of two consecutive rows + * rgb = points to the rgb image data that is written + * rgb_line = bytes between the beginnings of two consecutive rows + * columns, rows = bayer image size (both must be even) + * bpp = number of bytes in each pixel in the RGB image (should be 3 or 4) + */ +/* Execution time: 2133302 clock cycles for CIF image (Pentium II), fastest */ +static inline void qc_imag_bay2rgb_cottnoip(unsigned char *bay, int bay_line, + unsigned char *rgb, int rgb_line, + int columns, int rows, int bpp) +{ + unsigned char *cur_bay, *cur_rgb; + int bay_line2, rgb_line2; + int total_columns; + + /* Process 2 lines and rows per each iteration, but process the last row and column separately */ + total_columns = (columns>>1) - 1; + rows = (rows>>1) - 1; + bay_line2 = 2*bay_line; + rgb_line2 = 2*rgb_line; + do { + cur_bay = bay; + cur_rgb = rgb; + columns = total_columns; + do { + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], cur_bay[2], cur_bay[bay_line+2]); + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[bay_line2+1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, cur_bay[bay_line2+1], cur_bay[bay_line+1], cur_bay[bay_line+2]); + cur_bay += 2; + cur_rgb += 2*bpp; + } while (--columns); + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[bay_line2+1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, cur_bay[bay_line2+1], cur_bay[bay_line+1], cur_bay[bay_line]); + bay += bay_line2; + rgb += rgb_line2; + } while (--rows); + /* Last scanline handled here as special case */ + cur_bay = bay; + cur_rgb = rgb; + columns = total_columns; + do { + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], cur_bay[2], cur_bay[bay_line+2]); + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line+2]); + cur_bay += 2; + cur_rgb += 2*bpp; + } while (--columns); + /* Last lower-right pixel is handled here as special case */ + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); +} +/* }}} */ +/* {{{ [fold] qc_imag_bay2rgb_gptm_fast(unsigned char *bay, int bay_line, unsigned char *rgb, int rgb_line, int columns, int rows, int bpp) */ +/* Convert Bayer image to RGB image using Generalized Pei-Tam method + * Uses fixed weights */ +/* Execution time: 3795517 clock cycles */ +static inline void qc_imag_bay2rgb_gptm_fast(unsigned char *bay, int bay_line, + unsigned char *rgb, int rgb_line, + int columns, int rows, int bpp) +{ + int r,g,b,w; + unsigned char *cur_bay, *cur_rgb; + int bay_line2, bay_line3, rgb_line2; + int total_columns; + + /* Process 2 lines and rows per each iteration, but process the first and last two columns and rows separately */ + total_columns = (columns>>1) - 2; + rows = (rows>>1) - 2; + bay_line2 = 2*bay_line; + bay_line3 = 3*bay_line; + rgb_line2 = 2*rgb_line; + + /* Process first two pixel rows here */ + cur_bay = bay; + cur_rgb = rgb; + columns = total_columns + 2; + do { + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + cur_bay += 2; + cur_rgb += 2*bpp; + } while (--columns); + bay += bay_line2; + rgb += rgb_line2; + + do { + cur_bay = bay; + cur_rgb = rgb; + columns = total_columns; + + /* Process first 2x2 pixel block in a row here */ + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + cur_bay += 2; + cur_rgb += 2*bpp; + + do { + w = 4*cur_bay[0] - (cur_bay[-bay_line-1] + cur_bay[-bay_line+1] + cur_bay[bay_line-1] + cur_bay[bay_line+1]); + r = (2*(cur_bay[-1] + cur_bay[1]) + w) >> 2; + b = (2*(cur_bay[-bay_line] + cur_bay[bay_line]) + w) >> 2; + qc_imag_writergb(cur_rgb+0, bpp, CLIP(r,0,255), cur_bay[0], CLIP(b,0,255)); + + w = 4*cur_bay[1] - (cur_bay[-bay_line2+1] + cur_bay[-1] + cur_bay[3] + cur_bay[bay_line2+1]); + g = (2*(cur_bay[-bay_line+1] + cur_bay[0] + cur_bay[2] + cur_bay[bay_line+1]) + w) >> 3; + b = (2*(cur_bay[-bay_line] + cur_bay[-bay_line+2] + cur_bay[bay_line] + cur_bay[bay_line+2]) + w) >> 3; + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], CLIP(g,0,255), CLIP(b,0,255)); + + w = 4*cur_bay[bay_line] - (cur_bay[-bay_line] + cur_bay[bay_line-2] + cur_bay[bay_line+2] + cur_bay[bay_line3]); + r = ((cur_bay[-1] + cur_bay[1] + cur_bay[bay_line2-1] + cur_bay[bay_line2+1]) + w) >> 2; + g = ((cur_bay[0] + cur_bay[bay_line-1] + cur_bay[bay_line+1] + cur_bay[bay_line2]) + w) >> 2; + qc_imag_writergb(cur_rgb+rgb_line, bpp, CLIP(r,0,255), CLIP(g,0,255), cur_bay[bay_line]); + + w = 4*cur_bay[bay_line+1] - (cur_bay[0] + cur_bay[2] + cur_bay[bay_line2] + cur_bay[bay_line2+2]); + r = (2*(cur_bay[1] + cur_bay[bay_line2+1]) + w) >> 2; + b = (2*(cur_bay[bay_line] + cur_bay[bay_line+2]) + w) >> 2; + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, CLIP(r,0,255), cur_bay[bay_line+1], CLIP(b,0,255)); + + cur_bay += 2; + cur_rgb += 2*bpp; + } while (--columns); + + /* Process last 2x2 pixel block in a row here */ + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + + bay += bay_line2; + rgb += rgb_line2; + } while (--rows); + + /* Process last two pixel rows here */ + cur_bay = bay; + cur_rgb = rgb; + columns = total_columns + 2; + do { + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + cur_bay += 2; + cur_rgb += 2*bpp; + } while (--columns); +} +/* }}} */ +/* {{{ [fold] qc_imag_bay2rgb_gptm(unsigned char *bay, int bay_line, unsigned char *rgb, int rgb_line, int columns, int rows, int bpp, int sharpness) */ +/* Convert Bayer image to RGB image using Generalized Pei-Tam method (See: + * "Effective Color Interpolation in CCD Color Filter Arrays Using Signal Correlation" + * IEEE Transactions on Circuits and Systems for Video Technology, vol. 13, no. 6, June 2003. + * Note that this is much improved version of the algorithm described in the paper) + * bay = points to the bayer image data (upper left pixel is green) + * bay_line = bytes between the beginnings of two consecutive rows + * rgb = points to the rgb image data that is written + * rgb_line = bytes between the beginnings of two consecutive rows + * columns, rows = bayer image size (both must be even) + * bpp = number of bytes in each pixel in the RGB image (should be 3 or 4) + * sharpness = how sharp the image should be, between 0..65535 inclusive. + * 23170 gives in theory image that corresponds to the original + * best, but human eye likes slightly sharper picture... 32768 is a good bet. + * When sharpness = 0, this routine is same as bilinear interpolation. + */ +/* Execution time: 4344042 clock cycles for CIF image (Pentium II) */ +static inline void qc_imag_bay2rgb_gptm(unsigned char *bay, int bay_line, + unsigned char *rgb, int rgb_line, + int columns, int rows, int bpp, unsigned int sharpness) +{ + + /* 0.8 fixed point weights, should be between 0-256. Larger value = sharper, zero corresponds to bilinear interpolation. */ + /* Best PSNR with sharpness = 23170 */ + static const int wrg0 = 144; /* Weight for Red on Green */ + static const int wbg0 = 160; + static const int wgr0 = 120; + static const int wbr0 = 192; + static const int wgb0 = 120; + static const int wrb0 = 168; + + int wrg; + int wbg; + int wgr; + int wbr; + int wgb; + int wrb; + + unsigned int wu; + int r,g,b,w; + unsigned char *cur_bay, *cur_rgb; + int bay_line2, bay_line3, rgb_line2; + int total_columns; + + /* Compute weights */ + wu = (sharpness * sharpness) >> 16; + wu = (wu * wu) >> 16; + wrg = (wrg0 * wu) >> 10; + wbg = (wbg0 * wu) >> 10; + wgr = (wgr0 * wu) >> 10; + wbr = (wbr0 * wu) >> 10; + wgb = (wgb0 * wu) >> 10; + wrb = (wrb0 * wu) >> 10; + + /* Process 2 lines and rows per each iteration, but process the first and last two columns and rows separately */ + total_columns = (columns>>1) - 2; + rows = (rows>>1) - 2; + bay_line2 = 2*bay_line; + bay_line3 = 3*bay_line; + rgb_line2 = 2*rgb_line; + + /* Process first two pixel rows here */ + cur_bay = bay; + cur_rgb = rgb; + columns = total_columns + 2; + do { + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + cur_bay += 2; + cur_rgb += 2*bpp; + } while (--columns); + bay += bay_line2; + rgb += rgb_line2; + + do { + cur_bay = bay; + cur_rgb = rgb; + columns = total_columns; + + /* Process first 2x2 pixel block in a row here */ + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + cur_bay += 2; + cur_rgb += 2*bpp; + + do { + w = 4*cur_bay[0] - (cur_bay[-bay_line-1] + cur_bay[-bay_line+1] + cur_bay[bay_line-1] + cur_bay[bay_line+1]); + r = (512*(cur_bay[-1] + cur_bay[1]) + w*wrg) >> 10; + b = (512*(cur_bay[-bay_line] + cur_bay[bay_line]) + w*wbg) >> 10; + qc_imag_writergb(cur_rgb+0, bpp, CLIP(r,0,255), cur_bay[0], CLIP(b,0,255)); + + w = 4*cur_bay[1] - (cur_bay[-bay_line2+1] + cur_bay[-1] + cur_bay[3] + cur_bay[bay_line2+1]); + g = (256*(cur_bay[-bay_line+1] + cur_bay[0] + cur_bay[2] + cur_bay[bay_line+1]) + w*wgr) >> 10; + b = (256*(cur_bay[-bay_line] + cur_bay[-bay_line+2] + cur_bay[bay_line] + cur_bay[bay_line+2]) + w*wbr) >> 10; + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], CLIP(g,0,255), CLIP(b,0,255)); + + w = 4*cur_bay[bay_line] - (cur_bay[-bay_line] + cur_bay[bay_line-2] + cur_bay[bay_line+2] + cur_bay[bay_line3]); + r = (256*(cur_bay[-1] + cur_bay[1] + cur_bay[bay_line2-1] + cur_bay[bay_line2+1]) + w*wrb) >> 10; + g = (256*(cur_bay[0] + cur_bay[bay_line-1] + cur_bay[bay_line+1] + cur_bay[bay_line2]) + w*wgb) >> 10; + qc_imag_writergb(cur_rgb+rgb_line, bpp, CLIP(r,0,255), CLIP(g,0,255), cur_bay[bay_line]); + + w = 4*cur_bay[bay_line+1] - (cur_bay[0] + cur_bay[2] + cur_bay[bay_line2] + cur_bay[bay_line2+2]); + r = (512*(cur_bay[1] + cur_bay[bay_line2+1]) + w*wrg) >> 10; + b = (512*(cur_bay[bay_line] + cur_bay[bay_line+2]) + w*wbg) >> 10; + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, CLIP(r,0,255), cur_bay[bay_line+1], CLIP(b,0,255)); + + cur_bay += 2; + cur_rgb += 2*bpp; + } while (--columns); + + /* Process last 2x2 pixel block in a row here */ + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + + bay += bay_line2; + rgb += rgb_line2; + } while (--rows); + + /* Process last two pixel rows here */ + cur_bay = bay; + cur_rgb = rgb; + columns = total_columns + 2; + do { + qc_imag_writergb(cur_rgb+0, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+bpp, bpp, cur_bay[1], cur_bay[0], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + qc_imag_writergb(cur_rgb+rgb_line+bpp, bpp, cur_bay[1], cur_bay[bay_line+1], cur_bay[bay_line]); + cur_bay += 2; + cur_rgb += 2*bpp; + } while (--columns); +} +/* }}} */ +/* {{{ [fold] qc_imag_rgbbgr(unsigned char *dst, int pixels, int bpp) */ +/* Convert RGB image to BGR or vice versa with the given number of pixels and + * bytes per pixel + */ +static void inline qc_imag_rgbbgr(unsigned char *dst, int pixels, int bpp) +{ + unsigned char r,b; + do { + r = dst[0]; + b = dst[2]; + dst[0] = b; + dst[2] = r; + dst += bpp; + } while (--pixels); +} +/* }}} */ + +/* }}} */ +/* {{{ [fold] **** qc_fmt: Start of generic format query functions ********************** */ + +/* {{{ [fold] struct qc_fmt_format: a format definition */ +struct qc_fmt_format { + u32 fcc; /* M$ defined fourcc code, see http://www.fourcc.org */ + signed char bpp; /* 0=variable, -1=unknown (FIXME:what bpps do AVIs use here?) */ + char order; /* 'R' = RGB, 'B'=BGR, 0=not specified */ + unsigned char nr, ng, nb; /* Number of red, green, blue levels (0=256 levels) */ + char *name; /* Human-readable name */ + Bool supported; /* Can be converted to? */ + /* Here we could add a pointer to list containing conversion routines to other fourcc's */ + /* Then write code to create minimum spanning tree of format conversions */ + /* Include estimated cost per pixel to apply a conversion routine to weight edges */ +}; +/* }}} */ +/* {{{ [fold] List of supported formats */ +#define BF_RGB(r,g,b) 'R', (b)&0xFF, (g)&0xFF, (r)&0xFF +#define BF_BGR(r,g,b) 'B', (b)&0xFF, (g)&0xFF, (r)&0xFF +#define NO_BF 0, 0, 0, 0 +#define FORMAT(ID,FCC1,FCC2,FCC3,FCC4,BPP,BF,NAME,SUPP) \ +static const struct qc_fmt_format qc_fmt_formats_##ID = { v4l2_fourcc(FCC1,FCC2,FCC3,FCC4), BPP, BF, NAME, SUPP } +FORMAT(Y800, 'Y','8','0','0', 8, NO_BF, "GREY", TRUE); +FORMAT(RGB_HI, 'q','c','R','B', 8, BF_RGB(6, 6, 6), "HI240", FALSE); /* Not sure: BF_RGB or BF_BGR? Same as BT20? Don't think so */ +FORMAT(RGB_332, 3,0,0,0, 8, BF_RGB(8, 8, 4), "RGB332", FALSE); +/* Little endian RGB formats (least significant byte at lowest address) */ +FORMAT(RGB_555L, 3,0,0,0, 16, BF_RGB(32, 32, 32), "RGB555L",TRUE); /* Should this be 15 or 16 bpp? Is this same as RGB2? */ +FORMAT(RGB_565L, 3,0,0,0, 16, BF_RGB(32, 64, 32), "RGB565L",TRUE); /* Is this same as RGB2? */ +FORMAT(RGB_24L, 'R','G','B','2', 24, BF_RGB(256, 256, 256), "RGB24L", TRUE); +FORMAT(BGR_24L, 'R','G','B','2', 24, BF_BGR(256, 256, 256), "BGR24L", TRUE); +FORMAT(RGB_32L, 'R','G','B','2', 32, BF_RGB(256, 256, 256), "RGB32L", TRUE); +FORMAT(BGR_32L, 'R','G','B','2', 32, BF_BGR(256, 256, 256), "BGR32L", TRUE); +/* Big endian RGB formats (most significant byte at lowest address) */ +FORMAT(RGB_555B, 'q','c','R','B', 16, BF_RGB(32, 32, 32), "RGB555B",FALSE); +FORMAT(RGB_565B, 'q','c','R','B', 16, BF_RGB(32, 64, 32), "RGB565B",FALSE); +/* Component YUV formats */ +FORMAT(YUY2, 'Y','U','Y','2', 16, NO_BF, "YUV422", TRUE); /* 4:2:2 packed pixel YUYV */ +FORMAT(UYVY, 'U','Y','V','Y', 16, NO_BF, "UYVY", FALSE); +FORMAT(IYUV, 'I','Y','U','V', 12, NO_BF, "YUV420", FALSE); +/* Planar YUV formats */ +FORMAT(YV12, 'Y','V','1','2', 12, NO_BF, "YV12", FALSE); +FORMAT(YVU9, 'Y','V','U','9', 9, NO_BF, "YVU9", FALSE); +FORMAT(Y41P, 'Y','4','1','P', 12, NO_BF, "Y41P", FALSE); /* 4:1:1 packed pixel UYVY UYVY YYYY */ +FORMAT(qcY1, 'q','c','Y','1', 12, NO_BF, "YUV411P", FALSE); /* Like Y41P but planar and Y, U and V planes are in this order */ +FORMAT(qcY2, 'q','c','Y','2', 16, NO_BF, "YUV422P", TRUE); /* Like YUY2 but planar */ +FORMAT(qcV1, 'q','c','V','1', 12, NO_BF, "YVU411P", FALSE); /* Like qcY1 but V and U planes are in this order */ +FORMAT(qcV2, 'q','c','V','2', 16, NO_BF, "YVU422P", FALSE); /* Like qcY2 but V and U planes are in this order */ +FORMAT(qcU9, 'q','c','U','9', 9, NO_BF, "YUV410P", TRUE); /* Like YVU9 but U and V planes are in this order */ +FORMAT(qcYY, 'q','c','Y','Y', 12, NO_BF, "YYUV", FALSE); /* Packed 4:2:2 sampling, Y, Y, U, V */ +FORMAT(NV12, 'N','V','1','2', 12, NO_BF, "NV12", FALSE); +FORMAT(NV21, 'N','V','2','1', 12, NO_BF, "NV21", FALSE); +/* Special formats */ +FORMAT(qcBT, 'q','c','B','T', -1, NO_BF, "BT848 RAW", FALSE); /* RAW is raw scanline data sampled (before PAL decoding) */ +FORMAT(qcBR, 'q','c','B','R', 8, NO_BF, "BAYER", TRUE); /* Same as STVA? */ +FORMAT(qcMJ, 'q','c','M','J', 0, NO_BF, "MJPEG", TRUE); /* Same as MJPG? */ +FORMAT(qcWN, 'q','c','W','N', -1, NO_BF, "Winnov hw", FALSE); /* Same as WNV1 (or CHAM, WINX, YUV8)? */ +/* }}} */ +/* {{{ [fold] struct qc_fmt_alias: Alias fourcc codes for above formats */ +static struct qc_fmt_alias { + u32 fcc; + struct qc_fmt_format const *format; +} const qc_fmt_aliases[] = { + { v4l2_fourcc(0,0,0,0), &qc_fmt_formats_RGB_24L }, /* Could be any format with fourcc 'RGB2' */ + { v4l2_fourcc('Y','8',' ',' '), &qc_fmt_formats_Y800 }, + { v4l2_fourcc('Y','U','N','V'), &qc_fmt_formats_YUY2 }, + { v4l2_fourcc('V','4','2','2'), &qc_fmt_formats_YUY2 }, + { v4l2_fourcc('Y','4','2','2'), &qc_fmt_formats_UYVY }, + { v4l2_fourcc('U','Y','N','V'), &qc_fmt_formats_UYVY }, + { v4l2_fourcc('I','4','2','0'), &qc_fmt_formats_IYUV }, +}; +/* }}} */ +/* {{{ [fold] struct qc_fmt_palette: table to convert V4L code into fourcc, supported formats */ +static struct qc_fmt_palette { + int palette; /* V4L1 standard palette type */ + struct qc_fmt_format const *format; +} const qc_fmt_palettes[] = { + { VIDEO_PALETTE_GREY, &qc_fmt_formats_Y800 }, + { VIDEO_PALETTE_HI240, &qc_fmt_formats_RGB_HI }, + /* RGB formats */ + { VIDEO_PALETTE_RGB565, &qc_fmt_formats_RGB_565L }, + { VIDEO_PALETTE_RGB24, &qc_fmt_formats_BGR_24L }, + { VIDEO_PALETTE_RGB32, &qc_fmt_formats_BGR_32L }, + { VIDEO_PALETTE_RGB555, &qc_fmt_formats_RGB_555L }, + /* Component YUV formats */ + { VIDEO_PALETTE_YUV422, &qc_fmt_formats_YUY2 }, /* Assume this is YUY2, even though V4L1 docs say this is 8 bpp format */ + { VIDEO_PALETTE_YUYV, &qc_fmt_formats_YUY2 }, /* Benedict Bridgwater : Bt848 maps this to Y41P, but it is simply wrong--we follow V4L2 v4l_compat.c */ + { VIDEO_PALETTE_UYVY, &qc_fmt_formats_UYVY }, + { VIDEO_PALETTE_YUV420, &qc_fmt_formats_IYUV }, /* Assume this is planar, even though V4L1 header file indicates otherwise */ + { VIDEO_PALETTE_YUV411, &qc_fmt_formats_qcY1 }, /* Assume this is planar, even though V4L1 header file indicates otherwise (could be also fourcc 'Y41P') -from benedict */ + { VIDEO_PALETTE_RAW, &qc_fmt_formats_qcBT }, + /* Planar YUV formats */ + { VIDEO_PALETTE_YUV422P, &qc_fmt_formats_qcY2 }, + { VIDEO_PALETTE_YUV411P, &qc_fmt_formats_qcY1 }, + { VIDEO_PALETTE_YUV420P, &qc_fmt_formats_IYUV }, + { VIDEO_PALETTE_YUV410P, &qc_fmt_formats_qcU9 }, + /* Special formats */ + { VIDEO_PALETTE_BAYER, &qc_fmt_formats_qcBR }, + { VIDEO_PALETTE_MJPEG, &qc_fmt_formats_qcMJ }, +}; +/* }}} */ +/* {{{ [fold] struct qc_fmt_v4l2: V4L2 defines its own conflicting format codes */ +static struct qc_fmt_v4l2 { + u32 v4l2code; + struct qc_fmt_format const *format; +} const qc_fmt_v4l2s[] = { + { v4l2_fourcc('R','G','B','1'), &qc_fmt_formats_RGB_332 }, /* V4L2_PIX_FMT_RGB332 8 RGB-3-3-2 */ + { v4l2_fourcc('R','G','B','O'), &qc_fmt_formats_RGB_555L }, /* V4L2_PIX_FMT_RGB555 16 RGB-5-5-5 */ + { v4l2_fourcc('R','G','B','P'), &qc_fmt_formats_RGB_565L }, /* V4L2_PIX_FMT_RGB565 16 RGB-5-6-5 */ + { v4l2_fourcc('R','G','B','Q'), &qc_fmt_formats_RGB_555B }, /* V4L2_PIX_FMT_RGB555X 16 RGB-5-5-5 BE */ + { v4l2_fourcc('R','G','B','R'), &qc_fmt_formats_RGB_565B }, /* V4L2_PIX_FMT_RGB565X 16 RGB-5-6-5 BE */ + { v4l2_fourcc('B','G','R','3'), &qc_fmt_formats_BGR_24L }, /* V4L2_PIX_FMT_BGR24 24 BGR-8-8-8 */ + { v4l2_fourcc('R','G','B','3'), &qc_fmt_formats_RGB_24L }, /* V4L2_PIX_FMT_RGB24 24 RGB-8-8-8 */ + { v4l2_fourcc('B','G','R','4'), &qc_fmt_formats_BGR_32L }, /* V4L2_PIX_FMT_BGR32 32 BGR-8-8-8-8 */ + { v4l2_fourcc('R','G','B','4'), &qc_fmt_formats_RGB_32L }, /* V4L2_PIX_FMT_RGB32 32 RGB-8-8-8-8 */ + { v4l2_fourcc('G','R','E','Y'), &qc_fmt_formats_Y800 }, /* V4L2_PIX_FMT_GREY 8 Greyscale */ + { v4l2_fourcc('Y','V','U','9'), &qc_fmt_formats_YVU9 }, /* V4L2_PIX_FMT_YVU410 9 YVU 4:1:0 */ + { v4l2_fourcc('Y','V','1','2'), &qc_fmt_formats_YV12 }, /* V4L2_PIX_FMT_YVU420 12 YVU 4:2:0 */ + { v4l2_fourcc('Y','U','Y','V'), &qc_fmt_formats_YUY2 }, /* V4L2_PIX_FMT_YUYV 16 YUV 4:2:2 */ + { v4l2_fourcc('Y','U','Y','2'), &qc_fmt_formats_YUY2 }, /* V4L2_PIX_FMT_YUY2 16 YUV 4:2:2: undocumented, guess same as YUY2 */ + { v4l2_fourcc('U','Y','V','Y'), &qc_fmt_formats_UYVY }, /* V4L2_PIX_FMT_UYVY 16 YUV 4:2:2 */ + { v4l2_fourcc('Y','4','1','P'), &qc_fmt_formats_Y41P }, /* V4L2_PIX_FMT_Y41P 12 YUV 4:1:1 */ + { v4l2_fourcc('Y','U','V','9'), &qc_fmt_formats_qcU9 }, /* V4L2_PIX_FMT_YUV410 9 YUV 4:1:0 */ + { v4l2_fourcc('Y','U','1','2'), &qc_fmt_formats_IYUV }, /* V4L2_PIX_FMT_YUV420 12 YUV 4:2:0 */ + { v4l2_fourcc('P','4','2','2'), &qc_fmt_formats_qcY2 }, /* V4L2_PIX_FMT_YUV422P 16 YUV422 planar */ + { v4l2_fourcc('P','4','1','1'), &qc_fmt_formats_qcY1 }, /* V4L2_PIX_FMT_YUV411P 16 YUV411 planar: assume bpp should be 12 */ + { v4l2_fourcc('N','V','1','2'), &qc_fmt_formats_NV12 }, /* V4L2_PIX_FMT_NV12 12 Y/UV 4:2:0 */ + { v4l2_fourcc('4','2','2','P'), &qc_fmt_formats_qcV2 }, /* V4L2_PIX_FMT_YVU422P 16 YVU422 planar */ + { v4l2_fourcc('4','1','1','P'), &qc_fmt_formats_qcV1 }, /* V4L2_PIX_FMT_YVU411P 16 YVU411 planar: assume bpp should be 12 */ + { v4l2_fourcc('Y','Y','U','V'), &qc_fmt_formats_qcYY }, /* V4L2_PIX_FMT_YYUV 16 YUV 4:2:2: undocumented, guess this is qc YY */ + { v4l2_fourcc('H','I','2','4'), &qc_fmt_formats_RGB_HI }, /* V4L2_PIX_FMT_HI240 8 8-bit color */ + { v4l2_fourcc('N','V','2','1'), &qc_fmt_formats_NV21 }, /* V4L2_PIX_FMT_NV21 12 Y/UV 4:2:0 */ + { v4l2_fourcc('W','N','V','A'), &qc_fmt_formats_qcWN }, /* V4L2_PIX_FMT_WNVA Winnov hw compres */ +}; +/* }}} */ + +/* {{{ [fold] qc_fmt_issupported(int palette) */ +/* Check the format (can be called even before qc_fmt_init) */ +int qc_fmt_issupported(int palette) +{ + int i; + for (i=0; isupported) + return 0; + } + return -EINVAL; +} +/* }}} */ +/* {{{ [fold] qc_fmt_getname(int palette) */ +/* Return the format name (can be called even before qc_fmt_init) */ +const char *qc_fmt_getname(int palette) +{ + int i; + for (i=0; iname; + } + return "Unknown"; +} +/* }}} */ +/* {{{ [fold] qc_fmt_getdepth(int palette) */ +/* Return bits per pixel for the format, or + * 0=variable number (compressed formats), -1=unknown + * (can be called even before qc_fmt_init) */ +int qc_fmt_getdepth(int palette) +{ + int i; + for (i=0; ibpp; + } + return -1; /* Unknown bit depth */ +} +/* }}} */ +/* {{{ [fold] qc_fmt_init(struct quickcam *qc) */ +int qc_fmt_init(struct quickcam *qc) +{ + int r = 0; + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_fmt_init(qc=%p/compr=%i)",qc,qc->settings.compress); +#if COMPRESS + if (qc->settings.compress) { + qc->fmt_data.compress = TRUE; + r = qc_mjpeg_init(&qc->fmt_data.mjpeg_data, 24, DEFAULT_BGR); + } else { + qc->fmt_data.compress = FALSE; + } +#endif + if (r>=0) IDEBUG_INIT(qc->fmt_data); + return r; +} +/* }}} */ +/* {{{ [fold] qc_fmt_exit(struct quickcam *qc) */ +void qc_fmt_exit(struct quickcam *qc) +{ + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_fmt_exit(qc=%p)",qc); +#if COMPRESS + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_fmt_exit/compress=%i",qc->fmt_data.compress); + if (qc->fmt_data.compress) qc_mjpeg_exit(&qc->fmt_data.mjpeg_data); + POISON(qc->fmt_data.compress); + POISON(qc->fmt_data.mjpeg_data); +#endif + POISON(qc->fmt_data.lut); + IDEBUG_EXIT_NOPOISON(qc->fmt_data); +} +/* }}} */ +/* {{{ [fold] qc_fmt_convert(struct quickcam *qc, unsigned char *src, unsigned int src_len, unsigned char *dst, unsigned int dst_len, int *midvalue) */ +/* Called after each full frame of bayer or compressed image obtained */ +/* Convert camera data in src to the application requested palette in dst */ +/* Return negative error code if failure, otherwise data length stored in dst */ +/* src_len is the length of actual data in src, dst_len is the maximum data size storable in dst */ +/* Also src buffer may be modified */ +/* Return image average brightness in midvalue (or -1 if not computed) */ +int qc_fmt_convert(struct quickcam *qc, unsigned char *src, unsigned int src_len, unsigned char *dst, unsigned int dst_len, int *midvalue) +{ + signed int originx, originy; /* Upper-left corner coordinates of the capture window in the bayer image */ + unsigned char *bayerwin; + int length; /* Converted image data length in bytes */ + int r = 0; + + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_imag_convert(qc=%p,src=%p,src_len=%i,dst=%p,dst_len=%i)",qc,src,src_len,dst,dst_len); + if (PARANOID && (qc==NULL || src==NULL || dst==NULL)) { PRINTK(KERN_CRIT,"NULL"); return -EINVAL; } + if (PARANOID && midvalue==NULL) { PRINTK(KERN_CRIT,"NULL"); return -EINVAL; } + IDEBUG_TEST(qc->fmt_data); + *midvalue = -1; + + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("sensor_width=%i sensor_height=%i vwin.width=%i vwin.height=%i", + qc->sensor_data.width,qc->sensor_data.height,qc->vwin.width,qc->vwin.height); + + if (qc->sensor_data.width < qc->vwin.width || qc->sensor_data.height < qc->vwin.height) { + if (qcdebug&QC_DEBUGERRORS) PDEBUG("sensor window is smaller than requested"); + r = -ENOMSG; + goto fail; + } + +#if DUMPDATA + if (midvalue) *midvalue = -1; + memset(dst, 0, dst_len); + memcpy(dst, src, src_len>dst_len ? dst_len : src_len); + length = (int)qc->vwin.width * (int)qc->vwin.height * 3; + return length; +#endif + +#if COMPRESS + if (!qc->sensor_data.compress) { +#endif + /* src buffer contains fixed length data in bayer format */ + /* sensor_data.height/width = frame size that is captured from the camera */ + /* vwin.height/width = frame size that the application is expecting */ + + /* Check if src buffer contains enough data */ + if (src_len < qc->sensor_data.width * qc->sensor_data.height) { + if (qcdebug&QC_DEBUGERRORS) PDEBUG("too little data by %i (expected %i)", qc->sensor_data.width*qc->sensor_data.height - src_len, qc->sensor_data.width * qc->sensor_data.height); + r = -EBADE; + goto fail; + } + /* calculate view window origin inside the whole frame */ + originy = ((signed int)qc->sensor_data.height - (signed int)qc->vwin.height) / 2; + originx = ((signed int)qc->sensor_data.width - (signed int)qc->vwin.width) / 2; + originx &= ~1; /* Set upper-left corner to a even coordinate */ + originy &= ~1; /* so that the first bayer pixel is green */ + bayerwin = src + originy * qc->sensor_data.width + originx; + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("originy=%i originx=%i", originy,originx); + + if (qc->settings.adaptive && midvalue!=NULL) + *midvalue = qc_imag_bayer_midvalue(bayerwin, qc->sensor_data.width, qc->vwin.width, qc->vwin.height); + if (qc->settings.equalize || qc->settings.userlut) { + if (qc->settings.equalize) { + qc_imag_bayer_equalize(bayerwin, qc->sensor_data.width, qc->vwin.width, qc->vwin.height, &qc->fmt_data.lut); + } else { + /* Initialize LUT */ + int i; + for (i=0; i<256; i++) qc->fmt_data.lut[QC_LUT_RED+i] = i; + for (i=0; i<256; i++) qc->fmt_data.lut[QC_LUT_GREEN+i] = i; + for (i=0; i<256; i++) qc->fmt_data.lut[QC_LUT_BLUE+i] = i; + } + if (qc->settings.userlut) { + qc_imag_userlut(&qc->fmt_data.userlut, &qc->fmt_data.lut); + } + /* Could do here other effects to the lookup table */ + qc_imag_bayer_lut(bayerwin, qc->sensor_data.width, qc->vwin.width, qc->vwin.height, &qc->fmt_data.lut); + } + + if (qc->vpic.palette==VIDEO_PALETTE_BAYER) { + int i; + length = (int)qc->vwin.width * (int)qc->vwin.height; + if (length > dst_len) { + r = -ENOSPC; + goto fail; + } + /* It would be more efficient to capture data directly to the mmapped buffer, + * but more complex and hardly any application will use bayer palette anyway */ + for (i=0; ivwin.height; i++) { + memcpy(dst, bayerwin, qc->vwin.width); + bayerwin += qc->sensor_data.width; + dst += qc->vwin.width; + } + } else { + /* Convert the current frame to RGB */ + length = (int)qc->vwin.width * (int)qc->vwin.height * 3; + if (length > dst_len) { + r = -ENOSPC; + goto fail; + } + switch (qc->settings.quality) { + case 0: + qc_imag_bay2rgb_cottnoip(bayerwin, qc->sensor_data.width, + dst, 3*qc->vwin.width, + qc->vwin.width, qc->vwin.height, 3); + break; + case 1: + qc_imag_bay2rgb_cott(bayerwin, qc->sensor_data.width, + dst, 3*qc->vwin.width, + qc->vwin.width, qc->vwin.height, 3); + break; + case 2: + qc_imag_bay2rgb_horip(bayerwin, qc->sensor_data.width, + dst, 3*qc->vwin.width, + qc->vwin.width, qc->vwin.height, 3); + break; + case 3: + qc_imag_bay2rgb_ip(bayerwin, qc->sensor_data.width, + dst, 3*qc->vwin.width, + qc->vwin.width, qc->vwin.height, 3); + break; + default: + case 4: + qc_imag_bay2rgb_gptm_fast(bayerwin, qc->sensor_data.width, + dst, 3*qc->vwin.width, + qc->vwin.width, qc->vwin.height, 3); + break; + case 5: + qc_imag_bay2rgb_gptm(bayerwin, qc->sensor_data.width, + dst, 3*qc->vwin.width, + qc->vwin.width, qc->vwin.height, 3, qc->vpic.whiteness); + break; + } + goto rgb24; + } + +#if COMPRESS + } else { + /* src buffer contains variable length data in mjpeg format */ + if (qc->vpic.palette==VIDEO_PALETTE_MJPEG) { + /* Directly copy data from src to dst, can not resize */ + length = src_len; + if (length > dst_len) { + r = -ENOSPC; + goto fail; + } + memcpy(dst, src, src_len); + } else { + /* Decode compressed images */ + if (!qc->fmt_data.compress) { + r = -EINVAL; + goto fail; + } + length = qc->sensor_data.width * qc->sensor_data.height * 3; + if (length > dst_len) { + r = -ENOSPC; + goto fail; + } + r = qc_mjpeg_decode(&qc->fmt_data.mjpeg_data, src, src_len, dst); + if (r<0) goto fail; + + if ((int)qc->vwin.width < qc->sensor_data.width || (int)qc->vwin.height < qc->sensor_data.height) { + /* User requested smaller image than camera sent, so crop the image */ + unsigned char *s, *d = dst; + int i; + s = dst; + s += (qc->sensor_data.height - (int)qc->vwin.height)/2 * qc->sensor_data.width*3; + s += (qc->sensor_data.width - (int)qc->vwin.width)/2 * 3; + for (i=0; ivwin.height; i++) { + memcpy(d, s, (int)qc->vwin.width*3); + s += qc->sensor_data.width * 3; + d += (int)qc->vwin.width * 3; + } + /* vwin.width/height is always smaller or equal to sensor_data.width/height */ + length = (int)qc->vwin.width * (int)qc->vwin.height * 3; + } + if (qc->settings.adaptive && midvalue!=NULL) *midvalue = qc_imag_rgb24_midvalue(dst, 3*qc->sensor_data.width, (int)qc->vwin.width, (int)qc->vwin.height); + goto rgb24; + } + } +#endif + return length; + +rgb24: /* We have now RGB (24 bpp) data in dst. If some other format is desired, */ + /* convert the RGB image to it (e.g. YUV) */ + +#ifdef DEBUG +#if 1 +{ +/* Draw red rectangle around image (useful for debugging boundaries) */ +static const int R = 255; +static const int G = 0; +static const int B = 0; + int ty,tx; + for (tx=0; txvwin.width; tx++) { + ty=0; + dst[ty*qc->vwin.width*3+tx*3] = B; + dst[ty*qc->vwin.width*3+tx*3+1] = G; + dst[ty*qc->vwin.width*3+tx*3+2] = R; + ty=qc->vwin.height-1; + dst[ty*qc->vwin.width*3+tx*3] = B; + dst[ty*qc->vwin.width*3+tx*3+1] = G; + dst[ty*qc->vwin.width*3+tx*3+2] = R; + } + for (ty=0; tyvwin.height; ty++) { + tx=0; + dst[ty*qc->vwin.width*3+tx*3] = B; + dst[ty*qc->vwin.width*3+tx*3+1] = G; + dst[ty*qc->vwin.width*3+tx*3+2] = R; + tx=qc->vwin.width-1; + dst[ty*qc->vwin.width*3+tx*3] = B; + dst[ty*qc->vwin.width*3+tx*3+1] = G; + dst[ty*qc->vwin.width*3+tx*3+2] = R; + } +} +#endif +#endif + + if (qc->vpic.palette != VIDEO_PALETTE_RGB24) { + // FIXME: should check here that dst_len <= resulted image length + length = qc_yuv_rgb2yuv(dst, length, qc->vpic.palette); + } else if (qc->settings.compat_torgb) { + qc_imag_rgbbgr(dst, length/3, 3); + } + return length; + +fail: if (qcdebug&(QC_DEBUGERRORS|QC_DEBUGLOGIC)) PDEBUG("failed qc_imag_convert()=%i",r); + return r; +} +/* }}} */ + +/* }}} */ + +/* End of file */ --- linux-2.6.27.orig/ubuntu/qc-usb/videodev2.h +++ linux-2.6.27/ubuntu/qc-usb/videodev2.h @@ -0,0 +1,1156 @@ +/* + * Video for Linux Two + * + * Header file for V4L2 drivers and applications. + * + * Author: Bill Dirks + */ + +#ifndef __LINUX_VIDEODEV_H +#define __LINUX_VIDEODEV_H + +#define V4L2_MAJOR_VERSION 0 +#define V4L2_MINOR_VERSION 20 + +#include "videodevfix.h" + + +/* + * M I S C E L L A N E O U S + */ + +/* Four-character-code (FOURCC) */ +#define fourcc(a,b,c,d)\ + (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24)) + +/* Open flag for non-capturing opens on capture devices */ +#define O_NONCAP O_TRUNC +#define O_NOIO O_TRUNC + +/* Timestamp data type, 64-bit signed integer */ +/* Should be removed from here when UST is added to kernel */ +#ifndef STAMP_T +#define STAMP_T +typedef __s64 stamp_t; +#endif + +/* + * D R I V E R C A P A B I L I T I E S + */ +struct v4l2_capability +{ + char name[32]; /* Descriptive, and unique */ + int type; /* Device type, see below */ + int inputs; /* Num video inputs */ + int outputs; /* Num video outputs */ + int audios; /* Num audio devices */ + int maxwidth; + int maxheight; + int minwidth; + int minheight; + int maxframerate; + __u32 flags; /* Feature flags, see below */ + __u32 reserved[4]; +}; +/* Values for 'type' field */ +#define V4L2_TYPE_CAPTURE 0 /* Is a video capture device */ +#define V4L2_TYPE_CODEC 1 /* Is a CODEC device */ +#define V4L2_TYPE_OUTPUT 2 /* Is a video output device */ +#define V4L2_TYPE_FX 3 /* Is a video effects device */ +#define V4L2_TYPE_VBI 4 /* Is a VBI capture device */ +#define V4L2_TYPE_VTR 5 /* Is a tape recorder controller */ +#define V4L2_TYPE_VTX 6 /* Is a teletext device */ +#define V4L2_TYPE_RADIO 7 /* Is a radio device */ +#define V4L2_TYPE_PRIVATE 1000 /* Start of driver private types */ +/* Flags for 'flags' field */ +#define V4L2_FLAG_READ 0x00001 /* Can capture via read() call */ +#define V4L2_FLAG_WRITE 0x00002 /* Can accept data via write() */ +#define V4L2_FLAG_STREAMING 0x00004 /* Can capture streaming video */ +#define V4L2_FLAG_PREVIEW 0x00008 /* Can do automatic preview */ +#define V4L2_FLAG_SELECT 0x00010 /* Supports the select() call */ +#define V4L2_FLAG_TUNER 0x00020 /* Can tune */ +#define V4L2_FLAG_MONOCHROME 0x00040 /* Monochrome only */ +#define V4L2_FLAG_DATA_SERVICE 0x00080 /* Has a related data service dev. */ + + +/* + * V I D E O I M A G E F O R M A T + */ +struct v4l2_pix_format +{ + __u32 width; + __u32 height; + __u32 depth; + __u32 pixelformat; + __u32 flags; + __u32 bytesperline; /* only used when there are pad bytes */ + __u32 sizeimage; + __u32 priv; /* private data, depends on pixelformat */ +}; +/* Pixel format FOURCC depth Description */ +#define V4L2_PIX_FMT_RGB332 fourcc('R','G','B','1') /* 8 RGB-3-3-2 */ +#define V4L2_PIX_FMT_RGB555 fourcc('R','G','B','O') /* 16 RGB-5-5-5 */ +#define V4L2_PIX_FMT_RGB565 fourcc('R','G','B','P') /* 16 RGB-5-6-5 */ +#define V4L2_PIX_FMT_BGR24 fourcc('B','G','R','3') /* 24 BGR-8-8-8 */ +#define V4L2_PIX_FMT_RGB24 fourcc('R','G','B','3') /* 24 RGB-8-8-8 */ +#define V4L2_PIX_FMT_BGR32 fourcc('B','G','R','4') /* 32 BGR-8-8-8-8 */ +#define V4L2_PIX_FMT_RGB32 fourcc('R','G','B','4') /* 32 RGB-8-8-8-8 */ +#define V4L2_PIX_FMT_GREY fourcc('G','R','E','Y') /* 8 Greyscale */ +#define V4L2_PIX_FMT_YVU410 fourcc('Y','V','U','9') /* 9 YVU 4:1:0 */ +#define V4L2_PIX_FMT_YVU420 fourcc('Y','V','1','2') /* 12 YVU 4:2:0 */ +#define V4L2_PIX_FMT_YUYV fourcc('Y','U','Y','V') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_UYVY fourcc('U','Y','V','Y') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_YVU422P fourcc('4','2','2','P') /* 16 YVU422 planar */ +#define V4L2_PIX_FMT_YVU411P fourcc('4','1','1','P') /* 16 YVU411 planar */ + +/* The following formats are not defined in the V4L2 specification */ +#define V4L2_PIX_FMT_YUV410 fourcc('Y','U','V','9') /* 9 YUV 4:1:0 */ +#define V4L2_PIX_FMT_YUV420 fourcc('Y','U','1','2') /* 12 YUV 4:2:0 */ +#define V4L2_PIX_FMT_YYUV fourcc('Y','Y','U','V') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_HI240 fourcc('H','I','2','4') /* 8 8-bit color */ + + +/* Flags */ +#define V4L2_FMT_FLAG_COMPRESSED 0x0001 /* Compressed format */ +#define V4L2_FMT_FLAG_BYTESPERLINE 0x0002 /* bytesperline field valid */ +#define V4L2_FMT_FLAG_INTERLACED 0x0004 /* Image is interlaced */ +#define V4L2_FMT_FLAG_TOPFIELD 0x0008 /* is a top field only */ +#define V4L2_FMT_FLAG_BOTFIELD 0x0010 /* is a bottom field only */ +#define V4L2_FMT_FLAG_ODDFIELD V4L2_FMT_FLAG_TOPFIELD +#define V4L2_FMT_FLAG_EVENFIELD V4L2_FMT_FLAG_BOTFIELD +#define V4L2_FMT_FLAG_COMBINED V4L2_FMT_FLAG_INTERLACED +#define V4L2_FMT_CS_field 0xF000 /* Color space field mask */ +#define V4L2_FMT_CS_601YUV 0x1000 /* ITU YCrCb color space */ +#define V4L2_FMT_FLAG_SWCONVERSION 0x0800 /* used only in format enum. */ +/* SWCONVERSION indicates the format is not natively supported by the */ +/* driver and the driver uses software conversion to support it */ + + +/* + * F O R M A T E N U M E R A T I O N + */ +struct v4l2_fmtdesc +{ + int index; /* Format number */ + char description[32]; /* Description string */ + __u32 pixelformat; /* Format fourcc */ + __u32 flags; /* Format flags */ + __u32 depth; /* Bits per pixel */ + __u32 reserved[2]; +}; + +struct v4l2_cvtdesc +{ + int index; + struct + { + __u32 pixelformat; + __u32 flags; + __u32 depth; + __u32 reserved[2]; + } in, out; +}; + +struct v4l2_fxdesc +{ + int index; + char name[32]; + __u32 flags; + __u32 inputs; + __u32 controls; + __u32 reserved[2]; +}; + + +/* + * T I M E C O D E + */ +struct v4l2_timecode +{ + __u8 frames; + __u8 seconds; + __u8 minutes; + __u8 hours; + __u8 userbits[4]; + __u32 flags; + __u32 type; +}; +/* Type */ +#define V4L2_TC_TYPE_24FPS 1 +#define V4L2_TC_TYPE_25FPS 2 +#define V4L2_TC_TYPE_30FPS 3 +#define V4L2_TC_TYPE_50FPS 4 +#define V4L2_TC_TYPE_60FPS 5 + + +/* Flags */ +#define V4L2_TC_FLAG_DROPFRAME 0x0001 /* "drop-frame" mode */ +#define V4L2_TC_FLAG_COLORFRAME 0x0002 +#define V4L2_TC_USERBITS_field 0x000C +#define V4L2_TC_USERBITS_USERDEFINED 0x0000 +#define V4L2_TC_USERBITS_8BITCHARS 0x0008 +/* The above is based on SMPTE timecodes */ + + +/* + * C O M P R E S S I O N P A R A M E T E R S + */ +struct v4l2_compression +{ + int quality; + int keyframerate; + int pframerate; + __u32 reserved[5]; +}; + + +/* + * M E M O R Y - M A P P I N G B U F F E R S + */ +struct v4l2_requestbuffers +{ + int count; + __u32 type; + __u32 reserved[2]; +}; +struct v4l2_buffer +{ + int index; + __u32 type; + __u32 offset; + __u32 length; + __u32 bytesused; + __u32 flags; + stamp_t timestamp; + struct v4l2_timecode timecode; + __u32 sequence; + __u32 reserved[3]; +}; +/* Buffer type codes and flags for 'type' field */ +#define V4L2_BUF_TYPE_field 0x00001FFF /* Type field mask */ +#define V4L2_BUF_TYPE_CAPTURE 0x00000001 +#define V4L2_BUF_TYPE_CODECIN 0x00000002 +#define V4L2_BUF_TYPE_CODECOUT 0x00000003 +#define V4L2_BUF_TYPE_EFFECTSIN 0x00000004 +#define V4L2_BUF_TYPE_EFFECTSIN2 0x00000005 +#define V4L2_BUF_TYPE_EFFECTSOUT 0x00000006 +#define V4L2_BUF_TYPE_VIDEOOUT 0x00000007 +#define V4L2_BUF_TYPE_FXCONTROL 0x00000008 + +/* Starting value of driver private buffer types */ +#define V4L2_BUF_TYPE_PRIVATE 0x00001000 + +#define V4L2_BUF_ATTR_DEVICEMEM 0x00010000 /* Buffer is on device (flag) */ + +/* Flags used only in VIDIOC_REQBUFS */ +#define V4L2_BUF_REQ_field 0xF0000000 +#define V4L2_BUF_REQ_CONTIG 0x10000000 /* Map all buffers in one + contiguous mmap(). This flag + only used in VIDIOC_REQBUFS */ + +/* Flags for 'flags' field */ +#define V4L2_BUF_FLAG_MAPPED 0x0001 /* Buffer is mapped (flag) */ +#define V4L2_BUF_FLAG_QUEUED 0x0002 /* Buffer is queued for processing */ +#define V4L2_BUF_FLAG_DONE 0x0004 /* Buffer is ready */ +#define V4L2_BUF_FLAG_KEYFRAME 0x0008 /* Image is a keyframe (I-frame) */ +#define V4L2_BUF_FLAG_PFRAME 0x0010 /* Image is a P-frame */ +#define V4L2_BUF_FLAG_BFRAME 0x0020 /* Image is a B-frame */ +#define V4L2_BUF_FLAG_TOPFIELD 0x0040 /* Image is a top field only */ +#define V4L2_BUF_FLAG_BOTFIELD 0x0080 /* Image is a bottom field only */ +#define V4L2_BUF_FLAG_ODDFIELD V4L2_BUF_FLAG_TOPFIELD +#define V4L2_BUF_FLAG_EVENFIELD V4L2_BUF_FLAG_BOTFIELD +#define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */ + +/* + * O V E R L A Y P R E V I E W + */ +struct v4l2_framebuffer +{ + __u32 capability; + __u32 flags; + void *base[3]; + struct v4l2_pix_format fmt; +}; +/* Flags for the 'capability' field. Read only */ +#define V4L2_FBUF_CAP_EXTERNOVERLAY 0x0001 +#define V4L2_FBUF_CAP_CHROMAKEY 0x0002 +#define V4L2_FBUF_CAP_CLIPPING 0x0004 +#define V4L2_FBUF_CAP_SCALEUP 0x0008 +#define V4L2_FBUF_CAP_SCALEDOWN 0x0010 +#define V4L2_FBUF_CAP_BITMAP_CLIPPING 0x0020 +/* Flags for the 'flags' field. */ +#define V4L2_FBUF_FLAG_PRIMARY 0x0001 +#define V4L2_FBUF_FLAG_OVERLAY 0x0002 +#define V4L2_FBUF_FLAG_CHROMAKEY 0x0004 + +struct v4l2_clip +{ + int x; + int y; + int width; + int height; + struct v4l2_clip *next; +}; +struct v4l2_window +{ + int x; + int y; + int width; + int height; + __u32 chromakey; + struct v4l2_clip *clips; + int clipcount; + void *bitmap; +}; + + +/* + * D E V I C E P E R F O R M A N C E + */ +struct v4l2_performance +{ + int frames; + int framesdropped; + __u64 bytesin; + __u64 bytesout; + __u32 reserved[4]; +}; + +/* + * C A P T U R E P A R A M E T E R S + */ +struct v4l2_captureparm +{ + __u32 capability; /* Supported modes */ + __u32 capturemode; /* Current mode */ + unsigned long timeperframe; /* Time per frame in .1us units */ + __u32 extendedmode; /* Driver-specific extensions */ + __u32 reserved[4]; +}; +/* Flags for 'capability' and 'capturemode' fields */ +#define V4L2_MODE_HIGHQUALITY 0x0001 /* High quality imaging mode */ +//#define V4L2_MODE_VFLIP 0x0002 /* Flip image vertically */ +//#define V4L2_MODE_HFLIP 0x0004 /* Flip image horizontally */ +#define V4L2_CAP_TIMEPERFRAME 0x1000 /* timeperframe field is supported */ + +struct v4l2_outputparm +{ + __u32 capability; /* Supported modes */ + __u32 outputmode; /* Current mode */ + unsigned long timeperframe; /* Time per frame in .1us units */ + __u32 extendedmode; /* Driver-specific extensions */ + __u32 reserved[4]; +}; + +/* + * I N P U T I M A G E C R O P P I N G + */ +struct v4l2_cropcap +{ + __u32 capability; + int min_x; + int min_y; + int max_x; + int max_y; + int default_left; + int default_top; + int default_right; + int default_bottom; + __u32 reserved[2]; +}; +struct v4l2_crop +{ + int left; + int top; + int right; + int bottom; + __u32 reserved; +}; + +/* + * D I G I T A L Z O O M + */ +struct v4l2_zoomcap +{ + __u32 capability; + __u32 maxwidth; + __u32 maxheight; + __u32 minwidth; + __u32 minheight; + __u32 reserved[2]; +}; +/* Flags for the capability field */ +#define V4L2_ZOOM_NONCAP 0x0001 +#define V4L2_ZOOM_WHILESTREAMING 0x0002 + +struct v4l2_zoom +{ + __u32 x; + __u32 y; + __u32 width; + __u32 height; + __u32 reserved; +}; + + +/* + * A N A L O G V I D E O S T A N D A R D + */ +struct v4l2_standard +{ + __u8 name[24]; + struct { + __u32 numerator; + __u32 denominator; /* >= 1 */ + } framerate; /* Frames, not fields */ + __u32 framelines; + __u32 reserved1; + __u32 colorstandard; + union { + struct { + __u32 colorsubcarrier; /* Hz */ + } pal; + struct { + __u32 colorsubcarrier; /* Hz */ + } ntsc; + struct { + __u32 f0b; /* Hz (blue) */ + __u32 f0r; /* Hz (red) */ + } secam; + __u8 reserved[12]; + } colorstandard_data; + __u32 transmission; /* Bit field. Must be zero for + non-modulators/demodulators. */ + __u32 reserved2; /* Must be set to zero */ +}; + +/* Values for the 'colorstandard' field */ +#define V4L2_COLOR_STD_PAL 1 +#define V4L2_COLOR_STD_NTSC 2 +#define V4L2_COLOR_STD_SECAM 3 + +/* Values for the color subcarrier fields */ +#define V4L2_COLOR_SUBC_PAL 4433619 /* PAL BGHI, NTSC-44 */ +#define V4L2_COLOR_SUBC_PAL_M 3575611 /* PAL M (Brazil) */ +#define V4L2_COLOR_SUBC_PAL_N 3582056 /* PAL N */ +#define V4L2_COLOR_SUBC_NTSC 3579545 /* NTSC M, NTSC-Japan */ +#define V4L2_COLOR_SUBC_SECAMB 4250000 /* SECAM B - Y carrier */ +#define V4L2_COLOR_SUBC_SECAMR 4406250 /* SECAM R - Y carrier */ + +/* Flags for the 'transmission' field */ +#define V4L2_TRANSM_STD_B (1<<1) +#define V4L2_TRANSM_STD_D (1<<3) +#define V4L2_TRANSM_STD_G (1<<6) +#define V4L2_TRANSM_STD_H (1<<7) +#define V4L2_TRANSM_STD_I (1<<8) +#define V4L2_TRANSM_STD_K (1<<10) +#define V4L2_TRANSM_STD_K1 (1<<11) +#define V4L2_TRANSM_STD_L (1<<12) +#define V4L2_TRANSM_STD_M (1<<13) +#define V4L2_TRANSM_STD_N (1<<14) + + +/* Used in the VIDIOC_ENUMSTD ioctl for querying supported standards */ +struct v4l2_enumstd +{ + int index; + struct v4l2_standard std; + __u32 inputs; /* set of inputs that */ + /* support this standard */ + __u32 outputs; /* set of outputs that */ + /* support this standard */ + __u32 reserved[2]; +}; + + +/* + * V I D E O I N P U T S + */ +struct v4l2_input +{ + int index; /* Which input */ + char name[32]; /* Label */ + int type; /* Type of input */ + __u32 capability; /* Capability flags */ + int assoc_audio; /* Associated audio input */ + __u32 reserved[4]; +}; +/* Values for the 'type' field */ +#define V4L2_INPUT_TYPE_TUNER 1 +#define V4L2_INPUT_TYPE_CAMERA 2 + +/* Flags for the 'capability' field */ +#define V4L2_INPUT_CAP_AUDIO 0x0001 /* assoc_audio */ + + +/* + * V I D E O O U T P U T S + */ +struct v4l2_output +{ + int index; /* Which output */ + char name[32]; /* Label */ + int type; /* Type of output */ + __u32 capability; /* Capability flags */ + int assoc_audio; /* Associated audio */ + __u32 reserved[4]; +}; +/* Values for the 'type' field */ +#define V4L2_OUTPUT_TYPE_MODULATOR 1 +#define V4L2_OUTPUT_TYPE_ANALOG 2 +#define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 + +/* Flags for the 'capability' field */ +#define V4L2_OUTPUT_CAP_AUDIO 0x0001 /* assoc_audio */ + + +/* + * C O N T R O L S + */ +struct v4l2_control +{ + __u32 id; + int value; +}; + +/* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */ +struct v4l2_queryctrl +{ + __u32 id; + __u8 name[32]; /* Whatever */ + int minimum; /* Note signedness */ + int maximum; + unsigned int step; + int default_value; + __u32 type; + __u32 flags; + __u32 category; /* Automatically filled in by V4L2 */ + __u8 group[32]; /* for pre-defined controls */ + __u32 reserved[2]; +}; + +/* Used in the VIDIOC_QUERYMENU ioctl for querying menu items */ +struct v4l2_querymenu +{ + __u32 id; + int index; + __u8 name[32]; /* Whatever */ + int reserved; +}; + +/* Used in V4L2_BUF_TYPE_FXCONTROL buffers */ +struct v4l2_fxcontrol +{ + __u32 id; + __u32 value; +}; + +/* Control types */ +#define V4L2_CTRL_TYPE_INTEGER 0 +#define V4L2_CTRL_TYPE_BOOLEAN 1 +#define V4L2_CTRL_TYPE_MENU 2 +#define V4L2_CTRL_TYPE_BUTTON 3 + +/* Control flags */ +#define V4L2_CTRL_FLAG_DISABLED 0x0001 +#define V4L2_CTRL_FLAG_GRABBED 0x0002 + +/* Control categories */ +#define V4L2_CTRL_CAT_VIDEO 1 /* "Video" */ +#define V4L2_CTRL_CAT_AUDIO 2 /* "Audio" */ +#define V4L2_CTRL_CAT_EFFECT 3 /* "Effect" */ + +/* Control IDs defined by V4L2 */ +#define V4L2_CID_BASE 0x00980900 +/* IDs reserved for driver specific controls */ +#define V4L2_CID_PRIVATE_BASE 0x08000000 +/* IDs reserved for effect-specific controls on effects devices */ +#define V4L2_CID_EFFECT_BASE 0x0A00B000 + +#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0) +#define V4L2_CID_CONTRAST (V4L2_CID_BASE+1) +#define V4L2_CID_SATURATION (V4L2_CID_BASE+2) +#define V4L2_CID_HUE (V4L2_CID_BASE+3) +#define V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE+5) +#define V4L2_CID_AUDIO_BALANCE (V4L2_CID_BASE+6) +#define V4L2_CID_AUDIO_BASS (V4L2_CID_BASE+7) +#define V4L2_CID_AUDIO_TREBLE (V4L2_CID_BASE+8) +#define V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9) +#define V4L2_CID_AUDIO_LOUDNESS (V4L2_CID_BASE+10) +#define V4L2_CID_BLACK_LEVEL (V4L2_CID_BASE+11) +#define V4l2_CID_AUTO_WHITE_BALANCE (V4L2_CID_BASE+12) +#define V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13) +#define V4L2_CID_RED_BALANCE (V4L2_CID_BASE+14) +#define V4L2_CID_BLUE_BALANCE (V4L2_CID_BASE+15) +#define V4L2_CID_GAMMA (V4L2_CID_BASE+16) +#define V4L2_CID_WHITENESS (V4L2_CID_GAMMA) /* ? Not sure */ +#define V4L2_CID_EXPOSURE (V4L2_CID_BASE+17) +#define V4L2_CID_AUTOGAIN (V4L2_CID_BASE+18) +#define V4L2_CID_GAIN (V4L2_CID_BASE+19) +#define V4L2_CID_HFLIP (V4L2_CID_BASE+20) +#define V4L2_CID_VFLIP (V4L2_CID_BASE+21) +#define V4L2_CID_HCENTER (V4L2_CID_BASE+22) +#define V4L2_CID_VCENTER (V4l2_CID_BASE+23) +#define V4L2_CID_LASTP1 (V4L2_CID_BASE+24) /* last CID + 1 */ +/* Remember to change fill_ctrl_category() in videodev.c */ + +/* + * T U N I N G + */ +struct v4l2_tuner +{ + int input; + char name[32]; + struct v4l2_standard std; + __u32 capability; + __u32 rangelow; + __u32 rangehigh; + __u32 rxsubchans; + __u32 audmode; + int signal; + int afc; + __u32 reserved[4]; +}; +struct v4l2_modulator +{ + int output; + char name[32]; + struct v4l2_standard std; + __u32 capability; + __u32 rangelow; + __u32 rangehigh; + __u32 txsubchans; + __u32 reserved[4]; +}; +/* Flags for the 'capability' field */ +#define V4L2_TUNER_CAP_LOW 0x0001 +#define V4L2_TUNER_CAP_NORM 0x0002 +#define V4L2_TUNER_CAP_STEREO 0x0010 +#define V4L2_TUNER_CAP_LANG2 0x0020 +#define V4L2_TUNER_CAP_SAP 0x0020 +#define V4L2_TUNER_CAP_LANG1 0x0040 + +/* Flags for the 'rxsubchans' field */ +#define V4L2_TUNER_SUB_MONO 0x0001 +#define V4L2_TUNER_SUB_STEREO 0x0002 +#define V4L2_TUNER_SUB_LANG2 0x0004 +#define V4L2_TUNER_SUB_SAP 0x0004 +#define V4L2_TUNER_SUB_LANG1 0x0008 + +/* Values for the 'audmode' field */ +#define V4L2_TUNER_MODE_MONO 0x0000 +#define V4L2_TUNER_MODE_STEREO 0x0001 +#define V4L2_TUNER_MODE_LANG2 0x0002 +#define V4L2_TUNER_MODE_SAP 0x0002 +#define V4L2_TUNER_MODE_LANG1 0x0003 + +struct v4l2_frequency +{ + int port; + __u32 frequency; + __u32 reserved[2]; +}; + +/* + * A U D I O + */ +struct v4l2_audio +{ + int audio; + char name[32]; + __u32 capability; + __u32 mode; + __u32 reserved[2]; +}; +/* Flags for the 'capability' field */ +#define V4L2_AUDCAP_EFFECTS 0x0020 +#define V4L2_AUDCAP_LOUDNESS 0x0040 +#define V4L2_AUDCAP_AVL 0x0080 + +/* Flags for the 'mode' field */ +#define V4L2_AUDMODE_LOUDNESS 0x00002 +#define V4L2_AUDMODE_AVL 0x00004 +#define V4L2_AUDMODE_STEREO_field 0x0FF00 +#define V4L2_AUDMODE_STEREO_LINEAR 0x00100 +#define V4L2_AUDMODE_STEREO_PSEUDO 0x00200 +#define V4L2_AUDMODE_STEREO_SPATIAL30 0x00300 +#define V4L2_AUDMODE_STEREO_SPATIAL50 0x00400 + +struct v4l2_audioout +{ + int audio; + char name[32]; + __u32 capability; + __u32 mode; + __u32 reserved[2]; +}; + +/* + * D A T A S E R V I C E S ( V B I ) + */ + +struct v4l2_vbi_format +{ + __u32 sampling_rate; /* in 1 Hz */ + __u32 reserved1; /* must be zero */ + __u32 samples_per_line; + __u32 sample_format; /* V4L2_VBI_SF_* */ + __s32 start[2]; + __u32 count[2]; + __u32 flags; /* V4L2_VBI_* */ + __u32 reserved2; /* must be zero */ +}; + +/* VBI sampling formats */ +#define V4L2_VBI_SF_UBYTE 1 + +/* VBI flags */ +#define V4L2_VBI_UNSYNC (1<< 0) +#define V4L2_VBI_INTERLACED (1<< 1) + + +/* + * A G G R E G A T E S T R U C T U R E S + */ + +/* Stream data format + */ +struct v4l2_format +{ + __u32 type; + union + { + struct v4l2_pix_format pix; /* image format */ + struct v4l2_vbi_format vbi; /* VBI data */ + /* add more */ + __u8 raw_data[200]; /* user-defined */ + } fmt; +}; + + +/* Stream type-dependent parameters + */ +struct v4l2_streamparm +{ + __u32 type; + union + { + struct v4l2_captureparm capture; + struct v4l2_outputparm output; + /* add more */ + __u8 raw_data[200]; /* user-defined */ + } parm; +}; + + + +/* + * I O C T L C O D E S F O R V I D E O D E V I C E S + * + */ +#define VIDIOC_QUERYCAP _IOR ('V', 0, struct v4l2_capability) +#define VIDIOC_RESERVED _IO ('V', 1) +#define VIDIOC_ENUM_PIXFMT _IOWR ('V', 2, struct v4l2_fmtdesc) +#define VIDIOC_ENUM_FBUFFMT _IOWR ('V', 3, struct v4l2_fmtdesc) +#define VIDIOC_G_FMT _IOWR ('V', 4, struct v4l2_format) +#define VIDIOC_S_FMT _IOWR ('V', 5, struct v4l2_format) +#define VIDIOC_G_COMP _IOR ('V', 6, struct v4l2_compression) +#define VIDIOC_S_COMP _IOW ('V', 7, struct v4l2_compression) +#define VIDIOC_REQBUFS _IOWR ('V', 8, struct v4l2_requestbuffers) +#define VIDIOC_QUERYBUF _IOWR ('V', 9, struct v4l2_buffer) +#define VIDIOC_G_FBUF _IOR ('V', 10, struct v4l2_framebuffer) +#define VIDIOC_S_FBUF _IOW ('V', 11, struct v4l2_framebuffer) +#define VIDIOC_G_WIN _IOR ('V', 12, struct v4l2_window) +#define VIDIOC_S_WIN _IOW ('V', 13, struct v4l2_window) +#define VIDIOC_PREVIEW _IOWR ('V', 14, int) +#define VIDIOC_QBUF _IOWR ('V', 15, struct v4l2_buffer) +#define VIDIOC_DQBUF _IOWR ('V', 17, struct v4l2_buffer) +#define VIDIOC_STREAMON _IOW ('V', 18, int) +#define VIDIOC_STREAMOFF _IOW ('V', 19, int) +#define VIDIOC_G_PERF _IOR ('V', 20, struct v4l2_performance) +#define VIDIOC_G_PARM _IOWR ('V', 21, struct v4l2_streamparm) +#define VIDIOC_S_PARM _IOW ('V', 22, struct v4l2_streamparm) +#define VIDIOC_G_STD _IOR ('V', 23, struct v4l2_standard) +#define VIDIOC_S_STD _IOW ('V', 24, struct v4l2_standard) +#define VIDIOC_ENUMSTD _IOWR ('V', 25, struct v4l2_enumstd) +#define VIDIOC_ENUMINPUT _IOWR ('V', 26, struct v4l2_input) +#define VIDIOC_G_CTRL _IOWR ('V', 27, struct v4l2_control) +#define VIDIOC_S_CTRL _IOW ('V', 28, struct v4l2_control) +#define VIDIOC_G_TUNER _IOWR ('V', 29, struct v4l2_tuner) +#define VIDIOC_S_TUNER _IOW ('V', 30, struct v4l2_tuner) +#define VIDIOC_G_FREQ _IOR ('V', 31, int) +#define VIDIOC_S_FREQ _IOWR ('V', 32, int) +#define VIDIOC_G_AUDIO _IOWR ('V', 33, struct v4l2_audio) +#define VIDIOC_S_AUDIO _IOW ('V', 34, struct v4l2_audio) +#define VIDIOC_QUERYCTRL _IOWR ('V', 36, struct v4l2_queryctrl) +#define VIDIOC_QUERYMENU _IOWR ('V', 37, struct v4l2_querymenu) +#define VIDIOC_G_INPUT _IOR ('V', 38, int) +#define VIDIOC_S_INPUT _IOWR ('V', 39, int) +#define VIDIOC_ENUMCVT _IOWR ('V', 40, struct v4l2_cvtdesc) +#define VIDIOC_G_OUTPUT _IOR ('V', 46, int) +#define VIDIOC_S_OUTPUT _IOWR ('V', 47, int) +#define VIDIOC_ENUMOUTPUT _IOWR ('V', 48, struct v4l2_output) +#define VIDIOC_G_AUDOUT _IOWR ('V', 49, struct v4l2_audioout) +#define VIDIOC_S_AUDOUT _IOW ('V', 50, struct v4l2_audioout) +#define VIDIOC_ENUMFX _IOWR ('V', 51, struct v4l2_fxdesc) +#define VIDIOC_G_EFFECT _IOR ('V', 52, int) +#define VIDIOC_S_EFFECT _IOWR ('V', 53, int) +#define VIDIOC_G_MODULATOR _IOWR ('V', 54, struct v4l2_modulator) +#define VIDIOC_S_MODULATOR _IOW ('V', 55, struct v4l2_modulator) + +#define VIDIOC_ENUM_CAPFMT VIDIOC_ENUM_PIXFMT +#define VIDIOC_ENUM_OUTFMT VIDIOC_ENUM_PIXFMT +#define VIDIOC_ENUM_SRCFMT VIDIOC_ENUM_PIXFMT +#define VIDIOC_ENUMFMT VIDIOC_ENUM_PIXFMT + +#define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */ + + +#ifdef __KERNEL__ +/* + * These things are used only by drivers. + */ + +extern int videodev_init(void); + +/* + * + * V 4 L 2 D R I V E R H E L P E R A P I + * + * Some commonly needed functions for drivers. + */ + +extern void v4l2_version(int *major, int *minor); +extern int v4l2_major_number(void); + +/* Memory management */ +extern unsigned long v4l2_vmalloc_to_bus(void *virt); +extern unsigned long v4l2_vmalloc_to_page(void *virt); + +/* Simple queue management */ +struct v4l2_q_node +{ + struct v4l2_q_node *forw, *back; +}; +struct v4l2_queue +{ + struct v4l2_q_node *forw, *back; + rwlock_t qlock; +}; +extern void v4l2_q_init(struct v4l2_queue *q); +extern void v4l2_q_add_head(struct v4l2_queue *q, struct v4l2_q_node *node); +extern void v4l2_q_add_tail(struct v4l2_queue *q, struct v4l2_q_node *node); +extern void *v4l2_q_del_head(struct v4l2_queue *q); +extern void *v4l2_q_del_tail(struct v4l2_queue *q); +extern void *v4l2_q_peek_head(struct v4l2_queue *q); +extern void *v4l2_q_peek_tail(struct v4l2_queue *q); +extern void *v4l2_q_yank_node(struct v4l2_queue *q, struct v4l2_q_node *node); + +/* Math functions */ +extern u32 v4l2_math_div6432(u64 a, u32 d, u32 *r); + +/* Time functions */ +extern unsigned long v4l2_timestamp_divide(stamp_t t, + unsigned long p_100ns); +extern unsigned long v4l2_timestamp_correct(stamp_t *t, + unsigned long p_100ns); + +/* Master Clock functions */ +struct v4l2_clock +{ + void (*gettime)(stamp_t *); +}; +extern int v4l2_masterclock_register(struct v4l2_clock *clock); +extern void v4l2_masterclock_unregister(struct v4l2_clock *clock); +extern void v4l2_masterclock_gettime(stamp_t *curr); + +/* Video standard functions */ +extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs); +extern unsigned long v4l2_video_std_tpf(struct v4l2_standard *vs); +extern int v4l2_video_std_confirm(struct v4l2_standard *vs); +extern int v4l2_video_std_construct(struct v4l2_standard *vs, + int id, __u32 transmission); + +#define V4L2_STD_PAL 1 /* PAL B, G, H, I (...) */ +#define V4L2_STD_PAL_M 5 /* (Brazil) */ +#define V4L2_STD_PAL_N 6 /* (Argentina, Paraguay, Uruguay) */ +#define V4L2_STD_PAL_60 10 /* PAL/NTSC hybrid */ +#define V4L2_STD_NTSC 11 /* NTSC M (USA, ...) */ +#define V4L2_STD_NTSC_N 12 /* (Barbados, Bolivia, Colombia, + S. Korea) */ +#define V4L2_STD_NTSC_44 15 /* PAL/NTSC hybrid */ +#define V4L2_STD_SECAM 21 /* SECAM B, D, G, K, K1 (...) */ +//#define V4L2_STD_SECAM_H 27 /* (Greece, Iran, Morocco) */ +//#define V4L2_STD_SECAM_L 28 /* (France, Luxembourg, Monaco) */ +//#define V4L2_STD_SECAM_M 29 /* (Jamaica) */ + +/* + * D E V I C E D R I V E R R E G I S T R A T I O N + * + */ +struct v4l2_device +{ + char name[32]; + int type; + int minor; + + int (*open)(struct v4l2_device *v, + int flags, void **idptr); + void (*close)(void *id); + long (*read)(void *id, + char *buf, unsigned long count, int noblock); + long (*write)(void *id, + const char *buf, unsigned long count, int noblock); + int (*ioctl)(void *id, + unsigned int cmd, void *arg); + int (*mmap)(void *id, + struct vm_area_struct *vma); + int (*poll)(void *id, + struct file *file, poll_table *table); + + int (*initialize)(struct v4l2_device *v); + void *priv; /* may be used by the driver */ + + int busy; /* open count maintained by videodev.c */ + void *v4l2_priv; /* for V4L2 use */ + int v4l2_reserved[4]; /* for V4L2 use */ +}; + +/* Size of kernel ioctl arg buffer used in ioctl handler */ +#define V4L2_MAX_IOCTL_SIZE 256 + +extern int v4l2_register_device(struct v4l2_device *); +extern void v4l2_unregister_device(struct v4l2_device *); + +/* V4L2 structures */ +extern struct v4l2_device *v4l2_device_from_file(struct file *file); +extern void *v4l2_openid_from_file(struct file *file); + +#endif/*ifdef __KERNEL__ */ + + +/*---------------------------------------------------------------------- + Old Video for Linux backward compatibility below this line. + ---------------------------------------------------------------------- + + All new applications should use the new API calls. + + (These definitions taken from 2.2.1.) + + */ + + +#define VID_TYPE_CAPTURE 1 /* Can capture */ +#define VID_TYPE_TUNER 2 /* Can tune */ +#define VID_TYPE_TELETEXT 4 /* Does teletext */ +#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ +#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ +#define VID_TYPE_CLIPPING 32 /* Can clip */ +#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ +#define VID_TYPE_SCALES 128 /* Scalable */ +#define VID_TYPE_MONOCHROME 256 /* Monochrome only */ +#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ + +struct video_capability +{ + char name[32]; + int type; + int channels; /* Num channels */ + int audios; /* Num audio devices */ + int maxwidth; /* Supported width */ + int maxheight; /* And height */ + int minwidth; /* Supported width */ + int minheight; /* And height */ +}; + + +struct video_channel +{ + int channel; + char name[32]; + int tuners; + __u32 flags; +#define VIDEO_VC_TUNER 1 /* Channel has a tuner */ +#define VIDEO_VC_AUDIO 2 /* Channel has audio */ + __u16 type; +#define VIDEO_TYPE_TV 1 +#define VIDEO_TYPE_CAMERA 2 + __u16 norm; /* Norm set by channel */ +}; + +struct video_tuner +{ + int tuner; + char name[32]; + ulong rangelow, rangehigh; /* Tuner range */ + __u32 flags; +#define VIDEO_TUNER_PAL 1 +#define VIDEO_TUNER_NTSC 2 +#define VIDEO_TUNER_SECAM 4 +#define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */ +#define VIDEO_TUNER_NORM 16 /* Tuner can set norm */ +#define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */ +#define VIDEO_TUNER_RDS_ON 256 /* Tuner is seeing an RDS datastream */ +#define VIDEO_TUNER_MBS_ON 512 /* Tuner is seeing an MBS datastream */ + __u16 mode; /* PAL/NTSC/SECAM/OTHER */ +#define VIDEO_MODE_PAL 0 +#define VIDEO_MODE_NTSC 1 +#define VIDEO_MODE_SECAM 2 +#define VIDEO_MODE_AUTO 3 + __u16 signal; /* Signal strength 16bit scale */ +}; + +struct video_picture +{ + __u16 brightness; + __u16 hue; + __u16 colour; + __u16 contrast; + __u16 whiteness; /* Black and white only */ + __u16 depth; /* Capture depth */ + __u16 palette; /* Palette in use */ +#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */ +#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */ +#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */ +#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */ +#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */ +#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */ +#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */ +#define VIDEO_PALETTE_YUYV 8 +#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */ +#define VIDEO_PALETTE_YUV420 10 +#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */ +#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */ +#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */ +#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */ +#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */ +#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */ +#define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */ +#define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */ +}; + +struct video_audio +{ + int audio; /* Audio channel */ + __u16 volume; /* If settable */ + __u16 bass, treble; + __u32 flags; +#define VIDEO_AUDIO_MUTE 1 +#define VIDEO_AUDIO_MUTABLE 2 +#define VIDEO_AUDIO_VOLUME 4 +#define VIDEO_AUDIO_BASS 8 +#define VIDEO_AUDIO_TREBLE 16 +#define VIDEO_AUDIO_BALANCE 32 + char name[16]; +#define VIDEO_SOUND_MONO 1 +#define VIDEO_SOUND_STEREO 2 +#define VIDEO_SOUND_LANG1 4 +#define VIDEO_SOUND_LANG2 8 + __u16 mode; + __u16 balance; /* Stereo balance */ + __u16 step; /* Step actual volume uses */ +}; + +struct video_clip +{ + __s32 x,y; + __s32 width, height; + struct video_clip *next; /* For user use/driver use only */ +}; + +struct video_window +{ + __u32 x,y; /* Position of window */ + __u32 width,height; /* Its size */ + __u32 chromakey; + __u32 flags; + struct video_clip *clips; /* Set only */ + int clipcount; +#define VIDEO_WINDOW_INTERLACE 1 +#define VIDEO_CLIP_BITMAP -1 +/* bitmap is 1024x625, a '1' bit represents a clipped pixel */ +#define VIDEO_CLIPMAP_SIZE (128 * 625) +}; + +struct video_capture +{ + __u32 x,y; /* Offsets into image */ + __u32 width, height; /* Area to capture */ + __u16 decimation; /* Decimation divder */ + __u16 flags; /* Flags for capture */ +#define VIDEO_CAPTURE_ODD 0 /* Temporal */ +#define VIDEO_CAPTURE_EVEN 1 +}; + +struct video_buffer +{ + void *base; + int height,width; + int depth; + int bytesperline; +}; + +struct video_mmap +{ + unsigned int frame; /* Frame (0 - n) for double buffer */ + int height,width; + unsigned int format; /* should be VIDEO_PALETTE_* */ +}; + +struct video_key +{ + __u8 key[8]; + __u32 flags; +}; + + +#define VIDEO_MAX_FRAME 32 + +struct video_mbuf +{ + int size; /* Total memory to map */ + int frames; /* Frames */ + int offsets[VIDEO_MAX_FRAME]; +}; + + +#define VIDEO_NO_UNIT (-1) + + +struct video_unit +{ + int video; /* Video minor */ + int vbi; /* VBI minor */ + int radio; /* Radio minor */ + int audio; /* Audio minor */ + int teletext; /* Teletext minor */ +}; + +#define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */ +#define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */ +#define VIDIOCSCHAN _IOW('v',3,struct video_channel) /* Set channel */ +#define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */ +#define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */ +#define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */ +#define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */ +#define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */ +#define VIDIOCGWIN _IOR('v',9, struct video_window) /* Set the video overlay window */ +#define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ +#define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */ +#define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */ +#define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */ +#define VIDIOCGFREQ _IOR('v',14, unsigned long) /* Set tuner */ +#define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */ +#define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */ +#define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */ +#define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */ +#define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */ +#define VIDIOCGMBUF _IOR('v', 20, struct video_mbuf) /* Memory map buffer info */ +#define VIDIOCGUNIT _IOR('v', 21, struct video_unit) /* Get attached units */ +#define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get frame buffer */ +#define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set frame buffer - root only */ +#define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */ + + + +#endif/*ifndef __LINUX_VIDEODEV_H*/ --- linux-2.6.27.orig/ubuntu/qc-usb/Kconfig +++ linux-2.6.27/ubuntu/qc-usb/Kconfig @@ -0,0 +1,4 @@ +config QC_USB + tristate "Quickcam USB Driver" + default m + depends on USB --- linux-2.6.27.orig/ubuntu/qc-usb/videodevfix.h +++ linux-2.6.27/ubuntu/qc-usb/videodevfix.h @@ -0,0 +1,15 @@ +#ifndef VIDEODEVFIX_H +#define VIDEODEVFIX_H + +#include + +typedef int8_t __s8; +typedef u_int8_t __u8; +typedef int16_t __s16; +typedef u_int16_t __u16; +typedef int32_t __s32; +typedef u_int32_t __u32; +typedef int64_t __s64; +typedef u_int64_t __u64; + +#endif --- linux-2.6.27.orig/ubuntu/qc-usb/qc-memory.h +++ linux-2.6.27/ubuntu/qc-usb/qc-memory.h @@ -0,0 +1,10 @@ +#ifndef _LINUX_QC_MEMORY_H +#define _LINUX_QC_MEMORY_H + +#include + +void *qc_mm_rvmalloc(unsigned long size); +void qc_mm_rvfree(void *mem, unsigned long size); +int qc_mm_remap(struct vm_area_struct *vma, void *src, unsigned long src_size, const void *dst, unsigned long dst_size); + +#endif --- linux-2.6.27.orig/ubuntu/qc-usb/Makefile +++ linux-2.6.27/ubuntu/qc-usb/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_QC_USB) := quickcam.o + +quickcam-objs := qc-driver.o qc-hdcs.o qc-pb0100.o qc-vv6410.o qc-formats.o qc-mjpeg.o qc-memory.o --- linux-2.6.27.orig/ubuntu/qc-usb/qc-vv6410.c +++ linux-2.6.27/ubuntu/qc-usb/qc-vv6410.c @@ -0,0 +1,650 @@ +/* Start of file */ + +/* {{{ [fold] Comments */ +/* + * qce-ga, linux V4L driver for the QuickCam Express and Dexxa QuickCam + * + * vv6410.c - VV6410 Sensor Implementation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +/* }}} */ + +#include "quickcam.h" + +#ifndef QCEGA_MODE +#define QCEGA_MODE 0 /* If the driver doesn't work for you, try changing this to "1" */ +#endif + +/* LSB bit of I2C address signifies write (0) or read (1) */ + +/* I2C Address */ +#define VV6410_ADDR (0x10<<1) + +/* {{{ [fold] I2C Registers */ +/* Status registers */ +#define VV6410_DEVICEH 0x00 /* Chip identification number including revision indicator */ +#define VV6410_DEVICEL 0x01 +#define VV6410_STATUS0 0x02 /* User can determine whether timed I2C data has been consumed by interrogating flag states */ +#define VV6410_LINECOUNTH 0x03 /* Current line counter value */ +#define VV6410_LINECOUNTL 0x04 +#define VV6410_XENDH 0x05 /* End x coordinate of image size */ +#define VV6410_XENDL 0x06 +#define VV6410_YENDH 0x07 /* End y coordinate of image size */ +#define VV6410_YENDL 0x08 +#define VV6410_DARKAVGH 0x09 /* This is the average pixel value returned from the dark line offset cancellation algorithm */ +#define VV6410_DARKAVGL 0x0A +#define VV6410_BLACKAVGH 0x0B /* This is the average pixel value returned from the black line offset cancellation algorithm */ +#define VV6410_BLACKAVGL 0x0C +#define VV6410_STATUS1 0x0D /* Flags to indicate whether the x or y image coordinates have been clipped */ + +/* Setup registers */ +#define VV6410_SETUP0 0x10 /* Low-power/sleep modes & video timing */ +#define VV6410_SETUP1 0x11 /* Various parameters */ +#define VV6410_SYNCVALUE 0x12 /* Contains pixel counter reset value used by external sync */ +#define VV6410_FGMODES 0x14 /* Frame grabbing modes (FST, LST and QCK) */ +#define VV6410_PINMAPPING 0x15 /* FST and QCK mapping modes. */ +#define VV6410_DATAFORMAT 0x16 /* Data resolution */ +#define VV6410_OPFORMAT 0x17 /* Output coding formats */ +#define VV6410_MODESELECT 0x18 /* Various mode select bits */ + +/* Exposure registers */ +#define VV6410_FINEH 0x20 /* Fine exposure. */ +#define VV6410_FINEL 0x21 +#define VV6410_COARSEH 0x22 /* Coarse exposure */ +#define VV6410_COARSEL 0x23 +#define VV6410_ANALOGGAIN 0x24 /* Analog gain setting */ +#define VV6410_CLKDIV 0x25 /* Clock division */ +#define VV6410_DARKOFFSETH 0x2C /* Dark line offset cancellation value */ +#define VV6410_DARKOFFSETL 0x2D +#define VV6410_DARKOFFSETSETUP 0x2E /* Dark line offset cancellation enable */ + +/* Colour registers (none on this camera!) */ + +/* Video timing registers */ +#define VV6410_LINELENGTHH 0x52 /* Line Length (Pixel Clocks) */ +#define VV6410_LINELENGTHL 0x53 +#define VV6410_XOFFSETH 0x57 /* X-co-ordinate of top left corner of region of interest (x-offset) */ +#define VV6410_XOFFSETL 0x58 +#define VV6410_YOFFSETH 0x59 /* Y-co-ordinate of top left corner of region of interest (y-offset) */ +#define VV6410_YOFFSETL 0x5A +#define VV6410_FIELDLENGTHH 0x61 /* Field length (Lines) */ +#define VV6410_FIELDLENGTHL 0x62 + +/* Text overlay registers (none on this camera!) */ + +/* I2C autoload registers (none on this camera!) */ + +/* System registers */ +#define VV6410_BLACKOFFSETH 0x70 /* Black offset cancellation default value */ +#define VV6410_BLACKOFFSETL 0x71 +#define VV6410_BLACKOFFSETSETUP 0x72 /* Black offset cancellation setup */ +#define VV6410_CR0 0x75 /* Analog Control Register 0 */ +#define VV6410_CR1 0x76 /* Analog Control Register 1 */ +#define VV6410_AS0 0x77 /* ADC Setup Register */ +#define VV6410_AT0 0x78 /* Analog Test Register */ +#define VV6410_AT1 0x79 /* Audio Amplifier Setup Register */ +/* }}} */ + +#define I2C_SET_CHECK(reg,val) if ((r = qc_i2c_set(qc,(reg),(val)))<0) goto fail +#define STV_SET_CHECK(reg,val) if ((r = qc_stv_set(qc,(reg),(val)))<0) goto fail +#define STV_SETW_CHECK(reg,val) if ((r = qc_stv_setw(qc,(reg),(val)))<0) goto fail +#define IS_850(qc) (GET_PRODUCTID(qc)==0x850) /* Is it QuickCam Web/Legocam? */ + +#if QCEGA_MODE +#warning "Using old compatible code (QCEGA_MODE=1)" +#warning "If this works but otherwise it doesn't work, let me know!" +static int mode = 0; +#define VV6410_CONTROL 0x10 // Setup0 +#define VV6410_GAIN 0x24 +/* {{{ [fold] vv6410_set_window() */ +static int vv6410_set_window(struct quickcam *qc, int x, int y,int width, int height) +{ + int r = 0; + + // x offset + x = MAX(1,x); + I2C_SET_CHECK(0x57,x >> 8); + I2C_SET_CHECK(0x58,x & 0xff); + + // y offset + y = MAX(1,y); + I2C_SET_CHECK(0x59,y >> 8); + I2C_SET_CHECK(0x5a,y & 0xff); + + // Set the real + if (qc->sensor_data.subsample) { + qc->sensor_data.width=180; + qc->sensor_data.height=148; + } else { + qc->sensor_data.width=356; + qc->sensor_data.height=292; + } + + // line length + if (qc->sensor_data.subsample) { + if (IS_850(qc)) + width=250; + else + width=360; /* 180 * 2 (CLK-DIV is 2) */ + } + else { + if (IS_850(qc)) + width=416; + else + width=712; /* 356 * 2 */ + } + + I2C_SET_CHECK(0x52, width >> 8); + I2C_SET_CHECK(0x53, width & 0xff); + + // field length (num lines) + if (qc->sensor_data.subsample) + height=160; /* nearest of 148 = 10 * 16 */ + else + height=320; // 304; /* nearest of 292 = 19 * 16 */ + + I2C_SET_CHECK(0x61,height >> 8); + I2C_SET_CHECK(0x62,height & 0xff); + + // usb_quickcam_i2c_add(&i2cbuff,0x25,0x02); + if ((r = qc_i2c_wait(qc))<0) goto fail; + + return 0; +fail: + return -ENAMETOOLONG; //some silly code just for testing +} +/* }}} */ +#endif + +/* {{{ [fold] vv6410_set_size: Set window size */ +static int vv6410_set_size(struct quickcam *qc, unsigned int width, unsigned int height) +{ + struct qc_sensor_data *sd = &qc->sensor_data; + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("vv6410_set_size(qc=%p,width=%i,height=%i)",qc,width,height); + /* VV6410 appears to always give fixed 356*292 pixels */ + sd->width = sd->maxwidth; + sd->height = sd->maxheight; + return 0; +} +/* }}} */ +/* {{{ [fold] vv6410_start: Start grabbing */ +static int vv6410_start(struct quickcam *qc) +{ + struct qc_sensor_data *sd = &qc->sensor_data; + int r; + + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("vv6410_start(qc=%p)",qc); + if (PARANOID && !qc) { PDEBUG("qc==NULL"); return -EINVAL; } + I2C_SET_CHECK(VV6410_SETUP0, sd->subsample ? (BIT(7)|BIT(6)) : 0x00); + if (IS_850(qc)) qc_stv_set(qc, 0x1445, 1); /* Turn on LED */ + r = qc_i2c_wait(qc); +fail: return r; +} +/* }}} */ +/* {{{ [fold] vv6410_stop: Stop grabbing */ +static int vv6410_stop(struct quickcam *qc) +{ + static const int low_power_mode = 0; //1; + static const int sleep_mode = 1; + struct qc_sensor_data *sd = &qc->sensor_data; + unsigned char cmd; + int r; + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("vv6410_stop(qc=%p)",qc); + if (IS_850(qc)) qc_stv_set(qc, 0x1445, 0); /* Turn off LED */ + cmd = (sleep_mode << 1) | low_power_mode; + if (sd->subsample) cmd |= BIT(7)|BIT(6); /* sub-sampled QCIF mode */ + I2C_SET_CHECK(VV6410_SETUP0, cmd); + r = qc_i2c_wait(qc); +fail: return r; +} +/* }}} */ +#if COMPRESS +struct stv_init { + const u8 *data; /* If NULL, only single value to write, stored in len */ + u16 start; + u8 len; +}; +#endif +/* {{{ [fold] vv6410_init: Initialise parameters for vv6410 sensor. */ +/* Just try to send the same commands as Windoze QuickCam soft */ +static int vv6410_init(struct quickcam *qc) +{ + struct qc_sensor_data *sd = &qc->sensor_data; + int r; + +#if COMPRESS + if (IS_850(qc)) { +/* {{{ [fold] Initialization with compression support */ + +/* {{{ [fold] [fold] stv_init[] */ + static const u8 x0540[] = { /* 0x0540 - 0x0551 */ + 0x97,0x0B,0x4C,0xFC,0x36,0x00,0x75,0x00,0x59,0x02,0x32,0x01,0x56,0xFD,0xEE,0xFF, + 0xB8,0x05 }; + static const u8 x0560[] = { /* 0x0560 - 0x0563 */ + 0x40,0xFF,0xBF,0xBF }; + static const u8 x1500[] = { /* 0x1500 - 0x150F */ + 0x0B,0xA7,0xB7,0x00,0x00,0x00,0x14,0x14,0x14,0x14,0x2B,0x02,0x2B,0x02,0x2B,0x02 }; + static const u8 x1520[] = { /* 0x1520 - 0x152A */ + 0x05,0x14,0x0F,0x0F,0x98,0x98,0x98,0x98,0x2D,0x00,0x01 }; + static const u8 x1530[] = { /* 0x1530 - 0x153B */ + 0x08,0x02,0x00,0x00,0x02,0x00,0x02,0x00,0x60,0x01,0x20,0x01 }; + static const u8 x1552[] = { /* 0x1552 - 0x1558 */ + 0x72,0x90,0x00,0xB0,0xF0,0x77,0x72 }; + static const u8 x1564[] = { /* 0x1564 - 0x1567 */ + 0x00,0xFF,0x0C,0x00 }; + static const u8 x1580[] = { /* 0x1580 - 0x158F */ + 0x02,0x40,0x01,0xF0,0x00,0xD1,0x01,0xAC,0x01,0x07,0x00,0x00,0x00,0x00,0x00,0x00 }; + static const u8 x1590[] = { /* 0x1590 - 0x15A5 */ + 0xA8,0x05,0x64,0x07,0x0F,0x03,0xD8,0x07,0xA6,0x06,0x71,0x04,0x8F,0x01,0xFF,0xFB, + 0xEC,0xE6,0xE0,0xD9,0xC4,0xB8 }; + static const u8 x15C1[] = { /* 0x15C1 - 0x15C2 */ + 0x4B, 0x02 }; /* Output word 0x024B=587 (ISO size) */ + static const struct stv_init stv_init[] = { + { NULL, 0x1620, 0x80 }, /* This reg is written twice. Some kind of reset? */ + { NULL, 0x1620, 0x00 }, + { x0540, 0x0540, SIZE(x0540) }, + { x0560, 0x0560, SIZE(x0560) }, + { NULL, 0x1423, 0x04 }, + { NULL, 0x1440, 0x00 }, + { NULL, 0x1443, 0x00 }, + { NULL, 0x1445, 0x01 }, + { x1500, 0x1500, SIZE(x1500) }, + { x1520, 0x1520, SIZE(x1520) }, + { x1530, 0x1530, SIZE(x1530) }, + { x1552, 0x1552, SIZE(x1552) }, + { x1564, 0x1564, SIZE(x1564) }, + { x1580, 0x1580, SIZE(x1580) }, + { x1590, 0x1590, SIZE(x1590) }, + { x15C1, 0x15C1, SIZE(x15C1) }, + { NULL, 0x15C3, 0x00 }, + { NULL, 0x15C9, 0x01 }, + { NULL, 0x1704, 0x00 }, + }; +/* }}} */ +/* {{{ [fold] vv_init[][2] */ + static const u8 vv_init[][2] = { + /* Setup registers */ + { VV6410_SETUP0, BIT(2) }, /* Soft reset */ + { VV6410_SETUP0, BIT(1)|BIT(0) }, /* 25 fps PAL (30 fps NTSC doesn't work!), sleep mode */ + { VV6410_SETUP1, BIT(6) }, /* Use unsuffled read-out mode */ + { VV6410_FGMODES, BIT(6)|BIT(4)|BIT(2)|BIT(0) }, /* All modes to 1 */ + { VV6410_PINMAPPING, 0x00 }, + { VV6410_DATAFORMAT, BIT(7)|BIT(0) }, /* Pre-clock generator divide off */ + { VV6410_OPFORMAT, BIT(3)|BIT(4) }, + /* Exposure registers */ + { VV6410_FINEH, 320 >> 8 }, /* Initial exposure */ + { VV6410_FINEL, 320 & 0xFF }, + { VV6410_COARSEH, 192 >> 8 }, + { VV6410_COARSEL, 192 & 0xFF }, + { VV6410_ANALOGGAIN, 0xF0 | 11 }, /* Gain to 11 */ + { VV6410_CLKDIV, 0x01 }, /* Pixel clock divisor 2 */ + /* Video timing registers */ + { VV6410_LINELENGTHH, (416-1) >> 8 }, /* Set line length (columns) to 417 */ + { VV6410_LINELENGTHL, (416-1) & 0xFF }, + { VV6410_FIELDLENGTHH, (320-1) >> 8 }, /* Set field length (rows) to 320 */ + { VV6410_FIELDLENGTHL, (320-1) & 0xFF }, + /* System registers */ + { VV6410_AS0, BIT(6)|BIT(4)|BIT(3)|BIT(2)|BIT(1) }, /* Enable voltage doubler */ + { VV6410_AT0, 0x00 }, + { VV6410_AT1, BIT(4)|BIT(0) }, /* Power up audio, differential */ + }; +/* }}} */ + + unsigned int cols = 416; + unsigned int rows = 320; + unsigned int x = 1; + unsigned int y = 1; + int i,j; + + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("vv6410_init(qc=%p)",qc); + if (PARANOID && !qc) { PDEBUG("qc==NULL"); return -EINVAL; } + + sd->width = 320; /* Default to compressed mode */ + sd->height = 240; + + for (i=0; isubsample ? 0x10 : 0x20); /* Scan rate */ + STV_SET_CHECK(0x1446,1); + STV_SETW_CHECK(0x15C1,600); /* ISO size, 0x380|orig:600 */ + STV_SET_CHECK(0x1680,0x14); /* X ctrl */ + } + + for (i=0; icompress) { + /* Disable compression */ + STV_SET_CHECK(0x1443, sd->subsample ? 0x00 : 0x10); /* Scan rate: Larger -> slower */ + STV_SETW_CHECK(0x15C1, 1023); /* ISO-Size */ + STV_SET_CHECK(0x15C3, 1); /* Y control */ + sd->width = 356; + sd->height = 292; + if (qc->settings.subsample) { + //FIXME:subsampling (still) doesn't work yet + cols=250; + rows=160; + sd->width = 180; + sd->height = 148; + I2C_SET_CHECK(VV6410_SETUP0, BIT(7)|BIT(6)|BIT(1)|BIT(0)); /* Subsampled timing mode */ + } + } + I2C_SET_CHECK(VV6410_XOFFSETH, x >> 8); + I2C_SET_CHECK(VV6410_XOFFSETL, x & 0xFF); + I2C_SET_CHECK(VV6410_YOFFSETH, y >> 8); + I2C_SET_CHECK(VV6410_YOFFSETL, y & 0xFF); + I2C_SET_CHECK(VV6410_LINELENGTHH, (cols-1) >> 8); + I2C_SET_CHECK(VV6410_LINELENGTHL, (cols-1) & 0xFF); + I2C_SET_CHECK(VV6410_FIELDLENGTHH, (rows-1) >> 8); + I2C_SET_CHECK(VV6410_FIELDLENGTHL, (rows-1) & 0xFF); + sd->maxwidth = sd->width; + sd->maxheight = sd->height; + return 0; +/* }}} */ + } else { +#endif +/* {{{ [fold] Initialization without compression support */ + if (sd->compress) return -EINVAL; + if (sd->subsample) { + sd->maxwidth = 180; + sd->maxheight = 148; + } else { + sd->maxwidth = 356; + sd->maxheight = 292; + } + + +#if QCEGA_MODE +{ +int line_length = mode?250:416;//415; + + if (mode) { + sd->subsample=1; // quater. + sd->width = 180; + sd->height = 148; + } else { + sd->subsample=0; + sd->width = 356; + sd->height = 292; + } + + STV_SET_CHECK(STV_REG23, 5); // was 5. + + + if (!IS_850(qc)) { + /* logitech quickcam web has 0x850 as idProduct */ + STV_SET_CHECK(0x1446, 1); + } + + + STV_SET_CHECK(STV_SCAN_RATE, 0x00); + + + STV_SET_CHECK(0x1423, 0x04); + + + STV_SET_CHECK(STV_REG00, 0x1b); // 0x0b + + + + I2C_SET_CHECK(VV6410_CONTROL,0x04); // reset to defaults + if ((r = qc_i2c_wait(qc))<0) goto fail; + + + + + // CIF or QCIF and sleep. + if (IS_850(qc)) { + I2C_SET_CHECK(VV6410_CONTROL,(mode?0xa2:0x02)); + } else { + I2C_SET_CHECK(VV6410_CONTROL,(mode?0xc2:0x02)); + } + + if ((r = qc_i2c_wait(qc))<0) goto fail; + + + + I2C_SET_CHECK(VV6410_GAIN,0xfb); + if ((r = qc_i2c_wait(qc))<0) goto fail; + + + + + + STV_SET_CHECK(STV_REG04, 0x07); + + + STV_SET_CHECK(STV_REG03, 0x45); + + + /* set window size */ + if ((r=vv6410_set_window(qc,0,0,48,64)) < 0) { + PRINTK(KERN_ERR, "vv6410_set_window failed"); + goto fail; + } + + + /* EXPERIMENTAL */ + /* + * line length default is 415 so it's the value we use to + * calculate values for registers 0x20-0x21 + * Ref. DS Pag. 67 + */ + I2C_SET_CHECK(0x20,mode? ((line_length-23)>>8):((line_length-51)>>8)); + + I2C_SET_CHECK(0x21,mode?((line_length-23)&0xff):((line_length-51)&0xff)); + + I2C_SET_CHECK(0x22,mode?0x00:0x01); + //usb_quickcam_i2c_add(&i2cbuff,0x23,mode?0x9e:0x3e); + I2C_SET_CHECK(0x23,mode?158:318&0xff); + I2C_SET_CHECK(0x24,0xfa); + // clock divisor. + I2C_SET_CHECK(0x25,0x01); + + if ((r = qc_i2c_wait(qc))<0) goto fail; + + + /* + if (isaweb(dev)) + { + //EXPERIMENTAL: dark/black pixel cancellation + usb_quickcam_i2c_add(&i2cbuff,0x3e,0x01); + usb_quickcam_i2c_add(&i2cbuff,0x72,0x01); + if (usb_quickcam_i2c_send(dev,&i2cbuff,VV6410_ADDR) < 0) { + printk(KERN_ERR "usb_control_msg dark/black pixel failed"); + goto error; + } + } + */ + STV_SET_CHECK(STV_REG01, 0xb7); + + STV_SET_CHECK(STV_REG02, 0xa7); + + + + // setup + I2C_SET_CHECK(0x11,0x18); // 0x18 or Jochen 0x40 + I2C_SET_CHECK(0x14,0x55); // was 0x55 + I2C_SET_CHECK(0x15,0x10); // 0x10 or Jochen:0x00 + I2C_SET_CHECK(0x16,0x81); // Pre clock dividor. + I2C_SET_CHECK(0x17,0x18); // they are reserved. + I2C_SET_CHECK(0x18,0x00); + I2C_SET_CHECK(0x77,0x5e); + I2C_SET_CHECK(0x78,0x04);// 0x04 or Jochen:0x00 + if (IS_850(qc)) { + I2C_SET_CHECK(0x79,0x11);//audio init + } + if ((r = qc_i2c_wait(qc))<0) goto fail; + + + + + STV_SETW_CHECK(STV_ISO_SIZE, IS_850(qc)?1023:600); // 0x380|orig:600 + + + + + STV_SET_CHECK(STV_Y_CTRL, 1); + + + STV_SET_CHECK(STV_SCAN_RATE, mode?0x00:0x10); + + + + if (!IS_850(qc)) { + /* logitech quickam web has 0x0850 as idProduct */ + STV_SET_CHECK(STV_X_CTRL, 0x14); + } +} + +#else + STV_SET_CHECK(0x0423,0x05); /* Unknown register, 0x04 or 0x05 */ + STV_SET_CHECK(0x1423,0x04); /* Unknown register, 0x04 or 0x05 */ + STV_SET_CHECK(0x1443,0x00); /* Scan rate */ + STV_SET_CHECK(0x1500,0x1B); /* 0x0B */ + STV_SET_CHECK(0x1501,0xB7); + STV_SET_CHECK(0x1502,0xA7); + STV_SET_CHECK(0x1503,0x45); + STV_SET_CHECK(0x1504,0x07); + STV_SET_CHECK(0x15C3,1); /* Y ctrl */ + if (IS_850(qc)) { + STV_SET_CHECK(0x1443, sd->subsample ? 0x20 : 0x10); /* Scan rate */ + STV_SETW_CHECK(0x15C1,1023); /* ISO size, 0x380|orig:600 */ + } else { + STV_SET_CHECK(0x1443, sd->subsample ? 0x10 : 0x20); /* Scan rate */ + STV_SET_CHECK(0x1446,1); + STV_SETW_CHECK(0x15C1,600); /* ISO size, 0x380|orig:600 */ + STV_SET_CHECK(0x1680,0x14); /* X ctrl */ + } + + I2C_SET_CHECK(0x10,0x04); /* Control register: reset to defaults */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + I2C_SET_CHECK(0x10,sd->subsample ? 0xC2 : 0x02);/* Control register: CIF or QCIF and sleep */ + if ((r = qc_i2c_wait(qc))<0) goto fail; + I2C_SET_CHECK(0x11,0x18); /* 0x18 or Jochen 0x40 */ + I2C_SET_CHECK(0x14,0x55); + I2C_SET_CHECK(0x15,0x10); /* 0x10 or Jochen:0x00 */ + I2C_SET_CHECK(0x16,0x81); /* Pre clock dividor. */ + I2C_SET_CHECK(0x17,0x18); /* they are reserved. */ + I2C_SET_CHECK(0x18,0x00); + I2C_SET_CHECK(0x24,0xFB); /* Set gain value */ + I2C_SET_CHECK(0x25,0x01); /* Clock divisor value */ + I2C_SET_CHECK(0x77,0x5E); + I2C_SET_CHECK(0x78,0x04); /* 0x04 or Jochen:0x00 */ + if (IS_850(qc)) { + I2C_SET_CHECK(0x3E,0x01); /* EXPERIMENTAL: dark/black pixel cancellation */ + I2C_SET_CHECK(0x72,0x01); + } + + if ((r = qc_i2c_wait(qc))<0) goto fail; +#endif + + return 0; +/* }}} */ +#if COMPRESS + } +#endif + +fail: return r; +} +/* }}} */ +/* {{{ [fold] vv6410_set_exposure() */ +static int vv6410_set_exposure(struct quickcam *qc, unsigned int val) +{ + struct qc_sensor_data *sd = &qc->sensor_data; + static const unsigned int linelength = 415; /* For CIF */ + unsigned int fine; + unsigned int coarse; + int r; + + val = (val*val >> 14) + val/4; + if (sd->exposure==val) return 0; + sd->exposure = val; + fine = val % linelength; + coarse = val / linelength; + if (coarse>=512) coarse = 512; + + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("vv6410_set_exposure %d (%i,%i)",val,coarse,fine); + I2C_SET_CHECK(VV6410_FINEH, fine >> 8); + I2C_SET_CHECK(VV6410_FINEL, fine & 0xFF); + I2C_SET_CHECK(VV6410_COARSEH, coarse >> 8); + I2C_SET_CHECK(VV6410_COARSEL, coarse & 0xFF); +fail: return r; +} +/* }}} */ +/* {{{ [fold] vv6410_set_gains() */ +static int vv6410_set_gains(struct quickcam *qc, unsigned int hue, unsigned int sat, unsigned int val) +{ + static const int maxgain = 13; /* Absolute maximum is 14, recommended is 12 */ + struct qc_sensor_data *sd = &qc->sensor_data; + unsigned int gain; + int r; + + if (qcdebug&QC_DEBUGLOGIC) PDEBUG("vv6410_set_gains %d %d %d", hue, sat, val); + gain = val / 256; + gain >>= 4; + if (gain > maxgain) gain = maxgain; + if (sd->rgain==gain) return 0; + sd->rgain = gain; + r = qc_i2c_set(qc, VV6410_ANALOGGAIN, 0xF0 | gain); + return r; +} +/* }}} */ +/* {{{ [fold] vv6410_set_levels() */ +static int vv6410_set_levels(struct quickcam *qc, unsigned int exp, unsigned int gain, unsigned int hue, unsigned int sat) +{ + int r; + if ((r = vv6410_set_exposure(qc, exp))<0) goto fail; + vv6410_set_gains(qc, hue, sat, gain); +fail: return r; +} +/* }}} */ + +/* {{{ [fold] struct qc_sensor qc_sensor_vv6410 */ +const struct qc_sensor qc_sensor_vv6410 = { + name: "VV6410", + manufacturer: "ST Microelectronics", + init: vv6410_init, + start: vv6410_start, + stop: vv6410_stop, + set_size: vv6410_set_size, + set_levels: vv6410_set_levels, + /* Exposure and gain control information */ + autoexposure: FALSE, + adapt_gainlow: 40000, + adapt_gainhigh: 65535, + /* Information needed to access the sensor via I2C */ + reg23: 5, + i2c_addr: VV6410_ADDR, + /* Identification information used for auto-detection */ + id_reg: VV6410_DEVICEH, + id: 0x19, + length_id: 1, +}; +/* }}} */ + +/* End of file */ --- linux-2.6.27.orig/ubuntu/qc-usb/qc-memory.c +++ linux-2.6.27/ubuntu/qc-usb/qc-memory.c @@ -0,0 +1,252 @@ +/* Start of file */ + +/* {{{ [fold] Comments */ +/* + * qce-ga, linux V4L driver for the QuickCam Express and Dexxa QuickCam + * + * memory.c - contains all needed memory management functions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* These routines have been derived from the ov511 driver, into which they + * were derived from the bttv driver. + */ +/* }}} */ +/* {{{ [fold] Includes */ +#include +#include + +#ifdef CONFIG_SMP +#define __SMP__ +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include +#endif +#endif + +#include "qc-memory.h" +#include +#include /* Required on Alpha, from Bob McElrath */ +#include /* Required on Alpha */ +#include /* Required on Alpha */ +#include /* pmd_offset requires this on SuSE supplied kernels */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) +#include /* For proper mem_map_(un)reserve define, the compatibility define below might not work */ +#endif +/* }}} */ +/* {{{ [fold] Compatibility wrappers */ +#ifndef HAVE_VMA +#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,5,3) || (defined(RED_HAT_LINUX_KERNEL) && defined(pte_offset_map)) +#define HAVE_VMA 1 +#else +#define HAVE_VMA 0 +#endif +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) +#if HAVE_VMA +#warning "HAVE_VMA=1" +/* remap_page_range is still emulated in 2.6.10, in 2.6.11 it's completely removed */ +static inline int qc_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long pfn, unsigned long size, pgprot_t prot) { return remap_page_range(vma, from, pfn<=KERNEL_VERSION(2,5,3) || defined(pte_offset_map) +#define pte_offset(pmd,adr) pte_offset_map(pmd,adr) /* Emulation for a kernel using the new rmap-vm */ +#endif /* Fix by Michele Balistreri */ + +/* }}} */ + +/* {{{ [fold] kvirt_to_pa(): obtain physical address from virtual address obtained by vmalloc() */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +/* {{{ [fold] kvirt_to_pa(), 2.4.x and 2.6.x */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19) +static struct page *vmalloc_to_page(void * vmalloc_addr); +#endif + +/* Here we want the physical address of the memory obtained by vmalloc(). + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long kva, ret; + + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ + ret = __pa(kva); + return ret; +} +/* }}} */ +#else +/* {{{ [fold] kvirt_to_pa() for 2.2.x */ +#define page_address(x) (x | PAGE_OFFSET) /* Damn ugly hack from kcomp.h; replaces original page_address() that made different thing! */ + +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) +{ + unsigned long ret = 0UL; + pmd_t *pmd; + pte_t *ptep, pte; + + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if (pte_present(pte)) { + ret = (unsigned long) page_address(pte_page(pte)); + ret |= (adr & (PAGE_SIZE - 1)); + } + } + } + + return ret; +} + +/* Here we want the physical address of the memory obtained by vmalloc(). + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + return ret; +} +/* }}} */ +#endif +/* }}} */ +/* {{{ [fold] vmalloc_to_page(): obtain pointer to struct page from virtual address obtained by vmalloc() */ +#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,4,0) && LINUX_VERSION_CODE 0) { + SetPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + return mem; +} +/* }}} */ +/* {{{ [fold] qc_mm_rvfree(mem, size) */ +void qc_mm_rvfree(void *mem, unsigned long size) +{ + unsigned long adr; + + if (!mem) + return; + + adr = (unsigned long) mem; + while ((long) size > 0) { + ClearPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + vfree(mem); +} +/* }}} */ +/* {{{ [fold] qc_mm_remap(vma, src, src_size, dst, dst_size) */ +int qc_mm_remap(struct vm_area_struct *vma, void *src, unsigned long src_size, const void *dst, unsigned long dst_size) +{ + unsigned long start = (unsigned long)dst; + unsigned long size = dst_size; + unsigned long physaddr, pos; + + pos = (unsigned long)src; + while ((long)size > 0) { + physaddr = kvirt_to_pa(pos); +#if 1 + if ((physaddr & ~PAGE_MASK)!=0) { + printk(KERN_CRIT "qc_mm_remap: physaddr=%08X not page aligned!\n", (int)physaddr); + return -EIO; + } +#endif + if (remap_pfn_range(vma, start, physaddr>>PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start += PAGE_SIZE; + pos += PAGE_SIZE; + size -= PAGE_SIZE; + } + return 0; +} +/* }}} */ + +/* End of file */ --- linux-2.6.27.orig/ubuntu/qc-usb/BOM +++ linux-2.6.27/ubuntu/qc-usb/BOM @@ -0,0 +1,4 @@ +Downloaded from: http://sourceforge.net/project/showfiles.php?group_id=12924 +Current Version: 0.6.6 + +Took a bit of forward porting. Upstream project seems dead anyway. --- linux-2.6.27.orig/ubuntu/tlsup/tlsup_hotkeys.c +++ linux-2.6.27/ubuntu/tlsup/tlsup_hotkeys.c @@ -0,0 +1,238 @@ +/* Toshiba Laptop Support -- tlsup_hotkeys.c + * + * Hotkeys input support for T.L.S. + * + * Copyright 2008 Daniel Silverstone + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; specifically version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * + * Credits: + * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse + * engineering the Windows drivers + * Rob Miller - TV out and hotkeys help + * John Belmonte - The toshiba_acpi driver maintainance for some time. + */ + +#include +#include +#include +#include +#include +#include + +#include "tlsup.h" + +/* HCI registers */ +#define HCI_SYSTEM_EVENT 0x0016 + +/* Value manipulation */ + +/* Module stuff */ +static int hotkeys_checks_per_second = 4; +module_param(hotkeys_checks_per_second, uint, 0400); +MODULE_PARM_DESC(hotkeys_checks_per_second, "The number of times per second that the kernel will poll the HCI for hotkey events."); + +/* Keycode system */ + +struct key_entry { + u8 fncode; + u16 keycode; +}; + +static struct key_entry tlsup_hotkey_map[] = { + {2, KEY_FN_1}, + {0, 0} +}; + +static struct key_entry *tlsup_get_entry_by_scancode(int code) +{ + struct key_entry *key; + + for (key = tlsup_hotkey_map; key->fncode != 0; key++) { + if (key->fncode == code) + return key; + } + + return NULL; +} + +static struct key_entry *tlsup_get_entry_by_keycode(int code) +{ + struct key_entry *key; + + for (key = tlsup_hotkey_map; key->fncode != 0; key++) { + if (key->keycode == code) + return key; + } + + return NULL; +} + +static int tlsup_get_keycode(struct input_dev *dev, int scancode, int *keycode) +{ + struct key_entry *key = tlsup_get_entry_by_scancode(scancode); + + if (key != NULL) { + *keycode = key->keycode; + return 0; + } + + return -EINVAL; +} + +static int tlsup_set_keycode(struct input_dev *dev, int scancode, int keycode) +{ + struct key_entry *key = tlsup_get_entry_by_scancode(scancode); + int old_keycode; + + if (keycode < 0 || keycode > KEY_MAX) + return -EINVAL; + + if (key != NULL) { + old_keycode = key->keycode; + key->keycode = keycode; + set_bit(keycode, dev->keybit); + if (tlsup_get_entry_by_keycode(old_keycode) == NULL) + clear_bit(old_keycode, dev->keybit); + return 0; + } + + return -EINVAL; +} + +/* Hotkey system */ + +static struct input_polled_dev *tlsup_polled_dev = NULL; + +static int tlsup_read_hotkey_event(void) +{ + u32 value, hci_result; + if (tlsup_hci_read_1_reg(HCI_SYSTEM_EVENT, &value, &hci_result)) + return -EFAULT; + + if (hci_result == HCI_EMPTY) { + /* better luck next time */ + return 0; + } else if (hci_result == HCI_NOT_SUPPORTED) { + /* This is a workaround for an unresolved issue on + * some machines where system events sporadically + * become disabled. */ + tlsup_hci_write_1_reg(HCI_SYSTEM_EVENT, 1, &hci_result); + tlsup_info("Had to re-enable hotkeys.\n"); + return 0; + } else if (hci_result == HCI_SUCCESS) { + /* Process key */ + if (value == 0x0100) { + /* Fn+ */ + return 0; + } else { + return value; + } + } else { + /* Unknown result */ + return -EFAULT; + } + /* Not reached */ + BUG(); +} + +static void tlsup_polled_dev_poll(struct input_polled_dev *dev) +{ + int scancode = tlsup_read_hotkey_event(); + struct key_entry *key; + + if (scancode <= 0) + return; + + key = tlsup_get_entry_by_scancode(scancode & 0x7F); + + if (key != NULL) { + input_report_key(dev->input, key->keycode, + !(scancode & 0x80)); + input_sync(dev->input); + } + +} + +/* Registration functions */ + +int tlsup_register_hotkeys(void) +{ + int ret; + struct input_dev *input; + struct key_entry *key; + + /* Swallow what's there already */ + while ((ret = tlsup_read_hotkey_event()) > 0); + + if (ret < 0) + return -EFAULT; + + + + /* Present and results are sane, register the backlight driver. */ + tlsup_polled_dev = input_allocate_polled_device(); + if (tlsup_polled_dev == NULL) { + tlsup_err("Could not allocate polled device for hotkeys\n"); + return -ENOMEM; + } + + tlsup_polled_dev->private = kmalloc(sizeof(tlsup_hotkey_map), GFP_KERNEL); + + tlsup_polled_dev->poll = tlsup_polled_dev_poll; + tlsup_polled_dev->poll_interval = 1000 / hotkeys_checks_per_second; + + /* id name phys bits */ + + input = tlsup_polled_dev->input; + + input->id.bustype = BUS_HOST; + input->name = "tlsup: Toshiba Fn Hotkeys"; + input->phys = "toshiba/hotkeys0"; + + input->keycode = tlsup_polled_dev->private; + input->keycodemax = ARRAY_SIZE(tlsup_hotkey_map); + input->keycodesize = sizeof(unsigned short); + + input->getkeycode = tlsup_get_keycode; + input->setkeycode = tlsup_set_keycode; + + set_bit(EV_KEY, input->evbit); + for (key = tlsup_hotkey_map; key->fncode != 0; key++) + set_bit(key->keycode, input->keybit); + clear_bit(KEY_RESERVED, input->keybit); + + if ((ret = input_register_polled_device(tlsup_polled_dev)) < 0) { + input_free_polled_device(tlsup_polled_dev); + tlsup_err("Could not register polled device for hotkeys\n"); + tlsup_polled_dev = NULL; + return ret; + } + + tlsup_info("Hotkeys polled every %dms.\n", 1000 / hotkeys_checks_per_second); + + return 1; +} + +void tlsup_deregister_hotkeys(void) +{ + if (tlsup_polled_dev != NULL) { + input_unregister_polled_device(tlsup_polled_dev); + input_free_polled_device(tlsup_polled_dev); + tlsup_polled_dev = NULL; + } +} --- linux-2.6.27.orig/ubuntu/tlsup/tlsup.h +++ linux-2.6.27/ubuntu/tlsup/tlsup.h @@ -0,0 +1,44 @@ +/* Toshiba Laptop Support -- tlsup.h + * + * General top level definitions etc for T.L.S. + * + * Copyright 2008 Daniel Silverstone + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; specifically version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * + * Credits: + * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse + * engineering the Windows drivers + * Rob Miller - TV out and hotkeys help + * John Belmonte - The toshiba_acpi driver maintainance for some time. + */ + +#ifndef TLSUP_H +#define TLSUP_H + +#define MODULE_LOGPREFIX "tlsup: " + +#define tlsup_info(X...) printk(KERN_INFO MODULE_LOGPREFIX X) +#define tlsup_err(X...) printk(KERN_ERR MODULE_LOGPREFIX X) +#define tlsup_notice(X...) printk(KERN_NOTICE MODULE_LOGPREFIX X) + +#include "tlsup_acpi.h" +#include "tlsup_backlight.h" +#include "tlsup_hotkeys.h" +#include "tlsup_radios.h" + +#endif /* TLSUP_H */ --- linux-2.6.27.orig/ubuntu/tlsup/Kconfig +++ linux-2.6.27/ubuntu/tlsup/Kconfig @@ -0,0 +1,4 @@ +config TLSUP + tristate "Toshiba ACPI laptop driver" + depends on ACPI && X86 + default m --- linux-2.6.27.orig/ubuntu/tlsup/tlsup_backlight.h +++ linux-2.6.27/ubuntu/tlsup/tlsup_backlight.h @@ -0,0 +1,44 @@ +/* Toshiba Laptop Support -- tlsup_backlight.h + * + * LCD Backlight support for T.L.S. + * + * Copyright 2008 Daniel Silverstone + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; specifically version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * + * Credits: + * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse + * engineering the Windows drivers + * Rob Miller - TV out and hotkeys help + * John Belmonte - The toshiba_acpi driver maintainance for some time. + */ + +#ifndef TLSUP_BACKLIGHT_H +#define TLSUP_BACKLIGHT_H + +/* Look for the LCD backlight support and if present, register a backlight + * class device to manage it. + * + * Returns -errno on error, 0 on success (but no registration) or 1 if + * a backlight was registered. + */ +extern int tlsup_register_backlight(void); + +/* Remove the registration of the backlight. */ +extern void tlsup_deregister_backlight(void); + +#endif /* TLSUP_BACKLIGHT_H */ --- linux-2.6.27.orig/ubuntu/tlsup/tlsup_acpi.h +++ linux-2.6.27/ubuntu/tlsup/tlsup_acpi.h @@ -0,0 +1,81 @@ +/* Toshiba Laptop Support -- tlsup_acpi.h + * + * ACPI support for T.L.S. + * + * Copyright 2008 Daniel Silverstone + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; specifically version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * + * Credits: + * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse + * engineering the Windows drivers + * Rob Miller - TV out and hotkeys help + * John Belmonte - The toshiba_acpi driver maintainance for some time. + */ + +#ifndef TLSUP_ACPI_H +#define TLSUP_ACPI_H + +/* Detect the toshiba ACPI support and prepare the HCI. + * Returns zero on success, -errno on failure. + */ +extern int tlsup_acpi_detect(void); + +/* Report the details of the chosen/found ACPI interface to the kernel + * log + */ +extern void tlsup_acpi_report(void); + +/* Toshiba HCI */ + +#define HCI_SUCCESS 0x0000 +#define HCI_FAILURE 0x1000 +#define HCI_NOT_SUPPORTED 0x8000 +#define HCI_EMPTY 0x8c00 + +/* perform an HCI read operation, returning one u32 value and the + * HCI status. + * + * The function itself returns 0 on success, -errno on failure. + */ +extern int tlsup_hci_read_1_reg(u32 reg, u32 *result, u32 *hci_status); + +/* perform an HCI write operation with one u32 value and returning the + * HCI status. + * + * The function itself returns 0 on success, -errno on failure. + */ +extern int tlsup_hci_write_1_reg(u32 reg, u32 value, u32 *hci_status); + +/* perform an HCI read operation, returning two u32 values and the HCI + * status. + * + * The two values are passed to the call, so zero them if you don't + * want that. + * + * The function itself returns 0 on success, -errno on failure. + */ +extern int tlsup_hci_read_2_reg(u32 reg, u32 *result1, u32 *result2, u32 *hci_status); + +/* perform an HCI write operation with two u32 values and returning + * the HCI status. + * + * The function itself returns 0 on success, -errno on failure. + */ +extern int tlsup_hci_write_2_reg(u32 reg, u32 value1, u32 value2, u32 *hci_status); + +#endif /* TLSUP_ACPI_H */ --- linux-2.6.27.orig/ubuntu/tlsup/tlsup_acpi.c +++ linux-2.6.27/ubuntu/tlsup/tlsup_acpi.c @@ -0,0 +1,162 @@ +/* Toshiba Laptop Support -- tlsup_acpi.c + * + * ACPI support for T.L.S. + * + * Copyright 2008 Daniel Silverstone + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; specifically version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * + * Credits: + * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse + * engineering the Windows drivers + * Rob Miller - TV out and hotkeys help + * John Belmonte - The toshiba_acpi driver maintainance for some time. + */ + +#include +#include +#include +#include + +#include + +#include "tlsup.h" + +/* Toshibas use one of two ACPI method named typically. + * + * The one we detect goes in here. + */ +static const char *hci_method = NULL; + +#define HCI_METHOD_1 "\\_SB_.VALD.GHCI" +#define HCI_METHOD_2 "\\_SB_.VALZ.GHCI" + +/* Check if the provided method name is a valid ACPI method for + * the machine. + * + * Return 0 if it is not valid, 1 if it is. + */ +static int is_valid_acpi_path(const char *method_name) +{ + acpi_handle handle; + acpi_status status; + + status = acpi_get_handle(NULL, (char *)method_name, &handle); + return !ACPI_FAILURE(status); +} + + +/* Detect the toshiba ACPI support and prepare the HCI. + * Returns zero on success, -errno on failure. + */ +int tlsup_acpi_detect(void) +{ + if (acpi_disabled) + return -ENODEV; + + if (is_valid_acpi_path(HCI_METHOD_1)) + hci_method = HCI_METHOD_1; + else if (is_valid_acpi_path(HCI_METHOD_2)) + hci_method = HCI_METHOD_2; + else + return -ENODEV; + + return 0; +} + +void tlsup_acpi_report(void) +{ + tlsup_info(" HCI method: %s\n", hci_method); +} + +/* Toshiba HCI IO */ + +#define HCI_WORDS (6) + +/* operations */ +#define HCI_SET 0xff00 +#define HCI_GET 0xfe00 + +static acpi_status tlsup_hci_raw_io(const u32 input[HCI_WORDS], u32 output[HCI_WORDS]) +{ + struct acpi_object_list params; + union acpi_object in_objs[HCI_WORDS]; + struct acpi_buffer results; + union acpi_object out_objs[HCI_WORDS + 1]; + acpi_status status; + int i; + + params.count = HCI_WORDS; + params.pointer = in_objs; + for (i = 0; i < HCI_WORDS; ++i) { + in_objs[i].type = ACPI_TYPE_INTEGER; + in_objs[i].integer.value = input[i]; + } + + results.length = sizeof(out_objs); + results.pointer = out_objs; + + status = acpi_evaluate_object(NULL, (char *)hci_method, ¶ms, + &results); + if ((status == AE_OK) && (out_objs->package.count <= HCI_WORDS)) { + for (i = 0; i < out_objs->package.count; ++i) { + output[i] = out_objs->package.elements[i].integer.value; + } + } + + return status; +} + +int tlsup_hci_read_1_reg(u32 reg, u32 *result, u32 *hci_status) +{ + u32 hci_input[HCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 }; + u32 hci_output[HCI_WORDS]; + acpi_status status = tlsup_hci_raw_io(hci_input, hci_output); + *result = hci_output[2]; + *hci_status = (status == AE_OK) ? hci_output[0] : HCI_FAILURE; + return (status == AE_OK) ? 0 : -EIO; +} + +int tlsup_hci_write_1_reg(u32 reg, u32 value, u32 *hci_status) +{ + u32 hci_input[HCI_WORDS] = { HCI_SET, reg, value, 0, 0, 0 }; + u32 hci_output[HCI_WORDS]; + acpi_status status = tlsup_hci_raw_io(hci_input, hci_output); + *hci_status = (status == AE_OK) ? hci_output[0] : HCI_FAILURE; + return (status == AE_OK) ? 0 : -EIO; +} + +int tlsup_hci_read_2_reg(u32 reg, u32 *result1, u32 *result2, u32 *hci_status) +{ + u32 hci_input[HCI_WORDS] = { HCI_GET, reg, *result1, *result2, 0, 0 }; + u32 hci_output[HCI_WORDS]; + acpi_status status = tlsup_hci_raw_io(hci_input, hci_output); + *result1 = hci_output[2]; + *result2 = hci_output[3]; + *hci_status = (status == AE_OK) ? hci_output[0] : HCI_FAILURE; + return (status == AE_OK) ? 0 : -EIO; +} + +int tlsup_hci_write_2_reg(u32 reg, u32 value1, u32 value2, u32 *hci_status) +{ + u32 hci_input[HCI_WORDS] = { HCI_SET, reg, value1, value2, 0, 0 }; + u32 hci_output[HCI_WORDS]; + acpi_status status = tlsup_hci_raw_io(hci_input, hci_output); + *hci_status = (status == AE_OK) ? hci_output[0] : HCI_FAILURE; + return (status == AE_OK) ? 0 : -EIO; +} + --- linux-2.6.27.orig/ubuntu/tlsup/tlsup_radios.h +++ linux-2.6.27/ubuntu/tlsup/tlsup_radios.h @@ -0,0 +1,45 @@ +/* Toshiba Laptop Support -- tlsup_radios.h + * + * Radio kill-switch support for T.L.S. + * + * Copyright 2008 Daniel Silverstone + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; specifically version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * + * Credits: + * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse + * engineering the Windows drivers + * Rob Miller - TV out and hotkeys help + * John Belmonte - The toshiba_acpi driver maintainance for some time. + */ + +#ifndef TLSUP_RADIOS_H +#define TLSUP_RADIOS_H + +/* Look for the radio kill switch support and if present, register + * rfkill devices to manage them. This supports wifi, bluetooth and + * hsdpa modem. + * + * Returns -errno on error, 0 on success (but no registration) or the + * number of rfkills registered. + */ +extern int tlsup_register_radios(void); + +/* Remove the registration of the radios. */ +extern void tlsup_deregister_radios(void); + +#endif /* TLSUP_RADIOS_H */ --- linux-2.6.27.orig/ubuntu/tlsup/Makefile +++ linux-2.6.27/ubuntu/tlsup/Makefile @@ -0,0 +1,6 @@ +TLSUP_VERSION := 0.10 +EXTRA_CFLAGS += '-DTLSUP_VERSION="$(TLSUP_VERSION)"' + +obj-$(CONFIG_TLSUP) := tlsup.o + +tlsup-objs := tlsup_mod.o tlsup_acpi.o tlsup_backlight.o tlsup_hotkeys.o tlsup_radios.o --- linux-2.6.27.orig/ubuntu/tlsup/tlsup_hotkeys.h +++ linux-2.6.27/ubuntu/tlsup/tlsup_hotkeys.h @@ -0,0 +1,45 @@ +/* Toshiba Laptop Support -- tlsup_hotkeys.h + * + * Hotkeys input support for T.L.S. + * + * Copyright 2008 Daniel Silverstone + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; specifically version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * + * Credits: + * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse + * engineering the Windows drivers + * Rob Miller - TV out and hotkeys help + * John Belmonte - The toshiba_acpi driver maintainance for some time. + */ + +#ifndef TLSUP_HOTKEYS_H +#define TLSUP_HOTKEYS_H + +/* Look for the hotkey support in the HCI and if found, register with + * input-polldev to get an input device to provide events to userland + * with. + * + * Returns -errno on error, 0 on success (but no registration) or 1 if + * an input device was registered. + */ +extern int tlsup_register_hotkeys(void); + +/* Remove the registration of the hotkeys input device. */ +extern void tlsup_deregister_hotkeys(void); + +#endif /* TLSUP_BACKLIGHT_H */ --- linux-2.6.27.orig/ubuntu/tlsup/tlsup_backlight.c +++ linux-2.6.27/ubuntu/tlsup/tlsup_backlight.c @@ -0,0 +1,115 @@ +/* Toshiba Laptop Support -- tlsup_backlight.c + * + * LCD Backlight support for T.L.S. + * + * Copyright 2008 Daniel Silverstone + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; specifically version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * + * Credits: + * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse + * engineering the Windows drivers + * Rob Miller - TV out and hotkeys help + * John Belmonte - The toshiba_acpi driver maintainance for some time. + */ + +#include +#include +#include +#include +#include +#include + +#include "tlsup.h" + +/* HCI registers */ +#define HCI_REG_LCD_BRIGHTNESS 0x002a + +/* Value manipulation */ +#define HCI_LCD_BRIGHTNESS_BITS 3 +#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) +#define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS) + + +/* Backlight driver */ +static struct backlight_device *tlsup_backlight_device = NULL; + +static int tlsup_read_brightness(struct backlight_device *bd) +{ + u32 hci_result; + u32 value; + + if (tlsup_hci_read_1_reg(HCI_REG_LCD_BRIGHTNESS, &value, &hci_result)) + return -EFAULT; + + if (hci_result != HCI_SUCCESS) + return -EFAULT; + + return (value >> HCI_LCD_BRIGHTNESS_SHIFT); +} + +static int tlsup_set_brightness(struct backlight_device *bd) +{ + u32 hci_result; + u32 value = bd->props.brightness << HCI_LCD_BRIGHTNESS_SHIFT; + + if (tlsup_hci_write_1_reg(HCI_REG_LCD_BRIGHTNESS, value, &hci_result)) + return -EFAULT; + + if (hci_result != HCI_SUCCESS) + return -EFAULT; + + return 0; +} + +static struct backlight_ops tlsup_backlight_data = { + .get_brightness = tlsup_read_brightness, + .update_status = tlsup_set_brightness, +}; + +/* Registration functions */ + +int tlsup_register_backlight(void) +{ + u32 hci_result, ignored; + if (tlsup_hci_read_1_reg(HCI_REG_LCD_BRIGHTNESS, &ignored, &hci_result)) + return -EFAULT; + if (hci_result != HCI_SUCCESS) + return 0; + /* Present and results are sane, register the backlight driver. */ + tlsup_backlight_device = backlight_device_register("toshiba", + NULL, + NULL, + &tlsup_backlight_data); + + if (IS_ERR(tlsup_backlight_device)) { + int ret = PTR_ERR(tlsup_backlight_device); + tlsup_err("Could not register backlight device\n"); + tlsup_backlight_device = NULL; + return ret; + } + + tlsup_backlight_device->props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; + + return 1; +} + +void tlsup_deregister_backlight(void) +{ + if (tlsup_backlight_device) + backlight_device_unregister(tlsup_backlight_device); +} --- linux-2.6.27.orig/ubuntu/tlsup/tlsup_mod.c +++ linux-2.6.27/ubuntu/tlsup/tlsup_mod.c @@ -0,0 +1,87 @@ +/* Toshiba Laptop Support -- tlsup_mod.c + * + * Aggregation and module structural support for T.L.S. + * + * Copyright 2008 Daniel Silverstone + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; specifically version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * + * Credits: + * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse + * engineering the Windows drivers + * Rob Miller - TV out and hotkeys help + * John Belmonte - The toshiba_acpi driver maintainance for some time. + */ + +#include +#include +#include +#include + +#include "tlsup.h" + +MODULE_AUTHOR("Daniel Silverstone"); +MODULE_DESCRIPTION("Toshiba Laptop Support Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(TLSUP_VERSION); + +/* The following ACPI devices tend to be exported by toshiba laptops */ +MODULE_ALIAS("acpi:TOS6200"); +MODULE_ALIAS("acpi:TOS6207"); +MODULE_ALIAS("acpi:TOS6208"); + +static void toshiba_laptop_support_exit(void) +{ + tlsup_deregister_radios(); + tlsup_deregister_hotkeys(); + tlsup_deregister_backlight(); +} + +static int __init toshiba_laptop_support_init(void) +{ + int ret; + + if ((ret = tlsup_acpi_detect()) < 0) + return ret; + + tlsup_info("Toshiba Laptop Support version %s initialising...\n", + TLSUP_VERSION); + + tlsup_acpi_report(); + + if ((ret = tlsup_register_backlight()) < 0) + return ret; + + if ((ret = tlsup_register_hotkeys()) < 0) { + tlsup_deregister_backlight(); + return ret; + } + + if ((ret = tlsup_register_radios()) < 0) { + tlsup_deregister_hotkeys(); + tlsup_deregister_backlight(); + return ret; + } + + tlsup_info("Toshiba Laptop Support version %s loaded.\n", + TLSUP_VERSION); + + return 0; +} + +module_init(toshiba_laptop_support_init); +module_exit(toshiba_laptop_support_exit); --- linux-2.6.27.orig/ubuntu/tlsup/BOM +++ linux-2.6.27/ubuntu/tlsup/BOM @@ -0,0 +1,4 @@ +Downloaded from: http://bzr.digital-scurf.org/trees/dsilvers/toshiba-laptop-support/ +Current Version: Mon, 11 Aug 2008 13:07:54 -0400 +Comments: Supercedes toshiba and toshiba_acpi drivers. + --- linux-2.6.27.orig/ubuntu/tlsup/tlsup_radios.c +++ linux-2.6.27/ubuntu/tlsup/tlsup_radios.c @@ -0,0 +1,334 @@ +/* Toshiba Laptop Support -- tlsup_radios.c + * + * Radio kill switch support for T.L.S. + * + * Copyright 2008 Daniel Silverstone + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; specifically version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * + * Credits: + * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse + * engineering the Windows drivers + * Rob Miller - TV out and hotkeys help + * John Belmonte - The toshiba_acpi driver maintainance for some time. + */ + +#include +#include +#include +#include +#include +#include + +#include "tlsup.h" + +/* Module stuff */ +static int radio_powerdown_time = 100; +static int powerup_settle_time = 200; + +module_param(radio_powerdown_time, uint, 0400); +MODULE_PARM_DESC(radio_powerdown_time, "The number of milliseconds between powering off a radio and the device power."); +module_param(powerup_settle_time, uint, 0400); +MODULE_PARM_DESC(powerup_settle_time, "The number of milliseconds between powering on a device and applying radio power."); + +/* HCI registers */ +#define HCI_WIRELESS 0x0056 + +/* Value manipulation */ +#define HCI_WIRELESS_PRESENT 0x0000 +#define HCI_WIRELESS_STATUS 0x0001 +#define HCI_WIRELESS_GLOBAL_RADIO_SWITCH 0x0001 +#define HCI_WIRELESS_3GHSDPA_POWER 0x4000 +#define HCI_WIRELESS_3GHSDPA_RADIO 0x2000 +#define HCI_WIRELESS_BLUETOOTH_POWER 0x0040 +#define HCI_WIRELESS_BLUETOOTH_RADIO 0x0080 +#define HCI_WIRELESS_WLAN_RADIO 0x0200 + +/* Radio manipulation functions */ + +static u32 tlsup_radios_present = 0; + +static int tlsup_test_radio_presence(u32 this_switch) +{ + u32 swvalue; + u32 swaddr; + u32 hci_result; + u32 current_status; + + swvalue = 0; + swaddr = HCI_WIRELESS_STATUS; + + if (tlsup_hci_read_2_reg(HCI_WIRELESS, &swvalue, &swaddr, &hci_result)) + return 0; + if (hci_result != HCI_SUCCESS) + return 0; + + current_status = (swvalue & this_switch) ? 1 : 0; + + /* Attempt to invert the current state */ + + swvalue = !current_status; + swaddr = this_switch; + if (tlsup_hci_write_2_reg(HCI_WIRELESS, swvalue, swaddr, &hci_result)) + return 0; + if (hci_result != HCI_SUCCESS) + return 0; + + /* Read back the allegedly inverted switch status */ + swvalue = 0; + swaddr = HCI_WIRELESS_STATUS; + + if (tlsup_hci_read_2_reg(HCI_WIRELESS, &swvalue, &swaddr, &hci_result)) + return 0; + if (hci_result != HCI_SUCCESS) + return 0; + + if (((swvalue & this_switch) ? 1 : 0) != !current_status) + /* Failed to invert */ + return 0; + + /* inversion successful, attempt to restore previous value */ + + swvalue = current_status; + swaddr = this_switch; + + if (tlsup_hci_write_2_reg(HCI_WIRELESS, swvalue, swaddr, &hci_result)) + return 0; + if (hci_result != HCI_SUCCESS) + return 0; + + /* verify restoration of value */ + + swvalue = 0; + swaddr = HCI_WIRELESS_STATUS; + + if (tlsup_hci_read_2_reg(HCI_WIRELESS, &swvalue, &swaddr, &hci_result)) + return 0; + if (hci_result != HCI_SUCCESS) + return 0; + + if (((swvalue & this_switch) ? 1 : 0) != current_status) + /* Failed to restore */ + return 0; + + /* Restoration successful */ + + tlsup_radios_present |= this_switch; + return 1; +} + +static enum rfkill_state tlsup_read_switch_state(u32 this_switch) +{ + u32 swvalue = 0; + u32 swaddr = HCI_WIRELESS_STATUS; + u32 hci_result; + + if (tlsup_hci_read_2_reg(HCI_WIRELESS, &swvalue, &swaddr, &hci_result)) + return 0; + if (hci_result != HCI_SUCCESS) + return 0; + + return (swvalue & this_switch) ? RFKILL_STATE_ON : RFKILL_STATE_OFF; +} + +static void tlsup_set_switch_state(u32 this_switch, enum rfkill_state state) +{ + u32 swvalue = state; + u32 swaddr = this_switch; + u32 hci_result; + + if (tlsup_hci_write_2_reg(HCI_WIRELESS, swvalue, swaddr, &hci_result)) { + tlsup_err("Error setting switch state\n"); + } + if (hci_result != HCI_SUCCESS) { + tlsup_err("Error setting switch state\n"); + } +} + +/* Radio rfkill driver */ + +struct tlsup_radio_power_control { + u32 power_reg; + u32 radio_reg; +}; + +static int tlsup_radio_switch_set(void *data, enum rfkill_state state) +{ + struct tlsup_radio_power_control *rpc = (struct tlsup_radio_power_control *)data; + + if (state == RFKILL_STATE_OFF) { + if (rpc->radio_reg) { + tlsup_set_switch_state(rpc->radio_reg, RFKILL_STATE_OFF); + msleep(radio_powerdown_time); + } + + if (rpc->power_reg) + tlsup_set_switch_state(rpc->power_reg, RFKILL_STATE_OFF); + } else { + if (rpc->power_reg) { + tlsup_set_switch_state(rpc->power_reg, RFKILL_STATE_ON); + msleep(powerup_settle_time); + } + if (rpc->radio_reg) + tlsup_set_switch_state(rpc->radio_reg, RFKILL_STATE_ON); + } + + return 0; +} + +static struct rfkill *hsdpa_rfkill_dev = NULL; +static struct rfkill *bluetooth_rfkill_dev = NULL; +static struct rfkill *wlan_rfkill_dev = NULL; + +static struct rfkill *tlsup_register_rfkill(const char *name, enum rfkill_type rft, + u32 optional_power, + u32 optional_radio) +{ + struct tlsup_radio_power_control *rpc; + struct rfkill *ret; + enum rfkill_state curstate = RFKILL_STATE_OFF; + + ret = rfkill_allocate(NULL, rft); + + if (ret == NULL) + return NULL; + + rpc = kmalloc(sizeof(struct tlsup_radio_power_control), GFP_KERNEL); + if (rpc == NULL) { + rfkill_free(ret); + return NULL; + } + + ret->name = name; + ret->data = rpc; + + rpc->power_reg = optional_power; + rpc->radio_reg = optional_radio; + + if (optional_power) + curstate |= tlsup_read_switch_state(optional_power); + if (optional_radio) + curstate |= tlsup_read_switch_state(optional_radio); + + ret->state = curstate; + + if (optional_power) + tlsup_set_switch_state(optional_power, curstate); + if (optional_radio) + tlsup_set_switch_state(optional_radio, curstate); + + ret->toggle_radio = tlsup_radio_switch_set; + ret->user_claim_unsupported = 1; + + rfkill_register(ret); + + return ret; +} + +/* Registration functions */ + +int tlsup_register_radios(void) +{ + int hsdpa_present = 0, bluetooth_present = 0, wlan_present = 0; + int registered = 0; + + if (tlsup_test_radio_presence(HCI_WIRELESS_3GHSDPA_POWER)) { + hsdpa_present = 1; + } + + if (tlsup_test_radio_presence(HCI_WIRELESS_3GHSDPA_RADIO)) { + hsdpa_present = 1; + } + + if (tlsup_test_radio_presence(HCI_WIRELESS_BLUETOOTH_POWER)) { + bluetooth_present = 1; + } + + if (tlsup_test_radio_presence(HCI_WIRELESS_BLUETOOTH_RADIO)) { + bluetooth_present = 1; + } + + if (tlsup_test_radio_presence(HCI_WIRELESS_WLAN_RADIO)) { + wlan_present = 1; + } + + if (hsdpa_present) { + tlsup_info("HSDPA Modem power switch %spresent, radio switch %spresent\n", + (tlsup_radios_present & HCI_WIRELESS_3GHSDPA_POWER) ? "" : "not ", + (tlsup_radios_present & HCI_WIRELESS_3GHSDPA_RADIO) ? "" : "not "); + hsdpa_rfkill_dev = tlsup_register_rfkill("tlsup-hsdpa_3g_modem", RFKILL_TYPE_WLAN, + HCI_WIRELESS_3GHSDPA_POWER, + HCI_WIRELESS_3GHSDPA_RADIO); + if (hsdpa_rfkill_dev) { + tlsup_info("HSDPA Modem claims to be %s\n", + (hsdpa_rfkill_dev->state == RFKILL_STATE_OFF) ? "off" : "on"); + registered++; + } else { + tlsup_err("Failed to register HSDPA modem switch\n"); + } + } + + if (bluetooth_present) { + tlsup_info("Bluetooth power switch %spresent, radio switch %spresent\n", + (tlsup_radios_present & HCI_WIRELESS_BLUETOOTH_POWER) ? "" : "not ", + (tlsup_radios_present & HCI_WIRELESS_BLUETOOTH_RADIO) ? "" : "not "); + bluetooth_rfkill_dev = tlsup_register_rfkill("tlsup-bluetooth", RFKILL_TYPE_BLUETOOTH, + HCI_WIRELESS_BLUETOOTH_POWER, + HCI_WIRELESS_BLUETOOTH_RADIO); + if (bluetooth_rfkill_dev) { + tlsup_info("Bluetooth claims to be %s\n", + (bluetooth_rfkill_dev->state == RFKILL_STATE_OFF) ? "off" : "on"); + registered++; + } else { + tlsup_err("Failed to register bluetooth switch\n"); + } + } + + if (wlan_present) { + tlsup_info("WLAN radio switch %spresent\n", + (tlsup_radios_present & HCI_WIRELESS_WLAN_RADIO) ? "" : "not "); + wlan_rfkill_dev = tlsup_register_rfkill("tlsup-wlan", RFKILL_TYPE_WLAN, + 0, + HCI_WIRELESS_WLAN_RADIO); + if (wlan_rfkill_dev) { + tlsup_info("WLAN claims to be %s\n", + (wlan_rfkill_dev->state == RFKILL_STATE_OFF) ? "off" : "on"); + registered++; + } else { + tlsup_err("Failed to register WLAN switch\n"); + } + } + + return registered; +} + +static inline void tlsup_free_rfkill_dev(struct rfkill *d) +{ + void *data = d->data; + rfkill_unregister(d); + kfree(data); +} + +void tlsup_deregister_radios(void) +{ + if (hsdpa_rfkill_dev) + tlsup_free_rfkill_dev(hsdpa_rfkill_dev); + if (bluetooth_rfkill_dev) + tlsup_free_rfkill_dev(bluetooth_rfkill_dev); + if (wlan_rfkill_dev) + tlsup_free_rfkill_dev(wlan_rfkill_dev); +} --- linux-2.6.27.orig/ubuntu/heci/heci_data_structures.h +++ linux-2.6.27/ubuntu/heci/heci_data_structures.h @@ -0,0 +1,538 @@ +/* + * Part of Intel(R) Manageability Engine Interface Linux driver + * + * Copyright (c) 2003 - 2007 Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + */ + +#ifndef _HECI_DATA_STRUCTURES_H_ +#define _HECI_DATA_STRUCTURES_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * error code definition + */ +#define ESUCCESS 0 +#define ESLOTS_OVERFLOW 1 +#define ECORRUPTED_MESSAGE_HEADER 1000 +#define ECOMPLETE_MESSAGE 1001 +#define FC_MESSAGE_RESERVED_LENGTH 5 + +/** + * Number of queue lists used by this driver + */ +#define NUMBER_OF_LISTS 7 + +#define LEGACY_MTU 4160 +#pragma pack(1) + + +/** + * HECI HW Section + */ + +/* HECI addresses and defines */ +#define H_CB_WW 0 +#define H_CSR 4 +#define ME_CB_RW 8 +#define ME_CSR_HA 0xC + + +/* register bits - H_CSR */ + +#define H_CBD 0xFF000000 +#define H_CBWP 0x00FF0000 +#define H_CBRP 0x0000FF00 +#define H_RST 0x00000010 +#define H_RDY 0x00000008 +#define H_IG 0x00000004 +#define H_IS 0x00000002 +#define H_IE 0x00000001 + + +/* register bits - ME_CSR_HA */ +#define ME_CBD_HRA 0xFF000000 +#define ME_CBWP_HRA 0x00FF0000 +#define ME_CBRP_HRA 0x0000FF00 +#define ME_RST_HRA 0x00000010 +#define ME_RDY_HRA 0x00000008 +#define ME_IG_HRA 0x00000004 +#define ME_IS_HRA 0x00000002 +#define ME_IE_HRA 0x00000001 + +/** + * heci driver use additional char device for legacy mode + */ +#define MINORS_COUNT 2 + +#define LEGACY_MINOR_NUMBER 0 +#define HECI_MINOR_NUMBER 1 +#define MAX_OPEN_HANDLE_COUNT 253 +/** + * debug kernel print macro define + */ +#define HECI_INFO(format, arg...) printk(KERN_INFO "%s: " format, THIS_MODULE->name, ## arg) +#define HECI_ERR(format, arg...) printk(KERN_ERR "%s: " format, THIS_MODULE->name, ## arg) +#define HECI_WARN(format, arg...) printk(KERN_WARNING "%s: " format, THIS_MODULE->name, ## arg) + + +/* Module Parameters */ +#define DEF_PARM(type, name, init, perm, desc) \ + type name = (init); \ + MODULE_PARM_DESC(name, desc); \ + module_param(name, type, perm) + +extern int heci_debug; + +#define DBG(format, arg...) do {if (heci_debug) \ +printk(KERN_ERR "%s: " format , __func__ , ## arg); \ +} while (0) + +#ifdef HECI_DEBUG +#define assert(expr) do {} while (0) +#else +#define assert(expr) \ + if (!(expr)) { \ + printk("Assertion failed! %s, %s, %s, line=%d\n", \ + #expr, __FILE__, __func__, __LINE__); \ + } +#endif + +/** + * time to wait event + */ +#define HECI_INTEROP_TIMEOUT (HZ * 7) + +/** + * watch dog definition + */ +#define HECI_WATCHDOG_DATA_SIZE 16 +#define HECI_START_WD_DATA_SIZE 20 +#define HECI_WD_PARAMS_SIZE 4 + +#define HECI_NO_MSG_SENT 0 +#define HECI_WD_STATE_INDEPENDENCE_MSG_SENT (1 << 0) + + +#define HECI_WD_HOST_CLIENT_ID 1 +#define HECI_LEGACY_HOST_CLIENT_ID 2 + +#undef FALSE +#undef TRUE +#define TRUE 1 +#define FALSE 0 + +struct guid { + __u32 data1; + __u16 data2; + __u16 data3; + __u8 data4[8]; +}; + +/* File state */ +enum file_state { + HECI_FILE_INITIALIZING = 0, + HECI_FILE_CONNECTING, + HECI_FILE_CONNECTED, + HECI_FILE_DISCONNECTING, + HECI_FILE_DISCONNECTED +}; + +/* HECI states */ +enum heci_states{ + HECI_INITIALIZING = 0, + HECI_ENABLED, + HECI_RESETING, + HECI_DISABLED, + HECI_RECOVERING_FROM_RESET, + HECI_POWER_DOWN, + HECI_POWER_UP +}; + +enum legacy_states { + HECI_LEGACY_IDLE, + HECI_LEGACY_WRITING, + HECI_LEGACY_FLOW_CONTROL, + HECI_LEGACY_READING, + HECI_LEGACY_READ_COMPLETE +}; + +enum heci_file_transaction_states { + HECI_IDLE, + HECI_WRITING, + HECI_WRITE_COMPLETE, + HECI_FLOW_CONTROL, + HECI_READING, + HECI_READ_COMPLETE +}; + +/* HECI CB */ +enum heci_cb_major_types { + HECI_READ = 0, + HECI_WRITE, + HECI_IOCTL, + HECI_OPEN, + HECI_CLOSE +}; + +/* HECI user data struct */ +struct heci_message_data { + __u32 size; + char *data; +}; +#define SECOND_TO_MILLI 1000 +#define SECOND_TO_MICRO SECOND_TO_MILLI * 1000 +#define SECOND_TO_100NANO SECOND_TO_MICRO * 10 + +#define CONNECT_TIMEOUT 3 /* at least 2 seconds */ + +#define LEGACY_STALL_TIMER 12 /* seconds */ +#define LEGACY_READ_TIMER 15 /* seconds */ + +struct heci_cb_private { + struct list_head cb_list; + enum heci_cb_major_types major_file_operations; + void *file_private; + struct heci_message_data request_buffer; + struct heci_message_data response_buffer; + unsigned long information; + unsigned long read_time; + struct file *file_object; +}; + +/* Private file struct */ +struct heci_file_private { + struct list_head link; + struct file *file; + enum file_state state; + wait_queue_head_t tx_wait; + wait_queue_head_t rx_wait; + wait_queue_head_t wait; + spinlock_t file_lock; + spinlock_t read_io_lock; + spinlock_t write_io_lock; + int read_pending; + int status; + /* ID of client connected */ + __u8 host_client_id; + __u8 me_client_id; + __u8 flow_control_credentials; + __u8 timer_count; + enum heci_file_transaction_states reading_state; + enum heci_file_transaction_states writing_state; + int sm_state; + struct heci_cb_private *read_cb; +}; + +struct io_heci_list { + struct heci_cb_private heci_cb; + int status; + struct iamt_heci_device *device_extension; +}; + +struct heci_driver_version { + __u8 major; + __u8 minor; + __u8 hotfix; + __u16 build; +}; + + +struct heci_client { + __u32 max_message_length; + __u8 protocol_version; +}; +/* + * HECI BUS Interface Section + */ +struct heci_message_header { + __u32 me_address:8; + __u32 host_address:8; + __u32 length:9; + __u32 reserved:6; + __u32 message_complete:1; +}; + + +struct hbm_command { + __u8 command:7; + __u8 is_response:1; +}; + + +struct heci_bus_message { + struct hbm_command command; + __u8 command_specific_data[]; +}; + +struct hbm_version { + __u8 minor_version; + __u8 major_version; +}; + +struct hbm_host_version_request { + struct hbm_command command; + __u8 reserved; + struct hbm_version host_version; +}; + +struct hbm_host_version_response { + struct hbm_command command; + int host_version_supported; + struct hbm_version me_max_version; +}; + +struct hbm_host_stop_request { + struct hbm_command command; + __u8 reason; + __u8 reserved[2]; +}; + +struct hbm_host_stop_response { + struct hbm_command command; + __u8 reserved[3]; +}; + +struct hbm_me_stop_request { + struct hbm_command command; + __u8 reason; + __u8 reserved[2]; +}; + +struct hbm_host_enumeration_request { + struct hbm_command command; + __u8 reserved[3]; +}; + +struct hbm_host_enumeration_response { + struct hbm_command command; + __u8 reserved[3]; + __u8 valid_addresses[32]; +}; + +struct heci_client_properties { + struct guid protocol_name; + __u8 protocol_version; + __u8 max_number_of_connections; + __u8 fixed_address; + __u8 single_receive_buffer; + __u32 max_message_length; +}; + +struct hbm_host_client_properties_request { + struct hbm_command command; + __u8 address; + __u8 reserved[2]; +}; + + +struct hbm_host_client_properties_response { + struct hbm_command command; + __u8 address; + __u8 status; + __u8 reserved[1]; + struct heci_client_properties client_properties; +}; + +struct hbm_client_connect_request { + struct hbm_command command; + __u8 me_address; + __u8 host_address; + __u8 reserved; +}; + +struct hbm_client_connect_response { + struct hbm_command command; + __u8 me_address; + __u8 host_address; + __u8 status; +}; + +struct hbm_client_disconnect_request { + struct hbm_command command; + __u8 me_address; + __u8 host_address; + __u8 reserved[1]; +}; + +struct hbm_flow_control { + struct hbm_command command; + __u8 me_address; + __u8 host_address; + __u8 reserved[FC_MESSAGE_RESERVED_LENGTH]; +}; + +struct heci_me_client { + struct heci_client_properties properteis; + __u8 client_id; + __u8 flow_control_credentials; +}; + +/* private device struct */ +struct iamt_heci_device { + struct pci_dev *pdev; /* pointer to pci device struct */ + /* + * lists of queues + */ + struct io_heci_list *io_list_array[NUMBER_OF_LISTS]; /* array of pointers to aio lists */ + struct io_heci_list read_list; /* driver read queue */ + struct io_heci_list write_list; /* driver write queue */ + struct io_heci_list write_waiting_list; /* driver write waiting queue */ + struct io_heci_list control_write_list; /* driver managed write IOCTL list */ + struct io_heci_list control_read_list; /* driver managed read IOCTL list */ + struct io_heci_list pthi_cmd_list; /* driver managed PTHI list for cmd waiting */ + struct io_heci_list pthi_read_complete_list; /* driver managed PTHI list for read completed pthi command data */ + /* + * list of files + */ + struct list_head file_list; + /* + * memory of device + */ + unsigned int mem_base; + unsigned int mem_length; + char *mem_addr; + /* + * lock for the device + */ + spinlock_t device_lock; + spinlock_t extra_lock; + /* + * intterupts + */ + int irq; + struct work_struct work; + int received_message; + + struct timer_list timer; + struct timer_list wd_timer; + /* + * hw states of host and fw(ME) + */ + __u32 host_hw_state; + __u32 me_hw_state; + /* + * waiting queue for receive message from FW + */ + wait_queue_head_t wait_received_message; + wait_queue_head_t wait_stop_wd; + /* + * heci device states + */ + enum heci_states heci_state; + int stop; + /** + * virtual void GetParam(const char* UserParam); + * read write messages to/from heci fw + */ + __u32 extra_write_index; + __u32 read_message_buffer[128]; /* used for control messages */ + __u32 write_message_buffer[128]; /* used for control messages */ + __u32 extra_message_buffer[8]; /* for control responses */ + __u32 read_message_header; + + struct hbm_version version; + + int host_buffer_is_empty; + struct heci_file_private wd_file_extension; + struct heci_me_client *me_clients; /* Note: memory has to be allocated */ + __u8 heci_me_clients[32]; /* list of existing clients */ + __u8 num_heci_me_clients; + __u8 heci_host_clients[32]; /* list of existing clients */ + __u8 current_host_client_id; + + int wd_pending; + int wd_stoped; + __u16 wd_timeout; /* seconds ((wd_data[1] << 8) + wd_data[0]) */ + unsigned char wd_data[HECI_START_WD_DATA_SIZE]; + + + __u16 wd_due_counter; + int asf_mode; + int wd_bypass; /* if true,don't refresh watchdog ME client */ + + /* maybe this is not required */ + struct file *legacy_file_object; + struct heci_file_private legacy_file_extension; + int legacy_ioctl; + int legacy_canceled; + __u32 legacy_timer; + __u32 legacy_stall_timer; + unsigned char legacy_message_buffer[LEGACY_MTU]; + __u32 legacy_message_buffer_size; + __u32 legacy_message_buffer_index; + int legacy_flow_control_pending; + enum legacy_states legacy_state; + + struct heci_cb_private *legacy_current_cb; + __u8 write_hang; + int need_reset; + long open_handle_count; + +}; + +/** + * read_heci_register - Read a byte from the heci device + * @device: the device structure + * @offset: offset from which to read the data + * + * Return: + * the byte read. + */ +__u32 read_heci_register(struct iamt_heci_device * device, + unsigned long offset); + +/** + * write_heci_register - Write 4 bytes to the heci device + * @device: the device structure + * @offset: offset from which to write the data + * + * @value: the byte to write + */ +void write_heci_register(struct iamt_heci_device * device, unsigned long offset, + __u32 value); + +#endif /* _HECI_DATA_STRUCTURES_H_ */ --- linux-2.6.27.orig/ubuntu/heci/heci_main.c +++ linux-2.6.27/ubuntu/heci/heci_main.c @@ -0,0 +1,1444 @@ +/* + * Part of Intel(R) Manageability Engine Interface Linux driver + * + * Copyright (c) 2003 - 2007 Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kcompat.h" +#include "heci.h" +#include "heci_interface.h" +#include "version.h" + + +#define HECI_READ_TIMEOUT 45 + +#define MAX_OPEN_HANDLE_COUNT 253 +/** + * heci driver strings + */ +char heci_driver_name[] = "heci"; +char heci_driver_string[] = "Intel(R) AMT Management Interface"; +char heci_driver_version[] = DRIVER_VERSION; +char heci_copyright[] = "Copyright (c) 2003 - 2007 Intel Corporation."; + + +#ifdef HECI_DEBUG +DEF_PARM(int, heci_debug, 1, 0644, "Debug enabled or not"); +#else +DEF_PARM(int, heci_debug, 0, 0644, "Debug enabled or not"); +#endif + +/* heci char device for registration */ +static struct cdev heci_cdev = { + .kobj = {.name = "heci", }, + .owner = THIS_MODULE, +}; + +/* iamt legacy char device for registration */ +static struct cdev iamt_legacy_cdev = { + .kobj = {.name = "iamt_legacy", }, + .owner = THIS_MODULE, +}; + +/* major number for device */ +static int heci_major; +/* The device pointer */ +static struct pci_dev *heci_device; + +/* heci_pci_tbl - PCI Device ID Table */ +static struct pci_device_id heci_pci_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID1)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID2)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID3)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID4)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID5)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID6)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID7)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_HECI_DEVICE_ID8)}, + /* required last entry */ + {0, } +}; + +MODULE_DEVICE_TABLE(pci, heci_pci_tbl); + +/** + * Local Function Prototypes + */ +static int __init heci_init_module(void); +static void __exit heci_exit_module(void); +static int __devinit heci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent); +static void __devexit heci_remove(struct pci_dev *pdev); +static int heci_open(struct inode *inode, struct file *file); +static int heci_release(struct inode *inode, struct file *file); +static unsigned int heci_legacy_poll(struct file *file, poll_table * wait); +static ssize_t heci_read(struct file *file, char __user * ubuf, + size_t length, loff_t * offset); +static int heci_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long data); +static ssize_t heci_write(struct file *file, const char __user * ubuf, + size_t length, loff_t * offset); +static unsigned int heci_poll(struct file *file, poll_table * wait); +#ifdef CONFIG_PM +static int heci_suspend(struct pci_dev* pdev, pm_message_t state); +static int heci_resume(struct pci_dev* pdev); +static __u16 g_sus_wd_timeout; +#endif +/** + * PCI driver structure + */ +static struct pci_driver heci_driver = { + .name = heci_driver_name, + .id_table = heci_pci_tbl, + .probe = heci_probe, + .remove = heci_remove, + SHUTDOWN_METHOD(heci_remove) +#ifdef CONFIG_PM + .suspend = heci_suspend, + .resume = heci_resume +#endif +}; + +/** + * file operations structure will be use heci char device. + */ +static struct file_operations heci_fops = { + .owner = THIS_MODULE, + .read = heci_read, + .ioctl = heci_ioctl, + .open = heci_open, + .release = heci_release, + .write = heci_write, + .poll = heci_poll, +}; + +/** + * file operations structure will be use iamt legacy char device. + */ +static struct file_operations iamt_legacy_fops = { + .owner = THIS_MODULE, + .ioctl = heci_ioctl, + .open = heci_open, + .release = heci_release, + .poll = heci_legacy_poll, +}; + +/** + * For kernels withouth PCI shutdown support reboot notifier is essential + */ +HECI_REBOOT_NOTIFIER(heci_reboot_notifier, heci_driver, heci_remove) + +/** + * Set up the cdev structure for heci device. + * @dev - char device struct + * @minor - minor number for registration char device + * @fops - file operations structure + * @return : + * 0 on success, + * negative on failure + */ +static int heci_registration_cdev(struct cdev *dev, int minor, + struct file_operations *fops) +{ + int ret = ESUCCESS, devno = MKDEV(heci_major, minor); + + cdev_init(dev, fops); + dev->owner = THIS_MODULE; + dev->ops = fops; + ret = cdev_add(dev, devno, 1); + /* Fail gracefully if need be */ + if (ret) { + kobject_put(&dev->kobj); + HECI_ERR("Error %d registering heci device %d", ret, minor); + } + return ret; +} + + + +/** + * heci_init_module - Driver Registration Routine + * + * heci_init_module is the first routine called when the driver is + * loaded. All it does is register with the PCI subsystem. + * + * @return : + * 0 on success, + * negative on failure + */ +static int __init heci_init_module(void) +{ + int ret = ESUCCESS; + dev_t dev; + HECI_INFO("%s - version %s\n", heci_driver_string, heci_driver_version); + HECI_INFO("%s\n", heci_copyright); + + /* init pci module */ + ret = pci_register_driver(&heci_driver); + if (ret < 0) + goto end; + + REGISTER_REBOOT_NOTIFIER(heci_reboot_notifier); + /* registration char devices */ + ret = alloc_chrdev_region(&dev, 0, MINORS_COUNT, "heci"); + + heci_major = MAJOR(dev); + /* Now registration two cdevs. */ + ret = heci_registration_cdev(&iamt_legacy_cdev, LEGACY_MINOR_NUMBER, + &iamt_legacy_fops); + if (ret) + goto unregister; + + ret = heci_registration_cdev(&heci_cdev, HECI_MINOR_NUMBER, + &heci_fops); + if (ret) { + cdev_del(&iamt_legacy_cdev); + goto unregister; + } + return ret; + +unregister: + pci_unregister_driver(&heci_driver); + unregister_chrdev_region(MKDEV(heci_major, 0), MINORS_COUNT); +end: + return ret; +} + +module_init(heci_init_module); + + +/** + * heci_exit_module - Driver Exit Cleanup Routine + * + * heci_exit_module is called just before the driver is removed + * from memory. + * + * @return : + * none; + */ + +static void __exit heci_exit_module(void) +{ + UNREGISTER_REBOOT_NOTIFIER(heci_reboot_notifier); + pci_unregister_driver(&heci_driver); + /* Now unregister two cdevs. */ + cdev_del(&iamt_legacy_cdev); + cdev_del(&heci_cdev); + unregister_chrdev_region(MKDEV(heci_major, 0), MINORS_COUNT); +} + +module_exit(heci_exit_module); + + +/** + * heci_probe - Device Initialization Routine + * + * @pdev: PCI device information struct + * @ent: entry in kcs_pci_tbl + * + * @return : + * 0 on success, + * negative on failure + */ +static int __devinit heci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct iamt_heci_device *device = NULL; + int i, err = 0; + if (heci_device) { + err = -EEXIST; + goto end; + } + /* enable pci device */ + err = pci_enable_device(pdev); + if (err) { + HECI_ERR("Failed to enable pci device\n"); + goto end; + } + /* set PCI host mastering */ + pci_set_master(pdev); + /* pci request regions for heci driver */ + err = pci_request_regions(pdev, heci_driver_name); + if (err) { + HECI_ERR("Failed to get pci regions\n"); + goto disable_device; + } + /* allocates and initializes the heci device structure */ + device = init_heci_device(pdev); + if (!device) { + err = -ENOMEM; + goto release_regions; + } + /* mapping IO device memory */ + for (i = BAR_0; i <= BAR_5; i++) { + if (pci_resource_len(pdev, i) == 0) { + continue; + } + if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { + HECI_ERR("heci has an IO ports.\n"); + goto free_device; + } else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { + if (device->mem_base) { + HECI_ERR("Too many mem addresses.\n"); + goto free_device; + } + device->mem_base = pci_resource_start(pdev, i); + device->mem_length = pci_resource_len(pdev, i); + } + } + if (!device->mem_base) { + HECI_ERR("No address to use.\n"); + err = -ENODEV; + goto free_device; + } + device->mem_addr = ioremap_nocache(device->mem_base, device->mem_length); + if (!device->mem_addr) { + HECI_ERR(" Remap IO device memory failure.\n"); + err = -ENOMEM; + goto free_device; + } + /* request and enable interrupt */ + device->irq = pdev->irq; + err = request_irq(device->irq, heci_isr_interrupt, IRQF_SHARED, + heci_driver_name, device); + if (err) { + HECI_ERR("Request_irq failure. irq = %d \n", device->irq); + goto unmap_memory; + } + + if (heci_hw_init(device)) { + HECI_ERR("init hw failure.\n"); + err = -ENODEV; + goto release_irq; + } + init_timer(&device->wd_timer); + heci_initialize_clients(device); + if (device->heci_state != HECI_ENABLED) { + err = -ENODEV; + goto release_hw; + } + spin_lock_bh(&device->device_lock); + heci_device = pdev; + pci_set_drvdata(pdev, device); + spin_unlock_bh(&device->device_lock); + if (device->wd_timeout) { + mod_timer(&device->wd_timer, jiffies); + } +#ifdef CONFIG_PM + g_sus_wd_timeout = 0; +#endif + HECI_INFO("heci driver initialization successful.\n"); + return ESUCCESS; + +release_hw: + /* disable interrupts */ + device->host_hw_state = read_heci_register(device, H_CSR); + device->host_hw_state &= ~H_IE; + /* acknowledge interrupt and stop interupts */ + write_heci_register(device, H_CSR, device->host_hw_state); + + del_timer_sync(&device->wd_timer); + + + flush_scheduled_work(); + +release_irq: + free_irq(pdev->irq, device); +unmap_memory: + if (device->mem_addr) + iounmap(device->mem_addr); +free_device: + kfree(device); +release_regions: + pci_release_regions(pdev); +disable_device: + pci_disable_device(pdev); +end: + HECI_ERR("heci driver initialization failed.\n"); + return err; +} + +/** + * heci_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * heci_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. + * + * @return : + * none; + */ +static void __devexit heci_remove(struct pci_dev *pdev) +{ + struct iamt_heci_device *device = pci_get_drvdata(pdev); + int err = 0; + + if (heci_device != pdev) + return; + del_timer_sync(&device->wd_timer); + if (device->wd_file_extension.state == HECI_FILE_CONNECTED + && device->wd_timeout) { + spin_lock_bh(&device->device_lock); + device->wd_timeout = 0; + device->wd_due_counter = 0; + memcpy(device->wd_data, stop_wd_params, HECI_WD_PARAMS_SIZE); + device->stop = TRUE; + if (device->host_buffer_is_empty && + flow_control_credentials(device, &device->wd_file_extension)) { + device->host_buffer_is_empty = FALSE; + + if (!heci_send_wd(device)) + DBG("Send stop WD failed\n"); + else + flow_control_reduce(device, &device->wd_file_extension); + device->wd_pending = FALSE; + + } else { + device->wd_pending = TRUE; + } + spin_unlock_bh(&device->device_lock); + device->wd_stoped = FALSE; + + err = + wait_event_interruptible_timeout(device->wait_stop_wd, + (TRUE == + device->wd_stoped), + 10 * HZ); + if (!device->wd_stoped) + DBG("stop wd failed to complete.\n"); + else + DBG("stop wd complete.\n"); + } + + heci_device = NULL; + if (device->legacy_file_extension.status == HECI_FILE_CONNECTED) { + device->legacy_file_extension.status = HECI_FILE_DISCONNECTING; + heci_disconnect_host_client(device, + &device->legacy_file_extension); + } + if (device->wd_file_extension.status == HECI_FILE_CONNECTED) { + device->wd_file_extension.status = HECI_FILE_DISCONNECTING; + heci_disconnect_host_client(device, + &device->wd_file_extension); + } + /* remove entry if already in list */ + DBG("list del legacy and wd file list.\n"); + heci_remove_client_from_file_list(device, device->wd_file_extension. + host_client_id); + heci_remove_client_from_file_list(device, device->legacy_file_extension. + host_client_id); + flush_scheduled_work(); + /* disable interrupts */ + device->host_hw_state &= ~H_IE; + /* acknowledge interrupt and stop interupts */ + write_heci_register(device, H_CSR, device->host_hw_state); + free_irq(pdev->irq, device); + pci_set_drvdata(pdev, NULL); + + if (device->mem_addr) + iounmap(device->mem_addr); + kfree(device); + + pci_release_regions(pdev); + pci_disable_device(pdev); +} +/** + * heci_clear_list - remove all callbacks associated with file + * from heci_cb_list + * @file: file informtion struct + * @heci_cb_list: callbacks list + * heci_clear_list is called to clear resources associated with file + * when application calls close function or Ctrl-C was pressed + * + * @return :true if callback removed from the list, false otherwise + */ +static int heci_clear_list(struct iamt_heci_device *device, struct file *file, struct list_head *heci_cb_list) { + struct heci_cb_private *kernel_priv_cb_pos = NULL, *kernel_priv_cb_next = NULL; + struct file *file_temp = NULL; + int return_status = FALSE; + + /* list all list member */ + list_for_each_entry_safe(kernel_priv_cb_pos, kernel_priv_cb_next, heci_cb_list, cb_list){ + file_temp = (struct file *)kernel_priv_cb_pos->file_object; + /* check if list member associated with a file */ + if (file_temp == file) { + /* remove member from the list */ + list_del(&kernel_priv_cb_pos->cb_list); + /* check if cb equal to current legacy cb */ + if (device->legacy_current_cb == kernel_priv_cb_pos) { + device->legacy_current_cb = NULL; + /* send flow control to legacy client */ + heci_send_flow_control(device, &device->legacy_file_extension); + } + /* free all allocated buffers */ + kfree (kernel_priv_cb_pos->request_buffer.data); + kernel_priv_cb_pos->request_buffer.data = NULL; + kfree (kernel_priv_cb_pos->response_buffer.data); + kernel_priv_cb_pos->response_buffer.data = NULL; + kfree(kernel_priv_cb_pos); + return_status = TRUE; + } + } + return return_status; +} + +/** + * heci_clear_lists - remove all callbacks associated with file + * @device: device informtion struct + * @file: file informtion struct + * heci_clear_lists is called to clear resources associated with file + * when application calls close function or Ctrl-C was pressed + * + * @return :true if callback removed from the list, false otherwise + */ +static int heci_clear_lists(struct iamt_heci_device *device, struct file *file) +{ + int return_status = FALSE; + + /* remove callbacks associated with a file */ + heci_clear_list(device, file, &device->pthi_cmd_list.heci_cb.cb_list); + if (heci_clear_list(device, file, &device->pthi_read_complete_list.heci_cb.cb_list)) + return_status = TRUE; + heci_clear_list(device, file, &device->control_read_list.heci_cb.cb_list); + if (heci_clear_list(device, file, &device->control_write_list.heci_cb.cb_list)) + return_status = TRUE; + if (heci_clear_list(device, file, &device->write_waiting_list.heci_cb.cb_list)) + return_status = TRUE; + if (heci_clear_list(device, file, &device->write_list.heci_cb.cb_list)) + return_status = TRUE; + /* check if legacy_current_cb not NULL */ + if (device->legacy_current_cb && (!return_status)) { + /* check file and legacy current cb association */ + if (device->legacy_current_cb->file_object == file) { + /* remove cb */ + kfree (device->legacy_current_cb->request_buffer.data); + device->legacy_current_cb->request_buffer.data = NULL; + kfree (device->legacy_current_cb->response_buffer.data); + device->legacy_current_cb->response_buffer.data = NULL; + kfree(device->legacy_current_cb); + device->legacy_current_cb = NULL; + return_status = TRUE; + } + } + return return_status; +} + +/** + * heci_open - the open function + */ +static int heci_open(struct inode *inode, struct file *file) +{ + struct heci_file_private *file_extension = NULL; + int if_num = MINOR(inode->i_rdev); + struct iamt_heci_device *device = NULL; + if (!heci_device) + return -ENODEV; + device = pci_get_drvdata(heci_device); + if (((if_num != LEGACY_MINOR_NUMBER) + && (if_num != HECI_MINOR_NUMBER)) || (!device)) + return -ENODEV; + + if (if_num != LEGACY_MINOR_NUMBER) { + file_extension = alloc_priv(file); + if (!file_extension) + return -ENOMEM; + } else { + file->private_data = + (void *) &device->legacy_file_extension; + return ESUCCESS; + } + spin_lock_bh(&device->device_lock); + if (device->heci_state != HECI_ENABLED) { + spin_unlock_bh(&device->device_lock); + kfree(file_extension); + file_extension = NULL; + return -ENODEV; + } + if (device->open_handle_count >= MAX_OPEN_HANDLE_COUNT) { + spin_unlock_bh(&device->device_lock); + kfree(file_extension); + file_extension = NULL; + return -ENFILE; + }; + device->open_handle_count++; + list_add_tail(&file_extension->link, &device->file_list); + while ((device->heci_host_clients[device->current_host_client_id / 8] + & (1 << (device->current_host_client_id % 8))) != 0) { + device->current_host_client_id++; /* allow overflow */ + DBG("current_host_client_id = %d\n", device->current_host_client_id); + DBG("device->open_handle_count = %lu\n", device->open_handle_count); + } + DBG("current_host_client_id = %d\n", device->current_host_client_id); + file_extension->host_client_id = device->current_host_client_id; + device->heci_host_clients[file_extension->host_client_id / 8] |= + (1 << (file_extension->host_client_id % 8)); + spin_unlock_bh(&device->device_lock); + spin_lock(&file_extension->file_lock); + file_extension->state = HECI_FILE_INITIALIZING; + file_extension->sm_state = 0; + + file->private_data = file_extension; + spin_unlock(&file_extension->file_lock); + + return ESUCCESS; +} + +/** + * heci_release - the release function + */ +static int heci_release(struct inode *inode, struct file *file) +{ + int return_status = ESUCCESS; + int if_num = MINOR(inode->i_rdev); + struct heci_file_private *file_extension = file->private_data; + struct heci_cb_private *kernel_priv_cb = NULL; + struct iamt_heci_device *device = NULL; + + if (!heci_device) + return -ENODEV; + + device = pci_get_drvdata(heci_device); + if (((if_num != LEGACY_MINOR_NUMBER) + && (if_num != HECI_MINOR_NUMBER)) || (!device) + || (!file_extension)) + return -ENODEV; + if (file_extension != &device->legacy_file_extension) { + + spin_lock(&file_extension->file_lock); + if (file_extension->state == HECI_FILE_CONNECTED) { + file_extension->state = HECI_FILE_DISCONNECTING; + spin_unlock(&file_extension->file_lock); + DBG("disconnecting client host client = %d, ME client = %d\n", + file_extension->host_client_id, + file_extension->me_client_id); + return_status = + heci_disconnect_host_client(device, + file_extension); + spin_lock(&file_extension->file_lock); + } + spin_lock_bh(&device->device_lock); + heci_flush_queues(device, file_extension); + DBG("remove client host client = %d, ME client = %d\n", + file_extension->host_client_id, + file_extension->me_client_id); + device->heci_host_clients[file_extension->host_client_id / 8] &= ~(1 << (file_extension->host_client_id % 8)); + device->open_handle_count--; + heci_remove_client_from_file_list(device, file_extension->host_client_id); + spin_unlock_bh(&device->device_lock); + + /* free read cb */ + if (file_extension->read_cb != NULL) { + spin_unlock(&file_extension->file_lock); + kernel_priv_cb = file_extension->read_cb; + kfree(kernel_priv_cb->response_buffer.data); + kernel_priv_cb->response_buffer.data = NULL; + kfree(kernel_priv_cb); + kernel_priv_cb = NULL; + + file_extension->read_cb = NULL; + spin_lock(&file_extension->file_lock); + } + spin_unlock(&file_extension->file_lock); + kfree(file_extension); + file->private_data = NULL; + } else { + spin_lock_bh(&device->device_lock); + if (if_num != LEGACY_MINOR_NUMBER) { + device->open_handle_count--; + } + if (device->legacy_file_object == file + && device->legacy_state != HECI_LEGACY_IDLE) { + + DBG("pthi canceled legacy state %d\n", + device->legacy_state); + device->legacy_canceled = TRUE; + if (device->legacy_state == HECI_LEGACY_READ_COMPLETE) { + DBG("run next pthi legacy cb\n"); + run_next_legacy_cmd(device); + } + } + + if (heci_clear_lists(device, file)) { + device->legacy_state = HECI_LEGACY_IDLE; + } + spin_unlock_bh(&device->device_lock); + } + return return_status; +} + + +static struct heci_cb_private *find_read_list_entry(struct iamt_heci_device* device, + struct heci_file_private *file_extension) +{ + struct heci_cb_private *kernel_priv_cb_pos = NULL, *kernel_priv_cb_next = NULL; + struct heci_file_private *file_extension_list_temp = NULL; + + if (device->read_list.status == ESUCCESS + && !list_empty(&device->read_list.heci_cb.cb_list)) { + DBG("remove read_list CB \n"); + list_for_each_entry_safe(kernel_priv_cb_pos, kernel_priv_cb_next, &device->read_list.heci_cb.cb_list, cb_list){ + file_extension_list_temp = + (struct heci_file_private *) + kernel_priv_cb_pos->file_private; + if (file_extension_list_temp) { + if ((file_extension->host_client_id == file_extension_list_temp->host_client_id) + && (file_extension->me_client_id == file_extension_list_temp->me_client_id)) + return kernel_priv_cb_pos; + } + } + } + return NULL; +} +/** + * heci_read - the read client message function. + */ +static ssize_t heci_read(struct file *file, char __user * ubuf, + size_t length, loff_t * offset) +{ + int i; + int return_status = ESUCCESS, err = ESUCCESS; + int if_num = MINOR((file->f_dentry->d_inode->i_rdev)); + struct heci_file_private *file_extension = file->private_data; + struct heci_cb_private *kernel_priv_cb_pos = NULL; + struct heci_cb_private *kernel_priv_cb = NULL; + struct iamt_heci_device *device = NULL; + + if (!heci_device) + return -ENODEV; + + device = pci_get_drvdata(heci_device); + if ((if_num != HECI_MINOR_NUMBER) || (!device) || (!file_extension)) + return -ENODEV; + + spin_lock_bh(&device->device_lock); + if (device->heci_state != HECI_ENABLED) { + spin_unlock_bh(&device->device_lock); + return -ENODEV; + } + spin_unlock_bh(&device->device_lock); + if (!file_extension) + return -ENODEV; + + spin_lock(&file_extension->file_lock); + if((file_extension->sm_state & HECI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) { + spin_unlock(&file_extension->file_lock); + /* Do not allow to read watchdog client */ + for (i = 0; i < device->num_heci_me_clients; i++) { + if (0 == memcmp(&heci_wd_guid, &device->me_clients[i].properteis.protocol_name, sizeof(struct guid))) { + if (file_extension->me_client_id == device->me_clients[i].client_id) + return -EBADF; + } + } + } else { + file_extension->sm_state &= ~HECI_WD_STATE_INDEPENDENCE_MSG_SENT; + spin_unlock(&file_extension->file_lock); + } + if (file_extension == &device->legacy_file_extension) { + return_status = pthi_read(device, if_num, file, ubuf, length, offset); + goto out; + } + + if (file_extension->read_cb && file_extension->read_cb->information > *offset) { + kernel_priv_cb = file_extension->read_cb; + goto copy_buffer; + } + else if (file_extension->read_cb && file_extension->read_cb->information > 0 && + file_extension->read_cb->information <= *offset) { + kernel_priv_cb = file_extension->read_cb; + return_status = 0; + goto free; + } + else if ((!file_extension->read_cb || file_extension->read_cb->information == 0) && + *offset > 0) { + *offset = 0; /*Offset needs to be cleaned for contingous reads*/ + return_status = 0; + goto out; + } + + spin_lock(&file_extension->read_io_lock); + err = heci_start_read(device, if_num, file_extension); + if (err != ESUCCESS && err != -EBUSY) { + DBG("heci start read failure with status = %d\n", err); + spin_unlock(&file_extension->read_io_lock); + return_status = err; + goto out; + } + if (HECI_READ_COMPLETE != file_extension->reading_state && !waitqueue_active (&file_extension->rx_wait)) { + if (file->f_flags & O_NONBLOCK) { + return_status = -EAGAIN; + spin_unlock(&file_extension->read_io_lock); + goto out; + } + spin_unlock(&file_extension->read_io_lock); + + if (wait_event_interruptible(file_extension->rx_wait, + (HECI_READ_COMPLETE == file_extension->reading_state || + HECI_FILE_INITIALIZING == file_extension->state || + HECI_FILE_DISCONNECTED == file_extension->state || + HECI_FILE_DISCONNECTING == file_extension->state))) { + if (signal_pending (current)) { + return_status = -EINTR; + goto out; + } + return -ERESTARTSYS; + } + + if (HECI_FILE_INITIALIZING == file_extension->state || + HECI_FILE_DISCONNECTED == file_extension->state || + HECI_FILE_DISCONNECTING == file_extension->state) { + return_status = -EBUSY; + goto out; + } + spin_lock(&file_extension->read_io_lock); + } + + kernel_priv_cb = file_extension->read_cb; + + if (!kernel_priv_cb) { + spin_unlock(&file_extension->read_io_lock); + return -ENODEV; + } + if (file_extension->reading_state != HECI_READ_COMPLETE) { + spin_unlock(&file_extension->read_io_lock); + return ESUCCESS; + } + spin_unlock(&file_extension->read_io_lock); + /* now copy the data to user space */ +copy_buffer: + DBG("kernel_priv_cb->response_buffer size - %d\n", kernel_priv_cb->response_buffer.size); + DBG("kernel_priv_cb->information - %lu\n", kernel_priv_cb->information); + if (length == 0 || ubuf == NULL || *offset > kernel_priv_cb->information) { + return_status = -EMSGSIZE; + goto free; + } + + /* length is being turncated to PAGE_SIZE, however, information size may be longer */ + length = (length < (kernel_priv_cb->information - *offset) ? + length : (kernel_priv_cb->information - *offset)); + + if (copy_to_user(ubuf, kernel_priv_cb->response_buffer.data + *offset, length)) { + return_status = -EFAULT; + goto free; + } + else { + return_status = length; + *offset += length; + if ((unsigned long)*offset < kernel_priv_cb->information) { + goto out; + } + } +free: + spin_lock_bh(&device->device_lock); + kernel_priv_cb_pos = find_read_list_entry(device, file_extension); + /* Remove entry from read list */ + if (kernel_priv_cb_pos != NULL) + list_del(&kernel_priv_cb_pos->cb_list); + spin_unlock_bh(&device->device_lock); + kfree(kernel_priv_cb->response_buffer.data); + kernel_priv_cb->response_buffer.data = NULL; + kfree(kernel_priv_cb); + kernel_priv_cb = NULL; + spin_lock(&file_extension->read_io_lock); + file_extension->reading_state = HECI_IDLE; + file_extension->read_cb = NULL; + file_extension->read_pending = FALSE; + spin_unlock(&file_extension->read_io_lock); +out: DBG("end heci read return_status= %d\n", return_status); + return return_status; +} + +/** + * heci_write - the write function. + */ +static ssize_t heci_write(struct file *file, const char __user * ubuf, + size_t length, loff_t * offset) +{ + int return_status = ESUCCESS; + __u8 i; + int if_num = MINOR((file->f_dentry->d_inode->i_rdev)); + struct heci_file_private *file_extension = file->private_data; + struct heci_cb_private *priv_write_cb = NULL; + struct heci_message_header heci_header; + struct iamt_heci_device *device = NULL; + unsigned long currtime = get_seconds(); + + if (!heci_device) + return -ENODEV; + device = pci_get_drvdata(heci_device); + + if ((if_num != HECI_MINOR_NUMBER) || (!device) || (!file_extension)) + return -ENODEV; + spin_lock_bh(&device->device_lock); + + if (device->heci_state != HECI_ENABLED) { + spin_unlock_bh(&device->device_lock); + return -ENODEV; + } + if (file_extension == &device->legacy_file_extension) { + priv_write_cb = find_pthi_read_list_entry(device, file, file_extension); + if ((priv_write_cb && currtime - priv_write_cb->read_time > LEGACY_READ_TIMER) || + (priv_write_cb && file_extension->reading_state == HECI_READ_COMPLETE)) { + *offset = 0; + list_del(&priv_write_cb->cb_list); + kfree(priv_write_cb->request_buffer.data); + kfree(priv_write_cb->response_buffer.data); + kfree(priv_write_cb); + } + } + + //free entry used in read + if (file_extension->reading_state == HECI_READ_COMPLETE) + { + *offset = 0; + priv_write_cb = find_read_list_entry(device, file_extension); + if ( priv_write_cb != NULL) { + list_del(&priv_write_cb->cb_list); + kfree(priv_write_cb->response_buffer.data); + priv_write_cb->response_buffer.data = NULL; + kfree(priv_write_cb); + priv_write_cb = NULL; + spin_lock(&file_extension->read_io_lock); + file_extension->reading_state = HECI_IDLE; + file_extension->read_cb = NULL; + file_extension->read_pending = FALSE; + spin_unlock(&file_extension->read_io_lock); + } + } + else if (file_extension->reading_state == HECI_IDLE && + file_extension->read_pending == FALSE){ + *offset = 0; + } + + spin_unlock_bh(&device->device_lock); + + priv_write_cb = kmalloc(sizeof(struct heci_cb_private), GFP_KERNEL); + if (!priv_write_cb) + return -ENOMEM; + spin_lock(&file_extension->file_lock); + priv_write_cb->request_buffer.data = NULL; + priv_write_cb->response_buffer.data = NULL; + priv_write_cb->file_object = file; + priv_write_cb->file_private = file_extension; + spin_unlock(&file_extension->file_lock); + priv_write_cb->request_buffer.data = kmalloc(length, GFP_KERNEL); + if (!priv_write_cb->request_buffer.data) { + kfree(priv_write_cb); + return -ENOMEM; + } + DBG("length =%d\n", (int) length); + + if (copy_from_user(priv_write_cb->request_buffer.data, + ubuf, length)) { + return_status = -EFAULT; + goto fail; + } + + spin_lock(&file_extension->file_lock); + file_extension->sm_state = 0; + if (length == 4 && + ((memcmp(heci_wd_state_independence_msg[0], ubuf, 4) == 0) || + (memcmp(heci_wd_state_independence_msg[1], ubuf, 4) == 0))) { + file_extension->sm_state |= HECI_WD_STATE_INDEPENDENCE_MSG_SENT; + } + spin_unlock(&file_extension->file_lock); + + INIT_LIST_HEAD(&priv_write_cb->cb_list); + if (file_extension == &device->legacy_file_extension) { + priv_write_cb->response_buffer.data = + kmalloc(LEGACY_MTU, GFP_KERNEL); + if (!priv_write_cb->response_buffer.data) { + return_status = -ENOMEM; + goto fail; + } + spin_lock_bh(&device->device_lock); + if (device->heci_state != HECI_ENABLED) { + spin_unlock_bh(&device->device_lock); + return_status = -ENODEV; + goto fail; + } + for (i = 0; i < device->num_heci_me_clients; i++) { + if (device->me_clients[i].client_id == + device->legacy_file_extension.me_client_id) + break; + } + + BUG_ON(device->me_clients[i].client_id != + file_extension->me_client_id); + if ((i == device->num_heci_me_clients) + || (device->me_clients[i].client_id != device->legacy_file_extension.me_client_id)) { + spin_unlock_bh(&device->device_lock); + return_status = -ENODEV; + goto fail; + } else if (length > device->me_clients[i].properteis.max_message_length || length <= 0) { + spin_unlock_bh(&device->device_lock); + return_status = -EMSGSIZE; + goto fail; + } + + + priv_write_cb->response_buffer.size = LEGACY_MTU; + priv_write_cb->major_file_operations = HECI_IOCTL; + priv_write_cb->information = 0; + priv_write_cb->request_buffer.size = length; + if (device->legacy_file_extension.state != HECI_FILE_CONNECTED) { + spin_unlock_bh(&device->device_lock); + return_status = -ENODEV; + goto fail; + } + + if (!list_empty(&device->pthi_cmd_list.heci_cb.cb_list) + || device->legacy_state != HECI_LEGACY_IDLE) { + DBG("pthi_state = %d\n", (int) device->legacy_state); + DBG("add PTHI cb to pthi cmd waiting list\n"); + list_add_tail(&priv_write_cb->cb_list, + &device->pthi_cmd_list.heci_cb. + cb_list); + return_status = length; + } else { + DBG("call pthi write"); + return_status = pthi_write(device, priv_write_cb); + + if (ESUCCESS != return_status) { + DBG("pthi write failed with status = %d\n", + return_status); + spin_unlock_bh(&device->device_lock); + goto fail; + }; + return_status = length; + } + spin_unlock_bh(&device->device_lock); + return return_status; + } + + priv_write_cb->major_file_operations = HECI_WRITE; + /* make sure information is zero before we start */ + + priv_write_cb->information = 0; + priv_write_cb->request_buffer.size = length; + + spin_lock(&file_extension->write_io_lock); + DBG("host client = %d, ME client = %d\n", + file_extension->host_client_id, file_extension->me_client_id); + if (file_extension->state != HECI_FILE_CONNECTED) { + return_status = -ENODEV; + DBG("host client = %d, is not connected to ME client = %d", + file_extension->host_client_id, + file_extension->me_client_id); + + goto unlock; + } + for (i = 0; i < device->num_heci_me_clients; i++) { + if (device->me_clients[i].client_id == + file_extension->me_client_id) + break; + } + BUG_ON(device->me_clients[i].client_id != file_extension->me_client_id); + if (i == device->num_heci_me_clients) { + return_status = -ENODEV; + goto unlock; + } + if (length > device->me_clients[i].properteis.max_message_length + || length <= 0) { + return_status = -EINVAL; + goto unlock; + } + priv_write_cb->file_private = file_extension; + + spin_lock_bh(&device->device_lock); + if (flow_control_credentials(device, file_extension) && + device->host_buffer_is_empty) { + spin_unlock_bh(&device->device_lock); + device->host_buffer_is_empty = FALSE; + if (length > ((((device->host_hw_state & H_CBD) >> 24) * sizeof(__u32)) - sizeof(struct heci_message_header))) { + heci_header.length = (((device->host_hw_state & H_CBD) >> 24) + * sizeof(__u32)) - sizeof(struct heci_message_header); + heci_header.message_complete = 0; + } else { + heci_header.length = length; + heci_header.message_complete = 1; + } + heci_header.host_address = file_extension->host_client_id; + heci_header.me_address = file_extension->me_client_id; + heci_header.reserved = 0; + DBG("call heci_write_message header=%08x.\n", + *((__u32 *) & heci_header)); + spin_unlock(&file_extension->write_io_lock); + /* protect heci low level write */ + spin_lock_bh(&device->device_lock); + if (!heci_write_message(device, &heci_header, (unsigned char *) (priv_write_cb->request_buffer.data), + heci_header.length)) { + spin_unlock_bh(&device->device_lock); + kfree(priv_write_cb->request_buffer.data); + priv_write_cb->request_buffer.data = NULL; + kfree(priv_write_cb); + return_status = -ENODEV; + priv_write_cb->information = 0; + return return_status; + } + file_extension->writing_state = HECI_WRITING; + priv_write_cb->information = heci_header.length; + if (heci_header.message_complete) { + flow_control_reduce(device, file_extension); + list_add_tail(&priv_write_cb->cb_list, + &device->write_waiting_list.heci_cb. + cb_list); + } else { + list_add_tail(&priv_write_cb->cb_list, + &device->write_list.heci_cb.cb_list); + } + spin_unlock_bh(&device->device_lock); + + } else { + + spin_unlock_bh(&device->device_lock); + priv_write_cb->information = 0; + file_extension->writing_state = HECI_WRITING; + spin_unlock(&file_extension->write_io_lock); + list_add_tail(&priv_write_cb->cb_list, + &device->write_list.heci_cb.cb_list); + } + return length; + +unlock: + spin_unlock(&file_extension->write_io_lock); +fail: + kfree(priv_write_cb->request_buffer.data); + priv_write_cb->request_buffer.data = NULL; + kfree(priv_write_cb->response_buffer.data); + priv_write_cb->response_buffer.data = NULL; + kfree(priv_write_cb); + return return_status; + +} + +/** + * heci_ioctl - the IOCTL function + */ +static int heci_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long data) +{ + + int return_status = ESUCCESS; + int if_num = MINOR(inode->i_rdev); + struct heci_file_private *file_extension = file->private_data; + struct heci_message_data *u_msg = (struct heci_message_data *) data; /* in user space */ + struct heci_message_data k_msg; /* all in kernel on the stack */ + struct iamt_heci_device *device = NULL; + + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!heci_device) + return -ENODEV; + device = pci_get_drvdata(heci_device); + if (((if_num != LEGACY_MINOR_NUMBER) + && (if_num != HECI_MINOR_NUMBER)) || (!device) + || (!file_extension)) + return -ENODEV; + if (device->heci_state != HECI_ENABLED) + return -ENODEV; + /* first copy from user all data needed */ + if (copy_from_user(&k_msg, u_msg, sizeof(k_msg))) { + DBG("first copy from user all data needed filed\n"); + return -EFAULT; + } + DBG("user message size is %d\n", k_msg.size); + + switch (cmd) { + case IOCTL_HECI_GET_VERSION: + DBG(": IOCTL_HECI_GET_VERSION\n"); + return_status = + heci_ioctl_get_version(device, if_num, u_msg, k_msg, + file_extension); + break; + case IOCTL_HECI_CONNECT_CLIENT: + DBG(": IOCTL_HECI_CONNECT_CLIENT.\n"); + return_status = + heci_ioctl_connect_client(device, if_num, u_msg, k_msg, + file); + break; + case IOCTL_HECI_WD: + DBG(": IOCTL_HECI_WD.\n"); + return_status = + heci_ioctl_wd(device, if_num, k_msg, file_extension); + break; + case IOCTL_HECI_BYPASS_WD: + DBG(":IOCTL_HECI_BYPASS_WD.\n"); + return_status = + heci_ioctl_bypass_wd(device,if_num,k_msg,file_extension); + break; + case IAMT_KCS_SEND_MESSAGE_COMMAND: + DBG(": IAMT_KCS_SEND_MESSAGE_COMMAND.\n"); + return_status = + legacy_ioctl_send_message(device, if_num, k_msg, file); + break; + case IAMT_KCS_RECEIVE_MESSAGE_COMMAND: + DBG(": IAMT_KCS_RECEIVE_MESSAGE_COMMAND.\n"); + return_status = + legacy_ioctl_receive_message(device, if_num, u_msg, + k_msg, file); + break; + + default: + return_status = -EINVAL; + break; + } + return return_status; +} + +/** + * heci_legacy_poll - the poll function + */ +static unsigned int heci_legacy_poll(struct file *file, poll_table * wait) +{ + int if_num = MINOR((file->f_dentry->d_inode->i_rdev)); + unsigned int mask = 0; + struct iamt_heci_device *device = NULL; + struct heci_file_private *file_extension = file->private_data; + + + if (!heci_device || !file_extension) + return mask; + + device = pci_get_drvdata(heci_device); + + if ((if_num != LEGACY_MINOR_NUMBER) || (!device)) + return mask; + + spin_lock_bh(&device->device_lock); + if (device->heci_state != HECI_ENABLED){ + spin_unlock_bh(&device->device_lock); + return mask; + } + spin_unlock_bh(&device->device_lock); + if (file_extension == &device->legacy_file_extension) { + + poll_wait(file, &device->legacy_file_extension.wait, wait); + spin_lock(&device->legacy_file_extension.file_lock); + if (device->legacy_state == HECI_LEGACY_READ_COMPLETE + && device->legacy_file_object == file) { + mask |= (POLLIN | POLLRDNORM); + spin_lock_bh(&device->device_lock); + DBG("run next pthi legacy cb\n"); + run_next_legacy_cmd(device); + spin_unlock_bh(&device->device_lock); + } + spin_unlock(&device->legacy_file_extension.file_lock); + } + return mask; +} + +/** + * heci_poll - the poll function + */ +static unsigned int heci_poll(struct file *file, poll_table * wait) +{ + int if_num = MINOR((file->f_dentry->d_inode->i_rdev)); + unsigned int mask = 0; + struct heci_file_private *file_extension = file->private_data; + struct iamt_heci_device *device = NULL; + + if (!heci_device) + return mask; + + + device = pci_get_drvdata(heci_device); + + if ((if_num != HECI_MINOR_NUMBER) || (!device) + || (!file_extension)) + return mask; + + spin_lock_bh(&device->device_lock); + if (device->heci_state != HECI_ENABLED){ + spin_unlock_bh(&device->device_lock); + return mask; + + } + spin_unlock_bh(&device->device_lock); + if (file_extension == &device->legacy_file_extension) { + + + poll_wait(file, &device->legacy_file_extension.wait, wait); + spin_lock(&device->legacy_file_extension.file_lock); + if (device->legacy_state == HECI_LEGACY_READ_COMPLETE + && device->legacy_file_object == file) { + mask |= (POLLIN | POLLRDNORM); + spin_lock_bh(&device->device_lock); + DBG("run next pthi cb"); + run_next_legacy_cmd(device); + spin_unlock_bh(&device->device_lock); + } + spin_unlock(&device->legacy_file_extension.file_lock); + + } else{ + poll_wait(file, &file_extension->tx_wait, wait); + spin_lock(&file_extension->write_io_lock); + if (HECI_WRITE_COMPLETE == file_extension->writing_state) + mask |= (POLLIN | POLLRDNORM); + spin_unlock(&file_extension->write_io_lock); + } + return mask; +} + +#ifdef CONFIG_PM +static int heci_suspend(struct pci_dev* pdev, pm_message_t state) +{ + struct iamt_heci_device *device = pci_get_drvdata(pdev); + int err = 0; + + //Stop watchdog if exists + del_timer_sync(&device->wd_timer); + if (device->wd_file_extension.state == HECI_FILE_CONNECTED + && device->wd_timeout) { + spin_lock_bh(&device->device_lock); + g_sus_wd_timeout = device->wd_timeout; + device->wd_timeout = 0; + device->wd_due_counter = 0; + memcpy(device->wd_data, stop_wd_params, HECI_WD_PARAMS_SIZE); + device->stop = TRUE; + if (device->host_buffer_is_empty && + flow_control_credentials(device, &device->wd_file_extension)) { + device->host_buffer_is_empty = FALSE; + + if (!heci_send_wd(device)) + DBG("Send stop WD failed\n"); + else + flow_control_reduce(device, &device->wd_file_extension); + device->wd_pending = FALSE; + } else { + device->wd_pending = TRUE; + } + spin_unlock_bh(&device->device_lock); + device->wd_stoped = FALSE; + + err = + wait_event_interruptible_timeout(device->wait_stop_wd, + (TRUE == device->wd_stoped), 10 * HZ); + if (!device->wd_stoped) + DBG("stop wd failed to complete.\n"); + else { + DBG("stop wd complete %d.\n", err); + err = 0; + } + } + //Set new heci state + spin_lock_bh(&device->device_lock); + if (device->heci_state == HECI_ENABLED || + device->heci_state == HECI_RECOVERING_FROM_RESET) { + device->heci_state = HECI_POWER_DOWN; + heci_reset(device, FALSE); + } + spin_unlock_bh(&device->device_lock); + + pci_save_state(pdev); + + + pci_disable_device(pdev); + free_irq(pdev->irq, device); + + pci_set_power_state(pdev, PCI_D3hot); + + return err; +} + +static int heci_resume(struct pci_dev* pdev) +{ + struct iamt_heci_device *device = NULL; + int err = 0; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + device = pci_get_drvdata(pdev); + if (!device) { + return -ENODEV; + } + + /* request and enable interrupt */ + device->irq = pdev->irq; + err = request_irq(device->irq, heci_isr_interrupt, IRQF_SHARED, + heci_driver_name, device); + if (err) { + HECI_ERR("Request_irq failure. irq = %d \n", device->irq); + return err; + } + + spin_lock_bh(&device->device_lock); + device->heci_state = HECI_POWER_UP; + heci_reset(device, TRUE); + spin_unlock_bh(&device->device_lock); + + //Start watchdog if stopped in suspend + if (g_sus_wd_timeout != 0) { + device->wd_timeout = g_sus_wd_timeout; + + memcpy(device->wd_data, start_wd_params, HECI_WD_PARAMS_SIZE); + memcpy(device->wd_data + HECI_WD_PARAMS_SIZE, &device->wd_timeout, + sizeof(__u16)); + device->wd_due_counter = 1; + + if (device->wd_timeout) + mod_timer(&device->wd_timer, jiffies); + g_sus_wd_timeout = 0; + } + return err; +} +#endif +MODULE_AUTHOR("Intel Corporation"); /* FIXME: Add email address here */ +MODULE_DESCRIPTION("Intel(R) AMT Management Interface"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(DRIVER_VERSION); --- linux-2.6.27.orig/ubuntu/heci/io_heci.c +++ linux-2.6.27/ubuntu/heci/io_heci.c @@ -0,0 +1,1138 @@ +/* + * Part of Intel(R) Manageability Engine Interface Linux driver + * + * Copyright (c) 2003 - 2007 Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "heci_data_structures.h" +#include "heci.h" +#include "heci_interface.h" +#include "version.h" + + +/** + * heci_ioctl_get_version - the get driver version IOCTL function + * @device_object -Device object for our driver + * @if_num minor number + * @*u_msg pointer to user data struct in user space + * @k_msg data in kernel on the stack + * @file_extension -extension of the file object + * + * @return : + * 0 on success, + * negative on failure. + */ +int heci_ioctl_get_version(struct iamt_heci_device * device, int if_num, + struct heci_message_data *u_msg, + struct heci_message_data k_msg, + struct heci_file_private * file_extension) +{ + + int return_status = ESUCCESS; + struct heci_driver_version *version; + struct heci_message_data res_msg; + res_msg.data = NULL; + if ((if_num != HECI_MINOR_NUMBER) || (!device) + || (!file_extension)) + return -ENODEV; + + + if (k_msg.size < (sizeof(struct heci_driver_version) - 2)) { + DBG("user buffer less than heci_driver_version.\n"); + return -EMSGSIZE; + } + + res_msg.data = kmalloc(sizeof(struct heci_driver_version), GFP_KERNEL); + if (!res_msg.data) { + DBG("failed allocation response buffer size = %d.\n", + (int) sizeof(struct heci_driver_version)); + return -ENOMEM; + + } + version = (struct heci_driver_version *) res_msg.data; + version->major = MAJOR_VERSION; + version->minor = MINOR_VERSION; + version->hotfix = QUICK_FIX_NUMBER; + if (k_msg.size < sizeof(struct heci_driver_version)) { + res_msg.size = sizeof(struct heci_driver_version) - 2; + } else { + version->build = VER_BUILD; + res_msg.size = sizeof(struct heci_driver_version); + } + return_status = file_extension->status; + /* now copy the data to user space */ + if (copy_to_user(k_msg.data, res_msg.data, res_msg.size)) { + return_status = -EFAULT; + goto end; + } + if (put_user(res_msg.size, &u_msg->size)) { + return_status = -EFAULT; + goto end; + } +end: + kfree(res_msg.data); + return return_status; +} + +/** + * heci_ioctl_connect_client - the connect to fw client IOCTL function + * @device_object -Device object for our driver + * @if_num minor number + * @*u_msg pointer to user data struct in user space + * @k_msg data in kernel on the stack + * @file_extension -extension of the file object + * + * @return : + * 0 on success, + * negative on failure. + */ +int heci_ioctl_connect_client(struct iamt_heci_device * device, int if_num, + struct heci_message_data *u_msg, + struct heci_message_data k_msg, + struct file *file) +{ + + int return_status = ESUCCESS; + struct heci_message_data req_msg, res_msg; + struct heci_cb_private *kernel_priv_cb = NULL; + struct heci_client *client; + struct heci_file_private *file_extension = NULL; + struct heci_file_private *file_extension_pos = NULL; + struct heci_file_private *file_extension_next = NULL; + struct heci_file_private *file_extension_list_temp = NULL; + + struct heci_cb_private *kernel_priv_cb_pos = NULL, *kernel_priv_cb_next = NULL; + long timeout = 15; /*15 second */ + __u8 i; + int err = 0; + res_msg.data = NULL; + req_msg.data = NULL; + if ((if_num != HECI_MINOR_NUMBER) || (!device) + || (!file)) + return -ENODEV; + file_extension = file->private_data; + if (!file_extension) + return -ENODEV; + if (k_msg.size != sizeof(struct guid)) { + DBG("user buffer size is not equal to size of struct guid(16).\n"); + return -EMSGSIZE; + } + req_msg.data = kmalloc(sizeof(struct guid), GFP_KERNEL); + res_msg.data = kmalloc(sizeof(struct heci_client), GFP_KERNEL); + + + if (!res_msg.data) { + DBG("failed allocation response buffer size = %d.\n", + (int) sizeof(struct heci_client)); + if (req_msg.data) { + kfree(req_msg.data); + req_msg.data = NULL; + goto fail; + } + } + if (!req_msg.data) { + DBG("failed allocation request buffer size = %d.\n", + (int) sizeof(struct guid)); + if (res_msg.data) { + kfree(res_msg.data); + res_msg.data = NULL; + goto fail; + } + fail: + return -ENOMEM; + } + req_msg.size = sizeof(struct guid); + res_msg.size = sizeof(struct heci_client); + if (!k_msg.data) { + return_status = -EIO; + goto end; + } + + /* copy the message to kernel space - use a pointer already copied into kernel space */ + if (copy_from_user(req_msg.data, k_msg.data, k_msg.size)) { + return_status = -EFAULT; + goto end; + } + /* buffered ioctl cb */ + kernel_priv_cb = + kmalloc(sizeof(struct heci_cb_private), GFP_KERNEL); + if (!kernel_priv_cb) { + return_status = -ENOMEM; + goto end; + } + INIT_LIST_HEAD(&kernel_priv_cb->cb_list); + kernel_priv_cb->response_buffer.data = res_msg.data; + kernel_priv_cb->response_buffer.size = res_msg.size; + kernel_priv_cb->request_buffer.data = req_msg.data; + kernel_priv_cb->request_buffer.size = req_msg.size; + kernel_priv_cb->major_file_operations = HECI_IOCTL; + spin_lock_bh(&device->device_lock); + if (device->heci_state != HECI_ENABLED) { + return_status = -ENODEV; + spin_unlock_bh(&device->device_lock); + goto end; + } + if ((file_extension->state != HECI_FILE_INITIALIZING) && + (file_extension->state != HECI_FILE_DISCONNECTED)) { + return_status = -EBUSY; + spin_unlock_bh(&device->device_lock); + goto end; + } + + /* find ME client we're trying to connect to */ + for (i = 0; i < device->num_heci_me_clients; i++) { + if (0 == memcmp((struct guid *) req_msg.data, + &device->me_clients[i].properteis.protocol_name, + sizeof(struct guid))) { + if (device->me_clients[i].properteis.fixed_address == 0) { + file_extension->me_client_id = + device->me_clients[i].client_id; + file_extension->state = + HECI_FILE_CONNECTING; + } + break; + } + } + /*if we're connecting to PTHI client so we will use the exist connection */ + if (0 == memcmp((struct guid *) req_msg.data, &heci_pthi_guid, + sizeof(struct guid))) { + + if (device->legacy_file_extension.state != HECI_FILE_CONNECTED) { + return_status = -ENODEV; + spin_unlock_bh(&device->device_lock); + goto end; + } + device->heci_host_clients[file_extension->host_client_id / 8] &= + ~(1 << (file_extension->host_client_id % 8)); + list_for_each_entry_safe(file_extension_pos, file_extension_next, &device->file_list, link) { + if ((file_extension->host_client_id == + file_extension_pos->host_client_id) + && (file_extension->me_client_id == + file_extension_pos->me_client_id)) { + + DBG("remove file extension node host client = %d, ME client = %d\n", + file_extension_pos->host_client_id, + file_extension_pos->me_client_id); + list_del(&file_extension_pos->link); + } + + } + DBG("free file extension memory\n"); + kfree(file_extension); + file_extension = NULL; + file->private_data = &device->legacy_file_extension; + client = (struct heci_client *) res_msg.data; + client->max_message_length = + device->me_clients[i].properteis.max_message_length; + client->protocol_version = + device->me_clients[i].properteis.protocol_version; + return_status = device->legacy_file_extension.status; + spin_unlock_bh(&device->device_lock); + + /* now copy the data to user space */ + if (copy_to_user(k_msg.data, res_msg.data, res_msg.size)) { + return_status = -EFAULT; + goto end; + } + if (put_user(res_msg.size, &u_msg->size)) { + return_status = -EFAULT; + goto end; + } + goto end; + } + spin_lock(&file_extension->file_lock); + if (file_extension->state != HECI_FILE_CONNECTING) { + return_status = -ENODEV; + spin_unlock(&file_extension->file_lock); + spin_unlock_bh(&device->device_lock); + goto end; + } + spin_unlock(&file_extension->file_lock); + /* prepare the output buffer */ + client = (struct heci_client *) res_msg.data; + client->max_message_length = + device->me_clients[i].properteis.max_message_length; + client->protocol_version = + device->me_clients[i].properteis.protocol_version; + if (device->host_buffer_is_empty + && !other_client_is_connecting(device, file_extension)) { + device->host_buffer_is_empty = FALSE; + if (!heci_connect(device, file_extension)) { + return_status = -ENODEV; + spin_unlock_bh(&device->device_lock); + goto end; + } else { + file_extension->timer_count = CONNECT_TIMEOUT; + kernel_priv_cb->file_private = file_extension; + list_add_tail(&kernel_priv_cb->cb_list, + &device->control_read_list.heci_cb. + cb_list); + } + + + } else { + kernel_priv_cb->file_private = file_extension; + DBG("add connect cb to control write list\n"); + list_add_tail(&kernel_priv_cb->cb_list, + &device->control_write_list.heci_cb.cb_list); + } + spin_unlock_bh(&device->device_lock); + err = + wait_event_timeout(device->wait_received_message, + (HECI_FILE_CONNECTED == file_extension->state || HECI_FILE_DISCONNECTED == file_extension->state), + timeout * HZ); + if (HECI_FILE_CONNECTED == file_extension->state) { + DBG("successfully to connect to FW client.\n"); + return_status = file_extension->status; + /* now copy the data to user space */ + if (copy_to_user(k_msg.data, res_msg.data, res_msg.size)) { + return_status = -EFAULT; + goto end; + } + if (put_user(res_msg.size, &u_msg->size)) { + return_status = -EFAULT; + goto end; + } + goto end; + } else { + DBG("failed to connect to FW client.file_extension->state = %d\n", file_extension->state); + if (!err) + DBG("wait_event_interruptible_timeout failed on client connect message fw response message\n"); + + return_status = -EFAULT; + goto remove_list; + } + +remove_list: + if (kernel_priv_cb) { + spin_lock_bh(&device->device_lock); + if (device->control_read_list.status == ESUCCESS + && !list_empty(&device->control_read_list.heci_cb.cb_list)) { + list_for_each_entry_safe(kernel_priv_cb_pos, kernel_priv_cb_next, &device->control_read_list.heci_cb.cb_list, cb_list){ + file_extension_list_temp = + (struct heci_file_private *) + kernel_priv_cb_pos->file_private; + if (file_extension_list_temp) { + if ((file_extension->host_client_id == file_extension_list_temp->host_client_id) + && (file_extension->me_client_id == file_extension_list_temp->me_client_id)) + list_del(&kernel_priv_cb_pos->cb_list); + + } + + } + } + if (device->control_write_list.status == ESUCCESS + && !list_empty(&device->control_write_list.heci_cb.cb_list)) { + list_for_each_entry_safe(kernel_priv_cb_pos, kernel_priv_cb_next, &device->control_write_list.heci_cb.cb_list, cb_list){ + file_extension_list_temp = + (struct heci_file_private *) + kernel_priv_cb_pos->file_private; + if (file_extension_list_temp) { + if ((file_extension->host_client_id == file_extension_list_temp->host_client_id) + && (file_extension->me_client_id == file_extension_list_temp->me_client_id)) + list_del(&kernel_priv_cb_pos->cb_list); + + } + + } + } + spin_unlock_bh(&device->device_lock); + } +end: + DBG("free connect cb memory"); + kfree(req_msg.data); + req_msg.data = NULL; + kfree(res_msg.data); + res_msg.data = NULL; + kfree(kernel_priv_cb); + kernel_priv_cb = NULL; + return return_status; +} + +/** + * heci_ioctl_wd - the wd IOCTL function + * @device_object -Device object for our driver + * @if_num minor number + * @k_msg data in kernel on the stack + * @file_extension -extension of the file object + * + * @return : + * 0 on success, + * negative on failure. + */ +int heci_ioctl_wd(struct iamt_heci_device * device, int if_num, + struct heci_message_data k_msg, + struct heci_file_private * file_extension) +{ + int return_status = ESUCCESS; + struct heci_message_data req_msg; /*in kernel on the stack */ + if (if_num != HECI_MINOR_NUMBER) + return -ENODEV; + spin_lock(&file_extension->file_lock); + if (k_msg.size != HECI_WATCHDOG_DATA_SIZE) { + DBG("User buffer has invalid size.\n"); + spin_unlock(&file_extension->file_lock); + return -EMSGSIZE; + } + spin_unlock(&file_extension->file_lock); + req_msg.data = kmalloc(HECI_WATCHDOG_DATA_SIZE, GFP_KERNEL); + if (!req_msg.data) { + DBG("failed allocation request buffer size = %d.\n", + HECI_WATCHDOG_DATA_SIZE); + return -ENOMEM; + } + req_msg.size = HECI_WATCHDOG_DATA_SIZE; + + /* copy the message to kernel space - use a pointer already copied into kernel space */ + if (copy_from_user(req_msg.data, k_msg.data, req_msg.size)) { + return_status = -EFAULT; + goto end; + } + spin_lock_bh(&device->device_lock); + if (device->heci_state != HECI_ENABLED) { + return_status = -ENODEV; + spin_unlock_bh(&device->device_lock); + goto end; + } + + if (device->wd_file_extension.state != HECI_FILE_CONNECTED) { + return_status = -ENODEV; + spin_unlock_bh(&device->device_lock); + goto end; + } + if (!device->asf_mode) { + return_status = -EIO; + spin_unlock_bh(&device->device_lock); + goto end; + } + + memcpy(&device->wd_data[HECI_WD_PARAMS_SIZE], req_msg.data, + HECI_WATCHDOG_DATA_SIZE); + + device->wd_timeout = (req_msg.data[1] << 8) + + req_msg.data[0]; + if (device->wd_timeout == 0) { + memcpy(device->wd_data, &stop_wd_params, + HECI_WD_PARAMS_SIZE); + device->wd_pending = FALSE; + device->wd_due_counter = 1; /* next timer */ + } else { + memcpy(device->wd_data, &start_wd_params, + HECI_WD_PARAMS_SIZE); + device->wd_pending = FALSE; + device->wd_due_counter = 1; + } + spin_unlock_bh(&device->device_lock); +end: + kfree(req_msg.data); + req_msg.data = NULL; + return return_status; +} + + +/** + * heci_ioctl_bypass_wd - the bypass_wd IOCTL function + * @device_object -Device object for our driver + * @if_num minor number + * @k_msg data in kernel on the stack + * @file_extension -extension of the file object + * + * @return : + * 0 on success, + * negative on failure. + */ +int heci_ioctl_bypass_wd(struct iamt_heci_device * device, int if_num, + struct heci_message_data k_msg, + struct heci_file_private * file_extension) +{ + __u8 flag=0; + int return_status = ESUCCESS; + + if (if_num != HECI_MINOR_NUMBER) + return -ENODEV; + spin_lock(&file_extension->file_lock); + if (k_msg.size < 1) { + DBG("user buffer less than HECI_WATCHDOG_DATA_SIZE .\n"); + spin_unlock(&file_extension->file_lock); + return -EMSGSIZE; + } + spin_unlock(&file_extension->file_lock); + if (copy_from_user(&flag,k_msg.data,1)) { + return_status = -EFAULT; + goto end; + } + + spin_lock_bh(&device->device_lock); + flag = flag ?(TRUE):(FALSE); + device->wd_bypass = flag; + spin_unlock_bh(&device->device_lock); +end: + return return_status; +} + + +/** + * legacy_ioctl_send_message - send command data to pthi client + * @device_object -Device object for our driver + * @if_num minor number + * @*u_msg pointer to user data struct in user space + * @k_msg data in kernel on the stack + * @file_extension -extension of the file object + * + * @return : + * 0 on success, + * negative on failure. + */ +int legacy_ioctl_send_message(struct iamt_heci_device * device, int if_num, + struct heci_message_data k_msg, + struct file *file) +{ + + int return_status = ESUCCESS; + struct heci_message_data req_msg, res_msg; /*in kernel on the stack */ + struct heci_cb_private *kernel_priv_cb = NULL; + struct heci_file_private *file_extension = file->private_data; + __u8 i; + req_msg.data = NULL; + res_msg.data = NULL; + if ((if_num != LEGACY_MINOR_NUMBER) || (!device)) + return -ENODEV; + if (!file_extension) + return -ENODEV; + spin_lock_bh(&device->device_lock); + for (i = 0; i < device->num_heci_me_clients; i++) { + if (device->me_clients[i].client_id == + device->legacy_file_extension.me_client_id) + break; + } + + BUG_ON(device->me_clients[i].client_id != file_extension->me_client_id); + if ((i == device->num_heci_me_clients) + || (device->me_clients[i].client_id != + device->legacy_file_extension.me_client_id)) { + spin_unlock_bh(&device->device_lock); + return -ENODEV; + } else if (k_msg.size > + device->me_clients[i].properteis.max_message_length + || k_msg.size <= 0) { + spin_unlock_bh(&device->device_lock); + return -EMSGSIZE; + } + + + spin_unlock_bh(&device->device_lock); + req_msg.data = kmalloc(k_msg.size, GFP_KERNEL); + res_msg.data = kmalloc(LEGACY_MTU, GFP_KERNEL); + + if (!res_msg.data) { + DBG("failed allocation response buffer size = %d.\n", + (int) sizeof(struct heci_client)); + if (req_msg.data) { + + kfree(req_msg.data); + req_msg.data = NULL; + return -ENOMEM; + } + } + if (!req_msg.data) { + DBG("failed allocation request buffer size = %d.\n", + (int) sizeof(struct guid)); + if (res_msg.data) { + kfree(res_msg.data); + res_msg.data = NULL; + return -ENOMEM; + } + } + req_msg.size = k_msg.size; + res_msg.size = LEGACY_MTU; + if (!k_msg.data) { + return_status = -EIO; + goto end; + } + + /* copy the message to kernel space - use a pointer already copied into kernel space */ + if (copy_from_user(req_msg.data, k_msg.data, k_msg.size)) { + return_status = -EFAULT; + goto end; + } + /* buffered ioctl cb */ + kernel_priv_cb = + kmalloc(sizeof(struct heci_cb_private), GFP_KERNEL); + if (!kernel_priv_cb) { + return_status = -ENOMEM; + goto end; + } + INIT_LIST_HEAD(&kernel_priv_cb->cb_list); + + kernel_priv_cb->request_buffer.data = req_msg.data; + kernel_priv_cb->request_buffer.size = req_msg.size; + kernel_priv_cb->response_buffer.data = res_msg.data; + kernel_priv_cb->response_buffer.size = res_msg.size; + kernel_priv_cb->major_file_operations = HECI_IOCTL; + kernel_priv_cb->information = 0; + kernel_priv_cb->file_object = file; + kernel_priv_cb->file_private = file_extension; + spin_lock_bh(&device->device_lock); + + if (device->heci_state != HECI_ENABLED) { + return_status = -ENODEV; + spin_unlock_bh(&device->device_lock); + goto end; + } + if (device->legacy_file_extension.state != HECI_FILE_CONNECTED) { + return_status = -ENODEV; + spin_unlock_bh(&device->device_lock); + goto end; + } + + + if (!list_empty(&device->pthi_cmd_list.heci_cb.cb_list) + || device->legacy_state != HECI_LEGACY_IDLE) { + DBG("pthi_state = %d\n", (int) device->legacy_state); + DBG("add PTHI cb to pthi cmd waiting list"); + list_add_tail(&kernel_priv_cb->cb_list, + &device->pthi_cmd_list.heci_cb.cb_list); + + } else { + DBG("call pthi write\n"); + return_status = pthi_write(device, kernel_priv_cb); + + if (ESUCCESS != return_status) { + DBG("pthi write failed with status = %d\n", + return_status); + spin_unlock_bh(&device->device_lock); + goto end; + } + } + spin_unlock_bh(&device->device_lock); + return return_status; +end: + kfree(req_msg.data); + req_msg.data = NULL; + kfree(res_msg.data); + res_msg.data = NULL; + kfree(kernel_priv_cb); + kernel_priv_cb = NULL; + return return_status; +} + + +/** + * legacy_ioctl_receive_message - receive command data from pthi client + * @device_object -Device object for our driver + * @if_num minor number + * @*u_msg pointer to user data struct in user space + * @k_msg data in kernel on the stack + * @file_extension -extension of the file object + * + * @return : + * 0 on success, + * negative on failure. + */ +int legacy_ioctl_receive_message(struct iamt_heci_device * device, int if_num, + struct heci_message_data *u_msg, + struct heci_message_data k_msg, + struct file *file) +{ + + int return_status = ESUCCESS; + struct heci_message_data req_msg, res_msg; + struct heci_cb_private *kernel_priv_cb = NULL; + struct heci_file_private *file_extension = file->private_data; + __u8 i; + struct heci_file_private *file_extension_list_temp = NULL; + struct heci_cb_private *kernel_priv_cb_pos = NULL, *kernel_priv_cb_next = NULL; + + + res_msg.data = NULL; + req_msg.data = NULL; + + if ((if_num != LEGACY_MINOR_NUMBER) || (!device)) + return -ENODEV; + spin_lock_bh(&device->device_lock); + if (!file_extension) { + spin_unlock_bh(&device->device_lock); + return -ENODEV; + } + for (i = 0; i < device->num_heci_me_clients; i++) + if (device->me_clients[i].client_id == + device->legacy_file_extension.me_client_id) + break; + + BUG_ON(device->me_clients[i].client_id != + file_extension->me_client_id); + if ((i == device->num_heci_me_clients) + || (device->me_clients[i].client_id != + device->legacy_file_extension.me_client_id)) { + spin_unlock_bh(&device->device_lock); + return -ENODEV; + } + + if (device->pthi_read_complete_list.status == ESUCCESS) { + list_for_each_entry_safe(kernel_priv_cb_pos, kernel_priv_cb_next, &device->pthi_read_complete_list.heci_cb.cb_list, cb_list){ + file_extension_list_temp = + (struct heci_file_private *) + kernel_priv_cb_pos->file_private; + if (file_extension_list_temp) { + if ((file_extension == &device->legacy_file_extension) + && (kernel_priv_cb_pos->file_object == file)) { + list_del(&kernel_priv_cb_pos->cb_list); + kernel_priv_cb = + kernel_priv_cb_pos; + break; + } + } + + } + } + if (!kernel_priv_cb) { + spin_unlock_bh(&device->device_lock); + return -EAGAIN; + } + + + res_msg.data = kernel_priv_cb->response_buffer.data; + res_msg.size = kernel_priv_cb->response_buffer.size; + req_msg.data = kernel_priv_cb->request_buffer.data; + req_msg.size = kernel_priv_cb->request_buffer.size; + DBG("pthi kernel_priv_cb->response_buffer size - %d\n", + kernel_priv_cb->response_buffer.size); + DBG("pthi kernel_priv_cb->information - %lu\n", + kernel_priv_cb->information); + spin_unlock_bh(&device->device_lock); + + if (res_msg.size < kernel_priv_cb->information) { + return_status = -EMSGSIZE; + goto end; + } + /* now copy the data to user space */ + if (copy_to_user(k_msg.data, + res_msg.data, + kernel_priv_cb->information)) { + return_status = -EFAULT; + goto end; + } + if (put_user(kernel_priv_cb->information, &u_msg->size)) { + return_status = -EFAULT; + goto end; + } +end: + kfree(req_msg.data); + kfree(res_msg.data); + kfree(kernel_priv_cb); + return return_status; +} + +/** + * find_pthi_read_list_entry - finds a PTHIlist entry for current file + * @device_object -Device object for our driver + * + * @return : + * returned a list entry on success, + * NULL on failure. + */ +struct heci_cb_private* find_pthi_read_list_entry(struct iamt_heci_device* device, + struct file* file, struct heci_file_private* file_extension) +{ + struct heci_file_private *file_extension_list_temp = NULL; + struct heci_cb_private *kernel_priv_cb_pos = NULL, *kernel_priv_cb_next = NULL; + + if (device->pthi_read_complete_list.status == ESUCCESS + && !list_empty(&device->pthi_read_complete_list.heci_cb. + cb_list)) { + list_for_each_entry_safe(kernel_priv_cb_pos, kernel_priv_cb_next, &device->pthi_read_complete_list.heci_cb.cb_list, cb_list){ + file_extension_list_temp = + (struct heci_file_private *) + kernel_priv_cb_pos->file_private; + if (file_extension_list_temp) { + if ((file_extension == &device->legacy_file_extension) + && (kernel_priv_cb_pos->file_object == file)) { + return kernel_priv_cb_pos; + } + } + } + } + return NULL; +} +/** + * pthi_read - read data from pthi client + * @device_object -Device object for our driver + * @if_num minor number + * @*u_msg pointer to user data in user space + * @length-user data length + * + * @return : + * returned data length on success, + * zero if no data to read, + * negative on failure. + */ +int pthi_read(struct iamt_heci_device * device, int if_num, struct file *file, + char *ubuf, size_t length, loff_t * offset) +{ + + int return_status = ESUCCESS; + struct heci_cb_private *kernel_priv_cb = NULL; + struct heci_file_private *file_extension = file->private_data; + __u8 i; + unsigned long currtime = get_seconds(); + + if ((if_num != HECI_MINOR_NUMBER) || (!device)) + return -ENODEV; + + if (!file_extension) + return -ENODEV; + + spin_lock_bh(&device->device_lock); + for (i = 0; i < device->num_heci_me_clients; i++) + if (device->me_clients[i].client_id == + device->legacy_file_extension.me_client_id) + break; + BUG_ON(device->me_clients[i].client_id != file_extension->me_client_id); + if ((i == device->num_heci_me_clients) + || (device->me_clients[i].client_id != + device->legacy_file_extension.me_client_id)) { + DBG("PTHI client not found\n"); + spin_unlock_bh(&device->device_lock); + return -ENODEV; + } + kernel_priv_cb = find_pthi_read_list_entry(device, file, file_extension); + if (!kernel_priv_cb) { + spin_unlock_bh(&device->device_lock); + return 0; /* No more data to read */ + } + else { + /* 15 sec for the message has expired */ + if (kernel_priv_cb && currtime - kernel_priv_cb->read_time > LEGACY_READ_TIMER) { + list_del(&kernel_priv_cb->cb_list); + spin_unlock_bh(&device->device_lock); + return_status = -ETIMEDOUT; + goto free; + } + /* if the whole message will fit remove it from the list */ + if ((kernel_priv_cb->information >= *offset) && + (length >= (kernel_priv_cb->information - *offset))) { + list_del(&kernel_priv_cb->cb_list); + } + /* end of the message has been reached */ + else if ((kernel_priv_cb->information > 0) && + (kernel_priv_cb->information <= *offset)) { + list_del(&kernel_priv_cb->cb_list); + return_status = 0; + spin_unlock_bh(&device->device_lock); + goto free; + } + /* else means that not full buffer will be read and do not remove message from deletion list */ + } + DBG("pthi kernel_priv_cb->response_buffer size - %d\n", + kernel_priv_cb->response_buffer.size); + DBG("pthi kernel_priv_cb->information - %lu\n", + kernel_priv_cb->information); + spin_unlock_bh(&device->device_lock); + + /* length is being turncated to PAGE_SIZE, however, the information may be longer */ + length = length < (kernel_priv_cb->information - *offset) ? + length : (kernel_priv_cb->information - *offset); + + if (copy_to_user + (ubuf, kernel_priv_cb->response_buffer.data + *offset, length)) { + return_status = -EFAULT; + } else { + return_status = length; + if ((*offset + length) < kernel_priv_cb->information) { + *offset += length; + goto out; + } + } + DBG("free pthi cb memory\n"); +free: + *offset = 0; + kfree(kernel_priv_cb->request_buffer.data); + kfree(kernel_priv_cb->response_buffer.data); + kfree(kernel_priv_cb); +out: + return return_status; +} + +/** + * heci_start_read - the start read client message function. + * @device_object -Device object for our driver + * @if_num minor number + * @file_extension -extension of the file object + * + * @return : + * 0 on success, + * negative on failure. + */ +int heci_start_read(struct iamt_heci_device * device, int if_num, + struct heci_file_private * file_extension) +{ + int return_status = ESUCCESS; + __u8 i; + struct heci_cb_private *priv_cb = NULL; + if ((if_num != HECI_MINOR_NUMBER) || (!device) + || (!file_extension)) { + DBG("receive wrong function input param\n."); + return -ENODEV; + } + if (file_extension->state != HECI_FILE_CONNECTED) + return -ENODEV; + spin_lock_bh(&device->device_lock); + if (device->heci_state != HECI_ENABLED) { + spin_unlock_bh(&device->device_lock); + return -ENODEV; + } + spin_unlock_bh(&device->device_lock); + DBG("check if read is pending\n"); + if (file_extension->read_pending + || file_extension->read_cb != NULL) { + DBG("read is pending"); + return -EBUSY; + } + priv_cb = kmalloc(sizeof(struct heci_cb_private), GFP_KERNEL); + if (!priv_cb) + return -ENOMEM; + + DBG("allocation call back success\n"); + DBG("host client = %d, ME client = %d\n", + file_extension->host_client_id, file_extension->me_client_id); + spin_lock_bh(&device->device_lock); + for (i = 0; i < device->num_heci_me_clients; i++) + if (device->me_clients[i].client_id == + file_extension->me_client_id) + break; + + BUG_ON(device->me_clients[i].client_id != + file_extension->me_client_id); + if ((i == device->num_heci_me_clients)) { + return_status = -ENODEV; + goto unlock; + } + + priv_cb->response_buffer.size = + device->me_clients[i].properteis.max_message_length; + spin_unlock_bh(&device->device_lock); + priv_cb->response_buffer.data = + kmalloc(priv_cb->response_buffer.size, GFP_KERNEL); + if (!priv_cb->response_buffer.data) { + return_status = -ENOMEM; + goto fail; + } + DBG("allocation call back data success\n"); + priv_cb->major_file_operations = HECI_READ; + /* make sure information is zero before we start */ + priv_cb->information = 0; + priv_cb->file_private = (void *) file_extension; + file_extension->read_cb = priv_cb; + spin_lock_bh(&device->device_lock); + if (device->host_buffer_is_empty) { + device->host_buffer_is_empty = FALSE; + if (!heci_send_flow_control(device, file_extension)) { + return_status = -ENODEV; + goto unlock; + } else { + list_add_tail(&priv_cb->cb_list, + &device->read_list.heci_cb.cb_list); + } + } else { + list_add_tail(&priv_cb->cb_list, + &device->control_write_list.heci_cb.cb_list); + } + spin_unlock_bh(&device->device_lock); + return return_status; +unlock: + spin_unlock_bh(&device->device_lock); +fail: + kfree(priv_cb->response_buffer.data); + priv_cb->response_buffer.data = NULL; + priv_cb->file_private = NULL; + kfree(priv_cb); + return return_status; +} + +/** + * pthi_write - write legacy data to pthi client + * @device -Device object for our driver + * @kernel_priv_cb - heci call back struct + * @return : + * 0 on success, + * negative on failure. + */ +int pthi_write(struct iamt_heci_device * device, + struct heci_cb_private *kernel_priv_cb) +{ + int return_status = ESUCCESS; + struct heci_message_header heci_header; + + if ((!device) || (!kernel_priv_cb)) + return -ENODEV; + + DBG("write data to pthi client\n"); + + device->legacy_state = HECI_LEGACY_WRITING; + device->legacy_current_cb = kernel_priv_cb; + device->legacy_file_object = kernel_priv_cb->file_object; + device->legacy_canceled = FALSE; + device->legacy_ioctl = TRUE; + device->legacy_message_buffer_size = + kernel_priv_cb->request_buffer.size; + memcpy(device->legacy_message_buffer, + kernel_priv_cb->request_buffer.data, + kernel_priv_cb->request_buffer.size); + if (flow_control_credentials + (device, &device->legacy_file_extension) + && device->host_buffer_is_empty) { + device->host_buffer_is_empty = FALSE; + if (kernel_priv_cb->request_buffer.size > + (((device->host_hw_state & H_CBD) >> 24) * sizeof(__u32)) - sizeof(struct heci_message_header)) { + heci_header.length = + (((device->host_hw_state & H_CBD) >> 24) * sizeof(__u32)) - sizeof(struct heci_message_header); + heci_header.message_complete = 0; + } else { + heci_header.length = + kernel_priv_cb->request_buffer.size; + heci_header.message_complete = 1; + } + + heci_header.host_address = + device->legacy_file_extension.host_client_id; + heci_header.me_address = + device->legacy_file_extension.me_client_id; + heci_header.reserved = 0; + device->legacy_message_buffer_index += heci_header.length; + if (!heci_write_message(device, &heci_header, + (unsigned char *) (device->legacy_message_buffer), + heci_header.length)) + return -ENODEV; + + if (heci_header.message_complete) { + + flow_control_reduce(device, + &device-> + legacy_file_extension); + device->legacy_flow_control_pending = TRUE; + device->legacy_state = HECI_LEGACY_FLOW_CONTROL; + DBG("add pthi cb to write waiting list\n"); + device->legacy_current_cb = kernel_priv_cb; + device->legacy_file_object = kernel_priv_cb->file_object; + list_add_tail(&kernel_priv_cb->cb_list, + &device->write_waiting_list.heci_cb. + cb_list); + + } else { + DBG("message does not complete, so add pthi cb to write list\n"); + list_add_tail(&kernel_priv_cb->cb_list, + &device->write_list.heci_cb.cb_list); + } + + + + } else { + if (TRUE != device->host_buffer_is_empty) + DBG("host buffer is not empty"); + DBG("No flow control credentials, so add legacy cb to write list\n"); + list_add_tail(&kernel_priv_cb->cb_list, + &device->write_list.heci_cb.cb_list); + } + return return_status; +} + +/** + * legacy_ioctl_send_message - send command data to pthi client + * @device -Device object for our driver + * @return : + * 0 on success, + * negative on failure. + */ +void run_next_legacy_cmd(struct iamt_heci_device * device) +{ + struct heci_file_private *file_extension_temp = NULL; + struct heci_cb_private *kernel_priv_cb_pos = NULL, *kernel_priv_cb_next = NULL; + int legacy_write_status = ESUCCESS; + + if (!device) + return; + device->legacy_message_buffer_size = 0; + device->legacy_message_buffer_index = 0; + device->legacy_canceled = FALSE; + device->legacy_ioctl = TRUE; + device->legacy_state = HECI_LEGACY_IDLE; + device->legacy_timer = 0; + device->legacy_file_object = NULL; + + if (device->pthi_cmd_list.status == ESUCCESS + && !list_empty(&device->pthi_cmd_list.heci_cb.cb_list)) { + DBG("complete pthi cmd_list CB\n "); + list_for_each_entry_safe(kernel_priv_cb_pos, kernel_priv_cb_next, &device->pthi_cmd_list.heci_cb.cb_list, cb_list){ + list_del(&kernel_priv_cb_pos->cb_list); + file_extension_temp = (struct heci_file_private *) kernel_priv_cb_pos->file_private; + + if ((file_extension_temp) + && (file_extension_temp == &device->legacy_file_extension)) { + legacy_write_status = + pthi_write(device, kernel_priv_cb_pos); + if (legacy_write_status != ESUCCESS) { + DBG("pthi write failed with status = %d\n", + legacy_write_status); + return; + } + break; + } + } + } + return; +} --- linux-2.6.27.orig/ubuntu/heci/Kconfig +++ linux-2.6.27/ubuntu/heci/Kconfig @@ -0,0 +1,3 @@ +config HECI + tristate "Intel(R) Manageability Engine Interface Driver" + default m --- linux-2.6.27.orig/ubuntu/heci/heci_init.c +++ linux-2.6.27/ubuntu/heci/heci_init.c @@ -0,0 +1,1121 @@ +/* + * Part of Intel(R) Manageability Engine Interface Linux driver + * + * Copyright (c) 2007 Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kcompat.h" +#include "heci_data_structures.h" +#include "heci_interface.h" +#include "heci.h" + + +const __u8 watch_dog_data[] = + { 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; +const __u8 start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 }; +const __u8 stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 }; +const __u8 heci_wd_state_independence_msg[2][4] = { + {0x05, 0x02, 0x51, 0x10}, + {0x05, 0x02, 0x52, 0x10} }; +const struct guid heci_asf_guid = + { 0x75B30CD6, 0xA29E, 0x4AF7, {0xA7, 0x12, 0xE6, 0x17, 0x43, 0x93, + 0xC8, 0xA6} }; +const struct guid heci_wd_guid = + { 0x05B79A6F, 0x4628, 0x4D7F, {0x89, 0x9D, 0xA9, 0x15, 0x14, 0xCB, + 0x32, 0xAB} }; +const struct guid heci_pthi_guid = + { 0x12f80028, 0xb4b7, 0x4b2d, {0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, + 0x81, 0x4c} }; + + +/** + * heci init function prototypes + */ +int host_start_message(struct iamt_heci_device * device_object); +int host_enum_clients_message(struct iamt_heci_device * device_object); +int allocate_me_clents_storage(struct iamt_heci_device * device_object); +void heci_disable(struct iamt_heci_device * device_object); +void host_init_wd(struct iamt_heci_device * device_object); +void host_init_legacy(struct iamt_heci_device * device_object); + + +/** + * heci_initialize_list - Sets up a queue list. + * + * @list - An instance of our list structure + * @device_object -Device object for our driver + * + * @return : + * none; + */ +void heci_initialize_list(struct io_heci_list *list, + struct iamt_heci_device * device_object) +{ + /* initialize our queue list */ + INIT_LIST_HEAD(&list->heci_cb.cb_list); + list->status = ESUCCESS; + list->device_extension = device_object; + return; +} + +/** + * heci_flush_queues - flush our queues list belong to file_extension. + * + * @device_object -Device object for our driver + * + * @return : + * none; + */ +void heci_flush_queues(struct iamt_heci_device * device_object, + struct heci_file_private * file_extension) +{ + int i; + if (!device_object || !file_extension) + return; + /* flush our queue list belong to file_extension */ + for (i = 0; i < NUMBER_OF_LISTS; i++) { + DBG("remove list etnry belong to file_extension\n"); + heci_flush_list(device_object->io_list_array[i], + file_extension); + } + +} + + +/** + * heci_flush_list - remove list etnry belong to file_extension. + * + * @list - An instance of our list structure + * @file_extension -extension of the file object + + * @return : + * none; + */ +void heci_flush_list(struct io_heci_list *list, + struct heci_file_private * file_extension) +{ + struct heci_file_private *file_extension_temp = NULL; + struct heci_cb_private *kernel_priv_cb_pos = NULL, *kernel_priv_cb_next = NULL; + + if (!list || !file_extension) + return; + if (list->status == ESUCCESS + && !list_empty(&list->heci_cb.cb_list)) { + list_for_each_entry_safe(kernel_priv_cb_pos, kernel_priv_cb_next, &list->heci_cb.cb_list, cb_list){ + + if (kernel_priv_cb_pos) { + file_extension_temp = + (struct heci_file_private *) + kernel_priv_cb_pos->file_private; + } + if (file_extension_temp) { + if ((file_extension->host_client_id == file_extension_temp-> host_client_id) + && (file_extension->me_client_id == file_extension_temp-> me_client_id)) + list_del(&kernel_priv_cb_pos->cb_list); + } + + } + } + return; +} + +/** + * init_heci_device - allocates and initializes the heci device structure + * @pdev: The pci device structure + * + * @return : + * The heci_device_device pointer on success, NULL on failure. + */ +struct iamt_heci_device *init_heci_device(struct pci_dev * pdev) +{ + int i; + struct iamt_heci_device *device; + device = kmalloc(sizeof(struct iamt_heci_device), GFP_KERNEL); + if (!device) { + return NULL; + } + + /* setup our list array */ + device->io_list_array[0] = &device->read_list; + device->io_list_array[1] = &device->write_list; + device->io_list_array[2] = &device->write_waiting_list; + device->io_list_array[3] = &device->control_write_list; + device->io_list_array[4] = &device->control_read_list; + device->io_list_array[5] = &device->pthi_cmd_list; + device->io_list_array[6] = &device->pthi_read_complete_list; + INIT_LIST_HEAD(&device->file_list); + INIT_LIST_HEAD(&device->wd_file_extension.link); + INIT_LIST_HEAD(&device->legacy_file_extension.link); + spin_lock_init(&device->device_lock); + init_waitqueue_head(&device->wait_received_message); + init_waitqueue_head(&device->wait_stop_wd); + device->open_handle_count = 0; + device->num_heci_me_clients = 0; + device->mem_base = 0; + device->mem_length = 0; + device->extra_write_index = 0; + device->read_message_header = 0; + device->mem_addr = NULL; + device->asf_mode = FALSE; + device->need_reset = FALSE; + device->received_message = FALSE; + device->heci_state = HECI_INITIALIZING; + + device->num_heci_me_clients = 0; + device->legacy_current_cb = NULL; + device->legacy_file_object = NULL; + device->legacy_canceled = FALSE; + device->legacy_flow_control_pending = FALSE; + device->legacy_state = HECI_LEGACY_IDLE; + device->legacy_message_buffer_index = 0; + device->wd_pending = FALSE; + device->wd_stoped = FALSE; + device->wd_bypass = FALSE; + + device->me_clients = NULL; + /* init work for schedule work */ + INIT_WORK(&device->work, NULL); + for (i = 0; i < NUMBER_OF_LISTS; i++) + heci_initialize_list(device->io_list_array[i], device); + device->pdev = pdev; + return device; +} + +/** + * heci_hw_init - init host and fw to start work. + * + * @device_object -Device object for our driver + * + *@return: + * 0 on success. + * negative on failure + */ +int heci_hw_init(struct iamt_heci_device * device_object) +{ + int err = 0; + device_object->host_hw_state = + read_heci_register(device_object, H_CSR); + device_object->me_hw_state = + read_heci_register(device_object, ME_CSR_HA); + DBG("host_hw_state = 0x%08x, mestate = 0x%08x.\n", + device_object->host_hw_state, device_object->me_hw_state); + + if ((device_object->host_hw_state & H_IS) == H_IS) { + /* acknowledge interrupt and stop interupts */ + write_heci_register(device_object, H_CSR, + device_object->host_hw_state); + } + device_object->received_message = FALSE; + DBG("reset in start the heci device.\n"); + + heci_reset(device_object, TRUE); + + DBG("host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", + device_object->host_hw_state, device_object->me_hw_state); + + /* wait for ME to turn on ME_RDY */ + if (!device_object->received_message) { + err = + wait_event_interruptible_timeout(device_object-> + wait_received_message, + (device_object-> + received_message), + HECI_INTEROP_TIMEOUT); + } + + if (!err && !device_object->received_message) { + device_object->heci_state = HECI_DISABLED; + DBG("wait_event_interruptible_timeout failed on wait for ME to turn on ME_RDY.\n"); + return -ENODEV; + } else { + if (!(((device_object->host_hw_state & H_RDY) == H_RDY) + && ((device_object->me_hw_state & ME_RDY_HRA) == + ME_RDY_HRA))) { + device_object->heci_state = HECI_DISABLED; + DBG("host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", + device_object->host_hw_state, + device_object->me_hw_state); + + if (!(device_object->host_hw_state & H_RDY) != H_RDY) + DBG("host turn off H_RDY.\n"); + if (!(device_object->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA) + DBG("ME turn off ME_RDY.\n"); + HECI_ERR("link layer initialization failed.\n"); + return -ENODEV; + } + } + device_object->received_message = FALSE; + DBG("host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", + device_object->host_hw_state, device_object->me_hw_state); + DBG("ME turn on ME_RDY and host turn on H_RDY.\n"); + HECI_INFO("link layer has been established.\n"); + return ESUCCESS; +} + +/** + * heci_reset - reset host and fw. + * + * @device_object -Device object for our driver + * @interrupts - if interrupt should be enable after reset. + * + * @return: + * none; + */ +void heci_reset(struct iamt_heci_device * device_object, int interrupts) +{ + struct heci_file_private *file_extension_pos = NULL; + struct heci_file_private *file_extension_next = NULL; + struct heci_cb_private *kernel_priv_cb_pos = NULL, *kernel_priv_cb_next = NULL; + int unexpected = 0; + + if (device_object->heci_state == HECI_RECOVERING_FROM_RESET) { + device_object->need_reset = TRUE; + return; + } + + if (device_object->heci_state != HECI_INITIALIZING && + device_object->heci_state != HECI_DISABLED && + device_object->heci_state != HECI_POWER_DOWN && + device_object->heci_state != HECI_POWER_UP) + unexpected = 1; + + device_object->host_hw_state = + read_heci_register(device_object, H_CSR); + + DBG("before reset host_hw_state = 0x%08x.\n", + device_object->host_hw_state); + + device_object->host_hw_state |= (H_RST | H_IG); + + if (interrupts) + device_object->host_hw_state |= (H_IE); + else + device_object->host_hw_state &= ~(H_IE); + + write_heci_register(device_object, H_CSR, + device_object->host_hw_state); + + device_object->host_hw_state = + read_heci_register(device_object, H_CSR); + BUG_ON((device_object->host_hw_state & H_RST) != H_RST); + BUG_ON((device_object->host_hw_state & H_RDY) != 0); + + device_object->host_hw_state &= ~H_RST; + device_object->host_hw_state |= H_IG; + + write_heci_register(device_object, H_CSR, + device_object->host_hw_state); + + DBG("currently saved host_hw_state = 0x%08x.\n", + device_object->host_hw_state); + + device_object->need_reset = FALSE; + + if (device_object->heci_state != HECI_INITIALIZING) { + if (device_object->heci_state != HECI_DISABLED && + device_object->heci_state != HECI_POWER_DOWN) { + device_object->heci_state = HECI_RESETING; + } + list_for_each_entry_safe(file_extension_pos, file_extension_next, &device_object->file_list, link) { + file_extension_pos->state =HECI_FILE_DISCONNECTED; + file_extension_pos->flow_control_credentials =0; + file_extension_pos->read_cb = NULL; + file_extension_pos->timer_count = 0; + } + /* remove entry if already in list */ + DBG("list del legacy and wd file list.\n"); + heci_remove_client_from_file_list(device_object, + device_object-> + wd_file_extension. + host_client_id); + + heci_remove_client_from_file_list(device_object, + device_object-> + legacy_file_extension. + host_client_id); + /* reset legacy parameters. */ + device_object->legacy_current_cb = NULL; + device_object->legacy_message_buffer_size = 0; + device_object->legacy_message_buffer_index = 0; + device_object->legacy_canceled = FALSE; + device_object->legacy_file_extension.file = NULL; + device_object->legacy_ioctl = FALSE; + device_object->legacy_state = HECI_LEGACY_IDLE; + device_object->legacy_timer = 0; + device_object->wd_due_counter = 0; + device_object->extra_write_index = 0; + device_object->wd_pending = FALSE; + } + + device_object->num_heci_me_clients = 0; + device_object->read_message_header = 0; + device_object->stop = FALSE; + device_object->wd_pending = 0; + + /* update the state of the registers after reset */ + device_object->host_hw_state = + read_heci_register(device_object, H_CSR); + device_object->me_hw_state = + read_heci_register(device_object, ME_CSR_HA); + + DBG("after reset host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", + device_object->host_hw_state, device_object->me_hw_state); + + if (unexpected) + HECI_ERR("unexpected heci reset.\n"); + //Wake up all readings so they can be interrupted + list_for_each_entry_safe(file_extension_pos,file_extension_next, &device_object->file_list,link) { + if (&file_extension_pos->rx_wait && + waitqueue_active (&file_extension_pos->rx_wait)) { + HECI_INFO("Waking up client!\n"); + wake_up_interruptible(&file_extension_pos->rx_wait); + } + } + // remove all waiting requests + if (device_object->write_list.status == ESUCCESS && !list_empty(&device_object->write_list.heci_cb.cb_list)) { + list_for_each_entry_safe(kernel_priv_cb_pos, kernel_priv_cb_next, &device_object->write_list.heci_cb.cb_list, cb_list){ + if (kernel_priv_cb_pos) { + list_del(&kernel_priv_cb_pos->cb_list); + kfree(kernel_priv_cb_pos->request_buffer.data); + kernel_priv_cb_pos->request_buffer.data = NULL; + kfree(kernel_priv_cb_pos->response_buffer.data); + kernel_priv_cb_pos->response_buffer.data = NULL; + kfree(kernel_priv_cb_pos); + kernel_priv_cb_pos = NULL; + } + } + } +} + +/** + * heci_disable - reseting in disable routine. + * + * @device_object -Device object for our driver + * + * @return: + * none; + */ +void heci_disable(struct iamt_heci_device * device_object) +{ + if (device_object->heci_state != HECI_INITIALIZING) + HECI_ERR("driver stop request heci state is disable.\n"); + device_object->heci_state = HECI_DISABLED; +} + +/** + * heci_initialize_clients - routine. + * + * @device_object -Device object for our driver + * + * @return: + * none; + */ +int heci_initialize_clients(void *data) +{ + + int status; + struct iamt_heci_device *device_object = (struct iamt_heci_device *) data; + DBG("link is established start sending messages.\n"); + /* link is established start sending messages. */ + status = host_start_message(device_object); + if (status) { + DBG("start sending messages failed.\n"); + return -ENODEV; + } + /* enumerate clients */ + + status = host_enum_clients_message(device_object); + if (status) { + DBG("enum clients failed.\n"); + return -ENODEV; + } + /* allocate storage for ME clients representation */ + status = allocate_me_clents_storage(device_object); + if (status) { + DBG("allocate clients failed.\n"); + return -ENODEV; + } + /*heci initialization wd */ + host_init_wd(device_object); + /*heci initialization legacy client */ + host_init_legacy(device_object); + if (device_object->need_reset) { + device_object->need_reset = FALSE; + device_object->heci_state = HECI_DISABLED; + return -ENODEV; + } + + memset(device_object->heci_host_clients, 0, + sizeof(device_object->heci_host_clients)); + device_object->open_handle_count = 0; + device_object->heci_host_clients[0] |= 7; + device_object->current_host_client_id = 3; + device_object->heci_state = HECI_ENABLED; + DBG("initialization heci clients successful.\n"); + return ESUCCESS; +} + +/** + * host_start_message - heci host send start message. + * + * @device_object - Device object for our driver + * + * @return : + * 0 on success, + * negative on failure. + */ +int host_start_message(struct iamt_heci_device * device_object) +{ + long timeout = 60; /* 60 second */ + + struct heci_message_header *heci_header; + struct hbm_host_version_request *host_start_req; + struct hbm_host_stop_request *host_stop_req; + int err = 0; + /* host start message */ + msleep(100); + heci_header = + (struct heci_message_header *) & device_object-> + write_message_buffer[0]; + heci_header->host_address = 0; + heci_header->me_address = 0; + heci_header->length = sizeof(struct hbm_host_version_request); + heci_header->message_complete = 1; + heci_header->reserved = 0; + + host_start_req = + (struct hbm_host_version_request *) & device_object-> + write_message_buffer[1]; + memset(host_start_req, 0, sizeof(host_start_req)); + host_start_req->command.command = HOST_START_REQ_CMD; + host_start_req->reserved = 0; + host_start_req->host_version.major_version = HBM_MAJOR_VERSION; + host_start_req->host_version.minor_version = HBM_MINOR_VERSION; + device_object->received_message = FALSE; + if (!heci_write_message(device_object, heci_header, + (unsigned char *) (host_start_req), + heci_header->length)) { + device_object->heci_state = HECI_DISABLED; + DBG("send version to fw fail.\n"); + return -ENODEV; + } + DBG("call wait_event_interruptible_timeout for response message. \n"); + /* wait for response */ + err = + wait_event_interruptible_timeout(device_object-> + wait_received_message, + (device_object-> + received_message), + timeout * HZ); + if (!err && !device_object->received_message) { + device_object->heci_state = HECI_DISABLED; + DBG("wait_event_interruptible_timeout failed on host start response message. \n"); + return -ENODEV; + } + device_object->received_message = FALSE; + DBG("wait_event_interruptible_timeout successful on host start response message. \n"); + if ((device_object->version.major_version != HBM_MAJOR_VERSION) || + (device_object->version.minor_version != HBM_MINOR_VERSION)) { + /* send stop message */ + heci_header->host_address = 0; + heci_header->me_address = 0; + heci_header->length = sizeof(struct hbm_host_stop_request); + heci_header->message_complete = 1; + heci_header->reserved = 0; + + host_stop_req = + (struct hbm_host_stop_request *) & device_object-> + write_message_buffer[1]; + + memset(host_stop_req, 0, sizeof(host_stop_req)); + host_stop_req->command.command = HOST_STOP_REQ_CMD; + host_stop_req->reason = DRIVER_STOP_REQUEST; + memset(host_stop_req->reserved, 0, + sizeof(host_stop_req->reserved)); + heci_write_message(device_object, heci_header, + (unsigned char *) (host_stop_req), + heci_header->length); + DBG("version mismatch.\n"); + return -ENODEV; + } + + return ESUCCESS; +} + +/** + * host_enum_clients_message - host send enumeration client request message. + * + * @device_object - Device object for our driver + * + * @return : + * 0 on success, + * negative on failure. + */ +int host_enum_clients_message(struct iamt_heci_device * device_object) +{ + long timeout = 5; /*5 second */ + + struct heci_message_header *heci_header; + struct hbm_host_enumeration_request *host_enum_req; + int err = 0; + __u8 i, j; + heci_header = + (struct heci_message_header *) & device_object-> + write_message_buffer[0]; + /* enumerate clients */ + heci_header->host_address = 0; + heci_header->me_address = 0; + heci_header->length = sizeof(struct hbm_host_enumeration_request); + heci_header->message_complete = 1; + heci_header->reserved = 0; + + host_enum_req = + (struct hbm_host_enumeration_request *) & device_object-> + write_message_buffer[1]; + memset(host_enum_req, 0, sizeof(host_enum_req)); + host_enum_req->command.command = HOST_ENUM_REQ_CMD; + memset(host_enum_req->reserved, 0, + sizeof(host_enum_req->reserved)); + if (!heci_write_message(device_object, heci_header, + (unsigned char *) (host_enum_req), + heci_header->length)) { + device_object->heci_state = HECI_DISABLED; + DBG("send enumeration request fail.\n"); + return -ENODEV; + } + /* wait for response */ + device_object->received_message = FALSE; + err = + wait_event_interruptible_timeout(device_object-> + wait_received_message, + (device_object-> + received_message), + timeout * HZ); + if (!err && !device_object->received_message) { + + device_object->heci_state = HECI_DISABLED; + + DBG("wait_event_interruptible_timeout failed on enumeration cients response message. \n"); + return -ENODEV; + } + device_object->received_message = FALSE; + /* count how many ME clients we have */ + for (i = 0; i < sizeof(device_object->heci_me_clients); i++) + for (j = 0; j < 8; j++) + if ((device_object->heci_me_clients[i] & (1 << j)) != 0) + device_object->num_heci_me_clients++; + return ESUCCESS; +} + +/** + * allocate_me_clents_storage - allocate storage for me clients + * + * @device_object - Device object for our driver + * + * @return : + * 0 on success, + * negative on failure. + */ +int allocate_me_clents_storage(struct iamt_heci_device * device_object) +{ + long timeout = 10; /*10 second */ + struct heci_message_header *heci_header; + struct hbm_host_client_properties_request *host_cli_req; + __u8 client_num, i, j; + int err; + heci_header = + (struct heci_message_header *) & device_object-> + write_message_buffer[0]; + /* allocate storage for ME clients representation */ + if (device_object->num_heci_me_clients > 0) { + kfree(device_object->me_clients); + device_object->me_clients = + kcalloc(device_object->num_heci_me_clients, + sizeof(struct heci_me_client), + GFP_KERNEL); + if (!device_object->me_clients) { + device_object->heci_state = HECI_DISABLED; + DBG("allocate me clents memory failed.\n"); + return -ENOMEM; + } + + client_num = 0; + + for (i = 0; i < sizeof(device_object->heci_me_clients); + i++) { + for (j = 0; j < 8; j++) { + if ((device_object->heci_me_clients[i] & (1 << j)) != 0) { + device_object->me_clients[client_num].client_id = (i * 8) + j; + device_object->me_clients[client_num].flow_control_credentials = 0; + heci_header->host_address = 0; + heci_header->me_address = 0; + heci_header->length = sizeof(struct hbm_host_client_properties_request); + heci_header->message_complete = 1; + heci_header->reserved = 0; + + host_cli_req = (struct hbm_host_client_properties_request *)& device_object->write_message_buffer[1]; + memset(host_cli_req, 0, sizeof(struct hbm_host_client_properties_request)); + host_cli_req->command.command = HOST_CLIENT_PROPERTEIS_REQ_CMD; + host_cli_req->address = device_object->me_clients[client_num].client_id; + memset(host_cli_req->reserved, 0, sizeof(host_cli_req->reserved)); + if (!heci_write_message(device_object, heci_header, + (unsigned char *) (host_cli_req), heci_header->length)) { + DBG("send client properteis request fail.\n"); + device_object->heci_state = HECI_DISABLED; + kfree(device_object->me_clients); + return -ENODEV; + } + /* wait for response */ + device_object->received_message = FALSE; + err = wait_event_interruptible_timeout (device_object->wait_received_message, + (device_object->received_message), timeout * HZ); + if (!err && !device_object->received_message) { + DBG("wait_event_interruptible_timeout failed on client properteis response message.\n"); + device_object->heci_state = HECI_DISABLED; + kfree(device_object->me_clients); + return -ENODEV; + } + device_object->received_message = FALSE; + client_num++; + } + } + } + } + return ESUCCESS; +} + +/** + * host_init_wd - heci initialization wd. + * + * @device_object - Device object for our driver + * + * @return : + * none; + */ +void host_init_wd(struct iamt_heci_device * device_object) +{ + long timeout = 15; /*15 second */ + __u8 i; + int err = 0; + /*look for WD client and connect to it */ + spin_lock_init(&device_object->wd_file_extension.file_lock); + init_waitqueue_head(&device_object->wd_file_extension.wait); + device_object->wd_file_extension.file = NULL; + device_object->wd_file_extension.state = HECI_FILE_DISCONNECTED; + device_object->wd_timeout = 0; + device_object->asf_mode = FALSE; + /*find ME ASF client - otherwise assume AMT mode */ + DBG("find ME ASF client - otherwise assume AMT mode.\n"); + for (i = 0; i < device_object->num_heci_me_clients; i++) { + if (memcmp(&heci_asf_guid, + &device_object->me_clients[i].properteis. + protocol_name, sizeof(struct guid))==0) { + device_object->asf_mode = TRUE; + DBG("found ME ASF client.\n"); + } + } + if (device_object->asf_mode) { + memcpy(device_object->wd_data, + stop_wd_params, HECI_WD_PARAMS_SIZE); + + } + else { /* AMT mode */ + + DBG("assume AMT mode.\n"); + device_object->wd_timeout = AMT_WD_VALUE; + DBG("device_object->wd_timeout=%d.\n", + device_object->wd_timeout); + memcpy(device_object->wd_data, start_wd_params, HECI_WD_PARAMS_SIZE); + memcpy(device_object->wd_data + HECI_WD_PARAMS_SIZE, + &device_object->wd_timeout, sizeof(__u16)); + } + + /* find ME WD client */ + for (i = 0; i < device_object->num_heci_me_clients; i++) { + if (0 == memcmp(&heci_wd_guid, &device_object->me_clients[i].properteis.protocol_name, sizeof(struct guid))) { + + spin_lock_bh(&device_object->device_lock); + device_object->wd_file_extension.me_client_id = + device_object->me_clients[i].client_id; + device_object->wd_file_extension.state = + HECI_FILE_CONNECTING; + + device_object->wd_file_extension.host_client_id = + HECI_WD_HOST_CLIENT_ID; + + device_object->wd_file_extension. + flow_control_credentials = 0; + device_object->wd_file_extension.timer_count = 0; + list_add_tail(&device_object->wd_file_extension. + link, &device_object->file_list); + spin_unlock_bh(&device_object->device_lock); + break; + } + } + DBG("check wd_file_ext\n"); + if (HECI_FILE_CONNECTING == device_object->wd_file_extension.state) { + if (heci_connect(device_object, + &device_object->wd_file_extension)) { + + err = + wait_event_timeout + (device_object->wait_received_message, + (HECI_FILE_CONNECTED == device_object->wd_file_extension.state ||HECI_FILE_DISCONNECTED == device_object->wd_file_extension.state), + timeout * HZ); + if (HECI_FILE_CONNECTED == device_object->wd_file_extension.state) { + DBG("device_object->wd_timeout=%d.\n", + device_object->wd_timeout); + if (device_object->wd_timeout != 0) + device_object->wd_due_counter = 1; + else + device_object->wd_due_counter = 0; + DBG("successfully to connect to WD client.\n"); + } else { + + heci_remove_client_from_file_list + (device_object, + device_object->wd_file_extension. + host_client_id); + if (HECI_FILE_CONNECTED != + device_object->wd_file_extension.state) + DBG("wrong status received for WD client.\n"); + if (!err) + DBG("wait_event_interruptible_timeout failed on client connect message fw response message err=%08x\n", err); + DBG("failed to connect to WD client.\n"); + device_object->wd_file_extension.state = + HECI_FILE_DISCONNECTED; + } + } else { + DBG("failed to call heci_connect for wd_file_extension.\n"); + heci_remove_client_from_file_list(device_object, + device_object-> + wd_file_extension. + host_client_id); + device_object->wd_file_extension.state = + HECI_FILE_DISCONNECTED; + } + } else { + DBG("failed to find WD client.\n"); + } + + device_object->wd_timer.function = &heci_wd_timer; + device_object->wd_timer.data = (unsigned long) device_object; + return; +} + + +/** + * host_init_legacy - heci initialization legacy client. + * + * @device_object - Device object for our driver + * + * @return : + * none; + */ +void host_init_legacy(struct iamt_heci_device * device_object) +{ + long timeout = 15; /*15 second */ + __u8 i; + int err; + + + spin_lock_init(&device_object->legacy_file_extension.file_lock); + init_waitqueue_head(&device_object->legacy_file_extension.wait); + spin_lock_init(&device_object->legacy_file_extension.read_io_lock); + spin_lock_init(&device_object->legacy_file_extension. + write_io_lock); + init_waitqueue_head(&device_object->legacy_file_extension.rx_wait); + init_waitqueue_head(&device_object->legacy_file_extension.tx_wait); + device_object->legacy_file_extension.reading_state = HECI_IDLE; + device_object->legacy_file_extension.writing_state = HECI_IDLE; + device_object->legacy_file_extension.read_pending = FALSE; + device_object->legacy_file_extension.flow_control_credentials = 0; + device_object->legacy_file_extension.read_cb = NULL; + /* look for legacy client and connect to it */ + device_object->legacy_file_extension.file = NULL; + device_object->legacy_file_extension.state = + HECI_FILE_DISCONNECTED; + + /* find ME PTHI client */ + for (i = 0; i < device_object->num_heci_me_clients; i++) { + if (0 == memcmp(&heci_pthi_guid, &device_object->me_clients[i].properteis. protocol_name, sizeof(struct guid))) { + spin_lock_bh(&device_object->device_lock); + device_object->legacy_file_extension.me_client_id = + device_object->me_clients[i].client_id; + device_object->legacy_file_extension.state = + HECI_FILE_CONNECTING; + device_object->legacy_file_extension. + host_client_id = HECI_LEGACY_HOST_CLIENT_ID; + device_object->legacy_file_extension. + flow_control_credentials = 0; + device_object->legacy_file_extension.timer_count = 0; + list_add_tail(&device_object-> + legacy_file_extension.link, + &device_object->file_list); + spin_unlock_bh(&device_object->device_lock); + break; + } + } + if (device_object->asf_mode){ + device_object->legacy_file_extension.state = + HECI_FILE_DISCONNECTED; + heci_remove_client_from_file_list(device_object, + device_object-> + legacy_file_extension. + host_client_id); + return; + + } + if (device_object->legacy_file_extension.state == HECI_FILE_CONNECTING) { + BUG_ON(device_object->me_clients[i].properteis.max_message_length != LEGACY_MTU); + + if (device_object->me_clients[i].properteis.max_message_length < LEGACY_MTU) { + device_object->legacy_file_extension.state = + HECI_FILE_DISCONNECTED; + DBG("legacy client buffer too small.\n"); + } else { + if (heci_connect(device_object, &device_object-> legacy_file_extension)) { + err = wait_event_timeout (device_object->wait_received_message, + (device_object->legacy_file_extension.state == HECI_FILE_CONNECTED || + device_object->legacy_file_extension.state == HECI_FILE_DISCONNECTED), timeout * HZ); + if ((device_object->legacy_file_extension.state != HECI_FILE_CONNECTED)) { + heci_remove_client_from_file_list + (device_object, + device_object-> + legacy_file_extension. + host_client_id); + DBG("failed to connect to legacy client.\n"); + device_object-> + legacy_file_extension.state = + HECI_FILE_DISCONNECTED; + } else { + DBG("successfully to connect to legacy client.\n"); + device_object->legacy_state = + HECI_LEGACY_IDLE; + } + } else { + DBG("failed to call heci_connect for legacy_file_extension.\n"); + heci_remove_client_from_file_list + (device_object, + device_object->legacy_file_extension. + host_client_id); + device_object->legacy_file_extension. + state = HECI_FILE_DISCONNECTED; + } + } + } else { + if (!device_object->asf_mode) + DBG("failed to find legacy client.\n"); + } + return; +} + +/** + * alloc_priv - allocates a private file structure and set it up. + * @file: the file structure + * + * @return : + * The allocated file or NULL on failure + */ +struct heci_file_private *alloc_priv(struct file * file) +{ + struct heci_file_private *priv; + + priv = kmalloc(sizeof(struct heci_file_private), GFP_KERNEL); + if (!priv) + return NULL; + + spin_lock_init(&priv->file_lock); + spin_lock_init(&priv->read_io_lock); + spin_lock_init(&priv->write_io_lock); + init_waitqueue_head(&priv->wait); + init_waitqueue_head(&priv->rx_wait); + DBG("priv->rx_wait =%p\n", &priv->rx_wait); + init_waitqueue_head(&priv->tx_wait); + INIT_LIST_HEAD(&priv->link); + priv->reading_state = HECI_IDLE; + priv->writing_state = HECI_IDLE; + priv->file = file; + priv->flow_control_credentials = 0; + priv->timer_count = 0; + priv->me_client_id = 0; + priv->read_cb = NULL; + priv->status = ESUCCESS; + priv->read_pending = FALSE; + return priv; +} + + + +/** + * heci_disconnect_host_client - send disconnect message to fw from host client. + * + * @device_object -Device object for our driver + * @file_extension -extension of the file object + * + * @return : + * 0 on success, + * negative on failure. + */ +int heci_disconnect_host_client(struct iamt_heci_device * device_object, + struct heci_file_private * file_extension) +{ + int return_status = ESUCCESS, err = 0; + long timeout = 15; /*15 second */ + + struct heci_cb_private *kernel_priv_cb = NULL; + + struct heci_file_private *file_extension_list_temp = NULL; + + struct heci_cb_private *kernel_priv_cb_pos = NULL, *kernel_priv_cb_next = NULL; + + if ((!device_object) || (!file_extension)) + return -ENODEV; + kernel_priv_cb = kmalloc(sizeof(struct heci_cb_private), GFP_KERNEL); + if (!kernel_priv_cb) + return -ENOMEM; + if (file_extension->state == HECI_FILE_DISCONNECTING) { + INIT_LIST_HEAD(&kernel_priv_cb->cb_list); + kernel_priv_cb->file_private = file_extension; + kernel_priv_cb->major_file_operations = HECI_CLOSE; + spin_lock_bh(&device_object->device_lock); + if (device_object->host_buffer_is_empty){ + device_object->host_buffer_is_empty =FALSE; + if (heci_disconnect(device_object, file_extension)) { + list_add_tail(&kernel_priv_cb->cb_list, + &device_object->control_read_list. + heci_cb.cb_list); + } + else{ + spin_unlock_bh(&device_object->device_lock); + return_status = -ENODEV; + DBG("failed to call heci_disconnect for file_extension.\n"); + goto free; + } + } + else{ + kernel_priv_cb->file_private = file_extension; + DBG("add disconnect cb to control write list\n"); + list_add_tail(&kernel_priv_cb->cb_list, + &device_object->control_write_list.heci_cb.cb_list); + } + spin_unlock_bh(&device_object->device_lock); + + err = + wait_event_timeout + (device_object->wait_received_message, + (HECI_FILE_DISCONNECTED == file_extension->state), + timeout * HZ); + if (HECI_FILE_DISCONNECTED == file_extension->state) { + return_status = ESUCCESS; + DBG("successfully to disconnect from fw client.\n"); + } else { + return_status = -ENODEV; + if (HECI_FILE_DISCONNECTED != file_extension->state) + DBG("wrong status received for client disconnect.\n"); + if (!err) + DBG("wait_event_interruptible_timeout failed on client disconnect message fw response message err=%08x\n", err); + DBG("failed to diconnect to fw client.\n"); + } + + } + if (kernel_priv_cb) { + spin_lock_bh(&device_object->device_lock); + if (device_object->control_read_list.status == ESUCCESS + && !list_empty(&device_object->control_read_list.heci_cb.cb_list)) { + list_for_each_entry_safe(kernel_priv_cb_pos, kernel_priv_cb_next, &device_object->control_read_list.heci_cb.cb_list, cb_list){ + file_extension_list_temp = + (struct heci_file_private *) + kernel_priv_cb_pos->file_private; + if (file_extension_list_temp) { + if ((file_extension->host_client_id == file_extension_list_temp->host_client_id) + && (file_extension->me_client_id == file_extension_list_temp->me_client_id)) { + list_del(&kernel_priv_cb_pos->cb_list); + } + } + + } + } + spin_unlock_bh(&device_object->device_lock); +free: + kfree(kernel_priv_cb); + kernel_priv_cb = NULL; + + + } + + return return_status; +} + + +/** + * heci_remove_client_from_file_list - remove file extension from device file list + * + * @device_object -Device object for our driver + * @host_client_id -host client id to be removed + * + * @return : + * none; + */ +void heci_remove_client_from_file_list(struct iamt_heci_device * device_object, + __u8 host_client_id) +{ + struct heci_file_private *file_extension_pos = NULL; + struct heci_file_private *file_extension_next = NULL; + list_for_each_entry_safe(file_extension_pos, file_extension_next, &device_object->file_list, link) { + if (host_client_id == file_extension_pos->host_client_id) { + DBG("remove file extension node host client = %d, ME client = %d\n", + file_extension_pos->host_client_id, + file_extension_pos->me_client_id); + list_del(&file_extension_pos->link); + break; + } + + + } +} --- linux-2.6.27.orig/ubuntu/heci/kcompat.h +++ linux-2.6.27/ubuntu/heci/kcompat.h @@ -0,0 +1,165 @@ +/* + * Part of Intel(R) Manageability Engine Interface Linux driver + * + * Copyright (c) 2003 - 2007 Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + */ + +#ifndef _KCOMPAT_H_ +#define _KCOMPAT_H_ + +#include +#include +#include +#include +#include +#include +#include + + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ) +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28) ) +#undef INIT_WORK +#define INIT_WORK(_work, _func) \ +do { \ + INIT_LIST_HEAD(&(_work)->entry); \ + (_work)->pending = 0; \ + (_work)->func = (void (*)(void *))_func; \ + (_work)->data = _work; \ + init_timer(&(_work)->timer); \ +} while (0) +#undef PREPARE_WORK +#define PREPARE_WORK(_work, _func) \ + do { \ + (_work)->func = (void (*)(void *))_func;\ + (_work)->data = _work;\ + } while (0) + + +#endif + +#ifndef round_jiffies +#define round_jiffies(x) x +#endif + +#endif /* < 2.6.20 */ + + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ) + +#ifndef IRQF_PROBE_SHARED +#ifdef SA_PROBEIRQ +#define IRQF_PROBE_SHARED SA_PROBEIRQ +#else +#define IRQF_PROBE_SHARED 0 +#endif +#endif + +#ifndef IRQF_SHARED +#define IRQF_SHARED SA_SHIRQ +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +#endif /* < 2.6.18 */ + + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) ) + +#ifndef RHEL_VERSION +#define RHEL_VERSION 0 +#endif +#if (!(( RHEL_VERSION == 4 ) && ( RHEL_UPDATE >= 5 ))) +typedef irqreturn_t (*irq_handler_t)(int, void*, struct pt_regs *); +#endif +typedef irqreturn_t (*new_handler_t)(int, void*); +static inline irqreturn_t _kc_request_irq(unsigned int irq, new_handler_t handler, unsigned long flags, const char *devname, void *dev_id) +{ + irq_handler_t new_handler = (irq_handler_t) handler; + return request_irq(irq, new_handler, flags, devname, dev_id); +} + +#undef request_irq +#define request_irq(irq, handler, flags, devname, dev_id) _kc_request_irq((irq), (handler), (flags), (devname), (dev_id)) + +#endif + + +/*****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) ) +#define SHUTDOWN_METHOD(method) +#define HECI_REBOOT_NOTIFIER(reboot_notifier, driver, reboot_function) \ +static int heci_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) \ +{ \ + struct pci_dev *pdev = NULL; \ +\ + switch(event){ \ + case SYS_DOWN: \ + case SYS_HALT: \ + case SYS_POWER_OFF: \ + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) { \ + if (pci_dev_driver(pdev) == &driver) { \ + reboot_function(pdev); \ + } \ + } \ + } \ + return NOTIFY_DONE; \ +};\ +static struct notifier_block reboot_notifier = { \ + .notifier_call = heci_notify_reboot, \ + .next = NULL, \ + .priority = 0 \ +}; + +#define REGISTER_REBOOT_NOTIFIER(reboot_notifier) \ + register_reboot_notifier(&reboot_notifier); +#define UNREGISTER_REBOOT_NOTIFIER(reboot_notifier) \ + unregister_reboot_notifier(&reboot_notifier); +#else +#define SHUTDOWN_METHOD(method) .shutdown = method, +#define HECI_REBOOT_NOTIFIER(reboot_notifier, driver, reboot_function) +#define REGISTER_REBOOT_NOTIFIER(reboot_notifier) +#define UNREGISTER_REBOOT_NOTIFIER(reboot_notifier) +#define heci_reboot_notifier +#endif //( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) ) + + +#endif --- linux-2.6.27.orig/ubuntu/heci/heci_interface.h +++ linux-2.6.27/ubuntu/heci/heci_interface.h @@ -0,0 +1,177 @@ +/* + * Part of Intel(R) Manageability Engine Interface Linux driver + * + * Copyright (c) 2003 - 2007 Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + */ + + +#ifndef _HECI_INTERFACE_H_ +#define _HECI_INTERFACE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "heci_data_structures.h" + + +#define HBM_MINOR_VERSION 0 +#define HBM_MAJOR_VERSION 1 +#define HBM_TIMEOUT 1 /* 1 second */ + + +#define HOST_START_REQ_CMD 0x01 +#define HOST_START_RES_CMD 0x81 + +#define HOST_STOP_REQ_CMD 0x02 +#define HOST_STOP_RES_CMD 0x82 + +#define ME_STOP_REQ_CMD 0x03 + +#define HOST_ENUM_REQ_CMD 0x04 +#define HOST_ENUM_RES_CMD 0x84 + +#define HOST_CLIENT_PROPERTEIS_REQ_CMD 0x05 +#define HOST_CLIENT_PROPERTEIS_RES_CMD 0x85 + +#define CLIENT_CONNECT_REQ_CMD 0x06 +#define CLIENT_CONNECT_RES_CMD 0x86 + +#define CLIENT_DISCONNECT_REQ_CMD 0x07 +#define CLIENT_DISCONNECT_RES_CMD 0x87 + +#define FLOW_CONTROL_CMD 0x08 + + +#define AMT_WD_VALUE 120 /* seconds */ + +#define HECI_WATCHDOG_DATA_SIZE 16 +#define HECI_START_WD_DATA_SIZE 20 +#define HECI_WD_PARAMS_SIZE 4 + +/* IOCTL commands */ +#define HECI_IOCTL_LETTER 'H' + + +#define IOCTL_HECI_GET_VERSION \ + _IOWR(HECI_IOCTL_LETTER , 0x800, struct heci_message_data) +#define IOCTL_HECI_CONNECT_CLIENT \ + _IOWR(HECI_IOCTL_LETTER , 0x801, struct heci_message_data) +#define IOCTL_HECI_WD \ + _IOWR(HECI_IOCTL_LETTER , 0x802, struct heci_message_data) +#define IOCTL_HECI_BYPASS_WD \ + _IOWR(HECI_IOCTL_LETTER , 0x810, struct heci_message_data) + +#define IAMT_IOC_MAGIC 'i' +#define IAMT_KCS_SEND_MESSAGE_COMMAND _IOR(IAMT_IOC_MAGIC, 1, struct heci_message_data) +#define IAMT_KCS_RECEIVE_MESSAGE_COMMAND _IOW(IAMT_IOC_MAGIC, 2, struct heci_message_data) + + +#pragma pack(1) + + +enum heci_stop_reason_types{ + DRIVER_STOP_REQUEST = 0x00, + DEVICE_D1_ENTRY = 0x01, + DEVICE_D2_ENTRY = 0x02, + DEVICE_D3_ENTRY = 0x03, + SYSTEM_S1_ENTRY = 0x04, + SYSTEM_S2_ENTRY = 0x05, + SYSTEM_S3_ENTRY = 0x06, + SYSTEM_S4_ENTRY = 0x07, + SYSTEM_S5_ENTRY = 0x08 +}; + +enum me_stop_reason_types{ + FW_UPDATE = 0x00 +}; + +enum client_connect_status_types{ + CCS_SUCCESS = 0x00, + CCS_NOT_FOUND = 0x01, + CCS_ALREADY_STARTED = 0x02, + CCS_OUT_OF_RESOURCES = 0x03, + CCS_MESSAGE_SMALL = 0x04 +}; + +enum client_disconnect_status_types{ + CDS_SUCCESS = 0x00 +}; + + +/** + * heci interface function prototypes + */ +void heci_read_slots(struct iamt_heci_device * device_object, + unsigned char *buffer, unsigned long buffer_length); + +int heci_write_message(struct iamt_heci_device * device_object, + struct heci_message_header * header, + unsigned char *write_buffer, + unsigned long write_length); + +int host_buffer_is_empty(struct iamt_heci_device * device_object); + +__s32 count_full_read_slots(struct iamt_heci_device * device_object); + +__s32 count_empty_write_slots(struct iamt_heci_device * device_object); + +int flow_control_credentials(struct iamt_heci_device * device_object, + struct heci_file_private * file_extension); + +int heci_send_wd(struct iamt_heci_device * device_object); + +void flow_control_reduce(struct iamt_heci_device * device_object, + struct heci_file_private * file_extension); + +int heci_send_flow_control(struct iamt_heci_device * device_object, + struct heci_file_private * file_extension); + +int heci_disconnect(struct iamt_heci_device * device_object, + struct heci_file_private * file_extension); +int other_client_is_connecting(struct iamt_heci_device * device_object, + struct heci_file_private * file_extension); +int heci_connect(struct iamt_heci_device * device_object, + struct heci_file_private * file_extension); + +#endif /* _HECI_INTERFACE_H_ */ --- linux-2.6.27.orig/ubuntu/heci/heci_interface.c +++ linux-2.6.27/ubuntu/heci/heci_interface.c @@ -0,0 +1,525 @@ +/* + * Part of Intel(R) Manageability Engine Interface Linux driver + * + * Copyright (c) 2003 - 2007 Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + */ + + +#include "heci.h" +#include "heci_interface.h" + + + +static const __u8 interface_start_wd_params[] = + { 0x02, 0x12, 0x13, 0x10 }; +static const __u8 interface_stop_wd_params[] = + { 0x02, 0x02, 0x14, 0x10 }; + +/** + * read_heci_register - Read a byte from the heci device + * @device: the device structure + * @offset: offset from which to read the data + * + * Return: + * the byte read. + */ +__u32 read_heci_register(struct iamt_heci_device * device, + unsigned long offset) +{ + return readl(device->mem_addr + offset); +} + +/** + * write_heci_register - Write 4 bytes to the heci device + * @device: the device structure + * @offset: offset from which to write the data + * + * @value: the byte to write + */ +void write_heci_register(struct iamt_heci_device * device, unsigned long offset, + __u32 value) +{ + writel(value, device->mem_addr + offset); +} + +/** + * host_buffer_is_empty - check if host buffer is empty. + * + * @device_object -Device object for our driver + * + * @return : + * TRUE if empty + * FALSE - otherwise. + */ +int host_buffer_is_empty(struct iamt_heci_device * device_object) +{ + char read_ptr, write_ptr; + unsigned char buffer_depth, filled_slots, empty_slots; + device_object->host_hw_state = + read_heci_register(device_object, H_CSR); + read_ptr = (char) ((device_object->host_hw_state & H_CBRP) >> 8); + write_ptr = (char) ((device_object->host_hw_state & H_CBWP) >> 16); + buffer_depth = + (unsigned char) ((device_object->host_hw_state & H_CBD) >> 24); + filled_slots = (unsigned char) (write_ptr - read_ptr); + empty_slots = buffer_depth - filled_slots; + + if (filled_slots > 0) + return FALSE; + return TRUE; +} + +/** + * count_empty_write_slots - count write empty slots. + * + * @device_object - Device object for our driver + * + * + * @return : + * -1(ESLOTS_OVERFLOW) if overflow + * otherwise filed slots count + */ +__s32 count_empty_write_slots(struct iamt_heci_device * device_object) +{ + char read_ptr, write_ptr; + unsigned char buffer_depth, filled_slots, empty_slots; + + read_ptr = (char) ((device_object->host_hw_state & H_CBRP) >> 8); + write_ptr = (char) ((device_object->host_hw_state & H_CBWP) >> 16); + buffer_depth = + (unsigned char) ((device_object->host_hw_state & H_CBD) >> 24); + filled_slots = (unsigned char) (write_ptr - read_ptr); + empty_slots = buffer_depth - filled_slots; + + if (filled_slots > buffer_depth) + /* overfolw */ + return -ESLOTS_OVERFLOW; + + return (__s32) empty_slots; +} + +/** + * heci_write_message - write a message to heci device. + * + * @heci_header - header of message + * @write_buffer - message buffer will be write + * @write_length - message size will be write + * + * @return : + * TRUE if success + * FALSE - otherwise. + */ +int heci_write_message(struct iamt_heci_device * device_object, + struct heci_message_header * header, + unsigned char *write_buffer, + unsigned long write_length) +{ + __u32 temp_msg = 0; + unsigned long bytes_written = 0; + char read_ptr, write_ptr; + unsigned char buffer_depth, filled_slots, empty_slots; + unsigned long dw_to_write; + dw_to_write = ((write_length + 3) / 4); + DBG("host_hw_state = 0x%08x.\n", device_object->host_hw_state); + DBG("heci_write_message header=%08x.\n", *((__u32 *) header)); + + read_ptr = (char) ((device_object->host_hw_state & H_CBRP) >> 8); + write_ptr = (char) ((device_object->host_hw_state & H_CBWP) >> 16); + buffer_depth = + (unsigned char) ((device_object->host_hw_state & H_CBD) >> 24); + filled_slots = (unsigned char) (write_ptr - read_ptr); + empty_slots = buffer_depth - filled_slots; + DBG("filled = %hu, empty = %hu.\n", filled_slots, empty_slots); + + if (dw_to_write > empty_slots) { + return FALSE; + } + + write_heci_register(device_object, H_CB_WW, + *((__u32 *) header)); + + while (write_length >= 4) { + write_heci_register(device_object, H_CB_WW, + *(__u32 *) (write_buffer + + bytes_written)); + bytes_written += 4; + write_length -= 4; + } + + if (write_length > 0) { + memcpy(&temp_msg, &write_buffer[bytes_written], write_length); + write_heci_register(device_object, H_CB_WW, temp_msg); + } + + device_object->host_hw_state |= H_IG; + write_heci_register(device_object, H_CSR, + device_object->host_hw_state); + device_object->me_hw_state = + read_heci_register(device_object, ME_CSR_HA); + if ((device_object->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA) + return FALSE; + + device_object->write_hang = 0; + return TRUE; +} + +/** + * count_full_read_slots - reset host and fw. + * + * @device_object -Device object for our driver + * + * + * @return : + * -1(ESLOTS_OVERFLOW) if overflow + * otherwise filed slots count + */ +__s32 count_full_read_slots(struct iamt_heci_device * device_object) +{ + + char read_ptr, write_ptr; + unsigned char buffer_depth, filled_slots, empty_slots; + + device_object->me_hw_state = read_heci_register(device_object, ME_CSR_HA); + read_ptr = (char) ((device_object->me_hw_state & ME_CBRP_HRA) >> 8); + write_ptr = (char) ((device_object->me_hw_state & ME_CBWP_HRA) >> 16); + buffer_depth = (unsigned char) ((device_object->me_hw_state & ME_CBD_HRA) >> + 24); + filled_slots = (unsigned char) (write_ptr - read_ptr); + empty_slots = buffer_depth - filled_slots; + + if (filled_slots > buffer_depth) + /* overflow */ + return -ESLOTS_OVERFLOW; + + DBG("filled_slots =%08x \n", filled_slots); + return (__s32) filled_slots; +} + +/** + * heci_read_slots - read a message from heci device. + * + * @device_object - device object for our driver + * @buffer - message buffer will be write + * @buffer_length - message size will be read + * + * @return : + * none; + */ +void heci_read_slots(struct iamt_heci_device * device_object, + unsigned char *buffer, unsigned long buffer_length) +{ + __u32 i = 0; + unsigned char temp_buf[sizeof(__u32)]; + + while (buffer_length >= sizeof(__u32)) { + ((__u32 *) buffer)[i] = + read_heci_register(device_object, ME_CB_RW); + DBG("buffer[%d]= %d\n", i, ((__u32 *) buffer)[i]); + i++; + buffer_length -= sizeof(__u32); + } + + if (buffer_length > 0) { + *((__u32 *) & temp_buf) = + read_heci_register(device_object, ME_CB_RW); + memcpy(&buffer[i * 4], temp_buf, buffer_length); + } + + device_object->host_hw_state |= H_IG; + write_heci_register(device_object, H_CSR, + device_object->host_hw_state); + return; +} + +/** + * flow_control_credentials - check flow_control credentials. + * + * @device_object -Device object for our driver + * @file_extension -extension of the file object + * + * @return : + * TRUE if flow_control_credentials >0 + * FALSE - otherwise. + */ +int flow_control_credentials(struct iamt_heci_device * device_object, + struct heci_file_private * file_extension) +{ + __u8 i; + + if (!device_object->num_heci_me_clients) + return FALSE; + if (file_extension == NULL) + return FALSE; + if (file_extension->flow_control_credentials > 0) + return TRUE; + + for (i = 0; i < device_object->num_heci_me_clients; i++) { + if (device_object->me_clients[i].client_id == + file_extension->me_client_id) { + if (device_object->me_clients[i].flow_control_credentials > 0) { + BUG_ON(device_object->me_clients[i]. + properteis.single_receive_buffer == 0); + return TRUE; + } + return FALSE; + } + } + BUG_ON(1); + return FALSE; +} + +/** + * flow_control_reduce - reduce flow_control . + * + * @device_object -Device object for our driver + * @file_extension -extension of the file object + * + * @return : + * none; + */ +void flow_control_reduce(struct iamt_heci_device * device_object, + struct heci_file_private * file_extension) +{ + __u8 i; + + if (!device_object->num_heci_me_clients) + return; + + for (i = 0; i < device_object->num_heci_me_clients; i++) { + if (device_object->me_clients[i].client_id == file_extension->me_client_id) { + if (device_object->me_clients[i].properteis.single_receive_buffer != 0) { + BUG_ON(device_object->me_clients[i]. + flow_control_credentials <= 0); + device_object->me_clients[i]. + flow_control_credentials--; + } else { + BUG_ON(file_extension-> + flow_control_credentials <= 0); + file_extension->flow_control_credentials--; + } + return; + } + } + BUG_ON(1); +} + +/** + * heci_send_flow_control - send flow control to fw. + * + * @device_object -Device object for our driver + * @file_extension -extension of the file object + * + * @return : + * TRUE if success + * FALSE - otherwise. + */ +int heci_send_flow_control(struct iamt_heci_device * device_object, + struct heci_file_private * file_extension) +{ + struct heci_message_header *heci_header; + struct hbm_flow_control *heci_flow_control; + + heci_header = + (struct heci_message_header *) & device_object-> + write_message_buffer[0]; + heci_header->host_address = 0; + heci_header->me_address = 0; + heci_header->length = sizeof(struct hbm_flow_control); + heci_header->message_complete = 1; + heci_header->reserved = 0; + + heci_flow_control = + (struct hbm_flow_control *) & device_object-> + write_message_buffer[1]; + memset(heci_flow_control, 0, sizeof(heci_flow_control)); + heci_flow_control->host_address = file_extension->host_client_id; + heci_flow_control->me_address = file_extension->me_client_id; + heci_flow_control->command.command = FLOW_CONTROL_CMD; + memset(heci_flow_control->reserved, 0, sizeof(heci_flow_control->reserved)); + DBG("sending flow control host client = %d, me client = %d\n", + file_extension->host_client_id, file_extension->me_client_id); + if (!heci_write_message(device_object, heci_header, + (unsigned char *) heci_flow_control, sizeof(struct hbm_flow_control))) + return FALSE; + return TRUE; + +} + +/** + * other_client_is_connecting - check if other + * client with the same client id is connected. + * + * @device_object -Device object for our driver + * @file_extension -extension of the file object + * + * @return : + * TRUE if other client is connected. + * FALSE - otherwise. + */ +int other_client_is_connecting(struct iamt_heci_device * device_object, + struct heci_file_private * file_extension) +{ + + struct heci_file_private *file_extension_pos = NULL; + struct heci_file_private *file_extension_next = NULL; + list_for_each_entry_safe(file_extension_pos, file_extension_next, &device_object->file_list, link) { + if ((file_extension_pos->state == HECI_FILE_CONNECTING) + && (file_extension_pos != file_extension) + && file_extension->me_client_id == + file_extension_pos->me_client_id) + return TRUE; + } + return FALSE; +} + +/** + * heci_send_wd - send watch dog message to fw. + * + * @device_object -Device object for our driver + * + * @return : + * TRUE if success + * FALSE - otherwise. + */ +int heci_send_wd(struct iamt_heci_device * device_object) +{ + struct heci_message_header *heci_header; + + heci_header = + (struct heci_message_header *) & device_object-> + write_message_buffer[0]; + heci_header->host_address = + device_object->wd_file_extension.host_client_id; + heci_header->me_address = + device_object->wd_file_extension.me_client_id; + heci_header->message_complete = 1; + heci_header->reserved = 0; + + if (!memcmp(device_object->wd_data, interface_start_wd_params, + HECI_WD_PARAMS_SIZE)) { + heci_header->length = HECI_START_WD_DATA_SIZE; + } else { + BUG_ON(memcmp(device_object->wd_data, interface_stop_wd_params, + HECI_WD_PARAMS_SIZE)); + heci_header->length = HECI_WD_PARAMS_SIZE; + } + + if (!heci_write_message(device_object, heci_header, + device_object->wd_data, + heci_header->length)) + return FALSE; + return TRUE; +} + + +/** + * heci_disconnect - send disconnect message to fw. + * + * @device_object -Device object for our driver + * @file_extension -extension of the file object + * + * @return : + * TRUE if success + * FALSE - otherwise. + */ +int heci_disconnect(struct iamt_heci_device * device_object, + struct heci_file_private * file_extension) +{ + struct heci_message_header *heci_header; + struct hbm_client_disconnect_request *heci_cli_disconnect; + + heci_header = + (struct heci_message_header *) & device_object-> + write_message_buffer[0]; + heci_header->host_address = 0; + heci_header->me_address = 0; + heci_header->length = sizeof(struct hbm_client_disconnect_request); + heci_header->message_complete = 1; + heci_header->reserved = 0; + + heci_cli_disconnect = + (struct hbm_client_disconnect_request *) & device_object-> + write_message_buffer[1]; + memset(heci_cli_disconnect, 0, sizeof(heci_cli_disconnect)); + heci_cli_disconnect->host_address = file_extension->host_client_id; + heci_cli_disconnect->me_address = file_extension->me_client_id; + heci_cli_disconnect->command.command = CLIENT_DISCONNECT_REQ_CMD; + heci_cli_disconnect->reserved[0] = 0; + + if (TRUE != heci_write_message(device_object, heci_header, + (unsigned char *) heci_cli_disconnect, sizeof(struct hbm_client_disconnect_request))) + return FALSE; + return TRUE; +} + +/** + * heci_connect - send connect message to fw. + * + * @device_object -Device object for our driver + * @file_extension -extension of the file object + * + * @return : + * TRUE if success + * FALSE - otherwise. + */ +int heci_connect(struct iamt_heci_device * device_object, + struct heci_file_private * file_extension) +{ + struct heci_message_header *heci_header; + struct hbm_client_connect_request *heci_cli_connect; + + heci_header = + (struct heci_message_header *) & device_object-> + write_message_buffer[0]; + heci_header->host_address = 0; + heci_header->me_address = 0; + heci_header->length = sizeof(struct hbm_client_connect_request); + heci_header->message_complete = 1; + heci_header->reserved = 0; + + heci_cli_connect = + (struct hbm_client_connect_request *) & device_object-> + write_message_buffer[1]; + heci_cli_connect->host_address = file_extension->host_client_id; + heci_cli_connect->me_address = file_extension->me_client_id; + heci_cli_connect->command.command = CLIENT_CONNECT_REQ_CMD; + heci_cli_connect->reserved = 0; + if (TRUE != heci_write_message(device_object, heci_header, + (unsigned char *) heci_cli_connect, sizeof(struct hbm_client_connect_request))) + return FALSE; + return TRUE; +} --- linux-2.6.27.orig/ubuntu/heci/Makefile +++ linux-2.6.27/ubuntu/heci/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_HECI) += heci.o + +heci-objs := heci_init.o interrupt.o heci_interface.o io_heci.o heci_main.o --- linux-2.6.27.orig/ubuntu/heci/version.h +++ linux-2.6.27/ubuntu/heci/version.h @@ -0,0 +1,53 @@ +/* + * Part of Intel(R) Manageability Engine Interface Linux driver + * + * Copyright (c) 2006-2007 Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + */ + +#ifndef HECI_VERSION_H +#define HECI_VERSION_H + +#define MAJOR_VERSION 3 +#define MINOR_VERSION 2 +#define QUICK_FIX_NUMBER 0 +#define VER_BUILD 24 + +#define str(s) name(s) +#define name(s) #s +#define DRIVER_VERSION str(MAJOR_VERSION) "." str(MINOR_VERSION) "." str(QUICK_FIX_NUMBER) "." str(VER_BUILD) + +#endif --- linux-2.6.27.orig/ubuntu/heci/interrupt.c +++ linux-2.6.27/ubuntu/heci/interrupt.c @@ -0,0 +1,1413 @@ +/* + * Part of Intel(R) Manageability Engine Interface Linux driver + * + * Copyright (c) 2006-2007 Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + */ + +#include +#include +#include "kcompat.h" +#include "heci.h" +#include "heci_interface.h" + +/** + * interrupt function prototypes + */ + +void heci_bh_handler(struct work_struct *work); +int heci_bh_read_handler(struct io_heci_list *complete_list, + struct iamt_heci_device * device_object, + __s32 * slots); +int heci_bh_write_handler(struct io_heci_list *complete_list, + struct iamt_heci_device * device_object, + __s32 * slots); +void heci_bh_read_bus_message(struct iamt_heci_device * device_object, + struct heci_message_header * heci_header); +int heci_bh_read_pthi_message(struct io_heci_list *complete_list, + struct iamt_heci_device * device_object, + struct heci_message_header * heci_header); +int heci_bh_read_client_message(struct io_heci_list *complete_list, + struct iamt_heci_device * device_object, + struct heci_message_header * heci_header); +void heci_client_connect_response(struct iamt_heci_device * device_object, + struct hbm_client_connect_response * + connect_res); +void heci_client_disconnect_response(struct iamt_heci_device * device_object, + struct hbm_client_connect_response * + disconnect_res); +void heci_client_flow_control_response(struct iamt_heci_device * device_object, + struct hbm_flow_control * flow_control); +void heci_client_disconnect_request(struct iamt_heci_device * device_object, + struct hbm_client_disconnect_request * + disconnect_req); + + +/** + * heci_isr_interrupt - The ISR of the HECI device + * @irq: The irq number + * @dev_id: pointer to the device structure + * @regs: the register values + * + * @return : + * irqreturn_t + */ +irqreturn_t heci_isr_interrupt(int irq, void *dev_id) +{ + int err; + struct iamt_heci_device *device = (struct iamt_heci_device *) dev_id; + device->host_hw_state = read_heci_register(device, H_CSR); + + if ((device->host_hw_state & H_IS) != H_IS) + return IRQ_NONE; + + /* disable interrupts */ + device->host_hw_state &= ~H_IE; + /* acknowledge interrupt and stop interupts */ + write_heci_register(device, H_CSR, device->host_hw_state); + /** + * Our device interrupted, schedule work the heci_bh_handler + * to handle the interrupt processing. This needs to be a + * workqueue item since the handler can sleep. + */ + PREPARE_WORK(&device->work, heci_bh_handler); + DBG("schedule work the heci_bh_handler \n"); + err = schedule_work(&device->work); + if (!err) + HECI_ERR("schedule work the heci_bh_handler failed error=%x\n", + err); + return IRQ_HANDLED; +} + +/** + * heci_bh_handler - function called after ISR to handle the interrupt processing. + * @data: pointer to the device structure + * + * NOTE: This function is called by schedule work + * @return : + * none; + */ +void heci_bh_handler(struct work_struct *work) +{ + struct iamt_heci_device *device = container_of(work, struct iamt_heci_device, work); + struct io_heci_list complete_list; + __s32 slots; + int return_status; + struct heci_cb_private *kernel_priv_cb_pos = NULL, *kernel_priv_cb_next = NULL; + struct heci_file_private *file_extension = NULL; + int bus_message_received = FALSE; + struct task_struct *tsk; + + DBG("function called after ISR to handle the interrupt processing.\n"); + /* initialize our complete list */ + spin_lock_bh(&device->device_lock); + heci_initialize_list(&complete_list, device); + device->host_hw_state = read_heci_register(device, H_CSR); + device->me_hw_state = read_heci_register(device, ME_CSR_HA); + + /* check if ME wants a reset */ + if (((device->me_hw_state & ME_RDY_HRA) == 0) && + (device->heci_state != HECI_RESETING) + && (device->heci_state != HECI_INITIALIZING)) { + DBG("FW not ready.\n"); + heci_reset(device, TRUE); + spin_unlock_bh(&device->device_lock); + return; + } + + /* check if we need to start the device */ + if ((device->host_hw_state & H_RDY) == 0) { + + if ((device->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA) { + DBG("we need to start the device.\n"); + device->host_hw_state |= (H_IE | H_IG | H_RDY); + write_heci_register(device, H_CSR, + device->host_hw_state); + if (device->heci_state == HECI_INITIALIZING) { + + device->received_message = TRUE; + spin_unlock_bh(&device->device_lock); + wake_up_interruptible(&device-> + wait_received_message); + return; + + } else { + spin_unlock_bh(&device->device_lock); + tsk = kthread_run(heci_initialize_clients, + device, "heci"); + if (IS_ERR(tsk)) { + int rc = PTR_ERR(tsk); + printk(KERN_WARNING "heci: " + "Unable to start the thread for heci: %d\n", + rc); + } + return; + } + + + } else { + DBG("Enable interrupt FW not ready \n"); + device->host_hw_state |= (H_IE); + write_heci_register(device, H_CSR, + device->host_hw_state); + spin_unlock_bh(&device->device_lock); + return; + } + } + /* check slots avalable for reading */ + slots = count_full_read_slots(device); + DBG("slots =%08x extra_write_index =%08x.\n", slots, + device->extra_write_index); + while ((slots > 0) && (!device->extra_write_index)) { + DBG("slots =%08x extra_write_index =%08x.\n", slots, + device->extra_write_index); + DBG("call heci_bh_read_handler.\n"); + return_status = + heci_bh_read_handler(&complete_list, device, &slots); + if (return_status != ESUCCESS) + goto end; + } + return_status = + heci_bh_write_handler(&complete_list, device, &slots); +end: + DBG("end of bottom half function.\n"); + device->host_hw_state = read_heci_register(device, H_CSR); + device->host_buffer_is_empty = host_buffer_is_empty(device); + + if ((device->host_hw_state & H_IS) == H_IS) { + PREPARE_WORK(&device->work, heci_bh_handler); + DBG("schedule work the heci_bh_handler.\n"); + return_status = schedule_work(&device->work); + if (!return_status) + HECI_ERR("schedule work the heci_bh_handler failed error=%x\n", return_status); + } else { + device->host_hw_state |= H_IE; + } + + write_heci_register(device, H_CSR, device->host_hw_state); + + + if (device->received_message + && waitqueue_active(&device->wait_received_message)) { + DBG("received waiting bus message\n"); + bus_message_received = TRUE; + } + spin_unlock_bh(&device->device_lock); + if (bus_message_received) { + DBG("wake up device->wait_received_message\n"); + wake_up_interruptible(&device->wait_received_message); + bus_message_received = FALSE; + } + if (complete_list.status != ESUCCESS || list_empty(&complete_list.heci_cb.cb_list)){ + return; + } + + list_for_each_entry_safe(kernel_priv_cb_pos, kernel_priv_cb_next, &complete_list.heci_cb.cb_list, cb_list){ + + file_extension = + (struct heci_file_private *) kernel_priv_cb_pos-> + file_private; + list_del(&kernel_priv_cb_pos->cb_list); + if (file_extension && file_extension != &device->legacy_file_extension) { + DBG("completing call back.\n"); + if (kernel_priv_cb_pos->major_file_operations == HECI_WRITE) { + + kfree(kernel_priv_cb_pos-> request_buffer.data); + kernel_priv_cb_pos->request_buffer.data = NULL; + kfree(kernel_priv_cb_pos); + kernel_priv_cb_pos = NULL; + DBG("completing write call back.\n"); + file_extension->writing_state = + HECI_WRITE_COMPLETE; + if (&file_extension->tx_wait && + waitqueue_active (&file_extension->tx_wait)) { + wake_up_interruptible + (&file_extension->tx_wait); + } + } else if (kernel_priv_cb_pos->major_file_operations == HECI_READ + && HECI_READING == file_extension->reading_state) { + DBG("completing read call back information= %lu\n", + kernel_priv_cb_pos->information); + file_extension->reading_state = HECI_READ_COMPLETE; + if (&file_extension->rx_wait + && waitqueue_active (&file_extension->rx_wait)) { + wake_up_interruptible + (&file_extension->rx_wait); + } + + } + } else if (file_extension == &device->legacy_file_extension) { + if (device->legacy_canceled != TRUE) { + device->legacy_state = HECI_LEGACY_READ_COMPLETE; + device->legacy_stall_timer = 0; + memcpy(kernel_priv_cb_pos->response_buffer. + data, + device-> + legacy_message_buffer, + device-> + legacy_message_buffer_index); + list_add_tail(&kernel_priv_cb_pos->cb_list, + &device-> + pthi_read_complete_list. + heci_cb.cb_list); + DBG("pthi read completed\n"); + } else { + run_next_legacy_cmd(device); + } + if (&device->legacy_file_extension.wait) { + DBG("completing pthi call back.\n"); + wake_up_interruptible(&device-> + legacy_file_extension. + wait); + + } + + } + } + return; +} + + +/** + * heci_bh_read_handler - bottom half read routine after ISR to handle the read processing. + * + * + * @complete_list - An instance of our list structure + * @device_object - Device object for our driver + * @slots - slots to read. + * @return : + * 0 on success, + * negative on failure. + */ +int heci_bh_read_handler(struct io_heci_list *complete_list, + struct iamt_heci_device * device_object, + __s32 * slots) +{ + struct heci_message_header *heci_header; + int ret = ESUCCESS; + struct heci_file_private *file_extension_pos = NULL; + struct heci_file_private *file_extension_next = NULL; + if (!device_object->read_message_header) { + device_object->read_message_header = + read_heci_register(device_object, ME_CB_RW); + DBG("slots=%08x.\n", *slots); + (*slots)--; + DBG("slots=%08x.\n", *slots); + } + heci_header = + (struct heci_message_header *) & device_object->read_message_header; + DBG("heci_header->length =%d\n", heci_header->length); + + if ((heci_header->reserved) + || !(device_object->read_message_header)) { + DBG("corrupted message header.\n"); + ret = -ECORRUPTED_MESSAGE_HEADER; + goto end; + } + if (heci_header->host_address || heci_header->me_address) { + + list_for_each_entry_safe(file_extension_pos, file_extension_next, &device_object->file_list, link) { + DBG("list_for_each_entry_safe read host client = %d, ME client = %d\n", + file_extension_pos->host_client_id, + file_extension_pos->me_client_id); + if ((file_extension_pos->host_client_id == heci_header->host_address) + && (file_extension_pos->me_client_id == heci_header->me_address)) + break; + } + + if (&file_extension_pos->link==&device_object->file_list) { + DBG("corrupted message header\n"); + ret = -ECORRUPTED_MESSAGE_HEADER; + goto end; + + } + } + if (((*slots) * sizeof(__u32)) < heci_header->length) { + DBG("we can't read the message slots=%08x.\n", *slots); + /* we can't read the message */ + ret = -ERANGE; + goto end; + } + + + /* decide where to read the message too */ + if (!heci_header->host_address) { + DBG("call heci_bh_read_bus_message.\n"); + heci_bh_read_bus_message(device_object, heci_header); + DBG("end heci_bh_read_bus_message.\n"); + } else if (heci_header->host_address == + device_object->legacy_file_extension.host_client_id + && HECI_FILE_CONNECTED == + device_object->legacy_file_extension.state + && device_object->legacy_state == HECI_LEGACY_READING) { + DBG("call heci_bh_read_legacy_message.\n"); + DBG("heci_header->length =%d\n", heci_header->length); + ret = + heci_bh_read_pthi_message(complete_list, device_object, + heci_header); + if (ret != ESUCCESS) + goto end; + } else { + DBG("call heci_bh_read_client_message.\n"); + ret = heci_bh_read_client_message(complete_list, + device_object, + heci_header); + if (ret != ESUCCESS) + goto end; + } + + /* reset the number of slots and header */ + *slots = count_full_read_slots(device_object); + device_object->read_message_header = 0; + + if (*slots == -ESLOTS_OVERFLOW) { /* overflow - reset */ + DBG("reseting due to slots overflow\n"); + /* set the event since message has been read */ + ret = -ERANGE; + goto end; + } +end: + + return ret; + +} + + +/** + * heci_bh_read_bus_message - bottom half read routine after ISR to handle the read bus message + * command processing. + * + * + * @complete_list - An instance of our list structure + * @device_object - Device object for our driver + * @buffer - message buffer will be filled + * @heci_header - header of bus message + * + * @return : + * none; + */ +void heci_bh_read_bus_message(struct iamt_heci_device * device_object, + struct heci_message_header * heci_header) +{ + struct heci_bus_message *heci_message; + struct hbm_host_version_response *version_res; + struct hbm_client_connect_response *connect_res; + struct hbm_client_connect_response *disconnect_res; + struct hbm_flow_control *flow_control; + struct hbm_host_client_properties_response *properteis_res; + struct hbm_host_enumeration_response *enum_res; + struct hbm_client_disconnect_request *disconnect_req; + struct hbm_host_stop_request *h_stop_req; + int i; + unsigned char *buffer; + buffer = NULL; + /* read the message to our buffer */ + buffer = (unsigned char *) device_object->read_message_buffer; + BUG_ON(heci_header->length >= + sizeof(device_object->read_message_buffer)); + heci_read_slots(device_object, buffer, heci_header->length); + heci_message = (struct heci_bus_message *) buffer; + + switch (*(__u8 *) heci_message) { + case HOST_START_RES_CMD: + version_res = (struct hbm_host_version_response *) heci_message; + if (version_res->host_version_supported) { + device_object->version.major_version = + HBM_MAJOR_VERSION; + device_object->version.minor_version = + HBM_MINOR_VERSION; + } else { + device_object->version = + version_res->me_max_version; + } + device_object->received_message = TRUE; + DBG("host start response message received.\n"); + break; + + case CLIENT_CONNECT_RES_CMD: + connect_res = + (struct hbm_client_connect_response *) heci_message; + heci_client_connect_response(device_object, connect_res); + DBG("client connect response message received.\n"); + wake_up(&device_object->wait_received_message); + break; + + case CLIENT_DISCONNECT_RES_CMD: + disconnect_res = + (struct hbm_client_connect_response *) heci_message; + heci_client_disconnect_response(device_object, + disconnect_res); + DBG("client disconnect response message received.\n"); + wake_up(&device_object->wait_received_message); + break; + + case FLOW_CONTROL_CMD: + flow_control = (struct hbm_flow_control *) heci_message; + heci_client_flow_control_response(device_object, + flow_control); + DBG("client flow control response message received.\n"); + break; + case HOST_CLIENT_PROPERTEIS_RES_CMD: + properteis_res = + (struct hbm_host_client_properties_response *) heci_message; + + + if (properteis_res->status != 0) { + BUG_ON(1); + break; + } + for (i = 0; i < device_object->num_heci_me_clients; i++) { + if (device_object->me_clients[i].client_id == + properteis_res->address) { + device_object->me_clients[i].properteis = + properteis_res->client_properties; + break; + } + + } + device_object->received_message = TRUE; + break; + case HOST_ENUM_RES_CMD: + enum_res = + (struct hbm_host_enumeration_response *) heci_message; + memcpy(device_object->heci_me_clients, + enum_res->valid_addresses, 32); + device_object->received_message = TRUE; + break; + case HOST_STOP_RES_CMD: + device_object->heci_state = HECI_DISABLED; + DBG("Reseting becase of FW stop response\n"); + heci_reset(device_object, TRUE); + break; + case CLIENT_DISCONNECT_REQ_CMD: + /* search for client */ + disconnect_req = + (struct hbm_client_disconnect_request *) heci_message; + heci_client_disconnect_request(device_object, + disconnect_req); + break; + case ME_STOP_REQ_CMD: + /* prepare stop request */ + heci_header = + (struct heci_message_header *) & device_object-> + extra_message_buffer[0]; + heci_header->host_address = 0; + heci_header->me_address = 0; + heci_header->length = sizeof(struct hbm_host_stop_request); + heci_header->message_complete = 1; + heci_header->reserved = 0; + h_stop_req = + (struct hbm_host_stop_request *) & device_object-> + extra_message_buffer[1]; + memset(h_stop_req, 0, sizeof(struct hbm_host_stop_request)); + h_stop_req->command.command = HOST_STOP_REQ_CMD; + h_stop_req->reason = DRIVER_STOP_REQUEST; + h_stop_req->reserved[0] = 0; + h_stop_req->reserved[1] = 0; + device_object->extra_write_index = 2; + break; + + default: + BUG_ON(1); + break; + + } + + return; + +} + +/** + * heci_bh_read_legacy_message - bottom half read routine after ISR to handle the read legacy message + * data processing. + * + * + * @complete_list - An instance of our list structure + * @device_object - Device object for our driver + * @buffer - message buffer will be filled + * @heci_header - header of legacy message + * + * @return : + * 0 on success, + * negative on failure. + */ +int heci_bh_read_pthi_message(struct io_heci_list *complete_list, + struct iamt_heci_device * device_object, + struct heci_message_header * heci_header) +{ + struct heci_file_private *file_extension = NULL; + struct heci_cb_private *priv_cb = NULL; + int return_status = ESUCCESS; + unsigned char *buffer = NULL; + BUG_ON(heci_header->me_address != + device_object->legacy_file_extension.me_client_id); + BUG_ON(device_object->legacy_state != HECI_LEGACY_READING); + buffer = + (unsigned char *) (device_object->legacy_message_buffer + + device_object->legacy_message_buffer_index); + BUG_ON(sizeof(device_object->legacy_message_buffer) < + (device_object->legacy_message_buffer_index + + heci_header->length)); + heci_read_slots(device_object, buffer, heci_header->length); + + device_object->legacy_message_buffer_index += heci_header->length; + + if (heci_header->message_complete) { + DBG("pthi_message_buffer_index=%d\n", heci_header->length); + DBG("completed pthi read.\n "); + if (!device_object->legacy_current_cb) + return -ENODEV; + priv_cb = device_object->legacy_current_cb; + device_object->legacy_current_cb = NULL; + file_extension = + (struct heci_file_private *) priv_cb->file_private; + if (!file_extension) + return -ENODEV; + device_object->legacy_stall_timer = 0; + priv_cb->information = + device_object->legacy_message_buffer_index; + priv_cb->read_time = get_seconds(); + if (device_object->legacy_ioctl + && file_extension == &device_object->legacy_file_extension) { + /* found the legacy cb */ + DBG("complete the pthi read cb.\n "); + if (&device_object->legacy_file_extension) { + DBG("add the pthi read cb to complete.\n "); + list_add_tail(&priv_cb->cb_list, + &complete_list->heci_cb. + cb_list); + + } + } + } + return return_status; + +} + +/** + * heci_bh_read_client_message - bottom half read routine after ISR to handle the read heci client message + * data processing. + * + * + * @complete_list - An instance of our list structure + * @device_object - Device object for our driver + * @buffer - message buffer will be filled + * @heci_header - header of heci client message + * + * @return : + * 0 on success, + * negative on failure. + */ +int heci_bh_read_client_message(struct io_heci_list *complete_list, + struct iamt_heci_device * device_object, + struct heci_message_header * heci_header) +{ + struct heci_file_private *file_extension = NULL; + struct heci_cb_private *kernel_priv_cb_pos = NULL, *kernel_priv_cb_next = NULL; + unsigned char *buffer = NULL; + DBG ("Start client msg \n"); + if (device_object->read_list.status == ESUCCESS + && !list_empty(&device_object->read_list.heci_cb.cb_list)) { + list_for_each_entry_safe(kernel_priv_cb_pos, kernel_priv_cb_next, &device_object-> + read_list.heci_cb.cb_list, cb_list){ + file_extension = (struct heci_file_private *) kernel_priv_cb_pos->file_private; + if ((file_extension->host_client_id == heci_header->host_address) + && (file_extension->me_client_id == heci_header->me_address) + && (file_extension->state == HECI_FILE_CONNECTED) + && (HECI_READ_COMPLETE != file_extension->reading_state)) { + spin_lock(&file_extension->read_io_lock); + file_extension->reading_state = + HECI_READING; + buffer = (unsigned char *) (kernel_priv_cb_pos->response_buffer.data + + kernel_priv_cb_pos->information); + BUG_ON(kernel_priv_cb_pos->response_buffer.size < heci_header->length + + kernel_priv_cb_pos->information); + + if (kernel_priv_cb_pos->response_buffer.size < heci_header->length + + kernel_priv_cb_pos->information) { + DBG(" message overflow.\n"); + list_del(&kernel_priv_cb_pos->cb_list); + spin_unlock(&file_extension-> + read_io_lock); + return -ENOMEM; + } + if (buffer) + heci_read_slots(device_object, + buffer, + heci_header-> + length); + kernel_priv_cb_pos->information += + heci_header->length; + if (heci_header->message_complete) { + file_extension->status = ESUCCESS; + list_del(&kernel_priv_cb_pos->cb_list); + spin_unlock(&file_extension-> + read_io_lock); + DBG("completed read host client = %d, ME client = %d, data length = %lu\n", + file_extension->host_client_id, + file_extension->me_client_id, + kernel_priv_cb_pos->information); + *(kernel_priv_cb_pos->response_buffer.data + kernel_priv_cb_pos->information) = '\0'; + DBG("kernel_priv_cb_pos->response_buffer - %s\n", + kernel_priv_cb_pos->response_buffer.data); + list_add_tail(&kernel_priv_cb_pos->cb_list, + &complete_list->heci_cb.cb_list); + } else { + spin_unlock(&file_extension-> + read_io_lock); + } + + break; + } + + } + + } + DBG ("Message read\n"); + if (!buffer) { + heci_read_slots(device_object, + (unsigned char *) device_object-> + read_message_buffer, heci_header->length); + DBG("discarding message, header=%08x.\n", + *(__u32 *) device_object->read_message_buffer); + } + + return ESUCCESS; +} + + +/** + * heci_bh_write_handler - bottom half write routine after ISR to handle the write processing. + * + * + * @complete_list - An instance of our list structure + * @device_object - Device object for our driver + * @slots - slots to write. + * @return : + * 0 on success, + * negative on failure. + */ +int heci_bh_write_handler(struct io_heci_list *complete_list, + struct iamt_heci_device * device_object, + __s32 * slots) +{ + + struct heci_message_header *heci_header = NULL; + struct heci_file_private *file_extension = NULL; + struct heci_cb_private *kernel_priv_cb_pos = NULL, *kernel_priv_cb_next = NULL; + + + if (!host_buffer_is_empty(device_object)) { + DBG("host buffer is not empty.\n"); + return ESUCCESS; + } + device_object->write_hang = -1; + *slots = count_empty_write_slots(device_object); + /* complete all waiting for write CB */ + DBG("complete all waiting for write CB.\n"); + if (device_object->write_waiting_list.status == ESUCCESS + && !list_empty(&device_object->write_waiting_list.heci_cb.cb_list)) { + list_for_each_entry_safe(kernel_priv_cb_pos, kernel_priv_cb_next, &device_object-> + write_waiting_list.heci_cb.cb_list, cb_list){ + file_extension = (struct heci_file_private *) kernel_priv_cb_pos->file_private; + file_extension->status = ESUCCESS; + list_del(&kernel_priv_cb_pos->cb_list); + if (HECI_WRITING == file_extension->writing_state + && kernel_priv_cb_pos->major_file_operations == HECI_WRITING + && file_extension != &device_object->legacy_file_extension) { + DBG("HECI WRITE COMPLETE\n"); + file_extension->writing_state = HECI_WRITE_COMPLETE; + list_add_tail(&kernel_priv_cb_pos->cb_list, + &complete_list->heci_cb. + cb_list); + } + if (file_extension == &device_object->legacy_file_extension) { + DBG("check legacy flow control\n"); + if (device_object-> legacy_flow_control_pending) { + if (((*slots) * sizeof(__u32)) >= (sizeof(struct heci_message_header) + + sizeof(struct hbm_flow_control))) { + *slots -= (sizeof(struct heci_message_header) + + sizeof(struct hbm_flow_control) + 3) / 4; + if (!heci_send_flow_control (device_object, + &device_object->legacy_file_extension)) { + DBG("legacy flow control failed\n"); + } else { + DBG("legacy flow control success\n"); + device_object->legacy_state = HECI_LEGACY_READING; + device_object->legacy_flow_control_pending = FALSE; + device_object->legacy_message_buffer_index = 0; + device_object->legacy_message_buffer_size = 0; + device_object->legacy_stall_timer = LEGACY_STALL_TIMER; + device_object->host_buffer_is_empty = + host_buffer_is_empty(device_object); + } + } else { + return -ECOMPLETE_MESSAGE; + } + } + } + + } + } + + if (device_object->stop && !device_object->wd_pending) { + device_object->wd_stoped = TRUE; + wake_up_interruptible(&device_object->wait_stop_wd); + return ESUCCESS; + } + + if (device_object->extra_write_index != 0) { + DBG("extra_write_index =%d\n", + device_object->extra_write_index); + heci_write_message(device_object, + (struct heci_message_header *) & + device_object->extra_message_buffer[0], + (unsigned char *) &device_object-> + extra_message_buffer[1], + (device_object->extra_write_index - + 1) * sizeof(__u32)); + *slots -= device_object->extra_write_index; + device_object->extra_write_index = 0; + } + if (device_object->heci_state == HECI_ENABLED){ + if (device_object->wd_pending + && flow_control_credentials(device_object, + &device_object->wd_file_extension)) { + if (!heci_send_wd(device_object)) + DBG("Wd send failed\n"); + else + flow_control_reduce(device_object, + &device_object-> + wd_file_extension); + device_object->wd_pending = 0; + + if (device_object->wd_timeout != 0) { + *slots -= + (sizeof(struct heci_message_header) + + HECI_START_WD_DATA_SIZE + 3) / 4; + device_object->wd_due_counter = 2; + } else { + *slots -= + (sizeof(struct heci_message_header) + + HECI_WD_PARAMS_SIZE + 3) / 4; + device_object->wd_due_counter = 0; + } + + } + } + if (device_object->stop) + return ~ENODEV; + + /* complete control write list CB */ + if (device_object->control_write_list.status == ESUCCESS) { + /* complete control write list CB */ + DBG("complete control write list CB\n "); + list_for_each_entry_safe(kernel_priv_cb_pos, kernel_priv_cb_next, &device_object-> + control_write_list.heci_cb.cb_list, cb_list){ + file_extension = + (struct heci_file_private *) kernel_priv_cb_pos-> + file_private; + if (!file_extension) { + list_del(&kernel_priv_cb_pos->cb_list); + return -ENODEV; + } + switch (kernel_priv_cb_pos->major_file_operations) { + case HECI_CLOSE: + /* send disconnect message */ + if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_message_header) + + sizeof(struct hbm_client_disconnect_request))) { + *slots -= (sizeof(struct heci_message_header) + + sizeof(struct hbm_client_disconnect_request) + 3) / 4; + if (!heci_disconnect(device_object, + file_extension)) { + file_extension->status = ESUCCESS; + kernel_priv_cb_pos->information = 0; + list_del(&kernel_priv_cb_pos->cb_list); + list_add_tail(&kernel_priv_cb_pos->cb_list, + &complete_list->heci_cb. + cb_list); + return -ECOMPLETE_MESSAGE; + } else { + file_extension->state = HECI_FILE_DISCONNECTING; + file_extension->status = ESUCCESS; + kernel_priv_cb_pos->information = 0; + list_del(&kernel_priv_cb_pos->cb_list); + list_add_tail(&kernel_priv_cb_pos->cb_list, + &device_object->control_read_list. + heci_cb.cb_list); + file_extension->timer_count = CONNECT_TIMEOUT; + } + } else { + /* return the cancel routine */ + return -ECORRUPTED_MESSAGE_HEADER; + } + break; + case HECI_READ: + /* send flow control message */ + if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_message_header) + + sizeof(struct hbm_flow_control))) { + *slots -= (sizeof(struct heci_message_header) + + sizeof(struct hbm_flow_control) + 3) / 4; + if (!heci_send_flow_control(device_object, file_extension)) { + file_extension->status = -ENODEV; + kernel_priv_cb_pos->information = 0; + list_del(&kernel_priv_cb_pos->cb_list); + list_add_tail(&kernel_priv_cb_pos->cb_list, + &complete_list->heci_cb. + cb_list); + return -ENODEV; + + } else { + list_del(&kernel_priv_cb_pos->cb_list); + list_add_tail(&kernel_priv_cb_pos->cb_list, + &device_object->read_list. + heci_cb.cb_list); + } + } else { + /* return the cancel routine */ + list_del(&kernel_priv_cb_pos->cb_list); + return -ECORRUPTED_MESSAGE_HEADER; + } + break; + case HECI_IOCTL: + /* connect message */ + if (!other_client_is_connecting(device_object, file_extension)) { + continue; + } + if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_message_header) + + sizeof(struct hbm_client_connect_request))) { + file_extension->state = HECI_FILE_CONNECTING; + *slots -= (sizeof(struct heci_message_header) + + sizeof(struct hbm_client_connect_request) + 3) / 4; + if (!heci_connect(device_object, file_extension)) { + file_extension->status = -ENODEV; + kernel_priv_cb_pos->information = 0; + list_del(&kernel_priv_cb_pos->cb_list); + return -ENODEV; + } else { + list_del(&kernel_priv_cb_pos->cb_list); + list_add_tail(&kernel_priv_cb_pos->cb_list, + &device_object->control_read_list. + heci_cb.cb_list); + file_extension->timer_count = CONNECT_TIMEOUT; + } + } else { + /* return the cancel routine */ + list_del(&kernel_priv_cb_pos->cb_list); + return -ECORRUPTED_MESSAGE_HEADER; + } + break; + + default: + BUG_ON(1); + } + + } + } + /* complete write list CB */ + if (device_object->write_list.status == ESUCCESS + && !list_empty(&device_object->write_list.heci_cb.cb_list)) { + DBG("complete write list CB \n"); + list_for_each_entry_safe(kernel_priv_cb_pos, kernel_priv_cb_next, &device_object-> + write_list.heci_cb.cb_list, cb_list){ + file_extension = (struct heci_file_private *) kernel_priv_cb_pos->file_private; + + if ((file_extension != NULL) + && (file_extension != &device_object->legacy_file_extension)) { + if (!flow_control_credentials(device_object, + file_extension)) { + DBG("No flow control credentials for client %d, not sending\n", + file_extension->host_client_id); + continue; + } + if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_message_header) + + (kernel_priv_cb_pos->request_buffer.size - kernel_priv_cb_pos->information))) { + heci_header = (struct heci_message_header *) & device_object->write_message_buffer[0]; + heci_header->host_address = file_extension->host_client_id; + heci_header->me_address = file_extension->me_client_id; + heci_header->length = ((kernel_priv_cb_pos->request_buffer.size) - + (kernel_priv_cb_pos->information)); + heci_header->message_complete = 1; + heci_header->reserved = 0; + DBG("kernel_priv_cb_pos->request_buffer.size =%d heci_header->message_complete= %d\n", + kernel_priv_cb_pos->request_buffer.size, + heci_header->message_complete); + DBG("kernel_priv_cb_pos->information =%lu\n", + kernel_priv_cb_pos->information); + DBG("heci_header->length =%d\n", + heci_header->length); + *slots -= (sizeof(struct heci_message_header) + heci_header->length + 3) / 4; + if (!heci_write_message (device_object, heci_header, + (unsigned char *) (kernel_priv_cb_pos-> request_buffer.data + kernel_priv_cb_pos->information), + heci_header->length)) { + file_extension->status = -ENODEV; + list_del(&kernel_priv_cb_pos->cb_list); + list_add_tail(&kernel_priv_cb_pos->cb_list, + &complete_list->heci_cb. + cb_list); + return -ENODEV; + } else { + flow_control_reduce + (device_object, file_extension); + file_extension->status = ESUCCESS; + kernel_priv_cb_pos->information += heci_header->length; + list_del(&kernel_priv_cb_pos->cb_list); + list_add_tail(&kernel_priv_cb_pos->cb_list, + &device_object->write_waiting_list. + heci_cb.cb_list); + } + } else if (*slots == ((device_object->host_hw_state & H_CBD) >> 24)) { /* buffer is still empty */ + heci_header = (struct heci_message_header *) & device_object->write_message_buffer[0]; + heci_header->host_address = file_extension->host_client_id; + heci_header->me_address = file_extension->me_client_id; + heci_header->length = (*slots * sizeof(__u32)) - sizeof(struct heci_message_header); + heci_header->message_complete = 0; + heci_header->reserved = 0; + + (*slots) -= (sizeof(struct heci_message_header) + heci_header->length + 3) / 4; + if (!heci_write_message(device_object, heci_header, + (unsigned char *) (kernel_priv_cb_pos->request_buffer. data + kernel_priv_cb_pos->information), + heci_header->length)) { + file_extension->status = -ENODEV; + list_del(&kernel_priv_cb_pos->cb_list); + list_add_tail(&kernel_priv_cb_pos->cb_list, &complete_list->heci_cb.cb_list); + return -ENODEV; + } else { + kernel_priv_cb_pos->information += heci_header->length; + DBG("kernel_priv_cb_pos->request_buffer.size =%d heci_header->message_complete= %d\n", + kernel_priv_cb_pos->request_buffer.size, + heci_header->message_complete); + DBG("kernel_priv_cb_pos->information =%lu\n", kernel_priv_cb_pos->information); + DBG("heci_header->length =%d\n", heci_header->length); + } + return -ECOMPLETE_MESSAGE; + } else { + return -ECORRUPTED_MESSAGE_HEADER; + } + } else if (file_extension == &device_object->legacy_file_extension) { /* LEGACY IOCTL */ + DBG("complete pthi write cb\n"); + if (!flow_control_credentials(device_object, file_extension)) { + DBG("No flow control credentials for pthi client %d, not sending\n", + file_extension->host_client_id); + continue; + } + if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_message_header) + + device_object->legacy_message_buffer_size - device_object->legacy_message_buffer_index)) { + heci_header = (struct heci_message_header *) & device_object->write_message_buffer[0]; + heci_header->host_address = file_extension->host_client_id; + heci_header->me_address = file_extension->me_client_id; + heci_header->length = device_object->legacy_message_buffer_size - + device_object->legacy_message_buffer_index; + heci_header->message_complete = 1; + heci_header->reserved = 0; + + *slots -= (sizeof(struct heci_message_header) + heci_header->length + 3) / 4; + + if (!heci_write_message (device_object, heci_header, + (device_object->legacy_message_buffer + device_object->legacy_message_buffer_index), + heci_header->length)) { + device_object->legacy_state = HECI_LEGACY_IDLE; + file_extension->status = -ENODEV; + list_del(&kernel_priv_cb_pos->cb_list); + return -ENODEV; + } else { + flow_control_reduce (device_object, file_extension); + device_object->legacy_message_buffer_index += heci_header->length; + list_del(&kernel_priv_cb_pos->cb_list); + kernel_priv_cb_pos->information = device_object->legacy_message_buffer_index; + file_extension->status = ESUCCESS; + device_object->legacy_state = HECI_LEGACY_FLOW_CONTROL; + device_object->legacy_flow_control_pending = TRUE; + /* save legacy cb sent to pthi client */ + device_object->legacy_current_cb = kernel_priv_cb_pos; + list_add_tail(&kernel_priv_cb_pos->cb_list, + &device_object->write_waiting_list.heci_cb. cb_list); + + } + } else if (*slots == ((device_object->host_hw_state & H_CBD) >> 24)) { /* buffer is still empty */ + heci_header = (struct heci_message_header *) & device_object->write_message_buffer[0]; + heci_header->host_address = file_extension->host_client_id; + heci_header->me_address = file_extension->me_client_id; + heci_header->length = (*slots * sizeof(__u32)) - sizeof(struct heci_message_header); + heci_header->message_complete = 0; + heci_header->reserved = 0; + + *slots -= (sizeof(struct heci_message_header) + heci_header->length + 3) / 4; + + if (!heci_write_message (device_object, heci_header, (device_object->legacy_message_buffer + + device_object->legacy_message_buffer_index), heci_header->length)) { + file_extension->status = -ENODEV; + list_del(&kernel_priv_cb_pos->cb_list); + } else { + device_object->legacy_message_buffer_index += heci_header->length; + } + return -ECOMPLETE_MESSAGE; + } else { + return -ECORRUPTED_MESSAGE_HEADER;; + } + } + + } + + } + return ESUCCESS; +} + + +/** + * is_treat_specially_client - check if the message belong + * to the file extension . + * @file_extension -extension of the file object + * @connect_res -connect response bus message + * @device_object -Device object for our driver + * + * @return : + * TRUE if empty + * FALSE - otherwise. + */ +int is_treat_specially_client(struct heci_file_private * file_extension, + struct hbm_client_connect_response * + connect_res) +{ + int ret = FALSE; + if ((file_extension->host_client_id == connect_res->host_address) + && (file_extension->me_client_id == connect_res->me_address)) { + + if (connect_res->status == 0) { + DBG("client connect status = 0x%08x.\n", + connect_res->status); + file_extension->state = HECI_FILE_CONNECTED; + file_extension->status = ESUCCESS; + } else { + DBG("client connect status = 0x%08x.\n", + connect_res->status); + file_extension->state = HECI_FILE_DISCONNECTED; + file_extension->status = -ENODEV; + } + ret = TRUE; + } + DBG("client state = %d.\n", file_extension->state); + return ret; + +} + +/** + * heci_client_connect_response - connect response bh routine + * + * @device_object -Device object for our driver + * @connect_res -connect response bus message + * @complete_list - An instance of our list structure + * + * @return : + * none; + */ +void heci_client_connect_response(struct iamt_heci_device * device_object, + struct hbm_client_connect_response * + connect_res) +{ + + struct heci_file_private *file_extension = NULL; + struct heci_cb_private *kernel_priv_cb_pos = NULL, *kernel_priv_cb_next = NULL; + + /* if WD or legacy client treat specially */ + + if ((is_treat_specially_client(&(device_object->wd_file_extension), + connect_res)) + || (is_treat_specially_client(& + (device_object-> + legacy_file_extension), + connect_res))) { + return; + } + + if (device_object->control_read_list.status == ESUCCESS + && !list_empty(&device_object->control_read_list.heci_cb. + cb_list)) { + list_for_each_entry_safe(kernel_priv_cb_pos, kernel_priv_cb_next, &device_object->control_read_list.heci_cb.cb_list, cb_list){ + file_extension = + (struct heci_file_private *) kernel_priv_cb_pos-> + file_private; + if (!file_extension) { + list_del(&kernel_priv_cb_pos->cb_list); + return; + } + if (HECI_IOCTL == kernel_priv_cb_pos->major_file_operations) { + + if (is_treat_specially_client (file_extension, connect_res)) { + list_del(&kernel_priv_cb_pos->cb_list); + file_extension->status = ESUCCESS; + file_extension->timer_count = 0; + break; + } + } + } + } + return; +} + +/** + * heci_client_disconnect_response - disconnect response bh routine + * + * @device_object -Device object for our driver + * @disconnect_res -disconnect response bus message + * @complete_list - An instance of our list structure + * + * @return : + * none; + */ +void heci_client_disconnect_response(struct iamt_heci_device * device_object, + struct hbm_client_connect_response * + disconnect_res) +{ + struct heci_file_private *file_extension = NULL; + struct heci_cb_private *kernel_priv_cb_pos = NULL, *kernel_priv_cb_next = NULL; + if (device_object->control_read_list.status == ESUCCESS + && !list_empty(&device_object->control_read_list.heci_cb. + cb_list)) { + list_for_each_entry_safe(kernel_priv_cb_pos, kernel_priv_cb_next, &device_object->control_read_list.heci_cb.cb_list, cb_list){ + file_extension = + (struct heci_file_private *) kernel_priv_cb_pos-> + file_private; + + if (!file_extension) { + list_del(&kernel_priv_cb_pos->cb_list); + return; + } + + DBG("list_for_each_entry_safe in control_read_list.\n"); + if ((file_extension->host_client_id == disconnect_res->host_address) + && (file_extension->me_client_id == disconnect_res->me_address)) { + list_del(&kernel_priv_cb_pos->cb_list); + if (disconnect_res->status == 0) + file_extension->state = HECI_FILE_DISCONNECTED; + file_extension->status = ESUCCESS; + file_extension->timer_count = 0; + break; + } + } + } + return; +} + +/** + * heci_client_flow_control_response - flow control response bh routine + * + * @device_object -Device object for our driver + * @flow_control -flow control response bus message + * + * @return : + * none; + */ +void heci_client_flow_control_response(struct iamt_heci_device * device_object, + struct hbm_flow_control * flow_control) +{ + struct heci_file_private *file_extension_pos = NULL; + struct heci_file_private *file_extension_next = NULL; + int i; + if (flow_control->host_address == 0) { /* single receive buffer */ + for (i = 0; i < device_object->num_heci_me_clients; i++) { + if (flow_control->me_address == + device_object->me_clients[i].client_id) { + if (device_object->me_clients[i].properteis.single_receive_buffer != 0) { + device_object->me_clients[i]. + flow_control_credentials++; + DBG("received flow control message for ME client %d (single receive buffer).\n", + flow_control->me_address); + DBG("flow control credentials=%d.\n", + device_object->me_clients[i].flow_control_credentials); + } else { + BUG_ON(1); /* error in flow control */ + } + } + } + } else { /* normal connection */ + list_for_each_entry_safe(file_extension_pos, file_extension_next, &device_object->file_list, link) { + DBG("list_for_each_entry_safe in file_list\n"); + + DBG("file_extension of host client %d ME client %d.\n", + file_extension_pos->host_client_id, + file_extension_pos->me_client_id); + DBG("flow control message for host client %d ME client %d.\n", + flow_control->host_address, + flow_control->me_address); + if ((file_extension_pos->host_client_id == flow_control->host_address) + && (file_extension_pos->me_client_id == flow_control->me_address)) { + DBG("received flow control message for host client %d ME client %d.\n", + flow_control->host_address, + flow_control->me_address); + file_extension_pos->flow_control_credentials++; + DBG("flow control credentials=%d.\n", + file_extension_pos->flow_control_credentials); + break; + } + } + } + return; +} + +/** + * heci_client_disconnect_request - disconnect request bh routine + * + * @device_object -Device object for our driver + * @disconnect_req -disconnect request bus message + * + * @return : + * none; + */ +void heci_client_disconnect_request(struct iamt_heci_device * device_object, + struct hbm_client_disconnect_request * + disconnect_req) +{ + struct heci_message_header *heci_header; + struct hbm_client_connect_response *disconnect_res; + struct heci_file_private *file_extension_pos = NULL; + struct heci_file_private *file_extension_next = NULL; + + list_for_each_entry_safe(file_extension_pos, file_extension_next, &device_object->file_list, link) { + if ((file_extension_pos->host_client_id == disconnect_req->host_address) + && (file_extension_pos->me_client_id == disconnect_req->me_address)) { + DBG("received disconnect request for host client %d ME client %d.\n", + disconnect_req->host_address, + disconnect_req->me_address); + file_extension_pos->state = HECI_FILE_DISCONNECTED; + file_extension_pos->timer_count = 0; + if (file_extension_pos == &device_object->wd_file_extension) { + device_object->wd_due_counter = 0; + device_object->wd_pending = FALSE; + } else if (file_extension_pos == + &device_object->legacy_file_extension) { + device_object->legacy_timer = 0; + } + + /* prepare disconnect response */ + heci_header = (struct heci_message_header *) & device_object->extra_message_buffer[0]; + heci_header->host_address = 0; + heci_header->me_address = 0; + heci_header->length = sizeof(struct hbm_client_connect_response); + heci_header->message_complete = 1; + heci_header->reserved = 0; + + disconnect_res = (struct hbm_client_connect_response *) & + device_object->extra_message_buffer[1]; + disconnect_res->host_address = + file_extension_pos->host_client_id; + disconnect_res->me_address = file_extension_pos->me_client_id; + *(__u8 *) (&disconnect_res->command) = CLIENT_DISCONNECT_RES_CMD; + disconnect_res->status = 0; + device_object->extra_write_index = 2; + break; + } + } + return; +} + + +/** + * heci_timer - timer function . + * @data: pointer to the device structure + * + * NOTE: This function is called by timer interrupt work + * @return : + * none; + */ +void heci_wd_timer(unsigned long data) +{ + struct iamt_heci_device *device = (struct iamt_heci_device *) data; + DBG("send watchdog.\n"); + spin_lock_bh(&device->device_lock); + if (device->heci_state != HECI_ENABLED) { + mod_timer(&device->wd_timer, round_jiffies(jiffies + 2 * HZ)); + spin_unlock_bh(&device->device_lock); + return; + } + if (device->wd_file_extension.state != HECI_FILE_CONNECTED) { + mod_timer(&device->wd_timer, round_jiffies(jiffies + 2 * HZ)); + spin_unlock_bh(&device->device_lock); + return; + } + /*** Watchdog ***/ + if (device->wd_due_counter != 0 && FALSE == device->wd_bypass) { + if (--device->wd_due_counter == 0) { + if (device->host_buffer_is_empty && + flow_control_credentials(device, + &device-> + wd_file_extension)) { + device->host_buffer_is_empty = FALSE; + + if (!heci_send_wd(device)) + DBG("Wd send failed\n"); + else + flow_control_reduce(device, + &device-> + wd_file_extension); + if (device->wd_timeout != 0) + device->wd_due_counter = 2; + else + device->wd_due_counter = 0; + } else { + device->wd_pending = TRUE; + } + } + } + if (device->legacy_stall_timer != 0) { + if (--device->legacy_stall_timer == 0) { + DBG("Reseting because of hang to PTHI\n"); + heci_reset(device, TRUE); + device->legacy_message_buffer_size = 0; + device->legacy_message_buffer_index = 0; + device->legacy_canceled = FALSE; + device->legacy_ioctl = TRUE; + device->legacy_state = HECI_LEGACY_IDLE; + device->legacy_timer = 0; + spin_unlock_bh(&device->device_lock); + + if (device->legacy_current_cb) { + kfree(device->legacy_current_cb->request_buffer.data); + device->legacy_current_cb->request_buffer.data = NULL; + kfree(device->legacy_current_cb->response_buffer.data); + device->legacy_current_cb->response_buffer.data = NULL; + kfree(device->legacy_current_cb); + } + spin_lock_bh(&device->device_lock); + device->legacy_file_object = NULL; + device->legacy_current_cb = NULL; + run_next_legacy_cmd(device); + } + } + mod_timer(&device->wd_timer, round_jiffies(jiffies + 2 * HZ)); + spin_unlock_bh(&device->device_lock); + return; +} --- linux-2.6.27.orig/ubuntu/heci/BOM +++ linux-2.6.27/ubuntu/heci/BOM @@ -0,0 +1,2 @@ +Downloaded from: http://sourceforge.net/project/showfiles.php?group_id=193428 +Current Version: 3.2.0.24 --- linux-2.6.27.orig/ubuntu/heci/heci.h +++ linux-2.6.27/ubuntu/heci/heci.h @@ -0,0 +1,141 @@ +/* + * Part of Intel(R) Manageability Engine Interface Linux driver + * + * Copyright (c) 2003 - 2007 Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + */ + +#ifndef _HECI_H_ +#define _HECI_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "heci_data_structures.h" + + +extern const struct guid heci_pthi_guid; +extern const struct guid heci_wd_guid; +extern const __u8 start_wd_params[]; +extern const __u8 stop_wd_params[]; +extern const __u8 heci_wd_state_independence_msg[2][4]; + +/** + * memory IO BAR definition + */ +#define BAR_0 0 +#define BAR_1 1 +#define BAR_5 5 +/** + * Number of queue lists used by this driver + */ +#define PCI_HECI_DEVICE_ID1 0x2974 +#define PCI_HECI_DEVICE_ID2 0x2984 +#define PCI_HECI_DEVICE_ID3 0x2994 +#define PCI_HECI_DEVICE_ID4 0x29A4 +#define PCI_HECI_DEVICE_ID5 0x29B4 +#define PCI_HECI_DEVICE_ID6 0x29C4 +#define PCI_HECI_DEVICE_ID7 0x29E4 +#define PCI_HECI_DEVICE_ID8 0x29F4 + +/** + * heci init function prototypes + */ +struct iamt_heci_device *init_heci_device(struct pci_dev *pdev); +void heci_reset(struct iamt_heci_device * device_object, int interrupts); +int heci_hw_init(struct iamt_heci_device * device_object); +int heci_initialize_clients(void *data); +struct heci_file_private *alloc_priv(struct file *file); +int heci_disconnect_host_client(struct iamt_heci_device * device_object, + struct heci_file_private * file_extension); +void heci_initialize_list(struct io_heci_list *list, + struct iamt_heci_device * device_object); +void heci_flush_list(struct io_heci_list *list, + struct heci_file_private * file_extension); +void heci_flush_queues(struct iamt_heci_device * device_object, + struct heci_file_private * file_extension); + +void heci_remove_client_from_file_list(struct iamt_heci_device * device_object, + __u8 host_client_id); + +/** + * interrupt function prototype + */ +irqreturn_t heci_isr_interrupt(int irq, void *dev_id); +void heci_wd_timer(unsigned long data); +void heci_bh_handler(struct work_struct *work); +/** + * input output function prototype + */ +int heci_ioctl_get_version(struct iamt_heci_device * device, int if_num, + struct heci_message_data *u_msg, + struct heci_message_data k_msg, + struct heci_file_private * file_extension); +int heci_ioctl_connect_client(struct iamt_heci_device * device, int if_num, + struct heci_message_data *u_msg, + struct heci_message_data k_msg, + struct file *file); +int heci_ioctl_wd(struct iamt_heci_device * device, int if_num, + struct heci_message_data k_msg, + struct heci_file_private * file_extension); +int heci_ioctl_bypass_wd(struct iamt_heci_device * device, int if_num, + struct heci_message_data k_msg, + struct heci_file_private * file_extension); +int legacy_ioctl_send_message(struct iamt_heci_device * device, int if_num, + struct heci_message_data k_msg, + struct file *file); +int legacy_ioctl_receive_message(struct iamt_heci_device * device, int if_num, + struct heci_message_data *u_msg, + struct heci_message_data k_msg, + struct file *file); +int heci_start_read(struct iamt_heci_device * device, int if_num, + struct heci_file_private * file_extension); +int pthi_write(struct iamt_heci_device * device, + struct heci_cb_private *kernel_priv_cb); +int pthi_read(struct iamt_heci_device * device, int if_num, struct file *file, + char *ubuf, size_t length, loff_t* offset); +struct heci_cb_private* find_pthi_read_list_entry(struct iamt_heci_device* device, + struct file* file, struct heci_file_private* file_extension); +void run_next_legacy_cmd(struct iamt_heci_device * device); + +#endif /* _HECI_H_ */ --- linux-2.6.27.orig/ubuntu/gfs/util.c +++ linux-2.6.27/ubuntu/gfs/util.c @@ -0,0 +1,571 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "glock.h" +#include "lm.h" + +uint32_t gfs_random_number; + +struct kmem_cache *gfs_glock_cachep = NULL; +struct kmem_cache *gfs_inode_cachep = NULL; +struct kmem_cache *gfs_bufdata_cachep = NULL; +struct kmem_cache *gfs_mhc_cachep = NULL; + +/** + * gfs_random - Generate a random 32-bit number + * + * Generate a semi-crappy 32-bit pseudo-random number without using + * floating point. + * + * The PRNG is from "Numerical Recipes in C" (second edition), page 284. + * + * Returns: a 32-bit random number + */ + +uint32_t +gfs_random(void) +{ + gfs_random_number = 0x0019660D * gfs_random_number + 0x3C6EF35F; + return gfs_random_number; +} + +/** + * hash_more_internal - hash an array of data + * @data: the data to be hashed + * @len: the length of data to be hashed + * @hash: the hash from a previous call + * + * Take some data and convert it to a 32-bit hash. + * + * This is the 32-bit FNV-1a hash from: + * http://www.isthe.com/chongo/tech/comp/fnv/ + * + * Hash guts + * + * Returns: the hash + */ + +static __inline__ uint32_t +hash_more_internal(const void *data, unsigned int len, uint32_t hash) +{ + unsigned char *p = (unsigned char *)data; + unsigned char *e = p + len; + uint32_t h = hash; + + while (p < e) { + h ^= (uint32_t)(*p++); + h *= 0x01000193; + } + + return h; +} + +/** + * gfs_hash - hash an array of data + * @data: the data to be hashed + * @len: the length of data to be hashed + * + * Take some data and convert it to a 32-bit hash. + * + * This is the 32-bit FNV-1a hash from: + * http://www.isthe.com/chongo/tech/comp/fnv/ + * + * Returns: the hash + */ + +uint32_t +gfs_hash(const void *data, unsigned int len) +{ + uint32_t h = 0x811C9DC5; + h = hash_more_internal(data, len, h); + return h; +} + +/** + * gfs_hash_more - hash an array of data + * @data: the data to be hashed + * @len: the length of data to be hashed + * @hash: the hash from a previous call + * + * Take some data and convert it to a 32-bit hash. + * + * This is the 32-bit FNV-1a hash from: + * http://www.isthe.com/chongo/tech/comp/fnv/ + * + * This version let's you hash together discontinuous regions. + * For example, to compute the combined hash of the memory in + * (data1, len1), (data2, len2), and (data3, len3) you: + * + * h = gfs_hash(data1, len1); + * h = gfs_hash_more(data2, len2, h); + * h = gfs_hash_more(data3, len3, h); + * + * Returns: the hash + */ + +uint32_t +gfs_hash_more(const void *data, unsigned int len, uint32_t hash) +{ + uint32_t h; + h = hash_more_internal(data, len, hash); + return h; +} + +/* Byte-wise swap two items of size SIZE. */ + +#define SWAP(a, b, size) \ +do { \ + register size_t __size = (size); \ + register char *__a = (a), *__b = (b); \ + do { \ + char __tmp = *__a; \ + *__a++ = *__b; \ + *__b++ = __tmp; \ + } while (__size-- > 1); \ +} while (0) + +/** + * gfs_sort - Sort base array using shell sort algorithm + * @base: the input array + * @num_elem: number of elements in array + * @size: size of each element in array + * @compar: fxn to compare array elements (returns negative + * for lt, 0 for eq, and positive for gt + * + * Sorts the array passed in using the compar fxn to compare elements using + * the shell sort algorithm + */ + +void +gfs_sort(void *base, unsigned int num_elem, unsigned int size, + int (*compar) (const void *, const void *)) +{ + register char *pbase = (char *)base; + int i, j, k, h; + static int cols[16] = {1391376, 463792, 198768, 86961, + 33936, 13776, 4592, 1968, + 861, 336, 112, 48, + 21, 7, 3, 1}; + + for (k = 0; k < 16; k++) { + h = cols[k]; + for (i = h; i < num_elem; i++) { + j = i; + while (j >= h && + (*compar)((void *)(pbase + size * (j - h)), + (void *)(pbase + size * j)) > 0) { + SWAP(pbase + size * j, + pbase + size * (j - h), + size); + j = j - h; + } + } + } +} + +/** + * gfs_assert_i - Cause the machine to panic if @assertion is false + * @sdp: + * @assertion: + * @function: + * @file: + * @line: + * + */ + +void +gfs_assert_i(struct gfs_sbd *sdp, + char *assertion, + const char *function, + char *file, unsigned int line) +{ + if (sdp->sd_args.ar_oopses_ok) { + printk("GFS: fsid=%s: assertion \"%s\" failed\n" + "GFS: fsid=%s: function = %s\n" + "GFS: fsid=%s: file = %s, line = %u\n" + "GFS: fsid=%s: time = %lu\n", + sdp->sd_fsname, assertion, + sdp->sd_fsname, function, + sdp->sd_fsname, file, line, + sdp->sd_fsname, get_seconds()); + BUG(); + } + dump_stack(); + panic("GFS: fsid=%s: assertion \"%s\" failed\n" + "GFS: fsid=%s: function = %s\n" + "GFS: fsid=%s: file = %s, line = %u\n" + "GFS: fsid=%s: time = %lu\n", + sdp->sd_fsname, assertion, + sdp->sd_fsname, function, + sdp->sd_fsname, file, line, + sdp->sd_fsname, get_seconds()); +} + +/** + * gfs_assert_withdraw_i - Cause the machine to withdraw if @assertion is false + * @sdp: + * @assertion: + * @function: + * @file: + * @line: + * + * Returns: -1 if this call withdrew the machine, + * -2 if it was already withdrawn + */ + +int +gfs_assert_withdraw_i(struct gfs_sbd *sdp, + char *assertion, + const char *function, + char *file, unsigned int line) +{ + int me; + me = gfs_lm_withdraw(sdp, + "GFS: fsid=%s: fatal: assertion \"%s\" failed\n" + "GFS: fsid=%s: function = %s\n" + "GFS: fsid=%s: file = %s, line = %u\n" + "GFS: fsid=%s: time = %lu\n", + sdp->sd_fsname, assertion, + sdp->sd_fsname, function, + sdp->sd_fsname, file, line, + sdp->sd_fsname, get_seconds()); + return (me) ? -1 : -2; +} + +/** + * gfs_assert_warn_i - Print a message to the console if @assertion is false + * @sdp: + * @assertion: + * @function: + * @file: + * @line: + * + * Returns: -1 if we printed something + * -2 if we didn't + */ + +int +gfs_assert_warn_i(struct gfs_sbd *sdp, + char *assertion, + const char *function, + char *file, unsigned int line) +{ + if (time_before(jiffies, + sdp->sd_last_warning + + gfs_tune_get(sdp, gt_complain_secs) * HZ)) + return -2; + + printk("GFS: fsid=%s: warning: assertion \"%s\" failed\n" + "GFS: fsid=%s: function = %s\n" + "GFS: fsid=%s: file = %s, line = %u\n" + "GFS: fsid=%s: time = %lu\n", + sdp->sd_fsname, assertion, + sdp->sd_fsname, function, + sdp->sd_fsname, file, line, + sdp->sd_fsname, get_seconds()); + + sdp->sd_last_warning = jiffies; + if (sdp->sd_args.ar_debug) + BUG(); + + + return -1; +} + +/** + * gfs_consist_i - Flag a filesystem consistency error and withdraw + * @sdp: + * @cluster_wide: + * @function: + * @file: + * @line: + * + * Returns: -1 if this call withdrew the machine, + * 0 if it was already withdrawn + */ + +int +gfs_consist_i(struct gfs_sbd *sdp, int cluster_wide, + const char *function, + char *file, unsigned int line) +{ + return gfs_lm_withdraw(sdp, + "GFS: fsid=%s: fatal: filesystem consistency error\n" + "GFS: fsid=%s: function = %s\n" + "GFS: fsid=%s: file = %s, line = %u\n" + "GFS: fsid=%s: time = %lu\n", + sdp->sd_fsname, + sdp->sd_fsname, function, + sdp->sd_fsname, file, line, + sdp->sd_fsname, get_seconds()); +} + +/** + * gfs_consist_inode_i - Flag an inode consistency error and withdraw + * @ip: + * @cluster_wide: + * @function: + * @file: + * @line: + * + * Returns: -1 if this call withdrew the machine, + * 0 if it was already withdrawn + */ + +int +gfs_consist_inode_i(struct gfs_inode *ip, int cluster_wide, + const char *function, + char *file, unsigned int line) +{ + struct gfs_sbd *sdp = ip->i_sbd; + return gfs_lm_withdraw(sdp, + "GFS: fsid=%s: fatal: filesystem consistency error\n" + "GFS: fsid=%s: inode = %"PRIu64"/%"PRIu64"\n" + "GFS: fsid=%s: function = %s\n" + "GFS: fsid=%s: file = %s, line = %u\n" + "GFS: fsid=%s: time = %lu\n", + sdp->sd_fsname, + sdp->sd_fsname, ip->i_num.no_formal_ino, ip->i_num.no_addr, + sdp->sd_fsname, function, + sdp->sd_fsname, file, line, + sdp->sd_fsname, get_seconds()); +} + +/** + * gfs_consist_rgrpd_i - Flag a RG consistency error and withdraw + * @rgd: + * @cluster_wide: + * @function: + * @file: + * @line: + * + * Returns: -1 if this call withdrew the machine, + * 0 if it was already withdrawn + */ + +int +gfs_consist_rgrpd_i(struct gfs_rgrpd *rgd, int cluster_wide, + const char *function, + char *file, unsigned int line) +{ + struct gfs_sbd *sdp = rgd->rd_sbd; + return gfs_lm_withdraw(sdp, + "GFS: fsid=%s: fatal: filesystem consistency error\n" + "GFS: fsid=%s: RG = %"PRIu64"\n" + "GFS: fsid=%s: function = %s\n" + "GFS: fsid=%s: file = %s, line = %u\n" + "GFS: fsid=%s: time = %lu\n", + sdp->sd_fsname, + sdp->sd_fsname, rgd->rd_ri.ri_addr, + sdp->sd_fsname, function, + sdp->sd_fsname, file, line, + sdp->sd_fsname, get_seconds()); +} + +/** + * gfs_meta_check_ii - Flag a magic number consistency error and withdraw + * @sdp: + * @bh: + * @function: + * @file: + * @line: + * + * Returns: -1 if this call withdrew the machine, + * -2 if it was already withdrawn + */ + +int +gfs_meta_check_ii(struct gfs_sbd *sdp, struct buffer_head *bh, + const char *function, + char *file, unsigned int line) +{ + int me; + me = gfs_lm_withdraw(sdp, + "GFS: fsid=%s: fatal: invalid metadata block\n" + "GFS: fsid=%s: bh = %"PRIu64" (magic)\n" + "GFS: fsid=%s: function = %s\n" + "GFS: fsid=%s: file = %s, line = %u\n" + "GFS: fsid=%s: time = %lu\n", + sdp->sd_fsname, + sdp->sd_fsname, (uint64_t)bh->b_blocknr, + sdp->sd_fsname, function, + sdp->sd_fsname, file, line, + sdp->sd_fsname, get_seconds()); + return (me) ? -1 : -2; +} + +/** + * gfs_metatype_check_ii - Flag a metadata type consistency error and withdraw + * @sdp: + * @bh: + * @type: + * @t: + * @function: + * @file: + * @line: + * + * Returns: -1 if this call withdrew the machine, + * -2 if it was already withdrawn + */ + +int +gfs_metatype_check_ii(struct gfs_sbd *sdp, struct buffer_head *bh, + uint32_t type, uint32_t t, + const char *function, + char *file, unsigned int line) +{ + int me; + me = gfs_lm_withdraw(sdp, + "GFS: fsid=%s: fatal: invalid metadata block\n" + "GFS: fsid=%s: bh = %"PRIu64" (type: exp=%u, found=%u)\n" + "GFS: fsid=%s: function = %s\n" + "GFS: fsid=%s: file = %s, line = %u\n" + "GFS: fsid=%s: time = %lu\n", + sdp->sd_fsname, + sdp->sd_fsname, (uint64_t)bh->b_blocknr, type, t, + sdp->sd_fsname, function, + sdp->sd_fsname, file, line, + sdp->sd_fsname, get_seconds()); + return (me) ? -1 : -2; +} + +/** + * gfs_io_error_i - Flag an I/O error and withdraw + * @sdp: + * @function: + * @file: + * @line: + * + * Returns: -1 if this call withdrew the machine, + * 0 if it was already withdrawn + */ + +int +gfs_io_error_i(struct gfs_sbd *sdp, + const char *function, + char *file, unsigned int line) +{ + return gfs_lm_withdraw(sdp, + "GFS: fsid=%s: fatal: I/O error\n" + "GFS: fsid=%s: function = %s\n" + "GFS: fsid=%s: file = %s, line = %u\n" + "GFS: fsid=%s: time = %lu\n", + sdp->sd_fsname, + sdp->sd_fsname, function, + sdp->sd_fsname, file, line, + sdp->sd_fsname, get_seconds()); +} + +/** + * gfs_io_error_inode_i - Flag an inode I/O error and withdraw + * @ip: + * @function: + * @file: + * @line: + * + * Returns: -1 if this call withdrew the machine, + * 0 if it was already withdrawn + */ + +int +gfs_io_error_inode_i(struct gfs_inode *ip, + const char *function, + char *file, unsigned int line) +{ + struct gfs_sbd *sdp = ip->i_sbd; + return gfs_lm_withdraw(sdp, + "GFS: fsid=%s: fatal: I/O error\n" + "GFS: fsid=%s: inode = %"PRIu64"/%"PRIu64"\n" + "GFS: fsid=%s: function = %s\n" + "GFS: fsid=%s: file = %s, line = %u\n" + "GFS: fsid=%s: time = %lu\n", + sdp->sd_fsname, + sdp->sd_fsname, ip->i_num.no_formal_ino, ip->i_num.no_addr, + sdp->sd_fsname, function, + sdp->sd_fsname, file, line, + sdp->sd_fsname, get_seconds()); +} + +/** + * gfs_io_error_bh_i - Flag a buffer I/O error and withdraw + * @sdp: + * @bh: + * @function: + * @file: + * @line: + * + * Returns: -1 if this call withdrew the machine, + * 0 if it was already withdrawn + */ + +int +gfs_io_error_bh_i(struct gfs_sbd *sdp, struct buffer_head *bh, + const char *function, + char *file, unsigned int line) +{ + return gfs_lm_withdraw(sdp, + "GFS: fsid=%s: fatal: I/O error\n" + "GFS: fsid=%s: block = %"PRIu64"\n" + "GFS: fsid=%s: function = %s\n" + "GFS: fsid=%s: file = %s, line = %u\n" + "GFS: fsid=%s: time = %lu\n", + sdp->sd_fsname, + sdp->sd_fsname, (uint64_t)bh->b_blocknr, + sdp->sd_fsname, function, + sdp->sd_fsname, file, line, + sdp->sd_fsname, get_seconds()); +} + +/** + * gmalloc - malloc a small amount of memory + * @size: the number of bytes to malloc + * + * Returns: the memory + */ + +void * +gmalloc(unsigned int size) +{ + void *p; + RETRY_MALLOC(p = kmalloc(size, GFP_KERNEL), p); + return p; +} + +/** + * gfs_add_bh_to_ub - copy a buffer up to user space + * @ub: the structure representing where to copy + * @bh: the buffer + * + * Returns: errno + */ + +int +gfs_add_bh_to_ub(struct gfs_user_buffer *ub, struct buffer_head *bh) +{ + uint64_t blkno = bh->b_blocknr; + + if (ub->ub_count + sizeof(uint64_t) + bh->b_size > ub->ub_size) + return -ENOMEM; + + if (copy_to_user(ub->ub_data + ub->ub_count, + &blkno, + sizeof(uint64_t))) + return -EFAULT; + ub->ub_count += sizeof(uint64_t); + + if (copy_to_user(ub->ub_data + ub->ub_count, + bh->b_data, + bh->b_size)) + return -EFAULT; + ub->ub_count += bh->b_size; + + return 0; +} + --- linux-2.6.27.orig/ubuntu/gfs/ops_super.c +++ linux-2.6.27/ubuntu/gfs/ops_super.c @@ -0,0 +1,455 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "dio.h" +#include "glock.h" +#include "inode.h" +#include "lm.h" +#include "log.h" +#include "ops_fstype.h" +#include "ops_super.h" +#include "page.h" +#include "proc.h" +#include "quota.h" +#include "recovery.h" +#include "rgrp.h" +#include "super.h" +#include "sys.h" +#include "mount.h" + +/** + * gfs_write_inode - Make sure the inode is stable on the disk + * @inode: The inode + * @sync: synchronous write flag + * + * Returns: errno + */ + +static int +gfs_write_inode(struct inode *inode, int sync) +{ + struct gfs_inode *ip = get_v2ip(inode); + + atomic_inc(&ip->i_sbd->sd_ops_super); + + if (ip && sync) + gfs_log_flush_glock(ip->i_gl); + + return 0; +} + +/** + * gfs_drop_inode - drop an inode + * @inode: The inode + * + * If i_nlink is zero, any dirty data for the inode is thrown away. + * If a process on another machine has the file open, it may need that + * data. So, sync it out. + */ + +static void +gfs_drop_inode(struct inode *inode) +{ + struct gfs_sbd *sdp = get_v2sdp(inode->i_sb); + struct gfs_inode *ip = get_v2ip(inode); + + atomic_inc(&sdp->sd_ops_super); + + if (ip && + !inode->i_nlink && + S_ISREG(inode->i_mode) && + !sdp->sd_args.ar_localcaching) + gfs_sync_page_i(inode, DIO_START | DIO_WAIT); + generic_drop_inode(inode); +} + +/** + * gfs_put_super - Unmount the filesystem + * @sb: The VFS superblock + * + */ + +static void +gfs_put_super(struct super_block *sb) +{ + struct gfs_sbd *sdp = get_v2sdp(sb); + int error; + + if (!sdp) + return; + + atomic_inc(&sdp->sd_ops_super); + + gfs_proc_fs_del(sdp); + + /* Unfreeze the filesystem, if we need to */ + + down(&sdp->sd_freeze_lock); + if (sdp->sd_freeze_count) + gfs_glock_dq_uninit(&sdp->sd_freeze_gh); + up(&sdp->sd_freeze_lock); + + /* Kill off the inode thread */ + kthread_stop(sdp->sd_inoded_process); + + /* Kill off the quota thread */ + kthread_stop(sdp->sd_quotad_process); + + /* Kill off the log thread */ + kthread_stop(sdp->sd_logd_process); + + /* Kill off the recoverd thread */ + kthread_stop(sdp->sd_recoverd_process); + + /* Kill off the glockd threads */ + while (sdp->sd_glockd_num--) + kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]); + + /* Kill off the scand thread */ + kthread_stop(sdp->sd_scand_process); + + if (!test_bit(SDF_ROFS, &sdp->sd_flags)) { + error = gfs_make_fs_ro(sdp); + if (error) + gfs_io_error(sdp); + } + + /* At this point, we're through modifying the disk */ + + /* Release stuff */ + + gfs_inode_put(sdp->sd_riinode); + gfs_inode_put(sdp->sd_jiinode); + gfs_inode_put(sdp->sd_rooti); + gfs_inode_put(sdp->sd_qinode); + gfs_inode_put(sdp->sd_linode); + gfs_glock_put(sdp->sd_trans_gl); + gfs_glock_put(sdp->sd_rename_gl); + + if (!sdp->sd_args.ar_spectator) + gfs_glock_dq_uninit(&sdp->sd_journal_gh); + + gfs_glock_dq_uninit(&sdp->sd_live_gh); + + /* Get rid of rgrp bitmap structures */ + gfs_clear_rgrpd(sdp); + gfs_clear_journals(sdp); + + /* Take apart glock structures and buffer lists */ + gfs_gl_hash_clear(sdp, TRUE); + + /* Unmount the locking protocol */ + gfs_lm_unmount(sdp); + + /* At this point, we're through participating in the lockspace */ + + gfs_sys_fs_del(sdp); + + gfs_clear_dirty_j(sdp); + + /* Get rid of any extra inodes */ + while (invalidate_inodes(sb)) + yield(); + + vfree(sdp); + + set_v2sdp(sb, NULL); +} + +/** + * gfs_write_super - disk commit all incore transactions + * @sb: the filesystem + * + * This function is called every time sync(2) is called. + * After this exits, all dirty buffers and synced. + */ + +static void +gfs_write_super(struct super_block *sb) +{ + struct gfs_sbd *sdp = get_v2sdp(sb); + atomic_inc(&sdp->sd_ops_super); + gfs_log_flush(sdp); +} + +/** + * gfs_write_super_lockfs - prevent further writes to the filesystem + * @sb: the VFS structure for the filesystem + * + */ + +static void +gfs_write_super_lockfs(struct super_block *sb) +{ + struct gfs_sbd *sdp = get_v2sdp(sb); + int error; + + if (test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) + return; + + atomic_inc(&sdp->sd_ops_super); + + for (;;) { + error = gfs_freeze_fs(sdp); + if (!error) + break; + + switch (error) { + case -EBUSY: + printk("GFS: fsid=%s: waiting for recovery before freeze\n", + sdp->sd_fsname); + break; + + default: + printk("GFS: fsid=%s: error freezing FS: %d\n", + sdp->sd_fsname, error); + break; + } + + printk("GFS: fsid=%s: retrying...\n", sdp->sd_fsname); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + } +} + +/** + * gfs_unlockfs - reallow writes to the filesystem + * @sb: the VFS structure for the filesystem + * + */ + +static void +gfs_unlockfs(struct super_block *sb) +{ + struct gfs_sbd *sdp = get_v2sdp(sb); + + atomic_inc(&sdp->sd_ops_super); + + gfs_unfreeze_fs(sdp); +} + +/** + * gfs_statfs - Gather and return stats about the filesystem + * @sb: The superblock + * @statfsbuf: The buffer + * + * Returns: 0 on success or error code + */ + +static int gfs_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + struct super_block *sb = dentry->d_inode->i_sb; + struct gfs_sbd *sdp = get_v2sdp(sb); + struct gfs_stat_gfs sg; + int error; + + atomic_inc(&sdp->sd_ops_super); + + if (gfs_tune_get(sdp, gt_statfs_fast)) + return(gfs_statfs_fast(sdp, (void *)buf)); + + error = gfs_stat_gfs(sdp, &sg, TRUE); + if (error) + return error; + + memset(buf, 0, sizeof(struct kstatfs)); + + buf->f_type = GFS_MAGIC; + buf->f_bsize = sdp->sd_sb.sb_bsize; + buf->f_blocks = sg.sg_total_blocks; + buf->f_bfree = sg.sg_free + sg.sg_free_dinode + sg.sg_free_meta; + buf->f_bavail = sg.sg_free + sg.sg_free_dinode + sg.sg_free_meta; + buf->f_files = sg.sg_used_dinode + sg.sg_free_dinode + + sg.sg_free_meta + sg.sg_free; + buf->f_ffree = sg.sg_free_dinode + sg.sg_free_meta + sg.sg_free; + buf->f_namelen = GFS_FNAMESIZE; + + return 0; +} + +/** + * gfs_remount_fs - called when the FS is remounted + * @sb: the filesystem + * @flags: the remount flags + * @data: extra data passed in (not used right now) + * + * Returns: errno + */ + +static int +gfs_remount_fs(struct super_block *sb, int *flags, char *data) +{ + struct gfs_sbd *sdp = get_v2sdp(sb); + struct gfs_tune *gt = &sdp->sd_tune; + int error = 0; + struct gfs_args *args; + + atomic_inc(&sdp->sd_ops_super); + + args = kmalloc(sizeof(struct gfs_args), GFP_KERNEL); + if (!args) + return -ENOMEM; + + error = gfs_make_args(data, args, TRUE); + if (error) { + printk("GFS: can't parse remount arguments\n"); + goto out; + } + if (args->ar_posix_acls) { + sdp->sd_args.ar_posix_acls = TRUE; + sb->s_flags |= MS_POSIXACL; + } + else { + sdp->sd_args.ar_posix_acls = FALSE; + sb->s_flags &= ~MS_POSIXACL; + } + + if (*flags & (MS_NOATIME | MS_NODIRATIME)) + set_bit(SDF_NOATIME, &sdp->sd_flags); + else + clear_bit(SDF_NOATIME, &sdp->sd_flags); + + if (sdp->sd_args.ar_spectator) + *flags |= MS_RDONLY; + else { + if (*flags & MS_RDONLY) { + if (!test_bit(SDF_ROFS, &sdp->sd_flags)) + error = gfs_make_fs_ro(sdp); + } else if (!(*flags & MS_RDONLY) && + test_bit(SDF_ROFS, &sdp->sd_flags)) { + error = gfs_make_fs_rw(sdp); + } + } + + if (args->ar_noquota) { + if (sdp->sd_args.ar_noquota == FALSE) + printk("GFS: remounting without quota\n"); + sdp->sd_args.ar_noquota = TRUE; + spin_lock(>->gt_spin); + gt->gt_quota_enforce = 0; + gt->gt_quota_account = 0; + spin_unlock(>->gt_spin); + } + else { + if (sdp->sd_args.ar_noquota == TRUE) + printk("GFS: remounting with quota\n"); + sdp->sd_args.ar_noquota = FALSE; + spin_lock(>->gt_spin); + gt->gt_quota_enforce = 1; + gt->gt_quota_account = 1; + spin_unlock(>->gt_spin); + } + + /* Don't let the VFS update atimes. GFS handles this itself. */ + *flags |= MS_NOATIME | MS_NODIRATIME; + +out: + kfree(args); + return error; +} + +/** + * gfs_clear_inode - Deallocate an inode when VFS is done with it + * @inode: The VFS inode + * + * If there's a GFS incore inode structure attached to the VFS inode: + * -- Detach them from one another. + * -- Schedule reclaim of GFS inode struct, the glock protecting it, and + * the associated iopen glock. + */ + +static void +gfs_clear_inode(struct inode *inode) +{ + struct gfs_inode *ip = get_v2ip(inode); + + atomic_inc(&get_v2sdp(inode->i_sb)->sd_ops_super); + + if (ip) { + spin_lock(&ip->i_spin); + ip->i_vnode = NULL; + set_v2ip(inode, NULL); + spin_unlock(&ip->i_spin); + + gfs_glock_schedule_for_reclaim(ip->i_gl); + gfs_inode_put(ip); + } +} + +/** + * gfs_show_options - Show mount options for /proc/mounts + * @s: seq_file structure + * @mnt: vfsmount + * + * Returns: 0 on success or error code + */ + +static int +gfs_show_options(struct seq_file *s, struct vfsmount *mnt) +{ + struct gfs_sbd *sdp = get_v2sdp(mnt->mnt_sb); + struct gfs_args *args = &sdp->sd_args; + + atomic_inc(&sdp->sd_ops_super); + + if (args->ar_lockproto[0]) { + seq_printf(s, ",lockproto="); + seq_puts(s, args->ar_lockproto); + } + if (args->ar_locktable[0]) { + seq_printf(s, ",locktable="); + seq_puts(s, args->ar_locktable); + } + if (args->ar_hostdata[0]) { + seq_printf(s, ",hostdata="); + seq_puts(s, args->ar_hostdata); + } + if (args->ar_spectator) + seq_printf(s, ",spectator"); + if (args->ar_ignore_local_fs) + seq_printf(s, ",ignore_local_fs"); + if (args->ar_localflocks) + seq_printf(s, ",localflocks"); + if (args->ar_localcaching) + seq_printf(s, ",localcaching"); + if (args->ar_oopses_ok) + seq_printf(s, ",oopses_ok"); + if (args->ar_debug) + seq_printf(s, ",debug"); + if (args->ar_upgrade) + seq_printf(s, ",upgrade"); + if (args->ar_num_glockd != GFS_GLOCKD_DEFAULT) + seq_printf(s, ",num_glockd=%u", args->ar_num_glockd); + if (args->ar_posix_acls) + seq_printf(s, ",acl"); + if (args->ar_noquota) + seq_printf(s, ",noquota"); + if (args->ar_suiddir) + seq_printf(s, ",suiddir"); + + return 0; +} + +struct super_operations gfs_super_ops = { + .write_inode = gfs_write_inode, + .drop_inode = gfs_drop_inode, + .put_super = gfs_put_super, + .write_super = gfs_write_super, + .write_super_lockfs = gfs_write_super_lockfs, + .unlockfs = gfs_unlockfs, + .statfs = gfs_statfs, + .remount_fs = gfs_remount_fs, + .clear_inode = gfs_clear_inode, + .show_options = gfs_show_options, +}; --- linux-2.6.27.orig/ubuntu/gfs/proc.c +++ linux-2.6.27/ubuntu/gfs/proc.c @@ -0,0 +1,491 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "glock.h" +#include "lm.h" +#include "proc.h" +#include "super.h" + +struct list_head gfs_fs_list; +struct semaphore gfs_fs_lock; +char *gfs_proc_margs; +spinlock_t gfs_proc_margs_lock; +spinlock_t gfs_req_lock; + +/** + * gfs_proc_fs_add - Add a FS to the list of mounted FSs + * @sdp: + * + */ + +void +gfs_proc_fs_add(struct gfs_sbd *sdp) +{ + down(&gfs_fs_lock); + list_add(&sdp->sd_list, &gfs_fs_list); + up(&gfs_fs_lock); +} + +/** + * gfs_proc_fs_del - Remove a FS from the list of mounted FSs + * @sdp: + * + */ + +void +gfs_proc_fs_del(struct gfs_sbd *sdp) +{ + down(&gfs_fs_lock); + list_del(&sdp->sd_list); + up(&gfs_fs_lock); +} + +/** + * do_list - Copy the list of mountes FSs to userspace + * @user_buf: + * @size: + * + * @Returns: -errno, or the number of bytes copied to userspace + */ + +static ssize_t +do_list(char *user_buf, size_t size) +{ + struct list_head *tmp; + struct gfs_sbd *sdp = NULL; + unsigned int x; + char num[21]; + char device_id[32]; + char *buf; + int error = 0; + + down(&gfs_fs_lock); + + x = 0; + for (tmp = gfs_fs_list.next; tmp != &gfs_fs_list; tmp = tmp->next) { + sdp = list_entry(tmp, struct gfs_sbd, sd_list); + sprintf(device_id, "%u:%u", MAJOR(sdp->sd_vfs->s_dev), + MINOR(sdp->sd_vfs->s_dev)); + x += sprintf(num, "%lu", (unsigned long)sdp) + + strlen(device_id) + + strlen(sdp->sd_fsname) + 3; + } + + if (!x) + goto out; + + error = -EFBIG; + if (x > size) + goto out; + + error = -ENOMEM; + buf = kmalloc(x + 1, GFP_KERNEL); + if (!buf) + goto out; + + x = 0; + for (tmp = gfs_fs_list.next; tmp != &gfs_fs_list; tmp = tmp->next) { + sdp = list_entry(tmp, struct gfs_sbd, sd_list); + sprintf(device_id, "%u:%u", MAJOR(sdp->sd_vfs->s_dev), + MINOR(sdp->sd_vfs->s_dev)); + x += sprintf(buf + x, "%lu %s %s\n", + (unsigned long)sdp, device_id, sdp->sd_fsname); + } + + if (copy_to_user(user_buf, buf, x)) + error = -EFAULT; + else + error = x; + + kfree(buf); + + out: + up(&gfs_fs_lock); + + return error; +} + +/** + * find_argument - + * @p: + * + * Returns: + */ + +static char * +find_argument(char *p) +{ + char *p2; + + while (*p == ' ' || *p == '\n') + p++; + if (!*p) + return NULL; + for (p2 = p; *p2; p2++) /* do nothing */; + p2--; + while (*p2 == ' ' || *p2 == '\n') + *p2-- = 0; + + return p; +} + +/** + * do_freeze - freeze a filesystem + * @p: the freeze command + * + * Returns: errno + */ + +static int +do_freeze(char *p) +{ + struct list_head *tmp; + struct gfs_sbd *sdp; + char num[21]; + int error = 0; + + p = find_argument(p + 6); + if (!p) + return -ENOENT; + + down(&gfs_fs_lock); + + for (tmp = gfs_fs_list.next; tmp != &gfs_fs_list; tmp = tmp->next) { + sdp = list_entry(tmp, struct gfs_sbd, sd_list); + sprintf(num, "%lu", (unsigned long)sdp); + if (strcmp(num, p) == 0) + break; + } + + if (tmp == &gfs_fs_list) + error = -ENOENT; + else + error = gfs_freeze_fs(sdp); + + up(&gfs_fs_lock); + + return error; +} + +/** + * do_unfreeze - unfreeze a filesystem + * @p: the unfreeze command + * + * Returns: errno + */ + +static int +do_unfreeze(char *p) +{ + struct list_head *tmp; + struct gfs_sbd *sdp; + char num[21]; + int error = 0; + + p = find_argument(p + 8); + if (!p) + return -ENOENT; + + down(&gfs_fs_lock); + + for (tmp = gfs_fs_list.next; tmp != &gfs_fs_list; tmp = tmp->next) { + sdp = list_entry(tmp, struct gfs_sbd, sd_list); + sprintf(num, "%lu", (unsigned long)sdp); + if (strcmp(num, p) == 0) + break; + } + + if (tmp == &gfs_fs_list) + error = -ENOENT; + else + gfs_unfreeze_fs(sdp); + + up(&gfs_fs_lock); + + return error; +} + +/** + * do_margs - Pass in mount arguments + * @p: the margs command + * + * Returns: errno + */ + +static int +do_margs(char *p) +{ + char *new_buf, *old_buf; + + p = find_argument(p + 5); + if (!p) + return -ENOENT; + + new_buf = kmalloc(strlen(p) + 1, GFP_KERNEL); + if (!new_buf) + return -ENOMEM; + strcpy(new_buf, p); + + spin_lock(&gfs_proc_margs_lock); + old_buf = gfs_proc_margs; + gfs_proc_margs = new_buf; + spin_unlock(&gfs_proc_margs_lock); + + if (old_buf) + kfree(old_buf); + + return 0; +} + +/** + * do_withdraw - withdraw a from the cluster for one filesystem + * @p: the cookie of the filesystem + * + * Returns: errno + */ + +static int +do_withdraw(char *p) +{ + struct list_head *tmp; + struct gfs_sbd *sdp; + char num[21]; + int error = 0; + + p = find_argument(p + 8); + if (!p) + return -ENOENT; + + down(&gfs_fs_lock); + + for (tmp = gfs_fs_list.next; tmp != &gfs_fs_list; tmp = tmp->next) { + sdp = list_entry(tmp, struct gfs_sbd, sd_list); + sprintf(num, "%lu", (unsigned long)sdp); + if (strcmp(num, p) == 0) + break; + } + + if (tmp == &gfs_fs_list) + error = -ENOENT; + else + gfs_lm_withdraw(sdp, + "GFS: fsid=%s: withdrawing from cluster at user's request\n", + sdp->sd_fsname); + + up(&gfs_fs_lock); + + return error; +} + +/** + * do_lockdump - Copy out the lock hash table to userspace + * @p: the cookie of the filesystem + * @buf: + * @size: + * + * Returns: errno + */ + +static int +do_lockdump(char *p, char *buf, size_t size) +{ + struct list_head *tmp; + struct gfs_sbd *sdp; + char num[21]; + struct gfs_user_buffer ub; + int error = 0; + + p = find_argument(p + 8); + if (!p) + return -ENOENT; + + down(&gfs_fs_lock); + + for (tmp = gfs_fs_list.next; tmp != &gfs_fs_list; tmp = tmp->next) { + sdp = list_entry(tmp, struct gfs_sbd, sd_list); + sprintf(num, "%lu", (unsigned long)sdp); + if (strcmp(num, p) == 0) + break; + } + + if (tmp == &gfs_fs_list) + error = -ENOENT; + else { + ub.ub_data = buf; + ub.ub_size = size; + ub.ub_count = 0; + + error = gfs_dump_lockstate(sdp, &ub); + if (!error) + error = ub.ub_count; + } + + up(&gfs_fs_lock); + + return error; +} + +/** + * gfs_proc_write - take a command from userspace + * @file: + * @buf: + * @size: + * @offset: + * + * Returns: -errno or the number of bytes taken + */ + +static ssize_t +gfs_proc_write(struct file *file, const char *buf, size_t size, loff_t *offset) +{ + char *p; + + spin_lock(&gfs_req_lock); + p = file->private_data; + file->private_data = NULL; + spin_unlock(&gfs_req_lock); + + if (p) + kfree(p); + + if (!size) + return -EINVAL; + + p = kmalloc(size + 1, GFP_KERNEL); + if (!p) + return -ENOMEM; + p[size] = 0; + + if (copy_from_user(p, buf, size)) { + kfree(p); + return -EFAULT; + } + + spin_lock(&gfs_req_lock); + file->private_data = p; + spin_unlock(&gfs_req_lock); + + return size; +} + +/** + * gfs_proc_read - return the results of a command + * @file: + * @buf: + * @size: + * @offset: + * + * Returns: -errno or the number of bytes returned + */ + +static ssize_t +gfs_proc_read(struct file *file, char *buf, size_t size, loff_t *offset) +{ + char *p; + int error; + + spin_lock(&gfs_req_lock); + p = file->private_data; + file->private_data = NULL; + spin_unlock(&gfs_req_lock); + + if (!p) + return -ENOENT; + + if (!size) { + kfree(p); + return -EINVAL; + } + + if (strncmp(p, "list", 4) == 0) + error = do_list(buf, size); + else if (strncmp(p, "freeze", 6) == 0) + error = do_freeze(p); + else if (strncmp(p, "unfreeze", 8) == 0) + error = do_unfreeze(p); + else if (strncmp(p, "margs", 5) == 0) + error = do_margs(p); + else if (strncmp(p, "withdraw", 8) == 0) + error = do_withdraw(p); + else if (strncmp(p, "lockdump", 8) == 0) + error = do_lockdump(p, buf, size); + else + error = -ENOSYS; + + kfree(p); + + return error; +} + +/** + * gfs_proc_close - free any mismatches writes + * @inode: + * @file: + * + * Returns: 0 + */ + +static int +gfs_proc_close(struct inode *inode, struct file *file) +{ + if (file->private_data) + kfree(file->private_data); + return 0; +} + +static struct file_operations gfs_proc_fops = +{ + .owner = THIS_MODULE, + .write = gfs_proc_write, + .read = gfs_proc_read, + .release = gfs_proc_close, +}; + +/** + * gfs_proc_init - initialize GFS' proc interface + * + */ + +int +gfs_proc_init(void) +{ + struct proc_dir_entry *pde; + + INIT_LIST_HEAD(&gfs_fs_list); + init_MUTEX(&gfs_fs_lock); + gfs_proc_margs = NULL; + spin_lock_init(&gfs_proc_margs_lock); + spin_lock_init(&gfs_req_lock); + + pde = create_proc_entry("fs/gfs", S_IFREG | 0600, NULL); + if (!pde) + return -ENOMEM; + + pde->owner = THIS_MODULE; + pde->proc_fops = &gfs_proc_fops; + + return 0; +} + +/** + * gfs_proc_uninit - uninitialize GFS' proc interface + * + */ + +void +gfs_proc_uninit(void) +{ + if (gfs_proc_margs) + kfree(gfs_proc_margs); + remove_proc_entry("fs/gfs", NULL); +} + --- linux-2.6.27.orig/ubuntu/gfs/locking.c +++ linux-2.6.27/ubuntu/gfs/locking.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License version 2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lm_interface.h" + +struct lmh_wrapper { + struct list_head lw_list; + const struct lm_lockops *lw_ops; +}; + +/* List of registered low-level locking protocols. A file system selects one + of them by name at mount time, e.g. lock_nolock, lock_dlm. */ + +static LIST_HEAD(lmh_list); +static DEFINE_MUTEX(lmh_lock); + +/** + * gfs_register_lockproto - Register a low-level locking protocol + * @proto: the protocol definition + * + * Returns: 0 on success, -EXXX on failure + */ + +int gfs_register_lockproto(const struct lm_lockops *proto) +{ + struct lmh_wrapper *lw; + + mutex_lock(&lmh_lock); + + list_for_each_entry(lw, &lmh_list, lw_list) { + if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) { + mutex_unlock(&lmh_lock); + printk(KERN_INFO "GFS2: protocol %s already exists\n", + proto->lm_proto_name); + return -EEXIST; + } + } + + lw = kzalloc(sizeof(struct lmh_wrapper), GFP_KERNEL); + if (!lw) { + mutex_unlock(&lmh_lock); + return -ENOMEM; + } + + lw->lw_ops = proto; + list_add(&lw->lw_list, &lmh_list); + + mutex_unlock(&lmh_lock); + + return 0; +} + +/** + * gfs_unregister_lockproto - Unregister a low-level locking protocol + * @proto: the protocol definition + * + */ + +void gfs_unregister_lockproto(const struct lm_lockops *proto) +{ + struct lmh_wrapper *lw; + + mutex_lock(&lmh_lock); + + list_for_each_entry(lw, &lmh_list, lw_list) { + if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) { + list_del(&lw->lw_list); + mutex_unlock(&lmh_lock); + kfree(lw); + return; + } + } + + mutex_unlock(&lmh_lock); + + printk(KERN_WARNING "GFS2: can't unregister lock protocol %s\n", + proto->lm_proto_name); +} + +/** + * gfs_mount_lockproto - Mount a lock protocol + * @proto_name - the name of the protocol + * @table_name - the name of the lock space + * @host_data - data specific to this host + * @cb - the callback to the code using the lock module + * @sdp - The GFS2 superblock + * @min_lvb_size - the mininum LVB size that the caller can deal with + * @flags - LM_MFLAG_* + * @lockstruct - a structure returned describing the mount + * + * Returns: 0 on success, -EXXX on failure + */ + +int gfs_mount_lockproto(char *proto_name, char *table_name, char *host_data, + lm_callback_t cb, void *cb_data, + unsigned int min_lvb_size, int flags, + struct lm_lockstruct *lockstruct, + struct kobject *fskobj) +{ + struct lmh_wrapper *lw = NULL; + int try = 0; + int error, found; + +retry: + mutex_lock(&lmh_lock); + + found = 0; + list_for_each_entry(lw, &lmh_list, lw_list) { + if (!strcmp(lw->lw_ops->lm_proto_name, proto_name)) { + found = 1; + break; + } + } + + if (!found) { + if (!try && capable(CAP_SYS_MODULE)) { + try = 1; + mutex_unlock(&lmh_lock); + request_module(proto_name); + goto retry; + } + printk(KERN_INFO "GFS2: can't find protocol %s\n", proto_name); + error = -ENOENT; + goto out; + } + + if (!try_module_get(lw->lw_ops->lm_owner)) { + try = 0; + mutex_unlock(&lmh_lock); + msleep(1000); + goto retry; + } + + error = lw->lw_ops->lm_mount(table_name, host_data, cb, cb_data, + min_lvb_size, flags, lockstruct, fskobj); + if (error) + module_put(lw->lw_ops->lm_owner); +out: + mutex_unlock(&lmh_lock); + return error; +} + +void gfs_unmount_lockproto(struct lm_lockstruct *lockstruct) +{ + mutex_lock(&lmh_lock); + lockstruct->ls_ops->lm_unmount(lockstruct->ls_lockspace); + if (lockstruct->ls_ops->lm_owner) + module_put(lockstruct->ls_ops->lm_owner); + mutex_unlock(&lmh_lock); +} + +/** + * gfs_withdraw_lockproto - abnormally unmount a lock module + * @lockstruct: the lockstruct passed into mount + * + */ + +void gfs_withdraw_lockproto(struct lm_lockstruct *lockstruct) +{ + mutex_lock(&lmh_lock); + lockstruct->ls_ops->lm_withdraw(lockstruct->ls_lockspace); + if (lockstruct->ls_ops->lm_owner) + module_put(lockstruct->ls_ops->lm_owner); + mutex_unlock(&lmh_lock); +} --- linux-2.6.27.orig/ubuntu/gfs/lock_dlm_sysfs.c +++ linux-2.6.27/ubuntu/gfs/lock_dlm_sysfs.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License version 2. + */ + +#include +#include + +#include "lock_dlm.h" + +static ssize_t proto_name_show(struct gdlm_ls *ls, char *buf) +{ + return sprintf(buf, "%s\n", gdlm_ops.lm_proto_name); +} + +static ssize_t block_show(struct gdlm_ls *ls, char *buf) +{ + ssize_t ret; + int val = 0; + + if (test_bit(DFL_BLOCK_LOCKS, &ls->flags)) + val = 1; + ret = sprintf(buf, "%d\n", val); + return ret; +} + +static ssize_t block_store(struct gdlm_ls *ls, const char *buf, size_t len) +{ + ssize_t ret = len; + int val; + + val = simple_strtol(buf, NULL, 0); + + if (val == 1) + set_bit(DFL_BLOCK_LOCKS, &ls->flags); + else if (val == 0) { + clear_bit(DFL_BLOCK_LOCKS, &ls->flags); + gdlm_submit_delayed(ls); + } else { + ret = -EINVAL; + } + return ret; +} + +static ssize_t withdraw_show(struct gdlm_ls *ls, char *buf) +{ + ssize_t ret; + int val = 0; + + if (test_bit(DFL_WITHDRAW, &ls->flags)) + val = 1; + ret = sprintf(buf, "%d\n", val); + return ret; +} + +static ssize_t withdraw_store(struct gdlm_ls *ls, const char *buf, size_t len) +{ + ssize_t ret = len; + int val; + + val = simple_strtol(buf, NULL, 0); + + if (val == 1) + set_bit(DFL_WITHDRAW, &ls->flags); + else + ret = -EINVAL; + wake_up(&ls->wait_control); + return ret; +} + +static ssize_t id_show(struct gdlm_ls *ls, char *buf) +{ + return sprintf(buf, "%u\n", ls->id); +} + +static ssize_t jid_show(struct gdlm_ls *ls, char *buf) +{ + return sprintf(buf, "%d\n", ls->jid); +} + +static ssize_t first_show(struct gdlm_ls *ls, char *buf) +{ + return sprintf(buf, "%d\n", ls->first); +} + +static ssize_t first_done_show(struct gdlm_ls *ls, char *buf) +{ + return sprintf(buf, "%d\n", ls->first_done); +} + +static ssize_t recover_show(struct gdlm_ls *ls, char *buf) +{ + return sprintf(buf, "%d\n", ls->recover_jid); +} + +static ssize_t recover_store(struct gdlm_ls *ls, const char *buf, size_t len) +{ + ls->recover_jid = simple_strtol(buf, NULL, 0); + ls->fscb(ls->sdp, LM_CB_NEED_RECOVERY, &ls->recover_jid); + return len; +} + +static ssize_t recover_done_show(struct gdlm_ls *ls, char *buf) +{ + return sprintf(buf, "%d\n", ls->recover_jid_done); +} + +static ssize_t recover_status_show(struct gdlm_ls *ls, char *buf) +{ + return sprintf(buf, "%d\n", ls->recover_jid_status); +} + +static ssize_t drop_count_show(struct gdlm_ls *ls, char *buf) +{ + return sprintf(buf, "%d\n", ls->drop_locks_count); +} + +static ssize_t drop_count_store(struct gdlm_ls *ls, const char *buf, size_t len) +{ + ls->drop_locks_count = simple_strtol(buf, NULL, 0); + return len; +} + +struct gdlm_attr { + struct attribute attr; + ssize_t (*show)(struct gdlm_ls *, char *); + ssize_t (*store)(struct gdlm_ls *, const char *, size_t); +}; + +#define GDLM_ATTR(_name,_mode,_show,_store) \ +static struct gdlm_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store) + +GDLM_ATTR(proto_name, 0444, proto_name_show, NULL); +GDLM_ATTR(block, 0644, block_show, block_store); +GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store); +GDLM_ATTR(id, 0444, id_show, NULL); +GDLM_ATTR(jid, 0444, jid_show, NULL); +GDLM_ATTR(first, 0444, first_show, NULL); +GDLM_ATTR(first_done, 0444, first_done_show, NULL); +GDLM_ATTR(recover, 0644, recover_show, recover_store); +GDLM_ATTR(recover_done, 0444, recover_done_show, NULL); +GDLM_ATTR(recover_status, 0444, recover_status_show, NULL); +GDLM_ATTR(drop_count, 0644, drop_count_show, drop_count_store); + +static struct attribute *gdlm_attrs[] = { + &gdlm_attr_proto_name.attr, + &gdlm_attr_block.attr, + &gdlm_attr_withdraw.attr, + &gdlm_attr_id.attr, + &gdlm_attr_jid.attr, + &gdlm_attr_first.attr, + &gdlm_attr_first_done.attr, + &gdlm_attr_recover.attr, + &gdlm_attr_recover_done.attr, + &gdlm_attr_recover_status.attr, + &gdlm_attr_drop_count.attr, + NULL, +}; + +static ssize_t gdlm_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct gdlm_ls *ls = container_of(kobj, struct gdlm_ls, kobj); + struct gdlm_attr *a = container_of(attr, struct gdlm_attr, attr); + return a->show ? a->show(ls, buf) : 0; +} + +static ssize_t gdlm_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t len) +{ + struct gdlm_ls *ls = container_of(kobj, struct gdlm_ls, kobj); + struct gdlm_attr *a = container_of(attr, struct gdlm_attr, attr); + return a->store ? a->store(ls, buf, len) : len; +} + +static struct sysfs_ops gdlm_attr_ops = { + .show = gdlm_attr_show, + .store = gdlm_attr_store, +}; + +static struct kobj_type gdlm_ktype = { + .default_attrs = gdlm_attrs, + .sysfs_ops = &gdlm_attr_ops, +}; + +static struct kset *gdlm_kset; + +int gdlm_kobject_setup(struct gdlm_ls *ls, struct kobject *fskobj) +{ + int error; + + ls->kobj.kset = gdlm_kset; + error = kobject_init_and_add(&ls->kobj, &gdlm_ktype, fskobj, + "lock_module"); + if (error) + log_error("can't register kobj %d", error); + kobject_uevent(&ls->kobj, KOBJ_ADD); + + return error; +} + +void gdlm_kobject_release(struct gdlm_ls *ls) +{ + kobject_put(&ls->kobj); +} + +int gdlm_sysfs_init(void) +{ + gdlm_kset = kset_create_and_add("lock_dlm_gfs", NULL, kernel_kobj); + if (!gdlm_kset) { + printk(KERN_WARNING "%s: can not create kset\n", __FUNCTION__); + return -ENOMEM; + } + return 0; +} + +void gdlm_sysfs_exit(void) +{ + kset_unregister(gdlm_kset); +} + --- linux-2.6.27.orig/ubuntu/gfs/lock_dlm_lock.c +++ linux-2.6.27/ubuntu/gfs/lock_dlm_lock.c @@ -0,0 +1,527 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License version 2. + */ + +#include "lock_dlm.h" + +static char junk_lvb[GDLM_LVB_SIZE]; + +static void queue_complete(struct gdlm_lock *lp) +{ + struct gdlm_ls *ls = lp->ls; + + clear_bit(LFL_ACTIVE, &lp->flags); + + spin_lock(&ls->async_lock); + list_add_tail(&lp->clist, &ls->complete); + spin_unlock(&ls->async_lock); + wake_up(&ls->thread_wait); +} + +static inline void gdlm_ast(void *astarg) +{ + queue_complete(astarg); +} + +static inline void gdlm_bast(void *astarg, int mode) +{ + struct gdlm_lock *lp = astarg; + struct gdlm_ls *ls = lp->ls; + + if (!mode) { + printk(KERN_INFO "lock_dlm: bast mode zero %x,%llx\n", + lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number); + return; + } + + spin_lock(&ls->async_lock); + if (!lp->bast_mode) { + list_add_tail(&lp->blist, &ls->blocking); + lp->bast_mode = mode; + } else if (lp->bast_mode < mode) + lp->bast_mode = mode; + spin_unlock(&ls->async_lock); + wake_up(&ls->thread_wait); +} + +void gdlm_queue_delayed(struct gdlm_lock *lp) +{ + struct gdlm_ls *ls = lp->ls; + + spin_lock(&ls->async_lock); + list_add_tail(&lp->delay_list, &ls->delayed); + spin_unlock(&ls->async_lock); +} + +/* convert gfs lock-state to dlm lock-mode */ + +static s16 make_mode(s16 lmstate) +{ + switch (lmstate) { + case LM_ST_UNLOCKED: + return DLM_LOCK_NL; + case LM_ST_EXCLUSIVE: + return DLM_LOCK_EX; + case LM_ST_DEFERRED: + return DLM_LOCK_CW; + case LM_ST_SHARED: + return DLM_LOCK_PR; + } + gdlm_assert(0, "unknown LM state %d", lmstate); + return -1; +} + +/* convert dlm lock-mode to gfs lock-state */ + +s16 gdlm_make_lmstate(s16 dlmmode) +{ + switch (dlmmode) { + case DLM_LOCK_IV: + case DLM_LOCK_NL: + return LM_ST_UNLOCKED; + case DLM_LOCK_EX: + return LM_ST_EXCLUSIVE; + case DLM_LOCK_CW: + return LM_ST_DEFERRED; + case DLM_LOCK_PR: + return LM_ST_SHARED; + } + gdlm_assert(0, "unknown DLM mode %d", dlmmode); + return -1; +} + +/* verify agreement with GFS on the current lock state, NB: DLM_LOCK_NL and + DLM_LOCK_IV are both considered LM_ST_UNLOCKED by GFS. */ + +static void check_cur_state(struct gdlm_lock *lp, unsigned int cur_state) +{ + s16 cur = make_mode(cur_state); + if (lp->cur != DLM_LOCK_IV) + gdlm_assert(lp->cur == cur, "%d, %d", lp->cur, cur); +} + +static inline unsigned int make_flags(struct gdlm_lock *lp, + unsigned int gfs_flags, + s16 cur, s16 req) +{ + unsigned int lkf = 0; + + if (gfs_flags & LM_FLAG_TRY) + lkf |= DLM_LKF_NOQUEUE; + + if (gfs_flags & LM_FLAG_TRY_1CB) { + lkf |= DLM_LKF_NOQUEUE; + lkf |= DLM_LKF_NOQUEUEBAST; + } + + if (gfs_flags & LM_FLAG_PRIORITY) { + lkf |= DLM_LKF_NOORDER; + lkf |= DLM_LKF_HEADQUE; + } + + if (gfs_flags & LM_FLAG_ANY) { + if (req == DLM_LOCK_PR) + lkf |= DLM_LKF_ALTCW; + else if (req == DLM_LOCK_CW) + lkf |= DLM_LKF_ALTPR; + } + + if (lp->lksb.sb_lkid != 0) { + lkf |= DLM_LKF_CONVERT; + + /* Conversion deadlock avoidance by DLM */ + + if (!test_bit(LFL_FORCE_PROMOTE, &lp->flags) && + !(lkf & DLM_LKF_NOQUEUE) && + cur > DLM_LOCK_NL && req > DLM_LOCK_NL && cur != req) + lkf |= DLM_LKF_CONVDEADLK; + } + + if (lp->lvb) + lkf |= DLM_LKF_VALBLK; + + return lkf; +} + +/* make_strname - convert GFS lock numbers to a string */ + +static inline void make_strname(const struct lm_lockname *lockname, + struct gdlm_strname *str) +{ + sprintf(str->name, "%8x%16llx", lockname->ln_type, + (unsigned long long)lockname->ln_number); + str->namelen = GDLM_STRNAME_BYTES; +} + +static int gdlm_create_lp(struct gdlm_ls *ls, struct lm_lockname *name, + struct gdlm_lock **lpp) +{ + struct gdlm_lock *lp; + + lp = kzalloc(sizeof(struct gdlm_lock), GFP_NOFS); + if (!lp) + return -ENOMEM; + + lp->lockname = *name; + make_strname(name, &lp->strname); + lp->ls = ls; + lp->cur = DLM_LOCK_IV; + lp->lvb = NULL; + lp->hold_null = NULL; + INIT_LIST_HEAD(&lp->clist); + INIT_LIST_HEAD(&lp->blist); + INIT_LIST_HEAD(&lp->delay_list); + + spin_lock(&ls->async_lock); + list_add(&lp->all_list, &ls->all_locks); + ls->all_locks_count++; + spin_unlock(&ls->async_lock); + + *lpp = lp; + return 0; +} + +void gdlm_delete_lp(struct gdlm_lock *lp) +{ + struct gdlm_ls *ls = lp->ls; + + spin_lock(&ls->async_lock); + if (!list_empty(&lp->clist)) + list_del_init(&lp->clist); + if (!list_empty(&lp->blist)) + list_del_init(&lp->blist); + if (!list_empty(&lp->delay_list)) + list_del_init(&lp->delay_list); + gdlm_assert(!list_empty(&lp->all_list), "%x,%llx", lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number); + list_del_init(&lp->all_list); + ls->all_locks_count--; + spin_unlock(&ls->async_lock); + + kfree(lp); +} + +int gdlm_get_lock(void *lockspace, struct lm_lockname *name, + void **lockp) +{ + struct gdlm_lock *lp; + int error; + + error = gdlm_create_lp(lockspace, name, &lp); + + *lockp = lp; + return error; +} + +void gdlm_put_lock(void *lock) +{ + gdlm_delete_lp(lock); +} + +unsigned int gdlm_do_lock(struct gdlm_lock *lp) +{ + struct gdlm_ls *ls = lp->ls; + int error, bast = 1; + + /* + * When recovery is in progress, delay lock requests for submission + * once recovery is done. Requests for recovery (NOEXP) and unlocks + * can pass. + */ + + if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) && + !test_bit(LFL_NOBLOCK, &lp->flags) && lp->req != DLM_LOCK_NL) { + gdlm_queue_delayed(lp); + return LM_OUT_ASYNC; + } + + /* + * Submit the actual lock request. + */ + + if (test_bit(LFL_NOBAST, &lp->flags)) + bast = 0; + + set_bit(LFL_ACTIVE, &lp->flags); + + log_debug("lk %x,%llx id %x %d,%d %x", lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number, lp->lksb.sb_lkid, + lp->cur, lp->req, lp->lkf); + + error = dlm_lock(ls->dlm_lockspace, lp->req, &lp->lksb, lp->lkf, + lp->strname.name, lp->strname.namelen, 0, gdlm_ast, + lp, bast ? gdlm_bast : NULL); + + if ((error == -EAGAIN) && (lp->lkf & DLM_LKF_NOQUEUE)) { + lp->lksb.sb_status = -EAGAIN; + queue_complete(lp); + error = 0; + } + + if (error) { + log_error("%s: gdlm_lock %x,%llx err=%d cur=%d req=%d lkf=%x " + "flags=%lx", ls->fsname, lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number, error, + lp->cur, lp->req, lp->lkf, lp->flags); + return LM_OUT_ERROR; + } + return LM_OUT_ASYNC; +} + +static unsigned int gdlm_do_unlock(struct gdlm_lock *lp) +{ + struct gdlm_ls *ls = lp->ls; + unsigned int lkf = 0; + int error; + + set_bit(LFL_DLM_UNLOCK, &lp->flags); + set_bit(LFL_ACTIVE, &lp->flags); + + if (lp->lvb) + lkf = DLM_LKF_VALBLK; + + log_debug("un %x,%llx %x %d %x", lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number, + lp->lksb.sb_lkid, lp->cur, lkf); + + error = dlm_unlock(ls->dlm_lockspace, lp->lksb.sb_lkid, lkf, NULL, lp); + + if (error) { + log_error("%s: gdlm_unlock %x,%llx err=%d cur=%d req=%d lkf=%x " + "flags=%lx", ls->fsname, lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number, error, + lp->cur, lp->req, lp->lkf, lp->flags); + return LM_OUT_ERROR; + } + return LM_OUT_ASYNC; +} + +unsigned int gdlm_lock(void *lock, unsigned int cur_state, + unsigned int req_state, unsigned int flags) +{ + struct gdlm_lock *lp = lock; + + clear_bit(LFL_DLM_CANCEL, &lp->flags); + if (flags & LM_FLAG_NOEXP) + set_bit(LFL_NOBLOCK, &lp->flags); + + check_cur_state(lp, cur_state); + lp->req = make_mode(req_state); + lp->lkf = make_flags(lp, flags, lp->cur, lp->req); + + return gdlm_do_lock(lp); +} + +unsigned int gdlm_unlock(void *lock, unsigned int cur_state) +{ + struct gdlm_lock *lp = lock; + + clear_bit(LFL_DLM_CANCEL, &lp->flags); + if (lp->cur == DLM_LOCK_IV) + return 0; + return gdlm_do_unlock(lp); +} + +void gdlm_cancel(void *lock) +{ + struct gdlm_lock *lp = lock; + struct gdlm_ls *ls = lp->ls; + int error, delay_list = 0; + + if (test_bit(LFL_DLM_CANCEL, &lp->flags)) + return; + + log_info("gdlm_cancel %x,%llx flags %lx", lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number, lp->flags); + + spin_lock(&ls->async_lock); + if (!list_empty(&lp->delay_list)) { + list_del_init(&lp->delay_list); + delay_list = 1; + } + spin_unlock(&ls->async_lock); + + if (delay_list) { + set_bit(LFL_CANCEL, &lp->flags); + set_bit(LFL_ACTIVE, &lp->flags); + queue_complete(lp); + return; + } + + if (!test_bit(LFL_ACTIVE, &lp->flags) || + test_bit(LFL_DLM_UNLOCK, &lp->flags)) { + log_info("gdlm_cancel skip %x,%llx flags %lx", + lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number, lp->flags); + return; + } + + /* the lock is blocked in the dlm */ + + set_bit(LFL_DLM_CANCEL, &lp->flags); + set_bit(LFL_ACTIVE, &lp->flags); + + error = dlm_unlock(ls->dlm_lockspace, lp->lksb.sb_lkid, DLM_LKF_CANCEL, + NULL, lp); + + log_info("gdlm_cancel rv %d %x,%llx flags %lx", error, + lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number, lp->flags); + + if (error == -EBUSY) + clear_bit(LFL_DLM_CANCEL, &lp->flags); +} + +static int gdlm_add_lvb(struct gdlm_lock *lp) +{ + char *lvb; + + lvb = kzalloc(GDLM_LVB_SIZE, GFP_NOFS); + if (!lvb) + return -ENOMEM; + + lp->lksb.sb_lvbptr = lvb; + lp->lvb = lvb; + return 0; +} + +static void gdlm_del_lvb(struct gdlm_lock *lp) +{ + kfree(lp->lvb); + lp->lvb = NULL; + lp->lksb.sb_lvbptr = NULL; +} + +static int gdlm_ast_wait(void *word) +{ + schedule(); + return 0; +} + +/* This can do a synchronous dlm request (requiring a lock_dlm thread to get + the completion) because gfs won't call hold_lvb() during a callback (from + the context of a lock_dlm thread). */ + +static int hold_null_lock(struct gdlm_lock *lp) +{ + struct gdlm_lock *lpn = NULL; + int error; + + if (lp->hold_null) { + printk(KERN_INFO "lock_dlm: lvb already held\n"); + return 0; + } + + error = gdlm_create_lp(lp->ls, &lp->lockname, &lpn); + if (error) + goto out; + + lpn->lksb.sb_lvbptr = junk_lvb; + lpn->lvb = junk_lvb; + + lpn->req = DLM_LOCK_NL; + lpn->lkf = DLM_LKF_VALBLK | DLM_LKF_EXPEDITE; + set_bit(LFL_NOBAST, &lpn->flags); + set_bit(LFL_INLOCK, &lpn->flags); + set_bit(LFL_AST_WAIT, &lpn->flags); + + gdlm_do_lock(lpn); + wait_on_bit(&lpn->flags, LFL_AST_WAIT, gdlm_ast_wait, TASK_UNINTERRUPTIBLE); + error = lpn->lksb.sb_status; + if (error) { + printk(KERN_INFO "lock_dlm: hold_null_lock dlm error %d\n", + error); + gdlm_delete_lp(lpn); + lpn = NULL; + } +out: + lp->hold_null = lpn; + return error; +} + +/* This cannot do a synchronous dlm request (requiring a lock_dlm thread to get + the completion) because gfs may call unhold_lvb() during a callback (from + the context of a lock_dlm thread) which could cause a deadlock since the + other lock_dlm thread could be engaged in recovery. */ + +static void unhold_null_lock(struct gdlm_lock *lp) +{ + struct gdlm_lock *lpn = lp->hold_null; + + gdlm_assert(lpn, "%x,%llx", lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number); + lpn->lksb.sb_lvbptr = NULL; + lpn->lvb = NULL; + set_bit(LFL_UNLOCK_DELETE, &lpn->flags); + gdlm_do_unlock(lpn); + lp->hold_null = NULL; +} + +/* Acquire a NL lock because gfs requires the value block to remain + intact on the resource while the lvb is "held" even if it's holding no locks + on the resource. */ + +int gdlm_hold_lvb(void *lock, char **lvbp) +{ + struct gdlm_lock *lp = lock; + int error; + + error = gdlm_add_lvb(lp); + if (error) + return error; + + *lvbp = lp->lvb; + + error = hold_null_lock(lp); + if (error) + gdlm_del_lvb(lp); + + return error; +} + +void gdlm_unhold_lvb(void *lock, char *lvb) +{ + struct gdlm_lock *lp = lock; + + unhold_null_lock(lp); + gdlm_del_lvb(lp); +} + +void gdlm_submit_delayed(struct gdlm_ls *ls) +{ + struct gdlm_lock *lp, *safe; + + spin_lock(&ls->async_lock); + list_for_each_entry_safe(lp, safe, &ls->delayed, delay_list) { + list_del_init(&lp->delay_list); + list_add_tail(&lp->delay_list, &ls->submit); + } + spin_unlock(&ls->async_lock); + wake_up(&ls->thread_wait); +} + +int gdlm_release_all_locks(struct gdlm_ls *ls) +{ + struct gdlm_lock *lp, *safe; + int count = 0; + + spin_lock(&ls->async_lock); + list_for_each_entry_safe(lp, safe, &ls->all_locks, all_list) { + list_del_init(&lp->all_list); + + if (lp->lvb && lp->lvb != junk_lvb) + kfree(lp->lvb); + kfree(lp); + count++; + } + spin_unlock(&ls->async_lock); + + return count; +} + --- linux-2.6.27.orig/ubuntu/gfs/util.h +++ linux-2.6.27/ubuntu/gfs/util.h @@ -0,0 +1,330 @@ +#ifndef __UTIL_DOT_H__ +#define __UTIL_DOT_H__ + + +/* Utility functions */ + +extern uint32_t gfs_random_number; +uint32_t gfs_random(void); + +uint32_t gfs_hash(const void *data, unsigned int len); +uint32_t gfs_hash_more(const void *data, unsigned int len, uint32_t hash); + +void gfs_sort(void *base, unsigned int num_elem, unsigned int size, + int (*compar) (const void *, const void *)); + + +/* Error handling */ + +/** + * gfs_assert - Cause the machine to panic if @assertion is false + * @sdp: + * @assertion: + * @todo: + * + */ + +void gfs_assert_i(struct gfs_sbd *sdp, + char *assertion, + const char *function, + char *file, unsigned int line) +__attribute__ ((noreturn)); +#define gfs_assert(sdp, assertion, todo) \ +do { \ + if (unlikely(!(assertion))) { \ + {todo} \ + gfs_assert_i((sdp), #assertion, \ + __FUNCTION__, __FILE__, __LINE__); \ + } \ +} while (0) + +/** + * gfs_assert_withdraw - Cause the machine to withdraw if @assertion is false + * @sdp: + * @assertion: + * + * Returns: 0 if things are ok, + * -1 if this call withdrew the machine, + * -2 if it was already withdrawn + */ + +int gfs_assert_withdraw_i(struct gfs_sbd *sdp, + char *assertion, + const char *function, + char *file, unsigned int line); +#define gfs_assert_withdraw(sdp, assertion) \ +((likely(assertion)) ? 0 : \ + gfs_assert_withdraw_i((sdp), #assertion, \ + __FUNCTION__, __FILE__, __LINE__)) + +/** + * gfs_assert_warn - Print a message to the console if @assertion is false + * @sdp: + * @assertion: + * + * Returns: 0 if things are ok, + * -1 if we printed something + * -2 if we didn't + */ + +int gfs_assert_warn_i(struct gfs_sbd *sdp, + char *assertion, + const char *function, + char *file, unsigned int line); +#define gfs_assert_warn(sdp, assertion) \ +((likely(assertion)) ? 0 : \ + gfs_assert_warn_i((sdp), #assertion, \ + __FUNCTION__, __FILE__, __LINE__)) + +/** + * gfs_consist - Flag a filesystem consistency error and withdraw + * gfs_cconsist - Flag a filesystem consistency error and withdraw cluster + * @sdp: + * + * Returns: -1 if this call withdrew the machine, + * 0 if it was already withdrawn + */ + +int gfs_consist_i(struct gfs_sbd *sdp, int cluster_wide, + const char *function, + char *file, unsigned int line); +#define gfs_consist(sdp)\ +gfs_consist_i((sdp), FALSE, __FUNCTION__, __FILE__, __LINE__) +#define gfs_cconsist(sdp)\ +gfs_consist_i((sdp), TRUE, __FUNCTION__, __FILE__, __LINE__) + +/** + * gfs_consist_inode - Flag an inode consistency error and withdraw + * gfs_cconsist_inode - Flag an inode consistency error and withdraw cluster + * @ip: + * + * Returns: -1 if this call withdrew the machine, + * 0 if it was already withdrawn + */ + +int gfs_consist_inode_i(struct gfs_inode *ip, int cluster_wide, + const char *function, + char *file, unsigned int line); +#define gfs_consist_inode(ip) \ +gfs_consist_inode_i((ip), FALSE, __FUNCTION__, __FILE__, __LINE__) +#define gfs_cconsist_inode(ip) \ +gfs_consist_inode_i((ip), TRUE, __FUNCTION__, __FILE__, __LINE__) + +/** + * gfs_consist_rgrpd - Flag a RG consistency error and withdraw + * gfs_cconsist_rgrpd - Flag a RG consistency error and withdraw cluster + * @rgd: + * + * Returns: -1 if this call withdrew the machine, + * 0 if it was already withdrawn + */ + +int gfs_consist_rgrpd_i(struct gfs_rgrpd *rgd, int cluster_wide, + const char *function, + char *file, unsigned int line); +#define gfs_consist_rgrpd(rgd) \ +gfs_consist_rgrpd_i((rgd), FALSE, __FUNCTION__, __FILE__, __LINE__) +#define gfs_cconsist_rgrpd(rgd) \ +gfs_consist_rgrpd_i((rgd), TRUE, __FUNCTION__, __FILE__, __LINE__) + +/** + * gfs_meta_check - Flag a magic number consistency error and withdraw + * @sdp: + * @bh: + * + * Returns: 0 if things are ok, + * -1 if this call withdrew the machine, + * -2 if it was already withdrawn + */ + +int gfs_meta_check_ii(struct gfs_sbd *sdp, struct buffer_head *bh, + const char *function, + char *file, unsigned int line); +static __inline__ int +gfs_meta_check_i(struct gfs_sbd *sdp, struct buffer_head *bh, + const char *function, + char *file, unsigned int line) +{ + uint32_t magic; + magic = ((struct gfs_meta_header *)(bh)->b_data)->mh_magic; + magic = gfs32_to_cpu(magic); + if (likely(magic == GFS_MAGIC)) + return 0; + return gfs_meta_check_ii(sdp, bh, function, file, line); +} +#define gfs_meta_check(sdp, bh) \ +gfs_meta_check_i((sdp), (bh), \ + __FUNCTION__, __FILE__, __LINE__) + +/** + * gfs_metatype_check - Flag a metadata type consistency error and withdraw + * @sdp: + * @bh: + * @type: + * + * Returns: 0 if things are ok, + * -1 if this call withdrew the machine, + * -2 if it was already withdrawn + */ + +int gfs_metatype_check_ii(struct gfs_sbd *sdp, struct buffer_head *bh, + uint32_t type, uint32_t t, + const char *function, + char *file, unsigned int line); +static __inline__ int +gfs_metatype_check_i(struct gfs_sbd *sdp, struct buffer_head *bh, + uint32_t type, + const char *function, + char *file, unsigned int line) +{ + uint32_t magic, t; + magic = ((struct gfs_meta_header *)(bh)->b_data)->mh_magic; + magic = gfs32_to_cpu(magic); + if (unlikely(magic != GFS_MAGIC)) + return gfs_meta_check_ii(sdp, bh, function, file, line); + t = ((struct gfs_meta_header *)(bh)->b_data)->mh_type; + t = gfs32_to_cpu(t); + if (unlikely(t != type)) + return gfs_metatype_check_ii(sdp, bh, type, t, function, file, line); + return 0; +} +#define gfs_metatype_check(sdp, bh, type) \ +gfs_metatype_check_i((sdp), (bh), (type), \ + __FUNCTION__, __FILE__, __LINE__) + +/** + * gfs_metatype_check2 - Flag a metadata type consistency error and withdraw + * @sdp: + * @bh: + * @type1: + * @type2: + * + * Returns: 0 if things are ok, + * -1 if this call withdrew the machine, + * -2 if it was already withdrawn + */ + +static __inline__ int +gfs_metatype_check2_i(struct gfs_sbd *sdp, struct buffer_head *bh, + uint32_t type1, uint32_t type2, + const char *function, + char *file, unsigned int line) +{ + uint32_t magic, t; + magic = ((struct gfs_meta_header *)(bh)->b_data)->mh_magic; + magic = gfs32_to_cpu(magic); + if (unlikely(magic != GFS_MAGIC)) + return gfs_meta_check_ii(sdp, bh, function, file, line); + t = ((struct gfs_meta_header *)(bh)->b_data)->mh_type; + t = gfs32_to_cpu(t); + if (unlikely(t != type1 && t != type2)) + return gfs_metatype_check_ii(sdp, bh, type1, t, function, file, line); + return 0; +} +#define gfs_metatype_check2(sdp, bh, type1, type2) \ +gfs_metatype_check2_i((sdp), (bh), (type1), (type2), \ + __FUNCTION__, __FILE__, __LINE__) + +/** + * gfs_metatype_set - set the metadata type on a buffer + * @bh: + * @type: + * @format: + * + */ + +static __inline__ void +gfs_metatype_set(struct buffer_head *bh, uint32_t type, uint32_t format) +{ + struct gfs_meta_header *mh; + mh = (struct gfs_meta_header *)bh->b_data; + mh->mh_type = cpu_to_gfs32(type); + mh->mh_format = cpu_to_gfs32(format); +} + +/** + * gfs_io_error - Flag an I/O error and withdraw + * @sdp: + * + * Returns: -1 if this call withdrew the machine, + * 0 if it was already withdrawn + */ + +int gfs_io_error_i(struct gfs_sbd *sdp, + const char *function, + char *file, unsigned int line); +#define gfs_io_error(sdp) \ +gfs_io_error_i((sdp), __FUNCTION__, __FILE__, __LINE__); + +/** + * gfs_io_error_inode - Flag an inode I/O error and withdraw + * @ip: + * + * Returns: -1 if this call withdrew the machine, + * 0 if it was already withdrawn + */ + +int gfs_io_error_inode_i(struct gfs_inode *ip, + const char *function, + char *file, unsigned int line); +#define gfs_io_error_inode(ip) \ +gfs_io_error_inode_i((ip), __FUNCTION__, __FILE__, __LINE__); + +/** + * gfs_io_error_bh - Flag a buffer I/O error and withdraw + * @sdp: + * @bh: + * + * Returns: -1 if this call withdrew the machine, + * 0 if it was already withdrawn + */ + +int gfs_io_error_bh_i(struct gfs_sbd *sdp, struct buffer_head *bh, + const char *function, + char *file, unsigned int line); +#define gfs_io_error_bh(sdp, bh) \ +gfs_io_error_bh_i((sdp), (bh), __FUNCTION__, __FILE__, __LINE__); + + +/* Memory stuff */ + +#define RETRY_MALLOC(do_this, until_this) \ +for (;;) { \ + { do_this; } \ + if (until_this) \ + break; \ + printk("GFS: out of memory: %s, %u\n", __FILE__, __LINE__); \ + dump_stack(); \ + yield(); \ +} + +extern struct kmem_cache *gfs_glock_cachep; +extern struct kmem_cache *gfs_inode_cachep; +extern struct kmem_cache *gfs_bufdata_cachep; +extern struct kmem_cache *gfs_mhc_cachep; + +void *gmalloc(unsigned int size); + + +struct gfs_user_buffer { + char *ub_data; + unsigned int ub_size; + unsigned int ub_count; +}; +int gfs_add_bh_to_ub(struct gfs_user_buffer *ub, struct buffer_head *bh); + + +static __inline__ unsigned int +gfs_tune_get_i(struct gfs_tune *gt, unsigned int *p) +{ + unsigned int x; + spin_lock(>->gt_spin); + x = *p; + spin_unlock(>->gt_spin); + return x; +} +#define gfs_tune_get(sdp, field) \ +gfs_tune_get_i(&(sdp)->sd_tune, &(sdp)->sd_tune.field) + + +#endif /* __UTIL_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/lock_dlm_main.c +++ linux-2.6.27/ubuntu/gfs/lock_dlm_main.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License version 2. + */ + +#include + +#include "lock_dlm.h" + +int init_lock_dlm() +{ + int error; + + error = gfs_register_lockproto(&gdlm_ops); + if (error) { + printk(KERN_WARNING "lock_dlm: can't register protocol: %d\n", + error); + return error; + } + + error = gdlm_sysfs_init(); + if (error) { + gfs_unregister_lockproto(&gdlm_ops); + return error; + } + + printk(KERN_INFO + "Lock_DLM (built %s %s) installed\n", __DATE__, __TIME__); + return 0; +} + +void exit_lock_dlm() +{ + gdlm_sysfs_exit(); + gfs_unregister_lockproto(&gdlm_ops); +} --- linux-2.6.27.orig/ubuntu/gfs/ops_super.h +++ linux-2.6.27/ubuntu/gfs/ops_super.h @@ -0,0 +1,6 @@ +#ifndef __OPS_SUPER_DOT_H__ +#define __OPS_SUPER_DOT_H__ + +extern struct super_operations gfs_super_ops; + +#endif /* __OPS_SUPER_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/acl.c +++ linux-2.6.27/ubuntu/gfs/acl.c @@ -0,0 +1,396 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "acl.h" +#include "eattr.h" +#include "inode.h" + +/** + * gfs_acl_validate_set - + * @ip: + * @access: + * @er: + * @mode: + * @remove: + * + * Returns: errno + */ + +int +gfs_acl_validate_set(struct gfs_inode *ip, int access, + struct gfs_ea_request *er, + int *remove, mode_t *mode) +{ + struct posix_acl *acl; + int error; + + error = gfs_acl_validate_remove(ip, access); + if (error) + return error; + + if (!er->er_data) + return -EINVAL; + + acl = posix_acl_from_xattr(er->er_data, er->er_data_len); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (!acl) { + *remove = TRUE; + return 0; + } + + error = posix_acl_valid(acl); + if (error) + goto out; + + if (access) { + error = posix_acl_equiv_mode(acl, mode); + if (!error) + *remove = TRUE; + else if (error > 0) + error = 0; + } + + out: + posix_acl_release(acl); + + return error; +} + +/** + * gfs_acl_validate_remove - + * @ip: + * @access: + * + * Returns: errno + */ + +int +gfs_acl_validate_remove(struct gfs_inode *ip, int access) +{ + if (!ip->i_sbd->sd_args.ar_posix_acls) + return -EOPNOTSUPP; + if (current->fsuid != ip->i_di.di_uid && !capable(CAP_FOWNER)) + return -EPERM; + if (ip->i_di.di_type == GFS_FILE_LNK) + return -EOPNOTSUPP; + if (!access && ip->i_di.di_type != GFS_FILE_DIR) + return -EACCES; + + return 0; +} + +/** + * gfs_acl_get - + * @ip: + * @access: + * @acl: + * + * Returns: errno + */ + +int +gfs_acl_get(struct gfs_inode *ip, int access, struct posix_acl **acl) +{ + struct gfs_ea_request er; + struct gfs_ea_location el; + int error; + + if (!ip->i_di.di_eattr) + return 0; + + memset(&er, 0, sizeof(struct gfs_ea_request)); + if (access) { + er.er_name = GFS_POSIX_ACL_ACCESS; + er.er_name_len = GFS_POSIX_ACL_ACCESS_LEN; + } else { + er.er_name = GFS_POSIX_ACL_DEFAULT; + er.er_name_len = GFS_POSIX_ACL_DEFAULT_LEN; + } + er.er_type = GFS_EATYPE_SYS; + + error = gfs_ea_find(ip, &er, &el); + if (error) + return error; + if (!el.el_ea) + return 0; + if (!GFS_EA_DATA_LEN(el.el_ea)) + goto out; + + er.er_data = kmalloc(GFS_EA_DATA_LEN(el.el_ea), GFP_KERNEL); + error = -ENOMEM; + if (!er.er_data) + goto out; + + error = gfs_ea_get_copy(ip, &el, er.er_data); + if (error) + goto out_kfree; + + *acl = posix_acl_from_xattr(er.er_data, GFS_EA_DATA_LEN(el.el_ea)); + if (IS_ERR(*acl)) + error = PTR_ERR(*acl); + + out_kfree: + kfree(er.er_data); + + out: + brelse(el.el_bh); + + return error; +} + +/** + * gfs_check_acl - Check an ACL for to see if we're allowed to do something + * @inode: the file we want to do something to + * @mask: what we want to do + * + * Returns: errno + */ + +int +gfs_check_acl(struct inode *inode, int mask) +{ + struct posix_acl *acl = NULL; + int error; + + error = gfs_acl_get(get_v2ip(inode), TRUE, &acl); + if (error) + return error; + + if (acl) { + error = posix_acl_permission(inode, acl, mask); + posix_acl_release(acl); + return error; + } + + return -EAGAIN; +} + +/** + * gfs_acl_new_prep - + * @dip: + * @type: + * @mode: + * @a_acl: + * @d_acl: + * @blocks: + * @data: + * + * Returns: errno + */ + +int +gfs_acl_new_prep(struct gfs_inode *dip, + unsigned int type, mode_t *mode, + void **a_data, void **d_data, + unsigned int *size, + unsigned int *blocks) +{ + struct posix_acl *acl = NULL; + int set_a = FALSE, set_d = FALSE; + int error; + + if (!dip->i_sbd->sd_args.ar_posix_acls) + return 0; + if (type == GFS_FILE_LNK) + return 0; + + error = gfs_acl_get(dip, FALSE, &acl); + if (error) + return error; + if (!acl) { + (*mode) &= ~current->fs->umask; + return 0; + } + + { + struct posix_acl *clone = posix_acl_clone(acl, GFP_KERNEL); + error = -ENOMEM; + if (!clone) + goto out; + posix_acl_release(acl); + acl = clone; + } + + error = posix_acl_create_masq(acl, mode); + if (error < 0) + goto out; + if (error > 0) { + set_a = TRUE; + error = 0; + } + if (type == GFS_FILE_DIR) + set_d = TRUE; + + if (set_a || set_d) { + struct gfs_ea_request er; + void *d; + unsigned int s = posix_acl_xattr_size(acl->a_count); + unsigned int b; + + memset(&er, 0, sizeof(struct gfs_ea_request)); + er.er_name_len = GFS_POSIX_ACL_DEFAULT_LEN; + er.er_data_len = s; + error = gfs_ea_check_size(dip->i_sbd, &er); + if (error) + goto out; + + b = DIV_RU(er.er_data_len, dip->i_sbd->sd_jbsize); + if (set_a && set_d) + b *= 2; + b++; + + d = kmalloc(s, GFP_KERNEL); + error = -ENOMEM; + if (!d) + goto out; + posix_acl_to_xattr(acl, d, s); + + if (set_a) + *a_data = d; + if (set_d) + *d_data = d; + *size = s; + *blocks = b; + + error = 0; + } + + out: + posix_acl_release(acl); + + return error; +} + +/** + * gfs_acl_new_init - + * @dip: + * @ip: + * @a_data: + * @d_data: + * @size: + * + * Returns: errno + */ + +int gfs_acl_new_init(struct gfs_inode *dip, struct gfs_inode *ip, + void *a_data, void *d_data, unsigned int size) +{ + void *data = (a_data) ? a_data : d_data; + unsigned int x; + int error = 0; + + ip->i_alloc = dip->i_alloc; /* Cheesy, but it works. */ + + for (x = 0; x < 2; x++) { + struct gfs_ea_request er; + + memset(&er, 0, sizeof(struct gfs_ea_request)); + if (x) { + if (!a_data) + continue; + er.er_name = GFS_POSIX_ACL_ACCESS; + er.er_name_len = GFS_POSIX_ACL_ACCESS_LEN; + } else { + if (!d_data) + continue; + er.er_name = GFS_POSIX_ACL_DEFAULT; + er.er_name_len = GFS_POSIX_ACL_DEFAULT_LEN; + } + er.er_data = data; + er.er_data_len = size; + er.er_type = GFS_EATYPE_SYS; + + error = gfs_ea_acl_init(ip, &er); + if (error) + break; + } + + ip->i_alloc = NULL; + + kfree(data); + + return error; +} + +/** + * gfs_acl_chmod - + * @ip: + * @attr: + * + * Returns: errno + */ + +int +gfs_acl_chmod(struct gfs_inode *ip, struct iattr *attr) +{ + struct gfs_ea_request er; + struct gfs_ea_location el; + struct posix_acl *acl; + int error; + + if (!ip->i_di.di_eattr) + goto simple; + + memset(&er, 0, sizeof(struct gfs_ea_request)); + er.er_name = GFS_POSIX_ACL_ACCESS; + er.er_name_len = GFS_POSIX_ACL_ACCESS_LEN; + er.er_type = GFS_EATYPE_SYS; + + error = gfs_ea_find(ip, &er, &el); + if (error) + return error; + if (!el.el_ea) + goto simple; + if (!GFS_EA_DATA_LEN(el.el_ea)) + goto simple; + + er.er_data = kmalloc(GFS_EA_DATA_LEN(el.el_ea), GFP_KERNEL); + error = -ENOMEM; + if (!er.er_data) + goto out; + + error = gfs_ea_get_copy(ip, &el, er.er_data); + if (error) + goto out_kfree; + + acl = posix_acl_from_xattr(er.er_data, GFS_EA_DATA_LEN(el.el_ea)); + if (IS_ERR(acl)) { + error = PTR_ERR(acl); + goto out_kfree; + } else if (!acl) { + kfree(er.er_data); + brelse(el.el_bh); + goto simple; + } + + error = posix_acl_chmod_masq(acl, attr->ia_mode); + if (error) + goto out_acl; + + posix_acl_to_xattr(acl, er.er_data, GFS_EA_DATA_LEN(el.el_ea)); + + error = gfs_ea_acl_chmod(ip, &el, attr, er.er_data); + + out_acl: + posix_acl_release(acl); + + out_kfree: + kfree(er.er_data); + + out: + brelse(el.el_bh); + + return error; + + simple: + return gfs_setattr_simple(ip, attr); +} --- linux-2.6.27.orig/ubuntu/gfs/bits.c +++ linux-2.6.27/ubuntu/gfs/bits.c @@ -0,0 +1,211 @@ +/* + * These routines are used by the resource group routines (rgrp.c) + * to keep track of block allocation. Each block is represented by two + * bits. One bit indicates whether or not the block is used. (1=used, + * 0=free) The other bit indicates whether or not the block contains a + * dinode or not. (1=dinode, 0=data block) So, each byte represents + * GFS_NBBY (i.e. 4) blocks. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "bits.h" + +#if BITS_PER_LONG == 32 +#define LBITMASK (0x55555555UL) +#define LBITSKIP55 (0x55555555UL) +#define LBITSKIP00 (0x00000000UL) +#else +#define LBITMASK (0x5555555555555555UL) +#define LBITSKIP55 (0x5555555555555555UL) +#define LBITSKIP00 (0x0000000000000000UL) +#endif + +static const char valid_change[16] = { + /* current */ + /* n */ 0, 1, 1, 1, + /* e */ 1, 0, 0, 0, + /* w */ 1, 0, 0, 1, + 0, 0, 1, 0 +}; + +/** + * gfs_setbit - Set a bit in the bitmaps + * @buffer: the buffer that holds the bitmaps + * @buflen: the length (in bytes) of the buffer + * @block: the block to set + * @new_state: the new state of the block + * + */ + +void +gfs_setbit(struct gfs_rgrpd *rgd, + unsigned char *buffer, unsigned int buflen, + uint32_t block, unsigned char new_state) +{ + unsigned char *byte, *end, cur_state; + unsigned int bit; + + byte = buffer + (block / GFS_NBBY); + bit = (block % GFS_NBBY) * GFS_BIT_SIZE; + end = buffer + buflen; + + gfs_assert(rgd->rd_sbd, byte < end,); + + cur_state = (*byte >> bit) & GFS_BIT_MASK; + + if (valid_change[new_state * 4 + cur_state]) { + *byte ^= cur_state << bit; + *byte |= new_state << bit; + } else + gfs_consist_rgrpd(rgd); +} + +/** + * gfs_testbit - test a bit in the bitmaps + * @buffer: the buffer that holds the bitmaps + * @buflen: the length (in bytes) of the buffer + * @block: the block to read + * + */ + +unsigned char +gfs_testbit(struct gfs_rgrpd *rgd, + unsigned char *buffer, unsigned int buflen, uint32_t block) +{ + unsigned char *byte, *end, cur_state; + unsigned int bit; + + byte = buffer + (block / GFS_NBBY); + bit = (block % GFS_NBBY) * GFS_BIT_SIZE; + end = buffer + buflen; + + gfs_assert(rgd->rd_sbd, byte < end,); + + cur_state = (*byte >> bit) & GFS_BIT_MASK; + + return cur_state; +} + +/** + * gfs_bitfit - Search an rgrp's bitmap buffer to find a bit-pair representing + * a block in a given allocation state. + * @buffer: the buffer that holds the bitmaps + * @buflen: the length (in bytes) of the buffer + * @goal: start search at this block's bit-pair (within @buffer) + * @old_state: GFS_BLKST_XXX the state of the block we're looking for; + * bit 0 = alloc(1)/free(0), bit 1 = meta(1)/data(0) + * + * Scope of @goal and returned block number is only within this bitmap buffer, + * not entire rgrp or filesystem. + * @buffer will be offset from the actual beginning of a bitmap block buffer, + * skipping any header structures. + * + * Return: the block number (bitmap buffer scope) that was found + */ + +uint32_t +gfs_bitfit(unsigned char *buffer, unsigned int buflen, + uint32_t goal, unsigned char old_state) +{ + const u8 *byte, *start, *end; + int bit, startbit; + u32 g1, g2, misaligned; + unsigned long *plong; + unsigned long lskipval; + + lskipval = (old_state & GFS_BLKST_USED) ? LBITSKIP00 : LBITSKIP55; + g1 = (goal / GFS_NBBY); + start = buffer + g1; + byte = start; + end = buffer + buflen; + g2 = ALIGN(g1, sizeof(unsigned long)); + plong = (unsigned long *)(buffer + g2); + startbit = bit = (goal % GFS_NBBY) * GFS_BIT_SIZE; + misaligned = g2 - g1; + if (!misaligned) + goto ulong_aligned; +/* parse the bitmap a byte at a time */ +misaligned: + while (byte < end) { + if (((*byte >> bit) & GFS_BIT_MASK) == old_state) { + return goal + + (((byte - start) * GFS_NBBY) + + ((bit - startbit) >> 1)); + } + bit += GFS_BIT_SIZE; + if (bit >= GFS_NBBY * GFS_BIT_SIZE) { + bit = 0; + byte++; + misaligned--; + if (!misaligned) { + plong = (unsigned long *)byte; + goto ulong_aligned; + } + } + } + return BFITNOENT; + +/* parse the bitmap a unsigned long at a time */ +ulong_aligned: + /* Stop at "end - 1" or else prefetch can go past the end and segfault. + We could "if" it but we'd lose some of the performance gained. + This way will only slow down searching the very last 4/8 bytes + depending on architecture. I've experimented with several ways + of writing this section such as using an else before the goto + but this one seems to be the fastest. */ + while ((unsigned char *)plong < end - sizeof(unsigned long)) { + prefetch(plong + 1); + if (((*plong) & LBITMASK) != lskipval) + break; + plong++; + } + if ((unsigned char *)plong < end) { + byte = (const u8 *)plong; + misaligned += sizeof(unsigned long) - 1; + goto misaligned; + } + return BFITNOENT; +} + +/** + * gfs_bitcount - count the number of bits in a certain state + * @buffer: the buffer that holds the bitmaps + * @buflen: the length (in bytes) of the buffer + * @state: the state of the block we're looking for + * + * Returns: The number of bits + */ + +uint32_t +gfs_bitcount(struct gfs_rgrpd *rgd, + unsigned char *buffer, unsigned int buflen, + unsigned char state) +{ + unsigned char *byte = buffer; + unsigned char *end = buffer + buflen; + unsigned char state1 = state << 2; + unsigned char state2 = state << 4; + unsigned char state3 = state << 6; + uint32_t count = 0; + + for (; byte < end; byte++) { + if (((*byte) & 0x03) == state) + count++; + if (((*byte) & 0x0C) == state1) + count++; + if (((*byte) & 0x30) == state2) + count++; + if (((*byte) & 0xC0) == state3) + count++; + } + + return count; +} --- linux-2.6.27.orig/ubuntu/gfs/proc.h +++ linux-2.6.27/ubuntu/gfs/proc.h @@ -0,0 +1,14 @@ +#ifndef __PROC_DOT_H__ +#define __PROC_DOT_H__ + +/* Allow args to be passed to GFS when using an initial ram disk */ +extern char *gfs_proc_margs; +extern spinlock_t gfs_proc_margs_lock; + +void gfs_proc_fs_add(struct gfs_sbd *sdp); +void gfs_proc_fs_del(struct gfs_sbd *sdp); + +int gfs_proc_init(void); +void gfs_proc_uninit(void); + +#endif /* __PROC_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/lops.h +++ linux-2.6.27/ubuntu/gfs/lops.h @@ -0,0 +1,166 @@ +#ifndef __LOPS_DOT_H__ +#define __LOPS_DOT_H__ + +extern struct gfs_log_operations gfs_glock_lops; +extern struct gfs_log_operations gfs_buf_lops; +extern struct gfs_log_operations gfs_unlinked_lops; +extern struct gfs_log_operations gfs_quota_lops; + +extern struct gfs_log_operations *gfs_log_ops[]; + +#define INIT_LE(le, lops) \ +do \ +{ \ + (le)->le_ops = (lops); \ + (le)->le_trans = NULL; \ + INIT_LIST_HEAD(&(le)->le_list); \ +} \ +while (0) + +#define LO_ADD(sdp, le) \ +do \ +{ \ + if ((le)->le_ops->lo_add) \ + (le)->le_ops->lo_add((sdp), (le)); \ +} \ +while (0) + +#define LO_TRANS_END(sdp, le) \ +do \ +{ \ + if ((le)->le_ops->lo_trans_end) \ + (le)->le_ops->lo_trans_end((sdp), (le)); \ +} \ +while (0) + +#define LO_PRINT(sdp, le, where) \ +do \ +{ \ + if ((le)->le_ops->lo_print) \ + (le)->le_ops->lo_print((sdp), (le), (where)); \ +} \ +while (0) + +static __inline__ struct gfs_trans * +LO_OVERLAP_TRANS(struct gfs_sbd *sdp, struct gfs_log_element *le) +{ + if (le->le_ops->lo_overlap_trans) + return le->le_ops->lo_overlap_trans(sdp, le); + else + return NULL; +} + +#define LO_INCORE_COMMIT(sdp, tr, le) \ +do \ +{ \ + if ((le)->le_ops->lo_incore_commit) \ + (le)->le_ops->lo_incore_commit((sdp), (tr), (le)); \ +} \ +while (0) + +#define LO_ADD_TO_AIL(sdp, le) \ +do \ +{ \ + if ((le)->le_ops->lo_add_to_ail) \ + (le)->le_ops->lo_add_to_ail((sdp), (le)); \ +} \ +while (0) + +#define LO_CLEAN_DUMP(sdp, le) \ +do \ +{ \ + if ((le)->le_ops->lo_clean_dump) \ + (le)->le_ops->lo_clean_dump((sdp), (le)); \ +} \ +while (0) + +#define LO_TRANS_SIZE(sdp, tr, mblks, eblks, blocks, bmem) \ +do \ +{ \ + int __lops_x; \ + for (__lops_x = 0; gfs_log_ops[__lops_x]; __lops_x++) \ + if (gfs_log_ops[__lops_x]->lo_trans_size) \ + gfs_log_ops[__lops_x]->lo_trans_size((sdp), (tr), (mblks), (eblks), (blocks), (bmem)); \ +} \ +while (0) + +#define LO_TRANS_COMBINE(sdp, tr, new_tr) \ +do \ +{ \ + int __lops_x; \ + for (__lops_x = 0; gfs_log_ops[__lops_x]; __lops_x++) \ + if (gfs_log_ops[__lops_x]->lo_trans_combine) \ + gfs_log_ops[__lops_x]->lo_trans_combine((sdp), (tr), (new_tr)); \ +} \ +while (0) + +#define LO_BUILD_BHLIST(sdp, tr) \ +do \ +{ \ + int __lops_x; \ + for (__lops_x = 0; gfs_log_ops[__lops_x]; __lops_x++) \ + if (gfs_log_ops[__lops_x]->lo_build_bhlist) \ + gfs_log_ops[__lops_x]->lo_build_bhlist((sdp), (tr)); \ +} \ +while (0) + +#define LO_DUMP_SIZE(sdp, elements, blocks, bmem) \ +do \ +{ \ + int __lops_x; \ + for (__lops_x = 0; gfs_log_ops[__lops_x]; __lops_x++) \ + if (gfs_log_ops[__lops_x]->lo_dump_size) \ + gfs_log_ops[__lops_x]->lo_dump_size((sdp), (elements), (blocks), (bmem)); \ +} \ +while (0) + +#define LO_BUILD_DUMP(sdp, tr) \ +do \ +{ \ + int __lops_x; \ + for (__lops_x = 0; gfs_log_ops[__lops_x]; __lops_x++) \ + if (gfs_log_ops[__lops_x]->lo_build_dump) \ + gfs_log_ops[__lops_x]->lo_build_dump((sdp), (tr)); \ +} \ +while (0) + +#define LO_BEFORE_SCAN(sdp, jid, head, pass) \ +do \ +{ \ + int __lops_x; \ + for (__lops_x = 0; gfs_log_ops[__lops_x]; __lops_x++) \ + if (gfs_log_ops[__lops_x]->lo_before_scan) \ + gfs_log_ops[__lops_x]->lo_before_scan((sdp), (jid), (head), (pass)); \ +} \ +while (0) + +static __inline__ int +LO_SCAN_ELEMENTS(struct gfs_sbd *sdp, struct gfs_jindex *jdesc, + struct gfs_glock *gl, uint64_t start, + struct gfs_log_descriptor *desc, unsigned int pass) +{ + int x; + int error; + + for (x = 0; gfs_log_ops[x]; x++) + if (gfs_log_ops[x]->lo_scan_elements) { + error = gfs_log_ops[x]->lo_scan_elements(sdp, jdesc, gl, + start, desc, pass); + if (error) + return error; + } + + return 0; +} + +#define LO_AFTER_SCAN(sdp, jid, pass) \ +do \ +{ \ + int __lops_x; \ + for (__lops_x = 0; gfs_log_ops[__lops_x]; __lops_x++) \ + if (gfs_log_ops[__lops_x]->lo_after_scan) \ + gfs_log_ops[__lops_x]->lo_after_scan((sdp), (jid), (pass)); \ +} \ +while (0) + +#endif /* __LOPS_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/file.h +++ linux-2.6.27/ubuntu/gfs/file.h @@ -0,0 +1,42 @@ +#ifndef __FILE_DOT_H__ +#define __FILE_DOT_H__ + +typedef int (*read_copy_fn_t) (struct buffer_head *bh, void **buf, + unsigned int offset, unsigned int size); +typedef int (*write_copy_fn_t) (struct gfs_inode *ip, struct buffer_head *bh, + void **buf, unsigned int offset, + unsigned int size, int new); + +int gfs_copy2mem(struct buffer_head *bh, void **buf, + unsigned int offset, unsigned int size); +int gfs_copy2user(struct buffer_head *bh, void **buf, + unsigned int offset, unsigned int size); +int gfs_readi(struct gfs_inode *ip, void *buf, uint64_t offset, + unsigned int size, read_copy_fn_t copy_fn); + +int gfs_copy_from_mem(struct gfs_inode *ip, struct buffer_head *bh, void **buf, + unsigned int offset, unsigned int size, int new); +int gfs_copy_from_user(struct gfs_inode *ip, struct buffer_head *bh, void **buf, + unsigned int offset, unsigned int size, int new); +int gfs_writei(struct gfs_inode *ip, void *buf, uint64_t offset, + unsigned int size, write_copy_fn_t copy_fn, + struct kiocb *iocb); + +int gfs_zero_blocks(struct gfs_inode *ip, struct buffer_head *bh, void **buf, + unsigned int offset, unsigned int size, int new); + +static __inline__ int +gfs_internal_read(struct gfs_inode *ip, char *buf, uint64_t offset, + unsigned int size) +{ + return gfs_readi(ip, buf, offset, size, gfs_copy2mem); +} + +static __inline__ int +gfs_internal_write(struct gfs_inode *ip, char *buf, uint64_t offset, + unsigned int size) +{ + return gfs_writei(ip, buf, offset, size, gfs_copy_from_mem, NULL); +} + +#endif /* __FILE_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/ops_export.h +++ linux-2.6.27/ubuntu/gfs/ops_export.h @@ -0,0 +1,6 @@ +#ifndef __OPS_EXPORT_DOT_H__ +#define __OPS_EXPORT_DOT_H__ + +extern const struct export_operations gfs_export_ops; + +#endif /* __OPS_EXPORT_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/bits.h +++ linux-2.6.27/ubuntu/gfs/bits.h @@ -0,0 +1,18 @@ +#ifndef __BITS_DOT_H__ +#define __BITS_DOT_H__ + +#define BFITNOENT (0xFFFFFFFF) + +void gfs_setbit(struct gfs_rgrpd *rgd, + unsigned char *buffer, unsigned int buflen, + uint32_t block, unsigned char new_state); +unsigned char gfs_testbit(struct gfs_rgrpd *rgd, + unsigned char *buffer, unsigned int buflen, + uint32_t block); +uint32_t gfs_bitfit(unsigned char *buffer, unsigned int buflen, + uint32_t goal, unsigned char old_state); +uint32_t gfs_bitcount(struct gfs_rgrpd *rgd, + unsigned char *buffer, unsigned int buflen, + unsigned char state); + +#endif /* __BITS_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/sys.h +++ linux-2.6.27/ubuntu/gfs/sys.h @@ -0,0 +1,14 @@ +#ifndef __SYS_DOT_H__ +#define __SYS_DOT_H__ + +/* Allow args to be passed to GFS when using an initial ram disk */ +extern char *gfs_sys_margs; +extern spinlock_t gfs_sys_margs_lock; + +int gfs_sys_fs_add(struct gfs_sbd *sdp); +void gfs_sys_fs_del(struct gfs_sbd *sdp); + +int gfs_sys_init(void); +void gfs_sys_uninit(void); + +#endif /* __SYS_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/ops_file.c +++ linux-2.6.27/ubuntu/gfs/ops_file.c @@ -0,0 +1,1820 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs_ioctl.h" +#include "gfs.h" +#include "bmap.h" +#include "dio.h" +#include "dir.h" +#include "file.h" +#include "glock.h" +#include "glops.h" +#include "inode.h" +#include "ioctl.h" +#include "lm.h" +#include "log.h" +#include "ops_file.h" +#include "ops_vm.h" +#include "quota.h" +#include "rgrp.h" +#include "trans.h" + +/* "bad" is for NFS support */ +struct filldir_bad_entry { + char *fbe_name; + unsigned int fbe_length; + uint64_t fbe_offset; + struct gfs_inum fbe_inum; + unsigned int fbe_type; +}; + +struct filldir_bad { + struct gfs_sbd *fdb_sbd; + + struct filldir_bad_entry *fdb_entry; + unsigned int fdb_entry_num; + unsigned int fdb_entry_off; + + char *fdb_name; + unsigned int fdb_name_size; + unsigned int fdb_name_off; +}; + +/* For regular, non-NFS */ +struct filldir_reg { + struct gfs_sbd *fdr_sbd; + int fdr_prefetch; + + filldir_t fdr_filldir; + void *fdr_opaque; +}; + +typedef ssize_t(*do_rw_t) (struct file * file, + char *buf, + size_t size, loff_t * offset, + struct kiocb *iocb, + unsigned int num_gh, struct gfs_holder * ghs); + +/** + * gfs_llseek - seek to a location in a file + * @file: the file + * @offset: the offset + * @origin: Where to seek from (SEEK_SET, SEEK_CUR, or SEEK_END) + * + * SEEK_END requires the glock for the file because it references the + * file's size. + * + * Returns: The new offset, or errno + */ + +static loff_t +gfs_llseek(struct file *file, loff_t offset, int origin) +{ + struct gfs_inode *ip = get_v2ip(file->f_mapping->host); + struct gfs_holder i_gh; + loff_t error; + + atomic_inc(&ip->i_sbd->sd_ops_file); + + if (origin == 2) { + error = gfs_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); + if (!error) { + error = generic_file_llseek_unlocked(file, offset, origin); + gfs_glock_dq_uninit(&i_gh); + } + } else + error = generic_file_llseek_unlocked(file, offset, origin); + + return error; +} + +#define vma2state(vma) \ +((((vma)->vm_flags & (VM_MAYWRITE | VM_MAYSHARE)) == \ + (VM_MAYWRITE | VM_MAYSHARE)) ? \ + LM_ST_EXCLUSIVE : LM_ST_SHARED) \ + +/** + * functionname - summary + * @param1: description + * @param2: description + * @param3: description + * + * Function description + * + * Returns: what is returned + */ + +static ssize_t +walk_vm_hard(struct file *file, char *buf, size_t size, loff_t *offset, + struct kiocb *iocb, do_rw_t operation) +{ + struct gfs_holder *ghs; + unsigned int num_gh = 0; + ssize_t count; + + { + struct super_block *sb = file->f_dentry->d_inode->i_sb; + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + unsigned long start = (unsigned long)buf; + unsigned long end = start + size; + int dumping = (current->flags & PF_DUMPCORE); + unsigned int x = 0; + + for (vma = find_vma(mm, start); vma; vma = vma->vm_next) { + if (end <= vma->vm_start) + break; + if (vma->vm_file && + vma->vm_file->f_dentry->d_inode->i_sb == sb) { + num_gh++; + } + } + + ghs = kmalloc((num_gh + 1) * sizeof(struct gfs_holder), GFP_KERNEL); + if (!ghs) { + if (!dumping) + up_read(&mm->mmap_sem); + return -ENOMEM; + } + + for (vma = find_vma(mm, start); vma; vma = vma->vm_next) { + if (end <= vma->vm_start) + break; + if (vma->vm_file) { + struct inode *inode = vma->vm_file->f_dentry->d_inode; + if (inode->i_sb == sb) + gfs_holder_init(get_v2ip(inode)->i_gl, + vma2state(vma), + 0, &ghs[x++]); + } + } + + if (!dumping) + up_read(&mm->mmap_sem); + + gfs_assert(get_v2sdp(sb), x == num_gh,); + } + + count = operation(file, buf, size, offset, iocb, num_gh, ghs); + + while (num_gh--) + gfs_holder_uninit(&ghs[num_gh]); + kfree(ghs); + + return count; +} + +/** + * walk_vm - Walk the vmas associated with a buffer for read or write. + * If any of them are gfs, pass the gfs inode down to the read/write + * worker function so that locks can be acquired in the correct order. + * @file: The file to read/write from/to + * @buf: The buffer to copy to/from + * @size: The amount of data requested + * @offset: The current file offset + * @operation: The read or write worker function + * + * Outputs: Offset - updated according to number of bytes written + * + * Returns: The number of bytes written, errno on failure + */ + +static ssize_t +walk_vm(struct file *file, char *buf, size_t size, loff_t *offset, + struct kiocb *iocb, + do_rw_t operation) +{ + if (current->mm) { + struct super_block *sb = file->f_dentry->d_inode->i_sb; + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + unsigned long start = (unsigned long)buf; + unsigned long end = start + size; + int dumping = (current->flags & PF_DUMPCORE); + + if (!dumping) + down_read(&mm->mmap_sem); + + for (vma = find_vma(mm, start); vma; vma = vma->vm_next) { + if (end <= vma->vm_start) + break; + if (vma->vm_file && + vma->vm_file->f_dentry->d_inode->i_sb == sb) + goto do_locks; + } + + if (!dumping) + up_read(&mm->mmap_sem); + } + + { + struct gfs_holder gh; + return operation(file, buf, size, offset, iocb, 0, &gh); + } + + do_locks: + return walk_vm_hard(file, buf, size, offset, iocb, operation); +} + +/** + * functionname - summary + * @param1: description + * @param2: description + * @param3: description + * + * Function description + * + * Returns: what is returned + */ + +static ssize_t +do_read_readi(struct file *file, char *buf, size_t size, loff_t *offset, + struct kiocb *iocb) +{ + struct gfs_inode *ip = get_v2ip(file->f_mapping->host); + ssize_t count = 0; + + if (*offset < 0) + return -EINVAL; + if (!access_ok(VERIFY_WRITE, buf, size)) + return -EFAULT; + + if (!(file->f_flags & O_LARGEFILE)) { + if (*offset >= 0x7FFFFFFFull) + return -EFBIG; + if (*offset + size > 0x7FFFFFFFull) + size = 0x7FFFFFFFull - *offset; + } + + /* ToDo: not sure about iocb .. wcheng + */ + count = gfs_readi(ip, buf, *offset, size, gfs_copy2user); + + if (count > 0) + *offset += count; + + return count; +} + +/** + * do_read_direct - Read bytes from a file + * @file: The file to read from + * @buf: The buffer to copy into + * @size: The amount of data requested + * @offset: The current file offset + * @num_gh: The number of other locks we need to do the read + * @ghs: the locks we need plus one for our lock + * + * Outputs: Offset - updated according to number of bytes read + * + * Returns: The number of bytes read, errno on failure + */ + +static ssize_t +do_read_direct(struct file *file, char *buf, size_t size, loff_t *offset, + struct kiocb *iocb, + unsigned int num_gh, struct gfs_holder *ghs) +{ + struct inode *inode = file->f_mapping->host; + struct gfs_inode *ip = get_v2ip(inode); + unsigned int state = LM_ST_DEFERRED; + int flags = 0; + unsigned int x; + ssize_t count = 0; + int error; + + for (x = 0; x < num_gh; x++) + if (ghs[x].gh_gl == ip->i_gl) { + state = LM_ST_SHARED; + flags |= GL_LOCAL_EXCL; + break; + } + + gfs_holder_init(ip->i_gl, state, flags, &ghs[num_gh]); + + error = gfs_glock_nq_m(num_gh + 1, ghs); + if (error) + goto out; + + error = -EINVAL; + if (gfs_is_jdata(ip)) + goto out_gunlock; + + if (gfs_is_stuffed(ip)) { + size_t mask = bdev_hardsect_size(inode->i_sb->s_bdev) - 1; + + if (((*offset) & mask) || (((unsigned long)buf) & mask)) + goto out_gunlock; + + count = do_read_readi(file, buf, size & ~mask, offset, iocb); + } + else { + if (!iocb) + count = do_sync_read(file, buf, size, offset); + else { + struct iovec local_iov = { .iov_base = buf, .iov_len = size}; + + count = generic_file_aio_read(iocb, &local_iov, 1, *offset); + iocb->ki_pos = *offset; + } + } + + error = 0; + + out_gunlock: + gfs_glock_dq_m(num_gh + 1, ghs); + + out: + gfs_holder_uninit(&ghs[num_gh]); + + return (count) ? count : error; +} + +/** + * do_read_buf - Read bytes from a file + * @file: The file to read from + * @buf: The buffer to copy into + * @size: The amount of data requested + * @offset: The current file offset + * @num_gh: The number of other locks we need to do the read + * @ghs: the locks we need plus one for our lock + * + * Outputs: Offset - updated according to number of bytes read + * + * Returns: The number of bytes read, errno on failure + */ + +static ssize_t +do_read_buf(struct file *file, char *buf, size_t size, loff_t *offset, + struct kiocb *iocb, + unsigned int num_gh, struct gfs_holder *ghs) +{ + struct gfs_inode *ip = get_v2ip(file->f_mapping->host); + ssize_t count = 0; + int error; + + gfs_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &ghs[num_gh]); + + error = gfs_glock_nq_m_atime(num_gh + 1, ghs); + if (error) + goto out; + + if (gfs_is_jdata(ip) || + (gfs_is_stuffed(ip) && !test_bit(GIF_PAGED, &ip->i_flags))) + count = do_read_readi(file, buf, size, offset, iocb); + else { + if (!iocb) { + count = do_sync_read(file, buf, size, offset); + } else { + struct iovec local_iov = { .iov_base = buf, .iov_len = size}; + + count = generic_file_aio_read(iocb, &local_iov, 1, *offset); + iocb->ki_pos = *offset; + } + } + + gfs_glock_dq_m(num_gh + 1, ghs); + + out: + gfs_holder_uninit(&ghs[num_gh]); + + return (count) ? count : error; +} + +static ssize_t +__gfs_read(struct file *file, char *buf, size_t size, loff_t *offset, struct kiocb *iocb) +{ + atomic_inc(&get_v2sdp(file->f_mapping->host->i_sb)->sd_ops_file); + + if (file->f_flags & O_DIRECT) + return walk_vm(file, buf, size, offset, iocb, do_read_direct); + else + return walk_vm(file, buf, size, offset, iocb, do_read_buf); +} + +/** + * gfs_read - Read bytes from a file + * @file: The file to read from + * @buf: The buffer to copy into + * @size: The amount of data requested + * @offset: The current file offset + * + * Outputs: Offset - updated according to number of bytes read + * + * Returns: The number of bytes read, errno on failure + */ + +static ssize_t +gfs_read(struct file *file, char *buf, size_t size, loff_t *offset) +{ + return(__gfs_read(file, buf, size, offset, NULL)); +} + +/* + * gfs_aio_read: match with vfs generic_file_aio_read as: + * (struct kiocb *iocb, char __user *buf, size_t count, loff_t pos) + */ +static ssize_t +gfs_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long count, + loff_t pos) +{ + struct file *filp = iocb->ki_filp; + + BUG_ON(iocb->ki_pos != pos); + return(__gfs_read(filp, iov->iov_base, iov->iov_len, &iocb->ki_pos, iocb)); +} + +/** + * grope_mapping - feel up a mapping that needs to be written + * @buf: the start of the memory to be written + * @size: the size of the memory to be written + * + * We do this after acquiring the locks on the mapping, + * but before starting the write transaction. We need to make + * sure that we don't cause recursive transactions if blocks + * need to be allocated to the file backing the mapping. + * + * Returns: errno + */ + +static int +grope_mapping(char *buf, size_t size) +{ + unsigned long start = (unsigned long)buf; + unsigned long stop = start + size; + char c; + + while (start < stop) { + if (copy_from_user(&c, (char *)start, 1)) + return -EFAULT; + + start += PAGE_CACHE_SIZE; + start &= PAGE_CACHE_MASK; + } + + return 0; +} + +/** + * gfs_file_aio_write_nolock - Call vfs aio layer to write bytes to a file + * @file: The file to write to + * @buf: The buffer to copy from + * @size: The amount of data requested + * @offset: The offset in the file to write + * @iocb: The io control block. If NULL, a temporary one will be used. + * + * Returns: The number of bytes written, errno on failure + */ +static ssize_t +gfs_file_aio_write_nolock(struct file *file, char *buf, size_t size, + loff_t *offset, struct kiocb *iocb) +{ + struct iovec local_iov = { .iov_base = buf, .iov_len = size }; + struct kiocb local_iocb, *kiocb = NULL; + ssize_t count; + + if (!iocb) { + init_sync_kiocb(&local_iocb, file); + local_iocb.ki_nr_segs = 1; + kiocb = &local_iocb; + } + else + kiocb = iocb; + + kiocb->ki_pos = *offset; + count = generic_file_aio_write_nolock(kiocb, &local_iov, kiocb->ki_nr_segs, + kiocb->ki_pos); + *offset = kiocb->ki_pos; + if (kiocb == &local_iocb && count == -EIOCBQUEUED) + count = wait_on_sync_kiocb(kiocb); + return count; +} + +/** + * do_write_direct_alloc - Write bytes to a file + * @file: The file to write to + * @buf: The buffer to copy from + * @size: The amount of data requested + * @offset: The current file offset + * + * Outputs: Offset - updated according to number of bytes written + * + * Returns: The number of bytes written, errno on failure + */ + +static ssize_t +do_write_direct_alloc(struct file *file, char *buf, size_t size, loff_t *offset, + struct kiocb *iocb) +{ + struct inode *inode = file->f_mapping->host; + struct gfs_inode *ip = get_v2ip(inode); + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_alloc *al = NULL; + struct buffer_head *dibh; + unsigned int data_blocks, ind_blocks; + ssize_t count; + int error; + + gfs_write_calc_reserv(ip, size, &data_blocks, &ind_blocks); + + al = gfs_alloc_get(ip); + + error = gfs_quota_lock_m(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto fail; + + error = gfs_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid); + if (error) + goto fail_gunlock_q; + + al->al_requested_meta = ind_blocks; + al->al_requested_data = data_blocks; + + error = gfs_inplace_reserve(ip); + if (error) + goto fail_gunlock_q; + + /* Trans may require: + All blocks for a RG bitmap, whatever indirect blocks we + need, a modified dinode, and a quota change. */ + + error = gfs_trans_begin(sdp, + 1 + al->al_rgd->rd_ri.ri_length + ind_blocks, + 1); + if (error) + goto fail_ipres; + + if ((ip->i_di.di_mode & (S_ISUID | S_ISGID)) && !capable(CAP_FSETID)) { + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + goto fail_end_trans; + + ip->i_di.di_mode &= (ip->i_di.di_mode & S_IXGRP) ? (~(S_ISUID | S_ISGID)) : (~S_ISUID); + + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + if (gfs_is_stuffed(ip)) { error = gfs_unstuff_dinode(ip, gfs_unstuffer_sync, NULL); if (error) + goto fail_end_trans; + } + + count = gfs_file_aio_write_nolock(file, buf, size, offset, iocb); + if (count < 0) { + error = count; + goto fail_end_trans; + } + + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + goto fail_end_trans; + + if (ip->i_di.di_size < inode->i_size) + ip->i_di.di_size = inode->i_size; + ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + + gfs_trans_end(sdp); + + /* Question (wcheng) + * 1. should IS_SYNC flush glock ? + * 2. does gfs_log_flush_glock flush data ? + */ + if (file->f_flags & O_SYNC) + gfs_log_flush_glock(ip->i_gl); + + gfs_inplace_release(ip); + gfs_quota_unlock_m(ip); + gfs_alloc_put(ip); + + if (file->f_mapping->nrpages) { + error = filemap_fdatawrite(file->f_mapping); + if (!error) + error = filemap_fdatawait(file->f_mapping); + } + if (error) + return error; + + return count; + + fail_end_trans: + gfs_trans_end(sdp); + + fail_ipres: + gfs_inplace_release(ip); + + fail_gunlock_q: + gfs_quota_unlock_m(ip); + + fail: + gfs_alloc_put(ip); + + return error; +} + +/** + * do_write_direct - Write bytes to a file + * @file: The file to write to + * @buf: The buffer to copy from + * @size: The amount of data requested + * @offset: The current file offset + * @num_gh: The number of other locks we need to do the read + * @gh: the locks we need plus one for our lock + * + * Outputs: Offset - updated according to number of bytes written + * + * Returns: The number of bytes written, errno on failure + */ + +static ssize_t +do_write_direct(struct file *file, char *buf, size_t size, loff_t *offset, + struct kiocb *iocb, + unsigned int num_gh, struct gfs_holder *ghs) +{ + struct gfs_inode *ip = get_v2ip(file->f_mapping->host); + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_file *fp = get_v2fp(file); + unsigned int state = LM_ST_DEFERRED; + int alloc_required; + unsigned int x; + size_t s; + ssize_t count = 0; + int error; + + if (test_bit(GFF_DID_DIRECT_ALLOC, &fp->f_flags)) + state = LM_ST_EXCLUSIVE; + else + for (x = 0; x < num_gh; x++) + if (ghs[x].gh_gl == ip->i_gl) { + state = LM_ST_EXCLUSIVE; + break; + } + + restart: + gfs_holder_init(ip->i_gl, state, 0, &ghs[num_gh]); + + error = gfs_glock_nq_m(num_gh + 1, ghs); + if (error) + goto out; + + error = -EINVAL; + if (gfs_is_jdata(ip)) + goto out_gunlock; + + if (num_gh) { + error = grope_mapping(buf, size); + if (error) + goto out_gunlock; + } + + if (file->f_flags & O_APPEND) + *offset = ip->i_di.di_size; + + if (!(file->f_flags & O_LARGEFILE)) { + error = -EFBIG; + if (*offset >= 0x7FFFFFFFull) + goto out_gunlock; + if (*offset + size > 0x7FFFFFFFull) + size = 0x7FFFFFFFull - *offset; + } + + if (gfs_is_stuffed(ip) || + *offset + size > ip->i_di.di_size || + ((ip->i_di.di_mode & (S_ISUID | S_ISGID)) && !capable(CAP_FSETID))) + alloc_required = TRUE; + else { + error = gfs_write_alloc_required(ip, *offset, size, + &alloc_required); + if (error) + goto out_gunlock; + } + + if (alloc_required && state != LM_ST_EXCLUSIVE) { + gfs_glock_dq_m(num_gh + 1, ghs); + gfs_holder_uninit(&ghs[num_gh]); + state = LM_ST_EXCLUSIVE; + goto restart; + } + + if (alloc_required) { + set_bit(GFF_DID_DIRECT_ALLOC, &fp->f_flags); + + /* for asynchronous IO, the buffer can not be splitted */ + if (iocb) { + count = do_write_direct_alloc(file, buf, size, offset, iocb); + goto out_iocb_write; + } + + /* split large writes into smaller atomic transactions */ + while (size) { + s = gfs_tune_get(sdp, gt_max_atomic_write); + if (s > size) + s = size; + + error = do_write_direct_alloc(file, buf, s, offset, iocb); + if (error < 0) + goto out_gunlock; + + buf += error; + size -= error; + count += error; + } + } else { + struct gfs_holder t_gh; + + clear_bit(GFF_DID_DIRECT_ALLOC, &fp->f_flags); + + error = gfs_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, 0, &t_gh); + if (error) + goto out_gunlock; + + /* Todo: It would be nice if init_sync_kiocb is exported. + * .. wcheng + */ + count = gfs_file_aio_write_nolock(file, buf, size, offset, iocb); + gfs_glock_dq_uninit(&t_gh); + } + +out_iocb_write: + error = 0; + +out_gunlock: + gfs_glock_dq_m(num_gh + 1, ghs); + +out: + gfs_holder_uninit(&ghs[num_gh]); + + return (count) ? count : error; +} + +/** + * do_do_write_buf - Write bytes to a file + * @file: The file to write to + * @buf: The buffer to copy from + * @size: The amount of data requested + * @offset: The current file offset + * + * Outputs: Offset - updated according to number of bytes written + * + * Returns: The number of bytes written, errno on failure + */ + +static ssize_t +do_do_write_buf(struct file *file, char *buf, size_t size, loff_t *offset, + struct kiocb *iocb) +{ + struct inode *inode = file->f_mapping->host; + struct gfs_inode *ip = get_v2ip(inode); + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_alloc *al = NULL; + struct buffer_head *dibh; + unsigned int data_blocks, ind_blocks; + int alloc_required, journaled; + ssize_t count; + int error; + + journaled = gfs_is_jdata(ip); + + gfs_write_calc_reserv(ip, size, &data_blocks, &ind_blocks); + + error = gfs_write_alloc_required(ip, *offset, size, &alloc_required); + if (error) + return error; + + if (alloc_required) { + al = gfs_alloc_get(ip); + + error = gfs_quota_lock_m(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto fail; + + error = gfs_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid); + if (error) + goto fail_gunlock_q; + + if (journaled) + al->al_requested_meta = ind_blocks + data_blocks; + else { + al->al_requested_meta = ind_blocks; + al->al_requested_data = data_blocks; + } + + error = gfs_inplace_reserve(ip); + if (error) + goto fail_gunlock_q; + + /* Trans may require: + All blocks for a RG bitmap, whatever indirect blocks we + need, a modified dinode, and a quota change. */ + + error = gfs_trans_begin(sdp, + 1 + al->al_rgd->rd_ri.ri_length + + ind_blocks + + ((journaled) ? data_blocks : 0), 1); + if (error) + goto fail_ipres; + } else { + /* Trans may require: + A modified dinode. */ + + error = gfs_trans_begin(sdp, + 1 + ((journaled) ? data_blocks : 0), 0); + if (error) + goto fail_ipres; + } + + if ((ip->i_di.di_mode & (S_ISUID | S_ISGID)) && !capable(CAP_FSETID)) { + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + goto fail_end_trans; + + ip->i_di.di_mode &= (ip->i_di.di_mode & S_IXGRP) ? (~(S_ISUID | S_ISGID)) : (~S_ISUID); + + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + if (journaled || + (gfs_is_stuffed(ip) && !test_bit(GIF_PAGED, &ip->i_flags) && + *offset + size <= sdp->sd_sb.sb_bsize - sizeof(struct gfs_dinode))) { + + count = gfs_writei(ip, buf, *offset, size, gfs_copy_from_user, iocb); + if (count < 0) { + error = count; + goto fail_end_trans; + } + if (gfs_is_stuffed(ip)){ + struct page *page; + page = find_get_page(file->f_mapping, 0); + if (page) { + ClearPageUptodate(page); + page_cache_release(page); + } + } + *offset += count; + } else { + count = gfs_file_aio_write_nolock(file, buf, size, offset, iocb); + if (count < 0) { + error = count; + goto fail_end_trans; + } + + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + goto fail_end_trans; + + if (ip->i_di.di_size < inode->i_size) + ip->i_di.di_size = inode->i_size; + ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + gfs_trans_end(sdp); + + if (file->f_flags & O_SYNC || IS_SYNC(inode)) { + gfs_log_flush_glock(ip->i_gl); + error = filemap_fdatawrite(file->f_mapping); + if (error == 0) + error = filemap_fdatawait(file->f_mapping); + if (error) + goto fail_ipres; + } + + if (alloc_required) { + gfs_assert_warn(sdp, count != size || + al->al_alloced_meta || + al->al_alloced_data); + gfs_inplace_release(ip); + gfs_quota_unlock_m(ip); + gfs_alloc_put(ip); + } + + return count; + + fail_end_trans: + gfs_trans_end(sdp); + + fail_ipres: + if (alloc_required) + gfs_inplace_release(ip); + + fail_gunlock_q: + if (alloc_required) + gfs_quota_unlock_m(ip); + + fail: + if (alloc_required) + gfs_alloc_put(ip); + + return error; +} + +/** + * do_write_buf - Write bytes to a file + * @file: The file to write to + * @buf: The buffer to copy from + * @size: The amount of data requested + * @offset: The current file offset + * @num_gh: The number of other locks we need to do the read + * @gh: the locks we need plus one for our lock + * + * Outputs: Offset - updated according to number of bytes written + * + * Returns: The number of bytes written, errno on failure + */ + +static ssize_t +do_write_buf(struct file *file, + char *buf, size_t size, loff_t *offset, + struct kiocb *iocb, + unsigned int num_gh, struct gfs_holder *ghs) +{ + struct gfs_inode *ip = get_v2ip(file->f_mapping->host); + struct gfs_sbd *sdp = ip->i_sbd; + size_t s; + ssize_t count = 0; + int error; + + gfs_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ghs[num_gh]); + + error = gfs_glock_nq_m(num_gh + 1, ghs); + if (error) + goto out; + + if (num_gh) { + error = grope_mapping(buf, size); + if (error) + goto out_gunlock; + } + + if (file->f_flags & O_APPEND) + *offset = ip->i_di.di_size; + + if (!(file->f_flags & O_LARGEFILE)) { + error = -EFBIG; + if (*offset >= 0x7FFFFFFFull) + goto out_gunlock; + if (*offset + size > 0x7FFFFFFFull) + size = 0x7FFFFFFFull - *offset; + } + + /* split large writes into smaller atomic transactions */ + while (size) { + s = gfs_tune_get(sdp, gt_max_atomic_write); + if (s > size) + s = size; + + error = do_do_write_buf(file, buf, s, offset, iocb); + if (error < 0) + goto out_gunlock; + + buf += error; + size -= error; + count += error; + } + + error = 0; + + out_gunlock: + gfs_glock_dq_m(num_gh + 1, ghs); + + out: + gfs_holder_uninit(&ghs[num_gh]); + + return (count) ? count : error; +} + +/** + * gfs_write - Write bytes to a file + * @file: The file to write to + * @buf: The buffer to copy from + * @size: The amount of data requested + * @offset: The current file offset + * + * Outputs: Offset - updated according to number of bytes written + * + * Returns: The number of bytes written, errno on failure + */ + +static ssize_t +__gfs_write(struct file *file, const char *buf, size_t size, loff_t *offset, struct kiocb *iocb) +{ + struct inode *inode = file->f_mapping->host; + ssize_t count; + + atomic_inc(&get_v2sdp(inode->i_sb)->sd_ops_file); + + if (*offset < 0) + return -EINVAL; + if (!access_ok(VERIFY_READ, buf, size)) + return -EFAULT; + + mutex_lock(&inode->i_mutex); + if (file->f_flags & O_DIRECT) + count = walk_vm(file, (char *)buf, size, offset, iocb, do_write_direct); + else + count = walk_vm(file, (char *)buf, size, offset, iocb, do_write_buf); + mutex_unlock(&inode->i_mutex); + + return count; +} + +static ssize_t +gfs_write(struct file *file, const char *buf, size_t size, loff_t *offset) +{ + return(__gfs_write(file, buf, size, offset, NULL)); +} + +static ssize_t +gfs_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long segs, + loff_t pos) +{ + struct file *file = iocb->ki_filp; + + BUG_ON(iocb->ki_pos != pos); + + return(__gfs_write(file, iov->iov_base, iov->iov_len, &iocb->ki_pos, + iocb)); +} + +/** + * filldir_reg_func - Report a directory entry to the caller of gfs_dir_read() + * @opaque: opaque data used by the function + * @name: the name of the directory entry + * @length: the length of the name + * @offset: the entry's offset in the directory + * @inum: the inode number the entry points to + * @type: the type of inode the entry points to + * + * Returns: 0 on success, 1 if buffer full + */ + +static int +filldir_reg_func(void *opaque, + const char *name, unsigned int length, + uint64_t offset, + struct gfs_inum *inum, unsigned int type) +{ + struct filldir_reg *fdr = (struct filldir_reg *)opaque; + struct gfs_sbd *sdp = fdr->fdr_sbd; + unsigned int vfs_type; + int error; + + switch (type) { + case GFS_FILE_NON: + vfs_type = DT_UNKNOWN; + break; + case GFS_FILE_REG: + vfs_type = DT_REG; + break; + case GFS_FILE_DIR: + vfs_type = DT_DIR; + break; + case GFS_FILE_LNK: + vfs_type = DT_LNK; + break; + case GFS_FILE_BLK: + vfs_type = DT_BLK; + break; + case GFS_FILE_CHR: + vfs_type = DT_CHR; + break; + case GFS_FILE_FIFO: + vfs_type = DT_FIFO; + break; + case GFS_FILE_SOCK: + vfs_type = DT_SOCK; + break; + default: + if (gfs_consist(sdp)) + printk("GFS: fsid=%s: type = %u\n", + sdp->sd_fsname, type); + return -EIO; + } + + error = fdr->fdr_filldir(fdr->fdr_opaque, name, length, offset, + inum->no_formal_ino, vfs_type); + if (error) + return 1; + + /* Prefetch locks */ + if (fdr->fdr_prefetch && !(length == 1 && *name == '.')) { + gfs_glock_prefetch_num(sdp, + inum->no_formal_ino, &gfs_inode_glops, + LM_ST_SHARED, LM_FLAG_TRY | LM_FLAG_ANY); + gfs_glock_prefetch_num(sdp, + inum->no_addr, &gfs_iopen_glops, + LM_ST_SHARED, LM_FLAG_TRY); + } + + return 0; +} + +/** + * readdir_reg - Read directory entries from a directory + * @file: The directory to read from + * @dirent: Buffer for dirents + * @filldir: Function used to do the copying + * + * Returns: errno + */ + +static int +readdir_reg(struct file *file, void *dirent, filldir_t filldir) +{ + struct gfs_inode *dip = get_v2ip(file->f_mapping->host); + struct filldir_reg fdr; + struct gfs_holder d_gh; + uint64_t offset = file->f_pos; + int error; + + fdr.fdr_sbd = dip->i_sbd; + fdr.fdr_prefetch = TRUE; + fdr.fdr_filldir = filldir; + fdr.fdr_opaque = dirent; + + gfs_holder_init(dip->i_gl, LM_ST_SHARED, GL_ATIME, &d_gh); + error = gfs_glock_nq_atime(&d_gh); + if (error) { + gfs_holder_uninit(&d_gh); + return error; + } + + error = gfs_dir_read(dip, &offset, &fdr, filldir_reg_func); + + gfs_glock_dq_uninit(&d_gh); + + file->f_pos = offset; + + return error; +} + +/** + * filldir_bad_func - Report a directory entry to the caller of gfs_dir_read() + * @opaque: opaque data used by the function + * @name: the name of the directory entry + * @length: the length of the name + * @offset: the entry's offset in the directory + * @inum: the inode number the entry points to + * @type: the type of inode the entry points to + * + * For supporting NFS. + * + * Returns: 0 on success, 1 if buffer full + */ + +static int +filldir_bad_func(void *opaque, + const char *name, unsigned int length, + uint64_t offset, + struct gfs_inum *inum, unsigned int type) +{ + struct filldir_bad *fdb = (struct filldir_bad *)opaque; + struct gfs_sbd *sdp = fdb->fdb_sbd; + struct filldir_bad_entry *fbe; + + if (fdb->fdb_entry_off == fdb->fdb_entry_num || + fdb->fdb_name_off + length > fdb->fdb_name_size) + return 1; + + fbe = &fdb->fdb_entry[fdb->fdb_entry_off]; + fbe->fbe_name = fdb->fdb_name + fdb->fdb_name_off; + memcpy(fbe->fbe_name, name, length); + fbe->fbe_length = length; + fbe->fbe_offset = offset; + fbe->fbe_inum = *inum; + fbe->fbe_type = type; + + fdb->fdb_entry_off++; + fdb->fdb_name_off += length; + + /* Prefetch locks */ + if (!(length == 1 && *name == '.')) { + gfs_glock_prefetch_num(sdp, + inum->no_formal_ino, &gfs_inode_glops, + LM_ST_SHARED, LM_FLAG_TRY | LM_FLAG_ANY); + gfs_glock_prefetch_num(sdp, + inum->no_addr, &gfs_iopen_glops, + LM_ST_SHARED, LM_FLAG_TRY); + } + + return 0; +} + +/** + * readdir_bad - Read directory entries from a directory + * @file: The directory to read from + * @dirent: Buffer for dirents + * @filldir: Function used to do the copying + * + * For supporting NFS. + * + * Returns: errno + */ + +static int +readdir_bad(struct file *file, void *dirent, filldir_t filldir) +{ + struct gfs_inode *dip = get_v2ip(file->f_mapping->host); + struct gfs_sbd *sdp = dip->i_sbd; + struct filldir_reg fdr; + unsigned int entries, size; + struct filldir_bad *fdb; + struct gfs_holder d_gh; + uint64_t offset = file->f_pos; + unsigned int x; + struct filldir_bad_entry *fbe; + int error; + + entries = gfs_tune_get(sdp, gt_entries_per_readdir); + size = sizeof(struct filldir_bad) + + entries * (sizeof(struct filldir_bad_entry) + GFS_FAST_NAME_SIZE); + + fdb = kmalloc(size, GFP_KERNEL); + if (!fdb) + return -ENOMEM; + memset(fdb, 0, size); + + fdb->fdb_sbd = sdp; + fdb->fdb_entry = (struct filldir_bad_entry *)(fdb + 1); + fdb->fdb_entry_num = entries; + fdb->fdb_name = ((char *)fdb) + sizeof(struct filldir_bad) + + entries * sizeof(struct filldir_bad_entry); + fdb->fdb_name_size = entries * GFS_FAST_NAME_SIZE; + + gfs_holder_init(dip->i_gl, LM_ST_SHARED, GL_ATIME, &d_gh); + error = gfs_glock_nq_atime(&d_gh); + if (error) { + gfs_holder_uninit(&d_gh); + goto out; + } + + error = gfs_dir_read(dip, &offset, fdb, filldir_bad_func); + + gfs_glock_dq_uninit(&d_gh); + + fdr.fdr_sbd = sdp; + fdr.fdr_prefetch = FALSE; + fdr.fdr_filldir = filldir; + fdr.fdr_opaque = dirent; + + for (x = 0; x < fdb->fdb_entry_off; x++) { + fbe = &fdb->fdb_entry[x]; + + error = filldir_reg_func(&fdr, + fbe->fbe_name, fbe->fbe_length, + fbe->fbe_offset, + &fbe->fbe_inum, fbe->fbe_type); + if (error) { + file->f_pos = fbe->fbe_offset; + error = 0; + goto out; + } + } + + file->f_pos = offset; + + out: + kfree(fdb); + + return error; +} + +/** + * gfs_readdir - Read directory entries from a directory + * @file: The directory to read from + * @dirent: Buffer for dirents + * @filldir: Function used to do the copying + * + * Returns: errno + */ + +static int +gfs_readdir(struct file *file, void *dirent, filldir_t filldir) +{ + int error; + + atomic_inc(&get_v2sdp(file->f_mapping->host->i_sb)->sd_ops_file); + + /* Use "bad" one if we're called from NFS daemon */ + if (strcmp(current->comm, "nfsd") != 0) + error = readdir_reg(file, dirent, filldir); + else + error = readdir_bad(file, dirent, filldir); + + return error; +} + +/** + * gfs_ioctl - do an ioctl on a file + * @inode: the inode + * @file: the file pointer + * @cmd: the ioctl command + * @arg: the argument + * + * Returns: errno + */ + +static int +gfs_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct gfs_inode *ip = get_v2ip(inode); + + atomic_inc(&ip->i_sbd->sd_ops_file); + + switch (cmd) { + case GFS_IOCTL_IDENTIFY: { + unsigned int x = GFS_MAGIC; + if (copy_to_user((unsigned int *)arg, &x, sizeof(unsigned int))) + return -EFAULT; + return 0; + } + + case GFS_IOCTL_SUPER: + return gfs_ioctl_i(ip, (void *)arg); + + default: + return -ENOTTY; + } +} + +#ifdef CONFIG_COMPAT +/** + * gfs_compat_ioctl - do an ioctl on a file - compatible between 32-64 bit + * @inode: the inode + * @file: the file pointer + * @cmd: the ioctl command + * @arg: the argument + * + * Returns: errno + */ + +static long +gfs_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) +{ + struct gfs_inode *ip = get_v2ip(file->f_mapping->host); + + atomic_inc(&ip->i_sbd->sd_ops_file); + + switch (cmd) { + case GFS_IOCTL_IDENTIFY: { + unsigned int x = GFS_MAGIC; + if (copy_to_user((unsigned int *)arg, &x, sizeof(unsigned int))) + return -EFAULT; + return 0; + } + + case GFS_IOCTL_SUPER: + return gfs_ioctl_i_compat(ip, arg); + + default: + return -ENOTTY; + } +} +#endif + +/** + * gfs_mmap - We don't support shared writable mappings right now + * @file: The file to map + * @vma: The VMA which described the mapping + * + * Returns: 0 or error code + */ + +static int +gfs_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct gfs_inode *ip = get_v2ip(file->f_mapping->host); + struct gfs_holder i_gh; + int error; + + atomic_inc(&ip->i_sbd->sd_ops_file); + + gfs_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &i_gh); + error = gfs_glock_nq_atime(&i_gh); + if (error) { + gfs_holder_uninit(&i_gh); + return error; + } + + if (gfs_is_jdata(ip)) { + if (vma->vm_flags & VM_MAYSHARE) + error = -ENOSYS; + else + vma->vm_ops = &gfs_vm_ops_private; + } else { + /* This is VM_MAYWRITE instead of VM_WRITE because a call + to mprotect() can turn on VM_WRITE later. */ + + if ((vma->vm_flags & (VM_MAYSHARE | VM_MAYWRITE)) == (VM_MAYSHARE | VM_MAYWRITE)) + vma->vm_ops = &gfs_vm_ops_sharewrite; + else + vma->vm_ops = &gfs_vm_ops_private; + } + + gfs_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * gfs_open - open a file + * @inode: the inode to open + * @file: the struct file for this opening + * + * Returns: errno + */ + +static int +gfs_open(struct inode *inode, struct file *file) +{ + struct gfs_inode *ip = get_v2ip(inode); + struct gfs_holder i_gh; + struct gfs_file *fp; + int error; + + atomic_inc(&ip->i_sbd->sd_ops_file); + + fp = kmalloc(sizeof(struct gfs_file), GFP_KERNEL); + if (!fp) + return -ENOMEM; + memset(fp, 0, sizeof(struct gfs_file)); + + init_MUTEX(&fp->f_fl_lock); + + fp->f_inode = ip; + fp->f_vfile = file; + + gfs_assert_warn(ip->i_sbd, !get_v2fp(file)); + set_v2fp(file, fp); + + if (ip->i_di.di_type == GFS_FILE_REG) { + error = gfs_glock_nq_init(ip->i_gl, + LM_ST_SHARED, LM_FLAG_ANY, + &i_gh); + if (error) + goto fail; + + if (!(file->f_flags & O_LARGEFILE) && + ip->i_di.di_size > 0x7FFFFFFFull) { + error = -EFBIG; + goto fail_gunlock; + } + + /* Listen to the Direct I/O flag */ + + if (ip->i_di.di_flags & GFS_DIF_DIRECTIO) + file->f_flags |= O_DIRECT; + + /* Don't let the user open O_DIRECT on a jdata file */ + + if ((file->f_flags & O_DIRECT) && gfs_is_jdata(ip)) { + error = -EINVAL; + goto fail_gunlock; + } + + gfs_glock_dq_uninit(&i_gh); + } + + return 0; + + fail_gunlock: + gfs_glock_dq_uninit(&i_gh); + + fail: + set_v2fp(file, NULL); + kfree(fp); + + return error; +} + +/** + * gfs_close - called to close a struct file + * @inode: the inode the struct file belongs to + * @file: the struct file being closed + * + * Returns: errno + */ + +static int +gfs_close(struct inode *inode, struct file *file) +{ + struct gfs_sbd *sdp = get_v2sdp(inode->i_sb); + struct gfs_file *fp; + + atomic_inc(&sdp->sd_ops_file); + + fp = get_v2fp(file); + set_v2fp(file, NULL); + + if (!gfs_assert_warn(sdp, fp)) + kfree(fp); + + return 0; +} + +/** + * gfs_fsync - sync the dirty data for a file (across the cluster) + * @file: the file that points to the dentry (we ignore this) + * @dentry: the dentry that points to the inode to sync + * + * Returns: errno + * + * Obtain a SHARED lock on the file, to force any node with an EXCLUSIVE lock + * to sync file's dirty data to disk, as it releases the EXCLUSIVE lock. + */ + +static int +gfs_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + struct gfs_inode *ip = get_v2ip(dentry->d_inode); + struct gfs_holder i_gh; + struct inode *inode = dentry->d_inode; + int error; + + atomic_inc(&ip->i_sbd->sd_ops_file); + + error = gfs_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); + if (error) + return error; + + if (gfs_is_jdata(ip)) + gfs_log_flush_glock(ip->i_gl); + else { + if ((!datasync) || (inode->i_state & I_DIRTY_DATASYNC)) { + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .nr_to_write = 0, + }; + error = sync_inode(inode, &wbc); + } + } + + gfs_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * gfs_lock - acquire/release a posix lock on a file + * @file: the file pointer + * @cmd: either modify or retrieve lock state, possibly wait + * @fl: type and range of lock + * + * Returns: errno + */ + +static int +gfs_lock(struct file *file, int cmd, struct file_lock *fl) +{ + struct gfs_inode *ip = get_v2ip(file->f_mapping->host); + struct gfs_sbd *sdp = ip->i_sbd; + struct lm_lockname name = + { .ln_number = ip->i_num.no_formal_ino, + .ln_type = LM_TYPE_PLOCK }; + + atomic_inc(&sdp->sd_ops_file); + + if (!(fl->fl_flags & FL_POSIX)) + return -ENOLCK; + if ((ip->i_di.di_mode & (S_ISGID | S_IXGRP)) == S_ISGID) + return -ENOLCK; + + if (IS_GETLK(cmd)) + return gfs_lm_plock_get(sdp, &name, file, fl); + else if (fl->fl_type == F_UNLCK) + return gfs_lm_punlock(sdp, &name, file, fl); + else + return gfs_lm_plock(sdp, &name, file, cmd, fl); +} + +/** + * gfs_splice_read - Send bytes to a file or socket + * @in_file: The file to read from + * @out_file: The file to write to + * @count: The amount of data + * @ppos: The beginning file offset + * + * Outputs: offset - updated according to number of bytes read + * + * Returns: The number of bytes sent, errno on failure + */ + +static ssize_t +gfs_splice_read(struct file *in_file, loff_t *ppos, struct pipe_inode_info *pipe, size_t count, unsigned int flags) +{ + struct gfs_inode *ip = get_v2ip(in_file->f_mapping->host); + struct gfs_holder gh; + ssize_t retval; + + atomic_inc(&ip->i_sbd->sd_ops_file); + + gfs_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); + + retval = gfs_glock_nq_atime(&gh); + if (retval) + goto out; + + if (gfs_is_jdata(ip)) + retval = -ENOSYS; + else + retval = generic_file_splice_read(in_file, ppos, pipe, count, flags); + + gfs_glock_dq(&gh); + + out: + gfs_holder_uninit(&gh); + + return retval; +} + +/** + * do_flock - Acquire a flock on a file + * @file: + * @cmd: + * @fl: + * + * Returns: errno + */ + +static int +do_flock(struct file *file, int cmd, struct file_lock *fl) +{ + struct gfs_file *fp = get_v2fp(file); + struct gfs_holder *fl_gh = &fp->f_fl_gh; + struct gfs_inode *ip = fp->f_inode; + struct gfs_glock *gl; + unsigned int state; + int flags; + int error = 0; + + state = (fl->fl_type == F_WRLCK) ? LM_ST_EXCLUSIVE : LM_ST_SHARED; + flags = ((IS_SETLKW(cmd)) ? 0 : LM_FLAG_TRY) | GL_EXACT | GL_NOCACHE; + + down(&fp->f_fl_lock); + + gl = fl_gh->gh_gl; + if (gl) { + if (fl_gh->gh_state == state) + goto out; + gfs_glock_hold(gl); + flock_lock_file_wait(file, + &(struct file_lock){.fl_type = F_UNLCK}); + gfs_glock_dq_uninit(fl_gh); + } else { + error = gfs_glock_get(ip->i_sbd, + ip->i_num.no_formal_ino, &gfs_flock_glops, + CREATE, &gl); + if (error) + goto out; + } + + gfs_holder_init(gl, state, flags, fl_gh); + gfs_glock_put(gl); + + error = gfs_glock_nq(fl_gh); + if (error) { + gfs_holder_uninit(fl_gh); + if (error == GLR_TRYFAILED) + error = -EAGAIN; + } else { + error = flock_lock_file_wait(file, fl); + gfs_assert_warn(ip->i_sbd, !error); + } + + out: + up(&fp->f_fl_lock); + + return error; +} + +/** + * do_unflock - Release a flock on a file + * @file: the file + * @fl: + * + */ + +static void +do_unflock(struct file *file, struct file_lock *fl) +{ + struct gfs_file *fp = get_v2fp(file); + struct gfs_holder *fl_gh = &fp->f_fl_gh; + + down(&fp->f_fl_lock); + flock_lock_file_wait(file, fl); + if (fl_gh->gh_gl) + gfs_glock_dq_uninit(fl_gh); + up(&fp->f_fl_lock); +} + +/** + * gfs_flock - acquire/release a flock lock on a file + * @file: the file pointer + * @cmd: either modify or retrieve lock state, possibly wait + * @fl: type and range of lock + * + * Returns: errno + */ + +static int +gfs_flock(struct file *file, int cmd, struct file_lock *fl) +{ + struct gfs_inode *ip = get_v2ip(file->f_mapping->host); + + atomic_inc(&ip->i_sbd->sd_ops_file); + + if (!(fl->fl_flags & FL_FLOCK)) + return -ENOLCK; + if ((ip->i_di.di_mode & (S_ISGID | S_IXGRP)) == S_ISGID) + return -ENOLCK; + + if (fl->fl_type == F_UNLCK) { + do_unflock(file, fl); + return 0; + } else + return do_flock(file, cmd, fl); +} + +struct file_operations gfs_file_fops = { + .llseek = gfs_llseek, + .read = gfs_read, + .write = gfs_write, + .aio_read = gfs_aio_read, + .aio_write = gfs_aio_write, + .ioctl = gfs_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = gfs_compat_ioctl, +#endif + .mmap = gfs_mmap, + .open = gfs_open, + .release = gfs_close, + .fsync = gfs_fsync, + .lock = gfs_lock, + .splice_read = gfs_splice_read, + .flock = gfs_flock, +}; + +struct file_operations gfs_dir_fops = { + .readdir = gfs_readdir, + .ioctl = gfs_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = gfs_compat_ioctl, +#endif + .open = gfs_open, + .release = gfs_close, + .fsync = gfs_fsync, + .lock = gfs_lock, + .flock = gfs_flock, +}; + +struct file_operations gfs_file_fops_nolock = { + .llseek = gfs_llseek, + .read = gfs_read, + .write = gfs_write, + .aio_read = gfs_aio_read, + .aio_write = gfs_aio_write, + .ioctl = gfs_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = gfs_compat_ioctl, +#endif + .mmap = gfs_mmap, + .open = gfs_open, + .release = gfs_close, + .fsync = gfs_fsync, + .splice_read = gfs_splice_read, +}; + +struct file_operations gfs_dir_fops_nolock = { + .readdir = gfs_readdir, + .ioctl = gfs_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = gfs_compat_ioctl, +#endif + .open = gfs_open, + .release = gfs_close, + .fsync = gfs_fsync, +}; --- linux-2.6.27.orig/ubuntu/gfs/trans.c +++ linux-2.6.27/ubuntu/gfs/trans.c @@ -0,0 +1,453 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "dio.h" +#include "glock.h" +#include "log.h" +#include "lops.h" +#include "quota.h" +#include "trans.h" +#include "unlinked.h" + +/** + * gfs_trans_print - Print a transaction to the console + * @sdp: the filesystem + * @tr: The GFS transaction + * @where: Situation of transaction + * + */ + +void +gfs_trans_print(struct gfs_sbd *sdp, struct gfs_trans *tr, unsigned int where) +{ + struct gfs_log_element *le; + struct list_head *tmp, *head; + unsigned int mblks = 0, eblks = 0; + + LO_TRANS_SIZE(sdp, tr, &mblks, &eblks, NULL, NULL); + + printk("Transaction: (%s, %u)\n", tr->tr_file, tr->tr_line); + printk(" tr_mblks_asked = %u, tr_eblks_asked = %u, tr_seg_reserved = %u\n", + tr->tr_mblks_asked, tr->tr_eblks_asked, tr->tr_seg_reserved); + printk(" mblks = %u, eblks = %u\n", mblks, eblks); + printk(" tr_flags = 0x%.8X\n", tr->tr_flags); + + for (head = &tr->tr_elements, tmp = head->next; + tmp != head; + tmp = tmp->next) { + le = list_entry(tmp, struct gfs_log_element, le_list); + LO_PRINT(sdp, le, where); + } + + printk("End Trans\n"); +} + +/** + * gfs_trans_begin_i - Prepare to start a transaction + * @sdp: The GFS superblock + * @meta_blocks: Reserve this many metadata blocks in the log + * @extra_blocks: Number of non-metadata blocks to reserve + * + * Allocate the struct gfs_trans struct. + * Grab a shared TRANSaction lock (protects this transaction from + * overlapping with unusual fs writes, e.g. journal replay, fs upgrade, + * while allowing simultaneous transaction writes throughout cluster). + * Reserve space in the log. @meta_blocks and @extra_blocks must indicate + * the worst case (maximum) size of the transaction. + * Record this transaction as the *one* transaction being built by this + * Linux process, in current->journal_info. + * + * Returns: errno + */ + +int +gfs_trans_begin_i(struct gfs_sbd *sdp, + unsigned int meta_blocks, unsigned int extra_blocks, + char *file, unsigned int line) +{ + struct gfs_trans *tr; + unsigned int blocks; + int error; + + tr = kmalloc(sizeof(struct gfs_trans), GFP_KERNEL); + if (!tr) + return -ENOMEM; + memset(tr, 0, sizeof(struct gfs_trans)); + + INIT_LIST_HEAD(&tr->tr_elements); + INIT_LIST_HEAD(&tr->tr_free_bufs); + INIT_LIST_HEAD(&tr->tr_free_bmem); + INIT_LIST_HEAD(&tr->tr_bufs); + INIT_LIST_HEAD(&tr->tr_ail_bufs); + tr->tr_file = file; + tr->tr_line = line; + + error = -ENOMEM; + tr->tr_t_gh = gfs_holder_get(sdp->sd_trans_gl, LM_ST_SHARED, 0); + if (!tr->tr_t_gh) + goto fail; + + error = gfs_glock_nq(tr->tr_t_gh); + if (error) + goto fail_holder_put; + + if (test_bit(SDF_ROFS, &sdp->sd_flags)) { + tr->tr_t_gh->gh_flags |= GL_NOCACHE; + error = -EROFS; + goto fail_gunlock; + } + + /* Do log reservation */ + + tr->tr_mblks_asked = meta_blocks; + tr->tr_eblks_asked = extra_blocks; + + blocks = 1; + if (meta_blocks) + blocks += gfs_struct2blk(sdp, meta_blocks, + sizeof(struct gfs_block_tag)) + + meta_blocks; + blocks += extra_blocks; + tr->tr_seg_reserved = gfs_blk2seg(sdp, blocks); + + error = gfs_log_reserve(sdp, tr->tr_seg_reserved, FALSE); + if (error) + goto fail_gunlock; + + gfs_assert(sdp, !get_transaction,); + set_transaction(tr); + + return 0; + + fail_gunlock: + gfs_glock_dq(tr->tr_t_gh); + + fail_holder_put: + gfs_holder_put(tr->tr_t_gh); + + fail: + kfree(tr); + + return error; +} + +/** + * gfs_trans_end - End a transaction + * @sdp: The GFS superblock + * + * If buffers were actually added to the transaction, + * commit it. + * + */ + +void +gfs_trans_end(struct gfs_sbd *sdp) +{ + struct gfs_trans *tr; + struct gfs_holder *t_gh; + struct list_head *tmp, *head; + struct gfs_log_element *le; + + /* Linux task struct indicates current new trans for this process. + * We're done building it, so set it to NULL */ + tr = get_transaction; + gfs_assert(sdp, tr,); + set_transaction(NULL); + + t_gh = tr->tr_t_gh; + tr->tr_t_gh = NULL; + + /* If no buffers were ever added to trans, forget it */ + if (list_empty(&tr->tr_elements)) { + gfs_log_release(sdp, tr->tr_seg_reserved); + kfree(tr); + + gfs_glock_dq(t_gh); + gfs_holder_put(t_gh); + + return; + } + + /* Do trans_end log-operation for each log element */ + for (head = &tr->tr_elements, tmp = head->next; + tmp != head; + tmp = tmp->next) { + le = list_entry(tmp, struct gfs_log_element, le_list); + LO_TRANS_END(sdp, le); + } + + gfs_log_commit(sdp, tr); + + gfs_glock_dq(t_gh); + gfs_holder_put(t_gh); + + if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS) + gfs_log_flush(sdp); +} + +/** + * gfs_trans_add_gl - Add a glock to a transaction + * @gl: the glock + * + * If not already attached, add the given glock to this process's transaction. + * + * Even though no glock info will be written to the on-disk log, the glocks + * associated with a transaction provide bridges by which to combine + * a just-built transaction with an earlier incore committed transaction + * that was protected by the same glock. See incore_commit(). + * Combining transactions makes for more efficient logging. + * + * Note that more than one glock may be associated with a single transaction. + * However, a given glock protects no more than *one* transaction at a + * given stage in the transaction pipeline (i.e. new or incore-committed). + * After all, the process holds the glock EX (so no other process can be + * building a separate trans protected by this glock), and the process can + * build only one transaction at a time. + * + * Rules: + * This process must hold the glock in EXclusive mode, since we're going + * to be writing to something protected by this glock. + */ + +void +gfs_trans_add_gl(struct gfs_glock *gl) +{ + if (!gl->gl_new_le.le_trans) { + gfs_assert_withdraw(gl->gl_sbd, + gfs_glock_is_locked_by_me(gl) && + gfs_glock_is_held_excl(gl)); + gfs_glock_hold(gl); /* Released in glock_trans_end() */ + + /* Ask for eventual flush of (meta)data protected by this glock, + once trans is complete and logged. */ + set_bit(GLF_DIRTY, &gl->gl_flags); + + /* Invoke generic_le_add() */ + LO_ADD(gl->gl_sbd, &gl->gl_new_le); + gl->gl_new_le.le_trans->tr_num_gl++; + } +} + +/** + * gfs_trans_add_bh - Add a to-be-modified buffer to the current transaction + * @gl: the glock the buffer belongs to + * @bh: The buffer to add + * + * Add a to-be-modified buffer to the current being-built (i.e. new) trans, + * and pin the buffer in memory. + * + * Caller must hold the glock protecting this buffer. + * + * Call this as many times as you want during transaction formation. It does + * its attachment work only once. After buffer is attached to trans, the + * process building the trans can modify the buffer again and again (calling + * this function before each change). Only the final result (within this trans) + * will be written to log. A good example is when allocating blocks in an RG, + * a given bitmap buffer may be updated many times within a transaction. + * + * Note: This final result will also be written to its in-place location, + * unless this transaction gets combined with a later transaction, + * in which case only the later result will go to in-place. + * + */ + +void +gfs_trans_add_bh(struct gfs_glock *gl, struct buffer_head *bh) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + struct gfs_bufdata *bd; + + /* Make sure GFS private info struct is attached to buffer head */ + bd = get_v2bd(bh); + if (!bd) { + gfs_attach_bufdata(bh, gl); + bd = get_v2bd(bh); + } + + /* If buffer has already been attached to trans, we're done */ + if (bd->bd_new_le.le_trans) + return; + + gfs_meta_check(sdp, bh); + + gfs_assert(sdp, bd->bd_gl == gl,); + + /* Make sure glock is attached to trans */ + if (!gl->gl_new_le.le_trans) + gfs_trans_add_gl(gl); + + gfs_dpin(sdp, bh); + + /* Attach buffer to trans */ + LO_ADD(sdp, &bd->bd_new_le); + bd->bd_new_le.le_trans->tr_num_buf++; +} + +/** + * gfs_trans_add_unlinked - Add an unlinked or dealloced tag to + * the current transaction + * @sdp: the filesystem + * @type: the type of entry + * @inum: the inode number + * + * Returns: the unlinked structure + */ + +struct gfs_unlinked * +gfs_trans_add_unlinked(struct gfs_sbd *sdp, unsigned int type, + struct gfs_inum *inum) +{ + struct gfs_unlinked *ul; + + /* Find in fileystem's unlinked list, or create */ + ul = gfs_unlinked_get(sdp, inum, CREATE); + + LO_ADD(sdp, &ul->ul_new_le); + + switch (type) { + case GFS_LOG_DESC_IUL: + set_bit(ULF_NEW_UL, &ul->ul_flags); + ul->ul_new_le.le_trans->tr_num_iul++; + break; + case GFS_LOG_DESC_IDA: + clear_bit(ULF_NEW_UL, &ul->ul_flags); + ul->ul_new_le.le_trans->tr_num_ida++; + break; + default: + gfs_assert(sdp, FALSE,); + break; + } + + return ul; +} + +/** + * gfs_trans_add_quota - Add quota changes to a transaction + * @sdp: the filesystem + * @change: The number of blocks allocated (positive) or freed (negative) + * @uid: the user ID doing the change + * @gid: the group ID doing the change + * + */ + +void +gfs_trans_add_quota(struct gfs_sbd *sdp, int64_t change, + uint32_t uid, uint32_t gid) +{ + struct gfs_trans *tr; + struct list_head *tmp, *head, *next; + struct gfs_log_element *le; + struct gfs_quota_le *ql; + int found_uid, found_gid; + int error; + + if (!gfs_tune_get(sdp, gt_quota_account)) + return; + if (gfs_assert_warn(sdp, change)) + return; + + found_uid = (uid == NO_QUOTA_CHANGE); + found_gid = (gid == NO_QUOTA_CHANGE); + + if (gfs_assert_warn(sdp, !found_uid || !found_gid)) + return; + + tr = get_transaction; + gfs_assert(sdp, tr,); + + for (head = &tr->tr_elements, tmp = head->next, next = tmp->next; + tmp != head; + tmp = next, next = next->next) { + le = list_entry(tmp, struct gfs_log_element, le_list); + if (le->le_ops != &gfs_quota_lops) + continue; + + ql = container_of(le, struct gfs_quota_le, ql_le); + + if (test_bit(QDF_USER, &ql->ql_data->qd_flags)) { + if (ql->ql_data->qd_id == uid) { + ql->ql_change += change; + + spin_lock(&sdp->sd_quota_lock); + ql->ql_data->qd_change_new += change; + spin_unlock(&sdp->sd_quota_lock); + + list_del(&le->le_list); + + if (ql->ql_change) + list_add(&le->le_list, + &tr->tr_elements); + else { + gfs_quota_put(sdp, ql->ql_data); + kfree(ql); + tr->tr_num_q--; + } + + gfs_assert(sdp, !found_uid,); + found_uid = TRUE; + if (found_gid) + break; + } + } else { + if (ql->ql_data->qd_id == gid) { + ql->ql_change += change; + + spin_lock(&sdp->sd_quota_lock); + ql->ql_data->qd_change_new += change; + spin_unlock(&sdp->sd_quota_lock); + + list_del(&le->le_list); + + if (ql->ql_change) + list_add(&le->le_list, + &tr->tr_elements); + else { + gfs_quota_put(sdp, ql->ql_data); + kfree(ql); + tr->tr_num_q--; + } + + gfs_assert(sdp, !found_gid,); + found_gid = TRUE; + if (found_uid) + break; + } + } + } + + while (!found_uid || !found_gid) { + ql = gmalloc(sizeof(struct gfs_quota_le)); + memset(ql, 0, sizeof(struct gfs_quota_le)); + + INIT_LE(&ql->ql_le, &gfs_quota_lops); + + if (found_uid) { + error = gfs_quota_get(sdp, FALSE, gid, + NO_CREATE, + &ql->ql_data); + found_gid = TRUE; + } else { + error = gfs_quota_get(sdp, TRUE, uid, + NO_CREATE, + &ql->ql_data); + found_uid = TRUE; + } + + gfs_assert(sdp, !error && ql->ql_data,); + + ql->ql_change = change; + + spin_lock(&sdp->sd_quota_lock); + ql->ql_data->qd_change_new += change; + spin_unlock(&sdp->sd_quota_lock); + + LO_ADD(sdp, &ql->ql_le); + tr->tr_num_q++; + } +} --- linux-2.6.27.orig/ubuntu/gfs/glock.c +++ linux-2.6.27/ubuntu/gfs/glock.c @@ -0,0 +1,2996 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "dio.h" +#include "glock.h" +#include "glops.h" +#include "inode.h" +#include "lm.h" +#include "lops.h" +#include "quota.h" +#include "recovery.h" + +/* Must be kept in sync with the beginning of struct gfs_glock */ +struct glock_plug { + struct list_head gl_list; + unsigned long gl_flags; +}; + +struct greedy { + struct gfs_holder gr_gh; + struct delayed_work gr_work; +}; + +typedef void (*glock_examiner) (struct gfs_glock * gl, unsigned int *cnt); + +/** + * relaxed_state_ok - is a requested lock compatible with the current lock mode? + * @actual: the current state of the lock + * @requested: the lock state that was requested by the caller + * @flags: the modifier flags passed in by the caller + * + * Returns: TRUE if the locks are compatible, FALSE otherwise + * + * It's often possible that a holder B may request the lock in SHARED mode, + * while another holder A (on this same node) has the lock in EXCLUSIVE mode + * (node must hold the glock in EXCLUSIVE mode for this situation, of course). + * This is okay to grant, in some cases, since both holders would have access + * to the in-core up-to-date cached data that the EX holder would write to disk. + * This is the default behavior. + * + * The EXACT flag disallows this behavior, though. A SHARED request would + * compatible only with a SHARED lock with this flag. + * + * The ANY flag provides broader permission to grant the lock to a holder, + * whatever the requested state is, as long as the lock is locked in any mode. + */ + +static __inline__ int +relaxed_state_ok(unsigned int actual, unsigned requested, int flags) +{ + if (actual == requested) + return TRUE; + + if (flags & GL_EXACT) + return FALSE; + + if (actual == LM_ST_EXCLUSIVE && requested == LM_ST_SHARED) + return TRUE; + + if (actual != LM_ST_UNLOCKED && (flags & LM_FLAG_ANY)) + return TRUE; + + return FALSE; +} + +/** + * gl_hash() - Turn glock number into hash bucket number + * @lock: The glock number + * + * Returns: The number of the corresponding hash bucket + */ + +static unsigned int +gl_hash(struct lm_lockname *name) +{ + unsigned int h; + + h = gfs_hash(&name->ln_number, sizeof(uint64_t)); + h = gfs_hash_more(&name->ln_type, sizeof(unsigned int), h); + h &= GFS_GL_HASH_MASK; + + return h; +} + +/** + * glock_hold() - increment reference count on glock + * @gl: The glock to hold + * + */ + +static __inline__ void +glock_hold(struct gfs_glock *gl) +{ + gfs_assert(gl->gl_sbd, atomic_read(&gl->gl_count) > 0,); + atomic_inc(&gl->gl_count); +} + +/** + * glock_put() - Decrement reference count on glock + * @gl: The glock to put + * + */ + +static __inline__ void +glock_put(struct gfs_glock *gl) +{ + if (atomic_read(&gl->gl_count) == 1) + gfs_glock_schedule_for_reclaim(gl); + gfs_assert(gl->gl_sbd, atomic_read(&gl->gl_count) > 0,); + atomic_dec(&gl->gl_count); +} + +/** + * queue_empty - check to see if a glock's queue is empty + * @gl: the glock + * @head: the head of the queue to check + * + * Returns: TRUE if the queue is empty + */ + +static __inline__ int +queue_empty(struct gfs_glock *gl, struct list_head *head) +{ + int empty; + spin_lock(&gl->gl_spin); + empty = list_empty(head); + spin_unlock(&gl->gl_spin); + return empty; +} + +/** + * search_bucket() - Find struct gfs_glock by lock number + * @bucket: the bucket to search + * @name: The lock name + * + * Returns: NULL, or the struct gfs_glock with the requested number + */ + +static struct gfs_glock * +search_bucket(struct gfs_gl_hash_bucket *bucket, struct lm_lockname *name) +{ + struct list_head *tmp, *head; + struct gfs_glock *gl; + + for (head = &bucket->hb_list, tmp = head->next; + tmp != head; + tmp = tmp->next) { + gl = list_entry(tmp, struct gfs_glock, gl_list); + + if (test_bit(GLF_PLUG, &gl->gl_flags)) + continue; + if (!lm_name_equal(&gl->gl_name, name)) + continue; + + atomic_inc(&gl->gl_count); + + return gl; + } + + return NULL; +} + +/** + * gfs_glock_find() - Find glock by lock number + * @sdp: The GFS superblock + * @name: The lock name + * + * Figure out what bucket the lock is in, acquire the read lock on + * it and call search_bucket(). + * + * Returns: NULL, or the struct gfs_glock with the requested number + */ + +struct gfs_glock * +gfs_glock_find(struct gfs_sbd *sdp, struct lm_lockname *name) +{ + struct gfs_gl_hash_bucket *bucket = &sdp->sd_gl_hash[gl_hash(name)]; + struct gfs_glock *gl; + + read_lock(&bucket->hb_lock); + gl = search_bucket(bucket, name); + read_unlock(&bucket->hb_lock); + + return gl; +} + +/** + * glock_free() - Perform a few checks and then release struct gfs_glock + * @gl: The glock to release + * + * Also calls lock module to release its internal structure for this glock. + * + */ + +static void +glock_free(struct gfs_glock *gl) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + struct inode *aspace = gl->gl_aspace; + + gfs_assert_warn(sdp, list_empty(&gl->gl_list)); + gfs_assert_warn(sdp, atomic_read(&gl->gl_count) == 1); + gfs_assert_warn(sdp, list_empty(&gl->gl_holders)); + gfs_assert_warn(sdp, list_empty(&gl->gl_waiters1)); + gfs_assert_warn(sdp, list_empty(&gl->gl_waiters2)); + gfs_assert_warn(sdp, list_empty(&gl->gl_waiters3)); + gfs_assert_warn(sdp, gl->gl_state == LM_ST_UNLOCKED); + gfs_assert_warn(sdp, !gl->gl_object); + gfs_assert_warn(sdp, !gl->gl_lvb); + gfs_assert_warn(sdp, list_empty(&gl->gl_reclaim)); + + gfs_lm_put_lock(sdp, gl->gl_lock); + + if (aspace) + gfs_aspace_put(aspace); + + kmem_cache_free(gfs_glock_cachep, gl); + + atomic_dec(&sdp->sd_glock_count); +} + +/** + * gfs_glock_get() - Get a glock, or create one if one doesn't exist + * @sdp: The GFS superblock + * @number: the lock number + * @glops: The glock_operations to use + * @create: If FALSE, don't create the glock if it doesn't exist + * @glp: the glock is returned here + * + * This does not lock a glock, just finds/creates structures for one. + * + * Returns: errno + */ + +int +gfs_glock_get(struct gfs_sbd *sdp, + uint64_t number, struct gfs_glock_operations *glops, + int create, struct gfs_glock **glp) +{ + struct lm_lockname name; + struct gfs_glock *gl, *tmp; + struct gfs_gl_hash_bucket *bucket; + int error; + + /* Look for pre-existing glock in hash table */ + name.ln_number = number; + name.ln_type = glops->go_type; + bucket = &sdp->sd_gl_hash[gl_hash(&name)]; + + read_lock(&bucket->hb_lock); + gl = search_bucket(bucket, &name); + read_unlock(&bucket->hb_lock); + + if (gl || !create) { + *glp = gl; + return 0; + } + + /* None found; create a new one */ + gl = kmem_cache_alloc(gfs_glock_cachep, GFP_KERNEL); + if (!gl) + return -ENOMEM; + + memset(gl, 0, sizeof(struct gfs_glock)); + + INIT_LIST_HEAD(&gl->gl_list); + gl->gl_name = name; + atomic_set(&gl->gl_count, 1); + + spin_lock_init(&gl->gl_spin); + + gl->gl_state = LM_ST_UNLOCKED; + INIT_LIST_HEAD(&gl->gl_holders); + INIT_LIST_HEAD(&gl->gl_waiters1); + INIT_LIST_HEAD(&gl->gl_waiters2); + INIT_LIST_HEAD(&gl->gl_waiters3); + + gl->gl_ops = glops; + + INIT_LE(&gl->gl_new_le, &gfs_glock_lops); + INIT_LE(&gl->gl_incore_le, &gfs_glock_lops); + + gl->gl_bucket = bucket; + INIT_LIST_HEAD(&gl->gl_reclaim); + + gl->gl_sbd = sdp; + + INIT_LIST_HEAD(&gl->gl_ail_bufs); + + /* If this glock protects actual on-disk data or metadata blocks, + create a VFS inode to manage the pages/buffers holding them. */ + if (glops == &gfs_inode_glops || + glops == &gfs_rgrp_glops || + glops == &gfs_meta_glops) { + gl->gl_aspace = gfs_aspace_get(sdp); + if (!gl->gl_aspace) { + error = -ENOMEM; + goto fail; + } + } + + /* Ask lock module to find/create its structure for this lock + (but this doesn't lock the inter-node lock yet) */ + error = gfs_lm_get_lock(sdp, &name, &gl->gl_lock); + if (error) + goto fail_aspace; + + atomic_inc(&sdp->sd_glock_count); + + /* Double-check, in case another process created the glock, and has + put it in the hash table while we were preparing this one */ + write_lock(&bucket->hb_lock); + tmp = search_bucket(bucket, &name); + if (tmp) { + /* Somebody beat us to it; forget the one we prepared */ + write_unlock(&bucket->hb_lock); + glock_free(gl); + gl = tmp; + } else { + /* Add our glock to hash table */ + list_add_tail(&gl->gl_list, &bucket->hb_list); + write_unlock(&bucket->hb_lock); + } + + *glp = gl; + + return 0; + + fail_aspace: + if (gl->gl_aspace) + gfs_aspace_put(gl->gl_aspace); + + fail: + kmem_cache_free(gfs_glock_cachep, gl); + + return error; +} + +/** + * gfs_glock_hold() - As glock_hold(), but suitable for exporting + * @gl: The glock to hold + * + */ + +void +gfs_glock_hold(struct gfs_glock *gl) +{ + glock_hold(gl); +} + +/** + * gfs_glock_put() - As glock_put(), but suitable for exporting + * @gl: The glock to put + * + */ + +void +gfs_glock_put(struct gfs_glock *gl) +{ + glock_put(gl); +} + +/** + * gfs_holder_init - initialize a struct gfs_holder in the default way + * @gl: the glock + * @state: the state we're requesting + * @flags: the modifier flags + * @gh: the holder structure + * + */ + +void +gfs_holder_init(struct gfs_glock *gl, unsigned int state, int flags, + struct gfs_holder *gh) +{ + memset(gh, 0, sizeof(struct gfs_holder)); + + INIT_LIST_HEAD(&gh->gh_list); + gh->gh_gl = gl; + gh->gh_owner = current; + gh->gh_state = state; + gh->gh_flags = flags; + + if (gh->gh_state == LM_ST_EXCLUSIVE) + gh->gh_flags |= GL_LOCAL_EXCL; + + init_completion(&gh->gh_wait); + + glock_hold(gl); +} + +/** + * gfs_holder_reinit - reinitialize a struct gfs_holder so we can requeue it + * @state: the state we're requesting + * @flags: the modifier flags + * @gh: the holder structure + * + * Preserve holder's associated glock and owning process. + * Reset all holder state flags (we're starting a new request from scratch), + * except for HIF_ALLOCED. + * Don't do glock_hold() again (it was done in gfs_holder_init()). + * Don't mess with the glock. + * + * Rules: + * Holder must have been gfs_holder_init()d already + * Holder must *not* be in glock's holder list or wait queues now + */ + +void +gfs_holder_reinit(unsigned int state, int flags, struct gfs_holder *gh) +{ + int alloced; + + gfs_assert_warn(gh->gh_gl->gl_sbd, + list_empty(&gh->gh_list)); + + gh->gh_state = state; + gh->gh_flags = flags; + + if (gh->gh_state == LM_ST_EXCLUSIVE) + gh->gh_flags |= GL_LOCAL_EXCL; + + alloced = test_bit(HIF_ALLOCED, &gh->gh_iflags); + memset(&gh->gh_iflags, 0, sizeof(unsigned long)); + if (alloced) + set_bit(HIF_ALLOCED, &gh->gh_iflags); +} + +/** + * gfs_holder_uninit - uninitialize a holder structure (drop reference on glock) + * @gh: the holder structure + * + */ + +void +gfs_holder_uninit(struct gfs_holder *gh) +{ + struct gfs_glock *gl = gh->gh_gl; + + gfs_assert_warn(gl->gl_sbd, list_empty(&gh->gh_list)); + gh->gh_gl = NULL; + + glock_put(gl); +} + +/** + * gfs_holder_get - get a struct gfs_holder structure + * @gl: the glock + * @state: the state we're requesting + * @flags: the modifier flags + * + * Figure out how big an impact this function has. Either: + * 1) Replace it with a cache of structures hanging off the struct gfs_sbd + * 2) Leave it like it is + * + * Returns: the holder structure, NULL on ENOMEM + */ + +struct gfs_holder * +gfs_holder_get(struct gfs_glock *gl, unsigned int state, int flags) +{ + struct gfs_holder *gh; + + gh = kmalloc(sizeof(struct gfs_holder), GFP_KERNEL); + if (!gh) + return NULL; + + gfs_holder_init(gl, state, flags, gh); + set_bit(HIF_ALLOCED, &gh->gh_iflags); + + return gh; +} + +/** + * gfs_holder_put - get rid of a struct gfs_holder structure + * @gh: the holder structure + * + */ + +void +gfs_holder_put(struct gfs_holder *gh) +{ + if (gfs_assert_warn(gh->gh_gl->gl_sbd, + test_bit(HIF_ALLOCED, &gh->gh_iflags))) + return; + gfs_holder_uninit(gh); + kfree(gh); +} + +/** + * handle_recurse - put other holder structures (marked recursive) into the holders list + * @gh: the holder structure + * + */ + +static void +handle_recurse(struct gfs_holder *gh) +{ + struct gfs_glock *gl = gh->gh_gl; + struct gfs_sbd *sdp = gl->gl_sbd; + struct list_head *tmp, *head, *next; + struct gfs_holder *tmp_gh; + int found = FALSE; + + if (gfs_assert_warn(sdp, gh->gh_owner)) + return; + + for (head = &gl->gl_waiters3, tmp = head->next, next = tmp->next; + tmp != head; + tmp = next, next = tmp->next) { + tmp_gh = list_entry(tmp, struct gfs_holder, gh_list); + if (tmp_gh->gh_owner != gh->gh_owner) + continue; + + gfs_assert_warn(sdp, test_bit(HIF_RECURSE, &tmp_gh->gh_iflags)); + + list_move_tail(&tmp_gh->gh_list, &gl->gl_holders); + tmp_gh->gh_error = 0; + set_bit(HIF_HOLDER, &tmp_gh->gh_iflags); + + complete(&tmp_gh->gh_wait); + + found = TRUE; + } + + gfs_assert_warn(sdp, found); +} + +/** + * do_unrecurse - a recursive holder was just dropped of the waiters3 list + * @gh: the holder + * + * If there is only one other recursive holder, clear its HIF_RECURSE bit + * (it's no longer a recursive request). + * If there is more than one, leave them alone (they're recursive!). + * + */ + +static void +do_unrecurse(struct gfs_holder *gh) +{ + struct gfs_glock *gl = gh->gh_gl; + struct gfs_sbd *sdp = gl->gl_sbd; + struct list_head *tmp, *head; + struct gfs_holder *tmp_gh, *last_gh = NULL; + int found = FALSE; + + if (gfs_assert_warn(sdp, gh->gh_owner)) + return; + + for (head = &gl->gl_waiters3, tmp = head->next; + tmp != head; + tmp = tmp->next) { + tmp_gh = list_entry(tmp, struct gfs_holder, gh_list); + if (tmp_gh->gh_owner != gh->gh_owner) + continue; + + gfs_assert_warn(sdp, test_bit(HIF_RECURSE, &tmp_gh->gh_iflags)); + + /* found more than one */ + if (found) + return; + + found = TRUE; + last_gh = tmp_gh; + } + + /* found just one */ + if (!gfs_assert_warn(sdp, found)) + clear_bit(HIF_RECURSE, &last_gh->gh_iflags); +} + +/** + * rq_mutex - process a mutex request in the queue + * @gh: the glock holder + * + * Returns: TRUE if the queue is blocked (always, since there can be only one + * holder of the mutex). + * + * See lock_on_glock() + */ + +static int +rq_mutex(struct gfs_holder *gh) +{ + struct gfs_glock *gl = gh->gh_gl; + + list_del_init(&gh->gh_list); + /* gh->gh_error never examined. */ + set_bit(GLF_LOCK, &gl->gl_flags); + complete(&gh->gh_wait); + + return TRUE; +} + +/** + * rq_promote - process a promote request in the queue + * @gh: the glock holder + * + * Acquire a new inter-node lock, or change a lock state to more restrictive. + * + * Returns: TRUE if the queue is blocked + */ + +static int +rq_promote(struct gfs_holder *gh) +{ + struct gfs_glock *gl = gh->gh_gl; + struct gfs_sbd *sdp = gl->gl_sbd; + struct gfs_glock_operations *glops = gl->gl_ops; + int recurse; + + if (!relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) { + if (list_empty(&gl->gl_holders)) { + gl->gl_req_gh = gh; + set_bit(GLF_LOCK, &gl->gl_flags); + spin_unlock(&gl->gl_spin); + + /* If we notice a lot of glocks in reclaim list, free + up memory for 2 of them before locking a new one */ + if (atomic_read(&sdp->sd_reclaim_count) > + gfs_tune_get(sdp, gt_reclaim_limit) && + !(gh->gh_flags & LM_FLAG_PRIORITY)) { + gfs_reclaim_glock(sdp); + gfs_reclaim_glock(sdp); + } + + glops->go_xmote_th(gl, gh->gh_state, + gh->gh_flags); + + spin_lock(&gl->gl_spin); + } + return TRUE; + } + + if (list_empty(&gl->gl_holders)) { + set_bit(HIF_FIRST, &gh->gh_iflags); + set_bit(GLF_LOCK, &gl->gl_flags); + recurse = FALSE; + } else { + struct gfs_holder *next_gh; + if (gh->gh_flags & GL_LOCAL_EXCL) + return TRUE; + next_gh = list_entry(gl->gl_holders.next, struct gfs_holder, gh_list); + if (next_gh->gh_flags & GL_LOCAL_EXCL) + return TRUE; + recurse = test_bit(HIF_RECURSE, &gh->gh_iflags); + } + + list_move_tail(&gh->gh_list, &gl->gl_holders); + gh->gh_error = 0; + set_bit(HIF_HOLDER, &gh->gh_iflags); + + if (recurse) + handle_recurse(gh); + + complete(&gh->gh_wait); + + return FALSE; +} + +/** + * rq_demote - process a demote request in the queue + * @gh: the glock holder + * + * Returns: TRUE if the queue is blocked + * + * Unlock an inter-node lock, or change a lock state to less restrictive. + * If the glock is already the same as the holder's requested state, or is + * UNLOCKED, no lock module request is required. + * Otherwise, we need to ask lock module to unlock or change locked state + * of the glock. + * If requested state is UNLOCKED, or current glock state is SHARED or + * DEFERRED (neither of which have a less restrictive state other than + * UNLOCK), we call go_drop_th() to unlock the lock. + * Otherwise (i.e. requested is SHARED or DEFERRED, and current is EXCLUSIVE), + * we can continue to hold the lock, and just ask for a new state; + * we call go_xmote_th() to change state. + * + * Must be called with glock's gl->gl_spin locked. + */ + +static int +rq_demote(struct gfs_holder *gh) +{ + struct gfs_glock *gl = gh->gh_gl; + struct gfs_glock_operations *glops = gl->gl_ops; + + if (!list_empty(&gl->gl_holders)) + return TRUE; + + if (gl->gl_state == gh->gh_state || gl->gl_state == LM_ST_UNLOCKED) { + list_del_init(&gh->gh_list); + gh->gh_error = 0; + spin_unlock(&gl->gl_spin); + if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) + gfs_holder_put(gh); + else + complete(&gh->gh_wait); + spin_lock(&gl->gl_spin); + } else { + gl->gl_req_gh = gh; + set_bit(GLF_LOCK, &gl->gl_flags); + spin_unlock(&gl->gl_spin); + + if (gh->gh_state == LM_ST_UNLOCKED || + gl->gl_state != LM_ST_EXCLUSIVE) + /* Unlock */ + glops->go_drop_th(gl); + else + /* Change state while holding lock */ + glops->go_xmote_th(gl, gh->gh_state, gh->gh_flags); + + spin_lock(&gl->gl_spin); + } + + return FALSE; +} + +/** + * rq_greedy - process a queued request to drop greedy status + * @gh: the glock holder + * + * Returns: TRUE if the queue is blocked + */ + +static int +rq_greedy(struct gfs_holder *gh) +{ + struct gfs_glock *gl = gh->gh_gl; + + list_del_init(&gh->gh_list); + /* gh->gh_error never examined. */ + clear_bit(GLF_GREEDY, &gl->gl_flags); + spin_unlock(&gl->gl_spin); + + gfs_holder_uninit(gh); + kfree(container_of(gh, struct greedy, gr_gh)); + + spin_lock(&gl->gl_spin); + + return FALSE; +} + +/** + * run_queue - process holder structures on the glock's wait queues + * @gl: the glock + * + * Rules: + * Caller must hold gl->gl_spin. + */ + +static void +run_queue(struct gfs_glock *gl) +{ + struct gfs_holder *gh; + int blocked = TRUE; + + for (;;) { + /* Another process is manipulating the glock structure; + we can't do anything now */ + if (test_bit(GLF_LOCK, &gl->gl_flags)) + break; + + /* Waiting to manipulate the glock structure */ + if (!list_empty(&gl->gl_waiters1)) { + gh = list_entry(gl->gl_waiters1.next, + struct gfs_holder, gh_list); + + if (test_bit(HIF_MUTEX, &gh->gh_iflags)) + blocked = rq_mutex(gh); + else + gfs_assert_warn(gl->gl_sbd, FALSE); + + /* Waiting to demote the lock, or drop greedy status */ + } else if (!list_empty(&gl->gl_waiters2) && + !test_bit(GLF_SKIP_WAITERS2, &gl->gl_flags)) { + gh = list_entry(gl->gl_waiters2.next, + struct gfs_holder, gh_list); + + if (test_bit(HIF_DEMOTE, &gh->gh_iflags)) + blocked = rq_demote(gh); + else if (test_bit(HIF_GREEDY, &gh->gh_iflags)) + blocked = rq_greedy(gh); + else + gfs_assert_warn(gl->gl_sbd, FALSE); + + /* Waiting to promote the lock */ + } else if (!list_empty(&gl->gl_waiters3)) { + gh = list_entry(gl->gl_waiters3.next, + struct gfs_holder, gh_list); + + if (test_bit(HIF_PROMOTE, &gh->gh_iflags)) + blocked = rq_promote(gh); + else + gfs_assert_warn(gl->gl_sbd, FALSE); + + } else + break; + + if (blocked) + break; + } +} + +/** + * lock_on_glock - acquire a local lock on a glock (structure) + * @gl: the glock + * + * Gives caller exclusive access to manipulate a glock structure. + * Has nothing to do with inter-node lock state or GL_LOCAL_EXCL! + * + * If structure already locked, places temporary holder structure on glock's + * wait-for-exclusive-access queue, and blocks until exclusive access granted. + */ + +static void +lock_on_glock(struct gfs_glock *gl) +{ + struct gfs_holder gh; + + gfs_holder_init(gl, 0, 0, &gh); + set_bit(HIF_MUTEX, &gh.gh_iflags); + + spin_lock(&gl->gl_spin); + if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) + list_add_tail(&gh.gh_list, &gl->gl_waiters1); + else + complete(&gh.gh_wait); + spin_unlock(&gl->gl_spin); + + wait_for_completion(&gh.gh_wait); + gfs_holder_uninit(&gh); +} + +/** + * trylock_on_glock - try to acquire a local lock on a glock (structure) + * @gl: the glock + * + * Returns: TRUE if the glock is acquired + * + * Tries to give caller exclusive access to manipulate a glock structure. + * Has nothing to do with inter-node lock state or LOCAL_EXCL! + * + * If structure already locked, does not block to wait; returns FALSE. + */ + +static int +trylock_on_glock(struct gfs_glock *gl) +{ + int acquired = TRUE; + + spin_lock(&gl->gl_spin); + if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) + acquired = FALSE; + spin_unlock(&gl->gl_spin); + + return acquired; +} + +/** + * unlock_on_glock - release a local lock on a glock (structure) + * @gl: the glock + * + * Caller is done manipulating glock structure. + * Service any others waiting for exclusive access. + */ + +static void +unlock_on_glock(struct gfs_glock *gl) +{ + spin_lock(&gl->gl_spin); + clear_bit(GLF_LOCK, &gl->gl_flags); + run_queue(gl); + spin_unlock(&gl->gl_spin); +} + +/** + * handle_callback - add a demote request to a lock's queue + * @gl: the glock + * @state: the state the caller wants us to change to + * + * Called when we learn that another node needs a lock held by this node, + * or when this node simply wants to drop a lock as soon as it's done with + * it (NOCACHE flag), or dump a glock out of glock cache (reclaim it). + * + * We are told the @state that will satisfy the needs of the caller, so + * we can ask for a demote to that state. + * + * If another demote request is already on the queue for a different state, just + * set its request to UNLOCK (and don't bother queueing a request for us). + * This consolidates LM requests and moves the lock to the least restrictive + * state, so it will be compatible with whatever reason we were called. + * No need to be too smart here. Demotes between the shared and deferred + * states will often fail, so don't even try. + * + * Otherwise, queue a demote request to the requested state. + */ + +static void +handle_callback(struct gfs_glock *gl, unsigned int state) +{ + struct list_head *tmp, *head; + struct gfs_holder *gh, *new_gh = NULL; + + if (gfs_assert_warn(gl->gl_sbd, state != LM_ST_EXCLUSIVE)) + return; + + restart: + spin_lock(&gl->gl_spin); + + /* If another queued demote request is for a different state, + set its request to UNLOCKED */ + for (head = &gl->gl_waiters2, tmp = head->next; + tmp != head; + tmp = tmp->next) { + gh = list_entry(tmp, struct gfs_holder, gh_list); + if (test_bit(HIF_DEMOTE, &gh->gh_iflags) && + gl->gl_req_gh != gh) { + if (gh->gh_state != state) + gh->gh_state = LM_ST_UNLOCKED; + goto out; + } + } + + /* pass 2; add new holder to glock's demote request queue */ + if (new_gh) { + list_add_tail(&new_gh->gh_list, &gl->gl_waiters2); + new_gh = NULL; + + /* pass 1; set up a new holder struct for a demote request, then + check again to see if another process added a demote request + while we were preparing this one. */ + } else { + spin_unlock(&gl->gl_spin); + + RETRY_MALLOC(new_gh = gfs_holder_get(gl, state, LM_FLAG_TRY), + new_gh); + set_bit(HIF_DEMOTE, &new_gh->gh_iflags); + set_bit(HIF_DEALLOC, &new_gh->gh_iflags); + new_gh->gh_owner = NULL; + + goto restart; + } + + out: + spin_unlock(&gl->gl_spin); + + if (new_gh) + gfs_holder_put(new_gh); +} + +/** + * state_change - record that the glock is now in a different state + * @gl: the glock + * @new_state the new state + * + */ + +static void +state_change(struct gfs_glock *gl, unsigned int new_state) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + int held1, held2; + + held1 = (gl->gl_state != LM_ST_UNLOCKED); + held2 = (new_state != LM_ST_UNLOCKED); + + if (held1 != held2) { + if (held2) { + atomic_inc(&sdp->sd_glock_held_count); + glock_hold(gl); + } else { + atomic_dec(&sdp->sd_glock_held_count); + glock_put(gl); + } + } + + gl->gl_state = new_state; +} + +/** + * xmote_bh - Called after the lock module is done acquiring a lock + * @gl: The glock in question + * @ret: the int returned from the lock module + * + */ + +static void +xmote_bh(struct gfs_glock *gl, unsigned int ret) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + struct gfs_glock_operations *glops = gl->gl_ops; + struct gfs_holder *gh = gl->gl_req_gh; + int prev_state = gl->gl_state; + int op_done = TRUE; + + gfs_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); + gfs_assert_warn(sdp, queue_empty(gl, &gl->gl_holders)); + gfs_assert_warn(sdp, !(ret & LM_OUT_ASYNC)); + + state_change(gl, ret & LM_OUT_ST_MASK); + + if (prev_state != LM_ST_UNLOCKED && !(ret & LM_OUT_CACHEABLE)) { + if (glops->go_inval) + glops->go_inval(gl, DIO_METADATA | DIO_DATA); + } else if (gl->gl_state == LM_ST_DEFERRED) { + /* We might not want to do this here. + Look at moving to the inode glops. */ + if (glops->go_inval) + glops->go_inval(gl, DIO_DATA); + } + + /* Deal with each possible exit condition */ + + if (!gh) + gl->gl_stamp = jiffies; + + else if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) { + spin_lock(&gl->gl_spin); + list_del_init(&gh->gh_list); + gh->gh_error = -EIO; + if (test_bit(HIF_RECURSE, &gh->gh_iflags)) + do_unrecurse(gh); + spin_unlock(&gl->gl_spin); + + } else if (test_bit(HIF_DEMOTE, &gh->gh_iflags)) { + spin_lock(&gl->gl_spin); + list_del_init(&gh->gh_list); + if (gl->gl_state == gh->gh_state || + gl->gl_state == LM_ST_UNLOCKED) + gh->gh_error = 0; + else { + if (gfs_assert_warn(sdp, gh->gh_flags & + (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) == -1) + printk("GFS: fsid=%s: ret = 0x%.8X\n", + sdp->sd_fsname, ret); + gh->gh_error = GLR_TRYFAILED; + } + spin_unlock(&gl->gl_spin); + + if (ret & LM_OUT_CANCELED) + handle_callback(gl, LM_ST_UNLOCKED); /* Lame */ + + } else if (ret & LM_OUT_CANCELED) { + spin_lock(&gl->gl_spin); + list_del_init(&gh->gh_list); + gh->gh_error = GLR_CANCELED; + if (test_bit(HIF_RECURSE, &gh->gh_iflags)) + do_unrecurse(gh); + spin_unlock(&gl->gl_spin); + + } else if (relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) { + spin_lock(&gl->gl_spin); + list_move_tail(&gh->gh_list, &gl->gl_holders); + gh->gh_error = 0; + set_bit(HIF_HOLDER, &gh->gh_iflags); + spin_unlock(&gl->gl_spin); + + set_bit(HIF_FIRST, &gh->gh_iflags); + + op_done = FALSE; + + } else if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) { + spin_lock(&gl->gl_spin); + list_del_init(&gh->gh_list); + gh->gh_error = GLR_TRYFAILED; + if (test_bit(HIF_RECURSE, &gh->gh_iflags)) + do_unrecurse(gh); + spin_unlock(&gl->gl_spin); + + } else { + if (gfs_assert_withdraw(sdp, FALSE) == -1) + printk("GFS: fsid=%s: ret = 0x%.8X\n", + sdp->sd_fsname, ret); + } + + if (glops->go_xmote_bh) + glops->go_xmote_bh(gl); + + if (op_done) { + spin_lock(&gl->gl_spin); + gl->gl_req_gh = NULL; + gl->gl_req_bh = NULL; + clear_bit(GLF_LOCK, &gl->gl_flags); + run_queue(gl); + spin_unlock(&gl->gl_spin); + } + + glock_put(gl); + + if (gh) { + if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) + gfs_holder_put(gh); + else + complete(&gh->gh_wait); + } +} + +/** + * gfs_glock_xmote_th - Call into the lock module to acquire or change a glock + * @gl: The glock in question + * @state: the requested state + * @flags: modifier flags to the lock call + * + * Used to acquire a new glock, or to change an already-acquired glock to + * more/less restrictive state (other than LM_ST_UNLOCKED). + * + * *Not* used to unlock a glock; use gfs_glock_drop_th() for that. + */ + +void +gfs_glock_xmote_th(struct gfs_glock *gl, unsigned int state, int flags) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + struct gfs_glock_operations *glops = gl->gl_ops; + int lck_flags = flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB | + LM_FLAG_NOEXP | LM_FLAG_ANY | + LM_FLAG_PRIORITY); + unsigned int lck_ret; + + gfs_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); + gfs_assert_warn(sdp, queue_empty(gl, &gl->gl_holders)); + gfs_assert_warn(sdp, state != LM_ST_UNLOCKED); + gfs_assert_warn(sdp, state != gl->gl_state); + + /* Current state EX, may need to sync log/data/metadata to disk */ + if (gl->gl_state == LM_ST_EXCLUSIVE) { + if (glops->go_sync) + glops->go_sync(gl, DIO_METADATA | DIO_DATA); + } + + glock_hold(gl); + gl->gl_req_bh = xmote_bh; + + atomic_inc(&sdp->sd_lm_lock_calls); + + lck_ret = gfs_lm_lock(sdp, gl->gl_lock, + gl->gl_state, state, + lck_flags); + + if (gfs_assert_withdraw(sdp, !(lck_ret & LM_OUT_ERROR))) + goto out; + + if (lck_ret & LM_OUT_ASYNC) + gfs_assert_warn(sdp, lck_ret == LM_OUT_ASYNC); + else + xmote_bh(gl, lck_ret); + out: + return; +} + +/** + * drop_bh - Called after a lock module unlock completes + * @gl: the glock + * @ret: the return status + * + * Doesn't wake up the process waiting on the struct gfs_holder (if any) + * Doesn't drop the reference on the glock the top half took out + * + */ + +static void +drop_bh(struct gfs_glock *gl, unsigned int ret) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + struct gfs_glock_operations *glops = gl->gl_ops; + struct gfs_holder *gh = gl->gl_req_gh; + + clear_bit(GLF_PREFETCH, &gl->gl_flags); + + gfs_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); + gfs_assert_warn(sdp, queue_empty(gl, &gl->gl_holders)); + gfs_assert_warn(sdp, !ret); + + state_change(gl, LM_ST_UNLOCKED); + + if (glops->go_inval) + glops->go_inval(gl, DIO_METADATA | DIO_DATA); + + if (gh) { + spin_lock(&gl->gl_spin); + list_del_init(&gh->gh_list); + gh->gh_error = 0; + spin_unlock(&gl->gl_spin); + } + + if (glops->go_drop_bh) + glops->go_drop_bh(gl); + + spin_lock(&gl->gl_spin); + gl->gl_req_gh = NULL; + gl->gl_req_bh = NULL; + clear_bit(GLF_LOCK, &gl->gl_flags); + run_queue(gl); + spin_unlock(&gl->gl_spin); + + glock_put(gl); + + if (gh) { + if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) + gfs_holder_put(gh); + else + complete(&gh->gh_wait); + } +} + +/** + * gfs_glock_drop_th - call into the lock module to unlock a lock + * @gl: the glock + * + */ + +void +gfs_glock_drop_th(struct gfs_glock *gl) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + struct gfs_glock_operations *glops = gl->gl_ops; + unsigned int ret; + + gfs_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); + gfs_assert_warn(sdp, queue_empty(gl, &gl->gl_holders)); + gfs_assert_warn(sdp, gl->gl_state != LM_ST_UNLOCKED); + + /* Leaving state EX, may need to sync log/data/metadata to disk */ + if (gl->gl_state == LM_ST_EXCLUSIVE) { + if (glops->go_sync) + glops->go_sync(gl, DIO_METADATA | DIO_DATA); + } + + glock_hold(gl); + gl->gl_req_bh = drop_bh; + + atomic_inc(&sdp->sd_lm_unlock_calls); + + ret = gfs_lm_unlock(sdp, gl->gl_lock, gl->gl_state); + + if (gfs_assert_withdraw(sdp, !(ret & LM_OUT_ERROR))) + goto out; + + if (!ret) + drop_bh(gl, ret); + else + gfs_assert_warn(sdp, ret == LM_OUT_ASYNC); + out: + return; +} + +/** + * do_cancels - cancel requests for locks stuck waiting on an expire flag + * @gh: the LM_FLAG_PRIORITY holder waiting to acquire the lock + * + * Don't cancel GL_NOCANCEL requests. + */ + +static void +do_cancels(struct gfs_holder *gh) +{ + struct gfs_glock *gl = gh->gh_gl; + + spin_lock(&gl->gl_spin); + + while (gl->gl_req_gh != gh && + !test_bit(HIF_HOLDER, &gh->gh_iflags) && + !list_empty(&gh->gh_list)) { + if (gl->gl_req_bh && + !(gl->gl_req_gh && + (gl->gl_req_gh->gh_flags & GL_NOCANCEL))) { + spin_unlock(&gl->gl_spin); + gfs_lm_cancel(gl->gl_sbd, gl->gl_lock); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 10); + spin_lock(&gl->gl_spin); + } else { + spin_unlock(&gl->gl_spin); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 10); + spin_lock(&gl->gl_spin); + } + } + + spin_unlock(&gl->gl_spin); +} + +/** + * glock_wait_internal - wait on a glock acquisition + * @gh: the glock holder + * + * Returns: 0 on success + */ + +static int +glock_wait_internal(struct gfs_holder *gh) +{ + struct gfs_glock *gl = gh->gh_gl; + struct gfs_sbd *sdp = gl->gl_sbd; + struct gfs_glock_operations *glops = gl->gl_ops; + int error = 0; + + if (test_bit(HIF_ABORTED, &gh->gh_iflags)) + return -EIO; + + if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) { + spin_lock(&gl->gl_spin); + if (gl->gl_req_gh != gh && + !test_bit(HIF_HOLDER, &gh->gh_iflags) && + !list_empty(&gh->gh_list)) { + list_del_init(&gh->gh_list); + gh->gh_error = GLR_TRYFAILED; + if (test_bit(HIF_RECURSE, &gh->gh_iflags)) + do_unrecurse(gh); + run_queue(gl); + spin_unlock(&gl->gl_spin); + return GLR_TRYFAILED; + } + spin_unlock(&gl->gl_spin); + } + + if ((gh->gh_flags & LM_FLAG_PRIORITY) && + !(gh->gh_flags & GL_NOCANCEL_OTHER)) + do_cancels(gh); + + wait_for_completion(&gh->gh_wait); + + if (gh->gh_error) + return gh->gh_error; + + gfs_assert_withdraw(sdp, test_bit(HIF_HOLDER, &gh->gh_iflags)); + gfs_assert_withdraw(sdp, relaxed_state_ok(gl->gl_state, + gh->gh_state, + gh->gh_flags)); + + if (test_bit(HIF_FIRST, &gh->gh_iflags)) { + gfs_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); + + if (glops->go_lock) { + error = glops->go_lock(gl, gh->gh_flags); + if (error) { + spin_lock(&gl->gl_spin); + list_del_init(&gh->gh_list); + gh->gh_error = error; + if (test_and_clear_bit(HIF_RECURSE, &gh->gh_iflags)) + do_unrecurse(gh); + spin_unlock(&gl->gl_spin); + } + } + + spin_lock(&gl->gl_spin); + gl->gl_req_gh = NULL; + gl->gl_req_bh = NULL; + clear_bit(GLF_LOCK, &gl->gl_flags); + if (test_bit(HIF_RECURSE, &gh->gh_iflags)) + handle_recurse(gh); + run_queue(gl); + spin_unlock(&gl->gl_spin); + } + + return error; +} + +/** + * add_to_queue - Add a holder to the wait-for-promotion queue or holder list + * (according to recursion) + * @gh: the holder structure to add + * + * If the hold requestor's process already has a granted lock (on holder list), + * and this new request is compatible, go ahead and grant it, adding this + * new holder to the glock's holder list. + * + * If the hold requestor's process has earlier requested a lock, and is still + * waiting for it to be granted, and this new request is compatible with + * the earlier one, they can be handled at the same time when the request + * is finally granted. Mark both (all) with RECURSE flags, and add new + * holder to wait-for-promotion queue. + * + * If there is no previous holder from this process (on holder list or wait- + * for-promotion queue), simply add new holder to wait-for-promotion queue. + */ + +static void +add_to_queue(struct gfs_holder *gh) +{ + struct gfs_glock *gl = gh->gh_gl; + struct gfs_sbd *sdp = gl->gl_sbd; + struct list_head *tmp, *head; + struct gfs_holder *tmp_gh; + + if (gh->gh_owner) { + /* Search through glock's holders list to see if this process + already holds a granted lock. */ + for (head = &gl->gl_holders, tmp = head->next; + tmp != head; + tmp = tmp->next) { + tmp_gh = list_entry(tmp, struct gfs_holder, gh_list); + if (tmp_gh->gh_owner == gh->gh_owner) { + /* Make sure pre-existing holder is compatible + with this new one. */ + if (gfs_assert_warn(sdp, (gh->gh_flags & LM_FLAG_ANY) || + !(tmp_gh->gh_flags & LM_FLAG_ANY)) || + gfs_assert_warn(sdp, (tmp_gh->gh_flags & GL_LOCAL_EXCL) || + !(gh->gh_flags & GL_LOCAL_EXCL)) || + gfs_assert_warn(sdp, relaxed_state_ok(gl->gl_state, + gh->gh_state, + gh->gh_flags))) + goto fail; + + /* We're good! Grant the hold. */ + list_add_tail(&gh->gh_list, &gl->gl_holders); + set_bit(HIF_HOLDER, &gh->gh_iflags); + + gh->gh_error = 0; + complete(&gh->gh_wait); + + return; + } + } + + /* If not, Search through glock's wait-for-promotion list to + see if this process already is waiting for a grant. */ + for (head = &gl->gl_waiters3, tmp = head->next; + tmp != head; + tmp = tmp->next) { + tmp_gh = list_entry(tmp, struct gfs_holder, gh_list); + if (tmp_gh->gh_owner == gh->gh_owner) { + /* Yes, make sure it is compatible with new */ + if (gfs_assert_warn(sdp, test_bit(HIF_PROMOTE, + &tmp_gh->gh_iflags)) || + gfs_assert_warn(sdp, (gh->gh_flags & LM_FLAG_ANY) || + !(tmp_gh->gh_flags & LM_FLAG_ANY)) || + gfs_assert_warn(sdp, (tmp_gh->gh_flags & GL_LOCAL_EXCL) || + !(gh->gh_flags & GL_LOCAL_EXCL)) || + gfs_assert_warn(sdp, relaxed_state_ok(tmp_gh->gh_state, + gh->gh_state, + gh->gh_flags))) + goto fail; + + /* OK, make sure they're marked, so + * when one gets granted, the other will too. */ + set_bit(HIF_RECURSE, &gh->gh_iflags); + set_bit(HIF_RECURSE, &tmp_gh->gh_iflags); + + list_add_tail(&gh->gh_list, &gl->gl_waiters3); + + return; + } + } + } + + /* Else, no recursion ... + If high priority request, add to head of promote queue, else tail */ + if (gh->gh_flags & LM_FLAG_PRIORITY) + list_add(&gh->gh_list, &gl->gl_waiters3); + else + list_add_tail(&gh->gh_list, &gl->gl_waiters3); + + return; + + fail: + set_bit(HIF_ABORTED, &gh->gh_iflags); +} + +/** + * gfs_glock_nq - enqueue a struct gfs_holder onto a glock (acquire a glock) + * @gh: the holder structure + * + * if (gh->gh_flags & GL_ASYNC), this never returns an error + * + * Returns: 0, GLR_TRYFAILED, or errno on failure + * + * Rules: + * @gh must not be already attached to a glock. + * Don't ask for UNLOCKED state (use gfs_glock_dq() for that). + * LM_FLAG_ANY (liberal) and GL_EXACT (restrictive) are mutually exclusive. + */ + +int +gfs_glock_nq(struct gfs_holder *gh) +{ + struct gfs_glock *gl = gh->gh_gl; + struct gfs_sbd *sdp = gl->gl_sbd; + int error = 0; + + atomic_inc(&sdp->sd_glock_nq_calls); + + restart: + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) || + gfs_assert_warn(sdp, list_empty(&gh->gh_list)) || + gfs_assert_warn(sdp, gh->gh_state != LM_ST_UNLOCKED) || + gfs_assert_warn(sdp, (gh->gh_flags & (LM_FLAG_ANY | GL_EXACT)) != + (LM_FLAG_ANY | GL_EXACT))) { + set_bit(HIF_ABORTED, &gh->gh_iflags); + return -EIO; + } + + set_bit(HIF_PROMOTE, &gh->gh_iflags); + + spin_lock(&gl->gl_spin); + add_to_queue(gh); + run_queue(gl); + spin_unlock(&gl->gl_spin); + + if (!(gh->gh_flags & GL_ASYNC)) { + error = glock_wait_internal(gh); + if (error == GLR_CANCELED) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + goto restart; + } + } + + clear_bit(GLF_PREFETCH, &gl->gl_flags); + + return error; +} + +/** + * gfs_glock_poll - poll to see if an async request has been completed + * @gh: the holder + * + * Returns: TRUE if the request is ready to be gfs_glock_wait()ed on + */ + +int +gfs_glock_poll(struct gfs_holder *gh) +{ + struct gfs_glock *gl = gh->gh_gl; + int ready = FALSE; + + gfs_assert_warn(gl->gl_sbd, gh->gh_flags & GL_ASYNC); + + spin_lock(&gl->gl_spin); + + if (test_bit(HIF_HOLDER, &gh->gh_iflags)) + ready = TRUE; + else if (list_empty(&gh->gh_list)) { + if (gh->gh_error == GLR_CANCELED) { + spin_unlock(&gl->gl_spin); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + if (gfs_glock_nq(gh)) + return TRUE; + return FALSE; + } else + ready = TRUE; + } + + spin_unlock(&gl->gl_spin); + + return ready; +} + +/** + * gfs_glock_wait - wait for a lock acquisition that ended in a GLR_ASYNC + * @gh: the holder structure + * + * Returns: 0, GLR_TRYFAILED, or errno on failure + */ + +int +gfs_glock_wait(struct gfs_holder *gh) +{ + struct gfs_glock *gl = gh->gh_gl; + int error; + + gfs_assert_warn(gl->gl_sbd, gh->gh_flags & GL_ASYNC); + + error = glock_wait_internal(gh); + if (error == GLR_CANCELED) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + gh->gh_flags &= ~GL_ASYNC; + error = gfs_glock_nq(gh); + } + + return error; +} + +/** + * gfs_glock_dq - dequeue a struct gfs_holder from a glock (release a glock) + * @gh: the glock holder + * + * This releases a local process' hold on a glock, and services other waiters. + * If this is the last holder on this node, calls glock operation go_unlock(), + * and go_sync() if requested by glock's GL_SYNC flag. + * If glock's GL_NOCACHE flag is set, requests demotion to unlock the inter- + * node lock now, rather than caching the glock for later use. + * Otherwise, this function does *not* release the glock at inter-node scope. + * The glock will stay in glock cache until: + * -- This node uses it again (extending residence in glock cache), or + * -- Another node asks (via callback) for the lock, or + * -- The glock sits unused in glock cache for a while, and the cleanup + * daemons (gfs_scand and gfs_glockd) reclaim it. + */ + +void +gfs_glock_dq(struct gfs_holder *gh) +{ + struct gfs_glock *gl = gh->gh_gl; + struct gfs_sbd *sdp = gl->gl_sbd; + struct gfs_glock_operations *glops = gl->gl_ops; + + atomic_inc(&gl->gl_sbd->sd_glock_dq_calls); + + gfs_assert_withdraw(sdp, !queue_empty(gl, &gh->gh_list)); + gfs_assert_withdraw(sdp, test_bit(HIF_HOLDER, &gh->gh_iflags)); + + if (gh->gh_flags & GL_SYNC) + set_bit(GLF_SYNC, &gl->gl_flags); + + /* Don't cache glock; request demote to unlock at inter-node scope */ + if (gh->gh_flags & GL_NOCACHE && gl->gl_holders.next == &gh->gh_list && + gl->gl_holders.prev == &gh->gh_list) + /* There's a race here. If there are two holders, and both + * are dq'ed at almost the same time, you can't guarantee that + * you will call handle_callback. Fixing this will require + * some refactoring */ + handle_callback(gl, LM_ST_UNLOCKED); + + lock_on_glock(gl); + + spin_lock(&gl->gl_spin); + list_del_init(&gh->gh_list); + + /* If last holder, do appropriate glock operations, set cache timer */ + if (list_empty(&gl->gl_holders)) { + spin_unlock(&gl->gl_spin); + + if (glops->go_unlock) + glops->go_unlock(gl, gh->gh_flags); + + /* Do "early" sync, if requested by holder */ + if (test_bit(GLF_SYNC, &gl->gl_flags)) { + if (glops->go_sync) + glops->go_sync(gl, + DIO_METADATA | + DIO_DATA | + DIO_INVISIBLE); + } + + gl->gl_stamp = jiffies; + + spin_lock(&gl->gl_spin); + } + + clear_bit(GLF_LOCK, &gl->gl_flags); + run_queue(gl); + spin_unlock(&gl->gl_spin); +} + +/** + * gfs_glock_prefetch - Try to prefetch a glock + * @gl: the glock + * @state: the state to prefetch in + * @flags: flags passed to go_xmote_th() + * + * Bypass request queues of glock (i.e. no holder involved), and directly call + * go_xmote_th() to ask lock module for lock, to put in glock cache for + * later use. + * + * Will not prefetch the lock (no need to) if a process on this node is already + * interested in the lock, or if it's sitting in glock cache in a compatible + * state. + * + * Rules: + * Don't ask for UNLOCKED state (use gfs_glock_dq() for that). + * LM_FLAG_ANY (liberal) and GL_EXACT (restrictive) are mutually exclusive. + */ + +void +gfs_glock_prefetch(struct gfs_glock *gl, unsigned int state, int flags) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + struct gfs_glock_operations *glops = gl->gl_ops; + + if (gfs_assert_warn(sdp, state != LM_ST_UNLOCKED) || + gfs_assert_warn(sdp, (flags & (LM_FLAG_ANY | GL_EXACT)) != + (LM_FLAG_ANY | GL_EXACT))) + return; + + spin_lock(&gl->gl_spin); + + /* Should we prefetch? */ + if (test_bit(GLF_LOCK, &gl->gl_flags) || + !list_empty(&gl->gl_holders) || + !list_empty(&gl->gl_waiters1) || + !list_empty(&gl->gl_waiters2) || + !list_empty(&gl->gl_waiters3) || + relaxed_state_ok(gl->gl_state, state, flags)) { + spin_unlock(&gl->gl_spin); + return; + } + + /* Let bottom half know we're prefetching, ask lock module for lock */ + set_bit(GLF_PREFETCH, &gl->gl_flags); + + if (gfs_assert_warn(sdp, !gl->gl_req_gh)) + gl->gl_req_gh = NULL; + set_bit(GLF_LOCK, &gl->gl_flags); + spin_unlock(&gl->gl_spin); + + glops->go_xmote_th(gl, state, flags); + + atomic_inc(&gl->gl_sbd->sd_glock_prefetch_calls); +} + +/** + * gfs_glock_force_drop - Force a glock to be uncached + * @gl: the glock + * + */ + +void +gfs_glock_force_drop(struct gfs_glock *gl) +{ + struct gfs_holder gh; + + gfs_holder_init(gl, LM_ST_UNLOCKED, 0, &gh); + set_bit(HIF_DEMOTE, &gh.gh_iflags); + gh.gh_owner = NULL; + + spin_lock(&gl->gl_spin); + list_add_tail(&gh.gh_list, &gl->gl_waiters2); + run_queue(gl); + spin_unlock(&gl->gl_spin); + + wait_for_completion(&gh.gh_wait); + gfs_holder_uninit(&gh); +} + +/** + * greedy_work - + * @data: + * + */ + +static void +greedy_work(struct work_struct *work) +{ + struct greedy *gr = container_of(work, struct greedy, gr_work.work); + struct gfs_holder *gh = &gr->gr_gh; + struct gfs_glock *gl = gh->gh_gl; + struct gfs_glock_operations *glops = gl->gl_ops; + + clear_bit(GLF_SKIP_WAITERS2, &gl->gl_flags); + + if (glops->go_greedy) + glops->go_greedy(gl); + + spin_lock(&gl->gl_spin); + + if (list_empty(&gl->gl_waiters2)) { + clear_bit(GLF_GREEDY, &gl->gl_flags); + spin_unlock(&gl->gl_spin); + gfs_holder_uninit(gh); + kfree(gr); + } else { + glock_hold(gl); + list_add_tail(&gh->gh_list, &gl->gl_waiters2); + run_queue(gl); + spin_unlock(&gl->gl_spin); + glock_put(gl); + } +} + +/** + * gfs_glock_be_greedy - + * @gl: + * @time: + * + * Returns: 0 if go_greedy will be called, 1 otherwise + */ + +int +gfs_glock_be_greedy(struct gfs_glock *gl, unsigned int time) +{ + struct greedy *gr; + struct gfs_holder *gh; + + if (!time || + gl->gl_sbd->sd_args.ar_localcaching || + test_and_set_bit(GLF_GREEDY, &gl->gl_flags)) + return 1; + + gr = kmalloc(sizeof(struct greedy), GFP_KERNEL); + if (!gr) { + clear_bit(GLF_GREEDY, &gl->gl_flags); + return 1; + } + gh = &gr->gr_gh; + + gfs_holder_init(gl, 0, 0, gh); + set_bit(HIF_GREEDY, &gh->gh_iflags); + gh->gh_owner = NULL; + INIT_DELAYED_WORK(&gr->gr_work, greedy_work); + + set_bit(GLF_SKIP_WAITERS2, &gl->gl_flags); + schedule_delayed_work(&gr->gr_work, time); + + return 0; +} + +/** + * gfs_glock_nq_init - intialize a holder and enqueue it on a glock + * @gl: the glock + * @state: the state we're requesting + * @flags: the modifier flags + * @gh: the holder structure + * + * Returns: 0, GLR_*, or errno + */ + +int +gfs_glock_nq_init(struct gfs_glock *gl, unsigned int state, int flags, + struct gfs_holder *gh) +{ + int error; + + gfs_holder_init(gl, state, flags, gh); + + error = gfs_glock_nq(gh); + if (error) + gfs_holder_uninit(gh); + + return error; +} + +/** + * gfs_glock_dq_uninit - dequeue a holder from a glock and initialize it + * @gh: the holder structure + * + */ + +void +gfs_glock_dq_uninit(struct gfs_holder *gh) +{ + gfs_glock_dq(gh); + gfs_holder_uninit(gh); +} + +/** + * gfs_glock_nq_num - acquire a glock based on lock number + * @sdp: the filesystem + * @number: the lock number + * @glops: the glock operations for the type of glock + * @state: the state to acquire the glock in + * @flags: modifier flags for the aquisition + * @gh: the struct gfs_holder + * + * Returns: errno + */ + +int +gfs_glock_nq_num(struct gfs_sbd *sdp, + uint64_t number, struct gfs_glock_operations *glops, + unsigned int state, int flags, struct gfs_holder *gh) +{ + struct gfs_glock *gl; + int error; + + error = gfs_glock_get(sdp, number, glops, CREATE, &gl); + if (!error) { + error = gfs_glock_nq_init(gl, state, flags, gh); + glock_put(gl); + } + + return error; +} + +/** + * glock_compare - Compare two struct gfs_glock structures for sorting + * @arg_a: the first structure + * @arg_b: the second structure + * + */ + +static int +glock_compare(const void *arg_a, const void *arg_b) +{ + struct gfs_holder *gh_a = *(struct gfs_holder **)arg_a; + struct gfs_holder *gh_b = *(struct gfs_holder **)arg_b; + struct lm_lockname *a = &gh_a->gh_gl->gl_name; + struct lm_lockname *b = &gh_b->gh_gl->gl_name; + int ret = 0; + + if (a->ln_number > b->ln_number) + ret = 1; + else if (a->ln_number < b->ln_number) + ret = -1; + else { + if (gh_a->gh_state == LM_ST_SHARED && + gh_b->gh_state == LM_ST_EXCLUSIVE) + ret = 1; + else if (!(gh_a->gh_flags & GL_LOCAL_EXCL) && + (gh_b->gh_flags & GL_LOCAL_EXCL)) + ret = 1; + } + + return ret; +} + +/** + * nq_m_sync - synchonously acquire more than one glock in deadlock free order + * @num_gh: the number of structures + * @ghs: an array of struct gfs_holder structures + * + * Returns: 0 on success (all glocks acquired), errno on failure (no glocks acquired) + */ + +static int +nq_m_sync(unsigned int num_gh, struct gfs_holder *ghs, struct gfs_holder **p) +{ + unsigned int x; + int error = 0; + + for (x = 0; x < num_gh; x++) + p[x] = &ghs[x]; + + gfs_sort(p, num_gh, sizeof(struct gfs_holder *), glock_compare); + + for (x = 0; x < num_gh; x++) { + p[x]->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC); + + error = gfs_glock_nq(p[x]); + if (error) { + while (x--) + gfs_glock_dq(p[x]); + break; + } + } + + return error; +} + +/** + * gfs_glock_nq_m - acquire multiple glocks + * @num_gh: the number of structures + * @ghs: an array of struct gfs_holder structures + * + * Figure out how big an impact this function has. Either: + * 1) Replace this code with code that calls gfs_glock_prefetch() + * 2) Forget async stuff and just call nq_m_sync() + * 3) Leave it like it is + * + * Returns: 0 on success (all glocks acquired), errno on failure (no glocks acquired) + */ + +int +gfs_glock_nq_m(unsigned int num_gh, struct gfs_holder *ghs) +{ + int *e; + unsigned int x; + int borked = FALSE, serious = 0; + int error = 0; + + if (!num_gh) + return 0; + + /* For just one gh, do request synchronously */ + if (num_gh == 1) { + ghs->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC); + return gfs_glock_nq(ghs); + } + + /* using sizeof(struct gfs_holder *) instead of sizeof(int), because + * we're also using this memory for nq_m_sync and ints should never be + * larger than pointers.... I hope + */ + e = kmalloc(num_gh * sizeof(struct gfs_holder *), GFP_KERNEL); + if (!e) + return -ENOMEM; + + /* Send off asynchronous requests */ + for (x = 0; x < num_gh; x++) { + ghs[x].gh_flags |= LM_FLAG_TRY | GL_ASYNC; + error = gfs_glock_nq(&ghs[x]); + if (error) { + borked = TRUE; + serious = error; + num_gh = x; + break; + } + } + + /* Wait for all to complete */ + for (x = 0; x < num_gh; x++) { + error = e[x] = glock_wait_internal(&ghs[x]); + if (error) { + borked = TRUE; + if (error != GLR_TRYFAILED && error != GLR_CANCELED) + serious = error; + } + } + + /* If all good, done! */ + if (!borked) { + kfree(e); + return 0; + } + + for (x = 0; x < num_gh; x++) + if (!e[x]) + gfs_glock_dq(&ghs[x]); + + if (serious) + error = serious; + else { + for (x = 0; x < num_gh; x++) + gfs_holder_reinit(ghs[x].gh_state, ghs[x].gh_flags, + &ghs[x]); + error = nq_m_sync(num_gh, ghs, (struct gfs_holder **)e); + } + + kfree(e); + return error; +} + +/** + * gfs_glock_dq_m - release multiple glocks + * @num_gh: the number of structures + * @ghs: an array of struct gfs_holder structures + * + */ + +void +gfs_glock_dq_m(unsigned int num_gh, struct gfs_holder *ghs) +{ + unsigned int x; + + for (x = 0; x < num_gh; x++) + gfs_glock_dq(&ghs[x]); +} + +/** + * gfs_glock_prefetch_num - prefetch a glock based on lock number + * @sdp: the filesystem + * @number: the lock number + * @glops: the glock operations for the type of glock + * @state: the state to acquire the glock in + * @flags: modifier flags for the aquisition + * + * Returns: errno + */ + +void +gfs_glock_prefetch_num(struct gfs_sbd *sdp, + uint64_t number, struct gfs_glock_operations *glops, + unsigned int state, int flags) +{ + struct gfs_glock *gl; + int error; + + if (atomic_read(&sdp->sd_reclaim_count) < gfs_tune_get(sdp, gt_reclaim_limit)) { + error = gfs_glock_get(sdp, number, glops, CREATE, &gl); + if (!error) { + gfs_glock_prefetch(gl, state, flags); + glock_put(gl); + } + } +} + +/** + * gfs_lvb_hold - attach a LVB from a glock + * @gl: The glock in question + * + */ + +int +gfs_lvb_hold(struct gfs_glock *gl) +{ + int error; + + lock_on_glock(gl); + + if (!atomic_read(&gl->gl_lvb_count)) { + gfs_assert_warn(gl->gl_sbd, !gl->gl_lvb); + error = gfs_lm_hold_lvb(gl->gl_sbd, gl->gl_lock, &gl->gl_lvb); + if (error) { + unlock_on_glock(gl); + return error; + } + glock_hold(gl); + } + atomic_inc(&gl->gl_lvb_count); + + unlock_on_glock(gl); + + return 0; +} + +/** + * gfs_lvb_unhold - detach a LVB from a glock + * @gl: The glock in question + * + */ + +void +gfs_lvb_unhold(struct gfs_glock *gl) +{ + glock_hold(gl); + + lock_on_glock(gl); + + if (!gfs_assert_warn(gl->gl_sbd, atomic_read(&gl->gl_lvb_count) > 0) && + atomic_dec_and_test(&gl->gl_lvb_count)) { + gfs_assert_warn(gl->gl_sbd, gl->gl_lvb); + gfs_lm_unhold_lvb(gl->gl_sbd, gl->gl_lock, gl->gl_lvb); + gl->gl_lvb = NULL; + glock_put(gl); + } + + unlock_on_glock(gl); + + glock_put(gl); +} + +#if 0 +/** + * gfs_lvb_sync - sync a LVB + * @gl: The glock in question + * + */ + +void +gfs_lvb_sync(struct gfs_glock *gl) +{ + if (gfs_assert_warn(gl->gl_sbd, atomic_read(&gl->gl_lvb_count))) + return; + + lock_on_glock(gl); + + if (!gfs_assert_warn(gl->gl_sbd, gfs_glock_is_held_excl(gl))) + gfs_lm_sync_lvb(gl->gl_sbd, gl->gl_lock, gl->gl_lvb); + + unlock_on_glock(gl); +} +#endif + +/** + * blocking_cb - + * @sdp: + * @name: + * @state: + * + */ + +void +blocking_cb(struct gfs_sbd *sdp, struct lm_lockname *name, unsigned int state) +{ + struct gfs_glock *gl; + + gl = gfs_glock_find(sdp, name); + if (!gl) + return; + + if (gl->gl_ops->go_callback) + gl->gl_ops->go_callback(gl, state); + handle_callback(gl, state); + + spin_lock(&gl->gl_spin); + run_queue(gl); + spin_unlock(&gl->gl_spin); + + glock_put(gl); +} + +/** + * gfs_glock_cb - Callback used by locking module + * @fsdata: Pointer to the superblock + * @type: Type of callback + * @data: Type dependent data pointer + * + * Called by the locking module when it wants to tell us something. + * Either we need to drop a lock, one of our ASYNC requests completed, or + * another client expired (crashed/died) and we need to recover its journal. + * If another node needs a lock held by this node, we queue a request to demote + * our lock to a state compatible with that needed by the other node. + * For example, if the other node needs EXCLUSIVE, we request UNLOCKED. + * SHARED and DEFERRED modes can be shared with other nodes, so we request + * accordingly. + * Once all incompatible holders on this node are done with the lock, the + * queued request will cause run_queue() to call the lock module to demote + * our lock to a compatible state, allowing the other node to grab the lock. + */ + +void +gfs_glock_cb(void *fsdata, unsigned int type, void *data) +{ + struct gfs_sbd *sdp = fsdata; + + atomic_inc(&sdp->sd_lm_callbacks); + + switch (type) { + case LM_CB_NEED_E: + blocking_cb(sdp, (struct lm_lockname *)data, LM_ST_UNLOCKED); + return; + + case LM_CB_NEED_D: + blocking_cb(sdp, (struct lm_lockname *)data, LM_ST_DEFERRED); + return; + + case LM_CB_NEED_S: + blocking_cb(sdp, (struct lm_lockname *)data, LM_ST_SHARED); + return; + + case LM_CB_ASYNC: { + struct lm_async_cb *async = (struct lm_async_cb *)data; + struct gfs_glock *gl; + + gl = gfs_glock_find(sdp, &async->lc_name); + if (gfs_assert_warn(sdp, gl)) + return; + if (!gfs_assert_warn(sdp, gl->gl_req_bh)) + gl->gl_req_bh(gl, async->lc_ret); + glock_put(gl); + + return; + } + + case LM_CB_NEED_RECOVERY: + gfs_add_dirty_j(sdp, *(unsigned int *)data); + if (sdp->sd_recoverd_process) + wake_up_process(sdp->sd_recoverd_process); + return; + + case LM_CB_DROPLOCKS: + gfs_gl_hash_clear(sdp, FALSE); + gfs_quota_scan(sdp); + return; + + default: + gfs_assert_warn(sdp, FALSE); + return; + } +} + +/** + * gfs_try_toss_inode - try to remove a particular GFS inode struct from cache + * sdp: the filesystem + * inum: the inode number + * + * Look for the glock protecting the inode of interest. + * If no process is manipulating or holding the glock, see if the glock + * has a gfs_inode attached. + * If gfs_inode has no references, unhold its iopen glock, release any + * indirect addressing buffers, and destroy the gfs_inode. + */ + +void +gfs_try_toss_inode(struct gfs_sbd *sdp, struct gfs_inum *inum) +{ + struct gfs_glock *gl; + struct gfs_inode *ip; + int error; + + error = gfs_glock_get(sdp, + inum->no_formal_ino, &gfs_inode_glops, + NO_CREATE, &gl); + if (error || !gl) + return; + + if (!trylock_on_glock(gl)) + goto out; + + if (!queue_empty(gl, &gl->gl_holders)) + goto out_unlock; + + ip = get_gl2ip(gl); + if (!ip) + goto out_unlock; + + if (atomic_read(&ip->i_count)) + goto out_unlock; + + gfs_inode_destroy(ip); + + out_unlock: + unlock_on_glock(gl); + + out: + glock_put(gl); +} + +/** + * gfs_iopen_go_callback - Try to kick the inode/vnode associated with an iopen glock from memory + * @io_gl: the iopen glock + * @state: the state into which the glock should be put + * + */ + +void +gfs_iopen_go_callback(struct gfs_glock *io_gl, unsigned int state) +{ + struct gfs_glock *i_gl; + struct gfs_inode *ip; + + if (state != LM_ST_UNLOCKED) + return; + + spin_lock(&io_gl->gl_spin); + i_gl = get_gl2gl(io_gl); + if (i_gl) { + glock_hold(i_gl); + spin_unlock(&io_gl->gl_spin); + } else { + spin_unlock(&io_gl->gl_spin); + return; + } + + if (trylock_on_glock(i_gl)) { + if (queue_empty(i_gl, &i_gl->gl_holders)) { + ip = get_gl2ip(i_gl); + if (ip) { + gfs_try_toss_vnode(ip); + unlock_on_glock(i_gl); + gfs_glock_schedule_for_reclaim(i_gl); + goto out; + } + } + unlock_on_glock(i_gl); + } + + out: + glock_put(i_gl); +} + +/** + * demote_ok - Check to see if it's ok to unlock a glock (to remove it + * from glock cache) + * @gl: the glock + * + * Called when trying to reclaim glocks, once it's determined that the glock + * has no holders on this node. + * + * Returns: TRUE if it's ok + * + * It's not okay if: + * -- glock is STICKY + * -- PREFETCHed glock has not been given enough chance to be used + * -- glock-type-specific test says "no" + */ + +static int +demote_ok(struct gfs_glock *gl) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + struct gfs_glock_operations *glops = gl->gl_ops; + int demote = TRUE; + + if (test_bit(GLF_STICKY, &gl->gl_flags)) + demote = FALSE; + else if (test_bit(GLF_PREFETCH, &gl->gl_flags)) + demote = time_after_eq(jiffies, + gl->gl_stamp + + gfs_tune_get(sdp, gt_prefetch_secs) * HZ); + else if (glops->go_demote_ok) + demote = glops->go_demote_ok(gl); + + return demote; +} + +/** + * gfs_glock_schedule_for_reclaim - Add a glock to the reclaim list + * @gl: the glock + * + */ + +void +gfs_glock_schedule_for_reclaim(struct gfs_glock *gl) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + + spin_lock(&sdp->sd_reclaim_lock); + if (list_empty(&gl->gl_reclaim)) { + glock_hold(gl); + list_add(&gl->gl_reclaim, &sdp->sd_reclaim_list); + atomic_inc(&sdp->sd_reclaim_count); + } + spin_unlock(&sdp->sd_reclaim_lock); + + wake_up(&sdp->sd_reclaim_wchan); +} + +/** + * gfs_reclaim_glock - process the next glock on the filesystem's reclaim list + * @sdp: the filesystem + * + * Called from gfs_glockd() glock reclaim daemon, or when promoting a + * (different) glock and we notice that there are a lot of glocks in the + * reclaim list. + * + * Remove glock from filesystem's reclaim list, update reclaim statistics. + * If no holders (might have gotten added since glock was placed on reclaim + * list): + * -- Destroy any now-unused inode protected by glock + * (and release hold on iopen glock). + * -- Ask for demote to UNLOCKED to enable removal of glock from glock cache. + * + * If no further interest in glock struct, remove it from glock cache, and + * free it from memory. (During normal operation, this is the only place + * that this is done). + * + * Glock-type-specific considerations for permission to demote are handled + * in demote_ok(). This includes how long to retain a glock in cache after it + * is no longer held by any process. + */ + +void +gfs_reclaim_glock(struct gfs_sbd *sdp) +{ + struct gfs_glock *gl; + struct gfs_gl_hash_bucket *bucket; + + spin_lock(&sdp->sd_reclaim_lock); + + /* Nothing to reclaim? Done! */ + if (list_empty(&sdp->sd_reclaim_list)) { + spin_unlock(&sdp->sd_reclaim_lock); + return; + } + + /* Remove next victim from reclaim list */ + gl = list_entry(sdp->sd_reclaim_list.next, + struct gfs_glock, gl_reclaim); + list_del_init(&gl->gl_reclaim); + + spin_unlock(&sdp->sd_reclaim_lock); + + atomic_dec(&sdp->sd_reclaim_count); + atomic_inc(&sdp->sd_reclaimed); + + if (trylock_on_glock(gl)) { + if (queue_empty(gl, &gl->gl_holders)) { + /* Inode glock-type-specific; free unused gfs inode, + and release hold on iopen glock */ + if (gl->gl_ops == &gfs_inode_glops) { + struct gfs_inode *ip = get_gl2ip(gl); + if (ip && !atomic_read(&ip->i_count)) + gfs_inode_destroy(ip); + } + /* Generic (including inodes); try to unlock glock */ + if (gl->gl_state != LM_ST_UNLOCKED && + demote_ok(gl)) + handle_callback(gl, LM_ST_UNLOCKED); + } + unlock_on_glock(gl); + } + + bucket = gl->gl_bucket; + + /* If glock struct's only remaining reference is from being put on + the reclaim list, remove glock from hash table (sd_gl_hash), + and free the glock's memory */ + write_lock(&bucket->hb_lock); + if (atomic_read(&gl->gl_count) == 1) { + list_del_init(&gl->gl_list); + write_unlock(&bucket->hb_lock); + glock_free(gl); + } else { + write_unlock(&bucket->hb_lock); + glock_put(gl); /* see gfs_glock_schedule_for_reclaim() */ + } +} + +/** + * examine_bucket - Call a function for glock in a hash bucket + * @examiner: the function + * @sdp: the filesystem + * @bucket: the bucket + * + * Returns: TRUE if the bucket has entries + */ + +static int +examine_bucket(glock_examiner examiner, + struct gfs_sbd *sdp, struct gfs_gl_hash_bucket *bucket, + unsigned int *purge_nr) +{ + struct glock_plug plug; + struct list_head *tmp; + struct gfs_glock *gl; + int entries; + + /* Add "plug" to end of bucket list, work back up list from there */ + memset(&plug.gl_flags, 0, sizeof(unsigned long)); + set_bit(GLF_PLUG, &plug.gl_flags); + + write_lock(&bucket->hb_lock); + list_add(&plug.gl_list, &bucket->hb_list); + write_unlock(&bucket->hb_lock); + + /* Look at each bucket entry */ + for (;;) { + write_lock(&bucket->hb_lock); + + /* Work back up list from plug */ + for (;;) { + tmp = plug.gl_list.next; + + /* Top of list; we're done */ + if (tmp == &bucket->hb_list) { + list_del(&plug.gl_list); + entries = !list_empty(&bucket->hb_list); + write_unlock(&bucket->hb_lock); + return entries; + } + gl = list_entry(tmp, struct gfs_glock, gl_list); + + /* Move plug up list */ + list_move(&plug.gl_list, &gl->gl_list); + + if (test_bit(GLF_PLUG, &gl->gl_flags)) + continue; + + /* glock_hold; examiner must glock_put() */ + atomic_inc(&gl->gl_count); + + break; + } + + write_unlock(&bucket->hb_lock); + + examiner(gl, purge_nr); + } +} + +static void +try_purge_iopen(struct gfs_glock *gl, unsigned int *p_count) +{ + struct gfs_glock *i_gl; + + if (*p_count == 0) + return; + + /* find the associated inode glock */ + i_gl = get_gl2gl(gl); + if (!i_gl) + return; + + /* + * If the associated inode glock has been in unlocked + * state, try to purge it. + */ + if (trylock_on_glock(i_gl)) { + if (i_gl->gl_state == LM_ST_UNLOCKED) { + *p_count = *p_count - 1; + unlock_on_glock(i_gl); + atomic_inc(&gl->gl_count); + gfs_iopen_go_callback(gl, LM_ST_UNLOCKED); + handle_callback(gl, LM_ST_UNLOCKED); + spin_lock(&gl->gl_spin); + run_queue(gl); + spin_unlock(&gl->gl_spin); + glock_put(gl); + } else + unlock_on_glock(i_gl); + } + + return; +} + +/** + * scan_glock - look at a glock and see if we can reclaim it + * @gl: the glock to look at + * + * Called via examine_bucket() when trying to release glocks from glock cache, + * during normal operation (i.e. not unmount time). + * + * Place glock on filesystem's reclaim list if, on this node: + * -- No process is manipulating glock struct, and + * -- No current holders, and either: + * -- GFS incore inode, protected by glock, is no longer in use, or + * -- Glock-type-specific demote_ok glops gives permission + */ + +static void +scan_glock(struct gfs_glock *gl, unsigned int *p_count) +{ + if (trylock_on_glock(gl)) { + if (queue_empty(gl, &gl->gl_holders)) { + /* Inode glock-type-specific; reclaim glock if gfs inode + no longer in use. */ + if (gl->gl_ops == &gfs_inode_glops) { + struct gfs_inode *ip = get_gl2ip(gl); + if (ip && !atomic_read(&ip->i_count)) { + unlock_on_glock(gl); + gfs_glock_schedule_for_reclaim(gl); + goto out; + } + } + /* Generic (including inodes not scheduled above) */ + if (gl->gl_state != LM_ST_UNLOCKED && + demote_ok(gl)) { + unlock_on_glock(gl); + gfs_glock_schedule_for_reclaim(gl); + goto out; + } + } + /* iopen always has holder(s) */ + if (gl->gl_name.ln_type == LM_TYPE_IOPEN) { + unlock_on_glock(gl); + try_purge_iopen(gl, p_count); + goto out; + } + unlock_on_glock(gl); + } + + out: + glock_put(gl); /* see examine_bucket() */ +} + +/** + * gfs_scand_internal - Look for glocks and inodes to toss from memory + * @sdp: the filesystem + * + * Invokes scan_glock() for each glock in each cache bucket. + * + * Steps of reclaiming a glock: + * -- scan_glock() places eligible glocks on filesystem's reclaim list. + * -- gfs_reclaim_glock() processes list members, attaches demotion requests + * to wait queues of glocks still locked at inter-node scope. + * -- Demote to UNLOCKED state (if not already unlocked). + * -- gfs_reclaim_lock() cleans up glock structure. + */ + +void +gfs_scand_internal(struct gfs_sbd *sdp) +{ + unsigned int x, purge_nr; + + if (!sdp->sd_tune.gt_glock_purge) + purge_nr = 0; + else + purge_nr = atomic_read(&sdp->sd_glock_count) * + sdp->sd_tune.gt_glock_purge / 100; + + for (x = 0; x < GFS_GL_HASH_SIZE; x++) { + examine_bucket(scan_glock, sdp, &sdp->sd_gl_hash[x], &purge_nr); + cond_resched(); + } +} + +/** + * clear_glock - look at a glock and see if we can free it from glock cache + * @gl: the glock to look at + * + * Called via examine_bucket() when unmounting the filesystem, or + * when inter-node lock manager requests DROPLOCKS because it is running + * out of capacity. + * + * Similar to gfs_reclaim_glock(), except does *not*: + * -- Consult demote_ok() for permission + * -- Increment sdp->sd_reclaimed statistic + * + */ + +static void +clear_glock(struct gfs_glock *gl, unsigned int *unused) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + struct gfs_gl_hash_bucket *bucket = gl->gl_bucket; + + spin_lock(&sdp->sd_reclaim_lock); + if (!list_empty(&gl->gl_reclaim)) { + list_del_init(&gl->gl_reclaim); + atomic_dec(&sdp->sd_reclaim_count); + glock_put(gl); /* see gfs_glock_schedule_for_reclaim() */ + } + spin_unlock(&sdp->sd_reclaim_lock); + + if (trylock_on_glock(gl)) { + if (queue_empty(gl, &gl->gl_holders)) { + /* Inode glock-type-specific; free unused gfs inode, + and release hold on iopen glock */ + if (gl->gl_ops == &gfs_inode_glops) { + struct gfs_inode *ip = get_gl2ip(gl); + if (ip && !atomic_read(&ip->i_count)) + gfs_inode_destroy(ip); + } + /* Generic (including inodes); unlock glock */ + if (gl->gl_state != LM_ST_UNLOCKED) + handle_callback(gl, LM_ST_UNLOCKED); + } + + unlock_on_glock(gl); + } + + /* If glock struct's only remaining reference is from examine_bucket(), + remove glock from hash table (sd_gl_hash), and free glock's memory */ + write_lock(&bucket->hb_lock); + if (atomic_read(&gl->gl_count) == 1) { + list_del_init(&gl->gl_list); + write_unlock(&bucket->hb_lock); + glock_free(gl); + } else { + write_unlock(&bucket->hb_lock); + glock_put(gl); /* see examine_bucket() */ + } +} + +/** + * gfs_gl_hash_clear - Empty out the glock hash table + * @sdp: the filesystem + * @wait: wait until it's all gone + * + * Called when unmounting the filesystem, or when inter-node lock manager + * requests DROPLOCKS because it is running out of capacity. + */ + +void +gfs_gl_hash_clear(struct gfs_sbd *sdp, int wait) +{ + unsigned long t; + unsigned int x; + int cont; + + t = jiffies; + + for (;;) { + cont = FALSE; + + for (x = 0; x < GFS_GL_HASH_SIZE; x++) + if (examine_bucket(clear_glock, sdp, &sdp->sd_gl_hash[x], 0)) + cont = TRUE; + + if (!wait || !cont) + break; + + if (time_after_eq(jiffies, t + gfs_tune_get(sdp, gt_stall_secs) * HZ)) { + printk("GFS: fsid=%s: Unmount seems to be stalled. Dumping lock state...\n", + sdp->sd_fsname); + gfs_dump_lockstate(sdp, NULL); + t = jiffies; + } + + invalidate_inodes(sdp->sd_vfs); + schedule_timeout_interruptible(HZ / 10); + } +} + +/* + * Diagnostic routines to help debug distributed deadlock + */ + +/** + * dump_holder - print information about a glock holder + * @str: a string naming the type of holder + * @gh: the glock holder + * @buf: the buffer + * @size: the size of the buffer + * @count: where we are in the buffer + * + * Returns: 0 on success, -ENOBUFS when we run out of space + */ + +static int +dump_holder(char *str, struct gfs_holder *gh, + char *buf, unsigned int size, unsigned int *count) +{ + unsigned int x; + int error = -ENOBUFS; + + gfs_printf(" %s\n", str); + gfs_printf(" owner = %ld\n", + (gh->gh_owner) ? (long)gh->gh_owner->pid : -1); + gfs_printf(" gh_state = %u\n", gh->gh_state); + gfs_printf(" gh_flags ="); + for (x = 0; x < 32; x++) + if (gh->gh_flags & (1 << x)) + gfs_printf(" %u", x); + gfs_printf(" \n"); + gfs_printf(" error = %d\n", gh->gh_error); + gfs_printf(" gh_iflags ="); + for (x = 0; x < 32; x++) + if (test_bit(x, &gh->gh_iflags)) + gfs_printf(" %u", x); + gfs_printf(" \n"); + + error = 0; + + out: + return error; +} + +/** + * dump_inode - print information about an inode + * @ip: the inode + * @buf: the buffer + * @size: the size of the buffer + * @count: where we are in the buffer + * + * Returns: 0 on success, -ENOBUFS when we run out of space + */ + +static int +dump_inode(struct gfs_inode *ip, + char *buf, unsigned int size, unsigned int *count) +{ + unsigned int x; + int error = -ENOBUFS; + + gfs_printf(" Inode:\n"); + gfs_printf(" num = %" PRIu64 "/%" PRIu64 "\n", + ip->i_num.no_formal_ino, ip->i_num.no_addr); + gfs_printf(" type = %u\n", ip->i_di.di_type); + gfs_printf(" i_count = %d\n", atomic_read(&ip->i_count)); + gfs_printf(" i_flags ="); + for (x = 0; x < 32; x++) + if (test_bit(x, &ip->i_flags)) + gfs_printf(" %u", x); + gfs_printf(" \n"); + gfs_printf(" vnode = %s\n", (ip->i_vnode) ? "yes" : "no"); + + error = 0; + + out: + return error; +} + +/** + * dump_glock - print information about a glock + * @gl: the glock + * @buf: the buffer + * @size: the size of the buffer + * @count: where we are in the buffer + * + * Returns: 0 on success, -ENOBUFS when we run out of space + */ + +static int +dump_glock(struct gfs_glock *gl, + char *buf, unsigned int size, unsigned int *count) +{ + struct list_head *head, *tmp; + struct gfs_holder *gh; + unsigned int x; + int error = -ENOBUFS; + + spin_lock(&gl->gl_spin); + + gfs_printf("Glock (%u, %" PRIu64 ")\n", + gl->gl_name.ln_type, + gl->gl_name.ln_number); + gfs_printf(" gl_flags ="); + for (x = 0; x < 32; x++) + if (test_bit(x, &gl->gl_flags)) + gfs_printf(" %u", x); + gfs_printf(" \n"); + gfs_printf(" gl_count = %d\n", atomic_read(&gl->gl_count)); + gfs_printf(" gl_state = %u\n", gl->gl_state); + gfs_printf(" req_gh = %s\n", (gl->gl_req_gh) ? "yes" : "no"); + gfs_printf(" req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no"); + gfs_printf(" lvb_count = %d\n", atomic_read(&gl->gl_lvb_count)); + gfs_printf(" object = %s\n", (gl->gl_object) ? "yes" : "no"); + gfs_printf(" new_le = %s\n", (gl->gl_new_le.le_trans) ? "yes" : "no"); + gfs_printf(" incore_le = %s\n", (gl->gl_incore_le.le_trans) ? "yes" : "no"); + gfs_printf(" reclaim = %s\n", + (list_empty(&gl->gl_reclaim)) ? "no" : "yes"); + if (gl->gl_aspace) + gfs_printf(" aspace = %lu\n", + gl->gl_aspace->i_mapping->nrpages); + else + gfs_printf(" aspace = no\n"); + gfs_printf(" ail_bufs = %s\n", + (list_empty(&gl->gl_ail_bufs)) ? "no" : "yes"); + if (gl->gl_req_gh) { + error = dump_holder("Request", gl->gl_req_gh, buf, size, count); + if (error) + goto out; + } + for (head = &gl->gl_holders, tmp = head->next; + tmp != head; + tmp = tmp->next) { + gh = list_entry(tmp, struct gfs_holder, gh_list); + error = dump_holder("Holder", gh, buf, size, count); + if (error) + goto out; + } + for (head = &gl->gl_waiters1, tmp = head->next; + tmp != head; + tmp = tmp->next) { + gh = list_entry(tmp, struct gfs_holder, gh_list); + error = dump_holder("Waiter1", gh, buf, size, count); + if (error) + goto out; + } + for (head = &gl->gl_waiters2, tmp = head->next; + tmp != head; + tmp = tmp->next) { + gh = list_entry(tmp, struct gfs_holder, gh_list); + error = dump_holder("Waiter2", gh, buf, size, count); + if (error) + goto out; + } + for (head = &gl->gl_waiters3, tmp = head->next; + tmp != head; + tmp = tmp->next) { + gh = list_entry(tmp, struct gfs_holder, gh_list); + error = dump_holder("Waiter3", gh, buf, size, count); + if (error) + goto out; + } + if (gl->gl_ops == &gfs_inode_glops && get_gl2ip(gl)) { + if (!test_bit(GLF_LOCK, &gl->gl_flags) && + list_empty(&gl->gl_holders)) { + error = dump_inode(get_gl2ip(gl), buf, size, count); + if (error) + goto out; + } else { + error = -ENOBUFS; + gfs_printf(" Inode: busy\n"); + } + } + + error = 0; + + out: + spin_unlock(&gl->gl_spin); + + return error; +} + +/** + * gfs_dump_lockstate - print out the current lockstate + * @sdp: the filesystem + * @ub: the buffer to copy the information into + * + * If @ub is NULL, dump the lockstate to the console. + * + */ + +int +gfs_dump_lockstate(struct gfs_sbd *sdp, struct gfs_user_buffer *ub) +{ + struct gfs_gl_hash_bucket *bucket; + struct list_head *tmp, *head; + struct gfs_glock *gl; + char *buf = NULL; + unsigned int size = gfs_tune_get(sdp, gt_lockdump_size); + unsigned int x, count; + int error = 0; + + if (ub) { + buf = kmalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + } + + for (x = 0; x < GFS_GL_HASH_SIZE; x++) { + bucket = &sdp->sd_gl_hash[x]; + count = 0; + + read_lock(&bucket->hb_lock); + + for (head = &bucket->hb_list, tmp = head->next; + tmp != head; + tmp = tmp->next) { + gl = list_entry(tmp, struct gfs_glock, gl_list); + + if (test_bit(GLF_PLUG, &gl->gl_flags)) + continue; + + error = dump_glock(gl, buf, size, &count); + if (error) + break; + } + + read_unlock(&bucket->hb_lock); + + if (error) + break; + + if (ub) { + if (ub->ub_count + count > ub->ub_size) { + error = -ENOMEM; + break; + } + if (copy_to_user(ub->ub_data + ub->ub_count, buf, count)) { + error = -EFAULT; + break; + } + ub->ub_count += count; + } + } + + if (ub) + kfree(buf); + + return error; +} --- linux-2.6.27.orig/ubuntu/gfs/ops_export.c +++ linux-2.6.27/ubuntu/gfs/ops_export.c @@ -0,0 +1,403 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "dio.h" +#include "dir.h" +#include "glock.h" +#include "glops.h" +#include "inode.h" +#include "ops_dentry.h" +#include "ops_export.h" +#include "rgrp.h" + +struct inode_cookie +{ + uint64_t formal_ino; + uint32_t gen; + int gen_valid; +}; + +struct get_name_filldir +{ + uint64_t formal_ino; + char *name; +}; + +/** + * gfs_encode_fh - + * @param1: description + * @param2: description + * @param3: description + * + * Function description + * + * Returns: what is returned + */ + +int +gfs_encode_fh(struct dentry *dentry, __u32 *fh, int *len, + int connectable) +{ + struct inode *inode = dentry->d_inode; + struct gfs_inode *ip = get_v2ip(inode); + int maxlen = *len; + + atomic_inc(&ip->i_sbd->sd_ops_export); + + if (maxlen < 3) + return 255; + + fh[0] = cpu_to_gfs32((uint32_t)(ip->i_num.no_formal_ino >> 32)); + fh[1] = cpu_to_gfs32((uint32_t)(ip->i_num.no_formal_ino & 0xFFFFFFFF)); + fh[2] = cpu_to_gfs32(inode->i_generation); /* dinode's mh_incarn */ + *len = 3; + + if (maxlen < 5 || !connectable) + return 3; + + spin_lock(&dentry->d_lock); + + inode = dentry->d_parent->d_inode; + ip = get_v2ip(inode); + + fh[3] = cpu_to_gfs32((uint32_t)(ip->i_num.no_formal_ino >> 32)); + fh[4] = cpu_to_gfs32((uint32_t)(ip->i_num.no_formal_ino & 0xFFFFFFFF)); + *len = 5; + + if (maxlen < 6) { + spin_unlock(&dentry->d_lock); + return 5; + } + + fh[5] = cpu_to_gfs32(inode->i_generation); /* dinode's mh_incarn */ + + spin_unlock(&dentry->d_lock); + + *len = 6; + + return 6; +} + +/** + * get_name_filldir - + * @param1: description + * @param2: description + * @param3: description + * + * Function description + * + * Returns: what is returned + */ + +static int +get_name_filldir(void *opaque, + const char *name, unsigned int length, + uint64_t offset, + struct gfs_inum *inum, unsigned int type) +{ + struct get_name_filldir *gnfd = (struct get_name_filldir *)opaque; + + if (inum->no_formal_ino != gnfd->formal_ino) + return 0; + + memcpy(gnfd->name, name, length); + gnfd->name[length] = 0; + + return 1; +} + +/** + * gfs_get_name - + * @param1: description + * @param2: description + * @param3: description + * + * Function description + * + * Returns: what is returned + */ + +int gfs_get_name(struct dentry *parent, char *name, + struct dentry *child) +{ + struct inode *dir = parent->d_inode; + struct inode *inode = child->d_inode; + struct gfs_inode *dip, *ip; + struct get_name_filldir gnfd; + struct gfs_holder gh; + uint64_t offset = 0; + int error; + + if (!dir) + return -EINVAL; + + atomic_inc(&get_v2sdp(dir->i_sb)->sd_ops_export); + + if (!S_ISDIR(dir->i_mode) || !inode) + return -EINVAL; + + dip = get_v2ip(dir); + ip = get_v2ip(inode); + + *name = 0; + gnfd.formal_ino = ip->i_num.no_formal_ino; + gnfd.name = name; + + error = gfs_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &gh); + if (error) + return error; + + error = gfs_dir_read(dip, &offset, &gnfd, get_name_filldir); + + gfs_glock_dq_uninit(&gh); + + if (!error & !*name) + error = -ENOENT; + + return error; +} + +/** + * gfs_get_parent - + * @param1: description + * @param2: description + * @param3: description + * + * Function description + * + * Returns: what is returned + */ + +struct dentry * +gfs_get_parent(struct dentry *child) +{ + struct gfs_inode *dip = get_v2ip(child->d_inode); + struct gfs_holder d_gh, i_gh; + struct qstr dotdot = { .name = "..", .len = 2 }; + struct gfs_inode *ip; + struct inode *inode; + struct dentry *dentry; + int error; + + atomic_inc(&dip->i_sbd->sd_ops_export); + + gfs_holder_init(dip->i_gl, 0, 0, &d_gh); + error = gfs_lookupi(&d_gh, &dotdot, TRUE, &i_gh); + if (error) + goto fail; + + error = -ENOENT; + if (!i_gh.gh_gl) + goto fail; + + ip = get_gl2ip(i_gh.gh_gl); + + inode = gfs_iget(ip, CREATE); + gfs_inode_put(ip); + + gfs_glock_dq_uninit(&d_gh); + gfs_glock_dq_uninit(&i_gh); + + if (!inode) + return ERR_PTR(-ENOMEM); + + dentry = d_alloc_anon(inode); + if (!dentry) { + iput(inode); + return ERR_PTR(-ENOMEM); + } + + dentry->d_op = &gfs_dops; + return dentry; + + fail: + gfs_holder_uninit(&d_gh); + return ERR_PTR(error); +} + +/** + * gfs_get_dentry - + * @param1: description + * @param2: description + * @param3: description + * + * Function description + * + * Returns: what is returned + */ + +struct dentry * +gfs_get_dentry(struct super_block *sb, struct inode_cookie *cookie) +{ + struct gfs_sbd *sdp = get_v2sdp(sb); + struct gfs_inum inum; + struct gfs_holder i_gh, ri_gh, rgd_gh; + struct gfs_rgrpd *rgd; + struct buffer_head *bh; + struct gfs_dinode *di; + struct gfs_inode *ip; + struct inode *inode; + struct dentry *dentry; + int error; + + atomic_inc(&sdp->sd_ops_export); + + if (!cookie->formal_ino || + cookie->formal_ino == sdp->sd_jiinode->i_num.no_formal_ino || + cookie->formal_ino == sdp->sd_riinode->i_num.no_formal_ino || + cookie->formal_ino == sdp->sd_qinode->i_num.no_formal_ino) + return ERR_PTR(-EINVAL); + + inum.no_formal_ino = cookie->formal_ino; + inum.no_addr = cookie->formal_ino; + + error = gfs_glock_nq_num(sdp, + inum.no_formal_ino, &gfs_inode_glops, + LM_ST_SHARED, LM_FLAG_ANY | GL_LOCAL_EXCL, + &i_gh); + if (error) + return ERR_PTR(error); + + error = gfs_inode_get(i_gh.gh_gl, &inum, NO_CREATE, &ip); + if (error) + goto fail; + if (ip) + goto out; + + error = gfs_rindex_hold(sdp, &ri_gh); + if (error) + goto fail; + + error = -EINVAL; + rgd = gfs_blk2rgrpd(sdp, inum.no_addr); + if (!rgd) + goto fail_rindex; + + error = gfs_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh); + if (error) + goto fail_rindex; + + error = -ESTALE; + if (gfs_get_block_type(rgd, inum.no_addr) != GFS_BLKST_USEDMETA) + goto fail_rgd; + + error = gfs_dread(i_gh.gh_gl, inum.no_addr, + DIO_START | DIO_WAIT, &bh); + if (error) + goto fail_rgd; + + di = (struct gfs_dinode *)bh->b_data; + + error = -ESTALE; + if (gfs32_to_cpu(di->di_header.mh_magic) != GFS_MAGIC || + gfs32_to_cpu(di->di_header.mh_type) != GFS_METATYPE_DI || + (gfs32_to_cpu(di->di_flags) & GFS_DIF_UNUSED)) + goto fail_relse; + + brelse(bh); + gfs_glock_dq_uninit(&rgd_gh); + gfs_glock_dq_uninit(&ri_gh); + + error = gfs_inode_get(i_gh.gh_gl, &inum, CREATE, &ip); + if (error) + goto fail; + + atomic_inc(&sdp->sd_fh2dentry_misses); + + out: + inode = gfs_iget(ip, CREATE); + gfs_inode_put(ip); + + gfs_glock_dq_uninit(&i_gh); + + if (!inode) + return ERR_PTR(-ENOMEM); + + /* inode->i_generation is GFS dinode's mh_incarn value */ + if (cookie->gen_valid && cookie->gen != inode->i_generation) { + iput(inode); + return ERR_PTR(-ESTALE); + } + + dentry = d_alloc_anon(inode); + if (!dentry) { + iput(inode); + return ERR_PTR(-ENOMEM); + } + + dentry->d_op = &gfs_dops; + return dentry; + + fail_relse: + brelse(bh); + + fail_rgd: + gfs_glock_dq_uninit(&rgd_gh); + + fail_rindex: + gfs_glock_dq_uninit(&ri_gh); + + fail: + gfs_glock_dq_uninit(&i_gh); + return ERR_PTR(error); +} + +static struct dentry *gfs_fh_to_dentry(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type) +{ + struct inode_cookie this; + __u32 *fh = fid->raw; + + atomic_inc(&get_v2sdp(sb)->sd_ops_export); + + switch (fh_type) { + case 6: + case 5: + case 3: + this.gen_valid = TRUE; + this.gen = gfs32_to_cpu(fh[2]); + this.formal_ino = ((uint64_t)gfs32_to_cpu(fh[0])) << 32; + this.formal_ino |= (uint64_t)gfs32_to_cpu(fh[1]); + return gfs_get_dentry(sb, &this); + default: + return NULL; + } +} + +static struct dentry *gfs_fh_to_parent(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type) +{ + struct inode_cookie parent; + __u32 *fh = fid->raw; + + atomic_inc(&get_v2sdp(sb)->sd_ops_export); + + switch (fh_type) { + case 6: + parent.gen_valid = TRUE; + parent.gen = gfs32_to_cpu(fh[5]); + case 5: + parent.formal_ino = ((uint64_t)gfs32_to_cpu(fh[3])) << 32; + parent.formal_ino |= (uint64_t)gfs32_to_cpu(fh[4]); + default: + return NULL; + } + + return gfs_get_dentry(sb, &parent); +} + +const struct export_operations gfs_export_ops = { + .encode_fh = gfs_encode_fh, + .fh_to_dentry = gfs_fh_to_dentry, + .fh_to_parent = gfs_fh_to_parent, + .get_name = gfs_get_name, + .get_parent = gfs_get_parent, +}; + --- linux-2.6.27.orig/ubuntu/gfs/lvb.c +++ linux-2.6.27/ubuntu/gfs/lvb.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" + +#define pv(struct, member, fmt) printk(" "#member" = "fmt"\n", struct->member); + +#define CPIN_08(s1, s2, member, count) {memcpy((s1->member), (s2->member), (count));} +#define CPOUT_08(s1, s2, member, count) {memcpy((s2->member), (s1->member), (count));} +#define CPIN_16(s1, s2, member) {(s1->member) = gfs16_to_cpu((s2->member));} +#define CPOUT_16(s1, s2, member) {(s2->member) = cpu_to_gfs16((s1->member));} +#define CPIN_32(s1, s2, member) {(s1->member) = gfs32_to_cpu((s2->member));} +#define CPOUT_32(s1, s2, member) {(s2->member) = cpu_to_gfs32((s1->member));} +#define CPIN_64(s1, s2, member) {(s1->member) = gfs64_to_cpu((s2->member));} +#define CPOUT_64(s1, s2, member) {(s2->member) = cpu_to_gfs64((s1->member));} + +/** + * gfs_rgrp_lvb_in - Read in rgrp data + * @rb: the cpu-order structure + * @lvb: the lvb + * + */ + +void +gfs_rgrp_lvb_in(struct gfs_rgrp_lvb *rb, char *lvb) +{ + struct gfs_rgrp_lvb *str = (struct gfs_rgrp_lvb *)lvb; + + CPIN_32(rb, str, rb_magic); + CPIN_32(rb, str, rb_free); + CPIN_32(rb, str, rb_useddi); + CPIN_32(rb, str, rb_freedi); + CPIN_32(rb, str, rb_usedmeta); + CPIN_32(rb, str, rb_freemeta); +} + +/** + * gfs_rgrp_lvb_out - Write out rgrp data + * @rb: the cpu-order structure + * @lvb: the lvb + * + */ + +void +gfs_rgrp_lvb_out(struct gfs_rgrp_lvb *rb, char *lvb) +{ + struct gfs_rgrp_lvb *str = (struct gfs_rgrp_lvb *)lvb; + + CPOUT_32(rb, str, rb_magic); + CPOUT_32(rb, str, rb_free); + CPOUT_32(rb, str, rb_useddi); + CPOUT_32(rb, str, rb_freedi); + CPOUT_32(rb, str, rb_usedmeta); + CPOUT_32(rb, str, rb_freemeta); +} + +/** + * gfs_rgrp_lvb_print - Print out rgrp data + * @rb: the cpu-order structure + * @console - TRUE if this should be printed to the console, + * FALSE if it should be just printed to the incore debug + * buffer + */ + +void +gfs_rgrp_lvb_print(struct gfs_rgrp_lvb *rb) +{ + pv(rb, rb_magic, "%u"); + pv(rb, rb_free, "%u"); + pv(rb, rb_useddi, "%u"); + pv(rb, rb_freedi, "%u"); + pv(rb, rb_usedmeta, "%u"); + pv(rb, rb_freemeta, "%u"); +} + +/** + * gfs_quota_lvb_in - Read in quota data + * @rb: the cpu-order structure + * @lvb: the lvb + * + */ + +void +gfs_quota_lvb_in(struct gfs_quota_lvb *qb, char *lvb) +{ + struct gfs_quota_lvb *str = (struct gfs_quota_lvb *)lvb; + + CPIN_32(qb, str, qb_magic); + CPIN_32(qb, str, qb_pad); + CPIN_64(qb, str, qb_limit); + CPIN_64(qb, str, qb_warn); + CPIN_64(qb, str, qb_value); +} + +/** + * gfs_quota_lvb_out - Write out quota data + * @rb: the cpu-order structure + * @lvb: the lvb + * + */ + +void +gfs_quota_lvb_out(struct gfs_quota_lvb *qb, char *lvb) +{ + struct gfs_quota_lvb *str = (struct gfs_quota_lvb *)lvb; + + CPOUT_32(qb, str, qb_magic); + CPOUT_32(qb, str, qb_pad); + CPOUT_64(qb, str, qb_limit); + CPOUT_64(qb, str, qb_warn); + CPOUT_64(qb, str, qb_value); +} + +/** + * gfs_quota_lvb_print - Print out quota data + * @rb: the cpu-order structure + * @console - TRUE if this should be printed to the console, + * FALSE if it should be just printed to the incore debug + * buffer + */ + +void +gfs_quota_lvb_print(struct gfs_quota_lvb *qb) +{ + pv(qb, qb_magic, "%u"); + pv(qb, qb_pad, "%u"); + pv(qb, qb_limit, "%"PRIu64); + pv(qb, qb_warn, "%"PRIu64); + pv(qb, qb_value, "%"PRId64); +} --- linux-2.6.27.orig/ubuntu/gfs/sys.c +++ linux-2.6.27/ubuntu/gfs/sys.c @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "glock.h" +#include "lm.h" +#include "sys.h" +#include "super.h" + +char *gfs_sys_margs; +spinlock_t gfs_sys_margs_lock; + +static ssize_t id_show(struct gfs_sbd *sdp, char *buf) +{ + return sprintf(buf, "%s\n", sdp->sd_vfs->s_id); +} + +static ssize_t fsname_show(struct gfs_sbd *sdp, char *buf) +{ + return sprintf(buf, "%s\n", sdp->sd_fsname); +} + +struct gfs_attr { + struct attribute attr; + ssize_t (*show)(struct gfs_sbd *, char *); + ssize_t (*store)(struct gfs_sbd *, const char *, size_t); +}; + +#define GFS_ATTR(name, mode, show, store) \ +static struct gfs_attr gfs_attr_##name = __ATTR(name, mode, show, store) + +GFS_ATTR(id, 0444, id_show, NULL); +GFS_ATTR(fsname, 0444, fsname_show, NULL); + +static struct attribute *gfs_attrs[] = { + &gfs_attr_id.attr, + &gfs_attr_fsname.attr, + NULL, +}; + +static ssize_t gfs_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct gfs_sbd *sdp = container_of(kobj, struct gfs_sbd, sd_kobj); + struct gfs_attr *a = container_of(attr, struct gfs_attr, attr); + return a->show ? a->show(sdp, buf) : 0; +} + +static ssize_t gfs_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t len) +{ + struct gfs_sbd *sdp = container_of(kobj, struct gfs_sbd, sd_kobj); + struct gfs_attr *a = container_of(attr, struct gfs_attr, attr); + return a->store ? a->store(sdp, buf, len) : len; +} + +static struct sysfs_ops gfs_attr_ops = { + .show = gfs_attr_show, + .store = gfs_attr_store, +}; + +static struct kobj_type gfs_ktype = { + .default_attrs = gfs_attrs, + .sysfs_ops = &gfs_attr_ops, +}; + +static struct kset *gfs_kset; + +int gfs_sys_fs_add(struct gfs_sbd *sdp) +{ + int error; + + sdp->sd_kobj.kset = gfs_kset; + + error = kobject_init_and_add(&sdp->sd_kobj, &gfs_ktype, NULL, + "%s", sdp->sd_table_name); + if (error) + goto fail; + + kobject_uevent(&sdp->sd_kobj, KOBJ_ADD); + + return 0; + + fail: + return error; +} + +void gfs_sys_fs_del(struct gfs_sbd *sdp) +{ + kobject_put(&sdp->sd_kobj); +} + +int gfs_sys_init(void) +{ + gfs_sys_margs = NULL; + spin_lock_init(&gfs_sys_margs_lock); + gfs_kset = kset_create_and_add("gfs", NULL, fs_kobj); + if (!gfs_kset) + return -ENOMEM; + return 0; +} + +void gfs_sys_uninit(void) +{ + kfree(gfs_sys_margs); + kset_unregister(gfs_kset); +} --- linux-2.6.27.orig/ubuntu/gfs/ops_dentry.h +++ linux-2.6.27/ubuntu/gfs/ops_dentry.h @@ -0,0 +1,6 @@ +#ifndef __OPS_DENTRY_DOT_H__ +#define __OPS_DENTRY_DOT_H__ + +extern struct dentry_operations gfs_dops; + +#endif /* __OPS_DENTRY_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/ops_vm.h +++ linux-2.6.27/ubuntu/gfs/ops_vm.h @@ -0,0 +1,7 @@ +#ifndef __OPS_VM_DOT_H__ +#define __OPS_VM_DOT_H__ + +extern struct vm_operations_struct gfs_vm_ops_private; +extern struct vm_operations_struct gfs_vm_ops_sharewrite; + +#endif /* __OPS_VM_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/lops.c +++ linux-2.6.27/ubuntu/gfs/lops.c @@ -0,0 +1,1648 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "dio.h" +#include "glock.h" +#include "log.h" +#include "lops.h" +#include "quota.h" +#include "recovery.h" +#include "trans.h" +#include "unlinked.h" + +/** + * generic_le_add - generic routine to add a log element to a transaction + * @sdp: the filesystem + * @le: the log entry + * + */ + +static void +generic_le_add(struct gfs_sbd *sdp, struct gfs_log_element *le) +{ + struct gfs_trans *tr; + + /* Make sure it's not attached to a transaction already */ + gfs_assert(sdp, le->le_ops && + !le->le_trans && + list_empty(&le->le_list),); + + /* Attach it to the (one) transaction being built by this process */ + tr = get_transaction; + gfs_assert(sdp, tr,); + + le->le_trans = tr; + list_add(&le->le_list, &tr->tr_elements); +} + +/** + * glock_trans_end - drop a glock reference + * @sdp: the filesystem + * @le: the log element + * + * Called before incore-committing a transaction + * Release reference that was taken in gfs_trans_add_gl() + */ + +static void +glock_trans_end(struct gfs_sbd *sdp, struct gfs_log_element *le) +{ + struct gfs_glock *gl = container_of(le, struct gfs_glock, gl_new_le); + + gfs_assert(sdp, gfs_glock_is_locked_by_me(gl) && + gfs_glock_is_held_excl(gl),); + gfs_glock_put(gl); +} + +/** + * glock_print - print debug info about a log element + * @sdp: the filesystem + * @le: the log element + * @where: is this a new transaction or a incore transaction + * + */ + +static void +glock_print(struct gfs_sbd *sdp, struct gfs_log_element *le, unsigned int where) +{ + struct gfs_glock *gl; + + switch (where) { + case TRANS_IS_NEW: + gl = container_of(le, struct gfs_glock, gl_new_le); + break; + case TRANS_IS_INCORE: + gl = container_of(le, struct gfs_glock, gl_incore_le); + break; + default: + gfs_assert_warn(sdp, FALSE); + return; + } + + printk(" Glock: (%u, %"PRIu64")\n", + gl->gl_name.ln_type, + gl->gl_name.ln_number); +} + +/** + * glock_overlap_trans - Find any incore transactions that might overlap with + * (i.e. be combinable with the transaction containing) this LE + * @sdp: the filesystem + * @le: the log element + * + * Transactions that share a given glock are combinable. + * + * For a glock, the scope of the "search" is just the (max) one unique incore + * committed transaction to which the glock may be attached via its + * gl->gl_incore_le embedded log element. This trans may have previously + * been combined with other transactions, though (i.e. previous + * incore committed transactions that shared the same glock). + * + * Called as a beginning part of the incore commit of a transaction. + */ + +static struct gfs_trans * +glock_overlap_trans(struct gfs_sbd *sdp, struct gfs_log_element *le) +{ + struct gfs_glock *gl = container_of(le, struct gfs_glock, gl_new_le); + + return gl->gl_incore_le.le_trans; +} + +/** + * glock_incore_commit - commit this LE to the incore log + * @sdp: the filesystem + * @tr: the being-incore-committed transaction this LE is to be a part of + * @le: the log element (should be a gl->gl_new_le), which is attached + * to a "new" (just-ended) transaction. + * + * Attach glock's gl_incore_le to the being-incore-committed trans' LE list. + * Remove glock's gl_new_le from the just-ended new trans' LE list. + * If the just-ended new trans (le->le_trans) was combined (in incore_commit()) + * with a pre-existing incore trans (tr), this function effectively moves + * the LE from the new to the combined incore trans. + * If there was no combining, then the new trans itself is being committed + * (le->le_trans == tr); this function simply replaces the gl_new_le with a + * gl_incore_le on the trans' LE list. + * + * Make sure that this glock's gl_incore_le is attached to one and only one + * incore-committed transaction's (this one's) tr_elements list. + * One transaction (instead of a list of transactions) is sufficient, + * because incore_commit() combines multiple transactions that share a glock + * into one trans. + * Since transactions can contain multiple glocks, there are multiple + * possibilities for shared glocks, therefore multiple potential "bridges" + * for combining transactions. + */ + +static void +glock_incore_commit(struct gfs_sbd *sdp, struct gfs_trans *tr, + struct gfs_log_element *le) +{ + struct gfs_glock *gl = container_of(le, struct gfs_glock, gl_new_le); + + /* Transactions were combined, based on this glock */ + if (gl->gl_incore_le.le_trans) + gfs_assert(sdp, gl->gl_incore_le.le_trans == tr,); + else { + /* Attach gl->gl_incore_le to being-committed trans */ + gl->gl_incore_le.le_trans = tr; + list_add(&gl->gl_incore_le.le_list, &tr->tr_elements); + + /* If transactions were combined (via another shared glock), + the combined trans is getting a new glock log element */ + if (tr != le->le_trans) + tr->tr_num_gl++; + } + + /* Remove gl->gl_new_le from "new" trans */ + le->le_trans = NULL; + list_del_init(&le->le_list); +} + +/** + * glock_add_to_ail - Add this LE to the AIL + * @sdp: the filesystem + * @le: the log element + * + * Glocks don't really get added to AIL (there's nothing to write to disk), + * they just get removed from the transaction at this time. + */ + +static void +glock_add_to_ail(struct gfs_sbd *sdp, struct gfs_log_element *le) +{ + le->le_trans = NULL; + list_del_init(&le->le_list); +} + +/** + * glock_trans_combine - combine two incore transactions + * @sdp: the filesystem + * @tr: the surviving transaction + * @new_tr: the transaction that's going to disappear + * + */ + +static void +glock_trans_combine(struct gfs_sbd *sdp, struct gfs_trans *tr, + struct gfs_trans *new_tr) +{ + tr->tr_num_gl += new_tr->tr_num_gl; +} + +/** + * buf_print - print debug info about a log element + * @sdp: the filesystem + * @le: the log element + * @where: is this a new transaction or a incore transaction + * + */ + +static void +buf_print(struct gfs_sbd *sdp, struct gfs_log_element *le, unsigned int where) +{ + struct gfs_bufdata *bd; + + switch (where) { + case TRANS_IS_NEW: + bd = container_of(le, struct gfs_bufdata, bd_new_le); + break; + case TRANS_IS_INCORE: + bd = container_of(le, struct gfs_bufdata, bd_incore_le); + break; + default: + gfs_assert_warn(sdp, FALSE); + return; + } + + printk(" Buffer: %"PRIu64"\n", (uint64_t)bd->bd_bh->b_blocknr); +} + +/** + * buf_incore_commit - commit this buffer LE to the incore log + * @sdp: the filesystem + * @tr: the incore transaction this LE is a part of + * @le: the log element for the "new" (just now complete) trans + * + * Invoked from incore_commit(). + * Move this buffer from "new" stage to "incore committed" stage of the + * transaction pipeline. + * If this buffer was already attached to a pre-existing incore trans, GFS is + * combining the new and incore transactions; decrement buffer's recursive + * pin count that was incremented when it was added to the new transaction, + * and remove the reference to the "new" (being swallowed) trans. + * Else, move this buffer's attach point from "new" to "incore" embedded LE + * (same transaction, just new status) and add this buf to (incore) trans' + * LE list. + */ + +static void +buf_incore_commit(struct gfs_sbd *sdp, struct gfs_trans *tr, + struct gfs_log_element *le) +{ + struct gfs_bufdata *bd = container_of(le, struct gfs_bufdata, bd_new_le); + + /* We've completed our (atomic) changes to this buffer for this trans. + We no longer need the frozen copy. If frozen copy was not written + to on-disk log already, there's no longer a need to; we can now + write the "real" buffer (with more up-to-date content) instead. */ + if (bd->bd_frozen) { + kfree(bd->bd_frozen); + bd->bd_frozen = NULL; + } + + /* New trans being combined with pre-existing incore trans? */ + if (bd->bd_incore_le.le_trans) { + gfs_assert(sdp, bd->bd_incore_le.le_trans == tr,); + gfs_dunpin(sdp, bd->bd_bh, NULL); + } else { + bd->bd_incore_le.le_trans = tr; + list_add(&bd->bd_incore_le.le_list, &tr->tr_elements); + if (tr != le->le_trans) + tr->tr_num_buf++; + + sdp->sd_log_buffers++; + } + + /* Reset buffer's bd_new_le */ + le->le_trans = NULL; + list_del_init(&le->le_list); +} + +/** + * buf_add_to_ail - Add this LE to the AIL + * @sdp: the filesystem + * @le: the log element + * + */ + +static void +buf_add_to_ail(struct gfs_sbd *sdp, struct gfs_log_element *le) +{ + struct gfs_bufdata *bd = container_of(le, + struct gfs_bufdata, + bd_incore_le); + + gfs_dunpin(sdp, bd->bd_bh, le->le_trans); + + le->le_trans = NULL; + list_del_init(&le->le_list); + + gfs_assert(sdp, sdp->sd_log_buffers,); + sdp->sd_log_buffers--; +} + +/** + * buf_trans_size - compute how much space the LE class takes up in a transaction + * @sdp: the filesystem + * @tr: the transaction + * @mblks: the number of regular metadata blocks + * @eblks: the number of extra blocks + * @blocks: the number of log blocks + * @bmem: the number of buffer-sized chunks of memory we need + * + */ + +static void +buf_trans_size(struct gfs_sbd *sdp, struct gfs_trans *tr, + unsigned int *mblks, unsigned int *eblks, + unsigned int *blocks, unsigned int *bmem) +{ + unsigned int cblks; + + if (tr->tr_num_buf) { + cblks = gfs_struct2blk(sdp, tr->tr_num_buf, + sizeof(struct gfs_block_tag)); + + if (mblks) + *mblks += tr->tr_num_buf; + if (blocks) + *blocks += tr->tr_num_buf + cblks; + if (bmem) + *bmem += cblks; + } +} + +/** + * buf_trans_combine - combine two incore transactions + * @sdp: the filesystem + * @tr: the surviving transaction + * @new_tr: the transaction that's going to disappear + * + */ + +static void +buf_trans_combine(struct gfs_sbd *sdp, struct gfs_trans *tr, + struct gfs_trans *new_tr) +{ + tr->tr_num_buf += new_tr->tr_num_buf; +} + +/** + * increment_generation - increment the generation number in metadata buffer + * @sdp: the filesystem + * @bd: the struct gfs_bufdata structure associated with the buffer + * + * Increment the generation # of the most recent buffer contents, as well as + * that of frozen buffer, if any. If there is a frozen buffer, only *it* + * will be going to the log now ... in this case, the current buffer will + * have its gen # incremented again later, when it gets written to log. + * Gen # is used by journal recovery (replay_block()) to determine whether + * to overwrite an inplace block with the logged block contents. + */ + +static void +increment_generation(struct gfs_sbd *sdp, struct gfs_bufdata *bd) +{ + struct gfs_meta_header *mh, *mh2; + uint64_t tmp64; + + mh = (struct gfs_meta_header *)bd->bd_bh->b_data; + + tmp64 = gfs64_to_cpu(mh->mh_generation) + 1; + tmp64 = cpu_to_gfs64(tmp64); + + if (bd->bd_frozen) { + mh2 = (struct gfs_meta_header *)bd->bd_frozen; + gfs_assert(sdp, mh->mh_generation == mh2->mh_generation,); + mh2->mh_generation = tmp64; + } + mh->mh_generation = tmp64; +} + +/** + * buf_build_bhlist - create the buffers that will make up the ondisk part of a transaction + * @sdp: the filesystem + * @tr: the transaction + * + * Create the log (transaction) descriptor block + */ + +static void +buf_build_bhlist(struct gfs_sbd *sdp, struct gfs_trans *tr) +{ + struct list_head *tmp, *head; + struct gfs_log_element *le; + struct gfs_bufdata *bd; + struct gfs_log_descriptor desc; + struct gfs_block_tag tag; + struct gfs_log_buf *clb = NULL; + unsigned int num_ctl; + unsigned int offset = sizeof(struct gfs_log_descriptor); + unsigned int x, bufs; + + if (!tr->tr_num_buf) + return; + + /* set up control buffers for descriptor and tags */ + + num_ctl = gfs_struct2blk(sdp, tr->tr_num_buf, + sizeof(struct gfs_block_tag)); + + for (x = 0; x < num_ctl; x++) { + if (clb) + gfs_log_get_buf(sdp, tr); + else + clb = gfs_log_get_buf(sdp, tr); + } + + /* Init and copy log descriptor into 1st control block */ + memset(&desc, 0, sizeof(struct gfs_log_descriptor)); + desc.ld_header.mh_magic = GFS_MAGIC; + desc.ld_header.mh_type = GFS_METATYPE_LD; + desc.ld_header.mh_format = GFS_FORMAT_LD; + desc.ld_type = GFS_LOG_DESC_METADATA; + desc.ld_length = num_ctl + tr->tr_num_buf; + desc.ld_data1 = tr->tr_num_buf; + gfs_desc_out(&desc, clb->lb_bh.b_data); + + x = 1; + bufs = 0; + + for (head = &tr->tr_elements, tmp = head->next; + tmp != head; + tmp = tmp->next) { + le = list_entry(tmp, struct gfs_log_element, le_list); + + /* Skip over non-buffer (e.g. glock, unlinked, etc.) LEs */ + if (le->le_ops != &gfs_buf_lops) + continue; + + bd = container_of(le, struct gfs_bufdata, bd_incore_le); + + gfs_meta_check(sdp, bd->bd_bh); + + gfs_lock_buffer(bd->bd_bh); + + increment_generation(sdp, bd); + + /* Create "fake" buffer head to write block to on-disk log. Use + frozen copy if another transaction is modifying the "real" + buffer contents. Unlock real bh after log write completes, + so Linux can write real contents to inplace block. */ + gfs_log_fake_buf(sdp, tr, + (bd->bd_frozen) ? bd->bd_frozen : bd->bd_bh->b_data, + bd->bd_bh); + + /* find another buffer for tags if we're overflowing this one */ + if (offset + sizeof(struct gfs_block_tag) > sdp->sd_sb.sb_bsize) { + clb = list_entry(clb->lb_list.prev, + struct gfs_log_buf, lb_list); + if (gfs_log_is_header(sdp, clb->lb_bh.b_blocknr)) + clb = list_entry(clb->lb_list.prev, + struct gfs_log_buf, lb_list); + x++; + offset = 0; + } + + /* Write this LE's tag into a control buffer */ + memset(&tag, 0, sizeof(struct gfs_block_tag)); + tag.bt_blkno = bd->bd_bh->b_blocknr; + + gfs_block_tag_out(&tag, clb->lb_bh.b_data + offset); + + offset += sizeof(struct gfs_block_tag); + bufs++; + } + + gfs_assert(sdp, x == num_ctl,); + gfs_assert(sdp, bufs == tr->tr_num_buf,); +} + +/** + * buf_before_scan - called before journal replay + * @sdp: the filesystem + * @jid: the journal ID about to be replayed + * @head: the current head of the log + * @pass: the pass through the journal + * + */ + +static void +buf_before_scan(struct gfs_sbd *sdp, unsigned int jid, + struct gfs_log_header *head, unsigned int pass) +{ + if (pass == GFS_RECPASS_A1) + sdp->sd_recovery_replays = + sdp->sd_recovery_skips = + sdp->sd_recovery_sames = 0; +} + +/** + * replay_block - Replay a single metadata block + * @sdp: the filesystem + * @jdesc: the struct gfs_jindex structure for the journal being replayed + * @gl: the journal's glock + * @tag: the block tag describing the inplace location of the block + * @blkno: the location of the log's copy of the block + * + * Returns: errno + * + * Read in-place block from disk + * Read log (journal) block from disk + * Compare generation numbers + * Copy log block to in-place block on-disk if: + * log generation # > in-place generation # + * OR generation #s are ==, but data contained in block is different (corrupt) + */ + +static int +replay_block(struct gfs_sbd *sdp, struct gfs_jindex *jdesc, + struct gfs_glock *gl, struct gfs_block_tag *tag, uint64_t blkno) +{ + struct buffer_head *inplace_bh, *log_bh; + struct gfs_meta_header inplace_mh, log_mh; + int replay_block = TRUE; + int error = 0; + + gfs_replay_check(sdp); + + /* Warning: Using a real buffer here instead of a tempbh can be bad + on a OS that won't support multiple simultaneous buffers for the + same block on different glocks. */ + + error = gfs_dread(gl, tag->bt_blkno, + DIO_START | DIO_WAIT, &inplace_bh); + if (error) + return error; + if (gfs_meta_check(sdp, inplace_bh)) { + brelse(inplace_bh); + return -EIO; + } + gfs_meta_header_in(&inplace_mh, inplace_bh->b_data); + + error = gfs_dread(gl, blkno, DIO_START | DIO_WAIT, &log_bh); + if (error) { + brelse(inplace_bh); + return error; + } + if (gfs_meta_check(sdp, log_bh)) { + brelse(inplace_bh); + brelse(log_bh); + return -EIO; + } + gfs_meta_header_in(&log_mh, log_bh->b_data); + + if (log_mh.mh_generation < inplace_mh.mh_generation) { + replay_block = FALSE; + sdp->sd_recovery_skips++; + } else if (log_mh.mh_generation == inplace_mh.mh_generation) { + if (memcmp(log_bh->b_data, + inplace_bh->b_data, + sdp->sd_sb.sb_bsize) == 0) { + replay_block = FALSE; + sdp->sd_recovery_sames++; + } + } + + if (replay_block) { + memcpy(inplace_bh->b_data, + log_bh->b_data, + sdp->sd_sb.sb_bsize); + + error = gfs_replay_buf(gl, inplace_bh); + if (!error) + sdp->sd_recovery_replays++; + } + + brelse(log_bh); + brelse(inplace_bh); + + return error; +} + +/** + * buf_scan_elements - Replay a metadata log descriptor + * @sdp: the filesystem + * @jdesc: the struct gfs_jindex structure for the journal being replayed + * @gl: the journal's glock + * @start: the starting block of the descriptor + * @desc: the descriptor structure + * @pass: the pass through the journal + * + * Returns: errno + */ + +static int +buf_scan_elements(struct gfs_sbd *sdp, struct gfs_jindex *jdesc, + struct gfs_glock *gl, uint64_t start, + struct gfs_log_descriptor *desc, unsigned int pass) +{ + struct gfs_block_tag tag; + struct buffer_head *bh; + uint64_t cblk = start; + unsigned int num_tags = desc->ld_data1; + unsigned int offset = sizeof(struct gfs_log_descriptor); + unsigned int x; + int error; + + if (pass != GFS_RECPASS_A1) + return 0; + if (desc->ld_type != GFS_LOG_DESC_METADATA) + return 0; + + x = gfs_struct2blk(sdp, num_tags, sizeof(struct gfs_block_tag)); + while (x--) { + error = gfs_increment_blkno(sdp, jdesc, gl, &start, TRUE); + if (error) + return error; + } + + for (;;) { + gfs_assert(sdp, num_tags,); + + error = gfs_dread(gl, cblk, DIO_START | DIO_WAIT, &bh); + if (error) + return error; + + /* Do readahead for the inplace blocks in this control block */ + { + unsigned int o2 = offset; + unsigned int nt2 = num_tags; + + while (o2 + sizeof(struct gfs_block_tag) <= + sdp->sd_sb.sb_bsize) { + gfs_block_tag_in(&tag, bh->b_data + o2); + gfs_start_ra(gl, tag.bt_blkno, 1); + if (!--nt2) + break; + o2 += sizeof(struct gfs_block_tag); + } + } + + while (offset + sizeof(struct gfs_block_tag) <= + sdp->sd_sb.sb_bsize) { + gfs_block_tag_in(&tag, bh->b_data + offset); + + error = replay_block(sdp, jdesc, gl, &tag, start); + if (error) + goto out_drelse; + + if (!--num_tags) + goto out_drelse; + + error = gfs_increment_blkno(sdp, jdesc, gl, &start, TRUE); + if (error) + goto out_drelse; + + offset += sizeof(struct gfs_block_tag); + } + + brelse(bh); + + error = gfs_increment_blkno(sdp, jdesc, gl, &cblk, TRUE); + if (error) + return error; + + offset = 0; + } + + return 0; + + out_drelse: + brelse(bh); + + return error; +} + +/** + * buf_after_scan - called after journal replay + * @sdp: the filesystem + * @jid: the journal ID about to be replayed + * @pass: the pass through the journal + * + */ + +static void +buf_after_scan(struct gfs_sbd *sdp, unsigned int jid, unsigned int pass) +{ + if (pass == GFS_RECPASS_A1) { + printk("GFS: fsid=%s: jid=%u: Replayed %u of %u blocks\n", + sdp->sd_fsname, jid, + sdp->sd_recovery_replays, + sdp->sd_recovery_replays + sdp->sd_recovery_skips + + sdp->sd_recovery_sames); + printk("GFS: fsid=%s: jid=%u: replays = %u, skips = %u, sames = %u\n", + sdp->sd_fsname, jid, sdp->sd_recovery_replays, + sdp->sd_recovery_skips, sdp->sd_recovery_sames); + } +} + +/** + * unlinked_print - print debug info about a log element + * @sdp: the filesystem + * @le: the log element + * @where: is this a new transaction or a incore transaction + * + */ + +static void +unlinked_print(struct gfs_sbd *sdp, struct gfs_log_element *le, + unsigned int where) +{ + struct gfs_unlinked *ul; + char *type; + + switch (where) { + case TRANS_IS_NEW: + ul = container_of(le, struct gfs_unlinked, ul_new_le); + type = (test_bit(ULF_NEW_UL, &ul->ul_flags)) ? + "unlink" : "dealloc"; + break; + case TRANS_IS_INCORE: + ul = container_of(le, struct gfs_unlinked, ul_incore_le); + type = (test_bit(ULF_INCORE_UL, &ul->ul_flags)) ? + "unlink" : "dealloc"; + break; + default: + gfs_assert_warn(sdp, FALSE); + return; + } + + printk(" unlinked: %"PRIu64"/%"PRIu64", %s\n", + ul->ul_inum.no_formal_ino, ul->ul_inum.no_addr, + type); +} + +/** + * unlinked_incore_commit - commit this LE to the incore log + * @sdp: the filesystem + * @tr: the incore transaction this LE is a part of + * @le: the log element + * + */ + +static void +unlinked_incore_commit(struct gfs_sbd *sdp, struct gfs_trans *tr, + struct gfs_log_element *le) +{ + struct gfs_unlinked *ul = container_of(le, + struct gfs_unlinked, + ul_new_le); + int n = !!test_bit(ULF_NEW_UL, &ul->ul_flags); + int i = !!test_bit(ULF_INCORE_UL, &ul->ul_flags); + + if (ul->ul_incore_le.le_trans) { + gfs_assert(sdp, ul->ul_incore_le.le_trans == tr,); + gfs_assert(sdp, n != i,); + + ul->ul_incore_le.le_trans = NULL; + list_del_init(&ul->ul_incore_le.le_list); + gfs_unlinked_put(sdp, ul); + + if (i) { + gfs_assert(sdp, tr->tr_num_iul,); + tr->tr_num_iul--; + } else { + gfs_assert(sdp, tr->tr_num_ida,); + tr->tr_num_ida--; + } + } else { + gfs_unlinked_hold(sdp, ul); + ul->ul_incore_le.le_trans = tr; + list_add(&ul->ul_incore_le.le_list, &tr->tr_elements); + + if (n) { + set_bit(ULF_INCORE_UL, &ul->ul_flags); + if (tr != le->le_trans) + tr->tr_num_iul++; + } else { + clear_bit(ULF_INCORE_UL, &ul->ul_flags); + if (tr != le->le_trans) + tr->tr_num_ida++; + } + } + + if (n) { + gfs_unlinked_hold(sdp, ul); + gfs_assert(sdp, !test_bit(ULF_IC_LIST, &ul->ul_flags),); + set_bit(ULF_IC_LIST, &ul->ul_flags); + atomic_inc(&sdp->sd_unlinked_ic_count); + } else { + gfs_assert(sdp, test_bit(ULF_IC_LIST, &ul->ul_flags),); + clear_bit(ULF_IC_LIST, &ul->ul_flags); + gfs_unlinked_put(sdp, ul); + gfs_assert(sdp, atomic_read(&sdp->sd_unlinked_ic_count),); + atomic_dec(&sdp->sd_unlinked_ic_count); + } + + le->le_trans = NULL; + list_del_init(&le->le_list); + gfs_unlinked_put(sdp, ul); +} + +/** + * unlinked_add_to_ail - Add this LE to the AIL + * @sdp: the filesystem + * @le: the log element + * + */ + +static void +unlinked_add_to_ail(struct gfs_sbd *sdp, struct gfs_log_element *le) +{ + struct gfs_unlinked *ul = container_of(le, + struct gfs_unlinked, + ul_incore_le); + int i = !!test_bit(ULF_INCORE_UL, &ul->ul_flags); + + if (i) { + gfs_unlinked_hold(sdp, ul); + gfs_assert(sdp, !test_bit(ULF_OD_LIST, &ul->ul_flags),); + set_bit(ULF_OD_LIST, &ul->ul_flags); + atomic_inc(&sdp->sd_unlinked_od_count); + } else { + gfs_assert(sdp, test_bit(ULF_OD_LIST, &ul->ul_flags),); + clear_bit(ULF_OD_LIST, &ul->ul_flags); + gfs_unlinked_put(sdp, ul); + gfs_assert(sdp, atomic_read(&sdp->sd_unlinked_od_count),); + atomic_dec(&sdp->sd_unlinked_od_count); + } + + le->le_trans = NULL; + list_del_init(&le->le_list); + gfs_unlinked_put(sdp, ul); +} + +/** + * unlinked_clean_dump - clean up a LE after a log dump + * @sdp: the filesystem + * @le: the log element + * + */ + +static void +unlinked_clean_dump(struct gfs_sbd *sdp, struct gfs_log_element *le) +{ + le->le_trans = NULL; + list_del_init(&le->le_list); +} + +/** + * unlinked_trans_size - compute how much space the LE class takes up in a transaction + * @sdp: the filesystem + * @tr: the transaction + * @mblks: the number of regular metadata blocks + * @eblks: the number of extra blocks + * @blocks: the number of log blocks + * @bmem: the number of buffer-sized chunks of memory we need + * + */ + +static void +unlinked_trans_size(struct gfs_sbd *sdp, struct gfs_trans *tr, + unsigned int *mblks, unsigned int *eblks, + unsigned int *blocks, unsigned int *bmem) +{ + unsigned int ublks = 0; + + if (tr->tr_num_iul) + ublks = gfs_struct2blk(sdp, tr->tr_num_iul, + sizeof(struct gfs_inum)); + if (tr->tr_num_ida) + ublks += gfs_struct2blk(sdp, tr->tr_num_ida, + sizeof(struct gfs_inum)); + + if (eblks) + *eblks += ublks; + if (blocks) + *blocks += ublks; + if (bmem) + *bmem += ublks; +} + +/** + * unlinked_trans_combine - combine two incore transactions + * @sdp: the filesystem + * @tr: the surviving transaction + * @new_tr: the transaction that's going to disappear + * + */ + +static void +unlinked_trans_combine(struct gfs_sbd *sdp, struct gfs_trans *tr, + struct gfs_trans *new_tr) +{ + tr->tr_num_iul += new_tr->tr_num_iul; + tr->tr_num_ida += new_tr->tr_num_ida; +} + +/** + * unlinked_build_bhlist - create the buffers that will make up the ondisk part of a transaction + * @sdp: the filesystem + * @tr: the transaction + * + * For unlinked and/or deallocated inode log elements (separately): + * Get a log block + * Create a log descriptor in beginning of that block + * Fill rest of block with gfs_inum structs to identify each inode + * that became unlinked/deallocated during this transaction. + * Get another log block if needed, continue filling with gfs_inums. + */ + +static void +unlinked_build_bhlist(struct gfs_sbd *sdp, struct gfs_trans *tr) +{ + struct list_head *tmp, *head; + struct gfs_log_element *le; + struct gfs_unlinked *ul; + struct gfs_log_descriptor desc; + struct gfs_log_buf *lb; + unsigned int pass = 2; + unsigned int type, number; + unsigned int offset, entries; + + /* 2 passes: 1st for Unlinked, 2nd for De-Alloced inodes, + unless this is a log dump: just 1 pass, for Unlinked */ + while (pass--) { + if (tr->tr_flags & TRF_LOG_DUMP) { + if (pass) { + type = GFS_LOG_DESC_IUL; + number = tr->tr_num_iul; + } else + break; + } else { + if (pass) { + type = GFS_LOG_DESC_IUL; + number = tr->tr_num_iul; + } else { + type = GFS_LOG_DESC_IDA; + number = tr->tr_num_ida; + } + + if (!number) + continue; + } + + lb = gfs_log_get_buf(sdp, tr); + + /* Header: log descriptor */ + memset(&desc, 0, sizeof(struct gfs_log_descriptor)); + desc.ld_header.mh_magic = GFS_MAGIC; + desc.ld_header.mh_type = GFS_METATYPE_LD; + desc.ld_header.mh_format = GFS_FORMAT_LD; + desc.ld_type = type; + desc.ld_length = gfs_struct2blk(sdp, number, sizeof(struct gfs_inum)); + desc.ld_data1 = (tr->tr_flags & TRF_LOG_DUMP) ? TRUE : FALSE; + gfs_desc_out(&desc, lb->lb_bh.b_data); + + offset = sizeof(struct gfs_log_descriptor); + entries = 0; + + /* Look through transaction's log elements for Unlinked LEs */ + for (head = &tr->tr_elements, tmp = head->next; + tmp != head; + tmp = tmp->next) { + le = list_entry(tmp, struct gfs_log_element, le_list); + if (le->le_ops != &gfs_unlinked_lops) + continue; + if (tr->tr_flags & TRF_LOG_DUMP) + ul = container_of(le, + struct gfs_unlinked, + ul_ondisk_le); + else { + ul = container_of(le, + struct gfs_unlinked, + ul_incore_le); + if (!!test_bit(ULF_INCORE_UL, &ul->ul_flags) != pass) + continue; + } + + if (offset + sizeof(struct gfs_inum) > sdp->sd_sb.sb_bsize) { + offset = 0; + lb = gfs_log_get_buf(sdp, tr); + } + + /* Payload: write the inode identifier */ + gfs_inum_out(&ul->ul_inum, + lb->lb_bh.b_data + offset); + + offset += sizeof(struct gfs_inum); + entries++; + } + + gfs_assert(sdp, entries == number,); + } +} + +/** + * unlinked_dump_size - compute how much space the LE class takes up in a log dump + * @sdp: the filesystem + * @elements: the number of log elements in the dump + * @blocks: the number of blocks in the dump + * @bmem: the number of buffer-sized chunks of memory we need + * + */ + +static void +unlinked_dump_size(struct gfs_sbd *sdp, unsigned int *elements, + unsigned int *blocks, unsigned int *bmem) +{ + unsigned int c = atomic_read(&sdp->sd_unlinked_od_count); + unsigned int b = gfs_struct2blk(sdp, c, sizeof(struct gfs_inum)); + + if (elements) + *elements += c; + if (blocks) + *blocks += b; + if (bmem) + *bmem += b; +} + +/** + * unlinked_build_dump - create a transaction that represents a log dump for this LE class + * @sdp: the filesystem + * @tr: the transaction to fill + * + */ + +static void +unlinked_build_dump(struct gfs_sbd *sdp, struct gfs_trans *tr) +{ + struct list_head *tmp, *head; + struct gfs_unlinked *ul; + unsigned int x = 0; + + tr->tr_num_iul = atomic_read(&sdp->sd_unlinked_od_count); + + spin_lock(&sdp->sd_unlinked_lock); + + for (head = &sdp->sd_unlinked_list, tmp = head->next; + tmp != head; + tmp = tmp->next) { + ul = list_entry(tmp, struct gfs_unlinked, ul_list); + if (!test_bit(ULF_OD_LIST, &ul->ul_flags)) + continue; + + gfs_assert(sdp, !ul->ul_ondisk_le.le_trans,); + ul->ul_ondisk_le.le_trans = tr; + list_add(&ul->ul_ondisk_le.le_list, &tr->tr_elements); + + x++; + } + + spin_unlock(&sdp->sd_unlinked_lock); + + gfs_assert(sdp, x == atomic_read(&sdp->sd_unlinked_od_count),); +} + +/** + * unlinked_before_scan - called before a log dump is recovered + * @sdp: the filesystem + * @jid: the journal ID about to be scanned + * @head: the current head of the log + * @pass: the pass through the journal + * + */ + +static void +unlinked_before_scan(struct gfs_sbd *sdp, unsigned int jid, + struct gfs_log_header *head, unsigned int pass) +{ + if (pass == GFS_RECPASS_B1) + clear_bit(SDF_FOUND_UL_DUMP, &sdp->sd_flags); +} + +/** + * unlinked_scan_elements - scan unlinked inodes from the journal + * @sdp: the filesystem + * @jdesc: the struct gfs_jindex structure for the journal being scaned + * @gl: the journal's glock + * @start: the starting block of the descriptor + * @desc: the descriptor structure + * @pass: the pass through the journal + * + * Returns: errno + */ + +static int +unlinked_scan_elements(struct gfs_sbd *sdp, struct gfs_jindex *jdesc, + struct gfs_glock *gl, uint64_t start, + struct gfs_log_descriptor *desc, unsigned int pass) +{ + struct gfs_inum inum; + struct buffer_head *bh; + unsigned int offset = sizeof(struct gfs_log_descriptor); + unsigned int x; + int error; + + if (pass != GFS_RECPASS_B1) + return 0; + + switch (desc->ld_type) { + case GFS_LOG_DESC_IUL: + if (test_bit(SDF_FOUND_UL_DUMP, &sdp->sd_flags)) + gfs_assert(sdp, !desc->ld_data1,); + else { + gfs_assert(sdp, desc->ld_data1,); + set_bit(SDF_FOUND_UL_DUMP, &sdp->sd_flags); + } + break; + + case GFS_LOG_DESC_IDA: + gfs_assert(sdp, test_bit(SDF_FOUND_UL_DUMP, &sdp->sd_flags),); + break; + + default: + return 0; + } + + for (x = 0; x < desc->ld_length; x++) { + error = gfs_dread(gl, start, DIO_START | DIO_WAIT, &bh); + if (error) + return error; + + for (; + offset + sizeof(struct gfs_inum) <= sdp->sd_sb.sb_bsize; + offset += sizeof(struct gfs_inum)) { + gfs_inum_in(&inum, bh->b_data + offset); + + if (inum.no_addr) + gfs_unlinked_merge(sdp, desc->ld_type, &inum); + } + + brelse(bh); + + error = gfs_increment_blkno(sdp, jdesc, gl, &start, TRUE); + if (error) + return error; + + offset = 0; + } + + return 0; +} + +/** + * unlinked_after_scan - called after a log dump is recovered + * @sdp: the filesystem + * @jid: the journal ID about to be scanned + * @pass: the pass through the journal + * + */ + +static void +unlinked_after_scan(struct gfs_sbd *sdp, unsigned int jid, unsigned int pass) +{ + if (pass == GFS_RECPASS_B1) { + gfs_assert(sdp, test_bit(SDF_FOUND_UL_DUMP, &sdp->sd_flags),); + printk("GFS: fsid=%s: Found %d unlinked inodes\n", + sdp->sd_fsname, atomic_read(&sdp->sd_unlinked_ic_count)); + } +} + +/** + * quota_print - print debug info about a log element + * @sdp: the filesystem + * @le: the log element + * @where: is this a new transaction or a incore transaction + * + */ + +static void +quota_print(struct gfs_sbd *sdp, struct gfs_log_element *le, unsigned int where) +{ + struct gfs_quota_le *ql; + + ql = container_of(le, struct gfs_quota_le, ql_le); + printk(" quota: %s %u: %"PRId64" blocks\n", + (test_bit(QDF_USER, &ql->ql_data->qd_flags)) ? "user" : "group", + ql->ql_data->qd_id, ql->ql_change); +} + +/** + * quota_incore_commit - commit this LE to the incore log + * @sdp: the filesystem + * @tr: the incore transaction this LE is a part of + * @le: the log element + * + */ + +static void +quota_incore_commit(struct gfs_sbd *sdp, struct gfs_trans *tr, + struct gfs_log_element *le) +{ + struct gfs_quota_le *ql = container_of(le, struct gfs_quota_le, ql_le); + struct gfs_quota_data *qd = ql->ql_data; + + gfs_assert(sdp, ql->ql_change,); + + /* Make this change under the sd_quota_lock, so other processes + checking qd_change_ic don't have to acquire the log lock. */ + + spin_lock(&sdp->sd_quota_lock); + qd->qd_change_new -= ql->ql_change; + qd->qd_change_ic += ql->ql_change; + spin_unlock(&sdp->sd_quota_lock); + + if (le->le_trans == tr) + list_add(&ql->ql_data_list, &qd->qd_le_list); + else { + struct list_head *tmp, *head; + struct gfs_quota_le *tmp_ql; + int found = FALSE; + + for (head = &qd->qd_le_list, tmp = head->next; + tmp != head; + tmp = tmp->next) { + tmp_ql = list_entry(tmp, struct gfs_quota_le, ql_data_list); + if (tmp_ql->ql_le.le_trans != tr) + continue; + + tmp_ql->ql_change += ql->ql_change; + + list_del(&le->le_list); + gfs_quota_put(sdp, qd); + kfree(ql); + + if (!tmp_ql->ql_change) { + list_del(&tmp_ql->ql_data_list); + list_del(&tmp_ql->ql_le.le_list); + gfs_quota_put(sdp, tmp_ql->ql_data); + kfree(tmp_ql); + tr->tr_num_q--; + } + + found = TRUE; + break; + } + + if (!found) { + le->le_trans = tr; + list_move(&le->le_list, &tr->tr_elements); + tr->tr_num_q++; + list_add(&ql->ql_data_list, &qd->qd_le_list); + } + } +} + +/** + * quota_add_to_ail - Add this LE to the AIL + * @sdp: the filesystem + * @le: the log element + * + */ + +static void +quota_add_to_ail(struct gfs_sbd *sdp, struct gfs_log_element *le) +{ + struct gfs_quota_le *ql = container_of(le, struct gfs_quota_le, ql_le); + struct gfs_quota_data *qd = ql->ql_data; + + qd->qd_change_od += ql->ql_change; + if (qd->qd_change_od) { + if (!test_bit(QDF_OD_LIST, &qd->qd_flags)) { + gfs_quota_hold(sdp, qd); + set_bit(QDF_OD_LIST, &qd->qd_flags); + atomic_inc(&sdp->sd_quota_od_count); + } + } else { + gfs_assert(sdp, test_bit(QDF_OD_LIST, &qd->qd_flags),); + clear_bit(QDF_OD_LIST, &qd->qd_flags); + gfs_quota_put(sdp, qd); + gfs_assert(sdp, atomic_read(&sdp->sd_quota_od_count),); + atomic_dec(&sdp->sd_quota_od_count); + } + + list_del(&ql->ql_data_list); + list_del(&le->le_list); + gfs_quota_put(sdp, qd); + kfree(ql); +} + +/** + * quota_clean_dump - clean up a LE after a log dump + * @sdp: the filesystem + * @le: the log element + * + */ + +static void +quota_clean_dump(struct gfs_sbd *sdp, struct gfs_log_element *le) +{ + le->le_trans = NULL; + list_del_init(&le->le_list); +} + +/** + * quota_trans_size - compute how much space the LE class takes up in a transaction + * @sdp: the filesystem + * @tr: the transaction + * @mblks: the number of regular metadata blocks + * @eblks: the number of extra blocks + * @blocks: the number of log blocks + * @bmem: the number of buffer-sized chunks of memory we need + * + */ + +static void +quota_trans_size(struct gfs_sbd *sdp, struct gfs_trans *tr, + unsigned int *mblks, unsigned int *eblks, + unsigned int *blocks, unsigned int *bmem) +{ + unsigned int qblks; + + if (tr->tr_num_q) { + qblks = gfs_struct2blk(sdp, tr->tr_num_q, + sizeof(struct gfs_quota_tag)); + + if (eblks) + *eblks += qblks; + if (blocks) + *blocks += qblks; + if (bmem) + *bmem += qblks; + } +} + +/** + * quota_trans_combine - combine two incore transactions + * @sdp: the filesystem + * @tr: the surviving transaction + * @new_tr: the transaction that's going to disappear + * + */ + +static void +quota_trans_combine(struct gfs_sbd *sdp, struct gfs_trans *tr, + struct gfs_trans *new_tr) +{ + tr->tr_num_q += new_tr->tr_num_q; +} + +/** + * quota_build_bhlist - create the buffers that will make up the ondisk part of a transaction + * @sdp: the filesystem + * @tr: the transaction + * + */ + +static void +quota_build_bhlist(struct gfs_sbd *sdp, struct gfs_trans *tr) +{ + struct list_head *tmp, *head; + struct gfs_log_element *le; + struct gfs_quota_le *ql; + struct gfs_log_descriptor desc; + struct gfs_quota_tag tag; + struct gfs_log_buf *lb; + unsigned int offset = sizeof(struct gfs_log_descriptor), entries = 0; + + if (!tr->tr_num_q && !(tr->tr_flags & TRF_LOG_DUMP)) + return; + + lb = gfs_log_get_buf(sdp, tr); + + memset(&desc, 0, sizeof(struct gfs_log_descriptor)); + desc.ld_header.mh_magic = GFS_MAGIC; + desc.ld_header.mh_type = GFS_METATYPE_LD; + desc.ld_header.mh_format = GFS_FORMAT_LD; + desc.ld_type = GFS_LOG_DESC_Q; + desc.ld_length = gfs_struct2blk(sdp, tr->tr_num_q, + sizeof(struct gfs_quota_tag)); + desc.ld_data1 = tr->tr_num_q; + desc.ld_data2 = (tr->tr_flags & TRF_LOG_DUMP) ? TRUE : FALSE; + gfs_desc_out(&desc, lb->lb_bh.b_data); + + for (head = &tr->tr_elements, tmp = head->next; + tmp != head; + tmp = tmp->next) { + le = list_entry(tmp, struct gfs_log_element, le_list); + if (le->le_ops != &gfs_quota_lops) + continue; + + ql = container_of(le, struct gfs_quota_le, ql_le); + + if (offset + sizeof(struct gfs_quota_tag) > + sdp->sd_sb.sb_bsize) { + offset = 0; + lb = gfs_log_get_buf(sdp, tr); + } + + memset(&tag, 0, sizeof(struct gfs_quota_tag)); + tag.qt_change = ql->ql_change; + tag.qt_flags = (test_bit(QDF_USER, &ql->ql_data->qd_flags)) ? + GFS_QTF_USER : 0; + tag.qt_id = ql->ql_data->qd_id; + + gfs_quota_tag_out(&tag, lb->lb_bh.b_data + offset); + + offset += sizeof(struct gfs_quota_tag); + entries++; + } + + gfs_assert(sdp, entries == tr->tr_num_q,); +} + +/** + * quota_dump_size - compute how much space the LE class takes up in a log dump + * @sdp: the filesystem + * @elements: the number of log elements in the dump + * @blocks: the number of blocks in the dump + * @bmem: the number of buffer-sized chunks of memory we need + * + */ + +static void +quota_dump_size(struct gfs_sbd *sdp, unsigned int *elements, + unsigned int *blocks, unsigned int *bmem) +{ + unsigned int c = atomic_read(&sdp->sd_quota_od_count); + unsigned int b = gfs_struct2blk(sdp, c, sizeof(struct gfs_quota_tag)); + + if (elements) + *elements += c; + if (blocks) + *blocks += b; + if (bmem) + *bmem += b; +} + +/** + * quota_build_dump - create a transaction that represents a log dump for this LE class + * @sdp: the filesystem + * @tr: the transaction to fill + * + */ + +static void +quota_build_dump(struct gfs_sbd *sdp, struct gfs_trans *tr) +{ + struct list_head *tmp, *head; + struct gfs_quota_data *qd; + struct gfs_quota_le *ql; + unsigned int x = 0; + + tr->tr_num_q = atomic_read(&sdp->sd_quota_od_count); + + spin_lock(&sdp->sd_quota_lock); + + for (head = &sdp->sd_quota_list, tmp = head->next; + tmp != head; + tmp = tmp->next) { + qd = list_entry(tmp, struct gfs_quota_data, qd_list); + if (!test_bit(QDF_OD_LIST, &qd->qd_flags)) + continue; + + ql = &qd->qd_ondisk_ql; + + ql->ql_le.le_ops = &gfs_quota_lops; + gfs_assert(sdp, !ql->ql_le.le_trans,); + ql->ql_le.le_trans = tr; + list_add(&ql->ql_le.le_list, &tr->tr_elements); + + ql->ql_data = qd; + ql->ql_change = qd->qd_change_od; + + x++; + } + + spin_unlock(&sdp->sd_quota_lock); + + gfs_assert(sdp, x == atomic_read(&sdp->sd_quota_od_count),); +} + +/** + * quota_before_scan - called before a log dump is recovered + * @sdp: the filesystem + * @jid: the journal ID about to be scanned + * @head: the current head of the log + * @pass: the pass through the journal + * + */ + +static void +quota_before_scan(struct gfs_sbd *sdp, unsigned int jid, + struct gfs_log_header *head, unsigned int pass) +{ + if (pass == GFS_RECPASS_B1) + clear_bit(SDF_FOUND_Q_DUMP, &sdp->sd_flags); +} + +/** + * quota_scan_elements - scan quota inodes from the journal + * @sdp: the filesystem + * @jdesc: the struct gfs_jindex structure for the journal being scaned + * @gl: the journal's glock + * @start: the starting block of the descriptor + * @desc: the descriptor structure + * @pass: the pass through the journal + * + * Returns: errno + */ + +static int +quota_scan_elements(struct gfs_sbd *sdp, struct gfs_jindex *jdesc, + struct gfs_glock *gl, uint64_t start, + struct gfs_log_descriptor *desc, unsigned int pass) +{ + struct gfs_quota_tag tag; + struct buffer_head *bh; + unsigned int num_tags = desc->ld_data1; + unsigned int offset = sizeof(struct gfs_log_descriptor); + unsigned int x; + int error; + + if (pass != GFS_RECPASS_B1) + return 0; + if (desc->ld_type != GFS_LOG_DESC_Q) + return 0; + + if (test_bit(SDF_FOUND_Q_DUMP, &sdp->sd_flags)) + gfs_assert(sdp, !desc->ld_data2,); + else { + gfs_assert(sdp, desc->ld_data2,); + set_bit(SDF_FOUND_Q_DUMP, &sdp->sd_flags); + } + + if (!num_tags) + return 0; + + for (x = 0; x < desc->ld_length; x++) { + error = gfs_dread(gl, start, DIO_START | DIO_WAIT, &bh); + if (error) + return error; + + while (offset + sizeof(struct gfs_quota_tag) <= + sdp->sd_sb.sb_bsize) { + gfs_quota_tag_in(&tag, bh->b_data + offset); + + error = gfs_quota_merge(sdp, &tag); + if (error) + goto out_drelse; + + if (!--num_tags) + goto out_drelse; + + offset += sizeof(struct gfs_quota_tag); + } + + brelse(bh); + + error = gfs_increment_blkno(sdp, jdesc, gl, &start, TRUE); + if (error) + return error; + + offset = 0; + } + + return 0; + + out_drelse: + brelse(bh); + + return error; +} + +/** + * quota_after_scan - called after a log dump is recovered + * @sdp: the filesystem + * @jid: the journal ID about to be scanned + * @pass: the pass through the journal + * + */ + +static void +quota_after_scan(struct gfs_sbd *sdp, unsigned int jid, unsigned int pass) +{ + if (pass == GFS_RECPASS_B1) { + gfs_assert(sdp, !sdp->sd_sb.sb_quota_di.no_formal_ino || + test_bit(SDF_FOUND_Q_DUMP, &sdp->sd_flags),); + printk("GFS: fsid=%s: Found quota changes for %d IDs\n", + sdp->sd_fsname, atomic_read(&sdp->sd_quota_od_count)); + } +} + +struct gfs_log_operations gfs_glock_lops = { + .lo_add = generic_le_add, + .lo_trans_end = glock_trans_end, + .lo_print = glock_print, + .lo_overlap_trans = glock_overlap_trans, + .lo_incore_commit = glock_incore_commit, + .lo_add_to_ail = glock_add_to_ail, + .lo_trans_combine = glock_trans_combine, + .lo_name = "glock" +}; + +struct gfs_log_operations gfs_buf_lops = { + .lo_add = generic_le_add, + .lo_print = buf_print, + .lo_incore_commit = buf_incore_commit, + .lo_add_to_ail = buf_add_to_ail, + .lo_trans_size = buf_trans_size, + .lo_trans_combine = buf_trans_combine, + .lo_build_bhlist = buf_build_bhlist, + .lo_before_scan = buf_before_scan, + .lo_scan_elements = buf_scan_elements, + .lo_after_scan = buf_after_scan, + .lo_name = "buf" +}; + +struct gfs_log_operations gfs_unlinked_lops = { + .lo_add = generic_le_add, + .lo_print = unlinked_print, + .lo_incore_commit = unlinked_incore_commit, + .lo_add_to_ail = unlinked_add_to_ail, + .lo_clean_dump = unlinked_clean_dump, + .lo_trans_size = unlinked_trans_size, + .lo_trans_combine = unlinked_trans_combine, + .lo_build_bhlist = unlinked_build_bhlist, + .lo_dump_size = unlinked_dump_size, + .lo_build_dump = unlinked_build_dump, + .lo_before_scan = unlinked_before_scan, + .lo_scan_elements = unlinked_scan_elements, + .lo_after_scan = unlinked_after_scan, + .lo_name = "unlinked" +}; + +struct gfs_log_operations gfs_quota_lops = { + .lo_add = generic_le_add, + .lo_print = quota_print, + .lo_incore_commit = quota_incore_commit, + .lo_add_to_ail = quota_add_to_ail, + .lo_clean_dump = quota_clean_dump, + .lo_trans_size = quota_trans_size, + .lo_trans_combine = quota_trans_combine, + .lo_build_bhlist = quota_build_bhlist, + .lo_dump_size = quota_dump_size, + .lo_build_dump = quota_build_dump, + .lo_before_scan = quota_before_scan, + .lo_scan_elements = quota_scan_elements, + .lo_after_scan = quota_after_scan, + .lo_name = "quota" +}; + +struct gfs_log_operations *gfs_log_ops[] = { + &gfs_glock_lops, + &gfs_buf_lops, + &gfs_unlinked_lops, + &gfs_quota_lops, + NULL +}; --- linux-2.6.27.orig/ubuntu/gfs/daemon.c +++ linux-2.6.27/ubuntu/gfs/daemon.c @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "daemon.h" +#include "glock.h" +#include "log.h" +#include "quota.h" +#include "recovery.h" +#include "super.h" +#include "unlinked.h" + +/** + * gfs_scand - Look for cached glocks and inodes to toss from memory + * @sdp: Pointer to GFS superblock + * + * One of these daemons runs, finding candidates to add to sd_reclaim_list. + * See gfs_glockd() + */ + +int +gfs_scand(void *data) +{ + struct gfs_sbd *sdp = (struct gfs_sbd *)data; + + while (!kthread_should_stop()) { + gfs_scand_internal(sdp); + schedule_timeout_interruptible(gfs_tune_get(sdp, gt_scand_secs) * HZ); + } + + return 0; +} + +/** + * gfs_glockd - Reclaim unused glock structures + * @sdp: Pointer to GFS superblock + * + * One or more of these daemons run, reclaiming glocks on sd_reclaim_list. + * sd_glockd_num says how many daemons are running now. + * Number of daemons can be set by user, with num_glockd mount option. + * See gfs_scand() + */ + +int +gfs_glockd(void *data) +{ + struct gfs_sbd *sdp = (struct gfs_sbd *)data; + + while (!kthread_should_stop()) { + while (atomic_read(&sdp->sd_reclaim_count)) + gfs_reclaim_glock(sdp); + + wait_event_interruptible(sdp->sd_reclaim_wchan, + (atomic_read(&sdp->sd_reclaim_count) || + kthread_should_stop())); + } + + return 0; +} + +/** + * gfs_recoverd - Recover dead machine's journals + * @sdp: Pointer to GFS superblock + * + */ + +int +gfs_recoverd(void *data) +{ + struct gfs_sbd *sdp = (struct gfs_sbd *)data; + + while (!kthread_should_stop()) { + gfs_check_journals(sdp); + schedule_timeout_interruptible(gfs_tune_get(sdp, gt_recoverd_secs) * HZ); + } + + return 0; +} + +/** + * gfs_logd - Update log tail as Active Items get flushed to in-place blocks + * @sdp: Pointer to GFS superblock + * + * Also, periodically check to make sure that we're using the most recent + * journal index. + */ + +int +gfs_logd(void *data) +{ + struct gfs_sbd *sdp = (struct gfs_sbd *)data; + struct gfs_holder ji_gh; + + while (!kthread_should_stop()) { + /* Advance the log tail */ + gfs_ail_empty(sdp); + + /* Check for latest journal index */ + if (time_after_eq(jiffies, + sdp->sd_jindex_refresh_time + + gfs_tune_get(sdp, gt_jindex_refresh_secs) * HZ)) { + if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags) && + !gfs_jindex_hold(sdp, &ji_gh)) + gfs_glock_dq_uninit(&ji_gh); + sdp->sd_jindex_refresh_time = jiffies; + } + + schedule_timeout_interruptible(gfs_tune_get(sdp, gt_logd_secs) * HZ); + } + + return 0; +} + +/** + * gfs_quotad - Write cached quota changes into the quota file + * @sdp: Pointer to GFS superblock + * + */ + +int +gfs_quotad(void *data) +{ + struct gfs_sbd *sdp = (struct gfs_sbd *)data; + int error; + + while (!kthread_should_stop()) { + /* Update statfs file */ + if (gfs_tune_get(sdp, gt_statfs_fast) && + time_after_eq(jiffies, + sdp->sd_statfs_sync_time + + gfs_tune_get(sdp, gt_statfs_fast) * HZ)) { + error = gfs_statfs_sync(sdp); + if (error && error != -EROFS && + !test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) + printk("GFS: fsid=%s: statfs: error = %d\n", + sdp->sd_fsname, error); + sdp->sd_statfs_sync_time = jiffies; + } + /* Update quota file */ + if (time_after_eq(jiffies, + sdp->sd_quota_sync_time + + gfs_tune_get(sdp, gt_quota_quantum) * HZ)) { + error = gfs_quota_sync(sdp); + if (error && + error != -EROFS && + !test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) + printk("GFS: fsid=%s: quotad: error = %d\n", + sdp->sd_fsname, error); + sdp->sd_quota_sync_time = jiffies; + } + + /* Clean up */ + gfs_quota_scan(sdp); + schedule_timeout_interruptible(gfs_tune_get(sdp, gt_quotad_secs) * HZ); + } + + return 0; +} + +/** + * gfs_inoded - Deallocate unlinked inodes + * @sdp: Pointer to GFS superblock + * + */ + +int +gfs_inoded(void *data) +{ + struct gfs_sbd *sdp = (struct gfs_sbd *)data; + + while (!kthread_should_stop()) { + gfs_unlinked_dealloc(sdp); + schedule_timeout_interruptible(gfs_tune_get(sdp, gt_inoded_secs) * HZ); + } + + return 0; +} --- linux-2.6.27.orig/ubuntu/gfs/Kconfig +++ linux-2.6.27/ubuntu/gfs/Kconfig @@ -0,0 +1,18 @@ +config GFS_FS + tristate "GFS file system support" + select FS_POSIX_ACL + select CRC32 + help + A cluster filesystem. + + Allows a cluster of computers to simultaneously use a block device + that is shared between them (with FC, iSCSI, NBD, etc...). GFS reads + and writes to the block device like a local filesystem, but also uses + a lock module to allow the computers coordinate their I/O so + filesystem consistency is maintained. One of the nifty features of + GFS is perfect consistency -- changes made to the filesystem on one + machine show up immediately on all other machines in the cluster. + + To use the GFS filesystem, you will need to enable one or more of + the below locking modules. Documentation and utilities for GFS can + be found here: http://sources.redhat.com/cluster --- linux-2.6.27.orig/ubuntu/gfs/glops.h +++ linux-2.6.27/ubuntu/gfs/glops.h @@ -0,0 +1,13 @@ +#ifndef __GLOPS_DOT_H__ +#define __GLOPS_DOT_H__ + +extern struct gfs_glock_operations gfs_meta_glops; +extern struct gfs_glock_operations gfs_inode_glops; +extern struct gfs_glock_operations gfs_rgrp_glops; +extern struct gfs_glock_operations gfs_trans_glops; +extern struct gfs_glock_operations gfs_iopen_glops; +extern struct gfs_glock_operations gfs_flock_glops; +extern struct gfs_glock_operations gfs_nondisk_glops; +extern struct gfs_glock_operations gfs_quota_glops; + +#endif /* __GLOPS_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/ops_fstype.c +++ linux-2.6.27/ubuntu/gfs/ops_fstype.c @@ -0,0 +1,816 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "daemon.h" +#include "glock.h" +#include "glops.h" +#include "inode.h" +#include "lm.h" +#include "mount.h" +#include "ops_export.h" +#include "ops_fstype.h" +#include "ops_super.h" +#include "proc.h" +#include "quota.h" +#include "recovery.h" +#include "rgrp.h" +#include "super.h" +#include "sys.h" +#include "unlinked.h" + +#define DO 0 +#define UNDO 1 + +extern struct dentry_operations gfs_dops; + +static struct gfs_sbd *init_sbd(struct super_block *sb) +{ + struct gfs_sbd *sdp; + unsigned int x; + + sdp = vmalloc(sizeof(struct gfs_sbd)); + if (!sdp) + return NULL; + + memset(sdp, 0, sizeof(struct gfs_sbd)); + + set_v2sdp(sb, sdp); + sdp->sd_vfs = sb; + gfs_tune_init(&sdp->sd_tune); + + /* Init rgrp variables */ + + INIT_LIST_HEAD(&sdp->sd_rglist); + init_MUTEX(&sdp->sd_rindex_lock); + INIT_LIST_HEAD(&sdp->sd_rg_mru_list); + spin_lock_init(&sdp->sd_rg_mru_lock); + INIT_LIST_HEAD(&sdp->sd_rg_recent); + spin_lock_init(&sdp->sd_rg_recent_lock); + spin_lock_init(&sdp->sd_rg_forward_lock); + + spin_lock_init(&sdp->sd_statfs_spin); + + for (x = 0; x < GFS_GL_HASH_SIZE; x++) { + sdp->sd_gl_hash[x].hb_lock = RW_LOCK_UNLOCKED; + INIT_LIST_HEAD(&sdp->sd_gl_hash[x].hb_list); + } + + INIT_LIST_HEAD(&sdp->sd_reclaim_list); + spin_lock_init(&sdp->sd_reclaim_lock); + init_waitqueue_head(&sdp->sd_reclaim_wchan); + + for (x = 0; x < GFS_MHC_HASH_SIZE; x++) + INIT_LIST_HEAD(&sdp->sd_mhc[x]); + INIT_LIST_HEAD(&sdp->sd_mhc_single); + spin_lock_init(&sdp->sd_mhc_lock); + + for (x = 0; x < GFS_DEPEND_HASH_SIZE; x++) + INIT_LIST_HEAD(&sdp->sd_depend[x]); + spin_lock_init(&sdp->sd_depend_lock); + + init_MUTEX(&sdp->sd_freeze_lock); + + spin_lock_init(&sdp->sd_log_seg_lock); + INIT_LIST_HEAD(&sdp->sd_log_seg_list); + init_waitqueue_head(&sdp->sd_log_seg_wait); + INIT_LIST_HEAD(&sdp->sd_log_ail); + INIT_LIST_HEAD(&sdp->sd_log_incore); + init_rwsem(&sdp->sd_log_lock); + INIT_LIST_HEAD(&sdp->sd_unlinked_list); + spin_lock_init(&sdp->sd_unlinked_lock); + INIT_LIST_HEAD(&sdp->sd_quota_list); + spin_lock_init(&sdp->sd_quota_lock); + + INIT_LIST_HEAD(&sdp->sd_dirty_j); + spin_lock_init(&sdp->sd_dirty_j_lock); + + spin_lock_init(&sdp->sd_ail_lock); + INIT_LIST_HEAD(&sdp->sd_recovery_bufs); + + return sdp; +} + +static void init_vfs(struct super_block *sb, unsigned noatime) +{ + struct gfs_sbd *sdp = sb->s_fs_info; + + /* Set up Linux Virtual (VFS) Super Block */ + + sb->s_magic = GFS_MAGIC; + sb->s_op = &gfs_super_ops; + sb->s_export_op = &gfs_export_ops; + + /* Don't let the VFS update atimes. GFS handles this itself. */ + sb->s_flags |= MS_NOATIME | MS_NODIRATIME; + sb->s_maxbytes = MAX_LFS_FILESIZE; + + /* If we were mounted with -o acl (to support POSIX access control + lists), tell VFS */ + if (sdp->sd_args.ar_posix_acls) + sb->s_flags |= MS_POSIXACL; +} + +int init_names(struct gfs_sbd *sdp, int silent) +{ + struct gfs_sb *sb = NULL; + char *proto, *table; + int error = 0; + + proto = sdp->sd_args.ar_lockproto; + table = sdp->sd_args.ar_locktable; + + /* Try to autodetect */ + + if (!proto[0] || !table[0]) { + struct buffer_head *bh; + + bh = sb_getblk(sdp->sd_vfs, + GFS_SB_ADDR >> sdp->sd_fsb2bb_shift); + lock_buffer(bh); + clear_buffer_uptodate(bh); + clear_buffer_dirty(bh); + unlock_buffer(bh); + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + + if (!buffer_uptodate(bh)) { + brelse(bh); + return -EIO; + } + + sb = kmalloc(sizeof(struct gfs_sb), GFP_KERNEL); + if (!sb) { + brelse(bh); + return -ENOMEM; + } + gfs_sb_in(sb, bh->b_data); + brelse(bh); + + error = gfs_check_sb(sdp, sb, silent); + if (error) + goto out; + + if (!proto[0]) + proto = sb->sb_lockproto; + if (!table[0]) + table = sb->sb_locktable; + } + + if (!table[0]) + table = sdp->sd_vfs->s_id; + + snprintf(sdp->sd_proto_name, 256, "%s", proto); + snprintf(sdp->sd_table_name, 256, "%s", table); + + while ((table = strchr(sdp->sd_table_name, '/'))) + *table = '_'; + + out: + kfree(sb); + + return error; +} + +static int init_locking(struct gfs_sbd *sdp, struct gfs_holder *mount_gh, + int undo) +{ + struct task_struct *p; + int error = 0; + + if (undo) + goto fail_live; + + if ((sdp->sd_lockstruct.ls_flags & LM_LSFLAG_LOCAL) && + !sdp->sd_args.ar_ignore_local_fs) { + /* Force local [p|f]locks */ + sdp->sd_args.ar_localflocks = TRUE; + + /* Force local read ahead and caching */ + sdp->sd_args.ar_localcaching = TRUE; + + /* Allow the machine to oops */ + sdp->sd_args.ar_oopses_ok = TRUE; + } + + /* Start up the scand thread */ + + p = kthread_run(gfs_scand, sdp, "gfs_scand"); + error = IS_ERR(p); + if (error) { + printk("GFS: fsid=%s: can't start scand thread: %d\n", + sdp->sd_fsname, error); + return error; + } + sdp->sd_scand_process = p; + + /* Start up the glockd thread */ + + for (sdp->sd_glockd_num = 0; + sdp->sd_glockd_num < sdp->sd_args.ar_num_glockd; + sdp->sd_glockd_num++) { + p = kthread_run(gfs_glockd, sdp, "gfs_glockd"); + error = IS_ERR(p); + if (error) { + printk("GFS: fsid=%s: can't start glockd thread: %d\n", + sdp->sd_fsname, error); + goto fail; + } + sdp->sd_glockd_process[sdp->sd_glockd_num] = p; + } + + /* Only one node may mount at a time */ + error = gfs_glock_nq_num(sdp, + GFS_MOUNT_LOCK, &gfs_nondisk_glops, + LM_ST_EXCLUSIVE, LM_FLAG_NOEXP | GL_NOCACHE, + mount_gh); + if (error) { + printk("GFS: fsid=%s: can't acquire mount glock: %d\n", + sdp->sd_fsname, error); + goto fail; + } + + /* Show that cluster is alive */ + error = gfs_glock_nq_num(sdp, + GFS_LIVE_LOCK, &gfs_nondisk_glops, + LM_ST_SHARED, LM_FLAG_NOEXP | GL_EXACT, + &sdp->sd_live_gh); + if (error) { + printk("GFS: fsid=%s: can't acquire live glock: %d\n", + sdp->sd_fsname, error); + goto fail_mount; + } + + sdp->sd_live_gh.gh_owner = NULL; + return 0; + +fail_live: + gfs_glock_dq_uninit(&sdp->sd_live_gh); + +fail_mount: + gfs_glock_dq_uninit(mount_gh); + +fail: + while (sdp->sd_glockd_num--) + kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]); + + kthread_stop(sdp->sd_scand_process); + + return error; +} + +static int init_sb(struct gfs_sbd *sdp, int silent, int undo) +{ + struct super_block *sb = sdp->sd_vfs; + struct gfs_holder sb_gh; + int error = 0; + struct inode *inode; + + if (undo) + goto fail_dput; + + /* Read the SuperBlock from disk, get enough info to enable us + to read-in the journal index and replay all journals. */ + + error = gfs_glock_nq_num(sdp, + GFS_SB_LOCK, &gfs_meta_glops, + (sdp->sd_args.ar_upgrade) ? LM_ST_EXCLUSIVE : LM_ST_SHARED, + 0, &sb_gh); + if (error) { + printk("GFS: fsid=%s: can't acquire superblock glock: %d\n", + sdp->sd_fsname, error); + return error; + } + + error = gfs_read_sb(sdp, sb_gh.gh_gl, silent); + if (error) { + printk("GFS: fsid=%s: can't read superblock: %d\n", + sdp->sd_fsname, error); + goto out; + } + + /* Set up the buffer cache and SB for real, now that we know block + sizes, version #s, locations of important on-disk inodes, etc. */ + + error = -EINVAL; + if (sdp->sd_sb.sb_bsize < bdev_hardsect_size(sb->s_bdev)) { + printk("GFS: fsid=%s: FS block size (%u) is too small for device block size (%u)\n", + sdp->sd_fsname, sdp->sd_sb.sb_bsize, bdev_hardsect_size(sb->s_bdev)); + goto fail; + } + if (sdp->sd_sb.sb_bsize > PAGE_SIZE) { + printk("GFS: fsid=%s: FS block size (%u) is too big for machine page size (%u)\n", + sdp->sd_fsname, sdp->sd_sb.sb_bsize, + (unsigned int)PAGE_SIZE); + goto fail; + } + + /* Get rid of buffers from the original block size */ + sb_gh.gh_gl->gl_ops->go_inval(sb_gh.gh_gl, DIO_METADATA | DIO_DATA); + sb_gh.gh_gl->gl_aspace->i_blkbits = sdp->sd_sb.sb_bsize_shift; + + sb_set_blocksize(sb, sdp->sd_sb.sb_bsize); + + /* Read in the resource index inode */ + + error = gfs_get_riinode(sdp); + if (error) { + printk("GFS: fsid=%s: can't get resource index inode: %d\n", + sdp->sd_fsname, error); + goto fail; + } + + /* Get the root inode */ + error = gfs_get_rootinode(sdp); + if (error) { + printk("GFS: fsid=%s: can't read in root inode: %d\n", + sdp->sd_fsname, error); + goto fail_ri_free; + } + /* Get the root inode/dentry */ + + inode = gfs_iget(sdp->sd_rooti, CREATE); + if (!inode) { + printk("GFS: fsid=%s: can't get root inode\n", sdp->sd_fsname); + error = -ENOMEM; + goto fail_ri_free; + } + sb->s_root = d_alloc_root(inode); + if (!sb->s_root) { + iput(inode); + printk("GFS: fsid=%s: can't get root dentry\n", sdp->sd_fsname); + error = -ENOMEM; + goto fail_root_free; + } + sb->s_root->d_op = &gfs_dops; + + /* Read in the quota inode */ + error = gfs_get_qinode(sdp); + if (error) { + printk("GFS: fsid=%s: can't get quota file inode: %d\n", + sdp->sd_fsname, error); + goto fail_root_free; + } + + /* Implement fast statfs on the unused license inode location. + * sb->sb_quota_di.no_formal_ino = jindex_dinode + 2; + * sb->sb_quota_di.no_addr = jindex_dinode + 2; + * sb->sb_license_di.no_formal_ino = jindex_dinode + 3; + * sb->sb_license_di.no_addr = jindex_dinode + 3; + */ + error = gfs_get_linode(sdp); + if (error) { + printk("GFS: fsid=%s: can't get statfs file inode: %d\n", + sdp->sd_fsname, error); + goto fail_qi_free; + } + + /* We're through with the superblock lock */ +out: + gfs_glock_dq_uninit(&sb_gh); + return error; + +fail_dput: + gfs_inode_put(sdp->sd_linode); + if (sb->s_root) { + dput(sb->s_root); + sb->s_root = NULL; + } +fail_qi_free: + gfs_inode_put(sdp->sd_qinode); +fail_root_free: + gfs_inode_put(sdp->sd_rooti); +fail_ri_free: + gfs_inode_put(sdp->sd_riinode); + gfs_clear_rgrpd(sdp); +fail: + if (!undo) + gfs_glock_dq_uninit(&sb_gh); + return error; +} + +static int init_journal(struct gfs_sbd *sdp, int undo) +{ + struct gfs_holder ji_gh; + int error = 0; + unsigned int x; + int jindex = TRUE; + struct task_struct *p; + + if (undo) { + jindex = 0; + goto fail_recoverd; + } + + init_MUTEX(&sdp->sd_jindex_lock); + + /* Get a handle on the transaction glock; we need this for disk format + upgrade and journal replays, as well as normal operation. */ + + error = gfs_glock_get(sdp, GFS_TRANS_LOCK, &gfs_trans_glops, + CREATE, &sdp->sd_trans_gl); + if (error) + return error; + set_bit(GLF_STICKY, &sdp->sd_trans_gl->gl_flags); + + /* Load in the journal index special file */ + + error = gfs_jindex_hold(sdp, &ji_gh); + if (error) { + printk("GFS: fsid=%s: can't read journal index: %d\n", + sdp->sd_fsname, error); + goto fail_jhold; + } + + if (sdp->sd_args.ar_spectator) { + sdp->sd_jdesc = sdp->sd_jindex[0]; + sdp->sd_log_seg_free = sdp->sd_jdesc.ji_nsegment; + sdp->sd_log_seg_ail2 = 0; + } + else { + /* Discover this node's journal number (lock module tells us + which one to use), and lock it */ + error = -EINVAL; + if (sdp->sd_lockstruct.ls_jid >= sdp->sd_journals) { + printk("GFS: fsid=%s: can't mount journal #%u\n", + sdp->sd_fsname, sdp->sd_lockstruct.ls_jid); + printk("GFS: fsid=%s: there are only %u journals (0 - %u)\n", + sdp->sd_fsname, sdp->sd_journals, sdp->sd_journals - 1); + goto fail_jindex; + } + sdp->sd_jdesc = sdp->sd_jindex[sdp->sd_lockstruct.ls_jid]; + sdp->sd_log_seg_free = sdp->sd_jdesc.ji_nsegment; + sdp->sd_log_seg_ail2 = 0; + + error = gfs_glock_nq_num(sdp, + sdp->sd_jdesc.ji_addr, &gfs_meta_glops, + LM_ST_EXCLUSIVE, LM_FLAG_NOEXP, + &sdp->sd_journal_gh); + if (error) { + printk("GFS: fsid=%s: can't acquire the journal glock: %d\n", + sdp->sd_fsname, error); + goto fail_jindex; + } + } + + if (sdp->sd_lockstruct.ls_first) { + /* We're first node within cluster to mount this filesystem, + replay ALL of the journals, then let lock module know + that we're done. */ + for (x = 0; x < sdp->sd_journals; x++) { + error = gfs_recover_journal(sdp, + x, sdp->sd_jindex + x, + FALSE); + if (error) { + printk("GFS: fsid=%s: error recovering journal %u: %d\n", + sdp->sd_fsname, x, error); + goto fail_journal_gh; + } + } + + gfs_lm_others_may_mount(sdp); + } else if (!sdp->sd_args.ar_spectator) { + /* We're not the first; replay only our own journal. */ + error = gfs_recover_journal(sdp, sdp->sd_lockstruct.ls_jid, + &sdp->sd_jdesc, TRUE); + if (error) { + printk("GFS: fsid=%s: error recovering my journal: %d\n", + sdp->sd_fsname, error); + goto fail_journal_gh; + } + } + + gfs_glock_dq_uninit(&ji_gh); + jindex = FALSE; + + /* Disown my Journal glock */ + sdp->sd_journal_gh.gh_owner = NULL; + + /* Make the FS read/write */ + + if (!test_bit(SDF_ROFS, &sdp->sd_flags)) { + error = gfs_make_fs_rw(sdp); + if (error) { + printk("GFS: fsid=%s: can't make file system RW: %d\n", + sdp->sd_fsname, error); + goto fail_journal_gh; + } + } + + /* Start up the journal recovery thread */ + + p = kthread_run(gfs_recoverd, sdp, "gfs_recoverd"); + error = IS_ERR(p); + if (error) { + printk("GFS: fsid=%s: can't start recoverd thread: %d\n", + sdp->sd_fsname, error); + goto fail_journal_gh; + } + sdp->sd_recoverd_process = p; + + return 0; + +fail_recoverd: + kthread_stop(sdp->sd_recoverd_process); + sdp->sd_recoverd_process = NULL; + +fail_journal_gh: + if (!sdp->sd_args.ar_spectator) + gfs_glock_dq_uninit(&sdp->sd_journal_gh); + +fail_jindex: + if (jindex) + gfs_glock_dq_uninit(&ji_gh); + +fail_jhold: + gfs_glock_put(sdp->sd_trans_gl); + return error; +} + +static int init_threads(struct gfs_sbd *sdp, int undo) +{ + struct task_struct *p; + int error = 0; + + if (undo) + goto fail_logd; + + sdp->sd_jindex_refresh_time = jiffies; + + /* Start up the logd thread */ + p = kthread_run(gfs_logd, sdp, "gfs_logd"); + error = IS_ERR(p); + if (error) { + printk("GFS: fsid=%s: can't start logd thread: %d\n", + sdp->sd_fsname, error); + goto fail; + } + sdp->sd_logd_process = p; + + /* Start up the quotad thread */ + + p = kthread_run(gfs_quotad, sdp, "gfs_quotad"); + if (error < 0) { + printk("GFS: fsid=%s: can't start quotad thread: %d\n", + sdp->sd_fsname, error); + goto fail_quotad; + } + sdp->sd_quotad_process = p; + + /* Start up the inoded thread */ + + p = kthread_run(gfs_inoded, sdp, "gfs_inoded"); + if (error < 0) { + printk("GFS: fsid=%s: can't start inoded thread: %d\n", + sdp->sd_fsname, error); + goto fail_inoded; + } + sdp->sd_inoded_process = p; + return 0; + +fail_logd: + kthread_stop(sdp->sd_inoded_process); +fail_inoded: + kthread_stop(sdp->sd_quotad_process); +fail_quotad: + kthread_stop(sdp->sd_logd_process); +fail: + return error; +} + +/** + * fill_super - Read in superblock + * @sb: The VFS superblock + * @data: Mount options + * @silent: Don't complain if it's not a GFS filesystem + * + * Returns: errno + * + * After cross-linking Linux VFS incore superblock and our GFS incore + * superblock (filesystem instance structures) to one another, we: + * -- Init some of our GFS incore superblock, including some temporary + * block-size values (enough to read on-disk superblock). + * -- Set up some things in Linux VFS superblock. + * -- Mount a lock module, init glock system (incl. glock reclaim daemons), + * and init some important inter-node locks (MOUNT, LIVE, SuperBlock). + * -- Read-in the GFS on-disk superblock (1st time, to get enough info + * to do filesystem upgrade and journal replay, incl. journal index). + * -- Upgrade on-disk filesystem format (rarely needed). + * -- Replay journals (always; replay *all* journals if we're first-to-mount). + * -- Read-in on-disk superblock and journal index special file again + * (2nd time, assumed 100% valid now after journal replay). + * -- Read-in info on other special (hidden) files (root inode, resource index, + * quota inode, license inode). + * -- Start other daemons (journal/log recovery, log tail, quota updates, inode + * reclaim) for periodic maintenance. + * + */ + +static int fill_super(struct super_block *sb, void *data, int silent) +{ + struct gfs_sbd *sdp; + struct gfs_holder mount_gh; + int error; + + sdp = init_sbd(sb); + if (!sdp) { + printk(KERN_WARNING "GFS: can't alloc struct gfs_sbd\n"); + return -ENOMEM; + } + + error = gfs_make_args((char *)data, &sdp->sd_args, FALSE); + if (error) { + printk("GFS: can't parse mount arguments\n"); + goto fail; + } + + if (sdp->sd_args.ar_spectator) { + sb->s_flags |= MS_RDONLY; + set_bit(SDF_ROFS, &sdp->sd_flags); + } + + /* Copy VFS mount flags */ + + if (sb->s_flags & (MS_NOATIME | MS_NODIRATIME)) + set_bit(SDF_NOATIME, &sdp->sd_flags); + if (sb->s_flags & MS_RDONLY) + set_bit(SDF_ROFS, &sdp->sd_flags); + + init_vfs(sb, SDF_NOATIME); + + /* Turn off quota stuff if we get the noquota mount option, don't + need to grab the sd_tune lock here since its before anything + touches the sd_tune values */ + if (sdp->sd_args.ar_noquota) { + sdp->sd_tune.gt_quota_enforce = 0; + sdp->sd_tune.gt_quota_account = 0; + } + + /* Set up the buffer cache and fill in some fake block size values + to allow us to read-in the on-disk superblock. */ + + sdp->sd_sb.sb_bsize = sb_min_blocksize(sb, GFS_BASIC_BLOCK); + sdp->sd_sb.sb_bsize_shift = sb->s_blocksize_bits; + sdp->sd_fsb2bb_shift = sdp->sd_sb.sb_bsize_shift - GFS_BASIC_BLOCK_SHIFT; + sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift; + + if (sizeof(struct gfs_sb) > sdp->sd_sb.sb_bsize) { + printk("GFS: sizeof(struct gfs_sb) > sdp->sd_sb.sb_bsize\n" + "GFS: %u > %u\n", + (unsigned int)sizeof(struct gfs_sb), sdp->sd_sb.sb_bsize); + error = -EINVAL; + goto fail; + } + error = init_names(sdp, silent); + if (error) + goto fail; + + error = gfs_sys_fs_add(sdp); + if (error) + goto fail; + + /* Mount an inter-node lock module, check for local optimizations */ + + error = gfs_lm_mount(sdp, silent); + if (error) + goto fail_sys; + + error = init_locking(sdp, &mount_gh, DO); + if (error) + goto fail_lm; + + error = init_sb(sdp, silent, DO); + if (error) + goto fail_locking; + + /* Read-in journal index inode (but not the file contents, yet) */ + + error = gfs_get_jiinode(sdp); + if (error) { + printk("GFS: fsid=%s: can't get journal index inode: %d\n", + sdp->sd_fsname, error); + goto fail_jiinode; + } + + error = init_journal(sdp, DO); + if (error) + goto fail_sb; + /* Get a handle on the rename lock */ + + error = gfs_glock_get(sdp, GFS_RENAME_LOCK, &gfs_nondisk_glops, + CREATE, &sdp->sd_rename_gl); + if (error) + goto fail_journal; + + error = init_threads(sdp, DO); + if (error) + goto fail_journal; + + gfs_proc_fs_add(sdp); + gfs_glock_dq_uninit(&mount_gh); + + return 0; + +fail_journal: + init_journal(sdp, UNDO); + +fail_sb: + gfs_inode_put(sdp->sd_jiinode); + +fail_jiinode: + init_sb(sdp, 0, UNDO); + +fail_locking: + init_locking(sdp, &mount_gh, UNDO); + +fail_lm: + gfs_gl_hash_clear(sdp, TRUE); + gfs_lm_unmount(sdp); + gfs_clear_dirty_j(sdp); + while (invalidate_inodes(sb)) + yield(); + +fail_sys: + gfs_sys_fs_del(sdp); + +fail: + vfree(sdp); + sb->s_fs_info = NULL; + + return error; +} + +/** + * gfs_test_bdev_super - + * @sb: + * @data: + * + */ + +int +gfs_test_bdev_super(struct super_block *sb, void *data) +{ + return (void *)sb->s_bdev == data; +} + +/** + * gfs_test_bdev_super - + * @sb: + * @data: + * + */ + +int +gfs_set_bdev_super(struct super_block *sb, void *data) +{ + sb->s_bdev = data; + sb->s_dev = sb->s_bdev->bd_dev; + return 0; +} + +/** + * gfs_get_sb - + * @fs_type: + * @flags: + * @dev_name: + * @data: + * + * Rip off of get_sb_bdev(). + * + * Returns: the new superblock + */ + +static int gfs_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, struct vfsmount *mnt) +{ + return get_sb_bdev(fs_type, flags, dev_name, data, fill_super, mnt); +} + +/** + * gfs_kill_sb - + * @sb: + * + * Rip off of kill_block_super(). + * + */ + +void +gfs_kill_sb(struct super_block *sb) +{ + kill_block_super(sb); +} + +struct file_system_type gfs_fs_type = { + .name = "gfs", + .fs_flags = FS_REQUIRES_DEV, + .get_sb = gfs_get_sb, + .kill_sb = gfs_kill_sb, + .owner = THIS_MODULE, +}; --- linux-2.6.27.orig/ubuntu/gfs/ops_vm.c +++ linux-2.6.27/ubuntu/gfs/ops_vm.c @@ -0,0 +1,233 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "bmap.h" +#include "glock.h" +#include "inode.h" +#include "ops_vm.h" +#include "page.h" +#include "quota.h" +#include "rgrp.h" +#include "trans.h" + +/** + * pfault_be_greedy - + * @ip: + * + */ + +static void +pfault_be_greedy(struct gfs_inode *ip) +{ + unsigned int time; + + spin_lock(&ip->i_spin); + time = ip->i_greedy; + ip->i_last_pfault = jiffies; + spin_unlock(&ip->i_spin); + + gfs_inode_hold(ip); + if (gfs_glock_be_greedy(ip->i_gl, time)) + gfs_inode_put(ip); +} + +/** + * gfs_private_fault - + * @area: + * @address: + * @type: + * + * Returns: the page + */ + +static int gfs_private_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct gfs_inode *ip = get_v2ip(vma->vm_file->f_mapping->host); + struct gfs_holder i_gh; + int error; + int ret = 0; + + atomic_inc(&ip->i_sbd->sd_ops_vm); + + error = gfs_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh); + if (error) + goto out; + + set_bit(GIF_PAGED, &ip->i_flags); + + ret = filemap_fault(vma, vmf); + + if (ret && ret != VM_FAULT_OOM) + pfault_be_greedy(ip); + + gfs_glock_dq_uninit(&i_gh); + out: + return ret; +} + +/** + * alloc_page_backing - + * @ip: + * @index: + * + * Returns: errno + */ + +static int +alloc_page_backing(struct gfs_inode *ip, struct page *page) +{ + struct gfs_sbd *sdp = ip->i_sbd; + unsigned long index = page->index; + uint64_t lblock = index << (PAGE_CACHE_SHIFT - sdp->sd_sb.sb_bsize_shift); + unsigned int blocks = PAGE_CACHE_SIZE >> sdp->sd_sb.sb_bsize_shift; + struct gfs_alloc *al; + unsigned int x; + int error; + + al = gfs_alloc_get(ip); + + error = gfs_quota_lock_m(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out; + + error = gfs_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid); + if (error) + goto out_gunlock_q; + + gfs_write_calc_reserv(ip, PAGE_CACHE_SIZE, + &al->al_requested_data, &al->al_requested_meta); + + error = gfs_inplace_reserve(ip); + if (error) + goto out_gunlock_q; + + /* Trans may require: + a dinode block, RG bitmaps to allocate from, + indirect blocks, and a quota block */ + + error = gfs_trans_begin(sdp, + 1 + al->al_rgd->rd_ri.ri_length + + al->al_requested_meta, 1); + if (error) + goto out_ipres; + + if (gfs_is_stuffed(ip)) { + error = gfs_unstuff_dinode(ip, gfs_unstuffer_page, NULL); + if (error) + goto out_trans; + } + + for (x = 0; x < blocks; ) { + uint64_t dblock; + unsigned int extlen; + int new = TRUE; + + error = gfs_block_map(ip, lblock, &new, &dblock, &extlen); + if (error) + goto out_trans; + + lblock += extlen; + x += extlen; + } + + gfs_assert_warn(sdp, al->al_alloced_meta || al->al_alloced_data); + + out_trans: + gfs_trans_end(sdp); + + out_ipres: + gfs_inplace_release(ip); + + out_gunlock_q: + gfs_quota_unlock_m(ip); + + out: + gfs_alloc_put(ip); + + return error; +} + +/** + * gfs_sharewrite_fault - + * @area: + * @address: + * @type: + * + * Returns: the page + */ + +static int gfs_sharewrite_fault(struct vm_area_struct *vma, + struct vm_fault *vmf) +{ + struct file *file = vma->vm_file; + struct gfs_inode *ip = get_v2ip(file->f_mapping->host); + struct gfs_holder i_gh; + int alloc_required; + int error; + int ret = 0; + + atomic_inc(&ip->i_sbd->sd_ops_vm); + + error = gfs_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); + if (error) + goto out; + + if (gfs_is_jdata(ip)) + goto out_unlock; + + set_bit(GIF_PAGED, &ip->i_flags); + set_bit(GIF_SW_PAGED, &ip->i_flags); + + error = gfs_write_alloc_required(ip, + (u64)vmf->pgoff << PAGE_CACHE_SHIFT, + PAGE_CACHE_SIZE, &alloc_required); + if (error) { + ret = VM_FAULT_OOM; /* XXX: are these right? */ + goto out_unlock; + } + + ret = filemap_fault(vma, vmf); + if (ret & VM_FAULT_ERROR) + goto out_unlock; + + if (alloc_required) { + /* XXX: do we need to drop page lock around alloc_page_backing?*/ + error = alloc_page_backing(ip, vmf->page); + if (error) { + /* + * VM_FAULT_LOCKED should always be the case for + * filemap_fault, but it may not be in a future + * implementation. + */ + if (ret & VM_FAULT_LOCKED) + unlock_page(vmf->page); + page_cache_release(vmf->page); + ret = VM_FAULT_OOM; + goto out_unlock; + } + set_page_dirty(vmf->page); + } + + pfault_be_greedy(ip); + + out_unlock: + gfs_glock_dq_uninit(&i_gh); + out: + return ret; +} + +struct vm_operations_struct gfs_vm_ops_private = { + .fault = gfs_private_fault, +}; + +struct vm_operations_struct gfs_vm_ops_sharewrite = { + .fault = gfs_sharewrite_fault, +}; + --- linux-2.6.27.orig/ubuntu/gfs/lock_dlm_thread.c +++ linux-2.6.27/ubuntu/gfs/lock_dlm_thread.c @@ -0,0 +1,367 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License version 2. + */ + +#include "lock_dlm.h" + +/* A lock placed on this queue is re-submitted to DLM as soon as the lock_dlm + thread gets to it. */ + +static void queue_submit(struct gdlm_lock *lp) +{ + struct gdlm_ls *ls = lp->ls; + + spin_lock(&ls->async_lock); + list_add_tail(&lp->delay_list, &ls->submit); + spin_unlock(&ls->async_lock); + wake_up(&ls->thread_wait); +} + +static void process_blocking(struct gdlm_lock *lp, int bast_mode) +{ + struct gdlm_ls *ls = lp->ls; + unsigned int cb = 0; + + switch (gdlm_make_lmstate(bast_mode)) { + case LM_ST_EXCLUSIVE: + cb = LM_CB_NEED_E; + break; + case LM_ST_DEFERRED: + cb = LM_CB_NEED_D; + break; + case LM_ST_SHARED: + cb = LM_CB_NEED_S; + break; + default: + gdlm_assert(0, "unknown bast mode %u", lp->bast_mode); + } + + ls->fscb(ls->sdp, cb, &lp->lockname); +} + +static void wake_up_ast(struct gdlm_lock *lp) +{ + clear_bit(LFL_AST_WAIT, &lp->flags); + smp_mb__after_clear_bit(); + wake_up_bit(&lp->flags, LFL_AST_WAIT); +} + +static void process_complete(struct gdlm_lock *lp) +{ + struct gdlm_ls *ls = lp->ls; + struct lm_async_cb acb; + s16 prev_mode = lp->cur; + + memset(&acb, 0, sizeof(acb)); + + if (lp->lksb.sb_status == -DLM_ECANCEL) { + log_info("complete dlm cancel %x,%llx flags %lx", + lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number, + lp->flags); + + lp->req = lp->cur; + acb.lc_ret |= LM_OUT_CANCELED; + if (lp->cur == DLM_LOCK_IV) + lp->lksb.sb_lkid = 0; + goto out; + } + + if (test_and_clear_bit(LFL_DLM_UNLOCK, &lp->flags)) { + if (lp->lksb.sb_status != -DLM_EUNLOCK) { + log_info("unlock sb_status %d %x,%llx flags %lx", + lp->lksb.sb_status, lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number, + lp->flags); + return; + } + + lp->cur = DLM_LOCK_IV; + lp->req = DLM_LOCK_IV; + lp->lksb.sb_lkid = 0; + + if (test_and_clear_bit(LFL_UNLOCK_DELETE, &lp->flags)) { + gdlm_delete_lp(lp); + return; + } + goto out; + } + + if (lp->lksb.sb_flags & DLM_SBF_VALNOTVALID) + memset(lp->lksb.sb_lvbptr, 0, GDLM_LVB_SIZE); + + if (lp->lksb.sb_flags & DLM_SBF_ALTMODE) { + if (lp->req == DLM_LOCK_PR) + lp->req = DLM_LOCK_CW; + else if (lp->req == DLM_LOCK_CW) + lp->req = DLM_LOCK_PR; + } + + /* + * A canceled lock request. The lock was just taken off the delayed + * list and was never even submitted to dlm. + */ + + if (test_and_clear_bit(LFL_CANCEL, &lp->flags)) { + log_info("complete internal cancel %x,%llx", + lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number); + lp->req = lp->cur; + acb.lc_ret |= LM_OUT_CANCELED; + goto out; + } + + /* + * An error occured. + */ + + if (lp->lksb.sb_status) { + /* a "normal" error */ + if ((lp->lksb.sb_status == -EAGAIN) && + (lp->lkf & DLM_LKF_NOQUEUE)) { + lp->req = lp->cur; + if (lp->cur == DLM_LOCK_IV) + lp->lksb.sb_lkid = 0; + goto out; + } + + /* this could only happen with cancels I think */ + log_info("ast sb_status %d %x,%llx flags %lx", + lp->lksb.sb_status, lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number, + lp->flags); + return; + } + + /* + * This is an AST for an EX->EX conversion for sync_lvb from GFS. + */ + + if (test_and_clear_bit(LFL_SYNC_LVB, &lp->flags)) { + wake_up_ast(lp); + return; + } + + /* + * A lock has been demoted to NL because it initially completed during + * BLOCK_LOCKS. Now it must be requested in the originally requested + * mode. + */ + + if (test_and_clear_bit(LFL_REREQUEST, &lp->flags)) { + gdlm_assert(lp->req == DLM_LOCK_NL, "%x,%llx", + lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number); + gdlm_assert(lp->prev_req > DLM_LOCK_NL, "%x,%llx", + lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number); + + lp->cur = DLM_LOCK_NL; + lp->req = lp->prev_req; + lp->prev_req = DLM_LOCK_IV; + lp->lkf &= ~DLM_LKF_CONVDEADLK; + + set_bit(LFL_NOCACHE, &lp->flags); + + if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) && + !test_bit(LFL_NOBLOCK, &lp->flags)) + gdlm_queue_delayed(lp); + else + queue_submit(lp); + return; + } + + /* + * A request is granted during dlm recovery. It may be granted + * because the locks of a failed node were cleared. In that case, + * there may be inconsistent data beneath this lock and we must wait + * for recovery to complete to use it. When gfs recovery is done this + * granted lock will be converted to NL and then reacquired in this + * granted state. + */ + + if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) && + !test_bit(LFL_NOBLOCK, &lp->flags) && + lp->req != DLM_LOCK_NL) { + + lp->cur = lp->req; + lp->prev_req = lp->req; + lp->req = DLM_LOCK_NL; + lp->lkf |= DLM_LKF_CONVERT; + lp->lkf &= ~DLM_LKF_CONVDEADLK; + + log_debug("rereq %x,%llx id %x %d,%d", + lp->lockname.ln_type, + (unsigned long long)lp->lockname.ln_number, + lp->lksb.sb_lkid, lp->cur, lp->req); + + set_bit(LFL_REREQUEST, &lp->flags); + queue_submit(lp); + return; + } + + /* + * DLM demoted the lock to NL before it was granted so GFS must be + * told it cannot cache data for this lock. + */ + + if (lp->lksb.sb_flags & DLM_SBF_DEMOTED) + set_bit(LFL_NOCACHE, &lp->flags); + +out: + /* + * This is an internal lock_dlm lock + */ + + if (test_bit(LFL_INLOCK, &lp->flags)) { + clear_bit(LFL_NOBLOCK, &lp->flags); + lp->cur = lp->req; + wake_up_ast(lp); + return; + } + + /* + * Normal completion of a lock request. Tell GFS it now has the lock. + */ + + clear_bit(LFL_NOBLOCK, &lp->flags); + lp->cur = lp->req; + + acb.lc_name = lp->lockname; + acb.lc_ret |= gdlm_make_lmstate(lp->cur); + + if (!test_and_clear_bit(LFL_NOCACHE, &lp->flags) && + (lp->cur > DLM_LOCK_NL) && (prev_mode > DLM_LOCK_NL)) + acb.lc_ret |= LM_OUT_CACHEABLE; + + ls->fscb(ls->sdp, LM_CB_ASYNC, &acb); +} + +static inline int no_work(struct gdlm_ls *ls, int blocking) +{ + int ret; + + spin_lock(&ls->async_lock); + ret = list_empty(&ls->complete) && list_empty(&ls->submit); + if (ret && blocking) + ret = list_empty(&ls->blocking); + spin_unlock(&ls->async_lock); + + return ret; +} + +static inline int check_drop(struct gdlm_ls *ls) +{ + if (!ls->drop_locks_count) + return 0; + + if (time_after(jiffies, ls->drop_time + ls->drop_locks_period * HZ)) { + ls->drop_time = jiffies; + if (ls->all_locks_count >= ls->drop_locks_count) + return 1; + } + return 0; +} + +static int gdlm_thread(void *data, int blist) +{ + struct gdlm_ls *ls = (struct gdlm_ls *) data; + struct gdlm_lock *lp = NULL; + uint8_t complete, blocking, submit, drop; + + /* Only thread1 is allowed to do blocking callbacks since gfs + may wait for a completion callback within a blocking cb. */ + + while (!kthread_should_stop()) { + wait_event_interruptible(ls->thread_wait, + !no_work(ls, blist) || kthread_should_stop()); + + complete = blocking = submit = drop = 0; + + spin_lock(&ls->async_lock); + + if (blist && !list_empty(&ls->blocking)) { + lp = list_entry(ls->blocking.next, struct gdlm_lock, + blist); + list_del_init(&lp->blist); + blocking = lp->bast_mode; + lp->bast_mode = 0; + } else if (!list_empty(&ls->complete)) { + lp = list_entry(ls->complete.next, struct gdlm_lock, + clist); + list_del_init(&lp->clist); + complete = 1; + } else if (!list_empty(&ls->submit)) { + lp = list_entry(ls->submit.next, struct gdlm_lock, + delay_list); + list_del_init(&lp->delay_list); + submit = 1; + } + + drop = check_drop(ls); + spin_unlock(&ls->async_lock); + + if (complete) + process_complete(lp); + + else if (blocking) + process_blocking(lp, blocking); + + else if (submit) + gdlm_do_lock(lp); + + if (drop) + ls->fscb(ls->sdp, LM_CB_DROPLOCKS, NULL); + + schedule(); + } + + return 0; +} + +static int gdlm_thread1(void *data) +{ + return gdlm_thread(data, 1); +} + +static int gdlm_thread2(void *data) +{ + return gdlm_thread(data, 0); +} + +int gdlm_init_threads(struct gdlm_ls *ls) +{ + struct task_struct *p; + int error; + + p = kthread_run(gdlm_thread1, ls, "lock_dlm1"); + error = IS_ERR(p); + if (error) { + log_error("can't start lock_dlm1 thread %d", error); + return error; + } + ls->thread1 = p; + + p = kthread_run(gdlm_thread2, ls, "lock_dlm2"); + error = IS_ERR(p); + if (error) { + log_error("can't start lock_dlm2 thread %d", error); + kthread_stop(ls->thread1); + return error; + } + ls->thread2 = p; + + return 0; +} + +void gdlm_release_threads(struct gdlm_ls *ls) +{ + kthread_stop(ls->thread1); + kthread_stop(ls->thread2); +} + --- linux-2.6.27.orig/ubuntu/gfs/mount.c +++ linux-2.6.27/ubuntu/gfs/mount.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "mount.h" +#include "proc.h" +#include "sys.h" + +/** + * gfs_make_args - Parse mount arguments + * @data: + * @args: + * + * Return: errno + */ + +int +gfs_make_args(char *data_arg, struct gfs_args *args, int remount) +{ + char *data = data_arg; + char *options, *x, *y; + int error = 0; + + /* If someone preloaded options, use those instead */ + + spin_lock(&gfs_proc_margs_lock); + if (!remount && gfs_proc_margs) { + data = gfs_proc_margs; + gfs_proc_margs = NULL; + } + spin_unlock(&gfs_proc_margs_lock); + + /* Set some defaults */ + + memset(args, 0, sizeof(struct gfs_args)); + args->ar_num_glockd = GFS_GLOCKD_DEFAULT; + + if (!remount) { + /* If someone preloaded options, use those instead */ + spin_lock(&gfs_sys_margs_lock); + if (gfs_sys_margs) { + data = gfs_sys_margs; + gfs_sys_margs = NULL; + } + spin_unlock(&gfs_sys_margs_lock); + + /* Set some defaults */ + args->ar_num_glockd = GFS_GLOCKD_DEFAULT; + } + + /* Split the options into tokens with the "," character and + process them */ + + for (options = data; (x = strsep(&options, ",")); ) { + if (!*x) + continue; + + y = strchr(x, '='); + if (y) + *y++ = 0; + + if (!strcmp(x, "lockproto")) { + if (!y) { + printk("GFS: need argument to lockproto\n"); + error = -EINVAL; + break; + } + strncpy(args->ar_lockproto, y, GFS_LOCKNAME_LEN); + args->ar_lockproto[GFS_LOCKNAME_LEN - 1] = 0; + } + + else if (!strcmp(x, "locktable")) { + if (!y) { + printk("GFS: need argument to locktable\n"); + error = -EINVAL; + break; + } + strncpy(args->ar_locktable, y, GFS_LOCKNAME_LEN); + args->ar_locktable[GFS_LOCKNAME_LEN - 1] = 0; + } + + else if (!strcmp(x, "hostdata")) { + if (!y) { + printk("GFS: need argument to hostdata\n"); + error = -EINVAL; + break; + } + strncpy(args->ar_hostdata, y, GFS_LOCKNAME_LEN); + args->ar_hostdata[GFS_LOCKNAME_LEN - 1] = 0; + } + + else if (!strcmp(x, "spectator")) + args->ar_spectator = TRUE; + + else if (!strcmp(x, "ignore_local_fs")) + args->ar_ignore_local_fs = TRUE; + + else if (!strcmp(x, "localflocks")) + args->ar_localflocks = TRUE; + + else if (!strcmp(x, "localcaching")) + args->ar_localcaching = TRUE; + + else if (!strcmp(x, "oopses_ok")) + args->ar_oopses_ok = TRUE; + + else if (!strcmp(x, "debug")) { + args->ar_oopses_ok = TRUE; + args->ar_debug = TRUE; + + } else if (!strcmp(x, "upgrade")) + args->ar_upgrade = TRUE; + + else if (!strcmp(x, "num_glockd")) { + if (!y) { + printk("GFS: need argument to num_glockd\n"); + error = -EINVAL; + break; + } + sscanf(y, "%u", &args->ar_num_glockd); + if (!args->ar_num_glockd || args->ar_num_glockd > GFS_GLOCKD_MAX) { + printk("GFS: 0 < num_glockd <= %u (not %u)\n", + GFS_GLOCKD_MAX, args->ar_num_glockd); + error = -EINVAL; + break; + } + } + + else if (!strcmp(x, "acl")) + args->ar_posix_acls = TRUE; + + else if (!strcmp(x, "noacl")) + args->ar_posix_acls = FALSE; + + else if (!strcmp(x, "suiddir")) + args->ar_suiddir = TRUE; + + else if (!strcmp(x, "noquota")) + args->ar_noquota = TRUE; + + /* Unknown */ + + else { + printk("GFS: unknown option: %s\n", x); + error = -EINVAL; + break; + } + } + + if (error) + printk("GFS: invalid mount option(s)\n"); + + if (data != data_arg) + kfree(data); + + return error; +} + --- linux-2.6.27.orig/ubuntu/gfs/file.c +++ linux-2.6.27/ubuntu/gfs/file.c @@ -0,0 +1,437 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "bmap.h" +#include "dio.h" +#include "file.h" +#include "inode.h" +#include "trans.h" + +/** + * gfs_copy2mem - Trivial copy function for gfs_readi() + * @bh: The buffer to copy from, or NULL meaning zero the buffer + * @buf: The buffer to copy/zero + * @offset: The offset in the buffer to copy from + * @size: The amount of data to copy/zero + * + * Returns: errno + */ + +int +gfs_copy2mem(struct buffer_head *bh, void **buf, unsigned int offset, + unsigned int size) +{ + char **p = (char **)buf; + + if (bh) + memcpy(*p, bh->b_data + offset, size); + else + memset(*p, 0, size); + + *p += size; + + return 0; +} + +/** + * gfs_copy2user - Copy data to user space + * @bh: The buffer + * @buf: The destination of the data + * @offset: The offset into the buffer + * @size: The amount of data to copy + * + * Returns: errno + */ + +int +gfs_copy2user(struct buffer_head *bh, void **buf, + unsigned int offset, unsigned int size) +{ + char **p = (char **)buf; + int error; + + if (bh) + error = copy_to_user(*p, bh->b_data + offset, size); + else + error = clear_user(*p, size); + + if (error) + error = -EFAULT; + else + *p += size; + + return error; +} + +/** + * gfs_readi - Read a file + * @ip: The GFS Inode + * @buf: The buffer to place result into + * @offset: File offset to begin reading from + * @size: Amount of data to transfer + * @copy_fn: Function to actually perform the copy + * + * The @copy_fn only copies a maximum of a single block at once so + * we are safe calling it with int arguments. It is done so that + * we don't needlessly put 64bit arguments on the stack and it + * also makes the code in the @copy_fn nicer too. + * + * Returns: The amount of data actually copied or the error + */ + +int +gfs_readi(struct gfs_inode *ip, void *buf, + uint64_t offset, unsigned int size, + read_copy_fn_t copy_fn) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct buffer_head *bh; + uint64_t lblock, dblock; + unsigned int o; + uint32_t extlen = 0; + unsigned int amount; + int not_new = 0; + int journaled = gfs_is_jdata(ip); + int copied = 0; + int error = 0; + + if (offset >= ip->i_di.di_size) + return 0; + + if ((offset + size) > ip->i_di.di_size) + size = ip->i_di.di_size - offset; + + if (!size) + return 0; + + if (journaled) { + lblock = offset; + o = do_div(lblock, sdp->sd_jbsize); + } else { + lblock = offset >> sdp->sd_sb.sb_bsize_shift; + o = offset & (sdp->sd_sb.sb_bsize - 1); + } + + if (gfs_is_stuffed(ip)) + o += sizeof(struct gfs_dinode); + else if (journaled) + o += sizeof(struct gfs_meta_header); + + while (copied < size) { + amount = size - copied; + if (amount > sdp->sd_sb.sb_bsize - o) + amount = sdp->sd_sb.sb_bsize - o; + + if (!extlen) { + if (!gfs_is_stuffed(ip)) { + error = gfs_block_map(ip, lblock, ¬_new, + &dblock, &extlen); + if (error) + goto fail; + } else if (!lblock) { + dblock = ip->i_num.no_addr; + extlen = 1; + } else + dblock = 0; + } + + if (extlen > 1) + gfs_start_ra(ip->i_gl, dblock, extlen); + + if (dblock) { + error = gfs_get_data_buffer(ip, dblock, not_new, &bh); + if (error) + goto fail; + + dblock++; + extlen--; + } else + bh = NULL; + + error = copy_fn(bh, &buf, o, amount); + if (bh) + brelse(bh); + if (error) + goto fail; + + copied += amount; + lblock++; + + o = (journaled) ? sizeof(struct gfs_meta_header) : 0; + } + + return copied; + + fail: + return (copied) ? copied : error; +} + +/** + * gfs_copy_from_mem - Trivial copy function for gfs_writei() + * @ip: The file to write to + * @bh: The buffer to copy to or clear + * @buf: The buffer to copy from + * @offset: The offset in the buffer to write to + * @size: The amount of data to write + * @new: Flag indicating that remaining space in the buffer should be zeroed + * + * Returns: errno + */ + +int +gfs_copy_from_mem(struct gfs_inode *ip, struct buffer_head *bh, void **buf, + unsigned int offset, unsigned int size, int new) +{ + char **p = (char **)buf; + int error = 0; + + /* The dinode block always gets journaled */ + if (bh->b_blocknr == ip->i_num.no_addr) { + if (gfs_assert_warn(ip->i_sbd, !new)) + return -EIO; + gfs_trans_add_bh(ip->i_gl, bh); + memcpy(bh->b_data + offset, *p, size); + + /* Data blocks for journaled files get written added to the journal */ + } else if (gfs_is_jdata(ip)) { + gfs_trans_add_bh(ip->i_gl, bh); + memcpy(bh->b_data + offset, *p, size); + if (new) + gfs_buffer_clear_ends(bh, offset, size, TRUE); + + /* Non-journaled data blocks get written to in-place disk blocks */ + } else { + memcpy(bh->b_data + offset, *p, size); + if (new) + gfs_buffer_clear_ends(bh, offset, size, FALSE); + error = gfs_dwrite(ip->i_sbd, bh, DIO_DIRTY); + } + + if (!error) + *p += size; + + return error; +} + +/** + * gfs_copy_from_user - Copy bytes from user space for gfs_writei() + * @ip: The file to write to + * @bh: The buffer to copy to or clear + * @buf: The buffer to copy from + * @offset: The offset in the buffer to write to + * @size: The amount of data to write + * @new: Flag indicating that remaining space in the buffer should be zeroed + * + * Returns: errno + */ + +int +gfs_copy_from_user(struct gfs_inode *ip, struct buffer_head *bh, void **buf, + unsigned int offset, unsigned int size, int new) +{ + char **p = (char **)buf; + int error = 0; + + /* the dinode block always gets journaled */ + if (bh->b_blocknr == ip->i_num.no_addr) { + if (gfs_assert_warn(ip->i_sbd, !new)) + return -EIO; + gfs_trans_add_bh(ip->i_gl, bh); + if (copy_from_user(bh->b_data + offset, *p, size)) + error = -EFAULT; + + /* Data blocks for journaled files get written added to the journal */ + } else if (gfs_is_jdata(ip)) { + gfs_trans_add_bh(ip->i_gl, bh); + if (copy_from_user(bh->b_data + offset, *p, size)) + error = -EFAULT; + if (new) { + gfs_buffer_clear_ends(bh, offset, size, TRUE); + if (error) + memset(bh->b_data + offset, 0, size); + } + + /* non-journaled data blocks get written to in-place disk blocks */ + } else { + if (copy_from_user(bh->b_data + offset, *p, size)) + error = -EFAULT; + if (error) { + if (new) + gfs_buffer_clear(bh); + gfs_dwrite(ip->i_sbd, bh, DIO_DIRTY); + } else { + if (new) + gfs_buffer_clear_ends(bh, offset, size, FALSE); + error = gfs_dwrite(ip->i_sbd, bh, DIO_DIRTY); + } + } + + if (!error) + *p += size; + + return error; +} + +/** + * gfs_writei - Write bytes to a file + * @ip: The GFS inode + * @buf: The buffer containing information to be written + * @offset: The file offset to start writing at + * @size: The amount of data to write + * @copy_fn: Function to do the actual copying + * + * Returns: The number of bytes correctly written or error code + */ + +int +gfs_writei(struct gfs_inode *ip, void *buf, + uint64_t offset, unsigned int size, + write_copy_fn_t copy_fn, + struct kiocb *iocb) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct buffer_head *dibh, *bh; + uint64_t lblock, dblock; + unsigned int o; + uint32_t extlen = 0; + unsigned int amount; + int new; + int journaled = gfs_is_jdata(ip); + const uint64_t start = offset; + int copied = 0; + int error = 0; + + if (!size) + return 0; + + if (gfs_is_stuffed(ip) && + ((start + size) > (sdp->sd_sb.sb_bsize - sizeof(struct gfs_dinode)))) { + error = gfs_unstuff_dinode(ip, gfs_unstuffer_async, NULL); + if (error) + return error; + } + + if (journaled) { + lblock = offset; + o = do_div(lblock, sdp->sd_jbsize); + } else { + lblock = offset >> sdp->sd_sb.sb_bsize_shift; + o = offset & (sdp->sd_sb.sb_bsize - 1); + } + + if (gfs_is_stuffed(ip)) + o += sizeof(struct gfs_dinode); + else if (journaled) + o += sizeof(struct gfs_meta_header); + + while (copied < size) { + amount = size - copied; + if (amount > sdp->sd_sb.sb_bsize - o) + amount = sdp->sd_sb.sb_bsize - o; + + if (!extlen) { + if (!gfs_is_stuffed(ip)) { + new = TRUE; + error = gfs_block_map(ip, lblock, &new, &dblock, &extlen); + if (error) + goto fail; + } else { + new = FALSE; + dblock = ip->i_num.no_addr; + extlen = 1; + } + } + + if (journaled && extlen > 1) + gfs_start_ra(ip->i_gl, dblock, extlen); + + error = gfs_get_data_buffer(ip, dblock, + (amount == sdp->sd_sb.sb_bsize) ? TRUE : new, + &bh); + if (error) + goto fail; + + error = copy_fn(ip, bh, &buf, o, amount, new); + brelse(bh); + if (error) + goto fail; + + copied += amount; + lblock++; + dblock++; + extlen--; + + o = (journaled) ? sizeof(struct gfs_meta_header) : 0; + } + + out: + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + return error; + + if (ip->i_di.di_size < start + copied) + ip->i_di.di_size = start + copied; + ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + + return copied; + + fail: + if (copied) + goto out; + return error; +} + +/* + * gfs_zero_blocks - zero out disk blocks via gfs_writei() + * @ip: The file to write to + * @bh: The buffer to clear + * @buf: The pseudo buffer (not used but added to keep interface unchanged) + * @offset: The offset in the buffer to write to + * @size: The size to zero out + * @new: Flag indicating that remaining space in the buffer should be zeroed + * + * Returns: 0 on success, -EXXX on failure + */ + +int +gfs_zero_blocks(struct gfs_inode *ip, struct buffer_head *bh, void **buf, + unsigned int offset, unsigned int size, int new) +{ + int error = 0; + + /* The dinode block always gets journaled */ + if (bh->b_blocknr == ip->i_num.no_addr) { + if (gfs_assert_warn(ip->i_sbd, !new)) + return -EIO; + gfs_trans_add_bh(ip->i_gl, bh); + memset((bh)->b_data + offset, 0, size); + + /* Data blocks for journaled files get written added to the journal */ + } else if (gfs_is_jdata(ip)) { + gfs_trans_add_bh(ip->i_gl, bh); + memset((bh)->b_data + offset, 0, size); + if (new) + gfs_buffer_clear_ends(bh, offset, size, TRUE); + + /* Non-journaled data blocks get written to in-place disk blocks */ + } else { + memset((bh)->b_data + offset, 0, size); + if (new) + gfs_buffer_clear_ends(bh, offset, size, FALSE); + error = gfs_dwrite(ip->i_sbd, bh, DIO_DIRTY); + } + + return error; +} + --- linux-2.6.27.orig/ubuntu/gfs/ops_address.c +++ linux-2.6.27/ubuntu/gfs/ops_address.c @@ -0,0 +1,504 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "bmap.h" +#include "dio.h" +#include "file.h" +#include "glock.h" +#include "inode.h" +#include "ops_address.h" +#include "page.h" +#include "quota.h" +#include "trans.h" + +static int gfs_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to); +/** + * get_block - Fills in a buffer head with details about a block + * @inode: The inode + * @lblock: The block number to look up + * @bh_result: The buffer head to return the result in + * @create: Non-zero if we may add block to the file + * + * Returns: errno + */ + +static int +get_block(struct inode *inode, sector_t lblock, + struct buffer_head *bh_result, int create) +{ + struct gfs_inode *ip = get_v2ip(inode); + int new = create; + uint64_t dblock; + int error; + + error = gfs_block_map(ip, lblock, &new, &dblock, NULL); + if (error) + return error; + + if (!dblock) + return 0; + + map_bh(bh_result, inode->i_sb, dblock); + if (new) + set_buffer_new(bh_result); + + return 0; +} + +/** + * get_block_noalloc - Fills in a buffer head with details about a block + * @inode: The inode + * @lblock: The block number to look up + * @bh_result: The buffer head to return the result in + * @create: Non-zero if we may add block to the file + * + * Returns: errno + */ + +static int +get_block_noalloc(struct inode *inode, sector_t lblock, + struct buffer_head *bh_result, int create) +{ + int error; + + error = get_block(inode, lblock, bh_result, FALSE); + if (error) + return error; + + if (gfs_assert_withdraw(get_v2sdp(inode->i_sb), + !create || buffer_mapped(bh_result))) + return -EIO; + + return 0; +} + +/** + * get_blocks - + * @inode: + * @lblock: + * @max_blocks: + * @bh_result: + * @create: + * + * Returns: errno + */ + +static int +get_blocks(struct inode *inode, sector_t lblock, + struct buffer_head *bh_result, int create) +{ + struct gfs_inode *ip = get_v2ip(inode); + int new = create; + uint64_t dblock; + int error; + + error = gfs_block_map(ip, lblock, &new, &dblock, NULL); + if (error) + return error; + + if (!dblock) + return 0; + + map_bh(bh_result, inode->i_sb, dblock); + if (new) + set_buffer_new(bh_result); + + return 0; +} + +/** + * get_blocks_noalloc - + * @inode: + * @lblock: + * @max_blocks: + * @bh_result: + * @create: + * + * Returns: errno + */ + +static int +get_blocks_noalloc(struct inode *inode, sector_t lblock, + struct buffer_head *bh_result, int create) +{ + int error; + + error = get_blocks(inode, lblock, bh_result, FALSE); + if (error) + return error; + + if (gfs_assert_withdraw(get_v2sdp(inode->i_sb), + !create || buffer_mapped(bh_result))) + return -EIO; + + return 0; +} + +/** + * gfs_writepage - Write complete page + * @page: Page to write + * + * Returns: errno + * + * Use Linux VFS block_write_full_page() to write one page, + * using GFS's get_block_noalloc to find which blocks to write. + */ + +static int +gfs_writepage(struct page *page, struct writeback_control *wbc) +{ + struct gfs_inode *ip = get_v2ip(page->mapping->host); + struct gfs_sbd *sdp = ip->i_sbd; + int error; + + atomic_inc(&sdp->sd_ops_address); + + if (gfs_assert_withdraw(sdp, gfs_glock_is_held_excl(ip->i_gl))) { + unlock_page(page); + return -EIO; + } + if (get_transaction) { + redirty_page_for_writepage(wbc, page); + unlock_page(page); + return 0; + } + + error = block_write_full_page(page, get_block_noalloc, wbc); + + gfs_flush_meta_cache(ip); + + return error; +} + +/** + * stuffed_readpage - Fill in a Linux page with stuffed file data + * @ip: the inode + * @page: the page + * + * Returns: errno + */ + +static int +stuffed_readpage(struct gfs_inode *ip, struct page *page) +{ + struct buffer_head *dibh; + void *kaddr; + int error; + + error = gfs_get_inode_buffer(ip, &dibh); + if (!error) { + kaddr = kmap(page); + memcpy((char *)kaddr, + dibh->b_data + sizeof(struct gfs_dinode), + ip->i_di.di_size); + memset((char *)kaddr + ip->i_di.di_size, + 0, + PAGE_CACHE_SIZE - ip->i_di.di_size); + kunmap(page); + + brelse(dibh); + + SetPageUptodate(page); + } + + return error; +} + +/** + * readi_readpage - readpage that goes through gfs_internal_read() + * @page: The page to read + * + * Returns: errno + */ + +static int +readi_readpage(struct page *page) +{ + struct gfs_inode *ip = get_v2ip(page->mapping->host); + void *kaddr; + int ret; + + kaddr = kmap(page); + + ret = gfs_internal_read(ip, kaddr, + (uint64_t)page->index << PAGE_CACHE_SHIFT, + PAGE_CACHE_SIZE); + if (ret >= 0) { + if (ret < PAGE_CACHE_SIZE) + memset(kaddr + ret, 0, PAGE_CACHE_SIZE - ret); + SetPageUptodate(page); + ret = 0; + } + + kunmap(page); + + unlock_page(page); + + return ret; +} + +/** + * gfs_readpage - readpage with locking + * @file: The file to read a page for + * @page: The page to read + * + * Returns: errno + */ + +static int +gfs_readpage(struct file *file, struct page *page) +{ + struct gfs_inode *ip = get_v2ip(page->mapping->host); + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_holder *gh; + int error; + + atomic_inc(&sdp->sd_ops_address); + + /* When gfs_readpage is called from the sys_madvise code through the + * readahead code, the inode glock is not held. In this case, we hold + * the inode glock, unlock the page and return AOP_TRUNCATED_PAGE. The + * caller will then reload the page and call gfs_readpage again. We + * also add the flag GL_READPAGE to denote that the glock was held in + * this function and if so, we unlock it before leaving this function + */ + gh = gfs_glock_is_locked_by_me(ip->i_gl); + if (!gh) { + gh = kmalloc(sizeof(struct gfs_holder), GFP_NOFS); + if (!gh) + return -ENOBUFS; + gfs_holder_init(ip->i_gl, LM_ST_SHARED, + GL_READPAGE | LM_FLAG_ANY, gh); + unlock_page(page); + error = gfs_glock_nq(gh); + if (error) { + gfs_holder_uninit(gh); + kfree(gh); + goto out; + } + return AOP_TRUNCATED_PAGE; + } + + if (!gfs_is_jdata(ip)) { + if (gfs_is_stuffed(ip) && !page->index) { + error = stuffed_readpage(ip, page); + unlock_page(page); + } else + error = block_read_full_page(page, get_block); + } else + error = readi_readpage(page); + + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + error = -EIO; + + if (gh->gh_flags & GL_READPAGE) { /* If we grabbed the glock here */ + gfs_glock_dq_uninit(gh); + kfree(gh); + } +out: + return error; +} + +/** + * gfs_prepare_write - Prepare to write a page to a file + * @file: The file to write to + * @page: The page which is to be prepared for writing + * @from: From (byte range within page) + * @to: To (byte range within page) + * + * Returns: errno + * + * Make sure file's inode is glocked; we shouldn't write without that! + * If GFS dinode is currently stuffed (small enough that all data fits within + * the dinode block), and new file size is too large, unstuff it. + * Use Linux VFS block_prepare_write() to write blocks, using GFS' get_block() + * to find which blocks to write. + */ + +static int +gfs_prepare_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + struct gfs_inode *ip = get_v2ip(page->mapping->host); + struct gfs_sbd *sdp = ip->i_sbd; + int error = 0; + + atomic_inc(&sdp->sd_ops_address); + + /* We can't set commit_write in the structure in the declare */ + /* because if we do, loopback (loop.c) will interpret that to mean */ + /* it's okay to do buffered writes without locking through sendfile. */ + /* This is a kludge to get around the problem with loop.c because */ + /* the upstream community rejected my changes to loop.c. */ + ip->gfs_file_aops.commit_write = gfs_commit_write; + + if (gfs_assert_warn(sdp, gfs_glock_is_locked_by_me(ip->i_gl))) + return -ENOSYS; + + if (gfs_is_stuffed(ip)) { + uint64_t file_size = ((uint64_t)page->index << PAGE_CACHE_SHIFT) + to; + + if (file_size > sdp->sd_sb.sb_bsize - sizeof(struct gfs_dinode)) { + error = gfs_unstuff_dinode(ip, gfs_unstuffer_page, page); + if (!error) + error = block_prepare_write(page, from, to, get_block); + } else if (!PageUptodate(page)) + error = stuffed_readpage(ip, page); + } else + error = block_prepare_write(page, from, to, get_block); + + return error; +} + +/** + * gfs_commit_write - Commit write to a file + * @file: The file to write to + * @page: The page containing the data + * @from: From (byte range within page) + * @to: To (byte range within page) + * + * Returns: errno + */ + +static int +gfs_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + struct inode *inode = page->mapping->host; + struct gfs_inode *ip = get_v2ip(inode); + struct gfs_sbd *sdp = ip->i_sbd; + int error; + + atomic_inc(&sdp->sd_ops_address); + + if (gfs_is_stuffed(ip)) { + struct buffer_head *dibh; + uint64_t file_size = ((uint64_t)page->index << PAGE_CACHE_SHIFT) + to; + void *kaddr; + + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + goto fail; + + gfs_trans_add_bh(ip->i_gl, dibh); + + kaddr = kmap(page); + memcpy(dibh->b_data + sizeof(struct gfs_dinode) + from, + (char *)kaddr + from, + to - from); + kunmap(page); + + brelse(dibh); + + SetPageUptodate(page); + + if (inode->i_size < file_size) + i_size_write(inode, file_size); + } else { + loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + error = block_commit_write(page, from, to); + if (error) + goto fail; + if (pos > inode->i_size) { + i_size_write(inode, pos); + mark_inode_dirty(inode); + } + } + + ip->gfs_file_aops.commit_write = NULL; + return 0; + + fail: + ClearPageUptodate(page); + + return error; +} + +/** + * gfs_bmap - Block map function + * @mapping: Address space info + * @lblock: The block to map + * + * Returns: The disk address for the block or 0 on hole or error + */ + +static sector_t +gfs_bmap(struct address_space *mapping, sector_t lblock) +{ + struct gfs_inode *ip = get_v2ip(mapping->host); + struct gfs_holder i_gh; + int dblock = 0; + int error; + + atomic_inc(&ip->i_sbd->sd_ops_address); + + error = gfs_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); + if (error) + return 0; + + if (!gfs_is_stuffed(ip)) + dblock = generic_block_bmap(mapping, lblock, get_block); + + gfs_glock_dq_uninit(&i_gh); + + return dblock; +} + +/** + * gfs_direct_IO - + * @rw: + * @iocb: + * @iov: + * @offset: + * @nr_segs: + * + * Returns: errno + */ + +static ssize_t +gfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, + loff_t offset, unsigned long nr_segs) +{ + struct file *file = iocb->ki_filp; + struct inode *inode = file->f_mapping->host; + struct gfs_inode *ip = get_v2ip(inode); + struct gfs_sbd *sdp = ip->i_sbd; + get_block_t *gb = get_blocks; + + atomic_inc(&sdp->sd_ops_address); + + if (gfs_assert_warn(sdp, gfs_glock_is_locked_by_me(ip->i_gl)) || + gfs_assert_warn(sdp, !gfs_is_stuffed(ip))) + return -EINVAL; + + if (rw == WRITE && !get_transaction) + gb = get_blocks_noalloc; + + if (rw == WRITE) + return blockdev_direct_IO(rw, iocb, inode, + inode->i_sb->s_bdev, iov, + offset, nr_segs, gb, NULL); + else + return blockdev_direct_IO_no_locking(rw, iocb, inode, + inode->i_sb->s_bdev, iov, + offset, nr_segs, gb, NULL); + +} + +struct address_space_operations gfs_file_aops = { + .writepage = gfs_writepage, + .readpage = gfs_readpage, + .sync_page = block_sync_page, + .prepare_write = gfs_prepare_write, + .bmap = gfs_bmap, + .direct_IO = gfs_direct_IO, +}; --- linux-2.6.27.orig/ubuntu/gfs/incore.h +++ linux-2.6.27/ubuntu/gfs/incore.h @@ -0,0 +1,1207 @@ +/* + * In-core (memory/RAM) structures. + * These do not appear on-disk. See gfs_ondisk.h for on-disk structures. + */ + +#ifndef __INCORE_DOT_H__ +#define __INCORE_DOT_H__ + +/* flags used in function call parameters */ + +#define DIO_NEW (0x00000001) /* Newly allocated metadata */ +#define DIO_FORCE (0x00000002) /* Force read of block from disk */ +#define DIO_CLEAN (0x00000004) /* Don't write to disk */ +#define DIO_DIRTY (0x00000008) /* Data changed, must write to disk */ +#define DIO_START (0x00000010) /* Start disk read or write */ +#define DIO_WAIT (0x00000020) /* Wait for disk r/w to complete */ + +#define DIO_METADATA (0x00000040) /* Process glock's protected metadata */ +#define DIO_DATA (0x00000080) /* Process glock's protected filedata */ +#define DIO_INVISIBLE (0x00000100) /* Don't monkey with glock's dirty bit */ +#define DIO_CHECK (0x00000200) /* Make sure all metadata has been synced */ +#define DIO_ALL (0x00000400) /* Flush all AIL transactions to disk */ + +/* Structure prototypes */ + +struct gfs_log_operations; +struct gfs_log_element; +struct gfs_meta_header_cache; +struct gfs_depend; +struct gfs_bitmap; +struct gfs_rgrpd; +struct gfs_bufdata; +struct gfs_glock_operations; +struct gfs_holder; +struct gfs_glock; +struct gfs_alloc; +struct gfs_inode; +struct gfs_file; +struct gfs_unlinked; +struct gfs_quota_le; +struct gfs_quota_data; +struct gfs_log_buf; +struct gfs_trans; +struct gfs_gl_hash_bucket; +struct gfs_sbd; + +typedef void (*gfs_glop_bh_t) (struct gfs_glock * gl, unsigned int ret); + +/* + * Structure of operations that are associated with each + * type of element in the log. + */ +struct gfs_log_operations { + /* + * Operations specific to a given log element (LE). + * These are typically executed individually via macros such as LO_ADD. + */ + + /* Add new LE to transaction */ + void (*lo_add) (struct gfs_sbd * sdp, struct gfs_log_element * le); + + /* Do any cleanup, etc., needed just before commit to incore log */ + void (*lo_trans_end) (struct gfs_sbd * sdp, + struct gfs_log_element * le); + + /* Print LE-specific info via printk() */ + void (*lo_print) (struct gfs_sbd * sdp, struct gfs_log_element * le, + unsigned int where); + + /* Find any incore transactions that overlap through this LE (e.g. + * share glocks), to determine if any transactions can be combined. */ + struct gfs_trans *(*lo_overlap_trans) (struct gfs_sbd * sdp, + struct gfs_log_element * le); + + /* Change LE from "new" to "incore" status, before write to log */ + void (*lo_incore_commit) (struct gfs_sbd * sdp, struct gfs_trans * tr, + struct gfs_log_element * le); + + /* Allow writes to in-place locations, after log is on-disk */ + void (*lo_add_to_ail) (struct gfs_sbd * sdp, + struct gfs_log_element * le); + + /* Clean up LE after log dump */ + void (*lo_clean_dump) (struct gfs_sbd * sdp, + struct gfs_log_element * le); + + /* + * Operations specific to a class of log elements. + * These are typically executed over a whole transaction by + * macros such as LO_TRANS_SIZE. Each LE-type-specific operation + * for each LE contributes its part to the overall result. + */ + + /* Determine LE-type-specific quantities of blocks of various types + * required for writing the log */ + void (*lo_trans_size) (struct gfs_sbd * sdp, struct gfs_trans * tr, + unsigned int *mblks, unsigned int *eblks, + unsigned int *blocks, unsigned int *bmem); + + /* Combine LE-type-specific values in new_tr and tr, result is in tr */ + void (*lo_trans_combine) (struct gfs_sbd * sdp, struct gfs_trans * tr, + struct gfs_trans * new_tr); + + /* Create control and metadata buffers that will make up the log */ + void (*lo_build_bhlist) (struct gfs_sbd * sdp, struct gfs_trans * tr); + + /* Calculate log space needed for this LE in a log dump */ + void (*lo_dump_size) (struct gfs_sbd * sdp, unsigned int *elements, + unsigned int *blocks, unsigned int *bmem); + + /* Add LE to log dump */ + void (*lo_build_dump) (struct gfs_sbd * sdp, struct gfs_trans * tr); + + /* + * Operations that happen at recovery time + */ + + /* Reset/init whatever before doing recovery */ + void (*lo_before_scan) (struct gfs_sbd * sdp, unsigned int jid, + struct gfs_log_header * head, + unsigned int pass); + + /* LE-specific recovery procedure */ + int (*lo_scan_elements) (struct gfs_sbd * sdp, + struct gfs_jindex * jdesc, + struct gfs_glock * gl, uint64_t start, + struct gfs_log_descriptor * desc, + unsigned int pass); + + /* Verify and report recovery results/statistics */ + void (*lo_after_scan) (struct gfs_sbd * sdp, unsigned int jid, + unsigned int pass); + + + /* + * Type of element (glock/buf/unlinked/quota) + */ + char *lo_name; +}; + +/* + * Structure that gets added to struct gfs_trans->tr_elements. They + * make up the "stuff" in each transaction. + */ +struct gfs_log_element { + struct gfs_log_operations *le_ops; /* Vector of functions */ + + struct gfs_trans *le_trans; /* We're part of this transaction */ + struct list_head le_list; /* Link to transaction's element list */ +}; + +/* + * Meta-header cache structure. + * One for each metadata block that we've de-allocated. + * Used to temporarily store gfs_meta_header structs for meta blocks that + * have been freshly turned into FREEMETA (alloc'd or de-alloc'd). Storing + * these (small) structures in-core allows us to release the (large) buffers, + * and not need to re-read the header from disk if/when we re-allocate the + * blocks to USEDMETA, as long as this node holds the EXCLUSIVE lock for the + * resource group containing the blocks. If we release the EX lock, we must + * throw away the rgrp's cached meta headers, since another node could change + * the blocks' contents. + * In-core superblock structure hosts the hashed cache, as well as a + * linear list of all cached, in most-recently-added order. + * Also, each resource group keeps a list of cached blocks within its scope. + */ +struct gfs_meta_header_cache { + /* Links to various lists */ + struct list_head mc_list_hash; /* Superblock's hashed list */ + struct list_head mc_list_single; /* Superblock's list, MRU order */ + struct list_head mc_list_rgd; /* Resource group's list */ + + uint64_t mc_block; /* Block # (in-place address) */ + struct gfs_meta_header mc_mh; /* Payload: the block's meta-header */ +}; + +/* + * Dependency cache structure. + * In-core superblock structure hosts the actual cache. + * Also, each resource group keeps a list of dependency blocks within its scope. + */ +struct gfs_depend { + /* Links to various lists */ + struct list_head gd_list_hash; /* Superblock's hashed list */ + struct list_head gd_list_rgd; /* Resource group's list */ + + struct gfs_rgrpd *gd_rgd; /* Resource group descriptor */ + uint64_t gd_formal_ino; /* Inode ID */ + unsigned long gd_time; /* Time (jiffies) when put on list */ +}; + +/* + * Block allocation bitmap descriptor structure. + * One of these for each FS block that contains bitmap data + * (i.e. the resource group header blocks and their following bitmap blocks). + * Each allocatable FS data block is represented by 2 bits (4 alloc states). + */ +struct gfs_bitmap { + uint32_t bi_offset; /* Byte offset of bitmap within this bit block + (non-zero only for an rgrp header block) */ + uint32_t bi_start; /* Data block (rgrp scope, 32-bit) represented + by the first bit-pair in this bit block */ + uint32_t bi_len; /* The number of bitmap bytes in this bit block */ +}; + +/* + * Resource Group (Rgrp) descriptor structure. + * There is one of these for each resource (block) group in the FS. + * The filesystem is divided into a number of resource groups to allow + * simultaneous block alloc operations by a number of nodes. + */ +struct gfs_rgrpd { + /* Links to superblock lists */ + struct list_head rd_list; /* On-disk-order list of all rgrps */ + struct list_head rd_list_mru; /* Most Recently Used list of all rgs */ + struct list_head rd_recent; /* recently used rgrps */ + uint32_t rd_try_counter; /* # of times we fail a try lock */ + + struct gfs_glock *rd_gl; /* Glock for this rgrp */ + + struct gfs_rindex rd_ri; /* Resource Index (on-disk) structure */ + struct gfs_rgrp rd_rg; /* Resource Group (on-disk) structure */ + uint64_t rd_rg_vn; /* Version #: if != glock's gl_vn, + we need to read rgrp fm disk */ + + /* Block alloc bitmap cache */ + struct gfs_bitmap *rd_bits; /* Array of block bitmap descriptors */ + struct buffer_head **rd_bh; /* Array of ptrs to block bitmap bh's */ + + /* Block allocation strategy, rgrp scope. Start at these blocks when + searching for next data/meta block to alloc */ + uint32_t rd_last_alloc_data; /* Most recent data block allocated */ + uint32_t rd_last_alloc_meta; /* Most recent meta block allocated */ + + struct list_head rd_mhc; /* Cached meta-headers for this rgrp */ + struct list_head rd_depend; /* Dependent inodes (MRU order) */ + + struct gfs_sbd *rd_sbd; /* FS incore superblock (fs instance) */ +}; + +/* + * Per-buffer data + * One of these is attached as GFS private data to each FS block's buffer_head. + * These keep track of a buffer's progress through the transaction pipeline, + * using the "new" embedded log element to attach it to a being-built + * transaction, and moving the attachment point to the "incore" LE once + * the transaction completes (at which time the buffer becomes a candidate + * to be written to the on-disk log). + * A buffer may be attached simultaneously to a new and an incore transaction, + * but no more than one of each: Only one new trans may be built at a time + * for a given buffer, obviously, since the buffer's contents are protected + * by an EXclusive glock when writing. And, when a transaction is completely + * built, GFS combines incore transactions that share glocks (see + * incore_commit()), i.e. the glock that protects the buffer, so a buffer + * never needs to be attached to more than one (combined) incore trans. + * Note that multiple transactions can modify the buffer since its most + * recent writes to disk. This principle applies to both in-place and + * journal block locations on-disk, allowing this node to keep modifying the + * cached data without writing it to disk, unless/until another node needs + * to access the data, or the Linux OS tells us to sync to disk. + * If a transaction follows another transaction before the first transaction's + * log completes (indicated by the in-place buffer head still being pinned + * in RAM), GFS copies the first transaction's results to a "frozen" + * image of the buffer, so the first transaction results (an atomic + * snapshot) can be logged properly, while the second transaction is + * modifying the "real" buffer. This frozen copy lives only until the new + * transaction is complete, at which point one of two things has occurred: + * 1). Buffer was logged successfully; frozen copy's job is done. + * 2). Buffer was not yet logged; frozen copy no longer needed, newer + * buffer becomes the log candidate. + * + * gfs_bufdata structs also link into the Active Items Lists (AIL) (buffers + * flushed to on-disk log, but not yet flushed to on-disk in-place locations) + * attached to: + * 1). The latest transaction to modify and log (on-disk) the buffer, and + * 2). The glock that protects the buffer's contents. + * The buffer is attached to only the most recent transaction's AIL + * list for a couple of reasons. One is that only the most up-to-date + * buffer content needs to be written to the in-place block on-disk. The + * other is that since there is a more recent copy of the block in + * the log, we don't need to keep the older copies in the log. We can + * remove them from the AIL and let the log space be reused for new + * transactions (GFS advances the log tail when removing buffers from AIL). + */ +struct gfs_bufdata { + struct buffer_head *bd_bh; /* We belong to this Linux buffer_head */ + struct gfs_glock *bd_gl; /* This glock protects buffer's payload */ + + /* Log elements map us to a particular set of log operations functions, + and to a particular transaction */ + struct gfs_log_element bd_new_le; /* New, incomplete transaction */ + struct gfs_log_element bd_incore_le; /* Complete (committed) trans */ + + char *bd_frozen; /* "Frozen" copy of buffer's data */ + struct semaphore bd_lock; /* Protects access to this structure */ + + /* "Pin" means keep buffer in RAM, don't write to disk (yet) */ + unsigned int bd_pinned; /* Recursive pin count */ + + /* Links to Active Items Lists */ + struct list_head bd_ail_tr_list; /* This buf's most recent trans' AIL */ + struct list_head bd_ail_gl_list; /* This buf's glock's AIL */ +}; + +/* + * Glock operations + * One set of operations for each glock, the set selected by type of glock. + * These functions get called at various points in a glock's lifetime. + * "xmote" = promote or demote (change lock state) a glock at inter-node scope. + * "th" = top half, "bh" = bottom half + * Some operations/fields are required (GFS assumes they are there): + * go_xmote_th + * go_drop_th + * go_type + * Other operations are optional (GFS checks for presence before calling). + */ +struct gfs_glock_operations { + + /* Acquire lock or change lock state at inter-node scope: + Does type-specific preparation (if any) + Uses gfs_glock_xmote_th to call lock module. */ + void (*go_xmote_th) (struct gfs_glock * gl, unsigned int state, + int flags); + + /* After acquiring or changing a lock at inter-node scope */ + void (*go_xmote_bh) (struct gfs_glock * gl); + + /* Release (unlock) a lock at inter-node scope: + Does type-specific preparation (if any) + Uses gfs_glock_drop_th to call lock module. */ + void (*go_drop_th) (struct gfs_glock * gl); + + /* After releasing a lock at inter-node scope */ + void (*go_drop_bh) (struct gfs_glock * gl); + + /* Sync dirty data to disk (e.g. before demoting an EX inter-node lock) + (another node needs to read the updated data from disk) */ + void (*go_sync) (struct gfs_glock * gl, int flags); + + /* Invalidate local cached data just after releasing an inter-node lock + (another node may change the on-disk data, so it's no good to us) */ + void (*go_inval) (struct gfs_glock * gl, int flags); + + /* Lock-type-specific check to see if it's okay to unlock a glock + at inter-node scope (and remove it from our glock cache) */ + int (*go_demote_ok) (struct gfs_glock * gl); + + /* After getting lock for first holder (within this node) */ + int (*go_lock) (struct gfs_glock * gl, int flags); + + /* After last holder (within this node) gives up lock (glock may + remain in glock cache, though) */ + void (*go_unlock) (struct gfs_glock * gl, int flags); + + /* After receiving a callback: another node needs the lock */ + void (*go_callback) (struct gfs_glock * gl, unsigned int state); + + /* Called when the glock layer marks a lock as being not greedy + anymore */ + void (*go_greedy) (struct gfs_glock * gl); + + /* Lock type: locks with same lock # (often an FS block #), + but different types, are different locks */ + int go_type; +}; + +/* + * Glock holder structure + * One for each holder of a glock. + * These coordinate the use, within this node, of an acquired inter-node glock. + * Once a node has acquired a glock, it may be shared within that node by + * several processes, or even by several recursive requests from the same + * process. Each is a separate "holder". Different holders may co-exist + * having requested different lock states, as long as the node holds the + * glock in a state that is compatible. A hold requestor may select, via + * flags, the rules by which sharing within the node is granted: + * LM_FLAG_ANY: Grant if glock state is any other than UNLOCKED. + * GL_EXACT: Grant only if glock state is exactly the requested state. + * GL_LOCAL_EXCL: Grant only one holder at a time within this node. + * With no flags, a hold will be granted to a SHARED request even if the + * node holds the glock in EXCLUSIVE mode. See relaxed_state_ok(). + * When a process needs to manipulate a lock, it requests it via one of + * these holder structures. If the request cannot be satisfied immediately, + * the holder structure gets queued on one of these lists in gfs_glock: + * 1) waiters1, for gaining exclusive access to the (local) glock structure. + * 2) waiters2, for demoting a lock (unlocking a glock, or changing its state + * to be less restrictive) or relenquishing "greedy" status. + * 3) waiters3, for promoting (locking a new glock, or changing a glock state + * to be more restrictive). + * When holding a lock, gfs_holder struct stays on glock's holder list. + * See gfs-kernel/src/harness/lm_interface.h for gh_state (LM_ST_...) + * and gh_flags (LM_FLAG...) fields. + * Also see glock.h for gh_flags field (GL_...) flags. + */ + +/* Action requests */ +#define HIF_MUTEX (0) /* Exclusive (local) access to glock struct */ +#define HIF_PROMOTE (1) /* Change lock to more restrictive state */ +#define HIF_DEMOTE (2) /* Change lock to less restrictive state */ +#define HIF_GREEDY (3) /* Wait for the glock to be unlocked */ + +/* States */ +#define HIF_ALLOCED (4) /* Holder structure is or was in use */ +#define HIF_DEALLOC (5) /* Toss holder struct as soon as queued request + * is satisfied */ +#define HIF_HOLDER (6) /* We have been granted a hold on the lock */ +#define HIF_FIRST (7) /* We are first holder to get the lock */ +#define HIF_RECURSE (8) /* >1 hold requests on same glock by same process*/ +#define HIF_ABORTED (9) /* Aborted before being submitted */ + +struct gfs_holder { + struct list_head gh_list; /* Link to one of glock's holder lists */ + + struct gfs_glock *gh_gl; /* Glock that we're holding */ + struct task_struct *gh_owner; /* Linux process that is the holder */ + + /* request to change lock state */ + unsigned int gh_state; /* LM_ST_... requested lock state */ + int gh_flags; /* GL_... or LM_FLAG_... req modifiers */ + + int gh_error; /* GLR_... CANCELLED/TRYFAILED/-errno */ + unsigned long gh_iflags; /* HIF_... holder state, see above */ + struct completion gh_wait; /* Wait for completion of ... */ +}; + +/* + * Glock Structure + * One for each inter-node lock held by this node. + * A glock is a local representation/abstraction of an inter-node lock. + * Inter-node locks are managed by a "lock module" (LM) which plugs in to + * the lock harness / glock interface (see gfs-kernel/harness). Different + * lock modules support different lock protocols (e.g. GULM, GDLM, no_lock). + * A glock may have one or more holders within a node. See gfs_holder above. + * Glocks are managed within a hash table hosted by the in-core superblock. + * After all holders have released a glock, it will stay in the hash table + * cache for a time (depending on lock type), during which the inter-node + * lock will not be released unless another node needs the lock (lock + * manager requests this via callback to GFS through LM on this node). This + * provides better performance in case this node needs the glock again soon. + * See comments for meta_go_demote_ok(), glops.c. + * Each glock has an associated vector of lock-type-specific "glops" functions + * which are called at important times during the life of a glock, and + * which define the type of lock (e.g. dinode, rgrp, non-disk, etc). + * See gfs_glock_operations above. + * A glock, at inter-node scope, is identified by the following dimensions: + * 1) lock number (usually a block # for on-disk protected entities, + * or a fixed assigned number for non-disk locks, e.g. MOUNT). + * 2) lock type (actually, the type of entity protected by the lock). + * 3) lock namespace, to support multiple GFS filesystems simultaneously. + * Namespace (usually cluster:filesystem) is specified when mounting. + * See man page for gfs_mount. + * Glocks require support of Lock Value Blocks (LVBs) by the inter-node lock + * manager. LVBs are small (32-byte) chunks of data associated with a given + * lock, that can be quickly shared between cluster nodes. Used for certain + * purposes such as sharing an rgroup's block usage statistics without + * requiring the overhead of: + * -- sync-to-disk by one node, then a + * -- read from disk by another node. + * + */ + +#define GLF_PLUG (0) /* Dummy */ +#define GLF_LOCK (1) /* Exclusive (local) access to glock + * structure */ +#define GLF_STICKY (2) /* Don't release this inter-node lock + * unless another node explicitly asks */ +#define GLF_PREFETCH (3) /* This lock has been (speculatively) + * prefetched, demote if not used soon */ +#define GLF_SYNC (4) /* Sync lock's protected data as soon as + * there are no more holders */ +#define GLF_DIRTY (5) /* There is dirty data for this lock, + * sync before releasing inter-node */ +#define GLF_SKIP_WAITERS2 (6) /* Make run_queue() ignore gl_waiters2 + * (demote/greedy) holders */ +#define GLF_GREEDY (7) /* This lock is ignoring callbacks + * (requests from other nodes) for now */ + +struct gfs_glock { + struct list_head gl_list; /* Link to hb_list in one of superblock's + * sd_gl_hash glock hash table buckets */ + unsigned long gl_flags; /* GLF_... see above */ + struct lm_lockname gl_name; /* Lock number and lock type */ + atomic_t gl_count; /* Usage count */ + + spinlock_t gl_spin; /* Protects some members of this struct */ + + /* Lock state reflects inter-node manager's lock state */ + unsigned int gl_state; /* LM_ST_... see harness/lm_interface.h */ + + /* Lists of gfs_holders */ + struct list_head gl_holders; /* all current holders of the glock */ + struct list_head gl_waiters1; /* HIF_MUTEX */ + struct list_head gl_waiters2; /* HIF_DEMOTE, HIF_GREEDY */ + struct list_head gl_waiters3; /* HIF_PROMOTE */ + + struct gfs_glock_operations *gl_ops; /* function vector, defines type */ + + /* State to remember for async lock requests */ + struct gfs_holder *gl_req_gh; /* Holder for request being serviced */ + gfs_glop_bh_t gl_req_bh; /* The bottom half to execute */ + + void *gl_lock; /* Lock module's private lock data */ + char *gl_lvb; /* Lock Value Block */ + atomic_t gl_lvb_count; /* LVB recursive usage (hold/unhold) count */ + + uint64_t gl_vn; /* Incremented when protected data changes */ + unsigned long gl_stamp; /* Glock cache retention timer */ + void *gl_object; /* The protected entity (e.g. a dinode) */ + + /* Incore transaction stuff */ + /* Log elements map us to a particular set of log operations functions, + and to a particular transaction */ + struct gfs_log_element gl_new_le; /* New, incomplete transaction */ + struct gfs_log_element gl_incore_le; /* Complete (committed) trans */ + + struct gfs_gl_hash_bucket *gl_bucket; /* Our bucket in sd_gl_hash */ + struct list_head gl_reclaim; /* Link to sd_reclaim_list */ + + struct gfs_sbd *gl_sbd; /* Superblock (FS instance) */ + + struct inode *gl_aspace; /* The buffers protected by this lock */ + struct list_head gl_ail_bufs; /* AIL buffers protected by us */ +}; + +/* + * In-Place Reservation structure + * Coordinates allocation of "in-place" (as opposed to journal) FS blocks, + * which contain persistent inode/file/directory data and metadata. + * These blocks are the allocatable blocks within resource groups (i.e. + * not including rgrp header and block alloc bitmap blocks). + * gfs_inplace_reserve() calculates a fulfillment plan for allocating blocks, + * based on block statistics in the resource group headers. + * Then, gfs_blkalloc() or gfs_metaalloc() walks the block alloc bitmaps + * to do the actual allocation. + */ +struct gfs_alloc { + /* Up to 4 quotas (including an inode's user and group quotas) + can track changes in block allocation */ + + unsigned int al_qd_num; /* # of quotas tracking changes */ + struct gfs_quota_data *al_qd[4]; /* Ptrs to quota structures */ + struct gfs_holder al_qd_ghs[4]; /* Holders for quota glocks */ + + /* Request, filled in by the caller to gfs_inplace_reserve() */ + + uint32_t al_requested_di; /* Number of dinodes to reserve */ + uint32_t al_requested_meta; /* Number of metadata blocks to reserve */ + uint32_t al_requested_data; /* Number of data blocks to reserve */ + + /* Fulfillment plan, filled in by gfs_inplace_reserve() */ + + char *al_file; /* Debug info, .c file making request */ + unsigned int al_line; /* Debug info, line of code making req */ + struct gfs_holder al_ri_gh; /* Glock holder for resource grp index */ + struct gfs_holder al_rgd_gh; /* Glock holder for al_rgd rgrp */ + struct gfs_rgrpd *al_rgd; /* Resource group from which to alloc */ + uint32_t al_reserved_meta; /* Alloc up to this # meta blocks from al_rgd */ + uint32_t al_reserved_data; /* Alloc up to this # data blocks from al_rgd */ + + /* Actual alloc, filled in by gfs_blkalloc()/gfs_metaalloc(), etc. */ + + uint32_t al_alloced_di; /* # dinode blocks allocated */ + uint32_t al_alloced_meta; /* # meta blocks allocated */ + uint32_t al_alloced_data; /* # data blocks allocated */ + + /* Dinode allocation crap */ + + struct gfs_unlinked *al_ul; /* Unlinked dinode log entry */ +}; + +/* + * Incore inode structure + */ + +#define GIF_QD_LOCKED (0) +#define GIF_PAGED (1) +#define GIF_SW_PAGED (2) + +struct gfs_inode { + struct gfs_inum i_num; /* Formal inode # and block address */ + + atomic_t i_count; /* Usage count */ + unsigned long i_flags; /* GIF_... see above */ + + uint64_t i_vn; /* Version #: if different from glock's vn, + we need to read inode from disk */ + struct gfs_dinode i_di; /* Dinode (on-disk) structure */ + + struct gfs_glock *i_gl; /* This glock protects this inode */ + struct gfs_sbd *i_sbd; /* Superblock (fs instance structure) */ + struct inode *i_vnode; /* Linux VFS inode structure */ + + struct gfs_holder i_iopen_gh; /* Glock holder for Inode Open lock */ + + /* Block allocation strategy, inode scope */ + struct gfs_alloc *i_alloc; /* In-place block reservation structure */ + uint64_t i_last_rg_alloc; /* Most recent blk alloc was fm this rgrp */ + + spinlock_t i_spin; + struct rw_semaphore i_rw_mutex; + + /* Cache of most-recently used buffers in indirect addressing chain */ + struct buffer_head *i_cache[GFS_MAX_META_HEIGHT]; + + unsigned int i_greedy; /* The amount of time to be greedy */ + unsigned long i_last_pfault; /* The time of the last page fault */ + struct address_space_operations gfs_file_aops; +}; + +/* + * GFS per-fd structure + */ + +#define GFF_DID_DIRECT_ALLOC (0) + +struct gfs_file { + unsigned long f_flags; /* GFF_... see above */ + + struct semaphore f_fl_lock; /* Lock to protect flock operations */ + struct gfs_holder f_fl_gh; /* Holder for this f_vfile's flock */ + + struct gfs_inode *f_inode; /* Incore GFS inode */ + struct file *f_vfile; /* Linux file struct */ +}; + +/* + * Unlinked inode log entry incore structure + */ + +#define ULF_NEW_UL (0) /* Part of new (being built) trans */ +#define ULF_INCORE_UL (1) /* Part of incore-committed trans */ +#define ULF_IC_LIST (2) +#define ULF_OD_LIST (3) +#define ULF_LOCK (4) /* Protects access to this structure */ + +struct gfs_unlinked { + struct list_head ul_list; /* Link to superblock's sd_unlinked_list */ + unsigned int ul_count; /* Usage count */ + + struct gfs_inum ul_inum; /* Formal inode #, block addr */ + unsigned long ul_flags; /* ULF_... */ + + /* Log elements map us to a particular set of log operations functions, + and to a particular transaction */ + struct gfs_log_element ul_new_le; /* New, not yet committed */ + struct gfs_log_element ul_incore_le; /* Committed to incore log */ + struct gfs_log_element ul_ondisk_le; /* Committed to ondisk log */ +}; + +/* + * Quota log element + * One for each logged change in a block alloc value affecting a given quota. + * Only one of these for a given quota within a given transaction; + * multiple changes, within one transaction, for a given quota will be + * combined into one log element. + */ +struct gfs_quota_le { + /* Log element maps us to a particular set of log operations functions, + and to a particular transaction */ + struct gfs_log_element ql_le; /* Generic log element structure */ + + struct gfs_quota_data *ql_data; /* The quota we're changing */ + struct list_head ql_data_list; /* Link to quota's log element list */ + + int64_t ql_change; /* # of blocks alloc'd (+) or freed (-) */ +}; + +/* + * Quota structure + * One for each user or group quota. + * Summarizes all block allocation activity for a given quota, and supports + * recording updates of current block alloc values in GFS' special quota + * file, including the journaling of these updates, encompassing + * multiple transactions and log dumps. + */ + +#define QDF_USER (0) /* User (1) vs. group (0) quota */ +#define QDF_OD_LIST (1) /* Waiting for sync to quota file */ +#define QDF_LOCK (2) /* Protects access to this structure */ + +struct gfs_quota_data { + struct list_head qd_list; /* Link to superblock's sd_quota_list */ + unsigned int qd_count; /* Usage count */ + + uint32_t qd_id; /* User or group ID number */ + unsigned long qd_flags; /* QDF_... */ + + /* This list is for non-log-dump transactions */ + struct list_head qd_le_list; /* List of gfs_quota_le log elements */ + + /* Summary of block alloc changes affecting this quota, in various + stages of logging & syncing changes to the special quota file */ + int64_t qd_change_new; /* New, not yet committed to in-core log*/ + int64_t qd_change_ic; /* Committed to in-core log */ + int64_t qd_change_od; /* Committed to on-disk log */ + int64_t qd_change_sync; /* Being synced to the in-place quota file */ + + struct gfs_quota_le qd_ondisk_ql; /* Log element for log dump */ + uint64_t qd_sync_gen; /* Sync-to-quota-file generation # */ + + /* Glock provides protection for quota, *and* provides + lock value block (LVB) communication, between nodes, of current + quota values. Shared lock -> LVB read. EX lock -> LVB write. */ + struct gfs_glock *qd_gl; /* glock for this quota */ + struct gfs_quota_lvb qd_qb; /* LVB (limit/warn/value) */ + + unsigned long qd_last_warn; /* Jiffies of last warning to user */ +}; + +/* + * Log Buffer descriptor structure. + * One for each block buffer recorded in the log. + * When beginning a new transaction, GFS pre-allocates a number of these, + * and puts them on transaction's tr_free_bufs list. + * Logged buffers are of two types: + * 1). Exact copies of buffers to be written to in-place location in FS. + * 2). Log-only buffers such as log headers and control blocks (e.g. tags). + * A gfs_log_buf is required for both types; the ones for log-only buffers + * contain NULL in lb_unlock, and get cleaned up after the log write. + * lb_bh is a "fake" buffer head that directs Linux block I/O to write the buf + * to the on-disk log location, rather than the on-disk in-place location. + * Used for both types. + * lb_unlock points to the "real" buffer head that directs Linux to write the + * buf to its regular on-disk in-place filesystem location. Once the commit + * to the on-disk log is finished, GFS unlocks the "real" buffer so it can be + * written to in-place block, or modified by another transaction. + * Used only for type 1). + */ +struct gfs_log_buf { + /* Link to one of the transaction structure's lists */ + struct list_head lb_list; /* Link to tr_free_bufs or tr_list */ + + struct buffer_head lb_bh; /* "Fake" bh; for the log block */ + struct buffer_head *lb_unlock; /* "Real" bh; for the in-place block */ +}; + +/* + * Transaction structure + * One for each transaction + * This coordinates the logging and flushing of written metadata. + */ + +#define TRF_LOG_DUMP (0x00000001) +#define TRF_DUMMY (0x00000002) + +struct gfs_trans { + + /* Link to various lists */ + struct list_head tr_list; /* Superblk's incore trans or AIL list*/ + + /* Initial creation stuff */ + + char *tr_file; /* Debug info: .c file creating trans */ + unsigned int tr_line; /* Debug info: codeline creating trans */ + + /* Reservations for on-disk space in journal. + Meta blocks are copies of in-place filesystem blocks. + Extra blocks are log-only (log header and control blocks) */ + unsigned int tr_mblks_asked; /* # of meta log blocks requested */ + unsigned int tr_eblks_asked; /* # of extra log blocks requested */ + unsigned int tr_seg_reserved; /* # of segments actually reserved */ + + struct gfs_holder *tr_t_gh; /* Glock holder for this transaction */ + + /* Stuff filled in during creation */ + + unsigned int tr_flags; /* TRF_... */ + struct list_head tr_elements; /* List of this trans' log elements */ + + /* Stuff modified during the commit */ + + /* When creating a new transaction, GFS pre-allocates as many of + these buffers and descriptor structures as it might need for + all loggable filesystem (meta)data, and log-control (log-only, not + going to filesystem in-place location) data going to on-disk log. + It keeps them on these "free" lists until they get used (and linked + into tr_bufs list, below) or "refunded" if not needed. */ + unsigned int tr_num_free_bufs; /* List of free gfs_log_buf structs */ + struct list_head tr_free_bufs; /* .. 1 for each log block */ + unsigned int tr_num_free_bmem; /* List of free fs-block-size buffers */ + struct list_head tr_free_bmem; /* .. for log-only (e.g. tag) blocks */ + + /* Logged transaction starts with a (first) log header at a segment + boundary, and fills contiguous blocks after that. Each segment + boundary block gets another log header. */ + uint64_t tr_log_head; /* The next log block # to fill */ + uint64_t tr_first_head; /* Trans' first log header's block # */ + + /* gfs_log_buf structs move from tr_free_bufs to here when being used */ + struct list_head tr_bufs; /* List of buffers going to the log */ + + /* Stuff that's part of the Active Items List (AIL) */ + + struct list_head tr_ail_bufs; /* List of buffers on AIL list */ + + /* # log elements of various types on tr_elements list */ + + unsigned int tr_num_gl; /* Glocks */ + unsigned int tr_num_buf; /* Buffers */ + unsigned int tr_num_iul; /* Unlinked inodes */ + unsigned int tr_num_ida; /* De-allocated inodes */ + unsigned int tr_num_q; /* Quotas */ +}; + +#define GFS_GLOCKD_DEFAULT (1) +#define GFS_GLOCKD_MAX (32) + +#define GFS_QUOTA_DEFAULT GFS_QUOTA_OFF +#define GFS_QUOTA_OFF 0 +#define GFS_QUOTA_ACCOUNT 1 +#define GFS_QUOTA_ON 2 + +#define GFS_DATA_DEFAULT GFS_DATA_ORDERED +#define GFS_DATA_WRITEBACK 1 +#define GFS_DATA_ORDERED 2 + + +struct gfs_args { + char ar_lockproto[GFS_LOCKNAME_LEN]; /* The name of the Lock Protocol */ + char ar_locktable[GFS_LOCKNAME_LEN]; /* The name of the Lock Table */ + char ar_hostdata[GFS_LOCKNAME_LEN]; /* The host specific data */ + + int ar_spectator; /* Don't get a journal because we're always RO. */ + /* + * GFS can invoke some flock and disk caching optimizations if it is + * not in a cluster, i.e. is a local filesystem. The chosen lock + * module tells GFS, at mount time, if it supports clustering. + * The nolock module is the only one that does not support clustering; + * it sets to TRUE the local_fs field in the struct lm_lockops. + * GFS can either optimize, or ignore the opportunity. + * The user controls behavior via the following mount options. + */ + int ar_ignore_local_fs; /* Don't optimize even if local_fs is TRUE */ + int ar_localflocks; /* Let the VFS do flock|fcntl locks for us */ + int ar_localcaching; /* Local-style caching (dangerous on multihost) */ + int ar_oopses_ok; /* Allow oopses */ + + int ar_debug; /* Oops on errors instead of trying to be graceful */ + int ar_upgrade; /* Upgrade ondisk/multihost format */ + + unsigned int ar_num_glockd; /* # of glock cleanup daemons to run + (more daemons => faster cleanup) */ + int ar_posix_acls; /* Enable posix acls */ + int ar_suiddir; /* suiddir support */ + int ar_noquota; /* Turn off quota support */ +}; + +struct gfs_tune { + spinlock_t gt_spin; + + unsigned int gt_ilimit1; + unsigned int gt_ilimit1_tries; + unsigned int gt_ilimit1_min; + unsigned int gt_ilimit2; + unsigned int gt_ilimit2_tries; + unsigned int gt_ilimit2_min; + unsigned int gt_demote_secs; /* Cache retention for unheld glock */ + unsigned int gt_incore_log_blocks; + unsigned int gt_jindex_refresh_secs; /* Check for new journal index */ + unsigned int gt_depend_secs; + + /* How often various daemons run (seconds) */ + unsigned int gt_scand_secs; /* Find unused glocks and inodes */ + unsigned int gt_recoverd_secs; /* Recover journal of crashed node */ + unsigned int gt_logd_secs; /* Update log tail as AIL flushes */ + unsigned int gt_quotad_secs; /* Sync changes to quota file, clean*/ + unsigned int gt_inoded_secs; /* Toss unused inodes */ + unsigned int gt_glock_purge; /* Purge glock */ + + unsigned int gt_quota_simul_sync; /* Max # quotavals to sync at once */ + unsigned int gt_quota_warn_period; /* Secs between quota warn msgs */ + unsigned int gt_atime_quantum; /* Min secs between atime updates */ + unsigned int gt_quota_quantum; /* Secs between syncs to quota file */ + unsigned int gt_quota_scale_num; /* Numerator */ + unsigned int gt_quota_scale_den; /* Denominator */ + unsigned int gt_quota_enforce; + unsigned int gt_quota_account; + unsigned int gt_new_files_jdata; + unsigned int gt_new_files_directio; + unsigned int gt_max_atomic_write; /* Split large writes into this size*/ + unsigned int gt_max_readahead; /* Max bytes to read-ahead from disk */ + unsigned int gt_lockdump_size; + unsigned int gt_stall_secs; /* Detects trouble! */ + unsigned int gt_complain_secs; + unsigned int gt_reclaim_limit; /* Max # glocks in reclaim list */ + unsigned int gt_entries_per_readdir; + unsigned int gt_prefetch_secs; /* Usage window for prefetched glocks */ + unsigned int gt_statfs_slots; + unsigned int gt_max_mhc; /* Max # of meta headers in mhc cache */ + unsigned int gt_greedy_default; + unsigned int gt_greedy_quantum; + unsigned int gt_greedy_max; + unsigned int gt_rgrp_try_threshold; + unsigned int gt_statfs_fast; +}; + +/* + * One bucket of the filesystem's sd_gl_hash glock hash table. + * + * A gfs_glock links into a bucket's list via glock's gl_list member. + * + */ +struct gfs_gl_hash_bucket { + rwlock_t hb_lock; /* Protects list */ + struct list_head hb_list; /* List of glocks in this bucket */ +}; + +/* + * "Super Block" Data Structure + * One per mounted filesystem. + * This is the big instance structure that ties everything together for + * a given mounted filesystem. Each GFS mount has its own, supporting + * mounts of multiple GFS filesystems on each node. + * Pointer to this is usually seen as "sdp" throughout code. + * This is a very large structure, as structures go, in part because it + * contains arrays of hash buckets for various in-core caches. + */ + +#define SDF_JOURNAL_LIVE (0) /* Journaling is active (journal is writeable)*/ +#define SDF_SHUTDOWN (1) /* FS abnormaly shutdown */ + +/* (Re)mount options from Linux VFS */ +#define SDF_NOATIME (8) /* Don't change access time */ +#define SDF_ROFS (9) /* Read-only mode */ + +/* Journal log dump support */ +#define SDF_NEED_LOG_DUMP (10) /* Need to rewrite unlink and quota tags */ +#define SDF_FOUND_UL_DUMP (11) /* Recovery found unlinked tags */ +#define SDF_FOUND_Q_DUMP (12) /* Recovery found qutoa tags */ +#define SDF_IN_LOG_DUMP (13) /* Serializes log dumps */ + +/* Glock cache */ +#define GFS_GL_HASH_SHIFT (13) /* # hash buckets = 8K */ +#define GFS_GL_HASH_SIZE (1 << GFS_GL_HASH_SHIFT) +#define GFS_GL_HASH_MASK (GFS_GL_HASH_SIZE - 1) + +/* Meta header cache */ +#define GFS_MHC_HASH_SHIFT (10) /* # hash buckets = 1K */ +#define GFS_MHC_HASH_SIZE (1 << GFS_MHC_HASH_SHIFT) +#define GFS_MHC_HASH_MASK (GFS_MHC_HASH_SIZE - 1) + +/* Dependency cache */ +#define GFS_DEPEND_HASH_SHIFT (10) /* # hash buckets = 1K */ +#define GFS_DEPEND_HASH_SIZE (1 << GFS_DEPEND_HASH_SHIFT) +#define GFS_DEPEND_HASH_MASK (GFS_DEPEND_HASH_SIZE - 1) + +struct gfs_sbd { + struct gfs_sb sd_sb; /* GFS on-disk Super Block image */ + + struct super_block *sd_vfs; /* Linux VFS device independent sb */ + + struct gfs_args sd_args; /* Mount arguments */ + unsigned long sd_flags; /* SDF_... see above */ + + struct gfs_tune sd_tune; /* Filesystem tuning structure */ + + /* statfs */ + struct inode *sd_statfs_inode; + spinlock_t sd_statfs_spin; + struct gfs_statfs_change_host sd_statfs_master; + struct gfs_statfs_change_host sd_statfs_local; + unsigned long sd_statfs_sync_time; + + /* Resource group stuff */ + + struct gfs_inode *sd_riinode; /* Resource Index (rindex) inode */ + uint64_t sd_riinode_vn; /* Resource Index version # (detects + whether new rgrps have been added) */ + + struct list_head sd_rglist; /* List of all resource groups, + on-disk order */ + struct semaphore sd_rindex_lock;/* Serializes RIndex rereads */ + struct list_head sd_rg_mru_list;/* List of all resource groups, + most-recently-used (MRU) order */ + spinlock_t sd_rg_mru_lock; /* Protect mru list */ + struct list_head sd_rg_recent; /* List of rgrps from which blocks + were recently allocated */ + spinlock_t sd_rg_recent_lock; /* Protect recent list */ + struct gfs_rgrpd *sd_rg_forward;/* Next rgrp from which to attempt + a block alloc */ + spinlock_t sd_rg_forward_lock; /* Protect forward pointer */ + + unsigned int sd_rgcount; /* Total # of resource groups */ + + /* Constants computed on mount */ + + /* "bb" == "basic block" == 512Byte sector */ + uint32_t sd_fsb2bb; /* # 512B basic blocks in a FS block */ + uint32_t sd_fsb2bb_shift; /* Shift sector # to the right by + this to get FileSystem block addr */ + uint32_t sd_diptrs; /* Max # of block pointers in a dinode */ + uint32_t sd_inptrs; /* Max # of block pointers in an indirect blk */ + uint32_t sd_jbsize; /* Payload size (bytes) of a journaled metadata + block (GFS journals all meta blocks) */ + uint32_t sd_hash_bsize; /* sizeof(exhash hash block) */ + uint32_t sd_hash_bsize_shift; + uint32_t sd_hash_ptrs; /* Number of points in a hash block */ + uint32_t sd_max_dirres; /* Max blocks needed to add a directory entry */ + uint32_t sd_max_height; /* Max height of a file's tree */ + uint64_t sd_heightsize[GFS_MAX_META_HEIGHT]; + uint32_t sd_max_jheight; /* Max height, journaled file's tree */ + uint64_t sd_jheightsize[GFS_MAX_META_HEIGHT]; + + /* Lock Stuff */ + + /* Glock cache (all glocks currently held by this node for this FS) */ + struct gfs_gl_hash_bucket sd_gl_hash[GFS_GL_HASH_SIZE]; + + /* Glock reclaim support for scand and glockd */ + struct list_head sd_reclaim_list; /* List of glocks to reclaim */ + spinlock_t sd_reclaim_lock; + wait_queue_head_t sd_reclaim_wchan; + atomic_t sd_reclaim_count; /* # glocks on reclaim list */ + + /* Lock module tells us if we're first-to-mount, + which journal to use, etc. */ + struct lm_lockstruct sd_lockstruct; /* Info provided by lock module */ + + /* Other caches */ + + /* Meta-header cache (incore copies of on-disk meta headers) */ + struct list_head sd_mhc[GFS_MHC_HASH_SIZE]; /* hash buckets */ + struct list_head sd_mhc_single; /* Non-hashed list of all MHCs */ + spinlock_t sd_mhc_lock; + atomic_t sd_mhc_count; /* # MHCs in cache */ + + /* Dependency cache */ + struct list_head sd_depend[GFS_DEPEND_HASH_SIZE]; /* Hash buckets */ + spinlock_t sd_depend_lock; + atomic_t sd_depend_count; /* # dependencies in cache */ + + /* LIVE inter-node lock indicates that FS is mounted on at least + one node */ + struct gfs_holder sd_live_gh; /* Glock holder for LIVE lock */ + + /* For quiescing the filesystem */ + struct gfs_holder sd_freeze_gh; + struct semaphore sd_freeze_lock; + unsigned int sd_freeze_count; + + /* Inode Stuff */ + + struct gfs_inode *sd_rooti; /* FS's root inode */ + + /* Only 1 node at a time may rename (e.g. mv) directory from + one directory to another. */ + struct gfs_glock *sd_rename_gl; /* Rename glock */ + + /* Daemon stuff */ + + /* Scan for glocks and inodes to toss from memory */ + struct task_struct *sd_scand_process; /* Scand places on reclaim list*/ + struct task_struct *sd_glockd_process[GFS_GLOCKD_MAX]; + unsigned int sd_glockd_num; /* # of glockd procs to do reclaiming*/ + + /* Recover journal of a crashed node */ + struct task_struct *sd_recoverd_process; + + /* Update log tail as AIL gets flushed to in-place on-disk blocks */ + struct task_struct *sd_logd_process; + + /* Sync quota updates to disk, and clean up unused quota structs */ + struct task_struct *sd_quotad_process; + + /* Clean up unused inode structures */ + struct task_struct *sd_inoded_process; + + /* Log stuff */ + + /* Transaction lock protects the following from one another: + normal write transaction, journal replay (recovery), fs upgrade, + fs read-only => read/write and read/write => read-only conversions. + Also, acquiring the transaction lock in a state other than shared + causes all other machines in the cluster to sync out their dirty + data, mark their journal as being clean, and prevent any new FS + modifications from occuring (i.e. quiesces the FS). */ + struct gfs_glock *sd_trans_gl; /* Transaction glock structure */ + + struct gfs_inode *sd_jiinode; /* Journal index inode */ + uint64_t sd_jiinode_vn; /* Journal index version # (detects + if new journals have been added) */ + + unsigned int sd_journals; /* Number of journals in the FS */ + struct gfs_jindex *sd_jindex; /* Array of journal descriptors */ + struct semaphore sd_jindex_lock; + unsigned long sd_jindex_refresh_time; /* Poll for new journals (secs) */ + + struct gfs_jindex sd_jdesc; /* This machine's journal descriptor */ + struct gfs_holder sd_journal_gh; /* This machine's jrnl glock holder */ + + uint64_t sd_sequence; /* Assigned to xactions in order they commit */ + uint64_t sd_log_head; /* Block number of next journal write */ + uint64_t sd_log_wrap; + + spinlock_t sd_log_seg_lock; + unsigned int sd_log_seg_free; /* # of free segments in the log */ + unsigned int sd_log_seg_ail2; /* # of freeable segments in the log */ + struct list_head sd_log_seg_list; + wait_queue_head_t sd_log_seg_wait; + + /* "Active Items List" of transactions that have been flushed to + on-disk log, and are waiting for flush to in-place on-disk blocks */ + struct list_head sd_log_ail; /* "next" is head, "prev" is tail */ + + /* Transactions committed incore, but not yet flushed to on-disk log */ + struct list_head sd_log_incore; /* "Next" is newest, "prev" is oldest */ + unsigned int sd_log_buffers; /* # of buffers in the incore log */ + + struct rw_semaphore sd_log_lock; /* Lock for access to log values */ + + uint64_t sd_log_dump_last; + uint64_t sd_log_dump_last_wrap; + + /* + * Unlinked inode crap. + * List includes newly created, not-yet-linked inodes, + * as well as inodes that have been unlinked and are waiting + * to be de-allocated. + */ + struct list_head sd_unlinked_list; /* List of unlinked inodes */ + spinlock_t sd_unlinked_lock; /* Protects list and members */ + + atomic_t sd_unlinked_ic_count; + atomic_t sd_unlinked_od_count; + + /* Quota crap */ + + struct list_head sd_quota_list; /* List of all gfs_quota_data structs */ + spinlock_t sd_quota_lock; + + atomic_t sd_quota_count; /* # quotas on sd_quota_list */ + atomic_t sd_quota_od_count; /* # quotas waiting for sync to + special on-disk quota file */ + + struct gfs_inode *sd_qinode; /* Special on-disk quota file */ + + uint64_t sd_quota_sync_gen; /* Generation, incr when sync to file */ + unsigned long sd_quota_sync_time; /* Jiffies, last sync to quota file */ + + /* License crap */ + + struct gfs_inode *sd_linode; /* Special on-disk license file */ + + /* Recovery stuff */ + + /* Lock module tells GFS, via callback, when a journal needs recovery. + It stays on this list until recovery daemon performs recovery. */ + struct list_head sd_dirty_j; /* List of dirty journals */ + spinlock_t sd_dirty_j_lock; /* Protects list */ + + /* Statistics for 3 possible recovery actions for each buffer in log, + determined by comparing generation #s of logged block and + in-place block. Scope of stats is for one journal. */ + unsigned int sd_recovery_replays; /* newer than in-place; copy it */ + unsigned int sd_recovery_skips; /* older than in-place; ignore it */ + unsigned int sd_recovery_sames; /* same as in-place; ignore it */ + + /* Counters */ + + /* current quantities of various things */ + atomic_t sd_glock_count; /* # of gfs_glock structs alloc'd */ + atomic_t sd_glock_held_count; /* # of glocks locked by this node */ + atomic_t sd_inode_count; /* # of gfs_inode structs alloc'd */ + atomic_t sd_bufdata_count; /* # of gfs_bufdata structs alloc'd */ + + atomic_t sd_fh2dentry_misses; /* total # get_dentry misses */ + atomic_t sd_reclaimed; /* total # glocks reclaimed since mount */ + + /* total lock-related calls handled since mount */ + atomic_t sd_glock_nq_calls; + atomic_t sd_glock_dq_calls; + atomic_t sd_glock_prefetch_calls; + atomic_t sd_lm_lock_calls; + atomic_t sd_lm_unlock_calls; + atomic_t sd_lm_callbacks; + + atomic_t sd_lm_outstanding; + atomic_t sd_bio_reads; + atomic_t sd_bio_writes; + atomic_t sd_bio_outstanding; + + /* total calls from Linux VFS handled since mount */ + atomic_t sd_ops_address; + atomic_t sd_ops_dentry; + atomic_t sd_ops_export; + atomic_t sd_ops_file; + atomic_t sd_ops_inode; + atomic_t sd_ops_super; + atomic_t sd_ops_vm; + + char sd_fsname[256]; + char sd_table_name[256]; + char sd_proto_name[256]; + + struct kobject sd_kobj; + + /* Debugging crud */ + + unsigned long sd_last_warning; + + spinlock_t sd_ail_lock; + struct list_head sd_recovery_bufs; + + struct list_head sd_list; +}; + +#endif /* __INCORE_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/quota.c +++ linux-2.6.27/ubuntu/gfs/quota.c @@ -0,0 +1,1139 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "bmap.h" +#include "file.h" +#include "glock.h" +#include "glops.h" +#include "log.h" +#include "quota.h" +#include "rgrp.h" +#include "super.h" +#include "trans.h" + +/** + * gfs_quota_get - Get a structure to represent a quota change + * @sdp: the filesystem + * @user: TRUE if this is a user quota + * @id: the uid or gid + * @create: if TRUE, create the structure, otherwise return NULL + * @qdp: the returned quota structure + * + * Returns: errno + */ + +int +gfs_quota_get(struct gfs_sbd *sdp, int user, uint32_t id, int create, + struct gfs_quota_data **qdp) +{ + struct gfs_quota_data *qd = NULL, *new_qd = NULL; + struct list_head *tmp, *head; + int error; + + *qdp = NULL; + + for (;;) { + spin_lock(&sdp->sd_quota_lock); + + for (head = &sdp->sd_quota_list, tmp = head->next; + tmp != head; + tmp = tmp->next) { + qd = list_entry(tmp, struct gfs_quota_data, qd_list); + if (qd->qd_id == id && + !test_bit(QDF_USER, &qd->qd_flags) == !user) { + qd->qd_count++; + break; + } + } + + if (tmp == head) + qd = NULL; + + if (!qd && new_qd) { + qd = new_qd; + list_add(&qd->qd_list, &sdp->sd_quota_list); + new_qd = NULL; + } + + spin_unlock(&sdp->sd_quota_lock); + + if (qd || !create) { + if (new_qd) { + gfs_lvb_unhold(new_qd->qd_gl); + kfree(new_qd); + atomic_dec(&sdp->sd_quota_count); + } + *qdp = qd; + return 0; + } + + new_qd = kmalloc(sizeof(struct gfs_quota_data), GFP_KERNEL); + if (!new_qd) + return -ENOMEM; + memset(new_qd, 0, sizeof(struct gfs_quota_data)); + + new_qd->qd_count = 1; + + new_qd->qd_id = id; + if (user) + set_bit(QDF_USER, &new_qd->qd_flags); + + INIT_LIST_HEAD(&new_qd->qd_le_list); + + error = gfs_glock_get(sdp, 2 * (uint64_t)id + ((user) ? 0 : 1), + &gfs_quota_glops, CREATE, + &new_qd->qd_gl); + if (error) { + kfree(new_qd); + return error; + } + + error = gfs_lvb_hold(new_qd->qd_gl); + + gfs_glock_put(new_qd->qd_gl); + + if (error) { + kfree(new_qd); + return error; + } + + atomic_inc(&sdp->sd_quota_count); + } +} + +/** + * gfs_quota_hold - increment the usage count on a struct gfs_quota_data + * @sdp: the filesystem + * @qd: the structure + * + */ + +void +gfs_quota_hold(struct gfs_sbd *sdp, struct gfs_quota_data *qd) +{ + spin_lock(&sdp->sd_quota_lock); + gfs_assert(sdp, qd->qd_count,); + qd->qd_count++; + spin_unlock(&sdp->sd_quota_lock); +} + +/** + * gfs_quota_put - decrement the usage count on a struct gfs_quota_data + * @sdp: the filesystem + * @qd: the structure + * + * Free the structure if its reference count hits zero. + * + */ + +void +gfs_quota_put(struct gfs_sbd *sdp, struct gfs_quota_data *qd) +{ + spin_lock(&sdp->sd_quota_lock); + gfs_assert(sdp, qd->qd_count,); + qd->qd_count--; + spin_unlock(&sdp->sd_quota_lock); +} + +/** + * quota_find - Find a quota change to sync to the quota file + * @sdp: the filesystem + * + * The returned structure is locked and needs to be unlocked + * with quota_unlock(). + * + * Returns: A quota structure, or NULL + */ + +static struct gfs_quota_data * +quota_find(struct gfs_sbd *sdp) +{ + struct list_head *tmp, *head; + struct gfs_quota_data *qd = NULL; + + if (test_bit(SDF_ROFS, &sdp->sd_flags)) + return NULL; + + gfs_log_lock(sdp); + spin_lock(&sdp->sd_quota_lock); + + if (!atomic_read(&sdp->sd_quota_od_count)) + goto out; + + for (head = &sdp->sd_quota_list, tmp = head->next; + tmp != head; + tmp = tmp->next) { + qd = list_entry(tmp, struct gfs_quota_data, qd_list); + + if (test_bit(QDF_LOCK, &qd->qd_flags)) + continue; + if (!test_bit(QDF_OD_LIST, &qd->qd_flags)) + continue; + if (qd->qd_sync_gen >= sdp->sd_quota_sync_gen) + continue; + + list_move_tail(&qd->qd_list, &sdp->sd_quota_list); + + set_bit(QDF_LOCK, &qd->qd_flags); + qd->qd_count++; + qd->qd_change_sync = qd->qd_change_od; + + goto out; + } + + qd = NULL; + + out: + spin_unlock(&sdp->sd_quota_lock); + gfs_log_unlock(sdp); + + return qd; +} + +/** + * quota_trylock - Try to lock a given quota entry + * @sdp: the filesystem + * @qd: the quota data structure + * + * Returns: TRUE if the lock was successful, FALSE, otherwise + */ + +static int +quota_trylock(struct gfs_sbd *sdp, struct gfs_quota_data *qd) +{ + int ret = FALSE; + + if (test_bit(SDF_ROFS, &sdp->sd_flags)) + return FALSE; + + gfs_log_lock(sdp); + spin_lock(&sdp->sd_quota_lock); + + if (test_bit(QDF_LOCK, &qd->qd_flags)) + goto out; + if (!test_bit(QDF_OD_LIST, &qd->qd_flags)) + goto out; + + list_move_tail(&qd->qd_list, &sdp->sd_quota_list); + + set_bit(QDF_LOCK, &qd->qd_flags); + qd->qd_count++; + qd->qd_change_sync = qd->qd_change_od; + + ret = TRUE; + + out: + spin_unlock(&sdp->sd_quota_lock); + gfs_log_unlock(sdp); + + return ret; +} + +/** + * quota_unlock - drop and a reference on a quota structure + * @sdp: the filesystem + * @qd: the quota inode structure + * + */ + +static void +quota_unlock(struct gfs_sbd *sdp, struct gfs_quota_data *qd) +{ + spin_lock(&sdp->sd_quota_lock); + + gfs_assert_warn(sdp, test_bit(QDF_LOCK, &qd->qd_flags)); + clear_bit(QDF_LOCK, &qd->qd_flags); + + gfs_assert(sdp, qd->qd_count,); + qd->qd_count--; + + spin_unlock(&sdp->sd_quota_lock); +} + +/** + * gfs_quota_merge - add/remove a quota change from the in-memory list + * @sdp: the filesystem + * @tag: the quota change tag + * + * Returns: errno + */ + +int +gfs_quota_merge(struct gfs_sbd *sdp, struct gfs_quota_tag *tag) +{ + struct gfs_quota_data *qd; + int error; + + error = gfs_quota_get(sdp, + tag->qt_flags & GFS_QTF_USER, tag->qt_id, + CREATE, &qd); + if (error) + return error; + + gfs_assert(sdp, qd->qd_change_ic == qd->qd_change_od,); + + gfs_log_lock(sdp); + + qd->qd_change_ic += tag->qt_change; + qd->qd_change_od += tag->qt_change; + + if (qd->qd_change_od) { + if (!test_bit(QDF_OD_LIST, &qd->qd_flags)) { + gfs_quota_hold(sdp, qd); + set_bit(QDF_OD_LIST, &qd->qd_flags); + atomic_inc(&sdp->sd_quota_od_count); + } + } else { + gfs_assert_warn(sdp, test_bit(QDF_OD_LIST, &qd->qd_flags)); + clear_bit(QDF_OD_LIST, &qd->qd_flags); + gfs_quota_put(sdp, qd); + gfs_assert(sdp, atomic_read(&sdp->sd_quota_od_count) > 0,); + atomic_dec(&sdp->sd_quota_od_count); + } + + gfs_log_unlock(sdp); + + gfs_quota_put(sdp, qd); + + return 0; +} + +/** + * gfs_quota_scan - Look for unused struct gfs_quota_data structures to throw away + * @sdp: the filesystem + * + */ + +void +gfs_quota_scan(struct gfs_sbd *sdp) +{ + struct list_head *head, *tmp, *next; + struct gfs_quota_data *qd; + LIST_HEAD(dead); + + spin_lock(&sdp->sd_quota_lock); + + for (head = &sdp->sd_quota_list, tmp = head->next, next = tmp->next; + tmp != head; + tmp = next, next = next->next) { + qd = list_entry(tmp, struct gfs_quota_data, qd_list); + if (!qd->qd_count) + list_move(&qd->qd_list, &dead); + } + + spin_unlock(&sdp->sd_quota_lock); + + while (!list_empty(&dead)) { + qd = list_entry(dead.next, struct gfs_quota_data, qd_list); + + gfs_assert_warn(sdp, !qd->qd_count); + gfs_assert_warn(sdp, !test_bit(QDF_OD_LIST, &qd->qd_flags) && + !test_bit(QDF_LOCK, &qd->qd_flags)); + gfs_assert_warn(sdp, !qd->qd_change_new && !qd->qd_change_ic && + !qd->qd_change_od); + + list_del(&qd->qd_list); + gfs_lvb_unhold(qd->qd_gl); + kfree(qd); + atomic_dec(&sdp->sd_quota_count); + } +} + +/** + * gfs_quota_cleanup - get rid of any extra struct gfs_quota_data structures + * @sdp: the filesystem + * + */ + +void +gfs_quota_cleanup(struct gfs_sbd *sdp) +{ + struct gfs_quota_data *qd; + + restart: + gfs_log_lock(sdp); + + spin_lock(&sdp->sd_quota_lock); + + while (!list_empty(&sdp->sd_quota_list)) { + qd = list_entry(sdp->sd_quota_list.next, + struct gfs_quota_data, + qd_list); + + if (qd->qd_count > 1) { + spin_unlock(&sdp->sd_quota_lock); + gfs_log_unlock(sdp); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + goto restart; + + } else if (qd->qd_count) { + gfs_assert_warn(sdp, + test_bit(QDF_OD_LIST, &qd->qd_flags) && + !test_bit(QDF_LOCK, &qd->qd_flags)); + gfs_assert_warn(sdp, qd->qd_change_od && + qd->qd_change_od == qd->qd_change_ic); + gfs_assert_warn(sdp, !qd->qd_change_new); + + list_del(&qd->qd_list); + atomic_dec(&sdp->sd_quota_od_count); + + spin_unlock(&sdp->sd_quota_lock); + gfs_lvb_unhold(qd->qd_gl); + kfree(qd); + atomic_dec(&sdp->sd_quota_count); + spin_lock(&sdp->sd_quota_lock); + + } else { + gfs_assert_warn(sdp, + !test_bit(QDF_OD_LIST, &qd->qd_flags) && + !test_bit(QDF_LOCK, &qd->qd_flags)); + gfs_assert_warn(sdp, !qd->qd_change_new && + !qd->qd_change_ic && + !qd->qd_change_od); + + list_del(&qd->qd_list); + + spin_unlock(&sdp->sd_quota_lock); + gfs_lvb_unhold(qd->qd_gl); + kfree(qd); + atomic_dec(&sdp->sd_quota_count); + spin_lock(&sdp->sd_quota_lock); + } + } + + spin_unlock(&sdp->sd_quota_lock); + + gfs_assert(sdp, !atomic_read(&sdp->sd_quota_od_count),); + + gfs_log_unlock(sdp); +} + +/** + * sort_qd - figure out the order between two quota data structures + * @a: first quota data structure + * @b: second quota data structure + * + * Returns: -1 if @a comes before @b, 0 if @a equals @b, 1 if @b comes before @a + */ + +static int +sort_qd(const void *a, const void *b) +{ + struct gfs_quota_data *qd_a = *(struct gfs_quota_data **)a; + struct gfs_quota_data *qd_b = *(struct gfs_quota_data **)b; + int ret = 0; + + if (!test_bit(QDF_USER, &qd_a->qd_flags) != + !test_bit(QDF_USER, &qd_b->qd_flags)) { + if (test_bit(QDF_USER, &qd_a->qd_flags)) + ret = -1; + else + ret = 1; + } else { + if (qd_a->qd_id < qd_b->qd_id) + ret = -1; + else if (qd_a->qd_id > qd_b->qd_id) + ret = 1; + } + + return ret; +} + +/** + * do_quota_sync - Sync a bunch quota changes to the quota file + * @sdp: the filesystem + * @qda: an array of struct gfs_quota_data structures to be synced + * @num_qd: the number of elements in @qda + * + * Returns: errno + */ + +static int +do_quota_sync(struct gfs_sbd *sdp, struct gfs_quota_data **qda, + unsigned int num_qd) +{ + struct gfs_inode *ip = sdp->sd_qinode; + struct gfs_alloc *al = NULL; + struct gfs_holder i_gh, *ghs; + struct gfs_quota q; + char buf[sizeof(struct gfs_quota)]; + uint64_t offset; + unsigned int qx, x; + int ar; + unsigned int nalloc = 0; + unsigned int data_blocks, ind_blocks; + int error; + + gfs_write_calc_reserv(ip, sizeof(struct gfs_quota), &data_blocks, + &ind_blocks); + + ghs = kmalloc(num_qd * sizeof(struct gfs_holder), GFP_KERNEL); + if (!ghs) + return -ENOMEM; + + gfs_sort(qda, num_qd, sizeof (struct gfs_quota_data *), sort_qd); + for (qx = 0; qx < num_qd; qx++) { + error = gfs_glock_nq_init(qda[qx]->qd_gl, + LM_ST_EXCLUSIVE, + GL_NOCACHE, &ghs[qx]); + if (error) + goto fail; + } + + error = gfs_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); + if (error) + goto fail; + + for (x = 0; x < num_qd; x++) { + offset = (2 * (uint64_t)qda[x]->qd_id + + ((test_bit(QDF_USER, &qda[x]->qd_flags)) ? 0 : 1)) * + sizeof(struct gfs_quota); + + error = gfs_write_alloc_required(ip, offset, + sizeof(struct gfs_quota), + &ar); + if (error) + goto fail_gunlock; + + if (ar) + nalloc++; + } + + if (nalloc) { + al = gfs_alloc_get(ip); + + error = + gfs_quota_hold_m(ip, NO_QUOTA_CHANGE, + NO_QUOTA_CHANGE); + if (error) + goto fail_alloc; + + al->al_requested_meta = nalloc * (data_blocks + ind_blocks); + + error = gfs_inplace_reserve(ip); + if (error) + goto fail_qs; + + /* Trans may require: + two (journaled) data blocks, a dinode block, RG bitmaps to allocate from, + indirect blocks, and a quota block */ + + error = gfs_trans_begin(sdp, + 1 + al->al_rgd->rd_ri.ri_length + + num_qd * data_blocks + + nalloc * ind_blocks, + gfs_struct2blk(sdp, num_qd + 2, + sizeof(struct gfs_quota_tag))); + if (error) + goto fail_ipres; + } else { + /* Trans may require: + Data blocks, a dinode block, and quota blocks */ + + error = gfs_trans_begin(sdp, + 1 + data_blocks * num_qd, + gfs_struct2blk(sdp, num_qd, + sizeof(struct gfs_quota_tag))); + if (error) + goto fail_gunlock; + } + + for (x = 0; x < num_qd; x++) { + offset = (2 * (uint64_t)qda[x]->qd_id + + ((test_bit(QDF_USER, &qda[x]->qd_flags)) ? 0 : 1)) * + sizeof(struct gfs_quota); + + /* The quota file may not be a multiple of sizeof(struct gfs_quota) bytes. */ + memset(buf, 0, sizeof(struct gfs_quota)); + + error = gfs_internal_read(ip, buf, offset, + sizeof(struct gfs_quota)); + if (error < 0) + goto fail_end_trans; + + gfs_quota_in(&q, buf); + q.qu_value += qda[x]->qd_change_sync; + gfs_quota_out(&q, buf); + + error = gfs_internal_write(ip, buf, offset, + sizeof(struct gfs_quota)); + if (error < 0) + goto fail_end_trans; + else if (error != sizeof(struct gfs_quota)) { + error = -EIO; + goto fail_end_trans; + } + + if (test_bit(QDF_USER, &qda[x]->qd_flags)) + gfs_trans_add_quota(sdp, -qda[x]->qd_change_sync, + qda[x]->qd_id, NO_QUOTA_CHANGE); + else + gfs_trans_add_quota(sdp, -qda[x]->qd_change_sync, + NO_QUOTA_CHANGE, qda[x]->qd_id); + + memset(&qda[x]->qd_qb, 0, sizeof(struct gfs_quota_lvb)); + qda[x]->qd_qb.qb_magic = GFS_MAGIC; + qda[x]->qd_qb.qb_limit = q.qu_limit; + qda[x]->qd_qb.qb_warn = q.qu_warn; + qda[x]->qd_qb.qb_value = q.qu_value; + + gfs_quota_lvb_out(&qda[x]->qd_qb, qda[x]->qd_gl->gl_lvb); + } + + gfs_trans_end(sdp); + + if (nalloc) { + gfs_assert_warn(sdp, al->al_alloced_meta); + gfs_inplace_release(ip); + gfs_quota_unhold_m(ip); + gfs_alloc_put(ip); + } + + gfs_glock_dq_uninit(&i_gh); + + for (x = 0; x < num_qd; x++) + gfs_glock_dq_uninit(&ghs[x]); + + kfree(ghs); + + gfs_log_flush_glock(ip->i_gl); + + return 0; + + fail_end_trans: + gfs_trans_end(sdp); + + fail_ipres: + if (nalloc) + gfs_inplace_release(ip); + + fail_qs: + if (nalloc) + gfs_quota_unhold_m(ip); + + fail_alloc: + if (nalloc) + gfs_alloc_put(ip); + + fail_gunlock: + gfs_glock_dq_uninit(&i_gh); + + fail: + while (qx--) + gfs_glock_dq_uninit(&ghs[qx]); + + kfree(ghs); + + return error; +} + +/** + * glock_q - Acquire a lock for a quota entry + * @sdp: the filesystem + * @qd: the quota data structure to glock + * @force_refresh: If TRUE, always read from the quota file + * @q_gh: the glock holder for the quota lock + * + * Returns: errno + */ + +static int +glock_q(struct gfs_sbd *sdp, struct gfs_quota_data *qd, int force_refresh, + struct gfs_holder *q_gh) +{ + struct gfs_holder i_gh; + struct gfs_quota q; + char buf[sizeof(struct gfs_quota)]; + int error; + + restart: + error = gfs_glock_nq_init(qd->qd_gl, LM_ST_SHARED, 0, q_gh); + if (error) + return error; + + gfs_quota_lvb_in(&qd->qd_qb, qd->qd_gl->gl_lvb); + + if (force_refresh || + qd->qd_qb.qb_magic != GFS_MAGIC) { + gfs_glock_dq_uninit(q_gh); + error = gfs_glock_nq_init(qd->qd_gl, + LM_ST_EXCLUSIVE, GL_NOCACHE, + q_gh); + if (error) + return error; + + error = gfs_glock_nq_init(sdp->sd_qinode->i_gl, + LM_ST_SHARED, 0, + &i_gh); + if (error) + goto fail; + + memset(buf, 0, sizeof(struct gfs_quota)); + + error = gfs_internal_read(sdp->sd_qinode, buf, + (2 * (uint64_t)qd->qd_id + + ((test_bit(QDF_USER, &qd->qd_flags)) ? 0 : 1)) * + sizeof(struct gfs_quota), + sizeof(struct gfs_quota)); + if (error < 0) + goto fail_gunlock; + + gfs_glock_dq_uninit(&i_gh); + + gfs_quota_in(&q, buf); + + memset(&qd->qd_qb, 0, sizeof(struct gfs_quota_lvb)); + qd->qd_qb.qb_magic = GFS_MAGIC; + qd->qd_qb.qb_limit = q.qu_limit; + qd->qd_qb.qb_warn = q.qu_warn; + qd->qd_qb.qb_value = q.qu_value; + + gfs_quota_lvb_out(&qd->qd_qb, qd->qd_gl->gl_lvb); + + gfs_glock_dq_uninit(q_gh); + force_refresh = FALSE; + goto restart; + } + + return 0; + + fail_gunlock: + gfs_glock_dq_uninit(&i_gh); + + fail: + gfs_glock_dq_uninit(q_gh); + + return error; +} + +/** + * gfs_quota_hold_m - Hold the quota structures for up to 4 IDs + * @ip: Two of the IDs are the UID and GID from this file + * @uid: a UID or the constant NO_QUOTA_CHANGE + * @gid: a GID or the constant NO_QUOTA_CHANGE + * + * The struct gfs_quota_data structures representing the locks are + * stored in the ip->i_alloc->al_qd array. + * + * Returns: errno + */ + +int +gfs_quota_hold_m(struct gfs_inode *ip, uint32_t uid, uint32_t gid) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_alloc *al = ip->i_alloc; + unsigned int x = 0; + int error; + + if (gfs_assert_warn(sdp, !al->al_qd_num && + !test_bit(GIF_QD_LOCKED, &ip->i_flags))) + return -EIO; + + if (!gfs_tune_get(sdp, gt_quota_account)) + return 0; + + error = gfs_quota_get(sdp, TRUE, ip->i_di.di_uid, + CREATE, &al->al_qd[x]); + if (error) + goto fail; + x++; + + error = gfs_quota_get(sdp, FALSE, ip->i_di.di_gid, + CREATE, &al->al_qd[x]); + if (error) + goto fail; + x++; + + if (uid != NO_QUOTA_CHANGE) { + error = gfs_quota_get(sdp, TRUE, uid, + CREATE, &al->al_qd[x]); + if (error) + goto fail; + x++; + } + + if (gid != NO_QUOTA_CHANGE) { + error = gfs_quota_get(sdp, FALSE, gid, + CREATE, &al->al_qd[x]); + if (error) + goto fail; + x++; + } + + al->al_qd_num = x; + + return 0; + + fail: + if (x) { + al->al_qd_num = x; + gfs_quota_unhold_m(ip); + } + + return error; +} + +/** + * gfs_quota_unhold_m - throw away some quota locks + * @ip: the inode who's ip->i_alloc->al_qd array holds the structures + * + */ + +void +gfs_quota_unhold_m(struct gfs_inode *ip) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_alloc *al = ip->i_alloc; + unsigned int x; + + gfs_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags)); + + for (x = 0; x < al->al_qd_num; x++) { + gfs_quota_put(sdp, al->al_qd[x]); + al->al_qd[x] = NULL; + } + al->al_qd_num = 0; +} + +/** + * gfs_quota_lock_m - Acquire the quota locks for up to 4 IDs + * @ip: Two of the IDs are the UID and GID from this file + * @uid: a UID or the constant NO_QUOTA_CHANGE + * @gid: a GID or the constant NO_QUOTA_CHANGE + * + * The struct gfs_quota_data structures representing the locks are + * stored in the ip->i_alloc->al_qd array. + * + * Returns: errno + */ + +int +gfs_quota_lock_m(struct gfs_inode *ip, uint32_t uid, uint32_t gid) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_alloc *al = ip->i_alloc; + unsigned int x; + int error; + + gfs_quota_hold_m(ip, uid, gid); + + if (!gfs_tune_get(sdp, gt_quota_enforce)) + return 0; + if (capable(CAP_SYS_RESOURCE)) + return 0; + + gfs_sort(al->al_qd, al->al_qd_num, + sizeof(struct gfs_quota_data *), sort_qd); + + for (x = 0; x < al->al_qd_num; x++) { + error = glock_q(sdp, al->al_qd[x], FALSE, &al->al_qd_ghs[x]); + if (error) + goto fail; + } + + set_bit(GIF_QD_LOCKED, &ip->i_flags); + + return 0; + + fail: + while (x--) + gfs_glock_dq_uninit(&al->al_qd_ghs[x]); + + return error; +} + +/** + * gfs_quota_unlock_m - drop some quota locks + * @ip: the inode who's ip->i_alloc->al_qd array holds the locks + * + */ + +void +gfs_quota_unlock_m(struct gfs_inode *ip) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_alloc *al = ip->i_alloc; + struct gfs_quota_data *qd, *qda[4]; + int64_t value; + unsigned int count = 0; + unsigned int x; + int do_sync; + + if (!test_and_clear_bit(GIF_QD_LOCKED, &ip->i_flags)) + goto out; + + for (x = 0; x < al->al_qd_num; x++) { + qd = al->al_qd[x]; + + spin_lock(&sdp->sd_quota_lock); + value = qd->qd_change_new + qd->qd_change_ic; + spin_unlock(&sdp->sd_quota_lock); + + do_sync = TRUE; + if (!qd->qd_qb.qb_limit) + do_sync = FALSE; + else if (qd->qd_qb.qb_value >= (int64_t)qd->qd_qb.qb_limit) + do_sync = FALSE; + else { + struct gfs_tune *gt = &sdp->sd_tune; + unsigned int num, den; + int64_t v; + + spin_lock(>->gt_spin); + num = gt->gt_quota_scale_num; + den = gt->gt_quota_scale_den; + spin_unlock(>->gt_spin); + + v = value * gfs_num_journals(sdp) * num; + do_div(v, den); + v += qd->qd_qb.qb_value; + if (v < (int64_t)qd->qd_qb.qb_limit) + do_sync = FALSE; + } + + gfs_glock_dq_uninit(&al->al_qd_ghs[x]); + + if (do_sync) { + gfs_log_flush(sdp); + if (quota_trylock(sdp, qd)) + qda[count++] = qd; + } + } + + if (count) { + do_quota_sync(sdp, qda, count); + + for (x = 0; x < count; x++) + quota_unlock(sdp, qda[x]); + } + + out: + gfs_quota_unhold_m(ip); +} + +/** + * print_quota_message - print a message to the user's tty about quotas + * @sdp: the filesystem + * @qd: the quota ID that the message is about + * @type: the type of message ("exceeded" or "warning") + * + * Returns: errno + */ + +static int +print_quota_message(struct gfs_sbd *sdp, struct gfs_quota_data *qd, char *type) +{ + struct tty_struct *tty; + char *line; + int len; + + line = kmalloc(256, GFP_KERNEL); + if (!line) + return -ENOMEM; + + len = snprintf(line, 256, "GFS: fsid=%s: quota %s for %s %u\r\n", + sdp->sd_fsname, type, + (test_bit(QDF_USER, &qd->qd_flags)) ? "user" : "group", + qd->qd_id); + + if (current->signal) { + tty = current->signal->tty; + if (tty && tty->ops->write) + tty->ops->write(tty, line, len); + } + + kfree(line); + + return 0; +} + +/** + * gfs_quota_check - Check to see if a block allocation is possible + * @ip: the inode who's ip->i_res.ir_qd array holds the quota locks + * @uid: the UID the block is allocated for + * @gid: the GID the block is allocated for + * + */ + +int +gfs_quota_check(struct gfs_inode *ip, uint32_t uid, uint32_t gid) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_alloc *al = ip->i_alloc; + struct gfs_quota_data *qd; + int64_t value; + unsigned int x; + int error = 0; + + if (!al) + return 0; + + if (!gfs_tune_get(sdp, gt_quota_enforce)) + return 0; + + for (x = 0; x < al->al_qd_num; x++) { + qd = al->al_qd[x]; + + if (!((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) || + (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags)))) + continue; + + spin_lock(&sdp->sd_quota_lock); + value = qd->qd_change_new + qd->qd_change_ic; + spin_unlock(&sdp->sd_quota_lock); + value += qd->qd_qb.qb_value; + + if (qd->qd_qb.qb_limit && (int64_t)qd->qd_qb.qb_limit < value) { + print_quota_message(sdp, qd, "exceeded"); + error = -EDQUOT; + break; + } else if (qd->qd_qb.qb_warn && + (int64_t)qd->qd_qb.qb_warn < value && + time_after_eq(jiffies, + qd->qd_last_warn + + gfs_tune_get(sdp, gt_quota_warn_period) * HZ)) { + error = print_quota_message(sdp, qd, "warning"); + qd->qd_last_warn = jiffies; + } + } + + return error; +} + +/** + * gfs_quota_sync - Sync quota changes to the quota file + * @sdp: the filesystem + * + * Returns: errno + */ + +int +gfs_quota_sync(struct gfs_sbd *sdp) +{ + struct gfs_quota_data **qda; + unsigned int max_qd = gfs_tune_get(sdp, gt_quota_simul_sync); + unsigned int num_qd; + unsigned int x; + int error = 0; + + sdp->sd_quota_sync_gen++; + + qda = kmalloc(max_qd * sizeof(struct gfs_quota_data *), GFP_KERNEL); + if (!qda) + return -ENOMEM; + memset(qda, 0, max_qd * sizeof(struct gfs_quota_data *)); + + do { + num_qd = 0; + + for (;;) { + qda[num_qd] = quota_find(sdp); + if (!qda[num_qd]) + break; + + if (++num_qd == max_qd) + break; + } + + if (num_qd) { + error = do_quota_sync(sdp, qda, num_qd); + if (!error) + for (x = 0; x < num_qd; x++) + qda[x]->qd_sync_gen = + sdp->sd_quota_sync_gen; + + for (x = 0; x < num_qd; x++) + quota_unlock(sdp, qda[x]); + } + } + while (!error && num_qd == max_qd); + + kfree(qda); + + return error; +} + +/** + * gfs_quota_refresh - Refresh the LVB for a given quota ID + * @sdp: the filesystem + * @user: + * @id: + * + * Returns: errno + */ + +int +gfs_quota_refresh(struct gfs_sbd *sdp, int user, uint32_t id) +{ + struct gfs_quota_data *qd; + struct gfs_holder q_gh; + int error; + + error = gfs_quota_get(sdp, user, id, CREATE, &qd); + if (error) + return error; + + error = glock_q(sdp, qd, TRUE, &q_gh); + if (!error) + gfs_glock_dq_uninit(&q_gh); + + gfs_quota_put(sdp, qd); + + return error; +} + +/** + * gfs_quota_read - Read the info a given quota ID + * @sdp: the filesystem + * @user: + * @id: + * @q: + * + * Returns: errno + */ + +int +gfs_quota_read(struct gfs_sbd *sdp, int user, uint32_t id, + struct gfs_quota *q) +{ + struct gfs_quota_data *qd; + struct gfs_holder q_gh; + int error; + + if (((user) ? (id != current->fsuid) : (!in_group_p(id))) && + !capable(CAP_SYS_ADMIN)) + return -EACCES; + + error = gfs_quota_get(sdp, user, id, CREATE, &qd); + if (error) + return error; + + error = glock_q(sdp, qd, FALSE, &q_gh); + if (error) + goto out; + + memset(q, 0, sizeof(struct gfs_quota)); + q->qu_limit = qd->qd_qb.qb_limit; + q->qu_warn = qd->qd_qb.qb_warn; + q->qu_value = qd->qd_qb.qb_value; + + spin_lock(&sdp->sd_quota_lock); + q->qu_value += qd->qd_change_new + qd->qd_change_ic; + spin_unlock(&sdp->sd_quota_lock); + + gfs_glock_dq_uninit(&q_gh); + + out: + gfs_quota_put(sdp, qd); + + return error; +} --- linux-2.6.27.orig/ubuntu/gfs/dio.h +++ linux-2.6.27/ubuntu/gfs/dio.h @@ -0,0 +1,157 @@ +#ifndef __DIO_DOT_H__ +#define __DIO_DOT_H__ + +void gfs_ail_start_trans(struct gfs_sbd *sdp, struct gfs_trans *tr); +int gfs_ail_empty_trans(struct gfs_sbd *sdp, struct gfs_trans *tr); + +/* Asynchronous I/O Routines */ + +struct buffer_head *gfs_dgetblk(struct gfs_glock *gl, uint64_t blkno); +int gfs_dread(struct gfs_glock *gl, uint64_t blkno, + int flags, struct buffer_head **bhp); + +void gfs_prep_new_buffer(struct buffer_head *bh); +int gfs_dreread(struct gfs_sbd *sdp, struct buffer_head *bh, int flags); +int gfs_dwrite(struct gfs_sbd *sdp, struct buffer_head *bh, int flags); + +void gfs_attach_bufdata(struct buffer_head *bh, struct gfs_glock *gl); +int gfs_is_pinned(struct gfs_sbd *sdp, struct buffer_head *bh); +void gfs_dpin(struct gfs_sbd *sdp, struct buffer_head *bh); +void gfs_dunpin(struct gfs_sbd *sdp, struct buffer_head *bh, + struct gfs_trans *tr); + +static __inline__ +void gfs_lock_buffer(struct buffer_head *bh) +{ + struct gfs_bufdata *bd = get_v2bd(bh); + down(&bd->bd_lock); +} +static __inline__ +int gfs_trylock_buffer(struct buffer_head *bh) +{ + struct gfs_bufdata *bd = get_v2bd(bh); + return down_trylock(&bd->bd_lock); +} +static __inline__ +void gfs_unlock_buffer(struct buffer_head *bh) +{ + struct gfs_bufdata *bd = get_v2bd(bh); + up(&bd->bd_lock); +} + +void gfs_logbh_init(struct gfs_sbd *sdp, struct buffer_head *bh, uint64_t blkno, + char *data); +void gfs_logbh_uninit(struct gfs_sbd *sdp, struct buffer_head *bh); +void gfs_logbh_start(struct gfs_sbd *sdp, struct buffer_head *bh); +int gfs_logbh_wait(struct gfs_sbd *sdp, struct buffer_head *bh); + +int gfs_replay_buf(struct gfs_glock *gl, struct buffer_head *bh); +void gfs_replay_check(struct gfs_sbd *sdp); +void gfs_replay_wait(struct gfs_sbd *sdp); + +void gfs_wipe_buffers(struct gfs_inode *ip, struct gfs_rgrpd *rgd, + uint64_t bstart, uint32_t blen); + +void gfs_sync_meta(struct gfs_sbd *sdp); + +/* Buffer Caching routines */ + +int gfs_get_meta_buffer(struct gfs_inode *ip, int height, uint64_t num, int new, + struct buffer_head **bhp); +int gfs_get_data_buffer(struct gfs_inode *ip, uint64_t block, int new, + struct buffer_head **bhp); +void gfs_start_ra(struct gfs_glock *gl, uint64_t dblock, uint32_t extlen); + +static __inline__ int +gfs_get_inode_buffer(struct gfs_inode *ip, struct buffer_head **bhp) +{ + return gfs_get_meta_buffer(ip, 0, ip->i_num.no_addr, FALSE, bhp); +} + +struct inode *gfs_aspace_get(struct gfs_sbd *sdp); +void gfs_aspace_put(struct inode *aspace); + +void gfs_inval_buf(struct gfs_glock *gl); +void gfs_sync_buf(struct gfs_glock *gl, int flags); + +void gfs_flush_meta_cache(struct gfs_inode *ip); + +/* Buffer Content Functions */ + +/** + * gfs_buffer_clear - Zeros out a buffer + * @ip: The GFS inode + * @bh: The buffer to zero + * + */ + +static __inline__ void +gfs_buffer_clear(struct buffer_head *bh) +{ + memset(bh->b_data, 0, bh->b_size); +} + +/** + * gfs_buffer_clear_tail - Clear buffer beyond the dinode + * @bh: The buffer containing the on-disk inode + * @head: the size of the head of the buffer + * + * Clears the remaining part of an on-disk inode that is not a dinode. + * i.e. The data part of a stuffed inode, or the top level of metadata + * of a non-stuffed inode. + */ + +static __inline__ void +gfs_buffer_clear_tail(struct buffer_head *bh, int head) +{ + memset(bh->b_data + head, 0, bh->b_size - head); +} + +/** + * gfs_buffer_clear_ends - Zero out any bits of a buffer which are not being written + * @bh: The buffer + * @offset: Offset in buffer where write starts + * @amount: Amount of data being written + * @journaled: TRUE if this is a journaled buffer + * + */ + +static __inline__ void +gfs_buffer_clear_ends(struct buffer_head *bh, int offset, int amount, + int journaled) +{ + int z_off1 = (journaled) ? sizeof(struct gfs_meta_header) : 0; + int z_len1 = offset - z_off1; + int z_off2 = offset + amount; + int z_len2 = (bh)->b_size - z_off2; + + if (z_len1) + memset(bh->b_data + z_off1, 0, z_len1); + + if (z_len2) + memset(bh->b_data + z_off2, 0, z_len2); +} + +/** + * gfs_buffer_copy_tail - copies the tail of one buffer to another + * @to_bh: the buffer to copy to + * @to_head: the size of the head of to_bh + * @from_bh: the buffer to copy from + * @from_head: the size of the head of from_bh + * + * from_head is guaranteed to bigger than to_head + */ + +static __inline__ void +gfs_buffer_copy_tail(struct buffer_head *to_bh, int to_head, + struct buffer_head *from_bh, int from_head) +{ + memcpy(to_bh->b_data + to_head, + from_bh->b_data + from_head, + from_bh->b_size - from_head); + memset(to_bh->b_data + to_bh->b_size + to_head - from_head, + 0, + from_head - to_head); +} + +#endif /* __DIO_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/inode.c +++ linux-2.6.27/ubuntu/gfs/inode.c @@ -0,0 +1,2212 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "acl.h" +#include "bmap.h" +#include "dio.h" +#include "dir.h" +#include "eattr.h" +#include "glock.h" +#include "glops.h" +#include "inode.h" +#include "log.h" +#include "ops_address.h" +#include "ops_file.h" +#include "ops_inode.h" +#include "quota.h" +#include "rgrp.h" +#include "trans.h" +#include "unlinked.h" + +/** + * inode_attr_in - Copy attributes from the dinode into the VFS inode + * @ip: The GFS inode (with embedded disk inode data) + * @inode: The Linux VFS inode + * + */ + +static void +inode_attr_in(struct gfs_inode *ip, struct inode *inode) +{ + unsigned int mode; + + inode->i_ino = ip->i_num.no_formal_ino; + + switch (ip->i_di.di_type) { + case GFS_FILE_REG: + mode = S_IFREG; + inode->i_rdev = 0; + break; + case GFS_FILE_DIR: + mode = S_IFDIR; + inode->i_rdev = 0; + break; + case GFS_FILE_LNK: + mode = S_IFLNK; + inode->i_rdev = 0; + break; + case GFS_FILE_BLK: + mode = S_IFBLK; + inode->i_rdev = MKDEV(ip->i_di.di_major, ip->i_di.di_minor); + break; + case GFS_FILE_CHR: + mode = S_IFCHR; + inode->i_rdev = MKDEV(ip->i_di.di_major, ip->i_di.di_minor); + break; + case GFS_FILE_FIFO: + mode = S_IFIFO; + inode->i_rdev = 0; + break; + case GFS_FILE_SOCK: + mode = S_IFSOCK; + inode->i_rdev = 0; + break; + default: + if (gfs_consist_inode(ip)) + printk("GFS: fsid=%s: type = %u\n", + ip->i_sbd->sd_fsname, ip->i_di.di_type); + return; + }; + + inode->i_mode = mode | (ip->i_di.di_mode & S_IALLUGO); + inode->i_nlink = ip->i_di.di_nlink; + inode->i_uid = ip->i_di.di_uid; + inode->i_gid = ip->i_di.di_gid; + i_size_write(inode, ip->i_di.di_size); + inode->i_atime.tv_sec = ip->i_di.di_atime; + inode->i_mtime.tv_sec = ip->i_di.di_mtime; + inode->i_ctime.tv_sec = ip->i_di.di_ctime; + inode->i_atime.tv_nsec = inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = 0; + inode->i_blocks = ip->i_di.di_blocks << + (ip->i_sbd->sd_sb.sb_bsize_shift - GFS_BASIC_BLOCK_SHIFT); + inode->i_generation = ip->i_di.di_header.mh_incarn; + + if (ip->i_di.di_flags & GFS_DIF_IMMUTABLE) + inode->i_flags |= S_IMMUTABLE; + else + inode->i_flags &= ~S_IMMUTABLE; + + if (ip->i_di.di_flags & GFS_DIF_APPENDONLY) + inode->i_flags |= S_APPEND; + else + inode->i_flags &= ~S_APPEND; +} + +/** + * gfs_inode_attr_in - Copy attributes from the dinode into the VFS inode + * @ip: The GFS inode (with embedded disk inode data) + * + */ + +void +gfs_inode_attr_in(struct gfs_inode *ip) +{ + struct inode *inode; + + inode = gfs_iget(ip, NO_CREATE); + if (inode) { + inode_attr_in(ip, inode); + iput(inode); + } + +} + +/** + * gfs_inode_attr_out - Copy attributes from VFS inode into the dinode + * @ip: The GFS inode + * + * Only copy out the attributes that we want the VFS layer + * to be able to modify. + */ + +void +gfs_inode_attr_out(struct gfs_inode *ip) +{ + struct inode *inode = ip->i_vnode; + + ip->i_di.di_mode = inode->i_mode & S_IALLUGO; + ip->i_di.di_uid = inode->i_uid; + ip->i_di.di_gid = inode->i_gid; + ip->i_di.di_atime = inode->i_atime.tv_sec; + ip->i_di.di_mtime = inode->i_mtime.tv_sec; + ip->i_di.di_ctime = inode->i_ctime.tv_sec; +} + +/** + * gfs_iget - Get/Create a struct inode for a struct gfs_inode + * @ip: the struct gfs_inode to get the struct inode for + * @create: CREATE -- create a new struct inode if one does not already exist + * NO_CREATE -- return NULL if inode doesn't exist + * + * Returns: A VFS inode, or NULL if NO_CREATE and none in existance + * + * If this function creates a new inode, it: + * Copies fields from the GFS on-disk (d)inode to the VFS inode + * Attaches the appropriate ops vectors to the VFS inode and address_space + * Attaches the VFS inode to the gfs_inode + * Inserts the new inode in the VFS inode hash, while avoiding races + */ + +struct inode * +gfs_iget(struct gfs_inode *ip, int create) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct inode *inode = NULL, *tmp; + + spin_lock(&ip->i_spin); + if (ip->i_vnode) + inode = igrab(ip->i_vnode); + spin_unlock(&ip->i_spin); + + if (inode || !create) + return inode; + + tmp = new_inode(ip->i_sbd->sd_vfs); + if (!tmp) + return NULL; + + inode_attr_in(ip, tmp); + + /* Attach GFS-specific ops vectors */ + if (ip->i_di.di_type == GFS_FILE_REG) { + tmp->i_op = &gfs_file_iops; + memcpy(&ip->gfs_file_aops, &gfs_file_aops, + sizeof(struct address_space_operations)); + tmp->i_mapping->a_ops = &ip->gfs_file_aops; + if (sdp->sd_args.ar_localflocks) + tmp->i_fop = &gfs_file_fops_nolock; + else + tmp->i_fop = &gfs_file_fops; + } else if (ip->i_di.di_type == GFS_FILE_DIR) { + tmp->i_op = &gfs_dir_iops; + if (sdp->sd_args.ar_localflocks) + tmp->i_fop = &gfs_dir_fops_nolock; + else + tmp->i_fop = &gfs_dir_fops; + } else if (ip->i_di.di_type == GFS_FILE_LNK) { + tmp->i_op = &gfs_symlink_iops; + } else { + tmp->i_op = &gfs_dev_iops; + init_special_inode(tmp, tmp->i_mode, tmp->i_rdev); + } + + set_v2ip(tmp, NULL); + + /* Did another process successfully create an inode while we were + preparing this (tmp) one? If so, we can use that other one, and + trash the one we were preparing. + The other process might not be done inserting the inode in the + VFS hash table. If so, we need to wait until it is done, then + we can use it. */ + for (;;) { + spin_lock(&ip->i_spin); + if (!ip->i_vnode) + break; + inode = igrab(ip->i_vnode); + spin_unlock(&ip->i_spin); + + if (inode) { + iput(tmp); + return inode; + } + yield(); + } + + inode = tmp; + + gfs_inode_hold(ip); + ip->i_vnode = inode; + set_v2ip(inode, ip); + + spin_unlock(&ip->i_spin); + + insert_inode_hash(inode); + + return inode; +} + +/** + * gfs_copyin_dinode - Refresh the incore copy of the dinode + * @ip: The GFS inode + * + * Returns: errno + */ + +int +gfs_copyin_dinode(struct gfs_inode *ip) +{ + struct buffer_head *dibh; + int error; + + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + return error; + + if (gfs_metatype_check(ip->i_sbd, dibh, GFS_METATYPE_DI)) { + brelse(dibh); + return -EIO; + } + + gfs_dinode_in(&ip->i_di, dibh->b_data); + brelse(dibh); + + if (ip->i_num.no_formal_ino != ip->i_di.di_num.no_formal_ino) { + if (gfs_consist_inode(ip)) + gfs_dinode_print(&ip->i_di); + return -EIO; + } + + /* Handle a moved inode (not implemented yet) */ + if (ip->i_num.no_addr != ip->i_di.di_num.no_addr) { + if (gfs_consist_inode(ip)) + gfs_dinode_print(&ip->i_di); + return -EIO; + } + + ip->i_vn = ip->i_gl->gl_vn; + + return 0; +} + +/** + * inode_create - create a struct gfs_inode, acquire Inode-Open (iopen) glock, + * read dinode from disk + * @i_gl: The (already held) glock covering the inode + * @inum: The inode number + * @io_gl: the iopen glock to acquire/hold (using holder in new gfs_inode) + * @io_state: the state the iopen glock should be acquired in + * @ipp: pointer to put the returned inode in + * + * Returns: errno + */ + +static int +inode_create(struct gfs_glock *i_gl, struct gfs_inum *inum, + struct gfs_glock *io_gl, unsigned int io_state, + struct gfs_inode **ipp) +{ + struct gfs_sbd *sdp = i_gl->gl_sbd; + struct gfs_inode *ip; + int error = 0; + + RETRY_MALLOC(ip = kmem_cache_alloc(gfs_inode_cachep, GFP_KERNEL), ip); + memset(ip, 0, sizeof(struct gfs_inode)); + + ip->i_num = *inum; + + atomic_set(&ip->i_count, 1); + + ip->i_gl = i_gl; + ip->i_sbd = sdp; + + spin_lock_init(&ip->i_spin); + init_rwsem(&ip->i_rw_mutex); + + ip->i_greedy = gfs_tune_get(sdp, gt_greedy_default); + + /* Lock the iopen glock (may be recursive) */ + error = gfs_glock_nq_init(io_gl, + io_state, GL_LOCAL_EXCL | GL_EXACT, + &ip->i_iopen_gh); + if (error) + goto fail; + + ip->i_iopen_gh.gh_owner = NULL; + + /* Assign the inode's glock as this iopen glock's protected object */ + spin_lock(&io_gl->gl_spin); + gfs_glock_hold(i_gl); + set_gl2gl(io_gl, i_gl); + spin_unlock(&io_gl->gl_spin); + + /* Read dinode from disk */ + error = gfs_copyin_dinode(ip); + if (error) + goto fail_iopen; + + gfs_glock_hold(i_gl); + set_gl2ip(i_gl, ip); + + atomic_inc(&sdp->sd_inode_count); + + *ipp = ip; + + return 0; + + fail_iopen: + spin_lock(&io_gl->gl_spin); + set_gl2gl(io_gl, NULL); + gfs_glock_put(i_gl); + spin_unlock(&io_gl->gl_spin); + + gfs_glock_dq_uninit(&ip->i_iopen_gh); + + fail: + gfs_flush_meta_cache(ip); + kmem_cache_free(gfs_inode_cachep, ip); + *ipp = NULL; + + return error; +} + +/** + * gfs_inode_get - Get an inode given its number + * @i_gl: The glock covering the inode + * @inum: The inode number + * @create: Flag to say if we are allowed to create a new struct gfs_inode + * @ipp: pointer to put the returned inode in + * + * Returns: errno + * + * If creating a new gfs_inode structure, reads dinode from disk. + */ + +int +gfs_inode_get(struct gfs_glock *i_gl, struct gfs_inum *inum, int create, + struct gfs_inode **ipp) +{ + struct gfs_glock *io_gl; + int error = 0; + + *ipp = get_gl2ip(i_gl); + if (*ipp) { + atomic_inc(&(*ipp)->i_count); + gfs_assert_warn(i_gl->gl_sbd, + (*ipp)->i_num.no_formal_ino == + inum->no_formal_ino); + } else if (create) { + error = gfs_glock_get(i_gl->gl_sbd, + inum->no_addr, &gfs_iopen_glops, + CREATE, &io_gl); + if (!error) { + error = inode_create(i_gl, inum, io_gl, + LM_ST_SHARED, ipp); + gfs_glock_put(io_gl); + } + } + + return error; +} + +/** + * gfs_inode_hold - hold a struct gfs_inode structure + * @ip: The GFS inode + * + */ + +void +gfs_inode_hold(struct gfs_inode *ip) +{ + gfs_assert(ip->i_sbd, atomic_read(&ip->i_count) > 0,); + atomic_inc(&ip->i_count); +} + +/** + * gfs_inode_put - put a struct gfs_inode structure + * @ip: The GFS inode + * + */ + +void +gfs_inode_put(struct gfs_inode *ip) +{ + gfs_assert(ip->i_sbd, atomic_read(&ip->i_count) > 0,); + atomic_dec(&ip->i_count); +} + +/** + * gfs_inode_destroy - Destroy a GFS inode structure with no references on it + * @ip: The GFS inode + * + * Also, unhold the iopen glock and release indirect addressing buffers. + * This function must be called with a glocks held on the inode and + * the associated iopen. + * + */ + +void +gfs_inode_destroy(struct gfs_inode *ip) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_glock *io_gl = ip->i_iopen_gh.gh_gl; + struct gfs_glock *i_gl = ip->i_gl; + + gfs_assert_warn(sdp, !atomic_read(&ip->i_count)); + gfs_assert(sdp, get_gl2gl(io_gl) == i_gl,); + + /* Unhold the iopen glock */ + spin_lock(&io_gl->gl_spin); + set_gl2gl(io_gl, NULL); + gfs_glock_put(i_gl); + spin_unlock(&io_gl->gl_spin); + + gfs_glock_dq_uninit(&ip->i_iopen_gh); + + /* Release indirect addressing buffers, destroy the GFS inode struct */ + gfs_flush_meta_cache(ip); + kmem_cache_free(gfs_inode_cachep, ip); + + set_gl2ip(i_gl, NULL); + gfs_glock_put(i_gl); + + atomic_dec(&sdp->sd_inode_count); +} + +/** + * dinode_mark_unused - Set UNUSED flag in on-disk dinode + * @ip: + * + * Also: + * -- Increment incarnation number, to indicate that it no longer + * represents the old inode. + * -- Update change time (ctime) + * + * Returns: errno + */ + +static int +dinode_mark_unused(struct gfs_inode *ip) +{ + struct buffer_head *dibh; + struct gfs_dinode *di; + uint32_t incarn; + uint64_t ctime; + uint32_t flags; + int error; + + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + return error; + + di = (struct gfs_dinode *)dibh->b_data; + + gfs_trans_add_bh(ip->i_gl, dibh); + + incarn = gfs32_to_cpu(di->di_header.mh_incarn) + 1; + di->di_header.mh_incarn = cpu_to_gfs32(incarn); + + ctime = get_seconds(); + di->di_ctime = cpu_to_gfs64(ctime); + + flags = (gfs32_to_cpu(di->di_flags)) | GFS_DIF_UNUSED; + di->di_flags = cpu_to_gfs32(flags); + + brelse(dibh); + + return 0; +} + +/** + * dinode_dealloc - Put deallocate a dinode + * @ip: The GFS inode + * + * Returns: errno + */ + +static int +dinode_dealloc(struct gfs_inode *ip) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_alloc *al; + struct gfs_rgrpd *rgd; + int error; + + if (ip->i_di.di_blocks != 1) { + if (gfs_consist_inode(ip)) + gfs_dinode_print(&ip->i_di); + return -EIO; + } + + al = gfs_alloc_get(ip); + + error = gfs_quota_hold_m(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out; + + error = gfs_rindex_hold(sdp, &al->al_ri_gh); + if (error) + goto out_qs; + + rgd = gfs_blk2rgrpd(sdp, ip->i_num.no_addr); + if (!rgd) { + gfs_consist_inode(ip); + error = -EIO; + goto out_rindex_relse; + } + + error = gfs_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &al->al_rgd_gh); + if (error) + goto out_rindex_relse; + + /* Trans may require: + One block for the RG header. + One block for the dinode bit. + One block for the dinode. + We also need a block for the unlinked change. + One block for the quota change. */ + + error = gfs_trans_begin(sdp, 3, 2); + if (error) + goto out_rg_gunlock; + + /* Set the UNUSED flag in the on-disk dinode block, increment incarn */ + error = dinode_mark_unused(ip); + if (error) + goto out_end_trans; + + /* De-allocate on-disk dinode block to FREEMETA */ + gfs_difree(rgd, ip); + + gfs_trans_add_unlinked(sdp, GFS_LOG_DESC_IDA, &ip->i_num); + clear_bit(GLF_STICKY, &ip->i_gl->gl_flags); + + out_end_trans: + gfs_trans_end(sdp); + + out_rg_gunlock: + gfs_glock_dq_uninit(&al->al_rgd_gh); + + out_rindex_relse: + gfs_glock_dq_uninit(&al->al_ri_gh); + + out_qs: + gfs_quota_unhold_m(ip); + + out: + gfs_alloc_put(ip); + + return error; +} + +/** + * inode_dealloc - Deallocate all on-disk blocks for an inode (dinode) + * @sdp: the filesystem + * @inum: the inode number to deallocate + * @io_gh: a holder for the iopen glock for this inode + * + * De-allocates all on-disk blocks, data and metadata, associated with an inode. + * All metadata blocks become GFS_BLKST_FREEMETA. + * All data blocks become GFS_BLKST_FREE. + * Also de-allocates incore gfs_inode structure. + * + * Returns: errno + */ + +static int +inode_dealloc(struct gfs_sbd *sdp, struct gfs_inum *inum, + struct gfs_holder *io_gh) +{ + struct gfs_inode *ip; + struct gfs_holder i_gh; + int error; + + /* Lock the inode as we blow it away */ + error = gfs_glock_nq_num(sdp, + inum->no_formal_ino, &gfs_inode_glops, + LM_ST_EXCLUSIVE, 0, &i_gh); + if (error) + return error; + + /* We reacquire the iopen lock here to avoid a race with the NFS server + calling gfs_read_inode() with the inode number of a inode we're in + the process of deallocating. And we can't keep our hold on the lock + from inode_dealloc_init() for deadlock reasons. We do, however, + overlap this iopen lock with the one to be acquired EX within + inode_create(), below (recursive EX locks will be granted to same + holder process, i.e. this process). */ + + gfs_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY, io_gh); + error = gfs_glock_nq(io_gh); + switch (error) { + case 0: + break; + case GLR_TRYFAILED: + error = 0; + goto fail; + default: + goto fail; + } + + gfs_assert_warn(sdp, !get_gl2ip(i_gh.gh_gl)); + error = inode_create(i_gh.gh_gl, inum, io_gh->gh_gl, LM_ST_EXCLUSIVE, + &ip); + + gfs_glock_dq(io_gh); + + if (error) + goto fail; + + /* Verify disk (d)inode, gfs inode, and VFS (v)inode are unused */ + if (ip->i_di.di_nlink) { + if (gfs_consist_inode(ip)) + gfs_dinode_print(&ip->i_di); + error = -EIO; + goto fail_iput; + } + gfs_assert_warn(sdp, atomic_read(&ip->i_count) == 1); + gfs_assert_warn(sdp, !ip->i_vnode); + + /* Free all on-disk directory leaves (if any) to FREEMETA state */ + if (ip->i_di.di_type == GFS_FILE_DIR && + (ip->i_di.di_flags & GFS_DIF_EXHASH)) { + error = gfs_dir_exhash_free(ip); + if (error) + goto fail_iput; + } + + /* Free all on-disk extended attribute blocks to FREEMETA state */ + if (ip->i_di.di_eattr) { + error = gfs_ea_dealloc(ip); + if (error) + goto fail_iput; + } + + /* Free all data blocks to FREE state, and meta blocks to FREEMETA */ + error = gfs_shrink(ip, 0, NULL); + if (error) + goto fail_iput; + + /* Set UNUSED flag and increment incarn # in on-disk dinode block, + and de-alloc the block to FREEMETA */ + error = dinode_dealloc(ip); + if (error) + goto fail_iput; + + /* Free the GFS inode structure, unhold iopen and inode glocks */ + gfs_inode_put(ip); + gfs_inode_destroy(ip); + + gfs_glock_dq_uninit(&i_gh); + + return 0; + + fail_iput: + gfs_inode_put(ip); + gfs_inode_destroy(ip); + + fail: + gfs_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * inode_dealloc_init - Try to deallocate an initialized on-disk inode (dinode) + * and all of its associated data and meta blocks + * @sdp: the filesystem + * + * Returns: 0 on success, -errno on error, 1 on busy (inode open) + */ + +static int +inode_dealloc_init(struct gfs_sbd *sdp, struct gfs_inum *inum) +{ + struct gfs_holder io_gh; + int error = 0; + + /* If not busy (on this node), de-alloc GFS incore inode, releasing + any indirect addressing buffers, and unholding iopen glock */ + gfs_try_toss_inode(sdp, inum); + + /* Does another process (cluster-wide) have this inode open? */ + error = gfs_glock_nq_num(sdp, + inum->no_addr, &gfs_iopen_glops, + LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB, &io_gh); + switch (error) { + case 0: + break; + case GLR_TRYFAILED: + return 1; + default: + return error; + } + + /* Unlock here to prevent deadlock */ + gfs_glock_dq(&io_gh); + + /* No other process in the entire cluster has this inode open; + we can remove it and all of its associated blocks from disk */ + error = inode_dealloc(sdp, inum, &io_gh); + gfs_holder_uninit(&io_gh); + + return error; +} + +/** + * inode_dealloc_uninit - dealloc an uninitialized on-disk inode (dinode) block + * @sdp: the filesystem + * + * Create a transaction to change dinode block's alloc state to FREEMETA + * + * Returns: 0 on success, -errno on error, 1 on busy + */ + +static int +inode_dealloc_uninit(struct gfs_sbd *sdp, struct gfs_inum *inum) +{ + struct gfs_rgrpd *rgd; + struct gfs_holder ri_gh, rgd_gh; + int error; + + error = gfs_rindex_hold(sdp, &ri_gh); + if (error) + return error; + + rgd = gfs_blk2rgrpd(sdp, inum->no_addr); + if (!rgd) { + gfs_consist(sdp); + error = -EIO; + goto fail; + } + + error = gfs_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rgd_gh); + if (error) + goto fail; + + /* Trans may require: + One block for the RG header. + One block for the dinode bit. + We also need a block for the unlinked change. */ + + error = gfs_trans_begin(sdp, 2, 1); + if (error) + goto fail_gunlock; + + gfs_difree_uninit(rgd, inum->no_addr); + gfs_trans_add_unlinked(sdp, GFS_LOG_DESC_IDA, inum); + + gfs_trans_end(sdp); + + gfs_glock_dq_uninit(&rgd_gh); + gfs_glock_dq_uninit(&ri_gh); + + return 0; + + fail_gunlock: + gfs_glock_dq_uninit(&rgd_gh); + + fail: + gfs_glock_dq_uninit(&ri_gh); + + return error; +} + +/** + * gfs_inode_dealloc - Grab an unlinked inode off the list and try to free it. + * @sdp: the filesystem + * + * Returns: 0 on success, -errno on error, 1 on busy + */ + +int +gfs_inode_dealloc(struct gfs_sbd *sdp, struct gfs_inum *inum) +{ + if (inum->no_formal_ino) + return inode_dealloc_init(sdp, inum); + else + return inode_dealloc_uninit(sdp, inum); +} + +/** + * gfs_change_nlink - Change nlink count on inode + * @ip: The GFS inode + * @diff: The change in the nlink count required + * + * Returns: errno + */ + +int +gfs_change_nlink(struct gfs_inode *ip, int diff) +{ + struct buffer_head *dibh; + uint32_t nlink; + int error; + + nlink = ip->i_di.di_nlink + diff; + + /* Tricky. If we are reducing the nlink count, + but the new value ends up being bigger than the + old one, we must have underflowed. */ + if (diff < 0 && nlink > ip->i_di.di_nlink) { + if (gfs_consist_inode(ip)) + gfs_dinode_print(&ip->i_di); + return -EIO; + } + + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + return error; + + ip->i_di.di_nlink = nlink; + ip->i_di.di_ctime = get_seconds(); + + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + + return 0; +} + +/** + * gfs_lookupi - Look up a filename in a directory and return its inode + * @d_gh: An initialized holder for the directory glock + * @name: The name of the inode to look for + * @is_root: If TRUE, ignore the caller's permissions + * @i_gh: An uninitialized holder for the new inode glock + * + * There will always be a vnode (Linux VFS inode) for the d_gh inode unless + * @is_root is true. + * + * Returns: errno + */ + +int +gfs_lookupi(struct gfs_holder *d_gh, struct qstr *name, + int is_root, struct gfs_holder *i_gh) +{ + struct gfs_inode *dip = get_gl2ip(d_gh->gh_gl); + struct gfs_sbd *sdp = dip->i_sbd; + struct gfs_glock *gl; + struct gfs_inode *ip; + struct gfs_inum inum, inum2; + unsigned int type; + int error; + + i_gh->gh_gl = NULL; + + if (!name->len || name->len > GFS_FNAMESIZE) + return -ENAMETOOLONG; + + if (gfs_filecmp(name, ".", 1) || + (gfs_filecmp(name, "..", 2) && dip == sdp->sd_rooti)) { + gfs_holder_reinit(LM_ST_SHARED, 0, d_gh); + error = gfs_glock_nq(d_gh); + if (!error) { + error = gfs_glock_nq_init(dip->i_gl, + LM_ST_SHARED, 0, + i_gh); + if (error) { + gfs_glock_dq(d_gh); + return error; + } + gfs_inode_hold(dip); + } + return error; + } + + if (gfs_assert_warn(sdp, !gfs_glock_is_locked_by_me(d_gh->gh_gl))) + return -EINVAL; + + gfs_holder_reinit(LM_ST_SHARED, 0, d_gh); + error = gfs_glock_nq(d_gh); + if (error) + return error; + + if (!is_root) { + error = inode_permission(dip->i_vnode, MAY_EXEC); + if (error) { + gfs_glock_dq(d_gh); + return error; + } + } + + error = gfs_dir_search(dip, name, &inum, &type); + if (error) { + gfs_glock_dq(d_gh); + if (error == -ENOENT) + error = 0; + return error; + } + + restart: + error = gfs_glock_get(sdp, inum.no_formal_ino, &gfs_inode_glops, + CREATE, &gl); + if (error) { + gfs_glock_dq(d_gh); + return error; + } + + /* Acquire the second lock */ + + if (gl->gl_name.ln_number < dip->i_gl->gl_name.ln_number) { + gfs_glock_dq(d_gh); + + error = gfs_glock_nq_init(gl, LM_ST_SHARED, + LM_FLAG_ANY | GL_LOCAL_EXCL, + i_gh); + if (error) + goto out; + + gfs_holder_reinit(LM_ST_SHARED, 0, d_gh); + error = gfs_glock_nq(d_gh); + if (error) { + gfs_glock_dq_uninit(i_gh); + goto out; + } + + if (!is_root) { + error = inode_permission(dip->i_vnode, MAY_EXEC); + if (error) { + gfs_glock_dq(d_gh); + gfs_glock_dq_uninit(i_gh); + goto out; + } + } + + error = gfs_dir_search(dip, name, &inum2, &type); + if (error) { + gfs_glock_dq(d_gh); + gfs_glock_dq_uninit(i_gh); + if (error == -ENOENT) + error = 0; + goto out; + } + + if (!gfs_inum_equal(&inum, &inum2)) { + gfs_glock_dq_uninit(i_gh); + gfs_glock_put(gl); + inum = inum2; + goto restart; + } + } else { + error = gfs_glock_nq_init(gl, LM_ST_SHARED, + LM_FLAG_ANY | GL_LOCAL_EXCL, + i_gh); + if (error) { + gfs_glock_dq(d_gh); + goto out; + } + } + + error = gfs_inode_get(gl, &inum, CREATE, &ip); + if (error) { + gfs_glock_dq(d_gh); + gfs_glock_dq_uninit(i_gh); + } else if (ip->i_di.di_type != type) { + gfs_consist_inode(dip); + gfs_inode_put(ip); + gfs_glock_dq(d_gh); + gfs_glock_dq_uninit(i_gh); + error = -EIO; + } + + out: + gfs_glock_put(gl); + + return error; +} + +/** + * create_ok - OK to create a new on-disk inode here? + * @dip: Directory in which dinode is to be created + * @name: Name of new dinode + * @type: GFS_FILE_XXX (regular file, dir, etc.) + * + * Returns: errno + */ + +static int +create_ok(struct gfs_inode *dip, struct qstr *name, unsigned int type) +{ + int error; + + error = inode_permission(dip->i_vnode, MAY_WRITE | MAY_EXEC); + if (error) + return error; + + /* Don't create entries in an unlinked directory */ + + if (!dip->i_di.di_nlink) + return -EPERM; + + error = gfs_dir_search(dip, name, NULL, NULL); + switch (error) { + case -ENOENT: + error = 0; + break; + case 0: + return -EEXIST; + default: + return error; + } + + if (dip->i_di.di_entries == (uint32_t)-1) + return -EFBIG; + if (type == GFS_FILE_DIR && dip->i_di.di_nlink == (uint32_t)-1) + return -EMLINK; + + return 0; +} + +/** + * dinode_alloc - Create an on-disk inode + * @dip: Directory in which to create the dinode + * @ul: + * + * Since this dinode is not yet linked, we also create an unlinked inode + * descriptor. + * + * Returns: errno + */ + +static int +dinode_alloc(struct gfs_inode *dip, struct gfs_unlinked **ul) +{ + struct gfs_sbd *sdp = dip->i_sbd; + struct gfs_alloc *al; + struct gfs_inum inum; + int error; + + /* Create in-place allocation structure, reserve 1 dinode */ + al = gfs_alloc_get(dip); + al->al_requested_di = 1; + error = gfs_inplace_reserve(dip); + if (error) + goto out; + + error = gfs_trans_begin(sdp, al->al_rgd->rd_ri.ri_length, 1); + if (error) + goto out_inplace; + + inum.no_formal_ino = 0; + error = gfs_dialloc(dip, &inum.no_addr); + if (error) + goto out_end_trans; + + *ul = gfs_trans_add_unlinked(sdp, GFS_LOG_DESC_IUL, &inum); + gfs_unlinked_lock(sdp, *ul); + + gfs_trans_add_gl(dip->i_gl); + + out_end_trans: + gfs_trans_end(sdp); + + out_inplace: + gfs_inplace_release(dip); + + out: + gfs_alloc_put(dip); + + return error; +} + +/** + * pick_formal_ino - Pick a formal inode number for a given inode + * @sdp: the filesystem + * @inum: the inode number structure + * + */ + +static void +pick_formal_ino(struct gfs_sbd *sdp, struct gfs_inum *inum) +{ + /* This won't always be true */ + inum->no_formal_ino = inum->no_addr; +} + +/** + * make_dinode - Fill in a new dinode structure + * @dip: the directory this inode is being created in + * @gl: The glock covering the new inode + * @inum: the inode number + * @type: the file type + * @mode: the file permissions + * @uid: + * @gid: + * + */ + +static int +make_dinode(struct gfs_inode *dip, + struct gfs_glock *gl, struct gfs_inum *inum, + unsigned int type, unsigned int mode, + unsigned int uid, unsigned int gid) +{ + struct gfs_sbd *sdp = dip->i_sbd; + struct gfs_dinode di; + struct buffer_head *dibh; + struct gfs_rgrpd *rgd; + int error; + + error = gfs_dread(gl, inum->no_addr, + DIO_NEW | DIO_START | DIO_WAIT, + &dibh); + if (error) + return error; + + gfs_trans_add_bh(gl, dibh); + gfs_metatype_set(dibh, GFS_METATYPE_DI, GFS_FORMAT_DI); + gfs_buffer_clear_tail(dibh, sizeof(struct gfs_dinode)); + + memset(&di, 0, sizeof(struct gfs_dinode)); + + gfs_meta_header_in(&di.di_header, dibh->b_data); + + di.di_num = *inum; + + di.di_mode = mode & S_IALLUGO; + di.di_uid = uid; + di.di_gid = gid; + di.di_nlink = 1; + di.di_blocks = 1; + di.di_atime = di.di_mtime = di.di_ctime = get_seconds(); + + rgd = gfs_blk2rgrpd(sdp, inum->no_addr); + if (!rgd) { + if (gfs_consist(sdp)) + printk("GFS: fsid=%s: block = %"PRIu64"\n", + sdp->sd_fsname, inum->no_addr); + brelse(dibh); + return -EIO; + } + + di.di_rgrp = rgd->rd_ri.ri_addr; + di.di_goal_rgrp = di.di_rgrp; + di.di_goal_dblk = di.di_goal_mblk = inum->no_addr - rgd->rd_ri.ri_data1; + + if (type == GFS_FILE_REG) { + if ((dip->i_di.di_flags & GFS_DIF_INHERIT_JDATA) || + gfs_tune_get(sdp, gt_new_files_jdata)) + di.di_flags |= GFS_DIF_JDATA; + if ((dip->i_di.di_flags & GFS_DIF_INHERIT_DIRECTIO) || + gfs_tune_get(sdp, gt_new_files_directio)) + di.di_flags |= GFS_DIF_DIRECTIO; + } else if (type == GFS_FILE_DIR) { + di.di_flags |= (dip->i_di.di_flags & GFS_DIF_INHERIT_DIRECTIO); + di.di_flags |= (dip->i_di.di_flags & GFS_DIF_INHERIT_JDATA); + } + + di.di_type = type; + + gfs_dinode_out(&di, dibh->b_data); + brelse(dibh); + + return 0; +} + +/** + * inode_init_and_link - + * @dip: + * @name: + * @inum: + * @gl: + * @type: + * @mode: + * + * Returns: errno + */ + +static int +inode_init_and_link(struct gfs_inode *dip, struct qstr *name, + struct gfs_inum *inum, struct gfs_glock *gl, + unsigned int type, mode_t mode) +{ + struct gfs_sbd *sdp = dip->i_sbd; + struct gfs_alloc *al; + struct gfs_inode *ip; + unsigned int uid, gid; + int alloc_required; + void *acl_a_data = NULL, *acl_d_data = NULL; + unsigned int acl_size = 0, acl_blocks = 0; + int error; + + if (sdp->sd_args.ar_suiddir && + (dip->i_di.di_mode & S_ISUID) && + dip->i_di.di_uid) { + if (type == GFS_FILE_DIR) + mode |= S_ISUID; + else if (dip->i_di.di_uid != current->fsuid) + mode &= ~07111; + uid = dip->i_di.di_uid; + } else + uid = current->fsuid; + + if (dip->i_di.di_mode & S_ISGID) { + if (type == GFS_FILE_DIR) + mode |= S_ISGID; + gid = dip->i_di.di_gid; + } else + gid = current->fsgid; + + error = gfs_acl_new_prep(dip, type, &mode, + &acl_a_data, &acl_d_data, + &acl_size, &acl_blocks); + if (error) + return error; + + al = gfs_alloc_get(dip); + + error = gfs_quota_lock_m(dip, uid, gid); + if (error) + goto fail; + + error = gfs_quota_check(dip, uid, gid); + if (error) + goto fail_gunlock_q; + + if (acl_blocks) + alloc_required = TRUE; + else { + error = gfs_diradd_alloc_required(dip, name, &alloc_required); + if (error) + goto fail_gunlock_q; + } + + if (alloc_required) { + error = gfs_quota_check(dip, dip->i_di.di_uid, dip->i_di.di_gid); + if (error) + goto fail_gunlock_q; + + al->al_requested_meta = sdp->sd_max_dirres + acl_blocks; + + error = gfs_inplace_reserve(dip); + if (error) + goto fail_gunlock_q; + + /* Trans may require: + blocks for two dinodes, the directory blocks necessary for + a new entry, RG bitmap blocks for an allocation, + and one block for a quota change and + one block for an unlinked tag. */ + + error = gfs_trans_begin(sdp, + 2 + sdp->sd_max_dirres + acl_blocks + + al->al_rgd->rd_ri.ri_length, 2); + if (error) + goto fail_inplace; + } else { + error = gfs_rindex_hold(sdp, &al->al_ri_gh); + if (error) + goto fail_gunlock_q; + + /* Trans may require: + blocks for two dinodes, a leaf block, + and one block for a quota change and + one block for an unlinked tag. */ + + error = gfs_trans_begin(sdp, 3, 2); + if (error) + goto fail_inplace; + } + + error = gfs_dir_add(dip, name, inum, type); + if (error) + goto fail_end_trans; + + error = make_dinode(dip, gl, inum, type, mode, uid, gid); + if (error) + goto fail_end_trans; + + al->al_ul = gfs_trans_add_unlinked(sdp, GFS_LOG_DESC_IDA, + &(struct gfs_inum){0, inum->no_addr}); + gfs_trans_add_quota(sdp, +1, uid, gid); + + error = gfs_inode_get(gl, inum, CREATE, &ip); + + /* This should only fail if we are already shutdown. */ + if (gfs_assert_withdraw(sdp, !error)) + goto fail_end_trans; + + if (acl_blocks) + error = gfs_acl_new_init(dip, ip, + acl_a_data, acl_d_data, + acl_size); + + if (!alloc_required) + gfs_glock_dq_uninit(&al->al_ri_gh); + + return error; + + fail_end_trans: + gfs_trans_end(sdp); + + fail_inplace: + if (alloc_required) + gfs_inplace_release(dip); + else + gfs_glock_dq_uninit(&al->al_ri_gh); + + fail_gunlock_q: + gfs_quota_unlock_m(dip); + + fail: + gfs_alloc_put(dip); + if (acl_a_data) + kfree(acl_a_data); + else if (acl_d_data) + kfree(acl_d_data); + + return error; +} + +/** + * gfs_createi - Create a new inode + * @d_gh: An initialized holder for the directory glock + * @name: The name of the new file + * @type: The type of dinode (GFS_FILE_REG, GFS_FILE_DIR, GFS_FILE_LNK, ...) + * @mode: the permissions on the new inode + * @i_gh: An uninitialized holder for the new inode glock + * + * If the return value is 0, the glocks on both the directory and the new + * file are held. A transaction has been started and an inplace reservation + * is held, as well. + * + * Returns: errno + */ + +int +gfs_createi(struct gfs_holder *d_gh, struct qstr *name, + unsigned int type, unsigned int mode, + struct gfs_holder *i_gh) +{ + struct gfs_inode *dip = get_gl2ip(d_gh->gh_gl); + struct gfs_sbd *sdp = dip->i_sbd; + struct gfs_unlinked *ul; + struct gfs_inum inum; + struct gfs_holder io_gh; + int error; + + if (!name->len || name->len > GFS_FNAMESIZE) + return -ENAMETOOLONG; + + gfs_holder_reinit(LM_ST_EXCLUSIVE, 0, d_gh); + error = gfs_glock_nq(d_gh); + if (error) + return error; + + error = create_ok(dip, name, type); + if (error) + goto fail; + + error = dinode_alloc(dip, &ul); + if (error) + goto fail; + + inum.no_addr = ul->ul_inum.no_addr; + pick_formal_ino(sdp, &inum); + + if (inum.no_formal_ino < dip->i_num.no_formal_ino) { + gfs_glock_dq(d_gh); + + error = gfs_glock_nq_num(sdp, + inum.no_formal_ino, &gfs_inode_glops, + LM_ST_EXCLUSIVE, GL_SKIP, i_gh); + if (error) { + gfs_unlinked_unlock(sdp, ul); + return error; + } + + gfs_holder_reinit(LM_ST_EXCLUSIVE, 0, d_gh); + error = gfs_glock_nq(d_gh); + if (error) { + gfs_glock_dq_uninit(i_gh); + gfs_unlinked_unlock(sdp, ul); + return error; + } + + error = create_ok(dip, name, type); + if (error) + goto fail_gunlock_i; + } else { + error = gfs_glock_nq_num(sdp, + inum.no_formal_ino, &gfs_inode_glops, + LM_ST_EXCLUSIVE, GL_SKIP, i_gh); + if (error) + goto fail_ul; + } + + error = gfs_glock_nq_num(sdp, + inum.no_addr, &gfs_iopen_glops, + LM_ST_SHARED, GL_LOCAL_EXCL | GL_EXACT, + &io_gh); + if (error) + goto fail_gunlock_i; + + error = inode_init_and_link(dip, name, &inum, i_gh->gh_gl, type, mode); + if (error) + goto fail_gunlock_io; + + gfs_glock_dq_uninit(&io_gh); + + return 0; + + fail_gunlock_io: + gfs_glock_dq_uninit(&io_gh); + + fail_gunlock_i: + gfs_glock_dq_uninit(i_gh); + + fail_ul: + gfs_unlinked_unlock(sdp, ul); + + fail: + gfs_glock_dq(d_gh); + + return error; +} + +/** + * gfs_unlinki - Unlink a file + * @dip: The inode of the directory + * @name: The name of the file to be unlinked + * @ip: The inode of the file to be removed + * + * Assumes Glocks on both dip and ip are held. + * + * Returns: errno + */ + +int +gfs_unlinki(struct gfs_inode *dip, struct qstr *name, struct gfs_inode *ip) +{ + struct gfs_sbd *sdp = dip->i_sbd; + int error; + + error = gfs_dir_del(dip, name); + if (error) + return error; + + error = gfs_change_nlink(ip, -1); + if (error) + return error; + + /* If this inode is being unlinked from the directory structure, + we need to mark that in the log so that it isn't lost during + a crash. */ + + if (!ip->i_di.di_nlink) { + gfs_trans_add_unlinked(sdp, GFS_LOG_DESC_IUL, &ip->i_num); + set_bit(GLF_STICKY, &ip->i_gl->gl_flags); + } + + return 0; +} + +/** + * gfs_rmdiri - Remove a directory + * @dip: The parent directory of the directory to be removed + * @name: The name of the directory to be removed + * @ip: The GFS inode of the directory to be removed + * + * Assumes Glocks on dip and ip are held + * + * Returns: errno + */ + +int +gfs_rmdiri(struct gfs_inode *dip, struct qstr *name, struct gfs_inode *ip) +{ + struct gfs_sbd *sdp = dip->i_sbd; + struct qstr dotname; + int error; + + if (ip->i_di.di_entries != 2) { + if (gfs_consist_inode(ip)) + gfs_dinode_print(&ip->i_di); + return -EIO; + } + + error = gfs_dir_del(dip, name); + if (error) + return error; + + error = gfs_change_nlink(dip, -1); + if (error) + return error; + + dotname.len = 1; + dotname.name = "."; + error = gfs_dir_del(ip, &dotname); + if (error) + return error; + + dotname.len = 2; + dotname.name = ".."; + error = gfs_dir_del(ip, &dotname); + if (error) + return error; + + error = gfs_change_nlink(ip, -2); + if (error) + return error; + + /* This inode is being unlinked from the directory structure and + we need to mark that in the log so that it isn't lost during + a crash. */ + + gfs_trans_add_unlinked(sdp, GFS_LOG_DESC_IUL, &ip->i_num); + set_bit(GLF_STICKY, &ip->i_gl->gl_flags); + + return 0; +} + +/* + * gfs_unlink_ok - check to see that a inode is still in a directory + * @dip: the directory + * @name: the name of the file + * @ip: the inode + * + * Assumes that the lock on (at least) @dip is held. + * + * Returns: 0 if the parent/child relationship is correct, errno if it isn't + */ + +int +gfs_unlink_ok(struct gfs_inode *dip, struct qstr *name, struct gfs_inode *ip) +{ + struct gfs_inum inum; + unsigned int type; + int error; + + if (IS_IMMUTABLE(ip->i_vnode) || IS_APPEND(ip->i_vnode)) + return -EPERM; + + if ((dip->i_di.di_mode & S_ISVTX) && + dip->i_di.di_uid != current->fsuid && + ip->i_di.di_uid != current->fsuid && + !capable(CAP_FOWNER)) + return -EPERM; + + if (IS_APPEND(dip->i_vnode)) + return -EPERM; + + error = inode_permission(dip->i_vnode, MAY_WRITE | MAY_EXEC); + if (error) + return error; + + error = gfs_dir_search(dip, name, &inum, &type); + if (error) + return error; + + if (inum.no_formal_ino != ip->i_num.no_formal_ino) + return -ENOENT; + + if (ip->i_di.di_type != type) { + gfs_consist_inode(dip); + return -EIO; + } + + return 0; +} + +/* + * gfs_ok_to_move - check if it's ok to move a directory to another directory + * @this: move this + * @to: to here + * + * Follow @to back to the root and make sure we don't encounter @this + * Assumes we already hold the rename lock. + * + * Returns: errno + */ + +int +gfs_ok_to_move(struct gfs_inode *this, struct gfs_inode *to) +{ + struct gfs_sbd *sdp = this->i_sbd; + struct gfs_inode *tmp; + struct gfs_holder to_gh, tmp_gh; + struct qstr dotdot; + int error = 0; + + memset(&dotdot, 0, sizeof (struct qstr)); + dotdot.name = ".."; + dotdot.len = 2; + + gfs_inode_hold(to); + + for (;;) { + if (to == this) { + error = -EINVAL; + break; + } + if (to == sdp->sd_rooti) { + error = 0; + break; + } + + gfs_holder_init(to->i_gl, 0, 0, &to_gh); + + error = gfs_lookupi(&to_gh, &dotdot, TRUE, &tmp_gh); + if (error) { + gfs_holder_uninit(&to_gh); + break; + } + if (!tmp_gh.gh_gl) { + gfs_holder_uninit(&to_gh); + error = -ENOENT; + break; + } + + tmp = get_gl2ip(tmp_gh.gh_gl); + + gfs_glock_dq_uninit(&to_gh); + gfs_glock_dq_uninit(&tmp_gh); + + gfs_inode_put(to); + to = tmp; + } + + gfs_inode_put(to); + + return error; +} + +/** + * gfs_readlinki - return the contents of a symlink + * @ip: the symlink's inode + * @buf: a pointer to the buffer to be filled + * @len: a pointer to the length of @buf + * + * If @buf is too small, a piece of memory is kmalloc()ed and needs + * to be freed by the caller. + * + * Returns: errno + */ + +int +gfs_readlinki(struct gfs_inode *ip, char **buf, unsigned int *len) +{ + struct gfs_holder i_gh; + struct buffer_head *dibh; + unsigned int x; + int error; + + gfs_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &i_gh); + error = gfs_glock_nq_atime(&i_gh); + if (error) { + gfs_holder_uninit(&i_gh); + return error; + } + + if (!ip->i_di.di_size) { + gfs_consist_inode(ip); + error = -EIO; + goto out; + } + + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + goto out; + + x = ip->i_di.di_size + 1; + if (x > *len) { + *buf = kmalloc(x, GFP_KERNEL); + if (!*buf) { + error = -ENOMEM; + goto out_brelse; + } + } + + memcpy(*buf, dibh->b_data + sizeof(struct gfs_dinode), x); + *len = x; + + out_brelse: + brelse(dibh); + + out: + gfs_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * gfs_glock_nq_atime - Acquire a hold on an inode's glock, and + * conditionally update the inode's atime + * @gh: the holder to acquire + * + * Tests atime (access time) for gfs_read, gfs_readdir and gfs_mmap + * Update if the difference between the current time and the inode's current + * atime is greater than an interval specified at mount (or default). + * + * Will not update if GFS mounted NOATIME (this is *the* place where NOATIME + * has an effect) or Read-Only. + * + * Returns: errno + */ + +int +gfs_glock_nq_atime(struct gfs_holder *gh) +{ + struct gfs_glock *gl = gh->gh_gl; + struct gfs_sbd *sdp = gl->gl_sbd; + struct gfs_inode *ip = get_gl2ip(gl); + int64_t curtime, quantum = gfs_tune_get(sdp, gt_atime_quantum); + unsigned int state; + int flags; + int error; + + if (gfs_assert_warn(sdp, gh->gh_flags & GL_ATIME) || + gfs_assert_warn(sdp, !(gh->gh_flags & GL_ASYNC)) || + gfs_assert_warn(sdp, gl->gl_ops == &gfs_inode_glops)) + return -EINVAL; + + /* Save original request state of lock holder */ + state = gh->gh_state; + flags = gh->gh_flags; + + error = gfs_glock_nq(gh); + if (error) + return error; + + if (test_bit(SDF_NOATIME, &sdp->sd_flags) || + test_bit(SDF_ROFS, &sdp->sd_flags)) + return 0; + + curtime = get_seconds(); + if (curtime - ip->i_di.di_atime >= quantum) { + /* Get EX hold (force EX glock via !ANY) to write the dinode */ + gfs_glock_dq(gh); + gfs_holder_reinit(LM_ST_EXCLUSIVE, + gh->gh_flags & ~LM_FLAG_ANY, + gh); + error = gfs_glock_nq(gh); + if (error) + return error; + + /* Verify that atime hasn't been updated while we were + trying to get exclusive lock. */ + + curtime = get_seconds(); + if (curtime - ip->i_di.di_atime >= quantum) { + struct buffer_head *dibh; + + error = gfs_trans_begin(sdp, 1, 0); + if (error == -EROFS) + return 0; + if (error) + goto fail; + + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + goto fail_end_trans; + + ip->i_di.di_atime = curtime; + + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + + gfs_trans_end(sdp); + } + + /* If someone else has asked for the glock, + unlock and let them have it. Then reacquire + in the original state. */ + if (gfs_glock_is_blocking(gl)) { + gfs_glock_dq(gh); + gfs_holder_reinit(state, flags, gh); + return gfs_glock_nq(gh); + } + } + + return 0; + + fail_end_trans: + gfs_trans_end(sdp); + + fail: + gfs_glock_dq(gh); + + return error; +} + +/** + * glock_compare_atime - Compare two struct gfs_glock structures for gfs_sort() + * @arg_a: the first structure + * @arg_b: the second structure + * + * Sort order determined by (in order of priority): + * -- lock number + * -- lock state (SHARED > EXCLUSIVE or GL_ATIME, which can demand EXCLUSIVE) + * + * Returns: 1 if A > B + * -1 if A < B + * 0 if A = B + */ + +static int +glock_compare_atime(const void *arg_a, const void *arg_b) +{ + struct gfs_holder *gh_a = *(struct gfs_holder **)arg_a; + struct gfs_holder *gh_b = *(struct gfs_holder **)arg_b; + struct lm_lockname *a = &gh_a->gh_gl->gl_name; + struct lm_lockname *b = &gh_b->gh_gl->gl_name; + int ret = 0; + + if (a->ln_number > b->ln_number) + ret = 1; + else if (a->ln_number < b->ln_number) + ret = -1; + else { + if (gh_a->gh_state == LM_ST_SHARED && + gh_b->gh_state == LM_ST_EXCLUSIVE) + ret = 1; + else if (gh_a->gh_state == LM_ST_SHARED && + (gh_b->gh_flags & GL_ATIME)) + ret = 1; + } + + return ret; +} + +/** + * gfs_glock_nq_m_atime - acquire multiple glocks where one may need an + * atime update + * @num_gh: the number of structures + * @ghs: an array of struct gfs_holder structures + * + * Returns: 0 on success (all glocks acquired), + * errno on failure (no glocks acquired) + */ + +int +gfs_glock_nq_m_atime(unsigned int num_gh, struct gfs_holder *ghs) +{ + struct gfs_holder **p; + unsigned int x; + int error = 0; + + if (!num_gh) + return 0; + + if (num_gh == 1) { + ghs->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC); + if (ghs->gh_flags & GL_ATIME) + error = gfs_glock_nq_atime(ghs); + else + error = gfs_glock_nq(ghs); + return error; + } + + p = kmalloc(num_gh * sizeof(struct gfs_holder *), GFP_KERNEL); + if (!p) + return -ENOMEM; + + for (x = 0; x < num_gh; x++) + p[x] = &ghs[x]; + + gfs_sort(p, num_gh, sizeof(struct gfs_holder *), glock_compare_atime); + + for (x = 0; x < num_gh; x++) { + p[x]->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC); + + if (p[x]->gh_flags & GL_ATIME) + error = gfs_glock_nq_atime(p[x]); + else + error = gfs_glock_nq(p[x]); + + if (error) { + while (x--) + gfs_glock_dq(p[x]); + break; + } + } + + kfree(p); + return error; +} + +/** + * gfs_try_toss_vnode - See if we can toss a vnode from memory + * @ip: the inode + * + * Returns: TRUE if the vnode was tossed + */ + +void +gfs_try_toss_vnode(struct gfs_inode *ip) +{ + struct inode *inode; + + inode = gfs_iget(ip, NO_CREATE); + if (!inode) + return; + + d_prune_aliases(inode); + + if (ip->i_di.di_type == GFS_FILE_DIR) { + struct list_head *head = &inode->i_dentry; + struct dentry *d = NULL; + + spin_lock(&dcache_lock); + if (list_empty(head)) + spin_unlock(&dcache_lock); + else { + d = list_entry(head->next, struct dentry, d_alias); + dget_locked(d); + spin_unlock(&dcache_lock); + + if (have_submounts(d)) + dput(d); + else { + shrink_dcache_parent(d); + dput(d); + d_prune_aliases(inode); + } + } + } + + inode->i_nlink = 0; + iput(inode); +} + + +static int +__gfs_setattr_simple(struct gfs_inode *ip, struct iattr *attr) +{ + struct buffer_head *dibh; + int error; + + error = gfs_get_inode_buffer(ip, &dibh); + if (!error) { + error = inode_setattr(ip->i_vnode, attr); + gfs_assert_warn(ip->i_sbd, !error); + gfs_inode_attr_out(ip); + + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + return error; +} + +/** + * gfs_setattr_simple - + * @ip: + * @attr: + * + * Called with a reference on the vnode. + * + * Returns: errno + */ + +int +gfs_setattr_simple(struct gfs_inode *ip, struct iattr *attr) +{ + int error; + + if (get_transaction) + return __gfs_setattr_simple(ip, attr); + + /* Trans may require: + one dinode block. */ + + error = gfs_trans_begin(ip->i_sbd, 1, 0); + if (error) + return error; + + error = __gfs_setattr_simple(ip, attr); + + gfs_trans_end(ip->i_sbd); + + return error; +} + +/** + * iah_make_jdata - + * @gl: + * @inum: + * + */ + +static void +iah_make_jdata(struct gfs_glock *gl, struct gfs_inum *inum) +{ + struct buffer_head *bh; + struct gfs_dinode *di; + uint32_t flags; + int error; + + error = gfs_dread(gl, inum->no_addr, DIO_START | DIO_WAIT, &bh); + + /* This should only fail if we are already shutdown. */ + if (gfs_assert_withdraw(gl->gl_sbd, !error)) + return; + + di = (struct gfs_dinode *)bh->b_data; + + flags = di->di_flags; + flags = gfs32_to_cpu(flags) | GFS_DIF_JDATA; + di->di_flags = cpu_to_gfs32(flags); + + brelse(bh); +} + +/** + * iah_super_update - Write superblock to disk + * @sdp: filesystem instance structure + * + * Returns: errno + * + * Update on-disk superblock, using (modified) data in sdp->sd_sb + */ + +static int +iah_super_update(struct gfs_sbd *sdp) +{ + struct gfs_glock *gl; + struct buffer_head *bh; + int error; + + error = gfs_glock_get(sdp, + GFS_SB_LOCK, &gfs_meta_glops, + NO_CREATE, &gl); + if (gfs_assert_withdraw(sdp, !error && gl)) /* This should already be held. */ + return -EINVAL; + + error = gfs_dread(gl, GFS_SB_ADDR >> sdp->sd_fsb2bb_shift, + DIO_START | DIO_WAIT, &bh); + if (!error) { + gfs_trans_add_bh(gl, bh); + gfs_sb_out(&sdp->sd_sb, bh->b_data); + brelse(bh); + } + + gfs_glock_put(gl); + + return error; +} + +/** + * inode_alloc_hidden - allocate on-disk inode for a special (hidden) file + * @sdp: the filesystem instance structure + * @inum: new dinode's block # and formal inode #, to be filled + * in by this function. + * + * Returns: errno + * + * This function is called only very rarely, when the first-to-mount + * node can't find a pre-existing special file (e.g. license or quota file) that + * it expects to find. This should happen only when upgrading from an older + * version of the filesystem. + * + * The @inum must be a member of sdp->sd_sb in order to get updated to on-disk + * superblock properly. + */ + +static int +inode_alloc_hidden(struct gfs_sbd *sdp, struct gfs_inum *inum) +{ + struct gfs_inode *dip = sdp->sd_rooti; + struct gfs_holder d_gh, i_gh; + struct gfs_unlinked *ul; + int error; + + error = gfs_glock_nq_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, &d_gh); + if (error) + return error; + + error = dinode_alloc(dip, &ul); + if (error) + goto fail; + + inum->no_addr = ul->ul_inum.no_addr; + pick_formal_ino(sdp, inum); + + /* Don't worry about deadlock ordering here. We're the first + mounter and still under the mount lock (i.e. there is no + contention). */ + + error = gfs_glock_nq_num(sdp, + inum->no_formal_ino, &gfs_inode_glops, + LM_ST_EXCLUSIVE, GL_SKIP, &i_gh); + if (error) + goto fail_ul; + + gfs_alloc_get(dip); + + error = gfs_quota_hold_m(dip, 0, 0); + if (error) + goto fail_al; + + /* Trans may require: + The new inode, the superblock, + and one block for a quota change and + one block for an unlinked tag. */ + + error = gfs_trans_begin(sdp, 2, 2); + if (error) + goto fail_unhold; + + error = make_dinode(dip, i_gh.gh_gl, inum, GFS_FILE_REG, 0600, 0, 0); + if (error) + goto fail_end_trans; + + /* Hidden files get all of their data (not just metadata) journaled */ + iah_make_jdata(i_gh.gh_gl, inum); + + error = iah_super_update(sdp); + if (error) + goto fail_end_trans; + + gfs_trans_add_unlinked(sdp, GFS_LOG_DESC_IDA, + &(struct gfs_inum){0, inum->no_addr}); + gfs_trans_add_quota(sdp, +1, 0, 0); + gfs_trans_add_gl(dip->i_gl); + + gfs_trans_end(sdp); + gfs_quota_unhold_m(dip); + gfs_alloc_put(dip); + + gfs_glock_dq_uninit(&i_gh); + gfs_glock_dq_uninit(&d_gh); + + gfs_unlinked_unlock(sdp, ul); + + gfs_log_flush(sdp); + + return 0; + + fail_end_trans: + gfs_trans_end(sdp); + + fail_unhold: + gfs_quota_unhold_m(dip); + + fail_al: + gfs_alloc_put(dip); + gfs_glock_dq_uninit(&i_gh); + + fail_ul: + gfs_unlinked_unlock(sdp, ul); + + fail: + gfs_glock_dq_uninit(&d_gh); + + return error; +} + +/** + * gfs_alloc_qinode - allocate a quota inode + * @sdp: The GFS superblock + * + * Returns: 0 on success, error code otherwise + */ + +int +gfs_alloc_qinode(struct gfs_sbd *sdp) +{ + return inode_alloc_hidden(sdp, &sdp->sd_sb.sb_quota_di); +} + +/** + * gfs_alloc_linode - allocate a license inode + * @sdp: The GFS superblock + * + * Returns: 0 on success, error code otherwise + */ + +int +gfs_alloc_linode(struct gfs_sbd *sdp) +{ + return inode_alloc_hidden(sdp, &sdp->sd_sb.sb_license_di); +} --- linux-2.6.27.orig/ubuntu/gfs/page.c +++ linux-2.6.27/ubuntu/gfs/page.c @@ -0,0 +1,266 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "bmap.h" +#include "inode.h" +#include "page.h" + +/** + * gfs_inval_pte - Sync and invalidate all PTEs associated with a glock + * @gl: the glock + * + */ + +void +gfs_inval_pte(struct gfs_glock *gl) +{ + struct gfs_inode *ip; + struct inode *inode; + + ip = get_gl2ip(gl); + if (!ip || + ip->i_di.di_type != GFS_FILE_REG) + return; + + if (!test_bit(GIF_PAGED, &ip->i_flags)) + return; + + inode = gfs_iget(ip, NO_CREATE); + if (inode) { + unmap_shared_mapping_range(inode->i_mapping, 0, 0); + iput(inode); + + if (test_bit(GIF_SW_PAGED, &ip->i_flags)) + set_bit(GLF_DIRTY, &gl->gl_flags); + } + + clear_bit(GIF_SW_PAGED, &ip->i_flags); +} + +/** + * gfs_inval_page - Invalidate all pages associated with a glock + * @gl: the glock + * + */ + +void +gfs_inval_page(struct gfs_glock *gl) +{ + struct gfs_inode *ip; + struct inode *inode; + + ip = get_gl2ip(gl); + if (!ip || + ip->i_di.di_type != GFS_FILE_REG) + return; + + inode = gfs_iget(ip, NO_CREATE); + if (inode) { + struct address_space *mapping = inode->i_mapping; + + truncate_inode_pages(mapping, 0); + gfs_assert_withdraw(ip->i_sbd, !mapping->nrpages); + + iput(inode); + } + + clear_bit(GIF_PAGED, &ip->i_flags); +} + +/** + * gfs_sync_page_i - Sync the data pages (not metadata) for a struct inode + * @inode: the inode + * @flags: DIO_START | DIO_WAIT + * + */ + +void +gfs_sync_page_i(struct inode *inode, int flags) +{ + struct address_space *mapping = inode->i_mapping; + int error = 0; + + if (flags & DIO_START) + error = filemap_fdatawrite(mapping); + if (!error && (flags & DIO_WAIT)) + error = filemap_fdatawait(mapping); + + /* Find a better way to report this to the user. */ + if (error) + gfs_io_error_inode(get_v2ip(inode)); +} + +/** + * gfs_sync_page - Sync the data pages (not metadata) associated with a glock + * @gl: the glock + * @flags: DIO_START | DIO_WAIT + * + * Syncs data (not metadata) for a regular file. + * No-op for all other types. + */ + +void +gfs_sync_page(struct gfs_glock *gl, int flags) +{ + struct gfs_inode *ip; + struct inode *inode; + + ip = get_gl2ip(gl); + if (!ip || + ip->i_di.di_type != GFS_FILE_REG) + return; + + inode = gfs_iget(ip, NO_CREATE); + if (inode) { + gfs_sync_page_i(inode, flags); + iput(inode); + } +} + +/** + * gfs_unstuffer_page - unstuff a stuffed inode into a block cached by a page + * @ip: the inode + * @dibh: the dinode buffer + * @block: the block number that was allocated + * @private: any locked page held by the caller process + * + * Returns: errno + */ + +int +gfs_unstuffer_page(struct gfs_inode *ip, struct buffer_head *dibh, + uint64_t block, void *private) +{ + struct inode *inode = ip->i_vnode; + struct page *page = (struct page *)private; + struct buffer_head *bh; + int release = FALSE; + + if (!page || page->index) { + page = grab_cache_page(inode->i_mapping, 0); + if (!page) + return -ENOMEM; + release = TRUE; + } + + if (!PageUptodate(page)) { + void *kaddr = kmap(page); + + memcpy(kaddr, + dibh->b_data + sizeof(struct gfs_dinode), + ip->i_di.di_size); + memset(kaddr + ip->i_di.di_size, + 0, + PAGE_CACHE_SIZE - ip->i_di.di_size); + kunmap(page); + + SetPageUptodate(page); + } + + if (!page_has_buffers(page)) + create_empty_buffers(page, 1 << inode->i_blkbits, + (1 << BH_Uptodate)); + + bh = page_buffers(page); + + if (!buffer_mapped(bh)) + map_bh(bh, inode->i_sb, block); + else if (gfs_assert_warn(ip->i_sbd, + bh->b_bdev == inode->i_sb->s_bdev && + bh->b_blocknr == block)) + map_bh(bh, inode->i_sb, block); + + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + + if (release) { + unlock_page(page); + page_cache_release(page); + } + + return 0; +} + +/** + * gfs_truncator_page - truncate a partial data block in the page cache + * @ip: the inode + * @size: the size the file should be + * + * Returns: errno + */ + +int +gfs_truncator_page(struct gfs_inode *ip, uint64_t size) +{ + struct inode *inode = ip->i_vnode; + struct page *page; + struct buffer_head *bh; + void *kaddr; + uint64_t lbn, dbn; + unsigned long index; + unsigned int offset; + unsigned int bufnum; + int not_new = 0; + int error; + + lbn = size >> inode->i_blkbits; + error = gfs_block_map(ip, + lbn, ¬_new, + &dbn, NULL); + if (error || !dbn) + return error; + + index = size >> PAGE_CACHE_SHIFT; + offset = size & (PAGE_CACHE_SIZE - 1); + bufnum = lbn - (index << (PAGE_CACHE_SHIFT - inode->i_blkbits)); + + /* Not in a transaction here -- a non-disk-I/O error is ok. */ + + page = read_cache_page(inode->i_mapping, index, + (filler_t *)inode->i_mapping->a_ops->readpage, + NULL); + if (IS_ERR(page)) + return PTR_ERR(page); + + lock_page(page); + + if (!PageUptodate(page) || PageError(page)) { + error = -EIO; + goto out; + } + + kaddr = kmap(page); + memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); + kunmap(page); + + if (!page_has_buffers(page)) + create_empty_buffers(page, 1 << inode->i_blkbits, + (1 << BH_Uptodate)); + + for (bh = page_buffers(page); bufnum--; bh = bh->b_this_page) + /* Do nothing */; + + if (!buffer_mapped(bh)) + map_bh(bh, inode->i_sb, dbn); + else if (gfs_assert_warn(ip->i_sbd, + bh->b_bdev == inode->i_sb->s_bdev && + bh->b_blocknr == dbn)) + map_bh(bh, inode->i_sb, dbn); + + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + + out: + unlock_page(page); + page_cache_release(page); + + return error; +} --- linux-2.6.27.orig/ubuntu/gfs/lm.h +++ linux-2.6.27/ubuntu/gfs/lm.h @@ -0,0 +1,32 @@ +#ifndef __LM_DOT_H__ +#define __LM_DOT_H__ + +int gfs_lm_mount(struct gfs_sbd *sdp, int silent); +void gfs_lm_others_may_mount(struct gfs_sbd *sdp); +void gfs_lm_unmount(struct gfs_sbd *sdp); +int gfs_lm_withdraw(struct gfs_sbd *sdp, char *fmt, ...) +__attribute__ ((format(printf, 2, 3))); +int gfs_lm_get_lock(struct gfs_sbd *sdp, + struct lm_lockname *name, void **lockp); +void gfs_lm_put_lock(struct gfs_sbd *sdp, void *lock); +unsigned int gfs_lm_lock(struct gfs_sbd *sdp, void *lock, + unsigned int cur_state, unsigned int req_state, + unsigned int flags); +unsigned int gfs_lm_unlock(struct gfs_sbd *sdp, void *lock, + unsigned int cur_state); +void gfs_lm_cancel(struct gfs_sbd *sdp, void *lock); +int gfs_lm_hold_lvb(struct gfs_sbd *sdp, void *lock, char **lvbp); +void gfs_lm_unhold_lvb(struct gfs_sbd *sdp, void *lock, char *lvb); +int gfs_lm_plock_get(struct gfs_sbd *sdp, + struct lm_lockname *name, + struct file *file, struct file_lock *fl); +int gfs_lm_plock(struct gfs_sbd *sdp, + struct lm_lockname *name, + struct file *file, int cmd, struct file_lock *fl); +int gfs_lm_punlock(struct gfs_sbd *sdp, + struct lm_lockname *name, + struct file *file, struct file_lock *fl); +void gfs_lm_recovery_done(struct gfs_sbd *sdp, + unsigned int jid, unsigned int message); + +#endif /* __LM_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/page.h +++ linux-2.6.27/ubuntu/gfs/page.h @@ -0,0 +1,13 @@ +#ifndef __PAGE_DOT_H__ +#define __PAGE_DOT_H__ + +void gfs_inval_pte(struct gfs_glock *gl); +void gfs_inval_page(struct gfs_glock *gl); +void gfs_sync_page_i(struct inode *inode, int flags); +void gfs_sync_page(struct gfs_glock *gl, int flags); + +int gfs_unstuffer_page(struct gfs_inode *ip, struct buffer_head *dibh, + uint64_t block, void *private); +int gfs_truncator_page(struct gfs_inode *ip, uint64_t size); + +#endif /* __PAGE_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/Makefile +++ linux-2.6.27/ubuntu/gfs/Makefile @@ -0,0 +1,46 @@ +obj-$(CONFIG_GFS_FS) += gfs.o +gfs-objs := acl.o \ + bits.o \ + bmap.o \ + daemon.o \ + dio.o \ + dir.o \ + eaops.o \ + eattr.o \ + file.o \ + glock.o \ + glops.o \ + inode.o \ + ioctl.o \ + lm.o \ + locking.o \ + lock_nolock_main.o \ + lock_dlm_lock.o \ + lock_dlm_main.o \ + lock_dlm_mount.o \ + lock_dlm_sysfs.o \ + lock_dlm_thread.o \ + log.o \ + lops.o \ + lvb.o \ + main.o \ + mount.o \ + ondisk.o \ + ops_address.o \ + ops_dentry.o \ + ops_export.o \ + ops_file.o \ + ops_fstype.o \ + ops_inode.o \ + ops_super.o \ + ops_vm.o \ + page.o \ + proc.o \ + quota.o \ + recovery.o \ + rgrp.o \ + super.o \ + sys.o \ + trans.o \ + unlinked.o \ + util.o --- linux-2.6.27.orig/ubuntu/gfs/ioctl.c +++ linux-2.6.27/ubuntu/gfs/ioctl.c @@ -0,0 +1,1605 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs_ioctl.h" +#include "gfs.h" +#include "bmap.h" +#include "dio.h" +#include "dir.h" +#include "eattr.h" +#include "file.h" +#include "glock.h" +#include "glops.h" +#include "inode.h" +#include "ioctl.h" +#include "log.h" +#include "quota.h" +#include "rgrp.h" +#include "super.h" +#include "trans.h" + +typedef int (*gi_filler_t) (struct gfs_inode *ip, + struct gfs_ioctl *gi, + char *buf, + unsigned int size, + unsigned int *count); + +#define ARG_SIZE (32) + +/** + * gi_skeleton - Setup a buffer that functions can print into + * @ip: + * @gi: + * @filler: + * + * Returns: -errno or count of bytes copied to userspace + */ + +static int +gi_skeleton(struct gfs_inode *ip, struct gfs_ioctl *gi, + gi_filler_t filler) +{ + unsigned int size = gfs_tune_get(ip->i_sbd, gt_lockdump_size); + char *buf; + unsigned int count = 0; + int error; + + if (size > gi->gi_size) + size = gi->gi_size; + + buf = kmalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + error = filler(ip, gi, buf, size, &count); + if (error) + goto out; + + if (copy_to_user(gi->gi_data, buf, count + 1)) + error = -EFAULT; + else + error = count + 1; + + out: + kfree(buf); + + return error; +} + +/** + * gi_get_cookie - Return the "cookie" (identifying string) for a + * filesystem mount + * @ip: + * @gi: + * @buf: + * @size: + * @count: + * + * Returns: errno + */ + +static int +gi_get_cookie(struct gfs_inode *ip, + struct gfs_ioctl *gi, + char *buf, + unsigned int size, + unsigned int *count) +{ + int error = -ENOBUFS; + + if (gi->gi_argc != 1) + return -EINVAL; + + gfs_printf("version 0\n"); + gfs_printf("%lu", (unsigned long)ip->i_sbd); + + error = 0; + + out: + return error; +} + +/** + * gi_get_super - Return the "struct gfs_sb" for a filesystem + * @sdp: + * @gi: + * + * Returns: errno + */ + +static int +gi_get_super(struct gfs_sbd *sdp, struct gfs_ioctl *gi) +{ + struct gfs_holder sb_gh; + struct buffer_head *bh; + struct gfs_sb *sb; + int error; + + if (gi->gi_argc != 1) + return -EINVAL; + if (gi->gi_size != sizeof(struct gfs_sb)) + return -EINVAL; + + sb = kmalloc(sizeof(struct gfs_sb), GFP_KERNEL); + if (!sb) + return -ENOMEM; + + error = gfs_glock_nq_num(sdp, + GFS_SB_LOCK, &gfs_meta_glops, + LM_ST_SHARED, 0, &sb_gh); + if (error) + goto out; + + error = gfs_dread(sb_gh.gh_gl, GFS_SB_ADDR >> sdp->sd_fsb2bb_shift, + DIO_START | DIO_WAIT, &bh); + if (error) { + gfs_glock_dq_uninit(&sb_gh); + goto out; + } + gfs_sb_in(sb, bh->b_data); + brelse(bh); + + gfs_glock_dq_uninit(&sb_gh); + + if (copy_to_user(gi->gi_data, sb, + sizeof(struct gfs_sb))) + error = -EFAULT; + else + error = sizeof(struct gfs_sb); + + out: + kfree(sb); + + return error; +} + +/** + * gi_get_args - Return the mount arguments + * @ip: + * @gi: + * @buf: + * @size: + * @count: + * + * Returns: errno + */ + +static int +gi_get_args(struct gfs_inode *ip, + struct gfs_ioctl *gi, + char *buf, + unsigned int size, + unsigned int *count) +{ + struct gfs_args *args = &ip->i_sbd->sd_args; + int error = -ENOBUFS; + + if (gi->gi_argc != 1) + return -EINVAL; + + gfs_printf("version 0\n"); + gfs_printf("lockproto %s\n", args->ar_lockproto); + gfs_printf("locktable %s\n", args->ar_locktable); + gfs_printf("hostdata %s\n", args->ar_hostdata); + gfs_printf("ignore_local_fs %d\n", args->ar_ignore_local_fs); + gfs_printf("localcaching %d\n", args->ar_localcaching); + gfs_printf("localflocks %d\n", args->ar_localflocks); + gfs_printf("oopses_ok %d\n", args->ar_oopses_ok); + gfs_printf("upgrade %d\n", args->ar_upgrade); + gfs_printf("num_glockd %u\n", args->ar_num_glockd); + gfs_printf("posix_acls %d\n", args->ar_posix_acls); + gfs_printf("suiddir %d\n", args->ar_suiddir); + + error = 0; + + out: + return error; +} + +/** + * gi_get_lockstruct - Return the information in the FS' lockstruct + * @ip: + * @gi: + * @buf: + * @size: + * @count: + * + * Returns: errno + */ + +static int +gi_get_lockstruct(struct gfs_inode *ip, + struct gfs_ioctl *gi, + char *buf, + unsigned int size, + unsigned int *count) +{ + struct lm_lockstruct *ls = &ip->i_sbd->sd_lockstruct; + int error = -ENOBUFS; + + if (gi->gi_argc != 1) + return -EINVAL; + + gfs_printf("version 0\n"); + gfs_printf("jid %u\n", ls->ls_jid); + gfs_printf("first %u\n", ls->ls_first); + gfs_printf("lvb_size %u\n", ls->ls_lvb_size); + gfs_printf("flags %d\n", ls->ls_flags); + + error = 0; + + out: + return error; +} + +/** + * gi_get_stat_gfs - Return a filesystem's space usage information + * @ip: + * @gi: + * @buf: + * @size: + * @count: + * + * Returns: errno + */ + +static int +gi_get_stat_gfs(struct gfs_inode *ip, + struct gfs_ioctl *gi, + char *buf, + unsigned int size, + unsigned int *count) +{ + struct gfs_stat_gfs sg; + int error; + + if (gi->gi_argc != 1) + return -EINVAL; + + error = gfs_stat_gfs(ip->i_sbd, &sg, TRUE); + if (error) + return error; + + error = -ENOBUFS; + + gfs_printf("version 0\n"); + gfs_printf("bsize %u\n", ip->i_sbd->sd_sb.sb_bsize); + gfs_printf("total_blocks %"PRIu64"\n", sg.sg_total_blocks); + gfs_printf("free %"PRIu64"\n", sg.sg_free); + gfs_printf("used_dinode %"PRIu64"\n", sg.sg_used_dinode); + gfs_printf("free_dinode %"PRIu64"\n", sg.sg_free_dinode); + gfs_printf("used_meta %"PRIu64"\n", sg.sg_used_meta); + gfs_printf("free_meta %"PRIu64"\n", sg.sg_free_meta); + + error = 0; + + out: + return error; +} + +/** + * handle_roll - Read a atomic_t as an unsigned int + * @a: a counter + * + * if @a is negative, reset it to zero + * + * Returns: the value of the counter + */ + +static unsigned int +handle_roll(atomic_t *a) +{ + int x = atomic_read(a); + if (x < 0) { + atomic_set(a, 0); + return 0; + } + return (unsigned int)x; +} + +/** + * gi_get_counters - Return usage counters + * @ip: + * @gi: + * @buf: + * @size: + * @count: + * + * Returns: errno + */ + +static int +gi_get_counters(struct gfs_inode *ip, + struct gfs_ioctl *gi, + char *buf, + unsigned int size, + unsigned int *count) +{ + struct gfs_sbd *sdp = ip->i_sbd; + int error = -ENOBUFS; + + if (gi->gi_argc != 1) + return -EINVAL; + + gfs_printf("version 0\n"); + gfs_printf("sd_glock_count:locks::%d\n", + atomic_read(&sdp->sd_glock_count)); + gfs_printf("sd_glock_held_count:locks held::%d\n", + atomic_read(&sdp->sd_glock_held_count)); + gfs_printf("sd_freeze_count:freeze count::%d\n", + sdp->sd_freeze_count); + gfs_printf("sd_inode_count:incore inodes::%d\n", + atomic_read(&sdp->sd_inode_count)); + gfs_printf("sd_bufdata_count:metadata buffers::%d\n", + atomic_read(&sdp->sd_bufdata_count)); + gfs_printf("sd_unlinked_ic_count:unlinked inodes::%d\n", + atomic_read(&sdp->sd_unlinked_ic_count)); + gfs_printf("sd_quota_count:quota IDs::%d\n", + atomic_read(&sdp->sd_quota_count)); + gfs_printf("sd_log_buffers:incore log buffers::%u\n", + sdp->sd_log_buffers); + gfs_printf("sd_log_seg_free:log segments free::%u\n", + sdp->sd_log_seg_free); + gfs_printf("ji_nsegment:log segments total::%u\n", + sdp->sd_jdesc.ji_nsegment); + gfs_printf("sd_mhc_count:meta header cache entries::%d\n", + atomic_read(&sdp->sd_mhc_count)); + gfs_printf("sd_depend_count:glock dependencies::%d\n", + atomic_read(&sdp->sd_depend_count)); + gfs_printf("sd_reclaim_count:glocks on reclaim list::%d\n", + atomic_read(&sdp->sd_reclaim_count)); + gfs_printf("sd_log_wrap:log wraps::%"PRIu64"\n", + sdp->sd_log_wrap); + gfs_printf("sd_lm_outstanding:outstanding LM calls::%d\n", + atomic_read(&sdp->sd_lm_outstanding)); + gfs_printf("sd_bio_outstanding:outstanding BIO calls::%u\n", + atomic_read(&sdp->sd_bio_outstanding)); + gfs_printf("sd_fh2dentry_misses:fh2dentry misses:diff:%u\n", + handle_roll(&sdp->sd_fh2dentry_misses)); + gfs_printf("sd_reclaimed:glocks reclaimed:diff:%u\n", + handle_roll(&sdp->sd_reclaimed)); + gfs_printf("sd_glock_nq_calls:glock nq calls:diff:%u\n", + handle_roll(&sdp->sd_glock_nq_calls)); + gfs_printf("sd_glock_dq_calls:glock dq calls:diff:%u\n", + handle_roll(&sdp->sd_glock_dq_calls)); + gfs_printf("sd_glock_prefetch_calls:glock prefetch calls:diff:%u\n", + handle_roll(&sdp->sd_glock_prefetch_calls)); + gfs_printf("sd_lm_lock_calls:lm_lock calls:diff:%u\n", + handle_roll(&sdp->sd_lm_lock_calls)); + gfs_printf("sd_lm_unlock_calls:lm_unlock calls:diff:%u\n", + handle_roll(&sdp->sd_lm_unlock_calls)); + gfs_printf("sd_lm_callbacks:lm callbacks:diff:%u\n", + handle_roll(&sdp->sd_lm_callbacks)); + gfs_printf("sd_ops_address:address operations:diff:%u\n", + handle_roll(&sdp->sd_ops_address)); + gfs_printf("sd_ops_dentry:dentry operations:diff:%u\n", + handle_roll(&sdp->sd_ops_dentry)); + gfs_printf("sd_ops_export:export operations:diff:%u\n", + handle_roll(&sdp->sd_ops_export)); + gfs_printf("sd_ops_file:file operations:diff:%u\n", + handle_roll(&sdp->sd_ops_file)); + gfs_printf("sd_ops_inode:inode operations:diff:%u\n", + handle_roll(&sdp->sd_ops_inode)); + gfs_printf("sd_ops_super:super operations:diff:%u\n", + handle_roll(&sdp->sd_ops_super)); + gfs_printf("sd_ops_vm:vm operations:diff:%u\n", + handle_roll(&sdp->sd_ops_vm)); + gfs_printf("sd_bio_reads:block I/O reads:diff:%u\n", + handle_roll(&sdp->sd_bio_reads) >> + (sdp->sd_sb.sb_bsize_shift - 9)); + gfs_printf("sd_bio_writes:block I/O writes:diff:%u\n", + handle_roll(&sdp->sd_bio_writes) >> + (sdp->sd_sb.sb_bsize_shift - 9)); + + error = 0; + + out: + return error; +} + +/** + * gi_get_tune - Return current values of the tuneable parameters + * @ip: + * @gi: + * @buf: + * @size: + * @count: + * + * Returns: errno + */ + +static int +gi_get_tune(struct gfs_inode *ip, + struct gfs_ioctl *gi, + char *buf, + unsigned int size, + unsigned int *count) +{ + struct gfs_tune *gt = &ip->i_sbd->sd_tune; + int error = -ENOBUFS; + + if (gi->gi_argc != 1) + return -EINVAL; + + spin_lock(>->gt_spin); + + gfs_printf("version 0\n"); + gfs_printf("ilimit1 %u\n", gt->gt_ilimit1); + gfs_printf("ilimit1_tries %u\n", gt->gt_ilimit1_tries); + gfs_printf("ilimit1_min %u\n", gt->gt_ilimit1_min); + gfs_printf("ilimit2 %u\n", gt->gt_ilimit2); + gfs_printf("ilimit2_tries %u\n", gt->gt_ilimit2_tries); + gfs_printf("ilimit2_min %u\n", gt->gt_ilimit2_min); + gfs_printf("demote_secs %u\n", gt->gt_demote_secs); + gfs_printf("incore_log_blocks %u\n", gt->gt_incore_log_blocks); + gfs_printf("jindex_refresh_secs %u\n", gt->gt_jindex_refresh_secs); + gfs_printf("depend_secs %u\n", gt->gt_depend_secs); + gfs_printf("scand_secs %u\n", gt->gt_scand_secs); + gfs_printf("recoverd_secs %u\n", gt->gt_recoverd_secs); + gfs_printf("logd_secs %u\n", gt->gt_logd_secs); + gfs_printf("quotad_secs %u\n", gt->gt_quotad_secs); + gfs_printf("inoded_secs %u\n", gt->gt_inoded_secs); + gfs_printf("glock_purge %u\n", gt->gt_glock_purge); + gfs_printf("quota_simul_sync %u\n", gt->gt_quota_simul_sync); + gfs_printf("quota_warn_period %u\n", gt->gt_quota_warn_period); + gfs_printf("atime_quantum %u\n", gt->gt_atime_quantum); + gfs_printf("quota_quantum %u\n", gt->gt_quota_quantum); + gfs_printf("quota_scale_num %u\n", gt->gt_quota_scale_num); + gfs_printf("quota_scale_den %u\n", gt->gt_quota_scale_den); + gfs_printf("quota_enforce %u\n", gt->gt_quota_enforce); + gfs_printf("quota_account %u\n", gt->gt_quota_account); + gfs_printf("new_files_jdata %u\n", gt->gt_new_files_jdata); + gfs_printf("new_files_directio %u\n", gt->gt_new_files_directio); + gfs_printf("max_atomic_write %u\n", gt->gt_max_atomic_write); + gfs_printf("max_readahead %u\n", gt->gt_max_readahead); + gfs_printf("lockdump_size %u\n", gt->gt_lockdump_size); + gfs_printf("stall_secs %u\n", gt->gt_stall_secs); + gfs_printf("complain_secs %u\n", gt->gt_complain_secs); + gfs_printf("reclaim_limit %u\n", gt->gt_reclaim_limit); + gfs_printf("entries_per_readdir %u\n", gt->gt_entries_per_readdir); + gfs_printf("prefetch_secs %u\n", gt->gt_prefetch_secs); + gfs_printf("statfs_slots %u\n", gt->gt_statfs_slots); + gfs_printf("max_mhc %u\n", gt->gt_max_mhc); + gfs_printf("greedy_default %u\n", gt->gt_greedy_default); + gfs_printf("greedy_quantum %u\n", gt->gt_greedy_quantum); + gfs_printf("greedy_max %u\n", gt->gt_greedy_max); + gfs_printf("rgrp_try_threshold %u\n", gt->gt_rgrp_try_threshold); + gfs_printf("statfs_fast %u\n", gt->gt_statfs_fast); + + error = 0; + + out: + spin_unlock(>->gt_spin); + + return error; +} + +#define tune_set(f, v) \ +do { \ + spin_lock(>->gt_spin); \ + gt->f = (v); \ + spin_unlock(>->gt_spin); \ +} while (0) + +/** + * gi_set_tune - Set a tuneable parameter + * @sdp: + * @gi: + * + * Returns: errno + */ + +static int +gi_set_tune(struct gfs_sbd *sdp, struct gfs_ioctl *gi, int from_user) +{ + struct gfs_tune *gt = &sdp->sd_tune; + char param[ARG_SIZE], value[ARG_SIZE]; + unsigned int x; + int error; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (gi->gi_argc != 3) + return -EINVAL; + + if (from_user) { + if (strncpy_from_user(param, gi->gi_argv[1], ARG_SIZE) < 0) + return -EFAULT; + } else { + strncpy(param, gi->gi_argv[1], ARG_SIZE); + } + param[ARG_SIZE - 1] = 0; + + if (from_user) { + if (strncpy_from_user(value, gi->gi_argv[2], ARG_SIZE) < 0) + return -EFAULT; + } else { + strncpy(value, gi->gi_argv[2], ARG_SIZE); + } + + value[ARG_SIZE - 1] = 0; + + if (strcmp(param, "ilimit1") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_ilimit1, x); + + } else if (strcmp(param, "ilimit1_tries") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_ilimit1_tries, x); + + } else if (strcmp(param, "ilimit1_min") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_ilimit1_min, x); + + } else if (strcmp(param, "ilimit2") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_ilimit2, x); + + } else if (strcmp(param, "ilimit2_tries") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_ilimit2_tries, x); + + } else if (strcmp(param, "ilimit2_min") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_ilimit2_min, x); + + } else if (strcmp(param, "demote_secs") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_demote_secs, x); + + } else if (strcmp(param, "incore_log_blocks") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_incore_log_blocks, x); + + } else if (strcmp(param, "jindex_refresh_secs") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_jindex_refresh_secs, x); + + } else if (strcmp(param, "depend_secs") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_depend_secs, x); + + } else if (strcmp(param, "scand_secs") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_scand_secs, x); + wake_up_process(sdp->sd_scand_process); + + } else if (strcmp(param, "recoverd_secs") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_recoverd_secs, x); + wake_up_process(sdp->sd_recoverd_process); + + } else if (strcmp(param, "logd_secs") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_logd_secs, x); + wake_up_process(sdp->sd_logd_process); + + } else if (strcmp(param, "quotad_secs") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_quotad_secs, x); + wake_up_process(sdp->sd_quotad_process); + + } else if (strcmp(param, "inoded_secs") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_inoded_secs, x); + wake_up_process(sdp->sd_inoded_process); + + } else if (strcmp(param, "glock_purge") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_glock_purge, x); + + } else if (strcmp(param, "quota_simul_sync") == 0) { + if (sscanf(value, "%u", &x) != 1 || !x) + return -EINVAL; + tune_set(gt_quota_simul_sync, x); + + } else if (strcmp(param, "quota_warn_period") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_quota_warn_period, x); + + } else if (strcmp(param, "atime_quantum") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_atime_quantum, x); + + } else if (strcmp(param, "quota_quantum") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_quota_quantum, x); + + } else if (strcmp(param, "quota_scale") == 0) { + unsigned int y; + if (sscanf(value, "%u %u", &x, &y) != 2 || !y) + return -EINVAL; + spin_lock(>->gt_spin); + gt->gt_quota_scale_num = x; + gt->gt_quota_scale_den = y; + spin_unlock(>->gt_spin); + + } else if (strcmp(param, "quota_enforce") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + x = !!x; + spin_lock(>->gt_spin); + gt->gt_quota_enforce = x; + if (x) + gt->gt_quota_account = 1; + spin_unlock(>->gt_spin); + + } else if (strcmp(param, "quota_account") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + x = !!x; + spin_lock(>->gt_spin); + gt->gt_quota_account = x; + if (x) + spin_unlock(>->gt_spin); + else { + unsigned int y; + gt->gt_quota_enforce = 0; + spin_unlock(>->gt_spin); + for (y = 0; y < 2; y++) { + gfs_log_flush(sdp); + gfs_sync_meta(sdp); + gfs_quota_sync(sdp); + } + } + + } else if (strcmp(param, "new_files_jdata") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + x = !!x; + tune_set(gt_new_files_jdata, x); + + } else if (strcmp(param, "new_files_directio") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + x = !!x; + tune_set(gt_new_files_directio, x); + + } else if (strcmp(param, "max_atomic_write") == 0) { + if (sscanf(value, "%u", &x) != 1 || !x) + return -EINVAL; + tune_set(gt_max_atomic_write, x); + + } else if (strcmp(param, "max_readahead") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_max_readahead, x); + + } else if (strcmp(param, "lockdump_size") == 0) { + if (sscanf(value, "%u", &x) != 1 || !x) + return -EINVAL; + tune_set(gt_lockdump_size, x); + + } else if (strcmp(param, "stall_secs") == 0) { + if (sscanf(value, "%u", &x) != 1 || !x) + return -EINVAL; + tune_set(gt_stall_secs, x); + + } else if (strcmp(param, "complain_secs") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_complain_secs, x); + + } else if (strcmp(param, "reclaim_limit") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_reclaim_limit, x); + + } else if (strcmp(param, "entries_per_readdir") == 0) { + if (sscanf(value, "%u", &x) != 1 || !x) + return -EINVAL; + tune_set(gt_entries_per_readdir, x); + + } else if (strcmp(param, "prefetch_secs") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_prefetch_secs, x); + + } else if (strcmp(param, "statfs_slots") == 0) { + if (sscanf(value, "%u", &x) != 1 || !x) + return -EINVAL; + tune_set(gt_statfs_slots, x); + + } else if (strcmp(param, "max_mhc") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_max_mhc, x); + + } else if (strcmp(param, "greedy_default") == 0) { + if (sscanf(value, "%u", &x) != 1 || !x) + return -EINVAL; + tune_set(gt_greedy_default, x); + + } else if (strcmp(param, "greedy_quantum") == 0) { + if (sscanf(value, "%u", &x) != 1 || !x) + return -EINVAL; + tune_set(gt_greedy_quantum, x); + + } else if (strcmp(param, "greedy_max") == 0) { + if (sscanf(value, "%u", &x) != 1 || !x) + return -EINVAL; + tune_set(gt_greedy_max, x); + + } else if (strcmp(param, "rgrp_try_threshold") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + tune_set(gt_rgrp_try_threshold, x); + + } else if (strcmp(param, "statfs_fast") == 0) { + if (sscanf(value, "%u", &x) != 1) + return -EINVAL; + error = gfs_statfs_init(sdp, x); + if (error) + return error; + else + tune_set(gt_statfs_fast, x); + + + } else + return -EINVAL; + + return 0; +} + +/** + * gi_do_reclaim - Reclaim unused metadata + * @ip: + * @gi: + * @buf: + * @size: + * @count: + * + * Returns: errno + */ + +static int +gi_do_reclaim(struct gfs_inode *ip, + struct gfs_ioctl *gi, + char *buf, + unsigned int size, + unsigned int *count) +{ + uint64_t inodes, metadata; + int error; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (gi->gi_argc != 1) + return -EINVAL; + + error = gfs_reclaim_metadata(ip->i_sbd, + &inodes, + &metadata); + if (error) + return error; + + error = -ENOBUFS; + + gfs_printf("version 0\n"); + gfs_printf("inodes %"PRIu64"\n", inodes); + gfs_printf("metadata %"PRIu64"\n", metadata); + + error = 0; + + out: + return error; +} + +/** + * gi_do_shrink - throw out unused glocks + * @sdp: + * @gi: + * + * Returns: 0 + */ + +static int +gi_do_shrink(struct gfs_sbd *sdp, struct gfs_ioctl *gi) +{ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (gi->gi_argc != 1) + return -EINVAL; + gfs_gl_hash_clear(sdp, FALSE); + return 0; +} + +/** + * gi_get_file_stat - + * @ip: + * @gi: + * + * Returns: the number of bytes copied, or -errno + */ + +static int +gi_get_file_stat(struct gfs_inode *ip, struct gfs_ioctl *gi) +{ + struct gfs_holder i_gh; + struct gfs_dinode *di; + int error; + + if (gi->gi_argc != 1) + return -EINVAL; + if (gi->gi_size != sizeof(struct gfs_dinode)) + return -EINVAL; + + di = kmalloc(sizeof(struct gfs_dinode), GFP_KERNEL); + if (!di) + return -ENOMEM; + + error = gfs_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); + if (error) + goto out; + memcpy(di, &ip->i_di, sizeof(struct gfs_dinode)); + gfs_glock_dq_uninit(&i_gh); + + if (copy_to_user(gi->gi_data, di, + sizeof(struct gfs_dinode))) + error = -EFAULT; + else + error = sizeof(struct gfs_dinode); + + out: + kfree(di); + + return error; +} + +/** + * gi_set_file_flag - set or clear a flag on a file + * @ip: + * @gi: + * + * Returns: errno + */ + +static int +gi_set_file_flag(struct gfs_inode *ip, struct gfs_ioctl *gi, int from_user) +{ + char buf[ARG_SIZE]; + int set; + uint32_t flag; + struct gfs_holder i_gh; + struct buffer_head *dibh; + int error; + + if (gi->gi_argc != 3) + return -EINVAL; + + if (from_user) { + if (strncpy_from_user(buf, gi->gi_argv[1], ARG_SIZE) < 0) + return -EFAULT; + } else { + strncpy(buf, gi->gi_argv[1], ARG_SIZE); + } + buf[ARG_SIZE - 1] = 0; + + if (strcmp(buf, "set") == 0) + set = TRUE; + else if (strcmp(buf, "clear") == 0) + set = FALSE; + else + return -EINVAL; + + if (from_user) { + if (strncpy_from_user(buf, gi->gi_argv[2], ARG_SIZE) < 0) + return -EFAULT; + } else { + strncpy(buf, gi->gi_argv[2], ARG_SIZE); + } + buf[ARG_SIZE - 1] = 0; + + error = gfs_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); + if (error) + return error; + + error = -EACCES; + if (ip->i_di.di_uid != current->fsuid && !capable(CAP_FOWNER)) + goto out; + + error = -EINVAL; + + if (strcmp(buf, "jdata") == 0) { + if (ip->i_di.di_type != GFS_FILE_REG || + ip->i_di.di_size) + goto out; + flag = GFS_DIF_JDATA; + } else if (strcmp(buf, "directio") == 0) { + if (ip->i_di.di_type != GFS_FILE_REG) + goto out; + flag = GFS_DIF_DIRECTIO; + } else if (strcmp(buf, "immutable") == 0) { + /* The IMMUTABLE flag can only be changed by + the relevant capability. */ + error = -EPERM; + if (!capable(CAP_LINUX_IMMUTABLE)) + goto out; + flag = GFS_DIF_IMMUTABLE; + } else if (strcmp(buf, "appendonly") == 0) { + /* The APPENDONLY flag can only be changed by + the relevant capability. */ + error = -EPERM; + if (!capable(CAP_LINUX_IMMUTABLE)) + goto out; + flag = GFS_DIF_APPENDONLY; + } else if (strcmp(buf, "inherit_jdata") == 0) { + if (ip->i_di.di_type != GFS_FILE_DIR) + goto out; + flag = GFS_DIF_INHERIT_JDATA; + } else if (strcmp(buf, "inherit_directio") == 0) { + if (ip->i_di.di_type != GFS_FILE_DIR) + goto out; + flag = GFS_DIF_INHERIT_DIRECTIO; + } else + goto out; + + error = gfs_trans_begin(ip->i_sbd, 1, 0); + if (error) + goto out; + + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + goto out_trans_end; + + if (set) + ip->i_di.di_flags |= flag; + else + ip->i_di.di_flags &= ~flag; + + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + + brelse(dibh); + + out_trans_end: + gfs_trans_end(ip->i_sbd); + + out: + gfs_glock_dq_uninit(&i_gh); + + return error; + +} + +/** + * gi_get_file_meta - Return all the metadata for a file + * @ip: + * @gi: + * + * Returns: the number of bytes copied, or -errno + */ + +static int +gi_get_file_meta(struct gfs_inode *ip, struct gfs_ioctl *gi) +{ + struct gfs_holder i_gh; + struct gfs_user_buffer ub; + int error; + + if (gi->gi_argc != 1) + return -EINVAL; + + ub.ub_data = gi->gi_data; + ub.ub_size = gi->gi_size; + ub.ub_count = 0; + + error = gfs_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); + if (error) + return error; + + error = -EACCES; + if (ip->i_di.di_uid != current->fsuid && !capable(CAP_FOWNER)) + goto out; + + error = gfs_get_file_meta(ip, &ub); + if (error) + goto out; + + if (ip->i_di.di_type == GFS_FILE_DIR && + (ip->i_di.di_flags & GFS_DIF_EXHASH)) { + error = gfs_get_dir_meta(ip, &ub); + if (error) + goto out; + } + + if (ip->i_di.di_eattr) { + error = gfs_get_eattr_meta(ip, &ub); + if (error) + goto out; + } + + error = ub.ub_count; + + out: + gfs_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * gi_do_file_flush - sync out all dirty data and + * drop the cache (and lock) for a file. + * @ip: + * @gi: + * + * Returns: errno + */ + +static int +gi_do_file_flush(struct gfs_inode *ip, struct gfs_ioctl *gi) +{ + if (gi->gi_argc != 1) + return -EINVAL; + gfs_glock_force_drop(ip->i_gl); + return 0; +} + +/** + * gi2hip - return the "struct gfs_inode" for a hidden file + * @sdp: + * @gi: + * + * Returns: the "struct gfs_inode" + */ + +static struct gfs_inode * +gi2hip(struct gfs_sbd *sdp, struct gfs_ioctl *gi, int from_user) +{ + char buf[ARG_SIZE]; + + if (gi->gi_argc != 2) + return ERR_PTR(-EINVAL); + + if (from_user) { + if (strncpy_from_user(buf, gi->gi_argv[1], ARG_SIZE) < 0) + return ERR_PTR(-EFAULT); + } else { + strncpy(buf, gi->gi_argv[1], ARG_SIZE); + } + buf[ARG_SIZE - 1] = 0; + + if (strcmp(buf, "jindex") == 0) + return sdp->sd_jiinode; + else if (strcmp(buf, "rindex") == 0) + return sdp->sd_riinode; + else if (strcmp(buf, "quota") == 0) + return sdp->sd_qinode; + else if (strcmp(buf, "license") == 0) + return sdp->sd_linode; + else + return ERR_PTR(-EINVAL); +} + +/** + * gi_get_hfile_stat - get stat info on a hidden file + * @sdp: + * @gi: + * + * Returns: the number of bytes copied, or -errno + */ + +static int +gi_get_hfile_stat(struct gfs_sbd *sdp, struct gfs_ioctl *gi, int from_user) +{ + struct gfs_inode *ip; + struct gfs_dinode *di; + struct gfs_holder i_gh; + int error; + + ip = gi2hip(sdp, gi, from_user); + if (IS_ERR(ip)) + return PTR_ERR(ip); + + if (gi->gi_size != sizeof(struct gfs_dinode)) + return -EINVAL; + + di = kmalloc(sizeof(struct gfs_dinode), GFP_KERNEL); + if (!di) + return -ENOMEM; + + error = gfs_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); + if (error) + goto out; + memcpy(di, &ip->i_di, sizeof(struct gfs_dinode)); + gfs_glock_dq_uninit(&i_gh); + + if (copy_to_user(gi->gi_data, di, + sizeof(struct gfs_dinode))) + error = -EFAULT; + else + error = sizeof(struct gfs_dinode); + + out: + kfree(di); + + return error; +} + +/** + * gi_do_hfile_read - Read data from a hidden file + * @sdp: + * @gi: + * + * Returns: the number of bytes read, or -errno + */ + +static int +gi_do_hfile_read(struct gfs_sbd *sdp, struct gfs_ioctl *gi, int from_user) +{ + struct gfs_inode *ip; + struct gfs_holder i_gh; + int error; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + ip = gi2hip(sdp, gi, from_user); + if (IS_ERR(ip)) + return PTR_ERR(ip); + + if (!access_ok(VERIFY_WRITE, gi->gi_data, gi->gi_size)) + return -EFAULT; + + error = gfs_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh); + if (error) + return error; + + error = gfs_readi(ip, gi->gi_data, gi->gi_offset, gi->gi_size, + gfs_copy2user); + + gfs_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * gi_do_hfile_write - Write data to a hidden file + * @sdp: + * @gi: + * + * Returns: the number of bytes written, or -errno + */ + +static int +gi_do_hfile_write(struct gfs_sbd *sdp, struct gfs_ioctl *gi, int from_user) +{ + struct gfs_inode *ip; + struct gfs_alloc *al = NULL; + struct gfs_holder i_gh; + unsigned int data_blocks, ind_blocks; + int alloc_required; + int error; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + ip = gi2hip(sdp, gi, from_user); + if (IS_ERR(ip)) + return PTR_ERR(ip); + + if (!access_ok(VERIFY_READ, gi->gi_data, gi->gi_size)) + return -EFAULT; + + gfs_write_calc_reserv(ip, gi->gi_size, &data_blocks, &ind_blocks); + + error = gfs_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, + LM_FLAG_PRIORITY | GL_SYNC | GL_NOCANCEL_OTHER, + &i_gh); + if (error) + return error; + + if (!gfs_is_jdata(ip)) { + gfs_consist_inode(ip); + error = -EIO; + goto out; + } + + error = gfs_write_alloc_required(ip, gi->gi_offset, gi->gi_size, + &alloc_required); + if (error) + goto out; + + if (alloc_required) { + al = gfs_alloc_get(ip); + + error = gfs_quota_hold_m(ip, NO_QUOTA_CHANGE, + NO_QUOTA_CHANGE); + if (error) + goto out_alloc; + + al->al_requested_meta = ind_blocks + data_blocks; + + error = gfs_inplace_reserve(ip); + if (error) + goto out_qs; + + /* Trans may require: + All blocks for a RG bitmap, all the "data" blocks, whatever + indirect blocks we need, a modified dinode, and a quota change */ + + error = gfs_trans_begin(sdp, + 1 + al->al_rgd->rd_ri.ri_length + + ind_blocks + data_blocks, 1); + if (error) + goto out_relse; + } else { + /* Trans may require: + All the "data" blocks and a modified dinode. */ + + error = gfs_trans_begin(sdp, 1 + data_blocks, 0); + if (error) + goto out_relse; + } + + if (from_user) + error = gfs_writei(ip, gi->gi_data, gi->gi_offset, gi->gi_size, + gfs_copy_from_user, NULL); + else + error = gfs_writei(ip, gi->gi_data, gi->gi_offset, gi->gi_size, + gfs_copy_from_mem, NULL); + + gfs_trans_end(sdp); + + out_relse: + if (alloc_required) { + gfs_assert_warn(sdp, error || al->al_alloced_meta); + gfs_inplace_release(ip); + } + + out_qs: + if (alloc_required) + gfs_quota_unhold_m(ip); + + out_alloc: + if (alloc_required) + gfs_alloc_put(ip); + + out: + ip->i_gl->gl_vn++; + gfs_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * gi_do_hfile_trunc - truncate a hidden file + * @sdp: + * @gi: + * + * Returns: the number of bytes copied, or -errno + */ + +static int +gi_do_hfile_trunc(struct gfs_sbd *sdp, struct gfs_ioctl *gi, int from_user) +{ + struct gfs_inode *ip; + struct gfs_holder i_gh; + int error; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + ip = gi2hip(sdp, gi, from_user); + if (IS_ERR(ip)) + return PTR_ERR(ip); + + error = gfs_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SYNC, &i_gh); + if (error) + return error; + + error = gfs_truncatei(ip, gi->gi_offset, NULL); + + ip->i_gl->gl_vn++; + gfs_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * gi_do_quota_sync - sync the outstanding quota changes for a FS + * @sdp: + * @gi: + * + * Returns: errno + */ + +static int +gi_do_quota_sync(struct gfs_sbd *sdp, struct gfs_ioctl *gi) +{ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (gi->gi_argc != 1) + return -EINVAL; + return gfs_quota_sync(sdp); +} + +/** + * gi_do_quota_refresh - Refresh the a quota LVB from the quota file + * @sdp: + * @gi: + * + * Returns: errno + */ + +static int +gi_do_quota_refresh(struct gfs_sbd *sdp, struct gfs_ioctl *gi, int from_user) +{ + char buf[ARG_SIZE]; + int user; + uint32_t id; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (gi->gi_argc != 2) + return -EINVAL; + + if (from_user) { + if (strncpy_from_user(buf, gi->gi_argv[1], ARG_SIZE) < 0) + return -EFAULT; + } else { + strncpy(buf, gi->gi_argv[1], ARG_SIZE); + } + buf[ARG_SIZE - 1] = 0; + + switch (buf[0]) { + case 'u': + user = TRUE; + break; + case 'g': + user = FALSE; + break; + default: + return -EINVAL; + } + + if (buf[1] != ':') + return -EINVAL; + + if (sscanf(buf + 2, "%u", &id) != 1) + return -EINVAL; + + return gfs_quota_refresh(sdp, user, id); +} + +/** + * gi_do_quota_read - read quota values from the quota file + * @sdp: + * @gi: + * + * Returns: errno + */ + +static int +gi_do_quota_read(struct gfs_sbd *sdp, struct gfs_ioctl *gi, int from_user) +{ + char buf[ARG_SIZE]; + int user; + uint32_t id; + struct gfs_quota q; + int error; + + if (gi->gi_argc != 2) + return -EINVAL; + if (gi->gi_size != sizeof(struct gfs_quota)) + return -EINVAL; + + if (from_user) { + if (strncpy_from_user(buf, gi->gi_argv[1], ARG_SIZE) < 0) + return -EFAULT; + } else { + strncpy(buf, gi->gi_argv[1], ARG_SIZE); + } + buf[ARG_SIZE - 1] = 0; + + switch (buf[0]) { + case 'u': + user = TRUE; + break; + case 'g': + user = FALSE; + break; + default: + return -EINVAL; + } + + if (buf[1] != ':') + return -EINVAL; + + if (sscanf(buf + 2, "%u", &id) != 1) + return -EINVAL; + + error = gfs_quota_read(sdp, user, id, &q); + if (error) + return error; + + if (copy_to_user(gi->gi_data, &q, sizeof(struct gfs_quota))) + return -EFAULT; + + return 0; +} + +int +gfs_ioctl_i_local(struct gfs_inode *ip, struct gfs_ioctl *gi, const char *arg0, + int from_user) +{ + int error = -EFAULT; + + if (strcmp(arg0, "get_cookie") == 0) + error = gi_skeleton(ip, gi, gi_get_cookie); + else if (strcmp(arg0, "get_super") == 0) + error = gi_get_super(ip->i_sbd, gi); + else if (strcmp(arg0, "get_args") == 0) + error = gi_skeleton(ip, gi, gi_get_args); + else if (strcmp(arg0, "get_lockstruct") == 0) + error = gi_skeleton(ip, gi, gi_get_lockstruct); + else if (strcmp(arg0, "get_stat_gfs") == 0) + error = gi_skeleton(ip, gi, gi_get_stat_gfs); + else if (strcmp(arg0, "get_counters") == 0) + error = gi_skeleton(ip, gi, gi_get_counters); + else if (strcmp(arg0, "get_tune") == 0) + error = gi_skeleton(ip, gi, gi_get_tune); + else if (strcmp(arg0, "set_tune") == 0) + error = gi_set_tune(ip->i_sbd, gi, from_user); + else if (strcmp(arg0, "do_reclaim") == 0) + error = gi_skeleton(ip, gi, gi_do_reclaim); + else if (strcmp(arg0, "do_shrink") == 0) + error = gi_do_shrink(ip->i_sbd, gi); + else if (strcmp(arg0, "get_file_stat") == 0) + error = gi_get_file_stat(ip, gi); + else if (strcmp(arg0, "set_file_flag") == 0) + error = gi_set_file_flag(ip, gi, from_user); + else if (strcmp(arg0, "get_file_meta") == 0) + error = gi_get_file_meta(ip, gi); + else if (strcmp(arg0, "get_file_meta_quota") == 0) + error = gi_get_file_meta(ip->i_sbd->sd_qinode, gi); + else if (strcmp(arg0, "do_file_flush") == 0) + error = gi_do_file_flush(ip, gi); + else if (strcmp(arg0, "get_hfile_stat") == 0) + error = gi_get_hfile_stat(ip->i_sbd, gi, from_user); + else if (strcmp(arg0, "do_hfile_read") == 0) + error = gi_do_hfile_read(ip->i_sbd, gi, from_user); + else if (strcmp(arg0, "do_hfile_write") == 0) + error = gi_do_hfile_write(ip->i_sbd, gi, from_user); + else if (strcmp(arg0, "do_hfile_trunc") == 0) + error = gi_do_hfile_trunc(ip->i_sbd, gi, from_user); + else if (strcmp(arg0, "do_quota_sync") == 0) + error = gi_do_quota_sync(ip->i_sbd, gi); + else if (strcmp(arg0, "do_quota_refresh") == 0) + error = gi_do_quota_refresh(ip->i_sbd, gi, from_user); + else if (strcmp(arg0, "do_quota_read") == 0) + error = gi_do_quota_read(ip->i_sbd, gi, from_user); + else + error = -ENOTTY; + + return error; +} + +/** + * gfs_ioctl_i - Normal ioctls + * @ip: + * @arg: + * + * Returns: -errno or positive byte count + */ + +int +gfs_ioctl_i(struct gfs_inode *ip, void *arg) +{ + struct gfs_ioctl *gi_user = (struct gfs_ioctl *)arg; + struct gfs_ioctl gi; + char **argv; + char arg0[ARG_SIZE]; + int error = -EFAULT; + + if (copy_from_user(&gi, gi_user, sizeof(struct gfs_ioctl))) + return -EFAULT; + if (!gi.gi_argc) + return -EINVAL; + argv = kmalloc(gi.gi_argc * sizeof(char *), GFP_KERNEL); + if (!argv) + return -ENOMEM; + if (copy_from_user(argv, gi.gi_argv, + gi.gi_argc * sizeof(char *))) + goto out; + gi.gi_argv = argv; + + if (strncpy_from_user(arg0, argv[0], ARG_SIZE) < 0) + goto out; + arg0[ARG_SIZE - 1] = 0; + error = gfs_ioctl_i_local(ip, &gi, arg0, 1); + out: + kfree(argv); + + return error; +} + +#ifdef CONFIG_COMPAT +/** + * gfs_ioctl_i_compat - compatibility ioctls + * These ioctls are used to provide ioctls for situations + * where userland and kernel arch is different. + * For example, userland may be 32-bit ppc whereas the + * kernel may be ppc64. In this case, we need to do + * extra translation between the addresses. + * @ip: + * @arg: + * + * Returns: -errno or positive byte count + */ + +int +gfs_ioctl_i_compat(struct gfs_inode *ip, unsigned long arg) +{ + struct gfs_ioctl_compat *src; + struct gfs_ioctl dst; + char **argv, *argptr; + uint32_t *ptr; + char arg0[ARG_SIZE]; + char *tmparg; + int i; + int error = -EFAULT; + + src = (struct gfs_ioctl_compat *)compat_ptr(arg); + + memset(&dst, 0, sizeof(dst)); + dst.gi_argc = src->gi_argc; + dst.gi_size = src->gi_size; + dst.gi_offset = src->gi_offset; + + argv = kmalloc(dst.gi_argc * sizeof(char *), GFP_KERNEL); + if (!argv) + return -ENOMEM; + + memset(argv, 0, dst.gi_argc * sizeof(char *)); + ptr = (uint32_t *)compat_ptr(src->gi_argv); + + for (i = 0; i < dst.gi_argc; i++) { /* for each parm */ + tmparg = kmalloc(ARG_SIZE * sizeof(char *), GFP_KERNEL); + if (!tmparg) + goto out; + argptr = (char *)compat_ptr(*ptr); + if (strncpy_from_user(tmparg, argptr, ARG_SIZE) < 0) + goto out; + argv[i] = tmparg; + ptr++; + } + + strncpy(arg0, argv[0], ARG_SIZE); + arg0[ARG_SIZE - 1] = 0; + dst.gi_argv = argv; + dst.gi_data = compat_ptr(src->gi_data); + error = gfs_ioctl_i_local(ip, &dst, arg0, 0); + out: + for (i = 0; i < dst.gi_argc; i++) + kfree(argv[i]); + kfree(argv); + return error; +} +#endif --- linux-2.6.27.orig/ubuntu/gfs/ioctl.h +++ linux-2.6.27/ubuntu/gfs/ioctl.h @@ -0,0 +1,9 @@ +#ifndef __IOCTL_DOT_H__ +#define __IOCTL_DOT_H__ + +int gfs_ioctl_i_local(struct gfs_inode *ip, struct gfs_ioctl *gi, + const char *arg0, int from_user); +int gfs_ioctl_i_compat(struct gfs_inode *ip, unsigned long arg); +int gfs_ioctl_i(struct gfs_inode *ip, void *arg); + +#endif /* __IOCTL_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/unlinked.h +++ linux-2.6.27/ubuntu/gfs/unlinked.h @@ -0,0 +1,19 @@ +#ifndef __UNLINKED_DOT_H__ +#define __UNLINKED_DOT_H__ + +struct gfs_unlinked *gfs_unlinked_get(struct gfs_sbd *sdp, + struct gfs_inum *inum, int create); +void gfs_unlinked_hold(struct gfs_sbd *sdp, struct gfs_unlinked *ul); +void gfs_unlinked_put(struct gfs_sbd *sdp, struct gfs_unlinked *ul); + +void gfs_unlinked_lock(struct gfs_sbd *sdp, struct gfs_unlinked *ul); +void gfs_unlinked_unlock(struct gfs_sbd *sdp, struct gfs_unlinked *ul); + +void gfs_unlinked_merge(struct gfs_sbd *sdp, unsigned int type, + struct gfs_inum *inum); +void gfs_unlinked_cleanup(struct gfs_sbd *sdp); + +void gfs_unlinked_limit(struct gfs_sbd *sdp); +void gfs_unlinked_dealloc(struct gfs_sbd *sdp); + +#endif /* __UNLINKED_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/glock.h +++ linux-2.6.27/ubuntu/gfs/glock.h @@ -0,0 +1,137 @@ +#ifndef __GFS_GLOCK_DOT_H__ +#define __GFS_GLOCK_DOT_H__ + +/* Flags for lock requests; used in gfs_holder gh_flag field. */ +/* These are defined in lm_interface.h, commented out here. +#define LM_FLAG_TRY (0x00000001) +#define LM_FLAG_TRY_1CB (0x00000002) +#define LM_FLAG_NOEXP (0x00000004) +#define LM_FLAG_ANY (0x00000008) +#define LM_FLAG_PRIORITY (0x00000010) + These are defined here. */ +#define GL_LOCAL_EXCL (0x00000020) /* Only one holder may be granted the + * lock on this node, even if SHARED */ +#define GL_ASYNC (0x00000040) /* Don't block waiting for lock ... + * must poll to wait for grant */ +#define GL_EXACT (0x00000080) /* Requested state must == current state + * for lock to be granted */ +#define GL_SKIP (0x00000100) /* Don't read from disk after grant */ +#define GL_ATIME (0x00000200) /* Update inode's ATIME after grant */ +#define GL_NOCACHE (0x00000400) /* Release glock when done, don't cache */ +#define GL_SYNC (0x00000800) /* Sync to disk when no more holders */ +#define GL_NOCANCEL (0x00001000) /* Don't ever cancel this request */ +#define GL_READPAGE (0x00002000) /* gfs_readpage() issued this lock request */ +#define GL_NOCANCEL_OTHER (0x00004000) /* Don't cancel other locks for this */ + +#define GLR_TRYFAILED (13) +#define GLR_CANCELED (14) + +static __inline__ struct gfs_holder* +gfs_glock_is_locked_by_me(struct gfs_glock *gl) +{ + struct list_head *tmp, *head; + struct gfs_holder *gh; + + /* Look in glock's list of holders for one with current task as owner */ + spin_lock(&gl->gl_spin); + for (head = &gl->gl_holders, tmp = head->next; + tmp != head; + tmp = tmp->next) { + gh = list_entry(tmp, struct gfs_holder, gh_list); + if (gh->gh_owner == current) + goto out; + } + gh = NULL; +out: + spin_unlock(&gl->gl_spin); + return gh; +} +static __inline__ int +gfs_glock_is_held_excl(struct gfs_glock *gl) +{ + return (gl->gl_state == LM_ST_EXCLUSIVE); +} +static __inline__ int +gfs_glock_is_held_dfrd(struct gfs_glock *gl) +{ + return (gl->gl_state == LM_ST_DEFERRED); +} +static __inline__ int +gfs_glock_is_held_shrd(struct gfs_glock *gl) +{ + return (gl->gl_state == LM_ST_SHARED); +} + +static __inline__ int +gfs_glock_is_blocking(struct gfs_glock *gl) +{ + int ret; + spin_lock(&gl->gl_spin); + ret = !list_empty(&gl->gl_waiters2) || !list_empty(&gl->gl_waiters3); + spin_unlock(&gl->gl_spin); + return ret; +} + +struct gfs_glock *gfs_glock_find(struct gfs_sbd *sdp, + struct lm_lockname *name); +int gfs_glock_get(struct gfs_sbd *sdp, + uint64_t number, struct gfs_glock_operations *glops, + int create, struct gfs_glock **glp); +void gfs_glock_hold(struct gfs_glock *gl); +void gfs_glock_put(struct gfs_glock *gl); + +void gfs_holder_init(struct gfs_glock *gl, unsigned int state, int flags, + struct gfs_holder *gh); +void gfs_holder_reinit(unsigned int state, int flags, struct gfs_holder *gh); +void gfs_holder_uninit(struct gfs_holder *gh); +struct gfs_holder *gfs_holder_get(struct gfs_glock *gl, unsigned int state, + int flags); +void gfs_holder_put(struct gfs_holder *gh); + +void gfs_glock_xmote_th(struct gfs_glock *gl, unsigned int state, int flags); +void gfs_glock_drop_th(struct gfs_glock *gl); + +int gfs_glock_nq(struct gfs_holder *gh); +int gfs_glock_poll(struct gfs_holder *gh); +int gfs_glock_wait(struct gfs_holder *gh); +void gfs_glock_dq(struct gfs_holder *gh); + +void gfs_glock_prefetch(struct gfs_glock *gl, unsigned int state, int flags); +void gfs_glock_force_drop(struct gfs_glock *gl); + +int gfs_glock_be_greedy(struct gfs_glock *gl, unsigned int time); + +int gfs_glock_nq_init(struct gfs_glock *gl, unsigned int state, int flags, + struct gfs_holder *gh); +void gfs_glock_dq_uninit(struct gfs_holder *gh); +int gfs_glock_nq_num(struct gfs_sbd *sdp, + uint64_t number, struct gfs_glock_operations *glops, + unsigned int state, int flags, struct gfs_holder *gh); + +int gfs_glock_nq_m(unsigned int num_gh, struct gfs_holder *ghs); +void gfs_glock_dq_m(unsigned int num_gh, struct gfs_holder *ghs); + +void gfs_glock_prefetch_num(struct gfs_sbd *sdp, + uint64_t number, struct gfs_glock_operations *glops, + unsigned int state, int flags); + +/* Lock Value Block functions */ + +int gfs_lvb_hold(struct gfs_glock *gl); +void gfs_lvb_unhold(struct gfs_glock *gl); +void gfs_lvb_sync(struct gfs_glock *gl); + +void gfs_glock_cb(void *fsdata, unsigned int type, void *data); + +void gfs_try_toss_inode(struct gfs_sbd *sdp, struct gfs_inum *inum); +void gfs_iopen_go_callback(struct gfs_glock *gl, unsigned int state); + +void gfs_glock_schedule_for_reclaim(struct gfs_glock *gl); +void gfs_reclaim_glock(struct gfs_sbd *sdp); + +void gfs_scand_internal(struct gfs_sbd *sdp); +void gfs_gl_hash_clear(struct gfs_sbd *sdp, int wait); + +int gfs_dump_lockstate(struct gfs_sbd *sdp, struct gfs_user_buffer *ub); + +#endif /* __GFS_GLOCK_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/ondisk.c +++ linux-2.6.27/ubuntu/gfs/ondisk.c @@ -0,0 +1,15 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" + +#define pv(struct, member, fmt) printk(" "#member" = "fmt"\n", struct->member); + +#define WANT_GFS_CONVERSION_FUNCTIONS +#include "gfs_ondisk.h" + --- linux-2.6.27.orig/ubuntu/gfs/lock_nolock_main.c +++ linux-2.6.27/ubuntu/gfs/lock_nolock_main.c @@ -0,0 +1,230 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License version 2. + */ + +#include +#include +#include +#include +#include +#include "lm_interface.h" + +struct nolock_lockspace { + unsigned int nl_lvb_size; +}; + +static const struct lm_lockops nolock_ops; + +static int nolock_mount(char *table_name, char *host_data, + lm_callback_t cb, void *cb_data, + unsigned int min_lvb_size, int flags, + struct lm_lockstruct *lockstruct, + struct kobject *fskobj) +{ + char *c; + unsigned int jid; + struct nolock_lockspace *nl; + + c = strstr(host_data, "jid="); + if (!c) + jid = 0; + else { + c += 4; + sscanf(c, "%u", &jid); + } + + nl = kzalloc(sizeof(struct nolock_lockspace), GFP_KERNEL); + if (!nl) + return -ENOMEM; + + nl->nl_lvb_size = min_lvb_size; + + lockstruct->ls_jid = jid; + lockstruct->ls_first = 1; + lockstruct->ls_lvb_size = min_lvb_size; + lockstruct->ls_lockspace = nl; + lockstruct->ls_ops = &nolock_ops; + lockstruct->ls_flags = LM_LSFLAG_LOCAL; + + return 0; +} + +static void nolock_others_may_mount(void *lockspace) +{ +} + +static void nolock_unmount(void *lockspace) +{ + struct nolock_lockspace *nl = lockspace; + kfree(nl); +} + +static void nolock_withdraw(void *lockspace) +{ +} + +/** + * nolock_get_lock - get a lm_lock_t given a descripton of the lock + * @lockspace: the lockspace the lock lives in + * @name: the name of the lock + * @lockp: return the lm_lock_t here + * + * Returns: 0 on success, -EXXX on failure + */ + +static int nolock_get_lock(void *lockspace, struct lm_lockname *name, + void **lockp) +{ + *lockp = lockspace; + return 0; +} + +/** + * nolock_put_lock - get rid of a lock structure + * @lock: the lock to throw away + * + */ + +static void nolock_put_lock(void *lock) +{ +} + +/** + * nolock_lock - acquire a lock + * @lock: the lock to manipulate + * @cur_state: the current state + * @req_state: the requested state + * @flags: modifier flags + * + * Returns: A bitmap of LM_OUT_* + */ + +static unsigned int nolock_lock(void *lock, unsigned int cur_state, + unsigned int req_state, unsigned int flags) +{ + return req_state | LM_OUT_CACHEABLE; +} + +/** + * nolock_unlock - unlock a lock + * @lock: the lock to manipulate + * @cur_state: the current state + * + * Returns: 0 + */ + +static unsigned int nolock_unlock(void *lock, unsigned int cur_state) +{ + return 0; +} + +static void nolock_cancel(void *lock) +{ +} + +/** + * nolock_hold_lvb - hold on to a lock value block + * @lock: the lock the LVB is associated with + * @lvbp: return the lm_lvb_t here + * + * Returns: 0 on success, -EXXX on failure + */ + +static int nolock_hold_lvb(void *lock, char **lvbp) +{ + struct nolock_lockspace *nl = lock; + int error = 0; + + *lvbp = kzalloc(nl->nl_lvb_size, GFP_NOFS); + if (!*lvbp) + error = -ENOMEM; + + return error; +} + +/** + * nolock_unhold_lvb - release a LVB + * @lock: the lock the LVB is associated with + * @lvb: the lock value block + * + */ + +static void nolock_unhold_lvb(void *lock, char *lvb) +{ + kfree(lvb); +} + +static int nolock_plock_get(void *lockspace, struct lm_lockname *name, + struct file *file, struct file_lock *fl) +{ + posix_test_lock(file, fl); + + return 0; +} + +static int nolock_plock(void *lockspace, struct lm_lockname *name, + struct file *file, int cmd, struct file_lock *fl) +{ + int error; + error = posix_lock_file_wait(file, fl); + return error; +} + +static int nolock_punlock(void *lockspace, struct lm_lockname *name, + struct file *file, struct file_lock *fl) +{ + int error; + error = posix_lock_file_wait(file, fl); + return error; +} + +static void nolock_recovery_done(void *lockspace, unsigned int jid, + unsigned int message) +{ +} + +static const struct lm_lockops nolock_ops = { + .lm_proto_name = "lock_nolock", + .lm_mount = nolock_mount, + .lm_others_may_mount = nolock_others_may_mount, + .lm_unmount = nolock_unmount, + .lm_withdraw = nolock_withdraw, + .lm_get_lock = nolock_get_lock, + .lm_put_lock = nolock_put_lock, + .lm_lock = nolock_lock, + .lm_unlock = nolock_unlock, + .lm_cancel = nolock_cancel, + .lm_hold_lvb = nolock_hold_lvb, + .lm_unhold_lvb = nolock_unhold_lvb, + .lm_plock_get = nolock_plock_get, + .lm_plock = nolock_plock, + .lm_punlock = nolock_punlock, + .lm_recovery_done = nolock_recovery_done, + .lm_owner = THIS_MODULE, +}; + +int init_nolock() +{ + int error; + + error = gfs_register_lockproto(&nolock_ops); + if (error) { + printk(KERN_WARNING + "lock_nolock: can't register protocol: %d\n", error); + return error; + } + + printk(KERN_INFO + "Lock_Nolock (built %s %s) installed\n", __DATE__, __TIME__); + return 0; +} + +void exit_nolock() +{ + gfs_unregister_lockproto(&nolock_ops); +} --- linux-2.6.27.orig/ubuntu/gfs/unlinked.c +++ linux-2.6.27/ubuntu/gfs/unlinked.c @@ -0,0 +1,432 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "inode.h" +#include "log.h" +#include "lops.h" +#include "unlinked.h" + +/** + * gfs_unlinked_get - Get a structure to represent an unlinked inode + * @sdp: the filesystem + * @inum: identifies the inode that's unlinked + * @create: if TRUE, we're allowed to create the structure if we can't find it, + * otherwise return NULL + * + * Returns: the structure, or NULL + * + * Search the filesystem's list of gfs_unlinked to find a match. + * If none found, create a new one and place on list. + */ + +struct gfs_unlinked * +gfs_unlinked_get(struct gfs_sbd *sdp, struct gfs_inum *inum, int create) +{ + struct gfs_unlinked *ul = NULL, *new_ul = NULL; + struct list_head *tmp, *head; + + for (;;) { + spin_lock(&sdp->sd_unlinked_lock); + + for (head = &sdp->sd_unlinked_list, tmp = head->next; + tmp != head; + tmp = tmp->next) { + ul = list_entry(tmp, struct gfs_unlinked, ul_list); + if (gfs_inum_equal(&ul->ul_inum, inum)) { + ul->ul_count++; + break; + } + } + + if (tmp == head) + ul = NULL; + + /* 2nd pass, still not there; add the new_ul we prepared */ + if (!ul && new_ul) { + ul = new_ul; + list_add(&ul->ul_list, &sdp->sd_unlinked_list); + new_ul = NULL; + } + + spin_unlock(&sdp->sd_unlinked_lock); + + /* 1st pass; we found pre-existing, OR not allowed to create. + 2nd pass; another process added it, or we did */ + if (ul || !create) { + if (new_ul) + /* someone beat us to it; forget our new_ul */ + kfree(new_ul); + return ul; + } + + /* No match on list, 1st time through loop. + Prepare new_ul, then repeat loop to find out if another + process has created or unlinked an inode and put its + gfs_unlinked on list while we've been preparing this one. */ + new_ul = gmalloc(sizeof(struct gfs_unlinked)); + memset(new_ul, 0, sizeof(struct gfs_unlinked)); + + new_ul->ul_count = 1; + new_ul->ul_inum = *inum; + + INIT_LE(&new_ul->ul_new_le, &gfs_unlinked_lops); + INIT_LE(&new_ul->ul_incore_le, &gfs_unlinked_lops); + INIT_LE(&new_ul->ul_ondisk_le, &gfs_unlinked_lops); + } +} + +/** + * gfs_unlinked_hold - increment the usage count on a struct gfs_unlinked + * @sdp: the filesystem + * @ul: the structure + * + */ + +void +gfs_unlinked_hold(struct gfs_sbd *sdp, struct gfs_unlinked *ul) +{ + spin_lock(&sdp->sd_unlinked_lock); + gfs_assert(sdp, ul->ul_count,); + ul->ul_count++; + spin_unlock(&sdp->sd_unlinked_lock); +} + +/** + * gfs_unlinked_put - decrement the usage count on a struct gfs_unlinked + * @sdp: the filesystem + * @ul: the structure + * + * Free the structure if its reference count hits zero. + * + */ + +void +gfs_unlinked_put(struct gfs_sbd *sdp, struct gfs_unlinked *ul) +{ + spin_lock(&sdp->sd_unlinked_lock); + + gfs_assert(sdp, ul->ul_count,); + ul->ul_count--; + + if (!ul->ul_count) { + gfs_assert_warn(sdp, + !test_bit(ULF_IC_LIST, &ul->ul_flags) && + !test_bit(ULF_OD_LIST, &ul->ul_flags) && + !test_bit(ULF_LOCK, &ul->ul_flags)); + list_del(&ul->ul_list); + spin_unlock(&sdp->sd_unlinked_lock); + kfree(ul); + } else + spin_unlock(&sdp->sd_unlinked_lock); +} + +/** + * unlinked_find - Find a inode to try to deallocate + * @sdp: the filesystem + * + * The returned structure is locked and needs to be unlocked + * with gfs_unlinked_unlock(). + * + * Returns: A unlinked structure, or NULL + */ + +struct gfs_unlinked * +unlinked_find(struct gfs_sbd *sdp) +{ + struct list_head *tmp, *head; + struct gfs_unlinked *ul = NULL; + + if (test_bit(SDF_ROFS, &sdp->sd_flags)) + return NULL; + + gfs_log_lock(sdp); + spin_lock(&sdp->sd_unlinked_lock); + + if (!atomic_read(&sdp->sd_unlinked_ic_count)) + goto out; + + for (head = &sdp->sd_unlinked_list, tmp = head->next; + tmp != head; + tmp = tmp->next) { + ul = list_entry(tmp, struct gfs_unlinked, ul_list); + + if (test_bit(ULF_LOCK, &ul->ul_flags)) + continue; + if (!test_bit(ULF_IC_LIST, &ul->ul_flags)) + continue; + + list_move_tail(&ul->ul_list, &sdp->sd_unlinked_list); + + set_bit(ULF_LOCK, &ul->ul_flags); + ul->ul_count++; + + goto out; + } + + ul = NULL; + + out: + spin_unlock(&sdp->sd_unlinked_lock); + gfs_log_unlock(sdp); + + return ul; +} + +/** + * gfs_unlinked_lock - lock a unlinked structure + * @sdp: the filesystem + * @ul: the unlinked inode structure + * + */ + +void +gfs_unlinked_lock(struct gfs_sbd *sdp, struct gfs_unlinked *ul) +{ + spin_lock(&sdp->sd_unlinked_lock); + + gfs_assert_warn(sdp, !test_bit(ULF_LOCK, &ul->ul_flags)); + set_bit(ULF_LOCK, &ul->ul_flags); + + ul->ul_count++; + + spin_unlock(&sdp->sd_unlinked_lock); +} + +/** + * gfs_unlinked_unlock - drop a reference on a unlinked structure + * @sdp: the filesystem + * @ul: the unlinked inode structure + * + */ + +void +gfs_unlinked_unlock(struct gfs_sbd *sdp, struct gfs_unlinked *ul) +{ + spin_lock(&sdp->sd_unlinked_lock); + + gfs_assert_warn(sdp, test_bit(ULF_LOCK, &ul->ul_flags)); + clear_bit(ULF_LOCK, &ul->ul_flags); + + gfs_assert(sdp, ul->ul_count,); + ul->ul_count--; + + if (!ul->ul_count) { + gfs_assert_warn(sdp, !test_bit(ULF_IC_LIST, &ul->ul_flags) && + !test_bit(ULF_OD_LIST, &ul->ul_flags)); + list_del(&ul->ul_list); + spin_unlock(&sdp->sd_unlinked_lock); + kfree(ul); + } else + spin_unlock(&sdp->sd_unlinked_lock); +} + +/** + * gfs_unlinked_merge - add/remove a unlinked inode from the in-memory list + * @sdp: the filesystem + * @type: is this a unlink tag or a dealloc tag + * @inum: the inode number + * + * Called during journal recovery. + */ + +void +gfs_unlinked_merge(struct gfs_sbd *sdp, unsigned int type, + struct gfs_inum *inum) +{ + struct gfs_unlinked *ul; + + gfs_assert(sdp, atomic_read(&sdp->sd_unlinked_ic_count) == + atomic_read(&sdp->sd_unlinked_od_count),); + + ul = gfs_unlinked_get(sdp, inum, CREATE); + + gfs_log_lock(sdp); + + switch (type) { + case GFS_LOG_DESC_IUL: + gfs_unlinked_hold(sdp, ul); + gfs_unlinked_hold(sdp, ul); + gfs_assert(sdp, !test_bit(ULF_IC_LIST, &ul->ul_flags) && + !test_bit(ULF_OD_LIST, &ul->ul_flags),); + set_bit(ULF_IC_LIST, &ul->ul_flags); + set_bit(ULF_OD_LIST, &ul->ul_flags); + atomic_inc(&sdp->sd_unlinked_ic_count); + atomic_inc(&sdp->sd_unlinked_od_count); + + break; + + case GFS_LOG_DESC_IDA: + gfs_assert(sdp, test_bit(ULF_IC_LIST, &ul->ul_flags) && + test_bit(ULF_OD_LIST, &ul->ul_flags),); + clear_bit(ULF_IC_LIST, &ul->ul_flags); + clear_bit(ULF_OD_LIST, &ul->ul_flags); + gfs_unlinked_put(sdp, ul); + gfs_unlinked_put(sdp, ul); + gfs_assert(sdp, atomic_read(&sdp->sd_unlinked_ic_count) > 0,); + atomic_dec(&sdp->sd_unlinked_ic_count); + gfs_assert(sdp, atomic_read(&sdp->sd_unlinked_od_count) > 0,); + atomic_dec(&sdp->sd_unlinked_od_count); + + break; + } + + gfs_log_unlock(sdp); + + gfs_unlinked_put(sdp, ul); +} + +/** + * gfs_unlinked_cleanup - get rid of any extra struct gfs_unlinked structures + * @sdp: the filesystem + * + */ + +void +gfs_unlinked_cleanup(struct gfs_sbd *sdp) +{ + struct gfs_unlinked *ul; + + restart: + gfs_log_lock(sdp); + + gfs_assert(sdp, atomic_read(&sdp->sd_unlinked_ic_count) == + atomic_read(&sdp->sd_unlinked_od_count),); + + spin_lock(&sdp->sd_unlinked_lock); + + while (!list_empty(&sdp->sd_unlinked_list)) { + ul = list_entry(sdp->sd_unlinked_list.next, + struct gfs_unlinked, ul_list); + + if (ul->ul_count > 2) { + spin_unlock(&sdp->sd_unlinked_lock); + gfs_log_unlock(sdp); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + goto restart; + } + gfs_assert(sdp, ul->ul_count == 2,); + + gfs_assert_warn(sdp, + test_bit(ULF_IC_LIST, &ul->ul_flags) && + test_bit(ULF_OD_LIST, &ul->ul_flags) && + !test_bit(ULF_LOCK, &ul->ul_flags)); + + list_del(&ul->ul_list); + + atomic_dec(&sdp->sd_unlinked_ic_count); + atomic_dec(&sdp->sd_unlinked_od_count); + + spin_unlock(&sdp->sd_unlinked_lock); + kfree(ul); + spin_lock(&sdp->sd_unlinked_lock); + } + + spin_unlock(&sdp->sd_unlinked_lock); + + gfs_assert(sdp, !atomic_read(&sdp->sd_unlinked_ic_count) && + !atomic_read(&sdp->sd_unlinked_od_count),); + + gfs_log_unlock(sdp); +} + +/** + * gfs_unlinked_limit - limit the number of inodes waiting to be deallocated + * @sdp: the filesystem + * + * Returns: errno + */ + +void +gfs_unlinked_limit(struct gfs_sbd *sdp) +{ + unsigned int tries = 0, min = 0; + int error; + + if (atomic_read(&sdp->sd_unlinked_ic_count) >= + gfs_tune_get(sdp, gt_ilimit2)) { + tries = gfs_tune_get(sdp, gt_ilimit2_tries); + min = gfs_tune_get(sdp, gt_ilimit2_min); + } else if (atomic_read(&sdp->sd_unlinked_ic_count) >= + gfs_tune_get(sdp, gt_ilimit1)) { + tries = gfs_tune_get(sdp, gt_ilimit1_tries); + min = gfs_tune_get(sdp, gt_ilimit1_min); + } + + while (tries--) { + struct gfs_unlinked *ul = unlinked_find(sdp); + if (!ul) + break; + + error = gfs_inode_dealloc(sdp, &ul->ul_inum); + + gfs_unlinked_unlock(sdp, ul); + + if (!error) { + if (!--min) + break; + } else if (error != 1) + break; + } +} + +/** + * gfs_unlinked_dealloc - Go through the list of inodes to be deallocated + * @sdp: the filesystem + * + * Returns: errno + */ + +void +gfs_unlinked_dealloc(struct gfs_sbd *sdp) +{ + unsigned int hits, strikes; + int error; + + for (;;) { + hits = 0; + strikes = 0; + + for (;;) { + struct gfs_unlinked *ul = unlinked_find(sdp); + if (!ul) + return; + + error = gfs_inode_dealloc(sdp, &ul->ul_inum); + + gfs_unlinked_unlock(sdp, ul); + + if (!error) { + hits++; + if (strikes) + strikes--; + } else if (error == 1) { + strikes++; + if (strikes >= atomic_read(&sdp->sd_unlinked_ic_count)) { + error = 0; + break; + } + } else + goto out; + } + + if (!hits || kthread_should_stop()) + break; + + cond_resched(); + } + + out: + if (error && + error != -EROFS && + !test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) + printk("GFS: fsid=%s: error deallocating inodes: %d\n", + sdp->sd_fsname, error); +} --- linux-2.6.27.orig/ubuntu/gfs/ops_file.h +++ linux-2.6.27/ubuntu/gfs/ops_file.h @@ -0,0 +1,9 @@ +#ifndef __OPS_FILE_DOT_H__ +#define __OPS_FILE_DOT_H__ + +extern struct file_operations gfs_file_fops; +extern struct file_operations gfs_dir_fops; +extern struct file_operations gfs_file_fops_nolock; +extern struct file_operations gfs_dir_fops_nolock; + +#endif /* __OPS_FILE_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/rgrp.c +++ linux-2.6.27/ubuntu/gfs/rgrp.c @@ -0,0 +1,2152 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "bits.h" +#include "dio.h" +#include "file.h" +#include "glock.h" +#include "glops.h" +#include "rgrp.h" +#include "super.h" +#include "trans.h" + +/** + * mhc_hash: find the mhc hash bucket for a buffer + * @bh: the buffer + * + * Returns: The bucket number + */ + +static unsigned int +mhc_hash(struct buffer_head *bh) +{ + uint64_t blkno; + unsigned int h; + + blkno = bh->b_blocknr; + h = gfs_hash(&blkno, sizeof(uint64_t)) & GFS_MHC_HASH_MASK; + + return h; +} + +/** + * mhc_trim - Throw away cached meta-headers, if there are too many of them + * @sdp: The filesystem instance + * @max: Max # of cached meta-headers allowed to survive + * + * Walk filesystem's list of cached meta-headers, in least-recently-used order, + * and keep throwing them away until we're under the max threshold. + */ + +static void +mhc_trim(struct gfs_sbd *sdp, unsigned int max) +{ + struct gfs_meta_header_cache *mc; + + for (;;) { + spin_lock(&sdp->sd_mhc_lock); + if (list_empty(&sdp->sd_mhc_single)) { + spin_unlock(&sdp->sd_mhc_lock); + return; + } else { + mc = list_entry(sdp->sd_mhc_single.prev, + struct gfs_meta_header_cache, + mc_list_single); + list_del(&mc->mc_list_hash); + list_del(&mc->mc_list_single); + list_del(&mc->mc_list_rgd); + spin_unlock(&sdp->sd_mhc_lock); + + kmem_cache_free(gfs_mhc_cachep, mc); + atomic_dec(&sdp->sd_mhc_count); + + if (atomic_read(&sdp->sd_mhc_count) <= max) + return; + } + } +} + +/** + * gfs_mhc_add - add buffer(s) to the cache of metadata headers + * @rgd: Resource Group in which the buffered block(s) reside + * @bh: an array of buffer_head pointers + * @num: the number of bh pointers in the array + * + * Increment each meta-header's generation # by 2. + * Alloc and add each gfs_meta-header_cache to 3 lists/caches: + * Filesystem's meta-header cache (hash) + * Filesystem's list of cached meta-headers + * Resource Group's list of cached meta-headers + * If we now have too many cached, throw some older ones away + */ + +void +gfs_mhc_add(struct gfs_rgrpd *rgd, + struct buffer_head **bh, unsigned int num) +{ + struct gfs_sbd *sdp = rgd->rd_sbd; + unsigned int x; + + for (x = 0; x < num; x++) { + struct gfs_meta_header_cache *mc; + struct list_head *head; + uint64_t gen; + + if (gfs_meta_check(sdp, bh[x])) + return; + + mc = kmem_cache_alloc(gfs_mhc_cachep, GFP_KERNEL); + if (!mc) + return; + memset(mc, 0, sizeof(struct gfs_meta_header_cache)); + + mc->mc_block = bh[x]->b_blocknr; + memcpy(&mc->mc_mh, bh[x]->b_data, + sizeof(struct gfs_meta_header)); + + gen = gfs64_to_cpu(mc->mc_mh.mh_generation) + 2; + mc->mc_mh.mh_generation = cpu_to_gfs64(gen); + + head = &sdp->sd_mhc[mhc_hash(bh[x])]; + + spin_lock(&sdp->sd_mhc_lock); + list_add(&mc->mc_list_hash, head); + list_add(&mc->mc_list_single, &sdp->sd_mhc_single); + list_add(&mc->mc_list_rgd, &rgd->rd_mhc); + spin_unlock(&sdp->sd_mhc_lock); + + atomic_inc(&sdp->sd_mhc_count); + } + + x = gfs_tune_get(sdp, gt_max_mhc); + + /* If we've got too many cached, throw some older ones away */ + if (atomic_read(&sdp->sd_mhc_count) > x) + mhc_trim(sdp, x); +} + +/** + * gfs_mhc_fish - Try to fill in a meta buffer with meta-header from the cache + * @sdp: the filesystem + * @bh: the buffer to fill in + * + * Returns: TRUE if the buffer was cached, FALSE otherwise + * + * If buffer is referenced in meta-header cache (search using hash): + * Copy the cached meta-header into the buffer (instead of reading from disk). + * Note that only the meta-header portion of the buffer will have valid data + * (as would be on disk), rest of buffer does *not* reflect disk contents. + * Remove cached gfs_meta_header_cache from all cache lists, free its memory. + */ + +int +gfs_mhc_fish(struct gfs_sbd *sdp, struct buffer_head *bh) +{ + struct list_head *tmp, *head; + struct gfs_meta_header_cache *mc; + + head = &sdp->sd_mhc[mhc_hash(bh)]; + + spin_lock(&sdp->sd_mhc_lock); + + for (tmp = head->next; + tmp != head; + tmp = tmp->next) { + mc = list_entry(tmp, struct gfs_meta_header_cache, mc_list_hash); + if (mc->mc_block != bh->b_blocknr) + continue; + + list_del(&mc->mc_list_hash); + list_del(&mc->mc_list_single); + list_del(&mc->mc_list_rgd); + spin_unlock(&sdp->sd_mhc_lock); + + gfs_prep_new_buffer(bh); + memcpy(bh->b_data, &mc->mc_mh, + sizeof(struct gfs_meta_header)); + + kmem_cache_free(gfs_mhc_cachep, mc); + atomic_dec(&sdp->sd_mhc_count); + + return TRUE; + } + + spin_unlock(&sdp->sd_mhc_lock); + + return FALSE; +} + +/** + * gfs_mhc_zap - Throw away an RG's list of cached metadata headers + * @rgd: The resource group whose list we want to clear + * + * Simply throw away all cached metadata headers on RG's list, + * and free their memory. + */ + +void +gfs_mhc_zap(struct gfs_rgrpd *rgd) +{ + struct gfs_sbd *sdp = rgd->rd_sbd; + struct gfs_meta_header_cache *mc; + + spin_lock(&sdp->sd_mhc_lock); + + while (!list_empty(&rgd->rd_mhc)) { + mc = list_entry(rgd->rd_mhc.next, + struct gfs_meta_header_cache, + mc_list_rgd); + + list_del(&mc->mc_list_hash); + list_del(&mc->mc_list_single); + list_del(&mc->mc_list_rgd); + spin_unlock(&sdp->sd_mhc_lock); + + kmem_cache_free(gfs_mhc_cachep, mc); + atomic_dec(&sdp->sd_mhc_count); + + spin_lock(&sdp->sd_mhc_lock); + } + + spin_unlock(&sdp->sd_mhc_lock); +} + +/** + * depend_hash() - Turn glock number into hash bucket number + * @formal_ino: + * + * Returns: The number of the corresponding hash bucket + */ + +static unsigned int +depend_hash(uint64_t formal_ino) +{ + unsigned int h; + + h = gfs_hash(&formal_ino, sizeof(uint64_t)); + h &= GFS_DEPEND_HASH_MASK; + + return h; +} + +/** + * depend_sync_one - Sync metadata (not data) for a dependency inode + * @sdp: filesystem instance + * @gd: dependency descriptor + * + * Remove dependency from superblock's hash table and rgrp's list. + * Sync dependency inode's metadata to log and in-place location. + */ + +static void +depend_sync_one(struct gfs_sbd *sdp, struct gfs_depend *gd) +{ + struct gfs_glock *gl; + + spin_lock(&sdp->sd_depend_lock); + list_del(&gd->gd_list_hash); + spin_unlock(&sdp->sd_depend_lock); + list_del(&gd->gd_list_rgd); + + gl = gfs_glock_find(sdp, + &(struct lm_lockname){gd->gd_formal_ino, + LM_TYPE_INODE}); + if (gl) { + if (gl->gl_ops->go_sync) + gl->gl_ops->go_sync(gl, + DIO_METADATA | + DIO_INVISIBLE); + gfs_glock_put(gl); + } + + kfree(gd); + atomic_dec(&sdp->sd_depend_count); +} + +/** + * depend_sync_old - Sync older rgrp-dependent inodes to disk. + * @rgd: Resource group containing dependent inodes + * + * Look at oldest entries in resource group's dependency list, + * sync 'em if they're older than timeout threshold. + */ + +static void +depend_sync_old(struct gfs_rgrpd *rgd) +{ + struct gfs_sbd *sdp = rgd->rd_sbd; + struct gfs_depend *gd; + + while (!list_empty(&rgd->rd_depend)) { + /* Oldest entries are in prev direction */ + gd = list_entry(rgd->rd_depend.prev, + struct gfs_depend, + gd_list_rgd); + + if (time_before(jiffies, + gd->gd_time + + gfs_tune_get(sdp, gt_depend_secs) * HZ)) + return; + + depend_sync_one(sdp, gd); + } +} + +/** + * gfs_depend_add - Add a dependent inode to rgrp's and filesystem's list + * @rgd: Resource group containing blocks associated with inode + * @formal_ino: inode + * + * Dependent inodes must be flushed to log and in-place blocks before + * releasing an EXCLUSIVE rgrp lock. + * Find pre-existing dependency for this inode/rgrp combination in + * incore superblock struct's sd_depend hash table, or create a new one. + * Either way, move or attach dependency to head of superblock's hash bucket + * and top of rgrp's list. + * If we create a new one, take a moment to sync older dependencies to disk. + */ + +void +gfs_depend_add(struct gfs_rgrpd *rgd, uint64_t formal_ino) +{ + struct gfs_sbd *sdp = rgd->rd_sbd; + struct list_head *head, *tmp; + struct gfs_depend *gd; + + head = &sdp->sd_depend[depend_hash(formal_ino)]; + + spin_lock(&sdp->sd_depend_lock); + + for (tmp = head->next; + tmp != head; + tmp = tmp->next) { + gd = list_entry(tmp, struct gfs_depend, gd_list_hash); + if (gd->gd_rgd == rgd && + gd->gd_formal_ino == formal_ino) { + list_move(&gd->gd_list_hash, head); + spin_unlock(&sdp->sd_depend_lock); + list_move(&gd->gd_list_rgd, &rgd->rd_depend); + gd->gd_time = jiffies; + return; + } + } + + spin_unlock(&sdp->sd_depend_lock); + + gd = gmalloc(sizeof(struct gfs_depend)); + memset(gd, 0, sizeof(struct gfs_depend)); + + gd->gd_rgd = rgd; + gd->gd_formal_ino = formal_ino; + gd->gd_time = jiffies; + + spin_lock(&sdp->sd_depend_lock); + list_add(&gd->gd_list_hash, head); + spin_unlock(&sdp->sd_depend_lock); + list_add(&gd->gd_list_rgd, &rgd->rd_depend); + + atomic_inc(&sdp->sd_depend_count); + + depend_sync_old(rgd); +} + +/** + * gfs_depend_sync - Sync metadata (not data) for an rgrp's dependent inodes + * @rgd: Resource group containing the dependent inodes + * + * As long as this node owns an EXCLUSIVE lock on the rgrp, we can keep + * rgrp's modified metadata blocks in buffer cache. + * + * When this node releases the EX lock, we must flush metadata, so other + * nodes can read the modified content from disk. + */ + +void +gfs_depend_sync(struct gfs_rgrpd *rgd) +{ + struct gfs_sbd *sdp = rgd->rd_sbd; + struct gfs_depend *gd; + + while (!list_empty(&rgd->rd_depend)) { + gd = list_entry(rgd->rd_depend.next, + struct gfs_depend, + gd_list_rgd); + depend_sync_one(sdp, gd); + } +} + +/** + * rgrp_verify - Verify that a resource group is consistent + * @sdp: the filesystem + * @rgd: the rgrp + * + * Somebody should have already called gfs_glock_rg() on this RG. + */ + +static void +rgrp_verify(struct gfs_rgrpd *rgd) +{ + struct gfs_sbd *sdp = rgd->rd_sbd; + struct gfs_bitmap *bits = NULL; + uint32_t length = rgd->rd_ri.ri_length; + uint32_t count[4], tmp; + int buf, x; + + memset(count, 0, 4 * sizeof(uint32_t)); + + /* Count # blocks in each of 4 possible allocation states */ + for (buf = 0; buf < length; buf++) { + bits = &rgd->rd_bits[buf]; + for (x = 0; x < 4; x++) + count[x] += gfs_bitcount(rgd, + rgd->rd_bh[buf]->b_data + + bits->bi_offset, + bits->bi_len, x); + } + + if (count[0] != rgd->rd_rg.rg_free) { + if (gfs_consist_rgrpd(rgd)) + printk("GFS: fsid=%s: free data mismatch: %u != %u\n", + sdp->sd_fsname, count[0], rgd->rd_rg.rg_free); + return; + } + + tmp = rgd->rd_ri.ri_data - + (rgd->rd_rg.rg_usedmeta + rgd->rd_rg.rg_freemeta) - + (rgd->rd_rg.rg_useddi + rgd->rd_rg.rg_freedi) - + rgd->rd_rg.rg_free; + if (count[1] != tmp) { + if (gfs_consist_rgrpd(rgd)) + printk("GFS: fsid=%s: used data mismatch: %u != %u\n", + sdp->sd_fsname, count[1], tmp); + return; + } + + if (count[2] != rgd->rd_rg.rg_freemeta) { + if (gfs_consist_rgrpd(rgd)) + printk("GFS: fsid=%s: free metadata mismatch: %u != %u\n", + sdp->sd_fsname, count[2], rgd->rd_rg.rg_freemeta); + return; + } + + tmp = rgd->rd_rg.rg_usedmeta + + (rgd->rd_rg.rg_useddi + rgd->rd_rg.rg_freedi); + if (count[3] != tmp) { + if (gfs_consist_rgrpd(rgd)) + printk("GFS: fsid=%s: used metadata mismatch: %u != %u\n", + sdp->sd_fsname, count[3], tmp); + return; + } +} + +/** + * gfs_blk2rgrpd - Find resource group for a given data/meta block number + * @sdp: The GFS superblock + * @n: The data block number + * + * Returns: The resource group, or NULL if not found + * + * Don't try to use this for non-allocatable block numbers (i.e. rgrp header + * or bitmap blocks); it's for allocatable (data/meta) blocks only. + */ + +struct gfs_rgrpd * +gfs_blk2rgrpd(struct gfs_sbd *sdp, uint64_t blk) +{ + struct list_head *tmp, *head; + struct gfs_rgrpd *rgd = NULL; + struct gfs_rindex *ri; + + spin_lock(&sdp->sd_rg_mru_lock); + + for (head = &sdp->sd_rg_mru_list, tmp = head->next; + tmp != head; + tmp = tmp->next) { + rgd = list_entry(tmp, struct gfs_rgrpd, rd_list_mru); + ri = &rgd->rd_ri; + + if (ri->ri_data1 <= blk && blk < ri->ri_data1 + ri->ri_data) { + list_move(&rgd->rd_list_mru, &sdp->sd_rg_mru_list); + spin_unlock(&sdp->sd_rg_mru_lock); + return rgd; + } + } + + spin_unlock(&sdp->sd_rg_mru_lock); + + return NULL; +} + +/** + * gfs_rgrpd_get_first - get the first Resource Group in the filesystem + * @sdp: The GFS superblock + * + * Returns: The first rgrp in the filesystem + */ + +struct gfs_rgrpd * +gfs_rgrpd_get_first(struct gfs_sbd *sdp) +{ + gfs_assert(sdp, !list_empty(&sdp->sd_rglist),); + return list_entry(sdp->sd_rglist.next, struct gfs_rgrpd, rd_list); +} + +/** + * gfs_rgrpd_get_next - get the next RG + * @rgd: A RG + * + * Returns: The next rgrp + */ + +struct gfs_rgrpd * +gfs_rgrpd_get_next(struct gfs_rgrpd *rgd) +{ + if (rgd->rd_list.next == &rgd->rd_sbd->sd_rglist) + return NULL; + return list_entry(rgd->rd_list.next, struct gfs_rgrpd, rd_list); +} + +/** + * clear_rgrpdi - Clear up rgrps + * @sdp: The GFS superblock + * + */ + +void +clear_rgrpdi(struct gfs_sbd *sdp) +{ + struct gfs_rgrpd *rgd; + struct gfs_glock *gl; + + spin_lock(&sdp->sd_rg_forward_lock); + sdp->sd_rg_forward = NULL; + spin_unlock(&sdp->sd_rg_forward_lock); + + spin_lock(&sdp->sd_rg_recent_lock); + while (!list_empty(&sdp->sd_rg_recent)) { + rgd = list_entry(sdp->sd_rg_recent.next, + struct gfs_rgrpd, rd_recent); + list_del(&rgd->rd_recent); + } + spin_unlock(&sdp->sd_rg_recent_lock); + + while (!list_empty(&sdp->sd_rglist)) { + rgd = list_entry(sdp->sd_rglist.next, + struct gfs_rgrpd, rd_list); + gl = rgd->rd_gl; + + list_del(&rgd->rd_list); + list_del(&rgd->rd_list_mru); + + if (gl) { + gfs_glock_force_drop(gl); + if (atomic_read(&gl->gl_lvb_count)) + gfs_lvb_unhold(gl); + set_gl2rgd(gl, NULL); + gfs_glock_put(gl); + } + + if (rgd->rd_bits) + kfree(rgd->rd_bits); + if (rgd->rd_bh) + kfree(rgd->rd_bh); + + kfree(rgd); + } +} + +/** + * gfs_clear_rgrpd - Clear up rgrps + * @sdp: The GFS superblock + * + */ + +void +gfs_clear_rgrpd(struct gfs_sbd *sdp) +{ + down(&sdp->sd_rindex_lock); + clear_rgrpdi(sdp); + up(&sdp->sd_rindex_lock); +} + +/** + * gfs_compute_bitstructs - Compute the bitmap sizes + * @rgd: The resource group descriptor + * + * Calculates bitmap descriptors, one for each block that contains bitmap data + * + * Returns: errno + */ + +static int +compute_bitstructs(struct gfs_rgrpd *rgd) +{ + struct gfs_sbd *sdp = rgd->rd_sbd; + struct gfs_bitmap *bits; + uint32_t length = rgd->rd_ri.ri_length; /* # blocks in hdr & bitmap */ + uint32_t bytes_left, bytes; + int x; + + rgd->rd_bits = kmalloc(length * sizeof(struct gfs_bitmap), GFP_KERNEL); + if (!rgd->rd_bits) + return -ENOMEM; + memset(rgd->rd_bits, 0, length * sizeof(struct gfs_bitmap)); + + bytes_left = rgd->rd_ri.ri_bitbytes; + + for (x = 0; x < length; x++) { + bits = &rgd->rd_bits[x]; + + /* small rgrp; bitmap stored completely in header block */ + if (length == 1) { + bytes = bytes_left; + bits->bi_offset = sizeof(struct gfs_rgrp); + bits->bi_start = 0; + bits->bi_len = bytes; + /* header block */ + } else if (x == 0) { + bytes = sdp->sd_sb.sb_bsize - sizeof(struct gfs_rgrp); + bits->bi_offset = sizeof(struct gfs_rgrp); + bits->bi_start = 0; + bits->bi_len = bytes; + /* last block */ + } else if (x + 1 == length) { + bytes = bytes_left; + bits->bi_offset = sizeof(struct gfs_meta_header); + bits->bi_start = rgd->rd_ri.ri_bitbytes - bytes_left; + bits->bi_len = bytes; + /* other blocks */ + } else { + bytes = sdp->sd_sb.sb_bsize - sizeof(struct gfs_meta_header); + bits->bi_offset = sizeof(struct gfs_meta_header); + bits->bi_start = rgd->rd_ri.ri_bitbytes - bytes_left; + bits->bi_len = bytes; + } + + bytes_left -= bytes; + } + + if (bytes_left) { + gfs_consist_rgrpd(rgd); + return -EIO; + } + if ((rgd->rd_bits[length - 1].bi_start + + rgd->rd_bits[length - 1].bi_len) * GFS_NBBY != + rgd->rd_ri.ri_data) { + if (gfs_consist_rgrpd(rgd)) { + gfs_rindex_print(&rgd->rd_ri); + printk("GFS: fsid=%s: start=%u len=%u offset=%u\n", + sdp->sd_fsname, + rgd->rd_bits[length - 1].bi_start, + rgd->rd_bits[length - 1].bi_len, + rgd->rd_bits[length - 1].bi_offset); + } + return -EIO; + } + + rgd->rd_bh = kmalloc(length * sizeof(struct buffer_head *), GFP_KERNEL); + if (!rgd->rd_bh) { + kfree(rgd->rd_bits); + rgd->rd_bits = NULL; + return -ENOMEM; + } + memset(rgd->rd_bh, 0, length * sizeof(struct buffer_head *)); + + return 0; +} + +/** + * gfs_ri_update - Pull in a new resource index from the disk + * @gl: The glock covering the rindex inode + * + * Returns: 0 on successful update, error code otherwise + */ + +static int +gfs_ri_update(struct gfs_inode *ip) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_rgrpd *rgd; + char buf[sizeof(struct gfs_rindex)]; + int error; + + if (do_mod(ip->i_di.di_size, sizeof(struct gfs_rindex))) { + gfs_consist_inode(ip); + return -EIO; + } + + clear_rgrpdi(sdp); + + for (sdp->sd_rgcount = 0;; sdp->sd_rgcount++) { + error = gfs_internal_read(ip, buf, + sdp->sd_rgcount * + sizeof(struct gfs_rindex), + sizeof(struct gfs_rindex)); + if (!error) + break; + if (error != sizeof(struct gfs_rindex)) { + if (error > 0) + error = -EIO; + goto fail; + } + + rgd = kmalloc(sizeof(struct gfs_rgrpd), GFP_KERNEL); + error = -ENOMEM; + if (!rgd) + goto fail; + memset(rgd, 0, sizeof(struct gfs_rgrpd)); + + INIT_LIST_HEAD(&rgd->rd_mhc); + INIT_LIST_HEAD(&rgd->rd_depend); + rgd->rd_sbd = sdp; + + list_add_tail(&rgd->rd_list, &sdp->sd_rglist); + list_add_tail(&rgd->rd_list_mru, &sdp->sd_rg_mru_list); + + gfs_rindex_in(&rgd->rd_ri, buf); + + error = compute_bitstructs(rgd); + if (error) + goto fail; + + error = gfs_glock_get(sdp, rgd->rd_ri.ri_addr, &gfs_rgrp_glops, + CREATE, &rgd->rd_gl); + if (error) + goto fail; + + error = gfs_lvb_hold(rgd->rd_gl); + if (error) + goto fail; + + set_gl2rgd(rgd->rd_gl, rgd); + rgd->rd_rg_vn = rgd->rd_gl->gl_vn - 1; + } + + sdp->sd_riinode_vn = ip->i_gl->gl_vn; + + return 0; + + fail: + clear_rgrpdi(sdp); + + return error; +} + +/** + * gfs_rindex_hold - Grab a lock on the rindex + * @sdp: The GFS superblock + * @ri_gh: the glock holder + * + * We grab a lock on the rindex inode to make sure that it doesn't + * change whilst we are performing an operation. We keep this lock + * for quite long periods of time compared to other locks. This + * doesn't matter, since it is shared and it is very, very rarely + * accessed in the exclusive mode (i.e. only when expanding the filesystem). + * + * This makes sure that we're using the latest copy of the resource index + * special file, which might have been updated if someone expanded the + * filesystem (via gfs_grow utility), which adds new resource groups. + * + * Returns: 0 on success, error code otherwise + */ + +int +gfs_rindex_hold(struct gfs_sbd *sdp, struct gfs_holder *ri_gh) +{ + struct gfs_inode *ip = sdp->sd_riinode; + struct gfs_glock *gl = ip->i_gl; + int error; + + error = gfs_glock_nq_init(gl, LM_ST_SHARED, 0, ri_gh); + if (error) + return error; + + /* Read new copy from disk if we don't have the latest */ + if (sdp->sd_riinode_vn != gl->gl_vn) { + down(&sdp->sd_rindex_lock); + if (sdp->sd_riinode_vn != gl->gl_vn) { + error = gfs_ri_update(ip); + if (error) + gfs_glock_dq_uninit(ri_gh); + } + up(&sdp->sd_rindex_lock); + } + + return error; +} + +/** + * gfs_rgrp_read - Read in a RG's header and bitmaps + * @rgd: the struct gfs_rgrpd describing the RG to read in + * + * Read in all of a Resource Group's header and bitmap blocks. + * Caller must eventually call gfs_rgrp_relse() to free the bitmaps. + * + * Returns: errno + */ + +int +gfs_rgrp_read(struct gfs_rgrpd *rgd) +{ + struct gfs_sbd *sdp = rgd->rd_sbd; + struct gfs_glock *gl = rgd->rd_gl; + unsigned int x, length = rgd->rd_ri.ri_length; + int error; + + for (x = 0; x < length; x++) { + gfs_assert_warn(sdp, !rgd->rd_bh[x]); + rgd->rd_bh[x] = gfs_dgetblk(gl, rgd->rd_ri.ri_addr + x); + } + + for (x = 0; x < length; x++) { + error = gfs_dreread(sdp, rgd->rd_bh[x], DIO_START); + if (error) + goto fail; + } + + for (x = length; x--;) { + error = gfs_dreread(sdp, rgd->rd_bh[x], DIO_WAIT); + if (error) + goto fail; + if (gfs_metatype_check(sdp, rgd->rd_bh[x], + (x) ? GFS_METATYPE_RB : GFS_METATYPE_RG)) { + error = -EIO; + goto fail; + } + } + + if (rgd->rd_rg_vn != gl->gl_vn) { + gfs_rgrp_in(&rgd->rd_rg, (rgd->rd_bh[0])->b_data); + rgd->rd_rg_vn = gl->gl_vn; + } + + return 0; + + fail: + for (x = 0; x < length; x++) { + brelse(rgd->rd_bh[x]); + rgd->rd_bh[x] = NULL; + } + + return error; +} + +/** + * gfs_rgrp_relse - Release RG bitmaps read in with gfs_rgrp_read() + * @rgd: the struct gfs_rgrpd describing the RG to read in + * + */ + +void +gfs_rgrp_relse(struct gfs_rgrpd *rgd) +{ + int x, length = rgd->rd_ri.ri_length; + + for (x = 0; x < length; x++) { + brelse(rgd->rd_bh[x]); + rgd->rd_bh[x] = NULL; + } +} + +/** + * gfs_rgrp_lvb_fill - copy RG usage data out of the struct gfs_rgrp into the struct gfs_rgrp_lvb + * @rgd: the resource group data structure + * + */ + +void +gfs_rgrp_lvb_fill(struct gfs_rgrpd *rgd) +{ + struct gfs_rgrp *rg = &rgd->rd_rg; + struct gfs_rgrp_lvb *rb = (struct gfs_rgrp_lvb *)rgd->rd_gl->gl_lvb; + + rb->rb_magic = cpu_to_gfs32(GFS_MAGIC); + rb->rb_free = cpu_to_gfs32(rg->rg_free); + rb->rb_useddi = cpu_to_gfs32(rg->rg_useddi); + rb->rb_freedi = cpu_to_gfs32(rg->rg_freedi); + rb->rb_usedmeta = cpu_to_gfs32(rg->rg_usedmeta); + rb->rb_freemeta = cpu_to_gfs32(rg->rg_freemeta); +} + +/** + * gfs_rgrp_lvb_init - Init the data of a RG LVB + * @rgd: the resource group data structure + * + * Returns: errno + */ + +int +gfs_rgrp_lvb_init(struct gfs_rgrpd *rgd) +{ + struct gfs_glock *gl = rgd->rd_gl; + struct gfs_holder rgd_gh; + int error; + + error = gfs_glock_nq_init(gl, LM_ST_EXCLUSIVE, 0, &rgd_gh); + if (!error) { + gfs_rgrp_lvb_fill(rgd); + gfs_glock_dq_uninit(&rgd_gh); + } + + return error; +} + +/** + * gfs_alloc_get - allocate a struct gfs_alloc structure for an inode + * @ip: the incore GFS inode structure + * + * Alloc and zero an in-place reservation structure, + * and attach it to the GFS incore inode. + * + * FIXME: Don't use gmalloc() + * + * Returns: the struct gfs_alloc + */ + +struct gfs_alloc * +gfs_alloc_get(struct gfs_inode *ip) +{ + struct gfs_alloc *al = ip->i_alloc; + + gfs_assert_warn(ip->i_sbd, !al); + + al = gmalloc(sizeof(struct gfs_alloc)); + memset(al, 0, sizeof(struct gfs_alloc)); + + ip->i_alloc = al; + + return al; +} + +/** + * gfs_alloc_put - throw away the struct gfs_alloc for an inode + * @ip: the inode + * + */ + +void +gfs_alloc_put(struct gfs_inode *ip) +{ + struct gfs_alloc *al = ip->i_alloc; + + if (gfs_assert_warn(ip->i_sbd, al)) + return; + + ip->i_alloc = NULL; + kfree(al); +} + +/** + * try_rgrp_fit - See if a given reservation will fit in a given RG + * @rgd: the RG data + * @al: the struct gfs_alloc structure describing the reservation + * + * If there's room for the requested blocks to be allocated from the RG: + * Sets the $al_reserved_data field in @al. + * Sets the $al_reserved_meta field in @al. + * Sets the $al_rgd field in @al. + * + * Returns: 1 on success (it fits), 0 on failure (it doesn't fit) + */ + +static int +try_rgrp_fit(struct gfs_rgrpd *rgd, struct gfs_alloc *al) +{ + uint32_t freeblks = rgd->rd_rg.rg_free; + uint32_t freemeta = rgd->rd_rg.rg_freemeta; + uint32_t metares = al->al_requested_meta; + uint32_t datares = al->al_requested_data; + + /* First take care of the data blocks required */ + + if (freeblks < al->al_requested_data) + return 0; + + freeblks -= al->al_requested_data; + + /* Then take care of the dinodes */ + + metares += al->al_requested_di; + + /* Then take care of the metadata blocks */ + + while (freemeta < metares) { + if (freeblks < GFS_META_CLUMP) + return 0; + + freeblks -= GFS_META_CLUMP; + freemeta += GFS_META_CLUMP; + + datares += GFS_META_CLUMP; + } + + al->al_rgd = rgd; + al->al_reserved_meta = metares; + al->al_reserved_data = datares; + + return 1; +} + +/** + * recent_rgrp_first - get first RG from "recent" list + * @sdp: The GFS superblock + * @rglast: address of the rgrp used last + * + * Returns: The first rgrp in the recent list + */ + +static struct gfs_rgrpd * +recent_rgrp_first(struct gfs_sbd *sdp, uint64_t rglast) +{ + struct list_head *tmp, *head; + struct gfs_rgrpd *rgd = NULL; + + spin_lock(&sdp->sd_rg_recent_lock); + + if (list_empty(&sdp->sd_rg_recent)) + goto out; + + if (!rglast) + goto first; + + for (head = &sdp->sd_rg_recent, tmp = head->next; + tmp != head; + tmp = tmp->next) { + rgd = list_entry(tmp, struct gfs_rgrpd, rd_recent); + if (rgd->rd_ri.ri_addr == rglast) + goto out; + } + + first: + rgd = list_entry(sdp->sd_rg_recent.next, struct gfs_rgrpd, rd_recent); + + out: + spin_unlock(&sdp->sd_rg_recent_lock); + + return rgd; +} + +/** + * recent_rgrp_next - get next RG from "recent" list + * @cur_rgd: current rgrp + * @remove: + * + * Returns: The next rgrp in the recent list + */ + +static struct gfs_rgrpd * +recent_rgrp_next(struct gfs_rgrpd *cur_rgd, int remove) +{ + struct gfs_sbd *sdp = cur_rgd->rd_sbd; + struct list_head *tmp, *head; + struct gfs_rgrpd *rgd; + + spin_lock(&sdp->sd_rg_recent_lock); + + for (head = &sdp->sd_rg_recent, tmp = head->next; + tmp != head; + tmp = tmp->next) { + rgd = list_entry(tmp, struct gfs_rgrpd, rd_recent); + if (rgd == cur_rgd) { + if (cur_rgd->rd_recent.next != head) + rgd = list_entry(cur_rgd->rd_recent.next, + struct gfs_rgrpd, rd_recent); + else + rgd = NULL; + + if (remove) + list_del(&cur_rgd->rd_recent); + + goto out; + } + } + + rgd = NULL; + if (!list_empty(head)) + rgd = list_entry(head->next, struct gfs_rgrpd, rd_recent); + + out: + spin_unlock(&sdp->sd_rg_recent_lock); + + return rgd; +} + +/** + * recent_rgrp_add - add an RG to tail of "recent" list + * @new_rgd: The rgrp to add + * + * Before adding, make sure that: + * 1) it's not already on the list + * 2) there's still room for more entries + * The capacity limit imposed on the "recent" list is basically a node's "share" + * of rgrps within a cluster, i.e. (total # rgrps) / (# nodes (journals)) + */ + +static void +recent_rgrp_add(struct gfs_rgrpd *new_rgd) +{ + struct gfs_sbd *sdp = new_rgd->rd_sbd; + struct list_head *tmp, *head; + struct gfs_rgrpd *rgd = NULL; + unsigned int count = 0; + unsigned int max = sdp->sd_rgcount / gfs_num_journals(sdp); + + spin_lock(&sdp->sd_rg_recent_lock); + + for (head = &sdp->sd_rg_recent, tmp = head->next; + tmp != head; + tmp = tmp->next) { + rgd = list_entry(tmp, struct gfs_rgrpd, rd_recent); + if (rgd == new_rgd) + goto out; + + if (++count >= max) + goto out; + } + new_rgd->rd_try_counter = 0; + list_add_tail(&new_rgd->rd_recent, &sdp->sd_rg_recent); + + out: + spin_unlock(&sdp->sd_rg_recent_lock); +} + +/** + * forward_rgrp_get - get an rgrp to try next from full list + * @sdp: The GFS superblock + * + * Returns: The rgrp to try next + */ + +static struct gfs_rgrpd * +forward_rgrp_get(struct gfs_sbd *sdp) +{ + struct gfs_rgrpd *rgd; + unsigned int journals = gfs_num_journals(sdp); + unsigned int rg = 0, x; + + spin_lock(&sdp->sd_rg_forward_lock); + + rgd = sdp->sd_rg_forward; + if (!rgd) { + if (sdp->sd_rgcount >= journals) + rg = sdp->sd_rgcount * + sdp->sd_lockstruct.ls_jid / + journals; + + for (x = 0, rgd = gfs_rgrpd_get_first(sdp); + x < rg; + x++, rgd = gfs_rgrpd_get_next(rgd)) + /* Do Nothing */; + + sdp->sd_rg_forward = rgd; + } + + spin_unlock(&sdp->sd_rg_forward_lock); + + return rgd; +} + +/** + * forward_rgrp_set - set the forward rgrp pointer + * @sdp: the filesystem + * @rgd: The new forward rgrp + * + */ + +static void +forward_rgrp_set(struct gfs_sbd *sdp, struct gfs_rgrpd *rgd) +{ + spin_lock(&sdp->sd_rg_forward_lock); + sdp->sd_rg_forward = rgd; + spin_unlock(&sdp->sd_rg_forward_lock); +} + +/** + * get_local_rgrp - Choose and lock a rgrp for allocation + * @ip: the inode to reserve space for + * @rgp: the chosen and locked rgrp + * + * Try to acquire rgrp in way which avoids contending with others. + * + * Returns: errno + */ + +static int +get_local_rgrp(struct gfs_inode *ip) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_rgrpd *rgd, *begin = NULL; + struct gfs_alloc *al = ip->i_alloc; + int flags = LM_FLAG_TRY; + int skipped = 0; + int loops = 0; + int error; + int try_flag; + unsigned int try_threshold = gfs_tune_get(sdp, gt_rgrp_try_threshold); + + /* Try recently successful rgrps */ + + rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc); + + while (rgd) { + try_flag = (rgd->rd_try_counter >= try_threshold) ? + 0: LM_FLAG_TRY; + error = gfs_glock_nq_init(rgd->rd_gl, + LM_ST_EXCLUSIVE, try_flag, + &al->al_rgd_gh); + switch (error) { + case 0: + if (try_rgrp_fit(rgd, al)) { + rgd->rd_try_counter = 0; + goto out; + } + gfs_glock_dq_uninit(&al->al_rgd_gh); + rgd = recent_rgrp_next(rgd, TRUE); + break; + + case GLR_TRYFAILED: + rgd->rd_try_counter++; + rgd = recent_rgrp_next(rgd, FALSE); + break; + + default: + return error; + } + } + + /* Go through full list of rgrps */ + + begin = rgd = forward_rgrp_get(sdp); + + for (;;) { + error = gfs_glock_nq_init(rgd->rd_gl, + LM_ST_EXCLUSIVE, flags, + &al->al_rgd_gh); + switch (error) { + case 0: + if (try_rgrp_fit(rgd, al)) + goto out; + gfs_glock_dq_uninit(&al->al_rgd_gh); + break; + + case GLR_TRYFAILED: + skipped++; + break; + + default: + return error; + } + + rgd = gfs_rgrpd_get_next(rgd); + if (!rgd) + rgd = gfs_rgrpd_get_first(sdp); + + if (rgd == begin) { + if (++loops >= 2 || !skipped) + return -ENOSPC; + flags = 0; + } + } + + out: + ip->i_last_rg_alloc = rgd->rd_ri.ri_addr; + + if (begin) { + recent_rgrp_add(rgd); + rgd = gfs_rgrpd_get_next(rgd); + if (!rgd) + rgd = gfs_rgrpd_get_first(sdp); + forward_rgrp_set(sdp, rgd); + } + + return 0; +} + +/** + * gfs_inplace_reserve_i - Reserve space in the filesystem + * @ip: the inode to reserve space for + * + * Acquire resource group locks to allow for the maximum allocation + * described by "res". + * + * This should probably become more complex again, but for now, let's go + * for simple (one resource group) reservations. + * + * Returns: errno + */ + +int +gfs_inplace_reserve_i(struct gfs_inode *ip, + char *file, unsigned int line) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_alloc *al = ip->i_alloc; + int error; + + if (gfs_assert_warn(sdp, + al->al_requested_di || + al->al_requested_data || + al->al_requested_meta)) + return -EINVAL; + + error = gfs_rindex_hold(sdp, &al->al_ri_gh); + if (error) + return error; + + error = get_local_rgrp(ip); + if (error) { + gfs_glock_dq_uninit(&al->al_ri_gh); + return error; + } + + gfs_depend_sync(al->al_rgd); + + al->al_file = file; + al->al_line = line; + + return 0; +} + +/** + * gfs_inplace_release - release an inplace reservation + * @ip: the inode the reservation was taken out on + * + * Release a reservation made by gfs_inplace_reserve(). + */ + +void +gfs_inplace_release(struct gfs_inode *ip) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_alloc *al = ip->i_alloc; + + if (gfs_assert_warn(sdp, al->al_alloced_di <= al->al_requested_di) == -1) + printk("GFS: fsid=%s: al_alloced_di = %u, al_requested_di = %u\n" + "GFS: fsid=%s: al_file = %s, al_line = %u\n", + sdp->sd_fsname, al->al_alloced_di, al->al_requested_di, + sdp->sd_fsname, al->al_file, al->al_line); + if (gfs_assert_warn(sdp, al->al_alloced_meta <= al->al_reserved_meta) == -1) + printk("GFS: fsid=%s: al_alloced_meta = %u, al_reserved_meta = %u\n" + "GFS: fsid=%s: al_file = %s, al_line = %u\n", + sdp->sd_fsname, al->al_alloced_meta, al->al_reserved_meta, + sdp->sd_fsname, al->al_file, al->al_line); + if (gfs_assert_warn(sdp, al->al_alloced_data <= al->al_reserved_data) == -1) + printk("GFS: fsid=%s: al_alloced_data = %u, al_reserved_data = %u\n" + "GFS: fsid=%s: al_file = %s, al_line = %u\n", + sdp->sd_fsname, al->al_alloced_data, al->al_reserved_data, + sdp->sd_fsname, al->al_file, al->al_line); + + al->al_rgd = NULL; + gfs_glock_dq_uninit(&al->al_rgd_gh); + gfs_glock_dq_uninit(&al->al_ri_gh); +} + +/** + * gfs_get_block_type - Check a block in a RG is of given type + * @rgd: the resource group holding the block + * @block: the block number + * + * Returns: The block type (GFS_BLKST_*) + */ + +unsigned char +gfs_get_block_type(struct gfs_rgrpd *rgd, uint64_t block) +{ + struct gfs_bitmap *bits = NULL; + uint32_t length, rgrp_block, buf_block; + unsigned int buf; + unsigned char type; + + length = rgd->rd_ri.ri_length; + rgrp_block = block - rgd->rd_ri.ri_data1; + + for (buf = 0; buf < length; buf++) { + bits = &rgd->rd_bits[buf]; + if (rgrp_block < (bits->bi_start + bits->bi_len) * GFS_NBBY) + break; + } + + gfs_assert(rgd->rd_sbd, buf < length,); + buf_block = rgrp_block - bits->bi_start * GFS_NBBY; + + type = gfs_testbit(rgd, + rgd->rd_bh[buf]->b_data + bits->bi_offset, + bits->bi_len, buf_block); + + return type; +} + +/** + * blkalloc_internal - find a block in @old_state, change allocation + * state to @new_state + * @rgd: the resource group descriptor + * @goal: the goal block within the RG (start here to search for avail block) + * @old_state: GFS_BLKST_XXX the before-allocation state to find + * @new_state: GFS_BLKST_XXX the after-allocation block state + * + * Walk rgrp's bitmap to find bits that represent a block in @old_state. + * Add the found bitmap buffer to the transaction. + * Set the found bits to @new_state to change block's allocation state. + * + * This function never fails, because we wouldn't call it unless we + * know (from reservation results, etc.) that a block is available. + * + * Scope of @goal and returned block is just within rgrp (32-bit), + * not the whole filesystem (64-bit). + * + * Returns: the block # allocated (32-bit rgrp scope) + */ + +static uint32_t +blkalloc_internal(struct gfs_rgrpd *rgd, + uint32_t goal, + unsigned char old_state, unsigned char new_state) +{ + struct gfs_bitmap *bits = NULL; + uint32_t length = rgd->rd_ri.ri_length; + uint32_t blk = 0; + unsigned int buf, x; + + /* Find bitmap block that contains bits for goal block */ + for (buf = 0; buf < length; buf++) { + bits = &rgd->rd_bits[buf]; + if (goal < (bits->bi_start + bits->bi_len) * GFS_NBBY) + break; + } + + gfs_assert(rgd->rd_sbd, buf < length,); + + /* Convert scope of "goal" from rgrp-wide to within found bit block */ + goal -= bits->bi_start * GFS_NBBY; + + /* Search (up to entire) bitmap in this rgrp for allocatable block. + "x <= length", instead of "x < length", because we typically start + the search in the middle of a bit block, but if we can't find an + allocatable block anywhere else, we want to be able wrap around and + search in the first part of our first-searched bit block. */ + for (x = 0; x <= length; x++) { + blk = gfs_bitfit(rgd->rd_bh[buf]->b_data + bits->bi_offset, + bits->bi_len, goal, old_state); + if (blk != BFITNOENT) + break; + + /* Try next bitmap block (wrap back to rgrp header if at end) */ + buf = (buf + 1) % length; + bits = &rgd->rd_bits[buf]; + goal = 0; + } + + if (unlikely(x > length)) { + printk("GFS error: possible RG corruption\n"); + printk(" please run gfs_fsck after withdraw\n"); + dump_stack(); + if (gfs_assert_withdraw(rgd->rd_sbd, x <= length)) + blk = 0; + } + + /* Attach bitmap buffer to trans, modify bits to do block alloc */ + gfs_trans_add_bh(rgd->rd_gl, rgd->rd_bh[buf]); + gfs_setbit(rgd, + rgd->rd_bh[buf]->b_data + bits->bi_offset, + bits->bi_len, blk, new_state); + + /* Return allocated block #, rgrp scope (32-bit) */ + return bits->bi_start * GFS_NBBY + blk; +} + +/** + * blkfree_internal - Change alloc state of given block(s) + * @sdp: the filesystem + * @bstart: first block (64-bit filesystem scope) of a run of contiguous blocks + * @blen: the length of the block run (all must lie within ONE RG!) + * @new_state: GFS_BLKST_XXX the after-allocation block state + * + * Returns: Resource group containing the block(s) + * + * Find rgrp containing @bstart. + * For each block in run: + * Find allocation bitmap buffer. + * Add bitmap buffer to transaction. + * Set bits to new state. + * Typically used to free blocks to GFS_BLKST_FREE or GFS_BLKST_FREEMETA, + * but @new_state can be any GFS_BLKST_XXX + * + */ + +static struct gfs_rgrpd * +blkfree_internal(struct gfs_sbd *sdp, uint64_t bstart, uint32_t blen, + unsigned char new_state) +{ + struct gfs_rgrpd *rgd; + struct gfs_bitmap *bits = NULL; + uint32_t length, rgrp_blk, buf_blk; + unsigned int buf; + + /* Find rgrp */ + rgd = gfs_blk2rgrpd(sdp, bstart); + if (!rgd) { + if (gfs_consist(sdp)) + printk("GFS: fsid=%s: block = %llu\n", + sdp->sd_fsname, bstart); + return NULL; + } + + length = rgd->rd_ri.ri_length; + + /* Convert blk # from filesystem scope (64-bit) to RG scope (32-bit) */ + rgrp_blk = bstart - rgd->rd_ri.ri_data1; + + while (blen--) { + /* Find bitmap buffer for this block */ + for (buf = 0; buf < length; buf++) { + bits = &rgd->rd_bits[buf]; + if (rgrp_blk < (bits->bi_start + bits->bi_len) * GFS_NBBY) + break; + } + + gfs_assert(rgd->rd_sbd, buf < length,); + + /* Find bits and set 'em */ + buf_blk = rgrp_blk - bits->bi_start * GFS_NBBY; + rgrp_blk++; + + gfs_trans_add_bh(rgd->rd_gl, rgd->rd_bh[buf]); + gfs_setbit(rgd, + rgd->rd_bh[buf]->b_data + bits->bi_offset, + bits->bi_len, buf_blk, new_state); + } + + return rgd; +} + +/** + * clump_alloc - Allocate a clump of metadata blocks + * @rgd: the resource group in which to allocate + * @first: returns the first block allocated + * + * Returns: errno + * + * Bitmap-allocate a clump of metadata blocks + * Write metadata blocks to disk with dummy meta-headers + * Add meta-headers to incore meta-header cache + */ + +static int +clump_alloc(struct gfs_rgrpd *rgd, uint32_t *first) +{ + struct gfs_sbd *sdp = rgd->rd_sbd; + struct gfs_meta_header mh; + struct buffer_head **bh; + uint32_t goal, blk; + unsigned int x; + int error = 0; + + /* Dummy meta-header template */ + memset(&mh, 0, sizeof(struct gfs_meta_header)); + mh.mh_magic = GFS_MAGIC; + mh.mh_type = GFS_METATYPE_NONE; + + /* Array of bh pointers used in several steps */ + bh = gmalloc(GFS_META_CLUMP * sizeof(struct buffer_head *)); + memset(bh, 0, GFS_META_CLUMP * sizeof(struct buffer_head *)); + + /* Since we're looking for data blocks to change into meta blocks, + use last alloc'd *data* (not meta) block as start point */ + goal = rgd->rd_last_alloc_data; + + for (x = 0; x < GFS_META_CLUMP; x++) { + blk = blkalloc_internal(rgd, goal, GFS_BLKST_FREE, + GFS_BLKST_FREEMETA); + if (!x) + *first = blk; + + bh[x] = gfs_dgetblk(rgd->rd_gl, rgd->rd_ri.ri_data1 + blk); + + gfs_prep_new_buffer(bh[x]); + + gfs_meta_header_out(&mh, bh[x]->b_data); + ((struct gfs_meta_header *)bh[x]->b_data)->mh_generation = 0; + + /* start write of new meta-buffer to disk */ + error = gfs_dwrite(sdp, bh[x], DIO_DIRTY | DIO_START); + if (error) + goto out; + + goal = blk; + } + + /* Block alloc start point for next time */ + rgd->rd_last_alloc_data = goal; + + /* Wait for all new meta-buffers to get on-disk */ + for (x = 0; x < GFS_META_CLUMP; x++) { + error = gfs_dwrite(sdp, bh[x], DIO_WAIT); + if (error) + goto out; + } + + /* Add all new meta-headers to meta-header cache */ + gfs_mhc_add(rgd, bh, GFS_META_CLUMP); + + gfs_assert_withdraw(sdp, rgd->rd_rg.rg_free >= GFS_META_CLUMP); + rgd->rd_rg.rg_free -= GFS_META_CLUMP; + rgd->rd_rg.rg_freemeta += GFS_META_CLUMP; + + out: + for (x = 0; x < GFS_META_CLUMP; x++) + if (bh[x]) { + gfs_dwrite(sdp, bh[x], DIO_WAIT); + brelse(bh[x]); + } + kfree(bh); + + return error; +} + +/** + * gfs_blkalloc - Allocate a data block + * @ip: the inode to allocate the data block for + * @block: the block allocated + * + */ + +void +gfs_blkalloc(struct gfs_inode *ip, uint64_t *block) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_alloc *al = ip->i_alloc; + struct gfs_rgrpd *rgd = al->al_rgd; + uint32_t goal, blk; + int same; + + same = (rgd->rd_ri.ri_addr == ip->i_di.di_goal_rgrp); + goal = (same) ? ip->i_di.di_goal_dblk : rgd->rd_last_alloc_data; + + blk = blkalloc_internal(rgd, goal, + GFS_BLKST_FREE, GFS_BLKST_USED); + rgd->rd_last_alloc_data = blk; + + if (!same) { + ip->i_di.di_goal_rgrp = rgd->rd_ri.ri_addr; + ip->i_di.di_goal_mblk = 0; + } + ip->i_di.di_goal_dblk = blk; + + *block = rgd->rd_ri.ri_data1 + blk; + + gfs_assert_withdraw(sdp, rgd->rd_rg.rg_free); + rgd->rd_rg.rg_free--; + + gfs_trans_add_bh(rgd->rd_gl, rgd->rd_bh[0]); + gfs_rgrp_out(&rgd->rd_rg, rgd->rd_bh[0]->b_data); + + al->al_alloced_data++; + + gfs_trans_add_quota(sdp, +1, ip->i_di.di_uid, ip->i_di.di_gid); + + /* total=0, free=-1, dinodes=0 */ + gfs_statfs_modify(sdp, 0, -1, 0); +} + +/** + * gfs_metaalloc - Allocate a metadata block to a file + * @ip: the file + * @block: the block allocated + * + * Returns: errno + */ + +int +gfs_metaalloc(struct gfs_inode *ip, uint64_t *block) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_alloc *al = ip->i_alloc; + struct gfs_rgrpd *rgd = al->al_rgd; + uint32_t goal, blk; + int same; + int error; + + same = (rgd->rd_ri.ri_addr == ip->i_di.di_goal_rgrp); + + if (!rgd->rd_rg.rg_freemeta) { + error = clump_alloc(rgd, &goal); + if (error) + return error; + + al->al_alloced_data += GFS_META_CLUMP; + } else + goal = (same) ? ip->i_di.di_goal_mblk : rgd->rd_last_alloc_meta; + + blk = blkalloc_internal(rgd, goal, + GFS_BLKST_FREEMETA, GFS_BLKST_USEDMETA); + rgd->rd_last_alloc_meta = blk; + + if (!same) { + ip->i_di.di_goal_rgrp = rgd->rd_ri.ri_addr; + ip->i_di.di_goal_dblk = 0; + } + ip->i_di.di_goal_mblk = blk; + + *block = rgd->rd_ri.ri_data1 + blk; + + gfs_assert_withdraw(sdp, rgd->rd_rg.rg_freemeta); + rgd->rd_rg.rg_freemeta--; + rgd->rd_rg.rg_usedmeta++; + + gfs_trans_add_bh(rgd->rd_gl, rgd->rd_bh[0]); + gfs_rgrp_out(&rgd->rd_rg, rgd->rd_bh[0]->b_data); + + al->al_alloced_meta++; + + gfs_trans_add_quota(sdp, +1, ip->i_di.di_uid, ip->i_di.di_gid); + + /* total=0, free=-1, dinode=0 */ + gfs_statfs_modify(sdp, 0, -1, 0); + + return 0; +} + +/** + * gfs_dialloc - Allocate a dinode + * @dip: the directory that the inode is going in + * @block: the block (result) which this function allocates as the dinode + * (64-bit filesystem scope) + * + * Returns: errno + */ + +int +gfs_dialloc(struct gfs_inode *dip, uint64_t *block) +{ + struct gfs_sbd *sdp = dip->i_sbd; + struct gfs_alloc *al = dip->i_alloc; + struct gfs_rgrpd *rgd = al->al_rgd; + uint32_t goal, blk; + int error = 0; + + if (rgd->rd_rg.rg_freemeta) + /* pick up where we left off last time */ + goal = rgd->rd_last_alloc_meta; + else { + /* no free meta blocks, allocate a bunch more */ + error = clump_alloc(rgd, &goal); + if (error) + return error; + + al->al_alloced_data += GFS_META_CLUMP; + } + + /* Alloc the dinode; 32-bit "blk" is block offset within rgrp */ + blk = blkalloc_internal(rgd, goal, + GFS_BLKST_FREEMETA, GFS_BLKST_USEDMETA); + + /* remember where we left off, for next time */ + rgd->rd_last_alloc_meta = blk; + + /* convert from rgrp scope (32-bit) to filesystem scope (64-bit) */ + *block = rgd->rd_ri.ri_data1 + blk; + + gfs_assert_withdraw(rgd->rd_sbd, rgd->rd_rg.rg_freemeta); + rgd->rd_rg.rg_freemeta--; + rgd->rd_rg.rg_useddi++; + + /* Attach rgrp header to trans, update freemeta and useddi stats */ + gfs_trans_add_bh(rgd->rd_gl, rgd->rd_bh[0]); + gfs_rgrp_out(&rgd->rd_rg, rgd->rd_bh[0]->b_data); + + /* Update stats in in-place reservation struct */ + al->al_alloced_di++; + al->al_alloced_meta++; + + /* total=0, free=-1, dinodes=1 */ + gfs_statfs_modify(sdp, 0, -1, +1); + + return error; +} + +/** + * gfs_blkfree - free a contiguous run of data block(s) + * @ip: the inode these blocks are being freed from + * @bstart: first block (64-bit filesystem scope) of a run of contiguous blocks + * @blen: the length of the block run (all must lie within ONE RG!) + * + * Bitmap-deallocate the blocks (to FREE data state), add bitmap blks to trans + * Update rgrp alloc statistics in rgrp header, add rgrp header buf to trans + * Update quotas, add to trans. + */ + +void +gfs_blkfree(struct gfs_inode *ip, uint64_t bstart, uint32_t blen) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_rgrpd *rgd; + + rgd = blkfree_internal(sdp, bstart, blen, GFS_BLKST_FREE); + if (!rgd) + return; + + rgd->rd_rg.rg_free += blen; + + gfs_trans_add_bh(rgd->rd_gl, rgd->rd_bh[0]); + gfs_rgrp_out(&rgd->rd_rg, rgd->rd_bh[0]->b_data); + + gfs_trans_add_quota(sdp, -(int64_t)blen, + ip->i_di.di_uid, + ip->i_di.di_gid); + + /* total=0, free=+blen, dinodes=0 */ + gfs_statfs_modify(sdp, 0, blen, 0); +} + +/** + * gfs_metafree - free a contiguous run of metadata block(s) + * @ip: the inode these blocks are being freed from + * @bstart: first block (64-bit filesystem scope) of a run of contiguous blocks + * @blen: the length of the block run (all must lie within ONE RG!) + * + * Bitmap-deallocate the blocks (to FREEMETA state), add bitmap blks to trans. + * Update rgrp alloc statistics in rgrp header, add rgrp header to trans. + * Update quotas (quotas include metadata, not just data block usage), + * add to trans. + * Release deallocated buffers, add to meta-header cache (we save these in-core + * so we don't need to re-read meta blocks if/when they are re-alloc'd). + */ + +void +gfs_metafree(struct gfs_inode *ip, uint64_t bstart, uint32_t blen) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_rgrpd *rgd; + + rgd = blkfree_internal(sdp, bstart, blen, GFS_BLKST_FREEMETA); + if (!rgd) + return; + + if (rgd->rd_rg.rg_usedmeta < blen) + gfs_consist_rgrpd(rgd); + rgd->rd_rg.rg_usedmeta -= blen; + rgd->rd_rg.rg_freemeta += blen; + + gfs_trans_add_bh(rgd->rd_gl, rgd->rd_bh[0]); + gfs_rgrp_out(&rgd->rd_rg, rgd->rd_bh[0]->b_data); + + /* total=0, free=blen, dinode=0 */ + gfs_statfs_modify(sdp, 0, blen, 0); + + gfs_trans_add_quota(sdp, -(int64_t)blen, + ip->i_di.di_uid, + ip->i_di.di_gid); + gfs_wipe_buffers(ip, rgd, bstart, blen); +} + +/** + * gfs_difree_uninit - free a dinode block + * @rgd: the resource group that contains the dinode + * @addr: the dinode address + * + * De-allocate the dinode to FREEMETA using block alloc bitmap. + * Update rgrp's block usage statistics (used dinode--, free meta++). + * Add rgrp header to transaction. + */ + +void +gfs_difree_uninit(struct gfs_rgrpd *rgd, uint64_t addr) +{ + struct gfs_rgrpd *tmp_rgd; + + tmp_rgd = blkfree_internal(rgd->rd_sbd, addr, 1, + GFS_BLKST_FREEMETA); + if (!tmp_rgd) + return; + gfs_assert_withdraw(rgd->rd_sbd, rgd == tmp_rgd); + + if (!rgd->rd_rg.rg_useddi) + gfs_consist_rgrpd(rgd); + rgd->rd_rg.rg_useddi--; + rgd->rd_rg.rg_freemeta++; + + gfs_trans_add_bh(rgd->rd_gl, rgd->rd_bh[0]); + gfs_rgrp_out(&rgd->rd_rg, rgd->rd_bh[0]->b_data); + + /* total=0, free=1, dinodes=-1 */ + gfs_statfs_modify(rgd->rd_sbd, 0, +1, -1); +} + +/** + * gfs_difree - free a dinode block + * @rgd: the resource group that contains the dinode + * @ip: the inode representing the dinode to free + * + * Free the dinode block to FREEMETA, update rgrp's block usage stats. + * Update quotas (quotas include metadata, not just data block usage), + * add to trans. + * Release deallocated buffers, add to meta-header cache (we save these in-core + * so we don't need to re-read meta blocks if/when they are re-alloc'd). + */ + +void +gfs_difree(struct gfs_rgrpd *rgd, struct gfs_inode *ip) +{ + gfs_difree_uninit(rgd, ip->i_num.no_addr); + gfs_trans_add_quota(ip->i_sbd, -1, ip->i_di.di_uid, ip->i_di.di_gid); + gfs_wipe_buffers(ip, rgd, ip->i_num.no_addr, 1); +} + +/** + * gfs_rlist_add - add a RG to a list of RGs + * @sdp: the filesystem + * @rlist: the list of resource groups + * @block: the block + * + * Figure out what RG a block belongs to and add that RG to the list + * + * FIXME: Don't use gmalloc() + * + */ + +void +gfs_rlist_add(struct gfs_sbd *sdp, struct gfs_rgrp_list *rlist, uint64_t block) +{ + struct gfs_rgrpd *rgd; + struct gfs_rgrpd **tmp; + unsigned int new_space; + unsigned int x; + + if (gfs_assert_warn(sdp, !rlist->rl_ghs)) + return; + + rgd = gfs_blk2rgrpd(sdp, block); + if (!rgd) { + if (gfs_consist(sdp)) + printk("GFS: fsid=%s: block = %llu\n", + sdp->sd_fsname, block); + return; + } + + for (x = 0; x < rlist->rl_rgrps; x++) + if (rlist->rl_rgd[x] == rgd) + return; + + if (rlist->rl_rgrps == rlist->rl_space) { + new_space = rlist->rl_space + 10; + + tmp = gmalloc(new_space * sizeof(struct gfs_rgrpd *)); + + if (rlist->rl_rgd) { + memcpy(tmp, rlist->rl_rgd, + rlist->rl_space * sizeof(struct gfs_rgrpd *)); + kfree(rlist->rl_rgd); + } + + rlist->rl_space = new_space; + rlist->rl_rgd = tmp; + } + + rlist->rl_rgd[rlist->rl_rgrps++] = rgd; +} + +/** + * gfs_rlist_alloc - all RGs have been added to the rlist, now allocate + * and initialize an array of glock holders for them + * @rlist: the list of resource groups + * @state: the lock state to acquire the RG lock in + * @flags: the modifier flags for the holder structures + * + * FIXME: Don't use gmalloc() + * + */ + +void +gfs_rlist_alloc(struct gfs_rgrp_list *rlist, unsigned int state, int flags) +{ + unsigned int x; + + rlist->rl_ghs = gmalloc(rlist->rl_rgrps * sizeof(struct gfs_holder)); + for (x = 0; x < rlist->rl_rgrps; x++) + gfs_holder_init(rlist->rl_rgd[x]->rd_gl, + state, flags, + &rlist->rl_ghs[x]); +} + +/** + * gfs_rlist_free - free a resource group list + * @list: the list of resource groups + * + */ + +void +gfs_rlist_free(struct gfs_rgrp_list *rlist) +{ + unsigned int x; + + if (rlist->rl_rgd) + kfree(rlist->rl_rgd); + + if (rlist->rl_ghs) { + for (x = 0; x < rlist->rl_rgrps; x++) + gfs_holder_uninit(&rlist->rl_ghs[x]); + kfree(rlist->rl_ghs); + } +} + +/** + * gfs_reclaim_metadata - reclaims unused metadata + * @sdp: the file system + * @inodes: + * @metadata: + * + * This function will look through the resource groups and + * free the unused metadata. + * + * Returns: errno + */ + +int +gfs_reclaim_metadata(struct gfs_sbd *sdp, + uint64_t *inodes, + uint64_t *metadata) +{ + struct gfs_holder ji_gh, ri_gh, rgd_gh, t_gh; + struct gfs_rgrpd *rgd; + struct gfs_rgrp *rg; + struct gfs_dinode *di; + struct gfs_inum next; + struct buffer_head *bh; + uint32_t flags; + uint32_t goal; + unsigned int x; + int error = 0; + + *inodes = *metadata = 0; + + /* Acquire the jindex lock here so we don't deadlock with a + process writing the the jindex inode. :-( */ + + error = gfs_jindex_hold(sdp, &ji_gh); + if (error) + goto fail; + + error = gfs_rindex_hold(sdp, &ri_gh); + if (error) + goto fail_jindex_relse; + + for (rgd = gfs_rgrpd_get_first(sdp); + rgd; + rgd = gfs_rgrpd_get_next(rgd)) { + error = gfs_glock_nq_init(rgd->rd_gl, + LM_ST_EXCLUSIVE, GL_NOCACHE, + &rgd_gh); + if (error) + goto fail_rindex_relse; + + rgrp_verify(rgd); + + rg = &rgd->rd_rg; + + if (!rg->rg_freedi && !rg->rg_freemeta) { + gfs_glock_dq_uninit(&rgd_gh); + continue; + } + + gfs_mhc_zap(rgd); + gfs_depend_sync(rgd); + + error = gfs_lock_fs_check_clean(sdp, LM_ST_EXCLUSIVE, &t_gh); + if (error) + goto fail_gunlock_rg; + + error = gfs_trans_begin(sdp, rgd->rd_ri.ri_length, 0); + if (error) + goto fail_unlock_fs; + + next = rg->rg_freedi_list; + + for (x = rg->rg_freedi; x--;) { + if (!next.no_formal_ino || !next.no_addr) { + gfs_consist_rgrpd(rgd); + error = -EIO; + goto fail_end_trans; + } + + blkfree_internal(sdp, next.no_addr, 1, GFS_BLKST_FREE); + + error = gfs_dread(rgd->rd_gl, next.no_addr, + DIO_FORCE | DIO_START | DIO_WAIT, &bh); + if (error) + goto fail_end_trans; + + di = (struct gfs_dinode *)bh->b_data; + flags = di->di_flags; + flags = gfs32_to_cpu(flags); + if (!(flags & GFS_DIF_UNUSED)) { + gfs_consist_rgrpd(rgd); + brelse(bh); + error = -EIO; + goto fail_end_trans; + } + + gfs_inum_in(&next, (char *)&di->di_next_unused); + + brelse(bh); + + rg->rg_freedi--; + rg->rg_free++; + (*inodes)++; + } + + if (next.no_formal_ino || next.no_addr) { + gfs_consist_rgrpd(rgd); + error = -EIO; + goto fail_end_trans; + } + rg->rg_freedi_list = next; + + goal = 0; + for (x = rg->rg_freemeta; x--;) { + goal = blkalloc_internal(rgd, goal, + GFS_BLKST_FREEMETA, GFS_BLKST_FREE); + rg->rg_freemeta--; + rg->rg_free++; + (*metadata)++; + } + + gfs_trans_add_bh(rgd->rd_gl, rgd->rd_bh[0]); + gfs_rgrp_out(rg, rgd->rd_bh[0]->b_data); + + gfs_trans_end(sdp); + + gfs_glock_dq_uninit(&t_gh); + + gfs_glock_dq_uninit(&rgd_gh); + } + + gfs_glock_dq_uninit(&ri_gh); + + gfs_glock_dq_uninit(&ji_gh); + + return 0; + + fail_end_trans: + gfs_trans_end(sdp); + + fail_unlock_fs: + gfs_glock_dq_uninit(&t_gh); + + fail_gunlock_rg: + gfs_glock_dq_uninit(&rgd_gh); + + fail_rindex_relse: + gfs_glock_dq_uninit(&ri_gh); + + fail_jindex_relse: + gfs_glock_dq_uninit(&ji_gh); + + fail: + return error; +} --- linux-2.6.27.orig/ubuntu/gfs/lvb.h +++ linux-2.6.27/ubuntu/gfs/lvb.h @@ -0,0 +1,53 @@ +/* + * Formats of Lock Value Blocks (LVBs) for various types of locks. + * These 32-bit data chunks can be shared quickly between nodes + * via the inter-node lock manager (via LAN instead of on-disk). + */ + +#ifndef __LVB_DOT_H__ +#define __LVB_DOT_H__ + +#define GFS_MIN_LVB_SIZE (32) + +/* + * Resource Group block allocation statistics + * Each resource group lock contains one of these in its LVB. + * Used for sharing approximate current statistics for statfs. + * Not used for actual block allocation. + */ +struct gfs_rgrp_lvb { + uint32_t rb_magic; /* GFS_MAGIC sanity check value */ + uint32_t rb_free; /* # free data blocks */ + uint32_t rb_useddi; /* # used dinode blocks */ + uint32_t rb_freedi; /* # free dinode blocks */ + uint32_t rb_usedmeta; /* # used metadata blocks */ + uint32_t rb_freemeta; /* # free metadata blocks */ +}; + +/* + * Quota + * Each quota lock contains one of these in its LVB. + * Keeps track of block allocation limits and current block allocation + * for either a cluster-wide user or a cluster-wide group. + */ +struct gfs_quota_lvb { + uint32_t qb_magic; /* GFS_MAGIC sanity check value */ + uint32_t qb_pad; + uint64_t qb_limit; /* Hard limit of # blocks to alloc */ + uint64_t qb_warn; /* Warn user when alloc is above this # */ + int64_t qb_value; /* Current # blocks allocated */ +}; + +/* Translation functions */ + +void gfs_rgrp_lvb_in(struct gfs_rgrp_lvb *rb, char *lvb); +void gfs_rgrp_lvb_out(struct gfs_rgrp_lvb *rb, char *lvb); +void gfs_quota_lvb_in(struct gfs_quota_lvb *qb, char *lvb); +void gfs_quota_lvb_out(struct gfs_quota_lvb *qb, char *lvb); + +/* Printing functions */ + +void gfs_rgrp_lvb_print(struct gfs_rgrp_lvb *rb); +void gfs_quota_lvb_print(struct gfs_quota_lvb *qb); + +#endif /* __LVB_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/mount.h +++ linux-2.6.27/ubuntu/gfs/mount.h @@ -0,0 +1,6 @@ +#ifndef __MOUNT_DOT_H__ +#define __MOUNT_DOT_H__ + +int gfs_make_args(char *data, struct gfs_args *args, int remount); + +#endif /* __MOUNT_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/daemon.h +++ linux-2.6.27/ubuntu/gfs/daemon.h @@ -0,0 +1,11 @@ +#ifndef __DAEMON_DOT_H__ +#define __DAEMON_DOT_H__ + +int gfs_scand(void *data); +int gfs_glockd(void *data); +int gfs_recoverd(void *data); +int gfs_logd(void *data); +int gfs_quotad(void *data); +int gfs_inoded(void *data); + +#endif /* __DAEMON_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/quota.h +++ linux-2.6.27/ubuntu/gfs/quota.h @@ -0,0 +1,28 @@ +#ifndef __QUOTA_DOT_H__ +#define __QUOTA_DOT_H__ + +#define NO_QUOTA_CHANGE ((uint32_t)-1) + +int gfs_quota_get(struct gfs_sbd *sdp, int user, uint32_t id, int create, + struct gfs_quota_data **qdp); +void gfs_quota_hold(struct gfs_sbd *sdp, struct gfs_quota_data *qd); +void gfs_quota_put(struct gfs_sbd *sdp, struct gfs_quota_data *qd); + +int gfs_quota_merge(struct gfs_sbd *sdp, struct gfs_quota_tag *tag); +void gfs_quota_scan(struct gfs_sbd *sdp); +void gfs_quota_cleanup(struct gfs_sbd *sdp); + +int gfs_quota_hold_m(struct gfs_inode *ip, uint32_t uid, uint32_t gid); +void gfs_quota_unhold_m(struct gfs_inode *ip); + +int gfs_quota_lock_m(struct gfs_inode *ip, uint32_t uid, uint32_t gid); +void gfs_quota_unlock_m(struct gfs_inode *ip); + +int gfs_quota_check(struct gfs_inode *ip, uint32_t uid, uint32_t gid); + +int gfs_quota_sync(struct gfs_sbd *sdp); +int gfs_quota_refresh(struct gfs_sbd *sdp, int user, uint32_t id); +int gfs_quota_read(struct gfs_sbd *sdp, int user, uint32_t id, + struct gfs_quota *q); + +#endif /* __QUOTA_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/ops_address.h +++ linux-2.6.27/ubuntu/gfs/ops_address.h @@ -0,0 +1,6 @@ +#ifndef __OPS_ADDRESS_DOT_H__ +#define __OPS_ADDRESS_DOT_H__ + +extern struct address_space_operations gfs_file_aops; + +#endif /* __OPS_ADDRESS_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/bmap.h +++ linux-2.6.27/ubuntu/gfs/bmap.h @@ -0,0 +1,35 @@ +#ifndef __BMAP_DOT_H__ +#define __BMAP_DOT_H__ + +typedef int (*gfs_unstuffer_t) (struct gfs_inode * ip, + struct buffer_head * dibh, uint64_t block, + void *private); + +int gfs_unstuffer_sync(struct gfs_inode *ip, struct buffer_head *dibh, + uint64_t block, void *private); +int gfs_unstuffer_async(struct gfs_inode *ip, struct buffer_head *dibh, + uint64_t block, void *private); + +int gfs_unstuff_dinode(struct gfs_inode *ip, gfs_unstuffer_t unstuffer, + void *private); + +int gfs_block_map(struct gfs_inode *ip, + uint64_t lblock, int *new, + uint64_t *dblock, uint32_t *extlen); + +typedef int (*gfs_truncator_t) (struct gfs_inode * ip, uint64_t size); + +int gfs_truncator_default(struct gfs_inode *ip, uint64_t size); + +int gfs_shrink(struct gfs_inode *ip, uint64_t size, gfs_truncator_t truncator); +int gfs_truncatei(struct gfs_inode *ip, uint64_t size, + gfs_truncator_t truncator); + +void gfs_write_calc_reserv(struct gfs_inode *ip, unsigned int len, + unsigned int *data_blocks, unsigned int *ind_blocks); +int gfs_write_alloc_required(struct gfs_inode *ip, uint64_t offset, + unsigned int len, int *alloc_required); + +int gfs_get_file_meta(struct gfs_inode *ip, struct gfs_user_buffer *ub); + +#endif /* __BMAP_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/super.c +++ linux-2.6.27/ubuntu/gfs/super.c @@ -0,0 +1,1274 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "dio.h" +#include "file.h" +#include "format.h" +#include "glock.h" +#include "glops.h" +#include "inode.h" +#include "log.h" +#include "quota.h" +#include "recovery.h" +#include "rgrp.h" +#include "super.h" +#include "unlinked.h" +#include "trans.h" + +/** + * gfs_tune_init - Fill a gfs_tune structure with default values + * @gt: tune + * + */ + +void +gfs_tune_init(struct gfs_tune *gt) +{ + spin_lock_init(>->gt_spin); + + gt->gt_ilimit1 = 100; + gt->gt_ilimit1_tries = 3; + gt->gt_ilimit1_min = 1; + gt->gt_ilimit2 = 500; + gt->gt_ilimit2_tries = 10; + gt->gt_ilimit2_min = 3; + gt->gt_demote_secs = 300; + gt->gt_incore_log_blocks = 1024; + gt->gt_jindex_refresh_secs = 60; + gt->gt_depend_secs = 60; + gt->gt_scand_secs = 5; + gt->gt_recoverd_secs = 60; + gt->gt_logd_secs = 1; + gt->gt_quotad_secs = 5; + gt->gt_inoded_secs = 15; + gt->gt_glock_purge = 0; + gt->gt_quota_simul_sync = 64; + gt->gt_quota_warn_period = 10; + gt->gt_atime_quantum = 3600; + gt->gt_quota_quantum = 60; + gt->gt_quota_scale_num = 1; + gt->gt_quota_scale_den = 1; + gt->gt_quota_enforce = 1; + gt->gt_quota_account = 1; + gt->gt_new_files_jdata = 0; + gt->gt_new_files_directio = 0; + gt->gt_max_atomic_write = 4 << 20; + gt->gt_max_readahead = 1 << 18; + gt->gt_lockdump_size = 131072; + gt->gt_stall_secs = 600; + gt->gt_complain_secs = 10; + gt->gt_reclaim_limit = 5000; + gt->gt_entries_per_readdir = 32; + gt->gt_prefetch_secs = 10; + gt->gt_statfs_slots = 64; + gt->gt_max_mhc = 10000; + gt->gt_greedy_default = HZ / 10; + gt->gt_greedy_quantum = HZ / 40; + gt->gt_greedy_max = HZ / 4; + gt->gt_rgrp_try_threshold = 100; + gt->gt_statfs_fast = 0; +} + +/** + * gfs_check_sb - Check superblock + * @sdp: the filesystem + * @sb: The superblock + * @silent: Don't print a message if the check fails + * + * Checks the version code of the FS is one that we understand how to + * read and that the sizes of the various on-disk structures have not + * changed. + */ + +int +gfs_check_sb(struct gfs_sbd *sdp, struct gfs_sb *sb, int silent) +{ + unsigned int x; + + if (sb->sb_header.mh_magic != GFS_MAGIC || + sb->sb_header.mh_type != GFS_METATYPE_SB) { + if (!silent) + printk("GFS: not a GFS filesystem\n"); + return -EINVAL; + } + + /* If format numbers match exactly, we're done. */ + + if (sb->sb_fs_format == GFS_FORMAT_FS && + sb->sb_multihost_format == GFS_FORMAT_MULTI) + return 0; + + if (sb->sb_fs_format != GFS_FORMAT_FS) { + for (x = 0; gfs_old_fs_formats[x]; x++) + if (gfs_old_fs_formats[x] == sb->sb_fs_format) + break; + + if (!gfs_old_fs_formats[x]) { + printk("GFS: code version (%u, %u) is incompatible with ondisk format (%u, %u)\n", + GFS_FORMAT_FS, GFS_FORMAT_MULTI, + sb->sb_fs_format, sb->sb_multihost_format); + printk("GFS: I don't know how to upgrade this FS\n"); + return -EINVAL; + } + } + + if (sb->sb_multihost_format != GFS_FORMAT_MULTI) { + for (x = 0; gfs_old_multihost_formats[x]; x++) + if (gfs_old_multihost_formats[x] == sb->sb_multihost_format) + break; + + if (!gfs_old_multihost_formats[x]) { + printk("GFS: code version (%u, %u) is incompatible with ondisk format (%u, %u)\n", + GFS_FORMAT_FS, GFS_FORMAT_MULTI, + sb->sb_fs_format, sb->sb_multihost_format); + printk("GFS: I don't know how to upgrade this FS\n"); + return -EINVAL; + } + } + + if (!sdp->sd_args.ar_upgrade) { + printk("GFS: code version (%u, %u) is incompatible with ondisk format (%u, %u)\n", + GFS_FORMAT_FS, GFS_FORMAT_MULTI, + sb->sb_fs_format, sb->sb_multihost_format); + printk("GFS: Use the \"upgrade\" mount option to upgrade the FS\n"); + printk("GFS: See the manual for more details\n"); + return -EINVAL; + } + + return 0; +} + +/** + * gfs_read_sb - Read super block + * @sdp: The GFS superblock + * @gl: the glock for the superblock (assumed to be held) + * @silent: Don't print message if mount fails + * + */ + +int +gfs_read_sb(struct gfs_sbd *sdp, struct gfs_glock *gl, int silent) +{ + struct buffer_head *bh; + uint32_t hash_blocks, ind_blocks, leaf_blocks; + uint32_t tmp_blocks; + unsigned int x; + int error; + + error = gfs_dread(gl, GFS_SB_ADDR >> sdp->sd_fsb2bb_shift, + DIO_FORCE | DIO_START | DIO_WAIT, &bh); + if (error) { + if (!silent) + printk("GFS: fsid=%s: can't read superblock\n", + sdp->sd_fsname); + return error; + } + + gfs_assert(sdp, sizeof(struct gfs_sb) <= bh->b_size,); + gfs_sb_in(&sdp->sd_sb, bh->b_data); + brelse(bh); + + error = gfs_check_sb(sdp, &sdp->sd_sb, silent); + if (error) + return error; + + sdp->sd_fsb2bb_shift = sdp->sd_sb.sb_bsize_shift - + GFS_BASIC_BLOCK_SHIFT; + sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift; + sdp->sd_diptrs = (sdp->sd_sb.sb_bsize - sizeof(struct gfs_dinode)) / + sizeof(uint64_t); + sdp->sd_inptrs = (sdp->sd_sb.sb_bsize - sizeof(struct gfs_indirect)) / + sizeof(uint64_t); + sdp->sd_jbsize = sdp->sd_sb.sb_bsize - sizeof(struct gfs_meta_header); + sdp->sd_hash_bsize = sdp->sd_sb.sb_bsize / 2; + sdp->sd_hash_bsize_shift = sdp->sd_sb.sb_bsize_shift - 1; + sdp->sd_hash_ptrs = sdp->sd_hash_bsize / sizeof(uint64_t); + + /* Compute maximum reservation required to add a entry to a directory */ + + hash_blocks = DIV_RU(sizeof(uint64_t) * (1 << GFS_DIR_MAX_DEPTH), + sdp->sd_jbsize); + + ind_blocks = 0; + for (tmp_blocks = hash_blocks; tmp_blocks > sdp->sd_diptrs;) { + tmp_blocks = DIV_RU(tmp_blocks, sdp->sd_inptrs); + ind_blocks += tmp_blocks; + } + + leaf_blocks = 2 + GFS_DIR_MAX_DEPTH; + + sdp->sd_max_dirres = hash_blocks + ind_blocks + leaf_blocks; + + sdp->sd_heightsize[0] = sdp->sd_sb.sb_bsize - sizeof(struct gfs_dinode); + sdp->sd_heightsize[1] = sdp->sd_sb.sb_bsize * sdp->sd_diptrs; + for (x = 2;; x++) { + uint64_t space, d; + uint32_t m; + + space = sdp->sd_heightsize[x - 1] * sdp->sd_inptrs; + d = space; + m = do_div(d, sdp->sd_inptrs); + + if (d != sdp->sd_heightsize[x - 1] || m) + break; + sdp->sd_heightsize[x] = space; + } + sdp->sd_max_height = x; + gfs_assert(sdp, sdp->sd_max_height <= GFS_MAX_META_HEIGHT,); + + sdp->sd_jheightsize[0] = sdp->sd_sb.sb_bsize - sizeof(struct gfs_dinode); + sdp->sd_jheightsize[1] = sdp->sd_jbsize * sdp->sd_diptrs; + for (x = 2;; x++) { + uint64_t space, d; + uint32_t m; + + space = sdp->sd_jheightsize[x - 1] * sdp->sd_inptrs; + d = space; + m = do_div(d, sdp->sd_inptrs); + + if (d != sdp->sd_jheightsize[x - 1] || m) + break; + sdp->sd_jheightsize[x] = space; + } + sdp->sd_max_jheight = x; + gfs_assert(sdp, sdp->sd_max_jheight <= GFS_MAX_META_HEIGHT,); + + return 0; +} + +/** + * gfs_do_upgrade - upgrade a filesystem + * @sdp: The GFS superblock + * + */ + +int +gfs_do_upgrade(struct gfs_sbd *sdp, struct gfs_glock *sb_gl) +{ + struct gfs_holder ji_gh, t_gh, j_gh; + struct gfs_log_header lh; + struct buffer_head *bh; + unsigned int x; + int error; + + /* If format numbers match exactly, we're done. */ + + if (sdp->sd_sb.sb_fs_format == GFS_FORMAT_FS && + sdp->sd_sb.sb_multihost_format == GFS_FORMAT_MULTI) { + printk("GFS: fsid=%s: no upgrade necessary\n", + sdp->sd_fsname); + sdp->sd_args.ar_upgrade = FALSE; + return 0; + } + + error = gfs_jindex_hold(sdp, &ji_gh); + if (error) + goto fail; + + error = gfs_glock_nq_init(sdp->sd_trans_gl, + LM_ST_EXCLUSIVE, GL_NOCACHE, + &t_gh); + if (error) + goto fail_ji_relse; + + if (test_bit(SDF_ROFS, &sdp->sd_flags)) { + printk("GFS: fsid=%s: can't upgrade: read-only FS\n", + sdp->sd_fsname); + error = -EROFS; + goto fail_gunlock_tr; + } + + for (x = 0; x < sdp->sd_journals; x++) { + error = gfs_glock_nq_num(sdp, + sdp->sd_jindex[x].ji_addr, + &gfs_meta_glops, LM_ST_SHARED, + LM_FLAG_TRY | GL_NOCACHE, &j_gh); + switch (error) { + case 0: + break; + + case GLR_TRYFAILED: + printk("GFS: fsid=%s: journal %u is busy\n", + sdp->sd_fsname, x); + error = -EBUSY; + + default: + goto fail_gunlock_tr; + } + + error = gfs_find_jhead(sdp, &sdp->sd_jindex[x], + j_gh.gh_gl, &lh); + + gfs_glock_dq_uninit(&j_gh); + + if (error) + goto fail_gunlock_tr; + + if (!(lh.lh_flags & GFS_LOG_HEAD_UNMOUNT) || lh.lh_last_dump) { + printk("GFS: fsid=%s: journal %u is busy\n", + sdp->sd_fsname, x); + error = -EBUSY; + goto fail_gunlock_tr; + } + } + + /* We don't need to journal this change because we're changing + only one sector of one block. We definitely don't want to have + the journaling code running at this point. */ + + error = gfs_dread(sb_gl, GFS_SB_ADDR >> sdp->sd_fsb2bb_shift, + DIO_START | DIO_WAIT, &bh); + if (error) + goto fail_gunlock_tr; + + gfs_sb_in(&sdp->sd_sb, bh->b_data); + + error = gfs_check_sb(sdp, &sdp->sd_sb, FALSE); + if (error) { + gfs_consist(sdp); + brelse(bh); + goto fail_gunlock_tr; + } + + sdp->sd_sb.sb_fs_format = GFS_FORMAT_FS; + sdp->sd_sb.sb_multihost_format = GFS_FORMAT_MULTI; + + gfs_sb_out(&sdp->sd_sb, bh->b_data); + + set_bit(GLF_DIRTY, &sb_gl->gl_flags); + error = gfs_dwrite(sdp, bh, DIO_DIRTY | DIO_START | DIO_WAIT); + + brelse(bh); + + gfs_glock_dq_uninit(&t_gh); + + gfs_glock_dq_uninit(&ji_gh); + + if (!error) { + printk("GFS: fsid=%s: upgrade successful\n", + sdp->sd_fsname); + sdp->sd_args.ar_upgrade = FALSE; + } + + return error; + + fail_gunlock_tr: + gfs_glock_dq_uninit(&t_gh); + + fail_ji_relse: + gfs_glock_dq_uninit(&ji_gh); + + fail: + if (error == -EBUSY) + printk("GFS: fsid=%s: can't upgrade: the FS is still busy or contains dirty journals\n", + sdp->sd_fsname); + else + printk("GFS: fsid=%s: can't upgrade: %d\n", + sdp->sd_fsname, error); + + return error; +} + +/** + * clear_journalsi - Clear all the journal index information (without locking) + * @sdp: The GFS superblock + * + */ + +static void +clear_journalsi(struct gfs_sbd *sdp) +{ + if (sdp->sd_jindex) { + kfree(sdp->sd_jindex); + sdp->sd_jindex = NULL; + } + sdp->sd_journals = 0; +} + +/** + * gfs_clear_journals - Clear all the journal index information + * @sdp: The GFS superblock + * + */ + +void +gfs_clear_journals(struct gfs_sbd *sdp) +{ + down(&sdp->sd_jindex_lock); + clear_journalsi(sdp); + up(&sdp->sd_jindex_lock); +} + +/** + * gfs_ji_update - Update the journal index information + * @ip: The journal index inode + * + * Returns: errno + */ + +static int +gfs_ji_update(struct gfs_inode *ip) +{ + struct gfs_sbd *sdp = ip->i_sbd; + char buf[sizeof(struct gfs_jindex)]; + unsigned int j; + int error; + + if (do_mod(ip->i_di.di_size, sizeof(struct gfs_jindex))) { + gfs_consist_inode(ip); + return -EIO; + } + + clear_journalsi(sdp); + + sdp->sd_jindex = kmalloc(ip->i_di.di_size, GFP_KERNEL); + if (!sdp->sd_jindex) + return -ENOMEM; + memset(sdp->sd_jindex, 0, ip->i_di.di_size); + + for (j = 0;; j++) { + error = gfs_internal_read(ip, buf, + j * sizeof(struct gfs_jindex), + sizeof(struct gfs_jindex)); + if (!error) + break; + if (error != sizeof(struct gfs_jindex)) { + if (error > 0) + error = -EIO; + goto fail; + } + + gfs_jindex_in(sdp->sd_jindex + j, buf); + } + + sdp->sd_journals = j; + sdp->sd_jiinode_vn = ip->i_gl->gl_vn; + + return 0; + + fail: + clear_journalsi(sdp); + return error; +} + +/** + * gfs_jindex_hold - Grab a lock on the jindex + * @sdp: The GFS superblock + * @ji_gh: the holder for the jindex glock + * + * This makes sure that we're using the latest copy of the journal index + * special file (this describes all of the journals for this filesystem), + * which might have been updated if someone added journals + * (via gfs_jadd utility). + * + * This is very similar to the gfs_rindex_hold() function, except that + * in general we hold the jindex lock for longer periods of time and + * we grab it far less frequently (in general) then the rgrp lock. + * + * Returns: errno + */ + +int +gfs_jindex_hold(struct gfs_sbd *sdp, struct gfs_holder *ji_gh) +{ + struct gfs_inode *ip = sdp->sd_jiinode; + struct gfs_glock *gl = ip->i_gl; + int error; + + error = gfs_glock_nq_init(gl, LM_ST_SHARED, 0, ji_gh); + if (error) + return error; + + /* Read new copy from disk if we don't have the latest */ + if (sdp->sd_jiinode_vn != gl->gl_vn) { + down(&sdp->sd_jindex_lock); + if (sdp->sd_jiinode_vn != gl->gl_vn) + error = gfs_ji_update(ip); + up(&sdp->sd_jindex_lock); + } + + if (error) + gfs_glock_dq_uninit(ji_gh); + + return error; +} + +/** + * gfs_get_jiinode - Read-in the special (hidden) journal index inode + * @sdp: The GFS superblock + * + * Returns: errno + * + * This reads-in just the dinode, not the special file contents that describe + * the journals themselves (see gfs_jindex_hold()). + */ + +int +gfs_get_jiinode(struct gfs_sbd *sdp) +{ + struct gfs_holder ji_gh; + int error; + + error = gfs_glock_nq_num(sdp, + sdp->sd_sb.sb_jindex_di.no_formal_ino, + &gfs_inode_glops, + LM_ST_SHARED, GL_LOCAL_EXCL, + &ji_gh); + if (error) + return error; + + error = gfs_inode_get(ji_gh.gh_gl, &sdp->sd_sb.sb_jindex_di, + CREATE, &sdp->sd_jiinode); + if (!error) { + sdp->sd_jiinode_vn = ji_gh.gh_gl->gl_vn - 1; + set_bit(GLF_STICKY, &ji_gh.gh_gl->gl_flags); + } + + gfs_glock_dq_uninit(&ji_gh); + + return error; +} + +/** + * gfs_get_riinode - Read in the special (hidden) resource group index inode + * @sdp: The GFS superblock + * + * Returns: errno + * + * This reads-in just the dinode, not the special file contents that describe + * the resource groups themselves (see gfs_rindex_hold()). + */ + +int +gfs_get_riinode(struct gfs_sbd *sdp) +{ + struct gfs_holder ri_gh; + int error; + + error = gfs_glock_nq_num(sdp, + sdp->sd_sb.sb_rindex_di.no_formal_ino, + &gfs_inode_glops, + LM_ST_SHARED, GL_LOCAL_EXCL, + &ri_gh); + if (error) + return error; + + error = gfs_inode_get(ri_gh.gh_gl, &sdp->sd_sb.sb_rindex_di, + CREATE, &sdp->sd_riinode); + if (!error) { + sdp->sd_riinode_vn = ri_gh.gh_gl->gl_vn - 1; + set_bit(GLF_STICKY, &ri_gh.gh_gl->gl_flags); + } + + gfs_glock_dq_uninit(&ri_gh); + + return error; +} + +/** + * gfs_get_rootinode - Read in the filesystem's root inode + * @sdp: The GFS superblock + * + * Returns: errno + */ + +int +gfs_get_rootinode(struct gfs_sbd *sdp) +{ + struct gfs_holder i_gh; + int error; + + error = gfs_glock_nq_num(sdp, + sdp->sd_sb.sb_root_di.no_formal_ino, + &gfs_inode_glops, + LM_ST_SHARED, GL_LOCAL_EXCL, + &i_gh); + if (error) + return error; + + error = gfs_inode_get(i_gh.gh_gl, &sdp->sd_sb.sb_root_di, + CREATE, &sdp->sd_rooti); + + gfs_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * gfs_get_qinode - Read in the special (hidden) quota inode + * @sdp: The GFS superblock + * + * If one is not on-disk already, create a new one. + * Does not read in file contents, just the dinode. + * + * Returns: errno + */ + +int +gfs_get_qinode(struct gfs_sbd *sdp) +{ + struct gfs_holder i_gh; + int error; + + /* Create, if not on-disk already */ + if (!sdp->sd_sb.sb_quota_di.no_formal_ino) { + error = gfs_alloc_qinode(sdp); + if (error) + return error; + } + + error = gfs_glock_nq_num(sdp, + sdp->sd_sb.sb_quota_di.no_formal_ino, + &gfs_inode_glops, + LM_ST_SHARED, GL_LOCAL_EXCL, + &i_gh); + if (error) + return error; + + error = gfs_inode_get(i_gh.gh_gl, &sdp->sd_sb.sb_quota_di, + CREATE, &sdp->sd_qinode); + + gfs_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * gfs_get_linode - Read in the special (hidden) license inode + * @sdp: The GFS superblock + * + * If one is not on-disk already, create a new one. + * Does not read in file contents, just the dinode. + * + * Returns: errno + */ + +int +gfs_get_linode(struct gfs_sbd *sdp) +{ + struct gfs_holder i_gh; + int error; + + /* Create, if not on-disk already */ + if (!sdp->sd_sb.sb_license_di.no_formal_ino) { + error = gfs_alloc_linode(sdp); + if (error) + return error; + } + + error = gfs_glock_nq_num(sdp, + sdp->sd_sb.sb_license_di.no_formal_ino, + &gfs_inode_glops, + LM_ST_SHARED, GL_LOCAL_EXCL, + &i_gh); + if (error) + return error; + + /* iopen obtained in via gfs_glock_get(..gfs_iopen_glops) */ + error = gfs_inode_get(i_gh.gh_gl, &sdp->sd_sb.sb_license_di, + CREATE, &sdp->sd_linode); + + gfs_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * gfs_make_fs_rw - Turn a Read-Only FS into a Read-Write one + * @sdp: the filesystem + * + * Returns: errno + */ + +int +gfs_make_fs_rw(struct gfs_sbd *sdp) +{ + struct gfs_glock *j_gl = sdp->sd_journal_gh.gh_gl; + struct gfs_holder t_gh; + struct gfs_log_header head; + int error; + + error = gfs_glock_nq_init(sdp->sd_trans_gl, + LM_ST_SHARED, + GL_LOCAL_EXCL | GL_EXACT, + &t_gh); + if (error) + return error; + + j_gl->gl_ops->go_inval(j_gl, DIO_METADATA | DIO_DATA); + + error = gfs_find_jhead(sdp, &sdp->sd_jdesc, j_gl, &head); + if (error) + goto fail; + + if (!(head.lh_flags & GFS_LOG_HEAD_UNMOUNT)) { + gfs_consist(sdp); + error = -EIO; + goto fail; + } + + /* Initialize some head of the log stuff */ + sdp->sd_sequence = head.lh_sequence; + sdp->sd_log_head = head.lh_first + 1; + + error = gfs_recover_dump(sdp); + if (error) + goto fail; + + set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); + clear_bit(SDF_ROFS, &sdp->sd_flags); + + set_bit(GLF_DIRTY, &j_gl->gl_flags); + gfs_log_dump(sdp, TRUE); + + gfs_glock_dq_uninit(&t_gh); + + return 0; + + fail: + t_gh.gh_flags |= GL_NOCACHE; + gfs_glock_dq_uninit(&t_gh); + + return error; +} + +/** + * gfs_make_fs_ro - Turn a Read-Write FS into a Read-Only one + * @sdp: the filesystem + * + * Returns: errno + */ + +int +gfs_make_fs_ro(struct gfs_sbd *sdp) +{ + struct gfs_holder t_gh; + int error; + + error = gfs_glock_nq_init(sdp->sd_trans_gl, + LM_ST_SHARED, + GL_LOCAL_EXCL | GL_EXACT | GL_NOCACHE, + &t_gh); + if (error && + !test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) + return error; + + gfs_statfs_sync(sdp); + + gfs_log_flush(sdp); + gfs_quota_sync(sdp); + gfs_quota_scan(sdp); + + gfs_sync_meta(sdp); + gfs_log_dump(sdp, TRUE); + gfs_log_shutdown(sdp); + + set_bit(SDF_ROFS, &sdp->sd_flags); + clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); + + if (t_gh.gh_gl) + gfs_glock_dq_uninit(&t_gh); + + gfs_unlinked_cleanup(sdp); + gfs_quota_cleanup(sdp); + + return error; +} + +/** + * stat_gfs_fill - fill in the sg for a given RG + * @rgd: the RG + * @sg: the sg structure + * + * Returns: 0 on success, -ESTALE if the LVB is invalid + */ + +static int +stat_gfs_fill(struct gfs_rgrpd *rgd, struct gfs_stat_gfs *sg) +{ + struct gfs_rgrp_lvb *rb = (struct gfs_rgrp_lvb *)rgd->rd_gl->gl_lvb; + + if (gfs32_to_cpu(rb->rb_magic) != GFS_MAGIC) + return -ESTALE; + + sg->sg_total_blocks += rgd->rd_ri.ri_data; + sg->sg_free += gfs32_to_cpu(rb->rb_free); + sg->sg_used_dinode += gfs32_to_cpu(rb->rb_useddi); + sg->sg_free_dinode += gfs32_to_cpu(rb->rb_freedi); + sg->sg_used_meta += gfs32_to_cpu(rb->rb_usedmeta); + sg->sg_free_meta += gfs32_to_cpu(rb->rb_freemeta); + + return 0; +} + +/** + * stat_gfs_async - Stat a filesystem using asynchronous locking + * @sdp: the filesystem + * @sg: the sg info that will be returned + * @interruptible: TRUE if we should look for signals. + * + * Any error (other than a signal) will cause this routine to fall back + * to the synchronous version. + * + * FIXME: This really shouldn't busy wait like this. + * + * Returns: errno + */ + +static int +stat_gfs_async(struct gfs_sbd *sdp, struct gfs_stat_gfs *sg, int interruptible) +{ + struct gfs_rgrpd *rgd_next = gfs_rgrpd_get_first(sdp); + struct gfs_holder *gha, *gh; + unsigned int slots = gfs_tune_get(sdp, gt_statfs_slots); + unsigned int x; + int done; + int error = 0, err; + + memset(sg, 0, sizeof(struct gfs_stat_gfs)); + + gha = vmalloc(slots * sizeof(struct gfs_holder)); + if (!gha) + return -ENOMEM; + memset(gha, 0, slots * sizeof(struct gfs_holder)); + + for (;;) { + done = TRUE; + + for (x = 0; x < slots; x++) { + gh = gha + x; + + if (gh->gh_gl && gfs_glock_poll(gh)) { + err = gfs_glock_wait(gh); + if (err) { + gfs_holder_uninit(gh); + error = err; + } else { + if (!error) + error = stat_gfs_fill(get_gl2rgd(gh->gh_gl), sg); + gfs_glock_dq_uninit(gh); + } + } + + if (gh->gh_gl) + done = FALSE; + else if (rgd_next && !error) { + error = gfs_glock_nq_init(rgd_next->rd_gl, + LM_ST_SHARED, + GL_LOCAL_EXCL | GL_SKIP | GL_ASYNC, + gh); + rgd_next = gfs_rgrpd_get_next(rgd_next); + done = FALSE; + } + + if (interruptible && signal_pending(current)) + error = -ERESTARTSYS; + } + + if (done) + break; + + yield(); + } + + vfree(gha); + + return error; +} + +/** + * stat_gfs_sync - Stat a filesystem using synchronous locking + * @sdp: the filesystem + * @sg: the sg info that will be returned + * @interruptible: TRUE if we should look for signals. + * + * Returns: errno + */ + +static int +stat_gfs_sync(struct gfs_sbd *sdp, struct gfs_stat_gfs *sg, int interruptible) +{ + struct gfs_holder rgd_gh; + struct gfs_rgrpd *rgd; + int error; + + memset(sg, 0, sizeof(struct gfs_stat_gfs)); + + for (rgd = gfs_rgrpd_get_first(sdp); + rgd; + rgd = gfs_rgrpd_get_next(rgd)) { + for (;;) { + error = gfs_glock_nq_init(rgd->rd_gl, + LM_ST_SHARED, + GL_LOCAL_EXCL | GL_SKIP, + &rgd_gh); + if (error) + return error; + + error = stat_gfs_fill(rgd, sg); + + gfs_glock_dq_uninit(&rgd_gh); + + if (!error) + break; + + error = gfs_rgrp_lvb_init(rgd); + if (error) + return error; + } + + if (interruptible && signal_pending(current)) + return -ERESTARTSYS; + } + + return 0; +} + +/** + * gfs_stat_gfs - Do a statfs + * @sdp: the filesystem + * @sg: the sg structure + * @interruptible: Stop if there is a signal pending + * + * Returns: errno + */ + +int +gfs_stat_gfs(struct gfs_sbd *sdp, struct gfs_stat_gfs *sg, int interruptible) +{ + struct gfs_holder ri_gh; + int error; + + error = gfs_rindex_hold(sdp, &ri_gh); + if (error) + return error; + + error = stat_gfs_async(sdp, sg, interruptible); + if (error == -ESTALE) + error = stat_gfs_sync(sdp, sg, interruptible); + + gfs_glock_dq_uninit(&ri_gh); + + return error; +} + +/** + * gfs_lock_fs_check_clean - Stop all writes to the FS and check that all journals are clean + * @sdp: the file system + * @state: the state to put the transaction lock into + * @t_gh: the hold on the transaction lock + * + * Returns: errno + */ + +int +gfs_lock_fs_check_clean(struct gfs_sbd *sdp, unsigned int state, + struct gfs_holder *t_gh) +{ + struct gfs_holder ji_gh, cl_gh; + struct gfs_log_header lh; + unsigned int x; + int error; + + error = gfs_jindex_hold(sdp, &ji_gh); + if (error) + return error; + + error = gfs_glock_nq_num(sdp, + GFS_CRAP_LOCK, &gfs_meta_glops, + LM_ST_SHARED, GL_NOCACHE, + &cl_gh); + if (error) + goto fail; + + error = gfs_glock_nq_init(sdp->sd_trans_gl, state, + LM_FLAG_PRIORITY | GL_EXACT | GL_NOCACHE, + t_gh); + if (error) + goto fail_gunlock_craplock; + + for (x = 0; x < sdp->sd_journals; x++) { + error = gfs_find_jhead(sdp, &sdp->sd_jindex[x], + cl_gh.gh_gl, &lh); + if (error) + goto fail_gunlock_trans; + + if (!(lh.lh_flags & GFS_LOG_HEAD_UNMOUNT)) { + error = -EBUSY; + goto fail_gunlock_trans; + } + } + + gfs_glock_dq_uninit(&cl_gh); + gfs_glock_dq_uninit(&ji_gh); + + return 0; + + fail_gunlock_trans: + gfs_glock_dq_uninit(t_gh); + + fail_gunlock_craplock: + gfs_glock_dq_uninit(&cl_gh); + + fail: + gfs_glock_dq_uninit(&ji_gh); + + return error; +} + +/** + * gfs_freeze_fs - freezes the file system + * @sdp: the file system + * + * This function flushes data and meta data for all machines by + * aquiring the transaction log exclusively. All journals are + * ensured to be in a clean state as well. + * + * Returns: errno + */ + +int +gfs_freeze_fs(struct gfs_sbd *sdp) +{ + int error = 0; + + down(&sdp->sd_freeze_lock); + + if (!sdp->sd_freeze_count++) { + error = gfs_lock_fs_check_clean(sdp, LM_ST_DEFERRED, + &sdp->sd_freeze_gh); + if (error) + sdp->sd_freeze_count--; + else + sdp->sd_freeze_gh.gh_owner = NULL; + } + + up(&sdp->sd_freeze_lock); + + return error; +} + +/** + * gfs_unfreeze_fs - unfreezes the file system + * @sdp: the file system + * + * This function allows the file system to proceed by unlocking + * the exclusively held transaction lock. Other GFS nodes are + * now free to acquire the lock shared and go on with their lives. + * + */ + +void +gfs_unfreeze_fs(struct gfs_sbd *sdp) +{ + down(&sdp->sd_freeze_lock); + + if (sdp->sd_freeze_count && !--sdp->sd_freeze_count) + gfs_glock_dq_uninit(&sdp->sd_freeze_gh); + + up(&sdp->sd_freeze_lock); +} + +/* + * Fast statfs implementation - mostly based on GFS2 implementation. + */ + +void gfs_statfs_change_in(struct gfs_statfs_change_host *sc, const void *buf) +{ + const struct gfs_statfs_change *str = buf; + + sc->sc_total = be64_to_cpu(str->sc_total); + sc->sc_free = be64_to_cpu(str->sc_free); + sc->sc_dinodes = be64_to_cpu(str->sc_dinodes); +} + +void gfs_statfs_change_out(const struct gfs_statfs_change_host *sc, void *buf) +{ + struct gfs_statfs_change *str = buf; + + str->sc_total = cpu_to_be64(sc->sc_total); + str->sc_free = cpu_to_be64(sc->sc_free); + str->sc_dinodes = cpu_to_be64(sc->sc_dinodes); +} + +int gfs_statfs_start(struct gfs_sbd *sdp) +{ + struct gfs_stat_gfs sg; + struct gfs_inode *m_ip; + struct gfs_statfs_change_host *m_sc = &sdp->sd_statfs_master; + struct gfs_statfs_change_host *l_sc = &sdp->sd_statfs_local; + struct buffer_head *m_bh; + struct gfs_holder gh; + int error; + + printk("GFS: fsid=%s: fast statfs start time = %lu\n", + sdp->sd_fsname, get_seconds()); + + /* created via gfs_get_linode() in fill_super(). */ + /* gfs_inode_glops */ + m_ip = sdp->sd_linode; + + /* get real statistics */ + error = gfs_stat_gfs(sdp, &sg, TRUE); + if (error) + return error; + + /* make sure the page is refreshed via glock flushing */ + error = gfs_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE, + &gh); + if (error) + goto gfs_statfs_start_out; + + error = gfs_get_inode_buffer(m_ip, &m_bh); + if (error) + goto gfs_statfs_start_unlock; + + error = gfs_trans_begin(sdp, 1, 0); + if (error) + goto gfs_statfs_start_bh; + + spin_lock(&sdp->sd_statfs_spin); + m_sc->sc_total = sg.sg_total_blocks; + m_sc->sc_free = sg.sg_free + sg.sg_free_dinode + sg.sg_free_meta; + m_sc->sc_dinodes = sg.sg_used_dinode; + memset(l_sc, 0, sizeof(struct gfs_statfs_change_host)); + spin_unlock(&sdp->sd_statfs_spin); + + gfs_trans_add_bh(m_ip->i_gl, m_bh); + gfs_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs_dinode)); + + gfs_trans_end(sdp); + +gfs_statfs_start_bh: + brelse(m_bh); + +gfs_statfs_start_unlock: + gfs_glock_dq_uninit(&gh); + +gfs_statfs_start_out: + return 0; +} + +int gfs_statfs_init(struct gfs_sbd *sdp, int flag) +{ + int error; + + /* if flag == 0, do we want to turn this off ? */ + if (!flag) + return 0; + + error = gfs_statfs_start(sdp); + if (error) + printk("GFS: fsid=%s: can't initialize statfs subsystem: %d\n", + sdp->sd_fsname, error); + + return error; +} + +void gfs_statfs_modify(struct gfs_sbd *sdp, + int64_t total, + int64_t free, + int64_t dinodes) +{ + struct gfs_statfs_change_host *l_sc = &sdp->sd_statfs_local; + + spin_lock(&sdp->sd_statfs_spin); + l_sc->sc_total += total; + l_sc->sc_free += free; + l_sc->sc_dinodes += dinodes; + spin_unlock(&sdp->sd_statfs_spin); +} + +int gfs_statfs_sync(struct gfs_sbd *sdp) +{ + struct gfs_inode *m_ip = sdp->sd_linode; + struct gfs_statfs_change_host *m_sc = &sdp->sd_statfs_master; + struct gfs_statfs_change_host *l_sc = &sdp->sd_statfs_local; + struct gfs_holder gh; + struct buffer_head *m_bh; + int error; + + error = gfs_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE, + &gh); + if (error) + return error; + + error = gfs_get_inode_buffer(m_ip, &m_bh); + if (error) + goto gfs_statfs_sync_out; + + /* if no change, simply return */ + spin_lock(&sdp->sd_statfs_spin); + gfs_statfs_change_in(m_sc, m_bh->b_data + + sizeof(struct gfs_dinode)); + if (!l_sc->sc_total && !l_sc->sc_free && !l_sc->sc_dinodes) { + spin_unlock(&sdp->sd_statfs_spin); + goto out_bh; + } + spin_unlock(&sdp->sd_statfs_spin); + + error = gfs_trans_begin(sdp, 1, 0); + if (error) + goto out_bh; + + spin_lock(&sdp->sd_statfs_spin); + m_sc->sc_total += l_sc->sc_total; + m_sc->sc_free += l_sc->sc_free; + m_sc->sc_dinodes += l_sc->sc_dinodes; + memset(l_sc, 0, sizeof(struct gfs_statfs_change_host)); + spin_unlock(&sdp->sd_statfs_spin); + + gfs_trans_add_bh(m_ip->i_gl, m_bh); + gfs_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs_dinode)); + + gfs_trans_end(sdp); + +out_bh: + brelse(m_bh); + +gfs_statfs_sync_out: + gfs_glock_dq_uninit(&gh); + return error; +} + +int gfs_statfs_fast(struct gfs_sbd *sdp, void *b) +{ + struct kstatfs *buf = (struct kstatfs *)b; + struct gfs_statfs_change_host sc, *m_sc = &sdp->sd_statfs_master; + struct gfs_statfs_change_host *l_sc = &sdp->sd_statfs_local; + + spin_lock(&sdp->sd_statfs_spin); + + sc.sc_total = m_sc->sc_total + l_sc->sc_total; + sc.sc_free = m_sc->sc_free + l_sc->sc_free; + sc.sc_dinodes = m_sc->sc_dinodes + l_sc->sc_dinodes; + spin_unlock(&sdp->sd_statfs_spin); + + if (sc.sc_free < 0) + sc.sc_free = 0; + if (sc.sc_free > sc.sc_total) + sc.sc_free = sc.sc_total; + if (sc.sc_dinodes < 0) + sc.sc_dinodes = 0; + + /* fill in the statistics */ + memset(buf, 0, sizeof(struct kstatfs)); + + buf->f_type = GFS_MAGIC; buf->f_bsize = sdp->sd_sb.sb_bsize; + buf->f_blocks = sc.sc_total; + buf->f_bfree = sc.sc_free; + buf->f_bavail = sc.sc_free; + buf->f_files = sc.sc_dinodes + sc.sc_free; + buf->f_ffree = sc.sc_free; + buf->f_namelen = GFS_FNAMESIZE; + + return 0; +} --- linux-2.6.27.orig/ubuntu/gfs/lm.c +++ linux-2.6.27/ubuntu/gfs/lm.c @@ -0,0 +1,233 @@ +#include +#include +#include +#include +#include +#include + +#include "gfs_ondisk.h" +#include "gfs.h" +#include "incore.h" +#include "glock.h" +#include "lm.h" +#include "super.h" +#include "util.h" +#include "lvb.h" + +/** + * gfs_lm_mount - mount a locking protocol + * @sdp: the filesystem + * @args: mount arguements + * @silent: if 1, don't complain if the FS isn't a GFS fs + * + * Returns: errno + */ + +int gfs_lm_mount(struct gfs_sbd *sdp, int silent) +{ + char *proto = sdp->sd_proto_name; + char *table = sdp->sd_table_name; + int flags = 0; + int error; + + if (sdp->sd_args.ar_spectator) + flags |= LM_MFLAG_SPECTATOR; + + printk("Trying to join cluster \"%s\", \"%s\"\n", proto, table); + + error = gfs_mount_lockproto(proto, table, sdp->sd_args.ar_hostdata, + gfs_glock_cb, sdp, + GFS_MIN_LVB_SIZE, flags, + &sdp->sd_lockstruct, &sdp->sd_kobj); + if (error) { + printk("can't mount proto=%s, table=%s, hostdata=%s\n", + proto, table, sdp->sd_args.ar_hostdata); + goto out; + } + + if (gfs_assert_warn(sdp, sdp->sd_lockstruct.ls_lockspace) || + gfs_assert_warn(sdp, sdp->sd_lockstruct.ls_ops) || + gfs_assert_warn(sdp, sdp->sd_lockstruct.ls_lvb_size >= + GFS_MIN_LVB_SIZE)) { + gfs_unmount_lockproto(&sdp->sd_lockstruct); + goto out; + } + + if (sdp->sd_args.ar_spectator) + snprintf(sdp->sd_fsname, 256, "%s.s", table); + else + snprintf(sdp->sd_fsname, 256, "%s.%u", table, + sdp->sd_lockstruct.ls_jid); + + printk("Joined cluster. Now mounting FS...\n"); + if ((sdp->sd_lockstruct.ls_flags & LM_LSFLAG_LOCAL) && + !sdp->sd_args.ar_ignore_local_fs) { + sdp->sd_args.ar_localflocks = 1; + sdp->sd_args.ar_localcaching = 1; + } + + out: + return error; +} + +void gfs_lm_others_may_mount(struct gfs_sbd *sdp) +{ + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + sdp->sd_lockstruct.ls_ops->lm_others_may_mount( + sdp->sd_lockstruct.ls_lockspace); +} + +void gfs_lm_unmount(struct gfs_sbd *sdp) +{ + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + gfs_unmount_lockproto(&sdp->sd_lockstruct); +} + +int gfs_lm_withdraw(struct gfs_sbd *sdp, char *fmt, ...) +{ + va_list args; + + if (test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags)) + return 0; + + va_start(args, fmt); + vprintk(fmt, args); + va_end(args); + + printk("GFS: fsid=%s: about to withdraw from the cluster\n", + sdp->sd_fsname); + + BUG_ON(sdp->sd_args.ar_debug); + + printk("GFS: fsid=%s: telling LM to withdraw\n", + sdp->sd_fsname); + + gfs_withdraw_lockproto(&sdp->sd_lockstruct); + + printk("GFS: fsid=%s: withdrawn\n", + sdp->sd_fsname); + dump_stack(); + + return -1; +} + +int gfs_lm_get_lock(struct gfs_sbd *sdp, struct lm_lockname *name, + void **lockp) +{ + int error; + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + error = -EIO; + else + error = sdp->sd_lockstruct.ls_ops->lm_get_lock( + sdp->sd_lockstruct.ls_lockspace, name, lockp); + return error; +} + +void gfs_lm_put_lock(struct gfs_sbd *sdp, void *lock) +{ + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + sdp->sd_lockstruct.ls_ops->lm_put_lock(lock); +} + +unsigned int gfs_lm_lock(struct gfs_sbd *sdp, void *lock, + unsigned int cur_state, unsigned int req_state, + unsigned int flags) +{ + int ret; + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + ret = 0; + else + ret = sdp->sd_lockstruct.ls_ops->lm_lock(lock, + cur_state, + req_state, flags); + return ret; +} + +unsigned int gfs_lm_unlock(struct gfs_sbd *sdp, void *lock, + unsigned int cur_state) +{ + int ret; + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + ret = 0; + else + ret = sdp->sd_lockstruct.ls_ops->lm_unlock(lock, cur_state); + return ret; +} + +void gfs_lm_cancel(struct gfs_sbd *sdp, void *lock) +{ + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + sdp->sd_lockstruct.ls_ops->lm_cancel(lock); +} + +int gfs_lm_hold_lvb(struct gfs_sbd *sdp, void *lock, char **lvbp) +{ + int error; + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + error = -EIO; + else + error = sdp->sd_lockstruct.ls_ops->lm_hold_lvb(lock, lvbp); + return error; +} + +void gfs_lm_unhold_lvb(struct gfs_sbd *sdp, void *lock, char *lvb) +{ + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + sdp->sd_lockstruct.ls_ops->lm_unhold_lvb(lock, lvb); +} + +#if 0 +void gfs_lm_sync_lvb(struct gfs_sbd *sdp, void *lock, char *lvb) +{ + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + sdp->sd_lockstruct.ls_ops->lm_sync_lvb(lock, lvb); +} +#endif + +int gfs_lm_plock_get(struct gfs_sbd *sdp, struct lm_lockname *name, + struct file *file, struct file_lock *fl) +{ + int error; + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + error = -EIO; + else + error = sdp->sd_lockstruct.ls_ops->lm_plock_get( + sdp->sd_lockstruct.ls_lockspace, + name, file, fl); + return error; +} + +int gfs_lm_plock(struct gfs_sbd *sdp, struct lm_lockname *name, + struct file *file, int cmd, struct file_lock *fl) +{ + int error; + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + error = -EIO; + else + error = sdp->sd_lockstruct.ls_ops->lm_plock( + sdp->sd_lockstruct.ls_lockspace, + name, file, cmd, fl); + return error; +} + +int gfs_lm_punlock(struct gfs_sbd *sdp, struct lm_lockname *name, + struct file *file, struct file_lock *fl) +{ + int error; + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + error = -EIO; + else + error = sdp->sd_lockstruct.ls_ops->lm_punlock( + sdp->sd_lockstruct.ls_lockspace, + name, file, fl); + return error; +} + +void gfs_lm_recovery_done(struct gfs_sbd *sdp, unsigned int jid, + unsigned int message) +{ + if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + sdp->sd_lockstruct.ls_ops->lm_recovery_done( + sdp->sd_lockstruct.ls_lockspace, jid, message); +} + --- linux-2.6.27.orig/ubuntu/gfs/rgrp.h +++ linux-2.6.27/ubuntu/gfs/rgrp.h @@ -0,0 +1,75 @@ +#ifndef __RGRP_DOT_H__ +#define __RGRP_DOT_H__ + +void gfs_mhc_add(struct gfs_rgrpd *rgd, struct buffer_head **bh, + unsigned int num); +int gfs_mhc_fish(struct gfs_sbd *sdp, struct buffer_head *bh); +void gfs_mhc_zap(struct gfs_rgrpd *rgd); + +void gfs_depend_add(struct gfs_rgrpd *rgd, uint64_t formal_ino); +void gfs_depend_sync(struct gfs_rgrpd *rgd); + +struct gfs_rgrpd *gfs_blk2rgrpd(struct gfs_sbd *sdp, uint64_t blk); +struct gfs_rgrpd *gfs_rgrpd_get_first(struct gfs_sbd *sdp); +struct gfs_rgrpd *gfs_rgrpd_get_next(struct gfs_rgrpd *rgd); + +void gfs_clear_rgrpd(struct gfs_sbd *sdp); + +int gfs_rindex_hold(struct gfs_sbd *sdp, struct gfs_holder *ri_gh); + +int gfs_rgrp_read(struct gfs_rgrpd *rgd); +void gfs_rgrp_relse(struct gfs_rgrpd *rgd); + +void gfs_rgrp_lvb_fill(struct gfs_rgrpd *rgd); +int gfs_rgrp_lvb_init(struct gfs_rgrpd *rgd); + +struct gfs_alloc *gfs_alloc_get(struct gfs_inode *ip); +void gfs_alloc_put(struct gfs_inode *ip); + +int gfs_inplace_reserve_i(struct gfs_inode *ip, + char *file, unsigned int line); +#define gfs_inplace_reserve(ip) \ +gfs_inplace_reserve_i((ip), __FILE__, __LINE__) + +void gfs_inplace_release(struct gfs_inode *ip); + +unsigned char gfs_get_block_type(struct gfs_rgrpd *rgd, uint64_t block); + +void gfs_blkalloc(struct gfs_inode *ip, uint64_t *block); +int gfs_metaalloc(struct gfs_inode *ip, uint64_t *block); +int gfs_dialloc(struct gfs_inode *dip, uint64_t *block); + +void gfs_blkfree(struct gfs_inode *ip, uint64_t bstart, uint32_t blen); +void gfs_metafree(struct gfs_inode *ip, uint64_t bstart, uint32_t blen); +void gfs_difree_uninit(struct gfs_rgrpd *rgd, uint64_t addr); +void gfs_difree(struct gfs_rgrpd *rgd, struct gfs_inode *ip); + +extern void gfs_statfs_modify(struct gfs_sbd *sdp, + int64_t total, + int64_t free, + int64_t dinodes); + +/* + * gfs_rgrp_list + * + * Used to collect a list of all resource groups spanned by a given + * inode/file/directory + */ +struct gfs_rgrp_list { + unsigned int rl_rgrps; /* # (qty) of rgrps in list (array) */ + unsigned int rl_space; /* Current capacity in list for rgrps */ + struct gfs_rgrpd **rl_rgd; /* Array of ptrs to rgrp descriptors */ + struct gfs_holder *rl_ghs; /* Array of glock holders for rgrps */ +}; + +void gfs_rlist_add(struct gfs_sbd *sdp, struct gfs_rgrp_list *rlist, + uint64_t block); +void gfs_rlist_alloc(struct gfs_rgrp_list *rlist, unsigned int state, + int flags); +void gfs_rlist_free(struct gfs_rgrp_list *rlist); + +int gfs_reclaim_metadata(struct gfs_sbd *sdp, + uint64_t *inodes, + uint64_t *metadata); + +#endif /* __RGRP_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/ops_fstype.h +++ linux-2.6.27/ubuntu/gfs/ops_fstype.h @@ -0,0 +1,13 @@ +#ifndef __OPS_FSTYPE_DOT_H__ +#define __OPS_FSTYPE_DOT_H__ + +int gfs_sys_init(void); +void gfs_sys_uninit(void); +void gfs_sys_fs_del(struct gfs_sbd *sdp); +int gfs_test_bdev_super(struct super_block *sb, void *data); +int gfs_set_bdev_super(struct super_block *sb, void *data); +int init_names(struct gfs_sbd *sdp, int silent); + +extern struct file_system_type gfs_fs_type; + +#endif /* __OPS_FSTYPE_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/log.h +++ linux-2.6.27/ubuntu/gfs/log.h @@ -0,0 +1,66 @@ +#ifndef __LOG_DOT_H__ +#define __LOG_DOT_H__ + +/** + * gfs_log_lock - acquire the right to mess with the log manager + * @sdp: the filesystem + * + */ + +static __inline__ void +gfs_log_lock(struct gfs_sbd *sdp) +{ + down_write(&sdp->sd_log_lock); +} + +/** + * gfs_log_unlock - release the right to mess with the log manager + * @sdp: the filesystem + * + */ + +static __inline__ void +gfs_log_unlock(struct gfs_sbd *sdp) +{ + up_write(&sdp->sd_log_lock); +} + +unsigned int gfs_struct2blk(struct gfs_sbd *sdp, unsigned int nstruct, + unsigned int ssize); +unsigned int gfs_blk2seg(struct gfs_sbd *sdp, unsigned int blocks); + +int gfs_log_reserve(struct gfs_sbd *sdp, unsigned int segments, int jump_queue); +void gfs_log_release(struct gfs_sbd *sdp, unsigned int segments); + +void gfs_ail_start(struct gfs_sbd *sdp, int flags); +int gfs_ail_empty(struct gfs_sbd *sdp); + +void gfs_log_commit(struct gfs_sbd *sdp, struct gfs_trans *trans); +void gfs_log_flush(struct gfs_sbd *sdp); +void gfs_log_flush_glock(struct gfs_glock *gl); + +void gfs_log_shutdown(struct gfs_sbd *sdp); + +void gfs_log_dump(struct gfs_sbd *sdp, int force); + +/* Internal crap used the log operations */ + +/** + * gfs_log_is_header - Discover if block is on journal header + * @sdp: The GFS superblock + * @block: The block number + * + * Returns: TRUE if the block is on a journal segment boundary, FALSE otherwise + */ + +static __inline__ int +gfs_log_is_header(struct gfs_sbd *sdp, uint64_t block) +{ + return !do_mod(block, sdp->sd_sb.sb_seg_size); +} + +struct gfs_log_buf *gfs_log_get_buf(struct gfs_sbd *sdp, struct gfs_trans *tr); +void gfs_log_fake_buf(struct gfs_sbd *sdp, struct gfs_trans *tr, char *data, + struct buffer_head *unlock); + +#endif /* __LOG_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/format.h +++ linux-2.6.27/ubuntu/gfs/format.h @@ -0,0 +1,17 @@ +#ifndef __FORMAT_DOT_H__ +#define __FORMAT_DOT_H__ + +static const uint32_t gfs_old_fs_formats[] = { + 1308, + 1307, + 1306, + 1305, + 0 +}; + +static const uint32_t gfs_old_multihost_formats[] = { + 1400, + 0 +}; + +#endif /* __FORMAT_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/ops_dentry.c +++ linux-2.6.27/ubuntu/gfs/ops_dentry.c @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "dir.h" +#include "glock.h" +#include "ops_dentry.h" + +/** + * gfs_drevalidate - Check directory lookup consistency + * @dentry: the mapping to check + * @nd: + * + * Check to make sure the lookup necessary to arrive at this inode from its + * parent is still good. + * + * Returns: 1 if the dentry is ok, 0 if it isn't + */ + +static int +gfs_drevalidate(struct dentry *dentry, struct nameidata *nd) +{ + struct dentry *parent = dget_parent(dentry); + struct gfs_inode *dip = get_v2ip(parent->d_inode); + struct gfs_sbd *sdp = dip->i_sbd; + struct inode *inode; + struct gfs_holder d_gh; + struct gfs_inode *ip; + struct gfs_inum inum; + unsigned int type; + int error; + + lock_kernel(); + + atomic_inc(&sdp->sd_ops_dentry); + + if (sdp->sd_args.ar_localcaching) + goto valid; + + inode = dentry->d_inode; + if (inode && is_bad_inode(inode)) + goto invalid; + + error = gfs_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); + if (error) + goto fail; + + error = gfs_dir_search(dip, &dentry->d_name, &inum, &type); + switch (error) { + case 0: + if (!inode) + goto invalid_gunlock; + break; + case -ENOENT: + if (!inode) + goto valid_gunlock; + goto invalid_gunlock; + default: + goto fail_gunlock; + } + + ip = get_v2ip(inode); + + if (ip->i_num.no_formal_ino != inum.no_formal_ino) + goto invalid_gunlock; + + if (ip->i_di.di_type != type) { + gfs_consist_inode(dip); + goto fail_gunlock; + } + + valid_gunlock: + gfs_glock_dq_uninit(&d_gh); + + valid: + unlock_kernel(); + dput(parent); + return 1; + + invalid_gunlock: + gfs_glock_dq_uninit(&d_gh); + + invalid: + if (inode && S_ISDIR(inode->i_mode)) { + if (have_submounts(dentry)) + goto valid; + shrink_dcache_parent(dentry); + } + d_drop(dentry); + + unlock_kernel(); + dput(parent); + return 0; + + fail_gunlock: + gfs_glock_dq_uninit(&d_gh); + + fail: + unlock_kernel(); + dput(parent); + return 0; +} + +struct dentry_operations gfs_dops = { + .d_revalidate = gfs_drevalidate, +}; --- linux-2.6.27.orig/ubuntu/gfs/ops_inode.c +++ linux-2.6.27/ubuntu/gfs/ops_inode.c @@ -0,0 +1,1670 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "acl.h" +#include "bmap.h" +#include "dio.h" +#include "dir.h" +#include "eaops.h" +#include "eattr.h" +#include "glock.h" +#include "inode.h" +#include "ops_dentry.h" +#include "ops_inode.h" +#include "page.h" +#include "quota.h" +#include "rgrp.h" +#include "trans.h" +#include "unlinked.h" + +/** + * gfs_security_init - + * @dip: + * @ip: + * + * Returns: errno + */ + +static int +gfs_security_init(struct gfs_inode *dip, struct gfs_inode *ip) +{ + int err; + size_t len; + void *value; + char *name; + struct gfs_ea_request er; + + err = security_inode_init_security(ip->i_vnode, dip->i_vnode, + &name, &value, &len); + + if (err) { + if (err == -EOPNOTSUPP) + return 0; + return err; + } + + memset(&er, 0, sizeof(struct gfs_ea_request)); + + er.er_type = GFS_EATYPE_SECURITY; + er.er_name = name; + er.er_data = value; + er.er_name_len = strlen(name); + er.er_data_len = len; + + err = gfs_ea_set_i(ip, &er); + + kfree(value); + kfree(name); + + return err; +} + +/** + * gfs_create - Create a file + * @dir: The directory in which to create the file + * @dentry: The dentry of the new file + * @mode: The mode of the new file + * + * Returns: errno + */ + +static int +gfs_create(struct inode *dir, struct dentry *dentry, + int mode, struct nameidata *nd) +{ + struct gfs_inode *dip = get_v2ip(dir), *ip; + struct gfs_sbd *sdp = dip->i_sbd; + struct gfs_holder d_gh, i_gh; + struct inode *inode; + int new = TRUE; + int error; + + atomic_inc(&sdp->sd_ops_inode); + + gfs_unlinked_limit(sdp); + + gfs_holder_init(dip->i_gl, 0, 0, &d_gh); + + for (;;) { + error = gfs_createi(&d_gh, &dentry->d_name, + GFS_FILE_REG, mode, + &i_gh); + if (!error) + break; + else if (error != -EEXIST || + (nd && (nd->intent.open.flags & O_EXCL))) { + gfs_holder_uninit(&d_gh); + return error; + } + + error = gfs_lookupi(&d_gh, &dentry->d_name, + FALSE, &i_gh); + if (!error) { + if (i_gh.gh_gl) { + new = FALSE; + break; + } + } else { + gfs_holder_uninit(&d_gh); + return error; + } + } + + ip = get_gl2ip(i_gh.gh_gl); + + if (new) { + gfs_trans_end(sdp); + if (dip->i_alloc->al_rgd) + gfs_inplace_release(dip); + gfs_quota_unlock_m(dip); + gfs_unlinked_unlock(sdp, dip->i_alloc->al_ul); + gfs_alloc_put(dip); + } + + inode = gfs_iget(ip, CREATE); + gfs_inode_put(ip); + + if (!inode) + error = -ENOMEM; + else + error = gfs_security_init(dip, ip); + + gfs_glock_dq_uninit(&d_gh); + gfs_glock_dq_uninit(&i_gh); + + if (error) + return error; + + d_instantiate(dentry, inode); + if (new) + mark_inode_dirty(inode); + + return 0; +} + +/** + * lookup_cdpn_sub_at - Maybe lookup a Context Dependent Pathname + * @sdp: the filesystem + * @dentry: the original dentry to lookup + * @new_dentry: the new dentry, if this was a substitutable path. + * + * Returns: the new dentry, a ERR_PTR, or NULL + */ + +static struct dentry * +lookup_cdpn_sub_at(struct gfs_sbd *sdp, struct dentry *dentry) +{ + struct dentry *parent, *new = NULL; + char *buf; + + buf = kmalloc(2 * __NEW_UTS_LEN + 2, GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + parent = dget_parent(dentry); + + if (gfs_filecmp(&dentry->d_name, "@hostname", 9)) + new = lookup_one_len(init_utsname()->nodename, + parent, + strlen(init_utsname()->nodename)); + else if (gfs_filecmp(&dentry->d_name, "@mach", 5)) + new = lookup_one_len(init_utsname()->machine, + parent, + strlen(init_utsname()->machine)); + else if (gfs_filecmp(&dentry->d_name, "@os", 3)) + new = lookup_one_len(init_utsname()->sysname, + parent, + strlen(init_utsname()->sysname)); + else if (gfs_filecmp(&dentry->d_name, "@uid", 4)) + new = lookup_one_len(buf, + parent, + sprintf(buf, "%u", current->fsuid)); + else if (gfs_filecmp(&dentry->d_name, "@gid", 4)) + new = lookup_one_len(buf, + parent, + sprintf(buf, "%u", current->fsgid)); + else if (gfs_filecmp(&dentry->d_name, "@sys", 4)) + new = lookup_one_len(buf, + parent, + sprintf(buf, "%s_%s", + init_utsname()->machine, + init_utsname()->sysname)); + else if (gfs_filecmp(&dentry->d_name, "@jid", 4)) + new = lookup_one_len(buf, + parent, + sprintf(buf, "%u", + sdp->sd_lockstruct.ls_jid)); + + dput(parent); + kfree(buf); + + return new; +} + +/** + * lookup_cdpn_sub_brace - Maybe lookup a Context Dependent Pathname + * @sdp: the filesystem + * @dentry: the original dentry to lookup + * @new_dentry: the new dentry, if this was a substitutable path. + * + * Returns: the new dentry, a ERR_PTR, or NULL + */ + +static struct dentry * +lookup_cdpn_sub_brace(struct gfs_sbd *sdp, struct dentry *dentry) +{ + struct dentry *parent, *new = NULL; + char *buf; + + buf = kmalloc(2 * __NEW_UTS_LEN + 2, GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + parent = dget_parent(dentry); + + if (gfs_filecmp(&dentry->d_name, "{hostname}", 10)) + new = lookup_one_len(init_utsname()->nodename, + parent, + strlen(init_utsname()->nodename)); + else if (gfs_filecmp(&dentry->d_name, "{mach}", 6)) + new = lookup_one_len(init_utsname()->machine, + parent, + strlen(init_utsname()->machine)); + else if (gfs_filecmp(&dentry->d_name, "{os}", 4)) + new = lookup_one_len(init_utsname()->sysname, + parent, + strlen(init_utsname()->sysname)); + else if (gfs_filecmp(&dentry->d_name, "{uid}", 5)) + new = lookup_one_len(buf, + parent, + sprintf(buf, "%u", current->fsuid)); + else if (gfs_filecmp(&dentry->d_name, "{gid}", 5)) + new = lookup_one_len(buf, + parent, + sprintf(buf, "%u", current->fsgid)); + else if (gfs_filecmp(&dentry->d_name, "{sys}", 5)) + new = lookup_one_len(buf, + parent, + sprintf(buf, "%s_%s", + init_utsname()->machine, + init_utsname()->sysname)); + else if (gfs_filecmp(&dentry->d_name, "{jid}", 5)) + new = lookup_one_len(buf, + parent, + sprintf(buf, "%u", + sdp->sd_lockstruct.ls_jid)); + + dput(parent); + kfree(buf); + + return new; +} + +/** + * gfs_lookup - Look up a filename in a directory and return its inode + * @dir: The directory inode + * @dentry: The dentry of the new inode + * @nd: passed from Linux VFS, ignored by us + * + * Called by the VFS layer. Lock dir and call gfs_lookupi() + * + * Returns: errno + */ + +static struct dentry * +gfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) +{ + struct gfs_inode *dip = get_v2ip(dir), *ip; + struct gfs_holder d_gh, i_gh; + struct inode *inode = NULL; + int error; + + atomic_inc(&dip->i_sbd->sd_ops_inode); + + /* Do Context Dependent Path Name expansion */ + + if (*dentry->d_name.name == '@' && dentry->d_name.len > 1) { + struct dentry *new_dentry; + new_dentry = lookup_cdpn_sub_at(dip->i_sbd, dentry); + if (new_dentry) + return new_dentry; + } else if (*dentry->d_name.name == '{' && dentry->d_name.len > 2) { + struct dentry *new_dentry; + new_dentry = lookup_cdpn_sub_brace(dip->i_sbd, dentry); + if (new_dentry) + return new_dentry; + } + + dentry->d_op = &gfs_dops; + + gfs_holder_init(dip->i_gl, 0, 0, &d_gh); + + error = gfs_lookupi(&d_gh, &dentry->d_name, FALSE, &i_gh); + if (error) { + gfs_holder_uninit(&d_gh); + return ERR_PTR(error); + } + + if (i_gh.gh_gl) { + ip = get_gl2ip(i_gh.gh_gl); + + inode = gfs_iget(ip, CREATE); + gfs_inode_put(ip); + + gfs_glock_dq_uninit(&d_gh); + gfs_glock_dq_uninit(&i_gh); + + if (!inode) + return ERR_PTR(-ENOMEM); + } else + gfs_holder_uninit(&d_gh); + + if (inode) + return d_splice_alias(inode, dentry); + d_add(dentry, inode); + + return NULL; +} + +/** + * gfs_link - Link to a file + * @old_dentry: The inode to link + * @dir: Add link to this directory + * @dentry: The name of the link + * + * Link the inode in "old_dentry" into the directory "dir" with the + * name in "dentry". + * + * Returns: errno + */ + +static int +gfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) +{ + struct gfs_inode *dip = get_v2ip(dir); + struct gfs_sbd *sdp = dip->i_sbd; + struct inode *inode = old_dentry->d_inode; + struct gfs_inode *ip = get_v2ip(inode); + struct gfs_alloc *al = NULL; + struct gfs_holder ghs[2]; + int alloc_required; + int error; + + atomic_inc(&sdp->sd_ops_inode); + + if (ip->i_di.di_type == GFS_FILE_DIR) + return -EPERM; + + gfs_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, &ghs[0]); + gfs_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ghs[1]); + + error = gfs_glock_nq_m(2, ghs); + if (error) + goto fail; + + error = inode_permission(dir, MAY_WRITE | MAY_EXEC); + if (error) + goto fail_gunlock; + + error = gfs_dir_search(dip, &dentry->d_name, NULL, NULL); + switch (error) { + case -ENOENT: + break; + case 0: + error = -EEXIST; + default: + goto fail_gunlock; + } + + if (!dip->i_di.di_nlink) { + error = -EINVAL; + goto fail_gunlock; + } + if (dip->i_di.di_entries == (uint32_t)-1) { + error = -EFBIG; + goto fail_gunlock; + } + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { + error = -EPERM; + goto fail_gunlock; + } + if (!ip->i_di.di_nlink) { + error = -EINVAL; + goto fail_gunlock; + } + if (ip->i_di.di_nlink == (uint32_t)-1) { + error = -EMLINK; + goto fail_gunlock; + } + + error = gfs_diradd_alloc_required(dip, &dentry->d_name, &alloc_required); + if (error) + goto fail_gunlock; + + if (alloc_required) { + al = gfs_alloc_get(dip); + + error = gfs_quota_lock_m(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto fail_alloc; + + error = gfs_quota_check(dip, dip->i_di.di_uid, dip->i_di.di_gid); + if (error) + goto fail_gunlock_q; + + al->al_requested_meta = sdp->sd_max_dirres; + + error = gfs_inplace_reserve(dip); + if (error) + goto fail_gunlock_q; + + /* Trans may require: + two dinode blocks, directory modifications to add an entry, + RG bitmap blocks to allocate from, and quota change */ + + error = gfs_trans_begin(sdp, + 2 + sdp->sd_max_dirres + + al->al_rgd->rd_ri.ri_length, + 1); + if (error) + goto fail_ipres; + } else { + /* Trans may require: + Two dinode blocks and a leaf block. */ + + error = gfs_trans_begin(sdp, 3, 0); + if (error) + goto fail_ipres; + } + + error = gfs_dir_add(dip, &dentry->d_name, &ip->i_num, ip->i_di.di_type); + if (error) + goto fail_end_trans; + + error = gfs_change_nlink(ip, +1); + if (error) + goto fail_end_trans; + + gfs_trans_end(sdp); + + if (alloc_required) { + gfs_assert_warn(sdp, al->al_alloced_meta); + gfs_inplace_release(dip); + gfs_quota_unlock_m(dip); + gfs_alloc_put(dip); + } + + gfs_glock_dq_m(2, ghs); + + gfs_holder_uninit(&ghs[0]); + gfs_holder_uninit(&ghs[1]); + + atomic_inc(&inode->i_count); + + d_instantiate(dentry, inode); + mark_inode_dirty(inode); + + return 0; + + fail_end_trans: + gfs_trans_end(sdp); + + fail_ipres: + if (alloc_required) + gfs_inplace_release(dip); + + fail_gunlock_q: + if (alloc_required) + gfs_quota_unlock_m(dip); + + fail_alloc: + if (alloc_required) + gfs_alloc_put(dip); + + fail_gunlock: + gfs_glock_dq_m(2, ghs); + + fail: + gfs_holder_uninit(&ghs[0]); + gfs_holder_uninit(&ghs[1]); + + return error; +} + +/** + * gfs_unlink - Unlink a file + * @dir: The inode of the directory containing the file to unlink + * @dentry: The file itself + * + * Unlink a file. Call gfs_unlinki() + * + * Returns: errno + */ + +static int +gfs_unlink(struct inode *dir, struct dentry *dentry) +{ + struct gfs_inode *dip = get_v2ip(dir); + struct gfs_sbd *sdp = dip->i_sbd; + struct gfs_inode *ip = get_v2ip(dentry->d_inode); + struct gfs_holder ghs[2]; + int error; + + atomic_inc(&sdp->sd_ops_inode); + + gfs_unlinked_limit(sdp); + + gfs_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, &ghs[0]); + gfs_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ghs[1]); + + error = gfs_glock_nq_m(2, ghs); + if (error) + goto fail; + + error = gfs_unlink_ok(dip, &dentry->d_name, ip); + if (error) + goto fail_gunlock; + + /* Trans may require: + Two dinode blocks and one modified directory leaf block + and one unlinked tag. */ + + error = gfs_trans_begin(sdp, 3, 1); + if (error) + goto fail_gunlock; + + error = gfs_unlinki(dip, &dentry->d_name, ip); + if (error) + goto fail_end_trans; + + gfs_trans_end(sdp); + + gfs_glock_dq_m(2, ghs); + + gfs_holder_uninit(&ghs[0]); + gfs_holder_uninit(&ghs[1]); + + return 0; + + fail_end_trans: + gfs_trans_end(sdp); + + fail_gunlock: + gfs_glock_dq_m(2, ghs); + + fail: + gfs_holder_uninit(&ghs[0]); + gfs_holder_uninit(&ghs[1]); + + return error; +} + +/** + * gfs_symlink - Create a symlink + * @dir: The directory to create the symlink in + * @dentry: The dentry to put the symlink in + * @symname: The thing which the link points to + * + * Returns: errno + */ + +static int +gfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) +{ + struct gfs_inode *dip = get_v2ip(dir), *ip; + struct gfs_sbd *sdp = dip->i_sbd; + struct gfs_holder d_gh, i_gh; + struct inode *inode; + struct buffer_head *dibh; + int size; + int error; + + atomic_inc(&sdp->sd_ops_inode); + + gfs_unlinked_limit(sdp); + + /* Must be stuffed with a null terminator for gfs_follow_link() */ + size = strlen(symname); + if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs_dinode) - 1) + return -ENAMETOOLONG; + + gfs_holder_init(dip->i_gl, 0, 0, &d_gh); + + error = gfs_createi(&d_gh, &dentry->d_name, + GFS_FILE_LNK, S_IFLNK | S_IRWXUGO, + &i_gh); + if (error) { + gfs_holder_uninit(&d_gh); + return error; + } + + ip = get_gl2ip(i_gh.gh_gl); + + ip->i_di.di_size = size; + + error = gfs_get_inode_buffer(ip, &dibh); + + if (!gfs_assert_withdraw(sdp, !error)) { + gfs_dinode_out(&ip->i_di, dibh->b_data); + memcpy(dibh->b_data + sizeof(struct gfs_dinode), symname, size); + brelse(dibh); + } + + gfs_trans_end(sdp); + if (dip->i_alloc->al_rgd) + gfs_inplace_release(dip); + gfs_quota_unlock_m(dip); + gfs_unlinked_unlock(sdp, dip->i_alloc->al_ul); + gfs_alloc_put(dip); + + inode = gfs_iget(ip, CREATE); + gfs_inode_put(ip); + + error = gfs_security_init(dip, ip); + + gfs_glock_dq_uninit(&d_gh); + gfs_glock_dq_uninit(&i_gh); + + if (error) + return error; + + if (!inode) + return -ENOMEM; + + d_instantiate(dentry, inode); + mark_inode_dirty(inode); + + return 0; +} + +/** + * gfs_mkdir - Make a directory + * @dir: The parent directory of the new one + * @dentry: The dentry of the new directory + * @mode: The mode of the new directory + * + * Returns: errno + */ + +static int +gfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + struct gfs_inode *dip = get_v2ip(dir), *ip; + struct gfs_sbd *sdp = dip->i_sbd; + struct gfs_holder d_gh, i_gh; + struct inode *inode; + struct buffer_head *dibh; + int error; + + atomic_inc(&sdp->sd_ops_inode); + + gfs_unlinked_limit(sdp); + + gfs_holder_init(dip->i_gl, 0, 0, &d_gh); + + error = gfs_createi(&d_gh, &dentry->d_name, + GFS_FILE_DIR, S_IFDIR | mode, + &i_gh); + if (error) { + gfs_holder_uninit(&d_gh); + return error; + } + + ip = get_gl2ip(i_gh.gh_gl); + + ip->i_di.di_nlink = 2; + ip->i_di.di_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs_dinode); + ip->i_di.di_flags |= GFS_DIF_JDATA; + ip->i_di.di_payload_format = GFS_FORMAT_DE; + ip->i_di.di_entries = 2; + + error = gfs_get_inode_buffer(ip, &dibh); + + if (!gfs_assert_withdraw(sdp, !error)) { + struct gfs_dinode *di = (struct gfs_dinode *)dibh->b_data; + struct gfs_dirent *dent; + + gfs_dirent_alloc(ip, dibh, 1, &dent); + + dent->de_inum = di->di_num; /* already GFS endian */ + dent->de_hash = gfs_dir_hash(".", 1); + dent->de_hash = cpu_to_gfs32(dent->de_hash); + dent->de_type = cpu_to_gfs16(GFS_FILE_DIR); + memcpy((char *) (dent + 1), ".", 1); + di->di_entries = cpu_to_gfs32(1); + + gfs_dirent_alloc(ip, dibh, 2, &dent); + + gfs_inum_out(&dip->i_num, (char *) &dent->de_inum); + dent->de_hash = gfs_dir_hash("..", 2); + dent->de_hash = cpu_to_gfs32(dent->de_hash); + dent->de_type = cpu_to_gfs16(GFS_FILE_DIR); + memcpy((char *) (dent + 1), "..", 2); + + gfs_dinode_out(&ip->i_di, (char *)di); + + brelse(dibh); + } + + error = gfs_change_nlink(dip, +1); + gfs_assert_withdraw(sdp, !error); /* dip already pinned */ + + gfs_trans_end(sdp); + if (dip->i_alloc->al_rgd) + gfs_inplace_release(dip); + gfs_quota_unlock_m(dip); + gfs_unlinked_unlock(sdp, dip->i_alloc->al_ul); + gfs_alloc_put(dip); + + inode = gfs_iget(ip, CREATE); + gfs_inode_put(ip); + + if (!inode) + return -ENOMEM; + + error = gfs_security_init(dip, ip); + + gfs_glock_dq_uninit(&d_gh); + gfs_glock_dq_uninit(&i_gh); + + if (error) + return error; + + d_instantiate(dentry, inode); + mark_inode_dirty(inode); + + return 0; +} + +/** + * gfs_rmdir - Remove a directory + * @dir: The parent directory of the directory to be removed + * @dentry: The dentry of the directory to remove + * + * Remove a directory. Call gfs_rmdiri() + * + * Returns: errno + */ + +static int +gfs_rmdir(struct inode *dir, struct dentry *dentry) +{ + struct gfs_inode *dip = get_v2ip(dir); + struct gfs_sbd *sdp = dip->i_sbd; + struct gfs_inode *ip = get_v2ip(dentry->d_inode); + struct gfs_holder ghs[2]; + int error; + + atomic_inc(&sdp->sd_ops_inode); + + gfs_unlinked_limit(sdp); + + gfs_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, &ghs[0]); + gfs_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ghs[1]); + + error = gfs_glock_nq_m(2, ghs); + if (error) + goto fail; + + error = gfs_unlink_ok(dip, &dentry->d_name, ip); + if (error) + goto fail_gunlock; + + if (ip->i_di.di_entries < 2) { + if (gfs_consist_inode(ip)) + gfs_dinode_print(&ip->i_di); + error = -EIO; + goto fail_gunlock; + } + if (ip->i_di.di_entries > 2) { + error = -ENOTEMPTY; + goto fail_gunlock; + } + + /* Trans may require: + Two dinode blocks, one directory leaf block containing the + entry to be rmdired, two leaf blocks containing . and .. of + the directory being rmdired, and one unlinked tag */ + + error = gfs_trans_begin(sdp, 5, 1); + if (error) + goto fail_gunlock; + + error = gfs_rmdiri(dip, &dentry->d_name, ip); + if (error) + goto fail_end_trans; + + gfs_trans_end(sdp); + + gfs_glock_dq_m(2, ghs); + + gfs_holder_uninit(&ghs[0]); + gfs_holder_uninit(&ghs[1]); + + return 0; + + fail_end_trans: + gfs_trans_end(sdp); + + fail_gunlock: + gfs_glock_dq_m(2, ghs); + + fail: + gfs_holder_uninit(&ghs[0]); + gfs_holder_uninit(&ghs[1]); + + return error; +} + +/** + * gfs_mknod - Make a special file + * @dir: The directory in which the special file will reside + * @dentry: The dentry of the special file + * @mode: The mode of the special file + * @rdev: The device specification of the special file + * + */ + +static int +gfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +{ + struct gfs_inode *dip = get_v2ip(dir), *ip; + struct gfs_sbd *sdp = dip->i_sbd; + struct gfs_holder d_gh, i_gh; + struct inode *inode; + struct buffer_head *dibh; + uint16_t type = 0; + uint32_t major = 0, minor = 0; + int error; + + atomic_inc(&sdp->sd_ops_inode); + + gfs_unlinked_limit(sdp); + + switch (mode & S_IFMT) { + case S_IFBLK: + type = GFS_FILE_BLK; + major = MAJOR(dev); + minor = MINOR(dev); + break; + case S_IFCHR: + type = GFS_FILE_CHR; + major = MAJOR(dev); + minor = MINOR(dev); + break; + case S_IFIFO: + type = GFS_FILE_FIFO; + break; + case S_IFSOCK: + type = GFS_FILE_SOCK; + break; + default: + printk("GFS: fsid=%s: mknod() with invalid type (%d)\n", + sdp->sd_fsname, mode); + return -EINVAL; + }; + + gfs_holder_init(dip->i_gl, 0, 0, &d_gh); + + error = gfs_createi(&d_gh, &dentry->d_name, + type, mode, + &i_gh); + if (error) { + gfs_holder_uninit(&d_gh); + return error; + } + + ip = get_gl2ip(i_gh.gh_gl); + + ip->i_di.di_major = major; + ip->i_di.di_minor = minor; + + error = gfs_get_inode_buffer(ip, &dibh); + + if (!gfs_assert_withdraw(sdp, !error)) { + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + gfs_trans_end(sdp); + if (dip->i_alloc->al_rgd) + gfs_inplace_release(dip); + gfs_quota_unlock_m(dip); + gfs_unlinked_unlock(sdp, dip->i_alloc->al_ul); + gfs_alloc_put(dip); + + inode = gfs_iget(ip, CREATE); + gfs_inode_put(ip); + + error = gfs_security_init(dip, ip); + + gfs_glock_dq_uninit(&d_gh); + gfs_glock_dq_uninit(&i_gh); + + if (error) + return error; + + if (!inode) + return -ENOMEM; + + d_instantiate(dentry, inode); + mark_inode_dirty(inode); + + return 0; +} + +/** + * gfs_rename - Rename a file + * @odir: Parent directory of old file name + * @odentry: The old dentry of the file + * @ndir: Parent directory of new file name + * @ndentry: The new dentry of the file + * + * Returns: errno + */ + +static int +gfs_rename(struct inode *odir, struct dentry *odentry, + struct inode *ndir, struct dentry *ndentry) +{ + struct gfs_inode *odip = get_v2ip(odir); + struct gfs_inode *ndip = get_v2ip(ndir); + struct gfs_inode *ip = get_v2ip(odentry->d_inode); + struct gfs_inode *nip = NULL; + struct gfs_sbd *sdp = odip->i_sbd; + struct qstr name; + struct gfs_alloc *al; + struct gfs_holder ghs[4], r_gh; + unsigned int num_gh; + int dir_rename = FALSE; + int alloc_required; + unsigned int x; + int error; + + atomic_inc(&sdp->sd_ops_inode); + + gfs_unlinked_limit(sdp); + + if (ndentry->d_inode) { + nip = get_v2ip(ndentry->d_inode); + if (ip == nip) + return 0; + } + + /* Make sure we aren't trying to move a dirctory into it's subdir */ + + if (ip->i_di.di_type == GFS_FILE_DIR && odip != ndip) { + dir_rename = TRUE; + + error = gfs_glock_nq_init(sdp->sd_rename_gl, + LM_ST_EXCLUSIVE, 0, + &r_gh); + if (error) + return error; + + error = gfs_ok_to_move(ip, ndip); + if (error) + goto fail; + } + + gfs_holder_init(odip->i_gl, LM_ST_EXCLUSIVE, 0, &ghs[0]); + gfs_holder_init(ndip->i_gl, LM_ST_EXCLUSIVE, 0, &ghs[1]); + num_gh = 2; + + if (nip) + gfs_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, &ghs[num_gh++]); + + if (dir_rename) + gfs_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ghs[num_gh++]); + + error = gfs_glock_nq_m(num_gh, ghs); + if (error) + goto fail_uninit; + + /* Check out the old directory */ + + error = gfs_unlink_ok(odip, &odentry->d_name, ip); + if (error) + goto fail_gunlock; + + /* Check out the new directory */ + + if (nip) { + error = gfs_unlink_ok(ndip, &ndentry->d_name, nip); + if (error) + goto fail_gunlock; + + if (nip->i_di.di_type == GFS_FILE_DIR) { + if (nip->i_di.di_entries < 2) { + if (gfs_consist_inode(nip)) + gfs_dinode_print(&nip->i_di); + error = -EIO; + goto fail_gunlock; + } + if (nip->i_di.di_entries > 2) { + error = -ENOTEMPTY; + goto fail_gunlock; + } + } + } else { + error = inode_permission(ndir, MAY_WRITE | MAY_EXEC); + if (error) + goto fail_gunlock; + + error = gfs_dir_search(ndip, &ndentry->d_name, NULL, NULL); + switch (error) { + case -ENOENT: + error = 0; + break; + case 0: + error = -EEXIST; + default: + goto fail_gunlock; + }; + + if (odip != ndip) { + if (!ndip->i_di.di_nlink) { + error = -EINVAL; + goto fail_gunlock; + } + if (ndip->i_di.di_entries == (uint32_t)-1) { + error = -EFBIG; + goto fail_gunlock; + } + if (ip->i_di.di_type == GFS_FILE_DIR && + ndip->i_di.di_nlink == (uint32_t)-1) { + error = -EMLINK; + goto fail_gunlock; + } + } + } + + error = gfs_diradd_alloc_required(ndip, &ndentry->d_name, &alloc_required); + if (error) + goto fail_gunlock; + + if (alloc_required) { + al = gfs_alloc_get(ndip); + + error = gfs_quota_lock_m(ndip, + NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto fail_alloc; + + error = gfs_quota_check(ndip, ndip->i_di.di_uid, ndip->i_di.di_gid); + if (error) + goto fail_gunlock_q; + + al->al_requested_meta = sdp->sd_max_dirres; + + error = gfs_inplace_reserve(ndip); + if (error) + goto fail_gunlock_q; + + /* Trans may require: + Dinodes for the srcdir, srcino, dstdir, dstino. Blocks for + adding the entry to dstdir. RG bitmaps for that allocation. + One leaf block in the srcdir for removal of the entry. + One leaf block for changing .. in srcino (if it's a directory). + Two leaf blocks for removing . and .. from dstino (if it exists + and it's a directory), one unlinked tag, and one quota block. */ + + error = gfs_trans_begin(sdp, + 8 + sdp->sd_max_dirres + + al->al_rgd->rd_ri.ri_length, + 2); + if (error) + goto fail_ipres; + } else { + /* Trans may require: + Dinodes for the srcdir, srcino, dstdir, dstino. One block for + adding the entry to dstdir. + One leaf block in the srcdir for removal of the entry. + One leaf block for changing .. in srcino (if it's a directory). + Two leaf blocks for removing . and .. from dstino (if it exists + and it's a directory), and one unlinked tag. */ + + error = gfs_trans_begin(sdp, 9, 1); + if (error) + goto fail_ipres; + } + + /* Remove the target file, if it exists */ + + if (nip) { + if (nip->i_di.di_type == GFS_FILE_DIR) + error = gfs_rmdiri(ndip, &ndentry->d_name, nip); + else + error = gfs_unlinki(ndip, &ndentry->d_name, nip); + + if (error) + goto fail_end_trans; + } + + if (dir_rename) { + error = gfs_change_nlink(ndip, +1); + if (error) + goto fail_end_trans; + error = gfs_change_nlink(odip, -1); + if (error) + goto fail_end_trans; + + name.len = 2; + name.name = ".."; + + error = gfs_dir_mvino(ip, &name, &ndip->i_num, GFS_FILE_DIR); + if (error) + goto fail_end_trans; + } + + error = gfs_dir_del(odip, &odentry->d_name); + if (error) + goto fail_end_trans; + + error = gfs_dir_add(ndip, &ndentry->d_name, &ip->i_num, ip->i_di.di_type); + if (error) + goto fail_end_trans; + + if (dir_rename) + gfs_trans_add_gl(sdp->sd_rename_gl); + + gfs_trans_end(sdp); + + if (alloc_required) { + /* Don't check al->al_alloced_meta and friends. */ + gfs_inplace_release(ndip); + gfs_quota_unlock_m(ndip); + gfs_alloc_put(ndip); + } + + gfs_glock_dq_m(num_gh, ghs); + + for (x = 0; x < num_gh; x++) + gfs_holder_uninit(&ghs[x]); + + if (dir_rename) + gfs_glock_dq_uninit(&r_gh); + + return 0; + + fail_end_trans: + gfs_trans_end(sdp); + + fail_ipres: + if (alloc_required) + gfs_inplace_release(ndip); + + fail_gunlock_q: + if (alloc_required) + gfs_quota_unlock_m(ndip); + + fail_alloc: + if (alloc_required) + gfs_alloc_put(ndip); + + fail_gunlock: + gfs_glock_dq_m(num_gh, ghs); + + fail_uninit: + for (x = 0; x < num_gh; x++) + gfs_holder_uninit(&ghs[x]); + + fail: + if (dir_rename) + gfs_glock_dq_uninit(&r_gh); + + return error; +} + +/** + * gfs_readlink - Read the value of a symlink + * @dentry: the symlink + * @buf: the buffer to read the symlink data into + * @size: the size of the buffer + * + * Returns: errno + */ + +static int +gfs_readlink(struct dentry *dentry, char *user_buf, int user_size) +{ + struct gfs_inode *ip = get_v2ip(dentry->d_inode); + char array[GFS_FAST_NAME_SIZE], *buf = array; + unsigned int len = GFS_FAST_NAME_SIZE; + int error; + + atomic_inc(&ip->i_sbd->sd_ops_inode); + + error = gfs_readlinki(ip, &buf, &len); + if (error) + return error; + + if (user_size > len - 1) + user_size = len - 1; + + if (copy_to_user(user_buf, buf, user_size)) + error = -EFAULT; + else + error = user_size; + + if (buf != array) + kfree(buf); + + return error; +} + +/** + * gfs_follow_link - Follow a symbolic link + * @dentry: The dentry of the link + * @nd: Data that we pass to vfs_follow_link() + * + * This can handle symlinks of any size. It is optimised for symlinks + * under GFS_FAST_NAME_SIZE. + * + * Returns: 0 on success or error code + */ + +static void * +gfs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct gfs_inode *ip = get_v2ip(dentry->d_inode); + char array[GFS_FAST_NAME_SIZE], *buf = array; + unsigned int len = GFS_FAST_NAME_SIZE; + int error; + + atomic_inc(&ip->i_sbd->sd_ops_inode); + + error = gfs_readlinki(ip, &buf, &len); + if (!error) { + error = vfs_follow_link(nd, buf); + if (buf != array) + kfree(buf); + } + + return ERR_PTR(error); +} + +/** + * gfs_permission_i - + * @inode: + * @mask: + * + * Shamelessly ripped from ext3 + * + * Returns: errno + */ + +static int +gfs_permission_i(struct inode *inode, int mask) +{ + return generic_permission(inode, mask, gfs_check_acl); +} + +/** + * gfs_permission - + * @inode: + * @mask: + * + * Returns: errno + */ + +static int +gfs_permission(struct inode *inode, int mask) +{ + struct gfs_inode *ip = get_v2ip(inode); + struct gfs_holder i_gh; + int error; + + atomic_inc(&ip->i_sbd->sd_ops_inode); + + error = gfs_glock_nq_init(ip->i_gl, + LM_ST_SHARED, LM_FLAG_ANY, + &i_gh); + if (error) + return error; + + error = gfs_permission_i(inode, mask); + + gfs_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * gfs_setattr - Change attributes on an inode + * @dentry: The dentry which is changing + * @attr: The structure describing the change + * + * The VFS layer wants to change one or more of an inodes attributes. Write + * that change out to disk. + * + * Returns: errno + */ + +static int +gfs_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + struct gfs_inode *ip = get_v2ip(inode); + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_holder i_gh; + int error; + + atomic_inc(&sdp->sd_ops_inode); + + /* Bugzilla 203170: we'll have the same deadlock as described + * in bugzilla 173912 if + * 1. without RHEL4's DIO_CLUSTER_LOCKING, and + * 2. we come down to this line of code from do_truncate() + * where i_sem(i_mutex) and i_alloc_sem have been taken, and + * 3. grab the exclusive glock here. + * To avoid this to happen, i_alloc_sem must be dropped and trust + * be put into glock that it can carry the same protection. + * + * One issue with dropping i_alloc_sem is that the gfs_setattr() + * can be invoked from other code path without this sempaphore. + * We'll need a new rwsem function that can "up" the semaphore + * only when it is needed. Before that happens (will research the + * possibility), i_alloc_sem (now) is a meaningless lock within + * GFS. If it is ever been used by other non-directIO code, this + * hack will fall apart. + * + * wcheng@redhat.com 10/14/06 + */ + if (attr->ia_valid & ATTR_SIZE) { + up_write(&dentry->d_inode->i_alloc_sem); + } + + error = gfs_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); + + if (attr->ia_valid & ATTR_SIZE) { + down_write(&dentry->d_inode->i_alloc_sem); + } + + if (error) + return error; + + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { + error = -EPERM; + goto fail; + } + + error = inode_change_ok(inode, attr); + if (error) + goto fail; + + if (attr->ia_valid & ATTR_SIZE) { + error = inode_permission(inode, MAY_WRITE); + if (error) + goto fail; + + if (attr->ia_size != ip->i_di.di_size) { + error = vmtruncate(inode, attr->ia_size); + if (error) + goto fail; + } + + error = gfs_truncatei(ip, attr->ia_size, gfs_truncator_page); + if (error) { + if (inode->i_size != ip->i_di.di_size) + i_size_write(inode, ip->i_di.di_size); + goto fail; + } + + if ((sdp->sd_vfs->s_flags & MS_SYNCHRONOUS) && + !gfs_is_jdata(ip)) + i_gh.gh_flags |= GL_SYNC; + } + + else if (attr->ia_valid & (ATTR_UID | ATTR_GID)) { + struct gfs_alloc *al; + struct buffer_head *dibh; + uint32_t ouid, ogid, nuid, ngid; + + ouid = ip->i_di.di_uid; + ogid = ip->i_di.di_gid; + nuid = attr->ia_uid; + ngid = attr->ia_gid; + + if (!(attr->ia_valid & ATTR_UID) || ouid == nuid) + ouid = nuid = NO_QUOTA_CHANGE; + if (!(attr->ia_valid & ATTR_GID) || ogid == ngid) + ogid = ngid = NO_QUOTA_CHANGE; + + al = gfs_alloc_get(ip); + + error = gfs_quota_lock_m(ip, nuid, ngid); + if (error) + goto fail_alloc; + + if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { + error = gfs_quota_check(ip, nuid, ngid); + if (error) + goto fail_gunlock_q; + } + + /* Trans may require: + one dinode block and one quota change block */ + + error = gfs_trans_begin(sdp, 1, 1); + if (error) + goto fail_gunlock_q; + + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + goto fail_end_trans; + + if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { + gfs_trans_add_quota(sdp, -ip->i_di.di_blocks, + ouid, ogid); + gfs_trans_add_quota(sdp, ip->i_di.di_blocks, + nuid, ngid); + } + + error = inode_setattr(inode, attr); + gfs_assert_warn(sdp, !error); + gfs_inode_attr_out(ip); + + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + + gfs_trans_end(sdp); + + gfs_quota_unlock_m(ip); + gfs_alloc_put(ip); + } + + else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode)) { + error = gfs_acl_chmod(ip, attr); + if (error) + goto fail; + } + + else { + error = gfs_setattr_simple(ip, attr); + if (error) + goto fail; + } + + gfs_glock_dq_uninit(&i_gh); + + mark_inode_dirty(inode); + + return error; + + fail_end_trans: + gfs_trans_end(sdp); + + fail_gunlock_q: + gfs_quota_unlock_m(ip); + + fail_alloc: + gfs_alloc_put(ip); + + fail: + gfs_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * gfs_getattr - Read out an inode's attributes + * @mnt: ? + * @dentry: The dentry to stat + * @stat: The inode's stats + * + * Returns: errno + */ + +static int +gfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) +{ + struct inode *inode = dentry->d_inode; + struct gfs_inode *ip = get_v2ip(inode); + struct gfs_holder gh; + int error; + + atomic_inc(&ip->i_sbd->sd_ops_inode); + + error = gfs_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); + if (!error) { + generic_fillattr(inode, stat); + gfs_glock_dq_uninit(&gh); + } + + return error; +} + +/** + * gfs_setxattr - Set (or create or replace) an inode's extended attribute + * @dentry: + * @name: + * @data: + * @size: + * @flags: + * + * Returns: errno + */ + +int +gfs_setxattr(struct dentry *dentry, const char *name, + const void *data, size_t size, + int flags) +{ + struct gfs_ea_request er; + + atomic_inc(&get_v2sdp(dentry->d_inode->i_sb)->sd_ops_inode); + + memset(&er, 0, sizeof(struct gfs_ea_request)); + er.er_type = gfs_ea_name2type(name, &er.er_name); + if (er.er_type == GFS_EATYPE_UNUSED) + return -EOPNOTSUPP; + er.er_data = (char *)data; + er.er_name_len = strlen(er.er_name); + er.er_data_len = size; + er.er_flags = flags; + + return gfs_ea_set(get_v2ip(dentry->d_inode), &er); +} + +/** + * gfs_getxattr - + * @dentry: + * @name: + * @data: + * @size: + * + * Returns: The number of bytes put into data, or -errno + */ + +ssize_t +gfs_getxattr(struct dentry *dentry, const char *name, + void *data, size_t size) +{ + struct gfs_ea_request er; + + atomic_inc(&get_v2sdp(dentry->d_inode->i_sb)->sd_ops_inode); + + memset(&er, 0, sizeof(struct gfs_ea_request)); + er.er_type = gfs_ea_name2type(name, &er.er_name); + if (er.er_type == GFS_EATYPE_UNUSED) + return -EOPNOTSUPP; + er.er_data = data; + er.er_name_len = strlen(er.er_name); + er.er_data_len = size; + + return gfs_ea_get(get_v2ip(dentry->d_inode), &er); +} + +/** + * gfs_listxattr - + * @dentry: + * @buffer: + * @size: + * + * Returns: The number of bytes put into data, or -errno + */ + +ssize_t +gfs_listxattr(struct dentry *dentry, char *buffer, size_t size) +{ + struct gfs_ea_request er; + + atomic_inc(&get_v2sdp(dentry->d_inode->i_sb)->sd_ops_inode); + + memset(&er, 0, sizeof(struct gfs_ea_request)); + er.er_data = (size) ? buffer : NULL; + er.er_data_len = size; + + return gfs_ea_list(get_v2ip(dentry->d_inode), &er); +} + +/** + * gfs_removexattr - + * @dentry: + * @name: + * + * Returns: errno + */ + +int +gfs_removexattr(struct dentry *dentry, const char *name) +{ + struct gfs_ea_request er; + + atomic_inc(&get_v2sdp(dentry->d_inode->i_sb)->sd_ops_inode); + + memset(&er, 0, sizeof(struct gfs_ea_request)); + er.er_type = gfs_ea_name2type(name, &er.er_name); + if (er.er_type == GFS_EATYPE_UNUSED) + return -EOPNOTSUPP; + er.er_name_len = strlen(er.er_name); + + return gfs_ea_remove(get_v2ip(dentry->d_inode), &er); +} + +struct inode_operations gfs_file_iops = { + .permission = gfs_permission, + .setattr = gfs_setattr, + .getattr = gfs_getattr, + .setxattr = gfs_setxattr, + .getxattr = gfs_getxattr, + .listxattr = gfs_listxattr, + .removexattr = gfs_removexattr, +}; + +struct inode_operations gfs_dev_iops = { + .permission = gfs_permission, + .setattr = gfs_setattr, + .getattr = gfs_getattr, + .setxattr = gfs_setxattr, + .getxattr = gfs_getxattr, + .listxattr = gfs_listxattr, + .removexattr = gfs_removexattr, +}; + +struct inode_operations gfs_dir_iops = { + .create = gfs_create, + .lookup = gfs_lookup, + .link = gfs_link, + .unlink = gfs_unlink, + .symlink = gfs_symlink, + .mkdir = gfs_mkdir, + .rmdir = gfs_rmdir, + .mknod = gfs_mknod, + .rename = gfs_rename, + .permission = gfs_permission, + .setattr = gfs_setattr, + .getattr = gfs_getattr, + .setxattr = gfs_setxattr, + .getxattr = gfs_getxattr, + .listxattr = gfs_listxattr, + .removexattr = gfs_removexattr, +}; + +struct inode_operations gfs_symlink_iops = { + .readlink = gfs_readlink, + .follow_link = gfs_follow_link, + .permission = gfs_permission, + .setattr = gfs_setattr, + .getattr = gfs_getattr, + .setxattr = gfs_setxattr, + .getxattr = gfs_getxattr, + .listxattr = gfs_listxattr, + .removexattr = gfs_removexattr, +}; + --- linux-2.6.27.orig/ubuntu/gfs/eaops.h +++ linux-2.6.27/ubuntu/gfs/eaops.h @@ -0,0 +1,21 @@ +#ifndef __EAOPS_DOT_H__ +#define __EAOPS_DOT_H__ + +struct gfs_ea_request; + +struct gfs_eattr_operations { + int (*eo_get) (struct gfs_inode *ip, struct gfs_ea_request *er); + int (*eo_set) (struct gfs_inode *ip, struct gfs_ea_request *er); + int (*eo_remove) (struct gfs_inode *ip, struct gfs_ea_request *er); + char *eo_name; +}; + +unsigned int gfs_ea_name2type(const char *name, char **truncated_name); + +extern struct gfs_eattr_operations gfs_user_eaops; +extern struct gfs_eattr_operations gfs_system_eaops; + +extern struct gfs_eattr_operations *gfs_ea_ops[]; + +#endif /* __EAOPS_DOT_H__ */ + --- linux-2.6.27.orig/ubuntu/gfs/glops.c +++ linux-2.6.27/ubuntu/gfs/glops.c @@ -0,0 +1,664 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "dio.h" +#include "glock.h" +#include "glops.h" +#include "inode.h" +#include "log.h" +#include "page.h" +#include "recovery.h" +#include "rgrp.h" + +/** + * meta_go_sync - sync out the metadata for this glock + * @gl: the glock + * @flags: DIO_* + * + * Used for meta and rgrp glocks. + * + * Called when demoting (gfs_glock_xmote_th()) or unlocking + * (gfs_glock_drop_th() an EX glock at inter-node scope. We must flush + * to disk all dirty buffers/pages relating to this glock, and must not + * not return to caller to demote/unlock the glock until I/O is complete. + * + * This is *not* called from gfs_glock_dq(), because GL_SYNC flag is not + * currently used for anything but inode glocks. + */ + +static void +meta_go_sync(struct gfs_glock *gl, int flags) +{ + if (!(flags & DIO_METADATA)) + return; + + if (test_bit(GLF_DIRTY, &gl->gl_flags)) { + gfs_log_flush_glock(gl); + gfs_sync_buf(gl, flags | DIO_START | DIO_WAIT | DIO_CHECK); + } + + /* We've synced everything, clear SYNC request and DIRTY flags */ + clear_bit(GLF_DIRTY, &gl->gl_flags); + clear_bit(GLF_SYNC, &gl->gl_flags); +} + +/** + * meta_go_inval - invalidate the metadata for this glock + * @gl: the glock + * @flags: + * + */ + +static void +meta_go_inval(struct gfs_glock *gl, int flags) +{ + if (!(flags & DIO_METADATA)) + return; + + gfs_inval_buf(gl); + gl->gl_vn++; +} + +/** + * meta_go_demote_ok - Check to see if it's ok to unlock a meta glock + * @gl: the glock + * + * Returns: TRUE if we have no cached data; ok to demote meta glock + * + * Called when trying to dump (reclaim) a glock from the glock cache, after + * determining that there is currently no holder on this node for this glock, + * and before placing LM_ST_UNLOCKED request on glock's wait-for-demote queue. + * Note that callbacks from other nodes that need a lock do *not* + * seek permission from this function before requesting a demote. + * Nor do glocks obtained with the following flags (see demote_ok()): + * -- GL_NOCACHE: gets unlocked (and not cached) immediately after use + * -- GLF_STICKY: equivalent to always getting "FALSE" from this function + * -- GLF_PREFETCH: uses its own timeout + * + * For glocks that protect on-disk data (meta, inode, and rgrp glocks), disk + * accesses are slow, while lock manipulation is usually fast. Releasing + * a lock means that we: + * -- Must sync memory-cached write data to disk immediately, before another + * node can be granted the lock (at which point that node must read the + * data from disk). + * -- Must invalidate memory-cached data that we had read from or written + * to disk. Another node can change it if we don't have a lock, so it's + * now useless to us. + * + * Then, if we re-acquire the lock again in the future, we: + * -- Must (re-)read (perhaps unchanged) data from disk into memory. + * + * All of these are painful, so it pays to retain a glock in our glock cache + * as long as we have cached data (even though we have no active holders + * for this lock on this node currently), unless/until another node needs + * to change it. This allows Linux block I/O to sync write data to disk in + * a "lazy" way, rather than forcing an immediate sync (and resultant WAIT), + * and retains current data in memory as long as possible. + * + * This also helps GFS respond to memory pressure. There is no mechanism for + * the Linux virtual memory manager to directly call into GFS to ask it to + * drop locks. So, we take a hint from what the VM does to the page cache. + * When that cache is trimmed (and we see no more pages relating to this + * glock), we trim the glock cache as well, by releasing this lock. + */ + +static int +meta_go_demote_ok(struct gfs_glock *gl) +{ + return (gl->gl_aspace->i_mapping->nrpages) ? FALSE : TRUE; +} + +/** + * inode_go_xmote_th - promote/demote (but don't unlock) an inode glock + * @gl: the glock + * @state: the requested state + * @flags: the flags passed into gfs_glock() + * + * Acquire a new glock, or change an already-acquired glock to + * more/less restrictive state (other than LM_ST_UNLOCKED). + */ + +static void +inode_go_xmote_th(struct gfs_glock *gl, unsigned int state, int flags) +{ + if (gl->gl_state != LM_ST_UNLOCKED) + gfs_inval_pte(gl); + gfs_glock_xmote_th(gl, state, flags); +} + +/** + * inode_go_xmote_bh - After promoting/demoting (but not unlocking) + * an inode glock + * @gl: the glock + * + * FIXME: This will be really broken when (no_formal_ino != no_addr) + * and gl_name.ln_number no longer refers to the dinode block #. + * + * If we've just acquired the inter-node lock for an inode, + * read the dinode block from disk (but don't wait for I/O completion). + * Exceptions (don't read if): + * Glock state is UNLOCKED. + * Glock's requesting holder's GL_SKIP flag is set. + */ + +static void +inode_go_xmote_bh(struct gfs_glock *gl) +{ + struct gfs_holder *gh = gl->gl_req_gh; + struct buffer_head *bh; + int error; + + if (gl->gl_state != LM_ST_UNLOCKED && + (!gh || !(gh->gh_flags & GL_SKIP))) { + error = gfs_dread(gl, gl->gl_name.ln_number, DIO_START, &bh); + if (!error) + brelse(bh); + } +} + +/** + * inode_go_drop_th - unlock an inode glock + * @gl: the glock + * + * Invoked from rq_demote(). + * Another node needs the lock in EXCLUSIVE mode, or lock (unused for too long) + * is being purged from our node's glock cache; we're dropping lock. + */ + +static void +inode_go_drop_th(struct gfs_glock *gl) +{ + gfs_inval_pte(gl); + gfs_glock_drop_th(gl); +} + +/** + * inode_go_sync - Sync the dirty data and/or metadata for an inode glock + * @gl: the glock protecting the inode + * @flags: DIO_METADATA -- sync inode's metadata + * DIO_DATA -- sync inode's data + * DIO_INVISIBLE -- don't clear glock's DIRTY flag when done + * + * If DIO_INVISIBLE: + * 1) Called from gfs_glock_dq(), when releasing the last holder for an EX + * glock (but glock is still in our glock cache in EX state, and might + * stay there for a few minutes). Holder had GL_SYNC flag set, asking + * for early sync (i.e. now, instead of later when we release the EX at + * inter-node scope). GL_SYNC is currently used only for inodes in + * special cases, so inode is the only type of glock for which + * DIO_INVISIBLE would apply. + * 2) Called from depend_sync_one() to sync deallocated inode metadata + * before it can be reallocated by another process or machine. Since + * this call can happen at any time during the lifetime of the + * glock, don't clear the sync bit (more data might be dirtied + * momentarily). + * Else (later): + * Called when demoting (gfs_glock_xmote_th()) or unlocking + * (gfs_glock_drop_th() an EX glock at inter-node scope. We must flush + * to disk all dirty buffers/pages relating to this glock, and must not + * return to caller to demote/unlock the glock until I/O is complete. + * + * Syncs go in following order: + * Start data page writes + * Sync metadata to log (wait to complete I/O) + * Sync metadata to in-place location (wait to complete I/O) + * Wait for data page I/O to complete + * + */ + +static void +inode_go_sync(struct gfs_glock *gl, int flags) +{ + int meta = (flags & DIO_METADATA); + int data = (flags & DIO_DATA); + + if (test_bit(GLF_DIRTY, &gl->gl_flags)) { + if (meta && data) { + gfs_sync_page(gl, flags | DIO_START); + gfs_log_flush_glock(gl); + gfs_sync_buf(gl, flags | DIO_START | DIO_WAIT | DIO_CHECK); + gfs_sync_page(gl, flags | DIO_WAIT | DIO_CHECK); + } else if (meta) { + gfs_log_flush_glock(gl); + gfs_sync_buf(gl, flags | DIO_START | DIO_WAIT | DIO_CHECK); + } else if (data) + gfs_sync_page(gl, flags | DIO_START | DIO_WAIT | DIO_CHECK); + } + + /* If we've synced everything, clear the SYNC request. + If we're doing the final (not early) sync, clear DIRTY */ + if (meta && data) { + if (!(flags & DIO_INVISIBLE)) + clear_bit(GLF_DIRTY, &gl->gl_flags); + clear_bit(GLF_SYNC, &gl->gl_flags); + } +} + +/** + * inode_go_inval - prepare a inode glock to be released + * @gl: the glock + * @flags: + * + */ + +static void +inode_go_inval(struct gfs_glock *gl, int flags) +{ + int meta = (flags & DIO_METADATA); + int data = (flags & DIO_DATA); + + if (meta) { + gfs_inval_buf(gl); + gl->gl_vn++; + } + if (data) + gfs_inval_page(gl); +} + +/** + * inode_go_demote_ok - Check to see if it's ok to unlock an inode glock + * @gl: the glock + * + * See comments for meta_go_demote_ok(). + * + * While other glock types (meta, rgrp) that protect disk data can be retained + * indefinitely, GFS imposes a timeout (overridden when using no_lock lock + * module) for inode glocks, even if there is still data in page cache for + * this inode. + * + * Returns: TRUE if it's ok + */ + +static int +inode_go_demote_ok(struct gfs_glock *gl) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + int demote = FALSE; + + if (!get_gl2ip(gl) && !gl->gl_aspace->i_mapping->nrpages) + demote = TRUE; + else if (!sdp->sd_args.ar_localcaching && + time_after_eq(jiffies, gl->gl_stamp + gfs_tune_get(sdp, gt_demote_secs) * HZ)) + demote = TRUE; + + return demote; +} + +/** + * inode_go_lock - operation done after an inode lock is locked by + * a first holder on this node + * @gl: the glock + * @flags: the flags passed into gfs_glock() + * + * Returns: errno + */ + +static int +inode_go_lock(struct gfs_glock *gl, int flags) +{ + struct gfs_inode *ip = get_gl2ip(gl); + int error = 0; + + if (ip && ip->i_vn != gl->gl_vn) { + error = gfs_copyin_dinode(ip); + if (!error) + gfs_inode_attr_in(ip); + } + + return error; +} + +/** + * inode_go_unlock - operation done when an inode lock is unlocked by + * a last holder on this node + * @gl: the glock + * @flags: the flags passed into gfs_gunlock() + * + */ + +static void +inode_go_unlock(struct gfs_glock *gl, int flags) +{ + struct gfs_inode *ip = get_gl2ip(gl); + + if (ip && test_bit(GLF_DIRTY, &gl->gl_flags)) + gfs_inode_attr_in(ip); + + if (ip) + gfs_flush_meta_cache(ip); +} + +/** + * inode_greedy - + * @gl: the glock + * + */ + +static void +inode_greedy(struct gfs_glock *gl) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + struct gfs_inode *ip = get_gl2ip(gl); + unsigned int quantum = gfs_tune_get(sdp, gt_greedy_quantum); + unsigned int max = gfs_tune_get(sdp, gt_greedy_max); + unsigned int new_time; + + spin_lock(&ip->i_spin); + + if (time_after(ip->i_last_pfault + quantum, jiffies)) { + new_time = ip->i_greedy + quantum; + if (new_time > max) + new_time = max; + } else { + new_time = ip->i_greedy - quantum; + if (!new_time || new_time > max) + new_time = 1; + } + + ip->i_greedy = new_time; + + spin_unlock(&ip->i_spin); + + gfs_inode_put(ip); +} + +/** + * rgrp_go_xmote_th - promote/demote (but don't unlock) a resource group glock + * @gl: the glock + * @state: the requested state + * @flags: the flags passed into gfs_glock() + * + * Acquire a new glock, or change an already-acquired glock to + * more/less restrictive state (other than LM_ST_UNLOCKED). + * + * We're going to lock the lock in SHARED or EXCLUSIVE state, or + * demote it from EXCLUSIVE to SHARED (because another node needs it SHARED). + * When locking, gfs_mhc_zap() and gfs_depend_sync() are basically no-ops; + * meta-header cache and dependency lists should be empty. + * + */ + +static void +rgrp_go_xmote_th(struct gfs_glock *gl, unsigned int state, int flags) +{ + struct gfs_rgrpd *rgd = get_gl2rgd(gl); + + gfs_mhc_zap(rgd); + gfs_depend_sync(rgd); + gfs_glock_xmote_th(gl, state, flags); +} + +/** + * rgrp_go_drop_th - unlock a resource group glock + * @gl: the glock + * + * Invoked from rq_demote(). + * Another node needs the lock in EXCLUSIVE mode, or lock (unused for too long) + * is being purged from our node's glock cache; we're dropping lock. + */ + +static void +rgrp_go_drop_th(struct gfs_glock *gl) +{ + struct gfs_rgrpd *rgd = get_gl2rgd(gl); + + gfs_mhc_zap(rgd); + gfs_depend_sync(rgd); + gfs_glock_drop_th(gl); +} + +/** + * rgrp_go_demote_ok - Check to see if it's ok to unlock a RG's glock + * @gl: the glock + * + * See comments for meta_go_demote_ok(). + * + * In addition to Linux page cache, we also check GFS meta-header-cache. + * + * Returns: TRUE if it's ok + */ + +static int +rgrp_go_demote_ok(struct gfs_glock *gl) +{ + struct gfs_rgrpd *rgd = get_gl2rgd(gl); + int demote = TRUE; + + if (gl->gl_aspace->i_mapping->nrpages) + demote = FALSE; + else if (rgd && !list_empty(&rgd->rd_mhc)) /* Don't bother with lock here */ + demote = FALSE; + + return demote; +} + +/** + * rgrp_go_lock - operation done after an rgrp lock is locked by + * a first holder on this node. + * @gl: the glock + * @flags: the flags passed into gfs_glock() + * + * Returns: errno + * + * Read rgrp's header and block allocation bitmaps from disk. + */ + +static int +rgrp_go_lock(struct gfs_glock *gl, int flags) +{ + if (flags & GL_SKIP) + return 0; + return gfs_rgrp_read(get_gl2rgd(gl)); +} + +/** + * rgrp_go_unlock - operation done when an rgrp lock is unlocked by + * a last holder on this node. + * @gl: the glock + * @flags: the flags passed into gfs_gunlock() + * + * Release rgrp's bitmap buffers (read in when lock was first obtained). + * Make sure rgrp's glock's Lock Value Block has up-to-date block usage stats, + * so other nodes can see them. + */ + +static void +rgrp_go_unlock(struct gfs_glock *gl, int flags) +{ + struct gfs_rgrpd *rgd = get_gl2rgd(gl); + if (flags & GL_SKIP) + return; + gfs_rgrp_relse(rgd); + if (test_bit(GLF_DIRTY, &gl->gl_flags)) + gfs_rgrp_lvb_fill(rgd); +} + +/** + * trans_go_xmote_th - promote/demote (but don't unlock) the transaction glock + * @gl: the glock + * @state: the requested state + * @flags: the flags passed into gfs_glock() + * + * Acquire a new glock, or change an already-acquired glock to + * more/less restrictive state (other than LM_ST_UNLOCKED). + */ + +static void +trans_go_xmote_th(struct gfs_glock *gl, unsigned int state, int flags) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + + if (gl->gl_state != LM_ST_UNLOCKED && + test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { + gfs_sync_meta(sdp); + gfs_log_shutdown(sdp); + } + + gfs_glock_xmote_th(gl, state, flags); +} + +/** + * trans_go_xmote_bh - After promoting/demoting (but not unlocking) + * the transaction glock + * @gl: the glock + * + */ + +static void +trans_go_xmote_bh(struct gfs_glock *gl) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + struct gfs_glock *j_gl = sdp->sd_journal_gh.gh_gl; + struct gfs_log_header head; + int error; + + if (gl->gl_state != LM_ST_UNLOCKED && + test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { + j_gl->gl_ops->go_inval(j_gl, DIO_METADATA | DIO_DATA); + + error = gfs_find_jhead(sdp, &sdp->sd_jdesc, j_gl, &head); + if (error) + gfs_consist(sdp); + if (!(head.lh_flags & GFS_LOG_HEAD_UNMOUNT)) + gfs_consist(sdp); + + /* Initialize some head of the log stuff */ + if (!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) { + sdp->sd_sequence = head.lh_sequence; + sdp->sd_log_head = head.lh_first + 1; + } + } +} + +/** + * trans_go_drop_th - unlock the transaction glock + * @gl: the glock + * + * Invoked from rq_demote(). + * Another node needs the lock in EXCLUSIVE mode to quiesce the filesystem + * (for journal replay, etc.). + * + * We want to sync the device even with localcaching. Remember + * that localcaching journal replay only marks buffers dirty. + */ + +static void +trans_go_drop_th(struct gfs_glock *gl) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + + if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { + gfs_sync_meta(sdp); + gfs_log_shutdown(sdp); + } + + gfs_glock_drop_th(gl); +} + +/** + * nondisk_go_demote_ok - Check to see if it's ok to unlock a non-disk glock + * @gl: the glock + * + * See comments for meta_go_demote_ok(). + * + * We never give up a non-disk glock (unless another node needs it). + * Non-disk type used for GFS_MOUNT_LOCK, GFS_LIVE_LOCK, GFS_RENAME_LOCK. + * GFS_MOUNT_LOCK is always requested GL_NOCACHE, however, so it never uses + * this function. + * + * Returns: TRUE if it's ok + */ + +static int +nondisk_go_demote_ok(struct gfs_glock *gl) +{ + return FALSE; +} + +/** + * quota_go_demote_ok - Check to see if it's ok to unlock a quota glock + * @gl: the glock + * + * See comments for meta_go_demote_ok(). + * + * Returns: TRUE if it's ok + */ + +static int +quota_go_demote_ok(struct gfs_glock *gl) +{ + return !atomic_read(&gl->gl_lvb_count); +} + +struct gfs_glock_operations gfs_meta_glops = { + .go_xmote_th = gfs_glock_xmote_th, + .go_drop_th = gfs_glock_drop_th, + .go_sync = meta_go_sync, + .go_inval = meta_go_inval, + .go_demote_ok = meta_go_demote_ok, + .go_type = LM_TYPE_META +}; + +struct gfs_glock_operations gfs_inode_glops = { + .go_xmote_th = inode_go_xmote_th, + .go_xmote_bh = inode_go_xmote_bh, + .go_drop_th = inode_go_drop_th, + .go_sync = inode_go_sync, + .go_inval = inode_go_inval, + .go_demote_ok = inode_go_demote_ok, + .go_lock = inode_go_lock, + .go_unlock = inode_go_unlock, + .go_greedy = inode_greedy, + .go_type = LM_TYPE_INODE +}; + +struct gfs_glock_operations gfs_rgrp_glops = { + .go_xmote_th = rgrp_go_xmote_th, + .go_drop_th = rgrp_go_drop_th, + .go_sync = meta_go_sync, + .go_inval = meta_go_inval, + .go_demote_ok = rgrp_go_demote_ok, + .go_lock = rgrp_go_lock, + .go_unlock = rgrp_go_unlock, + .go_type = LM_TYPE_RGRP +}; + +struct gfs_glock_operations gfs_trans_glops = { + .go_xmote_th = trans_go_xmote_th, + .go_xmote_bh = trans_go_xmote_bh, + .go_drop_th = trans_go_drop_th, + .go_type = LM_TYPE_NONDISK +}; + +struct gfs_glock_operations gfs_iopen_glops = { + .go_xmote_th = gfs_glock_xmote_th, + .go_drop_th = gfs_glock_drop_th, + .go_callback = gfs_iopen_go_callback, + .go_type = LM_TYPE_IOPEN +}; + +struct gfs_glock_operations gfs_flock_glops = { + .go_xmote_th = gfs_glock_xmote_th, + .go_drop_th = gfs_glock_drop_th, + .go_type = LM_TYPE_FLOCK +}; + +struct gfs_glock_operations gfs_nondisk_glops = { + .go_xmote_th = gfs_glock_xmote_th, + .go_drop_th = gfs_glock_drop_th, + .go_demote_ok = nondisk_go_demote_ok, + .go_type = LM_TYPE_NONDISK +}; + +struct gfs_glock_operations gfs_quota_glops = { + .go_xmote_th = gfs_glock_xmote_th, + .go_drop_th = gfs_glock_drop_th, + .go_demote_ok = quota_go_demote_ok, + .go_type = LM_TYPE_QUOTA +}; --- linux-2.6.27.orig/ubuntu/gfs/lock_dlm.h +++ linux-2.6.27/ubuntu/gfs/lock_dlm.h @@ -0,0 +1,182 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License version 2. + */ + +#ifndef LOCK_DLM_DOT_H +#define LOCK_DLM_DOT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "lm_interface.h" + +/* + * Internally, we prefix things with gdlm_ and GDLM_ (for gfs-dlm) since a + * prefix of lock_dlm_ gets awkward. Externally, GFS refers to this module + * as "lock_dlm". + */ + +#define GDLM_STRNAME_BYTES 24 +#define GDLM_LVB_SIZE 32 +#define GDLM_DROP_COUNT 0 +#define GDLM_DROP_PERIOD 60 +#define GDLM_NAME_LEN 128 + +/* GFS uses 12 bytes to identify a resource (32 bit type + 64 bit number). + We sprintf these numbers into a 24 byte string of hex values to make them + human-readable (to make debugging simpler.) */ + +struct gdlm_strname { + unsigned char name[GDLM_STRNAME_BYTES]; + unsigned short namelen; +}; + +enum { + DFL_BLOCK_LOCKS = 0, + DFL_SPECTATOR = 1, + DFL_WITHDRAW = 2, +}; + +struct gdlm_ls { + u32 id; + int jid; + int first; + int first_done; + unsigned long flags; + struct kobject kobj; + char clustername[GDLM_NAME_LEN]; + char fsname[GDLM_NAME_LEN]; + int fsflags; + dlm_lockspace_t *dlm_lockspace; + lm_callback_t fscb; + struct gfs_sbd *sdp; + int recover_jid; + int recover_jid_done; + int recover_jid_status; + spinlock_t async_lock; + struct list_head complete; + struct list_head blocking; + struct list_head delayed; + struct list_head submit; + struct list_head all_locks; + u32 all_locks_count; + wait_queue_head_t wait_control; + struct task_struct *thread1; + struct task_struct *thread2; + wait_queue_head_t thread_wait; + unsigned long drop_time; + int drop_locks_count; + int drop_locks_period; +}; + +enum { + LFL_NOBLOCK = 0, + LFL_NOCACHE = 1, + LFL_DLM_UNLOCK = 2, + LFL_DLM_CANCEL = 3, + LFL_SYNC_LVB = 4, + LFL_FORCE_PROMOTE = 5, + LFL_REREQUEST = 6, + LFL_ACTIVE = 7, + LFL_INLOCK = 8, + LFL_CANCEL = 9, + LFL_NOBAST = 10, + LFL_HEADQUE = 11, + LFL_UNLOCK_DELETE = 12, + LFL_AST_WAIT = 13, +}; + +struct gdlm_lock { + struct gdlm_ls *ls; + struct lm_lockname lockname; + struct gdlm_strname strname; + char *lvb; + struct dlm_lksb lksb; + + s16 cur; + s16 req; + s16 prev_req; + u32 lkf; /* dlm flags DLM_LKF_ */ + unsigned long flags; /* lock_dlm flags LFL_ */ + + int bast_mode; /* protected by async_lock */ + + struct list_head clist; /* complete */ + struct list_head blist; /* blocking */ + struct list_head delay_list; /* delayed */ + struct list_head all_list; /* all locks for the fs */ + struct gdlm_lock *hold_null; /* NL lock for hold_lvb */ +}; + +#define gdlm_assert(assertion, fmt, args...) \ +do { \ + if (unlikely(!(assertion))) { \ + printk(KERN_EMERG "lock_dlm: fatal assertion failed \"%s\"\n" \ + "lock_dlm: " fmt "\n", \ + #assertion, ##args); \ + BUG(); \ + } \ +} while (0) + +#define log_print(lev, fmt, arg...) printk(lev "lock_dlm: " fmt "\n" , ## arg) +#define log_info(fmt, arg...) log_print(KERN_INFO , fmt , ## arg) +#define log_error(fmt, arg...) log_print(KERN_ERR , fmt , ## arg) +#ifdef LOCK_DLM_LOG_DEBUG +#define log_debug(fmt, arg...) log_print(KERN_DEBUG , fmt , ## arg) +#else +#define log_debug(fmt, arg...) +#endif + +/* sysfs.c */ + +int gdlm_sysfs_init(void); +void gdlm_sysfs_exit(void); +int gdlm_kobject_setup(struct gdlm_ls *, struct kobject *); +void gdlm_kobject_release(struct gdlm_ls *); + +/* thread.c */ + +int gdlm_init_threads(struct gdlm_ls *); +void gdlm_release_threads(struct gdlm_ls *); + +/* lock.c */ + +s16 gdlm_make_lmstate(s16); +void gdlm_queue_delayed(struct gdlm_lock *); +void gdlm_submit_delayed(struct gdlm_ls *); +int gdlm_release_all_locks(struct gdlm_ls *); +void gdlm_delete_lp(struct gdlm_lock *); +unsigned int gdlm_do_lock(struct gdlm_lock *); + +int gdlm_get_lock(void *, struct lm_lockname *, void **); +void gdlm_put_lock(void *); +unsigned int gdlm_lock(void *, unsigned int, unsigned int, unsigned int); +unsigned int gdlm_unlock(void *, unsigned int); +void gdlm_cancel(void *); +int gdlm_hold_lvb(void *, char **); +void gdlm_unhold_lvb(void *, char *); + +/* mount.c */ + +extern const struct lm_lockops gdlm_ops; + +#endif + --- linux-2.6.27.orig/ubuntu/gfs/lm_interface.h +++ linux-2.6.27/ubuntu/gfs/lm_interface.h @@ -0,0 +1,278 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License version 2. + */ + +#ifndef __LM_INTERFACE_DOT_H__ +#define __LM_INTERFACE_DOT_H__ + + +typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data); + +/* + * lm_mount() flags + * + * LM_MFLAG_SPECTATOR + * GFS is asking to join the filesystem's lockspace, but it doesn't want to + * modify the filesystem. The lock module shouldn't assign a journal to the FS + * mount. It shouldn't send recovery callbacks to the FS mount. If the node + * dies or withdraws, all locks can be wiped immediately. + */ + +#define LM_MFLAG_SPECTATOR 0x00000001 + +/* + * lm_lockstruct flags + * + * LM_LSFLAG_LOCAL + * The lock_nolock module returns LM_LSFLAG_LOCAL to GFS, indicating that GFS + * can make single-node optimizations. + */ + +#define LM_LSFLAG_LOCAL 0x00000001 + +/* + * lm_lockname types + */ + +#define LM_TYPE_RESERVED 0x00 +#define LM_TYPE_NONDISK 0x01 +#define LM_TYPE_INODE 0x02 +#define LM_TYPE_RGRP 0x03 +#define LM_TYPE_META 0x04 +#define LM_TYPE_IOPEN 0x05 +#define LM_TYPE_FLOCK 0x06 +#define LM_TYPE_PLOCK 0x07 +#define LM_TYPE_QUOTA 0x08 +#define LM_TYPE_JOURNAL 0x09 + +/* + * lm_lock() states + * + * SHARED is compatible with SHARED, not with DEFERRED or EX. + * DEFERRED is compatible with DEFERRED, not with SHARED or EX. + */ + +#define LM_ST_UNLOCKED 0 +#define LM_ST_EXCLUSIVE 1 +#define LM_ST_DEFERRED 2 +#define LM_ST_SHARED 3 + +/* + * lm_lock() flags + * + * LM_FLAG_TRY + * Don't wait to acquire the lock if it can't be granted immediately. + * + * LM_FLAG_TRY_1CB + * Send one blocking callback if TRY is set and the lock is not granted. + * + * LM_FLAG_NOEXP + * GFS sets this flag on lock requests it makes while doing journal recovery. + * These special requests should not be blocked due to the recovery like + * ordinary locks would be. + * + * LM_FLAG_ANY + * A SHARED request may also be granted in DEFERRED, or a DEFERRED request may + * also be granted in SHARED. The preferred state is whichever is compatible + * with other granted locks, or the specified state if no other locks exist. + * + * LM_FLAG_PRIORITY + * Override fairness considerations. Suppose a lock is held in a shared state + * and there is a pending request for the deferred state. A shared lock + * request with the priority flag would be allowed to bypass the deferred + * request and directly join the other shared lock. A shared lock request + * without the priority flag might be forced to wait until the deferred + * requested had acquired and released the lock. + */ + +#define LM_FLAG_TRY 0x00000001 +#define LM_FLAG_TRY_1CB 0x00000002 +#define LM_FLAG_NOEXP 0x00000004 +#define LM_FLAG_ANY 0x00000008 +#define LM_FLAG_PRIORITY 0x00000010 + +/* + * lm_lock() and lm_async_cb return flags + * + * LM_OUT_ST_MASK + * Masks the lower two bits of lock state in the returned value. + * + * LM_OUT_CACHEABLE + * The lock hasn't been released so GFS can continue to cache data for it. + * + * LM_OUT_CANCELED + * The lock request was canceled. + * + * LM_OUT_ASYNC + * The result of the request will be returned in an LM_CB_ASYNC callback. + */ + +#define LM_OUT_ST_MASK 0x00000003 +#define LM_OUT_CACHEABLE 0x00000004 +#define LM_OUT_CANCELED 0x00000008 +#define LM_OUT_ASYNC 0x00000080 +#define LM_OUT_ERROR 0x00000100 + +/* + * lm_callback_t types + * + * LM_CB_NEED_E LM_CB_NEED_D LM_CB_NEED_S + * Blocking callback, a remote node is requesting the given lock in + * EXCLUSIVE, DEFERRED, or SHARED. + * + * LM_CB_NEED_RECOVERY + * The given journal needs to be recovered. + * + * LM_CB_DROPLOCKS + * Reduce the number of cached locks. + * + * LM_CB_ASYNC + * The given lock has been granted. + */ + +#define LM_CB_NEED_E 257 +#define LM_CB_NEED_D 258 +#define LM_CB_NEED_S 259 +#define LM_CB_NEED_RECOVERY 260 +#define LM_CB_DROPLOCKS 261 +#define LM_CB_ASYNC 262 + +/* + * lm_recovery_done() messages + */ + +#define LM_RD_GAVEUP 308 +#define LM_RD_SUCCESS 309 + + +struct lm_lockname { + u64 ln_number; + unsigned int ln_type; +}; + +#define lm_name_equal(name1, name2) \ + (((name1)->ln_number == (name2)->ln_number) && \ + ((name1)->ln_type == (name2)->ln_type)) \ + +struct lm_async_cb { + struct lm_lockname lc_name; + int lc_ret; +}; + +struct lm_lockstruct; + +struct lm_lockops { + const char *lm_proto_name; + + /* + * Mount/Unmount + */ + + int (*lm_mount) (char *table_name, char *host_data, + lm_callback_t cb, void *cb_data, + unsigned int min_lvb_size, int flags, + struct lm_lockstruct *lockstruct, + struct kobject *fskobj); + + void (*lm_others_may_mount) (void *lockspace); + + void (*lm_unmount) (void *lockspace); + + void (*lm_withdraw) (void *lockspace); + + /* + * Lock oriented operations + */ + + int (*lm_get_lock) (void *lockspace, struct lm_lockname *name, void **lockp); + + void (*lm_put_lock) (void *lock); + + unsigned int (*lm_lock) (void *lock, unsigned int cur_state, + unsigned int req_state, unsigned int flags); + + unsigned int (*lm_unlock) (void *lock, unsigned int cur_state); + + void (*lm_cancel) (void *lock); + + int (*lm_hold_lvb) (void *lock, char **lvbp); + void (*lm_unhold_lvb) (void *lock, char *lvb); + + /* + * Posix Lock oriented operations + */ + + int (*lm_plock_get) (void *lockspace, struct lm_lockname *name, + struct file *file, struct file_lock *fl); + + int (*lm_plock) (void *lockspace, struct lm_lockname *name, + struct file *file, int cmd, struct file_lock *fl); + + int (*lm_punlock) (void *lockspace, struct lm_lockname *name, + struct file *file, struct file_lock *fl); + + /* + * Client oriented operations + */ + + void (*lm_recovery_done) (void *lockspace, unsigned int jid, + unsigned int message); + + struct module *lm_owner; +}; + +/* + * lm_mount() return values + * + * ls_jid - the journal ID this node should use + * ls_first - this node is the first to mount the file system + * ls_lvb_size - size in bytes of lock value blocks + * ls_lockspace - lock module's context for this file system + * ls_ops - lock module's functions + * ls_flags - lock module features + */ + +struct lm_lockstruct { + unsigned int ls_jid; + unsigned int ls_first; + unsigned int ls_lvb_size; + void *ls_lockspace; + const struct lm_lockops *ls_ops; + int ls_flags; +}; + +/* + * Lock module bottom interface. A lock module makes itself available to GFS + * with these functions. + */ + +int gfs_register_lockproto(const struct lm_lockops *proto); +void gfs_unregister_lockproto(const struct lm_lockops *proto); + +/* + * Lock module top interface. GFS calls these functions when mounting or + * unmounting a file system. + */ + +int gfs_mount_lockproto(char *proto_name, char *table_name, char *host_data, + lm_callback_t cb, void *cb_data, + unsigned int min_lvb_size, int flags, + struct lm_lockstruct *lockstruct, + struct kobject *fskobj); + +void gfs_unmount_lockproto(struct lm_lockstruct *lockstruct); + +void gfs_withdraw_lockproto(struct lm_lockstruct *lockstruct); + +int init_lock_dlm(void); +void exit_lock_dlm(void); +int init_nolock(void); +void exit_nolock(void); + +#endif /* __LM_INTERFACE_DOT_H__ */ + --- linux-2.6.27.orig/ubuntu/gfs/bmap.c +++ linux-2.6.27/ubuntu/gfs/bmap.c @@ -0,0 +1,1393 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "bmap.h" +#include "dio.h" +#include "glock.h" +#include "inode.h" +#include "quota.h" +#include "rgrp.h" +#include "trans.h" + +struct metapath { + unsigned int mp_list[GFS_MAX_META_HEIGHT]; +}; + +typedef int (*block_call_t) (struct gfs_inode *ip, struct buffer_head *dibh, + struct buffer_head *bh, uint64_t *top, + uint64_t *bottom, unsigned int height, + void *data); + +struct strip_mine { + int sm_first; + unsigned int sm_height; +}; + +/** + * gfs_unstuffer_sync - unstuff a dinode synchronously + * @ip: the inode + * @dibh: the dinode buffer + * @block: the block number that was allocated + * @private: not used + * + * Returns: errno + */ + +int +gfs_unstuffer_sync(struct gfs_inode *ip, struct buffer_head *dibh, + uint64_t block, void *private) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct buffer_head *bh; + int error; + + error = gfs_get_data_buffer(ip, block, TRUE, &bh); + if (error) + return error; + + gfs_buffer_copy_tail(bh, 0, dibh, sizeof(struct gfs_dinode)); + + error = gfs_dwrite(sdp, bh, DIO_DIRTY | DIO_START | DIO_WAIT); + + brelse(bh); + + return error; +} + +/** + * gfs_unstuffer_async - unstuff a dinode asynchronously + * @ip: the inode + * @dibh: the dinode buffer + * @block: the block number that was allocated + * @private: not used + * + * Returns: errno + */ + +int +gfs_unstuffer_async(struct gfs_inode *ip, struct buffer_head *dibh, + uint64_t block, void *private) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct buffer_head *bh; + int error; + + error = gfs_get_data_buffer(ip, block, TRUE, &bh); + if (error) + return error; + + gfs_buffer_copy_tail(bh, 0, dibh, sizeof(struct gfs_dinode)); + + error = gfs_dwrite(sdp, bh, DIO_DIRTY); + + brelse(bh); + + return error; +} + +/** + * gfs_unstuff_dinode - Unstuff a dinode when the data has grown too big + * @ip: The GFS inode to unstuff + * @unstuffer: the routine that handles unstuffing a non-zero length file + * @private: private data for the unstuffer + * + * This routine unstuffs a dinode and returns it to a "normal" state such + * that the height can be grown in the traditional way. + * + * Returns: errno + */ + +int +gfs_unstuff_dinode(struct gfs_inode *ip, gfs_unstuffer_t unstuffer, + void *private) +{ + struct buffer_head *bh, *dibh; + uint64_t block = 0; + int journaled = gfs_is_jdata(ip); + int error; + + down_write(&ip->i_rw_mutex); + + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + goto out; + + if (ip->i_di.di_size) { + /* Get a free block, fill it with the stuffed data, + and write it out to disk */ + + if (journaled) { + error = gfs_metaalloc(ip, &block); + if (error) + goto out_brelse; + + error = gfs_get_data_buffer(ip, block, TRUE, &bh); + if (error) + goto out_brelse; + + gfs_buffer_copy_tail(bh, sizeof(struct gfs_meta_header), + dibh, sizeof(struct gfs_dinode)); + + brelse(bh); + } else { + gfs_blkalloc(ip, &block); + + error = unstuffer(ip, dibh, block, private); + if (error) + goto out_brelse; + } + } + + /* Set up the pointer to the new block */ + + gfs_trans_add_bh(ip->i_gl, dibh); + + gfs_buffer_clear_tail(dibh, sizeof(struct gfs_dinode)); + + if (ip->i_di.di_size) { + *(uint64_t *)(dibh->b_data + sizeof(struct gfs_dinode)) = cpu_to_gfs64(block); + ip->i_di.di_blocks++; + } + + ip->i_di.di_height = 1; + + gfs_dinode_out(&ip->i_di, dibh->b_data); + + out_brelse: + brelse(dibh); + + out: + up_write(&ip->i_rw_mutex); + + return error; +} + +/** + * calc_tree_height - Calculate the height of a metadata tree + * @ip: The GFS inode + * @size: The proposed size of the file + * + * Work out how tall a metadata tree needs to be in order to accommodate a + * file of a particular size. If size is less than the current size of + * the inode, then the current size of the inode is used instead of the + * supplied one. + * + * Returns: the height the tree should be + */ + +static unsigned int +calc_tree_height(struct gfs_inode *ip, uint64_t size) +{ + struct gfs_sbd *sdp = ip->i_sbd; + uint64_t *arr; + unsigned int max, height; + + if (ip->i_di.di_size > size) + size = ip->i_di.di_size; + + if (gfs_is_jdata(ip)) { + arr = sdp->sd_jheightsize; + max = sdp->sd_max_jheight; + } else { + arr = sdp->sd_heightsize; + max = sdp->sd_max_height; + } + + for (height = 0; height < max; height++) + if (arr[height] >= size) + break; + + return height; +} + +/** + * build_height - Build a metadata tree of the requested height + * @ip: The GFS inode + * @height: The height to build to + * + * This routine makes sure that the metadata tree is tall enough to hold + * "size" bytes of data. + * + * Returns: errno + */ + +static int +build_height(struct gfs_inode *ip, int height) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct buffer_head *bh, *dibh; + uint64_t block, *bp; + unsigned int x; + int new_block; + int error; + + while (ip->i_di.di_height < height) { + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + return error; + + new_block = FALSE; + bp = (uint64_t *)(dibh->b_data + sizeof(struct gfs_dinode)); + for (x = 0; x < sdp->sd_diptrs; x++, bp++) + if (*bp) { + new_block = TRUE; + break; + } + + if (new_block) { + /* Get a new block, fill it with the old direct pointers, + and write it out */ + + error = gfs_metaalloc(ip, &block); + if (error) + goto fail; + + error = gfs_dread(ip->i_gl, block, + DIO_NEW | DIO_START | DIO_WAIT, &bh); + if (error) + goto fail; + + gfs_trans_add_bh(ip->i_gl, bh); + gfs_metatype_set(bh, + GFS_METATYPE_IN, + GFS_FORMAT_IN); + memset(bh->b_data + sizeof(struct gfs_meta_header), + 0, + sizeof(struct gfs_indirect) - + sizeof(struct gfs_meta_header)); + gfs_buffer_copy_tail(bh, sizeof(struct gfs_indirect), + dibh, sizeof(struct gfs_dinode)); + + brelse(bh); + } + + /* Set up the new direct pointer and write it out to disk */ + + gfs_trans_add_bh(ip->i_gl, dibh); + + gfs_buffer_clear_tail(dibh, sizeof(struct gfs_dinode)); + + if (new_block) { + *(uint64_t *)(dibh->b_data + sizeof(struct gfs_dinode)) = cpu_to_gfs64(block); + ip->i_di.di_blocks++; + } + + ip->i_di.di_height++; + + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + return 0; + + fail: + brelse(dibh); + + return error; +} + +/** + * find_metapath - Find path through the metadata tree + * @ip: The inode pointer + * @mp: The metapath to return the result in + * @block: The disk block to look up + * + * This routine returns a struct metapath structure that defines a path through + * the metadata of inode "ip" to get to block "block". + * + * Example: + * Given: "ip" is a height 3 file, "offset" is 101342453, and this is a + * filesystem with a blocksize of 4096. + * + * find_metapath() would return a struct metapath structure set to: + * mp_offset = 101342453, mp_height = 3, mp_list[0] = 0, mp_list[1] = 48, + * and mp_list[2] = 165. + * + * That means that in order to get to the block containing the byte at + * offset 101342453, we would load the indirect block pointed to by pointer + * 0 in the dinode. We would then load the indirect block pointed to by + * pointer 48 in that indirect block. We would then load the data block + * pointed to by pointer 165 in that indirect block. + * + * ---------------------------------------- + * | Dinode | | + * | | 4| + * | |0 1 2 3 4 5 9| + * | | 6| + * ---------------------------------------- + * | + * | + * V + * ---------------------------------------- + * | Indirect Block | + * | 5| + * | 4 4 4 4 4 5 5 1| + * |0 5 6 7 8 9 0 1 2| + * ---------------------------------------- + * | + * | + * V + * ---------------------------------------- + * | Indirect Block | + * | 1 1 1 1 1 5| + * | 6 6 6 6 6 1| + * |0 3 4 5 6 7 2| + * ---------------------------------------- + * | + * | + * V + * ---------------------------------------- + * | Data block containing offset | + * | 101342453 | + * | | + * | | + * ---------------------------------------- + * + */ + +static struct metapath * +find_metapath(struct gfs_inode *ip, uint64_t block) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct metapath *mp; + uint64_t b = block; + unsigned int i; + + mp = gmalloc(sizeof(struct metapath)); + memset(mp, 0, sizeof(struct metapath)); + + for (i = ip->i_di.di_height; i--;) + mp->mp_list[i] = do_div(b, sdp->sd_inptrs); + + return mp; +} + +/** + * metapointer - Return pointer to start of metadata in a buffer + * @bh: The buffer + * @height: The metadata height (0 = dinode) + * @mp: The metapath + * + * Return a pointer to the block number of the next height of the metadata + * tree given a buffer containing the pointer to the current height of the + * metadata tree. + */ + +static __inline__ uint64_t * +metapointer(struct buffer_head *bh, unsigned int height, struct metapath *mp) +{ + unsigned int head_size = (height > 0) ? + sizeof(struct gfs_indirect) : sizeof(struct gfs_dinode); + + return ((uint64_t *)(bh->b_data + head_size)) + mp->mp_list[height]; +} + +/** + * get_metablock - Get the next metadata block in metadata tree + * @ip: The GFS inode + * @bh: Buffer containing the pointers to metadata blocks + * @height: The height of the tree (0 = dinode) + * @mp: The metapath + * @create: Non-zero if we may create a new meatdata block + * @new: Used to indicate if we did create a new metadata block + * @block: the returned disk block number + * + * Given a metatree, complete to a particular height, checks to see if the next + * height of the tree exists. If not the next height of the tree is created. + * The block number of the next height of the metadata tree is returned. + * + * Returns: errno + */ + +static int +get_metablock(struct gfs_inode *ip, + struct buffer_head *bh, unsigned int height, struct metapath *mp, + int create, int *new, uint64_t *block) +{ + uint64_t *ptr = metapointer(bh, height, mp); + int error; + + if (*ptr) { + *block = gfs64_to_cpu(*ptr); + return 0; + } + + *block = 0; + + if (!create) + return 0; + + error = gfs_metaalloc(ip, block); + if (error) + return error; + + gfs_trans_add_bh(ip->i_gl, bh); + + *ptr = cpu_to_gfs64(*block); + ip->i_di.di_blocks++; + + *new = 1; + + return 0; +} + +/** + * get_datablock - Get datablock number from metadata block + * @ip: The GFS inode + * @bh: The buffer containing pointers to datablocks + * @mp: The metapath + * @create: Non-zero if we may create a new data block + * @new: Used to indicate if we created a new data block + * @block: the returned disk block number + * + * Given a fully built metadata tree, checks to see if a particular data + * block exists. It is created if it does not exist and the block number + * on disk is returned. + * + * Returns: errno + */ + +static int +get_datablock(struct gfs_inode *ip, + struct buffer_head *bh, struct metapath *mp, + int create, int *new, uint64_t *block) +{ + uint64_t *ptr = metapointer(bh, ip->i_di.di_height - 1, mp); + + if (*ptr) { + *block = gfs64_to_cpu(*ptr); + return 0; + } + + *block = 0; + + if (!create) + return 0; + + if (gfs_is_jdata(ip)) { + int error; + error = gfs_metaalloc(ip, block); + if (error) + return error; + } else + gfs_blkalloc(ip, block); + + gfs_trans_add_bh(ip->i_gl, bh); + + *ptr = cpu_to_gfs64(*block); + ip->i_di.di_blocks++; + + *new = 1; + + return 0; +} + +/** + * gfs_block_map - Map a block from an inode to a disk block + * @ip: The GFS inode + * @lblock: The logical block number + * @new: Value/Result argument (1 = may create/did create new blocks) + * @dblock: the disk block number of the start of an extent + * @extlen: the size of the extent + * + * Find the block number on the current device which corresponds to an + * inode's block. If the block had to be created, "new" will be set. + * + * Returns: errno + */ + +int +gfs_block_map(struct gfs_inode *ip, + uint64_t lblock, int *new, + uint64_t *dblock, uint32_t *extlen) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct buffer_head *bh; + struct metapath *mp; + int create = *new; + unsigned int bsize; + unsigned int height; + unsigned int end_of_metadata; + unsigned int x; + int error = 0; + + *new = 0; + *dblock = 0; + if (extlen) + *extlen = 0; + + if (create) + down_write(&ip->i_rw_mutex); + else + down_read(&ip->i_rw_mutex); + + if (gfs_assert_warn(sdp, !gfs_is_stuffed(ip))) + goto out; + + bsize = (gfs_is_jdata(ip)) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize; + + height = calc_tree_height(ip, (lblock + 1) * bsize); + if (ip->i_di.di_height < height) { + if (!create) + goto out; + + error = build_height(ip, height); + if (error) + goto out; + } + + mp = find_metapath(ip, lblock); + end_of_metadata = ip->i_di.di_height - 1; + + error = gfs_get_inode_buffer(ip, &bh); + if (error) + goto out_kfree; + + for (x = 0; x < end_of_metadata; x++) { + error = get_metablock(ip, bh, x, mp, create, new, dblock); + brelse(bh); + if (error || !*dblock) + goto out_kfree; + + error = gfs_get_meta_buffer(ip, x + 1, *dblock, *new, &bh); + if (error) + goto out_kfree; + } + + error = get_datablock(ip, bh, mp, create, new, dblock); + if (error) { + brelse(bh); + goto out_kfree; + } + + if (extlen && *dblock) { + *extlen = 1; + + if (!*new) { + uint64_t tmp_dblock; + int tmp_new; + unsigned int nptrs; + + nptrs = (end_of_metadata) ? sdp->sd_inptrs : sdp->sd_diptrs; + + while (++mp->mp_list[end_of_metadata] < nptrs) { + get_datablock(ip, bh, mp, + FALSE, &tmp_new, + &tmp_dblock); + + if (*dblock + *extlen != tmp_dblock) + break; + + (*extlen)++; + } + } + } + + brelse(bh); + + if (*new) { + error = gfs_get_inode_buffer(ip, &bh); + if (!error) { + gfs_trans_add_bh(ip->i_gl, bh); + gfs_dinode_out(&ip->i_di, bh->b_data); + brelse(bh); + } + } + + out_kfree: + kfree(mp); + + out: + if (create) + up_write(&ip->i_rw_mutex); + else + up_read(&ip->i_rw_mutex); + + return error; +} + +/** + * do_grow - Make a file look bigger than it is + * @ip: the inode + * @size: the size to set the file to + * + * Called with an exclusive lock on @ip. + * + * Returns: errno + */ + +static int +do_grow(struct gfs_inode *ip, uint64_t size) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_alloc *al; + struct buffer_head *dibh; + unsigned int h; + int journaled = gfs_is_jdata(ip); + int error; + + al = gfs_alloc_get(ip); + + error = gfs_quota_lock_m(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out; + + error = gfs_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid); + if (error) + goto out_gunlock_q; + + if (journaled) + al->al_requested_meta = sdp->sd_max_height + 1; + else { + al->al_requested_meta = sdp->sd_max_height; + al->al_requested_data = 1; + } + + error = gfs_inplace_reserve(ip); + if (error) + goto out_gunlock_q; + + /* Trans may require: + Full extention of the metadata tree, block allocation, + a dinode modification, and a quota change */ + + error = gfs_trans_begin(sdp, + sdp->sd_max_height + al->al_rgd->rd_ri.ri_length + + 1 + !!journaled, + 1); + if (error) + goto out_ipres; + + if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs_dinode)) { + if (gfs_is_stuffed(ip)) { + error = gfs_unstuff_dinode(ip, gfs_unstuffer_sync, NULL); + if (error) + goto out_end_trans; + } + + h = calc_tree_height(ip, size); + if (ip->i_di.di_height < h) { + down_write(&ip->i_rw_mutex); + error = build_height(ip, h); + up_write(&ip->i_rw_mutex); + if (error) + goto out_end_trans; + } + } + + ip->i_di.di_size = size; + ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + goto out_end_trans; + + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + + out_end_trans: + gfs_trans_end(sdp); + + out_ipres: + gfs_inplace_release(ip); + + out_gunlock_q: + gfs_quota_unlock_m(ip); + + out: + gfs_alloc_put(ip); + + return error; +} + +/** + * recursive_scan - recursively scan through the end of a file + * @ip: the inode + * @dibh: the dinode buffer + * @mp: the path through the metadata to the point to start + * @height: the height the recursion is at + * @block: the indirect block to look at + * @first: TRUE if this is the first block + * @bc: the call to make for each piece of metadata + * @data: data opaque to this function to pass to @bc + * + * When this is first called @height and @block should be zero and + * @first should be TRUE. + * + * Returns: errno + */ + +static int +recursive_scan(struct gfs_inode *ip, struct buffer_head *dibh, + struct metapath *mp, unsigned int height, uint64_t block, + int first, block_call_t bc, void *data) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct buffer_head *bh = NULL; + uint64_t *top, *bottom; + uint64_t bn; + int error; + + if (!height) { + error = gfs_get_inode_buffer(ip, &bh); + if (error) + goto fail; + dibh = bh; + + top = (uint64_t *)(bh->b_data + sizeof(struct gfs_dinode)) + + mp->mp_list[0]; + bottom = (uint64_t *)(bh->b_data + sizeof(struct gfs_dinode)) + + sdp->sd_diptrs; + } else { + error = gfs_get_meta_buffer(ip, height, block, FALSE, &bh); + if (error) + goto fail; + + top = (uint64_t *)(bh->b_data + sizeof(struct gfs_indirect)) + + ((first) ? mp->mp_list[height] : 0); + bottom = (uint64_t *)(bh->b_data + sizeof(struct gfs_indirect)) + + sdp->sd_inptrs; + } + + error = bc(ip, dibh, bh, top, bottom, height, data); + if (error) + goto fail; + + if (height < ip->i_di.di_height - 1) + for (; top < bottom; top++, first = FALSE) { + if (!*top) + continue; + + bn = gfs64_to_cpu(*top); + + error = recursive_scan(ip, dibh, mp, + height + 1, bn, first, + bc, data); + if (error) + goto fail; + } + + brelse(bh); + + return 0; + + fail: + if (bh) + brelse(bh); + + return error; +} + +/** + * do_strip - Look for a layer a particular layer of the file and strip it off + * @ip: the inode + * @dibh: the dinode buffer + * @bh: A buffer of pointers + * @top: The first pointer in the buffer + * @bottom: One more than the last pointer + * @height: the height this buffer is at + * @data: a pointer to a struct strip_mine + * + * Returns: errno + */ + +static int +do_strip(struct gfs_inode *ip, struct buffer_head *dibh, + struct buffer_head *bh, uint64_t *top, uint64_t *bottom, + unsigned int height, void *data) +{ + struct strip_mine *sm = (struct strip_mine *)data; + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_rgrp_list rlist; + uint64_t bn, bstart; + uint32_t blen; + uint64_t *p; + unsigned int rg_blocks = 0; + int metadata; + int x; + int error; + + if (!*top) + sm->sm_first = FALSE; + + if (height != sm->sm_height) + return 0; + + if (sm->sm_first) { + top++; + sm->sm_first = FALSE; + } + + metadata = (height != ip->i_di.di_height - 1) || gfs_is_jdata(ip); + + error = gfs_rindex_hold(sdp, &ip->i_alloc->al_ri_gh); + if (error) + return error; + + memset(&rlist, 0, sizeof(struct gfs_rgrp_list)); + bstart = 0; + blen = 0; + + for (p = top; p < bottom; p++) { + if (!*p) + continue; + + bn = gfs64_to_cpu(*p); + + if (bstart + blen == bn) + blen++; + else { + if (bstart) + gfs_rlist_add(sdp, &rlist, bstart); + + bstart = bn; + blen = 1; + } + } + + if (bstart) + gfs_rlist_add(sdp, &rlist, bstart); + else + goto out; /* Nothing to do */ + + gfs_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0); + + for (x = 0; x < rlist.rl_rgrps; x++) { + struct gfs_rgrpd *rgd; + rgd = get_gl2rgd(rlist.rl_ghs[x].gh_gl); + rg_blocks += rgd->rd_ri.ri_length; + } + + error = gfs_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs); + if (error) + goto out_rlist; + + /* Trans may require: + All the bitmaps that were reserved. + One block for the dinode. + One block for the indirect block being cleared. + One block for a quota change. */ + + error = gfs_trans_begin(sdp, rg_blocks + 2, 1); + if (error) + goto out_rg_gunlock; + + down_write(&ip->i_rw_mutex); + + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_trans_add_bh(ip->i_gl, bh); + + bstart = 0; + blen = 0; + + for (p = top; p < bottom; p++) { + if (!*p) + continue; + + bn = gfs64_to_cpu(*p); + + if (bstart + blen == bn) + blen++; + else { + if (bstart) { + if (metadata) + gfs_metafree(ip, bstart, blen); + else + gfs_blkfree(ip, bstart, blen); + } + + bstart = bn; + blen = 1; + } + + *p = 0; + if (!ip->i_di.di_blocks) + gfs_consist_inode(ip); + ip->i_di.di_blocks--; + } + if (bstart) { + if (metadata) + gfs_metafree(ip, bstart, blen); + else + gfs_blkfree(ip, bstart, blen); + } + + ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + + gfs_dinode_out(&ip->i_di, dibh->b_data); + + up_write(&ip->i_rw_mutex); + + gfs_trans_end(sdp); + + out_rg_gunlock: + gfs_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs); + + out_rlist: + gfs_rlist_free(&rlist); + + out: + gfs_glock_dq_uninit(&ip->i_alloc->al_ri_gh); + + return error; +} + +/** + * gfs_truncator_default - truncate a partial data block + * @ip: the inode + * @size: the size the file should be + * + * Returns: errno + */ + +int +gfs_truncator_default(struct gfs_inode *ip, uint64_t size) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct buffer_head *bh; + uint64_t bn; + int not_new = 0; + int error; + + error = gfs_block_map(ip, size >> sdp->sd_sb.sb_bsize_shift, ¬_new, + &bn, NULL); + if (error) + return error; + if (!bn) + return 0; + + error = gfs_get_data_buffer(ip, bn, FALSE, &bh); + if (error) + return error; + + gfs_buffer_clear_tail(bh, size & (sdp->sd_sb.sb_bsize - 1)); + + error = gfs_dwrite(sdp, bh, DIO_DIRTY); + + brelse(bh); + + return error; +} + +/** + * truncator_journaled - truncate a partial data block + * @ip: the inode + * @size: the size the file should be + * + * Returns: errno + */ + +static int +truncator_journaled(struct gfs_inode *ip, uint64_t size) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct buffer_head *bh; + uint64_t lbn, dbn; + uint32_t off; + int not_new = 0; + int error; + + lbn = size; + off = do_div(lbn, sdp->sd_jbsize); + + error = gfs_block_map(ip, lbn, ¬_new, &dbn, NULL); + if (error) + return error; + if (!dbn) + return 0; + + error = gfs_trans_begin(sdp, 1, 0); + if (error) + return error; + + error = gfs_get_data_buffer(ip, dbn, FALSE, &bh); + if (!error) { + gfs_trans_add_bh(ip->i_gl, bh); + gfs_buffer_clear_tail(bh, + sizeof(struct gfs_meta_header) + + off); + brelse(bh); + } + + gfs_trans_end(sdp); + + return error; +} + +/** + * gfs_shrink - make a file smaller + * @ip: the inode + * @size: the size to make the file + * @truncator: function to truncate the last partial block + * + * Called with an exclusive lock on @ip. + * + * Returns: errno + */ + +int +gfs_shrink(struct gfs_inode *ip, uint64_t size, gfs_truncator_t truncator) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_holder ri_gh; + struct gfs_rgrpd *rgd; + struct buffer_head *dibh; + uint64_t block; + unsigned int height; + int journaled = gfs_is_jdata(ip); + int error; + + if (!size) + block = 0; + else if (journaled) { + block = size - 1; + do_div(block, sdp->sd_jbsize); + } + else + block = (size - 1) >> sdp->sd_sb.sb_bsize_shift; + + /* Get rid of all the data/metadata blocks */ + + height = ip->i_di.di_height; + if (height) { + struct metapath *mp = find_metapath(ip, block); + gfs_alloc_get(ip); + + error = gfs_quota_hold_m(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) { + gfs_alloc_put(ip); + kfree(mp); + return error; + } + + while (height--) { + struct strip_mine sm; + + sm.sm_first = (size) ? TRUE : FALSE; + sm.sm_height = height; + + error = recursive_scan(ip, NULL, mp, 0, 0, TRUE, + do_strip, &sm); + if (error) { + gfs_quota_unhold_m(ip); + gfs_alloc_put(ip); + kfree(mp); + return error; + } + } + + gfs_quota_unhold_m(ip); + gfs_alloc_put(ip); + kfree(mp); + } + + /* If we truncated in the middle of a block, zero out the leftovers. */ + + if (gfs_is_stuffed(ip)) { + /* Do nothing */ + } else if (journaled) { + if (do_mod(size, sdp->sd_jbsize)) { + error = truncator_journaled(ip, size); + if (error) + return error; + } + } else if (size & (uint64_t)(sdp->sd_sb.sb_bsize - 1)) { + error = truncator(ip, size); + if (error) + return error; + } + + /* Set the new size (and possibly the height) */ + + if (!size) { + error = gfs_rindex_hold(sdp, &ri_gh); + if (error) + return error; + } + + error = gfs_trans_begin(sdp, 1, 0); + if (error) + goto out; + + down_write(&ip->i_rw_mutex); + + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + goto out_end_trans; + + if (!size) { + ip->i_di.di_height = 0; + + rgd = gfs_blk2rgrpd(sdp, ip->i_num.no_addr); + if (!rgd) { + gfs_consist_inode(ip); + error = -EIO; + goto out_end_trans; + } + + ip->i_di.di_goal_rgrp = rgd->rd_ri.ri_addr; + ip->i_di.di_goal_dblk = + ip->i_di.di_goal_mblk = + ip->i_num.no_addr - rgd->rd_ri.ri_data1; + } + + ip->i_di.di_size = size; + ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + + gfs_trans_add_bh(ip->i_gl, dibh); + + if (!ip->i_di.di_height && + size < sdp->sd_sb.sb_bsize - sizeof(struct gfs_dinode)) + gfs_buffer_clear_tail(dibh, sizeof(struct gfs_dinode) + size); + + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + + out_end_trans: + up_write(&ip->i_rw_mutex); + + gfs_trans_end(sdp); + + out: + if (!size) + gfs_glock_dq_uninit(&ri_gh); + + return error; +} + +/** + * do_same - truncate to same size (update time stamps) + * @ip: + * + * Returns: errno + */ + +static int +do_same(struct gfs_inode *ip) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct buffer_head *dibh; + int error; + + error = gfs_trans_begin(sdp, 1, 0); + if (error) + return error; + + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + goto out; + + ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds(); + + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + + brelse(dibh); + + out: + gfs_trans_end(sdp); + + return error; +} + +/** + * gfs_truncatei - make a file a give size + * @ip: the inode + * @size: the size to make the file + * @truncator: function to truncate the last partial block + * + * The file size can grow, shrink, or stay the same size. + * + * Returns: errno + */ + +int +gfs_truncatei(struct gfs_inode *ip, uint64_t size, + gfs_truncator_t truncator) +{ + if (gfs_assert_warn(ip->i_sbd, ip->i_di.di_type == GFS_FILE_REG)) + return -EINVAL; + + if (size == ip->i_di.di_size) + return do_same(ip); + else if (size > ip->i_di.di_size) + return do_grow(ip, size); + else + return gfs_shrink(ip, size, truncator); +} + +/** + * gfs_write_calc_reserv - calculate the number of blocks needed to write to a file + * @ip: the file + * @len: the number of bytes to be written to the file + * @data_blocks: returns the number of data blocks required + * @ind_blocks: returns the number of indirect blocks required + * + */ + +void +gfs_write_calc_reserv(struct gfs_inode *ip, unsigned int len, + unsigned int *data_blocks, unsigned int *ind_blocks) +{ + struct gfs_sbd *sdp = ip->i_sbd; + unsigned int tmp; + + if (gfs_is_jdata(ip)) { + *data_blocks = DIV_RU(len, sdp->sd_jbsize) + 2; + *ind_blocks = 3 * (sdp->sd_max_jheight - 1); + } else { + *data_blocks = (len >> sdp->sd_sb.sb_bsize_shift) + 3; + *ind_blocks = 3 * (sdp->sd_max_height - 1); + } + + for (tmp = *data_blocks; tmp > sdp->sd_diptrs;) { + tmp = DIV_RU(tmp, sdp->sd_inptrs); + *ind_blocks += tmp; + } +} + +/** + * gfs_write_alloc_required - figure out if a write is going to require an allocation + * @ip: the file being written to + * @offset: the offset to write to + * @len: the number of bytes being written + * @alloc_required: the int is set to TRUE if an alloc is required, FALSE otherwise + * + * Returns: errno + */ + +int +gfs_write_alloc_required(struct gfs_inode *ip, + uint64_t offset, unsigned int len, + int *alloc_required) +{ + struct gfs_sbd *sdp = ip->i_sbd; + uint64_t lblock, lblock_stop, dblock; + uint32_t extlen; + int not_new = FALSE; + int error = 0; + + *alloc_required = FALSE; + + if (!len) + return 0; + + if (gfs_is_stuffed(ip)) { + if (offset + len > sdp->sd_sb.sb_bsize - sizeof(struct gfs_dinode)) + *alloc_required = TRUE; + return 0; + } + + if (gfs_is_jdata(ip)) { + unsigned int bsize = sdp->sd_jbsize; + lblock = offset; + do_div(lblock, bsize); + lblock_stop = offset + len + bsize - 1; + do_div(lblock_stop, bsize); + } else { + unsigned int shift = sdp->sd_sb.sb_bsize_shift; + lblock = offset >> shift; + lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift; + } + + for (; lblock < lblock_stop; lblock += extlen) { + error = gfs_block_map(ip, lblock, ¬_new, &dblock, &extlen); + if (error) + return error; + + if (!dblock) { + *alloc_required = TRUE; + return 0; + } + } + + return 0; +} + +/** + * do_gfm - Copy out the dinode/indirect blocks of a file + * @ip: the file + * @dibh: the dinode buffer + * @bh: the indirect buffer we're looking at + * @top: the first pointer in the block + * @bottom: one more than the last pointer in the block + * @height: the height the block is at + * @data: a pointer to a struct gfs_user_buffer structure + * + * If this is a journaled file, copy out the data too. + * + * Returns: errno + */ + +static int +do_gfm(struct gfs_inode *ip, struct buffer_head *dibh, + struct buffer_head *bh, uint64_t *top, uint64_t *bottom, + unsigned int height, void *data) +{ + struct gfs_user_buffer *ub = (struct gfs_user_buffer *)data; + int error; + + error = gfs_add_bh_to_ub(ub, bh); + if (error) + return error; + + if (ip->i_di.di_type != GFS_FILE_DIR || + height + 1 != ip->i_di.di_height) + return 0; + + for (; top < bottom; top++) + if (*top) { + struct buffer_head *data_bh; + + error = gfs_dread(ip->i_gl, gfs64_to_cpu(*top), + DIO_START | DIO_WAIT, + &data_bh); + if (error) + return error; + + error = gfs_add_bh_to_ub(ub, data_bh); + + brelse(data_bh); + + if (error) + return error; + } + + return 0; +} + +/** + * gfs_get_file_meta - return all the metadata for a file + * @ip: the file + * @ub: the structure representing the meta + * + * Returns: errno + */ + +int +gfs_get_file_meta(struct gfs_inode *ip, struct gfs_user_buffer *ub) +{ + int error; + + if (gfs_is_stuffed(ip)) { + struct buffer_head *dibh; + error = gfs_get_inode_buffer(ip, &dibh); + if (!error) { + error = gfs_add_bh_to_ub(ub, dibh); + brelse(dibh); + } + } else { + struct metapath *mp = find_metapath(ip, 0); + error = recursive_scan(ip, NULL, mp, 0, 0, TRUE, do_gfm, ub); + kfree(mp); + } + + return error; +} --- linux-2.6.27.orig/ubuntu/gfs/recovery.h +++ linux-2.6.27/ubuntu/gfs/recovery.h @@ -0,0 +1,23 @@ +#ifndef __RECOVERY_DOT_H__ +#define __RECOVERY_DOT_H__ + +#define GFS_RECPASS_A1 (12) +#define GFS_RECPASS_B1 (14) + +void gfs_add_dirty_j(struct gfs_sbd *sdp, unsigned int jid); +void gfs_clear_dirty_j(struct gfs_sbd *sdp); + +int gfs_find_jhead(struct gfs_sbd *sdp, struct gfs_jindex *jdesc, + struct gfs_glock *gl, struct gfs_log_header *head); +int gfs_increment_blkno(struct gfs_sbd *sdp, struct gfs_jindex *jdesc, + struct gfs_glock *gl, uint64_t *addr, + int skip_headers); + +int gfs_recover_journal(struct gfs_sbd *sdp, + unsigned int jid, struct gfs_jindex *jdesc, + int wait); +void gfs_check_journals(struct gfs_sbd *sdp); + +int gfs_recover_dump(struct gfs_sbd *sdp); + +#endif /* __RECOVERY_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/fixed_div64.h +++ linux-2.6.27/ubuntu/gfs/fixed_div64.h @@ -0,0 +1,107 @@ +#ifndef __FIXED_DIV64_DOT_H__ +#define __FIXED_DIV64_DOT_H__ + +#include + +#if defined __i386__ +/* For ia32 we need to pull some tricks to get past various versions + * of the compiler which do not like us using do_div in the middle + * of large functions. + */ +static inline __u32 fixed_div64_do_div(void *a, __u32 b, int n) +{ + __u32 mod; + + switch (n) { + case 4: + mod = *(__u32 *)a % b; + *(__u32 *)a = *(__u32 *)a / b; + return mod; + case 8: + { + unsigned long __upper, __low, __high, __mod; + __u64 c = *(__u64 *)a; + __upper = __high = c >> 32; + __low = c; + if (__high) { + __upper = __high % (b); + __high = __high / (b); + } + asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (b), "0" (__low), "1" (__upper)); + asm("":"=A" (c):"a" (__low),"d" (__high)); + *(__u64 *)a = c; + return __mod; + } + } + + /* NOTREACHED */ + return 0; +} + +/* Side effect free 64 bit mod operation */ +static inline __u32 fixed_div64_do_mod(void *a, __u32 b, int n) +{ + switch (n) { + case 4: + return *(__u32 *)a % b; + case 8: + { + unsigned long __upper, __low, __high, __mod; + __u64 c = *(__u64 *)a; + __upper = __high = c >> 32; + __low = c; + if (__high) { + __upper = __high % (b); + __high = __high / (b); + } + asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (b), "0" (__low), "1" (__upper)); + asm("":"=A" (c):"a" (__low),"d" (__high)); + return __mod; + } + } + + /* NOTREACHED */ + return 0; +} +#else +static inline __u32 fixed_div64_do_div(void *a, __u32 b, int n) +{ + __u32 mod; + + switch (n) { + case 4: + mod = *(__u32 *)a % b; + *(__u32 *)a = *(__u32 *)a / b; + return mod; + case 8: + mod = do_div(*(__u64 *)a, b); + return mod; + } + + /* NOTREACHED */ + return 0; +} + +/* Side effect free 64 bit mod operation */ +static inline __u32 fixed_div64_do_mod(void *a, __u32 b, int n) +{ + switch (n) { + case 4: + return *(__u32 *)a % b; + case 8: + { + __u64 c = *(__u64 *)a; + return do_div(c, b); + } + } + + /* NOTREACHED */ + return 0; +} +#endif + +#undef do_div +#define do_div(a, b) fixed_div64_do_div(&(a), (b), sizeof(a)) +#define do_mod(a, b) fixed_div64_do_mod(&(a), (b), sizeof(a)) + +#endif /* __FIXED_DIV64_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/eattr.c +++ linux-2.6.27/ubuntu/gfs/eattr.c @@ -0,0 +1,2008 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "acl.h" +#include "dio.h" +#include "eaops.h" +#include "eattr.h" +#include "glock.h" +#include "inode.h" +#include "quota.h" +#include "rgrp.h" +#include "trans.h" + +/** + * ea_calc_size - returns the acutal number of bytes the request will take up + * (not counting any unstuffed data blocks) + * @sdp: + * @er: + * @size: + * + * Returns: TRUE if the EA should be stuffed + */ + +static int +ea_calc_size(struct gfs_sbd *sdp, + struct gfs_ea_request *er, + unsigned int *size) +{ + *size = GFS_EAREQ_SIZE_STUFFED(er); + if (*size <= sdp->sd_jbsize) + return TRUE; + + *size = GFS_EAREQ_SIZE_UNSTUFFED(sdp, er); + return FALSE; +} + +/** + * gfs_ea_check_size - + * @ip: + * @er: + * + * Returns: errno + */ + +int +gfs_ea_check_size(struct gfs_sbd *sdp, struct gfs_ea_request *er) +{ + unsigned int size; + + if (er->er_data_len > GFS_EA_MAX_DATA_LEN) + return -ERANGE; + + ea_calc_size(sdp, er, &size); + if (size > sdp->sd_jbsize) + return -ERANGE; /* This can only happen with 512 byte blocks */ + + return 0; +} + +typedef int (*ea_call_t) (struct gfs_inode *ip, + struct buffer_head *bh, + struct gfs_ea_header *ea, + struct gfs_ea_header *prev, + void *private); + +/** + * ea_foreach_i - + * @ip: + * @bh: + * @eabc: + * @data: + * + * Returns: errno + */ + +static int +ea_foreach_i(struct gfs_inode *ip, + struct buffer_head *bh, + ea_call_t ea_call, void *data) +{ + struct gfs_ea_header *ea, *prev = NULL; + int error = 0; + + if (gfs_metatype_check(ip->i_sbd, bh, GFS_METATYPE_EA)) + return -EIO; + + for (ea = GFS_EA_BH2FIRST(bh);; prev = ea, ea = GFS_EA2NEXT(ea)) { + if (!GFS_EA_REC_LEN(ea)) + goto fail; + if (!(bh->b_data <= (char *)ea && + (char *)GFS_EA2NEXT(ea) <= + bh->b_data + bh->b_size)) + goto fail; + if (!GFS_EATYPE_VALID(ea->ea_type)) + goto fail; + + error = ea_call(ip, bh, ea, prev, data); + if (error) + return error; + + if (GFS_EA_IS_LAST(ea)) { + if ((char *)GFS_EA2NEXT(ea) != + bh->b_data + bh->b_size) + goto fail; + break; + } + } + + return error; + + fail: + gfs_consist_inode(ip); + return -EIO; +} + +/** + * ea_foreach - + * @ip: + * @ea_call: + * @data: + * + * Returns: errno + */ + +static int +ea_foreach(struct gfs_inode *ip, + ea_call_t ea_call, + void *data) +{ + struct buffer_head *bh; + int error; + + error = gfs_dread(ip->i_gl, ip->i_di.di_eattr, + DIO_START | DIO_WAIT, &bh); + if (error) + return error; + + if (!(ip->i_di.di_flags & GFS_DIF_EA_INDIRECT)) + error = ea_foreach_i(ip, bh, ea_call, data); + else { + struct buffer_head *eabh; + uint64_t *eablk, *end; + + if (gfs_metatype_check(ip->i_sbd, bh, GFS_METATYPE_IN)) { + error = -EIO; + goto out; + } + + eablk = (uint64_t *)(bh->b_data + sizeof(struct gfs_indirect)); + end = eablk + ip->i_sbd->sd_inptrs; + + for (; eablk < end; eablk++) { + uint64_t bn; + + if (!*eablk) + break; + bn = gfs64_to_cpu(*eablk); + + error = gfs_dread(ip->i_gl, bn, + DIO_START | DIO_WAIT, &eabh); + if (error) + break; + error = ea_foreach_i(ip, eabh, ea_call, data); + brelse(eabh); + if (error) + break; + } + } + + out: + brelse(bh); + + return error; +} + +struct ea_find { + struct gfs_ea_request *ef_er; + struct gfs_ea_location *ef_el; +}; + +/** + * ea_find_i - + * @ip: + * @bh: + * @ea: + * @prev: + * @private: + * + * Returns: -errno on error, 1 if search is over, + * 0 if search should continue + */ + +static int +ea_find_i(struct gfs_inode *ip, + struct buffer_head *bh, + struct gfs_ea_header *ea, + struct gfs_ea_header *prev, + void *private) +{ + struct ea_find *ef = (struct ea_find *)private; + struct gfs_ea_request *er = ef->ef_er; + + if (ea->ea_type == GFS_EATYPE_UNUSED) + return 0; + + if (ea->ea_type == er->er_type) { + if (ea->ea_name_len == er->er_name_len && + !memcmp(GFS_EA2NAME(ea), er->er_name, ea->ea_name_len)) { + struct gfs_ea_location *el = ef->ef_el; + get_bh(bh); + el->el_bh = bh; + el->el_ea = ea; + el->el_prev = prev; + return 1; + } + } + +#if 0 + else if ((ip->i_di.di_flags & GFS_DIF_EA_PACKED) && + er->er_type == GFS_EATYPE_SYS) + return 1; +#endif + + return 0; +} + +/** + * gfs_ea_find - find a matching eattr + * @ip: + * @er: + * @el: + * + * Returns: errno + */ + +int +gfs_ea_find(struct gfs_inode *ip, + struct gfs_ea_request *er, + struct gfs_ea_location *el) +{ + struct ea_find ef; + int error; + + ef.ef_er = er; + ef.ef_el = el; + + memset(el, 0, sizeof(struct gfs_ea_location)); + + error = ea_foreach(ip, ea_find_i, &ef); + if (error > 0) + return 0; + + return error; +} + +/** + * ea_dealloc_unstuffed - + * @ip: + * @bh: + * @ea: + * @prev: + * @private: + * + * Take advantage of the fact that all unstuffed blocks are + * allocated from the same RG. But watch, this may not always + * be true. + * + * Returns: errno + */ + +static int +ea_dealloc_unstuffed(struct gfs_inode *ip, + struct buffer_head *bh, + struct gfs_ea_header *ea, + struct gfs_ea_header *prev, + void *private) +{ + int *leave = (int *)private; + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_rgrpd *rgd; + struct gfs_holder rg_gh; + struct buffer_head *dibh; + uint64_t *dataptrs, bn = 0; + uint64_t bstart = 0; + unsigned int blen = 0; + unsigned int x; + int error; + + if (GFS_EA_IS_STUFFED(ea)) + return 0; + + dataptrs = GFS_EA2DATAPTRS(ea); + for (x = 0; x < ea->ea_num_ptrs; x++, dataptrs++) + if (*dataptrs) { + bn = gfs64_to_cpu(*dataptrs); + break; + } + if (!bn) + return 0; + + rgd = gfs_blk2rgrpd(sdp, bn); + if (!rgd) { + gfs_consist_inode(ip); + return -EIO; + } + + error = gfs_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh); + if (error) + return error; + + error = gfs_trans_begin(sdp, 2 + rgd->rd_ri.ri_length, 1); + if (error) + goto out_gunlock; + + gfs_trans_add_bh(ip->i_gl, bh); + + dataptrs = GFS_EA2DATAPTRS(ea); + for (x = 0; x < ea->ea_num_ptrs; x++, dataptrs++) { + if (!*dataptrs) + break; + bn = gfs64_to_cpu(*dataptrs); + + if (bstart + blen == bn) + blen++; + else { + if (bstart) + gfs_metafree(ip, bstart, blen); + bstart = bn; + blen = 1; + } + + *dataptrs = 0; + if (!ip->i_di.di_blocks) + gfs_consist_inode(ip); + ip->i_di.di_blocks--; + } + if (bstart) + gfs_metafree(ip, bstart, blen); + + if (prev && !leave) { + uint32_t len; + + len = GFS_EA_REC_LEN(prev) + GFS_EA_REC_LEN(ea); + prev->ea_rec_len = cpu_to_gfs32(len); + + if (GFS_EA_IS_LAST(ea)) + prev->ea_flags |= GFS_EAFLAG_LAST; + } else { + ea->ea_type = GFS_EATYPE_UNUSED; + ea->ea_num_ptrs = 0; + } + + error = gfs_get_inode_buffer(ip, &dibh); + if (!error) { + ip->i_di.di_ctime = get_seconds(); + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + gfs_trans_end(sdp); + + out_gunlock: + gfs_glock_dq_uninit(&rg_gh); + + return error; +} + +/** + * ea_remove_unstuffed - + * @ip: + * @bh: + * @ea: + * @prev: + * @leave: + * + * Returns: errno + */ + +static int +ea_remove_unstuffed(struct gfs_inode *ip, + struct buffer_head *bh, + struct gfs_ea_header *ea, + struct gfs_ea_header *prev, + int leave) +{ + struct gfs_alloc *al; + int error; + + al = gfs_alloc_get(ip); + + error = gfs_quota_hold_m(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out_alloc; + + error = gfs_rindex_hold(ip->i_sbd, &al->al_ri_gh); + if (error) + goto out_quota; + + error = ea_dealloc_unstuffed(ip, + bh, ea, prev, + (leave) ? &error : NULL); + + gfs_glock_dq_uninit(&al->al_ri_gh); + + out_quota: + gfs_quota_unhold_m(ip); + + out_alloc: + gfs_alloc_put(ip); + + return error; +} + +/**************************************************************************************************/ + +/** + * gfs_ea_repack_i - + * @ip: + * + * Returns: errno + */ + +int +gfs_ea_repack_i(struct gfs_inode *ip) +{ + return -ENOSYS; +} + +/** + * gfs_ea_repack - + * @ip: + * + * Returns: errno + */ + +int gfs_ea_repack(struct gfs_inode *ip) +{ + struct gfs_holder gh; + int error; + + error = gfs_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); + if (error) + return error; + + /* Some sort of permissions checking would be nice */ + + error = gfs_ea_repack_i(ip); + + gfs_glock_dq_uninit(&gh); + + return error; +} + +struct ea_list { + struct gfs_ea_request *ei_er; + unsigned int ei_size; +}; + +/** + * ea_list_i - + * @ip: + * @bh: + * @ea: + * @prev: + * @private: + * + * Returns: errno + */ + +static int +ea_list_i(struct gfs_inode *ip, + struct buffer_head *bh, + struct gfs_ea_header *ea, + struct gfs_ea_header *prev, + void *private) +{ + struct ea_list *ei = (struct ea_list *)private; + struct gfs_ea_request *er = ei->ei_er; + unsigned int ea_size = gfs_ea_strlen(ea); + + if (ea->ea_type == GFS_EATYPE_UNUSED) + return 0; + + if (er->er_data_len) { + char *prefix; + unsigned int l; + char c = 0; + + if (ei->ei_size + ea_size > er->er_data_len) + return -ERANGE; + + switch (ea->ea_type) { + case GFS_EATYPE_USR: + prefix = "user."; + l = 5; + break; + case GFS_EATYPE_SYS: + prefix = "system."; + l = 7; + break; + case GFS_EATYPE_SECURITY: + prefix = "security."; + l = 9; + break; + default: + prefix = NULL; + l = 0; + break; + } + + if (prefix == NULL || l == 0) + return -EIO; + + memcpy(er->er_data + ei->ei_size, + prefix, l); + memcpy(er->er_data + ei->ei_size + l, + GFS_EA2NAME(ea), + ea->ea_name_len); + memcpy(er->er_data + ei->ei_size + + ea_size - 1, + &c, 1); + } + + ei->ei_size += ea_size; + + return 0; +} + +/** + * gfs_ea_list - + * @ip: + * @er: + * + * Returns: actual size of data on success, -errno on error + */ + +int +gfs_ea_list(struct gfs_inode *ip, struct gfs_ea_request *er) +{ + struct gfs_holder i_gh; + int error; + + if (!er->er_data || !er->er_data_len) { + er->er_data = NULL; + er->er_data_len = 0; + } + + error = gfs_glock_nq_init(ip->i_gl, + LM_ST_SHARED, LM_FLAG_ANY, + &i_gh); + if (error) + return error; + + if (ip->i_di.di_eattr) { + struct ea_list ei = { .ei_er = er, .ei_size = 0 }; + + error = ea_foreach(ip, ea_list_i, &ei); + if (!error) + error = ei.ei_size; + } + + gfs_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * ea_get_unstuffed - actually copies the unstuffed data into the + * request buffer + * @ip: + * @ea: + * @data: + * + * Returns: errno + */ + +static int +ea_get_unstuffed(struct gfs_inode *ip, struct gfs_ea_header *ea, + char *data) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct buffer_head **bh; + unsigned int amount = GFS_EA_DATA_LEN(ea); + unsigned int nptrs = DIV_RU(amount, sdp->sd_jbsize); + uint64_t *dataptrs = GFS_EA2DATAPTRS(ea); + unsigned int x; + int error = 0; + + bh = kmalloc(nptrs * sizeof(struct buffer_head *), GFP_KERNEL); + if (!bh) + return -ENOMEM; + + for (x = 0; x < nptrs; x++) { + error = gfs_dread(ip->i_gl, gfs64_to_cpu(*dataptrs), + DIO_START, bh + x); + if (error) { + while (x--) + brelse(bh[x]); + goto out; + } + dataptrs++; + } + + for (x = 0; x < nptrs; x++) { + error = gfs_dreread(sdp, bh[x], DIO_WAIT); + if (error) { + for (; x < nptrs; x++) + brelse(bh[x]); + goto out; + } + if (gfs_metatype_check2(sdp, bh[x], + GFS_METATYPE_ED, GFS_METATYPE_EA)) { + for (; x < nptrs; x++) + brelse(bh[x]); + error = -EIO; + goto out; + } + + memcpy(data, + bh[x]->b_data + sizeof(struct gfs_meta_header), + (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize); + + amount -= sdp->sd_jbsize; + data += sdp->sd_jbsize; + + brelse(bh[x]); + } + + out: + kfree(bh); + + return error; +} + +/** + * gfs_ea_get_copy - + * @ip: + * @el: + * @data: + * + * Returns: errno + */ + +int +gfs_ea_get_copy(struct gfs_inode *ip, + struct gfs_ea_location *el, + char *data) +{ + if (GFS_EA_IS_STUFFED(el->el_ea)) { + memcpy(data, + GFS_EA2DATA(el->el_ea), + GFS_EA_DATA_LEN(el->el_ea)); + return 0; + } else + return ea_get_unstuffed(ip, el->el_ea, data); +} + +/** + * gfs_ea_get_i - + * @ip: + * @er: + * + * Returns: actual size of data on success, -errno on error + */ + +int +gfs_ea_get_i(struct gfs_inode *ip, struct gfs_ea_request *er) +{ + struct gfs_ea_location el; + int error; + + if (!ip->i_di.di_eattr) + return -ENODATA; + + error = gfs_ea_find(ip, er, &el); + if (error) + return error; + if (!el.el_ea) + return -ENODATA; + + if (er->er_data_len) { + if (GFS_EA_DATA_LEN(el.el_ea) > er->er_data_len) + error = -ERANGE; + else + error = gfs_ea_get_copy(ip, &el, er->er_data); + } + if (!error) + error = GFS_EA_DATA_LEN(el.el_ea); + + brelse(el.el_bh); + + return error; +} + +/** + * gfs_ea_get - + * @ip: + * @er: + * + * Returns: actual size of data on success, -errno on error + */ + +int +gfs_ea_get(struct gfs_inode *ip, struct gfs_ea_request *er) +{ + struct gfs_holder i_gh; + int error; + + if (!er->er_name_len || + er->er_name_len > GFS_EA_MAX_NAME_LEN) + return -EINVAL; + if (!er->er_data || !er->er_data_len) { + er->er_data = NULL; + er->er_data_len = 0; + } + + error = gfs_glock_nq_init(ip->i_gl, + LM_ST_SHARED, LM_FLAG_ANY, + &i_gh); + if (error) + return error; + + error = gfs_ea_ops[er->er_type]->eo_get(ip, er); + + gfs_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * ea_alloc_blk - allocates a new block for extended attributes. + * @ip: A pointer to the inode that's getting extended attributes + * @bhp: + * + * Returns: errno + */ + +static int +ea_alloc_blk(struct gfs_inode *ip, + struct buffer_head **bhp) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_ea_header *ea; + uint64_t block; + int error; + + error = gfs_metaalloc(ip, &block); + if (error) + return error; + + error = gfs_dread(ip->i_gl, block, + DIO_NEW | DIO_START | DIO_WAIT, bhp); + if (error) + return error; + + gfs_trans_add_bh(ip->i_gl, *bhp); + gfs_metatype_set(*bhp, GFS_METATYPE_EA, GFS_FORMAT_EA); + + ea = GFS_EA_BH2FIRST(*bhp); + ea->ea_rec_len = cpu_to_gfs32(sdp->sd_jbsize); + ea->ea_type = GFS_EATYPE_UNUSED; + ea->ea_flags = GFS_EAFLAG_LAST; + ea->ea_num_ptrs = 0; + + ip->i_di.di_blocks++; + + return 0; +} + +/** + * ea_write - writes the request info to an ea, creating new blocks if + * necessary + * @ip: inode that is being modified + * @ea: the location of the new ea in a block + * @er: the write request + * + * Note: does not update ea_rec_len or the GFS_EAFLAG_LAST bin of ea_flags + * + * returns : errno + */ + +static int +ea_write(struct gfs_inode *ip, + struct gfs_ea_header *ea, + struct gfs_ea_request *er) +{ + struct gfs_sbd *sdp = ip->i_sbd; + + ea->ea_data_len = cpu_to_gfs32(er->er_data_len); + ea->ea_name_len = er->er_name_len; + ea->ea_type = er->er_type; + ea->ea_pad = 0; + + memcpy(GFS_EA2NAME(ea), er->er_name, er->er_name_len); + + if (GFS_EAREQ_SIZE_STUFFED(er) <= sdp->sd_jbsize) { + ea->ea_num_ptrs = 0; + memcpy(GFS_EA2DATA(ea), er->er_data, er->er_data_len); + } else { + uint64_t *dataptr = GFS_EA2DATAPTRS(ea); + const char *data = er->er_data; + unsigned int data_len = er->er_data_len; + unsigned int copy; + unsigned int x; + + ea->ea_num_ptrs = DIV_RU(er->er_data_len, sdp->sd_jbsize); + for (x = 0; x < ea->ea_num_ptrs; x++) { + struct buffer_head *bh; + uint64_t block; + int error; + + error = gfs_metaalloc(ip, &block); + if (error) + return error; + + error = gfs_dread(ip->i_gl, block, + DIO_NEW | DIO_START | DIO_WAIT, &bh); + if (error) + return error; + + gfs_trans_add_bh(ip->i_gl, bh); + gfs_metatype_set(bh, GFS_METATYPE_ED, GFS_FORMAT_ED); + ip->i_di.di_blocks++; + + copy = (data_len > sdp->sd_jbsize) ? sdp->sd_jbsize : data_len; + memcpy(bh->b_data + sizeof(struct gfs_meta_header), + data, + copy); + + *dataptr++ = cpu_to_gfs64((uint64_t)bh->b_blocknr); + data += copy; + data_len -= copy; + + brelse(bh); + } + + gfs_assert_withdraw(sdp, !data_len); + } + + return 0; +} + +typedef int (*ea_skeleton_call_t) (struct gfs_inode *ip, + struct gfs_ea_request *er, + void *private); +/** + * ea_alloc_skeleton - + * @ip: + * @er: + * @blks: + * @skeleton_call: + * @private: + * + * Returns: errno + */ + +static int +ea_alloc_skeleton(struct gfs_inode *ip, struct gfs_ea_request *er, + unsigned int blks, + ea_skeleton_call_t skeleton_call, void *private) +{ + struct gfs_alloc *al; + struct buffer_head *dibh; + int error; + + al = gfs_alloc_get(ip); + + error = gfs_quota_lock_m(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out; + + error = gfs_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid); + if (error) + goto out_gunlock_q; + + al->al_requested_meta = blks; + + error = gfs_inplace_reserve(ip); + if (error) + goto out_gunlock_q; + + /* Trans may require: + A modified dinode, multiple EA metadata blocks, and all blocks for a RG + bitmap */ + + error = gfs_trans_begin(ip->i_sbd, + 1 + blks + al->al_rgd->rd_ri.ri_length, 1); + if (error) + goto out_ipres; + + error = skeleton_call(ip, er, private); + if (error) + goto out_end_trans; + + error = gfs_get_inode_buffer(ip, &dibh); + if (!error) { + if (er->er_mode) { + ip->i_vnode->i_mode = er->er_mode; + gfs_inode_attr_out(ip); + } + ip->i_di.di_ctime = get_seconds(); + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + out_end_trans: + gfs_trans_end(ip->i_sbd); + + out_ipres: + gfs_inplace_release(ip); + + out_gunlock_q: + gfs_quota_unlock_m(ip); + + out: + gfs_alloc_put(ip); + + return error; +} + +/** + * ea_init_i - initializes a new eattr block + * @ip: + * @er: + * @private: + * + * Returns: errno + */ + +static int +ea_init_i(struct gfs_inode *ip, + struct gfs_ea_request *er, + void *private) +{ + struct buffer_head *bh; + int error; + + error = ea_alloc_blk(ip, &bh); + if (error) + return error; + + ip->i_di.di_eattr = bh->b_blocknr; + error = ea_write(ip, GFS_EA_BH2FIRST(bh), er); + + brelse(bh); + + return error; +} + +/** + * ea_init - initializes a new eattr block + * @ip: + * @er: + * + * Returns: errno + */ + +static int +ea_init(struct gfs_inode *ip, struct gfs_ea_request *er) +{ + unsigned int jbsize = ip->i_sbd->sd_jbsize; + unsigned int blks = 1; + + if (GFS_EAREQ_SIZE_STUFFED(er) > jbsize) + blks += DIV_RU(er->er_data_len, jbsize); + + return ea_alloc_skeleton(ip, er, + blks, + ea_init_i, NULL); +} + +/** + * ea_split_ea - + * @ea: + * + * Returns: the new ea + */ + +static struct gfs_ea_header * +ea_split_ea(struct gfs_ea_header *ea) +{ + uint32_t ea_size = GFS_EA_SIZE(ea); + struct gfs_ea_header *new = (struct gfs_ea_header *)((char *)ea + ea_size); + uint32_t new_size = GFS_EA_REC_LEN(ea) - ea_size; + int last = ea->ea_flags & GFS_EAFLAG_LAST; + + ea->ea_rec_len = cpu_to_gfs32(ea_size); + ea->ea_flags ^= last; + + new->ea_rec_len = cpu_to_gfs32(new_size); + new->ea_flags = last; + + return new; +} + +/** + * ea_set_remove_stuffed - + * @ip: + * @ea: + * + */ + +static void +ea_set_remove_stuffed(struct gfs_inode *ip, struct gfs_ea_location *el) +{ + struct gfs_ea_header *ea = el->el_ea; + struct gfs_ea_header *prev = el->el_prev; + uint32_t len; + + gfs_trans_add_bh(ip->i_gl, el->el_bh); + + if (!prev || !GFS_EA_IS_STUFFED(ea)) { + ea->ea_type = GFS_EATYPE_UNUSED; + return; + } else if (GFS_EA2NEXT(prev) != ea) { + prev = GFS_EA2NEXT(prev); + gfs_assert_withdraw(ip->i_sbd, GFS_EA2NEXT(prev) == ea); + } + + len = GFS_EA_REC_LEN(prev) + GFS_EA_REC_LEN(ea); + prev->ea_rec_len = cpu_to_gfs32(len); + + if (GFS_EA_IS_LAST(ea)) + prev->ea_flags |= GFS_EAFLAG_LAST; +} + +struct ea_set { + int ea_split; + + struct gfs_ea_request *es_er; + struct gfs_ea_location *es_el; + + struct buffer_head *es_bh; + struct gfs_ea_header *es_ea; +}; + +/** + * ea_set_simple_noalloc - + * @ip: + * @ea: + * @es: + * + * Returns: errno + */ + +static int +ea_set_simple_noalloc(struct gfs_inode *ip, + struct buffer_head *bh, + struct gfs_ea_header *ea, + struct ea_set *es) +{ + struct gfs_ea_request *er = es->es_er; + int error; + + error = gfs_trans_begin(ip->i_sbd, 3, 0); + if (error) + return error; + + gfs_trans_add_bh(ip->i_gl, bh); + + if (es->ea_split) + ea = ea_split_ea(ea); + + ea_write(ip, ea, er); + + if (es->es_el) + ea_set_remove_stuffed(ip, es->es_el); + + { + struct buffer_head *dibh; + error = gfs_get_inode_buffer(ip, &dibh); + if (!error) { + if (er->er_mode) { + ip->i_vnode->i_mode = er->er_mode; + gfs_inode_attr_out(ip); + } + ip->i_di.di_ctime = get_seconds(); + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + } + + gfs_trans_end(ip->i_sbd); + + return error; +} + +/** + * ea_set_simple_alloc - + * @ip: + * @er: + * @private: + * + * Returns: errno + */ + +static int +ea_set_simple_alloc(struct gfs_inode *ip, + struct gfs_ea_request *er, + void *private) +{ + struct ea_set *es = (struct ea_set *)private; + struct gfs_ea_header *ea = es->es_ea; + int error; + + gfs_trans_add_bh(ip->i_gl, es->es_bh); + + if (es->ea_split) + ea = ea_split_ea(ea); + + error = ea_write(ip, ea, er); + if (error) + return error; + + if (es->es_el) + ea_set_remove_stuffed(ip, es->es_el); + + return 0; +} + +/** + * ea_set_simple - + * @ip: + * @el: + * + * Returns: errno + */ + +static int +ea_set_simple(struct gfs_inode *ip, + struct buffer_head *bh, + struct gfs_ea_header *ea, + struct gfs_ea_header *prev, + void *private) +{ + struct ea_set *es = (struct ea_set *)private; + unsigned int size; + int stuffed; + int error; + + stuffed = ea_calc_size(ip->i_sbd, es->es_er, &size); + + if (ea->ea_type == GFS_EATYPE_UNUSED) { + if (GFS_EA_REC_LEN(ea) < size) + return 0; + if (!GFS_EA_IS_STUFFED(ea)) { + error = ea_remove_unstuffed(ip, bh, ea, prev, TRUE); + if (error) + return error; + } + es->ea_split = FALSE; + } else if (GFS_EA_REC_LEN(ea) - GFS_EA_SIZE(ea) >= size) + es->ea_split = TRUE; + else + return 0; + + if (stuffed) { + error = ea_set_simple_noalloc(ip, bh, ea, es); + if (error) + return error; + } else { + unsigned int blks; + + es->es_bh = bh; + es->es_ea = ea; + blks = 2 + DIV_RU(es->es_er->er_data_len, + ip->i_sbd->sd_jbsize); + + error = ea_alloc_skeleton(ip, es->es_er, + blks, + ea_set_simple_alloc, es); + if (error) + return error; + } + + return 1; +} + +/** + * ea_set_block - + * @ip: + * @er: + * @private: + * + * Returns: errno + */ + +static int +ea_set_block(struct gfs_inode *ip, + struct gfs_ea_request *er, + void *private) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct buffer_head *indbh, *newbh; + uint64_t *eablk; + int error; + + if (ip->i_di.di_flags & GFS_DIF_EA_INDIRECT) { + uint64_t *end; + + error = gfs_dread(ip->i_gl, ip->i_di.di_eattr, + DIO_START | DIO_WAIT, &indbh); + if (error) + return error; + + if (gfs_metatype_check(sdp, indbh, GFS_METATYPE_IN)) { + error = -EIO; + goto out; + } + + eablk = (uint64_t *)(indbh->b_data + sizeof(struct gfs_indirect)); + end = eablk + sdp->sd_inptrs; + + for (; eablk < end; eablk++) + if (!*eablk) + break; + + if (eablk == end) { + error = -ENOSPC; + goto out; + } + + gfs_trans_add_bh(ip->i_gl, indbh); + } else { + uint64_t blk; + + error = gfs_metaalloc(ip, &blk); + if (error) + return error; + + error = gfs_dread(ip->i_gl, blk, + DIO_NEW | DIO_START | DIO_WAIT, &indbh); + if (error) + return error; + + gfs_trans_add_bh(ip->i_gl, indbh); + gfs_metatype_set(indbh, GFS_METATYPE_IN, GFS_FORMAT_IN); + gfs_buffer_clear_tail(indbh, sizeof(struct gfs_meta_header)); + + eablk = (uint64_t *)(indbh->b_data + sizeof(struct gfs_indirect)); + *eablk = cpu_to_gfs64(ip->i_di.di_eattr); + ip->i_di.di_eattr = blk; + ip->i_di.di_flags |= GFS_DIF_EA_INDIRECT; + ip->i_di.di_blocks++; + + eablk++; + } + + error = ea_alloc_blk(ip, &newbh); + if (error) + goto out; + + *eablk = cpu_to_gfs64((uint64_t)newbh->b_blocknr); + error = ea_write(ip, GFS_EA_BH2FIRST(newbh), er); + brelse(newbh); + if (error) + goto out; + + if (private) + ea_set_remove_stuffed(ip, (struct gfs_ea_location *)private); + + out: + brelse(indbh); + + return error; +} + +/** + * ea_set_i - + * @ip: + * @el: + * + * Returns: errno + */ + +static int +ea_set_i(struct gfs_inode *ip, + struct gfs_ea_request *er, + struct gfs_ea_location *el) +{ + { + struct ea_set es; + int error; + + memset(&es, 0, sizeof(struct ea_set)); + es.es_er = er; + es.es_el = el; + + error = ea_foreach(ip, ea_set_simple, &es); + if (error > 0) + return 0; + if (error) + return error; + } + { + unsigned int blks = 2; + if (!(ip->i_di.di_flags & GFS_DIF_EA_INDIRECT)) + blks++; + if (GFS_EAREQ_SIZE_STUFFED(er) > ip->i_sbd->sd_jbsize) + blks += DIV_RU(er->er_data_len, + ip->i_sbd->sd_jbsize); + + return ea_alloc_skeleton(ip, er, blks, ea_set_block, el); + } +} + +/** + * ea_set_remove_unstuffed - + * @ip: + * @el: + * + * Returns: errno + */ + +static int +ea_set_remove_unstuffed(struct gfs_inode *ip, struct gfs_ea_location *el) +{ + if (el->el_prev && GFS_EA2NEXT(el->el_prev) != el->el_ea) { + el->el_prev = GFS_EA2NEXT(el->el_prev); + gfs_assert_withdraw(ip->i_sbd, + GFS_EA2NEXT(el->el_prev) == el->el_ea); + } + + return ea_remove_unstuffed(ip, el->el_bh, el->el_ea, el->el_prev, FALSE); +} + +/** + * gfs_ea_set_i - + * @ip: + * @er: + * + * Returns: errno + */ + +int +gfs_ea_set_i(struct gfs_inode *ip, struct gfs_ea_request *er) +{ + struct gfs_ea_location el; + int error; + + if (!ip->i_di.di_eattr) { + if (er->er_flags & XATTR_REPLACE) + return -ENODATA; + return ea_init(ip, er); + } + + error = gfs_ea_find(ip, er, &el); + if (error) + return error; + + if (el.el_ea) { + if (IS_APPEND(ip->i_vnode)) { + brelse(el.el_bh); + return -EPERM; + } + + error = -EEXIST; + if (!(er->er_flags & XATTR_CREATE)) { + int unstuffed = !GFS_EA_IS_STUFFED(el.el_ea); + error = ea_set_i(ip, er, &el); + if (!error && unstuffed) + ea_set_remove_unstuffed(ip, &el); + } + + brelse(el.el_bh); + } else { + error = -ENODATA; + if (!(er->er_flags & XATTR_REPLACE)) + error = ea_set_i(ip, er, NULL); + } + + return error; +} + +/** + * gfs_ea_set - + * @ip: + * @er: + * + * Returns: errno + */ + +int +gfs_ea_set(struct gfs_inode *ip, struct gfs_ea_request *er) +{ + struct gfs_holder i_gh; + int error; + + if (!er->er_name_len || + er->er_name_len > GFS_EA_MAX_NAME_LEN) + return -EINVAL; + if (!er->er_data || !er->er_data_len) { + er->er_data = NULL; + er->er_data_len = 0; + } + error = gfs_ea_check_size(ip->i_sbd, er); + if (error) + return error; + + error = gfs_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); + if (error) + return error; + + if (IS_IMMUTABLE(ip->i_vnode)) + error = -EPERM; + else + error = gfs_ea_ops[er->er_type]->eo_set(ip, er); + + gfs_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * ea_remove_stuffed - + * @ip: + * @el: + * @mode: + * + * Returns: errno + */ + +static int +ea_remove_stuffed(struct gfs_inode *ip, + struct gfs_ea_location *el) +{ + struct gfs_ea_header *ea = el->el_ea; + struct gfs_ea_header *prev = el->el_prev; + int error; + + error = gfs_trans_begin(ip->i_sbd, 2, 0); + if (error) + return error; + + gfs_trans_add_bh(ip->i_gl, el->el_bh); + + if (prev) { + uint32_t len; + + len = GFS_EA_REC_LEN(prev) + GFS_EA_REC_LEN(ea); + prev->ea_rec_len = cpu_to_gfs32(len); + + if (GFS_EA_IS_LAST(ea)) + prev->ea_flags |= GFS_EAFLAG_LAST; + } else + ea->ea_type = GFS_EATYPE_UNUSED; + + { + struct buffer_head *dibh; + error = gfs_get_inode_buffer(ip, &dibh); + if (!error) { + ip->i_di.di_ctime = get_seconds(); + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + } + + gfs_trans_end(ip->i_sbd); + + return error; +} + +/** + * gfs_ea_remove_i - + * @ip: + * @er: + * + * Returns: errno + */ + +int +gfs_ea_remove_i(struct gfs_inode *ip, struct gfs_ea_request *er) +{ + struct gfs_ea_location el; + int error; + + if (!ip->i_di.di_eattr) + return -ENODATA; + + error = gfs_ea_find(ip, er, &el); + if (error) + return error; + if (!el.el_ea) + return -ENODATA; + + if (GFS_EA_IS_STUFFED(el.el_ea)) + error = ea_remove_stuffed(ip, &el); + else + error = ea_remove_unstuffed(ip, el.el_bh, el.el_ea, el.el_prev, FALSE); + + brelse(el.el_bh); + + return error; +} + +/** + * gfs_ea_remove - sets (or creates or replaces) an extended attribute + * @ip: pointer to the inode of the target file + * @er: request information + * + * Returns: errno + */ + +int +gfs_ea_remove(struct gfs_inode *ip, struct gfs_ea_request *er) +{ + struct gfs_holder i_gh; + int error; + + if (!er->er_name_len || + er->er_name_len > GFS_EA_MAX_NAME_LEN) + return -EINVAL; + + error = gfs_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); + if (error) + return error; + + if (IS_IMMUTABLE(ip->i_vnode) || IS_APPEND(ip->i_vnode)) + error = -EPERM; + else + error = gfs_ea_ops[er->er_type]->eo_remove(ip, er); + + gfs_glock_dq_uninit(&i_gh); + + return error; +} + +/** + * gfs_ea_acl_init - + * @ip: + * @er: + * + * Returns: errno + */ + +int +gfs_ea_acl_init(struct gfs_inode *ip, struct gfs_ea_request *er) +{ + int error; + + if (!ip->i_di.di_eattr) + return ea_init_i(ip, er, NULL); + + { + struct buffer_head *bh; + struct gfs_ea_header *ea; + unsigned int size; + + ea_calc_size(ip->i_sbd, er, &size); + + error = gfs_dread(ip->i_gl, ip->i_di.di_eattr, + DIO_START | DIO_WAIT, &bh); + if (error) + return error; + + if (gfs_metatype_check(ip->i_sbd, bh, GFS_METATYPE_EA)) { + brelse(bh); + return -EIO; + } + + ea = GFS_EA_BH2FIRST(bh); + if (GFS_EA_REC_LEN(ea) - GFS_EA_SIZE(ea) >= size) { + ea = ea_split_ea(ea); + ea_write(ip, ea, er); + brelse(bh); + return 0; + } + + brelse(bh); + } + + error = ea_set_block(ip, er, NULL); + gfs_assert_withdraw(ip->i_sbd, error != -ENOSPC); + if (error) + return error; + + { + struct buffer_head *dibh; + error = gfs_get_inode_buffer(ip, &dibh); + if (error) + return error; + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + return error; +} + +/** + * ea_acl_chmod_unstuffed - + * @ip: + * @ea: + * @data: + * + * Returns: errno + */ + +static int +ea_acl_chmod_unstuffed(struct gfs_inode *ip, + struct gfs_ea_header *ea, + char *data) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct buffer_head **bh; + unsigned int amount = GFS_EA_DATA_LEN(ea); + unsigned int nptrs = DIV_RU(amount, sdp->sd_jbsize); + uint64_t *dataptrs = GFS_EA2DATAPTRS(ea); + unsigned int x; + int error; + + bh = kmalloc(nptrs * sizeof(struct buffer_head *), GFP_KERNEL); + if (!bh) + return -ENOMEM; + + error = gfs_trans_begin(sdp, 1 + nptrs, 0); + if (error) + goto out; + + for (x = 0; x < nptrs; x++) { + error = gfs_dread(ip->i_gl, gfs64_to_cpu(*dataptrs), + DIO_START, bh + x); + if (error) { + while (x--) + brelse(bh[x]); + goto fail; + } + dataptrs++; + } + + for (x = 0; x < nptrs; x++) { + error = gfs_dreread(sdp, bh[x], DIO_WAIT); + if (error) { + for (; x < nptrs; x++) + brelse(bh[x]); + goto fail; + } + if (gfs_metatype_check2(sdp, bh[x], + GFS_METATYPE_ED, GFS_METATYPE_EA)) { + for (; x < nptrs; x++) + brelse(bh[x]); + error = -EIO; + goto fail; + } + + gfs_trans_add_bh(ip->i_gl, bh[x]); + + memcpy(bh[x]->b_data + sizeof(struct gfs_meta_header), + data, + (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize); + + amount -= sdp->sd_jbsize; + data += sdp->sd_jbsize; + + brelse(bh[x]); + } + + out: + kfree(bh); + + return error; + + fail: + gfs_trans_end(sdp); + kfree(bh); + + return error; +} + +/** + * gfs_ea_acl_chmod - + * @ip: + * @el: + * @attr: + * @data: + * + * Returns: errno + */ + +int +gfs_ea_acl_chmod(struct gfs_inode *ip, struct gfs_ea_location *el, + struct iattr *attr, char *data) +{ + struct buffer_head *dibh; + int error; + + if (GFS_EA_IS_STUFFED(el->el_ea)) { + error = gfs_trans_begin(ip->i_sbd, 2, 0); + if (error) + return error; + + gfs_trans_add_bh(ip->i_gl, el->el_bh); + memcpy(GFS_EA2DATA(el->el_ea), + data, + GFS_EA_DATA_LEN(el->el_ea)); + } else + error = ea_acl_chmod_unstuffed(ip, el->el_ea, data); + + if (error) + return error; + + error = gfs_get_inode_buffer(ip, &dibh); + if (!error) { + error = inode_setattr(ip->i_vnode, attr); + gfs_assert_warn(ip->i_sbd, !error); + gfs_inode_attr_out(ip); + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + gfs_trans_end(ip->i_sbd); + + return error; +} + +/** + * ea_dealloc_indirect - + * @ip: + * + * Returns: errno + */ + +static int +ea_dealloc_indirect(struct gfs_inode *ip) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_rgrp_list rlist; + struct buffer_head *indbh, *dibh; + uint64_t *eablk, *end; + unsigned int rg_blocks = 0; + uint64_t bstart = 0; + unsigned int blen = 0; + unsigned int x; + int error; + + memset(&rlist, 0, sizeof(struct gfs_rgrp_list)); + + error = gfs_dread(ip->i_gl, ip->i_di.di_eattr, + DIO_START | DIO_WAIT, &indbh); + if (error) + return error; + + if (gfs_metatype_check(sdp, indbh, GFS_METATYPE_IN)) { + error = -EIO; + goto out; + } + + eablk = (uint64_t *)(indbh->b_data + sizeof(struct gfs_indirect)); + end = eablk + sdp->sd_inptrs; + + for (; eablk < end; eablk++) { + uint64_t bn; + + if (!*eablk) + break; + bn = gfs64_to_cpu(*eablk); + + if (bstart + blen == bn) + blen++; + else { + if (bstart) + gfs_rlist_add(sdp, &rlist, bstart); + bstart = bn; + blen = 1; + } + } + if (bstart) + gfs_rlist_add(sdp, &rlist, bstart); + else + goto out; + + gfs_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0); + + for (x = 0; x < rlist.rl_rgrps; x++) { + struct gfs_rgrpd *rgd; + rgd = get_gl2rgd(rlist.rl_ghs[x].gh_gl); + rg_blocks += rgd->rd_ri.ri_length; + } + + error = gfs_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs); + if (error) + goto out_rlist_free; + + error = gfs_trans_begin(sdp, 2 + rg_blocks, 1); + if (error) + goto out_gunlock; + + gfs_trans_add_bh(ip->i_gl, indbh); + + eablk = (uint64_t *)(indbh->b_data + sizeof(struct gfs_indirect)); + bstart = 0; + blen = 0; + + for (; eablk < end; eablk++) { + uint64_t bn; + + if (!*eablk) + break; + bn = gfs64_to_cpu(*eablk); + + if (bstart + blen == bn) + blen++; + else { + if (bstart) + gfs_metafree(ip, bstart, blen); + bstart = bn; + blen = 1; + } + + *eablk = 0; + if (!ip->i_di.di_blocks) + gfs_consist_inode(ip); + ip->i_di.di_blocks--; + } + if (bstart) + gfs_metafree(ip, bstart, blen); + + ip->i_di.di_flags &= ~GFS_DIF_EA_INDIRECT; + + error = gfs_get_inode_buffer(ip, &dibh); + if (!error) { + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + gfs_trans_end(sdp); + + out_gunlock: + gfs_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs); + + out_rlist_free: + gfs_rlist_free(&rlist); + + out: + brelse(indbh); + + return error; +} + +/** + * ea_dealloc_block - + * @ip: + * + * Returns: errno + */ + +static int +ea_dealloc_block(struct gfs_inode *ip) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct gfs_alloc *al = ip->i_alloc; + struct gfs_rgrpd *rgd; + struct buffer_head *dibh; + int error; + + rgd = gfs_blk2rgrpd(sdp, ip->i_di.di_eattr); + if (!rgd) { + gfs_consist_inode(ip); + return -EIO; + } + + error = gfs_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &al->al_rgd_gh); + if (error) + return error; + + error = gfs_trans_begin(sdp, 1 + rgd->rd_ri.ri_length, 1); + if (error) + goto out_gunlock; + + gfs_metafree(ip, ip->i_di.di_eattr, 1); + + ip->i_di.di_eattr = 0; + if (!ip->i_di.di_blocks) + gfs_consist_inode(ip); + ip->i_di.di_blocks--; + + error = gfs_get_inode_buffer(ip, &dibh); + if (!error) { + gfs_trans_add_bh(ip->i_gl, dibh); + gfs_dinode_out(&ip->i_di, dibh->b_data); + brelse(dibh); + } + + gfs_trans_end(sdp); + + out_gunlock: + gfs_glock_dq_uninit(&al->al_rgd_gh); + + return error; +} + +/** + * gfs_ea_dealloc - deallocate the extended attribute fork + * @ip: the inode + * + * Returns: errno + */ + +int +gfs_ea_dealloc(struct gfs_inode *ip) +{ + struct gfs_alloc *al; + int error; + + al = gfs_alloc_get(ip); + + error = gfs_quota_hold_m(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out_alloc; + + error = gfs_rindex_hold(ip->i_sbd, &al->al_ri_gh); + if (error) + goto out_quota; + + error = ea_foreach(ip, ea_dealloc_unstuffed, NULL); + if (error) + goto out_rindex; + + if (ip->i_di.di_flags & GFS_DIF_EA_INDIRECT) { + error = ea_dealloc_indirect(ip); + if (error) + goto out_rindex; + } + + error = ea_dealloc_block(ip); + + out_rindex: + gfs_glock_dq_uninit(&al->al_ri_gh); + + out_quota: + gfs_quota_unhold_m(ip); + + out_alloc: + gfs_alloc_put(ip); + + return error; +} + +/** + * gfs_get_eattr_meta - return all the eattr blocks of a file + * @dip: the directory + * @ub: the structure representing the user buffer to copy to + * + * Returns: errno + */ + +int +gfs_get_eattr_meta(struct gfs_inode *ip, struct gfs_user_buffer *ub) +{ + struct buffer_head *bh; + int error; + + error = gfs_dread(ip->i_gl, ip->i_di.di_eattr, + DIO_START | DIO_WAIT, &bh); + if (error) + return error; + + gfs_add_bh_to_ub(ub, bh); + + if (ip->i_di.di_flags & GFS_DIF_EA_INDIRECT) { + struct buffer_head *eabh; + uint64_t *eablk, *end; + + if (gfs_metatype_check(ip->i_sbd, bh, GFS_METATYPE_IN)) { + error = -EIO; + goto out; + } + + eablk = (uint64_t *)(bh->b_data + sizeof(struct gfs_indirect)); + end = eablk + ip->i_sbd->sd_inptrs; + + for (; eablk < end; eablk++) { + uint64_t bn; + + if (!*eablk) + break; + bn = gfs64_to_cpu(*eablk); + + error = gfs_dread(ip->i_gl, bn, + DIO_START | DIO_WAIT, &eabh); + if (error) + break; + gfs_add_bh_to_ub(ub, eabh); + brelse(eabh); + if (error) + break; + } + } + + out: + brelse(bh); + + return error; +} --- linux-2.6.27.orig/ubuntu/gfs/dir.h +++ linux-2.6.27/ubuntu/gfs/dir.h @@ -0,0 +1,42 @@ +#ifndef __DIR_DOT_H__ +#define __DIR_DOT_H__ + +/** + * gfs_filldir_t - Report a directory entry to the caller of gfs_dir_read() + * @opaque: opaque data used by the function + * @name: the name of the directory entry + * @length: the length of the name + * @offset: the entry's offset in the directory + * @inum: the inode number the entry points to + * @type: the type of inode the entry points to + * + * Returns: 0 on success, 1 if buffer full + */ + +typedef int (*gfs_filldir_t) (void *opaque, + const char *name, unsigned int length, + uint64_t offset, + struct gfs_inum *inum, unsigned int type); + +int gfs_filecmp(struct qstr *file1, char *file2, int len_of_file2); +int gfs_dirent_alloc(struct gfs_inode *dip, struct buffer_head *bh, + int name_len, struct gfs_dirent **dent_out); + +int gfs_dir_search(struct gfs_inode *dip, struct qstr *filename, + struct gfs_inum *inum, unsigned int *type); +int gfs_dir_add(struct gfs_inode *dip, struct qstr *filename, + struct gfs_inum *inum, unsigned int type); +int gfs_dir_del(struct gfs_inode *dip, struct qstr *filename); +int gfs_dir_read(struct gfs_inode *dip, uint64_t * offset, void *opaque, + gfs_filldir_t filldir); +int gfs_dir_mvino(struct gfs_inode *dip, struct qstr *filename, + struct gfs_inum *new_inum, unsigned int new_type); + +int gfs_dir_exhash_free(struct gfs_inode *dip); + +int gfs_diradd_alloc_required(struct gfs_inode *dip, struct qstr *filename, + int *alloc_required); + +int gfs_get_dir_meta(struct gfs_inode *ip, struct gfs_user_buffer *ub); + +#endif /* __DIR_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/ops_inode.h +++ linux-2.6.27/ubuntu/gfs/ops_inode.h @@ -0,0 +1,9 @@ +#ifndef __OPS_INODE_DOT_H__ +#define __OPS_INODE_DOT_H__ + +extern struct inode_operations gfs_file_iops; +extern struct inode_operations gfs_dir_iops; +extern struct inode_operations gfs_symlink_iops; +extern struct inode_operations gfs_dev_iops; + +#endif /* __OPS_INODE_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/dio.c +++ linux-2.6.27/ubuntu/gfs/dio.c @@ -0,0 +1,1342 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "dio.h" +#include "glock.h" +#include "glops.h" +#include "inode.h" +#include "log.h" +#include "lops.h" +#include "rgrp.h" +#include "trans.h" + +#define buffer_busy(bh) ((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock))) + +/** + * aspace_get_block - + * @inode: + * @lblock: + * @bh_result: + * @create: + * + * Returns: errno + */ + +static int +aspace_get_block(struct inode *inode, sector_t lblock, + struct buffer_head *bh_result, int create) +{ + gfs_assert_warn(get_v2sdp(inode->i_sb), FALSE); + return -ENOSYS; +} + +/** + * gfs_aspace_writepage - write an aspace page + * @page: the page + * @wbc: + * + * Returns: errno + */ + +static int +gfs_aspace_writepage(struct page *page, struct writeback_control *wbc) +{ + return block_write_full_page(page, aspace_get_block, wbc); +} + +/** + * stuck_releasepage - We're stuck in gfs_releasepage(). Print stuff out. + * @bh: the buffer we're stuck on + * + */ + +static void +stuck_releasepage(struct buffer_head *bh) +{ + struct gfs_sbd *sdp = get_v2sdp(bh->b_page->mapping->host->i_sb); + struct gfs_bufdata *bd = get_v2bd(bh); + + printk("GFS: fsid=%s: stuck in gfs_releasepage()...\n", sdp->sd_fsname); + printk("GFS: fsid=%s: blkno = %"PRIu64", bh->b_count = %d\n", + sdp->sd_fsname, + (uint64_t)bh->b_blocknr, + atomic_read(&bh->b_count)); + printk("GFS: fsid=%s: get_v2bd(bh) = %s\n", + sdp->sd_fsname, + (bd) ? "!NULL" : "NULL"); + + if (bd) { + struct gfs_glock *gl = bd->bd_gl; + + printk("GFS: fsid=%s: gl = (%u, %"PRIu64")\n", + sdp->sd_fsname, + gl->gl_name.ln_type, + gl->gl_name.ln_number); + + printk("GFS: fsid=%s: bd_new_le.le_trans = %s\n", + sdp->sd_fsname, + (bd->bd_new_le.le_trans) ? "!NULL" : "NULL"); + printk("GFS: fsid=%s: bd_incore_le.le_trans = %s\n", + sdp->sd_fsname, + (bd->bd_incore_le.le_trans) ? "!NULL" : "NULL"); + printk("GFS: fsid=%s: bd_frozen = %s\n", + sdp->sd_fsname, + (bd->bd_frozen) ? "!NULL" : "NULL"); + printk("GFS: fsid=%s: bd_pinned = %u\n", + sdp->sd_fsname, bd->bd_pinned); + printk("GFS: fsid=%s: bd_ail_tr_list = %s\n", + sdp->sd_fsname, + (list_empty(&bd->bd_ail_tr_list)) ? "Empty" : "!Empty"); + + if (gl->gl_ops == &gfs_inode_glops) { + struct gfs_inode *ip = get_gl2ip(gl); + + if (ip) { + unsigned int x; + + printk("GFS: fsid=%s: ip = %"PRIu64"/%"PRIu64"\n", + sdp->sd_fsname, + ip->i_num.no_formal_ino, + ip->i_num.no_addr); + printk("GFS: fsid=%s: ip->i_count = %d, ip->i_vnode = %s\n", + sdp->sd_fsname, + atomic_read(&ip->i_count), + (ip->i_vnode) ? "!NULL" : "NULL"); + for (x = 0; x < GFS_MAX_META_HEIGHT; x++) + printk("GFS: fsid=%s: ip->i_cache[%u] = %s\n", + sdp->sd_fsname, x, + (ip->i_cache[x]) ? "!NULL" : "NULL"); + } + } + } +} + +/** + * gfs_aspace_releasepage - free the metadata associated with a page + * @page: the page that's being released + * @gfp_mask: passed from Linux VFS, ignored by us + * + * Call try_to_free_buffers() if the buffers in this page can be + * released. + * + * Returns: 0 + */ + +static int +gfs_aspace_releasepage(struct page *page, gfp_t gfp_mask) +{ + struct inode *aspace = page->mapping->host; + struct gfs_sbd *sdp = get_v2sdp(aspace->i_sb); + struct buffer_head *bh, *head; + struct gfs_bufdata *bd; + unsigned long t; + + if (!page_has_buffers(page)) + goto out; + + head = bh = page_buffers(page); + do { + t = jiffies; + + while (atomic_read(&bh->b_count)) { + if (atomic_read(&aspace->i_writecount)) { + if (time_after_eq(jiffies, + t + + gfs_tune_get(sdp, gt_stall_secs) * HZ)) { + stuck_releasepage(bh); + t = jiffies; + } + + yield(); + continue; + } + + return 0; + } + + bd = get_v2bd(bh); + if (bd) { + gfs_assert_warn(sdp, bd->bd_bh == bh); + gfs_assert_warn(sdp, !bd->bd_new_le.le_trans); + gfs_assert_warn(sdp, !bd->bd_incore_le.le_trans); + gfs_assert_warn(sdp, !bd->bd_frozen); + gfs_assert_warn(sdp, !bd->bd_pinned); + gfs_assert_warn(sdp, list_empty(&bd->bd_ail_tr_list)); + kmem_cache_free(gfs_bufdata_cachep, bd); + atomic_dec(&sdp->sd_bufdata_count); + set_v2bd(bh, NULL); + } + + bh = bh->b_this_page; + } + while (bh != head); + + out: + return try_to_free_buffers(page); +} + +static struct address_space_operations aspace_aops = { + .writepage = gfs_aspace_writepage, + .releasepage = gfs_aspace_releasepage, +}; + +/** + * gfs_aspace_get - Create and initialize a struct inode structure + * @sdp: the filesystem the aspace is in + * + * Right now a struct inode is just a struct inode. Maybe Linux + * will supply a more lightweight address space construct (that works) + * in the future. + * + * Make sure pages/buffers in this aspace aren't in high memory. + * + * Returns: the aspace + */ + +struct inode * +gfs_aspace_get(struct gfs_sbd *sdp) +{ + struct inode *aspace; + + aspace = new_inode(sdp->sd_vfs); + if (aspace) { + mapping_set_gfp_mask(aspace->i_mapping, GFP_KERNEL); + aspace->i_mapping->a_ops = &aspace_aops; + aspace->i_size = ~0ULL; + set_v2ip(aspace, NULL); + insert_inode_hash(aspace); + } + + return aspace; +} + +/** + * gfs_aspace_put - get rid of an aspace + * @aspace: + * + */ + +void +gfs_aspace_put(struct inode *aspace) +{ + remove_inode_hash(aspace); + iput(aspace); +} + +/** + * gfs_ail_start_trans - Start I/O on a part of the AIL + * @sdp: the filesystem + * @tr: the part of the AIL + * + */ + +void +gfs_ail_start_trans(struct gfs_sbd *sdp, struct gfs_trans *tr) +{ + struct list_head *head, *tmp, *prev; + struct gfs_bufdata *bd; + struct buffer_head *bh; + int retry; + + do { + retry = FALSE; + + spin_lock(&sdp->sd_ail_lock); + + for (head = &tr->tr_ail_bufs, tmp = head->prev, prev = tmp->prev; + tmp != head; + tmp = prev, prev = tmp->prev) { + bd = list_entry(tmp, struct gfs_bufdata, bd_ail_tr_list); + bh = bd->bd_bh; + + if (gfs_trylock_buffer(bh)) + continue; + + if (bd->bd_pinned) { + gfs_unlock_buffer(bh); + continue; + } + + if (!buffer_busy(bh)) { + if (!buffer_uptodate(bh)) + gfs_io_error_bh(sdp, bh); + + list_del_init(&bd->bd_ail_tr_list); + list_del(&bd->bd_ail_gl_list); + + gfs_unlock_buffer(bh); + brelse(bh); + continue; + } + + if (buffer_dirty(bh)) { + list_move(&bd->bd_ail_tr_list, head); + + spin_unlock(&sdp->sd_ail_lock); + wait_on_buffer(bh); + ll_rw_block(WRITE, 1, &bh); + spin_lock(&sdp->sd_ail_lock); + + gfs_unlock_buffer(bh); + retry = TRUE; + break; + } + + gfs_unlock_buffer(bh); + } + + spin_unlock(&sdp->sd_ail_lock); + } while (retry); +} + +/** + * gfs_ail_empty_trans - Check whether or not a trans in the AIL has been synced + * @sdp: the filesystem + * @tr: the transaction + * + */ + +int +gfs_ail_empty_trans(struct gfs_sbd *sdp, struct gfs_trans *tr) +{ + struct list_head *head, *tmp, *prev; + struct gfs_bufdata *bd; + struct buffer_head *bh; + int ret; + + spin_lock(&sdp->sd_ail_lock); + + for (head = &tr->tr_ail_bufs, tmp = head->prev, prev = tmp->prev; + tmp != head; + tmp = prev, prev = tmp->prev) { + bd = list_entry(tmp, struct gfs_bufdata, bd_ail_tr_list); + bh = bd->bd_bh; + + if (gfs_trylock_buffer(bh)) + continue; + + if (bd->bd_pinned || buffer_busy(bh)) { + gfs_unlock_buffer(bh); + continue; + } + + if (!buffer_uptodate(bh)) + gfs_io_error_bh(sdp, bh); + + list_del_init(&bd->bd_ail_tr_list); + list_del(&bd->bd_ail_gl_list); + + gfs_unlock_buffer(bh); + brelse(bh); + } + + ret = list_empty(head); + + spin_unlock(&sdp->sd_ail_lock); + + return ret; +} + +/** + * ail_empty_gl - remove all buffers for a given lock from the AIL + * @gl: the glock + * + * None of the buffers should be dirty, locked, or pinned. + */ + +static void +ail_empty_gl(struct gfs_glock *gl) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + struct gfs_bufdata *bd; + struct buffer_head *bh; + + spin_lock(&sdp->sd_ail_lock); + + while (!list_empty(&gl->gl_ail_bufs)) { + bd = list_entry(gl->gl_ail_bufs.next, + struct gfs_bufdata, bd_ail_gl_list); + bh = bd->bd_bh; + + gfs_assert_withdraw(sdp, !bd->bd_pinned && !buffer_busy(bh)); + if (!buffer_uptodate(bh)) + gfs_io_error_bh(sdp, bh); + + list_del_init(&bd->bd_ail_tr_list); + list_del(&bd->bd_ail_gl_list); + + brelse(bh); + } + + spin_unlock(&sdp->sd_ail_lock); +} + +/** + * gfs_inval_buf - Invalidate all buffers associated with a glock + * @gl: the glock + * + */ + +void +gfs_inval_buf(struct gfs_glock *gl) +{ + struct inode *aspace = gl->gl_aspace; + struct address_space *mapping = gl->gl_aspace->i_mapping; + + ail_empty_gl(gl); + + atomic_inc(&aspace->i_writecount); + truncate_inode_pages(mapping, 0); + atomic_dec(&aspace->i_writecount); + + gfs_assert_withdraw(gl->gl_sbd, !mapping->nrpages); +} + +/** + * gfs_sync_buf - Sync all buffers associated with a glock + * @gl: The glock + * @flags: DIO_START | DIO_WAIT | DIO_CHECK + * + */ + +void +gfs_sync_buf(struct gfs_glock *gl, int flags) +{ + struct address_space *mapping = gl->gl_aspace->i_mapping; + int error = 0; + + if (flags & DIO_START) + error = filemap_fdatawrite(mapping); + if (!error && (flags & DIO_WAIT)) + error = filemap_fdatawait(mapping); + if (!error && (flags & (DIO_INVISIBLE | DIO_CHECK)) == DIO_CHECK) + ail_empty_gl(gl); + + if (error) + gfs_io_error(gl->gl_sbd); +} + +/** + * getbuf - Get a buffer with a given address space + * @sdp: the filesystem + * @aspace: the address space + * @blkno: the block number (filesystem scope) + * @create: TRUE if the buffer should be created + * + * Returns: the buffer + */ + +static struct buffer_head * +getbuf(struct gfs_sbd *sdp, struct inode *aspace, uint64_t blkno, int create) +{ + struct page *page; + struct buffer_head *bh; + unsigned int shift; + unsigned long index; + unsigned int bufnum; + + shift = PAGE_CACHE_SHIFT - sdp->sd_sb.sb_bsize_shift; + index = blkno >> shift; /* convert block to page */ + bufnum = blkno - (index << shift); /* block buf index within page */ + + if (create) { + RETRY_MALLOC(page = grab_cache_page(aspace->i_mapping, index), page); + } else { + page = find_lock_page(aspace->i_mapping, index); + if (!page) + return NULL; + } + + if (!page_has_buffers(page)) + create_empty_buffers(page, sdp->sd_sb.sb_bsize, 0); + + /* Locate header for our buffer within our page */ + for (bh = page_buffers(page); bufnum--; bh = bh->b_this_page) + /* Do nothing */; + get_bh(bh); + + if (!buffer_mapped(bh)) + map_bh(bh, sdp->sd_vfs, blkno); + else if (gfs_assert_warn(sdp, bh->b_bdev == sdp->sd_vfs->s_bdev && + bh->b_blocknr == blkno)) + map_bh(bh, sdp->sd_vfs, blkno); + + unlock_page(page); + page_cache_release(page); + + return bh; +} + +/** + * gfs_dgetblk - Get a block + * @gl: The glock associated with this block + * @blkno: The block number + * + * Returns: The buffer + */ + +struct buffer_head * +gfs_dgetblk(struct gfs_glock *gl, uint64_t blkno) +{ + return getbuf(gl->gl_sbd, gl->gl_aspace, blkno, CREATE); +} + +/** + * gfs_dread - Read a block from disk + * @gl: The glock covering the block + * @blkno: The block number + * @flags: flags to gfs_dreread() + * @bhp: the place where the buffer is returned (NULL on failure) + * + * Returns: errno + */ + +int +gfs_dread(struct gfs_glock *gl, uint64_t blkno, + int flags, struct buffer_head **bhp) +{ + int error; + + *bhp = gfs_dgetblk(gl, blkno); + error = gfs_dreread(gl->gl_sbd, *bhp, flags); + if (error) + brelse(*bhp); + + return error; +} + +/** + * gfs_prep_new_buffer - Mark a new buffer we just gfs_dgetblk()ed uptodate + * @bh: the buffer + * + */ + +void +gfs_prep_new_buffer(struct buffer_head *bh) +{ + wait_on_buffer(bh); + clear_buffer_dirty(bh); + set_buffer_uptodate(bh); +} + +/** + * gfs_dreread - Reread a block from disk + * @sdp: the filesystem + * @bh: The block to read + * @flags: Flags that control the read + * + * Returns: errno + */ + +int +gfs_dreread(struct gfs_sbd *sdp, struct buffer_head *bh, int flags) +{ + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + return -EIO; + + /* Fill in meta-header if we have a cached copy, else read from disk */ + if (flags & DIO_NEW) { + if (gfs_mhc_fish(sdp, bh)) + return 0; + clear_buffer_uptodate(bh); + } + + if (flags & DIO_FORCE) + clear_buffer_uptodate(bh); + + if ((flags & DIO_START) && !buffer_uptodate(bh)) + ll_rw_block(READ, 1, &bh); + + if (flags & DIO_WAIT) { + wait_on_buffer(bh); + + if (!buffer_uptodate(bh)) { + gfs_io_error_bh(sdp, bh); + return -EIO; + } + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + return -EIO; + } + + return 0; +} + +/** + * gfs_dwrite - Write a buffer to disk (and/or wait for write to complete) + * @sdp: the filesystem + * @bh: The buffer to write + * @flags: DIO_XXX The type of write/wait operation to do + * + * Returns: errno + */ + +int +gfs_dwrite(struct gfs_sbd *sdp, struct buffer_head *bh, int flags) +{ + if (gfs_assert_warn(sdp, !test_bit(SDF_ROFS, &sdp->sd_flags))) + return -EIO; + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + return -EIO; + + if (flags & DIO_CLEAN) { + lock_buffer(bh); + clear_buffer_dirty(bh); + unlock_buffer(bh); + } + + if (flags & DIO_DIRTY) { + if (gfs_assert_warn(sdp, buffer_uptodate(bh))) + return -EIO; + mark_buffer_dirty(bh); + } + + if ((flags & DIO_START) && buffer_dirty(bh)) { + wait_on_buffer(bh); + ll_rw_block(WRITE, 1, &bh); + } + + if (flags & DIO_WAIT) { + wait_on_buffer(bh); + + if (!buffer_uptodate(bh) || buffer_dirty(bh)) { + gfs_io_error_bh(sdp, bh); + return -EIO; + } + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + return -EIO; + } + + return 0; +} + +/** + * gfs_attach_bufdata - attach a struct gfs_bufdata structure to a buffer + * @bh: The buffer to be attached to + * @gl: the glock the buffer belongs to + * + */ + +void +gfs_attach_bufdata(struct buffer_head *bh, struct gfs_glock *gl) +{ + struct gfs_bufdata *bd; + + lock_page(bh->b_page); + + /* If there's one attached already, we're done */ + if (get_v2bd(bh)) { + unlock_page(bh->b_page); + return; + } + + RETRY_MALLOC(bd = kmem_cache_alloc(gfs_bufdata_cachep, GFP_KERNEL), bd); + atomic_inc(&gl->gl_sbd->sd_bufdata_count); + + memset(bd, 0, sizeof(struct gfs_bufdata)); + + bd->bd_bh = bh; + bd->bd_gl = gl; + + INIT_LE(&bd->bd_new_le, &gfs_buf_lops); + INIT_LE(&bd->bd_incore_le, &gfs_buf_lops); + + init_MUTEX(&bd->bd_lock); + + INIT_LIST_HEAD(&bd->bd_ail_tr_list); + + set_v2bd(bh, bd); + + unlock_page(bh->b_page); +} + +/** + * gfs_is_pinned - Figure out if a buffer is pinned or not + * @sdp: the filesystem the buffer belongs to + * @bh: The buffer to be pinned + * + * Returns: TRUE if the buffer is pinned, FALSE otherwise + */ + +int +gfs_is_pinned(struct gfs_sbd *sdp, struct buffer_head *bh) +{ + struct gfs_bufdata *bd = get_v2bd(bh); + int ret = FALSE; + + if (bd) { + gfs_lock_buffer(bh); + if (bd->bd_pinned) + ret = TRUE; + gfs_unlock_buffer(bh); + } + + return ret; +} + +/** + * gfs_dpin - Pin a metadata buffer in memory + * @sdp: the filesystem the buffer belongs to + * @bh: The buffer to be pinned + * + * "Pinning" means keeping buffer from being written to its in-place location. + * A buffer should be pinned from the time it is added to a new transaction, + * until after it has been written to the log. + * If an earlier change to this buffer is still pinned, waiting to be written + * to on-disk log, we need to keep a "frozen" copy of the old data while this + * transaction is modifying the real data. We keep the frozen copy until + * this transaction's incore_commit(), i.e. until the transaction has + * finished modifying the real data, at which point we can use the real + * buffer for logging, even if the frozen copy didn't get written to the log. + * + */ + +void +gfs_dpin(struct gfs_sbd *sdp, struct buffer_head *bh) +{ + struct gfs_bufdata *bd = get_v2bd(bh); + char *data; + + gfs_assert_withdraw(sdp, !test_bit(SDF_ROFS, &sdp->sd_flags)); + + gfs_lock_buffer(bh); + + gfs_assert_warn(sdp, !bd->bd_frozen); + + if (!bd->bd_pinned++) { + wait_on_buffer(bh); + + /* If this buffer is in the AIL and it has already been written + to in-place disk block, remove it from the AIL. */ + + spin_lock(&sdp->sd_ail_lock); + if (!list_empty(&bd->bd_ail_tr_list) && !buffer_busy(bh)) { + list_del_init(&bd->bd_ail_tr_list); + list_del(&bd->bd_ail_gl_list); + brelse(bh); + } + spin_unlock(&sdp->sd_ail_lock); + + clear_buffer_dirty(bh); + wait_on_buffer(bh); + + if (!buffer_uptodate(bh)) + gfs_io_error_bh(sdp, bh); + } else { + gfs_unlock_buffer(bh); + + gfs_assert_withdraw(sdp, buffer_uptodate(bh)); + + data = gmalloc(sdp->sd_sb.sb_bsize); + + gfs_lock_buffer(bh); + + /* Create frozen copy, if needed. */ + if (bd->bd_pinned > 1) { + memcpy(data, bh->b_data, sdp->sd_sb.sb_bsize); + bd->bd_frozen = data; + } else + kfree(data); + } + + gfs_unlock_buffer(bh); + + get_bh(bh); +} + +/** + * gfs_dunpin - Unpin a buffer + * @sdp: the filesystem the buffer belongs to + * @bh: The buffer to unpin + * @tr: The transaction in the AIL that contains this buffer + * If NULL, don't attach buffer to any AIL list + * (i.e. when dropping a pin reference when merging a new transaction + * with an already existing incore transaction) + * + * Called for (meta) buffers, after they've been logged to on-disk journal. + * Make a (meta) buffer writeable to in-place location on-disk, if recursive + * pin count is 1 (i.e. no other, later transaction is modifying this buffer). + * Add buffer to AIL lists of 1) the latest transaction that's modified and + * logged (on-disk) the buffer, and of 2) the glock that protects the buffer. + * A single buffer might have been modified by more than one transaction + * since the buffer's previous write to disk (in-place location). We keep + * the buffer on only one transaction's AIL list, i.e. that of the latest + * transaction that's completed logging this buffer (no need to write it to + * in-place block multiple times for multiple transactions, only once with + * the most up-to-date data). + * A single buffer will be protected by one and only one glock. If buffer is + * already on a (previous) transaction's AIL, we know that we're already + * on buffer's glock's AIL. + * + */ + +void +gfs_dunpin(struct gfs_sbd *sdp, struct buffer_head *bh, struct gfs_trans *tr) +{ + struct gfs_bufdata *bd = get_v2bd(bh); + + gfs_assert_withdraw(sdp, buffer_uptodate(bh)); + + gfs_lock_buffer(bh); + + if (gfs_assert_warn(sdp, bd->bd_pinned)) { + gfs_unlock_buffer(bh); + return; + } + + /* No other (later) transaction is modifying buffer; ready to write */ + if (bd->bd_pinned == 1) + mark_buffer_dirty(bh); + + bd->bd_pinned--; + + gfs_unlock_buffer(bh); + + if (tr) { + spin_lock(&sdp->sd_ail_lock); + + if (list_empty(&bd->bd_ail_tr_list)) { + /* Buffer not attached to any earlier transaction. Add + it to glock's AIL, and this trans' AIL (below). */ + list_add(&bd->bd_ail_gl_list, &bd->bd_gl->gl_ail_bufs); + } else { + /* Was part of earlier transaction. + Move from that trans' AIL to this newer one's AIL. + Buf is already on glock's AIL. */ + list_del_init(&bd->bd_ail_tr_list); + brelse(bh); + } + list_add(&bd->bd_ail_tr_list, &tr->tr_ail_bufs); + + spin_unlock(&sdp->sd_ail_lock); + } else + brelse(bh); +} + +/** + * logbh_end_io - Called by OS at the end of a logbh ("fake" bh) write to log + * @bh: the buffer + * @uptodate: whether or not the write succeeded + * + * Interrupt context, no ENTER/RETURN + * + */ + +static void +logbh_end_io(struct buffer_head *bh, int uptodate) +{ + if (uptodate) + set_buffer_uptodate(bh); + else + clear_buffer_uptodate(bh); + unlock_buffer(bh); +} + +/** + * gfs_logbh_init - Initialize a fake buffer head + * @sdp: the filesystem + * @bh: the buffer to initialize + * @blkno: the block address of the buffer + * @data: the data to be written + * + */ + +void +gfs_logbh_init(struct gfs_sbd *sdp, struct buffer_head *bh, + uint64_t blkno, char *data) +{ + memset(bh, 0, sizeof(struct buffer_head)); + bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock); + atomic_set(&bh->b_count, 1); + set_bh_page(bh, virt_to_page(data), ((unsigned long)data) & (PAGE_SIZE - 1)); + bh->b_blocknr = blkno; + bh->b_size = sdp->sd_sb.sb_bsize; + bh->b_bdev = sdp->sd_vfs->s_bdev; + init_buffer(bh, logbh_end_io, NULL); + INIT_LIST_HEAD(&bh->b_assoc_buffers); +} + +/** + * gfs_logbh_uninit - Clean up a fake buffer head + * @sdp: the filesystem + * @bh: the buffer to clean + * + */ + +void +gfs_logbh_uninit(struct gfs_sbd *sdp, struct buffer_head *bh) +{ + gfs_assert_warn(sdp, test_bit(SDF_SHUTDOWN, &sdp->sd_flags) || + !buffer_busy(bh)); + gfs_assert_warn(sdp, atomic_read(&bh->b_count) == 1); +} + +/** + * gfs_logbh_start - Start writing a fake buffer head + * @sdp: the filesystem + * @bh: the buffer to write + * + * This starts a block write to our journal. + */ + +void +gfs_logbh_start(struct gfs_sbd *sdp, struct buffer_head *bh) +{ + submit_bh(WRITE, bh); +} + +/** + * gfs_logbh_wait - Wait for the write of a fake buffer head to complete + * @sdp: the filesystem + * @bh: the buffer to write + * + * This waits for a block write to our journal to complete. + * + * Returns: errno + */ + +int +gfs_logbh_wait(struct gfs_sbd *sdp, struct buffer_head *bh) +{ + wait_on_buffer(bh); + + if (!buffer_uptodate(bh) || buffer_dirty(bh)) { + gfs_io_error_bh(sdp, bh); + return -EIO; + } + if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) + return -EIO; + + return 0; +} + +/** + * gfs_replay_buf - write a log buffer to its inplace location + * @gl: the journal's glock + * @bh: the buffer + * + * Returns: errno + */ + +int +gfs_replay_buf(struct gfs_glock *gl, struct buffer_head *bh) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + struct gfs_bufdata *bd; + + bd = get_v2bd(bh); + if (!bd) { + gfs_attach_bufdata(bh, gl); + bd = get_v2bd(bh); + } + + mark_buffer_dirty(bh); + + if (list_empty(&bd->bd_ail_tr_list)) { + get_bh(bh); + list_add(&bd->bd_ail_tr_list, &sdp->sd_recovery_bufs); + } + + return 0; +} + +/** + * gfs_replay_check - Check up on journal replay + * @sdp: the filesystem + * + */ + +void +gfs_replay_check(struct gfs_sbd *sdp) +{ + struct buffer_head *bh; + struct gfs_bufdata *bd; + + while (!list_empty(&sdp->sd_recovery_bufs)) { + bd = list_entry(sdp->sd_recovery_bufs.prev, + struct gfs_bufdata, bd_ail_tr_list); + bh = bd->bd_bh; + + if (buffer_busy(bh)) { + list_move(&bd->bd_ail_tr_list, + &sdp->sd_recovery_bufs); + break; + } else { + list_del_init(&bd->bd_ail_tr_list); + if (!buffer_uptodate(bh)) + gfs_io_error_bh(sdp, bh); + brelse(bh); + } + } +} + +/** + * gfs_replay_wait - Wait for all replayed buffers to hit the disk + * @sdp: the filesystem + * + */ + +void +gfs_replay_wait(struct gfs_sbd *sdp) +{ + struct list_head *head, *tmp, *prev; + struct buffer_head *bh; + struct gfs_bufdata *bd; + + for (head = &sdp->sd_recovery_bufs, tmp = head->prev, prev = tmp->prev; + tmp != head; + tmp = prev, prev = tmp->prev) { + bd = list_entry(tmp, struct gfs_bufdata, bd_ail_tr_list); + bh = bd->bd_bh; + + if (!buffer_busy(bh)) { + list_del_init(&bd->bd_ail_tr_list); + if (!buffer_uptodate(bh)) + gfs_io_error_bh(sdp, bh); + brelse(bh); + continue; + } + + if (buffer_dirty(bh)) { + wait_on_buffer(bh); + ll_rw_block(WRITE, 1, &bh); + } + } + + while (!list_empty(head)) { + bd = list_entry(head->prev, struct gfs_bufdata, bd_ail_tr_list); + bh = bd->bd_bh; + + wait_on_buffer(bh); + + gfs_assert_withdraw(sdp, !buffer_busy(bh)); + + list_del_init(&bd->bd_ail_tr_list); + if (!buffer_uptodate(bh)) + gfs_io_error_bh(sdp, bh); + brelse(bh); + } +} + +/** + * gfs_wipe_buffers - make inode's buffers so they aren't dirty/AILed anymore + * @ip: the inode who owns the buffers + * @rgd: the resource group + * @bstart: the first buffer in the run + * @blen: the number of buffers in the run + * + * Called when de-allocating a contiguous run of meta blocks within an rgrp. + * Make sure all buffers for de-alloc'd blocks are removed from the AIL, if + * they can be. Dirty or pinned blocks are left alone. Add relevant + * meta-headers to meta-header cache, so we don't need to read disk + * if we re-allocate blocks. + */ + +void +gfs_wipe_buffers(struct gfs_inode *ip, struct gfs_rgrpd *rgd, + uint64_t bstart, uint32_t blen) +{ + struct gfs_sbd *sdp = ip->i_sbd; + struct inode *aspace = ip->i_gl->gl_aspace; + struct buffer_head *bh; + struct gfs_bufdata *bd; + int busy; + int add = FALSE; + + while (blen) { + bh = getbuf(sdp, aspace, bstart, NO_CREATE); + if (bh) { + + bd = get_v2bd(bh); + + if (buffer_uptodate(bh)) { + if (bd) { + gfs_lock_buffer(bh); + gfs_mhc_add(rgd, &bh, 1); + busy = bd->bd_pinned || buffer_busy(bh); + gfs_unlock_buffer(bh); + + if (busy) + add = TRUE; + else { + spin_lock(&sdp->sd_ail_lock); + if (!list_empty(&bd->bd_ail_tr_list)) { + list_del_init(&bd->bd_ail_tr_list); + list_del(&bd->bd_ail_gl_list); + brelse(bh); + } + spin_unlock(&sdp->sd_ail_lock); + } + } else { + gfs_assert_withdraw(sdp, !buffer_dirty(bh)); + wait_on_buffer(bh); + gfs_assert_withdraw(sdp, !buffer_busy(bh)); + gfs_mhc_add(rgd, &bh, 1); + } + } else { + gfs_assert_withdraw(sdp, !bd || !bd->bd_pinned); + gfs_assert_withdraw(sdp, !buffer_dirty(bh)); + wait_on_buffer(bh); + gfs_assert_withdraw(sdp, !buffer_busy(bh)); + } + + brelse(bh); + } + + bstart++; + blen--; + } + + if (add) + gfs_depend_add(rgd, ip->i_num.no_formal_ino); +} + +/** + * gfs_sync_meta - sync all the buffers in a filesystem + * @sdp: the filesystem + * + * Flush metadata blocks to on-disk journal, then + * Flush metadata blocks (now in AIL) to on-disk in-place locations + * Periodically keep checking until done (AIL empty) + */ + +void +gfs_sync_meta(struct gfs_sbd *sdp) +{ + gfs_log_flush(sdp); + for (;;) { + gfs_ail_start(sdp, DIO_ALL); + if (gfs_ail_empty(sdp)) + break; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 10); + } +} + +/** + * gfs_flush_meta_cache - get rid of any references on buffers for this inode + * @ip: The GFS inode + * + * This releases buffers that are in the most-recently-used array of + * blocks used for indirect block addressing for this inode. + * Don't confuse this with the meta-HEADER cache (mhc)! + */ + +void +gfs_flush_meta_cache(struct gfs_inode *ip) +{ + struct buffer_head **bh_slot; + unsigned int x; + + spin_lock(&ip->i_spin); + + for (x = 0; x < GFS_MAX_META_HEIGHT; x++) { + bh_slot = &ip->i_cache[x]; + if (*bh_slot) { + brelse(*bh_slot); + *bh_slot = NULL; + } + } + + spin_unlock(&ip->i_spin); +} + +/** + * gfs_get_meta_buffer - Get a metadata buffer + * @ip: The GFS inode + * @height: The level of this buf in the metadata (indir addr) tree (if any) + * @num: The block number (device relative) of the buffer + * @new: Non-zero if we may create a new buffer + * @bhp: the buffer is returned here + * + * Returns: errno + */ + +int +gfs_get_meta_buffer(struct gfs_inode *ip, int height, uint64_t num, int new, + struct buffer_head **bhp) +{ + struct buffer_head *bh, **bh_slot = &ip->i_cache[height]; + int flags = ((new) ? DIO_NEW : 0) | DIO_START | DIO_WAIT; + int error; + + /* Try to use the gfs_inode's MRU metadata tree cache */ + spin_lock(&ip->i_spin); + bh = *bh_slot; + if (bh) { + if (bh->b_blocknr == num) + get_bh(bh); + else + bh = NULL; + } + spin_unlock(&ip->i_spin); + + if (bh) { + error = gfs_dreread(ip->i_sbd, bh, flags); + if (error) { + brelse(bh); + return error; + } + } else { + error = gfs_dread(ip->i_gl, num, flags, &bh); + if (error) + return error; + + spin_lock(&ip->i_spin); + if (*bh_slot != bh) { + if (*bh_slot) + brelse(*bh_slot); + *bh_slot = bh; + get_bh(bh); + } + spin_unlock(&ip->i_spin); + } + + if (new) { + if (gfs_assert_warn(ip->i_sbd, height)) { + brelse(bh); + return -EIO; + } + gfs_trans_add_bh(ip->i_gl, bh); + gfs_metatype_set(bh, GFS_METATYPE_IN, GFS_FORMAT_IN); + gfs_buffer_clear_tail(bh, sizeof(struct gfs_meta_header)); + } else if (gfs_metatype_check(ip->i_sbd, bh, + (height) ? GFS_METATYPE_IN : GFS_METATYPE_DI)) { + brelse(bh); + return -EIO; + } + + *bhp = bh; + + return 0; +} + +/** + * gfs_get_data_buffer - Get a data buffer + * @ip: The GFS inode + * @num: The block number (device relative) of the data block + * @new: Non-zero if this is a new allocation + * @bhp: the buffer is returned here + * + * Returns: errno + */ + +int +gfs_get_data_buffer(struct gfs_inode *ip, uint64_t block, int new, + struct buffer_head **bhp) +{ + struct buffer_head *bh; + int error = 0; + + if (block == ip->i_num.no_addr) { + if (gfs_assert_warn(ip->i_sbd, !new)) + return -EIO; + error = gfs_dread(ip->i_gl, block, DIO_START | DIO_WAIT, &bh); + if (error) + return error; + if (gfs_metatype_check(ip->i_sbd, bh, GFS_METATYPE_DI)) { + brelse(bh); + return -EIO; + } + } else if (gfs_is_jdata(ip)) { + if (new) { + error = gfs_dread(ip->i_gl, block, + DIO_NEW | DIO_START | DIO_WAIT, &bh); + if (error) + return error; + gfs_trans_add_bh(ip->i_gl, bh); + gfs_metatype_set(bh, GFS_METATYPE_JD, GFS_FORMAT_JD); + gfs_buffer_clear_tail(bh, sizeof(struct gfs_meta_header)); + } else { + error = gfs_dread(ip->i_gl, block, + DIO_START | DIO_WAIT, &bh); + if (error) + return error; + if (gfs_metatype_check(ip->i_sbd, bh, GFS_METATYPE_JD)) { + brelse(bh); + return -EIO; + } + } + } else { + if (new) { + bh = gfs_dgetblk(ip->i_gl, block); + gfs_prep_new_buffer(bh); + } else { + error = gfs_dread(ip->i_gl, block, + DIO_START | DIO_WAIT, &bh); + if (error) + return error; + } + } + + *bhp = bh; + + return 0; +} + +/** + * gfs_start_ra - start readahead on an extent of a file + * @gl: the glock the blocks belong to + * @dblock: the starting disk block + * @extlen: the number of blocks in the extent + * + */ + +void +gfs_start_ra(struct gfs_glock *gl, uint64_t dblock, uint32_t extlen) +{ + struct gfs_sbd *sdp = gl->gl_sbd; + struct inode *aspace = gl->gl_aspace; + struct buffer_head *first_bh, *bh; + uint32_t max_ra = gfs_tune_get(sdp, gt_max_readahead) >> sdp->sd_sb.sb_bsize_shift; + int error; + + if (!extlen) + return; + if (!max_ra) + return; + if (extlen > max_ra) + extlen = max_ra; + + first_bh = getbuf(sdp, aspace, dblock, CREATE); + + if (buffer_uptodate(first_bh)) + goto out; + if (!buffer_locked(first_bh)) { + error = gfs_dreread(sdp, first_bh, DIO_START); + if (error) + goto out; + } + + dblock++; + extlen--; + + while (extlen) { + bh = getbuf(sdp, aspace, dblock, CREATE); + + if (!buffer_uptodate(bh) && !buffer_locked(bh)) { + error = gfs_dreread(sdp, bh, DIO_START); + brelse(bh); + if (error) + goto out; + } else + brelse(bh); + + dblock++; + extlen--; + + if (buffer_uptodate(first_bh)) + break; + } + + out: + brelse(first_bh); +} --- linux-2.6.27.orig/ubuntu/gfs/acl.h +++ linux-2.6.27/ubuntu/gfs/acl.h @@ -0,0 +1,34 @@ +#ifndef __ACL_DOT_H__ +#define __ACL_DOT_H__ + +#define GFS_POSIX_ACL_ACCESS "posix_acl_access" +#define GFS_POSIX_ACL_ACCESS_LEN (16) +#define GFS_POSIX_ACL_DEFAULT "posix_acl_default" +#define GFS_POSIX_ACL_DEFAULT_LEN (17) + +#define GFS_ACL_IS_ACCESS(name, len) \ + ((len) == GFS_POSIX_ACL_ACCESS_LEN && \ + !memcmp(GFS_POSIX_ACL_ACCESS, (name), (len))) + +#define GFS_ACL_IS_DEFAULT(name, len) \ + ((len) == GFS_POSIX_ACL_DEFAULT_LEN && \ + !memcmp(GFS_POSIX_ACL_DEFAULT, (name), (len))) + +struct gfs_ea_request; + +int gfs_acl_validate_set(struct gfs_inode *ip, int access, + struct gfs_ea_request *er, + int *remove, mode_t *mode); +int gfs_acl_validate_remove(struct gfs_inode *ip, int access); +int gfs_acl_get(struct gfs_inode *ip, int access, struct posix_acl **acl); +int gfs_check_acl(struct inode *inode, int mask); +int gfs_acl_new_prep(struct gfs_inode *dip, + unsigned int type, mode_t *mode, + void **a_data, void **d_data, + unsigned int *size, + unsigned int *blocks); +int gfs_acl_new_init(struct gfs_inode *dip, struct gfs_inode *ip, + void *a_data, void *d_data, unsigned int size); +int gfs_acl_chmod(struct gfs_inode *ip, struct iattr *attr); + +#endif /* __ACL_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/eattr.h +++ linux-2.6.27/ubuntu/gfs/eattr.h @@ -0,0 +1,97 @@ +#ifndef __EATTR_DOT_H__ +#define __EATTR_DOT_H__ + +#define GFS_EA_REC_LEN(ea) gfs32_to_cpu((ea)->ea_rec_len) +#define GFS_EA_DATA_LEN(ea) gfs32_to_cpu((ea)->ea_data_len) + +#define GFS_EA_SIZE(ea) \ +MAKE_MULT8(sizeof(struct gfs_ea_header) + \ + (ea)->ea_name_len + \ + ((GFS_EA_IS_STUFFED(ea)) ? \ + GFS_EA_DATA_LEN(ea) : \ + (sizeof(uint64_t) * (ea)->ea_num_ptrs))) +#define GFS_EA_STRLEN(ea) \ +((((ea)->ea_type == GFS_EATYPE_USR) ? 5 : 7) + \ + (ea)->ea_name_len + 1) + +#define GFS_EA_IS_STUFFED(ea) (!(ea)->ea_num_ptrs) +#define GFS_EA_IS_LAST(ea) ((ea)->ea_flags & GFS_EAFLAG_LAST) + +#define GFS_EAREQ_SIZE_STUFFED(er) \ +MAKE_MULT8(sizeof(struct gfs_ea_header) + \ + (er)->er_name_len + (er)->er_data_len) +#define GFS_EAREQ_SIZE_UNSTUFFED(sdp, er) \ +MAKE_MULT8(sizeof(struct gfs_ea_header) + \ + (er)->er_name_len + \ + sizeof(uint64_t) * DIV_RU((er)->er_data_len, (sdp)->sd_jbsize)) + +#define GFS_EA2NAME(ea) ((char *)((struct gfs_ea_header *)(ea) + 1)) +#define GFS_EA2DATA(ea) (GFS_EA2NAME(ea) + (ea)->ea_name_len) +#define GFS_EA2DATAPTRS(ea) \ +((uint64_t *)(GFS_EA2NAME(ea) + MAKE_MULT8((ea)->ea_name_len))) +#define GFS_EA2NEXT(ea) \ +((struct gfs_ea_header *)((char *)(ea) + GFS_EA_REC_LEN(ea))) +#define GFS_EA_BH2FIRST(bh) \ +((struct gfs_ea_header *)((bh)->b_data + \ + sizeof(struct gfs_meta_header))) + +struct gfs_ea_request { + char *er_name; + char *er_data; + unsigned int er_name_len; + unsigned int er_data_len; + unsigned int er_type; /* GFS_EATYPE_... */ + int er_flags; + mode_t er_mode; +}; + +struct gfs_ea_location { + struct buffer_head *el_bh; + struct gfs_ea_header *el_ea; + struct gfs_ea_header *el_prev; +}; + +static inline unsigned int +gfs_ea_strlen(struct gfs_ea_header *ea) +{ + switch (ea->ea_type) { + case GFS_EATYPE_USR: + return (5 + (ea->ea_name_len + 1)); + case GFS_EATYPE_SYS: + return (7 + (ea->ea_name_len + 1)); + case GFS_EATYPE_SECURITY: + return (9 + (ea->ea_name_len + 1)); + default: + return (0); + } +} + +int gfs_ea_repack(struct gfs_inode *ip); + +int gfs_ea_get_i(struct gfs_inode *ip, struct gfs_ea_request *er); +int gfs_ea_set_i(struct gfs_inode *ip, struct gfs_ea_request *er); +int gfs_ea_remove_i(struct gfs_inode *ip, struct gfs_ea_request *er); + +int gfs_ea_list(struct gfs_inode *ip, struct gfs_ea_request *er); +int gfs_ea_get(struct gfs_inode *ip, struct gfs_ea_request *er); +int gfs_ea_set(struct gfs_inode *ip, struct gfs_ea_request *er); +int gfs_ea_remove(struct gfs_inode *ip, struct gfs_ea_request *er); + +int gfs_ea_dealloc(struct gfs_inode *ip); + +int gfs_get_eattr_meta(struct gfs_inode *ip, struct gfs_user_buffer *ub); + +/* Exported to acl.c */ + +int gfs_ea_check_size(struct gfs_sbd *sdp, struct gfs_ea_request *er); +int gfs_ea_find(struct gfs_inode *ip, + struct gfs_ea_request *er, + struct gfs_ea_location *el); +int gfs_ea_get_copy(struct gfs_inode *ip, + struct gfs_ea_location *el, + char *data); +int gfs_ea_acl_init(struct gfs_inode *ip, struct gfs_ea_request *er); +int gfs_ea_acl_chmod(struct gfs_inode *ip, struct gfs_ea_location *el, + struct iattr *attr, char *data); + +#endif /* __EATTR_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/eaops.c +++ linux-2.6.27/ubuntu/gfs/eaops.c @@ -0,0 +1,173 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "acl.h" +#include "eaops.h" +#include "eattr.h" + +/** + * gfs_ea_name2type - get the type of the ea, and trucate the type from the name + * @namep: ea name, possibly with type appended + * + * Returns: GFS_EATYPE_XXX + */ + +unsigned int +gfs_ea_name2type(const char *name, char **truncated_name) +{ + unsigned int type; + + if (strncmp(name, "system.", 7) == 0) { + type = GFS_EATYPE_SYS; + if (truncated_name) + *truncated_name = strchr(name, '.') + 1; + } else if (strncmp(name, "user.", 5) == 0) { + type = GFS_EATYPE_USR; + if (truncated_name) + *truncated_name = strchr(name, '.') + 1; + } else if (strncmp(name, "security.", 9) == 0) { + type = GFS_EATYPE_SECURITY; + if (truncated_name) + *truncated_name = strchr(name, '.') + 1; + } else { + type = GFS_EATYPE_UNUSED; + if (truncated_name) + *truncated_name = NULL; + } + + return type; +} + +/** + * system_eo_get - + * @ip: + * @er: + * + * Returns: errno + */ + +static int +system_eo_get(struct gfs_inode *ip, struct gfs_ea_request *er) +{ + if (!GFS_ACL_IS_ACCESS(er->er_name, er->er_name_len) && + !GFS_ACL_IS_DEFAULT(er->er_name, er->er_name_len) && + !capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (ip->i_sbd->sd_args.ar_posix_acls == FALSE && + (GFS_ACL_IS_ACCESS(er->er_name, er->er_name_len) || + GFS_ACL_IS_DEFAULT(er->er_name, er->er_name_len))) + return -EOPNOTSUPP; + + return gfs_ea_get_i(ip, er); +} + +/** + * system_eo_set - + * @ip: + * @er: + * + * Returns: errno + */ + +static int +system_eo_set(struct gfs_inode *ip, struct gfs_ea_request *er) +{ + int remove = FALSE; + int error; + + if (GFS_ACL_IS_ACCESS(er->er_name, er->er_name_len)) { + er->er_mode = ip->i_vnode->i_mode; + error = gfs_acl_validate_set(ip, TRUE, er, + &remove, &er->er_mode); + if (error) + return error; + error = gfs_ea_set_i(ip, er); + if (error) + return error; + if (remove) + gfs_ea_remove_i(ip, er); + return 0; + + } else if (GFS_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) { + int error = gfs_acl_validate_set(ip, FALSE, er, + &remove, NULL); + if (error) + return error; + if (!remove) + error = gfs_ea_set_i(ip, er); + else { + error = gfs_ea_remove_i(ip, er); + if (error == -ENODATA) + error = 0; + } + return error; + } + + return -EPERM; +} + +/** + * system_eo_remove - + * @ip: + * @er: + * + * Returns: errno + */ + +static int +system_eo_remove(struct gfs_inode *ip, struct gfs_ea_request *er) +{ + if (GFS_ACL_IS_ACCESS(er->er_name, er->er_name_len)) { + int error = gfs_acl_validate_remove(ip, TRUE); + if (error) + return error; + + } else if (GFS_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) { + int error = gfs_acl_validate_remove(ip, FALSE); + if (error) + return error; + + } else + return -EPERM; + + return gfs_ea_remove_i(ip, er); +} + +struct gfs_eattr_operations gfs_user_eaops = { + .eo_get = gfs_ea_get_i, + .eo_set = gfs_ea_set_i, + .eo_remove = gfs_ea_remove_i, + .eo_name = "user", +}; + +struct gfs_eattr_operations gfs_system_eaops = { + .eo_get = system_eo_get, + .eo_set = system_eo_set, + .eo_remove = system_eo_remove, + .eo_name = "system", +}; + +struct gfs_eattr_operations gfs_security_eaops = { + .eo_get = gfs_ea_get_i, + .eo_set = gfs_ea_set_i, + .eo_remove = gfs_ea_remove_i, + .eo_name = "security", +}; + +struct gfs_eattr_operations *gfs_ea_ops[] = { + NULL, + &gfs_user_eaops, + &gfs_system_eaops, + &gfs_security_eaops, +}; + --- linux-2.6.27.orig/ubuntu/gfs/gfs_ondisk.h +++ linux-2.6.27/ubuntu/gfs/gfs_ondisk.h @@ -0,0 +1,1904 @@ +/* + * On-disk structures. + * + * THE BIG PICTURE of on-disk layout: + * + * GFS filesystem code views the entire filesystem, including journals, as + * one contiguous group of blocks on one (perhaps virtual) storage device. + * The filesystem space is shared, not distributed; each node in the cluster + * must see the entire filesystem space. + * + * If the filesystem is spread across multiple physical storage devices, + * volume management (device mapping) must be used to present the fileystem + * space to GFS as one (virtual) device, with contiguous blocks. + * + * The superblock contains basic information about the filesytem, and appears + * at a location 64 KBytes into the filesystem. The first 64 KBytes of the + * filesystem are empty, providing a safety buffer against wayward volume + * management software (that sometimes write data into the first few bytes of + * a device) or administrators. + * + * After the superblock, the rest of the filesystem is divided into multiple + * Resource Groups and several journals. + * + * The Resource Groups (RGs or rgrps) contain the allocatable blocks that are + * used for storing files, directories, etc., and all of the associated + * metadata. Each RG has its own set of block allocation statistics (within + * the RG header), a number of blocks containing the block allocation bitmap, + * and a large number of allocatable blocks for file data and metadata. + * Multiple RGs allow multiple nodes to simultaneously allocate blocks from the + * filesystem (using different RGs), enhancing parallel access. RG size and + * number of RGs are determined by gfs_mkfs when creating the filesystem. + * An administrator can specify RG size (see man gfs_mkfs). + * + * The journals contain temporary copies of metadata blocks, along with + * other data, that allow GFS to recover the filesystem to a consistent state + * (at least as far as metadata is concerned) if a node fails in the midst + * of performing a write transaction. There must be one journal for each node + * in the cluster. Since access to the entire filesystem space is shared, + * if a node crashes, another node will be able to read the crashed node's + * journal, and perform recovery. + * + * Currently, gfs_mkfs places the journals right in the middle of a freshly + * created filesystem space, between 2 large groups of RGs. From a filesystem + * layout perspective, this placement is not a requirement; the journals + * could be placed anywhere within the filesystem space. + * + * New Resource Groups and Journals may be added to the filesystem after the + * filesystem has been created, if the filesystem's (virtual) device is made + * larger. See man gfs_grow and gfs_jadd. + * + * A few special hidden inodes are contained in a GFS filesystem. They do + * not appear in any directories; instead, the superblock points to them + * using block numbers for their location. The special inodes are: + * + * Root inode: Root directory of the filesystem + * Resource Group Index: A file containing block numbers and sizes of all RGs + * Journal Index: A file containing block numbers and sizes of all journals + * Quota: A file containing all quota information for the filesystem + * License: A file containing license information + * + * Note that there is NOTHING RELATED TO INTER-NODE LOCK MANAGEMENT ON-DISK. + * Locking is handled completely off-disk, typically via LAN. + * + * NOTE: + * If you add 8 byte fields to these structures, they must be 8 byte + * aligned. 4 byte field must be 4 byte aligned, etc... + * + * All structures must be a multiple of 8 bytes long. + * + * GRIPES: + * We should have forgetten about supporting 512B FS block sizes + * and made the di_reserved field in the struct gfs_dinode structure + * much bigger. + * + * de_rec_len in struct gfs_dirent should really have been a 32-bit value + * as it now limits us to a 64k FS block size (with the current code + * in dir.c). + */ + +#ifndef __GFS_ONDISK_DOT_H__ +#define __GFS_ONDISK_DOT_H__ + +#define GFS_MAGIC (0x01161970) /* for all on-disk headers */ +#define GFS_BASIC_BLOCK (512) /* "basic block" = "sector" = 512B */ +#define GFS_BASIC_BLOCK_SHIFT (9) + +/* Controls how much data can be logged in-core before dumping log to disk */ + +#define GFS_DUMPS_PER_LOG (4) /* 1/4 of on-disk journal size*/ + +/* Lock numbers of the LM_TYPE_NONDISK type. These protect certain + * cluster-wide operations (rather than on-disk entities). + * Currently, the LIVE lock is not used for any real purpose. */ + +#define GFS_MOUNT_LOCK (0) /* only one node can Mount at a time */ +#define GFS_LIVE_LOCK (1) /* shared by all mounted nodes */ +#define GFS_TRANS_LOCK (2) /* Transaction, protects jrnl recovery */ +#define GFS_RENAME_LOCK (3) /* only one node can Rename at a time */ + +/* On-disk format (version) numbers for various metadata types, + * used in gfs_meta_header */ + +#define GFS_FORMAT_SB (100) /* Super-Block */ +#define GFS_FORMAT_RG (200) /* Resource Group Header */ +#define GFS_FORMAT_RB (300) /* Resource Group Block Alloc BitBlock */ +#define GFS_FORMAT_DI (400) /* "Disk" inode (dinode) */ +#define GFS_FORMAT_IN (500) /* Indirect dinode block list */ +#define GFS_FORMAT_LF (600) /* Leaf dinode block list */ +#define GFS_FORMAT_JD (700) /* Journal Data */ +#define GFS_FORMAT_LH (800) /* Log Header */ +#define GFS_FORMAT_LD (900) /* Log Descriptor */ +/* These don't have actual struct gfs_meta_header structures to go with them */ +#define GFS_FORMAT_JI (1000) /* Journal Index */ +#define GFS_FORMAT_RI (1100) /* Resource Group Index */ +#define GFS_FORMAT_DE (1200) /* Directory Entry */ +#define GFS_FORMAT_QU (1500) /* Quota */ +#define GFS_FORMAT_EA (1600) /* Extended Attribute */ +#define GFS_FORMAT_ED (1700) /* Extended Attribute data */ +/* These version #s are embedded in the superblock */ +#define GFS_FORMAT_FS (1309) /* Filesystem (all-encompassing) */ +#define GFS_FORMAT_MULTI (1401) /* Multi-Host */ + +/* + * An on-disk inode number + * Initially, the on-disk block address of the inode block is assigned as the + * formal (permanent) ID as well. Block address can change (to move inode + * on-disk), but formal ID must stay unchanged once assigned. + */ + +#define gfs_inum_equal(ino1, ino2) \ +(((ino1)->no_formal_ino == (ino2)->no_formal_ino) && \ + ((ino1)->no_addr == (ino2)->no_addr)) + +struct gfs_inum { + uint64_t no_formal_ino; /* inode identifier */ + uint64_t no_addr; /* block # of dinode block */ +}; + +/* + * Generic metadata head structure + * + * Every inplace buffer logged in the journal must start + * with a struct gfs_meta_header. + * + * In addition to telling what kind of metadata is in the block, + * the metaheader contains the important generation and incarnation + * numbers. + * + * The generation number is used during journal recovery to determine + * whether an in-place block on-disk is older than an on-disk journaled copy + * of the block. If so, GFS overwrites the in-place block with the journaled + * version of the block. + * + * A meta block's generation number must increment monotonically across the + * cluster, each time new contents are committed to the block. This means + * that whenever GFS allocates a pre-existing metadata block, GFS must read + * that block from disk (in case another node has incremented it). It also + * means that GFS must sync the block (with incremented generation number) + * to disk (both log and in-place blocks), not only after changing contents + * of the block, but also after de-allocating the block (GFS can't just throw + * away incore metadata for a file that it's just erased). + * + * The incarnation number is used only for on-disk (d)inodes. GFS increments + * it each time it de-allocates a dinode block (i.e. each time the dinode + * loses its identity with a particular file, directory, etc.). When the + * dinode is later allocated (i.e. to be identified with a new file, etc.), + * GFS copies the incarnation number into the VFS inode's i_generation member. + * If GFS is used as the backing store for an NFS server, GFS uses this + * i_generation number as part of the NFS filehandle, which differentiates + * it from the previous identity of the dinode, and helps protect against + * filesystem corruption that could happen with the use of outdated, + * invalid, or malicious filehandles. See ops_export.c. + * + * GFS caches de-allocated meta-headers, to minimize disk reads. + * See struct gfs_meta_header_cache. + */ + +#define GFS_METATYPE_NONE (0) +#define GFS_METATYPE_SB (1) /* Super-Block */ +#define GFS_METATYPE_RG (2) /* Resource Group Header */ +#define GFS_METATYPE_RB (3) /* Resource Group Block Alloc BitBlock */ +#define GFS_METATYPE_DI (4) /* "Disk" inode (dinode) */ +#define GFS_METATYPE_IN (5) /* Indirect dinode block list */ +#define GFS_METATYPE_LF (6) /* Leaf dinode block list */ +#define GFS_METATYPE_JD (7) /* Journal Data */ +#define GFS_METATYPE_LH (8) /* Log Header (gfs_log_header) */ +#define GFS_METATYPE_LD (9) /* Log Descriptor (gfs_log_descriptor) */ +#define GFS_METATYPE_EA (10) /* Extended Attribute */ +#define GFS_METATYPE_ED (11) /* Extended Attribute data */ + +#define GFS_META_CLUMP (64) /* # blocks to convert fm data to meta */ + +struct gfs_meta_header { + uint32_t mh_magic; /* GFS_MAGIC sanity check magic number */ + uint32_t mh_type; /* GFS_METATYPE_XX type of metadata block */ + uint64_t mh_generation; /* increment before writing to journal */ + uint32_t mh_format; /* GFS_FORMAT_XX (version # for this type) */ + uint32_t mh_incarn; /* increment when marking dinode "unused" */ +}; + +/* + * super-block structure + * + * One of these is at beginning of filesystem. + * It's probably good if SIZEOF_SB <= GFS_BASIC_BLOCK (512 bytes) + */ + +/* Address of SuperBlock in GFS basic blocks. 1st 64K of filesystem is empty + for safety against getting clobbered by wayward volume managers, etc. + 64k was chosen because it's the largest GFS-supported fs block size. */ +#define GFS_SB_ADDR (128) + +/* The lock number for the superblock (must be zero) */ +#define GFS_SB_LOCK (0) +#define GFS_CRAP_LOCK (1) + +/* Requirement: GFS_LOCKNAME_LEN % 8 == 0 + Includes: the fencing zero at the end */ +#define GFS_LOCKNAME_LEN (64) + +struct gfs_sb { + /* Order is important; need to be able to read old superblocks + in order to support on-disk version upgrades */ + struct gfs_meta_header sb_header; + + uint32_t sb_fs_format; /* GFS_FORMAT_FS (on-disk version) */ + uint32_t sb_multihost_format; /* GFS_FORMAT_MULTI */ + uint32_t sb_flags; /* ?? */ + + uint32_t sb_bsize; /* fundamental FS block size in bytes */ + uint32_t sb_bsize_shift; /* log2(sb_bsize) */ + uint32_t sb_seg_size; /* Journal segment size in FS blocks */ + + /* These special inodes do not appear in any on-disk directory. */ + struct gfs_inum sb_jindex_di; /* journal index inode */ + struct gfs_inum sb_rindex_di; /* resource group index inode */ + struct gfs_inum sb_root_di; /* root directory inode */ + + /* Default inter-node locking protocol (lock module) and namespace */ + char sb_lockproto[GFS_LOCKNAME_LEN]; /* lock protocol name */ + char sb_locktable[GFS_LOCKNAME_LEN]; /* unique name for this FS */ + + /* More special inodes */ + struct gfs_inum sb_quota_di; /* quota inode */ + struct gfs_inum sb_license_di; /* license inode */ + + char sb_reserved[96]; +}; + +/* + * journal index structure + * + * One for each journal used by the filesystem. + * These descriptors are packed contiguously within the jindex inode (file). + */ + +struct gfs_jindex { + uint64_t ji_addr; /* starting block of the journal */ + uint32_t ji_nsegment; /* number (quantity) of segments in journal */ + uint32_t ji_pad; + + char ji_reserved[64]; +}; + +/* + * resource index structure + * + * One of these for each resource group in the filesystem. + * These descriptors are packed contiguously within the rindex inode (file). + * Also see struct gfs_rgrp. + */ + +struct gfs_rindex { + uint64_t ri_addr; /* block # of 1st block (header) in rgrp */ + uint32_t ri_length; /* # fs blocks containing rgrp header & bitmap */ + uint32_t ri_pad; + + uint64_t ri_data1; /* block # of first data/meta block in rgrp */ + uint32_t ri_data; /* number (qty) of data/meta blocks in rgrp */ + + uint32_t ri_bitbytes; /* total # bytes used by block alloc bitmap */ + + char ri_reserved[64]; +}; + +/* + * resource group header structure + * + * One of these at beginning of the first block of an rgrp, + * followed by block alloc bitmap data in remainder of first block. + * Each resource group contains: + * Header block, including block allocation statistics (struct gfs_rgrp) + * and first part of block alloc bitmap. + * Bitmap block(s), continuing block alloc bitmap started in header block. + * Data/meta blocks, allocatable blocks containing file data and metadata. + * + * In older versions, now-unused (but previously allocated) dinodes were + * saved for re-use in an on-disk linked list (chain). This is no longer + * done, but support still exists for reclaiming dinodes from this list, + * to support upgrades from older on-disk formats. + */ + +/* Each data block within rgrp is represented by 2 bits in the alloc bitmap */ +#define GFS_NBBY (4) /* # blocks represented by 1 bitmap byte */ +#define GFS_BIT_SIZE (2) +#define GFS_BIT_MASK (0x00000003) + +/* + * 4 possible block allocation states: + * bit 0 = alloc(1)/free(0) + * bit 1 = metadata(1)/data(0) + */ +#define GFS_BLKST_FREE (0) +#define GFS_BLKST_USED (1) +#define GFS_BLKST_FREEMETA (2) +#define GFS_BLKST_USEDMETA (3) + +struct gfs_rgrp { + struct gfs_meta_header rg_header; + + uint32_t rg_flags; /* ?? */ + + uint32_t rg_free; /* Number (qty) of free data blocks */ + + /* Dinodes are USEDMETA, but are handled separately from other METAs */ + uint32_t rg_useddi; /* Number (qty) of dinodes (used or free) */ + uint32_t rg_freedi; /* Number (qty) of unused (free) dinodes */ + struct gfs_inum rg_freedi_list; /* 1st block in chain of free dinodes */ + + /* These META statistics do not include dinodes (used or free) */ + uint32_t rg_usedmeta; /* Number (qty) of used metadata blocks */ + uint32_t rg_freemeta; /* Number (qty) of unused metadata blocks */ + + char rg_reserved[64]; +}; + +/* + * quota structure + */ + +struct gfs_quota { + uint64_t qu_limit; + uint64_t qu_warn; + int64_t qu_value; + + char qu_reserved[64]; +}; + +/* + * dinode (disk inode) structure + * The ondisk representation of inodes + * One for each file, directory, etc. + * GFS does not put more than one inode in a single block. + * The inode may be "stuffed", carrying file data along with metadata, + * if the file data is small enough. + * Otherwise, the inode block contains pointers to other blocks that contain + * either file data or other pointers to other blocks (indirect addressing + * via a metadata tree). + */ + +#define GFS_MAX_META_HEIGHT (10) +#define GFS_DIR_MAX_DEPTH (17) + +/* Dinode types */ +#define GFS_FILE_NON (0) +#define GFS_FILE_REG (1) /* regular file */ +#define GFS_FILE_DIR (2) /* directory */ +#define GFS_FILE_LNK (5) /* link */ +#define GFS_FILE_BLK (7) /* block device node */ +#define GFS_FILE_CHR (8) /* character device node */ +#define GFS_FILE_FIFO (101) /* fifo/pipe */ +#define GFS_FILE_SOCK (102) /* socket */ + +/* Dinode flags */ +#define GFS_DIF_JDATA (0x00000001) /* jrnl all data for this file */ +#define GFS_DIF_EXHASH (0x00000002) /* hashed directory (leaves) */ +#define GFS_DIF_UNUSED (0x00000004) /* unused dinode */ +#define GFS_DIF_EA_INDIRECT (0x00000008) /* extended attribute, indirect*/ +#define GFS_DIF_DIRECTIO (0x00000010) +#define GFS_DIF_IMMUTABLE (0x00000020) /* Can't change file */ +#define GFS_DIF_APPENDONLY (0x00000040) /* Can only add to end of file */ +#define GFS_DIF_NOATIME (0x00000080) /* Don't update access time + (currently unused/ignored) */ +#define GFS_DIF_SYNC (0x00000100) /* Flush to disk, don't cache + (currently unused/ignored) */ +#define GFS_DIF_INHERIT_DIRECTIO (0x40000000) /* new files get DIRECTIO flag */ +#define GFS_DIF_INHERIT_JDATA (0x80000000) /* new files get JDATA flag */ + +struct gfs_dinode { + struct gfs_meta_header di_header; + + struct gfs_inum di_num; /* formal inode # and block address */ + + uint32_t di_mode; /* mode of file */ + uint32_t di_uid; /* owner's user id */ + uint32_t di_gid; /* owner's group id */ + uint32_t di_nlink; /* number (qty) of links to this file */ + uint64_t di_size; /* number (qty) of bytes in file */ + uint64_t di_blocks; /* number (qty) of blocks in file */ + int64_t di_atime; /* time last accessed */ + int64_t di_mtime; /* time last modified */ + int64_t di_ctime; /* time last changed */ + + /* Non-zero only for character or block device nodes */ + uint32_t di_major; /* device major number */ + uint32_t di_minor; /* device minor number */ + + /* Block allocation strategy */ + uint64_t di_rgrp; /* dinode rgrp block number */ + uint64_t di_goal_rgrp; /* rgrp to alloc from next */ + uint32_t di_goal_dblk; /* data block goal */ + uint32_t di_goal_mblk; /* metadata block goal */ + + uint32_t di_flags; /* GFS_DIF_... */ + + /* struct gfs_rindex, struct gfs_jindex, or struct gfs_dirent */ + uint32_t di_payload_format; /* GFS_FORMAT_... */ + uint16_t di_type; /* GFS_FILE_... type of file */ + uint16_t di_height; /* height of metadata (0 == stuffed) */ + uint32_t di_incarn; /* incarnation (unused, see gfs_meta_header) */ + uint16_t di_pad; + + /* These only apply to directories */ + uint16_t di_depth; /* Number of bits in the table */ + uint32_t di_entries; /* The # (qty) of entries in the directory */ + + /* This formed an on-disk chain of unused dinodes */ + struct gfs_inum di_next_unused; /* used in old versions only */ + + uint64_t di_eattr; /* extended attribute block number */ + + char di_reserved[56]; +}; + +/* + * indirect block header + * + * A component of a dinode's indirect addressing metadata tree. + * These are pointed to by pointers in dinodes or other indirect blocks. + */ + +struct gfs_indirect { + struct gfs_meta_header in_header; + + char in_reserved[64]; +}; + +/* + * directory structure - many of these per directory file + * + * See comments at beginning of dir.c + */ + +#define GFS_FNAMESIZE (255) +#define GFS_DIRENT_SIZE(name_len) ((sizeof(struct gfs_dirent) + (name_len) + 7) & ~7) +#define IS_LEAF (1) /* Hashed (leaf) directory */ +#define IS_DINODE (2) /* Linear (stuffed dinode block) directory */ + +struct gfs_dirent { + struct gfs_inum de_inum; /* formal inode number and block address */ + uint32_t de_hash; /* hash of the filename */ + uint16_t de_rec_len; /* the length of the dirent */ + uint16_t de_name_len; /* the length of the name */ + uint16_t de_type; /* GFS_FILE_... type of dinode this points to */ + + char de_reserved[14]; +}; + +/* + * Header of leaf directory nodes + * + * See comments at beginning of dir.c + */ + +struct gfs_leaf { + struct gfs_meta_header lf_header; + + uint16_t lf_depth; /* Depth of leaf */ + uint16_t lf_entries; /* Number of dirents in leaf */ + uint32_t lf_dirent_format; /* GFS_FORMAT_DE (version #) */ + uint64_t lf_next; /* Next leaf, if overflow */ + + char lf_reserved[64]; +}; + +/* + * Log header structure + * + * Two of these are in the first block of a transaction log: + * 1) at beginning of block + * 2) at end of first 512-byte sector within block + */ + +#define GFS_LOG_HEAD_UNMOUNT (0x00000001) /* log is clean, can unmount fs */ + +struct gfs_log_header { + struct gfs_meta_header lh_header; + + uint32_t lh_flags; /* GFS_LOG_HEAD_... */ + uint32_t lh_pad; + + uint64_t lh_first; /* Block number of first header in this trans */ + uint64_t lh_sequence; /* Sequence number of this transaction */ + + uint64_t lh_tail; /* Block number of log tail */ + uint64_t lh_last_dump; /* Block number of last dump */ + + char lh_reserved[64]; +}; + +/* + * Log type descriptor + * + * One of these for each chunk in a transaction + */ + +#define GFS_LOG_DESC_METADATA (300) /* metadata */ +/* ld_data1 is the number (quantity) of metadata blocks in the descriptor. + ld_data2 is unused. + */ + +#define GFS_LOG_DESC_IUL (400) /* unlinked inode */ +/* ld_data1 is TRUE if this is a dump. + ld_data2 is unused. + FixMe!!! ld_data1 should be the number (quantity) of entries. + ld_data2 should be "TRUE if this is a dump". + */ + +#define GFS_LOG_DESC_IDA (401) /* de-allocated inode */ +/* ld_data1 is unused. + ld_data2 is unused. + FixMe!!! ld_data1 should be the number (quantity) of entries. + */ + +#define GFS_LOG_DESC_Q (402) /* quota */ +/* ld_data1 is the number of quota changes in the descriptor. + ld_data2 is TRUE if this is a dump. + */ + +#define GFS_LOG_DESC_LAST (500) /* final in a logged transaction */ +/* ld_data1 is unused. + ld_data2 is unused. + */ + +struct gfs_log_descriptor { + struct gfs_meta_header ld_header; + + uint32_t ld_type; /* GFS_LOG_DESC_... Type of this log chunk */ + uint32_t ld_length; /* Number of buffers in this chunk */ + uint32_t ld_data1; /* descriptor-specific field */ + uint32_t ld_data2; /* descriptor-specific field */ + + char ld_reserved[64]; +}; + +/* + * Metadata block tags + * + * One for each logged block. Tells where block really belongs on-disk. + * These descriptor tags are packed contiguously after a gfs_log_descriptor. + */ + +struct gfs_block_tag { + uint64_t bt_blkno; /* inplace block number */ + uint32_t bt_flags; /* ?? */ + uint32_t bt_pad; +}; + +/* + * Quota Journal Tag + */ + +#define GFS_QTF_USER (0x00000001) + +struct gfs_quota_tag { + int64_t qt_change; + uint32_t qt_flags; /* GFS_QTF_... */ + uint32_t qt_id; +}; + +/* + * Extended attribute header format + */ + +#define GFS_EA_MAX_NAME_LEN (255) +#define GFS_EA_MAX_DATA_LEN (65536) + +#define GFS_EATYPE_UNUSED (0) +#define GFS_EATYPE_USR (1) /* user attribute */ +#define GFS_EATYPE_SYS (2) /* system attribute */ +#define GFS_EATYPE_SECURITY (3) /* security attribute */ + +#define GFS_EATYPE_LAST (3) +#define GFS_EATYPE_VALID(x) ((x) <= GFS_EATYPE_LAST) + +#define GFS_EAFLAG_LAST (0x01) /* last ea in block */ + +struct gfs_ea_header { + uint32_t ea_rec_len; /* total record length: hdr + name + data */ + uint32_t ea_data_len; /* data length, in bytes */ + uint8_t ea_name_len; /* no NULL pointer after the string */ + uint8_t ea_type; /* GFS_EATYPE_... */ + uint8_t ea_flags; /* GFS_EAFLAG_... */ + uint8_t ea_num_ptrs; /* # fs blocks needed for EA */ + uint32_t ea_pad; +}; + +/* + * Statfs change + * Describes an change to the pool of free and allocated + * blocks. + */ + +struct gfs_statfs_change { + uint64_t sc_total; + uint64_t sc_free; + uint64_t sc_dinodes; +}; + +struct gfs_statfs_change_host { + int64_t sc_total; + int64_t sc_free; + int64_t sc_dinodes; +}; + +/* Endian functions */ + +#define GFS_ENDIAN_BIG + +#ifdef GFS_ENDIAN_BIG + +#define gfs16_to_cpu be16_to_cpu +#define gfs32_to_cpu be32_to_cpu +#define gfs64_to_cpu be64_to_cpu + +#define cpu_to_gfs16 cpu_to_be16 +#define cpu_to_gfs32 cpu_to_be32 +#define cpu_to_gfs64 cpu_to_be64 + +#else /* GFS_ENDIAN_BIG */ + +#define gfs16_to_cpu le16_to_cpu +#define gfs32_to_cpu le32_to_cpu +#define gfs64_to_cpu le64_to_cpu + +#define cpu_to_gfs16 cpu_to_le16 +#define cpu_to_gfs32 cpu_to_le32 +#define cpu_to_gfs64 cpu_to_le64 + +#endif /* GFS_ENDIAN_BIG */ + +/* Translation functions */ + +void gfs_inum_in(struct gfs_inum *no, char *buf); +void gfs_inum_out(struct gfs_inum *no, char *buf); +void gfs_meta_header_in(struct gfs_meta_header *mh, char *buf); +void gfs_meta_header_out(struct gfs_meta_header *mh, char *buf); +void gfs_sb_in(struct gfs_sb *sb, char *buf); +void gfs_sb_out(struct gfs_sb *sb, char *buf); +void gfs_jindex_in(struct gfs_jindex *jindex, char *buf); +void gfs_jindex_out(struct gfs_jindex *jindex, char *buf); +void gfs_rindex_in(struct gfs_rindex *rindex, char *buf); +void gfs_rindex_out(struct gfs_rindex *rindex, char *buf); +void gfs_rgrp_in(struct gfs_rgrp *rgrp, char *buf); +void gfs_rgrp_out(struct gfs_rgrp *rgrp, char *buf); +void gfs_quota_in(struct gfs_quota *quota, char *buf); +void gfs_quota_out(struct gfs_quota *quota, char *buf); +void gfs_dinode_in(struct gfs_dinode *dinode, char *buf); +void gfs_dinode_out(struct gfs_dinode *dinode, char *buf); +void gfs_indirect_in(struct gfs_indirect *indirect, char *buf); +void gfs_indirect_out(struct gfs_indirect *indirect, char *buf); +void gfs_dirent_in(struct gfs_dirent *dirent, char *buf); +void gfs_dirent_out(struct gfs_dirent *dirent, char *buf); +void gfs_leaf_in(struct gfs_leaf *leaf, char *buf); +void gfs_leaf_out(struct gfs_leaf *leaf, char *buf); +void gfs_log_header_in(struct gfs_log_header *head, char *buf); +void gfs_log_header_out(struct gfs_log_header *head, char *buf); +void gfs_desc_in(struct gfs_log_descriptor *desc, char *buf); +void gfs_desc_out(struct gfs_log_descriptor *desc, char *buf); +void gfs_block_tag_in(struct gfs_block_tag *btag, char *buf); +void gfs_block_tag_out(struct gfs_block_tag *btag, char *buf); +void gfs_quota_tag_in(struct gfs_quota_tag *qtag, char *buf); +void gfs_quota_tag_out(struct gfs_quota_tag *qtag, char *buf); +void gfs_ea_header_in(struct gfs_ea_header *qtag, char *buf); +void gfs_ea_header_out(struct gfs_ea_header *qtag, char *buf); + +/* Printing functions */ + +void gfs_inum_print(struct gfs_inum *no); +void gfs_meta_header_print(struct gfs_meta_header *mh); +void gfs_sb_print(struct gfs_sb *sb); +void gfs_jindex_print(struct gfs_jindex *jindex); +void gfs_rindex_print(struct gfs_rindex *rindex); +void gfs_rgrp_print(struct gfs_rgrp *rgrp); +void gfs_quota_print(struct gfs_quota *quota); +void gfs_dinode_print(struct gfs_dinode *dinode); +void gfs_indirect_print(struct gfs_indirect *indirect); +void gfs_dirent_print(struct gfs_dirent *dirent, char *name); +void gfs_leaf_print(struct gfs_leaf *leaf); +void gfs_log_header_print(struct gfs_log_header *head); +void gfs_desc_print(struct gfs_log_descriptor *desc); +void gfs_block_tag_print(struct gfs_block_tag *tag); +void gfs_quota_tag_print(struct gfs_quota_tag *tag); +void gfs_ea_header_print(struct gfs_ea_header *ea, char *name); + +/* The hash function for ExHash directories */ + +uint32_t gfs_dir_hash(const char *data, int len); + +#endif /* __GFS_ONDISK_DOT_H__ */ + + + +#ifdef WANT_GFS_CONVERSION_FUNCTIONS + +#define CPIN_08(s1, s2, member, count) {memcpy((s1->member), (s2->member), (count));} +#define CPOUT_08(s1, s2, member, count) {memcpy((s2->member), (s1->member), (count));} +#define CPIN_16(s1, s2, member) {(s1->member) = gfs16_to_cpu((s2->member));} +#define CPOUT_16(s1, s2, member) {(s2->member) = cpu_to_gfs16((s1->member));} +#define CPIN_32(s1, s2, member) {(s1->member) = gfs32_to_cpu((s2->member));} +#define CPOUT_32(s1, s2, member) {(s2->member) = cpu_to_gfs32((s1->member));} +#define CPIN_64(s1, s2, member) {(s1->member) = gfs64_to_cpu((s2->member));} +#define CPOUT_64(s1, s2, member) {(s2->member) = cpu_to_gfs64((s1->member));} + +#define pa(struct, member, count) print_array(#member, struct->member, count); + +/** + * print_array - Print out an array of bytes + * @title: what to print before the array + * @buf: the array + * @count: the number of bytes + * + */ + +static void +print_array(char *title, char *buf, int count) +{ + int x; + + printk(" %s =\n", title); + for (x = 0; x < count; x++) { + printk("%.2X ", (unsigned char)buf[x]); + if (x % 16 == 15) + printk("\n"); + } + if (x % 16) + printk("\n"); +} + +/** + * gfs_inum_in - Read in an inode number + * @no: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_inum_in(struct gfs_inum *no, char *buf) +{ + struct gfs_inum *str = (struct gfs_inum *)buf; + + CPIN_64(no, str, no_formal_ino); + CPIN_64(no, str, no_addr); +} + +/** + * gfs_inum_out - Write out an inode number + * @no: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_inum_out(struct gfs_inum *no, char *buf) +{ + struct gfs_inum *str = (struct gfs_inum *)buf; + + CPOUT_64(no, str, no_formal_ino); + CPOUT_64(no, str, no_addr); +} + +/** + * gfs_inum_print - Print out a inode number + * @no: the cpu-order buffer + * + */ + +void +gfs_inum_print(struct gfs_inum *no) +{ + pv(no, no_formal_ino, "%"PRIu64); + pv(no, no_addr, "%"PRIu64); +} + +/** + * gfs_meta_header_in - Read in a metadata header + * @mh: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_meta_header_in(struct gfs_meta_header *mh, char *buf) +{ + struct gfs_meta_header *str = (struct gfs_meta_header *)buf; + + CPIN_32(mh, str, mh_magic); + CPIN_32(mh, str, mh_type); + CPIN_64(mh, str, mh_generation); + CPIN_32(mh, str, mh_format); + CPIN_32(mh, str, mh_incarn); +} + +/** + * gfs_meta_header_in - Write out a metadata header + * @mh: the cpu-order structure + * @buf: the disk-order buffer + * + * Don't ever change the generation number in this routine. + * It's done manually in increment_generation(). + */ + +void +gfs_meta_header_out(struct gfs_meta_header *mh, char *buf) +{ + struct gfs_meta_header *str = (struct gfs_meta_header *)buf; + + CPOUT_32(mh, str, mh_magic); + CPOUT_32(mh, str, mh_type); +#if 0 + /* Don't do this! + Mh_generation should only be change manually. */ + CPOUT_64(mh, str, mh_generation); +#endif + CPOUT_32(mh, str, mh_format); + CPOUT_32(mh, str, mh_incarn); +} + +/** + * gfs_meta_header_print - Print out a metadata header + * @mh: the cpu-order buffer + * + */ + +void +gfs_meta_header_print(struct gfs_meta_header *mh) +{ + pv(mh, mh_magic, "0x%.8X"); + pv(mh, mh_type, "%u"); + pv(mh, mh_generation, "%"PRIu64); + pv(mh, mh_format, "%u"); + pv(mh, mh_incarn, "%u"); +} + +/** + * gfs_sb_in - Read in a superblock + * @sb: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_sb_in(struct gfs_sb *sb, char *buf) +{ + struct gfs_sb *str = (struct gfs_sb *)buf; + + gfs_meta_header_in(&sb->sb_header, buf); + + CPIN_32(sb, str, sb_fs_format); + CPIN_32(sb, str, sb_multihost_format); + CPIN_32(sb, str, sb_flags); + + CPIN_32(sb, str, sb_bsize); + CPIN_32(sb, str, sb_bsize_shift); + CPIN_32(sb, str, sb_seg_size); + + gfs_inum_in(&sb->sb_jindex_di, (char *)&str->sb_jindex_di); + gfs_inum_in(&sb->sb_rindex_di, (char *)&str->sb_rindex_di); + gfs_inum_in(&sb->sb_root_di, (char *)&str->sb_root_di); + + CPIN_08(sb, str, sb_lockproto, GFS_LOCKNAME_LEN); + CPIN_08(sb, str, sb_locktable, GFS_LOCKNAME_LEN); + + gfs_inum_in(&sb->sb_quota_di, (char *)&str->sb_quota_di); + gfs_inum_in(&sb->sb_license_di, (char *)&str->sb_license_di); + + CPIN_08(sb, str, sb_reserved, 96); +} + +/** + * gfs_sb_out - Write out a superblock + * @sb: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_sb_out(struct gfs_sb *sb, char *buf) +{ + struct gfs_sb *str = (struct gfs_sb *)buf; + + gfs_meta_header_out(&sb->sb_header, buf); + + CPOUT_32(sb, str, sb_fs_format); + CPOUT_32(sb, str, sb_multihost_format); + CPOUT_32(sb, str, sb_flags); + + CPOUT_32(sb, str, sb_bsize); + CPOUT_32(sb, str, sb_bsize_shift); + CPOUT_32(sb, str, sb_seg_size); + + gfs_inum_out(&sb->sb_jindex_di, (char *)&str->sb_jindex_di); + gfs_inum_out(&sb->sb_rindex_di, (char *)&str->sb_rindex_di); + gfs_inum_out(&sb->sb_root_di, (char *)&str->sb_root_di); + + CPOUT_08(sb, str, sb_lockproto, GFS_LOCKNAME_LEN); + CPOUT_08(sb, str, sb_locktable, GFS_LOCKNAME_LEN); + + gfs_inum_out(&sb->sb_quota_di, (char *)&str->sb_quota_di); + gfs_inum_out(&sb->sb_license_di, (char *)&str->sb_license_di); + + CPOUT_08(sb, str, sb_reserved, 96); +} + +/** + * gfs_sb_print - Print out a superblock + * @sb: the cpu-order buffer + * + */ + +void +gfs_sb_print(struct gfs_sb *sb) +{ + gfs_meta_header_print(&sb->sb_header); + + pv(sb, sb_fs_format, "%u"); + pv(sb, sb_multihost_format, "%u"); + pv(sb, sb_flags, "%u"); + + pv(sb, sb_bsize, "%u"); + pv(sb, sb_bsize_shift, "%u"); + pv(sb, sb_seg_size, "%u"); + + gfs_inum_print(&sb->sb_jindex_di); + gfs_inum_print(&sb->sb_rindex_di); + gfs_inum_print(&sb->sb_root_di); + + pv(sb, sb_lockproto, "%s"); + pv(sb, sb_locktable, "%s"); + + gfs_inum_print(&sb->sb_quota_di); + gfs_inum_print(&sb->sb_license_di); + + pa(sb, sb_reserved, 96); +} + +/** + * gfs_jindex_in - Read in a journal index structure + * @jindex: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_jindex_in(struct gfs_jindex *jindex, char *buf) +{ + struct gfs_jindex *str = (struct gfs_jindex *)buf; + + CPIN_64(jindex, str, ji_addr); + CPIN_32(jindex, str, ji_nsegment); + CPIN_32(jindex, str, ji_pad); + + CPIN_08(jindex, str, ji_reserved, 64); +} + +/** + * gfs_jindex_out - Write out a journal index structure + * @jindex: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_jindex_out(struct gfs_jindex *jindex, char *buf) +{ + struct gfs_jindex *str = (struct gfs_jindex *)buf; + + CPOUT_64(jindex, str, ji_addr); + CPOUT_32(jindex, str, ji_nsegment); + CPOUT_32(jindex, str, ji_pad); + + CPOUT_08(jindex, str, ji_reserved, 64); +} + +/** + * gfs_jindex_print - Print out a journal index structure + * @ji: the cpu-order buffer + * + */ + +void +gfs_jindex_print(struct gfs_jindex *ji) +{ + pv(ji, ji_addr, "%"PRIu64); + pv(ji, ji_nsegment, "%u"); + pv(ji, ji_pad, "%u"); + + pa(ji, ji_reserved, 64); +} + +/** + * gfs_rindex_in - Read in a resource index structure + * @rindex: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_rindex_in(struct gfs_rindex *rindex, char *buf) +{ + struct gfs_rindex *str = (struct gfs_rindex *)buf; + + CPIN_64(rindex, str, ri_addr); + CPIN_32(rindex, str, ri_length); + CPIN_32(rindex, str, ri_pad); + + CPIN_64(rindex, str, ri_data1); + CPIN_32(rindex, str, ri_data); + + CPIN_32(rindex, str, ri_bitbytes); + + CPIN_08(rindex, str, ri_reserved, 64); +} + +/** + * gfs_rindex_out - Write out a resource index structure + * @rindex: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_rindex_out(struct gfs_rindex *rindex, char *buf) +{ + struct gfs_rindex *str = (struct gfs_rindex *)buf; + + CPOUT_64(rindex, str, ri_addr); + CPOUT_32(rindex, str, ri_length); + CPOUT_32(rindex, str, ri_pad); + + CPOUT_64(rindex, str, ri_data1); + CPOUT_32(rindex, str, ri_data); + + CPOUT_32(rindex, str, ri_bitbytes); + + CPOUT_08(rindex, str, ri_reserved, 64); +} + +/** + * gfs_rindex_print - Print out a resource index structure + * @ri: the cpu-order buffer + * + */ + +void +gfs_rindex_print(struct gfs_rindex *ri) +{ + pv(ri, ri_addr, "%"PRIu64); + pv(ri, ri_length, "%u"); + pv(ri, ri_pad, "%u"); + + pv(ri, ri_data1, "%"PRIu64); + pv(ri, ri_data, "%u"); + + pv(ri, ri_bitbytes, "%u"); + + pa(ri, ri_reserved, 64); +} + +/** + * gfs_rgrp_in - Read in a resource group header + * @rgrp: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_rgrp_in(struct gfs_rgrp *rgrp, char *buf) +{ + struct gfs_rgrp *str = (struct gfs_rgrp *)buf; + + gfs_meta_header_in(&rgrp->rg_header, buf); + + CPIN_32(rgrp, str, rg_flags); + + CPIN_32(rgrp, str, rg_free); + + CPIN_32(rgrp, str, rg_useddi); + CPIN_32(rgrp, str, rg_freedi); + gfs_inum_in(&rgrp->rg_freedi_list, (char *)&str->rg_freedi_list); + + CPIN_32(rgrp, str, rg_usedmeta); + CPIN_32(rgrp, str, rg_freemeta); + + CPIN_08(rgrp, str, rg_reserved, 64); +} + +/** + * gfs_rgrp_out - Write out a resource group header + * @rgrp: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_rgrp_out(struct gfs_rgrp *rgrp, char *buf) +{ + struct gfs_rgrp *str = (struct gfs_rgrp *)buf; + + gfs_meta_header_out(&rgrp->rg_header, buf); + + CPOUT_32(rgrp, str, rg_flags); + + CPOUT_32(rgrp, str, rg_free); + + CPOUT_32(rgrp, str, rg_useddi); + CPOUT_32(rgrp, str, rg_freedi); + gfs_inum_out(&rgrp->rg_freedi_list, (char *)&str->rg_freedi_list); + + CPOUT_32(rgrp, str, rg_usedmeta); + CPOUT_32(rgrp, str, rg_freemeta); + + CPOUT_08(rgrp, str, rg_reserved, 64); +} + +/** + * gfs_rgrp_print - Print out a resource group header + * @rg: the cpu-order buffer + * + */ + +void +gfs_rgrp_print(struct gfs_rgrp *rg) +{ + gfs_meta_header_print(&rg->rg_header); + + pv(rg, rg_flags, "%u"); + + pv(rg, rg_free, "%u"); + + pv(rg, rg_useddi, "%u"); + pv(rg, rg_freedi, "%u"); + gfs_inum_print(&rg->rg_freedi_list); + + pv(rg, rg_usedmeta, "%u"); + pv(rg, rg_freemeta, "%u"); + + pa(rg, rg_reserved, 64); +} + +/** + * gfs_quota_in - Read in a quota structures + * @quota: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_quota_in(struct gfs_quota *quota, char *buf) +{ + struct gfs_quota *str = (struct gfs_quota *)buf; + + CPIN_64(quota, str, qu_limit); + CPIN_64(quota, str, qu_warn); + CPIN_64(quota, str, qu_value); + + CPIN_08(quota, str, qu_reserved, 64); +} + +/** + * gfs_quota_out - Write out a quota structure + * @quota: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_quota_out(struct gfs_quota *quota, char *buf) +{ + struct gfs_quota *str = (struct gfs_quota *)buf; + + CPOUT_64(quota, str, qu_limit); + CPOUT_64(quota, str, qu_warn); + CPOUT_64(quota, str, qu_value); + + CPOUT_08(quota, str, qu_reserved, 64); +} + +/** + * gfs_quota_print - Print out a quota structure + * @quota: the cpu-order buffer + * + */ + +void +gfs_quota_print(struct gfs_quota *quota) +{ + pv(quota, qu_limit, "%"PRIu64); + pv(quota, qu_warn, "%"PRIu64); + pv(quota, qu_value, "%"PRId64); + + pa(quota, qu_reserved, 64); +} + +/** + * gfs_dinode_in - Read in a dinode + * @dinode: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_dinode_in(struct gfs_dinode *dinode, char *buf) +{ + struct gfs_dinode *str = (struct gfs_dinode *)buf; + + gfs_meta_header_in(&dinode->di_header, buf); + + gfs_inum_in(&dinode->di_num, (char *)&str->di_num); + + CPIN_32(dinode, str, di_mode); + CPIN_32(dinode, str, di_uid); + CPIN_32(dinode, str, di_gid); + CPIN_32(dinode, str, di_nlink); + CPIN_64(dinode, str, di_size); + CPIN_64(dinode, str, di_blocks); + CPIN_64(dinode, str, di_atime); + CPIN_64(dinode, str, di_mtime); + CPIN_64(dinode, str, di_ctime); + CPIN_32(dinode, str, di_major); + CPIN_32(dinode, str, di_minor); + + CPIN_64(dinode, str, di_rgrp); + CPIN_64(dinode, str, di_goal_rgrp); + CPIN_32(dinode, str, di_goal_dblk); + CPIN_32(dinode, str, di_goal_mblk); + CPIN_32(dinode, str, di_flags); + CPIN_32(dinode, str, di_payload_format); + CPIN_16(dinode, str, di_type); + CPIN_16(dinode, str, di_height); + CPIN_32(dinode, str, di_incarn); + CPIN_16(dinode, str, di_pad); + + CPIN_16(dinode, str, di_depth); + CPIN_32(dinode, str, di_entries); + + gfs_inum_in(&dinode->di_next_unused, (char *)&str->di_next_unused); + + CPIN_64(dinode, str, di_eattr); + + CPIN_08(dinode, str, di_reserved, 56); +} + +/** + * gfs_dinode_out - Write out a dinode + * @dinode: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_dinode_out(struct gfs_dinode *dinode, char *buf) +{ + struct gfs_dinode *str = (struct gfs_dinode *)buf; + + gfs_meta_header_out(&dinode->di_header, buf); + + gfs_inum_out(&dinode->di_num, (char *)&str->di_num); + + CPOUT_32(dinode, str, di_mode); + CPOUT_32(dinode, str, di_uid); + CPOUT_32(dinode, str, di_gid); + CPOUT_32(dinode, str, di_nlink); + CPOUT_64(dinode, str, di_size); + CPOUT_64(dinode, str, di_blocks); + CPOUT_64(dinode, str, di_atime); + CPOUT_64(dinode, str, di_mtime); + CPOUT_64(dinode, str, di_ctime); + CPOUT_32(dinode, str, di_major); + CPOUT_32(dinode, str, di_minor); + + CPOUT_64(dinode, str, di_rgrp); + CPOUT_64(dinode, str, di_goal_rgrp); + CPOUT_32(dinode, str, di_goal_dblk); + CPOUT_32(dinode, str, di_goal_mblk); + CPOUT_32(dinode, str, di_flags); + CPOUT_32(dinode, str, di_payload_format); + CPOUT_16(dinode, str, di_type); + CPOUT_16(dinode, str, di_height); + CPOUT_32(dinode, str, di_incarn); + CPOUT_16(dinode, str, di_pad); + + CPOUT_16(dinode, str, di_depth); + CPOUT_32(dinode, str, di_entries); + + gfs_inum_out(&dinode->di_next_unused, (char *)&str->di_next_unused); + + CPOUT_64(dinode, str, di_eattr); + + CPOUT_08(dinode, str, di_reserved, 56); +} + +/** + * gfs_dinode_print - Print out a dinode + * @di: the cpu-order buffer + * + */ + +void +gfs_dinode_print(struct gfs_dinode *di) +{ + gfs_meta_header_print(&di->di_header); + + gfs_inum_print(&di->di_num); + + pv(di, di_mode, "0%o"); + pv(di, di_uid, "%u"); + pv(di, di_gid, "%u"); + pv(di, di_nlink, "%u"); + pv(di, di_size, "%"PRIu64); + pv(di, di_blocks, "%"PRIu64); + pv(di, di_atime, "%"PRId64); + pv(di, di_mtime, "%"PRId64); + pv(di, di_ctime, "%"PRId64); + pv(di, di_major, "%u"); + pv(di, di_minor, "%u"); + + pv(di, di_rgrp, "%"PRIu64); + pv(di, di_goal_rgrp, "%"PRIu64); + pv(di, di_goal_dblk, "%u"); + pv(di, di_goal_mblk, "%u"); + pv(di, di_flags, "0x%.8X"); + pv(di, di_payload_format, "%u"); + pv(di, di_type, "%u"); + pv(di, di_height, "%u"); + pv(di, di_incarn, "%u"); + pv(di, di_pad, "%u"); + + pv(di, di_depth, "%u"); + pv(di, di_entries, "%u"); + + gfs_inum_print(&di->di_next_unused); + + pv(di, di_eattr, "%"PRIu64); + + pa(di, di_reserved, 56); +} + +/** + * gfs_indirect_in - copy in the header of an indirect block + * @indirect: the in memory copy + * @buf: the buffer copy + * + */ + +void +gfs_indirect_in(struct gfs_indirect *indirect, char *buf) +{ + struct gfs_indirect *str = (struct gfs_indirect *)buf; + + gfs_meta_header_in(&indirect->in_header, buf); + + CPIN_08(indirect, str, in_reserved, 64); +} + +/** + * gfs_indirect_out - copy out the header of an indirect block + * @indirect: the in memory copy + * @buf: the buffer copy + * + */ + +void +gfs_indirect_out(struct gfs_indirect *indirect, char *buf) +{ + struct gfs_indirect *str = (struct gfs_indirect *)buf; + + gfs_meta_header_out(&indirect->in_header, buf); + + CPOUT_08(indirect, str, in_reserved, 64); +} + +/** + * gfs_indirect_print - Print out a indirect block header + * @indirect: the cpu-order buffer + * + */ + +void +gfs_indirect_print(struct gfs_indirect *indirect) +{ + gfs_meta_header_print(&indirect->in_header); + + pa(indirect, in_reserved, 64); +} + +/** + * gfs_dirent_in - Read in a directory entry + * @dirent: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_dirent_in(struct gfs_dirent *dirent, char *buf) +{ + struct gfs_dirent *str = (struct gfs_dirent *)buf; + + gfs_inum_in(&dirent->de_inum, (char *)&str->de_inum); + CPIN_32(dirent, str, de_hash); + CPIN_16(dirent, str, de_rec_len); + CPIN_16(dirent, str, de_name_len); + CPIN_16(dirent, str, de_type); + + CPIN_08(dirent, str, de_reserved, 14); +} + +/** + * gfs_dirent_out - Write out a directory entry + * @dirent: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_dirent_out(struct gfs_dirent *dirent, char *buf) +{ + struct gfs_dirent *str = (struct gfs_dirent *)buf; + + gfs_inum_out(&dirent->de_inum, (char *)&str->de_inum); + CPOUT_32(dirent, str, de_hash); + CPOUT_16(dirent, str, de_rec_len); + CPOUT_16(dirent, str, de_name_len); + CPOUT_16(dirent, str, de_type); + + CPOUT_08(dirent, str, de_reserved, 14); +} + +/** + * gfs_dirent_print - Print out a directory entry + * @de: the cpu-order buffer + * @name: the filename + * + */ + +void +gfs_dirent_print(struct gfs_dirent *de, char *name) +{ + char buf[GFS_FNAMESIZE + 1]; + + gfs_inum_print(&de->de_inum); + pv(de, de_hash, "0x%.8X"); + pv(de, de_rec_len, "%u"); + pv(de, de_name_len, "%u"); + pv(de, de_type, "%u"); + + pa(de, de_reserved, 14); + + memset(buf, 0, GFS_FNAMESIZE + 1); + memcpy(buf, name, de->de_name_len); + printk(" name = %s\n", buf); +} + +/** + * gfs_leaf_in - Read in a directory leaf header + * @leaf: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_leaf_in(struct gfs_leaf *leaf, char *buf) +{ + struct gfs_leaf *str = (struct gfs_leaf *)buf; + + gfs_meta_header_in(&leaf->lf_header, buf); + + CPIN_16(leaf, str, lf_depth); + CPIN_16(leaf, str, lf_entries); + CPIN_32(leaf, str, lf_dirent_format); + CPIN_64(leaf, str, lf_next); + + CPIN_08(leaf, str, lf_reserved, 64); +} + +/** + * gfs_leaf_out - Write out a directory leaf header + * @leaf: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_leaf_out(struct gfs_leaf *leaf, char *buf) +{ + struct gfs_leaf *str = (struct gfs_leaf *)buf; + + gfs_meta_header_out(&leaf->lf_header, buf); + + CPOUT_16(leaf, str, lf_depth); + CPOUT_16(leaf, str, lf_entries); + CPOUT_32(leaf, str, lf_dirent_format); + CPOUT_64(leaf, str, lf_next); + + CPOUT_08(leaf, str, lf_reserved, 64); +} + +/** + * gfs_leaf_print - Print out a directory leaf header + * @lf: the cpu-order buffer + * + */ + +void +gfs_leaf_print(struct gfs_leaf *lf) +{ + gfs_meta_header_print(&lf->lf_header); + + pv(lf, lf_depth, "%u"); + pv(lf, lf_entries, "%u"); + pv(lf, lf_dirent_format, "%u"); + pv(lf, lf_next, "%"PRIu64); + + pa(lf, lf_reserved, 64); +} + +/** + * gfs_log_header_in - Read in a log header + * @head: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_log_header_in(struct gfs_log_header *head, char *buf) +{ + struct gfs_log_header *str = (struct gfs_log_header *)buf; + + gfs_meta_header_in(&head->lh_header, buf); + + CPIN_32(head, str, lh_flags); + CPIN_32(head, str, lh_pad); + + CPIN_64(head, str, lh_first); + CPIN_64(head, str, lh_sequence); + + CPIN_64(head, str, lh_tail); + CPIN_64(head, str, lh_last_dump); + + CPIN_08(head, str, lh_reserved, 64); +} + +/** + * gfs_log_header_out - Write out a log header + * @head: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_log_header_out(struct gfs_log_header *head, char *buf) +{ + struct gfs_log_header *str = (struct gfs_log_header *)buf; + + gfs_meta_header_out(&head->lh_header, buf); + + CPOUT_32(head, str, lh_flags); + CPOUT_32(head, str, lh_pad); + + CPOUT_64(head, str, lh_first); + CPOUT_64(head, str, lh_sequence); + + CPOUT_64(head, str, lh_tail); + CPOUT_64(head, str, lh_last_dump); + + CPOUT_08(head, str, lh_reserved, 64); +} + +/** + * gfs_log_header_print - Print out a log header + * @head: the cpu-order buffer + * + */ + +void +gfs_log_header_print(struct gfs_log_header *lh) +{ + gfs_meta_header_print(&lh->lh_header); + + pv(lh, lh_flags, "0x%.8X"); + pv(lh, lh_pad, "%u"); + + pv(lh, lh_first, "%"PRIu64); + pv(lh, lh_sequence, "%"PRIu64); + + pv(lh, lh_tail, "%"PRIu64); + pv(lh, lh_last_dump, "%"PRIu64); + + pa(lh, lh_reserved, 64); +} + +/** + * gfs_desc_in - Read in a log descriptor + * @desc: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_desc_in(struct gfs_log_descriptor *desc, char *buf) +{ + struct gfs_log_descriptor *str = (struct gfs_log_descriptor *)buf; + + gfs_meta_header_in(&desc->ld_header, buf); + + CPIN_32(desc, str, ld_type); + CPIN_32(desc, str, ld_length); + CPIN_32(desc, str, ld_data1); + CPIN_32(desc, str, ld_data2); + + CPIN_08(desc, str, ld_reserved, 64); +} + +/** + * gfs_desc_out - Write out a log descriptor + * @desc: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_desc_out(struct gfs_log_descriptor *desc, char *buf) +{ + struct gfs_log_descriptor *str = (struct gfs_log_descriptor *)buf; + + gfs_meta_header_out(&desc->ld_header, buf); + + CPOUT_32(desc, str, ld_type); + CPOUT_32(desc, str, ld_length); + CPOUT_32(desc, str, ld_data1); + CPOUT_32(desc, str, ld_data2); + + CPOUT_08(desc, str, ld_reserved, 64); +} + +/** + * gfs_desc_print - Print out a log descriptor + * @ld: the cpu-order buffer + * + */ + +void +gfs_desc_print(struct gfs_log_descriptor *ld) +{ + gfs_meta_header_print(&ld->ld_header); + + pv(ld, ld_type, "%u"); + pv(ld, ld_length, "%u"); + pv(ld, ld_data1, "%u"); + pv(ld, ld_data2, "%u"); + + pa(ld, ld_reserved, 64); +} + +/** + * gfs_block_tag_in - Read in a block tag + * @tag: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_block_tag_in(struct gfs_block_tag *tag, char *buf) +{ + struct gfs_block_tag *str = (struct gfs_block_tag *)buf; + + CPIN_64(tag, str, bt_blkno); + CPIN_32(tag, str, bt_flags); + CPIN_32(tag, str, bt_pad); +} + +/** + * gfs_block_tag_out - Write out a block tag + * @tag: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_block_tag_out(struct gfs_block_tag *tag, char *buf) +{ + struct gfs_block_tag *str = (struct gfs_block_tag *)buf; + + CPOUT_64(tag, str, bt_blkno); + CPOUT_32(tag, str, bt_flags); + CPOUT_32(tag, str, bt_pad); +} + +/** + * gfs_block_tag_print - Print out a block tag + * @tag: the cpu-order buffer + * + */ + +void +gfs_block_tag_print(struct gfs_block_tag *tag) +{ + pv(tag, bt_blkno, "%"PRIu64); + pv(tag, bt_flags, "%u"); + pv(tag, bt_pad, "%u"); +} + +/** + * gfs_quota_tag_in - Read in a quota tag + * @tag: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_quota_tag_in(struct gfs_quota_tag *tag, char *buf) +{ + struct gfs_quota_tag *str = (struct gfs_quota_tag *)buf; + + CPIN_64(tag, str, qt_change); + CPIN_32(tag, str, qt_flags); + CPIN_32(tag, str, qt_id); +} + +/** + * gfs_quota_tag_out - Write out a quota tag + * @tag: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_quota_tag_out(struct gfs_quota_tag *tag, char *buf) +{ + struct gfs_quota_tag *str = (struct gfs_quota_tag *)buf; + + CPOUT_64(tag, str, qt_change); + CPOUT_32(tag, str, qt_flags); + CPOUT_32(tag, str, qt_id); +} + +/** + * gfs_quota_tag_print - Print out a quota tag + * @tag: the cpu-order buffer + * + */ + +void +gfs_quota_tag_print(struct gfs_quota_tag *tag) +{ + pv(tag, qt_change, "%"PRId64); + pv(tag, qt_flags, "0x%.8X"); + pv(tag, qt_id, "%u"); +} + +/** + * gfs_ea_header_in - Read in a Extended Attribute header + * @tag: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_ea_header_in(struct gfs_ea_header *ea, char *buf) +{ + struct gfs_ea_header *str = (struct gfs_ea_header *)buf; + + CPIN_32(ea, str, ea_rec_len); + CPIN_32(ea, str, ea_data_len); + ea->ea_name_len = str->ea_name_len; + ea->ea_type = str->ea_type; + ea->ea_flags = str->ea_flags; + ea->ea_num_ptrs = str->ea_num_ptrs; + CPIN_32(ea, str, ea_pad); +} + +/** + * gfs_ea_header_out - Write out a Extended Attribute header + * @ea: the cpu-order structure + * @buf: the disk-order buffer + * + */ + +void +gfs_ea_header_out(struct gfs_ea_header *ea, char *buf) +{ + struct gfs_ea_header *str = (struct gfs_ea_header *)buf; + + CPOUT_32(ea, str, ea_rec_len); + CPOUT_32(ea, str, ea_data_len); + str->ea_name_len = ea->ea_name_len; + str->ea_type = ea->ea_type; + str->ea_flags = ea->ea_flags; + str->ea_num_ptrs = ea->ea_num_ptrs; + CPOUT_32(ea, str, ea_pad); +} + +/** + * gfs_ea_header_printt - Print out a Extended Attribute header + * @ea: the cpu-order buffer + * + */ + +void +gfs_ea_header_print(struct gfs_ea_header *ea, char *name) +{ + char buf[GFS_EA_MAX_NAME_LEN + 1]; + + pv(ea, ea_rec_len, "%u"); + pv(ea, ea_data_len, "%u"); + pv(ea, ea_name_len, "%u"); + pv(ea, ea_type, "%u"); + pv(ea, ea_flags, "%u"); + pv(ea, ea_num_ptrs, "%u"); + pv(ea, ea_pad, "%u"); + + memset(buf, 0, GFS_EA_MAX_NAME_LEN + 1); + memcpy(buf, name, ea->ea_name_len); + printk(" name = %s\n", buf); +} + +static const uint32_t crc_32_tab[] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +/** + * gfs_dir_hash - hash an array of data + * @data: the data to be hashed + * @len: the length of data to be hashed + * + * Take some data and convert it to a 32-bit hash. + * + * The hash function is a 32-bit CRC of the data. The algorithm uses + * the crc_32_tab table above. + * + * This may not be the fastest hash function, but it does a fair bit better + * at providing uniform results than the others I've looked at. That's + * really important for efficient directories. + * + * Returns: the hash + */ + +uint32_t +gfs_dir_hash(const char *data, int len) +{ + uint32_t hash = 0xFFFFFFFF; + + for (; len--; data++) + hash = crc_32_tab[(hash ^ *data) & 0xFF] ^ (hash >> 8); + + hash = ~hash; + + return hash; +} + +#endif /* WANT_GFS_CONVERSION_FUNCTIONS */ + --- linux-2.6.27.orig/ubuntu/gfs/super.h +++ linux-2.6.27/ubuntu/gfs/super.h @@ -0,0 +1,53 @@ +#ifndef __SUPER_DOT_H__ +#define __SUPER_DOT_H__ + +void gfs_tune_init(struct gfs_tune *gt); + +int gfs_check_sb(struct gfs_sbd *sdp, struct gfs_sb *sb, int silent); +int gfs_read_sb(struct gfs_sbd *sdp, struct gfs_glock *gl, int silent); +int gfs_do_upgrade(struct gfs_sbd *sdp, struct gfs_glock *gl_sb); + +static __inline__ unsigned int +gfs_num_journals(struct gfs_sbd *sdp) +{ + unsigned int num; + down(&sdp->sd_jindex_lock); + num = sdp->sd_journals; + up(&sdp->sd_jindex_lock); + return num; +} + +int gfs_jindex_hold(struct gfs_sbd *sdp, struct gfs_holder *ji_gh); +void gfs_clear_journals(struct gfs_sbd *sdp); + +int gfs_get_jiinode(struct gfs_sbd *sdp); +int gfs_get_riinode(struct gfs_sbd *sdp); +int gfs_get_rootinode(struct gfs_sbd *sdp); +int gfs_get_qinode(struct gfs_sbd *sdp); +int gfs_get_linode(struct gfs_sbd *sdp); + +int gfs_make_fs_rw(struct gfs_sbd *sdp); +int gfs_make_fs_ro(struct gfs_sbd *sdp); + +int gfs_statfs_init(struct gfs_sbd *sdp, int flag); +int gfs_statfs_sync(struct gfs_sbd *sdp); +int gfs_statfs_fast(struct gfs_sbd *sdp, void *buf); + +struct gfs_stat_gfs { + uint64_t sg_total_blocks; + uint64_t sg_free; + uint64_t sg_used_dinode; + uint64_t sg_free_dinode; + uint64_t sg_used_meta; + uint64_t sg_free_meta; +}; + +int gfs_stat_gfs(struct gfs_sbd *sdp, struct gfs_stat_gfs *sg, + int interruptible); + +int gfs_lock_fs_check_clean(struct gfs_sbd *sdp, unsigned int state, + struct gfs_holder *t_gh); +int gfs_freeze_fs(struct gfs_sbd *sdp); +void gfs_unfreeze_fs(struct gfs_sbd *sdp); + +#endif /* __SUPER_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/lock_dlm_mount.c +++ linux-2.6.27/ubuntu/gfs/lock_dlm_mount.c @@ -0,0 +1,279 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License version 2. + */ + +#include "lock_dlm.h" + +const struct lm_lockops gdlm_ops; + + +static struct gdlm_ls *init_gdlm(lm_callback_t cb, struct gfs_sbd *sdp, + int flags, char *table_name) +{ + struct gdlm_ls *ls; + char buf[256], *p; + + ls = kzalloc(sizeof(struct gdlm_ls), GFP_KERNEL); + if (!ls) + return NULL; + + ls->drop_locks_count = GDLM_DROP_COUNT; + ls->drop_locks_period = GDLM_DROP_PERIOD; + ls->fscb = cb; + ls->sdp = sdp; + ls->fsflags = flags; + spin_lock_init(&ls->async_lock); + INIT_LIST_HEAD(&ls->complete); + INIT_LIST_HEAD(&ls->blocking); + INIT_LIST_HEAD(&ls->delayed); + INIT_LIST_HEAD(&ls->submit); + INIT_LIST_HEAD(&ls->all_locks); + init_waitqueue_head(&ls->thread_wait); + init_waitqueue_head(&ls->wait_control); + ls->thread1 = NULL; + ls->thread2 = NULL; + ls->drop_time = jiffies; + ls->jid = -1; + + strncpy(buf, table_name, 256); + buf[255] = '\0'; + + p = strchr(buf, ':'); + if (!p) { + log_info("invalid table_name \"%s\"", table_name); + kfree(ls); + return NULL; + } + *p = '\0'; + p++; + + strncpy(ls->clustername, buf, GDLM_NAME_LEN); + strncpy(ls->fsname, p, GDLM_NAME_LEN); + + return ls; +} + +static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir) +{ + char data[256]; + char *options, *x, *y; + int error = 0; + + memset(data, 0, 256); + strncpy(data, data_arg, 255); + + if (!strlen(data)) { + log_error("no mount options, (u)mount helpers not installed"); + return -EINVAL; + } + + for (options = data; (x = strsep(&options, ":")); ) { + if (!*x) + continue; + + y = strchr(x, '='); + if (y) + *y++ = 0; + + if (!strcmp(x, "jid")) { + if (!y) { + log_error("need argument to jid"); + error = -EINVAL; + break; + } + sscanf(y, "%u", &ls->jid); + + } else if (!strcmp(x, "first")) { + if (!y) { + log_error("need argument to first"); + error = -EINVAL; + break; + } + sscanf(y, "%u", &ls->first); + + } else if (!strcmp(x, "id")) { + if (!y) { + log_error("need argument to id"); + error = -EINVAL; + break; + } + sscanf(y, "%u", &ls->id); + + } else if (!strcmp(x, "nodir")) { + if (!y) { + log_error("need argument to nodir"); + error = -EINVAL; + break; + } + sscanf(y, "%u", nodir); + + } else { + log_error("unkonwn option: %s", x); + error = -EINVAL; + break; + } + } + + return error; +} + +static int gdlm_mount(char *table_name, char *host_data, + lm_callback_t cb, void *cb_data, + unsigned int min_lvb_size, int flags, + struct lm_lockstruct *lockstruct, + struct kobject *fskobj) +{ + struct gdlm_ls *ls; + int error = -ENOMEM, nodir = 0; + + if (min_lvb_size > GDLM_LVB_SIZE) + goto out; + + ls = init_gdlm(cb, cb_data, flags, table_name); + if (!ls) + goto out; + + error = make_args(ls, host_data, &nodir); + if (error) + goto out; + + error = gdlm_init_threads(ls); + if (error) + goto out_free; + + error = gdlm_kobject_setup(ls, fskobj); + if (error) + goto out_thread; + + error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname), + &ls->dlm_lockspace, + DLM_LSFL_FS | (nodir ? DLM_LSFL_NODIR : 0), + GDLM_LVB_SIZE); + if (error) { + log_error("dlm_new_lockspace error %d", error); + goto out_kobj; + } + + lockstruct->ls_jid = ls->jid; + lockstruct->ls_first = ls->first; + lockstruct->ls_lockspace = ls; + lockstruct->ls_ops = &gdlm_ops; + lockstruct->ls_flags = 0; + lockstruct->ls_lvb_size = GDLM_LVB_SIZE; + return 0; + +out_kobj: + gdlm_kobject_release(ls); +out_thread: + gdlm_release_threads(ls); +out_free: + kfree(ls); +out: + return error; +} + +static void gdlm_unmount(void *lockspace) +{ + struct gdlm_ls *ls = lockspace; + int rv; + + log_debug("unmount flags %lx", ls->flags); + + /* FIXME: serialize unmount and withdraw in case they + happen at once. Also, if unmount follows withdraw, + wait for withdraw to finish. */ + + if (test_bit(DFL_WITHDRAW, &ls->flags)) + goto out; + + gdlm_kobject_release(ls); + dlm_release_lockspace(ls->dlm_lockspace, 2); + gdlm_release_threads(ls); + rv = gdlm_release_all_locks(ls); + if (rv) + log_info("gdlm_unmount: %d stray locks freed", rv); +out: + kfree(ls); +} + +static void gdlm_recovery_done(void *lockspace, unsigned int jid, + unsigned int message) +{ + struct gdlm_ls *ls = lockspace; + ls->recover_jid_done = jid; + ls->recover_jid_status = message; + kobject_uevent(&ls->kobj, KOBJ_CHANGE); +} + +static void gdlm_others_may_mount(void *lockspace) +{ + struct gdlm_ls *ls = lockspace; + ls->first_done = 1; + kobject_uevent(&ls->kobj, KOBJ_CHANGE); +} + +/* Userspace gets the offline uevent, blocks new gfs locks on + other mounters, and lets us know (sets WITHDRAW flag). Then, + userspace leaves the mount group while we leave the lockspace. */ + +static void gdlm_withdraw(void *lockspace) +{ + struct gdlm_ls *ls = lockspace; + + kobject_uevent(&ls->kobj, KOBJ_OFFLINE); + + wait_event_interruptible(ls->wait_control, + test_bit(DFL_WITHDRAW, &ls->flags)); + + dlm_release_lockspace(ls->dlm_lockspace, 2); + gdlm_release_threads(ls); + gdlm_release_all_locks(ls); + gdlm_kobject_release(ls); +} + +static int gdlm_plock(void *lockspace, struct lm_lockname *name, + struct file *file, int cmd, struct file_lock *fl) +{ + struct gdlm_ls *ls = lockspace; + return dlm_posix_lock(ls->dlm_lockspace, name->ln_number, file, cmd, fl); +} + +static int gdlm_punlock(void *lockspace, struct lm_lockname *name, + struct file *file, struct file_lock *fl) +{ + struct gdlm_ls *ls = lockspace; + return dlm_posix_unlock(ls->dlm_lockspace, name->ln_number, file, fl); +} + +static int gdlm_plock_get(void *lockspace, struct lm_lockname *name, + struct file *file, struct file_lock *fl) +{ + struct gdlm_ls *ls = lockspace; + return dlm_posix_get(ls->dlm_lockspace, name->ln_number, file, fl); +} + +const struct lm_lockops gdlm_ops = { + .lm_proto_name = "lock_dlm", + .lm_mount = gdlm_mount, + .lm_others_may_mount = gdlm_others_may_mount, + .lm_unmount = gdlm_unmount, + .lm_withdraw = gdlm_withdraw, + .lm_get_lock = gdlm_get_lock, + .lm_put_lock = gdlm_put_lock, + .lm_lock = gdlm_lock, + .lm_unlock = gdlm_unlock, + .lm_plock = gdlm_plock, + .lm_punlock = gdlm_punlock, + .lm_plock_get = gdlm_plock_get, + .lm_cancel = gdlm_cancel, + .lm_hold_lvb = gdlm_hold_lvb, + .lm_unhold_lvb = gdlm_unhold_lvb, + .lm_recovery_done = gdlm_recovery_done, + .lm_owner = THIS_MODULE, +}; + --- linux-2.6.27.orig/ubuntu/gfs/log.c +++ linux-2.6.27/ubuntu/gfs/log.c @@ -0,0 +1,1429 @@ +/* + What rolls down stairs + Alone or in pairs + Rolls over your neighbor's dog. + What's great for a snack + And fits on your back + It's log, log, log! + It's lo-og, lo-og, + It's big, it's heavy, it's wood. + It's lo-og, lo-og, + It's better than bad, it's good. + Everyone wants a log, + You're gonna love it, log + Come on and get your log, + Everyone needs a log... + LOG... FROM BLAMMO! + + -- The Ren and Stimpy Show +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "dio.h" +#include "log.h" +#include "lops.h" + +/** + * gfs_struct2blk - compute stuff + * @sdp: the filesystem + * @nstruct: the number of structures + * @ssize: the size of the structures + * + * Compute the number of log descriptor blocks needed to hold a certain number + * of structures of a certain size. + * + * Returns: the number of blocks needed (minimum is always 1) + */ + +unsigned int +gfs_struct2blk(struct gfs_sbd *sdp, unsigned int nstruct, unsigned int ssize) +{ + unsigned int blks; + unsigned int first, second; + + blks = 1; + first = (sdp->sd_sb.sb_bsize - sizeof(struct gfs_log_descriptor)) / ssize; + + if (nstruct > first) { + second = sdp->sd_sb.sb_bsize / ssize; + blks += DIV_RU(nstruct - first, second); + } + + return blks; +} + +/** + * gfs_blk2seg - Convert number of blocks into number of segments + * @sdp: The GFS superblock + * @blocks: The number of blocks + * + * Returns: The number of journal segments + */ + +unsigned int +gfs_blk2seg(struct gfs_sbd *sdp, unsigned int blocks) +{ + return DIV_RU(blocks, sdp->sd_sb.sb_seg_size - 1); +} + +/** + * log_distance - Compute distance between two journal blocks + * @sdp: The GFS superblock + * @newer: The most recent journal block of the pair + * @older: The older journal block of the pair + * + * Compute the distance (in the journal direction) between two + * blocks in the journal + * + * Returns: the distance in blocks + */ + +static __inline__ unsigned int +log_distance(struct gfs_sbd *sdp, uint64_t newer, uint64_t older) +{ + int64_t dist; + + dist = newer - older; + if (dist < 0) + dist += sdp->sd_jdesc.ji_nsegment * sdp->sd_sb.sb_seg_size; + + return dist; +} + +/** + * log_incr_head - Increment journal head (next block to fill in journal) + * @sdp: The GFS superblock + * @head: the variable holding the head of the journal + * + * Increment journal head by one. + * At the end of the journal, wrap head back to the start. + * Don't confuse journal/log head with a gfs_log_header! + */ + +static __inline__ void +log_incr_head(struct gfs_sbd *sdp, uint64_t * head) +{ + struct gfs_jindex *jdesc = &sdp->sd_jdesc; + + if (++*head == + jdesc->ji_addr + jdesc->ji_nsegment * sdp->sd_sb.sb_seg_size) + *head = jdesc->ji_addr; +} + +/** + * gfs_ail_start - Start I/O on the AIL + * @sdp: the filesystem + * @flags: DIO_ALL -- flush *all* AIL transactions to disk + * default -- flush first-on-list AIL transaction to disk + * + */ + +void +gfs_ail_start(struct gfs_sbd *sdp, int flags) +{ + struct list_head *head = &sdp->sd_log_ail; + struct list_head *first, *tmp; + struct gfs_trans *first_tr, *tr; + + gfs_log_lock(sdp); + + if (list_empty(head)) { + gfs_log_unlock(sdp); + return; + } + + first = head->prev; + first_tr = list_entry(first, struct gfs_trans, tr_list); + gfs_ail_start_trans(sdp, first_tr); + + if (flags & DIO_ALL) + first_tr = NULL; + + for (tmp = first->prev; tmp != head; tmp = tmp->prev) { + if (first_tr && gfs_ail_empty_trans(sdp, first_tr)) + break; + + tr = list_entry(tmp, struct gfs_trans, tr_list); + gfs_ail_start_trans(sdp, tr); + } + + gfs_log_unlock(sdp); +} + +/** + * current_tail - Find block number of current log tail + * @sdp: The GFS superblock + * + * Find the block number of the current tail of the log. + * Assumes that the log lock is held. + * + * Returns: The tail's block number (must be on a log segment boundary) + */ + +static uint64_t +current_tail(struct gfs_sbd *sdp) +{ + struct gfs_trans *tr; + uint64_t tail; + + if (list_empty(&sdp->sd_log_ail)) { + tail = sdp->sd_log_head; + + if (!gfs_log_is_header(sdp, tail)) { + tail--; + gfs_assert(sdp, gfs_log_is_header(sdp, tail), ); + } + } else { + tr = list_entry(sdp->sd_log_ail.prev, + struct gfs_trans, tr_list); + tail = tr->tr_first_head; + } + + return tail; +} + +/** + * gfs_ail_empty - move the tail of the log forward (if possible) + * @sdp: the filesystem + * + * Returns: TRUE if the AIL is empty + * + * Checks each transaction on sd_log_ail, to see if it has been successfully + * flushed to in-place blocks on disk. If so, removes trans from sd_log_ail, + * effectively advancing the tail of the log (freeing log segments so they + * can be overwritten). + * Adds # freed log segments to sd_log_seg_free. + */ + +int +gfs_ail_empty(struct gfs_sbd *sdp) +{ + struct list_head *head, *tmp, *prev; + struct gfs_trans *tr; + uint64_t oldtail, newtail; + unsigned int dist; + unsigned int segments; + int ret; + + gfs_log_lock(sdp); + + oldtail = current_tail(sdp); + + for (head = &sdp->sd_log_ail, tmp = head->prev, prev = tmp->prev; + tmp != head; + tmp = prev, prev = tmp->prev) { + tr = list_entry(tmp, struct gfs_trans, tr_list); + if (gfs_ail_empty_trans(sdp, tr)) { + list_del(&tr->tr_list); + kfree(tr); + } + } + + newtail = current_tail(sdp); + + if (oldtail != newtail) { + dist = log_distance(sdp, newtail, oldtail); + + segments = dist / sdp->sd_sb.sb_seg_size; + gfs_assert(sdp, segments * sdp->sd_sb.sb_seg_size == dist,); + + sdp->sd_log_seg_ail2 += segments; + gfs_assert(sdp, sdp->sd_log_seg_free + sdp->sd_log_seg_ail2 <= + sdp->sd_jdesc.ji_nsegment,); + } + + ret = list_empty(head); + + gfs_log_unlock(sdp); + + return ret; +} + +/** + * gfs_log_reserve - Make a log reservation + * @sdp: The GFS superblock + * @segments: The number of segments to reserve + * @jump_queue: if TRUE, don't care about fairness ordering + * + * Returns: errno + */ + +int +gfs_log_reserve(struct gfs_sbd *sdp, unsigned int segments, int jump_queue) +{ + struct list_head list; + unsigned int try = 0; + + if (gfs_assert_warn(sdp, segments)) + return -EINVAL; + if (gfs_assert_warn(sdp, segments < sdp->sd_jdesc.ji_nsegment)) + return -EINVAL; + + INIT_LIST_HEAD(&list); + + for (;;) { + spin_lock(&sdp->sd_log_seg_lock); + + if (list_empty(&list)) { + if (jump_queue) + list_add(&list, &sdp->sd_log_seg_list); + else { + list_add_tail(&list, &sdp->sd_log_seg_list); + while (sdp->sd_log_seg_list.next != &list) { + DECLARE_WAITQUEUE(__wait_chan, current); + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&sdp->sd_log_seg_wait, + &__wait_chan); + spin_unlock(&sdp->sd_log_seg_lock); + schedule(); + spin_lock(&sdp->sd_log_seg_lock); + remove_wait_queue(&sdp->sd_log_seg_wait, + &__wait_chan); + set_current_state(TASK_RUNNING); + } + } + } + + if (sdp->sd_log_seg_free > segments) { + sdp->sd_log_seg_free -= segments; + list_del(&list); + spin_unlock(&sdp->sd_log_seg_lock); + wake_up(&sdp->sd_log_seg_wait); + break; + } + + spin_unlock(&sdp->sd_log_seg_lock); + + if (try) { + gfs_log_flush(sdp); + gfs_ail_start(sdp, 0); + } + + gfs_ail_empty(sdp); + + try++; + yield(); + } + + return 0; +} + +/** + * gfs_log_release - Release a given number of log segments + * @sdp: The GFS superblock + * @segments: The number of segments + * + */ + +void +gfs_log_release(struct gfs_sbd *sdp, unsigned int segments) +{ + spin_lock(&sdp->sd_log_seg_lock); + sdp->sd_log_seg_free += segments; + gfs_assert(sdp, sdp->sd_log_seg_free + sdp->sd_log_seg_ail2 <= + sdp->sd_jdesc.ji_nsegment,); + spin_unlock(&sdp->sd_log_seg_lock); +} + +/** + * log_get_header - Get and initialize a journal header buffer + * @sdp: The GFS superblock + * @tr: The transaction that needs a log header + * @next: FALSE if this log header appears in midst of current transaction + * TRUE if this starts next transaction (and commits current trans) + * + * Returns: the initialized log buffer descriptor + * + * Initialize one of the transaction's pre-allocated buffers (and associated + * log buffer descriptor) to be a log header for this transaction. + * A log header gets written to *each* log segment boundary block, so journal + * recovery will quickly be able to get its bearings. A single transaction + * may span several log segments, which means that log headers will appear + * in the midst of that transaction (@next == FALSE). These headers get + * added to trans' list of buffers to write to log. + * Log commit is accomplished by writing the log header for the next + * transaction (@next == TRUE), with pre-incremented sequence number, + * and updated first-in-transaction block number. These headers do *not* get + * added to trans' buffer list, since they are written separately to disk + * *after* the trans gets completely flushed to on-disk log. + * NOTE: This buffer will *not* get written to an in-place location in the + * filesystem; it is for use only within the log. + */ + +static struct gfs_log_buf * +log_get_header(struct gfs_sbd *sdp, struct gfs_trans *tr, int next) +{ + struct gfs_log_buf *lb; + struct list_head *bmem; + struct gfs_log_header header; + + /* Make sure we're on a log segment boundary block */ + gfs_assert(sdp, gfs_log_is_header(sdp, tr->tr_log_head),); + + /* Grab a free log buffer descriptor (attached to trans) */ + gfs_assert(sdp, tr->tr_num_free_bufs && + !list_empty(&tr->tr_free_bufs),); + lb = list_entry(tr->tr_free_bufs.next, struct gfs_log_buf, lb_list); + list_del(&lb->lb_list); + tr->tr_num_free_bufs--; + + /* Grab a free log buffer (attached to trans) */ + gfs_assert(sdp, tr->tr_num_free_bmem && + !list_empty(&tr->tr_free_bmem),); + bmem = tr->tr_free_bmem.next; + list_del(bmem); + tr->tr_num_free_bmem--; + + /* Create "fake" bh to write bmem to log header block */ + gfs_logbh_init(sdp, &lb->lb_bh, tr->tr_log_head, (char *)bmem); + memset(bmem, 0, sdp->sd_sb.sb_bsize); + + memset(&header, 0, sizeof (header)); + + if (next) { + /* Fill in header for next transaction, committing previous */ + header.lh_header.mh_magic = GFS_MAGIC; + header.lh_header.mh_type = GFS_METATYPE_LH; + header.lh_header.mh_format = GFS_FORMAT_LH; + header.lh_first = tr->tr_log_head; + header.lh_sequence = sdp->sd_sequence + 1; + header.lh_tail = current_tail(sdp); + header.lh_last_dump = sdp->sd_log_dump_last; + } else { + /* Fill in another header for this transaction */ + header.lh_header.mh_magic = GFS_MAGIC; + header.lh_header.mh_type = GFS_METATYPE_LH; + header.lh_header.mh_format = GFS_FORMAT_LH; + header.lh_first = tr->tr_first_head; + header.lh_sequence = sdp->sd_sequence; + header.lh_tail = current_tail(sdp); + header.lh_last_dump = sdp->sd_log_dump_last; + + /* Attach log header buf to trans' list of bufs going to log */ + list_add(&lb->lb_list, &tr->tr_bufs); + } + + /* Copy log header struct to beginning and end of buffer's 1st 512B */ + gfs_log_header_out(&header, lb->lb_bh.b_data); + gfs_log_header_out(&header, + lb->lb_bh.b_data + GFS_BASIC_BLOCK - + sizeof(struct gfs_log_header)); + + /* Find next log buffer to fill */ + log_incr_head(sdp, &tr->tr_log_head); + + return lb; +} + +/** + * gfs_log_get_buf - Get and initialize a buffer to use for log control data + * @sdp: The GFS superblock + * @tr: The GFS transaction + * + * Initialize one of the transaction's pre-allocated buffers (and associated + * log buffer descriptor) to be used for log control data (e.g. log tags). + * Make sure this buffer is attached to the transaction, to be logged to disk. + * NOTE: This buffer will *not* get written to an in-place location in the + * filesystem; it is for use only within the log. + * + * Returns: the log buffer descriptor + */ + +struct gfs_log_buf * +gfs_log_get_buf(struct gfs_sbd *sdp, struct gfs_trans *tr) +{ + struct gfs_log_buf *lb; + struct list_head *bmem; + + /* If next block in log is on a segment boundary, we need to + write a log header */ + if (gfs_log_is_header(sdp, tr->tr_log_head)) + log_get_header(sdp, tr, FALSE); + + /* Grab a free buffer descriptor (attached to trans) */ + gfs_assert(sdp, tr->tr_num_free_bufs && + !list_empty(&tr->tr_free_bufs),); + lb = list_entry(tr->tr_free_bufs.next, struct gfs_log_buf, lb_list); + list_del(&lb->lb_list); + tr->tr_num_free_bufs--; + + /* Grab a free buffer (attached to trans) */ + gfs_assert(sdp, tr->tr_num_free_bmem + && !list_empty(&tr->tr_free_bmem),); + bmem = tr->tr_free_bmem.next; + list_del(bmem); + tr->tr_num_free_bmem--; + + /* Create "fake" bh to write bmem to log block */ + gfs_logbh_init(sdp, &lb->lb_bh, tr->tr_log_head, (char *)bmem); + memset(bmem, 0, sdp->sd_sb.sb_bsize); + + list_add(&lb->lb_list, &tr->tr_bufs); + + /* Find next log buffer to fill */ + log_incr_head(sdp, &tr->tr_log_head); + + return lb; +} + +/** + * gfs_log_fake_buf - Build a fake buffer head to write metadata buffer to log + * @sdp: the filesystem + * @tr: the transaction this is part of + * @data: the data the buffer_head should point to + * @unlock: a buffer_head to be unlocked when struct gfs_log_buf is torn down + * (i.e. the "real" buffer_head that will write to in-place location) + * + * Initialize one of the transaction's pre-allocated log buffer descriptors + * to be used for writing a metadata buffer into the log. + * Make sure this buffer is attached to the transaction, to be logged to disk. + * NOTE: This buffer *will* be written to in-place location within filesytem, + * in addition to being written into the log. + * + */ + +void +gfs_log_fake_buf(struct gfs_sbd *sdp, struct gfs_trans *tr, char *data, + struct buffer_head *unlock) +{ + struct gfs_log_buf *lb; + + if (gfs_log_is_header(sdp, tr->tr_log_head)) + log_get_header(sdp, tr, FALSE); + + /* Grab a free buffer descriptor (attached to trans) */ + gfs_assert(sdp, tr->tr_num_free_bufs && + !list_empty(&tr->tr_free_bufs),); + lb = list_entry(tr->tr_free_bufs.next, struct gfs_log_buf, lb_list); + list_del(&lb->lb_list); + tr->tr_num_free_bufs--; + + /* Create "fake" bh to write data to log block */ + gfs_logbh_init(sdp, &lb->lb_bh, tr->tr_log_head, data); + lb->lb_unlock = unlock; + + list_add(&lb->lb_list, &tr->tr_bufs); + + /* Find next log buffer to fill */ + log_incr_head(sdp, &tr->tr_log_head); +} + +/** + * check_seg_usage - Check that we didn't use too many segments + * @sdp: The GFS superblock + * @tr: The transaction + * + * Also, make sure we don't write ever get to a point where there are + * no dumps in the log (corrupting the log). Panic before we let + * that happen. + * + */ + +static void +check_seg_usage(struct gfs_sbd *sdp, struct gfs_trans *tr) +{ + struct gfs_jindex *jdesc = &sdp->sd_jdesc; + unsigned int dist; + unsigned int segments; + uint64_t head_off, head_wrap; + uint64_t dump_off, dump_wrap; + + dist = log_distance(sdp, tr->tr_log_head, tr->tr_first_head); + + segments = dist / sdp->sd_sb.sb_seg_size; + gfs_assert(sdp, segments * sdp->sd_sb.sb_seg_size == dist,); + gfs_assert(sdp, segments == tr->tr_seg_reserved,); + + if (sdp->sd_log_dump_last) { + int diff; + + head_off = tr->tr_first_head + + tr->tr_seg_reserved * sdp->sd_sb.sb_seg_size; + head_wrap = sdp->sd_log_wrap; + if (head_off >= jdesc->ji_addr + + jdesc->ji_nsegment * sdp->sd_sb.sb_seg_size) { + head_off -= jdesc->ji_nsegment * sdp->sd_sb.sb_seg_size; + head_wrap++; + } + + dump_off = sdp->sd_log_dump_last; + dump_wrap = sdp->sd_log_dump_last_wrap; + + diff = (int)(head_wrap - dump_wrap); + switch (diff) { + case 0: + break; + + case 1: + if (head_off < dump_off - sdp->sd_sb.sb_seg_size) + break; + else if (head_off <= dump_off && + (tr->tr_flags & TRF_LOG_DUMP)) + break; + + default: + gfs_assert(sdp, FALSE, + printk("GFS: fsid=%s: head_off = %"PRIu64", head_wrap = %"PRIu64"\n" + "GFS: fsid=%s: dump_off = %"PRIu64", dump_wrap = %"PRIu64"\n", + sdp->sd_fsname, head_off, head_wrap, + sdp->sd_fsname, dump_off, dump_wrap);); + break; + } + } +} + +/** + * log_free_buf - Free a struct gfs_log_buf (and possibly the data it points to) + * @sdp: the filesystem + * @lb: the log buffer descriptor + * + * If buffer contains (meta)data to be written into filesystem in-place block, + * descriptor will point to the "real" (lb_unlock) buffer head. Unlock it. + * If buffer was used only for log header or control data (e.g. tags), we're + * done with it as soon as it gets written to on-disk log. Free it. + * Either way, we can free the log descriptor structure. + */ + +static void +log_free_buf(struct gfs_sbd *sdp, struct gfs_log_buf *lb) +{ + char *bmem; + + bmem = lb->lb_bh.b_data; + gfs_logbh_uninit(sdp, &lb->lb_bh); + + if (lb->lb_unlock) + gfs_unlock_buffer(lb->lb_unlock); + else + kfree(bmem); + + kfree(lb); +} + +/** + * sync_trans - Add "last" descriptor, sync transaction to on-disk log + * @sdp: The GFS superblock + * @tr: The transaction + * + * Add the "last" descriptor onto the end of the current transaction + * and sync the whole transaction out to on-disk log. + * Don't log-commit (i.e. write next transaction's log header) yet, though. + * + * Returns: errno + */ + +static int +sync_trans(struct gfs_sbd *sdp, struct gfs_trans *tr) +{ + struct list_head *tmp, *head, *prev; + struct gfs_log_descriptor desc; + struct gfs_log_buf *lb; + uint64_t blk; + int error = 0, e; + + /* Build LAST descriptor */ + + lb = gfs_log_get_buf(sdp, tr); + + memset(&desc, 0, sizeof(struct gfs_log_descriptor)); + desc.ld_header.mh_magic = GFS_MAGIC; + desc.ld_header.mh_type = GFS_METATYPE_LD; + desc.ld_header.mh_format = GFS_FORMAT_LD; + desc.ld_type = GFS_LOG_DESC_LAST; + desc.ld_length = 1; + for (blk = tr->tr_log_head; !gfs_log_is_header(sdp, blk); blk++) + desc.ld_length++; + gfs_desc_out(&desc, lb->lb_bh.b_data); + + while (!gfs_log_is_header(sdp, tr->tr_log_head)) + log_incr_head(sdp, &tr->tr_log_head); + + check_seg_usage(sdp, tr); + + /* Start I/O + Go in "prev" direction to start the I/O in order. */ + + for (head = &tr->tr_bufs, tmp = head->prev, prev = tmp->prev; + tmp != head; + tmp = prev, prev = tmp->prev) { + lb = list_entry(tmp, struct gfs_log_buf, lb_list); + gfs_logbh_start(sdp, &lb->lb_bh); + } + + /* Wait on I/O + Go in "next" direction to minimize sleeps/wakeups. */ + + while (!list_empty(&tr->tr_bufs)) { + lb = list_entry(tr->tr_bufs.next, struct gfs_log_buf, lb_list); + + e = gfs_logbh_wait(sdp, &lb->lb_bh); + if (e) + error = e; + + list_del(&lb->lb_list); + log_free_buf(sdp, lb); + } + + return error; +} + +/** + * commit_trans - Commit the current transaction + * @sdp: The GFS superblock + * @tr: The transaction + * + * Write next header to commit + * + * Returns: errno + */ + +static int +commit_trans(struct gfs_sbd *sdp, struct gfs_trans *tr) +{ + struct gfs_log_buf *lb; + int error; + + lb = log_get_header(sdp, tr, TRUE); + + gfs_logbh_start(sdp, &lb->lb_bh); + error = gfs_logbh_wait(sdp, &lb->lb_bh); + if (!error) { + spin_lock(&sdp->sd_log_seg_lock); + if (!(tr->tr_flags & TRF_DUMMY)) + sdp->sd_log_seg_free += sdp->sd_log_seg_ail2; + else + sdp->sd_log_seg_free += (sdp->sd_log_seg_ail2 - 1); + sdp->sd_log_seg_ail2 = 0; + spin_unlock(&sdp->sd_log_seg_lock); + } + log_free_buf(sdp, lb); + + return error; +} + +/** + * disk_commit - Write a transaction to the on-disk journal + * @sdp: The GFS superblock + * @tr: The transaction + * + * Returns: errno + */ + +static int +disk_commit(struct gfs_sbd *sdp, struct gfs_trans *tr) +{ + uint64_t last_dump, last_dump_wrap; + int error = 0; + + gfs_assert(sdp, !test_bit(SDF_ROFS, &sdp->sd_flags),); + tr->tr_log_head = sdp->sd_log_head; + tr->tr_first_head = tr->tr_log_head - 1; + gfs_assert(sdp, gfs_log_is_header(sdp, tr->tr_first_head),); + + LO_BUILD_BHLIST(sdp, tr); + + if (!(tr->tr_flags & TRF_DUMMY)) + gfs_assert(sdp, !list_empty(&tr->tr_bufs),); + + error = sync_trans(sdp, tr); + if (error) { + /* Eat unusable commit buffer */ + log_free_buf(sdp, log_get_header(sdp, tr, TRUE)); + goto out; + } + + if (tr->tr_flags & TRF_LOG_DUMP) { + /* This commit header should point to the log dump we're + commiting as the current one. But save the copy of the + old one in case we have problems commiting the dump. */ + + last_dump = sdp->sd_log_dump_last; + last_dump_wrap = sdp->sd_log_dump_last_wrap; + + sdp->sd_log_dump_last = tr->tr_first_head; + sdp->sd_log_dump_last_wrap = sdp->sd_log_wrap; + + error = commit_trans(sdp, tr); + if (error) { + sdp->sd_log_dump_last = last_dump; + sdp->sd_log_dump_last_wrap = last_dump_wrap; + goto out; + } + } else { + error = commit_trans(sdp, tr); + if (error) + goto out; + } + + if (sdp->sd_log_head > tr->tr_log_head) + sdp->sd_log_wrap++; + sdp->sd_log_head = tr->tr_log_head; + sdp->sd_sequence++; + + out: + gfs_assert_warn(sdp, !tr->tr_num_free_bufs && + list_empty(&tr->tr_free_bufs)); + gfs_assert_warn(sdp, !tr->tr_num_free_bmem && + list_empty(&tr->tr_free_bmem)); + + return error; +} + +/** + * add_trans_to_ail - Add a ondisk commited transaction to the AIL + * @sdp: the filesystem + * @tr: the transaction + * + */ + +static void +add_trans_to_ail(struct gfs_sbd *sdp, struct gfs_trans *tr) +{ + struct gfs_log_element *le; + + while (!list_empty(&tr->tr_elements)) { + le = list_entry(tr->tr_elements.next, + struct gfs_log_element, le_list); + LO_ADD_TO_AIL(sdp, le); + } + + list_add(&tr->tr_list, &sdp->sd_log_ail); +} + +/** + * log_refund - Refund log segments to the free pool + * @sdp: The GFS superblock + * @tr: The transaction to examine + * + * Look at the number of segments reserved for this transaction and the + * number of segments actually needed for it. If they aren't the + * same, refund the difference to the free segment pool. + * + * De-alloc any unneeded log buffers and log buffer descriptors. + * + * Called with the log lock held. + */ + +static void +log_refund(struct gfs_sbd *sdp, struct gfs_trans *tr) +{ + struct gfs_log_buf *lb; + struct list_head *bmem; + unsigned int num_bufs = 0, num_bmem = 0; + unsigned int segments; + + LO_TRANS_SIZE(sdp, tr, NULL, NULL, &num_bufs, &num_bmem); + + segments = gfs_blk2seg(sdp, num_bufs + 1); + num_bufs += segments + 1; + num_bmem += segments + 1; + + /* Unreserve unneeded log segments */ + if (tr->tr_seg_reserved > segments) { + spin_lock(&sdp->sd_log_seg_lock); + sdp->sd_log_seg_free += tr->tr_seg_reserved - segments; + gfs_assert(sdp, sdp->sd_log_seg_free + sdp->sd_log_seg_ail2 <= + sdp->sd_jdesc.ji_nsegment,); + spin_unlock(&sdp->sd_log_seg_lock); + + tr->tr_seg_reserved = segments; + } else + gfs_assert(sdp, tr->tr_seg_reserved == segments,); + + /* De-alloc unneeded log buffer descriptors */ + gfs_assert(sdp, tr->tr_num_free_bufs >= num_bufs,); + while (tr->tr_num_free_bufs > num_bufs) { + lb = list_entry(tr->tr_free_bufs.next, + struct gfs_log_buf, lb_list); + list_del(&lb->lb_list); + kfree(lb); + tr->tr_num_free_bufs--; + } + + /* De-alloc unneeded log buffers */ + gfs_assert(sdp, tr->tr_num_free_bmem >= num_bmem,); + while (tr->tr_num_free_bmem > num_bmem) { + bmem = tr->tr_free_bmem.next; + list_del(bmem); + kfree(bmem); + tr->tr_num_free_bmem--; + } +} + +/** + * trans_combine - combine two transactions + * @sdp: the filesystem + * @tr: the surviving transaction + * @new_tr: the transaction that gets freed + * + * Assumes that the two transactions are independent. + */ + +static void +trans_combine(struct gfs_sbd *sdp, struct gfs_trans *tr, + struct gfs_trans *new_tr) +{ + struct gfs_log_element *le; + struct gfs_log_buf *lb; + struct list_head *bmem; + + tr->tr_file = __FILE__; + tr->tr_line = __LINE__; + tr->tr_seg_reserved += new_tr->tr_seg_reserved; + tr->tr_flags |= new_tr->tr_flags; + tr->tr_num_free_bufs += new_tr->tr_num_free_bufs; + tr->tr_num_free_bmem += new_tr->tr_num_free_bmem; + + /* Combine the log elements of the two transactions */ + + while (!list_empty(&new_tr->tr_elements)) { + le = list_entry(new_tr->tr_elements.next, + struct gfs_log_element, le_list); + gfs_assert(sdp, le->le_trans == new_tr,); + le->le_trans = tr; + list_move(&le->le_list, &tr->tr_elements); + } + + LO_TRANS_COMBINE(sdp, tr, new_tr); + + /* Move free log buffer descriptors to surviving trans */ + while (!list_empty(&new_tr->tr_free_bufs)) { + lb = list_entry(new_tr->tr_free_bufs.next, + struct gfs_log_buf, lb_list); + list_move(&lb->lb_list, &tr->tr_free_bufs); + new_tr->tr_num_free_bufs--; + } + /* Move free log buffers to surviving trans */ + while (!list_empty(&new_tr->tr_free_bmem)) { + bmem = new_tr->tr_free_bmem.next; + list_move(bmem, &tr->tr_free_bmem); + new_tr->tr_num_free_bmem--; + } + + gfs_assert_warn(sdp, !new_tr->tr_num_free_bufs); + gfs_assert_warn(sdp, !new_tr->tr_num_free_bmem); + + kfree(new_tr); +} + +static void +make_dummy_transaction(struct gfs_sbd *sdp, struct gfs_trans *tr) +{ + struct gfs_log_buf *lb; + struct list_head *bmem; + + memset(tr, 0, sizeof(struct gfs_trans)); + INIT_LIST_HEAD(&tr->tr_list); + INIT_LIST_HEAD(&tr->tr_elements); + INIT_LIST_HEAD(&tr->tr_free_bufs); + INIT_LIST_HEAD(&tr->tr_free_bmem); + INIT_LIST_HEAD(&tr->tr_bufs); + INIT_LIST_HEAD(&tr->tr_ail_bufs); + tr->tr_flags = TRF_DUMMY; + tr->tr_file = __FILE__; + tr->tr_line = __LINE__; + tr->tr_seg_reserved = 1; + while (tr->tr_num_free_bufs < 2) { + lb = gmalloc(sizeof(struct gfs_log_buf)); + memset(lb, 0, sizeof(struct gfs_log_buf)); + list_add(&lb->lb_list, &tr->tr_free_bufs); + tr->tr_num_free_bufs++; + } + while (tr->tr_num_free_bmem < 2) { + bmem = gmalloc(sdp->sd_sb.sb_bsize); + list_add(bmem, &tr->tr_free_bmem); + tr->tr_num_free_bmem++; + } +} + + +/** + * log_flush_internal - flush incore transaction(s) + * @sdp: the filesystem + * @gl: The glock structure to flush. If NULL, flush the whole incore log + * + * If a glock is provided, we flush, to on-disk log, all of the metadata for + * the one incore-committed (complete, but not-yet-flushed-to-log) + * transaction that the glock protects. + * If NULL, we combine *all* of the filesystem's incore-committed + * transactions into one big transaction, and flush it to the log. + */ + +static void +log_flush_internal(struct gfs_sbd *sdp, struct gfs_glock *gl) +{ + + struct gfs_trans *trans = NULL, *tr; + int error; + + gfs_log_lock(sdp); + + if (!gl && list_empty(&sdp->sd_log_incore)) { + if (sdp->sd_log_seg_ail2) { + trans = gmalloc(sizeof(struct gfs_trans)); + make_dummy_transaction(sdp, trans); + } + else + goto out; + } + + if (gl) { + if (!gl->gl_incore_le.le_trans) + goto out; + + trans = gl->gl_incore_le.le_trans; + + list_del(&trans->tr_list); + } else { + /* combine *all* transactions in incore list */ + while (!list_empty(&sdp->sd_log_incore)) { + tr = list_entry(sdp->sd_log_incore.next, + struct gfs_trans, tr_list); + + list_del(&tr->tr_list); + + if (trans) + trans_combine(sdp, trans, tr); + else + trans = tr; + } + } + + log_refund(sdp, trans); + + /* Actually do the stuff to commit the transaction */ + + error = disk_commit(sdp, trans); + if (error) + gfs_io_error(sdp); + + add_trans_to_ail(sdp, trans); + + if (log_distance(sdp, sdp->sd_log_head, sdp->sd_log_dump_last) * GFS_DUMPS_PER_LOG >= + sdp->sd_jdesc.ji_nsegment * sdp->sd_sb.sb_seg_size) + set_bit(SDF_NEED_LOG_DUMP, &sdp->sd_flags); + + out: + if (list_empty(&sdp->sd_log_incore)) + sdp->sd_vfs->s_dirt = FALSE; + + gfs_log_unlock(sdp); + + /* Dump if we need to. */ + + if (test_bit(SDF_NEED_LOG_DUMP, &sdp->sd_flags)) + gfs_log_dump(sdp, FALSE); +} + +/** + * gfs_log_flush - flush the whole incore log + * @sdp: the filesystem + * + */ + +void +gfs_log_flush(struct gfs_sbd *sdp) +{ + log_flush_internal(sdp, NULL); +} + +/** + * gfs_log_flush_glock - flush the incore log for a glock + * @gl: the glock + * + */ + +void +gfs_log_flush_glock(struct gfs_glock *gl) +{ + log_flush_internal(gl->gl_sbd, gl); +} + +/** + * incore_commit - commit a transaction in-core + * @sdp: the filesystem + * @new_tr: the transaction to commit + * + * Add the transaction @new_tr to the end of the incore commit list. + * Pull up and merge any previously committed transactions that share + * locks. Also pull up any rename transactions that need it. + */ + +static void +incore_commit(struct gfs_sbd *sdp, struct gfs_trans *new_tr) +{ + struct gfs_log_element *le; + struct gfs_trans *trans = NULL, *exist_tr; + struct gfs_log_buf *lb; + struct list_head *bmem; + struct list_head *tmp, *head, *next; + + for (head = &new_tr->tr_elements, tmp = head->next; + tmp != head; + tmp = tmp->next) { + le = list_entry(tmp, struct gfs_log_element, le_list); + + /* Do overlap_trans log-op, if any, to find another + incore transaction with which we can combine new_tr */ + exist_tr = LO_OVERLAP_TRANS(sdp, le); + if (!exist_tr) + continue; + + if (exist_tr != trans) { + /* remove trans from superblock's sd_log_incore list */ + list_del(&exist_tr->tr_list); + + /* Maybe there's more than one that can be combined. + If so, combine them together before merging new_tr */ + if (trans) + trans_combine(sdp, trans, exist_tr); + else + trans = exist_tr; + } + } + + /* Yes, we can combine new_tr with pre-existing transaction(s) */ + if (trans) { + trans->tr_file = __FILE__; + trans->tr_line = __LINE__; + trans->tr_seg_reserved += new_tr->tr_seg_reserved; + trans->tr_flags |= new_tr->tr_flags; + trans->tr_num_free_bufs += new_tr->tr_num_free_bufs; + trans->tr_num_free_bmem += new_tr->tr_num_free_bmem; + + /* Move free log buffer descriptors to surviving trans */ + while (!list_empty(&new_tr->tr_free_bufs)) { + lb = list_entry(new_tr->tr_free_bufs.next, + struct gfs_log_buf, lb_list); + list_move(&lb->lb_list, &trans->tr_free_bufs); + new_tr->tr_num_free_bufs--; + } + + /* Move free log buffers to surviving trans */ + while (!list_empty(&new_tr->tr_free_bmem)) { + bmem = new_tr->tr_free_bmem.next; + list_move(bmem, &trans->tr_free_bmem); + new_tr->tr_num_free_bmem--; + } + } else + trans = new_tr; + + /* Do incore_commit log-op for each *new* log element (in new_tr). + Each commit log-op removes its log element from "new_tr" LE list, + and attaches an LE to "trans" LE list; if there was no trans + combining, "new_tr" is the same transaction as "trans". */ + for (head = &new_tr->tr_elements, tmp = head->next, next = tmp->next; + tmp != head; + tmp = next, next = next->next) { + le = list_entry(tmp, struct gfs_log_element, le_list); + LO_INCORE_COMMIT(sdp, trans, le); + } + + /* If we successfully combined transactions, new_tr should be empty */ + if (trans != new_tr) { + gfs_assert_warn(sdp, !new_tr->tr_num_free_bufs); + gfs_assert_warn(sdp, !new_tr->tr_num_free_bmem); + gfs_assert_warn(sdp, list_empty(&new_tr->tr_elements)); + kfree(new_tr); + } + + /* If we successfully combined transactions, we might have some log + segments that we reserved, and log buffers and buffer descriptors + that we allocated, but now don't need. */ + log_refund(sdp, trans); + + list_add(&trans->tr_list, &sdp->sd_log_incore); +} + +/** + * gfs_log_commit - Commit a transaction to the log + * @sdp: the filesystem + * @tr: the transaction + * + * Returns: errno + */ + +void +gfs_log_commit(struct gfs_sbd *sdp, struct gfs_trans *tr) +{ + struct gfs_log_buf *lb; + struct list_head *bmem; + unsigned int num_mblks = 0, num_eblks = 0, num_bufs = 0, num_bmem = 0; + unsigned int segments; + + /* Calculate actual log area needed for this trans */ + LO_TRANS_SIZE(sdp, tr, &num_mblks, &num_eblks, &num_bufs, &num_bmem); + + gfs_assert(sdp, num_mblks <= tr->tr_mblks_asked && + num_eblks <= tr->tr_eblks_asked, + printk("GFS: fsid=%s: type = (%s, %u)\n" + "GFS: fsid=%s: num_mblks = %u, tr->tr_mblks_asked = %u\n" + "GFS: fsid=%s: num_eblks = %u, tr->tr_eblks_asked = %u\n", + sdp->sd_fsname, tr->tr_file, tr->tr_line, + sdp->sd_fsname, num_mblks, tr->tr_mblks_asked, + sdp->sd_fsname, num_eblks, tr->tr_eblks_asked);); + + segments = gfs_blk2seg(sdp, num_bufs + 1); + num_bufs += segments + 1; + num_bmem += segments + 1; + + /* Alloc log buffer descriptors */ + while (num_bufs--) { + lb = gmalloc(sizeof(struct gfs_log_buf)); + memset(lb, 0, sizeof(struct gfs_log_buf)); + list_add(&lb->lb_list, &tr->tr_free_bufs); + tr->tr_num_free_bufs++; + } + /* Alloc log buffers */ + while (num_bmem--) { + bmem = gmalloc(sdp->sd_sb.sb_bsize); + list_add(bmem, &tr->tr_free_bmem); + tr->tr_num_free_bmem++; + } + + gfs_log_lock(sdp); + + incore_commit(sdp, tr); + + /* Flush log buffers to disk if we're over the threshold */ + if (sdp->sd_log_buffers > gfs_tune_get(sdp, gt_incore_log_blocks)) { + gfs_log_unlock(sdp); + gfs_log_flush(sdp); + } else { + sdp->sd_vfs->s_dirt = TRUE; + gfs_log_unlock(sdp); + } + +} + +/** + * gfs_log_dump - make a Log Dump entry in the log + * @sdp: the filesystem + * @force: if TRUE, always make the dump even if one has been made recently + * + */ + +void +gfs_log_dump(struct gfs_sbd *sdp, int force) +{ + struct gfs_log_element *le; + struct gfs_trans tr; + struct gfs_log_buf *lb; + struct list_head *bmem; + unsigned int num_bufs, num_bmem; + unsigned int segments; + int error; + + if (test_and_set_bit(SDF_IN_LOG_DUMP, &sdp->sd_flags)) { + gfs_assert(sdp, !force,); + return; + } + + memset(&tr, 0, sizeof(struct gfs_trans)); + INIT_LIST_HEAD(&tr.tr_elements); + INIT_LIST_HEAD(&tr.tr_free_bufs); + INIT_LIST_HEAD(&tr.tr_free_bmem); + INIT_LIST_HEAD(&tr.tr_bufs); + tr.tr_flags = TRF_LOG_DUMP; + tr.tr_file = __FILE__; + tr.tr_line = __LINE__; + + for (;;) { + gfs_log_lock(sdp); + + if (!force && !test_bit(SDF_NEED_LOG_DUMP, &sdp->sd_flags)) + goto out; + + num_bufs = num_bmem = 0; + LO_DUMP_SIZE(sdp, NULL, &num_bufs, &num_bmem); + gfs_assert(sdp, num_bufs,); + segments = gfs_blk2seg(sdp, num_bufs + 1); + num_bufs += segments + 1; + num_bmem += segments + 1; + + if (tr.tr_seg_reserved >= segments && + tr.tr_num_free_bufs >= num_bufs && + tr.tr_num_free_bmem >= num_bmem) + break; + + gfs_log_unlock(sdp); + + if (tr.tr_seg_reserved < segments) { + error = gfs_log_reserve(sdp, + segments - tr.tr_seg_reserved, + TRUE); + gfs_assert(sdp, !error,); + tr.tr_seg_reserved = segments; + } + while (tr.tr_num_free_bufs < num_bufs) { + lb = gmalloc(sizeof(struct gfs_log_buf)); + memset(lb, 0, sizeof(struct gfs_log_buf)); + list_add(&lb->lb_list, &tr.tr_free_bufs); + tr.tr_num_free_bufs++; + } + while (tr.tr_num_free_bmem < num_bmem) { + bmem = gmalloc(sdp->sd_sb.sb_bsize); + list_add(bmem, &tr.tr_free_bmem); + tr.tr_num_free_bmem++; + } + } + + if (tr.tr_seg_reserved > segments) { + spin_lock(&sdp->sd_log_seg_lock); + sdp->sd_log_seg_free += tr.tr_seg_reserved - segments; + gfs_assert(sdp, sdp->sd_log_seg_free + sdp->sd_log_seg_ail2 <= + sdp->sd_jdesc.ji_nsegment,); + spin_unlock(&sdp->sd_log_seg_lock); + tr.tr_seg_reserved = segments; + } + while (tr.tr_num_free_bufs > num_bufs) { + lb = list_entry(tr.tr_free_bufs.next, + struct gfs_log_buf, lb_list); + list_del(&lb->lb_list); + kfree(lb); + tr.tr_num_free_bufs--; + } + while (tr.tr_num_free_bmem > num_bmem) { + bmem = tr.tr_free_bmem.next; + list_del(bmem); + kfree(bmem); + tr.tr_num_free_bmem--; + } + + LO_BUILD_DUMP(sdp, &tr); + + error = disk_commit(sdp, &tr); + if (error) + gfs_io_error(sdp); + + while (!list_empty(&tr.tr_elements)) { + le = list_entry(tr.tr_elements.next, + struct gfs_log_element, le_list); + LO_CLEAN_DUMP(sdp, le); + } + + /* If there isn't anything in the AIL, we won't get back the log + space we reserved unless we do it ourselves. */ + + if (list_empty(&sdp->sd_log_ail)) { + spin_lock(&sdp->sd_log_seg_lock); + sdp->sd_log_seg_free += tr.tr_seg_reserved; + gfs_assert(sdp, sdp->sd_log_seg_free + sdp->sd_log_seg_ail2 <= + sdp->sd_jdesc.ji_nsegment,); + spin_unlock(&sdp->sd_log_seg_lock); + } + + clear_bit(SDF_NEED_LOG_DUMP, &sdp->sd_flags); + + out: + gfs_log_unlock(sdp); + clear_bit(SDF_IN_LOG_DUMP, &sdp->sd_flags); +} + +/** + * gfs_log_shutdown - write a shutdown header into a journal + * @sdp: the filesystem + * + */ + +void +gfs_log_shutdown(struct gfs_sbd *sdp) +{ + struct gfs_log_buf *lb; + char *bmem; + struct gfs_log_header head; + struct gfs_log_descriptor desc; + unsigned int elements = 0; + int error; + + lb = gmalloc(sizeof(struct gfs_log_buf)); + memset(lb, 0, sizeof(struct gfs_log_buf)); + bmem = gmalloc(sdp->sd_sb.sb_bsize); + + gfs_log_lock(sdp); + + gfs_assert_withdraw(sdp, list_empty(&sdp->sd_log_ail)); + gfs_assert_withdraw(sdp, sdp->sd_log_seg_free + sdp->sd_log_seg_ail2 == + sdp->sd_jdesc.ji_nsegment); + gfs_assert_withdraw(sdp, !sdp->sd_log_buffers); + gfs_assert_withdraw(sdp, gfs_log_is_header(sdp, sdp->sd_log_head - 1)); + if (test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) + goto out; + + /* Build a "last" log descriptor */ + + memset(&desc, 0, sizeof(struct gfs_log_descriptor)); + desc.ld_header.mh_magic = GFS_MAGIC; + desc.ld_header.mh_type = GFS_METATYPE_LD; + desc.ld_header.mh_format = GFS_FORMAT_LD; + desc.ld_type = GFS_LOG_DESC_LAST; + desc.ld_length = sdp->sd_sb.sb_seg_size - 1; + + /* Write the descriptor */ + + gfs_logbh_init(sdp, &lb->lb_bh, sdp->sd_log_head, bmem); + memset(bmem, 0, sdp->sd_sb.sb_bsize); + gfs_desc_out(&desc, lb->lb_bh.b_data); + gfs_logbh_start(sdp, &lb->lb_bh); + error = gfs_logbh_wait(sdp, &lb->lb_bh); + gfs_logbh_uninit(sdp, &lb->lb_bh); + + if (error) + goto out; + + /* Move to the next header */ + + while (!gfs_log_is_header(sdp, sdp->sd_log_head)) + log_incr_head(sdp, &sdp->sd_log_head); + + LO_DUMP_SIZE(sdp, &elements, NULL, NULL); + + /* Build the shutdown header */ + + memset(&head, 0, sizeof (struct gfs_log_header)); + head.lh_header.mh_magic = GFS_MAGIC; + head.lh_header.mh_type = GFS_METATYPE_LH; + head.lh_header.mh_format = GFS_FORMAT_LH; + head.lh_flags = GFS_LOG_HEAD_UNMOUNT; + head.lh_first = sdp->sd_log_head; + head.lh_sequence = sdp->sd_sequence + 1; + /* Don't care about tail */ + head.lh_last_dump = (elements) ? sdp->sd_log_dump_last : 0; + + /* Write out the shutdown header */ + + gfs_logbh_init(sdp, &lb->lb_bh, sdp->sd_log_head, bmem); + memset(bmem, 0, sdp->sd_sb.sb_bsize); + gfs_log_header_out(&head, lb->lb_bh.b_data); + gfs_log_header_out(&head, + lb->lb_bh.b_data + GFS_BASIC_BLOCK - + sizeof(struct gfs_log_header)); + gfs_logbh_start(sdp, &lb->lb_bh); + gfs_logbh_wait(sdp, &lb->lb_bh); + gfs_logbh_uninit(sdp, &lb->lb_bh); + + /* If a withdraw is called before we've a chance to relock the trans + * lock, the sd_log_head points to the wrong place, and a umount will + * fail on asserts because of this. + * Adding one puts sd_log_head at a value that passes the assert. The + * value may not be correct for on disk, but we've withdrawn so there is + * no more disk io. + * If we're not withdrawn, the next io will grab the trans lock, which + * will fill sd_log_head with the correct value. + */ + sdp->sd_log_head += 1; + + out: + gfs_log_unlock(sdp); + + kfree(lb); + kfree(bmem); +} --- linux-2.6.27.orig/ubuntu/gfs/inode.h +++ linux-2.6.27/ubuntu/gfs/inode.h @@ -0,0 +1,57 @@ +#ifndef __INODE_DOT_H__ +#define __INODE_DOT_H__ + +void gfs_inode_attr_in(struct gfs_inode *ip); +void gfs_inode_attr_out(struct gfs_inode *ip); +struct inode *gfs_iget(struct gfs_inode *ip, int create); + +int gfs_copyin_dinode(struct gfs_inode *ip); + +int gfs_inode_get(struct gfs_glock *i_gl, struct gfs_inum *inum, int create, + struct gfs_inode **ipp); +void gfs_inode_hold(struct gfs_inode *ip); +void gfs_inode_put(struct gfs_inode *ip); +void gfs_inode_destroy(struct gfs_inode *ip); + +int gfs_inode_dealloc(struct gfs_sbd *sdp, struct gfs_inum *inum); + +int gfs_change_nlink(struct gfs_inode *ip, int diff); +int gfs_lookupi(struct gfs_holder *d_gh, struct qstr *name, + int is_root, struct gfs_holder *i_gh); +int gfs_createi(struct gfs_holder *d_gh, struct qstr *name, + unsigned int type, unsigned int mode, + struct gfs_holder *i_gh); +int gfs_unlinki(struct gfs_inode *dip, struct qstr *name, struct gfs_inode *ip); +int gfs_rmdiri(struct gfs_inode *dip, struct qstr *name, struct gfs_inode *ip); +int gfs_unlink_ok(struct gfs_inode *dip, struct qstr *name, + struct gfs_inode *ip); +int gfs_ok_to_move(struct gfs_inode *this, struct gfs_inode *to); +int gfs_readlinki(struct gfs_inode *ip, char **buf, unsigned int *len); + +int gfs_glock_nq_atime(struct gfs_holder *gh); +int gfs_glock_nq_m_atime(unsigned int num_gh, struct gfs_holder *ghs); + +void gfs_try_toss_vnode(struct gfs_inode *ip); + +int gfs_setattr_simple(struct gfs_inode *ip, struct iattr *attr); + +/* Backwards compatibility functions */ + +int gfs_alloc_qinode(struct gfs_sbd *sdp); +int gfs_alloc_linode(struct gfs_sbd *sdp); + +/* Inlines */ + +static __inline__ int +gfs_is_stuffed(struct gfs_inode *ip) +{ + return !ip->i_di.di_height; +} + +static __inline__ int +gfs_is_jdata(struct gfs_inode *ip) +{ + return ip->i_di.di_flags & GFS_DIF_JDATA; +} + +#endif /* __INODE_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/gfs_ioctl.h +++ linux-2.6.27/ubuntu/gfs/gfs_ioctl.h @@ -0,0 +1,31 @@ +#ifndef __GFS_IOCTL_DOT_H__ +#define __GFS_IOCTL_DOT_H__ + +#define _GFSC_(x) (('G' << 8) | (x)) + +/* Ioctls implemented */ + +#define GFS_IOCTL_IDENTIFY _GFSC_(35) +#define GFS_IOCTL_SUPER _GFSC_(45) + +struct gfs_ioctl { + unsigned int gi_argc; + char **gi_argv; + + char __user *gi_data; + unsigned int gi_size; + uint64_t gi_offset; +}; + +#ifdef CONFIG_COMPAT +struct gfs_ioctl_compat { + unsigned int gi_argc; + uint32_t gi_argv; + + uint32_t gi_data; + unsigned int gi_size; + uint64_t gi_offset; +}; +#endif + +#endif /* ___GFS_IOCTL_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/main.c +++ linux-2.6.27/ubuntu/gfs/main.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "ops_fstype.h" +#include "sys.h" +#include "proc.h" + +/** + * init_gfs_fs - Register GFS as a filesystem + * + * Returns: 0 on success, error code on failure + */ + +int __init init_gfs_fs(void) +{ + int error; + struct timespec tv; + +/* gfs2_init_lmh(); gfs2 should do this for us*/ + + error = gfs_sys_init(); + if (error) + return error; + error = gfs_proc_init(); + if (error) + goto fail; + + getnstimeofday(&tv); + gfs_random_number = tv.tv_nsec; + + gfs_glock_cachep = kmem_cache_create("gfs_glock", sizeof(struct gfs_glock), + 0, 0, + NULL); + gfs_inode_cachep = NULL; + gfs_bufdata_cachep = NULL; + gfs_mhc_cachep = NULL; + error = -ENOMEM; + if (!gfs_glock_cachep) + goto fail1; + + gfs_inode_cachep = kmem_cache_create("gfs_inode", sizeof(struct gfs_inode), + 0, 0, + NULL); + if (!gfs_inode_cachep) + goto fail1; + + gfs_bufdata_cachep = kmem_cache_create("gfs_bufdata", sizeof(struct gfs_bufdata), + 0, 0, + NULL); + if (!gfs_bufdata_cachep) + goto fail1; + + gfs_mhc_cachep = kmem_cache_create("gfs_meta_header_cache", sizeof(struct gfs_meta_header_cache), + 0, 0, + NULL); + if (!gfs_mhc_cachep) + goto fail; + + error = register_filesystem(&gfs_fs_type); + if (error) + goto fail; + + printk("GFS %s (built %s %s) installed\n", + RELEASE_VERSION, __DATE__, __TIME__); + + error = init_lock_dlm(); + if (error) + goto fail1; + + error = init_nolock(); + if (error) + goto fail1; + + return 0; + + fail1: + if (gfs_mhc_cachep) + kmem_cache_destroy(gfs_mhc_cachep); + + if (gfs_bufdata_cachep) + kmem_cache_destroy(gfs_bufdata_cachep); + + if (gfs_inode_cachep) + kmem_cache_destroy(gfs_inode_cachep); + + if (gfs_glock_cachep) + kmem_cache_destroy(gfs_glock_cachep); + + gfs_proc_uninit(); + + fail: + gfs_sys_uninit(); + + return error; +} + +/** + * exit_gfs_fs - Unregister the file system + * + */ + +void __exit +exit_gfs_fs(void) +{ + exit_nolock(); + exit_lock_dlm(); + unregister_filesystem(&gfs_fs_type); + + kmem_cache_destroy(gfs_mhc_cachep); + kmem_cache_destroy(gfs_bufdata_cachep); + kmem_cache_destroy(gfs_inode_cachep); + kmem_cache_destroy(gfs_glock_cachep); + + gfs_proc_uninit(); + gfs_sys_uninit(); +} + +MODULE_DESCRIPTION("Global File System " RELEASE_VERSION); +MODULE_AUTHOR("Red Hat, Inc."); +MODULE_LICENSE("GPL"); + +module_init(init_gfs_fs); +module_exit(exit_gfs_fs); + --- linux-2.6.27.orig/ubuntu/gfs/dir.c +++ linux-2.6.27/ubuntu/gfs/dir.c @@ -0,0 +1,2394 @@ +/* +* Implements Extendible Hashing as described in: +* "Extendible Hashing" by Fagin, et al in +* __ACM Trans. on Database Systems__, Sept 1979. +* +* +* Here's the layout of dirents which is essentially the same as that of ext2 +* within a single block. The field de_name_len is the number of bytes +* actually required for the name (no null terminator). The field de_rec_len +* is the number of bytes allocated to the dirent. The offset of the next +* dirent in the block is (dirent + dirent->de_rec_len). When a dirent is +* deleted, the preceding dirent inherits its allocated space, ie +* prev->de_rec_len += deleted->de_rec_len. Since the next dirent is obtained +* by adding de_rec_len to the current dirent, this essentially causes the +* deleted dirent to get jumped over when iterating through all the dirents. +* +* When deleting the first dirent in a block, there is no previous dirent so +* the field de_ino is set to zero to designate it as deleted. When allocating +* a dirent, gfs_dirent_alloc iterates through the dirents in a block. If the +* first dirent has (de_ino == 0) and de_rec_len is large enough, this first +* dirent is allocated. Otherwise it must go through all the 'used' dirents +* searching for one in which the amount of total space minus the amount of +* used space will provide enough space for the new dirent. +* +* There are two types of blocks in which dirents reside. In a stuffed dinode, +* the dirents begin at offset sizeof(struct gfs_dinode) from the beginning of +* the block. In leaves, they begin at offset sizeof (struct gfs_leaf) from the +* beginning of the leaf block. The dirents reside in leaves when +* +* dip->i_di.di_flags & GFS_DIF_EXHASH is true +* +* Otherwise, the dirents are "linear", within a single stuffed dinode block. +* +* When the dirents are in leaves, the actual contents of the directory file are +* used as an array of 64-bit block pointers pointing to the leaf blocks. The +* dirents are NOT in the directory file itself. There can be more than one block +* pointer in the array that points to the same leaf. In fact, when a directory +* is first converted from linear to exhash, all of the pointers point to the +* same leaf. +* +* When a leaf is completely full, the size of the hash table can be +* doubled unless it is already at the maximum size which is hard coded into +* GFS_DIR_MAX_DEPTH. After that, leaves are chained together in a linked list, +* but never before the maximum hash table size has been reached. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "dio.h" +#include "dir.h" +#include "file.h" +#include "glock.h" +#include "inode.h" +#include "quota.h" +#include "rgrp.h" +#include "trans.h" + +#if 1 +#define gfs_dir_hash2offset(h) (((uint64_t)(h)) >> 1) +#define gfs_dir_offset2hash(p) ((uint32_t)(((uint64_t)(p)) << 1)) +#else +#define gfs_dir_hash2offset(h) (((uint64_t)(h))) +#define gfs_dir_offset2hash(p) ((uint32_t)(((uint64_t)(p)))) +#endif + +typedef int (*leaf_call_t) (struct gfs_inode *dip, + uint32_t index, uint32_t len, uint64_t leaf_no, + void *data); + +/** + * int gfs_filecmp - Compare two filenames + * @file1: The first filename + * @file2: The second filename + * @len_of_file2: The length of the second file + * + * This routine compares two filenames and returns TRUE if they are equal. + * + * Returns: TRUE (!=0) if the files are the same, otherwise FALSE (0). + */ + +int +gfs_filecmp(struct qstr *file1, char *file2, int len_of_file2) +{ + if (file1->len != len_of_file2) + return FALSE; + if (memcmp(file1->name, file2, file1->len)) + return FALSE; + return TRUE; +} + +/** + * dirent_first - Return the first dirent + * @dip: the directory + * @bh: The buffer + * @dent: Pointer to list of dirents + * + * return first dirent whether bh points to leaf or stuffed dinode + * + * Returns: IS_LEAF, IS_DINODE, or -errno + */ + +static int +dirent_first(struct gfs_inode *dip, struct buffer_head *bh, + struct gfs_dirent **dent) +{ + struct gfs_meta_header *h = (struct gfs_meta_header *)bh->b_data; + + if (gfs32_to_cpu(h->mh_type) == GFS_METATYPE_LF) { + if (gfs_meta_check(dip->i_sbd, bh)) + return -EIO; + *dent = (struct gfs_dirent *)(bh->b_data + sizeof(struct gfs_leaf)); + return IS_LEAF; + } else { + if (gfs_metatype_check(dip->i_sbd, bh, GFS_METATYPE_DI)) + return -EIO; + *dent = (struct gfs_dirent *)(bh->b_data + sizeof(struct gfs_dinode)); + return IS_DINODE; + } +} + +/** + * dirent_next - Next dirent + * @dip: the directory + * @bh: The buffer + * @dent: Pointer to list of dirents + * + * Returns: 0 on success, error code otherwise + */ + +static int +dirent_next(struct gfs_inode *dip, struct buffer_head *bh, + struct gfs_dirent **dent) +{ + struct gfs_dirent *tmp, *cur; + char *bh_end; + uint32_t cur_rec_len; + + cur = *dent; + bh_end = bh->b_data + bh->b_size; + cur_rec_len = gfs16_to_cpu(cur->de_rec_len); + + if ((char *)cur + cur_rec_len >= bh_end) { + if ((char *)cur + cur_rec_len > bh_end) { + gfs_consist_inode(dip); + return -EIO; + } + return -ENOENT; + } + + tmp = (struct gfs_dirent *)((char *)cur + cur_rec_len); + + if ((char *)tmp + gfs16_to_cpu(tmp->de_rec_len) > bh_end) { + gfs_consist_inode(dip); + return -EIO; + } + /* Only the first dent could ever have de_ino == 0 */ + if (!tmp->de_inum.no_formal_ino) { + gfs_consist_inode(dip); + return -EIO; + } + + *dent = tmp; + + return 0; +} + +/** + * dirent_del - Delete a dirent + * @dip: The GFS inode + * @bh: The buffer + * @prev: The previous dirent + * @cur: The current dirent + * + */ + +static void +dirent_del(struct gfs_inode *dip, struct buffer_head *bh, + struct gfs_dirent *prev, struct gfs_dirent *cur) +{ + uint32_t cur_rec_len, prev_rec_len; + + if (!cur->de_inum.no_formal_ino) { + gfs_consist_inode(dip); + return; + } + + gfs_trans_add_bh(dip->i_gl, bh); + + /* If there is no prev entry, this is the first entry in the block. + The de_rec_len is already as big as it needs to be. Just zero + out the inode number and return. */ + + if (!prev) { + cur->de_inum.no_formal_ino = 0; /* No endianess worries */ + return; + } + + /* Combine this dentry with the previous one. */ + + prev_rec_len = gfs16_to_cpu(prev->de_rec_len); + cur_rec_len = gfs16_to_cpu(cur->de_rec_len); + + if ((char *)prev + prev_rec_len != (char *)cur) + gfs_consist_inode(dip); + if ((char *)cur + cur_rec_len > bh->b_data + bh->b_size) + gfs_consist_inode(dip); + + prev_rec_len += cur_rec_len; + prev->de_rec_len = cpu_to_gfs16(prev_rec_len); +} + +/** + * gfs_dirent_alloc - Allocate a directory entry + * @dip: The GFS inode + * @bh: The buffer + * @name_len: The length of the name + * @dent_out: Pointer to list of dirents + * + * Returns: 0 on success, error code otherwise + */ + +int +gfs_dirent_alloc(struct gfs_inode *dip, struct buffer_head *bh, int name_len, + struct gfs_dirent **dent_out) +{ + struct gfs_dirent *dent, *new; + unsigned int rec_len = GFS_DIRENT_SIZE(name_len); + unsigned int entries = 0, offset = 0; + int type; + + type = dirent_first(dip, bh, &dent); + if (type < 0) + return type; + + if (type == IS_LEAF) { + struct gfs_leaf *leaf = (struct gfs_leaf *)bh->b_data; + entries = gfs16_to_cpu(leaf->lf_entries); + offset = sizeof(struct gfs_leaf); + } else { + struct gfs_dinode *dinode = (struct gfs_dinode *)bh->b_data; + entries = gfs32_to_cpu(dinode->di_entries); + offset = sizeof(struct gfs_dinode); + } + + if (!entries) { + if (dent->de_inum.no_formal_ino) { + gfs_consist_inode(dip); + return -EIO; + } + + gfs_trans_add_bh(dip->i_gl, bh); + + dent->de_rec_len = bh->b_size - offset; + dent->de_rec_len = cpu_to_gfs16(dent->de_rec_len); + dent->de_name_len = cpu_to_gfs16(name_len); + + *dent_out = dent; + return 0; + } + + do { + uint32_t cur_rec_len, cur_name_len; + + cur_rec_len = gfs16_to_cpu(dent->de_rec_len); + cur_name_len = gfs16_to_cpu(dent->de_name_len); + + if ((!dent->de_inum.no_formal_ino && cur_rec_len >= rec_len) || + (cur_rec_len >= GFS_DIRENT_SIZE(cur_name_len) + rec_len)) { + gfs_trans_add_bh(dip->i_gl, bh); + + if (dent->de_inum.no_formal_ino) { + new = (struct gfs_dirent *)((char *)dent + + GFS_DIRENT_SIZE(cur_name_len)); + memset(new, 0, sizeof(struct gfs_dirent)); + + new->de_rec_len = cpu_to_gfs16(cur_rec_len - + GFS_DIRENT_SIZE(cur_name_len)); + new->de_name_len = cpu_to_gfs16(name_len); + + dent->de_rec_len = cur_rec_len - gfs16_to_cpu(new->de_rec_len); + dent->de_rec_len = cpu_to_gfs16(dent->de_rec_len); + + *dent_out = new; + return 0; + } + + dent->de_name_len = cpu_to_gfs16(name_len); + + *dent_out = dent; + return 0; + } + } while (dirent_next(dip, bh, &dent) == 0); + + return -ENOSPC; +} + +/** + * dirent_fits - See if we can fit a entry in this buffer + * @dip: The GFS inode + * @bh: The buffer + * @name_len: The length of the name + * + * Returns: TRUE if it can fit, FALSE otherwise + */ + +static int +dirent_fits(struct gfs_inode *dip, struct buffer_head *bh, int name_len) +{ + struct gfs_dirent *dent; + unsigned int rec_len = GFS_DIRENT_SIZE(name_len); + unsigned int entries = 0; + int type; + + type = dirent_first(dip, bh, &dent); + if (type < 0) + return type; + + if (type == IS_LEAF) { + struct gfs_leaf *leaf = (struct gfs_leaf *)bh->b_data; + entries = gfs16_to_cpu(leaf->lf_entries); + } else { + struct gfs_dinode *dinode = (struct gfs_dinode *)bh->b_data; + entries = gfs32_to_cpu(dinode->di_entries); + } + + if (!entries) + return TRUE; + + do { + uint32_t cur_rec_len, cur_name_len; + + cur_rec_len = gfs16_to_cpu(dent->de_rec_len); + cur_name_len = gfs16_to_cpu(dent->de_name_len); + + if ((!dent->de_inum.no_formal_ino && cur_rec_len >= rec_len) || + (cur_rec_len >= GFS_DIRENT_SIZE(cur_name_len) + rec_len)) + return TRUE; + } while (dirent_next(dip, bh, &dent) == 0); + + return FALSE; +} + +/** + * leaf_search + * @bh: + * @filename: + * @dent_out: + * @dent_prev: + * + * Returns: + */ + +static int +leaf_search(struct gfs_inode *dip, + struct buffer_head *bh, struct qstr *filename, + struct gfs_dirent **dent_out, struct gfs_dirent **dent_prev) +{ + uint32_t hash; + struct gfs_dirent *dent, *prev = NULL; + unsigned int entries = 0; + int type; + + type = dirent_first(dip, bh, &dent); + if (type < 0) + return type; + + if (type == IS_LEAF) { + struct gfs_leaf *leaf = (struct gfs_leaf *)bh->b_data; + entries = gfs16_to_cpu(leaf->lf_entries); + } else if (type == IS_DINODE) { + struct gfs_dinode *dinode = (struct gfs_dinode *)bh->b_data; + entries = gfs32_to_cpu(dinode->di_entries); + } + + hash = gfs_dir_hash(filename->name, filename->len); + + do { + if (!dent->de_inum.no_formal_ino) { + prev = dent; + continue; + } + + if (gfs32_to_cpu(dent->de_hash) == hash && + gfs_filecmp(filename, (char *)(dent + 1), + gfs16_to_cpu(dent->de_name_len))) { + *dent_out = dent; + if (dent_prev) + *dent_prev = prev; + + return 0; + } + + prev = dent; + } while (dirent_next(dip, bh, &dent) == 0); + + return -ENOENT; +} + +/** + * get_leaf - Get leaf + * @dip: + * @leaf_no: + * @bh_out: + * + * Returns: 0 on success, error code otherwise + */ + +static int +get_leaf(struct gfs_inode *dip, uint64_t leaf_no, struct buffer_head **bhp) +{ + int error; + + error = gfs_dread(dip->i_gl, leaf_no, DIO_START | DIO_WAIT, bhp); + if (!error && gfs_metatype_check(dip->i_sbd, *bhp, GFS_METATYPE_LF)) + error = -EIO; + + return error; +} + +/** + * get_leaf_nr - Get a leaf number associated with the index + * @dip: The GFS inode + * @index: + * @leaf_out: + * + * Returns: 0 on success, error code otherwise + */ + +static int +get_leaf_nr(struct gfs_inode *dip, uint32_t index, uint64_t *leaf_out) +{ + uint64_t leaf_no; + int error; + + error = gfs_internal_read(dip, (char *)&leaf_no, + index * sizeof(uint64_t), + sizeof(uint64_t)); + if (error != sizeof(uint64_t)) + return (error < 0) ? error : -EIO; + + *leaf_out = gfs64_to_cpu(leaf_no); + + return 0; +} + +/** + * get_first_leaf - Get first leaf + * @dip: The GFS inode + * @index: + * @bh_out: + * + * Returns: 0 on success, error code otherwise + */ + +static int +get_first_leaf(struct gfs_inode *dip, uint32_t index, + struct buffer_head **bh_out) +{ + uint64_t leaf_no; + int error; + + error = get_leaf_nr(dip, index, &leaf_no); + if (!error) + error = get_leaf(dip, leaf_no, bh_out); + + return error; +} + +/** + * get_next_leaf - Get next leaf + * @dip: The GFS inode + * @bh_in: The buffer + * @bh_out: + * + * Returns: 0 on success, error code otherwise + */ + +static int +get_next_leaf(struct gfs_inode *dip, struct buffer_head *bh_in, + struct buffer_head **bh_out) +{ + struct gfs_leaf *leaf; + int error; + + leaf = (struct gfs_leaf *)bh_in->b_data; + + if (!leaf->lf_next) + error = -ENOENT; + else + error = get_leaf(dip, gfs64_to_cpu(leaf->lf_next), bh_out); + + return error; +} + +/** + * linked_leaf_search - Linked leaf search + * @dip: The GFS inode + * @filename: The filename to search for + * @dent_out: + * @dent_prev: + * @bh_out: + * + * Returns: 0 on sucess, error code otherwise + */ + +static int +linked_leaf_search(struct gfs_inode *dip, struct qstr *filename, + struct gfs_dirent **dent_out, struct gfs_dirent **dent_prev, + struct buffer_head **bh_out) +{ + struct buffer_head *bh = NULL, *bh_next; + uint32_t hsize, index; + uint32_t hash; + int error; + + hsize = 1 << dip->i_di.di_depth; + if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { + gfs_consist_inode(dip); + return -EIO; + } + + /* Figure out the address of the leaf node. */ + + hash = gfs_dir_hash(filename->name, filename->len); + index = hash >> (32 - dip->i_di.di_depth); + + error = get_first_leaf(dip, index, &bh_next); + if (error) + return error; + + /* Find the entry */ + + do { + if (bh) + brelse(bh); + + bh = bh_next; + + error = leaf_search(dip, bh, filename, dent_out, dent_prev); + switch (error) { + case 0: + *bh_out = bh; + return 0; + + case -ENOENT: + break; + + default: + brelse(bh); + return error; + } + + error = get_next_leaf(dip, bh, &bh_next); + } + while (!error); + + brelse(bh); + + return error; +} + +/** + * dir_make_exhash - Convert a stuffed directory into an ExHash directory + * @dip: The GFS inode + * + * Returns: 0 on success, error code otherwise + */ + +static int +dir_make_exhash(struct gfs_inode *dip) +{ + struct gfs_sbd *sdp = dip->i_sbd; + struct gfs_dirent *dent; + struct buffer_head *bh, *dibh; + struct gfs_leaf *leaf; + int y; + uint32_t x; + uint64_t *lp, bn; + int error; + + error = gfs_get_inode_buffer(dip, &dibh); + if (error) + return error; + + /* Allocate a new block for the first leaf node */ + + error = gfs_metaalloc(dip, &bn); + if (error) + goto fail; + + /* Turn over a new leaf */ + + error = gfs_dread(dip->i_gl, bn, DIO_NEW | DIO_START | DIO_WAIT, &bh); + if (error) + goto fail; + + gfs_trans_add_bh(dip->i_gl, bh); + gfs_metatype_set(bh, GFS_METATYPE_LF, GFS_FORMAT_LF); + gfs_buffer_clear_tail(bh, sizeof(struct gfs_meta_header)); + + /* Fill in the leaf structure */ + + leaf = (struct gfs_leaf *)bh->b_data; + + gfs_assert(sdp, dip->i_di.di_entries < (1 << 16),); + + leaf->lf_dirent_format = cpu_to_gfs32(GFS_FORMAT_DE); + leaf->lf_entries = cpu_to_gfs16(dip->i_di.di_entries); + + /* Copy dirents */ + + gfs_buffer_copy_tail(bh, sizeof(struct gfs_leaf), dibh, + sizeof(struct gfs_dinode)); + + /* Find last entry */ + + x = 0; + dirent_first(dip, bh, &dent); + + do { + if (!dent->de_inum.no_formal_ino) + continue; + if (++x == dip->i_di.di_entries) + break; + } + while (dirent_next(dip, bh, &dent) == 0); + + /* Adjust the last dirent's record length + (Remember that dent still points to the last entry.) */ + + dent->de_rec_len = gfs16_to_cpu(dent->de_rec_len) + + sizeof(struct gfs_dinode) - + sizeof(struct gfs_leaf); + dent->de_rec_len = cpu_to_gfs16(dent->de_rec_len); + + brelse(bh); + + /* We're done with the new leaf block, now setup the new + hash table. */ + + gfs_trans_add_bh(dip->i_gl, dibh); + gfs_buffer_clear_tail(dibh, sizeof (struct gfs_dinode)); + + lp = (uint64_t *)(dibh->b_data + sizeof(struct gfs_dinode)); + + for (x = sdp->sd_hash_ptrs; x--; lp++) + *lp = cpu_to_gfs64(bn); + + dip->i_di.di_size = sdp->sd_sb.sb_bsize / 2; + dip->i_di.di_blocks++; + dip->i_di.di_flags |= GFS_DIF_EXHASH; + dip->i_di.di_payload_format = 0; + + for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ; + dip->i_di.di_depth = y; + + gfs_dinode_out(&dip->i_di, dibh->b_data); + + brelse(dibh); + + return 0; + + fail: + brelse(dibh); + return error; +} + +/** + * dir_split_leaf - Split a leaf block into two + * @dip: The GFS inode + * @index: + * @leaf_no: + * + * Returns: 0 on success, error code on failure + */ + +static int +dir_split_leaf(struct gfs_inode *dip, uint32_t index, uint64_t leaf_no) +{ + struct buffer_head *nbh, *obh, *dibh; + struct gfs_leaf *nleaf, *oleaf; + struct gfs_dirent *dent, *prev = NULL, *next = NULL, *new; + uint32_t start, len, half_len, divider; + uint64_t bn, *lp; + uint32_t name_len; + int x, moved = FALSE; + int error, lp_vfree=0; + + /* Allocate the new leaf block */ + + error = gfs_metaalloc(dip, &bn); + if (error) + return error; + + /* Get the new leaf block */ + + error = gfs_dread(dip->i_gl, bn, + DIO_NEW | DIO_START | DIO_WAIT, &nbh); + if (error) + return error; + + gfs_trans_add_bh(dip->i_gl, nbh); + gfs_metatype_set(nbh, GFS_METATYPE_LF, GFS_FORMAT_LF); + gfs_buffer_clear_tail(nbh, sizeof (struct gfs_meta_header)); + + nleaf = (struct gfs_leaf *)nbh->b_data; + + nleaf->lf_dirent_format = cpu_to_gfs32(GFS_FORMAT_DE); + + /* Get the old leaf block */ + + error = get_leaf(dip, leaf_no, &obh); + if (error) + goto fail; + + gfs_trans_add_bh(dip->i_gl, obh); + + oleaf = (struct gfs_leaf *)obh->b_data; + + /* Compute the start and len of leaf pointers in the hash table. */ + + len = 1 << (dip->i_di.di_depth - gfs16_to_cpu(oleaf->lf_depth)); + half_len = len >> 1; + if (!half_len) { + gfs_consist_inode(dip); + error = -EIO; + goto fail_brelse; + } + + start = (index & ~(len - 1)); + + /* Change the pointers. + Don't bother distinguishing stuffed from non-stuffed. + This code is complicated enough already. */ + + lp = kmalloc(half_len * sizeof (uint64_t), GFP_KERNEL); + if (unlikely(!lp)) { + lp = vmalloc(half_len * sizeof (uint64_t)); + if (!lp) { + printk("GFS: dir_split_leaf vmalloc fail - half_len=%d\n", half_len); + error = -ENOMEM; + goto fail_brelse; + } else + lp_vfree = 1; + } + + error = gfs_internal_read(dip, (char *)lp, start * sizeof(uint64_t), + half_len * sizeof(uint64_t)); + if (error != half_len * sizeof(uint64_t)) { + if (error >= 0) + error = -EIO; + goto fail_lpfree; + } + + /* Change the pointers */ + + for (x = 0; x < half_len; x++) + lp[x] = cpu_to_gfs64(bn); + + error = gfs_internal_write(dip, (char *)lp, start * sizeof(uint64_t), + half_len * sizeof(uint64_t)); + if (error != half_len * sizeof(uint64_t)) { + if (error >= 0) + error = -EIO; + goto fail_lpfree; + } + + if (unlikely(lp_vfree)) + vfree(lp); + else + kfree(lp); + + /* Compute the divider */ + + divider = (start + half_len) << (32 - dip->i_di.di_depth); + + /* Copy the entries */ + + dirent_first(dip, obh, &dent); + + do { + next = dent; + if (dirent_next(dip, obh, &next)) + next = NULL; + + if (dent->de_inum.no_formal_ino && + gfs32_to_cpu(dent->de_hash) < divider) { + name_len = gfs16_to_cpu(dent->de_name_len); + + gfs_dirent_alloc(dip, nbh, name_len, &new); + + new->de_inum = dent->de_inum; /* No endianness worries */ + new->de_hash = dent->de_hash; /* No endianness worries */ + new->de_type = dent->de_type; /* No endianness worries */ + memcpy((char *)(new + 1), (char *)(dent + 1), + name_len); + + nleaf->lf_entries = gfs16_to_cpu(nleaf->lf_entries) + 1; + nleaf->lf_entries = cpu_to_gfs16(nleaf->lf_entries); + + dirent_del(dip, obh, prev, dent); + + if (!oleaf->lf_entries) + gfs_consist_inode(dip); + oleaf->lf_entries = gfs16_to_cpu(oleaf->lf_entries) - 1; + oleaf->lf_entries = cpu_to_gfs16(oleaf->lf_entries); + + if (!prev) + prev = dent; + + moved = TRUE; + } else + prev = dent; + + dent = next; + } + while (dent); + + /* If none of the entries got moved into the new leaf, + artificially fill in the first entry. */ + + if (!moved) { + gfs_dirent_alloc(dip, nbh, 0, &new); + new->de_inum.no_formal_ino = 0; + } + + oleaf->lf_depth = gfs16_to_cpu(oleaf->lf_depth) + 1; + oleaf->lf_depth = cpu_to_gfs16(oleaf->lf_depth); + nleaf->lf_depth = oleaf->lf_depth; + + error = gfs_get_inode_buffer(dip, &dibh); + if (!gfs_assert_withdraw(dip->i_sbd, !error)) { + dip->i_di.di_blocks++; + gfs_dinode_out(&dip->i_di, dibh->b_data); + brelse(dibh); + } + + brelse(obh); + brelse(nbh); + + return error; + + fail_lpfree: + if (unlikely(lp_vfree)) + vfree(lp); + else + kfree(lp); + + fail_brelse: + brelse(obh); + + fail: + brelse(nbh); + return error; +} + +/** + * dir_double_exhash - Double size of ExHash table + * @dip: The GFS dinode + * + * Returns: 0 on success, error code on failure + */ + +static int +dir_double_exhash(struct gfs_inode *dip) +{ + struct gfs_sbd *sdp = dip->i_sbd; + struct buffer_head *dibh; + uint32_t hsize; + uint64_t *buf; + uint64_t *from, *to; + uint64_t block; + int x; + int error = 0; + + hsize = 1 << dip->i_di.di_depth; + if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { + gfs_consist_inode(dip); + return -EIO; + } + + /* Allocate both the "from" and "to" buffers in one big chunk */ + + buf = gmalloc(3 * sdp->sd_hash_bsize); + + for (block = dip->i_di.di_size >> sdp->sd_hash_bsize_shift; block--;) { + error = gfs_internal_read(dip, (char *)buf, + block * sdp->sd_hash_bsize, + sdp->sd_hash_bsize); + if (error != sdp->sd_hash_bsize) { + if (error >= 0) + error = -EIO; + goto fail; + } + + from = buf; + to = (uint64_t *)((char *)buf + sdp->sd_hash_bsize); + + for (x = sdp->sd_hash_ptrs; x--; from++) { + *to++ = *from; /* No endianess worries */ + *to++ = *from; + } + + error = gfs_internal_write(dip, (char *)buf + sdp->sd_hash_bsize, + block * sdp->sd_sb.sb_bsize, + sdp->sd_sb.sb_bsize); + if (error != sdp->sd_sb.sb_bsize) { + if (error >= 0) + error = -EIO; + goto fail; + } + } + + kfree(buf); + + error = gfs_get_inode_buffer(dip, &dibh); + if (!gfs_assert_withdraw(sdp, !error)) { + dip->i_di.di_depth++; + gfs_dinode_out(&dip->i_di, dibh->b_data); + brelse(dibh); + } + + return error; + + fail: + kfree(buf); + + return error; +} + +/** + * compare_dents - compare directory entries by hash value + * @a: first dent + * @b: second dent + * + * When comparing the hash entries of @a to @b: + * gt: returns 1 + * lt: returns -1 + * eq: returns 0 + */ + +static int +compare_dents(const void *a, const void *b) +{ + struct gfs_dirent *dent_a, *dent_b; + uint32_t hash_a, hash_b; + int ret = 0; + + dent_a = *(struct gfs_dirent **)a; + hash_a = dent_a->de_hash; + hash_a = gfs32_to_cpu(hash_a); + + dent_b = *(struct gfs_dirent **)b; + hash_b = dent_b->de_hash; + hash_b = gfs32_to_cpu(hash_b); + + if (hash_a > hash_b) + ret = 1; + else if (hash_a < hash_b) + ret = -1; + else { + unsigned int len_a = gfs16_to_cpu(dent_a->de_name_len); + unsigned int len_b = gfs16_to_cpu(dent_b->de_name_len); + + if (len_a > len_b) + ret = 1; + else if (len_a < len_b) + ret = -1; + else + ret = memcmp((char *)(dent_a + 1), + (char *)(dent_b + 1), + len_a); + } + + return ret; +} + +/** + * do_filldir_main - read out directory entries + * @dip: The GFS inode + * @offset: The offset in the file to read from + * @opaque: opaque data to pass to filldir + * @filldir: The function to pass entries to + * @darr: an array of struct gfs_dirent pointers to read + * @entries: the number of entries in darr + * @copied: pointer to int that's non-zero if a entry has been copied out + * + * Jump through some hoops to make sure that if there are hash collsions, + * they are read out at the beginning of a buffer. We want to minimize + * the possibility that they will fall into different readdir buffers or + * that someone will want to seek to that location. + * + * Returns: errno, >0 on exception from filldir + */ + +static int +do_filldir_main(struct gfs_inode *dip, uint64_t *offset, + void *opaque, gfs_filldir_t filldir, + struct gfs_dirent **darr, uint32_t entries, int *copied) +{ + struct gfs_dirent *dent, *dent_next; + struct gfs_inum inum; + uint64_t off, off_next; + unsigned int x, y; + int run = FALSE; + int error = 0; + + gfs_sort(darr, entries, sizeof(struct gfs_dirent *), compare_dents); + + dent_next = darr[0]; + off_next = gfs32_to_cpu(dent_next->de_hash); + off_next = gfs_dir_hash2offset(off_next); + + for (x = 0, y = 1; x < entries; x++, y++) { + dent = dent_next; + off = off_next; + + if (y < entries) { + dent_next = darr[y]; + off_next = gfs32_to_cpu(dent_next->de_hash); + off_next = gfs_dir_hash2offset(off_next); + + if (off < *offset) + continue; + *offset = off; + + if (off_next == off) { + if (*copied && !run) + return 1; + run = TRUE; + } else + run = FALSE; + } else { + if (off < *offset) + continue; + *offset = off; + } + + gfs_inum_in(&inum, (char *)&dent->de_inum); + + error = filldir(opaque, (char *)(dent + 1), + gfs16_to_cpu(dent->de_name_len), + off, &inum, + gfs16_to_cpu(dent->de_type)); + if (error) + return 1; + + *copied = TRUE; + } + + /* Increment the *offset by one, so the next time we come into the do_filldir fxn, + we get the next entry instead of the last one in the current leaf */ + + (*offset)++; + + return 0; +} + +/** + * do_filldir_single - Read directory entries out of a single block + * @dip: The GFS inode + * @offset: The offset in the file to read from + * @opaque: opaque data to pass to filldir + * @filldir: The function to pass entries to + * @bh: the block + * @entries: the number of entries in the block + * @copied: pointer to int that's non-zero if a entry has been copied out + * + * Returns: errno, >0 on exception from filldir + */ + +static int +do_filldir_single(struct gfs_inode *dip, uint64_t *offset, + void *opaque, gfs_filldir_t filldir, + struct buffer_head *bh, uint32_t entries, int *copied) +{ + struct gfs_dirent **darr; + struct gfs_dirent *de; + unsigned int e = 0; + int error, do_vfree=0; + + if (!entries) + return 0; + + darr = kmalloc(entries * sizeof(struct gfs_dirent *), GFP_KERNEL); + if (unlikely(!darr)) { + darr = vmalloc(entries * sizeof (struct gfs_dirent *)); + if (!darr) { + printk("GFS: do_filldir_single vmalloc fails, entries=%d\n", entries); + return -ENOMEM; + } + else + do_vfree = 1; + } + + dirent_first(dip, bh, &de); + do { + if (!de->de_inum.no_formal_ino) + continue; + if (e >= entries) { + gfs_consist_inode(dip); + error = -EIO; + goto out; + } + darr[e++] = de; + } + while (dirent_next(dip, bh, &de) == 0); + + if (e != entries) { + gfs_consist_inode(dip); + error = -EIO; + goto out; + } + + error = do_filldir_main(dip, offset, opaque, filldir, darr, + entries, copied); + + out: + if (unlikely(do_vfree)) + vfree(darr); + else + kfree(darr); + + return error; +} + +/** + * do_filldir_multi - Read directory entries out of a linked leaf list + * @dip: The GFS inode + * @offset: The offset in the file to read from + * @opaque: opaque data to pass to filldir + * @filldir: The function to pass entries to + * @bh: the first leaf in the list + * @copied: pointer to int that's non-zero if a entry has been copied out + * + * Returns: errno, >0 on exception from filldir + */ + +static int +do_filldir_multi(struct gfs_inode *dip, uint64_t *offset, + void *opaque, gfs_filldir_t filldir, + struct buffer_head *bh, int *copied) +{ + struct buffer_head **larr = NULL; + struct gfs_dirent **darr; + struct gfs_leaf *leaf; + struct buffer_head *tmp_bh; + struct gfs_dirent *de; + unsigned int entries, e = 0; + unsigned int leaves = 0, l = 0; + unsigned int x; + uint64_t ln; + int error = 0, leaves_vfree=0, entries_vfree=0; + + /* Count leaves and entries */ + + leaf = (struct gfs_leaf *)bh->b_data; + entries = gfs16_to_cpu(leaf->lf_entries); + ln = leaf->lf_next; + + while (ln) { + ln = gfs64_to_cpu(ln); + + error = get_leaf(dip, ln, &tmp_bh); + if (error) + return error; + + leaf = (struct gfs_leaf *)tmp_bh->b_data; + if (leaf->lf_entries) { + entries += gfs16_to_cpu(leaf->lf_entries); + leaves++; + } + ln = leaf->lf_next; + + brelse(tmp_bh); + } + + /* Bail out if there's nothing to do */ + + if (!entries) + return 0; + + /* Alloc arrays */ + + if (leaves) { + larr = kmalloc(leaves * sizeof(struct buffer_head *), GFP_KERNEL); + if (unlikely(!larr)) { + larr = vmalloc(leaves * sizeof (struct buffer_head *)); + if (!larr) { + printk("GFS: do_filldir_multi vmalloc fails leaves=%d\n", leaves); + return -ENOMEM; + } else + leaves_vfree = 1; + } + } + + darr = kmalloc(entries * sizeof(struct gfs_dirent *), GFP_KERNEL); + if (unlikely(!darr)) { + darr = vmalloc(entries * sizeof (struct gfs_dirent *)); + if (!darr) { + printk("GFS: do_filldir_multi vmalloc fails entries=%d\n", entries); + if (larr) { + if (leaves_vfree) + vfree(larr); + else + kfree(larr); + } + return -ENOMEM; + } else + entries_vfree = 1; + } + if (!darr) { + if (larr) + kfree(larr); + return -ENOMEM; + } + + /* Fill in arrays */ + + leaf = (struct gfs_leaf *)bh->b_data; + if (leaf->lf_entries) { + dirent_first(dip, bh, &de); + do { + if (!de->de_inum.no_formal_ino) + continue; + if (e >= entries) { + gfs_consist_inode(dip); + error = -EIO; + goto out; + } + darr[e++] = de; + } + while (dirent_next(dip, bh, &de) == 0); + } + ln = leaf->lf_next; + + while (ln) { + ln = gfs64_to_cpu(ln); + + error = get_leaf(dip, ln, &tmp_bh); + if (error) + goto out; + + leaf = (struct gfs_leaf *)tmp_bh->b_data; + if (leaf->lf_entries) { + dirent_first(dip, tmp_bh, &de); + do { + if (!de->de_inum.no_formal_ino) + continue; + if (e >= entries) { + gfs_consist_inode(dip); + error = -EIO; + goto out; + } + darr[e++] = de; + } + while (dirent_next(dip, tmp_bh, &de) == 0); + + larr[l++] = tmp_bh; + + ln = leaf->lf_next; + } else { + ln = leaf->lf_next; + brelse(tmp_bh); + } + } + + if (gfs_assert_withdraw(dip->i_sbd, l == leaves)) { + error = -EIO; + goto out; + } + if (e != entries) { + gfs_consist_inode(dip); + error = -EIO; + goto out; + } + + /* Do work */ + + error = do_filldir_main(dip, offset, opaque, filldir, darr, + entries, copied); + + /* Clean up */ + + out: + if (unlikely(entries_vfree)) + vfree(darr); + else + kfree(darr); + + for (x = 0; x < l; x++) + brelse(larr[x]); + + if (leaves) { + if (unlikely(leaves_vfree)) + vfree(larr); + else + kfree(larr); + } + + return error; +} + +/** + * dir_e_search - Search exhash (leaf) dir for inode matching name + * @dip: The GFS inode + * @filename: Filename string + * @inode: If non-NULL, function fills with formal inode # and block address + * @type: If non-NULL, function fills with GFS_FILE_... dinode type + * + * Returns: + */ + +static int +dir_e_search(struct gfs_inode *dip, struct qstr *filename, + struct gfs_inum *inum, unsigned int *type) +{ + struct buffer_head *bh; + struct gfs_dirent *dent; + int error; + + error = linked_leaf_search(dip, filename, &dent, NULL, &bh); + if (error) + return error; + + if (inum) + gfs_inum_in(inum, (char *)&dent->de_inum); + if (type) + *type = gfs16_to_cpu(dent->de_type); + + brelse(bh); + + return 0; +} + +/** + * dir_e_add - + * @dip: The GFS inode + * @filename: + * @inode: + * @type: + * + */ + +static int +dir_e_add(struct gfs_inode *dip, struct qstr *filename, + struct gfs_inum *inum, unsigned int type) +{ + struct buffer_head *bh, *nbh, *dibh; + struct gfs_leaf *leaf, *nleaf; + struct gfs_dirent *dent; + uint32_t hsize, index; + uint32_t hash; + uint64_t leaf_no, bn; + int error; + + restart: + hsize = 1 << dip->i_di.di_depth; + if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { + gfs_consist_inode(dip); + return -EIO; + } + + /* Figure out the address of the leaf node. */ + + hash = gfs_dir_hash(filename->name, filename->len); + index = hash >> (32 - dip->i_di.di_depth); + + error = get_leaf_nr(dip, index, &leaf_no); + if (error) + return error; + + /* Add entry to the leaf */ + + for (;;) { + error = get_leaf(dip, leaf_no, &bh); + if (error) + return error; + + leaf = (struct gfs_leaf *)bh->b_data; + + if (gfs_dirent_alloc(dip, bh, filename->len, &dent)) { + + if (gfs16_to_cpu(leaf->lf_depth) < dip->i_di.di_depth) { + /* Can we split the leaf? */ + + brelse(bh); + + error = dir_split_leaf(dip, index, leaf_no); + if (error) + return error; + + goto restart; + + } else if (dip->i_di.di_depth < GFS_DIR_MAX_DEPTH) { + /* Can we double the hash table? */ + + brelse(bh); + + error = dir_double_exhash(dip); + if (error) + return error; + + goto restart; + + } else if (leaf->lf_next) { + /* Can we try the next leaf in the list? */ + leaf_no = gfs64_to_cpu(leaf->lf_next); + brelse(bh); + continue; + + } else { + /* Create a new leaf and add it to the list. */ + + error = gfs_metaalloc(dip, &bn); + if (error) { + brelse(bh); + return error; + } + + error = gfs_dread(dip->i_gl, bn, + DIO_NEW | DIO_START | DIO_WAIT, + &nbh); + if (error) { + brelse(bh); + return error; + } + + gfs_trans_add_bh(dip->i_gl, nbh); + gfs_metatype_set(nbh, + GFS_METATYPE_LF, + GFS_FORMAT_LF); + gfs_buffer_clear_tail(nbh, + sizeof(struct gfs_meta_header)); + + gfs_trans_add_bh(dip->i_gl, bh); + leaf->lf_next = cpu_to_gfs64(bn); + + nleaf = (struct gfs_leaf *)nbh->b_data; + nleaf->lf_depth = leaf->lf_depth; + nleaf->lf_dirent_format = cpu_to_gfs32(GFS_FORMAT_DE); + + gfs_dirent_alloc(dip, nbh, filename->len, &dent); + + dip->i_di.di_blocks++; + + brelse(bh); + + bh = nbh; + leaf = nleaf; + } + } + + /* If the gfs_dirent_alloc() succeeded, it pinned the "bh". */ + + gfs_inum_out(inum, (char *)&dent->de_inum); + dent->de_hash = cpu_to_gfs32(hash); + dent->de_type = cpu_to_gfs16(type); + memcpy((char *)(dent + 1), filename->name, filename->len); + + leaf->lf_entries = gfs16_to_cpu(leaf->lf_entries) + 1; + leaf->lf_entries = cpu_to_gfs16(leaf->lf_entries); + + brelse(bh); + + error = gfs_get_inode_buffer(dip, &dibh); + if (error) + return error; + + dip->i_di.di_entries++; + dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); + + gfs_trans_add_bh(dip->i_gl, dibh); + gfs_dinode_out(&dip->i_di, dibh->b_data); + brelse(dibh); + + return 0; + } + + return -ENOENT; +} + +/** + * dir_e_del - + * @dip: The GFS inode + * @filename: + * + * Returns: + */ + +static int +dir_e_del(struct gfs_inode *dip, struct qstr *filename) +{ + struct buffer_head *bh, *dibh; + struct gfs_dirent *dent, *prev; + struct gfs_leaf *leaf; + unsigned int entries; + int error; + + error = linked_leaf_search(dip, filename, &dent, &prev, &bh); + if (error == -ENOENT) { + gfs_consist_inode(dip); + return -EIO; + } + if (error) + return error; + + dirent_del(dip, bh, prev, dent); /* Pins bh */ + + leaf = (struct gfs_leaf *)bh->b_data; + entries = gfs16_to_cpu(leaf->lf_entries); + if (!entries) + gfs_consist_inode(dip); + entries--; + leaf->lf_entries = cpu_to_gfs16(entries); + + brelse(bh); + + error = gfs_get_inode_buffer(dip, &dibh); + if (error) + return error; + + if (!dip->i_di.di_entries) + gfs_consist_inode(dip); + dip->i_di.di_entries--; + dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); + + gfs_trans_add_bh(dip->i_gl, dibh); + gfs_dinode_out(&dip->i_di, dibh->b_data); + brelse(dibh); + + return 0; +} + +/** + * dir_e_read - Reads the entries from a directory into a filldir buffer + * @dip: dinode pointer + * @offset: the hash of the last entry read shifted to the right once + * @opaque: buffer for the filldir function to fill + * @filldir: points to the filldir function to use + * + * Returns: errno + */ + +static int +dir_e_read(struct gfs_inode *dip, uint64_t *offset, void *opaque, + gfs_filldir_t filldir) +{ + struct gfs_sbd *sdp = dip->i_sbd; + struct buffer_head *bh; + struct gfs_leaf leaf; + uint32_t hsize, len; + uint32_t ht_offset, lp_offset, ht_offset_cur = -1; + uint32_t hash, index; + uint64_t *lp; + int copied = FALSE; + int error = 0; + + hsize = 1 << dip->i_di.di_depth; + if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { + gfs_consist_inode(dip); + return -EIO; + } + + hash = gfs_dir_offset2hash(*offset); + index = hash >> (32 - dip->i_di.di_depth); + + lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL); + if (!lp) + return -ENOMEM; + + while (index < hsize) { + lp_offset = index & (sdp->sd_hash_ptrs - 1); + ht_offset = index - lp_offset; + + if (ht_offset_cur != ht_offset) { + error = gfs_internal_read(dip, (char *)lp, + ht_offset * sizeof(uint64_t), + sdp->sd_hash_bsize); + if (error != sdp->sd_hash_bsize) { + if (error >= 0) + error = -EIO; + goto out; + } + ht_offset_cur = ht_offset; + } + + error = get_leaf(dip, gfs64_to_cpu(lp[lp_offset]), &bh); + if (error) + goto out; + + gfs_leaf_in(&leaf, bh->b_data); + + if (leaf.lf_next) + error = do_filldir_multi(dip, offset, + opaque, filldir, + bh, &copied); + else + error = do_filldir_single(dip, offset, + opaque, filldir, + bh, leaf.lf_entries, + &copied); + + brelse(bh); + + if (error) { + if (error > 0) + error = 0; + goto out; + } + + len = 1 << (dip->i_di.di_depth - leaf.lf_depth); + index = (index & ~(len - 1)) + len; + } + + out: + kfree(lp); + + return error; +} + +/** + * dir_e_mvino - + * @dip: The GFS inode + * @filename: + * @new_inode: + * + * Returns: + */ + +static int +dir_e_mvino(struct gfs_inode *dip, struct qstr *filename, + struct gfs_inum *inum, unsigned int new_type) +{ + struct buffer_head *bh, *dibh; + struct gfs_dirent *dent; + int error; + + error = linked_leaf_search(dip, filename, &dent, NULL, &bh); + if (error == -ENOENT) { + gfs_consist_inode(dip); + return -EIO; + } + if (error) + return error; + + gfs_trans_add_bh(dip->i_gl, bh); + + gfs_inum_out(inum, (char *)&dent->de_inum); + dent->de_type = cpu_to_gfs16(new_type); + + brelse(bh); + + error = gfs_get_inode_buffer(dip, &dibh); + if (error) + return error; + + dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); + + gfs_trans_add_bh(dip->i_gl, dibh); + gfs_dinode_out(&dip->i_di, dibh->b_data); + brelse(dibh); + + return 0; +} + +/** + * dir_l_search - Search linear (stuffed dinode) dir for inode matching name + * @dip: The GFS inode + * @filename: Filename string + * @inode: If non-NULL, function fills with formal inode # and block address + * @type: If non-NULL, function fills with GFS_FILE_... dinode type + * + * Returns: + */ + +static int +dir_l_search(struct gfs_inode *dip, struct qstr *filename, + struct gfs_inum *inum, unsigned int *type) +{ + struct buffer_head *dibh; + struct gfs_dirent *dent; + int error; + + if (!gfs_is_stuffed(dip)) { + gfs_consist_inode(dip); + return -EIO; + } + + error = gfs_get_inode_buffer(dip, &dibh); + if (error) + return error; + + error = leaf_search(dip, dibh, filename, &dent, NULL); + if (!error) { + if (inum) + gfs_inum_in(inum, (char *)&dent->de_inum); + if (type) + *type = gfs16_to_cpu(dent->de_type); + } + + brelse(dibh); + + return error; +} + +/** + * dir_l_add - + * @dip: The GFS inode + * @filename: + * @inode: + * @type: + * + * Returns: + */ + +static int +dir_l_add(struct gfs_inode *dip, struct qstr *filename, + struct gfs_inum *inum, unsigned int type) +{ + struct buffer_head *dibh; + struct gfs_dirent *dent; + int error; + + if (!gfs_is_stuffed(dip)) { + gfs_consist_inode(dip); + return -EIO; + } + + error = gfs_get_inode_buffer(dip, &dibh); + if (error) + return error; + + if (gfs_dirent_alloc(dip, dibh, filename->len, &dent)) { + brelse(dibh); + + error = dir_make_exhash(dip); + if (!error) + error = dir_e_add(dip, filename, inum, type); + + return error; + } + + /* gfs_dirent_alloc() pins */ + + gfs_inum_out(inum, (char *)&dent->de_inum); + dent->de_hash = gfs_dir_hash(filename->name, filename->len); + dent->de_hash = cpu_to_gfs32(dent->de_hash); + dent->de_type = cpu_to_gfs16(type); + memcpy((char *)(dent + 1), filename->name, filename->len); + + dip->i_di.di_entries++; + dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); + + gfs_dinode_out(&dip->i_di, dibh->b_data); + brelse(dibh); + + return 0; +} + +/** + * dir_l_del - + * @dip: The GFS inode + * @filename: + * + * Returns: + */ + +static int +dir_l_del(struct gfs_inode *dip, struct qstr *filename) +{ + struct buffer_head *dibh; + struct gfs_dirent *dent, *prev; + int error; + + if (!gfs_is_stuffed(dip)) { + gfs_consist_inode(dip); + return -EIO; + } + + error = gfs_get_inode_buffer(dip, &dibh); + if (error) + return error; + + error = leaf_search(dip, dibh, filename, &dent, &prev); + if (error == -ENOENT) { + gfs_consist_inode(dip); + error = -EIO; + goto out; + } + if (error) + goto out; + + dirent_del(dip, dibh, prev, dent); + + /* dirent_del() pins */ + + if (!dip->i_di.di_entries) + gfs_consist_inode(dip); + dip->i_di.di_entries--; + + dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); + + gfs_dinode_out(&dip->i_di, dibh->b_data); + + out: + brelse(dibh); + + return error; +} + +/** + * dir_l_read - + * @dip: + * @offset: + * @opaque: + * @filldir: + * + * Returns: + */ + +static int +dir_l_read(struct gfs_inode *dip, uint64_t *offset, void *opaque, + gfs_filldir_t filldir) +{ + struct buffer_head *dibh; + int copied = FALSE; + int error; + + if (!gfs_is_stuffed(dip)) { + gfs_consist_inode(dip); + return -EIO; + } + + if (!dip->i_di.di_entries) + return 0; + + error = gfs_get_inode_buffer(dip, &dibh); + if (error) + return error; + + error = do_filldir_single(dip, offset, + opaque, filldir, + dibh, dip->i_di.di_entries, + &copied); + if (error > 0) + error = 0; + + brelse(dibh); + + return error; +} + +/** + * dir_l_mvino - + * @dip: + * @filename: + * @new_inode: + * + * Returns: + */ + +static int +dir_l_mvino(struct gfs_inode *dip, struct qstr *filename, + struct gfs_inum *inum, unsigned int new_type) +{ + struct buffer_head *dibh; + struct gfs_dirent *dent; + int error; + + if (!gfs_is_stuffed(dip)) { + gfs_consist_inode(dip); + return -EIO; + } + + error = gfs_get_inode_buffer(dip, &dibh); + if (error) + return error; + + error = leaf_search(dip, dibh, filename, &dent, NULL); + if (error == -ENOENT) { + gfs_consist_inode(dip); + error = -EIO; + goto out; + } + if (error) + goto out; + + gfs_trans_add_bh(dip->i_gl, dibh); + + gfs_inum_out(inum, (char *)&dent->de_inum); + dent->de_type = cpu_to_gfs16(new_type); + + dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds(); + + gfs_dinode_out(&dip->i_di, dibh->b_data); + + out: + brelse(dibh); + + return error; +} + +/** + * gfs_dir_search - Search a directory + * @dip: The GFS inode + * @filename: + * @inode: + * + * This routine searches a directory for a file or another directory. + * Assumes a glock is held on dip. + * + * Returns: errno + */ + +int +gfs_dir_search(struct gfs_inode *dip, struct qstr *filename, + struct gfs_inum *inum, unsigned int *type) +{ + int error; + + if (dip->i_di.di_flags & GFS_DIF_EXHASH) + error = dir_e_search(dip, filename, inum, type); + else + error = dir_l_search(dip, filename, inum, type); + + return error; +} + +/** + * gfs_dir_add - Add new filename into directory + * @dip: The GFS inode + * @filename: The new name + * @inode: The inode number of the entry + * @type: The type of the entry + * + * Returns: 0 on success, error code on failure + */ + +int +gfs_dir_add(struct gfs_inode *dip, struct qstr *filename, + struct gfs_inum *inum, unsigned int type) +{ + int error; + + if (dip->i_di.di_flags & GFS_DIF_EXHASH) + error = dir_e_add(dip, filename, inum, type); + else + error = dir_l_add(dip, filename, inum, type); + + return error; +} + +/** + * gfs_dir_del - Delete a directory entry + * @dip: The GFS inode + * @filename: The filename + * + * Returns: 0 on success, error code on failure + */ + +int +gfs_dir_del(struct gfs_inode *dip, struct qstr *filename) +{ + int error; + + if (dip->i_di.di_flags & GFS_DIF_EXHASH) + error = dir_e_del(dip, filename); + else + error = dir_l_del(dip, filename); + + return error; +} + +/** + * gfs_dir_read - Translate a GFS filename + * @dip: The GFS inode + * @offset: + * @opaque: + * @filldir: + * + * Returns: 0 on success, error code otherwise + */ + +int +gfs_dir_read(struct gfs_inode *dip, uint64_t * offset, void *opaque, + gfs_filldir_t filldir) +{ + int error; + + if (dip->i_di.di_flags & GFS_DIF_EXHASH) + error = dir_e_read(dip, offset, opaque, filldir); + else + error = dir_l_read(dip, offset, opaque, filldir); + + return error; +} + +/** + * gfs_dir_mvino - Change inode number of directory entry + * @dip: The GFS inode + * @filename: + * @new_inode: + * + * This routine changes the inode number of a directory entry. It's used + * by rename to change ".." when a directory is moved. + * Assumes a glock is held on dvp. + * + * Returns: errno + */ + +int +gfs_dir_mvino(struct gfs_inode *dip, struct qstr *filename, + struct gfs_inum *inum, unsigned int new_type) +{ + int error; + + if (dip->i_di.di_flags & GFS_DIF_EXHASH) + error = dir_e_mvino(dip, filename, inum, new_type); + else + error = dir_l_mvino(dip, filename, inum, new_type); + + return error; +} + +/** + * foreach_leaf - call a function for each leaf in a directory + * @dip: the directory + * @lc: the function to call for each each + * @data: private data to pass to it + * + * Returns: errno + */ + +static int +foreach_leaf(struct gfs_inode *dip, leaf_call_t lc, void *data) +{ + struct gfs_sbd *sdp = dip->i_sbd; + struct buffer_head *bh; + struct gfs_leaf leaf; + uint32_t hsize, len; + uint32_t ht_offset, lp_offset, ht_offset_cur = -1; + uint32_t index = 0; + uint64_t *lp; + uint64_t leaf_no; + int error = 0; + + hsize = 1 << dip->i_di.di_depth; + if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { + gfs_consist_inode(dip); + return -EIO; + } + + lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL); + if (!lp) + return -ENOMEM; + + while (index < hsize) { + lp_offset = index & (sdp->sd_hash_ptrs - 1); + ht_offset = index - lp_offset; + + if (ht_offset_cur != ht_offset) { + error = gfs_internal_read(dip, (char *)lp, + ht_offset * sizeof(uint64_t), + sdp->sd_hash_bsize); + if (error != sdp->sd_hash_bsize) { + if (error >= 0) + error = -EIO; + goto out; + } + ht_offset_cur = ht_offset; + } + + leaf_no = gfs64_to_cpu(lp[lp_offset]); + if (leaf_no) { + error = get_leaf(dip, leaf_no, &bh); + if (error) + goto out; + gfs_leaf_in(&leaf, bh->b_data); + brelse(bh); + + len = 1 << (dip->i_di.di_depth - leaf.lf_depth); + + error = lc(dip, index, len, leaf_no, data); + if (error) + goto out; + + index = (index & ~(len - 1)) + len; + } else + index++; + } + + if (index != hsize) { + gfs_consist_inode(dip); + error = -EIO; + } + + out: + kfree(lp); + + return error; +} + +/** + * leaf_free - Deallocate a directory leaf + * @dip: the directory + * @index: the hash table offset in the directory + * @len: the number of pointers to this leaf + * @leaf_no: the leaf number + * @data: not used + * + * Returns: errno + */ + +static int +leaf_free(struct gfs_inode *dip, + uint32_t index, uint32_t len, + uint64_t leaf_no, void *data) +{ + struct gfs_sbd *sdp = dip->i_sbd; + struct gfs_leaf tmp_leaf; + struct gfs_rgrp_list rlist; + struct buffer_head *bh, *dibh; + uint64_t blk; + unsigned int rg_blocks = 0; + char *ht=0; + unsigned int x, size = len * sizeof(uint64_t); + int error; + + memset(&rlist, 0, sizeof(struct gfs_rgrp_list)); + + gfs_alloc_get(dip); + + error = gfs_quota_hold_m(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out; + + error = gfs_rindex_hold(sdp, &dip->i_alloc->al_ri_gh); + if (error) + goto out_qs; + + /* Count the number of leaves */ + + for (blk = leaf_no; blk; blk = tmp_leaf.lf_next) { + error = get_leaf(dip, blk, &bh); + if (error) + goto out_rlist; + gfs_leaf_in(&tmp_leaf, (bh)->b_data); + brelse(bh); + + gfs_rlist_add(sdp, &rlist, blk); + } + + gfs_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0); + + for (x = 0; x < rlist.rl_rgrps; x++) { + struct gfs_rgrpd *rgd; + rgd = get_gl2rgd(rlist.rl_ghs[x].gh_gl); + rg_blocks += rgd->rd_ri.ri_length; + } + + error = gfs_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs); + if (error) + goto out_rlist; + + /* Trans may require: + All the bitmaps that were reserved. + One block for the dinode. + All the hash blocks that will be changed. + One block for a quota change. */ + + error = gfs_trans_begin(sdp, + rg_blocks + 1 + (DIV_RU(size, sdp->sd_jbsize) + 1), + 1); + if (error) + goto out_rg_gunlock; + + for (blk = leaf_no; blk; blk = tmp_leaf.lf_next) { + error = get_leaf(dip, blk, &bh); + if (error) + goto out_end_trans; + gfs_leaf_in(&tmp_leaf, bh->b_data); + brelse(bh); + + gfs_metafree(dip, blk, 1); + + if (!dip->i_di.di_blocks) + gfs_consist_inode(dip); + dip->i_di.di_blocks--; + } + + error = gfs_writei(dip, ht, index * sizeof (uint64_t), size, gfs_zero_blocks, NULL); + + if (error != size) { + if (error >= 0) + error = -EIO; + goto out_end_trans; + } + + error = gfs_get_inode_buffer(dip, &dibh); + if (error) + goto out_end_trans; + + gfs_trans_add_bh(dip->i_gl, dibh); + gfs_dinode_out(&dip->i_di, dibh->b_data); + brelse(dibh); + + out_end_trans: + gfs_trans_end(sdp); + + out_rg_gunlock: + gfs_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs); + + out_rlist: + gfs_rlist_free(&rlist); + gfs_glock_dq_uninit(&dip->i_alloc->al_ri_gh); + + out_qs: + gfs_quota_unhold_m(dip); + + out: + gfs_alloc_put(dip); + + return error; +} + +/** + * gfs_dir_exhash_free - free all the leaf blocks in a directory + * @dip: the directory + * + * Dealloc all on-disk directory leaves to FREEMETA state + * Change on-disk inode type to "regular file" + * + * Returns: errno + */ + +int +gfs_dir_exhash_free(struct gfs_inode *dip) +{ + struct gfs_sbd *sdp = dip->i_sbd; + struct buffer_head *bh; + int error; + + /* Dealloc on-disk leaves to FREEMETA state */ + error = foreach_leaf(dip, leaf_free, NULL); + if (error) + return error; + + /* Make this a regular file in case we crash. + (We don't want to free these blocks a second time.) */ + + error = gfs_trans_begin(sdp, 1, 0); + if (error) + return error; + + error = gfs_get_inode_buffer(dip, &bh); + if (!error) { + gfs_trans_add_bh(dip->i_gl, bh); + ((struct gfs_dinode *)bh->b_data)->di_type = cpu_to_gfs16(GFS_FILE_REG); + brelse(bh); + } + + gfs_trans_end(sdp); + + return error; +} + +/** + * gfs_diradd_alloc_required - figure out if an entry addition is going to require an allocation + * @ip: the file being written to + * @filname: the filename that's going to be added + * @alloc_required: the int is set to TRUE if an alloc is required, FALSE otherwise + * + * Returns: errno + */ + +int +gfs_diradd_alloc_required(struct gfs_inode *dip, struct qstr *filename, + int *alloc_required) +{ + struct buffer_head *bh = NULL, *bh_next; + uint32_t hsize, hash, index; + int error = 0; + + *alloc_required = FALSE; + + if (dip->i_di.di_flags & GFS_DIF_EXHASH) { + hsize = 1 << dip->i_di.di_depth; + if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { + gfs_consist_inode(dip); + return -EIO; + } + + hash = gfs_dir_hash(filename->name, filename->len); + index = hash >> (32 - dip->i_di.di_depth); + + error = get_first_leaf(dip, index, &bh_next); + if (error) + return error; + + do { + if (bh) + brelse(bh); + + bh = bh_next; + + if (dirent_fits(dip, bh, filename->len)) + break; + + error = get_next_leaf(dip, bh, &bh_next); + if (error == -ENOENT) { + *alloc_required = TRUE; + error = 0; + break; + } + } + while (!error); + + brelse(bh); + } else { + error = gfs_get_inode_buffer(dip, &bh); + if (error) + return error; + + if (!dirent_fits(dip, bh, filename->len)) + *alloc_required = TRUE; + + brelse(bh); + } + + return error; +} + +/** + * do_gdm - copy out one leaf (or list of leaves) + * @dip: the directory + * @index: the hash table offset in the directory + * @len: the number of pointers to this leaf + * @leaf_no: the leaf number + * @data: a pointer to a struct gfs_user_buffer structure + * + * Returns: errno + */ + +static int +do_gdm(struct gfs_inode *dip, + uint32_t index, uint32_t len, uint64_t leaf_no, + void *data) +{ + struct gfs_user_buffer *ub = (struct gfs_user_buffer *)data; + struct gfs_leaf leaf; + struct buffer_head *bh; + uint64_t blk; + int error = 0; + + for (blk = leaf_no; blk; blk = leaf.lf_next) { + error = get_leaf(dip, blk, &bh); + if (error) + break; + + gfs_leaf_in(&leaf, bh->b_data); + + error = gfs_add_bh_to_ub(ub, bh); + + brelse(bh); + + if (error) + break; + } + + return error; +} + +/** + * gfs_get_dir_meta - return all the leaf blocks of a directory + * @dip: the directory + * @ub: the structure representing the meta + * + * Returns: errno + */ + +int +gfs_get_dir_meta(struct gfs_inode *dip, struct gfs_user_buffer *ub) +{ + return foreach_leaf(dip, do_gdm, ub); +} --- linux-2.6.27.orig/ubuntu/gfs/trans.h +++ linux-2.6.27/ubuntu/gfs/trans.h @@ -0,0 +1,24 @@ +#ifndef __TRANS_DOT_H__ +#define __TRANS_DOT_H__ + +#define TRANS_IS_NEW (53) +#define TRANS_IS_INCORE (54) +void gfs_trans_print(struct gfs_sbd *sdp, struct gfs_trans *tr, + unsigned int where); + +int gfs_trans_begin_i(struct gfs_sbd *sdp, + unsigned int meta_blocks, unsigned int extra_blocks, + char *file, unsigned int line); +#define gfs_trans_begin(sdp, mb, eb) \ +gfs_trans_begin_i((sdp), (mb), (eb), __FILE__, __LINE__) + +void gfs_trans_end(struct gfs_sbd *sdp); + +void gfs_trans_add_gl(struct gfs_glock *gl); +void gfs_trans_add_bh(struct gfs_glock *gl, struct buffer_head *bh); +struct gfs_unlinked *gfs_trans_add_unlinked(struct gfs_sbd *sdp, unsigned int type, + struct gfs_inum *inum); +void gfs_trans_add_quota(struct gfs_sbd *sdp, int64_t change, uint32_t uid, + uint32_t gid); + +#endif /* __TRANS_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/gfs.h +++ linux-2.6.27/ubuntu/gfs/gfs.h @@ -0,0 +1,89 @@ +#ifndef __GFS_DOT_H__ +#define __GFS_DOT_H__ + +#define RELEASE_VERSION "" + +#include "lm_interface.h" + +#include "gfs_ondisk.h" +#include "fixed_div64.h" +#include "lvb.h" +#include "incore.h" +#include "util.h" + +#ifndef TRUE +#define TRUE (1) +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +#define NO_CREATE (0) +#define CREATE (1) + +#if (BITS_PER_LONG == 64) +#define PRIu64 "lu" +#define PRId64 "ld" +#define PRIo64 "lo" +#define PRIx64 "lx" +#define PRIX64 "lX" +#define SCNu64 "lu" +#define SCNd64 "ld" +#define SCNo64 "lo" +#define SCNx64 "lx" +#define SCNX64 "lX" +#else +#define PRIu64 "Lu" +#define PRId64 "Ld" +#define PRIo64 "Lo" +#define PRIx64 "Lx" +#define PRIX64 "LX" +#define SCNu64 "Lu" +#define SCNd64 "Ld" +#define SCNo64 "Lo" +#define SCNx64 "Lx" +#define SCNX64 "LX" +#endif + +/* Divide num by den. Round up if there is a remainder. */ +#define DIV_RU(num, den) (((num) + (den) - 1) / (den)) +#define MAKE_MULT8(x) (((x) + 7) & ~7) + +#define GFS_FAST_NAME_SIZE (8) + +#define get_v2sdp(sb) ((struct gfs_sbd *)(sb)->s_fs_info) +#define set_v2sdp(sb, sdp) (sb)->s_fs_info = (sdp) +#define get_v2ip(inode) ((struct gfs_inode *)(inode)->i_private) +#define set_v2ip(inode, ip) (inode)->i_private = (ip) +#define get_v2fp(file) ((struct gfs_file *)(file)->private_data) +#define set_v2fp(file, fp) (file)->private_data = (fp) +#define get_v2bd(bh) ((struct gfs_bufdata *)(bh)->b_private) +#define set_v2bd(bh, bd) (bh)->b_private = (bd) + +#define get_transaction ((struct gfs_trans *)(current->journal_info)) +#define set_transaction(tr) (current->journal_info) = (tr) + +#define get_gl2ip(gl) ((struct gfs_inode *)(gl)->gl_object) +#define set_gl2ip(gl, ip) (gl)->gl_object = (ip) +#define get_gl2rgd(gl) ((struct gfs_rgrpd *)(gl)->gl_object) +#define set_gl2rgd(gl, rgd) (gl)->gl_object = (rgd) +#define get_gl2gl(gl) ((struct gfs_glock *)(gl)->gl_object) +#define set_gl2gl(gl, gl2) (gl)->gl_object = (gl2) + +#define gfs_printf(fmt, args...) \ +do { \ + if (buf) { \ + int gspf_left = size - *count, gspf_out; \ + if (gspf_left <= 0) \ + goto out; \ + gspf_out = snprintf(buf + *count, gspf_left, fmt, ##args); \ + if (gspf_out < gspf_left) \ + *count += gspf_out; \ + else \ + goto out; \ + } else \ + printk(fmt, ##args); \ +} while (0) + +#endif /* __GFS_DOT_H__ */ --- linux-2.6.27.orig/ubuntu/gfs/recovery.c +++ linux-2.6.27/ubuntu/gfs/recovery.c @@ -0,0 +1,780 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "gfs.h" +#include "dio.h" +#include "glock.h" +#include "glops.h" +#include "lm.h" +#include "lops.h" +#include "recovery.h" + +#define bn2seg(bn) (((uint32_t)((bn) - jdesc->ji_addr)) / sdp->sd_sb.sb_seg_size) +#define seg2bn(seg) ((seg) * sdp->sd_sb.sb_seg_size + jdesc->ji_addr) + +struct dirty_j { + struct list_head dj_list; + unsigned int dj_jid; + struct gfs_jindex dj_desc; +}; + +/** + * gfs_add_dirty_j - add a jid to the list of dirty journals + * @sdp: the filesystem + * @jid: the journal ID number + * + */ + +void +gfs_add_dirty_j(struct gfs_sbd *sdp, unsigned int jid) +{ + struct dirty_j *dj; + + dj = gmalloc(sizeof(struct dirty_j)); + memset(dj, 0, sizeof(struct dirty_j)); + + dj->dj_jid = jid; + + spin_lock(&sdp->sd_dirty_j_lock); + list_add(&dj->dj_list, &sdp->sd_dirty_j); + spin_unlock(&sdp->sd_dirty_j_lock); +} + +/** + * get_dirty_j - return a dirty journal from the list + * @sdp: the filesystem + * + * Returns: a struct dirty_j or NULL + */ + +static struct dirty_j * +get_dirty_j(struct gfs_sbd *sdp) +{ + struct dirty_j *dj = NULL; + + spin_lock(&sdp->sd_dirty_j_lock); + if (!list_empty(&sdp->sd_dirty_j)) { + dj = list_entry(sdp->sd_dirty_j.prev, struct dirty_j, dj_list); + list_del(&dj->dj_list); + } + spin_unlock(&sdp->sd_dirty_j_lock); + + return dj; +} + +/** + * gfs_clear_dirty_j - destroy the list of dirty journals + * @sdp: the filesystem + * + */ + +void +gfs_clear_dirty_j(struct gfs_sbd *sdp) +{ + struct dirty_j *dj; + for (;;) { + dj = get_dirty_j(sdp); + if (!dj) + break; + kfree(dj); + } +} + +/** + * gfs_log_header - read the log header for a given segment + * @sdp: the filesystem + * @jdesc: the journal + * @gl: the journal's glock + * @seg: the segment to look at + * @lh: the log header to return + * + * Read the log header for a given segement in a given journal. Do a few + * sanity checks on it. + * + * Returns: 0 on success, 1 if the header was invalid or incomplete and, errno on error + */ + +static int +get_log_header(struct gfs_sbd *sdp, struct gfs_jindex *jdesc, + struct gfs_glock *gl, uint32_t seg, struct gfs_log_header *lh) +{ + struct buffer_head *bh; + struct gfs_log_header lh2; + int error; + + error = gfs_dread(gl, seg2bn(seg), DIO_START | DIO_WAIT, &bh); + if (error) + return error; + + gfs_log_header_in(lh, bh->b_data); + gfs_log_header_in(&lh2, + bh->b_data + GFS_BASIC_BLOCK - + sizeof(struct gfs_log_header)); + + brelse(bh); + + if (memcmp(lh, &lh2, sizeof(struct gfs_log_header)) != 0 || + lh->lh_header.mh_magic != GFS_MAGIC || + lh->lh_header.mh_type != GFS_METATYPE_LH) + error = 1; + + return error; +} + +/** + * find_good_lh - find a good log header + * @sdp: the filesystem + * @jdesc: the journal + * @gl: the journal's glock + * @seg: the segment to start searching from (it's also filled in with a new value.) + * @lh: the log header to fill in + * @forward: if true search forward in the log, else search backward + * + * Call get_log_header() to get a log header for a segment, but if the + * segment is bad, either scan forward or backward until we find a good one. + * + * Returns: errno + */ + +static int +find_good_lh(struct gfs_sbd *sdp, struct gfs_jindex *jdesc, + struct gfs_glock *gl, uint32_t *seg, struct gfs_log_header *lh, + int forward) +{ + int error; + uint32_t orig_seg = *seg; + + for (;;) { + error = get_log_header(sdp, jdesc, gl, *seg, lh); + if (error <= 0) + return error; + + if (forward) { + if (++*seg == jdesc->ji_nsegment) + *seg = 0; + } else { + if ((*seg)-- == 0) + *seg = jdesc->ji_nsegment - 1; + } + + if (*seg == orig_seg) { + gfs_consist(sdp); + return -EIO; + } + } +} + +/** + * verify_jhead - make sure we've found the head of the log + * @sdp: the filesystem + * @jdesc: the journal + * @gl: the journal's glock + * @head: this is filled in with the log descriptor of the head + * + * At this point, seg and lh should be either the head of the log or just + * before. Scan forward until we find the head. + * + * Returns: errno + */ + +static int +verify_jhead(struct gfs_sbd *sdp, struct gfs_jindex *jdesc, + struct gfs_glock *gl, struct gfs_log_header *head) +{ + struct gfs_log_header lh; + uint32_t seg; + int error; + + seg = bn2seg(head->lh_first); + + for (;;) { + if (++seg == jdesc->ji_nsegment) + seg = 0; + + error = get_log_header(sdp, jdesc, gl, seg, &lh); + if (error < 0) + return error; + + if (error == 1) + continue; + if (lh.lh_sequence == head->lh_sequence) + continue; + + if (lh.lh_sequence < head->lh_sequence) + break; + + memcpy(head, &lh, sizeof(struct gfs_log_header)); + } + + return 0; +} + +/** + * gfs_find_jhead - find the head of a log + * @sdp: the filesystem + * @jdesc: the journal + * @gl: the journal's glock + * @head: the log descriptor for the head of the log is returned here + * + * Do a binary search of a journal and find the valid log entry with the + * highest sequence number. (i.e. the log head) + * + * Returns: errno + */ + +int +gfs_find_jhead(struct gfs_sbd *sdp, struct gfs_jindex *jdesc, + struct gfs_glock *gl, struct gfs_log_header *head) +{ + struct gfs_log_header lh; + uint32_t seg1, seg2, seg_m; + int error; + uint64_t lh1_sequence; + + seg1 = 0; + seg2 = jdesc->ji_nsegment - 1; + + for (;;) { + seg_m = (seg1 + seg2) / 2; + + error = find_good_lh(sdp, jdesc, gl, &seg1, &lh, TRUE); + if (error) + break; + + if (seg1 == seg_m) { + error = verify_jhead(sdp, jdesc, gl, &lh); + if (unlikely(error)) + printk("GFS: verify_jhead error=%d\n", error); + else + memcpy(head, &lh, sizeof(struct gfs_log_header)); + break; + } + + lh1_sequence = lh.lh_sequence; + + error = find_good_lh(sdp, jdesc, gl, &seg_m, &lh, FALSE); + if (error) + break; + + if (lh1_sequence <= lh.lh_sequence) + seg1 = seg_m; + else + seg2 = seg_m; + } + + return error; +} + +/** + * gfs_increment_blkno - move to the next block in a journal + * @sdp: the filesystem + * @jdesc: the journal + * @gl: the journal's glock + * @addr: the block number to increment + * @skip_header: if this is TRUE, skip log headers + * + * Replace @addr with the location of the next block in the log. + * Take care of journal wrap and skip of log header if necessary. + * + * Returns: errno + */ + +int +gfs_increment_blkno(struct gfs_sbd *sdp, struct gfs_jindex *jdesc, + struct gfs_glock *gl, uint64_t *addr, int skip_headers) +{ + struct gfs_log_header header; + int error; + + (*addr)++; + + /* Handle journal wrap */ + + if (*addr == seg2bn(jdesc->ji_nsegment)) + *addr -= jdesc->ji_nsegment * sdp->sd_sb.sb_seg_size; + + gfs_start_ra(gl, *addr, + jdesc->ji_addr + + jdesc->ji_nsegment * sdp->sd_sb.sb_seg_size - *addr); + + /* Handle landing on a header block */ + + if (skip_headers && !do_mod(*addr, sdp->sd_sb.sb_seg_size)) { + error = get_log_header(sdp, jdesc, gl, bn2seg(*addr), &header); + if (error < 0) + return error; + + if (error) { /* Corrupt headers here are bad */ + if (gfs_consist(sdp)) + printk("GFS: fsid=%s: *addr = %"PRIu64"\n", + sdp->sd_fsname, *addr); + return -EIO; + } + if (header.lh_first == *addr) { + if (gfs_consist(sdp)) + printk("GFS: fsid=%s: *addr = %"PRIu64"\n", + sdp->sd_fsname, *addr); + gfs_log_header_print(&header); + return -EIO; + } + + (*addr)++; + /* Can't wrap here */ + } + + return 0; +} + +/** + * foreach_descriptor - go through the active part of the log + * @sdp: the filesystem + * @jdesc: the journal + * @gl: the journal's glock + * @start: the first log header in the active region + * @end: the last log header (don't process the contents of this entry)) + * @pass: the recovery pass + * + * Call a given function once for every log descriptor in the active + * portion of the log. + * + * Returns: errno + */ + +static int +foreach_descriptor(struct gfs_sbd *sdp, struct gfs_jindex *jdesc, + struct gfs_glock *gl, uint64_t start, uint64_t end, + unsigned int pass) +{ + struct gfs_log_header header; + struct gfs_log_descriptor desc; + struct buffer_head *bh; + int error = 0; + + while (start != end) { + if (do_mod(start, sdp->sd_sb.sb_seg_size)) { + gfs_consist(sdp); + return -EIO; + } + + error = get_log_header(sdp, jdesc, gl, bn2seg(start), &header); + if (error < 0) + return error; + + if (error) { /* Corrupt headers here are bad */ + if (gfs_consist(sdp)) + printk("GFS: fsid=%s: start = %"PRIu64"\n", + sdp->sd_fsname, start); + return -EIO; + } + if (header.lh_first != start) { + if (gfs_consist(sdp)) + printk("GFS: fsid=%s: start = %"PRIu64"\n", + sdp->sd_fsname, start); + gfs_log_header_print(&header); + return -EIO; + } + + start++; + + for (;;) { + error = gfs_dread(gl, start, DIO_START | DIO_WAIT, &bh); + if (error) + return error; + + if (gfs_metatype_check(sdp, bh, GFS_METATYPE_LD)) { + brelse(bh); + return -EIO; + } + + gfs_desc_in(&desc, bh->b_data); + brelse(bh); + + if (desc.ld_type != GFS_LOG_DESC_LAST) { + error = LO_SCAN_ELEMENTS(sdp, jdesc, gl, start, + &desc, pass); + if (error) + return error; + + while (desc.ld_length--) { + error = gfs_increment_blkno(sdp, jdesc, gl, + &start, TRUE); + if (error) + return error; + } + } else { + while (desc.ld_length--) { + error = gfs_increment_blkno(sdp, jdesc, gl, + &start, + !!desc.ld_length); + if (error) + return error; + } + + break; + } + } + } + + return error; +} + +/** + * clean_journal - mark a dirty journal as being clean + * @sdp: the filesystem + * @jdesc: the journal + * @gl: the journal's glock + * @head: the head journal to start from + * + * Returns: errno + */ + +static int noinline +clean_journal(struct gfs_sbd *sdp, struct gfs_jindex *jdesc, + struct gfs_glock *gl, struct gfs_log_header *head) +{ + struct gfs_log_header lh; + struct gfs_log_descriptor desc; + struct buffer_head *bh; + uint32_t seg; + uint64_t blkno; + int error; + + seg = bn2seg(head->lh_first); + + for (;;) { + if (++seg == jdesc->ji_nsegment) + seg = 0; + + error = get_log_header(sdp, jdesc, gl, seg, &lh); + if (error < 0) + return error; + + /* Rewrite corrupt header blocks */ + + if (error == 1) { + bh = gfs_dgetblk(gl, seg2bn(seg)); + + gfs_prep_new_buffer(bh); + gfs_buffer_clear(bh); + gfs_log_header_out(head, bh->b_data); + gfs_log_header_out(head, + bh->b_data + GFS_BASIC_BLOCK - + sizeof(struct gfs_log_header)); + + error = gfs_dwrite(sdp, bh, DIO_DIRTY | DIO_START | DIO_WAIT); + brelse(bh); + if (error) + return error; + } + + /* Stop when we get to the end of the log. */ + + if (lh.lh_sequence < head->lh_sequence) + break; + } + + /* Build a "last" descriptor for the transaction we are + about to commit by writing the shutdown header. */ + + memset(&desc, 0, sizeof(struct gfs_log_descriptor)); + desc.ld_header.mh_magic = GFS_MAGIC; + desc.ld_header.mh_type = GFS_METATYPE_LD; + desc.ld_header.mh_format = GFS_FORMAT_LD; + desc.ld_type = GFS_LOG_DESC_LAST; + desc.ld_length = 0; + + for (blkno = head->lh_first + 1; blkno != seg2bn(seg);) { + if (do_mod(blkno, sdp->sd_sb.sb_seg_size)) + desc.ld_length++; + if (++blkno == seg2bn(jdesc->ji_nsegment)) + blkno -= jdesc->ji_nsegment * sdp->sd_sb.sb_seg_size; + } + + /* Write the descriptor */ + + bh = gfs_dgetblk(gl, head->lh_first + 1); + + gfs_prep_new_buffer(bh); + gfs_buffer_clear(bh); + gfs_desc_out(&desc, bh->b_data); + + error = gfs_dwrite(sdp, bh, DIO_DIRTY | DIO_START | DIO_WAIT); + brelse(bh); + if (error) + return error; + + /* Build a log header that says the journal is clean */ + + memset(&lh, 0, sizeof(struct gfs_log_header)); + lh.lh_header.mh_magic = GFS_MAGIC; + lh.lh_header.mh_type = GFS_METATYPE_LH; + lh.lh_header.mh_format = GFS_FORMAT_LH; + lh.lh_flags = GFS_LOG_HEAD_UNMOUNT; + lh.lh_first = seg2bn(seg); + lh.lh_sequence = head->lh_sequence + 1; + /* Don't care about tail */ + lh.lh_last_dump = head->lh_last_dump; + + /* Write the header */ + + bh = gfs_dgetblk(gl, lh.lh_first); + + gfs_prep_new_buffer(bh); + gfs_buffer_clear(bh); + gfs_log_header_out(&lh, bh->b_data); + gfs_log_header_out(&lh, + bh->b_data + GFS_BASIC_BLOCK - + sizeof(struct gfs_log_header)); + + error = gfs_dwrite(sdp, bh, DIO_DIRTY | DIO_START | DIO_WAIT); + brelse(bh); + + return error; +} + +/** + * gfs_recover_journal - recover a given journal + * @sdp: the filesystem + * @jid: the number of the journal to recover + * @jdesc: the struct gfs_jindex describing the journal + * @wait: Don't return until the journal is clean (or an error is encountered) + * + * Acquire the journal's lock, check to see if the journal is clean, and + * do recovery if necessary. + * + * Returns: errno + */ + +int +gfs_recover_journal(struct gfs_sbd *sdp, + unsigned int jid, struct gfs_jindex *jdesc, + int wait) +{ + struct gfs_log_header *head; + struct gfs_holder j_gh, t_gh; + unsigned long t; + int error; + + printk("GFS: fsid=%s: jid=%u: Trying to acquire journal lock...\n", + sdp->sd_fsname, jid); + + /* Acquire the journal lock so we can do recovery */ + + error = gfs_glock_nq_num(sdp, + jdesc->ji_addr, &gfs_meta_glops, + LM_ST_EXCLUSIVE, + LM_FLAG_NOEXP | + ((wait) ? 0 : LM_FLAG_TRY) | + GL_NOCACHE, &j_gh); + switch (error) { + case 0: + break; + + case GLR_TRYFAILED: + printk("GFS: fsid=%s: jid=%u: Busy\n", sdp->sd_fsname, jid); + error = 0; + + default: + goto fail; + }; + + printk("GFS: fsid=%s: jid=%u: Looking at journal...\n", + sdp->sd_fsname, jid); + + head = kmalloc(sizeof(struct gfs_log_header), GFP_KERNEL); + if (!head) { + printk("GFS: fsid=%s jid=%u: Can't replay: Not enough memory", + sdp->sd_fsname, jid); + goto fail_gunlock; + } + + error = gfs_find_jhead(sdp, jdesc, j_gh.gh_gl, head); + if (error) + goto fail_header; + + if (!(head->lh_flags & GFS_LOG_HEAD_UNMOUNT)) { + if (test_bit(SDF_ROFS, &sdp->sd_flags)) { + printk("GFS: fsid=%s: jid=%u: Can't replay: read-only FS\n", + sdp->sd_fsname, jid); + error = -EROFS; + goto fail_header; + } + + printk("GFS: fsid=%s: jid=%u: Acquiring the transaction lock...\n", + sdp->sd_fsname, jid); + + t = jiffies; + + /* Acquire an exclusive hold on the transaction lock */ + + error = gfs_glock_nq_init(sdp->sd_trans_gl, + LM_ST_EXCLUSIVE, + LM_FLAG_NOEXP | + LM_FLAG_PRIORITY | + GL_NOCANCEL | + GL_NOCACHE, + &t_gh); + if (error) + goto fail_header; + + if (test_bit(SDF_ROFS, &sdp->sd_flags)) { + printk("GFS: fsid=%s: jid=%u: Can't replay: read-only FS\n", + sdp->sd_fsname, jid); + error = -EROFS; + goto fail_gunlock_tr; + } + + printk("GFS: fsid=%s: jid=%u: Replaying journal...\n", + sdp->sd_fsname, jid); + + set_bit(GLF_DIRTY, &j_gh.gh_gl->gl_flags); + + LO_BEFORE_SCAN(sdp, jid, head, GFS_RECPASS_A1); + + error = foreach_descriptor(sdp, jdesc, j_gh.gh_gl, + head->lh_tail, head->lh_first, + GFS_RECPASS_A1); + if (error) + goto fail_gunlock_tr; + + LO_AFTER_SCAN(sdp, jid, GFS_RECPASS_A1); + + gfs_replay_wait(sdp); + + error = clean_journal(sdp, jdesc, j_gh.gh_gl, head); + if (error) + goto fail_gunlock_tr; + + gfs_glock_dq_uninit(&t_gh); + + t = DIV_RU(jiffies - t, HZ); + + printk("GFS: fsid=%s: jid=%u: Journal replayed in %lus\n", + sdp->sd_fsname, jid, t); + } + + gfs_lm_recovery_done(sdp, jid, LM_RD_SUCCESS); + + kfree(head); + + gfs_glock_dq_uninit(&j_gh); + + printk("GFS: fsid=%s: jid=%u: Done\n", sdp->sd_fsname, jid); + + return 0; + + fail_gunlock_tr: + gfs_replay_wait(sdp); + gfs_glock_dq_uninit(&t_gh); + + fail_header: + kfree(head); + + fail_gunlock: + gfs_glock_dq_uninit(&j_gh); + + printk("GFS: fsid=%s: jid=%u: %s\n", + sdp->sd_fsname, jid, (error) ? "Failed" : "Done"); + + fail: + gfs_lm_recovery_done(sdp, jid, LM_RD_GAVEUP); + + return error; +} + +/** + * gfs_check_journals - Recover any dirty journals + * @sdp: the filesystem + * + */ + +void +gfs_check_journals(struct gfs_sbd *sdp) +{ + struct dirty_j *dj; + + for (;;) { + dj = get_dirty_j(sdp); + if (!dj) + break; + + down(&sdp->sd_jindex_lock); + + if (dj->dj_jid != sdp->sd_lockstruct.ls_jid && + dj->dj_jid < sdp->sd_journals) { + memcpy(&dj->dj_desc, + sdp->sd_jindex + dj->dj_jid, + sizeof(struct gfs_jindex)); + up(&sdp->sd_jindex_lock); + + gfs_recover_journal(sdp, + dj->dj_jid, &dj->dj_desc, + FALSE); + + } else { + up(&sdp->sd_jindex_lock); + gfs_lm_recovery_done(sdp, dj->dj_jid, LM_RD_GAVEUP); + } + + kfree(dj); + } +} + +/** + * gfs_recover_dump - recover the log elements in this machine's journal + * @sdp: the filesystem + * + * Returns: errno + */ + +int +gfs_recover_dump(struct gfs_sbd *sdp) +{ + struct gfs_log_header head; + int error; + + error = gfs_find_jhead(sdp, &sdp->sd_jdesc, sdp->sd_journal_gh.gh_gl, + &head); + if (error) + goto fail; + + if (!(head.lh_flags & GFS_LOG_HEAD_UNMOUNT)) { + gfs_consist(sdp); + return -EIO; + } + if (!head.lh_last_dump) + return error; + + printk("GFS: fsid=%s: Scanning for log elements...\n", + sdp->sd_fsname); + + LO_BEFORE_SCAN(sdp, sdp->sd_lockstruct.ls_jid, &head, GFS_RECPASS_B1); + + error = foreach_descriptor(sdp, &sdp->sd_jdesc, sdp->sd_journal_gh.gh_gl, + head.lh_last_dump, head.lh_first, + GFS_RECPASS_B1); + if (error) + goto fail; + + LO_AFTER_SCAN(sdp, sdp->sd_lockstruct.ls_jid, GFS_RECPASS_B1); + + /* We need to make sure if we crash during the next log dump that + all intermediate headers in the transaction point to the last + log dump before the one we're making so we don't lose it. */ + + sdp->sd_log_dump_last = head.lh_last_dump; + + printk("GFS: fsid=%s: Done\n", sdp->sd_fsname); + + return 0; + + fail: + printk("GFS: fsid=%s: Failed\n", sdp->sd_fsname); + + return error; +} --- linux-2.6.27.orig/ubuntu/unionfs/rename.c +++ linux-2.6.27/ubuntu/unionfs/rename.c @@ -0,0 +1,943 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: rename.c,v 1.47 2006/08/05 01:28:46 jro Exp $ + */ + +#include "unionfs.h" + +static int do_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + int bindex, struct dentry **wh_old) +{ + int err = 0; + struct dentry *hidden_old_dentry; + struct dentry *hidden_new_dentry; + struct dentry *hidden_old_dir_dentry; + struct dentry *hidden_new_dir_dentry; + struct dentry *hidden_wh_dentry; + struct dentry *hidden_wh_dir_dentry; + char *wh_name = NULL; + + print_entry(" bindex=%d", bindex); + + print_dentry("IN: do_rename, old_dentry", old_dentry); + print_dentry("IN: do_rename, new_dentry", new_dentry); + dprint(PRINT_DEBUG, "do_rename for bindex = %d\n", bindex); + + hidden_new_dentry = dtohd_index(new_dentry, bindex); + hidden_old_dentry = dtohd_index(old_dentry, bindex); + + if (!hidden_new_dentry) { + hidden_new_dentry = + create_parents(new_dentry->d_parent->d_inode, new_dentry, + bindex); + if (IS_ERR(hidden_new_dentry)) { + dprint(PRINT_DEBUG, + "error creating directory tree for rename, bindex = %d\n", + bindex); + err = PTR_ERR(hidden_new_dentry); + goto out; + } + } + + wh_name = alloc_whname(new_dentry->d_name.name, new_dentry->d_name.len); + if (IS_ERR(wh_name)) { + err = PTR_ERR(wh_name); + goto out; + } + + hidden_wh_dentry = + LOOKUP_ONE_LEN(wh_name, hidden_new_dentry->d_parent, + new_dentry->d_name.len + WHLEN); + if (IS_ERR(hidden_wh_dentry)) { + err = PTR_ERR(hidden_wh_dentry); + goto out; + } + + if (hidden_wh_dentry->d_inode) { + /* get rid of the whiteout that is existing */ + if (hidden_new_dentry->d_inode) { + printk(KERN_WARNING + "Both a whiteout and a dentry exist when doing a rename!\n"); + err = -EIO; + + DPUT(hidden_wh_dentry); + goto out; + } + + hidden_wh_dir_dentry = lock_parent(hidden_wh_dentry); + if (!(err = is_robranch_super(old_dentry->d_sb, bindex))) { + err = + vfs_unlink(hidden_wh_dir_dentry->d_inode, + hidden_wh_dentry, NULL); + } + DPUT(hidden_wh_dentry); + unlock_dir(hidden_wh_dir_dentry); + if (err) + goto out; + } else + DPUT(hidden_wh_dentry); + + DGET(hidden_old_dentry); + hidden_old_dir_dentry = GET_PARENT(hidden_old_dentry); + hidden_new_dir_dentry = GET_PARENT(hidden_new_dentry); + + lock_rename(hidden_old_dir_dentry, hidden_new_dir_dentry); + + err = is_robranch_super(old_dentry->d_sb, bindex); + if (err) + goto out_unlock; + + /* ready to whiteout for old_dentry. + caller will create the actual whiteout, + and must dput(*wh_old) */ + if (wh_old) { + char *whname; + whname = alloc_whname(old_dentry->d_name.name, + old_dentry->d_name.len); + err = PTR_ERR(whname); + if (IS_ERR(whname)) + goto out_unlock; + *wh_old = LOOKUP_ONE_LEN(whname, hidden_old_dir_dentry, + old_dentry->d_name.len + WHLEN); + KFREE(whname); + err = PTR_ERR(*wh_old); + if (IS_ERR(*wh_old)) { + *wh_old = NULL; + goto out_unlock; + } + } + + print_dentry("NEWBEF", new_dentry); + print_dentry("OLDBEF", old_dentry); + err = vfs_rename(hidden_old_dir_dentry->d_inode, hidden_old_dentry, + NULL, hidden_new_dir_dentry->d_inode, + hidden_new_dentry, NULL); + print_dentry("NEWAFT", new_dentry); + print_dentry("OLDAFT", old_dentry); + + out_unlock: + unlock_rename(hidden_old_dir_dentry, hidden_new_dir_dentry); + + DPUT(hidden_old_dir_dentry); + DPUT(hidden_new_dir_dentry); + DPUT(hidden_old_dentry); + + out: + if (!err) { + /* Fixup the newdentry. */ + if (bindex < dbstart(new_dentry)) + set_dbstart(new_dentry, bindex); + else if (bindex > dbend(new_dentry)) + set_dbend(new_dentry, bindex); + } + + KFREE(wh_name); + + print_dentry("OUT: do_rename, old_dentry", old_dentry); + print_dentry("OUT: do_rename, new_dentry", new_dentry); + + print_exit_status(err); + return err; +} + +static int unionfs_rename_whiteout(struct inode *old_dir, + struct dentry *old_dentry, + struct inode *new_dir, + struct dentry *new_dentry) +{ + int err = 0; + int bindex, bwh_old; + int old_bstart, old_bend; + int new_bstart, new_bend; + int do_copyup = -1; + struct dentry *parent_dentry; + int local_err = 0; + int eio = 0; + int revert = 0; + struct dentry *wh_old = NULL; + + print_entry_location(); + + old_bstart = dbstart(old_dentry); + bwh_old = old_bstart; + old_bend = dbend(old_dentry); + parent_dentry = old_dentry->d_parent; + + new_bstart = dbstart(new_dentry); + new_bend = dbend(new_dentry); + + /* Rename source to destination. */ + err = do_rename(old_dir, old_dentry, new_dir, new_dentry, old_bstart, + &wh_old); + if (err) { + if (!IS_COPYUP_ERR(err)) { + goto out; + } + do_copyup = old_bstart - 1; + } else { + revert = 1; + } + + /* Unlink all instances of destination that exist to the left of + * bstart of source. On error, revert back, goto out. + */ + for (bindex = old_bstart - 1; bindex >= new_bstart; bindex--) { + struct dentry *unlink_dentry; + struct dentry *unlink_dir_dentry; + + unlink_dentry = dtohd_index(new_dentry, bindex); + if (!unlink_dentry) { + continue; + } + + unlink_dir_dentry = lock_parent(unlink_dentry); + if (!(err = is_robranch_super(old_dir->i_sb, bindex))) { + err = + vfs_unlink(unlink_dir_dentry->d_inode, + unlink_dentry, NULL); + } + + fist_copy_attr_times(new_dentry->d_parent->d_inode, + unlink_dir_dentry->d_inode); + /* propagate number of hard-links */ + new_dentry->d_parent->d_inode->i_nlink = + get_nlinks(new_dentry->d_parent->d_inode); + + unlock_dir(unlink_dir_dentry); + if (!err) { + if (bindex != new_bstart) { + DPUT(unlink_dentry); + set_dtohd_index(new_dentry, bindex, NULL); + } + } else if (IS_COPYUP_ERR(err)) { + do_copyup = bindex - 1; + } else if (revert) { + DPUT(wh_old); + goto revert; + } + } + + if (do_copyup != -1) { + for (bindex = do_copyup; bindex >= 0; bindex--) { + /* copyup the file into some left directory, so that you can rename it */ + err = + copyup_dentry(old_dentry->d_parent->d_inode, + old_dentry, old_bstart, bindex, NULL, + old_dentry->d_inode->i_size); + if (!err) { + DPUT(wh_old); + bwh_old = bindex; + err = + do_rename(old_dir, old_dentry, new_dir, + new_dentry, bindex, &wh_old); + break; + } + } + } + + /* make it opaque */ + if (S_ISDIR(old_dentry->d_inode->i_mode)) { + err = make_dir_opaque(old_dentry, dbstart(old_dentry)); + if (err) + goto revert; + } + + /* Create whiteout for source, only if: + * (1) There is more than one underlying instance of source. + * (2) We did a copy_up + */ + if ((old_bstart != old_bend) || (do_copyup != -1)) { + struct dentry *hidden_parent; + BUG_ON(!wh_old || IS_ERR(wh_old) || wh_old->d_inode + || bwh_old < 0); + hidden_parent = lock_parent(wh_old); + local_err = vfs_create(hidden_parent->d_inode, wh_old, S_IRUGO, + NULL); + unlock_dir(hidden_parent); + if (!local_err) + set_dbopaque(old_dentry, bwh_old); + else { + /* We can't fix anything now, so we cop-out and use -EIO. */ + printk + ("<0>We can't create a whiteout for the source in rename!\n"); + err = -EIO; + } + } + + out: + DPUT(wh_old); + print_exit_status(err); + return err; + + revert: + /* Do revert here. */ + local_err = unionfs_refresh_hidden_dentry(new_dentry, old_bstart); + if (local_err) { + printk(KERN_WARNING + "Revert failed in rename: the new refresh failed.\n"); + eio = -EIO; + } + + local_err = unionfs_refresh_hidden_dentry(old_dentry, old_bstart); + if (local_err) { + printk(KERN_WARNING + "Revert failed in rename: the old refresh failed.\n"); + eio = -EIO; + goto revert_out; + } + + if (!dtohd_index(new_dentry, bindex) + || !dtohd_index(new_dentry, bindex)->d_inode) { + printk(KERN_WARNING + "Revert failed in rename: the object disappeared from under us!\n"); + eio = -EIO; + goto revert_out; + } + + if (dtohd_index(old_dentry, bindex) + && dtohd_index(old_dentry, bindex)->d_inode) { + printk(KERN_WARNING + "Revert failed in rename: the object was created underneath us!\n"); + eio = -EIO; + goto revert_out; + } + + local_err = + do_rename(new_dir, new_dentry, old_dir, old_dentry, old_bstart, + NULL); + + /* If we can't fix it, then we cop-out with -EIO. */ + if (local_err) { + printk(KERN_WARNING "Revert failed in rename!\n"); + eio = -EIO; + } + + local_err = unionfs_refresh_hidden_dentry(new_dentry, bindex); + if (local_err) + eio = -EIO; + local_err = unionfs_refresh_hidden_dentry(old_dentry, bindex); + if (local_err) + eio = -EIO; + + revert_out: + if (eio) + err = eio; + print_exit_status(err); + return err; +} + +/* + * Unfortunately, we cannot simply call things like dbstart() in different + * places of the rename code because we move things around. So, we use this + * structure to pass the necessary information around to all the places that + * need it. + */ +struct rename_info { + int do_copyup; + int do_whiteout; + int rename_ok; + + int old_bstart; + int old_bend; + int new_bstart; + int new_bend; + + int isdir; /* Is the source a directory? */ + int clobber; /* Are we clobbering the destination? */ + + int bwh_old; /* where we create the whiteout */ + struct dentry *wh_old; /* lookup and set by do_rename() */ +}; +#ifdef UNIONFS_DELETE_ALL +/* + * Rename all occurences of source except for the leftmost destination + */ +static int __rename_all(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + fd_set * success_mask, struct rename_info *info) +{ + int bindex; + int err = 0; + + print_entry_location(); + + /* Loop through all the branches from right to left and rename all + * instances of source to destination, except the leftmost destination + */ + for (bindex = info->old_bend; bindex >= info->old_bstart; bindex--) { + /* We don't rename if there is no source. */ + if (dtohd_index(old_dentry, bindex) == NULL) + continue; + + /* we rename the bstart of destination only at the last of + * all operations, so that we don't lose it on error + */ + if (info->clobber && (bindex == info->new_bstart)) + continue; + + DPUT(info->wh_old); + info->bwh_old = bindex; + /* We shouldn't have a handle on this if there is no inode. */ + err = + do_rename(old_dir, old_dentry, new_dir, new_dentry, bindex, + &info->wh_old); + if (!err) { + /* For reverting. */ + FD_SET(bindex, success_mask); + /* So we know not to copyup on failures the right */ + info->rename_ok = bindex; + } else if (IS_COPYUP_ERR(err)) { + if (info->isdir) { + err = -EXDEV; + break; + } + + /* we need a whiteout... */ + info->do_whiteout = bindex - 1; + + if (bindex == info->old_bstart) + /* ...and a copyup */ + info->do_copyup = bindex - 1; + + err = 0; /* reset error */ + } else + break; /* error is set by do_rename */ + } + + print_exit_status(err); + return err; +} + +/* + * Unlink all destinations (if they exist) to the left of the left-most + * source + */ +static int __rename_all_unlink(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + struct rename_info *info) +{ + int bindex; + + struct dentry *unlink_dentry; + struct dentry *unlink_dir_dentry; + + int err = 0; + + print_entry_location(); + + for (bindex = info->old_bstart - 1; bindex > info->new_bstart; bindex--) { + unlink_dentry = dtohd_index(new_dentry, bindex); + if (!unlink_dentry) + continue; + + /* lock, unlink if possible, copyup times, unlock */ + unlink_dir_dentry = lock_parent(unlink_dentry); + if (!(err = is_robranch_super(old_dir->i_sb, bindex))) + err = + vfs_unlink(unlink_dir_dentry->d_inode, + unlink_dentry, NULL); + + fist_copy_attr_times(new_dentry->d_parent->d_inode, + unlink_dir_dentry->d_inode); + new_dentry->d_parent->d_inode->i_nlink = + get_nlinks(new_dentry->d_parent->d_inode); + + unlock_dir(unlink_dir_dentry); + + if (!err) { + if (bindex != info->new_bstart) { + DPUT(unlink_dentry); + set_dtohd_index(new_dentry, bindex, NULL); + } + } else if (IS_COPYUP_ERR(err)) { + if (info->isdir) { + err = -EXDEV; + break; + } + info->do_copyup = bindex - 1; + + err = 0; /* reset error */ + } else + break; /* err is set by is_ro_branch_super or vfs_unlink */ + } + + print_exit_status(err); + return err; +} + +/* + * Try to revert everything we have done in __rename_all and __rename_all_unlink + */ +static int __rename_all_revert(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + fd_set * success_mask, struct rename_info *info) +{ + int bindex; + + int err; + int eio = 0; + + print_entry_location(); + + for (bindex = info->old_bstart; bindex <= info->old_bend; bindex++) { + if (!FD_ISSET(bindex, success_mask)) + continue; + + err = unionfs_refresh_hidden_dentry(new_dentry, bindex); + if (err) { + printk(KERN_WARNING "Revert failed in rename: " + "the new refresh failed.\n"); + eio = -EIO; + } + + err = unionfs_refresh_hidden_dentry(old_dentry, bindex); + if (err) { + printk(KERN_WARNING "Revert failed in rename: " + "the old refresh failed.\n"); + eio = -EIO; + continue; + } + + if (!dtohd_index(new_dentry, bindex) + || !dtohd_index(new_dentry, bindex)->d_inode) { + printk(KERN_WARNING "Revert failed in rename: " + "the object disappeared from under us!\n"); + eio = -EIO; + continue; + } + + if (dtohd_index(old_dentry, bindex) + && dtohd_index(old_dentry, bindex)->d_inode) { + printk(KERN_WARNING "Revert failed in rename: " + "the object was created underneath us!\n"); + eio = -EIO; + continue; + } + + err = + do_rename(new_dir, new_dentry, old_dir, old_dentry, bindex, + NULL); + /* If we can't fix it, then we cop-out with -EIO. */ + if (err) { + printk(KERN_WARNING "Revert failed in rename!\n"); + eio = -EIO; + } + + err = unionfs_refresh_hidden_dentry(new_dentry, bindex); + if (err) + eio = -EIO; + err = unionfs_refresh_hidden_dentry(old_dentry, bindex); + if (err) + eio = -EIO; + } + + print_exit_status(eio); + return eio; +} + +/* + * Finish off the rename, by either over writing the last destination or + * unlinking the last destination to the left of us + */ +static int __rename_all_clobber(struct inode *old_dir, + struct dentry *old_dentry, + struct inode *new_dir, + struct dentry *new_dentry, + struct rename_info *info) +{ + int err = 0; + + print_entry_location(); + + if (dtohd_index(old_dentry, info->new_bstart)) { + /* rename the last source, knowing we're overwriting something */ + DPUT(info->wh_old); + info->bwh_old = info->new_bstart; + err = + do_rename(old_dir, old_dentry, new_dir, new_dentry, + info->new_bstart, &info->wh_old); + if (IS_COPYUP_ERR(err)) { + if (info->isdir) { + err = -EXDEV; + goto out; + } + if (info->rename_ok > info->new_bstart) { + if ((info->do_copyup == -1) + || (info->new_bstart - 1 < info->do_copyup)) + info->do_copyup = info->new_bstart - 1; + } + if ((info->do_whiteout == -1) + || (info->new_bstart - 1 < info->do_whiteout)) { + info->do_whiteout = info->new_bstart - 1; + } + err = 0; // reset error + } + } else if (info->new_bstart < info->old_bstart) { + /* the newly renamed file would get hidden, let's unlink the + * file to the left of it */ + struct dentry *unlink_dentry; + struct dentry *unlink_dir_dentry; + + unlink_dentry = dtohd_index(new_dentry, info->new_bstart); + + unlink_dir_dentry = lock_parent(unlink_dentry); + if (!(err = is_robranch_super(old_dir->i_sb, info->new_bstart))) + err = vfs_unlink(unlink_dir_dentry->d_inode, + unlink_dentry, NULL); + + fist_copy_attr_times(new_dentry->d_parent->d_inode, + unlink_dir_dentry->d_inode); + new_dentry->d_parent->d_inode->i_nlink = + get_nlinks(new_dentry->d_parent->d_inode); + + unlock_dir(unlink_dir_dentry); + + if (IS_COPYUP_ERR(err)) { + if (info->isdir) { + err = -EXDEV; + goto out; + } + if ((info->do_copyup == -1) + || (info->new_bstart - 1 < info->do_copyup)) + info->do_copyup = info->new_bstart - 1; + + err = 0; // reset error + } + } + + out: + print_exit_status(err); + return err; +} + +/* + * The function is nasty, nasty, nasty, but so is rename. :( + */ +static int unionfs_rename_all(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + struct dentry *parent_dentry = NULL; + int err = 0; + int eio; + + /* These variables control error handling. */ + fd_set success_mask; + char *name = NULL; + + /* unfortunately, we have to resort to this, because dbstart/dbend would + return different things in different place of the rename code */ + struct rename_info info; + + info.rename_ok = FD_SETSIZE; /* The last rename that is ok. */ + info.do_copyup = -1; /* Where we should start copyup. */ + info.do_whiteout = -1; /* Where we should start whiteouts of the source. */ + info.wh_old = NULL; + info.bwh_old = -1; + + print_entry_location(); + + parent_dentry = old_dentry->d_parent; + name = KMALLOC(old_dentry->d_name.len + 1, GFP_KERNEL); + if (!name) { + err = -ENOMEM; + goto out; + } + strncpy(name, old_dentry->d_name.name, old_dentry->d_name.len + 1); + + info.new_bstart = dbstart(new_dentry); + info.new_bend = dbend(new_dentry); + + info.old_bstart = dbstart(old_dentry); + info.old_bend = dbend(old_dentry); + + BUG_ON(info.new_bstart < 0); + BUG_ON(info.old_bstart < 0); + + /* The failure mask only can deal with FD_SETSIZE entries. */ + BUG_ON(info.old_bend > FD_SETSIZE); + BUG_ON(info.new_bend > FD_SETSIZE); + FD_ZERO(&success_mask); + + /* Life is simpler if the dentry doesn't exist. */ + info.clobber = + (dtohd_index(new_dentry, info.new_bstart)->d_inode) ? 1 : 0; + info.isdir = S_ISDIR(old_dentry->d_inode->i_mode); + + /* rename everything we can */ + err = + __rename_all(old_dir, old_dentry, new_dir, new_dentry, + &success_mask, &info); + if (err) + goto revert; + + /* unlink destinations even further left */ + err = + __rename_all_unlink(old_dir, old_dentry, new_dir, new_dentry, + &info); + if (err) + goto revert; + + if (info.clobber) { + /* Now we need to handle the leftmost of the destination. */ + err = + __rename_all_clobber(old_dir, old_dentry, new_dir, + new_dentry, &info); + if (err) + goto revert; + } + + /* Copy up if necessary */ + if (info.do_copyup != -1) { + int bindex; + + for (bindex = info.do_copyup; bindex >= 0; bindex--) { + err = + copyup_dentry(old_dentry->d_parent->d_inode, + old_dentry, info.old_bstart, bindex, + NULL, old_dentry->d_inode->i_size); + if (!err) { + DPUT(info.wh_old); + info.bwh_old = bindex; + err = + do_rename(old_dir, old_dentry, new_dir, + new_dentry, bindex, &info.wh_old); + break; + } + } + } + + /* make it opaque */ + if (S_ISDIR(old_dentry->d_inode->i_mode)) { + err = make_dir_opaque(old_dentry, dbstart(old_dentry)); + if (err) + goto revert; + } + + /* Create a whiteout for the source. */ + if (info.do_whiteout != -1) { + struct dentry *hidden_parent; + BUG_ON(info.do_whiteout < 0 + || !info.wh_old || IS_ERR(info.wh_old) + || info.wh_old->d_inode || info.bwh_old < 0); + hidden_parent = lock_parent(info.wh_old); + err = vfs_create(hidden_parent->d_inode, info.wh_old, S_IRUGO, + NULL); + unlock_dir(hidden_parent); + if (!err) + set_dbopaque(old_dentry, info.bwh_old); + else { + /* We can't fix anything now, so we -EIO. */ + printk(KERN_WARNING "We can't create a whiteout for the" + "source in rename!\n"); + err = -EIO; + goto out; + } + } + + /* We are at the point where reverting doesn't happen. */ + goto out; + + revert: + /* something bad happened, try to revert */ + eio = + __rename_all_revert(old_dir, old_dentry, new_dir, new_dentry, + &success_mask, &info); + if (eio) + err = eio; + + out: + DPUT(info.wh_old); + KFREE(name); + print_exit_status(err); + return err; +} +#endif + +static struct dentry *lookup_whiteout(struct dentry *dentry) +{ + char *whname; + int bindex = -1, bstart = -1, bend = -1; + struct dentry *parent, *hidden_parent, *wh_dentry; + + whname = alloc_whname(dentry->d_name.name, dentry->d_name.len); + if (IS_ERR(whname)) + return (void *)whname; + + parent = GET_PARENT(dentry); + lock_dentry(parent); + bstart = dbstart(parent); + bend = dbend(parent); + wh_dentry = ERR_PTR(-ENOENT); + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_parent = dtohd_index(parent, bindex); + if (!hidden_parent) + continue; + wh_dentry = + LOOKUP_ONE_LEN(whname, hidden_parent, + dentry->d_name.len + WHLEN); + if (IS_ERR(wh_dentry)) + continue; + if (wh_dentry->d_inode) + break; + DPUT(wh_dentry); + wh_dentry = ERR_PTR(-ENOENT); + } + unlock_dentry(parent); + DPUT(parent); + KFREE(whname); + return wh_dentry; +} + +/* We can't copyup a directory, because it may involve huge + * numbers of children, etc. Doing that in the kernel would + * be bad, so instead we let the userspace recurse and ask us + * to copy up each file separately + */ +static int may_rename_dir(struct dentry *dentry) +{ + int err, bstart; + + err = check_empty(dentry, NULL); + if (err == -ENOTEMPTY) { + if (is_robranch(dentry)) + return -EXDEV; + } else if (err) + return err; + + bstart = dbstart(dentry); + if (dbend(dentry) == bstart || dbopaque(dentry) == bstart) + return 0; + + set_dbstart(dentry, bstart + 1); + err = check_empty(dentry, NULL); + set_dbstart(dentry, bstart); + if (err == -ENOTEMPTY) + err = -EXDEV; + return err; +} + +int unionfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + int err = 0; + struct dentry *wh_dentry; + + print_entry_location(); + + double_lock_dentry(old_dentry, new_dentry); + + checkinode(old_dir, "unionfs_rename-old_dir"); + checkinode(new_dir, "unionfs_rename-new_dir"); + print_dentry("IN: unionfs_rename, old_dentry", old_dentry); + print_dentry("IN: unionfs_rename, new_dentry", new_dentry); + + if (!S_ISDIR(old_dentry->d_inode->i_mode)) + err = unionfs_partial_lookup(old_dentry); + else + err = may_rename_dir(old_dentry); + + if (err) + goto out; + + err = unionfs_partial_lookup(new_dentry); + if (err) + goto out; + + /* + * if new_dentry is already hidden because of whiteout, + * simply override it even if the whiteouted dir is not empty. + */ + wh_dentry = lookup_whiteout(new_dentry); + if (!IS_ERR(wh_dentry)) + DPUT(wh_dentry); + else if (new_dentry->d_inode) { + if (S_ISDIR(old_dentry->d_inode->i_mode) != + S_ISDIR(new_dentry->d_inode->i_mode)) { + err = + S_ISDIR(old_dentry->d_inode-> + i_mode) ? -ENOTDIR : -EISDIR; + goto out; + } + + if (S_ISDIR(new_dentry->d_inode->i_mode)) { + struct unionfs_dir_state *namelist; + /* check if this unionfs directory is empty or not */ + err = check_empty(new_dentry, &namelist); + if (err) + goto out; + + if (!is_robranch(new_dentry)) + err = delete_whiteouts(new_dentry, + dbstart(new_dentry), + namelist); + + free_rdstate(namelist); + + if (err) + goto out; + } + } +#ifdef UNIONFS_DELETE_ALL + if (IS_SET(old_dir->i_sb, DELETE_ALL)) + err = unionfs_rename_all(old_dir, old_dentry, new_dir, + new_dentry); + else +#endif + err = unionfs_rename_whiteout(old_dir, old_dentry, new_dir, + new_dentry); + + out: + checkinode(new_dir, "post unionfs_rename-new_dir"); + print_dentry("OUT: unionfs_rename, old_dentry", old_dentry); + + if (err) { + /* clear the new_dentry stuff created */ + d_drop(new_dentry); + } else { + /* force re-lookup since the dir on ro branch is not renamed, + and hidden dentries still indicate the un-renamed ones. */ + if (S_ISDIR(old_dentry->d_inode->i_mode)) + atomic_dec(&dtopd(old_dentry)->udi_generation); + print_dentry("OUT: unionfs_rename, new_dentry", + new_dentry); + } + + unlock_dentry(new_dentry); + unlock_dentry(old_dentry); + print_exit_status(err); + return err; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/unionfs_macros.h +++ linux-2.6.27/ubuntu/unionfs/unionfs_macros.h @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: unionfs_macros.h,v 1.13 2006/06/01 03:11:03 jsipek Exp $ + */ + +#ifndef __UNIONFS_H_ +#error This file should only be included from unionfs.h! +#endif + +/* Inode to private data */ +static inline struct unionfs_inode_info *itopd(const struct inode *inode) +{ + return + &(container_of(inode, struct unionfs_inode_container, vfs_inode)-> + info); +} + +#define itohi_ptr(ino) (itopd(ino)->uii_inode) +#define ibstart(ino) (itopd(ino)->b_start) +#define ibend(ino) (itopd(ino)->b_end) + +/* Superblock to private data */ +#define stopd(super) ((struct unionfs_sb_info *)(super)->s_fs_info) +#define stopd_lhs(super) ((super)->s_fs_info) +#define sbstart(sb) 0 +#define sbend(sb) stopd(sb)->b_end +#define sbmax(sb) (stopd(sb)->b_end + 1) + +/* File to private Data */ +#define ftopd(file) ((struct unionfs_file_info *)((file)->private_data)) +#define ftopd_lhs(file) ((file)->private_data) +#define ftohf_ptr(file) (ftopd(file)->ufi_file) +#define fbstart(file) (ftopd(file)->b_start) +#define fbend(file) (ftopd(file)->b_end) + +/* File to hidden file. */ +static inline struct file *ftohf(struct file *f) +{ + return ftopd(f)->ufi_file[fbstart(f)]; +} + +static inline struct file *ftohf_index(const struct file *f, int index) +{ + return ftopd(f)->ufi_file[index]; +} + +static inline void set_ftohf_index(struct file *f, int index, struct file *val) +{ + ftopd(f)->ufi_file[index] = val; +} + +static inline void set_ftohf(struct file *f, struct file *val) +{ + ftopd(f)->ufi_file[fbstart(f)] = val; +} + +/* Inode to hidden inode. */ +static inline struct inode *itohi(const struct inode *i) +{ + return itopd(i)->uii_inode[ibstart(i)]; +} + +static inline struct inode *itohi_index(const struct inode *i, int index) +{ + return itopd(i)->uii_inode[index]; +} + +static inline void set_itohi_index(struct inode *i, int index, + struct inode *val) +{ + itopd(i)->uii_inode[index] = val; +} + +static inline void set_itohi(struct inode *i, struct inode *val) +{ + itopd(i)->uii_inode[ibstart(i)] = val; +} + +/* Superblock to hidden superblock. */ +static inline struct super_block *stohs(const struct super_block *o) +{ + return stopd(o)->usi_data[sbstart(o)].sb; +} + +static inline struct super_block *stohs_index(const struct super_block *o, int index) +{ + return stopd(o)->usi_data[index].sb; +} + +static inline void set_stohs_index(struct super_block *o, int index, + struct super_block *val) +{ + stopd(o)->usi_data[index].sb = val; +} + +static inline void set_stohs(struct super_block *o, struct super_block *val) +{ + stopd(o)->usi_data[sbstart(o)].sb = val; +} + +/* Super to hidden mount. */ +static inline struct vfsmount *stohiddenmnt_index(struct super_block *o, + int index) +{ + return stopd(o)->usi_data[index].hidden_mnt; +} + +static inline void set_stohiddenmnt_index(struct super_block *o, int index, + struct vfsmount *val) +{ + stopd(o)->usi_data[index].hidden_mnt = val; +} + +/* Branch count macros. */ +static inline int branch_count(struct super_block *o, int index) +{ + return atomic_read(&stopd(o)->usi_data[index].sbcount); +} + +static inline void set_branch_count(struct super_block *o, int index, int val) +{ + atomic_set(&stopd(o)->usi_data[index].sbcount, val); +} + +static inline void branchget(struct super_block *o, int index) +{ + atomic_inc(&stopd(o)->usi_data[index].sbcount); +} + +static inline void branchput(struct super_block *o, int index) +{ + atomic_dec(&stopd(o)->usi_data[index].sbcount); +} + +/* Dentry macros */ +static inline struct unionfs_dentry_info *dtopd(const struct dentry *dent) +{ + return (struct unionfs_dentry_info *)dent->d_fsdata; +} + +#define dtopd_lhs(dent) ((dent)->d_fsdata) +#define dtopd_nocheck(dent) dtopd(dent) +#define dbstart(dent) (dtopd(dent)->udi_bstart) +#define set_dbstart(dent, val) do { dtopd(dent)->udi_bstart = val; } while(0) +#define dbend(dent) (dtopd(dent)->udi_bend) +#define set_dbend(dent, val) do { dtopd(dent)->udi_bend = val; } while(0) +#define dbopaque(dent) (dtopd(dent)->udi_bopaque) +#define set_dbopaque(dent, val) do { dtopd(dent)->udi_bopaque = val; } while (0) + +static inline void set_dtohd_index(struct dentry *dent, int index, + struct dentry *val) +{ + dtopd(dent)->udi_dentry[index] = val; +} + +static inline struct dentry *dtohd_index(const struct dentry *dent, int index) +{ + return dtopd(dent)->udi_dentry[index]; +} + +static inline struct dentry *dtohd(const struct dentry *dent) +{ + return dtopd(dent)->udi_dentry[dbstart(dent)]; +} + +#define set_dtohd_index_nocheck(dent, index, val) set_dtohd_index(dent, index, val) +#define dtohd_index_nocheck(dent, index) dtohd_index(dent, index) + +#define dtohd_ptr(dent) (dtopd_nocheck(dent)->udi_dentry) + +/* Macros for locking a dentry. */ +#define lock_dentry(d) down(&dtopd(d)->udi_sem) +#define unlock_dentry(d) up(&dtopd(d)->udi_sem) +#define verify_locked(d) + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/rdstate.c +++ linux-2.6.27/ubuntu/unionfs/rdstate.c @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: rdstate.c,v 1.34 2006/08/05 01:28:46 jro Exp $ + */ + +#include "unionfs.h" + +/* This file contains the routines for maintaining readdir state. */ +/* There are two structures here, rdstate which is a hash table + * of the second structure which is a filldir_node. */ + +/* This is a struct kmem_cache for filldir nodes, because we allocate a lot of them + * and they shouldn't waste memory. If the node has a small name (as defined + * by the dentry structure), then we use an inline name to preserve kmalloc + * space. */ +static struct kmem_cache *unionfs_filldir_cachep; +int init_filldir_cache(void) +{ + unionfs_filldir_cachep = + kmem_cache_create("unionfs_filldir", sizeof(struct filldir_node), 0, + SLAB_RECLAIM_ACCOUNT, NULL); + + if (!unionfs_filldir_cachep) + return -ENOMEM; + + return 0; +} + +void destroy_filldir_cache(void) +{ + if (!unionfs_filldir_cachep) + return; + kmem_cache_destroy(unionfs_filldir_cachep); + return; +} + +/* This is a tuning parameter that tells us roughly how big to make the + * hash table in directory entries per page. This isn't perfect, but + * at least we get a hash table size that shouldn't be too overloaded. + * The following averages are based on my home directory. + * 14.44693 Overall + * 12.29 Single Page Directories + * 117.93 Multi-page directories + */ +#define DENTPAGE 4096 +#define DENTPERONEPAGE 12 +#define DENTPERPAGE 118 +#define MINHASHSIZE 1 +static int guesstimate_hash_size(struct inode *inode) +{ + struct inode *hidden_inode; + int bindex; + int hashsize = MINHASHSIZE; + + if (itopd(inode)->uii_hashsize > 0) + return itopd(inode)->uii_hashsize; + + for (bindex = ibstart(inode); bindex <= ibend(inode); bindex++) { + if (!(hidden_inode = itohi_index(inode, bindex))) + continue; + + if (hidden_inode->i_size == DENTPAGE) { + hashsize += DENTPERONEPAGE; + } else { + hashsize += + (hidden_inode->i_size / DENTPAGE) * DENTPERPAGE; + } + } + + return hashsize; +} + +int init_rdstate(struct file *file) +{ + BUG_ON(sizeof(loff_t) != (sizeof(unsigned int) + sizeof(unsigned int))); + BUG_ON(ftopd(file)->rdstate != NULL); + + ftopd(file)->rdstate = + alloc_rdstate(file->f_dentry->d_inode, fbstart(file)); + if (!ftopd(file)->rdstate) + return -ENOMEM; + return 0; +} + +struct unionfs_dir_state *find_rdstate(struct inode *inode, loff_t fpos) +{ + struct unionfs_dir_state *rdstate = NULL; + struct list_head *pos; + + print_entry("f_pos: %lld", fpos); + spin_lock(&itopd(inode)->uii_rdlock); + list_for_each(pos, &itopd(inode)->uii_readdircache) { + struct unionfs_dir_state *r = + list_entry(pos, struct unionfs_dir_state, uds_cache); + if (fpos == rdstate2offset(r)) { + itopd(inode)->uii_rdcount--; + list_del(&r->uds_cache); + rdstate = r; + break; + } + } + spin_unlock(&itopd(inode)->uii_rdlock); + print_exit_pointer(rdstate); + return rdstate; +} + +struct unionfs_dir_state *alloc_rdstate(struct inode *inode, int bindex) +{ + int i = 0; + int hashsize; + int mallocsize = sizeof(struct unionfs_dir_state); + struct unionfs_dir_state *rdstate; + + hashsize = guesstimate_hash_size(inode); + mallocsize += hashsize * sizeof(struct list_head); + /* Round it up to the next highest power of two. */ + mallocsize--; + mallocsize |= mallocsize >> 1; + mallocsize |= mallocsize >> 2; + mallocsize |= mallocsize >> 4; + mallocsize |= mallocsize >> 8; + mallocsize |= mallocsize >> 16; + mallocsize++; + + /* This should give us about 500 entries anyway. */ + if (mallocsize > PAGE_SIZE) + mallocsize = PAGE_SIZE; + + hashsize = + (mallocsize - + sizeof(struct unionfs_dir_state)) / sizeof(struct list_head); + + rdstate = KMALLOC(mallocsize, GFP_KERNEL); + if (!rdstate) + return NULL; + + spin_lock(&itopd(inode)->uii_rdlock); + if (itopd(inode)->uii_cookie >= (MAXRDCOOKIE - 1)) + itopd(inode)->uii_cookie = 1; + else + itopd(inode)->uii_cookie++; + + rdstate->uds_cookie = itopd(inode)->uii_cookie; + spin_unlock(&itopd(inode)->uii_rdlock); + rdstate->uds_offset = 1; + rdstate->uds_access = jiffies; + rdstate->uds_bindex = bindex; + rdstate->uds_dirpos = 0; + rdstate->uds_hashentries = 0; + rdstate->uds_size = hashsize; + for (i = 0; i < rdstate->uds_size; i++) + INIT_LIST_HEAD(&rdstate->uds_list[i]); + + return rdstate; +} + +static void free_filldir_node(struct filldir_node *node) +{ + if (node->namelen >= DNAME_INLINE_LEN_MIN) + KFREE(node->name); + kmem_cache_free(unionfs_filldir_cachep, node); +} + +void free_rdstate(struct unionfs_dir_state *state) +{ + struct filldir_node *tmp; + int i; + + for (i = 0; i < state->uds_size; i++) { + struct list_head *head = &(state->uds_list[i]); + struct list_head *pos, *n; + + /* traverse the list and deallocate space */ + list_for_each_safe(pos, n, head) { + tmp = list_entry(pos, struct filldir_node, file_list); + list_del(&tmp->file_list); + free_filldir_node(tmp); + } + } + + KFREE(state); +} + +struct filldir_node *find_filldir_node(struct unionfs_dir_state *rdstate, + const char *name, int namelen) +{ + int index; + unsigned int hash; + struct list_head *head; + struct list_head *pos; + struct filldir_node *cursor = NULL; + int found = 0; + + /* If we print entry, we end up with spurious data. */ + /* print_entry("name = %*s", namelen, name); */ + print_entry_location(); + + BUG_ON(namelen <= 0); + + hash = full_name_hash(name, namelen); + index = hash % rdstate->uds_size; + + head = &(rdstate->uds_list[index]); + list_for_each(pos, head) { + cursor = list_entry(pos, struct filldir_node, file_list); + + if (cursor->namelen == namelen && cursor->hash == hash + && !strncmp(cursor->name, name, namelen)) { + /* a duplicate exists, and hence no need to create entry to the list */ + found = 1; + /* if the duplicate is in this branch, then the file system is corrupted. */ + if (cursor->bindex == rdstate->uds_bindex) { + //buf->error = err = -EIO; + dprint(PRINT_DEBUG, + "Possible I/O error unionfs_filldir: a file is duplicated in the same branch %d: %s\n", + rdstate->uds_bindex, cursor->name); + } + break; + } + } + + if (!found) { + cursor = NULL; + } + print_exit_pointer(cursor); + return cursor; +} + +inline struct filldir_node *alloc_filldir_node(const char *name, int namelen, + unsigned int hash, int bindex) +{ + struct filldir_node *newnode; + + newnode = + (struct filldir_node *)kmem_cache_alloc(unionfs_filldir_cachep, + GFP_KERNEL); + if (!newnode) + goto out; + + out: + return newnode; +} + +int add_filldir_node(struct unionfs_dir_state *rdstate, const char *name, + int namelen, int bindex, int whiteout) +{ + struct filldir_node *new; + unsigned int hash; + int index; + int err = 0; + struct list_head *head; + + /* We can't print this because we end up Oopsing. */ + /* print_entry("name = %*s", namelen, name); */ + print_entry_location(); + + BUG_ON(namelen <= 0); + + hash = full_name_hash(name, namelen); + index = hash % rdstate->uds_size; + head = &(rdstate->uds_list[index]); + + new = alloc_filldir_node(name, namelen, hash, bindex); + if (!new) { + err = -ENOMEM; + goto out; + } + + INIT_LIST_HEAD(&new->file_list); + new->namelen = namelen; + new->hash = hash; + new->bindex = bindex; + new->whiteout = whiteout; + + if (namelen < DNAME_INLINE_LEN_MIN) { + new->name = new->iname; + } else { + new->name = (char *)KMALLOC(namelen + 1, GFP_KERNEL); + if (!new->name) { + kmem_cache_free(unionfs_filldir_cachep, new); + new = NULL; + goto out; + } + } + + memcpy(new->name, name, namelen); + new->name[namelen] = '\0'; + + rdstate->uds_hashentries++; + + list_add(&(new->file_list), head); + out: + print_exit_status(err); + return err; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/persistent_inode.c +++ linux-2.6.27/ubuntu/unionfs/persistent_inode.c @@ -0,0 +1,658 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: persistent_inode.c,v 1.36 2006/07/08 17:58:31 ezk Exp $ + */ +#ifdef UNIONFS_IMAP + +#include "unionfs.h" + +static ssize_t __fread(struct file *filp, void *buf, size_t size, loff_t * pos) +{ + int err; + mm_segment_t oldfs; + ssize_t(*func) (struct file *, char __user *, size_t, loff_t *); + + func = do_sync_read; + if (filp->f_op && filp->f_op->read) + func = filp->f_op->read; + + oldfs = get_fs(); + set_fs(KERNEL_DS); + do { + err = func(filp, (char __user *)buf, size, pos); + } while (err == -EAGAIN || err == -EINTR); + set_fs(oldfs); + return err; +} + +static ssize_t __fwrite(struct file *filp, void *buf, size_t size, loff_t * pos) +{ + int err; + mm_segment_t oldfs; + unsigned long flim; + struct rlimit *rl; + ssize_t(*func) (struct file *, const char __user *, size_t, loff_t *); + + func = do_sync_write; + if (filp->f_op && filp->f_op->write) + func = filp->f_op->write; + + /* + * it breaks RLIMIT_FSIZE, + * but users should be careful to quota. + */ + rl = current->signal->rlim + RLIMIT_FSIZE; + flim = rl->rlim_cur; + rl->rlim_cur = RLIM_INFINITY; + oldfs = get_fs(); + set_fs(KERNEL_DS); + do { + err = func(filp, (const char __user *)buf, size, pos); + } while (err == -EAGAIN || err == -EINTR); + set_fs(oldfs); + rl->rlim_cur = flim; + return err; +} + +/* + * verify_forwardmap(super_block *sb) + * sb: pointer to a superblock containing the forwardmap. + * returns: 0 on success EINVAL or ENOMEM on failure; + */ +static int verify_forwardmap(struct super_block *sb) +{ + int err = 0, bytesread = 0, bindex = 0, mallocsize = 0; + loff_t readpos = 0; + struct file *forwardmap = NULL; + struct fmaphdr header; + struct unionfs_sb_info *spd = NULL; + print_entry_location(); + + spd = stopd(sb); + BUG_ON(!spd); + + forwardmap = spd->usi_forwardmap; + if (!forwardmap) { + err = -EINVAL; + goto out; + } + bytesread = __fread(forwardmap, &header, sizeof(struct fmaphdr), + &readpos); + if (bytesread < sizeof(struct fmaphdr)) { + err = -EINVAL; + goto out; + } + if (header.magic != FORWARDMAP_MAGIC + || header.version != FORWARDMAP_VERSION) { + err = -EINVAL; + goto out; + } + spd->usi_bmap = + KMALLOC(sizeof(struct bmapent) * header.usedbranches, GFP_KERNEL); + + if (!spd->usi_bmap) { + err = -ENOMEM; + goto out; + } + + while (bindex < header.usedbranches) { + bytesread = __fread(forwardmap, &stopd(sb)->usi_bmap[bindex], + sizeof(struct bmapent), &readpos); + if (bytesread < sizeof(struct bmapent)) { + err = -EINVAL; + goto out_err; + } + bindex++; + } + + mallocsize = sizeof(int) * header.usedbranches; + goto out; + out_err: + if (spd->usi_bmap) + KFREE(spd->usi_bmap); + out: + print_exit_status(err); + return err; +} + +/* + * verify_reversemap(struct super_block sb, int rmapindex) + * + * sb: The unionfs superblock containing all of the current imap info + * rmapindex: the index in the usi_reversemaps array that we wish to + * verify + * + * Assumes the reverse maps less than rmapindex are valid. + * + * returns: 0 if the opperation succeds + * -EINVAL if the map file does not belong to the forward map + * + */ +static int verify_reversemap(struct super_block *sb, int rmapindex, + struct unionfs_dentry_info *hidden_root_info) +{ + int err = 0, i = 0, bindex = 0, found = 0, bytesread; + loff_t readpos = 0; + struct file *forwardmap, *reversemap; + struct fmaphdr fheader; + struct rmaphdr rheader; + struct kstatfs st; + struct unionfs_sb_info *spd = NULL; + + print_entry_location(); + + spd = stopd(sb); + BUG_ON(!spd); + + forwardmap = spd->usi_forwardmap; + if (!forwardmap) { + err = -EINVAL; + goto out; + } + reversemap = spd->usi_reversemaps[rmapindex]; + if (!reversemap) { + err = -EINVAL; + goto out; + } + bytesread = __fread(forwardmap, &fheader, sizeof(struct fmaphdr), + &readpos); + if (bytesread < sizeof(struct fmaphdr)) { + err = -EINVAL; + goto out; + } + readpos = 0; + bytesread = __fread(reversemap, &rheader, sizeof(struct rmaphdr), + &readpos); + if (bytesread < sizeof(struct rmaphdr)) { + err = -EINVAL; + goto out; + } + if (rheader.magic != REVERSEMAP_MAGIC + || rheader.version != REVERSEMAP_VERSION) { + err = -EINVAL; + goto out; + } + if (memcmp(fheader.uuid, rheader.fwduuid, sizeof(fheader.uuid))) { + err = -EINVAL; + goto out; + } + + /* XXX: Ok so here we take the new map and read the fsid from it. Then + * we go through all the branches in the union and see which ones it + * matches with*/ + for (i = 0; i < spd->usi_num_bmapents && !found; i++) { + if (memcmp + (rheader.revuuid, spd->usi_bmap[i].uuid, + sizeof(rheader.revuuid))) + continue; + + found = 1; + for (bindex = 0; bindex <= hidden_root_info->udi_bend; bindex++) { + struct dentry *d; + fsid_t fsid; + dev_t dev; + memset(&st, 0, sizeof(struct kstatfs)); + + d = hidden_root_info->udi_dentry[bindex]; + + err = d->d_sb->s_op->statfs(d->d_sb, &st); + if (err) + goto out; + + if (st.f_fsid.val[0] || st.f_fsid.val[1]) { + fsid = st.f_fsid; + } else { + + dev = d->d_sb->s_dev; + fsid.val[0] = MAJOR(dev); + fsid.val[1] = MINOR(dev); + } + + if (memcmp(&fsid, &rheader.fsid, sizeof(fsid))) + continue; + + if (spd->usi_bnum_table[bindex] == -1) + spd->usi_bnum_table[bindex] = i; + if (spd->usi_map_table[bindex]) { + printk(KERN_WARNING + "Two reverse maps share fsid %u%u!\n", + rheader.fsid.val[0], + rheader.fsid.val[1]); + err = -EINVAL; + goto out; + } else { + spd->usi_map_table[bindex] = reversemap; + } + } + } + if (!found) { + printk(KERN_WARNING + "Could not match the reversemap uuid with an entry in the forwardmap table\n"); + err = -EINVAL; + } + out: + print_exit_status(err); + return err; +} + +int init_imap_data(struct super_block *sb, + struct unionfs_dentry_info *hidden_root_info) +{ + int i, err = 0, mallocsize = 0; + struct unionfs_sb_info *spd; + + print_entry_location(); + + spd = stopd(sb); + + spd->usi_forwardmap = NULL; + spd->usi_reversemaps = NULL; + spd->usi_bnum_table = NULL; + + mallocsize = sizeof(struct file *) * (hidden_root_info->udi_bend + 1); + spd->usi_reversemaps = KZALLOC(mallocsize, GFP_KERNEL); + if (!spd->usi_reversemaps) { + err = -ENOMEM; + goto out_error; + } + + spd->usi_map_table = KZALLOC(mallocsize, GFP_KERNEL); + if (!spd->usi_map_table) { + err = -ENOMEM; + goto out_error; + } + + mallocsize = sizeof(int) * (hidden_root_info->udi_bend + 1); + spd->usi_bnum_table = KMALLOC(mallocsize, GFP_KERNEL); + if (!spd->usi_bnum_table) { + err = -ENOMEM; + goto out_error; + } + + for (i = 0; i <= hidden_root_info->udi_bend; i++) { + spd->usi_bnum_table[i] = -1; + } + + if (!err) + goto out; + out_error: + + if (spd->usi_reversemaps) { + KFREE(spd->usi_reversemaps); + spd->usi_reversemaps = NULL; + } + + if (spd->usi_map_table) { + KFREE(spd->usi_map_table); + spd->usi_map_table = NULL; + } + + if (spd->usi_bnum_table) { + KFREE(spd->usi_bnum_table); + spd->usi_bnum_table = NULL; + + } + + out: + print_exit_status(err); + return err; + +} + +void cleanup_imap_data(struct super_block *sb) +{ + int count = 0; + struct unionfs_sb_info *spd; + + print_entry_location(); + + spd = stopd(sb); + + spd->usi_persistent = 0; + count = spd->usi_num_bmapents; + while (count - 1 >= 0) { + if (spd->usi_reversemaps[count - 1]) { + filp_close(spd->usi_reversemaps[count - 1], NULL); + spd->usi_reversemaps[count - 1] = NULL; + } + count--; + } + if (spd->usi_reversemaps) { + KFREE(spd->usi_reversemaps); + spd->usi_reversemaps = NULL; + } + + if (spd->usi_map_table) { + KFREE(spd->usi_map_table); + spd->usi_map_table = NULL; + } + + if (spd->usi_bnum_table) { + KFREE(spd->usi_bnum_table); + spd->usi_bnum_table = NULL; + } + if (spd->usi_forwardmap) { + filp_close(spd->usi_forwardmap, NULL); + spd->usi_forwardmap = NULL; + } + print_exit_location(); +} + +int parse_imap_option(struct super_block *sb, + struct unionfs_dentry_info *hidden_root_info, + char *options) +{ + int count = 0, err = 0; + char *name; + struct unionfs_sb_info *spd = NULL; + + print_entry_location(); + spd = stopd(sb); + BUG_ON(!spd); + + err = init_imap_data(sb, hidden_root_info); + if (err) + goto out_error; + while ((name = strsep(&options, ":")) != NULL) { + if (!*name) + continue; + if (!spd->usi_forwardmap) { + spd->usi_forwardmap = filp_open(name, O_RDWR, 0); + if (IS_ERR(spd->usi_forwardmap)) { + err = PTR_ERR(spd->usi_forwardmap); + spd->usi_forwardmap = NULL; + goto out_error; + } + } else { + spd->usi_reversemaps[count] = + filp_open(name, O_RDWR, 0); + if (IS_ERR(spd->usi_reversemaps[count])) { + err = PTR_ERR(spd->usi_reversemaps[count]); + spd->usi_reversemaps[count] = NULL; + goto out_error; + + } + count++; + } + } + if (count <= 0) { + printk(KERN_WARNING "unionfs: no reverse maps specified.\n"); + err = -EINVAL; + } + if (err) + goto out_error; + + /* Initialize the super block's next_avail field */ + /* Dave, you can't use 64-bit division here because the i386 doesn't + * support it natively. Instead you need to punt if the size is + * greater than unsigned long, and then cast it down. Then you should + * be able to assign to this value, without having these problems. */ + + if (spd->usi_forwardmap->f_dentry->d_inode->i_size > ULONG_MAX) { + err = -EFBIG; + goto out_error; + } + spd->usi_next_avail = + ((unsigned long)(spd->usi_forwardmap->f_dentry->d_inode-> + i_size - (sizeof(struct fmaphdr) + + sizeof(struct bmapent[256]))) + / sizeof(struct fmapent)); + + if (spd->usi_next_avail < FIRST_VALID_INODE) + spd->usi_next_avail = FIRST_VALID_INODE; + + spd->usi_num_bmapents = count; + err = verify_forwardmap(sb); + if (err) + goto out_error; + while (count > 0) { + err = verify_reversemap(sb, --count, hidden_root_info); + if (err) + goto out_error; + } + spd->usi_persistent = 1; + + goto out; + + out_error: + spd->usi_num_bmapents = count; + cleanup_imap_data(sb); + + out: + print_exit_status(err); + return err; +} + + /* + * get @ino from @hidden_ino. + */ +static int __read_uin(struct unionfs_sb_info *sbi, ino_t hidden_ino, int bindex, + ino_t * ino) +{ + int err; + struct file *rev; + loff_t pos; + ssize_t sz; + uint64_t ino64; + const int elmnt = sizeof(ino64); + + rev = sbi->usi_map_table[bindex]; + pos = sizeof(struct rmaphdr) + elmnt * hidden_ino; + *ino = 0; + err = 0; + if (pos + elmnt > rev->f_dentry->d_inode->i_size) + goto out; + + sz = __fread(rev, &ino64, elmnt, &pos); + err = sz; + if (err < 0) + goto out; + err = 0; + *ino = -1; + if (sz != elmnt || ino64 > *ino) + err = -EIO; + *ino = ino64; + out: + print_exit_status(err); + return err; +} + +/* + * put unionfs @ino for @hidden_ino on @bindex. + */ +static int __write_uin(struct unionfs_sb_info *sbi, ino_t ino, int bindex, + ino_t hidden_ino) +{ + struct file *fwd, *rev; + struct fmapent ent; + loff_t pos; + ssize_t sz; + int err; + uint64_t ino64; + const int fwdhdr = sizeof(struct fmaphdr) + sizeof(struct bmapent[256]); + const int fwd_elmnt = sizeof(ent); + const int rev_elmnt = sizeof(ino64); + + err = -ENOSPC; + if (ino < FIRST_VALID_INODE) + goto out; + + fwd = sbi->usi_forwardmap; + ent.fsnum = sbi->usi_bnum_table[bindex]; + ent.inode = hidden_ino; + pos = fwdhdr + fwd_elmnt * ino; + sz = __fwrite(fwd, &ent, fwd_elmnt, &pos); + err = sz; + if (err < 0) + goto out; + err = -EIO; + if (sz != fwd_elmnt) + goto out; + + rev = sbi->usi_map_table[bindex]; + pos = sizeof(struct rmaphdr) + rev_elmnt * hidden_ino; + ino64 = ino; + sz = __fwrite(rev, &ino64, rev_elmnt, &pos); + err = sz; + if (err < 0) + goto out; + err = 0; + if (sz != rev_elmnt) + err = -EIO; + out: + print_exit_status(err); + return err; +} + +/* + * read_uin(struct super_block *sb, uint8_t branchnum, ino_t inode_number, int flag, ino_t *uino) + * fsnum: branch to reference when getting the inode number + * inode_number: lower level inode number use to reference the proper inode. + * flag: if set to O_CREAT it will creat the entry if it doesent exist + * otherwise it will return the existing one. + * returns: the unionfs inode number either created or retrieved based on + * the information. + */ +int read_uin(struct super_block *sb, uint8_t branchnum, ino_t inode_number, + int flag, ino_t * uino) +{ + int err = 0; + struct unionfs_sb_info *spd; + + print_entry_location(); + + spd = stopd(sb); + BUG_ON(!spd); + + /* Find appropriate reverse map and then read from the required position */ + /* get it from the array. */ + err = __read_uin(spd, inode_number, branchnum, uino); + if (err || *uino) + goto out; + + err = -EIO; + if (!(flag & O_CREAT)) + goto out; + + /* If we haven't found an entry and we have the O_CREAT flag set we want to + * create a new entry write it out to the file and return its index + */ + mutex_lock(&sb->s_lock); + *uino = spd->usi_next_avail++; + err = __write_uin(spd, *uino, branchnum, inode_number); + if (err) + spd->usi_next_avail--; + mutex_unlock(&sb->s_lock); + out: + print_exit_status(err); + return err; +} + +int write_uin(struct super_block *sb, ino_t ino, int bindex, ino_t hidden_ino) +{ + int err; + + print_entry_location(); + err = __write_uin(stopd(sb), ino, bindex, hidden_ino); + print_exit_status(err); + return err; +} + +/* + * get_lin(ino_t inode_number) + * inode_number : inode number for the unionfs inode + * returns: the lower level inode# and branch# + */ +/* entry should use a poiner on the stack. should be staticly allocated one + * level up*/ +int get_lin(struct super_block *sb, ino_t inode_number, struct fmapent *entry) +{ + struct file *forwardmap; + loff_t seek_size; + mm_segment_t oldfs; + int err = 0, bytesread = 0; + + print_entry_location(); + + if (!entry) { + entry = ERR_PTR(-ENOMEM); + goto out; + } + forwardmap = stopd(sb)->usi_forwardmap; + seek_size = + sizeof(struct fmaphdr) + sizeof(struct bmapent[256]) + + (sizeof(struct fmapent) * inode_number); + oldfs = get_fs(); + set_fs(KERNEL_DS); + bytesread = __fread(forwardmap, entry, sizeof(*entry), &seek_size); + set_fs(oldfs); + if (bytesread != sizeof(*entry)) + err = -EINVAL; + + out: + print_exit_location(); + return err; +} + +/* + * remove_map(struct super_block *sb,int bindex) + * + * sb: The super block containing all the current imap info + * bindex: the index of the branch that is being removed. + * + * This assumes that end hasen't been decremented yet. + * + * Returns: This function really can't fail. The only thing + * that could possibly happen is that it will oops but that + * requires unionfs to be in an inconsistant state which + * shoulden't happen. + */ +int remove_map(struct super_block *sb, int bindex) +{ + int i; + struct unionfs_sb_info *spd; + + print_entry_location(); + + spd = stopd(sb); + BUG_ON(!spd); + + for (i = bindex; i < sbend(sb); i++) { + spd->usi_map_table[i] = spd->usi_map_table[i + 1]; + spd->usi_bnum_table[i] = spd->usi_bnum_table[i + 1]; + } + return 0; +} + +#endif +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/subr.c +++ linux-2.6.27/ubuntu/unionfs/subr.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: subr.c,v 1.142 2006/09/21 18:19:36 jsipek Exp $ + */ + +#include "unionfs.h" +#include + +/* Pass an unionfs dentry and an index. It will try to create a whiteout + * for the filename in dentry, and will try in branch 'index'. On error, + * it will proceed to a branch to the left. + */ +int create_whiteout(struct dentry *dentry, int start) +{ + int bstart, bend, bindex; + struct dentry *hidden_dir_dentry; + struct dentry *hidden_dentry; + struct dentry *hidden_wh_dentry; + char *name = NULL; + int err = -EINVAL; + + print_entry("start = %d", start); + + verify_locked(dentry); + + print_dentry("IN create_whiteout", dentry); + bstart = dbstart(dentry); + bend = dbend(dentry); + + /* create dentry's whiteout equivalent */ + name = alloc_whname(dentry->d_name.name, dentry->d_name.len); + if (IS_ERR(name)) { + err = PTR_ERR(name); + goto out; + } + + for (bindex = start; bindex >= 0; bindex--) { + hidden_dentry = dtohd_index(dentry, bindex); + + if (!hidden_dentry) { + /* if hidden dentry is not present, create the entire + * hidden dentry directory structure and go ahead. + * Since we want to just create whiteout, we only want + * the parent dentry, and hence get rid of this dentry. + */ + hidden_dentry = create_parents(dentry->d_inode, + dentry, bindex); + if (!hidden_dentry || IS_ERR(hidden_dentry)) { + dprint(PRINT_DEBUG_WHITEOUT, + "create_parents failed for bindex = %d\n", + bindex); + continue; + } + } + hidden_wh_dentry = + LOOKUP_ONE_LEN(name, hidden_dentry->d_parent, + dentry->d_name.len + WHLEN); + if (IS_ERR(hidden_wh_dentry)) + continue; + + /* The whiteout already exists. This used to be impossible, but + * now is possible because of opaqueness. */ + if (hidden_wh_dentry->d_inode) { + DPUT(hidden_wh_dentry); + err = 0; + goto out; + } + + hidden_dir_dentry = lock_parent(hidden_wh_dentry); + if (!(err = is_robranch_super(dentry->d_sb, bindex))) { + err = + vfs_create(hidden_dir_dentry->d_inode, + hidden_wh_dentry, + ~current->fs->umask & S_IRWXUGO, NULL); + + } + unlock_dir(hidden_dir_dentry); + DPUT(hidden_wh_dentry); + + if (!err) + break; + + if (!IS_COPYUP_ERR(err)) + break; + } + + /* set dbopaque so that lookup will not proceed after this branch */ + if (!err) + set_dbopaque(dentry, bindex); + + print_dentry("OUT create_whiteout", dentry); + out: + KFREE(name); + print_exit_status(err); + return err; +} + +/* This is a helper function for rename, which ends up with hosed over dentries + * when it needs to revert. */ +int unionfs_refresh_hidden_dentry(struct dentry *dentry, int bindex) +{ + struct dentry *hidden_dentry; + struct dentry *hidden_parent; + int err = 0; + + print_entry(" bindex = %d", bindex); + + verify_locked(dentry); + lock_dentry(dentry->d_parent); + hidden_parent = dtohd_index(dentry->d_parent, bindex); + unlock_dentry(dentry->d_parent); + + BUG_ON(!S_ISDIR(hidden_parent->d_inode->i_mode)); + + hidden_dentry = + LOOKUP_ONE_LEN(dentry->d_name.name, hidden_parent, + dentry->d_name.len); + if (IS_ERR(hidden_dentry)) { + err = PTR_ERR(hidden_dentry); + goto out; + } + + if (dtohd_index(dentry, bindex)) + DPUT(dtohd_index(dentry, bindex)); + if (itohi_index(dentry->d_inode, bindex)) { + IPUT(itohi_index(dentry->d_inode, bindex)); + set_itohi_index(dentry->d_inode, bindex, NULL); + } + if (!hidden_dentry->d_inode) { + DPUT(hidden_dentry); + set_dtohd_index(dentry, bindex, NULL); + } else { + set_dtohd_index(dentry, bindex, hidden_dentry); + set_itohi_index(dentry->d_inode, bindex, + IGRAB(hidden_dentry->d_inode)); + } + + out: + print_exit_status(err); + return err; +} + +int make_dir_opaque(struct dentry *dentry, int bindex) +{ + int err; + struct dentry *hidden_dentry, *diropq; + struct inode *hidden_dir; + + hidden_dentry = dtohd_index(dentry, bindex); + hidden_dir = hidden_dentry->d_inode; + BUG_ON(!S_ISDIR(dentry->d_inode->i_mode) + || !S_ISDIR(hidden_dir->i_mode)); + + mutex_lock(&hidden_dir->i_mutex); + diropq = LOOKUP_ONE_LEN(UNIONFS_DIR_OPAQUE, hidden_dentry, + sizeof(UNIONFS_DIR_OPAQUE) - 1); + err = PTR_ERR(diropq); + if (IS_ERR(diropq)) + goto out; + err = 0; + + if (!diropq->d_inode) + err = vfs_create(hidden_dir, diropq, S_IRUGO, NULL); + DPUT(diropq); + if (!err) + set_dbopaque(dentry, bindex); + + out: + mutex_unlock(&hidden_dir->i_mutex); + return err; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/dentry.c +++ linux-2.6.27/ubuntu/unionfs/dentry.c @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: dentry.c,v 1.77 2006/08/05 01:28:46 jro Exp $ + */ + +#include "unionfs.h" + +/* declarations added for "sparse" */ +extern int unionfs_d_revalidate_wrap(struct dentry *dentry, + struct nameidata *nd); +extern void unionfs_d_release(struct dentry *dentry); +extern void unionfs_d_iput(struct dentry *dentry, struct inode *inode); + +/* + * THIS IS A BOOLEAN FUNCTION: returns 1 if valid, 0 otherwise. + */ +int unionfs_d_revalidate(struct dentry *dentry, struct nameidata *nd) +{ + int valid = 1; /* default is valid (1); invalid is 0. */ + struct dentry *hidden_dentry; + int bindex, bstart, bend; + int sbgen, dgen; + int positive = 0; + int locked = 0; + int restart = 0; + int interpose_flag; + + struct nameidata lowernd; + + if(nd) + memcpy(&lowernd, nd, sizeof(struct nameidata)); + else + memset(&lowernd, 0, sizeof(struct nameidata)); + + print_util_entry_location(); + + restart: + verify_locked(dentry); + + /* if the dentry is unhashed, do NOT revalidate */ + if (d_deleted(dentry)) { + dprint(PRINT_DEBUG, "unhashed dentry being revalidated: %*s\n", + dentry->d_name.len, dentry->d_name.name); + goto out; + } + + BUG_ON(dbstart(dentry) == -1); + if (dentry->d_inode) + positive = 1; + dgen = atomic_read(&dtopd(dentry)->udi_generation); + sbgen = atomic_read(&stopd(dentry->d_sb)->usi_generation); + /* If we are working on an unconnected dentry, then there is no + * revalidation to be done, because this file does not exist within the + * namespace, and Unionfs operates on the namespace, not data. + */ + if (sbgen != dgen) { + struct dentry *result; + int pdgen; + + unionfs_read_lock(dentry->d_sb); + locked = 1; + + /* The root entry should always be valid */ + BUG_ON(IS_ROOT(dentry)); + + /* We can't work correctly if our parent isn't valid. */ + pdgen = atomic_read(&dtopd(dentry->d_parent)->udi_generation); + if (!restart && (pdgen != sbgen)) { + unionfs_read_unlock(dentry->d_sb); + locked = 0; + /* We must be locked before our parent. */ + if (! + (dentry->d_parent->d_op-> + d_revalidate(dentry->d_parent, nd))) { + valid = 0; + goto out; + } + restart = 1; + goto restart; + } + BUG_ON(pdgen != sbgen); + + /* Free the pointers for our inodes and this dentry. */ + bstart = dbstart(dentry); + bend = dbend(dentry); + if (bstart >= 0) { + struct dentry *hidden_dentry; + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = + dtohd_index_nocheck(dentry, bindex); + if (!hidden_dentry) + continue; + DPUT(hidden_dentry); + } + } + set_dbstart(dentry, -1); + set_dbend(dentry, -1); + + interpose_flag = INTERPOSE_REVAL_NEG; + if (positive) { + interpose_flag = INTERPOSE_REVAL; + mutex_lock(&dentry->d_inode->i_mutex); + bstart = ibstart(dentry->d_inode); + bend = ibend(dentry->d_inode); + if (bstart >= 0) { + struct inode *hidden_inode; + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_inode = + itohi_index(dentry->d_inode, + bindex); + if (!hidden_inode) + continue; + IPUT(hidden_inode); + } + } + KFREE(itohi_ptr(dentry->d_inode)); + itohi_ptr(dentry->d_inode) = NULL; + ibstart(dentry->d_inode) = -1; + ibend(dentry->d_inode) = -1; + mutex_unlock(&dentry->d_inode->i_mutex); + } + + result = unionfs_lookup_backend(dentry, &lowernd, interpose_flag); + if (result) { + if (IS_ERR(result)) { + valid = 0; + goto out; + } + /* current unionfs_lookup_backend() doesn't return + a valid dentry */ + DPUT(dentry); + dentry = result; + } + + if (positive && itopd(dentry->d_inode)->uii_stale) { + make_stale_inode(dentry->d_inode); + d_drop(dentry); + valid = 0; + goto out; + } + goto out; + } + + /* The revalidation must occur across all branches */ + bstart = dbstart(dentry); + bend = dbend(dentry); + BUG_ON(bstart == -1); + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry || !hidden_dentry->d_op + || !hidden_dentry->d_op->d_revalidate) + continue; + + if (!hidden_dentry->d_op->d_revalidate(hidden_dentry, nd)) + valid = 0; + } + + if (!dentry->d_inode) + valid = 0; + if (valid) + fist_copy_attr_all(dentry->d_inode, itohi(dentry->d_inode)); + + out: + if (locked) + unionfs_read_unlock(dentry->d_sb); + print_dentry("revalidate out", dentry); + print_util_exit_status(valid); + return valid; +} + +int unionfs_d_revalidate_wrap(struct dentry *dentry, struct nameidata *nd) +{ + int err; + + print_entry_location(); + lock_dentry(dentry); + + err = unionfs_d_revalidate(dentry, nd); + + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +void unionfs_d_release(struct dentry *dentry) +{ + struct dentry *hidden_dentry; + int bindex, bstart, bend; + + print_entry_location(); + /* There is no reason to lock the dentry, because we have the only + * reference, but the printing functions verify that we have a lock + * on the dentry before calling dbstart, etc. */ + lock_dentry(dentry); + print_dentry_nocheck("unionfs_d_release IN dentry", dentry); + + /* this could be a negative dentry, so check first */ + if (!dtopd(dentry)) { + dprint(PRINT_DEBUG, "dentry without private data: %*s", + dentry->d_name.len, dentry->d_name.name); + goto out; + } else if (dbstart(dentry) < 0) { + /* this is due to a failed lookup */ + /* the failed lookup has a dtohd_ptr set to null, + but this is a better check */ + dprint(PRINT_DEBUG, "dentry without hidden dentries : %*s", + dentry->d_name.len, dentry->d_name.name); + goto out_free; + } + + /* Release all the hidden dentries */ + bstart = dbstart(dentry); + bend = dbend(dentry); + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + DPUT(hidden_dentry); + set_dtohd_index(dentry, bindex, NULL); + } + /* free private data (unionfs_dentry_info) here */ + KFREE(dtohd_ptr(dentry)); + dtohd_ptr(dentry) = NULL; + out_free: + /* No need to unlock it, because it is disappeared. */ +#ifdef TRACKLOCK + printk("DESTROYLOCK:%p\n", dentry); +#endif + free_dentry_private_data(dtopd(dentry)); + dtopd_lhs(dentry) = NULL; /* just to be safe */ + out: + print_exit_location(); +} + +/* + * we don't really need unionfs_d_iput, because dentry_iput will call iput() if + * unionfs_d_iput is not defined. We left this implemented for ease of + * tracing/debugging. + */ +void unionfs_d_iput(struct dentry *dentry, struct inode *inode) +{ + print_entry_location(); + IPUT(inode); + print_exit_location(); +} + +struct dentry_operations unionfs_dops = { + .d_revalidate = unionfs_d_revalidate_wrap, + .d_release = unionfs_d_release, + .d_iput = unionfs_d_iput, +}; + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/unionfs_imap.h +++ linux-2.6.27/ubuntu/unionfs/unionfs_imap.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: unionfs_imap.h,v 1.1 2006/05/30 21:38:45 jsipek Exp $ + */ + +#ifndef __UNIONFS_H_ +#error This file should only be included from unionfs.h! +#endif + +#ifdef UNIONFS_IMAP + +/*UUID typedef needed later*/ +typedef uint8_t uuid_t[16]; + +/* +* Defines,structs,and functions for persistent used by kernel and user +*/ +#define MAX_MAPS 256 +#define UUID_LEN 16 +#define FORWARDMAP_MAGIC 0x4b1cb38f +#define REVERSEMAP_MAGIC 0Xfcafad71 +#define FORWARDMAP_VERSION 0x02 +#define REVERSEMAP_VERSION 0x01 +#define FIRST_VALID_INODE 3 +struct fmaphdr { + uint32_t magic; + uint32_t version; + uint8_t usedbranches; + uint8_t uuid[UUID_LEN]; +}; + +struct rmaphdr { + uint32_t magic; + uint32_t version; + uint8_t fwduuid[UUID_LEN]; + uint8_t revuuid[UUID_LEN]; + fsid_t fsid; +}; +struct bmapent { + fsid_t fsid; + uint8_t uuid[UUID_LEN]; +}; +struct fmapent { + uint8_t fsnum; + uint64_t inode; +}; + +/* Persistant Inode functions */ +extern int read_uin(struct super_block *sb, uint8_t branchnum, + ino_t inode_number, int flag, ino_t * uino); +extern int write_uin(struct super_block *sb, ino_t ino, int bindex, + ino_t hidden_ino); +extern int get_lin(struct super_block *sb, ino_t inode_number, + struct fmapent *entry); +extern int parse_imap_option(struct super_block *sb, + struct unionfs_dentry_info *hidden_root_info, + char *options); +extern void cleanup_imap_data(struct super_block *sb); + +#endif /*#ifdef UNIONFS_IMAP */ + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/Kconfig +++ linux-2.6.27/ubuntu/unionfs/Kconfig @@ -0,0 +1,9 @@ +config FS_UNIONFS + tristate "UnionFS 1.4 Legacy" + default m + help + This is the v1.4 module, forward ported and beaten into + AppArmor submission. It is a fallback for aufs in case it ends + up being broken. We know this one works for the LiveCD, so + this is to keep the release managers from having to spend + long nights and pushing off deadlines. --- linux-2.6.27.orig/ubuntu/unionfs/stale_inode.c +++ linux-2.6.27/ubuntu/unionfs/stale_inode.c @@ -0,0 +1,133 @@ +/* + * Adpated from linux/fs/bad_inode.c + * + * Copyright (C) 1997, Stephen Tweedie + * + * Provide stub functions for "stale" inodes, a bit friendlier than the + * -EIO that bad_inode.c does. + */ +/* + * $Id: stale_inode.c,v 1.13 2006/03/21 09:22:11 jsipek Exp $ + */ + +#include + +#include +#include +#include + +static struct address_space_operations unionfs_stale_aops; + +/* declarations for "sparse */ +extern struct inode_operations stale_inode_ops; + +/* + * The follow_link operation is special: it must behave as a no-op + * so that a stale root inode can at least be unmounted. To do this + * we must dput() the base and return the dentry with a dget(). + */ +static void *stale_follow_link(struct dentry *dent, struct nameidata *nd) +{ + int err = vfs_follow_link(nd, ERR_PTR(-ESTALE)); + return ERR_PTR(err); +} + +static int return_ESTALE(void) +{ + return -ESTALE; +} + +#define ESTALE_ERROR ((void *) (return_ESTALE)) + +static struct file_operations stale_file_ops = { + .llseek = ESTALE_ERROR, + .read = ESTALE_ERROR, + .write = ESTALE_ERROR, + .readdir = ESTALE_ERROR, + .poll = ESTALE_ERROR, + .ioctl = ESTALE_ERROR, + .mmap = ESTALE_ERROR, + .open = ESTALE_ERROR, + .flush = ESTALE_ERROR, + .release = ESTALE_ERROR, + .fsync = ESTALE_ERROR, + .fasync = ESTALE_ERROR, + .lock = ESTALE_ERROR, +}; + +struct inode_operations stale_inode_ops = { + .create = ESTALE_ERROR, + .lookup = ESTALE_ERROR, + .link = ESTALE_ERROR, + .unlink = ESTALE_ERROR, + .symlink = ESTALE_ERROR, + .mkdir = ESTALE_ERROR, + .rmdir = ESTALE_ERROR, + .mknod = ESTALE_ERROR, + .rename = ESTALE_ERROR, + .readlink = ESTALE_ERROR, + .follow_link = stale_follow_link, + .truncate = ESTALE_ERROR, + .permission = ESTALE_ERROR, +}; + +/* + * When a filesystem is unable to read an inode due to an I/O error in + * its read_inode() function, it can call make_stale_inode() to return a + * set of stubs which will return ESTALE errors as required. + * + * We only need to do limited initialisation: all other fields are + * preinitialised to zero automatically. + */ + +/** + * make_stale_inode - mark an inode stale due to an I/O error + * @inode: Inode to mark stale + * + * When an inode cannot be read due to a media or remote network + * failure this function makes the inode "stale" and causes I/O operations + * on it to fail from this point on. + */ + +void make_stale_inode(struct inode *inode) +{ + inode->i_mode = S_IFREG; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_op = &stale_inode_ops; + inode->i_fop = &stale_file_ops; + inode->i_mapping->a_ops = &unionfs_stale_aops; +} + +/* + * This tests whether an inode has been flagged as stale. The test uses + * &stale_inode_ops to cover the case of invalidated inodes as well as + * those created by make_stale_inode() above. + */ + +/** + * is_stale_inode - is an inode errored + * @inode: inode to test + * + * Returns true if the inode in question has been marked as stale. + */ + +int is_stale_inode(struct inode *inode) +{ + return (inode->i_op == &stale_inode_ops); +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/unionfs.h +++ linux-2.6.27/ubuntu/unionfs/unionfs.h @@ -0,0 +1,736 @@ +#ifndef __UNIONFS_H_ +#define __UNIONFS_H_ + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#ifndef UNIONFS_UNSUPPORTED +#if LINUX_VERSION_CODE != KERNEL_VERSION(SUP_MAJOR,SUP_MINOR,SUP_PATCH) +#warning You are compiling Unionfs on an unsupported kernel version. +#warning To compile Unionfs, you will need to define UNIONFS_UNSUPPORTED. +#warning Try adding: EXTRACFLAGS=-DUNIONFS_UNSUPPORTED to fistdev.mk +#endif +#endif + +/* the file system name */ +#define UNIONFS_NAME "unionfs" + +/* unionfs file systems superblock magic */ +#define UNIONFS_SUPER_MAGIC 0xf15f083d + +/* unionfs root inode number */ +#define UNIONFS_ROOT_INO 1 + +/* Mount time flags */ +#define MOUNT_FLAG(sb) (stopd(sb)->usi_mount_flag) + +/* number of characters while generating unique temporary file names */ +#define UNIONFS_TMPNAM_LEN 12 + +/* Operations vectors defined in specific files. */ +extern struct file_operations unionfs_main_fops; +extern struct file_operations unionfs_dir_fops; +extern struct inode_operations unionfs_main_iops; +extern struct inode_operations unionfs_dir_iops; +extern struct inode_operations unionfs_symlink_iops; +extern struct super_operations unionfs_sops; +extern struct dentry_operations unionfs_dops; +#ifdef CONFIG_EXPORTFS +extern struct export_operations unionfs_export_ops; +#endif + +/* How long should an entry be allowed to persist */ +#define RDCACHE_JIFFIES 5*HZ + +/* file private data. */ +struct unionfs_file_info { + int b_start; + int b_end; + atomic_t ufi_generation; + + struct unionfs_dir_state *rdstate; + struct file **ufi_file; +}; + +/* unionfs inode data in memory */ +struct unionfs_inode_info { + int b_start; + int b_end; + atomic_t uii_generation; + int uii_stale; + /* Stuff for readdir over NFS. */ + spinlock_t uii_rdlock; + struct list_head uii_readdircache; + int uii_rdcount; + int uii_hashsize; + int uii_cookie; + /* The hidden inodes */ + struct inode **uii_inode; + /* to keep track of reads/writes for unlinks before closes */ + atomic_t uii_totalopens; +}; + +struct unionfs_inode_container { + struct unionfs_inode_info info; + struct inode vfs_inode; +}; + +/* unionfs dentry data in memory */ +struct unionfs_dentry_info { + /* The semaphore is used to lock the dentry as soon as we get into a + * unionfs function from the VFS. Our lock ordering is that children + * go before their parents. */ + struct semaphore udi_sem; + int udi_bstart; + int udi_bend; + int udi_bopaque; + int udi_bcount; + atomic_t udi_generation; + struct dentry **udi_dentry; +}; + +/* A putmap is used so that older files can still do branchput correctly. */ +struct putmap { + atomic_t count; + int bend; + int map[0]; +}; + +/* These are the pointers to our various objects. */ +struct unionfs_usi_data { + struct super_block *sb; + struct vfsmount *hidden_mnt; + atomic_t sbcount; + int branchperms; +}; + +/* unionfs super-block data in memory */ +struct unionfs_sb_info { + int b_end; + + atomic_t usi_generation; + unsigned long usi_mount_flag; + struct rw_semaphore usi_rwsem; + + struct unionfs_usi_data *usi_data; + + /* These map branch numbers for old generation numbers to the new bindex, + * so that branchput will behave properly. */ + int usi_firstputmap; + int usi_lastputmap; + struct putmap **usi_putmaps; + +#ifdef UNIONFS_IMAP + int usi_persistent; + /* These will need a lock. */ + uint64_t usi_next_avail; + uint8_t usi_num_bmapents; + struct bmapent *usi_bmap; + struct file *usi_forwardmap; + struct file **usi_reversemaps; + struct file **usi_map_table; + int *usi_bnum_table; //This is a table of branches to fsnums. +#endif /* UNIONFS_IMAP */ +}; + +/* + * structure for making the linked list of entries by readdir on left branch + * to compare with entries on right branch + */ +struct filldir_node { + struct list_head file_list; // list for directory entries + char *name; // name entry + int hash; // name hash + int namelen; // name len since name is not 0 terminated + int bindex; // we can check for duplicate whiteouts and files in the same branch in order to return -EIO. + int whiteout; // is this a whiteout entry? + char iname[DNAME_INLINE_LEN_MIN]; // Inline name, so we don't need to separately kmalloc small ones +}; + +/* Directory hash table. */ +struct unionfs_dir_state { + unsigned int uds_cookie; /* The cookie, which is based off of uii_rdversion */ + unsigned int uds_offset; /* The entry we have returned. */ + int uds_bindex; + loff_t uds_dirpos; /* The offset within the lower level directory. */ + int uds_size; /* How big is the hash table? */ + int uds_hashentries; /* How many entries have been inserted? */ + unsigned long uds_access; + /* This cache list is used when the inode keeps us around. */ + struct list_head uds_cache; + struct list_head uds_list[0]; +}; + +/* privileged io workqueue */ +#include "sioq.h" + +/* include miscellaneous macros */ +#include "unionfs_macros.h" + +/* include debug macros */ +#include "unionfs_debug.h" + +/* include persistent imap code */ +#include "unionfs_imap.h" + +/* Cache creation/deletion routines. */ +void destroy_filldir_cache(void); +int init_filldir_cache(void); +int init_inode_cache(void); +void destroy_inode_cache(void); +int init_dentry_cache(void); +void destroy_dentry_cache(void); + +/* Initialize and free readdir-specific state. */ +int init_rdstate(struct file *file); +struct unionfs_dir_state *alloc_rdstate(struct inode *inode, int bindex); +struct unionfs_dir_state *find_rdstate(struct inode *inode, loff_t fpos); +void free_rdstate(struct unionfs_dir_state *state); +int add_filldir_node(struct unionfs_dir_state *rdstate, const char *name, + int namelen, int bindex, int whiteout); +struct filldir_node *find_filldir_node(struct unionfs_dir_state *rdstate, + const char *name, int namelen); + +struct dentry **alloc_new_dentries(int objs); +struct unionfs_usi_data *alloc_new_data(int objs); + +#ifdef FIST_MALLOC_DEBUG + +extern void *unionfs_kzalloc(size_t size, gfp_t flags, int line, + const char *file); +extern void *unionfs_kmalloc(size_t size, gfp_t flags, int line, + const char *file); +extern void unionfs_kfree(void *ptr, int line, const char *file); + +extern struct dentry *unionfs_dget_parent(struct dentry *child, int line, + const char *file); +extern struct dentry *unionfs_dget(struct dentry *ptr, int line, + const char *file); +extern void unionfs_dput(struct dentry *ptr, int line, const char *file); +extern struct inode *unionfs_igrab(struct inode *inode, int line, char *file); +extern void unionfs_iput(struct inode *inode, int line, char *file); +extern struct dentry *unionfs_lookup_one_len(const char *name, + struct dentry *parent, int len, + int line, const char *file); +void record_path_lookup(struct nameidata *nd, int line, const char *file); +void record_path_release(struct nameidata *nd, int line, const char *file); +struct file *unionfs_dentry_open(struct dentry *ptr, struct vfsmount *mnt, + int flags, int line, const char *file); +void record_set(struct dentry *upper, int index, struct dentry *ptr, + struct dentry *old, int line, const char *file); + +#define KZALLOC(size,flags) unionfs_kzalloc((size),(flags),__LINE__,__FILE__) +#define KMALLOC(size,flags) unionfs_kmalloc((size),(flags),__LINE__,__FILE__) +#define KFREE(ptr) unionfs_kfree((ptr),__LINE__,__FILE__) +#define DGET(d) unionfs_dget((d),__LINE__,__FILE__) +#define DPUT(d) unionfs_dput((d),__LINE__,__FILE__) +# define IPUT(a) unionfs_iput((a),__LINE__,__FILE__) +# define IGRAB(a) unionfs_igrab((a),__LINE__,__FILE__) +#define LOOKUP_ONE_LEN(name,parent,len) unionfs_lookup_one_len((name),(parent),(len),__LINE__,__FILE__) +# define RECORD_PATH_LOOKUP(nd) record_path_lookup((nd),__LINE__,__FILE__) +# define RECORD_PATH_RELEASE(nd) record_path_release((nd),__LINE__,__FILE__) +/* This has the effect of reducing the reference count sooner or later, + * if the file is closed. If it isn't then the mount will be busy and + * you can't unmount. + */ +# define DENTRY_OPEN(d,m,f) unionfs_dentry_open((d),(m),(f),__LINE__,__FILE__) +# define GET_PARENT(dentry) unionfs_dget_parent((dentry),__LINE__,__FILE__) +#else /* not FIST_MALLOC_DEBUG */ +# define KZALLOC(a,b) kzalloc((a),(b)) +# define KMALLOC(a,b) kmalloc((a),(b)) +# define KFREE(a) kfree((a)) +# define DPUT(a) dput((a)) +# define DGET(a) dget((a)) +# define IPUT(a) iput((a)) +# define IGRAB(a) igrab((a)) +# define LOOKUP_ONE_LEN(a,b,c) lookup_one_len((a),(b),(c)) +# define RECORD_PATH_LOOKUP(a) +# define RECORD_PATH_RELEASE(a) +# define DENTRY_OPEN(d,m,f) dentry_open((d),(m),(f)) +# define GET_PARENT(d) dget_parent(d) +#endif /* not FIST_MALLOC_DEBUG */ + +/* We can only use 32-bits of offset for rdstate --- blech! */ +#define DIREOF (0xfffff) +#define RDOFFBITS 20 /* This is the number of bits in DIREOF. */ +#define MAXRDCOOKIE (0xfff) +/* Turn an rdstate into an offset. */ +static inline off_t rdstate2offset(struct unionfs_dir_state *buf) +{ + off_t tmp; + tmp = + ((buf->uds_cookie & MAXRDCOOKIE) << RDOFFBITS) | (buf-> + uds_offset & + DIREOF); + return tmp; +} + +#define unionfs_read_lock(sb) down_read(&stopd(sb)->usi_rwsem) +#define unionfs_read_unlock(sb) up_read(&stopd(sb)->usi_rwsem) +#define unionfs_write_lock(sb) down_write(&stopd(sb)->usi_rwsem) +#define unionfs_write_unlock(sb) up_write(&stopd(sb)->usi_rwsem) + +/* The double lock function needs to go after the debugmacros, so that + * dtopd is defined. */ +static inline void double_lock_dentry(struct dentry *d1, struct dentry *d2) +{ + if (d2 < d1) { + struct dentry *tmp = d1; + d1 = d2; + d2 = tmp; + } + lock_dentry(d1); + lock_dentry(d2); +} + +extern int new_dentry_private_data(struct dentry *dentry); +void free_dentry_private_data(struct unionfs_dentry_info *udi); +void update_bstart(struct dentry *dentry); +#define sbt(sb) ((sb)->s_type->name) + +/* + * EXTERNALS: + */ +/* replicates the directory structure upto given dentry in given branch */ +extern struct dentry *create_parents(struct inode *dir, struct dentry *dentry, + int bindex); +struct dentry *create_parents_named(struct inode *dir, struct dentry *dentry, + const char *name, int bindex); + +/* check if two branches overlap */ +extern int is_branch_overlap(struct dentry *dent1, struct dentry *dent2); + +/* partial lookup */ +extern int unionfs_partial_lookup(struct dentry *dentry); + +/* Pass an unionfs dentry and an index and it will try to create a whiteout in branch 'index'. + On error, it will proceed to a branch to the left */ +extern int create_whiteout(struct dentry *dentry, int start); +/* copies a file from dbstart to newbindex branch */ +extern int copyup_file(struct inode *dir, struct file *file, int bstart, + int newbindex, loff_t size); +extern int copyup_named_file(struct inode *dir, struct file *file, + char *name, int bstart, int new_bindex, + loff_t len); + +/* copies a dentry from dbstart to newbindex branch */ +extern int copyup_dentry(struct inode *dir, struct dentry *dentry, int bstart, + int new_bindex, struct file **copyup_file, loff_t len); +extern int copyup_named_dentry(struct inode *dir, struct dentry *dentry, + int bstart, int new_bindex, const char *name, + int namelen, struct file **copyup_file, + loff_t len); + +extern int remove_whiteouts(struct dentry *dentry, struct dentry *hidden_dentry, + int bindex); + +/* Is this directory empty: 0 if it is empty, -ENOTEMPTY if not. */ +extern int check_empty(struct dentry *dentry, + struct unionfs_dir_state **namelist); +/* Delete whiteouts from this directory in branch bindex. */ +extern int delete_whiteouts(struct dentry *dentry, int bindex, + struct unionfs_dir_state *namelist); + +/* Re-lookup a hidden dentry. */ +extern int unionfs_refresh_hidden_dentry(struct dentry *dentry, int bindex); + +extern void unionfs_reinterpose(struct dentry *this_dentry); +extern struct super_block *unionfs_duplicate_super(struct super_block *sb); + +/* Locking functions. */ +extern int unionfs_setlk(struct file *file, int cmd, struct file_lock *fl); +extern int unionfs_getlk(struct file *file, struct file_lock *fl); + +/* Common file operations. */ +extern int unionfs_file_revalidate(struct file *file, int willwrite); +extern int unionfs_open(struct inode *inode, struct file *file); +extern int unionfs_file_release(struct inode *inode, struct file *file); +extern int unionfs_flush(struct file *file, fl_owner_t id); +extern long unionfs_ioctl(struct file *file, unsigned int cmd, + unsigned long arg); + +/* Inode operations */ +extern int unionfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry); +int unionfs_unlink(struct inode *dir, struct dentry *dentry); +int unionfs_rmdir(struct inode *dir, struct dentry *dentry); + +int unionfs_d_revalidate(struct dentry *dentry, struct nameidata *nd); + +/* The values for unionfs_interpose's flag. */ +#define INTERPOSE_DEFAULT 0 +#define INTERPOSE_LOOKUP 1 +#define INTERPOSE_REVAL 2 +#define INTERPOSE_REVAL_NEG 3 +#define INTERPOSE_PARTIAL 4 + +extern int unionfs_interpose(struct dentry *this_dentry, struct super_block *sb, + int flag); + +/* Branch management ioctls. */ +int unionfs_ioctl_branchcount(struct file *file, unsigned int cmd, + unsigned long arg); +int unionfs_ioctl_incgen(struct file *file, unsigned int cmd, + unsigned long arg); +int unionfs_ioctl_addbranch(struct inode *inode, unsigned int cmd, + unsigned long arg); +int unionfs_ioctl_delbranch(struct super_block *sb, unsigned long arg); +int unionfs_ioctl_rdwrbranch(struct inode *inode, unsigned int cmd, + unsigned long arg); +int unionfs_ioctl_queryfile(struct file *file, unsigned int cmd, + unsigned long arg); + +/* Verify that a branch is valid. */ +int check_branch(struct nameidata *nd); + +/* Extended attribute functions. */ +extern void *xattr_alloc(size_t size, size_t limit); +extern void xattr_free(void *ptr, size_t size); + +extern ssize_t unionfs_getxattr(struct dentry *dentry, const char *name, + void *value, size_t size); +extern int unionfs_removexattr(struct dentry *dentry, const char *name); +extern ssize_t unionfs_listxattr(struct dentry *dentry, char *list, + size_t size); + +int unionfs_setxattr(struct dentry *dentry, const char *name, const void *value, + size_t size, int flags); + +/* The root directory is unhashed, but isn't deleted. */ +static inline int d_deleted(struct dentry *d) +{ + return d_unhashed(d) && (d != d->d_sb->s_root); +} + +/* returns the sum of the n_link values of all the underlying inodes of the passed inode */ +static inline int get_nlinks(struct inode *inode) +{ + int sum_nlinks = 0; + int dirs = 0; + int bindex; + struct inode *hidden_inode; + + if (!S_ISDIR(inode->i_mode)) + return itohi(inode)->i_nlink; + + for (bindex = ibstart(inode); bindex <= ibend(inode); bindex++) { + hidden_inode = itohi_index(inode, bindex); + if (!hidden_inode || !S_ISDIR(hidden_inode->i_mode)) + continue; + BUG_ON(hidden_inode->i_nlink < 0); + + /* A deleted directory. */ + if (hidden_inode->i_nlink == 0) + continue; + dirs++; + /* A broken directory (e.g., squashfs). */ + if (hidden_inode->i_nlink == 1) + sum_nlinks += 2; + else + sum_nlinks += (hidden_inode->i_nlink - 2); + } + + if (!dirs) + return 0; + return sum_nlinks + 2; +} + +static inline void fist_copy_attr_atime(struct inode *dest, + const struct inode *src) +{ + dest->i_atime = src->i_atime; +} +static inline void fist_copy_attr_times(struct inode *dest, + const struct inode *src) +{ + dest->i_atime = src->i_atime; + dest->i_mtime = src->i_mtime; + dest->i_ctime = src->i_ctime; +} +static inline void fist_copy_attr_timesizes(struct inode *dest, + const struct inode *src) +{ + dest->i_atime = src->i_atime; + dest->i_mtime = src->i_mtime; + dest->i_ctime = src->i_ctime; + dest->i_size = src->i_size; + dest->i_blocks = src->i_blocks; +} +static inline void fist_copy_attr_all(struct inode *dest, + const struct inode *src) +{ + print_entry_location(); + + dest->i_mode = src->i_mode; + /* we do not need to copy if the file is a deleted file */ + if (dest->i_nlink > 0) + dest->i_nlink = get_nlinks(dest); + dest->i_uid = src->i_uid; + dest->i_gid = src->i_gid; + dest->i_rdev = src->i_rdev; + dest->i_atime = src->i_atime; + dest->i_mtime = src->i_mtime; + dest->i_ctime = src->i_ctime; + dest->i_blkbits = src->i_blkbits; + dest->i_size = src->i_size; + dest->i_blocks = src->i_blocks; + dest->i_flags = src->i_flags; + + print_exit_location(); +} + +struct dentry *unionfs_lookup_backend(struct dentry *dentry, struct nameidata *nd, int lookupmode); +int is_stale_inode(struct inode *inode); +void make_stale_inode(struct inode *inode); + +#define IS_SET(sb, check_flag) (check_flag & MOUNT_FLAG(sb)) + +/* unionfs_permission, check if we should bypass error to facilitate copyup */ +#define IS_COPYUP_ERR(err) (err == -EROFS) + +/* unionfs_open, check if we need to copyup the file */ +#define OPEN_WRITE_FLAGS (O_WRONLY | O_RDWR | O_APPEND) +#define IS_WRITE_FLAG(flag) (flag & (OPEN_WRITE_FLAGS)) + +static inline int branchperms(struct super_block *sb, int index) +{ + BUG_ON(index < 0); + + return stopd(sb)->usi_data[index].branchperms; +} +static inline int set_branchperms(struct super_block *sb, int index, int perms) +{ + BUG_ON(index < 0); + + stopd(sb)->usi_data[index].branchperms = perms; + + return perms; +} + +/* Is this file on a read-only branch? */ +static inline int __is_robranch_super(struct super_block *sb, int index, + char *file, const char *function, + int line) +{ + int err = 0; + + print_util_entry_location(); + + if (!(branchperms(sb, index) & MAY_WRITE)) + err = -EROFS; + + print_util_exit_status(err); + return err; +} + +/* Is this file on a read-only branch? */ +static inline int __is_robranch_index(struct dentry *dentry, int index, + char *file, const char *function, + int line) +{ + int err = 0; + int perms; + + print_util_entry_location(); + + BUG_ON(index < 0); + + perms = stopd(dentry->d_sb)->usi_data[index].branchperms; + + if ((!(perms & MAY_WRITE)) + || (IS_RDONLY(dtohd_index(dentry, index)->d_inode))) + err = -EROFS; + + print_util_exit_status(err); + + return err; +} +static inline int __is_robranch(struct dentry *dentry, char *file, + const char *function, int line) +{ + int index; + int err; + + print_util_entry_location(); + + index = dtopd(dentry)->udi_bstart; + BUG_ON(index < 0); + + err = __is_robranch_index(dentry, index, file, function, line); + + print_util_exit_status(err); + + return err; +} + +#define is_robranch(d) __is_robranch(d, __FILE__, __FUNCTION__, __LINE__) +#define is_robranch_super(s, n) __is_robranch_super(s, n, __FILE__, __FUNCTION__, __LINE__) + +/* What do we use for whiteouts. */ +#define WHPFX ".wh." +#define WHLEN 4 +/* If a directory contains this file, then it is opaque. We start with the + * .wh. flag so that it is blocked by loomkup. + */ +#define UNIONFS_DIR_OPAQUE_NAME "__dir_opaque" +#define UNIONFS_DIR_OPAQUE WHPFX UNIONFS_DIR_OPAQUE_NAME + +/* construct whiteout filename */ +static inline char *alloc_whname(const char *name, int len) +{ + char *buf; + + buf = KMALLOC(len + WHLEN + 1, GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + strcpy(buf, WHPFX); + strlcat(buf, name, len + WHLEN + 1); + + return buf; +} + +/* Definitions for various ways to handle errors. + Each flag's value is its bit position */ + +/* 1 = DELETE_ALL, 0 = check for DELETE_WHITEOUT */ +#ifdef UNIONFS_DELETE_ALL +#define DELETE_ALL 4 +#else +#define DELETE_ALL 0 +#endif + +#define VALID_MOUNT_FLAGS (DELETE_ALL) + +/* + * MACROS: + */ + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif /* not SEEK_SET */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif /* not SEEK_CUR */ + +#ifndef SEEK_END +#define SEEK_END 2 +#endif /* not SEEK_END */ + +#ifndef DEFAULT_POLLMASK +#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM) +#endif + +/* + * EXTERNALS: + */ + +/* JS: These two functions are here because it is kind of daft to copy and paste the + * contents of the two functions to 32+ places in unionfs + */ +static inline struct dentry *lock_parent(struct dentry *dentry) +{ + struct dentry *dir = DGET(dentry->d_parent); + + mutex_lock(&dir->d_inode->i_mutex); + return dir; +} + +static inline void unlock_dir(struct dentry *dir) +{ + mutex_unlock(&dir->d_inode->i_mutex); + DPUT(dir); +} + +extern int make_dir_opaque(struct dentry *dir, int bindex); + +#endif /* __KERNEL__ */ + +/* + * DEFINITIONS FOR USER AND KERNEL CODE: + * (Note: ioctl numbers 1--9 are reserved for fistgen, the rest + * are auto-generated automatically based on the user's .fist file.) + */ +# define FIST_IOCTL_GET_DEBUG_VALUE _IOR(0x15, 1, int) +# define FIST_IOCTL_SET_DEBUG_VALUE _IOW(0x15, 2, int) +# define UNIONFS_IOCTL_BRANCH_COUNT _IOR(0x15, 10, int) +# define UNIONFS_IOCTL_INCGEN _IOR(0x15, 11, int) +# define UNIONFS_IOCTL_ADDBRANCH _IOW(0x15, 12, int) +# define UNIONFS_IOCTL_DELBRANCH _IOW(0x15, 13, int) +# define UNIONFS_IOCTL_RDWRBRANCH _IOW(0x15, 14, int) +# define UNIONFS_IOCTL_QUERYFILE _IOR(0x15, 15, int) + +/* We don't support normal remount, but unionctl uses it. */ +# define UNIONFS_REMOUNT_MAGIC 0x4a5a4380 + +/* should be at least LAST_USED_UNIONFS_PERMISSION<<1 */ +#define MAY_NFSRO 16 + +struct unionfs_addbranch_args { + unsigned int ab_branch; + char *ab_path; + unsigned int ab_perms; +}; + +struct unionfs_rdwrbranch_args { + unsigned int rwb_branch; + unsigned int rwb_perms; +}; + +#endif /* not __UNIONFS_H_ */ +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/copyup.c +++ linux-2.6.27/ubuntu/unionfs/copyup.c @@ -0,0 +1,738 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York* + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: copyup.c,v 1.78 2006/10/31 18:05:33 yiannos Exp $ + */ + +#include "unionfs.h" + +/*Not Working Yet*/ +static int copyup_xattrs(struct dentry *old_hidden_dentry, + struct dentry *new_hidden_dentry) +{ + int err = 0; + ssize_t list_size = -1; + char *name_list = NULL; + char *attr_value = NULL; + char *name_list_orig = NULL; + + print_entry_location(); + + list_size = vfs_listxattr(old_hidden_dentry, NULL, NULL, 0, NULL); + + if (list_size <= 0) { + err = list_size; + goto out; + } + + name_list = xattr_alloc(list_size + 1, XATTR_LIST_MAX); + if (!name_list || IS_ERR(name_list)) { + err = PTR_ERR(name_list); + goto out; + } + list_size = vfs_listxattr(old_hidden_dentry, NULL, name_list, + list_size, NULL); + attr_value = xattr_alloc(XATTR_SIZE_MAX, XATTR_SIZE_MAX); + if (!attr_value || IS_ERR(attr_value)) { + err = PTR_ERR(name_list); + goto out; + } + name_list_orig = name_list; + while (*name_list) { + ssize_t size; + + //We need to lock here since vfs_getxattr doesn't lock for us. + mutex_lock(&old_hidden_dentry->d_inode->i_mutex); + size = vfs_getxattr(old_hidden_dentry, NULL, name_list, + attr_value, XATTR_SIZE_MAX, NULL); + mutex_unlock(&old_hidden_dentry->d_inode->i_mutex); + if (size < 0) { + err = size; + goto out; + } + + if (size > XATTR_SIZE_MAX) { + err = -E2BIG; + goto out; + } + //We don't need to lock here since vfs_setxattr does it for us. + err = vfs_setxattr(new_hidden_dentry, NULL, name_list, + attr_value, size, 0, NULL); + + if (err < 0) + goto out; + name_list += strlen(name_list) + 1; + } + out: + name_list = name_list_orig; + + if (name_list) + xattr_free(name_list, list_size + 1); + if (attr_value) + xattr_free(attr_value, XATTR_SIZE_MAX); + /* It is no big deal if this fails, we just roll with the punches. */ + if (err == -ENOTSUPP || err == -EOPNOTSUPP) + err = 0; + return err; +} + +/* Determine the mode based on the copyup flags, and the existing dentry. */ +static int copyup_permissions(struct super_block *sb, + struct dentry *old_hidden_dentry, + struct dentry *new_hidden_dentry) +{ + struct iattr newattrs; + int err; + + print_entry_location(); + + newattrs.ia_atime = old_hidden_dentry->d_inode->i_atime; + newattrs.ia_mtime = old_hidden_dentry->d_inode->i_mtime; + newattrs.ia_ctime = old_hidden_dentry->d_inode->i_ctime; + newattrs.ia_valid = ATTR_CTIME | ATTR_ATIME | ATTR_MTIME | + ATTR_ATIME_SET | ATTR_MTIME_SET; + /* original mode of old file */ + newattrs.ia_mode = old_hidden_dentry->d_inode->i_mode; + newattrs.ia_gid = old_hidden_dentry->d_inode->i_gid; + newattrs.ia_uid = old_hidden_dentry->d_inode->i_uid; + newattrs.ia_valid |= ATTR_FORCE | ATTR_GID | ATTR_UID | ATTR_MODE; + if (newattrs.ia_valid & ATTR_MODE) { + newattrs.ia_mode = + (newattrs.ia_mode & S_IALLUGO) | (old_hidden_dentry-> + d_inode-> + i_mode & ~S_IALLUGO); + } + + err = notify_change(new_hidden_dentry, NULL, &newattrs); + + print_exit_status(err); + return err; +} + +int copyup_dentry(struct inode *dir, struct dentry *dentry, + int bstart, int new_bindex, + struct file **copyup_file, loff_t len) +{ + return copyup_named_dentry(dir, dentry, bstart, new_bindex, + dentry->d_name.name, + dentry->d_name.len, copyup_file, len); +} + +int copyup_named_dentry(struct inode *dir, struct dentry *dentry, + int bstart, int new_bindex, const char *name, + int namelen, struct file **copyup_file, loff_t len) +{ + struct dentry *new_hidden_dentry; + struct dentry *old_hidden_dentry = NULL; + struct super_block *sb; + struct file *input_file = NULL; + struct file *output_file = NULL; + struct sioq_args args; + ssize_t read_bytes, write_bytes; + mm_segment_t old_fs; + int err = 0; + char *buf; + int old_bindex; + int got_branch_input = -1; + int got_branch_output = -1; + int old_bstart; + int old_bend; + int old_mode; + loff_t size = len; + struct dentry *new_hidden_parent_dentry = NULL; + mm_segment_t oldfs; + char *symbuf = NULL; + + print_entry_location(); + verify_locked(dentry); + print_dentry("IN: copyup_named_dentry", dentry); + + old_bindex = bstart; + old_bstart = dbstart(dentry); + old_bend = dbend(dentry); + + BUG_ON(new_bindex < 0); + BUG_ON(new_bindex >= old_bindex); + + sb = dir->i_sb; + + unionfs_read_lock(sb); + + if ((err = is_robranch_super(sb, new_bindex))) + goto out; + + /* Create the directory structure above this dentry. */ + new_hidden_dentry = create_parents_named(dir, dentry, name, new_bindex); + if (IS_ERR(new_hidden_dentry)) { + err = PTR_ERR(new_hidden_dentry); + goto out; + } + + print_dentry("Copyup Object", new_hidden_dentry); + + /* Now we actually create the object. */ + old_hidden_dentry = dtohd_index(dentry, old_bindex); + DGET(old_hidden_dentry); + + old_mode = old_hidden_dentry->d_inode->i_mode; + + /* For symlinks, we must read the link before we lock the directory. */ + if (S_ISLNK(old_mode)) { + + symbuf = KMALLOC(PATH_MAX, GFP_KERNEL); + if (!symbuf) { + err = -ENOMEM; + goto copyup_readlink_err; + } + + oldfs = get_fs(); + set_fs(KERNEL_DS); + err = + old_hidden_dentry->d_inode->i_op-> + readlink(old_hidden_dentry, (char __user *)symbuf, + PATH_MAX); + set_fs(oldfs); + if (err < 0) + goto copyup_readlink_err; + symbuf[err] = '\0'; + } + + /* Now we lock the parent, and create the object in the new branch. */ + new_hidden_parent_dentry = lock_parent(new_hidden_dentry); + if (S_ISDIR(old_mode)) { + args.mkdir.parent = new_hidden_parent_dentry->d_inode; + args.mkdir.dentry = new_hidden_dentry; + args.mkdir.mode = old_mode; /*S_IRWXU*/ + run_sioq(__unionfs_mkdir, &args); + err = args.err; + } else if (S_ISLNK(old_mode)) { + args.symlink.parent = new_hidden_parent_dentry->d_inode; + args.symlink.dentry = new_hidden_dentry; + args.symlink.symbuf = symbuf; + args.symlink.mode = old_mode; + run_sioq(__unionfs_symlink, &args); + err = args.err; + } else if (S_ISBLK(old_mode) + || S_ISCHR(old_mode) + || S_ISFIFO(old_mode) + || S_ISSOCK(old_mode)) { + args.mknod.parent = new_hidden_parent_dentry->d_inode; + args.mknod.dentry = new_hidden_dentry; + args.mknod.mode = old_mode; + args.mknod.dev = old_hidden_dentry->d_inode->i_rdev; + run_sioq(__unionfs_mknod, &args); + err = args.err; + } else if (S_ISREG(old_mode)) { + args.create.parent = new_hidden_parent_dentry->d_inode; + args.create.dentry = new_hidden_dentry; + args.create.mode = old_mode; + args.create.nd = NULL; + run_sioq(__unionfs_create, &args); + err = args.err; + } else { + printk(KERN_ERR "Unknown inode type %d\n", + old_hidden_dentry->d_inode->i_mode); + BUG(); + } + + copyup_readlink_err: + KFREE(symbuf); + if (err) { + /* get rid of the hidden dentry and all its traces */ + DPUT(new_hidden_dentry); + set_dtohd_index(dentry, new_bindex, NULL); + set_dbstart(dentry, old_bstart); + set_dbend(dentry, old_bend); + goto out_dir; + } +#ifdef UNIONFS_IMAP + if (stopd(sb)->usi_persistent) { + err = write_uin(dentry->d_sb, dentry->d_inode->i_ino, + new_bindex, new_hidden_dentry->d_inode->i_ino); + if (err) + goto out_dir; + } +#endif + /* We actually copyup the file here. */ + if (S_ISREG(old_hidden_dentry->d_inode->i_mode)) { + mntget(stohiddenmnt_index(sb, old_bindex)); + branchget(sb, old_bindex); + got_branch_input = old_bindex; + input_file = + DENTRY_OPEN(old_hidden_dentry, + stohiddenmnt_index(sb, old_bindex), + O_RDONLY | O_LARGEFILE); + if (IS_ERR(input_file)) { + err = PTR_ERR(input_file); + goto out_dir; + } + if (!input_file->f_op || !input_file->f_op->read) { + err = -EINVAL; + goto out_dir; + } + + /* copy the new file */ + DGET(new_hidden_dentry); + mntget(stohiddenmnt_index(sb, new_bindex)); + branchget(sb, new_bindex); + got_branch_output = new_bindex; + output_file = + DENTRY_OPEN(new_hidden_dentry, + stohiddenmnt_index(sb, new_bindex), + O_WRONLY | O_LARGEFILE); + if (IS_ERR(output_file)) { + err = PTR_ERR(output_file); + goto out_dir; + } + if (!output_file->f_op || !output_file->f_op->write) { + err = -EINVAL; + goto out_dir; + } + + /* allocating a buffer */ + buf = (char *)KMALLOC(PAGE_SIZE, GFP_KERNEL); + if (!buf) { + err = -ENOMEM; + goto out_dir; + } + + /* now read PAGE_SIZE bytes from offset 0 in a loop */ + old_fs = get_fs(); + + input_file->f_pos = 0; + output_file->f_pos = 0; + + err = 0; // reset error just in case + set_fs(KERNEL_DS); + do { + if (len >= PAGE_SIZE) + size = PAGE_SIZE; + else if ((len < PAGE_SIZE) && (len > 0)) + size = len; + + len -= PAGE_SIZE; + + read_bytes = + input_file->f_op->read(input_file, + (char __user *)buf, size, + &input_file->f_pos); + if (read_bytes <= 0) { + err = read_bytes; + break; + } + + write_bytes = + output_file->f_op->write(output_file, + (char __user *)buf, + read_bytes, + &output_file->f_pos); + if (write_bytes < 0 || (write_bytes < read_bytes)) { + err = write_bytes; + break; + } + } while ((read_bytes > 0) && (len > 0)); + set_fs(old_fs); + KFREE(buf); +#ifdef UNIONFS_MMAP + /* SP: Now that we copied up the file, have to sync its data + * as otherwise when we do a read_cache_page(), we'll possibly + * read crap. + * + * another posisble solution would be in the address op code + * would be to check the "lower" page to see if its dirty, + * and if it's dirty, use it directl + */ + if (!err) { + err = + output_file->f_op->fsync(output_file, + new_hidden_dentry, 0); + } +#endif + if (err) { + /* copyup failed, because we ran out of space or quota, + * or something else happened so let's unlink; we don't + * really care about the return value of vfs_unlink */ + vfs_unlink(new_hidden_parent_dentry->d_inode, + new_hidden_dentry, NULL); + + goto out_dir; + } + } + + /* Set permissions. */ + if ((err = + copyup_permissions(sb, old_hidden_dentry, new_hidden_dentry))) + goto out_dir; + /* Selinux uses extended attributes for permissions. */ + if ((err = copyup_xattrs(old_hidden_dentry, new_hidden_dentry))) + goto out_dir; + + /* do not allow files getting deleted to be reinterposed */ + if (!d_deleted(dentry)) + unionfs_reinterpose(dentry); + + out_dir: + if (new_hidden_parent_dentry) + unlock_dir(new_hidden_parent_dentry); + + out: + if (input_file && !IS_ERR(input_file)) { + fput(input_file); + } else { + /* since input file was not opened, we need to explicitly + * dput the old_hidden_dentry + */ + DPUT(old_hidden_dentry); + } + + /* in any case, we have to branchput */ + if (got_branch_input >= 0) + branchput(sb, got_branch_input); + + if (output_file) { + if (copyup_file && !err) { + *copyup_file = output_file; + } else { + /* close the file if there was no error, or if we ran + * out of space in which case we unlinked the file */ + if (!IS_ERR(output_file)) + fput(output_file); + branchput(sb, got_branch_output); + } + } + + unionfs_read_unlock(sb); + + print_dentry("OUT: copyup_dentry", dentry); + print_inode("OUT: copyup_dentry", dentry->d_inode); + + print_exit_status(err); + return err; +} + +/* This function creates a copy of a file represented by 'file' which currently + * resides in branch 'bstart' to branch 'new_bindex. The copy will be named + * "name". */ +int copyup_named_file(struct inode *dir, struct file *file, char *name, + int bstart, int new_bindex, loff_t len) +{ + int err = 0; + struct file *output_file = NULL; + + print_entry_location(); + + err = copyup_named_dentry(dir, file->f_dentry, bstart, + new_bindex, name, strlen(name), &output_file, + len); + if (!err) { + fbstart(file) = new_bindex; + set_ftohf_index(file, new_bindex, output_file); + } + + print_exit_status(err); + return err; +} + +/* This function creates a copy of a file represented by 'file' which currently + * resides in branch 'bstart' to branch 'new_bindex. + */ +int copyup_file(struct inode *dir, struct file *file, int bstart, + int new_bindex, loff_t len) +{ + int err = 0; + struct file *output_file = NULL; + + print_entry_location(); + + err = copyup_dentry(dir, file->f_dentry, bstart, new_bindex, + &output_file, len); + if (!err) { + fbstart(file) = new_bindex; + set_ftohf_index(file, new_bindex, output_file); + } + + print_exit_status(err); + return err; +} + +/* This function replicates the directory structure upto given dentry + * in the bindex branch. Can create directory structure recursively to the right + * also. + */ +struct dentry *create_parents(struct inode *dir, struct dentry *dentry, + int bindex) +{ + struct dentry *hidden_dentry; + + print_entry_location(); + hidden_dentry = + create_parents_named(dir, dentry, dentry->d_name.name, bindex); + print_exit_location(); + + return (hidden_dentry); +} + +/* This function replicates the directory structure upto given dentry + * in the bindex branch. */ +struct dentry *create_parents_named(struct inode *dir, struct dentry *dentry, + const char *name, int bindex) +{ + int err; + struct dentry *child_dentry; + struct dentry *parent_dentry; + struct dentry *hidden_parent_dentry = NULL; + struct dentry *hidden_dentry = NULL; + struct sioq_args args; + const char *childname; + unsigned int childnamelen; + + int old_kmalloc_size; + int kmalloc_size; + int num_dentry; + int count; + + int old_bstart; + int old_bend; + struct dentry **path = NULL; + struct dentry **tmp_path; + struct super_block *sb; +#ifdef UNIONFS_IMAP + int persistent; +#endif + print_entry_location(); + + verify_locked(dentry); + + /* There is no sense allocating any less than the minimum. */ + kmalloc_size = 128; + num_dentry = kmalloc_size / sizeof(struct dentry *); + + if ((err = is_robranch_super(dir->i_sb, bindex))) { + hidden_dentry = ERR_PTR(err); + goto out; + } + + print_dentry("IN: create_parents_named", dentry); + dprint(PRINT_DEBUG, "name = %s\n", name); + + old_bstart = dbstart(dentry); + old_bend = dbend(dentry); + + hidden_dentry = ERR_PTR(-ENOMEM); + path = (struct dentry **)KZALLOC(kmalloc_size, GFP_KERNEL); + if (!path) + goto out; + + /* assume the negative dentry of unionfs as the parent dentry */ + parent_dentry = dentry; + + count = 0; + /* This loop finds the first parent that exists in the given branch. + * We start building the directory structure from there. At the end + * of the loop, the following should hold: + * child_dentry is the first nonexistent child + * parent_dentry is the first existent parent + * path[0] is the = deepest child + * path[count] is the first child to create + */ + do { + child_dentry = parent_dentry; + + /* find the parent directory dentry in unionfs */ + parent_dentry = child_dentry->d_parent; + lock_dentry(parent_dentry); + + /* find out the hidden_parent_dentry in the given branch */ + hidden_parent_dentry = dtohd_index(parent_dentry, bindex); + + /* store the child dentry */ + path[count++] = child_dentry; + if (count == num_dentry) { + old_kmalloc_size = kmalloc_size; + kmalloc_size *= 2; + num_dentry = kmalloc_size / sizeof(struct dentry *); + + tmp_path = + (struct dentry **)KZALLOC(kmalloc_size, GFP_KERNEL); + if (!tmp_path) { + hidden_dentry = ERR_PTR(-ENOMEM); + goto out; + } + memcpy(tmp_path, path, old_kmalloc_size); + KFREE(path); + path = tmp_path; + tmp_path = NULL; + } + + } while (!hidden_parent_dentry); + count--; + + sb = dentry->d_sb; +#ifdef UNIONFS_IMAP + persistent = stopd(sb)->usi_persistent; +#endif + /* This is basically while(child_dentry != dentry). This loop is + * horrible to follow and should be replaced with cleaner code. */ + while (1) { + // get hidden parent dir in the current branch + hidden_parent_dentry = dtohd_index(parent_dentry, bindex); + unlock_dentry(parent_dentry); + + // init the values to lookup + childname = child_dentry->d_name.name; + childnamelen = child_dentry->d_name.len; + + if (child_dentry != dentry) { + // lookup child in the underlying file system + hidden_dentry = + LOOKUP_ONE_LEN(childname, hidden_parent_dentry, + childnamelen); + if (IS_ERR(hidden_dentry)) + goto out; + } else { + int loop_start; + int loop_end; + int new_bstart = -1; + int new_bend = -1; + int i; + + /* is the name a whiteout of the childname ? */ + //lookup the whiteout child in the underlying file system + hidden_dentry = + LOOKUP_ONE_LEN(name, hidden_parent_dentry, + strlen(name)); + if (IS_ERR(hidden_dentry)) + goto out; + + /* Replace the current dentry (if any) with the new one. */ + DPUT(dtohd_index(dentry, bindex)); + set_dtohd_index(dentry, bindex, hidden_dentry); + + loop_start = + (old_bstart < bindex) ? old_bstart : bindex; + loop_end = (old_bend > bindex) ? old_bend : bindex; + + /* This loop sets the bstart and bend for the new + * dentry by traversing from left to right. + * It also dputs all negative dentries except + * bindex (the newly looked dentry + */ + for (i = loop_start; i <= loop_end; i++) { + if (!dtohd_index(dentry, i)) + continue; + + if (i == bindex) { + new_bend = i; + if (new_bstart < 0) + new_bstart = i; + continue; + } + + if (!dtohd_index(dentry, i)->d_inode) { + DPUT(dtohd_index(dentry, i)); + set_dtohd_index(dentry, i, NULL); + } else { + if (new_bstart < 0) + new_bstart = i; + new_bend = i; + } + } + + if (new_bstart < 0) + new_bstart = bindex; + if (new_bend < 0) + new_bend = bindex; + set_dbstart(dentry, new_bstart); + set_dbend(dentry, new_bend); + break; + } + + if (hidden_dentry->d_inode) { + /* since this already exists we dput to avoid + * multiple references on the same dentry */ + DPUT(hidden_dentry); + } else { + + /* its a negative dentry, create a new dir */ + hidden_parent_dentry = lock_parent(hidden_dentry); + args.mkdir.parent = hidden_parent_dentry->d_inode; + args.mkdir.dentry = hidden_dentry; + args.mkdir.mode = child_dentry->d_inode->i_mode; + run_sioq(__unionfs_mkdir, &args); + err = args.err; + if (!err) + err = copyup_permissions + (dir->i_sb, child_dentry, hidden_dentry); + unlock_dir(hidden_parent_dentry); + if (err) { + DPUT(hidden_dentry); + hidden_dentry = ERR_PTR(err); + goto out; + } +#ifdef UNIONFS_IMAP + if (persistent) { + err = write_uin + (sb, child_dentry->d_inode->i_ino, + bindex, hidden_dentry->d_inode->i_ino); + if (err) { + DPUT(hidden_dentry); + hidden_dentry = ERR_PTR(err); + goto out; + } + } +#endif + set_itohi_index(child_dentry->d_inode, bindex, + IGRAB(hidden_dentry->d_inode)); + if (ibstart(child_dentry->d_inode) > bindex) + ibstart(child_dentry->d_inode) = bindex; + if (ibend(child_dentry->d_inode) < bindex) + ibend(child_dentry->d_inode) = bindex; + + set_dtohd_index(child_dentry, bindex, hidden_dentry); + if (dbstart(child_dentry) > bindex) + set_dbstart(child_dentry, bindex); + if (dbend(child_dentry) < bindex) + set_dbend(child_dentry, bindex); + } + + parent_dentry = child_dentry; + child_dentry = path[--count]; + } + out: + KFREE(path); + print_dentry("OUT: create_parents_named", dentry); + print_exit_pointer(hidden_dentry); + return hidden_dentry; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/commonfops.c +++ linux-2.6.27/ubuntu/unionfs/commonfops.c @@ -0,0 +1,706 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: commonfops.c,v 1.61 2006/08/05 01:28:46 jro Exp $ + */ + +#include "unionfs.h" + +/* We only need this function here, but it could get promoted to unionfs.h, if + * other things need a generation specific branch putting function. */ +static inline void branchput_gen(int generation, struct super_block *sb, + int index) +{ + struct putmap *putmap; + + if (generation == atomic_read(&stopd(sb)->usi_generation)) { + branchput(sb, index); + return; + } + + BUG_ON(stopd(sb)->usi_firstputmap > generation); + BUG_ON(stopd(sb)->usi_lastputmap < generation); + + putmap = + stopd(sb)->usi_putmaps[generation - stopd(sb)->usi_firstputmap]; + BUG_ON(index < 0); + BUG_ON(index > putmap->bend); + BUG_ON(putmap->map[index] < 0); + branchput(sb, putmap->map[index]); + if (atomic_dec_and_test(&putmap->count)) { + stopd(sb)->usi_putmaps[generation - stopd(sb)->usi_firstputmap] + = NULL; + dprint(PRINT_DEBUG, "Freeing putmap %d.\n", generation); + KFREE(putmap); + } +} + +static char *get_random_name(int size, unsigned char *name) +{ + int i; + int j; + unsigned char *tmpbuf = NULL; + + if (size <= WHLEN) + return NULL; + + if (!name) + name = KMALLOC(size + 1, GFP_KERNEL); + if (!name) { + name = ERR_PTR(-ENOMEM); + goto out; + } + strncpy(name, WHPFX, WHLEN); + + tmpbuf = KMALLOC(size, GFP_KERNEL); + if (!tmpbuf) { + KFREE(name); + name = ERR_PTR(-ENOMEM); + goto out; + } + + get_random_bytes((void *)tmpbuf, (size - 3) / 2); + + j = WHLEN; + i = 0; + while ((i < (size - 3) / 2) && (j < size)) { + /* get characters in the 0-9, A-F range */ + + name[j] = + (tmpbuf[i] % 16) < + 10 ? (tmpbuf[i] % 16) + '0' : (tmpbuf[i] % 16) + 'a'; + j++; + if (j == size) + break; + name[j] = + (tmpbuf[i] >> 4) < + 10 ? (tmpbuf[i] >> 4) + '0' : (tmpbuf[i] >> 4) + 'a'; + j++; + + i++; + } + + name[size] = '\0'; + + out: + KFREE(tmpbuf); + return (name); + +} + +static int copyup_deleted_file(struct file *file, struct dentry *dentry, + int bstart, int bindex) +{ + int attempts = 0; + int err; + int exists = 1; + char *name = NULL; + struct dentry *tmp_dentry = NULL; + struct dentry *hidden_dentry = NULL; + struct dentry *hidden_dir_dentry = NULL; + + print_entry_location(); + + /* Try five times to get a unique file name, fail after that. Five is + * simply a magic number, because we shouldn't try forever. */ + while (exists) { + /* The first call allocates, the subsequent ones reuse. */ + name = get_random_name(UNIONFS_TMPNAM_LEN, name); + err = -ENOMEM; + if (!name) + goto out; + //XXX: Why do we do this every time? bstart never changes? + hidden_dentry = dtohd_index(dentry, bstart); + + tmp_dentry = LOOKUP_ONE_LEN(name, hidden_dentry->d_parent, + UNIONFS_TMPNAM_LEN); + err = PTR_ERR(tmp_dentry); + if (IS_ERR(tmp_dentry)) + goto out; + exists = tmp_dentry->d_inode ? 1 : 0; + DPUT(tmp_dentry); + + err = -EEXIST; + if (++attempts > 5) + goto out; + } + + err = copyup_named_file(dentry->d_parent->d_inode, file, name, bstart, + bindex, file->f_dentry->d_inode->i_size); + if (err) + goto out; + + /* bring it to the same state as an unlinked file */ + hidden_dentry = dtohd_index(dentry, dbstart(dentry)); + hidden_dir_dentry = lock_parent(hidden_dentry); + err = vfs_unlink(hidden_dir_dentry->d_inode, hidden_dentry, NULL); + unlock_dir(hidden_dir_dentry); + + out: + KFREE(name); + print_exit_status(err); + return err; +} + +int unionfs_file_revalidate(struct file *file, int willwrite) +{ + struct super_block *sb; + struct dentry *dentry; + int sbgen, fgen, dgen; + int bindex, bstart, bend; + struct file *hidden_file; + struct dentry *hidden_dentry; + int size; + + int err = 0; + + print_entry(" file = %p", file); + + dentry = file->f_dentry; + lock_dentry(dentry); + sb = dentry->d_sb; + unionfs_read_lock(sb); + if (!unionfs_d_revalidate(dentry, NULL) && !d_deleted(dentry)) { + err = -ESTALE; + goto out; + } + print_dentry("file revalidate in", dentry); + + sbgen = atomic_read(&stopd(sb)->usi_generation); + dgen = atomic_read(&dtopd(dentry)->udi_generation); + fgen = atomic_read(&ftopd(file)->ufi_generation); + + BUG_ON(sbgen > dgen); + + /* There are two cases we are interested in. The first is if the + * generation is lower than the super-block. The second is if someone + * has copied up this file from underneath us, we also need to refresh + * things. */ + if (!d_deleted(dentry) && + ((sbgen > fgen) || (dbstart(dentry) != fbstart(file)))) { + /* First we throw out the existing files. */ + bstart = fbstart(file); + bend = fbend(file); + for (bindex = bstart; bindex <= bend; bindex++) { + if (ftohf_index(file, bindex)) { + branchput_gen(fgen, dentry->d_sb, bindex); + fput(ftohf_index(file, bindex)); + } + } + + if (ftohf_ptr(file)) { + KFREE(ftohf_ptr(file)); + ftohf_ptr(file) = NULL; + } + + /* Now we reopen the file(s) as in unionfs_open. */ + bstart = fbstart(file) = dbstart(dentry); + bend = fbend(file) = dbend(dentry); + + size = sizeof(struct file *) * sbmax(sb); + ftohf_ptr(file) = KZALLOC(size, GFP_KERNEL); + if (!ftohf_ptr(file)) { + err = -ENOMEM; + goto out; + } + + if (S_ISDIR(dentry->d_inode->i_mode)) { + /* We need to open all the files. */ + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + continue; + + DGET(hidden_dentry); + mntget(stohiddenmnt_index(sb, bindex)); + branchget(sb, bindex); + + hidden_file = + DENTRY_OPEN(hidden_dentry, + stohiddenmnt_index(sb, bindex), + file->f_flags); + if (IS_ERR(hidden_file)) { + err = PTR_ERR(hidden_file); + goto out; + } else { + set_ftohf_index(file, bindex, + hidden_file); + } + } + } else { + /* We only open the highest priority branch. */ + hidden_dentry = dtohd(dentry); + if (willwrite && IS_WRITE_FLAG(file->f_flags) + && is_robranch(dentry)) { + for (bindex = bstart - 1; bindex >= 0; bindex--) { + + err = copyup_file(dentry-> + d_parent-> + d_inode, + file, + bstart, + bindex, + file-> + f_dentry-> + d_inode->i_size); + + if (!err) + break; + else + continue; + + } + atomic_set(&ftopd(file)->ufi_generation, + atomic_read(&itopd(dentry->d_inode)-> + uii_generation)); + goto out; + } + + DGET(hidden_dentry); + mntget(stohiddenmnt_index(sb, bstart)); + branchget(sb, bstart); + hidden_file = + DENTRY_OPEN(hidden_dentry, + stohiddenmnt_index(sb, bstart), + file->f_flags); + if (IS_ERR(hidden_file)) { + err = PTR_ERR(hidden_file); + goto out; + } + set_ftohf(file, hidden_file); + /* Fix up the position. */ + hidden_file->f_pos = file->f_pos; + + memcpy(&(hidden_file->f_ra), &(file->f_ra), + sizeof(struct file_ra_state)); + } + atomic_set(&ftopd(file)->ufi_generation, + atomic_read(&itopd(dentry->d_inode)-> + uii_generation)); + } + + /* Copyup on the first write to a file on a readonly branch. */ + if (willwrite && IS_WRITE_FLAG(file->f_flags) + && !IS_WRITE_FLAG(ftohf(file)->f_flags) && is_robranch(dentry)) { + dprint(PRINT_DEBUG, + "Doing delayed copyup of a read-write file on a read-only branch.\n"); + bstart = fbstart(file); + bend = fbend(file); + + BUG_ON(!S_ISREG(file->f_dentry->d_inode->i_mode)); + + for (bindex = bstart - 1; bindex >= 0; bindex--) { + if (!d_deleted(file->f_dentry)) { + err = + copyup_file(dentry->d_parent-> + d_inode, file, bstart, + bindex, + file->f_dentry-> + d_inode->i_size); + } else { + err = + copyup_deleted_file(file, dentry, bstart, + bindex); + } + + if (!err) + break; + else + continue; + + } + if (!err && (bstart > fbstart(file))) { + bend = fbend(file); + for (bindex = bstart; bindex <= bend; bindex++) { + if (ftohf_index(file, bindex)) { + branchput(dentry->d_sb, bindex); + fput(ftohf_index(file, bindex)); + set_ftohf_index(file, bindex, NULL); + } + } + fbend(file) = bend; + } + } + + out: + print_dentry("file revalidate out", dentry); + unlock_dentry(dentry); + unionfs_read_unlock(dentry->d_sb); + print_exit_status(err); + return err; +} + +int unionfs_open(struct inode *inode, struct file *file) +{ + int err = 0; + int hidden_flags; + struct file *hidden_file = NULL; + struct dentry *hidden_dentry = NULL; + struct dentry *dentry = NULL; + int bindex = 0, bstart = 0, bend = 0; + int locked = 0; + int size; + + print_entry_location(); + + ftopd_lhs(file) = KZALLOC(sizeof(struct unionfs_file_info), GFP_KERNEL); + if (!ftopd(file)) { + err = -ENOMEM; + goto out; + } + fbstart(file) = -1; + fbend(file) = -1; + atomic_set(&ftopd(file)->ufi_generation, + atomic_read(&itopd(inode)->uii_generation)); + + size = sizeof(struct file *) * sbmax(inode->i_sb); + ftohf_ptr(file) = KZALLOC(size, GFP_KERNEL); + if (!ftohf_ptr(file)) { + err = -ENOMEM; + goto out; + } + + hidden_flags = file->f_flags; + + dentry = file->f_dentry; + dprint(PRINT_DEBUG, "dentry to open is %p\n", dentry); + lock_dentry(dentry); + unionfs_read_lock(inode->i_sb); + locked = 1; + + bstart = fbstart(file) = dbstart(dentry); + bend = fbend(file) = dbend(dentry); + + /* increment to show the kind of open, so that we can + * flush appropriately + */ + atomic_inc(&itopd(dentry->d_inode)->uii_totalopens); + + /* open all directories and make the unionfs file struct point to these hidden file structs */ + if (S_ISDIR(inode->i_mode)) { + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + continue; + + DGET(hidden_dentry); + mntget(stohiddenmnt_index(inode->i_sb, bindex)); + hidden_file = + DENTRY_OPEN(hidden_dentry, + stohiddenmnt_index(inode->i_sb, bindex), + hidden_flags); + if (IS_ERR(hidden_file)) { + err = PTR_ERR(hidden_file); + goto out; + } + + set_ftohf_index(file, bindex, hidden_file); + /* The branchget goes after the open, because otherwise + * we would miss the reference on release. */ + branchget(inode->i_sb, bindex); + } + } else { + /* open a file */ + hidden_dentry = dtohd(dentry); + + /* check for the permission for hidden file. If the error is COPYUP_ERR, + * copyup the file. + */ + if (hidden_dentry->d_inode && is_robranch(dentry)) { + /* if the open will change the file, copy it up otherwise defer it. */ + if (hidden_flags & O_TRUNC) { + int size = 0; + + err = -EROFS; + /* copyup the file */ + for (bindex = bstart - 1; bindex >= 0; bindex--) { + err = + copyup_file(dentry-> + d_parent-> + d_inode, file, + bstart, bindex, size); + if (!err) { + break; + } + } + goto out; + } else { + hidden_flags &= ~(OPEN_WRITE_FLAGS); + } + } + + DGET(hidden_dentry); + /* dentry_open will decrement mnt refcnt if err. + * otherwise fput() will do an mntput() for us upon file close. + */ + mntget(stohiddenmnt_index(inode->i_sb, bstart)); + hidden_file = DENTRY_OPEN(hidden_dentry, + stohiddenmnt_index(inode->i_sb, + bstart), + hidden_flags); + if (IS_ERR(hidden_file)) { + err = PTR_ERR(hidden_file); + goto out; + } else { + set_ftohf(file, hidden_file); + branchget(inode->i_sb, bstart); + } + } + + out: + /* freeing the allocated resources, and fput the opened files */ + if (err < 0 && ftopd(file)) { + if (!locked) + unionfs_read_lock(file->f_dentry->d_sb); + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_file = ftohf_index(file, bindex); + if (hidden_file) { + branchput(file->f_dentry->d_sb, bindex); + /* fput calls dput for hidden_dentry */ + fput(hidden_file); + } + } + if (!locked) + unionfs_read_unlock(file->f_dentry->d_sb); + KFREE(ftohf_ptr(file)); + KFREE(ftopd(file)); + } + + print_file("OUT: unionfs_open", file); + + if (locked) { + unlock_dentry(dentry); + unionfs_read_unlock(inode->i_sb); + } + print_exit_status(err); + return err; +} + +int unionfs_file_release(struct inode *inode, struct file *file) +{ + int err = 0; + struct file *hidden_file = NULL; + int bindex, bstart, bend; + int fgen; + + print_entry_location(); + + checkinode(inode, "unionfs_release"); + + /* fput all the hidden files */ + fgen = atomic_read(&ftopd(file)->ufi_generation); + bstart = fbstart(file); + bend = fbend(file); + + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_file = ftohf_index(file, bindex); + + if (hidden_file) { + fput(hidden_file); + unionfs_read_lock(inode->i_sb); + branchput_gen(fgen, inode->i_sb, bindex); + unionfs_read_unlock(inode->i_sb); + } + } + KFREE(ftohf_ptr(file)); + + if (ftopd(file)->rdstate) { + ftopd(file)->rdstate->uds_access = jiffies; + dprint(PRINT_DEBUG, "Saving rdstate with cookie %u [%d.%lld]\n", + ftopd(file)->rdstate->uds_cookie, + ftopd(file)->rdstate->uds_bindex, + (long long)ftopd(file)->rdstate->uds_dirpos); + spin_lock(&itopd(inode)->uii_rdlock); + itopd(inode)->uii_rdcount++; + list_add_tail(&ftopd(file)->rdstate->uds_cache, + &itopd(inode)->uii_readdircache); + mark_inode_dirty(inode); + spin_unlock(&itopd(inode)->uii_rdlock); + ftopd(file)->rdstate = NULL; + } + KFREE(ftopd(file)); + + checkinode(inode, "post unionfs_release"); + + print_exit_status(err); + return err; +} + +long unionfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + long err = 0; /* don't fail by default */ + struct file *hidden_file = NULL; + int val; + + print_entry_location(); + + if ((err = unionfs_file_revalidate(file, 1))) + goto out; + + /* check if asked for local commands */ + switch (cmd) { + case FIST_IOCTL_GET_DEBUG_VALUE: + if (!capable(CAP_SYS_ADMIN)) { + err = -EACCES; + goto out; + } + val = get_debug_mask(); + err = put_user(val, (int __user *)arg); + break; + + case FIST_IOCTL_SET_DEBUG_VALUE: + if (!capable(CAP_SYS_ADMIN)) { + err = -EACCES; + goto out; + } + err = get_user(val, (int __user *)arg); + if (err) + break; + dprint(PRINT_DEBUG, "IOCTL SET: got arg %d\n", val); + if (val < 0 || val > PRINT_MAX) { + err = -EINVAL; + break; + } + set_debug_mask(val); + break; + + /* add non-debugging fist ioctl's here */ + + case UNIONFS_IOCTL_BRANCH_COUNT: + if (!capable(CAP_SYS_ADMIN)) { + err = -EACCES; + goto out; + } + err = unionfs_ioctl_branchcount(file, cmd, arg); + break; + + case UNIONFS_IOCTL_INCGEN: + if (!capable(CAP_SYS_ADMIN)) { + err = -EACCES; + goto out; + } + err = unionfs_ioctl_incgen(file, cmd, arg); + break; + + case UNIONFS_IOCTL_ADDBRANCH: + if (!capable(CAP_SYS_ADMIN)) { + err = -EACCES; + goto out; + } + err = + unionfs_ioctl_addbranch(file->f_dentry->d_inode, cmd, arg); + break; + + case UNIONFS_IOCTL_RDWRBRANCH: + if (!capable(CAP_SYS_ADMIN)) { + err = -EACCES; + goto out; + } + err = + unionfs_ioctl_rdwrbranch(file->f_dentry->d_inode, cmd, arg); + break; + + case UNIONFS_IOCTL_QUERYFILE: + /* XXX: This should take the file. */ + err = unionfs_ioctl_queryfile(file, cmd, arg); + break; + + default: + hidden_file = ftohf(file); + + err = -ENOTTY; + if (!hidden_file || !hidden_file->f_op) + goto out; + if (hidden_file->f_op->unlocked_ioctl) { + err = + hidden_file->f_op->unlocked_ioctl(hidden_file, cmd, + arg); + } else if (hidden_file->f_op->ioctl) { + lock_kernel(); + err = + hidden_file->f_op->ioctl(hidden_file->f_dentry-> + d_inode, hidden_file, cmd, + arg); + unlock_kernel(); + } + } /* end of outer switch statement */ + + out: + print_exit_status((int)err); + return err; +} + +int unionfs_flush(struct file *file, fl_owner_t id) +{ + int err = 0; /* assume ok (see open.c:close_fp) */ + struct file *hidden_file = NULL; + int bindex, bstart, bend; + + print_entry_location(); + + if ((err = unionfs_file_revalidate(file, 1))) + goto out; + if (!atomic_dec_and_test + (&itopd(file->f_dentry->d_inode)->uii_totalopens)) + goto out; + + lock_dentry(file->f_dentry); + + bstart = fbstart(file); + bend = fbend(file); + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_file = ftohf_index(file, bindex); + + if (hidden_file && hidden_file->f_op + && hidden_file->f_op->flush) { + err = hidden_file->f_op->flush(hidden_file, id); + if (err) + goto out_lock; + /* This was earlier done in the unlink_all function in unlink.c */ + /* if there are no more references to the dentry, dput it */ + if (d_deleted(file->f_dentry)) { + DPUT(dtohd_index(file->f_dentry, bindex)); + set_dtohd_index(file->f_dentry, bindex, NULL); + } + } + + } + + out_lock: + unlock_dentry(file->f_dentry); + out: + print_exit_status(err); + return err; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/xattr.c +++ linux-2.6.27/ubuntu/unionfs/xattr.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: xattr.c,v 1.32 2006/06/01 03:11:03 jsipek Exp $ + */ + +#include "unionfs.h" + +/* This is lifted from fs/xattr.c */ +void *xattr_alloc(size_t size, size_t limit) +{ + void *ptr; + + if (size > limit) + return ERR_PTR(-E2BIG); + + if (!size) /* size request, no buffer is needed */ + return NULL; + else if (size <= PAGE_SIZE) + ptr = KMALLOC((unsigned long)size, GFP_KERNEL); + else + ptr = vmalloc((unsigned long)size); + if (!ptr) + return ERR_PTR(-ENOMEM); + return ptr; +} + +void xattr_free(void *ptr, size_t size) +{ + if (!size) /* size request, no buffer was needed */ + return; + else if (size <= PAGE_SIZE) + KFREE(ptr); + else + vfree(ptr); +} + +/* BKL held by caller. + * dentry->d_inode->i_mutex locked + * ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); + */ +ssize_t unionfs_getxattr(struct dentry * dentry, const char *name, void *value, + size_t size) +{ + struct dentry *hidden_dentry = NULL; + int err = -EOPNOTSUPP; + + print_entry_location(); + + dprint(PRINT_DEBUG_XATTR, "getxattr: name=\"%s\", value %lu bytes\n", + name, size); + + lock_dentry(dentry); + + hidden_dentry = dtohd(dentry); + + err = vfs_getxattr(hidden_dentry, NULL, (char*)name, value, size, + NULL); + + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +/* BKL held by caller. + * dentry->d_inode->i_mutex locked + */ +int +unionfs_setxattr(struct dentry *dentry, const char *name, const void *value, + size_t size, int flags) +{ + struct dentry *hidden_dentry = NULL; + int err = -EOPNOTSUPP; + + print_entry_location(); + + lock_dentry(dentry); + hidden_dentry = dtohd(dentry); + + dprint(PRINT_DEBUG_XATTR, "setxattr: name=\"%s\", value %lu bytes," + "flags=%x\n", name, (unsigned long)size, flags); + + err = + vfs_setxattr(hidden_dentry, NULL, (char *)name, (char *)value, + size, flags, NULL); + + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +/* BKL held by caller. + * dentry->d_inode->i_mutex locked + */ +int unionfs_removexattr(struct dentry *dentry, const char *name) +{ + struct dentry *hidden_dentry = NULL; + int err = -EOPNOTSUPP; + + print_entry_location(); + + lock_dentry(dentry); + hidden_dentry = dtohd(dentry); + + dprint(PRINT_DEBUG_XATTR, "removexattr: name=\"%s\"\n", name); + + err = vfs_removexattr(hidden_dentry, NULL, (char*)name, NULL); + + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +/* BKL held by caller. + * dentry->d_inode->i_mutex locked + */ +ssize_t unionfs_listxattr(struct dentry * dentry, char *list, size_t size) +{ + struct dentry *hidden_dentry = NULL; + int err = -EOPNOTSUPP; + char *encoded_list = NULL; + + print_entry_location(); + lock_dentry(dentry); + + hidden_dentry = dtohd(dentry); + + encoded_list = list; + err = vfs_listxattr(hidden_dentry, NULL, encoded_list, size, NULL); + + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/dirfops.c +++ linux-2.6.27/ubuntu/unionfs/dirfops.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: dirfops.c,v 1.25 2006/08/05 01:28:46 jro Exp $ + */ + +#include "unionfs.h" + +/* Make sure our rdstate is playing by the rules. */ +static void verify_rdstate_offset(struct unionfs_dir_state *rdstate) +{ + BUG_ON(rdstate->uds_offset >= DIREOF); + BUG_ON(rdstate->uds_cookie >= MAXRDCOOKIE); +} + +struct unionfs_getdents_callback { + struct unionfs_dir_state *rdstate; + void *dirent; + int entries_written; + int filldir_called; + int filldir_error; + filldir_t filldir; + struct super_block *sb; +}; + +/* copied from generic filldir in fs/readir.c */ +static int unionfs_filldir(void *dirent, const char *name, int namelen, + loff_t offset, u64 ino, unsigned int d_type) +{ + struct unionfs_getdents_callback *buf = + (struct unionfs_getdents_callback *)dirent; + struct filldir_node *found = NULL; + int err = 0; + int is_wh_entry = 0; + + dprint(PRINT_DEBUG, "unionfs_filldir name=%*s\n", namelen, name); + + buf->filldir_called++; + + if ((namelen > WHLEN) && !strncmp(name, WHPFX, WHLEN)) { + name += WHLEN; + namelen -= WHLEN; + is_wh_entry = 1; + } + + found = find_filldir_node(buf->rdstate, name, namelen); + + if (found) + goto out; + + /* if 'name' isn't a whiteout filldir it. */ + if (!is_wh_entry) { + off_t pos = rdstate2offset(buf->rdstate); + ino_t unionfs_ino = ino; +#ifdef UNIONFS_IMAP + if (stopd(buf->sb)->usi_persistent) + err = read_uin(buf->sb, buf->rdstate->uds_bindex, + ino, O_CREAT, &unionfs_ino); +#endif + if (!err) { + err = buf->filldir(buf->dirent, name, namelen, pos, + unionfs_ino, d_type); + buf->rdstate->uds_offset++; + verify_rdstate_offset(buf->rdstate); + } + } + /* If we did fill it, stuff it in our hash, otherwise return an error */ + if (err) { + buf->filldir_error = err; + goto out; + } + buf->entries_written++; + if ((err = add_filldir_node(buf->rdstate, name, namelen, + buf->rdstate->uds_bindex, is_wh_entry))) + buf->filldir_error = err; + + out: + return err; +} + +static int unionfs_readdir(struct file *file, void *dirent, filldir_t filldir) +{ + int err = 0; + struct file *hidden_file = NULL; + struct inode *inode = NULL; + struct unionfs_getdents_callback buf; + struct unionfs_dir_state *uds; + int bend; + loff_t offset; + + print_entry("file = %p, pos = %llx", file, file->f_pos); + + print_file("In unionfs_readdir()", file); + + if ((err = unionfs_file_revalidate(file, 0))) + goto out; + + inode = file->f_dentry->d_inode; + checkinode(inode, "unionfs_readdir"); + + uds = ftopd(file)->rdstate; + if (!uds) { + if (file->f_pos == DIREOF) { + goto out; + } else if (file->f_pos > 0) { + uds = find_rdstate(inode, file->f_pos); + if (!uds) { + err = -ESTALE; + goto out; + } + ftopd(file)->rdstate = uds; + } else { + init_rdstate(file); + uds = ftopd(file)->rdstate; + } + } + bend = fbend(file); + + while (uds->uds_bindex <= bend) { + hidden_file = ftohf_index(file, uds->uds_bindex); + if (!hidden_file) { + dprint(PRINT_DEBUG, + "Incremented bindex to %d of %d," + " because hidden file is NULL.\n", + uds->uds_bindex, bend); + uds->uds_bindex++; + uds->uds_dirpos = 0; + continue; + } + + /* prepare callback buffer */ + buf.filldir_called = 0; + buf.filldir_error = 0; + buf.entries_written = 0; + buf.dirent = dirent; + buf.filldir = filldir; + buf.rdstate = uds; + buf.sb = inode->i_sb; + + /* Read starting from where we last left off. */ + offset = vfs_llseek(hidden_file, uds->uds_dirpos, 0); + if (offset < 0) { + err = offset; + goto out; + } + dprint(PRINT_DEBUG, "calling readdir for %d.%lld (offset = %lld)\n", + uds->uds_bindex, uds->uds_dirpos, offset); + err = vfs_readdir(hidden_file, unionfs_filldir, (void *)&buf); + dprint(PRINT_DEBUG, + "readdir on %d.%lld = %d (entries written %d, filldir called %d)\n", + uds->uds_bindex, (long long)uds->uds_dirpos, err, + buf.entries_written, buf.filldir_called); + /* Save the position for when we continue. */ + + offset = vfs_llseek(hidden_file, 0, 1); + if (offset < 0) { + err = offset; + goto out; + } + uds->uds_dirpos = offset; + + /* Copy the atime. */ + fist_copy_attr_atime(inode, hidden_file->f_dentry->d_inode); + + if (err < 0) { + goto out; + } + + if (buf.filldir_error) { + break; + } + + if (!buf.entries_written) { + uds->uds_bindex++; + uds->uds_dirpos = 0; + } + } + + if (!buf.filldir_error && uds->uds_bindex >= bend) { + dprint(PRINT_DEBUG, + "Discarding rdstate because readdir is over (hashsize = %d)\n", + uds->uds_hashentries); + /* Save the number of hash entries for next time. */ + itopd(inode)->uii_hashsize = uds->uds_hashentries; + free_rdstate(uds); + ftopd(file)->rdstate = NULL; + file->f_pos = DIREOF; + } else { + file->f_pos = rdstate2offset(uds); + dprint(PRINT_DEBUG, "rdstate now has a cookie of %u (err = %d)\n", + uds->uds_cookie, err); + } + + out: + checkinode(inode, "post unionfs_readdir"); + print_exit_status(err); + return err; +} + +/* This is not meant to be a generic repositioning function. If you do + * things that aren't supported, then we return EINVAL. + * + * What is allowed: + * (1) seeking to the same position that you are currently at + * This really has no effect, but returns where you are. + * (2) seeking to the end of the file, if you've read everything + * This really has no effect, but returns where you are. + * (3) seeking to the beginning of the file + * This throws out all state, and lets you begin again. + */ +static loff_t unionfs_dir_llseek(struct file *file, loff_t offset, int origin) +{ + struct unionfs_dir_state *rdstate; + loff_t err; + + print_entry(" file=%p, offset=0x%llx, origin = %d", file, offset, + origin); + + if ((err = unionfs_file_revalidate(file, 0))) + goto out; + + rdstate = ftopd(file)->rdstate; + + /* We let users seek to their current position, but not anywhere else. */ + if (!offset) { + switch (origin) { + case SEEK_SET: + if (rdstate) { + free_rdstate(rdstate); + ftopd(file)->rdstate = NULL; + } + init_rdstate(file); + err = 0; + break; + case SEEK_CUR: + if (file->f_pos) { + if (file->f_pos == DIREOF) + err = DIREOF; + else + BUG_ON(file->f_pos != + rdstate2offset(rdstate)); + err = file->f_pos; + } else { + err = 0; + } + break; + case SEEK_END: + /* Unsupported, because we would break everything. */ + err = -EINVAL; + break; + } + } else { + switch (origin) { + case SEEK_SET: + if (rdstate) { + if (offset == rdstate2offset(rdstate)) { + err = offset; + } else if (file->f_pos == DIREOF) { + err = DIREOF; + } else { + err = -EINVAL; + } + } else { + if ((rdstate = + find_rdstate(file->f_dentry->d_inode, + offset))) { + ftopd(file)->rdstate = rdstate; + err = rdstate->uds_offset; + } else { + err = -EINVAL; + } + } + break; + case SEEK_CUR: + case SEEK_END: + /* Unsupported, because we would break everything. */ + err = -EINVAL; + break; + } + } + + out: + print_exit_status((int)err); + return err; +} + +/* Trimmed directory options, we shouldn't pass everything down since + * we don't want to operate on partial directories. + */ +struct file_operations unionfs_dir_fops = { + .llseek = unionfs_dir_llseek, + .read = generic_read_dir, + .readdir = unionfs_readdir, + .unlocked_ioctl = unionfs_ioctl, + .open = unionfs_open, + .release = unionfs_file_release, + .flush = unionfs_flush, +}; + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/lookup.c +++ linux-2.6.27/ubuntu/unionfs/lookup.c @@ -0,0 +1,524 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: lookup.c,v 1.49 2006/10/31 18:05:33 yiannos Exp $ + */ + +#include "unionfs.h" + +static int is_opaque_dir(struct dentry *dentry, int bindex); +static int is_validname(const char *name); + +struct dentry *unionfs_lookup_backend(struct dentry *dentry, struct nameidata *nd, int lookupmode) +{ + int err = 0; + struct dentry *hidden_dentry = NULL; + struct dentry *wh_hidden_dentry = NULL; + struct dentry *hidden_dir_dentry = NULL; + struct dentry *parent_dentry = NULL; + int bindex, bstart, bend, bopaque; + int dentry_count = 0; /* Number of positive dentries. */ + int first_dentry_offset = -1; + struct dentry *first_hidden_dentry = NULL; + int locked_parent = 0; + int locked_child = 0; + + int opaque; + char *whname = NULL; + const char *name; + int namelen; + + print_entry("mode = %d", lookupmode); + + /* We should already have a lock on this dentry in the case of a + * partial lookup, or a revalidation. Otherwise it is returned from + * new_dentry_private_data already locked. */ + if (lookupmode == INTERPOSE_PARTIAL || lookupmode == INTERPOSE_REVAL + || lookupmode == INTERPOSE_REVAL_NEG) { + verify_locked(dentry); + } else { + BUG_ON(dtopd_nocheck(dentry) != NULL); + locked_child = 1; + } + if (lookupmode != INTERPOSE_PARTIAL) + if ((err = new_dentry_private_data(dentry))) + goto out; + /* must initialize dentry operations */ + dentry->d_op = &unionfs_dops; + + parent_dentry = GET_PARENT(dentry); + /* We never partial lookup the root directory. */ + if (parent_dentry != dentry) { + lock_dentry(parent_dentry); + locked_parent = 1; + } else { + DPUT(parent_dentry); + parent_dentry = NULL; + goto out; + } + + print_dentry("IN unionfs_lookup (parent)", parent_dentry); + print_dentry("IN unionfs_lookup (child)", dentry); + + name = dentry->d_name.name; + namelen = dentry->d_name.len; + + /* No dentries should get created for possible whiteout names. */ + if (!is_validname(name)) { + err = -EPERM; + goto out_free; + } + + /* Now start the actual lookup procedure. */ + bstart = dbstart(parent_dentry); + bend = dbend(parent_dentry); + bopaque = dbopaque(parent_dentry); + BUG_ON(bstart < 0); + + /* It would be ideal if we could convert partial lookups to only have + * to do this work when they really need to. It could probably improve + * performance quite a bit, and maybe simplify the rest of the code. */ + if (lookupmode == INTERPOSE_PARTIAL) { + bstart++; + if ((bopaque != -1) && (bopaque < bend)) + bend = bopaque; + } + + dprint(PRINT_DEBUG, "bstart = %d, bend = %d\n", bstart, bend); + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (lookupmode == INTERPOSE_PARTIAL && hidden_dentry) + continue; + BUG_ON(hidden_dentry != NULL); + + hidden_dir_dentry = dtohd_index(parent_dentry, bindex); + + /* if the parent hidden dentry does not exist skip this */ + if (!(hidden_dir_dentry && hidden_dir_dentry->d_inode)) + continue; + + /* also skip it if the parent isn't a directory. */ + if (!S_ISDIR(hidden_dir_dentry->d_inode->i_mode)) + continue; + + /* Reuse the whiteout name because its value doesn't change. */ + if (!whname) { + whname = alloc_whname(name, namelen); + if (IS_ERR(whname)) { + err = PTR_ERR(whname); + goto out_free; + } + } + + /* check if whiteout exists in this branch: lookup .wh.foo */ + wh_hidden_dentry = LOOKUP_ONE_LEN(whname, hidden_dir_dentry, + namelen + WHLEN); + if (IS_ERR(wh_hidden_dentry)) { + DPUT(first_hidden_dentry); + err = PTR_ERR(wh_hidden_dentry); + goto out_free; + } + + if (wh_hidden_dentry->d_inode) { + /* We found a whiteout so lets give up. */ + dprint(PRINT_DEBUG, "whiteout found in %d\n", bindex); + if (S_ISREG(wh_hidden_dentry->d_inode->i_mode)) { + set_dbend(dentry, bindex); + set_dbopaque(dentry, bindex); + DPUT(wh_hidden_dentry); + break; + } + err = -EIO; + printk(KERN_NOTICE "EIO: Invalid whiteout entry type" + " %d.\n", wh_hidden_dentry->d_inode->i_mode); + DPUT(wh_hidden_dentry); + DPUT(first_hidden_dentry); + goto out_free; + } + + DPUT(wh_hidden_dentry); + wh_hidden_dentry = NULL; + + /* Now do regular lookup; lookup foo */ + nd->path.dentry = dtohd_index(dentry, bindex); + /* FIXME: fix following line for mount point crossing */ + nd->path.mnt = stohiddenmnt_index(parent_dentry->d_sb, bindex); + + hidden_dentry = LOOKUP_ONE_LEN(name, hidden_dir_dentry, namelen); + print_dentry("hidden result", hidden_dentry); + if (IS_ERR(hidden_dentry)) { + DPUT(first_hidden_dentry); + err = PTR_ERR(hidden_dentry); + goto out_free; + } + + /* Store the first negative dentry specially, because if they + * are all negative we need this for future creates. */ + if (!hidden_dentry->d_inode) { + if (!first_hidden_dentry && (dbstart(dentry) == -1)) { + first_hidden_dentry = hidden_dentry; + first_dentry_offset = bindex; + } else { + DPUT(hidden_dentry); + } + continue; + } + + /* number of positive dentries */ + dentry_count++; + + /* store underlying dentry */ + if (dbstart(dentry) == -1) + set_dbstart(dentry, bindex); + set_dtohd_index(dentry, bindex, hidden_dentry); + set_dbend(dentry, bindex); + + /* update parent directory's atime with the bindex */ + fist_copy_attr_atime(parent_dentry->d_inode, + hidden_dir_dentry->d_inode); + + /* We terminate file lookups here. */ + if (!S_ISDIR(hidden_dentry->d_inode->i_mode)) { + if (lookupmode == INTERPOSE_PARTIAL) + continue; + if (dentry_count == 1) + goto out_positive; + /* This can only happen with mixed D-*-F-* */ + BUG_ON(!S_ISDIR(dtohd(dentry)->d_inode->i_mode)); + continue; + } + + opaque = is_opaque_dir(dentry, bindex); + if (opaque < 0) { + DPUT(first_hidden_dentry); + err = opaque; + goto out_free; + } + if (opaque) { + set_dbend(dentry, bindex); + set_dbopaque(dentry, bindex); + break; + } + } + + if (dentry_count) + goto out_positive; + else + goto out_negative; + + out_negative: + if (lookupmode == INTERPOSE_PARTIAL) + goto out; + + /* If we've only got negative dentries, then use the leftmost one. */ + if (lookupmode == INTERPOSE_REVAL) { + if (dentry->d_inode) { + itopd(dentry->d_inode)->uii_stale = 1; + } + goto out; + } + /* This should only happen if we found a whiteout. */ + if (first_dentry_offset == -1) { + nd->path.dentry = dentry; + /* FIXME: fix following line for mount point crossing */ + nd->path.mnt = stohiddenmnt_index(parent_dentry->d_sb, bindex); + + first_hidden_dentry = LOOKUP_ONE_LEN(name, hidden_dir_dentry, + namelen); + + first_dentry_offset = bindex; + if (IS_ERR(first_hidden_dentry)) { + err = PTR_ERR(first_hidden_dentry); + goto out; + } + } + set_dtohd_index(dentry, first_dentry_offset, first_hidden_dentry); + set_dbstart(dentry, first_dentry_offset); + set_dbend(dentry, first_dentry_offset); + + if (lookupmode == INTERPOSE_REVAL_NEG) + BUG_ON(dentry->d_inode != NULL); + else + d_add(dentry, NULL); + goto out; + +/* This part of the code is for positive dentries. */ + out_positive: + BUG_ON(dentry_count <= 0); + + /* If we're holding onto the first negative dentry throw it out. */ + DPUT(first_hidden_dentry); + + /* Partial lookups need to reinterpose, or throw away older negs. */ + if (lookupmode == INTERPOSE_PARTIAL) { + if (dentry->d_inode) { + unionfs_reinterpose(dentry); + goto out; + } + + /* This somehow turned positive, so it is as if we had a + * negative revalidation. */ + lookupmode = INTERPOSE_REVAL_NEG; + + update_bstart(dentry); + bstart = dbstart(dentry); + bend = dbend(dentry); + } + + err = unionfs_interpose(dentry, dentry->d_sb, lookupmode); + if (err) + goto out_drop; + + checkinode(dentry->d_inode, "unionfs_lookup OUT: child"); + checkinode(parent_dentry->d_inode, "unionfs_lookup OUT: dir"); + goto out; + + out_drop: + d_drop(dentry); + + out_free: + /* should dput all the underlying dentries on error condition */ + bstart = dbstart(dentry); + if (bstart >= 0) { + bend = dbend(dentry); + for (bindex = bstart; bindex <= bend; bindex++) + DPUT(dtohd_index(dentry, bindex)); + } + KFREE(dtohd_ptr(dentry)); + dtohd_ptr(dentry) = NULL; + set_dbstart(dentry, -1); + set_dbend(dentry, -1); + + out: + if (!err && dtopd(dentry)) { + BUG_ON(dbend(dentry) > dtopd(dentry)->udi_bcount); + BUG_ON(dbend(dentry) > sbmax(dentry->d_sb)); + BUG_ON(dbstart(dentry) < 0); + } + KFREE(whname); + print_dentry("OUT unionfs_lookup (parent)", parent_dentry); + print_dentry("OUT unionfs_lookup (child)", dentry); + if (locked_parent) + unlock_dentry(parent_dentry); + DPUT(parent_dentry); + if (locked_child) + unlock_dentry(dentry); + print_exit_status(err); + return ERR_PTR(err); +} + +/* This is a utility function that fills in a unionfs dentry.*/ +int unionfs_partial_lookup(struct dentry *dentry) +{ + struct dentry *tmp; + struct nameidata nd = { .flags = 0 }; + + tmp = unionfs_lookup_backend(dentry, &nd, INTERPOSE_PARTIAL); + if (!tmp) + return 0; + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + /* need to change the interface */ + BUG_ON(tmp != dentry); + return -ENOSYS; +} + +/* The rest of these are utility functions for lookup. */ +static int is_opaque_dir(struct dentry *dentry, int bindex) +{ + int err = 0; + struct dentry *hidden_dentry; + struct dentry *wh_hidden_dentry; + struct inode *hidden_inode; + struct sioq_args args; + + print_entry_location(); + + hidden_dentry = dtohd_index(dentry, bindex); + hidden_inode = hidden_dentry->d_inode; + + BUG_ON(!S_ISDIR(hidden_inode->i_mode)); + + mutex_lock(&hidden_inode->i_mutex); + if (!inode_permission(hidden_inode, MAY_EXEC)) + wh_hidden_dentry = LOOKUP_ONE_LEN(UNIONFS_DIR_OPAQUE, + hidden_dentry, + sizeof(UNIONFS_DIR_OPAQUE) - 1); + else { + args.isopaque.dentry = hidden_dentry; + run_sioq(__is_opaque_dir, &args); + wh_hidden_dentry = args.ret; + } + + mutex_unlock(&hidden_inode->i_mutex); + if (IS_ERR(wh_hidden_dentry)) { + err = PTR_ERR(wh_hidden_dentry); + dprint(PRINT_DEBUG, "LOOKUP_ONE_LEN returned: %d\n", err); + goto out; + } + if (wh_hidden_dentry->d_inode) + err = 1; + DPUT(wh_hidden_dentry); + out: + print_exit_status(err); + return err; +} + +static int is_validname(const char *name) +{ + if (!strncmp(name, WHPFX, WHLEN)) + return 0; + if (!strncmp(name, UNIONFS_DIR_OPAQUE_NAME, + sizeof(UNIONFS_DIR_OPAQUE_NAME) - 1)) + return 0; + return 1; +} + +/* The dentry cache is just so we have properly sized dentries. */ +static struct kmem_cache *unionfs_dentry_cachep; +int init_dentry_cache(void) +{ + unionfs_dentry_cachep = + kmem_cache_create("unionfs_dentry", + sizeof(struct unionfs_dentry_info), 0, + SLAB_RECLAIM_ACCOUNT, NULL); + + if (!unionfs_dentry_cachep) + return -ENOMEM; + return 0; +} + +void destroy_dentry_cache(void) +{ + if (!unionfs_dentry_cachep) + return; + kmem_cache_destroy(unionfs_dentry_cachep); + return; +} + +void free_dentry_private_data(struct unionfs_dentry_info *udi) +{ + if (!udi) + return; + kmem_cache_free(unionfs_dentry_cachep, udi); +} + +int new_dentry_private_data(struct dentry *dentry) +{ + int newsize; + int oldsize = 0; + + spin_lock(&dentry->d_lock); + if (!dtopd_nocheck(dentry)) { + dtopd_lhs(dentry) = (struct unionfs_dentry_info *) + kmem_cache_alloc(unionfs_dentry_cachep, GFP_ATOMIC); + if (!dtopd_nocheck(dentry)) + goto out; +#ifdef CONFIG_PREEMPT_RT + init_MUTEX(&dtopd_nocheck(dentry)->udi_sem); + down(&dtopd_nocheck(dentry)->udi_sem); +#else + init_MUTEX_LOCKED(&dtopd_nocheck(dentry)->udi_sem); +#endif + +#ifdef TRACKLOCK + printk("INITLOCK:%p\n", dentry); +#endif + dtohd_ptr(dentry) = NULL; + } else { + oldsize = sizeof(struct dentry *) * dtopd(dentry)->udi_bcount; + } + + dtopd_nocheck(dentry)->udi_bstart = -1; + dtopd_nocheck(dentry)->udi_bend = -1; + dtopd_nocheck(dentry)->udi_bopaque = -1; + dtopd_nocheck(dentry)->udi_bcount = sbmax(dentry->d_sb); + atomic_set(&dtopd_nocheck(dentry)->udi_generation, + atomic_read(&stopd(dentry->d_sb)->usi_generation)); + newsize = sizeof(struct dentry *) * sbmax(dentry->d_sb); + + /* Don't reallocate when we already have enough space. */ + /* It would be ideal if we could actually use the slab macros to + * determine what our object sizes is, but those are not exported. + */ + if (oldsize) { + int minsize = 128; + + if (!newsize || ((oldsize < newsize) && (newsize > minsize))) { + KFREE(dtohd_ptr(dentry)); + dtohd_ptr(dentry) = NULL; + } + } + + if (!dtohd_ptr(dentry) && newsize) { + dtohd_ptr(dentry) = KMALLOC(newsize, GFP_ATOMIC); + if (!dtohd_ptr(dentry)) + goto out; + } + + if (oldsize > newsize) + memset(dtohd_ptr(dentry), 0, oldsize); + else + memset(dtohd_ptr(dentry), 0, newsize); + + spin_unlock(&dentry->d_lock); + return 0; + + out: + free_dentry_private_data(dtopd_nocheck(dentry)); + dtopd_lhs(dentry) = NULL; + spin_unlock(&dentry->d_lock); + return -ENOMEM; +} + +void update_bstart(struct dentry *dentry) +{ + int bindex; + int bstart = dbstart(dentry); + int bend = dbend(dentry); + struct dentry *hidden_dentry; + + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + continue; + if (hidden_dentry->d_inode) { + set_dbstart(dentry, bindex); + break; + } + DPUT(hidden_dentry); + set_dtohd_index(dentry, bindex, NULL); + } +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/file.c +++ linux-2.6.27/ubuntu/unionfs/file.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: file.c,v 1.143 2006/08/05 01:28:46 jro Exp $ + */ + +#include "unionfs.h" + +/* declarations for sparse */ +extern ssize_t unionfs_read(struct file *, char __user *, size_t, loff_t *); +extern ssize_t unionfs_write(struct file *, const char __user *, size_t, + loff_t *); + +/******************* + * File Operations * + *******************/ + +#ifndef UNIONFS_MMAP +/* SP: Disable unionfs_llseek, as use generic_file_llseek on upper file */ +static loff_t unionfs_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t err; + struct file *hidden_file = NULL; + + print_entry_location(); + + dprint(PRINT_DEBUG, "unionfs_llseek: file=%p, offset=0x%llx, origin=%d\n", + file, offset, origin); + + if ((err = unionfs_file_revalidate(file, 0))) + goto out; + + hidden_file = ftohf(file); + /* always set hidden position to this one */ + hidden_file->f_pos = file->f_pos; + + memcpy(&(hidden_file->f_ra), &(file->f_ra), + sizeof(struct file_ra_state)); + + if (hidden_file->f_op && hidden_file->f_op->llseek) + err = hidden_file->f_op->llseek(hidden_file, offset, origin); + else + err = generic_file_llseek(hidden_file, offset, origin); + + if (err < 0) + goto out; + if (err != file->f_pos) { + file->f_pos = err; + // ION maybe this? + // file->f_pos = hidden_file->f_pos; + + file->f_version++; + } + out: + print_exit_status((int)err); + return err; +} +#endif +ssize_t __unionfs_read(struct file * file, char __user * buf, size_t count, + loff_t * ppos) +{ + int err = -EINVAL; + struct file *hidden_file = NULL; + loff_t pos = *ppos; + + print_file("entering __unionfs_read()", file); + + hidden_file = ftohf(file); + if (!hidden_file->f_op || !hidden_file->f_op->read) + goto out; + + err = hidden_file->f_op->read(hidden_file, buf, count, &pos); + *ppos = pos; + + out: + print_file("leaving __unionfs_read()", file); + + print_exit_status(err); + return err; +} + +ssize_t unionfs_read(struct file * file, char __user * buf, size_t count, + loff_t * ppos) +{ + int err = -EINVAL; + + print_entry_location(); + + if ((err = unionfs_file_revalidate(file, 0))) + goto out; + +#ifdef UNIONFS_MMAP + err = generic_file_read(file, buf, count, ppos); + if (err >= 0) + file_accessed(ftohf(file)); +#else + err = __unionfs_read(file, buf, count, ppos); +#endif + + out: + + print_exit_status(err); + return err; +} + +/* SP: Sendfile code not updated, but should be able to use + * generic_file_sendfile, as it would use readpage, which we now have */ +#ifdef SUPPORT_BROKEN_LOSETUP +static ssize_t unionfs_sendfile(struct file *file, loff_t * ppos, + size_t count, read_actor_t actor, void *target) +{ + ssize_t err; + struct file *hidden_file = NULL; + + print_entry_location(); + + if ((err = unionfs_file_revalidate(file, 0))) + goto out; + + hidden_file = ftohf(file); + + err = -EINVAL; + if (!hidden_file->f_op || !hidden_file->f_op->sendfile) + goto out; + + err = hidden_file->f_op->sendfile(hidden_file, ppos, count, actor, + target); + + out: + print_exit_status(err); + return err; +} +#endif +ssize_t __unionfs_write(struct file * file, const char __user * buf, + size_t count, loff_t * ppos) +{ + int err = -EINVAL; + struct file *hidden_file = NULL; + struct inode *inode; + struct inode *hidden_inode; + loff_t pos = *ppos; + int bstart, bend; + + print_entry_location(); + + inode = file->f_dentry->d_inode; + + bstart = fbstart(file); + bend = fbend(file); + + BUG_ON(bstart == -1); + + hidden_file = ftohf(file); + hidden_inode = hidden_file->f_dentry->d_inode; + + if (!hidden_file->f_op || !hidden_file->f_op->write) + goto out; + + /* adjust for append -- seek to the end of the file */ + if (file->f_flags & O_APPEND) + pos = inode->i_size; + + err = hidden_file->f_op->write(hidden_file, buf, count, &pos); + + /* + * copy ctime and mtime from lower layer attributes + * atime is unchanged for both layers + */ + if (err >= 0) + fist_copy_attr_times(inode, hidden_inode); + + *ppos = pos; + + /* update this inode's size */ + if (pos > inode->i_size) + inode->i_size = pos; + out: + print_exit_status(err); + return err; +} + +ssize_t unionfs_write(struct file * file, const char __user * buf, size_t count, + loff_t * ppos) +{ + int err = 0; + + print_entry_location(); + + if ((err = unionfs_file_revalidate(file, 1))) + goto out; +#ifdef UNIONFS_MMAP + err = generic_file_write(file, buf, count, ppos); +#else + err = __unionfs_write(file, buf, count, ppos); +#endif + out: + print_exit_status(err); + return err; +} + +static int unionfs_file_readdir(struct file *file, void *dirent, + filldir_t filldir) +{ + int err = -ENOTDIR; + print_entry_location(); + print_exit_status(err); + return err; +} + +static unsigned int unionfs_poll(struct file *file, poll_table * wait) +{ + unsigned int mask = DEFAULT_POLLMASK; + struct file *hidden_file = NULL; + + print_entry_location(); + + if (unionfs_file_revalidate(file, 0)) { + /* We should pretend an error happend. */ + mask = POLLERR | POLLIN | POLLOUT; + goto out; + } + + hidden_file = ftohf(file); + + if (!hidden_file->f_op || !hidden_file->f_op->poll) + goto out; + + mask = hidden_file->f_op->poll(hidden_file, wait); + + out: + print_exit_status(mask); + return mask; +} + +#ifndef UNIONFS_MMAP +static int __do_mmap(struct file *file, struct vm_area_struct *vma) +{ + int err; + struct file *hidden_file; + + print_entry_location(); + hidden_file = ftohf(file); + + err = -ENODEV; + if (!hidden_file->f_op || !hidden_file->f_op->mmap) + goto out; + + vma->vm_file = hidden_file; + err = hidden_file->f_op->mmap(hidden_file, vma); + get_file(hidden_file); /* make sure it doesn't get freed on us */ + fput(file); /* no need to keep extra ref on ours */ + out: + print_exit_status(err); + return err; +} +#endif +/* SP: mmap code now maps upper file + * like old code, will only copyup at this point, it's possible to copyup + * in writepage(), but I haven't bothered with that, as only apt-get seem + * to want to write to a shared/write mapping + */ +static int unionfs_mmap(struct file *file, struct vm_area_struct *vma) +{ + int err = 0; + int willwrite; + + print_entry_location(); + + /* This might could be deferred to mmap's writepage. */ + willwrite = ((vma->vm_flags | VM_SHARED | VM_WRITE) == vma->vm_flags); + if ((err = unionfs_file_revalidate(file, willwrite))) + goto out; +#ifdef UNIONFS_MMAP + err = generic_file_mmap(file, vma); + if (err) { + printk("unionfs_mmap: generic_file_mmap failed\n"); + } +#else + err = __do_mmap(file, vma); +#endif + + out: + print_exit_status(err); + return err; +} + +/* SP: disabled as use the generic file_fsync */ +#ifndef UNIONFS_MMAP +static int unionfs_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + int err; + struct file *hidden_file = NULL; + + print_entry_location(); + + if ((err = unionfs_file_revalidate(file, 1))) + goto out; + + hidden_file = ftohf(file); + + err = -EINVAL; + if (!hidden_file->f_op || !hidden_file->f_op->fsync) + goto out; + + mutex_lock(&hidden_file->f_dentry->d_inode->i_mutex); + err = hidden_file->f_op->fsync(hidden_file, hidden_file->f_dentry, + datasync); + mutex_unlock(&hidden_file->f_dentry->d_inode->i_mutex); + + out: + print_exit_status(err); + return err; +} +#endif + +/* SP: disabled as none of the other in kernel fs's seem to use it */ +static int unionfs_fasync(int fd, struct file *file, int flag) +{ + int err = 0; + struct file *hidden_file = NULL; + + print_entry_location(); + + if ((err = unionfs_file_revalidate(file, 1))) + goto out; + + hidden_file = ftohf(file); + + if (hidden_file->f_op && hidden_file->f_op->fasync) + err = hidden_file->f_op->fasync(fd, hidden_file, flag); + + out: + print_exit_status(err); + return err; +} + +struct file_operations unionfs_main_fops = { +#ifdef UNIONFS_MMAP + .llseek = generic_file_llseek, +#else + .llseek = unionfs_llseek, +#endif + .read = unionfs_read, + .write = unionfs_write, + .readdir = unionfs_file_readdir, + .poll = unionfs_poll, + .unlocked_ioctl = unionfs_ioctl, + .mmap = unionfs_mmap, + .open = unionfs_open, + .flush = unionfs_flush, + .release = unionfs_file_release, +#ifdef UNIONFS_MMAP + .fsync = file_fsync, +#else + .fsync = unionfs_fsync, +#endif + .fasync = unionfs_fasync, +#ifdef SUPPORT_BROKEN_LOSETUP + .sendfile = unionfs_sendfile, +#endif +}; + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/dirhelper.c +++ linux-2.6.27/ubuntu/unionfs/dirhelper.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: dirhelper.c,v 1.32 2006/10/31 18:05:33 yiannos Exp $ + */ + +#include "unionfs.h" + +/* Delete all of the whiteouts in a given directory for rmdir. */ +int do_delete_whiteouts(struct dentry *dentry, int bindex, + struct unionfs_dir_state *namelist) +{ + int err = 0; + struct dentry *hidden_dir_dentry = NULL; + struct dentry *hidden_dentry; + char *name = NULL, *p; + struct inode *hidden_dir; + + int i; + struct list_head *pos; + struct filldir_node *cursor; + + /* Find out hidden parent dentry */ + hidden_dir_dentry = dtohd_index(dentry, bindex); + BUG_ON(!S_ISDIR(hidden_dir_dentry->d_inode->i_mode)); + hidden_dir = hidden_dir_dentry->d_inode; + BUG_ON(!S_ISDIR(hidden_dir->i_mode)); + + err = -ENOMEM; + name = __getname(); + if (!name) + goto out; + strcpy(name, WHPFX); + p = name + WHLEN; + + err = 0; + for (i = 0; !err && i < namelist->uds_size; i++) { + list_for_each(pos, &namelist->uds_list[i]) { + cursor = + list_entry(pos, struct filldir_node, file_list); + /* Only operate on whiteouts in this branch. */ + if (cursor->bindex != bindex) + continue; + if (!cursor->whiteout) + continue; + + strcpy(p, cursor->name); + hidden_dentry = + lookup_one_len(name, hidden_dir_dentry, + cursor->namelen + WHLEN); + if (IS_ERR(hidden_dentry)) { + err = PTR_ERR(hidden_dentry); + break; + } + if (hidden_dentry->d_inode) + err = vfs_unlink(hidden_dir, hidden_dentry, + NULL); + dput(hidden_dentry); + if (err) + break; + } + } + + __putname(name); + + /* After all of the removals, we should copy the attributes once. */ + fist_copy_attr_times(dentry->d_inode, hidden_dir_dentry->d_inode); + +out: + return err; +} + +/* Delete all of the whiteouts in a given directory for rmdir. */ +int delete_whiteouts(struct dentry *dentry, int bindex, + struct unionfs_dir_state *namelist) +{ + int err = 0; + struct dentry *hidden_dir_dentry = NULL; + struct super_block *sb; + char *name = NULL, *p; + struct inode *hidden_dir; + + struct sioq_args args; + + print_entry_location(); + + sb = dentry->d_sb; + unionfs_read_lock(sb); + + BUG_ON(!S_ISDIR(dentry->d_inode->i_mode)); + BUG_ON(bindex < dbstart(dentry)); + BUG_ON(bindex > dbend(dentry)); + err = is_robranch_super(sb, bindex); + if (err) + goto out; + + /* Find out hidden parent dentry */ + hidden_dir_dentry = dtohd_index(dentry, bindex); + BUG_ON(!S_ISDIR(hidden_dir_dentry->d_inode->i_mode)); + hidden_dir = hidden_dir_dentry->d_inode; + BUG_ON(!S_ISDIR(hidden_dir->i_mode)); + + err = -ENOMEM; + name = __getname(); + if (!name) + goto out; + strcpy(name, WHPFX); + p = name + WHLEN; + + err = 0; + mutex_lock(&hidden_dir->i_mutex); + + if (!inode_permission(hidden_dir, MAY_WRITE | MAY_EXEC)) + err = do_delete_whiteouts(dentry, bindex, namelist); + else { + args.deletewh.namelist = namelist; + args.deletewh.dentry = dentry; + args.deletewh.bindex = bindex; + run_sioq(__delete_whiteouts, &args); + err = args.err; + } + + mutex_unlock(&hidden_dir->i_mutex); + + out: + unionfs_read_unlock(sb); + print_exit_status(err); + return err; +} + +#define RD_NONE 0 +#define RD_CHECK_EMPTY 1 +/* The callback structure for check_empty. */ +struct unionfs_rdutil_callback { + int err; + int filldir_called; + struct unionfs_dir_state *rdstate; + int mode; +}; + +/* This filldir function makes sure only whiteouts exist within a directory. */ +static int readdir_util_callback(void *dirent, const char *name, int namelen, + loff_t offset, u64 ino, unsigned int d_type) +{ + int err = 0; + struct unionfs_rdutil_callback *buf = + (struct unionfs_rdutil_callback *)dirent; + int whiteout = 0; + struct filldir_node *found; + + print_entry_location(); + + buf->filldir_called = 1; + + if (name[0] == '.' + && (namelen == 1 || (name[1] == '.' && namelen == 2))) + goto out; + + if ((namelen > WHLEN) && !strncmp(name, WHPFX, WHLEN)) { + namelen -= WHLEN; + name += WHLEN; + whiteout = 1; + } + + found = find_filldir_node(buf->rdstate, name, namelen); + /* If it was found in the table there was a previous whiteout. */ + if (found) + goto out; + + /* If it wasn't found and isn't a whiteout, the directory isn't empty. */ + err = -ENOTEMPTY; + if ((buf->mode == RD_CHECK_EMPTY) && !whiteout) + goto out; + + err = add_filldir_node(buf->rdstate, name, namelen, + buf->rdstate->uds_bindex, whiteout); + + out: + buf->err = err; + print_exit_status(err); + return err; +} + +/* Is a directory logically empty? */ +int check_empty(struct dentry *dentry, struct unionfs_dir_state **namelist) +{ + int err = 0; + struct dentry *hidden_dentry = NULL; + struct super_block *sb; + struct file *hidden_file; + struct unionfs_rdutil_callback *buf = NULL; + int bindex, bstart, bend, bopaque; + + print_entry_location(); + + sb = dentry->d_sb; + + unionfs_read_lock(sb); + + BUG_ON(!S_ISDIR(dentry->d_inode->i_mode)); + + if ((err = unionfs_partial_lookup(dentry))) + goto out; + + bstart = dbstart(dentry); + bend = dbend(dentry); + bopaque = dbopaque(dentry); + if (0 <= bopaque && bopaque < bend) + bend = bopaque; + + buf = KMALLOC(sizeof(struct unionfs_rdutil_callback), GFP_KERNEL); + if (!buf) { + err = -ENOMEM; + goto out; + } + buf->err = 0; + buf->mode = RD_CHECK_EMPTY; + buf->rdstate = alloc_rdstate(dentry->d_inode, bstart); + if (!buf->rdstate) { + err = -ENOMEM; + goto out; + } + + /* Process the hidden directories with rdutil_callback as a filldir. */ + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + continue; + if (!hidden_dentry->d_inode) + continue; + if (!S_ISDIR(hidden_dentry->d_inode->i_mode)) + continue; + + DGET(hidden_dentry); + mntget(stohiddenmnt_index(sb, bindex)); + branchget(sb, bindex); + hidden_file = + DENTRY_OPEN(hidden_dentry, stohiddenmnt_index(sb, bindex), + O_RDONLY); + if (IS_ERR(hidden_file)) { + err = PTR_ERR(hidden_file); + DPUT(hidden_dentry); + branchput(sb, bindex); + goto out; + } + + do { + buf->filldir_called = 0; + buf->rdstate->uds_bindex = bindex; + err = vfs_readdir(hidden_file, + readdir_util_callback, buf); + if (buf->err) + err = buf->err; + } while ((err >= 0) && buf->filldir_called); + + /* fput calls dput for hidden_dentry */ + fput(hidden_file); + branchput(sb, bindex); + + if (err < 0) + goto out; + } + + out: + if (buf) { + if (namelist && !err) + *namelist = buf->rdstate; + else if (buf->rdstate) + free_rdstate(buf->rdstate); + KFREE(buf); + } + + unionfs_read_unlock(sb); + + print_exit_status(err); + return err; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/inode.c +++ linux-2.6.27/ubuntu/unionfs/inode.c @@ -0,0 +1,1034 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: inode.c,v 1.275 2006/10/31 18:05:33 yiannos Exp $ + */ + +#include "unionfs.h" + +/* declarations added for "sparse" */ +extern struct dentry *unionfs_lookup(struct inode *, struct dentry *, + struct nameidata *); +extern int unionfs_readlink(struct dentry *dentry, char __user * buf, + int bufsiz); +extern void unionfs_put_link(struct dentry *dentry, struct nameidata *nd, + void *cookie); + +static int unionfs_create(struct inode *parent, struct dentry *dentry, + int mode, struct nameidata *nd) +{ + int err = 0; + struct dentry *hidden_dentry = NULL; + struct dentry *whiteout_dentry = NULL; + struct dentry *new_hidden_dentry; + struct dentry *hidden_parent_dentry = NULL; + int bindex = 0, bstart; + char *name = NULL; + + print_entry_location(); + lock_dentry(dentry); + print_dentry("IN unionfs_create", dentry); + + /* We start out in the leftmost branch. */ + bstart = dbstart(dentry); + hidden_dentry = dtohd(dentry); + + /* check if whiteout exists in this branch, i.e. lookup .wh.foo first */ + name = alloc_whname(dentry->d_name.name, dentry->d_name.len); + if (IS_ERR(name)) { + err = PTR_ERR(name); + goto out; + } + + whiteout_dentry = + LOOKUP_ONE_LEN(name, hidden_dentry->d_parent, + dentry->d_name.len + WHLEN); + if (IS_ERR(whiteout_dentry)) { + err = PTR_ERR(whiteout_dentry); + whiteout_dentry = NULL; + goto out; + } + + if (whiteout_dentry->d_inode) { + /* .wh.foo has been found. */ + /* First truncate it and then rename it to foo (hence having + * the same overall effect as a normal create. + * + * XXX: This is not strictly correct. If we have unlinked the + * file and it still has a reference count, then we should + * actually unlink the whiteout so that user's data isn't + * hosed over. + */ + struct dentry *hidden_dir_dentry; + struct iattr newattrs; + + mutex_lock(&whiteout_dentry->d_inode->i_mutex); + newattrs.ia_valid = ATTR_CTIME | ATTR_ATIME + | ATTR_MTIME | ATTR_UID | ATTR_GID | ATTR_FORCE + | ATTR_KILL_SUID | ATTR_KILL_SGID; + + newattrs.ia_mode = mode & ~current->fs->umask; + newattrs.ia_uid = current->fsuid; + newattrs.ia_gid = current->fsgid; + + if (whiteout_dentry->d_inode->i_size != 0) { + newattrs.ia_valid |= ATTR_SIZE; + newattrs.ia_size = 0; + } + + err = notify_change(whiteout_dentry, NULL, &newattrs); + + mutex_unlock(&whiteout_dentry->d_inode->i_mutex); + + if (err) + printk(KERN_WARNING + "unionfs: %s:%d: notify_change failed: %d, ignoring..\n", + __FILE__, __LINE__, err); + + new_hidden_dentry = dtohd(dentry); + DGET(new_hidden_dentry); + + hidden_dir_dentry = GET_PARENT(whiteout_dentry); + lock_rename(hidden_dir_dentry, hidden_dir_dentry); + + if (!(err = is_robranch_super(dentry->d_sb, bstart))) { + err = + vfs_rename(hidden_dir_dentry->d_inode, + whiteout_dentry, NULL, + hidden_dir_dentry->d_inode, + new_hidden_dentry, NULL); + } + if (!err) { + fist_copy_attr_timesizes(parent, + new_hidden_dentry->d_parent-> + d_inode); + parent->i_nlink = get_nlinks(parent); + } + + unlock_rename(hidden_dir_dentry, hidden_dir_dentry); + DPUT(hidden_dir_dentry); + + DPUT(new_hidden_dentry); + + if (err) { + /* exit if the error returned was NOT -EROFS */ + if (!IS_COPYUP_ERR(err)) + goto out; + /* We were not able to create the file in this branch, + * so, we try to create it in one branch to left + */ + bstart--; + } else { + /* reset the unionfs dentry to point to the .wh.foo entry. */ + + /* Discard any old reference. */ + DPUT(dtohd(dentry)); + + /* Trade one reference to another. */ + set_dtohd_index(dentry, bstart, whiteout_dentry); + whiteout_dentry = NULL; + + err = unionfs_interpose(dentry, parent->i_sb, 0); + goto out; + } + } + + for (bindex = bstart; bindex >= 0; bindex--) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) { + /* if hidden_dentry is NULL, create the entire + * dentry directory structure in branch 'bindex'. + * hidden_dentry will NOT be null when bindex == bstart + * because lookup passed as a negative unionfs dentry + * pointing to a lone negative underlying dentry */ + hidden_dentry = create_parents(parent, dentry, bindex); + if (!hidden_dentry || IS_ERR(hidden_dentry)) { + if (IS_ERR(hidden_dentry)) + err = PTR_ERR(hidden_dentry); + continue; + } + } + + checkinode(parent, "unionfs_create"); + + hidden_parent_dentry = lock_parent(hidden_dentry); + if (IS_ERR(hidden_parent_dentry)) { + err = PTR_ERR(hidden_parent_dentry); + goto out; + } + /* We shouldn't create things in a read-only branch. */ + if (!(err = is_robranch_super(dentry->d_sb, bindex))) { + //DQ: vfs_create has a different prototype in 2.6 + err = vfs_create(hidden_parent_dentry->d_inode, + hidden_dentry, mode, nd); + } + if (err || !hidden_dentry->d_inode) { + unlock_dir(hidden_parent_dentry); + + /* break out of for loop if the error wasn't -EROFS */ + if (!IS_COPYUP_ERR(err)) + break; + } else { + err = unionfs_interpose(dentry, parent->i_sb, 0); + if (!err) { + fist_copy_attr_timesizes(parent, + hidden_parent_dentry-> + d_inode); + /* update number of links on parent directory */ + parent->i_nlink = get_nlinks(parent); + } + unlock_dir(hidden_parent_dentry); + break; + } + } + + out: + DPUT(whiteout_dentry); + KFREE(name); + + print_dentry("OUT unionfs_create :", dentry); + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +struct dentry *unionfs_lookup(struct inode *parent, struct dentry *dentry, + struct nameidata *nd) +{ + struct nameidata lowernd; + + if(nd) + memcpy(&lowernd, nd, sizeof(struct nameidata)); + else + memset(&lowernd, 0, sizeof(struct nameidata)); + + /* The locking is done by unionfs_lookup_backend. */ + return unionfs_lookup_backend(dentry, &lowernd, INTERPOSE_LOOKUP); +} + +static int unionfs_link(struct dentry *old_dentry, struct inode *dir, + struct dentry *new_dentry) +{ + int err = 0; + struct dentry *hidden_old_dentry = NULL; + struct dentry *hidden_new_dentry = NULL; + struct dentry *hidden_dir_dentry = NULL; + struct dentry *whiteout_dentry; + char *name = NULL; + + print_entry_location(); + double_lock_dentry(new_dentry, old_dentry); + + hidden_new_dentry = dtohd(new_dentry); + + /* check if whiteout exists in the branch of new dentry, i.e. lookup + * .wh.foo first. If present, delete it */ + name = alloc_whname(new_dentry->d_name.name, new_dentry->d_name.len); + if (IS_ERR(name)) { + err = PTR_ERR(name); + goto out; + } + + whiteout_dentry = + LOOKUP_ONE_LEN(name, hidden_new_dentry->d_parent, + new_dentry->d_name.len + WHLEN); + if (IS_ERR(whiteout_dentry)) { + err = PTR_ERR(whiteout_dentry); + goto out; + } + + if (!whiteout_dentry->d_inode) { + DPUT(whiteout_dentry); + whiteout_dentry = NULL; + } else { + /* found a .wh.foo entry, unlink it and then call vfs_link() */ + hidden_dir_dentry = lock_parent(whiteout_dentry); + if (! + (err = + is_robranch_super(new_dentry->d_sb, + dbstart(new_dentry)))) { + err = + vfs_unlink(hidden_dir_dentry->d_inode, + whiteout_dentry, NULL); + } + fist_copy_attr_times(dir, hidden_dir_dentry->d_inode); + dir->i_nlink = get_nlinks(dir); + unlock_dir(hidden_dir_dentry); + hidden_dir_dentry = NULL; + DPUT(whiteout_dentry); + if (err) + goto out; + } + + if (dbstart(old_dentry) != dbstart(new_dentry)) { + hidden_new_dentry = + create_parents(dir, new_dentry, dbstart(old_dentry)); + err = PTR_ERR(hidden_new_dentry); + if (IS_COPYUP_ERR(err)) + goto docopyup; + if (!hidden_new_dentry || IS_ERR(hidden_new_dentry)) + goto out; + } + hidden_new_dentry = dtohd(new_dentry); + hidden_old_dentry = dtohd(old_dentry); + + BUG_ON(dbstart(old_dentry) != dbstart(new_dentry)); + hidden_dir_dentry = lock_parent(hidden_new_dentry); + if (!(err = is_robranch(old_dentry))) + err = + vfs_link(hidden_old_dentry, NULL, + hidden_dir_dentry->d_inode, + hidden_new_dentry, NULL); + unlock_dir(hidden_dir_dentry); + + docopyup: + if (IS_COPYUP_ERR(err)) { + int old_bstart = dbstart(old_dentry); + int bindex; + + for (bindex = old_bstart - 1; bindex >= 0; bindex--) { + err = + copyup_dentry(old_dentry->d_parent-> + d_inode, old_dentry, + old_bstart, bindex, NULL, + old_dentry->d_inode->i_size); + if (!err) { + hidden_new_dentry = + create_parents(dir, new_dentry, bindex); + hidden_old_dentry = dtohd(old_dentry); + hidden_dir_dentry = + lock_parent(hidden_new_dentry); + /* do vfs_link */ + err = vfs_link(hidden_old_dentry, NULL, + hidden_dir_dentry->d_inode, + hidden_new_dentry, NULL); + unlock_dir(hidden_dir_dentry); + goto check_link; + } + } + goto out; + } + check_link: + if (err || !hidden_new_dentry->d_inode) + goto out; + + /* Its a hard link, so use the same inode */ + new_dentry->d_inode = IGRAB(old_dentry->d_inode); + d_instantiate(new_dentry, new_dentry->d_inode); + fist_copy_attr_all(dir, hidden_new_dentry->d_parent->d_inode); + /* propagate number of hard-links */ + old_dentry->d_inode->i_nlink = get_nlinks(old_dentry->d_inode); + + out: + if (!new_dentry->d_inode) + d_drop(new_dentry); + + KFREE(name); + + unlock_dentry(new_dentry); + unlock_dentry(old_dentry); + + print_exit_status(err); + return err; +} + +static int unionfs_symlink(struct inode *dir, struct dentry *dentry, + const char *symname) +{ + int err = 0; + struct dentry *hidden_dentry = NULL; + struct dentry *whiteout_dentry = NULL; + struct dentry *hidden_dir_dentry = NULL; + umode_t mode; + int bindex = 0, bstart; + char *name = NULL; + + print_entry_location(); + lock_dentry(dentry); + print_dentry("IN unionfs_symlink", dentry); + + /* We start out in the leftmost branch. */ + bstart = dbstart(dentry); + + hidden_dentry = dtohd(dentry); + + /* check if whiteout exists in this branch, i.e. lookup .wh.foo first. If present, delete it */ + name = alloc_whname(dentry->d_name.name, dentry->d_name.len); + if (IS_ERR(name)) { + err = PTR_ERR(name); + goto out; + } + + whiteout_dentry = + LOOKUP_ONE_LEN(name, hidden_dentry->d_parent, + dentry->d_name.len + WHLEN); + if (IS_ERR(whiteout_dentry)) { + err = PTR_ERR(whiteout_dentry); + goto out; + } + + if (!whiteout_dentry->d_inode) { + DPUT(whiteout_dentry); + whiteout_dentry = NULL; + } else { + /* found a .wh.foo entry, unlink it and then call vfs_symlink() */ + hidden_dir_dentry = lock_parent(whiteout_dentry); + + print_dentry("HDD", hidden_dir_dentry); + print_dentry("WD", whiteout_dentry); + + if (!(err = is_robranch_super(dentry->d_sb, bstart))) { + err = + vfs_unlink(hidden_dir_dentry->d_inode, + whiteout_dentry, NULL); + } + DPUT(whiteout_dentry); + + fist_copy_attr_times(dir, hidden_dir_dentry->d_inode); + /* propagate number of hard-links */ + dir->i_nlink = get_nlinks(dir); + + unlock_dir(hidden_dir_dentry); + + if (err) { + /* exit if the error returned was NOT -EROFS */ + if (!IS_COPYUP_ERR(err)) + goto out; + /* should now try to create symlink in the another branch */ + bstart--; + } + } + + /* deleted whiteout if it was present, now do a normal vfs_symlink() with + possible recursive directory creation */ + for (bindex = bstart; bindex >= 0; bindex--) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) { + /* if hidden_dentry is NULL, create the entire + * dentry directory structure in branch 'bindex'. hidden_dentry will NOT be null when + * bindex == bstart because lookup passed as a negative unionfs dentry pointing to a + * lone negative underlying dentry */ + hidden_dentry = create_parents(dir, dentry, bindex); + if (!hidden_dentry || IS_ERR(hidden_dentry)) { + if (IS_ERR(hidden_dentry)) { + err = PTR_ERR(hidden_dentry); + } + dprint(PRINT_DEBUG, + "hidden dentry NULL (or error) for bindex = %d\n", + bindex); + continue; + } + } + + hidden_dir_dentry = lock_parent(hidden_dentry); + + if (!(err = is_robranch_super(dentry->d_sb, bindex))) { + mode = S_IALLUGO; + err = + vfs_symlink(hidden_dir_dentry->d_inode, + hidden_dentry, NULL, symname); + } + unlock_dir(hidden_dir_dentry); + + if (err || !hidden_dentry->d_inode) { + /* break out of for loop if error returned was NOT -EROFS */ + if (!IS_COPYUP_ERR(err)) + break; + } else { + err = unionfs_interpose(dentry, dir->i_sb, 0); + if (!err) { + fist_copy_attr_timesizes(dir, + hidden_dir_dentry-> + d_inode); + /* update number of links on parent directory */ + dir->i_nlink = get_nlinks(dir); + } + break; + } + } + + out: + if (!dentry->d_inode) + d_drop(dentry); + + KFREE(name); + print_dentry("OUT unionfs_symlink :", dentry); + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +static int unionfs_mkdir(struct inode *parent, struct dentry *dentry, int mode) +{ + int err = 0; + struct dentry *hidden_dentry = NULL, *whiteout_dentry = NULL; + struct dentry *hidden_parent_dentry = NULL; + int bindex = 0, bstart; + char *name = NULL; + int whiteout_unlinked = 0; + struct sioq_args args; + + print_entry_location(); + lock_dentry(dentry); + print_dentry("IN unionfs_mkdir", dentry); + bstart = dbstart(dentry); + + hidden_dentry = dtohd(dentry); + + // check if whiteout exists in this branch, i.e. lookup .wh.foo first + name = alloc_whname(dentry->d_name.name, dentry->d_name.len); + if (IS_ERR(name)) { + err = PTR_ERR(name); + goto out; + } + + whiteout_dentry = + LOOKUP_ONE_LEN(name, hidden_dentry->d_parent, + dentry->d_name.len + WHLEN); + if (IS_ERR(whiteout_dentry)) { + err = PTR_ERR(whiteout_dentry); + goto out; + } + + if (!whiteout_dentry->d_inode) { + DPUT(whiteout_dentry); + whiteout_dentry = NULL; + } else { + hidden_parent_dentry = lock_parent(whiteout_dentry); + + //found a.wh.foo entry, remove it then do vfs_mkdir + if (!(err = is_robranch_super(dentry->d_sb, bstart))) { + args.unlink.parent = hidden_parent_dentry->d_inode; + args.unlink.dentry = whiteout_dentry; + run_sioq(__unionfs_unlink, &args); + err = args.err; + } + DPUT(whiteout_dentry); + + unlock_dir(hidden_parent_dentry); + + if (err) { + /* exit if the error returned was NOT -EROFS */ + if (!IS_COPYUP_ERR(err)) + goto out; + bstart--; + } else { + whiteout_unlinked = 1; + } + } + + for (bindex = bstart; bindex >= 0; bindex--) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) { + hidden_dentry = create_parents(parent, dentry, bindex); + if (!hidden_dentry || IS_ERR(hidden_dentry)) { + dprint(PRINT_DEBUG, + "hidden dentry NULL for bindex = %d\n", + bindex); + continue; + } + } + + hidden_parent_dentry = lock_parent(hidden_dentry); + if (IS_ERR(hidden_parent_dentry)) { + err = PTR_ERR(hidden_parent_dentry); + goto out; + } + if (!(err = is_robranch_super(dentry->d_sb, bindex))) { + err = + vfs_mkdir(hidden_parent_dentry->d_inode, + hidden_dentry, NULL, mode); + } + unlock_dir(hidden_parent_dentry); + + /* XXX this could potentially return a negative hidden_dentry! */ + if (err || !hidden_dentry->d_inode) { + /* break out of for loop if error returned was NOT -EROFS */ + if (!IS_COPYUP_ERR(err)) + break; + } else { + int i; + int bend = dbend(dentry); + + for (i = bindex + 1; i < bend; i++) { + if (dtohd_index(dentry, i)) { + DPUT(dtohd_index(dentry, i)); + set_dtohd_index(dentry, i, NULL); + } + } + bend = bindex; + set_dbend(dentry, bend); + + err = unionfs_interpose(dentry, parent->i_sb, 0); + if (!err) { + fist_copy_attr_timesizes(parent, + hidden_parent_dentry-> + d_inode); + /* update number of links on parent directory */ + parent->i_nlink = get_nlinks(parent); + } + + err = make_dir_opaque(dentry, dbstart(dentry)); + if (err) { + dprint(PRINT_DEBUG, + "mkdir: error creating directory override entry: %d\n", + err); + goto out; + } + break; + } + } + + out: + if (!dentry->d_inode) + d_drop(dentry); + + KFREE(name); + + print_dentry("OUT unionfs_mkdir :", dentry); + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +static int unionfs_mknod(struct inode *dir, struct dentry *dentry, int mode, + dev_t dev) +{ + int err = 0; + struct dentry *hidden_dentry = NULL, *whiteout_dentry = NULL; + struct dentry *hidden_parent_dentry = NULL; + int bindex = 0, bstart; + char *name = NULL; + int whiteout_unlinked = 0; + + print_entry_location(); + lock_dentry(dentry); + print_dentry("IN unionfs_mknod", dentry); + bstart = dbstart(dentry); + + hidden_dentry = dtohd(dentry); + + // check if whiteout exists in this branch, i.e. lookup .wh.foo first + name = alloc_whname(dentry->d_name.name, dentry->d_name.len); + if (IS_ERR(name)) { + err = PTR_ERR(name); + goto out; + } + + whiteout_dentry = + LOOKUP_ONE_LEN(name, hidden_dentry->d_parent, + dentry->d_name.len + WHLEN); + if (IS_ERR(whiteout_dentry)) { + err = PTR_ERR(whiteout_dentry); + goto out; + } + + if (!whiteout_dentry->d_inode) { + DPUT(whiteout_dentry); + whiteout_dentry = NULL; + } else { + /* found .wh.foo, unlink it */ + hidden_parent_dentry = lock_parent(whiteout_dentry); + + //found a.wh.foo entry, remove it then do vfs_mkdir + if (!(err = is_robranch_super(dentry->d_sb, bstart))) + err = vfs_unlink(hidden_parent_dentry->d_inode, + whiteout_dentry, NULL); + DPUT(whiteout_dentry); + + unlock_dir(hidden_parent_dentry); + + if (err) { + if (!IS_COPYUP_ERR(err)) + goto out; + + bstart--; + } else { + whiteout_unlinked = 1; + } + } + + for (bindex = bstart; bindex >= 0; bindex--) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) { + hidden_dentry = create_parents(dir, dentry, bindex); + if (!hidden_dentry || IS_ERR(hidden_dentry)) { + dprint(PRINT_DEBUG, + "hidden dentry NULL for bindex = %d\n", + bindex); + continue; + } + } + + hidden_parent_dentry = lock_parent(hidden_dentry); + if (IS_ERR(hidden_parent_dentry)) { + err = PTR_ERR(hidden_parent_dentry); + goto out; + } + if (!(err = is_robranch_super(dentry->d_sb, bindex))) { + err = vfs_mknod(hidden_parent_dentry->d_inode, + hidden_dentry, NULL, mode, dev); + } + /* XXX this could potentially return a negative hidden_dentry! */ + if (err || !hidden_dentry->d_inode) { + unlock_dir(hidden_parent_dentry); + /* break out of for, if error was NOT -EROFS */ + if (!IS_COPYUP_ERR(err)) + break; + } else { + err = unionfs_interpose(dentry, dir->i_sb, 0); + if (!err) { + fist_copy_attr_timesizes(dir, + hidden_parent_dentry-> + d_inode); + /* update number of links on parent directory */ + dir->i_nlink = get_nlinks(dir); + } + unlock_dir(hidden_parent_dentry); + + break; + } + } + + out: + if (!dentry->d_inode) + d_drop(dentry); + + if (name) { + KFREE(name); + } + + print_dentry("OUT unionfs_mknod :", dentry); + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +int unionfs_readlink(struct dentry *dentry, char __user * buf, int bufsiz) +{ + int err; + struct dentry *hidden_dentry; + + print_entry_location(); + lock_dentry(dentry); + hidden_dentry = dtohd(dentry); + print_dentry("unionfs_readlink IN", dentry); + + if (!hidden_dentry->d_inode->i_op || + !hidden_dentry->d_inode->i_op->readlink) { + err = -EINVAL; + goto out; + } + + err = hidden_dentry->d_inode->i_op->readlink(hidden_dentry, + buf, bufsiz); + if (err > 0) + fist_copy_attr_atime(dentry->d_inode, hidden_dentry->d_inode); + + out: + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +/* We don't lock the dentry here, because readlink does the heavy lifting. */ +static void *unionfs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + char *buf; + int len = PAGE_SIZE, err; + mm_segment_t old_fs; + + print_entry_location(); + + /* This is freed by the put_link method assuming a successful call. */ + buf = (char *)KMALLOC(len, GFP_KERNEL); + if (!buf) { + err = -ENOMEM; + goto out; + } + + /* read the symlink, and then we will follow it */ + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len); + set_fs(old_fs); + if (err < 0) { + KFREE(buf); + buf = NULL; + goto out; + } + buf[err] = 0; + nd_set_link(nd, buf); + err = 0; + + out: + print_exit_status(err); + return ERR_PTR(err); +} + +void unionfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) +{ + char *link; + print_entry_location(); + link = nd_get_link(nd); + KFREE(link); + print_exit_location(); +} + +/* Basically copied from the kernel vfs permission(), but we've changed + * the following: (1) the IS_RDONLY check is skipped, and (2) if you set + * the mount option `nfsperms=insceure', we assume that -EACCES means that + * the export is read-only and we should check standard Unix permissions. + * This means that NFS ACL checks (or other advanced permission features) + * are bypassed. + */ +static int unionfs_inode_permission(struct inode *inode, int mask, struct nameidata *nd, + int bindex) +{ + int retval, submask; + + if (mask & MAY_WRITE) { + /* The first branch is allowed to be really readonly. */ + if (bindex == 0) { + umode_t mode = inode->i_mode; + if (IS_RDONLY(inode) && (S_ISREG(mode) || S_ISDIR(mode) + || S_ISLNK(mode))) + return -EROFS; + } + /* + * Nobody gets write access to an immutable file. + */ + if (IS_IMMUTABLE(inode)) + return -EACCES; + } + + /* Ordinary permission routines do not understand MAY_APPEND. */ + submask = mask & ~MAY_APPEND; + if (inode->i_op && inode->i_op->permission) { + retval = inode->i_op->permission(inode, submask); + if ((retval == -EACCES) && (submask & MAY_WRITE) && + (!strcmp("nfs", (inode)->i_sb->s_type->name)) && + (nd) && (nd->path.mnt) && (nd->path.mnt->mnt_sb) && + (branchperms(nd->path.mnt->mnt_sb, bindex) & MAY_NFSRO)) { + retval = generic_permission(inode, submask, NULL); + } + } else { + retval = generic_permission(inode, submask, NULL); + } + + if (retval && retval != -EROFS) /* ignore EROFS */ + return retval; + + /* + * skip the LSM permission check. This means unionfs will wrongly + * copy up a LSM non-writable/non-readable file on a readonly branch + * to a read-write branch leading to odd behaviour. Until the mess + * of the LSM interface changes are resolved, there's nothing else + * that can be done. + * retval = security_inode_permission(inode, mask, nd); + */ + return ((retval == -EROFS) ? 0 : retval); /* ignore EROFS */ +} + +static int unionfs_permission(struct inode *inode, int mask) +{ + struct inode *hidden_inode = NULL; + int err = 0; + int bindex, bstart, bend; + const int is_file = !S_ISDIR(inode->i_mode); + const int write_mask = (mask & MAY_WRITE) && !(mask & MAY_READ); + + print_entry_location(); + + bstart = ibstart(inode); + bend = ibend(inode); + + print_inode("IN unionfs_permission", inode); + + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_inode = itohi_index(inode, bindex); + if (!hidden_inode) + continue; + + /* check the condition for D-F-D underlying files/directories, + * we dont have to check for files, if we are checking for + * directories. + */ + if (!is_file && !S_ISDIR(hidden_inode->i_mode)) + continue; + /* We use our own special version of permission, such that + * only the first branch returns -EROFS. */ + err = unionfs_inode_permission(hidden_inode, mask, NULL, bindex); + /* The permissions are an intersection of the overall directory + * permissions, so we fail if one fails. */ + if (err) + goto out; + /* only the leftmost file matters. */ + if (is_file || write_mask) { + if (is_file && write_mask) { + err = get_write_access(hidden_inode); + if (!err) + put_write_access(hidden_inode); + } + break; + } + } + + out: + print_exit_status(err); + return err; +} + +static int unionfs_setattr(struct dentry *dentry, struct iattr *ia) +{ + int err = 0; + struct dentry *hidden_dentry; + struct inode *inode = NULL; + struct inode *hidden_inode = NULL; + int bstart, bend, bindex; + int i; + int copyup = 0; + + print_entry_location(); + lock_dentry(dentry); + bstart = dbstart(dentry); + bend = dbend(dentry); + inode = dentry->d_inode; + + for (bindex = bstart; (bindex <= bend) || (bindex == bstart); bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + continue; + BUG_ON(hidden_dentry->d_inode == NULL); + + /* If the file is on a read only branch */ + if (is_robranch_super(dentry->d_sb, bindex) + || IS_RDONLY(hidden_dentry->d_inode)) { + if (copyup || (bindex != bstart)) + continue; + /* Only if its the leftmost file, copyup the file */ + for (i = bstart - 1; i >= 0; i--) { + loff_t size = dentry->d_inode->i_size; + if (ia->ia_valid & ATTR_SIZE) + size = ia->ia_size; + err = copyup_dentry(dentry->d_parent->d_inode, + dentry, bstart, i, NULL, + size); + + if (!err) { + copyup = 1; + hidden_dentry = dtohd(dentry); + break; + } + /* if error is in the leftmost f/s, pass it up */ + if (i == 0) + goto out; + } + + } + /* + * mode change is for clearing setuid/setgid bits. Allow lower fs + * to interpret this in its own way. + */ + if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) + ia->ia_valid &= ~ATTR_MODE; + + err = notify_change(hidden_dentry, NULL, ia); + if (err) + goto out; + break; + } +#ifdef UNIONFS_MMAP + /* + * SP: notify_change will change the lower file's size, + * but we need to truncate the page tables, so need to call + * vmtruncate() + */ + + if (ia->ia_valid & ATTR_SIZE) { + if (ia->ia_size != i_size_read(inode)) { + err = vmtruncate(inode, ia->ia_size); + if (err) { + printk("unionfs_setattr: vmtruncate failed\n"); + } + } + } +#endif + /* get the size from the first hidden inode */ + hidden_inode = itohi(dentry->d_inode); + checkinode(inode, "unionfs_setattr"); + fist_copy_attr_all(inode, hidden_inode); + + out: + unlock_dentry(dentry); + checkinode(inode, "post unionfs_setattr"); + print_exit_status(err); + return err; +} + +struct inode_operations unionfs_symlink_iops = { + .readlink = unionfs_readlink, + .permission = unionfs_permission, + .follow_link = unionfs_follow_link, + .setattr = unionfs_setattr, + .put_link = unionfs_put_link, +}; + +struct inode_operations unionfs_dir_iops = { + .create = unionfs_create, + .lookup = unionfs_lookup, + .link = unionfs_link, + .unlink = unionfs_unlink, + .symlink = unionfs_symlink, + .mkdir = unionfs_mkdir, + .rmdir = unionfs_rmdir, + .mknod = unionfs_mknod, + .rename = unionfs_rename, + .permission = unionfs_permission, + .setattr = unionfs_setattr, + .setxattr = unionfs_setxattr, + .getxattr = unionfs_getxattr, + .removexattr = unionfs_removexattr, + .listxattr = unionfs_listxattr, +}; + +struct inode_operations unionfs_main_iops = { + .permission = unionfs_permission, + .setattr = unionfs_setattr, + .setxattr = unionfs_setxattr, + .getxattr = unionfs_getxattr, + .removexattr = unionfs_removexattr, + .listxattr = unionfs_listxattr, +}; + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/unionfs_debug.h +++ linux-2.6.27/ubuntu/unionfs/unionfs_debug.h @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: unionfs_debug.h,v 1.3 2006/06/01 21:25:18 jsipek Exp $ + */ + +#ifndef __UNIONFS_H_ +#error This file should only be included from unionfs.h! +#endif + +#ifdef UNIONFS_DEBUG +#define DEFAULT_DEBUG_MASK 0 +#else +#define DEFAULT_DEBUG_MASK (~0) +#endif + +/* debug print levels */ +#define PRINT_NONE 0x0000 +#define PRINT_MAIN_ENTRY 0x0001 +#define PRINT_MAIN_EXIT 0x0002 +#define PRINT_UTILITY_ENTRY 0x0004 +#define PRINT_UTILITY_EXIT 0x0008 +#define PRINT_MISC_ENTRY 0x0010 +#define PRINT_MISC_EXIT 0x0020 +#define PRINT_DATA_DENTRY 0x0040 +#define PRINT_DATA_FILE 0x0080 +#define PRINT_DATA_INODE 0x0100 +#define PRINT_DATA_SB 0x0200 +#define PRINT_DEBUG 0x0400 +#define __PRINT_DEBUG_XATTR 0x0800 +#define PRINT_DEBUG_XATTR (PRINT_DEBUG | __PRINT_DEBUG_XATTR) +#define __PRINT_DEBUG_WHITEOUT 0x1000 +#define PRINT_DEBUG_WHITEOUT (PRINT_DEBUG | __PRINT_DEBUG_WHITEOUT) + +#define PRINT_MAX (0x2000 - 1) +#define PRINT_ALL (~PRINT_NONE) + +extern unsigned int get_debug_mask(void); +extern int set_debug_mask(int val); + +/* print inode */ +extern void unionfs_print_inode(const unsigned int req, const char *prefix, const struct inode *inode); + +/* check inode */ +extern void unionfs_checkinode(const unsigned int req, const struct inode *inode, const char *msg); + +/* prunt file */ +extern void unionfs_print_file(const unsigned int req, const char *prefix, const struct file *file); + +/* print dentry */ +extern void unionfs_print_dentry(const unsigned int req, const char *prefix, const struct dentry *dentry); + +extern void unionfs_print_dentry_nocheck(const unsigned int req, const char *prefix, const struct dentry *dentry); + +/* print superblock */ +extern void unionfs_print_sb(const unsigned int req, const char *prefix, const struct super_block *sb); + +/* print message */ +extern int unionfs_print(const unsigned int req, const char *fmt, ...); + +/* forced print-debugging functions */ +#define force_print_dentry(prefix, ptr) \ + unionfs_print_dentry(PRINT_ALL, (prefix), (ptr)) +#define force_print_dentry_nocheck(prefix, ptr) \ + unionfs_print_dentry_nocheck(PRINT_ALL, (prefix), (ptr)) +#define force_print_file(prefix, ptr) \ + unionfs_print_file(PRINT_ALL, (prefix), (ptr)) +#define force_print_inode(prefix, ptr) \ + unionfs_print_inode(PRINT_ALL, (prefix), (ptr)) +#define force_print_sb(prefix, ptr) \ + unionfs_print_sb(PRINT_ALL, (prefix), (ptr)) + +#ifdef UNIONFS_DEBUG +/* + * Full-fledged debugging enabled + */ + +#define print_dentry(prefix, ptr) \ + unionfs_print_dentry(PRINT_DATA_DENTRY, (prefix), (ptr)) +#define print_dentry_nocheck(prefix, ptr) \ + unionfs_print_dentry_nocheck(PRINT_DATA_DENTRY, (prefix), (ptr)) +#define print_file(prefix, ptr) \ + unionfs_print_file(PRINT_DATA_FILE, (prefix), (ptr)) +#define print_inode(prefix, ptr) \ + unionfs_print_inode(PRINT_DATA_INODE, (prefix), (ptr)) +#define print_sb(prefix, ptr) \ + unionfs_print_sb(PRINT_DATA_SB, (prefix), (ptr)) +#define dprint(req, fmt, args...) \ + unionfs_print(req, fmt, ## args) + +#define checkinode(ptr, msg) \ + unionfs_checkinode(PRINT_DEBUG, (ptr), (msg)) + +#define __print_entryexit(req, ee, fmt, args...) \ + unionfs_print((req), \ + ee " %s %s:%d" fmt "\n", \ + __FUNCTION__, \ + __FILE__, \ + __LINE__, \ + ##args) + +#define print_entry(fmt, args...) \ + __print_entryexit(PRINT_MAIN_ENTRY, \ + "IN: ", " " fmt, ##args) + +#define print_entry_location() \ + __print_entryexit(PRINT_MAIN_ENTRY, \ + "IN: ", "") + +#define print_exit_location() \ + __print_entryexit(PRINT_MAIN_EXIT, \ + "OUT:", "") + +#define print_exit_status(status) \ + __print_entryexit(PRINT_MAIN_EXIT, \ + "OUT:", ", STATUS: %d", status) + +static inline void __print_exit_pointer(unsigned int req, void *status) +{ + if (IS_ERR(status)) + __print_entryexit(req, "OUT:", ", STATUS: %ld", + PTR_ERR(status)); + else + __print_entryexit(req, "OUT:", ", STATUS: 0x%p", + status); +} +#define print_exit_pointer(status) \ + __print_exit_pointer(PRINT_MAIN_EXIT, status) + +#define print_util_entry(fmt, args...) \ + __print_entryexit(PRINT_UTILITY_ENTRY, \ + "IN: ", " " fmt, ##args) + +#define print_util_entry_location() \ + __print_entryexit(PRINT_UTILITY_ENTRY, \ + "IN: ", "") + +#define print_util_exit_location() \ + __print_entryexit(PRINT_UTILITY_EXIT, \ + "OUT:", "") + +#define print_util_exit_status(status) \ + __print_entryexit(PRINT_UTILITY_EXIT, \ + "OUT:", ", STATUS: %d", status) + +#define print_util_exit_pointer(status) \ + __print_exit_pointer(PRINT_UTILITY_EXIT, status) + +#else /* UNIONFS_DEBUG */ +/* + * Full-fledged debugging disabled + */ + +#define print_dentry(prefix, ptr) +#define print_dentry_nocheck(prefix, ptr) +#define print_file(prefix, ptr) +#define print_inode(prefix, ptr) +#define print_sb(prefix, ptr) +#define dprint(req, fmt, args...) + +#define checkinode(ptr, msg) + +#define print_entry(args...) +#define print_entry_location() +#define print_exit_location() +#define print_exit_status(status) +#define print_exit_pointer(status) +#define print_util_entry(args...) +#define print_util_entry_location() +#define print_util_exit_location() +#define print_util_exit_status(status) +#define print_util_exit_pointer(status) + +#endif /* ! UNIONFS_DEBUG */ + + --- linux-2.6.27.orig/ubuntu/unionfs/Makefile +++ linux-2.6.27/ubuntu/unionfs/Makefile @@ -0,0 +1,16 @@ +UNIONFS_VERSION = 1.4 +SUP_MAJOR= 2 +SUP_MINOR= 6 +SUP_PATCH= 18 + +EXTRA_CFLAGS+=-DUNIONFS_VERSION=\"${UNIONFS_VERSION}\" -DSUP_MAJOR=${SUP_MAJOR} -DSUP_MINOR=${SUP_MINOR} -DSUP_PATCH=${SUP_PATCH} -DUNIONFS_UNSUPPORTED + +# This will enable full debugging support +# EXTRA_CFLAGS+=-DUNIONFS_DEBUG + +obj-$(CONFIG_FS_UNIONFS) += unionfs.o + +unionfs-objs := subr.o dentry.o file.o inode.o main.o super.o \ + stale_inode.o branchman.o xattr.o rdstate.o copyup.o \ + dirhelper.o rename.o unlink.o lookup.o persistent_inode.o \ + commonfops.o dirfops.o print.o sioq.o --- linux-2.6.27.orig/ubuntu/unionfs/sioq.h +++ linux-2.6.27/ubuntu/unionfs/sioq.h @@ -0,0 +1,80 @@ +#ifndef _SIOQ_H +#define _SIOQ_H + +struct deletewh_args { + struct unionfs_dir_state *namelist; + struct dentry *dentry; + int bindex; +}; + +struct isopaque_args { + struct dentry *dentry; +}; + +struct create_args { + struct inode *parent; + struct dentry *dentry; + umode_t mode; + struct nameidata *nd; +}; + +struct mkdir_args { + struct inode *parent; + struct dentry *dentry; + umode_t mode; +}; + +struct mknod_args { + struct inode *parent; + struct dentry *dentry; + umode_t mode; + dev_t dev; +}; + +struct symlink_args { + struct inode *parent; + struct dentry *dentry; + char *symbuf; + umode_t mode; +}; + +struct unlink_args { + struct inode *parent; + struct dentry *dentry; +}; + + +struct sioq_args { + + struct completion comp; + struct work_struct wk; + int err; + void *ret; + + union { + struct deletewh_args deletewh; + struct isopaque_args isopaque; + struct create_args create; + struct mkdir_args mkdir; + struct mknod_args mknod; + struct symlink_args symlink; + struct unlink_args unlink; + }; //} u; +}; + +extern struct workqueue_struct *sioq; +int __init init_sioq(void); +extern void fin_sioq(void); +extern void run_sioq(work_func_t func, struct sioq_args *args); + +/* Extern definitions for our privledge escalation helpers */ +extern void __unionfs_create(struct work_struct *work); +extern void __unionfs_mkdir(struct work_struct *work); +extern void __unionfs_mknod(struct work_struct *work); +extern void __unionfs_symlink(struct work_struct *work); +extern void __unionfs_unlink(struct work_struct *work); +extern void __delete_whiteouts(struct work_struct *work); +extern void __is_opaque_dir(struct work_struct *work); + +#endif /* _SIOQ_H */ + --- linux-2.6.27.orig/ubuntu/unionfs/sioq.c +++ linux-2.6.27/ubuntu/unionfs/sioq.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2004-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ + +#include "unionfs.h" + +struct workqueue_struct *sioq; + +int __init init_sioq(void) +{ + int err; + + sioq = create_workqueue("unionfs_siod"); + if (!IS_ERR(sioq)) + return 0; + + err = PTR_ERR(sioq); + printk(KERN_ERR "create_workqueue failed %d\n", err); + sioq = NULL; + return err; +} + +void fin_sioq(void) +{ + if (sioq) + destroy_workqueue(sioq); +} + +void run_sioq(work_func_t func, struct sioq_args *args) +{ + INIT_WORK(&args->wk, func); + + init_completion(&args->comp); + while (!queue_work(sioq, &args->wk)) { + // TODO: do accounting if needed + schedule(); + } + wait_for_completion(&args->comp); +} + +void __unionfs_create(struct work_struct *work) +{ + struct sioq_args *args = container_of(work, struct sioq_args, wk); + struct create_args *c = &args->create; + args->err = vfs_create(c->parent, c->dentry, c->mode, c->nd); + complete(&args->comp); +} + +void __unionfs_mkdir(struct work_struct *work) +{ + struct sioq_args *args = container_of(work, struct sioq_args, wk); + struct mkdir_args *m = &args->mkdir; + args->err = vfs_mkdir(m->parent, m->dentry, NULL, m->mode); + complete(&args->comp); +} + +void __unionfs_mknod(struct work_struct *work) +{ + struct sioq_args *args = container_of(work, struct sioq_args, wk); + struct mknod_args *m = &args->mknod; + args->err = vfs_mknod(m->parent, m->dentry, NULL, m->mode, m->dev); + complete(&args->comp); +} +void __unionfs_symlink(struct work_struct *work) +{ + struct sioq_args *args = container_of(work, struct sioq_args, wk); + struct symlink_args *s = &args->symlink; + args->err = vfs_symlink(s->parent, s->dentry, NULL, s->symbuf); + complete(&args->comp); +} + +void __unionfs_unlink(struct work_struct *work) +{ + struct sioq_args *args = container_of(work, struct sioq_args, wk); + struct unlink_args *u = &args->unlink; + args->err = vfs_unlink(u->parent, u->dentry, NULL); + complete(&args->comp); +} + +void __delete_whiteouts(struct work_struct *work) { + struct sioq_args *args = container_of(work, struct sioq_args, wk); + struct deletewh_args *d = &args->deletewh; + args->err = delete_whiteouts(d->dentry, d->bindex, d->namelist); + complete(&args->comp); +} + +void __is_opaque_dir(struct work_struct *work) +{ + struct sioq_args *args = container_of(work, struct sioq_args, wk); + + args->ret = lookup_one_len(UNIONFS_DIR_OPAQUE, args->isopaque.dentry, + sizeof(UNIONFS_DIR_OPAQUE) - 1); + complete(&args->comp); +} --- linux-2.6.27.orig/ubuntu/unionfs/super.c +++ linux-2.6.27/ubuntu/unionfs/super.c @@ -0,0 +1,762 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: super.c,v 1.101 2006/11/04 22:27:51 jsipek Exp $ + */ + +#include "unionfs.h" + +/* The inode cache is used with alloc_inode for both our inode info and the + * vfs inode. */ +static struct kmem_cache *unionfs_inode_cachep; + +void unionfs_read_inode(struct inode *inode) +{ +#ifdef UNIONFS_MMAP + /* SP: use real address operations */ + extern struct address_space_operations unionfs_aops; +#else + static struct address_space_operations unionfs_empty_aops; +#endif + int size; + + print_entry_location(); + + if (!itopd(inode)) { + printk(KERN_ERR + "No kernel memory when allocating inode private data!\n"); + BUG(); + } + + memset(itopd(inode), 0, sizeof(struct unionfs_inode_info)); + itopd(inode)->b_start = -1; + itopd(inode)->b_end = -1; + atomic_set(&itopd(inode)->uii_generation, + atomic_read(&stopd(inode->i_sb)->usi_generation)); + itopd(inode)->uii_rdlock = SPIN_LOCK_UNLOCKED; + itopd(inode)->uii_rdcount = 1; + itopd(inode)->uii_hashsize = -1; + INIT_LIST_HEAD(&itopd(inode)->uii_readdircache); + + size = sbmax(inode->i_sb) * sizeof(struct inode *); + itohi_ptr(inode) = KZALLOC(size, GFP_KERNEL); + if (!itohi_ptr(inode)) { + printk(KERN_ERR + "No kernel memory when allocating lower-pointer array!\n"); + BUG(); + } + + inode->i_version++; + inode->i_op = &unionfs_main_iops; + inode->i_fop = &unionfs_main_fops; +#ifdef UNIONFS_MMAP + inode->i_mapping->a_ops = &unionfs_aops; +#else + /* I don't think ->a_ops is ever allowed to be NULL */ + inode->i_mapping->a_ops = &unionfs_empty_aops; + dprint(PRINT_DEBUG, "setting inode 0x%p a_ops to empty (0x%p)\n", + inode, inode->i_mapping->a_ops); +#endif + + print_exit_location(); +} + +#if 0 +static void unionfs_put_inode(struct inode *inode) +{ + print_entry_location(); + + dprint(PRINT_DEBUG, "%s i_count = %d, i_nlink = %d\n", __FUNCTION__, + atomic_read(&inode->i_count), inode->i_nlink); + + /* + * This is really funky stuff: + * Basically, if i_count == 1, iput will then decrement it and this + * inode will be destroyed. It is currently holding a reference to the + * hidden inode. Therefore, it needs to release that reference by + * calling iput on the hidden inode. iput() _will_ do it for us (by + * calling our clear_inode), but _only_ if i_nlink == 0. The problem + * is, NFS keeps i_nlink == 1 for silly_rename'd files. So we must for + * our i_nlink to 0 here to trick iput() into calling our clear_inode. + */ + + if (atomic_read(&inode->i_count) == 1) + inode->i_nlink = 0; + + print_exit_location(); +} +#endif + +/* + * we now define delete_inode, because there are two VFS paths that may + * destroy an inode: one of them calls clear inode before doing everything + * else that's needed, and the other is fine. This way we truncate the inode + * size (and its pages) and then clear our own inode, which will do an iput + * on our and the lower inode. + */ +static void unionfs_delete_inode(struct inode *inode) +{ + print_entry_location(); + + checkinode(inode, "unionfs_delete_inode IN"); + inode->i_size = 0; /* every f/s seems to do that */ + +#ifdef UNIONFS_MMAP + /* SP: if you try to clear_inode() when + * inode->i_data.nrpages != 0, you'll hit a BUG + * this is also what generic_delete_inode does */ + if (inode->i_data.nrpages) + truncate_inode_pages(&inode->i_data, 0); +#endif + clear_inode(inode); + + print_exit_location(); +} + +/* final actions when unmounting a file system */ +static void unionfs_put_super(struct super_block *sb) +{ + int bindex, bstart, bend; + struct unionfs_sb_info *spd; + + print_entry_location(); + + if ((spd = stopd(sb))) { +#ifdef UNIONFS_IMAP + /* XXX: Free persistent inode stuff. */ + cleanup_imap_data(sb); +#endif + bstart = sbstart(sb); + bend = sbend(sb); + for (bindex = bstart; bindex <= bend; bindex++) + mntput(stohiddenmnt_index(sb, bindex)); + + /* Make sure we have no leaks of branchget/branchput. */ + for (bindex = bstart; bindex <= bend; bindex++) + BUG_ON(branch_count(sb, bindex) != 0); + + KFREE(spd->usi_data); + KFREE(spd); + stopd_lhs(sb) = NULL; + } + dprint(PRINT_DEBUG, "unionfs: released super\n"); + + print_exit_location(); +} + +/* Since people use this to answer the "How big of a file can I write?" + * question, we report the size of the highest priority branch as the size of + * the union. + */ +static int unionfs_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + int err = 0; + struct super_block *sb, *hidden_sb; + + sb = dentry->d_sb; + + hidden_sb = stohs_index(sb, sbstart(sb)); + err = vfs_statfs(hidden_sb->s_root, buf); + + buf->f_type = UNIONFS_SUPER_MAGIC; + buf->f_namelen -= WHLEN; + + memset(&buf->f_fsid, 0, sizeof(__kernel_fsid_t)); + memset(&buf->f_spare, 0, sizeof(buf->f_spare)); + + return err; +} + +static int do_binary_remount(struct super_block *sb, int *flags, char *data) +{ + unsigned long *uldata = (unsigned long *)data; + int err; + + uldata++; + + switch (*uldata) { + case UNIONFS_IOCTL_DELBRANCH: + err = unionfs_ioctl_delbranch(sb, *(uldata + 1)); + break; + default: + err = -ENOTTY; + } + + return err; +} + +/* We don't support a standard text remount, but we do have a magic remount + * for unionctl. The idea is that you can remove a branch without opening + * the union. Eventually it would be nice to support a full-on remount, so + * that you can have all of the directories change at once, but that would + * require some pretty complicated matching code. */ +static int unionfs_remount_fs(struct super_block *sb, int *flags, char *data) +{ + if (data && *((unsigned long *)data) == UNIONFS_REMOUNT_MAGIC) + return do_binary_remount(sb, flags, data); + printk("Warning! dirs delete and imap options to remount are ignored\n"); + return 0; +} + +/* + * Called by iput() when the inode reference count reached zero + * and the inode is not hashed anywhere. Used to clear anything + * that needs to be, before the inode is completely destroyed and put + * on the inode free list. + */ +static void unionfs_clear_inode(struct inode *inode) +{ + int bindex, bstart, bend; + struct inode *hidden_inode; + struct list_head *pos, *n; + struct unionfs_dir_state *rdstate; + + print_entry_location(); + + checkinode(inode, "unionfs_clear_inode IN"); + + list_for_each_safe(pos, n, &itopd(inode)->uii_readdircache) { + rdstate = list_entry(pos, struct unionfs_dir_state, uds_cache); + list_del(&rdstate->uds_cache); + free_rdstate(rdstate); + } + + /* Decrement a reference to a hidden_inode, which was incremented + * by our read_inode when it was created initially. */ + bstart = ibstart(inode); + bend = ibend(inode); + if (bstart >= 0) { + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_inode = itohi_index(inode, bindex); + if (!hidden_inode) + continue; + IPUT(hidden_inode); + } + } + // XXX: why this assertion fails? + // because it doesn't like us + // BUG_ON((inode->i_state & I_DIRTY) != 0); + KFREE(itohi_ptr(inode)); + itohi_ptr(inode) = NULL; + + print_exit_location(); +} + +static struct inode *unionfs_alloc_inode(struct super_block *sb) +{ + struct unionfs_inode_container *c; + + print_entry_location(); + + c = (struct unionfs_inode_container *) + kmem_cache_alloc(unionfs_inode_cachep, GFP_KERNEL); + if (!c) { + print_exit_pointer(NULL); + return NULL; + } + + memset(&c->info, 0, sizeof(c->info)); + + c->vfs_inode.i_version = 1; + print_exit_pointer(&c->vfs_inode); + return &c->vfs_inode; +} + +static void unionfs_destroy_inode(struct inode *inode) +{ + print_entry("inode = %p", inode); + kmem_cache_free(unionfs_inode_cachep, itopd(inode)); + print_exit_location(); +} + +static void init_once(void *v) +{ + struct unionfs_inode_container *c = (struct unionfs_inode_container *)v; + + print_entry_location(); + + inode_init_once(&c->vfs_inode); + + print_exit_location(); +} + +int init_inode_cache(void) +{ + int err = 0; + + print_entry_location(); + + unionfs_inode_cachep = + kmem_cache_create("unionfs_inode_cache", + sizeof(struct unionfs_inode_container), 0, + SLAB_RECLAIM_ACCOUNT, init_once); + if (!unionfs_inode_cachep) + err = -ENOMEM; + print_exit_status(err); + return err; +} + +void destroy_inode_cache(void) +{ + print_entry_location(); + if (!unionfs_inode_cachep) + goto out; + kmem_cache_destroy(unionfs_inode_cachep); + out: + print_exit_location(); + return; +} + +/* Called when we have a dirty inode, right here we only throw out + * parts of our readdir list that are too old. + */ +static int unionfs_write_inode(struct inode *inode, int sync) +{ + struct list_head *pos, *n; + struct unionfs_dir_state *rdstate; + + print_entry_location(); + + spin_lock(&itopd(inode)->uii_rdlock); + list_for_each_safe(pos, n, &itopd(inode)->uii_readdircache) { + rdstate = list_entry(pos, struct unionfs_dir_state, uds_cache); + /* We keep this list in LRU order. */ + if ((rdstate->uds_access + RDCACHE_JIFFIES) > jiffies) + break; + itopd(inode)->uii_rdcount--; + list_del(&rdstate->uds_cache); + free_rdstate(rdstate); + } + spin_unlock(&itopd(inode)->uii_rdlock); + + print_exit_location(); + return 0; +} + +/* + * Used only in nfs, to kill any pending RPC tasks, so that subsequent + * code can actually succeed and won't leave tasks that need handling. + * + * PS. I wonder if this is somehow useful to undo damage that was + * left in the kernel after a user level file server (such as amd) + * dies. + */ +static void unionfs_umount_begin(struct super_block *sb) +{ + struct super_block *hidden_sb; + int bindex, bstart, bend; + + print_entry_location(); +#if 0 + if (!(flags & MNT_FORCE)) + /* we are not being MNT_FORCEd, therefore we should emulate old + * behaviour + */ + goto out; +#endif + bstart = sbstart(sb); + bend = sbend(sb); + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_sb = stohs_index(sb, bindex); + + if (hidden_sb && hidden_sb->s_op && + hidden_sb->s_op->umount_begin) + hidden_sb->s_op->umount_begin(hidden_sb); + } + + print_exit_location(); +} + +static int unionfs_show_options(struct seq_file *m, struct vfsmount *mnt) +{ + struct super_block *sb = mnt->mnt_sb; + int ret = 0; + unsigned long tmp = 0; + char *hidden_path; + int bindex, bstart, bend; + int perms; + + lock_dentry(sb->s_root); + + tmp = __get_free_page(GFP_KERNEL); + if (!tmp) { + ret = -ENOMEM; + goto out; + } + + bindex = bstart = sbstart(sb); + bend = sbend(sb); + + seq_printf(m, ",dirs="); + for (bindex = bstart; bindex <= bend; bindex++) { + struct path tp; + tp.dentry = dtohd_index(sb->s_root, bindex); + tp.mnt = stohiddenmnt_index(sb, bindex); + + hidden_path = + d_path(&tp, (char *)tmp, PAGE_SIZE); + perms = branchperms(sb, bindex); + seq_printf(m, "%s=%s", hidden_path, + perms & MAY_WRITE ? "rw" : + perms & MAY_NFSRO ? "nfsro" : "ro"); + if (bindex != bend) { + seq_printf(m, ":"); + } + } + + seq_printf(m, ",debug=%u", get_debug_mask()); + +#ifdef UNIONFS_DELETE_ALL + if (IS_SET(sb, DELETE_ALL)) + seq_printf(m, ",delete=all"); + else +#endif + seq_printf(m, ",delete=whiteout"); + out: + if (tmp) + free_page(tmp); + unlock_dentry(sb->s_root); + return ret; +} + +#ifdef CONFIG_EXPORTFS +/* + * export operations. + * unionfs cannot handle disconnected dentry, since it has no hidden dentries. + */ +/* un-tested 64 bit environment (pointer and inode number) */ + +#define is_anon(d) ((d)->d_flags & DCACHE_DISCONNECTED) +extern struct export_operations export_op_default; + +static void prepend_path(char **path, const char *name, int len) +{ + *path -= len; + memcpy(*path, name, len); + (*path)--; + **path = '/'; +} + +struct filldir_arg { + int found, called; + char *path; + ino_t ino, parent_ino; +}; + +static int filldir(void *arg, const char *name, int len, loff_t pos, ino_t ino, + unsigned int d_type) +{ + struct filldir_arg *a = arg; + + a->called++; + if (len == 2 && !strncmp(name, "..", 2)) { + a->parent_ino = ino; + a->found++; + } else if (ino == a->ino) { + if (len != 1 || *name != '.') + prepend_path(&a->path, name, len); + a->found++; + } + return (a->found == 2) ? 1 : 0; +} + +static struct dentry *get_hidden_parent(struct super_block *hidden_sb, + ino_t hidden_parent_ino) +{ + __u32 fh[2]; + + if (hidden_sb->s_root->d_inode->i_ino == hidden_parent_ino) + return DGET(hidden_sb->s_root); + + fh[0] = hidden_parent_ino; + fh[1] = 0; + return export_op_default.get_dentry(hidden_sb, fh); +} + +static struct dentry *do_get_dentry(struct super_block *sb, ino_t ino, + __u32 gen, struct dentry *hidden_root, + ino_t hidden_ino, ino_t hidden_parent_ino) +{ + struct dentry *dentry, *hidden_parent, *parent; + char *path, *p; + struct filldir_arg arg = { + .ino = hidden_ino, + .parent_ino = hidden_parent_ino + }; + int open_flags, err, bindex, bend, found; + struct file *hidden_file; + struct super_block *hidden_sb; + + print_entry("hr%p, hi%lu, hpi%lu", + hidden_root, hidden_ino, hidden_parent_ino); + + dentry = ERR_PTR(-ENOMEM); + path = __getname(); + if (!path) + goto out; + arg.path = path + PATH_MAX - 1; + *arg.path = 0; + + open_flags = O_RDONLY | O_DIRECTORY /* | O_NOATIME */ ; + if (force_o_largefile()) + open_flags |= O_LARGEFILE; + + dentry = ERR_PTR(-ESTALE); + unionfs_read_lock(sb); + lock_dentry(sb->s_root); + bend = dbend(sb->s_root); + found = -1; + for (bindex = 0; found == -1 && bindex <= bend; bindex++) + if (hidden_root == dtohd_index(sb->s_root, bindex)) + found = bindex; + unlock_dentry(sb->s_root); + if (found == -1) + goto out_unlock; + + bindex = found; + hidden_sb = stohs_index(sb, bindex); + while (1) { + hidden_parent = get_hidden_parent(hidden_sb, hidden_parent_ino); + dentry = hidden_parent; + if (IS_ERR(hidden_parent)) + goto out_unlock; + + branchget(sb, bindex); + hidden_file = DENTRY_OPEN(DGET(hidden_parent), NULL, + open_flags); + if (IS_ERR(hidden_file)) { + dentry = (void *)hidden_file; + DPUT(hidden_parent); + branchput(sb, bindex); + goto out_unlock; + } + + arg.found = 0; + while (arg.found != 2) { + arg.called = 0; + err = vfs_readdir(hidden_file, filldir, &arg); + if (!arg.called || err < 0) + break; + } + fput(hidden_file); + branchput(sb, bindex); + if (arg.found != 2) { + dentry = ERR_PTR(-ESTALE); + DPUT(hidden_parent); + goto out_unlock; + } + + DPUT(hidden_parent); + if (hidden_parent_ino == hidden_root->d_inode->i_ino) + break; + arg.ino = hidden_parent_ino; + hidden_parent_ino = arg.parent_ino; + } + BUG_ON(arg.path < path); + + parent = DGET(sb->s_root); + p = strchr(++arg.path, '/'); + while (p) { + mutex_lock(&parent->d_inode->i_mutex); + dentry = LOOKUP_ONE_LEN(arg.path, parent, p - arg.path); + mutex_unlock(&parent->d_inode->i_mutex); + DPUT(parent); + if (IS_ERR(dentry)) + goto out_unlock; + if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)) { + DPUT(dentry); + dentry = ERR_PTR(-ESTALE); + goto out_unlock; + } + parent = dentry; + arg.path = p + 1; + p = strchr(arg.path, '/'); + } + mutex_lock(&parent->d_inode->i_mutex); + dentry = LOOKUP_ONE_LEN(arg.path, parent, strlen(arg.path)); + mutex_unlock(&parent->d_inode->i_mutex); + DPUT(parent); + if (!IS_ERR(dentry) + && (!dentry->d_inode + || dentry->d_inode->i_ino != ino + || dentry->d_inode->i_generation != gen)) { + DPUT(dentry); + dentry = ERR_PTR(-ESTALE); + } + + out_unlock: + unionfs_read_unlock(sb); + __putname(path); + out: + print_exit_pointer(dentry); + return dentry; +} + +enum { + FhHead = 4, FhHRoot1 = FhHead, FhHRoot2, + FhHIno1, FhHIno2, FhHPIno1, FhHPIno2, + FhTail +}; + +static void do_decode(__u32 * fh, struct dentry **hidden_root, + ino_t * hidden_ino, ino_t * hidden_parent_ino) +{ + unsigned long root; + + root = fh[FhHRoot2]; + *hidden_ino = fh[FhHIno2]; + *hidden_parent_ino = fh[FhHPIno2]; +#if BITS_PER_LONG == 64 + root |= ((unsigned long)fh[FhHRoot1]) << 32; + *hidden_ino |= ((unsigned long) fh[FhHIno1]) << 32; + *hidden_parent_ino |= ((unsigned long) fh[FhHPIno1]) << 32; +#elif BITS_PER_LONG == 32 + /* ok */ +#else +#error unknown size +#endif + + *hidden_root = (struct dentry*) root; +} + +static int unionfs_encode_fh(struct dentry *dentry, __u32 * fh, int *max_len, + int connectable) +{ + int type, len, bindex; + struct super_block *sb; + struct dentry *h_root; + ino_t h_ino, hp_ino; + static int warn; + + print_entry("dentry %p", dentry); + BUG_ON(is_anon(dentry) || !dentry->d_inode + || is_anon(dentry->d_parent)); + +#ifdef UNIONFS_IMAP + if (!warn && stopd(dentry->d_sb)->usi_persistent) + warn++; +#endif + if (!warn) { + printk(KERN_WARNING "Exporting Unionfs without imap" + " option may stop your NFS server or client"); + warn++; + } + + sb = dentry->d_sb; + unionfs_read_lock(sb); + lock_dentry(dentry); + + len = *max_len; + type = export_op_default.encode_fh(dentry, fh, max_len, connectable); + if (type == 255 || *max_len > FhHead || len < FhTail) { + type = 255; + goto out; + } + + *max_len = FhTail; + bindex = dbstart(dentry); + lock_dentry(sb->s_root); + h_root = dtohd_index(sb->s_root, bindex); + unlock_dentry(sb->s_root); + h_ino = itohi_index(dentry->d_inode, bindex)->i_ino; + hp_ino = parent_ino(dtohd(dentry)); + fh[FhHRoot2] = (unsigned long) h_root; + fh[FhHIno2] = h_ino; + fh[FhHPIno2] = hp_ino; +#if BITS_PER_LONG == 64 + fh[FhHRoot1] = ((unsigned long) h_root) >> 32; + fh[FhHIno1] = h_ino >> 32; + fh[FhHPIno1] = hp_ino >> 32; +#endif + + out: + unionfs_print(PRINT_MAIN_EXIT, "%d, fh{i%u, g%d, hr%x, hi%u, hpi%u}\n", + type, fh[0], fh[1], fh[FhHRoot2], fh[FhHIno2], + fh[FhHPIno2]); + unlock_dentry(dentry); + unionfs_read_unlock(sb); + return type; +} + +static struct dentry *unionfs_decode_fh(struct super_block *sb, __u32 * fh, + int fh_len, int fh_type, + int (*acceptable) (void *context, + struct dentry * de), + void *context) +{ + struct dentry *dentry, *hidden_root; + ino_t hidden_ino, hidden_parent_ino; + + print_entry("%d, fh{i%u, g%d, hr%x, hi%u, hpi%u}", + fh_type, fh[0], fh[1], fh[FhHRoot2], fh[FhHIno2], + fh[FhHPIno2]); + + dentry = export_op_default.get_dentry(sb, fh); + if (!dentry || IS_ERR(dentry) || (dentry->d_inode && !is_anon(dentry))) + return dentry; + + d_drop(dentry); + DPUT(dentry); + do_decode(fh, &hidden_root, &hidden_ino, &hidden_parent_ino); + dentry = do_get_dentry(sb, fh[0], fh[1], hidden_root, hidden_ino, + hidden_parent_ino); + if (!IS_ERR(dentry)) { + if (acceptable(context, dentry)) + return dentry; /* success */ + DPUT(dentry); + dentry = NULL; + } + return dentry; +} + +struct export_operations unionfs_export_ops = { + .decode_fh = unionfs_decode_fh, + .encode_fh = unionfs_encode_fh +}; +#endif + +struct super_operations unionfs_sops = { + //.put_inode = unionfs_put_inode, + .delete_inode = unionfs_delete_inode, + .put_super = unionfs_put_super, + .statfs = unionfs_statfs, + .remount_fs = unionfs_remount_fs, + .clear_inode = unionfs_clear_inode, + .umount_begin = unionfs_umount_begin, + .show_options = unionfs_show_options, + .write_inode = unionfs_write_inode, + .alloc_inode = unionfs_alloc_inode, + .destroy_inode = unionfs_destroy_inode, +}; + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/branchman.c +++ linux-2.6.27/ubuntu/unionfs/branchman.c @@ -0,0 +1,579 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: branchman.c,v 1.66 2006/10/31 00:05:22 yiannos Exp $ + */ + +#include "unionfs.h" + +struct dentry **alloc_new_dentries(int objs) +{ + if (!objs) + return NULL; + + return KZALLOC(sizeof(struct dentry *) * objs, GFP_KERNEL); +} + +struct unionfs_usi_data *alloc_new_data(int objs) +{ + if (!objs) + return NULL; + + return KZALLOC(sizeof(struct unionfs_usi_data) * objs, GFP_KERNEL); +} + +static void fixputmaps(struct super_block *sb) +{ + struct unionfs_sb_info *spd; + struct putmap *cur; + int gen; + int i; + + print_entry_location(); + + spd = stopd(sb); + cur = spd->usi_putmaps[spd->usi_lastputmap - spd->usi_firstputmap]; + + for (gen = 0; gen < spd->usi_lastputmap - spd->usi_firstputmap; gen++) { + if (!spd->usi_putmaps[gen]) + continue; + for (i = 0; i <= spd->usi_putmaps[gen]->bend; i++) + spd->usi_putmaps[gen]->map[i] = + cur->map[spd->usi_putmaps[gen]->map[i]]; + } + + print_exit_location(); +} + +static int newputmap(struct super_block *sb) +{ + struct unionfs_sb_info *spd; + struct putmap *newmap; + int count = 0; + int i; + + print_entry_location(); + + spd = stopd(sb); + + i = sizeof(int) * (sbend(sb) + 1); + newmap = KMALLOC(sizeof(struct putmap) + i, GFP_KERNEL); + if (!newmap) { + print_exit_status(-ENOMEM); + return -ENOMEM; + } + + if (!spd->usi_firstputmap) { + spd->usi_firstputmap = 1; + spd->usi_lastputmap = 1; + + spd->usi_putmaps = KMALLOC(sizeof(struct putmap *), GFP_KERNEL); + if (!spd->usi_putmaps) { + KFREE(newmap); + print_exit_status(-ENOMEM); + return -ENOMEM; + } + } else { + struct putmap **newlist; + int newfirst = spd->usi_firstputmap; + + while (!spd->usi_putmaps[newfirst - spd->usi_firstputmap] && + newfirst <= spd->usi_lastputmap) { + newfirst++; + } + + newlist = + KMALLOC(sizeof(struct putmap *) * + (1 + spd->usi_lastputmap - newfirst), GFP_KERNEL); + if (!newlist) { + KFREE(newmap); + print_exit_status(-ENOMEM); + return -ENOMEM; + } + + for (i = newfirst; i <= spd->usi_lastputmap; i++) { + newlist[i - newfirst] = + spd->usi_putmaps[i - spd->usi_firstputmap]; + } + + KFREE(spd->usi_putmaps); + spd->usi_putmaps = newlist; + spd->usi_firstputmap = newfirst; + spd->usi_lastputmap++; + } + + newmap->bend = sbend(sb); + for (i = 0; i <= sbend(sb); i++) { + count += branch_count(sb, i); + newmap->map[i] = i; + } + for (i = spd->usi_firstputmap; i < spd->usi_lastputmap; i++) { + struct putmap *cur; + cur = spd->usi_putmaps[i - spd->usi_firstputmap]; + if (!cur) + continue; + count -= atomic_read(&cur->count); + } + atomic_set(&newmap->count, count); + spd->usi_putmaps[spd->usi_lastputmap - spd->usi_firstputmap] = newmap; + + print_exit_status(0); + return 0; +} + +/* XXX: this function needs to go. There is no reason for this to be here */ +int unionfs_ioctl_branchcount(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int err = 0; + int bstart, bend; + int i; + struct super_block *sb = file->f_dentry->d_sb; + + print_entry_location(); + + bstart = sbstart(sb); + bend = sbend(sb); + + err = bend + 1; + if (!arg) + goto out; + + for (i = bstart; i <= bend; i++) { + if (put_user(branch_count(sb, i), ((int __user *)arg) + i)) { + err = -EFAULT; + goto out; + } + } + + out: + print_exit_status(err); + return err; +} + +int unionfs_ioctl_incgen(struct file *file, unsigned int cmd, unsigned long arg) +{ + int err = 0; + struct super_block *sb; + + print_entry_location(); + + sb = file->f_dentry->d_sb; + + unionfs_write_lock(sb); + if ((err = newputmap(sb))) + goto out; + + atomic_inc(&stopd(sb)->usi_generation); + err = atomic_read(&stopd(sb)->usi_generation); + + atomic_set(&dtopd(sb->s_root)->udi_generation, err); + atomic_set(&itopd(sb->s_root->d_inode)->uii_generation, err); + + out: + unionfs_write_unlock(sb); + print_exit_status(err); + return err; +} + +int unionfs_ioctl_addbranch(struct inode *inode, unsigned int cmd, + unsigned long arg) +{ + int err; + struct unionfs_addbranch_args *addargs = NULL; + struct nameidata nd; + char *path = NULL; + int gen; + int i; + + int pobjects; + + struct unionfs_usi_data *new_data = NULL; + struct dentry **new_udi_dentry = NULL; + struct inode **new_uii_inode = NULL; + + struct dentry *root = NULL; + struct dentry *hidden_root = NULL; + + print_entry_location(); + +#ifdef UNIONFS_IMAP + if (stopd(sb)->usi_persistent) { + printk(KERN_ERR "Cannot manipulate branches if imap is used\n"); + err = -EPERM; + goto out; + } +#endif + + err = -ENOMEM; + addargs = KMALLOC(sizeof(struct unionfs_addbranch_args), GFP_KERNEL); + if (!addargs) + goto out; + + err = -EFAULT; + if (copy_from_user + (addargs, (const void __user *)arg, + sizeof(struct unionfs_addbranch_args))) + goto out; + + err = -EINVAL; + if (addargs->ab_perms & ~(MAY_READ | MAY_WRITE | MAY_NFSRO)) + goto out; + if (!(addargs->ab_perms & MAY_READ)) + goto out; + + err = -E2BIG; + if (sbend(inode->i_sb) > FD_SETSIZE) + goto out; + + err = -ENOMEM; + if (!(path = getname((const char __user *)addargs->ab_path))) + goto out; + + err = path_lookup(path, LOOKUP_FOLLOW, &nd); + + RECORD_PATH_LOOKUP(&nd); + if (err) + goto out; + if ((err = check_branch(&nd))) { + path_put(&nd.path); + RECORD_PATH_RELEASE(&nd); + goto out; + } + + unionfs_write_lock(inode->i_sb); + lock_dentry(inode->i_sb->s_root); + + root = inode->i_sb->s_root; + for (i = dbstart(inode->i_sb->s_root); i <= dbend(inode->i_sb->s_root); + i++) { + hidden_root = dtohd_index(root, i); + if (is_branch_overlap(hidden_root, nd.path.dentry)) { + err = -EINVAL; + goto out; + } + } + + err = -EINVAL; + if (addargs->ab_branch < 0 + || (addargs->ab_branch > (sbend(inode->i_sb) + 1))) + goto out; + + if ((err = newputmap(inode->i_sb))) + goto out; + + stopd(inode->i_sb)->b_end++; + dtopd(inode->i_sb->s_root)->udi_bcount++; + set_dbend(inode->i_sb->s_root, dbend(inode->i_sb->s_root) + 1); + itopd(inode->i_sb->s_root->d_inode)->b_end++; + + atomic_inc(&stopd(inode->i_sb)->usi_generation); + gen = atomic_read(&stopd(inode->i_sb)->usi_generation); + + pobjects = sbend(inode->i_sb) + 1; + + /* Reallocate the dynamic structures. */ + new_data = alloc_new_data(pobjects); + new_udi_dentry = alloc_new_dentries(pobjects); + new_uii_inode = KZALLOC(sizeof(struct inode *) * pobjects, GFP_KERNEL); + + if (!new_udi_dentry || !new_uii_inode || !new_data) { + err = -ENOMEM; + goto out; + } + + /* Copy the in-place values to our new structure. */ + for (i = 0; i < addargs->ab_branch; i++) { + atomic_set(&(new_data[i].sbcount), + branch_count(inode->i_sb, i)); + + new_data[i].branchperms = branchperms(inode->i_sb, i); + new_data[i].hidden_mnt = stohiddenmnt_index(inode->i_sb, i); + new_data[i].sb = stohs_index(inode->i_sb, i); + + new_udi_dentry[i] = dtohd_index(inode->i_sb->s_root, i); + new_uii_inode[i] = itohi_index(inode->i_sb->s_root->d_inode, i); + } + + /* Shift the ends to the right (only handle reallocated bits). */ + for (i = sbend(inode->i_sb) - 1; i >= (int)addargs->ab_branch; i--) { + int j = i + 1; + int pmindex; + + atomic_set(&new_data[j].sbcount, branch_count(inode->i_sb, i)); + + new_data[j].branchperms = branchperms(inode->i_sb, i); + new_data[j].hidden_mnt = stohiddenmnt_index(inode->i_sb, i); + new_data[j].sb = stohs_index(inode->i_sb, i); + new_udi_dentry[j] = dtohd_index(inode->i_sb->s_root, i); + new_uii_inode[j] = itohi_index(inode->i_sb->s_root->d_inode, i); + + /* Update the newest putmap, so it is correct for later. */ + pmindex = stopd(inode->i_sb)->usi_lastputmap; + pmindex -= stopd(inode->i_sb)->usi_firstputmap; + stopd(inode->i_sb)->usi_putmaps[pmindex]->map[i] = j; + + } + + /* Now we can free the old ones. */ + KFREE(dtopd(inode->i_sb->s_root)->udi_dentry); + KFREE(itopd(inode->i_sb->s_root->d_inode)->uii_inode); + KFREE(stopd(inode->i_sb)->usi_data); + + /* Update the real pointers. */ + dtohd_ptr(inode->i_sb->s_root) = new_udi_dentry; + itohi_ptr(inode->i_sb->s_root->d_inode) = new_uii_inode; + stopd(inode->i_sb)->usi_data = new_data; + + /* Re-NULL the new ones so we don't try to free them. */ + new_data = NULL; + new_udi_dentry = NULL; + new_uii_inode = NULL; + + /* Put the new dentry information into it's slot. */ + set_dtohd_index(inode->i_sb->s_root, addargs->ab_branch, nd.path.dentry); + set_itohi_index(inode->i_sb->s_root->d_inode, addargs->ab_branch, + IGRAB(nd.path.dentry->d_inode)); + set_branchperms(inode->i_sb, addargs->ab_branch, addargs->ab_perms); + set_branch_count(inode->i_sb, addargs->ab_branch, 0); + set_stohiddenmnt_index(inode->i_sb, addargs->ab_branch, nd.path.mnt); + set_stohs_index(inode->i_sb, addargs->ab_branch, nd.path.dentry->d_sb); + + atomic_set(&dtopd(inode->i_sb->s_root)->udi_generation, gen); + atomic_set(&itopd(inode->i_sb->s_root->d_inode)->uii_generation, gen); + + fixputmaps(inode->i_sb); + + out: + unlock_dentry(inode->i_sb->s_root); + unionfs_write_unlock(inode->i_sb); + + KFREE(new_udi_dentry); + KFREE(new_uii_inode); + KFREE(new_data); + KFREE(addargs); + if (path) + putname(path); + + print_exit_status(err); + + return err; +} + +/* This must be called with the super block already locked. */ +int unionfs_ioctl_delbranch(struct super_block *sb, unsigned long arg) +{ + struct dentry *hidden_dentry; + struct inode *hidden_inode; + struct vfsmount *hidden_mnt; + struct dentry *root_dentry; + struct inode *root_inode; + int err = 0; + int pmindex, i, gen; + + print_entry("branch = %lu ", arg); + lock_dentry(sb->s_root); + +#ifdef UNIONFS_IMAP + if (stopd(sb)->usi_persistent) { + printk(KERN_ERR "Cannot manipulate branches if imap is used\n"); + err = -EPERM; + goto out; + } +#endif + err = -EBUSY; + if (sbmax(sb) == 1) + goto out; + err = -EINVAL; + if (arg < 0 || arg > stopd(sb)->b_end) + goto out; + err = -EBUSY; + if (branch_count(sb, arg)) + goto out; + if ((err = newputmap(sb))) + goto out; + + pmindex = stopd(sb)->usi_lastputmap; + pmindex -= stopd(sb)->usi_firstputmap; + + atomic_inc(&stopd(sb)->usi_generation); + gen = atomic_read(&stopd(sb)->usi_generation); + + root_dentry = sb->s_root; + root_inode = sb->s_root->d_inode; + + hidden_dentry = dtohd_index(root_dentry, arg); + hidden_mnt = stohiddenmnt_index(sb, arg); + hidden_inode = itohi_index(root_inode, arg); + + DPUT(hidden_dentry); + IPUT(hidden_inode); + mntput(hidden_mnt); + + for (i = arg; i <= (sbend(sb) - 1); i++) { + set_branch_count(sb, i, branch_count(sb, i + 1)); + set_stohiddenmnt_index(sb, i, stohiddenmnt_index(sb, i + 1)); + set_stohs_index(sb, i, stohs_index(sb, i + 1)); + set_branchperms(sb, i, branchperms(sb, i + 1)); + set_dtohd_index(root_dentry, i, + dtohd_index(root_dentry, i + 1)); + set_itohi_index(root_inode, i, itohi_index(root_inode, i + 1)); + stopd(sb)->usi_putmaps[pmindex]->map[i + 1] = i; + } + + set_dtohd_index(root_dentry, sbend(sb), NULL); + set_itohi_index(root_inode, sbend(sb), NULL); + set_stohiddenmnt_index(sb, sbend(sb), NULL); + set_stohs_index(sb, sbend(sb), NULL); + + //XXX: Place check for inode maps and removal of branch here + + stopd(sb)->b_end--; + set_dbend(root_dentry, dbend(root_dentry) - 1); + dtopd(root_dentry)->udi_bcount--; + itopd(root_inode)->b_end--; + + atomic_set(&dtopd(root_dentry)->udi_generation, gen); + atomic_set(&itopd(root_inode)->uii_generation, gen); + + fixputmaps(sb); + + /* This doesn't open a file, so we might have to free the map here. */ + if (atomic_read(&stopd(sb)->usi_putmaps[pmindex]->count) == 0) { + KFREE(stopd(sb)->usi_putmaps[pmindex]); + stopd(sb)->usi_putmaps[pmindex] = NULL; + } + + out: + unlock_dentry(sb->s_root); + print_exit_status(err); + + return err; +} + +int unionfs_ioctl_rdwrbranch(struct inode *inode, unsigned int cmd, + unsigned long arg) +{ + int err; + struct unionfs_rdwrbranch_args *rdwrargs = NULL; + int gen; + + print_entry_location(); + + unionfs_write_lock(inode->i_sb); + lock_dentry(inode->i_sb->s_root); + + if ((err = newputmap(inode->i_sb))) + goto out; + + err = -ENOMEM; + rdwrargs = KMALLOC(sizeof(struct unionfs_rdwrbranch_args), GFP_KERNEL); + if (!rdwrargs) + goto out; + + err = -EFAULT; + if (copy_from_user + (rdwrargs, (const void __user *)arg, + sizeof(struct unionfs_rdwrbranch_args))) + goto out; + + err = -EINVAL; + if (rdwrargs->rwb_branch < 0 + || (rdwrargs->rwb_branch > (sbend(inode->i_sb) + 1))) + goto out; + if (rdwrargs->rwb_perms & ~(MAY_READ | MAY_WRITE | MAY_NFSRO)) + goto out; + if (!(rdwrargs->rwb_perms & MAY_READ)) + goto out; + + set_branchperms(inode->i_sb, rdwrargs->rwb_branch, rdwrargs->rwb_perms); + + atomic_inc(&stopd(inode->i_sb)->usi_generation); + gen = atomic_read(&stopd(inode->i_sb)->usi_generation); + atomic_set(&dtopd(inode->i_sb->s_root)->udi_generation, gen); + atomic_set(&itopd(inode->i_sb->s_root->d_inode)->uii_generation, gen); + + err = 0; + + out: + unlock_dentry(inode->i_sb->s_root); + unionfs_write_unlock(inode->i_sb); + KFREE(rdwrargs); + + print_exit_status(err); + + return err; +} + +int unionfs_ioctl_queryfile(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int err = 0; + fd_set branchlist; + + int bstart = 0, bend = 0, bindex = 0; + struct dentry *dentry, *hidden_dentry; + + print_entry_location(); + + dentry = file->f_dentry; + lock_dentry(dentry); + if ((err = unionfs_partial_lookup(dentry))) + goto out; + bstart = dbstart(dentry); + bend = dbend(dentry); + + FD_ZERO(&branchlist); + + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + continue; + if (hidden_dentry->d_inode) + FD_SET(bindex, &branchlist); + } + + err = copy_to_user((void __user *)arg, &branchlist, sizeof(fd_set)); + if (err) { + err = -EFAULT; + goto out; + } + + out: + unlock_dentry(dentry); + err = err < 0 ? err : bend; + print_exit_status(err); + return (err); +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/BOM +++ linux-2.6.27/ubuntu/unionfs/BOM @@ -0,0 +1,7 @@ +Downloaded from: http://www.filesystems.org/project-unionfs.html +Current Version: 1.4 + +Don't bother updating this code. No, we do not want 2.3.x. Yes, this is +heavily patched to account for upstream VFS API changes and AppArmor. + +DO NOT TOUCH :) --- linux-2.6.27.orig/ubuntu/unionfs/main.c +++ linux-2.6.27/ubuntu/unionfs/main.c @@ -0,0 +1,869 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: main.c,v 1.176 2006/10/10 07:28:13 jsipek Exp $ + */ + +#include "unionfs.h" +#include +#include + +/* declarations added for "sparse" */ +extern void unionfs_kill_block_super(struct super_block *sb); + +/* declarations added for malloc_debugging */ + +#ifdef FIST_MALLOC_DEBUG +extern atomic_t unionfs_malloc_counter; +extern atomic_t unionfs_mallocs_outstanding; +#endif + +extern void unionfs_read_inode(struct inode *inode); + +static struct inode *unionfs_iget(struct super_block *sb, ino_t ino) +{ + struct inode *inode; + + inode = iget_locked(sb, ino); + if (!inode) + return ERR_PTR(-ENOMEM); + if (inode->i_state & I_NEW) { + unionfs_read_inode(inode); + unlock_new_inode(inode); + } + return inode; +} + +/* sb we pass is unionfs's super_block */ +int unionfs_interpose(struct dentry *dentry, struct super_block *sb, int flag) +{ + struct inode *hidden_inode; + struct dentry *hidden_dentry; + int err = 0; + struct inode *inode; + int is_negative_dentry = 1; + int bindex, bstart, bend; + + print_entry("flag = %d", flag); + + verify_locked(dentry); + + print_dentry("In unionfs_interpose", dentry); + + bstart = dbstart(dentry); + bend = dbend(dentry); + + /* Make sure that we didn't get a negative dentry. */ + for (bindex = bstart; bindex <= bend; bindex++) { + if (dtohd_index(dentry, bindex) && + dtohd_index(dentry, bindex)->d_inode) { + is_negative_dentry = 0; + break; + } + } + BUG_ON(is_negative_dentry); + + /* We allocate our new inode below, by calling iget. + * iget will call our read_inode which will initialize some + * of the new inode's fields + */ + + /* On revalidate we've already got our own inode and just need + * to fix it up. */ + if (flag == INTERPOSE_REVAL) { + inode = dentry->d_inode; + itopd(inode)->b_start = -1; + itopd(inode)->b_end = -1; + atomic_set(&itopd(inode)->uii_generation, + atomic_read(&stopd(sb)->usi_generation)); + + itohi_ptr(inode) = + KZALLOC(sbmax(sb) * sizeof(struct inode *), GFP_KERNEL); + if (!itohi_ptr(inode)) { + err = -ENOMEM; + goto out; + } + mutex_lock(&inode->i_mutex); + } else { + ino_t ino; + /* get unique inode number for unionfs */ +#ifdef UNIONFS_IMAP + if (stopd(sb)->usi_persistent) { + err = read_uin(sb, bindex, + dtohd_index(dentry, + bindex)->d_inode->i_ino, + O_CREAT, &ino); + if (err) + goto out; + } else +#endif + ino = iunique(sb, UNIONFS_ROOT_INO); + + inode = unionfs_iget(sb, ino); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + + mutex_lock(&inode->i_mutex); + if (atomic_read(&inode->i_count) > 1) + goto skip; + } + + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) { + set_itohi_index(inode, bindex, NULL); + continue; + } + /* Initialize the hidden inode to the new hidden inode. */ + if (!hidden_dentry->d_inode) + continue; + set_itohi_index(inode, bindex, IGRAB(hidden_dentry->d_inode)); + } + + ibstart(inode) = dbstart(dentry); + ibend(inode) = dbend(dentry); + + /* Use attributes from the first branch. */ + hidden_inode = itohi(inode); + + /* Use different set of inode ops for symlinks & directories */ + if (S_ISLNK(hidden_inode->i_mode)) + inode->i_op = &unionfs_symlink_iops; + else if (S_ISDIR(hidden_inode->i_mode)) + inode->i_op = &unionfs_dir_iops; + + /* Use different set of file ops for directories */ + if (S_ISDIR(hidden_inode->i_mode)) + inode->i_fop = &unionfs_dir_fops; + + /* properly initialize special inodes */ + if (S_ISBLK(hidden_inode->i_mode) || S_ISCHR(hidden_inode->i_mode) || + S_ISFIFO(hidden_inode->i_mode) || S_ISSOCK(hidden_inode->i_mode)) + init_special_inode(inode, hidden_inode->i_mode, + hidden_inode->i_rdev); +#ifndef UNIONFS_MMAP + /* Fix our inode's address operations to that of the lower inode (Unionfs is FiST-Lite) */ + if (inode->i_mapping->a_ops != hidden_inode->i_mapping->a_ops) { + dprint(PRINT_DEBUG, "fixing inode 0x%p a_ops (0x%p -> 0x%p)\n", + inode, inode->i_mapping->a_ops, + hidden_inode->i_mapping->a_ops); + inode->i_mapping->a_ops = hidden_inode->i_mapping->a_ops; + } +#endif + /* all well, copy inode attributes */ + fist_copy_attr_all(inode, hidden_inode); + + skip: + /* only (our) lookup wants to do a d_add */ + switch (flag) { + case INTERPOSE_DEFAULT: + case INTERPOSE_REVAL_NEG: + d_instantiate(dentry, inode); + break; + case INTERPOSE_LOOKUP: + err = PTR_ERR(d_splice_alias(inode, dentry)); + break; + case INTERPOSE_REVAL: + /* Do nothing. */ + break; + default: + printk(KERN_ERR "Invalid interpose flag passed!"); + BUG(); + } + + print_dentry("Leaving unionfs_interpose", dentry); + print_inode("Leaving unionfs_interpose", inode); + mutex_unlock(&inode->i_mutex); + + out: + print_exit_status(err); + return err; +} + +void unionfs_reinterpose(struct dentry *dentry) +{ + struct dentry *hidden_dentry; + struct inode *inode; + int bindex, bstart, bend; + + print_entry_location(); + verify_locked(dentry); + print_dentry("IN: unionfs_reinterpose: ", dentry); + + /* This is pre-allocated inode */ + inode = dentry->d_inode; + + bstart = dbstart(dentry); + bend = dbend(dentry); + for (bindex = bstart; bindex <= bend; bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + continue; + + if (!hidden_dentry->d_inode) + continue; + if (itohi_index(inode, bindex)) + continue; + set_itohi_index(inode, bindex, IGRAB(hidden_dentry->d_inode)); + } + ibstart(inode) = dbstart(dentry); + ibend(inode) = dbend(dentry); + + print_dentry("OUT: unionfs_reinterpose: ", dentry); + print_inode("OUT: unionfs_reinterpose: ", inode); + + print_exit_location(); +} + +int check_branch(struct nameidata *nd) +{ + if (!strcmp(nd->path.dentry->d_sb->s_type->name, "unionfs")) + return -EINVAL; + if (!nd->path.dentry->d_inode) + return -ENOENT; + if (!S_ISDIR(nd->path.dentry->d_inode->i_mode)) + return -ENOTDIR; + return 0; +} + +/* checks if two hidden_dentries have overlapping branches */ +int is_branch_overlap(struct dentry *dent1, struct dentry *dent2) +{ + struct dentry *dent = NULL; + + dent = dent1; + while ((dent != dent2) && (dent->d_parent != dent)) { + dent = dent->d_parent; + } + if (dent == dent2) { + return 1; + } + + dent = dent2; + while ((dent != dent1) && (dent->d_parent != dent)) { + dent = dent->d_parent; + } + if (dent == dent1) { + return 1; + } + + return 0; +} +static int parse_branch_mode(char *name) +{ + int perms; + int l = strlen(name); + if (!strcmp(name + l - 3, "=ro")) { + perms = MAY_READ; + name[l - 3] = '\0'; + } else if (!strcmp(name + l - 6, "=nfsro")) { + perms = MAY_READ | MAY_NFSRO; + name[l - 6] = '\0'; + } else if (!strcmp(name + l - 3, "=rw")) { + perms = MAY_READ | MAY_WRITE; + name[l - 3] = '\0'; + } else { + perms = MAY_READ | MAY_WRITE; + } + + return perms; +} +static int get_separator_count(char *options, char *separator) +{ + char *token, *locopts, *locsep = NULL; + int count = 0; + /* + * We copy options so we dont destroy our pointer for parsing + */ + if (separator == NULL) { + locsep = KMALLOC(2, GFP_KERNEL); + if (!locsep) { + count = -ENOMEM; + goto out; + } + strcpy(locsep, ":"); + } else { + locsep = separator; + } + locopts = KMALLOC(strlen(options) + 1, GFP_KERNEL); + if (!locopts) { + count = -ENOMEM; + goto out; + } + strcpy(locopts, options); + while ((token = strsep(&locopts, locsep)) != NULL) + count++; + out: + KFREE(locopts); + return count; +} +static int parse_dirs_option(struct super_block *sb, struct unionfs_dentry_info + *hidden_root_info, char *options, char *separator) +{ + struct nameidata nd; + char *name, *locsep = NULL; + int err = 0; + int branches = 1; + int bindex = 0; + int i = 0; + int j = 0; + + struct dentry *dent1 = NULL; + struct dentry *dent2 = NULL; + + if (options[0] == '\0') { + printk(KERN_WARNING "unionfs: no branches specified\n"); + err = -EINVAL; + goto out; + } + /* + * Check to see if separator is specified otherwise use ':' + */ + if (separator == NULL) { + locsep = KMALLOC(2, GFP_KERNEL); + if (!locsep) { + err = -ENOMEM; + goto out; + } + strcpy(locsep, ":"); + } else { + locsep = separator; + } + branches = get_separator_count(options, separator); + /* allocate space for underlying pointers to hidden dentry */ + if (!(stopd(sb)->usi_data = alloc_new_data(branches))) { + err = -ENOMEM; + goto out; + } + + if (!(hidden_root_info->udi_dentry = alloc_new_dentries(branches))) { + err = -ENOMEM; + goto out; + } + + /* now parsing the string b1:b2=rw:b3=ro:b4 */ + branches = 0; + while ((name = strsep(&options, locsep)) != NULL) { + int perms; + + if (!*name) + continue; + branches++; + + /* strip off =rw or =ro if it is specified. */ + perms = parse_branch_mode(name); + if (!bindex && !(perms & MAY_WRITE)) { + err = -EINVAL; + goto out; + } + + dprint(PRINT_DEBUG, "using directory: %s (%c%c%c)\n", + name, perms & MAY_READ ? 'r' : '-', + perms & MAY_WRITE ? 'w' : '-', + perms & MAY_NFSRO ? 'n' : '-'); + + err = path_lookup(name, LOOKUP_FOLLOW, &nd); + RECORD_PATH_LOOKUP(&nd); + if (err) { + printk(KERN_WARNING "unionfs: error accessing " + "hidden directory '%s' (error %d)\n", name, err); + goto out; + } + + if ((err = check_branch(&nd))) { + printk(KERN_WARNING "unionfs: hidden directory " + "'%s' is not a valid branch\n", name); + path_put(&nd.path); + RECORD_PATH_RELEASE(&nd); + goto out; + } + + hidden_root_info->udi_dentry[bindex] = nd.path.dentry; + + set_stohiddenmnt_index(sb, bindex, nd.path.mnt); + set_branchperms(sb, bindex, perms); + set_branch_count(sb, bindex, 0); + + if (hidden_root_info->udi_bstart < 0) + hidden_root_info->udi_bstart = bindex; + hidden_root_info->udi_bend = bindex; + bindex++; + } + + if (branches == 0) { + printk(KERN_WARNING "unionfs: no branches specified\n"); + err = -EINVAL; + goto out; + } + + BUG_ON(branches != (hidden_root_info->udi_bend + 1)); + + /* ensure that no overlaps exist in the branches */ + for (i = 0; i < branches; i++) { + for (j = i + 1; j < branches; j++) { + dent1 = hidden_root_info->udi_dentry[i]; + dent2 = hidden_root_info->udi_dentry[j]; + + if (is_branch_overlap(dent1, dent2)) { + goto out_overlap; + } + } + } + + out_overlap: + + if (i != branches) { + printk(KERN_WARNING "unionfs: branches %d and %d overlap\n", i, + j); + err = -EINVAL; + goto out; + } + + out: + if (err) { + for (i = 0; i < branches; i++) { + if (hidden_root_info->udi_dentry[i]) + DPUT(hidden_root_info->udi_dentry[i]); + } + + KFREE(hidden_root_info->udi_dentry); + KFREE(stopd(sb)->usi_data); + + /* MUST clear the pointers to prevent potential double free if + * the caller dies later on + */ + hidden_root_info->udi_dentry = NULL; + stopd(sb)->usi_data = NULL; + } + if (!separator) + KFREE(locsep); + return err; +} + +/* + * Parse mount options. See the manual page for usage instructions. + * + * Returns the dentry object of the lower-level (hidden) directory; + * We want to mount our stackable file system on top of that hidden directory. + * + * Sets default debugging level to N, if any. + */ +static struct unionfs_dentry_info *unionfs_parse_options(struct super_block *sb, + char *options) +{ + struct unionfs_dentry_info *hidden_root_info; + char *optname, *separator = NULL; + int err = 0; + int bindex; + int sepfound = 0; + int dirsfound = 0; +#ifdef UNIONFS_IMAP + int imapfound = 0; +#endif + print_entry_location(); + + /* allocate private data area */ + err = -ENOMEM; + hidden_root_info = + KZALLOC(sizeof(struct unionfs_dentry_info), GFP_KERNEL); + if (!hidden_root_info) + goto out_error; + hidden_root_info->udi_bstart = -1; + hidden_root_info->udi_bend = -1; + hidden_root_info->udi_bopaque = -1; + + while ((optname = strsep(&options, ",")) != NULL) { + char *optarg; + char *endptr; + int intval; + + if (!*optname) { + continue; + } + + optarg = strchr(optname, '='); + if (optarg) { + *optarg++ = '\0'; + } + + /* All of our options take an argument now. Insert ones that + * don't, above this check. */ + if (!optarg) { + printk("unionfs: %s requires an argument.\n", optname); + err = -EINVAL; + goto out_error; + } + + if (!strcmp("dirs", optname)) { + if (++dirsfound > 1) { + printk(KERN_WARNING + "unionfs: multiple dirs specified\n"); + err = -EINVAL; + goto out_error; + } + err = + parse_dirs_option(sb, hidden_root_info, optarg, + separator); + if (err) + goto out_error; + continue; + } +#ifdef UNIONFS_IMAP + if (!strcmp("imap", optname)) { + if (++imapfound > 1) { + printk(KERN_WARNING + "unionfs: multiple imap specified\n"); + err = -EINVAL; + goto out_error; + } + err = parse_imap_option(sb, hidden_root_info, optarg); + if (err) + goto out_error; + continue; + } +#endif + if (!strcmp("delete", optname)) { + if (!strcmp("whiteout", optarg)) { + /* default */ +#ifdef UNIONFS_DELETE_ALL + } else if (!strcmp("all", optarg)) { + MOUNT_FLAG(sb) |= DELETE_ALL; +#endif + } else { + printk(KERN_WARNING + "unionfs: invalid delete option '%s'\n", + optarg); + err = -EINVAL; + goto out_error; + } + continue; + } + + if (!strcmp("separator", optname)) { + if (dirsfound) { + printk(KERN_WARNING + "unionfs: dirs= already parsed separator '%s' will have no effect\n", + optarg); + continue; + } + sepfound = 1; + separator = KMALLOC(strlen(optarg) + 1, GFP_KERNEL); + if (!separator) { + err = -ENOMEM; + goto out_error; + } + strcpy(separator, optarg); + continue; + } + /* All of these options require an integer argument. */ + intval = simple_strtoul(optarg, &endptr, 0); + if (*endptr) { + printk(KERN_WARNING + "unionfs: invalid %s option '%s'\n", + optname, optarg); + err = -EINVAL; + goto out_error; + } + + if (!strcmp("debug", optname)) { + set_debug_mask(intval); + continue; + } + + err = -EINVAL; + printk(KERN_WARNING + "unionfs: unrecognized option '%s'\n", optname); + goto out_error; + } + if (dirsfound != 1) { + printk(KERN_WARNING "unionfs: dirs option required\n"); + err = -EINVAL; + goto out_error; + } + goto out; + + out_error: + if (hidden_root_info && hidden_root_info->udi_dentry) { + for (bindex = hidden_root_info->udi_bstart; + bindex >= 0 && bindex <= hidden_root_info->udi_bend; + bindex++) { + struct dentry *d; + d = hidden_root_info->udi_dentry[bindex]; + DPUT(d); + if (stohiddenmnt_index(sb, bindex)) + mntput(stohiddenmnt_index(sb, bindex)); + } + } + + KFREE(hidden_root_info->udi_dentry); + KFREE(hidden_root_info); + + KFREE(stopd(sb)->usi_data); + stopd(sb)->usi_data = NULL; + + hidden_root_info = ERR_PTR(err); + KFREE(separator); + out: + print_exit_location(); + return hidden_root_info; +} + +static struct dentry *unionfs_d_alloc_root(struct super_block *sb) +{ + struct dentry *ret = NULL; + + if (sb) { + static const struct qstr name = {.name = "/",.len = 1 }; + + ret = d_alloc(NULL, &name); + if (ret) { + ret->d_op = &unionfs_dops; + ret->d_sb = sb; + ret->d_parent = ret; + } + } + return ret; +} + +static int unionfs_read_super(struct super_block *sb, void *raw_data, + int silent) +{ + int err = 0; + + struct unionfs_dentry_info *hidden_root_info = NULL; + int bindex, bstart, bend; + unsigned long long maxbytes; + + print_entry_location(); + + if (!raw_data) { + printk(KERN_WARNING + "unionfs_read_super: missing data argument\n"); + err = -EINVAL; + goto out; + } + + /* + * Allocate superblock private data + */ + stopd_lhs(sb) = KZALLOC(sizeof(struct unionfs_sb_info), GFP_KERNEL); + if (!stopd(sb)) { + printk(KERN_WARNING "%s: out of memory\n", __FUNCTION__); + err = -ENOMEM; + goto out; + } + stopd(sb)->b_end = -1; + atomic_set(&stopd(sb)->usi_generation, 1); + init_rwsem(&stopd(sb)->usi_rwsem); + + hidden_root_info = unionfs_parse_options(sb, raw_data); + if (IS_ERR(hidden_root_info)) { + printk(KERN_WARNING + "unionfs_read_super: error while parsing options (err = %ld)\n", + PTR_ERR(hidden_root_info)); + err = PTR_ERR(hidden_root_info); + hidden_root_info = NULL; + goto out_free; + } + if (hidden_root_info->udi_bstart == -1) { + err = -ENOENT; + goto out_free; + } + + /* set the hidden superblock field of upper superblock */ + bstart = hidden_root_info->udi_bstart; + BUG_ON(bstart != 0); + sbend(sb) = bend = hidden_root_info->udi_bend; + for (bindex = bstart; bindex <= bend; bindex++) { + struct dentry *d; + + d = hidden_root_info->udi_dentry[bindex]; + + set_stohs_index(sb, bindex, d->d_sb); + } + + /* Unionfs: Max Bytes is the maximum bytes from among all the branches */ + maxbytes = -1; + for (bindex = bstart; bindex <= bend; bindex++) + if (maxbytes < stohs_index(sb, bindex)->s_maxbytes) + maxbytes = stohs_index(sb, bindex)->s_maxbytes; + sb->s_maxbytes = maxbytes; + + sb->s_op = &unionfs_sops; +#ifdef CONFIG_EXPORTFS + sb->s_export_op = &unionfs_export_ops; +#endif + + /* + * we can't use d_alloc_root if we want to use + * our own interpose function unchanged, + * so we simply call our own "fake" d_alloc_root + */ + sb->s_root = unionfs_d_alloc_root(sb); + if (!sb->s_root) { + err = -ENOMEM; + goto out_dput; + } + + /* link the upper and lower dentries */ + dtopd_lhs(sb->s_root) = NULL; + if ((err = new_dentry_private_data(sb->s_root))) + goto out_freedpd; + + /* Set the hidden dentries for s_root */ + for (bindex = bstart; bindex <= bend; bindex++) { + struct dentry *d; + + d = hidden_root_info->udi_dentry[bindex]; + + set_dtohd_index(sb->s_root, bindex, d); + } + set_dbstart(sb->s_root, bstart); + set_dbend(sb->s_root, bend); + + /* Set the generation number to one, since this is for the mount. */ + atomic_set(&dtopd(sb->s_root)->udi_generation, 1); + + /* call interpose to create the upper level inode */ + if ((err = unionfs_interpose(sb->s_root, sb, 0))) + goto out_freedpd; + unlock_dentry(sb->s_root); + goto out; + + out_freedpd: + if (dtopd(sb->s_root)) { + KFREE(dtohd_ptr(sb->s_root)); + free_dentry_private_data(dtopd(sb->s_root)); + } + DPUT(sb->s_root); + out_dput: + if (hidden_root_info && !IS_ERR(hidden_root_info)) { + for (bindex = hidden_root_info->udi_bstart; + bindex <= hidden_root_info->udi_bend; bindex++) { + struct dentry *d; + + d = hidden_root_info->udi_dentry[bindex]; + + if (d) + DPUT(d); + + if (stopd(sb) && stohiddenmnt_index(sb, bindex)) + mntput(stohiddenmnt_index(sb, bindex)); + } + KFREE(hidden_root_info->udi_dentry); + KFREE(hidden_root_info); + hidden_root_info = NULL; + } + out_free: + KFREE(stopd(sb)->usi_data); + KFREE(stopd(sb)); + stopd_lhs(sb) = NULL; + out: + if (hidden_root_info && !IS_ERR(hidden_root_info)) { + KFREE(hidden_root_info->udi_dentry); + KFREE(hidden_root_info); + } + print_exit_status(err); + return err; +} + +static int unionfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *raw_data, struct vfsmount *mnt) +{ + return get_sb_nodev(fs_type, flags, raw_data, unionfs_read_super, mnt); +} + +static struct file_system_type unionfs_fs_type = { + .owner = THIS_MODULE, + .name = "unionfs", + .get_sb = unionfs_get_sb, + .kill_sb = kill_anon_super, + .fs_flags = FS_REVAL_DOT, +}; + +static int init_debug = 0; +module_param_named(debug, init_debug, int, S_IRUGO); +MODULE_PARM_DESC(debug, "Initial Unionfs debug value."); + +static int __init init_unionfs_fs(void) +{ + int err; + printk("Registering unionfs " UNIONFS_VERSION "\n"); + + set_debug_mask(init_debug); + +#ifdef FIST_MALLOC_DEBUG + atomic_set(&unionfs_malloc_counter, 0); + atomic_set(&unionfs_mallocs_outstanding, 0); +#endif /* FIST_MALLOC_DEBUG */ + + if ((err = init_filldir_cache())) + goto out; + if ((err = init_inode_cache())) + goto out; + if ((err = init_dentry_cache())) + goto out; + if ((err = init_sioq())) + goto out; + err = register_filesystem(&unionfs_fs_type); + out: + if (err) { + fin_sioq(); + destroy_filldir_cache(); + destroy_inode_cache(); + destroy_dentry_cache(); + } + return err; +} +static void __exit exit_unionfs_fs(void) +{ + fin_sioq(); + destroy_filldir_cache(); + destroy_inode_cache(); + destroy_dentry_cache(); + unregister_filesystem(&unionfs_fs_type); + printk("Completed unionfs module unload.\n"); +} + +MODULE_AUTHOR + ("Filesystems and Storage Lab, Stony Brook University (http://www.fsl.cs.sunysb.edu/)"); +MODULE_DESCRIPTION("Unionfs " UNIONFS_VERSION + " (http://unionfs.filesystems.org/)"); +MODULE_LICENSE("GPL"); + +module_init(init_unionfs_fs); +module_exit(exit_unionfs_fs); +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/print.c +++ linux-2.6.27/ubuntu/unionfs/print.c @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef Sipek + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: print.c,v 1.77 2006/07/08 17:58:31 ezk Exp $ + */ + +/* Print debugging functions */ + +#include "unionfs.h" + +static unsigned int debug_mask = DEFAULT_DEBUG_MASK; + +/* get value of debugging variable */ +unsigned int get_debug_mask(void) +{ + return debug_mask; +} + +/* set debug level variable and return the previous value */ +int set_debug_mask(int val) +{ +#ifdef UNIONFS_DEBUG + int prev = debug_mask; + + debug_mask = val; + + printk(KERN_INFO UNIONFS_NAME ": debug mask set to %u\n", debug_mask); + + return prev; +#else /* UNIONFS_DEBUG */ + printk(KERN_WARNING UNIONFS_NAME ": debugging is not enabled\n"); + return -ENOTSUPP; +#endif /* ! UNIONFS_DEBUG */ +} + +static inline int should_print(const unsigned int req) +{ + return (req & debug_mask); +} + +static void unionfs_print_generic_inode(const char *prefix, + const char *prefix2, const struct inode *inode) +{ + if (!inode) { + printk(KERN_DEBUG UNIONFS_NAME ": PI:%s%s: NULL INODE PASSED!\n", prefix, prefix2); + return; + } + + if (IS_ERR(inode)) { + printk(KERN_DEBUG UNIONFS_NAME ": PI:%s%s: ERROR INODE PASSED: %ld\n", prefix, prefix2, + PTR_ERR(inode)); + return; + } + + printk(KERN_DEBUG UNIONFS_NAME ": PI:%s%s: i_ino=%lu\n", + prefix, prefix2, inode->i_ino); + printk(KERN_DEBUG UNIONFS_NAME ": PI:%s%s: i_count=%u\n", + prefix, prefix2, atomic_read(&inode->i_count)); + printk(KERN_DEBUG UNIONFS_NAME ": PI:%s%s: i_nlink=%u\n", + prefix, prefix2, inode->i_nlink); + printk(KERN_DEBUG UNIONFS_NAME ": PI:%s%s: i_mode=%o\n", + prefix, prefix2, inode->i_mode); + printk(KERN_DEBUG UNIONFS_NAME ": PI:%s%s: i_size=%llu\n", + prefix, prefix2, inode->i_size); + printk(KERN_DEBUG UNIONFS_NAME ": PI:%s%s: i_op=%p\n", + prefix, prefix2, inode->i_op); + printk(KERN_DEBUG UNIONFS_NAME ": PI:%s%s: i_sb=%p (%s)\n", + prefix, prefix2, inode->i_sb, (inode->i_sb ? sbt(inode->i_sb) : "NullTypeSB")); +} + +void unionfs_print_inode(const unsigned int req, const char *prefix, const struct inode *inode) +{ + int bindex; + + if (!should_print(req)) + return; + + if (!inode) { + printk(KERN_DEBUG UNIONFS_NAME ": PI:%s: NULL INODE PASSED!\n", prefix); + return; + } + if (IS_ERR(inode)) { + printk(KERN_DEBUG UNIONFS_NAME ": PI:%s: ERROR INODE PASSED: %ld\n", prefix, PTR_ERR(inode)); + return; + } + + unionfs_print_generic_inode(prefix, "", inode); + + if (strcmp("unionfs", sbt(inode->i_sb))) { + printk(KERN_DEBUG UNIONFS_NAME ": PI:%s: Not a " UNIONFS_NAME " inode.\n", prefix); + return; + } + + if (!itopd(inode)) + return; + + printk(KERN_DEBUG UNIONFS_NAME ": PI:%s: ibstart=%d, ibend=%d\n", prefix, ibstart(inode), ibend(inode)); + + if (ibstart(inode) == -1) + return; + + for (bindex = ibstart(inode); bindex <= ibend(inode); bindex++) { + struct inode *hidden_inode = itohi_index(inode, bindex); + char newstr[10]; + if (!hidden_inode) { + printk(KERN_DEBUG UNIONFS_NAME ": PI:%s: HI#%d: NULL\n", prefix, bindex); + continue; + } + snprintf(newstr, 10, ": HI%d", bindex); + unionfs_print_generic_inode(prefix, newstr, hidden_inode); + } +} + +static void unionfs_print_generic_file(const char *prefix, const char *prefix2, + const struct file *file) +{ + printk(KERN_DEBUG UNIONFS_NAME ": PF:%s%s: f_dentry=0x%p\n", prefix, prefix2, file->f_dentry); + + printk(KERN_DEBUG UNIONFS_NAME ": PF:%s%s: name=%s\n", prefix, prefix2, file->f_dentry->d_name.name); + if (file->f_dentry->d_inode) { + printk(KERN_DEBUG UNIONFS_NAME ": PF:%s%s: f_dentry->d_inode->i_ino=%lu\n", prefix, prefix2, file->f_dentry->d_inode->i_ino); + printk(KERN_DEBUG UNIONFS_NAME ": PF:%s%s: f_dentry->d_inode->i_mode=%o\n", prefix, prefix2, file->f_dentry->d_inode->i_mode); + } + printk(KERN_DEBUG UNIONFS_NAME ": PF:%s%s: f_op=0x%p\n", prefix, prefix2, file->f_op); + printk(KERN_DEBUG UNIONFS_NAME ": PF:%s%s: f_mode=0x%x\n", prefix, prefix2, file->f_mode); + printk(KERN_DEBUG UNIONFS_NAME ": PF:%s%s: f_pos=0x%llu\n", prefix, prefix2, file->f_pos); + printk(KERN_DEBUG UNIONFS_NAME ": PF:%s%s: f_count=%u\n", prefix, prefix2, atomic_read(&file->f_count)); + printk(KERN_DEBUG UNIONFS_NAME ": PF:%s%s: f_flags=0x%x\n", prefix, prefix2, file->f_flags); + printk(KERN_DEBUG UNIONFS_NAME ": PF:%s%s: f_version=%llu\n", prefix, prefix2, file->f_version); +} + +void unionfs_print_file(const unsigned int req, const char *prefix, const struct file *file) +{ + struct file *hidden_file; + + if (!should_print(req)) + return; + + if (!file) { + printk(KERN_DEBUG UNIONFS_NAME ": PF:%s: NULL FILE PASSED!\n", prefix); + return; + } + + unionfs_print_generic_file(prefix, "", file); + + if (strcmp("unionfs", sbt(file->f_dentry->d_sb))) { + printk(KERN_DEBUG UNIONFS_NAME ": PF:%s: Not a " UNIONFS_NAME " file.\n", prefix); + return; + } + + if (ftopd(file)) { + int bindex; + + printk(KERN_DEBUG UNIONFS_NAME ": PF:%s: fbstart=%d, fbend=%d\n", prefix, fbstart(file), fbend(file)); + + for (bindex = fbstart(file); bindex <= fbend(file); bindex++) { + char newstr[10]; + hidden_file = ftohf_index(file, bindex); + if (!hidden_file) { + printk(KERN_DEBUG UNIONFS_NAME ": PF:%s: HF#%d is NULL\n", prefix, bindex); + continue; + } + snprintf(newstr, 10, ": HF%d", bindex); + unionfs_print_generic_file(prefix, newstr, hidden_file); + } + } +} + +static char mode_to_type(mode_t mode) +{ + if (S_ISDIR(mode)) + return 'd'; + if (S_ISLNK(mode)) + return 'l'; + if (S_ISCHR(mode)) + return 'c'; + if (S_ISBLK(mode)) + return 'b'; + if (S_ISREG(mode)) + return 'f'; + return '?'; +} + +static void unionfs_print_generic_dentry(const char *prefix, const char *prefix2, const + struct dentry *dentry, int check) +{ + if (!dentry) { + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s%s: NULL DENTRY PASSED!\n", prefix, prefix2); + return; + } + + if (IS_ERR(dentry)) { + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s%s: ERROR DENTRY (%ld)!\n", prefix, prefix2, + PTR_ERR(dentry)); + return; + } + + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s%s: dentry = %p\n", prefix, prefix2, dentry); + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s%s: d_count=%d\n", prefix, prefix2, atomic_read(&dentry->d_count)); + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s%s: d_flags=%x\n", prefix, prefix2, (int)dentry->d_flags); + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s%s: d_name.name=\"%s\" (len = %d)\n", prefix, prefix2, dentry->d_name.name, dentry->d_name.len); + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s%s: d_sb=%p (%s)\n", prefix, prefix2, dentry->d_sb, sbt(dentry->d_sb)); + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s%s: d_inode=%p\n", prefix, prefix2, dentry->d_inode); + + if (dentry->d_inode) { + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s%s: d_inode->i_ino=%ld (%s)\n", prefix, prefix2, + dentry->d_inode->i_ino, + sbt(dentry->d_inode->i_sb)); + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s%s: dentry->d_inode->i_mode: %c%o\n", prefix, + prefix2, mode_to_type(dentry->d_inode->i_mode), + dentry->d_inode->i_mode); + } + + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s%s: d_parent=%p (%s)\n", prefix, prefix2, + dentry->d_parent, + (dentry->d_parent ? sbt(dentry->d_parent->d_sb) : "nil")); + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s%s: d_parent->d_name.name=\"%s\"\n", prefix, prefix2, + dentry->d_parent->d_name.name); + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s%s: d_parent->d_count=%d\n", prefix, prefix2, + atomic_read(&dentry->d_parent->d_count)); + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s%s: d_op=%p\n", prefix, prefix2, dentry->d_op); + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s%s: d_fsdata=%p\n", prefix, prefix2, + dentry->d_fsdata); + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s%s: hlist_unhashed(d_hash)=%d\n", prefix, prefix2, + hlist_unhashed(&((struct dentry *)dentry)->d_hash)); + + /* After we have printed it, we can assert something about it. */ + if (check) + BUG_ON(atomic_read(&dentry->d_count) <= 0); +} + +static void __unionfs_print_dentry(const char *prefix, const struct dentry *dentry, + int check) +{ + if (!dentry) { + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s: NULL DENTRY PASSED!\n", prefix); + return; + } + + if (IS_ERR(dentry)) { + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s: ERROR DENTRY (%ld)!\n", prefix, + PTR_ERR(dentry)); + return; + } + + unionfs_print_generic_dentry(prefix, "", dentry, check); + + if (strcmp("unionfs", sbt(dentry->d_sb))) { + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s: Not a " UNIONFS_NAME " dentry.\n", prefix); + return; + } + + if (!dtopd(dentry)) + return; + + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s: dbstart=%d, dbend=%d, dbopaque=%d\n", + prefix, dbstart(dentry), dbend(dentry), dbopaque(dentry)); + + if (dbstart(dentry) != -1) { + int bindex; + char newstr[10]; + struct dentry *hidden_dentry; + + for (bindex = dbstart(dentry); bindex <= dbend(dentry); + bindex++) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) { + printk(KERN_DEBUG UNIONFS_NAME ": PD:%s: HD#%d: NULL\n", prefix, bindex); + continue; + } + snprintf(newstr, 10, ": HD%d", bindex); + unionfs_print_generic_dentry(prefix, newstr, hidden_dentry, check); + } + } +} + +void unionfs_print_dentry(const unsigned int req, const char *prefix, const struct dentry *dentry) +{ + if (!should_print(req)) + return; + + __unionfs_print_dentry(prefix, dentry, 1); +} + +void unionfs_print_dentry_nocheck(const unsigned int req, const char *prefix, const struct dentry *dentry) +{ + if (!should_print(req)) + return; + + __unionfs_print_dentry(prefix, dentry, 0); +} + +void unionfs_checkinode(const unsigned int req, const struct inode *inode, const char *msg) +{ + if (!should_print(req)) + return; + + if (!inode) { + printk(KERN_DEBUG UNIONFS_NAME ": unionfs_checkinode - inode is NULL! (%s)\n", + msg); + return; + } + + if (!itopd(inode)) { + printk(KERN_DEBUG UNIONFS_NAME ": unionfs_checkinode(%ld) - no private data (%s)\n", + inode->i_ino, msg); + return; + } + + if ((itopd(inode)->b_start < 0) || !itohi(inode)) { + printk(KERN_DEBUG UNIONFS_NAME + "unionfs_checkinode(%ld) - underlying is NULL! (%s)\n", + inode->i_ino, msg); + return; + } + + if (!inode->i_sb) { + printk(KERN_DEBUG UNIONFS_NAME + ": unionfs_checkinode(%ld) - inode->i_sb is NULL! (%s)\n", + inode->i_ino, msg); + return; + } + + printk(KERN_DEBUG UNIONFS_NAME ": inode->i_sb->s_type %p\n", inode->i_sb->s_type); + if (!inode->i_sb->s_type) { + printk(KERN_DEBUG UNIONFS_NAME + ": unionfs_checkinode(%ld) - inode->i_sb->s_type is NULL! (%s)\n", + inode->i_ino, msg); + return; + } + + printk(KERN_DEBUG UNIONFS_NAME + ": CI: %s: inode->i_count = %d, hidden_inode->i_count = %d, inode = %lu, sb = %s, hidden_sb = %s\n", + msg, atomic_read(&inode->i_count), + itopd(inode)->b_start >= + 0 ? atomic_read(&itohi(inode)->i_count) : -1, inode->i_ino, + inode->i_sb->s_type->name, + itopd(inode)->b_start >= + 0 ? itohi(inode)->i_sb->s_type->name : "(none)"); +} + +void unionfs_print_sb(const unsigned int req, const char *prefix, const struct super_block *sb) +{ + struct super_block *hidden_superblock; + + if (!should_print(req)) + return; + + if (!sb) { + printk(KERN_DEBUG UNIONFS_NAME ": PSB:%s: NULL SB PASSED!\n", prefix); + return; + } + + printk(KERN_DEBUG UNIONFS_NAME ": PSB:%s: s_blocksize=%lu\n", prefix, sb->s_blocksize); + printk(KERN_DEBUG UNIONFS_NAME ": PSB:%s: s_blocksize_bits=%u\n", prefix, sb->s_blocksize_bits); + printk(KERN_DEBUG UNIONFS_NAME ": PSB:%s: s_flags=0x%lx\n", prefix, sb->s_flags); + printk(KERN_DEBUG UNIONFS_NAME ": PSB:%s: s_magic=0x%lx\n", prefix, sb->s_magic); + printk(KERN_DEBUG UNIONFS_NAME ": PSB:%s: s_maxbytes=%llu\n", prefix, sb->s_maxbytes); + printk(KERN_DEBUG UNIONFS_NAME ": PSB:%s: s_count=%d\n", prefix, sb->s_count); + printk(KERN_DEBUG UNIONFS_NAME ": PSB:%s: s_active=%d\n", prefix, atomic_read(&sb->s_active)); + + if (stopd(sb)) + printk(KERN_DEBUG UNIONFS_NAME ": sbstart=%d, sbend=%d\n", sbstart(sb), + sbend(sb)); + + if (stopd(sb)) { + int bindex; + for (bindex = sbstart(sb); bindex <= sbend(sb); bindex++) { + hidden_superblock = stohs_index(sb, bindex); + if (!hidden_superblock) { + printk(KERN_DEBUG UNIONFS_NAME ": PSB:%s: HS#%d is NULL", prefix, + bindex); + continue; + } + + printk(KERN_DEBUG UNIONFS_NAME ": PSB:%s: HS#%d: s_blocksize=%lu\n", prefix, bindex, + hidden_superblock->s_blocksize); + printk(KERN_DEBUG UNIONFS_NAME ": PSB:%s: HS#%d: s_blocksize_bits=%u\n", prefix, bindex, + hidden_superblock->s_blocksize_bits); + printk(KERN_DEBUG UNIONFS_NAME ": PSB:%s: HS#%d: s_flags=0x%lx\n", prefix, bindex, + hidden_superblock->s_flags); + printk(KERN_DEBUG UNIONFS_NAME ": PSB:%s: HS#%d: s_magic=0x%lx\n", prefix, bindex, + hidden_superblock->s_magic); + printk(KERN_DEBUG UNIONFS_NAME ": PSB:%s: HS#%d: s_maxbytes=%llu\n", prefix, bindex, + hidden_superblock->s_maxbytes); + printk(KERN_DEBUG UNIONFS_NAME ": PSB:%s: HS#%d: s_count=%d\n", prefix, bindex, + hidden_superblock->s_count); + printk(KERN_DEBUG UNIONFS_NAME ": PSB:%s: HS#%d: s_active=%d\n", prefix, bindex, + atomic_read(&hidden_superblock->s_active)); + } + } +} + +int unionfs_print(const unsigned int req, const char *fmt, ...) +{ + va_list ap; + int r; + + if (!should_print(req)) + return 0; + + printk(KERN_DEBUG UNIONFS_NAME ": "); + va_start(ap, fmt); + r = vprintk(fmt, ap); + va_end(ap); + + return r; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/unionfs/unlink.c +++ linux-2.6.27/ubuntu/unionfs/unlink.c @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2005-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * For specific licensing information, see the COPYING file distributed with + * this package. + * + * This Copyright notice must be kept intact and distributed with all sources. + */ +/* + * $Id: unlink.c,v 1.44 2006/08/05 01:28:46 jro Exp $ + */ + +#include "unionfs.h" + +#ifdef UNIONFS_DELETE_ALL +static int unionfs_unlink_all(struct inode *dir, struct dentry *dentry) +{ + struct dentry *hidden_dentry; + struct dentry *hidden_dir_dentry; + int bstart, bend, bindex; + int err = 0; + int global_err = 0; + + print_entry_location(); + + if ((err = unionfs_partial_lookup(dentry))) + goto out; + + bstart = dbstart(dentry); + bend = dbend(dentry); + + for (bindex = bend; bindex >= bstart; bindex--) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + continue; + + hidden_dir_dentry = lock_parent(hidden_dentry); + + /* avoid destroying the hidden inode if the file is in use */ + DGET(hidden_dentry); + if (!(err = is_robranch_super(dentry->d_sb, bindex))) + err = vfs_unlink(hidden_dir_dentry->d_inode, + hidden_dentry, NULL); + DPUT(hidden_dentry); + fist_copy_attr_times(dir, hidden_dir_dentry->d_inode); + unlock_dir(hidden_dir_dentry); + + if (err) { + /* passup the last error we got */ + if (!IS_COPYUP_ERR(err)) + goto out; + global_err = err; + } + } + + /* check if encountered error in the above loop */ + if (global_err) { + /* If we failed in the leftmost branch, then err will be set + * and we should move one over to create the whiteout. + * Otherwise, we should try in the leftmost branch. */ + if (err) { + if (dbstart(dentry) == 0) { + goto out; + } + err = create_whiteout(dentry, dbstart(dentry) - 1); + } else { + err = create_whiteout(dentry, dbstart(dentry)); + } + } else if (dbopaque(dentry) != -1) { + /* There is a hidden lower-priority file with the same name. */ + err = create_whiteout(dentry, dbopaque(dentry)); + } + out: + /* propagate number of hard-links */ + if (dentry->d_inode->i_nlink != 0) { + dentry->d_inode->i_nlink = get_nlinks(dentry->d_inode); + if (!err && global_err) + dentry->d_inode->i_nlink--; + } + /* We don't want to leave negative leftover dentries for revalidate. */ + if (!err && (global_err || dbopaque(dentry) != -1)) + update_bstart(dentry); + + print_exit_status(err); + return err; +} +#endif +static int unionfs_unlink_whiteout(struct inode *dir, struct dentry *dentry) +{ + struct dentry *hidden_dentry; + struct dentry *hidden_dir_dentry; + int bindex; + int err = 0; + + print_entry_location(); + + if ((err = unionfs_partial_lookup(dentry))) + goto out; + + bindex = dbstart(dentry); + + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + goto out; + + hidden_dir_dentry = lock_parent(hidden_dentry); + + /* avoid destroying the hidden inode if the file is in use */ + DGET(hidden_dentry); + if (!(err = is_robranch_super(dentry->d_sb, bindex))) + err = vfs_unlink(hidden_dir_dentry->d_inode, hidden_dentry, + NULL); + DPUT(hidden_dentry); + fist_copy_attr_times(dir, hidden_dir_dentry->d_inode); + unlock_dir(hidden_dir_dentry); + + if (err && !IS_COPYUP_ERR(err)) + goto out; + + if (err) { + if (dbstart(dentry) == 0) + goto out; + + err = create_whiteout(dentry, dbstart(dentry) - 1); + } else if (dbopaque(dentry) != -1) { + /* There is a hidden lower-priority file with the same name. */ + err = create_whiteout(dentry, dbopaque(dentry)); + } else { + err = create_whiteout(dentry, dbstart(dentry)); + } + + out: + if (!err) + dentry->d_inode->i_nlink--; + + /* We don't want to leave negative leftover dentries for revalidate. */ + if (!err && (dbopaque(dentry) != -1)) + update_bstart(dentry); + + print_exit_status(err); + return err; + +} + +int unionfs_unlink(struct inode *dir, struct dentry *dentry) +{ + int err = 0; + + print_entry_location(); + lock_dentry(dentry); + print_dentry("IN unionfs_unlink", dentry); + +#ifdef UNIONFS_DELETE_ALL + if (IS_SET(dir->i_sb, DELETE_ALL)) + err = unionfs_unlink_all(dir, dentry); + else +#endif + err = unionfs_unlink_whiteout(dir, dentry); + /* call d_drop so the system "forgets" about us */ + if (!err) + d_drop(dentry); + + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +static int unionfs_rmdir_first(struct inode *dir, struct dentry *dentry, + struct unionfs_dir_state *namelist) +{ + int err; + struct dentry *hidden_dentry; + struct dentry *hidden_dir_dentry = NULL; + + print_entry_location(); + print_dentry("IN unionfs_rmdir_first: ", dentry); + + /* Here we need to remove whiteout entries. */ + err = delete_whiteouts(dentry, dbstart(dentry), namelist); + if (err) { + goto out; + } + + hidden_dentry = dtohd(dentry); + + hidden_dir_dentry = lock_parent(hidden_dentry); + + /* avoid destroying the hidden inode if the file is in use */ + DGET(hidden_dentry); + if (!(err = is_robranch(dentry))) { + err = vfs_rmdir(hidden_dir_dentry->d_inode, hidden_dentry, + NULL); + } + DPUT(hidden_dentry); + + fist_copy_attr_times(dir, hidden_dir_dentry->d_inode); + /* propagate number of hard-links */ + dentry->d_inode->i_nlink = get_nlinks(dentry->d_inode); + + out: + if (hidden_dir_dentry) { + unlock_dir(hidden_dir_dentry); + } + print_dentry("OUT unionfs_rmdir_first: ", dentry); + print_exit_status(err); + return err; +} + +#ifdef UNIONFS_DELETE_ALL +static int unionfs_rmdir_all(struct inode *dir, struct dentry *dentry, + struct unionfs_dir_state *namelist) +{ + struct dentry *hidden_dentry; + struct dentry *hidden_dir_dentry; + int bstart, bend, bindex; + int err = 0; + int global_err = 0; + + print_entry_location(); + print_dentry("IN unionfs_rmdir_all: ", dentry); + + bstart = dbstart(dentry); + bend = dbend(dentry); + + for (bindex = bend; bindex >= bstart; bindex--) { + hidden_dentry = dtohd_index(dentry, bindex); + if (!hidden_dentry) + continue; + + hidden_dir_dentry = lock_parent(hidden_dentry); + if (S_ISDIR(hidden_dentry->d_inode->i_mode)) { + err = delete_whiteouts(dentry, bindex, namelist); + if (!err + && !(err = + is_robranch_super(dentry->d_sb, bindex))) { + err = + vfs_rmdir(hidden_dir_dentry->d_inode, + hidden_dentry, NULL); + } + } else { + err = -EISDIR; + } + + fist_copy_attr_times(dir, hidden_dir_dentry->d_inode); + unlock_dir(hidden_dir_dentry); + if (err) { + int local_err = + unionfs_refresh_hidden_dentry(dentry, bindex); + if (local_err) { + err = local_err; + goto out; + } + + if (!IS_COPYUP_ERR(err) && err != -ENOTEMPTY + && err != -EISDIR) + goto out; + + global_err = err; + } + } + + /* check if encountered error in the above loop */ + if (global_err) { + /* If we failed in the leftmost branch, then err will be set and we should + * move one over to create the whiteout. Otherwise, we should try in the + * leftmost branch. + */ + if (err) { + if (dbstart(dentry) == 0) { + goto out; + } + err = create_whiteout(dentry, dbstart(dentry) - 1); + } else { + err = create_whiteout(dentry, dbstart(dentry)); + } + } else { + err = create_whiteout(dentry, dbstart(dentry)); + } + + out: + /* propagate number of hard-links */ + dentry->d_inode->i_nlink = get_nlinks(dentry->d_inode); + + print_dentry("OUT unionfs_rmdir_all: ", dentry); + print_exit_status(err); + return err; +} +#endif +int unionfs_rmdir(struct inode *dir, struct dentry *dentry) +{ + int err = 0; + struct unionfs_dir_state *namelist = NULL; + + print_entry_location(); + lock_dentry(dentry); + print_dentry("IN unionfs_rmdir: ", dentry); + + /* check if this unionfs directory is empty or not */ + err = check_empty(dentry, &namelist); + if (err) { +#if 0 + /* vfs_rmdir(our caller) unhashed the dentry. This will recover + * the Unionfs inode number for the directory itself, but the + * children are already lost. It seems that tmpfs manages its + * way around this by upping the refcount on everything. + * + * Even if we do this, we still lose the inode numbers of the + * children. The best way to fix this is to fix the VFS (or + * use persistent inode maps). */ + if (d_unhashed(dentry)) + d_rehash(dentry); +#endif + goto out; + } +#ifdef UNIONFS_DELETE_ALL + if (IS_SET(dir->i_sb, DELETE_ALL)) { + /* delete all. */ + err = unionfs_rmdir_all(dir, dentry, namelist); + } else { /* Delete the first directory. */ +#endif + err = unionfs_rmdir_first(dir, dentry, namelist); + /* create whiteout */ + if (!err) { + err = create_whiteout(dentry, dbstart(dentry)); + } else { + int new_err; + + if (dbstart(dentry) == 0) + goto out; + + /* exit if the error returned was NOT -EROFS */ + if (!IS_COPYUP_ERR(err)) + goto out; + + new_err = create_whiteout(dentry, dbstart(dentry) - 1); + if (new_err != -EEXIST) + err = new_err; + } + +#ifdef UNIONFS_DELETE_ALL + } +#endif + out: + /* call d_drop so the system "forgets" about us */ + if (!err) + d_drop(dentry); + + if (namelist) + free_rdstate(namelist); + + unlock_dentry(dentry); + print_exit_status(err); + return err; +} + +/* + * + * vim:shiftwidth=8 + * vim:tabstop=8 + * + * For Emacs: + * Local variables: + * c-basic-offset: 8 + * c-comment-only-line-offset: 0 + * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0) + * (substatement-open . 0) (label . 0) (statement-cont . +)) + * indent-tabs-mode: t + * tab-width: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/include/README +++ linux-2.6.27/ubuntu/include/README @@ -0,0 +1,4 @@ +Only use this directory for things which need to share their headers with +other parts of the kernel or other modules in ubuntu/ + +Otherwise, keep them local to the module directory. --- linux-2.6.27.orig/ubuntu/include/linux/squashfs_fs_sb.h +++ linux-2.6.27/ubuntu/include/linux/squashfs_fs_sb.h @@ -0,0 +1,76 @@ +#ifndef SQUASHFS_FS_SB +#define SQUASHFS_FS_SB +/* + * Squashfs + * + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 + * Phillip Lougher + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * squashfs_fs_sb.h + */ + +#include + +struct squashfs_cache { + long long block; + int length; + long long next_index; + char *data; +}; + +struct squashfs_fragment_cache { + long long block; + int length; + unsigned int locked; + char *data; +}; + +struct squashfs_sb_info { + struct squashfs_super_block sblk; + int devblksize; + int devblksize_log2; + int swap; + struct squashfs_cache *block_cache; + struct squashfs_fragment_cache *fragment; + int next_cache; + int next_fragment; + int next_meta_index; + unsigned int *uid; + unsigned int *guid; + long long *fragment_index; + unsigned int *fragment_index_2; + char *read_page; + struct mutex read_data_mutex; + struct mutex read_page_mutex; + struct mutex block_cache_mutex; + struct mutex fragment_mutex; + struct mutex meta_index_mutex; + wait_queue_head_t waitq; + wait_queue_head_t fragment_wait_queue; + struct meta_index *meta_index; + z_stream stream; + long long *inode_lookup_table; + int unused_cache_blks; + int unused_frag_blks; + int (*read_inode)(struct inode *i, squashfs_inode_t \ + inode); + long long (*read_blocklist)(struct inode *inode, int \ + index, int readahead_blks, char *block_list, \ + unsigned short **block_p, unsigned int *bsize); + int (*read_fragment_index_table)(struct super_block *s); +}; +#endif --- linux-2.6.27.orig/ubuntu/include/linux/aufs_types.h +++ linux-2.6.27/ubuntu/include/linux/aufs_types.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* $Id: aufs_type.h,v 1.110 2008/06/09 01:11:58 sfjro Exp $ */ + +#include + +#ifndef __AUFS_TYPE_H__ +#define __AUFS_TYPE_H__ + +#define AUFS_VERSION "20080609" + +/* move this to linux-2.6.19/include/magic.h */ +#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_BRANCH_MAX_127 +/* some environments treat 'char' as 'unsigned char' by default */ +typedef signed char aufs_bindex_t; +#define AUFS_BRANCH_MAX 127 +#else +typedef short aufs_bindex_t; +#ifdef CONFIG_AUFS_BRANCH_MAX_511 +#define AUFS_BRANCH_MAX 511 +#elif defined(CONFIG_AUFS_BRANCH_MAX_1023) +#define AUFS_BRANCH_MAX 1023 +#elif defined(CONFIG_AUFS_BRANCH_MAX_32767) +#define AUFS_BRANCH_MAX 32767 +#else +#error unknown CONFIG_AUFS_BRANCH_MAX value +#endif +#endif + +#define AUFS_NAME "aufs" +#define AUFS_FSTYPE AUFS_NAME + +#define AUFS_ROOT_INO 2 +#define AUFS_FIRST_INO 11 + +#define AUFS_WH_PFX ".wh." +#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1) +#define AUFS_XINO_FNAME "." AUFS_NAME ".xino" +#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME +#define AUFS_XINO_TRUNC_INIT 64 /* blocks */ +#define AUFS_XINO_TRUNC_STEP 4 /* blocks */ +#define AUFS_DIRWH_DEF 3 +#define AUFS_RDCACHE_DEF 10 /* seconds */ +#define AUFS_WKQ_NAME AUFS_NAME "d" +#define AUFS_NWKQ_DEF 4 +#define AUFS_MFS_SECOND_DEF 30 /* seconds */ +#define AUFS_PLINK_WARN 100 /* number of plinks */ + +#ifdef CONFIG_AUFS_COMPAT +#define AUFS_DIROPQ_NAME "__dir_opaque" +#else +#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */ +#endif +#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME + +/* will be whiteouted doubly */ +#define AUFS_WH_BASENAME AUFS_WH_PFX AUFS_NAME +#define AUFS_WH_PLINKDIR AUFS_WH_PFX "plink" + +/* ---------------------------------------------------------------------- */ + +/* ioctl */ +#if 0 /* reserved for future use */ +enum { + AuCtlErr, + AuCtlErr_Last +}; +enum { + AuCtl_REFRESH, AuCtl_REFRESHV, + AuCtl_FLUSH_PLINK, + AuCtl_CPUP, + AuCtl_CPDOWN, AuCtl_MVDOWN, + AuCtl_DIROPQ +}; + +struct aufs_ctl_cp { + int bsrc, bdst; + int err; +}; + +#define AuCtlType 'A' +#define AUFS_CTL_REFRESH _IO(AuCtlType, AuCtl_REFRESH) +#define AUFS_CTL_REFRESHV _IO(AuCtlType, AuCtl_REFRESHV) +#define AUFS_CTL_FLUSH_PLINK _IOR(AuCtlType, AuCtl_FLUSH_PLINK) +#define AUFS_CTL_CPUP _IOWR(AuCtlType, AuCtl_CPUP, struct aufs_ctl_cp) +#define AUFS_CTL_CPDOWN \ + _IOWR(AuCtlType, AuCtl_CPDOWN, struct aufs_ctl_cp) +#define AUFS_CTL_MVDOWN \ + _IOWR(AuCtlType, AuCtl_MVDOWN, struct aufs_ctl_cp) +#define AUFS_CTL_DIROPQ _IO(AuCtlType, AuCtl_DIROPQ) +#endif + +#endif /* __AUFS_TYPE_H__ */ --- linux-2.6.27.orig/ubuntu/include/linux/squashfs_fs_i.h +++ linux-2.6.27/ubuntu/include/linux/squashfs_fs_i.h @@ -0,0 +1,45 @@ +#ifndef SQUASHFS_FS_I +#define SQUASHFS_FS_I +/* + * Squashfs + * + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 + * Phillip Lougher + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * squashfs_fs_i.h + */ + +struct squashfs_inode_info { + long long start_block; + unsigned int offset; + union { + struct { + long long fragment_start_block; + unsigned int fragment_size; + unsigned int fragment_offset; + long long block_list_start; + } s1; + struct { + long long directory_index_start; + unsigned int directory_index_offset; + unsigned int directory_index_count; + unsigned int parent_inode; + } s2; + } u; + struct inode vfs_inode; +}; +#endif --- linux-2.6.27.orig/ubuntu/include/linux/squashfs_fs.h +++ linux-2.6.27/ubuntu/include/linux/squashfs_fs.h @@ -0,0 +1,935 @@ +#ifndef SQUASHFS_FS +#define SQUASHFS_FS + +/* + * Squashfs + * + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 + * Phillip Lougher + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * squashfs_fs.h + */ + +#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY +#define CONFIG_SQUASHFS_2_0_COMPATIBILITY +#endif + +#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE +#define SQUASHFS_MAJOR 3 +#define SQUASHFS_MINOR 1 +#define SQUASHFS_MAGIC 0x73717368 +#define SQUASHFS_MAGIC_SWAP 0x68737173 +#define SQUASHFS_START 0 + +/* size of metadata (inode and directory) blocks */ +#define SQUASHFS_METADATA_SIZE 8192 +#define SQUASHFS_METADATA_LOG 13 + +/* default size of data blocks */ +#define SQUASHFS_FILE_SIZE 131072 +#define SQUASHFS_FILE_LOG 17 + +#define SQUASHFS_FILE_MAX_SIZE 1048576 + +/* Max number of uids and gids */ +#define SQUASHFS_UIDS 256 +#define SQUASHFS_GUIDS 255 + +/* Max length of filename (not 255) */ +#define SQUASHFS_NAME_LEN 256 + +#define SQUASHFS_INVALID ((long long) 0xffffffffffff) +#define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff) +#define SQUASHFS_INVALID_BLK ((long long) -1) +#define SQUASHFS_USED_BLK ((long long) -2) + +/* Filesystem flags */ +#define SQUASHFS_NOI 0 +#define SQUASHFS_NOD 1 +#define SQUASHFS_CHECK 2 +#define SQUASHFS_NOF 3 +#define SQUASHFS_NO_FRAG 4 +#define SQUASHFS_ALWAYS_FRAG 5 +#define SQUASHFS_DUPLICATE 6 +#define SQUASHFS_EXPORT 7 + +#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) + +#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_NOI) + +#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_NOD) + +#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_NOF) + +#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_NO_FRAG) + +#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_ALWAYS_FRAG) + +#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_DUPLICATE) + +#define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_EXPORT) + +#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_CHECK) + +#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \ + duplicate_checking, exportable) (noi | (nod << 1) | (check_data << 2) \ + | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \ + (duplicate_checking << 6) | (exportable << 7)) + +/* Max number of types and file types */ +#define SQUASHFS_DIR_TYPE 1 +#define SQUASHFS_FILE_TYPE 2 +#define SQUASHFS_SYMLINK_TYPE 3 +#define SQUASHFS_BLKDEV_TYPE 4 +#define SQUASHFS_CHRDEV_TYPE 5 +#define SQUASHFS_FIFO_TYPE 6 +#define SQUASHFS_SOCKET_TYPE 7 +#define SQUASHFS_LDIR_TYPE 8 +#define SQUASHFS_LREG_TYPE 9 + +/* 1.0 filesystem type definitions */ +#define SQUASHFS_TYPES 5 +#define SQUASHFS_IPC_TYPE 0 + +/* Flag whether block is compressed or uncompressed, bit is set if block is + * uncompressed */ +#define SQUASHFS_COMPRESSED_BIT (1 << 15) + +#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \ + (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT) + +#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT)) + +#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24) + +#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) ((B) & \ + ~SQUASHFS_COMPRESSED_BIT_BLOCK) + +#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) + +/* + * Inode number ops. Inodes consist of a compressed block number, and an + * uncompressed offset within that block + */ +#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16)) + +#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff)) + +#define SQUASHFS_MKINODE(A, B) ((squashfs_inode_t)(((squashfs_inode_t) (A)\ + << 16) + (B))) + +/* Compute 32 bit VFS inode number from squashfs inode number */ +#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \ + ((b) >> 2) + 1)) +/* XXX */ + +/* Translate between VFS mode and squashfs mode */ +#define SQUASHFS_MODE(a) ((a) & 0xfff) + +/* fragment and fragment table defines */ +#define SQUASHFS_FRAGMENT_BYTES(A) ((A) * sizeof(struct squashfs_fragment_entry)) + +#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \ + SQUASHFS_METADATA_SIZE - 1) / \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\ + sizeof(long long)) + +/* inode lookup table defines */ +#define SQUASHFS_LOOKUP_BYTES(A) ((A) * sizeof(squashfs_inode_t)) + +#define SQUASHFS_LOOKUP_BLOCK(A) (SQUASHFS_LOOKUP_BYTES(A) / \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_LOOKUP_BLOCK_OFFSET(A) (SQUASHFS_LOOKUP_BYTES(A) % \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_LOOKUP_BLOCKS(A) ((SQUASHFS_LOOKUP_BYTES(A) + \ + SQUASHFS_METADATA_SIZE - 1) / \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_LOOKUP_BLOCK_BYTES(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\ + sizeof(long long)) + +/* cached data constants for filesystem */ +#define SQUASHFS_CACHED_BLKS 8 + +#define SQUASHFS_MAX_FILE_SIZE_LOG 64 + +#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \ + (SQUASHFS_MAX_FILE_SIZE_LOG - 2)) + +#define SQUASHFS_MARKER_BYTE 0xff + +/* meta index cache */ +#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int)) +#define SQUASHFS_META_ENTRIES 31 +#define SQUASHFS_META_NUMBER 8 +#define SQUASHFS_SLOTS 4 + +struct meta_entry { + long long data_block; + unsigned int index_block; + unsigned short offset; + unsigned short pad; +}; + +struct meta_index { + unsigned int inode_number; + unsigned int offset; + unsigned short entries; + unsigned short skip; + unsigned short locked; + unsigned short pad; + struct meta_entry meta_entry[SQUASHFS_META_ENTRIES]; +}; + + +/* + * definitions for structures on disk + */ + +typedef long long squashfs_block_t; +typedef long long squashfs_inode_t; + +struct squashfs_super_block { + unsigned int s_magic; + unsigned int inodes; + unsigned int bytes_used_2; + unsigned int uid_start_2; + unsigned int guid_start_2; + unsigned int inode_table_start_2; + unsigned int directory_table_start_2; + unsigned int s_major:16; + unsigned int s_minor:16; + unsigned int block_size_1:16; + unsigned int block_log:16; + unsigned int flags:8; + unsigned int no_uids:8; + unsigned int no_guids:8; + unsigned int mkfs_time /* time of filesystem creation */; + squashfs_inode_t root_inode; + unsigned int block_size; + unsigned int fragments; + unsigned int fragment_table_start_2; + long long bytes_used; + long long uid_start; + long long guid_start; + long long inode_table_start; + long long directory_table_start; + long long fragment_table_start; + long long lookup_table_start; +} __attribute__ ((packed)); + +struct squashfs_dir_index { + unsigned int index; + unsigned int start_block; + unsigned char size; + unsigned char name[0]; +} __attribute__ ((packed)); + +#define SQUASHFS_BASE_INODE_HEADER \ + unsigned int inode_type:4; \ + unsigned int mode:12; \ + unsigned int uid:8; \ + unsigned int guid:8; \ + unsigned int mtime; \ + unsigned int inode_number; + +struct squashfs_base_inode_header { + SQUASHFS_BASE_INODE_HEADER; +} __attribute__ ((packed)); + +struct squashfs_ipc_inode_header { + SQUASHFS_BASE_INODE_HEADER; + unsigned int nlink; +} __attribute__ ((packed)); + +struct squashfs_dev_inode_header { + SQUASHFS_BASE_INODE_HEADER; + unsigned int nlink; + unsigned short rdev; +} __attribute__ ((packed)); + +struct squashfs_symlink_inode_header { + SQUASHFS_BASE_INODE_HEADER; + unsigned int nlink; + unsigned short symlink_size; + char symlink[0]; +} __attribute__ ((packed)); + +struct squashfs_reg_inode_header { + SQUASHFS_BASE_INODE_HEADER; + squashfs_block_t start_block; + unsigned int fragment; + unsigned int offset; + unsigned int file_size; + unsigned short block_list[0]; +} __attribute__ ((packed)); + +struct squashfs_lreg_inode_header { + SQUASHFS_BASE_INODE_HEADER; + unsigned int nlink; + squashfs_block_t start_block; + unsigned int fragment; + unsigned int offset; + long long file_size; + unsigned short block_list[0]; +} __attribute__ ((packed)); + +struct squashfs_dir_inode_header { + SQUASHFS_BASE_INODE_HEADER; + unsigned int nlink; + unsigned int file_size:19; + unsigned int offset:13; + unsigned int start_block; + unsigned int parent_inode; +} __attribute__ ((packed)); + +struct squashfs_ldir_inode_header { + SQUASHFS_BASE_INODE_HEADER; + unsigned int nlink; + unsigned int file_size:27; + unsigned int offset:13; + unsigned int start_block; + unsigned int i_count:16; + unsigned int parent_inode; + struct squashfs_dir_index index[0]; +} __attribute__ ((packed)); + +union squashfs_inode_header { + struct squashfs_base_inode_header base; + struct squashfs_dev_inode_header dev; + struct squashfs_symlink_inode_header symlink; + struct squashfs_reg_inode_header reg; + struct squashfs_lreg_inode_header lreg; + struct squashfs_dir_inode_header dir; + struct squashfs_ldir_inode_header ldir; + struct squashfs_ipc_inode_header ipc; +}; + +struct squashfs_dir_entry { + unsigned int offset:13; + unsigned int type:3; + unsigned int size:8; + int inode_number:16; + char name[0]; +} __attribute__ ((packed)); + +struct squashfs_dir_header { + unsigned int count:8; + unsigned int start_block; + unsigned int inode_number; +} __attribute__ ((packed)); + +struct squashfs_fragment_entry { + long long start_block; + unsigned int size; + unsigned int pending; +} __attribute__ ((packed)); + +extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen); +extern int squashfs_uncompress_init(void); +extern int squashfs_uncompress_exit(void); + +/* + * macros to convert each packed bitfield structure from little endian to big + * endian and vice versa. These are needed when creating or using a filesystem + * on a machine with different byte ordering to the target architecture. + * + */ + +#define SQUASHFS_SWAP_START \ + int bits;\ + int b_pos;\ + unsigned long long val;\ + unsigned char *s;\ + unsigned char *d; + +#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\ + SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\ + SQUASHFS_SWAP((s)->inodes, d, 32, 32);\ + SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\ + SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\ + SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\ + SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\ + SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\ + SQUASHFS_SWAP((s)->s_major, d, 224, 16);\ + SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\ + SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\ + SQUASHFS_SWAP((s)->block_log, d, 272, 16);\ + SQUASHFS_SWAP((s)->flags, d, 288, 8);\ + SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\ + SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\ + SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\ + SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\ + SQUASHFS_SWAP((s)->block_size, d, 408, 32);\ + SQUASHFS_SWAP((s)->fragments, d, 440, 32);\ + SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\ + SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\ + SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\ + SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\ + SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\ + SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\ + SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\ + SQUASHFS_SWAP((s)->lookup_table_start, d, 888, 64);\ +} + +#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\ + SQUASHFS_MEMSET(s, d, n);\ + SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ + SQUASHFS_SWAP((s)->mode, d, 4, 12);\ + SQUASHFS_SWAP((s)->uid, d, 16, 8);\ + SQUASHFS_SWAP((s)->guid, d, 24, 8);\ + SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ + SQUASHFS_SWAP((s)->inode_number, d, 64, 32); + +#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\ +} + +#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_ipc_inode_header))\ + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ +} + +#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_dev_inode_header)); \ + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ + SQUASHFS_SWAP((s)->rdev, d, 128, 16);\ +} + +#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_symlink_inode_header));\ + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ + SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\ +} + +#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_reg_inode_header));\ + SQUASHFS_SWAP((s)->start_block, d, 96, 64);\ + SQUASHFS_SWAP((s)->fragment, d, 160, 32);\ + SQUASHFS_SWAP((s)->offset, d, 192, 32);\ + SQUASHFS_SWAP((s)->file_size, d, 224, 32);\ +} + +#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_lreg_inode_header));\ + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 128, 64);\ + SQUASHFS_SWAP((s)->fragment, d, 192, 32);\ + SQUASHFS_SWAP((s)->offset, d, 224, 32);\ + SQUASHFS_SWAP((s)->file_size, d, 256, 64);\ +} + +#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_dir_inode_header));\ + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ + SQUASHFS_SWAP((s)->file_size, d, 128, 19);\ + SQUASHFS_SWAP((s)->offset, d, 147, 13);\ + SQUASHFS_SWAP((s)->start_block, d, 160, 32);\ + SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\ +} + +#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_ldir_inode_header));\ + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ + SQUASHFS_SWAP((s)->file_size, d, 128, 27);\ + SQUASHFS_SWAP((s)->offset, d, 155, 13);\ + SQUASHFS_SWAP((s)->start_block, d, 168, 32);\ + SQUASHFS_SWAP((s)->i_count, d, 200, 16);\ + SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\ +} + +#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\ + SQUASHFS_SWAP((s)->index, d, 0, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 32, 32);\ + SQUASHFS_SWAP((s)->size, d, 64, 8);\ +} + +#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\ + SQUASHFS_SWAP((s)->count, d, 0, 8);\ + SQUASHFS_SWAP((s)->start_block, d, 8, 32);\ + SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\ +} + +#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\ + SQUASHFS_SWAP((s)->offset, d, 0, 13);\ + SQUASHFS_SWAP((s)->type, d, 13, 3);\ + SQUASHFS_SWAP((s)->size, d, 16, 8);\ + SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\ +} + +#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\ + SQUASHFS_SWAP((s)->start_block, d, 0, 64);\ + SQUASHFS_SWAP((s)->size, d, 64, 32);\ +} + +#define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1) + +#define SQUASHFS_SWAP_SHORTS(s, d, n) {\ + int entry;\ + int bit_position;\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, n * 2);\ + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ + 16)\ + SQUASHFS_SWAP(s[entry], d, bit_position, 16);\ +} + +#define SQUASHFS_SWAP_INTS(s, d, n) {\ + int entry;\ + int bit_position;\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, n * 4);\ + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ + 32)\ + SQUASHFS_SWAP(s[entry], d, bit_position, 32);\ +} + +#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\ + int entry;\ + int bit_position;\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, n * 8);\ + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ + 64)\ + SQUASHFS_SWAP(s[entry], d, bit_position, 64);\ +} + +#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\ + int entry;\ + int bit_position;\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, n * bits / 8);\ + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ + bits)\ + SQUASHFS_SWAP(s[entry], d, bit_position, bits);\ +} + +#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) +#define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) + +#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY + +struct squashfs_base_inode_header_1 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:4; /* index into uid table */ + unsigned int guid:4; /* index into guid table */ +} __attribute__ ((packed)); + +struct squashfs_ipc_inode_header_1 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:4; /* index into uid table */ + unsigned int guid:4; /* index into guid table */ + unsigned int type:4; + unsigned int offset:4; +} __attribute__ ((packed)); + +struct squashfs_dev_inode_header_1 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:4; /* index into uid table */ + unsigned int guid:4; /* index into guid table */ + unsigned short rdev; +} __attribute__ ((packed)); + +struct squashfs_symlink_inode_header_1 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:4; /* index into uid table */ + unsigned int guid:4; /* index into guid table */ + unsigned short symlink_size; + char symlink[0]; +} __attribute__ ((packed)); + +struct squashfs_reg_inode_header_1 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:4; /* index into uid table */ + unsigned int guid:4; /* index into guid table */ + unsigned int mtime; + unsigned int start_block; + unsigned int file_size:32; + unsigned short block_list[0]; +} __attribute__ ((packed)); + +struct squashfs_dir_inode_header_1 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:4; /* index into uid table */ + unsigned int guid:4; /* index into guid table */ + unsigned int file_size:19; + unsigned int offset:13; + unsigned int mtime; + unsigned int start_block:24; +} __attribute__ ((packed)); + +union squashfs_inode_header_1 { + struct squashfs_base_inode_header_1 base; + struct squashfs_dev_inode_header_1 dev; + struct squashfs_symlink_inode_header_1 symlink; + struct squashfs_reg_inode_header_1 reg; + struct squashfs_dir_inode_header_1 dir; + struct squashfs_ipc_inode_header_1 ipc; +}; + +#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \ + SQUASHFS_MEMSET(s, d, n);\ + SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ + SQUASHFS_SWAP((s)->mode, d, 4, 12);\ + SQUASHFS_SWAP((s)->uid, d, 16, 4);\ + SQUASHFS_SWAP((s)->guid, d, 20, 4); + +#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\ +} + +#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ + sizeof(struct squashfs_ipc_inode_header_1));\ + SQUASHFS_SWAP((s)->type, d, 24, 4);\ + SQUASHFS_SWAP((s)->offset, d, 28, 4);\ +} + +#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ + sizeof(struct squashfs_dev_inode_header_1));\ + SQUASHFS_SWAP((s)->rdev, d, 24, 16);\ +} + +#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ + sizeof(struct squashfs_symlink_inode_header_1));\ + SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\ +} + +#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ + sizeof(struct squashfs_reg_inode_header_1));\ + SQUASHFS_SWAP((s)->mtime, d, 24, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 56, 32);\ + SQUASHFS_SWAP((s)->file_size, d, 88, 32);\ +} + +#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ + sizeof(struct squashfs_dir_inode_header_1));\ + SQUASHFS_SWAP((s)->file_size, d, 24, 19);\ + SQUASHFS_SWAP((s)->offset, d, 43, 13);\ + SQUASHFS_SWAP((s)->mtime, d, 56, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 88, 24);\ +} + +#endif + +#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY + +struct squashfs_dir_index_2 { + unsigned int index:27; + unsigned int start_block:29; + unsigned char size; + unsigned char name[0]; +} __attribute__ ((packed)); + +struct squashfs_base_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ +} __attribute__ ((packed)); + +struct squashfs_ipc_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ +} __attribute__ ((packed)); + +struct squashfs_dev_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned short rdev; +} __attribute__ ((packed)); + +struct squashfs_symlink_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned short symlink_size; + char symlink[0]; +} __attribute__ ((packed)); + +struct squashfs_reg_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned int mtime; + unsigned int start_block; + unsigned int fragment; + unsigned int offset; + unsigned int file_size:32; + unsigned short block_list[0]; +} __attribute__ ((packed)); + +struct squashfs_dir_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned int file_size:19; + unsigned int offset:13; + unsigned int mtime; + unsigned int start_block:24; +} __attribute__ ((packed)); + +struct squashfs_ldir_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned int file_size:27; + unsigned int offset:13; + unsigned int mtime; + unsigned int start_block:24; + unsigned int i_count:16; + struct squashfs_dir_index_2 index[0]; +} __attribute__ ((packed)); + +union squashfs_inode_header_2 { + struct squashfs_base_inode_header_2 base; + struct squashfs_dev_inode_header_2 dev; + struct squashfs_symlink_inode_header_2 symlink; + struct squashfs_reg_inode_header_2 reg; + struct squashfs_dir_inode_header_2 dir; + struct squashfs_ldir_inode_header_2 ldir; + struct squashfs_ipc_inode_header_2 ipc; +}; + +struct squashfs_dir_header_2 { + unsigned int count:8; + unsigned int start_block:24; +} __attribute__ ((packed)); + +struct squashfs_dir_entry_2 { + unsigned int offset:13; + unsigned int type:3; + unsigned int size:8; + char name[0]; +} __attribute__ ((packed)); + +struct squashfs_fragment_entry_2 { + unsigned int start_block; + unsigned int size; +} __attribute__ ((packed)); + +#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\ + SQUASHFS_MEMSET(s, d, n);\ + SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ + SQUASHFS_SWAP((s)->mode, d, 4, 12);\ + SQUASHFS_SWAP((s)->uid, d, 16, 8);\ + SQUASHFS_SWAP((s)->guid, d, 24, 8);\ + +#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\ +} + +#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \ + SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2)) + +#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ + sizeof(struct squashfs_dev_inode_header_2)); \ + SQUASHFS_SWAP((s)->rdev, d, 32, 16);\ +} + +#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ + sizeof(struct squashfs_symlink_inode_header_2));\ + SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\ +} + +#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ + sizeof(struct squashfs_reg_inode_header_2));\ + SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 64, 32);\ + SQUASHFS_SWAP((s)->fragment, d, 96, 32);\ + SQUASHFS_SWAP((s)->offset, d, 128, 32);\ + SQUASHFS_SWAP((s)->file_size, d, 160, 32);\ +} + +#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ + sizeof(struct squashfs_dir_inode_header_2));\ + SQUASHFS_SWAP((s)->file_size, d, 32, 19);\ + SQUASHFS_SWAP((s)->offset, d, 51, 13);\ + SQUASHFS_SWAP((s)->mtime, d, 64, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 96, 24);\ +} + +#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ + sizeof(struct squashfs_ldir_inode_header_2));\ + SQUASHFS_SWAP((s)->file_size, d, 32, 27);\ + SQUASHFS_SWAP((s)->offset, d, 59, 13);\ + SQUASHFS_SWAP((s)->mtime, d, 72, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 104, 24);\ + SQUASHFS_SWAP((s)->i_count, d, 128, 16);\ +} + +#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\ + SQUASHFS_SWAP((s)->index, d, 0, 27);\ + SQUASHFS_SWAP((s)->start_block, d, 27, 29);\ + SQUASHFS_SWAP((s)->size, d, 56, 8);\ +} +#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\ + SQUASHFS_SWAP((s)->count, d, 0, 8);\ + SQUASHFS_SWAP((s)->start_block, d, 8, 24);\ +} + +#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\ + SQUASHFS_SWAP((s)->offset, d, 0, 13);\ + SQUASHFS_SWAP((s)->type, d, 13, 3);\ + SQUASHFS_SWAP((s)->size, d, 16, 8);\ +} + +#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\ + SQUASHFS_SWAP((s)->start_block, d, 0, 32);\ + SQUASHFS_SWAP((s)->size, d, 32, 32);\ +} + +#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n) + +/* fragment and fragment table defines */ +#define SQUASHFS_FRAGMENT_BYTES_2(A) (A * sizeof(struct squashfs_fragment_entry_2)) + +#define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \ + SQUASHFS_METADATA_SIZE - 1) / \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\ + sizeof(int)) + +#endif + +#ifdef __KERNEL__ + +/* + * macros used to swap each structure entry, taking into account + * bitfields and different bitfield placing conventions on differing + * architectures + */ + +#include + +#ifdef __BIG_ENDIAN + /* convert from little endian to big endian */ +#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \ + tbits, b_pos) +#else + /* convert from big endian to little endian */ +#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \ + tbits, 64 - tbits - b_pos) +#endif + +#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\ + b_pos = pos % 8;\ + val = 0;\ + s = (unsigned char *)p + (pos / 8);\ + d = ((unsigned char *) &val) + 7;\ + for(bits = 0; bits < (tbits + b_pos); bits += 8) \ + *d-- = *s++;\ + value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\ +} + +#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n); + +#endif +#endif --- linux-2.6.27.orig/ubuntu/include/linux/tlsf.h +++ linux-2.6.27/ubuntu/include/linux/tlsf.h @@ -0,0 +1,93 @@ +/* + * Two Levels Segregate Fit memory allocator (TLSF) + * Version 2.3.2 + * + * Written by Miguel Masmano Tello + * + * Thanks to Ismael Ripoll for his suggestions and reviews + * + * Copyright (C) 2007, 2006, 2005, 2004 + * + * This code is released using a dual license strategy: GPL/LGPL + * You can choose the licence that better fits your requirements. + * + * Released under the terms of the GNU General Public License Version 2.0 + * Released under the terms of the GNU Lesser General Public License Version 2.1 + * + * This is kernel port of TLSF allocator. + * Original code can be found at: http://rtportal.upv.es/rtmalloc/ + * - Nitin Gupta (nitingupta910@gmail.com) + */ + +#ifndef _TLSF_H_ +#define _TLSF_H_ + +typedef void* (get_memory)(size_t bytes); +typedef void (put_memory)(void *ptr); + +/** + * tlsf_create_memory_pool - create dynamic memory pool + * @name: name of the pool + * @get_mem: callback function used to expand pool + * @put_mem: callback function used to shrink pool + * @init_size: inital pool size (in bytes) + * @max_size: maximum pool size (in bytes) - set this as 0 for no limit + * @grow_size: amount of memory (in bytes) added to pool whenever required + * + * All size values are rounded up to next page boundary. + */ +extern void *tlsf_create_memory_pool(const char *name, + get_memory get_mem, + put_memory put_mem, + size_t init_size, + size_t max_size, + size_t grow_size); +/** + * tlsf_destory_memory_pool - cleanup given pool + * @mem_pool: Pool to be destroyed + * + * Data structures associated with pool are freed. + * All memory allocated from pool must be freed before + * destorying it. + */ +extern void tlsf_destroy_memory_pool(void *mem_pool); + +/** + * tlsf_malloc - allocate memory from given pool + * @size: no. of bytes + * @mem_pool: pool to allocate from + */ +extern void *tlsf_malloc(size_t size, void *mem_pool); + +/** + * tlsf_calloc - allocate and zero-out memory from given pool + * @size: no. of bytes + * @mem_pool: pool to allocate from + */ +extern void *tlsf_calloc(size_t nelem, size_t elem_size, void *mem_pool); + +/** + * tlsf_free - free memory from given pool + * @ptr: address of memory to be freed + * @mem_pool: pool to free from + */ +extern void tlsf_free(void *ptr, void *mem_pool); + +/** + * tlsf_get_used_size - get memory currently used by given pool + * + * Used memory includes stored data + metadata + internal fragmentation + */ +extern size_t tlsf_get_used_size(void *mem_pool); + +/** + * tlsf_get_total_size - get total memory currently allocated for given pool + * + * This is the total memory currently allocated for this pool which includes + * used size + free size. + * + * (Total - Used) is good indicator of memory efficiency of allocator. + */ +extern size_t tlsf_get_total_size(void *mem_pool); + +#endif --- linux-2.6.27.orig/ubuntu/rfkill/av5100.c +++ linux-2.6.27/ubuntu/rfkill/av5100.c @@ -0,0 +1,174 @@ +/******************************************************************************* + + Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DRV_NAME "av5100" +#define DRV_VERSION "1.3" +#define DRV_DESCRIPTION "SW RF kill switch for Averatec 5100P" +#define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" + +static int radio = 1; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + +MODULE_PARM(radio, "i"); + +#else /* LINUX_VERSION_CODE < 2.6.0 */ + +#include +module_param(radio, int, 1); + +#endif /* LINUX_VERSION_CODE < 2.6.0 */ + +MODULE_PARM_DESC(radio, "controls state of radio (1=on, 0=off)"); + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_LICENSE("GPL"); + +#define AV5100_RADIO_ON (0xe0) +#define AV5100_RADIO_OFF (0xe1) + +static int av5100_radio = AV5100_RADIO_OFF; + +static void av5100_set_radio(int state) +{ + printk(KERN_INFO DRV_NAME ": Radio being turned %s\n", + (state == AV5100_RADIO_ON) ? "ON" : "OFF"); + outl(0x80020800, 0xcf8); + outb(0x6f, 0x0072); + outl(0x1800ffff, 0x1184); + outb(state, 0x00b2); + av5100_radio = state; +} + + +/* + * proc stuff + */ +static struct proc_dir_entry *dir_base = NULL; + +static int proc_set_radio(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + av5100_set_radio(buffer[0] == '0' ? AV5100_RADIO_OFF : AV5100_RADIO_ON); + + return count; +} + +static int proc_get_radio(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + int len = 0; + + len += snprintf(page, count, DRV_NAME ": %d\n", + av5100_radio == AV5100_RADIO_OFF ? 0 : 1); + + *eof = 1; + return len; +} + + +static void av5100_proc_cleanup(void) +{ + if (dir_base) { + remove_proc_entry("radio", dir_base); + remove_proc_entry(DRV_NAME, NULL); + dir_base = NULL; + } +} + + +static int av5100_proc_init(void) +{ + struct proc_dir_entry *ent; + int err = 0; + + dir_base = create_proc_entry(DRV_NAME, S_IFDIR, NULL); + if (dir_base == NULL) { + printk(KERN_ERR DRV_NAME ": Unable to initialise /proc/" + DRV_NAME "\n"); + err = -ENOMEM; + goto fail; + } + + + ent = create_proc_entry("radio", S_IFREG | S_IRUGO | S_IWUSR, + dir_base); + if (ent) { + ent->read_proc = proc_get_radio; + ent->write_proc = proc_set_radio; + } else { + printk(KERN_ERR + "Unable to initialize /proc/" DRV_NAME "/radio\n"); + err = -ENOMEM; + goto fail; + } + + return 0; + + fail: + av5100_proc_cleanup(); + return err; +} + +/* + * module stuff + */ +static int __init av5100_init(void) +{ + av5100_proc_init(); + + av5100_set_radio((radio == 1) ? AV5100_RADIO_ON : AV5100_RADIO_OFF); + + return 0; +} + +static void __exit av5100_exit(void) +{ + av5100_set_radio(AV5100_RADIO_OFF); + + av5100_proc_cleanup(); +} + +module_init(av5100_init); +module_exit(av5100_exit); + +/* + 1 2 3 4 5 6 7 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +*/ --- linux-2.6.27.orig/ubuntu/rfkill/pbe5.c +++ linux-2.6.27/ubuntu/rfkill/pbe5.c @@ -0,0 +1,205 @@ +/******************************************************************************* + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Author: + Pedro Ramalhais + + Based on: + av5100.c from http://ipw2100.sourceforge.net/ + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pbe5" +#define DRV_VERSION "1.3" +#define DRV_DESCRIPTION "SW RF kill switch for Packard Bell EasyNote E5" +#define DRV_AUTHOR "Pedro Ramalhais" +#define DRV_LICENSE "GPL" + +static int radio = 1; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + +MODULE_PARM(radio, "i"); + +#else /* LINUX_VERSION_CODE < 2.6.0 */ + +#include +module_param(radio, int, 1); + +#endif /* LINUX_VERSION_CODE < 2.6.0 */ + +MODULE_PARM_DESC(radio, "controls state of radio (1=on, 0=off)"); + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_AUTHOR(DRV_AUTHOR); +MODULE_LICENSE(DRV_LICENSE); + +/* + * NOTE: These values were obtained from disassembling the Icon.exe program + * installed in the Packard Bell EasyNote E5 laptop. The names were guessed, + * so don't rely on them. + */ +#define PBE5_PORT_TOGGLE 0x0b3 +#define PBE5_VALUE_TOGGLE_ON 0x01 +#define PBE5_VALUE_TOGGLE_OFF 0x00 +#define PBE5_PORT_APPLY 0x0b2 +#define PBE5_VALUE_APPLY 0xef + +// Some "booleans" =;-) +#define PBE5_RADIO_OFF 0 +#define PBE5_RADIO_ON 1 + +static int pbe5_radio_status = PBE5_RADIO_ON; + +unsigned char pbe5_get_radio(void) +{ + unsigned char val = 0x00; + + val = inb(PBE5_PORT_TOGGLE); + + return val; +} + +static void pbe5_set_radio(int state_set) +{ + pbe5_radio_status = pbe5_get_radio(); + + if (pbe5_radio_status != state_set) { + // Set the radio toggle register + outb(PBE5_VALUE_TOGGLE_ON, PBE5_PORT_TOGGLE); + // Commit the radio toggle register value + outb(PBE5_VALUE_APPLY, PBE5_PORT_APPLY); + // Update the radio status + pbe5_radio_status = pbe5_get_radio(); + + printk(KERN_INFO DRV_NAME ": Radio turned %s\n", + (state_set == PBE5_RADIO_ON) ? "ON" : "OFF"); + } else { + printk(KERN_INFO DRV_NAME ": Radio already %s\n", + (state_set == PBE5_RADIO_ON) ? "ON" : "OFF"); + } +} + + +/* + * proc stuff + */ +static struct proc_dir_entry *dir_base = NULL; + +static int proc_set_radio(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + pbe5_set_radio(buffer[0] == '0' ? PBE5_RADIO_OFF : PBE5_RADIO_ON); + + return count; +} + +static int proc_get_radio(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + int len = 0; + + len += snprintf(page, count, DRV_NAME ": %d\n", + pbe5_radio_status == PBE5_RADIO_OFF ? 0 : 1); + + *eof = 1; + return len; +} + + +static void pbe5_proc_cleanup(void) +{ + if (dir_base) { + remove_proc_entry("radio", dir_base); + remove_proc_entry(DRV_NAME, NULL); + dir_base = NULL; + } +} + + +static int pbe5_proc_init(void) +{ + struct proc_dir_entry *ent; + int err = 0; + + dir_base = create_proc_entry(DRV_NAME, S_IFDIR, NULL); + if (dir_base == NULL) { + printk(KERN_ERR DRV_NAME ": Unable to initialise /proc/" + DRV_NAME "\n"); + err = -ENOMEM; + goto fail; + } + + + ent = create_proc_entry("radio", S_IFREG | S_IRUGO | S_IWUSR, + dir_base); + if (ent) { + ent->read_proc = proc_get_radio; + ent->write_proc = proc_set_radio; + } else { + printk(KERN_ERR + "Unable to initialize /proc/" DRV_NAME "/radio\n"); + err = -ENOMEM; + goto fail; + } + + return 0; + + fail: + pbe5_proc_cleanup(); + return err; +} + +/* + * module stuff + */ +static int __init pbe5_init(void) +{ + pbe5_proc_init(); + + pbe5_set_radio((radio == 1) ? PBE5_RADIO_ON : PBE5_RADIO_OFF); + + return 0; +} + +static void __exit pbe5_exit(void) +{ + pbe5_set_radio(PBE5_RADIO_OFF); + + pbe5_proc_cleanup(); +} + +module_init(pbe5_init); +module_exit(pbe5_exit); + +/* + 1 2 3 4 5 6 7 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +*/ --- linux-2.6.27.orig/ubuntu/rfkill/Kconfig +++ linux-2.6.27/ubuntu/rfkill/Kconfig @@ -0,0 +1,7 @@ +config AVERATEC_5100P + tristate "Software kill switch for Averatec 5100P" + default m + +config PACKARDBELL_E5 + tristate "Software kill switch for Packard Bell EasyNote E5" + default m --- linux-2.6.27.orig/ubuntu/rfkill/Makefile +++ linux-2.6.27/ubuntu/rfkill/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for Ubuntu additional drivers +# + +obj-$(CONFIG_AVERATEC_5100P) += av5100.o +obj-$(CONFIG_PACKARDBELL_E5) += pbe5.o --- linux-2.6.27.orig/ubuntu/rfkill/BOM +++ linux-2.6.27/ubuntu/rfkill/BOM @@ -0,0 +1,6 @@ +Downloaded from: http://sourceforge.net/project/showfiles.php?group_id=108766 +Current Version: 1.3 +Comments: + +Had to change &proc_root to NULL due to changes in create/remove proc +entry usage. --- linux-2.6.27.orig/ubuntu/dm-raid4-5/dm-region_hash.h +++ linux-2.6.27/ubuntu/dm-raid4-5/dm-region_hash.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2003 Sistina Software Limited. + * Copyright (C) 2004-2007 Red Hat Inc. + * + * This file is released under the GPL. + */ + +#ifndef DM_RH_H +#define DM_RH_H + +#include "dm.h" +#include +#include "dm-bio-list.h" + +/*----------------------------------------------------------------- + * Region hash + *----------------------------------------------------------------*/ + +/* + * States a region can have. + */ +enum { + RH_CLEAN = 0x01, /* No writes in flight. */ + RH_DIRTY = 0x02, /* Writes in flight. */ + RH_NOSYNC = 0x04, /* Out of sync. */ + RH_RECOVERING = 0x08, /* Under resynchronization. */ + RH_ERROR = 0x10, /* Error recovering region */ +}; + +/* + * Conversion fns + */ +region_t rh_bio_to_region(void *rh, struct bio *bio); +region_t rh_sector_to_region(void *rh, sector_t sector); +sector_t rh_region_to_sector(void *rh, region_t region); + + +/* + * Functions to set a caller context in a region. + */ +void *rh_reg_get_context(void *reg); +void rh_reg_set_context(void *reg, void *context); + +/* + * Reagion hash and region parameters. + */ +region_t rh_get_region_size(void *rh); +sector_t rh_get_region_key(void *reg); + +int rh_init(void **rh, + unsigned int max_recovery, + void (*dispatch)(void *dispatch_context, struct bio_list *bios), + void *dispatch_context, + void (*wake)(void *wake_context), + void *wake_context, + struct dm_dirty_log *log, uint32_t region_size, region_t nr_regions); +void rh_exit(void *rh); + +int rh_state(void *rh, region_t region, int may_block); +void rh_update_states(void *rh); +void rh_flush(void *rh); + +void rh_inc(void *rh, region_t region); +void rh_inc_pending(void *rh, struct bio_list *bios); +void rh_dec(void *rh, region_t region); +void rh_delay(void *rh, struct bio *bio); +void rh_delay_by_region(void *rh, struct bio *bio, region_t region); + +int rh_recovery_prepare(void *rh); +void *rh_recovery_start(void *rh); +void rh_recovery_end(void *reg, int error); +void rh_stop_recovery(void *rh); +void rh_start_recovery(void *rh); + +#endif --- linux-2.6.27.orig/ubuntu/dm-raid4-5/dm-raid4-5.h +++ linux-2.6.27/ubuntu/dm-raid4-5/dm-raid4-5.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2006 Red Hat GmbH + * + * Module Author: Heinz Mauelshagen (Mauelshagen@RedHat.com) + * + * This file is released under the GPL. + * + */ + +#ifndef _DM_RAID45_H +#define _DM_RAID45_H + +/* Factor out to dm.h! */ +#define STR_LEN(ptr, str) ptr, str, strlen(ptr) + +enum lock_type { RAID45_EX, RAID45_SHARED }; + +struct dmraid45_locking_type { + /* Request a lock on a stripe. */ + void* (*lock)(sector_t key, enum lock_type type); + + /* Release a lock on a stripe. */ + void (*unlock)(void *lock_handle); + +}; + +#endif --- linux-2.6.27.orig/ubuntu/dm-raid4-5/dm-message.h +++ linux-2.6.27/ubuntu/dm-raid4-5/dm-message.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2007 Red Hat GmbH + * + * Module Author: Heinz Mauelshagen + * + * This file is released under the GPL. + * + */ + +#ifndef DM_MESSAGE_H +#define DM_MESSAGE_H + +/* Factor out to dm.h. */ +/* Reference to array end. */ +#define ARRAY_END(a) ((a) + ARRAY_SIZE(a)) + +/* Message return bits. */ +enum dm_message_return { + dm_msg_ret_ambiguous, /* Action ambiguous. */ + dm_msg_ret_inval, /* Action invalid. */ + dm_msg_ret_undef, /* Action undefined. */ + + dm_msg_ret_option, /* Option error. */ + dm_msg_ret_arg, /* Argument error. */ + dm_msg_ret_argcount, /* Argument count error. */ +}; + +/* Message argument type conversions. */ +enum dm_message_argument_type { + dm_msg_base_t, /* Basename string. */ + dm_msg_str_t, /* String. */ + dm_msg_int_t, /* Signed int. */ + dm_msg_uint_t, /* Unsigned int. */ + dm_msg_uint64_t, /* Unsigned int 64. */ +}; + +/* A message option. */ +struct dm_message_option { + unsigned num_options; + char **options; + unsigned long *actions; +}; + +/* Message arguments and types. */ +struct dm_message_argument { + unsigned num_args; + unsigned long **ptr; + enum dm_message_argument_type types[]; +}; + +/* Client message. */ +struct dm_msg { + unsigned long action; /* Identified action. */ + unsigned long ret; /* Return bits. */ + unsigned num_specs; /* # of sepcifications listed. */ + struct dm_msg_spec *specs; /* Specification list. */ + struct dm_msg_spec *spec; /* Specification selected. */ +}; + +/* Secification of the message. */ +struct dm_msg_spec { + const char *cmd; /* Name of the command (i.e. 'bandwidth'). */ + unsigned long action; + struct dm_message_option *options; + struct dm_message_argument *args; + unsigned long parm; /* Parameter to pass through to callback. */ + /* Function to process for action. */ + int (*f) (struct dm_msg *msg, void *context); +}; + +/* Parameter access macros. */ +#define DM_MSG_PARM(msg) ((msg)->spec->parm) + +#define DM_MSG_STR_ARGS(msg, idx) ((char*) *(msg)->spec->args->ptr[idx]) +#define DM_MSG_INT_ARGS(msg, idx) ((int) *(msg)->spec->args->ptr[idx]) +#define DM_MSG_UINT_ARGS(msg, idx) ((unsigned) DM_MSG_INT_ARG(msg, idx)) +#define DM_MSG_UINT64_ARGS(msg, idx) ((uint64_t) *(msg)->spec->args->ptr[idx]) + +#define DM_MSG_STR_ARG(msg) DM_MSG_STR_ARGS(msg, 0) +#define DM_MSG_INT_ARG(msg) DM_MSG_INT_ARGS(msg, 0) +#define DM_MSG_UINT_ARG(msg) DM_MSG_UINT_ARGS(msg, 0) +#define DM_MSG_UINT64_ARG(msg) DM_MSG_UINT64_ARGS(msg, 0) + + +/* Parse a message and its options and optionally call a function back. */ +int dm_message_parse(const char *caller, struct dm_msg *msg, void *context, + int argc, char **argv); + +#endif --- linux-2.6.27.orig/ubuntu/dm-raid4-5/dm-mem-cache.c +++ linux-2.6.27/ubuntu/dm-raid4-5/dm-mem-cache.c @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2006,2007 Red Hat GmbH + * + * Module Author: Heinz Mauelshagen + * + * Allocate/free total_pages to a per client page pool. + * Allocate/free memory objects with chunks (1..n) of pages_per_chunk pages + * hanging off. + * + * This file is released under the GPL. + */ + +#define DM_MEM_CACHE_VERSION "0.2" + +#include "dm.h" +#include +#include "dm-mem-cache.h" + +struct dm_mem_cache_client { + spinlock_t lock; + mempool_t *objs_pool; + struct page_list *free_list; + unsigned objects; + unsigned chunks; + unsigned free_pages; + unsigned total_pages; +}; + +/* + * Free pages and page_list elements of client. + */ +static void free_cache_pages(struct page_list *list) +{ + while (list) { + struct page_list *pl = list; + + list = pl->next; + BUG_ON(!pl->page); + __free_page(pl->page); + kfree(pl); + } +} + +/* + * Alloc number of pages and page_list elements as required by client. + */ +static struct page_list *alloc_cache_pages(unsigned pages) +{ + struct page_list *pl, *ret = NULL; + struct page *page; + + while (pages--) { + page = alloc_page(GFP_NOIO); + if (!page) + goto err; + + pl = kmalloc(sizeof(*pl), GFP_NOIO); + if (!pl) { + __free_page(page); + goto err; + } + + pl->page = page; + pl->next = ret; + ret = pl; + } + + return ret; + + err: + free_cache_pages(ret); + return NULL; +} + +/* + * Allocate page_list elements from the pool to chunks of the mem object + */ +static void alloc_chunks(struct dm_mem_cache_client *cl, + struct dm_mem_cache_object *obj, + unsigned pages_per_chunk) +{ + unsigned chunks = cl->chunks; + unsigned long flags; + + local_irq_save(flags); + local_irq_disable(); + while (chunks--) { + unsigned p = pages_per_chunk; + + obj[chunks].pl = NULL; + + while (p--) { + struct page_list *pl; + + /* Take next element from free list */ + spin_lock(&cl->lock); + pl = cl->free_list; + BUG_ON(!pl); + cl->free_list = pl->next; + spin_unlock(&cl->lock); + + pl->next = obj[chunks].pl; + obj[chunks].pl = pl; + } + } + + local_irq_restore(flags); +} + +/* + * Free page_list elements putting them back onto free list + */ +static void free_chunks(struct dm_mem_cache_client *cl, + struct dm_mem_cache_object *obj) +{ + unsigned chunks = cl->chunks; + unsigned long flags; + struct page_list *next, *pl; + + local_irq_save(flags); + local_irq_disable(); + while (chunks--) { + for (pl = obj[chunks].pl; pl; pl = next) { + next = pl->next; + + spin_lock(&cl->lock); + pl->next = cl->free_list; + cl->free_list = pl; + cl->free_pages++; + spin_unlock(&cl->lock); + } + } + + local_irq_restore(flags); +} + +/* + * Create/destroy dm memory cache client resources. + */ +struct dm_mem_cache_client * +dm_mem_cache_client_create(unsigned total_pages, unsigned objects, + unsigned chunks) +{ + struct dm_mem_cache_client *client; + + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return ERR_PTR(-ENOMEM); + + client->objs_pool = mempool_create_kmalloc_pool(objects, chunks * sizeof(struct dm_mem_cache_object)); + if (!client->objs_pool) + goto err; + + client->free_list = alloc_cache_pages(total_pages); + if (!client->free_list) + goto err1; + + spin_lock_init(&client->lock); + client->objects = objects; + client->chunks = chunks; + client->free_pages = client->total_pages = total_pages; + return client; + + err1: + mempool_destroy(client->objs_pool); + err: + kfree(client); + return ERR_PTR(-ENOMEM); +} + +void dm_mem_cache_client_destroy(struct dm_mem_cache_client *cl) +{ + BUG_ON(cl->free_pages != cl->total_pages); + free_cache_pages(cl->free_list); + mempool_destroy(cl->objs_pool); + kfree(cl); +} + +/* + * Grow a clients cache by an amount of pages. + * + * Don't call from interrupt context! + */ +int dm_mem_cache_grow(struct dm_mem_cache_client *cl, + unsigned pages_per_chunk) +{ + unsigned pages = cl->chunks * pages_per_chunk; + struct page_list *pl = alloc_cache_pages(pages), *last = pl; + + if (!pl) + return -ENOMEM; + + while (last->next) + last = last->next; + + spin_lock_irq(&cl->lock); + last->next = cl->free_list; + cl->free_list = pl; + cl->free_pages += pages; + cl->total_pages += pages; + cl->objects++; + spin_unlock_irq(&cl->lock); + + mempool_resize(cl->objs_pool, cl->objects, GFP_NOIO); + return 0; +} + +/* Shrink a clients cache by an amount of pages */ +int dm_mem_cache_shrink(struct dm_mem_cache_client *cl, + unsigned pages_per_chunk) +{ + int r = 0; + unsigned pages = cl->chunks * pages_per_chunk, p = pages; + unsigned long flags; + struct page_list *last = NULL, *pl, *pos; + + spin_lock_irqsave(&cl->lock, flags); + pl = pos = cl->free_list; + while (p-- && pos->next) { + last = pos; + pos = pos->next; + } + + if (++p) + r = -ENOMEM; + else { + cl->free_list = pos; + cl->free_pages -= pages; + cl->total_pages -= pages; + cl->objects--; + last->next = NULL; + } + spin_unlock_irqrestore(&cl->lock, flags); + + if (!r) { + free_cache_pages(pl); + mempool_resize(cl->objs_pool, cl->objects, GFP_NOIO); + } + + return r; +} + +/* + * Allocate/free a memory object + * + * Can be called from interrupt context + */ +struct dm_mem_cache_object *dm_mem_cache_alloc(struct dm_mem_cache_client *cl, + unsigned pages_per_chunk) +{ + int r = 0; + unsigned pages = cl->chunks * pages_per_chunk; + unsigned long flags; + struct dm_mem_cache_object *obj; + + obj = mempool_alloc(cl->objs_pool, GFP_NOIO); + if (!obj) + return ERR_PTR(-ENOMEM); + + spin_lock_irqsave(&cl->lock, flags); + if (pages > cl->free_pages) + r = -ENOMEM; + else + cl->free_pages -= pages; + spin_unlock_irqrestore(&cl->lock, flags); + + if (r) { + mempool_free(obj, cl->objs_pool); + return ERR_PTR(r); + } + + alloc_chunks(cl, obj, pages_per_chunk); + return obj; +} + +void dm_mem_cache_free(struct dm_mem_cache_client *cl, + struct dm_mem_cache_object *obj) +{ + free_chunks(cl, obj); + mempool_free(obj, cl->objs_pool); +} + +EXPORT_SYMBOL(dm_mem_cache_client_create); +EXPORT_SYMBOL(dm_mem_cache_client_destroy); +EXPORT_SYMBOL(dm_mem_cache_alloc); +EXPORT_SYMBOL(dm_mem_cache_free); +EXPORT_SYMBOL(dm_mem_cache_grow); +EXPORT_SYMBOL(dm_mem_cache_shrink); + +MODULE_DESCRIPTION(DM_NAME " dm memory cache"); +MODULE_AUTHOR("Heinz Mauelshagen "); +MODULE_LICENSE("GPL"); --- linux-2.6.27.orig/ubuntu/dm-raid4-5/Kconfig +++ linux-2.6.27/ubuntu/dm-raid4-5/Kconfig @@ -0,0 +1,6 @@ +config DM_RAID45 + tristate "RAID 4/5 target (EXPERIMENTAL)" + depends on BLK_DEV_DM && EXPERIMENTAL + default m + ---help--- + A target that supports RAID4 and RAID5 mappings. --- linux-2.6.27.orig/ubuntu/dm-raid4-5/Makefile +++ linux-2.6.27/ubuntu/dm-raid4-5/Makefile @@ -0,0 +1,3 @@ +EXTRA_CFLAGS += -I$(srctree)/drivers/md + +obj-$(CONFIG_DM_RAID45) += dm-raid4-5.o dm-mem-cache.o dm-region_hash.o dm-message.o --- linux-2.6.27.orig/ubuntu/dm-raid4-5/dm-region_hash.c +++ linux-2.6.27/ubuntu/dm-raid4-5/dm-region_hash.c @@ -0,0 +1,643 @@ +/* + * Copyright (C) 2003 Sistina Software Limited. + * Copyright (C) 2004-2007 Red Hat Inc. + * + * This file is released under the GPL. + */ + +#include "dm.h" +#include +#include "dm-region_hash.h" + +#include +#include +#include +#include + +#define DM_MSG_PREFIX "region hash" + +/*----------------------------------------------------------------- + * Region hash + * + * The set splits itself up into discrete regions. + * Each region can be in one of three states: + * + * o clean + * o dirty, + * o nosync. + * + * There is no need to put clean regions in the hash. + * + * + * In addition to being present in the hash table a region _may_ + * be present on one of three lists. + * + * clean_regions: Regions on this list have no io pending to + * them, they are in sync, we are no longer interested in them, + * they are dull. rh_update_states() will remove them from the + * hash table. + * + * quiesced_regions: These regions have been spun down, ready + * for recovery. rh_recovery_start() will remove regions from + * this list and hand them to kmirrord, which will schedule the + * recovery io with kcopyd. + * + * recovered_regions: Regions that kcopyd has successfully + * recovered. rh_update_states() will now schedule any delayed + * io, up the recovery_count, and remove the region from the hash. + * + * There are 2 locks: + * A rw spin lock 'hash_lock' protects just the hash table, + * this is never held in write mode from interrupt context, + * which I believe means that we only have to disable irqs when + * doing a write lock. + * + * An ordinary spin lock 'region_lock' that protects the three + * lists in the region_hash, with the 'state', 'list' and + * 'delayed_bios' fields of the regions. This is used from irq + * context, so all other uses will have to suspend local irqs. + *---------------------------------------------------------------*/ +enum region_hash_flags { + RECOVERY, +}; + +struct region_hash { + unsigned int max_recovery; /* Max # of regions to recover in parallel */ + unsigned long flags; + + /* Callback function to dispatch queued writes on recovered regions. */ + void (*dispatch)(void *context, struct bio_list *bios); + void *dispatch_context; + + /* Callback function to wakeup callers worker thread. */ + void (*wake)(void *context); + void *wake_context; + + uint32_t region_size; + unsigned int region_shift; + + /* holds persistent region state */ + struct dm_dirty_log *log; + + /* hash table */ + rwlock_t hash_lock; + mempool_t *region_pool; + unsigned int mask; + unsigned int nr_buckets; + unsigned int prime; + unsigned int shift; + struct list_head *buckets; + + spinlock_t region_lock; + struct semaphore recovery_count; + struct list_head clean_regions; + struct list_head quiesced_regions; + struct list_head recovered_regions; +}; + +struct region { + struct region_hash *rh; /* FIXME: can we get rid of this ? */ + region_t key; + int state; + void *context; /* Caller context. */ + + struct list_head hash_list; + struct list_head list; + + atomic_t pending; + struct bio_list delayed_bios; +}; + +/* + * Conversion fns + */ +region_t rh_sector_to_region(void *rh, sector_t sector) +{ + return sector >> ((struct region_hash*) rh)->region_shift; +} + +region_t rh_bio_to_region(void *rh, struct bio *bio) +{ + return rh_sector_to_region(rh, bio->bi_sector); +} + +sector_t rh_region_to_sector(void *rh, region_t region) +{ + return region << ((struct region_hash*) rh)->region_shift; +} + +/* + * Retrival fns. + */ +region_t rh_get_region_key(void *reg) +{ + return ((struct region *)reg)->key; +} + +sector_t rh_get_region_size(void *rh) +{ + return ((struct region_hash *)rh)->region_size; +} + +/* Squirrel a context with a region. */ +void *rh_reg_get_context(void *reg) +{ + return ((struct region*) reg)->context; +} + +void rh_reg_set_context(void *reg, void *context) +{ + ((struct region*) reg)->context = context; +} + +/* + * Region struct allocation/free. + */ +static void *region_alloc(unsigned int gfp_mask, void *pool_data) +{ + return kmalloc(sizeof(struct region), gfp_mask); +} + +static void region_free(void *element, void *pool_data) +{ + kfree(element); +} + +#define MIN_REGIONS 64 +int rh_init(void **region_hash, + unsigned int max_recovery, + + void (*dispatch)(void *dispatch_context, struct bio_list *bios), + void *dispatch_context, + void (*wake)(void *wake_context), + void *wake_context, + struct dm_dirty_log *log, uint32_t region_size, region_t nr_regions) +{ + unsigned int nr_buckets, max_buckets; + unsigned hash_primes[] = { + /* Table of primes for rh_hash/table size optimization. */ + 3, 7, 13, 27, 53, 97, 193, 389, 769, + 1543, 3079, 6151, 12289, 24593, + }; + size_t i; + struct region_hash *rh; + + if (region_size & (region_size - 1)) { + DMERR("region size must be 2^^n"); + return -EINVAL; + } + + rh = kmalloc(sizeof(*rh), GFP_KERNEL); + if (!rh) { + DMERR("unable to allocate region hash memory"); + return -ENOMEM; + } + + rh->max_recovery = max_recovery; + rh->dispatch = dispatch; + rh->dispatch_context = dispatch_context; + rh->wake = wake; + rh->wake_context = wake_context; + rh->log = log; + rh->region_size = region_size; + rh->region_shift = ffs(region_size) - 1; + rwlock_init(&rh->hash_lock); + + /* Calculate a suitable number of buckets for our hash table. */ + max_buckets = nr_regions >> 6; + for (nr_buckets = 128u; nr_buckets < max_buckets; nr_buckets <<= 1); + nr_buckets >>= 1; + rh->mask = rh->nr_buckets = nr_buckets; + rh->mask--; + rh->shift = ffs(nr_buckets); + rh->prime = hash_primes[rh->shift - 1]; + if (rh->prime > ARRAY_SIZE(hash_primes) - 2) + rh->prime = ARRAY_SIZE(hash_primes) - 1; + + rh->buckets = vmalloc(nr_buckets * sizeof(*rh->buckets)); + if (!rh->buckets) { + DMERR("unable to allocate region hash bucket memory"); + vfree(rh); + return -ENOMEM; + } + + for (i = 0; i < nr_buckets; i++) + INIT_LIST_HEAD(rh->buckets + i); + + spin_lock_init(&rh->region_lock); + sema_init(&rh->recovery_count, 0); + INIT_LIST_HEAD(&rh->clean_regions); + INIT_LIST_HEAD(&rh->quiesced_regions); + INIT_LIST_HEAD(&rh->recovered_regions); + + rh->region_pool = mempool_create(MIN_REGIONS, region_alloc, + region_free, NULL); + if (!rh->region_pool) { + vfree(rh->buckets); + vfree(rh); + return -ENOMEM; + } + + *region_hash = rh; + + return 0; +} + +void rh_exit(void *v) +{ + unsigned int h; + struct region *reg, *tmp; + struct region_hash *rh = v; + + BUG_ON(!list_empty(&rh->quiesced_regions)); + + for (h = 0; h < rh->nr_buckets; h++) { + list_for_each_entry_safe(reg, tmp, rh->buckets + h, hash_list) { + BUG_ON(atomic_read(®->pending)); + mempool_free(reg, rh->region_pool); + } + } + + dm_dirty_log_destroy(rh->log); + + if (rh->region_pool) + mempool_destroy(rh->region_pool); + + vfree(rh->buckets); + kfree(rh); +} + +static inline unsigned int rh_hash(struct region_hash *rh, region_t region) +{ + return (unsigned int) ((region * rh->prime) >> rh->shift) & rh->mask; +} + +static struct region *__rh_lookup(struct region_hash *rh, region_t region) +{ + struct region *reg; + struct list_head *bucket = rh->buckets + rh_hash(rh, region); + + list_for_each_entry(reg, bucket, hash_list) { + if (reg->key == region) + return reg; + } + + return NULL; +} + +static void __rh_insert(struct region_hash *rh, struct region *reg) +{ + unsigned int h = rh_hash(rh, reg->key); + list_add(®->hash_list, rh->buckets + h); +} + +static struct region *__rh_alloc(struct region_hash *rh, region_t region) +{ + struct region *reg, *nreg; + + read_unlock(&rh->hash_lock); + + nreg = mempool_alloc(rh->region_pool, GFP_NOIO); + nreg->state = rh->log->type->in_sync(rh->log, region, 1) ? + RH_CLEAN : RH_NOSYNC; + nreg->rh = rh; + nreg->key = region; + + INIT_LIST_HEAD(&nreg->list); + + atomic_set(&nreg->pending, 0); + bio_list_init(&nreg->delayed_bios); + + write_lock_irq(&rh->hash_lock); + + reg = __rh_lookup(rh, region); + if (reg) + /* we lost the race */ + mempool_free(nreg, rh->region_pool); + else { + __rh_insert(rh, nreg); + if (nreg->state == RH_CLEAN) { + spin_lock(&rh->region_lock); + list_add(&nreg->list, &rh->clean_regions); + spin_unlock(&rh->region_lock); + } + reg = nreg; + } + + write_unlock_irq(&rh->hash_lock); + read_lock(&rh->hash_lock); + + return reg; +} + +static inline struct region *__rh_find(struct region_hash *rh, region_t region) +{ + struct region *reg; + + reg = __rh_lookup(rh, region); + if (!reg) + reg = __rh_alloc(rh, region); + + return reg; +} + +int rh_state(void *v, region_t region, int may_block) +{ + int r = 0; + struct region *reg; + struct region_hash *rh = v; + + read_lock(&rh->hash_lock); + reg = __rh_lookup(rh, region); + if (reg) + r = reg->state; + read_unlock(&rh->hash_lock); + + if (r) + return r; + + /* + * The region wasn't in the hash, so we fall back to the dirty log. + */ + r = rh->log->type->in_sync(rh->log, region, may_block); + + /* + * Any error from the dirty log (eg. -EWOULDBLOCK) gets + * taken as a RH_NOSYNC + */ + return r == 1 ? RH_CLEAN : RH_NOSYNC; +} + +void rh_update_states(void *v) +{ + struct region *reg, *next; + struct region_hash *rh = v; + LIST_HEAD(clean); + LIST_HEAD(recovered); + + /* + * Quickly grab the lists. + */ + write_lock_irq(&rh->hash_lock); + spin_lock(&rh->region_lock); + if (!list_empty(&rh->clean_regions)) { + list_splice(&rh->clean_regions, &clean); + INIT_LIST_HEAD(&rh->clean_regions); + + list_for_each_entry(reg, &clean, list) + list_del(®->hash_list); + } + + if (!list_empty(&rh->recovered_regions)) { + list_splice(&rh->recovered_regions, &recovered); + INIT_LIST_HEAD(&rh->recovered_regions); + + list_for_each_entry(reg, &recovered, list) + list_del(®->hash_list); + } + + spin_unlock(&rh->region_lock); + write_unlock_irq(&rh->hash_lock); + + /* + * All the regions on the recovered and clean lists have + * now been pulled out of the system, so no need to do + * any more locking. + */ + list_for_each_entry_safe (reg, next, &recovered, list) { + if (reg->state != RH_ERROR) + rh->log->type->clear_region(rh->log, reg->key); + + rh->log->type->set_region_sync(rh->log, reg->key, + reg->state != RH_ERROR); + up(&rh->recovery_count); + if (reg->delayed_bios.head) + rh->dispatch(rh->dispatch_context, ®->delayed_bios); + + mempool_free(reg, rh->region_pool); + } + + list_for_each_entry_safe(reg, next, &clean, list) { + rh->log->type->clear_region(rh->log, reg->key); + mempool_free(reg, rh->region_pool); + } + + rh_flush(rh); +} + +void rh_inc(void *v, region_t region) +{ + struct region *reg; + struct region_hash *rh = v; + + read_lock(&rh->hash_lock); + reg = __rh_find(rh, region); + if (reg->state == RH_CLEAN) { + rh->log->type->mark_region(rh->log, reg->key); + + spin_lock_irq(&rh->region_lock); + reg->state = RH_DIRTY; + list_del_init(®->list); /* Take off the clean list. */ + spin_unlock_irq(&rh->region_lock); + } + + atomic_inc(®->pending); + read_unlock(&rh->hash_lock); +} + +void rh_inc_pending(void *v, struct bio_list *bios) +{ + struct bio *bio; + struct region_hash *rh = v; + + for (bio = bios->head; bio; bio = bio->bi_next) + rh_inc(rh, rh_bio_to_region(rh, bio)); +} + +void rh_dec(void *v, region_t region) +{ + unsigned long flags; + struct region *reg; + struct region_hash *rh = v; + + read_lock(&rh->hash_lock); + reg = __rh_lookup(rh, region); + read_unlock(&rh->hash_lock); + + BUG_ON(!reg); + + if (atomic_dec_and_test(®->pending)) { + spin_lock_irqsave(&rh->region_lock, flags); + if (reg->state == RH_RECOVERING) { + list_add_tail(®->list, &rh->quiesced_regions); + } else { + reg->state = RH_CLEAN; + list_add(®->list, &rh->clean_regions); + } + spin_unlock_irqrestore(&rh->region_lock, flags); + } +} + +/* + * Starts quiescing a region in preparation for recovery. + */ +static int __rh_recovery_prepare(struct region_hash *rh) +{ + int r; + struct region *reg; + region_t region; + + /* + * Ask the dirty log what's next. + */ + r = rh->log->type->get_resync_work(rh->log, ®ion); + if (r <= 0) + return r; + + /* + * Get this region, and start it quiescing + * by setting the recovering flag. + */ + read_lock(&rh->hash_lock); + reg = __rh_find(rh, region); + read_unlock(&rh->hash_lock); + + spin_lock_irq(&rh->region_lock); + + reg->state = RH_RECOVERING; + + /* Already quiesced ? */ + list_del_init(®->list); + if (!atomic_read(®->pending)) + list_add(®->list, &rh->quiesced_regions); + + spin_unlock_irq(&rh->region_lock); + + return 1; +} + +int rh_recovery_prepare(void *v) +{ + struct region_hash *rh = v; + + if (test_bit(RECOVERY, &rh->flags)) { + while (!down_trylock(&rh->recovery_count)) { + if (__rh_recovery_prepare(rh) <= 0) { + up(&rh->recovery_count); + return -ENOENT; + } + } + } + + return 0; +} + +/* + * Returns any quiesced regions. + */ +void *rh_recovery_start(void *v) +{ + struct region *reg = NULL; + struct region_hash *rh = v; + + spin_lock_irq(&rh->region_lock); + if (!list_empty(&rh->quiesced_regions)) { + reg = list_entry(rh->quiesced_regions.next, + struct region, list); + list_del_init(®->list); /* Remove from the quiesced list. */ + } + spin_unlock_irq(&rh->region_lock); + + return (void*) reg; +} + +/* + * Put region on list of recovered ones. + */ +void rh_recovery_end(void *v, int error) +{ + struct region *reg = v; + struct region_hash *rh = reg->rh; + + if (error) + reg->state = RH_ERROR; + + spin_lock_irq(&rh->region_lock); + list_add(®->list, &rh->recovered_regions); + spin_unlock_irq(&rh->region_lock); +} + +void rh_flush(void *v) +{ + struct region_hash *rh = v; + + rh->log->type->flush(rh->log); +} + +void rh_delay_by_region(void *v, struct bio *bio, region_t region) +{ + struct region_hash *rh = v; + struct region *reg; + + read_lock(&rh->hash_lock); + reg = __rh_find(rh, region); + bio_list_add(®->delayed_bios, bio); + read_unlock(&rh->hash_lock); +} + +void rh_delay(void *v, struct bio *bio) +{ + return rh_delay_by_region(v, bio, rh_bio_to_region(v, bio)); +} + +void rh_stop_recovery(void *v) +{ + int i; + struct region_hash *rh = v; + + clear_bit(RECOVERY, &rh->flags); + rh->wake(rh->wake_context); + + /* wait for any recovering regions */ + for (i = 0; i < rh->max_recovery; i++) + down(&rh->recovery_count); +} + +void rh_start_recovery(void *v) +{ + int i; + struct region_hash *rh = v; + + set_bit(RECOVERY, &rh->flags); + for (i = 0; i < rh->max_recovery; i++) + up(&rh->recovery_count); + + rh->wake(rh->wake_context); +} + +EXPORT_SYMBOL(rh_bio_to_region); +EXPORT_SYMBOL(rh_sector_to_region); +EXPORT_SYMBOL(rh_region_to_sector); +EXPORT_SYMBOL(rh_init); +EXPORT_SYMBOL(rh_exit); +EXPORT_SYMBOL(rh_state); +EXPORT_SYMBOL(rh_update_states); +EXPORT_SYMBOL(rh_flush); +EXPORT_SYMBOL(rh_inc); +EXPORT_SYMBOL(rh_inc_pending); +EXPORT_SYMBOL(rh_dec); +EXPORT_SYMBOL(rh_delay); +EXPORT_SYMBOL(rh_delay_by_region); +EXPORT_SYMBOL(rh_recovery_prepare); +EXPORT_SYMBOL(rh_recovery_start); +EXPORT_SYMBOL(rh_recovery_end); +EXPORT_SYMBOL(rh_stop_recovery); +EXPORT_SYMBOL(rh_start_recovery); +EXPORT_SYMBOL(rh_reg_get_context); +EXPORT_SYMBOL(rh_reg_set_context); +EXPORT_SYMBOL(rh_get_region_key); +EXPORT_SYMBOL(rh_get_region_size); + +MODULE_DESCRIPTION(DM_NAME " region hash"); +MODULE_AUTHOR("Heinz Mauelshagen "); +MODULE_LICENSE("GPL"); --- linux-2.6.27.orig/ubuntu/dm-raid4-5/dm-mem-cache.h +++ linux-2.6.27/ubuntu/dm-raid4-5/dm-mem-cache.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2006,2007 Red Hat GmbH + * + * Module Author: Heinz Mauelshagen + * + * Allocate/free total_pages to a per client page pool. + * Allocate/free memory objects with chunks (1..n) of pages_per_chunk pages + * hanging off. + * + * This file is released under the GPL. + */ + +#ifndef _DM_MEM_CACHE_H +#define _DM_MEM_CACHE_H + +#define DM_MEM_CACHE_H_VERSION "0.1" + +#include "dm.h" + +static inline struct page_list *pl_elem(struct page_list *pl, unsigned int p) +{ + while (pl && p--) + pl = pl->next; + + return pl; +} + +struct dm_mem_cache_object { + struct page_list *pl; /* Dynamically allocated array */ + void *private; /* Caller context reference */ +}; + +struct dm_mem_cache_client; + +/* + * Create/destroy dm memory cache client resources. + */ +struct dm_mem_cache_client *dm_mem_cache_client_create( + unsigned int total_pages, unsigned int objects, unsigned int chunks); +void dm_mem_cache_client_destroy(struct dm_mem_cache_client *client); + +/* + * Grow/shrink a dm memory cache client resources. + */ +int dm_mem_cache_grow(struct dm_mem_cache_client *client, unsigned int pages); +int dm_mem_cache_shrink(struct dm_mem_cache_client *client, unsigned int pages); + +/* + * Allocate/free a memory object + */ +struct dm_mem_cache_object * +dm_mem_cache_alloc(struct dm_mem_cache_client *client, + unsigned int pages_per_chunk); +void dm_mem_cache_free(struct dm_mem_cache_client *client, + struct dm_mem_cache_object *object); + +#endif --- linux-2.6.27.orig/ubuntu/dm-raid4-5/dm-raid4-5.c +++ linux-2.6.27/ubuntu/dm-raid4-5/dm-raid4-5.c @@ -0,0 +1,4422 @@ +/* + * Copyright (C) 2005-2008 Red Hat GmbH + * + * Module Author: Heinz Mauelshagen + * + * This file is released under the GPL. + * + * WARNING: this is Alpha software wich can corrupt your data! + * + * + * Linux 2.6 Device Mapper RAID4 and RAID5 target. + * + * Supports: + * o RAID4 with dedicated and selectable parity device + * o RAID5 with rotating parity (left+right, symmetric+asymmetric) + * + * + * Thanks to MD for: + * o the raid address calculation algorithm + * o the base of the biovec <-> page list copier. + * + * + * Uses region hash to keep track of how many writes are in flight to + * regions in order to use dirty log to keep state of regions to recover: + * + * o clean regions (those which are synchronized + * and don't have write io in flight) + * o dirty regions (those with write io in flight) + * + * + * On startup, any dirty regions are migrated to the 'nosync' state + * and are subject to recovery by the daemon. + * + * See raid_ctr() for table definition. + * + * + * FIXME: + * o add virtual interface for locking + * o remove instrumentation (REMOVEME:) + * + */ + +static const char *version = "v0.2427"; + +#include "dm.h" +#include "dm-bio-list.h" +#include +#include +#include "dm-mem-cache.h" +#include "dm-message.h" +#include "dm-region_hash.h" +#include "dm-raid4-5.h" +#include +#include + +#define STR_LEN(ptr, str) ptr, str, strlen(ptr) +/* + * Configurable parameters + */ +#define INLINE + +/* Default # of stripes if not set in constructor. */ +#define STRIPES 64 + +/* Minimum/maximum # of selectable stripes. */ +#define STRIPES_MIN 8 +#define STRIPES_MAX 16384 + +/* Default chunk size in sectors if not set in constructor. */ +#define CHUNK_SIZE 64 + +/* Default io size in sectors if not set in constructor. */ +#define IO_SIZE_MIN SECTORS_PER_PAGE +#define IO_SIZE IO_SIZE_MIN + +/* Maximum setable chunk size in sectors. */ +#define CHUNK_SIZE_MAX 16384 + +/* Recover io size default in sectors. */ +#define RECOVER_IO_SIZE_MIN 64 +#define RECOVER_IO_SIZE 256 + +/* Default percentage recover io bandwidth. */ +#define BANDWIDTH 10 +#define BANDWIDTH_MIN 1 +#define BANDWIDTH_MAX 100 +/* + * END Configurable parameters + */ + +#define TARGET "dm-raid45" +#define DAEMON "kraid45d" +#define DM_MSG_PREFIX TARGET + +#define SECTORS_PER_PAGE (PAGE_SIZE >> SECTOR_SHIFT) + +/* Amount/size for __xor(). */ +#define SECTORS_PER_XOR SECTORS_PER_PAGE +#define XOR_SIZE PAGE_SIZE + +/* Derive raid_set from stripe_cache pointer. */ +#define RS(x) container_of(x, struct raid_set, sc) + +/* Check value in range. */ +#define range_ok(i, min, max) (i >= min && i <= max) + +/* Page reference. */ +#define PAGE(stripe, p) ((stripe)->obj[p].pl->page) + +/* Bio list reference. */ +#define BL(stripe, p, rw) (stripe->ss[p].bl + rw) + +/* Page list reference. */ +#define PL(stripe, p) (stripe->obj[p].pl) + +/* Check argument is power of 2. */ +#define POWER_OF_2(a) (!(a & (a - 1))) + +/* xor optimization. */ +typedef unsigned long xor_t; + +/* Factor out to dm-bio-list.h */ +static inline void bio_list_push(struct bio_list *bl, struct bio *bio) +{ + bio->bi_next = bl->head; + bl->head = bio; + + if (!bl->tail) + bl->tail = bio; +} + +/* Factor out to dm.h */ +#define TI_ERR_RET(str, ret) \ + do { ti->error = DM_MSG_PREFIX ": " str; return ret; } while(0); +#define TI_ERR(str) TI_ERR_RET(str, -EINVAL) + +/*----------------------------------------------------------------- + * Stripe cache + * + * Cache for all reads and writes to raid sets (operational or degraded) + * + * We need to run all data to and from a RAID set through this cache, + * because parity chunks need to get calculated from data chunks + * or, in the degraded/resynchronization case, missing chunks need + * to be reconstructed using the other chunks of the stripe. + *---------------------------------------------------------------*/ +/* Protect kmem cache # counter. */ +static atomic_t _stripe_sc_nr = ATOMIC_INIT(-1); /* kmem cache # counter. */ + +/* A stripe set (holds bios hanging off). */ +struct stripe_set { + struct stripe *stripe; /* Backpointer to stripe for endio(). */ + struct bio_list bl[3]; /* Reads, writes, and writes merged. */ +#define WRITE_MERGED 2 +}; + +#if READ != 0 || WRITE != 1 +#error dm-raid45: READ/WRITE != 0/1 used as index!!! +#endif + +/* + * Stripe linked list indexes. Keep order, because the stripe + * and the stripe cache rely on the first 3! + */ +enum list_types { + LIST_IO = 0, /* Stripes with io pending. */ + LIST_ENDIO, /* Stripes to endio. */ + LIST_LRU, /* Least recently used stripes. */ + LIST_HASH, /* Hashed stripes. */ + NR_LISTS, /* To size array in struct stripe. */ +}; + +enum lock_types { + LOCK_ENDIO = 0, /* Protect endio list. */ + LOCK_LRU, /* Protect lru list. */ + NR_LOCKS, /* To size array in struct stripe_cache. */ +}; + +/* A stripe: the io object to handle all reads and writes to a RAID set. */ +struct stripe { + struct stripe_cache *sc; /* Backpointer to stripe cache. */ + + sector_t key; /* Hash key. */ + sector_t region; /* Region stripe is mapped to. */ + + /* Reference count. */ + atomic_t cnt; + + struct { + unsigned long flags; /* flags (see below). */ + + /* + * Pending ios in flight: + * + * used as a 'lock' to control move of stripe to endio list + */ + atomic_t pending; /* Pending ios in flight. */ + + /* Sectors to read and write for multi page stripe sets. */ + unsigned size; + } io; + + /* Lock on stripe (for clustering). */ + void *lock; + + /* + * 4 linked lists: + * o io list to flush io + * o endio list + * o LRU list to put stripes w/o reference count on + * o stripe cache hash + */ + struct list_head lists[NR_LISTS]; + + struct { + unsigned short parity; /* Parity chunk index. */ + short recover; /* Recovery chunk index. */ + } idx; + + /* This sets memory cache object (dm-mem-cache). */ + struct dm_mem_cache_object *obj; + + /* Array of stripe sets (dynamically allocated). */ + struct stripe_set ss[0]; +}; + +/* States stripes can be in (flags field). */ +enum stripe_states { + STRIPE_ACTIVE, /* Active io on stripe. */ + STRIPE_ERROR, /* io error on stripe. */ + STRIPE_MERGED, /* Writes got merged. */ + STRIPE_READ, /* Read. */ + STRIPE_RBW, /* Read-before-write. */ + STRIPE_RECONSTRUCT, /* reconstruct of a missing chunk required. */ + STRIPE_RECOVER, /* Stripe used for RAID set recovery. */ +}; + +/* ... and macros to access them. */ +#define BITOPS(name, what, var, flag) \ +static inline int TestClear ## name ## what(struct var *v) \ +{ return test_and_clear_bit(flag, &v->io.flags); } \ +static inline int TestSet ## name ## what(struct var *v) \ +{ return test_and_set_bit(flag, &v->io.flags); } \ +static inline void Clear ## name ## what(struct var *v) \ +{ clear_bit(flag, &v->io.flags); } \ +static inline void Set ## name ## what(struct var *v) \ +{ set_bit(flag, &v->io.flags); } \ +static inline int name ## what(struct var *v) \ +{ return test_bit(flag, &v->io.flags); } + + +BITOPS(Stripe, Active, stripe, STRIPE_ACTIVE) +BITOPS(Stripe, Merged, stripe, STRIPE_MERGED) +BITOPS(Stripe, Error, stripe, STRIPE_ERROR) +BITOPS(Stripe, Read, stripe, STRIPE_READ) +BITOPS(Stripe, RBW, stripe, STRIPE_RBW) +BITOPS(Stripe, Reconstruct, stripe, STRIPE_RECONSTRUCT) +BITOPS(Stripe, Recover, stripe, STRIPE_RECOVER) + +/* A stripe hash. */ +struct stripe_hash { + struct list_head *hash; + unsigned buckets; + unsigned mask; + unsigned prime; + unsigned shift; +}; + +/* A stripe cache. */ +struct stripe_cache { + /* Stripe hash. */ + struct stripe_hash hash; + + /* Stripes with io to flush, stripes to endio and LRU lists. */ + struct list_head lists[3]; + + /* Locks to protect endio and lru lists. */ + spinlock_t locks[NR_LOCKS]; + + /* Slab cache to allocate stripes from. */ + struct { + struct kmem_cache *cache; /* Cache itself. */ + char name[32]; /* Unique name. */ + } kc; + + struct dm_io_client *dm_io_client; /* dm-io client resource context. */ + + /* dm-mem-cache client resource context. */ + struct dm_mem_cache_client *dm_mem_cache_client; + + int stripes_parm; /* # stripes parameter from constructor. */ + atomic_t stripes; /* actual # of stripes in cache. */ + atomic_t stripes_to_shrink; /* # of stripes to shrink cache by. */ + atomic_t stripes_last; /* last # of stripes in cache. */ + atomic_t active_stripes; /* actual # of active stripes in cache. */ + + /* REMOVEME: */ + atomic_t max_active_stripes; /* actual # of active stripes in cache. */ +}; + +/* Flag specs for raid_dev */ ; +enum raid_dev_flags { DEVICE_FAILED, IO_QUEUED }; + +/* The raid device in a set. */ +struct raid_dev { + struct dm_dev *dev; + unsigned long flags; /* raid_dev_flags. */ + sector_t start; /* offset to map to. */ +}; + +/* Flags spec for raid_set. */ +enum raid_set_flags { + RS_CHECK_OVERWRITE, /* Check for chunk overwrites. */ + RS_DEAD, /* RAID set inoperational. */ + RS_DEVEL_STATS, /* REMOVEME: display status information. */ + RS_IO_ERROR, /* io error on set. */ + RS_RECOVER, /* Do recovery. */ + RS_RECOVERY_BANDWIDTH, /* Allow recovery bandwidth (delayed bios). */ + RS_REGION_GET, /* get a region to recover. */ + RS_SC_BUSY, /* stripe cache busy -> send an event. */ + RS_SUSPENDED, /* RAID set suspendedn. */ +}; + +/* REMOVEME: devel stats counters. */ +enum stats_types { + S_BIOS_READ, + S_BIOS_ADDED_READ, + S_BIOS_ENDIO_READ, + S_BIOS_WRITE, + S_BIOS_ADDED_WRITE, + S_BIOS_ENDIO_WRITE, + S_CAN_MERGE, + S_CANT_MERGE, + S_CONGESTED, + S_DM_IO_READ, + S_DM_IO_WRITE, + S_ACTIVE_READS, + S_BANDWIDTH, + S_BARRIER, + S_BIO_COPY_PL_NEXT, + S_DEGRADED, + S_DELAYED_BIOS, + S_EVICT, + S_FLUSHS, + S_HITS_1ST, + S_IOS_POST, + S_INSCACHE, + S_MAX_LOOKUP, + S_MERGE_PAGE_LOCKED, + S_NO_BANDWIDTH, + S_NOT_CONGESTED, + S_NO_RW, + S_NOSYNC, + S_PROHIBITPAGEIO, + S_RECONSTRUCT_EI, + S_RECONSTRUCT_DEV, + S_REDO, + S_REQUEUE, + S_STRIPE_ERROR, + S_SUM_DELAYED_BIOS, + S_XORS, + S_NR_STATS, /* # of stats counters. */ +}; + +/* Status type -> string mappings. */ +struct stats_map { + const enum stats_types type; + const char *str; +}; + +static struct stats_map stats_map[] = { + { S_BIOS_READ, "r=" }, + { S_BIOS_ADDED_READ, "/" }, + { S_BIOS_ENDIO_READ, "/" }, + { S_BIOS_WRITE, " w=" }, + { S_BIOS_ADDED_WRITE, "/" }, + { S_BIOS_ENDIO_WRITE, "/" }, + { S_DM_IO_READ, " rc=" }, + { S_DM_IO_WRITE, " wc=" }, + { S_ACTIVE_READS, " active_reads=" }, + { S_BANDWIDTH, " bandwidth=" }, + { S_NO_BANDWIDTH, " no_bandwidth=" }, + { S_BARRIER, " barrier=" }, + { S_BIO_COPY_PL_NEXT, " bio_copy_pl_next=" }, + { S_CAN_MERGE, " can_merge=" }, + { S_MERGE_PAGE_LOCKED, "/page_locked=" }, + { S_CANT_MERGE, "/cant_merge=" }, + { S_CONGESTED, " congested=" }, + { S_NOT_CONGESTED, "/not_congested=" }, + { S_DEGRADED, " degraded=" }, + { S_DELAYED_BIOS, " delayed_bios=" }, + { S_SUM_DELAYED_BIOS, "/sum_delayed_bios=" }, + { S_EVICT, " evict=" }, + { S_FLUSHS, " flushs=" }, + { S_HITS_1ST, " hits_1st=" }, + { S_IOS_POST, " ios_post=" }, + { S_INSCACHE, " inscache=" }, + { S_MAX_LOOKUP, " max_lookup=" }, + { S_NO_RW, " no_rw=" }, + { S_NOSYNC, " nosync=" }, + { S_PROHIBITPAGEIO, " ProhibitPageIO=" }, + { S_RECONSTRUCT_EI, " reconstruct_ei=" }, + { S_RECONSTRUCT_DEV, " reconstruct_dev=" }, + { S_REDO, " redo=" }, + { S_REQUEUE, " requeue=" }, + { S_STRIPE_ERROR, " stripe_error=" }, + { S_XORS, " xors=" }, +}; + +/* + * A RAID set. + */ +typedef void (*xor_function_t)(unsigned count, xor_t **data); +struct raid_set { + struct dm_target *ti; /* Target pointer. */ + + struct { + unsigned long flags; /* State flags. */ + spinlock_t in_lock; /* Protects central input list below. */ + struct bio_list in; /* Pending ios (central input list). */ + struct bio_list work; /* ios work set. */ + wait_queue_head_t suspendq; /* suspend synchronization. */ + atomic_t in_process; /* counter of queued bios (suspendq). */ + atomic_t in_process_max;/* counter of queued bios max. */ + + /* io work. */ + struct workqueue_struct *wq; + struct delayed_work dws; + } io; + + /* External locking. */ + struct dmraid45_locking_type *locking; + + struct stripe_cache sc; /* Stripe cache for this set. */ + + /* Xor optimization. */ + struct { + struct xor_func *f; + unsigned chunks; + unsigned speed; + } xor; + + /* Recovery parameters. */ + struct recover { + struct dm_dirty_log *dl; /* Dirty log. */ + void *rh; /* Region hash. */ + + region_t nr_regions; + region_t nr_regions_to_recover; + region_t nr_regions_recovered; + unsigned long start_jiffies; + unsigned long end_jiffies; + + unsigned bandwidth; /* Recovery bandwidth [%]. */ + unsigned bandwidth_work; /* Recovery bandwidth [factor]. */ + unsigned bandwidth_parm; /* " constructor parm. */ + unsigned io_size; /* io size <= chunk size. */ + unsigned io_size_parm; /* io size ctr parameter. */ + + /* recovery io throttling. */ + atomic_t io_count[2]; /* counter recover/regular io. */ + unsigned long last_jiffies; + + void *reg; /* Actual region to recover. */ + struct stripe *stripe; /* Stripe used for recovery. */ + sector_t pos; /* Position within region to recover. */ + sector_t end; /* End of region to recover. */ + } recover; + + /* RAID set parameters. */ + struct { + struct raid_type *raid_type; /* RAID type (eg, RAID4). */ + unsigned raid_parms; /* # variable raid parameters. */ + + unsigned chunk_size; /* Sectors per chunk. */ + unsigned chunk_size_parm; + unsigned chunk_mask; /* Mask for amount. */ + unsigned chunk_shift; /* rsector chunk size shift. */ + + unsigned io_size; /* Sectors per io. */ + unsigned io_size_parm; + unsigned io_mask; /* Mask for amount. */ + unsigned io_shift_mask; /* Mask for raid_address(). */ + unsigned io_shift; /* rsector io size shift. */ + unsigned pages_per_io; /* Pages per io. */ + + sector_t sectors_per_dev; /* Sectors per device. */ + + atomic_t failed_devs; /* Amount of devices failed. */ + + /* Index of device to initialize. */ + int dev_to_init; + int dev_to_init_parm; + + /* Raid devices dynamically allocated. */ + unsigned raid_devs; /* # of RAID devices below. */ + unsigned data_devs; /* # of RAID data devices. */ + + int ei; /* index of failed RAID device. */ + + /* index of dedicated parity device (i.e. RAID4). */ + int pi; + int pi_parm; /* constructor parm for status output. */ + } set; + + /* REMOVEME: devel stats counters. */ + atomic_t stats[S_NR_STATS]; + + /* Dynamically allocated temporary pointers for xor(). */ + xor_t **data; + + /* Dynamically allocated RAID devices. Alignment? */ + struct raid_dev dev[0]; +}; + + +BITOPS(RS, Bandwidth, raid_set, RS_RECOVERY_BANDWIDTH) +BITOPS(RS, CheckOverwrite, raid_set, RS_CHECK_OVERWRITE) +BITOPS(RS, Dead, raid_set, RS_DEAD) +BITOPS(RS, DevelStats, raid_set, RS_DEVEL_STATS) +BITOPS(RS, IoError, raid_set, RS_IO_ERROR) +BITOPS(RS, Recover, raid_set, RS_RECOVER) +BITOPS(RS, RegionGet, raid_set, RS_REGION_GET) +BITOPS(RS, ScBusy, raid_set, RS_SC_BUSY) +BITOPS(RS, Suspended, raid_set, RS_SUSPENDED) +#undef BITOPS + +#define PageIO(page) PageChecked(page) +#define AllowPageIO(page) SetPageChecked(page) +#define ProhibitPageIO(page) ClearPageChecked(page) + +/*----------------------------------------------------------------- + * Raid-4/5 set structures. + *---------------------------------------------------------------*/ +/* RAID level definitions. */ +enum raid_level { + raid4, + raid5, +}; + +/* Symmetric/Asymmetric, Left/Right parity rotating algorithms. */ +enum raid_algorithm { + none, + left_asym, + right_asym, + left_sym, + right_sym, +}; + +struct raid_type { + const char *name; /* RAID algorithm. */ + const char *descr; /* Descriptor text for logging. */ + const unsigned parity_devs; /* # of parity devices. */ + const unsigned minimal_devs; /* minimal # of devices in set. */ + const enum raid_level level; /* RAID level. */ + const enum raid_algorithm algorithm; /* RAID algorithm. */ +}; + +/* Supported raid types and properties. */ +static struct raid_type raid_types[] = { + {"raid4", "RAID4 (dedicated parity disk)", 1, 3, raid4, none}, + {"raid5_la", "RAID5 (left asymmetric)", 1, 3, raid5, left_asym}, + {"raid5_ra", "RAID5 (right asymmetric)", 1, 3, raid5, right_asym}, + {"raid5_ls", "RAID5 (left symmetric)", 1, 3, raid5, left_sym}, + {"raid5_rs", "RAID5 (right symmetric)", 1, 3, raid5, right_sym}, +}; + +/* Address as calculated by raid_address(). */ +struct address { + sector_t key; /* Hash key (start address of stripe). */ + unsigned di, pi; /* Data and parity disks index. */ +}; + +/* REMOVEME: reset statistics counters. */ +static void stats_reset(struct raid_set *rs) +{ + unsigned s = S_NR_STATS; + + while (s--) + atomic_set(rs->stats + s, 0); +} + +/*---------------------------------------------------------------- + * RAID set management routines. + *--------------------------------------------------------------*/ +/* + * Begin small helper functions. + */ +/* Queue (optionally delayed) io work. */ +static void wake_do_raid_delayed(struct raid_set *rs, unsigned long delay) +{ + struct delayed_work *dws = &rs->io.dws; + + cancel_delayed_work(dws); + queue_delayed_work(rs->io.wq, dws, delay); +} + +/* Queue io work immediately (called from region hash too). */ +static INLINE void wake_do_raid(void *context) +{ + wake_do_raid_delayed(context, 0); +} + +/* Wait until all io has been processed. */ +static INLINE void wait_ios(struct raid_set *rs) +{ + wait_event(rs->io.suspendq, !atomic_read(&rs->io.in_process)); +} + +/* Declare io queued to device. */ +static INLINE void io_dev_queued(struct raid_dev *dev) +{ + set_bit(IO_QUEUED, &dev->flags); +} + +/* Io on device and reset ? */ +static inline int io_dev_clear(struct raid_dev *dev) +{ + return test_and_clear_bit(IO_QUEUED, &dev->flags); +} + +/* Get an io reference. */ +static INLINE void io_get(struct raid_set *rs) +{ + int p = atomic_inc_return(&rs->io.in_process); + + if (p > atomic_read(&rs->io.in_process_max)) + atomic_set(&rs->io.in_process_max, p); /* REMOVEME: max. */ +} + +/* Put the io reference and conditionally wake io waiters. */ +static INLINE void io_put(struct raid_set *rs) +{ + if (atomic_dec_and_test(&rs->io.in_process)) + wake_up(&rs->io.suspendq); +} + +/* Calculate device sector offset. */ +static INLINE sector_t _sector(struct raid_set *rs, struct bio *bio) +{ + sector_t sector = bio->bi_sector; + + sector_div(sector, rs->set.data_devs); + return sector; +} + +/* Test device operational. */ +static INLINE int dev_operational(struct raid_set *rs, unsigned p) +{ + return !test_bit(DEVICE_FAILED, &rs->dev[p].flags); +} + +/* Return # of active stripes in stripe cache. */ +static INLINE int sc_active(struct stripe_cache *sc) +{ + return atomic_read(&sc->active_stripes); +} + +/* Test io pending on stripe. */ +static INLINE int stripe_io(struct stripe *stripe) +{ + return atomic_read(&stripe->io.pending); +} + +static INLINE void stripe_io_inc(struct stripe *stripe) +{ + atomic_inc(&stripe->io.pending); +} + +static INLINE void stripe_io_dec(struct stripe *stripe) +{ + atomic_dec(&stripe->io.pending); +} + +/* Wrapper needed by for_each_io_dev(). */ +static void _stripe_io_inc(struct stripe *stripe, unsigned p) +{ + stripe_io_inc(stripe); +} + +/* Error a stripe. */ +static INLINE void stripe_error(struct stripe *stripe, struct page *page) +{ + SetStripeError(stripe); + SetPageError(page); + atomic_inc(RS(stripe->sc)->stats + S_STRIPE_ERROR); +} + +/* Page IOed ok. */ +enum dirty_type { CLEAN, DIRTY }; +static INLINE void page_set(struct page *page, enum dirty_type type) +{ + switch (type) { + case DIRTY: + SetPageDirty(page); + AllowPageIO(page); + break; + + case CLEAN: + ClearPageDirty(page); + break; + + default: + BUG(); + } + + SetPageUptodate(page); + ClearPageError(page); +} + +/* Return region state for a sector. */ +static INLINE int +region_state(struct raid_set *rs, sector_t sector, unsigned long state) +{ + void *rh = rs->recover.rh; + + if (unlikely(RSRecover(rs))) + return rh_state(rh, rh_sector_to_region(rh, sector), 1) & state; + else + return 0; +} + +/* Check maximum devices which may fail in a raid set. */ +static inline int raid_set_degraded(struct raid_set *rs) +{ + return RSIoError(rs); +} + +/* Check # of devices which may fail in a raid set. */ +static INLINE int raid_set_operational(struct raid_set *rs) +{ + /* Too many failed devices -> BAD. */ + return atomic_read(&rs->set.failed_devs) <= + rs->set.raid_type->parity_devs; +} + +/* + * Return true in case a page_list should be read/written + * + * Conditions to read/write: + * o 1st page in list not uptodate + * o 1st page in list dirty + * o if we optimized io away, we flag it using the pages checked bit. + */ +static INLINE unsigned page_io(struct page *page) +{ + /* Optimization: page was flagged to need io during first run. */ + if (PagePrivate(page)) { + ClearPagePrivate(page); + return 1; + } + + /* Avoid io if prohibited or a locked page. */ + if (!PageIO(page) || PageLocked(page)) + return 0; + + if (!PageUptodate(page) || PageDirty(page)) { + /* Flag page needs io for second run optimization. */ + SetPagePrivate(page); + return 1; + } + + return 0; +} + +/* Call a function on each page list needing io. */ +static INLINE unsigned +for_each_io_dev(struct raid_set *rs, struct stripe *stripe, + void (*f_io)(struct stripe *stripe, unsigned p)) +{ + unsigned p = rs->set.raid_devs, r = 0; + + while (p--) { + if (page_io(PAGE(stripe, p))) { + f_io(stripe, p); + r++; + } + } + + return r; +} + +/* Reconstruct a particular device ?. */ +static INLINE int dev_to_init(struct raid_set *rs) +{ + return rs->set.dev_to_init > -1; +} + +/* Index of device to calculate parity on. */ +static INLINE unsigned dev_for_parity(struct stripe *stripe) +{ + struct raid_set *rs = RS(stripe->sc); + + return dev_to_init(rs) ? rs->set.dev_to_init : stripe->idx.parity; +} + +/* Return the index of the device to be recovered. */ +static int idx_get(struct raid_set *rs) +{ + /* Avoid to read in the pages to be reconstructed anyway. */ + if (dev_to_init(rs)) + return rs->set.dev_to_init; + else if (rs->set.raid_type->level == raid4) + return rs->set.pi; + + return -1; +} + +/* RAID set congested function. */ +static int raid_set_congested(void *congested_data, int bdi_bits) +{ + struct raid_set *rs = congested_data; + int r = 0; /* Assume uncongested. */ + unsigned p = rs->set.raid_devs; + + /* If any of our component devices are overloaded. */ + while (p--) + r |= bdi_congested(&bdev_get_queue(rs->dev[p].dev->bdev)->backing_dev_info, bdi_bits); + + /* REMOVEME: statistics. */ + atomic_inc(rs->stats + (r ? S_CONGESTED : S_NOT_CONGESTED)); + return r; +} + +/* Display RAID set dead message once. */ +static void raid_set_dead(struct raid_set *rs) +{ + if (!TestSetRSDead(rs)) { + unsigned p; + char buf[BDEVNAME_SIZE]; + + DMERR("FATAL: too many devices failed -> RAID set dead"); + + for (p = 0; p < rs->set.raid_devs; p++) { + if (!dev_operational(rs, p)) + DMERR("device /dev/%s failed", + bdevname(rs->dev[p].dev->bdev, buf)); + } + } +} + +/* RAID set degrade check. */ +static INLINE int +raid_set_check_and_degrade(struct raid_set *rs, + struct stripe *stripe, unsigned p) +{ + if (test_and_set_bit(DEVICE_FAILED, &rs->dev[p].flags)) + return -EPERM; + + /* Through an event in case of member device errors. */ + dm_table_event(rs->ti->table); + atomic_inc(&rs->set.failed_devs); + + /* Only log the first member error. */ + if (!TestSetRSIoError(rs)) { + char buf[BDEVNAME_SIZE]; + + /* Store index for recovery. */ + mb(); + rs->set.ei = p; + mb(); + + DMERR("CRITICAL: %sio error on device /dev/%s " + "in region=%llu; DEGRADING RAID set", + stripe ? "" : "FAKED ", + bdevname(rs->dev[p].dev->bdev, buf), + (unsigned long long) (stripe ? stripe->key : 0)); + DMERR("further device error messages suppressed"); + } + + return 0; +} + +static void +raid_set_check_degrade(struct raid_set *rs, struct stripe *stripe) +{ + unsigned p = rs->set.raid_devs; + + while (p--) { + struct page *page = PAGE(stripe, p); + + if (PageError(page)) { + ClearPageError(page); + raid_set_check_and_degrade(rs, stripe, p); + } + } +} + +/* RAID set upgrade check. */ +static int raid_set_check_and_upgrade(struct raid_set *rs, unsigned p) +{ + if (!test_and_clear_bit(DEVICE_FAILED, &rs->dev[p].flags)) + return -EPERM; + + if (atomic_dec_and_test(&rs->set.failed_devs)) { + ClearRSIoError(rs); + rs->set.ei = -1; + } + + return 0; +} + +/* Lookup a RAID device by name or by major:minor number. */ +union dev_lookup { + const char *dev_name; + struct raid_dev *dev; +}; +enum lookup_type { byname, bymajmin, bynumber }; +static int raid_dev_lookup(struct raid_set *rs, enum lookup_type by, + union dev_lookup *dl) +{ + unsigned p; + + /* + * Must be an incremental loop, because the device array + * can have empty slots still on calls from raid_ctr() + */ + for (p = 0; p < rs->set.raid_devs; p++) { + char buf[BDEVNAME_SIZE]; + struct raid_dev *dev = rs->dev + p; + + if (!dev->dev) + break; + + /* Format dev string appropriately if necessary. */ + if (by == byname) + bdevname(dev->dev->bdev, buf); + else if (by == bymajmin) + format_dev_t(buf, dev->dev->bdev->bd_dev); + + /* Do the actual check. */ + if (by == bynumber) { + if (dl->dev->dev->bdev->bd_dev == + dev->dev->bdev->bd_dev) + return p; + } else if (!strcmp(dl->dev_name, buf)) + return p; + } + + return -ENODEV; +} + +/* End io wrapper. */ +static INLINE void +_bio_endio(struct raid_set *rs, struct bio *bio, int error) +{ + /* REMOVEME: statistics. */ + atomic_inc(rs->stats + (bio_data_dir(bio) == WRITE ? + S_BIOS_ENDIO_WRITE : S_BIOS_ENDIO_READ)); + bio_endio(bio, error); + io_put(rs); /* Wake any suspend waiters. */ +} + +/* + * End small helper functions. + */ + + +/* + * Stripe hash functions + */ +/* Initialize/destroy stripe hash. */ +static int hash_init(struct stripe_hash *hash, unsigned stripes) +{ + unsigned buckets = 1, max_buckets = stripes / 4; + unsigned hash_primes[] = { + /* Table of primes for hash_fn/table size optimization. */ + 3, 7, 13, 27, 53, 97, 193, 389, 769, + 1543, 3079, 6151, 12289, 24593, + }; + + /* Calculate number of buckets (2^^n <= stripes / 4). */ + while ((buckets <<= 1) < max_buckets); + + /* Allocate stripe hash. */ + hash->hash = vmalloc(buckets * sizeof(*hash->hash)); + if (!hash->hash) + return -ENOMEM; + + hash->buckets = buckets; + hash->mask = buckets - 1; + hash->shift = ffs(buckets); + if (hash->shift > ARRAY_SIZE(hash_primes) + 1) + hash->shift = ARRAY_SIZE(hash_primes) + 1; + + BUG_ON(hash->shift - 2 > ARRAY_SIZE(hash_primes) + 1); + hash->prime = hash_primes[hash->shift - 2]; + + /* Initialize buckets. */ + while (buckets--) + INIT_LIST_HEAD(hash->hash + buckets); + + return 0; +} + +static INLINE void hash_exit(struct stripe_hash *hash) +{ + if (hash->hash) { + vfree(hash->hash); + hash->hash = NULL; + } +} + +/* List add (head/tail/locked/unlocked) inlines. */ +enum list_lock_type { LIST_LOCKED, LIST_UNLOCKED }; +#define LIST_DEL(name, list) \ +static void stripe_ ## name ## _del(struct stripe *stripe, \ + enum list_lock_type lock) { \ + struct list_head *lh = stripe->lists + (list); \ + spinlock_t *l = NULL; \ +\ + if (lock == LIST_LOCKED) { \ + l = stripe->sc->locks + LOCK_LRU; \ + spin_lock_irq(l); \ + } \ +\ +\ + if (!list_empty(lh)) \ + list_del_init(lh); \ +\ + if (lock == LIST_LOCKED) \ + spin_unlock_irq(l); \ +} + +LIST_DEL(hash, LIST_HASH) +LIST_DEL(lru, LIST_LRU) +#undef LIST_DEL + +enum list_pos_type { POS_HEAD, POS_TAIL }; +#define LIST_ADD(name, list) \ +static void stripe_ ## name ## _add(struct stripe *stripe, \ + enum list_pos_type pos, \ + enum list_lock_type lock) { \ + struct list_head *lh = stripe->lists + (list); \ + struct stripe_cache *sc = stripe->sc; \ + spinlock_t *l = NULL; \ +\ + if (lock == LIST_LOCKED) { \ + l = sc->locks + LOCK_LRU; \ + spin_lock_irq(l); \ + } \ +\ + if (list_empty(lh)) { \ + if (pos == POS_HEAD) \ + list_add(lh, sc->lists + (list)); \ + else \ + list_add_tail(lh, sc->lists + (list)); \ + } \ +\ + if (lock == LIST_LOCKED) \ + spin_unlock_irq(l); \ +} + +LIST_ADD(endio, LIST_ENDIO) +LIST_ADD(io, LIST_IO) +LIST_ADD(lru, LIST_LRU) +#undef LIST_ADD + +#define POP(list) \ + if (list_empty(sc->lists + list)) \ + stripe = NULL; \ + else { \ + stripe = list_entry(sc->lists[list].next, struct stripe, \ + lists[list]); \ + list_del_init(&stripe->lists[list]); \ + } + +/* Pop an available stripe off the lru list. */ +static struct stripe *stripe_lru_pop(struct stripe_cache *sc) +{ + struct stripe *stripe; + spinlock_t *lock = sc->locks + LOCK_LRU; + + spin_lock_irq(lock); + POP(LIST_LRU); + spin_unlock_irq(lock); + + if (stripe) + /* Remove from hash before reuse. */ + stripe_hash_del(stripe, LIST_UNLOCKED); + + return stripe; +} + +static inline unsigned hash_fn(struct stripe_hash *hash, sector_t key) +{ + return (unsigned) (((key * hash->prime) >> hash->shift) & hash->mask); +} + +static inline struct list_head * +hash_bucket(struct stripe_hash *hash, sector_t key) +{ + return hash->hash + hash_fn(hash, key); +} + +/* Insert an entry into a hash. */ +static inline void hash_insert(struct stripe_hash *hash, struct stripe *stripe) +{ + list_add(stripe->lists + LIST_HASH, hash_bucket(hash, stripe->key)); +} + +/* Insert an entry into the stripe hash. */ +static inline void +sc_insert(struct stripe_cache *sc, struct stripe *stripe) +{ + hash_insert(&sc->hash, stripe); +} + +/* Lookup an entry in the stripe hash. */ +static inline struct stripe * +stripe_lookup(struct stripe_cache *sc, sector_t key) +{ + unsigned c = 0; + struct stripe *stripe; + struct list_head *bucket = hash_bucket(&sc->hash, key); + + list_for_each_entry(stripe, bucket, lists[LIST_HASH]) { + /* REMOVEME: statisics. */ + if (++c > atomic_read(RS(sc)->stats + S_MAX_LOOKUP)) + atomic_set(RS(sc)->stats + S_MAX_LOOKUP, c); + + if (stripe->key == key) + return stripe; + } + + return NULL; +} + +/* Resize the stripe cache hash on size changes. */ +static int hash_resize(struct stripe_cache *sc) +{ + /* Resize threshold reached? */ + if (atomic_read(&sc->stripes) > 2 * atomic_read(&sc->stripes_last) + || atomic_read(&sc->stripes) < atomic_read(&sc->stripes_last) / 4) { + int r; + struct stripe_hash hash, hash_tmp; + spinlock_t *lock; + + r = hash_init(&hash, atomic_read(&sc->stripes)); + if (r) + return r; + + lock = sc->locks + LOCK_LRU; + spin_lock_irq(lock); + if (sc->hash.hash) { + unsigned b = sc->hash.buckets; + struct list_head *pos, *tmp; + + /* Walk old buckets and insert into new. */ + while (b--) { + list_for_each_safe(pos, tmp, sc->hash.hash + b) + hash_insert(&hash, + list_entry(pos, struct stripe, + lists[LIST_HASH])); + } + + } + + memcpy(&hash_tmp, &sc->hash, sizeof(hash_tmp)); + memcpy(&sc->hash, &hash, sizeof(sc->hash)); + atomic_set(&sc->stripes_last, atomic_read(&sc->stripes)); + spin_unlock_irq(lock); + + hash_exit(&hash_tmp); + } + + return 0; +} + +/* + * Stripe cache locking functions + */ +/* Dummy lock function for local RAID4+5. */ +static void *no_lock(sector_t key, enum lock_type type) +{ + return &no_lock; +} + +/* Dummy unlock function for local RAID4+5. */ +static void no_unlock(void *lock_handle) +{ +} + +/* No locking (for local RAID 4+5). */ +static struct dmraid45_locking_type locking_none = { + .lock = no_lock, + .unlock = no_unlock, +}; + +/* Clustered RAID 4+5. */ +/* FIXME: code this. */ +static struct dmraid45_locking_type locking_cluster = { + .lock = no_lock, + .unlock = no_unlock, +}; + +/* Lock a stripe (for clustering). */ +static int +stripe_lock(struct raid_set *rs, struct stripe *stripe, int rw, sector_t key) +{ + stripe->lock = rs->locking->lock(key, rw == READ ? RAID45_SHARED : + RAID45_EX); + return stripe->lock ? 0 : -EPERM; +} + +/* Unlock a stripe (for clustering). */ +static void stripe_unlock(struct raid_set *rs, struct stripe *stripe) +{ + rs->locking->unlock(stripe->lock); + stripe->lock = NULL; +} + +/* + * Stripe cache functions. + */ +/* + * Invalidate all page lists pages of a stripe. + * + * I only keep state for the whole list in the first page. + */ +static INLINE void +stripe_pages_invalidate(struct stripe *stripe) +{ + unsigned p = RS(stripe->sc)->set.raid_devs; + + while (p--) { + struct page *page = PAGE(stripe, p); + + ProhibitPageIO(page); + ClearPageChecked(page); + ClearPageDirty(page); + ClearPageError(page); + clear_page_locked(page); + ClearPagePrivate(page); + ClearPageUptodate(page); + } +} + +/* Prepare stripe for (re)use. */ +static INLINE void stripe_invalidate(struct stripe *stripe) +{ + stripe->io.flags = 0; + stripe_pages_invalidate(stripe); +} + +/* Allow io on all chunks of a stripe. */ +static INLINE void stripe_allow_io(struct stripe *stripe) +{ + unsigned p = RS(stripe->sc)->set.raid_devs; + + while (p--) + AllowPageIO(PAGE(stripe, p)); +} + +/* Initialize a stripe. */ +static void +stripe_init(struct stripe_cache *sc, struct stripe *stripe, unsigned io_size) +{ + unsigned p = RS(sc)->set.raid_devs; + unsigned i; + + /* Work all io chunks. */ + while (p--) { + struct stripe_set *ss = stripe->ss + p; + + stripe->obj[p].private = ss; + ss->stripe = stripe; + + i = ARRAY_SIZE(ss->bl); + while (i--) + bio_list_init(ss->bl + i); + } + + stripe->sc = sc; + + i = ARRAY_SIZE(stripe->lists); + while (i--) + INIT_LIST_HEAD(&stripe->lists[i]); + + stripe->io.size = io_size; + atomic_set(&stripe->cnt, 0); + atomic_set(&stripe->io.pending, 0); + + stripe_invalidate(stripe); +} + +/* Number of pages per chunk. */ +static inline unsigned chunk_pages(unsigned io_size) +{ + return dm_div_up(io_size, SECTORS_PER_PAGE); +} + +/* Number of pages per stripe. */ +static inline unsigned stripe_pages(struct raid_set *rs, unsigned io_size) +{ + return chunk_pages(io_size) * rs->set.raid_devs; +} + +/* Initialize part of page_list (recovery). */ +static INLINE void stripe_zero_pl_part(struct stripe *stripe, unsigned p, + unsigned start, unsigned count) +{ + unsigned pages = chunk_pages(count); + /* Get offset into the page_list. */ + struct page_list *pl = pl_elem(PL(stripe, p), start / SECTORS_PER_PAGE); + + BUG_ON(!pl); + while (pl && pages--) { + BUG_ON(!pl->page); + memset(page_address(pl->page), 0, PAGE_SIZE); + pl = pl->next; + } +} + +/* Initialize parity chunk of stripe. */ +static INLINE void stripe_zero_chunk(struct stripe *stripe, unsigned p) +{ + stripe_zero_pl_part(stripe, p, 0, stripe->io.size); +} + +/* Return dynamic stripe structure size. */ +static INLINE size_t stripe_size(struct raid_set *rs) +{ + return sizeof(struct stripe) + + rs->set.raid_devs * sizeof(struct stripe_set); +} + +/* Allocate a stripe and its memory object. */ +enum grow { grow, keep }; +static struct stripe *stripe_alloc(struct stripe_cache *sc, + unsigned io_size, enum grow grow) +{ + int r; + unsigned pages_per_chunk = chunk_pages(io_size); + struct stripe *stripe; + + stripe = kmem_cache_alloc(sc->kc.cache, GFP_KERNEL); + if (stripe) { + memset(stripe, 0, stripe_size(RS(sc))); + + /* Grow the dm-mem-cache on request. */ + if (grow == grow) { + r = dm_mem_cache_grow(sc->dm_mem_cache_client, + pages_per_chunk); + if (r) + goto err_free; + } + + stripe->obj = dm_mem_cache_alloc(sc->dm_mem_cache_client, + pages_per_chunk); + if (!stripe->obj) + goto err_shrink; + + stripe_init(sc, stripe, io_size); + } + + return stripe; + + err_shrink: + if (grow == grow) + dm_mem_cache_shrink(sc->dm_mem_cache_client, pages_per_chunk); + err_free: + kmem_cache_free(sc->kc.cache, stripe); + return NULL; +} + +/* + * Free a stripes memory object, shrink the + * memory cache and free the stripe itself + */ +static void stripe_free(struct stripe *stripe) +{ + dm_mem_cache_free(stripe->sc->dm_mem_cache_client, stripe->obj); + dm_mem_cache_shrink(stripe->sc->dm_mem_cache_client, + chunk_pages(stripe->io.size)); + kmem_cache_free(stripe->sc->kc.cache, stripe); +} + +/* Free the recovery stripe. */ +static void stripe_recover_free(struct raid_set *rs) +{ + if (rs->recover.stripe) { + ClearRSRecover(rs); + stripe_free(rs->recover.stripe); + rs->recover.stripe = NULL; + } +} + +/* Push a stripe safely onto the endio list to be handled by do_endios(). */ +static INLINE void stripe_endio_push(struct stripe *stripe) +{ + int wake; + unsigned long flags; + struct stripe_cache *sc = stripe->sc; + spinlock_t *lock = sc->locks + LOCK_ENDIO; + + spin_lock_irqsave(lock, flags); + wake = list_empty(sc->lists + LIST_ENDIO); + stripe_endio_add(stripe, POS_HEAD, LIST_UNLOCKED); + spin_unlock_irqrestore(lock, flags); + + if (wake) + wake_do_raid(RS(sc)); +} + +/* Protected check for stripe cache endio list empty. */ +static INLINE int stripe_endio_empty(struct stripe_cache *sc) +{ + int r; + spinlock_t *lock = sc->locks + LOCK_ENDIO; + + spin_lock_irq(lock); + r = list_empty(sc->lists + LIST_ENDIO); + spin_unlock_irq(lock); + + return r; +} + +/* Pop a stripe off safely off the endio list. */ +static struct stripe *stripe_endio_pop(struct stripe_cache *sc) +{ + struct stripe *stripe; + spinlock_t *lock = sc->locks + LOCK_ENDIO; + + /* This runs in parallel with endio(). */ + spin_lock_irq(lock); + POP(LIST_ENDIO) + spin_unlock_irq(lock); + return stripe; +} + +#undef POP + +/* Evict stripe from cache. */ +static void stripe_evict(struct stripe *stripe) +{ + struct raid_set *rs = RS(stripe->sc); + stripe_hash_del(stripe, LIST_UNLOCKED); /* Take off hash. */ + + if (list_empty(stripe->lists + LIST_LRU)) { + stripe_lru_add(stripe, POS_TAIL, LIST_LOCKED); + atomic_inc(rs->stats + S_EVICT); /* REMOVEME: statistics. */ + } +} + +/* Grow stripe cache. */ +static int +sc_grow(struct stripe_cache *sc, unsigned stripes, enum grow grow) +{ + int r = 0; + struct raid_set *rs = RS(sc); + + /* Try to allocate this many (additional) stripes. */ + while (stripes--) { + struct stripe *stripe = stripe_alloc(sc, rs->set.io_size, grow); + + if (likely(stripe)) { + stripe_lru_add(stripe, POS_TAIL, LIST_LOCKED); + atomic_inc(&sc->stripes); + } else { + r = -ENOMEM; + break; + } + } + + ClearRSScBusy(rs); + return r ? r : hash_resize(sc); +} + +/* Shrink stripe cache. */ +static int sc_shrink(struct stripe_cache *sc, unsigned stripes) +{ + int r = 0; + + /* Try to get unused stripe from LRU list. */ + while (stripes--) { + struct stripe *stripe; + + stripe = stripe_lru_pop(sc); + if (stripe) { + /* An lru stripe may never have ios pending!. */ + BUG_ON(stripe_io(stripe)); + stripe_free(stripe); + atomic_dec(&sc->stripes); + } else { + r = -ENOENT; + break; + } + } + + /* Check if stats are still sane. */ + if (atomic_read(&sc->max_active_stripes) > + atomic_read(&sc->stripes)) + atomic_set(&sc->max_active_stripes, 0); + + if (r) + return r; + + ClearRSScBusy(RS(sc)); + return hash_resize(sc); +} + +/* Create stripe cache. */ +static int sc_init(struct raid_set *rs, unsigned stripes) +{ + unsigned i, nr; + struct stripe_cache *sc = &rs->sc; + struct stripe *stripe; + + /* Initialize lists and locks. */ + i = ARRAY_SIZE(sc->lists); + while (i--) + INIT_LIST_HEAD(sc->lists + i); + + i = NR_LOCKS; + while (i--) + spin_lock_init(sc->locks + i); + + /* Initialize atomic variables. */ + atomic_set(&sc->stripes, 0); + atomic_set(&sc->stripes_last, 0); + atomic_set(&sc->stripes_to_shrink, 0); + atomic_set(&sc->active_stripes, 0); + atomic_set(&sc->max_active_stripes, 0); /* REMOVEME: */ + + /* + * We need a runtime unique # to suffix the kmem cache name + * because we'll have one for each active RAID set. + */ + nr = atomic_inc_return(&_stripe_sc_nr); + sprintf(sc->kc.name, "%s_%d", TARGET, nr); + sc->kc.cache = kmem_cache_create(sc->kc.name, stripe_size(rs), + 0, 0, NULL); + if (!sc->kc.cache) + return -ENOMEM; + + /* Create memory cache client context and Allocate memory objects. */ + sc->dm_mem_cache_client = dm_mem_cache_client_create( + stripes * stripe_pages(rs, rs->set.io_size) + + 2 * stripe_pages(rs, rs->recover.io_size), + stripes + 2, rs->set.raid_devs); + if (IS_ERR(sc->dm_mem_cache_client)) + return PTR_ERR(sc->dm_mem_cache_client); + + /* Allocate stripe for set recovery. */ + stripe = stripe_alloc(sc, rs->recover.io_size, keep); + if (!stripe) + return -ENOMEM; + + SetStripeRecover(stripe); + rs->recover.stripe = stripe; + return sc_grow(sc, stripes, keep); /* Grow the cache. */ +} + +/* Destroy the stripe cache. */ +static void sc_exit(struct stripe_cache *sc) +{ + if (sc->hash.hash) { + if (sc->kc.cache) { + BUG_ON(sc_shrink(sc, atomic_read(&sc->stripes))); + kmem_cache_destroy(sc->kc.cache); + } + + if (sc->dm_mem_cache_client) + dm_mem_cache_client_destroy(sc->dm_mem_cache_client); + + hash_exit(&sc->hash); + } +} + +/* + * Calculate RAID address + * + * Delivers tuple with the index of the data disk holding the chunk + * in the set, the parity disks index and the start of the stripe + * within the address space of the set (used as the stripe cache hash key). + */ +/* thx MD. */ +static struct address * +raid_address(struct raid_set *rs, sector_t sector, struct address *addr) +{ + unsigned data_devs = rs->set.data_devs, di, pi, + raid_devs = rs->set.raid_devs; + sector_t stripe, tmp; + + /* + * chunk_number = sector / chunk_size + * stripe = chunk_number / data_devs + * di = stripe % data_devs; + */ + stripe = sector >> rs->set.chunk_shift; + di = sector_div(stripe, data_devs); + + switch (rs->set.raid_type->level) { + case raid5: + tmp = stripe; + pi = sector_div(tmp, raid_devs); + + switch (rs->set.raid_type->algorithm) { + case left_asym: /* Left asymmetric. */ + pi = data_devs - pi; + case right_asym: /* Right asymmetric. */ + if (di >= pi) + di++; + break; + + case left_sym: /* Left symmetric. */ + pi = data_devs - pi; + case right_sym: /* Right symmetric. */ + di = (pi + di + 1) % raid_devs; + break; + + default: + DMERR("Unknown RAID algorithm %d", + rs->set.raid_type->algorithm); + goto out; + } + + break; + + case raid4: + pi = rs->set.pi; + if (di >= pi) + di++; + break; + + default: + DMERR("Unknown RAID level %d", rs->set.raid_type->level); + goto out; + } + + /* + * Hash key = start offset on any single device of the RAID set; + * adjusted in case io size differs from chunk size. + */ + addr->key = (stripe << rs->set.chunk_shift) + + (sector & rs->set.io_shift_mask); + addr->di = di; + addr->pi = pi; + + out: + return addr; +} + +/* + * Copy data across between stripe pages and bio vectors. + * + * Pay attention to data alignment in stripe and bio pages. + */ +static void +bio_copy_page_list(int rw, struct stripe *stripe, + struct page_list *pl, struct bio *bio) +{ + unsigned i, page_offset; + void *page_addr; + struct raid_set *rs = RS(stripe->sc); + struct bio_vec *bv; + + /* Get start page in page list for this sector. */ + i = (bio->bi_sector & rs->set.io_mask) / SECTORS_PER_PAGE; + pl = pl_elem(pl, i); + + page_addr = page_address(pl->page); + page_offset = to_bytes(bio->bi_sector & (SECTORS_PER_PAGE - 1)); + + /* Walk all segments and copy data across between bio_vecs and pages. */ + bio_for_each_segment(bv, bio, i) { + int len = bv->bv_len, size; + unsigned bio_offset = 0; + void *bio_addr = __bio_kmap_atomic(bio, i, KM_USER0); + redo: + size = (page_offset + len > PAGE_SIZE) ? + PAGE_SIZE - page_offset : len; + + if (rw == READ) + memcpy(bio_addr + bio_offset, + page_addr + page_offset, size); + else + memcpy(page_addr + page_offset, + bio_addr + bio_offset, size); + + page_offset += size; + if (page_offset == PAGE_SIZE) { + /* + * We reached the end of the chunk page -> + * need refer to the next one to copy more data. + */ + len -= size; + if (len) { + /* Get next page. */ + pl = pl->next; + BUG_ON(!pl); + page_addr = page_address(pl->page); + page_offset = 0; + bio_offset += size; + /* REMOVEME: statistics. */ + atomic_inc(rs->stats + S_BIO_COPY_PL_NEXT); + goto redo; + } + } + + __bio_kunmap_atomic(bio_addr, KM_USER0); + } +} + +/* + * Xor optimization macros. + */ +/* Xor data pointer declaration and initialization macros. */ +#define DECLARE_2 xor_t *d0 = data[0], *d1 = data[1] +#define DECLARE_3 DECLARE_2, *d2 = data[2] +#define DECLARE_4 DECLARE_3, *d3 = data[3] +#define DECLARE_5 DECLARE_4, *d4 = data[4] +#define DECLARE_6 DECLARE_5, *d5 = data[5] +#define DECLARE_7 DECLARE_6, *d6 = data[6] +#define DECLARE_8 DECLARE_7, *d7 = data[7] + +/* Xor unrole macros. */ +#define D2(n) d0[n] = d0[n] ^ d1[n] +#define D3(n) D2(n) ^ d2[n] +#define D4(n) D3(n) ^ d3[n] +#define D5(n) D4(n) ^ d4[n] +#define D6(n) D5(n) ^ d5[n] +#define D7(n) D6(n) ^ d6[n] +#define D8(n) D7(n) ^ d7[n] + +#define X_2(macro, offset) macro(offset); macro(offset + 1); +#define X_4(macro, offset) X_2(macro, offset); X_2(macro, offset + 2); +#define X_8(macro, offset) X_4(macro, offset); X_4(macro, offset + 4); +#define X_16(macro, offset) X_8(macro, offset); X_8(macro, offset + 8); +#define X_32(macro, offset) X_16(macro, offset); X_16(macro, offset + 16); +#define X_64(macro, offset) X_32(macro, offset); X_32(macro, offset + 32); + +/* Define a _xor_#chunks_#xors_per_run() function. */ +#define _XOR(chunks, xors_per_run) \ +static void _xor ## chunks ## _ ## xors_per_run(xor_t **data) \ +{ \ + unsigned end = XOR_SIZE / sizeof(data[0]), i; \ + DECLARE_ ## chunks; \ +\ + for (i = 0; i < end; i += xors_per_run) { \ + X_ ## xors_per_run(D ## chunks, i); \ + } \ +} + +/* Define xor functions for 2 - 8 chunks. */ +#define MAKE_XOR_PER_RUN(xors_per_run) \ + _XOR(2, xors_per_run); _XOR(3, xors_per_run); \ + _XOR(4, xors_per_run); _XOR(5, xors_per_run); \ + _XOR(6, xors_per_run); _XOR(7, xors_per_run); \ + _XOR(8, xors_per_run); + +MAKE_XOR_PER_RUN(8) /* Define _xor_*_8() functions. */ +MAKE_XOR_PER_RUN(16) /* Define _xor_*_16() functions. */ +MAKE_XOR_PER_RUN(32) /* Define _xor_*_32() functions. */ +MAKE_XOR_PER_RUN(64) /* Define _xor_*_64() functions. */ + +#define MAKE_XOR(xors_per_run) \ +struct { \ + void (*f)(xor_t**); \ +} static xor_funcs ## xors_per_run[] = { \ + { NULL }, \ + { NULL }, \ + { _xor2_ ## xors_per_run }, \ + { _xor3_ ## xors_per_run }, \ + { _xor4_ ## xors_per_run }, \ + { _xor5_ ## xors_per_run }, \ + { _xor6_ ## xors_per_run }, \ + { _xor7_ ## xors_per_run }, \ + { _xor8_ ## xors_per_run }, \ +}; \ +\ +static void xor_ ## xors_per_run(unsigned n, xor_t **data) \ +{ \ + /* Call respective function for amount of chunks. */ \ + xor_funcs ## xors_per_run[n].f(data); \ +} + +/* Define xor_8() - xor_64 functions. */ +MAKE_XOR(8) +MAKE_XOR(16) +MAKE_XOR(32) +MAKE_XOR(64) + +/* Maximum number of chunks, which can be xor'ed in one go. */ +#define XOR_CHUNKS_MAX (ARRAY_SIZE(xor_funcs8) - 1) + +struct xor_func { + xor_function_t f; + const char *name; +} static xor_funcs[] = { + {xor_8, "xor_8"}, + {xor_16, "xor_16"}, + {xor_32, "xor_32"}, + {xor_64, "xor_64"}, +}; + +/* + * Calculate crc. + * + * This indexes into the page list of the stripe. + * + * All chunks will be xored into the parity chunk + * in maximum groups of xor.chunks. + * + * FIXME: try mapping the pages on discontiguous memory. + */ +static void xor(struct stripe *stripe, unsigned pi, unsigned sector) +{ + struct raid_set *rs = RS(stripe->sc); + unsigned max_chunks = rs->xor.chunks, n, p; + unsigned o = sector / SECTORS_PER_PAGE; /* Offset into the page_list. */ + xor_t **d = rs->data; + xor_function_t xor_f = rs->xor.f->f; + + /* Address of parity page to xor into. */ + d[0] = page_address(pl_elem(PL(stripe, pi), o)->page); + + /* Preset pointers to data pages. */ + for (n = 1, p = rs->set.raid_devs; p--; ) { + if (p != pi && PageIO(PAGE(stripe, p))) + d[n++] = page_address(pl_elem(PL(stripe, p), o)->page); + + /* If max chunks -> xor .*/ + if (n == max_chunks) { + xor_f(n, d); + n = 1; + } + } + + /* If chunks -> xor. */ + if (n > 1) + xor_f(n, d); + + /* Set parity page uptodate and clean. */ + page_set(PAGE(stripe, pi), CLEAN); +} + +/* Common xor loop through all stripe page lists. */ +static void common_xor(struct stripe *stripe, sector_t count, + unsigned off, unsigned p) +{ + unsigned sector; + + for (sector = off; sector < count; sector += SECTORS_PER_XOR) + xor(stripe, p, sector); + + atomic_inc(RS(stripe->sc)->stats + S_XORS); /* REMOVEME: statistics. */ +} + +/* + * Calculate parity sectors on intact stripes. + * + * Need to calculate raid address for recover stripe, because its + * chunk sizes differs and is typically larger than io chunk size. + */ +static void parity_xor(struct stripe *stripe) +{ + struct raid_set *rs = RS(stripe->sc); + unsigned chunk_size = rs->set.chunk_size, + io_size = stripe->io.size, + xor_size = chunk_size > io_size ? io_size : chunk_size; + sector_t off; + + + /* This can be the recover stripe with a larger io size. */ + for (off = 0; off < io_size; off += xor_size) { + unsigned pi; + + /* + * Recover stripe likely is bigger than regular io + * ones and has no precalculated parity disk index -> + * need to calculate RAID address. + */ + if (unlikely(StripeRecover(stripe))) { + struct address addr; + + raid_address(rs, + (stripe->key + off) * rs->set.data_devs, + &addr); + pi = addr.pi; + stripe_zero_pl_part(stripe, pi, off, + rs->set.chunk_size); + } else + pi = stripe->idx.parity; + + common_xor(stripe, xor_size, off, pi); + page_set(PAGE(stripe, pi), DIRTY); + } +} + +/* Reconstruct missing chunk. */ +static void reconstruct_xor(struct stripe *stripe) +{ + struct raid_set *rs = RS(stripe->sc); + int p = stripe->idx.recover; + + BUG_ON(p < 0); + + /* REMOVEME: statistics. */ + atomic_inc(rs->stats + (raid_set_degraded(rs) ? + S_RECONSTRUCT_EI : S_RECONSTRUCT_DEV)); + + /* Zero chunk to be reconstructed. */ + stripe_zero_chunk(stripe, p); + common_xor(stripe, stripe->io.size, 0, p); +} + +/* + * Try getting a stripe either from the hash or from the lru list + */ +static inline void _stripe_get(struct stripe *stripe) +{ + atomic_inc(&stripe->cnt); +} + +static struct stripe *stripe_get(struct raid_set *rs, struct address *addr) +{ + struct stripe_cache *sc = &rs->sc; + struct stripe *stripe; + + + stripe = stripe_lookup(sc, addr->key); + if (stripe) { + _stripe_get(stripe); + /* Remove from the lru list if on. */ + stripe_lru_del(stripe, LIST_LOCKED); + atomic_inc(rs->stats + S_HITS_1ST); /* REMOVEME: statistics. */ + } else { + /* Second try to get an LRU stripe. */ + stripe = stripe_lru_pop(sc); + if (stripe) { + _stripe_get(stripe); + /* Invalidate before reinserting with changed key. */ + stripe_invalidate(stripe); + stripe->key = addr->key; + stripe->region = rh_sector_to_region(rs->recover.rh, + addr->key); + stripe->idx.parity = addr->pi; + sc_insert(sc, stripe); + /* REMOVEME: statistics. */ + atomic_inc(rs->stats + S_INSCACHE); + } + } + + return stripe; +} + +/* + * Decrement reference count on a stripe. + * + * Move it to list of LRU stripes if zero. + */ +static void stripe_put(struct stripe *stripe) +{ + if (atomic_dec_and_test(&stripe->cnt)) { + if (TestClearStripeActive(stripe)) + atomic_dec(&stripe->sc->active_stripes); + + /* Put stripe onto the LRU list. */ + stripe_lru_add(stripe, POS_TAIL, LIST_LOCKED); + } + + BUG_ON(atomic_read(&stripe->cnt) < 0); +} + +/* + * Process end io + * + * I need to do it here because I can't in interrupt + * + * Read and write functions are split in order to avoid + * conditionals in the main loop for performamce reasons. + */ +typedef void(*endio_helper_function)(struct stripe *, struct page_list *, + struct bio *); + +/* Helper read bios on a page list. */ +static void _bio_copy_page_list(struct stripe *stripe, struct page_list *pl, + struct bio *bio) +{ + bio_copy_page_list(READ, stripe, pl, bio); +} + +/* Helper write bios on a page list. */ +static void _rh_dec(struct stripe *stripe, struct page_list *pl, + struct bio *bio) +{ + rh_dec(RS(stripe->sc)->recover.rh, stripe->region); +} + +/* End io all bios on a page list. */ +static inline int +page_list_endio(int rw, struct stripe *stripe, unsigned p, unsigned *count) +{ + int r = 0; + struct bio_list *bl = BL(stripe, p, rw); + + if (!bio_list_empty(bl)) { + struct page_list *pl = PL(stripe, p); + struct page *page = pl->page; + + if (PageLocked(page)) + r = -EBUSY; + else if (PageUptodate(page)) { + struct bio *bio; + struct raid_set *rs = RS(stripe->sc); + endio_helper_function h_f = + rw == READ ? _bio_copy_page_list : _rh_dec; + + while ((bio = bio_list_pop(bl))) { + h_f(stripe, pl, bio); + _bio_endio(rs, bio, 0); + stripe_put(stripe); + if (count) + (*count)++; + } + } else + r = -EAGAIN; + } + + return r; +} + +/* + * End io all reads/writes on a stripe copying + * read date accross from stripe to bios. + */ +static int stripe_end_io(int rw, struct stripe *stripe, unsigned *count) +{ + int r = 0; + unsigned p = RS(stripe->sc)->set.raid_devs; + + while (p--) { + int rr = page_list_endio(rw, stripe, p, count); + + if (rr && r != -EIO) + r = rr; + } + + return r; +} + +/* Fail all ios on a bio list and return # of bios. */ +static unsigned +bio_list_fail(struct raid_set *rs, struct stripe *stripe, struct bio_list *bl) +{ + unsigned r; + struct bio *bio; + + raid_set_dead(rs); + + /* Update region counters. */ + if (stripe) { + void *rh = rs->recover.rh; + + bio_list_for_each(bio, bl) { + if (bio_data_dir(bio) == WRITE) + rh_dec(rh, stripe->region); + } + } + + /* Error end io all bios. */ + for (r = 0; (bio = bio_list_pop(bl)); r++) + _bio_endio(rs, bio, -EIO); + + return r; +} + +/* Fail all ios of a bio list of a stripe and drop io pending count. */ +static void +stripe_bio_list_fail(struct raid_set *rs, struct stripe *stripe, + struct bio_list *bl) +{ + unsigned put = bio_list_fail(rs, stripe, bl); + + while (put--) + stripe_put(stripe); +} + +/* Fail all ios hanging off all bio lists of a stripe. */ +static void stripe_fail_io(struct stripe *stripe) +{ + struct raid_set *rs = RS(stripe->sc); + unsigned p = rs->set.raid_devs; + + stripe_evict(stripe); + + while (p--) { + struct stripe_set *ss = stripe->ss + p; + int i = ARRAY_SIZE(ss->bl); + + while (i--) + stripe_bio_list_fail(rs, stripe, ss->bl + i); + } +} + +/* + * Handle all stripes by handing them to the daemon, because we can't + * map their pages to copy the data in interrupt context. + * + * We don't want to handle them here either, while interrupts are disabled. + */ + +/* Read/write endio function for dm-io (interrupt context). */ +static void endio(unsigned long error, void *context) +{ + struct dm_mem_cache_object *obj = context; + struct stripe_set *ss = obj->private; + struct stripe *stripe = ss->stripe; + struct page *page = obj->pl->page; + + if (unlikely(error)) + stripe_error(stripe, page); + else + page_set(page, CLEAN); + + clear_page_locked(page); + stripe_io_dec(stripe); + + /* Add stripe to endio list and wake daemon. */ + stripe_endio_push(stripe); +} + +/* + * Recovery io throttling + */ +/* Conditionally reset io counters. */ +enum count_type { IO_WORK = 0, IO_RECOVER }; +static int recover_io_reset(struct raid_set *rs) +{ + unsigned long j = jiffies; + + /* Pay attention to jiffies overflows. */ + if (j > rs->recover.last_jiffies + HZ + || j < rs->recover.last_jiffies) { + rs->recover.last_jiffies = j; + atomic_set(rs->recover.io_count + IO_WORK, 0); + atomic_set(rs->recover.io_count + IO_RECOVER, 0); + return 1; + } + + return 0; +} + +/* Count ios. */ +static INLINE void +recover_io_count(struct raid_set *rs, struct stripe *stripe) +{ + if (RSRecover(rs)) { + recover_io_reset(rs); + atomic_inc(rs->recover.io_count + + (stripe == rs->recover.stripe ? + IO_RECOVER : IO_WORK)); + } +} + +/* Read/Write a page_list asynchronously. */ +static void page_list_rw(struct stripe *stripe, unsigned p) +{ + struct stripe_cache *sc = stripe->sc; + struct raid_set *rs = RS(sc); + struct dm_mem_cache_object *obj = stripe->obj + p; + struct page_list *pl = obj->pl; + struct page *page = pl->page; + struct raid_dev *dev = rs->dev + p; + struct dm_io_region io = { + .bdev = dev->dev->bdev, + .sector = stripe->key, + .count = stripe->io.size, + }; + struct dm_io_request control = { + .bi_rw = PageDirty(page) ? WRITE : READ, + .mem.type = DM_IO_PAGE_LIST, + .mem.ptr.pl = pl, + .mem.offset = 0, + .notify.fn = endio, + .notify.context = obj, + .client = sc->dm_io_client, + }; + + BUG_ON(PageLocked(page)); + + /* + * Don't rw past end of device, which can happen, because + * typically sectors_per_dev isn't divisable by io_size. + */ + if (unlikely(io.sector + io.count > rs->set.sectors_per_dev)) + io.count = rs->set.sectors_per_dev - io.sector; + + io.sector += dev->start; /* Add . */ + recover_io_count(rs, stripe); /* Recovery io accounting. */ + + /* REMOVEME: statistics. */ + atomic_inc(rs->stats + (PageDirty(page) ? S_DM_IO_WRITE: S_DM_IO_READ)); + + ClearPageError(page); + set_page_locked(page); + io_dev_queued(dev); + BUG_ON(dm_io(&control, 1, &io, NULL)); +} + +/* + * Write dirty / read not uptodate page lists of a stripe. + */ +static unsigned stripe_page_lists_rw(struct raid_set *rs, struct stripe *stripe) +{ + unsigned r; + + /* + * Increment the pending count on the stripe + * first, so that we don't race in endio(). + * + * An inc (IO) is needed for any page: + * + * o not uptodate + * o dirtied by writes merged + * o dirtied by parity calculations + */ + r = for_each_io_dev(rs, stripe, _stripe_io_inc); + if (r) { + /* io needed: chunks are not uptodate/dirty. */ + int max; /* REMOVEME: */ + struct stripe_cache *sc = &rs->sc; + + if (!TestSetStripeActive(stripe)) + atomic_inc(&sc->active_stripes); + + /* Take off the lru list in case it got added there. */ + stripe_lru_del(stripe, LIST_LOCKED); + + /* Submit actual io. */ + for_each_io_dev(rs, stripe, page_list_rw); + + /* REMOVEME: statistics */ + max = sc_active(sc); + if (atomic_read(&sc->max_active_stripes) < max) + atomic_set(&sc->max_active_stripes, max); + + atomic_inc(rs->stats + S_FLUSHS); + /* END REMOVEME: statistics */ + } + + return r; +} + +/* Work in all pending writes. */ +static INLINE void _writes_merge(struct stripe *stripe, unsigned p) +{ + struct bio_list *write = BL(stripe, p, WRITE); + + if (!bio_list_empty(write)) { + struct page_list *pl = stripe->obj[p].pl; + struct bio *bio; + struct bio_list *write_merged = BL(stripe, p, WRITE_MERGED); + + /* + * We can play with the lists without holding a lock, + * because it is just us accessing them anyway. + */ + bio_list_for_each(bio, write) + bio_copy_page_list(WRITE, stripe, pl, bio); + + bio_list_merge(write_merged, write); + bio_list_init(write); + page_set(pl->page, DIRTY); + } +} + +/* Merge in all writes hence dirtying respective pages. */ +static INLINE void writes_merge(struct stripe *stripe) +{ + unsigned p = RS(stripe->sc)->set.raid_devs; + + while (p--) + _writes_merge(stripe, p); +} + +/* Check, if a chunk gets completely overwritten. */ +static INLINE int stripe_check_overwrite(struct stripe *stripe, unsigned p) +{ + unsigned sectors = 0; + struct bio *bio; + struct bio_list *bl = BL(stripe, p, WRITE); + + bio_list_for_each(bio, bl) + sectors += bio_sectors(bio); + + return sectors == RS(stripe->sc)->set.io_size; +} + +/* + * Prepare stripe to avoid io on broken/reconstructed + * drive to be reconstructed on endio. + */ +enum prepare_type { IO_ALLOW, IO_PROHIBIT }; +static void stripe_prepare(struct stripe *stripe, unsigned p, + enum prepare_type type) +{ + struct page *page = PAGE(stripe, p); + + switch (type) { + case IO_PROHIBIT: + /* REMOVEME: statistics. */ + atomic_inc(RS(stripe->sc)->stats + S_PROHIBITPAGEIO); + ProhibitPageIO(page); + stripe->idx.recover = p; + SetStripeReconstruct(stripe); + break; + + case IO_ALLOW: + AllowPageIO(page); + stripe->idx.recover = -1; + ClearStripeReconstruct(stripe); + break; + + default: + BUG(); + } +} + +/* + * Degraded/reconstruction mode. + * + * Check stripe state to figure which chunks don't need IO. + */ +static INLINE void stripe_check_reconstruct(struct stripe *stripe, + int prohibited) +{ + struct raid_set *rs = RS(stripe->sc); + + /* + * Degraded mode (device(s) failed) -> + * avoid io on the failed device. + */ + if (unlikely(raid_set_degraded(rs))) { + /* REMOVEME: statistics. */ + atomic_inc(rs->stats + S_DEGRADED); + stripe_prepare(stripe, rs->set.ei, IO_PROHIBIT); + return; + } else { + /* + * Reconstruction mode (ie. a particular device or + * some (rotating) parity chunk is being resynchronized) -> + * o make sure all needed pages are read in + * o writes are allowed to go through + */ + int r = region_state(rs, stripe->key, RH_NOSYNC); + + if (r) { + /* REMOVEME: statistics. */ + atomic_inc(rs->stats + S_NOSYNC); + stripe_prepare(stripe, dev_for_parity(stripe), + IO_PROHIBIT); + return; + } + } + + /* + * All disks good. Avoid reading parity chunk and reconstruct it + * unless we have prohibited io to chunk(s). + */ + if (!prohibited) { + if (StripeMerged(stripe)) + stripe_prepare(stripe, stripe->idx.parity, IO_ALLOW); + else { + stripe_prepare(stripe, stripe->idx.parity, IO_PROHIBIT); + ClearStripeReconstruct(stripe); + } + } +} + +/* Check, if stripe is ready to merge writes. */ +static INLINE int stripe_check_merge(struct stripe *stripe) +{ + struct raid_set *rs = RS(stripe->sc); + int prohibited = 0; + unsigned chunks = 0, p = rs->set.raid_devs; + + /* Walk all chunks. */ + while (p--) { + struct page *page = PAGE(stripe, p); + + /* Can't merge active chunks. */ + if (PageLocked(page)) { + /* REMOVEME: statistics. */ + atomic_inc(rs->stats + S_MERGE_PAGE_LOCKED); + break; + } + + /* Can merge uptodate chunks and have to count parity chunk. */ + if (PageUptodate(page) || p == stripe->idx.parity) { + chunks++; + continue; + } + + /* Read before write ordering. */ + if (RSCheckOverwrite(rs) && + bio_list_empty(BL(stripe, p, READ))) { + int r = stripe_check_overwrite(stripe, p); + + if (r) { + chunks++; + /* REMOVEME: statistics. */ + atomic_inc(RS(stripe->sc)->stats + + S_PROHIBITPAGEIO); + ProhibitPageIO(page); + prohibited = 1; + } + } + } + + if (chunks == rs->set.raid_devs) { + /* All pages are uptodate or get written over or mixture. */ + /* REMOVEME: statistics. */ + atomic_inc(rs->stats + S_CAN_MERGE); + return 0; + } else + /* REMOVEME: statistics.*/ + atomic_inc(rs->stats + S_CANT_MERGE); + + return prohibited ? 1 : -EPERM; +} + +/* Check, if stripe is ready to merge writes. */ +static INLINE int stripe_check_read(struct stripe *stripe) +{ + int r = 0; + unsigned p = RS(stripe->sc)->set.raid_devs; + + /* Walk all chunks. */ + while (p--) { + struct page *page = PAGE(stripe, p); + + if (!PageLocked(page) && + bio_list_empty(BL(stripe, p, READ))) { + ProhibitPageIO(page); + r = 1; + } + } + + return r; +} + +/* + * Read/write a stripe. + * + * States to cover: + * o stripe to read and/or write + * o stripe with error to reconstruct + */ +static int stripe_rw(struct stripe *stripe) +{ + struct raid_set *rs = RS(stripe->sc); + int prohibited = 0, r; + + /* + * Check the state of the RAID set and if degraded (or + * resynchronizing for reads), read in all other chunks but + * the one on the dead/resynchronizing device in order to be + * able to reconstruct the missing one. + * + * Merge all writes hanging off uptodate pages of the stripe. + */ + + /* Initially allow io on all chunks and prohibit below, if necessary. */ + stripe_allow_io(stripe); + + if (StripeRBW(stripe)) { + r = stripe_check_merge(stripe); + if (!r) { + /* + * If I could rely on valid parity (which would only + * be sure in case of a full synchronization), + * I could xor a fraction of chunks out of + * parity and back in. + * + * For the time being, I got to redo parity... + */ + // parity_xor(stripe); /* Xor chunks out. */ + stripe_zero_chunk(stripe, stripe->idx.parity); + writes_merge(stripe); /* Merge writes in. */ + parity_xor(stripe); /* Update parity. */ + ClearStripeRBW(stripe); /* Disable RBW. */ + SetStripeMerged(stripe); /* Writes merged. */ + } + + if (r > 0) + prohibited = 1; + } else if (!raid_set_degraded(rs)) + prohibited = stripe_check_read(stripe); + + /* + * Check, if io needs to be allowed/prohibeted on certain chunks + * because of a degraded set or reconstruction on a region. + */ + stripe_check_reconstruct(stripe, prohibited); + + /* Now submit any reads/writes. */ + r = stripe_page_lists_rw(rs, stripe); + if (!r) { + /* + * No io submitted because of chunk io prohibited or + * locked pages -> push to end io list for processing. + */ + atomic_inc(rs->stats + S_NO_RW); /* REMOVEME: statistics. */ + stripe_endio_push(stripe); + wake_do_raid(rs); /* Wake myself. */ + } + + return 0; +} + +/* Flush stripe either via flush list or imeediately. */ +enum flush_type { FLUSH_DELAY, FLUSH_NOW }; +static int stripe_flush(struct stripe *stripe, enum flush_type type) +{ + int r = 0; + + stripe_lru_del(stripe, LIST_LOCKED); + + /* Delay flush by putting it on io list for later processing. */ + if (type == FLUSH_DELAY) + stripe_io_add(stripe, POS_TAIL, LIST_UNLOCKED); + + /* Immediately flush. */ + else if (type == FLUSH_NOW) { + if (likely(raid_set_operational(RS(stripe->sc)))) + r = stripe_rw(stripe); /* Read/write stripe. */ + else + /* Optimization: Fail early on failed sets. */ + stripe_fail_io(stripe); + } else + BUG(); + + return r; +} + +/* + * Queue reads and writes to a stripe by hanging + * their bios off the stripsets read/write lists. + * + * Endio reads on uptodate chunks. + */ +static INLINE int stripe_queue_bio(struct raid_set *rs, struct bio *bio, + struct bio_list *reject) +{ + int r = 0; + struct address addr; + struct stripe *stripe = + stripe_get(rs, raid_address(rs, bio->bi_sector, &addr)); + + if (stripe) { + int rr, rw = bio_data_dir(bio); + + rr = stripe_lock(rs, stripe, rw, addr.key); /* Lock stripe */ + if (rr) { + stripe_put(stripe); + goto out; + } + + /* Distinguish read and write cases. */ + bio_list_add(BL(stripe, addr.di, rw), bio); + + /* REMOVEME: statistics */ + atomic_inc(rs->stats + (rw == WRITE ? + S_BIOS_ADDED_WRITE : S_BIOS_ADDED_READ)); + + if (rw == READ) + SetStripeRead(stripe); + else { + SetStripeRBW(stripe); + + /* Inrement pending write count on region. */ + rh_inc(rs->recover.rh, stripe->region); + r = 1; /* Region hash needs a flush. */ + } + + /* + * Optimize stripe flushing: + * + * o directly start io for read stripes. + * + * o put stripe onto stripe caches io_list for RBW, + * so that do_flush() can belabour it after we put + * more bios to the stripe for overwrite optimization. + */ + stripe_flush(stripe, + StripeRead(stripe) ? FLUSH_NOW : FLUSH_DELAY); + + /* Got no stripe from cache -> reject bio. */ + } else { + out: + bio_list_add(reject, bio); + /* REMOVEME: statistics. */ + atomic_inc(rs->stats + S_IOS_POST); + } + + return r; +} + +/* + * Recovery functions + */ +/* Read a stripe off a raid set for recovery. */ +static int recover_read(struct raid_set *rs, struct stripe *stripe, int idx) +{ + /* Invalidate all pages so that they get read in. */ + stripe_pages_invalidate(stripe); + + /* Allow io on all recovery chunks. */ + stripe_allow_io(stripe); + + if (idx > -1) + ProhibitPageIO(PAGE(stripe, idx)); + + stripe->key = rs->recover.pos; + return stripe_page_lists_rw(rs, stripe); +} + +/* Write a stripe to a raid set for recovery. */ +static int recover_write(struct raid_set *rs, struct stripe *stripe, int idx) +{ + /* + * If this is a reconstruct of a particular device, then + * reconstruct the respective page(s), else create parity page(s). + */ + if (idx > -1) { + struct page *page = PAGE(stripe, idx); + + AllowPageIO(page); + stripe_zero_chunk(stripe, idx); + common_xor(stripe, stripe->io.size, 0, idx); + page_set(page, DIRTY); + } else + parity_xor(stripe); + + return stripe_page_lists_rw(rs, stripe); +} + +/* Recover bandwidth available ?. */ +static int recover_bandwidth(struct raid_set *rs) +{ + int r, work; + + /* On reset -> allow recovery. */ + r = recover_io_reset(rs); + if (r || RSBandwidth(rs)) + goto out; + + work = atomic_read(rs->recover.io_count + IO_WORK); + if (work) { + /* Pay attention to larger recover stripe size. */ + int recover = + atomic_read(rs->recover.io_count + IO_RECOVER) * + rs->recover.stripe->io.size / + rs->set.io_size; + + /* + * Don't use more than given bandwidth of + * the work io for recovery. + */ + if (recover > work / rs->recover.bandwidth_work) { + /* REMOVEME: statistics. */ + atomic_inc(rs->stats + S_NO_BANDWIDTH); + return 0; + } + } + + out: + atomic_inc(rs->stats + S_BANDWIDTH); /* REMOVEME: statistics. */ + return 1; +} + +/* Try to get a region to recover. */ +static int recover_get_region(struct raid_set *rs) +{ + struct recover *rec = &rs->recover; + void *rh = rec->rh; + + /* Start quiescing some regions. */ + if (!RSRegionGet(rs)) { + int r = recover_bandwidth(rs); /* Enough bandwidth ?. */ + + if (r) { + if (rh_recovery_prepare(rh) < 0) { + DMINFO("No %sregions to recover", + rec->nr_regions_to_recover ? + "more " : ""); + return -ENOENT; + } + } else + return -EAGAIN; + + SetRSRegionGet(rs); + } + + if (!rec->reg) { + rec->reg = rh_recovery_start(rh); + if (rec->reg) { + /* + * A reference for the the region I'll + * keep till I've completely synced it. + */ + io_get(rs); + rec->pos = + rh_region_to_sector(rh, + rh_get_region_key(rec->reg)); + rec->end = rec->pos + rh_get_region_size(rh); + return 1; + } else + return -EAGAIN; + } + + return 0; +} + +/* Read/write a recovery stripe. */ +static INLINE int recover_stripe_rw(struct raid_set *rs, struct stripe *stripe) +{ + /* Read/write flip-flop. */ + if (TestClearStripeRBW(stripe)) { + SetStripeRead(stripe); + return recover_read(rs, stripe, idx_get(rs)); + } else if (TestClearStripeRead(stripe)) + return recover_write(rs, stripe, idx_get(rs)); + + return 0; +} + +/* Reset recovery variables. */ +static void recovery_region_reset(struct raid_set *rs) +{ + rs->recover.reg = NULL; + ClearRSRegionGet(rs); +} + +/* Update region hash state. */ +static void recover_rh_update(struct raid_set *rs, int error) +{ + struct recover *rec = &rs->recover; + void *rh = rec->rh; + void *reg = rec->reg; + + if (reg) { + rh_recovery_end(reg, error); + if (!error) + rec->nr_regions_recovered++; + + recovery_region_reset(rs); + } + + rh_update_states(rh); + rh_flush(rh); + io_put(rs); /* Release the io reference for the region. */ +} + +/* Called by main io daemon to recover regions. */ +static INLINE void do_recovery(struct raid_set *rs) +{ + if (RSRecover(rs)) { + int r; + struct recover *rec = &rs->recover; + struct stripe *stripe = rec->stripe; + + /* If recovery is active -> return. */ + if (StripeActive(stripe)) + return; + + /* io error is fatal for recovery -> stop it. */ + if (unlikely(StripeError(stripe))) + goto err; + + /* Get a region to recover. */ + r = recover_get_region(rs); + switch (r) { + case 1: /* Got a new region. */ + /* Flag read before write. */ + ClearStripeRead(stripe); + SetStripeRBW(stripe); + break; + + case 0: + /* Got a region in the works. */ + r = recover_bandwidth(rs); + if (r) /* Got enough bandwidth. */ + break; + + case -EAGAIN: + /* No bandwidth/quiesced region yet, try later. */ + wake_do_raid_delayed(rs, HZ / 10); + return; + + case -ENOENT: /* No more regions. */ + goto free; + } + + /* Read/write a recover stripe. */ + r = recover_stripe_rw(rs, stripe); + if (r) { + /* Io initiated, get another reference for the IO. */ + io_get(rs); + return; + } + + /* Update recovery position within region. */ + rec->pos += stripe->io.size; + + /* If we're at end of region, update region hash. */ + if (rec->pos >= rec->end || + rec->pos >= rs->set.sectors_per_dev) + recover_rh_update(rs, 0); + else + SetStripeRBW(stripe); + + /* Schedule myself for another round... */ + wake_do_raid(rs); + return; + + err: + raid_set_check_degrade(rs, stripe); + + { + char buf[BDEVNAME_SIZE]; + + DMERR("stopping recovery due to " + "ERROR on /dev/%s, stripe at offset %llu", + bdevname(rs->dev[rs->set.ei].dev->bdev, buf), + (unsigned long long) stripe->key); + + } + + /* Make sure, that all quiesced regions get released. */ + do { + if (rec->reg) + rh_recovery_end(rec->reg, -EIO); + + rec->reg = rh_recovery_start(rec->rh); + } while (rec->reg); + + recover_rh_update(rs, -EIO); + free: + stripe_recover_free(rs); + rs->set.dev_to_init = -1; + rs->recover.end_jiffies = jiffies; + /* Check for jiffies overrun. */ + if (rs->recover.end_jiffies < rs->recover.start_jiffies) + rs->recover.end_jiffies = ~0; + } +} + +/* + * END recovery functions + */ + +/* End io process all stripes handed in by endio() callback. */ +static void do_endios(struct raid_set *rs) +{ + struct stripe_cache *sc = &rs->sc; + struct stripe *stripe; + + while ((stripe = stripe_endio_pop(sc))) { + unsigned count; + + /* Recovery stripe special case. */ + if (unlikely(StripeRecover(stripe))) { + if (stripe_io(stripe)) + continue; + + io_put(rs); /* Release region io reference. */ + ClearStripeActive(stripe); + atomic_dec(&sc->active_stripes); /* REMOVEME: */ + continue; + } + + /* Early end io all reads on any uptodate chunks. */ + stripe_end_io(READ, stripe, (count = 0, &count)); + if (stripe_io(stripe)) { + if (count) /* REMOVEME: statistics. */ + atomic_inc(rs->stats + S_ACTIVE_READS); + + continue; + } + + /* Set stripe inactive after all io got processed. */ + if (TestClearStripeActive(stripe)) + atomic_dec(&sc->active_stripes); + + /* Unlock stripe (for clustering). */ + stripe_unlock(rs, stripe); + + /* + * If an io error on a stripe occured and the RAID set + * is still operational, requeue the stripe for io. + */ + if (TestClearStripeError(stripe)) { + raid_set_check_degrade(rs, stripe); + ClearStripeReconstruct(stripe); + + if (!StripeMerged(stripe) && + raid_set_operational(rs)) { + stripe_pages_invalidate(stripe); + stripe_flush(stripe, FLUSH_DELAY); + /* REMOVEME: statistics. */ + atomic_inc(rs->stats + S_REQUEUE); + continue; + } + } + + /* Check if the RAID set is inoperational to error ios. */ + if (!raid_set_operational(rs)) { + ClearStripeReconstruct(stripe); + stripe_fail_io(stripe); + BUG_ON(atomic_read(&stripe->cnt)); + continue; + } + + /* Got to reconstruct a missing chunk. */ + if (TestClearStripeReconstruct(stripe)) + reconstruct_xor(stripe); + + /* + * Now that we've got a complete stripe, we can + * process the rest of the end ios on reads. + */ + BUG_ON(stripe_end_io(READ, stripe, NULL)); + ClearStripeRead(stripe); + + /* + * Read-before-write stripes need to be flushed again in + * order to work the write data into the pages *after* + * they were read in. + */ + if (TestClearStripeMerged(stripe)) + /* End io all bios which got merged already. */ + BUG_ON(stripe_end_io(WRITE_MERGED, stripe, NULL)); + + /* Got to put on flush list because of new writes. */ + if (StripeRBW(stripe)) + stripe_flush(stripe, FLUSH_DELAY); + } +} + +/* + * Stripe cache shrinking. + */ +static INLINE void do_sc_shrink(struct raid_set *rs) +{ + unsigned shrink = atomic_read(&rs->sc.stripes_to_shrink); + + if (shrink) { + unsigned cur = atomic_read(&rs->sc.stripes); + + sc_shrink(&rs->sc, shrink); + shrink -= cur - atomic_read(&rs->sc.stripes); + atomic_set(&rs->sc.stripes_to_shrink, shrink); + + /* + * Wake myself up in case we failed to shrink the + * requested amount in order to try again later. + */ + if (shrink) + wake_do_raid(rs); + } +} + + +/* + * Process all ios + * + * We do different things with the io depending on the + * state of the region that it's in: + * + * o reads: hang off stripe cache or postpone if full + * + * o writes: + * + * CLEAN/DIRTY/NOSYNC: increment pending and hang io off stripe's stripe set. + * In case stripe cache is full or busy, postpone the io. + * + * RECOVERING: delay the io until recovery of the region completes. + * + */ +static INLINE void do_ios(struct raid_set *rs, struct bio_list *ios) +{ + int r; + unsigned flush = 0; + void *rh = rs->recover.rh; + struct bio *bio; + struct bio_list delay, reject; + + bio_list_init(&delay); + bio_list_init(&reject); + + /* + * Classify each io: + * o delay to recovering regions + * o queue to all other regions + */ + while ((bio = bio_list_pop(ios))) { + /* + * In case we get a barrier bio, push it back onto + * the input queue unless all work queues are empty + * and the stripe cache is inactive. + */ + if (unlikely(bio_barrier(bio))) { + /* REMOVEME: statistics. */ + atomic_inc(rs->stats + S_BARRIER); + if (!list_empty(rs->sc.lists + LIST_IO) || + !bio_list_empty(&delay) || + !bio_list_empty(&reject) || + sc_active(&rs->sc)) { + bio_list_push(ios, bio); + break; + } + } + + r = region_state(rs, _sector(rs, bio), RH_RECOVERING); + if (unlikely(r)) { + /* Got to wait for recovering regions. */ + bio_list_add(&delay, bio); + SetRSBandwidth(rs); + } else { + /* + * Process ios to non-recovering regions by queueing + * them to stripes (does rh_inc()) for writes). + */ + flush += stripe_queue_bio(rs, bio, &reject); + } + } + + if (flush) + rh_flush(rh); /* Writes got queued -> flush dirty log. */ + + /* Delay ios to regions which are recovering. */ + while ((bio = bio_list_pop(&delay))) { + /* REMOVEME: statistics.*/ + atomic_inc(rs->stats + S_DELAYED_BIOS); + atomic_inc(rs->stats + S_SUM_DELAYED_BIOS); + rh_delay_by_region(rh, bio, + rh_sector_to_region(rh, _sector(rs, bio))); + } + + /* Merge any rejected bios back to the head of the input list. */ + bio_list_merge_head(ios, &reject); +} + +/* Flush any stripes on the io list. */ +static INLINE void do_flush(struct raid_set *rs) +{ + struct list_head *list = rs->sc.lists + LIST_IO, *pos, *tmp; + + list_for_each_safe(pos, tmp, list) { + int r = stripe_flush(list_entry(pos, struct stripe, + lists[LIST_IO]), FLUSH_NOW); + + /* Remove from the list only if the stripe got processed. */ + if (!r) + list_del_init(pos); + } +} + +/* Send an event in case we're getting too busy. */ +static INLINE void do_busy_event(struct raid_set *rs) +{ + if ((sc_active(&rs->sc) > atomic_read(&rs->sc.stripes) * 4 / 5)) { + if (!TestSetRSScBusy(rs)) + dm_table_event(rs->ti->table); + } else + ClearRSScBusy(rs); +} + +/* Unplug: let the io role on the sets devices. */ +static INLINE void do_unplug(struct raid_set *rs) +{ + struct raid_dev *dev = rs->dev + rs->set.raid_devs; + + while (dev-- > rs->dev) { + /* Only call any device unplug function, if io got queued. */ + if (io_dev_clear(dev)) { + struct request_queue *q = + bdev_get_queue(dev->dev->bdev); + + if (q->unplug_fn) + q->unplug_fn(q); + } + } +} + +/*----------------------------------------------------------------- + * RAID daemon + *---------------------------------------------------------------*/ +/* + * o belabour all end ios + * o optionally shrink the stripe cache + * o update the region hash states + * o optionally do recovery + * o grab the input queue + * o work an all requeued or new ios and perform stripe cache flushs + * unless the RAID set is inoperational (when we error ios) + * o check, if the stripe cache gets too busy and throw an event if so + * o unplug any component raid devices with queued bios + */ +static void do_raid(struct work_struct *ws) +{ + struct raid_set *rs = container_of(ws, struct raid_set, io.dws.work); + struct bio_list *ios = &rs->io.work, *ios_in = &rs->io.in; + spinlock_t *lock = &rs->io.in_lock; + + /* + * We always need to end io, so that ios + * can get errored in case the set failed + * and the region counters get decremented + * before we update the region hash states. + */ + redo: + do_endios(rs); + + /* + * Now that we've end io'd, which may have put stripes on + * the LRU list, we shrink the stripe cache if requested. + */ + do_sc_shrink(rs); + + /* Update region hash states before we go any further. */ + rh_update_states(rs->recover.rh); + + /* Try to recover regions. */ + do_recovery(rs); + + /* More endios -> process. */ + if (!stripe_endio_empty(&rs->sc)) { + atomic_inc(rs->stats + S_REDO); + goto redo; + } + + /* Quickly grab all new ios queued and add them to the work list. */ + spin_lock_irq(lock); + bio_list_merge(ios, ios_in); + bio_list_init(ios_in); + spin_unlock_irq(lock); + + /* Let's assume we're operational most of the time ;-). */ + if (likely(raid_set_operational(rs))) { + /* If we got ios, work them into the cache. */ + if (!bio_list_empty(ios)) { + do_ios(rs, ios); + do_unplug(rs); /* Unplug the sets device queues. */ + } + + do_flush(rs); /* Flush any stripes on io list. */ + do_unplug(rs); /* Unplug the sets device queues. */ + do_busy_event(rs); /* Check if we got too busy. */ + + /* More endios -> process. */ + if (!stripe_endio_empty(&rs->sc)) { + atomic_inc(rs->stats + S_REDO); + goto redo; + } + } else + /* No way to reconstruct data with too many devices failed. */ + bio_list_fail(rs, NULL, ios); +} + +/* + * Callback for region hash to dispatch + * delayed bios queued to recovered regions + * (Gets called via rh_update_states()). + */ +static void dispatch_delayed_bios(void *context, struct bio_list *bl) +{ + struct raid_set *rs = context; + struct bio *bio; + + /* REMOVEME: decrement pending delayed bios counter. */ + bio_list_for_each(bio, bl) + atomic_dec(rs->stats + S_DELAYED_BIOS); + + /* Merge region hash private list to work list. */ + bio_list_merge_head(&rs->io.work, bl); + bio_list_init(bl); + ClearRSBandwidth(rs); +} + +/************************************************************* + * Constructor helpers + *************************************************************/ +#define XOR_SPEED_SIZE rs->recover.io_size + +/* Calculate MB/sec. */ +static INLINE unsigned mbpers(struct raid_set *rs, unsigned speed) +{ + return to_bytes(speed * rs->set.data_devs * + XOR_SPEED_SIZE * HZ >> 10) >> 10; +} + +/* + * Discover fastest xor algorithm and # of chunks combination. + */ +/* Calculate speed for algorithm and # of chunks. */ +static INLINE unsigned xor_speed(struct raid_set *rs) +{ + unsigned r = 0; + unsigned long j; + + for (j = jiffies; j == jiffies;); /* Wait for next tick. */ + + /* Do xors for a full tick. */ + for (j = jiffies; j == jiffies;) { + mb(); + common_xor(rs->recover.stripe, XOR_SPEED_SIZE, 0, 0); + mb(); + r++; + mb(); + } + + return r; +} + +/* Optimize xor algorithm for this RAID set. */ +static unsigned xor_optimize(struct raid_set *rs) +{ + unsigned chunks_max = 2, speed_max = 0; + struct xor_func *f = ARRAY_END(xor_funcs), *f_max = NULL; + + /* + * Got to allow io on all chunks, so that + * xor() will actually work on them. + */ + stripe_allow_io(rs->recover.stripe); + + /* Try all xor functions. */ + while (f-- > xor_funcs) { + unsigned speed; + + /* Set actual xor function for common_xor(). */ + rs->xor.f = f; + rs->xor.chunks = XOR_CHUNKS_MAX + 1; + + while (rs->xor.chunks-- > 2) { + speed = xor_speed(rs); + if (speed > speed_max) { + speed_max = speed; + chunks_max = rs->xor.chunks; + f_max = f; + } + } + } + + /* Memorize optimum parameters. */ + rs->xor.f = f_max; + rs->xor.chunks = chunks_max; + return speed_max; +} + +/* + * Allocate a RAID context (a RAID set) + */ +static int +context_alloc(struct raid_set **raid_set, struct raid_type *raid_type, + unsigned stripes, unsigned chunk_size, unsigned io_size, + unsigned recover_io_size, unsigned raid_devs, + sector_t sectors_per_dev, + struct dm_target *ti, unsigned dl_parms, char **argv) +{ + int r; + unsigned p; + size_t len; + sector_t region_size, ti_len; + struct raid_set *rs = NULL; + struct dm_dirty_log *dl; + + /* + * Create the dirty log + * + * We need to change length for the dirty log constructor, + * because we want an amount of regions for all stripes derived + * from the single device size, so that we can keep region + * size = 2^^n independant of the number of devices + */ + ti_len = ti->len; + ti->len = sectors_per_dev; + dl = dm_dirty_log_create(argv[0], ti, dl_parms, argv + 2); + ti->len = ti_len; + if (!dl) + goto bad_dirty_log; + + /* Chunk size *must* be smaller than region size. */ + region_size = dl->type->get_region_size(dl); + if (chunk_size > region_size) + goto bad_chunk_size; + + /* Recover io size *must* be smaller than region size as well. */ + if (recover_io_size > region_size) + goto bad_recover_io_size; + + /* Size and allocate the RAID set structure. */ + len = sizeof(*rs->data) + sizeof(*rs->dev); + if (array_too_big(sizeof(*rs), len, raid_devs)) + goto bad_array; + + len = sizeof(*rs) + raid_devs * len; + rs = kzalloc(len, GFP_KERNEL); + if (!rs) + goto bad_alloc; + + atomic_set(&rs->io.in_process, 0); + atomic_set(&rs->io.in_process_max, 0); + rs->recover.io_size = recover_io_size; + + /* Pointer to data array. */ + rs->data = (xor_t **) ((void *) rs->dev + raid_devs * sizeof(*rs->dev)); + rs->recover.dl = dl; + rs->set.raid_devs = p = raid_devs; + rs->set.data_devs = raid_devs - raid_type->parity_devs; + rs->set.raid_type = raid_type; + + /* + * Set chunk and io size and respective shifts + * (used to avoid divisions) + */ + rs->set.chunk_size = chunk_size; + rs->set.chunk_mask = chunk_size - 1; + rs->set.chunk_shift = ffs(chunk_size) - 1; + + rs->set.io_size = io_size; + rs->set.io_mask = io_size - 1; + rs->set.io_shift = ffs(io_size) - 1; + rs->set.io_shift_mask = rs->set.chunk_mask & ~rs->set.io_mask; + + rs->set.pages_per_io = chunk_pages(io_size); + rs->set.sectors_per_dev = sectors_per_dev; + + rs->set.ei = -1; /* Indicate no failed device. */ + atomic_set(&rs->set.failed_devs, 0); + + rs->ti = ti; + + atomic_set(rs->recover.io_count + IO_WORK, 0); + atomic_set(rs->recover.io_count + IO_RECOVER, 0); + + /* Initialize io lock and queues. */ + spin_lock_init(&rs->io.in_lock); + bio_list_init(&rs->io.in); + bio_list_init(&rs->io.work); + + init_waitqueue_head(&rs->io.suspendq); /* Suspend waiters (dm-io). */ + + rs->recover.nr_regions = dm_sector_div_up(sectors_per_dev, region_size); + r = rh_init(&rs->recover.rh, 1, dispatch_delayed_bios, rs, + wake_do_raid, rs, dl, region_size, + rs->recover.nr_regions); + if (r) + goto bad_rh; + + /* Initialize stripe cache. */ + r = sc_init(rs, stripes); + if (r) + goto bad_sc; + + /* Create dm-io client context. */ + rs->sc.dm_io_client = dm_io_client_create(rs->set.raid_devs * + rs->set.pages_per_io); + if (IS_ERR(rs->sc.dm_io_client)) + goto bad_dm_io_client; + + /* REMOVEME: statistics. */ + stats_reset(rs); + ClearRSDevelStats(rs); /* Disnable development status. */ + + *raid_set = rs; + return 0; + + bad_dirty_log: + TI_ERR_RET("Error creating dirty log", -ENOMEM); + + + bad_chunk_size: + dm_dirty_log_destroy(dl); + TI_ERR("Chunk size larger than region size"); + + bad_recover_io_size: + dm_dirty_log_destroy(dl); + TI_ERR("Recover stripe io size larger than region size"); + + bad_array: + dm_dirty_log_destroy(dl); + TI_ERR("Arry too big"); + + bad_alloc: + dm_dirty_log_destroy(dl); + TI_ERR_RET("Cannot allocate raid context", -ENOMEM); + + bad_rh: + dm_dirty_log_destroy(dl); + ti->error = DM_MSG_PREFIX "Error creating dirty region hash"; + goto free_rs; + + bad_sc: + ti->error = DM_MSG_PREFIX "Error creating stripe cache"; + goto free; + + bad_dm_io_client: + ti->error = DM_MSG_PREFIX "Error allocating dm-io resources"; + free: + sc_exit(&rs->sc); + rh_exit(rs->recover.rh); + free_rs: + kfree(rs); + return -ENOMEM; +} + +/* Free a RAID context (a RAID set). */ +static void +context_free(struct raid_set *rs, struct dm_target *ti, unsigned r) +{ + while (r--) + dm_put_device(ti, rs->dev[r].dev); + + dm_io_client_destroy(rs->sc.dm_io_client); + stripe_recover_free(rs); + sc_exit(&rs->sc); + rh_exit(rs->recover.rh); /* Destroys dirty log as well. */ + kfree(rs); +} + +/* Create work queue and initialize work. */ +static int rs_workqueue_init(struct raid_set *rs) +{ + struct dm_target *ti = rs->ti; + + rs->io.wq = create_singlethread_workqueue(DAEMON); + if (!rs->io.wq) + TI_ERR_RET("failed to create " DAEMON, -ENOMEM); + + INIT_DELAYED_WORK(&rs->io.dws, do_raid); + return 0; +} + +/* Return pointer to raid_type structure for raid name. */ +static struct raid_type *get_raid_type(char *name) +{ + struct raid_type *r = ARRAY_END(raid_types); + + while (r-- > raid_types) { + if (!strnicmp(STR_LEN(r->name, name))) + return r; + } + + return NULL; +} + +/* FIXME: factor out to dm core. */ +static int multiple(sector_t a, sector_t b, sector_t *n) +{ + sector_t r = a; + + sector_div(r, b); + *n = r; + return a == r * b; +} + +/* Log RAID set information to kernel log. */ +static void raid_set_log(struct raid_set *rs, unsigned speed) +{ + unsigned p; + char buf[BDEVNAME_SIZE]; + + for (p = 0; p < rs->set.raid_devs; p++) + DMINFO("/dev/%s is raid disk %u", + bdevname(rs->dev[p].dev->bdev, buf), p); + + DMINFO("%d/%d/%d sectors chunk/io/recovery size, %u stripes", + rs->set.chunk_size, rs->set.io_size, rs->recover.io_size, + atomic_read(&rs->sc.stripes)); + DMINFO("algorithm \"%s\", %u chunks with %uMB/s", rs->xor.f->name, + rs->xor.chunks, mbpers(rs, speed)); + DMINFO("%s set with net %u/%u devices", rs->set.raid_type->descr, + rs->set.data_devs, rs->set.raid_devs); +} + +/* Get all devices and offsets. */ +static int +dev_parms(struct dm_target *ti, struct raid_set *rs, + char **argv, int *p) +{ + for (*p = 0; *p < rs->set.raid_devs; (*p)++, argv += 2) { + int r; + unsigned long long tmp; + struct raid_dev *dev = rs->dev + *p; + union dev_lookup dl = {.dev = dev }; + + /* Get offset and device. */ + r = sscanf(argv[1], "%llu", &tmp); + if (r != 1) + TI_ERR("Invalid RAID device offset parameter"); + + dev->start = tmp; + r = dm_get_device(ti, argv[0], dev->start, + rs->set.sectors_per_dev, + dm_table_get_mode(ti->table), &dev->dev); + if (r) + TI_ERR_RET("RAID device lookup failure", r); + + r = raid_dev_lookup(rs, bynumber, &dl); + if (r != -ENODEV && r < *p) { + (*p)++; /* Ensure dm_put_device() on actual device. */ + TI_ERR_RET("Duplicate RAID device", -ENXIO); + } + } + + return 0; +} + +/* Set recovery bandwidth. */ +static INLINE void +recover_set_bandwidth(struct raid_set *rs, unsigned bandwidth) +{ + rs->recover.bandwidth = bandwidth; + rs->recover.bandwidth_work = 100 / bandwidth; +} + +/* Handle variable number of RAID parameters. */ +static int +raid_variable_parms(struct dm_target *ti, char **argv, + unsigned i, int *raid_parms, + int *chunk_size, int *chunk_size_parm, + int *stripes, int *stripes_parm, + int *io_size, int *io_size_parm, + int *recover_io_size, int *recover_io_size_parm, + int *bandwidth, int *bandwidth_parm) +{ + /* Fetch # of variable raid parameters. */ + if (sscanf(argv[i++], "%d", raid_parms) != 1 || + !range_ok(*raid_parms, 0, 5)) + TI_ERR("Bad variable raid parameters number"); + + if (*raid_parms) { + /* + * If we've got variable RAID parameters, + * chunk size is the first one + */ + if (sscanf(argv[i++], "%d", chunk_size) != 1 || + (*chunk_size != -1 && + (!POWER_OF_2(*chunk_size) || + !range_ok(*chunk_size, IO_SIZE_MIN, CHUNK_SIZE_MAX)))) + TI_ERR ("Invalid chunk size; " + "must be 2^^n and <= 16384"); + + *chunk_size_parm = *chunk_size; + if (*chunk_size == -1) + *chunk_size = CHUNK_SIZE; + + /* + * In case we've got 2 or more variable raid + * parameters, the number of stripes is the second one + */ + if (*raid_parms > 1) { + if (sscanf(argv[i++], "%d", stripes) != 1 || + (*stripes != -1 && + !range_ok(*stripes, STRIPES_MIN, + STRIPES_MAX))) + TI_ERR("Invalid number of stripes: must " + "be >= 8 and <= 8192"); + } + + *stripes_parm = *stripes; + if (*stripes == -1) + *stripes = STRIPES; + + /* + * In case we've got 3 or more variable raid + * parameters, the io size is the third one. + */ + if (*raid_parms > 2) { + if (sscanf(argv[i++], "%d", io_size) != 1 || + (*io_size != -1 && + (!POWER_OF_2(*io_size) || + !range_ok(*io_size, IO_SIZE_MIN, + min(BIO_MAX_SECTORS / 2, + *chunk_size))))) + TI_ERR("Invalid io size; must " + "be 2^^n and less equal " + "min(BIO_MAX_SECTORS/2, chunk size)"); + } else + *io_size = *chunk_size; + + *io_size_parm = *io_size; + if (*io_size == -1) + *io_size = *chunk_size; + + /* + * In case we've got 4 variable raid parameters, + * the recovery stripe io_size is the fourth one + */ + if (*raid_parms > 3) { + if (sscanf(argv[i++], "%d", recover_io_size) != 1 || + (*recover_io_size != -1 && + (!POWER_OF_2(*recover_io_size) || + !range_ok(*recover_io_size, RECOVER_IO_SIZE_MIN, + BIO_MAX_SECTORS / 2)))) + TI_ERR("Invalid recovery io size; must be " + "2^^n and less equal BIO_MAX_SECTORS/2"); + } + + *recover_io_size_parm = *recover_io_size; + if (*recover_io_size == -1) + *recover_io_size = RECOVER_IO_SIZE; + + /* + * In case we've got 5 variable raid parameters, + * the recovery io bandwidth is the fifth one + */ + if (*raid_parms > 4) { + if (sscanf(argv[i++], "%d", bandwidth) != 1 || + (*bandwidth != -1 && + !range_ok(*bandwidth, BANDWIDTH_MIN, + BANDWIDTH_MAX))) + TI_ERR("Invalid recovery bandwidth " + "percentage; must be > 0 and <= 100"); + } + + *bandwidth_parm = *bandwidth; + if (*bandwidth == -1) + *bandwidth = BANDWIDTH; + } + + return 0; +} + +/* Parse optional locking parameters. */ +static int +raid_locking_parms(struct dm_target *ti, char **argv, + unsigned i, int *locking_parms, + struct dmraid45_locking_type **locking_type) +{ + *locking_parms = 0; + *locking_type = &locking_none; + + if (!strnicmp(argv[i], "none", strlen(argv[i]))) + *locking_parms = 1; + else if (!strnicmp(argv[i + 1], "locking", strlen(argv[i + 1]))) { + *locking_type = &locking_none; + *locking_parms = 2; + } else if (!strnicmp(argv[i + 1], "cluster", strlen(argv[i + 1]))) { + *locking_type = &locking_cluster; + /* FIXME: namespace. */ + *locking_parms = 3; + } + + return *locking_parms == 1 ? -EINVAL : 0; +} + +/* Set backing device information properties of RAID set. */ +static void rs_set_bdi(struct raid_set *rs, unsigned stripes, unsigned chunks) +{ + unsigned p, ra_pages; + struct mapped_device *md = dm_table_get_md(rs->ti->table); + struct backing_dev_info *bdi = &dm_disk(md)->queue->backing_dev_info; + + /* Set read-ahead for the RAID set and the component devices. */ + bdi->ra_pages = stripes * stripe_pages(rs, rs->set.io_size); + ra_pages = chunks * chunk_pages(rs->set.io_size); + for (p = rs->set.raid_devs; p--; ) + bdev_get_queue(rs->dev[p].dev->bdev)->backing_dev_info.ra_pages = ra_pages; + + /* Set congested function and data. */ + bdi->congested_fn = raid_set_congested; + bdi->congested_data = rs; + + dm_put(md); +} + +/* Get backing device information properties of RAID set. */ +static void rs_get_ra(struct raid_set *rs, unsigned *stripes, unsigned *chunks) +{ + struct mapped_device *md = dm_table_get_md(rs->ti->table); + + *stripes = dm_disk(md)->queue->backing_dev_info.ra_pages + / stripe_pages(rs, rs->set.io_size); + *chunks = bdev_get_queue(rs->dev->dev->bdev)->backing_dev_info.ra_pages + / chunk_pages(rs->set.io_size); + + dm_put(md); +} + +/* + * Construct a RAID4/5 mapping: + * + * log_type #log_params \ + * raid_type [#parity_dev] #raid_variable_params \ + * [locking "none"/"cluster"] + * #raid_devs #dev_to_initialize [ ]{3,} + * + * log_type = "core"/"disk", + * #log_params = 1-3 (1-2 for core dirty log type, 3 for disk dirty log only) + * log_params = [dirty_log_path] region_size [[no]sync]) + * + * raid_type = "raid4", "raid5_la", "raid5_ra", "raid5_ls", "raid5_rs" + * + * #parity_dev = N if raid_type = "raid4" + * o N = -1: pick default = last device + * o N >= 0 and < #raid_devs: parity device index + * + * #raid_variable_params = 0-5; raid_params (-1 = default): + * [chunk_size [#stripes [io_size [recover_io_size [%recovery_bandwidth]]]]] + * o chunk_size (unit to calculate drive addresses; must be 2^^n, > 8 + * and <= CHUNK_SIZE_MAX) + * o #stripes is number of stripes allocated to stripe cache + * (must be > 1 and < STRIPES_MAX) + * o io_size (io unit size per device in sectors; must be 2^^n and > 8) + * o recover_io_size (io unit size per device for recovery in sectors; + must be 2^^n, > SECTORS_PER_PAGE and <= region_size) + * o %recovery_bandwith is the maximum amount spend for recovery during + * application io (1-100%) + * If raid_variable_params = 0, defaults will be used. + * Any raid_variable_param can be set to -1 to apply a default + * + * #raid_devs = N (N >= 3) + * + * #dev_to_initialize = N + * -1: initialize parity on all devices + * >= 0 and < #raid_devs: initialize raid_path; used to force reconstruction + * of a failed devices content after replacement + * + * = device_path (eg, /dev/sdd1) + * = begin at offset on + * + */ +#define MIN_PARMS 13 +static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv) +{ + int bandwidth = BANDWIDTH, bandwidth_parm = -1, + chunk_size = CHUNK_SIZE, chunk_size_parm = -1, + dev_to_init, dl_parms, locking_parms, parity_parm, pi = -1, + i, io_size = IO_SIZE, io_size_parm = -1, + r, raid_devs, raid_parms, + recover_io_size = RECOVER_IO_SIZE, recover_io_size_parm = -1, + stripes = STRIPES, stripes_parm = -1; + unsigned speed; + sector_t tmp, sectors_per_dev; + struct dmraid45_locking_type *locking; + struct raid_set *rs; + struct raid_type *raid_type; + + /* Ensure minimum number of parameters. */ + if (argc < MIN_PARMS) + TI_ERR("Not enough parameters"); + + /* Fetch # of dirty log parameters. */ + if (sscanf(argv[1], "%d", &dl_parms) != 1 + || !range_ok(dl_parms, 1, 4711)) + TI_ERR("Bad dirty log parameters number"); + + /* Check raid_type. */ + raid_type = get_raid_type(argv[dl_parms + 2]); + if (!raid_type) + TI_ERR("Bad raid type"); + + /* In case of RAID4, parity drive is selectable. */ + parity_parm = !!(raid_type->level == raid4); + + /* Handle variable number of RAID parameters. */ + r = raid_variable_parms(ti, argv, dl_parms + parity_parm + 3, + &raid_parms, + &chunk_size, &chunk_size_parm, + &stripes, &stripes_parm, + &io_size, &io_size_parm, + &recover_io_size, &recover_io_size_parm, + &bandwidth, &bandwidth_parm); + if (r) + return r; + + r = raid_locking_parms(ti, argv, + dl_parms + parity_parm + raid_parms + 4, + &locking_parms, &locking); + if (r) + return r; + + /* # of raid devices. */ + if (sscanf(argv[dl_parms + parity_parm + raid_parms + locking_parms +4], + "%d", &raid_devs) != 1 || raid_devs < raid_type->minimal_devs) + TI_ERR("Invalid number of raid devices"); + + /* In case of RAID4, check parity drive index is in limits. */ + if (raid_type->level == raid4) { + /* Fetch index of parity device. */ + if (sscanf(argv[dl_parms + 3], "%d", &pi) != 1 || + !range_ok(pi, 0, raid_devs - 1)) + TI_ERR("Invalid RAID4 parity device index"); + } + + /* + * Index of device to initialize starts at 0 + * + * o -1 -> don't initialize a particular device, + * o 0..raid_devs-1 -> initialize respective device + * (used for reconstruction of a replaced device) + */ + if (sscanf + (argv[dl_parms + parity_parm + raid_parms + locking_parms + 5], + "%d", &dev_to_init) != 1 + || !range_ok(dev_to_init, -1, raid_devs - 1)) + TI_ERR("Invalid number for raid device to initialize"); + + /* Check # of raid device arguments. */ + if (argc - dl_parms - parity_parm - raid_parms - 6 != + 2 * raid_devs) + TI_ERR("Wrong number of raid device/offset arguments"); + + /* + * Check that the table length is devisable + * w/o rest by (raid_devs - parity_devs) + */ + if (!multiple(ti->len, raid_devs - raid_type->parity_devs, + §ors_per_dev)) + TI_ERR + ("Target length not divisable by number of data devices"); + + /* + * Check that the device size is + * devisable w/o rest by chunk size + */ + if (!multiple(sectors_per_dev, chunk_size, &tmp)) + TI_ERR("Device length not divisable by chunk_size"); + + /**************************************************************** + * Now that we checked the constructor arguments -> + * let's allocate the RAID set + ****************************************************************/ + r = context_alloc(&rs, raid_type, stripes, chunk_size, io_size, + recover_io_size, raid_devs, sectors_per_dev, + ti, dl_parms, argv); + if (r) + return r; + + /* + * Set these here in order to avoid passing + * too many arguments to context_alloc() + */ + rs->set.dev_to_init_parm = dev_to_init; + rs->set.dev_to_init = dev_to_init; + rs->set.pi_parm = pi; + rs->set.pi = (pi == -1) ? rs->set.data_devs : pi; + rs->set.raid_parms = raid_parms; + rs->set.chunk_size_parm = chunk_size_parm; + rs->set.io_size_parm = io_size_parm; + rs->sc.stripes_parm = stripes_parm; + rs->recover.io_size_parm = recover_io_size_parm; + rs->recover.bandwidth_parm = bandwidth_parm; + recover_set_bandwidth(rs, bandwidth); + + /* Use locking type to lock stripe access. */ + rs->locking = locking; + + /* Get the device/offset tupels. */ + argv += dl_parms + 6 + parity_parm + raid_parms; + r = dev_parms(ti, rs, argv, &i); + if (r) + goto err; + + /* Initialize recovery. */ + rs->recover.start_jiffies = jiffies; + rs->recover.end_jiffies = 0; + recovery_region_reset(rs); + SetRSRecover(rs); + + /* Set backing device information (eg. read ahead). */ + rs_set_bdi(rs, chunk_size * 2, io_size * 4); + SetRSCheckOverwrite(rs); /* Allow chunk overwrite checks. */ + + speed = xor_optimize(rs); /* Select best xor algorithm. */ + + /* Initialize work queue to handle this RAID set's io. */ + r = rs_workqueue_init(rs); + if (r) + goto err; + + raid_set_log(rs, speed); /* Log information about RAID set. */ + + /* + * Make sure that dm core only hands maximum io size + * length down and pays attention to io boundaries. + */ + ti->split_io = rs->set.io_size; + ti->private = rs; + return 0; + + err: + context_free(rs, ti, i); + return r; +} + +/* + * Destruct a raid mapping + */ +static void raid_dtr(struct dm_target *ti) +{ + struct raid_set *rs = ti->private; + + /* Indicate recovery end. */ + ClearRSRecover(rs); + wake_do_raid(rs); /* Wake daemon. */ + wait_ios(rs); /* Wait for any io still being processed. */ + destroy_workqueue(rs->io.wq); + context_free(rs, ti, rs->set.raid_devs); +} + +/* Queues ios to RAID sets. */ +static inline void queue_bio(struct raid_set *rs, struct bio *bio) +{ + int wake; + struct bio_list *in = &rs->io.in; + spinlock_t *in_lock = &rs->io.in_lock; + + spin_lock_irq(in_lock); + wake = bio_list_empty(in); + bio_list_add(in, bio); + spin_unlock_irq(in_lock); + + /* Wake daemon if input list was empty. */ + if (wake) + wake_do_raid(rs); +} + +/* Raid mapping function. */ +static int raid_map(struct dm_target *ti, struct bio *bio, + union map_info *map_context) +{ + /* I don't want to waste stripe cache capacity. */ + if (bio_rw(bio) == READA) + return -EIO; + else { + struct raid_set *rs = ti->private; + + /* REMOVEME: statistics. */ + atomic_inc(rs->stats + + (bio_data_dir(bio) == WRITE ? + S_BIOS_WRITE : S_BIOS_READ)); + + /* + * Get io reference to be waiting for to drop + * to zero on device suspension/destruction. + */ + io_get(rs); + bio->bi_sector -= ti->begin; /* Remap sector. */ + queue_bio(rs, bio); /* Queue to the daemon. */ + return DM_MAPIO_SUBMITTED; /* Handle later. */ + } +} + +/* Device suspend. */ +static void raid_postsuspend(struct dm_target *ti) +{ + struct raid_set *rs = ti->private; + struct dm_dirty_log *dl = rs->recover.dl; + + SetRSSuspended(rs); + + if (RSRecover(rs)) + rh_stop_recovery(rs->recover.rh); /* Wakes do_raid(). */ + else + wake_do_raid(rs); + + wait_ios(rs); /* Wait for completion of all ios being processed. */ + if (dl->type->postsuspend && dl->type->postsuspend(dl)) + /* Suspend dirty log. */ + /* FIXME: need better error handling. */ + DMWARN("log suspend failed"); +} + +/* Device resume. */ +static void raid_resume(struct dm_target *ti) +{ + struct raid_set *rs = ti->private; + struct dm_dirty_log *dl = rs->recover.dl; + + if (dl->type->resume && dl->type->resume(dl)) + /* Resume dirty log. */ + /* FIXME: need better error handling. */ + DMWARN("log resume failed"); + + rs->recover.nr_regions_to_recover = + rs->recover.nr_regions - dl->type->get_sync_count(dl); + + ClearRSSuspended(rs); + + /* Reset any unfinished recovery. */ + if (RSRecover(rs)) { + recovery_region_reset(rs); + rh_start_recovery(rs->recover.rh); /* Calls wake_do_raid(). */ + } else + wake_do_raid(rs); +} + +static INLINE unsigned sc_size(struct raid_set *rs) +{ + return to_sector(atomic_read(&rs->sc.stripes) * + (sizeof(struct stripe) + + (sizeof(struct stripe_set) + + (sizeof(struct page_list) + + to_bytes(rs->set.io_size) * + rs->set.raid_devs)) + + (rs->recover. + end_jiffies ? 0 : to_bytes(rs->set.raid_devs * + rs->recover. + io_size)))); +} + +/* REMOVEME: status output for development. */ +static void +raid_devel_stats(struct dm_target *ti, char *result, + unsigned *size, unsigned maxlen) +{ + unsigned chunks, stripes, sz = *size; + unsigned long j; + char buf[BDEVNAME_SIZE], *p; + struct stats_map *sm, *sm_end = ARRAY_END(stats_map); + struct raid_set *rs = ti->private; + struct recover *rec = &rs->recover; + struct timespec ts; + + DMEMIT("%s ", version); + DMEMIT("io_inprocess=%d ", atomic_read(&rs->io.in_process)); + DMEMIT("io_inprocess_max=%d ", atomic_read(&rs->io.in_process_max)); + + for (sm = stats_map; sm < sm_end; sm++) + DMEMIT("%s%d", sm->str, atomic_read(rs->stats + sm->type)); + + DMEMIT(" overwrite=%s ", RSCheckOverwrite(rs) ? "on" : "off"); + DMEMIT("sc=%u/%u/%u/%u/%u ", rs->set.chunk_size, rs->set.io_size, + atomic_read(&rs->sc.stripes), rs->sc.hash.buckets, + sc_size(rs)); + + j = (rec->end_jiffies ? rec->end_jiffies : jiffies) - + rec->start_jiffies; + jiffies_to_timespec(j, &ts); + sprintf(buf, "%ld.%ld", ts.tv_sec, ts.tv_nsec); + p = strchr(buf, '.'); + p[3] = 0; + + DMEMIT("rg=%llu%s/%llu/%llu/%u %s ", + (unsigned long long) rec->nr_regions_recovered, + RSRegionGet(rs) ? "+" : "", + (unsigned long long) rec->nr_regions_to_recover, + (unsigned long long) rec->nr_regions, rec->bandwidth, buf); + + rs_get_ra(rs, &stripes, &chunks); + DMEMIT("ra=%u/%u ", stripes, chunks); + + *size = sz; +} + +static int +raid_status(struct dm_target *ti, status_type_t type, + char *result, unsigned maxlen) +{ + unsigned i, sz = 0; + char buf[BDEVNAME_SIZE]; + struct raid_set *rs = ti->private; + + switch (type) { + case STATUSTYPE_INFO: + /* REMOVEME: statistics. */ + if (RSDevelStats(rs)) + raid_devel_stats(ti, result, &sz, maxlen); + + DMEMIT("%u ", rs->set.raid_devs); + + for (i = 0; i < rs->set.raid_devs; i++) + DMEMIT("%s ", + format_dev_t(buf, rs->dev[i].dev->bdev->bd_dev)); + + DMEMIT("1 "); + for (i = 0; i < rs->set.raid_devs; i++) { + DMEMIT("%c", + dev_operational(rs, i) ? 'A' : 'D'); + + if (rs->set.raid_type->level == raid4 && + i == rs->set.pi) + DMEMIT("p"); + + if (rs->set.dev_to_init == i) + DMEMIT("i"); + } + + break; + + case STATUSTYPE_TABLE: + sz = rs->recover.dl->type->status(rs->recover.dl, type, + result, maxlen); + DMEMIT("%s %u ", rs->set.raid_type->name, + rs->set.raid_parms); + + if (rs->set.raid_type->level == raid4) + DMEMIT("%d ", rs->set.pi_parm); + + if (rs->set.raid_parms) + DMEMIT("%d ", rs->set.chunk_size_parm); + + if (rs->set.raid_parms > 1) + DMEMIT("%d ", rs->sc.stripes_parm); + + if (rs->set.raid_parms > 2) + DMEMIT("%d ", rs->set.io_size_parm); + + if (rs->set.raid_parms > 3) + DMEMIT("%d ", rs->recover.io_size_parm); + + if (rs->set.raid_parms > 4) + DMEMIT("%d ", rs->recover.bandwidth_parm); + + DMEMIT("%u %d ", rs->set.raid_devs, rs->set.dev_to_init); + + for (i = 0; i < rs->set.raid_devs; i++) + DMEMIT("%s %llu ", + format_dev_t(buf, + rs->dev[i].dev->bdev->bd_dev), + (unsigned long long) rs->dev[i].start); + } + + return 0; +} + +/* + * Message interface + */ +enum raid_msg_actions { + act_bw, /* Recovery bandwidth switch. */ + act_dev, /* Device failure switch. */ + act_overwrite, /* Stripe overwrite check. */ + act_read_ahead, /* Set read ahead. */ + act_stats, /* Development statistics switch. */ + act_sc, /* Stripe cache switch. */ + + act_on, /* Set entity on. */ + act_off, /* Set entity off. */ + act_reset, /* Reset entity. */ + + act_set = act_on, /* Set # absolute. */ + act_grow = act_off, /* Grow # by an amount. */ + act_shrink = act_reset, /* Shrink # by an amount. */ +}; + +/* Turn a delta to absolute. */ +static int _absolute(unsigned long action, int act, int r) +{ + /* Make delta absolute. */ + if (test_bit(act_set, &action)); + else if (test_bit(act_grow, &action)) + r += act; + else if (test_bit(act_shrink, &action)) + r = act - r; + else + r = -EINVAL; + + return r; +} + + /* Change recovery io bandwidth. */ +static int bandwidth_change(struct dm_msg *msg, void *context) +{ + struct raid_set *rs = context; + int act = rs->recover.bandwidth; + int bandwidth = DM_MSG_INT_ARG(msg); + + if (range_ok(bandwidth, BANDWIDTH_MIN, BANDWIDTH_MAX)) { + /* Make delta bandwidth absolute. */ + bandwidth = _absolute(msg->action, act, bandwidth); + + /* Check range. */ + if (range_ok(bandwidth, BANDWIDTH_MIN, BANDWIDTH_MAX)) { + recover_set_bandwidth(rs, bandwidth); + return 0; + } + } + + set_bit(dm_msg_ret_arg, &msg->ret); + set_bit(dm_msg_ret_inval, &msg->ret); + return -EINVAL; +} + +/* Change state of a device (running/offline). */ +/* FIXME: this only works while recovering!. */ +static int device_state(struct dm_msg *msg, void *context) +{ + int r; + const char *str = "is already "; + union dev_lookup dl = { .dev_name = DM_MSG_STR_ARG(msg) }; + struct raid_set *rs = context; + + r = raid_dev_lookup(rs, strchr(dl.dev_name, ':') ? + bymajmin : byname, &dl); + if (r == -ENODEV) { + DMERR("device %s is no member of this set", dl.dev_name); + return r; + } + + if (test_bit(act_off, &msg->action)) { + if (dev_operational(rs, r)) + str = ""; + } else if (!dev_operational(rs, r)) + str = ""; + + DMINFO("/dev/%s %s%s", dl.dev_name, str, + test_bit(act_off, &msg->action) ? "offline" : "running"); + + return test_bit(act_off, &msg->action) ? + raid_set_check_and_degrade(rs, NULL, r) : + raid_set_check_and_upgrade(rs, r); +} + +/* Set/reset development feature flags. */ +static int devel_flags(struct dm_msg *msg, void *context) +{ + struct raid_set *rs = context; + + if (test_bit(act_on, &msg->action)) + return test_and_set_bit(msg->spec->parm, + &rs->io.flags) ? -EPERM : 0; + else if (test_bit(act_off, &msg->action)) + return test_and_clear_bit(msg->spec->parm, + &rs->io.flags) ? 0 : -EPERM; + else if (test_bit(act_reset, &msg->action)) { + if (test_bit(act_stats, &msg->action)) { + stats_reset(rs); + goto on; + } else if (test_bit(act_overwrite, &msg->action)) { + on: + set_bit(msg->spec->parm, &rs->io.flags); + return 0; + } + } + + return -EINVAL; +} + + /* Set stripe and chunk read ahead pages. */ +static int read_ahead_set(struct dm_msg *msg, void *context) +{ + int stripes = DM_MSG_INT_ARGS(msg, 0); + int chunks = DM_MSG_INT_ARGS(msg, 1); + + if (range_ok(stripes, 1, 512) && + range_ok(chunks, 1, 512)) { + rs_set_bdi(context, stripes, chunks); + return 0; + } + + set_bit(dm_msg_ret_arg, &msg->ret); + set_bit(dm_msg_ret_inval, &msg->ret); + return -EINVAL; +} + +/* Resize the stripe cache. */ +static int stripecache_resize(struct dm_msg *msg, void *context) +{ + int act, stripes; + struct raid_set *rs = context; + + /* Deny permission in case the daemon is still shrinking!. */ + if (atomic_read(&rs->sc.stripes_to_shrink)) + return -EPERM; + + stripes = DM_MSG_INT_ARG(msg); + if (stripes > 0) { + act = atomic_read(&rs->sc.stripes); + + /* Make delta stripes absolute. */ + stripes = _absolute(msg->action, act, stripes); + + /* + * Check range and that the # of stripes changes. + * We can grow from gere but need to leave any + * shrinking to the worker for synchronization. + */ + if (range_ok(stripes, STRIPES_MIN, STRIPES_MAX)) { + if (stripes > act) + return sc_grow(&rs->sc, stripes - act, grow); + else if (stripes < act) { + atomic_set(&rs->sc.stripes_to_shrink, + act - stripes); + wake_do_raid(rs); + } + + return 0; + } + } + + set_bit(dm_msg_ret_arg, &msg->ret); + set_bit(dm_msg_ret_inval, &msg->ret); + return -EINVAL; +} + +/* Parse the RAID message action. */ +/* + * 'ba[ndwidth] {se[t],g[row],sh[rink]} #' # e.g 'ba se 50' + * 'de{vice] o[ffline]/r[unning] DevName/maj:min' # e.g 'device o /dev/sda' + * "o[verwrite] {on,of[f],r[eset]}' # e.g. 'o of' + * "r[ead_ahead] set #stripes #chunks # e.g. 'r se 3 2' + * 'sta[tistics] {on,of[f],r[eset]}' # e.g. 'stat of' + * 'str[ipecache] {se[t],g[row],sh[rink]} #' # e.g. 'stripe set 1024' + * + */ +static int +raid_message(struct dm_target *ti, unsigned argc, char **argv) +{ + /* Variables to store the parsed parameters im. */ + static int i[2]; + static unsigned long *i_arg[] = { + (unsigned long *) i + 0, + (unsigned long *) i + 1, + }; + static char *p; + static unsigned long *p_arg[] = { (unsigned long *) &p }; + + /* Declare all message option strings. */ + static char *str_sgs[] = { "set", "grow", "shrink" }; + static char *str_dev[] = { "running", "offline" }; + static char *str_oor[] = { "on", "off", "reset" }; + + /* Declare all actions. */ + static unsigned long act_sgs[] = { act_set, act_grow, act_shrink }; + static unsigned long act_oor[] = { act_on, act_off, act_reset }; + + /* Bandwidth option. */ + static struct dm_message_option bw_opt = { 3, str_sgs, act_sgs }; + static struct dm_message_argument bw_args = + { 1, i_arg, { dm_msg_int_t } }; + + /* Device option. */ + static struct dm_message_option dev_opt = { 2, str_dev, act_oor }; + static struct dm_message_argument dev_args = + { 1, p_arg, { dm_msg_base_t } }; + + /* Read ahead option. */ + static struct dm_message_option ra_opt = { 1, str_sgs, act_sgs }; + static struct dm_message_argument ra_args = + { 2, i_arg, { dm_msg_int_t, dm_msg_int_t } }; + + static struct dm_message_argument null_args = + { 0, NULL, { dm_msg_int_t } }; + + /* Overwrite and statistics option. */ + static struct dm_message_option ovr_stats_opt = { 3, str_oor, act_oor }; + + /* Sripecache option. */ + static struct dm_message_option stripe_opt = { 3, str_sgs, act_sgs }; + + /* Declare messages. */ + static struct dm_msg_spec specs[] = { + { "bandwidth", act_bw, &bw_opt, &bw_args, + 0, bandwidth_change }, + { "device", act_dev, &dev_opt, &dev_args, + 0, device_state }, + { "overwrite", act_overwrite, &ovr_stats_opt, &null_args, + RS_CHECK_OVERWRITE, devel_flags }, + { "read_ahead", act_read_ahead, &ra_opt, &ra_args, + 0, read_ahead_set }, + { "statistics", act_stats, &ovr_stats_opt, &null_args, + RS_DEVEL_STATS, devel_flags }, + { "stripecache", act_sc, &stripe_opt, &bw_args, + 0, stripecache_resize }, + }; + + /* The message for the parser. */ + struct dm_msg msg = { + .num_specs = ARRAY_SIZE(specs), + .specs = specs, + }; + + return dm_message_parse(TARGET, &msg, ti->private, argc, argv); +} +/* + * END message interface + */ + +static struct target_type raid_target = { + .name = "raid45", + .version = {1, 0, 0}, + .module = THIS_MODULE, + .ctr = raid_ctr, + .dtr = raid_dtr, + .map = raid_map, + .postsuspend = raid_postsuspend, + .resume = raid_resume, + .status = raid_status, + .message = raid_message, +}; + +static void init_exit(const char *bad_msg, const char *good_msg, int r) +{ + if (r) + DMERR("Failed to %sregister target [%d]", bad_msg, r); + else + DMINFO("%s %s", good_msg, version); +} + +static int __init dm_raid_init(void) +{ + int r; + + r = dm_register_target(&raid_target); + init_exit("", "initialized", r); + return r; +} + +static void __exit dm_raid_exit(void) +{ + int r; + + r = dm_unregister_target(&raid_target); + init_exit("un", "exit", r); +} + +/* Module hooks. */ +module_init(dm_raid_init); +module_exit(dm_raid_exit); + +MODULE_DESCRIPTION(DM_NAME " raid4/5 target"); +MODULE_AUTHOR("Heinz Mauelshagen "); +MODULE_LICENSE("GPL"); --- linux-2.6.27.orig/ubuntu/dm-raid4-5/BOM +++ linux-2.6.27/ubuntu/dm-raid4-5/BOM @@ -0,0 +1,3 @@ +Downloaded from: http://people.redhat.com/~heinzm/sw/dm/dm-raid45/ +Current Version: 20080221 +Comments: All of the patches to dmraid1/dm-log, etc are upstream. --- linux-2.6.27.orig/ubuntu/dm-raid4-5/dm-message.c +++ linux-2.6.27/ubuntu/dm-raid4-5/dm-message.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2007 Red Hat GmbH + * + * Module Author: Heinz Mauelshagen + * + * This file is released under the GPL. + * + * device-mapper message parser. + * + */ + +#include "dm.h" +#include "dm-message.h" +#include + +#define DM_MSG_PREFIX "dm_message" + +/* Basename of a path. */ +static inline char * +basename(char *s) +{ + char *p = strrchr(s, '/'); + + return p ? p + 1 : s; +} + +/* Get an argument depending on type. */ +static void +message_arguments(struct dm_msg *msg, int argc, char **argv) +{ + + if (argc) { + int i; + struct dm_message_argument *args = msg->spec->args; + + for (i = 0; i < args->num_args; i++) { + int r; + unsigned long **ptr = args->ptr; + enum dm_message_argument_type type = args->types[i]; + + switch (type) { + case dm_msg_base_t: + ((char **) ptr)[i] = basename(argv[i]); + break; + + case dm_msg_str_t: + ((char **) ptr)[i] = argv[i]; + break; + + case dm_msg_int_t: + r = sscanf(argv[i], "%d", ((int **) ptr)[i]); + goto check; + + case dm_msg_uint_t: + r = sscanf(argv[i], "%u", + ((unsigned **) ptr)[i]); + goto check; + + case dm_msg_uint64_t: + r = sscanf(argv[i], "%llu", + ((unsigned long long **) ptr)[i]); + + check: + if (r != 1) { + set_bit(dm_msg_ret_undef, &msg->ret); + set_bit(dm_msg_ret_arg, &msg->ret); + } + } + } + } +} + +/* Parse message options. */ +static void +message_options_parse(struct dm_msg *msg, int argc, char **argv) +{ + int hit = 0; + unsigned long *action; + size_t l1 = strlen(*argv), l_hit = 0; + struct dm_message_option *o = msg->spec->options; + char **option, **option_end = o->options + o->num_options; + + for (option = o->options, action = o->actions; + option < option_end; option++, action++) { + size_t l2 = strlen(*option); + + if (!strnicmp(*argv, *option, min(l1, l2))) { + hit++; + l_hit = l2; + set_bit(*action, &msg->action); + } + } + + /* Assume error. */ + msg->ret = 0; + set_bit(dm_msg_ret_option, &msg->ret); + if (!hit || l1 > l_hit) + set_bit(dm_msg_ret_undef, &msg->ret); /* Undefined option. */ + else if (hit > 1) + set_bit(dm_msg_ret_ambiguous, &msg->ret); /* Ambiguous option.*/ + else { + clear_bit(dm_msg_ret_option, &msg->ret); /* Option OK. */ + message_arguments(msg, --argc, ++argv); + } +} + +static inline void +print_ret(const char *caller, unsigned long ret) +{ + struct { + unsigned long err; + const char *err_str; + } static err_msg[] = { + { dm_msg_ret_ambiguous, "message ambiguous" }, + { dm_msg_ret_inval, "message invalid" }, + { dm_msg_ret_undef, "message undefined" }, + { dm_msg_ret_arg, "message argument" }, + { dm_msg_ret_argcount, "message argument count" }, + { dm_msg_ret_option, "option" }, + }, *e = ARRAY_END(err_msg); + + while (e-- > err_msg) { + if (test_bit(e->err, &ret)) + DMERR("%s %s", caller, e->err_str); + } +} + +/* Parse a message action. */ +int +dm_message_parse(const char *caller, struct dm_msg *msg, void *context, + int argc, char **argv) +{ + int hit = 0; + size_t l1 = strlen(*argv), l_hit = 0; + struct dm_msg_spec *s, *s_hit = NULL, + *s_end = msg->specs + msg->num_specs; + + if (argc < 2) + return -EINVAL; + + for (s = msg->specs; s < s_end; s++) { + size_t l2 = strlen(s->cmd); + + if (!strnicmp(*argv, s->cmd, min(l1, l2))) { + hit++; + l_hit = l2; + s_hit = s; + } + } + + msg->ret = 0; + if (!hit || l1 > l_hit) /* No hit or message string too long. */ + set_bit(dm_msg_ret_undef, &msg->ret); + else if (hit > 1) /* Ambiguous message. */ + set_bit(dm_msg_ret_ambiguous, &msg->ret); + else if (argc - 2 != s_hit->args->num_args) { + set_bit(dm_msg_ret_undef, &msg->ret); + set_bit(dm_msg_ret_argcount, &msg->ret); + } + + if (msg->ret) + goto bad; + + msg->action = 0; + msg->spec = s_hit; + set_bit(s_hit->action, &msg->action); + message_options_parse(msg, --argc, ++argv); + + if (!msg->ret) + return msg->spec->f(msg, context); + + bad: + print_ret(caller, msg->ret); + return -EINVAL; +} +EXPORT_SYMBOL(dm_message_parse); + +MODULE_DESCRIPTION(DM_NAME " device-mapper target message parser"); +MODULE_AUTHOR("Heinz Mauelshagen "); +MODULE_LICENSE("GPL"); --- linux-2.6.27.orig/ubuntu/compcache/compcache.txt +++ linux-2.6.27/ubuntu/compcache/compcache.txt @@ -0,0 +1,29 @@ + +compcache: Compressed RAM based swap device +------------------------------------------- + +Project home: http://code.google.com/p/compcache + +* Introduction +This is a RAM based block device which acts as swap disk. +Pages swapped to this device are compressed and stored in +memory itself. + +It uses these components: + - TLSF: memory allocator + - LZO: de/compressor + +* Usage + - modprobe compcache compcache_size_kbytes= + (If no size is specified, default size of 25% of RAM is taken). + - swapon /dev/ramzswap0 + +* Notes + - Allocator and compcache statistics are exported via /proc interface: + (if stats are enabled for corresponding modules) + - /proc/tlsfinfo (from tlsf.ko) + - /proc/compcache (from compcache.ko) + + +Nitin Gupta +(nitingupta910@gmail.com) --- linux-2.6.27.orig/ubuntu/compcache/Kconfig +++ linux-2.6.27/ubuntu/compcache/Kconfig @@ -0,0 +1,61 @@ +menu "Compcache options" + +config BLK_DEV_COMPCACHE + tristate "Compressed RAM based swap device" + default m + select TLSF + select LZO_COMPRESS + select LZO_DECOMPRESS + help + This creates RAM based block device which acts as swap disk. Pages + swapped to this disk are compressed and stored in memory itself. + Project Home: http://code.google.com/p/compcache/ + +config BLK_DEV_COMPCACHE_DEBUG + default n + depends on BLK_DEV_COMPCACHE + bool "Enable debugging" + help + This causes negligible performance loss and size increase. + If unsure, say Y. + +config BLK_DEV_COMPCACHE_STATS + default n + depends on BLK_DEV_COMPCACHE + bool "Enable statistics" + help + Creates /proc/compcache to export various statistics. + This adds about 4K to size with negligible performance loss. + If unsure, say Y. +endmenu + +menu "Two Level Segregate Fit Allocator" + +config TLSF + tristate "TLSF Allocator" + default m + help + Two Level Segregate Fit Allocator. Its fast and gives low + fragmentation. See: + http://rtportal.upv.es/rtmalloc/ + http://code.google.com/p/compcache/wiki/TLSFAllocator + for more information. + +config TLSF_DEBUG + default n + depends on TLSF + bool "Enable TLSF allocator debugging" + help + Enable TLSF debugging. + This causes negligible performance loss and size increase. + If unusure, say Y. + +config TLSF_STATS + default n + depends on TLSF + bool "Collect TLSF statistics" + help + Creates /proc/tlsfinfo to export various tlsf statistics. + This adds about 30K to size with significant performance loss. + If unsure, say N. +endmenu --- linux-2.6.27.orig/ubuntu/compcache/compcache.h +++ linux-2.6.27/ubuntu/compcache/compcache.h @@ -0,0 +1,96 @@ +/* + * Compressed RAM based swap device + * + * (C) 2008 Nitin Gupta + * + * This RAM based block device acts as swap disk. + * Pages swapped to this device are compressed and + * stored in memory. + * + * Released under the terms of the GNU General Public + * License (version 2). See linux/COPYING for more information. + * + * Project home: http://code.google.com/p/compcache + */ + +#ifndef _COMPCACHE_H_ +#define _COMPCACHE_H_ + +#define SECTOR_SHIFT 9 +#define SECTOR_SIZE (1 << SECTOR_SHIFT) +#define SECTORS_PER_PAGE_SHIFT (PAGE_SHIFT - SECTOR_SHIFT) +#define SECTORS_PER_PAGE (1 << SECTORS_PER_PAGE_SHIFT) + +/*-- Configurable parameters */ +/* Default compcache size: 25% of total RAM */ +#define DEFAULT_COMPCACHE_PERCENT 25 +#define INIT_SIZE_BYTES (16 * 1024) +#define GROW_SIZE_BYTES INIT_SIZE_BYTES +/*-- */ + +/* Message prefix */ +#define C "compcache: " + +/* Debugging and Stats */ +#define NOP do { } while(0) + +#if defined(CONFIG_BLK_DEV_COMPCACHE_DEBUG) +#define DEBUG +#endif + +#if defined(CONFIG_BLK_DEV_COMPCACHE_STATS) +#define STATS +#endif + +#if defined(STATS) +#define stat_inc(stat) (stat++) +#define stat_dec(stat) (stat--) +#define stat_set(stat, val) (stat = val) +#define stat_setmax(stat, curr) (stat = (curr) > stat ? (curr) : stat) +#define stat_inc_if_less(stat, val1, val2) \ + (stat += ((val1) < (val2) ? 1 : 0)) +#else /* STATS */ +#define stat_inc(x) NOP +#define stat_dec(x) NOP +#define stat_set(x, v) NOP +#define stat_setmax(x, v) NOP +#define stat_inc_if_less(x, v1, v2) NOP +#endif /* STATS */ + +/*-- Data structures */ +/* Indexed by page no. */ +struct table { + void *addr; + unsigned long len; +}; + +struct compcache { + void *mem_pool; + void *compress_workmem; + void *compress_buffer; + struct table *table; + struct mutex lock; + struct gendisk *disk; + size_t size; /* In sectors */ +}; + +#if defined(STATS) +struct compcache_stats { + u32 num_reads; /* failed + successful */ + u32 num_writes; /* --do-- */ + u32 failed_reads; /* can happen when memory is tooo low */ + u32 failed_writes; /* should NEVER! happen */ + u32 invalid_io; /* non-swap I/O requests */ + u32 good_compress; /* no. of pages with compression + * ratio <= 50%. TODO: export full + * compressed page size histogram */ + u32 pages_expand; /* no. of incompressible pages */ + u32 notify_free; /* count of swap entry free notifications */ + size_t curr_pages; /* current no. of compressed pages */ + size_t curr_mem; /* current total size of compressed pages */ + size_t peak_mem; +}; +#endif +/*-- */ + +#endif --- linux-2.6.27.orig/ubuntu/compcache/Makefile +++ linux-2.6.27/ubuntu/compcache/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_BLK_DEV_COMPCACHE) += compcache.o +obj-$(CONFIG_TLSF) += tlsf.o --- linux-2.6.27.orig/ubuntu/compcache/tlsf.c +++ linux-2.6.27/ubuntu/compcache/tlsf.c @@ -0,0 +1,676 @@ +/* + * Two Levels Segregate Fit memory allocator (TLSF) + * Version 2.3.2 + * + * Written by Miguel Masmano Tello + * + * Thanks to Ismael Ripoll for his suggestions and reviews + * + * Copyright (C) 2007, 2006, 2005, 2004 + * + * This code is released using a dual license strategy: GPL/LGPL + * You can choose the licence that better fits your requirements. + * + * Released under the terms of the GNU General Public License Version 2.0 + * Released under the terms of the GNU Lesser General Public License Version 2.1 + * + * This is kernel port of TLSF allocator. + * Original code can be found at: http://rtportal.upv.es/rtmalloc/ + * - Nitin Gupta (nitingupta910@gmail.com) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "tlsf_int.h" + +static spinlock_t pool_list_lock; +static struct list_head pool_list_head; + +#if defined(CONFIG_TLSF_STATS) +static struct proc_dir_entry *proc; + +/* Print in format similar to /proc/slabinfo -- easy to awk */ +static void print_tlsfinfo_header(struct seq_file *tlsf) +{ + seq_puts(tlsf, "# Size in kB\n"); + seq_puts(tlsf, "# name " + " "); +#if defined(CONFIG_TLSF_STATS) + seq_puts(tlsf, " " + " " + " "); +#endif +#if defined(CONFIG_TLSF_DEBUG) + seq_puts(tlsf, " "); +#endif + + seq_putc(tlsf, '\n'); +} + +/* Get pool no. (*pos) from pool list */ +static void *tlsf_start(struct seq_file *tlsf, loff_t *pos) +{ + struct list_head *lp; + loff_t p = *pos; + + spin_lock(&pool_list_lock); + if (!p) + return SEQ_START_TOKEN; + + list_for_each(lp, &pool_list_head) { + if (!--p) + return lp; + } + + return NULL; +} + +/* Get pool next to the one given by tlsf_start()/previous tlsf_next() */ +static void *tlsf_next(struct seq_file *tlsf, void *v, loff_t *pos) +{ + struct list_head *lp; + + if (v == SEQ_START_TOKEN) + lp = &pool_list_head; + else + lp = v; + + lp = lp->next; + if (lp == &pool_list_head) + return NULL; + + ++*pos; + return lp; +} + +static void tlsf_stop(struct seq_file *tlsf, void *v) +{ + spin_unlock(&pool_list_lock); +} + +/* Display stats for pool given by tlsf_next() */ +static int tlsf_show(struct seq_file *tlsf, void *v) +{ + struct pool *pool; + size_t used, total; + if (v == SEQ_START_TOKEN) { + print_tlsfinfo_header(tlsf); + return 0; + } + + pool = list_entry(v, struct pool, list); + used = tlsf_get_used_size(pool); + total = tlsf_get_total_size(pool); +#define K(x) ((x) >> 10) + seq_printf(tlsf, "%-16s %6zu %6zu %6zu %6zu %6zu %6zu", + pool->name, + K(pool->init_size), + K(pool->max_size), + K(pool->grow_size), + K(used), + K(total), + K(total - used)); + +#if defined(CONFIG_TLSF_STATS) + seq_printf(tlsf, " %6zu %6zu %6zu %6zu %6zu %6zu %6zu %6zu", + K(pool->peak_used), + K(pool->peak_total), + K(pool->peak_extra), + pool->count_alloc, + pool->count_free, + pool->count_region_alloc, + pool->count_region_free, + pool->count_failed_alloc); +#endif + +#if defined(CONFIG_TLSF_DEBUG) + seq_printf(tlsf, " %u", pool->valid); +#endif + + seq_putc(tlsf, '\n'); + return 0; +} + +static struct seq_operations tlsfinfo_op = { + .start = tlsf_start, + .next = tlsf_next, + .stop = tlsf_stop, + .show = tlsf_show, +}; + +static int tlsfinfo_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &tlsfinfo_op); +} + +static const struct file_operations proc_tlsfinfo_operations = { + .open = tlsfinfo_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; +#endif /* CONFIG_TLSF_STATS */ + +/* + * Helping functions + */ + +/** + * Returns indexes (fl, sl) of the list used to serve request of size r + */ +static inline void MAPPING_SEARCH(size_t *r, int *fl, int *sl) +{ + int t; + + if (*r < SMALL_BLOCK) { + *fl = 0; + *sl = *r / (SMALL_BLOCK / MAX_SLI); + } else { + t = (1 << (fls(*r) - 1 - MAX_LOG2_SLI)) - 1; + *r = *r + t; + *fl = fls(*r) - 1; + *sl = (*r >> (*fl - MAX_LOG2_SLI)) - MAX_SLI; + *fl -= FLI_OFFSET; + /*if ((*fl -= FLI_OFFSET) < 0) // FL will be always >0! + *fl = *sl = 0; + */ + *r &= ~t; + } +} + +/** + * Returns indexes (fl, sl) which is used as starting point to search + * for a block of size r. It also rounds up requested size(r) to the + * next list. + */ +static inline void MAPPING_INSERT(size_t r, int *fl, int *sl) +{ + if (r < SMALL_BLOCK) { + *fl = 0; + *sl = r / (SMALL_BLOCK / MAX_SLI); + } else { + *fl = fls(r) - 1; + *sl = (r >> (*fl - MAX_LOG2_SLI)) - MAX_SLI; + *fl -= FLI_OFFSET; + } +} + +/** + * Returns first block from a list that hold blocks larger than or + * equal to the one pointed by the indexes (fl, sl) + */ +static inline struct bhdr *FIND_SUITABLE_BLOCK(struct pool *p, int *fl, + int *sl) +{ + u32 tmp = p->sl_bitmap[*fl] & (~0 << *sl); + struct bhdr *b = NULL; + + if (tmp) { + *sl = ffs(tmp) - 1; + b = p->matrix[*fl][*sl]; + } else { + *fl = ffs(p->fl_bitmap & (~0 << (*fl + 1))) - 1; + if (*fl > 0) { /* likely */ + *sl = ffs(p->sl_bitmap[*fl]) - 1; + b = p->matrix[*fl][*sl]; + } + } + return b; +} + +/** + * Remove first free block(b) from free list with indexes (fl, sl). + */ +static inline void EXTRACT_BLOCK_HDR(struct bhdr *b, struct pool *p, int fl, + int sl) +{ + p->matrix[fl][sl] = b->ptr.free_ptr.next; + if (p->matrix[fl][sl]) + p->matrix[fl][sl]->ptr.free_ptr.prev = NULL; + else { + clear_bit(sl, (void *)&p->sl_bitmap[fl]); + if(!p->sl_bitmap[fl]) + clear_bit (fl, (void *)&p->fl_bitmap); + } + b->ptr.free_ptr = (struct free_ptr) {NULL, NULL}; +} + +/** + * Removes block(b) from free list with indexes (fl, sl) + */ +static inline void EXTRACT_BLOCK(struct bhdr *b, struct pool *p, int fl, + int sl) +{ + if (b->ptr.free_ptr.next) + b->ptr.free_ptr.next->ptr.free_ptr.prev = + b->ptr.free_ptr.prev; + if (b->ptr.free_ptr.prev) + b->ptr.free_ptr.prev->ptr.free_ptr.next = + b->ptr.free_ptr.next; + if (p->matrix[fl][sl] == b) { + p->matrix[fl][sl] = b->ptr.free_ptr.next; + if (!p->matrix[fl][sl]) { + clear_bit(sl, (void *)&p->sl_bitmap[fl]); + if (!p->sl_bitmap[fl]) + clear_bit (fl, (void *)&p->fl_bitmap); + } + } + b->ptr.free_ptr = (struct free_ptr) {NULL, NULL}; +} + +/** + * Insert block(b) in free list with indexes (fl, sl) + */ +static inline void INSERT_BLOCK(struct bhdr *b, struct pool *p, int fl, int sl) +{ + b->ptr.free_ptr = (struct free_ptr) {NULL, p->matrix[fl][sl]}; + if (p->matrix[fl][sl]) + p->matrix[fl][sl]->ptr.free_ptr.prev = b; + p->matrix[fl][sl] = b; + set_bit(sl, (void *)&p->sl_bitmap[fl]); + set_bit(fl, (void *)&p->fl_bitmap); +} + +/** + * Region is a virtually contiguous memory region and Pool is + * collection of such regions + */ +static inline void ADD_REGION(void *region, size_t region_size, + struct pool *pool) +{ + int fl, sl; + struct bhdr *b, *lb; + + b = (struct bhdr *)(region); + b->prev_hdr = NULL; + b->size = ROUNDDOWN_SIZE(region_size - 2 * BHDR_OVERHEAD) + | FREE_BLOCK | PREV_USED; + MAPPING_INSERT(b->size & BLOCK_SIZE_MASK, &fl, &sl); + INSERT_BLOCK(b, pool, fl, sl); + /* The sentinel block: allows us to know when we're in the last block */ + lb = GET_NEXT_BLOCK(b->ptr.buffer, b->size & BLOCK_SIZE_MASK); + lb->prev_hdr = b; + lb->size = 0 | USED_BLOCK | PREV_FREE; + pool->used_size += BHDR_OVERHEAD; /* only sentinel block is "used" */ + pool->num_regions++; + stat_inc(pool->count_region_alloc); +} + +/* + * Allocator code start + */ + +/** + * tlsf_create_memory_pool - create dynamic memory pool + * @name: name of the pool + * @get_mem: callback function used to expand pool + * @put_mem: callback function used to shrink pool + * @init_size: inital pool size (in bytes) + * @max_size: maximum pool size (in bytes) - set this as 0 for no limit + * @grow_size: amount of memory (in bytes) added to pool whenever required + * + * All size values are rounded up to next page boundary. + */ +void *tlsf_create_memory_pool(const char *name, + get_memory get_mem, + put_memory put_mem, + size_t init_size, + size_t max_size, + size_t grow_size) +{ + struct pool *pool; + void *region; +#if defined(CONFIG_TLSF_STATS) + size_t used, total; +#endif + + if (max_size) + BUG_ON(max_size < init_size); + + pool = get_mem(ROUNDUP_SIZE(sizeof(*pool))); + if (pool == NULL) + goto out; + memset(pool, 0, ROUNDUP_SIZE(sizeof(*pool))); + + /* Round to next page boundary */ + init_size = ROUNDUP_PAGE(init_size); + max_size = ROUNDUP_PAGE(max_size); + grow_size = ROUNDUP_PAGE(grow_size); + pr_info(T "pool: %p, init_size=%zu, max_size=%zu, grow_size=%zu\n", + pool, init_size, max_size, grow_size); + + /* pool global overhead not included in used size */ + pool->used_size = 0; + + pool->init_size = init_size; + pool->max_size = max_size; + pool->grow_size = grow_size; + pool->get_mem = get_mem; + pool->put_mem = put_mem; + strncpy(pool->name, name, MAX_POOL_NAME_LEN); + pool->name[MAX_POOL_NAME_LEN - 1] = '\0'; +#if defined(CONFIG_TLSF_DEBUG) + pool->valid = 1; +#endif + region = get_mem(init_size); + if (region == NULL) + goto out_region; + ADD_REGION(region, init_size, pool); + pool->init_region = region; + + spin_lock_init(&pool->lock); + + spin_lock(&pool_list_lock); + list_add_tail(&pool->list, &pool_list_head); + spin_unlock(&pool_list_lock); + + /* Pool created: update stats */ + stat_set(used, tlsf_get_used_size(pool)); + stat_set(total, tlsf_get_total_size(pool)); + stat_inc(pool->count_alloc); + stat_setmax(pool->peak_extra, total - used); + stat_setmax(pool->peak_used, used); + stat_setmax(pool->peak_total, total); + + return pool; + +out_region: + put_mem(pool); + +out: + return NULL; +} +EXPORT_SYMBOL_GPL(tlsf_create_memory_pool); + +/** + * tlsf_get_used_size - get memory currently used by given pool + * + * Used memory includes stored data + metadata + internal fragmentation + */ +size_t tlsf_get_used_size(void *mem_pool) +{ + struct pool *pool = (struct pool *)mem_pool; + return pool->used_size; +} +EXPORT_SYMBOL_GPL(tlsf_get_used_size); + +/** + * tlsf_get_total_size - get total memory currently allocated for given pool + * + * This is the total memory currently allocated for this pool which includes + * used size + free size. + * + * (Total - Used) is good indicator of memory efficiency of allocator. + */ +size_t tlsf_get_total_size(void *mem_pool) +{ + size_t total; + struct pool *pool = (struct pool *)mem_pool; + total = ROUNDUP_SIZE(sizeof(*pool)) + + pool->init_size + + (pool->num_regions - 1) * pool->grow_size; + return total; +} +EXPORT_SYMBOL_GPL(tlsf_get_total_size); + +/** + * tlsf_destory_memory_pool - cleanup given pool + * @mem_pool: Pool to be destroyed + * + * Data structures associated with pool are freed. + * All memory allocated from pool must be freed before + * destorying it. + */ +void tlsf_destroy_memory_pool(void *mem_pool) +{ + struct pool *pool; + + if (mem_pool == NULL) + return; + + pool = (struct pool *)mem_pool; + + /* User is destorying without ever allocating from this pool */ + if (tlsf_get_used_size(pool) == BHDR_OVERHEAD) { + pool->put_mem(pool->init_region); + pool->used_size -= BHDR_OVERHEAD; + stat_inc(pool->count_region_free); + } + + /* Check for memory leaks in this pool */ + if (tlsf_get_used_size(pool)) { + pr_warning(T "memory leak in pool: %s (%p). " + "%zu bytes still in use.\n", + pool->name, pool, tlsf_get_used_size(pool)); + +#if defined(CONFIG_TLSF_DEBUG) + pool->valid = 0; + /* Invalid pools stay in list for debugging purpose */ + return; +#endif + } + spin_lock(&pool_list_lock); + list_del_init(&pool->list); + spin_unlock(&pool_list_lock); + pool->put_mem(pool); +} +EXPORT_SYMBOL_GPL(tlsf_destroy_memory_pool); + +/** + * tlsf_malloc - allocate memory from given pool + * @size: no. of bytes + * @mem_pool: pool to allocate from + */ +void *tlsf_malloc(size_t size, void *mem_pool) +{ + struct pool *pool = (struct pool *)mem_pool; + struct bhdr *b, *b2, *next_b, *region; + int fl, sl; + size_t tmp_size; +#if defined(CONFIG_TLSF_STATS) + size_t used, total; +#endif + +#if defined(CONFIG_TLSF_DEBUG) + unsigned int retries = 0; +#endif + + size = (size < MIN_BLOCK_SIZE) ? MIN_BLOCK_SIZE : ROUNDUP_SIZE(size); + /* Rounding up the requested size and calculating fl and sl */ + + spin_lock(&pool->lock); +retry_find: + MAPPING_SEARCH(&size, &fl, &sl); + + /* Searching a free block */ + if (!(b = FIND_SUITABLE_BLOCK(pool, &fl, &sl))) { +#if defined(CONFIG_TLSF_DEBUG) + /* + * This can happen if there are too many users + * allocating from this pool simultaneously. + */ + if (unlikely(retries == MAX_RETRY_EXPAND)) + goto out_locked; + retries++; +#endif + /* Not found */ + if (size > (pool->grow_size - 2 * BHDR_OVERHEAD)) + goto out_locked; + if (pool->max_size && (pool->init_size + + pool->num_regions * pool->grow_size + > pool->max_size)) + goto out_locked; + spin_unlock(&pool->lock); + if ((region = pool->get_mem(pool->grow_size)) == NULL) + goto out; + spin_lock(&pool->lock); + ADD_REGION(region, pool->grow_size, pool); + goto retry_find; + } + EXTRACT_BLOCK_HDR(b, pool, fl, sl); + + /*-- found: */ + next_b = GET_NEXT_BLOCK(b->ptr.buffer, b->size & BLOCK_SIZE_MASK); + /* Should the block be split? */ + tmp_size = (b->size & BLOCK_SIZE_MASK) - size; + if (tmp_size >= sizeof(struct bhdr) ) { + tmp_size -= BHDR_OVERHEAD; + b2 = GET_NEXT_BLOCK(b->ptr.buffer, size); + + b2->size = tmp_size | FREE_BLOCK | PREV_USED; + b2->prev_hdr = b; + + next_b->prev_hdr = b2; + + MAPPING_INSERT(tmp_size, &fl, &sl); + INSERT_BLOCK(b2, pool, fl, sl); + + b->size = size | (b->size & PREV_STATE); + } else { + next_b->size &= (~PREV_FREE); + b->size &= (~FREE_BLOCK); /* Now it's used */ + } + + pool->used_size += (b->size & BLOCK_SIZE_MASK) + BHDR_OVERHEAD; + + /* Successful alloc: update stats. */ + stat_set(used, tlsf_get_used_size(pool)); + stat_set(total, tlsf_get_total_size(pool)); + stat_inc(pool->count_alloc); + stat_setmax(pool->peak_extra, total - used); + stat_setmax(pool->peak_used, used); + stat_setmax(pool->peak_total, total); + + spin_unlock(&pool->lock); + return (void *)b->ptr.buffer; + + /* Failed alloc */ +out_locked: + spin_unlock(&pool->lock); + +out: + stat_inc(pool->count_failed_alloc); + return NULL; +} +EXPORT_SYMBOL_GPL(tlsf_malloc); + +/** + * tlsf_free - free memory from given pool + * @ptr: address of memory to be freed + * @mem_pool: pool to free from + */ +void tlsf_free(void *ptr, void *mem_pool) +{ + struct pool *pool = (struct pool *)mem_pool; + struct bhdr *b, *tmp_b; + int fl = 0, sl = 0; +#if defined(CONFIG_TLSF_STATS) + size_t used, total; +#endif + if (unlikely(ptr == NULL)) + return; + + b = (struct bhdr *) ((char *) ptr - BHDR_OVERHEAD); + + spin_lock(&pool->lock); + b->size |= FREE_BLOCK; + pool->used_size -= (b->size & BLOCK_SIZE_MASK) + BHDR_OVERHEAD; + b->ptr.free_ptr = (struct free_ptr) { NULL, NULL}; + tmp_b = GET_NEXT_BLOCK(b->ptr.buffer, b->size & BLOCK_SIZE_MASK); + if (tmp_b->size & FREE_BLOCK) { + MAPPING_INSERT(tmp_b->size & BLOCK_SIZE_MASK, &fl, &sl); + EXTRACT_BLOCK(tmp_b, pool, fl, sl); + b->size += (tmp_b->size & BLOCK_SIZE_MASK) + BHDR_OVERHEAD; + } + if (b->size & PREV_FREE) { + tmp_b = b->prev_hdr; + MAPPING_INSERT(tmp_b->size & BLOCK_SIZE_MASK, &fl, &sl); + EXTRACT_BLOCK(tmp_b, pool, fl, sl); + tmp_b->size += (b->size & BLOCK_SIZE_MASK) + BHDR_OVERHEAD; + b = tmp_b; + } + tmp_b = GET_NEXT_BLOCK(b->ptr.buffer, b->size & BLOCK_SIZE_MASK); + tmp_b->prev_hdr = b; + + MAPPING_INSERT(b->size & BLOCK_SIZE_MASK, &fl, &sl); + + if ((b->prev_hdr == NULL) && ((tmp_b->size & BLOCK_SIZE_MASK) == 0)) { + pool->put_mem(b); + pool->num_regions--; + pool->used_size -= BHDR_OVERHEAD; /* sentinel block header */ + stat_inc(pool->count_region_free); + goto out; + } + + INSERT_BLOCK(b, pool, fl, sl); + + tmp_b->size |= PREV_FREE; + tmp_b->prev_hdr = b; +out: + /* Update stats */ + stat_set(used, tlsf_get_used_size(pool)); + stat_set(total, tlsf_get_total_size(pool)); + stat_inc(pool->count_free); + stat_setmax(pool->peak_extra, total - used); + stat_setmax(pool->peak_used, used); + stat_setmax(pool->peak_total, total); + + spin_unlock(&pool->lock); +} +EXPORT_SYMBOL_GPL(tlsf_free); + +/** + * tlsf_calloc - allocate and zero-out memory from given pool + * @size: no. of bytes + * @mem_pool: pool to allocate from + */ +void *tlsf_calloc(size_t nelem, size_t elem_size, void *mem_pool) +{ + void *ptr; + + if (nelem == 0 || elem_size == 0) + return NULL; + + if ((ptr = tlsf_malloc(nelem * elem_size, mem_pool)) == NULL) + return NULL; + memset(ptr, 0, nelem * elem_size); + + return ptr; +} +EXPORT_SYMBOL_GPL(tlsf_calloc); + +static int __init tlsf_init(void) +{ + INIT_LIST_HEAD(&pool_list_head); + spin_lock_init(&pool_list_lock); +#if defined(CONFIG_TLSF_STATS) + proc = create_proc_entry("tlsfinfo", S_IRUGO, NULL); + if (proc) + proc->proc_fops = &proc_tlsfinfo_operations; + else + pr_warning(T "error creating proc entry\n"); +#endif + return 0; +} + +static void __exit tlsf_exit(void) +{ +#if defined(CONFIG_TLSF_STATS) + if (proc) + remove_proc_entry("tlsfinfo", proc->parent); +#endif + return; +} + +module_init(tlsf_init); +module_exit(tlsf_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nitin Gupta "); +MODULE_DESCRIPTION("TLSF Memory Allocator"); --- linux-2.6.27.orig/ubuntu/compcache/compcache.c +++ linux-2.6.27/ubuntu/compcache/compcache.c @@ -0,0 +1,480 @@ +/* + * Compressed RAM based swap device + * + * (C) 2008 Nitin Gupta + * + * This RAM based block device acts as swap disk. + * Pages swapped to this device are compressed and + * stored in memory. + * + * Released under the terms of the GNU General Public + * License (version 2). See linux/COPYING for more information. + * + * Project home: http://code.google.com/p/compcache + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "compcache.h" + +static struct block_device_operations compcache_devops = { + .owner = THIS_MODULE, +}; + +static unsigned int init_done; +static struct compcache compcache; +static unsigned long compcache_size_kbytes; +#if defined(STATS) +static struct compcache_stats stats; +#endif + +#if defined(STATS) +static struct proc_dir_entry *proc; + +static int proc_compcache_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; +#if defined(STATS) + size_t succ_writes; + unsigned int good_compress_perc = 0, no_compress_perc = 0; +#endif + + if (off > 0) { + *eof = 1; + return 0; + } + + len = sprintf(page, + "DiskSize: %8zu kB\n", + compcache.size >> (10 - SECTOR_SHIFT)); +#if defined(STATS) + succ_writes = stats.num_writes - stats.failed_writes; + if (succ_writes) { + good_compress_perc = stats.good_compress * 100 / succ_writes; + no_compress_perc = stats.pages_expand * 100 / succ_writes; + } + +#define K(x) ((x) >> 10) + len += sprintf(page + len, + "NumReads: %8u\n" + "NumWrites: %8u\n" + "FailedReads: %8u\n" + "FailedWrites: %8u\n" + "InvalidIO: %8u\n" + "GoodCompress: %8u %%\n" + "NoCompress: %8u %%\n" + "NotifyFree: %8u\n" + "CurrentPages: %8zu\n" + "CurrentMem: %8zu kB\n" + "PeakMem: %8zu kB\n", + stats.num_reads, + stats.num_writes, + stats.failed_reads, + stats.failed_writes, + stats.invalid_io, + good_compress_perc, + no_compress_perc, + stats.notify_free, + stats.curr_pages, + K(stats.curr_mem), + K(stats.peak_mem)); +#endif + return len; +} +#endif /* STATS */ + +/* + * callback function called when swap_map[offset] == 0 + * i.e page at this swap offset is no longer used + */ +static void notify_swap_entry_free(unsigned long offset) +{ + stat_inc(stats.notify_free); + + /* + * + * This callback happened due to some page being + * freed from swap-cache. This page was not written + * to swap disk. + */ + if (compcache.table[offset].addr == NULL) + return; + + tlsf_free(compcache.table[offset].addr, compcache.mem_pool); + stat_dec(stats.curr_pages); + stat_set(stats.curr_mem, stats.curr_mem - + compcache.table[offset].len); + compcache.table[offset].addr = NULL; + compcache.table[offset].len = 0; +} + +/* Check if request is within bounds and page aligned */ +static inline int valid_swap_request(struct bio *bio) +{ + if (unlikely((bio->bi_sector >= compcache.size) || + (bio->bi_sector & (SECTORS_PER_PAGE - 1)) || + (bio->bi_vcnt != 1) || + (bio->bi_size != PAGE_SIZE) || + (bio->bi_io_vec[0].bv_offset != 0))) + return 0; + return 1; +} + +static int compcache_make_request(struct request_queue *queue, struct bio *bio) +{ + int ret; + size_t clen, page_no; + void *user_mem; + struct page *page; + + if (!valid_swap_request(bio)) { + stat_inc(stats.invalid_io); + goto out_nomap; + } + + page = bio->bi_io_vec[0].bv_page; + page_no = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT; + + if (unlikely(!init_done) && PageSwapCache(page)) { + swp_entry_t entry = { .val = page_private(page) }; + set_notify_swap_entry_free(swp_type(entry), + notify_swap_entry_free); + init_done = 1; + } + + user_mem = kmap(page); + + if (bio_data_dir(bio) == READ) { + stat_inc(stats.num_reads); + /* + * This is attempt to read before any previous write + * to this location. This happens due to readahead when + * swap device is read from user-space (e.g. during swapon) + */ + if (unlikely(compcache.table[page_no].addr == NULL)) { + pr_debug("Read before write on swap device: " + "sector=%lu, size=%u, offset=%u\n", + (ulong)(bio->bi_sector), + bio->bi_size, + bio->bi_io_vec[0].bv_offset); + memset(user_mem, 0, PAGE_SIZE); + kunmap(page); + set_bit(BIO_UPTODATE, &bio->bi_flags); + bio_endio(bio, 0); + return 0; + } + + /* Page is stored uncompressed since its incompressible */ + if (unlikely(compcache.table[page_no].len == PAGE_SIZE)) { + memcpy(user_mem, compcache.table[page_no].addr, + PAGE_SIZE); + kunmap(page); + set_bit(BIO_UPTODATE, &bio->bi_flags); + bio_endio(bio, 0); + return 0; + } + + clen = PAGE_SIZE; + ret = lzo1x_decompress_safe( + compcache.table[page_no].addr, + compcache.table[page_no].len, + user_mem, + &clen); + + /* should NEVER happen */ + if (unlikely(ret != LZO_E_OK)) { + pr_err(C "Decompression failed! " + "err=%d, page=%zu, len=%lu\n", ret, page_no, + compcache.table[page_no].len); + stat_inc(stats.failed_reads); + goto out; + } + + kunmap(page); + set_bit(BIO_UPTODATE, &bio->bi_flags); + bio_endio(bio, 0); + return 0; + } else { /* Write */ + unsigned char *src = compcache.compress_buffer; + stat_inc(stats.num_writes); + /* + * System swaps to same sector again when the stored page + * is no longer referenced by any process. So, its now safe + * to free the memory that was allocated for this page. + */ + if (compcache.table[page_no].addr) { + tlsf_free(compcache.table[page_no].addr, + compcache.mem_pool); + stat_dec(stats.curr_pages); + stat_set(stats.curr_mem, stats.curr_mem - + compcache.table[page_no].len); + compcache.table[page_no].addr = NULL; + compcache.table[page_no].len = 0; + } + + mutex_lock(&compcache.lock); + ret = lzo1x_1_compress(user_mem, PAGE_SIZE, + src, &clen, compcache.compress_workmem); + if (unlikely(ret != LZO_E_OK)) { + mutex_unlock(&compcache.lock); + pr_err(C "Compression failed! err=%d\n", ret); + compcache.table[page_no].addr = NULL; + compcache.table[page_no].len = 0; + stat_inc(stats.failed_writes); + goto out; + } + + /* Page is incompressible - store it as is */ + if (clen >= PAGE_SIZE) { + pr_debug("Page expand on compression: " + "page=%zu, size=%zu\n", page_no, clen); + clen = PAGE_SIZE; + src = user_mem; + } + + if ((compcache.table[page_no].addr = tlsf_malloc(clen, + compcache.mem_pool)) == NULL) { + mutex_unlock(&compcache.lock); + pr_err(C "Error allocating memory for compressed " + "page: %zu, size=%zu \n", page_no, clen); + compcache.table[page_no].len = 0; + stat_inc(stats.failed_writes); + goto out; + } + + memcpy(compcache.table[page_no].addr, src, clen); + + /* Update stats */ + stat_inc(stats.curr_pages); + stat_set(stats.curr_mem, stats.curr_mem + clen); + stat_setmax(stats.peak_mem, stats.curr_mem); + stat_inc_if_less(stats.pages_expand, PAGE_SIZE - 1, clen); + stat_inc_if_less(stats.good_compress, clen, + PAGE_SIZE / 2 + 1); + mutex_unlock(&compcache.lock); + + compcache.table[page_no].len = clen; + + kunmap(page); + set_bit(BIO_UPTODATE, &bio->bi_flags); + bio_endio(bio, 0); + return 0; + } +out: + kunmap(page); +out_nomap: + bio_io_error(bio); + return 0; +} + +static void setup_swap_header(union swap_header *s) +{ + s->info.version = 1; + s->info.last_page = compcache.size >> SECTORS_PER_PAGE_SHIFT; + s->info.nr_badpages = 0; + memcpy(s->magic.magic, "SWAPSPACE2", 10); +} + +static void *get_mem(size_t size) +{ + return __vmalloc(size, GFP_NOIO, PAGE_KERNEL); +} + +static void put_mem(void *ptr) +{ + vfree(ptr); +} + +static int __init compcache_init(void) +{ + int ret; + size_t num_pages; + struct sysinfo i; + + mutex_init(&compcache.lock); + + if (compcache_size_kbytes == 0) { + pr_info(C "compcache size not provided." + " Using default: (%u%% of Total RAM).\n" + "Use compcache_size_kbytes module param to specify" + " custom size\n", DEFAULT_COMPCACHE_PERCENT); + si_meminfo(&i); + compcache_size_kbytes = ((DEFAULT_COMPCACHE_PERCENT * + i.totalram) / 100) << (PAGE_SHIFT - 10); + } + + compcache.size = compcache_size_kbytes << 10; + compcache.size = (compcache.size + PAGE_SIZE - 1) & PAGE_MASK; + pr_info(C "Compressed swap size set to: %zu KB\n", compcache.size >> 10); + compcache.size >>= SECTOR_SHIFT; + + compcache.compress_workmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL); + if (compcache.compress_workmem == NULL) { + pr_err(C "Error allocating compressor working memory\n"); + ret = -ENOMEM; + goto fail; + } + + compcache.compress_buffer = kmalloc(2 * PAGE_SIZE, GFP_KERNEL); + if (compcache.compress_buffer == NULL) { + pr_err(C "Error allocating compressor buffer space\n"); + ret = -ENOMEM; + goto fail; + } + + num_pages = compcache.size >> SECTORS_PER_PAGE_SHIFT; + compcache.table = vmalloc(num_pages * sizeof(*compcache.table)); + if (compcache.table == NULL) { + pr_err(C "Error allocating compcache address table\n"); + ret = -ENOMEM; + goto fail; + } + memset(compcache.table, 0, num_pages * sizeof(*compcache.table)); + + compcache.table[0].addr = (void *)get_zeroed_page(GFP_KERNEL); + if (compcache.table[0].addr == NULL) { + pr_err(C "Error allocating swap header page\n"); + ret = -ENOMEM; + goto fail; + } + compcache.table[0].len = PAGE_SIZE; + setup_swap_header((union swap_header *)(compcache.table[0].addr)); + + compcache.disk = alloc_disk(1); + if (compcache.disk == NULL) { + pr_err(C "Error allocating disk structure\n"); + ret = -ENOMEM; + goto fail; + } + + compcache.disk->first_minor = 0; + compcache.disk->fops = &compcache_devops; + /* + * It is named like this to prevent distro installers + * from offering compcache as installation target. They + * seem to ignore all devices beginning with 'ram' + */ + strcpy(compcache.disk->disk_name, "ramzswap0"); + + compcache.disk->major = register_blkdev(0, compcache.disk->disk_name); + if (compcache.disk->major < 0) { + pr_err(C "Cannot register block device\n"); + ret = -EFAULT; + goto fail; + } + + compcache.disk->queue = blk_alloc_queue(GFP_KERNEL); + if (compcache.disk->queue == NULL) { + pr_err(C "Cannot register disk queue\n"); + ret = -EFAULT; + goto fail; + } + + set_capacity(compcache.disk, compcache.size); + blk_queue_make_request(compcache.disk->queue, compcache_make_request); + blk_queue_hardsect_size(compcache.disk->queue, PAGE_SIZE); + add_disk(compcache.disk); + + compcache.mem_pool = tlsf_create_memory_pool("compcache", + get_mem, put_mem, + INIT_SIZE_BYTES, 0, GROW_SIZE_BYTES); + if (compcache.mem_pool == NULL) { + pr_err(C "Error creating memory pool\n"); + ret = -ENOMEM; + goto fail; + } + +#if defined(STATS) + proc = create_proc_entry("compcache", S_IRUGO, NULL); + if (proc) + proc->read_proc = &proc_compcache_read; + else { + ret = -ENOMEM; + pr_warning(C "Error creating proc entry\n"); + goto fail; + } +#endif + + pr_debug(C "Initialization done!\n"); + return 0; + +fail: + if (compcache.disk != NULL) { + if (compcache.disk->major > 0) + unregister_blkdev(compcache.disk->major, + compcache.disk->disk_name); + del_gendisk(compcache.disk); + } + + free_page((unsigned long)compcache.table[0].addr); + kfree(compcache.compress_workmem); + kfree(compcache.compress_buffer); + vfree(compcache.table); + tlsf_destroy_memory_pool(compcache.mem_pool); +#if defined(STATS) + if (proc) + remove_proc_entry("compcache", proc->parent); +#endif + pr_err(C "Initialization failed: err=%d\n", ret); + return ret; +} + +static void __exit compcache_exit(void) +{ + size_t i, num_pages; + num_pages = compcache.size >> SECTORS_PER_PAGE_SHIFT; + + unregister_blkdev(compcache.disk->major, compcache.disk->disk_name); + del_gendisk(compcache.disk); + free_page((unsigned long)compcache.table[0].addr); + kfree(compcache.compress_workmem); + kfree(compcache.compress_buffer); + + /* Free all pages that are still in compcache */ + for (i = 1; i < num_pages; i++) + if (compcache.table[i].addr) + tlsf_free(compcache.table[i].addr, compcache.mem_pool); + vfree(compcache.table); + tlsf_destroy_memory_pool(compcache.mem_pool); + +#if defined(STATS) + remove_proc_entry("compcache", proc->parent); +#endif + pr_debug("cleanup done!\n"); +} + +#ifndef MODULE +static int __init compcache_size_setup(char *str) +{ + if (str) + compcache_size_kbytes = strtoul(str, NULL, 10); + return 1; +} + +__setup("compcache_size_kbytes=", compcache_size_setup); +#endif + +module_param(compcache_size_kbytes, ulong, 0); +MODULE_PARM_DESC(compcache_size_kbytes, "compcache device size (in KB)"); + +module_init(compcache_init); +module_exit(compcache_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nitin Gupta "); +MODULE_DESCRIPTION("Compressed RAM Based Swap Device"); --- linux-2.6.27.orig/ubuntu/compcache/tlsf_int.h +++ linux-2.6.27/ubuntu/compcache/tlsf_int.h @@ -0,0 +1,145 @@ +/* + * To be used internally by TLSF allocator. + */ + +#ifndef _TLSF_INT_H_ +#define _TLSF_INT_H_ + +#include +#include + +/* Debugging and Stats */ +#define NOP do { } while(0) + +#if defined(CONFIG_TLSF_STATS) +#define stat_inc(stat) (stat++) +#define stat_set(stat, val) (stat = val) +#define stat_setmax(stat, curr) (stat = (curr) > stat ? (curr) : stat) + +#else /* STATS */ +#define stat_inc(x) NOP +#define stat_dec(x) NOP +#define stat_set(x, v) NOP +#define stat_setmax(x, v) NOP +#endif /* STATS */ + +/* Messsage prefix */ +#define T "TLSF: " + +#define MAX_POOL_NAME_LEN 16 + +/*-- TLSF structures */ + +/* Some IMPORTANT TLSF parameters */ +#define MEM_ALIGN (sizeof(void *) * 2) +#define MEM_ALIGN_MASK (~(MEM_ALIGN - 1)) + +#define MAX_FLI (30) +#define MAX_LOG2_SLI (5) +#define MAX_SLI (1 << MAX_LOG2_SLI) + +#define FLI_OFFSET (6) +/* tlsf structure just will manage blocks bigger than 128 bytes */ +#define SMALL_BLOCK (128) +#define REAL_FLI (MAX_FLI - FLI_OFFSET) +#define MIN_BLOCK_SIZE (sizeof(struct free_ptr)) +#define BHDR_OVERHEAD (sizeof(struct bhdr) - MIN_BLOCK_SIZE) + +#define PTR_MASK (sizeof(void *) - 1) +#define BLOCK_SIZE_MASK (0xFFFFFFFF - PTR_MASK) + +#define GET_NEXT_BLOCK(addr, r) ((struct bhdr *) \ + ((char *)(addr) + (r))) +#define ROUNDUP_SIZE(r) (((r) + MEM_ALIGN - 1) & MEM_ALIGN_MASK) +#define ROUNDDOWN_SIZE(r) ((r) & MEM_ALIGN_MASK) +#define ROUNDUP_PAGE(r) (((r) + PAGE_SIZE - 1) & PAGE_MASK) + +#define BLOCK_STATE (0x1) +#define PREV_STATE (0x2) + +/* bit 0 of the block size */ +#define FREE_BLOCK (0x1) +#define USED_BLOCK (0x0) + +/* bit 1 of the block size */ +#define PREV_FREE (0x2) +#define PREV_USED (0x0) + +#if defined(CONFIG_TLSF_DEBUG) +#define MAX_RETRY_EXPAND 10 +#endif + +struct free_ptr { + struct bhdr *prev; + struct bhdr *next; +}; + +struct bhdr { + /* All blocks in a region are linked in order of physical address */ + struct bhdr *prev_hdr; + /* + * The size is stored in bytes + * bit 0: block is free, if set + * bit 1: previous block is free, if set + */ + u32 size; + /* Free blocks in individual freelists are linked */ + union { + struct free_ptr free_ptr; + u8 buffer[sizeof(struct free_ptr)]; + } ptr; +}; + +struct pool { + /* First level bitmap (REAL_FLI bits) */ + u32 fl_bitmap; + + /* Second level bitmap */ + u32 sl_bitmap[REAL_FLI]; + + /* Free lists */ + struct bhdr *matrix[REAL_FLI][MAX_SLI]; + + spinlock_t lock; + + size_t init_size; + size_t max_size; + size_t grow_size; + + /* Basic stats */ + size_t used_size; + size_t num_regions; + + /* User provided functions for expanding/shrinking pool */ + get_memory *get_mem; + put_memory *put_mem; + + struct list_head list; + +#if defined(CONFIG_TLSF_STATS) + /* Extra stats */ + size_t peak_used; + size_t peak_total; + size_t peak_extra; /* MAX(Total - Used) */ + size_t count_alloc; + size_t count_free; + size_t count_region_alloc; + size_t count_region_free; + size_t count_failed_alloc; +#endif + +#if defined(CONFIG_TLSF_DEBUG) + /* + * Pool used size must be 0 when its destroyed. + * When non-empty pool is destroyed, it suggests + * memory leak. Such pools are marked invalid + * and kept in pool list for later debugging. + */ + unsigned int valid; +#endif + void *init_region; + char name[MAX_POOL_NAME_LEN]; +}; +/*-- TLSF structures end */ + +#endif --- linux-2.6.27.orig/ubuntu/compcache/BOM +++ linux-2.6.27/ubuntu/compcache/BOM @@ -0,0 +1,5 @@ +Downloaded from: http://code.google.com/p/compcache/ +Current Version: Patch for 2.6.26.rc6 + +Moved compcache and tlsf modules to ubuntu/. Only touches swap subsystem +for free page callback. --- linux-2.6.27.orig/ubuntu/dm-loop/dm-loop.c +++ linux-2.6.27/ubuntu/dm-loop/dm-loop.c @@ -0,0 +1,1036 @@ +/* + * Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved. + * + * This file is part of device-mapper. + * + * Extent mapping implementation heavily influenced by mm/swapfile.c + * Bryn Reeves + * + * File mapping and block lookup algorithms support by + * Heinz Mauelshagen . + * + * This file is released under the GPL. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dm.h" +#include "dm-bio-list.h" + +#define DM_LOOP_DAEMON "kloopd" +#define DM_MSG_PREFIX "loop" + +enum flags { DM_LOOP_BMAP, DM_LOOP_FSIO }; + +/*-------------------------------------------------------------------- + * Loop context + *--------------------------------------------------------------------*/ + +struct loop_c { + unsigned long flags; + + /* Backing store */ + + struct file *filp; + char *path; + loff_t offset; + struct block_device *bdev; + unsigned blkbits; /* file system block size shift bits */ + + loff_t size; /* size of entire file in bytes */ + loff_t blocks; /* blocks allocated to loop file */ + sector_t mapped_sectors; /* size of mapped area in sectors */ + + int (*map_fn)(struct dm_target *, struct bio *); + void *map_data; +}; + +/* + * Block map extent + */ +struct dm_loop_extent { + sector_t start; /* start sector in mapped device */ + sector_t to; /* start sector on target device */ + sector_t len; /* length in sectors */ +}; + +/* + * Temporary extent list + */ +struct extent_list { + struct dm_loop_extent *extent; + struct list_head list; +}; + +static struct kmem_cache *dm_loop_extent_cache; + +/* + * Block map private context + */ +struct block_map_c { + int nr_extents; /* number of extents in map */ + struct dm_loop_extent **map; /* linear map of extent pointers */ + struct dm_loop_extent **mru; /* pointer to mru entry */ + spinlock_t mru_lock; /* protects mru */ +}; + +/* + * File map private context + */ +struct file_map_c { + spinlock_t lock; /* protects in */ + struct bio_list in; /* new bios for processing */ + struct bio_list work; /* bios queued for processing */ + struct workqueue_struct *wq; /* workqueue */ + struct work_struct ws; /* loop work */ + struct loop_c *loop; /* for filp & offset */ +}; + +/*-------------------------------------------------------------------- + * Generic helpers + *--------------------------------------------------------------------*/ + +static sector_t blk2sect(struct loop_c *lc, blkcnt_t block) +{ + return block << (lc->blkbits - SECTOR_SHIFT); +} + +static blkcnt_t sec2blk(struct loop_c *lc, sector_t sector) +{ + return sector >> (lc->blkbits - SECTOR_SHIFT); +} + +/*-------------------------------------------------------------------- + * File I/O helpers + *--------------------------------------------------------------------*/ + +/* + * transfer data to/from file using the read/write file_operations. + */ +static int fs_io(int rw, struct file *filp, loff_t *pos, struct bio_vec *bv) +{ + ssize_t r; + void __user *ptr = (void __user __force *) kmap(bv->bv_page) + bv->bv_offset; + mm_segment_t old_fs = get_fs(); + + set_fs(get_ds()); + r = (rw == READ) ? filp->f_op->read(filp, ptr, bv->bv_len, pos) : + filp->f_op->write(filp, ptr, bv->bv_len, pos); + set_fs(old_fs); + kunmap(bv->bv_page); + + return (r == bv->bv_len) ? 0 : -EIO; +} + +/* + * Handle I/O for one bio + */ +static void do_one_bio(struct file_map_c *fc, struct bio *bio) +{ + int r = 0, rw = bio_data_dir(bio); + loff_t start = (bio->bi_sector << 9) + fc->loop->offset, pos = start; + struct bio_vec *bv, *bv_end = bio->bi_io_vec + bio->bi_vcnt; + + for (bv = bio->bi_io_vec; bv < bv_end; bv++) { + r = fs_io(rw, fc->loop->filp, &pos, bv); + if (r) { + DMERR("%s error %d", rw ? "write" : "read", r); + break; + } + } + + bio_endio(bio, r); +} + +/* + * Worker thread for a 'file' type loop device + */ +static void do_loop_work(struct work_struct *ws) +{ + struct file_map_c *fc = container_of(ws, struct file_map_c, ws); + struct bio *bio; + + /* quickly grab all new bios queued and add them to the work list */ + spin_lock_irq(&fc->lock); + bio_list_merge(&fc->work, &fc->in); + bio_list_init(&fc->in); + spin_unlock_irq(&fc->lock); + + /* work the list and do file I/O on all bios */ + while ((bio = bio_list_pop(&fc->work))) + do_one_bio(fc, bio); +} + +/* + * Create work queue and initialize work + */ +static int loop_work_init(struct loop_c *lc) +{ + struct file_map_c *fc = lc->map_data; + + fc->wq = create_singlethread_workqueue(DM_LOOP_DAEMON); + if (!fc->wq) + return -ENOMEM; + + return 0; +} + +/* + * Destroy work queue + */ +static void loop_work_exit(struct loop_c *lc) +{ + struct file_map_c *fc = lc->map_data; + + if (fc->wq) + destroy_workqueue(fc->wq); +} + +/* + * DM_LOOP_FSIO map_fn. Mapping just queues bios to the file map + * context and lets the daemon deal with them. + */ +static int loop_file_map(struct dm_target *ti, struct bio *bio) +{ + int wake; + struct loop_c *lc = ti->private; + struct file_map_c *fc = lc->map_data; + + spin_lock_irq(&fc->lock); + wake = bio_list_empty(&fc->in); + bio_list_add(&fc->in, bio); + spin_unlock_irq(&fc->lock); + + /* + * Only call queue_work() if necessary to avoid + * superfluous preempt_{disable/enable}() overhead. + */ + if (wake) + queue_work(fc->wq, &fc->ws); + + /* Handling bio - will submit later. */ + return 0; +} + +/* + * Shutdown the workqueue and free a file mapping + */ +static void destroy_file_map(struct loop_c *lc) +{ + loop_work_exit(lc); + kfree(lc->map_data); +} + +/* + * Set up a file map context and workqueue + */ +static int setup_file_map(struct loop_c *lc) +{ + struct file_map_c *fc = kzalloc(sizeof(*fc), GFP_KERNEL); + + if (!fc) + return -ENOMEM; + + spin_lock_init(&fc->lock); + bio_list_init(&fc->in); + bio_list_init(&fc->work); + INIT_WORK(&fc->ws, do_loop_work); + fc->loop = lc; + + lc->map_data = fc; + lc->map_fn = loop_file_map; + + return loop_work_init(lc); +} + +/*-------------------------------------------------------------------- + * Block I/O helpers + *--------------------------------------------------------------------*/ + +static int contains_sector(struct dm_loop_extent *e, sector_t s) +{ + if (likely(e)) + return s < (e->start + (e->len)) && s >= e->start; + + return 0; +} + +/* + * Walk over a linked list of extent_list structures, freeing them as + * we go. Does not free el->extent. + */ +static void destroy_extent_list(struct list_head *head) +{ + struct list_head *curr, *n; + struct extent_list *el; + + if (list_empty(head)) + return; + + list_for_each_safe(curr, n, head) { + el = list_entry(curr, struct extent_list, list); + list_del(curr); + kfree(el); + } +} + +/* + * Add a new extent to the tail of the list at *head with + * start/to/len parameters. Allocates from the extent cache. + */ +static int list_add_extent(struct list_head *head, sector_t start, + sector_t to, sector_t len) +{ + struct dm_loop_extent *extent; + struct extent_list *list; + + extent = kmem_cache_alloc(dm_loop_extent_cache, GFP_KERNEL); + if (!extent) + goto out; + + list = kmalloc(sizeof(*list), GFP_KERNEL); + if (!list) + goto out; + + extent->start = start; + extent->to = to; + extent->len = len; + + list->extent = extent; + list_add_tail(&list->list, head); + + return 0; +out: + if (extent) + kmem_cache_free(dm_loop_extent_cache, extent); + return -ENOMEM; +} + +/* + * Return an extent range (i.e. beginning and ending physical block numbers). + */ +static int extent_range(struct inode *inode, + blkcnt_t logical_blk, blkcnt_t last_blk, + blkcnt_t *begin_blk, blkcnt_t *end_blk) +{ + sector_t dist = 0, phys_blk, probe_blk = logical_blk; + + /* Find beginning physical block of extent starting at logical_blk. */ + *begin_blk = phys_blk = bmap(inode, probe_blk); + if (!phys_blk) + return -ENXIO; + + for (; phys_blk == *begin_blk + dist; dist++) { + *end_blk = phys_blk; + if (++probe_blk > last_blk) + break; + + phys_blk = bmap(inode, probe_blk); + if (unlikely(!phys_blk)) + return -ENXIO; + } + + return 0; +} + +/* + * Create a sequential list of extents from an inode and return + * it in *head. On success return the number of extents found or + * -ERRNO on failure. + */ +static int loop_extents(struct loop_c *lc, struct inode *inode, + struct list_head *head) +{ + sector_t start = 0; + int r, nr_extents = 0; + blkcnt_t nr_blks = 0, begin_blk = 0, end_blk = 0; + blkcnt_t after_last_blk = sec2blk(lc, + (lc->mapped_sectors + (lc->offset >> 9))); + blkcnt_t logical_blk = sec2blk(lc, (lc->offset >> 9)); + + /* for each block in the mapped region */ + while (logical_blk < after_last_blk) { + r = extent_range(inode, logical_blk, after_last_blk - 1, + &begin_blk, &end_blk); + + /* sparse file fallback */ + if (unlikely(r)) { + DMWARN("%s has a hole; sparse file detected - " + "switching to filesystem I/O", lc->path); + clear_bit(DM_LOOP_BMAP, &lc->flags); + set_bit(DM_LOOP_FSIO, &lc->flags); + return r; + } + + nr_blks = 1 + end_blk - begin_blk; + + if (unlikely(!nr_blks)) + continue; + + r = list_add_extent(head, start, blk2sect(lc, begin_blk), + blk2sect(lc, nr_blks)); + if (unlikely(r)) + return r; + + /* advance to next extent */ + nr_extents++; + start += blk2sect(lc, nr_blks); + logical_blk += nr_blks; + } + + return nr_extents; +} + +/* + * Walk over the extents in a block_map_c, returning them to the cache and + * freeing bc->map and bc. + */ +static void destroy_block_map(struct block_map_c *bc) +{ + unsigned i; + + if (!bc) + return; + + for (i = 0; i < bc->nr_extents; i++) + kmem_cache_free(dm_loop_extent_cache, bc->map[i]); + + DMDEBUG("destroying block map of %d entries", i); + + vfree(bc->map); + kfree(bc); +} + +/* + * Find an extent in *bc using binary search. Returns a pointer into the + * extent map. Calculate index as (extent - bc->map). + */ +static struct dm_loop_extent **extent_binary_lookup(struct block_map_c *bc, + struct dm_loop_extent **extent_mru, sector_t sector) +{ + unsigned nr_extents = bc->nr_extents; + unsigned delta, dist, prev_dist = 0; + struct dm_loop_extent **eptr; + + /* Optimize lookup range based on MRU extent. */ + dist = extent_mru - bc->map; + if ((*extent_mru)->start >= sector) + delta = dist = dist / 2; + else { + delta = (nr_extents - dist) / 2; + dist += delta; + } + + eptr = bc->map + dist; + while (*eptr && !contains_sector(*eptr, sector)) { + if (sector >= (*eptr)->start + (*eptr)->len) { + prev_dist = dist; + if (delta > 1) + delta /= 2; + dist += delta; + } else { + delta = (dist - prev_dist) / 2; + if (!delta) + delta = 1; + dist -= delta; + } + eptr = bc->map + dist; + } + + return eptr; +} + +/* + * Lookup an extent for a sector using the mru cache and binary search. + */ +static struct dm_loop_extent *extent_lookup(struct block_map_c *bc, sector_t sector) +{ + struct dm_loop_extent **eptr; + + spin_lock_irq(&bc->mru_lock); + eptr = bc->mru; + spin_unlock_irq(&bc->mru_lock); + + if (contains_sector(*eptr, sector)) + return *eptr; + + eptr = extent_binary_lookup(bc, eptr, sector); + if (!eptr) + return NULL; + + spin_lock_irq(&bc->mru_lock); + bc->mru = eptr; + spin_unlock_irq(&bc->mru_lock); + + return *eptr; +} + +/* + * DM_LOOP_BMAP map_fn. Looks up the sector in the extent map and + * rewrites the bio device and bi_sector fields. + */ +static int loop_block_map(struct dm_target *ti, struct bio *bio) +{ + struct loop_c *lc = ti->private; + struct dm_loop_extent *extent = extent_lookup(lc->map_data, bio->bi_sector); + + if (likely(extent)) { + bio->bi_bdev = lc->bdev; + bio->bi_sector = extent->to + (bio->bi_sector - extent->start); + return 1; /* Done with bio -> submit */ + } + + DMERR("no matching extent in map for sector %llu", + (unsigned long long) bio->bi_sector + ti->begin); + BUG(); + + return -EIO; +} + +/* + * Turn an extent_list into a linear pointer map of nr_extents + 1 entries + * and set the final entry to NULL. + */ +static struct dm_loop_extent **build_extent_map(struct list_head *head, int nr_extents, + unsigned long *flags) +{ + unsigned map_size, cache_size; + struct dm_loop_extent **map, **curr; + struct list_head *pos; + struct extent_list *el; + + map_size = 1 + (sizeof(*map) * nr_extents); + cache_size = kmem_cache_size(dm_loop_extent_cache) * nr_extents; + + map = vmalloc(map_size); + curr = map; + + DMDEBUG("allocated extent map of %u %s for %d extents (%u %s)", + (map_size < 8192) ? map_size : map_size >> 10, + (map_size < 8192) ? "bytes" : "kilobytes", nr_extents, + (cache_size < 8192) ? cache_size : cache_size >> 10, + (cache_size < 8192) ? "bytes" : "kilobytes"); + + list_for_each(pos, head) { + el = list_entry(pos, struct extent_list, list); + *(curr++) = el->extent; + } + *curr = NULL; + + return map; +} + +/* + * Set up a block map context and extent map + */ +static int setup_block_map(struct loop_c *lc, struct inode *inode) +{ + int r, nr_extents; + struct block_map_c *bc; + LIST_HEAD(head); + + if (!inode || !inode->i_sb || !inode->i_sb->s_bdev) + return -ENXIO; + + /* build a linked list of extents in linear order */ + r = nr_extents = loop_extents(lc, inode, &head); + if (nr_extents < 1) + goto out; + + r = -ENOMEM; + bc = kzalloc(sizeof(*bc), GFP_KERNEL); + if (!bc) + goto out; + + /* create a linear map of pointers into the extent cache */ + bc->map = build_extent_map(&head, nr_extents, &lc->flags); + destroy_extent_list(&head); + + if (IS_ERR(bc->map)) { + r = PTR_ERR(bc->map); + goto out; + } + + spin_lock_init(&bc->mru_lock); + bc->mru = bc->map; + bc->nr_extents = nr_extents; + lc->bdev = inode->i_sb->s_bdev; + lc->map_data = bc; + lc->map_fn = loop_block_map; + + return 0; + +out: + return r; +} + +/*-------------------------------------------------------------------- + * Generic helpers + *--------------------------------------------------------------------*/ + +/* + * Invalidate all unlocked loop file pages + */ +static int loop_invalidate_file(struct file *filp) +{ + int r; + + /* Same as generic_file_direct_IO() */ + unmap_mapping_range(filp->f_mapping, 0, ~0UL, 0); + + r = filemap_write_and_wait(filp->f_mapping); + if (r) + return r; + + /* + * This will remove all pages except dirty ones. + * If there are dirty pages at this point, it means that the user + * is writing to the file and the coherency is lost anyway. + * If the user was writing to the file simultaneously, this + * returns non-zero, but we ignore that. + */ + invalidate_inode_pages2_range(filp->f_mapping, 0, ~0UL); + + return 0; +} + +/* + * Acquire or release a "no-truncate" lock on *filp. + * We overload the S_SWAPFILE flag for loop targets because + * it provides the same no-truncate semantics we require, and + * holding onto i_sem is no longer an option. + */ +static void file_truncate_lock(struct file *filp) +{ + struct inode *inode = filp->f_mapping->host; + + mutex_lock(&inode->i_mutex); + inode->i_flags |= S_SWAPFILE; + mutex_unlock(&inode->i_mutex); +} + +static void file_truncate_unlock(struct file *filp) +{ + struct inode *inode = filp->f_mapping->host; + + mutex_lock(&inode->i_mutex); + inode->i_flags &= ~S_SWAPFILE; + mutex_unlock(&inode->i_mutex); +} + +/* + * Fill out split_io for taget backing store + */ +static void set_split_io(struct dm_target *ti) +{ + struct loop_c *lc = ti->private; + + if (test_bit(DM_LOOP_BMAP, &lc->flags)) + /* Split I/O at block boundaries */ + ti->split_io = 1 << (lc->blkbits - SECTOR_SHIFT); + else + ti->split_io = 64; + + DMDEBUG("splitting io at %llu sector boundaries", + (unsigned long long) ti->split_io); +} + +/* + * Check that the loop file is regular and available. + */ +static int loop_check_file(struct dm_target *ti) +{ + struct loop_c *lc = ti->private; + struct file *filp = lc->filp; + struct inode *inode = filp->f_mapping->host; + + if (!inode) + return -ENXIO; + + ti->error = "backing file must be a regular file"; + if (!S_ISREG(inode->i_mode)) + return -EINVAL; + + ti->error = "backing file is mapped into userspace for writing"; + if (mapping_writably_mapped(filp->f_mapping)) + return -EBUSY; + + if (mapping_mapped(filp->f_mapping)) + DMWARN("%s is mapped into userspace", lc->path); + + if (!inode->i_sb || !inode->i_sb->s_bdev) { + DMWARN("%s has no blockdevice - switching to filesystem I/O", + lc->path); + clear_bit(DM_LOOP_BMAP, &lc->flags); + set_bit(DM_LOOP_FSIO, &lc->flags); + } + + ti->error = "backing file already in use"; + if (IS_SWAPFILE(inode)) + return -EBUSY; + + return 0; +} + +/* + * Check loop file size and store it in the loop context + */ +static int loop_setup_size(struct dm_target *ti) +{ + struct loop_c *lc = ti->private; + struct inode *inode = lc->filp->f_mapping->host; + int r = -EINVAL; + + lc->size = i_size_read(inode); + lc->blkbits = inode->i_blkbits; + + ti->error = "backing file is empty"; + if (!lc->size) + goto out; + + DMDEBUG("set backing file size to %llu", (unsigned long long) lc->size); + + ti->error = "backing file cannot be less than one block in size"; + if (lc->size < (blk2sect(lc, 1) << 9)) + goto out; + + ti->error = "loop file offset must be a multiple of fs blocksize"; + if (lc->offset & ((1 << lc->blkbits) - 1)) + goto out; + + ti->error = "loop file offset too large"; + if (lc->offset > (lc->size - (1 << 9))) + goto out; + + lc->mapped_sectors = (lc->size - lc->offset) >> 9; + DMDEBUG("set mapped sectors to %llu (%llu bytes)", + (unsigned long long) lc->mapped_sectors, + (lc->size - lc->offset)); + + if ((lc->offset + (lc->mapped_sectors << 9)) < lc->size) + DMWARN("not using %llu bytes in incomplete block at EOF", + lc->size - (lc->offset + (lc->mapped_sectors << 9))); + + ti->error = "mapped region cannot be smaller than target size"; + if (lc->size - lc->offset < (ti->len << 9)) + goto out; + + r = 0; + +out: + return r; +} + +/* + * release a loop file + */ +static void loop_put_file(struct file *filp) +{ + if (!filp) + return; + + file_truncate_unlock(filp); + filp_close(filp, NULL); +} + +/* + * Open loop file and perform type, availability and size checks. + */ +static int loop_get_file(struct dm_target *ti) +{ + int flags = ((dm_table_get_mode(ti->table) & FMODE_WRITE) ? + O_RDWR : O_RDONLY) | O_LARGEFILE; + struct loop_c *lc = ti->private; + struct file *filp; + int r = 0; + + ti->error = "could not open backing file"; + filp = filp_open(lc->path, flags, 0); + if (IS_ERR(filp)) + return PTR_ERR(filp); + lc->filp = filp; + r = loop_check_file(ti); + if (r) + goto err; + + r = loop_setup_size(ti); + if (r) + goto err; + + file_truncate_lock(filp); + return 0; + +err: + fput(filp); + return r; +} + +/* + * invalidate mapped pages belonging to the loop file + */ +static void loop_flush(struct dm_target *ti) +{ + struct loop_c *lc = ti->private; + + loop_invalidate_file(lc->filp); +} + +/*-------------------------------------------------------------------- + * Device-mapper target methods + *--------------------------------------------------------------------*/ + +/* + * Generic loop map function. Re-base I/O to target begin and submit + */ +static int loop_map(struct dm_target *ti, struct bio *bio, + union map_info *context) +{ + struct loop_c *lc = ti->private; + + if (unlikely(bio_barrier(bio))) + return -EOPNOTSUPP; + + bio->bi_sector -= ti->begin; + + if (lc->map_fn) + return lc->map_fn(ti, bio); + + return -EIO; +} + +/* + * Block status helper + */ +static ssize_t loop_file_status(struct loop_c *lc, char *result, + unsigned maxlen) +{ + ssize_t sz = 0; + struct file_map_c *fc = lc->map_data; + int qlen; + + spin_lock_irq(&fc->lock); + qlen = bio_list_size(&fc->work); + qlen += bio_list_size(&fc->in); + spin_unlock_irq(&fc->lock); + + DMEMIT("file %d", qlen); + + return sz; +} + +/* + * File status helper + */ +static ssize_t loop_block_status(struct loop_c *lc, char *result, + unsigned maxlen) +{ + ssize_t sz = 0; + struct block_map_c *bc = lc->map_data; + int mru; + + spin_lock_irq(&bc->mru_lock); + mru = bc->mru - bc->map; + spin_unlock_irq(&bc->mru_lock); + + DMEMIT("block %d %d", bc->nr_extents, mru); + + return sz; +} + +/* + * This needs some thought on handling unlinked backing files. some parts of + * the kernel return a cached name (now invalid), while others return a dcache + * "/path/to/foo (deleted)" name (never was/is valid). Which is "better" is + * debatable. + * + * On the one hand, using a cached name gives table output which is directly + * usable assuming the user re-creates the unlinked image file, on the other + * it is more consistent with e.g. swap to use the dcache name. + * +*/ +static int loop_status(struct dm_target *ti, status_type_t type, char *result, + unsigned maxlen) +{ + struct loop_c *lc = ti->private; + ssize_t sz = 0; + + switch (type) { + case STATUSTYPE_INFO: + if (test_bit(DM_LOOP_BMAP, &lc->flags)) + sz += loop_block_status(lc, result, maxlen - sz); + else if (test_bit(DM_LOOP_FSIO, &lc->flags)) + sz += loop_file_status(lc, result, maxlen - sz); + break; + + case STATUSTYPE_TABLE: + DMEMIT("%s %llu", lc->path, lc->offset); + break; + } + return 0; +} + +/* + * Destroy a loopback mapping + */ +static void loop_dtr(struct dm_target *ti) +{ + struct loop_c *lc = ti->private; + + if ((dm_table_get_mode(ti->table) & FMODE_WRITE)) + loop_invalidate_file(lc->filp); + + if (test_bit(DM_LOOP_BMAP, &lc->flags) && lc->map_data) + destroy_block_map((struct block_map_c *)lc->map_data); + if (test_bit(DM_LOOP_FSIO, &lc->flags) && lc->map_data) + destroy_file_map(lc); + + loop_put_file(lc->filp); + DMINFO("released file %s", lc->path); + + kfree(lc); +} + +/* + * Construct a loopback mapping: + */ +static int loop_ctr(struct dm_target *ti, unsigned argc, char **argv) +{ + struct loop_c *lc = NULL; + int r = -EINVAL; + + ti->error = "invalid argument count"; + if (argc != 2) + goto err; + + r = -ENOMEM; + ti->error = "cannot allocate loop context"; + lc = kzalloc(sizeof(*lc), GFP_KERNEL); + if (!lc) + goto err; + + /* default */ + set_bit(DM_LOOP_BMAP, &lc->flags); + ti->error = "cannot allocate loop path"; + lc->path = kstrdup(argv[0], GFP_KERNEL); + if (!lc->path) + goto err; + + ti->private = lc; + + r = -EINVAL; + ti->error = "invalid file offset"; + if (sscanf(argv[1], "%lld", &lc->offset) != 1) + goto err; + + if (lc->offset) + DMDEBUG("setting file offset to %lld", lc->offset); + + /* open & check file and set size parameters */ + r = loop_get_file(ti); + + /* ti->error has been set by loop_get_file */ + if (r) + goto err; + + ti->error = "could not create loop mapping"; + if (test_bit(DM_LOOP_BMAP, &lc->flags)) + r = setup_block_map(lc, lc->filp->f_mapping->host); + if (test_bit(DM_LOOP_FSIO, &lc->flags)) + r = setup_file_map(lc); + + if (r) + goto err_putf; + + loop_invalidate_file(lc->filp); + + set_split_io(ti); + if (lc->bdev) + dm_set_device_limits(ti, lc->bdev); + + DMDEBUG("constructed loop target on %s " + "(%lldk, %llu sectors)", lc->path, + (lc->size >> 10), (unsigned long long)lc->mapped_sectors); + ti->error = NULL; + + return 0; + +err_putf: + loop_put_file(lc->filp); +err: + if (lc) + kfree(lc); + return r; +} + +static struct target_type loop_target = { + .name = "loop", + .version = {0, 0, 2}, + .module = THIS_MODULE, + .ctr = loop_ctr, + .dtr = loop_dtr, + .map = loop_map, + .presuspend = loop_flush, + .flush = loop_flush, + .status = loop_status, +}; + +/*-------------------------------------------------------------------- + * Module bits + *--------------------------------------------------------------------*/ +static int __init dm_loop_init(void) +{ + int r; + + r = dm_register_target(&loop_target); + if (r < 0) { + DMERR("register failed %d", r); + goto err; + } + + r = -ENOMEM; + dm_loop_extent_cache = KMEM_CACHE(dm_loop_extent, SLAB_HWCACHE_ALIGN); + if (!dm_loop_extent_cache) + goto err; + + DMINFO("version %u.%u.%u loaded", + loop_target.version[0], loop_target.version[1], + loop_target.version[2]); + + return 0; + +err: + if (dm_loop_extent_cache) + kmem_cache_destroy(dm_loop_extent_cache); + + return r; +} + +static void __exit dm_loop_exit(void) +{ + int r; + + r = dm_unregister_target(&loop_target); + kmem_cache_destroy(dm_loop_extent_cache); + + if (r < 0) + DMERR("target unregister failed %d", r); + else + DMINFO("version %u.%u.%u unloaded", + loop_target.version[0], loop_target.version[1], + loop_target.version[2]); +} + +module_init(dm_loop_init); +module_exit(dm_loop_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Bryn Reeves "); +MODULE_DESCRIPTION("device-mapper loop target"); --- linux-2.6.27.orig/ubuntu/dm-loop/Kconfig +++ linux-2.6.27/ubuntu/dm-loop/Kconfig @@ -0,0 +1,9 @@ +config DM_LOOP + tristate "Loop target (EXPERIMENTAL)" + depends on BLK_DEV_DM && EXPERIMENTAL + ---help--- + This device-mapper target allows you to treat a regular file as + a block device. + + If unsure, say N. + --- linux-2.6.27.orig/ubuntu/dm-loop/Makefile +++ linux-2.6.27/ubuntu/dm-loop/Makefile @@ -0,0 +1,5 @@ +EXTRA_CFLAGS += -I$(srctree)/drivers/md + +obj-$(CONFIG_DM_LOOP) += dm-loop.o + + --- linux-2.6.27.orig/ubuntu/dm-loop/BOM +++ linux-2.6.27/ubuntu/dm-loop/BOM @@ -0,0 +1,4 @@ +Downloaded from: http://sources.redhat.com/lvm2/wiki/DMLoop +Current Version: Tues, 10 Jun 2008 09:10:03 -0000 +Comments: Fairly easy to integrate in + --- linux-2.6.27.orig/ubuntu/et131x/ET1310_pm.h +++ linux-2.6.27/ubuntu/et131x/ET1310_pm.h @@ -0,0 +1,216 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * ET1310_pm.h - Defines, structs, enums, prototypes, etc. pertaining to power + * management. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/08/01 19:35:11 $ + $Revision: 1.5 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +#ifndef _ET1310_PM_H_ +#define _ET1310_PM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + + + +/****************************************************************************** + INCLUDES + *****************************************************************************/ +#include "ET1310_common.h" + + + + +/****************************************************************************** + CONSTANTS FOR POWER MANAGEMENT + *****************************************************************************/ +#define MAX_WOL_PACKET_SIZE 0x80 +#define MAX_WOL_MASK_SIZE ( MAX_WOL_PACKET_SIZE / 8 ) +#define NUM_WOL_PATTERNS 0x5 +#define CRC16_POLY 0x1021 + + + + +/****************************************************************************** + Definition of NDIS_DEVICE_POWER_STATE + *****************************************************************************/ +typedef enum +{ + NdisDeviceStateUnspecified = 0, + NdisDeviceStateD0, + NdisDeviceStateD1, + NdisDeviceStateD2, + NdisDeviceStateD3 +} NDIS_DEVICE_POWER_STATE; + + + + +/****************************************************************************** + Structure for Power Management Info + *****************************************************************************/ +typedef struct _MP_PM_CONFIG_SPACE_INFO_t +{ + UCHAR capId; + UCHAR nextItemPtr; + UINT16 pmcr; + UINT16 pmcsr; + UCHAR pmscr_bse; + UCHAR pm_data_regs; +} +MP_PM_CONFIG_SPACE_INFO_t, *pMP_PM_CONFIG_SPACE_INFO_t; + + + + +typedef struct _MP_POWER_MGMT +{ + /************************************************************************** + variable putting the phy into coma mode when boot up with no cable + plugged in after 5 seconds + *************************************************************************/ + UCHAR TransPhyComaModeOnBoot; + + + /************************************************************************** + Array holding the five CRC values that the device is currently using + for WOL. This will be queried when a pattern is to be removed. + *************************************************************************/ + UINT32 localWolAndCrc0; + UINT16 WOLPatternList[ NUM_WOL_PATTERNS ]; + UCHAR WOLMaskList[ NUM_WOL_PATTERNS ][ MAX_WOL_MASK_SIZE ]; + UINT32 WOLMaskSize[ NUM_WOL_PATTERNS ]; + + + /************************************************************************** + IP address + *************************************************************************/ + union + { + UINT32 u32; + UCHAR u8[4]; + } IPAddress; + + + /************************************************************************** + Current Power state of the adapter. + *************************************************************************/ + NDIS_DEVICE_POWER_STATE PowerState; + BOOL_t WOLState; + BOOL_t WOLEnabled; + BOOL_t Failed10Half; + BOOL_t bFailedStateTransition; + + /************************************************************************** + Next two used to save power information at power down. + This information will be used during power up to set up parts of Power + Management in JAGCore + *************************************************************************/ + UINT32 tx_en; + UINT32 rx_en; + UINT16 PowerDownSpeed; + UCHAR PowerDownDuplex; + + MP_PM_CONFIG_SPACE_INFO_t pmConfigRegs; +} MP_POWER_MGMT, *PMP_POWER_MGMT; + + + + +/****************************************************************************** + Forward declaration of the private adapter structure + ( IS THERE A WAY TO DO THIS WITH A TYPEDEF??? ) + *****************************************************************************/ +struct et131x_adapter; + + + + +/****************************************************************************** + PROTOTYPES for ET1310_pm.c + *****************************************************************************/ +UINT16 CalculateCCITCRC16( PUCHAR Pattern, PUCHAR Mask, UINT32 MaskSize ); + +void EnablePhyComa( struct et131x_adapter *pAdapter ); + +void DisablePhyComa( struct et131x_adapter *pAdapter ); + + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _ET1310_PM_H_ */ --- linux-2.6.27.orig/ubuntu/et131x/et131x_supp.h +++ linux-2.6.27/ubuntu/et131x/et131x_supp.h @@ -0,0 +1,133 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_supp.h - Misc. defines, structs, enums, prototypes, etc. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/08/01 19:35:13 $ + $Revision: 1.5 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + +#ifndef __ET131X_SUPP_H__ +#define __ET131X_SUPP_H__ + + + + +/****************************************************************************** + Enum for use with netif_indicate_status + *****************************************************************************/ +typedef enum netif_status +{ + NETIF_STATUS_INVALID = 0, + NETIF_STATUS_MEDIA_CONNECT, + NETIF_STATUS_MEDIA_DISCONNECT, + NETIF_STATUS_MAX +} NETIF_STATUS; + + + + +/****************************************************************************** + Definitions to maintain compatibility with older versions of the kernel + *****************************************************************************/ +#ifndef netdev_priv +#define netdev_priv(x) (ET131X_ADAPTER *)netdev->priv +#endif + +#ifndef SET_NETDEV_DEV +#define SET_NETDEV_DEV(net, pdev) +#endif + +#ifndef free_netdev +#define free_netdev(x) kfree(x) +#endif + +#ifndef if_mii +#define if_mii(x) (struct mii_ioctl_data *)&x->ifr_ifru +#endif + + + + +/****************************************************************************** + PROTOTYPES + *****************************************************************************/ +void et131x_init_enet_crc_calc( void ); + +UINT32 et131x_calc_enet_crc( PUCHAR Message, UINT32 MessageSize ); + +UINT32 pci_slot_information_read( struct pci_dev *pdev, UINT32 where, + UINT8 *buf, UINT32 len ); + +UINT32 pci_slot_information_write( struct pci_dev *pdev, UINT32 where, + UINT8 *buf, UINT32 len ); + +void netif_indicate_status( struct net_device *netdev, NETIF_STATUS status ); + + + + +#endif /* __ET131X_SUPP_H__ */ --- linux-2.6.27.orig/ubuntu/et131x/et131x_version.h +++ linux-2.6.27/ubuntu/et131x/et131x_version.h @@ -0,0 +1,124 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_version.h - This file provides system and device version information. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2006/01/31 20:58:43 $ + $Revision: 1.16 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +#ifndef __ET131X_VERSION_H__ +#define __ET131X_VERSION_H__ + + + + +/****************************************************************************** + Includes + *****************************************************************************/ +#include +#include + + + + +/****************************************************************************** + Constant Definitions + *****************************************************************************/ +#define DRIVER_AUTHOR "Victor Soriano (vjsoriano@agere.com)" +#define DRIVER_LICENSE "BSD" +#define DRIVER_DEVICE_STRING "ET1310" +#define DRIVER_NAME "et131x" +#define DRIVER_MAJOR_VERSION 1 +#define DRIVER_MINOR_VERSION 2 +#define DRIVER_PATCH_VERSION 3 +#define DRIVER_VERSION_STRING "1.2.3" +#define DRIVER_VENDOR "Agere Systems, http://www.agere.com" +#define DRIVER_BUILD_DATE "01/31/2006 15:40:00" +#define DRIVER_DESC "10/100/1000 Base-T Ethernet Driver" + +#define STRUCT_MODULE "net" // blux: missed by the kernel + +#define DRIVER_INFO DRIVER_DESC " for the "\ + DRIVER_DEVICE_STRING ", v" \ + DRIVER_VERSION_STRING " " \ + DRIVER_BUILD_DATE " by " \ + DRIVER_VENDOR + + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) +#define DRIVER_NAME_EXT "et131x.o" +#else +#define DRIVER_NAME_EXT "et131x.ko" +#endif + + + + +#endif /* __ET131X_VERSION_H__ */ --- linux-2.6.27.orig/ubuntu/et131x/et131x_defs.h +++ linux-2.6.27/ubuntu/et131x/et131x_defs.h @@ -0,0 +1,223 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_defs.h - Defines, structs, enums, prototypes, etc. to assist with OS + * compatibility + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/10/28 18:43:46 $ + $Revision: 1.8 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +#ifndef __ET131X_DEFS_H__ +#define __ET131X_DEFS_H__ + + + + +/****************************************************************************** + Define a boolean type + *****************************************************************************/ +typedef enum { FALSE, TRUE } __attribute__ ((packed)) BOOL_t; + + + + +/****************************************************************************** + Packet and header sizes + *****************************************************************************/ +#define NIC_MIN_PACKET_SIZE 60 +#define NIC_HEADER_SIZE ETH_HLEN //14 + + + + +/****************************************************************************** + Multicast list size + *****************************************************************************/ +#define NIC_MAX_MCAST_LIST 128 + + + + +/****************************************************************************** + Supported Filters + *****************************************************************************/ +#define ET131X_PACKET_TYPE_DIRECTED 0x0001 +#define ET131X_PACKET_TYPE_MULTICAST 0x0002 +#define ET131X_PACKET_TYPE_BROADCAST 0x0004 +#define ET131X_PACKET_TYPE_PROMISCUOUS 0x0008 +#define ET131X_PACKET_TYPE_ALL_MULTICAST 0x0010 + + + + +/****************************************************************************** + Tx Timeout + *****************************************************************************/ +#define ET131X_TX_TIMEOUT (1 * HZ) +#define NIC_SEND_HANG_THRESHOLD 0 + + + + +/****************************************************************************** + MP_TCB flags + *****************************************************************************/ +#define fMP_DEST_MULTI 0x00000001 +#define fMP_DEST_BROAD 0x00000002 + + + + +/****************************************************************************** + MP_ADAPTER flags + *****************************************************************************/ +#define fMP_ADAPTER_RECV_LOOKASIDE 0x00000004 +#define fMP_ADAPTER_INTERRUPT_IN_USE 0x00000008 +#define fMP_ADAPTER_SECONDARY 0x00000010 + + + + +/****************************************************************************** + MP_SHARED flags + *****************************************************************************/ +#define fMP_ADAPTER_SHUTDOWN 0x00100000 +#define fMP_ADAPTER_LOWER_POWER 0x00200000 + +#define fMP_ADAPTER_NON_RECOVER_ERROR 0x00800000 +#define fMP_ADAPTER_RESET_IN_PROGRESS 0x01000000 +#define fMP_ADAPTER_NO_CABLE 0x02000000 +#define fMP_ADAPTER_HARDWARE_ERROR 0x04000000 +#define fMP_ADAPTER_REMOVE_IN_PROGRESS 0x08000000 +#define fMP_ADAPTER_HALT_IN_PROGRESS 0x10000000 +#define fMP_ADAPTER_LINK_DETECTION 0x20000000 + +#define fMP_ADAPTER_FAIL_SEND_MASK 0x3ff00000 +#define fMP_ADAPTER_NOT_READY_MASK 0x3ff00000 + + + + +/****************************************************************************** + Some offsets in PCI config space that are actually used. + *****************************************************************************/ +#define ET1310_PCI_PM_CAPABILITY (UINT32)0x40 +#define ET1310_PCI_PM_CSR (UINT32)0x44 +#define ET1310_PCI_MAX_PYLD (UINT32)0x4C +#define ET1310_PCI_DEV_CTRL (UINT32)0x50 +#define ET1310_PCI_DEV_STAT (UINT32)0x52 +#define ET1310_NMI_DISABLE (UINT32)0x61 +#define ET1310_PCI_MAC_ADDRESS (UINT32)0xA4 +#define ET1310_PCI_EEPROM_STATUS (UINT32)0xB2 +#define ET1310_PCI_PHY_INDEX_REG (UINT32)0xB4 +#define ET1310_PCI_ACK_NACK (UINT32)0xC0 +#define ET1310_PCI_REPLAY (UINT32)0xC2 +#define ET1310_PCI_L0L1LATENCY (UINT32)0xCF +#define ET1310_PCI_SEL_PHY_CTRL (UINT32)0xE4 +#define ET1310_PCI_ADVANCED_ERR (UINT32)0x100 + + + + +/****************************************************************************** + PCI Vendor/Product IDs + *****************************************************************************/ +#define ET131X_PCI_VENDOR_ID 0x11C1 // Agere Systems +#define ET131X_PCI_DEVICE_ID_GIG 0xED00 // ET1310 1000 Base-T +#define ET131X_PCI_DEVICE_ID_FAST 0xED01 // ET1310 100 Base-T + + + + +/****************************************************************************** + Define FIELD_OFFSET macro + *****************************************************************************/ +#define FIELD_OFFSET(type,field) ((int)(&((type *)0)->field)) + + + + +/****************************************************************************** + Handle name change of some regsiter bits + *****************************************************************************/ +#define phy_sw_coma pm_phy_sw_coma + + + + +/****************************************************************************** + Define order of magnitude converter + *****************************************************************************/ +#define NANO_IN_A_MICRO 1000 + + + + +#endif /* __ET131X_DEFS_H__ */ --- linux-2.6.27.orig/ubuntu/et131x/et131x_isr.h +++ linux-2.6.27/ubuntu/et131x/et131x_isr.h @@ -0,0 +1,95 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_isr.h - Defines, structs, enums, prototypes, etc. pertaining to the + * ISR processing code. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/08/01 19:35:13 $ + $Revision: 1.3 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +#ifndef __ET131X_ISR_H__ +#define __ET131X_ISR_H__ + + + + +/****************************************************************************** + Function Prototypes + *****************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) +void et131x_isr( int irq, void *dev_id, struct pt_regs *regs ); +#else +irqreturn_t et131x_isr( int irq, void *dev_id ); +#endif + +void et131x_isr_handler( struct work_struct *work ); + + +#endif /* __ET131X_ISR_H__ */ --- linux-2.6.27.orig/ubuntu/et131x/et131x_config.h +++ linux-2.6.27/ubuntu/et131x/et131x_config.h @@ -0,0 +1,99 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_config.h - Defines, structs, enums, prototypes, etc. to support + * et131x_config.c + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/08/01 19:35:12 $ + $Revision: 1.4 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +#ifndef __ET131X_CONFIG_H__ +#define __ET131X_CONFIG_H__ + + + + +/****************************************************************************** + Forward declaration of the private adapter structure + *****************************************************************************/ +struct et131x_adapter; + + + + +/****************************************************************************** + PROTOTYPES for et131x_config.c + *****************************************************************************/ +void et131x_config_parse( struct et131x_adapter *pAdapter ); + + + + +#endif /* __ET131X_CONFIG_H__ */ --- linux-2.6.27.orig/ubuntu/et131x/et131x_main.c +++ linux-2.6.27/ubuntu/et131x/et131x_main.c @@ -0,0 +1,258 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_main.c - This file contains the driver's main Linux entry points. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/08/01 19:35:13 $ + $Revision: 1.6 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +/****************************************************************************** + Includes + *****************************************************************************/ +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include +#include +#include +#include + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ET1310_phy.h" +#include "ET1310_pm.h" +#include "ET1310_jagcore.h" + +#include "et131x_supp.h" +#include "et131x_adapter.h" +#include "et131x_initpci.h" + + + + +/****************************************************************************** + Modinfo parameters (filled out using defines from et131x_version.h) + *****************************************************************************/ +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_INFO ); +MODULE_LICENSE( DRIVER_LICENSE ); + + + + +/****************************************************************************** + Module Parameters and related data for debugging facilities + *****************************************************************************/ +#ifdef ET131X_DBG + +static u32 et131x_debug_level = DBG_LVL; +static u32 et131x_debug_flags = DBG_DEFAULTS; + +module_param( et131x_debug_level, uint, 0 ); +module_param( et131x_debug_flags, uint, 0 ); + +MODULE_PARM_DESC( et131x_debug_level, + "Level of debugging desired (0-7)" ); + +dbg_info_t et131x_info = { DRIVER_NAME_EXT, 0, 0 }; +dbg_info_t *et131x_dbginfo = &et131x_info; + +#endif /* ET131X_DBG */ + + + + +/****************************************************************************** + ROUTINE : et131x_init_module + ****************************************************************************** + + DESCRIPTION : The "main" entry point called on driver initialization + + PARAMETERS : N/A + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_init_module( void ) +{ + int result; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_init_module" ); + + +#ifdef ET131X_DBG + /************************************************************************** + Set the level of debug messages displayed using the module parameter + *************************************************************************/ + et131x_dbginfo->dbgFlags = et131x_debug_flags; + + switch( et131x_debug_level ) + { + case 7: + et131x_dbginfo->dbgFlags |= ( DBG_RX_ON | DBG_TX_ON ); + + case 6: + et131x_dbginfo->dbgFlags |= DBG_PARAM_ON; + + case 5: + et131x_dbginfo->dbgFlags |= DBG_VERBOSE_ON; + + case 4: + et131x_dbginfo->dbgFlags |= DBG_TRACE_ON; + + case 3: + et131x_dbginfo->dbgFlags |= DBG_NOTICE_ON; + + case 2: + case 1: + case 0: + default: + break; + } +#endif /* ET131X_DBG */ + + DBG_ENTER( et131x_dbginfo ); + DBG_PRINT( "%s\n", DRIVER_INFO ); + + + result = et131x_pci_register( ); + + + DBG_LEAVE( et131x_dbginfo ); + return result; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_cleanup_module + ****************************************************************************** + + DESCRIPTION : The entry point called on driver cleanup + + PARAMETERS : N/A + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_cleanup_module( void ) +{ + DBG_FUNC( "et131x_cleanup_module" ); + DBG_ENTER( et131x_dbginfo ); + + + et131x_pci_unregister( ); + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + These macros map the driver-specific init_module() and cleanup_module() + routines so they can be called by the kernel. + *****************************************************************************/ +module_init(et131x_init_module); +module_exit(et131x_cleanup_module); --- linux-2.6.27.orig/ubuntu/et131x/et131x_adapter.h +++ linux-2.6.27/ubuntu/et131x/et131x_adapter.h @@ -0,0 +1,508 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_adapter.h - Header which includes the private adapter structure, along + * with related support structures, macros, definitions, etc. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2006/01/25 20:48:56 $ + $Revision: 1.15 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +#ifndef __ET131X_ADAPTER_H__ +#define __ET131X_ADAPTER_H__ + + + + +#include "ET1310_address_map.h" +#include "ET1310_tx.h" +#include "ET1310_rx.h" + + + + +/****************************************************************************** + Do not change these values: if changed, then change also in respective + TXdma and Rxdma engines + *****************************************************************************/ +#define NUM_DESC_PER_RING_TX 512 // TX Do not change these values +#define NUM_TCB 64 + + + + +/****************************************************************************** + These values are all superseded by registry entries to facilitate tuning. + Once the desired performance has been achieved, the optimal registry values + should be re-populated to these #defines: + *****************************************************************************/ +#define NUM_TRAFFIC_CLASSES 1 + + + + +/****************************************************************************** + There are three ways of counting errors - if there are more than X errors + in Y packets (represented by the "SAMPLE" macros), if there are more than + N errors in a S mSec time period (the "PERIOD" macros), or if there are + consecutive packets with errors (CONSEC_ERRORED_THRESH). This last covers + for "Bursty" errors, and the errored packets may well not be contiguous, + but several errors where the packet counter has changed by less than a + small amount will cause this count to increment. + *****************************************************************************/ +#define TX_PACKETS_IN_SAMPLE 10000 +#define TX_MAX_ERRORS_IN_SAMPLE 50 + +#define TX_ERROR_PERIOD 1000 +#define TX_MAX_ERRORS_IN_PERIOD 10 + +#define LINK_DETECTION_TIMER 5000 + +#define TX_CONSEC_RANGE 5 +#define TX_CONSEC_ERRORED_THRESH 10 + +#define LO_MARK_PERCENT_FOR_PSR 15 +#define LO_MARK_PERCENT_FOR_RX 15 + + + + +/****************************************************************************** + Macros for flag and ref count operations + *****************************************************************************/ +#define MP_SET_FLAG(_M, _F) ((_M)->Flags |= (_F)) +#define MP_CLEAR_FLAG(_M, _F) ((_M)->Flags &= ~(_F)) +#define MP_CLEAR_FLAGS(_M) ((_M)->Flags = 0) +#define MP_TEST_FLAG(_M, _F) (((_M)->Flags & (_F)) != 0) +#define MP_TEST_FLAGS(_M, _F) (((_M)->Flags & (_F)) == (_F)) +#define MP_IS_FLAG_CLEAR(_M, _F) (((_M)->Flags & (_F)) == 0) + +#define MP_INC_RCV_REF(_A) atomic_inc(&(_A)->RcvRefCount) +#define MP_DEC_RCV_REF(_A) atomic_dec(&(_A)->RcvRefCount) +#define MP_GET_RCV_REF(_A) atomic_read(&(_A)->RcvRefCount) + + + + +/****************************************************************************** + Macros specific to the private adapter structure + *****************************************************************************/ +#define MP_TCB_RESOURCES_AVAILABLE(_M) ((_M)->TxRing.nBusySend < NUM_TCB) +#define MP_TCB_RESOURCES_NOT_AVAILABLE(_M) ((_M)->TxRing.nBusySend >= NUM_TCB) + +#define MP_SHOULD_FAIL_SEND(_M) ((_M)->Flags & fMP_ADAPTER_FAIL_SEND_MASK) +#define MP_IS_NOT_READY(_M) ((_M)->Flags & fMP_ADAPTER_NOT_READY_MASK) +#define MP_IS_READY(_M) !((_M)->Flags & fMP_ADAPTER_NOT_READY_MASK) + +#define MP_HAS_CABLE(_M) !((_M)->Flags & fMP_ADAPTER_NO_CABLE) +#define MP_LINK_DETECTED(_M) !((_M)->Flags & fMP_ADAPTER_LINK_DETECTION) + + + + +/****************************************************************************** + Counters for error rate monitoring + *****************************************************************************/ +typedef struct _MP_ERR_COUNTERS +{ + UINT32 PktCountTxPackets; + UINT32 PktCountTxErrors; + UINT32 TimerBasedTxErrors; + UINT32 PktCountLastError; + UINT32 ErredConsecPackets; +} MP_ERR_COUNTERS, *PMP_ERR_COUNTERS; + + + + +/****************************************************************************** + RFD (Receive Frame Descriptor) + *****************************************************************************/ +typedef struct _MP_RFD +{ + struct list_head list_node; + struct sk_buff *Packet; + UINT32 PacketSize; // total size of receive frame + UINT16 iBufferIndex; + UINT8 iRingIndex; +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) + BOOL_t bHasVLANTag; + UINT16 VLANTag; +#endif +} MP_RFD, *PMP_RFD; + + + + +/****************************************************************************** + Enum for Flow Control + *****************************************************************************/ +typedef enum _eflow_control_t { + Both = 0, + TxOnly = 1, + RxOnly = 2, + None = 3 +} eFLOW_CONTROL_t, *PeFLOW_CONTROL_t; + + + + +/****************************************************************************** + Struct to define some device statistics + *****************************************************************************/ +typedef struct _ce_stats_t +{ + /************************************************************************** + Link Input/Output stats + *************************************************************************/ + UINT64 ipackets; // # of in packets + UINT64 opackets; // # of out packets + + + /************************************************************************** + MIB II variables + *************************************************************************/ + /************************************************************************** + NOTE - atomic_t types are only guaranteed to store 24-bits; if we MUST + have 32, then we'll need another way to perform atomic operations + *************************************************************************/ + UINT32 unircv; // # multicast packets received + atomic_t unixmt; // # multicast packets for Tx + UINT32 multircv; // # multicast packets received + atomic_t multixmt; // # multicast packets for Tx + UINT32 brdcstrcv; // # broadcast packets received + atomic_t brdcstxmt; // # broadcast packets for Tx + UINT32 norcvbuf; // # Rx packets discarded + UINT32 noxmtbuf; // # Tx packets discarded + + + /************************************************************************** + Transciever state informations. + *************************************************************************/ + UINT32 xcvr_addr; + UINT32 xcvr_id; + + + /************************************************************************** + Tx Statistics. + *************************************************************************/ + UINT32 tx_uflo; //Tx Underruns + + UINT32 collisions; + UINT32 excessive_collisions; + UINT32 first_collision; + UINT32 late_collisions; + UINT32 max_pkt_error; + UINT32 tx_deferred; + + + /************************************************************************** + Rx Statistics. + *************************************************************************/ + UINT32 rx_ov_flow; //Rx Over Flow + + UINT32 length_err; + UINT32 alignment_err; + UINT32 crc_err; + UINT32 code_violations; + UINT32 other_errors; + +#ifdef ET131X_DBG + UINT32 UnhandledInterruptsPerSec; + UINT32 RxDmaInterruptsPerSec; + UINT32 TxDmaInterruptsPerSec; + UINT32 WatchDogInterruptsPerSec; +#endif /* ET131X_DBG */ + + UINT32 SynchrounousIterations; + INT_STATUS_t InterruptStatus; +} +CE_STATS_t, *PCE_STATS_t; + + + + +/****************************************************************************** + The private adapter structure + *****************************************************************************/ +typedef struct et131x_adapter +{ + struct net_device *netdev; + struct pci_dev *pdev; + + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) + struct tq_struct task; +#else + struct work_struct task; +#endif + + + /************************************************************************** + Flags that indicate current state of the adapter + *************************************************************************/ + UINT32 Flags; + UINT32 HwErrCount; + + + /************************************************************************** + Configuration + *************************************************************************/ + UCHAR PermanentAddress[ETH_ALEN]; + UCHAR CurrentAddress[ETH_ALEN]; + BOOL_t bOverrideAddress; + BOOL_t bEepromPresent; + UCHAR eepromData[2]; + + + /************************************************************************** + Spinlocks + *************************************************************************/ + spinlock_t Lock; + + spinlock_t TCBSendQLock; + spinlock_t TCBReadyQLock; + spinlock_t SendHWLock; + spinlock_t SendWaitLock; + + spinlock_t RcvLock; + spinlock_t RcvPendLock; + spinlock_t FbrLock; + + spinlock_t PHYLock; + + + /************************************************************************** + Packet Filter and look ahead size + *************************************************************************/ + UINT32 PacketFilter; + UINT32 ulLookAhead; + UINT32 uiLinkSpeed; + UINT32 uiDuplexMode; + UINT32 uiAutoNegStatus; + UCHAR ucLinkStatus; + + + /************************************************************************** + multicast list + *************************************************************************/ + UINT32 MCAddressCount; + UCHAR MCList[NIC_MAX_MCAST_LIST][ETH_ALEN]; + + + /************************************************************************** + MAC test + *************************************************************************/ + TXMAC_TXTEST_t TxMacTest; + + + /************************************************************************** + Pointer to the device's PCI register space + *************************************************************************/ + ADDRESS_MAP_t *CSRAddress; + + + /************************************************************************** + PCI config space info, for debug purposes only. + *************************************************************************/ + UCHAR RevisionID; + UINT16 VendorID; + UINT16 DeviceID; + UINT16 SubVendorID; + UINT16 SubSystemID; + UINT32 CacheFillSize; + UINT16 PciXDevCtl; + UCHAR pci_lat_timer; + UCHAR pci_hdr_type; + UCHAR pci_bist; + UINT32 pci_cfg_state[64 / sizeof(u32)]; + + + /************************************************************************** + Registry parameters + *************************************************************************/ + UCHAR SpeedDuplex; // speed/duplex + eFLOW_CONTROL_t RegistryFlowControl; // for 802.3x flow control + UCHAR RegistryWOLMatch; // Enable WOL pattern-matching + UCHAR RegistryWOLLink; // Link state change is independant + UCHAR RegistryPhyComa; // Phy Coma mode enable/disable + + UINT32 RegistryRxMemEnd; // Size of internal rx memory + UCHAR RegistryMACStat; // If set, read MACSTAT, else don't + UINT32 RegistryVlanTag; // 802.1q Vlan TAG + UINT32 RegistryJumboPacket; // Max supported ethernet packet size + + UINT32 RegistryTxNumBuffers; + UINT32 RegistryTxTimeInterval; + + UINT32 RegistryRxNumBuffers; + UINT32 RegistryRxTimeInterval; + + + /************************************************************************** + Validation helpers + *************************************************************************/ + UCHAR RegistryPMWOL; + UCHAR RegistryNMIDisable; + UINT32 RegistryDMACache; + UINT32 RegistrySCGain; + UCHAR RegistryPhyLoopbk; // Enable Phy loopback + + + /************************************************************************** + Derived from the registry: + *************************************************************************/ + UCHAR AiForceDpx; // duplex setting + UINT16 AiForceSpeed; // 'Speed', user over-ride of line speed + eFLOW_CONTROL_t FlowControl; // flow control validated by the far-end + NETIF_STATUS MediaState; + UCHAR DriverNoPhyAccess; + + + /************************************************************************** + Minimize init-time + *************************************************************************/ + BOOL_t bQueryPending; + BOOL_t bSetPending; + BOOL_t bResetPending; + struct timer_list ErrorTimer; + BOOL_t bLinkTimerActive; + MP_POWER_MGMT PoMgmt; + INT_MASK_t CachedMaskValue; + + atomic_t RcvRefCount; // Num packets not yet returned + + + /************************************************************************** + Xcvr status at last poll + *************************************************************************/ + MI_BMSR_t Bmsr; + + + /************************************************************************** + Tx Memory Variables + *************************************************************************/ + TX_RING_t TxRing; + + + /************************************************************************** + Rx Memory Variables + *************************************************************************/ + RX_RING_t RxRing; + + + /************************************************************************** + ET1310 register Access + *************************************************************************/ + JAGCORE_ACCESS_REGS JagCoreRegs; + PCI_CFG_SPACE_REGS PciCfgRegs; + + + /************************************************************************** + Loopback specifics + *************************************************************************/ + UCHAR ReplicaPhyLoopbk; // Replica Enable + UCHAR ReplicaPhyLoopbkPF; // Replica Enable Pass/Fail + + + /************************************************************************** + Stats + *************************************************************************/ + CE_STATS_t Stats; + + struct net_device_stats net_stats; + struct net_device_stats net_stats_prev; + + + /************************************************************************** + VLAN + *************************************************************************/ +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) + struct vlan_group *vlgrp; +#endif + + /************************************************************************** + Data to support workaround for bad config space addresses; see + et131x_pci_setup() for more information + *************************************************************************/ + BOOL_t pci_bar_workaround; + unsigned long pci_bar_addr_orig; +} ET131X_ADAPTER, *PET131X_ADAPTER; + + + + +#define MPSendPacketsHandler MPSendPackets +#define MP_FREE_SEND_PACKET_FUN(Adapter, pMpTcb) et131x_free_send_packet(Adapter, pMpTcb) +#define MpSendPacketFun(Adapter,Packet) MpSendPacket(Adapter, Packet) + + + + +#endif /* __ET131X_ADAPTER_H__ */ --- linux-2.6.27.orig/ubuntu/et131x/Kconfig +++ linux-2.6.27/ubuntu/et131x/Kconfig @@ -0,0 +1,3 @@ +config NET_ET131X + tristate "Agere Systems 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs" + depends on PCI && NET --- linux-2.6.27.orig/ubuntu/et131x/ET1310_eeprom.h +++ linux-2.6.27/ubuntu/et131x/ET1310_eeprom.h @@ -0,0 +1,127 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * ET1310_eeprom.h - Defines, structs, enums, prototypes, etc. used for EEPROM + * access routines + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/08/01 19:35:10 $ + $Revision: 1.4 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +#ifndef __ET1310_EEPROM_H__ +#define __ET1310_EEPROM_H__ + + + + +/****************************************************************************** + INCLUDES + *****************************************************************************/ +#include "ET1310_common.h" + + +#ifndef SUCCESS + #define SUCCESS 0 + #define FAILURE 1 +#endif + +#ifndef READ + #define READ 0 + #define WRITE 1 +#endif + +#ifndef SINGLE_BYTE + #define SINGLE_BYTE 0 + #define DUAL_BYTE 1 +#endif + + + + +/****************************************************************************** + Forward declaration of the private adapter structure + *****************************************************************************/ +struct et131x_adapter; + + + + +UINT32 EEPROM_access( struct et131x_adapter *pAdapter, UCHAR bAccessFlag, + UINT32 unOffset, UCHAR bWidth, void *pData ); + +INT32 EepromWriteByte( struct et131x_adapter *pAdapter, UINT32 unAddress, + UCHAR bData, UINT32 unEepromId, UINT32 unAddressingMode ); + +INT32 EepromReadByte( struct et131x_adapter *pAdapter, UINT32 unAddress, + PUCHAR pbData, UINT32 unEepromId, UINT32 unAddressingMode ); + + + + +#endif /* _ET1310_EEPROM_H_ */ --- linux-2.6.27.orig/ubuntu/et131x/et131x_netdev.h +++ linux-2.6.27/ubuntu/et131x/et131x_netdev.h @@ -0,0 +1,91 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_netdev.h - Defines, structs, enums, prototypes, etc. related to the + * driver's net_device support. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/08/01 19:35:13 $ + $Revision: 1.3 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +#ifndef __ET131X_NETDEV_H__ +#define __ET131X_NETDEV_H__ + + + + +struct net_device * et131x_device_alloc( void ); + +void et131x_device_free( struct net_device *netdev ); + + + + +#endif /* __ET131X_NETDEV_H__ */ + --- linux-2.6.27.orig/ubuntu/et131x/ET1310_rx.h +++ linux-2.6.27/ubuntu/et131x/ET1310_rx.h @@ -0,0 +1,488 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * ET1310_rx.h - Defines, structs, enums, prototypes, etc. pertaining to data + * reception. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/10/28 18:43:45 $ + $Revision: 1.10 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +#ifndef __ET1310_RX_H__ +#define __ET1310_RX_H__ + + +#ifdef __cplusplus +extern "C" { +#endif + + + + +/****************************************************************************** + INCLUDES + *****************************************************************************/ +#include "ET1310_common.h" + +#define USE_FBR0 TRUE + +#ifdef USE_FBR0 +//#define FBR0_BUFFER_SIZE 256 +#endif + +//#define FBR1_BUFFER_SIZE 2048 + +#define FBR_CHUNKS 32 + +#define MAX_DESC_PER_RING_RX 1024 + + + + +/****************************************************************************** + number of RFDs - default and min + *****************************************************************************/ +#ifdef USE_FBR0 + #define RFD_LOW_WATER_MARK 40 + #define NIC_MIN_NUM_RFD 64 + #define NIC_DEFAULT_NUM_RFD 1024 +#else + #define RFD_LOW_WATER_MARK 20 + #define NIC_MIN_NUM_RFD 64 + #define NIC_DEFAULT_NUM_RFD 256 +#endif + +#define NUM_PACKETS_HANDLED 256 + +#define ALCATEL_BAD_STATUS 0xe47f0000 +#define ALCATEL_MULTICAST_PKT 0x01000000 +#define ALCATEL_BROADCAST_PKT 0x02000000 + + + + +/****************************************************************************** + typedefs for Free Buffer Descriptors + *****************************************************************************/ +typedef union _FBR_WORD2_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved:22; //bits 10-31 + UINT32 bi:10; //bits 0-9(Buffer Index) + #else + UINT32 bi:10; //bits 0-9(Buffer Index) + UINT32 reserved:22; //bit 10-31 + #endif + } bits; +} +FBR_WORD2_t, *PFBR_WORD2_t; + +typedef struct _FBR_DESC_t +{ + UINT32 addr_lo; + UINT32 addr_hi; + FBR_WORD2_t word2; +} +FBR_DESC_t, *PFBR_DESC_t; +/*===========================================================================*/ + + + + +/****************************************************************************** + Typedefs for Packet Status Ring Descriptors + *****************************************************************************/ +typedef union _PKT_STAT_DESC_WORD0_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + // top 16 bits are from the Alcatel Status Word as enumerated in + // PE-MCXMAC Data Sheet IPD DS54 0210-1 (also IPD-DS80 0205-2) +#if 0 + UINT32 asw_trunc:1; //bit 31(Rx frame truncated) +#endif + UINT32 asw_long_evt:1; //bit 31(Rx long event) + UINT32 asw_VLAN_tag:1; //bit 30(VLAN tag detected) + UINT32 asw_unsupported_op:1; //bit 29(unsupported OP code) + UINT32 asw_pause_frame:1; //bit 28(is a pause frame) + UINT32 asw_control_frame:1; //bit 27(is a control frame) + UINT32 asw_dribble_nibble:1; //bit 26(spurious bits after EOP) + UINT32 asw_broadcast:1; //bit 25(has a broadcast address) + UINT32 asw_multicast:1; //bit 24(has a multicast address) + UINT32 asw_OK:1; //bit 23(valid CRC + no code error) + UINT32 asw_too_long:1; //bit 22(frame length > 1518 bytes) + UINT32 asw_len_chk_err:1; //bit 21(frame length field incorrect) + UINT32 asw_CRC_err:1; //bit 20(CRC error) + UINT32 asw_code_err:1; //bit 19(one or more nibbles signalled as errors) + UINT32 asw_false_carrier_event:1; //bit 18(bad carrier since last good packet) + UINT32 asw_RX_DV_event:1; //bit 17(short receive event detected) + UINT32 asw_prev_pkt_dropped:1; //bit 16(e.g. IFG too small on previous) + UINT32 unused:5; //bits 11-15 + UINT32 vp:1; //bit 10(VLAN Packet) + UINT32 jp:1; //bit 9(Jumbo Packet) + UINT32 ft:1; //bit 8(Frame Truncated) + UINT32 drop:1; //bit 7(Drop packet) + UINT32 rxmac_error:1; //bit 6(RXMAC Error Indicator) + UINT32 wol:1; //bit 5(WOL Event) + UINT32 tcpp:1; //bit 4(TCP checksum pass) + UINT32 tcpa:1; //bit 3(TCP checksum assist) + UINT32 ipp:1; //bit 2(IP checksum pass) + UINT32 ipa:1; //bit 1(IP checksum assist) + UINT32 hp:1; //bit 0(hash pass) + #else + UINT32 hp:1; //bit 0(hash pass) + UINT32 ipa:1; //bit 1(IP checksum assist) + UINT32 ipp:1; //bit 2(IP checksum pass) + UINT32 tcpa:1; //bit 3(TCP checksum assist) + UINT32 tcpp:1; //bit 4(TCP checksum pass) + UINT32 wol:1; //bit 5(WOL Event) + UINT32 rxmac_error:1; //bit 6(RXMAC Error Indicator) + UINT32 drop:1; //bit 7(Drop packet) + UINT32 ft:1; //bit 8(Frame Truncated) + UINT32 jp:1; //bit 9(Jumbo Packet) + UINT32 vp:1; //bit 10(VLAN Packet) + UINT32 unused:5; //bits 11-15 + UINT32 asw_prev_pkt_dropped:1; //bit 16(e.g. IFG too small on previous) + UINT32 asw_RX_DV_event:1; //bit 17(short receive event detected) + UINT32 asw_false_carrier_event:1; //bit 18(bad carrier since last good packet) + UINT32 asw_code_err:1; //bit 19(one or more nibbles signalled as errors) + UINT32 asw_CRC_err:1; //bit 20(CRC error) + UINT32 asw_len_chk_err:1; //bit 21(frame length field incorrect) + UINT32 asw_too_long:1; //bit 22(frame length > 1518 bytes) + UINT32 asw_OK:1; //bit 23(valid CRC + no code error) + UINT32 asw_multicast:1; //bit 24(has a multicast address) + UINT32 asw_broadcast:1; //bit 25(has a broadcast address) + UINT32 asw_dribble_nibble:1; //bit 26(spurious bits after EOP) + UINT32 asw_control_frame:1; //bit 27(is a control frame) + UINT32 asw_pause_frame:1; //bit 28(is a pause frame) + UINT32 asw_unsupported_op:1; //bit 29(unsupported OP code) + UINT32 asw_VLAN_tag:1; //bit 30(VLAN tag detected) + UINT32 asw_long_evt:1; //bit 31(Rx long event) +#if 0 + UINT32 asw_trunc:1; //bit 31(Rx frame truncated) +#endif + #endif + } bits; +} +PKT_STAT_DESC_WORD0_t, *PPKT_STAT_WORD0_t; + +typedef union _PKT_STAT_DESC_WORD1_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:4; //bits 28-31 + UINT32 ri:2; //bits 26-27(Ring Index) + UINT32 bi:10; //bits 16-25(Buffer Index) + UINT32 length:16; //bit 0-15(length in bytes) + #else + UINT32 length:16; //bit 0-15(length in bytes) + UINT32 bi:10; //bits 16-25(Buffer Index) + UINT32 ri:2; //bits 26-27(Ring Index) + UINT32 unused:4; //bits 28-31 + #endif + } bits; +} +PKT_STAT_DESC_WORD1_t, *PPKT_STAT_WORD1_t; + +typedef struct _PKT_STAT_DESC_t +{ + PKT_STAT_DESC_WORD0_t word0; + PKT_STAT_DESC_WORD1_t word1; +} +PKT_STAT_DESC_t, *PPKT_STAT_DESC_t; +/*===========================================================================*/ + + + + +/****************************************************************************** + Typedefs for the RX DMA status word + *****************************************************************************/ +/****************************************************************************** + RXSTAT_WORD0_t structure holds part of the status bits of the Rx DMA engine + that get copied out to memory by the ET-1310. Word 0 is a 32 bit word which + contains Free Buffer ring 0 and 1 available offset. + *****************************************************************************/ +typedef union _rxstat_word0_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 FBR1unused:5; //bits 27-31 + UINT32 FBR1wrap:1; //bit 26 + UINT32 FBR1offset:10; //bits 16-25 + UINT32 FBR0unused:5; //bits 11-15 + UINT32 FBR0wrap:1; //bit 10 + UINT32 FBR0offset:10; //bits 0-9 + #else + UINT32 FBR0offset:10; //bits 0-9 + UINT32 FBR0wrap:1; //bit 10 + UINT32 FBR0unused:5; //bits 11-15 + UINT32 FBR1offset:10; //bits 16-25 + UINT32 FBR1wrap:1; //bit 26 + UINT32 FBR1unused:5; //bits 27-31 + #endif + } bits; +}RXSTAT_WORD0_t, *PRXSTAT_WORD0_t; + + + + +/****************************************************************************** + RXSTAT_WORD1_t structure holds part of the status bits of the Rx DMA engine + that get copied out to memory by the ET-1310. Word 3 is a 32 bit word which + contains the Packet Status Ring available offset. + *****************************************************************************/ +typedef union _rxstat_word1_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 PSRunused:3; //bits 29-31 + UINT32 PSRwrap:1; //bit 28 + UINT32 PSRoffset:12; //bits 16-27 + UINT32 reserved:16; //bits 0-15 + #else + UINT32 reserved:16; //bits 0-15 + UINT32 PSRoffset:12; //bits 16-27 + UINT32 PSRwrap:1; //bit 28 + UINT32 PSRunused:3; //bits 29-31 + #endif + } bits; +}RXSTAT_WORD1_t, *PRXSTAT_WORD1_t; + + + + +/****************************************************************************** + RX_STATUS_BLOCK_t is sructure representing the status of the Rx DMA engine + it sits in free memory, and is pointed to by 0x101c / 0x1020 + *****************************************************************************/ + +typedef struct _rx_status_block_t +{ + RXSTAT_WORD0_t Word0; + RXSTAT_WORD1_t Word1; +} +RX_STATUS_BLOCK_t, *PRX_STATUS_BLOCK_t; + + + + +/****************************************************************************** + Structure for look-up table holding free buffer ring pointers + *****************************************************************************/ +typedef struct _FbrLookupTable +{ + void *Va [MAX_DESC_PER_RING_RX]; + void *Buffer1 [MAX_DESC_PER_RING_RX]; + void *Buffer2 [MAX_DESC_PER_RING_RX]; + UINT32 PAHigh [MAX_DESC_PER_RING_RX]; + UINT32 PALow [MAX_DESC_PER_RING_RX]; +} FBRLOOKUPTABLE, *PFBRLOOKUPTABLE; + +typedef enum { + ONE_PACKET_INTERRUPT, + FOUR_PACKET_INTERRUPT +} +eRX_INTERRUPT_STATE_t, *PeRX_INTERRUPT_STATE_t; + + + + +/****************************************************************************** + Structure to hold the skb's in a list + *****************************************************************************/ +typedef struct rx_skb_list_elem +{ + struct list_head skb_list_elem; + dma_addr_t dma_addr; + struct sk_buff *skb; +} RX_SKB_LIST_ELEM, *PRX_SKB_LIST_ELEM; + + + + +/****************************************************************************** + RX_RING_t is sructure representing the adaptor's local reference(s) to the + rings + *****************************************************************************/ +typedef struct _rx_ring_t +{ +#ifdef USE_FBR0 + void *pFbr0RingVa; + dma_addr_t pFbr0RingPa; + void *Fbr0MemVa[ MAX_DESC_PER_RING_RX / FBR_CHUNKS ]; + dma_addr_t Fbr0MemPa[ MAX_DESC_PER_RING_RX / FBR_CHUNKS ]; + UINT64 Fbr0Realpa; + UINT64 Fbr0offset; + RXDMA_FBR_FULL_OFFSET_t local_Fbr0_full; + UINT32 Fbr0NumEntries; + UINT32 Fbr0BufferSize; +#endif + void *pFbr1RingVa; + dma_addr_t pFbr1RingPa; + void *Fbr1MemVa[ MAX_DESC_PER_RING_RX / FBR_CHUNKS ]; + dma_addr_t Fbr1MemPa[ MAX_DESC_PER_RING_RX / FBR_CHUNKS ]; + UINT64 Fbr1Realpa; + UINT64 Fbr1offset; + FBRLOOKUPTABLE *Fbr[2]; + RXDMA_FBR_FULL_OFFSET_t local_Fbr1_full; + UINT32 Fbr1NumEntries; + UINT32 Fbr1BufferSize; + + void *pPSRingVa; + dma_addr_t pPSRingPa; + UINT64 pPSRingRealPa; + UINT64 pPSRingOffset; + RXDMA_PSR_FULL_OFFSET_t local_psr_full; + UINT32 PsrNumEntries; + + void *pRxStatusVa; + dma_addr_t pRxStatusPa; + UINT64 RxStatusRealPA; + UINT64 RxStatusOffset; + + struct list_head RecvBufferPool; + + + /************************************************************************** + RECV + *************************************************************************/ + struct list_head RecvList; + struct list_head RecvPendingList; + UINT32 nReadyRecv; + + UINT32 NumRfd; + + BOOL_t UnfinishedReceives; + + struct list_head RecvPacketPool; + + + /************************************************************************** + lookaside lists + *************************************************************************/ + struct kmem_cache *RecvLookaside; +} +RX_RING_t, *PRX_RING_t; + + + + +/****************************************************************************** + Forward reference of RFD + *****************************************************************************/ +struct _MP_RFD; + + + + +/****************************************************************************** + Forward declaration of the private adapter structure + *****************************************************************************/ +struct et131x_adapter; + + + + +/****************************************************************************** + PROTOTYPES for Initialization + *****************************************************************************/ +int et131x_rx_dma_memory_alloc( struct et131x_adapter *adapter ); +void et131x_rx_dma_memory_free( struct et131x_adapter *adapter ); +int et131x_rfd_resources_alloc( struct et131x_adapter *adapter, struct _MP_RFD *pMpRfd ); +void et131x_rfd_resources_free( struct et131x_adapter *adapter, struct _MP_RFD *pMpRfd ); +int et131x_init_recv( struct et131x_adapter *adapter ); + +void ConfigRxDmaRegs( struct et131x_adapter *pAdapter ); +void SetRxDmaTimer( struct et131x_adapter *pAdapter ); +void et131x_rx_dma_disable( struct et131x_adapter *pAdapter ); +void et131x_rx_dma_enable( struct et131x_adapter *pAdapter ); + +void et131x_reset_recv( struct et131x_adapter *pAdapter ); + +void et131x_handle_recv_interrupt( struct et131x_adapter *pAdapter ); + + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __ET1310_RX_H__ */ --- linux-2.6.27.orig/ubuntu/et131x/et131x_initpci.c +++ linux-2.6.27/ubuntu/et131x/et131x_initpci.c @@ -0,0 +1,1839 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_initpci.c - Routines and data used to register the driver with the + * PCI (and PCI Express) subsystem, as well as basic driver + * init and startup. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2006/01/25 20:48:56 $ + $Revision: 1.22 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +/****************************************************************************** + Includes + *****************************************************************************/ +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include +#include +#include +#include +#include + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) +#include +#endif + +#include "ET1310_phy.h" +#include "ET1310_pm.h" +#include "ET1310_jagcore.h" + +#include "et131x_supp.h" +#include "et131x_adapter.h" +#include "et131x_netdev.h" +#include "et131x_config.h" +#include "et131x_isr.h" + +#include "ET1310_address_map.h" +#include "ET1310_jagcore.h" +#include "ET1310_tx.h" +#include "ET1310_rx.h" +#include "ET1310_mac.h" +#include "ET1310_eeprom.h" + + + + +/****************************************************************************** + Data for debugging facilities + *****************************************************************************/ +#ifdef ET131X_DBG +extern dbg_info_t *et131x_dbginfo; +#endif /* ET131X_DBG */ + + + + +/****************************************************************************** + Prototypes for functions with local scope + *****************************************************************************/ +int __devinit et131x_pci_probe( struct pci_dev *pdev, + const struct pci_device_id *ent ); + +void __devexit et131x_pci_remove( struct pci_dev *pdev ); + +int et131x_pci_setup( struct pci_dev *pdev ); + + + + +/****************************************************************************** + Data for PCI registration + *****************************************************************************/ +enum et131x_pci_versions +{ + Agere_Systems_PCI_V1 = 0, +}; + + +static struct pci_device_id et131x_pci_table[] __devinitdata = +{ + { ET131X_PCI_VENDOR_ID, ET131X_PCI_DEVICE_ID_GIG, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { ET131X_PCI_VENDOR_ID, ET131X_PCI_DEVICE_ID_FAST, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { 0, } +}; + +MODULE_DEVICE_TABLE( pci, et131x_pci_table ); + + +static struct pci_driver et131x_driver = +{ + name: DRIVER_NAME, + id_table: et131x_pci_table, + probe: et131x_pci_probe, + remove: __devexit_p( et131x_pci_remove ), + suspend: NULL, //et131x_pci_suspend, + resume: NULL, //et131x_pci_resume, +}; + + + + +/****************************************************************************** + ROUTINE : et131x_find_adapter + ****************************************************************************** + + DESCRIPTION : Find the adapter and get all the assigned resources + + PARAMETERS : adapter - pointer to our private adapter structure + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_find_adapter( ET131X_ADAPTER *adapter, struct pci_dev *pdev ) +{ + int result; + UCHAR eepromStat = 0; + UCHAR maxPayload = 0; + UCHAR latencyTimers = 0; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_find_adapter" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Allow disabling of Non-Maskable Interrupts in I/O space, to + support validation. + *************************************************************************/ + if( adapter->RegistryNMIDisable ) + { + UCHAR RegisterVal; + + RegisterVal = inb( ET1310_NMI_DISABLE ); + RegisterVal &= 0xf3; + + if( adapter->RegistryNMIDisable == 2 ) + { + RegisterVal |= 0xc; + } + + outb( ET1310_NMI_DISABLE, RegisterVal ); + } + + + /************************************************************************** + We first need to check the EEPROM Status code located at offset 0xB2 + of config space + *************************************************************************/ + + result = pci_slot_information_read( pdev, + ET1310_PCI_EEPROM_STATUS, + &eepromStat, + sizeof( UCHAR )); + /************************************************************************* + THIS IS A WORKAROUND: + * I need to call this function twice to get my card in a + LG M1 Express Dual running. I tried also a msleep before this + function, because I thougth there could be some time condidions + but it didn't work. Call the whole function twice also work. + *************************************************************************/ + result = pci_slot_information_read( pdev, + ET1310_PCI_EEPROM_STATUS, + &eepromStat, + sizeof( UCHAR )); + + if( result != sizeof( UCHAR )) + { + DBG_ERROR( et131x_dbginfo, "Could not read PCI config space for " + "EEPROM Status\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -EIO; + } + + + /************************************************************************** + Determine if the error(s) we care about are present. If they are + present, we need to fail. + *************************************************************************/ + if( eepromStat & 0x4C ) + { + result = pci_slot_information_read( pdev, + PCI_REVISION_ID, + &adapter->RevisionID, + sizeof( UCHAR )); + if( result != sizeof( UCHAR )) + { + DBG_ERROR( et131x_dbginfo, + "Could not read PCI config space for " + "Revision ID\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -EIO; + } + else if( adapter->RevisionID == 0x01 ) + { + INT32 nLoop; + UCHAR ucTemp[4] = {0xFE, 0x13, 0x10, 0xFF}; + + /****************************************************************** + Re-write the first 4 bytes if we have an eeprom present and + the revision id is 1, this fixes the corruption seen with + 1310 B Silicon + *****************************************************************/ + for( nLoop = 0; nLoop < 3; nLoop++ ) + { + EepromWriteByte( adapter, nLoop, ucTemp[nLoop], 0, SINGLE_BYTE ); + } + } + + DBG_ERROR( et131x_dbginfo, "Fatal EEPROM Status Error - 0x%04x\n", + eepromStat ); + + /********************************************************************** + This error could mean that there was an error reading the eeprom + or that the eeprom doesn't exist. We will treat each case the + same and not try to gather additional information that normally + would come from the eeprom, like MAC Address + *********************************************************************/ + adapter->bEepromPresent = FALSE; + + DBG_LEAVE( et131x_dbginfo ); + return -EIO; + } + else + { + DBG_TRACE( et131x_dbginfo, "EEPROM Status Code - 0x%04x\n", eepromStat ); + adapter->bEepromPresent = TRUE; + } + + + /************************************************************************** + Read the EEPROM for information regarding LED behavior. Refer to + ET1310_phy.c, et131x_xcvr_init(), for its use. + *************************************************************************/ + EepromReadByte( adapter, 0x70, &adapter->eepromData [0], 0, SINGLE_BYTE ); + EepromReadByte( adapter, 0x71, &adapter->eepromData [1], 0, SINGLE_BYTE ); + + if( adapter->eepromData[0] != 0xcd ) + { + adapter->eepromData[1] = 0x00; // Disable all optional features + } + + + /************************************************************************** + Let's set up the PORT LOGIC Register. First we need to know what the + max_payload_size is + *************************************************************************/ + result = pci_slot_information_read( pdev, + ET1310_PCI_MAX_PYLD, + &maxPayload, + sizeof( UCHAR )); + + if( result != sizeof( UCHAR )) + { + DBG_ERROR( et131x_dbginfo, "Could not read PCI config space for " + "Max Payload Size\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -EIO; + } + else + { + UINT16 AckNak [2] = {0x76, 0xD0}; + UINT16 Replay [2] = {0x1E0, 0x2ED}; + + + /********************************************************************** + Program the Ack/Nak latency and replay timers + *********************************************************************/ + maxPayload &= 0x07; // Only the lower 3 bits are valid + + if( maxPayload < 2 ) + { + result = pci_slot_information_write( pdev, + ET1310_PCI_ACK_NACK, + (UINT8 *)&AckNak[maxPayload], + sizeof( UINT16 )); + if( result != sizeof( UINT16 )) + { + DBG_ERROR( et131x_dbginfo, "Could not write PCI config space " + "for ACK/NAK\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -EIO; + } + + result = pci_slot_information_write( pdev, + ET1310_PCI_REPLAY, + (UINT8 *)&Replay[maxPayload], + sizeof( UINT16 )); + if( result != sizeof( UINT16 )) + { + DBG_ERROR( et131x_dbginfo, "Could not write PCI config space " + "for Replay Timer\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -EIO; + } + } + } + + + /************************************************************************** + l0s and l1 latency timers. We are using default values. + *************************************************************************/ + latencyTimers = 0x11; // Representing 001 for L0s and 010 for L1 + + result = pci_slot_information_write( pdev, + ET1310_PCI_L0L1LATENCY, + (UINT8 *)&latencyTimers, + sizeof( UCHAR )); + if( result != sizeof( UCHAR )) + { + DBG_ERROR( et131x_dbginfo, "Could not write PCI config space for " + "Latency Timers\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -EIO; + } + + + /************************************************************************** + Archive Power management capability values for later use + *************************************************************************/ + result = pci_slot_information_read( pdev, + ET1310_PCI_PM_CAPABILITY, + (UINT8 *)&adapter->PoMgmt.pmConfigRegs, + sizeof( MP_PM_CONFIG_SPACE_INFO_t )); + if( result != sizeof( MP_PM_CONFIG_SPACE_INFO_t )) + { + DBG_ERROR( et131x_dbginfo, + "Could not read PCI config space for PM Capability\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -EIO; + } + else + { + UCHAR read_size_reg; + + /****************************************************************** + Change the max read size to 2k + *****************************************************************/ + result = pci_slot_information_read( pdev, + 0x51, + (void *)&read_size_reg, + sizeof( UCHAR )); + + if( result != sizeof( UCHAR )) + { + DBG_ERROR( et131x_dbginfo, + "Could not read PCI config space for Max read size\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -EIO; + } + + read_size_reg &= 0x8f; + read_size_reg |= 0x40; + + result = pci_slot_information_write( pdev, + 0x51, + &read_size_reg, + sizeof( UCHAR )); + if( result != sizeof( UCHAR )) + { + DBG_ERROR( et131x_dbginfo, + "Could not write PCI config space for Max read size\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -EIO; + } + } + + + /************************************************************************** + PCI Express Configuration registers 0x48-0x5B (Device Control) + *************************************************************************/ + result = pci_slot_information_read( pdev, + ET1310_PCI_DEV_CTRL, + (UINT8 *)&adapter->PciXDevCtl, + sizeof( UINT16 )); + + if( result != sizeof( UINT16 )) + { + DBG_ERROR( et131x_dbginfo, + "Could not read PCI config space for PCI Express Dev Ctl\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -EIO; + } + + + /************************************************************************** + Get MAC address from config space if an eeprom exists, otherwise the + MAC address there will not be valid + *************************************************************************/ + if( adapter->bEepromPresent ) + { + result = pci_slot_information_read( pdev, + ET1310_PCI_MAC_ADDRESS, + (UINT8 *)adapter->PermanentAddress, + ETH_ALEN ); + if( result != ETH_ALEN ) + { + DBG_ERROR( et131x_dbginfo, + "Could not read PCI config space for MAC address\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -EIO; + } + } + + + DBG_LEAVE( et131x_dbginfo ); + return 0; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_error_timer_handler + ****************************************************************************** + + DESCRIPTION : The routine called when the error timer expires, to + track the number of recurring errors. + + PARAMETERS : data - a timer-specific variable; in this case, a + pointer to our private adapter structure + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_error_timer_handler( unsigned long data ) +{ + ET131X_ADAPTER *pAdapter = (ET131X_ADAPTER *)data; + PM_CSR_t pm_csr; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_error_timer_handler" ); + + + pm_csr = pAdapter->CSRAddress->global.pm_csr; + + if( pm_csr.bits.pm_phy_sw_coma == 0 ) + { + if( pAdapter->RegistryMACStat ) + { + UpdateMacStatHostCounters( pAdapter ); + } + } + else + { + DBG_VERBOSE( et131x_dbginfo, + "No interrupts, in PHY coma, pm_csr = 0x%x\n", + pm_csr.value ); + } + + + if( !pAdapter->Bmsr.bits.link_status && + pAdapter->RegistryPhyComa && + pAdapter->PoMgmt.TransPhyComaModeOnBoot < 11 ) + { + pAdapter->PoMgmt.TransPhyComaModeOnBoot++; + } + + if( pAdapter->PoMgmt.TransPhyComaModeOnBoot == 10 ) + { + if( !pAdapter->Bmsr.bits.link_status && pAdapter->RegistryPhyComa ) + { + if( pAdapter->CSRAddress->global.pm_csr.bits.phy_sw_coma == 0 ) + { + // NOTE - This was originally a 'sync with interrupt'. How + // to do that under Linux? + et131x_enable_interrupts( pAdapter ); + EnablePhyComa( pAdapter ); + } + } + } + + + /************************************************************************** + This is a periodic timer, so reschedule + *************************************************************************/ + add_timer( &pAdapter->ErrorTimer ); + + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: et131x_link_detection_handler + ****************************************************************************** + DESCRIPTION: + Timer function for handling link up at driver load time + + PARAMETERS : + SystemSpecific1 Not used + FunctionContext Pointer to our adapter + SystemSpecific2 Not used + SystemSpecific3 Not used + + RETURNS : + NONE + + *****************************************************************************/ +void et131x_link_detection_handler( unsigned long data ) +{ + ET131X_ADAPTER *pAdapter = (ET131X_ADAPTER *)data; + unsigned long lockflags; + /*-----------------------------------------------------------------------*/ + + + /************************************************************************** + Let everyone know that we have run + *************************************************************************/ + pAdapter->bLinkTimerActive = FALSE; + + if( pAdapter->MediaState == 0 ) + { + spin_lock_irqsave( &pAdapter->Lock, lockflags ); + + pAdapter->MediaState = NETIF_STATUS_MEDIA_DISCONNECT; + MP_CLEAR_FLAG( pAdapter, fMP_ADAPTER_LINK_DETECTION ); + + spin_unlock_irqrestore( &pAdapter->Lock, lockflags ); + + netif_indicate_status( pAdapter->netdev, pAdapter->MediaState ); + + if( pAdapter->bSetPending ) + { + pAdapter->bSetPending = FALSE; + } + } + + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_adapter_setup + ****************************************************************************** + + DESCRIPTION : Used to set the adapter up as per cassini+ documentation + + PARAMETERS : adapter - pointer to our private adapter structure + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_adapter_setup( ET131X_ADAPTER *pAdapter ) +{ + int status = 0; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_adapter_setup" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Configure the JAGCore + *************************************************************************/ + ConfigGlobalRegs( pAdapter ); + + ConfigMACRegs1( pAdapter ); + ConfigMMCRegs( pAdapter ); + + ConfigRxMacRegs( pAdapter ); + ConfigTxMacRegs( pAdapter ); + + ConfigRxDmaRegs( pAdapter ); + ConfigTxDmaRegs( pAdapter ); + + ConfigMacStatRegs( pAdapter ); + + + /************************************************************************** + Move the following code to Timer function?? + *************************************************************************/ + status = et131x_xcvr_find( pAdapter ); + + if( status != 0 ) + { + DBG_WARNING( et131x_dbginfo, "Could not find the xcvr\n" ); + } + + + /********************************************************************** + Prepare the TRUEPHY library. + *********************************************************************/ + ET1310_PhyInit( pAdapter ); + + + /************************************************************************** + Reset the phy now so changes take place + *************************************************************************/ + ET1310_PhyReset( pAdapter ); + + + /************************************************************************** + Power down PHY + *************************************************************************/ + ET1310_PhyPowerDown( pAdapter, 1 ); + + + /************************************************************************** + We need to turn off 1000 base half dulplex, the mac does not + support it + For the 10/100 part, turn off all gig advertisement + *************************************************************************/ + if( pAdapter->DeviceID != ET131X_PCI_DEVICE_ID_FAST ) + { + ET1310_PhyAdvertise1000BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_FULL ); + } + else + { + ET1310_PhyAdvertise1000BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_NONE ); + } + + + /************************************************************************** + Power up PHY + *************************************************************************/ + ET1310_PhyPowerDown( pAdapter, 0 ); + + et131x_setphy_normal( pAdapter ); + + + DBG_LEAVE( et131x_dbginfo ); + return status; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_setup_hardware_properties + ****************************************************************************** + + DESCRIPTION : Used to set up the MAC Address on the ET1310 + + PARAMETERS : adapter - pointer to our private adapter structure + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_setup_hardware_properties( ET131X_ADAPTER *adapter ) +{ + DBG_FUNC( "et131x_setup_hardware_properties" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + If have our default mac from registry and no mac address from EEPROM + then we need to generate the last octet and set it on the device + *************************************************************************/ + if( !adapter->bOverrideAddress ) + { + if (adapter->PermanentAddress[0] == 0x00 && + adapter->PermanentAddress[1] == 0x00 && + adapter->PermanentAddress[2] == 0x00 && + adapter->PermanentAddress[3] == 0x00 && + adapter->PermanentAddress[4] == 0x00 && + adapter->PermanentAddress[5] == 0x00 ) + { + /****************************************************************** + We need to randomly generate the last octet so we decrease our + chances of setting the mac address to same as another one of + our cards in the system + *****************************************************************/ + get_random_bytes( &adapter->CurrentAddress[5], 1 ); + + + /****************************************************************** + We have the default value in the register we are working with + so we need to copy the current address into the permanent + address + *****************************************************************/ + memcpy( adapter->PermanentAddress, + adapter->CurrentAddress, + ETH_ALEN ); + } + else + { + /****************************************************************** + We do not have an override address, so set the current address + to the permanent address and add it to the device + *****************************************************************/ + memcpy( adapter->CurrentAddress, + adapter->PermanentAddress, + ETH_ALEN ); + } + } + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_soft_reset + ****************************************************************************** + + DESCRIPTION : Issue a soft reset to the hardware, complete for ET1310. + + PARAMETERS : adapter - pointer to our private adapter structure + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_soft_reset( ET131X_ADAPTER *adapter ) +{ + DBG_FUNC( "et131x_soft_reset" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Disable MAC Core + *************************************************************************/ + adapter->CSRAddress->mac.cfg1.value = 0xc00f0000; + + + /************************************************************************** + Set everything to a reset value + *************************************************************************/ + adapter->CSRAddress->global.sw_reset.value = 0x7F; + adapter->CSRAddress->mac.cfg1.value = 0x000f0000; + adapter->CSRAddress->mac.cfg1.value = 0x00000000; + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_align_allocated_memory + ****************************************************************************** + + DESCRIPTION : Align an allocated block of memory on a given boundary + + PARAMETERS : adapter - pointer to our adapter structure + phys_addr - pointer to Physical address + offset - pointer to the offset variable + mask - correct mask + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_align_allocated_memory( ET131X_ADAPTER *adapter, + UINT64 *phys_addr, + UINT64 *offset, + UINT64 mask ) +{ + UINT64 new_addr; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_align_allocated_memory" ); + DBG_ENTER( et131x_dbginfo ); + + + *offset = 0; + + new_addr = *phys_addr & ~mask; + + if( new_addr != *phys_addr ) + { + new_addr += mask+1; // Move to next aligned block + *offset = new_addr - *phys_addr; // Return offset for adjusting virt addr + *phys_addr = new_addr; // Return new physical address + } + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_adapter_memory_alloc + ****************************************************************************** + + DESCRIPTION : Allocate all the memory blocks for send, receive and + others. + + PARAMETERS : adapter - pointer to our private adapter structure + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_adapter_memory_alloc( ET131X_ADAPTER *adapter ) +{ + int status = 0; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_adapter_memory_alloc" ); + DBG_ENTER( et131x_dbginfo ); + + do + { + /********************************************************************** + Allocate memory for the Tx Ring + *********************************************************************/ + status = et131x_tx_dma_memory_alloc( adapter ); + if( status != 0 ) + { + DBG_ERROR( et131x_dbginfo, "et131x_tx_dma_memory_alloc FAILED\n" ); + break; + } + + + /********************************************************************** + Receive buffer memory allocation + *********************************************************************/ + status = et131x_rx_dma_memory_alloc( adapter ); + if( status != 0 ) + { + DBG_ERROR( et131x_dbginfo, "et131x_rx_dma_memory_alloc FAILED\n" ); + et131x_tx_dma_memory_free( adapter ); + break; + } + + + /********************************************************************** + Init receive data structures + *********************************************************************/ + status = et131x_init_recv( adapter ); + if( status != 0 ) + { + DBG_ERROR( et131x_dbginfo, "et131x_init_recv FAILED\n" ); + et131x_tx_dma_memory_free( adapter ); + et131x_rx_dma_memory_free( adapter ); + break; + } + } while( 0 ); + + + DBG_LEAVE( et131x_dbginfo ); + return status; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_adapter_memory_free + ****************************************************************************** + + DESCRIPTION : Free all memory allocated for use by Tx & Rx code + + PARAMETERS : adapter - pointer to our private adapter structure + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_adapter_memory_free( ET131X_ADAPTER *adapter ) +{ + DBG_FUNC( "et131x_adapter_memory_free" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Free DMA memory + *************************************************************************/ + et131x_tx_dma_memory_free( adapter ); + et131x_rx_dma_memory_free( adapter ); + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_pci_register + ****************************************************************************** + + DESCRIPTION : This function uses the above data to regsiter the PCI + function table and PCI Vendor/Product ID(s) with the PCI + subsystem to match corresponding devices to this driver. + + PARAMETERS : N/A + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_pci_register( void ) +{ + int result; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_pci_register" ); + DBG_ENTER( et131x_dbginfo ); + + + result = pci_register_driver( &et131x_driver ); + DBG_TRACE( et131x_dbginfo, + " pci_register_driver( ) returns %d \n", + result ); + + + DBG_LEAVE( et131x_dbginfo ); + return result; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_pci_cleanup + ****************************************************************************** + + DESCRIPTION : This function deregisters the PCI function table and + related PCI Vendor/Product ID(s) with the PCI subsytem. + + PARAMETERS : N/A + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_pci_unregister( void ) +{ + DBG_FUNC( "et131x_pci_unregister" ); + DBG_ENTER( et131x_dbginfo ); + + + pci_unregister_driver( &et131x_driver ); + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_pci_probe + ****************************************************************************** + + DESCRIPTION : Registered in the pci_driver structure, this function is + called when the PCI subsystem finds a new PCI device + which matches the information contained in the + pci_device_id table. This routine is the equivalent to + a device insertion routine. + + PARAMETERS : pdev - a pointer to the device's pci_dev structure + ent - this device's entry in the pci_device_id table + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int __devinit et131x_pci_probe( struct pci_dev *pdev, + const struct pci_device_id *ent ) +{ + int result; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_pci_probe" ); + DBG_ENTER( et131x_dbginfo ); + + + result = et131x_pci_setup( pdev ); + + + DBG_LEAVE( et131x_dbginfo ); + return 0; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_pci_remove + ****************************************************************************** + + DESCRIPTION : Registered in the pci_driver structure, this function is + called when the PCI subsystem detects that a PCI device + which matches the information contained in the + pci_device_id table has been removed. + + PARAMETERS : pdev - a pointer to the device's pci_dev structure + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void __devexit et131x_pci_remove( struct pci_dev *pdev ) +{ + struct net_device *netdev = NULL; + ET131X_ADAPTER *adapter = NULL; + BOOL_t bar_workaround; + unsigned long bar_addr_orig = 0; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_pci_remove" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Make sure the pci_dev pointer is valid + *************************************************************************/ + if( pdev == NULL ) + { + DBG_ERROR( et131x_dbginfo, + "PCI subsys passed in an invalid pci_dev pointer\n" ); + DBG_LEAVE( et131x_dbginfo ); + return; + } + + + /************************************************************************** + Retrieve the net_device pointer from the pci_dev struct, as well as the + private adapter struct + *************************************************************************/ + netdev = (struct net_device *)pci_get_drvdata( pdev ); + if( netdev == NULL ) + { + DBG_ERROR( et131x_dbginfo, + "Could not retrieve net_device struct\n" ); + DBG_LEAVE( et131x_dbginfo ); + return; + } + + adapter = netdev_priv( netdev ); + if( adapter == NULL ) + { + DBG_ERROR( et131x_dbginfo, + "Could not retrieve private adapter struct\n" ); + DBG_LEAVE( et131x_dbginfo ); + return; + } + + + /************************************************************************** + Retrieve config space workaround info before deleting the private + adapter struct + *************************************************************************/ + bar_workaround = adapter->pci_bar_workaround; + bar_addr_orig = adapter->pci_bar_addr_orig; + + + /************************************************************************** + Perform device cleanup + *************************************************************************/ + unregister_netdev( netdev ); + et131x_adapter_memory_free( adapter ); + iounmap( (void *)adapter->CSRAddress ); + et131x_device_free( netdev ); + + if( bar_workaround == FALSE ) + { + pci_release_regions( pdev ); + } + else + { + pdev->resource[0].start = bar_addr_orig; + } + + pci_disable_device( pdev ); + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_pci_setup + ****************************************************************************** + + DESCRIPTION : Called by et131x_pci_probe() to perform device + initialization. + + PARAMETERS : pdev - a pointer to the device's pci_dev structure + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_pci_setup( struct pci_dev *pdev ) +{ + int result = 0; + int pm_cap; + BOOL_t pci_using_dac; + unsigned long et131x_reg_base; + unsigned long et131x_reg_len; + struct net_device *netdev = NULL; + ET131X_ADAPTER *adapter = NULL; + BOOL_t bar_workaround = FALSE; + unsigned long bar_addr_orig = 0; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_pci_setup" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Make sure the device pointer is valid + *************************************************************************/ + if( pdev == NULL ) + { + DBG_ERROR( et131x_dbginfo, + "PCI subsys passed in an invalid pci_dev pointer\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -ENODEV; + } + + + /************************************************************************** + On some systems, the base address for a PCI device's config space which + is stored in the pci_dev structure is incorrect and different from + what's actually in the config space. If they're different, workaround + the issue by correcting the address. + *************************************************************************/ + pci_read_config_dword( pdev, PCI_BASE_ADDRESS_0, (u32 *)&et131x_reg_base ); + et131x_reg_base &= ~0x07; + + if( (u32)pdev->resource[0].start != (u32)et131x_reg_base ) + { + DBG_WARNING( et131x_dbginfo, "PCI CONFIG SPACE WORKAROUND REQUIRED\n" ); + DBG_WARNING( et131x_dbginfo, "pdev->resource[0].start : 0x%08x\n", + (unsigned int)pdev->resource[0].start ); + DBG_WARNING( et131x_dbginfo, "et131x_reg_base : 0x%08x\n", + (unsigned int)et131x_reg_base ); + bar_workaround = TRUE; + bar_addr_orig = pdev->resource[0].start; + pdev->resource[0].start = et131x_reg_base; + } + + + /************************************************************************** + Enable the device via the PCI subsystem + *************************************************************************/ + result = pci_enable_device( pdev ); + if( result != 0 ) + { + if( bar_workaround ) + { + pdev->resource[0].start = bar_addr_orig; + } + + DBG_ERROR( et131x_dbginfo, "pci_enable_device() failed\n" ); + DBG_LEAVE( et131x_dbginfo ); + return result; + } + + + /************************************************************************** + Perform some basic PCI checks + *************************************************************************/ + if( !( pci_resource_flags( pdev, 0 ) & IORESOURCE_MEM )) + { + if( bar_workaround ) + { + pdev->resource[0].start = bar_addr_orig; + } + + DBG_ERROR( et131x_dbginfo, + "Can't find PCI device's base address\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -ENODEV; + } + + if( bar_workaround == FALSE ) + { + result = pci_request_regions( pdev, DRIVER_NAME ); + if( result != 0 ) + { + DBG_ERROR( et131x_dbginfo, + "Can't get PCI resources\n" ); + + pci_disable_device( pdev ); + + DBG_LEAVE( et131x_dbginfo ); + return result; + } + } + + + /************************************************************************** + Enable PCI bus mastering + *************************************************************************/ + DBG_TRACE( et131x_dbginfo, "Setting PCI Bus Mastering...\n" ); + pci_set_master( pdev ); + + + /************************************************************************** + Query PCI for Power Mgmt Capabilities + + NOTE: Now reading PowerMgmt in another location; is this still needed? + *************************************************************************/ + pm_cap = pci_find_capability( pdev, PCI_CAP_ID_PM ); + if( pm_cap == 0 ) + { + DBG_ERROR( et131x_dbginfo, + "Cannot find Power Management capabilities\n" ); + + if( bar_workaround == FALSE ) + { + pci_release_regions( pdev ); + } + else + { + pdev->resource[0].start = bar_addr_orig; + } + + pci_disable_device( pdev ); + + DBG_LEAVE( et131x_dbginfo ); + return -EIO; + } + + + /************************************************************************** + Check the DMA addressing support of this device + *************************************************************************/ + if( !pci_set_dma_mask( pdev, 0xffffffffffffffffULL )) + { + DBG_TRACE( et131x_dbginfo, + "64-bit DMA addressing supported\n" ); + pci_using_dac = TRUE; + +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION( 2,6,0 )) + result = pci_set_consistent_dma_mask( pdev, 0xffffffffffffffffULL ); + if( result != 0 ) + { + DBG_ERROR( et131x_dbginfo, + "Unable to obtain 64 bit DMA for consistent allocations\n" ); + if( bar_workaround == FALSE ) + { + pci_release_regions( pdev ); + } + else + { + pdev->resource[0].start = bar_addr_orig; + } + + pci_disable_device( pdev ); + + DBG_LEAVE( et131x_dbginfo ); + return -EIO; + } +#endif + } + else if( !pci_set_dma_mask( pdev, 0xffffffffULL )) + { + DBG_TRACE( et131x_dbginfo, + "64-bit DMA addressing NOT supported\n" ); + DBG_TRACE( et131x_dbginfo, + "32-bit DMA addressing will be used\n" ); + pci_using_dac = FALSE; + } + else + { + DBG_ERROR( et131x_dbginfo, "No usable DMA addressing method\n" ); + + if( bar_workaround == FALSE ) + { + pci_release_regions( pdev ); + } + else + { + pdev->resource[0].start = bar_addr_orig; + } + + pci_disable_device( pdev ); + + DBG_LEAVE( et131x_dbginfo ); + return -EIO; + } + + + /************************************************************************** + Allocate netdev and private adapter structs + *************************************************************************/ + DBG_TRACE( et131x_dbginfo, "Allocate netdev and private adapter structs...\n" ); + netdev = et131x_device_alloc( ); + + if( netdev == NULL ) + { + DBG_ERROR( et131x_dbginfo, "Couldn't alloc netdev struct\n" ); + + if( bar_workaround == FALSE ) + { + pci_release_regions( pdev ); + } + else + { + pdev->resource[0].start = bar_addr_orig; + } + + pci_disable_device( pdev ); + + DBG_LEAVE( et131x_dbginfo ); + return -ENOMEM; + } + + + /************************************************************************** + Setup the fundamental net_device and private adapter structure elements + *************************************************************************/ + DBG_TRACE( et131x_dbginfo, "Setting fundamental net_device info...\n" ); + + #if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) + SET_MODULE_OWNER( netdev ); + #endif + #if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20)) + SET_NETDEV_DEV( netdev, &pdev->dev ); + #endif + if( pci_using_dac ) + { + //netdev->features |= NETIF_F_HIGHDMA; + } + + + /************************************************************************** + NOTE - Turn this on when we're ready to deal with SG-DMA + + NOTE: According to "Linux Device Drivers", 3rd ed, Rubini et al, if + checksumming is not performed in HW, then the kernel will not use SG. + From pp 510-511: + + "Note that the kernel does not perform scatter/gather I/O to your device + if it does not also provide some form of checksumming as well. The + reason is that, if the kernel has to make a pass over a fragmented + ("nonlinear") packet to calculate the checksum, it might as well copy + the data and coalesce the packet at the same time." + + This has been verified by setting the flags below and still not + receiving a scattered buffer from the network stack, so leave it off + until checksums are calculated in HW. + *************************************************************************/ + //netdev->features |= NETIF_F_SG; + //netdev->features |= NETIF_F_NO_CSUM; + +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION( 2,6,0 )) + //netdev->features |= NETIF_F_LLTX; +#endif + +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) + /************************************************************************** + The ET1310 does not perform VLAN tagging in hardware, so these flags are + not set. + *************************************************************************/ + /* + netdev->features |= NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_RX | + NETIF_F_HW_VLAN_FILTER; + */ +#endif + + /************************************************************************** + Allocate private adapter struct and copy in relevant information + *************************************************************************/ + adapter = netdev_priv( netdev ); + adapter->pdev = pdev; + adapter->netdev = netdev; + adapter->VendorID = pdev->vendor; + adapter->DeviceID = pdev->device; + + adapter->pci_bar_workaround = bar_workaround; + adapter->pci_bar_addr_orig = bar_addr_orig; + + + /************************************************************************** + Do the same for the netdev struct + *************************************************************************/ + netdev->irq = pdev->irq; + netdev->base_addr = pdev->resource[0].start; + + + /************************************************************************** + Initialize spinlocks here + *************************************************************************/ + DBG_TRACE( et131x_dbginfo, "Initialize spinlocks...\n" ); + + spin_lock_init( &adapter->Lock ); + spin_lock_init( &adapter->TCBSendQLock ); + spin_lock_init( &adapter->TCBReadyQLock ); + spin_lock_init( &adapter->SendHWLock ); + spin_lock_init( &adapter->SendWaitLock ); + spin_lock_init( &adapter->RcvLock ); + spin_lock_init( &adapter->RcvPendLock ); + spin_lock_init( &adapter->FbrLock ); + spin_lock_init( &adapter->PHYLock ); + + + /************************************************************************** + Parse configuration parameters into the private adapter struct + *************************************************************************/ + et131x_config_parse( adapter ); + + + /************************************************************************** + Find the physical adapter + + NOTE: This is the equivalent of the MpFindAdapter() routine; can we + lump it's init with the device specific init below into a single + init function? + *************************************************************************/ + //while(et131x_find_adapter( adapter, pdev ) != 0); + et131x_find_adapter( adapter, pdev ); + + /************************************************************************** + Map the bus-relative registers to system virtual memory + *************************************************************************/ + DBG_TRACE( et131x_dbginfo, "Mapping bus-relative registers to virtual memory...\n" ); + + if( bar_workaround == FALSE ) + { + et131x_reg_base = pci_resource_start( pdev, 0 ); + et131x_reg_len = pci_resource_len( pdev, 0 ); + } + else + { + et131x_reg_len = 0x00200000; + } + + adapter->CSRAddress = (ADDRESS_MAP_t *)ioremap_nocache( et131x_reg_base, + et131x_reg_len ); + if( adapter->CSRAddress == NULL ) + { + DBG_ERROR( et131x_dbginfo, "Cannot map device registers\n" ); + + et131x_device_free( netdev ); + + if( bar_workaround == FALSE ) + { + pci_release_regions( pdev ); + } + else + { + pdev->resource[0].start = bar_addr_orig; + } + + pci_disable_device( pdev ); + + DBG_LEAVE( et131x_dbginfo ); + return -ENOMEM; + } + + + /************************************************************************** + Perform device-specific initialization here (See code below) + *************************************************************************/ + + /************************************************************************** + If Phy COMA mode was enabled when we went down, disable it here. + *************************************************************************/ + { + PM_CSR_t GlobalPmCSR = {0}; + + GlobalPmCSR.bits.pm_sysclk_gate = 1; + GlobalPmCSR.bits.pm_txclk_gate = 1; + GlobalPmCSR.bits.pm_rxclk_gate = 1; + + adapter->CSRAddress->global.pm_csr = GlobalPmCSR; + } + + + /************************************************************************** + Issue a global reset to the et1310 + *************************************************************************/ + DBG_TRACE( et131x_dbginfo, "Issuing soft reset...\n" ); + et131x_soft_reset( adapter ); + + + /************************************************************************** + Disable all interrupts (paranoid) + *************************************************************************/ + DBG_TRACE( et131x_dbginfo, "Disable device interrupts...\n" ); + et131x_disable_interrupts( adapter ); + + + /************************************************************************** + Allocate DMA memory + *************************************************************************/ + result = et131x_adapter_memory_alloc( adapter ); + if( result != 0 ) + { + DBG_ERROR( et131x_dbginfo, + "Could not alloc adapater memory (DMA)\n" ); + + iounmap( (void *)adapter->CSRAddress ); + + et131x_device_free( netdev ); + + if( bar_workaround == FALSE ) + { + pci_release_regions( pdev ); + } + else + { + pdev->resource[0].start = bar_addr_orig; + } + + pci_disable_device( pdev ); + + DBG_LEAVE( et131x_dbginfo ); + return -ENOMEM; + } + + + /************************************************************************** + Init send data structures + *************************************************************************/ + DBG_TRACE( et131x_dbginfo, "Init send data structures...\n" ); + et131x_init_send( adapter ); + + adapter->PoMgmt.PowerState = NdisDeviceStateD0; + + + /************************************************************************** + Register the interrupt + + NOTE - This is being done in the open routine, where most other Linux + drivers setup IRQ handlers. Make sure device interrupts are not + turned on before the IRQ is registered!!!! + + What we will do here is setup the task structure for the ISR's + deferred handler + *************************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) + adapter->task.routine = (void (*)(void *))et131x_isr_handler; + adapter->task.data = adapter; +#else + INIT_WORK( &adapter->task, et131x_isr_handler ); +#endif + + + /************************************************************************** + Determine MAC Address, and copy into the net_device struct + *************************************************************************/ + DBG_TRACE( et131x_dbginfo, "Retrieve MAC address...\n" ); + et131x_setup_hardware_properties( adapter ); + + memcpy( netdev->dev_addr, adapter->CurrentAddress, ETH_ALEN ); + + + /************************************************************************** + Setup up our lookup table for CRC Calculations + *************************************************************************/ + DBG_TRACE( et131x_dbginfo, "Setup CRC lookup table...\n" ); + et131x_init_enet_crc_calc( ); + + + /************************************************************************** + Setup et1310 as per the documentation + *************************************************************************/ + DBG_TRACE( et131x_dbginfo, "Setup the adapter...\n" ); + et131x_adapter_setup( adapter ); + + + /************************************************************************** + Create a timer to count errors received by the NIC + *************************************************************************/ + init_timer( &adapter->ErrorTimer ); + + adapter->ErrorTimer.expires = jiffies + TX_ERROR_PERIOD * HZ / 1000; + adapter->ErrorTimer.function = et131x_error_timer_handler; + adapter->ErrorTimer.data = (unsigned long)adapter; + + + /************************************************************************** + Initialize link state + *************************************************************************/ + et131x_link_detection_handler( (unsigned long)adapter ); + + + /************************************************************************** + Intialize variable for counting how long we do not have link status + *************************************************************************/ + adapter->PoMgmt.TransPhyComaModeOnBoot = 0; + + + /************************************************************************** + We can enable interrupts now + + NOTE - Because registration of interrupt handler is done in the device's + open(), defer enabling device interrupts to that point + *************************************************************************/ + + + /************************************************************************** + Register the net_device struct with the Linux network layer + *************************************************************************/ + DBG_TRACE( et131x_dbginfo, "Registering net_device...\n" ); + + + if(( result = register_netdev( netdev )) != 0 ) + { + DBG_ERROR( et131x_dbginfo, "register_netdev() failed\n" ); + + et131x_adapter_memory_free( adapter ); + + iounmap( (void *)adapter->CSRAddress ); + + et131x_device_free( netdev ); + + if( bar_workaround == FALSE ) + { + pci_release_regions( pdev ); + } + else + { + pdev->resource[0].start = bar_addr_orig; + } + + pci_disable_device( pdev ); + + DBG_LEAVE( et131x_dbginfo ); + return result; + } + + + /************************************************************************** + Register the net_device struct with the PCI subsystem. Save a copy + of the PCI config space for this device now that the device has been + initialized, just in case it needs to be quickly restored. + *************************************************************************/ + pci_set_drvdata( pdev, netdev ); + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,10 )) + pci_save_state( adapter->pdev, adapter->pci_cfg_state); +#else + pci_save_state( adapter->pdev ); +#endif + + + /************************************************************************** + Print out some information about this device + *************************************************************************/ + DBG_TRACE( et131x_dbginfo, + "DEVICE FOUND\n" ); + DBG_TRACE( et131x_dbginfo, + "------------------------------\n" ); + DBG_TRACE( et131x_dbginfo, + "Device Vendor ID : 0x%04x\n", + pdev->vendor ); + DBG_TRACE( et131x_dbginfo, + "Device Product ID : 0x%04x\n", + pdev->device ); + DBG_TRACE( et131x_dbginfo, + "Device SubVendor ID : 0x%04x\n", + pdev->subsystem_vendor ); + DBG_TRACE( et131x_dbginfo, + "Device SubProduct ID : 0x%04x\n", + pdev->subsystem_device ); + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) + DBG_TRACE( et131x_dbginfo, + "Device Name : %s\n", + pdev->name ); +#endif + + DBG_TRACE( et131x_dbginfo, + "Device on Bus # : %d\n", + pdev->bus->number ); + DBG_TRACE( et131x_dbginfo, + " Bus Name : %s\n", + pdev->bus->name ); + DBG_TRACE( et131x_dbginfo, + "Device in Slot # : %d\n", + PCI_SLOT( pdev->devfn )); + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,11 )) + DBG_TRACE( et131x_dbginfo, + " Slot Name : %s\n", + pdev->slot_name ); +#endif + + DBG_TRACE( et131x_dbginfo, + "Device Base Address : 0x%#03lx\n", + netdev->base_addr ); + DBG_TRACE( et131x_dbginfo, + "Device IRQ : %d\n", + netdev->irq ); + DBG_TRACE( et131x_dbginfo, + "Device MAC Address : %02x:%02x:%02x:%02x:%02x:%02x\n", + adapter->CurrentAddress[0], adapter->CurrentAddress[1], + adapter->CurrentAddress[2], adapter->CurrentAddress[3], + adapter->CurrentAddress[4], adapter->CurrentAddress[5] ); + + + DBG_LEAVE( et131x_dbginfo ); + return 0; +} +/*===========================================================================*/ --- linux-2.6.27.orig/ubuntu/et131x/et131x_debug.c +++ linux-2.6.27/ubuntu/et131x/et131x_debug.c @@ -0,0 +1,328 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_debug.c - Routines used for debugging. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/08/01 19:35:12 $ + $Revision: 1.6 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +#ifdef ET131X_DBG + + + + +/****************************************************************************** + Includes + *****************************************************************************/ +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include +#include +#include +#include +#include + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "ET1310_phy.h" +#include "ET1310_pm.h" +#include "ET1310_jagcore.h" + +#include "et131x_supp.h" +#include "et131x_adapter.h" +#include "et131x_netdev.h" +#include "et131x_config.h" +#include "et131x_isr.h" + +#include "ET1310_address_map.h" +#include "ET1310_jagcore.h" +#include "ET1310_tx.h" +#include "ET1310_rx.h" +#include "ET1310_mac.h" + + + + +/****************************************************************************** + Data for debugging facilities + *****************************************************************************/ +extern dbg_info_t *et131x_dbginfo; + + + + +/****************************************************************************** + ROUTINE: DumpTxQueueContents + ****************************************************************************** + DESCRIPTION: + Used to dump out hte tx queue and the shadow pointers + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +void DumpTxQueueContents( int dbgLvl, ET131X_ADAPTER *pAdapter ) +{ + UINT32 TxQueueAddr; + /*-----------------------------------------------------------------------*/ + + + if( DBG_FLAGS( et131x_dbginfo ) & dbgLvl ) + { + + for( TxQueueAddr = 0x200; TxQueueAddr< 0x3ff; TxQueueAddr++ ) + { + pAdapter->CSRAddress->mmc.sram_access.bits.req_addr = TxQueueAddr; + pAdapter->CSRAddress->mmc.sram_access.bits.req_access = 1; + + + DBG_PRINT( "Addr 0x%x, Access 0x%08x\t" + "Value 1 0x%08x, Value 2 0x%08x, " + "Value 3 0x%08x, Value 4 0x%08x, \n", + TxQueueAddr, + pAdapter->CSRAddress->mmc.sram_access.value, + pAdapter->CSRAddress->mmc.sram_word1.data, + pAdapter->CSRAddress->mmc.sram_word2.data, + pAdapter->CSRAddress->mmc.sram_word3.data, + pAdapter->CSRAddress->mmc.sram_word4.data ); + + } + + DBG_PRINT( "Shadow Pointers 0x%08x\n", + pAdapter->CSRAddress->txmac.shadow_ptr.value ); + } + + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: DumpDeviceBlock + ****************************************************************************** + + DESCRIPTION: + Dumps the first 64 regs of each block of the et-1310 (each block is + mapped to a new page, each page is 4096 bytes). + + PARAMETERS : + pAdapter - pointer to our adapter + + RETURN : + VOID + *****************************************************************************/ +#define NUM_BLOCKS 8 +void DumpDeviceBlock( int dbgLvl, ET131X_ADAPTER *pAdapter, UINT32 Block ) +{ + UINT32 Address1, Address2; + UINT32 *BigDevicePointer = (UINT32 *)pAdapter->CSRAddress; + /*-----------------------------------------------------------------------*/ + + + char* BlockNames[NUM_BLOCKS] = + {"Global", "Tx DMA", "Rx DMA", "Tx MAC", + "Rx MAC", "MAC", "MAC Stat", "MMC" }; + /*-----------------------------------------------------------------------*/ + + + /************************************************************************** + Output the debug counters to the debug terminal + *************************************************************************/ + if( DBG_FLAGS( et131x_dbginfo ) & dbgLvl ) + { + DBG_PRINT( "%s block\n", BlockNames[Block] ); + + for( Address1 = 0; Address1 < 8; Address1++ ) + { + for( Address2 = 0; Address2 < 8; Address2++ ) + { + if( Block == 0 ) + { + if((( Address1 * 8 ) + Address2 ) == 6 ) + { + DBG_PRINT( " ISR , " ); + } + else + { + DBG_PRINT( "0x%08x, ", + BigDevicePointer[( Block * 1024 ) + + ( Address1 * 8 ) + Address2] ); + + } + } + else + { + DBG_PRINT( "0x%08x, ", + BigDevicePointer[( Block * 1024 ) + + ( Address1 * 8 ) + Address2] ); + } + } + + DBG_PRINT( "\n" ); + } + + DBG_PRINT( "\n" ); + } + + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: DumpDeviceReg + ****************************************************************************** + + DESCRIPTION: + Dumps the first 64 regs of each block of the et-1310 (each block is + mapped to a new page, each page is 4096 bytes). + + PARAMETERS : + pAdapter - pointer to our adapter + + RETURN : + VOID + *****************************************************************************/ +void DumpDeviceReg( int dbgLvl, ET131X_ADAPTER *pAdapter ) +{ + UINT32 Address1, Address2; + UINT32 Block; + UINT32 *BigDevicePointer = (UINT32 *)pAdapter->CSRAddress; + + char* BlockNames[NUM_BLOCKS] = + {"Global", "Tx DMA", "Rx DMA", "Tx MAC", + "Rx MAC", "MAC", "MAC Stat", "MMC" }; + /*-----------------------------------------------------------------------*/ + + + /************************************************************************** + Output the debug counters to the debug terminal + *************************************************************************/ + if( DBG_FLAGS( et131x_dbginfo ) & dbgLvl ) + { + for( Block = 0; Block < NUM_BLOCKS; Block++ ) + { + DBG_PRINT( "%s block\n", BlockNames[Block] ); + + for( Address1 = 0; Address1 < 8; Address1++ ) + { + for( Address2 = 0; Address2 < 8; Address2++ ) + { + DBG_PRINT( "0x%08x, ", + BigDevicePointer[( Block * 1024 ) + + ( Address1 * 8 ) + Address2] ); + } + + DBG_PRINT( "\n" ); + } + + DBG_PRINT( "\n" ); + } + } + + return; +} +/*==========================================================================*/ + + + + +#endif // ET131X_DBG --- linux-2.6.27.orig/ubuntu/et131x/et131x_initpci.h +++ linux-2.6.27/ubuntu/et131x/et131x_initpci.h @@ -0,0 +1,103 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_initpci.h - Header which includes common data and function prototypes + * related to the driver's PCI (and PCI Express) information. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/10/28 17:31:23 $ + $Revision: 1.4 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +#ifndef __ET131X_INITPCI_H__ +#define __ET131X_INITPCI_H__ + + + + +/****************************************************************************** + Function Prototypes + *****************************************************************************/ +int et131x_pci_register( void ); +void et131x_pci_unregister( void ); + +void et131x_align_allocated_memory( ET131X_ADAPTER *adapter, + UINT64 *phys_addr, + UINT64 *offset, + UINT64 mask ); + + + + +int et131x_adapter_setup( ET131X_ADAPTER *pAdapter ); +int et131x_adapter_memory_alloc( ET131X_ADAPTER *adapter ); +void et131x_adapter_memory_free( ET131X_ADAPTER *adapter ); +void et131x_setup_hardware_properties( ET131X_ADAPTER *adapter ); +void et131x_soft_reset( ET131X_ADAPTER *adapter ); + +#endif /* __ET131X_INITPCI_H__ */ --- linux-2.6.27.orig/ubuntu/et131x/ET1310_jagcore.c +++ linux-2.6.27/ubuntu/et131x/ET1310_jagcore.c @@ -0,0 +1,642 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * ET1310_jagcore.c - All code pertaining to the ET1301/ET131x's JAGcore + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/10/28 18:43:44 $ + $Revision: 1.9 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +/****************************************************************************** + Includes + *****************************************************************************/ +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include +#include +#include +#include + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ET1310_phy.h" +#include "ET1310_pm.h" +#include "ET1310_jagcore.h" + +#include "et131x_supp.h" +#include "et131x_adapter.h" +#include "et131x_initpci.h" + + + + +/****************************************************************************** + Data for debugging facilities + *****************************************************************************/ +#ifdef ET131X_DBG +extern dbg_info_t *et131x_dbginfo; +#endif /* ET131X_DBG */ + + + + +/****************************************************************************** + ROUTINE: ConfigGlobalRegs + ****************************************************************************** + + DESCRIPTION: + Used to configure the global registers on the JAGCore + + PARAMETERS : + pAdpater - pointer to our adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +void ConfigGlobalRegs( ET131X_ADAPTER *pAdapter ) +{ + PGLOBAL_t pGbl; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "ConfigGlobalRegs" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Map a local pointer to the global section of the JAGCore + *************************************************************************/ + pGbl = &pAdapter->CSRAddress->global; + + if( pAdapter->RegistryPhyLoopbk == FALSE ) + { + if( pAdapter->RegistryJumboPacket < 2048 ) + { + /****************************************************************** + Tx / RxDMA and Tx/Rx MAC interfaces have a 1k word block of RAM + that the driver can split between Tx and Rx as it desires. Our + default is to split it 50/50: + *****************************************************************/ + pGbl->rxq_start_addr.value = 0; + pGbl->rxq_end_addr.value = pAdapter->RegistryRxMemEnd; + pGbl->txq_start_addr.value = pGbl->rxq_end_addr.bits.rxq_end_addr + 1; + pGbl->txq_end_addr.value = INTERNAL_MEM_SIZE - 1; + } + else if( pAdapter->RegistryJumboPacket < 8192 ) + { + /****************************************************************** + For jumbo packets > 2k in length, but < 8k, split 50-50. + *****************************************************************/ + pGbl->rxq_start_addr.value = 0; + pGbl->rxq_end_addr.value = INTERNAL_MEM_RX_OFFSET; + pGbl->txq_start_addr.value = INTERNAL_MEM_RX_OFFSET + 1; + pGbl->txq_end_addr.value = INTERNAL_MEM_SIZE - 1; + } + else + { + /****************************************************************** + 9216 is the only packet size greater than 8k that is available. + The Tx buffer has to be big enough for one whole packet on the + Tx side. We'll make the Tx 9408, and give the rest to Rx + *****************************************************************/ + pGbl->rxq_start_addr.value = 0x0000; + pGbl->rxq_end_addr.value = 0x01b3; + pGbl->txq_start_addr.value = 0x01b4; + pGbl->txq_end_addr.value = INTERNAL_MEM_SIZE - 1; + } + + /********************************************************************** + Initialize the loopback register. Disable all loopbacks. + *********************************************************************/ + pGbl->loopback.value = 0x0; + } + else + { + /************************************************************************** + For PHY Line loopback, the memory is configured as if Tx and Rx both + have all the memory. This is because the RxMAC will write data into + the space, and the TxMAC will read it out. + *************************************************************************/ + pGbl->rxq_start_addr.value = 0; + pGbl->rxq_end_addr.value = INTERNAL_MEM_SIZE - 1; + pGbl->txq_start_addr.value = 0; + pGbl->txq_end_addr.value = INTERNAL_MEM_SIZE - 1; + + /************************************************************************** + Initialize the loopback register (MAC loopback). + *************************************************************************/ + pGbl->loopback.value = 0x1; + } + + /************************************************************************** + MSI Register + *************************************************************************/ + pGbl->msi_config.value = 0x0; + + + /************************************************************************** + By default, disable the watchdog timer. It will be enabled when + a packet is queued. + *************************************************************************/ + pGbl->watchdog_timer = 0; + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: ConfigMMCRegs + ****************************************************************************** + + DESCRIPTION: + Used to configure the main memory registers in the JAGCore + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +void ConfigMMCRegs( ET131X_ADAPTER *pAdapter ) +{ + MMC_CTRL_t mmc_ctrl = {0}; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "ConfigMMCRegs" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + All we need to do is initialize the Memory Control Register + *************************************************************************/ + mmc_ctrl.bits.force_ce = 0x0; + mmc_ctrl.bits.rxdma_disable = 0x0; + mmc_ctrl.bits.txdma_disable = 0x0; + mmc_ctrl.bits.txmac_disable = 0x0; + mmc_ctrl.bits.rxmac_disable = 0x0; + mmc_ctrl.bits.arb_disable = 0x0; + mmc_ctrl.bits.mmc_enable = 0x1; + + pAdapter->CSRAddress->mmc.mmc_ctrl.value = mmc_ctrl.value; + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_enable_interrupts + ****************************************************************************** + + DESCRIPTION : Enable interupts on the ET131x + + PARAMETERS : adapter - a pointer to our private adapter structure + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_enable_interrupts( ET131X_ADAPTER *adapter ) +{ + UINT32 MaskValue; + + + /************************************************************************** + Enable all global interrupts + *************************************************************************/ + if(( adapter->FlowControl == TxOnly ) || + ( adapter->FlowControl == Both )) + { + MaskValue = INT_MASK_ENABLE; + } + else + { + MaskValue = INT_MASK_ENABLE_NO_FLOW; + } + + if( adapter->DriverNoPhyAccess ) + { + MaskValue |= 0x10000; + } + + adapter->CachedMaskValue.value = MaskValue; + adapter->CSRAddress->global.int_mask.value = MaskValue; + + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_disable_interrupts + ****************************************************************************** + + DESCRIPTION : Enable interrupts on the ET131x + + PARAMETERS : adapter - a pointer to our private adapter structure + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ + +void et131x_disable_interrupts( ET131X_ADAPTER *adapter ) +{ + /************************************************************************** + Disable all global interrupts + *************************************************************************/ + adapter->CachedMaskValue.value = INT_MASK_DISABLE; + adapter->CSRAddress->global.int_mask.value = INT_MASK_DISABLE; + + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: NICGetRegs + ****************************************************************************** + + DESCRIPTION: + function used to get register data + + PARAMETERS : + pAdapter - pointer to our adapter structure + InfoBuf - pointer to data struct containing registers to get + ulBytesAvailable - + ulInfoLen - + + RETURN : + NONE + + *****************************************************************************/ +void * et131x_get_regs( ET131X_ADAPTER *pAdapter, void *InfoBuf, + PUINT32 ulBytesAvailable, PUINT32 ulInfoLen ) +{ + INT32 nRegCount; + PINT8 pJCBase; + INT32 x; + PUINT32 pReg; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_get_regs" ); + DBG_ENTER( et131x_dbginfo ); + + + memset( (void *)&pAdapter->JagCoreRegs, 0, sizeof( JAGCORE_ACCESS_REGS )); + + + /************************************************************************** + Get the user supplied data + *************************************************************************/ + pAdapter->JagCoreRegs = *(PJAGCORE_ACCESS_REGS)InfoBuf; + nRegCount = pAdapter->JagCoreRegs.nRegCount; + + pJCBase = (PINT8)&pAdapter->CSRAddress->global; + + for( x = 0; x < nRegCount; x++ ) + { + pReg = (PUINT32)( pJCBase+pAdapter->JagCoreRegs.nOffsets[x] ); + + pAdapter->JagCoreRegs.nData[x] = *pReg; + } + + *ulBytesAvailable = sizeof( JAGCORE_ACCESS_REGS ); + *ulInfoLen = sizeof( JAGCORE_ACCESS_REGS ); + + + DBG_LEAVE( et131x_dbginfo ); + return( (void *)&pAdapter->JagCoreRegs ); +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: et131x_set_regs + ****************************************************************************** + + DESCRIPTION: + function used to set register data + + PARAMETERS : + pAdapter - pointer to our adapter structure + InfoBuf - pointer to data struct containing register offset and data + to set + RETURN : + N/A + + *****************************************************************************/ +void et131x_set_regs( ET131X_ADAPTER *pAdapter, void *InfoBuf ) +{ + INT32 nRegCount; + PINT8 pJCBase; + INT32 x; + PUINT32 pReg; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_set_regs" ); + DBG_ENTER( et131x_dbginfo ); + + + memset( (void *)&pAdapter->JagCoreRegs, 0, sizeof( JAGCORE_ACCESS_REGS )); + + + /************************************************************************** + Get the user supplied data + *************************************************************************/ + pAdapter->JagCoreRegs = *(PJAGCORE_ACCESS_REGS)InfoBuf; + + nRegCount = pAdapter->JagCoreRegs.nRegCount; + + pJCBase = (PINT8)&pAdapter->CSRAddress->global; + + for( x = 0; x < nRegCount; x++ ) + { + pReg = (PUINT32)(pJCBase+pAdapter->JagCoreRegs.nOffsets[x]); + *pReg = pAdapter->JagCoreRegs.nData[x]; + } + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: GetPciCfgRegs + ****************************************************************************** + + DESCRIPTION: + function used to get register data + + PARAMETERS : + pAdapter - pointer to our adapter structure + InfoBuf - pointer to data struct containing registers to get + ulBytesAvailable - + ulInfoLen - + + RETURN : + NONE + + *****************************************************************************/ +void * GetPciCfgRegs( ET131X_ADAPTER *pAdapter, void * InfoBuf, + PUINT32 ulBytesAvailable, PUINT32 ulInfoLen ) +{ + INT32 nRegCount; + UINT32 ByteLength = 0; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "GetPciCfgRegs" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Get the user supplied data + *************************************************************************/ + pAdapter->PciCfgRegs = *(PPCI_CFG_SPACE_REGS)InfoBuf; + nRegCount = pAdapter->PciCfgRegs.nRegCount; + + + /************************************************************************** + Support for 8,16,32 bit widths + *************************************************************************/ + ByteLength = pAdapter->PciCfgRegs.nDataWidth/8; + + pci_slot_information_read( pAdapter->pdev, + pAdapter->PciCfgRegs.nOffsets[0], + (UINT8 *)&pAdapter->PciCfgRegs.nData, + ByteLength * nRegCount ); + + *ulBytesAvailable = sizeof( PCI_CFG_SPACE_REGS ); + *ulInfoLen = sizeof( PCI_CFG_SPACE_REGS ); + + + DBG_LEAVE( et131x_dbginfo ); + return( (void *)&pAdapter->PciCfgRegs ); +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: SetPciCfgRegs + ****************************************************************************** + + DESCRIPTION: + function used to set register data + + PARAMETERS : + pAdapter - pointer to our adapter structure + InfoBuf - pointer to data struct containing register offset and data + to set + RETURN : + N/A + + *****************************************************************************/ +void SetPciCfgRegs( ET131X_ADAPTER *pAdapter, void * InfoBuf ) +{ + INT32 nRegCount; + INT32 x; + UINT32 ByteLength = 0; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "SetPciCfgRegs" ); + DBG_ENTER( et131x_dbginfo ); + + + memset( (void *)&pAdapter->PciCfgRegs, 0, sizeof( PCI_CFG_SPACE_REGS )); + + + /************************************************************************** + Get the user supplied data + *************************************************************************/ + pAdapter->PciCfgRegs = *(PPCI_CFG_SPACE_REGS)InfoBuf; + + nRegCount = pAdapter->PciCfgRegs.nRegCount; + ByteLength = pAdapter->PciCfgRegs.nDataWidth/8; + + for( x = 0; x < nRegCount; x++ ) + { + pci_slot_information_write( pAdapter->pdev, + pAdapter->PciCfgRegs.nOffsets[x], + (UINT8 *)&pAdapter->PciCfgRegs.nData[x * ByteLength], + ByteLength ); + } + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: MemTest + ****************************************************************************** + + DESCRIPTION: + function used to test rx/tx queue memory at 0x0 and 0x200 + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURN : + TRUE or FALSE + + *****************************************************************************/ +BOOL_t MemTest( ET131X_ADAPTER *pAdapter, UINT32 addr ) +{ + UINT32 data; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "MemTest" ); + DBG_ENTER( et131x_dbginfo ); + + + // Read initial value + pAdapter->CSRAddress->mmc.sram_access.value = 1; + data = pAdapter->CSRAddress->mmc.sram_word1.data; + + + // Write test value + pAdapter->CSRAddress->mmc.sram_word1.data = 0xdeadbeef; + pAdapter->CSRAddress->mmc.sram_access.value = 0xf003; + + + // Read back test value + pAdapter->CSRAddress->mmc.sram_access.bits.req_access = 1; + if ( pAdapter->CSRAddress->mmc.sram_word1.data != 0xdeadbeef ) + { + DBG_LEAVE( et131x_dbginfo ); + return FALSE; + } + + // Restore initial value + pAdapter->CSRAddress->mmc.sram_word1.data = data; + pAdapter->CSRAddress->mmc.sram_access.value = 0xf003; + + + DBG_LEAVE( et131x_dbginfo ); + return TRUE; +} +/*===========================================================================*/ --- linux-2.6.27.orig/ubuntu/et131x/Makefile +++ linux-2.6.27/ubuntu/et131x/Makefile @@ -0,0 +1,6 @@ +obj-$(CONFIG_NET_ET131X) += et131x.o + +et131x-objs += et131x_main.o et131x_initpci.o et131x_isr.o et131x_netdev.o \ + et131x_supp.o et131x_config.o et131x_debug.o ET1310_jagcore.o \ + ET1310_tx.o ET1310_rx.o ET1310_phy.o ET1310_mac.o ET1310_pm.o \ + ET1310_eeprom.o --- linux-2.6.27.orig/ubuntu/et131x/et131x_debug.h +++ linux-2.6.27/ubuntu/et131x/et131x_debug.h @@ -0,0 +1,267 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_debug.h - Defines, structs, enums, prototypes, etc. used for + * outputting debug messages to the system logging facility + * (ksyslogd) + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/08/01 19:35:12 $ + $Revision: 1.10 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +#ifndef __ET131X_DBG_H__ +#define __ET131X_DBG_H__ + + + + +/****************************************************************************** + Define Masks for debugging types/levels + *****************************************************************************/ +#define DBG_ERROR_ON 0x00000001L +#define DBG_WARNING_ON 0x00000002L +#define DBG_NOTICE_ON 0x00000004L +#define DBG_TRACE_ON 0x00000008L +#define DBG_VERBOSE_ON 0x00000010L +#define DBG_PARAM_ON 0x00000020L +#define DBG_BREAK_ON 0x00000040L +#define DBG_RX_ON 0x00000100L +#define DBG_TX_ON 0x00000200L + + + + +#ifdef ET131X_DBG + + +/****************************************************************************** + Set the level of debugging if not done with a preprocessor define. See + et131x_main.c, function et131x_init_module() for how the debug level + translates into the types of messages displayed. + *****************************************************************************/ +#ifndef DBG_LVL +#define DBG_LVL 3 +#endif /* DBG_LVL */ + + +#define DBG_DEFAULTS (DBG_ERROR_ON | DBG_WARNING_ON | DBG_BREAK_ON ) + +#define DBG_FLAGS(A) (A)->dbgFlags +#define DBG_NAME(A) (A)->dbgName +#define DBG_LEVEL(A) (A)->dbgLevel + + +#ifndef PRINTK +# define PRINTK(S...) printk(S) +#endif /* PRINTK */ + + +#ifndef DBG_PRINT +# define DBG_PRINT(S...) PRINTK(KERN_DEBUG S) +#endif /* DBG_PRINT */ + + +#ifndef DBG_PRINTC +# define DBG_PRINTC(S...) PRINTK(S) +#endif /* DBG_PRINTC */ + + +#ifndef DBG_TRAP +# define DBG_TRAP {} //BUG() +#endif /* DBG_TRAP */ + + +#define _ENTER_STR ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" +#define _LEAVE_STR "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" + + +#define _DBG_ENTER(A) DBG_PRINT("%s:%.*s:%s\n",DBG_NAME(A),++DBG_LEVEL(A),_ENTER_STR,__FUNC__) +#define _DBG_LEAVE(A) DBG_PRINT("%s:%.*s:%s\n",DBG_NAME(A),DBG_LEVEL(A)--,_LEAVE_STR,__FUNC__) + + +#define DBG_FUNC(F) static const char __FUNC__[] = F; + + +#define DBG_ENTER(A) {if (DBG_FLAGS(A) & DBG_TRACE_ON) \ + _DBG_ENTER(A);} + + +#define DBG_LEAVE(A) {if (DBG_FLAGS(A) & DBG_TRACE_ON) \ + _DBG_LEAVE(A);} + + +#define DBG_PARAM(A,N,F,S...) {if (DBG_FLAGS(A) & DBG_PARAM_ON) \ + DBG_PRINT(" %s -- "F"\n",N,S);} + + +#define DBG_ERROR(A,S...) {if (DBG_FLAGS(A) & DBG_ERROR_ON) \ + {DBG_PRINT("%s:ERROR:%s ",DBG_NAME(A),__FUNC__);DBG_PRINTC(S);DBG_TRAP;}} + + +#define DBG_WARNING(A,S...) {if (DBG_FLAGS(A) & DBG_WARNING_ON) \ + {DBG_PRINT("%s:WARNING:%s ",DBG_NAME(A),__FUNC__);DBG_PRINTC(S);}} + + +#define DBG_NOTICE(A,S...) {if (DBG_FLAGS(A) & DBG_NOTICE_ON) \ + {DBG_PRINT("%s:NOTICE:%s ",DBG_NAME(A),__FUNC__);DBG_PRINTC(S);}} + + +#define DBG_TRACE(A,S...) {if (DBG_FLAGS(A) & DBG_TRACE_ON) \ + {DBG_PRINT("%s:TRACE:%s ",DBG_NAME(A),__FUNC__);DBG_PRINTC(S);}} + +#define DBG_VERBOSE(A,S...) {if (DBG_FLAGS(A) & DBG_VERBOSE_ON) \ + {DBG_PRINT("%s:VERBOSE:%s ",DBG_NAME(A),__FUNC__);DBG_PRINTC(S);}} + + +#define DBG_RX(A,S...) {if (DBG_FLAGS(A) & DBG_RX_ON) \ + {DBG_PRINT(S);}} + +#define DBG_RX_ENTER(A) {if (DBG_FLAGS(A) & DBG_RX_ON) \ + _DBG_ENTER(A);} + +#define DBG_RX_LEAVE(A) {if (DBG_FLAGS(A) & DBG_RX_ON) \ + _DBG_LEAVE(A);} + +#define DBG_TX(A,S...) {if (DBG_FLAGS(A) & DBG_TX_ON) \ + {DBG_PRINT(S);}} + +#define DBG_TX_ENTER(A) {if (DBG_FLAGS(A) & DBG_TX_ON) \ + _DBG_ENTER(A);} + +#define DBG_TX_LEAVE(A) {if (DBG_FLAGS(A) & DBG_TX_ON) \ + _DBG_LEAVE(A);} + + +#define DBG_ASSERT(C) {if (!(C)) \ + {DBG_PRINT("ASSERT(%s) -- %s#%d (%s)\n", \ + #C,__FILE__,__LINE__,__FUNC__); \ + DBG_TRAP;}} +#define STATIC + + +typedef struct +{ + char *dbgName; + int dbgLevel; + unsigned long dbgFlags; +} dbg_info_t; + + + + +#else /* ET131X_DBG */ + + + + +#define DBG_DEFN +#define DBG_TRAP +#define DBG_FUNC(F) +#define DBG_PRINT(S...) +#define DBG_ENTER(A) +#define DBG_LEAVE(A) +#define DBG_PARAM(A,N,F,S...) +#define DBG_ERROR(A,S...) +#define DBG_WARNING(A,S...) +#define DBG_NOTICE(A,S...) +#define DBG_TRACE(A,S...) +#define DBG_VERBOSE(A,S...) +#define DBG_RX(A,S...) +#define DBG_RX_ENTER(A) +#define DBG_RX_LEAVE(A) +#define DBG_TX(A,S...) +#define DBG_TX_ENTER(A) +#define DBG_TX_LEAVE(A) +#define DBG_ASSERT(C) +#define STATIC static + +#endif /* ET131X_DBG */ + + + + +/****************************************************************************** + Forward declaration of the private adapter structure + *****************************************************************************/ +struct et131x_adapter; + + + + +/****************************************************************************** + PROTOTYPES for et131x_debug.c + *****************************************************************************/ +void DumpTxQueueContents( int dbgLvl, struct et131x_adapter *pAdapter ); +void DumpDeviceBlock( int dbgLvl, struct et131x_adapter *pAdapter, unsigned int Block ); +void DumpDeviceReg( int dbgLvl, struct et131x_adapter *pAdapter ); + + + + +#endif /* __ET131X_DBG_H__ */ --- linux-2.6.27.orig/ubuntu/et131x/et131x_isr.c +++ linux-2.6.27/ubuntu/et131x/et131x_isr.c @@ -0,0 +1,656 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_isr.c - File which contains the ISR, ISR handler, and related routines + * for processing interrupts from the device. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2006/01/31 20:58:43 $ + $Revision: 1.13 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +/****************************************************************************** + Includes + *****************************************************************************/ +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include +#include +#include +#include + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ET1310_phy.h" +#include "ET1310_pm.h" +#include "ET1310_jagcore.h" +#include "ET1310_mac.h" + +#include "et131x_supp.h" +#include "et131x_adapter.h" + + + + +/****************************************************************************** + Data for debugging facilities + *****************************************************************************/ +#ifdef ET131X_DBG +extern dbg_info_t *et131x_dbginfo; +#endif /* ET131X_DBG */ + + + + +/****************************************************************************** + Prototypes for functions with local scope + *****************************************************************************/ + + + + +/****************************************************************************** + Defines for 2.4 compatibility with the new 2.6 IRQ handler return values + *****************************************************************************/ +#ifndef IRQ_RETVAL + +typedef void irqreturn_t; +#define IRQ_NONE +#define IRQ_HANDLED +#define IRQ_RETVAL(x) + +#endif /* IRQ_RETVAL */ + + + + +/****************************************************************************** + ROUTINE : et131x_isr + ****************************************************************************** + + DESCRIPTION : The Interrupt Service Routine for the driver. + + PARAMETERS : irq - the IRQ on which the interrupt was received. + dev_id - a buffer containing device-specific info (in + this case, a pointer to a net_device struct) + regs - + + RETURNS : For 2.4.x kernels - N/A + For 2.6.x kernels - A value indicating if the interrupt + was handled. + + REUSE INFORMATION : + + *****************************************************************************/ +irqreturn_t et131x_isr( int irq, void *dev_id ) +{ + BOOL_t handled = TRUE; + struct net_device *netdev = (struct net_device *)dev_id; + ET131X_ADAPTER *adapter = NULL; + INT_STATUS_t status; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_isr" ); + + + do + { + if(( netdev == NULL ) || ( !netif_device_present( netdev ))) + { + DBG_WARNING( et131x_dbginfo, + "No net_device struct or device not present\n" ); + handled = FALSE; + break; + } + + adapter = netdev_priv( netdev ); + + + /********************************************************************** + If the adapter is in low power state, then it should not recognize + any interrupt + + NOTE + *********************************************************************/ + + + /********************************************************************** + Disable Device Interrupts + *********************************************************************/ + et131x_disable_interrupts( adapter ); + + + /********************************************************************** + Get a copy of the value in the interrupt status register so we can + process the interrupting section + *********************************************************************/ + status.value = adapter->CSRAddress->global.int_status.value; + + if(( adapter->FlowControl == TxOnly ) || + ( adapter->FlowControl == Both )) + { + status.value &= ~INT_MASK_ENABLE; + } + else + { + status.value &= ~INT_MASK_ENABLE_NO_FLOW; + } + + + /********************************************************************** + Make sure this is our interrupt + *********************************************************************/ + if( !status.value ) + { +#ifdef ET131X_DBG + adapter->Stats.UnhandledInterruptsPerSec++; +#endif + handled = FALSE; + DBG_VERBOSE( et131x_dbginfo, "NOT OUR INTERRUPT\n" ); + et131x_enable_interrupts( adapter ); + break; + } + + /********************************************************************** + This is our interrupt, so process accordingly + *********************************************************************/ +#ifdef ET131X_DBG + if( status.bits.rxdma_xfr_done ) + { + adapter->Stats.RxDmaInterruptsPerSec++; + } + + if( status.bits.txdma_isr ) + { + adapter->Stats.TxDmaInterruptsPerSec++; + } +#endif + + if( status.bits.watchdog_interrupt ) + { + PMP_TCB pMpTcb = adapter->TxRing.CurrSendHead; + + if( pMpTcb ) + { + if( ++pMpTcb->PacketStaleCount > 1 ) + { + status.bits.txdma_isr = 1; + } + } + + if( adapter->RxRing.UnfinishedReceives ) + { + status.bits.rxdma_xfr_done = 1; + } + else if( pMpTcb == 0 ) + { + adapter->CSRAddress->global.watchdog_timer = 0; + } + + status.bits.watchdog_interrupt = 0; +#ifdef ET131X_DBG + adapter->Stats.WatchDogInterruptsPerSec++; +#endif + } + + if( status.value == 0 ) + { + /****************************************************************** + This interrupt has in some way been "handled" by the ISR. Either + it was a spurious Rx interrupt, or it was a Tx interrupt that + has been filtered by the ISR. + *****************************************************************/ + et131x_enable_interrupts( adapter ); + break; + } + + /********************************************************************** + We need to save the interrupt status value for use in our DPC. We + will clear the software copy of that in that routine. + *********************************************************************/ + adapter->Stats.InterruptStatus = status; + + + /********************************************************************** + Schedule the ISR handler as a bottom-half task in the kernel's + tq_immediate queue, and mark the queue for execution + *********************************************************************/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) + schedule_task( &adapter->task ); +#else + schedule_work( &adapter->task ); +#endif + + } while( 0 ); + + return IRQ_RETVAL( handled ); +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_isr_handler + ****************************************************************************** + + DESCRIPTION : The ISR handler, scheduled to run in a deferred context + by the ISR. This is where the ISR's work actually gets + done. + + PARAMETERS : p_adapter - a pointer to the device's private adapter + structure + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_isr_handler( struct work_struct *work ) +{ + ET131X_ADAPTER *pAdapter = container_of( work, ET131X_ADAPTER, task ); + + INT_STATUS_t GlobStatus = pAdapter->Stats.InterruptStatus; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_isr_handler" ); + + + /************************************************************************** + These first two are by far the most common. Once handled, we clear + their two bits in the status word. If the word is now zero, we exit. + *************************************************************************/ + /************************************************************************** + Handle all the completed Transmit interrupts + *************************************************************************/ + if( GlobStatus.bits.txdma_isr ) + { + DBG_TX( et131x_dbginfo, "TXDMA_ISR interrupt\n" ); + et131x_handle_send_interrupt( pAdapter ); + } + + + /************************************************************************** + Handle all the completed Receives interrupts + *************************************************************************/ + if( GlobStatus.bits.rxdma_xfr_done ) + { + DBG_RX( et131x_dbginfo, "RXDMA_XFR_DONE interrupt\n" ); + et131x_handle_recv_interrupt( pAdapter ); + } + + GlobStatus.value &= 0xffffffd7; + + if( GlobStatus.value ) + { + + /********************************************************************** + Handle the TXDMA Error interrupt + *********************************************************************/ + if( GlobStatus.bits.txdma_err ) + { + TXDMA_ERROR_t TxDmaErr; + + + /****************************************************************** + Following read also clears the register (COR register) + *****************************************************************/ + TxDmaErr.value = pAdapter->CSRAddress->txdma.TxDmaError.value; + + DBG_WARNING( et131x_dbginfo, "TXDMA_ERR interrupt, error = %d\n", + TxDmaErr.value ); + } + + + /********************************************************************** + Handle Free Buffer Ring 0 and 1 Low interrupt + *********************************************************************/ + if( GlobStatus.bits.rxdma_fb_ring0_low || + GlobStatus.bits.rxdma_fb_ring1_low ) + { + /****************************************************************** + This indicates the number of unused buffers in RXDMA free buffer + ring 0 is <= the limit you programmed. Free buffer resources + need to be returned. Free buffers are consumed as packets are + passed from the network to the host. The host becomes aware of + the packets from the contents of the packet status ring. This + ring is queried when the packet done interrupt occurs. Packets + are then passed to the OS. When the OS is done with the packets + the resources can be returned to the ET1310 for re-use. This + interrupt is one method of returning resources. + *****************************************************************/ + DBG_WARNING( et131x_dbginfo, + "RXDMA_FB_RING0_LOW or " + "RXDMA_FB_RING1_LOW interrupt\n" ); + + + /****************************************************************** + If the user has flow control on, then we will send a pause + packet, otherwise just exit + *****************************************************************/ + if(( pAdapter->FlowControl == TxOnly ) || + ( pAdapter->FlowControl == Both )) + { + /************************************************************** + Tell the device to send a pause packet via the back pressure + register + *************************************************************/ + if( pAdapter->CSRAddress->global.pm_csr.bits.pm_phy_sw_coma == 0 ) + { + TXMAC_BP_CTRL_t bp_ctrl; + + bp_ctrl.bits.bp_req = 1; + bp_ctrl.bits.bp_xonxoff = 1; + + pAdapter->CSRAddress->txmac.bp_ctrl.value = bp_ctrl.value; + } + } + } + + + /********************************************************************** + Handle Packet Status Ring Low Interrupt + *********************************************************************/ + if( GlobStatus.bits.rxdma_pkt_stat_ring_low ) + { + DBG_WARNING( et131x_dbginfo, + "RXDMA_PKT_STAT_RING_LOW interrupt\n" ); + + + /****************************************************************** + Same idea as with the two Free Buffer Rings. Packets going from + the network to the host each consume a free buffer resource and + a packet status resource. These resoures are passed to the OS. + When the OS is done with the resources, they need to be returned + to the ET1310. This is one method of returning the resources. + *****************************************************************/ + } + + + /********************************************************************** + Handle RXDMA Error Interrupt + *********************************************************************/ + if( GlobStatus.bits.rxdma_err ) + { + /****************************************************************** + The rxdma_error interrupt is sent when a time-out on a request + issued by the JAGCore has occurred or a completion is returned + with an un-successful status. In both cases the request is + considered complete. The JAGCore will automatically re-try the + request in question. Normally information on events like these + are sent to the host using the "Advanced Error Reporting" + capability. This interrupt is another way of getting similar + information. The only thing required is to clear the interrupt + by reading the ISR in the global resources. The JAGCore will do + a re-try on the request. Normally you should never see this + interrupt. If you start to see this interrupt occurring + frequently then something bad has occurred. + A reset might be the thing to do. + *****************************************************************/ + // TRAP(); + + pAdapter->TxMacTest = pAdapter->CSRAddress->txmac.tx_test; + DBG_WARNING( et131x_dbginfo, + "RxDMA_ERR interrupt, error %x\n", + pAdapter->TxMacTest.value ); + } + + + /********************************************************************** + Handle the Wake on LAN Event + *********************************************************************/ + if( GlobStatus.bits.wake_on_lan ) + { + /****************************************************************** + This is a secondary interrupt for wake on LAN. The driver + should never see this, if it does, something serious is wrong. + We will TRAP the message when we are in DBG mode, otherwise we + will ignore it. + *****************************************************************/ + DBG_ERROR( et131x_dbginfo, "WAKE_ON_LAN interrupt\n" ); + } + + + /********************************************************************** + Handle the PHY interrupt + *********************************************************************/ + if( GlobStatus.bits.phy_interrupt ) + { + MI_BMSR_t BmsrInts, BmsrData; + MI_ISR_t myIsr; + + DBG_VERBOSE( et131x_dbginfo, "PHY interrupt\n" ); + + /****************************************************************** + If we are in coma mode when we get this interrupt, we need to + disable it. + *****************************************************************/ + if( pAdapter->CSRAddress->global.pm_csr.bits.phy_sw_coma == 1 ) + { + /************************************************************** + Check to see if we are in coma mode and if so, disable it + because we will not be able to read PHY values until we are + out. + *************************************************************/ + DBG_VERBOSE( et131x_dbginfo, "Device is in COMA mode, " + "need to wake up\n" ); + DisablePhyComa( pAdapter ); + } + + + /****************************************************************** + Read the PHY ISR to clear the reason for the interrupt. + *****************************************************************/ + MiRead( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + (UINT8)FIELD_OFFSET( MI_REGS_t, isr ), &myIsr.value ); + + if( !pAdapter->ReplicaPhyLoopbk ) + { + MiRead( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + (UINT8)FIELD_OFFSET( MI_REGS_t, bmsr ), &BmsrData.value ); + + BmsrInts.value = pAdapter->Bmsr.value ^ BmsrData.value; + pAdapter->Bmsr.value = BmsrData.value; + + DBG_VERBOSE( et131x_dbginfo, + "Bmsr.value = 0x%04x," + "Bmsr_ints.value = 0x%04x\n", + BmsrData.value, + BmsrInts.value ); + + + /************************************************************** + Do all the cable in / cable out stuff + *************************************************************/ + et131x_Mii_check( pAdapter, BmsrData, BmsrInts ); + } + } + + + /********************************************************************** + Let's move on to the TxMac + *********************************************************************/ + if( GlobStatus.bits.txmac_interrupt ) + { + pAdapter->TxRing.TxMacErr.value = pAdapter->CSRAddress->txmac.err.value; + + /****************************************************************** + When any of the errors occur and TXMAC generates an interrupt to + report these errors, it usually means that TXMAC has detected an + error in the data stream retrieved from the on-chip Tx Q. All of + these errors are catastrophic and TXMAC won’t be able to recover + data when these errors occur. In a nutshell, the whole Tx path + will have to be reset and re-configured afterwards. + *****************************************************************/ + DBG_WARNING( et131x_dbginfo, + "TXMAC interrupt, error 0x%08x\n", + pAdapter->TxRing.TxMacErr.value ); + + + /******************************************************************* + If we are debugging, we want to see this error, otherwise we just + want the device to be reset and continue + *****************************************************************/ + //DBG_TRAP(); + + } + + /********************************************************************** + Handle RXMAC Interrupt + *********************************************************************/ + if( GlobStatus.bits.rxmac_interrupt ) + { + /****************************************************************** + These interrupts are catastrophic to the device, what we need to + do is disable the interrupts and set the flag to cause us to + reset so we can solve this issue. + ******************************************************************/ + // MP_SET_FLAG( pAdapter, fMP_ADAPTER_HARDWARE_ERROR ); + + DBG_WARNING( et131x_dbginfo, + "RXMAC interrupt, error 0x%08x. Requesting reset\n", + pAdapter->CSRAddress->rxmac.err_reg.value ); + + DBG_WARNING( et131x_dbginfo, + "Enable 0x%08x, Diag 0x%p\n", + pAdapter->CSRAddress->rxmac.ctrl.value, + &pAdapter->CSRAddress->rxmac.rxq_diag ); + + + /******************************************************************* + If we are debugging, we want to see this error, otherwise we just + want the device to be reset and continue + *****************************************************************/ + // TRAP(); + } + + /********************************************************************** + Handle MAC_STAT Interrupt + *********************************************************************/ + if( GlobStatus.bits.mac_stat_interrupt ) + { + /****************************************************************** + This means at least one of the un-masked counters in the MAC_STAT + block has rolled over. Use this to maintain the top, software + managed bits of the counter(s). + *****************************************************************/ + DBG_VERBOSE( et131x_dbginfo, "MAC_STAT interrupt\n" ); + HandleMacStatInterrupt( pAdapter ); + } + + + /********************************************************************** + Handle SLV Timeout Interrupt + *********************************************************************/ + if( GlobStatus.bits.slv_timeout ) + { + /****************************************************************** + This means a timeout has occured on a read or write request to + one of the JAGCore registers. The Global Resources block has + terminated the request and on a read request, returned a "fake" + value. The most likely reasons are: Bad Address or the + addressed module is in a power-down state and can't respond. + *****************************************************************/ + DBG_VERBOSE( et131x_dbginfo, "SLV_TIMEOUT interrupt\n" ); + } + } + + + if( pAdapter->PoMgmt.PowerState == NdisDeviceStateD0 ) + { + et131x_enable_interrupts( pAdapter ); + } + + return; +} +/*===========================================================================*/ --- linux-2.6.27.orig/ubuntu/et131x/et131x_supp.c +++ linux-2.6.27/ubuntu/et131x/et131x_supp.c @@ -0,0 +1,440 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_supp.c - Misc. support routines. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/08/01 19:35:13 $ + $Revision: 1.6 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +/****************************************************************************** + Includes + *****************************************************************************/ +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include +#include +#include +#include +#include + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ET1310_phy.h" +#include "ET1310_pm.h" +#include "ET1310_jagcore.h" +#include "ET1310_mac.h" + +#include "et131x_supp.h" + + + + +/****************************************************************************** + Data for debugging facilities + *****************************************************************************/ +#ifdef ET131X_DBG +extern dbg_info_t *et131x_dbginfo; +#endif /* ET131X_DBG */ + + + + +/****************************************************************************** + Global look-up table used to calculate CRC. Preset with the appropriate + XORs from the 256 possible byte values that might be in the message. + *****************************************************************************/ +static UINT32 SynDrome [256]; + + + + +/****************************************************************************** + Prototypes for functions with local scope + *****************************************************************************/ +static UINT32 crc32byte( UINT32 remainder, UCHAR data ); + + + + +/****************************************************************************** + ROUTINE : et131x_init_enet_crc_calc + ****************************************************************************** + + DESCRIPTION : Initializes the look-up table (syndrome) for CRC + calculation. + + PARAMETERS : N/A + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_init_enet_crc_calc( void ) +{ + UINT32 EthernetKey = 0x04c11db7; + UINT32 i; + UINT32 j; + UINT32 reg; + BOOL_t topBit; + /*-----------------------------------------------------------------------*/ + + + for( i = 0; i < 256; i++ ) + { + reg = i << 24; + + for( j = 0; j < 8; j++ ) + { + topBit = ( reg & 0x80000000 ) != 0; + + reg <<= 1; + + if( topBit ) + { + reg ^= EthernetKey; + } + } + SynDrome[i] = reg; + } + + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : crc32byte + ****************************************************************************** + + DESCRIPTION : + + PARAMETERS : + + RETURNS : + + REUSE INFORMATION : + + *****************************************************************************/ +#define CRC32_POLY 0x4C11DB7 + +static UINT32 crc32byte( UINT32 remainder, UCHAR data ) +{ + int index; + UINT32 remndr, hitbit; + /*-----------------------------------------------------------------------*/ + + + remndr = remainder; + + for( index = 0; index < 8; index++ ) + { + hitbit = (remndr >> 31) ^ (data & 0x01); + + data = data >> 1; // get the next data bit + remndr = remndr << 1; // get the next remainder bit + + if( hitbit ) + { + remndr = remndr ^ CRC32_POLY; + } + } + + return remndr; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_calc_enet_crc + ****************************************************************************** + + DESCRIPTION : Used to calculate the CRC of an ethernet message. Used + in the device's filtering of multi-cast packets. + + PARAMETERS : Message - A pointer to the Ethernet bytes to be encoded + MessageSize - The number of bytes in the message + + RETURNS : The computed CRC + + REUSE INFORMATION : + + *****************************************************************************/ +UINT32 et131x_calc_enet_crc( PUCHAR Message, UINT32 MessageSize ) +{ + UINT32 Result = 0xFFFFFFFF; + UINT32 i; + /*-----------------------------------------------------------------------*/ + + for( i = 0; i < MessageSize; i++ ) + { + Result = crc32byte( Result, *Message ); + Message++; + } + + return Result; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : pci_slot_information_read + ****************************************************************************** + + DESCRIPTION : Reads a segment of the PCI configuration space for a + device. + + This is a port of the NDIS function + NdisReadPciSlotInformation + + This function does not begin with 'et131x_' in order to + remain consistent with other system pci_xxx() calls. + + PARAMETERS : pdev - pointer to a pci_dev structure for the device + whose PCI config space is to be read + where - the offset to read + buf - a pointer to a buffer in which the data will be + returned + len - the length of the above buffer + + RETURNS : The length of the buffer read + + REUSE INFORMATION : + + *****************************************************************************/ +UINT32 pci_slot_information_read( struct pci_dev *pdev, UINT32 where, + UINT8 *buf, UINT32 len ) +{ + int i; + int status; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "pci_slot_information_read" ); + + + for( i = 0; i < len; i++ ) + { + status = pci_read_config_byte( pdev, where+i, &buf[i] ); + + if( status != 0 ) + { + DBG_ERROR( et131x_dbginfo, "Cannot Read PCI config space...\n" ); + break; + } + } + + return len; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : pci_slot_information_write + ****************************************************************************** + + DESCRIPTION : Writes a segment of the PCI configuration space for a + device. + + This is a port of the NDIS function + NdisWritePciSlotInformation + + This function does not begin with 'et131x_' in order to + remain consistent with other system pci_xxx() calls. + + PARAMETERS : pdev - pointer to a pci_dev structure for the device + whose PCI config space is to be written + where - the offset to write + buf - a pointer to a buffer containing the data to be + written + len - the length of the above buffer + + RETURNS : The length of the buffer written + + REUSE INFORMATION : + + *****************************************************************************/ +UINT32 pci_slot_information_write( struct pci_dev *pdev, UINT32 where, + UINT8 *buf, UINT32 len ) +{ + int i; + int status; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "pci_slot_information_write" ); + + + for( i = 0; i < len; i++ ) + { + status = pci_write_config_byte( pdev, where+i, buf[i] ); + + if( status != 0 ) + { + DBG_ERROR( et131x_dbginfo, "Cannot Write PCI config space...\n" ); + break; + } + } + + return len; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : netif_indicate_status + ****************************************************************************** + + DESCRIPTION : Provides the network stack with link status for the + given device. + + This is a port of the NDIS function + NdisMIndicateStatus. Unlike NDIS, there is no + corresponding status completion function. + + This function does not begin with 'et131x_' in order to + remain consistent with other system netif_xxx() calls. + + PARAMETERS : netdev - a pointer to the net_device struct representing + the device whose status we wosh to indicate. + status - the link status + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void netif_indicate_status( struct net_device *netdev, NETIF_STATUS status ) +{ + DBG_FUNC( "netif_indicate_status" ); + + + if( netdev != NULL ) + { + switch( status ) + { + case NETIF_STATUS_MEDIA_CONNECT: + DBG_VERBOSE( et131x_dbginfo, "Indicating Link UP\n" ); + netif_carrier_on( netdev ); + break; + + case NETIF_STATUS_MEDIA_DISCONNECT: + DBG_VERBOSE( et131x_dbginfo, "Indicating Link DOWN\n" ); + netif_carrier_off( netdev ); + break; + + default: + DBG_WARNING( et131x_dbginfo, + "Unknown link status code: %d\n", + status ); + break; + } + } + else + { + DBG_WARNING( et131x_dbginfo, "net_device pointer is NULL\n" ); + } + + return; +} +/*===========================================================================*/ --- linux-2.6.27.orig/ubuntu/et131x/ET1310_tx.c +++ linux-2.6.27/ubuntu/et131x/ET1310_tx.c @@ -0,0 +1,2084 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * ET1310_tx.c - Routines used to perform data transmission. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2006/01/20 21:29:44 $ + $Revision: 1.24 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +/****************************************************************************** + Includes + *****************************************************************************/ +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include +#include +#include +#include +#include + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) +#include +#endif + +#include "ET1310_phy.h" +#include "ET1310_pm.h" +#include "ET1310_jagcore.h" + +#include "et131x_supp.h" +#include "et131x_adapter.h" +#include "et131x_initpci.h" +#include "et131x_isr.h" + +#include "ET1310_tx.h" + + + + +/****************************************************************************** + Data for debugging facilities + *****************************************************************************/ +#ifdef ET131X_DBG +extern dbg_info_t *et131x_dbginfo; +#endif /* ET131X_DBG */ + + + + +/****************************************************************************** + Prototypes for functions local to this module + *****************************************************************************/ +void et131x_update_tcb_list( ET131X_ADAPTER *pAdapter ); +void et131x_check_send_wait_list( ET131X_ADAPTER *pAdapter ); +__inline void et131x_free_send_packet( ET131X_ADAPTER *pAdapter, PMP_TCB pMpTcb ); + +int et131x_send_packet( struct sk_buff *skb, ET131X_ADAPTER *pAdapter ); +int nic_send_packet( ET131X_ADAPTER *pAdapter, PMP_TCB pMpTcb ); + + + + +/****************************************************************************** + ROUTINE : et131x_tx_dma_memory_alloc + ****************************************************************************** + + DESCRIPTION : Allocates memory that will be visible both to the device + and to the CPU. The OS will pass us packets, pointers to + which we will insert in the Tx Descriptor queue. The + device will read this queue to find the packets in + memory. The device will update the "status" in memory + each time it xmits a packet. + + PARAMETERS : adapter - pointer to our private adapter structure + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_tx_dma_memory_alloc( ET131X_ADAPTER *adapter ) +{ + int desc_size = 0; + TX_RING_t *tx_ring; + MP_TCB *tcb; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_tx_dma_memory_alloc" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Allocate memory for the TCB's (Transmit Control Block) + *************************************************************************/ + adapter->TxRing.MpTcbMem = kmalloc( NUM_TCB * sizeof( MP_TCB ), + GFP_ATOMIC | GFP_DMA ); + if( !adapter->TxRing.MpTcbMem ) + { + DBG_ERROR( et131x_dbginfo, "Cannot alloc memory for TCBs\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -ENOMEM; + } + + memset( adapter->TxRing.MpTcbMem, 0, ( NUM_TCB * sizeof( MP_TCB ))); + + + /************************************************************************** + Setup some convenience pointers + *************************************************************************/ + tx_ring = (TX_RING_t *)&adapter->TxRing; + tcb = (MP_TCB *)adapter->TxRing.MpTcbMem; + + + /************************************************************************** + Allocate enough memory for the Tx descriptor ring, and allocate some + extra so that the ring can be aligned on a 4k boundary. + *************************************************************************/ + desc_size = ( sizeof( TX_DESC_ENTRY_t ) * NUM_DESC_PER_RING_TX ) + 4096 - 1; + tx_ring->pTxDescRingVa = (PTX_DESC_ENTRY_t)pci_alloc_consistent( adapter->pdev, + desc_size, + &tx_ring->pTxDescRingPa ); + if( !adapter->TxRing.pTxDescRingVa ) + { + DBG_ERROR( et131x_dbginfo, "Cannot alloc memory for Tx Ring\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -ENOMEM; + } + + + /************************************************************************** + Save physical address + + NOTE : pci_alloc_consistent(), used above to alloc DMA regions, ALWAYS + returns SAC (32-bit) addresses. If DAC (64-bit) addresses are + ever returned, make sure the high part is retrieved here before + storing the adjusted address. + *************************************************************************/ + tx_ring->pTxDescRingAdjustedPa = tx_ring->pTxDescRingPa; + + + /************************************************************************** + Align Tx Descriptor Ring on a 4k (0x1000) byte boundary + *************************************************************************/ + et131x_align_allocated_memory( adapter, + &tx_ring->pTxDescRingAdjustedPa, + &tx_ring->TxDescOffset, + 0x0FFF ); + + tx_ring->pTxDescRingVa += tx_ring->TxDescOffset; + + + /************************************************************************** + Allocate memory for the Tx status block + *************************************************************************/ + tx_ring->pTxStatusVa = pci_alloc_consistent( adapter->pdev, + sizeof( TX_STATUS_BLOCK_t ), + &tx_ring->pTxStatusPa ); + if( !adapter->TxRing.pTxStatusPa ) + { + DBG_ERROR( et131x_dbginfo, "Cannot alloc memory for Tx status block\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -ENOMEM; + } + + + /************************************************************************** + Allocate memory for a dummy buffer + *************************************************************************/ + tx_ring->pTxDummyBlkVa = pci_alloc_consistent( adapter->pdev, + NIC_MIN_PACKET_SIZE, + &tx_ring->pTxDummyBlkPa ); + if( !adapter->TxRing.pTxDummyBlkPa ) + { + DBG_ERROR( et131x_dbginfo, "Cannot alloc memory for Tx dummy buffer\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -ENOMEM; + } + + + DBG_LEAVE( et131x_dbginfo ); + return 0; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_tx_dma_memory_free + ****************************************************************************** + + DESCRIPTION : Free all memory allocated within this module + + PARAMETERS : adapter - pointer to our private adapter structure + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_tx_dma_memory_free( ET131X_ADAPTER *adapter ) +{ + int desc_size = 0; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_tx_dma_memory_free" ); + DBG_ENTER( et131x_dbginfo ); + + + if( adapter->TxRing.pTxDescRingVa ) + { + /********************************************************************** + Free memory relating to Tx rings here + *********************************************************************/ + adapter->TxRing.pTxDescRingVa -= adapter->TxRing.TxDescOffset; + + desc_size = ( sizeof( TX_DESC_ENTRY_t ) * NUM_DESC_PER_RING_TX ) + 4096 - 1; + + pci_free_consistent( adapter->pdev, + desc_size, + adapter->TxRing.pTxDescRingVa, + adapter->TxRing.pTxDescRingPa ); + + adapter->TxRing.pTxDescRingVa = NULL ; + } + + + /************************************************************************** + Free memory for the Tx status block + *************************************************************************/ + if( adapter->TxRing.pTxStatusVa ) + { + pci_free_consistent( adapter->pdev, + sizeof( TX_STATUS_BLOCK_t ), + adapter->TxRing.pTxStatusVa, + adapter->TxRing.pTxStatusPa ); + + adapter->TxRing.pTxStatusVa = NULL ; + } + + + /************************************************************************** + Free memory for the dummy buffer + *************************************************************************/ + if( adapter->TxRing.pTxDummyBlkVa ) + { + pci_free_consistent( adapter->pdev, + NIC_MIN_PACKET_SIZE, + adapter->TxRing.pTxDummyBlkVa, + adapter->TxRing.pTxDummyBlkPa ); + + adapter->TxRing.pTxDummyBlkVa = NULL ; + } + + + /************************************************************************** + Free the memory for MP_TCB structures + *************************************************************************/ + if( adapter->TxRing.MpTcbMem ) + { + kfree( adapter->TxRing.MpTcbMem ); + adapter->TxRing.MpTcbMem = NULL; + } + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : ConfigTxDmaRegs + ****************************************************************************** + + DESCRIPTION : Used to set up the tx dma section of the JAGCore. + + PARAMETERS : adapter - pointer to our private adapter structure + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void ConfigTxDmaRegs( ET131X_ADAPTER *pAdapter ) +{ + PTXDMA_t pTxDma; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "ConfigTxDmaRegs" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + First lets get a copy of the pointer + *************************************************************************/ + pTxDma = &pAdapter->CSRAddress->txdma; + + + /************************************************************************** + Load the hardware with the start of the transmit descriptor ring. + *************************************************************************/ + pTxDma->pr_base_hi.addr_hi = + (UINT32)( pAdapter->TxRing.pTxDescRingAdjustedPa >> 32 ); + pTxDma->pr_base_lo.addr_lo = + (UINT32)( pAdapter->TxRing.pTxDescRingAdjustedPa ); + + + /************************************************************************** + Initialise the transmit DMA engine + *************************************************************************/ + pTxDma->pr_num_des.value = NUM_DESC_PER_RING_TX - 1; + + + /************************************************************************** + Load the completion writeback physical address + + NOTE : pci_alloc_consistent(), used above to alloc DMA regions, ALWAYS + returns SAC (32-bit) addresses. If DAC (64-bit) addresses are + ever returned, make sure the high part is retrieved here before + storing the adjusted address. + *************************************************************************/ + pTxDma->dma_wb_base_hi.addr_hi = 0x0; + pTxDma->dma_wb_base_lo.addr_lo = pAdapter->TxRing.pTxStatusPa; + + memset( pAdapter->TxRing.pTxStatusVa, 0, sizeof( TX_STATUS_BLOCK_t )); + + + pTxDma->service_request.value = 0x0; + pAdapter->TxRing.txDmaReadyToSend.value = 0x0; + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: et131x_tx_dma_disable + ****************************************************************************** + DESCRIPTION: + Stop OF Tx_DMA on the ET1310 + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + N/A + + *****************************************************************************/ +void et131x_tx_dma_disable( ET131X_ADAPTER *pAdapter ) +{ + DBG_FUNC( "et131x_tx_dma_disable" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Setup the tramsmit dma configuration register + *************************************************************************/ + pAdapter->CSRAddress->txdma.csr.value = 0x101; + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: et131x_tx_dma_enable + ****************************************************************************** + DESCRIPTION: + re-start OF Tx_DMA on the ET1310. Mainly used after a return to the + D0 (full-power) state from a lower state. + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + N/A + + *****************************************************************************/ +void et131x_tx_dma_enable( ET131X_ADAPTER *pAdapter ) +{ + TXDMA_CSR_t csr = {0}; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_tx_dma_enable" ); + DBG_ENTER( et131x_dbginfo ); + + + if( pAdapter->RegistryPhyLoopbk ) + { + /********************************************************************** + TxDMA is disabled for loopback operation. + *********************************************************************/ + pAdapter->CSRAddress->txdma.csr.value = 0x101; + + } + else + { + /********************************************************************** + Setup the transmit dma configuration register for normal operation + *********************************************************************/ + csr.bits.sngl_epkt_mode = 1; + csr.bits.halt = 0; + csr.bits.cache_thrshld = pAdapter->RegistryDMACache; + + pAdapter->CSRAddress->txdma.csr.value = csr.value; + } + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_init_send + ****************************************************************************** + + DESCRIPTION : Initialize send data structures + + PARAMETERS : adapter - pointer to our private adapter structure + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_init_send( ET131X_ADAPTER *adapter ) +{ + PMP_TCB pMpTcb; + UINT32 TcbCount; + TX_RING_t *tx_ring; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_init_send" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Setup some convenience pointers + *************************************************************************/ + tx_ring = (TX_RING_t *)&adapter->TxRing; + pMpTcb = (PMP_TCB)adapter->TxRing.MpTcbMem; + + + tx_ring->TCBReadyQueueHead = pMpTcb; + + + /************************************************************************** + Go through and set up each TCB + *************************************************************************/ + for( TcbCount = 0; TcbCount < NUM_TCB; TcbCount++ ) + { + memset( pMpTcb, 0, sizeof( MP_TCB )); + + + /********************************************************************** + Set the link pointer in HW TCB to the next TCB in the chain. If + this is the last TCB in the chain, also set the tail pointer. + *********************************************************************/ + if( TcbCount < NUM_TCB - 1 ) + { + pMpTcb->Next = pMpTcb + 1; + } + else + { + tx_ring->TCBReadyQueueTail = pMpTcb; + pMpTcb->Next = (PMP_TCB)NULL; + } + + pMpTcb++; + } + + /************************************************************************** + Curr send queue should now be empty + *************************************************************************/ + tx_ring->CurrSendHead = (PMP_TCB)NULL; + tx_ring->CurrSendTail = (PMP_TCB)NULL; + + INIT_LIST_HEAD( &adapter->TxRing.SendWaitQueue ); + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: et131x_send_packets + ****************************************************************************** + + DESCRIPTION: + This function is called by the OS to send packets + + PARAMETERS : + skb - the packet(s) to send + netdev - the net_device struct corresponding to the device on which to + TX the above packet(s) + + RETURN : + 0 in almost all cases + non-zero value in extreme hard failure only + + *****************************************************************************/ +int et131x_send_packets( struct sk_buff *skb, struct net_device *netdev ) +{ + int status = 0; + ET131X_ADAPTER *pAdapter = NULL; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_send_packets" ); + DBG_TX_ENTER( et131x_dbginfo ); + + + pAdapter = netdev_priv( netdev ); + + + /************************************************************************** + Send these packets + + NOTE: The Linux Tx entry point is only given one packet at a time + to Tx, so the PacketCount and it's array used makes no sense here + *************************************************************************/ + + /************************************************************************** + Queue is not empty or TCB is not available + *************************************************************************/ + if( !list_empty( &pAdapter->TxRing.SendWaitQueue ) || + MP_TCB_RESOURCES_NOT_AVAILABLE( pAdapter )) + { + /********************************************************************** + NOTE - If there's an error on send, no need to queue the + packet under Linux; if we just send an error up to the netif + layer, it will resend the skb to us. + *********************************************************************/ + DBG_VERBOSE( et131x_dbginfo, + "TCB Resources Not Available\n" ); + status = -ENOMEM; + } + else + { + /********************************************************************** + We need to see if the link is up; if it's not, make the netif layer + think we're good and drop the packet + *********************************************************************/ + //if( MP_SHOULD_FAIL_SEND( pAdapter ) || pAdapter->DriverNoPhyAccess ) + if( MP_SHOULD_FAIL_SEND( pAdapter ) || pAdapter->DriverNoPhyAccess || + !netif_carrier_ok( netdev )) + { + DBG_VERBOSE( et131x_dbginfo, + "Can't Tx, Link is DOWN; drop the packet\n" ); + + dev_kfree_skb_any( skb ); + skb = NULL; + + pAdapter->net_stats.tx_dropped++; + } + else + { + status = et131x_send_packet( skb, pAdapter ); + + if( status == -ENOMEM ) + { + + /************************************************************** + NOTE - If there's an error on send, no need to queue the + packet under Linux; if we just send an error up to the netif + layer, it will resend the skb to us. + *************************************************************/ + DBG_WARNING( et131x_dbginfo, + "Resources problem, Queue tx packet\n" ); + } + else if( status != 0 ) + { + /************************************************************** + On any other error, make netif think we're OK and drop the + packet + *************************************************************/ + DBG_WARNING( et131x_dbginfo, + "General error, drop packet\n" ); + + dev_kfree_skb_any( skb ); + skb = NULL; + + pAdapter->net_stats.tx_dropped++; + } + } + } + + + DBG_TX_LEAVE( et131x_dbginfo ); + return status; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: et131x_send_packet + ****************************************************************************** + DESCRIPTION: + Do the work to send a packet + + Assumption: Send spinlock has been acquired + + PARAMETERS : + skb - the packet(s) to send + pAdapter - a pointer to the device's private adapter structure + + RETURN : + 0 in almost all cases + non-zero value in extreme hard failure only + + *****************************************************************************/ +int et131x_send_packet( struct sk_buff *skb, ET131X_ADAPTER *pAdapter ) +{ + int status = 0; + PMP_TCB pMpTcb = NULL; + PUINT16 pShBufVa; + unsigned long lockflags; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_send_packet" ); + DBG_TX_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Is our buffer scattered, or continuous? + *************************************************************************/ + if( skb_shinfo( skb )->nr_frags == 0 ) + { + DBG_TX( et131x_dbginfo, "Scattered buffer: NO\n" ); + } + else + { + DBG_TX( et131x_dbginfo, "Scattered buffer: YES, Num Frags: %d\n", + skb_shinfo( skb )->nr_frags ); + } + + + /************************************************************************** + All packets must have at least a MAC address and a protocol type + *************************************************************************/ + if( skb->len < ETH_HLEN ) + { + DBG_ERROR( et131x_dbginfo, "Packet size < ETH_HLEN (14 bytes)\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -EIO; + } + + + /************************************************************************** + Is this packet VLAN tagged? If so, is it a tag previously registered? + If not, drop the packet + + NOTE - We need not worry about the above note for now, as VLAN is handled + by the linux kernel (for the most part). + *************************************************************************/ +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) +#if defined __vlan_get_tag + { + unsigned short vlan_tag; + + if( __vlan_get_tag( skb, &vlan_tag ) == -EINVAL ) + { + DBG_TX( et131x_dbginfo, + "VLAN: No TX packet tag\n" ); + } + else + { + DBG_TX( et131x_dbginfo, + "VLAN: TX packet tag: %d\n", vlan_tag ); + } + } +#endif +#endif + + + /************************************************************************** + Get a TCB for this packet + *************************************************************************/ + spin_lock_irqsave( &pAdapter->TCBReadyQLock, lockflags ); + + pMpTcb = pAdapter->TxRing.TCBReadyQueueHead; + + if( pMpTcb == NULL ) + { + spin_unlock_irqrestore( &pAdapter->TCBReadyQLock, lockflags ); + + DBG_WARNING( et131x_dbginfo, "Can't obtain a TCB\n" ); + DBG_TX_LEAVE( et131x_dbginfo ); + return -ENOMEM; + } + + pAdapter->TxRing.TCBReadyQueueHead = pMpTcb->Next; + + if( pAdapter->TxRing.TCBReadyQueueHead == NULL ) + { + pAdapter->TxRing.TCBReadyQueueTail = NULL; + } + + spin_unlock_irqrestore( &pAdapter->TCBReadyQLock, lockflags ); + + pMpTcb->PacketLength = skb->len; + pMpTcb->Packet = skb; + + if(( skb->data != NULL ) && (( skb->len - skb->data_len ) >= 6 )) + { + pShBufVa = (PUINT16)skb->data; + + if(( pShBufVa [0] == 0xffff ) && + ( pShBufVa [1] == 0xffff ) && + ( pShBufVa [2] == 0xffff )) + { + MP_SET_FLAG( pMpTcb, fMP_DEST_BROAD ); + } + else if(( pShBufVa [0] & 0x3 ) == 0x0001 ) + { + MP_SET_FLAG( pMpTcb, fMP_DEST_MULTI ); + } + } + + pMpTcb->Next = NULL; + + + /************************************************************************** + Call the NIC specific send handler. + *************************************************************************/ + if( status == 0 ) + { + status = nic_send_packet( pAdapter, pMpTcb ); + } + + if( status != 0 ) + { + spin_lock_irqsave( &pAdapter->TCBReadyQLock, lockflags ); + + if( pAdapter->TxRing.TCBReadyQueueTail ) + { + pAdapter->TxRing.TCBReadyQueueTail->Next = pMpTcb; + } + else + { + /****************************************************************** + Apparently ready Q is empty. + *****************************************************************/ + pAdapter->TxRing.TCBReadyQueueHead = pMpTcb; + } + + pAdapter->TxRing.TCBReadyQueueTail = pMpTcb; + + spin_unlock_irqrestore( &pAdapter->TCBReadyQLock, lockflags ); + + DBG_TX_LEAVE( et131x_dbginfo ); + return status ; + } + + DBG_ASSERT( pAdapter->TxRing.nBusySend <= NUM_TCB ); + + + DBG_TX_LEAVE( et131x_dbginfo ); + return 0; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: nic_send_packet + ****************************************************************************** + DESCRIPTION: + NIC specific send handler. This version of the send routine is designed + for version B silicon. + + PARAMETERS : + pAdapter - pointer to our adapter + pMpTcb - pointer to MP_TCB + + RETURNS : + 0 or errno + + *****************************************************************************/ +int nic_send_packet( ET131X_ADAPTER *pAdapter, PMP_TCB pMpTcb ) +{ + UINT32 loopIndex; + TX_DESC_ENTRY_t CurDesc[24]; + UINT32 FragmentNumber = 0; + UINT32 iThisCopy, iRemainder; + struct sk_buff *pPacket = pMpTcb->Packet; + UINT32 FragListCount = skb_shinfo( pPacket )->nr_frags + 1; + struct skb_frag_struct *pFragList = &skb_shinfo( pPacket )->frags[0]; + unsigned long lockflags1, lockflags2; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "nic_send_packet" ); + DBG_TX_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Part of the optimizations of this send routine restrict us to + sending 24 fragments at a pass. In practice we should never see more + than 5 fragments. + + NOTE: The older version of this function (below) can handle any number + of fragments. If needed, we can call this function, although it is less + efficient. + *************************************************************************/ + if( FragListCount > 23 ) + { + DBG_TX_LEAVE( et131x_dbginfo ); + return -EIO; + } + + memset( CurDesc, 0, sizeof( TX_DESC_ENTRY_t ) * ( FragListCount + 1 )); + + for( loopIndex = 0; loopIndex < FragListCount; loopIndex++ ) + { + /********************************************************************** + If there is something in this element, lets get a descriptor from + the ring and get the necessary data + *********************************************************************/ + if( loopIndex == 0 ) + { + /****************************************************************** + If the fragments are smaller than a standard MTU, then map them + to a single descriptor in the Tx Desc ring. However, if they're + larger, as is possible with support for jumbo packets, then + split them each across 2 descriptors. + + This will work until we determine why the hardware doesn't seem + to like large fragments. + *****************************************************************/ + if(( pPacket->len - pPacket->data_len ) <= 1514 ) + { + DBG_TX( et131x_dbginfo, + "Got packet of length %d, " + "filling desc entry %d, " + "TCB: 0x%p\n", + ( pPacket->len - pPacket->data_len ), + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req, + pMpTcb ); + + CurDesc[FragmentNumber].DataBufferPtrHigh = 0; + + CurDesc[FragmentNumber].word2.bits.length_in_bytes = + pPacket->len - pPacket->data_len; + + /****************************************************************** + NOTE - Here, the dma_addr_t returned from pci_map_single() is + implicitly cast as a UINT32. Although dma_addr_t can be 64-bit, + the address returned by pci_map_single() is always 32-bit + addressable (as defined by the pci/dma subsystem) + ******************************************************************/ + CurDesc[FragmentNumber++].DataBufferPtrLow = pci_map_single( pAdapter->pdev, + pPacket->data, + pPacket->len - pPacket->data_len, + PCI_DMA_TODEVICE ); + } + else + { + DBG_TX( et131x_dbginfo, + "Got packet of length %d, " + "filling desc entry %d, " + "TCB: 0x%p\n", + ( pPacket->len - pPacket->data_len ), + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req, + pMpTcb ); + + CurDesc[FragmentNumber].DataBufferPtrHigh = 0; + + CurDesc[FragmentNumber].word2.bits.length_in_bytes = + (( pPacket->len - pPacket->data_len ) / 2 ); + + /****************************************************************** + NOTE - Here, the dma_addr_t returned from pci_map_single() is + implicitly cast as a UINT32. Although dma_addr_t can be 64-bit, + the address returned by pci_map_single() is always 32-bit + addressable (as defined by the pci/dma subsystem) + ******************************************************************/ + CurDesc[FragmentNumber++].DataBufferPtrLow = pci_map_single( pAdapter->pdev, + pPacket->data, + (( pPacket->len - pPacket->data_len ) / 2 ), + PCI_DMA_TODEVICE ); + CurDesc[FragmentNumber].DataBufferPtrHigh = 0; + + CurDesc[FragmentNumber].word2.bits.length_in_bytes = + (( pPacket->len - pPacket->data_len ) / 2 ); + + /****************************************************************** + NOTE - Here, the dma_addr_t returned from pci_map_single() is + implicitly cast as a UINT32. Although dma_addr_t can be 64-bit, + the address returned by pci_map_single() is always 32-bit + addressable (as defined by the pci/dma subsystem) + ******************************************************************/ + CurDesc[FragmentNumber++].DataBufferPtrLow = pci_map_single( pAdapter->pdev, + pPacket->data + (( pPacket->len - pPacket->data_len ) / 2 ), + (( pPacket->len - pPacket->data_len ) / 2 ), + PCI_DMA_TODEVICE ); + } + } + else + { + DBG_TX( et131x_dbginfo, + "Got packet of length %d," + "filling desc entry %d\n" + "TCB: 0x%p\n", + pFragList[loopIndex].size, + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req, + pMpTcb ); + + CurDesc[FragmentNumber].DataBufferPtrHigh = 0; + + + CurDesc[FragmentNumber].word2.bits.length_in_bytes = + pFragList[loopIndex - 1].size; + + /****************************************************************** + NOTE - Here, the dma_addr_t returned from pci_map_page() is + implicitly cast as a UINT32. Although dma_addr_t can be 64-bit, + the address returned by pci_map_page() is always 32-bit + addressable (as defined by the pci/dma subsystem) + ******************************************************************/ + CurDesc[FragmentNumber++].DataBufferPtrLow = pci_map_page( pAdapter->pdev, + pFragList[loopIndex - 1].page, + pFragList[loopIndex - 1].page_offset, + pFragList[loopIndex - 1].size, + PCI_DMA_TODEVICE ); + } + } + + if( FragmentNumber == 0 ) + { + DBG_WARNING( et131x_dbginfo, "No. frags is 0\n" ); + return -EIO; + } + + if( pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS ) + { + if( ++pAdapter->TxRing.TxPacketsSinceLastinterrupt == + pAdapter->RegistryTxNumBuffers ) + { + CurDesc[FragmentNumber - 1].word3.value = 0x5; + pAdapter->TxRing.TxPacketsSinceLastinterrupt = 0; + } + else + { + CurDesc[FragmentNumber - 1].word3.value = 0x1; + } + } + else + { + CurDesc[FragmentNumber - 1].word3.value = 0x5; + } + + CurDesc[0].word3.bits.f = 1; + + pMpTcb->WrIndexStart = pAdapter->TxRing.txDmaReadyToSend; + + pMpTcb->PacketStaleCount = 0; + + spin_lock_irqsave( &pAdapter->SendHWLock, lockflags1 ); + + iThisCopy = NUM_DESC_PER_RING_TX - pAdapter->TxRing.txDmaReadyToSend.bits.serv_req; + + if( iThisCopy >= FragmentNumber ) + { + iRemainder = 0; + iThisCopy = FragmentNumber; + } + else + { + iRemainder = FragmentNumber - iThisCopy; + } + + memcpy( pAdapter->TxRing.pTxDescRingVa + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req, + CurDesc, + sizeof( TX_DESC_ENTRY_t ) * iThisCopy ); + + + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req += iThisCopy; + + if(( pAdapter->TxRing.txDmaReadyToSend.bits.serv_req == 0 ) || + ( pAdapter->TxRing.txDmaReadyToSend.bits.serv_req == NUM_DESC_PER_RING_TX)) + { + if( pAdapter->TxRing.txDmaReadyToSend.bits.serv_req_wrap ) + { + pAdapter->TxRing.txDmaReadyToSend.value = 0; + } + else + { + pAdapter->TxRing.txDmaReadyToSend.value = 0x400; + } + } + + if( iRemainder ) + { + memcpy( pAdapter->TxRing.pTxDescRingVa, + CurDesc + iThisCopy, + sizeof( TX_DESC_ENTRY_t ) * iRemainder ); + + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req += iRemainder; + } + + if( pAdapter->TxRing.txDmaReadyToSend.bits.serv_req == 0 ) + { + if( pAdapter->TxRing.txDmaReadyToSend.value ) + { + pMpTcb->WrIndex.value = NUM_DESC_PER_RING_TX - 1; + } + else + { + pMpTcb->WrIndex.value = 0x400 | ( NUM_DESC_PER_RING_TX - 1 ); + } + } + else + { + pMpTcb->WrIndex.value = pAdapter->TxRing.txDmaReadyToSend.value - 1; + } + + spin_lock_irqsave( &pAdapter->TCBSendQLock, lockflags2 ); + + if( pAdapter->TxRing.CurrSendTail ) + { + pAdapter->TxRing.CurrSendTail->Next = pMpTcb; + } + else + { + pAdapter->TxRing.CurrSendHead = pMpTcb; + } + + pAdapter->TxRing.CurrSendTail = pMpTcb; + + DBG_ASSERT( pMpTcb->Next == NULL ); + + pAdapter->TxRing.nBusySend++; + + spin_unlock_irqrestore( &pAdapter->TCBSendQLock, lockflags2 ); + + + /************************************************************************** + Write the new write pointer back to the device. + *************************************************************************/ + pAdapter->CSRAddress->txdma.service_request.value = + pAdapter->TxRing.txDmaReadyToSend.value; + + + /************************************************************************** + For Gig only, we use Tx Interrupt coalescing. Enable the software + timer to wake us up if this packet isn't followed by N more. + *************************************************************************/ + if( pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS ) + { + pAdapter->CSRAddress->global.watchdog_timer = + pAdapter->RegistryTxTimeInterval * NANO_IN_A_MICRO; + } + + spin_unlock_irqrestore( &pAdapter->SendHWLock, lockflags1 ); + + + DBG_TX_LEAVE( et131x_dbginfo ); + return 0; +} +/*===========================================================================*/ + + + + +/* NOTE - For now, keep this older version of NICSendPacket around for + reference, even though it's not used */ +#if 0 + +/****************************************************************************** + ROUTINE: NICSendPacket + ****************************************************************************** + DESCRIPTION: + NIC specific send handler. This version of the send routine is designed + for version A silicon. + + Assumption: Send spinlock has been acquired + + PARAMETERS : + pAdapter - pointer to our adapter + pMpTcb - pointer to MP_TCB + pFragList - pointer to the frag list to be filled + + RETURNS : + 0 on succes, errno on failure + + *****************************************************************************/ +int nic_send_packet( ET131X_ADAPTER *pAdapter, PMP_TCB pMpTcb ) +{ + UINT32 loopIndex, fragIndex, loopEnd; + UINT32 iSplitFirstElement = 0; + UINT32 SegmentSize = 0; + TX_DESC_ENTRY_t CurDesc; + TX_DESC_ENTRY_t *CurDescPostCopy = NULL; + UINT32 SlotsAvailable; + TXDMA_SERVICE_COMPLETE_t ServiceComplete = pAdapter->CSRAddress->txdma.NewServiceComplete; + unsigned int lockflags1, lockflags2; + struct sk_buff *pPacket = pMpTcb->Packet; + UINT32 FragListCount = skb_shinfo( pPacket )->nr_frags + 1; + struct skb_frag_struct *pFragList = &skb_shinfo( pPacket )->frags[0]; + PGLOBAL_t pGbl; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "nic_send_packet" ); + DBG_TX_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Attempt to fix TWO hardware bugs: + 1) NEVER write an odd number of descriptors. + 2) If packet length is less than NIC_MIN_PACKET_SIZE, then pad the + packet to NIC_MIN_PACKET_SIZE bytes by adding a new last + descriptor IN HALF DUPLEX MODE ONLY + NOTE that (2) interacts with (1). If the packet is less than + NIC_MIN_PACKET_SIZE bytes then we will append a descriptor. Therefore + if it is even now, it will eventually end up odd, and so will need + adjusting. + + VLAN tags get involved since VLAN tags add another one or two + segments. + *************************************************************************/ + DBG_TX( et131x_dbginfo, + "pMpTcb->PacketLength: %d\n", pMpTcb->PacketLength ); + + if(( pAdapter->uiDuplexMode == 0 ) && ( pMpTcb->PacketLength < NIC_MIN_PACKET_SIZE )) + { + DBG_TX( et131x_dbginfo, + "HALF DUPLEX mode AND len < MIN_PKT_SIZE\n" ); + if(( FragListCount & 0x1 ) == 0 ) + { + DBG_TX( et131x_dbginfo, + "Even number of descs, split 1st elem\n" ); + iSplitFirstElement = 1; + //SegmentSize = pFragList[0].size / 2; + SegmentSize = ( pPacket->len - pPacket->data_len ) / 2; + } + } + else if( FragListCount & 0x1 ) + { + DBG_TX( et131x_dbginfo, + "Odd number of descs, split 1st elem\n" ); + + iSplitFirstElement = 1; + //SegmentSize = pFragList[0].size / 2; + SegmentSize = ( pPacket->len - pPacket->data_len ) / 2; + } + + spin_lock_irqsave( &pAdapter->SendHWLock, lockflags1 ); + + if( pAdapter->TxRing.txDmaReadyToSend.bits.serv_req_wrap == + ServiceComplete.bits.serv_cpl_wrap ) + { + /********************************************************************** + The ring hasn't wrapped. Slots available should be (RING_SIZE) - + the difference between the two pointers. + *********************************************************************/ + SlotsAvailable = NUM_DESC_PER_RING_TX - + ( pAdapter->TxRing.txDmaReadyToSend.bits.serv_req - ServiceComplete.bits.serv_cpl); + } + else + { + /********************************************************************** + The ring has wrapped. Slots available should be the difference + between the two pointers. + *********************************************************************/ + SlotsAvailable = ServiceComplete.bits.serv_cpl - + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req; + } + + if(( FragListCount + iSplitFirstElement ) > SlotsAvailable ) + { + DBG_WARNING( et131x_dbginfo, "Not Enough Space in Tx Desc Ring\n" ); + spin_unlock_irqrestore( &pAdapter->SendHWLock, lockflags1 ); + return -ENOMEM; + } + + loopEnd = ( FragListCount ) + iSplitFirstElement; + fragIndex = 0; + + DBG_TX( et131x_dbginfo, + "TCB : 0x%p\n", pMpTcb ); + DBG_TX( et131x_dbginfo, + "Packet (SKB) : 0x%p\t Packet->len: %d\t Packet->data_len: %d\n", + pPacket, pPacket->len, pPacket->data_len ); + + DBG_TX( et131x_dbginfo, + "FragListCount : %d\t iSplitFirstElement: %d\t loopEnd:%d\n", + FragListCount, iSplitFirstElement, loopEnd ); + + for( loopIndex = 0; loopIndex < loopEnd; loopIndex++ ) + { + if( loopIndex > iSplitFirstElement ) + { + fragIndex++; + } + + DBG_TX( et131x_dbginfo, "In loop, loopIndex: %d\t fragIndex: %d\n", + loopIndex, fragIndex ); + + + /********************************************************************** + If there is something in this element, let's get a descriptor from + the ring and get the necessary data + *********************************************************************/ + DBG_TX( et131x_dbginfo, + "Packet Length %d," + "filling desc entry %d\n", + pPacket->len, + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req ); + + // NOTE - Should we do a paranoia check here to make sure the fragment + // actually has a length? It's HIGHLY unlikely the fragment would + // contain no data... + if( 1 ) + { + // NOTE - Currently always getting 32-bit addrs, and dma_addr_t is + // only 32-bit, so leave "high" ptr value out for now + CurDesc.DataBufferPtrHigh = 0; + + CurDesc.word2.value = 0; + CurDesc.word3.value = 0; + + + if( fragIndex == 0 ) + { + if( iSplitFirstElement ) + { + DBG_TX( et131x_dbginfo, "Split first element: YES\n" ); + + if( loopIndex == 0 ) + { + DBG_TX( et131x_dbginfo, + "Got fragment of length %d, fragIndex: %d\n", + pPacket->len - pPacket->data_len, + fragIndex ); + DBG_TX( et131x_dbginfo, + "SegmentSize: %d\n", SegmentSize ); + + + CurDesc.word2.bits.length_in_bytes = SegmentSize; + CurDesc.DataBufferPtrLow = pci_map_single( pAdapter->pdev, + pPacket->data, + SegmentSize, + PCI_DMA_TODEVICE ); + DBG_TX( et131x_dbginfo, "pci_map_single() returns: 0x%08x\n", + CurDesc.DataBufferPtrLow ); + } + else + { + DBG_TX( et131x_dbginfo, + "Got fragment of length %d, fragIndex: %d\n", + pPacket->len - pPacket->data_len, + fragIndex ); + DBG_TX( et131x_dbginfo, + "Leftover Size: %d\n", + ( pPacket->len - pPacket->data_len - SegmentSize )); + + CurDesc.word2.bits.length_in_bytes = (( pPacket->len - pPacket->data_len ) - + SegmentSize ); + CurDesc.DataBufferPtrLow = pci_map_single( pAdapter->pdev, + ( pPacket->data + SegmentSize ), + ( pPacket->len - pPacket->data_len - + SegmentSize ), + PCI_DMA_TODEVICE ); + DBG_TX( et131x_dbginfo, "pci_map_single() returns: 0x%08x\n", + CurDesc.DataBufferPtrLow ); + } + } + else + { + DBG_TX( et131x_dbginfo, "Split first element: NO\n" ); + + CurDesc.word2.bits.length_in_bytes = pPacket->len - + pPacket->data_len; + + CurDesc.DataBufferPtrLow = pci_map_single( pAdapter->pdev, + pPacket->data, + ( pPacket->len - + pPacket->data_len ), + PCI_DMA_TODEVICE ); + DBG_TX( et131x_dbginfo, "pci_map_single() returns: 0x%08x\n", + CurDesc.DataBufferPtrLow ); + } + } + else + { + + CurDesc.word2.bits.length_in_bytes = pFragList[fragIndex - 1].size; + CurDesc.DataBufferPtrLow = pci_map_page( pAdapter->pdev, + pFragList[fragIndex - 1].page, + pFragList[fragIndex - 1].page_offset, + pFragList[fragIndex - 1].size, + PCI_DMA_TODEVICE ); + DBG_TX( et131x_dbginfo, "pci_map_page() returns: 0x%08x\n", + CurDesc.DataBufferPtrLow ); + } + + if( loopIndex == 0 ) + { + /************************************************************** + This is the first descriptor of the packet + *************************************************************/ + /************************************************************** + Set the "f" bit to indicate this is the first descriptor in + the packet. + *************************************************************/ + DBG_TX( et131x_dbginfo, "This is our FIRST descriptor\n" ); + CurDesc.word3.bits.f = 1; + + pMpTcb->WrIndexStart = pAdapter->TxRing.txDmaReadyToSend; + } + + if(( loopIndex == (loopEnd - 1 )) && + ( pAdapter->uiDuplexMode || + ( pMpTcb->PacketLength >= NIC_MIN_PACKET_SIZE ))) + { + /************************************************************** + This is the Last descriptor of the packet + *************************************************************/ + DBG_TX( et131x_dbginfo, "THIS is our LAST descriptor\n" ); + + if( pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS ) + { + if( ++pAdapter->TxRing.TxPacketsSinceLastinterrupt >= pAdapter->RegistryTxNumBuffers ) + { + CurDesc.word3.value = 0x5; + pAdapter->TxRing.TxPacketsSinceLastinterrupt = 0; + } + else + { + CurDesc.word3.value = 0x1; + } + } + else + { + CurDesc.word3.value = 0x5; + } + + + /************************************************************** + Following index will be used during freeing of packet + *************************************************************/ + pMpTcb->WrIndex = pAdapter->TxRing.txDmaReadyToSend; + pMpTcb->PacketStaleCount = 0; + } + + /****************************************************************** + Copy the descriptor (filled above) into the descriptor ring + at the next free entry. Advance the "next free entry" variable + *****************************************************************/ + memcpy( pAdapter->TxRing.pTxDescRingVa + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req, + &CurDesc, + sizeof( TX_DESC_ENTRY_t )); + + CurDescPostCopy = pAdapter->TxRing.pTxDescRingVa + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req; + + DBG_TX( et131x_dbginfo, "CURRENT DESCRIPTOR\n" ); + DBG_TX( et131x_dbginfo, "\tAddress : 0x%p\n", CurDescPostCopy ); + DBG_TX( et131x_dbginfo, "\tDataBufferPtrHigh : 0x%08x\n", CurDescPostCopy->DataBufferPtrHigh ); + DBG_TX( et131x_dbginfo, "\tDataBufferPtrLow : 0x%08x\n", CurDescPostCopy->DataBufferPtrLow ); + DBG_TX( et131x_dbginfo, "\tword2 : 0x%08x\n", CurDescPostCopy->word2.value ); + DBG_TX( et131x_dbginfo, "\tword3 : 0x%08x\n", CurDescPostCopy->word3.value ); + + + if( ++pAdapter->TxRing.txDmaReadyToSend.bits.serv_req >= NUM_DESC_PER_RING_TX ) + { + if( pAdapter->TxRing.txDmaReadyToSend.bits.serv_req_wrap ) + { + pAdapter->TxRing.txDmaReadyToSend.value = 0; + } + else + { + pAdapter->TxRing.txDmaReadyToSend.value = 0x400; + } + } + } + } + + + if(( pAdapter->uiDuplexMode == 0 ) && ( pMpTcb->PacketLength < NIC_MIN_PACKET_SIZE )) + { + // NOTE - Same 32/64-bit issue as above... + CurDesc.DataBufferPtrHigh = 0x0; + CurDesc.DataBufferPtrLow = pAdapter->TxRing.pTxDummyBlkPa; + CurDesc.word2.value = 0; + + if( pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS ) + { + if( ++pAdapter->TxRing.TxPacketsSinceLastinterrupt >= pAdapter->RegistryTxNumBuffers ) + { + CurDesc.word3.value = 0x5; + pAdapter->TxRing.TxPacketsSinceLastinterrupt = 0; + } + else + { + CurDesc.word3.value = 0x1; + } + } + else + { + CurDesc.word3.value = 0x5; + } + + CurDesc.word2.bits.length_in_bytes = NIC_MIN_PACKET_SIZE - pMpTcb->PacketLength; + + pMpTcb->WrIndex = pAdapter->TxRing.txDmaReadyToSend; + + memcpy( pAdapter->TxRing.pTxDescRingVa + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req, + &CurDesc, + sizeof( TX_DESC_ENTRY_t )); + + CurDescPostCopy = pAdapter->TxRing.pTxDescRingVa + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req; + + DBG_TX( et131x_dbginfo, "CURRENT DESCRIPTOR\n" ); + DBG_TX( et131x_dbginfo, "\tAddress : 0x%p\n", CurDescPostCopy ); + DBG_TX( et131x_dbginfo, "\tDataBufferPtrHigh : 0x%08x\n", CurDescPostCopy->DataBufferPtrHigh ); + DBG_TX( et131x_dbginfo, "\tDataBufferPtrLow : 0x%08x\n", CurDescPostCopy->DataBufferPtrLow ); + DBG_TX( et131x_dbginfo, "\tword2 : 0x%08x\n", CurDescPostCopy->word2.value ); + DBG_TX( et131x_dbginfo, "\tword3 : 0x%08x\n", CurDescPostCopy->word3.value ); + + + if( ++pAdapter->TxRing.txDmaReadyToSend.bits.serv_req >= NUM_DESC_PER_RING_TX ) + { + if( pAdapter->TxRing.txDmaReadyToSend.bits.serv_req_wrap ) + { + pAdapter->TxRing.txDmaReadyToSend.value = 0; + } + else + { + pAdapter->TxRing.txDmaReadyToSend.value = 0x400; + } + } + + DBG_TX( et131x_dbginfo, "Padding descriptor %d by %d bytes\n", + //pAdapter->TxRing.txDmaReadyToSend.value, + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req, + NIC_MIN_PACKET_SIZE - pMpTcb->PacketLength ); + } + + spin_lock_irqsave( &pAdapter->TCBSendQLock, lockflags2 ); + + if( pAdapter->TxRing.CurrSendTail ) + { + pAdapter->TxRing.CurrSendTail->Next = pMpTcb; + } + else + { + pAdapter->TxRing.CurrSendHead = pMpTcb; + } + + pAdapter->TxRing.CurrSendTail = pMpTcb; + + DBG_ASSERT( pMpTcb->Next == NULL ); + + pAdapter->TxRing.nBusySend++; + + spin_unlock_irqrestore( &pAdapter->TCBSendQLock, lockflags2 ); + + + /************************************************************************** + Write the new write pointer back to the device. + *************************************************************************/ + pAdapter->CSRAddress->txdma.service_request.value = pAdapter->TxRing.txDmaReadyToSend.value; + +#if ( ET131X_DBG == 1 ) + DumpDeviceBlock( DBG_TX_ON, pAdapter, 1 ); +#endif + + + /************************************************************************** + Map a local pointer to the global section of the JAGCore + *************************************************************************/ + pGbl = &pAdapter->CSRAddress->global; + + + /************************************************************************** + For Gig only, we use Tx Interrupt coalescing. Enable the software + timer to wake us up if this packet isn't followed by N more. + *************************************************************************/ + if( pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS ) + { + pAdapter->CSRAddress->global.watchdog_timer = + pAdapter->RegistryTxTimeInterval * NANO_IN_A_MICRO; + } + + spin_unlock_irqrestore( &pAdapter->SendHWLock, lockflags1 ); + + + DBG_TX_LEAVE( et131x_dbginfo ); + return 0; +} +/*===========================================================================*/ +#endif + + + + +/****************************************************************************** + ROUTINE: et131x_free_send_packet + ****************************************************************************** + DESCRIPTION: + Recycle a MP_TCB and complete the packet if necessary + + Assumption: Send spinlock has been acquired + + PARAMETERS : + pAdapter - pointer to our adapter + pMpTcb - pointer to MP_TCB + + RETURNS : + NONE + + *****************************************************************************/ +__inline void et131x_free_send_packet( ET131X_ADAPTER *pAdapter, PMP_TCB pMpTcb ) +{ + unsigned long lockflags; + TX_DESC_ENTRY_t *desc = NULL; + struct net_device_stats *stats = &pAdapter->net_stats; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_free_send_packet" ); + + + if( MP_TEST_FLAG( pMpTcb, fMP_DEST_BROAD ) ) + { + atomic_inc( &pAdapter->Stats.brdcstxmt ); + } + else if( MP_TEST_FLAG( pMpTcb, fMP_DEST_MULTI )) + { + atomic_inc( &pAdapter->Stats.multixmt ); + } + else + { + atomic_inc( &pAdapter->Stats.unixmt ); + } + + if( pMpTcb->Packet ) + { + stats->tx_bytes += pMpTcb->Packet->len; + + + /********************************************************************** + Iterate through the TX descriptors on the ring corresponding to this + packet and umap the fragments they point to + *********************************************************************/ + DBG_TX( et131x_dbginfo, "Unmap descriptors Here\n" ); + + DBG_TX( et131x_dbginfo, + "TCB : 0x%p\n", pMpTcb ); + + DBG_TX( et131x_dbginfo, + "TCB Next : 0x%p\n", pMpTcb->Next ); + + DBG_TX( et131x_dbginfo, + "TCB PacketLength : %d\n", pMpTcb->PacketLength ); + + DBG_TX( et131x_dbginfo, + "TCB WrIndex.value : 0x%08x\n", pMpTcb->WrIndexStart.value ); + DBG_TX( et131x_dbginfo, + "TCB WrIndex.serv_req : %d\n", pMpTcb->WrIndexStart.bits.serv_req ); + + DBG_TX( et131x_dbginfo, + "TCB WrIndex.value : 0x%08x\n", pMpTcb->WrIndex.value ); + DBG_TX( et131x_dbginfo, + "TCB WrIndex.serv_req : %d\n", pMpTcb->WrIndex.bits.serv_req ); + + do + { + desc = (TX_DESC_ENTRY_t *)( pAdapter->TxRing.pTxDescRingVa + + pMpTcb->WrIndexStart.bits.serv_req ); + + DBG_TX( et131x_dbginfo, "CURRENT DESCRIPTOR\n" ); + DBG_TX( et131x_dbginfo, "\tAddress : 0x%p\n", desc ); + DBG_TX( et131x_dbginfo, "\tDataBufferPtrHigh : 0x%08x\n", desc->DataBufferPtrHigh ); + DBG_TX( et131x_dbginfo, "\tDataBufferPtrLow : 0x%08x\n", desc->DataBufferPtrLow ); + DBG_TX( et131x_dbginfo, "\tword2 : 0x%08x\n", desc->word2.value ); + DBG_TX( et131x_dbginfo, "\tword3 : 0x%08x\n", desc->word3.value ); + + pci_unmap_single( pAdapter->pdev, + desc->DataBufferPtrLow, + desc->word2.value, + PCI_DMA_TODEVICE ); + + if( ++pMpTcb->WrIndexStart.bits.serv_req >= NUM_DESC_PER_RING_TX ) + { + if( pMpTcb->WrIndexStart.bits.serv_req_wrap ) + { + pMpTcb->WrIndexStart.value = 0; + } + else + { + pMpTcb->WrIndexStart.value = 0x400; + } + } + } + while( desc != ( pAdapter->TxRing.pTxDescRingVa + + pMpTcb->WrIndex.bits.serv_req )); + + DBG_TX( et131x_dbginfo, + "Free Packet (SKB) : 0x%p\n", pMpTcb->Packet ); + + dev_kfree_skb_any( pMpTcb->Packet ); + } + + memset( pMpTcb, 0, sizeof( MP_TCB )); + + + /************************************************************************** + Add the TCB to the Ready Q + *************************************************************************/ + spin_lock_irqsave( &pAdapter->TCBReadyQLock, lockflags ); + + pAdapter->Stats.opackets++; + + if( pAdapter->TxRing.TCBReadyQueueTail ) + { + pAdapter->TxRing.TCBReadyQueueTail->Next = pMpTcb; + } + else + { + /********************************************************************** + Apparently ready Q is empty. + *********************************************************************/ + pAdapter->TxRing.TCBReadyQueueHead = pMpTcb; + } + + pAdapter->TxRing.TCBReadyQueueTail = pMpTcb; + + spin_unlock_irqrestore( &pAdapter->TCBReadyQLock, lockflags ); + + + DBG_ASSERT( pAdapter->TxRing.nBusySend >= 0 ); + + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: et131x_free_busy_send_packets + ****************************************************************************** + DESCRIPTION: + Free and complete the stopped active sends + + Assumption: Send spinlock has been acquired + + PARAMETERS : + pAdapter - pointer to our adapter + + RETURNS : + NONE + + *****************************************************************************/ +void et131x_free_busy_send_packets( ET131X_ADAPTER *pAdapter ) +{ + PMP_TCB pMpTcb; + struct list_head *pEntry; + struct sk_buff *pPacket = NULL; + unsigned long lockflags; + UINT32 FreeCounter = 0; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_free_busy_send_packets" ); + DBG_ENTER( et131x_dbginfo ); + + + while( !list_empty( &pAdapter->TxRing.SendWaitQueue )) + { + spin_lock_irqsave( &pAdapter->SendWaitLock, lockflags ); + + pAdapter->TxRing.nWaitSend--; + spin_unlock_irqrestore( &pAdapter->SendWaitLock, lockflags ); + + pEntry = pAdapter->TxRing.SendWaitQueue.next; + + pPacket = NULL; + } + + pAdapter->TxRing.nWaitSend = 0; + + + /************************************************************************** + Any packets being sent? Check the first TCB on the send list + *************************************************************************/ + spin_lock_irqsave( &pAdapter->TCBSendQLock, lockflags ); + + pMpTcb = pAdapter->TxRing.CurrSendHead; + + while(( pMpTcb != NULL ) && ( FreeCounter < NUM_TCB )) + { + PMP_TCB pNext = pMpTcb->Next; + + pAdapter->TxRing.CurrSendHead = pNext; + + if( pNext == NULL ) + { + pAdapter->TxRing.CurrSendTail = NULL; + } + + pAdapter->TxRing.nBusySend--; + + spin_unlock_irqrestore( &pAdapter->TCBSendQLock, lockflags ); + + DBG_VERBOSE( et131x_dbginfo, + "pMpTcb = 0x%p\n", + pMpTcb ); + + FreeCounter++; + MP_FREE_SEND_PACKET_FUN( pAdapter, pMpTcb ); + + spin_lock_irqsave( &pAdapter->TCBSendQLock, lockflags ); + + pMpTcb = pAdapter->TxRing.CurrSendHead; + } + + if( FreeCounter == NUM_TCB ) + { + DBG_ERROR( et131x_dbginfo, + "MpFreeBusySendPackets exitted loop for a bad reason\n" ); + BUG(); + } + + spin_unlock_irqrestore( &pAdapter->TCBSendQLock, lockflags ); + + pAdapter->TxRing.nBusySend = 0; + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: et131x_handle_send_interrupt + ****************************************************************************** + DESCRIPTION: + Interrupt handler for sending processing + Re-claim the send resources, complete sends and get more to send from + the send wait queue + + Assumption: Send spinlock has been acquired + + PARAMETERS : + pAdapter - pointer to our adapter + + RETURNS : + Nothing + + *****************************************************************************/ +void et131x_handle_send_interrupt( ET131X_ADAPTER *pAdapter ) +{ + DBG_FUNC( "et131x_handle_send_interrupt" ); + DBG_TX_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Mark as completed any packets which have been sent by the device. + *************************************************************************/ + et131x_update_tcb_list( pAdapter ); + + + /************************************************************************** + If we queued any transmits because we didn't have any TCBs earlier, + dequeue and send those packets now, as long as we have free TCBs. + *************************************************************************/ + et131x_check_send_wait_list( pAdapter ); + + + DBG_TX_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: et131x_update_tcb_list + ****************************************************************************** + DESCRIPTION: + Helper routine for Send Interrupt handler. Re-claims the send + resources and completes sends. Can also be called as part of the NIC + send routine when the "ServiceComplete" indication has wrapped. + + Assumption: + + PARAMETERS : + pAdapter - pointer to our adapter + + RETURNS : + Nothing + + *****************************************************************************/ +void et131x_update_tcb_list( ET131X_ADAPTER *pAdapter ) +{ + unsigned long lockflags; + TXDMA_SERVICE_COMPLETE_t ServiceComplete = pAdapter->CSRAddress->txdma.NewServiceComplete; + PMP_TCB pMpTcb; + /*-----------------------------------------------------------------------*/ + + + /************************************************************************** + Has the ring wrapped? Process any descriptors that do not have + the same "wrap" indicator as the current completion indicator + *************************************************************************/ + spin_lock_irqsave( &pAdapter->TCBSendQLock, lockflags ); + + pMpTcb = pAdapter->TxRing.CurrSendHead; + + if( ServiceComplete.bits.serv_cpl_wrap ) + { + while( pMpTcb && + !pMpTcb->WrIndex.bits.serv_req_wrap && + ( pMpTcb->WrIndex.bits.serv_req > ServiceComplete.bits.serv_cpl )) + { + PMP_TCB pNext = pMpTcb->Next; + + pAdapter->TxRing.CurrSendHead = pNext; + + if( pNext == NULL ) + { + pAdapter->TxRing.CurrSendTail = NULL; + } + + pAdapter->TxRing.nBusySend--; + + spin_unlock_irqrestore( &pAdapter->TCBSendQLock, lockflags ); + MP_FREE_SEND_PACKET_FUN( pAdapter, pMpTcb ); + spin_lock_irqsave( &pAdapter->TCBSendQLock, lockflags ); + + + /****************************************************************** + Goto the next packet + *****************************************************************/ + pMpTcb = pAdapter->TxRing.CurrSendHead; + } + } + else + { + while( pMpTcb && + pMpTcb->WrIndex.bits.serv_req_wrap && + ( pMpTcb->WrIndex.bits.serv_req > ServiceComplete.bits.serv_cpl )) + { + PMP_TCB pNext = pMpTcb->Next; + + pAdapter->TxRing.CurrSendHead = pNext; + + if( pNext == NULL ) + { + pAdapter->TxRing.CurrSendTail = NULL; + } + + pAdapter->TxRing.nBusySend--; + + spin_unlock_irqrestore( &pAdapter->TCBSendQLock, lockflags ); + MP_FREE_SEND_PACKET_FUN( pAdapter, pMpTcb ); + spin_lock_irqsave( &pAdapter->TCBSendQLock, lockflags ); + + + /****************************************************************** + Goto the next packet + *****************************************************************/ + pMpTcb = pAdapter->TxRing.CurrSendHead; + } + } + + while( pMpTcb && + ( ServiceComplete.bits.serv_cpl_wrap == pMpTcb->WrIndex.bits.serv_req_wrap ) && + ( ServiceComplete.bits.serv_cpl > pMpTcb->WrIndex.bits.serv_req )) + { + PMP_TCB pNext = pMpTcb->Next; + + pAdapter->TxRing.CurrSendHead = pNext; + + if( pNext == NULL ) + { + pAdapter->TxRing.CurrSendTail = NULL; + } + + pAdapter->TxRing.nBusySend--; + + spin_unlock_irqrestore( &pAdapter->TCBSendQLock, lockflags ); + MP_FREE_SEND_PACKET_FUN( pAdapter, pMpTcb ); + spin_lock_irqsave( &pAdapter->TCBSendQLock, lockflags ); + + + /********************************************************************** + Goto the next packet + *********************************************************************/ + pMpTcb = pAdapter->TxRing.CurrSendHead; + } + + + /* Wake up the queue when we hit a low-water mark */ + if( pAdapter->TxRing.nBusySend <= ( NUM_TCB / 3 )) + { + netif_wake_queue( pAdapter->netdev ); + } + + spin_unlock_irqrestore( &pAdapter->TCBSendQLock, lockflags ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: et131x_check_send_wait_list + ****************************************************************************** + DESCRIPTION: + Helper routine for the interrupt handler. Takes packets from the send + wait queue and posts them to the device (if room available). + + Assumption: + + PARAMETERS : + pAdapter - pointer to our adapter + + RETURNS : + Nothing + + *****************************************************************************/ +void et131x_check_send_wait_list( ET131X_ADAPTER *pAdapter ) +{ + unsigned long lockflags; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_check_send_wait_list" ); + + + spin_lock_irqsave( &pAdapter->SendWaitLock, lockflags ); + + while( !list_empty( &pAdapter->TxRing.SendWaitQueue ) && + MP_TCB_RESOURCES_AVAILABLE( pAdapter )) + { + struct list_head *pEntry; + + DBG_VERBOSE( et131x_dbginfo, + "Tx packets on the wait queue\n" ); + + pEntry = pAdapter->TxRing.SendWaitQueue.next; + + pAdapter->TxRing.nWaitSend--; + + DBG_WARNING( et131x_dbginfo, + "MpHandleSendInterrupt - sent a queued pkt. Waiting %d\n", + pAdapter->TxRing.nWaitSend ); + } + + spin_unlock_irqrestore( &pAdapter->SendWaitLock, lockflags ); + + return; +} +/*===========================================================================*/ + --- linux-2.6.27.orig/ubuntu/et131x/ET1310_phy.h +++ linux-2.6.27/ubuntu/et131x/ET1310_phy.h @@ -0,0 +1,1228 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * ET1310_phy.h - Defines, structs, enums, prototypes, etc. pertaining to the + * PHY. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2006/01/18 22:18:33 $ + $Revision: 1.10 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +#ifndef _ET1310_PHY_H_ +#define _ET1310_PHY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + + + +/****************************************************************************** + INCLUDES + *****************************************************************************/ +#include "ET1310_common.h" + + + + +#define TRUEPHY_SUCCESS 0 +#define TRUEPHY_FAILURE 1 +typedef void *TRUEPHY_HANDLE; +typedef void *TRUEPHY_PLATFORM_HANDLE; +typedef void *TRUEPHY_OSAL_HANDLE; + + + + +/****************************************************************************** + CONSTANTS for PHY Register + *****************************************************************************/ +/* MI Register Addresses */ +#define MI_CONTROL_REG 0 +#define MI_STATUS_REG 1 +#define MI_PHY_IDENTIFIER_1_REG 2 +#define MI_PHY_IDENTIFIER_2_REG 3 +#define MI_AUTONEG_ADVERTISEMENT_REG 4 +#define MI_AUTONEG_LINK_PARTNER_ABILITY_REG 5 +#define MI_AUTONEG_EXPANSION_REG 6 +#define MI_AUTONEG_NEXT_PAGE_TRANSMIT_REG 7 +#define MI_LINK_PARTNER_NEXT_PAGE_REG 8 +#define MI_1000BASET_CONTROL_REG 9 +#define MI_1000BASET_STATUS_REG 10 +#define MI_RESERVED11_REG 11 +#define MI_RESERVED12_REG 12 +#define MI_RESERVED13_REG 13 +#define MI_RESERVED14_REG 14 +#define MI_EXTENDED_STATUS_REG 15 + +/* VMI Register Addresses */ +#define VMI_RESERVED16_REG 16 +#define VMI_RESERVED17_REG 17 +#define VMI_RESERVED18_REG 18 +#define VMI_LOOPBACK_CONTROL_REG 19 +#define VMI_RESERVED20_REG 20 +#define VMI_MI_CONTROL_REG 21 +#define VMI_PHY_CONFIGURATION_REG 22 +#define VMI_PHY_CONTROL_REG 23 +#define VMI_INTERRUPT_MASK_REG 24 +#define VMI_INTERRUPT_STATUS_REG 25 +#define VMI_PHY_STATUS_REG 26 +#define VMI_LED_CONTROL_1_REG 27 +#define VMI_LED_CONTROL_2_REG 28 +#define VMI_RESERVED29_REG 29 +#define VMI_RESERVED30_REG 30 +#define VMI_RESERVED31_REG 31 + + + + +/****************************************************************************** + PHY Register Mapping(MI) Management Interface Regs + *****************************************************************************/ +typedef struct _MI_REGS_t +{ + UCHAR bmcr; // Basic mode control reg(Reg 0x00) + UCHAR bmsr; // Basic mode status reg(Reg 0x01) + UCHAR idr1; // Phy identifier reg 1(Reg 0x02) + UCHAR idr2; // Phy identifier reg 2(Reg 0x03) + UCHAR anar; // Auto-Negotiation advertisement(Reg 0x04) + UCHAR anlpar; // Auto-Negotiation link Partner Ability(Reg 0x05) + UCHAR aner; // Auto-Negotiation expansion reg(Reg 0x06) + UCHAR annptr; // Auto-Negotiation next page transmit reg(Reg 0x07) + UCHAR lpnpr; // link partner next page reg(Reg 0x08) + UCHAR gcr; // Gigabit basic mode control reg(Reg 0x09) + UCHAR gsr; // Gigabit basic mode status reg(Reg 0x0A) + UCHAR mi_res1[4]; // Future use by MI working group(Reg 0x0B - 0x0E) + UCHAR esr; // Extended status reg(Reg 0x0F) + UCHAR mi_res2[3]; // Future use by MI working group(Reg 0x10 - 0x12) + UCHAR loop_ctl; // Loopback Control Reg(Reg 0x13) + UCHAR mi_res3; // Future use by MI working group(Reg 0x14) + UCHAR mcr; // MI Control Reg(Reg 0x15) + UCHAR pcr; // Configuration Reg(Reg 0x16) + UCHAR phy_ctl; // PHY Control Reg(Reg 0x17) + UCHAR imr; // Interrupt Mask Reg(Reg 0x18) + UCHAR isr; // Interrupt Status Reg(Reg 0x19) + UCHAR psr; // PHY Status Reg(Reg 0x1A) + UCHAR lcr1; // LED Control 1 Reg(Reg 0x1B) + UCHAR lcr2; // LED Control 2 Reg(Reg 0x1C) + UCHAR mi_res4[3]; // Future use by MI working group(Reg 0x1D - 0x1F) +} +MI_REGS_t, *PMI_REGS_t; + + + + +/****************************************************************************** + MI Register 0: Basic mode control register + *****************************************************************************/ +typedef union _MI_BMCR_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 reset:1; //bit 15 + UINT16 loopback:1; //bit 14 + UINT16 speed_sel:1; //bit 13 + UINT16 enable_autoneg:1; //bit 12 + UINT16 power_down:1; //bit 11 + UINT16 isolate:1; //bit 10 + UINT16 restart_autoneg:1; //bit 9 + UINT16 duplex_mode:1; //bit 8 + UINT16 col_test:1; //bit 7 + UINT16 speed_1000_sel:1; //bit 6 + UINT16 res1:6; //bits 0-5 + #else + UINT16 res1:6; //bits 0-5 + UINT16 speed_1000_sel:1; //bit 6 + UINT16 col_test:1; //bit 7 + UINT16 duplex_mode:1; //bit 8 + UINT16 restart_autoneg:1; //bit 9 + UINT16 isolate:1; //bit 10 + UINT16 power_down:1; //bit 11 + UINT16 enable_autoneg:1; //bit 12 + UINT16 speed_sel:1; //bit 13 + UINT16 loopback:1; //bit 14 + UINT16 reset:1; //bit 15 + #endif + } bits; +} +MI_BMCR_t, *PMI_BMCR_t; + + + + +/****************************************************************************** + MI Register 1: Basic mode status register + *****************************************************************************/ +typedef union _MI_BMSR_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 link_100T4:1; //bit 15 + UINT16 link_100fdx:1; //bit 14 + UINT16 link_100hdx:1; //bit 13 + UINT16 link_10fdx:1; //bit 12 + UINT16 link_10hdx:1; //bit 11 + UINT16 link_100T2fdx:1; //bit 10 + UINT16 link_100T2hdx:1; //bit 9 + UINT16 extend_status:1; //bit 8 + UINT16 res1:1; //bit 7 + UINT16 preamble_supress:1; //bit 6 + UINT16 auto_neg_complete:1; //bit 5 + UINT16 remote_fault:1; //bit 4 + UINT16 auto_neg_able:1; //bit 3 + UINT16 link_status:1; //bit 2 + UINT16 jabber_detect:1; //bit 1 + UINT16 ext_cap:1; //bit 0 + #else + UINT16 ext_cap:1; //bit 0 + UINT16 jabber_detect:1; //bit 1 + UINT16 link_status:1; //bit 2 + UINT16 auto_neg_able:1; //bit 3 + UINT16 remote_fault:1; //bit 4 + UINT16 auto_neg_complete:1; //bit 5 + UINT16 preamble_supress:1; //bit 6 + UINT16 res1:1; //bit 7 + UINT16 extend_status:1; //bit 8 + UINT16 link_100T2hdx:1; //bit 9 + UINT16 link_100T2fdx:1; //bit 10 + UINT16 link_10hdx:1; //bit 11 + UINT16 link_10fdx:1; //bit 12 + UINT16 link_100hdx:1; //bit 13 + UINT16 link_100fdx:1; //bit 14 + UINT16 link_100T4:1; //bit 15 + #endif + } bits; +} +MI_BMSR_t, *PMI_BMSR_t; + + + + +/****************************************************************************** + MI Register 2: Physical Identifier 1 + *****************************************************************************/ +typedef union _MI_IDR1_t +{ + UINT16 value; + struct + { + UINT16 ieee_address:16; //0x0282 default(bits 0-15) + } bits; +} +MI_IDR1_t, *PMI_IDR1_t; + + + + +/****************************************************************************** + MI Register 3: Physical Identifier 2 + *****************************************************************************/ +typedef union _MI_IDR2_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 ieee_address:6; //111100 default(bits 10-15) + UINT16 model_no:6; //000001 default(bits 4-9) + UINT16 rev_no:4; //0010 default(bits 0-3) + #else + UINT16 rev_no:4; //0010 default(bits 0-3) + UINT16 model_no:6; //000001 default(bits 4-9) + UINT16 ieee_address:6; //111100 default(bits 10-15) + #endif + } bits; +} +MI_IDR2_t, *PMI_IDR2_t; + + + + +/****************************************************************************** + MI Register 4: Auto-negotiation advertisement register + *****************************************************************************/ +typedef union _MI_ANAR_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 np_indication:1; //bit 15 + UINT16 res2:1; //bit 14 + UINT16 remote_fault:1; //bit 13 + UINT16 res1:1; //bit 12 + UINT16 cap_asmpause:1; //bit 11 + UINT16 cap_pause:1; //bit 10 + UINT16 cap_100T4:1; //bit 9 + UINT16 cap_100fdx:1; //bit 8 + UINT16 cap_100hdx:1; //bit 7 + UINT16 cap_10fdx:1; //bit 6 + UINT16 cap_10hdx:1; //bit 5 + UINT16 selector:5; //bits 0-4 + #else + UINT16 selector:5; //bits 0-4 + UINT16 cap_10hdx:1; //bit 5 + UINT16 cap_10fdx:1; //bit 6 + UINT16 cap_100hdx:1; //bit 7 + UINT16 cap_100fdx:1; //bit 8 + UINT16 cap_100T4:1; //bit 9 + UINT16 cap_pause:1; //bit 10 + UINT16 cap_asmpause:1; //bit 11 + UINT16 res1:1; //bit 12 + UINT16 remote_fault:1; //bit 13 + UINT16 res2:1; //bit 14 + UINT16 np_indication:1; //bit 15 + #endif + } bits; +} +MI_ANAR_t, *PMI_ANAR_t; + + + + +/****************************************************************************** + MI Register 5: Auto-negotiation link partner advertisement register + *****************************************************************************/ +typedef struct _MI_ANLPAR_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 np_indication:1; //bit 15 + UINT16 acknowledge:1; //bit 14 + UINT16 remote_fault:1; //bit 13 + UINT16 res1:1; //bit 12 + UINT16 cap_asmpause:1; //bit 11 + UINT16 cap_pause:1; //bit 10 + UINT16 cap_100T4:1; //bit 9 + UINT16 cap_100fdx:1; //bit 8 + UINT16 cap_100hdx:1; //bit 7 + UINT16 cap_10fdx:1; //bit 6 + UINT16 cap_10hdx:1; //bit 5 + UINT16 selector:5; //bits 0-4 + #else + UINT16 selector:5; //bits 0-4 + UINT16 cap_10hdx:1; //bit 5 + UINT16 cap_10fdx:1; //bit 6 + UINT16 cap_100hdx:1; //bit 7 + UINT16 cap_100fdx:1; //bit 8 + UINT16 cap_100T4:1; //bit 9 + UINT16 cap_pause:1; //bit 10 + UINT16 cap_asmpause:1; //bit 11 + UINT16 res1:1; //bit 12 + UINT16 remote_fault:1; //bit 13 + UINT16 acknowledge:1; //bit 14 + UINT16 np_indication:1; //bit 15 + #endif + } bits; +} +MI_ANLPAR_t, *PMI_ANLPAR_t; + + + + +/****************************************************************************** + MI Register 6: Auto-negotiation expansion register + *****************************************************************************/ +typedef union _MI_ANER_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 res:11; //bits 5-15 + UINT16 pdf:1; //bit 4 + UINT16 lp_np_able:1; //bit 3 + UINT16 np_able:1; //bit 2 + UINT16 page_rx:1; //bit 1 + UINT16 lp_an_able:1; //bit 0 + #else + UINT16 lp_an_able:1; //bit 0 + UINT16 page_rx:1; //bit 1 + UINT16 np_able:1; //bit 2 + UINT16 lp_np_able:1; //bit 3 + UINT16 pdf:1; //bit 4 + UINT16 res:11; //bits 5-15 + #endif + } bits; +} +MI_ANER_t, *PMI_ANER_t; + + + + +/****************************************************************************** + MI Register 7: Auto-negotiation next page transmit reg(0x07) + *****************************************************************************/ +typedef union _MI_ANNPTR_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 np:1; //bit 15 + UINT16 res1:1; //bit 14 + UINT16 msg_page:1; //bit 13 + UINT16 ack2:1; //bit 12 + UINT16 toggle:1; //bit 11 + UINT16 msg:11; //bits 0-10 + #else + UINT16 msg:11; //bits 0-10 + UINT16 toggle:1; //bit 11 + UINT16 ack2:1; //bit 12 + UINT16 msg_page:1; //bit 13 + UINT16 res1:1; //bit 14 + UINT16 np:1; //bit 15 + #endif + } bits; +} +MI_ANNPTR_t, *PMI_ANNPTR_t; + + + + +/****************************************************************************** + MI Register 8: Link Partner Next Page Reg(0x08) + *****************************************************************************/ +typedef union _MI_LPNPR_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 np:1; //bit 15 + UINT16 ack:1; //bit 14 + UINT16 msg_page:1; //bit 13 + UINT16 ack2:1; //bit 12 + UINT16 toggle:1; //bit 11 + UINT16 msg:11; //bits 0-10 + #else + UINT16 msg:11; //bits 0-10 + UINT16 toggle:1; //bit 11 + UINT16 ack2:1; //bit 12 + UINT16 msg_page:1; //bit 13 + UINT16 ack:1; //bit 14 + UINT16 np:1; //bit 15 + #endif + } bits; +} +MI_LPNPR_t, *PMI_LPNPR_t; + + + + +/****************************************************************************** + MI Register 9: 1000BaseT Control Reg(0x09) + *****************************************************************************/ +typedef union _MI_GCR_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 test_mode:3; //bits 13-15 + UINT16 ms_config_en:1; //bit 12 + UINT16 ms_value:1; //bit 11 + UINT16 port_type:1; //bit 10 + UINT16 link_1000fdx:1; //bit 9 + UINT16 link_1000hdx:1; //bit 8 + UINT16 res:8; //bit 0-7 + #else + UINT16 res:8; //bit 0-7 + UINT16 link_1000hdx:1; //bit 8 + UINT16 link_1000fdx:1; //bit 9 + UINT16 port_type:1; //bit 10 + UINT16 ms_value:1; //bit 11 + UINT16 ms_config_en:1; //bit 12 + UINT16 test_mode:3; //bits 13-15 + #endif + } bits; +} +MI_GCR_t, *PMI_GCR_t; + + + + +/****************************************************************************** + MI Register 10: 1000BaseT Status Reg(0x0A) + *****************************************************************************/ +typedef union _MI_GSR_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 ms_config_fault:1; //bit 15 + UINT16 ms_resolve:1; //bit 14 + UINT16 local_rx_status:1; //bit 13 + UINT16 remote_rx_status:1; //bit 12 + UINT16 link_1000fdx:1; //bit 11 + UINT16 link_1000hdx:1; //bit 10 + UINT16 res:2; //bits 8-9 + UINT16 idle_err_cnt:8; //bits 0-7 + #else + UINT16 idle_err_cnt:8; //bits 0-7 + UINT16 res:2; //bits 8-9 + UINT16 link_1000hdx:1; //bit 10 + UINT16 link_1000fdx:1; //bit 11 + UINT16 remote_rx_status:1; //bit 12 + UINT16 local_rx_status:1; //bit 13 + UINT16 ms_resolve:1; //bit 14 + UINT16 ms_config_fault:1; //bit 15 + #endif + } bits; +} +MI_GSR_t, *PMI_GSR_t; + + + + +/****************************************************************************** + MI Register 11 - 14: Reserved Regs(0x0B - 0x0E) + *****************************************************************************/ +typedef union _MI_RES_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 res15:1; //bit 15 + UINT16 res14:1; //bit 14 + UINT16 res13:1; //bit 13 + UINT16 res12:1; //bit 12 + UINT16 res11:1; //bit 11 + UINT16 res10:1; //bit 10 + UINT16 res9:1; //bit 9 + UINT16 res8:1; //bit 8 + UINT16 res7:1; //bit 7 + UINT16 res6:1; //bit 6 + UINT16 res5:1; //bit 5 + UINT16 res4:1; //bit 4 + UINT16 res3:1; //bit 3 + UINT16 res2:1; //bit 2 + UINT16 res1:1; //bit 1 + UINT16 res0:1; //bit 0 + #else + UINT16 res0:1; //bit 0 + UINT16 res1:1; //bit 1 + UINT16 res2:1; //bit 2 + UINT16 res3:1; //bit 3 + UINT16 res4:1; //bit 4 + UINT16 res5:1; //bit 5 + UINT16 res6:1; //bit 6 + UINT16 res7:1; //bit 7 + UINT16 res8:1; //bit 8 + UINT16 res9:1; //bit 9 + UINT16 res10:1; //bit 10 + UINT16 res11:1; //bit 11 + UINT16 res12:1; //bit 12 + UINT16 res13:1; //bit 13 + UINT16 res14:1; //bit 14 + UINT16 res15:1; //bit 15 + #endif + } bits; +} +MI_RES_t, *PMI_RES_t; + + + + +/****************************************************************************** + MI Register 15: Extended status Reg(0x0F) + *****************************************************************************/ +typedef union _MI_ESR_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 link_1000Xfdx:1; //bit 15 + UINT16 link_1000Xhdx:1; //bit 14 + UINT16 link_1000fdx:1; //bit 13 + UINT16 link_1000hdx:1; //bit 12 + UINT16 res:12; //bit 0-11 + #else + UINT16 res:12; //bit 0-11 + UINT16 link_1000hdx:1; //bit 12 + UINT16 link_1000fdx:1; //bit 13 + UINT16 link_1000Xhdx:1; //bit 14 + UINT16 link_1000Xfdx:1; //bit 15 + #endif + } bits; +} +MI_ESR_t, *PMI_ESR_t; + + + + +/****************************************************************************** + MI Register 16 - 18: Reserved Reg(0x10-0x12) + *****************************************************************************/ + + + + +/****************************************************************************** + MI Register 19: Loopback Control Reg(0x13) + *****************************************************************************/ +typedef union _MI_LCR_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 mii_en:1; //bit 15 + UINT16 pcs_en:1; //bit 14 + UINT16 pmd_en:1; //bit 13 + UINT16 all_digital_en:1; //bit 12 + UINT16 replica_en:1; //bit 11 + UINT16 line_driver_en:1; //bit 10 + UINT16 res:10; //bit 0-9 + #else + UINT16 res:10; //bit 0-9 + UINT16 line_driver_en:1; //bit 10 + UINT16 replica_en:1; //bit 11 + UINT16 all_digital_en:1; //bit 12 + UINT16 pmd_en:1; //bit 13 + UINT16 pcs_en:1; //bit 14 + UINT16 mii_en:1; //bit 15 + #endif + } bits; +} +MI_LCR_t, *PMI_LCR_t; + + + + +/****************************************************************************** + MI Register 20: Reserved Reg(0x14) + *****************************************************************************/ + + + + +/****************************************************************************** + MI Register 21: Management Interface Control Reg(0x15) + *****************************************************************************/ +typedef union _MI_MICR_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 res1:5; //bits 11-15 + UINT16 mi_error_count:7; //bits 4-10 + UINT16 res2:1; //bit 3 + UINT16 ignore_10g_fr:1; //bit 2 + UINT16 res3:1; //bit 1 + UINT16 preamble_supress_en:1; //bit 0 + #else + UINT16 preamble_supress_en:1; //bit 0 + UINT16 res3:1; //bit 1 + UINT16 ignore_10g_fr:1; //bit 2 + UINT16 res2:1; //bit 3 + UINT16 mi_error_count:7; //bits 4-10 + UINT16 res1:5; //bits 11-15 + #endif + } bits; +} +MI_MICR_t, *PMI_MICR_t; + + + + +/****************************************************************************** + MI Register 22: PHY Configuration Reg(0x16) + *****************************************************************************/ +typedef union _MI_PHY_CONFIG_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 crs_tx_en:1; //bit 15 + UINT16 res1:1; //bit 14 + UINT16 tx_fifo_depth:2; //bits 12-13 + UINT16 speed_downshift:2; //bits 10-11 + UINT16 pbi_detect:1; //bit 9 + UINT16 tbi_rate:1; //bit 8 + UINT16 alternate_np:1; //bit 7 + UINT16 group_mdio_en:1; //bit 6 + UINT16 tx_clock_en:1; //bit 5 + UINT16 sys_clock_en:1; //bit 4 + UINT16 res2:1; //bit 3 + UINT16 mac_if_mode:3; //bits 0-2 + #else + UINT16 mac_if_mode:3; //bits 0-2 + UINT16 res2:1; //bit 3 + UINT16 sys_clock_en:1; //bit 4 + UINT16 tx_clock_en:1; //bit 5 + UINT16 group_mdio_en:1; //bit 6 + UINT16 alternate_np:1; //bit 7 + UINT16 tbi_rate:1; //bit 8 + UINT16 pbi_detect:1; //bit 9 + UINT16 speed_downshift:2; //bits 10-11 + UINT16 tx_fifo_depth:2; //bits 12-13 + UINT16 res1:1; //bit 14 + UINT16 crs_tx_en:1; //bit 15 + #endif + } bits; +} +MI_PHY_CONFIG_t, *PMI_PHY_CONFIG_t; + + + + +/****************************************************************************** + MI Register 23: PHY CONTROL Reg(0x17) + *****************************************************************************/ +typedef union _MI_PHY_CONTROL_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 res1:1; //bit 15 + UINT16 tdr_en:1; //bit 14 + UINT16 res2:1; //bit 13 + UINT16 downshift_attempts:2; //bits 11-12 + UINT16 res3:5; //bit 6-10 + UINT16 jabber_10baseT:1; //bit 5 + UINT16 sqe_10baseT:1; //bit 4 + UINT16 tp_loopback_10baseT:1; //bit 3 + UINT16 preamble_gen_en:1; //bit 2 + UINT16 res4:1; //bit 1 + UINT16 force_int:1; //bit 0 + #else + UINT16 force_int:1; //bit 0 + UINT16 res4:1; //bit 1 + UINT16 preamble_gen_en:1; //bit 2 + UINT16 tp_loopback_10baseT:1; //bit 3 + UINT16 sqe_10baseT:1; //bit 4 + UINT16 jabber_10baseT:1; //bit 5 + UINT16 res3:5; //bit 6-10 + UINT16 downshift_attempts:2; //bits 11-12 + UINT16 res2:1; //bit 13 + UINT16 tdr_en:1; //bit 14 + UINT16 res1:1; //bit 15 + #endif + } bits; +} +MI_PHY_CONTROL_t, *PMI_PHY_CONTROL_t; + + + + +/****************************************************************************** + MI Register 24: Interrupt Mask Reg(0x18) + *****************************************************************************/ +typedef union _MI_IMR_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 res1:6; //bits 10-15 + UINT16 mdio_sync_lost:1; //bit 9 + UINT16 autoneg_status:1; //bit 8 + UINT16 hi_bit_err:1; //bit 7 + UINT16 np_rx:1; //bit 6 + UINT16 err_counter_full:1; //bit 5 + UINT16 fifo_over_underflow:1; //bit 4 + UINT16 rx_status:1; //bit 3 + UINT16 link_status:1; //bit 2 + UINT16 automatic_speed:1; //bit 1 + UINT16 int_en:1; //bit 0 + #else + UINT16 int_en:1; //bit 0 + UINT16 automatic_speed:1; //bit 1 + UINT16 link_status:1; //bit 2 + UINT16 rx_status:1; //bit 3 + UINT16 fifo_over_underflow:1; //bit 4 + UINT16 err_counter_full:1; //bit 5 + UINT16 np_rx:1; //bit 6 + UINT16 hi_bit_err:1; //bit 7 + UINT16 autoneg_status:1; //bit 8 + UINT16 mdio_sync_lost:1; //bit 9 + UINT16 res1:6; //bits 10-15 + #endif + } bits; +} +MI_IMR_t, *PMI_IMR_t; + + + + +/****************************************************************************** + MI Register 25: Interrupt Status Reg(0x19) + *****************************************************************************/ +typedef union _MI_ISR_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 res1:6; //bits 10-15 + UINT16 mdio_sync_lost:1; //bit 9 + UINT16 autoneg_status:1; //bit 8 + UINT16 hi_bit_err:1; //bit 7 + UINT16 np_rx:1; //bit 6 + UINT16 err_counter_full:1; //bit 5 + UINT16 fifo_over_underflow:1; //bit 4 + UINT16 rx_status:1; //bit 3 + UINT16 link_status:1; //bit 2 + UINT16 automatic_speed:1; //bit 1 + UINT16 int_en:1; //bit 0 + #else + UINT16 int_en:1; //bit 0 + UINT16 automatic_speed:1; //bit 1 + UINT16 link_status:1; //bit 2 + UINT16 rx_status:1; //bit 3 + UINT16 fifo_over_underflow:1; //bit 4 + UINT16 err_counter_full:1; //bit 5 + UINT16 np_rx:1; //bit 6 + UINT16 hi_bit_err:1; //bit 7 + UINT16 autoneg_status:1; //bit 8 + UINT16 mdio_sync_lost:1; //bit 9 + UINT16 res1:6; //bits 10-15 + #endif + } bits; +} +MI_ISR_t, *PMI_ISR_t; + + + + +/****************************************************************************** + MI Register 26: PHY Status Reg(0x1A) + *****************************************************************************/ +typedef union _MI_PSR_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 res1:1; //bit 15 + UINT16 autoneg_fault:2; //bit 13-14 + UINT16 autoneg_status:1; //bit 12 + UINT16 mdi_x_status:1; //bit 11 + UINT16 polarity_status:1; //bit 10 + UINT16 speed_status:2; //bits 8-9 + UINT16 duplex_status:1; //bit 7 + UINT16 link_status:1; //bit 6 + UINT16 tx_status:1; //bit 5 + UINT16 rx_status:1; //bit 4 + UINT16 collision_status:1; //bit 3 + UINT16 autoneg_en:1; //bit 2 + UINT16 pause_en:1; //bit 1 + UINT16 asymmetric_dir:1; //bit 0 + #else + UINT16 asymmetric_dir:1; //bit 0 + UINT16 pause_en:1; //bit 1 + UINT16 autoneg_en:1; //bit 2 + UINT16 collision_status:1; //bit 3 + UINT16 rx_status:1; //bit 4 + UINT16 tx_status:1; //bit 5 + UINT16 link_status:1; //bit 6 + UINT16 duplex_status:1; //bit 7 + UINT16 speed_status:2; //bits 8-9 + UINT16 polarity_status:1; //bit 10 + UINT16 mdi_x_status:1; //bit 11 + UINT16 autoneg_status:1; //bit 12 + UINT16 autoneg_fault:2; //bit 13-14 + UINT16 res1:1; //bit 15 + #endif + } bits; +} +MI_PSR_t, *PMI_PSR_t; + + + + +/****************************************************************************** + MI Register 27: LED Control Reg 1(0x1B) + *****************************************************************************/ +typedef union _MI_LCR1_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 res1:2; //bits 14-15 + UINT16 led_dup_indicate:2; //bits 12-13 + UINT16 led_10baseT:2; //bits 10-11 + UINT16 led_collision:2; //bits 8-9 + UINT16 res2:2; //bits 6-7 + UINT16 res3:2; //bits 4-5 + UINT16 pulse_dur:2; //bits 2-3 + UINT16 pulse_stretch1:1; //bit 1 + UINT16 pulse_stretch0:1; //bit 0 + #else + UINT16 pulse_stretch0:1; //bit 0 + UINT16 pulse_stretch1:1; //bit 1 + UINT16 pulse_dur:2; //bits 2-3 + UINT16 res3:2; //bits 4-5 + UINT16 res2:2; //bits 6-7 + UINT16 led_collision:2; //bits 8-9 + UINT16 led_10baseT:2; //bits 10-11 + UINT16 led_dup_indicate:2; //bits 12-13 + UINT16 res1:2; //bits 14-15 + #endif + } bits; +} +MI_LCR1_t, *PMI_LCR1_t; + + + + +/****************************************************************************** + MI Register 28: LED Control Reg 2(0x1C) + *****************************************************************************/ +typedef union _MI_LCR2_t +{ + UINT16 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT16 led_link:4; //bits 12-15 + UINT16 led_tx_rx:4; //bits 8-11 + UINT16 led_100BaseTX:4; //bits 4-7 + UINT16 led_1000BaseT:4; //bits 0-3 + #else + UINT16 led_1000BaseT:4; //bits 0-3 + UINT16 led_100BaseTX:4; //bits 4-7 + UINT16 led_tx_rx:4; //bits 8-11 + UINT16 led_link:4; //bits 12-15 + #endif + } bits; +} +MI_LCR2_t, *PMI_LCR2_t; + + + + +/****************************************************************************** + MI Register 29 - 31: Reserved Reg(0x1D - 0x1E) + *****************************************************************************/ + + + + +/****************************************************************************** + TruePHY headers + *****************************************************************************/ +typedef struct _TRUEPHY_ACCESS_MI_REGS_ +{ + TRUEPHY_HANDLE hTruePhy; + INT32 nPhyId; + UCHAR bReadWrite; + PUCHAR pbyRegs; + PUCHAR pwData; + INT32 nRegCount; +} +TRUEPHY_ACCESS_MI_REGS, *PTRUEPHY_ACCESS_MI_REGS; + + + + +/****************************************************************************** + TruePHY headers + *****************************************************************************/ +typedef struct _TAG_TPAL_ACCESS_MI_REGS_ +{ + UINT32 nPhyId; + UCHAR bReadWrite; + UINT32 nRegCount; + UINT16 Data[4096]; + UCHAR Regs[4096]; +} TPAL_ACCESS_MI_REGS, *PTPAL_ACCESS_MI_REGS; + + + + +/****************************************************************************** + Required TruePHY PROTOTYPES + *****************************************************************************/ +/****************************************************************************** + TYPE DEFINITIONS + *****************************************************************************/ +typedef TRUEPHY_HANDLE TPAL_HANDLE; + + +/****************************************************************************** + Forward declaration of the private adapter structure + *****************************************************************************/ +struct et131x_adapter; + + +/////////////////////////////////////////////////////////////////////////////// +//// TruePHY Platform Specific Functions //// +/////////////////////////////////////////////////////////////////////////////// +//TRUEPHY_HANDLE TPAL_PlatformInit( void * pPlatformInfo, +// PTRUEPHY_PLATFORM_FUNCTIONS pPlatFunctions ); + +INT32 TPAL_MiAccessRegs( TPAL_HANDLE hPlatform, + INT32 nPhyId, + PUCHAR pbyAccessFlags, + PUCHAR pbyRegisters, + PUINT16 pwData, + PUINT16 pwAndMasks, + PUINT16 pwOrMasks, + INT32 nRegCount ); + +void TPAL_PlatformExit( TRUEPHY_PLATFORM_HANDLE hPlatform ); + + + + +/////////////////////////////////////////////////////////////////////////////// +//// OS Specific Functions //// +/////////////////////////////////////////////////////////////////////////////// +void *TPAL_AllocMem( TRUEPHY_PLATFORM_HANDLE hPlatform, u_long ulNumBytes ); +void TPAL_FreeMem( TRUEPHY_PLATFORM_HANDLE hPlatform, void *pMemBlock ); +void TPAL_Sleep( TRUEPHY_PLATFORM_HANDLE hPlatform, u_long ulMsec ); +u_long TPAL_GetSystemUpTime( TRUEPHY_PLATFORM_HANDLE hPlatform ); +void TPAL_GetLinkStatusInfo( struct et131x_adapter *adapter ); + +INT32 TPAL_SetPhy10HalfDuplex( struct et131x_adapter *adapter ); +INT32 TPAL_SetPhy10FullDuplex( struct et131x_adapter *adapter ); +void TPAL_SetPhy10Force( struct et131x_adapter * pAdapter ); +INT32 TPAL_SetPhy100HalfDuplex( struct et131x_adapter *adapter ); +INT32 TPAL_SetPhy100FullDuplex( struct et131x_adapter *adapter ); +void TPAL_SetPhy100Force( struct et131x_adapter * pAdapter ); +INT32 TPAL_SetPhy1000FullDuplex( struct et131x_adapter *adapter); +INT32 TPAL_SetPhyAutoNeg( struct et131x_adapter *adapter ); + + + + +/****************************************************************************** + PROTOTYPES for ET1310_phy.c + *****************************************************************************/ +int et131x_xcvr_find( struct et131x_adapter *adapter ); + +int et131x_setphy_normal( struct et131x_adapter *adapter ); +INT32 et131x_xcvr_init( struct et131x_adapter *adapter ); + +INT32 MiRead( struct et131x_adapter *adapter, + UINT8 xcvrAddr, + UINT8 xcvrReg, + UINT16 *value ); + +INT32 MiWrite( struct et131x_adapter *adapter, + UINT8 xcvrAddr, + UINT8 xcvReg, + UINT16 value ); + +void et131x_Mii_check( struct et131x_adapter *pAdapter, + MI_BMSR_t bmsr, + MI_BMSR_t bmsr_ints ); + + + + +/****************************************************************************** + This last is not strictly required (the driver could call the TPAL + version instead), but this sets the adapter up correctly, and calls the + access routine indirectly. This protects the driver from changes in TPAL. + *****************************************************************************/ +void SetPhy_10BaseTHalfDuplex( struct et131x_adapter *adapter ); + + + + +/****************************************************************************** + Defines for PHY access routines + *****************************************************************************/ +// Define bit operation flags +#define TRUEPHY_BIT_CLEAR 0 +#define TRUEPHY_BIT_SET 1 +#define TRUEPHY_BIT_READ 2 + +// Define read/write operation flags +#ifndef TRUEPHY_READ +#define TRUEPHY_READ 0 +#define TRUEPHY_WRITE 1 +#define TRUEPHY_MASK 2 +#endif + +// Define speeds +#define TRUEPHY_SPEED_10MBPS 0 +#define TRUEPHY_SPEED_100MBPS 1 +#define TRUEPHY_SPEED_1000MBPS 2 + +// Define duplex modes +#define TRUEPHY_DUPLEX_HALF 0 +#define TRUEPHY_DUPLEX_FULL 1 + +// Define master/slave configuration values +#define TRUEPHY_CFG_SLAVE 0 +#define TRUEPHY_CFG_MASTER 1 + +// Define MDI/MDI-X settings +#define TRUEPHY_MDI 0 +#define TRUEPHY_MDIX 1 +#define TRUEPHY_AUTO_MDI_MDIX 2 + +// Define 10Base-T link polarities +#define TRUEPHY_POLARITY_NORMAL 0 +#define TRUEPHY_POLARITY_INVERTED 1 + +// Define auto-negotiation results +#define TRUEPHY_ANEG_NOT_COMPLETE 0 +#define TRUEPHY_ANEG_COMPLETE 1 +#define TRUEPHY_ANEG_DISABLED 2 + +/* Define duplex advertisment flags */ +#define TRUEPHY_ADV_DUPLEX_NONE 0x00 +#define TRUEPHY_ADV_DUPLEX_FULL 0x01 +#define TRUEPHY_ADV_DUPLEX_HALF 0x02 +#define TRUEPHY_ADV_DUPLEX_BOTH \ + (TRUEPHY_ADV_DUPLEX_FULL | TRUEPHY_ADV_DUPLEX_HALF) + +#define PHY_CONTROL 0x00 //#define TRU_MI_CONTROL_REGISTER 0 +#define PHY_STATUS 0x01 //#define TRU_MI_STATUS_REGISTER 1 +#define PHY_ID_1 0x02 //#define TRU_MI_PHY_IDENTIFIER_1_REGISTER 2 +#define PHY_ID_2 0x03 //#define TRU_MI_PHY_IDENTIFIER_2_REGISTER 3 +#define PHY_AUTO_ADVERTISEMENT 0x04 //#define TRU_MI_ADVERTISEMENT_REGISTER 4 +#define PHY_AUTO_LINK_PARTNER 0x05 //#define TRU_MI_LINK_PARTNER_ABILITY_REGISTER 5 +#define PHY_AUTO_EXPANSION 0x06 //#define TRU_MI_EXPANSION_REGISTER 6 +#define PHY_AUTO_NEXT_PAGE_TX 0x07 //#define TRU_MI_NEXT_PAGE_TRANSMIT_REGISTER 7 +#define PHY_LINK_PARTNER_NEXT_PAGE 0x08 //#define TRU_MI_LINK_PARTNER_NEXT_PAGE_REGISTER 8 +#define PHY_1000_CONTROL 0x09 //#define TRU_MI_1000BASET_CONTROL_REGISTER 9 +#define PHY_1000_STATUS 0x0A //#define TRU_MI_1000BASET_STATUS_REGISTER 10 + + +#define PHY_EXTENDED_STATUS 0x0F //#define TRU_MI_EXTENDED_STATUS_REGISTER 15 + +// some defines for modem registers that seem to be 'reserved' +#define PHY_INDEX_REG 0x10 +#define PHY_DATA_REG 0x11 + +#define PHY_MPHY_CONTROL_REG 0x12 //#define TRU_VMI_MPHY_CONTROL_REGISTER 18 + +#define PHY_LOOPBACK_CONTROL 0x13 //#define TRU_VMI_LOOPBACK_CONTROL_1_REGISTER 19 + //#define TRU_VMI_LOOPBACK_CONTROL_2_REGISTER 20 +#define PHY_REGISTER_MGMT_CONTROL 0x15 //#define TRU_VMI_MI_SEQ_CONTROL_REGISTER 21 +#define PHY_CONFIG 0x16 //#define TRU_VMI_CONFIGURATION_REGISTER 22 +#define PHY_PHY_CONTROL 0x17 //#define TRU_VMI_PHY_CONTROL_REGISTER 23 +#define PHY_INTERRUPT_MASK 0x18 //#define TRU_VMI_INTERRUPT_MASK_REGISTER 24 +#define PHY_INTERRUPT_STATUS 0x19 //#define TRU_VMI_INTERRUPT_STATUS_REGISTER 25 +#define PHY_PHY_STATUS 0x1A //#define TRU_VMI_PHY_STATUS_REGISTER 26 +#define PHY_LED_1 0x1B //#define TRU_VMI_LED_CONTROL_1_REGISTER 27 +#define PHY_LED_2 0x1C //#define TRU_VMI_LED_CONTROL_2_REGISTER 28 + //#define TRU_VMI_LINK_CONTROL_REGISTER 29 + //#define TRU_VMI_TIMING_CONTROL_REGISTER + + + + +/****************************************************************************** + Prototypes for PHY access routines + *****************************************************************************/ +void ET1310_PhyInit( struct et131x_adapter *pAdapter ); +void ET1310_PhyReset( struct et131x_adapter *pAdapter ); +void ET1310_PhyPowerDown( struct et131x_adapter *pAdapter, BOOL_t down ); +void ET1310_PhyAutoNeg( struct et131x_adapter *pAdapter, BOOL_t enable ); +void ET1310_PhyDuplexMode( struct et131x_adapter *pAdapter, UINT16 duplex ); +void ET1310_PhySpeedSelect( struct et131x_adapter *pAdapter, UINT16 speed ); +void ET1310_PhyAdvertise1000BaseT( struct et131x_adapter *pAdapter, UINT16 duplex ); +void ET1310_PhyAdvertise100BaseT( struct et131x_adapter *pAdapter, UINT16 duplex ); +void ET1310_PhyAdvertise10BaseT( struct et131x_adapter *pAdapter, UINT16 duplex ); +void ET1310_PhyLinkStatus( struct et131x_adapter *pAdapter, + UCHAR *ucLinkStatus, + UINT32 *uiAutoNeg, + UINT32 *uiLinkSpeed, + UINT32 *uiDuplexMode, + UINT32 *uiMdiMdix, + UINT32 *uiMasterSlave, + UINT32 *uiPolarity ); +void ET1310_PhyAndOrReg( struct et131x_adapter *pAdapter, + UINT16 regnum, + UINT16 andMask, + UINT16 orMask ); +void ET1310_PhyAccessMiBit( struct et131x_adapter *pAdapter, + UINT16 action, + UINT16 regnum, + UINT16 bitnum, + UINT8 *value ); + + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _ET1310_PHY_H_ */ --- linux-2.6.27.orig/ubuntu/et131x/et131x_config.c +++ linux-2.6.27/ubuntu/et131x/et131x_config.c @@ -0,0 +1,383 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_config.c - Handles parsing of configuration data during + * initialization. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/10/28 18:43:46 $ + $Revision: 1.8 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +/****************************************************************************** + Includes + *****************************************************************************/ +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include +#include +#include +#include + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ET1310_phy.h" +#include "ET1310_pm.h" +#include "ET1310_jagcore.h" + +#include "et131x_supp.h" +#include "et131x_adapter.h" +#include "et131x_initpci.h" + +#include "ET1310_tx.h" + + + +/****************************************************************************** + Data for debugging facilities + *****************************************************************************/ +#ifdef ET131X_DBG +extern dbg_info_t *et131x_dbginfo; +#endif /* ET131X_DBG */ + + + + +/****************************************************************************** + Defines for Parameter Default/Min/Max vaules + *****************************************************************************/ +#define PARM_SPEED_DUPLEX_DEF 0 +#define PARM_SPEED_DUPLEX_MIN 0 +#define PARM_SPEED_DUPLEX_MAX 5 + +#define PARM_VLAN_TAG_DEF 0 +#define PARM_VLAN_TAG_MIN 0 +#define PARM_VLAN_TAG_MAX 4095 + +#define PARM_FLOW_CTL_DEF 0 +#define PARM_FLOW_CTL_MIN 0 +#define PARM_FLOW_CTL_MAX 3 + +#define PARM_WOL_LINK_DEF 3 +#define PARM_WOL_LINK_MIN 0 +#define PARM_WOL_LINK_MAX 3 + +#define PARM_WOL_MATCH_DEF 7 +#define PARM_WOL_MATCH_MIN 0 +#define PARM_WOL_MATCH_MAX 7 + +#define PARM_JUMBO_PKT_DEF 1514 +#define PARM_JUMBO_PKT_MIN 1514 +#define PARM_JUMBO_PKT_MAX 9216 + +#define PARM_PHY_COMA_DEF 0 +#define PARM_PHY_COMA_MIN 0 +#define PARM_PHY_COMA_MAX 1 + +#define PARM_RX_NUM_BUFS_DEF 4 +#define PARM_RX_NUM_BUFS_MIN 1 +#define PARM_RX_NUM_BUFS_MAX 64 + +#define PARM_RX_TIME_INT_DEF 10 +#define PARM_RX_TIME_INT_MIN 2 +#define PARM_RX_TIME_INT_MAX 320 + +#define PARM_TX_NUM_BUFS_DEF 4 +#define PARM_TX_NUM_BUFS_MIN 1 +#define PARM_TX_NUM_BUFS_MAX 40 + +#define PARM_TX_TIME_INT_DEF 40 +#define PARM_TX_TIME_INT_MIN 1 +#define PARM_TX_TIME_INT_MAX 140 + +#define PARM_RX_MEM_END_DEF 0x2bc +#define PARM_RX_MEM_END_MIN 0 +#define PARM_RX_MEM_END_MAX 0x3ff + +#define PARM_MAC_STAT_DEF 1 +#define PARM_MAC_STAT_MIN 0 +#define PARM_MAC_STAT_MAX 1 + +#define PARM_SC_GAIN_DEF 7 +#define PARM_SC_GAIN_MIN 0 +#define PARM_SC_GAIN_MAX 7 + +#define PARM_PM_WOL_DEF 0 +#define PARM_PM_WOL_MIN 0 +#define PARM_PM_WOL_MAX 1 + +#define PARM_NMI_DISABLE_DEF 0 +#define PARM_NMI_DISABLE_MIN 0 +#define PARM_NMI_DISABLE_MAX 2 + +#define PARM_DMA_CACHE_DEF 0 +#define PARM_DMA_CACHE_MIN 0 +#define PARM_DMA_CACHE_MAX 15 + +#define PARM_PHY_LOOPBK_DEF 0 +#define PARM_PHY_LOOPBK_MIN 0 +#define PARM_PHY_LOOPBK_MAX 1 + + +#define PARM_MAC_ADDRESS_DEF { 0x00, 0x05, 0x3d, 0x00, 0x02, 0x00 } + + + + +/****************************************************************************** + Module parameter for disabling NMI + *****************************************************************************/ +static u32 et131x_nmi_disable = PARM_NMI_DISABLE_DEF; + +module_param ( et131x_nmi_disable, uint, 0 ); +MODULE_PARM_DESC( et131x_nmi_disable, "Disable NMI (0-2) [0]" ); + + +/***************************************************************************** + Module parameter for manual speed setting + ****************************************************************************/ +static u32 et131x_speed_set = PARM_SPEED_DUPLEX_DEF; +module_param (et131x_speed_set, uint, 0); +MODULE_PARM_DESC( et131x_speed_set, "Set Link speed and dublex manually (0-5) [0] \n 1 : 10Mb Half-Duplex \n 2 : 10Mb Full-Duplex \n 3 : 100Mb Half-Duplex \n 4 : 100Mb Full-Duplex \n 5 : 1000Mb Full-Duplex \n 0 : Auto Speed Auto Dublex"); + + +/****************************************************************************** + ROUTINE : et131x_config_parse + ****************************************************************************** + + DESCRIPTION : Parses a configuration from some location (module + parameters, for example) into the private adapter struct + + PARAMETERS : pAdapter - pointer to the private adapter struct + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_config_parse( ET131X_ADAPTER *pAdapter ) +{ + UINT8 macAddrDef[] = PARM_MAC_ADDRESS_DEF; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_config_parse" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + The NDIS driver uses the registry to store persistent per-device + configuration, and reads this configuration into the appropriate + elements of the private adapter structure on initialization. Because + Linux has no analog to the registry, use this function to initialize the + private adapter structure with a default configuration. + + One other possibility is to use a series of module parameters which can + be passed in by the caller when the module is initialized. However, this + implementation does not allow for seperate configurations in the event + multiple devices are present, and hence will not suffice. + + If another method is derived which addresses this problem, this is where + it should be implemented. + *************************************************************************/ + + /************************************************************************** + Set the private adapter struct with default values for the corresponding + parameters + *************************************************************************/ + if( et131x_speed_set != PARM_SPEED_DUPLEX_DEF ) + { + DBG_VERBOSE( et131x_dbginfo, "Speed set manually to : %d \n",et131x_speed_set ); + pAdapter->SpeedDuplex = et131x_speed_set; + } + else + { + pAdapter->SpeedDuplex = PARM_SPEED_DUPLEX_DEF; + } + + // pAdapter->SpeedDuplex = PARM_SPEED_DUPLEX_DEF; + + pAdapter->RegistryVlanTag = PARM_VLAN_TAG_DEF; + pAdapter->RegistryFlowControl = PARM_FLOW_CTL_DEF; + pAdapter->RegistryWOLLink = PARM_WOL_LINK_DEF; + pAdapter->RegistryWOLMatch = PARM_WOL_MATCH_DEF; + pAdapter->RegistryJumboPacket = PARM_JUMBO_PKT_DEF; + pAdapter->RegistryPhyComa = PARM_PHY_COMA_DEF; + pAdapter->RegistryRxNumBuffers = PARM_RX_NUM_BUFS_DEF; + pAdapter->RegistryRxTimeInterval = PARM_RX_TIME_INT_DEF; + pAdapter->RegistryTxNumBuffers = PARM_TX_NUM_BUFS_DEF; + pAdapter->RegistryTxTimeInterval = PARM_TX_TIME_INT_DEF; + pAdapter->RegistryRxMemEnd = PARM_RX_MEM_END_DEF; + pAdapter->RegistryMACStat = PARM_MAC_STAT_DEF; + pAdapter->RegistrySCGain = PARM_SC_GAIN_DEF; + pAdapter->RegistryPMWOL = PARM_PM_WOL_DEF; + + if( et131x_nmi_disable != PARM_NMI_DISABLE_DEF ) + { + pAdapter->RegistryNMIDisable = et131x_nmi_disable; + } + else + { + pAdapter->RegistryNMIDisable = PARM_NMI_DISABLE_DEF; + } + + pAdapter->RegistryDMACache = PARM_DMA_CACHE_DEF; + pAdapter->RegistryPhyLoopbk = PARM_PHY_LOOPBK_DEF; + + + /************************************************************************** + Set the MAC address to a default + *************************************************************************/ + memcpy( pAdapter->CurrentAddress, macAddrDef, ETH_ALEN ); + pAdapter->bOverrideAddress = FALSE; + + DBG_TRACE( et131x_dbginfo, + "Default MAC Address : %02x:%02x:%02x:%02x:%02x:%02x\n", + pAdapter->CurrentAddress[0], pAdapter->CurrentAddress[1], + pAdapter->CurrentAddress[2], pAdapter->CurrentAddress[3], + pAdapter->CurrentAddress[4], pAdapter->CurrentAddress[5] ); + + + /************************************************************************** + Decode SpeedDuplex + + Set up as if we are auto negotiating always and then change if we go + into force mode + *************************************************************************/ + pAdapter->AiForceSpeed = 0; // Auto speed + pAdapter->AiForceDpx = 0; // Auto FDX + + + /************************************************************************** + If we are the 10/100 device, and gigabit is somehow requested then + knock it down to 100 full. + *************************************************************************/ + if(( pAdapter->DeviceID == ET131X_PCI_DEVICE_ID_FAST ) && + ( pAdapter->SpeedDuplex == 5 )) + { + pAdapter->SpeedDuplex = 4; + } + + + switch( pAdapter->SpeedDuplex ) + { + case 1: // 10Mb Half-Duplex + pAdapter->AiForceSpeed = 10; + pAdapter->AiForceDpx = 1; + break; + + case 2: // 10Mb Full-Duplex + pAdapter->AiForceSpeed = 10; + pAdapter->AiForceDpx = 2; + break; + + case 3: // 100Mb Half-Duplex + pAdapter->AiForceSpeed = 100; + pAdapter->AiForceDpx = 1; + break; + + case 4: // 100Mb Full-Duplex + pAdapter->AiForceSpeed = 100; + pAdapter->AiForceDpx = 2; + break; + + case 5: // 1000Mb Full-Duplex + pAdapter->AiForceSpeed = 1000; + pAdapter->AiForceDpx = 2; + break; + } + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + --- linux-2.6.27.orig/ubuntu/et131x/ET1310_tx.h +++ linux-2.6.27/ubuntu/et131x/ET1310_tx.h @@ -0,0 +1,354 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * ET1310_tx.h - Defines, structs, enums, prototypes, etc. pertaining to data + * transmission. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/10/07 21:26:45 $ + $Revision: 1.9 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +#ifndef __ET1310_TX_H__ +#define __ET1310_TX_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + + + +/****************************************************************************** + Typedefs for Tx Descriptor Ring + *****************************************************************************/ +/****************************************************************************** + TXDESC_WORD2_t structure holds part of the control bits in the Tx Descriptor + ring for the ET-1310 + *****************************************************************************/ +typedef union _txdesc_word2_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 vlan_prio:3; //bits 29-31(VLAN priority) + UINT32 vlan_cfi:1; //bit 28(cfi) + UINT32 vlan_tag:12; //bits 16-27(VLAN tag) + UINT32 length_in_bytes:16; //bits 0-15(packet length) + #else + UINT32 length_in_bytes:16; //bits 0-15(packet length) + UINT32 vlan_tag:12; //bits 16-27(VLAN tag) + UINT32 vlan_cfi:1; //bit 28(cfi) + UINT32 vlan_prio:3; //bits 29-31(VLAN priority) + #endif /* _BIT_FIELDS_HTOL */ + } bits; +}TXDESC_WORD2_t, *PTXDESC_WORD2_t; + + + + +/****************************************************************************** + TXDESC_WORD3_t structure holds part of the control bits in the Tx Descriptor + ring for the ET-1310 + *****************************************************************************/ +typedef union _txdesc_word3_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:17; //bits 15-31 + UINT32 udpa:1; //bit 14(UDP checksum assist) + UINT32 tcpa:1; //bit 13(TCP checksum assist) + UINT32 ipa:1; //bit 12(IP checksum assist) + UINT32 vlan:1; //bit 11(append VLAN tag) + UINT32 hp:1; //bit 10(Packet is a Huge packet) + UINT32 pp:1; //bit 9(pad packet) + UINT32 mac:1; //bit 8(MAC override) + UINT32 crc:1; //bit 7(append CRC) + UINT32 e:1; //bit 6(Tx frame has error) + UINT32 pf:1; //bit 5(send pause frame) + UINT32 bp:1; //bit 4(Issue half-duplex backpressure (XON/XOFF) + UINT32 cw:1; //bit 3(Control word - no packet data) + UINT32 ir:1; //bit 2(interrupt the processor when this pkt sent) + UINT32 f:1; //bit 1(first packet in the sequence) + UINT32 l:1; //bit 0(last packet in the sequence) + #else + UINT32 l:1; //bit 0(last packet in the sequence) + UINT32 f:1; //bit 1(first packet in the sequence) + UINT32 ir:1; //bit 2(interrupt the processor when this pkt sent) + UINT32 cw:1; //bit 3(Control word - no packet data) + UINT32 bp:1; //bit 4(Issue half-duplex backpressure (XON/XOFF) + UINT32 pf:1; //bit 5(send pause frame) + UINT32 e:1; //bit 6(Tx frame has error) + UINT32 crc:1; //bit 7(append CRC) + UINT32 mac:1; //bit 8(MAC override) + UINT32 pp:1; //bit 9(pad packet) + UINT32 hp:1; //bit 10(Packet is a Huge packet) + UINT32 vlan:1; //bit 11(append VLAN tag) + UINT32 ipa:1; //bit 12(IP checksum assist) + UINT32 tcpa:1; //bit 13(TCP checksum assist) + UINT32 udpa:1; //bit 14(UDP checksum assist) + UINT32 unused:17; //bits 15-31 + #endif /* _BIT_FIELDS_HTOL */ + } bits; +}TXDESC_WORD3_t, *PTXDESC_WORD3_t; + + + + +/****************************************************************************** + TX_DESC_ENTRY_t is sructure representing each descriptor on the ring + *****************************************************************************/ +typedef struct _tx_desc_entry_t +{ + UINT32 DataBufferPtrHigh; + UINT32 DataBufferPtrLow; + TXDESC_WORD2_t word2; // control words how to xmit the + TXDESC_WORD3_t word3; // data (detailed above) +} +TX_DESC_ENTRY_t, *PTX_DESC_ENTRY_t; +/*===========================================================================*/ + + + + +/****************************************************************************** + Typedefs for Tx DMA engine status writeback + *****************************************************************************/ +/****************************************************************************** + TX_STATUS_BLOCK_t is sructure representing the status of the Tx DMA engine + it sits in free memory, and is pointed to by 0x101c / 0x1020 + *****************************************************************************/ + +typedef union _tx_status_block_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:21; //bits 11-31 + UINT32 serv_cpl_wrap:1; //bit 10 + UINT32 serv_cpl:10; //bits 0-9 + #else + UINT32 serv_cpl:10; //bits 0-9 + UINT32 serv_cpl_wrap:1; //bit 10 + UINT32 unused:21; //bits 11-31 + #endif + } bits; +} +TX_STATUS_BLOCK_t, *PTX_STATUS_BLOCK_t; +/*===========================================================================*/ + + + + +/****************************************************************************** + TCB (Transmit Control Block) + *****************************************************************************/ +typedef struct _MP_TCB +{ + struct _MP_TCB *Next; + UINT32 Flags; + UINT32 Count; + UINT32 PacketStaleCount; + struct sk_buff *Packet; + UINT32 PacketLength; + TXDMA_SERVICE_REQUEST_t WrIndex; + TXDMA_SERVICE_REQUEST_t WrIndexStart; +} MP_TCB, *PMP_TCB; + + + + +/****************************************************************************** + Structure to hold the skb's in a list + *****************************************************************************/ +typedef struct tx_skb_list_elem +{ + struct list_head skb_list_elem; + struct sk_buff *skb; +} TX_SKB_LIST_ELEM, *PTX_SKB_LIST_ELEM; + + + + +/****************************************************************************** + TX_RING_t is sructure representing our local reference(s) to the ring + *****************************************************************************/ +typedef struct _tx_ring_t +{ + /************************************************************************** + TCB (Transmit Control Block) memory and lists + *************************************************************************/ + PUCHAR MpTcbMem; + + + /************************************************************************** + List of TCBs that are ready to be used + *************************************************************************/ + PMP_TCB TCBReadyQueueHead; + PMP_TCB TCBReadyQueueTail; + + + /************************************************************************** + list of TCBs that are currently being sent. NOTE that access to all + three of these (including nBusySend) are controlled via the + TCBSendQLock. This lock should be secured prior to incementing / + decrementing nBusySend, or any queue manipulation on CurrSendHead / Tail + *************************************************************************/ + PMP_TCB CurrSendHead; + PMP_TCB CurrSendTail; + INT32 nBusySend; + + + /************************************************************************** + List of packets (not TCBs) that were queued for lack of resources + *************************************************************************/ + struct list_head SendWaitQueue; + INT32 nWaitSend; + + + /************************************************************************** + The actual descriptor ring + *************************************************************************/ + PTX_DESC_ENTRY_t pTxDescRingVa; + dma_addr_t pTxDescRingPa; + UINT64 pTxDescRingAdjustedPa; + UINT64 TxDescOffset; + + + /************************************************************************** + ReadyToSend indicates where we last wrote to in the descriptor ring. + *************************************************************************/ + TXDMA_SERVICE_REQUEST_t txDmaReadyToSend; + + + /************************************************************************** + The location of the write-back status block + *************************************************************************/ + PTX_STATUS_BLOCK_t pTxStatusVa; + dma_addr_t pTxStatusPa; + + + /************************************************************************** + A Block of zeroes, used to pad packets that are less than 60 bytes. + *************************************************************************/ + void *pTxDummyBlkVa; + dma_addr_t pTxDummyBlkPa; + + TXMAC_ERR_t TxMacErr; + + + /************************************************************************** + Variables to track the Tx interrupt coalescing features + *************************************************************************/ + INT32 TxPacketsSinceLastinterrupt; +} +TX_RING_t, *PTX_RING_t; + + + + +/****************************************************************************** + Forward declaration of the frag-list for the following prototypes + *****************************************************************************/ +typedef struct _MP_FRAG_LIST MP_FRAG_LIST, *PMP_FRAG_LIST; + + + + +/****************************************************************************** + Forward declaration of the private adapter structure + *****************************************************************************/ +struct et131x_adapter; + + + + +/****************************************************************************** + PROTOTYPES for et1310_tx.c + *****************************************************************************/ +int et131x_tx_dma_memory_alloc( struct et131x_adapter *adapter ); +void et131x_tx_dma_memory_free( struct et131x_adapter *adapter ); +void ConfigTxDmaRegs( struct et131x_adapter *pAdapter ); +void et131x_init_send( struct et131x_adapter *adapter ); +void et131x_tx_dma_disable( struct et131x_adapter *pAdapter ); +void et131x_tx_dma_enable( struct et131x_adapter *pAdapter ); +void et131x_handle_send_interrupt( struct et131x_adapter *pAdapter ); +void et131x_free_busy_send_packets( struct et131x_adapter *pAdapter ); +int et131x_send_packets( struct sk_buff *skb, struct net_device *netdev ); + + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __ET1310_TX_H__ */ --- linux-2.6.27.orig/ubuntu/et131x/ET1310_mac.c +++ linux-2.6.27/ubuntu/et131x/ET1310_mac.c @@ -0,0 +1,1247 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * ET1310_mac.c - All code and routines pertaining to the MAC + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/10/28 18:43:44 $ + $Revision: 1.11 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +/****************************************************************************** + Includes + *****************************************************************************/ +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include +#include +#include +#include + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ET1310_phy.h" +#include "ET1310_pm.h" +#include "ET1310_jagcore.h" +#include "ET1310_mac.h" + +#include "et131x_supp.h" +#include "et131x_adapter.h" +#include "et131x_initpci.h" +#include "et131x_supp.h" + + + + +/****************************************************************************** + Data for debugging facilities + *****************************************************************************/ +#ifdef ET131X_DBG +extern dbg_info_t *et131x_dbginfo; +#endif /* ET131X_DBG */ + + + + +/****************************************************************************** + ROUTINE: ConfigMacRegs1 + ****************************************************************************** + + DESCRIPTION: + Used to configure the first part of MAC regs to a known initialized + state + + PARAMETERS : + pAdpater - pointer to our adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +void ConfigMACRegs1( ET131X_ADAPTER *pAdapter ) +{ + PMAC_t pMac; + MAC_STATION_ADDR1_t station1; + MAC_STATION_ADDR2_t station2; + MAC_IPG_t ipg; + MAC_HFDP_t hfdp; + MII_MGMT_CFG_t mii_mgmt_cfg; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "ConfigMACRegs1" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Let's get our pointer to the MAC regs + *************************************************************************/ + pMac = &pAdapter->CSRAddress->mac; + + + /************************************************************************** + First we need to reset everything. Write to MAC configuration register + 1 to perform reset. + *************************************************************************/ + pMac->cfg1.value = 0xC00F0000; + + + /************************************************************************** + Next lets configure the MAC Inter-packet gap register + *************************************************************************/ + ipg.bits.non_B2B_ipg_1 = 0x38; //58d + ipg.bits.non_B2B_ipg_2 = 0x58; //88d + ipg.bits.min_ifg_enforce = 0x50; //80d + ipg.bits.B2B_ipg = 0x60; //96d + + pMac->ipg.value = ipg.value; + + + /************************************************************************** + Next lets configure the MAC Half Duplex register + *************************************************************************/ + hfdp.bits.alt_beb_trunc = 0xA; + hfdp.bits.alt_beb_enable = 0x0; + hfdp.bits.bp_no_backoff = 0x0; + hfdp.bits.no_backoff = 0x0; + hfdp.bits.excess_defer = 0x1; + hfdp.bits.rexmit_max = 0xF; + hfdp.bits.coll_window = 0x37; //55d + + pMac->hfdp.value = hfdp.value; + + + /************************************************************************** + Next lets configure the MAC Interface Control register + *************************************************************************/ + pMac->if_ctrl.value = 0x0; + + + /************************************************************************** + Let's move on to setting up the mii managment configuration + *************************************************************************/ + mii_mgmt_cfg.bits.reset_mii_mgmt = 0; + mii_mgmt_cfg.bits.scan_auto_incremt = 0; + mii_mgmt_cfg.bits.preamble_suppress = 0; + mii_mgmt_cfg.bits.mgmt_clk_reset = 0x7; + + pMac->mii_mgmt_cfg.value = mii_mgmt_cfg.value; + + + /************************************************************************** + Next lets configure the MAC Station Address register. These values are + read from the EEPROM during initialization and stored in the adapter + structure. We write what is stored in the adapter structure to the MAC + Station Address registers high and low. This station address is used + for generating and checking pause control packets. + *************************************************************************/ + station2.bits.Octet1 = pAdapter->CurrentAddress[0]; + station2.bits.Octet2 = pAdapter->CurrentAddress[1]; + station1.bits.Octet3 = pAdapter->CurrentAddress[2]; + station1.bits.Octet4 = pAdapter->CurrentAddress[3]; + station1.bits.Octet5 = pAdapter->CurrentAddress[4]; + station1.bits.Octet6 = pAdapter->CurrentAddress[5]; + + pMac->station_addr_1.value = station1.value; + pMac->station_addr_2.value = station2.value; + + + /************************************************************************** + Max ethernet packet in bytes that will passed by the mac without being + truncated. Allow the MAC to pass 8 more than our max packet size. This + is 4 for the Ethernet CRC and 4 for the VLAN ID. + + Packets larger than (RegistryJumboPacket) that do not contain a VLAN + ID will be dropped by the Rx function. + *************************************************************************/ +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) + pMac->max_fm_len.value = pAdapter->RegistryJumboPacket + 8; +#else + pMac->max_fm_len.value = pAdapter->RegistryJumboPacket + 4; +#endif + + + /************************************************************************** + clear out MAC config reset + *************************************************************************/ + pAdapter->CSRAddress->mac.cfg1.value = 0x0; + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: ConfigMacRegs2 + ****************************************************************************** + + DESCRIPTION: + Used to configure the second part of MAC regs to a known initialized + state + + PARAMETERS : + pAdpater - pointer to our adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +void ConfigMACRegs2( ET131X_ADAPTER *pAdapter ) +{ + INT32 delay = 0; + PMAC_t pMac; + MAC_CFG1_t cfg1; + MAC_CFG2_t cfg2; + MAC_IF_CTRL_t ifctrl; + TXMAC_CTL_t ctl = pAdapter->CSRAddress->txmac.ctl; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "ConfigMACRegs2" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Let's get our pointer to the MAC regs + *************************************************************************/ + pMac = &pAdapter->CSRAddress->mac; + + cfg1.value = pMac->cfg1.value; + cfg2.value = pMac->cfg2.value; + ifctrl.value = pMac->if_ctrl.value; + + if( pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS ) + { + cfg2.bits.if_mode = 0x2; + ifctrl.bits.phy_mode = 0x0; + } + else + { + cfg2.bits.if_mode = 0x1; + ifctrl.bits.phy_mode = 0x1; + } + + + /************************************************************************** + We need to enable Rx/Tx + *************************************************************************/ + cfg1.bits.rx_enable = 0x1; + cfg1.bits.tx_enable = 0x1; + + + /************************************************************************** + Set up flow control + *************************************************************************/ + cfg1.bits.tx_flow = 0x1; + + if( ( pAdapter->FlowControl == RxOnly ) || + ( pAdapter->FlowControl == Both )) + { + cfg1.bits.rx_flow = 0x1; + } + else + { + cfg1.bits.rx_flow = 0x0; + } + + + /************************************************************************** + Initialize loop back to off + *************************************************************************/ + cfg1.bits.loop_back = 0; + + pAdapter->CSRAddress->mac.cfg1.value = cfg1.value; + + + /************************************************************************** + Now we need to initialize the MAC Configuration 2 register + *************************************************************************/ + cfg2.bits.preamble_len = 0x7; + cfg2.bits.huge_frame = 0x0; + /* LENGTH FIELD CHECKING bit4: Set this bit to cause the MAC to check the + * frame’s length field to ensure it matches the actual data field length. Clear this bit if no + * length field checking is desired. Its default is ‘0’. + */ + cfg2.bits.len_check = 0x1; + + if ( pAdapter->RegistryPhyLoopbk == FALSE ) + { + cfg2.bits.pad_crc = 0x1; + cfg2.bits.crc_enable = 0x1; + } + else + { + cfg2.bits.pad_crc = 0; + cfg2.bits.crc_enable = 0; + } + + + /************************************************************************** + 1 – full duplex, 0 – half-duplex + *************************************************************************/ + cfg2.bits.full_duplex = pAdapter->uiDuplexMode; + ifctrl.bits.ghd_mode = !pAdapter->uiDuplexMode; + + pAdapter->CSRAddress->mac.if_ctrl = ifctrl; + pAdapter->CSRAddress->mac.cfg2.value = cfg2.value; + + do + { + udelay( 10 ); + delay++; + } while(( !pAdapter->CSRAddress->mac.cfg1.bits.syncd_rx_en || + !pAdapter->CSRAddress->mac.cfg1.bits.syncd_tx_en ) && + ( delay < 100 )); + + if( delay == 100 ) + { + DBG_ERROR( et131x_dbginfo, + "Syncd bits did not respond correctly cfg1 word 0x%08x\n", + pAdapter->CSRAddress->mac.cfg1.value ); + } + + DBG_TRACE( et131x_dbginfo, + "Speed %d, Dup %d, CFG1 0x%08x, CFG2 0x%08x, if_ctrl 0x%08x\n", + pAdapter->uiLinkSpeed, pAdapter->uiDuplexMode, + pAdapter->CSRAddress->mac.cfg1.value, + pAdapter->CSRAddress->mac.cfg2.value, + pAdapter->CSRAddress->mac.if_ctrl.value ); + + + /************************************************************************** + Enable TXMAC + *************************************************************************/ + ctl.bits.txmac_en = 0x1; + ctl.bits.fc_disable = 0x1; + pAdapter->CSRAddress->txmac.ctl = ctl; + + + /************************************************************************** + Ready to start the RXDMA/TXDMA engine + *************************************************************************/ + if( !MP_TEST_FLAG( pAdapter, fMP_ADAPTER_LOWER_POWER )) + { + et131x_rx_dma_enable( pAdapter ); + et131x_tx_dma_enable( pAdapter ); + } + else + { + DBG_WARNING( et131x_dbginfo, + "Didn't enable Rx/Tx due to low-power mode\n" ); + } + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: ConfigRxMacRegs + ****************************************************************************** + + DESCRIPTION: + Used to configure the RX MAC registers in the JAGCore + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +void ConfigRxMacRegs( ET131X_ADAPTER *pAdapter ) +{ + PRXMAC_t pRxMac; + RXMAC_WOL_SA_LO_t sa_lo; + RXMAC_WOL_SA_HI_t sa_hi; + RXMAC_PF_CTRL_t pf_ctrl = {0}; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "ConfigRxMacRegs" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Let's get a local pointer to the RX MAC Registers + *************************************************************************/ + pRxMac = &pAdapter->CSRAddress->rxmac; + + + /************************************************************************** + Disable the MAC while it is being configured (also disable WOL) + *************************************************************************/ + pRxMac->ctrl.value = 0x8; + + + /************************************************************************** + Initialize WOL to disabled. + *************************************************************************/ + + pRxMac->crc0.value = 0x0; + pRxMac->crc12.value = 0x0000; + pRxMac->crc34.value = 0x0000; + + + /************************************************************************** + We need to set the WOL mask0 – mask4 next. We initialize it to its + default Values of 0x00000000 because there are not WOL masks as of + this time. + *************************************************************************/ + pRxMac->mask0_word0.mask = 0x00000000; + pRxMac->mask0_word1.mask = 0x00000000; + pRxMac->mask0_word2.mask = 0x00000000; + pRxMac->mask0_word3.mask = 0x00000000; + + pRxMac->mask1_word0.mask = 0x00000000; + pRxMac->mask1_word1.mask = 0x00000000; + pRxMac->mask1_word2.mask = 0x00000000; + pRxMac->mask1_word3.mask = 0x00000000; + + pRxMac->mask2_word0.mask = 0x00000000; + pRxMac->mask2_word1.mask = 0x00000000; + pRxMac->mask2_word2.mask = 0x00000000; + pRxMac->mask2_word3.mask = 0x00000000; + + pRxMac->mask3_word0.mask = 0x00000000; + pRxMac->mask3_word1.mask = 0x00000000; + pRxMac->mask3_word2.mask = 0x00000000; + pRxMac->mask3_word3.mask = 0x00000000; + + pRxMac->mask4_word0.mask = 0x00000000; + pRxMac->mask4_word1.mask = 0x00000000; + pRxMac->mask4_word2.mask = 0x00000000; + pRxMac->mask4_word3.mask = 0x00000000; + + + /************************************************************************** + Lets setup the WOL Source Address + *************************************************************************/ + sa_lo.bits.sa3 = pAdapter->CurrentAddress[2]; + sa_lo.bits.sa4 = pAdapter->CurrentAddress[3]; + sa_lo.bits.sa5 = pAdapter->CurrentAddress[4]; + sa_lo.bits.sa6 = pAdapter->CurrentAddress[5]; + pRxMac->sa_lo.value = sa_lo.value; + + sa_hi.bits.sa1 = pAdapter->CurrentAddress[0]; + sa_hi.bits.sa2 = pAdapter->CurrentAddress[1]; + pRxMac->sa_hi.value = sa_hi.value; + + + /************************************************************************** + Disable all Packet Filtering + *************************************************************************/ + pRxMac->pf_ctrl.value = 0; + + + /************************************************************************** + Let's initialize the Unicast Packet filtering address + *************************************************************************/ + if( pAdapter->PacketFilter & ET131X_PACKET_TYPE_DIRECTED ) + { + SetupDeviceForUnicast( pAdapter ); + pf_ctrl.bits.filter_uni_en = 1; + } + else + { + pRxMac->uni_pf_addr1.value = 0x00000000; + pRxMac->uni_pf_addr2.value = 0x00000000; + pRxMac->uni_pf_addr3.value = 0x00000000; + } + + + /************************************************************************** + Let's initialize the Multicast hash + *************************************************************************/ + if( pAdapter->PacketFilter & ET131X_PACKET_TYPE_ALL_MULTICAST ) + { + pf_ctrl.bits.filter_multi_en = 0; + } + else + { + pf_ctrl.bits.filter_multi_en = 1; + SetupDeviceForMulticast( pAdapter ); + } + + + /************************************************************************** + Runt packet filtering. Didn't work in version A silicon. + *************************************************************************/ + pf_ctrl.bits.min_pkt_size = NIC_MIN_PACKET_SIZE + 4; + pf_ctrl.bits.filter_frag_en = 1; + + if( pAdapter->RegistryJumboPacket > 8192 ) + { + RXMAC_MCIF_CTRL_MAX_SEG_t mcif_ctrl_max_seg; + + + /********************************************************************** + In order to transmit jumbo packets greater than 8k, the FIFO + between RxMAC and RxDMA needs to be reduced in size to (16k - + Jumbo packet size). In order to implement this, we must use + "cut through" mode in the RxMAC, which chops packets down into + segments which are (max_size * 16). In this case we selected + 256 bytes, since this is the size of the PCI-Express TLP's that + the 1310 uses. + *********************************************************************/ + mcif_ctrl_max_seg.bits.seg_en = 0x1; + mcif_ctrl_max_seg.bits.fc_en = 0x0; + mcif_ctrl_max_seg.bits.max_size = 0x10; + + pRxMac->mcif_ctrl_max_seg.value = mcif_ctrl_max_seg.value; + } + else + { + pRxMac->mcif_ctrl_max_seg.value = 0x0; + } + + + /************************************************************************** + Initialize the MCIF water marks + *************************************************************************/ + pRxMac->mcif_water_mark.value = 0x0; + + + /************************************************************************** + Initialize the MIF control + *************************************************************************/ + pRxMac->mif_ctrl.value = 0x0; + + + /************************************************************************** + Initialize the Space Available Register + *************************************************************************/ + pRxMac->space_avail.value = 0x0; + + /* Initialize the the mif_ctrl register + * bit 3 - Receive code error. One or more nibbles were signaled as errors + during the reception of the packet. Clear this bit in Gigabit, + set it in 100Mbit. This was derived experimentally at UNH. + * bit 4 - Receive CRC error. The packet’s CRC did not match the + internally generated CRC. + * bit 5 - Receive length check error. Indicates that frame length field + value in the packet does not match the actual data byte length + and is not a type field. + * bit 16 - Receive frame truncated. + * bit 17 - Drop packet enable + */ + if( pAdapter->uiLinkSpeed == TRUEPHY_SPEED_100MBPS ) + { + pRxMac->mif_ctrl.value = 0x30038; + } + else + { + pRxMac->mif_ctrl.value = 0x30030; + } + + + /************************************************************************** + Finally we initialize RxMac to be enabled & WOL disabled. Packet filter + is always enabled since it is where the runt packets are supposed to be + dropped. For version A silicon, runt packet dropping doesn't work, so + it is disabled in the pf_ctrl register, but we still leave the packet + filter on. + *************************************************************************/ + pRxMac->pf_ctrl = pf_ctrl; + pRxMac->ctrl.value = 0x9; + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: ConfigTxMacRegs + ****************************************************************************** + + DESCRIPTION: + used to configure the TX MAC registers of the JAGCore + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +void ConfigTxMacRegs( ET131X_ADAPTER *pAdapter ) +{ + PTXMAC_t pTxMac; + TXMAC_CF_PARAM_t Local; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "ConfigTxMacRegs" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Let's get the pointer to tx mac section of regs + *************************************************************************/ + pTxMac = &pAdapter->CSRAddress->txmac; + + + /************************************************************************** + We need to update the Control Frame Parameters + cfpt - control frame pause timer set to 64 (0x40) + cfep - control frame extended pause timer set to 0x0 + *************************************************************************/ + if( pAdapter->FlowControl == None ) + { + pTxMac->cf_param.value = 0x0; + } + else + { + Local.bits.cfpt = 0x40; + Local.bits.cfep = 0x0; + pTxMac->cf_param.value = Local.value; + } + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: ConfigMacStatRegs + ****************************************************************************** + + DESCRIPTION: + Used to configure the MAC STAT section of the JAGCore + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +void ConfigMacStatRegs( ET131X_ADAPTER *pAdapter ) +{ + PMAC_STAT_t pDevMacStat; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "ConfigMacStatRegs" ); + DBG_ENTER( et131x_dbginfo ); + + + pDevMacStat = &pAdapter->CSRAddress->macStat; + + + /************************************************************************** + Next we need to initialize all the MAC_STAT registers to zero on the + device. + *************************************************************************/ + pDevMacStat->RFcs = 0x0; + pDevMacStat->RAln = 0x0; + pDevMacStat->RFlr = 0x0; + pDevMacStat->RDrp = 0x0; + pDevMacStat->RCde = 0x0; + pDevMacStat->ROvr = 0x0; + pDevMacStat->RFrg = 0x0; + + pDevMacStat->TScl = 0x0; + pDevMacStat->TDfr = 0x0; + pDevMacStat->TMcl = 0x0; + pDevMacStat->TLcl = 0x0; + pDevMacStat->TNcl = 0x0; + pDevMacStat->TOvr = 0x0; + pDevMacStat->TUnd = 0x0; + + + /*************************************************************************** + Unmask any counters that we want to track the overflow of. Initially + this will be all counters. It may become clear later that we do not + need to track all counters. + **************************************************************************/ + { + MAC_STAT_REG_1_t Carry1M = {0xffffffff}; + + Carry1M.bits.rdrp = 0x0; + Carry1M.bits.rjbr = 0x1; + Carry1M.bits.rfrg = 0x0; + Carry1M.bits.rovr = 0x0; + Carry1M.bits.rund = 0x1; + Carry1M.bits.rcse = 0x1; + Carry1M.bits.rcde = 0x0; + Carry1M.bits.rflr = 0x0; + Carry1M.bits.raln = 0x0; + Carry1M.bits.rxuo = 0x1; + Carry1M.bits.rxpf = 0x1; + Carry1M.bits.rxcf = 0x1; + Carry1M.bits.rbca = 0x1; + Carry1M.bits.rmca = 0x1; + Carry1M.bits.rfcs = 0x0; + Carry1M.bits.rpkt = 0x1; + Carry1M.bits.rbyt = 0x1; + Carry1M.bits.trmgv = 0x1; + Carry1M.bits.trmax = 0x1; + Carry1M.bits.tr1k = 0x1; + Carry1M.bits.tr511 = 0x1; + Carry1M.bits.tr255 = 0x1; + Carry1M.bits.tr127 = 0x1; + Carry1M.bits.tr64 = 0x1; + + pDevMacStat->Carry1M = Carry1M; + } + + { + MAC_STAT_REG_2_t Carry2M = {0xffffffff}; + + Carry2M.bits.tdrp = 0x1; + Carry2M.bits.tpfh = 0x1; + Carry2M.bits.tncl = 0x0; + Carry2M.bits.txcl = 0x1; + Carry2M.bits.tlcl = 0x0; + Carry2M.bits.tmcl = 0x0; + Carry2M.bits.tscl = 0x0; + Carry2M.bits.tedf = 0x1; + Carry2M.bits.tdfr = 0x0; + Carry2M.bits.txpf = 0x1; + Carry2M.bits.tbca = 0x1; + Carry2M.bits.tmca = 0x1; + Carry2M.bits.tpkt = 0x1; + Carry2M.bits.tbyt = 0x1; + Carry2M.bits.tfrg = 0x1; + Carry2M.bits.tund = 0x0; + Carry2M.bits.tovr = 0x0; + Carry2M.bits.txcf = 0x1; + Carry2M.bits.tfcs = 0x1; + Carry2M.bits.tjbr = 0x1; + + pDevMacStat->Carry2M = Carry2M; + } + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: ConfigFlowControl + ****************************************************************************** + + DESCRIPTION: + Used to configure the MAC STAT section of the JAGCore + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +void ConfigFlowControl( ET131X_ADAPTER *pAdapter ) +{ + if( pAdapter->uiDuplexMode == 0 ) + { + pAdapter->FlowControl = None; + } + else + { + char RemotePause, RemoteAsyncPause; + + ET1310_PhyAccessMiBit( pAdapter, + TRUEPHY_BIT_READ, 5, 10, &RemotePause ); + ET1310_PhyAccessMiBit( pAdapter, + TRUEPHY_BIT_READ, 5, 11, &RemoteAsyncPause ); + + if(( RemotePause == TRUEPHY_BIT_SET ) && + ( RemoteAsyncPause == TRUEPHY_BIT_SET )) + { + pAdapter->FlowControl = pAdapter->RegistryFlowControl; + } + else if(( RemotePause == TRUEPHY_BIT_SET ) && + ( RemoteAsyncPause == TRUEPHY_BIT_CLEAR )) + { + if( pAdapter->RegistryFlowControl == Both ) + { + pAdapter->FlowControl = Both; + } + else + { + pAdapter->FlowControl = None; + } + } + else if(( RemotePause == TRUEPHY_BIT_CLEAR ) && + ( RemoteAsyncPause == TRUEPHY_BIT_CLEAR )) + { + pAdapter->FlowControl = None; + } + else /* if (( RemotePause == TRUEPHY_CLEAR_BIT ) && + ( RemoteAsyncPause == TRUEPHY_SET_BIT )) */ + { + if( pAdapter->RegistryFlowControl == Both ) + { + pAdapter->FlowControl = RxOnly; + } + else + { + pAdapter->FlowControl = None; + } + } + } +} +/*===========================================================================*/ + + + + + + +/****************************************************************************** + ROUTINE: UpdateMacStatHostCounters + ****************************************************************************** + + DESCRIPTION: + used to update the local copy of the statistics held in the adapter + structure + + PARAMETERS : + pAdapter - pointer to the adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +void UpdateMacStatHostCounters( ET131X_ADAPTER *pAdapter ) +{ + PMAC_STAT_t pDevMacStat; + /*-----------------------------------------------------------------------*/ + + + /************************************************************************** + Get a local pointer to the adapter macstat regs and update stats + *************************************************************************/ + pDevMacStat = &pAdapter->CSRAddress->macStat; + + pAdapter->Stats.collisions += pDevMacStat->TNcl; + pAdapter->Stats.first_collision += pDevMacStat->TScl; + pAdapter->Stats.tx_deferred += pDevMacStat->TDfr; + pAdapter->Stats.excessive_collisions += pDevMacStat->TMcl; + pAdapter->Stats.late_collisions += pDevMacStat->TLcl; + pAdapter->Stats.tx_uflo += pDevMacStat->TUnd; + pAdapter->Stats.max_pkt_error += pDevMacStat->TOvr; + + pAdapter->Stats.alignment_err += pDevMacStat->RAln; + pAdapter->Stats.crc_err += pDevMacStat->RCde; + pAdapter->Stats.norcvbuf += pDevMacStat->RDrp; + pAdapter->Stats.rx_ov_flow += pDevMacStat->ROvr; + pAdapter->Stats.code_violations += pDevMacStat->RFcs; + pAdapter->Stats.length_err += pDevMacStat->RFlr; + + pAdapter->Stats.other_errors += pDevMacStat->RFrg; + + return; +} +/*===========================================================================*/ + + + + + +/****************************************************************************** + ROUTINE: HandleMacStatInterrupt + ****************************************************************************** + + DESCRIPTION: + One of the MACSTAT counters has wrapped. Update the local copy of + the statistics held in the adapter structure, checking the "wrap" + bit for each counter. + + PARAMETERS : + pAdapter - pointer to the adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +void HandleMacStatInterrupt( ET131X_ADAPTER *pAdapter ) +{ + MAC_STAT_REG_1_t Carry1; + MAC_STAT_REG_2_t Carry2; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "HandleMacStatInterrupt" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Read the interrupt bits from the register(s). These are Clear On Write. + *************************************************************************/ + Carry1 = pAdapter->CSRAddress->macStat.Carry1; + Carry2 = pAdapter->CSRAddress->macStat.Carry2; + + pAdapter->CSRAddress->macStat.Carry1 = Carry1; + pAdapter->CSRAddress->macStat.Carry2 = Carry2; + + + /************************************************************************** + We need to do update the host copy of all the MAC_STAT counters. For + each counter, check it's overflow bit. If the overflow bit is set, then + increment the host version of the count by one complete revolution of the + counter. This routine is called when the counter block indicates that + one of the counters has wrapped. + *************************************************************************/ + if( Carry1.bits.rfcs ) + { + pAdapter->Stats.code_violations += COUNTER_WRAP_16_BIT; + } + + if( Carry1.bits.raln ) + { + pAdapter->Stats.alignment_err += COUNTER_WRAP_12_BIT; + } + + if( Carry1.bits.rflr ) + { + pAdapter->Stats.length_err += COUNTER_WRAP_16_BIT; + } + + if( Carry1.bits.rfrg ) + { + pAdapter->Stats.other_errors += COUNTER_WRAP_16_BIT; + } + + if( Carry1.bits.rcde ) + { + pAdapter->Stats.crc_err += COUNTER_WRAP_16_BIT; + } + + if( Carry1.bits.rovr ) + { + pAdapter->Stats.rx_ov_flow += COUNTER_WRAP_16_BIT; + } + + if( Carry1.bits.rdrp ) + { + pAdapter->Stats.norcvbuf += COUNTER_WRAP_16_BIT; + } + + if( Carry2.bits.tovr ) + { + pAdapter->Stats.max_pkt_error += COUNTER_WRAP_12_BIT; + } + + if( Carry2.bits.tund ) + { + pAdapter->Stats.tx_uflo += COUNTER_WRAP_12_BIT; + } + + if( Carry2.bits.tscl ) + { + pAdapter->Stats.first_collision += COUNTER_WRAP_12_BIT; + } + + if( Carry2.bits.tdfr ) + { + pAdapter->Stats.tx_deferred += COUNTER_WRAP_12_BIT; + } + + if( Carry2.bits.tmcl ) + { + pAdapter->Stats.excessive_collisions += COUNTER_WRAP_12_BIT; + } + + if( Carry2.bits.tlcl ) + { + pAdapter->Stats.late_collisions += COUNTER_WRAP_12_BIT; + } + + if( Carry2.bits.tncl ) + { + pAdapter->Stats.collisions += COUNTER_WRAP_12_BIT; + } + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : SetupDeviceForMulticast + ****************************************************************************** + + DESCRIPTION : + Use to set the ET1310 to do multicast filtering + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + NONE + + REUSE INFORMATION : + NONE + + *****************************************************************************/ +void SetupDeviceForMulticast( ET131X_ADAPTER *pAdapter ) +{ + UINT32 nIndex; + UINT32 result; + RXMAC_MULTI_HASH_t hash1 = {0}; + RXMAC_MULTI_HASH_t hash2 = {0}; + RXMAC_MULTI_HASH_t hash3 = {0}; + RXMAC_MULTI_HASH_t hash4 = {0}; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "SetupDeviceForMulticast" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + If ET131X_PACKET_TYPE_MULTICAST is specified, then we provision the + multi-cast LIST. If it is NOT specified, (and "ALL" is not specified) + then we should pass NO multi-cast addresses to the driver. + *************************************************************************/ + if( pAdapter->PacketFilter & ET131X_PACKET_TYPE_MULTICAST ) + { + DBG_VERBOSE( et131x_dbginfo, "MULTICAST flag is set, MCCount: %d\n", + pAdapter->MCAddressCount ); + + + /********************************************************************** + Loop through our multicast array and set up the device + **********************************************************************/ + for( nIndex = 0; nIndex < pAdapter->MCAddressCount; nIndex++ ) + { + DBG_VERBOSE( et131x_dbginfo, + "MCList[%d]: %02x:%02x:%02x:%02x:%02x:%02x\n", + nIndex, + pAdapter->MCList[nIndex][0], + pAdapter->MCList[nIndex][1], + pAdapter->MCList[nIndex][2], + pAdapter->MCList[nIndex][3], + pAdapter->MCList[nIndex][4], + pAdapter->MCList[nIndex][5] ); + + result = et131x_calc_enet_crc( pAdapter->MCList[nIndex], 6 ); + + result = ( result & 0x3F800000 ) >> 23; + + if( result < 32 ) + { + hash1.hash |= ( 1 << result ); + } + else if(( 31 < result ) && ( result < 64 )) + { + result -= 32; + hash2.hash |= ( 1 << result ); + } + else if(( 63 < result ) && ( result < 96 )) + { + result -= 64; + hash3.hash |= ( 1 << result ); + } + else + { + result -= 96; + hash4.hash |= ( 1 << result ); + } + } + } + + + /************************************************************************** + Write out the new hash to the device + *************************************************************************/ + if( pAdapter->CSRAddress->global.pm_csr.bits.pm_phy_sw_coma == 0 ) + { + pAdapter->CSRAddress->rxmac.multi_hash1.hash = hash1.hash; + pAdapter->CSRAddress->rxmac.multi_hash2.hash = hash2.hash; + pAdapter->CSRAddress->rxmac.multi_hash3.hash = hash3.hash; + pAdapter->CSRAddress->rxmac.multi_hash4.hash = hash4.hash; + } + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : SetupDeviceForUnicast + ****************************************************************************** + + DESCRIPTION : + Use to set the ET1310 to do unicast filtering + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + NONE + + REUSE INFORMATION : + NONE + + *****************************************************************************/ +void SetupDeviceForUnicast( ET131X_ADAPTER *pAdapter ) +{ + RXMAC_UNI_PF_ADDR1_t uni_pf1; + RXMAC_UNI_PF_ADDR2_t uni_pf2; + RXMAC_UNI_PF_ADDR3_t uni_pf3; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "SetupDeviceForUnicast" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Set up unicast packet filter reg 3 to be the first two octets of the + MAC address for both address + *************************************************************************/ + /************************************************************************** + Set up unicast packet filter reg 2 to be the octets 2 - 5 of the + MAC address for second address + *************************************************************************/ + /************************************************************************** + Set up unicast packet filter reg 3 to be the octets 2 - 5 of the + MAC address for first address + *************************************************************************/ + uni_pf3.bits.addr1_1 = pAdapter->CurrentAddress[0]; + uni_pf3.bits.addr1_2 = pAdapter->CurrentAddress[1]; + uni_pf3.bits.addr2_1 = pAdapter->CurrentAddress[0]; + uni_pf3.bits.addr2_2 = pAdapter->CurrentAddress[1]; + + uni_pf2.bits.addr2_3 = pAdapter->CurrentAddress[2]; + uni_pf2.bits.addr2_4 = pAdapter->CurrentAddress[3]; + uni_pf2.bits.addr2_5 = pAdapter->CurrentAddress[4]; + uni_pf2.bits.addr2_6 = pAdapter->CurrentAddress[5]; + + uni_pf1.bits.addr1_3 = pAdapter->CurrentAddress[2]; + uni_pf1.bits.addr1_4 = pAdapter->CurrentAddress[3]; + uni_pf1.bits.addr1_5 = pAdapter->CurrentAddress[4]; + uni_pf1.bits.addr1_6 = pAdapter->CurrentAddress[5]; + + if( pAdapter->CSRAddress->global.pm_csr.bits.pm_phy_sw_coma == 0 ) + { + pAdapter->CSRAddress->rxmac.uni_pf_addr1 = uni_pf1; + pAdapter->CSRAddress->rxmac.uni_pf_addr2 = uni_pf2; + pAdapter->CSRAddress->rxmac.uni_pf_addr3 = uni_pf3; + } + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ --- linux-2.6.27.orig/ubuntu/et131x/ET1310_pm.c +++ linux-2.6.27/ubuntu/et131x/ET1310_pm.c @@ -0,0 +1,1723 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * ET1310_pm.c - All power management related code (not completely implemented) + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2006/01/20 21:29:44 $ + $Revision: 1.8 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +/****************************************************************************** + Includes + *****************************************************************************/ +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include +#include +#include +#include + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ET1310_phy.h" +#include "ET1310_pm.h" +#include "ET1310_jagcore.h" +#include "ET1310_mac.h" +#include "ET1310_rx.h" + +#include "et131x_supp.h" +#include "et131x_adapter.h" +#include "et131x_initpci.h" + + + + +/****************************************************************************** + Data for debugging facilities + *****************************************************************************/ +#ifdef ET131X_DBG +extern dbg_info_t *et131x_dbginfo; +#endif /* ET131X_DBG */ + + + + +/****************************************************************************** + ROUTINE: CalculateCCITCRC16 + ****************************************************************************** + DESCRIPTION: + This routine calculates the CCIT CRC-16 value required for power + management. + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +UINT16 CalculateCCITCRC16( PUCHAR Pattern, PUCHAR Mask, UINT32 MaskSize ) +{ + UINT32 i, j, k, HitBit; + UINT16 RemainderCRC = 0xFFFF; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "CalculateCCITCRC16" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + There is one bit in the mask for every byte in the pattern. Therefore, + this first loop (the "i" loop) iterates over every byte in the mask, + the inner "j" loop iterates over every bit in each byte. If that bit + in the mask is clear, then we skip over this byte of packet date (the + "continue"). + *************************************************************************/ + for( i = 0; i < MaskSize; i++ ) + { + for( j = 0; j < 8; j++ ) + { + if(( Mask[i] & ( 1 << j )) == 0 ) + { + continue; + } + + /****************************************************************** + Following 10 lines iterates over every bit in this byte of the + pattern, and applies the CRC-16 calculation as defined by CCIT. + It could be optimized using a look-up-table, but this function + will be called infrequently, so the memory overhead of + optimization can be avoided. + *****************************************************************/ + for( k = 0; k < 8; k++ ) + { + HitBit = (( RemainderCRC >> 15 ) & 1 ); + HitBit ^= ( Pattern[(i*8)+j] >> k ) & 1; + + RemainderCRC <<= 1; + + if( HitBit ) + { + RemainderCRC ^= CRC16_POLY; + } + } + } + } + + DBG_LEAVE( et131x_dbginfo ); + return( RemainderCRC ); +} + +/*===========================================================================*/ + + + +#if 0 +/****************************************************************************** + ROUTINE: MPSetPowerD0 + ****************************************************************************** + DESCRIPTION: + Used to set the power state to D0, Updated for the ET1310 + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +VOID MPSetPowerD0( IN PMP_ADAPTER pAdapter ) +{ + UINT32 uPmCsr; + NDIS_DEVICE_POWER_STATE ComingBackFrom; + PM_CSR_t pm_csr = pAdapter->CSRAddress->global.pm_csr; + RXMAC_CTRL_t ctrl; + MI_ISR_t isr; + MI_BMSR_t Bmsr, BmsrInts; + UINT32 delay = 0; + + /*-----------------------------------------------------------------------*/ + + DBGPRINT( MP_TRACE, ( "----> MPSetPowerD0\n" )); + + /************************************************************************** + Archive the power-state we are returning from, and then set the + "current" power state back to fully operational + *************************************************************************/ + ComingBackFrom = pAdapter->PoMgmt.PowerState; + pAdapter->PoMgmt.PowerState = NdisDeviceStateD0; + + + /********************************************************************** + Allow disabling of Non-Maskable Interrupts in I/O space, to + support validation. + *********************************************************************/ + if( pAdapter->RegistryNMIDisable ) + { + UCHAR RegisterVal; + + NdisRawReadPortUchar( ET1310_NMI_DISABLE, &RegisterVal ); + + RegisterVal &= 0xf3; + + if( pAdapter->RegistryNMIDisable == 2 ) + { + RegisterVal |= 0xc; + } + + NdisRawWritePortUchar( ET1310_NMI_DISABLE, RegisterVal ); + } + + { + UCHAR read_size_reg; + + /****************************************************************** + Change the max read size to 2k + *****************************************************************/ + NdisReadPciSlotInformation( pAdapter->AdapterHandle, + 0, // not used + 0x51, + (PVOID)&read_size_reg, + sizeof( UCHAR )); + + read_size_reg &= 0x8f; + read_size_reg |= 0x40; + + NdisWritePciSlotInformation( pAdapter->AdapterHandle, + 0, + 0x51, + &read_size_reg, + sizeof( UCHAR )); + } + + + /************************************************************************** + Sample read of pmcsr to aid validation. Will be catured by PCI-e + analyzer + *************************************************************************/ + NdisReadPciSlotInformation( pAdapter->AdapterHandle, + 0, // Slot no. Reserved. Ndis ignores. + ET1310_PCI_PM_CSR, + (PVOID)&uPmCsr, + sizeof( UINT32 )); + + /************************************************************************** + we now need to set the JAGCore gating control registers for this power + state. Bypass this for nonwake device since in that case the JAGCore + and gigE PHY have been reset + + This is only supposeto be for wake mode, when in non-wake mode, the + device enters L1 which causes a reset of the jagcore which basically + clears the PM_STATE. But due to issue with system not staying in L1 the + hardware reset is not happening. So we take care of it here. + *************************************************************************/ + if( TRUE ) //pAdapter->PoMgmt.WOLEnabled ) + { + pm_csr.bits.pm_gigephy_en = 0; + pm_csr.bits.pm_jagcore_rx_en = 0; + pm_csr.bits.pm_jagcore_tx_en = 0; + pm_csr.bits.pm_phy_lped_en = 0; + pm_csr.bits.pm_phy_sw_coma = 0; + + /********************************************************************** + enable clock first + *********************************************************************/ + pm_csr.bits.pm_sysclk_gate = 1; + pm_csr.bits.pm_txclk_gate = 1; + pm_csr.bits.pm_rxclk_gate = 1; + + /********************************************************************** + tx_en and rx_en should remain the same as in power down + *********************************************************************/ + pAdapter->CSRAddress->global.pm_csr = pm_csr; + + /********************************************************************** + poll the PMSTATE until JAGCore is in normal state + *********************************************************************/ + while(( pAdapter->CSRAddress->global.pm_csr.bits.pm_jagcore_rx_rdy != 0 ) && + ( pAdapter->CSRAddress->global.pm_csr.bits.pm_jagcore_tx_rdy != 0 ) && + ( delay < 100 )) + { + NdisStallExecution( 10 ); + delay++; + } + + if( delay >= 100 ) + { + pm_csr = pAdapter->CSRAddress->global.pm_csr; + + pm_csr.bits.pm_jagcore_rx_en = 0; + pm_csr.bits.pm_jagcore_tx_en = 0; + pAdapter->CSRAddress->global.pm_csr.value = pm_csr.value; + } + } + + /************************************************************************** + now lets set up JAGcore pm control for D0 + *************************************************************************/ + pm_csr.bits.pm_gigephy_en = 0; + + pm_csr.bits.pm_jagcore_rx_en = pAdapter->PoMgmt.rx_en; + pm_csr.bits.pm_jagcore_tx_en = pAdapter->PoMgmt.tx_en; + + pAdapter->CSRAddress->global.pm_csr = pm_csr; + + /************************************************************************** + we also need to read and clear the phy_interrupt register in case of + wakeup on link status change + *************************************************************************/ + MiRead( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + (UINT8)FIELD_OFFSET( MI_REGS_t, isr ), &isr.value ); + + /************************************************************************** + disable WOL + *************************************************************************/ + ctrl = pAdapter->CSRAddress->rxmac.ctrl; + + ctrl.bits.wol_disable = 1; + ctrl.bits.mif_disable = 0; + ctrl.bits.async_disable = 0; + + pAdapter->CSRAddress->rxmac.ctrl = ctrl; + + /************************************************************************** + Set the power state to 0 (d0), and flip the PME status pin. Clear the + PME Enable pin, if it were set. + *************************************************************************/ + uPmCsr = 0x00008000; + NdisWritePciSlotInformation( pAdapter->AdapterHandle, + 0, // Slot no. Reserved. Ndis ignores. + ET1310_PCI_PM_CSR, + &uPmCsr, + sizeof( UINT32 )); + + /************************************************************************** + When the adapter is placed in D3 wake, it is set in 10 Base-T + half-duplex mode. However, we archived the speed and duplex settings + that were current prior to that, so restore them now and then tell + the phy to do it's thing. + *************************************************************************/ + if(( ComingBackFrom == NdisDeviceStateD3 ) || + ( ComingBackFrom == NdisDeviceStateD1 && !pAdapter->PoMgmt.WOLEnabledByCurrentState )) + { + pAdapter->AiForceSpeed = pAdapter->PoMgmt.PowerDownSpeed; + pAdapter->AiForceDpx = pAdapter->PoMgmt.PowerDownDuplex; + + /********************************************************************** + Re-initialize the send structures + **********************************************************************/ + MPInitSend( pAdapter ); + + /********************************************************************** + Reset the RFD list and re-start RU + *********************************************************************/ + NICResetRecv( pAdapter ); + + /********************************************************************** + Bring the device back to the state it was during init prior + to autonegotiation being complete. This way, when we get the + auto-neg complete interrupt, we can complete init by calling + ConfigMacREGS2. + *********************************************************************/ + HwSoftwareReset( pAdapter ); + + /********************************************************************** + setup et1310 as per the documentation + *********************************************************************/ + NICSetAdapterUp( pAdapter ); + } + + /************************************************************************** + Allow Tx to restart + *************************************************************************/ + MP_CLEAR_FLAG( pAdapter, fMP_ADAPTER_LOWER_POWER ); + + /************************************************************************** + Check to see if the link status bit is set in the BMSR register, if it + is not, this means we had a cable pull when at a lower power state and + need to indicate that we are disconnected to NDIS + *************************************************************************/ + MiRead( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + (UINT8)FIELD_OFFSET( MI_REGS_t, bmsr ), &Bmsr.value ); + + if( !Bmsr.bits.link_status ) + { + + pAdapter->Bmsr.value = Bmsr.value; + + NdisAcquireSpinLock( &pAdapter->Lock ); + MP_SET_FLAG( pAdapter, fMP_ADAPTER_LINK_DETECTION ); + pAdapter->MediaState = 0; + + NdisReleaseSpinLock( &pAdapter->Lock ); + + // get timer going again... + NdisMSetPeriodicTimer( &pAdapter->PeriodicTimer, + TX_ERROR_PERIOD ); + + // setup for possible disconnect + NdisMSetTimer( &pAdapter->LinkDetectionTimer, + LINK_DETECTION_TIMER ); + + pAdapter->bLinkTimerActive = TRUE; + + if( pAdapter->RegistryPhyComa ) + { + MPSetPhyComa( pAdapter ); + } + /********************************************************************** + In the case of link-in before sleep, link-out after sleep, we need + to re-start the start-of-day timer so that we eventually flop + into PhyComa. In this case, the above state change gets overwritten + since we get a PHY interrupt almost straight away, and PHY interrupt + handling pulls us out of PHY coma mode. + *********************************************************************/ + pAdapter->PoMgmt.TransPhyComaModeOnBoot = 0; + } + + /************************************************************************** + we need to enable interrupts + *************************************************************************/ + NdisMSynchronizeWithInterrupt( &pAdapter->Interrupt, + (PVOID)NICEnableInterrupts, + pAdapter ); + + DBGPRINT( MP_TRACE, ( "<---- MPSetPowerD0\n" )); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: MPSetLowPower + ****************************************************************************** + DESCRIPTION: + This routine is called when the adapter receives a SetPower to any + state other than d0. Most of the common stuff for setting to a lower + power state should be handled in here. + + PARAMETERS : + pAdapter - pointer to our adapter structure + PowerState - NewPowerState + + RETURNS : + NONE + + *****************************************************************************/ +VOID MPSetLowPower( IN PMP_ADAPTER pAdapter, + IN NDIS_DEVICE_POWER_STATE PowerState ) +{ + PM_CSR_t GlobalPmCSR; + RXMAC_CTRL_t ctrl; + MI_ISR_t isr; + MI_BMSR_t lBmsr; + BOOLEAN bDummy; + /*-----------------------------------------------------------------------*/ + + /************************************************************************** + if we are in coma mode when we get this request, we need to disable it + *************************************************************************/ + if( pAdapter->CSRAddress->global.pm_csr.bits.pm_phy_sw_coma == 1 ) + { + /********************************************************************** + check to see if we are in coma mode and if so, disable it because + we will not be able to read phy values until we are out. + *********************************************************************/ + MPDisablePhyComa( pAdapter ); + } + + /************************************************************************** + interrupts will be queued until after this routine completes. May as + well disable them now, since we do not want any of the queued interrupts. + *************************************************************************/ + NdisMSynchronizeWithInterrupt( &pAdapter->Interrupt, + (PVOID)NICDisableInterrupts, + pAdapter ); + + /************************************************************************** + Set the adapter power state to requested, lower state + *************************************************************************/ + pAdapter->PoMgmt.PowerState = PowerState; + + /************************************************************************** + Cancel timers - start them again when power restored + *************************************************************************/ + NdisMCancelTimer( &pAdapter->PeriodicTimer, &bDummy ); + + if( pAdapter->bLinkTimerActive == TRUE ){ + NdisMCancelTimer( &pAdapter->LinkDetectionTimer, &bDummy ); + } + + /************************************************************************** + Save the GbE PHY speed and duplex modes + + Need to restore this for: D1 nonwake, D3 wake and nonwake modes + *************************************************************************/ + pAdapter->PoMgmt.PowerDownSpeed = pAdapter->AiForceSpeed; + pAdapter->PoMgmt.PowerDownDuplex = pAdapter->AiForceDpx; + + NdisAcquireSpinLock( &pAdapter->SendHWLock ); + + /************************************************************************** + Stop sending packets. + *************************************************************************/ + MP_SET_FLAG( pAdapter, fMP_ADAPTER_LOWER_POWER ); + + NdisReleaseSpinLock( &pAdapter->SendHWLock ); + + /************************************************************************** + Free the packets being actively sent & stopped + **************************************************************************/ + MpFreeBusySendPackets( pAdapter ); + + /************************************************************************** + Save Rx/Tx enable condition. Used during restore to D0 state. + *************************************************************************/ + pAdapter->PoMgmt.tx_en = pAdapter->CSRAddress->global.pm_csr.bits.pm_jagcore_tx_en; + pAdapter->PoMgmt.rx_en = pAdapter->CSRAddress->global.pm_csr.bits.pm_jagcore_rx_en; + + /************************************************************************** + set the JAGCore gating control registers for this power state + *************************************************************************/ + GlobalPmCSR = pAdapter->CSRAddress->global.pm_csr; + + if( pAdapter->PoMgmt.WOLEnabledByCurrentState ) + { + GlobalPmCSR.bits.pm_gigephy_en = 0; + } + else + { + GlobalPmCSR.bits.pm_gigephy_en = 1; + } + + /************************************************************************** + only exercise the PM state machine when the link is up + *************************************************************************/ + if( pAdapter->Bmsr.bits.link_status ) + { + GlobalPmCSR.bits.pm_jagcore_tx_en = 1; + GlobalPmCSR.bits.pm_jagcore_rx_en = 1; + + } + pAdapter->CSRAddress->global.pm_csr = GlobalPmCSR; + + ctrl = pAdapter->CSRAddress->rxmac.ctrl; + + /************************************************************************** + only exercise the PM state machine when the link is up + *************************************************************************/ + if( pAdapter->Bmsr.bits.link_status ) + { + /********************************************************************** + disable MIF so power state can transition + *********************************************************************/ + ctrl.bits.mif_disable = 1; + pAdapter->CSRAddress->rxmac.ctrl = ctrl; + + while(( pAdapter->CSRAddress->global.pm_csr.bits.pm_jagcore_rx_rdy != 1 ) + && ( pAdapter->CSRAddress->global.pm_csr.bits.pm_jagcore_tx_rdy != 1 )) + { + NdisStallExecution( 10 ); + } + } + + /************************************************************************** + Stop hardware from receiving packets - Set the RU to idle + *************************************************************************/ + NICRxDmaDisable( pAdapter ); + + /************************************************************************** + Wait for outstanding Receive packets + *************************************************************************/ + while( MP_GET_RCV_REF( pAdapter ) != 0 ) + { + /********************************************************************** + Sleep for 2 Ms; + *********************************************************************/ + NdisStallExecution( 2000 ); + } + + /************************************************************************** + D3Wake only - set the MAC and Phy to 10BaseT half-duplex operation. + Archive the current settings in the pAdapter structure so we can + restore them when done. + *************************************************************************/ + if(( PowerState == NdisDeviceStateD3 ) && pAdapter->PoMgmt.WOLEnabledByCurrentState && + pAdapter->Bmsr.bits.link_status ) + { + /********************************************************************** + initialize variable for testing if we failed to go to specific link + *********************************************************************/ + pAdapter->PoMgmt.Failed10Half = FALSE; + + /********************************************************************** + set the phy properly + *********************************************************************/ + pAdapter->AiForceSpeed = 10; + pAdapter->AiForceDpx = 1; + + TPAL_SetPhy10HalfDuplex( pAdapter ); + + /********************************************************************** + get the link status here, we need to wait until the link comes back + after reconfiguring it. + *********************************************************************/ + TPAL_GetLinkStatusInfo( pAdapter ); + + if( pAdapter->PoMgmt.Failed10Half ) + { + /****************************************************************** + re-initialize variable for testing if we failed to go to + specific link speed + *****************************************************************/ + pAdapter->PoMgmt.Failed10Half = FALSE; + + /****************************************************************** + set the phy properly + *****************************************************************/ + pAdapter->AiForceSpeed = 100; + pAdapter->AiForceDpx = 1; + + TPAL_SetPhy100HalfDuplex( pAdapter ); + + /****************************************************************** + get the link status here, we need to wait until the link comes + back after reconfiguring it. + *****************************************************************/ + TPAL_GetLinkStatusInfo( pAdapter ); + } + + // SetRxDmaTimer( pAdapter ); + ConfigMACRegs2( pAdapter ); + } + + if( pAdapter->PoMgmt.WOLEnabledByCurrentState ) + { + RXMAC_WOL_CTL_CRC0_t rxmac_ctl_crc0 = pAdapter->CSRAddress->rxmac.crc0; + RXMAC_WOL_CRC12_t crc12; + RXMAC_WOL_CRC34_t crc34; + ULONG ulResult; + UINT32 SerdesPhyControl; + UINT mask; + + ulResult = NdisReadPciSlotInformation( pAdapter->AdapterHandle, + 0, // not used + ET1310_PCI_PHY_INDEX_REG, + (PVOID)&SerdesPhyControl, + sizeof( UINT32 )); + + if( pAdapter->RegistryPMWOL ) + { + SerdesPhyControl |= 0x00010000; + } + else + { + SerdesPhyControl &= 0xfffeffff; + } + + ulResult = NdisWritePciSlotInformation( + pAdapter->AdapterHandle, + 0, + ET1310_PCI_PHY_INDEX_REG, + (PVOID)&SerdesPhyControl, + sizeof( UINT32 )); + + if( pAdapter->Bmsr.bits.link_status ) + { + /********************************************************************** + need to do this for all wake devices + make sure all ignore bits are set + *********************************************************************/ + rxmac_ctl_crc0.bits.ignore_broad = 1; + rxmac_ctl_crc0.bits.ignore_multi = 1; + rxmac_ctl_crc0.bits.ignore_uni = 1; + + if( pAdapter->RegistryWOLMatch & 0x1 ) + { + rxmac_ctl_crc0.bits.ignore_mp = 0; + } + else + { + rxmac_ctl_crc0.bits.ignore_mp = 1; + } + + if( pAdapter->RegistryWOLMatch & 0x2 ) + { + rxmac_ctl_crc0.bits.ignore_pp = 0; + } + else + { + rxmac_ctl_crc0.bits.ignore_pp = 1; + } + + if( pAdapter->RegistryWOLLink & 0x1 ) + { + rxmac_ctl_crc0.bits.ignore_link_chg = 0; + } + else + { + rxmac_ctl_crc0.bits.ignore_link_chg = 1; + } + + /****************************************************************** + Clear the pattern match validity bits - i.e. make all patterns + invalid + *****************************************************************/ + rxmac_ctl_crc0.value &= ~0x1f; + + if(( pAdapter->RegistryWOLMatch & 0x2 ) && + ( pAdapter->PoMgmt.localWolAndCrc0 & 0x1f )) + { + /************************************************************** + set the validity bits based on what has been enabled in + the adapter + *************************************************************/ + rxmac_ctl_crc0.value |= (pAdapter->PoMgmt.localWolAndCrc0 & 0x1f); + + /************************************************************** + Copy the five CRCs from the adapter + *************************************************************/ + rxmac_ctl_crc0.bits.crc0 = pAdapter->PoMgmt.WOLPatternList [0]; + crc12.bits.crc1 = pAdapter->PoMgmt.WOLPatternList [1]; + crc12.bits.crc2 = pAdapter->PoMgmt.WOLPatternList [2]; + crc34.bits.crc3 = pAdapter->PoMgmt.WOLPatternList [3]; + crc34.bits.crc4 = pAdapter->PoMgmt.WOLPatternList [4]; + + for( mask = 0; mask < 5; mask++) + { + UINT i; + PUINT32 pDevicePatternMask = (PUINT32) + (&pAdapter->CSRAddress->rxmac.mask0_word0) + + (mask * MAX_WOL_MASK_SIZE / 4); + if(( pAdapter->PoMgmt.localWolAndCrc0 >> mask ) & 0x1 ) + { + UINT32 Temp[ MAX_WOL_MASK_SIZE / 4 ]; + PUCHAR pNdisPatternMask; + + pNdisPatternMask = (PUCHAR)&pAdapter->PoMgmt.WOLMaskList[ mask ][ 0 ]; + + NdisZeroMemory( Temp, sizeof( Temp )); + NdisMoveMemory( Temp, pNdisPatternMask, + pAdapter->PoMgmt.WOLMaskSize[ mask ] ); + + /************************************************************** + Write the mask to the device using the pointer calculated + above. + *************************************************************/ + for( i=0; i<( MAX_WOL_MASK_SIZE / 4 ); i++ ) + { + pDevicePatternMask[ i ] = Temp[ i ]; + } + } + } + } + + pAdapter->CSRAddress->rxmac.crc0 = rxmac_ctl_crc0; + pAdapter->CSRAddress->rxmac.crc12 = crc12; + pAdapter->CSRAddress->rxmac.crc34 = crc34; + + /****************************************************************** + we also need to read and clear the phy_interrupt register in + case of wakeup on link status change + *****************************************************************/ + MiRead( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + (UINT8)FIELD_OFFSET( MI_REGS_t, isr ), &isr.value ); + + MiRead( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + (UINT8)FIELD_OFFSET( MI_REGS_t, bmsr ), &lBmsr.value ); + + /****************************************************************** + disable mif and async + *****************************************************************/ + ctrl.bits.mif_disable = 1; + ctrl.bits.async_disable = 1; + ctrl.bits.wol_disable = 0; + pAdapter->CSRAddress->rxmac.ctrl = ctrl; + + rxmac_ctl_crc0.bits.clr_intr = 1; + pAdapter->CSRAddress->rxmac.crc0.value = rxmac_ctl_crc0.value; + + DBGPRINT( MP_SPEC, ("Going down - ctrl 0x%x, crc0_ctl 0x%x\n", + pAdapter->CSRAddress->rxmac.ctrl.value, + pAdapter->CSRAddress->rxmac.crc0.value )); + + pAdapter->Stats.InterruptStatus.value = pAdapter->CSRAddress->global.int_status.value; + + DBGPRINT( MP_SPEC, ("Going down - int stat was 0x%x, now 0x%x\n", + pAdapter->Stats.InterruptStatus.value, + pAdapter->CSRAddress->global.int_status.value )); + } + else if( pAdapter->RegistryWOLLink & 0x1 ) + { + GlobalPmCSR = pAdapter->CSRAddress->global.pm_csr; + + /************************************************************************** + Gate off JAGCore 3 clock domains + *************************************************************************/ + GlobalPmCSR.bits.pm_sysclk_gate = 0; + GlobalPmCSR.bits.pm_txclk_gate = 0; + GlobalPmCSR.bits.pm_rxclk_gate = 0; + pAdapter->CSRAddress->global.pm_csr = GlobalPmCSR; + + /************************************************************************** + Program gigE PHY in to Coma mode + *************************************************************************/ + GlobalPmCSR.bits.pm_phy_sw_coma = 1; + GlobalPmCSR.bits.pm_phy_lped_en = 1; + + pAdapter->CSRAddress->global.pm_csr = GlobalPmCSR; + } + } +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: MPSetPowerD1Wake + ****************************************************************************** + DESCRIPTION: + This routine is called when the adapter receives a SetPower to + D1 PowerState, and there is a set of wake-up patterns programmed + in the adapter. The set could consist of a single wake-up pattern. + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +VOID MPSetPowerD1Wake( PMP_ADAPTER pAdapter ) +{ + UINT32 uPmCsr; + PM_CSR_t pm_csr; + /*-----------------------------------------------------------------------*/ + + DBGPRINT( MP_TRACE, ( "----> MPSetPowerD1Wake\n" )); + + /************************************************************************** + common power down functionality; disable Tx & Rx, disable wol while + it is being provisioned, archive Tx and Rx enable, and do some of the + gating into jagcore. + *************************************************************************/ + MPSetLowPower( pAdapter, NdisDeviceStateD1 ); + + if((( pAdapter->RegistryWOLLink & 0x1) == 0 ) || ( pAdapter->Bmsr.bits.link_status )) + { + /********************************************************************** + gate off paths we do not want active and leave ones we do + *********************************************************************/ + pm_csr = pAdapter->CSRAddress->global.pm_csr; + + pm_csr.bits.pm_sysclk_gate = 0; + pm_csr.bits.pm_txclk_gate = 0; + pm_csr.bits.pm_rxclk_gate = 1; + + pAdapter->CSRAddress->global.pm_csr = pm_csr; + } + + /************************************************************************** + Set the power state to 1 (d1), and blip the PME status pin. Set the + PME Enable pin, which indicates wake state to PCI. + *************************************************************************/ + uPmCsr = 0x00008100; + NdisWritePciSlotInformation( pAdapter->AdapterHandle, + 0, // Slot no. Reserved. Ndis ignores. + ET1310_PCI_PM_CSR, + &uPmCsr, + sizeof( UINT32 )); + + DBGPRINT( MP_TRACE, ( "<---- MPSetPowerD1Wake\n" )); + return; +} +/*===========================================================================*/ + + + + + +/****************************************************************************** + ROUTINE: MPSetPowerD1NonWake + ****************************************************************************** + DESCRIPTION: + This routine is called when the adapter receives a SetPower to + D1 PowerState, and there are no wake-up patterns programmed + in the adapter. + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +VOID MPSetPowerD1NonWake( PMP_ADAPTER pAdapter ) +{ + UINT32 uPmCsr; + PM_CSR_t pm_csr; + /*-----------------------------------------------------------------------*/ + + DBGPRINT( MP_TRACE, ( "----> MPSetPowerD1NonWake\n" )); + + /************************************************************************** + common power down functionality; disable Tx & Rx, disable wol, + archive Tx and Rx enable, and do some of the gating into jagcore. + *************************************************************************/ + MPSetLowPower( pAdapter, NdisDeviceStateD1 ); + + /************************************************************************** + gate off paths we do not want active and leave ones we do + *************************************************************************/ + pm_csr = pAdapter->CSRAddress->global.pm_csr; + + pm_csr.bits.pm_sysclk_gate = 1; + pm_csr.bits.pm_txclk_gate = 1; + pm_csr.bits.pm_rxclk_gate = 1; + + pAdapter->CSRAddress->global.pm_csr = pm_csr; + + /************************************************************************** + Set the power state to 1 (d1), and blip the PME status pin. Leave the + PME Enable pin clear, which indicates non-wake state to PCI. + *************************************************************************/ + uPmCsr = 0x00008000; + NdisWritePciSlotInformation( pAdapter->AdapterHandle, + 0, // Slot no. Reserved. Ndis ignores. + ET1310_PCI_PM_CSR, + &uPmCsr, + sizeof( UINT32 )); + + DBGPRINT( MP_TRACE, ( "<---- MPSetPowerD1NonWake\n" )); + return; +} +/*===========================================================================*/ + + + + + +/****************************************************************************** + ROUTINE: MPSetPowerD3Wake + ****************************************************************************** + DESCRIPTION: + This routine is called when the adapter receives a SetPower to + D3 PowerState, and there is a set of wake-up patterns programmed + in the adapter. The set could consist of a single wake-up pattern. + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +VOID MPSetPowerD3Wake( PMP_ADAPTER pAdapter ) +{ + UINT32 uPmCsr; + PM_CSR_t pm_csr; + /*-----------------------------------------------------------------------*/ + + DBGPRINT( MP_TRACE, ( "----> MPSetPowerD3Wake\n" )); + + /************************************************************************** + common power down functionality; disable Tx & Rx, disable wol while + it is being provisioned, archive Tx and Rx enable, and do some of the + gating into jagcore. + *************************************************************************/ + MPSetLowPower( pAdapter, NdisDeviceStateD3 ); + + if((( pAdapter->RegistryWOLLink & 0x1) == 0 ) || ( pAdapter->Bmsr.bits.link_status )) + { + /********************************************************************** + gate off paths we do not want active and leave ones we do + *********************************************************************/ + pm_csr = pAdapter->CSRAddress->global.pm_csr; + + pm_csr.bits.pm_sysclk_gate = 0; + pm_csr.bits.pm_txclk_gate = 0; + pm_csr.bits.pm_rxclk_gate = 1; + + pAdapter->CSRAddress->global.pm_csr = pm_csr; + } + + /************************************************************************** + Set the power state to 3 (d3), and blip the PME status pin. Set the + PME Enable pin, which indicates wake state to PCI. + *************************************************************************/ + uPmCsr = 0x00008100; + NdisWritePciSlotInformation( pAdapter->AdapterHandle, + 0, // Slot no. Reserved. Ndis ignores. + ET1310_PCI_PM_CSR, + &uPmCsr, + sizeof( UINT32 )); + + DBGPRINT( MP_TRACE, ( "<---- MPSetPowerD3Wake\n" )); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: MPSetPowerD3NonWake + ****************************************************************************** + DESCRIPTION: + This routine is called when the adapter receives a SetPower to + D3 PowerState, and there are no wake-up patterns programmed + in the adapter. + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +VOID MPSetPowerD3NonWake( PMP_ADAPTER pAdapter ) +{ + UINT32 uPmCsr; + PM_CSR_t pm_csr; + /*-----------------------------------------------------------------------*/ + + DBGPRINT( MP_TRACE, ( "----> MPSetPowerD3NonWake\n" )); + + /************************************************************************** + common power down functionality; disable Tx & Rx, disable wol, + archive Tx and Rx enable, and do some of the gating into jagcore. + *************************************************************************/ + MPSetLowPower( pAdapter, NdisDeviceStateD3 ); + + /************************************************************************** + gate off paths we do not want active and leave ones we do + *************************************************************************/ + pm_csr = pAdapter->CSRAddress->global.pm_csr; + pm_csr.bits.pm_sysclk_gate = 1; + pm_csr.bits.pm_txclk_gate = 1; + pm_csr.bits.pm_rxclk_gate = 1; + + pAdapter->CSRAddress->global.pm_csr = pm_csr; + + /************************************************************************** + Set the power state to 3 (d3), and blip the PME status pin. Leave the + PME Enable pin clear, which indicates non-wake state to PCI. + *************************************************************************/ + uPmCsr = 0x00008000; + NdisWritePciSlotInformation( pAdapter->AdapterHandle, + 0, // Slot no. Reserved. Ndis ignores. + ET1310_PCI_PM_CSR, + &uPmCsr, + sizeof( UINT32 )); + + DBGPRINT( MP_TRACE, ( "<---- MPSetPowerD3NonWake\n" )); + + return; +} +/*===========================================================================*/ + +#endif + + +/****************************************************************************** + ROUTINE: EnablePhyComa + ****************************************************************************** + DESCRIPTION: + This routine is called when network cable is unplugged -- driver + receive an phy status change interrupt while in D0 and check that + phy_status is down. + + -- gate off JAGCore; + -- set gigE PHY in Coma mode + -- wake on phy_interrupt; Perform software reset JAGCore, + re-initialize jagcore and gigE PHY + + Add D0-ASPM-PhyLinkDown Support: + -- while in D0, when there is a phy_interrupt indicating phy link + down status, call the MPSetPhyComa routine to enter this active + state power saving mode + -- while in D0-ASPM-PhyLinkDown mode, when there is a phy_interrupt + indicating linkup status, call the MPDisablePhyComa routine to + restore JAGCore and gigE PHY + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +void EnablePhyComa( ET131X_ADAPTER *pAdapter ) +{ + unsigned long lockflags; + PM_CSR_t GlobalPmCSR = pAdapter->CSRAddress->global.pm_csr; + INT32 LoopCounter = 10; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "EnablePhyComa" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Save the GbE PHY speed and duplex modes + Need to restore this when cable is plugged back in + *************************************************************************/ + pAdapter->PoMgmt.PowerDownSpeed = pAdapter->AiForceSpeed; + pAdapter->PoMgmt.PowerDownDuplex = pAdapter->AiForceDpx; + + + /************************************************************************** + Stop sending packets. + *************************************************************************/ + spin_lock_irqsave( &pAdapter->SendHWLock, lockflags ); + + MP_SET_FLAG( pAdapter, fMP_ADAPTER_LOWER_POWER ); + + spin_unlock_irqrestore( &pAdapter->SendHWLock, lockflags ); + + + /************************************************************************** + Wait for outstanding Receive packets + *************************************************************************/ + while(( MP_GET_RCV_REF( pAdapter ) != 0 ) && ( LoopCounter-- > 0 )) + { + /********************************************************************** + Sleep for 2 Ms; + *********************************************************************/ + mdelay( 2 ); + } + + + /************************************************************************** + Gate off JAGCore 3 clock domains + *************************************************************************/ + GlobalPmCSR.bits.pm_sysclk_gate = 0; + GlobalPmCSR.bits.pm_txclk_gate = 0; + GlobalPmCSR.bits.pm_rxclk_gate = 0; + pAdapter->CSRAddress->global.pm_csr = GlobalPmCSR; + + + /************************************************************************** + Program gigE PHY in to Coma mode + *************************************************************************/ + GlobalPmCSR.bits.pm_phy_sw_coma = 1; + + pAdapter->CSRAddress->global.pm_csr = GlobalPmCSR; + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: DisablePhyComa + ****************************************************************************** + DESCRIPTION: + This routine is used to disable the Phy Coma Mode + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +void DisablePhyComa( ET131X_ADAPTER *pAdapter ) +{ + PM_CSR_t GlobalPmCSR = pAdapter->CSRAddress->global.pm_csr; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "DisablePhyComa" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************* + Disable phy_sw_coma register and re-enable JAGCore clocks + ************************************************************************/ + GlobalPmCSR.bits.pm_sysclk_gate = 1; + GlobalPmCSR.bits.pm_txclk_gate = 1; + GlobalPmCSR.bits.pm_rxclk_gate = 1; + GlobalPmCSR.bits.pm_phy_sw_coma = 0; + + pAdapter->CSRAddress->global.pm_csr = GlobalPmCSR; + + + /************************************************************************** + Restore the GbE PHY speed and duplex modes; + Reset JAGCore; re-configure and initialize JAGCore and gigE PHY + *************************************************************************/ + pAdapter->AiForceSpeed = pAdapter->PoMgmt.PowerDownSpeed; + pAdapter->AiForceDpx = pAdapter->PoMgmt.PowerDownDuplex; + + + /************************************************************************** + Re-initialize the send structures + *************************************************************************/ + et131x_init_send( pAdapter ); + + + /************************************************************************** + Reset the RFD list and re-start RU + *************************************************************************/ + et131x_reset_recv( pAdapter ); + + + /************************************************************************** + Bring the device back to the state it was during init prior to + autonegotiation being complete. This way, when we get the auto-neg + complete interrupt, we can complete init by calling ConfigMacREGS2. + *************************************************************************/ + et131x_soft_reset( pAdapter ); + + + /************************************************************************** + setup et1310 as per the documentation ?? + *************************************************************************/ + et131x_adapter_setup( pAdapter ); + + + /************************************************************************** + Allow Tx to restart + *************************************************************************/ + MP_CLEAR_FLAG( pAdapter, fMP_ADAPTER_LOWER_POWER ); + + + /************************************************************************** + Need to re-enable Rx. + *************************************************************************/ + et131x_rx_dma_enable( pAdapter ); + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + +#if 0 +/****************************************************************************** + ROUTINE: MPSetPower + ****************************************************************************** + + DESCRIPTION: + This routine is called when the adapter receives a SetPower + request. It redirects the call to an appropriate routine to + Set the New PowerState + + PARAMETERS : + pAdapter - pointer to the adapter structure + PowerState - NewPowerState + + RETURN : + NONE + + *****************************************************************************/ +VOID MPSetPower( IN PMP_ADAPTER pAdapter, + IN NDIS_DEVICE_POWER_STATE PowerState ) +{ + DBGPRINT( MP_TRACE, ( "====> MPSetPower()\n" )); + + /************************************************************************** + determine what power state we are going to and go there + *************************************************************************/ + pAdapter->PoMgmt.WOLEnabledByCurrentState = TRUE; + + if( !pAdapter->PoMgmt.WOLEnabledByNdis ) + { + pAdapter->PoMgmt.WOLEnabledByCurrentState = FALSE; + } + + if(( pAdapter->RegistryWOLMatch == 0 ) && ( pAdapter->RegistryWOLLink == 0 )) + { + pAdapter->PoMgmt.WOLEnabledByCurrentState = FALSE; + } + + if(( pAdapter->PoMgmt.localWolAndCrc0 & 0x1f ) == 0 ) + { + /********************************************************************** + There are no wake patterns programmed. + *********************************************************************/ + if( pAdapter->RegistryWOLLink == 0 ) + { + pAdapter->PoMgmt.WOLEnabledByCurrentState = FALSE; + } + } + + /************************************************************************** + If the link is pulled, then the only wake event that will wake us + up is wake on link state change. If this change is disabled (0), go + to a non-wake state. + *************************************************************************/ + if( !pAdapter->ucLinkStatus && ( pAdapter->RegistryWOLLink == 0 )) + { + pAdapter->PoMgmt.WOLEnabledByCurrentState = 0; + } + + if( PowerState == NdisDeviceStateD0 ) + { + MPSetPowerD0( pAdapter ); + } + else if( PowerState == NdisDeviceStateD1 ) + { + if( pAdapter->PoMgmt.WOLEnabledByCurrentState ) + { + MPSetPowerD1Wake( pAdapter ); + } + else + { + MPSetPowerD1NonWake( pAdapter ); + } + } + else if( PowerState == NdisDeviceStateD3 ) + { + if( pAdapter->PoMgmt.WOLEnabledByCurrentState ) + { + MPSetPowerD3Wake( pAdapter ); + } + else + { + MPSetPowerD3NonWake( pAdapter ); + } + } + + DBGPRINT( MP_TRACE, ( "<==== MPSetPower()\n" )); +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: MPFillPoMgmtCaps + ****************************************************************************** + + DESCRIPTION: + Fills in the Power Managment structure depending the capabilities of + the software driver and the card. MGS CURRENTLY NOT SUPPORTED + + + PARAMETERS : + pAdapter - pointer to the adapter structure + pPowManageCaps - power management struct as defined in the DDK, + pStatus - status to be returned by the request, + pulInfoLen - length of the pPowerManagmentCapabilites + + RETURN : + Success or failure + + NOTE: + If the driver returns NDIS_STATUS_SUCCESS in response to a query of + this OID, NDIS treats a miniport driver as power management-aware. + If the driver returns NDIS_STATUS_NOT_SUPPORTED, NDIS treats the + miniport driver as a legacy driver that is not power + management-aware. + + The Bus driver is the power policy owner here so we do not have to + perform our mapping of System States to Device states, that is + accomplished by NDIS, we need to worry more about our wake-up + capabilities + + *****************************************************************************/ +VOID MPFillPoMgmtCaps( IN PMP_ADAPTER pAdapter, + IN OUT PNDIS_PNP_CAPABILITIES pPowMgmtCaps, + IN OUT PNDIS_STATUS pStatus, + IN OUT PULONG pulInfoLen ) +{ + BOOLEAN bIsPoMgmtSupported = TRUE; + /*-----------------------------------------------------------------------*/ + + bIsPoMgmtSupported = MPIsPoMgmtSupported( pAdapter ); + + if( bIsPoMgmtSupported ) + { + /********************************************************************** + NDIS_DEVICE_WAKE_UP_ENABLE; + *********************************************************************/ + pPowMgmtCaps->Flags = 0; + + /********************************************************************** + Magic Packet wakeups + *********************************************************************/ + pPowMgmtCaps->WakeUpCapabilities.MinMagicPacketWakeUp = + NdisDeviceStateD3; + + /********************************************************************** + NdisDeviceStateD3; + *********************************************************************/ + pPowMgmtCaps->WakeUpCapabilities.MinPatternWakeUp = + NdisDeviceStateD3; + pPowMgmtCaps->WakeUpCapabilities.MinLinkChangeWakeUp = + NdisDeviceStateD3; + + *pulInfoLen = sizeof( *pPowMgmtCaps ); + *pStatus = NDIS_STATUS_SUCCESS; + } + else + { + NdisZeroMemory( pPowMgmtCaps, sizeof( *pPowMgmtCaps )); + + *pStatus = NDIS_STATUS_NOT_SUPPORTED; + *pulInfoLen = 0; + } +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: MPAddWakeUpPattern + ****************************************************************************** + + DESCRIPTION: + This routine will allocate a local memory structure, copy the pattern, + insert the pattern into a linked list and return success + + We are gauranteed that we wll get only one request at a time, so this + is implemented without locks. + + PARAMETERS : + pAdapter - pointer to the adapter structure + InformationBuffer - Wake up Pattern + InformationBufferLength - Wake Up Pattern Length + + RETURN : + Success - if successful + NDIS_STATUS_FAILURE - if memory allocation fails + + *****************************************************************************/ +NDIS_STATUS MPAddWakeUpPattern( IN PMP_ADAPTER pAdapter, + IN PVOID InfoBuf, + IN UINT InfoBufLen ) +{ + NDIS_STATUS Status; + PNDIS_PM_PACKET_PATTERN pPmPattern = NULL; + UINT Slot = 0, FreeSlot = 0xff; + PUCHAR pNdisPatternMask; + PUINT32 pDevicePatternMask; + UINT16 DevMagicNumber; + UINT i; + + PUCHAR TempBuf; + ULONG offset; + + /*-----------------------------------------------------------------------*/ + + pPmPattern = (PNDIS_PM_PACKET_PATTERN)InfoBuf; + + /************************************************************************** + Check that the wake-up pattern is not too large for us. Also, not + sure how to deal with a pattern whose mask is smaller than the pattern + *************************************************************************/ + if(( pPmPattern->MaskSize < (( pPmPattern->PatternSize / 8) + 1)) || + ( pPmPattern->PatternSize > MAX_WOL_PACKET_SIZE)) + { + return( NDIS_STATUS_RESOURCES ); + } + + NdisAcquireSpinLock( &pAdapter->Lock ); + + /************************************************************************** + Check to see if there is an empty slot on the device to store this + pattern. Store the slot number for later use. + *************************************************************************/ + while ((FreeSlot == 0xff) && (Slot < NUM_WOL_PATTERNS)) + { + if (!((pAdapter->PoMgmt.localWolAndCrc0 >> Slot) & 0x1)) + { + FreeSlot = Slot; + } + else + { + Slot++; + } + } + + if( FreeSlot == 0xff ) + { + /********************************************************************** + Failed to find a free slot. + *********************************************************************/ + NdisReleaseSpinLock( &pAdapter->Lock ); + return( NDIS_STATUS_RESOURCES ); + } + + pNdisPatternMask = (PUCHAR)InfoBuf + sizeof( NDIS_PM_PACKET_PATTERN ); + + /************************************************************************** + Make a copy of what Ndis sent us + *************************************************************************/ + for( i=0; iMaskSize; i++ ) + { + pAdapter->PoMgmt.WOLMaskList[ FreeSlot ][ i ] = pNdisPatternMask[ i ]; + } + + /************************************************************************** + Calculate the CRC that will be used by the device to identify this + packet + *************************************************************************/ + offset = 0; + TempBuf = (PUCHAR)( InfoBuf ) + pPmPattern->PatternOffset; + + DevMagicNumber = MPCalculateCCITCRC16( TempBuf, + (PUCHAR )( InfoBuf ) + + sizeof( NDIS_PM_PACKET_PATTERN ), + pPmPattern->MaskSize ); + + DBGPRINT( MP_SPEC, ( "DevMagicNumber 0x%08x\n", DevMagicNumber )); + DBGPRINT( MP_SPEC, ( "Pattern Size : 0x%08x, MaskSize : 0x%08x\n", + pPmPattern->PatternSize, pPmPattern->MaskSize )); + + pAdapter->PoMgmt.localWolAndCrc0 |= ( 1 << FreeSlot ); + + /************************************************************************** + Now handle storing the pattern in our adapter. Only store what makes + the pattern unique to our device. (the CRC, the mask and the mask + size. The pattern is irrelevant, since it is not stored in the + device). The mask is stored above. + *************************************************************************/ + pAdapter->PoMgmt.WOLPatternList[ FreeSlot ] = DevMagicNumber; + pAdapter->PoMgmt.WOLMaskSize[ FreeSlot ] = pPmPattern->MaskSize; + + NdisReleaseSpinLock( &pAdapter->Lock ); + return( NDIS_STATUS_SUCCESS ); +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: MPRemoveWakeUpPattern + ****************************************************************************** + + DESCRIPTION: + This routine will scan the array of wake up patterns and attempt to + match the wake up pattern. If it finds a copy , it will remove that + WakeUpPattern + + PARAMETERS: + pAdapter - pointer to the Adapter structure + InformationBuffer - Wake up Pattern + InformationBufferLength - Wake Up Pattern Length + + RETURN: + Success - if successful. + NDIS_STATUS_FAILURE - if memory allocation fails. + + *****************************************************************************/ +NDIS_STATUS MPRemoveWakeUpPattern( IN PMP_ADAPTER pAdapter, + IN PVOID InformationBuffer, + IN UINT InformationBufferLength ) +{ + + PNDIS_PM_PACKET_PATTERN pPmPattern = NULL; + UINT Slot = 0, FoundSlot = 0xff; + UINT16 DevMagicNumber; + /*-----------------------------------------------------------------------*/ + + pPmPattern = (PNDIS_PM_PACKET_PATTERN)InformationBuffer; + + /************************************************************************** + Check that the wake-up pattern is not too large for us. Also, not + sure how to deal with a pattern whose mask is not the same size + as the pattern. + *************************************************************************/ + if(( pPmPattern->MaskSize < (( pPmPattern->PatternSize / 8) + 1)) || + ( pPmPattern->PatternSize > MAX_WOL_PACKET_SIZE)) + { + return NDIS_STATUS_FAILURE; + } + + /************************************************************************** + Calculate the CRC that will be used by the device to identify this + packet + *************************************************************************/ + DevMagicNumber = MPCalculateCCITCRC16( (PUCHAR )( InformationBuffer ) + + pPmPattern->PatternOffset , + (PUCHAR )( InformationBuffer ) + + sizeof( NDIS_PM_PACKET_PATTERN ), + pPmPattern->MaskSize ); + + NdisAcquireSpinLock( &pAdapter->Lock ); + + while ((FoundSlot == 0xff) && (Slot < NUM_WOL_PATTERNS)) + { + if(( pAdapter->PoMgmt.WOLPatternList[ Slot ] == DevMagicNumber ) && + ( pAdapter->PoMgmt.WOLMaskSize[ Slot ] == pPmPattern->MaskSize ) && + (( pAdapter->PoMgmt.localWolAndCrc0 >> Slot ) & 0x1) ) + { + UINT i; + PUCHAR pIncomingMask = (PUCHAR)( InformationBuffer ) + + sizeof( NDIS_PM_PACKET_PATTERN ); + + for( i=0; iMaskSize; i++ ) + { + if( pAdapter->PoMgmt.WOLMaskList[ Slot ][ i ] != + pIncomingMask[ i ] ) + { + break; + } + } + if( i >= pPmPattern->MaskSize ) + { + FoundSlot = Slot; + } + } + + Slot++; + } + + if( FoundSlot == 0xff ) + { + /********************************************************************** + Failed to find this packet in the list coinciding with a valid + entry in the device. + *********************************************************************/ + NdisReleaseSpinLock( &pAdapter->Lock ); + return( NDIS_STATUS_FAILURE ); + } + + pAdapter->PoMgmt.localWolAndCrc0 &= ~( 1 << FoundSlot ); + + NdisReleaseSpinLock( &pAdapter->Lock ); + + return( NDIS_STATUS_SUCCESS ); +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: MPRemoveAllWakeUpPatterns + ****************************************************************************** + + DESCRIPTION: + This routine disables all wake-up on the device. Probably not + required. + + PARAMETERS: + pAdapter - pointer to the adapter structure + + RETURN: + Nothing + + *****************************************************************************/ +VOID MPRemoveAllWakeUpPatterns( IN PMP_ADAPTER pAdapter ) +{ + RXMAC_WOL_CTL_CRC0_t crc0; + /*-----------------------------------------------------------------------*/ + + if( pAdapter ) + { + NdisAcquireSpinLock( &pAdapter->Lock ); + + pAdapter->PoMgmt.localWolAndCrc0 = 0; + + NdisReleaseSpinLock( &pAdapter->Lock ); + } +} +/*===========================================================================*/ + +#endif --- linux-2.6.27.orig/ubuntu/et131x/ET1310_eeprom.c +++ linux-2.6.27/ubuntu/et131x/ET1310_eeprom.c @@ -0,0 +1,710 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * ET1310_eeprom.c - Code used to access the device's EEPROM + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2006/01/18 22:18:33 $ + $Revision: 1.6 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +/****************************************************************************** + Includes + *****************************************************************************/ +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include +#include +#include +#include +#include + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ET1310_phy.h" +#include "ET1310_pm.h" +#include "ET1310_jagcore.h" +#include "ET1310_eeprom.h" + +#include "et131x_supp.h" +#include "et131x_adapter.h" +#include "et131x_initpci.h" +#include "et131x_isr.h" + +#include "ET1310_tx.h" + + + + +/****************************************************************************** + EEPROM Defines + *****************************************************************************/ +/* LBCIF Register Groups (addressed via 32-bit offsets) */ +#define LBCIF_DWORD0_GROUP_OFFSET 0xAC +#define LBCIF_DWORD1_GROUP_OFFSET 0xB0 + +/* LBCIF Registers (addressed via 8-bit offsets) */ +#define LBCIF_ADDRESS_REGISTER_OFFSET 0xAC +#define LBCIF_DATA_REGISTER_OFFSET 0xB0 +#define LBCIF_CONTROL_REGISTER_OFFSET 0xB1 +#define LBCIF_STATUS_REGISTER_OFFSET 0xB2 + +/* LBCIF Control Register Bits */ +#define LBCIF_CONTROL_SEQUENTIAL_READ 0x01 +#define LBCIF_CONTROL_PAGE_WRITE 0x02 +#define LBCIF_CONTROL_UNUSED1 0x04 +#define LBCIF_CONTROL_EEPROM_RELOAD 0x08 +#define LBCIF_CONTROL_UNUSED2 0x10 +#define LBCIF_CONTROL_TWO_BYTE_ADDR 0x20 +#define LBCIF_CONTROL_I2C_WRITE 0x40 +#define LBCIF_CONTROL_LBCIF_ENABLE 0x80 + +/* LBCIF Status Register Bits */ +#define LBCIF_STATUS_PHY_QUEUE_AVAIL 0x01 +#define LBCIF_STATUS_I2C_IDLE 0x02 +#define LBCIF_STATUS_ACK_ERROR 0x04 +#define LBCIF_STATUS_GENERAL_ERROR 0x08 +#define LBCIF_STATUS_UNUSED 0x30 +#define LBCIF_STATUS_CHECKSUM_ERROR 0x40 +#define LBCIF_STATUS_EEPROM_PRESENT 0x80 + +/* Miscellaneous Constraints */ +#define MAX_NUM_REGISTER_POLLS 1000 +#define MAX_NUM_WRITE_RETRIES 2 + + + + +/****************************************************************************** + Define macros that allow individual register values to be extracted from a + DWORD1 register grouping + *****************************************************************************/ +#define EXTRACT_DATA_REGISTER(x) (UCHAR)(x & 0xFF) +#define EXTRACT_STATUS_REGISTER(x) (UCHAR)((x >> 16) & 0xFF) +#define EXTRACT_CONTROL_REG(x) (UCHAR)((x >> 8) & 0xFF) + + + + +static INT32 LbcifWriteByte( ET131X_ADAPTER *pAdapter, UINT32 unOffset, UCHAR bByte ) +{ + return EEPROM_access( pAdapter, WRITE, unOffset, 8, &bByte ); +} + + +static INT32 LbcifReadDword( ET131X_ADAPTER *pAdapter, UINT32 unOffset, PUINT32 punData ) +{ + return EEPROM_access( pAdapter, READ, unOffset, 32, punData ); +} + + +static INT32 LbcifWriteDword( ET131X_ADAPTER *pAdapter,UINT32 unOffset, UINT32 unData ) +{ + return EEPROM_access( pAdapter, WRITE, unOffset, 32, &unData ); +} + + + + +/****************************************************************************** + ROUTINE : EepromWriteByte + ****************************************************************************** + + DESCRIPTION : Write a byte to the ET1310's EEPROM + + PARAMETERS : pAdapter - pointer to our private adapter structure + unAddress - the address to write + bData - the value to write + unEepronId - the ID of the EEPROM + unAddressingMode - how the EEPROM is to be accessed + + RETURNS : SUCCESS or FAILURE + + REUSE INFORMATION : + + *****************************************************************************/ +INT32 EepromWriteByte( ET131X_ADAPTER *pAdapter, UINT32 unAddress, UCHAR bData, + UINT32 unEepromId, UINT32 unAddressingMode ) +{ + INT32 nIndex; + INT32 nRetries; + INT32 nError = FALSE; + INT32 nI2CWriteActive = 0; + INT32 nWriteSuccessful = 0; + UCHAR bControl; + UCHAR bStatus = 0; + UINT32 unDword1 = 0; + + UINT32 unData = 0; + /*-----------------------------------------------------------------------*/ + + + /************************************************************************** + The following excerpt is from "Serial EEPROM HW Design Specification" + Version 0.92 (9/20/2004): + + Single Byte Writes + + For an EEPROM, an I2C single byte write is defined as a START + condition followed by the device address, EEPROM address, one byte + of data and a STOP condition. The STOP condition will trigger the + EEPROM's internally timed write cycle to the nonvolatile memory. + All inputs are disabled during this write cycle and the EEPROM will + not respond to any access until the internal write is complete. + The steps to execute a single byte write are as follows: + + 1. Check LBCIF Status Register for bits 6 & 3:2 all equal to 0 and + bits 7,1:0 both equal to 1, at least once after reset. Subsequent + operations need only to check that bits 1:0 are equal to 1 prior + to starting a single byte write. + + 2. Write to the LBCIF Control Register: bit 7=1, bit 6=1, bit 3=0, + and bits 1:0 both =0. Bit 5 should be set according to the type + of EEPROM being accessed (1=two byte addressing, 0=one byte + addressing). + + 3. Write the address to the LBCIF Address Register. + + 4. Write the data to the LBCIF Data Register (the I2C write will + begin). + + 5. Monitor bit 1:0 of the LBCIF Status Register. When bits 1:0 are + both equal to 1, the I2C write has completed and the internal + write cycle of the EEPROM is about to start. (bits 1:0 = 01 is a + legal state while waiting from both equal to 1, but bits 1:0 = 10 + is invalid and implies that something is broken). + + 6. Check bit 3 of the LBCIF Status Register. If equal to 1, an + error has occurred. + + 7. Check bit 2 of the LBCIF Status Register. If equal to 1 an ACK + error has occurred on the address phase of the write. This could + be due to an actual hardware failure or the EEPROM may still be in + its internal write cycle from a previous write. This write oper- + ation was ignored and must be repeated later. + + 8. Set bit 6 of the LBCIF Control Register = 0. If another write is + required, go to step 1. + *************************************************************************/ + + + /************************************************************************** + Step 1: + *************************************************************************/ + for( nIndex = 0; nIndex < MAX_NUM_REGISTER_POLLS; nIndex++) + { + /********************************************************************** + Read registers grouped in DWORD1 + *********************************************************************/ + if( LbcifReadDword( pAdapter, LBCIF_DWORD1_GROUP_OFFSET, &unDword1 )) + { + nError = 1; + break; + } + + bStatus = EXTRACT_STATUS_REGISTER( unDword1 ); + + if( bStatus & LBCIF_STATUS_PHY_QUEUE_AVAIL && + bStatus & LBCIF_STATUS_I2C_IDLE ) + { + /****************************************************************** + bits 1:0 are equal to 1 + *****************************************************************/ + break; + } + } + + if( nError || ( nIndex >= MAX_NUM_REGISTER_POLLS )) + { + return( FAILURE ); + } + + + /************************************************************************** + Step 2: + *************************************************************************/ + bControl = 0; + bControl |= LBCIF_CONTROL_LBCIF_ENABLE | LBCIF_CONTROL_I2C_WRITE; + + if( unAddressingMode == DUAL_BYTE ) + { + bControl |= LBCIF_CONTROL_TWO_BYTE_ADDR; + } + + if( LbcifWriteByte( pAdapter, LBCIF_CONTROL_REGISTER_OFFSET, bControl )) + { + return( FAILURE ); + } + + nI2CWriteActive = 1; + + + /************************************************************************** + Prepare EEPROM address for Step 3 + *************************************************************************/ + unAddress |= ( unAddressingMode == DUAL_BYTE ) ? + ( unEepromId << 16 ) : ( unEepromId << 8 ); + + for( nRetries = 0; nRetries < MAX_NUM_WRITE_RETRIES; nRetries++ ) + { + /********************************************************************** + Step 3: + *********************************************************************/ + if( LbcifWriteDword( pAdapter, LBCIF_ADDRESS_REGISTER_OFFSET, unAddress )) + { + break; + } + + /********************************************************************** + Step 4: + *********************************************************************/ + if( LbcifWriteByte( pAdapter, LBCIF_DATA_REGISTER_OFFSET, bData )) + { + break; + } + + /********************************************************************** + Step 5: + *********************************************************************/ + for( nIndex = 0; nIndex < MAX_NUM_REGISTER_POLLS; nIndex++ ) + { + /****************************************************************** + Read registers grouped in DWORD1 + *****************************************************************/ + if( LbcifReadDword( pAdapter, LBCIF_DWORD1_GROUP_OFFSET, + &unDword1 )) + { + nError = 1; + break; + } + + bStatus = EXTRACT_STATUS_REGISTER( unDword1 ); + + if( bStatus & LBCIF_STATUS_PHY_QUEUE_AVAIL && + bStatus & LBCIF_STATUS_I2C_IDLE ) + { + /************************************************************** + I2C write complete + *************************************************************/ + break; + } + } + + if( nError || ( nIndex >= MAX_NUM_REGISTER_POLLS )) + { + break; + } + + + /********************************************************************** + Step 6: Don't break here if we are revision 1, this is so we do a + blind write for load bug. + *********************************************************************/ + if( bStatus & LBCIF_STATUS_GENERAL_ERROR && pAdapter->RevisionID == 0 ) + { + break; + } + + + /********************************************************************** + Step 7: + *********************************************************************/ + if( bStatus & LBCIF_STATUS_ACK_ERROR ) + { + /****************************************************************** + This could be due to an actual hardware failure or the EEPROM + may still be in its internal write cycle from a previous write. + This write operation was ignored and must be repeated later. + *****************************************************************/ + udelay( 10 ); + continue; + } + + nWriteSuccessful = 1; + break; + } + + + /************************************************************************** + Step 8: + *************************************************************************/ + udelay( 10 ); + nIndex = 0; + while( nI2CWriteActive ) + { + bControl &= ~LBCIF_CONTROL_I2C_WRITE; + + if( LbcifWriteByte( pAdapter, LBCIF_CONTROL_REGISTER_OFFSET, bControl )) + { + nWriteSuccessful = 0; + } + + /* Do read until internal ACK_ERROR goes away meaning write completed */ + for( ;; ) + { + /* unAddress */ + LbcifWriteDword( pAdapter, LBCIF_ADDRESS_REGISTER_OFFSET, unAddress ); + + for( ;; ) + { + LbcifReadDword( pAdapter, LBCIF_DATA_REGISTER_OFFSET, &unData ); + + if( unData & 0x00010000 ) + { + break; + } + } + + if(( unData & 0x00040000 ) == 0x0 ) + { + break; + } + } + + bControl = EXTRACT_CONTROL_REG( unData ); + + if( bControl != 0xC0 || nIndex == 10000 ) + { + break; + } + + nIndex++; + } + + return(( nWriteSuccessful ) ? SUCCESS : FAILURE ); +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : EepromReadByte + ****************************************************************************** + + DESCRIPTION : Read a byte from the ET1310's EEPROM + + PARAMETERS : pAdapter - pointer to our private adapter structure + unAddress - the address from which to read + pbData - a pointer to a byte in which to store the + value of the read + unEepronId - the ID of the EEPROM + unAddressingMode - how the EEPROM is to be accessed + + RETURNS : SUCCESS or FAILURE + + REUSE INFORMATION : + + *****************************************************************************/ +INT32 EepromReadByte( ET131X_ADAPTER *pAdapter, UINT32 unAddress, PUCHAR pbData, + UINT32 unEepromId, UINT32 unAddressingMode ) +{ + INT32 nIndex; + INT32 nError = 0; + INT32 nReadSuccessful = 0; + UCHAR bControl; + UCHAR bStatus = 0; + UINT32 unDword1 = 0; + /*-----------------------------------------------------------------------*/ + + + /************************************************************************** + The following excerpt is from "Serial EEPROM HW Design Specification" + Version 0.92 (9/20/2004): + + Single Byte Reads + + A single byte read is similar to the single byte write, with the + exception of the data flow: + + 1. Check LBCIF Status Register for bits 6 & 3:2 all equal to 0 and + bits 7,1:0 both equal to 1, at least once after reset. Subsequent + operations need only to check that bits 1:0 are equal to 1 prior + to starting a single byte read. + + 2. Write to the LBCIF Control Register: bit 7=1, bit 6=0, bit 3=0, + and bits 1:0 both =0. Bit 5 should be set according to the type + of EEPROM being accessed (1=two byte addressing, 0=one byte addr- + essing). + + 3. Write the address to the LBCIF Address Register (I2C read will + begin). + + 4. Monitor bit 0 of the LBCIF Status Register. When =1, I2C read is + complete. (if bit 1 =1 and bit 0 stays =0, a hardware failure has + occurred). + + 5. Check bit 2 of the LBCIF Status Register. If =1, then an error has + occurred. The data that has been returned from the PHY may be + invalid. + + 6. Regardless of error status, read data byte from LBCIF Data Register. + If another byte is required, go to step 1. + *************************************************************************/ + + + /************************************************************************** + Step 1: + *************************************************************************/ + for( nIndex = 0; nIndex < MAX_NUM_REGISTER_POLLS; nIndex++) + { + /********************************************************************** + Read registers grouped in DWORD1 + *********************************************************************/ + if( LbcifReadDword( pAdapter, LBCIF_DWORD1_GROUP_OFFSET, &unDword1 )) + { + nError = 1; + break; + } + + bStatus = EXTRACT_STATUS_REGISTER( unDword1 ); + + if( bStatus & LBCIF_STATUS_PHY_QUEUE_AVAIL && + bStatus & LBCIF_STATUS_I2C_IDLE ) + { + /****************************************************************** + bits 1:0 are equal to 1 + *****************************************************************/ + break; + } + } + + if( nError || ( nIndex >= MAX_NUM_REGISTER_POLLS )) + { + return( FAILURE ); + } + + + /************************************************************************** + Step 2: + *************************************************************************/ + bControl = 0; + bControl |= LBCIF_CONTROL_LBCIF_ENABLE; + + if( unAddressingMode == DUAL_BYTE ) + { + bControl |= LBCIF_CONTROL_TWO_BYTE_ADDR; + } + + if( LbcifWriteByte( pAdapter, LBCIF_CONTROL_REGISTER_OFFSET, bControl )) + { + return( FAILURE ); + } + + + /************************************************************************** + Step 3: + *************************************************************************/ + unAddress |= ( unAddressingMode == DUAL_BYTE ) ? + ( unEepromId << 16 ) : ( unEepromId << 8 ); + + if( LbcifWriteDword( pAdapter, LBCIF_ADDRESS_REGISTER_OFFSET, unAddress )) + { + return( FAILURE ); + } + + + /************************************************************************** + Step 4: + *************************************************************************/ + for( nIndex = 0; nIndex < MAX_NUM_REGISTER_POLLS; nIndex++ ) + { + /********************************************************************** + Read registers grouped in DWORD1 + *********************************************************************/ + if( LbcifReadDword( pAdapter, LBCIF_DWORD1_GROUP_OFFSET, &unDword1 )) + { + nError = 1; + break; + } + + bStatus = EXTRACT_STATUS_REGISTER( unDword1 ); + + if( bStatus & LBCIF_STATUS_PHY_QUEUE_AVAIL + && bStatus & LBCIF_STATUS_I2C_IDLE ) + { + /****************************************************************** + I2C read complete + *****************************************************************/ + break; + } + } + + if( nError || ( nIndex >= MAX_NUM_REGISTER_POLLS )) + { + return( FAILURE ); + } + + + /************************************************************************** + Step 5: + *************************************************************************/ + nReadSuccessful = ( bStatus & LBCIF_STATUS_ACK_ERROR ) ? 0 : 1; + + + /************************************************************************** + Step 6: + *************************************************************************/ + *pbData = EXTRACT_DATA_REGISTER( unDword1 ); + + return( nReadSuccessful ) ? SUCCESS : FAILURE; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : EEPROM_access + ****************************************************************************** + + DESCRIPTION : + Performs a read or write of a given data width at a specified offset + from EEPROM + + PARAMETERS : + pAdapter - [in] pointer to the adapter structure + bAccessFlag - [in] A flag indicating what type of transaction + READ/WRITE + unOffset - [in] Specifies the offset within the EEPROM + bWidth - [in] Defines the width (in bits) of the requested + access. Valid values are 8 or 32. + pData - [in/out] Pointer to a buffer that contains the data + requested by or resulting from the transaction + specified by 'bAccessFlag'. + Method in which this parameter is processed + (de-referenced) is determined by the value of + 'bWidth', i.e. 8-bit or 32-bit read/write + accesses. + + RETURNS : + result from PCI Config space access + + REUSE INFORMATION : + YES + + *****************************************************************************/ +UINT32 EEPROM_access( ET131X_ADAPTER *pAdapter, UCHAR bAccessFlag, + UINT32 unOffset, UCHAR bWidth, void *pData ) +{ + UINT32 ulResult; + /*-----------------------------------------------------------------------*/ + + if( bAccessFlag == WRITE ) + { + /********************************************************************** + we are doing a write + *********************************************************************/ + ulResult = pci_slot_information_write( pAdapter->pdev, + unOffset, + pData, + ( bWidth / 8 )); + } + else + { + /********************************************************************** + do the read read + *********************************************************************/ + ulResult = pci_slot_information_read( pAdapter->pdev, + unOffset, + pData, + ( bWidth / 8 )); + } + if( ulResult != 0 ) + { + return( 0 ); + } + else + { + return( ulResult ); + } +} +/*===========================================================================*/ --- linux-2.6.27.orig/ubuntu/et131x/ET1310_jagcore.h +++ linux-2.6.27/ubuntu/et131x/ET1310_jagcore.h @@ -0,0 +1,180 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * ET1310_jagcore.h - Defines, structs, enums, prototypes, etc. pertaining to + * the JAGCore + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/10/28 18:43:44 $ + $Revision: 1.7 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +#ifndef __ET1310_JAGCORE_H__ +#define __ET1310_JAGCORE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + + + +/****************************************************************************** + INCLUDES + *****************************************************************************/ +#include "ET1310_common.h" + + + + +/****************************************************************************** + CONSTANTS FOR JAGCORE + *****************************************************************************/ +#define INTERNAL_MEM_SIZE 0x400 //1024 of internal memory +#define INTERNAL_MEM_RX_OFFSET 0x1FF //50% Tx, 50% Rx + +#define REGS_MAX_ARRAY 4096 + + + + +/****************************************************************************** + For interrupts, normal running is: + rxdma_xfr_done, phy_interrupt, mac_stat_interrupt, + watchdog_interrupt & txdma_xfer_done + + In both cases, when flow control is enabled for either Tx or bi-direction, + we additional enable rx_fbr0_low and rx_fbr1_low, so we know when the + buffer rings are running low. + *****************************************************************************/ +#define INT_MASK_DISABLE 0xffffffff + +// NOTE: Masking out MAC_STAT Interrupt for now... +//#define INT_MASK_ENABLE 0xfff6bf17 +//#define INT_MASK_ENABLE_NO_FLOW 0xfff6bfd7 +#define INT_MASK_ENABLE 0xfffebf17 +#define INT_MASK_ENABLE_NO_FLOW 0xfffebfd7 + + + + +/****************************************************************************** + DATA STRUCTURES FOR DIRECT REGISTER ACCESS + *****************************************************************************/ +typedef struct +{ + u8 bReadWrite; + u32 nRegCount; + u32 nData [REGS_MAX_ARRAY]; + u32 nOffsets [REGS_MAX_ARRAY]; +} JAGCORE_ACCESS_REGS, *PJAGCORE_ACCESS_REGS; + + +typedef struct +{ + u8 bReadWrite; + u32 nDataWidth; + u32 nRegCount; + u32 nOffsets [REGS_MAX_ARRAY]; + u32 nData [REGS_MAX_ARRAY]; +} PCI_CFG_SPACE_REGS, *PPCI_CFG_SPACE_REGS; + + + + +/****************************************************************************** + Forward declaration of the private adapter structure + *****************************************************************************/ +struct et131x_adapter; + + + + +/****************************************************************************** + PROTOTYPES + *****************************************************************************/ +void ConfigGlobalRegs(struct et131x_adapter *pAdapter ); + +void ConfigMMCRegs( struct et131x_adapter *pAdapter ); + +void et131x_enable_interrupts( struct et131x_adapter *adapter ); + +void et131x_disable_interrupts( struct et131x_adapter *adapter ); + +void * et131x_get_regs( struct et131x_adapter *pAdapter, void *InfoBuf, + PUINT32 ulBytesAvailable, PUINT32 ulInfoLen ); + +void et131x_set_regs( struct et131x_adapter *pAdapter, void *InfoBuf ); + + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __ET1310_JAGCORE_H__ */ --- linux-2.6.27.orig/ubuntu/et131x/ET1310_address_map.h +++ linux-2.6.27/ubuntu/et131x/ET1310_address_map.h @@ -0,0 +1,3216 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * ET1310_address_map.h - Contains the register mapping for the ET1310 + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/10/28 18:43:43 $ + $Revision: 1.8 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +#ifndef _ET1310_ADDRESS_MAP_H_ +#define _ET1310_ADDRESS_MAP_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************** + some typedefs for compiler + *****************************************************************************/ +typedef s8 INT8, *PINT8; +typedef s16 INT16, *PINT16; +typedef s32 INT32, *PINT32; +typedef s64 INT64, *PINT64; + +typedef u8 UINT8, *PUINT8; +typedef u16 UINT16, *PUINT16; +typedef u32 UINT32, *PUINT32; +typedef u64 UINT64, *PUINT64; + +typedef u8 UCHAR, *PUCHAR; + + + + +/*===========================================================================*/ +/*===========================================================================*/ +/*=== START OF GLOBAL REGISTER ADDRESS MAP ===*/ +/*===========================================================================*/ +/*===========================================================================*/ +/****************************************************************************** + structure for tx queue start address reg in global address map + located at address 0x0000 + *****************************************************************************/ +typedef union _TXQ_START_ADDR_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:22; //bits 10-31 + UINT32 txq_start:10; //bits 0-9 + #else + UINT32 txq_start:10; //bits 0-9 + UINT32 unused:22; //bits 10-31 + #endif + } bits; +} +TXQ_START_ADDR_t, *PTXQ_START_ADDR_t; + + +/****************************************************************************** + structure for tx queue end address reg in global address map + located at address 0x0004 + *****************************************************************************/ +typedef union _TXQ_END_ADDR_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:22; //bits 10-31 + UINT32 txq_end:10; //bits 0-9 + #else + UINT32 txq_end:10; //bits 0-9 + UINT32 unused:22; //bits 10-31 + #endif + } bits; +} +TXQ_END_ADDR_t, *PTXQ_END_ADDR_t; + + +/****************************************************************************** + structure for rx queue start address reg in global address map + located at address 0x0008 + *****************************************************************************/ +typedef union _RXQ_START_ADDR_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:22; //bits 10-31 + UINT32 rxq_start_addr:10; //bits 0-9 + #else + UINT32 rxq_start_addr:10; //bits 0-9 + UINT32 unused:22; //bits 10-31 + #endif + } bits; +} +RXQ_START_ADDR_t, *PRXQ_START_ADDR_t; + + +/****************************************************************************** + structure for rx queue end address reg in global address map + located at address 0x000C + *****************************************************************************/ +typedef union _RXQ_END_ADDR_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:22; //bits 10-31 + UINT32 rxq_end_addr:10; //bits 0-9 + #else + UINT32 rxq_end_addr:10; //bits 0-9 + UINT32 unused:22; //bits 10-31 + #endif + } bits; +} +RXQ_END_ADDR_t, *PRXQ_END_ADDR_t; + + +/****************************************************************************** + structure for power management control status reg in global address map + located at address 0x0010 + *****************************************************************************/ +typedef union _PM_CSR_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:22; //bits 10-31 + UINT32 pm_jagcore_rx_rdy:1; //bit 9 + UINT32 pm_jagcore_tx_rdy:1; //bit 8 + UINT32 pm_phy_lped_en:1; //bit 7 + UINT32 pm_phy_sw_coma:1; //bit 6 + UINT32 pm_rxclk_gate:1; //bit 5 + UINT32 pm_txclk_gate:1; //bit 4 + UINT32 pm_sysclk_gate:1; //bit 3 + UINT32 pm_jagcore_rx_en:1; //bit 2 + UINT32 pm_jagcore_tx_en:1; //bit 1 + UINT32 pm_gigephy_en:1; //bit 0 + #else + UINT32 pm_gigephy_en:1; //bit 0 + UINT32 pm_jagcore_tx_en:1; //bit 1 + UINT32 pm_jagcore_rx_en:1; //bit 2 + UINT32 pm_sysclk_gate:1; //bit 3 + UINT32 pm_txclk_gate:1; //bit 4 + UINT32 pm_rxclk_gate:1; //bit 5 + UINT32 pm_phy_sw_coma:1; //bit 6 + UINT32 pm_phy_lped_en:1; //bit 7 + UINT32 pm_jagcore_tx_rdy:1; //bit 8 + UINT32 pm_jagcore_rx_rdy:1; //bit 9 + UINT32 unused:22; //bits 10-31 + #endif + } bits; +} +PM_CSR_t, *PPM_CSR_t; + + +/****************************************************************************** + structure for interrupt status reg in global address map + located at address 0x0018 + *****************************************************************************/ +typedef union _INT_STATUS_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused5:11; //bits 21-31 + UINT32 slv_timeout:1; //bit 20 + UINT32 mac_stat_interrupt:1; //bit 19 + UINT32 rxmac_interrupt:1; //bit 18 + UINT32 txmac_interrupt:1; //bit 17 + UINT32 phy_interrupt:1; //bit 16 + UINT32 wake_on_lan:1; //bit 15 + UINT32 watchdog_interrupt:1; //bit 14 + UINT32 unused4:4; //bits 10-13 + UINT32 rxdma_err:1; //bit 9 + UINT32 rxdma_pkt_stat_ring_low:1; //bit 8 + UINT32 rxdma_fb_ring1_low:1; //bit 7 + UINT32 rxdma_fb_ring0_low:1; //bit 6 + UINT32 rxdma_xfr_done:1; //bit 5 + UINT32 txdma_err:1; //bit 4 + UINT32 txdma_isr:1; //bit 3 + UINT32 unused3:1; //bit 2 + UINT32 unused2:1; //bit 1 + UINT32 unused1:1; //bit 0 + #else + UINT32 unused1:1; //bit 0 + UINT32 unused2:1; //bit 1 + UINT32 unused3:1; //bit 2 + UINT32 txdma_isr:1; //bit 3 + UINT32 txdma_err:1; //bit 4 + UINT32 rxdma_xfr_done:1; //bit 5 + UINT32 rxdma_fb_ring0_low:1; //bit 6 + UINT32 rxdma_fb_ring1_low:1; //bit 7 + UINT32 rxdma_pkt_stat_ring_low:1; //bit 8 + UINT32 rxdma_err:1; //bit 9 + UINT32 unused4:4; //bits 10-13 + UINT32 watchdog_interrupt:1; //bit 14 + UINT32 wake_on_lan:1; //bit 15 + UINT32 phy_interrupt:1; //bit 16 + UINT32 txmac_interrupt:1; //bit 17 + UINT32 rxmac_interrupt:1; //bit 18 + UINT32 mac_stat_interrupt:1; //bit 19 + UINT32 slv_timeout:1; //bit 20 + UINT32 unused5:11; //bits 21-31 + #endif + } bits; +} +INT_STATUS_t, *PINT_STATUS_t; + + +/****************************************************************************** + structure for interrupt mask reg in global address map + located at address 0x001C + *****************************************************************************/ +typedef union _INT_MASK_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused5:11; //bits 21-31 + UINT32 slv_timeout:1; //bit 20 + UINT32 mac_stat_interrupt:1; //bit 19 + UINT32 rxmac_interrupt:1; //bit 18 + UINT32 txmac_interrupt:1; //bit 17 + UINT32 phy_interrupt:1; //bit 16 + UINT32 wake_on_lan:1; //bit 15 + UINT32 unused4:5; //bits 10-14 + UINT32 rxdma_err:1; //bit 9 + UINT32 rxdma_pkt_stat_ring_low:1; //bit 8 + UINT32 rxdma_fb_ring1_low:1; //bit 7 + UINT32 rxdma_fb_ring0_low:1; //bit 6 + UINT32 rxdma_xfr_done:1; //bit 5 + UINT32 txdma_err:1; //bit 4 + UINT32 txdma_isr:1; //bit 3 + UINT32 unused3:1; //bit 2 + UINT32 unused2:1; //bit 1 + UINT32 unused1:1; //bit 0 + #else + UINT32 unused1:1; //bit 0 + UINT32 unused2:1; //bit 1 + UINT32 unused3:1; //bit 2 + UINT32 txdma_isr:1; //bit 3 + UINT32 txdma_err:1; //bit 4 + UINT32 rxdma_xfr_done:1; //bit 5 + UINT32 rxdma_fb_ring0_low:1; //bit 6 + UINT32 rxdma_fb_ring1_low:1; //bit 7 + UINT32 rxdma_pkt_stat_ring_low:1; //bit 8 + UINT32 rxdma_err:1; //bit 9 + UINT32 unused4:5; //bits 10-14 + UINT32 wake_on_lan:1; //bit 15 + UINT32 phy_interrupt:1; //bit 16 + UINT32 txmac_interrupt:1; //bit 17 + UINT32 rxmac_interrupt:1; //bit 18 + UINT32 mac_stat_interrupt:1; //bit 19 + UINT32 slv_timeout:1; //bit 20 + UINT32 unused5:11; //bits 21-31 + #endif + } bits; +} +INT_MASK_t, *PINT_MASK_t; + + +/****************************************************************************** + structure for interrupt alias clear mask reg in global address map + located at address 0x0020 + *****************************************************************************/ +typedef union _INT_ALIAS_CLR_EN_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused5:11; //bits 21-31 + UINT32 slv_timeout:1; //bit 20 + UINT32 mac_stat_interrupt:1; //bit 19 + UINT32 rxmac_interrupt:1; //bit 18 + UINT32 txmac_interrupt:1; //bit 17 + UINT32 phy_interrupt:1; //bit 16 + UINT32 wake_on_lan:1; //bit 15 + UINT32 watchdog_interrupt:1; //bit 14 + UINT32 unused4:4; //bits 10-13 + UINT32 rxdma_err:1; //bit 9 + UINT32 rxdma_pkt_stat_ring_low:1; //bit 8 + UINT32 rxdma_fb_ring1_low:1; //bit 7 + UINT32 rxdma_fb_ring0_low:1; //bit 6 + UINT32 rxdma_xfr_done:1; //bit 5 + UINT32 txdma_err:1; //bit 4 + UINT32 txdma_isr:1; //bit 3 + UINT32 unused3:1; //bit 2 + UINT32 unused2:1; //bit 1 + UINT32 unused1:1; //bit 0 + #else + UINT32 unused1:1; //bit 0 + UINT32 unused2:1; //bit 1 + UINT32 unused3:1; //bit 2 + UINT32 txdma_isr:1; //bit 3 + UINT32 txdma_err:1; //bit 4 + UINT32 rxdma_xfr_done:1; //bit 5 + UINT32 rxdma_fb_ring0_low:1; //bit 6 + UINT32 rxdma_fb_ring1_low:1; //bit 7 + UINT32 rxdma_pkt_stat_ring_low:1; //bit 8 + UINT32 rxdma_err:1; //bit 9 + UINT32 unused4:4; //bits 10-13 + UINT32 watchdog_interrupt:1; //bit 14 + UINT32 wake_on_lan:1; //bit 15 + UINT32 phy_interrupt:1; //bit 16 + UINT32 txmac_interrupt:1; //bit 17 + UINT32 rxmac_interrupt:1; //bit 18 + UINT32 mac_stat_interrupt:1; //bit 19 + UINT32 slv_timeout:1; //bit 20 + UINT32 unused5:11; //bits 21-31 + #endif + } bits; +} +INT_ALIAS_CLR_EN_t, *PINT_ALIAS_CLR_EN_t; + + +/****************************************************************************** + structure for interrupt status alias reg in global address map + located at address 0x0024 + *****************************************************************************/ +typedef union _INT_STATUS_ALIAS_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused5:11; //bits 21-31 + UINT32 slv_timeout:1; //bit 20 + UINT32 mac_stat_interrupt:1; //bit 19 + UINT32 rxmac_interrupt:1; //bit 18 + UINT32 txmac_interrupt:1; //bit 17 + UINT32 phy_interrupt:1; //bit 16 + UINT32 wake_on_lan:1; //bit 15 + UINT32 watchdog_interrupt:1; //bit 14 + UINT32 unused4:4; //bits 10-13 + UINT32 rxdma_err:1; //bit 9 + UINT32 rxdma_pkt_stat_ring_low:1; //bit 8 + UINT32 rxdma_fb_ring1_low:1; //bit 7 + UINT32 rxdma_fb_ring0_low:1; //bit 6 + UINT32 rxdma_xfr_done:1; //bit 5 + UINT32 txdma_err:1; //bit 4 + UINT32 txdma_isr:1; //bit 3 + UINT32 unused3:1; //bit 2 + UINT32 unused2:1; //bit 1 + UINT32 unused1:1; //bit 0 + #else + UINT32 unused1:1; //bit 0 + UINT32 unused2:1; //bit 1 + UINT32 unused3:1; //bit 2 + UINT32 txdma_isr:1; //bit 3 + UINT32 txdma_err:1; //bit 4 + UINT32 rxdma_xfr_done:1; //bit 5 + UINT32 rxdma_fb_ring0_low:1; //bit 6 + UINT32 rxdma_fb_ring1_low:1; //bit 7 + UINT32 rxdma_pkt_stat_ring_low:1; //bit 8 + UINT32 rxdma_err:1; //bit 9 + UINT32 unused4:4; //bits 10-13 + UINT32 watchdog_interrupt:1; //bit 14 + UINT32 wake_on_lan:1; //bit 15 + UINT32 phy_interrupt:1; //bit 16 + UINT32 txmac_interrupt:1; //bit 17 + UINT32 rxmac_interrupt:1; //bit 18 + UINT32 mac_stat_interrupt:1; //bit 19 + UINT32 slv_timeout:1; //bit 20 + UINT32 unused5:11; //bits 21-31 + #endif + } bits; +} +INT_STATUS_ALIAS_t, *PINT_STATUS_ALIAS_t; + + +/****************************************************************************** + structure for software reset reg in global address map + located at address 0x0028 + *****************************************************************************/ +typedef union _SW_RESET_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 selfclr_disable:1; //bit 31 + UINT32 unused:24; //bits 7-30 + UINT32 mmc_sw_reset:1; //bit 6 + UINT32 mac_stat_sw_reset:1; //bit 5 + UINT32 mac_sw_reset:1; //bit 4 + UINT32 rxmac_sw_reset:1; //bit 3 + UINT32 txmac_sw_reset:1; //bit 2 + UINT32 rxdma_sw_reset:1; //bit 1 + UINT32 txdma_sw_reset:1; //bit 0 + #else + UINT32 txdma_sw_reset:1; //bit 0 + UINT32 rxdma_sw_reset:1; //bit 1 + UINT32 txmac_sw_reset:1; //bit 2 + UINT32 rxmac_sw_reset:1; //bit 3 + UINT32 mac_sw_reset:1; //bit 4 + UINT32 mac_stat_sw_reset:1; //bit 5 + UINT32 mmc_sw_reset:1; //bit 6 + UINT32 unused:24; //bits 7-30 + UINT32 selfclr_disable:1; //bit 31 + #endif + } bits; +} +SW_RESET_t, *PSW_RESET_t; + + +/****************************************************************************** + structure for SLV Timer reg in global address map + located at address 0x002C + *****************************************************************************/ +typedef union _SLV_TIMER_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:8; //bits 24-31 + UINT32 timer_ini:24; //bits 0-23 + #else + UINT32 timer_ini:24; //bits 0-23 + UINT32 unused:8; //bits 24-31 + #endif + } bits; +} +SLV_TIMER_t, *PSLV_TIMER_t; + + +/****************************************************************************** + structure for MSI Configuration reg in global address map + located at address 0x0030 + *****************************************************************************/ +typedef union _MSI_CONFIG_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused1:13; //bits 19-31 + UINT32 msi_tc:3; //bits 16-18 + UINT32 unused2:11; //bits 5-15 + UINT32 msi_vector:5; //bits 0-4 + #else + UINT32 msi_vector:5; //bits 0-4 + UINT32 unused2:11; //bits 5-15 + UINT32 msi_tc:3; //bits 16-18 + UINT32 unused1:13; //bits 19-31 + #endif + } bits; +} +MSI_CONFIG_t, *PMSI_CONFIG_t; + + +/****************************************************************************** + structure for Loopback reg in global address map + located at address 0x0034 + *****************************************************************************/ +typedef union _LOOPBACK_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:30; //bits 2-31 + UINT32 dma_loopback:1; //bit 1 + UINT32 mac_loopback:1; //bit 0 + #else + UINT32 mac_loopback:1; //bit 0 + UINT32 dma_loopback:1; //bit 1 + UINT32 unused:30; //bits 2-31 + #endif + } bits; +} +LOOPBACK_t, *PLOOPBACK_t; + + +/****************************************************************************** + GLOBAL Module of JAGCore Address Mapping + Located at address 0x0000 + *****************************************************************************/ +typedef struct _GLOBAL_t +{ //Location: + TXQ_START_ADDR_t txq_start_addr; // 0x0000 + TXQ_END_ADDR_t txq_end_addr; // 0x0004 + RXQ_START_ADDR_t rxq_start_addr; // 0x0008 + RXQ_END_ADDR_t rxq_end_addr; // 0x000C + PM_CSR_t pm_csr; // 0x0010 + UINT32 unused; // 0x0014 + INT_STATUS_t int_status; // 0x0018 + INT_MASK_t int_mask; // 0x001C + INT_ALIAS_CLR_EN_t int_alias_clr_en; // 0x0020 + INT_STATUS_ALIAS_t int_status_alias; // 0x0024 + SW_RESET_t sw_reset; // 0x0028 + SLV_TIMER_t slv_timer; // 0x002C + MSI_CONFIG_t msi_config; // 0x0030 + LOOPBACK_t loopback; // 0x0034 + UINT32 watchdog_timer; // 0x0038 +} +GLOBAL_t, *PGLOBAL_t; +/*===========================================================================*/ +/*===========================================================================*/ +/*=== END OF GLOBAL REGISTER ADDRESS MAP ===*/ +/*===========================================================================*/ +/*===========================================================================*/ + + + + +/*===========================================================================*/ +/*===========================================================================*/ +/*=== START OF TXDMA REGISTER ADDRESS MAP ===*/ +/*===========================================================================*/ +/*===========================================================================*/ +/****************************************************************************** + structure for txdma control status reg in txdma address map + located at address 0x1000 + *****************************************************************************/ +typedef union _TXDMA_CSR_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused2:19; //bits 13-31 + UINT32 traffic_class:4; //bits 9-12 + UINT32 sngl_epkt_mode:1; //bit 8 + UINT32 cache_thrshld:4; //bits 4-7 + UINT32 unused1:2; //bits 2-3 + UINT32 drop_TLP_disable:1; //bit 1 + UINT32 halt:1; //bit 0 + #else + UINT32 halt:1; //bit 0 + UINT32 drop_TLP_disable:1; //bit 1 + UINT32 unused1:2; //bits 2-3 + UINT32 cache_thrshld:4; //bits 4-7 + UINT32 sngl_epkt_mode:1; //bit 8 + UINT32 traffic_class:4; //bits 9-12 + UINT32 unused2:19; //bits 13-31 + #endif + } bits; +} +TXDMA_CSR_t, *PTXDMA_CSR_t; + + +/****************************************************************************** + structure for txdma packet ring base address hi reg in txdma address map + located at address 0x1004 + *****************************************************************************/ +typedef struct _TXDMA_PR_BASE_HI_t +{ + UINT32 addr_hi; //bits 0-31 +} +TXDMA_PR_BASE_HI_t, *PTXDMA_PR_BASE_HI_t; + + +/****************************************************************************** + structure for txdma packet ring base address low reg in txdma address map + located at address 0x1008 + *****************************************************************************/ +typedef struct _TXDMA_PR_BASE_LO_t +{ + UINT32 addr_lo; //bits 0-31 +} +TXDMA_PR_BASE_LO_t, *PTXDMA_PR_BASE_LO_t; + + +/****************************************************************************** + structure for txdma packet ring number of descriptor reg in txdma address + map. Located at address 0x100C + *****************************************************************************/ +typedef union _TXDMA_PR_NUM_DES_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:22; //bits 10-31 + UINT32 pr_ndes:10; //bits 0-9 + #else + UINT32 pr_ndes:10; //bits 0-9 + UINT32 unused:22; //bits 10-31 + #endif + } bits; +} +TXDMA_PR_NUM_DES_t, *PTXDMA_PR_NUM_DES_t; + + +/****************************************************************************** + structure for txdma tx queue write address reg in txdma address map + located at address 0x1010 + *****************************************************************************/ +typedef union _TXDMA_TXQ_WR_ADDR_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:21; //bits 11-31 + UINT32 txq_wr_wrap:1; //bit 10 + UINT32 txq_wr:10; //bits 0-9 + #else + UINT32 txq_wr:10; //bits 0-9 + UINT32 txq_wr_wrap:1; //bit 10 + UINT32 unused:21; //bits 11-31 + #endif + } bits; +} +TXDMA_TXQ_WR_ADDR_t, *PTXDMA_TXQ_WR_ADDR_t; + + +/****************************************************************************** + structure for txdma tx queue write address external reg in txdma address map + located at address 0x1014 + *****************************************************************************/ +typedef union _TXDMA_TXQ_WR_ADDR_EXT_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:21; //bits 11-31 + UINT32 txq_wr_ext_wrap:1; //bit 10 + UINT32 txq_wr_ext:10; //bits 0-9 + #else + UINT32 txq_wr_ext:10; //bits 0-9 + UINT32 txq_wr_ext_wrap:1; //bit 10 + UINT32 unused:21; //bits 11-31 + #endif + } bits; +} +TXDMA_TXQ_WR_ADDR_EXT_t, *PTXDMA_TXQ_WR_ADDR_EXT_t; + + +/****************************************************************************** + structure for txdma tx queue read address reg in txdma address map + located at address 0x1018 + *****************************************************************************/ +typedef union _TXDMA_TXQ_RD_ADDR_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:21; //bits 11-31 + UINT32 txq_rd_wrap:1; //bit 10 + UINT32 txq_rd:10; //bits 0-9 + #else + UINT32 txq_rd:10; //bits 0-9 + UINT32 txq_rd_wrap:1; //bit 10 + UINT32 unused:21; //bits 11-31 + #endif + } bits; +} +TXDMA_TXQ_RD_ADDR_t, *PTXDMA_TXQ_RD_ADDR_t; + + +/****************************************************************************** + structure for txdma status writeback address hi reg in txdma address map + located at address 0x101C + *****************************************************************************/ +typedef struct _TXDMA_DMA_WB_ADDR_HI_t +{ + UINT32 addr_hi; //bits 0-31 +} +TXDMA_DMA_WB_ADDR_HI_t, *PTXDMA_DMA_WB_ADDR_HI_t; + + +/****************************************************************************** + structure for txdma status writeback address lo reg in txdma address map + located at address 0x1020 + *****************************************************************************/ +typedef struct _TXDMA_DMA_WB_ADDR_LO_t +{ + UINT32 addr_lo; //bits 0-31 +} +TXDMA_DMA_WB_ADDR_LO_t, *PTXDMA_DMA_WB_ADDR_LO_t; + + +/****************************************************************************** + structure for txdma service request reg in txdma address map + located at address 0x1024 + *****************************************************************************/ +typedef union _TXDMA_SERVICE_REQUEST_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:21; //bits 11-31 + UINT32 serv_req_wrap:1; //bit 10 + UINT32 serv_req:10; //bits 0-9 + #else + UINT32 serv_req:10; //bits 0-9 + UINT32 serv_req_wrap:1; //bit 10 + UINT32 unused:21; //bits 11-31 + #endif + } bits; +} +TXDMA_SERVICE_REQUEST_t, *PTXDMA_SERVICE_REQUEST_t; + + +/****************************************************************************** + structure for txdma service complete reg in txdma address map + located at address 0x1028 + *****************************************************************************/ +typedef union _TXDMA_SERVICE_COMPLETE_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:21; //bits 11-31 + UINT32 serv_cpl_wrap:1; //bit 10 + UINT32 serv_cpl:10; //bits 0-9 + #else + UINT32 serv_cpl:10; //bits 0-9 + UINT32 serv_cpl_wrap:1; //bit 10 + UINT32 unused:21; //bits 11-31 + #endif + } bits; +} +TXDMA_SERVICE_COMPLETE_t, *PTXDMA_SERVICE_COMPLETE_t; + + +/****************************************************************************** + structure for txdma tx descriptor cache read index reg in txdma address map + located at address 0x102C + *****************************************************************************/ +typedef union _TXDMA_CACHE_RD_INDEX_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:27; //bits 5-31 + UINT32 rdi_wrap:1; //bit 4 + UINT32 rdi:4; //bit 0-3 + #else + UINT32 rdi:4; //bits 0-3 + UINT32 rdi_wrap:1; //bit 4 + UINT32 unused:27; //bits 5-31 + #endif + } bits; +} +TXDMA_CACHE_RD_INDEX_t, *PTXDMA_CACHE_RD_INDEX_t; + + +/****************************************************************************** + structure for txdma tx descriptor cache write index reg in txdma address map + located at address 0x1030 + *****************************************************************************/ +typedef union _TXDMA_CACHE_WR_INDEX_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:27; //bits 5-31 + UINT32 wri_wrap:1; //bit 4 + UINT32 wri:4; //bit 0-3 + #else + UINT32 wri:4; //bits 0-3 + UINT32 wri_wrap:1; //bit 4 + UINT32 unused:27; //bits 5-31 + #endif + } bits; +} +TXDMA_CACHE_WR_INDEX_t, *PTXDMA_CACHE_WR_INDEX_t; + + +/****************************************************************************** + structure for txdma error reg in txdma address map + located at address 0x1034 + *****************************************************************************/ +typedef union _TXDMA_ERROR_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused3:22; //bits 10-31 + UINT32 WrbkRewind:1; //bit 9 + UINT32 WrbkResend:1; //bit 8 + UINT32 unused2:2; //bits 6-7 + UINT32 DescrRewind:1; //bit 5 + UINT32 DescrResend:1; //bit 4 + UINT32 unused1:2; //bits 2-3 + UINT32 PyldRewind:1; //bit 1 + UINT32 PyldResend:1; //bit 0 + #else + UINT32 PyldResend:1; //bit 0 + UINT32 PyldRewind:1; //bit 1 + UINT32 unused1:2; //bits 2-3 + UINT32 DescrResend:1; //bit 4 + UINT32 DescrRewind:1; //bit 5 + UINT32 unused2:2; //bits 6-7 + UINT32 WrbkResend:1; //bit 8 + UINT32 WrbkRewind:1; //bit 9 + UINT32 unused3:22; //bits 10-31 + #endif + } bits; +} +TXDMA_ERROR_t, *PTXDMA_ERROR_t; + + +/****************************************************************************** + Tx DMA Module of JAGCore Address Mapping + Located at address 0x1000 + *****************************************************************************/ +typedef struct _TXDMA_t +{ //Location: + TXDMA_CSR_t csr; // 0x1000 + TXDMA_PR_BASE_HI_t pr_base_hi; // 0x1004 + TXDMA_PR_BASE_LO_t pr_base_lo; // 0x1008 + TXDMA_PR_NUM_DES_t pr_num_des; // 0x100C + TXDMA_TXQ_WR_ADDR_t txq_wr_addr; // 0x1010 + TXDMA_TXQ_WR_ADDR_EXT_t txq_wr_addr_ext; // 0x1014 + TXDMA_TXQ_RD_ADDR_t txq_rd_addr; // 0x1018 + TXDMA_DMA_WB_ADDR_HI_t dma_wb_base_hi; // 0x101C + TXDMA_DMA_WB_ADDR_LO_t dma_wb_base_lo; // 0x1020 + TXDMA_SERVICE_REQUEST_t service_request; // 0x1024 + TXDMA_SERVICE_COMPLETE_t service_complete; // 0x1028 + TXDMA_CACHE_RD_INDEX_t cache_rd_index; // 0x102C + TXDMA_CACHE_WR_INDEX_t cache_wr_index; // 0x1030 + TXDMA_ERROR_t TxDmaError; // 0x1034 + UINT32 DescAbortCount; // 0x1038 + UINT32 PayloadAbortCnt; // 0x103c + UINT32 WriteBackAbortCnt; // 0x1040 + UINT32 DescTimeoutCnt; // 0x1044 + UINT32 PayloadTimeoutCnt; // 0x1048 + UINT32 WriteBackTimeoutCnt;// 0x104c + UINT32 DescErrorCount; // 0x1050 + UINT32 PayloadErrorCnt; // 0x1054 + UINT32 WriteBackErrorCnt; // 0x1058 + UINT32 DroppedTLPCount; // 0x105c + TXDMA_SERVICE_COMPLETE_t NewServiceComplete; // 0x1060 + UINT32 EthernetPacketCount;// 0x1064 +} +TXDMA_t, *PTXDMA_t; +/*===========================================================================*/ +/*===========================================================================*/ +/*=== END OF TXDMA REGISTER ADDRESS MAP ===*/ +/*===========================================================================*/ +/*===========================================================================*/ + + + +/*===========================================================================*/ +/*===========================================================================*/ +/*=== START OF RXDMA REGISTER ADDRESS MAP ===*/ +/*===========================================================================*/ +/*===========================================================================*/ +/****************************************************************************** + structure for control status reg in rxdma address map + Located at address 0x2000 + *****************************************************************************/ +typedef union _RXDMA_CSR_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused2:14; //bits 18-31 + UINT32 halt_status:1; //bit 17 + UINT32 pkt_done_flush:1; //bit 16 + UINT32 pkt_drop_disable:1; //bit 15 + UINT32 unused1:1; //bit 14 + UINT32 fbr1_enable:1; //bit 13 + UINT32 fbr1_size:2; //bits 11-12 + UINT32 fbr0_enable:1; //bit 10 + UINT32 fbr0_size:2; //bits 8-9 + UINT32 dma_big_endian:1; //bit 7 + UINT32 pkt_big_endian:1; //bit 6 + UINT32 psr_big_endian:1; //bit 5 + UINT32 fbr_big_endian:1; //bit 4 + UINT32 tc:3; //bits 1-3 + UINT32 halt:1; //bit 0 + #else + UINT32 halt:1; //bit 0 + UINT32 tc:3; //bits 1-3 + UINT32 fbr_big_endian:1; //bit 4 + UINT32 psr_big_endian:1; //bit 5 + UINT32 pkt_big_endian:1; //bit 6 + UINT32 dma_big_endian:1; //bit 7 + UINT32 fbr0_size:2; //bits 8-9 + UINT32 fbr0_enable:1; //bit 10 + UINT32 fbr1_size:2; //bits 11-12 + UINT32 fbr1_enable:1; //bit 13 + UINT32 unused1:1; //bit 14 + UINT32 pkt_drop_disable:1; //bit 15 + UINT32 pkt_done_flush:1; //bit 16 + UINT32 halt_status:1; //bit 17 + UINT32 unused2:14; //bits 18-31 + #endif + } bits; +} +RXDMA_CSR_t, *PRXDMA_CSR_t; + + +/****************************************************************************** + structure for dma writeback lo reg in rxdma address map + located at address 0x2004 + *****************************************************************************/ +typedef struct _RXDMA_DMA_WB_BASE_LO_t +{ + UINT32 addr_lo; //bits 0-31 +} +RXDMA_DMA_WB_BASE_LO_t, *PRXDMA_DMA_WB_BASE_LO_t; + + +/****************************************************************************** + structure for dma writeback hi reg in rxdma address map + located at address 0x2008 + *****************************************************************************/ +typedef struct _RXDMA_DMA_WB_BASE_HI_t +{ + UINT32 addr_hi; //bits 0-31 +} +RXDMA_DMA_WB_BASE_HI_t, *PRXDMA_DMA_WB_BASE_HI_t; + + +/****************************************************************************** + structure for number of packets done reg in rxdma address map + located at address 0x200C + *****************************************************************************/ +typedef union _RXDMA_NUM_PKT_DONE_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:24; //bits 8-31 + UINT32 num_done:8; //bits 0-7 + #else + UINT32 num_done:8; //bits 0-7 + UINT32 unused:24; //bits 8-31 + #endif + } bits; +} +RXDMA_NUM_PKT_DONE_t, *PRXDMA_NUM_PKT_DONE_t; + + +/****************************************************************************** + structure for max packet time reg in rxdma address map + located at address 0x2010 + *****************************************************************************/ +typedef union _RXDMA_MAX_PKT_TIME_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:14; //bits 18-31 + UINT32 time_done:18; //bits 0-17 + #else + UINT32 time_done:18; //bits 0-17 + UINT32 unused:14; //bits 18-31 + #endif + } bits; +} +RXDMA_MAX_PKT_TIME_t, *PRXDMA_MAX_PKT_TIME_t; + + +/****************************************************************************** + structure for rx queue read address reg in rxdma address map + located at address 0x2014 + *****************************************************************************/ +typedef union _RXDMA_RXQ_RD_ADDR_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:21; //bits 11-31 + UINT32 rxq_rd_wrap:1; //bit 10 + UINT32 rxq_rd:10; //bits 0-9 + #else + UINT32 rxq_rd:10; //bits 0-9 + UINT32 rxq_rd_wrap:1; //bit 10 + UINT32 unused:21; //bits 11-31 + #endif + } bits; +} +RXDMA_RXQ_RD_ADDR_t, *PRXDMA_RXQ_RD_ADDR_t; + + +/****************************************************************************** + structure for rx queue read address external reg in rxdma address map + located at address 0x2018 + *****************************************************************************/ +typedef union _RXDMA_RXQ_RD_ADDR_EXT_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:21; //bits 11-31 + UINT32 rxq_rd_ext_wrap:1; //bit 10 + UINT32 rxq_rd_ext:10; //bits 0-9 + #else + UINT32 rxq_rd_ext:10; //bits 0-9 + UINT32 rxq_rd_ext_wrap:1; //bit 10 + UINT32 unused:21; //bits 11-31 + #endif + } bits; +} +RXDMA_RXQ_RD_ADDR_EXT_t, *PRXDMA_RXQ_RD_ADDR_EXT_t; + + +/****************************************************************************** + structure for rx queue write address reg in rxdma address map + located at address 0x201C + *****************************************************************************/ +typedef union _RXDMA_RXQ_WR_ADDR_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:21; //bits 11-31 + UINT32 rxq_wr_wrap:1; //bit 10 + UINT32 rxq_wr:10; //bits 0-9 + #else + UINT32 rxq_wr:10; //bits 0-9 + UINT32 rxq_wr_wrap:1; //bit 10 + UINT32 unused:21; //bits 11-31 + #endif + } bits; +} +RXDMA_RXQ_WR_ADDR_t, *PRXDMA_RXQ_WR_ADDR_t; + + +/****************************************************************************** + structure for packet status ring base address lo reg in rxdma address map + located at address 0x2020 + *****************************************************************************/ +typedef struct _RXDMA_PSR_BASE_LO_t +{ + UINT32 addr_lo; //bits 0-31 +} +RXDMA_PSR_BASE_LO_t, *PRXDMA_PSR_BASE_LO_t; + + +/****************************************************************************** + structure for packet status ring base address hi reg in rxdma address map + located at address 0x2024 + *****************************************************************************/ +typedef struct _RXDMA_PSR_BASE_HI_t +{ + UINT32 addr_hi; //bits 0-31 +} +RXDMA_PSR_BASE_HI_t, *PRXDMA_PSR_BASE_HI_t; + + +/****************************************************************************** + structure for packet status ring number of descriptors reg in rxdma address + map. Located at address 0x2028 + *****************************************************************************/ +typedef union _RXDMA_PSR_NUM_DES_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:20; //bits 12-31 + UINT32 psr_ndes:12; //bit 0-11 + #else + UINT32 psr_ndes:12; //bit 0-11 + UINT32 unused:20; //bits 12-31 + #endif + } bits; +} +RXDMA_PSR_NUM_DES_t, *PRXDMA_PSR_NUM_DES_t; + + +/****************************************************************************** + structure for packet status ring available offset reg in rxdma address map + located at address 0x202C + *****************************************************************************/ +typedef union _RXDMA_PSR_AVAIL_OFFSET_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:19; //bits 13-31 + UINT32 psr_avail_wrap:1; //bit 12 + UINT32 psr_avail:12; //bit 0-11 + #else + UINT32 psr_avail:12; //bit 0-11 + UINT32 psr_avail_wrap:1; //bit 12 + UINT32 unused:19; //bits 13-31 + #endif + } bits; +} +RXDMA_PSR_AVAIL_OFFSET_t, *PRXDMA_PSR_AVAIL_OFFSET_t; + + +/****************************************************************************** + structure for packet status ring full offset reg in rxdma address map + located at address 0x2030 + *****************************************************************************/ +typedef union _RXDMA_PSR_FULL_OFFSET_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:19; //bits 13-31 + UINT32 psr_full_wrap:1; //bit 12 + UINT32 psr_full:12; //bit 0-11 + #else + UINT32 psr_full:12; //bit 0-11 + UINT32 psr_full_wrap:1; //bit 12 + UINT32 unused:19; //bits 13-31 + #endif + } bits; +} +RXDMA_PSR_FULL_OFFSET_t, *PRXDMA_PSR_FULL_OFFSET_t; + + +/****************************************************************************** + structure for packet status ring access index reg in rxdma address map + located at address 0x2034 + *****************************************************************************/ +typedef union _RXDMA_PSR_ACCESS_INDEX_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:27; //bits 5-31 + UINT32 psr_ai:5; //bits 0-4 + #else + UINT32 psr_ai:5; //bits 0-4 + UINT32 unused:27; //bits 5-31 + #endif + } bits; +} +RXDMA_PSR_ACCESS_INDEX_t, *PRXDMA_PSR_ACCESS_INDEX_t; + + +/****************************************************************************** + structure for packet status ring minimum descriptors reg in rxdma address + map. Located at address 0x2038 + *****************************************************************************/ +typedef union _RXDMA_PSR_MIN_DES_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:20; //bits 12-31 + UINT32 psr_min:12; //bits 0-11 + #else + UINT32 psr_min:12; //bits 0-11 + UINT32 unused:20; //bits 12-31 + #endif + } bits; +} +RXDMA_PSR_MIN_DES_t, *PRXDMA_PSR_MIN_DES_t; + + +/****************************************************************************** + structure for free buffer ring base lo address reg in rxdma address map + located at address 0x203C + *****************************************************************************/ +typedef struct _RXDMA_FBR_BASE_LO_t +{ + UINT32 addr_lo; //bits 0-31 +} +RXDMA_FBR_BASE_LO_t, *PRXDMA_FBR_BASE_LO_t; + + +/****************************************************************************** + structure for free buffer ring base hi address reg in rxdma address map + located at address 0x2040 + *****************************************************************************/ +typedef struct _RXDMA_FBR_BASE_HI_t +{ + UINT32 addr_hi; //bits 0-31 +} +RXDMA_FBR_BASE_HI_t, *PRXDMA_FBR_BASE_HI_t; + + +/****************************************************************************** + structure for free buffer ring number of descriptors reg in rxdma address + map. Located at address 0x2044 + *****************************************************************************/ +typedef union _RXDMA_FBR_NUM_DES_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:22; //bits 10-31 + UINT32 fbr_ndesc:10; //bits 0-9 + #else + UINT32 fbr_ndesc:10; //bits 0-9 + UINT32 unused:22; //bits 10-31 + #endif + } bits; +} +RXDMA_FBR_NUM_DES_t, *PRXDMA_FBR_NUM_DES_t; + + +/****************************************************************************** + structure for free buffer ring 0 available offset reg in rxdma address map + located at address 0x2048 + *****************************************************************************/ +typedef union _RXDMA_FBR_AVAIL_OFFSET_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:21; //bits 11-31 + UINT32 fbr_avail_wrap:1; //bit 10 + UINT32 fbr_avail:10; //bit 0-9 + #else + UINT32 fbr_avail:10; //bit 0-9 + UINT32 fbr_avail_wrap:1; //bit 10 + UINT32 unused:21; //bits 11-31 + #endif + } bits; +} +RXDMA_FBR_AVAIL_OFFSET_t, *PRXDMA_FBR_AVAIL_OFFSET_t; + + +/****************************************************************************** + structure for free buffer ring 0 full offset reg in rxdma address map + located at address 0x204C + *****************************************************************************/ +typedef union _RXDMA_FBR_FULL_OFFSET_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:21; //bits 11-31 + UINT32 fbr_full_wrap:1; //bit 10 + UINT32 fbr_full:10; //bit 0-9 + #else + UINT32 fbr_full:10; //bit 0-9 + UINT32 fbr_full_wrap:1; //bit 10 + UINT32 unused:21; //bits 11-31 + #endif + } bits; +} +RXDMA_FBR_FULL_OFFSET_t, *PRXDMA_FBR_FULL_OFFSET_t; + + +/****************************************************************************** + structure for free buffer cache 0 full offset reg in rxdma address map + located at address 0x2050 + *****************************************************************************/ +typedef union _RXDMA_FBC_RD_INDEX_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:27; //bits 5-31 + UINT32 fbc_rdi:5; //bit 0-4 + #else + UINT32 fbc_rdi:5; //bit 0-4 + UINT32 unused:27; //bits 5-31 + #endif + } bits; +} +RXDMA_FBC_RD_INDEX_t, *PRXDMA_FBC_RD_INDEX_t; + + +/****************************************************************************** + structure for free buffer ring 0 minimum descriptor reg in rxdma address map + located at address 0x2054 + *****************************************************************************/ +typedef union _RXDMA_FBR_MIN_DES_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:22; //bits 10-31 + UINT32 fbr_min:10; //bits 0-9 + #else + UINT32 fbr_min:10; //bits 0-9 + UINT32 unused:22; //bits 10-31 + #endif + } bits; +} +RXDMA_FBR_MIN_DES_t, *PRXDMA_FBR_MIN_DES_t; + + +/****************************************************************************** + structure for free buffer ring 1 base address lo reg in rxdma address map + located at address 0x2058 - 0x205C + Defined earlier (RXDMA_FBR_BASE_LO_t and RXDMA_FBR_BASE_HI_t) + *****************************************************************************/ + +/****************************************************************************** + structure for free buffer ring 1 number of descriptors reg in rxdma address + map. Located at address 0x2060 + Defined earlier (RXDMA_FBR_NUM_DES_t) + *****************************************************************************/ + +/****************************************************************************** + structure for free buffer ring 1 available offset reg in rxdma address map + located at address 0x2064 + Defined Earlier (RXDMA_FBR_AVAIL_OFFSET_t) + *****************************************************************************/ + +/****************************************************************************** + structure for free buffer ring 1 full offset reg in rxdma address map + located at address 0x2068 + Defined Earlier (RXDMA_FBR_FULL_OFFSET_t) + *****************************************************************************/ + +/****************************************************************************** + structure for free buffer cache 1 read index reg in rxdma address map + located at address 0x206C + Defined Earlier (RXDMA_FBC_RD_INDEX_t) + *****************************************************************************/ + +/****************************************************************************** + structure for free buffer ring 1 minimum descriptor reg in rxdma address map + located at address 0x2070 + Defined Earlier (RXDMA_FBR_MIN_DES_t) + *****************************************************************************/ + + +/****************************************************************************** + Rx DMA Module of JAGCore Address Mapping + Located at address 0x2000 + *****************************************************************************/ +typedef struct _RXDMA_t +{ //Location: + RXDMA_CSR_t csr; // 0x2000 + RXDMA_DMA_WB_BASE_LO_t dma_wb_base_lo; // 0x2004 + RXDMA_DMA_WB_BASE_HI_t dma_wb_base_hi; // 0x2008 + RXDMA_NUM_PKT_DONE_t num_pkt_done; // 0x200C + RXDMA_MAX_PKT_TIME_t max_pkt_time; // 0x2010 + RXDMA_RXQ_RD_ADDR_t rxq_rd_addr; // 0x2014 + RXDMA_RXQ_RD_ADDR_EXT_t rxq_rd_addr_ext; // 0x2018 + RXDMA_RXQ_WR_ADDR_t rxq_wr_addr; // 0x201C + RXDMA_PSR_BASE_LO_t psr_base_lo; // 0x2020 + RXDMA_PSR_BASE_HI_t psr_base_hi; // 0x2024 + RXDMA_PSR_NUM_DES_t psr_num_des; // 0x2028 + RXDMA_PSR_AVAIL_OFFSET_t psr_avail_offset; // 0x202C + RXDMA_PSR_FULL_OFFSET_t psr_full_offset; // 0x2030 + RXDMA_PSR_ACCESS_INDEX_t psr_access_index; // 0x2034 + RXDMA_PSR_MIN_DES_t psr_min_des; // 0x2038 + RXDMA_FBR_BASE_LO_t fbr0_base_lo; // 0x203C + RXDMA_FBR_BASE_HI_t fbr0_base_hi; // 0x2040 + RXDMA_FBR_NUM_DES_t fbr0_num_des; // 0x2044 + RXDMA_FBR_AVAIL_OFFSET_t fbr0_avail_offset; // 0x2048 + RXDMA_FBR_FULL_OFFSET_t fbr0_full_offset; // 0x204C + RXDMA_FBC_RD_INDEX_t fbr0_rd_index; // 0x2050 + RXDMA_FBR_MIN_DES_t fbr0_min_des; // 0x2054 + RXDMA_FBR_BASE_LO_t fbr1_base_lo; // 0x2058 + RXDMA_FBR_BASE_HI_t fbr1_base_hi; // 0x205C + RXDMA_FBR_NUM_DES_t fbr1_num_des; // 0x2060 + RXDMA_FBR_AVAIL_OFFSET_t fbr1_avail_offset; // 0x2064 + RXDMA_FBR_FULL_OFFSET_t fbr1_full_offset; // 0x2068 + RXDMA_FBC_RD_INDEX_t fbr1_rd_index; // 0x206C + RXDMA_FBR_MIN_DES_t fbr1_min_des; // 0x2070 +} +RXDMA_t, *PRXDMA_t; +/*===========================================================================*/ +/*===========================================================================*/ +/*=== END OF RXDMA REGISTER ADDRESS MAP ===*/ +/*===========================================================================*/ +/*===========================================================================*/ + + + +/*===========================================================================*/ +/*===========================================================================*/ +/*=== START OF TXMAC REGISTER ADDRESS MAP ===*/ +/*===========================================================================*/ +/*===========================================================================*/ +/****************************************************************************** + structure for control reg in txmac address map + located at address 0x3000 + *****************************************************************************/ +typedef union _TXMAC_CTL_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:24; //bits 8-31 + UINT32 cklseg_diable:1; //bit 7 + UINT32 ckbcnt_disable:1; //bit 6 + UINT32 cksegnum:1; //bit 5 + UINT32 async_disable:1; //bit 4 + UINT32 fc_disable:1; //bit 3 + UINT32 mcif_disable:1; //bit 2 + UINT32 mif_disable:1; //bit 1 + UINT32 txmac_en:1; //bit 0 + #else + UINT32 txmac_en:1; //bit 0 + UINT32 mif_disable:1; //bit 1 mac interface + UINT32 mcif_disable:1; //bit 2 memory controller interface + UINT32 fc_disable:1; //bit 3 + UINT32 async_disable:1; //bit 4 + UINT32 cksegnum:1; //bit 5 + UINT32 ckbcnt_disable:1; //bit 6 + UINT32 cklseg_diable:1; //bit 7 + UINT32 unused:24; //bits 8-31 + #endif + } bits; +} +TXMAC_CTL_t, *PTXMAC_CTL_t; + + +/****************************************************************************** + structure for shadow pointer reg in txmac address map + located at address 0x3004 + *****************************************************************************/ +typedef union _TXMAC_SHADOW_PTR_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved2:5; //bits 27-31 + UINT32 txq_rd_ptr:11; //bits 16-26 + UINT32 reserved:5; //bits 11-15 + UINT32 txq_wr_ptr:11; //bits 0-10 + #else + UINT32 txq_wr_ptr:11; //bits 0-10 + UINT32 reserved:5; //bits 11-15 + UINT32 txq_rd_ptr:11; //bits 16-26 + UINT32 reserved2:5; //bits 27-31 + #endif + } bits; +} +TXMAC_SHADOW_PTR_t, *PTXMAC_SHADOW_PTR_t; + + +/****************************************************************************** + structure for error count reg in txmac address map + located at address 0x3008 + *****************************************************************************/ +typedef union _TXMAC_ERR_CNT_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:20; //bits 12-31 + UINT32 reserved:4; //bits 8-11 + UINT32 txq_underrun:4; //bits 4-7 + UINT32 fifo_underrun:4; //bits 0-3 + #else + UINT32 fifo_underrun:4; //bits 0-3 + UINT32 txq_underrun:4; //bits 4-7 + UINT32 reserved:4; //bits 8-11 + UINT32 unused:20; //bits 12-31 + #endif + } bits; +} TXMAC_ERR_CNT_t, *PTXMAC_ERR_CNT_t; + + +/****************************************************************************** + structure for max fill reg in txmac address map + located at address 0x300C + *****************************************************************************/ +typedef union _TXMAC_MAX_FILL_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:20; //bits 12-31 + UINT32 max_fill:12; //bits 0-11 + #else + UINT32 max_fill:12; //bits 0-11 + UINT32 unused:20; //bits 12-31 + #endif + } bits; +} +TXMAC_MAX_FILL_t, *PTXMAC_MAX_FILL_t; + + +/****************************************************************************** + structure for cf parameter reg in txmac address map + located at address 0x3010 + *****************************************************************************/ +typedef union _TXMAC_CF_PARAM_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 cfep:16; //bits 16-31 + UINT32 cfpt:16; //bits 0-15 + #else + UINT32 cfpt:16; //bits 0-15 + UINT32 cfep:16; //bits 16-31 + #endif + } bits; +} +TXMAC_CF_PARAM_t, *PTXMAC_CF_PARAM_t; + + +/****************************************************************************** + structure for tx test reg in txmac address map + located at address 0x3014 + *****************************************************************************/ +typedef union _TXMAC_TXTEST_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused2:15; //bits 17-31 + UINT32 reserved1:1; //bit 16 + UINT32 txtest_en:1; //bit 15 + UINT32 unused1:4; //bits 11-14 + UINT32 txqtest_ptr:11; //bits 0-11 + #else + UINT32 txqtest_ptr:11; //bits 0-10 + UINT32 unused1:4; //bits 11-14 + UINT32 txtest_en:1; //bit 15 + UINT32 reserved1:1; //bit 16 + UINT32 unused2:15; //bits 17-31 + #endif + } bits; +} +TXMAC_TXTEST_t, *PTXMAC_TXTEST_t; + + +/****************************************************************************** + structure for error reg in txmac address map + located at address 0x3018 + *****************************************************************************/ +typedef union _TXMAC_ERR_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused2:23; //bits 9-31 + UINT32 fifo_underrun:1; //bit 8 + UINT32 unused1:2; //bits 6-7 + UINT32 ctrl2_err:1; //bit 5 + UINT32 txq_underrun:1; //bit 4 + UINT32 bcnt_err:1; //bit 3 + UINT32 lseg_err:1; //bit 2 + UINT32 segnum_err:1; //bit 1 + UINT32 seg0_err:1; //bit 0 + #else + UINT32 seg0_err:1; //bit 0 + UINT32 segnum_err:1; //bit 1 + UINT32 lseg_err:1; //bit 2 + UINT32 bcnt_err:1; //bit 3 + UINT32 txq_underrun:1; //bit 4 + UINT32 ctrl2_err:1; //bit 5 + UINT32 unused1:2; //bits 6-7 + UINT32 fifo_underrun:1; //bit 8 + UINT32 unused2:23; //bits 9-31 + #endif + } bits; +} +TXMAC_ERR_t, *PTXMAC_ERR_t; + + +/****************************************************************************** + structure for error interrupt reg in txmac address map + located at address 0x301C + *****************************************************************************/ +typedef union _TXMAC_ERR_INT_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused2:23; //bits 9-31 + UINT32 fifo_underrun:1; //bit 8 + UINT32 unused1:2; //bits 6-7 + UINT32 ctrl2_err:1; //bit 5 + UINT32 txq_underrun:1; //bit 4 + UINT32 bcnt_err:1; //bit 3 + UINT32 lseg_err:1; //bit 2 + UINT32 segnum_err:1; //bit 1 + UINT32 seg0_err:1; //bit 0 + #else + UINT32 seg0_err:1; //bit 0 + UINT32 segnum_err:1; //bit 1 + UINT32 lseg_err:1; //bit 2 + UINT32 bcnt_err:1; //bit 3 + UINT32 txq_underrun:1; //bit 4 + UINT32 ctrl2_err:1; //bit 5 + UINT32 unused1:2; //bits 6-7 + UINT32 fifo_underrun:1; //bit 8 + UINT32 unused2:23; //bits 9-31 + #endif + } bits; +} +TXMAC_ERR_INT_t, *PTXMAC_ERR_INT_t; + + +/****************************************************************************** + structure for error interrupt reg in txmac address map + located at address 0x3020 + *****************************************************************************/ +typedef union _TXMAC_CP_CTRL_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:30; //bits 2-31 + UINT32 bp_req:1; //bit 1 + UINT32 bp_xonxoff:1; //bit 0 + #else + UINT32 bp_xonxoff:1; //bit 0 + UINT32 bp_req:1; //bit 1 + UINT32 unused:30; //bits 2-31 + #endif + } bits; +} +TXMAC_BP_CTRL_t, *PTXMAC_BP_CTRL_t; + + +/****************************************************************************** + Tx MAC Module of JAGCore Address Mapping + *****************************************************************************/ +typedef struct _TXMAC_t +{ //Location: + TXMAC_CTL_t ctl; // 0x3000 + TXMAC_SHADOW_PTR_t shadow_ptr; // 0x3004 + TXMAC_ERR_CNT_t err_cnt; // 0x3008 + TXMAC_MAX_FILL_t max_fill; // 0x300C + TXMAC_CF_PARAM_t cf_param; // 0x3010 + TXMAC_TXTEST_t tx_test; // 0x3014 + TXMAC_ERR_t err; // 0x3018 + TXMAC_ERR_INT_t err_int; // 0x301C + TXMAC_BP_CTRL_t bp_ctrl; // 0x3020 +} +TXMAC_t, *PTXMAC_t; +/*===========================================================================*/ +/*===========================================================================*/ +/*=== END OF TXMAC REGISTER ADDRESS MAP ===*/ +/*===========================================================================*/ +/*===========================================================================*/ + + + +/*===========================================================================*/ +/*===========================================================================*/ +/*=== START OF RXMAC REGISTER ADDRESS MAP ===*/ +/*===========================================================================*/ +/*===========================================================================*/ +/****************************************************************************** + structure for rxmac control reg in rxmac address map + located at address 0x4000 + *****************************************************************************/ +typedef union _RXMAC_CTRL_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved:25; //bits 7-31 + UINT32 rxmac_int_disable:1; //bit 6 + UINT32 async_disable:1; //bit 5 + UINT32 mif_disable:1; //bit 4 + UINT32 wol_disable:1; //bit 3 + UINT32 pkt_filter_disable:1; //bit 2 + UINT32 mcif_disable:1; //bit 1 + UINT32 rxmac_en:1; //bit 0 + #else + UINT32 rxmac_en:1; //bit 0 + UINT32 mcif_disable:1; //bit 1 + UINT32 pkt_filter_disable:1; //bit 2 + UINT32 wol_disable:1; //bit 3 + UINT32 mif_disable:1; //bit 4 + UINT32 async_disable:1; //bit 5 + UINT32 rxmac_int_disable:1; //bit 6 + UINT32 reserved:25; //bits 7-31 + #endif + } bits; +} +RXMAC_CTRL_t, *PRXMAC_CTRL_t; + + +/****************************************************************************** + structure for Wake On Lan Control and CRC 0 reg in rxmac address map + located at address 0x4004 + *****************************************************************************/ +typedef union _RXMAC_WOL_CTL_CRC0_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 crc0:16; //bits 16-31 + UINT32 reserve:4; //bits 12-15 + UINT32 ignore_pp:1; //bit 11 + UINT32 ignore_mp:1; //bit 10 + UINT32 clr_intr:1; //bit 9 + UINT32 ignore_link_chg:1; //bit 8 + UINT32 ignore_uni:1; //bit 7 + UINT32 ignore_multi:1; //bit 6 + UINT32 ignore_broad:1; //bit 5 + UINT32 valid_crc4:1; //bit 4 + UINT32 valid_crc3:1; //bit 3 + UINT32 valid_crc2:1; //bit 2 + UINT32 valid_crc1:1; //bit 1 + UINT32 valid_crc0:1; //bit 0 + #else + UINT32 valid_crc0:1; //bit 0 + UINT32 valid_crc1:1; //bit 1 + UINT32 valid_crc2:1; //bit 2 + UINT32 valid_crc3:1; //bit 3 + UINT32 valid_crc4:1; //bit 4 + UINT32 ignore_broad:1; //bit 5 + UINT32 ignore_multi:1; //bit 6 + UINT32 ignore_uni:1; //bit 7 + UINT32 ignore_link_chg:1; //bit 8 + UINT32 clr_intr:1; //bit 9 + UINT32 ignore_mp:1; //bit 10 + UINT32 ignore_pp:1; //bit 11 + UINT32 reserve:4; //bits 12-15 + UINT32 crc0:16; //bits 16-31 + #endif + } bits; +} +RXMAC_WOL_CTL_CRC0_t, *PRXMAC_WOL_CTL_CRC0_t; + + +/****************************************************************************** + structure for CRC 1 and CRC 2 reg in rxmac address map + located at address 0x4008 + *****************************************************************************/ +typedef union _RXMAC_WOL_CRC12_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 crc2:16; //bits 16-31 + UINT32 crc1:16; //bits 0-15 + #else + UINT32 crc1:16; //bits 0-15 + UINT32 crc2:16; //bits 16-31 + #endif + } bits; +} +RXMAC_WOL_CRC12_t, *PRXMAC_WOL_CRC12_t; + + +/****************************************************************************** + structure for CRC 3 and CRC 4 reg in rxmac address map + located at address 0x400C + *****************************************************************************/ +typedef union _RXMAC_WOL_CRC34_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 crc4:16; //bits 16-31 + UINT32 crc3:16; //bits 0-15 + #else + UINT32 crc3:16; //bits 0-15 + UINT32 crc4:16; //bits 16-31 + #endif + } bits; +} +RXMAC_WOL_CRC34_t, *PRXMAC_WOL_CRC34_t; + + +/****************************************************************************** + structure for Wake On Lan Source Address Lo reg in rxmac address map + located at address 0x4010 + *****************************************************************************/ +typedef union _RXMAC_WOL_SA_LO_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 sa3:8; //bits 24-31 + UINT32 sa4:8; //bits 16-23 + UINT32 sa5:8; //bits 8-15 + UINT32 sa6:8; //bits 0-7 + #else + UINT32 sa6:8; //bits 0-7 + UINT32 sa5:8; //bits 8-15 + UINT32 sa4:8; //bits 16-23 + UINT32 sa3:8; //bits 24-31 + #endif + } bits; +} +RXMAC_WOL_SA_LO_t, *PRXMAC_WOL_SA_LO_t; + + +/****************************************************************************** + structure for Wake On Lan Source Address Hi reg in rxmac address map + located at address 0x4014 + *****************************************************************************/ +typedef union _RXMAC_WOL_SA_HI_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved:16; //bits 16-31 + UINT32 sa1:8; //bits 8-15 + UINT32 sa2:8; //bits 0-7 + #else + UINT32 sa2:8; //bits 0-7 + UINT32 sa1:8; //bits 8-15 + UINT32 reserved:16; //bits 16-31 + #endif + } bits; +} +RXMAC_WOL_SA_HI_t, *PRXMAC_WOL_SA_HI_t; + + +/****************************************************************************** + structure for Wake On Lan mask reg in rxmac address map + located at address 0x4018 - 0x4064 + *****************************************************************************/ +typedef struct _RXMAC_WOL_MASK_t +{ + UINT32 mask; //bits 0-31 +} +RXMAC_WOL_MASK_t, *PRXMAC_WOL_MASK_t; + + +/****************************************************************************** + structure for Unicast Paket Filter Address 1 reg in rxmac address map + located at address 0x4068 + *****************************************************************************/ +typedef union _RXMAC_UNI_PF_ADDR1_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 addr1_3:8; //bits 24-31 + UINT32 addr1_4:8; //bits 16-23 + UINT32 addr1_5:8; //bits 8-15 + UINT32 addr1_6:8; //bits 0-7 + #else + UINT32 addr1_6:8; //bits 0-7 + UINT32 addr1_5:8; //bits 8-15 + UINT32 addr1_4:8; //bits 16-23 + UINT32 addr1_3:8; //bits 24-31 + #endif + } bits; +} +RXMAC_UNI_PF_ADDR1_t, *PRXMAC_UNI_PF_ADDR1_t; + + +/****************************************************************************** + structure for Unicast Paket Filter Address 2 reg in rxmac address map + located at address 0x406C + *****************************************************************************/ +typedef union _RXMAC_UNI_PF_ADDR2_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 addr2_3:8; //bits 24-31 + UINT32 addr2_4:8; //bits 16-23 + UINT32 addr2_5:8; //bits 8-15 + UINT32 addr2_6:8; //bits 0-7 + #else + UINT32 addr2_6:8; //bits 0-7 + UINT32 addr2_5:8; //bits 8-15 + UINT32 addr2_4:8; //bits 16-23 + UINT32 addr2_3:8; //bits 24-31 + #endif + } bits; +} +RXMAC_UNI_PF_ADDR2_t, *PRXMAC_UNI_PF_ADDR2_t; + + +/****************************************************************************** + structure for Unicast Paket Filter Address 1 & 2 reg in rxmac address map + located at address 0x4070 + *****************************************************************************/ +typedef union _RXMAC_UNI_PF_ADDR3_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 addr2_1:8; //bits 24-31 + UINT32 addr2_2:8; //bits 16-23 + UINT32 addr1_1:8; //bits 8-15 + UINT32 addr1_2:8; //bits 0-7 + #else + UINT32 addr1_2:8; //bits 0-7 + UINT32 addr1_1:8; //bits 8-15 + UINT32 addr2_2:8; //bits 16-23 + UINT32 addr2_1:8; //bits 24-31 + #endif + } bits; +} +RXMAC_UNI_PF_ADDR3_t, *PRXMAC_UNI_PF_ADDR3_t; + + +/****************************************************************************** + structure for Multicast Hash reg in rxmac address map + located at address 0x4074 - 0x4080 + *****************************************************************************/ +typedef struct _RXMAC_MULTI_HASH_t +{ + UINT32 hash; //bits 0-31 +} +RXMAC_MULTI_HASH_t, *PRXMAC_MULTI_HASH_t; + + +/****************************************************************************** + structure for Packet Filter Control reg in rxmac address map + located at address 0x4084 + *****************************************************************************/ +typedef union _RXMAC_PF_CTRL_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused2:9; //bits 23-31 + UINT32 min_pkt_size:7; //bits 16-22 + UINT32 unused1:12; //bits 4-15 + UINT32 filter_frag_en:1; //bit 3 + UINT32 filter_uni_en:1; //bit 2 + UINT32 filter_multi_en:1; //bit 1 + UINT32 filter_broad_en:1; //bit 0 + #else + UINT32 filter_broad_en:1; //bit 0 + UINT32 filter_multi_en:1; //bit 1 + UINT32 filter_uni_en:1; //bit 2 + UINT32 filter_frag_en:1; //bit 3 + UINT32 unused1:12; //bits 4-15 + UINT32 min_pkt_size:7; //bits 16-22 + UINT32 unused2:9; //bits 23-31 + #endif + } bits; +} +RXMAC_PF_CTRL_t, *PRXMAC_PF_CTRL_t; + + +/****************************************************************************** + structure for Memory Controller Interface Control Max Segment reg in rxmac + address map. Located at address 0x4088 + *****************************************************************************/ +typedef union _RXMAC_MCIF_CTRL_MAX_SEG_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved:22; //bits 10-31 + UINT32 max_size:8; //bits 2-9 + UINT32 fc_en:1; //bit 1 + UINT32 seg_en:1; //bit 0 + #else + UINT32 seg_en:1; //bit 0 + UINT32 fc_en:1; //bit 1 + UINT32 max_size:8; //bits 2-9 + UINT32 reserved:22; //bits 10-31 + #endif + } bits; +} +RXMAC_MCIF_CTRL_MAX_SEG_t, *PRXMAC_MCIF_CTRL_MAX_SEG_t; + + +/****************************************************************************** + structure for Memory Controller Interface Water Mark reg in rxmac address + map. Located at address 0x408C + *****************************************************************************/ +typedef union _RXMAC_MCIF_WATER_MARK_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved2:6; //bits 26-31 + UINT32 mark_hi:10; //bits 16-25 + UINT32 reserved1:6; //bits 10-15 + UINT32 mark_lo:10; //bits 0-9 + #else + UINT32 mark_lo:10; //bits 0-9 + UINT32 reserved1:6; //bits 10-15 + UINT32 mark_hi:10; //bits 16-25 + UINT32 reserved2:6; //bits 26-31 + #endif + } bits; +} +RXMAC_MCIF_WATER_MARK_t, *PRXMAC_MCIF_WATER_MARK_t; + + +/****************************************************************************** + structure for Rx Queue Dialog reg in rxmac address map. + located at address 0x4090 + *****************************************************************************/ +typedef union _RXMAC_RXQ_DIAG_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved2:6; //bits 26-31 + UINT32 rd_ptr:10; //bits 16-25 + UINT32 reserved1:6; //bits 10-15 + UINT32 wr_ptr:10; //bits 0-9 + #else + UINT32 wr_ptr:10; //bits 0-9 + UINT32 reserved1:6; //bits 10-15 + UINT32 rd_ptr:10; //bits 16-25 + UINT32 reserved2:6; //bits 26-31 + #endif + } bits; +} +RXMAC_RXQ_DIAG_t, *PRXMAC_RXQ_DIAG_t; + + +/****************************************************************************** + structure for space availiable reg in rxmac address map. + located at address 0x4094 + *****************************************************************************/ +typedef union _RXMAC_SPACE_AVAIL_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved2:15; //bits 17-31 + UINT32 space_avail_en:1; //bit 16 + UINT32 reserved1:6; //bits 10-15 + UINT32 space_avail:10; //bits 0-9 + #else + UINT32 space_avail:10; //bits 0-9 + UINT32 reserved1:6; //bits 10-15 + UINT32 space_avail_en:1; //bit 16 + UINT32 reserved2:15; //bits 17-31 + #endif + } bits; +} +RXMAC_SPACE_AVAIL_t, *PRXMAC_SPACE_AVAIL_t; + + +/****************************************************************************** + structure for management interface reg in rxmac address map. + located at address 0x4098 + *****************************************************************************/ +typedef union _RXMAC_MIF_CTL_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserve:14; //bits 18-31 + UINT32 drop_pkt_en:1; //bit 17 + UINT32 drop_pkt_mask:17; //bits 0-16 + #else + UINT32 drop_pkt_mask:17; //bits 0-16 + UINT32 drop_pkt_en:1; //bit 17 + UINT32 reserve:14; //bits 18-31 + #endif + } bits; +} +RXMAC_MIF_CTL_t, *PRXMAC_MIF_CTL_t; + + +/****************************************************************************** + structure for Error reg in rxmac address map. + located at address 0x409C + *****************************************************************************/ +typedef union _RXMAC_ERROR_REG_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserve:28; //bits 4-31 + UINT32 mif:1; //bit 3 + UINT32 async:1; //bit 2 + UINT32 pkt_filter:1; //bit 1 + UINT32 mcif:1; //bit 0 + #else + UINT32 mcif:1; //bit 0 + UINT32 pkt_filter:1; //bit 1 + UINT32 async:1; //bit 2 + UINT32 mif:1; //bit 3 + UINT32 reserve:28; //bits 4-31 + #endif + } bits; +} +RXMAC_ERROR_REG_t, *PRXMAC_ERROR_REG_t; + + +/****************************************************************************** + Rx MAC Module of JAGCore Address Mapping + *****************************************************************************/ +typedef struct _RXMAC_t +{ //Location: + RXMAC_CTRL_t ctrl; // 0x4000 + RXMAC_WOL_CTL_CRC0_t crc0; // 0x4004 + RXMAC_WOL_CRC12_t crc12; // 0x4008 + RXMAC_WOL_CRC34_t crc34; // 0x400C + RXMAC_WOL_SA_LO_t sa_lo; // 0x4010 + RXMAC_WOL_SA_HI_t sa_hi; // 0x4014 + RXMAC_WOL_MASK_t mask0_word0; // 0x4018 + RXMAC_WOL_MASK_t mask0_word1; // 0x401C + RXMAC_WOL_MASK_t mask0_word2; // 0x4020 + RXMAC_WOL_MASK_t mask0_word3; // 0x4024 + RXMAC_WOL_MASK_t mask1_word0; // 0x4028 + RXMAC_WOL_MASK_t mask1_word1; // 0x402C + RXMAC_WOL_MASK_t mask1_word2; // 0x4030 + RXMAC_WOL_MASK_t mask1_word3; // 0x4034 + RXMAC_WOL_MASK_t mask2_word0; // 0x4038 + RXMAC_WOL_MASK_t mask2_word1; // 0x403C + RXMAC_WOL_MASK_t mask2_word2; // 0x4040 + RXMAC_WOL_MASK_t mask2_word3; // 0x4044 + RXMAC_WOL_MASK_t mask3_word0; // 0x4048 + RXMAC_WOL_MASK_t mask3_word1; // 0x404C + RXMAC_WOL_MASK_t mask3_word2; // 0x4050 + RXMAC_WOL_MASK_t mask3_word3; // 0x4054 + RXMAC_WOL_MASK_t mask4_word0; // 0x4058 + RXMAC_WOL_MASK_t mask4_word1; // 0x405C + RXMAC_WOL_MASK_t mask4_word2; // 0x4060 + RXMAC_WOL_MASK_t mask4_word3; // 0x4064 + RXMAC_UNI_PF_ADDR1_t uni_pf_addr1; // 0x4068 + RXMAC_UNI_PF_ADDR2_t uni_pf_addr2; // 0x406C + RXMAC_UNI_PF_ADDR3_t uni_pf_addr3; // 0x4070 + RXMAC_MULTI_HASH_t multi_hash1; // 0x4074 + RXMAC_MULTI_HASH_t multi_hash2; // 0x4078 + RXMAC_MULTI_HASH_t multi_hash3; // 0x407C + RXMAC_MULTI_HASH_t multi_hash4; // 0x4080 + RXMAC_PF_CTRL_t pf_ctrl; // 0x4084 + RXMAC_MCIF_CTRL_MAX_SEG_t mcif_ctrl_max_seg; // 0x4088 + RXMAC_MCIF_WATER_MARK_t mcif_water_mark; // 0x408C + RXMAC_RXQ_DIAG_t rxq_diag; // 0x4090 + RXMAC_SPACE_AVAIL_t space_avail; // 0x4094 + + RXMAC_MIF_CTL_t mif_ctrl; // 0x4098 + RXMAC_ERROR_REG_t err_reg; // 0x409C +} +RXMAC_t, *PRXMAC_t; +/*===========================================================================*/ +/*===========================================================================*/ +/*=== END OF TXMAC REGISTER ADDRESS MAP ===*/ +/*===========================================================================*/ +/*===========================================================================*/ + + + +/*===========================================================================*/ +/*===========================================================================*/ +/*=== START OF MAC REGISTER ADDRESS MAP ===*/ +/*===========================================================================*/ +/*===========================================================================*/ +/****************************************************************************** + structure for configuration #1 reg in mac address map. + located at address 0x5000 + *****************************************************************************/ +typedef union _MAC_CFG1_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 soft_reset:1; //bit 31 + UINT32 sim_reset:1; //bit 30 + UINT32 reserved3:10; //bits 20-29 + UINT32 reset_rx_mc:1; //bit 19 + UINT32 reset_tx_mc:1; //bit 18 + UINT32 reset_rx_fun:1; //bit 17 + UINT32 reset_tx_fun:1; //bit 16 + UINT32 reserved2:7; //bits 9-15 + UINT32 loop_back:1; //bit 8 + UINT32 reserved1:2; //bits 6-7 + UINT32 rx_flow:1; //bit 5 + UINT32 tx_flow:1; //bit 4 + UINT32 syncd_rx_en:1; //bit 3 + UINT32 rx_enable:1; //bit 2 + UINT32 syncd_tx_en:1; //bit 1 + UINT32 tx_enable:1; //bit 0 + #else + UINT32 tx_enable:1; //bit 0 + UINT32 syncd_tx_en:1; //bit 1 + UINT32 rx_enable:1; //bit 2 + UINT32 syncd_rx_en:1; //bit 3 + UINT32 tx_flow:1; //bit 4 + UINT32 rx_flow:1; //bit 5 + UINT32 reserved1:2; //bits 6-7 + UINT32 loop_back:1; //bit 8 + UINT32 reserved2:7; //bits 9-15 + UINT32 reset_tx_fun:1; //bit 16 + UINT32 reset_rx_fun:1; //bit 17 + UINT32 reset_tx_mc:1; //bit 18 + UINT32 reset_rx_mc:1; //bit 19 + UINT32 reserved3:10; //bits 20-29 + UINT32 sim_reset:1; //bit 30 + UINT32 soft_reset:1; //bit 31 + #endif + } bits; +} +MAC_CFG1_t, *PMAC_CFG1_t; + + +/****************************************************************************** + structure for configuration #2 reg in mac address map. + located at address 0x5004 + *****************************************************************************/ +typedef union _MAC_CFG2_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved3:16; //bits 16-31 + UINT32 preamble_len:4; //bits 12-15 + UINT32 reserved2:2; //bits 10-11 + UINT32 if_mode:2; //bits 8-9 + UINT32 reserved1:2; //bits 6-7 + UINT32 huge_frame:1; //bit 5 + UINT32 len_check:1; //bit 4 + UINT32 undefined:1; //bit 3 + UINT32 pad_crc:1; //bit 2 + UINT32 crc_enable:1; //bit 1 + UINT32 full_duplex:1; //bit 0 + #else + UINT32 full_duplex:1; //bit 0 + UINT32 crc_enable:1; //bit 1 + UINT32 pad_crc:1; //bit 2 + UINT32 undefined:1; //bit 3 + UINT32 len_check:1; //bit 4 + UINT32 huge_frame:1; //bit 5 + UINT32 reserved1:2; //bits 6-7 + UINT32 if_mode:2; //bits 8-9 + UINT32 reserved2:2; //bits 10-11 + UINT32 preamble_len:4; //bits 12-15 + UINT32 reserved3:16; //bits 16-31 + #endif + } bits; +} +MAC_CFG2_t, *PMAC_CFG2_t; + + +/****************************************************************************** + structure for Interpacket gap reg in mac address map. + located at address 0x5008 + *****************************************************************************/ +typedef union _MAC_IPG_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved:1; //bit 31 + UINT32 non_B2B_ipg_1:7; //bits 24-30 + UINT32 undefined2:1; //bit 23 + UINT32 non_B2B_ipg_2:7; //bits 16-22 + UINT32 min_ifg_enforce:8; //bits 8-15 + UINT32 undefined1:1; //bit 7 + UINT32 B2B_ipg:7; //bits 0-6 + #else + UINT32 B2B_ipg:7; //bits 0-6 + UINT32 undefined1:1; //bit 7 + UINT32 min_ifg_enforce:8; //bits 8-15 + UINT32 non_B2B_ipg_2:7; //bits 16-22 + UINT32 undefined2:1; //bit 23 + UINT32 non_B2B_ipg_1:7; //bits 24-30 + UINT32 reserved:1; //bit 31 + #endif + } bits; +} +MAC_IPG_t, *PMAC_IPG_t; + + +/****************************************************************************** + structure for half duplex reg in mac address map. + located at address 0x500C + *****************************************************************************/ +typedef union _MAC_HFDP_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved2:8; //bits 24-31 + UINT32 alt_beb_trunc:4; //bits 23-20 + UINT32 alt_beb_enable:1; //bit 19 + UINT32 bp_no_backoff:1; //bit 18 + UINT32 no_backoff:1; //bit 17 + UINT32 excess_defer:1; //bit 16 + UINT32 rexmit_max:4; //bits 12-15 + UINT32 reserved1:2; //bits 10-11 + UINT32 coll_window:10; //bits 0-9 + #else + UINT32 coll_window:10; //bits 0-9 + UINT32 reserved1:2; //bits 10-11 + UINT32 rexmit_max:4; //bits 12-15 + UINT32 excess_defer:1; //bit 16 + UINT32 no_backoff:1; //bit 17 + UINT32 bp_no_backoff:1; //bit 18 + UINT32 alt_beb_enable:1; //bit 19 + UINT32 alt_beb_trunc:4; //bits 23-20 + UINT32 reserved2:8; //bits 24-31 + #endif + } bits; +} +MAC_HFDP_t, *PMAC_HFDP_t; + + +/****************************************************************************** + structure for Maximum Frame Length reg in mac address map. + located at address 0x5010 + *****************************************************************************/ +typedef union _MAC_MAX_FM_LEN_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved:16; //bits 16-31 + UINT32 max_len:16; //bits 0-15 + #else + UINT32 max_len:16; //bits 0-15 + UINT32 reserved:16; //bits 16-31 + #endif + } bits; +} +MAC_MAX_FM_LEN_t, *PMAC_MAX_FM_LEN_t; + + +/****************************************************************************** + structure for Reserve 1 reg in mac address map. + located at address 0x5014 - 0x5018 + *****************************************************************************/ +typedef struct _MAC_RSV_t +{ + UINT32 value; //bits 0-31 +} +MAC_RSV_t, *PMAC_RSV_t; + + +/****************************************************************************** + structure for Test reg in mac address map. + located at address 0x501C + *****************************************************************************/ +typedef union _MAC_TEST_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:29; //bits 3-31 + UINT32 mac_test:3; //bits 0-2 + #else + UINT32 mac_test:3; //bits 0-2 + UINT32 unused:29; //bits 3-31 + #endif + } bits; +} +MAC_TEST_t, *PMAC_TEST_t; + + +/****************************************************************************** + structure for MII Management Configuration reg in mac address map. + located at address 0x5020 + *****************************************************************************/ +typedef union _MII_MGMT_CFG_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reset_mii_mgmt:1; //bit 31 + UINT32 reserved:25; //bits 6-30 + UINT32 scan_auto_incremt:1; //bit 5 + UINT32 preamble_suppress:1; //bit 4 + UINT32 undefined:1; //bit 3 + UINT32 mgmt_clk_reset:3; //bits 0-2 + #else + UINT32 mgmt_clk_reset:3; //bits 0-2 + UINT32 undefined:1; //bit 3 + UINT32 preamble_suppress:1; //bit 4 + UINT32 scan_auto_incremt:1; //bit 5 + UINT32 reserved:25; //bits 6-30 + UINT32 reset_mii_mgmt:1; //bit 31 + #endif + } bits; +} +MII_MGMT_CFG_t, *PMII_MGMT_CFG_t; + + +/****************************************************************************** + structure for MII Management Command reg in mac address map. + located at address 0x5024 + *****************************************************************************/ +typedef union _MII_MGMT_CMD_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved:30; //bits 2-31 + UINT32 scan_cycle:1; //bit 1 + UINT32 read_cycle:1; //bit 0 + #else + UINT32 read_cycle:1; //bit 0 + UINT32 scan_cycle:1; //bit 1 + UINT32 reserved:30; //bits 2-31 + #endif + } bits; +} +MII_MGMT_CMD_t, *PMII_MGMT_CMD_t; + + +/****************************************************************************** + structure for MII Management Address reg in mac address map. + located at address 0x5028 + *****************************************************************************/ +typedef union _MII_MGMT_ADDR_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved2:19; //bit 13-31 + UINT32 phy_addr:5; //bits 8-12 + UINT32 reserved1:3; //bits 5-7 + UINT32 reg_addr:5; //bits 0-4 + #else + UINT32 reg_addr:5; //bits 0-4 + UINT32 reserved1:3; //bits 5-7 + UINT32 phy_addr:5; //bits 8-12 + UINT32 reserved2:19; //bit 13-31 + #endif + } bits; +} +MII_MGMT_ADDR_t, *PMII_MGMT_ADDR_t; + + +/****************************************************************************** + structure for MII Management Control reg in mac address map. + located at address 0x502C + *****************************************************************************/ +typedef union _MII_MGMT_CTRL_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved:16; //bits 16-31 + UINT32 phy_ctrl:16; //bits 0-15 + #else + UINT32 phy_ctrl:16; //bits 0-15 + UINT32 reserved:16; //bits 16-31 + #endif + } bits; +} +MII_MGMT_CTRL_t, *PMII_MGMT_CTRL_t; + + +/****************************************************************************** + structure for MII Management Status reg in mac address map. + located at address 0x5030 + *****************************************************************************/ +typedef union _MII_MGMT_STAT_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved:16; //bits 16-31 + UINT32 phy_stat:16; //bits 0-15 + #else + UINT32 phy_stat:16; //bits 0-15 + UINT32 reserved:16; //bits 16-31 + #endif + } bits; +} +MII_MGMT_STAT_t, *PMII_MGMT_STAT_t; + + +/****************************************************************************** + structure for MII Management Indicators reg in mac address map. + located at address 0x5034 + *****************************************************************************/ +typedef union _MII_MGMT_INDICATOR_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved:29; //bits 3-31 + UINT32 not_valid:1; //bit 2 + UINT32 scanning:1; //bit 1 + UINT32 busy:1; //bit 0 + #else + UINT32 busy:1; //bit 0 + UINT32 scanning:1; //bit 1 + UINT32 not_valid:1; //bit 2 + UINT32 reserved:29; //bits 3-31 + #endif + } bits; +} +MII_MGMT_INDICATOR_t, *PMII_MGMT_INDICATOR_t; + + +/****************************************************************************** + structure for Interface Control reg in mac address map. + located at address 0x5038 + *****************************************************************************/ +typedef union _MAC_IF_CTRL_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reset_if_module:1; //bit 31 + UINT32 reserved4:3; //bit 28-30 + UINT32 tbi_mode:1; //bit 27 + UINT32 ghd_mode:1; //bit 26 + UINT32 lhd_mode:1; //bit 25 + UINT32 phy_mode:1; //bit 24 + UINT32 reset_per_mii:1; //bit 23 + UINT32 reserved3:6; //bits 17-22 + UINT32 speed:1; //bit 16 + UINT32 reset_pe100x:1; //bit 15 + UINT32 reserved2:4; //bits 11-14 + UINT32 force_quiet:1; //bit 10 + UINT32 no_cipher:1; //bit 9 + UINT32 disable_link_fail:1; //bit 8 + UINT32 reset_gpsi:1; //bit 7 + UINT32 reserved1:6; //bits 1-6 + UINT32 enab_jab_protect:1; //bit 0 + #else + UINT32 enab_jab_protect:1; //bit 0 + UINT32 reserved1:6; //bits 1-6 + UINT32 reset_gpsi:1; //bit 7 + UINT32 disable_link_fail:1; //bit 8 + UINT32 no_cipher:1; //bit 9 + UINT32 force_quiet:1; //bit 10 + UINT32 reserved2:4; //bits 11-14 + UINT32 reset_pe100x:1; //bit 15 + UINT32 speed:1; //bit 16 + UINT32 reserved3:6; //bits 17-22 + UINT32 reset_per_mii:1; //bit 23 + UINT32 phy_mode:1; //bit 24 + UINT32 lhd_mode:1; //bit 25 + UINT32 ghd_mode:1; //bit 26 + UINT32 tbi_mode:1; //bit 27 + UINT32 reserved4:3; //bit 28-30 + UINT32 reset_if_module:1; //bit 31 + #endif + } bits; +} +MAC_IF_CTRL_t, *PMAC_IF_CTRL_t; + + +/****************************************************************************** + structure for Interface Status reg in mac address map. + located at address 0x503C + *****************************************************************************/ +typedef union _MAC_IF_STAT_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved:22; //bits 10-31 + UINT32 excess_defer:1; //bit 9 + UINT32 clash:1; //bit 8 + UINT32 phy_jabber:1; //bit 7 + UINT32 phy_link_ok:1; //bit 6 + UINT32 phy_full_duplex:1; //bit 5 + UINT32 phy_speed:1; //bit 4 + UINT32 pe100x_link_fail:1; //bit 3 + UINT32 pe10t_loss_carrie:1; //bit 2 + UINT32 pe10t_sqe_error:1; //bit 1 + UINT32 pe10t_jabber:1; //bit 0 + #else + UINT32 pe10t_jabber:1; //bit 0 + UINT32 pe10t_sqe_error:1; //bit 1 + UINT32 pe10t_loss_carrie:1; //bit 2 + UINT32 pe100x_link_fail:1; //bit 3 + UINT32 phy_speed:1; //bit 4 + UINT32 phy_full_duplex:1; //bit 5 + UINT32 phy_link_ok:1; //bit 6 + UINT32 phy_jabber:1; //bit 7 + UINT32 clash:1; //bit 8 + UINT32 excess_defer:1; //bit 9 + UINT32 reserved:22; //bits 10-31 + #endif + } bits; +} +MAC_IF_STAT_t, *PMAC_IF_STAT_t; + + +/****************************************************************************** + structure for Mac Station Address, Part 1 reg in mac address map. + located at address 0x5040 + *****************************************************************************/ +typedef union _MAC_STATION_ADDR1_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 Octet6:8; //bits 24-31 + UINT32 Octet5:8; //bits 16-23 + UINT32 Octet4:8; //bits 8-15 + UINT32 Octet3:8; //bits 0-7 + #else + UINT32 Octet3:8; //bits 0-7 + UINT32 Octet4:8; //bits 8-15 + UINT32 Octet5:8; //bits 16-23 + UINT32 Octet6:8; //bits 24-31 + #endif + } bits; +} +MAC_STATION_ADDR1_t, *PMAC_STATION_ADDR1_t; + + +/****************************************************************************** + structure for Mac Station Address, Part 2 reg in mac address map. + located at address 0x5044 + *****************************************************************************/ +typedef union _MAC_STATION_ADDR2_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 Octet2:8; //bits 24-31 + UINT32 Octet1:8; //bits 16-23 + UINT32 reserved:16; //bits 0-15 + #else + UINT32 reserved:16; //bit 0-15 + UINT32 Octet1:8; //bits 16-23 + UINT32 Octet2:8; //bits 24-31 + #endif + } bits; +} +MAC_STATION_ADDR2_t, *PMAC_STATION_ADDR2_t; + + +/****************************************************************************** + MAC Module of JAGCore Address Mapping + *****************************************************************************/ +typedef struct _MAC_t +{ //Location: + MAC_CFG1_t cfg1; // 0x5000 + MAC_CFG2_t cfg2; // 0x5004 + MAC_IPG_t ipg; // 0x5008 + MAC_HFDP_t hfdp; // 0x500C + MAC_MAX_FM_LEN_t max_fm_len; // 0x5010 + MAC_RSV_t rsv1; // 0x5014 + MAC_RSV_t rsv2; // 0x5018 + MAC_TEST_t mac_test; // 0x501C + MII_MGMT_CFG_t mii_mgmt_cfg; // 0x5020 + MII_MGMT_CMD_t mii_mgmt_cmd; // 0x5024 + MII_MGMT_ADDR_t mii_mgmt_addr; // 0x5028 + MII_MGMT_CTRL_t mii_mgmt_ctrl; // 0x502C + MII_MGMT_STAT_t mii_mgmt_stat; // 0x5030 + MII_MGMT_INDICATOR_t mii_mgmt_indicator; // 0x5034 + MAC_IF_CTRL_t if_ctrl; // 0x5038 + MAC_IF_STAT_t if_stat; // 0x503C + MAC_STATION_ADDR1_t station_addr_1; // 0x5040 + MAC_STATION_ADDR2_t station_addr_2; // 0x5044 +} +MAC_t, *PMAC_t; +/*===========================================================================*/ +/*===========================================================================*/ +/*=== END OF MAC REGISTER ADDRESS MAP ===*/ +/*===========================================================================*/ +/*===========================================================================*/ + + + +/*===========================================================================*/ +/*===========================================================================*/ +/*=== START OF MAC STAT REGISTER ADDRESS MAP ===*/ +/*===========================================================================*/ +/*===========================================================================*/ +/****************************************************************************** + structure for Carry Register One and it's Mask Register reg located in mac + stat address map address 0x6130 and 0x6138. + *****************************************************************************/ +typedef union _MAC_STAT_REG_1_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 tr64:1; //bit 31 + UINT32 tr127:1; //bit 30 + UINT32 tr255:1; //bit 29 + UINT32 tr511:1; //bit 28 + UINT32 tr1k:1; //bit 27 + UINT32 trmax:1; //bit 26 + UINT32 trmgv:1; //bit 25 + UINT32 unused:8; //bits 17-24 + UINT32 rbyt:1; //bit 16 + UINT32 rpkt:1; //bit 15 + UINT32 rfcs:1; //bit 14 + UINT32 rmca:1; //bit 13 + UINT32 rbca:1; //bit 12 + UINT32 rxcf:1; //bit 11 + UINT32 rxpf:1; //bit 10 + UINT32 rxuo:1; //bit 9 + UINT32 raln:1; //bit 8 + UINT32 rflr:1; //bit 7 + UINT32 rcde:1; //bit 6 + UINT32 rcse:1; //bit 5 + UINT32 rund:1; //bit 4 + UINT32 rovr:1; //bit 3 + UINT32 rfrg:1; //bit 2 + UINT32 rjbr:1; //bit 1 + UINT32 rdrp:1; //bit 0 + #else + UINT32 rdrp:1; //bit 0 + UINT32 rjbr:1; //bit 1 + UINT32 rfrg:1; //bit 2 + UINT32 rovr:1; //bit 3 + UINT32 rund:1; //bit 4 + UINT32 rcse:1; //bit 5 + UINT32 rcde:1; //bit 6 + UINT32 rflr:1; //bit 7 + UINT32 raln:1; //bit 8 + UINT32 rxuo:1; //bit 9 + UINT32 rxpf:1; //bit 10 + UINT32 rxcf:1; //bit 11 + UINT32 rbca:1; //bit 12 + UINT32 rmca:1; //bit 13 + UINT32 rfcs:1; //bit 14 + UINT32 rpkt:1; //bit 15 + UINT32 rbyt:1; //bit 16 + UINT32 unused:8; //bits 17-24 + UINT32 trmgv:1; //bit 25 + UINT32 trmax:1; //bit 26 + UINT32 tr1k:1; //bit 27 + UINT32 tr511:1; //bit 28 + UINT32 tr255:1; //bit 29 + UINT32 tr127:1; //bit 30 + UINT32 tr64:1; //bit 31 + #endif + } bits; +} +MAC_STAT_REG_1_t, *PMAC_STAT_REG_1_t; + + +/****************************************************************************** + structure for Carry Register Two Mask Register reg in mac stat address map. + located at address 0x613C + *****************************************************************************/ +typedef union _MAC_STAT_REG_2_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 unused:12; //bit 20-31 + UINT32 tjbr:1; //bit 19 + UINT32 tfcs:1; //bit 18 + UINT32 txcf:1; //bit 17 + UINT32 tovr:1; //bit 16 + UINT32 tund:1; //bit 15 + UINT32 tfrg:1; //bit 14 + UINT32 tbyt:1; //bit 13 + UINT32 tpkt:1; //bit 12 + UINT32 tmca:1; //bit 11 + UINT32 tbca:1; //bit 10 + UINT32 txpf:1; //bit 9 + UINT32 tdfr:1; //bit 8 + UINT32 tedf:1; //bit 7 + UINT32 tscl:1; //bit 6 + UINT32 tmcl:1; //bit 5 + UINT32 tlcl:1; //bit 4 + UINT32 txcl:1; //bit 3 + UINT32 tncl:1; //bit 2 + UINT32 tpfh:1; //bit 1 + UINT32 tdrp:1; //bit 0 + #else + UINT32 tdrp:1; //bit 0 + UINT32 tpfh:1; //bit 1 + UINT32 tncl:1; //bit 2 + UINT32 txcl:1; //bit 3 + UINT32 tlcl:1; //bit 4 + UINT32 tmcl:1; //bit 5 + UINT32 tscl:1; //bit 6 + UINT32 tedf:1; //bit 7 + UINT32 tdfr:1; //bit 8 + UINT32 txpf:1; //bit 9 + UINT32 tbca:1; //bit 10 + UINT32 tmca:1; //bit 11 + UINT32 tpkt:1; //bit 12 + UINT32 tbyt:1; //bit 13 + UINT32 tfrg:1; //bit 14 + UINT32 tund:1; //bit 15 + UINT32 tovr:1; //bit 16 + UINT32 txcf:1; //bit 17 + UINT32 tfcs:1; //bit 18 + UINT32 tjbr:1; //bit 19 + UINT32 unused:12; //bit 20-31 + #endif + } bits; +} +MAC_STAT_REG_2_t, *PMAC_STAT_REG_2_t; + + + + +/****************************************************************************** + MAC STATS Module of JAGCore Address Mapping + *****************************************************************************/ +typedef struct _MAC_STAT_t +{ //Location: + UINT32 pad[32]; // 0x6000 - 607C + + //Tx/Rx 0-64 Byte Frame Counter + UINT32 TR64; // 0x6080 + + //Tx/Rx 65-127 Byte Frame Counter + UINT32 TR127; // 0x6084 + + //Tx/Rx 128-255 Byte Frame Counter + UINT32 TR255; // 0x6088 + + //Tx/Rx 256-511 Byte Frame Counter + UINT32 TR511; // 0x608C + + //Tx/Rx 512-1023 Byte Frame Counter + UINT32 TR1K; // 0x6090 + + //Tx/Rx 1024-1518 Byte Frame Counter + UINT32 TRMax; // 0x6094 + + //Tx/Rx 1519-1522 Byte Good VLAN Frame Count + UINT32 TRMgv; // 0x6098 + + //Rx Byte Counter + UINT32 RByt; // 0x609C + + //Rx Packet Counter + UINT32 RPkt; // 0x60A0 + + //Rx FCS Error Counter + UINT32 RFcs; // 0x60A4 + + //Rx Multicast Packet Counter + UINT32 RMca; // 0x60A8 + + //Rx Broadcast Packet Counter + UINT32 RBca; // 0x60AC + + //Rx Control Frame Packet Counter + UINT32 RxCf; // 0x60B0 + + //Rx Pause Frame Packet Counter + UINT32 RxPf; // 0x60B4 + + //Rx Unknown OP Code Counter + UINT32 RxUo; // 0x60B8 + + //Rx Alignment Error Counter + UINT32 RAln; // 0x60BC + + //Rx Frame Length Error Counter + UINT32 RFlr; // 0x60C0 + + //Rx Code Error Counter + UINT32 RCde; // 0x60C4 + + //Rx Carrier Sense Error Counter + UINT32 RCse; // 0x60C8 + + //Rx Undersize Packet Counter + UINT32 RUnd; // 0x60CC + + //Rx Oversize Packet Counter + UINT32 ROvr; // 0x60D0 + + //Rx Fragment Counter + UINT32 RFrg; // 0x60D4 + + //Rx Jabber Counter + UINT32 RJbr; // 0x60D8 + + //Rx Drop + UINT32 RDrp; // 0x60DC + + //Tx Byte Counter + UINT32 TByt; // 0x60E0 + + //Tx Packet Counter + UINT32 TPkt; // 0x60E4 + + //Tx Multicast Packet Counter + UINT32 TMca; // 0x60E8 + + //Tx Broadcast Packet Counter + UINT32 TBca; // 0x60EC + + //Tx Pause Control Frame Counter + UINT32 TxPf; // 0x60F0 + + //Tx Deferral Packet Counter + UINT32 TDfr; // 0x60F4 + + //Tx Excessive Deferral Packet Counter + UINT32 TEdf; // 0x60F8 + + //Tx Single Collision Packet Counter + UINT32 TScl; // 0x60FC + + //Tx Multiple Collision Packet Counter + UINT32 TMcl; // 0x6100 + + //Tx Late Collision Packet Counter + UINT32 TLcl; // 0x6104 + + //Tx Excessive Collision Packet Counter + UINT32 TXcl; // 0x6108 + + //Tx Total Collision Packet Counter + UINT32 TNcl; // 0x610C + + //Tx Pause Frame Honored Counter + UINT32 TPfh; // 0x6110 + + //Tx Drop Frame Counter + UINT32 TDrp; // 0x6114 + + //Tx Jabber Frame Counter + UINT32 TJbr; // 0x6118 + + //Tx FCS Error Counter + UINT32 TFcs; // 0x611C + + //Tx Control Frame Counter + UINT32 TxCf; // 0x6120 + + //Tx Oversize Frame Counter + UINT32 TOvr; // 0x6124 + + //Tx Undersize Frame Counter + UINT32 TUnd; // 0x6128 + + //Tx Fragments Frame Counter + UINT32 TFrg; // 0x612C + + //Carry Register One Register + MAC_STAT_REG_1_t Carry1; // 0x6130 + + //Carry Register Two Register + MAC_STAT_REG_2_t Carry2; // 0x6134 + + //Carry Register One Mask Register + MAC_STAT_REG_1_t Carry1M; // 0x6138 + + //Carry Register Two Mask Register + MAC_STAT_REG_2_t Carry2M; // 0x613C +} +MAC_STAT_t, *PMAC_STAT_t; +/*===========================================================================*/ +/*===========================================================================*/ +/*=== END OF MAC STAT REGISTER ADDRESS MAP ===*/ +/*===========================================================================*/ +/*===========================================================================*/ + + + +/*===========================================================================*/ +/*===========================================================================*/ +/*=== START OF MMC REGISTER ADDRESS MAP ===*/ +/*===========================================================================*/ +/*===========================================================================*/ +/****************************************************************************** + structure for Main Memory Controller Control reg in mmc address map. + located at address 0x7000 + *****************************************************************************/ +typedef union _MMC_CTRL_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 reserved:25; //bits 7-31 + UINT32 force_ce:1; //bit 6 + UINT32 rxdma_disable:1; //bit 5 + UINT32 txdma_disable:1; //bit 4 + UINT32 txmac_disable:1; //bit 3 + UINT32 rxmac_disable:1; //bit 2 + UINT32 arb_disable:1; //bit 1 + UINT32 mmc_enable:1; //bit 0 + #else + UINT32 mmc_enable:1; //bit 0 + UINT32 arb_disable:1; //bit 1 + UINT32 rxmac_disable:1; //bit 2 + UINT32 txmac_disable:1; //bit 3 + UINT32 txdma_disable:1; //bit 4 + UINT32 rxdma_disable:1; //bit 5 + UINT32 force_ce:1; //bit 6 + UINT32 reserved:25; //bits 7-31 + #endif + } bits; +} +MMC_CTRL_t, *PMMC_CTRL_t; + + +/****************************************************************************** + structure for Main Memory Controller Host Memory Access Address reg in mmc + address map. Located at address 0x7004 + *****************************************************************************/ +typedef union _MMC_SRAM_ACCESS_t +{ + UINT32 value; + struct + { + #ifdef _BIT_FIELDS_HTOL + UINT32 byte_enable:16; //bits 16-31 + UINT32 reserved2:2; //bits 14-15 + UINT32 req_addr:10; //bits 4-13 + UINT32 reserved1:1; //bit 3 + UINT32 is_ctrl_word:1; //bit 2 + UINT32 wr_access:1; //bit 1 + UINT32 req_access:1; //bit 0 + #else + UINT32 req_access:1; //bit 0 + UINT32 wr_access:1; //bit 1 + UINT32 is_ctrl_word:1; //bit 2 + UINT32 reserved1:1; //bit 3 + UINT32 req_addr:10; //bits 4-13 + UINT32 reserved2:2; //bits 14-15 + UINT32 byte_enable:16; //bits 16-31 + #endif + } bits; +} +MMC_SRAM_ACCESS_t, *PMMC_SRAM_ACCESS_t; + + +/****************************************************************************** + structure for Main Memory Controller Host Memory Access Data reg in mmc + address map. Located at address 0x7008 - 0x7014 + *****************************************************************************/ +typedef struct _MMC_SRAM_WORD_t +{ + UINT32 data; //bits 0-31 +} MMC_SRAM_WORD_t, *PMMC_SRAM_WORD_t; + + +/****************************************************************************** + Memory Control Module of JAGCore Address Mapping + *****************************************************************************/ +typedef struct _MMC_t +{ //Location: + MMC_CTRL_t mmc_ctrl; // 0x7000 + MMC_SRAM_ACCESS_t sram_access; // 0x7004 + MMC_SRAM_WORD_t sram_word1; // 0x7008 + MMC_SRAM_WORD_t sram_word2; // 0x700C + MMC_SRAM_WORD_t sram_word3; // 0x7010 + MMC_SRAM_WORD_t sram_word4; // 0x7014 +} +MMC_t, *PMMC_t; +/*===========================================================================*/ +/*===========================================================================*/ +/*=== END OF MMC REGISTER ADDRESS MAP ===*/ +/*===========================================================================*/ +/*===========================================================================*/ + + + +/*===========================================================================*/ +/*===========================================================================*/ +/*=== START OF EXP ROM REGISTER ADDRESS MAP ===*/ +/*===========================================================================*/ +/*===========================================================================*/ +/****************************************************************************** + Expansion ROM Module of JAGCore Address Mapping + *****************************************************************************/ + +/* Take this out until it is not empty */ +#if 0 +typedef struct _EXP_ROM_t +{ + +} +EXP_ROM_t, *PEXP_ROM_t; +#endif +/*===========================================================================*/ +/*===========================================================================*/ +/*=== END OF EXP ROM REGISTER ADDRESS MAP ===*/ +/*===========================================================================*/ +/*===========================================================================*/ + + + + +/****************************************************************************** + JAGCore Address Mapping + *****************************************************************************/ +typedef struct _ADDRESS_MAP_t +{ + GLOBAL_t global; + UCHAR unused_global[4096 - sizeof (GLOBAL_t)]; //unused section of global address map + TXDMA_t txdma; + UCHAR unused_txdma[4096 - sizeof (TXDMA_t)]; //unused section of txdma address map + RXDMA_t rxdma; + UCHAR unused_rxdma[4096 - sizeof (RXDMA_t)]; //unused section of rxdma address map + TXMAC_t txmac; + UCHAR unused_txmac[4096 - sizeof (TXMAC_t)]; //unused section of txmac address map + RXMAC_t rxmac; + UCHAR unused_rxmac[4096 - sizeof (RXMAC_t)]; //unused section of rxmac address map + MAC_t mac; + UCHAR unused_mac[4096 - sizeof (MAC_t)]; //unused section of mac address map + MAC_STAT_t macStat; + UCHAR unused_mac_stat[4096 - sizeof (MAC_STAT_t)]; //unused section of mac stat address map + MMC_t mmc; + UCHAR unused_mmc[4096 - sizeof (MMC_t)]; //unused section of mmc address map + UCHAR unused_[1015808]; //unused section of address map + +/* Take this out until it is not empty */ +#if 0 + EXP_ROM_t exp_rom; +#endif + + UCHAR unused_exp_rom[4096]; //MGS-size TBD + UCHAR unused__[524288]; //unused section of address map +} +ADDRESS_MAP_t, *PADDRESS_MAP_t; +/*===========================================================================*/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _ET1310_ADDRESS_MAP_H_ */ --- linux-2.6.27.orig/ubuntu/et131x/ET1310_phy.c +++ linux-2.6.27/ubuntu/et131x/ET1310_phy.c @@ -0,0 +1,2728 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * ET1310_phy.c - Routines for configuring and accessing the PHY + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2006/01/20 21:29:44 $ + $Revision: 1.13 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +/****************************************************************************** + Includes + *****************************************************************************/ +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include +#include +#include +#include +#include + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "ET1310_phy.h" +#include "ET1310_pm.h" +#include "ET1310_jagcore.h" + +#include "et131x_supp.h" +#include "et131x_adapter.h" +#include "et131x_netdev.h" +#include "et131x_initpci.h" + +#include "ET1310_address_map.h" +#include "ET1310_jagcore.h" +#include "ET1310_tx.h" +#include "ET1310_rx.h" +#include "ET1310_mac.h" + + + + +/****************************************************************************** + Data for debugging facilities + *****************************************************************************/ +#ifdef ET131X_DBG +extern dbg_info_t *et131x_dbginfo; +#endif /* ET131X_DBG */ + + + + +/****************************************************************************** + Prototypes for functions with local scope + *****************************************************************************/ +int et131x_xcvr_init( ET131X_ADAPTER *adapter ); + + + + +/****************************************************************************** + ROUTINE : MiRead + ****************************************************************************** + + DESCRIPTION : Used to read from the PHY through the MII Interface on + the MAC. + + PARAMETERS : adapter - pointer to our private adapter structure + xcvrAddr - the address of the transciever + xcvrReg - the register to read + value - pointer to a 16-bit value in which the value + will be stored. + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int MiRead( ET131X_ADAPTER *adapter, UINT8 xcvrAddr, UINT8 xcvrReg, UINT16 *value ) +{ + int status = 0; + UINT32 delay; + MII_MGMT_ADDR_t miiAddr; + MII_MGMT_CMD_t miiCmd; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "MiRead" ); + + + /************************************************************************** + Save a local copy of the registers we are dealing with so we can set + them back + *************************************************************************/ + miiAddr.value = adapter->CSRAddress->mac.mii_mgmt_addr.value; + miiCmd.value = adapter->CSRAddress->mac.mii_mgmt_cmd.value; + + + /************************************************************************** + Stop the current operation + *************************************************************************/ + adapter->CSRAddress->mac.mii_mgmt_cmd.value = 0x0; + + + /************************************************************************** + Set up the register we need to read from on the correct PHY + *************************************************************************/ + { + MII_MGMT_ADDR_t mii_mgmt_addr = {0}; + + mii_mgmt_addr.bits.phy_addr = xcvrAddr; + mii_mgmt_addr.bits.reg_addr = xcvrReg; + + adapter->CSRAddress->mac.mii_mgmt_addr = mii_mgmt_addr; + } + + + /************************************************************************** + Kick the read cycle off + *************************************************************************/ + delay = 0; + + adapter->CSRAddress->mac.mii_mgmt_cmd.value = 0x1; + + do + { + udelay( 50 ); + delay++; + } while(( adapter->CSRAddress->mac.mii_mgmt_indicator.bits.not_valid || + adapter->CSRAddress->mac.mii_mgmt_indicator.bits.busy ) && + ( delay < 50 )); + + + /************************************************************************** + If we hit the max delay, we could not read the register + *************************************************************************/ + if( delay >= 50 ) + { + DBG_WARNING( et131x_dbginfo, "xcvrReg 0x%08x could not be read\n", xcvrReg ); + DBG_WARNING( et131x_dbginfo, "status is 0x%08x\n", + adapter->CSRAddress->mac.mii_mgmt_indicator.value ); + + status = -EIO; + } + + + /************************************************************************** + If we hit here we were able to read the register and we need to return + the value to the caller + *************************************************************************/ + *value = (UINT16)adapter->CSRAddress->mac.mii_mgmt_stat.bits.phy_stat; + + + /************************************************************************** + Stop the read operation + *************************************************************************/ + adapter->CSRAddress->mac.mii_mgmt_cmd.value = 0x0; + + DBG_VERBOSE( et131x_dbginfo, " xcvr_addr = 0x%02x, " + "xcvr_reg = 0x%02x, " + "value = 0x%04x.\n", + xcvrAddr, xcvrReg, *value ); + + + /************************************************************************** + set the registers we touched back to the state at which we entered + this function + *************************************************************************/ + adapter->CSRAddress->mac.mii_mgmt_addr.value = miiAddr.value; + adapter->CSRAddress->mac.mii_mgmt_cmd.value = miiCmd.value; + + + return status; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : MiWrite + ****************************************************************************** + + DESCRIPTION : Used to write to a PHY register through the MII + interface of the MAC. Updated for the ET1310. + + PARAMETERS : adapter - pointer to our private adapter structure + xcvrAddr - the address of the transciever + xcvrReg - the register to read + value - 16-bit value to write + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int MiWrite( ET131X_ADAPTER *adapter, UINT8 xcvrAddr, UINT8 xcvrReg, UINT16 value ) +{ + int status = 0; + UINT32 delay; + MII_MGMT_ADDR_t miiAddr; + MII_MGMT_CMD_t miiCmd; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "MiWrite" ); + + + /************************************************************************** + Save a local copy of the registers we are dealing with so we can set + them back + *************************************************************************/ + miiAddr.value = adapter->CSRAddress->mac.mii_mgmt_addr.value; + miiCmd.value = adapter->CSRAddress->mac.mii_mgmt_cmd.value; + + + /************************************************************************** + Stop the current operation + *************************************************************************/ + adapter->CSRAddress->mac.mii_mgmt_cmd.value = 0x0; + + + /************************************************************************** + Set up the register we need to write to on the correct PHY + *************************************************************************/ + { + MII_MGMT_ADDR_t mii_mgmt_addr = {0}; + + mii_mgmt_addr.bits.phy_addr = xcvrAddr; + mii_mgmt_addr.bits.reg_addr = xcvrReg; + + adapter->CSRAddress->mac.mii_mgmt_addr = mii_mgmt_addr; + } + + + /************************************************************************** + Add the value to write to the registers to the mac + *************************************************************************/ + adapter->CSRAddress->mac.mii_mgmt_ctrl.value = value; + delay = 0; + + do + { + udelay( 50 ); + delay++; + } while(( adapter->CSRAddress->mac.mii_mgmt_indicator.bits.busy ) && + ( delay < 100 )); + + + /************************************************************************** + If we hit the max delay, we could not write the register + *************************************************************************/ + if( delay == 100 ) + { + UINT16 TempValue; + + DBG_WARNING( et131x_dbginfo, "xcvrReg 0x%08x could not be written", + xcvrReg ); + DBG_WARNING( et131x_dbginfo, "status is 0x%08x\n", + adapter->CSRAddress->mac.mii_mgmt_indicator.value ); + DBG_WARNING( et131x_dbginfo, "command is 0x%08x\n", + adapter->CSRAddress->mac.mii_mgmt_cmd.value ); + + MiRead( adapter, xcvrAddr, xcvrReg, &TempValue ); + + status = -EIO; + } + + + /************************************************************************** + Stop the write operation + *************************************************************************/ + adapter->CSRAddress->mac.mii_mgmt_cmd.value = 0x0; + + + /************************************************************************** + set the registers we touched back to the state at which we entered + this function + *************************************************************************/ + adapter->CSRAddress->mac.mii_mgmt_addr.value = miiAddr.value; + adapter->CSRAddress->mac.mii_mgmt_cmd.value = miiCmd.value; + + + DBG_VERBOSE( et131x_dbginfo, " xcvr_addr = 0x%02x, " + "xcvr_reg = 0x%02x, " + "value = 0x%04x.\n", + xcvrAddr, xcvrReg, value ); + + return status; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_xcvr_find + ****************************************************************************** + + DESCRIPTION : Used to find the PHY ID + + PARAMETERS : adapter - pointer to our private adapter structure + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_xcvr_find( ET131X_ADAPTER *adapter ) +{ + int status = -ENODEV; + UINT8 xcvr_addr; + MI_IDR1_t idr1; + MI_IDR2_t idr2; + UINT32 xcvr_id; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_xcvr_find" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + We need to get xcvr id and address we just get the first one + *************************************************************************/ + for( xcvr_addr = 0; xcvr_addr < 32; xcvr_addr++ ) + { + /********************************************************************** + Read the ID from the PHY + *********************************************************************/ + MiRead( adapter, xcvr_addr, (UINT8)FIELD_OFFSET(MI_REGS_t, idr1), &idr1.value ); + MiRead( adapter, xcvr_addr, (UINT8)FIELD_OFFSET(MI_REGS_t, idr2), &idr2.value ); + + xcvr_id = (UINT32)(( idr1.value << 16 ) | idr2.value ); + + if(( idr1.value != 0) && ( idr1.value != 0xffff )) + { + DBG_TRACE( et131x_dbginfo, "Xcvr addr: 0x%02x\tXcvr_id: 0x%08x\n", + xcvr_addr, xcvr_id ); + + adapter->Stats.xcvr_id = xcvr_id; + adapter->Stats.xcvr_addr = (UINT32)xcvr_addr; + + status = 0; + break; + } + } + + + DBG_LEAVE( et131x_dbginfo ); + return status; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_setphy_normal + ****************************************************************************** + + DESCRIPTION : Used by Power Management to force the PHY into 10 Base T + half-duplex mode, when going to D3 in WOL mode. Also + used during initialization to set the PHY for normal + operation. + + PARAMETERS : adapter - pointer to our private adapter structure + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_setphy_normal( ET131X_ADAPTER *adapter ) +{ + int status; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_setphy_normal" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Make sure the PHY is powered up + *************************************************************************/ + ET1310_PhyPowerDown( adapter, 0 ); + status = et131x_xcvr_init( adapter ); + + + DBG_LEAVE( et131x_dbginfo ); + return status; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_xcvr_init + ****************************************************************************** + + DESCRIPTION : Used to init the phy if we are setting it into force mode + + PARAMETERS : adapter - pointer to our private adapter structure + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_xcvr_init( ET131X_ADAPTER *adapter ) +{ + int status = 0; + MI_IMR_t imr; + MI_ISR_t isr; + MI_LCR2_t lcr2; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_xcvr_init" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Zero out the adapter structure variable representing BMSR + *************************************************************************/ + adapter->Bmsr.value = 0; + + MiRead( adapter, (UINT8)adapter->Stats.xcvr_addr, + (UINT8)FIELD_OFFSET( MI_REGS_t, isr ), &isr.value ); + + MiRead( adapter, (UINT8)adapter->Stats.xcvr_addr, + (UINT8)FIELD_OFFSET( MI_REGS_t, imr ), &imr.value ); + + + /************************************************************************** + Set the link status interrupt only. Bad behavior when link status and + auto neg are set, we run into a nested interrupt problem + *************************************************************************/ + imr.bits.int_en = 0x1; + imr.bits.link_status = 0x1; + imr.bits.autoneg_status = 0x1; + + MiWrite( adapter, (UINT8)adapter->Stats.xcvr_addr, + (UINT8)FIELD_OFFSET( MI_REGS_t, imr ), imr.value ); + + + /************************************************************************** + Set the LED behavior such that LED 1 indicates speed (off = 10Mbits, + blink = 100Mbits, on = 1000Mbits) and LED 2 indicates link and + activity (on for link, blink off for activity). + + NOTE: Some customizations have been added here for specific vendors; + The LED behavior is now determined by vendor data in the EEPROM. However, + the above description is the default. + *************************************************************************/ + if(( adapter->eepromData[1] & 0x4 ) == 0 ) + { + MiRead( adapter, (UINT8)adapter->Stats.xcvr_addr, + (UINT8)FIELD_OFFSET( MI_REGS_t, lcr2 ), &lcr2.value ); + + if(( adapter->eepromData[1] & 0x8 ) == 0 ) + { + lcr2.bits.led_tx_rx = 0x3; + } + else + { + lcr2.bits.led_tx_rx = 0x4; + } + + lcr2.bits.led_link = 0xa; + + MiWrite( adapter, (UINT8)adapter->Stats.xcvr_addr, + (UINT8)FIELD_OFFSET( MI_REGS_t, lcr2 ), lcr2.value ); + } + + + /************************************************************************** + Determine if we need to go into a force mode and set it + *************************************************************************/ + if( adapter->AiForceSpeed == 0 && adapter->AiForceDpx == 0 ) + { + if(( adapter->RegistryFlowControl == TxOnly ) || + ( adapter->RegistryFlowControl == Both )) + { + ET1310_PhyAccessMiBit( adapter, + TRUEPHY_BIT_SET, 4, 11, NULL ); + } + else + { + ET1310_PhyAccessMiBit( adapter, + TRUEPHY_BIT_CLEAR, 4, 11, NULL ); + } + + if( adapter->RegistryFlowControl == Both ) + { + ET1310_PhyAccessMiBit( adapter, + TRUEPHY_BIT_SET, 4, 10, NULL ); + } + else + { + ET1310_PhyAccessMiBit( adapter, + TRUEPHY_BIT_CLEAR, 4, 10, NULL ); + } + + + /********************************************************************** + Set the phy to autonegotiation + *********************************************************************/ + ET1310_PhyAutoNeg( adapter, TRUE ); + + + /* NOTE - Do we need this? */ + ET1310_PhyAccessMiBit( adapter, + TRUEPHY_BIT_SET, 0, 9, NULL ); + + DBG_LEAVE( et131x_dbginfo ); + return status; + } + else + { + ET1310_PhyAutoNeg( adapter, FALSE ); + + /********************************************************************** + Set to the correct force mode. + *********************************************************************/ + if( adapter->AiForceDpx != 1 ) + { + if(( adapter->RegistryFlowControl == TxOnly ) || + ( adapter->RegistryFlowControl == Both )) + { + ET1310_PhyAccessMiBit( adapter, + TRUEPHY_BIT_SET, 4, 11, NULL ); + } + else + { + ET1310_PhyAccessMiBit( adapter, + TRUEPHY_BIT_CLEAR, 4, 11, NULL ); + } + + if( adapter->RegistryFlowControl == Both ) + { + ET1310_PhyAccessMiBit( adapter, + TRUEPHY_BIT_SET, 4, 10, NULL ); + } + else + { + ET1310_PhyAccessMiBit( adapter, + TRUEPHY_BIT_CLEAR, 4, 10, NULL ); + } + } + else + { + ET1310_PhyAccessMiBit( adapter, + TRUEPHY_BIT_CLEAR, 4, 10, NULL ); + ET1310_PhyAccessMiBit( adapter, + TRUEPHY_BIT_CLEAR, 4, 11, NULL ); + } + + switch( adapter->AiForceSpeed ) + { + case 10: + if( adapter->AiForceDpx == 1 ) + { + TPAL_SetPhy10HalfDuplex( adapter ); + } + else if( adapter->AiForceDpx == 2 ) + { + TPAL_SetPhy10FullDuplex( adapter ); + } + else + { + TPAL_SetPhy10Force( adapter ); + } + break; + + case 100: + if( adapter->AiForceDpx == 1 ) + { + TPAL_SetPhy100HalfDuplex( adapter ); + } + else if( adapter->AiForceDpx == 2 ) + { + TPAL_SetPhy100FullDuplex( adapter ); + } + else + { + TPAL_SetPhy100Force( adapter ); + } + break; + + case 1000: + TPAL_SetPhy1000FullDuplex( adapter ); + break; + } + + + DBG_LEAVE( et131x_dbginfo ); + return status; + } +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: et131x_Mii_check + ****************************************************************************** + + DESCRIPTION: + used to + + PARAMETERS : + pAdapter - pointer to our adapter + bmsr - + + RETURNS : + Nothing + + *****************************************************************************/ +void et131x_Mii_check( ET131X_ADAPTER *pAdapter, + MI_BMSR_t bmsr, + MI_BMSR_t bmsr_ints ) +{ + UCHAR ucLinkStatus; + INT32 nAutoNegStatus; + INT32 nSpeed; + INT32 nDuplex; + INT32 nMdiMdix; + INT32 nMasterSlave; + INT32 nPolarity; + unsigned long lockflags; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_Mii_check" ); + DBG_ENTER( et131x_dbginfo ); + + + if( bmsr_ints.bits.link_status ) + { + if( bmsr.bits.link_status ) + { + pAdapter->PoMgmt.TransPhyComaModeOnBoot = 20; + + + /****************************************************************** + Update our state variables and indicate the connected state + *****************************************************************/ + spin_lock_irqsave( &pAdapter->Lock, lockflags ); + + pAdapter->MediaState = NETIF_STATUS_MEDIA_CONNECT; + MP_CLEAR_FLAG( pAdapter, fMP_ADAPTER_LINK_DETECTION ); + + spin_unlock_irqrestore( &pAdapter->Lock, lockflags ); + + if( pAdapter->RegistryPhyLoopbk == FALSE ) + { + /************************************************************** + Don't indicate state if we're in loopback mode + *************************************************************/ + netif_indicate_status( pAdapter->netdev, pAdapter->MediaState ); + } + } + else + { + DBG_WARNING( et131x_dbginfo, "Link down cable problem\n" ); + + if( pAdapter->uiLinkSpeed == TRUEPHY_SPEED_10MBPS ) + { + // NOTE - Is there a way to query this without TruePHY? + //if( TRU_QueryCoreType ( pAdapter->hTruePhy, 0 ) == EMI_TRUEPHY_A13O ) + { + UINT16 Register18; + + MiRead( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + 0x12, &Register18 ); + MiWrite( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + 0x12, Register18 | 0x4 ); + MiWrite( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + 0x10, Register18 | 0x8402 ); + MiWrite( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + 0x11, Register18 | 511 ); + MiWrite( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + 0x12, Register18 ); + } + } + + /****************************************************************** + For the first N seconds of life, we are in "link detection" + When we are in this state, we should only report "connected". + When the LinkDetection Timer expires, we can report + disconnected (handled in the LinkDetectionDPC). + *****************************************************************/ + if(( MP_IS_FLAG_CLEAR( pAdapter, fMP_ADAPTER_LINK_DETECTION )) || + ( pAdapter->MediaState == NETIF_STATUS_MEDIA_DISCONNECT )) + { + spin_lock_irqsave( &pAdapter->Lock, lockflags ); + pAdapter->MediaState = NETIF_STATUS_MEDIA_DISCONNECT; + spin_unlock_irqrestore( &pAdapter->Lock, lockflags ); + + /************************************************************** + Only indicate state if we're in loopback mode + *************************************************************/ + if( pAdapter->RegistryPhyLoopbk == FALSE ) + { + netif_indicate_status( pAdapter->netdev, pAdapter->MediaState ); + } + } + + pAdapter->uiLinkSpeed = 0; + pAdapter->uiDuplexMode = 0; + + + /****************************************************************** + Free the packets being actively sent & stopped + *****************************************************************/ + et131x_free_busy_send_packets( pAdapter ); + + + /****************************************************************** + Re-initialize the send structures + *****************************************************************/ + et131x_init_send( pAdapter ); + + + /****************************************************************** + Reset the RFD list and re-start RU + *****************************************************************/ + et131x_reset_recv( pAdapter ); + + + /****************************************************************** + Bring the device back to the state it was during init prior + to autonegotiation being complete. This way, when we get the + auto-neg complete interrupt, we can complete init by calling + ConfigMacREGS2. + *****************************************************************/ + et131x_soft_reset( pAdapter ); + + + /****************************************************************** + Setup ET1310 as per the documentation + *****************************************************************/ + et131x_adapter_setup( pAdapter ); + + + /****************************************************************** + Setup the PHY into coma mode until the cable is plugged back in + *****************************************************************/ + if( pAdapter->RegistryPhyComa == 1 ) + { + EnablePhyComa( pAdapter ); + } + } + } + + if( bmsr_ints.bits.auto_neg_complete || + (( pAdapter->AiForceDpx == 3 ) && ( bmsr_ints.bits.link_status ))) + { + if( bmsr.bits.auto_neg_complete || + ( pAdapter->AiForceDpx == 3 )) + { + ET1310_PhyLinkStatus( pAdapter, + &ucLinkStatus, + &nAutoNegStatus, + &nSpeed, + &nDuplex, + &nMdiMdix, + &nMasterSlave, + &nPolarity ); + + + pAdapter->uiLinkSpeed = nSpeed; + pAdapter->uiDuplexMode = nDuplex; + + DBG_TRACE( et131x_dbginfo, + "pAdapter->uiLinkSpeed 0x%04x, pAdapter->uiDuplex 0x%08x\n", + pAdapter->uiLinkSpeed, pAdapter->uiDuplexMode ); + + pAdapter->PoMgmt.TransPhyComaModeOnBoot = 20; + + if( pAdapter->uiLinkSpeed == TRUEPHY_SPEED_10MBPS ) + { + // NOTE - Is there a way to query this without TruePHY? + //if( TRU_QueryCoreType ( pAdapter->hTruePhy, 0 ) == EMI_TRUEPHY_A13O ) + { + UINT16 Register18; + + MiRead( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + 0x12, &Register18 ); + MiWrite( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + 0x12, Register18 | 0x4 ); + MiWrite( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + 0x10, Register18 | 0x8402 ); + MiWrite( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + 0x11, Register18 | 511 ); + MiWrite( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + 0x12, Register18 ); + } + } + + ConfigFlowControl( pAdapter ); + + + if(( pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS ) && + ( pAdapter->RegistryJumboPacket > 2048 )) + + { + ET1310_PhyAndOrReg( pAdapter, 0x16, 0xcfff, 0x2000 ); + } + + SetRxDmaTimer( pAdapter ); + ConfigMACRegs2( pAdapter ); + } + } + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : TPAL_MiAccessRegs + ****************************************************************************** + + DESCRIPTION : Used to perform a single or series of MI Register + transactions on the specified PHY + + PARAMETERS : hPlatform - handle to platform resources + nPhyId - logical PHY ID (if >= 0) or + logical PHY group ID (if <0) + pbyAccessFlags - Pointer to a list of flags, which + specify the transaction type associated + with each register contained in the + 'pbyRegisters' array. Valid values: + TRUEPHY_READ + TRUEPHY_WRITE + TRUEPHY_MASK + If a logical PHY Group ID is specified + in 'nPhyId', the value of these flags + must be TRUEPHY_WRITE + pbyRegisters - Pointer to a list of MI registers + addressess (0-31), one of each register + specified by 'nRegCount' + pwData - Pointer to a buffer that contains the + data required by or resulting from each + transaction, the contents of which are + dependent upon the 'pbyAccessFlags' + parameter. Specifically: + + If 'pbyAccessFlags[i]' is TRUEPHY_READ, + the contents of the register specified + by 'pbyRegisters[i]' is read and stored + in 'pwData[i]'. + + If 'pbyAccessFlags[i]' is TRUEPHY_WRITE, + the contents of 'pwData[i]' is written + to the register specified by + 'pbyRegisters[i]'. + + If 'pbyAccessFlags[i]' is TRUEPHY_MASK, + the contents of the register specified + by 'pbyRegisters[i]' is read and stored + in 'pwData [i]', which is then + logically AND'ed with the contents of + 'pwAndMasks[i]' and logically OR'ed + with the contents of 'pwOrMasks[i]' + before it is written back to the + register specified by 'pbyRegisters[i]' + + This allows the calling function to + interleave a register read, logical + and/or, and write operation within a + single transaction. + + pwAndMasks - Pointer to buffer containing AND masks, + which is required if the corresponding + transaction type is TRUEPHY_MASK; + otherwise, this parameter is ignored. + pwOrMasks - Pointer to buffer containing OR masks, + which is required if the corresponding + transaction type is TRUEPHY_MASK; + otherwise, this parameter is ignored. + nRegCount - Specifies the number of register + transactions to be performed. + + RETURNS : TRUEPHY_SUCCESS + TRUEPHY_FAILURE + + REUSE INFORMATION : + + *****************************************************************************/ +INT32 TPAL_MiAccessRegs( TPAL_HANDLE hPlatform, + INT32 nPhyId, + PUCHAR pbyAccessFlags, + PUCHAR pbyRegisters, + PUINT16 pwData, + PUINT16 pwAndMasks, + PUINT16 pwOrMasks, + INT32 nRegCount ) +{ + INT32 nStatus = TRUEPHY_FAILURE; + INT32 index; + INT16 wTemp; + UINT8 xcvrAddr; + ET131X_ADAPTER *pAdapter = hPlatform; + unsigned long lockflags; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "TPAL_MiAccessRegs" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Validate Input parameters. We are not worried about nPhyId because we + can only access the one we control + *************************************************************************/ + if( pbyAccessFlags != NULL && pwData != NULL ) + { + /********************************************************************** + Convert nPhyId into a PHY physical address(nPhyAddress) + *********************************************************************/ + + + /********************************************************************** + Convert nPhyId into a MI bus address (nBusAddress). + + NOTE: This is only needed for platforms that support multiple MI + buses + *********************************************************************/ + + + /********************************************************************** + Get the xcvr addr for all transactions to go to + *********************************************************************/ + xcvrAddr = (UINT8)pAdapter->Stats.xcvr_addr; + + + /********************************************************************** + Go through all registers performing specific transaction indicated + in the corresponding pbyAccessFlags array. + *********************************************************************/ + for( index = 0; index < nRegCount; index++ ) + { + /****************************************************************** + Validate MI register + *****************************************************************/ + if( pbyRegisters[index] > 31 ) + { + break; + } + + + /****************************************************************** + Is this a read? + *****************************************************************/ + if( pbyAccessFlags[index] == TRUEPHY_READ ) + { + /************************************************************** + Group reads are not allowed + *************************************************************/ + if( nPhyId < 0 ) + { + break; + } + + + /************************************************************** + Make sure we acquire the spin lock + *************************************************************/ + spin_lock_irqsave( &pAdapter->PHYLock, lockflags ); + + + /************************************************************** + Let's perform the read operation + *************************************************************/ + MiRead( pAdapter, xcvrAddr, pbyRegisters[index], + (PUINT16)&pwData[index] ); + + spin_unlock_irqrestore( &pAdapter->PHYLock, lockflags ); + + } + else if( pbyAccessFlags[index] == TRUEPHY_WRITE ) + { + /************************************************************** + Make sure we acquire the spin lock + *************************************************************/ + spin_lock_irqsave( &pAdapter->PHYLock, lockflags ); + + + /************************************************************** + Let's perform the write operation + *************************************************************/ + MiWrite( pAdapter, xcvrAddr, pbyRegisters[index], + (UINT16)pwData[index] ); + + spin_unlock_irqrestore( &pAdapter->PHYLock, lockflags ); + } + else if( pbyAccessFlags[index] == TRUEPHY_MASK ) + { + /************************************************************** + Group masks are not allowed + *************************************************************/ + if( nPhyId < 0 ) + { + break; + } + + /************************************************************** + Pointer to AND and OR masks must not be NULL + *************************************************************/ + if(( pwOrMasks == NULL ) || ( pwAndMasks == NULL )) + { + break; + } + + /************************************************************** + Make sure we acquire the spin lock + *************************************************************/ + spin_lock_irqsave( &pAdapter->PHYLock, lockflags ); + + + /************************************************************** + Perform read + *************************************************************/ + MiRead( pAdapter, xcvrAddr, pbyRegisters[index], + (PUINT16)&pwData[index] ); + + + /************************************************************** + Perform and/or masks and write it back + *************************************************************/ + wTemp = (( pwData[index] & pwAndMasks[index] ) | + pwOrMasks[index] ); + + MiWrite( pAdapter, xcvrAddr, pbyRegisters[index], + (UINT16)wTemp ); + + spin_unlock_irqrestore( &pAdapter->PHYLock, lockflags ); + } + else + { + /************************************************************** + Invalid transaction type, just break out of the loop + *************************************************************/ + break; + } + }//end for loop + + /********************************************************************** + If we completed all the transactions, indicate success + *********************************************************************/ + if( index == nRegCount ) + { + nStatus = TRUEPHY_SUCCESS; + } + }//end if + + + DBG_LEAVE( et131x_dbginfo ); + return nStatus; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : TPAL_PlatformExit + ****************************************************************************** + + DESCRIPTION : Used to exit the TRUEPHY library which will de-allocate + any system resources allocated. + + PARAMETERS : hPlatform - handle to the platform resources + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ + +void TPAL_PlatformExit( TRUEPHY_OSAL_HANDLE hPlatform ) +{ + DBG_FUNC( "TPAL_PlatformExit" ); + DBG_ENTER( et131x_dbginfo ); + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + +/////////////////////////////////////////////////////////////////////////////// +//// OS Specific Functions //// +/////////////////////////////////////////////////////////////////////////////// +/****************************************************************************** + ROUTINE : TPAL_AllocMem + ****************************************************************************** + + DESCRIPTION : Used so the TRUEPHY library can allocate memory + + PARAMETERS : ulNumBytes - number of bytes to allocate + + RETURNS : pointer to allocated memory block on success, or + NULL on failure + + REUSE INFORMATION : + + *****************************************************************************/ +void * TPAL_AllocMem( TRUEPHY_OSAL_HANDLE hPlatform, u_long ulNumBytes ) +{ + void *pBuffer = NULL; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "TPAL_AllocMem" ); + DBG_ENTER( et131x_dbginfo ); + + + pBuffer = kmalloc( ulNumBytes, GFP_ATOMIC ); + + + DBG_LEAVE( et131x_dbginfo ); + return pBuffer; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : TPAL_FreeMem + ****************************************************************************** + + DESCRIPTION : Used to free a previously allocated block of memory + + PARAMETERS : pMemBlock - the pointer to the buffer to free + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void TPAL_FreeMem( TRUEPHY_OSAL_HANDLE hPlatform, void *pMemBlock ) +{ + DBG_FUNC( "TPAL_FreeMem" ); + DBG_ENTER( et131x_dbginfo ); + + + kfree( pMemBlock ); + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: TPAL_Sleep + ****************************************************************************** + + DESCRIPTION: + Used to delay execution for a specified number of milliseconds + + PARAMETERS : + ulMsec - Number of milliseconds to delay. This parameter can be zero + + RETURNS : + NONE + + *****************************************************************************/ +void TPAL_Sleep( TRUEPHY_OSAL_HANDLE hPlatform, u_long ulMsec ) +{ + DBG_FUNC( "TPAL_Sleep" ); + DBG_ENTER( et131x_dbginfo ); + + + mdelay( ulMsec ); + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: TPAL_GetSystemUpTime + ****************************************************************************** + + DESCRIPTION: + Used to get the numberr of milliseconds that have elapsed since the + system was started + + PARAMETERS : + NONE + + RETURNS : + number of milliseconds since system was started + + *****************************************************************************/ +u_long TPAL_GetSystemUpTime( TRUEPHY_OSAL_HANDLE hPlatform ) +{ + UINT32 uptime; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "TPAL_GetSystemUpTime" ); + DBG_ENTER( et131x_dbginfo ); + + + uptime = 10 * jiffies / HZ; + + + DBG_LEAVE( et131x_dbginfo ); + return uptime; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: TPAL_GetLinkStatusInfo + ****************************************************************************** + + DESCRIPTION: + used to determine what link speed and duplex the phy is set to + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + NONE + + *****************************************************************************/ +void TPAL_GetLinkStatusInfo( ET131X_ADAPTER *pAdapter ) +{ + UINT32 index = 0; + INT32 MdiMdix; + INT32 MasterSlave; + INT32 Polarity; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "TPAL_GetLinkStatusInfo" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Get the link status information from the phy. Loop until the + autonegstatus is complete or link status is up. + + If looping for 50 uSec, break out, we have a problem + *************************************************************************/ + do + { + ET1310_PhyLinkStatus( pAdapter, + &pAdapter->ucLinkStatus, + &pAdapter->uiAutoNegStatus, + &pAdapter->uiLinkSpeed, + &pAdapter->uiDuplexMode, + &MdiMdix, + &MasterSlave, + &Polarity ); + + DBG_VERBOSE( et131x_dbginfo, + "uiAutoNegStatus 0x%08x ucLinkStatus 0x%04x\n " + "uiLinkSpeed 0x%04x, uiDuplexMode 0x%08x\n", + pAdapter->uiAutoNegStatus, + pAdapter->ucLinkStatus, + pAdapter->uiLinkSpeed, + pAdapter->uiDuplexMode ); + + udelay( 100 ); + index++; + + if( index == 10000 ) + { + /****************************************************************** + We hit our limit, we need to set a variable so during power + management we know to try 100/half + *****************************************************************/ + pAdapter->PoMgmt.Failed10Half = TRUE; + break; + } + } while( pAdapter->uiAutoNegStatus != TRUEPHY_ANEG_COMPLETE || + pAdapter->ucLinkStatus == 0 ); + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: TPAL_SetPhy10HalfDuplex + ****************************************************************************** + + DESCRIPTION: + Used to force the phy into 10 Base T Half Duplex mode. Also sets the + MAC so it is syncd up properly + + PARAMETERS : + pAdapter - pointer to the adapter structure + + RETURNS : + TRUEPHY_SUCCESS - if everything goes according to plan + TRUEPHY_FALIURE -if something goes wrong + + *****************************************************************************/ +INT32 TPAL_SetPhy10HalfDuplex( ET131X_ADAPTER *pAdapter ) +{ + INT32 returnValue = TRUEPHY_SUCCESS; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "TPAL_SetPhy10HalfDuplex" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Power down PHY + *************************************************************************/ + ET1310_PhyPowerDown( pAdapter, 1 ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, "Could not power down the PHY\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + /************************************************************************** + First we need to turn off all other advertisement + *************************************************************************/ + ET1310_PhyAdvertise1000BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_NONE ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, + "Could not turn off advertisement of 1000 BaseT\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + ET1310_PhyAdvertise100BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_NONE ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, + "Could not turn off advertisement of 100 BaseT " + "for forcing 10 BaseT Half Duplex\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + /************************************************************************** + Set our advertise values accordingly + *************************************************************************/ + ET1310_PhyAdvertise10BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_HALF ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, "Could not set Advertise of 10 Half\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + /************************************************************************** + Power up PHY + *************************************************************************/ + ET1310_PhyPowerDown( pAdapter, 0 ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, "Could not power up the PHY\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + DBG_LEAVE( et131x_dbginfo ); + return returnValue ; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: TPAL_SetPhy10FullDuplex + ****************************************************************************** + + DESCRIPTION: + Used to force the phy into 10 Base T Full Duplex mode. Also sets the + MAC so it is syncd up properly + + PARAMETERS : + pAdapter - pointer to the adapter structure + + RETURNS : + TRUEPHY_SUCCESS - if everything goes according to plan + TRUEPHY_FALIURE -if somethign goes wrong during the procedures + + *****************************************************************************/ +INT32 TPAL_SetPhy10FullDuplex( ET131X_ADAPTER *pAdapter ) +{ + INT32 returnValue = TRUEPHY_SUCCESS; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "TPAL_SetPhy10FullDuplex" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Power down PHY + *************************************************************************/ + ET1310_PhyPowerDown( pAdapter, 1 ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, "Could not power down the PHY\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + /************************************************************************** + First we need to turn off all other advertisement + *************************************************************************/ + ET1310_PhyAdvertise1000BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_NONE ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, + "Could not turn off advertisement of 1000 BaseT " + "for Forcing 10 BaseT Full Duplex\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + ET1310_PhyAdvertise100BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_NONE ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, + "Could not turn off advertisement of 100 BaseT " + "for Forcing 10 BaseT Full Duplex\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + /************************************************************************** + Set our advertise values accordingly + *************************************************************************/ + ET1310_PhyAdvertise10BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_FULL ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, "Could not set Advertise of 10 Full\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + /************************************************************************** + Power up PHY + *************************************************************************/ + ET1310_PhyPowerDown( pAdapter, 0 ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, "Could not power up the phy\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + DBG_LEAVE( et131x_dbginfo ); + return returnValue; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: TPAL_SetPhy10Force + ****************************************************************************** + + DESCRIPTION: + Used to force the phy into 10 Base T Full Duplex mode WITHOUT using + autonegotiation. + + PARAMETERS : + pAdapter - pointer to the adapter structure + + RETURNS : + + *****************************************************************************/ +void TPAL_SetPhy10Force( ET131X_ADAPTER *pAdapter ) +{ + DBG_FUNC( "TPAL_SetPhy10Force" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Power down PHY + *************************************************************************/ + ET1310_PhyPowerDown( pAdapter, 1 ); + + + /************************************************************************** + Disable autoneg + *************************************************************************/ + ET1310_PhyAutoNeg( pAdapter, FALSE ); + + + /************************************************************************** + Disable all advertisement + *************************************************************************/ + ET1310_PhyAdvertise1000BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_NONE ); + + ET1310_PhyAdvertise10BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_NONE ); + + ET1310_PhyAdvertise100BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_NONE ); + + + /************************************************************************** + Force 10 Mbps + *************************************************************************/ + ET1310_PhySpeedSelect( pAdapter, TRUEPHY_SPEED_10MBPS ); + + + /************************************************************************** + Force Full duplex + *************************************************************************/ + ET1310_PhyDuplexMode( pAdapter, TRUEPHY_DUPLEX_FULL ); + + + /************************************************************************** + Power up PHY + *************************************************************************/ + ET1310_PhyPowerDown( pAdapter, 0 ); + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: TPAL_SetPhy100HalfDuplex + ****************************************************************************** + + DESCRIPTION: + Used to force the phy into 100 Base T Half Duplex mode. Also sets the + MAC so it is syncd up properly + + PARAMETERS : + pAdapter - pointer to the adapter structure + + RETURNS : + TRUEPHY_SUCCESS - if everything goes according to plan + TRUEPHY_FALIURE -if somethign goes wrong during the procedures + + *****************************************************************************/ +INT32 TPAL_SetPhy100HalfDuplex( ET131X_ADAPTER *pAdapter ) +{ + INT32 returnValue = TRUEPHY_SUCCESS; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "TPAL_SetPhy100HalfDuplex" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Power down PHY + *************************************************************************/ + ET1310_PhyPowerDown( pAdapter, 1 ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + + DBG_ERROR( et131x_dbginfo, "Could not power down the PHY\n" ); + DBG_LEAVE( et131x_dbginfo ); + return( returnValue ); + } + + + /************************************************************************** + first we need to turn off all other advertisement + *************************************************************************/ + ET1310_PhyAdvertise1000BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_NONE ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, + "Could not turn off advertisement of 1000 BaseT " + "for Forcing 100 BaseT Half Duplex\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + ET1310_PhyAdvertise10BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_NONE ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, + "Could not turn off advertisement of 10 BaseT " + "for Forcing 100 BaseT Half Duplex\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + /************************************************************************** + Set our advertise values accordingly + *************************************************************************/ + ET1310_PhyAdvertise100BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_HALF ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, "Could not set Advertise of 100 Half\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + /* Set speed */ + ET1310_PhySpeedSelect( pAdapter, TRUEPHY_SPEED_100MBPS ); + + + /************************************************************************** + Power up PHY + *************************************************************************/ + ET1310_PhyPowerDown( pAdapter, 0 ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, "Could not power up the PHY\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + DBG_LEAVE( et131x_dbginfo ); + return returnValue; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: TPAL_SetPhy100FullDuplex + ****************************************************************************** + + DESCRIPTION: + Used to force the phy into 100 Base T Full Duplex mode. Also sets the + MAC so it is syncd up properly + + PARAMETERS : + pAdapter - pointer to the adapter structure + + RETURNS : + TRUEPHY_SUCCESS - if everything goes according to plan + TRUEPHY_FALIURE -if somethign goes wrong during the procedures + + *****************************************************************************/ +INT32 TPAL_SetPhy100FullDuplex( ET131X_ADAPTER *pAdapter ) +{ + INT32 returnValue = TRUEPHY_SUCCESS; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "TPAL_SetPhy100FullDuplex" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Power down PHY + *************************************************************************/ + ET1310_PhyPowerDown( pAdapter, 1 ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, "Could not power down PHY\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + /************************************************************************** + First we need to turn off all other advertisement + *************************************************************************/ + ET1310_PhyAdvertise1000BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_NONE ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, + "Could not turn off advertisement of 1000 BaseT " + "for Forcing 100 BaseT Full Duplex\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + ET1310_PhyAdvertise10BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_NONE ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, + "Could not turn off advertisement of 10 BaseT " + "for Forcing 100 BaseT Full Duplex\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + /************************************************************************** + Set our advertise values accordingly + *************************************************************************/ + ET1310_PhyAdvertise100BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_FULL ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, "Could not set Advertise of 100 Full\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + /************************************************************************** + Power up PHY + *************************************************************************/ + ET1310_PhyPowerDown( pAdapter, 0 ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, "Could not power up PHY\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + DBG_LEAVE( et131x_dbginfo ); + return returnValue; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: TPAL_SetPhy100Force + ****************************************************************************** + + DESCRIPTION: + Used to force the phy into 100 Base T Full Duplex mode WITHOUT using + autonegotiation. + + PARAMETERS : + pAdapter - pointer to the adapter structure + + RETURNS : + + *****************************************************************************/ +void TPAL_SetPhy100Force( ET131X_ADAPTER *pAdapter ) +{ + DBG_FUNC( "TPAL_SetPhy100Force" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Power down PHY + *************************************************************************/ + ET1310_PhyPowerDown( pAdapter, 1 ); + + + /************************************************************************** + Disable autoneg + *************************************************************************/ + ET1310_PhyAutoNeg( pAdapter, FALSE ); + + + /************************************************************************** + Disable all advertisement + *************************************************************************/ + ET1310_PhyAdvertise1000BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_NONE ); + + + ET1310_PhyAdvertise10BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_NONE ); + + + ET1310_PhyAdvertise100BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_NONE ); + + + /************************************************************************** + Force 100 Mbps + *************************************************************************/ + ET1310_PhySpeedSelect( pAdapter, TRUEPHY_SPEED_100MBPS ); + + + /************************************************************************** + Force Full duplex + *************************************************************************/ + ET1310_PhyDuplexMode( pAdapter, TRUEPHY_DUPLEX_FULL ); + + + /************************************************************************** + Power up PHY + *************************************************************************/ + ET1310_PhyPowerDown( pAdapter, 0 ); + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: TPAL_SetPhy1000FullDuplex + ****************************************************************************** + + DESCRIPTION: + Used to force the phy into 1000 Base T Full Duplex mode. Also sets the + MAC so it is syncd up properly + + PARAMETERS : + pAdapter - pointer to the adapter structure + + RETURNS : + TRUEPHY_SUCCESS - if everything goes according to plan + TRUEPHY_FALIURE -if somethign goes wrong during the procedures + + *****************************************************************************/ +INT32 TPAL_SetPhy1000FullDuplex( ET131X_ADAPTER *pAdapter ) +{ + INT32 returnValue = TRUEPHY_SUCCESS; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "TPAL_SetPhy1000FullDuplex" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Power down PHY + *************************************************************************/ + ET1310_PhyPowerDown( pAdapter, 1 ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, "Could not power down phy\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + /************************************************************************** + first we need to turn off all other advertisement + *************************************************************************/ + ET1310_PhyAdvertise100BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_NONE ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, + "Could not turn off advertisement of 100 BaseT " + "for Forcing 1000 BaseT Full Duplex\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + ET1310_PhyAdvertise10BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_NONE ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, + "Could not turn off advertisement of 10 BaseT " + "for Forcing 1000 BaseT Full Duplex\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + /************************************************************************** + set our advertise values accordingly + *************************************************************************/ + ET1310_PhyAdvertise1000BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_FULL ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, "Could not set Advertise of 1000 Full\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + /************************************************************************** + power up PHY + *************************************************************************/ + ET1310_PhyPowerDown( pAdapter, 0 ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, "Could not power up PHY\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + DBG_LEAVE( et131x_dbginfo ); + return returnValue; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: TPAL_SetPhyAutoNeg + ****************************************************************************** + + DESCRIPTION: + Used to set phy to autonegotiation mode. + + PARAMETERS : + pAdapter - pointer to the adapter structure + + RETURNS : + TRUEPHY_SUCCESS - if everything goes according to plan + TRUEPHY_FALIURE -if somethign goes wrong during the procedures + + *****************************************************************************/ +INT32 TPAL_SetPhyAutoNeg( ET131X_ADAPTER *pAdapter ) +{ + INT32 returnValue = TRUEPHY_SUCCESS; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "TPAL_SetPhyAutoNeg" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Power down PHY + *************************************************************************/ + ET1310_PhyPowerDown( pAdapter, 1 ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, "Could not power down phy\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + /************************************************************************** + Turn on advertisement of all capabilities + *************************************************************************/ + ET1310_PhyAdvertise10BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_BOTH ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, + "Could not Turn on Advertisement of 10 BaseT " + "from Setting to Auto Negotiation\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + ET1310_PhyAdvertise100BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_BOTH ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, + "Could not Turn on Advertisement of 100 BaseT " + "from Setting to Auto Negotiation\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + if( pAdapter->DeviceID != ET131X_PCI_DEVICE_ID_FAST ) + { + ET1310_PhyAdvertise1000BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_FULL ); + } + else + { + ET1310_PhyAdvertise1000BaseT( pAdapter, TRUEPHY_ADV_DUPLEX_NONE ); + } + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, + "Could not Turn on Advertisement of 1000 BaseT " + "from Setting to Auto Negotiation\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + /************************************************************************** + Make sure auto-neg is ON (it is disabled in FORCE modes) + *************************************************************************/ + ET1310_PhyAutoNeg( pAdapter, TRUE ); + + + /************************************************************************** + Power up PHY + *************************************************************************/ + ET1310_PhyPowerDown( pAdapter, 0 ); + + if( returnValue == TRUEPHY_FAILURE ) + { + /********************************************************************** + HANDLE ERROR HERE + *********************************************************************/ + DBG_ERROR( et131x_dbginfo, "Could not power up phy\n" ); + DBG_LEAVE( et131x_dbginfo ); + return returnValue; + } + + + DBG_LEAVE( et131x_dbginfo ); + return returnValue; +} +/*===========================================================================*/ + + + + +/****************************************************************************** +******************************************************************************* + + The routines which follow provide low-level access to the PHY, and are used + primarily by the routines above (although there are a few places elsewhere in + the driver where this level of access is required). + +******************************************************************************* +******************************************************************************/ + +static UINT16 ConfigPhy[25][2] = +{ + /* Reg Value Register */ + /* Addr */ + {0x880B, 0x0926}, /* AfeIfCreg4B1000Msbs */ + {0x880C, 0x0926}, /* AfeIfCreg4B100Msbs */ + {0x880D, 0x0926}, /* AfeIfCreg4B10Msbs */ + + {0x880E, 0xB4D3}, /* AfeIfCreg4B1000Lsbs */ + {0x880F, 0xB4D3}, /* AfeIfCreg4B100Lsbs */ + {0x8810, 0xB4D3}, /* AfeIfCreg4B10Lsbs */ + + {0x8805, 0xB03E}, /* AfeIfCreg3B1000Msbs */ + {0x8806, 0xB03E}, /* AfeIfCreg3B100Msbs */ + {0x8807, 0xFF00}, /* AfeIfCreg3B10Msbs */ + + {0x8808, 0xE090}, /* AfeIfCreg3B1000Lsbs */ + {0x8809, 0xE110}, /* AfeIfCreg3B100Lsbs */ + {0x880A, 0x0000}, /* AfeIfCreg3B10Lsbs */ + + {0x300D, 1 }, /* DisableNorm */ + + {0x280C, 0x0180}, /* LinkHoldEnd */ + + {0x1C21, 0x0002}, /* AlphaM */ + + {0x3821, 6 }, /* FfeLkgTx0 */ + {0x381D, 1 }, /* FfeLkg1g4 */ + {0x381E, 1 }, /* FfeLkg1g5 */ + {0x381F, 1 }, /* FfeLkg1g6 */ + {0x3820, 1 }, /* FfeLkg1g7 */ + + {0x8402, 0x01F0}, /* Btinact */ + {0x800E, 20 }, /* LftrainTime */ + {0x800F, 24 }, /* DvguardTime */ + {0x8010, 46 }, /* IdlguardTime */ + + {0, 0 } + +}; +// +// condensed version of the phy initialization routine +// +void ET1310_PhyInit( ET131X_ADAPTER *pAdapter ) +{ + UINT16 usData, usIndex; + + + if( pAdapter == NULL ) + { + return; + } + + + // get the identity (again ?) + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_ID_1, &usData ); + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_ID_2, &usData ); + + // what does this do/achieve ? + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_MPHY_CONTROL_REG, &usData ); // should read 0002 + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_MPHY_CONTROL_REG, 0x0006 ); + + // read modem register 0402, should I do something with the return data ? + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_INDEX_REG, 0x0402 ); + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_DATA_REG, &usData ); + + // what does this do/achieve ? + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_MPHY_CONTROL_REG, 0x0002 ); + + // get the identity (again ?) + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_ID_1, &usData ); + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_ID_2, &usData ); + + // what does this achieve ? + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_MPHY_CONTROL_REG, &usData ); // should read 0002 + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_MPHY_CONTROL_REG, 0x0006 ); + + // read modem register 0402, should I do something with the return data ? + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_INDEX_REG, 0x0402 ); + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_DATA_REG, &usData ); + + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_MPHY_CONTROL_REG, 0x0002 ); + + // what does this achieve (should return 0x1040) + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_CONTROL, &usData ); + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_MPHY_CONTROL_REG, &usData ); // should read 0002 + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_CONTROL, 0x1840 ); + + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_MPHY_CONTROL_REG, 0x0007 ); + + // here the writing of the array starts.... + usIndex = 0; + while( ConfigPhy[usIndex][0] != 0x0000 ) + { + // write value + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_INDEX_REG, ConfigPhy[usIndex][0] ); + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_DATA_REG, ConfigPhy[usIndex][1] ); + + // read it back + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_INDEX_REG, ConfigPhy[usIndex][0] ); + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_DATA_REG, &usData ); + + // do a check on the value read back ? + usIndex++; + } + // here the writing of the array ends... + + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_CONTROL, &usData ); // 0x1840 + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_MPHY_CONTROL_REG, &usData ); // should read 0007 + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_CONTROL, 0x1040 ); + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_MPHY_CONTROL_REG, 0x0002 ); + + return; + +} + + + + +void ET1310_PhyReset( ET131X_ADAPTER *pAdapter ) +{ + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_CONTROL, 0x8000 ); + return; +} + + + + +void ET1310_PhyPowerDown( ET131X_ADAPTER *pAdapter, BOOL_t down ) +{ + UINT16 usData; + + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_CONTROL, &usData ); + + if( down == FALSE ) + { + // Power UP + usData &= ~0x0800; + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_CONTROL, usData ); + } + else + { + // Power DOWN + usData |= 0x0800; + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_CONTROL, usData ); + } + + return; +} + + +void ET1310_PhyAutoNeg( ET131X_ADAPTER *pAdapter, BOOL_t enable ) +{ + UINT16 usData; + + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_CONTROL, &usData ); + + if( enable == TRUE ) + { + // Autonegotiation ON + usData |= 0x1000; + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_CONTROL, usData ); + } + else + { + // Autonegotiation OFF + usData &= ~0x1000; + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_CONTROL, usData ); + } + + return; +} + +void ET1310_PhyDuplexMode( ET131X_ADAPTER *pAdapter, UINT16 duplex ) +{ + UINT16 usData; + + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_CONTROL, &usData ); + + if( duplex == TRUEPHY_DUPLEX_FULL ) + { + // Set Full Duplex + usData |= 0x100; + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_CONTROL, usData ); + } + else + { + // Set Half Duplex + usData &= ~0x100; + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_CONTROL, usData ); + } + + return; +} + + +void ET1310_PhySpeedSelect( ET131X_ADAPTER *pAdapter, UINT16 speed ) +{ + UINT16 usData; + + // Read the PHY control register + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_CONTROL, &usData ); + + // Clear all Speed settings (Bits 6, 13) + usData &= ~0x2040; + + // Reset the speed bits based on user selection + switch( speed ) + { + case TRUEPHY_SPEED_10MBPS: + // Bits already cleared above, do nothing + break; + + case TRUEPHY_SPEED_100MBPS: + // 100M == Set bit 13 + usData |= 0x2000; + break; + + case TRUEPHY_SPEED_1000MBPS: + default: + usData |= 0x0040; + break; + } + + // Write back the new speed + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_CONTROL, usData ); + + return; +} + + +void ET1310_PhyAdvertise1000BaseT( ET131X_ADAPTER *pAdapter, UINT16 duplex ) +{ + UINT16 usData; + + // Read the PHY 1000 Base-T Control Register + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_1000_CONTROL, &usData ); + + // Clear Bits 8,9 + usData &= ~0x0300; + + switch( duplex ) + { + case TRUEPHY_ADV_DUPLEX_NONE: + // Duplex already cleared, do nothing + break; + + case TRUEPHY_ADV_DUPLEX_FULL: + // Set Bit 9 + usData |= 0x0200; + break; + + case TRUEPHY_ADV_DUPLEX_HALF: + // Set Bit 8 + usData |= 0x0100; + break; + + case TRUEPHY_ADV_DUPLEX_BOTH: + default: + usData |= 0x0300; + break; + } + + // Write back advertisement + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_1000_CONTROL, usData ); + + return; +} + + +void ET1310_PhyAdvertise100BaseT( ET131X_ADAPTER *pAdapter, UINT16 duplex ) +{ + UINT16 usData; + + // Read the Autonegotiation Register (10/100) + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_AUTO_ADVERTISEMENT, &usData ); + + // Clear bits 7,8 + usData &= ~0x0180; + + switch( duplex ) + { + case TRUEPHY_ADV_DUPLEX_NONE: + // Duplex already cleared, do nothing + break; + + case TRUEPHY_ADV_DUPLEX_FULL: + // Set Bit 8 + usData |= 0x0100; + break; + + case TRUEPHY_ADV_DUPLEX_HALF: + // Set Bit 7 + usData |= 0x0080; + break; + + case TRUEPHY_ADV_DUPLEX_BOTH: + default: + // Set Bits 7,8 + usData |= 0x0180; + break; + } + + // Write back advertisement + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_AUTO_ADVERTISEMENT, usData ); + + return; +} + + +void ET1310_PhyAdvertise10BaseT( ET131X_ADAPTER *pAdapter, UINT16 duplex ) +{ + UINT16 usData; + + // Read the Autonegotiation Register (10/100) + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_AUTO_ADVERTISEMENT, &usData ); + + // Clear bits 5,6 + usData &= ~0x0060; + + switch( duplex ) + { + case TRUEPHY_ADV_DUPLEX_NONE: + // Duplex already cleared, do nothing + break; + + case TRUEPHY_ADV_DUPLEX_FULL: + // Set Bit 6 + usData |= 0x0040; + break; + + case TRUEPHY_ADV_DUPLEX_HALF: + // Set Bit 5 + usData |= 0x0020; + break; + + case TRUEPHY_ADV_DUPLEX_BOTH: + default: + // Set Bits 5,6 + usData |= 0x0060; + break; + } + + // Write back advertisement + MiWrite( pAdapter, pAdapter->Stats.xcvr_addr, PHY_AUTO_ADVERTISEMENT, usData ); + + return; +} + + + + +void ET1310_PhyLinkStatus( ET131X_ADAPTER *pAdapter, + UCHAR *ucLinkStatus, + UINT32 *uiAutoNeg, + UINT32 *uiLinkSpeed, + UINT32 *uiDuplexMode, + UINT32 *uiMdiMdix, + UINT32 *uiMasterSlave, + UINT32 *uiPolarity ) +{ + UINT16 usMiStatus = 0; + UINT16 us1000BaseT = 0; + UINT16 usVmiPhyStatus = 0; + UINT16 usControl = 0; + + + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_STATUS, &usMiStatus ); + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_1000_STATUS, &us1000BaseT ); + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_PHY_STATUS, &usVmiPhyStatus ); + MiRead( pAdapter, pAdapter->Stats.xcvr_addr, PHY_CONTROL, &usControl ); + + if( ucLinkStatus ) + { + *ucLinkStatus = (unsigned char)(( usVmiPhyStatus & 0x0040 ) ? 1 : 0 ); + } + + if( uiAutoNeg ) + { + *uiAutoNeg = ( usControl & 0x1000 ) ? (( usVmiPhyStatus & 0x0020 ) ? TRUEPHY_ANEG_COMPLETE : TRUEPHY_ANEG_NOT_COMPLETE ) : TRUEPHY_ANEG_DISABLED; + } + + if( uiLinkSpeed ) + { + *uiLinkSpeed = ( usVmiPhyStatus & 0x0300 ) >> 8; + } + + if( uiDuplexMode ) + { + *uiDuplexMode = ( usVmiPhyStatus & 0x0080 ) >> 7; + } + + if( uiMdiMdix ) + { + /* NOTE: Need to complete this */ + *uiMdiMdix = 0; + } + + if( uiMasterSlave ) + { + *uiMasterSlave = ( us1000BaseT & 0x4000 ) ? TRUEPHY_CFG_MASTER : TRUEPHY_CFG_SLAVE; + } + + if( uiPolarity ) + { + *uiPolarity = ( usVmiPhyStatus & 0x0400 ) ? TRUEPHY_POLARITY_INVERTED : TRUEPHY_POLARITY_NORMAL; + } + + return; +} + + +void ET1310_PhyAndOrReg( ET131X_ADAPTER *pAdapter, + UINT16 regnum, + UINT16 andMask, + UINT16 orMask ) +{ + UINT16 reg; + + // Read the requested register + MiRead( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + regnum, ® ); + + // Apply the AND mask + reg &= andMask; + + // Apply the OR mask + reg |= orMask; + + // Write the value back to the register + MiWrite( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + regnum, reg ); + + return; +} + + +void ET1310_PhyAccessMiBit( ET131X_ADAPTER *pAdapter, + UINT16 action, + UINT16 regnum, + UINT16 bitnum, + UINT8 *value ) +{ + UINT16 reg; + UINT16 mask = 0; + + // Create a mask to isolate the requested bit + mask = 0x0001 << bitnum; + + // Read the requested register + MiRead( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, + regnum, ® ); + + switch( action ) + { + case TRUEPHY_BIT_READ: + if( value != NULL ) + { + *value = ( reg & mask ) >> bitnum; + } + + break; + + case TRUEPHY_BIT_SET: + reg |= mask; + MiWrite( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, regnum, reg ); + break; + + case TRUEPHY_BIT_CLEAR: + reg &= ~mask; + MiWrite( pAdapter, (UINT8)pAdapter->Stats.xcvr_addr, regnum, reg ); + break; + + default: + break; + } + + return; +} + --- linux-2.6.27.orig/ubuntu/et131x/ET1310_rx.c +++ linux-2.6.27/ubuntu/et131x/ET1310_rx.c @@ -0,0 +1,2056 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * ET1310_rx.c - Routines used to perform data reception + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2006/01/20 21:29:44 $ + $Revision: 1.21 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +/****************************************************************************** + Includes + *****************************************************************************/ +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include +#include +#include +#include +#include + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) +#include +#endif + +#include "ET1310_phy.h" +#include "ET1310_pm.h" +#include "ET1310_jagcore.h" + +#include "et131x_supp.h" +#include "et131x_adapter.h" +#include "et131x_initpci.h" + +#include "ET1310_rx.h" + + + + +/****************************************************************************** + Data for debugging facilities + *****************************************************************************/ +#ifdef ET131X_DBG +extern dbg_info_t *et131x_dbginfo; +#endif /* ET131X_DBG */ + + + + +/****************************************************************************** + Prototypes for functions local to this module + *****************************************************************************/ +void nic_return_rfd( ET131X_ADAPTER *pAdapter, PMP_RFD pMpRfd ); + + + + +/****************************************************************************** + ROUTINE : et131x_rx_dma_memory_alloc + ****************************************************************************** + + DESCRIPTION : Allocates Free buffer ring 1 for sure, free buffer ring + 0 if required, and the Packet Status Ring + + PARAMETERS : adapter - pointer to our private adapter structure + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_rx_dma_memory_alloc( ET131X_ADAPTER *adapter ) +{ + UINT32 OuterLoop, InnerLoop; + UINT32 bufsize; + UINT32 pktStatRingSize, FBRChunkSize; + RX_RING_t *rx_ring; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_rx_dma_memory_alloc" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Setup some convenience pointers + *************************************************************************/ + rx_ring = (RX_RING_t *)&adapter->RxRing; + + + /************************************************************************** + Alloc memory for the lookup table + *************************************************************************/ +#ifdef USE_FBR0 + rx_ring->Fbr[0] = kmalloc( sizeof( FBRLOOKUPTABLE ), GFP_KERNEL ); +#endif + + rx_ring->Fbr[1] = kmalloc( sizeof( FBRLOOKUPTABLE ), GFP_KERNEL ); + + + /************************************************************************** + The first thing we will do is configure the sizes of the buffer rings. + These will change based on jumbo packet support. Larger jumbo packets + increases the size of each entry in FBR0, and the number of entries in + FBR0, while at the same time decreasing the number of entries in FBR1. + + FBR1 holds "large" frames, FBR0 holds "small" frames. If FBR1 entries + are huge in order to accomodate a "jumbo" frame, then it will have less + entries. Conversely, FBR1 will now be relied upon to carry more + "normal" frames, thus it's entry size also increases and the number + of entries goes up too (since it now carries "small" + "regular" + packets. + + In this scheme, we try to maintain 512 entries between the two rings. + Also, FBR1 remains a constant size - when it's size doubles the + number of entries halves. FBR0 increases in size, however. + *************************************************************************/ + + if( adapter->RegistryJumboPacket < 2048 ) + { +#ifdef USE_FBR0 + rx_ring->Fbr0BufferSize = 256; + rx_ring->Fbr0NumEntries = 512; +#endif + rx_ring->Fbr1BufferSize = 2048; + rx_ring->Fbr1NumEntries = 512; + } + else if( adapter->RegistryJumboPacket < 4096 ) + { +#ifdef USE_FBR0 + rx_ring->Fbr0BufferSize = 512; + rx_ring->Fbr0NumEntries = 1024; +#endif + rx_ring->Fbr1BufferSize = 4096; + rx_ring->Fbr1NumEntries = 512; + } + else + { +#ifdef USE_FBR0 + rx_ring->Fbr0BufferSize = 1024; + rx_ring->Fbr0NumEntries = 768; +#endif + rx_ring->Fbr1BufferSize = 16384; + rx_ring->Fbr1NumEntries = 128; + } + +#ifdef USE_FBR0 + adapter->RxRing.PsrNumEntries = adapter->RxRing.Fbr0NumEntries + + adapter->RxRing.Fbr1NumEntries; +#else + adapter->RxRing.PsrNumEntries = adapter->RxRing.Fbr1NumEntries; +#endif + + + /************************************************************************** + Allocate an area of memory for Free Buffer Ring 1 + *************************************************************************/ + bufsize = ( sizeof( FBR_DESC_t ) * rx_ring->Fbr1NumEntries) + 0xfff; + rx_ring->pFbr1RingVa = pci_alloc_consistent( adapter->pdev, + bufsize, + &rx_ring->pFbr1RingPa ); + if( !rx_ring->pFbr1RingVa ) + { + DBG_ERROR( et131x_dbginfo, "Cannot alloc memory for Free Buffer Ring 1\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -ENOMEM; + } + + + /************************************************************************** + Save physical address + + NOTE : pci_alloc_consistent(), used above to alloc DMA regions, ALWAYS + returns SAC (32-bit) addresses. If DAC (64-bit) addresses are + ever returned, make sure the high part is retrieved here before + storing the adjusted address. + *************************************************************************/ + rx_ring->Fbr1Realpa = rx_ring->pFbr1RingPa; + + + /************************************************************************** + Align Free Buffer Ring 1 on a 4K boundary + *************************************************************************/ + et131x_align_allocated_memory( adapter, + &rx_ring->Fbr1Realpa, + &rx_ring->Fbr1offset, + 0x0FFF ); + + rx_ring->pFbr1RingVa = (void *)( (PUCHAR)rx_ring->pFbr1RingVa + + rx_ring->Fbr1offset ); + + +#ifdef USE_FBR0 + /************************************************************************** + Allocate an area of memory for Free Buffer Ring 0 + *************************************************************************/ + bufsize = ( sizeof( FBR_DESC_t ) * rx_ring->Fbr0NumEntries ) + 0xfff; + rx_ring->pFbr0RingVa = pci_alloc_consistent( adapter->pdev, + bufsize, + &rx_ring->pFbr0RingPa ); + if( !rx_ring->pFbr0RingVa ) + { + DBG_ERROR( et131x_dbginfo, "Cannot alloc memory for Free Buffer Ring 0\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -ENOMEM; + } + + + /************************************************************************** + Save physical address + + NOTE : pci_alloc_consistent(), used above to alloc DMA regions, ALWAYS + returns SAC (32-bit) addresses. If DAC (64-bit) addresses are + ever returned, make sure the high part is retrieved here before + storing the adjusted address. + *************************************************************************/ + rx_ring->Fbr0Realpa = rx_ring->pFbr0RingPa; + + + /************************************************************************** + Align Free Buffer Ring 0 on a 4K boundary + *************************************************************************/ + et131x_align_allocated_memory( adapter, + &rx_ring->Fbr0Realpa, + &rx_ring->Fbr0offset, + 0x0FFF ); + + rx_ring->pFbr0RingVa = (void *)( (PUCHAR)rx_ring->pFbr0RingVa + + rx_ring->Fbr0offset ); + +#endif + + + for( OuterLoop = 0; OuterLoop < (rx_ring->Fbr1NumEntries / FBR_CHUNKS); OuterLoop++ ) + { + UINT64 Fbr1Offset; + UINT64 Fbr1TempPa; + UINT32 Fbr1Align; + + /********************************************************************** + This code allocates an area of memory big enough for N free + buffers + (buffer_size - 1) so that the buffers can be aligned + on 4k boundaries. If each buffer were aligned + to a buffer_size boundary, the effect would be to double the size + of FBR0. By allocating N buffers at once, we reduce this overhead. + *********************************************************************/ + if( rx_ring->Fbr1BufferSize > 4096 ) + { + Fbr1Align = 4096; + } + else + { + Fbr1Align = rx_ring->Fbr1BufferSize; + } + + FBRChunkSize = ( FBR_CHUNKS * rx_ring->Fbr1BufferSize ) + Fbr1Align - 1; + rx_ring->Fbr1MemVa[OuterLoop] = pci_alloc_consistent( adapter->pdev, + FBRChunkSize, + &rx_ring->Fbr1MemPa[OuterLoop] ); + + if( !rx_ring->Fbr1MemVa[OuterLoop] ) + { + DBG_ERROR( et131x_dbginfo, "Could not alloc memory\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -ENOMEM; + } + + + /********************************************************************** + See NOTE in "Save Physical Address" comment above + *********************************************************************/ + Fbr1TempPa = rx_ring->Fbr1MemPa[OuterLoop]; + + et131x_align_allocated_memory( adapter, + &Fbr1TempPa, + &Fbr1Offset, + (Fbr1Align - 1)); + + + for( InnerLoop = 0; InnerLoop < FBR_CHUNKS; InnerLoop++ ) + { + UINT32 index = (OuterLoop * FBR_CHUNKS) + InnerLoop; + + + /****************************************************************** + Save the Virtual address of this index for quick access later + *****************************************************************/ + rx_ring->Fbr[1]->Va[index] = (PUCHAR)rx_ring->Fbr1MemVa[OuterLoop] + + ( InnerLoop * rx_ring->Fbr1BufferSize ) + + Fbr1Offset; + + + /****************************************************************** + now store the physical address in the descriptor so the device + can access it + *****************************************************************/ + rx_ring->Fbr[1]->PAHigh[index] = (UINT32)(Fbr1TempPa >> 32); + rx_ring->Fbr[1]->PALow[index] = (UINT32) Fbr1TempPa; + + Fbr1TempPa += rx_ring->Fbr1BufferSize; + + rx_ring->Fbr[1]->Buffer1[index] = rx_ring->Fbr[1]->Va[index]; + rx_ring->Fbr[1]->Buffer2[index] = rx_ring->Fbr[1]->Va[index] - 4; + } + } + +#ifdef USE_FBR0 + /************************************************************************** + Same for FBR0 (if in use) + *************************************************************************/ + for( OuterLoop = 0; OuterLoop < (rx_ring->Fbr0NumEntries / FBR_CHUNKS); OuterLoop++ ) + { + UINT64 Fbr0Offset; + UINT64 Fbr0TempPa; + + FBRChunkSize = (( FBR_CHUNKS + 1 ) * rx_ring->Fbr0BufferSize ) - 1; + rx_ring->Fbr0MemVa[OuterLoop] = pci_alloc_consistent( adapter->pdev, + FBRChunkSize, + &rx_ring->Fbr0MemPa[OuterLoop] ); + + if( !rx_ring->Fbr0MemVa[OuterLoop] ) + { + DBG_ERROR( et131x_dbginfo, "Could not alloc memory\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -ENOMEM; + } + + + /********************************************************************** + See NOTE in "Save Physical Address" comment above + *********************************************************************/ + Fbr0TempPa = rx_ring->Fbr0MemPa[OuterLoop]; + + et131x_align_allocated_memory( adapter, + &Fbr0TempPa, + &Fbr0Offset, + rx_ring->Fbr0BufferSize - 1 ); + + + for( InnerLoop = 0; InnerLoop < FBR_CHUNKS; InnerLoop++ ) + { + UINT32 index = (OuterLoop * FBR_CHUNKS) + InnerLoop; + + rx_ring->Fbr[0]->Va[index] = (PUCHAR)rx_ring->Fbr0MemVa[OuterLoop] + + ( InnerLoop * rx_ring->Fbr0BufferSize ) + + Fbr0Offset; + + rx_ring->Fbr[0]->PAHigh[index] = (UINT32)(Fbr0TempPa >> 32); + rx_ring->Fbr[0]->PALow[index] = (UINT32) Fbr0TempPa; + + Fbr0TempPa += rx_ring->Fbr0BufferSize; + + rx_ring->Fbr[0]->Buffer1[index] = rx_ring->Fbr[0]->Va[index]; + rx_ring->Fbr[0]->Buffer2[index] = rx_ring->Fbr[0]->Va[index] - 4; + } + } +#endif + + /************************************************************************** + Allocate an area of memory for the FIFO of Packet Status ring entries + *************************************************************************/ + pktStatRingSize = sizeof( PKT_STAT_DESC_t ) * adapter->RxRing.PsrNumEntries; + + rx_ring->pPSRingVa = pci_alloc_consistent( adapter->pdev, + pktStatRingSize + 0x0fff, + &rx_ring->pPSRingPa ); + + if( !rx_ring->pPSRingVa ) + { + DBG_ERROR( et131x_dbginfo, "Cannot alloc memory for Packet Status Ring\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -ENOMEM; + } + + + /************************************************************************** + Save physical address + + NOTE : pci_alloc_consistent(), used above to alloc DMA regions, ALWAYS + returns SAC (32-bit) addresses. If DAC (64-bit) addresses are + ever returned, make sure the high part is retrieved here before + storing the adjusted address. + *************************************************************************/ + rx_ring->pPSRingRealPa = rx_ring->pPSRingPa; + + + /************************************************************************** + Align Packet Status Ring on a 4K boundary + *************************************************************************/ + et131x_align_allocated_memory( adapter, + &rx_ring->pPSRingRealPa, + &rx_ring->pPSRingOffset, + 0x0FFF ); + + rx_ring->pPSRingVa = (void *)( (PUCHAR)rx_ring->pPSRingVa + + rx_ring->pPSRingOffset ); + + + /************************************************************************** + Allocate an area of memory for the writeback of status information + *************************************************************************/ + rx_ring->pRxStatusVa = pci_alloc_consistent( adapter->pdev, + sizeof( RX_STATUS_BLOCK_t ) + 0x7, + &rx_ring->pRxStatusPa ); + if( !rx_ring->pRxStatusVa ) + { + DBG_ERROR( et131x_dbginfo, "Cannot alloc memory for Status Block\n" ); + DBG_LEAVE( et131x_dbginfo ); + return -ENOMEM; + } + + + /************************************************************************** + Save physical address + *************************************************************************/ + rx_ring->RxStatusRealPA = rx_ring->pRxStatusPa; + + + /************************************************************************** + Align write back on an 8 byte boundary + *************************************************************************/ + et131x_align_allocated_memory( adapter, + &rx_ring->RxStatusRealPA, + &rx_ring->RxStatusOffset, + 0x07 ); + + rx_ring->pRxStatusVa = (void *)( (PUCHAR)rx_ring->pRxStatusVa + + rx_ring->RxStatusOffset ); + rx_ring->NumRfd = NIC_DEFAULT_NUM_RFD; + + + /************************************************************************** + Recv + pci_pool_create initializes a lookaside list. + After successful creation, nonpaged fixed-size blocks can be + allocated from and freed to the lookaside list. + + RFDs will be allocated from this pool. + *************************************************************************/ + rx_ring->RecvLookaside = + #if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)) + kmem_cache_create( adapter->netdev->name, + sizeof( MP_RFD ), + 0, + SLAB_CACHE_DMA | + SLAB_HWCACHE_ALIGN, + NULL, + NULL ); + #endif + #if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) + kmem_cache_create( adapter->netdev->name, + sizeof( MP_RFD ), + 0, + SLAB_CACHE_DMA | + SLAB_HWCACHE_ALIGN, + NULL); + #endif + + MP_SET_FLAG( adapter, fMP_ADAPTER_RECV_LOOKASIDE ); + + + /************************************************************************** + The RFDs are going to be put on lists later on, so initialize the lists + now. + *************************************************************************/ + INIT_LIST_HEAD( &rx_ring->RecvList ); + INIT_LIST_HEAD( &rx_ring->RecvPendingList ); + + + DBG_LEAVE( et131x_dbginfo ); + return 0; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_rx_dma_memory_free + ****************************************************************************** + + DESCRIPTION : Should basically free all memory allocated within this + module. + + PARAMETERS : adapter - pointer to our private adapter structure + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_rx_dma_memory_free( ET131X_ADAPTER *adapter ) +{ + UINT32 index; + UINT32 bufsize; + UINT32 pktStatRingSize; + PMP_RFD pMpRfd; + RX_RING_t *rx_ring; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_rx_dma_memory_free" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Setup some convenience pointers + *************************************************************************/ + rx_ring = (RX_RING_t *)&adapter->RxRing; + + + /************************************************************************** + Free RFDs and associated packet descriptors + *************************************************************************/ + DBG_ASSERT( rx_ring->nReadyRecv == rx_ring->NumRfd ); + + while( !list_empty( &rx_ring->RecvList )) + { + pMpRfd = (MP_RFD *)list_entry( rx_ring->RecvList.next, + MP_RFD, + list_node ); + + list_del( &pMpRfd->list_node ); + et131x_rfd_resources_free( adapter, pMpRfd ); + } + + while( !list_empty( &rx_ring->RecvPendingList )) + { + pMpRfd = (MP_RFD *)list_entry( rx_ring->RecvPendingList.next, + MP_RFD, + list_node ); + list_del( &pMpRfd->list_node ); + et131x_rfd_resources_free( adapter, pMpRfd ); + } + + + /************************************************************************** + Free Free Buffer Ring 1 + *************************************************************************/ + if( rx_ring->pFbr1RingVa ) + { + /********************************************************************** + First the packet memory + *********************************************************************/ + for( index = 0; index < + (rx_ring->Fbr1NumEntries / FBR_CHUNKS); index++ ) + { + if( rx_ring->Fbr1MemVa[index] ) + { + UINT32 Fbr1Align; + + if( rx_ring->Fbr1BufferSize > 4096 ) + { + Fbr1Align = 4096; + } + else + { + Fbr1Align = rx_ring->Fbr1BufferSize; + } + + bufsize = ( rx_ring->Fbr1BufferSize * FBR_CHUNKS ) + + Fbr1Align - 1; + + pci_free_consistent( adapter->pdev, + bufsize, + rx_ring->Fbr1MemVa[index], + rx_ring->Fbr1MemPa[index] ); + + rx_ring->Fbr1MemVa[index] = 0; + } + } + + + /********************************************************************** + Now the FIFO itself + *********************************************************************/ + rx_ring->pFbr1RingVa = (void *)( (PUCHAR)rx_ring->pFbr1RingVa - + rx_ring->Fbr1offset ); + + bufsize = ( sizeof( FBR_DESC_t ) * rx_ring->Fbr1NumEntries ) + 0xfff; + + pci_free_consistent( adapter->pdev, + bufsize, + rx_ring->pFbr1RingVa, + rx_ring->pFbr1RingPa ); + + rx_ring->pFbr1RingVa = NULL; + } + + +#ifdef USE_FBR0 + /********************************************************************** + Now the same for Free Buffer Ring 0 + *********************************************************************/ + if( rx_ring->pFbr0RingVa ) + { + /********************************************************************** + First the packet memory + *********************************************************************/ + for( index = 0; index < + (rx_ring->Fbr0NumEntries / FBR_CHUNKS); index++ ) + { + if( rx_ring->Fbr0MemVa[index] ) + { + bufsize = ( rx_ring->Fbr0BufferSize * ( FBR_CHUNKS + 1 )) - 1; + + pci_free_consistent( adapter->pdev, + bufsize, + rx_ring->Fbr0MemVa[index], + rx_ring->Fbr0MemPa[index] ); + + rx_ring->Fbr0MemVa[index] = 0; + } + } + + + /********************************************************************** + Now the FIFO itself + *********************************************************************/ + rx_ring->pFbr0RingVa = (void *)( (PUCHAR)rx_ring->pFbr0RingVa - + rx_ring->Fbr0offset ); + + bufsize = ( sizeof( FBR_DESC_t ) * rx_ring->Fbr0NumEntries ) + 0xfff; + + pci_free_consistent( adapter->pdev, + bufsize, + rx_ring->pFbr0RingVa, + rx_ring->pFbr0RingPa ); + + rx_ring->pFbr0RingVa = NULL; + } +#endif + + + /************************************************************************** + Free Packet Status Ring + *************************************************************************/ + if( rx_ring->pPSRingVa ) + { + rx_ring->pPSRingVa = (void *)( (PUCHAR)rx_ring->pPSRingVa - + rx_ring->pPSRingOffset ); + + pktStatRingSize = sizeof( PKT_STAT_DESC_t ) * adapter->RxRing.PsrNumEntries; + + pci_free_consistent( adapter->pdev, + pktStatRingSize + 0x0fff, + rx_ring->pPSRingVa, + rx_ring->pPSRingPa ); + + rx_ring->pPSRingVa = NULL; + } + + + /********************************************************************** + Free area of memory for the writeback of status information + *********************************************************************/ + if( rx_ring->pRxStatusVa ) + { + rx_ring->pRxStatusVa = (void *)( (PUCHAR)rx_ring->pRxStatusVa - + rx_ring->RxStatusOffset ); + + pci_free_consistent( adapter->pdev, + sizeof( RX_STATUS_BLOCK_t ) + 0x7, + rx_ring->pRxStatusVa, + rx_ring->pRxStatusPa ); + + rx_ring->pRxStatusVa = NULL; + } + + + /************************************************************************** + Free receive buffer pool + *************************************************************************/ + + + /************************************************************************** + Free receive packet pool + *************************************************************************/ + + + /************************************************************************** + Destroy the lookaside (RFD) pool + *************************************************************************/ + if( MP_TEST_FLAG( adapter, fMP_ADAPTER_RECV_LOOKASIDE )) + { + kmem_cache_destroy( rx_ring->RecvLookaside ); + MP_CLEAR_FLAG( adapter, fMP_ADAPTER_RECV_LOOKASIDE ); + } + + + /************************************************************************** + Free the FBR Lookup Table + *************************************************************************/ +#ifdef USE_FBR0 + kfree( rx_ring->Fbr[0] ); +#endif + + kfree( rx_ring->Fbr[1] ); + + + /************************************************************************** + Reset Counters + *************************************************************************/ + rx_ring->nReadyRecv = 0; + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_init_recv + ****************************************************************************** + + DESCRIPTION : Initialize receive data structures. + + PARAMETERS : adapter - pointer to our private adapter structure + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_init_recv( ET131X_ADAPTER *adapter ) +{ + int status = -ENOMEM; + PMP_RFD pMpRfd = NULL; + UINT32 RfdCount; + UINT32 TotalNumRfd = 0; + RX_RING_t *rx_ring = NULL; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_init_recv" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Setup some convenience pointers + *************************************************************************/ + rx_ring = (RX_RING_t *)&adapter->RxRing; + + + /************************************************************************** + Setup each RFD + *************************************************************************/ + for( RfdCount = 0; RfdCount < rx_ring->NumRfd; RfdCount++ ) + { + pMpRfd = ( MP_RFD * )kmem_cache_alloc( rx_ring->RecvLookaside, + GFP_ATOMIC | GFP_DMA ); + + if( !pMpRfd ) + { + DBG_ERROR( et131x_dbginfo, "Couldn't alloc RFD out of kmem_cache\n" ); + + status = -ENOMEM; + continue; + } + + status = et131x_rfd_resources_alloc( adapter,pMpRfd ); + if( status != 0 ) + { + DBG_ERROR( et131x_dbginfo, "Couldn't alloc packet for RFD\n" ); + kmem_cache_free( rx_ring->RecvLookaside, pMpRfd ); + continue; + } + + + /********************************************************************** + Add this RFD to the RecvList + *********************************************************************/ + list_add_tail( &pMpRfd->list_node, &rx_ring->RecvList ); + + + /********************************************************************** + Increment both the available RFD's, and the total RFD's. + *********************************************************************/ + rx_ring->nReadyRecv++; + TotalNumRfd++; + } + + if( TotalNumRfd > NIC_MIN_NUM_RFD ) + { + status = 0; + } + + rx_ring->NumRfd = TotalNumRfd; + + if( status != 0 ) + { + kmem_cache_free( rx_ring->RecvLookaside, pMpRfd ); + DBG_ERROR( et131x_dbginfo, "Allocation problems in et131x_init_recv\n" ); + } + + + DBG_LEAVE( et131x_dbginfo ); + return status; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_rfd_resources_alloc + ****************************************************************************** + + DESCRIPTION : + + PARAMETERS : adapter - pointer to our private adapter structure + pMpRfd - pointer to a RFD + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_rfd_resources_alloc( ET131X_ADAPTER *adapter, MP_RFD *pMpRfd ) +{ + pMpRfd->Packet = NULL; + + return 0; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_rfd_resources_free + ****************************************************************************** + + DESCRIPTION : Free the packet allocated for the given RFD + + PARAMETERS : adapter - pointer to our private adapter structure + pMpRfd - pointer to a RFD + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_rfd_resources_free( ET131X_ADAPTER *adapter, MP_RFD *pMpRfd ) +{ + pMpRfd->Packet = NULL; + kmem_cache_free( adapter->RxRing.RecvLookaside, pMpRfd ); + + return; +} +/*===========================================================================*/ + + + + + +/****************************************************************************** + ROUTINE: ConfigRxDmaRegs + ****************************************************************************** + DESCRIPTION: + START OF Rx_DMA INIT SEQUENCE + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + + + *****************************************************************************/ +void ConfigRxDmaRegs( ET131X_ADAPTER *pAdapter ) +{ + PRXDMA_t pRxDma; + PFBR_DESC_t pFbrEntry; + UINT32 iEntry; + unsigned long lockflags; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "ConfigRxDmaRegs" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Let's get our pointer to the RxDma section of regs + *************************************************************************/ + pRxDma = &pAdapter->CSRAddress->rxdma; + + + /************************************************************************** + Halt RXDMA to perform the reconfigure. + *************************************************************************/ + et131x_rx_dma_disable( pAdapter ); + + + /************************************************************************** + Load the completion writeback physical address + + NOTE : pci_alloc_consistent(), used above to alloc DMA regions, ALWAYS + returns SAC (32-bit) addresses. If DAC (64-bit) addresses are + ever returned, make sure the high part is retrieved here before + storing the adjusted address. + *************************************************************************/ + pRxDma->dma_wb_base_hi.addr_hi = (UINT32)( pAdapter->RxRing.RxStatusRealPA >> 32 ); + pRxDma->dma_wb_base_lo.addr_lo = (UINT32)( pAdapter->RxRing.RxStatusRealPA ); + + memset( pAdapter->RxRing.pRxStatusVa, 0, sizeof( RX_STATUS_BLOCK_t )); + + + /************************************************************************** + Set the address and parameters of the packet status ring into the 1310's + registers + *************************************************************************/ + pRxDma->psr_base_hi.addr_hi = (UINT32)( pAdapter->RxRing.pPSRingRealPa >> 32 ); + pRxDma->psr_base_lo.addr_lo = (UINT32)( pAdapter->RxRing.pPSRingRealPa ); + + pRxDma->psr_num_des.value = pAdapter->RxRing.PsrNumEntries - 1; + + pRxDma->psr_full_offset.value = 0; + + pRxDma->psr_min_des.value = + ( pRxDma->psr_num_des.bits.psr_ndes * LO_MARK_PERCENT_FOR_PSR ) / 100; + + spin_lock_irqsave( &pAdapter->RcvLock, lockflags ); + + + /************************************************************************** + These local variables track the PSR in the adapter structure + *************************************************************************/ + pAdapter->RxRing.local_psr_full.bits.psr_full = 0; + pAdapter->RxRing.local_psr_full.bits.psr_full_wrap = 0; + + + /************************************************************************** + Now's the best time to initialize FBR1 contents + *************************************************************************/ + pFbrEntry = (PFBR_DESC_t) pAdapter->RxRing.pFbr1RingVa; + + for (iEntry=0; iEntry < pAdapter->RxRing.Fbr1NumEntries; iEntry++) + { + pFbrEntry->addr_hi = pAdapter->RxRing.Fbr[1]->PAHigh[ iEntry ]; + pFbrEntry->addr_lo = pAdapter->RxRing.Fbr[1]->PALow [ iEntry ]; + pFbrEntry->word2.bits.bi = iEntry; + pFbrEntry++; + } + + + /************************************************************************** + Set the address and parameters of Free buffer ring 1 (and 0 if required) + into the 1310's registers + *************************************************************************/ + pRxDma->fbr1_base_hi.addr_hi = (UINT32)( pAdapter->RxRing.Fbr1Realpa >> 32 ); + pRxDma->fbr1_base_lo.addr_lo = (UINT32)( pAdapter->RxRing.Fbr1Realpa ); + + pRxDma->fbr1_num_des.value = pAdapter->RxRing.Fbr1NumEntries - 1; + + { + RXDMA_FBR_FULL_OFFSET_t fbr1_full; + + fbr1_full.bits.fbr_full = 0; + fbr1_full.bits.fbr_full_wrap = 1; + + pRxDma->fbr1_full_offset = fbr1_full; + } + + + /************************************************************************** + This variable tracks the free buffer ring 1 full position, so it has to + match the above. + *************************************************************************/ + pAdapter->RxRing.local_Fbr1_full.bits.fbr_full = 0; + pAdapter->RxRing.local_Fbr1_full.bits.fbr_full_wrap = 1; + + pRxDma->fbr1_min_des.bits.fbr_min = + (( pAdapter->RxRing.Fbr1NumEntries * LO_MARK_PERCENT_FOR_RX ) / 100) - 1; + + +#ifdef USE_FBR0 + /************************************************************************** + Now's the best time to initialize FBR0 contents + *************************************************************************/ + pFbrEntry = (PFBR_DESC_t) pAdapter->RxRing.pFbr0RingVa; + + for (iEntry=0; iEntry < pAdapter->RxRing.Fbr0NumEntries; iEntry++) + { + pFbrEntry->addr_hi = pAdapter->RxRing.Fbr[0]->PAHigh[iEntry]; + pFbrEntry->addr_lo = pAdapter->RxRing.Fbr[0]->PALow [iEntry]; + pFbrEntry->word2.bits.bi = iEntry; + pFbrEntry++; + } + + pRxDma->fbr0_base_hi.addr_hi = (UINT32)( pAdapter->RxRing.Fbr0Realpa >> 32 ); + pRxDma->fbr0_base_lo.addr_lo = (UINT32)( pAdapter->RxRing.Fbr0Realpa ); + + pRxDma->fbr0_num_des.bits.fbr_ndesc = pAdapter->RxRing.Fbr0NumEntries - 1; + + { + RXDMA_FBR_FULL_OFFSET_t fbr0_full; + + fbr0_full.bits.fbr_full = 0; + fbr0_full.bits.fbr_full_wrap = 1; + + pRxDma->fbr0_full_offset = fbr0_full; + } + + + /************************************************************************** + This variable tracks the free buffer ring 0 full position, so it has to + match the above. + *************************************************************************/ + pAdapter->RxRing.local_Fbr0_full.bits.fbr_full = 0; + pAdapter->RxRing.local_Fbr0_full.bits.fbr_full_wrap = 1; + + pRxDma->fbr0_min_des.bits.fbr_min = + (( pAdapter->RxRing.Fbr0NumEntries * LO_MARK_PERCENT_FOR_RX ) / 100) - 1; +#endif + + + /************************************************************************** + Program the number of packets we will receive before generating an + interrupt. + + For version B silicon, this value gets updated once autoneg is complete. + *************************************************************************/ + pRxDma->num_pkt_done.value = pAdapter->RegistryRxNumBuffers; + + + /************************************************************************** + The "time_done" is not working correctly to coalesce interrupts after + a given time period, but rather is giving us an interrupt regardless + of whether we have received packets. + + This value gets updated once autoneg is complete. + *************************************************************************/ + pRxDma->max_pkt_time.value = pAdapter->RegistryRxTimeInterval; + + spin_unlock_irqrestore( &pAdapter->RcvLock, lockflags ); + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: SetRxDmaTimer + ****************************************************************************** + DESCRIPTION: + SET the heartbeat timer according to line rate. + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + N/A + + *****************************************************************************/ +void SetRxDmaTimer( ET131X_ADAPTER *pAdapter ) +{ + /************************************************************************** + For version B silicon, we do not use the RxDMA timer for 10 and 100 + Mbits/s line rates. We do not enable and RxDMA interrupt coalescing. + *************************************************************************/ + if(( pAdapter->uiLinkSpeed == TRUEPHY_SPEED_100MBPS ) || + ( pAdapter->uiLinkSpeed == TRUEPHY_SPEED_10MBPS )) + { + pAdapter->CSRAddress->rxdma.max_pkt_time.value = 0; + pAdapter->CSRAddress->rxdma.num_pkt_done.value = 1; + } + + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: et131x_rx_dma_disable + ****************************************************************************** + DESCRIPTION: + Stop OF Rx_DMA on the ET1310 + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + + + *****************************************************************************/ +void et131x_rx_dma_disable( ET131X_ADAPTER *pAdapter ) +{ + DBG_FUNC( "et131x_rx_dma_disable" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Setup the receive dma configuration register + *************************************************************************/ + pAdapter->CSRAddress->rxdma.csr.value = 0x00002001; + + if( pAdapter->CSRAddress->rxdma.csr.bits.halt_status != 1 ) + { + udelay( 5 ); + if( pAdapter->CSRAddress->rxdma.csr.bits.halt_status != 1 ) + { + DBG_ERROR( et131x_dbginfo, + "RX Dma failed to enter halt state. CSR 0x%08x\n", + pAdapter->CSRAddress->rxdma.csr.value ); + } + } + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: et131x_rx_dma_enable + ****************************************************************************** + DESCRIPTION: + re-start OF Rx_DMA on the ET1310. + + PARAMETERS : + pAdapter - pointer to our adapter structure + + RETURNS : + + + *****************************************************************************/ +void et131x_rx_dma_enable( ET131X_ADAPTER *pAdapter ) +{ + DBG_FUNC( "et131x_rx_dma_enable" ); + DBG_RX_ENTER( et131x_dbginfo ); + + + if( pAdapter->RegistryPhyLoopbk ) + { + /********************************************************************** + RxDMA is disabled for loopback operation. + *********************************************************************/ + pAdapter->CSRAddress->rxdma.csr.value = 0x1; + } + else + { + /********************************************************************** + Setup the receive dma configuration register for normal operation. + *********************************************************************/ + { + RXDMA_CSR_t csr = {0}; + + csr.bits.fbr1_enable = 1; + + if( pAdapter->RxRing.Fbr1BufferSize == 4096 ) + { + csr.bits.fbr1_size = 1; + } + else if( pAdapter->RxRing.Fbr1BufferSize == 8192 ) + { + csr.bits.fbr1_size = 2; + } + else if( pAdapter->RxRing.Fbr1BufferSize == 16384 ) + { + csr.bits.fbr1_size = 3; + } +#ifdef USE_FBR0 + csr.bits.fbr0_enable = 1; + + if( pAdapter->RxRing.Fbr0BufferSize == 256 ) + { + csr.bits.fbr0_size = 1; + } + else if( pAdapter->RxRing.Fbr0BufferSize == 512 ) + { + csr.bits.fbr0_size = 2; + } + else if( pAdapter->RxRing.Fbr0BufferSize == 1024 ) + { + csr.bits.fbr0_size = 3; + } +#endif + pAdapter->CSRAddress->rxdma.csr = csr; + } + + if( pAdapter->CSRAddress->rxdma.csr.bits.halt_status != 0 ) + { + udelay( 5 ); + if( pAdapter->CSRAddress->rxdma.csr.bits.halt_status != 0 ) + { + DBG_ERROR( et131x_dbginfo, + "RX Dma failed to exit halt state. CSR 0x%08x\n", + pAdapter->CSRAddress->rxdma.csr.value ); + } + } + } + + + DBG_RX_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: nic_rx_pkts + ****************************************************************************** + DESCRIPTION: + Checks the hardware for available packets, using completion ring + If packets are available, it gets an RFD from the RecvList, attaches + the packet to it, puts the RFD in the RecvPendList, and also returns + the pointer to the RFD. + + PARAMETERS : + pAdapter - pointer to our adapter + + RETURNS : + pMpRfd - pointer to our MPRFD + + *****************************************************************************/ +PMP_RFD nic_rx_pkts( ET131X_ADAPTER *pAdapter ) +{ + PRX_STATUS_BLOCK_t pRxStatusBlock; + PPKT_STAT_DESC_t pPSREntry; + PMP_RFD pMpRfd; + UINT32 nIndex; + PUCHAR pBufVa; + PUINT16 pShBufVa; + unsigned long lockflags; + struct list_head *element; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "nic_rx_pkts" ); + DBG_RX_ENTER( et131x_dbginfo ); + + + /************************************************************************** + RX Status block is written by the DMA engine prior to every interrupt. + It contains the next to be used entry in the Packet Status Ring, and + also the two Free Buffer rings. + *************************************************************************/ + pRxStatusBlock = (PRX_STATUS_BLOCK_t)pAdapter->RxRing.pRxStatusVa; + + if(( pRxStatusBlock->Word1.bits.PSRoffset != + pAdapter->RxRing.local_psr_full.bits.psr_full ) || + ( pRxStatusBlock->Word1.bits.PSRwrap != + pAdapter->RxRing.local_psr_full.bits.psr_full_wrap )) + { + UINT8 ringIndex; + UINT16 bufferIndex; + UINT32 localLen; + PKT_STAT_DESC_WORD0_t Word0; + + + /********************************************************************** + The packet status ring indicates that data is available. + *********************************************************************/ + pPSREntry = (PPKT_STAT_DESC_t)( pAdapter->RxRing.pPSRingVa ) + + pAdapter->RxRing.local_psr_full.bits.psr_full; + + + /********************************************************************** + Grab any information that is required once the PSR is advanced, + since we can no longer rely on the memory being accurate + *********************************************************************/ + localLen = pPSREntry->word1.bits.length; + ringIndex = (UINT8)pPSREntry->word1.bits.ri; + bufferIndex = (UINT16)pPSREntry->word1.bits.bi; + Word0 = pPSREntry->word0; + + DBG_RX( et131x_dbginfo, "RX PACKET STATUS\n" ); + DBG_RX( et131x_dbginfo, "\tlength : %d\n", localLen ); + DBG_RX( et131x_dbginfo, "\tringIndex : %d\n", ringIndex ); + DBG_RX( et131x_dbginfo, "\tbufferIndex : %d\n", bufferIndex ); + DBG_RX( et131x_dbginfo, "\tword0 : 0x%08x\n", Word0.value ); + + +#if 0 + /********************************************************************** + Check the Status Word that the MAC has appended to the PSR entry in + case the MAC has detected errors. + *********************************************************************/ + if( Word0.value & ALCATEL_BAD_STATUS ) + { + DBG_ERROR( et131x_dbginfo, + "NICRxPkts >> Alcatel Status Word error." + "Value 0x%08x\n", + pPSREntry->word0.value ); + } +#endif + + + /********************************************************************** + Indicate that we have used this PSR entry. + *********************************************************************/ + if( ++pAdapter->RxRing.local_psr_full.bits.psr_full > + ( pAdapter->RxRing.PsrNumEntries - 1 )) + { + pAdapter->RxRing.local_psr_full.bits.psr_full = 0; + pAdapter->RxRing.local_psr_full.bits.psr_full_wrap ^= 1; + } + + pAdapter->CSRAddress->rxdma.psr_full_offset = + pAdapter->RxRing.local_psr_full; + +#ifndef USE_FBR0 + if( ringIndex != 1 ) + { + DBG_ERROR( et131x_dbginfo, + "NICRxPkts PSR Entry %d indicates " + "Buffer Ring 0 in use\n", + pAdapter->RxRing.local_psr_full.bits.psr_full ); + + DBG_RX_LEAVE( et131x_dbginfo ); + return NULL; + } +#endif + +#ifdef USE_FBR0 + if(( ringIndex > 1 ) || + (( ringIndex == 0 ) && ( bufferIndex > ( pAdapter->RxRing.Fbr0NumEntries - 1 ))) || + (( ringIndex == 1 ) && ( bufferIndex > ( pAdapter->RxRing.Fbr1NumEntries - 1 )))) +#else + if(( ringIndex != 1 ) || ( bufferIndex > ( pAdapter->RxRing.Fbr1NumEntries - 1 ))) +#endif + { + /****************************************************************** + Illegal buffer or ring index cannot be used by the S/W + *****************************************************************/ + DBG_ERROR( et131x_dbginfo, + "NICRxPkts PSR Entry %d indicates " + "length of %d and/or bad bi(%d)\n", + pAdapter->RxRing.local_psr_full.bits.psr_full, + localLen, + bufferIndex ); + + DBG_RX_LEAVE( et131x_dbginfo ); + return NULL; + } + + + /********************************************************************** + Get and fill the RFD. + *********************************************************************/ + spin_lock_irqsave( &pAdapter->RcvLock, lockflags ); + + pMpRfd = NULL; + element = pAdapter->RxRing.RecvList.next; + pMpRfd = (PMP_RFD)list_entry( element, MP_RFD, list_node ); + + if( pMpRfd == NULL ) + { + DBG_RX( et131x_dbginfo, + "NULL RFD returned from RecvList via list_entry()\n" ); + DBG_RX_LEAVE( et131x_dbginfo ); + return NULL; + } + + list_del( &pMpRfd->list_node ); + pAdapter->RxRing.nReadyRecv--; + + spin_unlock_irqrestore( &pAdapter->RcvLock, lockflags ); + + pMpRfd->iBufferIndex = bufferIndex; + pMpRfd->iRingIndex = ringIndex; + + + /********************************************************************** + In V1 silicon, there is a bug which screws up filtering of runt + packets. Therefore runt packet filtering is disabled in the MAC + and the packets are dropped here. They are also counted here. + *********************************************************************/ + if( localLen < ( NIC_MIN_PACKET_SIZE + 4 )) + { + pAdapter->Stats.other_errors++; + localLen = 0; + } + + +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) + if( localLen ) + { + pShBufVa = pAdapter->RxRing.Fbr[ringIndex]->Va[bufferIndex]; + + pMpRfd->bHasVLANTag = FALSE; + + + /****************************************************************** + The protocol value of 0x8100 means there is a VLAN tag in the + packet. Also the original protocol value will be present four + bytes further on. + *****************************************************************/ + if( pShBufVa[6] == 0x0081 ) + { + UINT16 LocalShort = (( pShBufVa[7] & 0xff00 ) >> 8 ) + + (( pShBufVa[7] & 0x00ff ) << 8 ); + UINT16 vlan_tag = LocalShort & 0x0fff; + + pMpRfd->bHasVLANTag = TRUE; + + DBG_RX( et131x_dbginfo, + "VLAN: RX packet Tag: %d\n", vlan_tag ); + + + /************************************************************** + The rules are: + - if our VLAN tag is zero we can pass anything up + - if our VLAN tag matches the incoming we can pass it + - If the packet is a protocol 802.3ad we pass it + regardless (802.3ad had protocol val of 0x8809. + proto val is now in ShBuf [8]) + - If the packet is a GARP VLAN Registration Protocol + (GVRP) packet, we pass it regardless. + 01:80:c2:00:00:21 is the GVRP address. + + NOTE: Because the ET1310 doesn't perform VLAN tagging + (it's done in the kernel) always pass packets up. + We'll leave this code in, however, just in case it's + needed in the future. + *************************************************************/ + if(( 1 ) || + ( pShBufVa[8] == 0x0988 ) || + (( pShBufVa[0] == 0x8001 ) && + ( pShBufVa[1] == 0x00c2 ) && + ( pShBufVa[2] == 0x2100 ))) + { + DBG_RX( et131x_dbginfo, + "VLAN: Passed test, send pkt up\n" ); + pMpRfd->VLANTag = vlan_tag; + } + else + { + /********************************************************* + Our VLAN tag is non-zero, AND the incoming tag does + not match it. Drop the packet. + ********************************************************/ + DBG_RX( et131x_dbginfo, + "VLAN: no match, drop pkt\n" ); + localLen = 0; + } + } + else if(( pShBufVa[6] == 0x0988 ) || + (( pShBufVa[0] == 0x8001 ) && + ( pShBufVa[1] == 0x00c2 ) && + ( pShBufVa[2] == 0x2100 ))) + { + /****************************************************************** + The protocol type (ethertype) of 0x8809 corresponds to 802.3ad + The MAC address of 01:80:c2:00:00:21 is the GARP VLAN + registration protocol (GVRP) address. + + Both of these message types should be passed up regardless + of their VLAN tagging. + *****************************************************************/ + DBG_RX( et131x_dbginfo, + "VLAN: No tag, but 802.3ad/GVRP, send pkt up\n" ); + } + else + { + /****************************************************************** + Our VLAN tag is non-zero. no VLAN header on incoming. + Packet is not GVRP or 802.3ad. Drop the packet. + *****************************************************************/ + DBG_RX( et131x_dbginfo, + "VLAN: No RX packet tag\n" ); + // NOTE: Same as the note above; never drop a packet for now. + // localLen = 0; + } + } +#endif + + if( localLen ) + { + if ( pAdapter->ReplicaPhyLoopbk == 1 ) + { + pBufVa = pAdapter->RxRing.Fbr[ringIndex]->Va[bufferIndex]; + + if( memcmp( &pBufVa[6], &pAdapter->CurrentAddress[0], ETH_ALEN ) == 0 ) + { + if( memcmp( &pBufVa[42], "Replica packet", ETH_HLEN )) + { + pAdapter->ReplicaPhyLoopbkPF = 1; + } + } + DBG_WARNING( et131x_dbginfo, + "pBufVa:\t%02x:%02x:%02x:%02x:%02x:%02x\n", + pBufVa[6], + pBufVa[7], + pBufVa[8], + pBufVa[9], + pBufVa[10], + pBufVa[11] ); + + DBG_WARNING( et131x_dbginfo, + "CurrentAddr:\t%02x:%02x:%02x:%02x:%02x:%02x\n", + pAdapter->CurrentAddress[0], + pAdapter->CurrentAddress[1], + pAdapter->CurrentAddress[2], + pAdapter->CurrentAddress[3], + pAdapter->CurrentAddress[4], + pAdapter->CurrentAddress[5] ); + } + + /****************************************************************** + Determine if this is a multicast packet coming in + *****************************************************************/ + if(( Word0.value & ALCATEL_MULTICAST_PKT ) && + !( Word0.value & ALCATEL_BROADCAST_PKT )) + { + /************************************************************** + Promiscuous mode and Multicast mode are not mutually + exclusive as was first thought. I guess Promiscuous is + just considered a super-set of the other filters. + Generally filter is 0x2b when in promiscuous mode. + *************************************************************/ + if(( pAdapter->PacketFilter & ET131X_PACKET_TYPE_MULTICAST ) && + !( pAdapter->PacketFilter & ET131X_PACKET_TYPE_PROMISCUOUS ) && + !( pAdapter->PacketFilter & ET131X_PACKET_TYPE_ALL_MULTICAST )) + { + pBufVa = pAdapter->RxRing.Fbr[ringIndex]->Va[bufferIndex]; + + /********************************************************** + Loop through our list to see if the destination address + of this packet matches one in our list. + *********************************************************/ + for( nIndex = 0; nIndex < pAdapter->MCAddressCount; nIndex++ ) + { + if( pBufVa[0] == pAdapter->MCList[nIndex][0] && + pBufVa[1] == pAdapter->MCList[nIndex][1] && + pBufVa[2] == pAdapter->MCList[nIndex][2] && + pBufVa[3] == pAdapter->MCList[nIndex][3] && + pBufVa[4] == pAdapter->MCList[nIndex][4] && + pBufVa[5] == pAdapter->MCList[nIndex][5] ) + { + break; + } + } + + /********************************************************** + If our index is equal to the number of Multicast + address we have, then this means we did not find this + packet's matching address in our list. Set the + PacketSize to zero, so we free our RFD when we return + from this function. + *********************************************************/ + if( nIndex == pAdapter->MCAddressCount ) + { + localLen = 0; + } + } + + if( localLen > 0 ) + { + pAdapter->Stats.multircv++; + } + } + else if( Word0.value & ALCATEL_BROADCAST_PKT ) + { + pAdapter->Stats.brdcstrcv++; + } + else + { + /************************************************************** + Not sure what this counter measures in promiscuous mode. + Perhaps we should check the MAC address to see if it is + directed to us in promiscuous mode. + *************************************************************/ + pAdapter->Stats.unircv++; + } + } + + if( localLen > 0 ) + { + struct sk_buff *skb = NULL; + +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) +#ifdef __vlan_get_tag + unsigned short vlan_tag = 0; +#endif +#endif + + //vlan_tag = 0; + + //pMpRfd->PacketSize = localLen - 4; + pMpRfd->PacketSize = localLen; + + skb = dev_alloc_skb( pMpRfd->PacketSize + 2 ); + if( !skb ) + { + DBG_ERROR( et131x_dbginfo, "Couldn't alloc an SKB for Rx\n" ); + DBG_RX_LEAVE( et131x_dbginfo ); + return NULL; + } + + pAdapter->net_stats.rx_bytes += pMpRfd->PacketSize; + + memcpy( skb_put( skb, pMpRfd->PacketSize ), + pAdapter->RxRing.Fbr[ringIndex]->Va[bufferIndex], + pMpRfd->PacketSize ); + + skb->dev = pAdapter->netdev; + skb->protocol = eth_type_trans( skb, pAdapter->netdev ); + skb->ip_summed = CHECKSUM_NONE; + + +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) +#if defined __vlan_get_tag + if( __vlan_get_tag( skb, &vlan_tag ) == -EINVAL ) + { + DBG_RX( et131x_dbginfo, + "VLAN: No Rx packet tag\n" ); + } + else + { + DBG_RX( et131x_dbginfo, + "VLAN: Rx packet tag: %d\n", vlan_tag ); + } +#endif +#endif + + netif_rx( skb ); + } + else + { + pMpRfd->PacketSize = 0; + } + + nic_return_rfd( pAdapter, pMpRfd ); + + + DBG_RX( et131x_dbginfo, "(1)\n" ); + DBG_RX_LEAVE( et131x_dbginfo ); + return pMpRfd; + } + else + { + /********************************************************************** + Looks like this ring is not updated yet + *********************************************************************/ + DBG_RX( et131x_dbginfo, "(0)\n" ); + DBG_RX_LEAVE( et131x_dbginfo ); + return NULL; + } +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: et131x_reset_recv + ****************************************************************************** + DESCRIPTION: + Reset the receive list + + Assumption: Rcv spinlock has been acquired + + PARAMETERS : + pAdapter - pointer to our adapter + + RETURNS : + NONE + + *****************************************************************************/ +void et131x_reset_recv( ET131X_ADAPTER *pAdapter ) +{ + PMP_RFD pMpRfd; + struct list_head *element; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_reset_recv" ); + DBG_ENTER( et131x_dbginfo ); + + + DBG_ASSERT( !list_empty( &pAdapter->RxRing.RecvList )); + + + /************************************************************************** + Take all the RFD's from the pending list, and stick them on the + RecvList. + *************************************************************************/ + while( !list_empty( &pAdapter->RxRing.RecvPendingList ) ) + { + element = pAdapter->RxRing.RecvPendingList.next; + + pMpRfd = (PMP_RFD)list_entry( element, MP_RFD, list_node ); + + list_del( &pMpRfd->list_node ); + list_add_tail( &pMpRfd->list_node, &pAdapter->RxRing.RecvList ); + } + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: et131x_handle_recv_interrupt + ****************************************************************************** + DESCRIPTION: + Interrupt handler for receive processing + + Assumption: Rcv spinlock has been acquired + + PARAMETERS : + pAdapter - pointer to our adapter + + RETURNS : + NONE + + *****************************************************************************/ +void et131x_handle_recv_interrupt( ET131X_ADAPTER *pAdapter ) +{ + PMP_RFD pMpRfd = NULL; + struct sk_buff *PacketArray [NUM_PACKETS_HANDLED]; + PMP_RFD RFDFreeArray[NUM_PACKETS_HANDLED]; + UINT32 PacketArrayCount = 0; + UINT32 PacketsToHandle; + UINT32 PacketFreeCount = 0; + BOOL_t TempUnfinishedRec = FALSE; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_handle_recv_interrupt" ); + DBG_RX_ENTER( et131x_dbginfo ); + + + PacketsToHandle = NUM_PACKETS_HANDLED; + + + /************************************************************************** + Process up to available RFD's + *************************************************************************/ + while( PacketArrayCount < PacketsToHandle ) + { + if( list_empty( &pAdapter->RxRing.RecvList )) + { + DBG_ASSERT( pAdapter->RxRing.nReadyRecv == 0 ); + DBG_ERROR( et131x_dbginfo, "NO RFD's !!!!!!!!!!!!!\n" ); + TempUnfinishedRec = TRUE; + break; + } + + pMpRfd = nic_rx_pkts( pAdapter ); + + if( pMpRfd == NULL) + { + break; + } + + + /********************************************************************** + Do not receive any packets until a filter has been set. + Do not receive any packets until we are at D0. + Do not receive any packets until we have link. + If length is zero, return the RFD in order to advance the Free + buffer ring. + *********************************************************************/ + if(( !pAdapter->PacketFilter ) || + ( pAdapter->PoMgmt.PowerState != NdisDeviceStateD0 ) || + ( !MP_LINK_DETECTED( pAdapter )) || + ( pMpRfd->PacketSize == 0 )) + { + continue; + } + + + /********************************************************************** + Increment the number of packets we received + *********************************************************************/ + pAdapter->Stats.ipackets++; + + + /********************************************************************** + Set the status on the packet, either resources or success + *********************************************************************/ + if( pAdapter->RxRing.nReadyRecv >= RFD_LOW_WATER_MARK ) + { + /****************************************************************** + Put this RFD on the pending list + + NOTE - nic_rx_pkts() above is already returning the RFD to the + RecvList, so don't additionally do that here. + + Besides, we don't really need (at this point) the pending list + anyway. + *****************************************************************/ + //spin_lock_irqsave( &pAdapter->RcvPendLock, lockflags ); + //list_add_tail( &pMpRfd->list_node, &pAdapter->RxRing.RecvPendingList ); + //spin_unlock_irqrestore( &pAdapter->RcvPendLock, lockflags ); + + + /****************************************************************** + Update the number of outstanding Recvs + *****************************************************************/ + //MP_INC_RCV_REF( pAdapter ); + } + else + { + RFDFreeArray[PacketFreeCount] = pMpRfd; + PacketFreeCount++; + + DBG_WARNING( et131x_dbginfo, "RFD's are running out !!!!!!!!!!!!!\n" ); + } + + PacketArray[PacketArrayCount] = pMpRfd->Packet; + PacketArrayCount++; + } + + + if(( PacketArrayCount == NUM_PACKETS_HANDLED ) || TempUnfinishedRec ) + { + pAdapter->RxRing.UnfinishedReceives = TRUE; + pAdapter->CSRAddress->global.watchdog_timer = + pAdapter->RegistryTxTimeInterval * NANO_IN_A_MICRO; + } + else + { + /********************************************************************** + Watchdog timer will disable itself if appropriate. + *********************************************************************/ + pAdapter->RxRing.UnfinishedReceives = FALSE; + } + + + DBG_RX_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE: NICReturnRFD + ****************************************************************************** + DESCRIPTION: + Recycle a RFD and put it back onto the receive list + + PARAMETERS : + pAdapter - pointer to our adapter + pMpRfd - pointer to the RFD + + RETURNS : + NONE + + *****************************************************************************/ +void nic_return_rfd( ET131X_ADAPTER *pAdapter, PMP_RFD pMpRfd ) +{ + UINT16 ReturnedBI = pMpRfd->iBufferIndex; + UINT8 ReturnedRI = pMpRfd->iRingIndex; + unsigned long lockflags; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "nic_return_rfd" ); + DBG_RX_ENTER( et131x_dbginfo ); + + + /************************************************************************** + We don't use any of the OOB data besides status + Otherwise, we need to clean up OOB data + *************************************************************************/ + if( +#ifdef USE_FBR0 + (( ReturnedRI == 0 ) && ( ReturnedBI < pAdapter->RxRing.Fbr0NumEntries )) || +#endif + (( ReturnedRI == 1 ) && ( ReturnedBI < pAdapter->RxRing.Fbr1NumEntries ))) + { + spin_lock_irqsave( &pAdapter->FbrLock, lockflags ); + + if( ReturnedRI == 1 ) + { + PFBR_DESC_t pNextDesc = (PFBR_DESC_t)(pAdapter->RxRing.pFbr1RingVa) + + pAdapter->RxRing.local_Fbr1_full.bits.fbr_full; + + /****************************************************************** + Handle the Free Buffer Ring advancement here. Write the + PA / Buffer Index for the returned buffer into the oldest + (next to be freed)FBR entry + *****************************************************************/ + pNextDesc->addr_hi = pAdapter->RxRing.Fbr[1]->PAHigh[ReturnedBI]; + pNextDesc->addr_lo = pAdapter->RxRing.Fbr[1]->PALow[ReturnedBI]; + pNextDesc->word2.value = ReturnedBI; + + if( ++pAdapter->RxRing.local_Fbr1_full.bits.fbr_full > + ( pAdapter->RxRing.Fbr1NumEntries - 1 )) + { + pAdapter->RxRing.local_Fbr1_full.bits.fbr_full = 0; + pAdapter->RxRing.local_Fbr1_full.bits.fbr_full_wrap ^= 1; + } + + pAdapter->CSRAddress->rxdma.fbr1_full_offset = + pAdapter->RxRing.local_Fbr1_full; + } +#ifdef USE_FBR0 + else + { + PFBR_DESC_t pNextDesc = (PFBR_DESC_t)(pAdapter->RxRing.pFbr0RingVa) + + pAdapter->RxRing.local_Fbr0_full.bits.fbr_full; + + /****************************************************************** + Handle the Free Buffer Ring advancement here. Write the + PA / Buffer Index for the returned buffer into the oldest + (next to be freed) FBR entry + *****************************************************************/ + pNextDesc->addr_hi = pAdapter->RxRing.Fbr[0]->PAHigh[ReturnedBI]; + pNextDesc->addr_lo = pAdapter->RxRing.Fbr[0]->PALow[ReturnedBI]; + pNextDesc->word2.value = ReturnedBI; + + if( ++pAdapter->RxRing.local_Fbr0_full.bits.fbr_full > + (pAdapter->RxRing.Fbr0NumEntries - 1)) + { + pAdapter->RxRing.local_Fbr0_full.bits.fbr_full = 0; + pAdapter->RxRing.local_Fbr0_full.bits.fbr_full_wrap ^= 1; + } + + pAdapter->CSRAddress->rxdma.fbr0_full_offset = + pAdapter->RxRing.local_Fbr0_full; + } +#endif + spin_unlock_irqrestore( &pAdapter->FbrLock, lockflags ); + } + else + { + DBG_ERROR( et131x_dbginfo, + "NICReturnRFD illegal Buffer Index returned\n" ); + } + + + /************************************************************************** + The processing on this RFD is done, so put it back on the tail of + our list + *************************************************************************/ + spin_lock_irqsave( &pAdapter->RcvLock, lockflags ); + + list_add_tail( &pMpRfd->list_node, &pAdapter->RxRing.RecvList ); + pAdapter->RxRing.nReadyRecv++; + + spin_unlock_irqrestore( &pAdapter->RcvLock, lockflags ); + + DBG_ASSERT( pAdapter->RxRing.nReadyRecv <= pAdapter->RxRing.NumRfd ); + + + DBG_RX_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ --- linux-2.6.27.orig/ubuntu/et131x/et131x_netdev.c +++ linux-2.6.27/ubuntu/et131x/et131x_netdev.c @@ -0,0 +1,1624 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_netdev.c - Routines and data required by all Linux network devices. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2007/01/22 23:13:56 $ + $Revision: 1.21 $ + $Name: T_20060131_v1-2-3 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +/******************************************************************************* + Includes + ******************************************************************************/ +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include +#include +#include +#include + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,0 )) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) +#include +#endif + +#include "ET1310_phy.h" +#include "ET1310_pm.h" +#include "ET1310_jagcore.h" +#include "ET1310_mac.h" +#include "ET1310_tx.h" + +#include "et131x_supp.h" +#include "et131x_adapter.h" +#include "et131x_isr.h" +#include "et131x_initpci.h" + + + + +/****************************************************************************** + Data for debugging facilities + *****************************************************************************/ +#ifdef ET131X_DBG +extern dbg_info_t *et131x_dbginfo; +#endif /* ET131X_DBG */ + + + + +/****************************************************************************** + Prototypes for functions with local scope + *****************************************************************************/ +int et131x_init( struct net_device *netdev ); + +int et131x_config( struct net_device *netdev, struct ifmap *map ); + +struct net_device_stats *et131x_stats( struct net_device *netdev ); + +int et131x_open( struct net_device *netdev ); + +int et131x_close( struct net_device *netdev ); + +int et131x_ioctl( struct net_device *netdev, struct ifreq *reqbuf, int cmd ); + +void et131x_multicast( struct net_device *netdev ); + +int et131x_tx( struct sk_buff *skb, struct net_device *netdev ); + +void et131x_tx_timeout( struct net_device *netdev ); + +int et131x_change_mtu( struct net_device *netdev, int new_mtu ); + +int et131x_set_mac_addr( struct net_device *netdev, void *new_mac ); + +void et131x_vlan_rx_register( struct net_device *netdev, struct vlan_group *grp ); + +void et131x_vlan_rx_add_vid( struct net_device *netdev, UINT16 vid ); + +void et131x_vlan_rx_kill_vid( struct net_device *netdev, UINT16 vid ); + + + + +/****************************************************************************** + ROUTINE : et131x_device_alloc() + ****************************************************************************** + + DESCRIPTION : Create instances of net_device and wl_private for the + new adapter and register the device's entry points in + the net_device structure. + + PARAMETERS : N/A + + RETURNS : pointer to the allocated and initialized net_device + struct for this device. + + REUSE INFORMATION : + + *****************************************************************************/ +struct net_device * et131x_device_alloc( void ) +{ + struct net_device *netdev = NULL; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_device_alloc" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Alloc net_device and adapter structs + *************************************************************************/ + netdev = alloc_etherdev( sizeof( ET131X_ADAPTER )); + + if( netdev == NULL ) + { + DBG_ERROR( et131x_dbginfo, + "Alloc of net_device struct failed\n" ); + DBG_LEAVE( et131x_dbginfo ); + return NULL; + } + + + /************************************************************************** + Setup the function registration table (and other data) for a net_device + *************************************************************************/ + //netdev->init = &et131x_init; + netdev->set_config = &et131x_config; + netdev->get_stats = &et131x_stats; + netdev->open = &et131x_open; + netdev->stop = &et131x_close; + netdev->do_ioctl = &et131x_ioctl; + netdev->set_multicast_list = &et131x_multicast; + netdev->hard_start_xmit = &et131x_tx; + netdev->tx_timeout = &et131x_tx_timeout; + netdev->watchdog_timeo = ET131X_TX_TIMEOUT; + netdev->change_mtu = &et131x_change_mtu; + netdev->set_mac_address = &et131x_set_mac_addr; + +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) + netdev->vlan_rx_register = &et131x_vlan_rx_register; + netdev->vlan_rx_add_vid = &et131x_vlan_rx_add_vid; + netdev->vlan_rx_kill_vid = &et131x_vlan_rx_kill_vid; +#endif + + //netdev->ethtool_ops = &et131x_ethtool_ops; + + // Poll? + //netdev->poll = &et131x_poll; + //netdev->poll_controller = &et131x_poll_controller; + + + DBG_LEAVE( et131x_dbginfo ); + return netdev; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_device_free() + ****************************************************************************** + + DESCRIPTION : Free the net_device and adapter private resources for + an adapter and perform basic cleanup. + + PARAMETERS : netdev - a pointer to the net_device structure + representing the device whose resources should + be freed. + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_device_free( struct net_device *netdev ) +{ + + DBG_FUNC( "et131x_device_free" ); + DBG_ENTER( et131x_dbginfo ); + + if( netdev == NULL ) + { + DBG_WARNING( et131x_dbginfo, "Pointer to net_device == NULL\n" ); + DBG_LEAVE( et131x_dbginfo ); + return; + } + else + { + free_netdev( netdev ); + } + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_init + ****************************************************************************** + + DESCRIPTION : This function is called by the kernel to initialize a + device + + PARAMETERS : netdev - a pointer to a net_device struct representing + the device to be initialized. + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : At the moment, this routine does nothing, as most init + processing needs to be performed before this point. + + *****************************************************************************/ +int et131x_init( struct net_device *netdev ) +{ + + DBG_FUNC( "et131x_init" ); + DBG_ENTER( et131x_dbginfo ); + + + DBG_LEAVE( et131x_dbginfo ); + return 0; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_config + ****************************************************************************** + + DESCRIPTION : Implement the SIOCSIFMAP interface. + + PARAMETERS : netdev - a pointer to a net_device struct representing + the device to be configured. + map - a pointer to an ifmap struct + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_config( struct net_device *netdev, struct ifmap *map ) +{ + DBG_FUNC( "et131x_config" ); + DBG_ENTER( et131x_dbginfo ); + + + DBG_LEAVE( et131x_dbginfo ); + return 0; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_stats + ****************************************************************************** + + DESCRIPTION : Return the current device statistics. + + PARAMETERS : netdev - a pointer to a net_device struct representing + the device whose stats are being queried. + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +struct net_device_stats *et131x_stats( struct net_device *netdev ) +{ + ET131X_ADAPTER *adapter = netdev_priv(netdev); + struct net_device_stats *stats = &adapter->net_stats; + CE_STATS_t *devstat = &adapter->Stats; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_stats" ); + DBG_ENTER( et131x_dbginfo ); + + + stats->rx_packets = devstat->ipackets; + stats->tx_packets = devstat->opackets; + stats->rx_errors = devstat->length_err + devstat->alignment_err + + devstat->crc_err + devstat->code_violations + + devstat->other_errors; + stats->tx_errors = devstat->max_pkt_error; + stats->multicast = devstat->multircv; + stats->collisions = devstat->collisions; + + stats->rx_length_errors = devstat->length_err; + stats->rx_over_errors = devstat->rx_ov_flow; + stats->rx_crc_errors = devstat->crc_err; + + // NOTE: These stats don't have corresponding values in CE_STATS, so we're + // going to have to update these directly from within the TX/RX code + //stats->rx_bytes = 20; //devstat->; + //stats->tx_bytes = 20; //devstat->; + //stats->rx_dropped = devstat->; + //stats->tx_dropped = devstat->; + + // NOTE: Not used, can't find analogous statistics + //stats->rx_frame_errors = devstat->; + //stats->rx_fifo_errors = devstat->; + //stats->rx_missed_errors = devstat->; + + //stats->tx_aborted_errors = devstat->; + //stats->tx_carrier_errors = devstat->; + //stats->tx_fifo_errors = devstat->; + //stats->tx_heartbeat_errors = devstat->; + //stats->tx_window_errors = devstat->; + + + DBG_LEAVE( et131x_dbginfo ); + return stats; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_open + ****************************************************************************** + + DESCRIPTION : Open the device for use. + + PARAMETERS : netdev - a pointer to a net_device struct representing + the device to be opened. + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_open( struct net_device *netdev ) +{ + int result = 0; + ET131X_ADAPTER *adapter = NULL; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_open" ); + DBG_ENTER( et131x_dbginfo ); + + + adapter = netdev_priv( netdev ); + + + /************************************************************************** + Start the timer to track NIC errors + *************************************************************************/ + add_timer( &adapter->ErrorTimer ); + + + /************************************************************************** + Register our ISR + *************************************************************************/ + DBG_TRACE( et131x_dbginfo, "Registering ISR...\n" ); + + result = request_irq( netdev->irq, et131x_isr, IRQF_SHARED, netdev->name, netdev ); + if( result ) + { + DBG_ERROR( et131x_dbginfo, "Could not register ISR\n" ); + DBG_LEAVE( et131x_dbginfo ); + return result; + } + + + /************************************************************************** + Enable the Tx and Rx DMA engines (if not already enabled) + *************************************************************************/ + et131x_rx_dma_enable( adapter ); + et131x_tx_dma_enable( adapter ); + + + /************************************************************************** + Enable device interrupts + *************************************************************************/ + et131x_enable_interrupts( adapter ); + + MP_SET_FLAG( adapter, fMP_ADAPTER_INTERRUPT_IN_USE ); + + + /************************************************************************** + We're ready to move some data, so start the queue + *************************************************************************/ + netif_start_queue( netdev ); + + + DBG_LEAVE( et131x_dbginfo ); + return result; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_close + ****************************************************************************** + + DESCRIPTION : Close the device. + + PARAMETERS : netdev - a pointer to a net_device struct representing + the device to be opened. + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_close( struct net_device *netdev ) +{ + ET131X_ADAPTER *adapter = NULL; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_close" ); + DBG_ENTER( et131x_dbginfo ); + + + adapter = netdev_priv( netdev ); + + + /************************************************************************** + First thing is to stop the queue + *************************************************************************/ + netif_stop_queue( netdev ); + + + /************************************************************************** + Stop the Tx and Rx DMA engines + *************************************************************************/ + et131x_rx_dma_disable( adapter ); + et131x_tx_dma_disable( adapter ); + + + /************************************************************************** + Disable device interrupts + *************************************************************************/ + et131x_disable_interrupts( adapter ); + + + /************************************************************************** + Deregistering ISR + *************************************************************************/ + MP_CLEAR_FLAG( adapter, fMP_ADAPTER_INTERRUPT_IN_USE ); + + DBG_TRACE( et131x_dbginfo, "Deregistering ISR...\n" ); + free_irq( netdev->irq, netdev ); + + + /************************************************************************** + Stop the error timer + *************************************************************************/ + del_timer_sync( &adapter->ErrorTimer ); + + + DBG_LEAVE( et131x_dbginfo ); + return 0; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_ioctl_mii + ****************************************************************************** + + DESCRIPTION : The function which handles MII IOCTLs + + PARAMETERS : netdev - the net_device struct corresponding to the + device on which the query is being made + reqbuf - the request-specific data buffer + cmd - the command request code + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_ioctl_mii( struct net_device *netdev, struct ifreq *reqbuf, int cmd ) +{ + int status = 0; + ET131X_ADAPTER *pAdapter = netdev_priv(netdev); + struct mii_ioctl_data *data = if_mii( reqbuf ); + UINT16 mii_reg; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_ioctl_mii" ); + DBG_ENTER( et131x_dbginfo ); + + + switch( cmd ) + { + case SIOCGMIIPHY: + DBG_VERBOSE( et131x_dbginfo, "SIOCGMIIPHY\n" ); + data->phy_id = pAdapter->Stats.xcvr_addr; + break; + + + case SIOCGMIIREG: + DBG_VERBOSE( et131x_dbginfo, "SIOCGMIIREG\n" ); + if( !capable( CAP_NET_ADMIN )) + { + status = -EPERM; + } + else + { + status = MiRead( pAdapter, + pAdapter->Stats.xcvr_addr, + data->reg_num, + &data->val_out ); + } + + break; + + + case SIOCSMIIREG: + DBG_VERBOSE( et131x_dbginfo, "SIOCSMIIREG\n" ); + if( !capable( CAP_NET_ADMIN )) + { + status = -EPERM; + } + else + { + mii_reg = data->val_in; + + status = MiWrite( pAdapter, + pAdapter->Stats.xcvr_addr, + data->reg_num, + mii_reg ); + } + + break; + + + default: + status = -EOPNOTSUPP; + } + + + DBG_LEAVE( et131x_dbginfo ); + return status; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_ioctl + ****************************************************************************** + + DESCRIPTION : The I/O Control handler for the driver. + + PARAMETERS : netdev - a pointer to a net_device struct representing + the device on which the control request is + being made. + reqbuf - a pointer to the IOCTL request buffer. + cmd - the IOCTL command code. + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_ioctl( struct net_device *netdev, struct ifreq *reqbuf, int cmd ) +{ + int status = 0; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_ioctl" ); + DBG_ENTER( et131x_dbginfo ); + + + switch( cmd ) + { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + status = et131x_ioctl_mii( netdev, reqbuf, cmd ); + break; + + default: +/* DBG_WARNING( et131x_dbginfo, "Unhandled IOCTL Code: 0x%04x\n", cmd );*/ + status = -EOPNOTSUPP; + } + + + DBG_LEAVE( et131x_dbginfo ); + return status; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_set_packet_filter + ****************************************************************************** + + DESCRIPTION : Configures the Rx Packet filtering on the device + + PARAMETERS : adapter - pointer to our private adapter structure + + RETURNS : 0 on success, errno on failure + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_set_packet_filter( ET131X_ADAPTER *adapter ) +{ + int status = 0; + UINT32 filter = adapter->PacketFilter; + RXMAC_CTRL_t ctrl = adapter->CSRAddress->rxmac.ctrl; + RXMAC_PF_CTRL_t pf_ctrl = adapter->CSRAddress->rxmac.pf_ctrl; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_set_packet_filter" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Default to disabled packet filtering. Enable it in the individual case + statements that require the device to filter something + *************************************************************************/ + ctrl.bits.pkt_filter_disable = 1; + + + /************************************************************************** + Set us to be in promiscuous mode so we receive everything, + this is also true when we get a packet filter of 0 + *************************************************************************/ + if(( filter & ET131X_PACKET_TYPE_PROMISCUOUS ) || filter == 0 ) + { + pf_ctrl.bits.filter_broad_en = 0; + pf_ctrl.bits.filter_multi_en = 0; + pf_ctrl.bits.filter_uni_en = 0; + } + else + { + /********************************************************************** + Set us up with Multicast packet filtering. Three cases are + possible - (1) we have a multi-cast list, (2) we receive ALL + multicast entries or (3) we receive none. + *********************************************************************/ + if( filter & ET131X_PACKET_TYPE_ALL_MULTICAST ) + { + DBG_VERBOSE( et131x_dbginfo, + "Multicast filtering OFF (Rx ALL MULTICAST)\n" ); + pf_ctrl.bits.filter_multi_en = 0; + } + else + { + DBG_VERBOSE( et131x_dbginfo, "Multicast filtering ON\n" ); + SetupDeviceForMulticast( adapter ); + pf_ctrl.bits.filter_multi_en = 1; + ctrl.bits.pkt_filter_disable = 0; + } + + + /********************************************************************** + Set us up with Unicast packet filtering + *********************************************************************/ + if( filter & ET131X_PACKET_TYPE_DIRECTED ) + { + DBG_VERBOSE( et131x_dbginfo, "Unicast Filtering ON\n" ); + SetupDeviceForUnicast( adapter ); + pf_ctrl.bits.filter_uni_en = 1; + ctrl.bits.pkt_filter_disable = 0; + } + + + /********************************************************************** + Set us up with Broadcast packet filtering + *********************************************************************/ + if( filter & ET131X_PACKET_TYPE_BROADCAST ) + { + DBG_VERBOSE( et131x_dbginfo, "Broadcast Filtering ON\n" ); + pf_ctrl.bits.filter_broad_en = 1; + ctrl.bits.pkt_filter_disable = 0; + } + else + { + DBG_VERBOSE( et131x_dbginfo, "Broadcast Filtering OFF\n" ); + pf_ctrl.bits.filter_broad_en = 0; + } + + + /********************************************************************** + Setup the receive mac configuration registers - Packet Filter + control + the enable / disable for packet filter in the control + reg. + *********************************************************************/ + adapter->CSRAddress->rxmac.pf_ctrl.value = pf_ctrl.value; + adapter->CSRAddress->rxmac.ctrl = ctrl; + } + + DBG_LEAVE( et131x_dbginfo ); + return status; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_multicast + ****************************************************************************** + + DESCRIPTION : The handler to configure multicasting on the interface. + + PARAMETERS : netdev - a pointer to a net_device struct representing + the device. + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_multicast( struct net_device *netdev ) +{ + ET131X_ADAPTER *adapter = NULL; + UINT32 PacketFilter = 0; + UINT32 count; + unsigned long lockflags; + struct dev_mc_list *mclist = netdev->mc_list; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_multicast" ); + DBG_ENTER( et131x_dbginfo ); + + + adapter = netdev_priv( netdev ); + + + spin_lock_irqsave( &adapter->Lock, lockflags ); + + + /************************************************************************** + Before we modify the platform-independent filter flags, store them + locally. This allows us to determine if anything's changed and if we + even need to bother the hardware + *************************************************************************/ + PacketFilter = adapter->PacketFilter; + + + /************************************************************************** + Clear the 'multicast' flag locally; becuase we only have a single flag + to check multicast, and multiple multicast addresses can be set, this is + the easiest way to determine if more than one multicast address is being + set. + *************************************************************************/ + PacketFilter &= ~ET131X_PACKET_TYPE_MULTICAST; + + + /************************************************************************** + Check the net_device flags and set the device independent flags + accordingly + *************************************************************************/ + DBG_VERBOSE( et131x_dbginfo, + "MULTICAST ADDR COUNT: %d\n", + netdev->mc_count ); + + if( netdev->flags & IFF_PROMISC ) + { + DBG_VERBOSE( et131x_dbginfo, "Request: PROMISCUOUS MODE ON\n" ); + adapter->PacketFilter |= ET131X_PACKET_TYPE_PROMISCUOUS; + } + else + { + DBG_VERBOSE( et131x_dbginfo, "Request: PROMISCUOUS MODE OFF\n" ); + adapter->PacketFilter &= ~ET131X_PACKET_TYPE_PROMISCUOUS; + } + + + if( netdev->flags & IFF_ALLMULTI ) + { + DBG_VERBOSE( et131x_dbginfo, "Request: ACCEPT ALL MULTICAST\n" ); + adapter->PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST; + } + + + if( netdev->mc_count > NIC_MAX_MCAST_LIST ) + { + DBG_WARNING( et131x_dbginfo, + "ACCEPT ALL MULTICAST for now, as there's more Multicast " + "addresses than the HW supports\n" ); + + adapter->PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST; + } + + + if( netdev->mc_count < 1 ) + { + DBG_VERBOSE( et131x_dbginfo, "Request: REJECT ALL MULTICAST\n" ); + adapter->PacketFilter &= ~ET131X_PACKET_TYPE_ALL_MULTICAST; + adapter->PacketFilter &= ~ET131X_PACKET_TYPE_MULTICAST; + } + else + { + DBG_VERBOSE( et131x_dbginfo, "Request: SET MULTICAST FILTER(S)\n" ); + adapter->PacketFilter |= ET131X_PACKET_TYPE_MULTICAST; + } + + + /************************************************************************** + Set values in the private adapter struct + *************************************************************************/ + adapter->MCAddressCount = netdev->mc_count; + + if( netdev->mc_count ) + { + if( mclist->dmi_addrlen != ETH_ALEN ) + { + DBG_WARNING( et131x_dbginfo, "Multicast addrs are not ETH_ALEN in size\n" ); + } + else + { + count = netdev->mc_count - 1; + memcpy( adapter->MCList[count], mclist->dmi_addr, ETH_ALEN ); + } + } + + + /************************************************************************** + Are the new flags different from the previous ones? If not, then no + action is required + + NOTE - This block will always update the MCList with the hardware, even + if the addresses aren't the same. + *************************************************************************/ + if( PacketFilter != adapter->PacketFilter ) + { + /********************************************************************** + Call the device's filter function + *********************************************************************/ + DBG_VERBOSE( et131x_dbginfo, + "UPDATE REQUIRED, FLAGS changed\n" ); + + et131x_set_packet_filter( adapter ); + } + else + { + DBG_VERBOSE( et131x_dbginfo, + "NO UPDATE REQUIRED, FLAGS didn't change\n" ); + } + + + spin_unlock_irqrestore( &adapter->Lock, lockflags ); + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_tx + ****************************************************************************** + + DESCRIPTION : The handler called when the Linux network layer wants + to a Tx a packet on the device. + + PARAMETERS : skb - a pointer to the sk_buff structure which + represents the data to be Tx'd. + netdev - a pointer to a net_device struct representing + the device on which data is to be Tx'd. + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_tx( struct sk_buff *skb, struct net_device *netdev ) +{ + int status = 0; + ET131X_ADAPTER *adapter; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_tx" ); + DBG_TX_ENTER( et131x_dbginfo ); + + + adapter = netdev_priv( netdev ); + + + /************************************************************************** + Save the timestamp for the TX timeout watchdog + *************************************************************************/ + netdev->trans_start = jiffies; + + + /************************************************************************** + Call the device-specific data Tx routine + *************************************************************************/ + status = et131x_send_packets( skb, netdev ); + + + /************************************************************************** + Check status and manage the netif queue if necessary + *************************************************************************/ + if( status != 0 ) + { + if( status == -ENOMEM ) + { + DBG_VERBOSE( et131x_dbginfo, "OUT OF TCBs; STOP NETIF QUEUE\n" ); + + /* Put the queue to sleep until resources are available */ + netif_stop_queue( netdev ); + status = 1; + } + else + { + DBG_WARNING( et131x_dbginfo, "Misc error; drop packet\n" ); + status = 0; + } + } + + DBG_TX_LEAVE( et131x_dbginfo ); + return status; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_tx_timeout + ****************************************************************************** + + DESCRIPTION : The handler called when a Tx request times out. The + timeout period is specified by the 'tx_timeo" element in + the net_device structure (see et131x_alloc_device() to + see how this value is set). + + PARAMETERS : netdev - a pointer to a net_device struct representing + the device. + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_tx_timeout( struct net_device *netdev ) +{ + ET131X_ADAPTER *pAdapter = netdev_priv( netdev ); + PMP_TCB pMpTcb; + unsigned long lockflags; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_tx_timeout" ); + DBG_WARNING( et131x_dbginfo, "TX TIMEOUT\n" ); + + + /************************************************************************** + Just skip this part if the adapter is doing link detection + *************************************************************************/ + if( MP_TEST_FLAG( pAdapter, fMP_ADAPTER_LINK_DETECTION )) + { + DBG_ERROR( et131x_dbginfo, "Still doing link detection\n" ); + return; + } + + + /************************************************************************** + Any nonrecoverable hardware error? + Checks adapter->flags for any failure in phy reading + *************************************************************************/ + if( MP_TEST_FLAG( pAdapter, fMP_ADAPTER_NON_RECOVER_ERROR )) + { + DBG_WARNING( et131x_dbginfo, "Non recoverable error - remove\n" ); + return; + } + + + /************************************************************************** + Hardware failure? + *************************************************************************/ + if( MP_TEST_FLAG( pAdapter, fMP_ADAPTER_HARDWARE_ERROR )) + { + DBG_WARNING( et131x_dbginfo, "hardware error - reset\n" ); + return; + } + + /************************************************************************** + Is send stuck? + *************************************************************************/ + spin_lock_irqsave( &pAdapter->TCBSendQLock, lockflags ); + + pMpTcb = pAdapter->TxRing.CurrSendHead; + + if( pMpTcb != NULL ) + { + pMpTcb->Count++; + + if( pMpTcb->Count > NIC_SEND_HANG_THRESHOLD ) + { +#ifdef ET131X_DBG + TX_STATUS_BLOCK_t txDmaComplete = *( pAdapter->TxRing.pTxStatusVa ); + PTX_DESC_ENTRY_t pDesc = pAdapter->TxRing.pTxDescRingVa + + pMpTcb->WrIndex.bits.serv_req; +#endif + TX_DESC_ENTRY_t StuckDescriptors[10]; + + if( pMpTcb->WrIndex.bits.serv_req > 7 ) + { + memcpy( StuckDescriptors, + pAdapter->TxRing.pTxDescRingVa + pMpTcb->WrIndex.bits.serv_req - 6, + sizeof( TX_DESC_ENTRY_t ) * 10 ); + } + + spin_unlock_irqrestore( &pAdapter->TCBSendQLock, lockflags ); + + DBG_WARNING( et131x_dbginfo, + "Send stuck - reset. pMpTcb->WrIndex %x, Flags 0x%08x\n", + pMpTcb->WrIndex.bits.serv_req, pMpTcb->Flags ); + + DBG_WARNING( et131x_dbginfo, + "pDesc 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", + pDesc->DataBufferPtrHigh, pDesc->DataBufferPtrLow, + pDesc->word2.value, pDesc->word3.value ); + + DBG_WARNING( et131x_dbginfo, + "WbStatus 0x%08x\n", + txDmaComplete.value ); + +#ifdef ET131X_DBG + DumpDeviceBlock( DBG_WARNING_ON, pAdapter, 0 ); + DumpDeviceBlock( DBG_WARNING_ON, pAdapter, 1 ); + DumpDeviceBlock( DBG_WARNING_ON, pAdapter, 3 ); + DumpDeviceBlock( DBG_WARNING_ON, pAdapter, 5 ); +#endif + et131x_close( netdev ); + et131x_open( netdev ); + + return; + } + } + + spin_unlock_irqrestore( &pAdapter->TCBSendQLock, lockflags ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_change_mtu + ****************************************************************************** + + DESCRIPTION : The handler called to change the MTU for the device. + + PARAMETERS : netdev - a pointer to a net_device struct representing + the device whose MTU is to be changed. + + new_mtu - the desired MTU. + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + *****************************************************************************/ +int et131x_change_mtu( struct net_device *netdev, int new_mtu ) +{ + int result = 0; + ET131X_ADAPTER *adapter = NULL; + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_change_mtu" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Get the private adapter structure + *************************************************************************/ + adapter = netdev_priv( netdev ); + + if( adapter == NULL ) + { + DBG_LEAVE( et131x_dbginfo ); + return -ENODEV; + } + + + /************************************************************************** + Make sure the requested MTU is valid + *************************************************************************/ + if( new_mtu == 0 || new_mtu > 9216 ) + { + DBG_LEAVE( et131x_dbginfo ); + return -EINVAL; + } + + + /************************************************************************** + Stop the netif queue + *************************************************************************/ + netif_stop_queue( netdev ); + + + /************************************************************************** + Stop the Tx and Rx DMA engines + *************************************************************************/ + et131x_rx_dma_disable( adapter ); + et131x_tx_dma_disable( adapter ); + + + /************************************************************************** + Disable device interrupts + *************************************************************************/ + et131x_disable_interrupts( adapter ); + et131x_handle_send_interrupt( adapter ); + et131x_handle_recv_interrupt( adapter ); + + + /************************************************************************** + Set the new MTU + *************************************************************************/ + netdev->mtu = new_mtu; + + + /************************************************************************** + Free Rx DMA memory + *************************************************************************/ + et131x_adapter_memory_free( adapter ); + + + /************************************************************************** + Set the config parameter for Jumbo Packet support + *************************************************************************/ + adapter->RegistryJumboPacket = new_mtu + 14; + et131x_soft_reset( adapter ); + + + /************************************************************************** + Alloc and init Rx DMA memory + *************************************************************************/ + result = et131x_adapter_memory_alloc( adapter ); + if( result != 0 ) + { + DBG_WARNING( et131x_dbginfo, + "Change MTU failed; couldn't re-alloc DMA memory\n" ); + return result; + } + + et131x_init_send( adapter ); + + + et131x_setup_hardware_properties( adapter ); + memcpy( netdev->dev_addr, adapter->CurrentAddress, ETH_ALEN ); + et131x_init_enet_crc_calc( ); + + + /************************************************************************** + Init the device with the new settings + *************************************************************************/ + et131x_adapter_setup( adapter ); + + + /************************************************************************** + Enable interrupts + *************************************************************************/ + if( MP_TEST_FLAG( adapter, fMP_ADAPTER_INTERRUPT_IN_USE )) + { + et131x_enable_interrupts( adapter ); + } + + + /************************************************************************** + Restart the Tx and Rx DMA engines + *************************************************************************/ + et131x_rx_dma_enable( adapter ); + et131x_tx_dma_enable( adapter ); + + + /************************************************************************** + Restart the netif queue + *************************************************************************/ + netif_wake_queue( netdev ); + + + DBG_LEAVE( et131x_dbginfo ); + return result; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_set_mac_addr + ****************************************************************************** + + DESCRIPTION : The handler called to change the MAC address for the + device. + + PARAMETERS : netdev - a pointer to a net_device struct representing + the device whose MAC is to be changed. + + new_mac - a buffer containing a sock_addr struct in which + the desired MAC address is stored. + + RETURNS : 0 on success + errno on failure (as defined in errno.h) + + REUSE INFORMATION : + + IMPLEMENTED BY : blux http://berndlux.de 22.01.2007 21:14 + + *****************************************************************************/ +int et131x_set_mac_addr( struct net_device *netdev, void *new_mac ) +{ + int result = 0; + ET131X_ADAPTER *adapter = NULL; + struct sockaddr *address = new_mac; + + DBG_FUNC( "et131x_set_mac_addr" ); + DBG_ENTER( et131x_dbginfo ); + // begin blux + // DBG_VERBOSE( et131x_dbginfo, "Function not implemented!!\n" ); + + /*-----------------------------------------------------------------------*/ + + + /************************************************************************** + Get the private adapter structure + *************************************************************************/ + adapter = netdev_priv( netdev ); + + if( adapter == NULL ) + { + DBG_LEAVE( et131x_dbginfo ); + return -ENODEV; + } + + + /************************************************************************** + Make sure the requested MAC is valid + *************************************************************************/ + if (!is_valid_ether_addr(address->sa_data)) + { + DBG_LEAVE( et131x_dbginfo ); + return -EINVAL; + } + + + /************************************************************************** + Stop the netif queue + *************************************************************************/ + netif_stop_queue( netdev ); + + + /************************************************************************** + Stop the Tx and Rx DMA engines + *************************************************************************/ + et131x_rx_dma_disable( adapter ); + et131x_tx_dma_disable( adapter ); + + + /************************************************************************** + Disable device interrupts + *************************************************************************/ + et131x_disable_interrupts( adapter ); + et131x_handle_send_interrupt( adapter ); + et131x_handle_recv_interrupt( adapter ); + + + /************************************************************************** + Set the new MAC + *************************************************************************/ + // netdev->set_mac_address = &new_mac; + // netdev->mtu = new_mtu; + + + memcpy(netdev->dev_addr, address->sa_data, netdev->addr_len); + + printk("%s: Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n", netdev->name, + netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], + netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); + + + /************************************************************************** + Free Rx DMA memory + *************************************************************************/ + et131x_adapter_memory_free( adapter ); + + + /************************************************************************** + Set the config parameter for Jumbo Packet support + *************************************************************************/ + //adapter->RegistryJumboPacket = new_mtu + 14; + // blux: not needet here, w'll change the MAC + + et131x_soft_reset( adapter ); + + + /************************************************************************** + Alloc and init Rx DMA memory + *************************************************************************/ + result = et131x_adapter_memory_alloc( adapter ); + if( result != 0 ) + { + DBG_WARNING( et131x_dbginfo, + "Change MAC failed; couldn't re-alloc DMA memory\n" ); + return result; + } + + et131x_init_send( adapter ); + + + et131x_setup_hardware_properties( adapter ); + // memcpy( netdev->dev_addr, adapter->CurrentAddress, ETH_ALEN ); + // blux: no, do not override our nice address + et131x_init_enet_crc_calc( ); + + + /************************************************************************** + Init the device with the new settings + *************************************************************************/ + et131x_adapter_setup( adapter ); + + + /************************************************************************** + Enable interrupts + *************************************************************************/ + if( MP_TEST_FLAG( adapter, fMP_ADAPTER_INTERRUPT_IN_USE )) + { + et131x_enable_interrupts( adapter ); + } + + + /************************************************************************** + Restart the Tx and Rx DMA engines + *************************************************************************/ + et131x_rx_dma_enable( adapter ); + et131x_tx_dma_enable( adapter ); + + + /************************************************************************** + Restart the netif queue + *************************************************************************/ + netif_wake_queue( netdev ); + + + + DBG_LEAVE( et131x_dbginfo ); + return result; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + NOTE: The ET1310 doesn't support hardware VLAN tagging, so these functions + are currently not used; they are in place to eventually support the + feature if needed. + *****************************************************************************/ + +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) + +/****************************************************************************** + ROUTINE : et131x_vlan_rx_register + ****************************************************************************** + + DESCRIPTION : The handler called to enable or disable VLAN support on + the device. + + PARAMETERS : netdev - a pointer to a net_device struct representing + the device on which VLAN should be enabled or + disabled. + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_vlan_rx_register( struct net_device *netdev, struct vlan_group *grp ) +{ + ET131X_ADAPTER *pAdapter = netdev_priv( netdev ); + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_vlan_rx_register" ); + DBG_ENTER( et131x_dbginfo ); + + + /************************************************************************** + Track the vlan_group struct in the adapter private structure; if this + element is NULL, then VLAN is disabled; otherwise, it is enabled. + *************************************************************************/ + if( grp ) + { + DBG_VERBOSE( et131x_dbginfo, "VLAN: Enable, 0x%p\n", grp ); + } + else + { + DBG_VERBOSE( et131x_dbginfo, "VLAN: Disable\n" ); + } + + pAdapter->vlgrp = grp; + + + /************************************************************************** + This is where any interfacing with the hardware to enable or disable + VLAN would be done. Since the ET1310 doesn't handle this in hardware, + nothing else needs to be done. + *************************************************************************/ + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_vlan_rx_add_vid + ****************************************************************************** + + DESCRIPTION : The handler called to register a VLAN tag. + + PARAMETERS : netdev - a pointer to a net_device struct representing + the device on which a VLAN tag should be added. + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_vlan_rx_add_vid( struct net_device *netdev, UINT16 vid ) +{ + DBG_FUNC( "et131x_vlan_rx_add_vid" ); + DBG_ENTER( et131x_dbginfo ); + + + DBG_VERBOSE( et131x_dbginfo, "VLAN, Add VID: %d\n", vid ); + + + /************************************************************************** + This is where any interfacing with the hardware to register VLAN IDs + would take place. Since the ET1310 doesn't handle this in hardware, + nothing else needs to be done here; the vlan_group structure's + vlan_devices element can be used in the TX/RX routines to determine if + a VLAN tag has been 'registered' with the device. + *************************************************************************/ + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + + + + +/****************************************************************************** + ROUTINE : et131x_vlan_rx_kill_vid + ****************************************************************************** + + DESCRIPTION : The handler called to deregister a VLAN tag. + + PARAMETERS : netdev - a pointer to a net_device struct representing + the device on which a VLAN tag should be + removed. + + RETURNS : N/A + + REUSE INFORMATION : + + *****************************************************************************/ +void et131x_vlan_rx_kill_vid( struct net_device *netdev, UINT16 vid ) +{ + ET131X_ADAPTER *pAdapter = netdev_priv( netdev ); + /*-----------------------------------------------------------------------*/ + + + DBG_FUNC( "et131x_vlan_rx_kill_vid" ); + DBG_ENTER( et131x_dbginfo ); + + + DBG_VERBOSE( et131x_dbginfo, "VLAN, Remove VID: %d\n", vid ); + + if( pAdapter->vlgrp ) + { + pAdapter->vlgrp->vlan_devices_arrays[vid] = NULL; + } + + + /************************************************************************** + This is where any interfacing with the hardware to deregister VLAN IDs + would take place. Since the ET1310 doesn't handle this in hardware, + nothing else needs to be done here. + *************************************************************************/ + + + DBG_LEAVE( et131x_dbginfo ); + return; +} +/*===========================================================================*/ + +#endif --- linux-2.6.27.orig/ubuntu/et131x/BOM +++ linux-2.6.27/ubuntu/et131x/BOM @@ -0,0 +1,2 @@ +Downloaded from: http://sourceforge.net/project/platformdownload.php?group_id=179406 +Current Version: 1.2.3-3 --- linux-2.6.27.orig/ubuntu/et131x/ET1310_mac.h +++ linux-2.6.27/ubuntu/et131x/ET1310_mac.h @@ -0,0 +1,140 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * ET1310_mac.h - Defines, structs, enums, prototypes, etc. pertaining to the + * MAC. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/08/01 19:35:11 $ + $Revision: 1.5 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +#ifndef _ET1310_MAC_H_ +#define _ET1310_MAC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + + + +/****************************************************************************** + INCLUDES + *****************************************************************************/ +#include "ET1310_common.h" + + + + +/****************************************************************************** + MACSTAT #defines + *****************************************************************************/ +#define COUNTER_WRAP_28_BIT 0x10000000 +#define COUNTER_WRAP_22_BIT 0x400000 +#define COUNTER_WRAP_16_BIT 0x10000 +#define COUNTER_WRAP_12_BIT 0x1000 + +#define COUNTER_MASK_28_BIT (COUNTER_WRAP_28_BIT - 1) +#define COUNTER_MASK_22_BIT (COUNTER_WRAP_22_BIT - 1) +#define COUNTER_MASK_16_BIT (COUNTER_WRAP_16_BIT - 1) +#define COUNTER_MASK_12_BIT (COUNTER_WRAP_12_BIT - 1) + +#define UPDATE_COUNTER(HostCnt,DevCnt) \ + HostCnt = HostCnt + DevCnt; + + + + +/****************************************************************************** + Forward declaration of the private adapter structure + *****************************************************************************/ +struct et131x_adapter; + + +/****************************************************************************** + PROTOTYPES + *****************************************************************************/ +void ConfigMACRegs1( struct et131x_adapter *pAdapter ); +void ConfigMACRegs2( struct et131x_adapter *pAdapter ); +void ConfigRxMacRegs( struct et131x_adapter *pAdapter ); +void ConfigTxMacRegs( struct et131x_adapter *pAdapter ); +void ConfigMacStatRegs( struct et131x_adapter *pAdapter ); +void ConfigFlowControl( struct et131x_adapter *pAdapter ); +void UpdateMacStatHostCounters( struct et131x_adapter *pAdapter ); +void HandleMacStatInterrupt( struct et131x_adapter *pAdapter ); +void SetupDeviceForMulticast( struct et131x_adapter *pAdapter ); +void SetupDeviceForUnicast( struct et131x_adapter *pAdapter ); + + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _ET1310_MAC_H_ */ --- linux-2.6.27.orig/ubuntu/et131x/ET1310_common.h +++ linux-2.6.27/ubuntu/et131x/ET1310_common.h @@ -0,0 +1,97 @@ +/******************************************************************************* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * ET1310.h - Common defines, structs, enums, prototypes, etc. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + + + + +/****************************************************************************** + * VERSION CONTROL INFORMATION + ****************************************************************************** + + $RCSFile: $ + $Date: 2005/08/01 19:35:10 $ + $Revision: 1.5 $ + $Name: T_20060131_v1-2-2 $ + $Author: vjs $ + + *****************************************************************************/ + + + + +#ifndef __ET1310_COMMON_H__ +#define __ET1310_COMMON_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + + + +/****************************************************************************** + INCLUDES + *****************************************************************************/ +#include "ET1310_address_map.h" + + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __ET1310_COMMON_H__ */ --- linux-2.6.27.orig/ubuntu/gnbd/gnbd.h +++ linux-2.6.27/ubuntu/gnbd/gnbd.h @@ -0,0 +1,93 @@ +#ifndef LINUX_GNBD_H +#define LINUX_GNBD_H + +#define GNBD_DO_IT _IO( 0xab, 0x20 ) +#define GNBD_CLEAR_QUE _IO( 0xab, 0x21 ) +#define GNBD_PRINT_DEBUG _IO( 0xab, 0x22 ) +#define GNBD_DISCONNECT _IO( 0xab, 0x23 ) +#define GNBD_PING _IO( 0xab, 0x24 ) +#define GNBD_GET_TIME _IO( 0xab, 0x25 ) + +enum { + GNBD_CMD_READ = 0, + GNBD_CMD_WRITE = 1, + GNBD_CMD_DISC = 2, + GNBD_CMD_PING = 3 +}; + +#define gnbd_cmd(req) ((req)->__cmd[0]) +#define MAX_GNBD 128 + +/* values for flags field */ +#define GNBD_READ_ONLY 0x0001 + +/* userspace doesn't need the gnbd_device structure */ +#ifdef __KERNEL__ + +struct gnbd_device { + unsigned short int flags; + struct socket * sock; + struct file * file; /* If == NULL, device is not ready, yet */ + int magic; + spinlock_t queue_lock; + spinlock_t open_lock; + struct list_head queue_head;/* Requests are added here... */ + struct semaphore tx_lock; + struct gendisk *disk; + pid_t receiver_pid; + struct semaphore do_it_lock; + int open_count; + struct device class_dev; + unsigned short int server_port; + char *server_name; + char name[32]; + unsigned long last_received; + struct block_device *bdev; + struct request *current_request; + wait_queue_head_t tx_wait; + int corrupt; +}; + +#endif /* __KERNEL__ */ + +/* These are sent over the network in the request/reply magic fields */ + +#define GNBD_REQUEST_MAGIC 0x37a07e00 +#define GNBD_REPLY_MAGIC 0x41f09370 +#define GNBD_KEEP_ALIVE_MAGIC 0x5B46D8C2 +/* Do *not* use magics: 0x12560953 0x96744668. */ + +/* + * This is the packet used for communication between client and + * server. All data are in network byte order. + */ +struct gnbd_request { + uint32_t magic; + uint32_t type; /* == READ || == WRITE why so long */ + char handle[8]; /* why is this a char array instead of a u64 */ + uint64_t from; + uint32_t len; +} +#ifdef __GNUC__ + __attribute__ ((packed)) +#endif /* __GNUC__ */ +; + +/* + * This is the reply packet that gnbd-server sends back to the client after + * it has completed an I/O request (or an error occurs). + */ +#define SIZE_OF_REPLY 16 +struct gnbd_reply { + uint32_t magic; + uint32_t error; /* 0 = ok, else error */ + char handle[8]; /* handle you got from request */ +}; + +struct do_it_req_s { + unsigned int minor; + int sock_fd; +}; +typedef struct do_it_req_s do_it_req_t; + +#endif /* LINUX_GNBD_H */ --- linux-2.6.27.orig/ubuntu/gnbd/Kconfig +++ linux-2.6.27/ubuntu/gnbd/Kconfig @@ -0,0 +1,4 @@ +config GNBD + tristate "GFS Network Block Device" + default m + depends on SYSFS && NET && INET --- linux-2.6.27.orig/ubuntu/gnbd/gnbd.c +++ linux-2.6.27/ubuntu/gnbd/gnbd.c @@ -0,0 +1,1118 @@ +/* Large chunks of this code were lifted from nbd.c */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_COMPAT +#include +#endif + +#include +#include + +#include "gnbd.h" + +static int major_nr = 0; +uint64_t insmod_time; + + +#define GNBD_MAGIC 0x74d06100 + +#ifdef NDEBUG +#define dprintk(flags, fmt...) +#else /* NDEBUG */ +#define dprintk(flags, fmt...) do { \ + if (debugflags & (flags)) printk(KERN_DEBUG fmt); \ +} while (0) +#define DBG_IOCTL 0x0004 +#define DBG_INIT 0x0010 +#define DBG_EXIT 0x0020 +#define DBG_BLKDEV 0x0100 +#define DBG_RX 0x0200 +#define DBG_TX 0x0400 +static unsigned int debugflags; +#endif /* NDEBUG */ + +static struct gnbd_device gnbd_dev[MAX_GNBD]; + +struct request shutdown_req; +struct request ping_req; + +static spinlock_t gnbd_lock = SPIN_LOCK_UNLOCKED; + +#define to_gnbd_dev(d) container_of(d, struct gnbd_device, class_dev) + +static void gnbd_class_release(struct device *class_dev) +{ + /* FIXME -- What the hell do I have to free up here */ +} + +static struct class gnbd_class = { + .name = "gnbd", + .dev_release = gnbd_class_release +}; + +static ssize_t show_pid(struct device *class_dev, struct device_attribute *attr, char *buf) +{ + struct gnbd_device *dev = to_gnbd_dev(class_dev); + return sprintf(buf, "%d\n", dev->receiver_pid); +} + +DEVICE_ATTR(pid, S_IRUGO, show_pid, NULL); + +static ssize_t show_server(struct device *class_dev, struct device_attribute *attr, char *buf) +{ + struct gnbd_device *dev = to_gnbd_dev(class_dev); + if (dev->server_name) + return sprintf(buf, "%s/%hx\n", dev->server_name, + dev->server_port); + else + return sprintf(buf, "\n"); +} + +/* FIXME -- should a empty store free the memory */ +static ssize_t store_server(struct device *class_dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int res; + short unsigned int port; + char *ptr; + struct gnbd_device *dev = to_gnbd_dev(class_dev); + if (down_trylock(&dev->do_it_lock)) + return -EBUSY; + if (dev->server_name) + kfree(dev->server_name); + dev->server_name = kmalloc(count + 1, GFP_KERNEL); + if (!dev->server_name) + return -ENOMEM; + memcpy(dev->server_name, buf, count); + dev->server_name[count] = 0; + ptr = strchr(dev->server_name, '/'); + if (!ptr) + return -EINVAL; + *ptr++ = 0; + res = sscanf(ptr, "%4hx", &port); + if (res != 1){ + up(&dev->do_it_lock); + return -EINVAL; + } + dev->server_port = port; + up(&dev->do_it_lock); + return count; +} + +DEVICE_ATTR(server, S_IRUGO | S_IWUSR, show_server, store_server); + +static ssize_t show_name(struct device *class_dev, struct device_attribute *attr, char *buf) +{ + struct gnbd_device *dev = to_gnbd_dev(class_dev); + return sprintf(buf, "%s\n", dev->name); +} + +static ssize_t store_name(struct device *class_dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int res; + struct gnbd_device *dev = to_gnbd_dev(class_dev); + if (down_trylock(&dev->do_it_lock)) + return -EBUSY; + res = sscanf(buf, "%31s", dev->name); + up(&dev->do_it_lock); + if (res != 1) + return -EINVAL; + return count; +} + +DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_name, store_name); + + +static ssize_t show_sectors(struct device *class_dev, struct device_attribute *attr, char *buf) +{ + struct gnbd_device *dev = to_gnbd_dev(class_dev); + return sprintf(buf, "%Lu\n", + (unsigned long long)get_capacity(dev->disk)); +} + +static ssize_t store_sectors(struct device *class_dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int res; + sector_t size; + struct block_device *bdev; + struct gnbd_device *dev = to_gnbd_dev(class_dev); + + if (down_trylock(&dev->do_it_lock)) + return -EBUSY; + res = sscanf(buf, "%Lu\n", (unsigned long long int *)&size); + if (res != 1){ + up(&dev->do_it_lock); + return -EINVAL; + } + /* FIXME -- should I switch the order here, so that I don't have + capacity set to one thing and the bdev inode size set to another */ + set_capacity(dev->disk, size); + bdev = bdget_disk(dev->disk, 0); + if (bdev) { + mutex_lock(&bdev->bd_inode->i_mutex); + i_size_write(bdev->bd_inode, (loff_t)size << 9); + mutex_unlock(&bdev->bd_inode->i_mutex); + bdput(bdev); + } + up(&dev->do_it_lock); + return count; +} + +DEVICE_ATTR(sectors, S_IRUGO | S_IWUSR, show_sectors, store_sectors); + +static ssize_t show_usage(struct device *class_dev, struct device_attribute *attr, char *buf) +{ + struct gnbd_device *dev = to_gnbd_dev(class_dev); + return sprintf(buf, "%d\n", dev->open_count); +} + +DEVICE_ATTR(usage, S_IRUGO, show_usage, NULL); + +static ssize_t show_flags(struct device *class_dev, struct device_attribute *attr, char *buf) +{ + struct gnbd_device *dev = to_gnbd_dev(class_dev); + return sprintf(buf, "0x%04x\n", dev->flags); +} + +static ssize_t store_flags(struct device *class_dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int res; + + struct gnbd_device *dev = to_gnbd_dev(class_dev); + if (down_trylock(&dev->do_it_lock)) + return -EBUSY; + res = sscanf(buf, "0x%hx", &dev->flags); + up(&dev->do_it_lock); + if (res != 1) + return -EINVAL; + return count; +} + + +DEVICE_ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags); + +static ssize_t show_waittime(struct device *class_dev, struct device_attribute *attr, char *buf) +{ + struct gnbd_device *dev = to_gnbd_dev(class_dev); + if (list_empty(&dev->queue_head)) + return sprintf(buf, "-1\n"); + return sprintf(buf, "%ld\n", + ((long)jiffies - (long)dev->last_received) / HZ); +} + +DEVICE_ATTR(waittime, S_IRUGO, show_waittime, NULL); + +static ssize_t show_connected(struct device *class_dev, struct device_attribute *attr, char *buf) +{ + struct gnbd_device *dev = to_gnbd_dev(class_dev); + return sprintf(buf, "%d\n", (dev->sock != NULL)); +} + +DEVICE_ATTR(connected, S_IRUGO, show_connected, NULL); + +#ifndef NDEBUG +static const char *ioctl_cmd_to_ascii(int cmd) +{ + switch (cmd) { + case GNBD_DO_IT: return "do-it"; + case GNBD_CLEAR_QUE: return "clear-que"; + case GNBD_PRINT_DEBUG: return "print-debug"; + case GNBD_DISCONNECT: return "disconnect"; + } + return "unknown"; +} + +static const char *gnbdcmd_to_ascii(int cmd) +{ + switch (cmd) { + case GNBD_CMD_READ: return "read"; + case GNBD_CMD_WRITE: return "write"; + case GNBD_CMD_DISC: return "disconnect"; + case GNBD_CMD_PING: return "ping"; + } + return "invalid"; +} +#endif /* NDEBUG */ + + +static int wait_for_send(struct request *req, struct gnbd_device *dev) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&dev->tx_wait, &wait); + while(dev->current_request == req) { + set_current_state(TASK_INTERRUPTIBLE); + if (signal_pending(current)) { + printk(KERN_WARNING "gnbd (pid %d: %s) wait interrupted by signal\n", + current->pid, current->comm); + return -EINTR; + } + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&dev->tx_wait, &wait); + return 0; +} + +static void gnbd_end_request(struct request *req) +{ + int error = req->errors ? -EIO : 0; + struct request_queue *q = req->q; + unsigned long flags; + + dprintk(DBG_BLKDEV, "%s: request %p: %s\n", req->rq_disk->disk_name, + req, error ? "failed" : "done"); + + if (error) + printk("%s %d called gnbd_end_request with an error\n", + current->comm, current->pid); + + spin_lock_irqsave(q->queue_lock, flags); + __blk_end_request(req, error, req->nr_sectors << 9); + spin_unlock_irqrestore(q->queue_lock, flags); +} + +/* + * Send or receive packet. + */ +static int sock_xmit(struct socket *sock, int send, void *buf, int size, + int msg_flags, int can_signal) +{ + mm_segment_t oldfs; + int result; + struct msghdr msg; + struct iovec iov; + unsigned long flags; + sigset_t oldset; + + oldfs = get_fs(); + set_fs(get_ds()); + spin_lock_irqsave(¤t->sighand->siglock, flags); + oldset = current->blocked; + sigfillset(¤t->blocked); + if (can_signal) + sigdelsetmask(¤t->blocked, sigmask(SIGKILL) | + sigmask(SIGTERM) | sigmask(SIGHUP)); + recalc_sigpending(); + spin_unlock_irqrestore(¤t->sighand->siglock, flags); + + do { + sock->sk->sk_allocation = GFP_NOIO; + iov.iov_base = buf; + iov.iov_len = size; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_namelen = 0; + msg.msg_flags = msg_flags | MSG_NOSIGNAL; + + if (send) + result = sock_sendmsg(sock, &msg, size); + else + result = sock_recvmsg(sock, &msg, size, 0); + + if (can_signal && signal_pending(current)) { + printk(KERN_WARNING "gnbd (pid %d: %s) got signal\n", + current->pid, current->comm); + result = -EINTR; + break; + } + + if (result <= 0) { + if (result == 0) + result = -EPIPE; /* short read */ + break; + } + size -= result; + buf += result; + } while (size > 0); + + spin_lock_irqsave(¤t->sighand->siglock, flags); + current->blocked = oldset; + recalc_sigpending(); + spin_unlock_irqrestore(¤t->sighand->siglock, flags); + + set_fs(oldfs); + return result; +} + +static inline int sock_send_bvec(struct socket *sock, struct bio_vec *bvec, + int flags, int can_signal) +{ + int result; + void *kaddr = kmap(bvec->bv_page); + result = sock_xmit(sock, 1, kaddr + bvec->bv_offset, bvec->bv_len, + flags, can_signal); + kunmap(bvec->bv_page); + return result; +} + + +#define gnbd_send_req(dev, req, can_sig) \ +__gnbd_send_req((dev), (dev)->sock, (req), (can_sig)) + +int __gnbd_send_req(struct gnbd_device *dev, struct socket *sock, + struct request *req, int can_signal) +{ + int result, flags; + struct gnbd_request request; + unsigned long size = req->nr_sectors << 9; + + request.magic = htonl(GNBD_REQUEST_MAGIC); + request.type = htonl(gnbd_cmd(req)); + request.from = cpu_to_be64((u64) req->sector << 9); + request.len = htonl(size); + memcpy(request.handle, &req, sizeof(req)); + + down(&dev->tx_lock); + + if (dev->corrupt) { + printk(KERN_ERR "%s: Attempted to send on a faulty socket\n", + dev->disk->disk_name); + result = -EBADFD; + goto error_out; + } + if (!sock) { + printk(KERN_ERR "%s: Attempted send on closed socket\n", + dev->disk->disk_name); + result = -ENOTCONN; + goto error_out; + } + + dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%luB)\n", + dev->disk->disk_name, req, + gnbdcmd_to_ascii(gnbd_cmd(req)), + (unsigned long long)req->sector << 9, + req->nr_sectors << 9); + dev->current_request = req; + result = sock_xmit(sock, 1, &request, sizeof(request), + (gnbd_cmd(req) == GNBD_CMD_WRITE)? MSG_MORE: 0, + can_signal); + if (result < 0) { + printk(KERN_ERR "%s: Send control failed (result %d)\n", + dev->disk->disk_name, result); + goto send_error_out; + } + + if (gnbd_cmd(req) == GNBD_CMD_WRITE) { + struct req_iterator iter; + struct bio_vec *bvec; + /* + * we are really probing at internals to determine + * whether to set MSG_MORE or not... + */ + rq_for_each_segment(bvec, req, iter) { + flags = 0; + if (!rq_iter_last(req, iter)) + flags = MSG_MORE; + dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n", + dev->disk->disk_name, req, + bvec->bv_len); + result = sock_send_bvec(sock, bvec, flags, + can_signal); + if (result < 0) { + printk(KERN_ERR "%s: Send data failed (result %d)\n", + dev->disk->disk_name, + result); + goto send_error_out; + } + } + } + dev->current_request = NULL; + wake_up(&dev->tx_wait); + up(&dev->tx_lock); + return 0; + +send_error_out: + dev->corrupt = 1; + dev->current_request = NULL; + wake_up(&dev->tx_wait); +error_out: + up(&dev->tx_lock); + return result; +} + + +static int gnbd_find_request(struct gnbd_device *dev, struct request *xreq) +{ + struct request *req; + struct list_head *tmp; + + list_for_each(tmp, &dev->queue_head) { + req = list_entry(tmp, struct request, queuelist); + if (req != xreq) + continue; + return 1; + } + return 0; +} + +static inline int sock_recv_bvec(struct socket *sock, struct bio_vec *bvec) +{ + int result; + void *kaddr = kmap(bvec->bv_page); + result = sock_xmit(sock, 0, kaddr + bvec->bv_offset, bvec->bv_len, + MSG_WAITALL, 1); + kunmap(bvec->bv_page); + return result; +} + +int gnbd_recv_req(struct gnbd_device *dev, struct request *req) +{ + int result; + struct bio_vec *bvec; + struct req_iterator iter; + + rq_for_each_segment(bvec, req, iter) { + result = sock_recv_bvec(dev->sock, bvec); + if (result < 0) { + printk(KERN_ERR "%s: Receive data failed (result %d)\n", + dev->disk->disk_name, + result); + return result; + } + dprintk(DBG_RX, "%s: request %p: got %d bytes data\n", + dev->disk->disk_name, req, bvec->bv_len); + } + return 0; +} + +int gnbd_do_it(struct gnbd_device *dev) +{ + int result; + struct gnbd_reply reply; + struct request *req; + struct socket *sock = dev->sock; + + BUG_ON(dev->magic != GNBD_MAGIC); + + while((result = sock_xmit(sock, 0, &reply,sizeof(reply), MSG_WAITALL, 1)) > 0){ + if (dev->corrupt) { + printk(KERN_ERR "%s: faulty socket\n",dev->disk->disk_name); + return -EBADFD; + } + + if (ntohl(reply.magic) == GNBD_KEEP_ALIVE_MAGIC) + /* FIXME -- I should reset the wait time here */ + continue; + + memcpy(&req, reply.handle, sizeof(req)); + if (req == &shutdown_req) + return 0; + + if (!gnbd_find_request(dev, req)){ + printk(KERN_ERR "%s: Unexpected reply (%p)\n", + dev->disk->disk_name, reply.handle); + return -EBADR; + } + if (ntohl(reply.magic) != GNBD_REPLY_MAGIC) { + printk(KERN_ERR "%s: Wrong magic (0x%lx)\n", + dev->disk->disk_name, + (unsigned long)ntohl(reply.magic)); + return -EPROTO; + } + if (ntohl(reply.error)) { + printk(KERN_ERR "%s: Other side returned error (%d)\n", + dev->disk->disk_name, ntohl(reply.error)); + req->errors++; + goto remove_req; + } + dprintk(DBG_RX, "%s: request %p: got reply\n", + dev->disk->disk_name, req); + + if (gnbd_cmd(req) == GNBD_CMD_READ){ + result = gnbd_recv_req(dev, req); + if (result < 0) + return result; + } +remove_req: + result = wait_for_send(req, dev); + if (result != 0) + return result; + spin_lock(&dev->queue_lock); + list_del_init(&req->queuelist); + dev->last_received = jiffies; + spin_unlock(&dev->queue_lock); + if (req != &ping_req) + gnbd_end_request(req); + } + printk(KERN_ERR "%s: Receive control failed (result %d)\n", + dev->disk->disk_name, result); + return result; +} + +int gnbd_clear_que(struct gnbd_device *dev) +{ + int err; + struct request *req; + + BUG_ON(dev->magic != GNBD_MAGIC); + + do { + req = NULL; + if (!list_empty(&dev->queue_head)) { + req = list_entry(dev->queue_head.next, struct request, queuelist); + err = wait_for_send(req, dev); + if (err) + return err; + list_del_init(&req->queuelist); + } + if (req && req != &ping_req) { + req->errors++; + gnbd_end_request(req); + } + } while (req); + + return 0; +} + +/* + * We always wait for result of write, for now. It would be nice to make it optional + * in future + * if ((req->cmd == WRITE) && (dev->flags & GNBD_WRITE_NOCHK)) + * { printk( "Warning: Ignoring result!\n"); gnbd_end_request( req ); } + */ + +static void do_gnbd_request(struct request_queue *q) +{ + int err; + struct request *req; + + while ((req = elv_next_request(q)) != NULL) { + struct gnbd_device *dev; + + blkdev_dequeue_request(req); + dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n", + req->rq_disk->disk_name, req, req->cmd_type); + + if (!blk_fs_request(req)) + goto error_out; + + dev = req->rq_disk->private_data; + + if (dev->receiver_pid == -1) + goto error_out; + + BUG_ON(dev->magic != GNBD_MAGIC); + + gnbd_cmd(req) = GNBD_CMD_READ; + if (rq_data_dir(req) == WRITE) { + gnbd_cmd(req) = GNBD_CMD_WRITE; + if (dev->flags & GNBD_READ_ONLY) { + printk(KERN_ERR "%s: Write on read-only\n", + dev->disk->disk_name); + goto error_out; + } + } + + req->errors = 0; + spin_unlock_irq(q->queue_lock); + + spin_lock(&dev->queue_lock); + + if (list_empty(&dev->queue_head)) + dev->last_received = jiffies; + list_add(&req->queuelist, &dev->queue_head); + spin_unlock(&dev->queue_lock); + + err = gnbd_send_req(dev, req, 0); + + spin_lock_irq(q->queue_lock); + if (err) + goto sock_error; + continue; + +error_out: + req->errors++; + spin_unlock(q->queue_lock); + gnbd_end_request(req); + spin_lock(q->queue_lock); + } + return; + +sock_error: + return; +} + +/* + * This is called before dev-sock is set, so you dodn't need + * to worry about the tx_lock or the queue_lock + */ +static int gnbd_resend_requests(struct gnbd_device *dev, struct socket *sock) +{ + int err = 0; + struct request *req; + struct list_head *tmp; + + printk("resending requests\n"); + list_for_each(tmp, &dev->queue_head) { + req = list_entry(tmp, struct request, queuelist); + err = __gnbd_send_req(dev, sock, req, 1); + + if (err){ + printk("failed trying to resend request (%d)\n", err); + break; + } + } + + return err; +} +/* +static int get_server_info(struct gnbd_device *dev, struct socket *sock) +{ + struct sockaddr_in server; + int len; + int err; + + err = sock->ops->getname(sock, (struct sockaddr *) &server, &len, 1); + if (err) { + printk(KERN_WARNING "cannot get socket info, shutting down\n"); + } else{ + dev->server_addr = server.sin_addr; + dev->server_port = server.sin_port; + } + return err; +} +*/ + +static int gnbd_ctl_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct gnbd_device *dev = NULL; + struct block_device *bdev; + do_it_req_t req; + int error; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (cmd == GNBD_DISCONNECT || cmd == GNBD_CLEAR_QUE || + cmd == GNBD_PING || cmd == GNBD_PRINT_DEBUG) { + if (arg >= MAX_GNBD) + return -EINVAL; + dev = &gnbd_dev[arg]; + BUG_ON(dev->magic != GNBD_MAGIC); + } + + /* Anyone capable of this syscall can do *real bad* things */ + dprintk(DBG_IOCTL, "%s: gnbd_ioctl cmd=%s(0x%x) arg=%lu\n", + dev->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg); + + switch (cmd) { + case GNBD_DISCONNECT: + printk(KERN_INFO "%s: GNBD_DISCONNECT\n", dev->disk->disk_name); + spin_lock(&dev->open_lock); + if (dev->open_count > 0){ + spin_unlock(&dev->open_lock); + return -EBUSY; + } + dev->receiver_pid = -1; + spin_unlock(&dev->open_lock); + /* There is no one using the device, you can disconnect it */ + if (dev->sock == NULL) + return -ENOTCONN; + gnbd_send_req(dev, &shutdown_req, 1); + return 0; + case GNBD_CLEAR_QUE: + if (down_interruptible(&dev->do_it_lock)) + return -EBUSY; + dev->receiver_pid = -1; + error = gnbd_clear_que(dev); + if (error) + return error; + bdev = dev->bdev; + if (bdev) { + blk_run_queue(dev->disk->queue); +#if 0 + fsync_bdev(bdev); + invalidate_bdev(bdev); +#endif + } + up(&dev->do_it_lock); + return 0; + case GNBD_DO_IT: + if (copy_from_user(&req, (do_it_req_t *)arg, sizeof(req))) + return -EFAULT; + if (req.minor >= 128) + return -EINVAL; + dev = &gnbd_dev[req.minor]; + BUG_ON(dev->magic != GNBD_MAGIC); + if (dev->file) + return -EBUSY; + error = -EINVAL; + file = fget(req.sock_fd); + if (!file) + return error; + inode = file->f_dentry->d_inode; + if (!S_ISSOCK(inode->i_mode)) { + fput(file); + return error; + } + if (down_trylock(&dev->do_it_lock)){ + fput(file); + return -EBUSY; + } + error = gnbd_resend_requests(dev, SOCKET_I(inode)); + if (error){ + printk("quitting GNBD_DO_IT\n"); + up(&dev->do_it_lock); + fput(file); + return error; + } + dev->file = file; + dev->sock = SOCKET_I(inode); + dev->corrupt = 0; + dev->receiver_pid = current->pid; + blk_run_queue(dev->disk->queue); + error = gnbd_do_it(dev); + /* should I kill the socket first */ + up(&dev->do_it_lock); + down(&dev->tx_lock); + if (dev->sock) { + printk(KERN_WARNING "%s: shutting down socket\n", + dev->disk->disk_name); + dev->sock->ops->shutdown(dev->sock, + SEND_SHUTDOWN|RCV_SHUTDOWN); + dev->sock = NULL; + } + up(&dev->tx_lock); + file = dev->file; + dev->file = NULL; + if (file) + fput(file); + printk("exiting GNBD_DO_IT ioctl\n"); + return error; + case GNBD_PING: + /* FIXME -- should I allow pings if everything is compeletely + * shutdown */ + spin_lock(&dev->queue_lock); + /* only one outstanding ping at a time */ + if (list_empty(&ping_req.queuelist)){ + if (list_empty(&dev->queue_head)) + dev->last_received = jiffies; + list_add(&ping_req.queuelist, &dev->queue_head); + } + spin_unlock(&dev->queue_lock); + gnbd_send_req(dev, &ping_req, 1); /* ignore the errors */ + return 0; + case GNBD_PRINT_DEBUG: + printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n", + dev->disk->disk_name, + dev->queue_head.next, dev->queue_head.prev, + &dev->queue_head); + return 0; + case GNBD_GET_TIME: + if (copy_to_user((void *)arg, &insmod_time, sizeof(uint64_t))){ + printk(KERN_WARNING "couldn't copy time argument to user\n"); + return -EFAULT; + } + return 0; + } + /* FIXME -- should I print something, is EINVAL the right error */ + return -EINVAL; +} + +#ifdef CONFIG_COMPAT +static long gnbd_ctl_compat_ioctl(struct file *f, unsigned cmd, + unsigned long arg) +{ + int ret; + switch (cmd) { + case GNBD_DISCONNECT: + case GNBD_CLEAR_QUE: + case GNBD_PING: + case GNBD_PRINT_DEBUG: + lock_kernel(); + ret = gnbd_ctl_ioctl(f->f_dentry->d_inode, f, cmd, arg); + unlock_kernel(); + return ret; + case GNBD_DO_IT: + case GNBD_GET_TIME: + lock_kernel(); + ret = gnbd_ctl_ioctl(f->f_dentry->d_inode, f, cmd, + (unsigned long)compat_ptr(arg)); + unlock_kernel(); + return ret; + default: + return -ENOIOCTLCMD; + } +} +#endif + +static int gnbd_open(struct inode *inode, struct file *file) +{ + struct gnbd_device *dev = inode->i_bdev->bd_disk->private_data; + spin_lock(&dev->open_lock); + if (dev->receiver_pid == -1){ + spin_unlock(&dev->open_lock); + return -ENXIO; + } + spin_unlock(&dev->open_lock); + if ((file->f_mode & FMODE_WRITE) && (dev->flags & GNBD_READ_ONLY)){ + printk(KERN_INFO "cannot open read only gnbd device read/write"); + return -EROFS; + } + + dev->open_count++; + dev->bdev = inode->i_bdev; + return 0; +} + +/* FIXME -- I don't sync the device at close. This means that If you write + * something, and close the device, and expect that then it is written, + * you are wrong.... This might cause problems */ +static int gnbd_release(struct inode *inode, struct file *file) +{ + struct gnbd_device *dev = inode->i_bdev->bd_disk->private_data; + + dev->open_count--; + if (dev->open_count == 0) + dev->bdev = NULL; + return 0; +} + +static struct file_operations _gnbd_ctl_fops = +{ + .ioctl = gnbd_ctl_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = gnbd_ctl_compat_ioctl, +#endif + .owner = THIS_MODULE, +}; + +static struct miscdevice _gnbd_misc = +{ + .minor = MISC_DYNAMIC_MINOR, + .name = "gnbd_ctl", + .fops = &_gnbd_ctl_fops +}; + +/* FIXME -- I should probably do more here */ +int __init gnbd_ctl_init(void) +{ + int err; + + err = misc_register(&_gnbd_misc); + if (err) { + printk("cannot register control device\n"); + return err; + } + return 0; +} + +void gnbd_ctl_cleanup(void) +{ + if (misc_deregister(&_gnbd_misc) < 0) + printk("cannot deregister control device\n"); +} + +static struct block_device_operations gnbd_fops = +{ + .open = gnbd_open, + .release = gnbd_release, + .owner = THIS_MODULE, +}; + +/* + * And here should be modules and kernel interface + * (Just smiley confuses emacs :-) + */ + +static int __init gnbd_init(void) +{ + int err = -ENOMEM; + struct timeval tv; + int i; + + BUILD_BUG_ON(sizeof(struct gnbd_request) != 28); + + shutdown_req.cmd_type = REQ_TYPE_SPECIAL; + gnbd_cmd(&shutdown_req) = GNBD_CMD_DISC; + shutdown_req.sector = 0; + shutdown_req.nr_sectors = 0; + + ping_req.cmd_type = REQ_TYPE_SPECIAL; + gnbd_cmd(&ping_req) = GNBD_CMD_PING; + ping_req.sector = 0; + ping_req.nr_sectors = 0; + + for (i = 0; i < MAX_GNBD; i++) { + struct gendisk *disk = alloc_disk(1); + if (!disk) + goto out; + gnbd_dev[i].disk = disk; + /* + * The new linux 2.5 block layer implementation requires + * every gendisk to have its very own request_queue struct. + * These structs are big so we dynamically allocate them. + */ + disk->queue = blk_init_queue(do_gnbd_request, &gnbd_lock); + if (!disk->queue) { + put_disk(disk); + goto out; + } + elevator_exit(disk->queue->elevator); + err = elevator_init(disk->queue, "deadline"); + if (err) { + blk_cleanup_queue(disk->queue); + put_disk(disk); + goto out; + } + } + major_nr = register_blkdev(major_nr, "gnbd"); + if (major_nr < 0) { + printk("gnbd: unable to get a major number\n"); + err = major_nr; + goto out; + } + + printk(KERN_INFO "gnbd: registered device at major %d\n", major_nr); + dprintk(DBG_INIT, "gnbd: debugflags=0x%x\n", debugflags); + + err = class_register(&gnbd_class); + if (err) + goto out_unregister; + for (i = 0; i < MAX_GNBD; i++) { + struct gendisk *disk = gnbd_dev[i].disk; + gnbd_dev[i].file = NULL; + gnbd_dev[i].magic = GNBD_MAGIC; + gnbd_dev[i].flags = 0; + gnbd_dev[i].open_count = 0; + gnbd_dev[i].receiver_pid = -1; + gnbd_dev[i].server_name = NULL; + gnbd_dev[i].server_port = 0; + gnbd_dev[i].name[0] = '\0'; + gnbd_dev[i].bdev = NULL; + spin_lock_init(&gnbd_dev[i].queue_lock); + spin_lock_init(&gnbd_dev[i].open_lock); + INIT_LIST_HEAD(&gnbd_dev[i].queue_head); + init_MUTEX(&gnbd_dev[i].tx_lock); + init_MUTEX(&gnbd_dev[i].do_it_lock); + init_waitqueue_head(&gnbd_dev[i].tx_wait); + gnbd_dev[i].current_request = NULL; + gnbd_dev[i].class_dev.class = &gnbd_class; + sprintf(gnbd_dev[i].class_dev.bus_id, "gnbd%d", i); + err = device_register(&gnbd_dev[i].class_dev); + if (err){ + printk("device_register failed with %d\n", err); + goto out_unregister_class; + } + if(device_create_file(&gnbd_dev[i].class_dev, + &dev_attr_pid)) + goto out_remove_file; + if(device_create_file(&gnbd_dev[i].class_dev, + &dev_attr_server)) + goto out_remove_file; + if(device_create_file(&gnbd_dev[i].class_dev, + &dev_attr_name)) + goto out_remove_file; + if(device_create_file(&gnbd_dev[i].class_dev, + &dev_attr_sectors)) + goto out_remove_file; + if(device_create_file(&gnbd_dev[i].class_dev, + &dev_attr_usage)) + goto out_remove_file; + if(device_create_file(&gnbd_dev[i].class_dev, + &dev_attr_flags)) + goto out_remove_file; + if(device_create_file(&gnbd_dev[i].class_dev, + &dev_attr_waittime)) + goto out_remove_file; + if(device_create_file(&gnbd_dev[i].class_dev, + &dev_attr_connected)) + goto out_remove_file; + disk->major = major_nr; + disk->first_minor = i; + disk->fops = &gnbd_fops; + disk->private_data = &gnbd_dev[i]; + sprintf(disk->disk_name, "gnbd%d", i); + set_capacity(disk, 0); + add_disk(disk); + if(sysfs_create_link(&gnbd_dev[i].class_dev.kobj, + &gnbd_dev[i].disk->dev.kobj, "block")) + goto out_remove_disk; + + } + + err = gnbd_ctl_init(); + if (err) + goto out_unregister_class; + + do_gettimeofday(&tv); + insmod_time = (uint64_t) tv.tv_sec * 1000000 + tv.tv_usec; + + return 0; +out_remove_disk: + del_gendisk(gnbd_dev[i].disk); +out_remove_file: + device_unregister(&gnbd_dev[i].class_dev); +out_unregister_class: + while(i--){ + del_gendisk(gnbd_dev[i].disk); + device_unregister(&gnbd_dev[i].class_dev); + } + i = MAX_GNBD; + class_unregister(&gnbd_class); +out_unregister: + unregister_blkdev(major_nr, "gnbd"); +out: + while (i--) { + blk_cleanup_queue(gnbd_dev[i].disk->queue); + put_disk(gnbd_dev[i].disk); + } + return err; +} + +static void __exit gnbd_cleanup(void) +{ + int i; + + gnbd_ctl_cleanup(); + for (i = 0; i < MAX_GNBD; i++) { + struct gendisk *disk = gnbd_dev[i].disk; + device_unregister(&gnbd_dev[i].class_dev); + if (disk) { + del_gendisk(disk); + blk_cleanup_queue(disk->queue); + put_disk(disk); + } + if (gnbd_dev[i].server_name) + kfree(gnbd_dev[i].server_name); + } + class_unregister(&gnbd_class); + unregister_blkdev(major_nr, "gnbd"); + printk(KERN_INFO "gnbd: unregistered device at major %d\n", major_nr); +} + +module_init(gnbd_init); +module_exit(gnbd_cleanup); + +MODULE_DESCRIPTION("Network Block Device"); +MODULE_LICENSE("GPL"); + +#ifndef NDEBUG +module_param(debugflags, uint, 0644); +MODULE_PARM_DESC(debugflags, "flags for controlling debug output"); +#endif --- linux-2.6.27.orig/ubuntu/gnbd/Makefile +++ linux-2.6.27/ubuntu/gnbd/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_GNBD) += gnbd.o --- linux-2.6.27.orig/ubuntu/gnbd/BOM +++ linux-2.6.27/ubuntu/gnbd/BOM @@ -0,0 +1,2 @@ +Downloaded from: http://git.fedorahosted.org/git/cluster.git +Current Version: 2.03.06 --- linux-2.6.27.orig/ubuntu/misc/tp_smapi.c +++ linux-2.6.27/ubuntu/misc/tp_smapi.c @@ -0,0 +1,1477 @@ +/* + * tp_smapi.c - ThinkPad SMAPI support + * + * This driver exposes some features of the System Management Application + * Program Interface (SMAPI) BIOS found on ThinkPad laptops. It works on + * models in which the SMAPI BIOS runs in SMM and is invoked by writing + * to the APM control port 0xB2. Older models use a different interface; + * for those, try the out-of-tree "thinkpad" module from "tpctl". + * It also exposes battery status information, obtained from the ThinkPad + * embedded controller (via the thinkpad_ec module). + * + * Many of the battery status values obtained from the EC simply mirror + * values provided by the battery's Smart Battery System (SBS) interface, so + * their meaning is defined by the Smart Battery Data Specification. + * References to this SBS spec are given in the code where relevant. + * + * Copyright (C) 2006 Shem Multinymous . + * SMAPI access code based on the mwave driver by Mike Sullivan. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include /* CMOS defines */ +#include +#include +#include "thinkpad_ec.h" +#include +#include +#include + +#define TP_VERSION "0.37" +#define TP_DESC "ThinkPad SMAPI Support" +#define TP_DIR "smapi" + +MODULE_AUTHOR("Shem Multinymous"); +MODULE_DESCRIPTION(TP_DESC); +MODULE_VERSION(TP_VERSION); +MODULE_LICENSE("GPL"); + +static struct platform_device *pdev; + +static int tp_debug; +module_param_named(debug, tp_debug, int, 0600); +MODULE_PARM_DESC(debug, "Debug level (0=off, 1=on)"); + +/* A few macros for printk()ing: */ +#define TPRINTK(level, fmt, args...) \ + dev_printk(level, &(pdev->dev), "%s: " fmt "\n", __func__, ## args) +#define DPRINTK(fmt, args...) \ + do { if (tp_debug) TPRINTK(KERN_DEBUG, fmt, ## args); } while (0) + +/********************************************************************* + * SMAPI interface + */ + +/* SMAPI functions (register BX when making the SMM call). */ +#define SMAPI_GET_INHIBIT_CHARGE 0x2114 +#define SMAPI_SET_INHIBIT_CHARGE 0x2115 +#define SMAPI_GET_THRESH_START 0x2116 +#define SMAPI_SET_THRESH_START 0x2117 +#define SMAPI_GET_FORCE_DISCHARGE 0x2118 +#define SMAPI_SET_FORCE_DISCHARGE 0x2119 +#define SMAPI_GET_THRESH_STOP 0x211a +#define SMAPI_SET_THRESH_STOP 0x211b + +/* SMAPI error codes (see ThinkPad 770 Technical Reference Manual p.83 at + http://www-307.ibm.com/pc/support/site.wss/document.do?lndocid=PFAN-3TUQQD */ +#define SMAPI_RETCODE_EOF 0xff +static struct { u8 rc; char *msg; int ret; } smapi_retcode[] = +{ + {0x00, "OK", 0}, + {0x53, "SMAPI fuction is not available", -ENXIO}, + {0x81, "Invalid parameter", -EINVAL}, + {0x86, "Function is not supported by SMAPI BIOS", -EOPNOTSUPP}, + {0x90, "System error", -EIO}, + {0x91, "System is invalid", -EIO}, + {0x92, "System is busy, -EBUSY"}, + {0xa0, "Device error (disk read error)", -EIO}, + {0xa1, "Device is busy", -EBUSY}, + {0xa2, "Device is not attached", -ENXIO}, + {0xa3, "Device is disbled", -EIO}, + {0xa4, "Request parameter is out of range", -EINVAL}, + {0xa5, "Request parameter is not accepted", -EINVAL}, + {0xa6, "Transient error", -EBUSY}, /* ? */ + {SMAPI_RETCODE_EOF, "Unknown error code", -EIO} +}; + + +#define SMAPI_MAX_RETRIES 10 +#define SMAPI_PORT2 0x4F /* fixed port, meaning unclear */ +static unsigned short smapi_port; /* APM control port, normally 0xB2 */ + +static DECLARE_MUTEX(smapi_mutex); + +/** + * find_smapi_port - read SMAPI port from NVRAM + */ +static int __init find_smapi_port(void) +{ + u16 smapi_id = 0; + unsigned short port = 0; + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); + smapi_id = CMOS_READ(0x7C); + smapi_id |= (CMOS_READ(0x7D) << 8); + spin_unlock_irqrestore(&rtc_lock, flags); + + if (smapi_id != 0x5349) { + printk(KERN_ERR "SMAPI not supported (ID=0x%x)\n", smapi_id); + return -ENXIO; + } + spin_lock_irqsave(&rtc_lock, flags); + port = CMOS_READ(0x7E); + port |= (CMOS_READ(0x7F) << 8); + spin_unlock_irqrestore(&rtc_lock, flags); + if (port == 0) { + printk(KERN_ERR "unable to read SMAPI port number\n"); + return -ENXIO; + } + return port; +} + +/** + * smapi_request - make a SMAPI call + * @inEBX, @inECX, @inEDI, @inESI: input registers + * @outEBX, @outECX, @outEDX, @outEDI, @outESI: outputs registers + * @msg: textual error message + * Invokes the SMAPI SMBIOS with the given input and outpu args. + * All outputs are optional (can be %NULL). + * Returns 0 when successful, and a negative errno constant + * (see smapi_retcode above) upon failure. + */ +static int smapi_request(u32 inEBX, u32 inECX, + u32 inEDI, u32 inESI, + u32 *outEBX, u32 *outECX, u32 *outEDX, + u32 *outEDI, u32 *outESI, const char **msg) +{ + int ret = 0; + int i; + int retries; + u8 rc; + /* Must use local vars for output regs, due to reg pressure. */ + u32 tmpEAX, tmpEBX, tmpECX, tmpEDX, tmpEDI, tmpESI; + + for (retries = 0; retries < SMAPI_MAX_RETRIES; ++retries) { + DPRINTK("req_in: BX=%x CX=%x DI=%x SI=%x", + inEBX, inECX, inEDI, inESI); + + /* SMAPI's SMBIOS call and thinkpad_ec end up using use + * different interfaces to the same chip, so play it safe. */ + ret = thinkpad_ec_lock(); + if (ret) + return ret; + + __asm__ __volatile__( + "movl $0x00005380,%%eax\n\t" + "movl %6,%%ebx\n\t" + "movl %7,%%ecx\n\t" + "movl %8,%%edi\n\t" + "movl %9,%%esi\n\t" + "xorl %%edx,%%edx\n\t" + "movw %10,%%dx\n\t" + "out %%al,%%dx\n\t" /* trigger SMI to SMBIOS */ + "out %%al,$0x4F\n\t" + "movl %%eax,%0\n\t" + "movl %%ebx,%1\n\t" + "movl %%ecx,%2\n\t" + "movl %%edx,%3\n\t" + "movl %%edi,%4\n\t" + "movl %%esi,%5\n\t" + :"=m"(tmpEAX), + "=m"(tmpEBX), + "=m"(tmpECX), + "=m"(tmpEDX), + "=m"(tmpEDI), + "=m"(tmpESI) + :"m"(inEBX), "m"(inECX), "m"(inEDI), "m"(inESI), + "m"((u16)smapi_port) + :"%eax", "%ebx", "%ecx", "%edx", "%edi", + "%esi"); + + thinkpad_ec_invalidate(); + thinkpad_ec_unlock(); + + /* Don't let the next SMAPI access happen too quickly, + * may case problems. (We're hold smapi_mutex). */ + msleep(50); + + if (outEBX) *outEBX = tmpEBX; + if (outECX) *outECX = tmpECX; + if (outEDX) *outEDX = tmpEDX; + if (outESI) *outESI = tmpESI; + if (outEDI) *outEDI = tmpEDI; + + /* Look up error code */ + rc = (tmpEAX>>8)&0xFF; + for (i = 0; smapi_retcode[i].rc != SMAPI_RETCODE_EOF && + smapi_retcode[i].rc != rc; ++i) {} + ret = smapi_retcode[i].ret; + if (msg) + *msg = smapi_retcode[i].msg; + + DPRINTK("req_out: AX=%x BX=%x CX=%x DX=%x DI=%x SI=%x r=%d", + tmpEAX, tmpEBX, tmpECX, tmpEDX, tmpEDI, tmpESI, ret); + if (ret) + TPRINTK(KERN_NOTICE, "SMAPI error: %s (func=%x)", + smapi_retcode[i].msg, inEBX); + + if (ret != -EBUSY) + return ret; + } + return ret; +} + +/* Convenience wrapper: discard output arguments */ +static int smapi_write(u32 inEBX, u32 inECX, + u32 inEDI, u32 inESI, const char **msg) +{ + return smapi_request(inEBX, inECX, inEDI, inESI, + NULL, NULL, NULL, NULL, NULL, msg); +} + + +/********************************************************************* + * Specific SMAPI services + * All of these functions return 0 upon success, and a negative errno + * constant (see smapi_retcode) on failure. + */ + +enum thresh_type { + THRESH_STOP = 0, /* the code assumes this is 0 for brevity */ + THRESH_START +}; +#define THRESH_NAME(which) ((which == THRESH_START) ? "start" : "stop") + +/** + * __get_real_thresh - read battery charge start/stop threshold from SMAPI + * @bat: battery number (0 or 1) + * @which: THRESH_START or THRESH_STOP + * @thresh: 1..99, 0=default 1..99, 0=default (pass this as-is to SMAPI) + * @outEDI: some additional state that needs to be preserved, meaning unknown + * @outESI: some additional state that needs to be preserved, meaning unknown + */ +static int __get_real_thresh(int bat, enum thresh_type which, int *thresh, + u32 *outEDI, u32 *outESI) +{ + u32 ebx = (which == THRESH_START) ? SMAPI_GET_THRESH_START + : SMAPI_GET_THRESH_STOP; + u32 ecx = (bat+1)<<8; + const char *msg; + int ret = smapi_request(ebx, ecx, 0, 0, NULL, + &ecx, NULL, outEDI, outESI, &msg); + if (ret) { + TPRINTK(KERN_NOTICE, "cannot get %s_thresh of bat=%d: %s", + THRESH_NAME(which), bat, msg); + return ret; + } + if (!(ecx&0x00000100)) { + TPRINTK(KERN_NOTICE, "cannot get %s_thresh of bat=%d: ecx=0%x", + THRESH_NAME(which), bat, ecx); + return -EIO; + } + if (thresh) + *thresh = ecx&0xFF; + return 0; +} + +/** + * get_real_thresh - read battery charge start/stop threshold from SMAPI + * @bat: battery number (0 or 1) + * @which: THRESH_START or THRESH_STOP + * @thresh: 1..99, 0=default (passes as-is to SMAPI) + */ +static int get_real_thresh(int bat, enum thresh_type which, int *thresh) +{ + return __get_real_thresh(bat, which, thresh, NULL, NULL); +} + +/** + * set_real_thresh - write battery start/top charge threshold to SMAPI + * @bat: battery number (0 or 1) + * @which: THRESH_START or THRESH_STOP + * @thresh: 1..99, 0=default (passes as-is to SMAPI) + */ +static int set_real_thresh(int bat, enum thresh_type which, int thresh) +{ + u32 ebx = (which == THRESH_START) ? SMAPI_SET_THRESH_START + : SMAPI_SET_THRESH_STOP; + u32 ecx = ((bat+1)<<8) + thresh; + u32 getDI, getSI; + const char *msg; + int ret; + + /* verify read before writing */ + ret = __get_real_thresh(bat, which, NULL, &getDI, &getSI); + if (ret) + return ret; + + ret = smapi_write(ebx, ecx, getDI, getSI, &msg); + if (ret) + TPRINTK(KERN_NOTICE, "set %s to %d for bat=%d failed: %s", + THRESH_NAME(which), thresh, bat, msg); + else + TPRINTK(KERN_INFO, "set %s to %d for bat=%d", + THRESH_NAME(which), thresh, bat); + return ret; +} + +/** + * __get_inhibit_charge_minutes - get inhibit charge period from SMAPI + * @bat: battery number (0 or 1) + * @minutes: period in minutes (1..65535 minutes, 0=disabled) + * @outECX: some additional state that needs to be preserved, meaning unknown + * Note that @minutes is the originally set value, it does not count down. + */ +static int __get_inhibit_charge_minutes(int bat, int *minutes, u32 *outECX) +{ + u32 ecx = (bat+1)<<8; + u32 esi; + const char *msg; + int ret = smapi_request(SMAPI_GET_INHIBIT_CHARGE, ecx, 0, 0, + NULL, &ecx, NULL, NULL, &esi, &msg); + if (ret) { + TPRINTK(KERN_NOTICE, "failed for bat=%d: %s", bat, msg); + return ret; + } + if (!(ecx&0x0100)) { + TPRINTK(KERN_NOTICE, "bad ecx=0x%x for bat=%d", ecx, bat); + return -EIO; + } + if (minutes) + *minutes = (ecx&0x0001)?esi:0; + if (outECX) + *outECX = ecx; + return 0; +} + +/** + * get_inhibit_charge_minutes - get inhibit charge period from SMAPI + * @bat: battery number (0 or 1) + * @minutes: period in minutes (1..65535 minutes, 0=disabled) + * Note that @minutes is the originally set value, it does not count down. + */ +static int get_inhibit_charge_minutes(int bat, int *minutes) +{ + return __get_inhibit_charge_minutes(bat, minutes, NULL); +} + +/** + * set_inhibit_charge_minutes - write inhibit charge period to SMAPI + * @bat: battery number (0 or 1) + * @minutes: period in minutes (1..65535 minutes, 0=disabled) + */ +static int set_inhibit_charge_minutes(int bat, int minutes) +{ + u32 ecx; + const char *msg; + int ret; + + /* verify read before writing */ + ret = __get_inhibit_charge_minutes(bat, NULL, &ecx); + if (ret) + return ret; + + ecx = ((bat+1)<<8) | (ecx&0x00FE) | (minutes > 0 ? 0x0001 : 0x0000); + if (minutes > 0xFFFF) + minutes = 0xFFFF; + ret = smapi_write(SMAPI_SET_INHIBIT_CHARGE, ecx, 0, minutes, &msg); + if (ret) + TPRINTK(KERN_NOTICE, + "set to %d failed for bat=%d: %s", minutes, bat, msg); + else + TPRINTK(KERN_INFO, "set to %d for bat=%d\n", minutes, bat); + return ret; +} + + +/** + * get_force_discharge - get status of forced discharging from SMAPI + * @bat: battery number (0 or 1) + * @enabled: 1 if forced discharged is enabled, 0 if not + */ +static int get_force_discharge(int bat, int *enabled) +{ + u32 ecx = (bat+1)<<8; + const char *msg; + int ret = smapi_request(SMAPI_GET_FORCE_DISCHARGE, ecx, 0, 0, + NULL, &ecx, NULL, NULL, NULL, &msg); + if (ret) { + TPRINTK(KERN_NOTICE, "failed for bat=%d: %s", bat, msg); + return ret; + } + *enabled = (!(ecx&0x00000100) && (ecx&0x00000001))?1:0; + return 0; +} + +/** + * set_force_discharge - write status of forced discharging to SMAPI + * @bat: battery number (0 or 1) + * @enabled: 1 if forced discharged is enabled, 0 if not + */ +static int set_force_discharge(int bat, int enabled) +{ + u32 ecx = (bat+1)<<8; + const char *msg; + int ret = smapi_request(SMAPI_GET_FORCE_DISCHARGE, ecx, 0, 0, + NULL, &ecx, NULL, NULL, NULL, &msg); + if (ret) { + TPRINTK(KERN_NOTICE, "get failed for bat=%d: %s", bat, msg); + return ret; + } + if (ecx&0x00000100) { + TPRINTK(KERN_NOTICE, "cannot force discharge bat=%d", bat); + return -EIO; + } + + ecx = ((bat+1)<<8) | (ecx&0x000000FA) | (enabled?0x00000001:0); + ret = smapi_write(SMAPI_SET_FORCE_DISCHARGE, ecx, 0, 0, &msg); + if (ret) + TPRINTK(KERN_NOTICE, "set to %d failed for bat=%d: %s", + enabled, bat, msg); + else + TPRINTK(KERN_INFO, "set to %d for bat=%d", enabled, bat); + return ret; +} + + +/********************************************************************* + * Wrappers to threshold-related SMAPI functions, which handle default + * thresholds and related quirks. + */ + +/* Minimum, default and minimum difference for battery charging thresholds: */ +#define MIN_THRESH_DELTA 4 /* Min delta between start and stop thresh */ +#define MIN_THRESH_START 2 +#define MAX_THRESH_START (100-MIN_THRESH_DELTA) +#define MIN_THRESH_STOP (MIN_THRESH_START + MIN_THRESH_DELTA) +#define MAX_THRESH_STOP 100 +#define DEFAULT_THRESH_START MAX_THRESH_START +#define DEFAULT_THRESH_STOP MAX_THRESH_STOP + +/* The GUI of IBM's Battery Maximizer seems to show a start threshold that + * is 1 more than the value we set/get via SMAPI. Since the threshold is + * maintained across reboot, this can be confusing. So we kludge our + * interface for interoperability: */ +#define BATMAX_FIX 1 + +/* Get charge start/stop threshold (1..100), + * substituting default values if needed and applying BATMAT_FIX. */ +static int get_thresh(int bat, enum thresh_type which, int *thresh) +{ + int ret = get_real_thresh(bat, which, thresh); + if (ret) + return ret; + if (*thresh == 0) + *thresh = (which == THRESH_START) ? DEFAULT_THRESH_START + : DEFAULT_THRESH_STOP; + else if (which == THRESH_START) + *thresh += BATMAX_FIX; + return 0; +} + + +/* Set charge start/stop threshold (1..100), + * substituting default values if needed and applying BATMAT_FIX. */ +static int set_thresh(int bat, enum thresh_type which, int thresh) +{ + if (which == THRESH_STOP && thresh == DEFAULT_THRESH_STOP) + thresh = 0; /* 100 is out of range, but default means 100 */ + if (which == THRESH_START) + thresh -= BATMAX_FIX; + return set_real_thresh(bat, which, thresh); +} + +/********************************************************************* + * ThinkPad embedded controller readout and basic functions + */ + +/** + * read_tp_ec_row - read data row from the ThinkPad embedded controller + * @arg0: EC command code + * @bat: battery number, 0 or 1 + * @j: the byte value to be used for "junk" (unused) input/outputs + * @dataval: result vector + */ +static int read_tp_ec_row(u8 arg0, int bat, u8 j, u8 *dataval) +{ + int ret; + const struct thinkpad_ec_row args = { .mask = 0xFFFF, + .val = {arg0, j,j,j,j,j,j,j,j,j,j,j,j,j,j, (u8)bat} }; + struct thinkpad_ec_row data = { .mask = 0xFFFF }; + + ret = thinkpad_ec_lock(); + if (ret) + return ret; + ret = thinkpad_ec_read_row(&args, &data); + thinkpad_ec_unlock(); + memcpy(dataval, &data.val, TP_CONTROLLER_ROW_LEN); + return ret; +} + +/** + * power_device_present - check for presence of battery or AC power + * @bat: 0 for battery 0, 1 for battery 1, otherwise AC power + * Returns 1 if present, 0 if not present, negative if error. + */ +static int power_device_present(int bat) +{ + u8 row[TP_CONTROLLER_ROW_LEN]; + u8 test; + int ret = read_tp_ec_row(1, bat, 0, row); + if (ret) + return ret; + switch (bat) { + case 0: test = 0x40; break; /* battery 0 */ + case 1: test = 0x20; break; /* battery 1 */ + default: test = 0x80; /* AC power */ + } + return (row[0] & test) ? 1 : 0; +} + +/** + * bat_has_status - check if battery can report detailed status + * @bat: 0 for battery 0, 1 for battery 1 + * Returns 1 if yes, 0 if no, negative if error. + */ +static int bat_has_status(int bat) +{ + u8 row[TP_CONTROLLER_ROW_LEN]; + int ret = read_tp_ec_row(1, bat, 0, row); + if (ret) + return ret; + if ((row[0] & (bat?0x20:0x40)) == 0) /* no battery */ + return 0; + if ((row[1] & (0x60)) == 0) /* no status */ + return 0; + return 1; +} + +/** + * get_tp_ec_bat_16 - read a 16-bit value from EC battery status data + * @arg0: first argument to EC + * @off: offset in row returned from EC + * @bat: battery (0 or 1) + * @val: the 16-bit value obtained + * Returns nonzero on error. + */ +static int get_tp_ec_bat_16(u8 arg0, int offset, int bat, u16 *val) +{ + u8 row[TP_CONTROLLER_ROW_LEN]; + int ret; + if (bat_has_status(bat) != 1) + return -ENXIO; + ret = read_tp_ec_row(arg0, bat, 0, row); + if (ret) + return ret; + *val = *(u16 *)(row+offset); + return 0; +} + +/********************************************************************* + * sysfs attributes for batteries - + * definitions and helper functions + */ + +/* A custom device attribute struct which holds a battery number */ +struct bat_device_attribute { + struct device_attribute dev_attr; + int bat; +}; + +/** + * attr_get_bat - get the battery to which the attribute belongs + */ +static int attr_get_bat(struct device_attribute *attr) +{ + return container_of(attr, struct bat_device_attribute, dev_attr)->bat; +} + +/** + * show_tp_ec_bat_u16 - show an unsigned 16-bit battery attribute + * @arg0: specified 1st argument of EC raw to read + * @offset: byte offset in EC raw data + * @mul: correction factor to multiply by + * @na_msg: string to output is value not available (0xFFFFFFFF) + * @attr: battery attribute + * @buf: output buffer + * The 16-bit value is read from the EC, treated as unsigned, + * transformed as x->mul*x, and printed to the buffer. + * If the value is 0xFFFFFFFF and na_msg!=%NULL, na_msg is printed instead. + */ +static ssize_t show_tp_ec_bat_u16(u8 arg0, int offset, int mul, + const char *na_msg, + struct device_attribute *attr, char *buf) +{ + u16 val; + int ret = get_tp_ec_bat_16(arg0, offset, attr_get_bat(attr), &val); + if (ret) + return ret; + if (na_msg && val == 0xFFFF) + return sprintf(buf, "%s\n", na_msg); + else + return sprintf(buf, "%u\n", mul*(unsigned int)val); +} + +/** + * show_tp_ec_bat_s16 - show an signed 16-bit battery attribute + * @arg0: specified 1st argument of EC raw to read + * @offset: byte offset in EC raw data + * @mul: correction factor to multiply by + * @add: correction term to add after multiplication + * @attr: battery attribute + * @buf: output buffer + * The 16-bit value is read from the EC, treated as signed, + * transformed as x->mul*x+add, and printed to the buffer. + */ +static ssize_t show_tp_ec_bat_s16(u8 arg0, int offset, int mul, int add, + struct device_attribute *attr, char *buf) +{ + u16 val; + int ret = get_tp_ec_bat_16(arg0, offset, attr_get_bat(attr), &val); + if (ret) + return ret; + return sprintf(buf, "%d\n", mul*(s16)val+add); +} + +/** + * show_tp_ec_bat_str - show a string from EC battery status data + * @arg0: specified 1st argument of EC raw to read + * @offset: byte offset in EC raw data + * @maxlen: maximum string length + * @attr: battery attribute + * @buf: output buffer + */ +static ssize_t show_tp_ec_bat_str(u8 arg0, int offset, int maxlen, + struct device_attribute *attr, char *buf) +{ + int bat = attr_get_bat(attr); + u8 row[TP_CONTROLLER_ROW_LEN]; + int ret; + if (bat_has_status(bat) != 1) + return -ENXIO; + ret = read_tp_ec_row(arg0, bat, 0, row); + if (ret) + return ret; + strncpy(buf, (char *)row+offset, maxlen); + buf[maxlen] = 0; + strcat(buf, "\n"); + return strlen(buf); +} + +/** + * show_tp_ec_bat_power - show a power readout from EC battery status data + * @arg0: specified 1st argument of EC raw to read + * @offV: byte offset of voltage in EC raw data + * @offI: byte offset of current in EC raw data + * @attr: battery attribute + * @buf: output buffer + * Computes the power as current*voltage from the two given readout offsets. + */ +static ssize_t show_tp_ec_bat_power(u8 arg0, int offV, int offI, + struct device_attribute *attr, char *buf) +{ + u8 row[TP_CONTROLLER_ROW_LEN]; + int milliamp, millivolt, ret; + int bat = attr_get_bat(attr); + if (bat_has_status(bat) != 1) + return -ENXIO; + ret = read_tp_ec_row(1, bat, 0, row); + if (ret) + return ret; + millivolt = *(u16 *)(row+offV); + milliamp = *(s16 *)(row+offI); + return sprintf(buf, "%d\n", milliamp*millivolt/1000); /* units: mW */ +} + +/** + * show_tp_ec_bat_date - decode and show a date from EC battery status data + * @arg0: specified 1st argument of EC raw to read + * @offset: byte offset in EC raw data + * @attr: battery attribute + * @buf: output buffer + */ +static ssize_t show_tp_ec_bat_date(u8 arg0, int offset, + struct device_attribute *attr, char *buf) +{ + u8 row[TP_CONTROLLER_ROW_LEN]; + u16 v; + int ret; + int day, month, year; + int bat = attr_get_bat(attr); + if (bat_has_status(bat) != 1) + return -ENXIO; + ret = read_tp_ec_row(arg0, bat, 0, row); + if (ret) + return ret; + + /* Decode bit-packed: v = day | (month<<5) | ((year-1980)<<9) */ + v = *(u16 *)(row+offset); + day = v & 0x1F; + month = (v >> 5) & 0xF; + year = (v >> 9) + 1980; + + return sprintf(buf, "%04d-%02d-%02d\n", year, month, day); +} + + +/********************************************************************* + * sysfs attribute I/O for batteries - + * the actual attribute show/store functions + */ + +static ssize_t show_battery_start_charge_thresh(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int thresh; + int bat = attr_get_bat(attr); + int ret = get_thresh(bat, THRESH_START, &thresh); + if (ret) + return ret; + return sprintf(buf, "%d\n", thresh); /* units: percent */ +} + +static ssize_t show_battery_stop_charge_thresh(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int thresh; + int bat = attr_get_bat(attr); + int ret = get_thresh(bat, THRESH_STOP, &thresh); + if (ret) + return ret; + return sprintf(buf, "%d\n", thresh); /* units: percent */ +} + +/** + * store_battery_start_charge_thresh - store battery_start_charge_thresh attr + * Since this is a kernel<->user interface, we ensure a valid state for + * the hardware. We do this by clamping the requested threshold to the + * valid range and, if necessary, moving the other threshold so that + * it's MIN_THRESH_DELTA away from this one. + */ +static ssize_t store_battery_start_charge_thresh(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int thresh, other_thresh, ret; + int bat = attr_get_bat(attr); + + if (sscanf(buf, "%d", &thresh) != 1 || thresh < 1 || thresh > 100) + return -EINVAL; + + if (thresh < MIN_THRESH_START) /* clamp up to MIN_THRESH_START */ + thresh = MIN_THRESH_START; + if (thresh > MAX_THRESH_START) /* clamp down to MAX_THRESH_START */ + thresh = MAX_THRESH_START; + + down(&smapi_mutex); + ret = get_thresh(bat, THRESH_STOP, &other_thresh); + if (ret != -EOPNOTSUPP) { + if (ret) /* other threshold is set? */ + goto out; + ret = get_real_thresh(bat, THRESH_START, NULL); + if (ret) /* this threshold is set? */ + goto out; + if (other_thresh < thresh+MIN_THRESH_DELTA) { + /* move other thresh to keep it above this one */ + ret = set_thresh(bat, THRESH_STOP, + thresh+MIN_THRESH_DELTA); + if (ret) + goto out; + } + } + ret = set_thresh(bat, THRESH_START, thresh); +out: + up(&smapi_mutex); + return count; + +} + +/** + * store_battery_stop_charge_thresh - store battery_stop_charge_thresh attr + * Since this is a kernel<->user interface, we ensure a valid state for + * the hardware. We do this by clamping the requested threshold to the + * valid range and, if necessary, moving the other threshold so that + * it's MIN_THRESH_DELTA away from this one. + */ +static ssize_t store_battery_stop_charge_thresh(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int thresh, other_thresh, ret; + int bat = attr_get_bat(attr); + + if (sscanf(buf, "%d", &thresh) != 1 || thresh < 1 || thresh > 100) + return -EINVAL; + + if (thresh < MIN_THRESH_STOP) /* clamp up to MIN_THRESH_STOP */ + thresh = MIN_THRESH_STOP; + + down(&smapi_mutex); + ret = get_thresh(bat, THRESH_START, &other_thresh); + if (ret != -EOPNOTSUPP) { /* other threshold exists? */ + if (ret) + goto out; + /* this threshold exists? */ + ret = get_real_thresh(bat, THRESH_STOP, NULL); + if (ret) + goto out; + if (other_thresh >= thresh-MIN_THRESH_DELTA) { + /* move other thresh to be below this one */ + ret = set_thresh(bat, THRESH_START, + thresh-MIN_THRESH_DELTA); + if (ret) + goto out; + } + } + ret = set_thresh(bat, THRESH_STOP, thresh); +out: + up(&smapi_mutex); + return count; +} + +static ssize_t show_battery_inhibit_charge_minutes(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int minutes; + int bat = attr_get_bat(attr); + int ret = get_inhibit_charge_minutes(bat, &minutes); + if (ret) + return ret; + return sprintf(buf, "%d\n", minutes); /* units: minutes */ +} + +static ssize_t store_battery_inhibit_charge_minutes(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + int minutes; + int bat = attr_get_bat(attr); + if (sscanf(buf, "%d", &minutes) != 1 || minutes < 0) { + TPRINTK(KERN_ERR, "inhibit_charge_minutes: " + "must be a non-negative integer"); + return -EINVAL; + } + ret = set_inhibit_charge_minutes(bat, minutes); + if (ret) + return ret; + return count; +} + +static ssize_t show_battery_force_discharge(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int enabled; + int bat = attr_get_bat(attr); + int ret = get_force_discharge(bat, &enabled); + if (ret) + return ret; + return sprintf(buf, "%d\n", enabled); /* type: boolean */ +} + +static ssize_t store_battery_force_discharge(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + int enabled; + int bat = attr_get_bat(attr); + if (sscanf(buf, "%d", &enabled) != 1 || enabled < 0 || enabled > 1) + return -EINVAL; + ret = set_force_discharge(bat, enabled); + if (ret) + return ret; + return count; +} + +static ssize_t show_battery_installed( + struct device *dev, struct device_attribute *attr, char *buf) +{ + int bat = attr_get_bat(attr); + int ret = power_device_present(bat); + if (ret < 0) + return ret; + return sprintf(buf, "%d\n", ret); /* type: boolean */ +} + +static ssize_t show_battery_state( + struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 row[TP_CONTROLLER_ROW_LEN]; + const char *txt; + int ret; + int bat = attr_get_bat(attr); + if (bat_has_status(bat) != 1) + return sprintf(buf, "none\n"); + ret = read_tp_ec_row(1, bat, 0, row); + if (ret) + return ret; + switch (row[1] & 0xf0) { + case 0xc0: txt = "idle"; break; + case 0xd0: txt = "discharging"; break; + case 0xe0: txt = "charging"; break; + default: return sprintf(buf, "unknown (0x%x)\n", row[1]); + } + return sprintf(buf, "%s\n", txt); /* type: string from fixed set */ +} + +static ssize_t show_battery_manufacturer( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* type: string. SBS spec v1.1 p34: ManufacturerName() */ + return show_tp_ec_bat_str(4, 2, TP_CONTROLLER_ROW_LEN-2, attr, buf); +} + +static ssize_t show_battery_model( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* type: string. SBS spec v1.1 p34: DeviceName() */ + return show_tp_ec_bat_str(5, 2, TP_CONTROLLER_ROW_LEN-2, attr, buf); +} + +static ssize_t show_battery_barcoding( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* type: string */ + return show_tp_ec_bat_str(7, 2, TP_CONTROLLER_ROW_LEN-2, attr, buf); +} + +static ssize_t show_battery_chemistry( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* type: string. SBS spec v1.1 p34-35: DeviceChemistry() */ + return show_tp_ec_bat_str(6, 2, 5, attr, buf); +} + +static ssize_t show_battery_voltage( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: mV. SBS spec v1.1 p24: Voltage() */ + return show_tp_ec_bat_u16(1, 6, 1, NULL, attr, buf); +} + +static ssize_t show_battery_design_voltage( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: mV. SBS spec v1.1 p32: DesignVoltage() */ + return show_tp_ec_bat_u16(3, 4, 1, NULL, attr, buf); +} + +static ssize_t show_battery_charging_max_voltage( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: mV. SBS spec v1.1 p37,39: ChargingVoltage() */ + return show_tp_ec_bat_u16(9, 8, 1, NULL, attr, buf); +} + +static ssize_t show_battery_group0_voltage( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: mV */ + return show_tp_ec_bat_u16(0xA, 12, 1, NULL, attr, buf); +} + +static ssize_t show_battery_group1_voltage( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: mV */ + return show_tp_ec_bat_u16(0xA, 10, 1, NULL, attr, buf); +} + +static ssize_t show_battery_group2_voltage( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: mV */ + return show_tp_ec_bat_u16(0xA, 8, 1, NULL, attr, buf); +} + +static ssize_t show_battery_group3_voltage( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: mV */ + return show_tp_ec_bat_u16(0xA, 6, 1, NULL, attr, buf); +} + +static ssize_t show_battery_current_now( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: mA. SBS spec v1.1 p24: Current() */ + return show_tp_ec_bat_s16(1, 8, 1, 0, attr, buf); +} + +static ssize_t show_battery_current_avg( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: mA. SBS spec v1.1 p24: AverageCurrent() */ + return show_tp_ec_bat_s16(1, 10, 1, 0, attr, buf); +} + +static ssize_t show_battery_charging_max_current( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: mA. SBS spec v1.1 p36,38: ChargingCurrent() */ + return show_tp_ec_bat_s16(9, 6, 1, 0, attr, buf); +} + +static ssize_t show_battery_power_now( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: mW. SBS spec v1.1: Voltage()*Current() */ + return show_tp_ec_bat_power(1, 6, 8, attr, buf); +} + +static ssize_t show_battery_power_avg( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: mW. SBS spec v1.1: Voltage()*AverageCurrent() */ + return show_tp_ec_bat_power(1, 6, 10, attr, buf); +} + +static ssize_t show_battery_remaining_percent( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: percent. SBS spec v1.1 p25: RelativeStateOfCharge() */ + return show_tp_ec_bat_u16(1, 12, 1, NULL, attr, buf); +} + +static ssize_t show_battery_remaining_charging_time( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: minutes. SBS spec v1.1 p27: AverageTimeToFull() */ + return show_tp_ec_bat_u16(2, 8, 1, "not_charging", attr, buf); +} + +static ssize_t show_battery_remaining_running_time( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: minutes. SBS spec v1.1 p27: RunTimeToEmpty() */ + return show_tp_ec_bat_u16(2, 6, 1, "not_discharging", attr, buf); +} + +static ssize_t show_battery_remaining_running_time_now( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: minutes. SBS spec v1.1 p27: RunTimeToEmpty() */ + return show_tp_ec_bat_u16(2, 4, 1, "not_discharging", attr, buf); +} + +static ssize_t show_battery_remaining_capacity( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: mWh. SBS spec v1.1 p26. */ + return show_tp_ec_bat_u16(1, 14, 10, "", attr, buf); +} + +static ssize_t show_battery_last_full_capacity( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: mWh. SBS spec v1.1 p26: FullChargeCapacity() */ + return show_tp_ec_bat_u16(2, 2, 10, "", attr, buf); +} + +static ssize_t show_battery_design_capacity( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: mWh. SBS spec v1.1 p32: DesignCapacity() */ + return show_tp_ec_bat_u16(3, 2, 10, "", attr, buf); +} + +static ssize_t show_battery_cycle_count( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: ordinal. SBS spec v1.1 p32: CycleCount() */ + return show_tp_ec_bat_u16(2, 12, 1, "", attr, buf); +} + +static ssize_t show_battery_temperature( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* units: millicelsius. SBS spec v1.1: Temperature()*10 */ + return show_tp_ec_bat_s16(1, 4, 100, -273100, attr, buf); +} + +static ssize_t show_battery_serial( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* type: int. SBS spec v1.1 p34: SerialNumber() */ + return show_tp_ec_bat_u16(3, 10, 1, "", attr, buf); +} + +static ssize_t show_battery_manufacture_date( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* type: YYYY-MM-DD. SBS spec v1.1 p34: ManufactureDate() */ + return show_tp_ec_bat_date(3, 8, attr, buf); +} + +static ssize_t show_battery_first_use_date( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* type: YYYY-MM-DD */ + return show_tp_ec_bat_date(8, 2, attr, buf); +} + +/** + * show_battery_dump - show the battery's dump attribute + * The dump attribute gives a hex dump of all EC readouts related to a + * battery. Some of the enumerated values don't really exist (i.e., the + * EC function just leaves them untouched); we use a kludge to detect and + * denote these. + */ +#define MIN_DUMP_ARG0 0x00 +#define MAX_DUMP_ARG0 0x0a /* 0x0b is useful too but hangs old EC firmware */ +static ssize_t show_battery_dump( + struct device *dev, struct device_attribute *attr, char *buf) +{ + int i; + char *p = buf; + int bat = attr_get_bat(attr); + u8 arg0; /* first argument to EC */ + u8 rowa[TP_CONTROLLER_ROW_LEN], + rowb[TP_CONTROLLER_ROW_LEN]; + const u8 junka = 0xAA, + junkb = 0x55; /* junk values for testing changes */ + int ret; + + for (arg0 = MIN_DUMP_ARG0; arg0 <= MAX_DUMP_ARG0; ++arg0) { + if ((p-buf) > PAGE_SIZE-TP_CONTROLLER_ROW_LEN*5) + return -ENOMEM; /* don't overflow sysfs buf */ + /* Read raw twice with different junk values, + * to detect unused output bytes which are left unchaged: */ + ret = read_tp_ec_row(arg0, bat, junka, rowa); + if (ret) + return ret; + ret = read_tp_ec_row(arg0, bat, junkb, rowb); + if (ret) + return ret; + for (i = 0; i < TP_CONTROLLER_ROW_LEN; i++) { + if (rowa[i] == junka && rowb[i] == junkb) + p += sprintf(p, "-- "); /* unused by EC */ + else + p += sprintf(p, "%02x ", rowa[i]); + } + p += sprintf(p, "\n"); + } + return p-buf; +} + + +/********************************************************************* + * sysfs attribute I/O, other than batteries + */ + +static ssize_t show_ac_connected( + struct device *dev, struct device_attribute *attr, char *buf) +{ + int ret = power_device_present(0xFF); + if (ret < 0) + return ret; + return sprintf(buf, "%d\n", ret); /* type: boolean */ +} + +/********************************************************************* + * The the "smapi_request" sysfs attribute executes a raw SMAPI call. + * You write to make a request and read to get the result. The state + * is saved globally rather than per fd (sysfs limitation), so + * simultaenous requests may get each other's results! So this is for + * development and debugging only. + */ +#define MAX_SMAPI_ATTR_ANSWER_LEN 128 +static char smapi_attr_answer[MAX_SMAPI_ATTR_ANSWER_LEN] = ""; + +static ssize_t show_smapi_request(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = snprintf(buf, PAGE_SIZE, "%s", smapi_attr_answer); + smapi_attr_answer[0] = '\0'; + return ret; +} + +static ssize_t store_smapi_request(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int inEBX, inECX, inEDI, inESI; + u32 outEBX, outECX, outEDX, outEDI, outESI; + const char *msg; + int ret; + if (sscanf(buf, "%x %x %x %x", &inEBX, &inECX, &inEDI, &inESI) != 4) { + smapi_attr_answer[0] = '\0'; + return -EINVAL; + } + ret = smapi_request( + inEBX, inECX, inEDI, inESI, + &outEBX, &outECX, &outEDX, &outEDI, &outESI, &msg); + snprintf(smapi_attr_answer, MAX_SMAPI_ATTR_ANSWER_LEN, + "%x %x %x %x %x %d '%s'\n", + (unsigned int)outEBX, (unsigned int)outECX, + (unsigned int)outEDX, (unsigned int)outEDI, + (unsigned int)outESI, ret, msg); + if (ret) + return ret; + else + return count; +} + +/********************************************************************* + * Power management: the embedded controller forgets the battery + * thresholds when the system is suspended to disk and unplugged from + * AC and battery, so we restore it upon resume. + */ + +static int saved_threshs[4] = {-1, -1, -1, -1}; /* -1 = don't know */ + +static int tp_suspend(struct platform_device *dev, pm_message_t state) +{ + if (get_real_thresh(0, THRESH_STOP , &saved_threshs[0])) + saved_threshs[0] = -1; + if (get_real_thresh(0, THRESH_START, &saved_threshs[1])) + saved_threshs[1] = -1; + if (get_real_thresh(1, THRESH_STOP , &saved_threshs[2])) + saved_threshs[2] = -1; + if (get_real_thresh(1, THRESH_START, &saved_threshs[3])) + saved_threshs[3] = -1; + DPRINTK("suspend saved: %d %d %d %d", saved_threshs[0], + saved_threshs[1], saved_threshs[2], saved_threshs[3]); + return 0; +} + +static int tp_resume(struct platform_device *dev) +{ + DPRINTK("resume restoring: %d %d %d %d", saved_threshs[0], + saved_threshs[1], saved_threshs[2], saved_threshs[3]); + if (saved_threshs[0] >= 0) + set_real_thresh(0, THRESH_STOP , saved_threshs[0]); + if (saved_threshs[1] >= 0) + set_real_thresh(0, THRESH_START, saved_threshs[1]); + if (saved_threshs[2] >= 0) + set_real_thresh(1, THRESH_STOP , saved_threshs[2]); + if (saved_threshs[3] >= 0) + set_real_thresh(1, THRESH_START, saved_threshs[3]); + return 0; +} + + +/********************************************************************* + * Driver model + */ + +static struct platform_driver tp_driver = { + .suspend = tp_suspend, + .resume = tp_resume, + .driver = { + .name = "smapi", + .owner = THIS_MODULE + }, +}; + + +/********************************************************************* + * Sysfs device model + */ + +/* Attributes in /sys/devices/platform/smapi/ */ + +static DEVICE_ATTR(ac_connected, 0444, show_ac_connected, NULL); +static DEVICE_ATTR(smapi_request, 0600, show_smapi_request, + store_smapi_request); + +static struct attribute *tp_root_attributes[] = { + &dev_attr_ac_connected.attr, + &dev_attr_smapi_request.attr, + NULL +}; +static struct attribute_group tp_root_attribute_group = { + .attrs = tp_root_attributes +}; + +/* Attributes under /sys/devices/platform/smapi/BAT{0,1}/ : + * Every attribute needs to be defined (i.e., statically allocated) for + * each battery, and then referenced in the attribute list of each battery. + * We use preprocessor voodoo to avoid duplicating the list of attributes 4 + * times. The preprocessor output is just normal sysfs attributes code. + */ + +/** + * FOREACH_BAT_ATTR - invoke the given macros on all our battery attributes + * @_BAT: battery number (0 or 1) + * @_ATTR_RW: macro to invoke for each read/write attribute + * @_ATTR_R: macro to invoke for each read-only attribute + */ +#define FOREACH_BAT_ATTR(_BAT, _ATTR_RW, _ATTR_R) \ + _ATTR_RW(_BAT, start_charge_thresh) \ + _ATTR_RW(_BAT, stop_charge_thresh) \ + _ATTR_RW(_BAT, inhibit_charge_minutes) \ + _ATTR_RW(_BAT, force_discharge) \ + _ATTR_R(_BAT, installed) \ + _ATTR_R(_BAT, state) \ + _ATTR_R(_BAT, manufacturer) \ + _ATTR_R(_BAT, model) \ + _ATTR_R(_BAT, barcoding) \ + _ATTR_R(_BAT, chemistry) \ + _ATTR_R(_BAT, voltage) \ + _ATTR_R(_BAT, group0_voltage) \ + _ATTR_R(_BAT, group1_voltage) \ + _ATTR_R(_BAT, group2_voltage) \ + _ATTR_R(_BAT, group3_voltage) \ + _ATTR_R(_BAT, current_now) \ + _ATTR_R(_BAT, current_avg) \ + _ATTR_R(_BAT, charging_max_current) \ + _ATTR_R(_BAT, power_now) \ + _ATTR_R(_BAT, power_avg) \ + _ATTR_R(_BAT, remaining_percent) \ + _ATTR_R(_BAT, remaining_charging_time) \ + _ATTR_R(_BAT, remaining_running_time) \ + _ATTR_R(_BAT, remaining_running_time_now) \ + _ATTR_R(_BAT, remaining_capacity) \ + _ATTR_R(_BAT, last_full_capacity) \ + _ATTR_R(_BAT, design_voltage) \ + _ATTR_R(_BAT, charging_max_voltage) \ + _ATTR_R(_BAT, design_capacity) \ + _ATTR_R(_BAT, cycle_count) \ + _ATTR_R(_BAT, temperature) \ + _ATTR_R(_BAT, serial) \ + _ATTR_R(_BAT, manufacture_date) \ + _ATTR_R(_BAT, first_use_date) \ + _ATTR_R(_BAT, dump) + +/* Define several macros we will feed into FOREACH_BAT_ATTR: */ + +#define DEFINE_BAT_ATTR_RW(_BAT,_NAME) \ + static struct bat_device_attribute dev_attr_##_NAME##_##_BAT = { \ + .dev_attr = __ATTR(_NAME, 0644, show_battery_##_NAME, \ + store_battery_##_NAME), \ + .bat = _BAT \ + }; + +#define DEFINE_BAT_ATTR_R(_BAT,_NAME) \ + static struct bat_device_attribute dev_attr_##_NAME##_##_BAT = { \ + .dev_attr = __ATTR(_NAME, 0644, show_battery_##_NAME, 0), \ + .bat = _BAT \ + }; + +#define REF_BAT_ATTR(_BAT,_NAME) \ + &dev_attr_##_NAME##_##_BAT.dev_attr.attr, + +/* This provide all attributes for one battery: */ + +#define PROVIDE_BAT_ATTRS(_BAT) \ + FOREACH_BAT_ATTR(_BAT, DEFINE_BAT_ATTR_RW, DEFINE_BAT_ATTR_R) \ + static struct attribute *tp_bat##_BAT##_attributes[] = { \ + FOREACH_BAT_ATTR(_BAT, REF_BAT_ATTR, REF_BAT_ATTR) \ + NULL \ + }; \ + static struct attribute_group tp_bat##_BAT##_attribute_group = { \ + .name = "BAT" #_BAT, \ + .attrs = tp_bat##_BAT##_attributes \ + }; + +/* Finally genereate the attributes: */ + +PROVIDE_BAT_ATTRS(0) +PROVIDE_BAT_ATTRS(1) + +/* List of attribute groups */ + +static struct attribute_group *attr_groups[] = { + &tp_root_attribute_group, + &tp_bat0_attribute_group, + &tp_bat1_attribute_group, + NULL +}; + + +/********************************************************************* + * Init and cleanup + */ + +static struct attribute_group **next_attr_group; /* next to register */ + +static int __init tp_init(void) +{ + int ret; + printk(KERN_INFO "tp_smapi " TP_VERSION " loading...\n"); + + ret = find_smapi_port(); + if (ret < 0) + goto err; + else + smapi_port = ret; + + if (!request_region(smapi_port, 1, "smapi")) { + printk(KERN_ERR "tp_smapi cannot claim port 0x%x\n", + smapi_port); + ret = -ENXIO; + goto err; + } + + if (!request_region(SMAPI_PORT2, 1, "smapi")) { + printk(KERN_ERR "tp_smapi cannot claim port 0x%x\n", + SMAPI_PORT2); + ret = -ENXIO; + goto err_port1; + } + + ret = platform_driver_register(&tp_driver); + if (ret) + goto err_port2; + + pdev = platform_device_alloc("smapi", -1); + if (!pdev) { + ret = -ENOMEM; + goto err_driver; + } + + ret = platform_device_add(pdev); + if (ret) + goto err_device_free; + + for (next_attr_group = attr_groups; *next_attr_group; + ++next_attr_group) { + ret = sysfs_create_group(&pdev->dev.kobj, *next_attr_group); + if (ret) + goto err_attr; + } + + printk(KERN_INFO "tp_smapi successfully loaded (smapi_port=0x%x).\n", + smapi_port); + return 0; + +err_attr: + while (--next_attr_group >= attr_groups) + sysfs_remove_group(&pdev->dev.kobj, *next_attr_group); + platform_device_unregister(pdev); +err_device_free: + platform_device_put(pdev); +err_driver: + platform_driver_unregister(&tp_driver); +err_port2: + release_region(SMAPI_PORT2, 1); +err_port1: + release_region(smapi_port, 1); +err: + printk(KERN_ERR "tp_smapi init failed (ret=%d)!\n", ret); + return ret; +} + +static void __exit tp_exit(void) +{ + while (next_attr_group && --next_attr_group >= attr_groups) + sysfs_remove_group(&pdev->dev.kobj, *next_attr_group); + platform_device_unregister(pdev); + platform_driver_unregister(&tp_driver); + release_region(SMAPI_PORT2, 1); + if (smapi_port) + release_region(smapi_port, 1); + + printk(KERN_INFO "tp_smapi unloaded.\n"); +} + +module_init(tp_init); +module_exit(tp_exit); --- linux-2.6.27.orig/ubuntu/misc/fsam7400.c +++ linux-2.6.27/ubuntu/misc/fsam7400.c @@ -0,0 +1,373 @@ +/******************************************************************************* + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Author: + Marcel Naziri + + Based on: + pbe5.c by Pedro Ramalhais + + Many thanks to: + Pedro Ramalhais for spending several nights with me on IRC disassembling + the structure of the windows driver files... :) + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "fsam7400" +#define DRV_VERSION "0.4.0" +#define DRV_DESCRIPTION "SW RF kill switch for Fujitsu Siemens Amilo M 7400" +#define DRV_COPYRIGHT "Copyright(c) 2004 zwobbl ;)" +#define DRV_AUTHOR "Marcel Naziri" +#define DRV_LICENSE "GPL" + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_AUTHOR(DRV_AUTHOR); +MODULE_LICENSE(DRV_LICENSE); + +#define RADIO_NONE 0xFFFFFFFF +#define RADIO_OFF 0x00000000 +#define RADIO_ON 0x00000010 + +static int radio = RADIO_NONE; +module_param(radio, uint, 0400); +MODULE_PARM_DESC(radio, "desired radio state when loading module"); + +static int autooff = 1; +module_param(autooff, uint, 0400); +MODULE_PARM_DESC(autooff, "turns radio off when unloading module " + "(default)"); + +static int uid = 0; +module_param(uid, uint, 0400); +MODULE_PARM_DESC(uid, "user ID for proc entry"); + +static int gid = 0; +module_param(gid, uint, 0400); +MODULE_PARM_DESC(gid, "group ID for proc entry"); + +/* some more or less useful macros */ +#ifdef CONFIG_IPW2100_DEBUG +#define DEBUG_OUT0(a) printk(KERN_INFO DRV_NAME ": " a) +#define DEBUG_OUT1(a,b) printk(KERN_INFO DRV_NAME ": " a,b) +#define DEBUG_OUT2(a,b,c) printk(KERN_INFO DRV_NAME ": " a,b,c) +#define DEBUG_OUT3(a,b,c,d) printk(KERN_INFO DRV_NAME ": " a,b,c,d) +#else +#define DEBUG_OUT0(a) +#define DEBUG_OUT1(a,b) +#define DEBUG_OUT2(a,b,c) +#define DEBUG_OUT3(a,b,c,d) +#endif + +#define ONOFF(x) (x) ? "ON" : "OFF" +#define RADIO_ONOFF(x) (x) == RADIO_ON ? "ON" : "OFF" +#define TOUL(x) (unsigned long) (x) + +/* + * NOTE: These values were obtained from disassembling the wbutton.sys driver + * installed in the Fujitsu Siemens Amilo M 7400 laptop. The names were guessed, + * so don't rely on them. + */ + +/*** hardware dependant stuff ***/ + +#define BIOS_CODE_ADDR 0x000F0000 +#define BIOS_CODE_ALT_MASK 0xFFFFC000 + +#define BIOS_CODE_MAPSIZE 0x010000 +#define BIOS_CODE_ALT_MAPSIZE 0x004000 + +#define BIOS_MAGIC_COMMAND 0x9610 +#define BIOS_MAGIC_OFF 0x0035 +#define BIOS_MAGIC_ON 0x0135 +#define BIOS_MAGIC_CHECK 0x0235 + +#define PTR_POSITION 5 +#define ALLIGNED_STEP 0x10 + +#define BIOS_SIGN_SIZE 4 +static const char bios_sign[] = { + 0x42, 0x21, 0x55, 0x30 +}; + +#define WLAN_DISABLED_IN_BIOS 0x01 +#define WLAN_ENABLED_IN_BIOS 0x03 + +static unsigned long bios_code = 0; + +static int fsam_bios_routine(int eax, int ebx) +{ + __asm__ __volatile__( + "call *%3 \t\n" + : "=a"(eax) + : "a"(eax), "b"(ebx), "c"(bios_code) + ); + return (eax & 0xFF); +} + +static int fsam_call_bios(int value) +{ + if (bios_code) { + int command = BIOS_MAGIC_COMMAND; + + DEBUG_OUT2("bios routine gets parameter eax=%X and ebx=%X\n", + command, value); + + value = fsam_bios_routine(command, value); + + DEBUG_OUT1("bios routine results %X\n", value); + return value; + } + return ~0; +} + +/* pointer to mapped memory*/ +static void *mem_code = NULL; + +static inline void fsam_unmap_memory(void) +{ + bios_code = 0; + if (mem_code) { + iounmap(mem_code); + } +} + +static inline int fsam_map_memory(void) +{ + const unsigned long max_offset = BIOS_CODE_MAPSIZE - BIOS_SIGN_SIZE - PTR_POSITION; + unsigned long offset; + unsigned int addr; + + mem_code = ioremap(BIOS_CODE_ADDR, BIOS_CODE_MAPSIZE); + if (!mem_code) + goto fail; + + DEBUG_OUT3("physical memory %x-%x mapped to virtual address %p\n", + BIOS_CODE_ADDR, BIOS_CODE_ADDR+BIOS_CODE_MAPSIZE, mem_code); + + for ( offset = 0; offset < max_offset; offset += ALLIGNED_STEP ) + if (check_signature(mem_code + offset, bios_sign, BIOS_SIGN_SIZE)) + break; + + if (offset >= max_offset) + goto fail; + + DEBUG_OUT1("bios signature found at offset %lx\n", offset); + + addr = readl(mem_code + offset + PTR_POSITION); + + if (addr < BIOS_CODE_ADDR) + { + DEBUG_OUT0("bios routine out of memory range, " + "doing some new memory mapping...\n"); + iounmap(mem_code); + mem_code = NULL; + + addr &= BIOS_CODE_ALT_MASK; + + mem_code = ioremap(addr, BIOS_CODE_ALT_MAPSIZE); + if (!mem_code) + goto fail; + + DEBUG_OUT3("physical memory %x-%x mapped to virtual address %p\n", + addr, addr+BIOS_CODE_ALT_MAPSIZE, mem_code); + + addr &= 0x3FFF; + } + else + addr &= 0xFFFF; + + bios_code = addr + TOUL(mem_code); + DEBUG_OUT1("supposed address of bios routine is %lx\n", bios_code); + + return 1; + + fail: + fsam_unmap_memory(); + return 0; +} + +/*** interface stuff ***/ + +static void rfkill_set_radio(int value) +{ + radio = value == RADIO_ON ? fsam_call_bios(BIOS_MAGIC_ON) : + fsam_call_bios(BIOS_MAGIC_OFF); +} + +static inline int rfkill_get_radio(void) +{ + return radio; +} + +static inline int rfkill_supported(void) +{ + return bios_code != 0; +} + +static inline void rfkill_initialize(void) { + fsam_map_memory(); + + if (rfkill_supported()) { + radio = radio != RADIO_NONE + ? ( radio ? RADIO_ON : RADIO_OFF ) /*module parameter*/ + : ( fsam_call_bios(BIOS_MAGIC_CHECK) == WLAN_ENABLED_IN_BIOS + ? RADIO_ON : RADIO_OFF ); + } +} + +static inline void rfkill_uninitialize(void) { + fsam_unmap_memory(); +} + +/*** proc stuff ***/ + +static inline int common_proc_set_radio(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned long len = 4; + char newstate[len]; + + len = count < len ? count : len; + + if ( copy_from_user(newstate, buffer, len) != 0 ) + return -EFAULT; + + if ( (*newstate == '1' || *newstate == '0') && + (count == 1 || isspace(newstate[1])) ) + rfkill_set_radio(*newstate == '1' ? RADIO_ON : RADIO_OFF); + else + if ( !strncmp(newstate, "on", 2) && + (count == 2 || isspace(newstate[2])) ) + rfkill_set_radio(RADIO_ON); + else + if ( !strncmp(newstate, "off", 3) && + (count == 3 || isspace(newstate[3])) ) + rfkill_set_radio(RADIO_OFF); + + return count; +} + +static inline int common_proc_get_radio(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + int len = snprintf(page, count, DRV_DESCRIPTION ", v" DRV_VERSION "\n" + " auto-off is %s\n", + ONOFF(autooff)); + len += snprintf(page+len, count-len, " radio state is %s\n", + RADIO_ONOFF(rfkill_get_radio())); + *eof = 1; + + return len; +} + +#define PROC_DIR "driver/wireless" +#define PROC_RADIO "radio" + +static struct proc_dir_entry *dir_base = NULL; + +static inline void common_proc_cleanup(void) +{ + if (dir_base) { + remove_proc_entry(PROC_RADIO, dir_base); + remove_proc_entry(PROC_DIR, NULL); + dir_base = NULL; + } +} + +static inline int common_proc_init(void) +{ + struct proc_dir_entry *ent; + int err = 0; + + dir_base = proc_mkdir(PROC_DIR, NULL); + if (dir_base == NULL) { + printk(KERN_ERR DRV_NAME ": Unable to initialize /proc/" PROC_DIR "\n"); + err = -ENOMEM; + goto fail; + } + + ent = create_proc_entry(PROC_RADIO, + S_IFREG | S_IRUGO | S_IWUSR | S_IWGRP, + dir_base); + ent->uid = uid; + ent->gid = gid; + if (ent) { + ent->read_proc = common_proc_get_radio; + ent->write_proc = common_proc_set_radio; + } else { + printk(KERN_ERR DRV_NAME ": Unable to initialize /proc/" + PROC_DIR "/" PROC_RADIO "\n"); + err = -ENOMEM; + goto fail; + } + return 0; + + fail: + common_proc_cleanup(); + return err; +} + +/*** module stuff ***/ + +static int __init common_init(void) +{ + printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", v" DRV_VERSION "\n"); + printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); + + rfkill_initialize(); + + if (rfkill_supported()) { + common_proc_init(); + if (radio != RADIO_NONE) + rfkill_set_radio(radio); + } else + printk(KERN_INFO DRV_NAME ": no supported wireless hardware found\n"); + + return 0; +} + +static void __exit common_exit(void) +{ + if (rfkill_supported() && autooff) + rfkill_set_radio(RADIO_OFF); + + common_proc_cleanup(); + rfkill_uninitialize(); + + printk(KERN_INFO DRV_NAME ": module removed successfully\n"); +} + +module_init(common_init); +module_exit(common_exit); + +/* + 1 2 3 4 5 6 7 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +*/ --- linux-2.6.27.orig/ubuntu/misc/Kconfig +++ linux-2.6.27/ubuntu/misc/Kconfig @@ -0,0 +1,36 @@ +config USB_APPLEIR + tristate "Apple USB Infrared Receiver" + default m + depends on USB + +config BLK_DEV_DM_BBR + tristate "Bad-block-relocation target for device-mapper" + default m + depends on BLK_DEV_DM + +config INPUT_ACERHK + tristate "Acer Travelmate laptop special key support" + default m + depends on X86_32 + +config FSAM7400 + tristate "SW RF kill switch for Fujitsu Siemens Amilo M 7400" + default m + select CHECK_SIGNATURE + +config LMPCM_USB + tristate "USB Logitech MediaPlay Cordless Mouse driver" + default m + depends on USB + +config TP_SMAPI + tristate "ThinkPad SMAPI Support" + default m + +config TP_SMAPI_EC + tristate "ThinkPad embedded controller LPC3 functions" + default m + +source "ubuntu/misc/media/Kconfig" + +source "ubuntu/misc/wireless/Kconfig" --- linux-2.6.27.orig/ubuntu/misc/acerhk.c +++ linux-2.6.27/ubuntu/misc/acerhk.c @@ -0,0 +1,3001 @@ +/********************************************************************* + * Filename: acerhk.c + * Version: 0.5 + * + * Copyright (C) 2002-2006, Olaf Tauber (olaf-tauber@versanet.de) + * + * Description: kernel driver for Acer Travelmate and similar + * laptops special keys + * Author: Olaf Tauber + * Created at: Mon Apr 29 22:16:42 2002 + * Modified at: Tue Feb 28 21:38:41 2006 + * Modified by: Olaf Tauber + * Modified at: Thu Nov 24 13:03:01 2005 + * Modified by: Antonio Cuni + * Modified at: Wed Oct 27 19:47:11 CEST 2004 + * Modified by: Joachim Fenkes + * + * This program is free software; you can redistribute + * it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, + * Suite 330, Boston, MA 02111-1307 USA + * + * + */ + +/* This driver is heavily dependent on the architecture, don't let anyone + * without an X86 machine use it. I doubt that there are laptops out there + * which would need this driver and are not X86, so it doesn't matter anyway. + */ +#ifdef CONFIG_X86 + +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +#define KERNEL26 +#include +#else +#include +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) +#define STATIC_INPUT_DEV +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acerhk.h" + +/* #define ACERDEBUG */ +/* #define DUMMYHW */ + +#define ACERHK_VERSION "0.5.34" +#define MODULE_NAME "acerhk" + +/* maximum number of polling loops, adjust it if needed to values between + * 1 and 32 + */ +#define MAX_POLLING_LOOPS 16U + +/* maximum length for model string */ +#define ACERHK_MODEL_STRLEN 16 +/* size of mapped areas */ +#define AREA_SIZE 0xffff +/* needed for colussi algorithm */ +#define XSIZE 20 + +/* Module parameters */ +static int poll=1; +static int autowlan; +static int usedritek=1; +static int wlan_state=-1; +static int bluetooth_state=-1; +static int verbose; +static unsigned int force_series; +#ifdef KERNEL26 +module_param(poll, int, 0444); +module_param(autowlan, int, 0444); +module_param(usedritek, int, 0444); +module_param(verbose, int, 0444); +module_param(wlan_state, int, 0444); +module_param(bluetooth_state, int, 0444); +module_param(force_series, uint, 0444); +#else +MODULE_PARM(poll, "i"); +MODULE_PARM(autowlan, "i"); +MODULE_PARM(wlan_state, "i"); +MODULE_PARM(bluetooth_state, "i"); +MODULE_PARM(usedritek, "i"); +MODULE_PARM(verbose, "i"); +MODULE_PARM(force_series, "i"); +#endif +MODULE_PARM_DESC(poll, "start polling timer"); +MODULE_PARM_DESC(autowlan, "automatic switching of wlan hardware"); +MODULE_PARM_DESC(wlan_state, "(assumed) initial state of WLAN LED/hardware"); +MODULE_PARM_DESC(bluetooth_state, "(assumed) initial state of Bluetooth LED/hardware"); +MODULE_PARM_DESC(usedritek, "enable dritek keyboard extension"); +MODULE_PARM_DESC(verbose, "output additional information"); +MODULE_PARM_DESC(force_series, "force laptop series, skip autodetection"); + +/* input device */ +static struct input_dev *acerhk_input_dev_ptr; +#ifdef STATIC_INPUT_DEV +static struct input_dev acerhk_input_dev; +#endif + +/* mapped IO area from 0xf0000 */ +static void *reg1; +/* mapped IO area from 0xe0000 */ +static void *reg2; +/* Pointer to mapped area at 0x400 on 520 series */ +static void *preg400; +/* location of IO routine in mapped area */ +static unsigned int bios_routine; +/* index of CMOS port to get key event */ +static unsigned int cmos_index; +/* function for bios call */ +static bios_call call_bios; +/* address of model string */ +static char *acerhk_model_addr; +/* copied string, maximum length 16 ('TravelMate xxx') */ +static char acerhk_model_string[ACERHK_MODEL_STRLEN]; +/* type of hardware access */ +static t_acer_type acerhk_type; +/* travelmate series */ +static unsigned int acerhk_series; +/* supported features for this model */ +static unsigned int acerhk_model_features; +/* map of acer key codes to acer key names */ +static unsigned char acerhk_key2name[0xff]; +/* map of acer key names to key events */ +static t_map_name2event acerhk_name2event; +/* timer for polling key presses */ +static struct timer_list acerhk_timer_poll; +/* polling active */ +static int acerhk_polling_state; +/* polling delay */ +static unsigned acerhk_polling_delay = HZ/5; +/* wlan hardware toggle */ +static int acerhk_wlan_state; +/* bluetooth hardware toggle */ +static int acerhk_bluetooth_state; + +/* bluetooth blinking state; added by Antonio Cuni + possible values: + -1: blinking disabled (default) + 0: blinking enabled, led currently off + 1: blinking enabled, led currently on +*/ +static int acerhk_blueled_blinking = -1; +/* delay between two changes of state, in jiffies */ +static unsigned acerhk_blueled_blinking_delay; +/* timer for blinking */ +static struct timer_list acerhk_timer_blinking; + +/* function prototypes */ +static void start_polling(void); +static void stop_polling(void); + +/* Added by Antonio Cuni */ +static void start_blinking(void); +static void stop_blinking(void); + +/* {{{ Experimental use of dritek keyboard extension */ + +#define EC_STATUS_REG 0x66 /* Status register of EC (R) */ +#define EC_CNTL_REG 0x66 /* Controller command register of EC (W) */ +#define EC_DATA_REG 0x62 /* EC data register (R/W) */ + +#ifdef KERNEL26 + +#include + +#define KBD_STATUS_REG 0x64 /* Status register (R) */ +#define KBD_CNTL_REG 0x64 /* Controller command register (W) */ +#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ + +#else + +#ifndef KEY_MEDIA +#define KEY_MEDIA 226 +#endif + +#define preempt_disable() do { } while (0) +#define preempt_enable_no_resched() do { } while (0) +#define preempt_enable() do { } while (0) +#define preempt_check_resched() do { } while (0) +#include + +#endif + +static inline int my_i8042_read_status(void) +{ + return inb(KBD_STATUS_REG); +} +static int my_i8042_wait_write(void) +{ + int i = 0; + while ((my_i8042_read_status() & 0x02) && (i < 10000)) { + udelay(50); + i++; + } + return -(i == 10000); +} +static void send_kbd_cmd(unsigned char cmd, unsigned char val) +{ + if (usedritek) { + preempt_disable(); + if (!my_i8042_wait_write()) + outb(cmd, KBD_CNTL_REG); + if (!my_i8042_wait_write()) + outb(val, KBD_DATA_REG); + preempt_enable_no_resched(); + } else { + printk(KERN_INFO"acerhk: request for accessing EC ignored\n" + KERN_INFO"acerhk: Use of dritek keyboard extension not enabled, use module\n" + KERN_INFO"acerhk: parameter usedritek=1 to do that (possibly dangerous)\n"); + } +} +#ifdef ACERDEBUG +static inline int my_i8042_read_ecstatus(void) +{ + return inb(EC_STATUS_REG); +} +static int my_i8042_wait_ecwrite(void) +{ + int i = 0; + while ((my_i8042_read_ecstatus() & 0x02) && (i < 10000)) { + udelay(50); + i++; + } + return -(i == 10000); +} +static void send_ec_cmd(unsigned char cmd, unsigned char val) +{ + if (usedritek) { + preempt_disable(); + if (!my_i8042_wait_ecwrite()) + outb(cmd, EC_CNTL_REG); + if (!my_i8042_wait_ecwrite()) + outb(val, EC_DATA_REG); + preempt_enable_no_resched(); + } else { + printk(KERN_INFO"acerhk: request for accessing EC ignored\n" + KERN_INFO"acerhk: Use of dritek keyboard extension not enabled, use module\n" + KERN_INFO"acerhk: parameter usedritek=1 to do that (possibly dangerous)\n"); + } +} +#endif +#ifdef ACERDEBUG +static void enable_mute_led_ec(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: enabling mute led via EC\n"); + send_kbd_cmd(0x59, 0x94); +} +static void disable_mute_led_ec(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: disabling mute led via EC\n"); + send_kbd_cmd(0x59, 0x95); +} +static void enable_dmm_function(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: enabling WLAN via EC variant 2\n"); + send_kbd_cmd(0x45, 0xd3); +} +#endif +static void enable_wlan_ec_1(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: enabling WLAN via EC variant 1\n"); + send_kbd_cmd(0xe7, 0x01); + acerhk_wlan_state = 1; +} +static void disable_wlan_ec_1(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: disabling WLAN via EC variant 1\n"); + send_kbd_cmd(0xe7, 0x00); + acerhk_wlan_state = 0; +} +static void enable_bluetooth_ec_1(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: enabling Bluetooth via EC variant 1\n"); + send_kbd_cmd(0xe7, 0x03); + acerhk_bluetooth_state = 1; +} +static void disable_bluetooth_ec_1(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: disabling Bluetooth via EC variant 1\n"); + send_kbd_cmd(0xe7, 0x02); + acerhk_bluetooth_state = 0; +} +static void enable_wlan_ec_2(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: enabling WLAN via EC variant 2\n"); + send_kbd_cmd(0x45, acerhk_bluetooth_state ? 0xa2 : 0xa0); + acerhk_wlan_state = 1; +} +static void disable_wlan_ec_2(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: disabling WLAN via EC variant 2\n"); + send_kbd_cmd(0x45, acerhk_bluetooth_state ? 0xa1 : 0xa3); + acerhk_wlan_state = 0; +} +static void enable_bluetooth_ec_2(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: enabling Bluetooth via EC variant 2\n"); + send_kbd_cmd(0x45, acerhk_wlan_state ? 0xa2 : 0xa1); + acerhk_bluetooth_state = 1; +} +static void disable_bluetooth_ec_2(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: disabling Bluetooth via EC variant 2\n"); + send_kbd_cmd(0x45, acerhk_wlan_state ? 0xa0 : 0xa3); + acerhk_bluetooth_state = 0; +} +#ifdef ACERDEBUG +static void enable_wireless_ec(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: enabling wireless hardware\n"); + if (usedritek) { + preempt_disable(); + if (!my_i8042_wait_ecwrite()) + outb(0x4d, EC_CNTL_REG); + if (!my_i8042_wait_ecwrite()) + outb(0xd2, EC_DATA_REG); + if (!my_i8042_wait_ecwrite()) + outb(0x01, EC_DATA_REG); + preempt_enable_no_resched(); + } + acerhk_wlan_state = 1; +} +static void disable_wireless_ec(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: disabling wireless hardware\n"); + if (usedritek) { + preempt_disable(); + if (!my_i8042_wait_ecwrite()) + outb(0x4d, EC_CNTL_REG); + if (!my_i8042_wait_ecwrite()) + outb(0xd2, EC_DATA_REG); + if (!my_i8042_wait_ecwrite()) + outb(0x00, EC_DATA_REG); + preempt_enable_no_resched(); + } + acerhk_wlan_state = 0; +} +#endif +static void enable_dritek_keyboard(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: enabling dritek keyboard extension\n"); + send_kbd_cmd(0x59, 0x90); +} +static void disable_dritek_keyboard(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: disabling dritek keyboard extension\n"); + send_kbd_cmd(0x59, 0x91); +} +static void enable_mail_led_ec_1(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: enabling mail led via EC variant 1\n"); + send_kbd_cmd(0xe8, 0x01); +} +static void disable_mail_led_ec_1(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: disabling mail led via EC variant 1\n"); + send_kbd_cmd(0xe8, 0x00); +} + +static void enable_mail_led_ec_2(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: enabling mail led via EC variant 2\n"); + send_kbd_cmd(0x59, 0x92); +} +static void disable_mail_led_ec_2(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: disabling mail led via EC variant 2\n"); + send_kbd_cmd(0x59, 0x93); +} +static void enable_mail_led_ec_3(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: enabling mail led via EC variant 3\n"); + if (usedritek) { + preempt_disable(); + if (!my_i8042_wait_write()) + outl(0x80008894, 0xCF8); + if (!my_i8042_wait_write()) + outw(0xC061, 0xCFC); + preempt_enable_no_resched(); + } +} +static void disable_mail_led_ec_3(void) +{ + if (verbose) + printk(KERN_INFO "acerhk: disabling mail led via EC variant 3\n"); + if (usedritek) { + preempt_disable(); + if (!my_i8042_wait_write()) + outl(0x80008894, 0xCF8); + if (!my_i8042_wait_write()) + outw(0xC060, 0xCFC); + preempt_enable_no_resched(); + } +} + +/* }}} */ + +/* {{{ string search functions */ + +/* This is the Colussi algorithm, the code is taken from + http://www-igm.univ-mlv.fr/~lecroq/string +*/ +int preColussi(char *x, int m, int *h, int *next, int *shift) +{ + int i, k, nd, q, r, s; + int hmax[XSIZE], kmin[XSIZE], nhd0[XSIZE], rmin[XSIZE]; + /* Computation of hmax */ + i = k = 1; + do { + while (x[i] == x[i - k]) + i++; + hmax[k] = i; + q = k + 1; + while (hmax[q - k] + k < i) { + hmax[q] = hmax[q - k] + k; + q++; + } + k = q; + if (k == i + 1) + i = k; + } while (k <= m); /* Computation of kmin */ + memset(kmin, 0, m*sizeof(int)); + r = 0; + for (i = m; i >= 1; --i) + if (hmax[i] < m) + kmin[hmax[i]] = i; /* Computation of rmin */ + for (i = m - 1; i >= 0; --i) { + if (hmax[i + 1] == m) + r = i + 1; + if (kmin[i] == 0) + rmin[i] = r; + else + rmin[i] = 0; + } /* Computation of h */ + s = -1; + r = m; + for (i = 0; i < m; ++i) + if (kmin[i] == 0) + h[--r] = i; + else + h[++s] = i; + nd = s; /* Computation of shift */ + for (i = 0; i <= nd; ++i) + shift[i] = kmin[h[i]]; + for (i = nd + 1; i < m; ++i) + shift[i] = rmin[h[i]]; + shift[m] = rmin[0]; /* Computation of nhd0 */ + s = 0; + for (i = 0; i < m; ++i) { + nhd0[i] = s; + if (kmin[i] > 0) + ++s; + } /* Computation of next */ + for (i = 0; i <= nd; ++i) + next[i] = nhd0[h[i] - kmin[h[i]]]; + for (i = nd + 1; i < m; ++i) + next[i] = nhd0[m - rmin[h[i]]]; + next[m] = nhd0[m - rmin[h[m - 1]]]; return(nd); +} + +int COLUSSI(char *x, int m, char *y, int n) { + int i, j, last, nd, + h[XSIZE], next[XSIZE], shift[XSIZE]; /* Processing */ + int match_pos; /* position of first match */ + nd = preColussi(x, m, h, next, shift); /* Searching */ + i = j = 0; + last = -1; + match_pos = -1; + while ( (match_pos == -1) + && (j <= n - m) ) { + while (i < m && last < j + h[i] && + x[h[i]] == y[j + h[i]]) + i++; + if (i >= m || last >= j + h[i]) { + /* Match found, bail out */ + match_pos = j; + i = m; + } + if (i > nd) + last = j + m - 1; + j += shift[i]; + i = next[i]; + } + return match_pos; +} + +/* }}} */ + +/* {{{ hardware access functions */ + +/* call_bios_ + * + * call request handler in mapped system rom + * + * the request is handed over via all 6 general purpose registers, results are + * taken from them and copied back to buf + */ +static asmlinkage void call_bios_6xx(struct register_buffer *buf) +{ + if (bios_routine) { + local_irq_disable(); + __asm__ __volatile__( + "movl %1,%%edx\n\t" + "pusha\n\t" + "movl %%edx,%%ebp\n\t" + "movl (%%ebp),%%eax\n\t" + "movl 4(%%ebp),%%ebx\n\t" + "movl 8(%%ebp),%%ecx\n\t" + "movl 12(%%ebp),%%edx\n\t" + "movl 16(%%ebp),%%edi\n\t" + "movl 20(%%ebp),%%esi\n\t" + "pushl %%ebp\n\t" + "call *%0\n\t" + "popl %%ebp\n\t" + "movl %%eax, (%%ebp)\n\t" + "movl %%ebx, 4(%%ebp)\n\t" + "movl %%ecx, 8(%%ebp)\n\t" + "movl %%edx, 12(%%ebp)\n\t" + "movl %%edi, 16(%%ebp)\n\t" + "movl %%esi, 20(%%ebp)\n\t" + "popa\n\t" + : + :"m" (bios_routine), "m" (buf) + :"%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi"//, "%ebp" + ); + local_irq_enable(); + } +} + +static asmlinkage void call_bios_52x(struct register_buffer *buf) +{ + if (bios_routine) { + local_irq_disable(); + __asm__ __volatile__( + "movl %2,%%edx\n\t" + "pusha\n\t" + "movl %%edx,%%ebp\n\t" + "movl (%%ebp),%%eax\n\t" + "movl 4(%%ebp),%%ebx\n\t" + "movl 8(%%ebp),%%ecx\n\t" + "movl 12(%%ebp),%%edx\n\t" + "movl 16(%%ebp),%%edi\n\t" + "movl 20(%%ebp),%%esi\n\t" + "pushl %%ebp\n\t" + "movl %1, %%ebp\n\t" + "call *%0\n\t" + "popl %%ebp\n\t" + "movl %%eax, (%%ebp)\n\t" + "movl %%ebx, 4(%%ebp)\n\t" + "movl %%ecx, 8(%%ebp)\n\t" + "movl %%edx, 12(%%ebp)\n\t" + "movl %%edi, 16(%%ebp)\n\t" + "movl %%esi, 20(%%ebp)\n\t" + "popa\n\t" + : + :"m" (bios_routine), "m" (preg400), "m" (buf) + :"%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi"//, "%ebp" + ); + local_irq_enable(); + } +} + +#define PRINT_BUFFER(x) \ + printk(KERN_INFO"acerhk: eax=0x%x ebx=0x%x ecx=0x%x edx=0x%x\n" \ + "acerhk: edi=0x%x esi=0x%x ebp=0x%x\n", \ + x.eax, x.ebx, x.ecx, x.edx, x.edi, x.esi, x.ebp); + +/* get_fnkey_event + * + * gets the first (oldest) key id from the queue of events + * + * return value: id of key + */ +static int get_fnkey_event(void) +{ + struct register_buffer regs; + regs.eax = 0x9610; + regs.ebx = 0x61C; + /* clear other registers, some models need this */ + regs.ecx = 0; + regs.edx = 0; + preempt_disable(); + call_bios(®s); + preempt_enable_no_resched(); + return regs.eax & 0xffff; +} + +/* get_thermal_event + * + * does what? + * + * return value: event ? + */ +static int get_thermal_event(void) +{ + struct register_buffer regs; + if (acerhk_model_features & TM_F_THERMAL) { + regs.eax = 0x9612; + regs.ebx = 0x12e; + preempt_disable(); + call_bios(®s); + preempt_enable_no_resched(); + if (verbose > 3) + printk(KERN_INFO"acerhk: thermal event = 0x%x\n", regs.eax); + } else { + regs.eax = 0x00; + if (verbose > 3) + printk(KERN_INFO"acerhk: thermal event not supported\n"); + } + return regs.eax & 0xffff; +} + +#ifdef ACERDEBUG +/* pbutton_fct + * + * does what? + * + * return value: ? + */ +static int pbutton_fct(void) +{ + struct register_buffer regs; + if (acerhk_model_features & TM_F_PBUTTON) { + regs.eax = 0x9612; + regs.ebx = 0x10b; + regs.ecx = 0x2; + preempt_disable(); + call_bios(®s); + preempt_enable_no_resched(); + if (verbose > 3) + printk(KERN_INFO"acerhk: pbutton = 0x%x\n", regs.eax); + } else { + if (verbose > 3) + printk(KERN_INFO"acerhk: pbutton function not supported\n"); + regs.eax = 0x00; + } + return regs.eax & 0xffff; +} +#endif + +/* wbutton_fct_1 + * + * turn on installed Bluetooth hardware together with the corresponding LED + * + * val: 0 turns off the LED + * 1 turns the LED to green/blue + * + * return value: ? + */ +static int wbutton_fct_1(int val) +{ + struct register_buffer regs; + if (acerhk_model_features & TM_F_WBUTTON) { + acerhk_bluetooth_state = val; + regs.eax = 0x9610; + regs.ebx = ((val & 0xff) << 8) | 0x34; + preempt_disable(); + call_bios(®s); + preempt_enable_no_resched(); + if (verbose > 3) + printk(KERN_INFO"acerhk: wbutton1 = 0x%x\n", regs.eax); + } else { + if (verbose > 3) + printk(KERN_INFO"acerhk: wbutton function 1 not supported\n"); + regs.eax = 0x00; + } + return regs.eax & 0xffff; +} + +/* wbutton_fct_2 + * + * turn on installed WLAN hardware together with the corresponding LED + * + * val: 0 turns off the LED + * 1 turns the LED to orange + * + * return value: ? + */ +static int wbutton_fct_2(int val) +{ + struct register_buffer regs; + if (acerhk_model_features & TM_F_WBUTTON) { + acerhk_wlan_state = val; + regs.eax = 0x9610; + regs.ebx = ((val & 0xff) << 8) | 0x35; + preempt_disable(); + call_bios(®s); + preempt_enable_no_resched(); + if (verbose > 3) + printk(KERN_INFO"acerhk: wbutton2 = 0x%x\n", regs.eax); + } else { + if (verbose > 3) + printk(KERN_INFO"acerhk: wbutton function 2 not supported\n"); + regs.eax = 0x00; + } + return regs.eax & 0xffff; +} + +/* get_cmos_index + * + * gets index of CMOS port from ROM. The number of events is monitored + * in this port. + * + * return value: index of CMOS port + */ +static int get_cmos_index(void) +{ + struct register_buffer regs; + regs.eax = 0x9610; + regs.ebx = 0x51C; + preempt_disable(); + call_bios(®s); + preempt_enable_no_resched(); + cmos_index = regs.ecx & 0xff; + if (verbose) + printk(KERN_INFO"acerhk: cmos index set to 0x%x\n", cmos_index); + return cmos_index; +} + +/* get_nr_events + * + * gets the number of cached events (keys pressed) in queue. Up to 31 events + * are cached. + * + * return value: number of events in queue + */ +static int get_nr_events(void) +{ + unsigned long flags; + unsigned char c = 0; + + spin_lock_irqsave (&rtc_lock, flags); +#ifndef DUMMYHW + if (cmos_index) + c = CMOS_READ(cmos_index); + else if (verbose > 3) + printk(KERN_INFO"acerhk: get_nr_events - no valid cmos index set\n"); +#endif + spin_unlock_irqrestore (&rtc_lock, flags); + return c; +} + +/* set_mail_led + * + * change state of mail led + * + * val: 0 - switch led off + * 1 - switch led on (blinking) + * + * return value: 1 - action succesfull (val valid) + * 0 - no action taken (val invalid) + */ +static int set_mail_led(int val) +{ + struct register_buffer regs; + if (acerhk_model_features & TM_F_MAIL_LED) { + regs.eax = 0x9610; + regs.ebx = ((val & 0xff) << 8) | 0x31; + preempt_disable(); + call_bios(®s); + preempt_enable_no_resched(); + if (verbose > 3) + printk(KERN_INFO"acerhk: mail led set to = 0x%x\n", val); + } else if (acerhk_model_features & TM_F_MAIL_LED_EC) { + if (val == 1) + enable_mail_led_ec_1(); + else if (val == 0) + disable_mail_led_ec_1(); + } else if (acerhk_model_features & TM_F_MAIL_LED_EC2) { + if (val == 1) + enable_mail_led_ec_2(); + else if (val == 0) + disable_mail_led_ec_2(); + } else if (acerhk_model_features & TM_F_MAIL_LED_EC3) { + if (val == 1) + enable_mail_led_ec_3(); + else if (val == 0) + disable_mail_led_ec_3(); + } else { + if (verbose > 3) + printk(KERN_INFO"acerhk: mail led not supported\n"); + regs.eax = 0x00; + } + return regs.eax & 0xffff; +} + +/* launch_connect + * + * does what? + * val: 1 - only known value from windows driver + */ +static int launch_connect(int val) +{ + struct register_buffer regs; + if (acerhk_model_features & TM_F_CONNECT) { + regs.eax = 0x9610; + regs.ebx = ((val & 0xff) << 8) | 0x2e; + preempt_disable(); + call_bios(®s); + preempt_enable_no_resched(); + if (verbose > 3) + printk(KERN_INFO"acerhk: connect(%d) = 0x%x\n", val, regs.eax); + } else { + if (verbose > 3) + printk(KERN_INFO"acerhk: connect not supported\n"); + regs.eax = 0x00; + } + return regs.eax & 0xffff; +} + +/* }}} */ + +/* {{{ hardware probing */ + +static struct proc_dir_entry *proc_acer_dir; + +static unsigned int __init find_hk_area(void) +{ + int offset, sig; + unsigned int fkt; + fkt = 0; + sig = -1; /* offset to signature in io area */ + /* Look for signature, start at 0xf0000, search until 0xffff0 */ + for (offset = 0;offset < 0xfffd; offset += 16) { + if (readl(reg1 + offset) == 0x30552142) { + sig = offset; + offset = 0xffff; + } + } + if (sig < 0) + printk(KERN_WARNING"acerhk: could not find request handler, possibly not all functions available\n"); + else { + /* compute location of bios routine */ + fkt = readl(reg1 + sig + 5); + /* adjust fkt to address of mapped IO area */ + if (fkt >= 0xf0000) + fkt = (unsigned int)reg1 + fkt - 0xf0000; + else if (fkt >= 0xe0000) + fkt = (unsigned int)reg1 + fkt - 0xe0000; + else + fkt = 0; + } + return fkt; +} + +static void print_features(void) +{ + int i; + printk(KERN_INFO"acerhk: supported keys:"); + for (i = 0; i < 255; i++) { + switch (acerhk_key2name[i]) { + case k_help: printk(" help"); break; + case k_setup: printk(" setup"); break; + case k_p1: printk(" p1"); break; + case k_p2: printk(" p2"); break; + case k_p3: printk(" p3"); break; + case k_www: printk(" www"); break; + case k_mail: printk(" mail"); break; + case k_wireless: printk(" wireless"); break; + case k_power: printk(" power"); break; + case k_mute: printk(" mute"); break; + case k_volup: printk(" volup"); break; + case k_voldn: printk(" voldn"); break; + case k_res: printk(" res"); break; + case k_close: printk(" close"); break; + case k_open: printk(" open"); break; + case k_wireless2: printk(" wireless2"); break; + case k_play: printk(" play"); break; + case k_stop: printk(" stop"); break; + case k_prev: printk(" prev"); break; + case k_next: printk(" next"); break; + case k_display: printk(" display"); break; + default: break; + } + } + printk("\n"); + if (acerhk_model_features & TM_F_MUTE_LED_EC) + printk(KERN_INFO"acerhk: mute led is supported\n"); + if (acerhk_model_features & TM_F_MAIL_LED) + printk(KERN_INFO"acerhk: mail led is supported\n"); + else if (acerhk_model_features & TM_F_MAIL_LED_EC) + printk(KERN_INFO"acerhk: mail led (EC) is supported\n"); + else if (acerhk_model_features & TM_F_MAIL_LED_EC2) + printk(KERN_INFO"acerhk: mail led (EC2) is supported\n"); + else if (acerhk_model_features & TM_F_MAIL_LED_EC3) + printk(KERN_INFO"acerhk: mail led (EC3) is supported\n"); + printk(KERN_INFO"acerhk: supported functions:"); + if (acerhk_model_features & TM_F_CONNECT) + printk(" connect"); + if (acerhk_model_features & TM_F_THERMAL) + printk(" thermal"); + if (acerhk_model_features & TM_F_PBUTTON) + printk(" pbutton"); + if (acerhk_model_features & TM_F_WBUTTON) + printk(" wbutton"); + printk("\n"); +} + +static void __init setup_keymap_model(unsigned int series) +{ + /* clear mapping keycode -> keyname, */ + memset(&acerhk_key2name[0], k_none, sizeof(acerhk_key2name)); + /* first set the common keys, namely FnF1 and FnF2, */ + acerhk_key2name[1] = k_help; + acerhk_key2name[2] = k_setup; + /* then set known keycodes according to model */ + switch (series) { + case 110: + acerhk_key2name[48] = k_wireless; + acerhk_key2name[17] = k_p1; + acerhk_key2name[18] = k_p2; + acerhk_key2name[54] = k_www; + acerhk_key2name[49] = k_mail; + acerhk_key2name[3] = k_power; + acerhk_key2name[8] = k_mute; + acerhk_key2name[32] = k_volup; + acerhk_key2name[33] = k_voldn; + /* C110 generates 2 extra codes when opening/closing the lid */ + acerhk_key2name[74] = k_close; + acerhk_key2name[75] = k_open; + break; + case 300: /* treat C300 like C100 with Bluetooth button */ + acerhk_key2name[68] = k_wireless2; + case 100: + acerhk_key2name[48] = k_wireless; + acerhk_key2name[17] = k_p1; + acerhk_key2name[18] = k_p2; + acerhk_key2name[49] = k_www; + acerhk_key2name[54] = k_mail; + acerhk_key2name[3] = k_power; + acerhk_key2name[8] = k_mute; + acerhk_key2name[32] = k_volup; + acerhk_key2name[33] = k_voldn; + break; + default: + /* only the two common keys are supported */ + break; + case 210: + acerhk_key2name[19] = k_p1; + acerhk_key2name[20] = k_p2; + acerhk_key2name[17] = k_www; + acerhk_key2name[18] = k_mail; + break; + case 220: + case 260: /* 260 with same keys? */ + acerhk_key2name[49] = k_p1; + acerhk_key2name[19] = k_p2; + acerhk_key2name[18] = k_www; + acerhk_key2name[17] = k_mail; + break; + case 230: + case 280: /* 280 with same keys? */ + acerhk_key2name[17] = k_p1; + acerhk_key2name[18] = k_p2; + acerhk_key2name[49] = k_mail; + acerhk_key2name[54] = k_www; + break; + case 1500: + acerhk_key2name[0x49] = k_setup; + acerhk_key2name[0x36] = k_www; + acerhk_key2name[0x31] = k_mail; + acerhk_key2name[0x11] = k_p1; + acerhk_key2name[0x12] = k_p2; + acerhk_key2name[0x30] = k_wireless; + acerhk_key2name[0x44] = k_wireless2; + acerhk_key2name[0x03] = k_power; + break; + case 240: + acerhk_key2name[0x31] = k_www; + acerhk_key2name[0x36] = k_mail; + acerhk_key2name[0x11] = k_p1; + acerhk_key2name[0x12] = k_p2; + acerhk_key2name[0x44] = k_wireless; + acerhk_key2name[0x30] = k_wireless2; + acerhk_key2name[0x03] = k_power; + acerhk_key2name[0x08] = k_mute; + // acerhk_key2name[] = k_volup; + // acerhk_key2name[] = k_voldn; + break; + case 2900: + acerhk_key2name[0x31] = k_mail; /* with led */ + acerhk_key2name[0x36] = k_www; + acerhk_key2name[0x11] = k_p1; + acerhk_key2name[0x12] = k_p2; + acerhk_key2name[0x30] = k_wireless; /* wireless, with led, related with autowlan=1 */ + break; + case 250: /* enriqueg@altern.org */ + /* TravelMate 254LMi_DT manual common for 240/250 series, but key order + differ from 240 already present on acerhk driver */ + /* TravelMate 254LMi_DT: 6 buttons: left to right: mail, www, p1, p2, bluetooth, wireless */ + acerhk_key2name[0x31] = k_mail; /* with led */ + acerhk_key2name[0x36] = k_www; + acerhk_key2name[0x11] = k_p1; + acerhk_key2name[0x12] = k_p2; + acerhk_key2name[0x44] = k_wireless2; /* bluetooth, hw optional */ + acerhk_key2name[0x30] = k_wireless; /* wireless, with led, related with autowlan=1 */ + acerhk_key2name[0x03] = k_power; /* Fn+F3 */ + acerhk_key2name[0x08] = k_mute; /* Fn+F8 */ + break; + case 380: + /* TM 380 has same codes as TM 370, with an additional one */ + acerhk_key2name[0x03] = k_power; + case 370: + acerhk_key2name[0x30] = k_wireless; + acerhk_key2name[0x11] = k_p1; + acerhk_key2name[0x12] = k_p2; + acerhk_key2name[0x13] = k_p3; + acerhk_key2name[0x36] = k_www; + acerhk_key2name[0x31] = k_mail; + break; + case 360: + /* 360 series has the same layout as 350, with an + additional wireless key */ + acerhk_key2name[64] = k_wireless; + case 350: + acerhk_key2name[17] = k_p1; + acerhk_key2name[18] = k_p2; + acerhk_key2name[20] = k_p3; + acerhk_key2name[21] = k_www; + acerhk_key2name[19] = k_mail; + break; + case 520: + acerhk_key2name[19] = k_p1; + acerhk_key2name[20] = k_p2; + acerhk_key2name[17] = k_www; + acerhk_key2name[18] = k_mail; + break; + case 610: + acerhk_key2name[17] = k_p1; + acerhk_key2name[18] = k_p2; + acerhk_key2name[19] = k_p3; + acerhk_key2name[21] = k_www; + acerhk_key2name[20] = k_mail; + acerhk_key2name[64] = k_wireless; + break; + case 630: + /* 630 has all keys of 620 plus one */ + acerhk_key2name[8] = k_mute; + case 620: + acerhk_key2name[17] = k_p1; + acerhk_key2name[18] = k_p2; + acerhk_key2name[19] = k_p3; + acerhk_key2name[54] = k_www; + acerhk_key2name[49] = k_mail; + acerhk_key2name[48] = k_wireless; + acerhk_key2name[3] = k_power; + acerhk_key2name[32] = k_volup; + acerhk_key2name[33] = k_voldn; + break; + case 290: + case 420: + case 430: + case 530: + case 540: + case 650: + case 660: + case 800: + case 1450: + case 2300: + case 2350: + case 4000: + case 4050: + case 6000: + case 8000: + case 4100: + case 4150: + case 4500: + case 4600: + case 4650: + case 1680: + case 1690: + /* keys are handled by dritek EC */ + acerhk_key2name[1] = k_none; + acerhk_key2name[2] = k_none; + break; + case 1300: + case 1310: + case 1350: + case 1360: + case 1400: + case 1700: + case 1800: + case 2000: + case 2010: + case 2020: + /* Aspire 13xx series laptops use dritek hardware, no + acerhk-mapping needed + VolUp and VolDown are managed as normal keys + 1300/1310 series should have P1, P2, Mail, WWW, Mute buttons + 1353 has bluetooth, wifi, p1, p2, www, mail, help, setup, power + and mute + Aspire 1400/1450/Ferrari use dritek EC, too + 1450 should have bluetooth, wifi, p1, p2, www, mail, help, + setup, power and mute + Aspire 1700 uses dritek EC, too + 1700 should have bluetooth, wifi, p1, p2, www, mail, help, + setup, power and mute + need the MM-buttons Activation? (forward, shuffle, ...) + 2000 hast lots of MM buttons + 2010 should have bluetooth, wifi, p1, p2, www, mail, help, + setup, power and mute + */ + acerhk_key2name[1] = k_none; + acerhk_key2name[2] = k_none; + break; + case 1600: + /* Aspire 1600 has acer keycode 0x49 for FnF2 */ + acerhk_key2name[73] = k_setup; + acerhk_key2name[48] = k_wireless; + acerhk_key2name[49] = k_mail; + acerhk_key2name[54] = k_www; + acerhk_key2name[17] = k_p1; + acerhk_key2name[18] = k_p2; + acerhk_key2name[19] = k_p3; + acerhk_key2name[3] = k_power; + acerhk_key2name[8] = k_mute; + /* VolUp and VolDown keys doesn't seem to be managed as special keys + but as normal keys ! */ + break; + case 5020: /* Aspire 5020 has 0x6a for Fn+F2 */ + acerhk_key2name[2] = k_none; + acerhk_key2name[106] = k_setup; + acerhk_key2name[3] = k_power; + acerhk_key2name[5] = k_display; + acerhk_key2name[49] = k_mail; + acerhk_key2name[54] = k_www; + acerhk_key2name[17] = k_p1; + acerhk_key2name[18] = k_p2; + acerhk_key2name[48] = k_wireless; + acerhk_key2name[68] = k_wireless2; + break; + case 2410: /* TM 2410 is very similar to Aspire 5020, but has 0x6s for Fn-F3 */ + acerhk_key2name[2] = k_none; + acerhk_key2name[106] = k_setup; + acerhk_key2name[109] = k_power; + acerhk_key2name[49] = k_mail; + acerhk_key2name[54] = k_www; + acerhk_key2name[17] = k_p1; + acerhk_key2name[18] = k_p2; + acerhk_key2name[48] = k_wireless; + acerhk_key2name[68] = k_wireless2; + break; + case 40100: + /* Medion MD40100, 4 keys */ + acerhk_key2name[54] = k_www; + acerhk_key2name[49] = k_mail; + acerhk_key2name[48] = k_wireless; + acerhk_key2name[55] = k_res; + break; + case 96500: + case 95400: + /* Medion MD95400, many keys */ + acerhk_key2name[49] = k_mail; /* 1 */ + acerhk_key2name[54] = k_www; /* 2 */ + acerhk_key2name[48] = k_wireless; /* 3 */ + acerhk_key2name[68] = k_wireless2; /* 4 (Bluetooth) */ + + acerhk_key2name[17] = k_p1; /* 5 */ + acerhk_key2name[18] = k_p2; /* 6 */ + acerhk_key2name[36] = k_play; /* 7 */ + acerhk_key2name[37] = k_stop; /* 8 */ + acerhk_key2name[34] = k_prev; /* 9 */ + acerhk_key2name[35] = k_next; /* 10 */ + acerhk_key2name[33] = k_voldn; /* 11 */ + acerhk_key2name[32] = k_volup; /* 12 */ + acerhk_key2name[38] = k_p3; /* 13 */ + acerhk_key2name[8] = k_mute; /* 14 */ + + acerhk_key2name[1] = k_help; /* FN+F1 (Help) */ + acerhk_key2name[5] = k_display; /* FN+F3 (Display switch) */ + acerhk_key2name[6] = k_res; /* FN+F4 (Display ein/ausschalten) */ + break; + case 42200: + /* Medion MD42200, 7 keys, no setup */ + acerhk_key2name[2] = k_none; + acerhk_key2name[5] = k_display; + acerhk_key2name[54] = k_www; + acerhk_key2name[48] = k_wireless; + acerhk_key2name[49] = k_mail; + acerhk_key2name[17] = k_p1; + acerhk_key2name[18] = k_p2; + break; + case 9783: + /* Medion MD9783, 6 keys + info, no setup */ + acerhk_key2name[2] = k_none; + acerhk_key2name[54] = k_www; + acerhk_key2name[49] = k_mail; + acerhk_key2name[17] = k_p1; + acerhk_key2name[18] = k_p2; + acerhk_key2name[19] = k_p3; + acerhk_key2name[8] = k_mute; + break; + case 7400: + /* Amilo Pro V2000 does not have Help and Setup key (?) + Amilo M 7400 has Help key, disabling only setup + */ + acerhk_key2name[2] = k_none; + acerhk_key2name[48] = k_wireless; + acerhk_key2name[49] = k_mail; + acerhk_key2name[54] = k_www; + acerhk_key2name[17] = k_p1; + acerhk_key2name[18] = k_p2; + break; + case 1559: + acerhk_key2name[6] = k_display; /* FN+F4 (Display ein/ausschalten) */ + case 1555: + /* AOpen (Ahtec Signal 1555M) is similar to FS Amilo M */ + acerhk_key2name[2] = k_none; + acerhk_key2name[48] = k_wireless; + acerhk_key2name[49] = k_mail; + acerhk_key2name[54] = k_www; + acerhk_key2name[17] = k_p1; + acerhk_key2name[18] = k_p2; + acerhk_key2name[34] = k_prev; + acerhk_key2name[35] = k_next; + acerhk_key2name[36] = k_play; + acerhk_key2name[37] = k_stop; + break; + case 6800: + case 7820: + /* Amilo D does not have Setup key */ + acerhk_key2name[2] = k_none; + acerhk_key2name[49] = k_mail; + acerhk_key2name[54] = k_www; + acerhk_key2name[17] = k_p1; + acerhk_key2name[18] = k_p2; + acerhk_key2name[19] = k_p3; + acerhk_key2name[8] = k_mute; + break; + case 6805: /* Added by damagedspline@aim.com */ + /* Amilo A1xxx does not have Setup key nor a mail key */ + acerhk_key2name[2] = k_none; + acerhk_key2name[54] = k_www; + acerhk_key2name[5] = k_display; + acerhk_key2name[110] = k_setup; //This is the Fancy Fan (cool-n'-quiet) key on A1650g + acerhk_key2name[48] = k_wireless; + break; + } +} + +static void __init setup_model_features(unsigned int series) +{ + switch (series) { + case 200: + case 210: + case 520: + /* nothing special */ + acerhk_model_features = 0; + acerhk_type = TM_old; + break; + case 220: + case 230: + case 260: + case 280: + case 360: + case 40100: /* Medion MD40100 */ + case 95400: /* Medion MD95400 */ + case 96500: /* Medion MD96500 */ + /* all special functions, no mail led */ + acerhk_model_features = 0x00f00000; + acerhk_type = TM_new; + break; + case 42200: /* Medion MD42200 */ + /* has WLAN button, should call connect() */ + acerhk_model_features = TM_F_WBUTTON | TM_F_CONNECT; + acerhk_type = TM_old; + break; + case 9783: /* Medion MD9783 */ + /* only email led */ + acerhk_model_features = TM_F_MAIL_LED; + acerhk_type = TM_new; + break; + case 1600: + acerhk_type = TM_new; + /* Do Aspire 1600 series have special functions or not ? I enable + them, perhaps it helps with problems Francois Valenduc has */ + acerhk_model_features = 0x00f00000; + break; + case 300: + case 100: + case 110: + case 240: + case 350: + case 610: + case 620: + case 630: + /* all special functions, mail led */ + acerhk_model_features = TM_F_MAIL_LED | 0x00f00000; + acerhk_type = TM_new; + break; + case 370: + case 380: + case 2410: + case 2900: /* Medion MD2900 */ + case 2100: /* TM 2100 uses same driver as 5020 */ + case 5020: /* Aspire 5020 is still old hardware */ + acerhk_model_features = TM_F_MAIL_LED | TM_F_CONNECT| TM_F_WBUTTON; + acerhk_type = TM_new; + break; + case 7400: + case 1555: + case 1559: + /* all special functions for Fujitsu-Siemens Amilo M7400, Pro V2000; AOpen */ + acerhk_model_features = 0x00f00000; + acerhk_type = TM_new; + break; + case 6805: /* Added by damagedspline@aim.com */ + /* Amilo A1xxx does not have a mail led */ + acerhk_model_features = 0x00f00000; + acerhk_type = TM_new; + break; + case 6800: + case 7820: + /* mail led and all special functions for FS Amilo D */ + acerhk_model_features = TM_F_MAIL_LED | 0x00f00000; + acerhk_type = TM_new; + break; + case 2350: + case 4050: + acerhk_wlan_state = 1; // Default state is on + case 290: + /* no special functions, wireless hardware controlled by EC */ + acerhk_model_features = TM_F_WLAN_EC2 | TM_F_BLUE_EC2; + acerhk_type = TM_dritek; + break; + case 650: + case 1300: + case 1310: + case 1400: + case 1700: + /* all special functions, wireless hardware can be controlled */ + acerhk_model_features = 0x00f00000; + acerhk_type = TM_dritek; + break; + case 4100: + case 4600: + case 1680: + case 1690: /* Aspire 1680/1690 should be similar to TM 4100/4600 */ + /* mail led, wireless and bluetooth controlled the old way, but keys are + controlled by normal keyboard controller, so mark as dritek and + deactivate dritek use */ + acerhk_model_features = TM_F_MAIL_LED | TM_F_WBUTTON; + acerhk_type = TM_dritek; + usedritek=0; + break; + case 660: + case 800: + /* all special functions, mail led */ + acerhk_model_features = TM_F_MAIL_LED | 0x00f00000; + acerhk_type = TM_dritek; + break; + case 1350: + case 1360: + /* mail led, handled by EC, wireless HW is not (yet) controllable ? */ + acerhk_model_features = TM_F_MAIL_LED_EC|TM_F_WLAN_EC1; + acerhk_type = TM_dritek; + break; + case 1450: + /* Bluetooth/Wlan led, Mail led handled by EC (variant 3) */ + acerhk_model_features = TM_F_MAIL_LED_EC3|TM_F_WBUTTON; + acerhk_type = TM_dritek; + break; + case 1500: + /* Bluetooth/Wlan led */ + acerhk_model_features = TM_F_WBUTTON; + acerhk_type = TM_new; + break; + case 420: + case 430: + /* all functions and dritek EC, mail LED is handled by EC, second + variant. An additional led is available, mute. (really?) + */ + acerhk_type = TM_dritek; + acerhk_model_features = TM_F_MUTE_LED_EC|TM_F_MAIL_LED_EC2; + break; + case 2300: + case 4000: + case 4500: + /* wireless hardware, hopefully under control of my driver */ + acerhk_type = TM_dritek; + acerhk_model_features = TM_F_BLUE_EC1|TM_F_WLAN_EC1; + break; + case 3200: + /* test, if this model uses old style wlan control */ + acerhk_model_features = TM_F_WBUTTON; + acerhk_type = TM_dritek; + break; + case 6000: + case 8000: + /* 6000 and 8000 have wireless hardware, but I don't know how to handle, + so I choose no features */ + acerhk_type = TM_dritek; + break; + case 530: + case 540: + case 2000: + /* No features (?) dritek EC, mail LED is handled by EC but + different from other Aspire series */ + acerhk_type = TM_dritek; + acerhk_model_features = TM_F_MAIL_LED_EC2; + break; + case 4150: + case 4650: + /* Dritek EC, bluetooth, wifi, mail */ + /* According to Andreas Stumpfl his TM 4652LMi does also work as series + 3200, which might mean that the BIOS function accesses the EC */ + acerhk_type = TM_dritek; + acerhk_model_features = TM_F_MAIL_LED_EC2 | TM_F_WLAN_EC2 | TM_F_BLUE_EC2; + break; + case 1800: + case 2010: + case 2020: + /* Dritek EC, bluetooth, wifi, mail */ + acerhk_type = TM_dritek; + acerhk_model_features = TM_F_MAIL_LED_EC2 | TM_F_WLAN_EC2 | TM_F_BLUE_EC2; + acerhk_wlan_state = 1; // Default state is on + break; + case 250: /* enriqueg@altern.org */ + /* TravelMate254LMi_DT : mail led, bluetooth (button present, hw optional), wifi (with led) */ + acerhk_model_features = TM_F_MAIL_LED| + TM_F_WBUTTON ; + acerhk_type = TM_new; + acerhk_wlan_state = 0; //Initial state is off on 254LMi_DT + break; + default: + /* nothing special */ + acerhk_model_features = 0; + acerhk_type = TM_unknown; + break; + } + /* set the correct bios call function according to type */ + if ((acerhk_type == TM_new) || (acerhk_type == TM_dritek)) { + call_bios = call_bios_6xx; + if (verbose > 2) + printk(KERN_INFO"acerhk: using call_bios_6xx mode\n"); + } else { + call_bios = call_bios_52x; + if (verbose > 2) + printk(KERN_INFO"acerhk: using call_bios_52x mode\n"); + } + /* remove key file on dritek hardware */ + if (acerhk_type == TM_dritek) { + remove_proc_entry("key", proc_acer_dir); + } + /* setup available keys */ + setup_keymap_model(acerhk_series); + if (verbose > 1) + print_features(); +} + +static unsigned int __init determine_laptop_series(char * str) +{ + /* 0 means unknown series, handled like TM 200 */ + unsigned int series = 0; + if (strncmp(str, "TravelMate ", 11) == 0) { + switch (str[11]) { + case 'C': + if (str[12] == '1') { + if (str[13] == '0') { + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates TM C100 series\n"); + series = 100; + } else if (str[13] == '1') { + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates TM C110 series\n"); + series = 110; + } + } else if (str[12] == '3') { + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates TM C300 series\n"); + series = 300; + } + break; + case 'F': + if (str[12] == '4') { + series = 230; + } + break; + case '2': + if (str[14] == '0') { + /* newer Travelmate 2xxx series */ + switch (str[12]) { + case '0': + case '5': + series = 2000; // 2000 and 2500 are the same + break; + case '1': + if (str[13] == '0') + series = 2100; + break; + case '2': + case '7': + series = 2200; // 2200 and 2700 are the same + break; + case '3': + if (str[13] == '0') + series = 4000; // 2300 is the same as 4000 + else if (str[13] == '5') + series = 4050; // 2350 is the same as 4050 + break; + case '4': + if (str[13] == '1') + series = 2410; + break; + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown TM 2xxx series\n"); + break; + } + } else { + /* older Travelmate 2xx series */ + switch (str[12]) { + case '0': series = 200; break; + case '1': series = 210; break; + case '2': series = 220; break; + case '4': series = 240; break; + case '5': series = 250; break; /* enriqueg@altern.org */ + case '6': series = 260; break; + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown TM 2xx series\n"); + break; + } + } + break; + case '3': + switch (str[12]) { + case '0': series = 3200; break; /* TM 3000 works like TM 3200 */ + /* Travelmate 3xx series */ + case '5': series = 350; break; + case '6': series = 360; break; + case '7': series = 370; break; + case '8': series = 380; break; + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown TM 3xx series\n"); + break; + } + break; + case '4': + if ( (strnlen(str, ACERHK_MODEL_STRLEN-1) == 15) && + (str[14] == '0') ) { /* Travelmate 4xxx series */ + switch (str[12]) { + case '0': /* 4000 and 4500 are the same */ + case '5': + series = 4000; + break; + case '1': + case '6': /* 4100 and 4600 are the same */ + series = 4100; + break; + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown TM 4xxx series\n"); + break; + } + } else { /* Travelmate 4xx series */ + switch (str[12]) { + case '2': series = 420; break; + case '3': series = 430; break; + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown TM 4xx series\n"); + break; + } + } + break; + case '5': /* Travelmate 5xx series */ + if (str[12] == '2') + series = 520; + else if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown TM 5xx series\n"); + break; + case '6': /* older Travelmate 6xx series */ + switch (str[12]) { + case '1': series = 610; break; + case '2': series = 620; break; + case '3': series = 630; break; + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown TM 6xx series\n"); + break; + } + break; + default: + printk(KERN_INFO"acerhk: model string indicates unknown TM xxx series\n"); + break; + } + if (series && verbose > 1) + printk(KERN_INFO"acerhk: model string indicates TM %d series\n", series); + } + /* newer Travelmate series do not have a space after 'TravelMate' */ + else if (strncmp(str, "TravelMate", 10) == 0) { + switch (str[10]) { + case '2': + if (str[11] == '9') { + series = 290; + } else { + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown TM2xx series\n"); + } + break; + case '3': + if (str[11] == '2' && str[14] == '3') { + // TM 3200 uses "TravelMate32003" + series = 3200; + } else { + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown TM3xxx series\n"); + } + break; + case '4': + switch (str[11]) { + case '3': series = 430; break; + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown TM4xx series\n"); + break; + } + break; + case '5': + switch (str[11]) { + case '3': series = 530; break; + case '4': series = 540; break; + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown TM5xx series\n"); + break; + } + break; + case '6': + switch (str[11]) { + case '5': series = 650; break; + case '6': series = 660; break; + case '0': + if (strncmp(str, "TravelMate60003", 15) == 0) { + series = 6000; break; + } + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown TM6xx series\n"); + break; + } + break; + case '8': + if (strncmp(str, "TravelMate80003", 15) == 0) { + series = 8000; + } else if (str[11] == '0') { + series = 800; + } else { + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown TM8xx series\n"); + } + break; + default: + printk(KERN_INFO"acerhk: model string indicates unknown TMxxx series\n"); + break; + } + if (series && verbose > 1) + printk(KERN_INFO"acerhk: model string indicates TM%d series\n", series); + } + else if (strncmp(str, "Aspire ", 7) == 0) { + switch(str[7]) { + case '1': /* Aspire 1xxx series */ + switch(str[8]) { + case '3': /* Aspire 13xx series */ + switch (str[9]) { + case '0': series = 1300; break; + case '1': series = 1310; break; + case '5': series = 1350; break; + case '6': series = 1360; break; + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown Aspire 13xx series\n"); + break; + } + break; + case '4': /* Aspire 14xx series */ + switch (str[9]) { + case '0': series = 1400; break; + case '5': series = 1450; break; + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown Aspire 14xx series\n"); + break; + } + break; + case '5': series = 1500; break; + case '6': /* Aspire 14xx series */ + switch (str[9]) { + case '0': series = 1600; break; + case '8': + case '9': series = 1680; break; + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown Aspire 16xx series\n"); + break; + } + break; + case '7': series = 1700; break; + case '8': series = 1800; break; + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown Aspire 1xxx series\n"); + break; + } + break; + case '2': /* Aspire 2xxx series */ + if (str[8] == '0') { + switch (str[9]) { + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown Aspire 20xx series\n"); + break; + case '0': series = 2000; break; + case '1': series = 2010; break; + case '2': series = 2020; break; + } + } else { + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown Aspire 2xxx series\n"); + } + break; + case '3': /* Aspire 3xxx series */ + if (str[8] == '0') { + switch (str[9]) { + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown Aspire 30xx series\n"); + break; + case '2': series = 5020; break; /* Aspire 3020/5020 are identical */ + } + } else { + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown Aspire 3xxx series\n"); + } + break; + case '5': /* Aspire 5xxx series */ + if (str[8] == '0') { + switch (str[9]) { + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown Aspire 50xx series\n"); + break; + case '2': series = 5020; break; + } + } else { + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown Aspire 5xxx series\n"); + } + break; + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown Aspire series\n"); + break; + } + if (series && verbose > 1) + printk(KERN_INFO"acerhk: model string indicates Aspire %d series\n", series); + } + else if (strncmp(str, "Extensa ", 8) == 0) { + /* Extensa series */ + switch (str[8]) { + case '3': + switch (str[9]) { + case '0': + series = 3000; break; + default: break; + } + break; + default: break; + } + if (series && verbose > 1) + printk(KERN_INFO"acerhk: model string indicates Extensa %d series\n", series); + else if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown Extensa series\n"); + } + else if (strncmp(str, "Amilo ", 6) == 0) { + switch (str[6]) { + case 'D': /* complete string is "Amilo D-Series", there seems to be no model number */ + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates FS Amilo D series\n"); + /* this is the model number of my Amilo */ + series = 7820; + break; + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown FS Amilo XX series\n"); + series = 7820; + } + } + else if (strncmp(str, "AMILO ", 6) == 0) { + switch (str[6]) { + case 'D': /* AMILO D 6800 P4-2000 */ + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates FS AMILO D series\n"); + series = 6800; + break; + case 'M': + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates FS AMILO M(7400) series\n"); + series = 7400; + break; + case 'P': + /* it is assumed, that 'AMILO P' appears only on Amilo Pro Series */ + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates FS AMILO Pro (V2000) series\n"); + series = 7400; + break; + case 'A': /* AMILO Axxxx - added by damagedspline@aim.com */ + switch (str[7]) { + case '1': /* AMILO A1xxx */ + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates FS AMILO A1xxx series\n"); + series = 6805; + break; + } + break; + default: + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates unknown FS AMILO XX series\n"); + series = 6800; + } + } + else if (strncmp(str, "MEDIONPC", 8) == 0) { + uint medionmodel; + if ((medionmodel = COLUSSI("WIM 2040", 4, reg1, AREA_SIZE)) >= 0) { + printk(KERN_INFO"acerhk: found Medion model string:'%s'\n", (char*)reg1+medionmodel); + series = 96500; + } else { + if ((medionmodel = COLUSSI("MD 9", 4, reg1, AREA_SIZE)) >= 0) { + printk(KERN_INFO"acerhk: found Medion model string:'%s'\n", (char*)reg1+medionmodel); + } + series = 95400; + } + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates a medion MD %d\n", series); + } + else if (strncmp(str, "MEDIONNB", 8) == 0) { + /* Search for the Product string of the MD9783. */ + if (COLUSSI("MD 42200", 8, reg1, AREA_SIZE) >= 0) { + if (verbose>1) + printk(KERN_INFO"acerhk: model string indicates a Medion MD 42200\n"); + series = 42200; + } else if (COLUSSI("MD 9783", 7, reg1, AREA_SIZE) >= 0){ + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates a medion MD 9783\n"); + series = 9783; + } else if (COLUSSI("WIM 2000", 7, reg1, AREA_SIZE) >= 0){ + if (verbose>1) + printk(KERN_INFO"acerhk: model string indicates a Medion MD 2900\n"); + series = 2900; + } else { + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates a medion MD40100\n"); + series = 40100; + } + } else if (strncmp(str, "AOpen", 5) == 0) { + if (strncmp(str, "AOpen*EzRestore", 15) == 0) { + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates a AOpen 1559\n"); + series = 1559; + } else { + /* Unless I know of other models no further differentiation, + although there is a second part of the model string */ + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates a AOpen\n"); + series = 1555; + } + } else if (strncmp(str, "CL56", 4) == 0) { + /* Unless I know of other models no further differentiation, + although there are strings with more numbers ("CL561" on a Compal + CL56/Zepto 4200, reported by Stian B. Barmen) + It has the same functions as Acer Aspire 2010 + */ + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates a Compal CL56 (or similar)\n"); + series = 2010; + } else { + if (verbose > 1) + printk(KERN_INFO"acerhk: model string indicates no supported hardware\n"); + } + return (series); +} + +static void __init probe_model(void) { + int offset; /* offset from beginning of reg1 to Model string */ + if (verbose) + printk(KERN_INFO"acerhk: start search for model string at %p\n", reg1); + /* first we look for Travelmate, if it isn't one we try to identify other + laptops, such as Medion or Aspire */ + offset = COLUSSI("Travel", 6, reg1, AREA_SIZE); + /* Try to detect Aspire laptops */ + if (offset < 0) + offset = COLUSSI("Aspire", 6, reg1, AREA_SIZE); + /* Try to detect Extensa laptops */ + if (offset < 0) + offset = COLUSSI("Extensa", 7, reg1, AREA_SIZE); + /* Try to detect Medion laptops */ + if (offset < 0) + offset = COLUSSI("MEDION", 6, reg1, AREA_SIZE); + /* Try to detect AOpen laptops */ + if (offset < 0) + offset = COLUSSI("AOpen", 5, reg1, AREA_SIZE); + /* Try to detect Fujitsu Siemens Amilo laptops */ + if (offset < 0) + offset = COLUSSI("Amilo", 5, reg1, AREA_SIZE); + if (offset < 0) + offset = COLUSSI("AMILO", 5, reg1, AREA_SIZE); + /* Try to detect Compal */ + if (offset < 0) + offset = COLUSSI("CL56", 4, reg1, AREA_SIZE); + if (offset >= 0) { + acerhk_model_addr = reg1 + offset; + /* copy the string, but not more than 15 characters */ + strncpy(acerhk_model_string, acerhk_model_addr, ACERHK_MODEL_STRLEN-1); + if (verbose) + printk(KERN_INFO"acerhk: found model string '%s' at %p\n", + acerhk_model_string, acerhk_model_addr); + if (bios_routine && verbose > 2) + printk(KERN_INFO"acerhk: offset from model string to function address: 0x%lx\n", + bios_routine - (unsigned long)acerhk_model_addr); + acerhk_series = determine_laptop_series(acerhk_model_string); + } else { + printk(KERN_WARNING"acerhk: Could not find model string, will assume type 200 series\n"); + acerhk_series = 200; + } +} + +/* }}} */ + +/* {{{ key polling and translation */ + +static void print_mapping(void) +{ + printk(KERN_INFO"acerhk: key mapping:\n"); + printk("acerhk: help 0x%x\n", acerhk_name2event[k_help]); + printk("acerhk: setup 0x%x\n", acerhk_name2event[k_setup]); + printk("acerhk: p1 0x%x\n", acerhk_name2event[k_p1]); + printk("acerhk: p2 0x%x\n", acerhk_name2event[k_p2]); + printk("acerhk: p3 0x%x\n", acerhk_name2event[k_p3]); + printk("acerhk: www 0x%x\n", acerhk_name2event[k_www]); + printk("acerhk: mail 0x%x\n", acerhk_name2event[k_mail]); + printk("acerhk: wireless 0x%x\n", acerhk_name2event[k_wireless]); + printk("acerhk: power 0x%x\n", acerhk_name2event[k_power]); + printk("acerhk: mute 0x%x\n", acerhk_name2event[k_mute]); + printk("acerhk: volup 0x%x\n", acerhk_name2event[k_volup]); + printk("acerhk: voldn 0x%x\n", acerhk_name2event[k_voldn]); + printk("acerhk: res 0x%x\n", acerhk_name2event[k_res]); + printk("acerhk: close 0x%x\n", acerhk_name2event[k_close]); + printk("acerhk: open 0x%x\n", acerhk_name2event[k_open]); + printk("acerhk: wireless2 0x%x\n", acerhk_name2event[k_wireless2]); + printk("acerhk: play 0x%x\n", acerhk_name2event[k_play]); + printk("acerhk: stop 0x%x\n", acerhk_name2event[k_stop]); + printk("acerhk: prev 0x%x\n", acerhk_name2event[k_prev]); + printk("acerhk: next 0x%x\n", acerhk_name2event[k_next]); + printk("acerhk: display 0x%x\n", acerhk_name2event[k_display]); +} + +static void set_keymap_name(t_key_names name, unsigned int key) +{ + acerhk_name2event[name] = key; +} + +static void init_keymap_input(void) +{ + /* these values for input keys are chosen to match the key names on the + actual Acer laptop */ + set_keymap_name(k_none, KEY_RESERVED); + set_keymap_name(k_help, KEY_HELP); + set_keymap_name(k_setup, KEY_CONFIG); + set_keymap_name(k_p1, KEY_PROG1); + set_keymap_name(k_p2, KEY_PROG2); + set_keymap_name(k_p3, KEY_PROG3); + set_keymap_name(k_www, KEY_WWW); + set_keymap_name(k_mail, KEY_MAIL); + set_keymap_name(k_wireless, KEY_XFER); + set_keymap_name(k_power, KEY_POWER); + set_keymap_name(k_mute, KEY_MUTE); + set_keymap_name(k_volup, KEY_VOLUMEUP); + set_keymap_name(k_voldn, KEY_VOLUMEDOWN); + set_keymap_name(k_res, KEY_CONFIG); + set_keymap_name(k_close, KEY_CLOSE); + set_keymap_name(k_open, KEY_OPEN); + /* I am not really happy with the selections for wireless and wireless2, + but coffee looks good. Michal Veselenyi proposed this value */ + set_keymap_name(k_wireless2, KEY_COFFEE); + set_keymap_name(k_play, KEY_PLAYPAUSE); + set_keymap_name(k_stop, KEY_STOPCD); + set_keymap_name(k_prev, KEY_PREVIOUSSONG); + set_keymap_name(k_next, KEY_NEXTSONG); + set_keymap_name(k_display, KEY_MEDIA); /* also not happy with this */ + if (verbose > 1) + print_mapping(); +} + +static int filter_idle_value(int keycode) +{ + int validkey = 0; + if (keycode != 0x0 && + keycode != 0x9610 && + keycode != 0xc100 && /* Francois Valenduc, Aspire 1601 LC */ + keycode != 0x8610 && + keycode != 0x861 && + keycode != 0x8650 && + keycode != 0x865) + validkey = keycode; + if (verbose > 4 && !validkey) + printk(KERN_INFO"acerhk: throw away idle value 0x%x\n", keycode); + return validkey; +} + +static void send_key_event(t_key_names key) +{ + unsigned int input_key; + if (key != k_none) { + /* convert key name to kernel keycode */ + input_key = acerhk_name2event[key]; + if (verbose > 2) + printk(KERN_INFO"acerhk: translated acer key name 0x%x to input key 0x%x\n", + key, input_key); + /* send press and release together, as there is no such event from acer as 'release' */ + input_report_key(acerhk_input_dev_ptr, input_key, 1); + input_report_key(acerhk_input_dev_ptr, input_key, 0); + } +} + +static t_key_names transl8_key_code(int keycode) +{ + t_key_names keyname = k_none; + /* first filter out idle values */ + if ( (keycode = filter_idle_value(keycode)) ) { + if (verbose > 3) + printk(KERN_INFO"acerhk: received key code 0x%x\n", keycode); + /* translate keycode to key name */ + if (keycode >= 0 && keycode <= 255) + keyname = acerhk_key2name[keycode]; + else { + if (verbose > 3) + printk(KERN_INFO"acerhk: keycode 0x%x too big, will use only 8 bits\n", keycode); + /* use only lower 8 bits of value to distinguish keys */ + keyname = acerhk_key2name[keycode&0xff]; + } + /* produce some log information for higher verbosity levels */ + if (keyname != k_none && verbose > 2) + printk(KERN_INFO"acerhk: translated acer key code 0x%x to key name 0x%x\n", + keycode, keyname); + else if (keyname == k_none && verbose > 3) + printk(KERN_INFO"acerhk: translated acer key code 0x%x to no key\n", + keycode); + if (autowlan) { + /* if automatic switching of wlan hardware is enabled, do it here + on wireless key press */ + if (keyname == k_wireless2) { + if (acerhk_bluetooth_state) + wbutton_fct_1(0); + else + wbutton_fct_1(1); + } + if (keyname == k_wireless) { + if (acerhk_wlan_state) + wbutton_fct_2(0); + else + wbutton_fct_2(1); + } + } + } + return keyname; +} + +/* polling timer handler */ +static void acerhk_poll_event(unsigned long save_size) +{ +#ifndef DUMMYHW + unsigned int max = MAX_POLLING_LOOPS; + /* make sure not to loop more then 32 times */ + if (!max || max > 32) + max = 32; + if (acerhk_type != TM_dritek) { + while (get_nr_events() && max--) { + send_key_event(transl8_key_code(get_fnkey_event())); + } + } else { + send_key_event(transl8_key_code(get_fnkey_event())); + } +#endif + acerhk_timer_poll.expires = jiffies + acerhk_polling_delay; + add_timer(&acerhk_timer_poll); +} + +/* blinking timer handler; added by Antonio Cuni */ +static void acerhk_blink_event(unsigned long not_used) +{ + if (acerhk_blueled_blinking != -1) { + acerhk_blueled_blinking = !acerhk_blueled_blinking; +#ifndef DUMMYHW + wbutton_fct_1(acerhk_blueled_blinking); +#endif + acerhk_timer_blinking.expires = jiffies + acerhk_blueled_blinking_delay; + add_timer(&acerhk_timer_blinking); + } + else + printk(KERN_WARNING "acerhk: blinking event called, but blinking not active\n"); +} + +static void init_input(void) +{ + int i; + +#ifndef KERNEL26 + /* request keyboard input module */ + request_module("keybdev"); + if (verbose > 3) + printk(KERN_INFO"requested keyboard input driver\n"); +#endif + +#ifndef STATIC_INPUT_DEV + /* allocate acerhk input device */ + acerhk_input_dev_ptr=input_allocate_device(); + /* enter some name */ + acerhk_input_dev_ptr->name = "Acer hotkey driver"; +#else + acerhk_input_dev_ptr=&acerhk_input_dev; +#endif + + /* some laptops have a mail led, should I announce it here? */ + acerhk_input_dev_ptr->evbit[0] = BIT(EV_KEY); + /* announce keys to input system + * the generated keys can be changed on runtime, + * but to publish those changes the device needs to + * get reconnected (I dont't know any other way) + * Therefore I enable all possible keys */ + for (i = KEY_RESERVED; i < BTN_MISC; i++) + set_bit(i, acerhk_input_dev_ptr->keybit); + /* set mapping keyname -> input event */ + init_keymap_input(); + if (verbose) + printk(KERN_INFO"acerhk: registered input device\n"); + input_register_device(acerhk_input_dev_ptr); + init_timer(&acerhk_timer_poll); + acerhk_polling_state = 0; +} + +static void stop_polling(void) +{ + if (acerhk_polling_state == 1) { + del_timer(&acerhk_timer_poll); + if (verbose) + printk(KERN_INFO"acerhk: key polling stopped\n"); + acerhk_polling_state = 0; + } else + if (verbose) + printk(KERN_INFO"acerhk: key polling not active\n"); +} + +static void start_polling(void) +{ + if (acerhk_polling_state != 1) { + acerhk_timer_poll.function = acerhk_poll_event; + acerhk_timer_poll.expires = jiffies + acerhk_polling_delay; + acerhk_timer_poll.data = get_nr_events(); + add_timer(&acerhk_timer_poll); + acerhk_polling_state = 1; + if (acerhk_type == TM_dritek) { + printk(KERN_INFO"acerhk: Your hardware does not need polling enabled for hotkeys to work, " + "you can safely disable polling by using the module parameter poll=0 (unless you " + "want to play around with the driver and see if there are buttons which need polling).\n"); + } + if (verbose) + printk(KERN_INFO"acerhk: starting key polling, every %d ms\n", acerhk_polling_delay); + } else + if (verbose) + printk(KERN_INFO"acerhk: key polling already active\n"); +} + +/* addedd by Antonio Cuni */ +static void start_blinking(void) +{ + if (acerhk_blueled_blinking == -1) { + // blinking was disabled... enable it! + acerhk_timer_blinking.function = acerhk_blink_event; + acerhk_timer_blinking.expires = jiffies + acerhk_blueled_blinking_delay; + acerhk_timer_blinking.data = 0; // not used + add_timer(&acerhk_timer_blinking); + acerhk_blueled_blinking = 0; + if (verbose) + printk(KERN_INFO "acerhk: starting blueled blinking\n"); + } else + if (verbose) + printk(KERN_INFO "acerhk: blueled already blinking\n"); +} + +/* Added by Antonio Cuni */ +static void stop_blinking(void) +{ + if (acerhk_blueled_blinking != -1) { + del_timer(&acerhk_timer_blinking); + if (verbose) + printk(KERN_INFO "acerhk: blueled blinking stopped\n"); + acerhk_blueled_blinking = -1; + } +} + +static void release_input(void) +{ + stop_polling(); + input_unregister_device(acerhk_input_dev_ptr); +} + +/* }}} */ + +/* {{{ procfs functions */ + +#ifndef CONFIG_PROC_FS + +static int acerhk_proc_init(void) +{ + return 1; +} +#else + +/* This macro frees the machine specific function from bounds checking and + * things like that... */ +#define PRINT_PROC(fmt,args...) \ + do { \ + *len += sprintf( buffer+*len, fmt, ##args ); \ + if (*begin + *len > offset + size) \ + return( 0 ); \ + if (*begin + *len < offset) { \ + *begin += *len; \ + *len = 0; \ + } \ + } while(0) + +static int pc_proc_infos( char *buffer, int *len, + off_t *begin, off_t offset, int size ) +{ + PRINT_PROC( "Acer hotkeys version %s\n", ACERHK_VERSION); + PRINT_PROC( "Model(Type)\t: %s(", acerhk_model_string); + switch(acerhk_type) { + default: + PRINT_PROC( "unknown)\n"); + break; + case TM_old: + PRINT_PROC( "old)\n"); + break; + case TM_new: + PRINT_PROC( "new)\n"); + break; + case TM_dritek: + PRINT_PROC( "Dritek)\n"); + break; + } + if (bios_routine != 0) { + PRINT_PROC( "request handler\t: 0x%x\n", bios_routine); + if (cmos_index) { + PRINT_PROC( "CMOS index\t: 0x%x\n", cmos_index); + PRINT_PROC( "events pending\t: %u\n", get_nr_events()); + } else { + PRINT_PROC( "CMOS index\t: not available\n"); + } + if (acerhk_polling_state == 1) + PRINT_PROC( "kernel polling\t: active\n"); + else + PRINT_PROC( "kernel polling\t: inactive\n"); + PRINT_PROC( "autoswitch wlan\t: "); + if (autowlan == 1) + PRINT_PROC( "enabled\n"); + else + PRINT_PROC( "disabled\n"); + } else { + PRINT_PROC( "request handler\t: not found\n"); + PRINT_PROC( "kernel polling\t: not possible\n"); + } + /* model specific infos */ + if (acerhk_type == TM_dritek) { + PRINT_PROC( "use of Dritek EC: "); + if (usedritek) + PRINT_PROC( "enabled\n"); + else + PRINT_PROC( "disabled\n"); + } + if (acerhk_type == TM_old) + PRINT_PROC( "preg400\t\t: 0x%p\n", preg400); + return (1); +} + +static int acerhk_proc_info( char *buffer, char **start, off_t offset, + int size, int *eof, void *data ) +{ + int len = 0; + off_t begin = 0; + + *eof = pc_proc_infos( buffer, &len, &begin, offset, size ); + + if (offset >= begin + len) + return( 0 ); + *start = buffer + (offset - begin); + return( size < begin + len - offset ? size : begin + len - offset ); + +} + +static int acerhk_proc_key( char *buffer, char **start, off_t offset, + int size, int *eof, void *data ) +{ + if (size >= 5 && offset == 0) { + if (acerhk_type == TM_dritek || acerhk_polling_state == 1) { + snprintf(buffer+offset, size, "n/a\n"); + } else { + snprintf(buffer+offset, size, "0x%02x\n", filter_idle_value(get_fnkey_event())); + } + *eof = 1; + return 5; + } + *eof = 1; + return 0; +} + +static int acerhk_proc_led(struct file* file, const char* buffer, + unsigned long count, void* data) +{ + char str[4]; + int len; + if (count > 4) + len = 4; + else + len = count; + if (copy_from_user(str, buffer, len)) + return -EFAULT; + str[3] = '\0'; + if ( ( (len >= 2) && (!strncmp(str, "on", 2) || !strncmp(str, "an", 2)) ) + || str[0] == '1') + set_mail_led(1); + else + set_mail_led(0); + return len; +} + +static int acerhk_proc_wirelessled(struct file* file, const char* buffer, + unsigned long count, void* data) +{ + char str[4]; + int len; + if (count > 4) + len = 4; + else + len = count; + if (copy_from_user(str, buffer, len)) + return -EFAULT; + str[3] = '\0'; + if ( ( (len >= 2) && (!strncmp(str, "on", 2) || !strncmp(str, "an", 2)) ) + || str[0] == '1') { + if (acerhk_model_features & TM_F_WLAN_EC1) + enable_wlan_ec_1(); + else if (acerhk_model_features & TM_F_WLAN_EC2) + enable_wlan_ec_2(); + else + wbutton_fct_2(1); + } + else { + if (acerhk_model_features & TM_F_WLAN_EC1) + disable_wlan_ec_1(); + else if (acerhk_model_features & TM_F_WLAN_EC2) + disable_wlan_ec_2(); + else + wbutton_fct_2(0); + } + return len; +} + + +/* Modified by Antonio Cuni: added support for blinking + possible values: + - off, 0: led always off + - on, an, 1: led alway on + - n (a number): led blinking; n is the delay between + two changes of state, in jiffies; n must + be > 50, to prevent the user from overloading + the kernel. + + */ +static int acerhk_proc_blueled(struct file* file, const char* buffer, + unsigned long count, void* data) +{ + const int MAXLEN=11; + char str[MAXLEN]; + int len; + int isNumber; + + if (count > MAXLEN) + len = MAXLEN; + else + len = count; + if (copy_from_user(str, buffer, len)) + return -EFAULT; + str[MAXLEN - 1] = '\0'; + + /* try to parse a number */ + isNumber = sscanf(str, "%u", &acerhk_blueled_blinking_delay); + /* if the delay is 0, turn off the led */ + if (isNumber && acerhk_blueled_blinking_delay != 0 && acerhk_blueled_blinking_delay != 1) { + if (acerhk_blueled_blinking_delay < 50) + printk(KERN_INFO"acerhk: blinking request rejected. The delay must be > 50.\n"); + else { + if (verbose) + printk(KERN_INFO"acerhk: blinking delay set to %u.\n", acerhk_blueled_blinking_delay); + start_blinking(); + } + } else if (acerhk_blueled_blinking_delay == 1 || !strncmp(str, "on", 2) || !strncmp(str, "an", 2)) { + stop_blinking(); + if (acerhk_model_features & TM_F_BLUE_EC1) + enable_bluetooth_ec_1(); + else if (acerhk_model_features & TM_F_BLUE_EC2) + enable_bluetooth_ec_2(); + else + wbutton_fct_1(1); + } else { + /* it's 0 or everything else */ + stop_blinking(); + if (acerhk_model_features & TM_F_BLUE_EC1) + disable_bluetooth_ec_1(); + else if (acerhk_model_features & TM_F_BLUE_EC2) + disable_bluetooth_ec_2(); + else + wbutton_fct_1(0); + } + return len; +} + +#ifdef ACERDEBUG +static void do_debug(const char* buffer, unsigned long len) +{ + unsigned int h, i; + switch (buffer[0]) { + case 'b': + /* test WLAN on TM 4001 */ + switch (buffer[1]) { + case '0': + disable_wlan_ec_1(); + break; + case '1': + default: + enable_wlan_ec_1(); + } + break; + case 'B': + /* test BLUETOOTH on TM 4001 */ + switch (buffer[1]) { + case '0': + disable_bluetooth_ec_1(); + break; + case '1': + default: + enable_bluetooth_ec_1(); + } + break; + case 'D': + /* test "DMM Function Enabled" entry of TM 4150/4650 */ + enable_dmm_function(); + break; + case 'i': + case '1': +#ifndef KERNEL26 + MOD_INC_USE_COUNT; +#endif + break; + case 'e': + switch (buffer[1]) { + case '1': + start_polling(); + break; + default: + stop_polling(); + } + break; + case 'k': + for (i = 0; i <= 255;i++) { + input_report_key(acerhk_input_dev_ptr, i, 1); + input_report_key(acerhk_input_dev_ptr, i, 0); + } + break; + case 'm': + /* set mapping key names -> input events */ + sscanf(&buffer[2],"%x", &i); + h = buffer[1] - '0' + 1; + printk("acerhk: key name %x maps to %x\n", h, i); + acerhk_name2event[h] = i; + break; + case 'M': + /* test mute LED on dritek hardware */ + switch (buffer[1]) { + case '0': + disable_mute_led_ec(); + break; + case '1': + default: + enable_mute_led_ec(); + } + break; + case 'p': + printk("acerhk: pbutton = 0x%x\n", pbutton_fct()); + break; + case 's': + /* send key event to test the key translation in input system */ + sscanf(&buffer[1],"%x", &h); + printk("acerhk: sending key event 0x%x\n", h); + input_report_key(acerhk_input_dev_ptr, h, 1); + input_report_key(acerhk_input_dev_ptr, h, 0); + break; + case 'S': + /* simulate key codes to test the key translation in acerhk */ + sscanf(&buffer[1],"%x", &h); + send_key_event(transl8_key_code(h)); + break; + case 't': + printk("acerhk: thermal event = 0x%x\n", get_thermal_event()); + break; + case 'w': + /* test the wbutton functions, someone really needs to have another look + at the windows driver */ + switch (buffer[1]) { + case '2': + printk("acerhk: wbutton_2(%d) = 0x%x\n", buffer[2]-'0', wbutton_fct_2(buffer[2]-'0')); + break; + case '1': + default: + printk("acerhk: wbutton_1(%d) = 0x%x\n", buffer[2]-'0', wbutton_fct_1(buffer[2]-'0')); + } + break; + case 'W': + /* test wireless HW/LED on some models using dritek hardware */ + switch (buffer[1]) { + case '0': + disable_wireless_ec(); + break; + case '1': + default: + enable_wireless_ec(); + } + break; + case 'v': + verbose = buffer[1]-'0'; + printk("acerhk: verbosity level changed to %d\n", verbose); + break; + case 'd': + case '0': + default: +#ifndef KERNEL26 + MOD_DEC_USE_COUNT; +#endif + break; + } +} + +static int acerhk_proc_debug(struct file* file, const char* buffer, + unsigned long count, void* data) +{ + char str[5]; + int len; + if (count > 5) + len = 5; + else + len = count; + if (copy_from_user(str, buffer, len)) + return -EFAULT; + str[4] = '\0'; + do_debug(str, len); + return len; +} +#endif + +static int acerhk_proc_init(void) +{ + int retval; + struct proc_dir_entry *entry; + /* create own directory */ + proc_acer_dir = proc_mkdir("driver/acerhk", NULL); + if (proc_acer_dir == NULL) { + retval = 0; + printk(KERN_INFO"acerhk: could not create /proc/driver/acerhk\n"); + } + else { + proc_acer_dir->owner = THIS_MODULE; + /* now create several files, first general info ... */ + entry = create_proc_read_entry("info", + 0444, proc_acer_dir, acerhk_proc_info, NULL); + if (entry == NULL) { + printk(KERN_INFO"acerhk: cannot create info file\n"); + remove_proc_entry("driver/acerhk", NULL); + retval = 0; + } else { + entry->owner = THIS_MODULE; + /* ... last pressed key ... */ + entry = create_proc_read_entry("key", + 0444, proc_acer_dir, acerhk_proc_key, NULL); + if (entry == NULL) { + printk(KERN_INFO"acerhk: cannot create key file\n"); + remove_proc_entry("info", proc_acer_dir); + remove_proc_entry("driver/acerhk", NULL); + retval = 0; + } else { + entry->owner = THIS_MODULE; + /* ... and led control file */ + entry = create_proc_entry("led", 0222, proc_acer_dir); + if (entry == NULL) { + printk(KERN_INFO"acerhk: cannot create LED file\n"); + remove_proc_entry("info", proc_acer_dir); + remove_proc_entry("key", proc_acer_dir); + remove_proc_entry("driver/acerhk", NULL); + retval = 0; + } + else { + entry->write_proc = acerhk_proc_led; + entry->owner = THIS_MODULE; + /* ... and wireless led controll file */ + entry = create_proc_entry("wirelessled", 0222, proc_acer_dir); + if (entry == NULL) { + printk(KERN_INFO"acerhk: cannot create wirelessled file\n"); + remove_proc_entry("info", proc_acer_dir); + remove_proc_entry("key", proc_acer_dir); + remove_proc_entry("led", proc_acer_dir); + remove_proc_entry("driver/acerhk", NULL); + retval = 0; + } + else { + entry->write_proc = acerhk_proc_wirelessled; + entry->owner = THIS_MODULE; + /* ... and bluetooth led controll file */ + entry = create_proc_entry("blueled", 0222, proc_acer_dir); + if (entry == NULL) { + printk(KERN_INFO"acerhk: cannot create blueled file\n"); + remove_proc_entry("info", proc_acer_dir); + remove_proc_entry("key", proc_acer_dir); + remove_proc_entry("led", proc_acer_dir); + remove_proc_entry("wirelessled", proc_acer_dir); + remove_proc_entry("driver/acerhk", NULL); + retval = 0; + } else { + entry->write_proc = acerhk_proc_blueled; + entry->owner = THIS_MODULE; + retval = 1; +#ifdef ACERDEBUG + /* add extra file for debugging purposes */ + entry = create_proc_entry("debug", 0222, proc_acer_dir); + if (entry == NULL) { + printk(KERN_INFO"acerhk: cannot create debug file\n"); + remove_proc_entry("info", proc_acer_dir); + remove_proc_entry("key", proc_acer_dir); + remove_proc_entry("led", proc_acer_dir); + remove_proc_entry("wirelessled", proc_acer_dir); + remove_proc_entry("blueled", proc_acer_dir); + remove_proc_entry("driver/acerhk", NULL); + retval = 0; + } + else { + entry->write_proc = acerhk_proc_debug; + entry->owner = THIS_MODULE; + retval = 1; + } +#endif + } + } + } + } + } + } + return retval; +} + +static void acerhk_proc_cleanup(void) +{ + if (proc_acer_dir) { + remove_proc_entry("info", proc_acer_dir); + /* On dritek type hardware key file is already removed */ + if (acerhk_type != TM_dritek) + remove_proc_entry("key", proc_acer_dir); + remove_proc_entry("led", proc_acer_dir); + remove_proc_entry("wirelessled", proc_acer_dir); + remove_proc_entry("blueled", proc_acer_dir); +#ifdef ACERDEBUG + remove_proc_entry("debug", proc_acer_dir); +#endif + remove_proc_entry("driver/acerhk", NULL); + proc_acer_dir = NULL; + } +} + +#endif /* CONFIG_PROC_FS */ + +/* }}} */ + +/* {{{ file operations */ + +static int acerhk_ioctl( struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg ) +{ + int retval; + switch( cmd ) { + case ACERHK_GET_KEYCOUNT: + { + char nr; + nr = get_nr_events(); + put_user(nr, (char*)arg); + retval = 0; + break; + } + case ACERHK_GET_KEYID: + { + char id; + id = get_fnkey_event(); + put_user(id, (char*)arg); + retval = 0; + break; + } + case ACERHK_CONNECT: + launch_connect(1); + retval = 0; + break; + case ACERHK_START_POLLING: + start_polling(); + retval = 0; + break; + case ACERHK_STOP_POLLING: + stop_polling(); + retval = 0; + break; + case ACERHK_DISCONNECT: + launch_connect(0); + retval = 0; + break; + case ACERHK_GET_THERMAL_EVENT: + { + short event; + event = get_thermal_event(); + put_user(event, (short*)arg); + retval = 0; + break; + } + case ACERHK_MAIL_LED_OFF: + set_mail_led(0); + retval = 0; + break; + case ACERHK_MAIL_LED_ON: + set_mail_led(1); + retval = 0; + break; + case ACERHK_GET_KEY_MAP: + if (copy_to_user((t_map_name2event*)arg, &acerhk_name2event, sizeof(acerhk_name2event))) + retval = -EFAULT; + else + retval = 0; + break; + case ACERHK_SET_KEY_MAP: + if (copy_from_user(&acerhk_name2event, (t_map_name2event*)arg, sizeof(acerhk_name2event))) + retval = -EFAULT; + else { + if (verbose) { + printk(KERN_INFO"acerhk: changed key mapping\n"); + print_mapping(); + } + retval = 0; + } + break; + default: + retval = -EINVAL; + } + return retval; +} + +#ifdef ACERDEBUG +static ssize_t acerhk_write (struct file* file, const char* buffer, size_t length, loff_t* offset) +{ + if (length) + do_debug(buffer, length); + return length; +} +#endif + +static int acerhk_open( struct inode *inode, struct file *file ) +{ + return 0; +} + +static int acerhk_release( struct inode *inode, struct file *file ) +{ + return 0; +} + +static struct file_operations acerhk_fops = { + owner: THIS_MODULE, + ioctl: acerhk_ioctl, + open: acerhk_open, +#ifdef ACERDEBUG + write: acerhk_write, +#endif + release: acerhk_release, +}; + +static struct miscdevice acerhk_dev = { + MISC_DYNAMIC_MINOR, + "acerhk", + &acerhk_fops +}; + +/* }}} */ + +static void __init model_init(void) +{ + /* set callroutine, features and keymap for model */ + setup_model_features(acerhk_series); + /* override initial state of wireless hardware if specified by module options */ + if (wlan_state >= 0) acerhk_wlan_state = wlan_state; + if (bluetooth_state >= 0) acerhk_bluetooth_state = bluetooth_state; + /* Launch connect only if available */ + if (acerhk_model_features & TM_F_CONNECT) { + if (verbose) + printk(KERN_INFO"acerhk: Model type %d, calling launch_connect(1)\n", + acerhk_type); + launch_connect(1); + } + if ( acerhk_type != TM_dritek ) { + get_cmos_index(); + } + if ( acerhk_type == TM_dritek ) { + enable_dritek_keyboard(); + } + /* added by Antonio Cuni */ + init_timer(&acerhk_timer_blinking); +} + + +static void __exit acerhk_cleanup_module (void); +static int __init acerhk_init(void) +{ + int ret; + + ret = misc_register( &acerhk_dev ); + if (ret) { + printk(KERN_ERR "acerhk: can't misc_register on minor=%d\n", ACERHK_MINOR); + ret = -EAGAIN; + } + else if (!acerhk_proc_init()) { + printk(KERN_ERR "acerhk: can't create procfs entries\n"); + ret = -ENOMEM; + misc_deregister( &acerhk_dev ); + } + else { + reg1 = ioremap(0xf0000, 0xffff); + if (verbose > 1) + printk(KERN_INFO"acerhk: area from 0xf000 to 0xffff mapped to %p\n", reg1); + reg2 = ioremap(0xe0000, 0xffff); + if (verbose > 1) + printk(KERN_INFO"acerhk: area from 0xe000 to 0xffff mapped to %p\n", reg2); + /* the area 0x400 is used as data area by earlier (520) series */ + preg400 = ioremap(0x400, 0xfff); + if (verbose > 1) + printk(KERN_INFO"acerhk: area from 0x400 to 0x13ff mapped to %p\n", preg400); + /* attach to input system */ + init_input(); + memset(acerhk_model_string, 0x00, ACERHK_MODEL_STRLEN); +#ifdef DUMMYHW + acerhk_model_addr = (void*)0x12345678; + /* copy the string, but not more than 15 characters */ + strncpy(acerhk_model_string, "TravelmateDummy", ACERHK_MODEL_STRLEN-1); + /* set callroutine for model */ + if (force_series) + acerhk_series = force_series; + else + acerhk_series = 2000; + setup_model_features(acerhk_series); + printk(KERN_INFO "Acer Travelmate hotkey driver v" ACERHK_VERSION " dummy\n"); + if ( acerhk_type == TM_dritek ) + enable_dritek_keyboard(); + if (poll) + start_polling(); + init_timer(&acerhk_timer_blinking); +#else + bios_routine = find_hk_area(); + if (!force_series) + probe_model(); + else { + if (verbose) + printk(KERN_INFO"acerhk: forced laptop series to %d\n", force_series); + acerhk_series = force_series; + } + /* do model specific initialization */ + model_init(); + /* Without a bios routine we cannot do anything except on dritek + type HW, unload on other types */ + if (bios_routine || (acerhk_type == TM_dritek)) { + ret = 0; + if (verbose && bios_routine) + printk(KERN_INFO"acerhk: bios routine found at 0x%x\n", bios_routine); + printk(KERN_INFO "Acer Travelmate hotkey driver v" ACERHK_VERSION "\n"); + /* If automatic switching of wlan is wanted but polling is disabled, + automatically enable it */ + if (!poll && autowlan) { + printk(KERN_INFO "Automatic switching of wireless hardware needs polling, enabling it\n"); + poll = 1; + } + /* start automatic polling of key presses if wanted and bios routine found */ + if (poll && bios_routine) + start_polling(); + } else { + printk(KERN_ERR "acerhk: can't find bios routine, cannot do anything for you, sorry!\n"); + ret = -ENOMEM; + acerhk_cleanup_module(); + } +#endif + } + return ret; +} + +static void __exit acerhk_cleanup_module (void) +{ + acerhk_proc_cleanup(); + stop_blinking(); + if (reg1) + iounmap(reg1); + if (reg2) + iounmap(reg2); + if (preg400) + iounmap(preg400); + release_input(); + misc_deregister( &acerhk_dev ); + if ( acerhk_type == TM_dritek ) { + disable_dritek_keyboard(); + } + if (verbose > 2) + printk(KERN_INFO "acerhk: unloaded\n"); +} + +module_init(acerhk_init); +module_exit(acerhk_cleanup_module); + +MODULE_AUTHOR("Olaf Tauber"); +MODULE_DESCRIPTION("AcerHotkeys extra buttons keyboard driver"); +MODULE_LICENSE("GPL"); + +#ifndef KERNEL26 +EXPORT_NO_SYMBOLS; +#endif + +#else +#error This driver is only available for X86 architecture +#endif +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 4 + * End: + */ + --- linux-2.6.27.orig/ubuntu/misc/lmpcm_usb.c +++ linux-2.6.27/ubuntu/misc/lmpcm_usb.c @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2004-2005 David Oliveira + * + * USB Logitech MediaPlay Cordless Mouse driver + * + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * If you need to contact me, you can do it by e-mail, sending a mail + * message to + */ + +#include +#include +#include +#include +#include +#include + +#ifdef BIT +#undef BIT +#endif +#define BIT(x) (1UL<<((x)%BITS_PER_LONG)) +#define LONG(x) ((x)/BITS_PER_LONG) + +#define DRIVER_VERSION "v0.5.5" +#define DRIVER_AUTHOR "David Oliveira " +#define DRIVER_DESC "USB Logitech MediaPlay Cordless Mouse driver" +#define DRIVER_LICENSE "GPL" + +#define GETBIT(v,n) ((v>>(n))&0x01) +#define SETBIT(v,n) (v |= (0x01<<(n))) + +#ifdef SLAB_ATOMIC +# define ATOMIC SLAB_ATOMIC +#else +# define ATOMIC GFP_ATOMIC +#endif + + +/* Module properties */ + +MODULE_AUTHOR ( DRIVER_AUTHOR ); +MODULE_DESCRIPTION ( DRIVER_DESC ); +MODULE_LICENSE ( DRIVER_LICENSE ); + + +/* Own type */ + +typedef struct usb_lmpcm { + + // Device name + + char name[128]; + + // USB interrupt data + + signed char *data; + + char phys[64]; + + dma_addr_t data_dma; + + // USB device + + struct usb_device *usbdev; + + // Input device + + struct input_dev *inputdev; + + // USB Request block + + struct urb *urb; + + // Number of openned times + + int open; + +} lmpcm_t; + + +// Initialize lmpcm structure + +void lmpcm_init ( lmpcm_t *lmpcm ) { + + memset(lmpcm, 0, sizeof(lmpcm_t)); + lmpcm->inputdev = NULL; + lmpcm->urb = NULL; + lmpcm->data = NULL; + +} + + +// Free lmpcm buffers + +void lmpcm_free ( lmpcm_t *lmpcm ) { + + if ( lmpcm->urb ) + usb_free_urb(lmpcm->urb); + + if ( lmpcm->data ) + usb_buffer_free(lmpcm->usbdev,8,lmpcm->data,lmpcm->data_dma); + + kfree(lmpcm); + +} + + +// Create new lmpcm (buffer allocation + +lmpcm_t *lmpcm_new ( struct usb_device *dev ) { + + lmpcm_t *lmpcm; + + // Create object + + if (!(lmpcm = kmalloc(sizeof(lmpcm_t), GFP_KERNEL))) + return NULL; + + // Initialize + + lmpcm_init(lmpcm); + + + // Input device + + if ( (lmpcm->inputdev = input_allocate_device()) == NULL ) { + lmpcm_free(lmpcm); + return NULL; + } + + + // Create urb handler + + if (!(lmpcm->urb = usb_alloc_urb(0, GFP_KERNEL))) { + lmpcm_free(lmpcm); + return NULL; + } + + + // Create data required for urb transfer + + if (!(lmpcm->data = usb_buffer_alloc(dev,8,ATOMIC,&lmpcm->data_dma))) { + lmpcm_free(lmpcm); + return NULL; + } + + + // Set lmpcm usb device + + lmpcm->usbdev = dev; + + + return lmpcm; + +} + + + + + +// Get data from urb and send to input API + +void input_send_data ( struct input_dev *dev, char *data ) { + + char + btn = data[0], // Basic buttons (left, right, middle, side and extra) + mbtn = data[6], // Media buttons + x = data[1], // X movement + y = data[2], // Y movement + w = data[3]; // Wheel movement + + + input_report_key(dev, BTN_LEFT, GETBIT(btn,0)); + input_report_key(dev, BTN_RIGHT, GETBIT(btn,1)); + input_report_key(dev, BTN_MIDDLE, GETBIT(btn,2)); + input_report_key(dev, BTN_SIDE, GETBIT(btn,3)); + input_report_key(dev, BTN_EXTRA, GETBIT(btn,4)); + input_report_key(dev, KEY_PLAYCD, GETBIT(btn,5)); + input_report_key(dev, KEY_BACK, GETBIT(btn,6)); + input_report_key(dev, KEY_FORWARD, GETBIT(btn,7)); + + input_report_key(dev, KEY_VOLUMEUP, GETBIT(mbtn,0)); + input_report_key(dev, KEY_VOLUMEDOWN, GETBIT(mbtn,1)); + input_report_key(dev, KEY_NEXTSONG, GETBIT(mbtn,2)); + input_report_key(dev, KEY_PREVIOUSSONG, GETBIT(mbtn,3)); + input_report_key(dev, KEY_PLAYPAUSE, GETBIT(mbtn,4)); + + input_report_rel(dev, REL_X, x); + input_report_rel(dev, REL_Y, y); + input_report_rel(dev, REL_WHEEL, w); + +} + +static void usb_lmpcm_handle(struct urb *urb) { + + lmpcm_t *mouse = urb->context; + signed char *data = mouse->data; + struct input_dev *inputdev = mouse->inputdev; + + + // Check returned status + + if (urb->status) return ; + + + // Send data to input interface + + input_send_data(inputdev,data); + + input_sync(inputdev); + usb_submit_urb(urb,ATOMIC); + +} + +static int usb_lmpcm_open(struct input_dev *dev) { + + lmpcm_t *mouse = (lmpcm_t *)input_get_drvdata(dev); + + if (mouse->open++) + return 0; + + mouse->urb->dev = mouse->usbdev; + + if (usb_submit_urb(mouse->urb, GFP_KERNEL)) { + mouse->open--; + return -EIO; + } + + return 0; + +} + +static void usb_lmpcm_close(struct input_dev *dev) { + + lmpcm_t *mouse = (lmpcm_t *)input_get_drvdata(dev); + + if (!--mouse->open) + usb_kill_urb(mouse->urb); + +} + +static void input_device_init ( struct input_dev *inputdev, struct usb_interface *intf, void *private, struct usb_device *dev ) { + + char path[64]; + + lmpcm_t *mouse = (lmpcm_t *) private; + + int + x, + keys[] = { KEY_PLAYPAUSE, KEY_BACK, KEY_FORWARD, KEY_PLAYCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, + KEY_NEXTSONG, KEY_PREVIOUSSONG, 0 }; + + + // Events + + inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + + // Add special keys + + for ( x = 0 ; keys[x] ; x++ ) + set_bit(keys[x],inputdev->keybit); + + // Add basic buttons + + inputdev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | + BIT(BTN_SIDE) | BIT(BTN_EXTRA); + + // Add move mouse movement (X/Y) + + inputdev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + + // Add wheel + + inputdev->relbit[0] |= BIT(REL_WHEEL); + + + // Private data structure + + input_set_drvdata(inputdev, mouse); + + // Input file operations + + inputdev->open = usb_lmpcm_open; + inputdev->close = usb_lmpcm_close; + + // Device + + inputdev->name = mouse->name; + + usb_make_path(dev,path,64); + snprintf(mouse->phys,64,"%s/input0",path); + + inputdev->phys = mouse->phys; + inputdev->id.bustype = BUS_USB; + inputdev->id.vendor = dev->descriptor.idVendor; + inputdev->id.product = dev->descriptor.idProduct; + inputdev->id.version = dev->descriptor.bcdDevice; + +} + +static int usb_lmpcm_probe(struct usb_interface *intf, const struct usb_device_id *id) { + + struct usb_device *dev = interface_to_usbdev(intf); + struct usb_host_interface *interface; + + + struct usb_endpoint_descriptor *endpoint; + lmpcm_t *mouse; + int pipe, maxp; + char *buf; + + + // Get mouse endpoint + + interface = intf->cur_altsetting; + + if ( interface->desc.bNumEndpoints != 1 ) return -ENODEV; + endpoint = &interface->endpoint[0].desc; + + + // Check endpoint + + if (!(endpoint->bEndpointAddress & USB_DIR_IN)) + return -ENODEV; + + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) + return -ENODEV; + + + // Create endpoint pipe + + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); + maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + + + // Create lmpcm object + + if (!(mouse = lmpcm_new(dev))) + return -ENOMEM; + + // Initialize input device + + input_device_init(mouse->inputdev,intf,mouse,dev); + + + // Set device name + + if (!(buf = kmalloc(63, GFP_KERNEL))) { + lmpcm_free(mouse); + return -ENOMEM; + } + + + if (dev->descriptor.iManufacturer && + usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0) + strcat(mouse->name, buf); + + if (dev->descriptor.iProduct && + usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0) + sprintf(mouse->name, "%s %s", mouse->name, buf); + + if (!strlen(mouse->name)) + sprintf(mouse->name, "lmpcm_usb.c: Logitech MediaPlay Mouse on usb%04x:%04x", + mouse->inputdev->id.vendor, mouse->inputdev->id.product); + + kfree(buf); + + + // Initialize interrupt transfer + + usb_fill_int_urb(mouse->urb,dev,pipe,mouse->data,((maxp > 8)?8:maxp),usb_lmpcm_handle,mouse,endpoint->bInterval); + mouse->urb->transfer_dma = mouse->data_dma; + mouse->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + + // Register input device + + input_register_device(mouse->inputdev); + + + printk(KERN_INFO "lmpcm_usb.c: Detected device: %s\n", mouse->name); + + // Set usb handler interface data + + usb_set_intfdata(intf,mouse); + + + return 0; + +} + + +static void usb_lmpcm_disconnect(struct usb_interface *intf) { + + lmpcm_t *mouse = usb_get_intfdata(intf); + + usb_set_intfdata(intf,NULL); + if (mouse) { + usb_kill_urb(mouse->urb); + input_unregister_device(mouse->inputdev); + lmpcm_free(mouse); + } + +} + + + + +/* Module structures */ + +static struct usb_device_id usb_lmpcm_id_table [] = { + { USB_DEVICE(0x46d, 0xc50e) }, + { } +}; + +MODULE_DEVICE_TABLE (usb, usb_lmpcm_id_table); + +static struct usb_driver usb_lmpcm_driver = { + + .name = "lmpcm_usb", + .probe = usb_lmpcm_probe, + .disconnect = usb_lmpcm_disconnect, + .id_table = usb_lmpcm_id_table + +}; + + + +/* Module main functions */ + +static int __init usb_lmpcm_init(void) { + + int rv; + + // Register usb driver + + rv = usb_register(&usb_lmpcm_driver); + + info(DRIVER_VERSION ":" DRIVER_DESC); + + return rv; +} + +static void __exit usb_lmpcm_exit(void) { + + usb_deregister(&usb_lmpcm_driver); + +} + +// Set + +module_init(usb_lmpcm_init); +module_exit(usb_lmpcm_exit); --- linux-2.6.27.orig/ubuntu/misc/thinkpad_ec.c +++ linux-2.6.27/ubuntu/misc/thinkpad_ec.c @@ -0,0 +1,489 @@ +/* + * thinkpad_ec.c - ThinkPad embedded controller LPC3 functions + * + * The embedded controller on ThinkPad laptops has a non-standard interface, + * where LPC channel 3 of the H8S EC chip is hooked up to IO ports + * 0x1600-0x161F and implements (a special case of) the H8S LPC protocol. + * The EC LPC interface provides various system management services (currently + * known: battery information and accelerometer readouts). This driver + * provides access and mutual exclusion for the EC interface. +* + * The LPC protocol and terminology is documented here: + * "H8S/2104B Group Hardware Manual", + * http://documentation.renesas.com/eng/products/mpumcu/rej09b0300_2140bhm.pdf + * + * Copyright (C) 2006-2007 Shem Multinymous + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include "thinkpad_ec.h" +#include +#include +#include + +#define TP_VERSION "0.37" + +MODULE_AUTHOR("Shem Multinymous"); +MODULE_DESCRIPTION("ThinkPad embedded controller hardware access"); +MODULE_VERSION(TP_VERSION); +MODULE_LICENSE("GPL"); + +/* IO ports used by embedded controller LPC channel 3: */ +#define TPC_BASE_PORT 0x1600 +#define TPC_NUM_PORTS 0x20 +#define TPC_STR3_PORT 0x1604 /* Reads H8S EC register STR3 */ +#define TPC_TWR0_PORT 0x1610 /* Mapped to H8S EC register TWR0MW/SW */ +#define TPC_TWR15_PORT 0x161F /* Mapped to H8S EC register TWR15. */ + /* (and port TPC_TWR0_PORT+i is mapped to H8S reg TWRi for 00x%02x", \ + msg, args->val[0x0], args->val[0xF], code) + +/* State of request prefetching: */ +static u8 prefetch_arg0, prefetch_argF; /* Args of last prefetch */ +static u64 prefetch_jiffies; /* time of prefetch, or: */ +#define TPC_PREFETCH_NONE INITIAL_JIFFIES /* No prefetch */ +#define TPC_PREFETCH_JUNK (INITIAL_JIFFIES+1) /* Ignore prefetch */ + +/* Locking: */ + +static DECLARE_MUTEX(thinkpad_ec_mutex); + +/** + * thinkpad_ec_lock - get lock on the ThinkPad EC + * + * Get exclusive lock for accesing the ThinkPad embedded controller LPC3 + * interface. Returns 0 iff lock acquired. + */ +int thinkpad_ec_lock(void) +{ + int ret; + ret = down_interruptible(&thinkpad_ec_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(thinkpad_ec_lock); + +/** + * thinkpad_ec_try_lock - try getting lock on the ThinkPad EC + * + * Try getting an exclusive lock for accesing the ThinkPad embedded + * controller LPC3. Returns immediately if lock is not available; neither + * blocks nor sleeps. Returns 0 iff lock acquired . + */ +int thinkpad_ec_try_lock(void) +{ + return down_trylock(&thinkpad_ec_mutex); +} +EXPORT_SYMBOL_GPL(thinkpad_ec_try_lock); + +/** + * thinkpad_ec_unlock - release lock on ThinkPad EC + * + * Release a previously acquired exclusive lock on the ThinkPad ebmedded + * controller LPC3 interface. + */ +void thinkpad_ec_unlock(void) +{ + up(&thinkpad_ec_mutex); +} +EXPORT_SYMBOL_GPL(thinkpad_ec_unlock); + +/** + * thinkpad_ec_request_row - tell embedded controller to prepare a row + * @args Input register arguments + * + * Requests a data row by writing to H8S LPC registers TRW0 through TWR15 (or + * a subset thereof) following the protocol prescribed by the "H8S/2104B Group + * Hardware Manual". Does sanity checks via status register STR3. + */ +static int thinkpad_ec_request_row(const struct thinkpad_ec_row *args) +{ + u8 str3; + int i; + + /* EC protocol requires write to TWR0 (function code): */ + if (!(args->mask & 0x0001)) { + printk(KERN_ERR MSG_FMT("bad args->mask=0x%02x", args->mask)); + return -EINVAL; + } + + /* Check initial STR3 status: */ + str3 = inb(TPC_STR3_PORT) & H8S_STR3_MASK; + if (str3 & H8S_STR3_OBF3B) { /* data already pending */ + inb(TPC_TWR15_PORT); /* marks end of previous transaction */ + if (prefetch_jiffies == TPC_PREFETCH_NONE) + printk(KERN_WARNING REQ_FMT( + "EC has result from unrequested transaction", + str3)); + return -EBUSY; /* EC will be ready in a few usecs */ + } else if (str3 == H8S_STR3_SWMF) { /* busy with previous request */ + if (prefetch_jiffies == TPC_PREFETCH_NONE) + printk(KERN_WARNING REQ_FMT( + "EC is busy with unrequested transaction", + str3)); + return -EBUSY; /* data will be pending in a few usecs */ + } else if (str3 != 0x00) { /* unexpected status? */ + printk(KERN_WARNING REQ_FMT("unexpected initial STR3", str3)); + return -EIO; + } + + /* Send TWR0MW: */ + outb(args->val[0], TPC_TWR0_PORT); + str3 = inb(TPC_STR3_PORT) & H8S_STR3_MASK; + if (str3 != H8S_STR3_MWMF) { /* not accepted? */ + printk(KERN_WARNING REQ_FMT("arg0 rejected", str3)); + return -EIO; + } + + /* Send TWR1 through TWR14: */ + for (i = 1; i < TP_CONTROLLER_ROW_LEN-1; i++) + if ((args->mask>>i)&1) + outb(args->val[i], TPC_TWR0_PORT+i); + + /* Send TWR15 (default to 0x01). This marks end of command. */ + outb((args->mask & 0x8000) ? args->val[0xF] : 0x01, TPC_TWR15_PORT); + + /* Wait until EC starts writing its reply (~60ns on average). + * Releasing locks before this happens may cause an EC hang + * due to firmware bug! + */ + for (i = 0; i < TPC_REQUEST_RETRIES; i++) { + str3 = inb(TPC_STR3_PORT) & H8S_STR3_MASK; + if (str3 & H8S_STR3_SWMF) /* EC started replying */ + return 0; + else if (!(str3 & ~(H8S_STR3_IBF3B|H8S_STR3_MWMF))) + /* Normal progress (the EC hasn't seen the request + * yet, or is processing it). Wait it out. */ + ndelay(TPC_REQUEST_NDELAY); + else { /* weird EC status */ + printk(KERN_WARNING + REQ_FMT("bad end STR3", str3)); + return -EIO; + } + } + printk(KERN_WARNING REQ_FMT("EC is mysteriously silent", str3)); + return -EIO; +} + +/** + * thinkpad_ec_read_data - read pre-requested row-data from EC + * @args Input register arguments of pre-requested rows + * @data Output register values + * + * Reads current row data from the controller, assuming it's already + * requested. Follows the H8S spec for register access and status checks. + */ +static int thinkpad_ec_read_data(const struct thinkpad_ec_row *args, + struct thinkpad_ec_row *data) +{ + int i; + u8 str3 = inb(TPC_STR3_PORT) & H8S_STR3_MASK; + /* Once we make a request, STR3 assumes the sequence of values listed + * in the following 'if' as it reads the request and writes its data. + * It takes about a few dozen nanosecs total, with very high variance. + */ + if (str3 == (H8S_STR3_IBF3B|H8S_STR3_MWMF) || + str3 == 0x00 || /* the 0x00 is indistinguishable from idle EC! */ + str3 == H8S_STR3_SWMF) + return -EBUSY; /* not ready yet */ + /* Finally, the EC signals output buffer full: */ + if (str3 != (H8S_STR3_OBF3B|H8S_STR3_SWMF)) { + printk(KERN_WARNING + REQ_FMT("bad initial STR3", str3)); + return -EIO; + } + + /* Read first byte (signals start of read transactions): */ + data->val[0] = inb(TPC_TWR0_PORT); + /* Optionally read 14 more bytes: */ + for (i = 1; i < TP_CONTROLLER_ROW_LEN-1; i++) + if ((data->mask >> i)&1) + data->val[i] = inb(TPC_TWR0_PORT+i); + /* Read last byte from 0x161F (signals end of read transaction): */ + data->val[0xF] = inb(TPC_TWR15_PORT); + + /* Readout still pending? */ + str3 = inb(TPC_STR3_PORT) & H8S_STR3_MASK; + if (str3 & H8S_STR3_OBF3B) + printk(KERN_WARNING + REQ_FMT("OBF3B=1 after read", str3)); + /* If port 0x161F returns 0x80 too often, the EC may lock up. Warn: */ + if (data->val[0xF] == 0x80) + printk(KERN_WARNING + REQ_FMT("0x161F reports error", data->val[0xF])); + return 0; +} + +/** + * thinkpad_ec_is_row_fetched - is the given row currently prefetched? + * + * To keep things simple we compare only the first and last args; + * this suffices for all known cases. + */ +static int thinkpad_ec_is_row_fetched(const struct thinkpad_ec_row *args) +{ + return (prefetch_jiffies != TPC_PREFETCH_NONE) && + (prefetch_jiffies != TPC_PREFETCH_JUNK) && + (prefetch_arg0 == args->val[0]) && + (prefetch_argF == args->val[0xF]) && + (get_jiffies_64() < prefetch_jiffies + TPC_PREFETCH_TIMEOUT); +} + +/** + * thinkpad_ec_read_row - request and read data from ThinkPad EC + * @args Input register arguments + * @data Output register values + * + * Read a data row from the ThinkPad embedded controller LPC3 interface. + * Does fetching and retrying if needed. The row is specified by an + * array of 16 bytes, some of which may be undefined (but the first is + * mandatory). These bytes are given in @args->val[], where @args->val[i] is + * used iff (@args->mask>>i)&1). The resulting row data is stored in + * @data->val[], but is only guaranteed to be valid for indices corresponding + * to set bit in @data->mask. That is, if @data->mask&(1<val[i] is undefined. + * + * Returns -EBUSY on transient error and -EIO on abnormal condition. + * Caller must hold controller lock. + */ +int thinkpad_ec_read_row(const struct thinkpad_ec_row *args, + struct thinkpad_ec_row *data) +{ + int retries, ret; + + if (thinkpad_ec_is_row_fetched(args)) + goto read_row; /* already requested */ + + /* Request the row */ + for (retries = 0; retries < TPC_READ_RETRIES; ++retries) { + ret = thinkpad_ec_request_row(args); + if (!ret) + goto read_row; + if (ret != -EBUSY) + break; + ndelay(TPC_READ_NDELAY); + } + printk(KERN_ERR REQ_FMT("failed requesting row", ret)); + goto out; + +read_row: + /* Read the row's data */ + for (retries = 0; retries < TPC_READ_RETRIES; ++retries) { + ret = thinkpad_ec_read_data(args, data); + if (!ret) + goto out; + if (ret != -EBUSY) + break; + ndelay(TPC_READ_NDELAY); + } + + printk(KERN_ERR REQ_FMT("failed waiting for data", ret)); + +out: + prefetch_jiffies = TPC_PREFETCH_JUNK; + return ret; +} +EXPORT_SYMBOL_GPL(thinkpad_ec_read_row); + +/** + * thinkpad_ec_try_read_row - try reading prefetched data from ThinkPad EC + * @args Input register arguments + * @data Output register values + * + * Try reading a data row from the ThinkPad embedded controller LPC3 + * interface, if this raw was recently prefetched using + * thinkpad_ec_prefetch_row(). Does not fetch, retry or block. + * The parameters have the same meaning as in thinkpad_ec_read_row(). + * + * Returns -EBUSY is data not ready and -ENODATA if row not prefetched. + * Caller must hold controller lock. + */ +int thinkpad_ec_try_read_row(const struct thinkpad_ec_row *args, + struct thinkpad_ec_row *data) +{ + int ret; + if (!thinkpad_ec_is_row_fetched(args)) { + ret = -ENODATA; + } else { + ret = thinkpad_ec_read_data(args, data); + if (!ret) + prefetch_jiffies = TPC_PREFETCH_NONE; /* eaten up */ + } + return ret; +} +EXPORT_SYMBOL_GPL(thinkpad_ec_try_read_row); + +/** + * thinkpad_ec_prefetch_row - prefetch data from ThinkPad EC + * @args Input register arguments + * + * Prefetch a data row from the ThinkPad embedded controller LCP3 + * interface. A subsequent call to thinkpad_ec_read_row() with the + * same arguments will be faster, and a subsequent call to + * thinkpad_ec_try_read_row() stands a good chance of succeeding if + * done neither too soon nor too late. See + * thinkpad_ec_read_row() for the meaning of @args. + * + * Returns -EBUSY on transient error and -EIO on abnormal condition. + * Caller must hold controller lock. + */ +int thinkpad_ec_prefetch_row(const struct thinkpad_ec_row *args) +{ + int ret; + ret = thinkpad_ec_request_row(args); + if (ret) { + prefetch_jiffies = TPC_PREFETCH_JUNK; + } else { + prefetch_jiffies = get_jiffies_64(); + prefetch_arg0 = args->val[0x0]; + prefetch_argF = args->val[0xF]; + } + return ret; +} +EXPORT_SYMBOL_GPL(thinkpad_ec_prefetch_row); + +/** + * thinkpad_ec_invalidate - invalidate prefetched ThinkPad EC data + * + * Invalidate the data prefetched via thinkpad_ec_prefetch_row() from the + * ThinkPad embedded controller LPC3 interface. + * Must be called before unlocking by any code that accesses the controller + * ports directly. + */ +void thinkpad_ec_invalidate(void) +{ + prefetch_jiffies = TPC_PREFETCH_JUNK; +} +EXPORT_SYMBOL_GPL(thinkpad_ec_invalidate); + + +/*** Checking for EC hardware ***/ + +/** + * thinkpad_ec_test - verify the EC is present and follows protocol + * + * Ensure the EC LPC3 channel really works on this machine by making + * an EC request and seeing if the EC follows the documented H8S protocol. + * The requested row just reads battery status, so it should be harmless to + * access it (on a correct EC). + * This test writes to IO ports, so execute only after checking DMI. + */ +static int __init thinkpad_ec_test(void) +{ + int ret; + const struct thinkpad_ec_row args = /* battery 0 basic status */ + { .mask = 0x8001, .val = {0x01,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x00} }; + struct thinkpad_ec_row data = { .mask = 0x0000 }; + ret = thinkpad_ec_lock(); + if (ret) + return ret; + ret = thinkpad_ec_read_row(&args, &data); + thinkpad_ec_unlock(); + return ret; +} + +/* Search all DMI device names of a given type for a substring */ +static int __init dmi_find_substring(int type, const char *substr) +{ + const struct dmi_device *dev = NULL; + while ((dev = dmi_find_device(type, NULL, dev))) { + if (strstr(dev->name, substr)) + return 1; + } + return 0; +} + +#define TP_DMI_MATCH(vendor,model) { \ + .ident = vendor " " model, \ + .matches = { \ + DMI_MATCH(DMI_BOARD_VENDOR, vendor), \ + DMI_MATCH(DMI_PRODUCT_VERSION, model) \ + } \ +} + +/* Check DMI for existence of ThinkPad embedded controller */ +static int __init check_dmi_for_ec(void) +{ + /* A few old models that have a good EC but don't report it in DMI */ + struct dmi_system_id tp_whitelist[] = { + TP_DMI_MATCH("IBM", "ThinkPad A30"), + TP_DMI_MATCH("IBM", "ThinkPad T23"), + TP_DMI_MATCH("IBM", "ThinkPad X24"), + { .ident = NULL } + }; + return dmi_find_substring(DMI_DEV_TYPE_OEM_STRING, + "IBM ThinkPad Embedded Controller") || + dmi_check_system(tp_whitelist); +} + +/*** Init and cleanup ***/ + +static int __init thinkpad_ec_init(void) +{ + if (!check_dmi_for_ec()) { + printk(KERN_WARNING + "thinkpad_ec: no ThinkPad embedded controller!\n"); + return -ENODEV; + } + + if (!request_region(TPC_BASE_PORT, TPC_NUM_PORTS, + "thinkpad_ec")) { + printk(KERN_ERR "thinkpad_ec: cannot claim io ports %#x-%#x\n", + TPC_BASE_PORT, + TPC_BASE_PORT + TPC_NUM_PORTS - 1); + return -ENXIO; + } + prefetch_jiffies = TPC_PREFETCH_JUNK; + if (thinkpad_ec_test()) { + printk(KERN_ERR "thinkpad_ec: initial ec test failed\n"); + release_region(TPC_BASE_PORT, TPC_NUM_PORTS); + return -ENXIO; + } + printk(KERN_INFO "thinkpad_ec: thinkpad_ec " TP_VERSION " loaded.\n"); + return 0; +} + +static void __exit thinkpad_ec_exit(void) +{ + release_region(TPC_BASE_PORT, TPC_NUM_PORTS); + printk(KERN_INFO "thinkpad_ec: unloaded.\n"); +} + +module_init(thinkpad_ec_init); +module_exit(thinkpad_ec_exit); --- linux-2.6.27.orig/ubuntu/misc/Makefile +++ linux-2.6.27/ubuntu/misc/Makefile @@ -0,0 +1,15 @@ +# +# Makefile for Ubuntu additional drivers +# + +obj-$(CONFIG_USB_APPLEIR) += appleir.o +obj-$(CONFIG_BLK_DEV_DM_BBR) += dm-bbr.o +obj-$(CONFIG_INPUT_ACERHK) += acerhk.o +obj-$(CONFIG_LMPCM_USB) += lmpcm_usb.o +obj-$(CONFIG_TP_SMAPI) += tp_smapi.o +obj-$(CONFIG_TP_SMAPI_EC) += thinkpad_ec.o +obj-$(CONFIG_FSAM7400) += fsam7400.o + +obj-m += media/ wireless/ + +CFLAGS_dm-bbr.o += -I$(srctree)/drivers/md --- linux-2.6.27.orig/ubuntu/misc/thinkpad_ec.h +++ linux-2.6.27/ubuntu/misc/thinkpad_ec.h @@ -0,0 +1,47 @@ +/* + * thinkpad_ec.h - interface to ThinkPad embedded controller LPC3 functions + * + * Copyright (C) 2005 Shem Multinymous + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _THINKPAD_EC_H +#define _THINKPAD_EC_H + +#ifdef __KERNEL__ + +#define TP_CONTROLLER_ROW_LEN 16 + +/* EC transactions input and output (possibly partial) vectors of 16 bytes. */ +struct thinkpad_ec_row { + u16 mask; /* bitmap of which entries of val[] are meaningful */ + u8 val[TP_CONTROLLER_ROW_LEN]; +}; + +extern int __must_check thinkpad_ec_lock(void); +extern int __must_check thinkpad_ec_try_lock(void); +extern void thinkpad_ec_unlock(void); + +extern int thinkpad_ec_read_row(const struct thinkpad_ec_row *args, + struct thinkpad_ec_row *data); +extern int thinkpad_ec_try_read_row(const struct thinkpad_ec_row *args, + struct thinkpad_ec_row *mask); +extern int thinkpad_ec_prefetch_row(const struct thinkpad_ec_row *args); +extern void thinkpad_ec_invalidate(void); + + +#endif /* __KERNEL */ +#endif /* _THINKPAD_EC_H */ --- linux-2.6.27.orig/ubuntu/misc/dm-bbr.c +++ linux-2.6.27/ubuntu/misc/dm-bbr.c @@ -0,0 +1,1012 @@ +/* + * (C) Copyright IBM Corp. 2002, 2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * linux/drivers/md/dm-bbr.c + * + * Bad-block-relocation (BBR) target for device-mapper. + * + * The BBR target is designed to remap I/O write failures to another safe + * location on disk. Note that most disk drives have BBR built into them, + * this means that our software BBR will be only activated when all hardware + * BBR replacement sectors have been used. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dm-bio-record.h" +#include "dm.h" +#include "dm-bbr.h" + +#define DM_MSG_PREFIX "bbr" +#define SECTOR_SIZE (1 << SECTOR_SHIFT) + +static struct workqueue_struct *dm_bbr_wq = NULL; +static void bbr_remap_handler(struct work_struct *work); +static struct kmem_cache *bbr_remap_cache; +static struct kmem_cache *bbr_io_cache; +static mempool_t *bbr_io_pool; + +/** + * bbr_binary_tree_destroy + * + * Destroy the binary tree. + **/ +static void bbr_binary_tree_destroy(struct bbr_runtime_remap *root) +{ + struct bbr_runtime_remap **link = NULL; + struct bbr_runtime_remap *node = root; + + while (node) { + if (node->left) { + link = &node->left; + node = node->left; + continue; + } + if (node->right) { + link = &node->right; + node = node->right; + continue; + } + + kmem_cache_free(bbr_remap_cache, node); + if (node == root) { + /* If root is deleted, we're done. */ + break; + } + + /* Back to root. */ + node = root; + *link = NULL; + } +} + +static void bbr_free_remap(struct bbr_private *bbr_id) +{ + spin_lock_irq(&bbr_id->remap_root_lock); + bbr_binary_tree_destroy(bbr_id->remap_root); + bbr_id->remap_root = NULL; + spin_unlock_irq(&bbr_id->remap_root_lock); +} + +static struct bbr_private *bbr_alloc_private(void) +{ + struct bbr_private *bbr_id; + + bbr_id = kzalloc(sizeof(*bbr_id), GFP_KERNEL); + if (bbr_id == NULL) + return NULL; + + INIT_WORK(&bbr_id->remap_work, bbr_remap_handler); + spin_lock_init(&bbr_id->remap_root_lock); + spin_lock_init(&bbr_id->remap_ios_lock); + bbr_id->in_use_replacement_blks = (atomic_t) ATOMIC_INIT(0); + + return bbr_id; +} + +static void bbr_free_private(struct bbr_private *bbr_id) +{ + vfree(bbr_id->bbr_table); + bbr_free_remap(bbr_id); + kfree(bbr_id); +} + +static u32 crc_table[256]; +static u32 crc_table_built = 0; + +static void build_crc_table(void) +{ + u32 i, j, crc; + + for (i = 0; i <= 255; i++) { + crc = i; + for (j = 8; j > 0; j--) { + if (crc & 1) + crc = (crc >> 1) ^ CRC_POLYNOMIAL; + else + crc >>= 1; + } + crc_table[i] = crc; + } + crc_table_built = 1; +} + +static u32 calculate_crc(u32 crc, void *buffer, u32 buffersize) +{ + unsigned char *current_byte; + u32 temp1, temp2, i; + + current_byte = (unsigned char *) buffer; + /* Make sure the crc table is available */ + if (!crc_table_built) + build_crc_table(); + /* Process each byte in the buffer. */ + for (i = 0; i < buffersize; i++) { + temp1 = (crc >> 8) & 0x00FFFFFF; + temp2 = crc_table[(crc ^ (u32) * current_byte) & + (u32) 0xff]; + current_byte++; + crc = temp1 ^ temp2; + } + return crc; +} + +/** + * le_bbr_table_sector_to_cpu + * + * Convert bbr meta data from on-disk (LE) format + * to the native cpu endian format. + **/ +static void le_bbr_table_sector_to_cpu(struct bbr_table *p) +{ + int i; + p->signature = le32_to_cpup(&p->signature); + p->crc = le32_to_cpup(&p->crc); + p->sequence_number = le32_to_cpup(&p->sequence_number); + p->in_use_cnt = le32_to_cpup(&p->in_use_cnt); + for (i = 0; i < BBR_ENTRIES_PER_SECT; i++) { + p->entries[i].bad_sect = + le64_to_cpup(&p->entries[i].bad_sect); + p->entries[i].replacement_sect = + le64_to_cpup(&p->entries[i].replacement_sect); + } +} + +/** + * cpu_bbr_table_sector_to_le + * + * Convert bbr meta data from cpu endian format to on-disk (LE) format + **/ +static void cpu_bbr_table_sector_to_le(struct bbr_table *p, + struct bbr_table *le) +{ + int i; + le->signature = cpu_to_le32p(&p->signature); + le->crc = cpu_to_le32p(&p->crc); + le->sequence_number = cpu_to_le32p(&p->sequence_number); + le->in_use_cnt = cpu_to_le32p(&p->in_use_cnt); + for (i = 0; i < BBR_ENTRIES_PER_SECT; i++) { + le->entries[i].bad_sect = + cpu_to_le64p(&p->entries[i].bad_sect); + le->entries[i].replacement_sect = + cpu_to_le64p(&p->entries[i].replacement_sect); + } +} + +/** + * validate_bbr_table_sector + * + * Check the specified BBR table sector for a valid signature and CRC. If it's + * valid, endian-convert the table sector. + **/ +static int validate_bbr_table_sector(struct bbr_table *p) +{ + int org_crc, final_crc; + + if (le32_to_cpup(&p->signature) != BBR_TABLE_SIGNATURE) { + DMERR("BBR table signature doesn't match!"); + DMERR("Found 0x%x. Expecting 0x%x", + le32_to_cpup(&p->signature), BBR_TABLE_SIGNATURE); + return -EINVAL; + } + + if (!p->crc) { + DMERR("BBR table sector has no CRC!"); + return -EINVAL; + } + + org_crc = le32_to_cpup(&p->crc); + p->crc = 0; + final_crc = calculate_crc(INITIAL_CRC, (void *)p, sizeof(*p)); + if (final_crc != org_crc) { + DMERR("CRC failed!"); + DMERR("Found 0x%x. Expecting 0x%x", + org_crc, final_crc); + return -EINVAL; + } + + p->crc = cpu_to_le32p(&org_crc); + le_bbr_table_sector_to_cpu(p); + + return 0; +} + +/** + * bbr_binary_tree_insert + * + * Insert a node into the binary tree. + **/ +static void bbr_binary_tree_insert(struct bbr_runtime_remap **root, + struct bbr_runtime_remap *newnode) +{ + struct bbr_runtime_remap **node = root; + while (node && *node) { + node = (newnode->remap.bad_sect > (*node)->remap.bad_sect) ? + &(*node)->right : &(*node)->left; + } + + newnode->left = newnode->right = NULL; + *node = newnode; +} + +/** + * bbr_binary_search + * + * Search for a node that contains bad_sect == lsn. + **/ +static struct bbr_runtime_remap *bbr_binary_search( + struct bbr_runtime_remap *root, + u64 lsn) +{ + struct bbr_runtime_remap *node = root; + while (node) { + if (node->remap.bad_sect == lsn) + break; + + node = (lsn > node->remap.bad_sect) ? node->right : node->left; + } + return node; +} + +/** + * bbr_insert_remap_entry + * + * Create a new remap entry and add it to the binary tree for this node. + **/ +static int bbr_insert_remap_entry(struct bbr_private *bbr_id, + struct bbr_table_entry *new_bbr_entry) +{ + struct bbr_runtime_remap *newnode; + + newnode = kmem_cache_alloc(bbr_remap_cache, GFP_NOIO); + if (!newnode) { + DMERR("Could not allocate from remap cache!"); + return -ENOMEM; + } + newnode->remap.bad_sect = new_bbr_entry->bad_sect; + newnode->remap.replacement_sect = new_bbr_entry->replacement_sect; + spin_lock_irq(&bbr_id->remap_root_lock); + bbr_binary_tree_insert(&bbr_id->remap_root, newnode); + spin_unlock_irq(&bbr_id->remap_root_lock); + return 0; +} + +/** + * bbr_table_to_remap_list + * + * The on-disk bbr table is sorted by the replacement sector LBA. In order to + * improve run time performance, the in memory remap list must be sorted by + * the bad sector LBA. This function is called at discovery time to initialize + * the remap list. This function assumes that at least one copy of meta data + * is valid. + **/ +static u32 bbr_table_to_remap_list(struct bbr_private *bbr_id) +{ + u32 in_use_blks = 0; + int i, j; + struct bbr_table *p; + + for (i = 0, p = bbr_id->bbr_table; + i < bbr_id->nr_sects_bbr_table; + i++, p++) { + if (!p->in_use_cnt) + break; + + in_use_blks += p->in_use_cnt; + for (j = 0; j < p->in_use_cnt; j++) + bbr_insert_remap_entry(bbr_id, &p->entries[j]); + } + if (in_use_blks) { + char b[32]; + DMWARN("There are %u BBR entries for device %s", + in_use_blks, format_dev_t(b, bbr_id->dev->bdev->bd_dev)); + } + + return in_use_blks; +} + +/** + * bbr_search_remap_entry + * + * Search remap entry for the specified sector. If found, return a pointer to + * the table entry. Otherwise, return NULL. + **/ +static struct bbr_table_entry *bbr_search_remap_entry( + struct bbr_private *bbr_id, + u64 lsn) +{ + struct bbr_runtime_remap *p; + + spin_lock_irq(&bbr_id->remap_root_lock); + p = bbr_binary_search(bbr_id->remap_root, lsn); + spin_unlock_irq(&bbr_id->remap_root_lock); + return (p) ? &p->remap : NULL; +} + +/** + * bbr_remap + * + * If *lsn is in the remap table, return TRUE and modify *lsn, + * else, return FALSE. + **/ +static int bbr_remap(struct bbr_private *bbr_id, + u64 *lsn) +{ + struct bbr_table_entry *e; + + if (atomic_read(&bbr_id->in_use_replacement_blks)) { + e = bbr_search_remap_entry(bbr_id, *lsn); + if (e) { + *lsn = e->replacement_sect; + return 1; + } + } + return 0; +} + +/** + * bbr_remap_probe + * + * If any of the sectors in the range [lsn, lsn+nr_sects] are in the remap + * table return TRUE, Else, return FALSE. + **/ +static int bbr_remap_probe(struct bbr_private *bbr_id, + u64 lsn, u64 nr_sects) +{ + u64 tmp, cnt; + + if (atomic_read(&bbr_id->in_use_replacement_blks)) { + for (cnt = 0, tmp = lsn; + cnt < nr_sects; + cnt += bbr_id->blksize_in_sects, tmp = lsn + cnt) { + if (bbr_remap(bbr_id,&tmp)) + return 1; + } + } + return 0; +} + +static int rw_table(struct bbr_private *bbr_id, void *vma, + struct dm_io_region *ptr, int rw) +{ + bbr_id->vma_io_req.bi_rw = rw; + bbr_id->vma_io_req.mem.ptr.vma = vma; + bbr_id->vma_io_req.notify.fn = NULL; + + return dm_io(&bbr_id->vma_io_req, 1, ptr, NULL); +} + +static int io_sync(struct bbr_private *bbr_id, struct page_list *pl, + unsigned offset, struct dm_io_region *ptr, int rw) +{ + bbr_id->page_io_req.bi_rw = rw; + bbr_id->page_io_req.mem.ptr.pl = pl; + bbr_id->page_io_req.mem.offset = offset; + bbr_id->page_io_req.notify.fn = NULL; + + return dm_io(&bbr_id->page_io_req, 1, ptr, NULL); +} + +/** + * bbr_setup + * + * Read the remap tables from disk and set up the initial remap tree. + **/ +static int bbr_setup(struct bbr_private *bbr_id) +{ + struct bbr_table *table = bbr_id->bbr_table; + struct dm_io_region job; + int i, rc = 0; + + job.bdev = bbr_id->dev->bdev; + job.count = 1; + + /* Read and verify each BBR table sector individually. */ + for (i = 0; i < bbr_id->nr_sects_bbr_table; i++, table++) { + job.sector = bbr_id->lba_table1 + i; + rc = rw_table(bbr_id, table, &job, READ); + if (rc && bbr_id->lba_table2) { + job.sector = bbr_id->lba_table2 + i; + rc = rw_table(bbr_id, table, &job, READ); + } + if (rc) { + goto out; + } + + rc = validate_bbr_table_sector(table); + if (rc) { + goto out; + } + } + atomic_set(&bbr_id->in_use_replacement_blks, + bbr_table_to_remap_list(bbr_id)); + +out: + if (rc) + DMERR("error during device setup: %d", rc); + return rc; +} + +/** + * bbr_io_remap_error + * @bbr_id: Private data for the BBR node. + * @rw: READ or WRITE. + * @starting_lsn: Starting sector of request to remap. + * @count: Number of sectors in the request. + * @page: Page containing the data for the request. + * @offset: Byte-offset of the data within the page. + * + * For the requested range, try to write each sector individually. For each + * sector that fails, find the next available remap location and write the + * data to that new location. Then update the table and write both copies + * of the table to disk. Finally, update the in-memory mapping and do any + * other necessary bookkeeping. + **/ +static int bbr_io_remap_error(struct bbr_private *bbr_id, + int rw, + u64 starting_lsn, + u64 count, + struct page *page, + unsigned int offset) +{ + struct bbr_table *bbr_table; + struct dm_io_region job; + struct page_list pl; + unsigned long table_sector_index; + unsigned long table_sector_offset; + unsigned long index; + u64 lsn, new_lsn; + char b[32]; + int rc; + + job.bdev = bbr_id->dev->bdev; + job.count = 1; + pl.page = page; + pl.next = NULL; + + /* For each sector in the request. */ + for (lsn = 0; lsn < count; lsn++, offset += SECTOR_SIZE) { + job.sector = starting_lsn + lsn; + rc = io_sync(bbr_id, &pl, offset, &job, rw); + while (rc) { + /* Find the next available relocation sector. */ + new_lsn = atomic_read(&bbr_id->in_use_replacement_blks); + if (new_lsn >= bbr_id->nr_replacement_blks) { + /* No more replacement sectors available. */ + return -EIO; + } + new_lsn += bbr_id->start_replacement_sect; + + /* Write the data to its new location. */ + DMWARN("device %s: Trying to remap bad sector "PFU64" to sector "PFU64, + format_dev_t(b, bbr_id->dev->bdev->bd_dev), + starting_lsn + lsn, new_lsn); + job.sector = new_lsn; + rc = io_sync(bbr_id, &pl, offset, &job, rw); + if (rc) { + /* This replacement sector is bad. + * Try the next one. + */ + DMERR("device %s: replacement sector "PFU64" is bad. Skipping.", + format_dev_t(b, bbr_id->dev->bdev->bd_dev), new_lsn); + atomic_inc(&bbr_id->in_use_replacement_blks); + continue; + } + + /* Add this new entry to the on-disk table. */ + table_sector_index = new_lsn - + bbr_id->start_replacement_sect; + table_sector_offset = table_sector_index / + BBR_ENTRIES_PER_SECT; + index = table_sector_index % BBR_ENTRIES_PER_SECT; + + bbr_table = &bbr_id->bbr_table[table_sector_offset]; + bbr_table->entries[index].bad_sect = starting_lsn + lsn; + bbr_table->entries[index].replacement_sect = new_lsn; + bbr_table->in_use_cnt++; + bbr_table->sequence_number++; + bbr_table->crc = 0; + bbr_table->crc = calculate_crc(INITIAL_CRC, + bbr_table, + sizeof(struct bbr_table)); + + /* Write the table to disk. */ + cpu_bbr_table_sector_to_le(bbr_table, bbr_table); + if (bbr_id->lba_table1) { + job.sector = bbr_id->lba_table1 + table_sector_offset; + rc = rw_table(bbr_id, bbr_table, &job, WRITE); + } + if (bbr_id->lba_table2) { + job.sector = bbr_id->lba_table2 + table_sector_offset; + rc |= rw_table(bbr_id, bbr_table, &job, WRITE); + } + le_bbr_table_sector_to_cpu(bbr_table); + + if (rc) { + /* Error writing one of the tables to disk. */ + DMERR("device %s: error updating BBR tables on disk.", + format_dev_t(b, bbr_id->dev->bdev->bd_dev)); + return rc; + } + + /* Insert a new entry in the remapping binary-tree. */ + rc = bbr_insert_remap_entry(bbr_id, + &bbr_table->entries[index]); + if (rc) { + DMERR("device %s: error adding new entry to remap tree.", + format_dev_t(b, bbr_id->dev->bdev->bd_dev)); + return rc; + } + + atomic_inc(&bbr_id->in_use_replacement_blks); + } + } + + return 0; +} + +/** + * bbr_io_process_request + * + * For each sector in this request, check if the sector has already + * been remapped. If so, process all previous sectors in the request, + * followed by the remapped sector. Then reset the starting lsn and + * count, and keep going with the rest of the request as if it were + * a whole new request. If any of the sync_io's return an error, + * call the remapper to relocate the bad sector(s). + * + * 2.5 Note: When switching over to bio's for the I/O path, we have made + * the assumption that the I/O request described by the bio is one + * virtually contiguous piece of memory (even though the bio vector + * describes it using a series of physical page addresses). + **/ +static int bbr_io_process_request(struct bbr_private *bbr_id, + struct bio *bio) +{ + struct dm_io_region job; + u64 starting_lsn = bio->bi_sector; + u64 count, lsn, remapped_lsn; + struct page_list pl; + unsigned int offset; + int i, rw = bio_data_dir(bio); + int rc = 0; + + job.bdev = bbr_id->dev->bdev; + pl.next = NULL; + + /* Each bio can contain multiple vectors, each with a different page. + * Treat each vector as a separate request. + */ + /* KMC: Is this the right way to walk the bvec list? */ + for (i = 0; + i < bio->bi_vcnt; + i++, bio->bi_idx++, starting_lsn += count) { + + /* Bvec info: number of sectors, page, + * and byte-offset within page. + */ + count = bio_iovec(bio)->bv_len >> SECTOR_SHIFT; + pl.page = bio_iovec(bio)->bv_page; + offset = bio_iovec(bio)->bv_offset; + + /* For each sector in this bvec, check if the sector has + * already been remapped. If so, process all previous sectors + * in this request, followed by the remapped sector. Then reset + * the starting lsn and count and keep going with the rest of + * the request as if it were a whole new request. + */ + for (lsn = 0; lsn < count; lsn++) { + remapped_lsn = starting_lsn + lsn; + rc = bbr_remap(bbr_id, &remapped_lsn); + if (!rc) { + /* This sector is fine. */ + continue; + } + + /* Process all sectors in the request up to this one. */ + if (lsn > 0) { + job.sector = starting_lsn; + job.count = lsn; + rc = io_sync(bbr_id, &pl, offset, &job, rw); + if (rc) { + /* If this I/O failed, then one of the + * sectors in this request needs to be + * relocated. + */ + rc = bbr_io_remap_error(bbr_id, rw, + starting_lsn, + lsn, pl.page, + offset); + if (rc) { + /* KMC: Return? Or continue to next bvec? */ + return rc; + } + } + offset += (lsn << SECTOR_SHIFT); + } + + /* Process the remapped sector. */ + job.sector = remapped_lsn; + job.count = 1; + rc = io_sync(bbr_id, &pl, offset, &job, rw); + if (rc) { + /* BUGBUG - Need more processing if this caused + * an error. If this I/O failed, then the + * existing remap is now bad, and we need to + * find a new remap. Can't use + * bbr_io_remap_error(), because the existing + * map entry needs to be changed, not added + * again, and the original table entry also + * needs to be changed. + */ + return rc; + } + + starting_lsn += (lsn + 1); + count -= (lsn + 1); + lsn = -1; + offset += SECTOR_SIZE; + } + + /* Check for any remaining sectors after the last split. This + * could potentially be the whole request, but that should be a + * rare case because requests should only be processed by the + * thread if we know an error occurred or they contained one or + * more remapped sectors. + */ + if (count) { + job.sector = starting_lsn; + job.count = count; + rc = io_sync(bbr_id, &pl, offset, &job, rw); + if (rc) { + /* If this I/O failed, then one of the sectors + * in this request needs to be relocated. + */ + rc = bbr_io_remap_error(bbr_id, rw, starting_lsn, + count, pl.page, offset); + if (rc) { + /* KMC: Return? Or continue to next bvec? */ + return rc; + } + } + } + } + + return 0; +} + +static void bbr_io_process_requests(struct bbr_private *bbr_id, + struct bio *bio) +{ + struct bio *next; + int rc; + + while (bio) { + next = bio->bi_next; + bio->bi_next = NULL; + + rc = bbr_io_process_request(bbr_id, bio); + + bio_endio(bio, rc); + + bio = next; + } +} + +/** + * bbr_remap_handler + * + * This is the handler for the bbr work-queue. + * + * I/O requests should only be sent to this handler if we know that: + * a) the request contains at least one remapped sector. + * or + * b) the request caused an error on the normal I/O path. + * + * This function uses synchronous I/O, so sending a request to this + * thread that doesn't need special processing will cause severe + * performance degredation. + **/ +static void bbr_remap_handler(struct work_struct *work) +{ + struct bbr_private *bbr_id = + container_of(work, struct bbr_private, remap_work); + struct bio *bio; + unsigned long flags; + + spin_lock_irqsave(&bbr_id->remap_ios_lock, flags); + bio = bio_list_get(&bbr_id->remap_ios); + spin_unlock_irqrestore(&bbr_id->remap_ios_lock, flags); + + bbr_io_process_requests(bbr_id, bio); +} + +/** + * bbr_endio + * + * This is the callback for normal write requests. Check for an error + * during the I/O, and send to the thread for processing if necessary. + **/ +static int bbr_endio(struct dm_target *ti, struct bio *bio, + int error, union map_info *map_context) +{ + struct bbr_private *bbr_id = ti->private; + struct dm_bio_details *bbr_io = map_context->ptr; + + if (error && bbr_io) { + unsigned long flags; + char b[32]; + + dm_bio_restore(bbr_io, bio); + map_context->ptr = NULL; + + DMERR("device %s: I/O failure on sector %lu. " + "Scheduling for retry.", + format_dev_t(b, bbr_id->dev->bdev->bd_dev), + (unsigned long)bio->bi_sector); + + spin_lock_irqsave(&bbr_id->remap_ios_lock, flags); + bio_list_add(&bbr_id->remap_ios, bio); + spin_unlock_irqrestore(&bbr_id->remap_ios_lock, flags); + + queue_work(dm_bbr_wq, &bbr_id->remap_work); + + error = 1; + } + + if (bbr_io) + mempool_free(bbr_io, bbr_io_pool); + + return error; +} + +/** + * Construct a bbr mapping + **/ +static int bbr_ctr(struct dm_target *ti, unsigned int argc, char **argv) +{ + struct bbr_private *bbr_id; + unsigned long block_size; + char *end; + int rc = -EINVAL; + + if (argc != 8) { + ti->error = "dm-bbr requires exactly 8 arguments: " + "device offset table1_lsn table2_lsn table_size start_replacement nr_replacement_blks block_size"; + goto out1; + } + + bbr_id = bbr_alloc_private(); + if (!bbr_id) { + ti->error = "dm-bbr: Error allocating bbr private data."; + goto out1; + } + + bbr_id->offset = simple_strtoull(argv[1], &end, 10); + bbr_id->lba_table1 = simple_strtoull(argv[2], &end, 10); + bbr_id->lba_table2 = simple_strtoull(argv[3], &end, 10); + bbr_id->nr_sects_bbr_table = simple_strtoull(argv[4], &end, 10); + bbr_id->start_replacement_sect = simple_strtoull(argv[5], &end, 10); + bbr_id->nr_replacement_blks = simple_strtoull(argv[6], &end, 10); + block_size = simple_strtoul(argv[7], &end, 10); + bbr_id->blksize_in_sects = (block_size >> SECTOR_SHIFT); + + bbr_id->vma_io_req.mem.type = DM_IO_VMA; + bbr_id->vma_io_req.client = dm_io_client_create(1); + if (IS_ERR(bbr_id->vma_io_req.client)) { + rc = PTR_ERR(bbr_id->vma_io_req.client); + DMWARN("couldn't allocate disk VMA io client"); + goto out2; + } + + bbr_id->page_io_req.mem.type = DM_IO_PAGE_LIST; + bbr_id->page_io_req.client = dm_io_client_create(1); + if (IS_ERR(bbr_id->page_io_req.client)) { + rc = PTR_ERR(bbr_id->page_io_req.client); + DMWARN("couldn't allocate pagelist io client"); + goto out3; + } + + bbr_id->bbr_table = vmalloc(bbr_id->nr_sects_bbr_table << SECTOR_SHIFT); + if (!bbr_id->bbr_table) { + ti->error = "dm-bbr: Error allocating bbr table."; + goto out4; + } + + if (dm_get_device(ti, argv[0], 0, ti->len, + dm_table_get_mode(ti->table), &bbr_id->dev)) { + ti->error = "dm-bbr: Device lookup failed"; + goto out4; + } + + rc = bbr_setup(bbr_id); + if (rc) { + ti->error = "dm-bbr: Device setup failed"; + goto out5; + } + + ti->private = bbr_id; + return 0; + +out5: + dm_put_device(ti, bbr_id->dev); +out4: + dm_io_client_destroy(bbr_id->page_io_req.client); +out3: + dm_io_client_destroy(bbr_id->vma_io_req.client); +out2: + bbr_free_private(bbr_id); +out1: + return rc; +} + +static void bbr_dtr(struct dm_target *ti) +{ + struct bbr_private *bbr_id = ti->private; + + dm_put_device(ti, bbr_id->dev); + dm_io_client_destroy(bbr_id->page_io_req.client); + dm_io_client_destroy(bbr_id->vma_io_req.client); + bbr_free_private(bbr_id); +} + +static int bbr_map(struct dm_target *ti, struct bio *bio, + union map_info *map_context) +{ + struct bbr_private *bbr_id = ti->private; + struct dm_bio_details *bbr_io; + unsigned long flags; + int rc = 1; + + bio->bi_sector += bbr_id->offset; + + if (atomic_read(&bbr_id->in_use_replacement_blks) == 0 || + !bbr_remap_probe(bbr_id, bio->bi_sector, bio_sectors(bio))) { + /* No existing remaps or this request doesn't + * contain any remapped sectors. + */ + bio->bi_bdev = bbr_id->dev->bdev; + + bbr_io = mempool_alloc(bbr_io_pool, GFP_NOIO); + dm_bio_record(bbr_io, bio); + map_context->ptr = bbr_io; + } else { + /* This request has at least one remapped sector. + * Give it to the work-queue for processing. + */ + map_context->ptr = NULL; + spin_lock_irqsave(&bbr_id->remap_ios_lock, flags); + bio_list_add(&bbr_id->remap_ios, bio); + spin_unlock_irqrestore(&bbr_id->remap_ios_lock, flags); + + queue_work(dm_bbr_wq, &bbr_id->remap_work); + rc = 0; + } + + return rc; +} + +static int bbr_status(struct dm_target *ti, status_type_t type, + char *result, unsigned int maxlen) +{ + struct bbr_private *bbr_id = ti->private; + char b[BDEVNAME_SIZE]; + + switch (type) { + case STATUSTYPE_INFO: + result[0] = '\0'; + break; + + case STATUSTYPE_TABLE: + snprintf(result, maxlen, "%s "PFU64" "PFU64" "PFU64" "PFU64" "PFU64" "PFU64" %u", + format_dev_t(b, bbr_id->dev->bdev->bd_dev), + bbr_id->offset, bbr_id->lba_table1, bbr_id->lba_table2, + bbr_id->nr_sects_bbr_table, + bbr_id->start_replacement_sect, + bbr_id->nr_replacement_blks, + bbr_id->blksize_in_sects << SECTOR_SHIFT); + break; + } + return 0; +} + +static struct target_type bbr_target = { + .name = "bbr", + .version= {1, 0, 1}, + .module = THIS_MODULE, + .ctr = bbr_ctr, + .dtr = bbr_dtr, + .map = bbr_map, + .end_io = bbr_endio, + .status = bbr_status, +}; + +int __init dm_bbr_init(void) +{ + int rc; + + rc = dm_register_target(&bbr_target); + if (rc) { + DMERR("error registering target."); + goto err1; + } + + bbr_remap_cache = kmem_cache_create("bbr-remap", + sizeof(struct bbr_runtime_remap), + 0, SLAB_HWCACHE_ALIGN, NULL); + if (!bbr_remap_cache) { + DMERR("error creating remap cache."); + rc = ENOMEM; + goto err2; + } + + bbr_io_cache = kmem_cache_create("bbr-io", sizeof(struct dm_bio_details), + 0, SLAB_HWCACHE_ALIGN, NULL); + if (!bbr_io_cache) { + DMERR("error creating io cache."); + rc = ENOMEM; + goto err3; + } + + bbr_io_pool = mempool_create(256, mempool_alloc_slab, + mempool_free_slab, bbr_io_cache); + if (!bbr_io_pool) { + DMERR("error creating io mempool."); + rc = ENOMEM; + goto err4; + } + + dm_bbr_wq = create_workqueue("dm-bbr"); + if (!dm_bbr_wq) { + DMERR("error creating work-queue."); + rc = ENOMEM; + goto err5; + } + + return 0; + +err5: + mempool_destroy(bbr_io_pool); +err4: + kmem_cache_destroy(bbr_io_cache); +err3: + kmem_cache_destroy(bbr_remap_cache); +err2: + dm_unregister_target(&bbr_target); +err1: + return rc; +} + +void __exit dm_bbr_exit(void) +{ + destroy_workqueue(dm_bbr_wq); + mempool_destroy(bbr_io_pool); + kmem_cache_destroy(bbr_io_cache); + kmem_cache_destroy(bbr_remap_cache); + dm_unregister_target(&bbr_target); +} + +module_init(dm_bbr_init); +module_exit(dm_bbr_exit); +MODULE_LICENSE("GPL"); --- linux-2.6.27.orig/ubuntu/misc/dm-bbr.h +++ linux-2.6.27/ubuntu/misc/dm-bbr.h @@ -0,0 +1,132 @@ +/* + * (C) Copyright IBM Corp. 2002, 2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * linux/drivers/md/dm-bbr.h + * + * Bad-block-relocation (BBR) target for device-mapper. + * + * The BBR target is designed to remap I/O write failures to another safe + * location on disk. Note that most disk drives have BBR built into them, + * this means that our software BBR will be only activated when all hardware + * BBR replacement sectors have been used. + */ + +#include +#include +#include + +#define BBR_TABLE_SIGNATURE 0x42627254 /* BbrT */ +#define BBR_ENTRIES_PER_SECT 31 +#define INITIAL_CRC 0xFFFFFFFF +#define CRC_POLYNOMIAL 0xEDB88320L + +/** + * Macros to cleanly print 64-bit numbers on both 32-bit and 64-bit machines. + * Use these in place of %Ld, %Lu, and %Lx. + **/ +#if BITS_PER_LONG > 32 +#define PFU64 "%lu" +#else +#define PFU64 "%Lu" +#endif + +/** + * struct bbr_table_entry + * @bad_sect: LBA of bad location. + * @replacement_sect: LBA of new location. + * + * Structure to describe one BBR remap. + **/ +struct bbr_table_entry { + u64 bad_sect; + u64 replacement_sect; +}; + +/** + * struct bbr_table + * @signature: Signature on each BBR table sector. + * @crc: CRC for this table sector. + * @sequence_number: Used to resolve conflicts when primary and secondary + * tables do not match. + * @in_use_cnt: Number of in-use table entries. + * @entries: Actual table of remaps. + * + * Structure to describe each sector of the metadata table. Each sector in this + * table can describe 31 remapped sectors. + **/ +struct bbr_table { + u32 signature; + u32 crc; + u32 sequence_number; + u32 in_use_cnt; + struct bbr_table_entry entries[BBR_ENTRIES_PER_SECT]; +}; + +/** + * struct bbr_runtime_remap + * + * Node in the binary tree used to keep track of remaps. + **/ +struct bbr_runtime_remap { + struct bbr_table_entry remap; + struct bbr_runtime_remap *left; + struct bbr_runtime_remap *right; +}; + +/** + * struct bbr_private + * @dev: Info about underlying device. + * @bbr_table: Copy of metadata table. + * @remap_root: Binary tree containing all remaps. + * @remap_root_lock: Lock for the binary tree. + * @remap_work: For adding work items to the work-queue. + * @remap_ios: List of I/Os for the work-queue to handle. + * @remap_ios_lock: Lock for the remap_ios list. + * @offset: LBA of data area. + * @lba_table1: LBA of primary BBR table. + * @lba_table2: LBA of secondary BBR table. + * @nr_sects_bbr_table: Size of each BBR table. + * @nr_replacement_blks: Number of replacement blocks. + * @start_replacement_sect: LBA of start of replacement blocks. + * @blksize_in_sects: Size of each block. + * @in_use_replacement_blks: Current number of remapped blocks. + * + * Private data for each BBR target. + **/ +struct bbr_private { + struct dm_dev *dev; + struct bbr_table *bbr_table; + struct bbr_runtime_remap *remap_root; + spinlock_t remap_root_lock; + + struct dm_io_request vma_io_req; + struct dm_io_request page_io_req; + + struct work_struct remap_work; + struct bio_list remap_ios; + spinlock_t remap_ios_lock; + + u64 offset; + u64 lba_table1; + u64 lba_table2; + u64 nr_sects_bbr_table; + u64 start_replacement_sect; + u64 nr_replacement_blks; + u32 blksize_in_sects; + atomic_t in_use_replacement_blks; +}; + --- linux-2.6.27.orig/ubuntu/misc/appleir.c +++ linux-2.6.27/ubuntu/misc/appleir.c @@ -0,0 +1,401 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Version Information + * + */ + +#if 0 +#define DUMP_PACKETS +#else +#undef DUMP_PACKETS +#endif + +#define DRIVER_VERSION "v1.1" +#define DRIVER_AUTHOR "James McKenzie" +#define DRIVER_DESC "USB Apple MacMini IR Receiver driver" +#define DRIVER_LICENSE "GPL" + +MODULE_AUTHOR (DRIVER_AUTHOR); +MODULE_DESCRIPTION (DRIVER_DESC); +MODULE_LICENSE (DRIVER_LICENSE); + +#ifndef USB_VENDOR_ID_APPLE +#define USB_VENDOR_ID_APPLE 0x05ac +#endif +#ifndef USB_DEVICE_ID_APPLE_IR +#define USB_DEVICE_ID_APPLE_IR 0x8240 +#endif +#ifndef USB_DEVICE_ID_APPLE_IR2 +#define USB_DEVICE_ID_APPLE_IR2 0x8242 +#endif + +#define URB_SIZE 32 + +#define MAX_KEYS 8 +#define MAX_KEYS_MASK (MAX_KEYS - 1 ) + +struct appleir +{ + struct input_dev *dev; + uint8_t *data; + dma_addr_t dma_buf; + struct usb_device *usbdev; + struct urb *urb; + int timer_initted; + struct timer_list key_up_timer; + int current_key; + char phys[32]; +}; + + +static struct usb_device_id appleir_ids[] = { + {USB_DEVICE (USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR),.driver_info = 0}, + {USB_DEVICE (USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR2),.driver_info = 0}, + {} +}; + +MODULE_DEVICE_TABLE (usb, appleir_ids); + + +/* I have two devices both of which report the following */ +/* 25 87 ee 83 0a + */ +/* 25 87 ee 83 0c - */ +/* 25 87 ee 83 09 << */ +/* 25 87 ee 83 06 >> */ +/* 25 87 ee 83 05 >" */ +/* 25 87 ee 83 03 menu */ +/* 26 00 00 00 00 for key repeat*/ + +/* Thomas Glanzmann reports the following responses */ +/* 25 87 ee ca 0b + */ +/* 25 87 ee ca 0d - */ +/* 25 87 ee ca 08 << */ +/* 25 87 ee ca 07 >> */ +/* 25 87 ee ca 04 >" */ +/* 25 87 ee ca 02 menu */ +/* 26 00 00 00 00 for key repeat*/ +/* He also observes the following event sometimes */ +/* sent after a key is release, which I interpret */ +/* as a flat battery message */ +/* 25 87 e0 ca 06 flat battery */ + +/* Alexandre Karpenko reports the following responses for Device ID 0x8242 */ +/* 25 87 ee 47 0b + */ +/* 25 87 ee 47 0d - */ +/* 25 87 ee 47 08 << */ +/* 25 87 ee 47 07 >> */ +/* 25 87 ee 47 04 >" */ +/* 25 87 ee 47 02 menu */ +/* 26 87 ee 47 ** for key repeat (** is the code of the key being held) */ + + +static int keymap[MAX_KEYS] = { + KEY_RESERVED, KEY_MENU, + KEY_PLAYPAUSE, KEY_FORWARD, + KEY_BACK, KEY_VOLUMEUP, + KEY_VOLUMEDOWN, KEY_RESERVED +}; + +static void +dump_packet (struct appleir *appleir, char *msg, uint8_t * data, int len) +{ + int i; + + printk (KERN_ERR "appleir: %s (%d bytes)", msg, len); + + for (i = 0; i < len; ++i) + { + printk (" %02x", data[i]); + } + + printk ("\n"); +} + + +static void +key_up (struct appleir *appleir, int key) +{ + //printk (KERN_ERR "key %d up\n", key); + input_report_key (appleir->dev, key, 0); + input_sync (appleir->dev); +} + +static void +key_down (struct appleir *appleir, int key) +{ + //printk (KERN_ERR "key %d down\n", key); + input_report_key (appleir->dev, key, 1); + input_sync (appleir->dev); +} + +static void +battery_flat (struct appleir *appleir) +{ + printk (KERN_ERR "appleir: possible flat battery?\n"); +} + +static void +key_up_tick (unsigned long data) +{ + struct appleir *appleir = (struct appleir *) data; + + if (appleir->current_key) + { + key_up (appleir, appleir->current_key); + appleir->current_key = 0; + } +} + +static void +new_data (struct appleir *appleir, uint8_t * data, int len) +{ + static const uint8_t keydown[] = { 0x25, 0x87, 0xee }; + static const uint8_t keyrepeat[] = { 0x26 }; + static const uint8_t flatbattery[] = { 0x25, 0x87, 0xe0 }; + +#ifdef DUMP_PACKETS + dump_packet (appleir, "received", data, len); +#endif + + if (len != 5) + return; + + if (!memcmp (data, keydown, sizeof (keydown))) + { + /*If we already have a key down, take it up before marking */ + /*this one down */ + if (appleir->current_key) + key_up (appleir, appleir->current_key); + appleir->current_key = keymap[(data[4] >> 1) & MAX_KEYS_MASK]; + + key_down (appleir, appleir->current_key); + /*remote doesn't do key up, either pull them up, in the test */ + /*above, or here set a timer which pulls them up after 1/8 s */ + mod_timer (&appleir->key_up_timer, jiffies + HZ / 8); + + return; + } + + if (!memcmp (data, keyrepeat, sizeof (keyrepeat))) + { + key_down (appleir, appleir->current_key); + /*remote doesn't do key up, either pull them up, in the test */ + /*above, or here set a timer which pulls them up after 1/8 s */ + mod_timer (&appleir->key_up_timer, jiffies + HZ / 8); + return; + } + + if (!memcmp (data, flatbattery, sizeof (flatbattery))) + { + battery_flat (appleir); + /*Fall through */ + } + + dump_packet (appleir, "unknown packet", data, len); +} + +static void +appleir_urb (struct urb *urb) +{ + struct appleir *appleir = urb->context; + int retval; + + switch (urb->status) + { + case 0: + new_data (appleir, urb->transfer_buffer, urb->actual_length); + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg ("%s - urb shutting down with status: %d", __FUNCTION__, + urb->status); + return; + default: + dbg ("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + } + + retval = usb_submit_urb (urb, GFP_ATOMIC); + if (retval) + err ("%s - usb_submit_urb failed with result %d", __FUNCTION__, retval); +} + + +static int +appleir_open (struct input_dev *dev) +{ + struct appleir *appleir = (struct appleir *)input_get_drvdata(dev); + + if (usb_submit_urb (appleir->urb, GFP_KERNEL)) + return -EIO; + + return 0; +} + +static void +appleir_close (struct input_dev *dev) +{ + struct appleir *appleir = (struct appleir *)input_get_drvdata(dev); + usb_kill_urb (appleir->urb); + del_timer_sync (&appleir->key_up_timer); +} + + + + +static int +appleir_probe (struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev (intf); + struct usb_endpoint_descriptor *endpoint; + struct appleir *appleir = NULL; + struct input_dev *input_dev; + int i; + + appleir = kzalloc (sizeof (struct appleir), GFP_KERNEL); + if (!appleir) + goto fail; + + memset (appleir, 0, sizeof (struct appleir)); + + + appleir->data = + usb_buffer_alloc (dev, URB_SIZE, GFP_KERNEL, &appleir->dma_buf); + if (!appleir->data) + goto fail; + + appleir->urb = usb_alloc_urb (0, GFP_KERNEL); + if (!appleir->urb) + goto fail; + + appleir->usbdev = dev; + + input_dev = input_allocate_device (); + if (!input_dev) + goto fail; + + appleir->dev = input_dev; + + + usb_make_path (dev, appleir->phys, sizeof (appleir->phys)); + strlcpy (appleir->phys, "/input0", sizeof (appleir->phys)); + + input_dev->name = "Apple Mac mini infrared remote control driver"; + input_dev->phys = appleir->phys; + usb_to_input_id (dev, &input_dev->id); + input_dev->dev.parent = &intf->dev; + input_set_drvdata(input_dev, appleir); + + input_dev->evbit[0] = BIT (EV_KEY) | BIT (EV_REP); + input_dev->ledbit[0] = 0; + + for (i = 0; i < MAX_KEYS; i++) + { + set_bit (keymap[i], input_dev->keybit); + } + + clear_bit (0, input_dev->keybit); + + input_dev->open = appleir_open; + input_dev->close = appleir_close; + + endpoint = &intf->cur_altsetting->endpoint[0].desc; + + usb_fill_int_urb (appleir->urb, dev, + usb_rcvintpipe (dev, endpoint->bEndpointAddress), + appleir->data, 8, + appleir_urb, appleir, endpoint->bInterval); + + appleir->urb->transfer_dma = appleir->dma_buf; + appleir->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + usb_set_intfdata (intf, appleir); + + init_timer (&appleir->key_up_timer); + + appleir->key_up_timer.function = key_up_tick; + appleir->key_up_timer.data = (unsigned long) appleir; + + appleir->timer_initted++; + + input_register_device (appleir->dev); + + return 0; + +fail: + + if (appleir) + { + + + if (appleir->data) + usb_buffer_free (dev, URB_SIZE, appleir->data, appleir->dma_buf); + + if (appleir->timer_initted) + del_timer_sync (&appleir->key_up_timer); + + if (appleir->dev) + input_free_device (appleir->dev); + + kfree (appleir); + } + + return -ENOMEM; +} + +static void +appleir_disconnect (struct usb_interface *intf) +{ + struct appleir *appleir = usb_get_intfdata (intf); + + usb_set_intfdata (intf, NULL); + if (appleir) + { + input_unregister_device (appleir->dev); + if (appleir->timer_initted) + del_timer_sync (&appleir->key_up_timer); + usb_kill_urb (appleir->urb); + usb_free_urb (appleir->urb); + usb_buffer_free (interface_to_usbdev (intf), URB_SIZE, appleir->data, + appleir->dma_buf); + kfree (appleir); + } +} + +static struct usb_driver appleir_driver = { + .name = "appleir", + .probe = appleir_probe, + .disconnect = appleir_disconnect, + .id_table = appleir_ids, +}; + +static int __init +appleir_init (void) +{ + int retval; + retval = usb_register (&appleir_driver); + if (retval) + goto out; + info (DRIVER_VERSION ":" DRIVER_DESC); +out: + return retval; +} + +static void __exit +appleir_exit (void) +{ + usb_deregister (&appleir_driver); +} + +module_init (appleir_init); +module_exit (appleir_exit); --- linux-2.6.27.orig/ubuntu/misc/BOM +++ linux-2.6.27/ubuntu/misc/BOM @@ -0,0 +1,3 @@ +Module: dm-bbr +Downloaded from: http://dev.gentoo.org/~dsd/gentoo-sources/patches-2.6.25-2.htm +Comments: Changes in md headers for 2.6.26 required some munging. --- linux-2.6.27.orig/ubuntu/misc/acerhk.h +++ linux-2.6.27/ubuntu/misc/acerhk.h @@ -0,0 +1,91 @@ +#ifndef __ACERHK_H__ +#define __ACERHK_H__ + +#include + +#define ACERHK_MINOR MISC_DYNAMIC_MINOR + +#define ACERHK_GET_KEYCOUNT _IOR('p', 0x01, char) /* Get number of cached key presses */ +#define ACERHK_GET_KEYID _IOR('p', 0x02, char) /* Get first key in queue */ +#define ACERHK_CONNECT _IO('p', 0x03) /* ? */ +#define ACERHK_DISCONNECT _IO('p', 0x04) /* ? */ +#define ACERHK_GET_THERMAL_EVENT _IOR('p', 0x05, short) /* ? */ +#define ACERHK_MAIL_LED_OFF _IO('p', 0x10) /* switch mail LED off */ +#define ACERHK_MAIL_LED_ON _IO('p', 0x11) /* switch mail LED on (blinking) */ +#define ACERHK_START_POLLING _IO('p', 0x12) /* poll keys in kernel, send real key events */ +#define ACERHK_STOP_POLLING _IO('p', 0x13) /* stop key polling in kernel */ +#define ACERHK_GET_KEY_MAP _IOR('p', 0x20, int) /* Get mapping of key names to key events, */ +#define ACERHK_SET_KEY_MAP _IOW('p', 0x21, int) /* Set mapping of key names to key events */ + +/* all possible keys (known to me) */ +typedef enum e_key_names { + k_none = 0, + k_help = 1, /* Fn+F1 */ + k_setup = 2, /* Fn+F2 */ + k_p1 = 3, + k_p2 = 4, + k_p3 = 5, + k_www = 6, + k_mail = 7, + k_wireless = 8, + k_power = 9, /* Fn+F3 */ + k_mute = 10, /* Fn+F8 */ + k_volup = 11, /* Fn+Up */ + k_voldn = 12, /* Fn+Down */ + k_res = 13, /* resolution change on Medion MD 40100 */ + k_close = 14, /* if lid is closed in tablet mode */ + k_open = 15, /* if lid is opend in tablet mode */ + k_wireless2 = 16, /* second wireless button on TM 243LC */ + k_play = 17, /* Play/Pause found on AOpen */ + k_stop = 18, /* Stop/Eject found on AOpen */ + k_prev = 19, /* Prev found on AOpen */ + k_next = 20, /* Next found on AOpen */ + k_display = 21 /* Change internal/external display on MD 42200 */ +} t_key_names; +#define NR_KEY_NAMES 22 +typedef unsigned int t_map_name2event[NR_KEY_NAMES]; + +#ifdef __KERNEL__ + +/* available features */ +#define TM_F_WLAN_EC1 0x00000010 +#define TM_F_BLUE_EC1 0x00000020 +#define TM_F_WLAN_EC2 0x00000040 +#define TM_F_BLUE_EC2 0x00000080 +#define TM_F_MUTE_LED_EC 0x00001000 +#define TM_F_MAIL_LED 0x00010000 +#define TM_F_MAIL_LED_EC 0x00020000 +#define TM_F_MAIL_LED_EC2 0x00040000 +#define TM_F_MAIL_LED_EC3 0x00080000 + +#define TM_F_CONNECT 0x00100000 +#define TM_F_THERMAL 0x00200000 +#define TM_F_PBUTTON 0x00400000 +#define TM_F_WBUTTON 0x00800000 + +typedef enum acer_type { + TM_unknown, + /* 200, 210, 520, 600 and 730 series, Medion MD42200 */ + TM_old, + /* C100, C110, 220, 230, 240, 260, 350, 360, 610, 620, 630, 740 series + Medion MD40100, Aspire 1600, FS Amilo */ + TM_new, + /* Aspire 13xx, 14xx, 1700, TM 290, 650, 660, 800 */ + TM_dritek +} t_acer_type; + +struct register_buffer { + unsigned int eax; + unsigned int ebx; + unsigned int ecx; + unsigned int edx; + unsigned int edi; + unsigned int esi; + unsigned int ebp; +}; + +typedef asmlinkage void (*bios_call) (struct register_buffer *); + +#endif + +#endif --- linux-2.6.27.orig/ubuntu/misc/media/snd-bt-sco.c +++ linux-2.6.27/ubuntu/misc/media/snd-bt-sco.c @@ -0,0 +1,1231 @@ +/* + * Bluetooth SCO soundcard + * Copyright (c) 2003, 2004 by Jonathan Paisley + * + * Based on dummy.c which is + * Copyright (c) by Jaroslav Kysela + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + +/* note: defining these two independently is not tested, + * thus not recommended + */ + +/* enable dynamic compression */ +#define DYNAMIC_COMPRESSION +/* enable automatic endianness fixup */ +#define AUTO_FIXUP_BYTESHIFT + + +#ifdef DYNAMIC_COMPRESSION +/* Autoadjust mic at most this often in 1/8000s */ +#define GRABSAMPLES 400 +/* Maximum push for the mike 16= 1:1 - default 20:1 = 320 */ +#define COMPRESSION_MAX_16 320 +/* Minimum push for the mike 1= 1:16 */ +#define COMPRESSION_MIN_16 1 +#endif + +#define chip_t snd_card_bt_sco_t + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// this was ostensibly for newer kernels but fails on 2.6.19.2 +#if 0 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) +#include +#endif +#endif +#include +#include +#include +#include +#include +#define SNDRV_GET_ID +#include + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) +#include +#else +#define mutex semaphore +#define mutex_init init_MUTEX +#define mutex_lock down +#define mutex_unlock up +#endif + +#ifndef SNDRV_HWDEP_IFACE_BLUETOOTH +#define SNDRV_HWDEP_IFACE_BLUETOOTH (SNDRV_HWDEP_IFACE_EMUX_WAVETABLE + 1) +#endif + +#ifndef SNDRV_HWDEP_IFACE_BT_SCO +#define SNDRV_HWDEP_IFACE_BT_SCO (SNDRV_HWDEP_IFACE_BLUETOOTH + 1) +#endif + +#define SNDRV_BT_SCO_IOCTL_SET_SCO_SOCKET _IOW ('H', 0x10, int) +#define SNDRV_BT_SCO_IOCTL_REQ_INFO _IO ('H', 0x11) + +static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* Exclude the first card */ + +#define MOD_REVISION "$Revision: 1.19 $"; +static char *mod_revision = MOD_REVISION; + +MODULE_AUTHOR("Jonathan Paisley "); +MODULE_DESCRIPTION("Bluetooth SCO Headset Soundcard"); +MODULE_VERSION(MOD_REVISION); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{ALSA,Bluetooth SCO Soundcard}}"); + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for Bluetooth SCO Headset Soundcard."); + +#undef dprintk +#if 1 +#define dprintk(fmt...) printk(KERN_INFO "snd-bt-sco: " fmt) +#else +#define dprintk(fmt...) do {} while(0) +#endif + +#define MAX_BUFFER_SIZE (32*1024) + +#define MIXER_ADDR_MASTER 0 +#define MIXER_ADDR_MIC 1 +#define MIXER_ADDR_LAST 1 + +#define MIXER_MASK_MASTER 1 +#define MIXER_MASK_MIC 2 + +#define MIXER_MIN_VOLUME 1 +#define MIXER_MAX_VOLUME 15 + +struct snd_card_bt_sco_pcm; + +typedef struct snd_card_bt_sco_info { + int mixer_volume[MIXER_ADDR_LAST + 1]; + int playback_count, capture_count; +} snd_card_bt_sco_info_t; + +typedef struct snd_card_bt_sco { + struct snd_card *card; + spinlock_t mixer_lock; + int mixer_volume[MIXER_ADDR_LAST + 1]; +#ifdef DYNAMIC_COMPRESSION + struct snd_kcontrol *mixer_controls[MIXER_ADDR_LAST + 2 + 1]; /* also loopback and agc */ +#else + struct snd_kcontrol *mixer_controls[MIXER_ADDR_LAST + 2 ]; /* also loopback */ +#endif + volatile int loopback; +#ifdef DYNAMIC_COMPRESSION + volatile int agc; +#endif + atomic_t playback_count, capture_count; + volatile int count_changed; + spinlock_t count_changed_lock; + + spinlock_t mixer_changed_lock; + volatile int mixer_changed; + wait_queue_head_t hwdep_wait; + + struct task_struct *thread; + + struct mutex thread_sem; + + volatile struct socket *sco_sock; + struct mutex sock_sem; + wait_queue_head_t wait; + + struct mutex playback_sem; + struct snd_card_bt_sco_pcm *playback; + struct mutex capture_sem; + struct snd_card_bt_sco_pcm *capture; +} snd_card_bt_sco_t; + +typedef struct snd_card_bt_sco_pcm { + snd_card_bt_sco_t *bt_sco; + spinlock_t lock; + unsigned int pcm_size; + unsigned int pcm_count; + unsigned int pcm_bps; /* bytes per second */ + unsigned int pcm_irq_pos; /* IRQ position */ + unsigned int pcm_buf_pos; /* position in buffer */ + struct snd_pcm_substream *substream; +} snd_card_bt_sco_pcm_t; + +static struct snd_card *snd_bt_sco_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; + +static int snd_card_bt_sco_playback_trigger(struct snd_pcm_substream * + substream, int cmd) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + snd_card_bt_sco_pcm_t *bspcm = runtime->private_data; + snd_card_bt_sco_t *bt_sco = snd_pcm_substream_chip(substream); + + dprintk("playback_trigger %d\n", cmd); + + if (cmd == SNDRV_PCM_TRIGGER_START) { + bt_sco->playback = bspcm; + dprintk("setting playback to bspcm\n"); + } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { + bt_sco->playback = NULL; + dprintk("setting playback to NULL\n"); + } else { + return -EINVAL; + } + return 0; +} + +static int snd_card_bt_sco_capture_trigger(struct snd_pcm_substream * + substream, int cmd) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + snd_card_bt_sco_pcm_t *bspcm = runtime->private_data; + snd_card_bt_sco_t *bt_sco = snd_pcm_substream_chip(substream); + + dprintk("capture_trigger %d\n", cmd); + + if (cmd == SNDRV_PCM_TRIGGER_START) { + bt_sco->capture = bspcm; + dprintk("setting capture to bspcm\n"); + } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { + bt_sco->capture = NULL; + dprintk("setting capture to NULL\n"); + } else { + return -EINVAL; + } + return 0; +} + +static int snd_card_bt_sco_pcm_prepare(struct snd_pcm_substream * substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + snd_card_bt_sco_pcm_t *bspcm = runtime->private_data; + unsigned int bps; + + bps = runtime->rate * runtime->channels; + bps *= snd_pcm_format_width(runtime->format); + bps /= 8; + if (bps <= 0) + return -EINVAL; + bspcm->pcm_bps = bps; + bspcm->pcm_size = snd_pcm_lib_buffer_bytes(substream); + bspcm->pcm_count = snd_pcm_lib_period_bytes(substream); + bspcm->pcm_irq_pos = 0; + bspcm->pcm_buf_pos = 0; + dprintk("prepare ok bps: %d size: %d count: %d\n", + bspcm->pcm_bps, bspcm->pcm_size, bspcm->pcm_count); + return 0; +} + +static int snd_card_bt_sco_playback_prepare(struct snd_pcm_substream * substream) +{ + return snd_card_bt_sco_pcm_prepare(substream); +} + +static int snd_card_bt_sco_capture_prepare(struct snd_pcm_substream * substream) +{ + dprintk("capture_prepare\n"); + return snd_card_bt_sco_pcm_prepare(substream); +} + +static void snd_card_bt_sco_pcm_receive(snd_card_bt_sco_pcm_t * bspcm, + unsigned char *data, unsigned int len) +{ + unsigned long flags; + unsigned int oldptr; + + spin_lock_irqsave(&bspcm->lock, flags); + oldptr = bspcm->pcm_buf_pos; + bspcm->pcm_irq_pos += len; + bspcm->pcm_buf_pos += len; + bspcm->pcm_buf_pos %= bspcm->pcm_size; + spin_unlock_irqrestore(&bspcm->lock, flags); + /* copy a data chunk */ + if (oldptr + len > bspcm->pcm_size) { + unsigned int cnt = bspcm->pcm_size - oldptr; + memcpy(bspcm->substream->runtime->dma_area + oldptr, data, cnt); + memcpy(bspcm->substream->runtime->dma_area, data + cnt, + len - cnt); + } else { + memcpy(bspcm->substream->runtime->dma_area + oldptr, data, len); + } + /* update the pointer, call callback if necessary */ + spin_lock_irqsave(&bspcm->lock, flags); + if (bspcm->pcm_irq_pos >= bspcm->pcm_count) { + bspcm->pcm_irq_pos %= bspcm->pcm_count; + spin_unlock_irqrestore(&bspcm->lock, flags); + snd_pcm_period_elapsed(bspcm->substream); + } else + spin_unlock_irqrestore(&bspcm->lock, flags); + +} + +static void snd_card_bt_sco_pcm_send(snd_card_bt_sco_pcm_t * bspcm, + unsigned char *data, unsigned int len) +{ + unsigned long flags; + unsigned int oldptr; + + spin_lock_irqsave(&bspcm->lock, flags); + oldptr = bspcm->pcm_buf_pos; + bspcm->pcm_irq_pos += len; + bspcm->pcm_buf_pos += len; + bspcm->pcm_buf_pos %= bspcm->pcm_size; + spin_unlock_irqrestore(&bspcm->lock, flags); + /* copy a data chunk */ + if (oldptr + len > bspcm->pcm_size) { + unsigned int cnt = bspcm->pcm_size - oldptr; + memcpy(data, bspcm->substream->runtime->dma_area + oldptr, cnt); + memcpy(data + cnt, bspcm->substream->runtime->dma_area, + len - cnt); + } else { + memcpy(data, bspcm->substream->runtime->dma_area + oldptr, len); + } + /* update the pointer, call callback if necessary */ + spin_lock_irqsave(&bspcm->lock, flags); + if (bspcm->pcm_irq_pos >= bspcm->pcm_count) { + bspcm->pcm_irq_pos %= bspcm->pcm_count; + spin_unlock_irqrestore(&bspcm->lock, flags); + snd_pcm_period_elapsed(bspcm->substream); + } else + spin_unlock_irqrestore(&bspcm->lock, flags); +} + +static snd_pcm_uframes_t +snd_card_bt_sco_playback_pointer(struct snd_pcm_substream * substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + snd_card_bt_sco_pcm_t *bspcm = runtime->private_data; + + return bytes_to_frames(runtime, bspcm->pcm_buf_pos); +} + +static snd_pcm_uframes_t +snd_card_bt_sco_capture_pointer(struct snd_pcm_substream * substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + snd_card_bt_sco_pcm_t *bspcm = runtime->private_data; + + return bytes_to_frames(runtime, bspcm->pcm_buf_pos); +} + +static struct snd_pcm_hardware snd_card_bt_sco_playback = { + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_8000, + .rate_min = 8000, + .rate_max = 8000, + .channels_min = 1, + .channels_max = 1, + .buffer_bytes_max = MAX_BUFFER_SIZE, + .period_bytes_min = 24, + .period_bytes_max = MAX_BUFFER_SIZE, + .periods_min = 1, + .periods_max = 4 * 8000 / 24, + .fifo_size = 0, +}; + +static struct snd_pcm_hardware snd_card_bt_sco_capture = { + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_8000, + .rate_min = 8000, + .rate_max = 8000, + .channels_min = 1, + .channels_max = 1, + .buffer_bytes_max = MAX_BUFFER_SIZE, + .period_bytes_min = 24, + .period_bytes_max = MAX_BUFFER_SIZE, + .periods_min = 1, + .periods_max = 4 * 8000 / 24, + .fifo_size = 0, +}; + +static void snd_card_bt_sco_runtime_free(struct snd_pcm_runtime * runtime) +{ + snd_card_bt_sco_pcm_t *bspcm = runtime->private_data; + kfree(bspcm); +} + +static int snd_card_bt_sco_playback_open(struct snd_pcm_substream * substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + snd_card_bt_sco_pcm_t *bspcm; + snd_card_bt_sco_t *bt_sco = snd_pcm_substream_chip(substream); + + dprintk("playback_open\n"); + + bspcm = kmalloc(sizeof(*bspcm), GFP_KERNEL); + if (bspcm == NULL) + return -ENOMEM; + memset(bspcm, 0, sizeof(*bspcm)); + if ((runtime->dma_area = + snd_malloc_pages(MAX_BUFFER_SIZE, GFP_KERNEL)) == NULL) { + kfree(bspcm); + return -ENOMEM; + } + runtime->dma_bytes = MAX_BUFFER_SIZE; + spin_lock_init(&bspcm->lock); + bspcm->substream = substream; + runtime->private_data = bspcm; + runtime->private_free = snd_card_bt_sco_runtime_free; + runtime->hw = snd_card_bt_sco_playback; + + atomic_inc(&bt_sco->playback_count); + spin_lock_irq(&bt_sco->count_changed_lock); + bt_sco->count_changed = 1; + spin_unlock_irq(&bt_sco->count_changed_lock); + wake_up(&bt_sco->hwdep_wait); + + return 0; +} + +static int snd_card_bt_sco_capture_open(struct snd_pcm_substream * substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + snd_card_bt_sco_pcm_t *bspcm; + snd_card_bt_sco_t *bt_sco = snd_pcm_substream_chip(substream); + + dprintk("capture_open\n"); + + bspcm = kmalloc(sizeof(*bspcm), GFP_KERNEL); + if (bspcm == NULL) + return -ENOMEM; + memset(bspcm, 0, sizeof(*bspcm)); + if ((runtime->dma_area = + snd_malloc_pages(MAX_BUFFER_SIZE, GFP_KERNEL)) == NULL) { + kfree(bspcm); + return -ENOMEM; + } + runtime->dma_bytes = MAX_BUFFER_SIZE; + memset(runtime->dma_area, 0, runtime->dma_bytes); + spin_lock_init(&bspcm->lock); + bspcm->substream = substream; + runtime->private_data = bspcm; + runtime->private_free = snd_card_bt_sco_runtime_free; + runtime->hw = snd_card_bt_sco_capture; + + atomic_inc(&bt_sco->capture_count); + spin_lock_irq(&bt_sco->count_changed_lock); + bt_sco->count_changed = 1; + spin_unlock_irq(&bt_sco->count_changed_lock); + wake_up(&bt_sco->hwdep_wait); + + return 0; +} + +static int snd_card_bt_sco_playback_close(struct snd_pcm_substream * substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + snd_card_bt_sco_t *bt_sco = snd_pcm_substream_chip(substream); + + snd_assert(bt_sco->playback == NULL,; + ); + + /* Ensure any references to this in our thread have finished */ + mutex_lock(&bt_sco->playback_sem); + mutex_unlock(&bt_sco->playback_sem); + + atomic_dec(&bt_sco->playback_count); + spin_lock_irq(&bt_sco->count_changed_lock); + bt_sco->count_changed = 1; + spin_unlock_irq(&bt_sco->count_changed_lock); + wake_up(&bt_sco->hwdep_wait); + + snd_free_pages(runtime->dma_area, runtime->dma_bytes); + return 0; +} + +static int snd_card_bt_sco_capture_close(struct snd_pcm_substream * substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_card_bt_sco *bt_sco = + (struct snd_card_bt_sco *)substream->private_data; + + snd_assert(bt_sco->capture == NULL,; + ); + + /* Ensure any references to this in our thread have finished */ + mutex_lock(&bt_sco->capture_sem); + mutex_unlock(&bt_sco->capture_sem); + + atomic_dec(&bt_sco->capture_count); + spin_lock_irq(&bt_sco->count_changed_lock); + bt_sco->count_changed = 1; + spin_unlock_irq(&bt_sco->count_changed_lock); + wake_up(&bt_sco->hwdep_wait); + + snd_free_pages(runtime->dma_area, runtime->dma_bytes); + return 0; +} + +static struct snd_pcm_ops snd_card_bt_sco_playback_ops = { + .open = snd_card_bt_sco_playback_open, + .close = snd_card_bt_sco_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .prepare = snd_card_bt_sco_playback_prepare, + .trigger = snd_card_bt_sco_playback_trigger, + .pointer = snd_card_bt_sco_playback_pointer, +}; + +static struct snd_pcm_ops snd_card_bt_sco_capture_ops = { + .open = snd_card_bt_sco_capture_open, + .close = snd_card_bt_sco_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .prepare = snd_card_bt_sco_capture_prepare, + .trigger = snd_card_bt_sco_capture_trigger, + .pointer = snd_card_bt_sco_capture_pointer, +}; + +static int __init snd_card_bt_sco_pcm(snd_card_bt_sco_t * bt_sco) +{ + struct snd_pcm *pcm; + int err; + + if ((err = + snd_pcm_new(bt_sco->card, "Bluetooth SCO PCM", 0, 1, 1, &pcm)) < 0) + return err; + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_card_bt_sco_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_card_bt_sco_capture_ops); + pcm->private_data = bt_sco; + pcm->info_flags = 0; + strcpy(pcm->name, "BT SCO PCM"); + return 0; +} + +#define BT_SCO_VOLUME(xname, xindex, addr) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .info = snd_bt_sco_volume_info, \ + .get = snd_bt_sco_volume_get, .put = snd_bt_sco_volume_put, \ + .private_value = addr } + +static int snd_bt_sco_volume_info(struct snd_kcontrol * kcontrol, + struct snd_ctl_elem_info * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = MIXER_MIN_VOLUME; + uinfo->value.integer.max = MIXER_MAX_VOLUME; + return 0; +} + +static int snd_bt_sco_volume_get(struct snd_kcontrol * kcontrol, + struct snd_ctl_elem_value * ucontrol) +{ + snd_card_bt_sco_t *bt_sco = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int addr = kcontrol->private_value; + + spin_lock_irqsave(&bt_sco->mixer_lock, flags); + ucontrol->value.integer.value[0] = bt_sco->mixer_volume[addr]; + spin_unlock_irqrestore(&bt_sco->mixer_lock, flags); + return 0; +} + +static int snd_bt_sco_volume_put(struct snd_kcontrol * kcontrol, + struct snd_ctl_elem_value * ucontrol) +{ + snd_card_bt_sco_t *bt_sco = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int changed, addr = kcontrol->private_value; + int vol; + + vol = ucontrol->value.integer.value[0]; + if (vol < MIXER_MIN_VOLUME) + vol = MIXER_MIN_VOLUME; + if (vol > MIXER_MAX_VOLUME) + vol = MIXER_MAX_VOLUME; + spin_lock_irqsave(&bt_sco->mixer_lock, flags); + changed = bt_sco->mixer_volume[addr] != vol; + bt_sco->mixer_volume[addr] = vol; + spin_unlock_irqrestore(&bt_sco->mixer_lock, flags); + if (changed) { + spin_lock_irqsave(&bt_sco->mixer_changed_lock, flags); + bt_sco->mixer_changed = 1; + spin_unlock_irqrestore(&bt_sco->mixer_changed_lock, flags); + wake_up(&bt_sco->hwdep_wait); + } + return changed; +} + +static int snd_bt_sco_boolean_info(struct snd_kcontrol * kcontrol, + struct snd_ctl_elem_info * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_bt_sco_loopback_get(struct snd_kcontrol * kcontrol, + struct snd_ctl_elem_value * ucontrol) +{ + snd_card_bt_sco_t *bt_sco = snd_kcontrol_chip(kcontrol); + unsigned long flags; + + spin_lock_irqsave(&bt_sco->mixer_lock, flags); + ucontrol->value.integer.value[0] = bt_sco->loopback; + spin_unlock_irqrestore(&bt_sco->mixer_lock, flags); + return 0; +} + +static int snd_bt_sco_loopback_put(struct snd_kcontrol * kcontrol, + struct snd_ctl_elem_value * ucontrol) +{ + snd_card_bt_sco_t *bt_sco = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int changed; + int loopback; + + loopback = !!ucontrol->value.integer.value[0]; + + spin_lock_irqsave(&bt_sco->mixer_lock, flags); + changed = bt_sco->loopback != loopback; + bt_sco->loopback = loopback; + spin_unlock_irqrestore(&bt_sco->mixer_lock, flags); + return changed; +} + +#ifdef DYNAMIC_COMPRESSION +static int snd_bt_sco_agc_get(struct snd_kcontrol * kcontrol, + struct snd_ctl_elem_value * ucontrol) +{ + snd_card_bt_sco_t *bt_sco = snd_kcontrol_chip(kcontrol); + unsigned long flags; + + spin_lock_irqsave(&bt_sco->mixer_lock, flags); + ucontrol->value.integer.value[0] = bt_sco->agc; + spin_unlock_irqrestore(&bt_sco->mixer_lock, flags); + return 0; +} + +static int snd_bt_sco_agc_put(struct snd_kcontrol * kcontrol, + struct snd_ctl_elem_value * ucontrol) +{ + snd_card_bt_sco_t *bt_sco = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int changed; + int agc; + + agc = !!ucontrol->value.integer.value[0]; + + spin_lock_irqsave(&bt_sco->mixer_lock, flags); + changed = bt_sco->agc != agc; + bt_sco->agc = agc; + spin_unlock_irqrestore(&bt_sco->mixer_lock, flags); + return changed; +} +#endif + +#define BT_SCO_CONTROLS (sizeof(snd_bt_sco_controls)/sizeof(struct snd_kcontrol_new)) + +static struct snd_kcontrol_new snd_bt_sco_controls[] = { + BT_SCO_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER), + BT_SCO_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC), + {.iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Loopback Switch", + .index = 0, + .info = snd_bt_sco_boolean_info, + .get = snd_bt_sco_loopback_get, + .put = snd_bt_sco_loopback_put, + } +#ifdef DYNAMIC_COMPRESSION + , + {.iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "AGC Switch", + .index = 0, + .info = snd_bt_sco_boolean_info, + .get = snd_bt_sco_agc_get, + .put = snd_bt_sco_agc_put, + } +#endif +}; + +int __init snd_card_bt_sco_new_mixer(snd_card_bt_sco_t * bt_sco) +{ + struct snd_card *card = bt_sco->card; + + unsigned int idx; + int err; + + snd_assert(bt_sco != NULL, return -EINVAL); + spin_lock_init(&bt_sco->mixer_lock); + strcpy(card->mixername, "BT Headset Mixer"); + + for (idx = 0; idx < BT_SCO_CONTROLS; idx++) { + bt_sco->mixer_controls[idx] = + snd_ctl_new1(&snd_bt_sco_controls[idx], bt_sco); + + if ((err = snd_ctl_add(card, bt_sco->mixer_controls[idx])) < 0) + return err; + } + return 0; +} + +static int snd_card_bt_open(struct snd_hwdep * hw, struct file *file) +{ + return 0; +} + +static int snd_card_bt_release(struct snd_hwdep * hw, struct file *file) +{ + return 0; +} + +static int snd_card_bt_ioctl(struct snd_hwdep * hw, struct file *file, + unsigned int cmd, unsigned long arg) +{ + snd_card_bt_sco_t *bt_sco = hw->card->private_data; + struct socket *sock; + int err = -ENOTTY; + int fd = arg; + + switch (cmd) { + case SNDRV_BT_SCO_IOCTL_SET_SCO_SOCKET: + err = 0; + /* Interrupt any socket operations, so that we may + * change the socket */ + mutex_lock(&bt_sco->sock_sem); + kthread_stop(bt_sco->thread); + if (bt_sco->sco_sock) { + dprintk("Disposing of previous socket count %d\n", + file_count(bt_sco->sco_sock->file)); + /* Extra brackets needed here since sockfd_put is a poorly implemented macro */ + sockfd_put(((struct socket *)bt_sco->sco_sock)); + + bt_sco->sco_sock = NULL; + } + + if (fd >= 0) { + err = -EINVAL; + sock = sockfd_lookup(fd, &err); + if (sock) { + if (sock->sk->sk_family == PF_BLUETOOTH && + sock->sk->sk_protocol == BTPROTO_SCO) { + bt_sco->sco_sock = sock; + wake_up(&bt_sco->wait); + err = 0; + } else { + dprintk + ("Not a bluetooth SCO socket %d:%d\n", + sock->sk->sk_family, + sock->sk->sk_protocol); + sockfd_put(sock); + } + } + } + mutex_unlock(&bt_sco->sock_sem); + break; + case SNDRV_BT_SCO_IOCTL_REQ_INFO: + spin_lock_irq(&bt_sco->count_changed_lock); + bt_sco->count_changed = 1; + spin_unlock_irq(&bt_sco->count_changed_lock); + wake_up(&bt_sco->hwdep_wait); + break; + } + return err; +} + +static long snd_card_bt_write(struct snd_hwdep * hw, const char *buf, long count, + loff_t * offset) +{ + snd_card_bt_sco_t *bt_sco = hw->card->private_data; + int mixer_volume[MIXER_ADDR_LAST + 1]; + int retval; + int i; + + if (count != sizeof(mixer_volume)) + return -EINVAL; + + if (copy_from_user(mixer_volume, buf, sizeof(mixer_volume))) + return -EFAULT; + + retval = sizeof(mixer_volume); + + spin_lock_irq(&bt_sco->mixer_lock); + for (i = 0; i <= MIXER_ADDR_LAST; i++) { + int vol = mixer_volume[i]; + if (vol > MIXER_MAX_VOLUME) + vol = MIXER_MAX_VOLUME; + if (vol < MIXER_MIN_VOLUME) + vol = MIXER_MIN_VOLUME; + if (bt_sco->mixer_volume[i] != vol) { + bt_sco->mixer_volume[i] = vol; + snd_ctl_notify(bt_sco->card, + SNDRV_CTL_EVENT_MASK_VALUE, + &bt_sco->mixer_controls[i]->id); + } + } + spin_unlock_irq(&bt_sco->mixer_lock); + + return retval; +} + +static long snd_card_bt_read(struct snd_hwdep * hw, char *buf, long count, + loff_t * offset) +{ + snd_card_bt_sco_t *bt_sco = hw->card->private_data; + DECLARE_WAITQUEUE(wait, current); + ssize_t retval; + int changed; + snd_card_bt_sco_info_t infobuf; + + if (count < sizeof(bt_sco->mixer_volume)) + return -EINVAL; + + add_wait_queue(&bt_sco->hwdep_wait, &wait); + current->state = TASK_INTERRUPTIBLE; + do { + changed = 0; + spin_lock_irq(&bt_sco->mixer_changed_lock); + if(bt_sco->mixer_changed) + changed = 1; + bt_sco->mixer_changed = 0; + spin_unlock_irq(&bt_sco->mixer_changed_lock); + + spin_lock_irq(&bt_sco->count_changed_lock); + if(bt_sco->count_changed) + changed = 1; + bt_sco->count_changed = 0; + spin_unlock_irq(&bt_sco->count_changed_lock); + + if (changed != 0) + break; + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + schedule(); + } while (1); + + memcpy(infobuf.mixer_volume, bt_sco->mixer_volume, sizeof(infobuf.mixer_volume)); + infobuf.playback_count = atomic_read(&bt_sco->playback_count); + infobuf.capture_count = atomic_read(&bt_sco->capture_count); + + if (copy_to_user + (buf, &infobuf, sizeof(infobuf))) + retval = -EFAULT; + else + retval = sizeof(infobuf); + + out: + current->state = TASK_RUNNING; + remove_wait_queue(&bt_sco->hwdep_wait, &wait); + return retval; +} + +static unsigned int snd_card_bt_poll(struct snd_hwdep * hw, + struct file *file, poll_table * wait) +{ + snd_card_bt_sco_t *bt_sco = hw->card->private_data; + int ret; + + poll_wait(file, &bt_sco->hwdep_wait, wait); + + ret = 0; + spin_lock_irq(&bt_sco->mixer_changed_lock); + if(bt_sco->mixer_changed) + ret |= POLLIN | POLLRDNORM; + spin_unlock_irq(&bt_sco->mixer_changed_lock); + + spin_lock_irq(&bt_sco->count_changed_lock); + if(bt_sco->count_changed) + ret |= POLLIN | POLLRDNORM; + spin_unlock_irq(&bt_sco->count_changed_lock); + + return ret; +} + +static int snd_card_bt_sco_thread(void *data) +{ + struct snd_card *card = (struct snd_card *) data; + snd_card_bt_sco_t *bt_sco = card->private_data; + struct socket *sock; + int len; +#define BUF_SIZE 256 + unsigned char buf[BUF_SIZE]; + struct msghdr msg; + struct iovec iov; +#if defined(DYNAMIC_COMPRESSION) || defined(AUTO_FIXUP_BYTESHIFT) + int i; +#endif +#ifdef DYNAMIC_COMPRESSION + static int factor=16; + static int maxvalsmoothed=0; + static int maxvalgrablen=GRABSAMPLES; /* adjust volume at most 4 times/second */ +#endif +#ifdef AUTO_FIXUP_BYTESHIFT + static int shift=0; + static unsigned char lastbyte; +#endif + + set_freezable(); + + dprintk("snd-bt-scod thread starting\n"); + mutex_unlock(&bt_sco->thread_sem); + + do { + /* This may be woken up by a wake_up() when + * a new socket is installed, or by a signal. + * Signals are sent to terminate the thread, + * in which case thread_exit is set, and to force + * recvmesg() to wake up (from the ioctl handler) + */ + wait_event_freezable(bt_sco->wait, bt_sco->sco_sock || kthread_should_stop()); + + mutex_lock(&bt_sco->sock_sem); + sock = (struct socket *)bt_sco->sco_sock; + if (sock) + get_file(sock->file); + mutex_unlock(&bt_sco->sock_sem); + + if (!sock) + continue; + + /* We have a socket, let's read from it and write to it... */ + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &iov; + iov.iov_base = buf; + iov.iov_len = BUF_SIZE; + + /* This will block until we receive data or a signal */ + len = sock_recvmsg(sock, &msg, BUF_SIZE, 0); + if (len > 0) { + +#if defined (AUTO_FIXUP_BYTESHIFT) || defined (DYNAMIC_COMPRESSION) + +#ifdef AUTO_FIXUP_BYTESHIFT + int lostatcnt=0; +#endif + if (len&1) dprintk("odd len %d\n",len); +#ifdef AUTO_FIXUP_BYTESHIFT + if (shift) { + unsigned char newlastbyte; + newlastbyte=buf[len-1]; + memmove(buf+1,buf,len-1); + buf[0]=lastbyte; + lastbyte=newlastbyte; + } +#endif + for(i=0;i0x7fff) { + k=0x7fff; + if (bt_sco->agc&&factor>COMPRESSION_MIN_16) factor--; + } else if (k<-0x8000) { + k=0x8000; + if (bt_sco->agc&&factor>COMPRESSION_MIN_16) factor--; + } + buf[i+1]=(k>>8)&0xff; + buf[i ]=k&0xff; + + /* find the highest absolute value in a + * GRABSAMPLES long interval. + */ + if (k<0) k=-j; + if (k>maxvalsmoothed) maxvalsmoothed=k; + /* if the interval is over, recalculate + * the compression factor. Move it slowly. + */ + if (maxvalgrablen--<=0) { + maxvalgrablen=GRABSAMPLES; + /* If the noise goes up over 1000, we stop + * pushing the software gain + */ + if (maxvalsmoothed<1000&&factoragc) factor=16; + maxvalsmoothed=0; + } +#endif + } +#ifdef AUTO_FIXUP_BYTESHIFT + if (lostatcnt==len/2&&len>32) { + shift=!shift; + //dprintk("Shift problem detected! Fixing to %d.\n",shift); + } +#endif +#endif /* any of them */ + mutex_lock(&bt_sco->capture_sem); + if (bt_sco->capture) { + snd_card_bt_sco_pcm_receive + (bt_sco->capture, buf, len); + } + mutex_unlock(&bt_sco->capture_sem); + + mutex_lock(&bt_sco->playback_sem); + + if (bt_sco->playback || !bt_sco->loopback) { + memset(buf, 0, len); +#if 0 + /* fill with tone instead of silence */ + int i; + + for (i = 0; i < len / 2; i++) { + buf[i] = 0; + } + for (i = len / 2; i < len; i++) { + buf[i] = 127; + } +#endif + } + if (bt_sco->playback) { + int i, notzero = -1; + + snd_card_bt_sco_pcm_send + (bt_sco->playback, buf, len); + + /* Strangely, when the device is open but no audio is + being written by the app, there's an occasional glitch + in the silence data. This hack eliminates it. */ + + for (i = 0; i < len; i++) { + if (buf[i] != 0) { + if (notzero >= 0) + break; + notzero = i; + } + } + if (notzero >= 0 && i >= len) { + buf[notzero] = 0; + } + } + mutex_unlock(&bt_sco->playback_sem); + +#if 0 + /* This chunk of code lets us record (using arecord) + what data alsa is sending out. + + e.g., when idle, we'd expect something like: + + 8080 8080 8080 8080 8483 8281 8182 8384 + 8080 8080 8080 8080 8080 8080 8080 8080 + 8080 8080 8080 8080 8483 8281 8182 8384 + 8080 8080 8080 8080 8080 8080 8080 8080 + + (this is from 'xxd' of a wav file, that data in + which is unsigned, whereas we are dealing with signed). + */ + + mutex_lock(&bt_sco->capture_sem); + if (bt_sco->capture) { + snd_card_bt_sco_pcm_receive + (bt_sco->capture, "\001\002\003\004", 4); + snd_card_bt_sco_pcm_receive + (bt_sco->capture, buf, len); + snd_card_bt_sco_pcm_receive + (bt_sco->capture, "\004\003\002\001", 4); + } + mutex_unlock(&bt_sco->capture_sem); +#endif + msg.msg_flags = 0; + msg.msg_iov = &iov; + iov.iov_base = buf; + iov.iov_len = BUF_SIZE; + sock_sendmsg(sock, &msg, len); + } + + /* Expect this to be 3 because we (this thead) have a copy, + the driver process keeps one, and the app has the socket open. + */ + if (file_count(sock->file) != 3) { + dprintk("file_count is %d (expected 3)\n", + file_count(sock->file)); + } + fput(sock->file); + + schedule(); + } while (!kthread_should_stop() || bt_sco->sco_sock); + + dprintk("thread exiting\n"); + + return 0; +} + +static void snd_card_bt_private_free(struct snd_card * card) +{ + snd_card_bt_sco_t *bt_sco = card->private_data; + + dprintk("private_free, killing thread\n"); + kthread_stop(bt_sco->thread); + dprintk("private_free, thread exited\n"); + + if (bt_sco->sco_sock) { + dprintk("shutdown: freeing socket count %d\n", + file_count(bt_sco->sco_sock->file)); + + sockfd_put(((struct socket *)bt_sco->sco_sock)); + } + + kfree(bt_sco); +} + +static int __init snd_card_bt_sco_probe(int dev) +{ + struct snd_card *card; + snd_card_bt_sco_t *bt_sco; + int err; + struct snd_hwdep *hw; + + card = + snd_card_new(index[dev], SNDRV_DEFAULT_STR1, + THIS_MODULE, 0); + if (card == NULL) + return -ENOMEM; + + bt_sco = kmalloc(sizeof(*bt_sco), GFP_KERNEL); + if(bt_sco == NULL) + return -ENOMEM; + memset(bt_sco, 0, sizeof(*bt_sco)); + card->private_data = bt_sco; + card->private_free = snd_card_bt_private_free; + + bt_sco->card = card; + + mutex_init(&bt_sco->thread_sem); + mutex_lock(&bt_sco->thread_sem); + mutex_init(&bt_sco->sock_sem); + mutex_init(&bt_sco->capture_sem); + mutex_init(&bt_sco->playback_sem); + init_waitqueue_head(&bt_sco->wait); + init_waitqueue_head(&bt_sco->hwdep_wait); + spin_lock_init(&bt_sco->mixer_changed_lock); + spin_lock_init(&bt_sco->count_changed_lock); + + /* These clone flags copied from some other driver. + Not sure that they're really correct... */ + bt_sco->thread = + kthread_run(snd_card_bt_sco_thread, card, "snd-bt-scod"); + if (IS_ERR(bt_sco->thread)) { + err = PTR_ERR(bt_sco->thread); + goto __nodev; + } + + mutex_lock(&bt_sco->thread_sem); + + if ((err = snd_card_bt_sco_pcm(bt_sco)) < 0) + goto __nodev; + if ((err = snd_card_bt_sco_new_mixer(bt_sco)) < 0) + goto __nodev; + strcpy(card->driver, "Bluetooth SCO"); + strcpy(card->shortname, "BT Headset"); + sprintf(card->longname, "BT Headset %i", dev + 1); + + err = snd_hwdep_new(card, "BTSCO", 0, &hw); + if (err < 0) + goto __nodev; + + sprintf(hw->name, "BTSCO"); + hw->iface = SNDRV_HWDEP_IFACE_BT_SCO; + hw->ops.open = snd_card_bt_open; + hw->ops.ioctl = snd_card_bt_ioctl; + hw->ops.release = snd_card_bt_release; + hw->ops.read = snd_card_bt_read; + hw->ops.write = snd_card_bt_write; + hw->ops.poll = snd_card_bt_poll; + + if ((err = snd_card_register(card)) == 0) { + snd_bt_sco_cards[dev] = card; + return 0; + } + __nodev: + snd_card_free(card); + return err; +} + +static int __init alsa_card_bt_sco_init(void) +{ + printk(KERN_INFO "snd-bt-sco revision %s\n", mod_revision + 11); + + if (snd_card_bt_sco_probe(0) < 0) { +#ifdef MODULE + printk(KERN_ERR + "Bluetooth SCO soundcard not found or device busy\n"); +#endif + return -ENODEV; + } + return 0; +} + +static void __exit alsa_card_bt_sco_exit(void) +{ + int idx; + + for (idx = 0; idx < SNDRV_CARDS; idx++) + snd_card_free(snd_bt_sco_cards[idx]); +} + +module_init(alsa_card_bt_sco_init) + module_exit(alsa_card_bt_sco_exit) +#ifndef MODULE +static int __init alsa_card_bt_sco_setup(char *str) +{ + static unsigned __initdata nr_dev = 0; + + if (nr_dev >= SNDRV_CARDS) + return 0; + nr_dev++; + return 1; +} + +__setup("snd-bt-sco=", alsa_card_bt_sco_setup); + +#endif /* ifndef MODULE */ --- linux-2.6.27.orig/ubuntu/misc/media/Kconfig +++ linux-2.6.27/ubuntu/misc/media/Kconfig @@ -0,0 +1,13 @@ +menu "Media related drivers" + +config SND_BTSCO + tristate "Bluetooth SCO Sound driver" + default m + depends on SND && BT + +config USB_OV511_NEW + tristate "OmniVision OV511 Camera-to-USB Bridge Driver" + default m + depends on USB && VIDEO_V4L2 + +endmenu --- linux-2.6.27.orig/ubuntu/misc/media/Makefile +++ linux-2.6.27/ubuntu/misc/media/Makefile @@ -0,0 +1,4 @@ +# + +obj-$(CONFIG_SND_BTSCO) += snd-bt-sco.o +obj-$(CONFIG_USB_OV511_NEW) += ov511/ --- linux-2.6.27.orig/ubuntu/misc/media/ov511/ov511.c +++ linux-2.6.27/ubuntu/misc/media/ov511/ov511.c @@ -0,0 +1,6123 @@ +/* + * OmniVision OV511 Camera-to-USB Bridge Driver + * + * Copyright (c) 1999-2003 Mark W. McClelland + * Original decompression code Copyright 1998-2000 OmniVision Technologies + * Many improvements by Bret Wallach + * Color fixes by by Orion Sky Lawlor (2/26/2000) + * Snapshot code by Kevin Moore + * OV7620 fixes by Charl P. Botha + * Changes by Claudio Matsuoka + * Original SAA7111A code by Dave Perks + * URB error messages from pwc driver by Nemosoft + * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox + * Memory management (rvmalloc) code from bttv driver, by Gerd Knorr and others + * + * Based on the Linux CPiA driver written by Peter Pregler, + * Scott J. Bertin and Johannes Erdfelt. + * + * Please see the file: Documentation/usb/ov511.txt + * and the website at: http://alpha.dyndns.org/ov511 + * for more info. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined (__i386__) + #include +#endif + +#include "ov511.h" + +/* + * Version Information + */ +#define DRIVER_VERSION "v1.64 for Linux 2.5" +#define EMAIL "mark@alpha.dyndns.org" +#define DRIVER_AUTHOR "Mark McClelland & Bret Wallach \ + & Orion Sky Lawlor & Kevin Moore & Charl P. Botha \ + & Claudio Matsuoka " +#define DRIVER_DESC "ov511 USB Camera Driver" + +#define OV511_I2C_RETRIES 3 +#define ENABLE_Y_QUANTABLE 1 +#define ENABLE_UV_QUANTABLE 1 + +#define OV511_MAX_UNIT_VIDEO 16 + +/* Pixel count * bytes per YUV420 pixel (1.5) */ +#define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3 / 2) + +#define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval)) + +/* Max size * bytes per YUV420 pixel (1.5) + one extra isoc frame for safety */ +#define MAX_RAW_DATA_SIZE(w, h) ((w) * (h) * 3 / 2 + 1024) + +#define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM) + +/********************************************************************** + * Module Parameters + * (See ov511.txt for detailed descriptions of these) + **********************************************************************/ + +/* These variables (and all static globals) default to zero */ +static int autobright = 1; +static int autogain = 1; +static int autoexp = 1; +static int debug; +static int snapshot; +static int cams = 1; +static int compress; +static int testpat; +static int dumppix; +static int led = 1; +static int dump_bridge; +static int dump_sensor; +static int printph; +static int phy = 0x1f; +static int phuv = 0x05; +static int pvy = 0x06; +static int pvuv = 0x06; +static int qhy = 0x14; +static int qhuv = 0x03; +static int qvy = 0x04; +static int qvuv = 0x04; +static int lightfreq; +static int bandingfilter; +static int clockdiv = -1; +static int packetsize = -1; +static int framedrop = -1; +static int fastset; +static int force_palette; +static int backlight; +static int unit_video[OV511_MAX_UNIT_VIDEO]; +static int remove_zeros; +static int mirror; +static int ov518_color; + +module_param(autobright, int, 0); +MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness"); +module_param(autogain, int, 0); +MODULE_PARM_DESC(autogain, "Sensor automatically changes gain"); +module_param(autoexp, int, 0); +MODULE_PARM_DESC(autoexp, "Sensor automatically changes exposure"); +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, + "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max"); +module_param(snapshot, int, 0); +MODULE_PARM_DESC(snapshot, "Enable snapshot mode"); +module_param(cams, int, 0); +MODULE_PARM_DESC(cams, "Number of simultaneous cameras"); +module_param(compress, int, 0); +MODULE_PARM_DESC(compress, "Turn on compression"); +module_param(testpat, int, 0); +MODULE_PARM_DESC(testpat, + "Replace image with vertical bar testpattern (only partially working)"); +module_param(dumppix, int, 0); +MODULE_PARM_DESC(dumppix, "Dump raw pixel data"); +module_param(led, int, 0); +MODULE_PARM_DESC(led, + "LED policy (OV511+ or later). 0=off, 1=on (default), 2=auto (on when open)"); +module_param(dump_bridge, int, 0); +MODULE_PARM_DESC(dump_bridge, "Dump the bridge registers"); +module_param(dump_sensor, int, 0); +MODULE_PARM_DESC(dump_sensor, "Dump the sensor registers"); +module_param(printph, int, 0); +MODULE_PARM_DESC(printph, "Print frame start/end headers"); +module_param(phy, int, 0); +MODULE_PARM_DESC(phy, "Prediction range (horiz. Y)"); +module_param(phuv, int, 0); +MODULE_PARM_DESC(phuv, "Prediction range (horiz. UV)"); +module_param(pvy, int, 0); +MODULE_PARM_DESC(pvy, "Prediction range (vert. Y)"); +module_param(pvuv, int, 0); +MODULE_PARM_DESC(pvuv, "Prediction range (vert. UV)"); +module_param(qhy, int, 0); +MODULE_PARM_DESC(qhy, "Quantization threshold (horiz. Y)"); +module_param(qhuv, int, 0); +MODULE_PARM_DESC(qhuv, "Quantization threshold (horiz. UV)"); +module_param(qvy, int, 0); +MODULE_PARM_DESC(qvy, "Quantization threshold (vert. Y)"); +module_param(qvuv, int, 0); +MODULE_PARM_DESC(qvuv, "Quantization threshold (vert. UV)"); +module_param(lightfreq, int, 0); +MODULE_PARM_DESC(lightfreq, + "Light frequency. Set to 50 or 60 Hz, or zero for default settings"); +module_param(bandingfilter, int, 0); +MODULE_PARM_DESC(bandingfilter, + "Enable banding filter (to reduce effects of fluorescent lighting)"); +module_param(clockdiv, int, 0); +MODULE_PARM_DESC(clockdiv, "Force pixel clock divisor to a specific value"); +module_param(packetsize, int, 0); +MODULE_PARM_DESC(packetsize, "Force a specific isoc packet size"); +module_param(framedrop, int, 0); +MODULE_PARM_DESC(framedrop, "Force a specific frame drop register setting"); +module_param(fastset, int, 0); +MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately"); +module_param(force_palette, int, 0); +MODULE_PARM_DESC(force_palette, "Force the palette to a specific value"); +module_param(backlight, int, 0); +MODULE_PARM_DESC(backlight, "For objects that are lit from behind"); +static int num_uv; +module_param_array(unit_video, int, &num_uv, 0); +MODULE_PARM_DESC(unit_video, + "Force use of specific minor number(s). 0 is not allowed."); +module_param(remove_zeros, int, 0); +MODULE_PARM_DESC(remove_zeros, + "Remove zero-padding from uncompressed incoming data"); +module_param(mirror, int, 0); +MODULE_PARM_DESC(mirror, "Reverse image horizontally"); +module_param(ov518_color, int, 0); +MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)"); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/********************************************************************** + * Miscellaneous Globals + **********************************************************************/ + +static struct usb_driver ov511_driver; + +static struct ov51x_decomp_ops *ov511_decomp_ops; +static struct ov51x_decomp_ops *ov511_mmx_decomp_ops; +static struct ov51x_decomp_ops *ov518_decomp_ops; +static struct ov51x_decomp_ops *ov518_mmx_decomp_ops; + +/* Number of times to retry a failed I2C transaction. Increase this if you + * are getting "Failed to read sensor ID..." */ +static int i2c_detect_tries = 5; + +/* MMX support is present in kernel and CPU. Checked upon decomp module load. */ +#if defined(__i386__) || defined(__x86_64__) +#define ov51x_mmx_available (cpu_has_mmx) +#else +#define ov51x_mmx_available (0) +#endif + +static struct usb_device_id device_table [] = { + { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) }, + { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) }, + { USB_DEVICE(VEND_OMNIVISION, PROD_OV518) }, + { USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) }, + { USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, device_table); + +static unsigned char yQuanTable511[] = OV511_YQUANTABLE; +static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE; +static unsigned char yQuanTable518[] = OV518_YQUANTABLE; +static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE; + +/********************************************************************** + * Symbolic Names + **********************************************************************/ + +/* Known OV511-based cameras */ +static struct symbolic_list camlist[] = { + { 0, "Generic Camera (no ID)" }, + { 1, "Mustek WCam 3X" }, + { 3, "D-Link DSB-C300" }, + { 4, "Generic OV511/OV7610" }, + { 5, "Puretek PT-6007" }, + { 6, "Lifeview USB Life TV (NTSC)" }, + { 21, "Creative Labs WebCam 3" }, + { 22, "Lifeview USB Life TV (PAL D/K+B/G)" }, + { 36, "Koala-Cam" }, + { 38, "Lifeview USB Life TV (PAL)" }, + { 41, "Samsung Anycam MPC-M10" }, + { 43, "Mtekvision Zeca MV402" }, + { 46, "Suma eON" }, + { 70, "Lifeview USB Life TV (PAL/SECAM)" }, + { 100, "Lifeview RoboCam" }, + { 102, "AverMedia InterCam Elite" }, + { 112, "MediaForte MV300" }, /* or OV7110 evaluation kit */ + { 134, "Ezonics EZCam II" }, + { 192, "Webeye 2000B" }, + { 253, "Alpha Vision Tech. AlphaCam SE" }, + { -1, NULL } +}; + +/* Video4Linux1 Palettes */ +static struct symbolic_list v4l1_plist[] = { + { VIDEO_PALETTE_GREY, "GREY" }, + { VIDEO_PALETTE_HI240, "HI240" }, + { VIDEO_PALETTE_RGB565, "RGB565" }, + { VIDEO_PALETTE_RGB24, "RGB24" }, + { VIDEO_PALETTE_RGB32, "RGB32" }, + { VIDEO_PALETTE_RGB555, "RGB555" }, + { VIDEO_PALETTE_YUV422, "YUV422" }, + { VIDEO_PALETTE_YUYV, "YUYV" }, + { VIDEO_PALETTE_UYVY, "UYVY" }, + { VIDEO_PALETTE_YUV420, "YUV420" }, + { VIDEO_PALETTE_YUV411, "YUV411" }, + { VIDEO_PALETTE_RAW, "RAW" }, + { VIDEO_PALETTE_YUV422P,"YUV422P" }, + { VIDEO_PALETTE_YUV411P,"YUV411P" }, + { VIDEO_PALETTE_YUV420P,"YUV420P" }, + { VIDEO_PALETTE_YUV410P,"YUV410P" }, + { -1, NULL } +}; + +static struct symbolic_list brglist[] = { + { BRG_OV511, "OV511" }, + { BRG_OV511PLUS, "OV511+" }, + { BRG_OV518, "OV518" }, + { BRG_OV518PLUS, "OV518+" }, + { -1, NULL } +}; + +static struct symbolic_list senlist[] = { + { SEN_OV76BE, "OV76BE" }, + { SEN_OV7610, "OV7610" }, + { SEN_OV7620, "OV7620" }, + { SEN_OV7620AE, "OV7620AE" }, + { SEN_OV6620, "OV6620" }, + { SEN_OV6630, "OV6630" }, + { SEN_OV6630AE, "OV6630AE" }, + { SEN_OV6630AF, "OV6630AF" }, + { SEN_OV8600, "OV8600" }, + { SEN_KS0127, "KS0127" }, + { SEN_KS0127B, "KS0127B" }, + { SEN_SAA7111A, "SAA7111A" }, + { -1, NULL } +}; + +/* URB error codes: */ +static struct symbolic_list urb_errlist[] = { + { -ENOSR, "Buffer error (overrun)" }, + { -EPIPE, "Stalled (device not responding)" }, + { -EOVERFLOW, "Babble (bad cable?)" }, + { -EPROTO, "Bit-stuff error (bad cable?)" }, + { -EILSEQ, "CRC/Timeout" }, + { -ETIMEDOUT, "NAK (device does not respond)" }, + { -1, NULL } +}; + +/********************************************************************** + * Memory management + **********************************************************************/ +static void * +rvmalloc(unsigned long size) +{ + void *mem; + unsigned long adr; + + size = PAGE_ALIGN(size); + mem = vmalloc_32(size); + if (!mem) + return NULL; + + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr = (unsigned long) mem; + while (size > 0) { + SetPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + return mem; +} + +static void +rvfree(void *mem, unsigned long size) +{ + unsigned long adr; + + if (!mem) + return; + + adr = (unsigned long) mem; + while ((long) size > 0) { + ClearPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + vfree(mem); +} + +/********************************************************************** + * + * Register I/O + * + **********************************************************************/ + +/* Write an OV51x register */ +static int +reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) +{ + int rc; + + PDEBUG(5, "0x%02X:0x%02X", reg, value); + + down(&ov->cbuf_lock); + ov->cbuf[0] = value; + rc = usb_control_msg(ov->dev, + usb_sndctrlpipe(ov->dev, 0), + (ov->bclass == BCL_OV518)?1:2 /* REG_IO */, + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, (__u16)reg, &ov->cbuf[0], 1, 1000); + up(&ov->cbuf_lock); + + if (rc < 0) + err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc)); + + return rc; +} + +/* Read from an OV51x register */ +/* returns: negative is error, pos or zero is data */ +static int +reg_r(struct usb_ov511 *ov, unsigned char reg) +{ + int rc; + + down(&ov->cbuf_lock); + rc = usb_control_msg(ov->dev, + usb_rcvctrlpipe(ov->dev, 0), + (ov->bclass == BCL_OV518)?1:3 /* REG_IO */, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, (__u16)reg, &ov->cbuf[0], 1, 1000); + + if (rc < 0) { + err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc)); + } else { + rc = ov->cbuf[0]; + PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]); + } + + up(&ov->cbuf_lock); + + return rc; +} + +/* + * Writes bits at positions specified by mask to an OV51x reg. Bits that are in + * the same position as 1's in "mask" are cleared and set to "value". Bits + * that are in the same position as 0's in "mask" are preserved, regardless + * of their respective state in "value". + */ +static int +reg_w_mask(struct usb_ov511 *ov, + unsigned char reg, + unsigned char value, + unsigned char mask) +{ + int ret; + unsigned char oldval, newval; + + ret = reg_r(ov, reg); + if (ret < 0) + return ret; + + oldval = (unsigned char) ret; + oldval &= (~mask); /* Clear the masked bits */ + value &= mask; /* Enforce mask on value */ + newval = oldval | value; /* Set the desired bits */ + + return (reg_w(ov, reg, newval)); +} + +/* + * Writes multiple (n) byte value to a single register. Only valid with certain + * registers (0x30 and 0xc4 - 0xce). + */ +static int +ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n) +{ + int rc; + + PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n); + + down(&ov->cbuf_lock); + + *((__le32 *)ov->cbuf) = __cpu_to_le32(val); + + rc = usb_control_msg(ov->dev, + usb_sndctrlpipe(ov->dev, 0), + 1 /* REG_IO */, + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, (__u16)reg, ov->cbuf, n, 1000); + up(&ov->cbuf_lock); + + if (rc < 0) + err("reg write multiple: error %d: %s", rc, + symbolic(urb_errlist, rc)); + + return rc; +} + +static int +ov511_upload_quan_tables(struct usb_ov511 *ov) +{ + unsigned char *pYTable = yQuanTable511; + unsigned char *pUVTable = uvQuanTable511; + unsigned char val0, val1; + int i, rc, reg = R511_COMP_LUT_BEGIN; + + PDEBUG(4, "Uploading quantization tables"); + + for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) { + if (ENABLE_Y_QUANTABLE) { + val0 = *pYTable++; + val1 = *pYTable++; + val0 &= 0x0f; + val1 &= 0x0f; + val0 |= val1 << 4; + rc = reg_w(ov, reg, val0); + if (rc < 0) + return rc; + } + + if (ENABLE_UV_QUANTABLE) { + val0 = *pUVTable++; + val1 = *pUVTable++; + val0 &= 0x0f; + val1 &= 0x0f; + val0 |= val1 << 4; + rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0); + if (rc < 0) + return rc; + } + + reg++; + } + + return 0; +} + +/* OV518 quantization tables are 8x4 (instead of 8x8) */ +static int +ov518_upload_quan_tables(struct usb_ov511 *ov) +{ + unsigned char *pYTable = yQuanTable518; + unsigned char *pUVTable = uvQuanTable518; + unsigned char val0, val1; + int i, rc, reg = R511_COMP_LUT_BEGIN; + + PDEBUG(4, "Uploading quantization tables"); + + for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) { + if (ENABLE_Y_QUANTABLE) { + val0 = *pYTable++; + val1 = *pYTable++; + val0 &= 0x0f; + val1 &= 0x0f; + val0 |= val1 << 4; + rc = reg_w(ov, reg, val0); + if (rc < 0) + return rc; + } + + if (ENABLE_UV_QUANTABLE) { + val0 = *pUVTable++; + val1 = *pUVTable++; + val0 &= 0x0f; + val1 &= 0x0f; + val0 |= val1 << 4; + rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0); + if (rc < 0) + return rc; + } + + reg++; + } + + return 0; +} + +static int +ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type) +{ + int rc; + + /* Setting bit 0 not allowed on 518/518Plus */ + if (ov->bclass == BCL_OV518) + reset_type &= 0xfe; + + PDEBUG(4, "Reset: type=0x%02X", reset_type); + + rc = reg_w(ov, R51x_SYS_RESET, reset_type); + rc = reg_w(ov, R51x_SYS_RESET, 0); + + if (rc < 0) + err("reset: command failed"); + + return rc; +} + +/********************************************************************** + * + * Low-level I2C I/O functions + * + **********************************************************************/ + +/* NOTE: Do not call this function directly! + * The OV518 I2C I/O procedure is different, hence, this function. + * This is normally only called from i2c_w(). Note that this function + * always succeeds regardless of whether the sensor is present and working. + */ +static int +ov518_i2c_write_internal(struct usb_ov511 *ov, + unsigned char reg, + unsigned char value) +{ + int rc; + + PDEBUG(5, "0x%02X:0x%02X", reg, value); + + /* Select camera register */ + rc = reg_w(ov, R51x_I2C_SADDR_3, reg); + if (rc < 0) + return rc; + + /* Write "value" to I2C data port of OV511 */ + rc = reg_w(ov, R51x_I2C_DATA, value); + if (rc < 0) + return rc; + + /* Initiate 3-byte write cycle */ + rc = reg_w(ov, R518_I2C_CTL, 0x01); + if (rc < 0) + return rc; + + return 0; +} + +/* NOTE: Do not call this function directly! */ +static int +ov511_i2c_write_internal(struct usb_ov511 *ov, + unsigned char reg, + unsigned char value) +{ + int rc, retries; + + PDEBUG(5, "0x%02X:0x%02X", reg, value); + + /* Three byte write cycle */ + for (retries = OV511_I2C_RETRIES; ; ) { + /* Select camera register */ + rc = reg_w(ov, R51x_I2C_SADDR_3, reg); + if (rc < 0) + break; + + /* Write "value" to I2C data port of OV511 */ + rc = reg_w(ov, R51x_I2C_DATA, value); + if (rc < 0) + break; + + /* Initiate 3-byte write cycle */ + rc = reg_w(ov, R511_I2C_CTL, 0x01); + if (rc < 0) + break; + + /* Retry until idle */ + do + rc = reg_r(ov, R511_I2C_CTL); + while (rc > 0 && ((rc&1) == 0)); + if (rc < 0) + break; + + /* Ack? */ + if ((rc&2) == 0) { + rc = 0; + break; + } +#if 0 + /* I2C abort */ + reg_w(ov, R511_I2C_CTL, 0x10); +#endif + if (--retries < 0) { + err("i2c write retries exhausted"); + rc = -1; + break; + } + } + + return rc; +} + +/* NOTE: Do not call this function directly! + * The OV518 I2C I/O procedure is different, hence, this function. + * This is normally only called from i2c_r(). Note that this function + * always succeeds regardless of whether the sensor is present and working. + */ +static int +ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) +{ + int rc, value; + + /* Select camera register */ + rc = reg_w(ov, R51x_I2C_SADDR_2, reg); + if (rc < 0) + return rc; + + /* Initiate 2-byte write cycle */ + rc = reg_w(ov, R518_I2C_CTL, 0x03); + if (rc < 0) + return rc; + + /* Initiate 2-byte read cycle */ + rc = reg_w(ov, R518_I2C_CTL, 0x05); + if (rc < 0) + return rc; + + value = reg_r(ov, R51x_I2C_DATA); + + PDEBUG(5, "0x%02X:0x%02X", reg, value); + + return value; +} + +/* NOTE: Do not call this function directly! + * returns: negative is error, pos or zero is data */ +static int +ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) +{ + int rc, value, retries; + + /* Two byte write cycle */ + for (retries = OV511_I2C_RETRIES; ; ) { + /* Select camera register */ + rc = reg_w(ov, R51x_I2C_SADDR_2, reg); + if (rc < 0) + return rc; + + /* Initiate 2-byte write cycle */ + rc = reg_w(ov, R511_I2C_CTL, 0x03); + if (rc < 0) + return rc; + + /* Retry until idle */ + do + rc = reg_r(ov, R511_I2C_CTL); + while (rc > 0 && ((rc&1) == 0)); + if (rc < 0) + return rc; + + if ((rc&2) == 0) /* Ack? */ + break; + + /* I2C abort */ + reg_w(ov, R511_I2C_CTL, 0x10); + + if (--retries < 0) { + err("i2c write retries exhausted"); + return -1; + } + } + + /* Two byte read cycle */ + for (retries = OV511_I2C_RETRIES; ; ) { + /* Initiate 2-byte read cycle */ + rc = reg_w(ov, R511_I2C_CTL, 0x05); + if (rc < 0) + return rc; + + /* Retry until idle */ + do + rc = reg_r(ov, R511_I2C_CTL); + while (rc > 0 && ((rc&1) == 0)); + if (rc < 0) + return rc; + + if ((rc&2) == 0) /* Ack? */ + break; + + /* I2C abort */ + rc = reg_w(ov, R511_I2C_CTL, 0x10); + if (rc < 0) + return rc; + + if (--retries < 0) { + err("i2c read retries exhausted"); + return -1; + } + } + + value = reg_r(ov, R51x_I2C_DATA); + + PDEBUG(5, "0x%02X:0x%02X", reg, value); + + /* This is needed to make i2c_w() work */ + rc = reg_w(ov, R511_I2C_CTL, 0x05); + if (rc < 0) + return rc; + + return value; +} + +/* returns: negative is error, pos or zero is data */ +static int +i2c_r(struct usb_ov511 *ov, unsigned char reg) +{ + int rc; + + down(&ov->i2c_lock); + + if (ov->bclass == BCL_OV518) + rc = ov518_i2c_read_internal(ov, reg); + else + rc = ov511_i2c_read_internal(ov, reg); + + up(&ov->i2c_lock); + + return rc; +} + +static int +i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) +{ + int rc; + + down(&ov->i2c_lock); + + if (ov->bclass == BCL_OV518) + rc = ov518_i2c_write_internal(ov, reg, value); + else + rc = ov511_i2c_write_internal(ov, reg, value); + + up(&ov->i2c_lock); + + return rc; +} + +/* Do not call this function directly! */ +static int +ov51x_i2c_write_mask_internal(struct usb_ov511 *ov, + unsigned char reg, + unsigned char value, + unsigned char mask) +{ + int rc; + unsigned char oldval, newval; + + if (mask == 0xff) { + newval = value; + } else { + if (ov->bclass == BCL_OV518) + rc = ov518_i2c_read_internal(ov, reg); + else + rc = ov511_i2c_read_internal(ov, reg); + if (rc < 0) + return rc; + + oldval = (unsigned char) rc; + oldval &= (~mask); /* Clear the masked bits */ + value &= mask; /* Enforce mask on value */ + newval = oldval | value; /* Set the desired bits */ + } + + if (ov->bclass == BCL_OV518) + return (ov518_i2c_write_internal(ov, reg, newval)); + else + return (ov511_i2c_write_internal(ov, reg, newval)); +} + +/* Writes bits at positions specified by mask to an I2C reg. Bits that are in + * the same position as 1's in "mask" are cleared and set to "value". Bits + * that are in the same position as 0's in "mask" are preserved, regardless + * of their respective state in "value". + */ +static int +i2c_w_mask(struct usb_ov511 *ov, + unsigned char reg, + unsigned char value, + unsigned char mask) +{ + int rc; + + down(&ov->i2c_lock); + rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); + up(&ov->i2c_lock); + + return rc; +} + +/* Set the read and write slave IDs. The "slave" argument is the write slave, + * and the read slave will be set to (slave + 1). ov->i2c_lock should be held + * when calling this. This should not be called from outside the i2c I/O + * functions. + */ +static int +i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave) +{ + int rc; + + rc = reg_w(ov, R51x_I2C_W_SID, slave); + if (rc < 0) + return rc; + + rc = reg_w(ov, R51x_I2C_R_SID, slave + 1); + if (rc < 0) + return rc; + + return 0; +} + +/* Write to a specific I2C slave ID and register, using the specified mask */ +static int +i2c_w_slave(struct usb_ov511 *ov, + unsigned char slave, + unsigned char reg, + unsigned char value, + unsigned char mask) +{ + int rc = 0; + + down(&ov->i2c_lock); + + /* Set new slave IDs */ + rc = i2c_set_slave_internal(ov, slave); + if (rc < 0) + goto out; + + rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); + +out: + /* Restore primary IDs */ + if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0) + err("Couldn't restore primary I2C slave"); + + up(&ov->i2c_lock); + return rc; +} + +/* Read from a specific I2C slave ID and register */ +static int +i2c_r_slave(struct usb_ov511 *ov, + unsigned char slave, + unsigned char reg) +{ + int rc; + + down(&ov->i2c_lock); + + /* Set new slave IDs */ + rc = i2c_set_slave_internal(ov, slave); + if (rc < 0) + goto out; + + if (ov->bclass == BCL_OV518) + rc = ov518_i2c_read_internal(ov, reg); + else + rc = ov511_i2c_read_internal(ov, reg); + +out: + /* Restore primary IDs */ + if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0) + err("Couldn't restore primary I2C slave"); + + up(&ov->i2c_lock); + return rc; +} + +/* Sets I2C read and write slave IDs. Returns <0 for error */ +static int +ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid) +{ + int rc; + + down(&ov->i2c_lock); + + rc = i2c_set_slave_internal(ov, sid); + if (rc < 0) + goto out; + + // FIXME: Is this actually necessary? + rc = ov51x_reset(ov, OV511_RESET_NOREGS); +out: + up(&ov->i2c_lock); + return rc; +} + +static int +write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals) +{ + int rc; + + while (pRegvals->bus != OV511_DONE_BUS) { + if (pRegvals->bus == OV511_REG_BUS) { + if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0) + return rc; + } else if (pRegvals->bus == OV511_I2C_BUS) { + if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0) + return rc; + } else { + err("Bad regval array"); + return -1; + } + pRegvals++; + } + return 0; +} + +#ifdef OV511_DEBUG +static void +dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn) +{ + int i, rc; + + for (i = reg1; i <= regn; i++) { + rc = i2c_r(ov, i); + info("Sensor[0x%02X] = 0x%02X", i, rc); + } +} + +static void +dump_i2c_regs(struct usb_ov511 *ov) +{ + info("I2C REGS"); + dump_i2c_range(ov, 0x00, 0x7C); +} + +static void +dump_reg_range(struct usb_ov511 *ov, int reg1, int regn) +{ + int i, rc; + + for (i = reg1; i <= regn; i++) { + rc = reg_r(ov, i); + info("OV511[0x%02X] = 0x%02X", i, rc); + } +} + +static void +ov511_dump_regs(struct usb_ov511 *ov) +{ + info("CAMERA INTERFACE REGS"); + dump_reg_range(ov, 0x10, 0x1f); + info("DRAM INTERFACE REGS"); + dump_reg_range(ov, 0x20, 0x23); + info("ISO FIFO REGS"); + dump_reg_range(ov, 0x30, 0x31); + info("PIO REGS"); + dump_reg_range(ov, 0x38, 0x39); + dump_reg_range(ov, 0x3e, 0x3e); + info("I2C REGS"); + dump_reg_range(ov, 0x40, 0x49); + info("SYSTEM CONTROL REGS"); + dump_reg_range(ov, 0x50, 0x55); + dump_reg_range(ov, 0x5e, 0x5f); + info("OmniCE REGS"); + dump_reg_range(ov, 0x70, 0x79); + /* NOTE: Quantization tables are not readable. You will get the value + * in reg. 0x79 for every table register */ + dump_reg_range(ov, 0x80, 0x9f); + dump_reg_range(ov, 0xa0, 0xbf); + +} + +static void +ov518_dump_regs(struct usb_ov511 *ov) +{ + info("VIDEO MODE REGS"); + dump_reg_range(ov, 0x20, 0x2f); + info("DATA PUMP AND SNAPSHOT REGS"); + dump_reg_range(ov, 0x30, 0x3f); + info("I2C REGS"); + dump_reg_range(ov, 0x40, 0x4f); + info("SYSTEM CONTROL AND VENDOR REGS"); + dump_reg_range(ov, 0x50, 0x5f); + info("60 - 6F"); + dump_reg_range(ov, 0x60, 0x6f); + info("70 - 7F"); + dump_reg_range(ov, 0x70, 0x7f); + info("Y QUANTIZATION TABLE"); + dump_reg_range(ov, 0x80, 0x8f); + info("UV QUANTIZATION TABLE"); + dump_reg_range(ov, 0x90, 0x9f); + info("A0 - BF"); + dump_reg_range(ov, 0xa0, 0xbf); + info("CBR"); + dump_reg_range(ov, 0xc0, 0xcf); +} +#endif + +/*****************************************************************************/ + +/* Temporarily stops OV511 from functioning. Must do this before changing + * registers while the camera is streaming */ +static inline int +ov51x_stop(struct usb_ov511 *ov) +{ + PDEBUG(4, "stopping"); + ov->stopped = 1; + if (ov->bclass == BCL_OV518) + return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a)); + else + return (reg_w(ov, R51x_SYS_RESET, 0x3d)); +} + +/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not + * actually stopped (for performance). */ +static inline int +ov51x_restart(struct usb_ov511 *ov) +{ + if (ov->stopped) { + PDEBUG(4, "restarting"); + ov->stopped = 0; + + /* Reinitialize the stream */ + if (ov->bclass == BCL_OV518) + reg_w(ov, 0x2f, 0x80); + + return (reg_w(ov, R51x_SYS_RESET, 0x00)); + } + + return 0; +} + +/* Sleeps until no frames are active. Returns !0 if got signal */ +static int +ov51x_wait_frames_inactive(struct usb_ov511 *ov) +{ + return wait_event_interruptible(ov->wq, ov->curframe < 0); +} + +/* Resets the hardware snapshot button */ +static void +ov51x_clear_snapshot(struct usb_ov511 *ov) +{ + if (ov->bclass == BCL_OV511) { + reg_w(ov, R51x_SYS_SNAP, 0x00); + reg_w(ov, R51x_SYS_SNAP, 0x02); + reg_w(ov, R51x_SYS_SNAP, 0x00); + } else if (ov->bclass == BCL_OV518) { + warn("snapshot reset not supported yet on OV518(+)"); + } else { + err("clear snap: invalid bridge type"); + } +} + +#if 0 +/* Checks the status of the snapshot button. Returns 1 if it was pressed since + * it was last cleared, and zero in all other cases (including errors) */ +static int +ov51x_check_snapshot(struct usb_ov511 *ov) +{ + int ret, status = 0; + + if (ov->bclass == BCL_OV511) { + ret = reg_r(ov, R51x_SYS_SNAP); + if (ret < 0) { + err("Error checking snspshot status (%d)", ret); + } else if (ret & 0x08) { + status = 1; + } + } else if (ov->bclass == BCL_OV518) { + warn("snapshot check not supported yet on OV518(+)"); + } else { + err("check snap: invalid bridge type"); + } + + return status; +} +#endif + +/* This does an initial reset of an OmniVision sensor and ensures that I2C + * is synchronized. Returns <0 for failure. + */ +static int +init_ov_sensor(struct usb_ov511 *ov) +{ + int i, success; + + /* Reset the sensor */ + if (i2c_w(ov, 0x12, 0x80) < 0) + return -EIO; + + /* Wait for it to initialize */ + msleep(150); + + for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { + if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && + (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) { + success = 1; + continue; + } + + /* Reset the sensor */ + if (i2c_w(ov, 0x12, 0x80) < 0) + return -EIO; + /* Wait for it to initialize */ + msleep(150); + /* Dummy read to sync I2C */ + if (i2c_r(ov, 0x00) < 0) + return -EIO; + } + + if (!success) + return -EIO; + + PDEBUG(1, "I2C synced in %d attempt(s)", i); + + return 0; +} + +static int +ov511_set_packet_size(struct usb_ov511 *ov, int size) +{ + int alt, mult; + + if (ov51x_stop(ov) < 0) + return -EIO; + + mult = size >> 5; + + if (ov->bridge == BRG_OV511) { + if (size == 0) + alt = OV511_ALT_SIZE_0; + else if (size == 257) + alt = OV511_ALT_SIZE_257; + else if (size == 513) + alt = OV511_ALT_SIZE_513; + else if (size == 769) + alt = OV511_ALT_SIZE_769; + else if (size == 993) + alt = OV511_ALT_SIZE_993; + else { + err("Set packet size: invalid size (%d)", size); + return -EINVAL; + } + } else if (ov->bridge == BRG_OV511PLUS) { + if (size == 0) + alt = OV511PLUS_ALT_SIZE_0; + else if (size == 33) + alt = OV511PLUS_ALT_SIZE_33; + else if (size == 129) + alt = OV511PLUS_ALT_SIZE_129; + else if (size == 257) + alt = OV511PLUS_ALT_SIZE_257; + else if (size == 385) + alt = OV511PLUS_ALT_SIZE_385; + else if (size == 513) + alt = OV511PLUS_ALT_SIZE_513; + else if (size == 769) + alt = OV511PLUS_ALT_SIZE_769; + else if (size == 961) + alt = OV511PLUS_ALT_SIZE_961; + else { + err("Set packet size: invalid size (%d)", size); + return -EINVAL; + } + } else { + err("Set packet size: Invalid bridge type"); + return -EINVAL; + } + + PDEBUG(3, "%d, mult=%d, alt=%d", size, mult, alt); + + if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0) + return -EIO; + + if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { + err("Set packet size: set interface error"); + return -EBUSY; + } + + if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) + return -EIO; + + ov->packet_size = size; + + if (ov51x_restart(ov) < 0) + return -EIO; + + return 0; +} + +/* Note: Unlike the OV511/OV511+, the size argument does NOT include the + * optional packet number byte. The actual size *is* stored in ov->packet_size, + * though. */ +static int +ov518_set_packet_size(struct usb_ov511 *ov, int size) +{ + int alt; + + if (ov51x_stop(ov) < 0) + return -EIO; + + if (ov->bclass == BCL_OV518) { + if (size == 0) + alt = OV518_ALT_SIZE_0; + else if (size == 128) + alt = OV518_ALT_SIZE_128; + else if (size == 256) + alt = OV518_ALT_SIZE_256; + else if (size == 384) + alt = OV518_ALT_SIZE_384; + else if (size == 512) + alt = OV518_ALT_SIZE_512; + else if (size == 640) + alt = OV518_ALT_SIZE_640; + else if (size == 768) + alt = OV518_ALT_SIZE_768; + else if (size == 896) + alt = OV518_ALT_SIZE_896; + else { + err("Set packet size: invalid size (%d)", size); + return -EINVAL; + } + } else { + err("Set packet size: Invalid bridge type"); + return -EINVAL; + } + + PDEBUG(3, "%d, alt=%d", size, alt); + + ov->packet_size = size; + if (size > 0) { + /* Program ISO FIFO size reg (packet number isn't included) */ + ov518_reg_w32(ov, 0x30, size, 2); + + if (ov->packet_numbering) + ++ov->packet_size; + } + + if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { + err("Set packet size: set interface error"); + return -EBUSY; + } + + /* Initialize the stream */ + if (reg_w(ov, 0x2f, 0x80) < 0) + return -EIO; + + if (ov51x_restart(ov) < 0) + return -EIO; + + if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) + return -EIO; + + return 0; +} + +/* Upload compression params and quantization tables. Returns 0 for success. */ +static int +ov511_init_compression(struct usb_ov511 *ov) +{ + int rc = 0; + + if (!ov->compress_inited) { + reg_w(ov, 0x70, phy); + reg_w(ov, 0x71, phuv); + reg_w(ov, 0x72, pvy); + reg_w(ov, 0x73, pvuv); + reg_w(ov, 0x74, qhy); + reg_w(ov, 0x75, qhuv); + reg_w(ov, 0x76, qvy); + reg_w(ov, 0x77, qvuv); + + if (ov511_upload_quan_tables(ov) < 0) { + err("Error uploading quantization tables"); + rc = -EIO; + goto out; + } + } + + ov->compress_inited = 1; +out: + return rc; +} + +/* Upload compression params and quantization tables. Returns 0 for success. */ +static int +ov518_init_compression(struct usb_ov511 *ov) +{ + int rc = 0; + + if (!ov->compress_inited) { + if (ov518_upload_quan_tables(ov) < 0) { + err("Error uploading quantization tables"); + rc = -EIO; + goto out; + } + } + + ov->compress_inited = 1; +out: + return rc; +} + +/* -------------------------------------------------------------------------- */ + +/* Sets sensor's contrast setting to "val" */ +static int +sensor_set_contrast(struct usb_ov511 *ov, unsigned short val) +{ + int rc; + + PDEBUG(3, "%d", val); + + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) + return -EIO; + + switch (ov->sensor) { + case SEN_OV7610: + case SEN_OV6620: + { + rc = i2c_w(ov, OV7610_REG_CNT, val >> 8); + if (rc < 0) + goto out; + break; + } + case SEN_OV6630: + { + rc = i2c_w_mask(ov, OV7610_REG_CNT, val >> 12, 0x0f); + if (rc < 0) + goto out; + break; + } + case SEN_OV7620: + { + unsigned char ctab[] = { + 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57, + 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff + }; + + /* Use Y gamma control instead. Bit 0 enables it. */ + rc = i2c_w(ov, 0x64, ctab[val>>12]); + if (rc < 0) + goto out; + break; + } + case SEN_SAA7111A: + { + rc = i2c_w(ov, 0x0b, val >> 9); + if (rc < 0) + goto out; + break; + } + default: + { + PDEBUG(3, "Unsupported with this sensor"); + rc = -EPERM; + goto out; + } + } + + rc = 0; /* Success */ + ov->contrast = val; +out: + if (ov51x_restart(ov) < 0) + return -EIO; + + return rc; +} + +/* Gets sensor's contrast setting */ +static int +sensor_get_contrast(struct usb_ov511 *ov, unsigned short *val) +{ + int rc; + + switch (ov->sensor) { + case SEN_OV7610: + case SEN_OV6620: + rc = i2c_r(ov, OV7610_REG_CNT); + if (rc < 0) + return rc; + else + *val = rc << 8; + break; + case SEN_OV6630: + rc = i2c_r(ov, OV7610_REG_CNT); + if (rc < 0) + return rc; + else + *val = rc << 12; + break; + case SEN_OV7620: + /* Use Y gamma reg instead. Bit 0 is the enable bit. */ + rc = i2c_r(ov, 0x64); + if (rc < 0) + return rc; + else + *val = (rc & 0xfe) << 8; + break; + case SEN_SAA7111A: + *val = ov->contrast; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + return -EPERM; + } + + PDEBUG(3, "%d", *val); + ov->contrast = *val; + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/* Sets sensor's brightness setting to "val" */ +static int +sensor_set_brightness(struct usb_ov511 *ov, unsigned short val) +{ + int rc; + + PDEBUG(4, "%d", val); + + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) + return -EIO; + + switch (ov->sensor) { + case SEN_OV7610: + case SEN_OV76BE: + case SEN_OV6620: + case SEN_OV6630: + rc = i2c_w(ov, OV7610_REG_BRT, val >> 8); + if (rc < 0) + goto out; + break; + case SEN_OV7620: + /* 7620 doesn't like manual changes when in auto mode */ + if (!ov->auto_brt) { + rc = i2c_w(ov, OV7610_REG_BRT, val >> 8); + if (rc < 0) + goto out; + } + break; + case SEN_SAA7111A: + rc = i2c_w(ov, 0x0a, val >> 8); + if (rc < 0) + goto out; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + rc = -EPERM; + goto out; + } + + rc = 0; /* Success */ + ov->brightness = val; +out: + if (ov51x_restart(ov) < 0) + return -EIO; + + return rc; +} + +/* Gets sensor's brightness setting */ +static int +sensor_get_brightness(struct usb_ov511 *ov, unsigned short *val) +{ + int rc; + + switch (ov->sensor) { + case SEN_OV7610: + case SEN_OV76BE: + case SEN_OV7620: + case SEN_OV6620: + case SEN_OV6630: + rc = i2c_r(ov, OV7610_REG_BRT); + if (rc < 0) + return rc; + else + *val = rc << 8; + break; + case SEN_SAA7111A: + *val = ov->brightness; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + return -EPERM; + } + + PDEBUG(3, "%d", *val); + ov->brightness = *val; + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/* Sets sensor's saturation (color intensity) setting to "val" */ +static int +sensor_set_saturation(struct usb_ov511 *ov, unsigned short val) +{ + int rc; + + PDEBUG(3, "%d", val); + + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) + return -EIO; + + switch (ov->sensor) { + case SEN_OV7610: + case SEN_OV76BE: + case SEN_OV6620: + case SEN_OV6630: + rc = i2c_w(ov, OV7610_REG_SAT, val >> 8); + if (rc < 0) + goto out; + break; + case SEN_OV7620: +// /* Use UV gamma control instead. Bits 0 & 7 are reserved. */ +// rc = ov_i2c_write(ov->dev, 0x62, (val >> 9) & 0x7e); +// if (rc < 0) +// goto out; + rc = i2c_w(ov, OV7610_REG_SAT, val >> 8); + if (rc < 0) + goto out; + break; + case SEN_SAA7111A: + rc = i2c_w(ov, 0x0c, val >> 9); + if (rc < 0) + goto out; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + rc = -EPERM; + goto out; + } + + rc = 0; /* Success */ + ov->colour = val; +out: + if (ov51x_restart(ov) < 0) + return -EIO; + + return rc; +} + +/* Gets sensor's saturation (color intensity) setting */ +static int +sensor_get_saturation(struct usb_ov511 *ov, unsigned short *val) +{ + int rc; + + switch (ov->sensor) { + case SEN_OV7610: + case SEN_OV76BE: + case SEN_OV6620: + case SEN_OV6630: + rc = i2c_r(ov, OV7610_REG_SAT); + if (rc < 0) + return rc; + else + *val = rc << 8; + break; + case SEN_OV7620: +// /* Use UV gamma reg instead. Bits 0 & 7 are reserved. */ +// rc = i2c_r(ov, 0x62); +// if (rc < 0) +// return rc; +// else +// *val = (rc & 0x7e) << 9; + rc = i2c_r(ov, OV7610_REG_SAT); + if (rc < 0) + return rc; + else + *val = rc << 8; + break; + case SEN_SAA7111A: + *val = ov->colour; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + return -EPERM; + } + + PDEBUG(3, "%d", *val); + ov->colour = *val; + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/* Sets sensor's hue (red/blue balance) setting to "val" */ +static int +sensor_set_hue(struct usb_ov511 *ov, unsigned short val) +{ + int rc; + + PDEBUG(3, "%d", val); + + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) + return -EIO; + + switch (ov->sensor) { + case SEN_OV7610: + case SEN_OV6620: + case SEN_OV6630: + rc = i2c_w(ov, OV7610_REG_RED, 0xFF - (val >> 8)); + if (rc < 0) + goto out; + + rc = i2c_w(ov, OV7610_REG_BLUE, val >> 8); + if (rc < 0) + goto out; + break; + case SEN_OV7620: +// Hue control is causing problems. I will enable it once it's fixed. +#if 0 + rc = i2c_w(ov, 0x7a, (unsigned char)(val >> 8) + 0xb); + if (rc < 0) + goto out; + + rc = i2c_w(ov, 0x79, (unsigned char)(val >> 8) + 0xb); + if (rc < 0) + goto out; +#endif + break; + case SEN_SAA7111A: + rc = i2c_w(ov, 0x0d, (val + 32768) >> 8); + if (rc < 0) + goto out; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + rc = -EPERM; + goto out; + } + + rc = 0; /* Success */ + ov->hue = val; +out: + if (ov51x_restart(ov) < 0) + return -EIO; + + return rc; +} + +/* Gets sensor's hue (red/blue balance) setting */ +static int +sensor_get_hue(struct usb_ov511 *ov, unsigned short *val) +{ + int rc; + + switch (ov->sensor) { + case SEN_OV7610: + case SEN_OV6620: + case SEN_OV6630: + rc = i2c_r(ov, OV7610_REG_BLUE); + if (rc < 0) + return rc; + else + *val = rc << 8; + break; + case SEN_OV7620: + rc = i2c_r(ov, 0x7a); + if (rc < 0) + return rc; + else + *val = rc << 8; + break; + case SEN_SAA7111A: + *val = ov->hue; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + return -EPERM; + } + + PDEBUG(3, "%d", *val); + ov->hue = *val; + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +static int +sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p) +{ + int rc; + + PDEBUG(4, "sensor_set_picture"); + + ov->whiteness = p->whiteness; + + /* Don't return error if a setting is unsupported, or rest of settings + * will not be performed */ + + rc = sensor_set_contrast(ov, p->contrast); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_set_brightness(ov, p->brightness); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_set_saturation(ov, p->colour); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_set_hue(ov, p->hue); + if (FATAL_ERROR(rc)) + return rc; + + return 0; +} + +static int +sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p) +{ + int rc; + + PDEBUG(4, "sensor_get_picture"); + + /* Don't return error if a setting is unsupported, or rest of settings + * will not be performed */ + + rc = sensor_get_contrast(ov, &(p->contrast)); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_get_brightness(ov, &(p->brightness)); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_get_saturation(ov, &(p->colour)); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_get_hue(ov, &(p->hue)); + if (FATAL_ERROR(rc)) + return rc; + + p->whiteness = 105 << 8; + + return 0; +} + +#if 0 +// FIXME: Exposure range is only 0x00-0x7f in interlace mode +/* Sets current exposure for sensor. This only has an effect if auto-exposure + * is off */ +static inline int +sensor_set_exposure(struct usb_ov511 *ov, unsigned char val) +{ + int rc; + + PDEBUG(3, "%d", val); + + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) + return -EIO; + + switch (ov->sensor) { + case SEN_OV6620: + case SEN_OV6630: + case SEN_OV7610: + case SEN_OV7620: + case SEN_OV76BE: + case SEN_OV8600: + rc = i2c_w(ov, 0x10, val); + if (rc < 0) + goto out; + + break; + case SEN_KS0127: + case SEN_KS0127B: + case SEN_SAA7111A: + PDEBUG(3, "Unsupported with this sensor"); + return -EPERM; + default: + err("Sensor not supported for set_exposure"); + return -EINVAL; + } + + rc = 0; /* Success */ + ov->exposure = val; +out: + if (ov51x_restart(ov) < 0) + return -EIO; + + return rc; +} +#endif + +/* Gets current exposure level from sensor, regardless of whether it is under + * manual control. */ +static int +sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val) +{ + int rc; + + switch (ov->sensor) { + case SEN_OV7610: + case SEN_OV6620: + case SEN_OV6630: + case SEN_OV7620: + case SEN_OV76BE: + case SEN_OV8600: + rc = i2c_r(ov, 0x10); + if (rc < 0) + return rc; + else + *val = rc; + break; + case SEN_KS0127: + case SEN_KS0127B: + case SEN_SAA7111A: + val = NULL; + PDEBUG(3, "Unsupported with this sensor"); + return -EPERM; + default: + err("Sensor not supported for get_exposure"); + return -EINVAL; + } + + PDEBUG(3, "%d", *val); + ov->exposure = *val; + + return 0; +} + +/* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */ +static void +ov51x_led_control(struct usb_ov511 *ov, int enable) +{ + PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); + + if (ov->bridge == BRG_OV511PLUS) + reg_w(ov, R511_SYS_LED_CTL, enable ? 1 : 0); + else if (ov->bclass == BCL_OV518) + reg_w_mask(ov, R518_GPIO_OUT, enable ? 0x02 : 0x00, 0x02); + + return; +} + +/* Matches the sensor's internal frame rate to the lighting frequency. + * Valid frequencies are: + * 50 - 50Hz, for European and Asian lighting + * 60 - 60Hz, for American lighting + * + * Tested with: OV7610, OV7620, OV76BE, OV6620 + * Unsupported: KS0127, KS0127B, SAA7111A + * Returns: 0 for success + */ +static int +sensor_set_light_freq(struct usb_ov511 *ov, int freq) +{ + int sixty; + + PDEBUG(4, "%d Hz", freq); + + if (freq == 60) + sixty = 1; + else if (freq == 50) + sixty = 0; + else { + err("Invalid light freq (%d Hz)", freq); + return -EINVAL; + } + + switch (ov->sensor) { + case SEN_OV7610: + i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); + i2c_w(ov, 0x2b, sixty?0x00:0xac); + i2c_w_mask(ov, 0x13, 0x10, 0x10); + i2c_w_mask(ov, 0x13, 0x00, 0x10); + break; + case SEN_OV7620: + case SEN_OV76BE: + case SEN_OV8600: + i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); + i2c_w(ov, 0x2b, sixty?0x00:0xac); + i2c_w_mask(ov, 0x76, 0x01, 0x01); + break; + case SEN_OV6620: + case SEN_OV6630: + i2c_w(ov, 0x2b, sixty?0xa8:0x28); + i2c_w(ov, 0x2a, sixty?0x84:0xa4); + break; + case SEN_KS0127: + case SEN_KS0127B: + case SEN_SAA7111A: + PDEBUG(5, "Unsupported with this sensor"); + return -EPERM; + default: + err("Sensor not supported for set_light_freq"); + return -EINVAL; + } + + ov->lightfreq = freq; + + return 0; +} + +/* If enable is true, turn on the sensor's banding filter, otherwise turn it + * off. This filter tries to reduce the pattern of horizontal light/dark bands + * caused by some (usually fluorescent) lighting. The light frequency must be + * set either before or after enabling it with ov51x_set_light_freq(). + * + * Tested with: OV7610, OV7620, OV76BE, OV6620. + * Unsupported: KS0127, KS0127B, SAA7111A + * Returns: 0 for success + */ +static int +sensor_set_banding_filter(struct usb_ov511 *ov, int enable) +{ + int rc; + + PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); + + if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B + || ov->sensor == SEN_SAA7111A) { + PDEBUG(5, "Unsupported with this sensor"); + return -EPERM; + } + + rc = i2c_w_mask(ov, 0x2d, enable?0x04:0x00, 0x04); + if (rc < 0) + return rc; + + ov->bandfilt = enable; + + return 0; +} + +/* If enable is true, turn on the sensor's auto brightness control, otherwise + * turn it off. + * + * Unsupported: KS0127, KS0127B, SAA7111A + * Returns: 0 for success + */ +static int +sensor_set_auto_brightness(struct usb_ov511 *ov, int enable) +{ + int rc; + + PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); + + if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B + || ov->sensor == SEN_SAA7111A) { + PDEBUG(5, "Unsupported with this sensor"); + return -EPERM; + } + + rc = i2c_w_mask(ov, 0x2d, enable?0x10:0x00, 0x10); + if (rc < 0) + return rc; + + ov->auto_brt = enable; + + return 0; +} + +/* If enable is true, turn on the sensor's auto exposure control, otherwise + * turn it off. + * + * Unsupported: KS0127, KS0127B, SAA7111A + * Returns: 0 for success + */ +static int +sensor_set_auto_exposure(struct usb_ov511 *ov, int enable) +{ + PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); + + switch (ov->sensor) { + case SEN_OV7610: + i2c_w_mask(ov, 0x29, enable?0x00:0x80, 0x80); + break; + case SEN_OV6620: + case SEN_OV7620: + case SEN_OV76BE: + case SEN_OV8600: + i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01); + break; + case SEN_OV6630: + i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10); + break; + case SEN_KS0127: + case SEN_KS0127B: + case SEN_SAA7111A: + PDEBUG(5, "Unsupported with this sensor"); + return -EPERM; + default: + err("Sensor not supported for set_auto_exposure"); + return -EINVAL; + } + + ov->auto_exp = enable; + + return 0; +} + +/* Modifies the sensor's exposure algorithm to allow proper exposure of objects + * that are illuminated from behind. + * + * Tested with: OV6620, OV7620 + * Unsupported: OV7610, OV76BE, KS0127, KS0127B, SAA7111A + * Returns: 0 for success + */ +static int +sensor_set_backlight(struct usb_ov511 *ov, int enable) +{ + PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); + + switch (ov->sensor) { + case SEN_OV7620: + case SEN_OV8600: + i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0); + i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); + i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); + break; + case SEN_OV6620: + i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0); + i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); + i2c_w_mask(ov, 0x0e, enable?0x80:0x00, 0x80); + break; + case SEN_OV6630: + i2c_w_mask(ov, 0x4e, enable?0x80:0x60, 0xe0); + i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); + i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); + break; + case SEN_OV7610: + case SEN_OV76BE: + case SEN_KS0127: + case SEN_KS0127B: + case SEN_SAA7111A: + PDEBUG(5, "Unsupported with this sensor"); + return -EPERM; + default: + err("Sensor not supported for set_backlight"); + return -EINVAL; + } + + ov->backlight = enable; + + return 0; +} + +static int +sensor_set_mirror(struct usb_ov511 *ov, int enable) +{ + PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); + + switch (ov->sensor) { + case SEN_OV6620: + case SEN_OV6630: + case SEN_OV7610: + case SEN_OV7620: + case SEN_OV76BE: + case SEN_OV8600: + i2c_w_mask(ov, 0x12, enable?0x40:0x00, 0x40); + break; + case SEN_KS0127: + case SEN_KS0127B: + case SEN_SAA7111A: + PDEBUG(5, "Unsupported with this sensor"); + return -EPERM; + default: + err("Sensor not supported for set_mirror"); + return -EINVAL; + } + + ov->mirror = enable; + + return 0; +} + +/* Returns number of bits per pixel (regardless of where they are located; + * planar or not), or zero for unsupported format. + */ +static inline int +get_depth(int palette) +{ + switch (palette) { + case VIDEO_PALETTE_GREY: return 8; + case VIDEO_PALETTE_YUV420: return 12; + case VIDEO_PALETTE_YUV420P: return 12; /* Planar */ + default: return 0; /* Invalid format */ + } +} + +/* Bytes per frame. Used by read(). Return of 0 indicates error */ +static inline long int +get_frame_length(struct ov511_frame *frame) +{ + if (!frame) + return 0; + else + return ((frame->width * frame->height + * get_depth(frame->format)) >> 3); +} + +static int +mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height, + int mode, int sub_flag, int qvga) +{ + int clock; + + /******** Mode (VGA/QVGA) and sensor specific regs ********/ + + switch (ov->sensor) { + case SEN_OV7610: + i2c_w(ov, 0x14, qvga?0x24:0x04); +// FIXME: Does this improve the image quality or frame rate? +#if 0 + i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); + i2c_w(ov, 0x24, 0x10); + i2c_w(ov, 0x25, qvga?0x40:0x8a); + i2c_w(ov, 0x2f, qvga?0x30:0xb0); + i2c_w(ov, 0x35, qvga?0x1c:0x9c); +#endif + break; + case SEN_OV7620: +// i2c_w(ov, 0x2b, 0x00); + i2c_w(ov, 0x14, qvga?0xa4:0x84); + i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); + i2c_w(ov, 0x24, qvga?0x20:0x3a); + i2c_w(ov, 0x25, qvga?0x30:0x60); + i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40); + i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0); + i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); + break; + case SEN_OV76BE: +// i2c_w(ov, 0x2b, 0x00); + i2c_w(ov, 0x14, qvga?0xa4:0x84); +// FIXME: Enable this once 7620AE uses 7620 initial settings +#if 0 + i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); + i2c_w(ov, 0x24, qvga?0x20:0x3a); + i2c_w(ov, 0x25, qvga?0x30:0x60); + i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40); + i2c_w_mask(ov, 0x67, qvga?0xb0:0x90, 0xf0); + i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); +#endif + break; + case SEN_OV6620: + i2c_w(ov, 0x14, qvga?0x24:0x04); + break; + case SEN_OV6630: + i2c_w(ov, 0x14, qvga?0xa0:0x80); + break; + default: + err("Invalid sensor"); + return -EINVAL; + } + + /******** Palette-specific regs ********/ + + if (mode == VIDEO_PALETTE_GREY) { + if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { + /* these aren't valid on the OV6620/OV7620/6630? */ + i2c_w_mask(ov, 0x0e, 0x40, 0x40); + } + + if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518 + && ov518_color) { + i2c_w_mask(ov, 0x12, 0x00, 0x10); + i2c_w_mask(ov, 0x13, 0x00, 0x20); + } else { + i2c_w_mask(ov, 0x13, 0x20, 0x20); + } + } else { + if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { + /* not valid on the OV6620/OV7620/6630? */ + i2c_w_mask(ov, 0x0e, 0x00, 0x40); + } + + /* The OV518 needs special treatment. Although both the OV518 + * and the OV6630 support a 16-bit video bus, only the 8 bit Y + * bus is actually used. The UV bus is tied to ground. + * Therefore, the OV6630 needs to be in 8-bit multiplexed + * output mode */ + + if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518 + && ov518_color) { + i2c_w_mask(ov, 0x12, 0x10, 0x10); + i2c_w_mask(ov, 0x13, 0x20, 0x20); + } else { + i2c_w_mask(ov, 0x13, 0x00, 0x20); + } + } + + /******** Clock programming ********/ + + /* The OV6620 needs special handling. This prevents the + * severe banding that normally occurs */ + if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) + { + /* Clock down */ + + i2c_w(ov, 0x2a, 0x04); + + if (ov->compress) { +// clock = 0; /* This ensures the highest frame rate */ + clock = 3; + } else if (clockdiv == -1) { /* If user didn't override it */ + clock = 3; /* Gives better exposure time */ + } else { + clock = clockdiv; + } + + PDEBUG(4, "Setting clock divisor to %d", clock); + + i2c_w(ov, 0x11, clock); + + i2c_w(ov, 0x2a, 0x84); + /* This next setting is critical. It seems to improve + * the gain or the contrast. The "reserved" bits seem + * to have some effect in this case. */ + i2c_w(ov, 0x2d, 0x85); + } + else + { + if (ov->compress) { + clock = 1; /* This ensures the highest frame rate */ + } else if (clockdiv == -1) { /* If user didn't override it */ + /* Calculate and set the clock divisor */ + clock = ((sub_flag ? ov->subw * ov->subh + : width * height) + * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2) + / 66000; + } else { + clock = clockdiv; + } + + PDEBUG(4, "Setting clock divisor to %d", clock); + + i2c_w(ov, 0x11, clock); + } + + /******** Special Features ********/ + + if (framedrop >= 0) + i2c_w(ov, 0x16, framedrop); + + /* Test Pattern */ + i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02); + + /* Enable auto white balance */ + i2c_w_mask(ov, 0x12, 0x04, 0x04); + + // This will go away as soon as ov51x_mode_init_sensor_regs() + // is fully tested. + /* 7620/6620/6630? don't have register 0x35, so play it safe */ + if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { + if (width == 640 && height == 480) + i2c_w(ov, 0x35, 0x9e); + else + i2c_w(ov, 0x35, 0x1e); + } + + return 0; +} + +static int +set_ov_sensor_window(struct usb_ov511 *ov, int width, int height, int mode, + int sub_flag) +{ + int ret; + int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize; + int hoffset, voffset, hwscale = 0, vwscale = 0; + + /* The different sensor ICs handle setting up of window differently. + * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */ + switch (ov->sensor) { + case SEN_OV7610: + case SEN_OV76BE: + hwsbase = 0x38; + hwebase = 0x3a; + vwsbase = vwebase = 0x05; + break; + case SEN_OV6620: + case SEN_OV6630: + hwsbase = 0x38; + hwebase = 0x3a; + vwsbase = 0x05; + vwebase = 0x06; + break; + case SEN_OV7620: + hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */ + hwebase = 0x2f; + vwsbase = vwebase = 0x05; + break; + default: + err("Invalid sensor"); + return -EINVAL; + } + + if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) { + /* Note: OV518(+) does downsample on its own) */ + if ((width > 176 && height > 144) + || ov->bclass == BCL_OV518) { /* CIF */ + ret = mode_init_ov_sensor_regs(ov, width, height, + mode, sub_flag, 0); + if (ret < 0) + return ret; + hwscale = 1; + vwscale = 1; /* The datasheet says 0; it's wrong */ + hwsize = 352; + vwsize = 288; + } else if (width > 176 || height > 144) { + err("Illegal dimensions"); + return -EINVAL; + } else { /* QCIF */ + ret = mode_init_ov_sensor_regs(ov, width, height, + mode, sub_flag, 1); + if (ret < 0) + return ret; + hwsize = 176; + vwsize = 144; + } + } else { + if (width > 320 && height > 240) { /* VGA */ + ret = mode_init_ov_sensor_regs(ov, width, height, + mode, sub_flag, 0); + if (ret < 0) + return ret; + hwscale = 2; + vwscale = 1; + hwsize = 640; + vwsize = 480; + } else if (width > 320 || height > 240) { + err("Illegal dimensions"); + return -EINVAL; + } else { /* QVGA */ + ret = mode_init_ov_sensor_regs(ov, width, height, + mode, sub_flag, 1); + if (ret < 0) + return ret; + hwscale = 1; + hwsize = 320; + vwsize = 240; + } + } + + /* Center the window */ + hoffset = ((hwsize - width) / 2) >> hwscale; + voffset = ((vwsize - height) / 2) >> vwscale; + + /* FIXME! - This needs to be changed to support 160x120 and 6620!!! */ + if (sub_flag) { + i2c_w(ov, 0x17, hwsbase+(ov->subx>>hwscale)); + i2c_w(ov, 0x18, hwebase+((ov->subx+ov->subw)>>hwscale)); + i2c_w(ov, 0x19, vwsbase+(ov->suby>>vwscale)); + i2c_w(ov, 0x1a, vwebase+((ov->suby+ov->subh)>>vwscale)); + } else { + i2c_w(ov, 0x17, hwsbase + hoffset); + i2c_w(ov, 0x18, hwebase + hoffset + (hwsize>>hwscale)); + i2c_w(ov, 0x19, vwsbase + voffset); + i2c_w(ov, 0x1a, vwebase + voffset + (vwsize>>vwscale)); + } + +#ifdef OV511_DEBUG + if (dump_sensor) + dump_i2c_regs(ov); +#endif + + return 0; +} + +/* Set up the OV511/OV511+ with the given image parameters. + * + * Do not put any sensor-specific code in here (including I2C I/O functions) + */ +static int +ov511_mode_init_regs(struct usb_ov511 *ov, + int width, int height, int mode, int sub_flag) +{ + int hsegs, vsegs; + + if (sub_flag) { + width = ov->subw; + height = ov->subh; + } + + PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", + width, height, mode, sub_flag); + + // FIXME: This should be moved to a 7111a-specific function once + // subcapture is dealt with properly + if (ov->sensor == SEN_SAA7111A) { + if (width == 320 && height == 240) { + /* No need to do anything special */ + } else if (width == 640 && height == 480) { + /* Set the OV511 up as 320x480, but keep the + * V4L resolution as 640x480 */ + width = 320; + } else { + err("SAA7111A only allows 320x240 or 640x480"); + return -EINVAL; + } + } + + /* Make sure width and height are a multiple of 8 */ + if (width % 8 || height % 8) { + err("Invalid size (%d, %d) (mode = %d)", width, height, mode); + return -EINVAL; + } + + if (width < ov->minwidth || height < ov->minheight) { + err("Requested dimensions are too small"); + return -EINVAL; + } + + if (ov51x_stop(ov) < 0) + return -EIO; + + if (mode == VIDEO_PALETTE_GREY) { + reg_w(ov, R511_CAM_UV_EN, 0x00); + reg_w(ov, R511_SNAP_UV_EN, 0x00); + reg_w(ov, R511_SNAP_OPTS, 0x01); + } else { + reg_w(ov, R511_CAM_UV_EN, 0x01); + reg_w(ov, R511_SNAP_UV_EN, 0x01); + reg_w(ov, R511_SNAP_OPTS, 0x03); + } + + /* Here I'm assuming that snapshot size == image size. + * I hope that's always true. --claudio + */ + hsegs = (width >> 3) - 1; + vsegs = (height >> 3) - 1; + + reg_w(ov, R511_CAM_PXCNT, hsegs); + reg_w(ov, R511_CAM_LNCNT, vsegs); + reg_w(ov, R511_CAM_PXDIV, 0x00); + reg_w(ov, R511_CAM_LNDIV, 0x00); + + /* YUV420, low pass filter on */ + reg_w(ov, R511_CAM_OPTS, 0x03); + + /* Snapshot additions */ + reg_w(ov, R511_SNAP_PXCNT, hsegs); + reg_w(ov, R511_SNAP_LNCNT, vsegs); + reg_w(ov, R511_SNAP_PXDIV, 0x00); + reg_w(ov, R511_SNAP_LNDIV, 0x00); + + if (ov->compress) { + /* Enable Y and UV quantization and compression */ + reg_w(ov, R511_COMP_EN, 0x07); + reg_w(ov, R511_COMP_LUT_EN, 0x03); + ov51x_reset(ov, OV511_RESET_OMNICE); + } + + if (ov51x_restart(ov) < 0) + return -EIO; + + return 0; +} + +/* Sets up the OV518/OV518+ with the given image parameters + * + * OV518 needs a completely different approach, until we can figure out what + * the individual registers do. Also, only 15 FPS is supported now. + * + * Do not put any sensor-specific code in here (including I2C I/O functions) + */ +static int +ov518_mode_init_regs(struct usb_ov511 *ov, + int width, int height, int mode, int sub_flag) +{ + int hsegs, vsegs, hi_res; + + if (sub_flag) { + width = ov->subw; + height = ov->subh; + } + + PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", + width, height, mode, sub_flag); + + if (width % 16 || height % 8) { + err("Invalid size (%d, %d)", width, height); + return -EINVAL; + } + + if (width < ov->minwidth || height < ov->minheight) { + err("Requested dimensions are too small"); + return -EINVAL; + } + + if (width >= 320 && height >= 240) { + hi_res = 1; + } else if (width >= 320 || height >= 240) { + err("Invalid width/height combination (%d, %d)", width, height); + return -EINVAL; + } else { + hi_res = 0; + } + + if (ov51x_stop(ov) < 0) + return -EIO; + + /******** Set the mode ********/ + + reg_w(ov, 0x2b, 0); + reg_w(ov, 0x2c, 0); + reg_w(ov, 0x2d, 0); + reg_w(ov, 0x2e, 0); + reg_w(ov, 0x3b, 0); + reg_w(ov, 0x3c, 0); + reg_w(ov, 0x3d, 0); + reg_w(ov, 0x3e, 0); + + if (ov->bridge == BRG_OV518 && ov518_color) { + /* OV518 needs U and V swapped */ + i2c_w_mask(ov, 0x15, 0x00, 0x01); + + if (mode == VIDEO_PALETTE_GREY) { + /* Set 16-bit input format (UV data are ignored) */ + reg_w_mask(ov, 0x20, 0x00, 0x08); + + /* Set 8-bit (4:0:0) output format */ + reg_w_mask(ov, 0x28, 0x00, 0xf0); + reg_w_mask(ov, 0x38, 0x00, 0xf0); + } else { + /* Set 8-bit (YVYU) input format */ + reg_w_mask(ov, 0x20, 0x08, 0x08); + + /* Set 12-bit (4:2:0) output format */ + reg_w_mask(ov, 0x28, 0x80, 0xf0); + reg_w_mask(ov, 0x38, 0x80, 0xf0); + } + } else { + reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); + reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); + } + + hsegs = width / 16; + vsegs = height / 4; + + reg_w(ov, 0x29, hsegs); + reg_w(ov, 0x2a, vsegs); + + reg_w(ov, 0x39, hsegs); + reg_w(ov, 0x3a, vsegs); + + /* Windows driver does this here; who knows why */ + reg_w(ov, 0x2f, 0x80); + + /******** Set the framerate (to 15 FPS) ********/ + + /* Mode independent, but framerate dependent, regs */ + reg_w(ov, 0x51, 0x02); /* Clock divider; lower==faster */ + reg_w(ov, 0x22, 0x18); + reg_w(ov, 0x23, 0xff); + + if (ov->bridge == BRG_OV518PLUS) + reg_w(ov, 0x21, 0x19); + else + reg_w(ov, 0x71, 0x19); /* Compression-related? */ + + // FIXME: Sensor-specific + /* Bit 5 is what matters here. Of course, it is "reserved" */ + i2c_w(ov, 0x54, 0x23); + + reg_w(ov, 0x2f, 0x80); + + if (ov->bridge == BRG_OV518PLUS) { + reg_w(ov, 0x24, 0x94); + reg_w(ov, 0x25, 0x90); + ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */ + ov518_reg_w32(ov, 0xc6, 540, 2); /* 21ch */ + ov518_reg_w32(ov, 0xc7, 540, 2); /* 21ch */ + ov518_reg_w32(ov, 0xc8, 108, 2); /* 6ch */ + ov518_reg_w32(ov, 0xca, 131098, 3); /* 2001ah */ + ov518_reg_w32(ov, 0xcb, 532, 2); /* 214h */ + ov518_reg_w32(ov, 0xcc, 2400, 2); /* 960h */ + ov518_reg_w32(ov, 0xcd, 32, 2); /* 20h */ + ov518_reg_w32(ov, 0xce, 608, 2); /* 260h */ + } else { + reg_w(ov, 0x24, 0x9f); + reg_w(ov, 0x25, 0x90); + ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */ + ov518_reg_w32(ov, 0xc6, 500, 2); /* 1f4h */ + ov518_reg_w32(ov, 0xc7, 500, 2); /* 1f4h */ + ov518_reg_w32(ov, 0xc8, 142, 2); /* 8eh */ + ov518_reg_w32(ov, 0xca, 131098, 3); /* 2001ah */ + ov518_reg_w32(ov, 0xcb, 532, 2); /* 214h */ + ov518_reg_w32(ov, 0xcc, 2000, 2); /* 7d0h */ + ov518_reg_w32(ov, 0xcd, 32, 2); /* 20h */ + ov518_reg_w32(ov, 0xce, 608, 2); /* 260h */ + } + + reg_w(ov, 0x2f, 0x80); + + if (ov51x_restart(ov) < 0) + return -EIO; + + /* Reset it just for good measure */ + if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) + return -EIO; + + return 0; +} + +/* This is a wrapper around the OV511, OV518, and sensor specific functions */ +static int +mode_init_regs(struct usb_ov511 *ov, + int width, int height, int mode, int sub_flag) +{ + int rc = 0; + + if (!ov || !ov->dev) + return -EFAULT; + + if (ov->bclass == BCL_OV518) { + rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag); + } else { + rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag); + } + + if (FATAL_ERROR(rc)) + return rc; + + switch (ov->sensor) { + case SEN_OV7610: + case SEN_OV7620: + case SEN_OV76BE: + case SEN_OV8600: + case SEN_OV6620: + case SEN_OV6630: + rc = set_ov_sensor_window(ov, width, height, mode, sub_flag); + break; + case SEN_KS0127: + case SEN_KS0127B: + err("KS0127-series decoders not supported yet"); + rc = -EINVAL; + break; + case SEN_SAA7111A: +// rc = mode_init_saa_sensor_regs(ov, width, height, mode, +// sub_flag); + + PDEBUG(1, "SAA status = 0x%02X", i2c_r(ov, 0x1f)); + break; + default: + err("Unknown sensor"); + rc = -EINVAL; + } + + if (FATAL_ERROR(rc)) + return rc; + + /* Sensor-independent settings */ + rc = sensor_set_auto_brightness(ov, ov->auto_brt); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_set_auto_exposure(ov, ov->auto_exp); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_set_banding_filter(ov, bandingfilter); + if (FATAL_ERROR(rc)) + return rc; + + if (ov->lightfreq) { + rc = sensor_set_light_freq(ov, lightfreq); + if (FATAL_ERROR(rc)) + return rc; + } + + rc = sensor_set_backlight(ov, ov->backlight); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_set_mirror(ov, ov->mirror); + if (FATAL_ERROR(rc)) + return rc; + + return 0; +} + +/* This sets the default image parameters. This is useful for apps that use + * read() and do not set these. + */ +static int +ov51x_set_default_params(struct usb_ov511 *ov) +{ + int i; + + /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used + * (using read() instead). */ + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov->frame[i].width = ov->maxwidth; + ov->frame[i].height = ov->maxheight; + ov->frame[i].bytes_read = 0; + if (force_palette) + ov->frame[i].format = force_palette; + else + ov->frame[i].format = VIDEO_PALETTE_YUV420; + + ov->frame[i].depth = get_depth(ov->frame[i].format); + } + + PDEBUG(3, "%dx%d, %s", ov->maxwidth, ov->maxheight, + symbolic(v4l1_plist, ov->frame[0].format)); + + /* Initialize to max width/height, YUV420 or RGB24 (if supported) */ + if (mode_init_regs(ov, ov->maxwidth, ov->maxheight, + ov->frame[0].format, 0) < 0) + return -EINVAL; + + return 0; +} + +/********************************************************************** + * + * Video decoder stuff + * + **********************************************************************/ + +/* Set analog input port of decoder */ +static int +decoder_set_input(struct usb_ov511 *ov, int input) +{ + PDEBUG(4, "port %d", input); + + switch (ov->sensor) { + case SEN_SAA7111A: + { + /* Select mode */ + i2c_w_mask(ov, 0x02, input, 0x07); + /* Bypass chrominance trap for modes 4..7 */ + i2c_w_mask(ov, 0x09, (input > 3) ? 0x80:0x00, 0x80); + break; + } + default: + return -EINVAL; + } + + return 0; +} + +/* Get ASCII name of video input */ +static int +decoder_get_input_name(struct usb_ov511 *ov, int input, char *name) +{ + switch (ov->sensor) { + case SEN_SAA7111A: + { + if (input < 0 || input > 7) + return -EINVAL; + else if (input < 4) + sprintf(name, "CVBS-%d", input); + else // if (input < 8) + sprintf(name, "S-Video-%d", input - 4); + break; + } + default: + sprintf(name, "%s", "Camera"); + } + + return 0; +} + +/* Set norm (NTSC, PAL, SECAM, AUTO) */ +static int +decoder_set_norm(struct usb_ov511 *ov, int norm) +{ + PDEBUG(4, "%d", norm); + + switch (ov->sensor) { + case SEN_SAA7111A: + { + int reg_8, reg_e; + + if (norm == VIDEO_MODE_NTSC) { + reg_8 = 0x40; /* 60 Hz */ + reg_e = 0x00; /* NTSC M / PAL BGHI */ + } else if (norm == VIDEO_MODE_PAL) { + reg_8 = 0x00; /* 50 Hz */ + reg_e = 0x00; /* NTSC M / PAL BGHI */ + } else if (norm == VIDEO_MODE_AUTO) { + reg_8 = 0x80; /* Auto field detect */ + reg_e = 0x00; /* NTSC M / PAL BGHI */ + } else if (norm == VIDEO_MODE_SECAM) { + reg_8 = 0x00; /* 50 Hz */ + reg_e = 0x50; /* SECAM / PAL 4.43 */ + } else { + return -EINVAL; + } + + i2c_w_mask(ov, 0x08, reg_8, 0xc0); + i2c_w_mask(ov, 0x0e, reg_e, 0x70); + break; + } + default: + return -EINVAL; + } + + return 0; +} + +/********************************************************************** + * + * Raw data parsing + * + **********************************************************************/ + +/* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the + * image at pOut is specified by w. + */ +static inline void +make_8x8(unsigned char *pIn, unsigned char *pOut, int w) +{ + unsigned char *pOut1 = pOut; + int x, y; + + for (y = 0; y < 8; y++) { + pOut1 = pOut; + for (x = 0; x < 8; x++) { + *pOut1++ = *pIn++; + } + pOut += w; + } +} + +/* + * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments. + * The segments represent 4 squares of 8x8 pixels as follows: + * + * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 + * 8 9 ... 15 72 73 ... 79 200 201 ... 207 + * ... ... ... + * 56 57 ... 63 120 121 ... 127 248 249 ... 255 + * + */ +static void +yuv400raw_to_yuv400p(struct ov511_frame *frame, + unsigned char *pIn0, unsigned char *pOut0) +{ + int x, y; + unsigned char *pIn, *pOut, *pOutLine; + + /* Copy Y */ + pIn = pIn0; + pOutLine = pOut0; + for (y = 0; y < frame->rawheight - 1; y += 8) { + pOut = pOutLine; + for (x = 0; x < frame->rawwidth - 1; x += 8) { + make_8x8(pIn, pOut, frame->rawwidth); + pIn += 64; + pOut += 8; + } + pOutLine += 8 * frame->rawwidth; + } +} + +/* + * For YUV 4:2:0 images, the data show up in 384 byte segments. + * The first 64 bytes of each segment are U, the next 64 are V. The U and + * V are arranged as follows: + * + * 0 1 ... 7 + * 8 9 ... 15 + * ... + * 56 57 ... 63 + * + * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block). + * + * The next 256 bytes are full resolution Y data and represent 4 squares + * of 8x8 pixels as follows: + * + * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 + * 8 9 ... 15 72 73 ... 79 200 201 ... 207 + * ... ... ... + * 56 57 ... 63 120 121 ... 127 ... 248 249 ... 255 + * + * Note that the U and V data in one segment represent a 16 x 16 pixel + * area, but the Y data represent a 32 x 8 pixel area. If the width is not an + * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the + * next horizontal stripe. + * + * If dumppix module param is set, _parse_data just dumps the incoming segments, + * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480 + * this puts the data on the standard output and can be analyzed with the + * parseppm.c utility I wrote. That's a much faster way for figuring out how + * these data are scrambled. + */ + +/* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0. + * + * FIXME: Currently only handles width and height that are multiples of 16 + */ +static void +yuv420raw_to_yuv420p(struct ov511_frame *frame, + unsigned char *pIn0, unsigned char *pOut0) +{ + int k, x, y; + unsigned char *pIn, *pOut, *pOutLine; + const unsigned int a = frame->rawwidth * frame->rawheight; + const unsigned int w = frame->rawwidth / 2; + + /* Copy U and V */ + pIn = pIn0; + pOutLine = pOut0 + a; + for (y = 0; y < frame->rawheight - 1; y += 16) { + pOut = pOutLine; + for (x = 0; x < frame->rawwidth - 1; x += 16) { + make_8x8(pIn, pOut, w); + make_8x8(pIn + 64, pOut + a/4, w); + pIn += 384; + pOut += 8; + } + pOutLine += 8 * w; + } + + /* Copy Y */ + pIn = pIn0 + 128; + pOutLine = pOut0; + k = 0; + for (y = 0; y < frame->rawheight - 1; y += 8) { + pOut = pOutLine; + for (x = 0; x < frame->rawwidth - 1; x += 8) { + make_8x8(pIn, pOut, frame->rawwidth); + pIn += 64; + pOut += 8; + if ((++k) > 3) { + k = 0; + pIn += 128; + } + } + pOutLine += 8 * frame->rawwidth; + } +} + +/********************************************************************** + * + * Decompression + * + **********************************************************************/ + +/* Chooses a decompression module, locks it, and sets ov->decomp_ops + * accordingly. Returns -ENXIO if decompressor is not available, otherwise + * returns 0 if no other error. + */ +static int +request_decompressor(struct usb_ov511 *ov) +{ + if (!ov) + return -ENODEV; + + if (ov->decomp_ops) { + err("ERROR: Decompressor already requested!"); + return -EINVAL; + } + + lock_kernel(); + + /* Try to get MMX, and fall back on no-MMX if necessary */ + if (ov->bclass == BCL_OV511) { + if (ov511_mmx_decomp_ops) { + PDEBUG(3, "Using OV511 MMX decompressor"); + ov->decomp_ops = ov511_mmx_decomp_ops; + } else if (ov511_decomp_ops) { + PDEBUG(3, "Using OV511 decompressor"); + ov->decomp_ops = ov511_decomp_ops; + } else { + err("No decompressor available"); + } + } else if (ov->bclass == BCL_OV518) { + if (ov518_mmx_decomp_ops) { + PDEBUG(3, "Using OV518 MMX decompressor"); + ov->decomp_ops = ov518_mmx_decomp_ops; + } else if (ov518_decomp_ops) { + PDEBUG(3, "Using OV518 decompressor"); + ov->decomp_ops = ov518_decomp_ops; + } else { + err("No decompressor available"); + } + } else { + err("Unknown bridge"); + } + + if (!ov->decomp_ops) + goto nosys; + + if (!ov->decomp_ops->owner) { + ov->decomp_ops = NULL; + goto nosys; + } + + if (!try_module_get(ov->decomp_ops->owner)) + goto nosys; + + unlock_kernel(); + return 0; + + nosys: + unlock_kernel(); + return -ENOSYS; +} + +/* Unlocks decompression module and nulls ov->decomp_ops. Safe to call even + * if ov->decomp_ops is NULL. + */ +static void +release_decompressor(struct usb_ov511 *ov) +{ + int released = 0; /* Did we actually do anything? */ + + if (!ov) + return; + + lock_kernel(); + + if (ov->decomp_ops) { + module_put(ov->decomp_ops->owner); + released = 1; + } + + ov->decomp_ops = NULL; + + unlock_kernel(); + + if (released) + PDEBUG(3, "Decompressor released"); +} + +static void +decompress(struct usb_ov511 *ov, struct ov511_frame *frame, + unsigned char *pIn0, unsigned char *pOut0) +{ + if (!ov->decomp_ops) + if (request_decompressor(ov)) + return; + + PDEBUG(4, "Decompressing %d bytes", frame->bytes_recvd); + + if (frame->format == VIDEO_PALETTE_GREY + && ov->decomp_ops->decomp_400) { + int ret = ov->decomp_ops->decomp_400( + pIn0, + pOut0, + frame->compbuf, + frame->rawwidth, + frame->rawheight, + frame->bytes_recvd); + PDEBUG(4, "DEBUG: decomp_400 returned %d", ret); + } else if (frame->format != VIDEO_PALETTE_GREY + && ov->decomp_ops->decomp_420) { + int ret = ov->decomp_ops->decomp_420( + pIn0, + pOut0, + frame->compbuf, + frame->rawwidth, + frame->rawheight, + frame->bytes_recvd); + PDEBUG(4, "DEBUG: decomp_420 returned %d", ret); + } else { + err("Decompressor does not support this format"); + } +} + +/********************************************************************** + * + * Format conversion + * + **********************************************************************/ + +/* Fuses even and odd fields together, and doubles width. + * INPUT: an odd field followed by an even field at pIn0, in YUV planar format + * OUTPUT: a normal YUV planar image, with correct aspect ratio + */ +static void +deinterlace(struct ov511_frame *frame, int rawformat, + unsigned char *pIn0, unsigned char *pOut0) +{ + const int fieldheight = frame->rawheight / 2; + const int fieldpix = fieldheight * frame->rawwidth; + const int w = frame->width; + int x, y; + unsigned char *pInEven, *pInOdd, *pOut; + + PDEBUG(5, "fieldheight=%d", fieldheight); + + if (frame->rawheight != frame->height) { + err("invalid height"); + return; + } + + if ((frame->rawwidth * 2) != frame->width) { + err("invalid width"); + return; + } + + /* Y */ + pInOdd = pIn0; + pInEven = pInOdd + fieldpix; + pOut = pOut0; + for (y = 0; y < fieldheight; y++) { + for (x = 0; x < frame->rawwidth; x++) { + *pOut = *pInEven; + *(pOut+1) = *pInEven++; + *(pOut+w) = *pInOdd; + *(pOut+w+1) = *pInOdd++; + pOut += 2; + } + pOut += w; + } + + if (rawformat == RAWFMT_YUV420) { + /* U */ + pInOdd = pIn0 + fieldpix * 2; + pInEven = pInOdd + fieldpix / 4; + for (y = 0; y < fieldheight / 2; y++) { + for (x = 0; x < frame->rawwidth / 2; x++) { + *pOut = *pInEven; + *(pOut+1) = *pInEven++; + *(pOut+w/2) = *pInOdd; + *(pOut+w/2+1) = *pInOdd++; + pOut += 2; + } + pOut += w/2; + } + /* V */ + pInOdd = pIn0 + fieldpix * 2 + fieldpix / 2; + pInEven = pInOdd + fieldpix / 4; + for (y = 0; y < fieldheight / 2; y++) { + for (x = 0; x < frame->rawwidth / 2; x++) { + *pOut = *pInEven; + *(pOut+1) = *pInEven++; + *(pOut+w/2) = *pInOdd; + *(pOut+w/2+1) = *pInOdd++; + pOut += 2; + } + pOut += w/2; + } + } +} + +static void +ov51x_postprocess_grey(struct usb_ov511 *ov, struct ov511_frame *frame) +{ + /* Deinterlace frame, if necessary */ + if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) { + if (frame->compressed) + decompress(ov, frame, frame->rawdata, + frame->tempdata); + else + yuv400raw_to_yuv400p(frame, frame->rawdata, + frame->tempdata); + + deinterlace(frame, RAWFMT_YUV400, frame->tempdata, + frame->data); + } else { + if (frame->compressed) + decompress(ov, frame, frame->rawdata, + frame->data); + else + yuv400raw_to_yuv400p(frame, frame->rawdata, + frame->data); + } +} + +/* Process raw YUV420 data into standard YUV420P */ +static void +ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame) +{ + /* Deinterlace frame, if necessary */ + if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) { + if (frame->compressed) + decompress(ov, frame, frame->rawdata, frame->tempdata); + else + yuv420raw_to_yuv420p(frame, frame->rawdata, + frame->tempdata); + + deinterlace(frame, RAWFMT_YUV420, frame->tempdata, + frame->data); + } else { + if (frame->compressed) + decompress(ov, frame, frame->rawdata, frame->data); + else + yuv420raw_to_yuv420p(frame, frame->rawdata, + frame->data); + } +} + +/* Post-processes the specified frame. This consists of: + * 1. Decompress frame, if necessary + * 2. Deinterlace frame and scale to proper size, if necessary + * 3. Convert from YUV planar to destination format, if necessary + * 4. Fix the RGB offset, if necessary + */ +static void +ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame) +{ + if (dumppix) { + memset(frame->data, 0, + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); + PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd); + memcpy(frame->data, frame->rawdata, frame->bytes_recvd); + } else { + switch (frame->format) { + case VIDEO_PALETTE_GREY: + ov51x_postprocess_grey(ov, frame); + break; + case VIDEO_PALETTE_YUV420: + case VIDEO_PALETTE_YUV420P: + ov51x_postprocess_yuv420(ov, frame); + break; + default: + err("Cannot convert data to %s", + symbolic(v4l1_plist, frame->format)); + } + } +} + +/********************************************************************** + * + * OV51x data transfer, IRQ handler + * + **********************************************************************/ + +static inline void +ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n) +{ + int num, offset; + int pnum = in[ov->packet_size - 1]; /* Get packet number */ + int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight); + struct ov511_frame *frame = &ov->frame[ov->curframe]; + struct timeval *ts; + + /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th + * byte non-zero. The EOF packet has image width/height in the + * 10th and 11th bytes. The 9th byte is given as follows: + * + * bit 7: EOF + * 6: compression enabled + * 5: 422/420/400 modes + * 4: 422/420/400 modes + * 3: 1 + * 2: snapshot button on + * 1: snapshot frame + * 0: even/odd field + */ + + if (printph) { + info("ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", + pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6], + in[7], in[8], in[9], in[10], in[11]); + } + + /* Check for SOF/EOF packet */ + if ((in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) || + (~in[8] & 0x08)) + goto check_middle; + + /* Frame end */ + if (in[8] & 0x80) { + ts = (struct timeval *)(frame->data + + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); + do_gettimeofday(ts); + + /* Get the actual frame size from the EOF header */ + frame->rawwidth = ((int)(in[9]) + 1) * 8; + frame->rawheight = ((int)(in[10]) + 1) * 8; + + PDEBUG(4, "Frame end, frame=%d, pnum=%d, w=%d, h=%d, recvd=%d", + ov->curframe, pnum, frame->rawwidth, frame->rawheight, + frame->bytes_recvd); + + /* Validate the header data */ + RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); + RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, + ov->maxheight); + + /* Don't allow byte count to exceed buffer size */ + RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw); + + if (frame->scanstate == STATE_LINES) { + int nextf; + + frame->grabstate = FRAME_DONE; + wake_up_interruptible(&frame->wq); + + /* If next frame is ready or grabbing, + * point to it */ + nextf = (ov->curframe + 1) % OV511_NUMFRAMES; + if (ov->frame[nextf].grabstate == FRAME_READY + || ov->frame[nextf].grabstate == FRAME_GRABBING) { + ov->curframe = nextf; + ov->frame[nextf].scanstate = STATE_SCANNING; + } else { + if (frame->grabstate == FRAME_DONE) { + PDEBUG(4, "** Frame done **"); + } else { + PDEBUG(4, "Frame not ready? state = %d", + ov->frame[nextf].grabstate); + } + + ov->curframe = -1; + } + } else { + PDEBUG(5, "Frame done, but not scanning"); + } + /* Image corruption caused by misplaced frame->segment = 0 + * fixed by carlosf@conectiva.com.br + */ + } else { + /* Frame start */ + PDEBUG(4, "Frame start, framenum = %d", ov->curframe); + + /* Check to see if it's a snapshot frame */ + /* FIXME?? Should the snapshot reset go here? Performance? */ + if (in[8] & 0x02) { + frame->snapshot = 1; + PDEBUG(3, "snapshot detected"); + } + + frame->scanstate = STATE_LINES; + frame->bytes_recvd = 0; + frame->compressed = in[8] & 0x40; + } + +check_middle: + /* Are we in a frame? */ + if (frame->scanstate != STATE_LINES) { + PDEBUG(5, "Not in a frame; packet skipped"); + return; + } + + /* If frame start, skip header */ + if (frame->bytes_recvd == 0) + offset = 9; + else + offset = 0; + + num = n - offset - 1; + + /* Dump all data exactly as received */ + if (dumppix == 2) { + frame->bytes_recvd += n - 1; + if (frame->bytes_recvd <= max_raw) + memcpy(frame->rawdata + frame->bytes_recvd - (n - 1), + in, n - 1); + else + PDEBUG(3, "Raw data buffer overrun!! (%d)", + frame->bytes_recvd - max_raw); + } else if (!frame->compressed && !remove_zeros) { + frame->bytes_recvd += num; + if (frame->bytes_recvd <= max_raw) + memcpy(frame->rawdata + frame->bytes_recvd - num, + in + offset, num); + else + PDEBUG(3, "Raw data buffer overrun!! (%d)", + frame->bytes_recvd - max_raw); + } else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */ + int b, read = 0, allzero, copied = 0; + if (offset) { + frame->bytes_recvd += 32 - offset; // Bytes out + memcpy(frame->rawdata, in + offset, 32 - offset); + read += 32; + } + + while (read < n - 1) { + allzero = 1; + for (b = 0; b < 32; b++) { + if (in[read + b]) { + allzero = 0; + break; + } + } + + if (allzero) { + /* Don't copy it */ + } else { + if (frame->bytes_recvd + copied + 32 <= max_raw) + { + memcpy(frame->rawdata + + frame->bytes_recvd + copied, + in + read, 32); + copied += 32; + } else { + PDEBUG(3, "Raw data buffer overrun!!"); + } + } + read += 32; + } + + frame->bytes_recvd += copied; + } +} + +static inline void +ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n) +{ + int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight); + struct ov511_frame *frame = &ov->frame[ov->curframe]; + struct timeval *ts; + + /* Don't copy the packet number byte */ + if (ov->packet_numbering) + --n; + + /* A false positive here is likely, until OVT gives me + * the definitive SOF/EOF format */ + if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) { + if (printph) { + info("ph: %2x %2x %2x %2x %2x %2x %2x %2x", in[0], + in[1], in[2], in[3], in[4], in[5], in[6], in[7]); + } + + if (frame->scanstate == STATE_LINES) { + PDEBUG(4, "Detected frame end/start"); + goto eof; + } else { //scanstate == STATE_SCANNING + /* Frame start */ + PDEBUG(4, "Frame start, framenum = %d", ov->curframe); + goto sof; + } + } else { + goto check_middle; + } + +eof: + ts = (struct timeval *)(frame->data + + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); + do_gettimeofday(ts); + + PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d", + ov->curframe, + (int)(in[9]), (int)(in[10]), frame->bytes_recvd); + + // FIXME: Since we don't know the header formats yet, + // there is no way to know what the actual image size is + frame->rawwidth = frame->width; + frame->rawheight = frame->height; + + /* Validate the header data */ + RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); + RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight); + + /* Don't allow byte count to exceed buffer size */ + RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw); + + if (frame->scanstate == STATE_LINES) { + int nextf; + + frame->grabstate = FRAME_DONE; + wake_up_interruptible(&frame->wq); + + /* If next frame is ready or grabbing, + * point to it */ + nextf = (ov->curframe + 1) % OV511_NUMFRAMES; + if (ov->frame[nextf].grabstate == FRAME_READY + || ov->frame[nextf].grabstate == FRAME_GRABBING) { + ov->curframe = nextf; + ov->frame[nextf].scanstate = STATE_SCANNING; + frame = &ov->frame[nextf]; + } else { + if (frame->grabstate == FRAME_DONE) { + PDEBUG(4, "** Frame done **"); + } else { + PDEBUG(4, "Frame not ready? state = %d", + ov->frame[nextf].grabstate); + } + + ov->curframe = -1; + PDEBUG(4, "SOF dropped (no active frame)"); + return; /* Nowhere to store this frame */ + } + } +sof: + PDEBUG(4, "Starting capture on frame %d", frame->framenum); + +// Snapshot not reverse-engineered yet. +#if 0 + /* Check to see if it's a snapshot frame */ + /* FIXME?? Should the snapshot reset go here? Performance? */ + if (in[8] & 0x02) { + frame->snapshot = 1; + PDEBUG(3, "snapshot detected"); + } +#endif + frame->scanstate = STATE_LINES; + frame->bytes_recvd = 0; + frame->compressed = 1; + +check_middle: + /* Are we in a frame? */ + if (frame->scanstate != STATE_LINES) { + PDEBUG(4, "scanstate: no SOF yet"); + return; + } + + /* Dump all data exactly as received */ + if (dumppix == 2) { + frame->bytes_recvd += n; + if (frame->bytes_recvd <= max_raw) + memcpy(frame->rawdata + frame->bytes_recvd - n, in, n); + else + PDEBUG(3, "Raw data buffer overrun!! (%d)", + frame->bytes_recvd - max_raw); + } else { + /* All incoming data are divided into 8-byte segments. If the + * segment contains all zero bytes, it must be skipped. These + * zero-segments allow the OV518 to mainain a constant data rate + * regardless of the effectiveness of the compression. Segments + * are aligned relative to the beginning of each isochronous + * packet. The first segment in each image is a header (the + * decompressor skips it later). + */ + + int b, read = 0, allzero, copied = 0; + + while (read < n) { + allzero = 1; + for (b = 0; b < 8; b++) { + if (in[read + b]) { + allzero = 0; + break; + } + } + + if (allzero) { + /* Don't copy it */ + } else { + if (frame->bytes_recvd + copied + 8 <= max_raw) + { + memcpy(frame->rawdata + + frame->bytes_recvd + copied, + in + read, 8); + copied += 8; + } else { + PDEBUG(3, "Raw data buffer overrun!!"); + } + } + read += 8; + } + frame->bytes_recvd += copied; + } +} + +static void +ov51x_isoc_irq(struct urb *urb) +{ + int i; + struct usb_ov511 *ov; + struct ov511_sbuf *sbuf; + + if (!urb->context) { + PDEBUG(4, "no context"); + return; + } + + sbuf = urb->context; + ov = sbuf->ov; + + if (!ov || !ov->dev || !ov->user) { + PDEBUG(4, "no device, or not open"); + return; + } + + if (!ov->streaming) { + PDEBUG(4, "hmmm... not streaming, but got interrupt"); + return; + } + + if (urb->status == -ENOENT || urb->status == -ECONNRESET) { + PDEBUG(4, "URB unlinked"); + return; + } + + if (urb->status != -EINPROGRESS && urb->status != 0) { + err("ERROR: urb->status=%d: %s", urb->status, + symbolic(urb_errlist, urb->status)); + } + + /* Copy the data received into our frame buffer */ + PDEBUG(5, "sbuf[%d]: Moving %d packets", sbuf->n, + urb->number_of_packets); + for (i = 0; i < urb->number_of_packets; i++) { + /* Warning: Don't call *_move_data() if no frame active! */ + if (ov->curframe >= 0) { + int n = urb->iso_frame_desc[i].actual_length; + int st = urb->iso_frame_desc[i].status; + unsigned char *cdata; + + urb->iso_frame_desc[i].actual_length = 0; + urb->iso_frame_desc[i].status = 0; + + cdata = urb->transfer_buffer + + urb->iso_frame_desc[i].offset; + + if (!n) { + PDEBUG(4, "Zero-length packet"); + continue; + } + + if (st) + PDEBUG(2, "data error: [%d] len=%d, status=%d", + i, n, st); + + if (ov->bclass == BCL_OV511) + ov511_move_data(ov, cdata, n); + else if (ov->bclass == BCL_OV518) + ov518_move_data(ov, cdata, n); + else + err("Unknown bridge device (%d)", ov->bridge); + + } else if (waitqueue_active(&ov->wq)) { + wake_up_interruptible(&ov->wq); + } + } + + /* Resubmit this URB */ + urb->dev = ov->dev; + if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0) + err("usb_submit_urb() ret %d", i); + + return; +} + +/**************************************************************************** + * + * Stream initialization and termination + * + ***************************************************************************/ + +static int +ov51x_init_isoc(struct usb_ov511 *ov) +{ + struct urb *urb; + int fx, err, n, size; + + PDEBUG(3, "*** Initializing capture ***"); + + ov->curframe = -1; + + if (ov->bridge == BRG_OV511) { + if (cams == 1) + size = 993; + else if (cams == 2) + size = 513; + else if (cams == 3 || cams == 4) + size = 257; + else { + err("\"cams\" parameter too high!"); + return -1; + } + } else if (ov->bridge == BRG_OV511PLUS) { + if (cams == 1) + size = 961; + else if (cams == 2) + size = 513; + else if (cams == 3 || cams == 4) + size = 257; + else if (cams >= 5 && cams <= 8) + size = 129; + else if (cams >= 9 && cams <= 31) + size = 33; + else { + err("\"cams\" parameter too high!"); + return -1; + } + } else if (ov->bclass == BCL_OV518) { + if (cams == 1) + size = 896; + else if (cams == 2) + size = 512; + else if (cams == 3 || cams == 4) + size = 256; + else if (cams >= 5 && cams <= 8) + size = 128; + else { + err("\"cams\" parameter too high!"); + return -1; + } + } else { + err("invalid bridge type"); + return -1; + } + + // FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now + if (ov->bclass == BCL_OV518) { + if (packetsize == -1) { + ov518_set_packet_size(ov, 640); + } else { + info("Forcing packet size to %d", packetsize); + ov518_set_packet_size(ov, packetsize); + } + } else { + if (packetsize == -1) { + ov511_set_packet_size(ov, size); + } else { + info("Forcing packet size to %d", packetsize); + ov511_set_packet_size(ov, packetsize); + } + } + + for (n = 0; n < OV511_NUMSBUF; n++) { + urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); + if (!urb) { + err("init isoc: usb_alloc_urb ret. NULL"); + return -ENOMEM; + } + ov->sbuf[n].urb = urb; + urb->dev = ov->dev; + urb->context = &ov->sbuf[n]; + urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = ov->sbuf[n].data; + urb->complete = ov51x_isoc_irq; + urb->number_of_packets = FRAMES_PER_DESC; + urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC; + urb->interval = 1; + for (fx = 0; fx < FRAMES_PER_DESC; fx++) { + urb->iso_frame_desc[fx].offset = ov->packet_size * fx; + urb->iso_frame_desc[fx].length = ov->packet_size; + } + } + + ov->streaming = 1; + + for (n = 0; n < OV511_NUMSBUF; n++) { + ov->sbuf[n].urb->dev = ov->dev; + err = usb_submit_urb(ov->sbuf[n].urb, GFP_KERNEL); + if (err) { + err("init isoc: usb_submit_urb(%d) ret %d", n, err); + return err; + } + } + + return 0; +} + +static void +ov51x_unlink_isoc(struct usb_ov511 *ov) +{ + int n; + + /* Unschedule all of the iso td's */ + for (n = OV511_NUMSBUF - 1; n >= 0; n--) { + if (ov->sbuf[n].urb) { + usb_kill_urb(ov->sbuf[n].urb); + usb_free_urb(ov->sbuf[n].urb); + ov->sbuf[n].urb = NULL; + } + } +} + +static void +ov51x_stop_isoc(struct usb_ov511 *ov) +{ + if (!ov->streaming || !ov->dev) + return; + + PDEBUG(3, "*** Stopping capture ***"); + + if (ov->bclass == BCL_OV518) + ov518_set_packet_size(ov, 0); + else + ov511_set_packet_size(ov, 0); + + ov->streaming = 0; + + ov51x_unlink_isoc(ov); +} + +static int +ov51x_new_frame(struct usb_ov511 *ov, int framenum) +{ + struct ov511_frame *frame; + int newnum; + + PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum); + + if (!ov->dev) + return -1; + + /* If we're not grabbing a frame right now and the other frame is */ + /* ready to be grabbed into, then use it instead */ + if (ov->curframe == -1) { + newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES; + if (ov->frame[newnum].grabstate == FRAME_READY) + framenum = newnum; + } else + return 0; + + frame = &ov->frame[framenum]; + + PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum, + frame->width, frame->height); + + frame->grabstate = FRAME_GRABBING; + frame->scanstate = STATE_SCANNING; + frame->snapshot = 0; + + ov->curframe = framenum; + + /* Make sure it's not too big */ + if (frame->width > ov->maxwidth) + frame->width = ov->maxwidth; + + frame->width &= ~7L; /* Multiple of 8 */ + + if (frame->height > ov->maxheight) + frame->height = ov->maxheight; + + frame->height &= ~3L; /* Multiple of 4 */ + + return 0; +} + +/**************************************************************************** + * + * Buffer management + * + ***************************************************************************/ + +/* + * - You must acquire buf_lock before entering this function. + * - Because this code will free any non-null pointer, you must be sure to null + * them if you explicitly free them somewhere else! + */ +static void +ov51x_do_dealloc(struct usb_ov511 *ov) +{ + int i; + PDEBUG(4, "entered"); + + if (ov->fbuf) { + rvfree(ov->fbuf, OV511_NUMFRAMES + * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); + ov->fbuf = NULL; + } + + vfree(ov->rawfbuf); + ov->rawfbuf = NULL; + + vfree(ov->tempfbuf); + ov->tempfbuf = NULL; + + for (i = 0; i < OV511_NUMSBUF; i++) { + kfree(ov->sbuf[i].data); + ov->sbuf[i].data = NULL; + } + + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov->frame[i].data = NULL; + ov->frame[i].rawdata = NULL; + ov->frame[i].tempdata = NULL; + if (ov->frame[i].compbuf) { + free_page((unsigned long) ov->frame[i].compbuf); + ov->frame[i].compbuf = NULL; + } + } + + PDEBUG(4, "buffer memory deallocated"); + ov->buf_state = BUF_NOT_ALLOCATED; + PDEBUG(4, "leaving"); +} + +static int +ov51x_alloc(struct usb_ov511 *ov) +{ + int i; + const int w = ov->maxwidth; + const int h = ov->maxheight; + const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h); + const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h); + + PDEBUG(4, "entered"); + down(&ov->buf_lock); + + if (ov->buf_state == BUF_ALLOCATED) + goto out; + + ov->fbuf = rvmalloc(data_bufsize); + if (!ov->fbuf) + goto error; + + ov->rawfbuf = vmalloc(raw_bufsize); + if (!ov->rawfbuf) + goto error; + + memset(ov->rawfbuf, 0, raw_bufsize); + + ov->tempfbuf = vmalloc(raw_bufsize); + if (!ov->tempfbuf) + goto error; + + memset(ov->tempfbuf, 0, raw_bufsize); + + for (i = 0; i < OV511_NUMSBUF; i++) { + ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC * + MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL); + if (!ov->sbuf[i].data) + goto error; + + PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data); + } + + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h); + ov->frame[i].rawdata = ov->rawfbuf + + i * MAX_RAW_DATA_SIZE(w, h); + ov->frame[i].tempdata = ov->tempfbuf + + i * MAX_RAW_DATA_SIZE(w, h); + + ov->frame[i].compbuf = + (unsigned char *) __get_free_page(GFP_KERNEL); + if (!ov->frame[i].compbuf) + goto error; + + PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data); + } + + ov->buf_state = BUF_ALLOCATED; +out: + up(&ov->buf_lock); + PDEBUG(4, "leaving"); + return 0; +error: + ov51x_do_dealloc(ov); + up(&ov->buf_lock); + PDEBUG(4, "errored"); + return -ENOMEM; +} + +static void +ov51x_dealloc(struct usb_ov511 *ov) +{ + PDEBUG(4, "entered"); + down(&ov->buf_lock); + ov51x_do_dealloc(ov); + up(&ov->buf_lock); + PDEBUG(4, "leaving"); +} + +/**************************************************************************** + * + * V4L 1 API + * + ***************************************************************************/ + +static int +ov51x_v4l1_open(struct inode *inode, struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct usb_ov511 *ov = video_get_drvdata(vdev); + int err, i; + + PDEBUG(4, "opening"); + + down(&ov->lock); + + err = -EBUSY; + if (ov->user) + goto out; + + ov->sub_flag = 0; + + /* In case app doesn't set them... */ + err = ov51x_set_default_params(ov); + if (err < 0) + goto out; + + /* Make sure frames are reset */ + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov->frame[i].grabstate = FRAME_UNUSED; + ov->frame[i].bytes_read = 0; + } + + /* If compression is on, make sure now that a + * decompressor can be loaded */ + if (ov->compress && !ov->decomp_ops) { + err = request_decompressor(ov); + if (err && !dumppix) + goto out; + } + + err = ov51x_alloc(ov); + if (err < 0) + goto out; + + err = ov51x_init_isoc(ov); + if (err) { + ov51x_dealloc(ov); + goto out; + } + + ov->user++; + file->private_data = vdev; + + if (ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 1); + +out: + up(&ov->lock); + return err; +} + +static int +ov51x_v4l1_close(struct inode *inode, struct file *file) +{ + struct video_device *vdev = file->private_data; + struct usb_ov511 *ov = video_get_drvdata(vdev); + + PDEBUG(4, "ov511_close"); + + down(&ov->lock); + + ov->user--; + ov51x_stop_isoc(ov); + + release_decompressor(ov); + + if (ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 0); + + if (ov->dev) + ov51x_dealloc(ov); + + up(&ov->lock); + + /* Device unplugged while open. Only a minimum of unregistration is done + * here; the disconnect callback already did the rest. */ + if (!ov->dev) { + down(&ov->cbuf_lock); + kfree(ov->cbuf); + ov->cbuf = NULL; + up(&ov->cbuf_lock); + + ov51x_dealloc(ov); + kfree(ov); + ov = NULL; + } + + file->private_data = NULL; + return 0; +} + +/* Do not call this function directly! */ +static int +ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct video_device *vdev = file->private_data; + struct usb_ov511 *ov = video_get_drvdata(vdev); + PDEBUG(5, "IOCtl: 0x%X", cmd); + + if (!ov->dev) + return -EIO; + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability *b = arg; + + PDEBUG(4, "VIDIOCGCAP"); + + memset(b, 0, sizeof(struct video_capability)); + sprintf(b->name, "%s USB Camera", + symbolic(brglist, ov->bridge)); + b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE; + b->channels = ov->num_inputs; + b->audios = 0; + b->maxwidth = ov->maxwidth; + b->maxheight = ov->maxheight; + b->minwidth = ov->minwidth; + b->minheight = ov->minheight; + + return 0; + } + case VIDIOCGCHAN: + { + struct video_channel *v = arg; + + PDEBUG(4, "VIDIOCGCHAN"); + + if ((unsigned)(v->channel) >= ov->num_inputs) { + err("Invalid channel (%d)", v->channel); + return -EINVAL; + } + + v->norm = ov->norm; + v->type = VIDEO_TYPE_CAMERA; + v->flags = 0; +// v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0; + v->tuners = 0; + decoder_get_input_name(ov, v->channel, v->name); + + return 0; + } + case VIDIOCSCHAN: + { + struct video_channel *v = arg; + int err; + + PDEBUG(4, "VIDIOCSCHAN"); + + /* Make sure it's not a camera */ + if (!ov->has_decoder) { + if (v->channel == 0) + return 0; + else + return -EINVAL; + } + + if (v->norm != VIDEO_MODE_PAL && + v->norm != VIDEO_MODE_NTSC && + v->norm != VIDEO_MODE_SECAM && + v->norm != VIDEO_MODE_AUTO) { + err("Invalid norm (%d)", v->norm); + return -EINVAL; + } + + if ((unsigned)(v->channel) >= ov->num_inputs) { + err("Invalid channel (%d)", v->channel); + return -EINVAL; + } + + err = decoder_set_input(ov, v->channel); + if (err) + return err; + + err = decoder_set_norm(ov, v->norm); + if (err) + return err; + + return 0; + } + case VIDIOCGPICT: + { + struct video_picture *p = arg; + + PDEBUG(4, "VIDIOCGPICT"); + + memset(p, 0, sizeof(struct video_picture)); + if (sensor_get_picture(ov, p)) + return -EIO; + + /* Can we get these from frame[0]? -claudio? */ + p->depth = ov->frame[0].depth; + p->palette = ov->frame[0].format; + + return 0; + } + case VIDIOCSPICT: + { + struct video_picture *p = arg; + int i, rc; + + PDEBUG(4, "VIDIOCSPICT"); + + if (!get_depth(p->palette)) + return -EINVAL; + + if (sensor_set_picture(ov, p)) + return -EIO; + + if (force_palette && p->palette != force_palette) { + info("Palette rejected (%s)", + symbolic(v4l1_plist, p->palette)); + return -EINVAL; + } + + // FIXME: Format should be independent of frames + if (p->palette != ov->frame[0].format) { + PDEBUG(4, "Detected format change"); + + rc = ov51x_wait_frames_inactive(ov); + if (rc) + return rc; + + mode_init_regs(ov, ov->frame[0].width, + ov->frame[0].height, p->palette, ov->sub_flag); + } + + PDEBUG(4, "Setting depth=%d, palette=%s", + p->depth, symbolic(v4l1_plist, p->palette)); + + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov->frame[i].depth = p->depth; + ov->frame[i].format = p->palette; + } + + return 0; + } + case VIDIOCGCAPTURE: + { + int *vf = arg; + + PDEBUG(4, "VIDIOCGCAPTURE"); + + ov->sub_flag = *vf; + return 0; + } + case VIDIOCSCAPTURE: + { + struct video_capture *vc = arg; + + PDEBUG(4, "VIDIOCSCAPTURE"); + + if (vc->flags) + return -EINVAL; + if (vc->decimation) + return -EINVAL; + + vc->x &= ~3L; + vc->y &= ~1L; + vc->y &= ~31L; + + if (vc->width == 0) + vc->width = 32; + + vc->height /= 16; + vc->height *= 16; + if (vc->height == 0) + vc->height = 16; + + ov->subx = vc->x; + ov->suby = vc->y; + ov->subw = vc->width; + ov->subh = vc->height; + + return 0; + } + case VIDIOCSWIN: + { + struct video_window *vw = arg; + int i, rc; + + PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height); + +#if 0 + if (vw->flags) + return -EINVAL; + if (vw->clipcount) + return -EINVAL; + if (vw->height != ov->maxheight) + return -EINVAL; + if (vw->width != ov->maxwidth) + return -EINVAL; +#endif + + rc = ov51x_wait_frames_inactive(ov); + if (rc) + return rc; + + rc = mode_init_regs(ov, vw->width, vw->height, + ov->frame[0].format, ov->sub_flag); + if (rc < 0) + return rc; + + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov->frame[i].width = vw->width; + ov->frame[i].height = vw->height; + } + + return 0; + } + case VIDIOCGWIN: + { + struct video_window *vw = arg; + + memset(vw, 0, sizeof(struct video_window)); + vw->x = 0; /* FIXME */ + vw->y = 0; + vw->width = ov->frame[0].width; + vw->height = ov->frame[0].height; + vw->flags = 30; + + PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height); + + return 0; + } + case VIDIOCGMBUF: + { + struct video_mbuf *vm = arg; + int i; + + PDEBUG(4, "VIDIOCGMBUF"); + + memset(vm, 0, sizeof(struct video_mbuf)); + vm->size = OV511_NUMFRAMES + * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); + vm->frames = OV511_NUMFRAMES; + + vm->offsets[0] = 0; + for (i = 1; i < OV511_NUMFRAMES; i++) { + vm->offsets[i] = vm->offsets[i-1] + + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); + } + + return 0; + } + case VIDIOCMCAPTURE: + { + struct video_mmap *vm = arg; + int rc, depth; + unsigned int f = vm->frame; + + PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width, + vm->height, symbolic(v4l1_plist, vm->format)); + + depth = get_depth(vm->format); + if (!depth) { + PDEBUG(2, "VIDIOCMCAPTURE: invalid format (%s)", + symbolic(v4l1_plist, vm->format)); + return -EINVAL; + } + + if (f >= OV511_NUMFRAMES) { + err("VIDIOCMCAPTURE: invalid frame (%d)", f); + return -EINVAL; + } + + if (vm->width > ov->maxwidth + || vm->height > ov->maxheight) { + err("VIDIOCMCAPTURE: requested dimensions too big"); + return -EINVAL; + } + + if (ov->frame[f].grabstate == FRAME_GRABBING) { + PDEBUG(4, "VIDIOCMCAPTURE: already grabbing"); + return -EBUSY; + } + + if (force_palette && (vm->format != force_palette)) { + PDEBUG(2, "palette rejected (%s)", + symbolic(v4l1_plist, vm->format)); + return -EINVAL; + } + + if ((ov->frame[f].width != vm->width) || + (ov->frame[f].height != vm->height) || + (ov->frame[f].format != vm->format) || + (ov->frame[f].sub_flag != ov->sub_flag) || + (ov->frame[f].depth != depth)) { + PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters"); + + rc = ov51x_wait_frames_inactive(ov); + if (rc) + return rc; + + rc = mode_init_regs(ov, vm->width, vm->height, + vm->format, ov->sub_flag); +#if 0 + if (rc < 0) { + PDEBUG(1, "Got error while initializing regs "); + return ret; + } +#endif + ov->frame[f].width = vm->width; + ov->frame[f].height = vm->height; + ov->frame[f].format = vm->format; + ov->frame[f].sub_flag = ov->sub_flag; + ov->frame[f].depth = depth; + } + + /* Mark it as ready */ + ov->frame[f].grabstate = FRAME_READY; + + PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", f); + + return ov51x_new_frame(ov, f); + } + case VIDIOCSYNC: + { + unsigned int fnum = *((unsigned int *) arg); + struct ov511_frame *frame; + int rc; + + if (fnum >= OV511_NUMFRAMES) { + err("VIDIOCSYNC: invalid frame (%d)", fnum); + return -EINVAL; + } + + frame = &ov->frame[fnum]; + + PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum, + frame->grabstate); + + switch (frame->grabstate) { + case FRAME_UNUSED: + return -EINVAL; + case FRAME_READY: + case FRAME_GRABBING: + case FRAME_ERROR: +redo: + if (!ov->dev) + return -EIO; + + rc = wait_event_interruptible(frame->wq, + (frame->grabstate == FRAME_DONE) + || (frame->grabstate == FRAME_ERROR)); + + if (rc) + return rc; + + if (frame->grabstate == FRAME_ERROR) { + if ((rc = ov51x_new_frame(ov, fnum)) < 0) + return rc; + goto redo; + } + /* Fall through */ + case FRAME_DONE: + if (ov->snap_enabled && !frame->snapshot) { + if ((rc = ov51x_new_frame(ov, fnum)) < 0) + return rc; + goto redo; + } + + frame->grabstate = FRAME_UNUSED; + + /* Reset the hardware snapshot button */ + /* FIXME - Is this the best place for this? */ + if ((ov->snap_enabled) && (frame->snapshot)) { + frame->snapshot = 0; + ov51x_clear_snapshot(ov); + } + + /* Decompression, format conversion, etc... */ + ov51x_postprocess(ov, frame); + + break; + } /* end switch */ + + return 0; + } + case VIDIOCGFBUF: + { + struct video_buffer *vb = arg; + + PDEBUG(4, "VIDIOCGFBUF"); + + memset(vb, 0, sizeof(struct video_buffer)); + + return 0; + } + case VIDIOCGUNIT: + { + struct video_unit *vu = arg; + + PDEBUG(4, "VIDIOCGUNIT"); + + memset(vu, 0, sizeof(struct video_unit)); + + vu->video = ov->vdev->minor; + vu->vbi = VIDEO_NO_UNIT; + vu->radio = VIDEO_NO_UNIT; + vu->audio = VIDEO_NO_UNIT; + vu->teletext = VIDEO_NO_UNIT; + + return 0; + } + case OV511IOC_WI2C: + { + struct ov511_i2c_struct *w = arg; + + return i2c_w_slave(ov, w->slave, w->reg, w->value, w->mask); + } + case OV511IOC_RI2C: + { + struct ov511_i2c_struct *r = arg; + int rc; + + rc = i2c_r_slave(ov, r->slave, r->reg); + if (rc < 0) + return rc; + + r->value = rc; + return 0; + } + default: + PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd); + return -ENOIOCTLCMD; + } /* end switch */ + + return 0; +} + +static int +ov51x_v4l1_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct video_device *vdev = file->private_data; + struct usb_ov511 *ov = video_get_drvdata(vdev); + int rc; + + if (down_interruptible(&ov->lock)) + return -EINTR; + + rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal); + + up(&ov->lock); + return rc; +} + +static ssize_t +ov51x_v4l1_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos) +{ + struct video_device *vdev = file->private_data; + int noblock = file->f_flags&O_NONBLOCK; + unsigned long count = cnt; + struct usb_ov511 *ov = video_get_drvdata(vdev); + int i, rc = 0, frmx = -1; + struct ov511_frame *frame; + + if (down_interruptible(&ov->lock)) + return -EINTR; + + PDEBUG(4, "%ld bytes, noblock=%d", count, noblock); + + if (!vdev || !buf) { + rc = -EFAULT; + goto error; + } + + if (!ov->dev) { + rc = -EIO; + goto error; + } + +// FIXME: Only supports two frames + /* See if a frame is completed, then use it. */ + if (ov->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ + frmx = 0; + else if (ov->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */ + frmx = 1; + + /* If nonblocking we return immediately */ + if (noblock && (frmx == -1)) { + rc = -EAGAIN; + goto error; + } + + /* If no FRAME_DONE, look for a FRAME_GRABBING state. */ + /* See if a frame is in process (grabbing), then use it. */ + if (frmx == -1) { + if (ov->frame[0].grabstate == FRAME_GRABBING) + frmx = 0; + else if (ov->frame[1].grabstate == FRAME_GRABBING) + frmx = 1; + } + + /* If no frame is active, start one. */ + if (frmx == -1) { + if ((rc = ov51x_new_frame(ov, frmx = 0))) { + err("read: ov51x_new_frame error"); + goto error; + } + } + + frame = &ov->frame[frmx]; + +restart: + if (!ov->dev) { + rc = -EIO; + goto error; + } + + /* Wait while we're grabbing the image */ + PDEBUG(4, "Waiting image grabbing"); + rc = wait_event_interruptible(frame->wq, + (frame->grabstate == FRAME_DONE) + || (frame->grabstate == FRAME_ERROR)); + + if (rc) + goto error; + + PDEBUG(4, "Got image, frame->grabstate = %d", frame->grabstate); + PDEBUG(4, "bytes_recvd = %d", frame->bytes_recvd); + + if (frame->grabstate == FRAME_ERROR) { + frame->bytes_read = 0; + err("** ick! ** Errored frame %d", ov->curframe); + if (ov51x_new_frame(ov, frmx)) { + err("read: ov51x_new_frame error"); + goto error; + } + goto restart; + } + + + /* Repeat until we get a snapshot frame */ + if (ov->snap_enabled) + PDEBUG(4, "Waiting snapshot frame"); + if (ov->snap_enabled && !frame->snapshot) { + frame->bytes_read = 0; + if ((rc = ov51x_new_frame(ov, frmx))) { + err("read: ov51x_new_frame error"); + goto error; + } + goto restart; + } + + /* Clear the snapshot */ + if (ov->snap_enabled && frame->snapshot) { + frame->snapshot = 0; + ov51x_clear_snapshot(ov); + } + + /* Decompression, format conversion, etc... */ + ov51x_postprocess(ov, frame); + + PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx, + frame->bytes_read, + get_frame_length(frame)); + + /* copy bytes to user space; we allow for partials reads */ +// if ((count + frame->bytes_read) +// > get_frame_length((struct ov511_frame *)frame)) +// count = frame->scanlength - frame->bytes_read; + + /* FIXME - count hardwired to be one frame... */ + count = get_frame_length(frame); + + PDEBUG(4, "Copy to user space: %ld bytes", count); + if ((i = copy_to_user(buf, frame->data + frame->bytes_read, count))) { + PDEBUG(4, "Copy failed! %d bytes not copied", i); + rc = -EFAULT; + goto error; + } + + frame->bytes_read += count; + PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld", + count, frame->bytes_read); + + /* If all data have been read... */ + if (frame->bytes_read + >= get_frame_length(frame)) { + frame->bytes_read = 0; + +// FIXME: Only supports two frames + /* Mark it as available to be used again. */ + ov->frame[frmx].grabstate = FRAME_UNUSED; + if ((rc = ov51x_new_frame(ov, !frmx))) { + err("ov51x_new_frame returned error"); + goto error; + } + } + + PDEBUG(4, "read finished, returning %ld (sweet)", count); + + up(&ov->lock); + return count; + +error: + up(&ov->lock); + return rc; +} + +static int +ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct video_device *vdev = file->private_data; + unsigned long start = vma->vm_start; + unsigned long size = vma->vm_end - vma->vm_start; + struct usb_ov511 *ov = video_get_drvdata(vdev); + unsigned long page, pos; + + if (ov->dev == NULL) + return -EIO; + + PDEBUG(4, "mmap: %ld (%lX) bytes", size, size); + + if (size > (((OV511_NUMFRAMES + * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight) + + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))) + return -EINVAL; + + if (down_interruptible(&ov->lock)) + return -EINTR; + + pos = (unsigned long)ov->fbuf; + while (size > 0) { + page = vmalloc_to_pfn((void *)pos); + if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { + up(&ov->lock); + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + up(&ov->lock); + return 0; +} + +static struct file_operations ov511_fops = { + .owner = THIS_MODULE, + .open = ov51x_v4l1_open, + .release = ov51x_v4l1_close, + .read = ov51x_v4l1_read, + .mmap = ov51x_v4l1_mmap, + .ioctl = ov51x_v4l1_ioctl, + .llseek = no_llseek, +}; + +static struct video_device vdev_template = { + .name = "OV511 USB Camera", + .fops = &ov511_fops, + .release = video_device_release, + .minor = -1, +}; + +/**************************************************************************** + * + * OV511 and sensor configuration + * + ***************************************************************************/ + +/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses + * the same register settings as the OV7610, since they are very similar. + */ +static int +ov7xx0_configure(struct usb_ov511 *ov) +{ + int i, success; + int rc; + + /* Lawrence Glaister reports: + * + * Register 0x0f in the 7610 has the following effects: + * + * 0x85 (AEC method 1): Best overall, good contrast range + * 0x45 (AEC method 2): Very overexposed + * 0xa5 (spec sheet default): Ok, but the black level is + * shifted resulting in loss of contrast + * 0x05 (old driver setting): very overexposed, too much + * contrast + */ + static struct ov511_regvals aRegvalsNorm7610[] = { + { OV511_I2C_BUS, 0x10, 0xff }, + { OV511_I2C_BUS, 0x16, 0x06 }, + { OV511_I2C_BUS, 0x28, 0x24 }, + { OV511_I2C_BUS, 0x2b, 0xac }, + { OV511_I2C_BUS, 0x12, 0x00 }, + { OV511_I2C_BUS, 0x38, 0x81 }, + { OV511_I2C_BUS, 0x28, 0x24 }, /* 0c */ + { OV511_I2C_BUS, 0x0f, 0x85 }, /* lg's setting */ + { OV511_I2C_BUS, 0x15, 0x01 }, + { OV511_I2C_BUS, 0x20, 0x1c }, + { OV511_I2C_BUS, 0x23, 0x2a }, + { OV511_I2C_BUS, 0x24, 0x10 }, + { OV511_I2C_BUS, 0x25, 0x8a }, + { OV511_I2C_BUS, 0x26, 0xa2 }, + { OV511_I2C_BUS, 0x27, 0xc2 }, + { OV511_I2C_BUS, 0x2a, 0x04 }, + { OV511_I2C_BUS, 0x2c, 0xfe }, + { OV511_I2C_BUS, 0x2d, 0x93 }, + { OV511_I2C_BUS, 0x30, 0x71 }, + { OV511_I2C_BUS, 0x31, 0x60 }, + { OV511_I2C_BUS, 0x32, 0x26 }, + { OV511_I2C_BUS, 0x33, 0x20 }, + { OV511_I2C_BUS, 0x34, 0x48 }, + { OV511_I2C_BUS, 0x12, 0x24 }, + { OV511_I2C_BUS, 0x11, 0x01 }, + { OV511_I2C_BUS, 0x0c, 0x24 }, + { OV511_I2C_BUS, 0x0d, 0x24 }, + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + static struct ov511_regvals aRegvalsNorm7620[] = { + { OV511_I2C_BUS, 0x00, 0x00 }, + { OV511_I2C_BUS, 0x01, 0x80 }, + { OV511_I2C_BUS, 0x02, 0x80 }, + { OV511_I2C_BUS, 0x03, 0xc0 }, + { OV511_I2C_BUS, 0x06, 0x60 }, + { OV511_I2C_BUS, 0x07, 0x00 }, + { OV511_I2C_BUS, 0x0c, 0x24 }, + { OV511_I2C_BUS, 0x0c, 0x24 }, + { OV511_I2C_BUS, 0x0d, 0x24 }, + { OV511_I2C_BUS, 0x11, 0x01 }, + { OV511_I2C_BUS, 0x12, 0x24 }, + { OV511_I2C_BUS, 0x13, 0x01 }, + { OV511_I2C_BUS, 0x14, 0x84 }, + { OV511_I2C_BUS, 0x15, 0x01 }, + { OV511_I2C_BUS, 0x16, 0x03 }, + { OV511_I2C_BUS, 0x17, 0x2f }, + { OV511_I2C_BUS, 0x18, 0xcf }, + { OV511_I2C_BUS, 0x19, 0x06 }, + { OV511_I2C_BUS, 0x1a, 0xf5 }, + { OV511_I2C_BUS, 0x1b, 0x00 }, + { OV511_I2C_BUS, 0x20, 0x18 }, + { OV511_I2C_BUS, 0x21, 0x80 }, + { OV511_I2C_BUS, 0x22, 0x80 }, + { OV511_I2C_BUS, 0x23, 0x00 }, + { OV511_I2C_BUS, 0x26, 0xa2 }, + { OV511_I2C_BUS, 0x27, 0xea }, + { OV511_I2C_BUS, 0x28, 0x20 }, + { OV511_I2C_BUS, 0x29, 0x00 }, + { OV511_I2C_BUS, 0x2a, 0x10 }, + { OV511_I2C_BUS, 0x2b, 0x00 }, + { OV511_I2C_BUS, 0x2c, 0x88 }, + { OV511_I2C_BUS, 0x2d, 0x91 }, + { OV511_I2C_BUS, 0x2e, 0x80 }, + { OV511_I2C_BUS, 0x2f, 0x44 }, + { OV511_I2C_BUS, 0x60, 0x27 }, + { OV511_I2C_BUS, 0x61, 0x02 }, + { OV511_I2C_BUS, 0x62, 0x5f }, + { OV511_I2C_BUS, 0x63, 0xd5 }, + { OV511_I2C_BUS, 0x64, 0x57 }, + { OV511_I2C_BUS, 0x65, 0x83 }, + { OV511_I2C_BUS, 0x66, 0x55 }, + { OV511_I2C_BUS, 0x67, 0x92 }, + { OV511_I2C_BUS, 0x68, 0xcf }, + { OV511_I2C_BUS, 0x69, 0x76 }, + { OV511_I2C_BUS, 0x6a, 0x22 }, + { OV511_I2C_BUS, 0x6b, 0x00 }, + { OV511_I2C_BUS, 0x6c, 0x02 }, + { OV511_I2C_BUS, 0x6d, 0x44 }, + { OV511_I2C_BUS, 0x6e, 0x80 }, + { OV511_I2C_BUS, 0x6f, 0x1d }, + { OV511_I2C_BUS, 0x70, 0x8b }, + { OV511_I2C_BUS, 0x71, 0x00 }, + { OV511_I2C_BUS, 0x72, 0x14 }, + { OV511_I2C_BUS, 0x73, 0x54 }, + { OV511_I2C_BUS, 0x74, 0x00 }, + { OV511_I2C_BUS, 0x75, 0x8e }, + { OV511_I2C_BUS, 0x76, 0x00 }, + { OV511_I2C_BUS, 0x77, 0xff }, + { OV511_I2C_BUS, 0x78, 0x80 }, + { OV511_I2C_BUS, 0x79, 0x80 }, + { OV511_I2C_BUS, 0x7a, 0x80 }, + { OV511_I2C_BUS, 0x7b, 0xe2 }, + { OV511_I2C_BUS, 0x7c, 0x00 }, + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + PDEBUG(4, "starting configuration"); + + /* This looks redundant, but is necessary for WebCam 3 */ + ov->primary_i2c_slave = OV7xx0_SID; + if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) + return -1; + + if (init_ov_sensor(ov) >= 0) { + PDEBUG(1, "OV7xx0 sensor initalized (method 1)"); + } else { + /* Reset the 76xx */ + if (i2c_w(ov, 0x12, 0x80) < 0) + return -1; + + /* Wait for it to initialize */ + msleep(150); + + i = 0; + success = 0; + while (i <= i2c_detect_tries) { + if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && + (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) { + success = 1; + break; + } else { + i++; + } + } + +// Was (i == i2c_detect_tries) previously. This obviously used to always report +// success. Whether anyone actually depended on that bug is unknown + if ((i >= i2c_detect_tries) && (success == 0)) { + err("Failed to read sensor ID. You might not have an"); + err("OV7610/20, or it may be not responding. Report"); + err("this to " EMAIL); + err("This is only a warning. You can attempt to use"); + err("your camera anyway"); +// Only issue a warning for now +// return -1; + } else { + PDEBUG(1, "OV7xx0 initialized (method 2, %dx)", i+1); + } + } + + /* Detect sensor (sub)type */ + rc = i2c_r(ov, OV7610_REG_COM_I); + + if (rc < 0) { + err("Error detecting sensor type"); + return -1; + } else if ((rc & 3) == 3) { + info("Sensor is an OV7610"); + ov->sensor = SEN_OV7610; + } else if ((rc & 3) == 1) { + /* I don't know what's different about the 76BE yet. */ + if (i2c_r(ov, 0x15) & 1) + info("Sensor is an OV7620AE"); + else + info("Sensor is an OV76BE"); + + /* OV511+ will return all zero isoc data unless we + * configure the sensor as a 7620. Someone needs to + * find the exact reg. setting that causes this. */ + if (ov->bridge == BRG_OV511PLUS) { + info("Enabling 511+/7620AE workaround"); + ov->sensor = SEN_OV7620; + } else { + ov->sensor = SEN_OV76BE; + } + } else if ((rc & 3) == 0) { + info("Sensor is an OV7620"); + ov->sensor = SEN_OV7620; + } else { + err("Unknown image sensor version: %d", rc & 3); + return -1; + } + + if (ov->sensor == SEN_OV7620) { + PDEBUG(4, "Writing 7620 registers"); + if (write_regvals(ov, aRegvalsNorm7620)) + return -1; + } else { + PDEBUG(4, "Writing 7610 registers"); + if (write_regvals(ov, aRegvalsNorm7610)) + return -1; + } + + /* Set sensor-specific vars */ + ov->maxwidth = 640; + ov->maxheight = 480; + ov->minwidth = 64; + ov->minheight = 48; + + // FIXME: These do not match the actual settings yet + ov->brightness = 0x80 << 8; + ov->contrast = 0x80 << 8; + ov->colour = 0x80 << 8; + ov->hue = 0x80 << 8; + + return 0; +} + +/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */ +static int +ov6xx0_configure(struct usb_ov511 *ov) +{ + int rc; + + static struct ov511_regvals aRegvalsNorm6x20[] = { + { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */ + { OV511_I2C_BUS, 0x11, 0x01 }, + { OV511_I2C_BUS, 0x03, 0x60 }, + { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */ + { OV511_I2C_BUS, 0x07, 0xa8 }, + /* The ratio of 0x0c and 0x0d controls the white point */ + { OV511_I2C_BUS, 0x0c, 0x24 }, + { OV511_I2C_BUS, 0x0d, 0x24 }, + { OV511_I2C_BUS, 0x0f, 0x15 }, /* COMS */ + { OV511_I2C_BUS, 0x10, 0x75 }, /* AEC Exposure time */ + { OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */ + { OV511_I2C_BUS, 0x14, 0x04 }, + /* 0x16: 0x06 helps frame stability with moving objects */ + { OV511_I2C_BUS, 0x16, 0x06 }, +// { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */ + { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */ + /* 0x28: 0x05 Selects RGB format if RGB on */ + { OV511_I2C_BUS, 0x28, 0x05 }, + { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */ +// { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */ + { OV511_I2C_BUS, 0x2d, 0x99 }, + { OV511_I2C_BUS, 0x33, 0xa0 }, /* Color Processing Parameter */ + { OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */ + { OV511_I2C_BUS, 0x38, 0x8b }, + { OV511_I2C_BUS, 0x39, 0x40 }, + + { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */ + { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */ + { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */ + + { OV511_I2C_BUS, 0x3d, 0x80 }, + /* These next two registers (0x4a, 0x4b) are undocumented. They + * control the color balance */ + { OV511_I2C_BUS, 0x4a, 0x80 }, + { OV511_I2C_BUS, 0x4b, 0x80 }, + { OV511_I2C_BUS, 0x4d, 0xd2 }, /* This reduces noise a bit */ + { OV511_I2C_BUS, 0x4e, 0xc1 }, + { OV511_I2C_BUS, 0x4f, 0x04 }, +// Do 50-53 have any effect? +// Toggle 0x12[2] off and on here? + { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */ + }; + + static struct ov511_regvals aRegvalsNorm6x30[] = { + /*OK*/ { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */ + { OV511_I2C_BUS, 0x11, 0x00 }, + /*OK*/ { OV511_I2C_BUS, 0x03, 0x60 }, + /*0A?*/ { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */ + { OV511_I2C_BUS, 0x07, 0xa8 }, + /* The ratio of 0x0c and 0x0d controls the white point */ + /*OK*/ { OV511_I2C_BUS, 0x0c, 0x24 }, + /*OK*/ { OV511_I2C_BUS, 0x0d, 0x24 }, + /*A*/ { OV511_I2C_BUS, 0x0e, 0x20 }, +// /*04?*/ { OV511_I2C_BUS, 0x14, 0x80 }, + { OV511_I2C_BUS, 0x16, 0x03 }, +// /*OK*/ { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */ + // 21 & 22? The suggested values look wrong. Go with default + /*A*/ { OV511_I2C_BUS, 0x23, 0xc0 }, + /*A*/ { OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default +// /*OK*/ { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */ + + /* 0x28: 0x05 Selects RGB format if RGB on */ +// /*04?*/ { OV511_I2C_BUS, 0x28, 0x05 }, +// /*04?*/ { OV511_I2C_BUS, 0x28, 0x45 }, // DEBUG: Tristate UV bus + + /*OK*/ { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */ +// /*OK*/ { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */ + { OV511_I2C_BUS, 0x2d, 0x99 }, +// /*A*/ { OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620 +// /*d2?*/ { OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */ +// /*8b?*/ { OV511_I2C_BUS, 0x38, 0x83 }, +// /*40?*/ { OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7 +// { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */ +// { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */ +// { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */ + { OV511_I2C_BUS, 0x3d, 0x80 }, +// /*A*/ { OV511_I2C_BUS, 0x3f, 0x0e }, + + /* These next two registers (0x4a, 0x4b) are undocumented. They + * control the color balance */ +// /*OK?*/ { OV511_I2C_BUS, 0x4a, 0x80 }, // Check these +// /*OK?*/ { OV511_I2C_BUS, 0x4b, 0x80 }, + { OV511_I2C_BUS, 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */ + /*c1?*/ { OV511_I2C_BUS, 0x4e, 0x40 }, + + /* UV average mode, color killer: strongest */ + { OV511_I2C_BUS, 0x4f, 0x07 }, + + { OV511_I2C_BUS, 0x54, 0x23 }, /* Max AGC gain: 18dB */ + { OV511_I2C_BUS, 0x57, 0x81 }, /* (default) */ + { OV511_I2C_BUS, 0x59, 0x01 }, /* AGC dark current comp: +1 */ + { OV511_I2C_BUS, 0x5a, 0x2c }, /* (undocumented) */ + { OV511_I2C_BUS, 0x5b, 0x0f }, /* AWB chrominance levels */ +// { OV511_I2C_BUS, 0x5c, 0x10 }, + { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */ + }; + + PDEBUG(4, "starting sensor configuration"); + + if (init_ov_sensor(ov) < 0) { + err("Failed to read sensor ID. You might not have an OV6xx0,"); + err("or it may be not responding. Report this to " EMAIL); + return -1; + } else { + PDEBUG(1, "OV6xx0 sensor detected"); + } + + /* Detect sensor (sub)type */ + rc = i2c_r(ov, OV7610_REG_COM_I); + + if (rc < 0) { + err("Error detecting sensor type"); + return -1; + } + + if ((rc & 3) == 0) { + ov->sensor = SEN_OV6630; + info("Sensor is an OV6630"); + } else if ((rc & 3) == 1) { + ov->sensor = SEN_OV6620; + info("Sensor is an OV6620"); + } else if ((rc & 3) == 2) { + ov->sensor = SEN_OV6630; + info("Sensor is an OV6630AE"); + } else if ((rc & 3) == 3) { + ov->sensor = SEN_OV6630; + info("Sensor is an OV6630AF"); + } + + /* Set sensor-specific vars */ + ov->maxwidth = 352; + ov->maxheight = 288; + ov->minwidth = 64; + ov->minheight = 48; + + // FIXME: These do not match the actual settings yet + ov->brightness = 0x80 << 8; + ov->contrast = 0x80 << 8; + ov->colour = 0x80 << 8; + ov->hue = 0x80 << 8; + + if (ov->sensor == SEN_OV6620) { + PDEBUG(4, "Writing 6x20 registers"); + if (write_regvals(ov, aRegvalsNorm6x20)) + return -1; + } else { + PDEBUG(4, "Writing 6x30 registers"); + if (write_regvals(ov, aRegvalsNorm6x30)) + return -1; + } + + return 0; +} + +/* This initializes the KS0127 and KS0127B video decoders. */ +static int +ks0127_configure(struct usb_ov511 *ov) +{ + int rc; + +// FIXME: I don't know how to sync or reset it yet +#if 0 + if (ov51x_init_ks_sensor(ov) < 0) { + err("Failed to initialize the KS0127"); + return -1; + } else { + PDEBUG(1, "KS012x(B) sensor detected"); + } +#endif + + /* Detect decoder subtype */ + rc = i2c_r(ov, 0x00); + if (rc < 0) { + err("Error detecting sensor type"); + return -1; + } else if (rc & 0x08) { + rc = i2c_r(ov, 0x3d); + if (rc < 0) { + err("Error detecting sensor type"); + return -1; + } else if ((rc & 0x0f) == 0) { + info("Sensor is a KS0127"); + ov->sensor = SEN_KS0127; + } else if ((rc & 0x0f) == 9) { + info("Sensor is a KS0127B Rev. A"); + ov->sensor = SEN_KS0127B; + } + } else { + err("Error: Sensor is an unsupported KS0122"); + return -1; + } + + /* Set sensor-specific vars */ + ov->maxwidth = 640; + ov->maxheight = 480; + ov->minwidth = 64; + ov->minheight = 48; + + // FIXME: These do not match the actual settings yet + ov->brightness = 0x80 << 8; + ov->contrast = 0x80 << 8; + ov->colour = 0x80 << 8; + ov->hue = 0x80 << 8; + + /* This device is not supported yet. Bail out now... */ + err("This sensor is not supported yet."); + return -1; + + return 0; +} + +/* This initializes the SAA7111A video decoder. */ +static int +saa7111a_configure(struct usb_ov511 *ov) +{ + int rc; + + /* Since there is no register reset command, all registers must be + * written, otherwise gives erratic results */ + static struct ov511_regvals aRegvalsNormSAA7111A[] = { + { OV511_I2C_BUS, 0x06, 0xce }, + { OV511_I2C_BUS, 0x07, 0x00 }, + { OV511_I2C_BUS, 0x10, 0x44 }, /* YUV422, 240/286 lines */ + { OV511_I2C_BUS, 0x0e, 0x01 }, /* NTSC M or PAL BGHI */ + { OV511_I2C_BUS, 0x00, 0x00 }, + { OV511_I2C_BUS, 0x01, 0x00 }, + { OV511_I2C_BUS, 0x03, 0x23 }, + { OV511_I2C_BUS, 0x04, 0x00 }, + { OV511_I2C_BUS, 0x05, 0x00 }, + { OV511_I2C_BUS, 0x08, 0xc8 }, /* Auto field freq */ + { OV511_I2C_BUS, 0x09, 0x01 }, /* Chrom. trap off, APER=0.25 */ + { OV511_I2C_BUS, 0x0a, 0x80 }, /* BRIG=128 */ + { OV511_I2C_BUS, 0x0b, 0x40 }, /* CONT=1.0 */ + { OV511_I2C_BUS, 0x0c, 0x40 }, /* SATN=1.0 */ + { OV511_I2C_BUS, 0x0d, 0x00 }, /* HUE=0 */ + { OV511_I2C_BUS, 0x0f, 0x00 }, + { OV511_I2C_BUS, 0x11, 0x0c }, + { OV511_I2C_BUS, 0x12, 0x00 }, + { OV511_I2C_BUS, 0x13, 0x00 }, + { OV511_I2C_BUS, 0x14, 0x00 }, + { OV511_I2C_BUS, 0x15, 0x00 }, + { OV511_I2C_BUS, 0x16, 0x00 }, + { OV511_I2C_BUS, 0x17, 0x00 }, + { OV511_I2C_BUS, 0x02, 0xc0 }, /* Composite input 0 */ + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + +// FIXME: I don't know how to sync or reset it yet +#if 0 + if (ov51x_init_saa_sensor(ov) < 0) { + err("Failed to initialize the SAA7111A"); + return -1; + } else { + PDEBUG(1, "SAA7111A sensor detected"); + } +#endif + + /* 640x480 not supported with PAL */ + if (ov->pal) { + ov->maxwidth = 320; + ov->maxheight = 240; /* Even field only */ + } else { + ov->maxwidth = 640; + ov->maxheight = 480; /* Even/Odd fields */ + } + + ov->minwidth = 320; + ov->minheight = 240; /* Even field only */ + + ov->has_decoder = 1; + ov->num_inputs = 8; + ov->norm = VIDEO_MODE_AUTO; + ov->stop_during_set = 0; /* Decoder guarantees stable image */ + + /* Decoder doesn't change these values, so we use these instead of + * acutally reading the registers (which doesn't work) */ + ov->brightness = 0x80 << 8; + ov->contrast = 0x40 << 9; + ov->colour = 0x40 << 9; + ov->hue = 32768; + + PDEBUG(4, "Writing SAA7111A registers"); + if (write_regvals(ov, aRegvalsNormSAA7111A)) + return -1; + + /* Detect version of decoder. This must be done after writing the + * initial regs or the decoder will lock up. */ + rc = i2c_r(ov, 0x00); + + if (rc < 0) { + err("Error detecting sensor version"); + return -1; + } else { + info("Sensor is an SAA7111A (version 0x%x)", rc); + ov->sensor = SEN_SAA7111A; + } + + // FIXME: Fix this for OV518(+) + /* Latch to negative edge of clock. Otherwise, we get incorrect + * colors and jitter in the digital signal. */ + if (ov->bclass == BCL_OV511) + reg_w(ov, 0x11, 0x00); + else + warn("SAA7111A not yet supported with OV518/OV518+"); + + return 0; +} + +/* This initializes the OV511/OV511+ and the sensor */ +static int +ov511_configure(struct usb_ov511 *ov) +{ + static struct ov511_regvals aRegvalsInit511[] = { + { OV511_REG_BUS, R51x_SYS_RESET, 0x7f }, + { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x7f }, + { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x3f }, + { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x3d }, + { OV511_DONE_BUS, 0x0, 0x00}, + }; + + static struct ov511_regvals aRegvalsNorm511[] = { + { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0x01 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, + { OV511_REG_BUS, R511_FIFO_OPTS, 0x1f }, + { OV511_REG_BUS, R511_COMP_EN, 0x00 }, + { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + static struct ov511_regvals aRegvalsNorm511Plus[] = { + { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0xff }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, + { OV511_REG_BUS, R511_FIFO_OPTS, 0xff }, + { OV511_REG_BUS, R511_COMP_EN, 0x00 }, + { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + PDEBUG(4, ""); + + ov->customid = reg_r(ov, R511_SYS_CUST_ID); + if (ov->customid < 0) { + err("Unable to read camera bridge registers"); + goto error; + } + + PDEBUG (1, "CustomID = %d", ov->customid); + ov->desc = symbolic(camlist, ov->customid); + info("model: %s", ov->desc); + + if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) { + err("Camera type (%d) not recognized", ov->customid); + err("Please notify " EMAIL " of the name,"); + err("manufacturer, model, and this number of your camera."); + err("Also include the output of the detection process."); + } + + if (ov->customid == 70) /* USB Life TV (PAL/SECAM) */ + ov->pal = 1; + + if (write_regvals(ov, aRegvalsInit511)) + goto error; + + if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 0); + + /* The OV511+ has undocumented bits in the flow control register. + * Setting it to 0xff fixes the corruption with moving objects. */ + if (ov->bridge == BRG_OV511) { + if (write_regvals(ov, aRegvalsNorm511)) + goto error; + } else if (ov->bridge == BRG_OV511PLUS) { + if (write_regvals(ov, aRegvalsNorm511Plus)) + goto error; + } else { + err("Invalid bridge"); + } + + if (ov511_init_compression(ov)) + goto error; + + ov->packet_numbering = 1; + ov511_set_packet_size(ov, 0); + + ov->snap_enabled = snapshot; + + /* Test for 7xx0 */ + PDEBUG(3, "Testing for 0V7xx0"); + ov->primary_i2c_slave = OV7xx0_SID; + if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) + goto error; + + if (i2c_w(ov, 0x12, 0x80) < 0) { + /* Test for 6xx0 */ + PDEBUG(3, "Testing for 0V6xx0"); + ov->primary_i2c_slave = OV6xx0_SID; + if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) + goto error; + + if (i2c_w(ov, 0x12, 0x80) < 0) { + /* Test for 8xx0 */ + PDEBUG(3, "Testing for 0V8xx0"); + ov->primary_i2c_slave = OV8xx0_SID; + if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0) + goto error; + + if (i2c_w(ov, 0x12, 0x80) < 0) { + /* Test for SAA7111A */ + PDEBUG(3, "Testing for SAA7111A"); + ov->primary_i2c_slave = SAA7111A_SID; + if (ov51x_set_slave_ids(ov, SAA7111A_SID) < 0) + goto error; + + if (i2c_w(ov, 0x0d, 0x00) < 0) { + /* Test for KS0127 */ + PDEBUG(3, "Testing for KS0127"); + ov->primary_i2c_slave = KS0127_SID; + if (ov51x_set_slave_ids(ov, KS0127_SID) < 0) + goto error; + + if (i2c_w(ov, 0x10, 0x00) < 0) { + err("Can't determine sensor slave IDs"); + goto error; + } else { + if (ks0127_configure(ov) < 0) { + err("Failed to configure KS0127"); + goto error; + } + } + } else { + if (saa7111a_configure(ov) < 0) { + err("Failed to configure SAA7111A"); + goto error; + } + } + } else { + err("Detected unsupported OV8xx0 sensor"); + goto error; + } + } else { + if (ov6xx0_configure(ov) < 0) { + err("Failed to configure OV6xx0"); + goto error; + } + } + } else { + if (ov7xx0_configure(ov) < 0) { + err("Failed to configure OV7xx0"); + goto error; + } + } + + return 0; + +error: + err("OV511 Config failed"); + + return -EBUSY; +} + +/* This initializes the OV518/OV518+ and the sensor */ +static int +ov518_configure(struct usb_ov511 *ov) +{ + /* For 518 and 518+ */ + static struct ov511_regvals aRegvalsInit518[] = { + { OV511_REG_BUS, R51x_SYS_RESET, 0x40 }, + { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x3e }, + { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x00 }, + { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, + { OV511_REG_BUS, 0x46, 0x00 }, + { OV511_REG_BUS, 0x5d, 0x03 }, + { OV511_DONE_BUS, 0x0, 0x00}, + }; + + static struct ov511_regvals aRegvalsNorm518[] = { + { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */ + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */ + { OV511_REG_BUS, 0x31, 0x0f }, + { OV511_REG_BUS, 0x5d, 0x03 }, + { OV511_REG_BUS, 0x24, 0x9f }, + { OV511_REG_BUS, 0x25, 0x90 }, + { OV511_REG_BUS, 0x20, 0x00 }, + { OV511_REG_BUS, 0x51, 0x04 }, + { OV511_REG_BUS, 0x71, 0x19 }, + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + static struct ov511_regvals aRegvalsNorm518Plus[] = { + { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */ + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */ + { OV511_REG_BUS, 0x31, 0x0f }, + { OV511_REG_BUS, 0x5d, 0x03 }, + { OV511_REG_BUS, 0x24, 0x9f }, + { OV511_REG_BUS, 0x25, 0x90 }, + { OV511_REG_BUS, 0x20, 0x60 }, + { OV511_REG_BUS, 0x51, 0x02 }, + { OV511_REG_BUS, 0x71, 0x19 }, + { OV511_REG_BUS, 0x40, 0xff }, + { OV511_REG_BUS, 0x41, 0x42 }, + { OV511_REG_BUS, 0x46, 0x00 }, + { OV511_REG_BUS, 0x33, 0x04 }, + { OV511_REG_BUS, 0x21, 0x19 }, + { OV511_REG_BUS, 0x3f, 0x10 }, + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + PDEBUG(4, ""); + + /* First 5 bits of custom ID reg are a revision ID on OV518 */ + info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID)); + + /* Give it the default description */ + ov->desc = symbolic(camlist, 0); + + if (write_regvals(ov, aRegvalsInit518)) + goto error; + + /* Set LED GPIO pin to output mode */ + if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0) + goto error; + + /* LED is off by default with OV518; have to explicitly turn it on */ + if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 0); + else + ov51x_led_control(ov, 1); + + /* Don't require compression if dumppix is enabled; otherwise it's + * required. OV518 has no uncompressed mode, to save RAM. */ + if (!dumppix && !ov->compress) { + ov->compress = 1; + warn("Compression required with OV518...enabling"); + } + + if (ov->bridge == BRG_OV518) { + if (write_regvals(ov, aRegvalsNorm518)) + goto error; + } else if (ov->bridge == BRG_OV518PLUS) { + if (write_regvals(ov, aRegvalsNorm518Plus)) + goto error; + } else { + err("Invalid bridge"); + } + + if (reg_w(ov, 0x2f, 0x80) < 0) + goto error; + + if (ov518_init_compression(ov)) + goto error; + + if (ov->bridge == BRG_OV518) + { + struct usb_interface *ifp; + struct usb_host_interface *alt; + __u16 mxps = 0; + + ifp = usb_ifnum_to_if(ov->dev, 0); + if (ifp) { + alt = usb_altnum_to_altsetting(ifp, 7); + if (alt) + mxps = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + } + + /* Some OV518s have packet numbering by default, some don't */ + if (mxps == 897) + ov->packet_numbering = 1; + else + ov->packet_numbering = 0; + } else { + /* OV518+ has packet numbering turned on by default */ + ov->packet_numbering = 1; + } + + ov518_set_packet_size(ov, 0); + + ov->snap_enabled = snapshot; + + /* Test for 76xx */ + ov->primary_i2c_slave = OV7xx0_SID; + if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) + goto error; + + /* The OV518 must be more aggressive about sensor detection since + * I2C write will never fail if the sensor is not present. We have + * to try to initialize the sensor to detect its presence */ + + if (init_ov_sensor(ov) < 0) { + /* Test for 6xx0 */ + ov->primary_i2c_slave = OV6xx0_SID; + if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) + goto error; + + if (init_ov_sensor(ov) < 0) { + /* Test for 8xx0 */ + ov->primary_i2c_slave = OV8xx0_SID; + if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0) + goto error; + + if (init_ov_sensor(ov) < 0) { + err("Can't determine sensor slave IDs"); + goto error; + } else { + err("Detected unsupported OV8xx0 sensor"); + goto error; + } + } else { + if (ov6xx0_configure(ov) < 0) { + err("Failed to configure OV6xx0"); + goto error; + } + } + } else { + if (ov7xx0_configure(ov) < 0) { + err("Failed to configure OV7xx0"); + goto error; + } + } + + ov->maxwidth = 352; + ov->maxheight = 288; + + // The OV518 cannot go as low as the sensor can + ov->minwidth = 160; + ov->minheight = 120; + + return 0; + +error: + err("OV518 Config failed"); + + return -EBUSY; +} + +/**************************************************************************** + * sysfs + ***************************************************************************/ + +static inline struct usb_ov511 *cd_to_ov(struct device *cd) +{ + struct video_device *vdev = to_video_device(cd); + return video_get_drvdata(vdev); +} + +static ssize_t show_custom_id(struct device *cd, struct device_attribute *attr, char *buf) +{ + struct usb_ov511 *ov = cd_to_ov(cd); + return sprintf(buf, "%d\n", ov->customid); +} +static DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL); + +static ssize_t show_model(struct device *cd, struct device_attribute *attr, char *buf) +{ + struct usb_ov511 *ov = cd_to_ov(cd); + return sprintf(buf, "%s\n", ov->desc); +} +static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); + +static ssize_t show_bridge(struct device *cd, struct device_attribute *attr, char *buf) +{ + struct usb_ov511 *ov = cd_to_ov(cd); + return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge)); +} +static DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL); + +static ssize_t show_sensor(struct device *cd, struct device_attribute *attr, char *buf) +{ + struct usb_ov511 *ov = cd_to_ov(cd); + return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor)); +} +static DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL); + +static ssize_t show_brightness(struct device *cd, struct device_attribute *attr, char *buf) +{ + struct usb_ov511 *ov = cd_to_ov(cd); + unsigned short x; + + if (!ov->dev) + return -ENODEV; + sensor_get_brightness(ov, &x); + return sprintf(buf, "%d\n", x >> 8); +} +static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); + +static ssize_t show_saturation(struct device *cd, struct device_attribute *attr, char *buf) +{ + struct usb_ov511 *ov = cd_to_ov(cd); + unsigned short x; + + if (!ov->dev) + return -ENODEV; + sensor_get_saturation(ov, &x); + return sprintf(buf, "%d\n", x >> 8); +} +static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); + +static ssize_t show_contrast(struct device *cd, struct device_attribute *attr, char *buf) +{ + struct usb_ov511 *ov = cd_to_ov(cd); + unsigned short x; + + if (!ov->dev) + return -ENODEV; + sensor_get_contrast(ov, &x); + return sprintf(buf, "%d\n", x >> 8); +} +static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); + +static ssize_t show_hue(struct device *cd, struct device_attribute *attr, char *buf) +{ + struct usb_ov511 *ov = cd_to_ov(cd); + unsigned short x; + + if (!ov->dev) + return -ENODEV; + sensor_get_hue(ov, &x); + return sprintf(buf, "%d\n", x >> 8); +} +static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); + +static ssize_t show_exposure(struct device *cd, struct device_attribute *attr, char *buf) +{ + struct usb_ov511 *ov = cd_to_ov(cd); + unsigned char exp = 0; + + if (!ov->dev) + return -ENODEV; + sensor_get_exposure(ov, &exp); + return sprintf(buf, "%d\n", exp >> 8); +} +static DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL); + +static void ov_create_sysfs(struct device *dev) +{ + device_create_file(dev, &dev_attr_custom_id); + device_create_file(dev, &dev_attr_model); + device_create_file(dev, &dev_attr_bridge); + device_create_file(dev, &dev_attr_sensor); + device_create_file(dev, &dev_attr_brightness); + device_create_file(dev, &dev_attr_saturation); + device_create_file(dev, &dev_attr_contrast); + device_create_file(dev, &dev_attr_hue); + device_create_file(dev, &dev_attr_exposure); +} + +/**************************************************************************** + * USB routines + ***************************************************************************/ + +static int +ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct usb_interface_descriptor *idesc; + struct usb_ov511 *ov; + int i; + + PDEBUG(1, "probing for device..."); + + /* We don't handle multi-config cameras */ + if (dev->descriptor.bNumConfigurations != 1) + return -ENODEV; + + idesc = &intf->cur_altsetting->desc; + + if (idesc->bInterfaceClass != 0xFF) + return -ENODEV; + if (idesc->bInterfaceSubClass != 0x00) + return -ENODEV; + + if ((ov = kmalloc(sizeof(*ov), GFP_KERNEL)) == NULL) { + err("couldn't kmalloc ov struct"); + goto error_out; + } + + memset(ov, 0, sizeof(*ov)); + + ov->dev = dev; + ov->iface = idesc->bInterfaceNumber; + ov->led_policy = led; + ov->compress = compress; + ov->lightfreq = lightfreq; + ov->num_inputs = 1; /* Video decoder init functs. change this */ + ov->stop_during_set = !fastset; + ov->backlight = backlight; + ov->mirror = mirror; + ov->auto_brt = autobright; + ov->auto_gain = autogain; + ov->auto_exp = autoexp; + + switch (le16_to_cpu(dev->descriptor.idProduct)) { + case PROD_OV511: + ov->bridge = BRG_OV511; + ov->bclass = BCL_OV511; + break; + case PROD_OV511PLUS: + ov->bridge = BRG_OV511PLUS; + ov->bclass = BCL_OV511; + break; + case PROD_OV518: + ov->bridge = BRG_OV518; + ov->bclass = BCL_OV518; + break; + case PROD_OV518PLUS: + ov->bridge = BRG_OV518PLUS; + ov->bclass = BCL_OV518; + break; + case PROD_ME2CAM: + if (le16_to_cpu(dev->descriptor.idVendor) != VEND_MATTEL) + goto error; + ov->bridge = BRG_OV511PLUS; + ov->bclass = BCL_OV511; + break; + default: + err("Unknown product ID 0x%04x", le16_to_cpu(dev->descriptor.idProduct)); + goto error; + } + + info("USB %s video device found", symbolic(brglist, ov->bridge)); + + init_waitqueue_head(&ov->wq); + + init_MUTEX(&ov->lock); /* to 1 == available */ + init_MUTEX(&ov->buf_lock); + init_MUTEX(&ov->param_lock); + init_MUTEX(&ov->i2c_lock); + init_MUTEX(&ov->cbuf_lock); + + ov->buf_state = BUF_NOT_ALLOCATED; + + if (usb_make_path(dev, ov->usb_path, OV511_USB_PATH_LEN) < 0) { + err("usb_make_path error"); + goto error; + } + + /* Allocate control transfer buffer. */ + /* Must be kmalloc()'ed, for DMA compatibility */ + ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL); + if (!ov->cbuf) + goto error; + + if (ov->bclass == BCL_OV518) { + if (ov518_configure(ov) < 0) + goto error; + } else { + if (ov511_configure(ov) < 0) + goto error; + } + + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov->frame[i].framenum = i; + init_waitqueue_head(&ov->frame[i].wq); + } + + for (i = 0; i < OV511_NUMSBUF; i++) { + ov->sbuf[i].ov = ov; + spin_lock_init(&ov->sbuf[i].lock); + ov->sbuf[i].n = i; + } + + /* Unnecessary? (This is done on open(). Need to make sure variables + * are properly initialized without this before removing it, though). */ + if (ov51x_set_default_params(ov) < 0) + goto error; + +#ifdef OV511_DEBUG + if (dump_bridge) { + if (ov->bclass == BCL_OV511) + ov511_dump_regs(ov); + else + ov518_dump_regs(ov); + } +#endif + + ov->vdev = video_device_alloc(); + if (!ov->vdev) + goto error; + + memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev)); +// ov->vdev->dev = &dev->dev; + video_set_drvdata(ov->vdev, ov); + + for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) { + /* Minor 0 cannot be specified; assume user wants autodetect */ + if (unit_video[i] == 0) + break; + + if (video_register_device(ov->vdev, VFL_TYPE_GRABBER, + unit_video[i]) >= 0) { + break; + } + } + + /* Use the next available one */ + if ((ov->vdev->minor == -1) && + video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1) < 0) { + err("video_register_device failed"); + goto error; + } + + info("Device at %s registered to minor %d", ov->usb_path, + ov->vdev->minor); + + usb_set_intfdata(intf, ov); + ov_create_sysfs(&ov->dev->dev); + return 0; + +error: + if (ov->vdev) { + if (-1 == ov->vdev->minor) + video_device_release(ov->vdev); + else + video_unregister_device(ov->vdev); + ov->vdev = NULL; + } + + if (ov->cbuf) { + down(&ov->cbuf_lock); + kfree(ov->cbuf); + ov->cbuf = NULL; + up(&ov->cbuf_lock); + } + + kfree(ov); + ov = NULL; + +error_out: + err("Camera initialization failed"); + return -EIO; +} + +static void +ov51x_disconnect(struct usb_interface *intf) +{ + struct usb_ov511 *ov = usb_get_intfdata(intf); + int n; + + PDEBUG(3, ""); + + usb_set_intfdata (intf, NULL); + + if (!ov) + return; + + if (ov->vdev) + video_unregister_device(ov->vdev); + + for (n = 0; n < OV511_NUMFRAMES; n++) + ov->frame[n].grabstate = FRAME_ERROR; + + ov->curframe = -1; + + /* This will cause the process to request another frame */ + for (n = 0; n < OV511_NUMFRAMES; n++) + wake_up_interruptible(&ov->frame[n].wq); + + wake_up_interruptible(&ov->wq); + + ov->streaming = 0; + ov51x_unlink_isoc(ov); + + ov->dev = NULL; + + /* Free the memory */ + if (ov && !ov->user) { + down(&ov->cbuf_lock); + kfree(ov->cbuf); + ov->cbuf = NULL; + up(&ov->cbuf_lock); + + ov51x_dealloc(ov); + kfree(ov); + ov = NULL; + } + + PDEBUG(3, "Disconnect complete"); +} + +static struct usb_driver ov511_driver = { + .name = "ov511", + .id_table = device_table, + .probe = ov51x_probe, + .disconnect = ov51x_disconnect +}; + +/**************************************************************************** + * + * Module routines + * + ***************************************************************************/ + +/* Returns 0 for success */ +int +ov511_register_decomp_module(int ver, struct ov51x_decomp_ops *ops, int ov518, + int mmx) +{ + if (ver != DECOMP_INTERFACE_VER) { + err("Decompression module has incompatible"); + err("interface version %d", ver); + err("Interface version %d is required", DECOMP_INTERFACE_VER); + return -EINVAL; + } + + if (!ops) + return -EFAULT; + + if (mmx && !ov51x_mmx_available) { + err("MMX not available on this system or kernel"); + return -EINVAL; + } + + lock_kernel(); + + if (ov518) { + if (mmx) { + if (ov518_mmx_decomp_ops) + goto err_in_use; + else + ov518_mmx_decomp_ops = ops; + } else { + if (ov518_decomp_ops) + goto err_in_use; + else + ov518_decomp_ops = ops; + } + } else { + if (mmx) { + if (ov511_mmx_decomp_ops) + goto err_in_use; + else + ov511_mmx_decomp_ops = ops; + } else { + if (ov511_decomp_ops) + goto err_in_use; + else + ov511_decomp_ops = ops; + } + } + + unlock_kernel(); + return 0; + +err_in_use: + unlock_kernel(); + return -EBUSY; +} + +void +ov511_deregister_decomp_module(int ov518, int mmx) +{ + lock_kernel(); + + if (ov518) { + if (mmx) + ov518_mmx_decomp_ops = NULL; + else + ov518_decomp_ops = NULL; + } else { + if (mmx) + ov511_mmx_decomp_ops = NULL; + else + ov511_decomp_ops = NULL; + } + + unlock_kernel(); +} + +static int __init +usb_ov511_init(void) +{ + int retval; + + retval = usb_register(&ov511_driver); + if (retval) + goto out; + + info(DRIVER_VERSION " : " DRIVER_DESC); + +out: + return retval; +} + +static void __exit +usb_ov511_exit(void) +{ + usb_deregister(&ov511_driver); + info("driver deregistered"); + +} + +module_init(usb_ov511_init); +module_exit(usb_ov511_exit); + +EXPORT_SYMBOL(ov511_register_decomp_module); +EXPORT_SYMBOL(ov511_deregister_decomp_module); --- linux-2.6.27.orig/ubuntu/misc/media/ov511/ov511_decomp.c +++ linux-2.6.27/ubuntu/misc/media/ov511/ov511_decomp.c @@ -0,0 +1,581 @@ +/* OV511 Decompression Support Module + * + * Copyright (c) 1999-2003 Mark W. McClelland. All rights reserved. + * http://alpha.dyndns.org/ov511/ + * + * Original decompression code Copyright 1998-2000 OmniVision Technologies + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + + +#if defined(OUTSIDE_KERNEL) + #if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) + #define MODVERSIONS + #endif + + #include + + #ifdef MODVERSIONS + #include + #endif +#else + #include +#endif + +#include +#include + +#include "ov511.h" + +/****************************************************************************** + * Version Information + ******************************************************************************/ + +#define DRIVER_VERSION "v1.6" +#define DRIVER_AUTHOR "Mark McClelland , OmniVision \ +Technologies " +#define DRIVER_DESC "OV511 Decompression Module" + +/****************************************************************************** + * Prototypes + ******************************************************************************/ + +extern int ov511_register_decomp_module(int ver, struct ov51x_decomp_ops *ops, + int ov518, int mmx); +extern void ov511_deregister_decomp_module(int ov518, int mmx); + +/****************************************************************************** + * Decompression Module Interface Constants + ******************************************************************************/ + +static const int interface_ver = DECOMP_INTERFACE_VER; +static const int ov518 = 0; +static const int mmx = 0; + +/****************************************************************************** + * Module Features + ******************************************************************************/ + +static int debug; + +module_param(debug, uint, 0400); +MODULE_PARM_DESC(debug, + "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max"); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +#if defined(MODULE_LICENSE) /* Introduced in ~2.4.10 */ +MODULE_LICENSE("GPL"); +#endif + +/****************************************************************************** + * Decompression Functions + ******************************************************************************/ + +static void +DecompressYHI(unsigned char *pIn, + unsigned char *pOut, + int *iIn, /* in/out */ + int *iOut, /* in/out */ + const int w, + const int YUVFlag) +{ + short ZigZag[64]; + int temp[64]; + int Zcnt_Flag = 0; + int Num8_Flag = 0; + int in_pos = *iIn; + int out_pos = *iOut; + int tmp, tmp1, tmp2, tmp3; + unsigned char header, ZTable[64]; + short tmpl, tmph, half_byte, idx, count; + unsigned long ZigZag_length = 0, ZT_length, i, j; + short DeZigZag[64]; + + const short a = 11584; + const short b = 16068; + const short c = 15136; + const short d = 13624; + const short e = 9104; + const short f = 6270; + const short g = 3196; + + int out_idx; + + /* Take off every 'Zig' */ + for (i = 0; i < 64; i++) { + ZigZag[i] = 0; + } + + /***************************** + * Read in the Y header byte * + *****************************/ + + header = pIn[in_pos]; + in_pos++; + + ZigZag_length = header & 0x3f; + ZigZag_length = ZigZag_length + 1; + + Num8_Flag = header & 0x40; + Zcnt_Flag = header & 0x80; + + /************************* + * Read in the Y content * + *************************/ + + if (Zcnt_Flag == 0) { /* Without Zero Table read contents directly */ + /* Read in ZigZag[0] */ + ZigZag[0] = pIn[in_pos++]; + tmpl = pIn[in_pos++]; + tmph = tmpl<<8; + ZigZag[0] = ZigZag[0] | tmph; + ZigZag[0] = ZigZag[0]<<4; + ZigZag[0] = ZigZag[0]>>4; + + if (Num8_Flag) { /* 8 Bits */ + for (i = 1; i < ZigZag_length; i++) { + ZigZag[i] = pIn[in_pos++]; + ZigZag[i] = ZigZag[i]<<8; + ZigZag[i] = ZigZag[i]>>8; + } + } else { /* 12 bits and has no Zero Table */ + idx = 1; + half_byte = 0; + for (i = 1; i < ZigZag_length; i++) { + if (half_byte == 0) { + ZigZag[i] = pIn[in_pos++]; + tmpl = pIn[in_pos++]; + tmph = tmpl<<8; + tmph = tmph&0x0f00; + ZigZag[i] = ZigZag[i] | tmph; + ZigZag[i] = ZigZag[i]<<4; + ZigZag[i] = ZigZag[i]>>4; + half_byte = 1; + } else { + ZigZag[i] = pIn[in_pos++]; + ZigZag[i] = ZigZag[i]<<8; + tmpl = tmpl & 0x00f0; + ZigZag[i] = ZigZag[i] | tmpl; + ZigZag[i] = ZigZag[i]>>4; + half_byte = 0; + } + } + } + } else { /* Has Zero Table */ + /* Calculate Z-Table length */ + ZT_length = ZigZag_length/8; + tmp = ZigZag_length%8; + + if (tmp > 0) { + ZT_length = ZT_length + 1; + } + + /* Read in Zero Table */ + for (j = 0; j < ZT_length; j++) { + ZTable[j] = pIn[in_pos++]; + } + + /* Read in ZigZag[0] */ + ZigZag[0] = pIn[in_pos++]; + tmpl = pIn[in_pos++]; + tmph = tmpl<<8; + ZigZag[0] = ZigZag[0] | tmph; + ZigZag[0] = ZigZag[0]<<4; + ZigZag[0] = ZigZag[0]>>4; + + /* Decode ZigZag */ + idx = 0; + ZTable[idx] = ZTable[idx]<<1; + count = 7; + + if (Num8_Flag) { /* 8 Bits and has zero table */ + for (i = 1; i < ZigZag_length; i++) { + if ((ZTable[idx]&0x80)) { + ZigZag[i] = pIn[in_pos++]; + ZigZag[i] = ZigZag[i]<<8; + ZigZag[i] = ZigZag[i]>>8; + } + + ZTable[idx]=ZTable[idx]<<1; + count--; + if (count == 0) { + count = 8; + idx++; + } + } + } else { /* 12 bits and has Zero Table */ + half_byte = 0; + for (i = 1; i < ZigZag_length; i++) { + if (ZTable[idx]&0x80) { + if (half_byte == 0) { + ZigZag[i] = pIn[in_pos++]; + tmpl = pIn[in_pos++]; + tmph = tmpl <<8; + tmph = tmph & 0x0f00; + ZigZag[i] = ZigZag[i] | tmph; + ZigZag[i] = ZigZag[i]<<4; + ZigZag[i] = ZigZag[i]>>4; + half_byte = 1; + } else { + ZigZag[i] = pIn[in_pos++]; + ZigZag[i] = ZigZag[i]<<8; + tmpl = tmpl & 0x00f0; + ZigZag[i] = ZigZag[i] | tmpl; + ZigZag[i] = ZigZag[i]>>4; + half_byte = 0; + } + } + + ZTable[idx] = ZTable[idx]<<1; + count--; + if (count == 0) { + count = 8; + idx++; + } + } + } + } + + /************* + * De-ZigZag * + *************/ + + for (j = 0; j < 64; j++) { + DeZigZag[j] = 0; + } + + if (YUVFlag == 1) { + DeZigZag[0] = ZigZag[0]; + DeZigZag[1] = ZigZag[1]<<1; + DeZigZag[2] = ZigZag[5]<<1; + DeZigZag[3] = ZigZag[6]<<2; + + DeZigZag[8] = ZigZag[2]<<1; + DeZigZag[9] = ZigZag[4]<<1; + DeZigZag[10] = ZigZag[7]<<1; + DeZigZag[11] = ZigZag[13]<<2; + + DeZigZag[16] = ZigZag[3]<<1; + DeZigZag[17] = ZigZag[8]<<1; + DeZigZag[18] = ZigZag[12]<<2; + DeZigZag[19] = ZigZag[17]<<2; + + DeZigZag[24] = ZigZag[9]<<2; + DeZigZag[25] = ZigZag[11]<<2; + DeZigZag[26] = ZigZag[18]<<2; + DeZigZag[27] = ZigZag[24]<<3; + } else { + DeZigZag[0] = ZigZag[0]; + DeZigZag[1] = ZigZag[1]<<2; + DeZigZag[2] = ZigZag[5]<<2; + DeZigZag[3] = ZigZag[6]<<3; + + DeZigZag[8] = ZigZag[2]<<2; + DeZigZag[9] = ZigZag[4]<<2; + DeZigZag[10] = ZigZag[7]<<2; + DeZigZag[11] = ZigZag[13]<<4; + + DeZigZag[16] = ZigZag[3]<<2; + DeZigZag[17] = ZigZag[8]<<2; + DeZigZag[18] = ZigZag[12]<<3; + DeZigZag[19] = ZigZag[17]<<4; + + DeZigZag[24] = ZigZag[9]<<3; + DeZigZag[25] = ZigZag[11]<<4; + DeZigZag[26] = ZigZag[18]<<4; + DeZigZag[27] = ZigZag[24]<<4; + } + + /***************** + **** IDCT 1D **** + *****************/ + +#define IDCT_1D(c0, c1, c2, c3, in) \ + do { \ + tmp1=((c0)*DeZigZag[in])+((c2)*DeZigZag[(in)+2]); \ + tmp2=(c1)*DeZigZag[(in)+1]; \ + tmp3=(c3)*DeZigZag[(in)+3]; \ + } while (0) + +#define COMPOSE_1(out1, out2) \ + do { \ + tmp=tmp1+tmp2+tmp3; \ + temp[out1] = tmp>>15; \ + tmp=tmp1-tmp2-tmp3; \ + temp[out2] = tmp>>15; \ + } while (0) + +#define COMPOSE_2(out1, out2) \ + do { \ + tmp=tmp1+tmp2-tmp3; \ + temp[out1] = tmp>>15; \ + tmp=tmp1-tmp2+tmp3; \ + temp[out2] = tmp>>15; \ + } while (0) + + /* j = 0 */ + IDCT_1D(a, b, c, d, 0); COMPOSE_1( 0, 56); + IDCT_1D(a, b, c, d, 8); COMPOSE_1( 1, 57); + IDCT_1D(a, b, c, d, 16); COMPOSE_1( 2, 58); + IDCT_1D(a, b, c, d, 24); COMPOSE_1( 3, 59); + + /* j = 1 */ + IDCT_1D(a, d, f, g, 0); COMPOSE_2( 8, 48); + IDCT_1D(a, d, f, g, 8); COMPOSE_2( 9, 49); + IDCT_1D(a, d, f, g, 16); COMPOSE_2(10, 50); + IDCT_1D(a, d, f, g, 24); COMPOSE_2(11, 51); + + /* j = 2 */ + IDCT_1D(a, e, -f, b, 0); COMPOSE_2(16, 40); + IDCT_1D(a, e, -f, b, 8); COMPOSE_2(17, 41); + IDCT_1D(a, e, -f, b, 16); COMPOSE_2(18, 42); + IDCT_1D(a, e, -f, b, 24); COMPOSE_2(19, 43); + + /* j = 3 */ + IDCT_1D(a, g, -c, e, 0); COMPOSE_2(24, 32); + IDCT_1D(a, g, -c, e, 8); COMPOSE_2(25, 33); + IDCT_1D(a, g, -c, e, 16); COMPOSE_2(26, 34); + IDCT_1D(a, g, -c, e, 24); COMPOSE_2(27, 35); + +#undef IDCT_1D +#undef COMPOSE_1 +#undef COMPOSE_2 + + /***************** + **** IDCT 2D **** + *****************/ + +#define IDCT_2D(c0, c1, c2, c3, in) \ + do { \ + tmp = temp[in]*(c0) + temp[(in)+1]*(c1) \ + + temp[(in)+2]*(c2) + temp[(in)+3]*(c3); \ + } while (0) + +#define STORE(i) \ + do { \ + tmp = tmp >> 15; \ + tmp = tmp + 128; \ + if (tmp > 255) tmp = 255; \ + if (tmp < 0) tmp = 0; \ + pOut[i] = (unsigned char) tmp; \ + } while (0) + +#define IDCT_2D_ROW(in) \ + do { \ + IDCT_2D(a, b, c, d, in); STORE(0+out_idx); \ + IDCT_2D(a, d, f, -g, in); STORE(1+out_idx); \ + IDCT_2D(a, e, -f, -b, in); STORE(2+out_idx); \ + IDCT_2D(a, g, -c, -e, in); STORE(3+out_idx); \ + IDCT_2D(a, -g, -c, e, in); STORE(4+out_idx); \ + IDCT_2D(a, -e, -f, b, in); STORE(5+out_idx); \ + IDCT_2D(a, -d, f, g, in); STORE(6+out_idx); \ + IDCT_2D(a, -b, c, -d, in); STORE(7+out_idx); \ + } while (0) + + +#define IDCT_2D_FAST(c0, c1, c2, c3, in) \ + do { \ + tmp1=((c0)*temp[in])+((c2)*temp[(in)+2]); \ + tmp2=(c1)*temp[(in)+1]; \ + tmp3=(c3)*temp[(in)+3]; \ + } while (0) + +#define STORE_FAST_1(out1, out2) \ + do { \ + tmp=tmp1+tmp2+tmp3; \ + STORE((out1)+out_idx); \ + tmp=tmp1-tmp2-tmp3; \ + STORE((out2)+out_idx); \ + } while (0) + +#define STORE_FAST_2(out1, out2) \ + do { \ + tmp=tmp1+tmp2-tmp3; \ + STORE((out1)+out_idx); \ + tmp=tmp1-tmp2+tmp3; \ + STORE((out2)+out_idx); \ + } while (0) + +#define IDCT_2D_FAST_ROW(in) \ + do { \ + IDCT_2D_FAST(a, b, c, d, in); STORE_FAST_1(0, 7); \ + IDCT_2D_FAST(a, d, f, g, in); STORE_FAST_2(1, 6); \ + IDCT_2D_FAST(a, e, -f, b, in); STORE_FAST_2(2, 5); \ + IDCT_2D_FAST(a, g, -c, e, in); STORE_FAST_2(3, 4); \ + } while (0) + + out_idx = out_pos; + + IDCT_2D_ROW(0); out_idx += w; + IDCT_2D_ROW(8); out_idx += w; + IDCT_2D_ROW(16); out_idx += w; + IDCT_2D_ROW(24); out_idx += w; + IDCT_2D_ROW(32); out_idx += w; + IDCT_2D_ROW(40); out_idx += w; + IDCT_2D_FAST_ROW(48); out_idx += w; + IDCT_2D_FAST_ROW(56); + + *iIn = in_pos; + *iOut = out_pos + 8; +} + +#define DECOMP_Y() DecompressYHI(pIn, pY, &iIn, &iY, w, 1) +#define DECOMP_U() DecompressYHI(pIn, pU, &iIn, &iU, w/2, 2) +#define DECOMP_V() DecompressYHI(pIn, pV, &iIn, &iV, w/2, 2) + +inline static int +Decompress400HiNoMMX(unsigned char *pIn, + unsigned char *pOut, + const int w, + const int h, + const int inSize) +{ + unsigned char *pY = pOut; + int x, y, iIn, iY; + + iIn = 0; + for (y = 0; y < h; y += 8) { + iY = w*y; + + for (x = 0; x < w; x += 8) + DECOMP_Y(); + } + + return 0; +} + +inline static int +Decompress420HiNoMMX(unsigned char *pIn, + unsigned char *pOut, + const int w, + const int h, + const int inSize) +{ + unsigned char *pY = pOut; + unsigned char *pU = pY + w*h; + unsigned char *pV = pU + w*h/4; + int xY, xUV, iY, iU, iV, iIn, count; + const int nBlocks = (w*h) / (32*8); + + iIn = 0; + iY = iU = iV = 0; + xY = xUV = 0; + + for (count = 0; count < nBlocks; count++) { + DECOMP_U(); + DECOMP_V(); xUV += 16; + if (xUV >= w) { + iU += (w*7)/2; + iV += (w*7)/2; + xUV = 0; + } + + DECOMP_Y(); xY += 8; + DECOMP_Y(); xY += 8; + if (xY >= w) { + iY += w*7; + xY = 0; + } + DECOMP_Y(); xY += 8; + DECOMP_Y(); xY += 8; + if (xY >= w) { + iY += w*7; + xY = 0; + } + } + + return 0; +} + +/* Input format is raw isoc. data (with header and packet + * number stripped, and all-zero blocks removed). + * Output format is YUV400 + * Returns uncompressed data length if success, or zero if error + */ +static int +Decompress400(unsigned char *pIn, + unsigned char *pOut, + unsigned char *pTmp, + int w, + int h, + int inSize) +{ + int numpix = w * h; + int rc; + + PDEBUG(4, "%dx%d pIn=%p pOut=%p inSize=%d", w, h, pIn, pOut, inSize); + + rc = Decompress400HiNoMMX(pIn, pOut, w, h, inSize); + + if (rc) + return 0; + + return numpix; +} + +/* Input format is raw isoc. data (with header and packet + * number stripped, and all-zero blocks removed). + * Output format is planar YUV420 + * Returns uncompressed data length if success, or zero if error + */ +static int +Decompress420(unsigned char *pIn, + unsigned char *pOut, + unsigned char *pTmp, + int w, + int h, + int inSize) +{ + int numpix = w * h; + int rc; + + PDEBUG(4, "%dx%d pIn=%p pOut=%p inSize=%d", w, h, pIn, pOut, inSize); + + rc = Decompress420HiNoMMX(pIn, pOut, w, h, inSize); + + if (rc) + return 0; + + return (numpix * 3 / 2); +} + +/****************************************************************************** + * Module Functions + ******************************************************************************/ + +static struct ov51x_decomp_ops decomp_ops = { + .decomp_400 = Decompress400, + .decomp_420 = Decompress420, + .owner = THIS_MODULE, +}; + +static int __init +decomp_init(void) +{ + int rc; + + rc = ov511_register_decomp_module(DECOMP_INTERFACE_VER, &decomp_ops, + ov518, mmx); + if (rc) { + err("Could not register with ov511 (rc=%d)", rc); + return -1; + } + + info(DRIVER_VERSION " : " DRIVER_DESC); + + return 0; +} + +static void __exit +decomp_exit(void) +{ + ov511_deregister_decomp_module(ov518, mmx); + info("deregistered\n"); +} + +module_init(decomp_init); +module_exit(decomp_exit); --- linux-2.6.27.orig/ubuntu/misc/media/ov511/Makefile +++ linux-2.6.27/ubuntu/misc/media/ov511/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_USB_OV511_NEW) += ov511.o ov511_decomp.o ov518_decomp.o --- linux-2.6.27.orig/ubuntu/misc/media/ov511/ov518_decomp.c +++ linux-2.6.27/ubuntu/misc/media/ov511/ov518_decomp.c @@ -0,0 +1,1566 @@ +/* OV518 Decompression Support Module (No-MMX version) + * + * Copyright (c) 2002-2003 Mark W. McClelland. All rights reserved. + * http://alpha.dyndns.org/ov511/ + * + * Fast integer iDCT by Yuri van Oers + * Original OV511 decompression code Copyright 1998-2000 OmniVision Technologies + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + + +#if defined(OUTSIDE_KERNEL) + #if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) + #define MODVERSIONS + #endif + + #include + + #ifdef MODVERSIONS + #include + #endif +#else + #include +#endif + +#include +#include + +#include "ov511.h" + +/****************************************************************************** + * Compile-time Options + ******************************************************************************/ + +/* Defining APPROXIMATE_MUL_BY_SHIFT increases performance by approximation + * the multiplications by shifts. I think there's no change in the + * calculated picture, but I'm not sure, so the choice is still in here. */ +#undef APPROXIMATE_MUL_BY_SHIFT + +/* Allows printing the dynamic quantization tables (only if debug >= 5) */ +#define PRINT_QT + +/****************************************************************************** + * Version Information + ******************************************************************************/ + +#define DRIVER_VERSION "v1.3" +#define DRIVER_AUTHOR "Mark McClelland , \ +Yuri van Oers , OmniVision Technologies \ +" +#define DRIVER_DESC "OV518 Decompression Module" + +/****************************************************************************** + * Decompression Module Interface Constants + ******************************************************************************/ + +static const int interface_ver = DECOMP_INTERFACE_VER; +static const int ov518 = 1; +static const int mmx = 0; + +/****************************************************************************** + * Module Features + ******************************************************************************/ + +static int debug = 0; + +/* Static quantization. This uses a fixed quantization table versus the one + * that is normally embedded in the data. Define this if you see very bad + * contrast or "blockiness" in the decompressed output. */ +static int staticquant = 0; + +module_param(debug, uint, 0400); +MODULE_PARM_DESC(debug, + "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max"); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +#if defined(MODULE_LICENSE) /* Introduced in ~2.4.10 */ +MODULE_LICENSE("GPL"); +#endif + +/****************************************************************************** + * Prototypes + ******************************************************************************/ + +extern int ov511_register_decomp_module(int ver, struct ov51x_decomp_ops *ops, + int ov518, int mmx); +extern void ov511_deregister_decomp_module(int ov518, int mmx); + +/****************************************************************************** + * Local Data Types + ******************************************************************************/ + +/* Make sure this remains naturally aligned and 2^n bytes in size */ +struct tree_node { + short left; /* Pointer to left child node */ + short right; /* Pointer to right child node */ + signed char depth; /* Depth (starting at 1) if leaf, else -1 */ + signed char coeffbits; /* Size of coefficient data, or zero if none */ + signed char skip; /* Number of zero coefficients. Unused w/ DC */ + char padding; /* Pad out to 8 bytes */ +}; + +struct comp_info { + int bytes; /* Number of processed input bytes */ + int bits; /* Number of unprocessed input bits */ + int rawLen; /* Total number of bytes in input buffer */ + unsigned char *qt; /* Current quantization table */ +}; + +/****************************************************************************** + * Constant Data Definitions + ******************************************************************************/ + +/* Zig-Zag Table */ +static const unsigned char ZigZag518[] = { + 0x00, 0x02, 0x03, 0x09, + 0x01, 0x04, 0x08, 0x0a, + 0x05, 0x07, 0x0b, 0x11, + 0x06, 0x0c, 0x10, 0x12, + 0x0d, 0x0f, 0x13, 0x19, + 0x0e, 0x14, 0x18, 0x1a, + 0x15, 0x17, 0x1b, 0x1e, + 0x16, 0x1c, 0x1d, 0x1f +}; + +/* Huffman trees */ + +static const struct tree_node treeYAC[] = { + { 1, 4, -1, 0, -1}, { 2, 3, -1, 0, -1}, + { -1, -1, 2, 1, 0}, { -1, -1, 2, 2, 0}, + { 5, 9, -1, 0, -1}, { 6, 7, -1, 0, -1}, + { -1, -1, 3, 3, 0}, {323, 8, -1, 0, -1}, + { -1, -1, 4, 4, 0}, { 10, 13, -1, 0, -1}, + { 38, 11, -1, 0, -1}, { 12, 39, -1, 0, -1}, + { -1, -1, 5, 5, 0}, { 59, 14, -1, 0, -1}, + { 15, 18, -1, 0, -1}, { 16, 113, -1, 0, -1}, + { 17, 40, -1, 0, -1}, { -1, -1, 7, 6, 0}, + { 19, 22, -1, 0, -1}, { 20, 41, -1, 0, -1}, + { 21, 61, -1, 0, -1}, { -1, -1, 8, 7, 0}, + { 23, 27, -1, 0, -1}, {169, 24, -1, 0, -1}, + {208, 25, -1, 0, -1}, { 26, 62, -1, 0, -1}, + { -1, -1, 10, 8, 0}, { 44, 28, -1, 0, -1}, + { 63, 29, -1, 0, -1}, { 30, 191, -1, 0, -1}, + { 31, 119, -1, 0, -1}, { 32, 82, -1, 0, -1}, + { 33, 55, -1, 0, -1}, { 34, 48, -1, 0, -1}, + {171, 35, -1, 0, -1}, { 36, 37, -1, 0, -1}, + { -1, -1, 16, 9, 0}, { -1, -1, 16, 10, 0}, + { -1, -1, 4, 1, 1}, { -1, -1, 5, 2, 1}, + { -1, -1, 7, 3, 1}, {151, 42, -1, 0, -1}, + { 43, 79, -1, 0, -1}, { -1, -1, 9, 4, 1}, + { 96, 45, -1, 0, -1}, {246, 46, -1, 0, -1}, + { 47, 115, -1, 0, -1}, { -1, -1, 11, 5, 1}, + { 49, 52, -1, 0, -1}, { 50, 51, -1, 0, -1}, + { -1, -1, 16, 6, 1}, { -1, -1, 16, 7, 1}, + { 53, 54, -1, 0, -1}, { -1, -1, 16, 8, 1}, + { -1, -1, 16, 9, 1}, { 56, 71, -1, 0, -1}, + { 57, 68, -1, 0, -1}, { 58, 67, -1, 0, -1}, + { -1, -1, 16, 10, 1}, { 60, 77, -1, 0, -1}, + { -1, -1, 5, 1, 2}, { -1, -1, 8, 2, 2}, + { -1, -1, 10, 3, 2}, {265, 64, -1, 0, -1}, + { 65, 134, -1, 0, -1}, { 66, 80, -1, 0, -1}, + { -1, -1, 12, 4, 2}, { -1, -1, 16, 5, 2}, + { 69, 70, -1, 0, -1}, { -1, -1, 16, 6, 2}, + { -1, -1, 16, 7, 2}, { 72, 75, -1, 0, -1}, + { 73, 74, -1, 0, -1}, { -1, -1, 16, 8, 2}, + { -1, -1, 16, 9, 2}, { 76, 81, -1, 0, -1}, + { -1, -1, 16, 10, 2}, { 78, 95, -1, 0, -1}, + { -1, -1, 6, 1, 3}, { -1, -1, 9, 2, 3}, + { -1, -1, 12, 3, 3}, { -1, -1, 16, 4, 3}, + { 83, 101, -1, 0, -1}, { 84, 91, -1, 0, -1}, + { 85, 88, -1, 0, -1}, { 86, 87, -1, 0, -1}, + { -1, -1, 16, 5, 3}, { -1, -1, 16, 6, 3}, + { 89, 90, -1, 0, -1}, { -1, -1, 16, 7, 3}, + { -1, -1, 16, 8, 3}, { 92, 98, -1, 0, -1}, + { 93, 94, -1, 0, -1}, { -1, -1, 16, 9, 3}, + { -1, -1, 16, 10, 3}, { -1, -1, 6, 1, 4}, + { 97, 225, -1, 0, -1}, { -1, -1, 10, 2, 4}, + { 99, 100, -1, 0, -1}, { -1, -1, 16, 3, 4}, + { -1, -1, 16, 4, 4}, {102, 109, -1, 0, -1}, + {103, 106, -1, 0, -1}, {104, 105, -1, 0, -1}, + { -1, -1, 16, 5, 4}, { -1, -1, 16, 6, 4}, + {107, 108, -1, 0, -1}, { -1, -1, 16, 7, 4}, + { -1, -1, 16, 8, 4}, {110, 116, -1, 0, -1}, + {111, 112, -1, 0, -1}, { -1, -1, 16, 9, 4}, + { -1, -1, 16, 10, 4}, {114, 133, -1, 0, -1}, + { -1, -1, 7, 1, 5}, { -1, -1, 11, 2, 5}, + {117, 118, -1, 0, -1}, { -1, -1, 16, 3, 5}, + { -1, -1, 16, 4, 5}, {120, 156, -1, 0, -1}, + {121, 139, -1, 0, -1}, {122, 129, -1, 0, -1}, + {123, 126, -1, 0, -1}, {124, 125, -1, 0, -1}, + { -1, -1, 16, 5, 5}, { -1, -1, 16, 6, 5}, + {127, 128, -1, 0, -1}, { -1, -1, 16, 7, 5}, + { -1, -1, 16, 8, 5}, {130, 136, -1, 0, -1}, + {131, 132, -1, 0, -1}, { -1, -1, 16, 9, 5}, + { -1, -1, 16, 10, 5}, { -1, -1, 7, 1, 6}, + {135, 152, -1, 0, -1}, { -1, -1, 12, 2, 6}, + {137, 138, -1, 0, -1}, { -1, -1, 16, 3, 6}, + { -1, -1, 16, 4, 6}, {140, 147, -1, 0, -1}, + {141, 144, -1, 0, -1}, {142, 143, -1, 0, -1}, + { -1, -1, 16, 5, 6}, { -1, -1, 16, 6, 6}, + {145, 146, -1, 0, -1}, { -1, -1, 16, 7, 6}, + { -1, -1, 16, 8, 6}, {148, 153, -1, 0, -1}, + {149, 150, -1, 0, -1}, { -1, -1, 16, 9, 6}, + { -1, -1, 16, 10, 6}, { -1, -1, 8, 1, 7}, + { -1, -1, 12, 2, 7}, {154, 155, -1, 0, -1}, + { -1, -1, 16, 3, 7}, { -1, -1, 16, 4, 7}, + {157, 175, -1, 0, -1}, {158, 165, -1, 0, -1}, + {159, 162, -1, 0, -1}, {160, 161, -1, 0, -1}, + { -1, -1, 16, 5, 7}, { -1, -1, 16, 6, 7}, + {163, 164, -1, 0, -1}, { -1, -1, 16, 7, 7}, + { -1, -1, 16, 8, 7}, {166, 172, -1, 0, -1}, + {167, 168, -1, 0, -1}, { -1, -1, 16, 9, 7}, + { -1, -1, 16, 10, 7}, {170, 187, -1, 0, -1}, + { -1, -1, 9, 1, 8}, { -1, -1, 15, 2, 8}, + {173, 174, -1, 0, -1}, { -1, -1, 16, 3, 8}, + { -1, -1, 16, 4, 8}, {176, 183, -1, 0, -1}, + {177, 180, -1, 0, -1}, {178, 179, -1, 0, -1}, + { -1, -1, 16, 5, 8}, { -1, -1, 16, 6, 8}, + {181, 182, -1, 0, -1}, { -1, -1, 16, 7, 8}, + { -1, -1, 16, 8, 8}, {184, 188, -1, 0, -1}, + {185, 186, -1, 0, -1}, { -1, -1, 16, 9, 8}, + { -1, -1, 16, 10, 8}, { -1, -1, 9, 1, 9}, + {189, 190, -1, 0, -1}, { -1, -1, 16, 2, 9}, + { -1, -1, 16, 3, 9}, {192, 258, -1, 0, -1}, + {193, 226, -1, 0, -1}, {194, 210, -1, 0, -1}, + {195, 202, -1, 0, -1}, {196, 199, -1, 0, -1}, + {197, 198, -1, 0, -1}, { -1, -1, 16, 4, 9}, + { -1, -1, 16, 5, 9}, {200, 201, -1, 0, -1}, + { -1, -1, 16, 6, 9}, { -1, -1, 16, 7, 9}, + {203, 206, -1, 0, -1}, {204, 205, -1, 0, -1}, + { -1, -1, 16, 8, 9}, { -1, -1, 16, 9, 9}, + {207, 209, -1, 0, -1}, { -1, -1, 16, 10, 9}, + { -1, -1, 9, 1, 10}, { -1, -1, 16, 2, 10}, + {211, 218, -1, 0, -1}, {212, 215, -1, 0, -1}, + {213, 214, -1, 0, -1}, { -1, -1, 16, 3, 10}, + { -1, -1, 16, 4, 10}, {216, 217, -1, 0, -1}, + { -1, -1, 16, 5, 10}, { -1, -1, 16, 6, 10}, + {219, 222, -1, 0, -1}, {220, 221, -1, 0, -1}, + { -1, -1, 16, 7, 10}, { -1, -1, 16, 8, 10}, + {223, 224, -1, 0, -1}, { -1, -1, 16, 9, 10}, + { -1, -1, 16, 10, 10}, { -1, -1, 10, 1, 11}, + {227, 242, -1, 0, -1}, {228, 235, -1, 0, -1}, + {229, 232, -1, 0, -1}, {230, 231, -1, 0, -1}, + { -1, -1, 16, 2, 11}, { -1, -1, 16, 3, 11}, + {233, 234, -1, 0, -1}, { -1, -1, 16, 4, 11}, + { -1, -1, 16, 5, 11}, {236, 239, -1, 0, -1}, + {237, 238, -1, 0, -1}, { -1, -1, 16, 6, 11}, + { -1, -1, 16, 7, 11}, {240, 241, -1, 0, -1}, + { -1, -1, 16, 8, 11}, { -1, -1, 16, 9, 11}, + {243, 251, -1, 0, -1}, {244, 248, -1, 0, -1}, + {245, 247, -1, 0, -1}, { -1, -1, 16, 10, 11}, + { -1, -1, 10, 1, 12}, { -1, -1, 16, 2, 12}, + {249, 250, -1, 0, -1}, { -1, -1, 16, 3, 12}, + { -1, -1, 16, 4, 12}, {252, 255, -1, 0, -1}, + {253, 254, -1, 0, -1}, { -1, -1, 16, 5, 12}, + { -1, -1, 16, 6, 12}, {256, 257, -1, 0, -1}, + { -1, -1, 16, 7, 12}, { -1, -1, 16, 8, 12}, + {259, 292, -1, 0, -1}, {260, 277, -1, 0, -1}, + {261, 270, -1, 0, -1}, {262, 267, -1, 0, -1}, + {263, 264, -1, 0, -1}, { -1, -1, 16, 9, 12}, + { -1, -1, 16, 10, 12}, {266, 322, -1, 0, -1}, + { -1, -1, 11, 1, 13}, {268, 269, -1, 0, -1}, + { -1, -1, 16, 2, 13}, { -1, -1, 16, 3, 13}, + {271, 274, -1, 0, -1}, {272, 273, -1, 0, -1}, + { -1, -1, 16, 4, 13}, { -1, -1, 16, 5, 13}, + {275, 276, -1, 0, -1}, { -1, -1, 16, 6, 13}, + { -1, -1, 16, 7, 13}, {278, 285, -1, 0, -1}, + {279, 282, -1, 0, -1}, {280, 281, -1, 0, -1}, + { -1, -1, 16, 8, 13}, { -1, -1, 16, 9, 13}, + {283, 284, -1, 0, -1}, { -1, -1, 16, 10, 13}, + { -1, -1, 16, 1, 14}, {286, 289, -1, 0, -1}, + {287, 288, -1, 0, -1}, { -1, -1, 16, 2, 14}, + { -1, -1, 16, 3, 14}, {290, 291, -1, 0, -1}, + { -1, -1, 16, 4, 14}, { -1, -1, 16, 5, 14}, + {293, 308, -1, 0, -1}, {294, 301, -1, 0, -1}, + {295, 298, -1, 0, -1}, {296, 297, -1, 0, -1}, + { -1, -1, 16, 6, 14}, { -1, -1, 16, 7, 14}, + {299, 300, -1, 0, -1}, { -1, -1, 16, 8, 14}, + { -1, -1, 16, 9, 14}, {302, 305, -1, 0, -1}, + {303, 304, -1, 0, -1}, { -1, -1, 16, 10, 14}, + { -1, -1, 16, 1, 15}, {306, 307, -1, 0, -1}, + { -1, -1, 16, 2, 15}, { -1, -1, 16, 3, 15}, + {309, 316, -1, 0, -1}, {310, 313, -1, 0, -1}, + {311, 312, -1, 0, -1}, { -1, -1, 16, 4, 15}, + { -1, -1, 16, 5, 15}, {314, 315, -1, 0, -1}, + { -1, -1, 16, 6, 15}, { -1, -1, 16, 7, 15}, + {317, 320, -1, 0, -1}, {318, 319, -1, 0, -1}, + { -1, -1, 16, 8, 15}, { -1, -1, 16, 9, 15}, + {321, -1, -1, 0, -1}, { -1, -1, 16, 10, 15}, + { -1, -1, 11, 0, 16}, { -1, -1, 4, 0, -1}, +}; + +static const struct tree_node treeUVAC[] = { + { 1, 3, -1, 0, -1}, {323, 2, -1, 0, -1}, + { -1, -1, 2, 1, 0}, { 4, 8, -1, 0, -1}, + { 5, 6, -1, 0, -1}, { -1, -1, 3, 2, 0}, + { 7, 37, -1, 0, -1}, { -1, -1, 4, 3, 0}, + { 9, 13, -1, 0, -1}, { 10, 60, -1, 0, -1}, + { 11, 12, -1, 0, -1}, { -1, -1, 5, 4, 0}, + { -1, -1, 5, 5, 0}, { 14, 17, -1, 0, -1}, + { 15, 97, -1, 0, -1}, { 16, 38, -1, 0, -1}, + { -1, -1, 6, 6, 0}, { 18, 21, -1, 0, -1}, + { 19, 39, -1, 0, -1}, { 20, 135, -1, 0, -1}, + { -1, -1, 7, 7, 0}, { 22, 26, -1, 0, -1}, + { 82, 23, -1, 0, -1}, { 24, 99, -1, 0, -1}, + { 25, 42, -1, 0, -1}, { -1, -1, 9, 8, 0}, + { 27, 31, -1, 0, -1}, {211, 28, -1, 0, -1}, + {248, 29, -1, 0, -1}, { 30, 63, -1, 0, -1}, + { -1, -1, 10, 9, 0}, { 43, 32, -1, 0, -1}, + { 33, 48, -1, 0, -1}, {153, 34, -1, 0, -1}, + { 35, 64, -1, 0, -1}, { 36, 47, -1, 0, -1}, + { -1, -1, 12, 10, 0}, { -1, -1, 4, 1, 1}, + { -1, -1, 6, 2, 1}, {152, 40, -1, 0, -1}, + { 41, 62, -1, 0, -1}, { -1, -1, 8, 3, 1}, + { -1, -1, 9, 4, 1}, { 84, 44, -1, 0, -1}, + {322, 45, -1, 0, -1}, { 46, 136, -1, 0, -1}, + { -1, -1, 11, 5, 1}, { -1, -1, 12, 6, 1}, + { 49, 189, -1, 0, -1}, { 50, 119, -1, 0, -1}, + { 51, 76, -1, 0, -1}, { 66, 52, -1, 0, -1}, + { 53, 69, -1, 0, -1}, { 54, 57, -1, 0, -1}, + { 55, 56, -1, 0, -1}, { -1, -1, 16, 7, 1}, + { -1, -1, 16, 8, 1}, { 58, 59, -1, 0, -1}, + { -1, -1, 16, 9, 1}, { -1, -1, 16, 10, 1}, + { 61, 81, -1, 0, -1}, { -1, -1, 5, 1, 2}, + { -1, -1, 8, 2, 2}, { -1, -1, 10, 3, 2}, + { 65, 86, -1, 0, -1}, { -1, -1, 12, 4, 2}, + {286, 67, -1, 0, -1}, { 68, 304, -1, 0, -1}, + { -1, -1, 15, 5, 2}, { 70, 73, -1, 0, -1}, + { 71, 72, -1, 0, -1}, { -1, -1, 16, 6, 2}, + { -1, -1, 16, 7, 2}, { 74, 75, -1, 0, -1}, + { -1, -1, 16, 8, 2}, { -1, -1, 16, 9, 2}, + { 77, 102, -1, 0, -1}, { 78, 91, -1, 0, -1}, + { 79, 88, -1, 0, -1}, { 80, 87, -1, 0, -1}, + { -1, -1, 16, 10, 2}, { -1, -1, 5, 1, 3}, + { 83, 171, -1, 0, -1}, { -1, -1, 8, 2, 3}, + { 85, 117, -1, 0, -1}, { -1, -1, 10, 3, 3}, + { -1, -1, 12, 4, 3}, { -1, -1, 16, 5, 3}, + { 89, 90, -1, 0, -1}, { -1, -1, 16, 6, 3}, + { -1, -1, 16, 7, 3}, { 92, 95, -1, 0, -1}, + { 93, 94, -1, 0, -1}, { -1, -1, 16, 8, 3}, + { -1, -1, 16, 9, 3}, { 96, 101, -1, 0, -1}, + { -1, -1, 16, 10, 3}, { 98, 116, -1, 0, -1}, + { -1, -1, 6, 1, 4}, {100, 188, -1, 0, -1}, + { -1, -1, 9, 2, 4}, { -1, -1, 16, 3, 4}, + {103, 110, -1, 0, -1}, {104, 107, -1, 0, -1}, + {105, 106, -1, 0, -1}, { -1, -1, 16, 4, 4}, + { -1, -1, 16, 5, 4}, {108, 109, -1, 0, -1}, + { -1, -1, 16, 6, 4}, { -1, -1, 16, 7, 4}, + {111, 114, -1, 0, -1}, {112, 113, -1, 0, -1}, + { -1, -1, 16, 8, 4}, { -1, -1, 16, 9, 4}, + {115, 118, -1, 0, -1}, { -1, -1, 16, 10, 4}, + { -1, -1, 6, 1, 5}, { -1, -1, 10, 2, 5}, + { -1, -1, 16, 3, 5}, {120, 156, -1, 0, -1}, + {121, 138, -1, 0, -1}, {122, 129, -1, 0, -1}, + {123, 126, -1, 0, -1}, {124, 125, -1, 0, -1}, + { -1, -1, 16, 4, 5}, { -1, -1, 16, 5, 5}, + {127, 128, -1, 0, -1}, { -1, -1, 16, 6, 5}, + { -1, -1, 16, 7, 5}, {130, 133, -1, 0, -1}, + {131, 132, -1, 0, -1}, { -1, -1, 16, 8, 5}, + { -1, -1, 16, 9, 5}, {134, 137, -1, 0, -1}, + { -1, -1, 16, 10, 5}, { -1, -1, 7, 1, 6}, + { -1, -1, 11, 2, 6}, { -1, -1, 16, 3, 6}, + {139, 146, -1, 0, -1}, {140, 143, -1, 0, -1}, + {141, 142, -1, 0, -1}, { -1, -1, 16, 4, 6}, + { -1, -1, 16, 5, 6}, {144, 145, -1, 0, -1}, + { -1, -1, 16, 6, 6}, { -1, -1, 16, 7, 6}, + {147, 150, -1, 0, -1}, {148, 149, -1, 0, -1}, + { -1, -1, 16, 8, 6}, { -1, -1, 16, 9, 6}, + {151, 155, -1, 0, -1}, { -1, -1, 16, 10, 6}, + { -1, -1, 7, 1, 7}, {154, 267, -1, 0, -1}, + { -1, -1, 11, 2, 7}, { -1, -1, 16, 3, 7}, + {157, 173, -1, 0, -1}, {158, 165, -1, 0, -1}, + {159, 162, -1, 0, -1}, {160, 161, -1, 0, -1}, + { -1, -1, 16, 4, 7}, { -1, -1, 16, 5, 7}, + {163, 164, -1, 0, -1}, { -1, -1, 16, 6, 7}, + { -1, -1, 16, 7, 7}, {166, 169, -1, 0, -1}, + {167, 168, -1, 0, -1}, { -1, -1, 16, 8, 7}, + { -1, -1, 16, 9, 7}, {170, 172, -1, 0, -1}, + { -1, -1, 16, 10, 7}, { -1, -1, 8, 1, 8}, + { -1, -1, 16, 2, 8}, {174, 181, -1, 0, -1}, + {175, 178, -1, 0, -1}, {176, 177, -1, 0, -1}, + { -1, -1, 16, 3, 8}, { -1, -1, 16, 4, 8}, + {179, 180, -1, 0, -1}, { -1, -1, 16, 5, 8}, + { -1, -1, 16, 6, 8}, {182, 185, -1, 0, -1}, + {183, 184, -1, 0, -1}, { -1, -1, 16, 7, 8}, + { -1, -1, 16, 8, 8}, {186, 187, -1, 0, -1}, + { -1, -1, 16, 9, 8}, { -1, -1, 16, 10, 8}, + { -1, -1, 9, 1, 9}, {190, 257, -1, 0, -1}, + {191, 224, -1, 0, -1}, {192, 207, -1, 0, -1}, + {193, 200, -1, 0, -1}, {194, 197, -1, 0, -1}, + {195, 196, -1, 0, -1}, { -1, -1, 16, 2, 9}, + { -1, -1, 16, 3, 9}, {198, 199, -1, 0, -1}, + { -1, -1, 16, 4, 9}, { -1, -1, 16, 5, 9}, + {201, 204, -1, 0, -1}, {202, 203, -1, 0, -1}, + { -1, -1, 16, 6, 9}, { -1, -1, 16, 7, 9}, + {205, 206, -1, 0, -1}, { -1, -1, 16, 8, 9}, + { -1, -1, 16, 9, 9}, {208, 217, -1, 0, -1}, + {209, 214, -1, 0, -1}, {210, 213, -1, 0, -1}, + { -1, -1, 16, 10, 9}, {212, 230, -1, 0, -1}, + { -1, -1, 9, 1, 10}, { -1, -1, 16, 2, 10}, + {215, 216, -1, 0, -1}, { -1, -1, 16, 3, 10}, + { -1, -1, 16, 4, 10}, {218, 221, -1, 0, -1}, + {219, 220, -1, 0, -1}, { -1, -1, 16, 5, 10}, + { -1, -1, 16, 6, 10}, {222, 223, -1, 0, -1}, + { -1, -1, 16, 7, 10}, { -1, -1, 16, 8, 10}, + {225, 241, -1, 0, -1}, {226, 234, -1, 0, -1}, + {227, 231, -1, 0, -1}, {228, 229, -1, 0, -1}, + { -1, -1, 16, 9, 10}, { -1, -1, 16, 10, 10}, + { -1, -1, 9, 1, 11}, {232, 233, -1, 0, -1}, + { -1, -1, 16, 2, 11}, { -1, -1, 16, 3, 11}, + {235, 238, -1, 0, -1}, {236, 237, -1, 0, -1}, + { -1, -1, 16, 4, 11}, { -1, -1, 16, 5, 11}, + {239, 240, -1, 0, -1}, { -1, -1, 16, 6, 11}, + { -1, -1, 16, 7, 11}, {242, 250, -1, 0, -1}, + {243, 246, -1, 0, -1}, {244, 245, -1, 0, -1}, + { -1, -1, 16, 8, 11}, { -1, -1, 16, 9, 11}, + {247, 249, -1, 0, -1}, { -1, -1, 16, 10, 11}, + { -1, -1, 9, 1, 12}, { -1, -1, 16, 2, 12}, + {251, 254, -1, 0, -1}, {252, 253, -1, 0, -1}, + { -1, -1, 16, 3, 12}, { -1, -1, 16, 4, 12}, + {255, 256, -1, 0, -1}, { -1, -1, 16, 5, 12}, + { -1, -1, 16, 6, 12}, {258, 291, -1, 0, -1}, + {259, 275, -1, 0, -1}, {260, 268, -1, 0, -1}, + {261, 264, -1, 0, -1}, {262, 263, -1, 0, -1}, + { -1, -1, 16, 7, 12}, { -1, -1, 16, 8, 12}, + {265, 266, -1, 0, -1}, { -1, -1, 16, 9, 12}, + { -1, -1, 16, 10, 12}, { -1, -1, 11, 1, 13}, + {269, 272, -1, 0, -1}, {270, 271, -1, 0, -1}, + { -1, -1, 16, 2, 13}, { -1, -1, 16, 3, 13}, + {273, 274, -1, 0, -1}, { -1, -1, 16, 4, 13}, + { -1, -1, 16, 5, 13}, {276, 283, -1, 0, -1}, + {277, 280, -1, 0, -1}, {278, 279, -1, 0, -1}, + { -1, -1, 16, 6, 13}, { -1, -1, 16, 7, 13}, + {281, 282, -1, 0, -1}, { -1, -1, 16, 8, 13}, + { -1, -1, 16, 9, 13}, {284, 288, -1, 0, -1}, + {285, 287, -1, 0, -1}, { -1, -1, 16, 10, 13}, + { -1, -1, 14, 1, 14}, { -1, -1, 16, 2, 14}, + {289, 290, -1, 0, -1}, { -1, -1, 16, 3, 14}, + { -1, -1, 16, 4, 14}, {292, 308, -1, 0, -1}, + {293, 300, -1, 0, -1}, {294, 297, -1, 0, -1}, + {295, 296, -1, 0, -1}, { -1, -1, 16, 5, 14}, + { -1, -1, 16, 6, 14}, {298, 299, -1, 0, -1}, + { -1, -1, 16, 7, 14}, { -1, -1, 16, 8, 14}, + {301, 305, -1, 0, -1}, {302, 303, -1, 0, -1}, + { -1, -1, 16, 9, 14}, { -1, -1, 16, 10, 14}, + { -1, -1, 15, 1, 15}, {306, 307, -1, 0, -1}, + { -1, -1, 16, 2, 15}, { -1, -1, 16, 3, 15}, + {309, 316, -1, 0, -1}, {310, 313, -1, 0, -1}, + {311, 312, -1, 0, -1}, { -1, -1, 16, 4, 15}, + { -1, -1, 16, 5, 15}, {314, 315, -1, 0, -1}, + { -1, -1, 16, 6, 15}, { -1, -1, 16, 7, 15}, + {317, 320, -1, 0, -1}, {318, 319, -1, 0, -1}, + { -1, -1, 16, 8, 15}, { -1, -1, 16, 9, 15}, + {321, -1, -1, 0, -1}, { -1, -1, 16, 10, 15}, + { -1, -1, 10, 0, 16}, { -1, -1, 2, 0, -1}, +}; + +static const struct tree_node treeYDC[] = { + { 1, 6, -1, 0}, { 2, 3, -1, 0}, + { -1, -1, 2, 0}, { 4, 5, -1, 0}, + { -1, -1, 3, 1}, { -1, -1, 3, 2}, + { 7, 10, -1, 0}, { 8, 9, -1, 0}, + { -1, -1, 3, 3}, { -1, -1, 3, 4}, + { 11, 12, -1, 0}, { -1, -1, 3, 5}, + { 13, 14, -1, 0}, { -1, -1, 4, 6}, + { 15, 16, -1, 0}, { -1, -1, 5, 7}, + { 17, 18, -1, 0}, { -1, -1, 6, 8}, + { 19, 20, -1, 0}, { -1, -1, 7, 9}, + { 21, 22, -1, 0}, { -1, -1, 8, 10}, + { 23, -1, -1, 0}, { -1, -1, 9, 11}, +}; + +static const struct tree_node treeUVDC[] = { + { 1, 4, -1, 0}, { 2, 3, -1, 0}, + { -1, -1, 2, 0}, { -1, -1, 2, 1}, + { 5, 6, -1, 0}, { -1, -1, 2, 2}, + { 7, 8, -1, 0}, { -1, -1, 3, 3}, + { 9, 10, -1, 0}, { -1, -1, 4, 4}, + { 11, 12, -1, 0}, { -1, -1, 5, 5}, + { 13, 14, -1, 0}, { -1, -1, 6, 6}, + { 15, 16, -1, 0}, { -1, -1, 7, 7}, + { 17, 18, -1, 0}, { -1, -1, 8, 8}, + { 19, 20, -1, 0}, { -1, -1, 9, 9}, + { 21, 22, -1, 0}, { -1, -1, 10, 10}, + { 23, -1, -1, 0}, { -1, -1, 11, 11}, +}; + +/****************************************************************************** + * Debugging + ******************************************************************************/ + +#ifdef PRINT_QT +#define PRN_QT_ROW(a, i) PDEBUG(5, "%02x %02x %02x %02x %02x %02x %02x %02x", \ + (a)[(i)], (a)[(i)+1], (a)[(i)+2], (a)[(i)+3], (a)[(i)+4], (a)[(i)+5], \ + (a)[(i)+6], (a)[(i)+7]) + +static inline void +print_qt(unsigned char *qt) +{ + PDEBUG(5, "Y Quantization table:"); + PRN_QT_ROW(qt, 0); + PRN_QT_ROW(qt, 8); + PRN_QT_ROW(qt, 16); + PRN_QT_ROW(qt, 24); + PDEBUG(5, "UV Quantization table:"); + PRN_QT_ROW(qt, 32); + PRN_QT_ROW(qt, 40); + PRN_QT_ROW(qt, 48); + PRN_QT_ROW(qt, 56); +} +#else +static inline void +print_qt(unsigned char *qt) { } +#endif /* PRINT_QT */ + +/****************************************************************************** + * Huffman Decoder + ******************************************************************************/ + +/* Note: There is no penalty for passing the tree as an argument, since dummy + * args are passed anyway (to maintain 16-byte stack alignment), and since the + * address is loaded into a register either way. */ + +/* If no node is found, coeffbits and skip will not be modified */ +/* Return: Depth of node found, or -1 if invalid input code */ +static int +getNodeAC(unsigned int in, signed char *coeffbits, signed char *skip, + const struct tree_node *tree) +{ + int node = 0; + int i = 0; + int depth; + + do { + if ((in & 0x80000000) == 0) + node = tree[node].left; + else + node = tree[node].right; + + if (node == -1) + break; + + depth = tree[node].depth; + + /* Is it a leaf? If not, branch downward */ + if (depth != -1) { + *coeffbits = tree[node].coeffbits; + *skip = tree[node].skip; + return depth; + } + + in <<= 1; + ++i; + } while (i <= 15); + + return -1; +} + +/* If no node is found, coeffbits will not be modified */ +/* Return: Depth of node found, or -1 if invalid input code */ +static int +getNodeDC(unsigned int in, signed char *coeffbits, const struct tree_node *tree) +{ + int node = 0; + int i = 0; + int depth; + + do { + if ((in & 0x80000000) == 0) + node = tree[node].left; + else + node = tree[node].right; + + if (node == -1) + break; + + depth = tree[node].depth; + + /* Is it a leaf? If not, branch downward */ + if (depth != -1) { + *coeffbits = tree[node].coeffbits; + return depth; + } + + in <<= 1; + ++i; + } while (i <= 15); + + return -1; +} + +static inline unsigned int +getBytes(int *rawData, struct comp_info *cinfo) +{ + int bufLen = cinfo->rawLen; + int bits = cinfo->bits; + int bytes = cinfo->bytes; + unsigned char *in = bytes + (unsigned char *) rawData; + unsigned char b1, b2, b3, b4, b5; + unsigned int packedIn; + + /* Pull 5 bytes out of raw data */ + if (bytes < bufLen - 4) { + b1 = in[0]; + b2 = in[1]; + b3 = in[2]; + b4 = in[3]; + b5 = in[4]; + } else { + if (bytes < bufLen - 3) { + b1 = in[0]; + b2 = in[1]; + b3 = in[2]; + b4 = in[3]; + } else { + if (bytes < bufLen - 2) { + b1 = in[0]; + b2 = in[1]; + b3 = in[2]; + } else { + if (bytes < bufLen - 1) { + b1 = in[0]; + b2 = in[1]; + } else { + if (bytes <= bufLen) { + b1 = in[0]; + } else { + b1 = 0; + } + b2 = 0; + } + b3 = 0; + } + b4 = 0; + } + b5 = 0; + } + + /* Pack the bytes */ + packedIn = b1 << 24; + packedIn += b2 << 16; + packedIn += b3 << 8; + packedIn += b4; + + if (bits != 0) { + packedIn = packedIn << bits; + packedIn += b5 >> (8 - bits); + } + + return packedIn; +} + +static int +getACCoefficient(int *rawData, int *coeff, struct comp_info *cinfo, + const struct tree_node *tree) +{ + int input, bits, bytes, tmp_c; + signed char coeffbits = 0; + signed char skip = 0; + + input = getBytes(rawData, cinfo); + bits = getNodeAC(input, &coeffbits, &skip, tree); + + if (coeffbits) { + input = input << (bits - 1); + input &= 0x7fffffff; + if (! (input & 0x40000000)) + input |= 0x80000000; + + tmp_c = input >> (31 - coeffbits); + if (tmp_c < 0) + tmp_c++; + *coeff = tmp_c; + + bits += coeffbits; + } + + bytes = (bits + cinfo->bits) >> 3; + cinfo->bytes += bytes; + cinfo->bits += bits - (bytes << 3); + + return skip; +} + +static void +getDCCoefficient(int *rawData, int *coeff, struct comp_info *cinfo, + const struct tree_node *tree) +{ + int input, bits, bytes, tmp_c; + signed char coeffbits = 0; + + input = getBytes(rawData, cinfo); + bits = getNodeDC(input, &coeffbits, tree); + + if (bits == -1) { + bits = 1; /* Try to re-sync at the next bit */ + *coeff = 0; /* Indicates no change from last DC */ + } else { + + input = input << (bits - 1); + input &= 0x7fffffff; + if (! (input & 0x40000000)) + input |= 0x80000000; + + tmp_c = input >> (31 - coeffbits); + if (tmp_c < 0) + tmp_c++; + *coeff = tmp_c; + + bits += coeffbits; + } + + bytes = (bits + cinfo->bits) >> 3; + cinfo->bytes += bytes; + cinfo->bits += bits - (bytes << 3); +} + +/* For AC coefficients, here is what the "skip" value means: + * -1: Either the 8x4 block has ended, or the decoding failed. + * 0: Use the returned coeff. Don't skip anything. + * 1-15: The next coeffs are zero. The returned coeff is used. + * 16: The next 16 coeffs are zero. The returned coeff is ignored. + * + * You must ensure that the C[] array not be overrun, or stack corruption will + * result. + */ +static void +huffmanDecoderY(int *C, int *pIn, struct comp_info *cinfo) +{ + int coeff = 0; + int i = 1; + int k, skip; + + getDCCoefficient(pIn, C, cinfo, treeYDC); + + i = 1; + do { + skip = getACCoefficient(pIn, &coeff, cinfo, treeYAC); + + if (skip == -1) { + break; + } else if (skip == 0) { + C[i++] = coeff; + } else if (skip == 16) { + k = 16; + if (i > 16) + k = 32 - i; + + while (k--) + C[i++] = 0; + } else { + k = skip; + if (skip > 31 - i) + k = 31 - i; + + while (k--) + C[i++] = 0; + + C[i++] = coeff; + } + } while (i <= 31); + + if (skip == -1) + while (i <= 31) C[i++] = 0; + else + getACCoefficient(pIn, &coeff, cinfo, treeYAC); +} + +/* Same as huffmanDecoderY, except for the tables used */ +static void +huffmanDecoderUV(int *C, int *pIn, struct comp_info *cinfo) +{ + int coeff = 0; + int i = 1; + int k, skip; + + getDCCoefficient(pIn, C, cinfo, treeUVDC); + + i = 1; + do { + skip = getACCoefficient(pIn, &coeff, cinfo, treeUVAC); + + if (skip == -1) { + break; + } else if (skip == 0) { + C[i++] = coeff; + } else if (skip == 16) { + k = 16; + if (i > 16) + k = 32 - i; + + while (k--) + C[i++] = 0; + } else { + k = skip; + if (skip > 31 - i) + k = 31 - i; + + while (k--) + C[i++] = 0; + + C[i++] = coeff; + } + } while (i <= 31); + + if (skip == -1) + while (i <= 31) C[i++] = 0; + else + getACCoefficient(pIn, &coeff, cinfo, treeUVAC); +} + +/****************************************************************************** + * iDCT Functions + ******************************************************************************/ + +#ifndef APPROXIMATE_MUL_BY_SHIFT + +#define IDCT_MESSAGE "iDCT with multiply" + +#define TIMES_16382(u) ((u)? 16382 * (u):0) +#define TIMES_23168(u) ((u)? 23168 * (u):0) +#define TIMES_30270(u) ((u)? 30270 * (u):0) +#define TIMES_41986(u) ((u)? 41986 * (u):0) +#define TIMES_35594(u) ((u)? 35594 * (u):0) +#define TIMES_23783(u) ((u)? 23783 * (u):0) +#define TIMES_8351(u) ((u)? 8351 * (u):0) +#define TIMES_17391(u) ((u)? 17391 * (u):0) +#define TIMES_14743(u) ((u)? 14743 * (u):0) +#define TIMES_9851(u) ((u)? 9851 * (u):0) +#define TIMES_3459(u) ((u)? 3459 * (u):0) +#define TIMES_32134(u) ((u)? 32134 * (u):0) +#define TIMES_27242(u) ((u)? 27242 * (u):0) +#define TIMES_18202(u) ((u)? 18202 * (u):0) +#define TIMES_6392(u) ((u)? 6392 * (u):0) +#define TIMES_39550(u) ((u)? 39550 * (u):0) +#define TIMES_6785(u) ((u)? 6785 * (u):0) +#define TIMES_12538(u) ((u)? 12538 * (u):0) + +#else + +#define IDCT_MESSAGE "iDCT with shift" + +#define TIMES_16382(u) ( (u)? x=(u) , (x<<14) - (x<<1) :0 ) +#define TIMES_23168(u) ( (u)? x=(u) , (x<<14) + (x<<12) + (x<<11) + (x<<9) :0 ) +#define TIMES_30270(u) ( (u)? x=(u) , (x<<15) - (x<<11) :0 ) +#define TIMES_41986(u) ( (u)? x=(u) , (x<<15) + (x<<13) + (x<<10) :0 ) +#define TIMES_35594(u) ( (u)? x=(u) , (x<<15) + (x<<11) + (x<<9) + (x<<8) :0 ) +#define TIMES_23783(u) ( (u)? x=(u) , (x<<14) + (x<<13) - (x<<9) - (x<<8) :0 ) +#define TIMES_8351(u) ( (u)? x=(u) , (x<<13) :0 ) +#define TIMES_17391(u) ( (u)? x=(u) , (x<<14) + (x<<10) :0 ) +#define TIMES_14743(u) ( (u)? x=(u) , (x<<14) - (x<<10) - (x<<9) :0 ) +#define TIMES_9851(u) ( (u)? x=(u) , (x<<13) + (x<<10) + (x<<9) :0 ) +#define TIMES_3459(u) ( (u)? x=(u) , (x<<12) - (x<<9) :0 ) +#define TIMES_32134(u) ( (u)? x=(u) , (x<<15) - (x<<9) :0 ) +#define TIMES_27242(u) ( (u)? x=(u) , (x<<14) + (x<<13) + (x<<11) + (x<<9) :0 ) +#define TIMES_18202(u) ( (u)? x=(u) , (x<<14) + (x<<11) - (x<<8) :0 ) +#define TIMES_6392(u) ( (u)? x=(u) , (x<<13) - (x<<11) + (x<<8) :0 ) +#define TIMES_39550(u) ( (u)? x=(u) , (x<<15) + (x<<12) + (x<<11) + (x<<9) :0 ) +#define TIMES_6785(u) ( (u)? x=(u) , (x<<12) + (x<<11) + (x<<9) :0 ) +#define TIMES_12538(u) ( (u)? x=(u) , (x<<13) + (x<<12) + (x<<8) :0 ) + +/* + * The variables C0, C4, C16 and C20 can also be removed from the algorithm + * if APPROXIMATE_MUL_BY_SHIFTS is defined. They store correction values + * and can be considered insignificant. + */ + +#endif + +static void +DCT_8x4(int *coeff, unsigned char *out) +/* pre: coeff == coefficients + post: coeff != coefficients + ** DO NOT ASSUME coeff TO BE THE SAME BEFORE AND AFTER CALLING THIS FUNCTION! +*/ +{ + register int base,val1,val2,val3; + int tmp1,tmp2; + int C0,C4,C16,C20; + int C2_18,C6_22,C1_17,C3_19,C5_21,C7_23; + register int t; +#ifdef APPROXIMATE_MUL_BY_SHIFT + register int x; +#endif + + C0=coeff[0]; + C4=coeff[4]; + C16=coeff[16]; + C20=coeff[20]; + + coeff[0]=TIMES_23168(coeff[0]); + coeff[4]=TIMES_23168(coeff[4]); + coeff[16]=TIMES_23168(coeff[16]); + coeff[20]=TIMES_23168(coeff[20]); + + C2_18 = coeff[2]+coeff[18]; + C6_22 = coeff[6]+coeff[22]; + C1_17 = coeff[1]+coeff[17]; + C3_19 = coeff[3]+coeff[19]; + C5_21 = coeff[5]+coeff[21]; + C7_23 = coeff[7]+coeff[23]; + +// 0,7,25,32 + + base = 0x1000000; + base += coeff[0]+coeff[4]+coeff[16]+coeff[20]; + base += TIMES_30270(C2_18); + base += TIMES_12538(C6_22); + + val1 = TIMES_41986(coeff[9]); + val1 += TIMES_35594(coeff[11]); + val1 += TIMES_23783(coeff[13]); + val1 += TIMES_8351(coeff[15]); + val1 += TIMES_17391(coeff[25]); + val1 += TIMES_14743(coeff[27]); + val1 += TIMES_9851(coeff[29]); + val1 += TIMES_3459(coeff[31]); + + val2 = TIMES_32134(C1_17); + val2 += TIMES_27242(C3_19); + val2 += TIMES_18202(C5_21); + val2 += TIMES_6392(C7_23); + + val3 = TIMES_39550(coeff[10]); + val3 += TIMES_16382(coeff[14]+coeff[26]); + val3 += TIMES_6785(coeff[30]); + val3 += TIMES_30270(coeff[8]+coeff[12]); + val3 += TIMES_12538(coeff[24]+coeff[28]); + + t=(base + val1 + val2 + val3) >> 17; + out[0]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 - val2 + val3 - C4 - C20) >> 17; + out[7]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 + val2 - val3 - C16- C20) >> 17; + out[24]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base + val1 - val2 - val3 - C4 - C16 - C20) >> 17; + out[31]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + +//1,6,25,30 + + base = 0x1000000; + base += coeff[0]-coeff[4]+coeff[16]-coeff[20]; + base += TIMES_12538(C2_18); + base -= TIMES_30270(C6_22); + + val1 = TIMES_35594(coeff[9]); + val1 -= TIMES_8351(coeff[11]); + val1 -= TIMES_41986(coeff[13]); + val1 -= TIMES_23783(coeff[15]); + val1 -= TIMES_14743(coeff[25]); + val1 -= TIMES_3459(coeff[27]); + val1 -= TIMES_17391(coeff[29]); + val1 -= TIMES_9851(coeff[31]); + + val2 = TIMES_27242(C1_17); + val2 -= TIMES_6392(C3_19); + val2 -= TIMES_32134(C5_21); + val2 -= TIMES_18202(C7_23); + + val3 = TIMES_16382(coeff[10]-coeff[30]); + val3 -= TIMES_39550(coeff[14]); + val3 += TIMES_6785(coeff[26]); + val3 += TIMES_12538(coeff[24]-coeff[28]); + val3 += TIMES_30270(coeff[8]-coeff[12]); + + t=(base + val1 + val2 + val3 + C4 + C20) >> 17; + out[1]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 - val2 + val3) >> 17; + out[6]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 + val2 - val3 + C4 - C16 + C20) >> 17; + out[25]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base + val1 - val2 - val3 + C20) >> 17; + out[30]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + +//2,5,26,29 + + base = 0x1000000; + base += coeff[0] - coeff[4] + coeff[16] - coeff[20]; + base -= TIMES_12538(C2_18); + base += TIMES_30270(C6_22); + + val1 = TIMES_23783(coeff[9]); + val1 -= TIMES_41986(coeff[11]); + val1 += TIMES_8351(coeff[13]); + val1 += TIMES_35594(coeff[15]); + val1 += TIMES_9851(coeff[25]); + val1 -= TIMES_17391(coeff[27]); + val1 += TIMES_3459(coeff[29]); + val1 += TIMES_14743(coeff[31]); + + val2 = TIMES_18202(C1_17); + val2 -= TIMES_32134(C3_19); + val2 += TIMES_6392(C5_21); + val2 += TIMES_27242(C7_23); + + val3 = -TIMES_16382(coeff[10] - coeff[30]); + val3 += TIMES_39550(coeff[14]); + val3 -= TIMES_6785(coeff[26]); + val3 += TIMES_12538(coeff[24] - coeff[28]); + val3 += TIMES_30270(coeff[8] - coeff[12]); + + t=(base + val1 + val2 + val3) >> 17; + out[2]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 - val2 + val3) >> 17; + out[5]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 + val2 - val3 - C16) >> 17; + out[26]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base + val1 - val2 - val3 + C4 - C16 + C20) >> 17; + out[29]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + +//3,4,27,28 + + base = 0x1000000; + base += coeff[0] + coeff[4] + coeff[16] + coeff[20]; + base -= TIMES_30270(C2_18); + base -= TIMES_12538(C6_22); + + val1 = TIMES_8351(coeff[9]); + val1 -= TIMES_23783(coeff[11]); + val1 += TIMES_35594(coeff[13]); + val1 += TIMES_3459(coeff[25]); + val1 -= TIMES_9851(coeff[27]); + val1 += TIMES_14743(coeff[29]); + + val2 = TIMES_6392(C1_17); + val2 -= TIMES_18202(C3_19); + val2 += TIMES_27242(C5_21); + + val3 = -TIMES_39550(coeff[10]); + val3 += TIMES_16382(coeff[14] + coeff[26]); + val3 -= TIMES_6785(coeff[30]); + val3 += TIMES_30270(coeff[8] + coeff[12]); + val3 += TIMES_12538(coeff[24] + coeff[28]); + + tmp1 = TIMES_32134(C7_23); + tmp2 = TIMES_41986(coeff[15]) + TIMES_17391(coeff[31]); + + t=(base + val1 + val2 + val3 - tmp1 - tmp2 - C4 - C20) >> 17; + out[3]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 - val2 + val3) >> 17; + out[4]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 + val2 - val3 - tmp1 + tmp2) >> 17; + out[27]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base + val1 - val2 - val3 - C16 - C20) >> 17; + out[28]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + +// Second half + C2_18 = coeff[2] - coeff[18]; + C6_22 = coeff[6] - coeff[22]; + C1_17 = coeff[1] - coeff[17]; + C3_19 = coeff[3] - coeff[19]; + C5_21 = coeff[5] - coeff[21]; + C7_23 = coeff[7] - coeff[23]; + +// 8,15,16,23 + + base = 0x1000000; + base += coeff[0] + coeff[4] - coeff[16] - coeff[20]; + base +=TIMES_30270(C2_18); + base +=TIMES_12538(C6_22); + + val1 = TIMES_17391(coeff[9]); + val1 += TIMES_14743(coeff[11]); + val1 += TIMES_9851(coeff[13]); + val1 += TIMES_3459(coeff[15]); + val1 -= TIMES_41986(coeff[25]); + val1 -= TIMES_35594(coeff[27]); + val1 -= TIMES_23783(coeff[29]); + val1 -= TIMES_8351(coeff[31]); + + val2 = TIMES_32134(C1_17); + val2 += TIMES_27242(C3_19); + val2 += TIMES_18202(C5_21); + val2 += TIMES_6392(C7_23); + + val3 = TIMES_16382(coeff[10] - coeff[30]); + val3 += TIMES_6785(coeff[14]); + val3 -= TIMES_39550(coeff[26]); + val3 -=TIMES_30270(coeff[24] + coeff[28]); + val3 +=TIMES_12538(coeff[8] + coeff[12]); + + t=(base + val1 + val2 + val3) >> 17; + out[8]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 - val2 + val3 - C4 + C16 + C20) >> 17; + out[15]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 + val2 - val3) >> 17; + out[16]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base + val1 - val2 - val3 - C4 + C20) >> 17; + out[23]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + +//9,14,17,22 + + base = 0x1000000; + base += coeff[0] - coeff[4] - coeff[16] + coeff[20]; + base += TIMES_12538(C2_18); + base -= TIMES_30270(C6_22); + + val1 = TIMES_14743(coeff[9]); + val1 -= TIMES_3459(coeff[11]); + val1 -= TIMES_17391(coeff[13]); + val1 -= TIMES_9851(coeff[15]); + val1 -= TIMES_35594(coeff[25]); + val1 += TIMES_8351(coeff[27]); + val1 += TIMES_41986(coeff[29]); + val1 += TIMES_23783(coeff[31]); + + val2 = TIMES_27242(C1_17); + val2 -= TIMES_6392(C3_19); + val2 -= TIMES_32134(C5_21); + val2 -= TIMES_18202(C7_23); + + val3 = TIMES_6785(coeff[10]); + val3 -= TIMES_16382(coeff[14] + coeff[26]); + val3 += TIMES_39550(coeff[30]); + val3 += TIMES_12538(coeff[8] - coeff[12]); + val3 -= TIMES_30270(coeff[24] - coeff[28]); + + t=(base + val1 + val2 + val3 + C4 + C16 - C20) >> 17; + out[9]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 - val2 + val3 + C16) >> 17; + out[14]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 + val2 - val3 + C4) >> 17; + out[17]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base + val1 - val2 - val3) >> 17; + out[22]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + +//10,13,18,21 + + base = 0x1000000; + base += coeff[0] - coeff[4] - coeff[16] + coeff[20]; + base -= TIMES_12538(C2_18); + base += TIMES_30270(C6_22); + + val1 = TIMES_9851(coeff[9]); + val1 -= TIMES_17391(coeff[11]); + val1 += TIMES_3459(coeff[13]); + val1 += TIMES_14743(coeff[15]); + val1 -= TIMES_23783(coeff[25]); + val1 += TIMES_41986(coeff[27]); + val1 -= TIMES_8351(coeff[29]); + val1 -= TIMES_35594(coeff[31]); + + val2 = TIMES_18202(C1_17); + val2 -= TIMES_32134(C3_19); + val2 += TIMES_6392(C5_21); + val2 += TIMES_27242(C7_23); + + val3 = -TIMES_6785(coeff[10]); + val3 += TIMES_16382(coeff[14]+coeff[26]); + val3 -= TIMES_39550(coeff[30]); + val3 += TIMES_12538(coeff[8]-coeff[12]); + val3 -= TIMES_30270(coeff[24]-coeff[28]); + + t=(base + val1 + val2 + val3) >> 17; + out[10]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 - val2 + val3 + C4 + C16 - C20) >> 17; + out[13]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 + val2 - val3) >> 17; + out[18]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base + val1 - val2 - val3 + C4) >> 17; + out[21]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + +// 11,12,19,20 + + base = 0x1000000; + base += coeff[0]+coeff[4]-coeff[16]-coeff[20]; + base -= TIMES_30270(C2_18); + base -= TIMES_12538(C6_22); + + val1 = TIMES_3459(coeff[9]); + val1 -= TIMES_9851(coeff[11]); + val1 += TIMES_14743(coeff[13]); + val1 -= TIMES_8351(coeff[25]); + val1 += TIMES_23783(coeff[27]); + val1 -= TIMES_35594(coeff[29]); + + val2 = TIMES_6392(C1_17); + val2 -= TIMES_18202(C3_19); + val2 += TIMES_27242(C5_21); + + val3 = -TIMES_16382(coeff[10] - coeff[30]); + val3 -= TIMES_6785(coeff[14]); + val3 += TIMES_39550(coeff[26]); + val3 -= TIMES_30270(coeff[24]+coeff[28]); + val3 += TIMES_12538(coeff[8]+coeff[12]); + + tmp1 = TIMES_32134(C7_23); + tmp2 = -TIMES_17391(coeff[15]) + TIMES_41986(coeff[31]); + + t=(base + val1 + val2 + val3 - tmp1 + tmp2 + C16 + C20) >> 17; + out[11]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 - val2 + val3 + C16 + C20) >> 17; + out[12]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base - val1 + val2 - val3 - tmp1 - tmp2 - C4 + C20) >> 17; + out[19]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; + t=(base + val1 - val2 - val3) >> 17; + out[20]= t&0xFFFFFF00? t<0?0:255 : (unsigned char)t; +} + +#undef TIMES_16382 +#undef TIMES_23168 +#undef TIMES_30270 +#undef TIMES_41986 +#undef TIMES_35594 +#undef TIMES_23783 +#undef TIMES_8351 +#undef TIMES_17391 +#undef TIMES_14743 +#undef TIMES_9851 +#undef TIMES_3459 +#undef TIMES_32134 +#undef TIMES_27242 +#undef TIMES_18202 +#undef TIMES_6392 +#undef TIMES_39550 +#undef TIMES_6785 +#undef TIMES_12538 + +/****************************************************************************** + * Main Decoder Functions + ******************************************************************************/ + +/* This function handles the decompression of a single 8x4 block. It is + * independent of the palette (YUV422, YUV420, YUV400, GBR422...). cinfo->bytes + * determines the positin in the input buffer. + */ +static int +decompress8x4(unsigned char *pOut, + unsigned char *pIn, + int *lastDC, + int uvFlag, + struct comp_info *cinfo) +{ + int i, x, y, dc; + int coeffs[32]; + int deZigZag[32]; + int *dest; + int *src; + unsigned char *qt = cinfo->qt; + + if (! uvFlag) { + huffmanDecoderY(coeffs, (int*) pIn, cinfo); + + /* iDPCM and dequantize first coefficient */ + dc = (*lastDC) + coeffs[0]; + coeffs[0] = dc * (qt[0] + 1); + *lastDC = dc; + + /* ...and the second coefficient */ + coeffs[1] = ((qt[1] + 1) * coeffs[1]) >> 1; + + /* Dequantize, starting at 3rd element */ + for (i = 2; i < 32; i++) + coeffs[i] = (qt[i] + 1) * coeffs[i]; + } else { + huffmanDecoderUV(coeffs, (int*) pIn, cinfo); + + /* iDPCM */ + dc = (*lastDC) + coeffs[0]; + coeffs[0] = dc; + *lastDC = dc; + + /* Dequantize */ + for (i = 0; i < 32; i++) + coeffs[i] = (qt[32 + i] + 1) * coeffs[i]; + } + + /* Dezigzag */ + for (i = 0; i < 32; i++) + deZigZag[i] = coeffs[ZigZag518[i]]; + + /* Transpose the dezigzagged coefficient matrix */ + src = deZigZag; + dest = coeffs; + for (y = 0; y <= 3; ++y) { + for (x = 0; x <= 7; ++x) { + dest[x] = src[x * 4]; + } + src += 1; + dest += 8; + } + + /* Do the inverse DCT transform */ + DCT_8x4(coeffs, pOut); + + return 0; /* Always returns 0 */ +} + +static inline void +copyBlock(unsigned char *src, unsigned char *dest, int destInc) +{ + int i; + unsigned int *pSrc, *pDest; + + for (i = 0; i <= 3; i++) { + pSrc = (unsigned int *) src; + pDest = (unsigned int *) dest; + pDest[0] = pSrc[0]; + pDest[1] = pSrc[1]; + src += 8; + dest += destInc; + } +} + +static inline int +decompress400NoMMXOV518(unsigned char *pIn, + unsigned char *pOut, + unsigned char *pTmp, + const int w, + const int h, + const int numpix, + struct comp_info *cinfo) +{ + int iOutY, x, y; + int lastYDC = 0; + + /* Start Y loop */ + y = 0; + do { + iOutY = w * y; + x = 0; + do { + decompress8x4(pTmp, pIn, &lastYDC, 0, cinfo); + copyBlock(pTmp, pOut + iOutY, w); + iOutY += 8; + x += 8; + } while (x < w); + y += 4; + } while (y < h); + + /* Did we decode too much? */ + if (cinfo->bytes > cinfo->rawLen + 897) + return 1; + + /* Did we decode enough? */ + if (cinfo->bytes >= cinfo->rawLen - 897) + return 0; + else + return 1; +} + +static inline int +decompress420NoMMXOV518(unsigned char *pIn, + unsigned char *pOut, + unsigned char *pTmp, + const int w, + const int h, + const int numpix, + struct comp_info *cinfo) +{ + unsigned char *pOutU = pOut + numpix; + unsigned char *pOutV = pOutU + numpix / 4; + int iOutY, iOutU, iOutV, x, y; + int lastYDC = 0; + int lastUDC = 0; + int lastVDC = 0; + + /* Start Y loop */ + y = 0; + do { + iOutY = w * y; + iOutV = iOutU = iOutY / 4; + + x = 0; + do { + decompress8x4(pTmp, pIn, &lastYDC, 0, cinfo); + copyBlock(pTmp, pOut + iOutY, w); + iOutY += 8; + x += 8; + } while (x < w); + + + + iOutY = w * (y + 4); + x = 0; + do { + decompress8x4(pTmp, pIn, &lastUDC, 1, cinfo); + copyBlock(pTmp, pOutU + iOutU, w/2); + iOutU += 8; + + decompress8x4(pTmp, pIn, &lastVDC, 1, cinfo); + copyBlock(pTmp, pOutV + iOutV, w/2); + iOutV += 8; + + decompress8x4(pTmp, pIn, &lastYDC, 0, cinfo); + copyBlock(pTmp, pOut + iOutY, w); + iOutY += 8; + + decompress8x4(pTmp, pIn, &lastYDC, 0, cinfo); + copyBlock(pTmp, pOut + iOutY, w); + iOutY += 8; + + x += 16; + } while (x < w); + + y += 8; + } while (y < h); + + /* Did we decode too much? */ + if (cinfo->bytes > cinfo->rawLen + 897) + return 1; + + /* Did we decode enough? */ + if (cinfo->bytes >= cinfo->rawLen - 897) + return 0; + else + return 1; +} + +/* Get quantization tables from static arrays + * Returns: <0 if error, or >=0 otherwise */ +static int +get_qt_static(struct comp_info *cinfo) +{ + unsigned char qtY[] = OV518_YQUANTABLE; + unsigned char qtUV[] = OV518_UVQUANTABLE; + unsigned char qt[64]; + + memcpy(qt, qtY, 32); + memcpy(qt + 32, qtUV, 32); + cinfo->qt = qt; + + return 0; +} + + +/* Get quantization tables from input + * Returns: <0 if error, or >=0 otherwise */ +static int +get_qt_dynamic(unsigned char *pIn, struct comp_info *cinfo) +{ + int rawLen = cinfo->rawLen; + + /* Make sure input is actually big enough to hold trailer */ + if (rawLen < 72) { + PDEBUG(1, "Not enough input to decompress"); + return -EINVAL; + } + + cinfo->qt = pIn + rawLen - 64; + + print_qt(cinfo->qt); + + return 0; +} + +/* Input format is raw isoc. data (with intact SOF header, packet numbers + * stripped, and all-zero blocks removed). + * Output format is planar YUV400 + * Returns uncompressed data length if success, or zero if error + */ +static int +Decompress400(unsigned char *pIn, + unsigned char *pOut, + unsigned char *pTmp, + int w, + int h, + int inSize) +{ + struct comp_info cinfo; + int numpix = w * h; + + PDEBUG(4, "%dx%d pIn=%p pOut=%p pTmp=%p inSize=%d", w, h, pIn, pOut, + pTmp, inSize); + + cinfo.bytes = 0; + cinfo.bits = 0; + cinfo.rawLen = inSize; + + if (staticquant) { + if (get_qt_static(&cinfo) < 0) + return 0; + } else { + if (get_qt_dynamic(pIn, &cinfo) < 0) + return 0; + } + + /* Decompress, skipping the 8-byte SOF header */ + if (decompress400NoMMXOV518(pIn + 8, pOut, pTmp, w, h, numpix, &cinfo)) +// return 0; + ; /* Don't return error yet */ + + return (numpix); +} + +/* Input format is raw isoc. data (with intact SOF header, packet numbers + * stripped, and all-zero blocks removed). + * Output format is planar YUV420 + * Returns uncompressed data length if success, or zero if error + */ +static int +Decompress420(unsigned char *pIn, + unsigned char *pOut, + unsigned char *pTmp, + int w, + int h, + int inSize) +{ + struct comp_info cinfo; + int numpix = w * h; + + PDEBUG(4, "%dx%d pIn=%p pOut=%p pTmp=%p inSize=%d", w, h, pIn, pOut, + pTmp, inSize); + + cinfo.bytes = 0; + cinfo.bits = 0; + cinfo.rawLen = inSize; + + if (staticquant) { + if (get_qt_static(&cinfo) < 0) + return 0; + } else { + if (get_qt_dynamic(pIn, &cinfo) < 0) + return 0; + } + + /* Decompress, skipping the 8-byte SOF header */ + if (decompress420NoMMXOV518(pIn + 8, pOut, pTmp, w, h, numpix, &cinfo)) +// return 0; + ; /* Don't return error yet */ + + return (numpix * 3 / 2); +} + +/****************************************************************************** + * Module Functions + ******************************************************************************/ + +static struct ov51x_decomp_ops decomp_ops = { + .decomp_400 = Decompress400, + .decomp_420 = Decompress420, + .owner = THIS_MODULE, +}; + +static int __init +decomp_init(void) +{ + int rc; + + rc = ov511_register_decomp_module(DECOMP_INTERFACE_VER, &decomp_ops, + ov518, mmx); + if (rc) { + err("Could not register with ov511 (rc=%d)", rc); + return -1; + } + + info(DRIVER_VERSION " : " DRIVER_DESC); + PDEBUG(1, "Using %s, %s quantization", IDCT_MESSAGE, + staticquant ? "static" : "dynamic"); + + return 0; +} + +static void __exit +decomp_exit(void) +{ + ov511_deregister_decomp_module(ov518, mmx); + info("deregistered"); +} + +module_init(decomp_init); +module_exit(decomp_exit); --- linux-2.6.27.orig/ubuntu/misc/media/ov511/ov511.h +++ linux-2.6.27/ubuntu/misc/media/ov511/ov511.h @@ -0,0 +1,570 @@ +#ifndef __LINUX_OV511_H +#define __LINUX_OV511_H + +#include +#include +#include +#include +#include + +#define OV511_DEBUG /* Turn on debug messages */ + +#ifdef OV511_DEBUG + #define PDEBUG(level, fmt, args...) \ + if (debug >= (level)) info("[%s:%d] " fmt, \ + __FUNCTION__, __LINE__ , ## args) +#else + #define PDEBUG(level, fmt, args...) do {} while(0) +#endif + +/* This macro restricts an int variable to an inclusive range */ +#define RESTRICT_TO_RANGE(v,mi,ma) { \ + if ((v) < (mi)) (v) = (mi); \ + else if ((v) > (ma)) (v) = (ma); \ +} + +/* --------------------------------- */ +/* DEFINES FOR OV511 AND OTHER CHIPS */ +/* --------------------------------- */ + +/* USB IDs */ +#define VEND_OMNIVISION 0x05A9 +#define PROD_OV511 0x0511 +#define PROD_OV511PLUS 0xA511 +#define PROD_OV518 0x0518 +#define PROD_OV518PLUS 0xA518 + +#define VEND_MATTEL 0x0813 +#define PROD_ME2CAM 0x0002 + +/* --------------------------------- */ +/* OV51x REGISTER MNEMONICS */ +/* --------------------------------- */ + +/* Camera interface register numbers */ +#define R511_CAM_DELAY 0x10 +#define R511_CAM_EDGE 0x11 +#define R511_CAM_PXCNT 0x12 +#define R511_CAM_LNCNT 0x13 +#define R511_CAM_PXDIV 0x14 +#define R511_CAM_LNDIV 0x15 +#define R511_CAM_UV_EN 0x16 +#define R511_CAM_LINE_MODE 0x17 +#define R511_CAM_OPTS 0x18 + +/* Snapshot mode camera interface register numbers */ +#define R511_SNAP_FRAME 0x19 +#define R511_SNAP_PXCNT 0x1A +#define R511_SNAP_LNCNT 0x1B +#define R511_SNAP_PXDIV 0x1C +#define R511_SNAP_LNDIV 0x1D +#define R511_SNAP_UV_EN 0x1E +#define R511_SNAP_OPTS 0x1F + +/* DRAM register numbers */ +#define R511_DRAM_FLOW_CTL 0x20 +#define R511_DRAM_ARCP 0x21 +#define R511_DRAM_MRC 0x22 +#define R511_DRAM_RFC 0x23 + +/* ISO FIFO register numbers */ +#define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */ +#define R511_FIFO_OPTS 0x31 + +/* Parallel IO register numbers */ +#define R511_PIO_OPTS 0x38 +#define R511_PIO_DATA 0x39 +#define R511_PIO_BIST 0x3E +#define R518_GPIO_IN 0x55 /* OV518(+) only */ +#define R518_GPIO_OUT 0x56 /* OV518(+) only */ +#define R518_GPIO_CTL 0x57 /* OV518(+) only */ +#define R518_GPIO_PULSE_IN 0x58 /* OV518(+) only */ +#define R518_GPIO_PULSE_CLEAR 0x59 /* OV518(+) only */ +#define R518_GPIO_PULSE_POL 0x5a /* OV518(+) only */ +#define R518_GPIO_PULSE_EN 0x5b /* OV518(+) only */ +#define R518_GPIO_RESET 0x5c /* OV518(+) only */ + +/* I2C registers */ +#define R511_I2C_CTL 0x40 +#define R518_I2C_CTL 0x47 /* OV518(+) only */ +#define R51x_I2C_W_SID 0x41 +#define R51x_I2C_SADDR_3 0x42 +#define R51x_I2C_SADDR_2 0x43 +#define R51x_I2C_R_SID 0x44 +#define R51x_I2C_DATA 0x45 +#define R51x_I2C_CLOCK 0x46 +#define R51x_I2C_TIMEOUT 0x47 + +/* I2C snapshot registers */ +#define R511_SI2C_SADDR_3 0x48 +#define R511_SI2C_DATA 0x49 + +/* System control registers */ +#define R51x_SYS_RESET 0x50 + /* Reset type definitions */ +#define OV511_RESET_UDC 0x01 +#define OV511_RESET_I2C 0x02 +#define OV511_RESET_FIFO 0x04 +#define OV511_RESET_OMNICE 0x08 +#define OV511_RESET_DRAM 0x10 +#define OV511_RESET_CAM_INT 0x20 +#define OV511_RESET_OV511 0x40 +#define OV511_RESET_NOREGS 0x3F /* All but OV511 & regs */ +#define OV511_RESET_ALL 0x7F + +#define R511_SYS_CLOCK_DIV 0x51 +#define R51x_SYS_SNAP 0x52 +#define R51x_SYS_INIT 0x53 +#define R511_SYS_PWR_CLK 0x54 /* OV511+/OV518(+) only */ +#define R511_SYS_LED_CTL 0x55 /* OV511+ only */ +#define R511_SYS_USER 0x5E +#define R511_SYS_CUST_ID 0x5F + +/* OmniCE (compression) registers */ +#define R511_COMP_PHY 0x70 +#define R511_COMP_PHUV 0x71 +#define R511_COMP_PVY 0x72 +#define R511_COMP_PVUV 0x73 +#define R511_COMP_QHY 0x74 +#define R511_COMP_QHUV 0x75 +#define R511_COMP_QVY 0x76 +#define R511_COMP_QVUV 0x77 +#define R511_COMP_EN 0x78 +#define R511_COMP_LUT_EN 0x79 +#define R511_COMP_LUT_BEGIN 0x80 + +/* --------------------------------- */ +/* ALTERNATE NUMBERS */ +/* --------------------------------- */ + +/* Alternate numbers for various max packet sizes (OV511 only) */ +#define OV511_ALT_SIZE_992 0 +#define OV511_ALT_SIZE_993 1 +#define OV511_ALT_SIZE_768 2 +#define OV511_ALT_SIZE_769 3 +#define OV511_ALT_SIZE_512 4 +#define OV511_ALT_SIZE_513 5 +#define OV511_ALT_SIZE_257 6 +#define OV511_ALT_SIZE_0 7 + +/* Alternate numbers for various max packet sizes (OV511+ only) */ +#define OV511PLUS_ALT_SIZE_0 0 +#define OV511PLUS_ALT_SIZE_33 1 +#define OV511PLUS_ALT_SIZE_129 2 +#define OV511PLUS_ALT_SIZE_257 3 +#define OV511PLUS_ALT_SIZE_385 4 +#define OV511PLUS_ALT_SIZE_513 5 +#define OV511PLUS_ALT_SIZE_769 6 +#define OV511PLUS_ALT_SIZE_961 7 + +/* Alternate numbers for various max packet sizes (OV518(+) only) */ +#define OV518_ALT_SIZE_0 0 +#define OV518_ALT_SIZE_128 1 +#define OV518_ALT_SIZE_256 2 +#define OV518_ALT_SIZE_384 3 +#define OV518_ALT_SIZE_512 4 +#define OV518_ALT_SIZE_640 5 +#define OV518_ALT_SIZE_768 6 +#define OV518_ALT_SIZE_896 7 + +/* --------------------------------- */ +/* OV7610 REGISTER MNEMONICS */ +/* --------------------------------- */ + +/* OV7610 registers */ +#define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */ +#define OV7610_REG_BLUE 0x01 /* blue channel balance */ +#define OV7610_REG_RED 0x02 /* red channel balance */ +#define OV7610_REG_SAT 0x03 /* saturation */ + /* 04 reserved */ +#define OV7610_REG_CNT 0x05 /* Y contrast */ +#define OV7610_REG_BRT 0x06 /* Y brightness */ + /* 08-0b reserved */ +#define OV7610_REG_BLUE_BIAS 0x0C /* blue channel bias (5:0) */ +#define OV7610_REG_RED_BIAS 0x0D /* read channel bias (5:0) */ +#define OV7610_REG_GAMMA_COEFF 0x0E /* gamma settings */ +#define OV7610_REG_WB_RANGE 0x0F /* AEC/ALC/S-AWB settings */ +#define OV7610_REG_EXP 0x10 /* manual exposure setting */ +#define OV7610_REG_CLOCK 0x11 /* polarity/clock prescaler */ +#define OV7610_REG_COM_A 0x12 /* misc common regs */ +#define OV7610_REG_COM_B 0x13 /* misc common regs */ +#define OV7610_REG_COM_C 0x14 /* misc common regs */ +#define OV7610_REG_COM_D 0x15 /* misc common regs */ +#define OV7610_REG_FIELD_DIVIDE 0x16 /* field interval/mode settings */ +#define OV7610_REG_HWIN_START 0x17 /* horizontal window start */ +#define OV7610_REG_HWIN_END 0x18 /* horizontal window end */ +#define OV7610_REG_VWIN_START 0x19 /* vertical window start */ +#define OV7610_REG_VWIN_END 0x1A /* vertical window end */ +#define OV7610_REG_PIXEL_SHIFT 0x1B /* pixel shift */ +#define OV7610_REG_ID_HIGH 0x1C /* manufacturer ID MSB */ +#define OV7610_REG_ID_LOW 0x1D /* manufacturer ID LSB */ + /* 0e-0f reserved */ +#define OV7610_REG_COM_E 0x20 /* misc common regs */ +#define OV7610_REG_YOFFSET 0x21 /* Y channel offset */ +#define OV7610_REG_UOFFSET 0x22 /* U channel offset */ + /* 23 reserved */ +#define OV7610_REG_ECW 0x24 /* Exposure white level for AEC */ +#define OV7610_REG_ECB 0x25 /* Exposure black level for AEC */ +#define OV7610_REG_COM_F 0x26 /* misc settings */ +#define OV7610_REG_COM_G 0x27 /* misc settings */ +#define OV7610_REG_COM_H 0x28 /* misc settings */ +#define OV7610_REG_COM_I 0x29 /* misc settings */ +#define OV7610_REG_FRAMERATE_H 0x2A /* frame rate MSB + misc */ +#define OV7610_REG_FRAMERATE_L 0x2B /* frame rate LSB */ +#define OV7610_REG_ALC 0x2C /* Auto Level Control settings */ +#define OV7610_REG_COM_J 0x2D /* misc settings */ +#define OV7610_REG_VOFFSET 0x2E /* V channel offset adjustment */ +#define OV7610_REG_ARRAY_BIAS 0x2F /* Array bias -- don't change */ + /* 30-32 reserved */ +#define OV7610_REG_YGAMMA 0x33 /* misc gamma settings (7:6) */ +#define OV7610_REG_BIAS_ADJUST 0x34 /* misc bias settings */ +#define OV7610_REG_COM_L 0x35 /* misc settings */ + /* 36-37 reserved */ +#define OV7610_REG_COM_K 0x38 /* misc registers */ + +/* --------------------------------- */ +/* I2C ADDRESSES */ +/* --------------------------------- */ + +#define OV7xx0_SID 0x42 +#define OV6xx0_SID 0xC0 +#define OV8xx0_SID 0xA0 +#define KS0127_SID 0xD8 +#define SAA7111A_SID 0x48 + +/* --------------------------------- */ +/* MISCELLANEOUS DEFINES */ +/* --------------------------------- */ + +#define I2C_CLOCK_PRESCALER 0x03 + +#define FRAMES_PER_DESC 10 /* FIXME - What should this be? */ +#define MAX_FRAME_SIZE_PER_DESC 993 /* For statically allocated stuff */ +#define PIXELS_PER_SEG 256 /* Pixels per segment */ + +#define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */ + +#define OV511_NUMFRAMES 2 +#if OV511_NUMFRAMES > VIDEO_MAX_FRAME + #error "OV511_NUMFRAMES is too high" +#endif + +#define OV511_NUMSBUF 2 + +/* Control transfers use up to 4 bytes */ +#define OV511_CBUF_SIZE 4 + +/* Size of usb_make_path() buffer */ +#define OV511_USB_PATH_LEN 64 + +/* Bridge types */ +enum { + BRG_UNKNOWN, + BRG_OV511, + BRG_OV511PLUS, + BRG_OV518, + BRG_OV518PLUS, +}; + +/* Bridge classes */ +enum { + BCL_UNKNOWN, + BCL_OV511, + BCL_OV518, +}; + +/* Sensor types */ +enum { + SEN_UNKNOWN, + SEN_OV76BE, + SEN_OV7610, + SEN_OV7620, + SEN_OV7620AE, + SEN_OV6620, + SEN_OV6630, + SEN_OV6630AE, + SEN_OV6630AF, + SEN_OV8600, + SEN_KS0127, + SEN_KS0127B, + SEN_SAA7111A, +}; + +enum { + STATE_SCANNING, /* Scanning for start */ + STATE_HEADER, /* Parsing header */ + STATE_LINES, /* Parsing lines */ +}; + +/* Buffer states */ +enum { + BUF_NOT_ALLOCATED, + BUF_ALLOCATED, +}; + +/* --------- Definition of ioctl interface --------- */ + +#define OV511_INTERFACE_VER 101 + +/* LED options */ +enum { + LED_OFF, + LED_ON, + LED_AUTO, +}; + +/* Raw frame formats */ +enum { + RAWFMT_INVALID, + RAWFMT_YUV400, + RAWFMT_YUV420, + RAWFMT_YUV422, + RAWFMT_GBR422, +}; + +struct ov511_i2c_struct { + unsigned char slave; /* Write slave ID (read ID - 1) */ + unsigned char reg; /* Index of register */ + unsigned char value; /* User sets this w/ write, driver does w/ read */ + unsigned char mask; /* Bits to be changed. Not used with read ops */ +}; + +/* ioctls */ +#define OV511IOC_WI2C _IOW('v', BASE_VIDIOCPRIVATE + 5, \ + struct ov511_i2c_struct) +#define OV511IOC_RI2C _IOWR('v', BASE_VIDIOCPRIVATE + 6, \ + struct ov511_i2c_struct) +/* ------------- End IOCTL interface -------------- */ + +struct usb_ov511; /* Forward declaration */ + +struct ov511_sbuf { + struct usb_ov511 *ov; + unsigned char *data; + struct urb *urb; + spinlock_t lock; + int n; +}; + +enum { + FRAME_UNUSED, /* Unused (no MCAPTURE) */ + FRAME_READY, /* Ready to start grabbing */ + FRAME_GRABBING, /* In the process of being grabbed into */ + FRAME_DONE, /* Finished grabbing, but not been synced yet */ + FRAME_ERROR, /* Something bad happened while processing */ +}; + +struct ov511_regvals { + enum { + OV511_DONE_BUS, + OV511_REG_BUS, + OV511_I2C_BUS, + } bus; + unsigned char reg; + unsigned char val; +}; + +struct ov511_frame { + int framenum; /* Index of this frame */ + unsigned char *data; /* Frame buffer */ + unsigned char *tempdata; /* Temp buffer for multi-stage conversions */ + unsigned char *rawdata; /* Raw camera data buffer */ + unsigned char *compbuf; /* Temp buffer for decompressor */ + + int depth; /* Bytes per pixel */ + int width; /* Width application is expecting */ + int height; /* Height application is expecting */ + + int rawwidth; /* Actual width of frame sent from camera */ + int rawheight; /* Actual height of frame sent from camera */ + + int sub_flag; /* Sub-capture mode for this frame? */ + unsigned int format; /* Format for this frame */ + int compressed; /* Is frame compressed? */ + + volatile int grabstate; /* State of grabbing */ + int scanstate; /* State of scanning */ + + int bytes_recvd; /* Number of image bytes received from camera */ + + long bytes_read; /* Amount that has been read() */ + + wait_queue_head_t wq; /* Processes waiting */ + + int snapshot; /* True if frame was a snapshot */ +}; + +#define DECOMP_INTERFACE_VER 4 + +/* Compression module operations */ +struct ov51x_decomp_ops { + int (*decomp_400)(unsigned char *, unsigned char *, unsigned char *, + int, int, int); + int (*decomp_420)(unsigned char *, unsigned char *, unsigned char *, + int, int, int); + int (*decomp_422)(unsigned char *, unsigned char *, unsigned char *, + int, int, int); + struct module *owner; +}; + +struct usb_ov511 { + struct video_device *vdev; + struct usb_device *dev; + + int customid; + char *desc; + unsigned char iface; + char usb_path[OV511_USB_PATH_LEN]; + + /* Determined by sensor type */ + int maxwidth; + int maxheight; + int minwidth; + int minheight; + + int brightness; + int colour; + int contrast; + int hue; + int whiteness; + int exposure; + int auto_brt; /* Auto brightness enabled flag */ + int auto_gain; /* Auto gain control enabled flag */ + int auto_exp; /* Auto exposure enabled flag */ + int backlight; /* Backlight exposure algorithm flag */ + int mirror; /* Image is reversed horizontally */ + + int led_policy; /* LED: off|on|auto; OV511+ only */ + + struct semaphore lock; /* Serializes user-accessible operations */ + int user; /* user count for exclusive use */ + + int streaming; /* Are we streaming Isochronous? */ + int grabbing; /* Are we grabbing? */ + + int compress; /* Should the next frame be compressed? */ + int compress_inited; /* Are compression params uploaded? */ + + int lightfreq; /* Power (lighting) frequency */ + int bandfilt; /* Banding filter enabled flag */ + + unsigned char *fbuf; /* Videodev buffer area */ + unsigned char *tempfbuf; /* Temporary (intermediate) buffer area */ + unsigned char *rawfbuf; /* Raw camera data buffer area */ + + int sub_flag; /* Pix Array subcapture on flag */ + int subx; /* Pix Array subcapture x offset */ + int suby; /* Pix Array subcapture y offset */ + int subw; /* Pix Array subcapture width */ + int subh; /* Pix Array subcapture height */ + + int curframe; /* Current receiving sbuf */ + struct ov511_frame frame[OV511_NUMFRAMES]; + + struct ov511_sbuf sbuf[OV511_NUMSBUF]; + + wait_queue_head_t wq; /* Processes waiting */ + + int snap_enabled; /* Snapshot mode enabled */ + + int bridge; /* Type of bridge (BRG_*) */ + int bclass; /* Class of bridge (BCL_*) */ + int sensor; /* Type of image sensor chip (SEN_*) */ + + int packet_size; /* Frame size per isoc desc */ + int packet_numbering; /* Is ISO frame numbering enabled? */ + + struct semaphore param_lock; /* params lock for this camera */ + + /* Framebuffer/sbuf management */ + int buf_state; + struct semaphore buf_lock; + + struct ov51x_decomp_ops *decomp_ops; + + /* Stop streaming while changing picture settings */ + int stop_during_set; + + int stopped; /* Streaming is temporarily paused */ + + /* Video decoder stuff */ + int input; /* Composite, S-VIDEO, etc... */ + int num_inputs; /* Number of inputs */ + int norm; /* NTSC / PAL / SECAM */ + int has_decoder; /* Device has a video decoder */ + int pal; /* Device is designed for PAL resolution */ + + /* I2C interface */ + struct semaphore i2c_lock; /* Protect I2C controller regs */ + unsigned char primary_i2c_slave; /* I2C write id of sensor */ + + /* Control transaction stuff */ + unsigned char *cbuf; /* Buffer for payload */ + struct semaphore cbuf_lock; +}; + +/* Used to represent a list of values and their respective symbolic names */ +struct symbolic_list { + int num; + char *name; +}; + +#define NOT_DEFINED_STR "Unknown" + +/* Returns the name of the matching element in the symbolic_list array. The + * end of the list must be marked with an element that has a NULL name. + */ +static inline char * +symbolic(struct symbolic_list list[], int num) +{ + int i; + + for (i = 0; list[i].name != NULL; i++) + if (list[i].num == num) + return (list[i].name); + + return (NOT_DEFINED_STR); +} + +/* Compression stuff */ + +#define OV511_QUANTABLESIZE 64 +#define OV518_QUANTABLESIZE 32 + +#define OV511_YQUANTABLE { \ + 0, 1, 1, 2, 2, 3, 3, 4, \ + 1, 1, 1, 2, 2, 3, 4, 4, \ + 1, 1, 2, 2, 3, 4, 4, 4, \ + 2, 2, 2, 3, 4, 4, 4, 4, \ + 2, 2, 3, 4, 4, 5, 5, 5, \ + 3, 3, 4, 4, 5, 5, 5, 5, \ + 3, 4, 4, 4, 5, 5, 5, 5, \ + 4, 4, 4, 4, 5, 5, 5, 5 \ +} + +#define OV511_UVQUANTABLE { \ + 0, 2, 2, 3, 4, 4, 4, 4, \ + 2, 2, 2, 4, 4, 4, 4, 4, \ + 2, 2, 3, 4, 4, 4, 4, 4, \ + 3, 4, 4, 4, 4, 4, 4, 4, \ + 4, 4, 4, 4, 4, 4, 4, 4, \ + 4, 4, 4, 4, 4, 4, 4, 4, \ + 4, 4, 4, 4, 4, 4, 4, 4, \ + 4, 4, 4, 4, 4, 4, 4, 4 \ +} + +#define OV518_YQUANTABLE { \ + 5, 4, 5, 6, 6, 7, 7, 7, \ + 5, 5, 5, 5, 6, 7, 7, 7, \ + 6, 6, 6, 6, 7, 7, 7, 8, \ + 7, 7, 6, 7, 7, 7, 8, 8 \ +} + +#define OV518_UVQUANTABLE { \ + 6, 6, 6, 7, 7, 7, 7, 7, \ + 6, 6, 6, 7, 7, 7, 7, 7, \ + 6, 6, 6, 7, 7, 7, 7, 8, \ + 7, 7, 7, 7, 7, 7, 8, 8 \ +} + +#endif --- linux-2.6.27.orig/ubuntu/misc/wireless/Kconfig +++ linux-2.6.27/ubuntu/misc/wireless/Kconfig @@ -0,0 +1,24 @@ +menu "Wireless Drivers" + +config WIRELESS_ACX + tristate "TI ACX1xx based wireless cards (CardBus/PCI/USB)" + default m + depends on NET && IEEE80211 + +config P80211 + tristate + default n + depends on NET + +config PRISM2_USB + tristate "Prism2 based USB devices" + default m + depends on NET + select P80211 + +config WIRELESS_AT76 + tristate "Wireless devices based on Atmel AT76C503A/505/505A" + default m + depends on NET && IEEE80211 + +endmenu --- linux-2.6.27.orig/ubuntu/misc/wireless/Makefile +++ linux-2.6.27/ubuntu/misc/wireless/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for Ubuntu additional drivers +# + +obj-$(CONFIG_WIRELESS_ACX) += acx/ +obj-$(CONFIG_P80211) += p80211/ +obj-$(CONFIG_PRISM2_USB) += prism2_usb/ +obj-$(CONFIG_WIRELESS_AT76) += at76/ --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/p80211mod.c +++ linux-2.6.27/ubuntu/misc/wireless/p80211/p80211mod.c @@ -0,0 +1,219 @@ +/* src/p80211/p80211mod.c +* +* Module entry and exit for p80211 +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* This file contains the p80211.o entry and exit points defined for linux +* kernel modules. +* +* Notes: +* - all module parameters for p80211.o should be defined here. +* +* -------------------------------------------------------------------- +*/ + +/*================================================================*/ +/* System Includes */ + + +#include + +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,25)) +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +/*================================================================*/ +/* Project Includes */ + +#include +#include +#include +#include +#include +#include +#include + +/*================================================================*/ +/* Local Constants */ + + +/*================================================================*/ +/* Local Macros */ + + +/*================================================================*/ +/* Local Types */ + + +/*================================================================*/ +/* Local Static Definitions */ + +static char *version = "p80211.o: " WLAN_RELEASE; + + +/*----------------------------------------------------------------*/ +/* --Module Parameters */ + +int wlan_watchdog = 5000; +module_param(wlan_watchdog, int, 0644); +MODULE_PARM_DESC(wlan_watchdog, "transmit timeout in milliseconds"); + +int wlan_wext_write = 1; +#if WIRELESS_EXT > 12 +module_param(wlan_wext_write, int, 0644); +MODULE_PARM_DESC(wlan_wext_write, "enable write wireless extensions"); +#endif + +#ifdef WLAN_INCLUDE_DEBUG +int wlan_debug=0; +module_param(wlan_debug, int, 0644); +MODULE_PARM_DESC(wlan_debug, "p80211 debug level"); +#endif + +MODULE_LICENSE("Dual MPL/GPL"); + +/*================================================================*/ +/* Local Function Declarations */ + +int init_module(void); +void cleanup_module(void); + +/*================================================================*/ +/* Function Definitions */ + +/*---------------------------------------------------------------- +* init_module +* +* Module initialization routine, called once at module load time. +* +* Arguments: +* none +* +* Returns: +* 0 - success +* ~0 - failure, module is unloaded. +* +* Side effects: +* TODO: define +* +* Call context: +* process thread (insmod or modprobe) +----------------------------------------------------------------*/ +int init_module(void) +{ + DBFENTER; + +#if 0 + printk(KERN_NOTICE "%s (%s) Loaded\n", version, WLAN_BUILD_DATE); +#endif + + p80211netdev_startup(); +#ifdef CONFIG_HOTPLUG + p80211_run_sbin_hotplug(NULL, WLAN_HOTPLUG_STARTUP); +#endif + + DBFEXIT; + return 0; +} + + +/*---------------------------------------------------------------- +* cleanup_module +* +* Called at module unload time. This is our last chance to +* clean up after ourselves. +* +* Arguments: +* none +* +* Returns: +* nothing +* +* Side effects: +* TODO: define +* +* Call context: +* process thread +* +----------------------------------------------------------------*/ +void cleanup_module(void) +{ + DBFENTER; + +#ifdef CONFIG_HOTPLUG + p80211_run_sbin_hotplug(NULL, WLAN_HOTPLUG_SHUTDOWN); +#endif + p80211netdev_shutdown(); + printk(KERN_NOTICE "%s Unloaded\n", version); + + DBFEXIT; + return; +} + +EXPORT_SYMBOL(p80211netdev_hwremoved); +EXPORT_SYMBOL(register_wlandev); +EXPORT_SYMBOL(p80211netdev_rx); +EXPORT_SYMBOL(unregister_wlandev); +EXPORT_SYMBOL(wlan_setup); +EXPORT_SYMBOL(wlan_unsetup); +EXPORT_SYMBOL(p80211_suspend); +EXPORT_SYMBOL(p80211_resume); + +EXPORT_SYMBOL(p80211skb_free); +EXPORT_SYMBOL(p80211skb_rxmeta_attach); + +EXPORT_SYMBOL(p80211wext_event_associated); + +EXPORT_SYMBOL(wlan_wext_write); +EXPORT_SYMBOL(p80211_allow_ioctls); --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/p80211wext.c +++ linux-2.6.27/ubuntu/misc/wireless/p80211/p80211wext.c @@ -0,0 +1,2174 @@ +/* src/p80211/p80211wext.c +* +* Glue code to make linux-wlan-ng a happy wireless extension camper. +* +* original author: Reyk Floeter +* Completely re-written by Solomon Peachy +* +* Copyright (C) 2002 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +*/ + +/*================================================================*/ +/* System Includes */ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#if WIRELESS_EXT > 12 +#include +#endif +#include +#include +#include +#include + +/*================================================================*/ +/* Project Includes */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int p80211wext_giwrate(netdevice_t *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra); +static int p80211wext_giwessid(netdevice_t *dev, + struct iw_request_info *info, + struct iw_point *data, char *essid); +/* compatibility to wireless extensions */ +#ifdef WIRELESS_EXT + +static UINT8 p80211_mhz_to_channel(UINT16 mhz) +{ + if (mhz >= 5000) { + return ((mhz - 5000) / 5); + } + + if (mhz == 2482) + return 14; + + if (mhz >= 2407) { + return ((mhz - 2407) / 5); + } + + return 0; +} + +static UINT16 p80211_channel_to_mhz(UINT8 ch, int dot11a) +{ + + if (ch == 0) + return 0; + if (ch > 200) + return 0; + + /* 5G */ + + if (dot11a) { + return (5000 + (5 * ch)); + } + + /* 2.4G */ + + if (ch == 14) + return 2484; + + if ((ch < 14) && (ch > 0)) { + return (2407 + (5 * ch)); + } + + return 0; +} + +/* taken from orinoco.c ;-) */ +static const long p80211wext_channel_freq[] = { + 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 +}; +#define NUM_CHANNELS (sizeof(p80211wext_channel_freq) / sizeof(p80211wext_channel_freq[0])) + +/* steal a spare bit to store the shared/opensystems state. should default to open if not set */ +#define HOSTWEP_SHAREDKEY BIT3 + + +/** function declarations =============== */ + +static int qual_as_percent(int snr ) { + if ( snr <= 0 ) + return 0; + if ( snr <= 40 ) + return snr*5/2; + return 100; +} + +static inline int invalid_state(wlandevice_t *wlandev ) { + return wlandev->msdstate != WLAN_MSD_RUNNING; +} + +static int p80211wext_dorequest(wlandevice_t *wlandev, UINT32 did, UINT32 data) +{ + p80211msg_dot11req_mibset_t msg; + p80211item_uint32_t mibitem; + int result; + + DBFENTER; + + msg.msgcode = DIDmsg_dot11req_mibset; + mibitem.did = did; + mibitem.data = data; + memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + DBFEXIT; + return result; +} + +static int p80211wext_autojoin(wlandevice_t *wlandev) +{ + p80211msg_lnxreq_autojoin_t msg; + struct iw_point data; + char ssid[IW_ESSID_MAX_SIZE]; + + int result; + int err = 0; + + DBFENTER; + + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + err = -EBUSY; + goto exit; + } + + /* Get ESSID */ + result = p80211wext_giwessid(wlandev->netdev, NULL, &data, ssid); + + if (result) { + err = -EFAULT; + goto exit; + } + + if ( wlandev->hostwep & HOSTWEP_SHAREDKEY ) + msg.authtype.data = P80211ENUM_authalg_sharedkey; + else + msg.authtype.data = P80211ENUM_authalg_opensystem; + + msg.msgcode = DIDmsg_lnxreq_autojoin; + + /* Trim the last '\0' to fit the SSID format */ + + if (data.length && ssid[data.length-1] == '\0') { + data.length = data.length - 1; + } + + memcpy(msg.ssid.data.data, ssid, data.length); + msg.ssid.data.len = data.length; + + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + if (result) { + err = -EFAULT; + goto exit; + } + +exit: + + DBFEXIT; + return err; + +} + +/* called by /proc/net/wireless */ +struct iw_statistics* p80211wext_get_wireless_stats (netdevice_t *dev) +{ + p80211msg_lnxreq_commsquality_t quality; + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + struct iw_statistics* wstats = &wlandev->wstats; + int retval; + + DBFENTER; + /* Check */ + if ( (wlandev == NULL) || (wlandev->msdstate != WLAN_MSD_RUNNING) ) + return NULL; + + /* XXX Only valid in station mode */ + wstats->status = 0; + + /* build request message */ + quality.msgcode = DIDmsg_lnxreq_commsquality; + quality.dbm.data = P80211ENUM_truth_true; + quality.dbm.status = P80211ENUM_msgitem_status_data_ok; + + /* send message to nsd */ + if ( wlandev->mlmerequest == NULL ) + return NULL; + + retval = wlandev->mlmerequest(wlandev, (p80211msg_t*) &quality); + + wstats->qual.qual = qual_as_percent(quality.link.data); /* overall link quality */ + wstats->qual.level = quality.level.data; /* instant signal level */ + wstats->qual.noise = quality.noise.data; /* instant noise level */ + +#if WIRELESS_EXT > 18 + wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; +#else + wstats->qual.updated = 7; +#endif + wstats->discard.code = wlandev->rx.decrypt_err; + wstats->discard.nwid = 0; + wstats->discard.misc = 0; + +#if WIRELESS_EXT > 11 + wstats->discard.fragment = 0; // incomplete fragments + wstats->discard.retries = 0; // tx retries. + wstats->miss.beacon = 0; +#endif + + DBFEXIT; + + return wstats; +} + +static int p80211wext_giwname(netdevice_t *dev, + struct iw_request_info *info, + char *name, char *extra) +{ + struct iw_param rate; + int result; + int err = 0; + + DBFENTER; + + result = p80211wext_giwrate(dev, NULL, &rate, NULL); + + if (result) { + err = -EFAULT; + goto exit; + } + + switch (rate.value) { + case 1000000: + case 2000000: + strcpy(name, "IEEE 802.11-DS"); + break; + case 5500000: + case 11000000: + strcpy(name, "IEEE 802.11-b"); + break; + } +exit: + DBFEXIT; + return err; +} + +static int p80211wext_giwfreq(netdevice_t *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + p80211item_uint32_t mibitem; + p80211msg_dot11req_mibset_t msg; + int result; + int err = 0; + + DBFENTER; + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + err = -EBUSY; + goto exit; + } + + + msg.msgcode = DIDmsg_dot11req_mibget; + mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel; + memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + if (result) { + err = -EFAULT; + goto exit; + } + + memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); + + if (mibitem.data > NUM_CHANNELS) { + err = -EFAULT; + goto exit; + } + + /* convert into frequency instead of a channel */ + freq->e = 1; + freq->m = p80211_channel_to_mhz(mibitem.data, 0) * 100000; + + exit: + DBFEXIT; + return err; +} + +static int p80211wext_siwfreq(netdevice_t *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + p80211item_uint32_t mibitem; + p80211msg_dot11req_mibset_t msg; + int result; + int err = 0; + + DBFENTER; + + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + err = -EBUSY; + goto exit; + } + + if (!wlan_wext_write) { + err = (-EOPNOTSUPP); + goto exit; + } + + msg.msgcode = DIDmsg_dot11req_mibset; + mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel; + mibitem.status = P80211ENUM_msgitem_status_data_ok; + + if ( (freq->e == 0) && (freq->m <= 1000) ) + mibitem.data = freq->m; + else + mibitem.data = p80211_mhz_to_channel(freq->m); + + memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + if (result) { + err = -EFAULT; + goto exit; + } + + exit: + DBFEXIT; + return err; +} + +#if WIRELESS_EXT > 8 + +static int p80211wext_giwmode(netdevice_t *dev, + struct iw_request_info *info, + __u32 *mode, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + + DBFENTER; + + switch (wlandev->macmode) { + case WLAN_MACMODE_IBSS_STA: + *mode = IW_MODE_ADHOC; + break; + case WLAN_MACMODE_ESS_STA: + *mode = IW_MODE_INFRA; + break; + case WLAN_MACMODE_ESS_AP: + *mode = IW_MODE_MASTER; + break; + default: + /* Not set yet. */ + *mode = IW_MODE_AUTO; + } + + DBFEXIT; + return 0; +} + +static int p80211wext_siwmode(netdevice_t *dev, + struct iw_request_info *info, + __u32 *mode, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + p80211item_uint32_t mibitem; + p80211msg_dot11req_mibset_t msg; + int result; + int err = 0; + + DBFENTER; + + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + err = -EBUSY; + goto exit; + } + if (!wlan_wext_write) { + err = (-EOPNOTSUPP); + goto exit; + } + + if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA && + *mode != IW_MODE_MASTER) { + err = (-EOPNOTSUPP); + goto exit; + } + + /* Operation mode is the same with current mode */ + if (*mode == wlandev->macmode) + goto exit; + + switch (*mode) { + case IW_MODE_ADHOC: + wlandev->macmode = WLAN_MACMODE_IBSS_STA; + break; + case IW_MODE_INFRA: + wlandev->macmode = WLAN_MACMODE_ESS_STA; + break; + case IW_MODE_MASTER: + wlandev->macmode = WLAN_MACMODE_ESS_AP; + break; + default: + /* Not set yet. */ + WLAN_LOG_INFO("Operation mode: %d not support\n", *mode); + return -EOPNOTSUPP; + } + + /* Set Operation mode to the PORT TYPE RID */ + +#warning "get rid of p2mib here" + + msg.msgcode = DIDmsg_dot11req_mibset; + mibitem.did = DIDmib_p2_p2Static_p2CnfPortType; + mibitem.data = (*mode == IW_MODE_ADHOC) ? 0 : 1; + memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + if (result) + err = -EFAULT; + + exit: + DBFEXIT; + + return err; +} + + +static int p80211wext_giwrange(netdevice_t *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct iw_range *range = (struct iw_range *) extra; + int i, val; + + DBFENTER; + + // for backward compatability set size & zero everything we don't understand + data->length = sizeof(*range); + memset(range,0,sizeof(*range)); + +#if WIRELESS_EXT > 9 + range->txpower_capa = IW_TXPOW_DBM; + // XXX what about min/max_pmp, min/max_pmt, etc. +#endif + +#if WIRELESS_EXT > 10 + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 13; + + range->retry_capa = IW_RETRY_LIMIT; + range->retry_flags = IW_RETRY_LIMIT; + range->min_retry = 0; + range->max_retry = 255; +#endif /* WIRELESS_EXT > 10 */ + +#if WIRELESS_EXT > 16 + range->event_capa[0] = (IW_EVENT_CAPA_K_0 | //mode/freq/ssid + IW_EVENT_CAPA_MASK(SIOCGIWAP) | + IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); + range->event_capa[1] = IW_EVENT_CAPA_K_1; //encode + range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVQUAL) | + IW_EVENT_CAPA_MASK(IWEVCUSTOM) ); +#endif + + range->num_channels = NUM_CHANNELS; + + /* XXX need to filter against the regulatory domain &| active set */ + val = 0; + for (i = 0; i < NUM_CHANNELS ; i++) { + range->freq[val].i = i + 1; + range->freq[val].m = p80211wext_channel_freq[i] * 100000; + range->freq[val].e = 1; + val++; + } + + range->num_frequency = val; + + /* Max of /proc/net/wireless */ + range->max_qual.qual = 100; + range->max_qual.level = 0; + range->max_qual.noise = 0; + range->sensitivity = 3; + // XXX these need to be nsd-specific! + + range->min_rts = 0; + range->max_rts = 2347; + range->min_frag = 256; + range->max_frag = 2346; + + range->max_encoding_tokens = NUM_WEPKEYS; + range->num_encoding_sizes = 2; + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + + // XXX what about num_bitrates/throughput? + range->num_bitrates = 0; + + /* estimated max throughput */ + // XXX need to cap it if we're running at ~2Mbps.. + range->throughput = 5500000; + + DBFEXIT; + return 0; +} +#endif + +static int p80211wext_giwap(netdevice_t *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + + DBFENTER; + + memcpy(ap_addr->sa_data, wlandev->bssid, WLAN_BSSID_LEN); + ap_addr->sa_family = ARPHRD_ETHER; + + DBFEXIT; + return 0; +} + +#if WIRELESS_EXT > 8 +static int p80211wext_giwencode(netdevice_t *dev, + struct iw_request_info *info, + struct iw_point *erq, char *key) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + int err = 0; + int i; + + DBFENTER; + + i = (erq->flags & IW_ENCODE_INDEX) - 1; + erq->flags = 0; + + if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) + erq->flags |= IW_ENCODE_ENABLED; + else + erq->flags |= IW_ENCODE_DISABLED; + + if (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED) + erq->flags |= IW_ENCODE_RESTRICTED; + else + erq->flags |= IW_ENCODE_OPEN; + + if (i == -1) + i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK; + + if ((i < 0) || (i >= NUM_WEPKEYS)) { + err = -EINVAL; + goto exit; + } + + erq->flags |= i + 1; + + /* copy the key from the driver cache as the keys are read-only MIBs */ + erq->length = wlandev->wep_keylens[i]; + memcpy(key, wlandev->wep_keys[i], erq->length); + + exit: + DBFEXIT; + return err; +} + +static int p80211wext_siwencode(netdevice_t *dev, + struct iw_request_info *info, + struct iw_point *erq, char *key) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + p80211msg_dot11req_mibset_t msg; + p80211item_pstr32_t pstr; + + int err = 0; + int result = 0; + int i; + + DBFENTER; + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + err = -EBUSY; + goto exit; + } + + if (!wlan_wext_write) { + err = (-EOPNOTSUPP); + goto exit; + } + + /* Check the Key index first. */ + if((i = (erq->flags & IW_ENCODE_INDEX))) { + + if ((i < 1) || (i > NUM_WEPKEYS)) { + err = -EINVAL; + goto exit; + } else { + i--; + } + + /* Set current key number only if no keys are given */ + if (erq->flags & IW_ENCODE_NOKEY) { + result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, i); + + if (result) { + err = -EFAULT; + goto exit; + } + } + + } else { + // Use defaultkey if no Key Index + i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK; + } + + /* Check if there is no key information in the iwconfig request */ + if((erq->flags & IW_ENCODE_NOKEY) == 0 ) { + + /*------------------------------------------------------------ + * If there is WEP Key for setting, check the Key Information + * and then set it to the firmware. + -------------------------------------------------------------*/ + + if (erq->length > 0) { + + /* copy the key from the driver cache as the keys are read-only MIBs */ + wlandev->wep_keylens[i] = erq->length; + memcpy(wlandev->wep_keys[i], key, erq->length); + + /* Prepare data struture for p80211req_dorequest. */ + memcpy(pstr.data.data, key, erq->length); + pstr.data.len = erq->length; + + switch(i) + { + case 0: + pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0; + break; + + case 1: + pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1; + break; + + case 2: + pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2; + break; + + case 3: + pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3; + break; + + default: + err = -EINVAL; + goto exit; + } + + msg.msgcode = DIDmsg_dot11req_mibset; + memcpy(&msg.mibattribute.data, &pstr, sizeof(pstr)); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + if (result) { + err = -EFAULT; + goto exit; + } + } + + } + + /* Check the PrivacyInvoked flag */ + if (erq->flags & IW_ENCODE_DISABLED) { + result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_false); + } else { + result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_true); + } + + if (result) { + err = -EFAULT; + goto exit; + } + + /* The security mode may be open or restricted, and its meaning + depends on the card used. With most cards, in open mode no + authentication is used and the card may also accept non- + encrypted sessions, whereas in restricted mode only encrypted + sessions are accepted and the card will use authentication if + available. + */ + if (erq->flags & IW_ENCODE_RESTRICTED) { + result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_true); + // wlandev->hostwep |= HOSTWEP_SHAREDKEY; + } else if (erq->flags & IW_ENCODE_OPEN) { + result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_false); + // wlandev->hostwep &= ~HOSTWEP_SHAREDKEY; + } + + if (result) { + err = -EFAULT; + goto exit; + } + + exit: + + DBFEXIT; + return err; +} + +static int p80211wext_giwessid(netdevice_t *dev, + struct iw_request_info *info, + struct iw_point *data, char *essid) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + + DBFENTER; + + if (wlandev->ssid.len) { + data->length = wlandev->ssid.len; + data->flags = 1; + memcpy(essid, wlandev->ssid.data, data->length); + essid[data->length] = 0; +#if (WIRELESS_EXT < 21) + data->length++; +#endif + } else { + memset(essid, 0, sizeof(wlandev->ssid.data)); + data->length = 0; + data->flags = 0; + } + + DBFEXIT; + return 0; +} + +static int p80211wext_siwessid(netdevice_t *dev, + struct iw_request_info *info, + struct iw_point *data, char *essid) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + p80211msg_lnxreq_autojoin_t msg; + + int result; + int err = 0; + int length = data->length; + + DBFENTER; + + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + err = -EBUSY; + goto exit; + } + if (!wlan_wext_write) { + err = (-EOPNOTSUPP); + goto exit; + } + + + if ( wlandev->hostwep & HOSTWEP_SHAREDKEY ) + msg.authtype.data = P80211ENUM_authalg_sharedkey; + else + msg.authtype.data = P80211ENUM_authalg_opensystem; + + msg.msgcode = DIDmsg_lnxreq_autojoin; + +#if (WIRELESS_EXT < 21) + if (length) length--; +#endif + + /* Trim the last '\0' to fit the SSID format */ + + if (length && essid[length-1] == '\0') { + length--; + } + + memcpy(msg.ssid.data.data, essid, length); + msg.ssid.data.len = length; + + WLAN_LOG_DEBUG(1,"autojoin_ssid for %s \n",essid); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + WLAN_LOG_DEBUG(1,"autojoin_ssid %d\n",result); + + if (result) { + err = -EFAULT; + goto exit; + } + + exit: + DBFEXIT; + return err; +} + + +static int p80211wext_siwcommit(netdevice_t *dev, + struct iw_request_info *info, + struct iw_point *data, char *essid) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + int err = 0; + + DBFENTER; + + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + err = -EBUSY; + goto exit; + } + if (!wlan_wext_write) { + err = (-EOPNOTSUPP); + goto exit; + } + + /* Auto Join */ + err = p80211wext_autojoin(wlandev); + + exit: + DBFEXIT; + return err; +} + + +static int p80211wext_giwrate(netdevice_t *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + p80211item_uint32_t mibitem; + p80211msg_dot11req_mibset_t msg; + int result; + int err = 0; + + DBFENTER; + + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + err = -EBUSY; + goto exit; + } + msg.msgcode = DIDmsg_dot11req_mibget; + mibitem.did = DIDmib_p2_p2MAC_p2CurrentTxRate; + memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + if (result) { + err = -EFAULT; + goto exit; + } + + memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); + + rrq->fixed = 0; /* can it change? */ + rrq->disabled = 0; + rrq->value = 0; + +#define HFA384x_RATEBIT_1 ((UINT16)1) +#define HFA384x_RATEBIT_2 ((UINT16)2) +#define HFA384x_RATEBIT_5dot5 ((UINT16)4) +#define HFA384x_RATEBIT_11 ((UINT16)8) + + switch (mibitem.data) { + case HFA384x_RATEBIT_1: + rrq->value = 1000000; + break; + case HFA384x_RATEBIT_2: + rrq->value = 2000000; + break; + case HFA384x_RATEBIT_5dot5: + rrq->value = 5500000; + break; + case HFA384x_RATEBIT_11: + rrq->value = 11000000; + break; + default: + err = -EINVAL; + } + exit: + DBFEXIT; + return err; +} + +static int p80211wext_giwrts(netdevice_t *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + p80211item_uint32_t mibitem; + p80211msg_dot11req_mibset_t msg; + int result; + int err = 0; + + DBFENTER; + + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + err = -EBUSY; + goto exit; + } + msg.msgcode = DIDmsg_dot11req_mibget; + mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold; + memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + if (result) { + err = -EFAULT; + goto exit; + } + + memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); + + rts->value = mibitem.data; + rts->disabled = (rts->value == 2347); + rts->fixed = 1; + + exit: + DBFEXIT; + return err; +} + + +static int p80211wext_siwrts(netdevice_t *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + p80211item_uint32_t mibitem; + p80211msg_dot11req_mibset_t msg; + int result; + int err = 0; + + DBFENTER; + + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + err = -EBUSY; + goto exit; + } + if (!wlan_wext_write) { + err = (-EOPNOTSUPP); + goto exit; + } + + msg.msgcode = DIDmsg_dot11req_mibget; + mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold; + if (rts->disabled) + mibitem.data = 2347; + else + mibitem.data = rts->value; + + memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + if (result) { + err = -EFAULT; + goto exit; + } + + exit: + DBFEXIT; + return err; +} + +static int p80211wext_giwfrag(netdevice_t *dev, + struct iw_request_info *info, + struct iw_param *frag, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + p80211item_uint32_t mibitem; + p80211msg_dot11req_mibset_t msg; + int result; + int err = 0; + + DBFENTER; + + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + err = -EBUSY; + goto exit; + } + msg.msgcode = DIDmsg_dot11req_mibget; + mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold; + memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + if (result) { + err = -EFAULT; + goto exit; + } + + memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); + + frag->value = mibitem.data; + frag->disabled = (frag->value == 2346); + frag->fixed = 1; + + exit: + DBFEXIT; + return err; +} + +static int p80211wext_siwfrag(netdevice_t *dev, + struct iw_request_info *info, + struct iw_param *frag, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + p80211item_uint32_t mibitem; + p80211msg_dot11req_mibset_t msg; + int result; + int err = 0; + + DBFENTER; + + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + err = -EBUSY; + goto exit; + } + if (!wlan_wext_write) { + err = (-EOPNOTSUPP); + goto exit; + } + + msg.msgcode = DIDmsg_dot11req_mibset; + mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold; + + if (frag->disabled) + mibitem.data = 2346; + else + mibitem.data = frag->value; + + memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + if (result) { + err = -EFAULT; + goto exit; + } + + exit: + DBFEXIT; + return err; +} + +#endif /* WIRELESS_EXT > 8 */ + +#if WIRELESS_EXT > 10 + +#ifndef IW_RETRY_LONG +#define IW_RETRY_LONG IW_RETRY_MAX +#endif + +#ifndef IW_RETRY_SHORT +#define IW_RETRY_SHORT IW_RETRY_MIN +#endif + +static int p80211wext_giwretry(netdevice_t *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + p80211item_uint32_t mibitem; + p80211msg_dot11req_mibset_t msg; + int result; + int err = 0; + UINT16 shortretry, longretry, lifetime; + + DBFENTER; + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + err = -EBUSY; + goto exit; + } + + msg.msgcode = DIDmsg_dot11req_mibget; + mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit; + + memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + if (result) { + err = -EFAULT; + goto exit; + } + + memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); + + shortretry = mibitem.data; + + mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit; + + memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + if (result) { + err = -EFAULT; + goto exit; + } + + memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); + + longretry = mibitem.data; + + mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime; + + memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + if (result) { + err = -EFAULT; + goto exit; + } + + memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); + + lifetime = mibitem.data; + + rrq->disabled = 0; + + if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { + rrq->flags = IW_RETRY_LIFETIME; + rrq->value = lifetime * 1024; + } else { + if (rrq->flags & IW_RETRY_LONG) { + rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; + rrq->value = longretry; + } else { + rrq->flags = IW_RETRY_LIMIT; + rrq->value = shortretry; + if (shortretry != longretry) + rrq->flags |= IW_RETRY_SHORT; + } + } + + exit: + DBFEXIT; + return err; + +} + +static int p80211wext_siwretry(netdevice_t *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + p80211item_uint32_t mibitem; + p80211msg_dot11req_mibset_t msg; + int result; + int err = 0; + + DBFENTER; + + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + err = -EBUSY; + goto exit; + } + if (!wlan_wext_write) { + err = (-EOPNOTSUPP); + goto exit; + } + + if (rrq->disabled) { + err = -EINVAL; + goto exit; + } + + msg.msgcode = DIDmsg_dot11req_mibset; + + if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { + mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime; + mibitem.data = rrq->value /= 1024; + + memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + if (result) { + err = -EFAULT; + goto exit; + } + } else { + if (rrq->flags & IW_RETRY_LONG) { + mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit; + mibitem.data = rrq->value; + + memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + if (result) { + err = -EFAULT; + goto exit; + } + } + + if (rrq->flags & IW_RETRY_SHORT) { + mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit; + mibitem.data = rrq->value; + + memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + if (result) { + err = -EFAULT; + goto exit; + } + } + } + + exit: + DBFEXIT; + return err; + +} + +#endif /* WIRELESS_EXT > 10 */ + +#if WIRELESS_EXT > 9 +static int p80211wext_siwtxpow(netdevice_t *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + p80211item_uint32_t mibitem; + p80211msg_dot11req_mibset_t msg; + int result; + int err = 0; + + DBFENTER; + + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + err = -EBUSY; + goto exit; + } + if (!wlan_wext_write) { + err = (-EOPNOTSUPP); + goto exit; + } + + msg.msgcode = DIDmsg_dot11req_mibset; + + switch (rrq->value) { + + case 1 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel1; break; + case 2 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel2; break; + case 3 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel3; break; + case 4 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel4; break; + case 5 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel5; break; + case 6 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel6; break; + case 7 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel7; break; + case 8 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel8; break; + default: mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel8; break; + } + + memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + if (result) { + err = -EFAULT; + goto exit; + } + + exit: + DBFEXIT; + return err; +} + +static int p80211wext_giwtxpow(netdevice_t *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + p80211item_uint32_t mibitem; + p80211msg_dot11req_mibset_t msg; + int result; + int err = 0; + + DBFENTER; + + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + err = -EBUSY; + goto exit; + } + msg.msgcode = DIDmsg_dot11req_mibget; + mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel; + + memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + + if (result) { + err = -EFAULT; + goto exit; + } + + memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); + + // XXX handle OFF by setting disabled = 1; + + rrq->flags = 0; // IW_TXPOW_DBM; + rrq->disabled = 0; + rrq->fixed = 0; + rrq->value = mibitem.data; + + exit: + DBFEXIT; + return err; +} +#endif /* WIRELESS_EXT > 9 */ + +static int p80211wext_siwspy(netdevice_t *dev, + struct iw_request_info *info, + struct iw_point *srq, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + struct sockaddr address[IW_MAX_SPY]; + int number = srq->length; + int i; + + DBFENTER; + + /* Copy the data from the input buffer */ + memcpy(address, extra, sizeof(struct sockaddr)*number); + + wlandev->spy_number = 0; + + if (number > 0) { + + /* extract the addresses */ + for (i = 0; i < number; i++) { + + memcpy(wlandev->spy_address[i], address[i].sa_data, ETH_ALEN); + } + + /* reset stats */ + memset(wlandev->spy_stat, 0, sizeof(struct iw_quality) * IW_MAX_SPY); + + /* set number of addresses */ + wlandev->spy_number = number; + } + + DBFEXIT; + return 0; +} + +/* jkriegl: from orinoco, modified */ +static int p80211wext_giwspy(netdevice_t *dev, + struct iw_request_info *info, + struct iw_point *srq, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + + struct sockaddr address[IW_MAX_SPY]; + struct iw_quality spy_stat[IW_MAX_SPY]; + int number; + int i; + + DBFENTER; + + number = wlandev->spy_number; + + if (number > 0) { + + /* populate address and spy struct's */ + for (i = 0; i < number; i++) { + memcpy(address[i].sa_data, wlandev->spy_address[i], ETH_ALEN); + address[i].sa_family = AF_UNIX; + memcpy(&spy_stat[i], &wlandev->spy_stat[i], sizeof(struct iw_quality)); + } + + /* reset update flag */ + for (i=0; i < number; i++) + wlandev->spy_stat[i].updated = 0; + } + + /* push stuff to user space */ + srq->length = number; + memcpy(extra, address, sizeof(struct sockaddr)*number); + memcpy(extra+sizeof(struct sockaddr)*number, spy_stat, sizeof(struct iw_quality)*number); + + DBFEXIT; + return 0; +} + +static int prism2_result2err (int prism2_result) +{ + int err = 0; + + switch (prism2_result) { + case P80211ENUM_resultcode_invalid_parameters: + err = -EINVAL; + break; + case P80211ENUM_resultcode_implementation_failure: + err = -EIO; + break; + case P80211ENUM_resultcode_not_supported: + err = -EOPNOTSUPP; + break; + default: + err = 0; + break; + } + + return err; +} + +#if WIRELESS_EXT > 13 +static int p80211wext_siwscan(netdevice_t *dev, + struct iw_request_info *info, + struct iw_point *srq, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + p80211msg_dot11req_scan_t msg; + int result; + int err = 0; + int i = 0; + + DBFENTER; + + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + err = -EBUSY; + goto exit; + } + if (wlandev->macmode == WLAN_MACMODE_ESS_AP) { + WLAN_LOG_ERROR("Can't scan in AP mode\n"); + err = (-EOPNOTSUPP); + goto exit; + } + + memset(&msg, 0x00, sizeof(p80211msg_dot11req_scan_t)); + msg.msgcode = DIDmsg_dot11req_scan; + msg.bsstype.data = P80211ENUM_bsstype_any; + + memset(&(msg.bssid.data), 0xFF, sizeof (p80211item_pstr6_t)); + msg.bssid.data.len = 6; + + msg.scantype.data = P80211ENUM_scantype_active; + msg.probedelay.data = 0; + + for (i = 1; i <= 14; i++) + msg.channellist.data.data[i-1] = i; + msg.channellist.data.len = 14; + + msg.maxchanneltime.data = 250; + msg.minchanneltime.data = 200; + + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + if (result) + err = prism2_result2err (msg.resultcode.data); + + exit: + DBFEXIT; + return err; +} + + +/* Helper to translate scan into Wireless Extensions scan results. + * Inspired by the prism54 code, which was in turn inspired by the + * airo driver code. + */ +static char * +wext_translate_bss(char *current_ev, char *end_buf, p80211msg_dot11req_scan_results_t *bss, + struct iw_request_info *info) +{ + struct iw_event iwe; /* Temporary buffer */ + + /* The first entry must be the MAC address */ + memcpy(iwe.u.ap_addr.sa_data, bss->bssid.data.data, WLAN_BSSID_LEN); + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + iwe.cmd = SIOCGIWAP; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); + + /* The following entries will be displayed in the same order we give them */ + + /* The ESSID. */ + if (bss->ssid.data.len > 0) { + char essid[IW_ESSID_MAX_SIZE + 1]; + int size; + + size = wlan_min(IW_ESSID_MAX_SIZE, bss->ssid.data.len); + memset(&essid, 0, sizeof (essid)); + memcpy(&essid, bss->ssid.data.data, size); + WLAN_LOG_DEBUG(1, " essid size = %d\n", size); + iwe.u.data.length = size; + iwe.u.data.flags = 1; + iwe.cmd = SIOCGIWESSID; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, &essid[0]); + WLAN_LOG_DEBUG(1, " essid size OK.\n"); + } + + switch (bss->bsstype.data) { + case P80211ENUM_bsstype_infrastructure: + iwe.u.mode = IW_MODE_MASTER; + break; + + case P80211ENUM_bsstype_independent: + iwe.u.mode = IW_MODE_ADHOC; + break; + + default: + iwe.u.mode = 0; + break; + } + iwe.cmd = SIOCGIWMODE; + if (iwe.u.mode) + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN); + + /* Encryption capability */ + if (bss->privacy.data == P80211ENUM_truth_true) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + iwe.cmd = SIOCGIWENCODE; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, NULL); + + /* Add frequency. (short) bss->channel is the frequency in MHz */ + iwe.u.freq.m = bss->dschannel.data; + iwe.u.freq.e = 0; + iwe.cmd = SIOCGIWFREQ; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); + + /* Add quality statistics */ + iwe.u.qual.level = bss->signal.data; + iwe.u.qual.noise = bss->noise.data; + /* do a simple SNR for quality */ + iwe.u.qual.qual = qual_as_percent(bss->signal.data - bss->noise.data); + iwe.cmd = IWEVQUAL; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); + + return current_ev; +} + + +static int p80211wext_giwscan(netdevice_t *dev, + struct iw_request_info *info, + struct iw_point *srq, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + p80211msg_dot11req_scan_results_t msg; + int result = 0; + int err = 0; + int i = 0; + int scan_good = 0; + char *current_ev = extra; + + DBFENTER; + + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + err = -EBUSY; + goto exit; + } + + /* Since wireless tools doesn't really have a way of passing how + * many scan results results there were back here, keep grabbing them + * until we fail. + */ + do { + memset(&msg, 0, sizeof(msg)); + msg.msgcode = DIDmsg_dot11req_scan_results; + msg.bssindex.data = i; + + result = p80211req_dorequest(wlandev, (UINT8*)&msg); + if ((result != 0) || + (msg.resultcode.data != P80211ENUM_resultcode_success)) { + break; + } + + current_ev = wext_translate_bss(current_ev, extra + IW_SCAN_MAX_DATA, &msg, info); + scan_good = 1; + i++; + } while (i < IW_MAX_AP); + + srq->length = (current_ev - extra); + srq->flags = 0; /* todo */ + + if (result && !scan_good) + err = prism2_result2err (msg.resultcode.data); + exit: + DBFEXIT; + return err; +} +#endif + +/*****************************************************/ +//extra wireless extensions stuff to support NetworkManager (I hope) + +#if WIRELESS_EXT > 17 +/* SIOCSIWENCODEEXT */ +static int p80211wext_set_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + p80211msg_dot11req_mibset_t msg; + p80211item_pstr32_t *pstr; + + int result = 0; + struct iw_point *encoding = &wrqu->encoding; + int idx = encoding->flags & IW_ENCODE_INDEX; + + DBFENTER; + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + result = -EBUSY; + goto exit; + } + + WLAN_LOG_DEBUG(1,"set_encode_ext flags[%d] alg[%d] keylen[%d]\n",ext->ext_flags,(int)ext->alg,(int)ext->key_len); + + + if ( ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY ) { + // set default key ? I'm not sure if this the the correct thing to do here + + if ( idx ) { + if (idx < 1 || idx > NUM_WEPKEYS) { + return -EINVAL; + } else + idx--; + } + WLAN_LOG_DEBUG(1,"setting default key (%d)\n",idx); + result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, idx); + if ( result ) + return -EFAULT; + } + + + if ( ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY ) { + if ( ! ext->alg & IW_ENCODE_ALG_WEP) { + WLAN_LOG_DEBUG(1,"asked to set a non wep key :("); + return -EINVAL; + } + if (idx) { + if (idx <1 || idx > NUM_WEPKEYS) + return -EINVAL; + else + idx--; + } + WLAN_LOG_DEBUG(1,"Set WEP key (%d)\n",idx); + wlandev->wep_keylens[idx] = ext->key_len; + memcpy(wlandev->wep_keys[idx], ext->key, ext->key_len); + + memset( &msg,0,sizeof(msg)); + pstr = (p80211item_pstr32_t*)&msg.mibattribute.data; + memcpy(pstr->data.data, ext->key,ext->key_len); + pstr->data.len = ext->key_len; + switch (idx) { + case 0: + pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0; + break; + case 1: + pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1; + break; + case 2: + pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2; + break; + case 3: + pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3; + break; + default: + break; + } + msg.msgcode = DIDmsg_dot11req_mibset; + result = p80211req_dorequest(wlandev,(UINT8*)&msg); + WLAN_LOG_DEBUG(1,"result (%d)\n",result); + } + exit: + DBFEXIT; + return result; +} + +/* SIOCGIWENCODEEXT */ +static int p80211wext_get_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) + +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + + struct iw_point *encoding = &wrqu->encoding; + int result = 0; + int max_len; + int idx; + + DBFENTER; + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + result = -EBUSY; + goto exit; + } + + + WLAN_LOG_DEBUG(1,"get_encode_ext flags[%d] alg[%d] keylen[%d]\n",ext->ext_flags,(int)ext->alg,(int)ext->key_len); + + + max_len = encoding->length - sizeof(*ext); + if ( max_len <= 0) { + WLAN_LOG_DEBUG(1,"get_encodeext max_len [%d] invalid\n",max_len); + result = -EINVAL; + goto exit; + } + idx = encoding->flags & IW_ENCODE_INDEX; + + WLAN_LOG_DEBUG(1,"get_encode_ext index [%d]\n",idx); + + if (idx) { + if (idx < 1 || idx > NUM_WEPKEYS ) { + WLAN_LOG_DEBUG(1,"get_encode_ext invalid key index [%d]\n",idx); + result = -EINVAL; + goto exit; + } + idx--; + } else { + /* default key ? not sure what to do */ + /* will just use key[0] for now ! FIX ME */ + } + + encoding->flags = idx + 1; + memset(ext,0,sizeof(*ext)); + + ext->alg = IW_ENCODE_ALG_WEP; + ext->key_len = wlandev->wep_keylens[idx]; + memcpy( ext->key, wlandev->wep_keys[idx] , ext->key_len ); + + encoding->flags |= IW_ENCODE_ENABLED; +exit: + DBFEXIT; + + return result; +} + + +/* SIOCSIWAUTH */ +static int p80211_wext_set_iwauth (struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + struct iw_param *param = &wrqu->param; + int result =0; + + DBFENTER; + if ( invalid_state(wlandev) ) { + WLAN_LOG_DEBUG(1,"called from invalid state [%d]\n",wlandev->msdstate); + result = -EBUSY; + goto exit; + } + + + WLAN_LOG_DEBUG(1,"set_iwauth flags[%d]\n",(int)param->flags & IW_AUTH_INDEX ); + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_DROP_UNENCRYPTED: + WLAN_LOG_DEBUG(1,"drop_unencrypted %d\n",param->value); + if (param->value) + result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_true); + else + result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_false); + break; + + case IW_AUTH_PRIVACY_INVOKED: + WLAN_LOG_DEBUG(1,"privacy invoked %d\n",param->value); + if ( param->value) + result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_true); + else + result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_false); + + break; + + case IW_AUTH_80211_AUTH_ALG: + if ( param->value & IW_AUTH_ALG_OPEN_SYSTEM ) { + WLAN_LOG_DEBUG(1,"set open_system\n"); + wlandev->hostwep &= ~HOSTWEP_SHAREDKEY; + } else if ( param->value & IW_AUTH_ALG_SHARED_KEY) { + WLAN_LOG_DEBUG(1,"set shared key\n"); + wlandev->hostwep |= HOSTWEP_SHAREDKEY; + } else { + /* don't know what to do know :( */ + WLAN_LOG_DEBUG(1,"unknown AUTH_ALG (%d)\n",param->value); + result = -EINVAL; + } + break; + + default: + break; + } + + exit: + DBFEXIT; + return result; +} + +/* SIOCSIWAUTH */ +static int p80211_wext_get_iwauth (struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + struct iw_param *param = &wrqu->param; + int result =0; + + DBFENTER; + WLAN_LOG_DEBUG(1,"get_iwauth flags[%d]\n",(int)param->flags & IW_AUTH_INDEX ); + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_DROP_UNENCRYPTED: + param->value = wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED?1:0; + break; + + case IW_AUTH_PRIVACY_INVOKED: + param->value = wlandev->hostwep & HOSTWEP_PRIVACYINVOKED?1:0; + break; + + case IW_AUTH_80211_AUTH_ALG: + param->value = wlandev->hostwep & HOSTWEP_SHAREDKEY?IW_AUTH_ALG_SHARED_KEY:IW_AUTH_ALG_OPEN_SYSTEM; + break; + + + default: + break; + } + + DBFEXIT; + + return result; +} + + +#endif + + + + + + +/*****************************************************/ + + + + + +/* +typedef int (*iw_handler)(netdevice_t *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +*/ + +#if WIRELESS_EXT > 12 +static iw_handler p80211wext_handlers[] = { + (iw_handler) p80211wext_siwcommit, /* SIOCSIWCOMMIT */ + (iw_handler) p80211wext_giwname, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) p80211wext_siwfreq, /* SIOCSIWFREQ */ + (iw_handler) p80211wext_giwfreq, /* SIOCGIWFREQ */ + (iw_handler) p80211wext_siwmode, /* SIOCSIWMODE */ + (iw_handler) p80211wext_giwmode, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL, /* not used */ /* SIOCSIWRANGE */ + (iw_handler) p80211wext_giwrange, /* SIOCGIWRANGE */ + (iw_handler) NULL, /* not used */ /* SIOCSIWPRIV */ + (iw_handler) NULL, /* kernel code */ /* SIOCGIWPRIV */ + (iw_handler) NULL, /* not used */ /* SIOCSIWSTATS */ + (iw_handler) NULL, /* kernel code */ /* SIOCGIWSTATS */ + (iw_handler) p80211wext_siwspy, /* SIOCSIWSPY */ + (iw_handler) p80211wext_giwspy, /* SIOCGIWSPY */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCSIWAP */ + (iw_handler) p80211wext_giwap, /* SIOCGIWAP */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCGIWAPLIST */ +#if WIRELESS_EXT > 13 + (iw_handler) p80211wext_siwscan, /* SIOCSIWSCAN */ + (iw_handler) p80211wext_giwscan, /* SIOCGIWSCAN */ +#else /* WIRELESS_EXT > 13 */ + (iw_handler) NULL, /* null */ /* SIOCSIWSCAN */ + (iw_handler) NULL, /* null */ /* SIOCGIWSCAN */ +#endif /* WIRELESS_EXT > 13 */ + (iw_handler) p80211wext_siwessid, /* SIOCSIWESSID */ + (iw_handler) p80211wext_giwessid, /* SIOCGIWESSID */ + (iw_handler) NULL, /* SIOCSIWNICKN */ + (iw_handler) p80211wext_giwessid, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCSIWRATE */ + (iw_handler) p80211wext_giwrate, /* SIOCGIWRATE */ + (iw_handler) p80211wext_siwrts, /* SIOCSIWRTS */ + (iw_handler) p80211wext_giwrts, /* SIOCGIWRTS */ + (iw_handler) p80211wext_siwfrag, /* SIOCSIWFRAG */ + (iw_handler) p80211wext_giwfrag, /* SIOCGIWFRAG */ + (iw_handler) p80211wext_siwtxpow, /* SIOCSIWTXPOW */ + (iw_handler) p80211wext_giwtxpow, /* SIOCGIWTXPOW */ + (iw_handler) p80211wext_siwretry, /* SIOCSIWRETRY */ + (iw_handler) p80211wext_giwretry, /* SIOCGIWRETRY */ + (iw_handler) p80211wext_siwencode, /* SIOCSIWENCODE */ + (iw_handler) p80211wext_giwencode, /* SIOCGIWENCODE */ + (iw_handler) NULL, /* SIOCSIWPOWER */ + (iw_handler) NULL, /* SIOCGIWPOWER */ +#if WIRELESS_EXT > 17 +/* WPA operations */ + + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCSIWGENIE set generic IE */ + (iw_handler) NULL, /* SIOCGIWGENIE get generic IE */ + (iw_handler) p80211_wext_set_iwauth, /* SIOCSIWAUTH set authentication mode params */ + (iw_handler) p80211_wext_get_iwauth, /* SIOCGIWAUTH get authentication mode params */ + + (iw_handler) p80211wext_set_encodeext, /* SIOCSIWENCODEEXT set encoding token & mode */ + (iw_handler) p80211wext_get_encodeext, /* SIOCGIWENCODEEXT get encoding token & mode */ + (iw_handler) NULL, /* SIOCSIWPMKSA PMKSA cache operation */ +#endif +}; + +struct iw_handler_def p80211wext_handler_def = { + .num_standard = sizeof(p80211wext_handlers) / sizeof(iw_handler), + .num_private = 0, + .num_private_args = 0, + .standard = p80211wext_handlers, + .private = NULL, + .private_args = NULL, +#if WIRELESS_EXT > 16 + .get_wireless_stats = p80211wext_get_wireless_stats +#endif +}; + +#endif + +/* wireless extensions' ioctls */ +int p80211wext_support_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + +#if WIRELESS_EXT < 13 + struct iwreq *iwr = (struct iwreq*)ifr; +#endif + + p80211item_uint32_t mibitem; + int err = 0; + + DBFENTER; + + mibitem.status = P80211ENUM_msgitem_status_data_ok; + + if ( wlandev->msdstate != WLAN_MSD_RUNNING ) { + err = -ENODEV; + goto exit; + } + + WLAN_LOG_DEBUG(1, "Received wireless extension ioctl #%d.\n", cmd); + + switch (cmd) { +#if WIRELESS_EXT < 13 + case SIOCSIWNAME: /* unused */ + err = (-EOPNOTSUPP); + break; + case SIOCGIWNAME: /* get name == wireless protocol */ + err = p80211wext_giwname(dev, NULL, (char *) &iwr->u, NULL); + break; + case SIOCSIWNWID: + case SIOCGIWNWID: + err = (-EOPNOTSUPP); + break; + case SIOCSIWFREQ: /* set channel */ + err = p80211wext_siwfreq(dev, NULL, &(iwr->u.freq), NULL); + break; + case SIOCGIWFREQ: /* get channel */ + err = p80211wext_giwfreq(dev, NULL, &(iwr->u.freq), NULL); + break; + case SIOCSIWRANGE: + case SIOCSIWPRIV: + case SIOCSIWAP: /* set access point MAC addresses (BSSID) */ + err = (-EOPNOTSUPP); + break; + + case SIOCGIWAP: /* get access point MAC addresses (BSSID) */ + err = p80211wext_giwap(dev, NULL, &(iwr->u.ap_addr), NULL); + break; + +#if WIRELESS_EXT > 8 + case SIOCSIWMODE: /* set operation mode */ + case SIOCSIWESSID: /* set SSID (network name) */ + case SIOCSIWRATE: /* set default bit rate (bps) */ + err = (-EOPNOTSUPP); + break; + + case SIOCGIWMODE: /* get operation mode */ + err = p80211wext_giwmode(dev, NULL, &iwr->u.mode, NULL); + + break; + case SIOCGIWNICKN: /* get node name/nickname */ + case SIOCGIWESSID: /* get SSID */ + if(iwr->u.essid.pointer) { + char ssid[IW_ESSID_MAX_SIZE+1]; + memset(ssid, 0, sizeof(ssid)); + + err = p80211wext_giwessid(dev, NULL, &iwr->u.essid, ssid); + if(copy_to_user(iwr->u.essid.pointer, ssid, sizeof(ssid))) + err = (-EFAULT); + } + break; + case SIOCGIWRATE: + err = p80211wext_giwrate(dev, NULL, &iwr->u.bitrate, NULL); + break; + case SIOCGIWRTS: + err = p80211wext_giwrts(dev, NULL, &iwr->u.rts, NULL); + break; + case SIOCGIWFRAG: + err = p80211wext_giwfrag(dev, NULL, &iwr->u.rts, NULL); + break; + case SIOCGIWENCODE: + if (!capable(CAP_NET_ADMIN)) + err = -EPERM; + else if (iwr->u.encoding.pointer) { + char keybuf[MAX_KEYLEN]; + err = p80211wext_giwencode(dev, NULL, + &iwr->u.encoding, keybuf); + if (copy_to_user(iwr->u.encoding.pointer, keybuf, + iwr->u.encoding.length)) + err = -EFAULT; + } + break; + case SIOCGIWAPLIST: + case SIOCSIWRTS: + case SIOCSIWFRAG: + case SIOCSIWSENS: + case SIOCGIWSENS: + case SIOCSIWNICKN: /* set node name/nickname */ + case SIOCSIWENCODE: /* set encoding token & mode */ + case SIOCSIWSPY: + case SIOCGIWSPY: + case SIOCSIWPOWER: + case SIOCGIWPOWER: + case SIOCGIWPRIV: + err = (-EOPNOTSUPP); + break; + case SIOCGIWRANGE: + if(iwr->u.data.pointer != NULL) { + struct iw_range range; + err = p80211wext_giwrange(dev, NULL, &iwr->u.data, + (char *) &range); + /* Push that up to the caller */ + if (copy_to_user(iwr->u.data.pointer, &range, sizeof(range))) + err = -EFAULT; + } + break; +#endif /* WIRELESS_EXT > 8 */ +#if WIRELESS_EXT > 9 + case SIOCSIWTXPOW: + err = (-EOPNOTSUPP); + break; + case SIOCGIWTXPOW: + err = p80211wext_giwtxpow(dev, NULL, &iwr->u.txpower, NULL); + break; +#endif /* WIRELESS_EXT > 9 */ +#if WIRELESS_EXT > 10 + case SIOCSIWRETRY: + err = (-EOPNOTSUPP); + break; + case SIOCGIWRETRY: + err = p80211wext_giwretry(dev, NULL, &iwr->u.retry, NULL); + break; +#endif /* WIRELESS_EXT > 10 */ + +#endif /* WIRELESS_EXT <= 12 */ + + default: + err = (-EOPNOTSUPP); + break; + } + + exit: + DBFEXIT; + return (err); +} + +int p80211wext_event_associated(wlandevice_t *wlandev, int assoc) +{ + union iwreq_data data; + + DBFENTER; + +#if WIRELESS_EXT > 13 + /* Send the association state first */ + data.ap_addr.sa_family = ARPHRD_ETHER; + if (assoc) { + memcpy(data.ap_addr.sa_data, wlandev->bssid, WLAN_ADDR_LEN); + } else { + memset(data.ap_addr.sa_data, 0, WLAN_ADDR_LEN); + } + + if (wlan_wext_write) + wireless_send_event(wlandev->netdev, SIOCGIWAP, &data, NULL); + + if (!assoc) goto done; + + // XXX send association data, like IEs, etc etc. +#endif + done: + DBFEXIT; + return 0; +} + + +#endif /* compatibility to wireless extensions */ + + + + --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/p80211netdev.c +++ linux-2.6.27/ubuntu/misc/wireless/p80211/p80211netdev.c @@ -0,0 +1,1558 @@ +/* src/p80211/p80211knetdev.c +* +* Linux Kernel net device interface +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* The functions required for a Linux network device are defined here. +* +* -------------------------------------------------------------------- +*/ + + +/*================================================================*/ +/* System Includes */ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef SIOCETHTOOL +#include +#endif + +#if WIRELESS_EXT > 12 +#include +#endif + +/*================================================================*/ +/* Project Includes */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*================================================================*/ +/* Local Constants */ + +/*================================================================*/ +/* Local Macros */ + + +/*================================================================*/ +/* Local Types */ + +/*================================================================*/ +/* Local Static Definitions */ + +#define __NO_VERSION__ /* prevent the static definition */ + +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *proc_p80211; +#endif + +/*================================================================*/ +/* Local Function Declarations */ + +/* Support functions */ +static void p80211netdev_rx_bh(unsigned long arg); + +/* netdevice method functions */ +static int p80211knetdev_init( netdevice_t *netdev); +static struct net_device_stats* p80211knetdev_get_stats(netdevice_t *netdev); +static int p80211knetdev_open( netdevice_t *netdev); +static int p80211knetdev_stop( netdevice_t *netdev ); +static int p80211knetdev_hard_start_xmit( struct sk_buff *skb, netdevice_t *netdev); +static void p80211knetdev_set_multicast_list(netdevice_t *dev); +static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd); +static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr); +static void p80211knetdev_tx_timeout(netdevice_t *netdev); +static int p80211_rx_typedrop( wlandevice_t *wlandev, UINT16 fc); + +#ifdef CONFIG_PROC_FS +static int +p80211netdev_proc_read( + char *page, + char **start, + off_t offset, + int count, + int *eof, + void *data); +#endif + +/*================================================================*/ +/* Function Definitions */ + +/*---------------------------------------------------------------- +* p80211knetdev_startup +* +* Initialize the wlandevice/netdevice part of 802.11 services at +* load time. +* +* Arguments: +* none +* +* Returns: +* nothing +----------------------------------------------------------------*/ +void p80211netdev_startup(void) +{ + DBFENTER; + +#ifdef CONFIG_PROC_FS + if (PROC_NET != NULL) { + proc_p80211 = create_proc_entry( + "p80211", + (S_IFDIR|S_IRUGO|S_IXUGO), + PROC_NET); + } +#endif + DBFEXIT; + return; +} + +/*---------------------------------------------------------------- +* p80211knetdev_shutdown +* +* Shutdown the wlandevice/netdevice part of 802.11 services at +* unload time. +* +* Arguments: +* none +* +* Returns: +* nothing +----------------------------------------------------------------*/ +void +p80211netdev_shutdown(void) +{ + DBFENTER; +#ifdef CONFIG_PROC_FS + if (proc_p80211 != NULL) { + remove_proc_entry("p80211", PROC_NET); + } +#endif + DBFEXIT; +} + +/*---------------------------------------------------------------- +* p80211knetdev_init +* +* Init method for a Linux netdevice. Called in response to +* register_netdev. +* +* Arguments: +* none +* +* Returns: +* nothing +----------------------------------------------------------------*/ +static int p80211knetdev_init( netdevice_t *netdev) +{ + DBFENTER; + /* Called in response to register_netdev */ + /* This is usually the probe function, but the probe has */ + /* already been done by the MSD and the create_kdev */ + /* function. All we do here is return success */ + DBFEXIT; + return 0; +} + + +/*---------------------------------------------------------------- +* p80211knetdev_get_stats +* +* Statistics retrieval for linux netdevices. Here we're reporting +* the Linux i/f level statistics. Hence, for the primary numbers, +* we don't want to report the numbers from the MIB. Eventually, +* it might be useful to collect some of the error counters though. +* +* Arguments: +* netdev Linux netdevice +* +* Returns: +* the address of the statistics structure +----------------------------------------------------------------*/ +static struct net_device_stats* +p80211knetdev_get_stats(netdevice_t *netdev) +{ + wlandevice_t *wlandev = (wlandevice_t*)netdev->priv; + DBFENTER; + + /* TODO: review the MIB stats for items that correspond to + linux stats */ + + DBFEXIT; + return &(wlandev->linux_stats); +} + + +/*---------------------------------------------------------------- +* p80211knetdev_open +* +* Linux netdevice open method. Following a successful call here, +* the device is supposed to be ready for tx and rx. In our +* situation that may not be entirely true due to the state of the +* MAC below. +* +* Arguments: +* netdev Linux network device structure +* +* Returns: +* zero on success, non-zero otherwise +----------------------------------------------------------------*/ +static int p80211knetdev_open( netdevice_t *netdev ) +{ + int result = 0; /* success */ + wlandevice_t *wlandev = (wlandevice_t*)(netdev->priv); + + DBFENTER; + + /* Check to make sure the MSD is running */ + if ( wlandev->msdstate != WLAN_MSD_RUNNING ) { + return -ENODEV; + } + + /* Tell the MSD to open */ + if ( wlandev->open != NULL) { + result = wlandev->open(wlandev); + if ( result == 0 ) { +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43) ) + netdev->interrupt = 0; +#endif + p80211netdev_start_queue(wlandev); + wlandev->state = WLAN_DEVICE_OPEN; + } + } else { + result = -EAGAIN; + } + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* p80211knetdev_stop +* +* Linux netdevice stop (close) method. Following this call, +* no frames should go up or down through this interface. +* +* Arguments: +* netdev Linux network device structure +* +* Returns: +* zero on success, non-zero otherwise +----------------------------------------------------------------*/ +static int p80211knetdev_stop( netdevice_t *netdev ) +{ + int result = 0; + wlandevice_t *wlandev = (wlandevice_t*)(netdev->priv); + + DBFENTER; + + if ( wlandev->close != NULL ) { + result = wlandev->close(wlandev); + } + + p80211netdev_stop_queue(wlandev); + wlandev->state = WLAN_DEVICE_CLOSED; + + DBFEXIT; + return result; +} + +/*---------------------------------------------------------------- +* p80211netdev_rx +* +* Frame receive function called by the mac specific driver. +* +* Arguments: +* wlandev WLAN network device structure +* skb skbuff containing a full 802.11 frame. +* Returns: +* nothing +* Side effects: +* +----------------------------------------------------------------*/ +void +p80211netdev_rx(wlandevice_t *wlandev, struct sk_buff *skb ) +{ + DBFENTER; + + /* Enqueue for post-irq processing */ + skb_queue_tail(&wlandev->nsd_rxq, skb); + + tasklet_schedule(&wlandev->rx_bh); + + DBFEXIT; + return; +} + +/*---------------------------------------------------------------- +* p80211netdev_rx_bh +* +* Deferred processing of all received frames. +* +* Arguments: +* wlandev WLAN network device structure +* skb skbuff containing a full 802.11 frame. +* Returns: +* nothing +* Side effects: +* +----------------------------------------------------------------*/ +static void p80211netdev_rx_bh(unsigned long arg) +{ + wlandevice_t *wlandev = (wlandevice_t *) arg; + struct sk_buff *skb = NULL; + netdevice_t *dev = wlandev->netdev; + p80211_hdr_a3_t *hdr; + UINT16 fc; + + DBFENTER; + + /* Let's empty our our queue */ + while ( (skb = skb_dequeue(&wlandev->nsd_rxq)) ) { + if (wlandev->state == WLAN_DEVICE_OPEN) { + + if (dev->type != ARPHRD_ETHER) { + /* RAW frame; we shouldn't convert it */ + // XXX Append the Prism Header here instead. + + /* set up various data fields */ + skb->dev = dev; + skb_reset_mac_header(skb); + + skb->ip_summed = CHECKSUM_NONE; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_80211_RAW); + dev->last_rx = jiffies; + + wlandev->linux_stats.rx_packets++; + wlandev->linux_stats.rx_bytes += skb->len; + netif_rx_ni(skb); + continue; + } else { + hdr = (p80211_hdr_a3_t *)skb->data; + fc = ieee2host16(hdr->fc); + if (p80211_rx_typedrop(wlandev, fc)) { + dev_kfree_skb(skb); + continue; + } + + /* perform mcast filtering */ + if (wlandev->netdev->flags & IFF_ALLMULTI) { + /* allow my local address through */ + if (memcmp(hdr->a1, wlandev->netdev->dev_addr, WLAN_ADDR_LEN) != 0) { + /* but reject anything else that isn't multicast */ + if (!(hdr->a1[0] & 0x01)) { + dev_kfree_skb(skb); + continue; + } + } + } + + if ( skb_p80211_to_ether(wlandev, wlandev->ethconv, skb) == 0 ) { + skb->dev->last_rx = jiffies; + wlandev->linux_stats.rx_packets++; + wlandev->linux_stats.rx_bytes += skb->len; + netif_rx_ni(skb); + continue; + } + WLAN_LOG_DEBUG(1, "p80211_to_ether failed.\n"); + } + } + dev_kfree_skb(skb); + } + + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* p80211knetdev_hard_start_xmit +* +* Linux netdevice method for transmitting a frame. +* +* Arguments: +* skb Linux sk_buff containing the frame. +* netdev Linux netdevice. +* +* Side effects: +* If the lower layers report that buffers are full. netdev->tbusy +* will be set to prevent higher layers from sending more traffic. +* +* Note: If this function returns non-zero, higher layers retain +* ownership of the skb. +* +* Returns: +* zero on success, non-zero on failure. +----------------------------------------------------------------*/ +static int p80211knetdev_hard_start_xmit( struct sk_buff *skb, netdevice_t *netdev) +{ + int result = 0; + int txresult = -1; + wlandevice_t *wlandev = (wlandevice_t*)netdev->priv; + p80211_hdr_t p80211_hdr; + p80211_metawep_t p80211_wep; + + DBFENTER; + + if (skb == NULL) { + return 0; + } + + if (wlandev->state != WLAN_DEVICE_OPEN) { + result = 1; + goto failed; + } + + memset(&p80211_hdr, 0, sizeof(p80211_hdr_t)); + memset(&p80211_wep, 0, sizeof(p80211_metawep_t)); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,38) ) + if ( test_and_set_bit(0, (void*)&(netdev->tbusy)) != 0 ) { + /* We've been called w/ tbusy set, has the tx */ + /* path stalled? */ + WLAN_LOG_DEBUG(1, "called when tbusy set\n"); + result = 1; + goto failed; + } +#else + if ( netif_queue_stopped(netdev) ) { + WLAN_LOG_DEBUG(1, "called when queue stopped.\n"); + result = 1; + goto failed; + } + + netif_stop_queue(netdev); + + /* No timeout handling here, 2.3.38+ kernels call the + * timeout function directly. + * TODO: Add timeout handling. + */ +#endif + + /* Check to see that a valid mode is set */ + switch( wlandev->macmode ) { + case WLAN_MACMODE_IBSS_STA: + case WLAN_MACMODE_ESS_STA: + case WLAN_MACMODE_ESS_AP: + break; + default: + /* Mode isn't set yet, just drop the frame + * and return success . + * TODO: we need a saner way to handle this + */ + if(skb->protocol != ETH_P_80211_RAW) { + p80211netdev_start_queue(wlandev); + WLAN_LOG_NOTICE( + "Tx attempt prior to association, frame dropped.\n"); + wlandev->linux_stats.tx_dropped++; + result = 0; + goto failed; + } + break; + } + + /* Check for raw transmits */ + if(skb->protocol == ETH_P_80211_RAW) { + if (!capable(CAP_NET_ADMIN)) { + result = 1; + goto failed; + } + /* move the header over */ + memcpy(&p80211_hdr, skb->data, sizeof(p80211_hdr_t)); + skb_pull(skb, sizeof(p80211_hdr_t)); + } else { + if ( skb_ether_to_p80211(wlandev, wlandev->ethconv, skb, &p80211_hdr, &p80211_wep) != 0 ) { + /* convert failed */ + WLAN_LOG_DEBUG(1, "ether_to_80211(%d) failed.\n", + wlandev->ethconv); + result = 1; + goto failed; + } + } + if ( wlandev->txframe == NULL ) { + result = 1; + goto failed; + } + + netdev->trans_start = jiffies; + + wlandev->linux_stats.tx_packets++; + /* count only the packet payload */ + wlandev->linux_stats.tx_bytes += skb->len; + + txresult = wlandev->txframe(wlandev, skb, &p80211_hdr, &p80211_wep); + + if ( txresult == 0) { + /* success and more buf */ + /* avail, re: hw_txdata */ + p80211netdev_wake_queue(wlandev); + result = 0; + } else if ( txresult == 1 ) { + /* success, no more avail */ + WLAN_LOG_DEBUG(3, "txframe success, no more bufs\n"); + /* netdev->tbusy = 1; don't set here, irqhdlr */ + /* may have already cleared it */ + result = 0; + } else if ( txresult == 2 ) { + /* alloc failure, drop frame */ + WLAN_LOG_DEBUG(3, "txframe returned alloc_fail\n"); + result = 1; + } else { + /* buffer full or queue busy, drop frame. */ + WLAN_LOG_DEBUG(3, "txframe returned full or busy\n"); + result = 1; + } + + failed: + /* Free up the WEP buffer if it's not the same as the skb */ + if ((p80211_wep.data) && (p80211_wep.data != skb->data)) + kfree(p80211_wep.data); + + /* we always free the skb here, never in a lower level. */ + if (!result) + dev_kfree_skb(skb); + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* p80211knetdev_set_multicast_list +* +* Called from higher lavers whenever there's a need to set/clear +* promiscuous mode or rewrite the multicast list. +* +* Arguments: +* none +* +* Returns: +* nothing +----------------------------------------------------------------*/ +static void p80211knetdev_set_multicast_list(netdevice_t *dev) +{ + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + + DBFENTER; + + /* TODO: real multicast support as well */ + + if (wlandev->set_multicast_list) + wlandev->set_multicast_list(wlandev, dev); + + DBFEXIT; +} + +#ifdef SIOCETHTOOL + +static int p80211netdev_ethtool(wlandevice_t *wlandev, void __user *useraddr) +{ + UINT32 ethcmd; + struct ethtool_drvinfo info; + struct ethtool_value edata; + + memset(&info, 0, sizeof(info)); + memset(&edata, 0, sizeof(edata)); + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: + info.cmd = ethcmd; + snprintf(info.driver, sizeof(info.driver), "p80211_%s", + wlandev->nsdname); + snprintf(info.version, sizeof(info.version), "%s", + WLAN_RELEASE); + + // info.fw_version + // info.bus_info + + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; +#ifdef ETHTOOL_GLINK + case ETHTOOL_GLINK: + edata.cmd = ethcmd; + + if (wlandev->linkstatus && + (wlandev->macmode != WLAN_MACMODE_NONE)) { + edata.data = 1; + } else { + edata.data = 0; + } + + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } +#endif + + return -EOPNOTSUPP; +} + +#endif + +/*---------------------------------------------------------------- +* p80211knetdev_do_ioctl +* +* Handle an ioctl call on one of our devices. Everything Linux +* ioctl specific is done here. Then we pass the contents of the +* ifr->data to the request message handler. +* +* Arguments: +* dev Linux kernel netdevice +* ifr Our private ioctl request structure, typed for the +* generic struct ifreq so we can use ptr to func +* w/o cast. +* +* Returns: +* zero on success, a negative errno on failure. Possible values: +* -ENETDOWN Device isn't up. +* -EBUSY cmd already in progress +* -ETIME p80211 cmd timed out (MSD may have its own timers) +* -EFAULT memory fault copying msg from user buffer +* -ENOMEM unable to allocate kernel msg buffer +* -ENOSYS bad magic, it the cmd really for us? +* -EINTR sleeping on cmd, awakened by signal, cmd cancelled. +* +* Call Context: +* Process thread (ioctl caller). TODO: SMP support may require +* locks. +----------------------------------------------------------------*/ +static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) +{ + int result = 0; + p80211ioctl_req_t *req = (p80211ioctl_req_t*)ifr; + wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + UINT8 *msgbuf; + DBFENTER; + + WLAN_LOG_DEBUG(2, "rx'd ioctl, cmd=%d, len=%d\n", cmd, req->len); + + mutex_lock(&wlandev->ioctl_lock); +#if WIRELESS_EXT < 13 + /* Is this a wireless extensions ioctl? */ + if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { + if ((result = p80211wext_support_ioctl(dev, ifr, cmd)) + != (-EOPNOTSUPP)) { + goto bail; + } + } +#endif + +#ifdef SIOCETHTOOL + if (cmd == SIOCETHTOOL) { + result = p80211netdev_ethtool(wlandev, (void __user *) ifr->ifr_data); + goto bail; + } +#endif + + /* Test the magic, assume ifr is good if it's there */ + if ( req->magic != P80211_IOCTL_MAGIC ) { + result = -ENOSYS; + goto bail; + } + + if ( cmd == P80211_IFTEST ) { + result = 0; + goto bail; + } else if ( cmd != P80211_IFREQ ) { + result = -ENOSYS; + goto bail; + } + + /* Allocate a buf of size req->len */ + if ((msgbuf = kmalloc( req->len, GFP_KERNEL))) { + if ( copy_from_user( msgbuf, (void __user *) req->data, req->len) ) { + result = -EFAULT; + } else { + result = p80211req_dorequest( wlandev, msgbuf); + } + + if ( result == 0 ) { + if ( copy_to_user( (void __user *) req->data, msgbuf, req->len)) { + result = -EFAULT; + } + } + kfree(msgbuf); + } else { + result = -ENOMEM; + } +bail: + mutex_unlock(&wlandev->ioctl_lock); + + DBFEXIT; + + return result; /* If allocate,copyfrom or copyto fails, return errno */ +} + +/*---------------------------------------------------------------- +* p80211knetdev_set_mac_address +* +* Handles the ioctl for changing the MACAddress of a netdevice +* +* references: linux/netdevice.h and drivers/net/net_init.c +* +* NOTE: [MSM] We only prevent address changes when the netdev is +* up. We don't control anything based on dot11 state. If the +* address is changed on a STA that's currently associated, you +* will probably lose the ability to send and receive data frames. +* Just be aware. Therefore, this should usually only be done +* prior to scan/join/auth/assoc. +* +* Arguments: +* dev netdevice struct +* addr the new MACAddress (a struct) +* +* Returns: +* zero on success, a negative errno on failure. Possible values: +* -EBUSY device is bussy (cmd not possible) +* -and errors returned by: p80211req_dorequest(..) +* +* by: Collin R. Mulliner +----------------------------------------------------------------*/ +static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr) +{ + struct sockaddr *new_addr = addr; + p80211msg_dot11req_mibset_t dot11req; + p80211item_unk392_t *mibattr; + p80211item_pstr6_t *macaddr; + p80211item_uint32_t *resultcode; + int result = 0; + + DBFENTER; + /* If we're running, we don't allow MAC address changes */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,38) ) + if ( dev->start) { + return -EBUSY; + } +#else + if (netif_running(dev)) { + return -EBUSY; + } +#endif + + /* Set up some convenience pointers. */ + mibattr = &dot11req.mibattribute; + macaddr = (p80211item_pstr6_t*)&mibattr->data; + resultcode = &dot11req.resultcode; + + /* Set up a dot11req_mibset */ + memset(&dot11req, 0, sizeof(p80211msg_dot11req_mibset_t)); + dot11req.msgcode = DIDmsg_dot11req_mibset; + dot11req.msglen = sizeof(p80211msg_dot11req_mibset_t); + memcpy(dot11req.devname, + ((wlandevice_t*)(dev->priv))->name, + WLAN_DEVNAMELEN_MAX - 1); + + /* Set up the mibattribute argument */ + mibattr->did = DIDmsg_dot11req_mibset_mibattribute; + mibattr->status = P80211ENUM_msgitem_status_data_ok; + mibattr->len = sizeof(mibattr->data); + + macaddr->did = DIDmib_dot11mac_dot11OperationTable_dot11MACAddress; + macaddr->status = P80211ENUM_msgitem_status_data_ok; + macaddr->len = sizeof(macaddr->data); + macaddr->data.len = WLAN_ADDR_LEN; + memcpy(&macaddr->data.data, new_addr->sa_data, WLAN_ADDR_LEN); + + /* Set up the resultcode argument */ + resultcode->did = DIDmsg_dot11req_mibset_resultcode; + resultcode->status = P80211ENUM_msgitem_status_no_value; + resultcode->len = sizeof(resultcode->data); + resultcode->data = 0; + + /* now fire the request */ + result = p80211req_dorequest(dev->priv, (UINT8*)&dot11req); + + /* If the request wasn't successful, report an error and don't + * change the netdev address + */ + if ( result != 0 || resultcode->data != P80211ENUM_resultcode_success) { + WLAN_LOG_ERROR( + "Low-level driver failed dot11req_mibset(dot11MACAddress).\n"); + result = -EADDRNOTAVAIL; + } else { + /* everything's ok, change the addr in netdev */ + memcpy(dev->dev_addr, new_addr->sa_data, dev->addr_len); + } + + DBFEXIT; + return result; +} + +static int wlan_change_mtu(netdevice_t *dev, int new_mtu) +{ + DBFENTER; + // 2312 is max 802.11 payload, 20 is overhead, (ether + llc +snap) + // and another 8 for wep. + if ( (new_mtu < 68) || (new_mtu > (2312 - 20 - 8))) + return -EINVAL; + + dev->mtu = new_mtu; + + DBFEXIT; + + return 0; +} + +/*--------------------------------------------------------- + * wlan_alloc_netdev + * + * create a netdev properly over different kernel versions + * this should work with kernels earlier than 2.6.26, and if + * anyone cares they can change it +----------------------------------------------------------*/ + +static inline netdevice_t * wlan_alloc_netdev() { + netdevice_t *dev; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) ) + dev = alloc_netdev(0,"wlan%d",ether_setup); +#else + dev = kmalloc(sizeof(netdevice_t), GFP_ATOMIC); + if ( dev ) { + memset( dev, 0, sizeof(netdevice_t)); + ether_setup(dev); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) ) + dev->nd_net = &init_net; +#endif + } +#endif + return dev; +} + + +/*---------------------------------------------------------------- +* wlan_setup +* +* Roughly matches the functionality of ether_setup. Here +* we set up any members of the wlandevice structure that are common +* to all devices. Additionally, we allocate a linux 'struct device' +* and perform the same setup as ether_setup. +* +* Note: It's important that the caller have setup the wlandev->name +* ptr prior to calling this function. +* +* Arguments: +* wlandev ptr to the wlandev structure for the +* interface. +* Returns: +* zero on success, non-zero otherwise. +* Call Context: +* Should be process thread. We'll assume it might be +* interrupt though. When we add support for statically +* compiled drivers, this function will be called in the +* context of the kernel startup code. +----------------------------------------------------------------*/ +int wlan_setup(wlandevice_t *wlandev) +{ + int result = 0; + netdevice_t *dev; + + DBFENTER; + + /* Set up the wlandev */ + wlandev->state = WLAN_DEVICE_CLOSED; + wlandev->ethconv = WLAN_ETHCONV_8021h; + wlandev->macmode = WLAN_MACMODE_NONE; + + /* Set up the rx queue */ + skb_queue_head_init(&wlandev->nsd_rxq); + tasklet_init(&wlandev->rx_bh, + p80211netdev_rx_bh, + (unsigned long)wlandev); + + /* Allocate and initialize the struct net device */ + dev = wlan_alloc_netdev(); + if ( dev == NULL ) { + WLAN_LOG_ERROR("Failed to alloc netdev.\n"); + result = 1; + } else { + wlandev->netdev = dev; + dev->priv = wlandev; + dev->hard_start_xmit = p80211knetdev_hard_start_xmit; + dev->get_stats = p80211knetdev_get_stats; + + mutex_init(&wlandev->ioctl_lock); + /* block ioctls until fully initialised. Don't forget to call allow_ioctls at some point!*/ + mutex_lock(&wlandev->ioctl_lock); + +#ifdef HAVE_PRIVATE_IOCTL + dev->do_ioctl = p80211knetdev_do_ioctl; +#endif +#ifdef HAVE_MULTICAST + dev->set_multicast_list = p80211knetdev_set_multicast_list; +#endif + dev->init = p80211knetdev_init; + dev->open = p80211knetdev_open; + dev->stop = p80211knetdev_stop; + +#if defined(CONFIG_NET_WIRELESS) || defined(WIRELESS_EXT) +#if (WIRELESS_EXT < 17) + dev->get_wireless_stats = p80211wext_get_wireless_stats; +#endif +#if WIRELESS_EXT > 12 + dev->wireless_handlers = &p80211wext_handler_def; +#endif +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,38) ) + dev->tbusy = 1; + dev->start = 0; +#else + netif_stop_queue(dev); +#endif +#ifdef HAVE_CHANGE_MTU + dev->change_mtu = wlan_change_mtu; +#endif +#ifdef HAVE_SET_MAC_ADDR + dev->set_mac_address = p80211knetdev_set_mac_address; +#endif +#ifdef HAVE_TX_TIMEOUT + dev->tx_timeout = &p80211knetdev_tx_timeout; + dev->watchdog_timeo = (wlan_watchdog * HZ) / 1000; +#endif + netif_carrier_off(dev); + } + + DBFEXIT; + return result; +} + +/*---------------------------------------------------------------- +* wlan_unsetup +* +* This function is paired with the wlan_setup routine. It should +* be called after unregister_wlandev. Basically, all it does is +* free the 'struct device' that's associated with the wlandev. +* We do it here because the 'struct device' isn't allocated +* explicitly in the driver code, it's done in wlan_setup. To +* do the free in the driver might seem like 'magic'. +* +* Arguments: +* wlandev ptr to the wlandev structure for the +* interface. +* Returns: +* zero on success, non-zero otherwise. +* Call Context: +* Should be process thread. We'll assume it might be +* interrupt though. When we add support for statically +* compiled drivers, this function will be called in the +* context of the kernel startup code. +----------------------------------------------------------------*/ +int wlan_unsetup(wlandevice_t *wlandev) +{ + int result = 0; + + DBFENTER; + + tasklet_kill(&wlandev->rx_bh); + + if (wlandev->netdev == NULL ) { + WLAN_LOG_ERROR("called without wlandev->netdev set.\n"); + result = 1; + } else { + free_netdev(wlandev->netdev); + wlandev->netdev = NULL; + } + + DBFEXIT; + return 0; +} + + + +/*---------------------------------------------------------------- +* register_wlandev +* +* Roughly matches the functionality of register_netdev. This function +* is called after the driver has successfully probed and set up the +* resources for the device. It's now ready to become a named device +* in the Linux system. +* +* First we allocate a name for the device (if not already set), then +* we call the Linux function register_netdevice. +* +* Arguments: +* wlandev ptr to the wlandev structure for the +* interface. +* Returns: +* zero on success, non-zero otherwise. +* Call Context: +* Can be either interrupt or not. +----------------------------------------------------------------*/ +int register_wlandev(wlandevice_t *wlandev) +{ + int i = 0; + netdevice_t *dev = wlandev->netdev; + + DBFENTER; +/* alloc_netdev already sets up the name */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) ) + i = register_netdev(dev); + if (i) + return i; +#else + i = dev_alloc_name(wlandev->netdev, "wlan%d"); + if (i >= 0) { + i = register_netdev(wlandev->netdev); + } + if (i != 0) { + return -EIO; + } + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) ) + dev->name = wlandev->name; +#else + strcpy(wlandev->name, dev->name); +#endif +#endif + + +#ifdef CONFIG_PROC_FS + if (proc_p80211) { + wlandev->procdir = proc_mkdir(wlandev->name, proc_p80211); + if ( wlandev->procdir ) + wlandev->procwlandev = + create_proc_read_entry("wlandev", 0, + wlandev->procdir, + p80211netdev_proc_read, + wlandev); + if (wlandev->nsd_proc_read) + create_proc_read_entry("nsd", 0, + wlandev->procdir, + wlandev->nsd_proc_read, + wlandev); + } +#endif + + if (wlan_wext_write) { +/* + // fake out a call to ifstate_enable! + p80211msg_lnxreq_ifstate_t msg; + memset(&msg, 0, sizeof(msg)); + msg.msgcode = DIDmsg_lnxreq_ifstate; + msg.msglen = sizeof(msg); + msg.ifstate.status = P80211ENUM_msgitem_status_data_ok; + msg.ifstate.data = P80211ENUM_ifstate_enable; + + p80211req_dorequest(wlandev, &msg); +*/ + } else { +#ifdef CONFIG_HOTPLUG + p80211_run_sbin_hotplug(wlandev, WLAN_HOTPLUG_REGISTER); +#endif + } + + DBFEXIT; + return 0; +} + + +/*---------------------------------------------------------------- +* unregister_wlandev +* +* Roughly matches the functionality of unregister_netdev. This +* function is called to remove a named device from the system. +* +* First we tell linux that the device should no longer exist. +* Then we remove it from the list of known wlan devices. +* +* Arguments: +* wlandev ptr to the wlandev structure for the +* interface. +* Returns: +* zero on success, non-zero otherwise. +* Call Context: +* Can be either interrupt or not. +----------------------------------------------------------------*/ +int unregister_wlandev(wlandevice_t *wlandev) +{ + struct sk_buff *skb; + + DBFENTER; + +#ifdef CONFIG_HOTPLUG + p80211_run_sbin_hotplug(wlandev, WLAN_HOTPLUG_REMOVE); +#endif + +#ifdef CONFIG_PROC_FS + if ( wlandev->procwlandev ) { + remove_proc_entry("wlandev", wlandev->procdir); + } + if ( wlandev->nsd_proc_read ) { + remove_proc_entry("nsd", wlandev->procdir); + } + if (wlandev->procdir) { + remove_proc_entry(wlandev->name, proc_p80211); + } +#endif + + unregister_netdev(wlandev->netdev); + + /* Now to clean out the rx queue */ + while ( (skb = skb_dequeue(&wlandev->nsd_rxq)) ) { + dev_kfree_skb(skb); + } + + DBFEXIT; + return 0; +} + +#ifdef CONFIG_PROC_FS +/*---------------------------------------------------------------- +* proc_read +* +* Read function for /proc/net/p80211//wlandev +* +* Arguments: +* buf +* start +* offset +* count +* eof +* data +* Returns: +* zero on success, non-zero otherwise. +* Call Context: +* Can be either interrupt or not. +----------------------------------------------------------------*/ +static int +p80211netdev_proc_read( + char *page, + char **start, + off_t offset, + int count, + int *eof, + void *data) +{ + char *p = page; + wlandevice_t *wlandev = (wlandevice_t *) data; + + DBFENTER; + if (offset != 0) { + *eof = 1; + goto exit; + } + + p += sprintf(p, "p80211 version: %s (%s)\n\n", + WLAN_RELEASE, WLAN_BUILD_DATE); + p += sprintf(p, "name : %s\n", wlandev->name); + p += sprintf(p, "nsd name : %s\n", wlandev->nsdname); + p += sprintf(p, "address : %02x:%02x:%02x:%02x:%02x:%02x\n", + wlandev->netdev->dev_addr[0], wlandev->netdev->dev_addr[1], wlandev->netdev->dev_addr[2], + wlandev->netdev->dev_addr[3], wlandev->netdev->dev_addr[4], wlandev->netdev->dev_addr[5]); + p += sprintf(p, "nsd caps : %s%s%s%s%s%s%s%s%s%s\n", + (wlandev->nsdcaps & P80211_NSDCAP_HARDWAREWEP) ? "wep_hw " : "", + (wlandev->nsdcaps & P80211_NSDCAP_TIEDWEP) ? "wep_tied " : "", + (wlandev->nsdcaps & P80211_NSDCAP_NOHOSTWEP) ? "wep_hw_only " : "", + (wlandev->nsdcaps & P80211_NSDCAP_PBCC) ? "pbcc " : "", + (wlandev->nsdcaps & P80211_NSDCAP_SHORT_PREAMBLE) ? "short_preamble " : "", + (wlandev->nsdcaps & P80211_NSDCAP_AGILITY) ? "agility " : "", + (wlandev->nsdcaps & P80211_NSDCAP_AP_RETRANSMIT) ? "ap_retransmit " : "", + (wlandev->nsdcaps & P80211_NSDCAP_HWFRAGMENT) ? "hw_frag " : "", + (wlandev->nsdcaps & P80211_NSDCAP_AUTOJOIN) ? "autojoin " : "", + (wlandev->nsdcaps & P80211_NSDCAP_NOSCAN) ? "" : "scan "); + + + p += sprintf(p, "bssid : %02x:%02x:%02x:%02x:%02x:%02x\n", + wlandev->bssid[0], wlandev->bssid[1], wlandev->bssid[2], + wlandev->bssid[3], wlandev->bssid[4], wlandev->bssid[5]); + + p += sprintf(p, "Enabled : %s%s\n", + (wlandev->shortpreamble) ? "short_preamble " : "", + (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) ? "privacy" : ""); + p += sprintf(p, "msdstate=%d\n", wlandev->msdstate); + + + exit: + DBFEXIT; + return (p - page); +} +#endif + +/*---------------------------------------------------------------- +* p80211netdev_hwremoved +* +* Hardware removed notification. This function should be called +* immediately after an MSD has detected that the underlying hardware +* has been yanked out from under us. The primary things we need +* to do are: +* - Mark the wlandev +* - Prevent any further traffic from the knetdev i/f +* - Prevent any further requests from mgmt i/f +* - If there are any waitq'd mgmt requests or mgmt-frame exchanges, +* shut them down. +* - Call the MSD hwremoved function. +* +* The remainder of the cleanup will be handled by unregister(). +* Our primary goal here is to prevent as much tickling of the MSD +* as possible since the MSD is already in a 'wounded' state. +* +* TODO: As new features are added, this function should be +* updated. +* +* Arguments: +* wlandev WLAN network device structure +* Returns: +* nothing +* Side effects: +* +* Call context: +* Usually interrupt. +----------------------------------------------------------------*/ +void p80211netdev_hwremoved(wlandevice_t *wlandev) +{ + DBFENTER; + wlandev->hwremoved = 1; + if ( wlandev->state == WLAN_DEVICE_OPEN) { + p80211netdev_stop_queue(wlandev); + } + + netif_device_detach(wlandev->netdev); + + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* p80211_rx_typedrop +* +* Classifies the frame, increments the appropriate counter, and +* returns 0|1|2 indicating whether the driver should handle, ignore, or +* drop the frame +* +* Arguments: +* wlandev wlan device structure +* fc frame control field +* +* Returns: +* zero if the frame should be handled by the driver, +* one if the frame should be ignored +* anything else means we drop it. +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static int p80211_rx_typedrop( wlandevice_t *wlandev, UINT16 fc) +{ + UINT16 ftype; + UINT16 fstype; + int drop = 0; + /* Classify frame, increment counter */ + ftype = WLAN_GET_FC_FTYPE(fc); + fstype = WLAN_GET_FC_FSTYPE(fc); +#if 0 + WLAN_LOG_DEBUG(4, + "rx_typedrop : ftype=%d fstype=%d.\n", ftype, fstype); +#endif + switch ( ftype ) { + case WLAN_FTYPE_MGMT: + if ((wlandev->netdev->flags & IFF_PROMISC) || + (wlandev->netdev->flags & IFF_ALLMULTI)) { + drop = 1; + break; + } + WLAN_LOG_DEBUG(3, "rx'd mgmt:\n"); + wlandev->rx.mgmt++; + switch( fstype ) { + case WLAN_FSTYPE_ASSOCREQ: + /* printk("assocreq"); */ + wlandev->rx.assocreq++; + break; + case WLAN_FSTYPE_ASSOCRESP: + /* printk("assocresp"); */ + wlandev->rx.assocresp++; + break; + case WLAN_FSTYPE_REASSOCREQ: + /* printk("reassocreq"); */ + wlandev->rx.reassocreq++; + break; + case WLAN_FSTYPE_REASSOCRESP: + /* printk("reassocresp"); */ + wlandev->rx.reassocresp++; + break; + case WLAN_FSTYPE_PROBEREQ: + /* printk("probereq"); */ + wlandev->rx.probereq++; + break; + case WLAN_FSTYPE_PROBERESP: + /* printk("proberesp"); */ + wlandev->rx.proberesp++; + break; + case WLAN_FSTYPE_BEACON: + /* printk("beacon"); */ + wlandev->rx.beacon++; + break; + case WLAN_FSTYPE_ATIM: + /* printk("atim"); */ + wlandev->rx.atim++; + break; + case WLAN_FSTYPE_DISASSOC: + /* printk("disassoc"); */ + wlandev->rx.disassoc++; + break; + case WLAN_FSTYPE_AUTHEN: + /* printk("authen"); */ + wlandev->rx.authen++; + break; + case WLAN_FSTYPE_DEAUTHEN: + /* printk("deauthen"); */ + wlandev->rx.deauthen++; + break; + default: + /* printk("unknown"); */ + wlandev->rx.mgmt_unknown++; + break; + } + /* printk("\n"); */ + drop = 2; + break; + + case WLAN_FTYPE_CTL: + if ((wlandev->netdev->flags & IFF_PROMISC) || + (wlandev->netdev->flags & IFF_ALLMULTI)) { + drop = 1; + break; + } + WLAN_LOG_DEBUG(3, "rx'd ctl:\n"); + wlandev->rx.ctl++; + switch( fstype ) { + case WLAN_FSTYPE_PSPOLL: + /* printk("pspoll"); */ + wlandev->rx.pspoll++; + break; + case WLAN_FSTYPE_RTS: + /* printk("rts"); */ + wlandev->rx.rts++; + break; + case WLAN_FSTYPE_CTS: + /* printk("cts"); */ + wlandev->rx.cts++; + break; + case WLAN_FSTYPE_ACK: + /* printk("ack"); */ + wlandev->rx.ack++; + break; + case WLAN_FSTYPE_CFEND: + /* printk("cfend"); */ + wlandev->rx.cfend++; + break; + case WLAN_FSTYPE_CFENDCFACK: + /* printk("cfendcfack"); */ + wlandev->rx.cfendcfack++; + break; + default: + /* printk("unknown"); */ + wlandev->rx.ctl_unknown++; + break; + } + /* printk("\n"); */ + drop = 2; + break; + + case WLAN_FTYPE_DATA: + wlandev->rx.data++; + switch( fstype ) { + case WLAN_FSTYPE_DATAONLY: + wlandev->rx.dataonly++; + break; + case WLAN_FSTYPE_DATA_CFACK: + wlandev->rx.data_cfack++; + break; + case WLAN_FSTYPE_DATA_CFPOLL: + wlandev->rx.data_cfpoll++; + break; + case WLAN_FSTYPE_DATA_CFACK_CFPOLL: + wlandev->rx.data__cfack_cfpoll++; + break; + case WLAN_FSTYPE_NULL: + WLAN_LOG_DEBUG(3, "rx'd data:null\n"); + wlandev->rx.null++; + break; + case WLAN_FSTYPE_CFACK: + WLAN_LOG_DEBUG(3, "rx'd data:cfack\n"); + wlandev->rx.cfack++; + break; + case WLAN_FSTYPE_CFPOLL: + WLAN_LOG_DEBUG(3, "rx'd data:cfpoll\n"); + wlandev->rx.cfpoll++; + break; + case WLAN_FSTYPE_CFACK_CFPOLL: + WLAN_LOG_DEBUG(3, "rx'd data:cfack_cfpoll\n"); + wlandev->rx.cfack_cfpoll++; + break; + default: + /* printk("unknown"); */ + wlandev->rx.data_unknown++; + break; + } + + break; + } + return drop; +} + +#ifdef CONFIG_HOTPLUG +/* Notify userspace when a netdevice event occurs, + * by running '/sbin/hotplug net' with certain + * environment variables set. + */ +int p80211_run_sbin_hotplug(wlandevice_t *wlandev, char *action) +{ + char *argv[3], *envp[7], ifname[12 + IFNAMSIZ], action_str[32]; + char nsdname[32], wlan_wext[32]; + int i; + + if (wlandev) { + sprintf(ifname, "INTERFACE=%s", wlandev->name); + sprintf(nsdname, "NSDNAME=%s", wlandev->nsdname); + } else { + sprintf(ifname, "INTERFACE=null"); + sprintf(nsdname, "NSDNAME=null"); + } + + sprintf(wlan_wext, "WLAN_WEXT=%s", wlan_wext_write ? "y" : ""); + sprintf(action_str, "ACTION=%s", action); + + i = 0; + argv[i++] = hotplug_path; + argv[i++] = "wlan"; + argv[i] = NULL; + + i = 0; + /* minimal command environment */ + envp [i++] = "HOME=/"; + envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; + envp [i++] = ifname; + envp [i++] = action_str; + envp [i++] = nsdname; + envp [i++] = wlan_wext; + envp [i] = NULL; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,62)) + return call_usermodehelper(argv [0], argv, envp); +#else + return call_usermodehelper(argv [0], argv, envp, 0); +#endif +} + +#endif + + +void p80211_suspend(wlandevice_t *wlandev) +{ + DBFENTER; + +#ifdef CONFIG_HOTPLUG + p80211_run_sbin_hotplug(wlandev, WLAN_HOTPLUG_SUSPEND); +#endif + + DBFEXIT; +} + +void p80211_resume(wlandevice_t *wlandev) +{ + DBFENTER; + +#ifdef CONFIG_HOTPLUG + p80211_run_sbin_hotplug(wlandev, WLAN_HOTPLUG_RESUME); +#endif + + DBFEXIT; +} + +static void p80211knetdev_tx_timeout( netdevice_t *netdev) +{ + wlandevice_t *wlandev = (wlandevice_t*)netdev->priv; + DBFENTER; + + if (wlandev->tx_timeout) { + wlandev->tx_timeout(wlandev); + } else { + WLAN_LOG_WARNING("Implement tx_timeout for %s\n", + wlandev->nsdname); + p80211netdev_wake_queue(wlandev); + } + + DBFEXIT; +} + +void p80211_allow_ioctls(wlandevice_t *wlandev) { + mutex_unlock(&wlandev->ioctl_lock); +} --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/Makefile +++ linux-2.6.27/ubuntu/misc/wireless/p80211/Makefile @@ -0,0 +1,11 @@ +obj-$(CONFIG_P80211) := p80211.o + +p80211-objs := p80211mod.o \ + p80211conv.o \ + p80211req.o \ + p80211wep.o \ + p80211wext.o \ + p80211netdev.o + +EXTRA_CFLAGS += -DWLAN_TXMGMT_MINBRATE -DRSN_INTERNAL_ROAM \ + -DWLAN_HOSTIF=WLAN_NONE -I$(src) --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/p80211wep.c +++ linux-2.6.27/ubuntu/misc/wireless/p80211/p80211wep.c @@ -0,0 +1,317 @@ +/* src/p80211/p80211wep.c +* +* WEP encode/decode for P80211. +* +* Copyright (C) 2002 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +*/ + +/*================================================================*/ +/* System Includes */ + + +#include + +#include +#include +#include +#include + +#include +#include + +// #define WEP_DEBUG + +/*================================================================*/ +/* Project Includes */ + +#include +#include +#include +#include +#include +#include + +/*================================================================*/ +/* Local Constants */ + +#define SSWAP(a,b) {UINT8 tmp = s[a]; s[a] = s[b]; s[b] = tmp;} +#define WEP_KEY(x) (((x) & 0xC0) >> 6) + +/*================================================================*/ +/* Local Macros */ + + +/*================================================================*/ +/* Local Types */ + + +/*================================================================*/ +/* Local Static Definitions */ + +static const UINT32 wep_crc32_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +/*================================================================*/ +/* Local Function Declarations */ + +/*================================================================*/ +/* Function Definitions */ + +/* keylen in bytes! */ + +int wep_change_key(wlandevice_t *wlandev, int keynum, UINT8* key, int keylen) +{ + if (keylen < 0) return -1; + if (keylen >= MAX_KEYLEN) return -1; + if (key == NULL) return -1; + if (keynum < 0) return -1; + if (keynum >= NUM_WEPKEYS) return -1; + + +#ifdef WEP_DEBUG + printk(KERN_DEBUG "WEP key %d len %d = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", keynum, keylen, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7]); +#endif + + wlandev->wep_keylens[keynum] = keylen; + memcpy(wlandev->wep_keys[keynum], key, keylen); + + return 0; +} + +/* + 4-byte IV at start of buffer, 4-byte ICV at end of buffer. + if successful, buf start is payload begin, length -= 8; + */ +int wep_decrypt(wlandevice_t *wlandev, UINT8 *buf, UINT32 len, int key_override, UINT8 *iv, UINT8 *icv) +{ + UINT32 i, j, k, crc, keylen; + UINT8 s[256], key[64], c_crc[4]; + UINT8 keyidx; + + /* Needs to be at least 8 bytes of payload */ + if (len <= 0) return -1; + + /* initialize the first bytes of the key from the IV */ + key[0] = iv[0]; + key[1] = iv[1]; + key[2] = iv[2]; + keyidx = WEP_KEY(iv[3]); + + if (key_override >= 0) + keyidx = key_override; + + if (keyidx >= NUM_WEPKEYS) return -2; + + keylen = wlandev->wep_keylens[keyidx]; + + if (keylen == 0) return -3; + + /* copy the rest of the key over from the designated key */ + memcpy(key+3, wlandev->wep_keys[keyidx], keylen); + + keylen+=3; /* add in IV bytes */ + +#ifdef WEP_DEBUG + printk(KERN_DEBUG "D %d: %02x %02x %02x (%d %d) %02x:%02x:%02x:%02x:%02x\n", len, key[0], key[1], key[2], keyidx, keylen, key[3], key[4], key[5], key[6], key[7]); +#endif + + /* set up the RC4 state */ + for (i = 0; i < 256; i++) + s[i] = i; + j = 0; + for (i = 0; i < 256; i++) { + j = (j + s[i] + key[i % keylen]) & 0xff; + SSWAP(i,j); + } + + /* Apply the RC4 to the data, update the CRC32 */ + crc = ~0; + i = j = 0; + for (k = 0; k < len; k++) { + i = (i+1) & 0xff; + j = (j+s[i]) & 0xff; + SSWAP(i,j); + buf[k] ^= s[(s[i] + s[j]) & 0xff]; + crc = wep_crc32_table[(crc ^ buf[k]) & 0xff] ^ (crc >> 8); + } + crc = ~crc; + + /* now let's check the crc */ + c_crc[0] = crc; + c_crc[1] = crc >> 8; + c_crc[2] = crc >> 16; + c_crc[3] = crc >> 24; + + for (k = 0; k < 4; k++) { + i = (i + 1) & 0xff; + j = (j+s[i]) & 0xff; + SSWAP(i,j); + if ((c_crc[k] ^ s[(s[i] + s[j]) & 0xff]) != icv[k]) + return -(4 | (k << 4)) ; /* ICV mismatch */ + } + + return 0; +} + +/* encrypts in-place. */ +int wep_encrypt(wlandevice_t *wlandev, UINT8 *buf, UINT8 *dst, UINT32 len, int keynum, UINT8 *iv, UINT8 *icv) +{ + UINT32 i, j, k, crc, keylen; + UINT8 s[256], key[64]; + + /* no point in WEPping an empty frame */ + if (len <= 0) return -1; + + /* we need to have a real key.. */ + if (keynum >= NUM_WEPKEYS) return -2; + keylen = wlandev->wep_keylens[keynum]; + if (keylen <= 0) return -3; + + /* use a random IV. And skip known weak ones. */ + get_random_bytes(iv, 3); + while ((iv[1] == 0xff) && (iv[0] >= 3) && (iv[0] < keylen)) + get_random_bytes(iv, 3); + + iv[3] = (keynum & 0x03) << 6; + + key[0] = iv[0]; + key[1] = iv[1]; + key[2] = iv[2]; + + /* copy the rest of the key over from the designated key */ + memcpy(key+3, wlandev->wep_keys[keynum], keylen); + + keylen+=3; /* add in IV bytes */ + +#ifdef WEP_DEBUG + printk(KERN_DEBUG "E %d (%d/%d %d) %02x %02x %02x %02x:%02x:%02x:%02x:%02x\n", len, iv[3], keynum, keylen, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7]); +#endif + + /* set up the RC4 state */ + for (i = 0; i < 256; i++) + s[i] = i; + j = 0; + for (i = 0; i < 256; i++) { + j = (j + s[i] + key[i % keylen]) & 0xff; + SSWAP(i,j); + } + + /* Update CRC32 then apply RC4 to the data */ + crc = ~0; + i = j = 0; + for (k = 0; k < len; k++) { + crc = wep_crc32_table[(crc ^ buf[k]) & 0xff] ^ (crc >> 8); + i = (i+1) & 0xff; + j = (j+s[i]) & 0xff; + SSWAP(i,j); + dst[k] = buf[k] ^ s[(s[i] + s[j]) & 0xff]; + } + crc = ~crc; + + /* now let's encrypt the crc */ + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + + for (k = 0; k < 4; k++) { + i = (i + 1) & 0xff; + j = (j+s[i]) & 0xff; + SSWAP(i,j); + icv[k] ^= s[(s[i] + s[j]) & 0xff]; + } + + return 0; +} --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/p80211req.c +++ linux-2.6.27/ubuntu/misc/wireless/p80211/p80211req.c @@ -0,0 +1,329 @@ +/* src/p80211/p80211req.c +* +* Request/Indication/MacMgmt interface handling functions +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* This file contains the functions, types, and macros to support the +* MLME request interface that's implemented via the device ioctls. +* +* -------------------------------------------------------------------- +*/ + +/*================================================================*/ +/* System Includes */ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/*================================================================*/ +/* Project Includes */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*================================================================*/ +/* Local Constants */ + +/* Maximum amount of time we'll wait for a request to complete */ +#define P80211REQ_MAXTIME 3*HZ /* 3 seconds */ + +/*================================================================*/ +/* Local Macros */ + +/*================================================================*/ +/* Local Types */ + +/*================================================================*/ +/* Local Static Definitions */ + +/*================================================================*/ +/* Local Function Declarations */ + +static void p80211req_handlemsg( wlandevice_t *wlandev, p80211msg_t *msg); +static int p80211req_mibset_mibget(wlandevice_t *wlandev, p80211msg_dot11req_mibget_t *mib_msg, int isget); + +/*================================================================*/ +/* Function Definitions */ + + +/*---------------------------------------------------------------- +* p80211req_dorequest +* +* Handles an MLME reqest/confirm message. +* +* Arguments: +* wlandev WLAN device struct +* msgbuf Buffer containing a request message +* +* Returns: +* 0 on success, an errno otherwise +* +* Call context: +* Potentially blocks the caller, so it's a good idea to +* not call this function from an interrupt context. +----------------------------------------------------------------*/ +int p80211req_dorequest( wlandevice_t *wlandev, UINT8 *msgbuf) +{ + int result = 0; + p80211msg_t *msg = (p80211msg_t*)msgbuf; + + DBFENTER; + + /* Check to make sure the MSD is running */ + if ( + !((wlandev->msdstate == WLAN_MSD_HWPRESENT && + msg->msgcode == DIDmsg_lnxreq_ifstate) || + wlandev->msdstate == WLAN_MSD_RUNNING || + wlandev->msdstate == WLAN_MSD_FWLOAD) ) { + return -ENODEV; + } + + /* Check Permissions */ + if (!capable(CAP_NET_ADMIN) && + (msg->msgcode != DIDmsg_dot11req_mibget)) { + WLAN_LOG_ERROR("%s: only dot11req_mibget allowed for non-root.\n", wlandev->name); + return -EPERM; + } + + /* Check for busy status */ + if ( test_and_set_bit(1, &(wlandev->request_pending))) { + return -EBUSY; + } + + /* Allow p80211 to look at msg and handle if desired. */ + /* So far, all p80211 msgs are immediate, no waitq/timer necessary */ + /* This may change. */ + p80211req_handlemsg(wlandev, msg); + + /* Pass it down to wlandev via wlandev->mlmerequest */ + if ( wlandev->mlmerequest != NULL ) + wlandev->mlmerequest(wlandev, msg); + + clear_bit( 1, &(wlandev->request_pending)); + DBFEXIT; + return result; /* if result==0, msg->status still may contain an err */ +} + +/*---------------------------------------------------------------- +* p80211req_handlemsg +* +* p80211 message handler. Primarily looks for messages that +* belong to p80211 and then dispatches the appropriate response. +* TODO: we don't do anything yet. Once the linuxMIB is better +* defined we'll need a get/set handler. +* +* Arguments: +* wlandev WLAN device struct +* msg message structure +* +* Returns: +* nothing (any results are set in the status field of the msg) +* +* Call context: +* Process thread +----------------------------------------------------------------*/ +static void p80211req_handlemsg( wlandevice_t *wlandev, p80211msg_t *msg) +{ + DBFENTER; + + switch (msg->msgcode) { + + case DIDmsg_lnxreq_hostwep: { + p80211msg_lnxreq_hostwep_t *req = (p80211msg_lnxreq_hostwep_t*) msg; + wlandev->hostwep &= ~(HOSTWEP_DECRYPT|HOSTWEP_ENCRYPT); + if (req->decrypt.data == P80211ENUM_truth_true) + wlandev->hostwep |= HOSTWEP_DECRYPT; + if (req->encrypt.data == P80211ENUM_truth_true) + wlandev->hostwep |= HOSTWEP_ENCRYPT; + + break; + } + case DIDmsg_dot11req_mibget: + case DIDmsg_dot11req_mibset: { + int isget = (msg->msgcode == DIDmsg_dot11req_mibget); + p80211msg_dot11req_mibget_t *mib_msg = (p80211msg_dot11req_mibget_t *) msg; + p80211req_mibset_mibget (wlandev, mib_msg, isget); + } + default: + // XXX do nothing! + ; + } /* switch msg->msgcode */ + + DBFEXIT; + + return; +} + +static int p80211req_mibset_mibget(wlandevice_t *wlandev, + p80211msg_dot11req_mibget_t *mib_msg, + int isget) +{ + p80211itemd_t *mibitem = (p80211itemd_t *) mib_msg->mibattribute.data; + p80211pstrd_t *pstr = (p80211pstrd_t*) mibitem->data; + UINT8 *key = mibitem->data + sizeof(p80211pstrd_t); + + DBFENTER; + + switch (mibitem->did) { + case DIDmib_dot11smt_p80211Table_p80211_ifstate: { + UINT32 *data = (UINT32 *) mibitem->data; + if (isget) + switch (wlandev->msdstate) { + case WLAN_MSD_HWPRESENT: + *data = P80211ENUM_ifstate_disable; + break; + case WLAN_MSD_FWLOAD: + *data = P80211ENUM_ifstate_fwload; + break; + case WLAN_MSD_RUNNING: + *data = P80211ENUM_ifstate_enable; + break; + default: + *data = P80211ENUM_ifstate_enable; + } + break; + } + case DIDmib_dot11phy_dot11PhyOperationTable_dot11ShortPreambleEnabled: { + UINT32 *data = (UINT32 *) mibitem->data; + + if (isget) + *data = wlandev->shortpreamble; + else + wlandev->shortpreamble = *data; + break; + } + case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0: { + if (!isget) + wep_change_key(wlandev, 0, key, pstr->len); + break; + } + case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1: { + if (!isget) + wep_change_key(wlandev, 1, key, pstr->len); + break; + } + case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2: { + if (!isget) + wep_change_key(wlandev, 2, key, pstr->len); + break; + } + case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3: { + if (!isget) + wep_change_key(wlandev, 3, key, pstr->len); + break; + } + case DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID: { + UINT32 *data = (UINT32 *) mibitem->data; + + if (isget) { + *data = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK; + } else { + wlandev->hostwep &= ~(HOSTWEP_DEFAULTKEY_MASK); + + wlandev->hostwep |= (*data & HOSTWEP_DEFAULTKEY_MASK); + } + break; + } + case DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked: { + UINT32 *data = (UINT32 *) mibitem->data; + + if (isget) { + if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) + *data = P80211ENUM_truth_true; + else + *data = P80211ENUM_truth_false; + } else { + wlandev->hostwep &= ~(HOSTWEP_PRIVACYINVOKED); + if (*data == P80211ENUM_truth_true) + wlandev->hostwep |= HOSTWEP_PRIVACYINVOKED; + } + break; + } + case DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted: { + UINT32 *data = (UINT32 *) mibitem->data; + + if (isget) { + if (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED) + *data = P80211ENUM_truth_true; + else + *data = P80211ENUM_truth_false; + } else { + wlandev->hostwep &= ~(HOSTWEP_EXCLUDEUNENCRYPTED); + if (*data == P80211ENUM_truth_true) + wlandev->hostwep |= HOSTWEP_EXCLUDEUNENCRYPTED; + } + break; + } + default: + // XXXX do nothing! + ; + } + + DBFEXIT; + return 0; +} + --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/p80211conv.c +++ linux-2.6.27/ubuntu/misc/wireless/p80211/p80211conv.c @@ -0,0 +1,691 @@ +/* src/p80211/p80211conv.c +* +* Ether/802.11 conversions and packet buffer routines +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* This file defines the functions that perform Ethernet to/from +* 802.11 frame conversions. +* +* -------------------------------------------------------------------- +*/ +/*================================================================*/ +/* System Includes */ + +#define __NO_VERSION__ /* prevent the static definition */ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +/*================================================================*/ +/* Project Includes */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/*================================================================*/ +/* Local Constants */ + +/*================================================================*/ +/* Local Macros */ + + +/*================================================================*/ +/* Local Types */ + + +/*================================================================*/ +/* Local Static Definitions */ + +static UINT8 oui_rfc1042[] = {0x00, 0x00, 0x00}; +static UINT8 oui_8021h[] = {0x00, 0x00, 0xf8}; + +/*================================================================*/ +/* Local Function Declarations */ + + +/*================================================================*/ +/* Function Definitions */ + +/*---------------------------------------------------------------- +* p80211pb_ether_to_80211 +* +* Uses the contents of the ether frame and the etherconv setting +* to build the elements of the 802.11 frame. +* +* We don't actually set +* up the frame header here. That's the MAC's job. We're only handling +* conversion of DIXII or 802.3+LLC frames to something that works +* with 802.11. +* +* Note -- 802.11 header is NOT part of the skb. Likewise, the 802.11 +* FCS is also not present and will need to be added elsewhere. +* +* Arguments: +* ethconv Conversion type to perform +* skb skbuff containing the ether frame +* p80211_hdr 802.11 header +* +* Returns: +* 0 on success, non-zero otherwise +* +* Call context: +* May be called in interrupt or non-interrupt context +----------------------------------------------------------------*/ +int skb_ether_to_p80211( wlandevice_t *wlandev, UINT32 ethconv, struct sk_buff *skb, p80211_hdr_t *p80211_hdr, p80211_metawep_t *p80211_wep) +{ + + UINT16 fc; + UINT16 proto; + wlan_ethhdr_t e_hdr; + wlan_llc_t *e_llc; + wlan_snap_t *e_snap; + int foo; + + DBFENTER; + memcpy(&e_hdr, skb->data, sizeof(e_hdr)); + + if (skb->len <= 0) { + WLAN_LOG_DEBUG(1, "zero-length skb!\n"); + return 1; + } + + if ( ethconv == WLAN_ETHCONV_ENCAP ) { /* simplest case */ + WLAN_LOG_DEBUG(3, "ENCAP len: %d\n", skb->len); + /* here, we don't care what kind of ether frm. Just stick it */ + /* in the 80211 payload */ + /* which is to say, leave the skb alone. */ + } else { + /* step 1: classify ether frame, DIX or 802.3? */ + proto = ntohs(e_hdr.type); + if ( proto <= 1500 ) { + WLAN_LOG_DEBUG(3, "802.3 len: %d\n", skb->len); + /* codes <= 1500 reserved for 802.3 lengths */ + /* it's 802.3, pass ether payload unchanged, */ + + /* trim off ethernet header */ + skb_pull(skb, WLAN_ETHHDR_LEN); + + /* leave off any PAD octets. */ + skb_trim(skb, proto); + } else { + WLAN_LOG_DEBUG(3, "DIXII len: %d\n", skb->len); + /* it's DIXII, time for some conversion */ + + /* trim off ethernet header */ + skb_pull(skb, WLAN_ETHHDR_LEN); + + /* tack on SNAP */ + e_snap = (wlan_snap_t *) skb_push(skb, sizeof(wlan_snap_t)); + e_snap->type = htons(proto); + if ( ethconv == WLAN_ETHCONV_8021h && p80211_stt_findproto(proto) ) { + memcpy( e_snap->oui, oui_8021h, WLAN_IEEE_OUI_LEN); + } else { + memcpy( e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN); + } + + /* tack on llc */ + e_llc = (wlan_llc_t *) skb_push(skb, sizeof(wlan_llc_t)); + e_llc->dsap = 0xAA; /* SNAP, see IEEE 802 */ + e_llc->ssap = 0xAA; + e_llc->ctl = 0x03; + + } + } + + /* Set up the 802.11 header */ + /* It's a data frame */ + fc = host2ieee16( WLAN_SET_FC_FTYPE(WLAN_FTYPE_DATA) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DATAONLY)); + + switch ( wlandev->macmode ) { + case WLAN_MACMODE_IBSS_STA: + memcpy(p80211_hdr->a3.a1, &e_hdr.daddr, WLAN_ADDR_LEN); + memcpy(p80211_hdr->a3.a2, wlandev->netdev->dev_addr, WLAN_ADDR_LEN); + memcpy(p80211_hdr->a3.a3, wlandev->bssid, WLAN_ADDR_LEN); + break; + case WLAN_MACMODE_ESS_STA: + fc |= host2ieee16(WLAN_SET_FC_TODS(1)); + memcpy(p80211_hdr->a3.a1, wlandev->bssid, WLAN_ADDR_LEN); + memcpy(p80211_hdr->a3.a2, wlandev->netdev->dev_addr, WLAN_ADDR_LEN); + memcpy(p80211_hdr->a3.a3, &e_hdr.daddr, WLAN_ADDR_LEN); + break; + case WLAN_MACMODE_ESS_AP: + fc |= host2ieee16(WLAN_SET_FC_FROMDS(1)); + memcpy(p80211_hdr->a3.a1, &e_hdr.daddr, WLAN_ADDR_LEN); + memcpy(p80211_hdr->a3.a2, wlandev->bssid, WLAN_ADDR_LEN); + memcpy(p80211_hdr->a3.a3, &e_hdr.saddr, WLAN_ADDR_LEN); + break; + default: + WLAN_LOG_ERROR("Error: Converting eth to wlan in unknown mode.\n"); + return 1; + break; + } + + p80211_wep->data = NULL; + + if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) && (wlandev->hostwep & HOSTWEP_ENCRYPT)) { + // XXXX need to pick keynum other than default? + +#if 1 + p80211_wep->data = kmalloc(skb->len, GFP_ATOMIC); +#else + p80211_wep->data = skb->data; +#endif + + if ((foo = wep_encrypt(wlandev, skb->data, p80211_wep->data, + skb->len, + (wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK), + p80211_wep->iv, p80211_wep->icv))) { + WLAN_LOG_WARNING("Host en-WEP failed, dropping frame (%d).\n", foo); + return 2; + } + fc |= host2ieee16(WLAN_SET_FC_ISWEP(1)); + } + + + // skb->nh.raw = skb->data; + + p80211_hdr->a3.fc = fc; + p80211_hdr->a3.dur = 0; + p80211_hdr->a3.seq = 0; + + DBFEXIT; + return 0; +} + +/* jkriegl: from orinoco, modified */ +static void orinoco_spy_gather(wlandevice_t *wlandev, char *mac, + p80211_rxmeta_t *rxmeta) +{ + int i; + + /* Gather wireless spy statistics: for each packet, compare the + * source address with out list, and if match, get the stats... */ + + for (i = 0; i < wlandev->spy_number; i++) { + + if (!memcmp(wlandev->spy_address[i], mac, ETH_ALEN)) { + memcpy(wlandev->spy_address[i], mac, ETH_ALEN); + wlandev->spy_stat[i].level = rxmeta->signal; + wlandev->spy_stat[i].noise = rxmeta->noise; + wlandev->spy_stat[i].qual = (rxmeta->signal > rxmeta->noise) ? \ + (rxmeta->signal - rxmeta->noise) : 0; + wlandev->spy_stat[i].updated = 0x7; + } + } +} + +/*---------------------------------------------------------------- +* p80211pb_80211_to_ether +* +* Uses the contents of a received 802.11 frame and the etherconv +* setting to build an ether frame. +* +* This function extracts the src and dest address from the 802.11 +* frame to use in the construction of the eth frame. +* +* Arguments: +* ethconv Conversion type to perform +* skb Packet buffer containing the 802.11 frame +* +* Returns: +* 0 on success, non-zero otherwise +* +* Call context: +* May be called in interrupt or non-interrupt context +----------------------------------------------------------------*/ +int skb_p80211_to_ether( wlandevice_t *wlandev, UINT32 ethconv, struct sk_buff *skb) +{ + netdevice_t *netdev = wlandev->netdev; + UINT16 fc; + UINT payload_length; + UINT payload_offset; + UINT8 daddr[WLAN_ETHADDR_LEN]; + UINT8 saddr[WLAN_ETHADDR_LEN]; + p80211_hdr_t *w_hdr; + wlan_ethhdr_t *e_hdr; + wlan_llc_t *e_llc; + wlan_snap_t *e_snap; + + int foo; + + DBFENTER; + + payload_length = skb->len - WLAN_HDR_A3_LEN - WLAN_CRC_LEN; + payload_offset = WLAN_HDR_A3_LEN; + + w_hdr = (p80211_hdr_t *) skb->data; + + /* setup some vars for convenience */ + fc = ieee2host16(w_hdr->a3.fc); + if ( (WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 0) ) { + memcpy(daddr, w_hdr->a3.a1, WLAN_ETHADDR_LEN); + memcpy(saddr, w_hdr->a3.a2, WLAN_ETHADDR_LEN); + } else if( (WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 1) ) { + memcpy(daddr, w_hdr->a3.a1, WLAN_ETHADDR_LEN); + memcpy(saddr, w_hdr->a3.a3, WLAN_ETHADDR_LEN); + } else if( (WLAN_GET_FC_TODS(fc) == 1) && (WLAN_GET_FC_FROMDS(fc) == 0) ) { + memcpy(daddr, w_hdr->a3.a3, WLAN_ETHADDR_LEN); + memcpy(saddr, w_hdr->a3.a2, WLAN_ETHADDR_LEN); + } else { + payload_offset = WLAN_HDR_A4_LEN; + payload_length -= ( WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN ); + if (payload_length < 0 ) { + WLAN_LOG_ERROR("A4 frame too short!\n"); + return 1; + } + memcpy(daddr, w_hdr->a4.a3, WLAN_ETHADDR_LEN); + memcpy(saddr, w_hdr->a4.a4, WLAN_ETHADDR_LEN); + } + + /* perform de-wep if necessary.. */ + if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) && WLAN_GET_FC_ISWEP(fc) && (wlandev->hostwep & HOSTWEP_DECRYPT)) { + if (payload_length <= 8) { + WLAN_LOG_ERROR("WEP frame too short (%u).\n", + skb->len); + return 1; + } + if ((foo = wep_decrypt(wlandev, skb->data + payload_offset + 4, + payload_length - 8, -1, + skb->data + payload_offset, + skb->data + payload_offset + payload_length - 4))) { + /* de-wep failed, drop skb. */ + WLAN_LOG_DEBUG(1, "Host de-WEP failed, dropping frame (%d).\n", foo); + wlandev->rx.decrypt_err++; + return 2; + } + + /* subtract the IV+ICV length off the payload */ + payload_length -= 8; + /* chop off the IV */ + skb_pull(skb, 4); + /* chop off the ICV. */ + skb_trim(skb, skb->len - 4); + + wlandev->rx.decrypt++; + } + + e_hdr = (wlan_ethhdr_t *) (skb->data + payload_offset); + + e_llc = (wlan_llc_t *) (skb->data + payload_offset); + e_snap = (wlan_snap_t *) (skb->data + payload_offset + sizeof(wlan_llc_t)); + + /* Test for the various encodings */ + if ( (payload_length >= sizeof(wlan_ethhdr_t)) && + ( e_llc->dsap != 0xaa || e_llc->ssap != 0xaa ) && + ((memcmp(daddr, e_hdr->daddr, WLAN_ETHADDR_LEN) == 0) || + (memcmp(saddr, e_hdr->saddr, WLAN_ETHADDR_LEN) == 0))) { + WLAN_LOG_DEBUG(3, "802.3 ENCAP len: %d\n", payload_length); + /* 802.3 Encapsulated */ + /* Test for an overlength frame */ + if ( payload_length > (netdev->mtu + WLAN_ETHHDR_LEN)) { + /* A bogus length ethfrm has been encap'd. */ + /* Is someone trying an oflow attack? */ + WLAN_LOG_ERROR("ENCAP frame too large (%d > %d)\n", + payload_length, netdev->mtu + WLAN_ETHHDR_LEN); + return 1; + } + + /* Chop off the 802.11 header. it's already sane. */ + skb_pull(skb, payload_offset); + /* chop off the 802.11 CRC */ + skb_trim(skb, skb->len - WLAN_CRC_LEN); + + } else if ((payload_length >= sizeof(wlan_llc_t) + sizeof(wlan_snap_t)) && + (e_llc->dsap == 0xaa) && + (e_llc->ssap == 0xaa) && + (e_llc->ctl == 0x03) && + (((memcmp( e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN)==0) && + (ethconv == WLAN_ETHCONV_8021h) && + (p80211_stt_findproto(ieee2host16(e_snap->type)))) || + (memcmp( e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN)!=0))) + { + WLAN_LOG_DEBUG(3, "SNAP+RFC1042 len: %d\n", payload_length); + /* it's a SNAP + RFC1042 frame && protocol is in STT */ + /* build 802.3 + RFC1042 */ + + /* Test for an overlength frame */ + if ( payload_length > netdev->mtu ) { + /* A bogus length ethfrm has been sent. */ + /* Is someone trying an oflow attack? */ + WLAN_LOG_ERROR("SNAP frame too large (%d > %d)\n", + payload_length, netdev->mtu); + return 1; + } + + /* chop 802.11 header from skb. */ + skb_pull(skb, payload_offset); + + /* create 802.3 header at beginning of skb. */ + e_hdr = (wlan_ethhdr_t *) skb_push(skb, WLAN_ETHHDR_LEN); + memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN); + memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN); + e_hdr->type = htons(payload_length); + + /* chop off the 802.11 CRC */ + skb_trim(skb, skb->len - WLAN_CRC_LEN); + + } else if ((payload_length >= sizeof(wlan_llc_t) + sizeof(wlan_snap_t)) && + (e_llc->dsap == 0xaa) && + (e_llc->ssap == 0xaa) && + (e_llc->ctl == 0x03) ) { + WLAN_LOG_DEBUG(3, "802.1h/RFC1042 len: %d\n", payload_length); + /* it's an 802.1h frame || (an RFC1042 && protocol is not in STT) */ + /* build a DIXII + RFC894 */ + + /* Test for an overlength frame */ + if ((payload_length - sizeof(wlan_llc_t) - sizeof(wlan_snap_t)) + > netdev->mtu) { + /* A bogus length ethfrm has been sent. */ + /* Is someone trying an oflow attack? */ + WLAN_LOG_ERROR("DIXII frame too large (%ld > %d)\n", + (long int) (payload_length - sizeof(wlan_llc_t) - + sizeof(wlan_snap_t)), + netdev->mtu); + return 1; + } + + /* chop 802.11 header from skb. */ + skb_pull(skb, payload_offset); + + /* chop llc header from skb. */ + skb_pull(skb, sizeof(wlan_llc_t)); + + /* chop snap header from skb. */ + skb_pull(skb, sizeof(wlan_snap_t)); + + /* create 802.3 header at beginning of skb. */ + e_hdr = (wlan_ethhdr_t *) skb_push(skb, WLAN_ETHHDR_LEN); + e_hdr->type = e_snap->type; + memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN); + memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN); + + /* chop off the 802.11 CRC */ + skb_trim(skb, skb->len - WLAN_CRC_LEN); + } else { + WLAN_LOG_DEBUG(3, "NON-ENCAP len: %d\n", payload_length); + /* any NON-ENCAP */ + /* it's a generic 80211+LLC or IPX 'Raw 802.3' */ + /* build an 802.3 frame */ + /* allocate space and setup hostbuf */ + + /* Test for an overlength frame */ + if ( payload_length > netdev->mtu ) { + /* A bogus length ethfrm has been sent. */ + /* Is someone trying an oflow attack? */ + WLAN_LOG_ERROR("OTHER frame too large (%d > %d)\n", + payload_length, + netdev->mtu); + return 1; + } + + /* Chop off the 802.11 header. */ + skb_pull(skb, payload_offset); + + /* create 802.3 header at beginning of skb. */ + e_hdr = (wlan_ethhdr_t *) skb_push(skb, WLAN_ETHHDR_LEN); + memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN); + memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN); + e_hdr->type = htons(payload_length); + + /* chop off the 802.11 CRC */ + skb_trim(skb, skb->len - WLAN_CRC_LEN); + + } + + /* + * Note that eth_type_trans() expects an skb w/ skb->data pointing + * at the MAC header, it then sets the following skb members: + * skb->mac_header, + * skb->data, and + * skb->pkt_type. + * It then _returns_ the value that _we're_ supposed to stuff in + * skb->protocol. This is nuts. + */ + skb->protocol = eth_type_trans(skb, netdev); + + /* jkriegl: process signal and noise as set in hfa384x_int_rx() */ + /* jkriegl: only process signal/noise if requested by iwspy */ + if (wlandev->spy_number) + orinoco_spy_gather(wlandev, eth_hdr(skb)->h_source, P80211SKB_RXMETA(skb)); + + /* Free the metadata */ + p80211skb_rxmeta_detach(skb); + + DBFEXIT; + return 0; +} + +/*---------------------------------------------------------------- +* p80211_stt_findproto +* +* Searches the 802.1h Selective Translation Table for a given +* protocol. +* +* Arguments: +* proto protocl number (in host order) to search for. +* +* Returns: +* 1 - if the table is empty or a match is found. +* 0 - if the table is non-empty and a match is not found. +* +* Call context: +* May be called in interrupt or non-interrupt context +----------------------------------------------------------------*/ +int p80211_stt_findproto(UINT16 proto) +{ + /* Always return found for now. This is the behavior used by the */ + /* Zoom Win95 driver when 802.1h mode is selected */ + /* TODO: If necessary, add an actual search we'll probably + need this to match the CMAC's way of doing things. + Need to do some testing to confirm. + */ + + if (proto == 0x80f3) /* APPLETALK */ + return 1; + + return 0; +} + +/*---------------------------------------------------------------- +* p80211skb_rxmeta_detach +* +* Disconnects the frmmeta and rxmeta from an skb. +* +* Arguments: +* wlandev The wlandev this skb belongs to. +* skb The skb we're attaching to. +* +* Returns: +* 0 on success, non-zero otherwise +* +* Call context: +* May be called in interrupt or non-interrupt context +----------------------------------------------------------------*/ +void +p80211skb_rxmeta_detach(struct sk_buff *skb) +{ + p80211_rxmeta_t *rxmeta; + p80211_frmmeta_t *frmmeta; + + DBFENTER; + /* Sanity checks */ + if ( skb==NULL ) { /* bad skb */ + WLAN_LOG_DEBUG(1, "Called w/ null skb.\n"); + goto exit; + } + frmmeta = P80211SKB_FRMMETA(skb); + if ( frmmeta == NULL ) { /* no magic */ + WLAN_LOG_DEBUG(1, "Called w/ bad frmmeta magic.\n"); + goto exit; + } + rxmeta = frmmeta->rx; + if ( rxmeta == NULL ) { /* bad meta ptr */ + WLAN_LOG_DEBUG(1, "Called w/ bad rxmeta ptr.\n"); + goto exit; + } + + /* Free rxmeta */ + kfree(rxmeta); + + /* Clear skb->cb */ + memset(skb->cb, 0, sizeof(skb->cb)); +exit: + DBFEXIT; + return; +} + +/*---------------------------------------------------------------- +* p80211skb_rxmeta_attach +* +* Allocates a p80211rxmeta structure, initializes it, and attaches +* it to an skb. +* +* Arguments: +* wlandev The wlandev this skb belongs to. +* skb The skb we're attaching to. +* +* Returns: +* 0 on success, non-zero otherwise +* +* Call context: +* May be called in interrupt or non-interrupt context +----------------------------------------------------------------*/ +int +p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb) +{ + int result = 0; + p80211_rxmeta_t *rxmeta; + p80211_frmmeta_t *frmmeta; + + DBFENTER; + + /* If these already have metadata, we error out! */ + if (P80211SKB_RXMETA(skb) != NULL) { + WLAN_LOG_ERROR("%s: RXmeta already attached!\n", + wlandev->name); + result = 0; + goto exit; + } + + /* Allocate the rxmeta */ + rxmeta = kmalloc(sizeof(p80211_rxmeta_t), GFP_ATOMIC); + + if ( rxmeta == NULL ) { + WLAN_LOG_ERROR("%s: Failed to allocate rxmeta.\n", + wlandev->name); + result = 1; + goto exit; + } + + /* Initialize the rxmeta */ + memset(rxmeta, 0, sizeof(p80211_rxmeta_t)); + rxmeta->wlandev = wlandev; + rxmeta->hosttime = jiffies; + + /* Overlay a frmmeta_t onto skb->cb */ + memset(skb->cb, 0, sizeof(p80211_frmmeta_t)); + frmmeta = (p80211_frmmeta_t*)(skb->cb); + frmmeta->magic = P80211_FRMMETA_MAGIC; + frmmeta->rx = rxmeta; +exit: + DBFEXIT; + return result; +} + +/*---------------------------------------------------------------- +* p80211skb_free +* +* Frees an entire p80211skb by checking and freeing the meta struct +* and then freeing the skb. +* +* Arguments: +* wlandev The wlandev this skb belongs to. +* skb The skb we're attaching to. +* +* Returns: +* 0 on success, non-zero otherwise +* +* Call context: +* May be called in interrupt or non-interrupt context +----------------------------------------------------------------*/ +void +p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb) +{ + p80211_frmmeta_t *meta; + DBFENTER; + meta = P80211SKB_FRMMETA(skb); + if ( meta && meta->rx) { + p80211skb_rxmeta_detach(skb); + } else { + WLAN_LOG_ERROR("Freeing an skb (%p) w/ no frmmeta.\n", skb); + } + + dev_kfree_skb(skb); + DBFEXIT; + return; +} --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/wlan/p80211ioctl.h +++ linux-2.6.27/ubuntu/misc/wireless/p80211/wlan/p80211ioctl.h @@ -0,0 +1,123 @@ +/* src/include/wlan/p80211ioctl.h +* +* Declares constants and types for the p80211 ioctls +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* While this file is called 'ioctl' is purpose goes a little beyond +* that. This file defines the types and contants used to implement +* the p80211 request/confirm/indicate interfaces on Linux. The +* request/confirm interface is, in fact, normally implemented as an +* ioctl. The indicate interface on the other hand, is implemented +* using the Linux 'netlink' interface. +* +* The reason I say that request/confirm is 'normally' implemented +* via ioctl is that we're reserving the right to be able to send +* request commands via the netlink interface. This will be necessary +* if we ever need to send request messages when there aren't any +* wlan network devices present (i.e. sending a message that only p80211 +* cares about. +* -------------------------------------------------------------------- +*/ + + +#ifndef _P80211IOCTL_H +#define _P80211IOCTL_H + +/*================================================================*/ +/* Constants */ + +/*----------------------------------------------------------------*/ +/* p80211 ioctl "request" codes. See argument 2 of ioctl(2). */ + +#define P80211_IFTEST (SIOCDEVPRIVATE + 0) +#define P80211_IFREQ (SIOCDEVPRIVATE + 1) + +/*----------------------------------------------------------------*/ +/* Magic number, a quick test to see we're getting the desired struct */ + +#define P80211_IOCTL_MAGIC (0x4a2d464dUL) + +/*----------------------------------------------------------------*/ +/* Netlink protocol numbers for the indication interface */ + +#define P80211_NL_SOCK_IND NETLINK_USERSOCK + +/*----------------------------------------------------------------*/ +/* Netlink multicast bits for different types of messages */ + +#define P80211_NL_MCAST_GRP_MLME BIT0 /* Local station messages */ +#define P80211_NL_MCAST_GRP_SNIFF BIT1 /* Sniffer messages */ +#define P80211_NL_MCAST_GRP_DIST BIT2 /* Distribution system messages */ + +/*================================================================*/ +/* Macros */ + + +/*================================================================*/ +/* Types */ + +/*----------------------------------------------------------------*/ +/* A ptr to the following structure type is passed as the third */ +/* argument to the ioctl system call when issuing a request to */ +/* the p80211 module. */ + +typedef struct p80211ioctl_req +{ + char name[WLAN_DEVNAMELEN_MAX]; + caddr_t data; + UINT32 magic; + UINT16 len; + UINT32 result; +} __WLAN_ATTRIB_PACK__ p80211ioctl_req_t; + + +/*================================================================*/ +/* Extern Declarations */ + + +/*================================================================*/ +/* Function Declarations */ + + +#endif /* _P80211IOCTL_H */ --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/wlan/p80211msg.h +++ linux-2.6.27/ubuntu/misc/wireless/p80211/wlan/p80211msg.h @@ -0,0 +1,102 @@ +/* src/include/wlan/p80211msg.h +* +* Macros, constants, types, and funcs for req and ind messages +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +*/ + +#ifndef _P80211MSG_H +#define _P80211MSG_H + +/*================================================================*/ +/* System Includes */ + +/*================================================================*/ +/* Project Includes */ + +#ifndef _WLAN_COMPAT_H +#include +#endif + +/*================================================================*/ +/* Constants */ + +#define MSG_BUFF_LEN 4000 +#define WLAN_DEVNAMELEN_MAX 16 + +/*================================================================*/ +/* Macros */ + +/*================================================================*/ +/* Types */ + +/*--------------------------------------------------------------------*/ +/*----- Message Structure Types --------------------------------------*/ + +/*--------------------------------------------------------------------*/ +/* Prototype msg type */ + +typedef struct p80211msg +{ + UINT32 msgcode; + UINT32 msglen; + UINT8 devname[WLAN_DEVNAMELEN_MAX]; +} __WLAN_ATTRIB_PACK__ p80211msg_t; + +typedef struct p80211msgd +{ + UINT32 msgcode; + UINT32 msglen; + UINT8 devname[WLAN_DEVNAMELEN_MAX]; + UINT8 args[0]; +} __WLAN_ATTRIB_PACK__ p80211msgd_t; + +/*================================================================*/ +/* Extern Declarations */ + + +/*================================================================*/ +/* Function Declarations */ + +#endif /* _P80211MSG_H */ + --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/wlan/p80211req.h +++ linux-2.6.27/ubuntu/misc/wireless/p80211/wlan/p80211req.h @@ -0,0 +1,68 @@ +/* src/include/wlan/p80211req.h +* +* Request handling functions +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +*/ + +#ifndef _LINUX_P80211REQ_H +#define _LINUX_P80211REQ_H + +/*================================================================*/ +/* Constants */ + +/*================================================================*/ +/* Macros */ + +/*================================================================*/ +/* Types */ + +/*================================================================*/ +/* Externs */ + +/*================================================================*/ +/* Function Declarations */ + +int p80211req_dorequest(wlandevice_t *wlandev, UINT8 *msgbuf); + +#endif --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/wlan/p80211metastruct.h +++ linux-2.6.27/ubuntu/misc/wireless/p80211/wlan/p80211metastruct.h @@ -0,0 +1,644 @@ +/* This file is GENERATED AUTOMATICALLY. DO NOT EDIT OR MODIFY. +* -------------------------------------------------------------------- +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +*/ + +#ifndef _P80211MKMETASTRUCT_H +#define _P80211MKMETASTRUCT_H + + +typedef struct p80211msg_dot11req_mibget +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_unk392_t mibattribute ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_dot11req_mibget_t; + +typedef struct p80211msg_dot11req_mibset +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_unk392_t mibattribute ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_dot11req_mibset_t; + +typedef struct p80211msg_dot11req_powermgmt +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t powermgmtmode ; + p80211item_uint32_t wakeup ; + p80211item_uint32_t receivedtims ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_dot11req_powermgmt_t; + +typedef struct p80211msg_dot11req_scan +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t bsstype ; + p80211item_pstr6_t bssid ; + UINT8 pad_0C[1] ; + p80211item_pstr32_t ssid ; + UINT8 pad_1D[3] ; + p80211item_uint32_t scantype ; + p80211item_uint32_t probedelay ; + p80211item_pstr14_t channellist ; + UINT8 pad_2C[1] ; + p80211item_uint32_t minchanneltime ; + p80211item_uint32_t maxchanneltime ; + p80211item_uint32_t resultcode ; + p80211item_uint32_t numbss ; + p80211item_uint32_t append ; +} __WLAN_ATTRIB_PACK__ p80211msg_dot11req_scan_t; + +typedef struct p80211msg_dot11req_scan_results +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t bssindex ; + p80211item_uint32_t resultcode ; + p80211item_uint32_t signal ; + p80211item_uint32_t noise ; + p80211item_pstr6_t bssid ; + UINT8 pad_3C[1] ; + p80211item_pstr32_t ssid ; + UINT8 pad_4D[3] ; + p80211item_uint32_t bsstype ; + p80211item_uint32_t beaconperiod ; + p80211item_uint32_t dtimperiod ; + p80211item_uint32_t timestamp ; + p80211item_uint32_t localtime ; + p80211item_uint32_t fhdwelltime ; + p80211item_uint32_t fhhopset ; + p80211item_uint32_t fhhoppattern ; + p80211item_uint32_t fhhopindex ; + p80211item_uint32_t dschannel ; + p80211item_uint32_t cfpcount ; + p80211item_uint32_t cfpperiod ; + p80211item_uint32_t cfpmaxduration ; + p80211item_uint32_t cfpdurremaining ; + p80211item_uint32_t ibssatimwindow ; + p80211item_uint32_t cfpollable ; + p80211item_uint32_t cfpollreq ; + p80211item_uint32_t privacy ; + p80211item_uint32_t basicrate1 ; + p80211item_uint32_t basicrate2 ; + p80211item_uint32_t basicrate3 ; + p80211item_uint32_t basicrate4 ; + p80211item_uint32_t basicrate5 ; + p80211item_uint32_t basicrate6 ; + p80211item_uint32_t basicrate7 ; + p80211item_uint32_t basicrate8 ; + p80211item_uint32_t supprate1 ; + p80211item_uint32_t supprate2 ; + p80211item_uint32_t supprate3 ; + p80211item_uint32_t supprate4 ; + p80211item_uint32_t supprate5 ; + p80211item_uint32_t supprate6 ; + p80211item_uint32_t supprate7 ; + p80211item_uint32_t supprate8 ; +} __WLAN_ATTRIB_PACK__ p80211msg_dot11req_scan_results_t; + +typedef struct p80211msg_dot11req_join +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_pstr6_t bssid ; + UINT8 pad_5C[1] ; + p80211item_uint32_t joinfailuretimeout ; + p80211item_uint32_t basicrate1 ; + p80211item_uint32_t basicrate2 ; + p80211item_uint32_t basicrate3 ; + p80211item_uint32_t basicrate4 ; + p80211item_uint32_t basicrate5 ; + p80211item_uint32_t basicrate6 ; + p80211item_uint32_t basicrate7 ; + p80211item_uint32_t basicrate8 ; + p80211item_uint32_t operationalrate1 ; + p80211item_uint32_t operationalrate2 ; + p80211item_uint32_t operationalrate3 ; + p80211item_uint32_t operationalrate4 ; + p80211item_uint32_t operationalrate5 ; + p80211item_uint32_t operationalrate6 ; + p80211item_uint32_t operationalrate7 ; + p80211item_uint32_t operationalrate8 ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_dot11req_join_t; + +typedef struct p80211msg_dot11req_authenticate +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_pstr6_t peerstaaddress ; + UINT8 pad_6C[1] ; + p80211item_uint32_t authenticationtype ; + p80211item_uint32_t authenticationfailuretimeout ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_dot11req_authenticate_t; + +typedef struct p80211msg_dot11req_deauthenticate +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_pstr6_t peerstaaddress ; + UINT8 pad_7C[1] ; + p80211item_uint32_t reasoncode ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_dot11req_deauthenticate_t; + +typedef struct p80211msg_dot11req_associate +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_pstr6_t peerstaaddress ; + UINT8 pad_8C[1] ; + p80211item_uint32_t associatefailuretimeout ; + p80211item_uint32_t cfpollable ; + p80211item_uint32_t cfpollreq ; + p80211item_uint32_t privacy ; + p80211item_uint32_t listeninterval ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_dot11req_associate_t; + +typedef struct p80211msg_dot11req_reassociate +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_pstr6_t newapaddress ; + UINT8 pad_9C[1] ; + p80211item_uint32_t reassociatefailuretimeout ; + p80211item_uint32_t cfpollable ; + p80211item_uint32_t cfpollreq ; + p80211item_uint32_t privacy ; + p80211item_uint32_t listeninterval ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_dot11req_reassociate_t; + +typedef struct p80211msg_dot11req_disassociate +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_pstr6_t peerstaaddress ; + UINT8 pad_10C[1] ; + p80211item_uint32_t reasoncode ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_dot11req_disassociate_t; + +typedef struct p80211msg_dot11req_reset +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t setdefaultmib ; + p80211item_pstr6_t macaddress ; + UINT8 pad_11C[1] ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_dot11req_reset_t; + +typedef struct p80211msg_dot11req_start +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_pstr32_t ssid ; + UINT8 pad_12D[3] ; + p80211item_uint32_t bsstype ; + p80211item_uint32_t beaconperiod ; + p80211item_uint32_t dtimperiod ; + p80211item_uint32_t cfpperiod ; + p80211item_uint32_t cfpmaxduration ; + p80211item_uint32_t fhdwelltime ; + p80211item_uint32_t fhhopset ; + p80211item_uint32_t fhhoppattern ; + p80211item_uint32_t dschannel ; + p80211item_uint32_t ibssatimwindow ; + p80211item_uint32_t probedelay ; + p80211item_uint32_t cfpollable ; + p80211item_uint32_t cfpollreq ; + p80211item_uint32_t basicrate1 ; + p80211item_uint32_t basicrate2 ; + p80211item_uint32_t basicrate3 ; + p80211item_uint32_t basicrate4 ; + p80211item_uint32_t basicrate5 ; + p80211item_uint32_t basicrate6 ; + p80211item_uint32_t basicrate7 ; + p80211item_uint32_t basicrate8 ; + p80211item_uint32_t operationalrate1 ; + p80211item_uint32_t operationalrate2 ; + p80211item_uint32_t operationalrate3 ; + p80211item_uint32_t operationalrate4 ; + p80211item_uint32_t operationalrate5 ; + p80211item_uint32_t operationalrate6 ; + p80211item_uint32_t operationalrate7 ; + p80211item_uint32_t operationalrate8 ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_dot11req_start_t; + +typedef struct p80211msg_dot11ind_authenticate +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_pstr6_t peerstaaddress ; + UINT8 pad_13C[1] ; + p80211item_uint32_t authenticationtype ; +} __WLAN_ATTRIB_PACK__ p80211msg_dot11ind_authenticate_t; + +typedef struct p80211msg_dot11ind_deauthenticate +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_pstr6_t peerstaaddress ; + UINT8 pad_14C[1] ; + p80211item_uint32_t reasoncode ; +} __WLAN_ATTRIB_PACK__ p80211msg_dot11ind_deauthenticate_t; + +typedef struct p80211msg_dot11ind_associate +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_pstr6_t peerstaaddress ; + UINT8 pad_15C[1] ; + p80211item_uint32_t aid ; +} __WLAN_ATTRIB_PACK__ p80211msg_dot11ind_associate_t; + +typedef struct p80211msg_dot11ind_reassociate +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_pstr6_t peerstaaddress ; + UINT8 pad_16C[1] ; + p80211item_uint32_t aid ; + p80211item_pstr6_t oldapaddress ; + UINT8 pad_17C[1] ; +} __WLAN_ATTRIB_PACK__ p80211msg_dot11ind_reassociate_t; + +typedef struct p80211msg_dot11ind_disassociate +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_pstr6_t peerstaaddress ; + UINT8 pad_18C[1] ; + p80211item_uint32_t reasoncode ; +} __WLAN_ATTRIB_PACK__ p80211msg_dot11ind_disassociate_t; + +typedef struct p80211msg_lnxreq_ifstate +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t ifstate ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_lnxreq_ifstate_t; + +typedef struct p80211msg_lnxreq_wlansniff +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t enable ; + p80211item_uint32_t channel ; + p80211item_uint32_t prismheader ; + p80211item_uint32_t wlanheader ; + p80211item_uint32_t keepwepflags ; + p80211item_uint32_t stripfcs ; + p80211item_uint32_t packet_trunc ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_lnxreq_wlansniff_t; + +typedef struct p80211msg_lnxreq_hostwep +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t resultcode ; + p80211item_uint32_t decrypt ; + p80211item_uint32_t encrypt ; +} __WLAN_ATTRIB_PACK__ p80211msg_lnxreq_hostwep_t; + +typedef struct p80211msg_lnxreq_commsquality +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t resultcode ; + p80211item_uint32_t dbm ; + p80211item_uint32_t link ; + p80211item_uint32_t level ; + p80211item_uint32_t noise ; +} __WLAN_ATTRIB_PACK__ p80211msg_lnxreq_commsquality_t; + +typedef struct p80211msg_lnxreq_autojoin +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_pstr32_t ssid ; + UINT8 pad_19D[3] ; + p80211item_uint32_t authtype ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_lnxreq_autojoin_t; + +typedef struct p80211msg_lnxind_wlansniffrm +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t hosttime ; + p80211item_uint32_t mactime ; + p80211item_uint32_t channel ; + p80211item_uint32_t rssi ; + p80211item_uint32_t sq ; + p80211item_uint32_t signal ; + p80211item_uint32_t noise ; + p80211item_uint32_t rate ; + p80211item_uint32_t istx ; + p80211item_uint32_t frmlen ; +} __WLAN_ATTRIB_PACK__ p80211msg_lnxind_wlansniffrm_t; + +typedef struct p80211msg_lnxind_roam +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t reason ; +} __WLAN_ATTRIB_PACK__ p80211msg_lnxind_roam_t; + +typedef struct p80211msg_p2req_join +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_pstr6_t bssid ; + UINT8 pad_20C[1] ; + p80211item_uint32_t basicrate1 ; + p80211item_uint32_t basicrate2 ; + p80211item_uint32_t basicrate3 ; + p80211item_uint32_t basicrate4 ; + p80211item_uint32_t basicrate5 ; + p80211item_uint32_t basicrate6 ; + p80211item_uint32_t basicrate7 ; + p80211item_uint32_t basicrate8 ; + p80211item_uint32_t operationalrate1 ; + p80211item_uint32_t operationalrate2 ; + p80211item_uint32_t operationalrate3 ; + p80211item_uint32_t operationalrate4 ; + p80211item_uint32_t operationalrate5 ; + p80211item_uint32_t operationalrate6 ; + p80211item_uint32_t operationalrate7 ; + p80211item_uint32_t operationalrate8 ; + p80211item_pstr32_t ssid ; + UINT8 pad_21D[3] ; + p80211item_uint32_t channel ; + p80211item_uint32_t authtype ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_join_t; + +typedef struct p80211msg_p2req_readpda +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_unk1024_t pda ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_readpda_t; + +typedef struct p80211msg_p2req_readcis +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_unk1024_t cis ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_readcis_t; + +typedef struct p80211msg_p2req_auxport_state +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t enable ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_auxport_state_t; + +typedef struct p80211msg_p2req_auxport_read +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t addr ; + p80211item_uint32_t len ; + p80211item_unk1024_t data ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_auxport_read_t; + +typedef struct p80211msg_p2req_auxport_write +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t addr ; + p80211item_uint32_t len ; + p80211item_unk1024_t data ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_auxport_write_t; + +typedef struct p80211msg_p2req_low_level +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t command ; + p80211item_uint32_t param0 ; + p80211item_uint32_t param1 ; + p80211item_uint32_t param2 ; + p80211item_uint32_t resp0 ; + p80211item_uint32_t resp1 ; + p80211item_uint32_t resp2 ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_low_level_t; + +typedef struct p80211msg_p2req_test_command +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t testcode ; + p80211item_uint32_t testparam ; + p80211item_uint32_t resultcode ; + p80211item_uint32_t status ; + p80211item_uint32_t resp0 ; + p80211item_uint32_t resp1 ; + p80211item_uint32_t resp2 ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_test_command_t; + +typedef struct p80211msg_p2req_mmi_read +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t addr ; + p80211item_uint32_t value ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_mmi_read_t; + +typedef struct p80211msg_p2req_mmi_write +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t addr ; + p80211item_uint32_t data ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_mmi_write_t; + +typedef struct p80211msg_p2req_ramdl_state +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t enable ; + p80211item_uint32_t exeaddr ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_ramdl_state_t; + +typedef struct p80211msg_p2req_ramdl_write +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t addr ; + p80211item_uint32_t len ; + p80211item_unk4096_t data ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_ramdl_write_t; + +typedef struct p80211msg_p2req_flashdl_state +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t enable ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_flashdl_state_t; + +typedef struct p80211msg_p2req_flashdl_write +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t addr ; + p80211item_uint32_t len ; + p80211item_unk4096_t data ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_flashdl_write_t; + +typedef struct p80211msg_p2req_mm_state +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t enable ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_mm_state_t; + +typedef struct p80211msg_p2req_dump_state +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t level ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_dump_state_t; + +typedef struct p80211msg_p2req_channel_info +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t channellist ; + p80211item_uint32_t channeldwelltime ; + p80211item_uint32_t resultcode ; + p80211item_uint32_t numchinfo ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_channel_info_t; + +typedef struct p80211msg_p2req_channel_info_results +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t channel ; + p80211item_uint32_t resultcode ; + p80211item_uint32_t avgnoiselevel ; + p80211item_uint32_t peaknoiselevel ; + p80211item_uint32_t bssactive ; + p80211item_uint32_t pcfactive ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_channel_info_results_t; + +typedef struct p80211msg_p2req_enable +{ + UINT32 msgcode ; + UINT32 msglen ; + UINT8 devname[WLAN_DEVNAMELEN_MAX] ; + p80211item_uint32_t resultcode ; +} __WLAN_ATTRIB_PACK__ p80211msg_p2req_enable_t; + +#endif --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/wlan/p80211metamib.h +++ linux-2.6.27/ubuntu/misc/wireless/p80211/wlan/p80211metamib.h @@ -0,0 +1,105 @@ +/* src/include/wlan/p80211metamib.h +* +* Macros, const, types, and funcs for p80211 mib metadata +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* This file declares some of the constants and types used in various +* parts of the linux-wlan system. +* +* Notes: +* - Constant values are always in HOST byte order. +* +* All functions and statics declared here are implemented in p80211types.c +* -------------------------------------------------------------------- +*/ + +#ifndef _P80211METAMIB_H +#define _P80211METAMIB_H + +/*================================================================*/ +/* System Includes */ + +/*================================================================*/ +/* Project Includes */ + +#ifndef _WLAN_COMPAT_H +#include +#endif + +/*================================================================*/ +/* Constants */ + +/*----------------------------------------------------------------*/ +/* */ + +/*================================================================*/ +/* Macros */ + +/*----------------------------------------------------------------*/ +/* */ + +/*================================================================*/ +/* Types */ + +/*----------------------------------------------------------------*/ +/* */ + +/*================================================================*/ +/* Extern Declarations */ + +/*----------------------------------------------------------------*/ +/* The following is the external declaration for the mib */ +/* category metadata list */ + +extern catlistitem_t mib_catlist[]; +extern UINT32 mib_catlist_size; + + +/*================================================================*/ +/* Function Declarations */ + +/*----------------------------------------------------------------*/ +/* */ + +#endif /* _P80211METAMIB_H */ --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/wlan/p80211mgmt.h +++ linux-2.6.27/ubuntu/misc/wireless/p80211/wlan/p80211mgmt.h @@ -0,0 +1,575 @@ +/* src/include/wlan/p80211mgmt.h +* +* Macros, types, and functions to handle 802.11 mgmt frames +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* This file declares the constants and types used in the interface +* between a wlan driver and the user mode utilities. +* +* Notes: +* - Constant values are always in HOST byte order. To assign +* values to multi-byte fields they _must_ be converted to +* ieee byte order. To retrieve multi-byte values from incoming +* frames, they must be converted to host order. +* +* - The len member of the frame structure does NOT!!! include +* the MAC CRC. Therefore, the len field on rx'd frames should +* have 4 subtracted from it. +* +* All functions declared here are implemented in p80211.c +* +* The types, macros, and functions defined here are primarily +* used for encoding and decoding management frames. They are +* designed to follow these patterns of use: +* +* DECODE: +* 1) a frame of length len is received into buffer b +* 2) using the hdr structure and macros, we determine the type +* 3) an appropriate mgmt frame structure, mf, is allocated and zeroed +* 4) mf.hdr = b +* mf.buf = b +* mf.len = len +* 5) call mgmt_decode( mf ) +* 6) the frame field pointers in mf are now set. Note that any +* multi-byte frame field values accessed using the frame field +* pointers are in ieee byte order and will have to be converted +* to host order. +* +* ENCODE: +* 1) Library client allocates buffer space for maximum length +* frame of the desired type +* 2) Library client allocates a mgmt frame structure, called mf, +* of the desired type +* 3) Set the following: +* mf.type = +* mf.buf = +* 4) call mgmt_encode( mf ) +* 5) all of the fixed field pointers and fixed length information element +* pointers in mf are now set to their respective locations in the +* allocated space (fortunately, all variable length information elements +* fall at the end of their respective frames). +* 5a) The length field is set to include the last of the fixed and fixed +* length fields. It may have to be updated for optional or variable +* length information elements. +* 6) Optional and variable length information elements are special cases +* and must be handled individually by the client code. +* -------------------------------------------------------------------- +*/ + +#ifndef _P80211MGMT_H +#define _P80211MGMT_H + +/*================================================================*/ +/* System Includes */ + +/*================================================================*/ +/* Project Includes */ + +#ifndef _WLAN_COMPAT_H +#include +#endif + +#ifndef _P80211HDR_H +#include +#endif + + +/*================================================================*/ +/* Constants */ + +/*-- Information Element IDs --------------------*/ +#define WLAN_EID_SSID 0 +#define WLAN_EID_SUPP_RATES 1 +#define WLAN_EID_FH_PARMS 2 +#define WLAN_EID_DS_PARMS 3 +#define WLAN_EID_CF_PARMS 4 +#define WLAN_EID_TIM 5 +#define WLAN_EID_IBSS_PARMS 6 +/*-- values 7-15 reserved --*/ +#define WLAN_EID_CHALLENGE 16 +/*-- values 17-31 reserved for challenge text extension --*/ +/*-- values 32-255 reserved --*/ + +/*-- Reason Codes -------------------------------*/ +#define WLAN_MGMT_REASON_RSVD 0 +#define WLAN_MGMT_REASON_UNSPEC 1 +#define WLAN_MGMT_REASON_PRIOR_AUTH_INVALID 2 +#define WLAN_MGMT_REASON_DEAUTH_LEAVING 3 +#define WLAN_MGMT_REASON_DISASSOC_INACTIVE 4 +#define WLAN_MGMT_REASON_DISASSOC_AP_BUSY 5 +#define WLAN_MGMT_REASON_CLASS2_NONAUTH 6 +#define WLAN_MGMT_REASON_CLASS3_NONASSOC 7 +#define WLAN_MGMT_REASON_DISASSOC_STA_HASLEFT 8 +#define WLAN_MGMT_REASON_CANT_ASSOC_NONAUTH 9 + +/*-- Status Codes -------------------------------*/ +#define WLAN_MGMT_STATUS_SUCCESS 0 +#define WLAN_MGMT_STATUS_UNSPEC_FAILURE 1 +#define WLAN_MGMT_STATUS_CAPS_UNSUPPORTED 10 +#define WLAN_MGMT_STATUS_REASSOC_NO_ASSOC 11 +#define WLAN_MGMT_STATUS_ASSOC_DENIED_UNSPEC 12 +#define WLAN_MGMT_STATUS_UNSUPPORTED_AUTHALG 13 +#define WLAN_MGMT_STATUS_RX_AUTH_NOSEQ 14 +#define WLAN_MGMT_STATUS_CHALLENGE_FAIL 15 +#define WLAN_MGMT_STATUS_AUTH_TIMEOUT 16 +#define WLAN_MGMT_STATUS_ASSOC_DENIED_BUSY 17 +#define WLAN_MGMT_STATUS_ASSOC_DENIED_RATES 18 + /* p80211b additions */ +#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOSHORT 19 +#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOPBCC 20 +#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOAGILITY 21 + + + +/*-- Auth Algorithm Field ---------------------------*/ +#define WLAN_AUTH_ALG_OPENSYSTEM 0 +#define WLAN_AUTH_ALG_SHAREDKEY 1 + +/*-- Management Frame Field Offsets -------------*/ +/* Note: Not all fields are listed because of variable lengths, */ +/* see the code in p80211.c to see how we search for fields */ +/* Note: These offsets are from the start of the frame data */ + +#define WLAN_BEACON_OFF_TS 0 +#define WLAN_BEACON_OFF_BCN_INT 8 +#define WLAN_BEACON_OFF_CAPINFO 10 +#define WLAN_BEACON_OFF_SSID 12 + +#define WLAN_DISASSOC_OFF_REASON 0 + +#define WLAN_ASSOCREQ_OFF_CAP_INFO 0 +#define WLAN_ASSOCREQ_OFF_LISTEN_INT 2 +#define WLAN_ASSOCREQ_OFF_SSID 4 + +#define WLAN_ASSOCRESP_OFF_CAP_INFO 0 +#define WLAN_ASSOCRESP_OFF_STATUS 2 +#define WLAN_ASSOCRESP_OFF_AID 4 +#define WLAN_ASSOCRESP_OFF_SUPP_RATES 6 + +#define WLAN_REASSOCREQ_OFF_CAP_INFO 0 +#define WLAN_REASSOCREQ_OFF_LISTEN_INT 2 +#define WLAN_REASSOCREQ_OFF_CURR_AP 4 +#define WLAN_REASSOCREQ_OFF_SSID 10 + +#define WLAN_REASSOCRESP_OFF_CAP_INFO 0 +#define WLAN_REASSOCRESP_OFF_STATUS 2 +#define WLAN_REASSOCRESP_OFF_AID 4 +#define WLAN_REASSOCRESP_OFF_SUPP_RATES 6 + +#define WLAN_PROBEREQ_OFF_SSID 0 + +#define WLAN_PROBERESP_OFF_TS 0 +#define WLAN_PROBERESP_OFF_BCN_INT 8 +#define WLAN_PROBERESP_OFF_CAP_INFO 10 +#define WLAN_PROBERESP_OFF_SSID 12 + +#define WLAN_AUTHEN_OFF_AUTH_ALG 0 +#define WLAN_AUTHEN_OFF_AUTH_SEQ 2 +#define WLAN_AUTHEN_OFF_STATUS 4 +#define WLAN_AUTHEN_OFF_CHALLENGE 6 + +#define WLAN_DEAUTHEN_OFF_REASON 0 + + +/*================================================================*/ +/* Macros */ + +/*-- Capability Field ---------------------------*/ +#define WLAN_GET_MGMT_CAP_INFO_ESS(n) ((n) & BIT0) +#define WLAN_GET_MGMT_CAP_INFO_IBSS(n) (((n) & BIT1) >> 1) +#define WLAN_GET_MGMT_CAP_INFO_CFPOLLABLE(n) (((n) & BIT2) >> 2) +#define WLAN_GET_MGMT_CAP_INFO_CFPOLLREQ(n) (((n) & BIT3) >> 3) +#define WLAN_GET_MGMT_CAP_INFO_PRIVACY(n) (((n) & BIT4) >> 4) + /* p80211b additions */ +#define WLAN_GET_MGMT_CAP_INFO_SHORT(n) (((n) & BIT5) >> 5) +#define WLAN_GET_MGMT_CAP_INFO_PBCC(n) (((n) & BIT6) >> 6) +#define WLAN_GET_MGMT_CAP_INFO_AGILITY(n) (((n) & BIT7) >> 7) + +#define WLAN_SET_MGMT_CAP_INFO_ESS(n) (n) +#define WLAN_SET_MGMT_CAP_INFO_IBSS(n) ((n) << 1) +#define WLAN_SET_MGMT_CAP_INFO_CFPOLLABLE(n) ((n) << 2) +#define WLAN_SET_MGMT_CAP_INFO_CFPOLLREQ(n) ((n) << 3) +#define WLAN_SET_MGMT_CAP_INFO_PRIVACY(n) ((n) << 4) + /* p80211b additions */ +#define WLAN_SET_MGMT_CAP_INFO_SHORT(n) ((n) << 5) +#define WLAN_SET_MGMT_CAP_INFO_PBCC(n) ((n) << 6) +#define WLAN_SET_MGMT_CAP_INFO_AGILITY(n) ((n) << 7) + + +/*================================================================*/ +/* Types */ + +/*-- Information Element Types --------------------*/ +/* prototype structure, all IEs start with these members */ + +typedef struct wlan_ie +{ + UINT8 eid; + UINT8 len; +} __WLAN_ATTRIB_PACK__ wlan_ie_t; + +/*-- Service Set Identity (SSID) -----------------*/ +typedef struct wlan_ie_ssid +{ + UINT8 eid; + UINT8 len; + UINT8 ssid[1]; /* may be zero, ptrs may overlap */ +} __WLAN_ATTRIB_PACK__ wlan_ie_ssid_t; + +/*-- Supported Rates -----------------------------*/ +typedef struct wlan_ie_supp_rates +{ + UINT8 eid; + UINT8 len; + UINT8 rates[1]; /* had better be at LEAST one! */ +} __WLAN_ATTRIB_PACK__ wlan_ie_supp_rates_t; + +/*-- FH Parameter Set ----------------------------*/ +typedef struct wlan_ie_fh_parms +{ + UINT8 eid; + UINT8 len; + UINT16 dwell; + UINT8 hopset; + UINT8 hoppattern; + UINT8 hopindex; +} __WLAN_ATTRIB_PACK__ wlan_ie_fh_parms_t; + +/*-- DS Parameter Set ----------------------------*/ +typedef struct wlan_ie_ds_parms +{ + UINT8 eid; + UINT8 len; + UINT8 curr_ch; +} __WLAN_ATTRIB_PACK__ wlan_ie_ds_parms_t; + +/*-- CF Parameter Set ----------------------------*/ + +typedef struct wlan_ie_cf_parms +{ + UINT8 eid; + UINT8 len; + UINT8 cfp_cnt; + UINT8 cfp_period; + UINT16 cfp_maxdur; + UINT16 cfp_durremaining; +} __WLAN_ATTRIB_PACK__ wlan_ie_cf_parms_t; + +/*-- TIM ------------------------------------------*/ +typedef struct wlan_ie_tim +{ + UINT8 eid; + UINT8 len; + UINT8 dtim_cnt; + UINT8 dtim_period; + UINT8 bitmap_ctl; + UINT8 virt_bm[1]; +} __WLAN_ATTRIB_PACK__ wlan_ie_tim_t; + +/*-- IBSS Parameter Set ---------------------------*/ +typedef struct wlan_ie_ibss_parms +{ + UINT8 eid; + UINT8 len; + UINT16 atim_win; +} __WLAN_ATTRIB_PACK__ wlan_ie_ibss_parms_t; + +/*-- Challenge Text ------------------------------*/ +typedef struct wlan_ie_challenge +{ + UINT8 eid; + UINT8 len; + UINT8 challenge[1]; +} __WLAN_ATTRIB_PACK__ wlan_ie_challenge_t; + +/*-------------------------------------------------*/ +/* Frame Types */ + +/* prototype structure, all mgmt frame types will start with these members */ +typedef struct wlan_fr_mgmt +{ + UINT16 type; + UINT16 len; /* DOES NOT include CRC !!!!*/ + UINT8 *buf; + p80211_hdr_t *hdr; + /* used for target specific data, skb in Linux */ + void *priv; + /*-- fixed fields -----------*/ + /*-- info elements ----------*/ +} wlan_fr_mgmt_t; + +/*-- Beacon ---------------------------------------*/ +typedef struct wlan_fr_beacon +{ + UINT16 type; + UINT16 len; + UINT8 *buf; + p80211_hdr_t *hdr; + /* used for target specific data, skb in Linux */ + void *priv; + /*-- fixed fields -----------*/ + UINT64 *ts; + UINT16 *bcn_int; + UINT16 *cap_info; + /*-- info elements ----------*/ + wlan_ie_ssid_t *ssid; + wlan_ie_supp_rates_t *supp_rates; + wlan_ie_fh_parms_t *fh_parms; + wlan_ie_ds_parms_t *ds_parms; + wlan_ie_cf_parms_t *cf_parms; + wlan_ie_ibss_parms_t *ibss_parms; + wlan_ie_tim_t *tim; + +} wlan_fr_beacon_t; + + +/*-- IBSS ATIM ------------------------------------*/ +typedef struct wlan_fr_ibssatim +{ + UINT16 type; + UINT16 len; + UINT8* buf; + p80211_hdr_t *hdr; + /* used for target specific data, skb in Linux */ + void *priv; + + /*-- fixed fields -----------*/ + /*-- info elements ----------*/ + + /* this frame type has a null body */ + +} wlan_fr_ibssatim_t; + +/*-- Disassociation -------------------------------*/ +typedef struct wlan_fr_disassoc +{ + UINT16 type; + UINT16 len; + UINT8 *buf; + p80211_hdr_t *hdr; + /* used for target specific data, skb in Linux */ + void *priv; + /*-- fixed fields -----------*/ + UINT16 *reason; + + /*-- info elements ----------*/ + +} wlan_fr_disassoc_t; + +/*-- Association Request --------------------------*/ +typedef struct wlan_fr_assocreq +{ + UINT16 type; + UINT16 len; + UINT8* buf; + p80211_hdr_t *hdr; + /* used for target specific data, skb in Linux */ + void *priv; + /*-- fixed fields -----------*/ + UINT16 *cap_info; + UINT16 *listen_int; + /*-- info elements ----------*/ + wlan_ie_ssid_t *ssid; + wlan_ie_supp_rates_t *supp_rates; + +} wlan_fr_assocreq_t; + +/*-- Association Response -------------------------*/ +typedef struct wlan_fr_assocresp +{ + UINT16 type; + UINT16 len; + UINT8 *buf; + p80211_hdr_t *hdr; + /* used for target specific data, skb in Linux */ + void *priv; + /*-- fixed fields -----------*/ + UINT16 *cap_info; + UINT16 *status; + UINT16 *aid; + /*-- info elements ----------*/ + wlan_ie_supp_rates_t *supp_rates; + +} wlan_fr_assocresp_t; + +/*-- Reassociation Request ------------------------*/ +typedef struct wlan_fr_reassocreq +{ + UINT16 type; + UINT16 len; + UINT8 *buf; + p80211_hdr_t *hdr; + /* used for target specific data, skb in Linux */ + void *priv; + /*-- fixed fields -----------*/ + UINT16 *cap_info; + UINT16 *listen_int; + UINT8 *curr_ap; + /*-- info elements ----------*/ + wlan_ie_ssid_t *ssid; + wlan_ie_supp_rates_t *supp_rates; + +} wlan_fr_reassocreq_t; + +/*-- Reassociation Response -----------------------*/ +typedef struct wlan_fr_reassocresp +{ + UINT16 type; + UINT16 len; + UINT8 *buf; + p80211_hdr_t *hdr; + /* used for target specific data, skb in Linux */ + void *priv; + /*-- fixed fields -----------*/ + UINT16 *cap_info; + UINT16 *status; + UINT16 *aid; + /*-- info elements ----------*/ + wlan_ie_supp_rates_t *supp_rates; + +} wlan_fr_reassocresp_t; + +/*-- Probe Request --------------------------------*/ +typedef struct wlan_fr_probereq +{ + UINT16 type; + UINT16 len; + UINT8 *buf; + p80211_hdr_t *hdr; + /* used for target specific data, skb in Linux */ + void *priv; + /*-- fixed fields -----------*/ + /*-- info elements ----------*/ + wlan_ie_ssid_t *ssid; + wlan_ie_supp_rates_t *supp_rates; + +} wlan_fr_probereq_t; + +/*-- Probe Response -------------------------------*/ +typedef struct wlan_fr_proberesp +{ + UINT16 type; + UINT16 len; + UINT8 *buf; + p80211_hdr_t *hdr; + /* used for target specific data, skb in Linux */ + void *priv; + /*-- fixed fields -----------*/ + UINT64 *ts; + UINT16 *bcn_int; + UINT16 *cap_info; + /*-- info elements ----------*/ + wlan_ie_ssid_t *ssid; + wlan_ie_supp_rates_t *supp_rates; + wlan_ie_fh_parms_t *fh_parms; + wlan_ie_ds_parms_t *ds_parms; + wlan_ie_cf_parms_t *cf_parms; + wlan_ie_ibss_parms_t *ibss_parms; +} wlan_fr_proberesp_t; + +/*-- Authentication -------------------------------*/ +typedef struct wlan_fr_authen +{ + UINT16 type; + UINT16 len; + UINT8 *buf; + p80211_hdr_t *hdr; + /* used for target specific data, skb in Linux */ + void *priv; + /*-- fixed fields -----------*/ + UINT16 *auth_alg; + UINT16 *auth_seq; + UINT16 *status; + /*-- info elements ----------*/ + wlan_ie_challenge_t *challenge; + +} wlan_fr_authen_t; + +/*-- Deauthenication -----------------------------*/ +typedef struct wlan_fr_deauthen +{ + UINT16 type; + UINT16 len; + UINT8 *buf; + p80211_hdr_t *hdr; + /* used for target specific data, skb in Linux */ + void *priv; + /*-- fixed fields -----------*/ + UINT16 *reason; + + /*-- info elements ----------*/ + +} wlan_fr_deauthen_t; + + +/*================================================================*/ +/* Extern Declarations */ + + +/*================================================================*/ +/* Function Declarations */ + +void wlan_mgmt_encode_beacon( wlan_fr_beacon_t *f ); +void wlan_mgmt_decode_beacon( wlan_fr_beacon_t *f ); +void wlan_mgmt_encode_disassoc( wlan_fr_disassoc_t *f ); +void wlan_mgmt_decode_disassoc( wlan_fr_disassoc_t *f ); +void wlan_mgmt_encode_assocreq( wlan_fr_assocreq_t *f ); +void wlan_mgmt_decode_assocreq( wlan_fr_assocreq_t *f ); +void wlan_mgmt_encode_assocresp( wlan_fr_assocresp_t *f ); +void wlan_mgmt_decode_assocresp( wlan_fr_assocresp_t *f ); +void wlan_mgmt_encode_reassocreq( wlan_fr_reassocreq_t *f ); +void wlan_mgmt_decode_reassocreq( wlan_fr_reassocreq_t *f ); +void wlan_mgmt_encode_reassocresp( wlan_fr_reassocresp_t *f ); +void wlan_mgmt_decode_reassocresp( wlan_fr_reassocresp_t *f ); +void wlan_mgmt_encode_probereq( wlan_fr_probereq_t *f ); +void wlan_mgmt_decode_probereq( wlan_fr_probereq_t *f ); +void wlan_mgmt_encode_proberesp( wlan_fr_proberesp_t *f ); +void wlan_mgmt_decode_proberesp( wlan_fr_proberesp_t *f ); +void wlan_mgmt_encode_authen( wlan_fr_authen_t *f ); +void wlan_mgmt_decode_authen( wlan_fr_authen_t *f ); +void wlan_mgmt_encode_deauthen( wlan_fr_deauthen_t *f ); +void wlan_mgmt_decode_deauthen( wlan_fr_deauthen_t *f ); + + +#endif /* _P80211MGMT_H */ --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/wlan/p80211meta.h +++ linux-2.6.27/ubuntu/misc/wireless/p80211/wlan/p80211meta.h @@ -0,0 +1,169 @@ +/* src/include/wlan/p80211meta.h +* +* Macros, constants, types, and funcs for p80211 metadata +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* This file declares some of the constants and types used in various +* parts of the linux-wlan system. +* +* Notes: +* - Constant values are always in HOST byte order. +* +* All functions and statics declared here are implemented in p80211types.c +* -------------------------------------------------------------------- +*/ + +#ifndef _P80211META_H +#define _P80211META_H + +/*================================================================*/ +/* System Includes */ + +/*================================================================*/ +/* Project Includes */ + +#ifndef _WLAN_COMPAT_H +#include +#endif + +/*================================================================*/ +/* Constants */ + +/*----------------------------------------------------------------*/ +/* */ + +/*================================================================*/ +/* Macros */ + +/*----------------------------------------------------------------*/ +/* The following macros are used to ensure consistent naming */ +/* conventions for all the different metadata lists. */ + +#define MKREQMETANAME(name) p80211meta_ ## req ## _ ## name +#define MKINDMETANAME(name) p80211meta_ ## ind ## _ ## name +#define MKMIBMETANAME(name) p80211meta_ ## mib ## _ ## name +#define MKGRPMETANAME(name) p80211meta_ ## grp ## _ ## name + +#define MKREQMETASIZE(name) p80211meta_ ## req ## _ ## name ## _ ## size +#define MKINDMETASIZE(name) p80211meta_ ## ind ## _ ## name ## _ ## size +#define MKMIBMETASIZE(name) p80211meta_ ## mib ## _ ## name ## _ ## size +#define MKGRPMETASIZE(name) p80211meta_ ## grp ## _ ## name ## _ ## size + +#define GETMETASIZE(aptr) (**((UINT32**)(aptr))) + +/*----------------------------------------------------------------*/ +/* The following ifdef depends on the following defines: */ +/* P80211_NOINCLUDESTRINGS - if defined, all metadata name fields */ +/* are empty strings */ + +#ifdef P80211_NOINCLUDESTRINGS + #define MKITEMNAME(s) ("") +#else + #define MKITEMNAME(s) (s) +#endif + +/*================================================================*/ +/* Types */ + +/*----------------------------------------------------------------*/ +/* The following structure types are used for the metadata */ +/* representation of category list metadata, group list metadata, */ +/* and data item metadata for both Mib and Messages. */ + +typedef struct p80211meta +{ + char *name; /* data item name */ + UINT32 did; /* partial did */ + UINT32 flags; /* set of various flag bits */ + UINT32 min; /* min value of a BOUNDEDINT */ + UINT32 max; /* max value of a BOUNDEDINT */ + + UINT32 maxlen; /* maxlen of a OCTETSTR or DISPLAYSTR */ + UINT32 minlen; /* minlen of a OCTETSTR or DISPLAYSTR */ + p80211enum_t *enumptr; /* ptr to the enum type for ENUMINT */ + p80211_totext_t totextptr; /* ptr to totext conversion function */ + p80211_fromtext_t fromtextptr; /* ptr to totext conversion function */ + p80211_valid_t validfunptr; /* ptr to totext conversion function */ +} p80211meta_t; + +typedef struct grplistitem +{ + char *name; + p80211meta_t *itemlist; +} grplistitem_t; + +typedef struct catlistitem +{ + char *name; + grplistitem_t *grplist; +} catlistitem_t; + +/*================================================================*/ +/* Extern Declarations */ + +/*----------------------------------------------------------------*/ +/* */ + +/*================================================================*/ +/* Function Declarations */ + +/*----------------------------------------------------------------*/ +/* */ +UINT32 p80211_text2did(catlistitem_t *catlist, char *catname, char *grpname, char *itemname); +UINT32 p80211_text2catdid(catlistitem_t *list, char *name ); +UINT32 p80211_text2grpdid(grplistitem_t *list, char *name ); +UINT32 p80211_text2itemdid(p80211meta_t *list, char *name ); +UINT32 p80211_isvalid_did( catlistitem_t *catlist, UINT32 did ); +UINT32 p80211_isvalid_catdid( catlistitem_t *catlist, UINT32 did ); +UINT32 p80211_isvalid_grpdid( catlistitem_t *catlist, UINT32 did ); +UINT32 p80211_isvalid_itemdid( catlistitem_t *catlist, UINT32 did ); +catlistitem_t *p80211_did2cat( catlistitem_t *catlist, UINT32 did ); +grplistitem_t *p80211_did2grp( catlistitem_t *catlist, UINT32 did ); +p80211meta_t *p80211_did2item( catlistitem_t *catlist, UINT32 did ); +UINT32 p80211item_maxdatalen( struct catlistitem *metalist, UINT32 did ); +UINT32 p80211_metaname2did(struct catlistitem *metalist, char *itemname); +UINT32 p80211item_getoffset( struct catlistitem *metalist, UINT32 did ); +int p80211item_gettype(p80211meta_t *meta); + +#endif /* _P80211META_H */ --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/wlan/p80211netdev.h +++ linux-2.6.27/ubuntu/misc/wireless/p80211/wlan/p80211netdev.h @@ -0,0 +1,339 @@ +/* src/include/wlan/p80211netdev.h +* +* WLAN net device structure and functions +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* This file declares the structure type that represents each wlan +* interface. +* +* -------------------------------------------------------------------- +*/ + +#ifndef _LINUX_P80211NETDEV_H +#define _LINUX_P80211NETDEV_H + +#include +#include + +/*================================================================*/ +/* Constants */ + +#define WLAN_DEVICE_CLOSED 0 +#define WLAN_DEVICE_OPEN 1 + +#define WLAN_MACMODE_NONE 0 +#define WLAN_MACMODE_IBSS_STA 1 +#define WLAN_MACMODE_ESS_STA 2 +#define WLAN_MACMODE_ESS_AP 3 + +/* MSD States */ +#define WLAN_MSD_START -1 +#define WLAN_MSD_DRIVERLOADED 0 +#define WLAN_MSD_HWPRESENT_PENDING 1 +#define WLAN_MSD_HWFAIL 2 +#define WLAN_MSD_HWPRESENT 3 +#define WLAN_MSD_FWLOAD_PENDING 4 +#define WLAN_MSD_FWLOAD 5 +#define WLAN_MSD_RUNNING_PENDING 6 +#define WLAN_MSD_RUNNING 7 + +#ifndef ETH_P_ECONET +#define ETH_P_ECONET 0x0018 /* needed for 2.2.x kernels */ +#endif + +#define ETH_P_80211_RAW (ETH_P_ECONET + 1) + +#ifndef ARPHRD_IEEE80211 +#define ARPHRD_IEEE80211 801 /* kernel 2.4.6 */ +#endif + +#ifndef ARPHRD_IEEE80211_PRISM /* kernel 2.4.18 */ +#define ARPHRD_IEEE80211_PRISM 802 +#endif + +/*--- NSD Capabilities Flags ------------------------------*/ +#define P80211_NSDCAP_HARDWAREWEP 0x01 /* hardware wep engine */ +#define P80211_NSDCAP_TIEDWEP 0x02 /* can't decouple en/de */ +#define P80211_NSDCAP_NOHOSTWEP 0x04 /* must use hardware wep */ +#define P80211_NSDCAP_PBCC 0x08 /* hardware supports PBCC */ +#define P80211_NSDCAP_SHORT_PREAMBLE 0x10 /* hardware supports */ +#define P80211_NSDCAP_AGILITY 0x20 /* hardware supports */ +#define P80211_NSDCAP_AP_RETRANSMIT 0x40 /* nsd handles retransmits */ +#define P80211_NSDCAP_HWFRAGMENT 0x80 /* nsd handles frag/defrag */ +#define P80211_NSDCAP_AUTOJOIN 0x100 /* nsd does autojoin */ +#define P80211_NSDCAP_NOSCAN 0x200 /* nsd can scan */ + +/*================================================================*/ +/* Macros */ + +/*================================================================*/ +/* Types */ + +/* Received frame statistics */ +typedef struct p80211_frmrx_t +{ + UINT32 mgmt; + UINT32 assocreq; + UINT32 assocresp; + UINT32 reassocreq; + UINT32 reassocresp; + UINT32 probereq; + UINT32 proberesp; + UINT32 beacon; + UINT32 atim; + UINT32 disassoc; + UINT32 authen; + UINT32 deauthen; + UINT32 mgmt_unknown; + UINT32 ctl; + UINT32 pspoll; + UINT32 rts; + UINT32 cts; + UINT32 ack; + UINT32 cfend; + UINT32 cfendcfack; + UINT32 ctl_unknown; + UINT32 data; + UINT32 dataonly; + UINT32 data_cfack; + UINT32 data_cfpoll; + UINT32 data__cfack_cfpoll; + UINT32 null; + UINT32 cfack; + UINT32 cfpoll; + UINT32 cfack_cfpoll; + UINT32 data_unknown; + UINT32 decrypt; + UINT32 decrypt_err; +} p80211_frmrx_t; + +#ifdef WIRELESS_EXT +/* called by /proc/net/wireless */ +struct iw_statistics* p80211wext_get_wireless_stats(netdevice_t *dev); +/* wireless extensions' ioctls */ +int p80211wext_support_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd); +#if WIRELESS_EXT > 12 +extern struct iw_handler_def p80211wext_handler_def; +#endif + +int p80211wext_event_associated(struct wlandevice *wlandev, int assoc); + +#endif /* wireless extensions */ + +/* WEP stuff */ +#define NUM_WEPKEYS 4 +#define MAX_KEYLEN 32 + +#define HOSTWEP_DEFAULTKEY_MASK (BIT1|BIT0) +#define HOSTWEP_DECRYPT BIT4 +#define HOSTWEP_ENCRYPT BIT5 +#define HOSTWEP_PRIVACYINVOKED BIT6 +#define HOSTWEP_EXCLUDEUNENCRYPTED BIT7 + +extern int wlan_watchdog; +extern int wlan_wext_write; + +/* WLAN device type */ +typedef struct wlandevice +{ + struct wlandevice *next; /* link for list of devices */ + void *priv; /* private data for MSD */ + + /* Subsystem State */ + char name[WLAN_DEVNAMELEN_MAX]; /* Dev name, from register_wlandev()*/ + char *nsdname; + + UINT32 state; /* Device I/F state (open/closed) */ + UINT32 msdstate; /* state of underlying driver */ + UINT32 hwremoved; /* Has the hw been yanked out? */ + + /* Hardware config */ + UINT irq; + UINT iobase; + UINT membase; + UINT32 nsdcaps; /* NSD Capabilities flags */ + + /* Config vars */ + UINT ethconv; + + /* device methods (init by MSD, used by p80211 */ + int (*open)(struct wlandevice *wlandev); + int (*close)(struct wlandevice *wlandev); + void (*reset)(struct wlandevice *wlandev ); + int (*txframe)(struct wlandevice *wlandev, struct sk_buff *skb, p80211_hdr_t *p80211_hdr, p80211_metawep_t *p80211_wep); + int (*mlmerequest)(struct wlandevice *wlandev, p80211msg_t *msg); + int (*set_multicast_list)(struct wlandevice *wlandev, + netdevice_t *dev); + void (*tx_timeout)(struct wlandevice *wlandev); + +#ifdef CONFIG_PROC_FS + int (*nsd_proc_read)(char *page, char **start, off_t offset, int count, int *eof, void *data); +#endif + + /* 802.11 State */ + UINT8 bssid[WLAN_BSSID_LEN]; + p80211pstr32_t ssid; + UINT32 macmode; + int linkstatus; + int shortpreamble; /* C bool */ + + /* WEP State */ + UINT8 wep_keys[NUM_WEPKEYS][MAX_KEYLEN]; + UINT8 wep_keylens[NUM_WEPKEYS]; + int hostwep; + + /* Request/Confirm i/f state (used by p80211) */ + unsigned long request_pending; /* flag, access atomically */ + + /* netlink socket */ + /* queue for indications waiting for cmd completion */ + /* Linux netdevice and support */ + netdevice_t *netdev; /* ptr to linux netdevice */ + struct net_device_stats linux_stats; + +#ifdef CONFIG_PROC_FS + /* Procfs support */ + struct proc_dir_entry *procdir; + struct proc_dir_entry *procwlandev; +#endif + + /* Rx bottom half */ + struct tasklet_struct rx_bh; + + struct sk_buff_head nsd_rxq; + + /* 802.11 device statistics */ + struct p80211_frmrx_t rx; + +/* compatibility to wireless extensions */ +#ifdef WIRELESS_EXT + struct iw_statistics wstats; + + /* jkriegl: iwspy fields */ + UINT8 spy_number; + char spy_address[IW_MAX_SPY][ETH_ALEN]; + struct iw_quality spy_stat[IW_MAX_SPY]; + +#endif + + struct mutex ioctl_lock; +} wlandevice_t; + +/* WEP stuff */ +int wep_change_key(wlandevice_t *wlandev, int keynum, UINT8* key, int keylen); +int wep_decrypt(wlandevice_t *wlandev, UINT8 *buf, UINT32 len, int key_override, UINT8 *iv, UINT8 *icv); +int wep_encrypt(wlandevice_t *wlandev, UINT8 *buf, UINT8 *dst, UINT32 len, int keynum, UINT8 *iv, UINT8 *icv); + +/*================================================================*/ +/* Externs */ + +/*================================================================*/ +/* Function Declarations */ + +void p80211netdev_startup(void); +void p80211netdev_shutdown(void); +int wlan_setup(wlandevice_t *wlandev); +int wlan_unsetup(wlandevice_t *wlandev); +int register_wlandev(wlandevice_t *wlandev); +int unregister_wlandev(wlandevice_t *wlandev); +void p80211netdev_rx(wlandevice_t *wlandev, struct sk_buff *skb); +void p80211netdev_hwremoved(wlandevice_t *wlandev); +void p80211_suspend(wlandevice_t *wlandev); +void p80211_resume(wlandevice_t *wlandev); + +void p80211_allow_ioctls(wlandevice_t *wlandev); + +/*================================================================*/ +/* Function Definitions */ + +static inline void +p80211netdev_stop_queue(wlandevice_t *wlandev) +{ + if ( !wlandev ) return; + if ( !wlandev->netdev ) return; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,38) ) + wlandev->netdev->tbusy = 1; + wlandev->netdev->start = 0; +#else + netif_stop_queue(wlandev->netdev); +#endif +} + +static inline void +p80211netdev_start_queue(wlandevice_t *wlandev) +{ + if ( !wlandev ) return; + if ( !wlandev->netdev ) return; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,38) ) + wlandev->netdev->tbusy = 0; + wlandev->netdev->start = 1; +#else + netif_start_queue(wlandev->netdev); +#endif +} + +static inline void +p80211netdev_wake_queue(wlandevice_t *wlandev) +{ + if ( !wlandev ) return; + if ( !wlandev->netdev ) return; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,38) ) + wlandev->netdev->tbusy = 0; + mark_bh(NET_BH); +#else + netif_wake_queue(wlandev->netdev); +#endif +} + +#ifdef CONFIG_HOTPLUG +#define WLAN_HOTPLUG_REGISTER "register" +#define WLAN_HOTPLUG_REMOVE "remove" +#define WLAN_HOTPLUG_STARTUP "startup" +#define WLAN_HOTPLUG_SHUTDOWN "shutdown" +#define WLAN_HOTPLUG_SUSPEND "suspend" +#define WLAN_HOTPLUG_RESUME "resume" +int p80211_run_sbin_hotplug(wlandevice_t *wlandev, char *action); +#endif + +#endif --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/wlan/p80211conv.h +++ linux-2.6.27/ubuntu/misc/wireless/p80211/wlan/p80211conv.h @@ -0,0 +1,186 @@ +/* src/include/wlan/p80211conv.h +* +* Ether/802.11 conversions and packet buffer routines +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* This file declares the functions, types and macros that perform +* Ethernet to/from 802.11 frame conversions. +* +* -------------------------------------------------------------------- +*/ + +#ifndef _LINUX_P80211CONV_H +#define _LINUX_P80211CONV_H + +/*================================================================*/ +/* Constants */ + +#define WLAN_ETHADDR_LEN 6 +#define WLAN_IEEE_OUI_LEN 3 + +#define WLAN_ETHCONV_ENCAP 1 +#define WLAN_ETHCONV_RFC1042 2 +#define WLAN_ETHCONV_8021h 3 + +#define WLAN_MIN_ETHFRM_LEN 60 +#define WLAN_MAX_ETHFRM_LEN 1514 +#define WLAN_ETHHDR_LEN 14 + +#define P80211CAPTURE_VERSION 0x80211001 + +/*================================================================*/ +/* Macros */ + +#define P80211_FRMMETA_MAGIC 0x802110 + +#define P80211SKB_FRMMETA(s) \ + (((((p80211_frmmeta_t*)((s)->cb))->magic)==P80211_FRMMETA_MAGIC) ? \ + ((p80211_frmmeta_t*)((s)->cb)) : \ + (NULL)) + +#define P80211SKB_RXMETA(s) \ + (P80211SKB_FRMMETA((s)) ? P80211SKB_FRMMETA((s))->rx : ((p80211_rxmeta_t*)(NULL))) + +typedef struct p80211_rxmeta +{ + struct wlandevice *wlandev; + + UINT64 mactime; /* Hi-rez MAC-supplied time value */ + UINT64 hosttime; /* Best-rez host supplied time value */ + + UINT rxrate; /* Receive data rate in 100kbps */ + UINT priority; /* 0-15, 0=contention, 6=CF */ + INT signal; /* An SSI, see p80211netdev.h */ + INT noise; /* An SSI, see p80211netdev.h */ + UINT channel; /* Receive channel (mostly for snifs) */ + UINT preamble; /* P80211ENUM_preambletype_* */ + UINT encoding; /* P80211ENUM_encoding_* */ + +} p80211_rxmeta_t; + +typedef struct p80211_frmmeta +{ + UINT magic; + p80211_rxmeta_t *rx; +} p80211_frmmeta_t; + +void p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb); +int p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb); +void p80211skb_rxmeta_detach(struct sk_buff *skb); + +/*================================================================*/ +/* Types */ + +/* + * Frame capture header. (See doc/capturefrm.txt) + */ +typedef struct p80211_caphdr +{ + UINT32 version; + UINT32 length; + UINT64 mactime; + UINT64 hosttime; + UINT32 phytype; + UINT32 channel; + UINT32 datarate; + UINT32 antenna; + UINT32 priority; + UINT32 ssi_type; + INT32 ssi_signal; + INT32 ssi_noise; + UINT32 preamble; + UINT32 encoding; +} p80211_caphdr_t; + +/* buffer free method pointer type */ +typedef void (* freebuf_method_t)(void *buf, int size); + +typedef struct p80211_metawep { + void *data; + UINT8 iv[4]; + UINT8 icv[4]; +} p80211_metawep_t; + +/* local ether header type */ +typedef struct wlan_ethhdr +{ + UINT8 daddr[WLAN_ETHADDR_LEN]; + UINT8 saddr[WLAN_ETHADDR_LEN]; + UINT16 type; +} __WLAN_ATTRIB_PACK__ wlan_ethhdr_t; + +/* local llc header type */ +typedef struct wlan_llc +{ + UINT8 dsap; + UINT8 ssap; + UINT8 ctl; +} __WLAN_ATTRIB_PACK__ wlan_llc_t; + +/* local snap header type */ +typedef struct wlan_snap +{ + UINT8 oui[WLAN_IEEE_OUI_LEN]; + UINT16 type; +} __WLAN_ATTRIB_PACK__ wlan_snap_t; + +/* Circular include trick */ +struct wlandevice; + +/*================================================================*/ +/* Externs */ + +/*================================================================*/ +/*Function Declarations */ + +int skb_p80211_to_ether( struct wlandevice *wlandev, UINT32 ethconv, + struct sk_buff *skb); +int skb_ether_to_p80211( struct wlandevice *wlandev, UINT32 ethconv, + struct sk_buff *skb, p80211_hdr_t *p80211_hdr, + p80211_metawep_t *p80211_wep ); + +int p80211_stt_findproto(UINT16 proto); +int p80211_stt_addproto(UINT16 proto); + +#endif --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/wlan/p80211hdr.h +++ linux-2.6.27/ubuntu/misc/wireless/p80211/wlan/p80211hdr.h @@ -0,0 +1,299 @@ +/* src/include/wlan/p80211hdr.h +* +* Macros, types, and functions for handling 802.11 MAC headers +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* This file declares the constants and types used in the interface +* between a wlan driver and the user mode utilities. +* +* Note: +* - Constant values are always in HOST byte order. To assign +* values to multi-byte fields they _must_ be converted to +* ieee byte order. To retrieve multi-byte values from incoming +* frames, they must be converted to host order. +* +* All functions declared here are implemented in p80211.c +* -------------------------------------------------------------------- +*/ + +#ifndef _P80211HDR_H +#define _P80211HDR_H + +/*================================================================*/ +/* System Includes */ + +/*================================================================*/ +/* Project Includes */ + +#ifndef _WLAN_COMPAT_H +#include +#endif + + +/*================================================================*/ +/* Constants */ + +/*--- Sizes -----------------------------------------------*/ +#define WLAN_ADDR_LEN 6 +#define WLAN_CRC_LEN 4 +#define WLAN_BSSID_LEN 6 +#define WLAN_BSS_TS_LEN 8 +#define WLAN_HDR_A3_LEN 24 +#define WLAN_HDR_A4_LEN 30 +#define WLAN_SSID_MAXLEN 32 +#define WLAN_DATA_MAXLEN 2312 +#define WLAN_A3FR_MAXLEN (WLAN_HDR_A3_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN) +#define WLAN_A4FR_MAXLEN (WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN) +#define WLAN_BEACON_FR_MAXLEN (WLAN_HDR_A3_LEN + 334) +#define WLAN_ATIM_FR_MAXLEN (WLAN_HDR_A3_LEN + 0) +#define WLAN_DISASSOC_FR_MAXLEN (WLAN_HDR_A3_LEN + 2) +#define WLAN_ASSOCREQ_FR_MAXLEN (WLAN_HDR_A3_LEN + 48) +#define WLAN_ASSOCRESP_FR_MAXLEN (WLAN_HDR_A3_LEN + 16) +#define WLAN_REASSOCREQ_FR_MAXLEN (WLAN_HDR_A3_LEN + 54) +#define WLAN_REASSOCRESP_FR_MAXLEN (WLAN_HDR_A3_LEN + 16) +#define WLAN_PROBEREQ_FR_MAXLEN (WLAN_HDR_A3_LEN + 44) +#define WLAN_PROBERESP_FR_MAXLEN (WLAN_HDR_A3_LEN + 78) +#define WLAN_AUTHEN_FR_MAXLEN (WLAN_HDR_A3_LEN + 261) +#define WLAN_DEAUTHEN_FR_MAXLEN (WLAN_HDR_A3_LEN + 2) +#define WLAN_WEP_NKEYS 4 +#define WLAN_WEP_MAXKEYLEN 13 +#define WLAN_CHALLENGE_IE_LEN 130 +#define WLAN_CHALLENGE_LEN 128 +#define WLAN_WEP_IV_LEN 4 +#define WLAN_WEP_ICV_LEN 4 + +/*--- Frame Control Field -------------------------------------*/ +/* Frame Types */ +#define WLAN_FTYPE_MGMT 0x00 +#define WLAN_FTYPE_CTL 0x01 +#define WLAN_FTYPE_DATA 0x02 + +/* Frame subtypes */ +/* Management */ +#define WLAN_FSTYPE_ASSOCREQ 0x00 +#define WLAN_FSTYPE_ASSOCRESP 0x01 +#define WLAN_FSTYPE_REASSOCREQ 0x02 +#define WLAN_FSTYPE_REASSOCRESP 0x03 +#define WLAN_FSTYPE_PROBEREQ 0x04 +#define WLAN_FSTYPE_PROBERESP 0x05 +#define WLAN_FSTYPE_BEACON 0x08 +#define WLAN_FSTYPE_ATIM 0x09 +#define WLAN_FSTYPE_DISASSOC 0x0a +#define WLAN_FSTYPE_AUTHEN 0x0b +#define WLAN_FSTYPE_DEAUTHEN 0x0c + +/* Control */ +#define WLAN_FSTYPE_BLOCKACKREQ 0x8 +#define WLAN_FSTYPE_BLOCKACK 0x9 +#define WLAN_FSTYPE_PSPOLL 0x0a +#define WLAN_FSTYPE_RTS 0x0b +#define WLAN_FSTYPE_CTS 0x0c +#define WLAN_FSTYPE_ACK 0x0d +#define WLAN_FSTYPE_CFEND 0x0e +#define WLAN_FSTYPE_CFENDCFACK 0x0f + +/* Data */ +#define WLAN_FSTYPE_DATAONLY 0x00 +#define WLAN_FSTYPE_DATA_CFACK 0x01 +#define WLAN_FSTYPE_DATA_CFPOLL 0x02 +#define WLAN_FSTYPE_DATA_CFACK_CFPOLL 0x03 +#define WLAN_FSTYPE_NULL 0x04 +#define WLAN_FSTYPE_CFACK 0x05 +#define WLAN_FSTYPE_CFPOLL 0x06 +#define WLAN_FSTYPE_CFACK_CFPOLL 0x07 + + +/*================================================================*/ +/* Macros */ + +/*--- FC Macros ----------------------------------------------*/ +/* Macros to get/set the bitfields of the Frame Control Field */ +/* GET_FC_??? - takes the host byte-order value of an FC */ +/* and retrieves the value of one of the */ +/* bitfields and moves that value so its lsb is */ +/* in bit 0. */ +/* SET_FC_??? - takes a host order value for one of the FC */ +/* bitfields and moves it to the proper bit */ +/* location for ORing into a host order FC. */ +/* To send the FC produced from SET_FC_???, */ +/* one must put the bytes in IEEE order. */ +/* e.g. */ +/* printf("the frame subtype is %x", */ +/* GET_FC_FTYPE( ieee2host( rx.fc ))) */ +/* */ +/* tx.fc = host2ieee( SET_FC_FTYPE(WLAN_FTYP_CTL) | */ +/* SET_FC_FSTYPE(WLAN_FSTYPE_RTS) ); */ +/*------------------------------------------------------------*/ + +#define WLAN_GET_FC_PVER(n) (((UINT16)(n)) & (BIT0 | BIT1)) +#define WLAN_GET_FC_FTYPE(n) ((((UINT16)(n)) & (BIT2 | BIT3)) >> 2) +#define WLAN_GET_FC_FSTYPE(n) ((((UINT16)(n)) & (BIT4|BIT5|BIT6|BIT7)) >> 4) +#define WLAN_GET_FC_TODS(n) ((((UINT16)(n)) & (BIT8)) >> 8) +#define WLAN_GET_FC_FROMDS(n) ((((UINT16)(n)) & (BIT9)) >> 9) +#define WLAN_GET_FC_MOREFRAG(n) ((((UINT16)(n)) & (BIT10)) >> 10) +#define WLAN_GET_FC_RETRY(n) ((((UINT16)(n)) & (BIT11)) >> 11) +#define WLAN_GET_FC_PWRMGT(n) ((((UINT16)(n)) & (BIT12)) >> 12) +#define WLAN_GET_FC_MOREDATA(n) ((((UINT16)(n)) & (BIT13)) >> 13) +#define WLAN_GET_FC_ISWEP(n) ((((UINT16)(n)) & (BIT14)) >> 14) +#define WLAN_GET_FC_ORDER(n) ((((UINT16)(n)) & (BIT15)) >> 15) + +#define WLAN_SET_FC_PVER(n) ((UINT16)(n)) +#define WLAN_SET_FC_FTYPE(n) (((UINT16)(n)) << 2) +#define WLAN_SET_FC_FSTYPE(n) (((UINT16)(n)) << 4) +#define WLAN_SET_FC_TODS(n) (((UINT16)(n)) << 8) +#define WLAN_SET_FC_FROMDS(n) (((UINT16)(n)) << 9) +#define WLAN_SET_FC_MOREFRAG(n) (((UINT16)(n)) << 10) +#define WLAN_SET_FC_RETRY(n) (((UINT16)(n)) << 11) +#define WLAN_SET_FC_PWRMGT(n) (((UINT16)(n)) << 12) +#define WLAN_SET_FC_MOREDATA(n) (((UINT16)(n)) << 13) +#define WLAN_SET_FC_ISWEP(n) (((UINT16)(n)) << 14) +#define WLAN_SET_FC_ORDER(n) (((UINT16)(n)) << 15) + +/*--- Duration Macros ----------------------------------------*/ +/* Macros to get/set the bitfields of the Duration Field */ +/* - the duration value is only valid when bit15 is zero */ +/* - the firmware handles these values, so I'm not going */ +/* these macros right now. */ +/*------------------------------------------------------------*/ + +/*--- Sequence Control Macros -------------------------------*/ +/* Macros to get/set the bitfields of the Sequence Control */ +/* Field. */ +/*------------------------------------------------------------*/ +#define WLAN_GET_SEQ_FRGNUM(n) (((UINT16)(n)) & (BIT0|BIT1|BIT2|BIT3)) +#define WLAN_GET_SEQ_SEQNUM(n) ((((UINT16)(n)) & (~(BIT0|BIT1|BIT2|BIT3))) >> 4) + +/*--- Data ptr macro -----------------------------------------*/ +/* Creates a UINT8* to the data portion of a frame */ +/* Assumes you're passing in a ptr to the beginning of the hdr*/ +/*------------------------------------------------------------*/ +#define WLAN_HDR_A3_DATAP(p) (((UINT8*)(p)) + WLAN_HDR_A3_LEN) +#define WLAN_HDR_A4_DATAP(p) (((UINT8*)(p)) + WLAN_HDR_A4_LEN) + +#define DOT11_RATE5_ISBASIC_GET(r) (((UINT8)(r)) & BIT7) + +/*================================================================*/ +/* Types */ + +/* BSS Timestamp */ +typedef UINT8 wlan_bss_ts_t[WLAN_BSS_TS_LEN]; + +/* Generic 802.11 Header types */ + +typedef struct p80211_hdr_a3 +{ + UINT16 fc; + UINT16 dur; + UINT8 a1[WLAN_ADDR_LEN]; + UINT8 a2[WLAN_ADDR_LEN]; + UINT8 a3[WLAN_ADDR_LEN]; + UINT16 seq; +} __WLAN_ATTRIB_PACK__ p80211_hdr_a3_t; + +typedef struct p80211_hdr_a4 +{ + UINT16 fc; + UINT16 dur; + UINT8 a1[WLAN_ADDR_LEN]; + UINT8 a2[WLAN_ADDR_LEN]; + UINT8 a3[WLAN_ADDR_LEN]; + UINT16 seq; + UINT8 a4[WLAN_ADDR_LEN]; +} __WLAN_ATTRIB_PACK__ p80211_hdr_a4_t; + +typedef union p80211_hdr +{ + p80211_hdr_a3_t a3; + p80211_hdr_a4_t a4; +} __WLAN_ATTRIB_PACK__ p80211_hdr_t; + + +/*================================================================*/ +/* Extern Declarations */ + + +/*================================================================*/ +/* Function Declarations */ + +/* Frame and header lenght macros */ + +#define WLAN_CTL_FRAMELEN(fstype) (\ + (fstype) == WLAN_FSTYPE_BLOCKACKREQ ? 24 : \ + (fstype) == WLAN_FSTYPE_BLOCKACK ? 152 : \ + (fstype) == WLAN_FSTYPE_PSPOLL ? 20 : \ + (fstype) == WLAN_FSTYPE_RTS ? 20 : \ + (fstype) == WLAN_FSTYPE_CTS ? 14 : \ + (fstype) == WLAN_FSTYPE_ACK ? 14 : \ + (fstype) == WLAN_FSTYPE_CFEND ? 20 : \ + (fstype) == WLAN_FSTYPE_CFENDCFACK ? 20 : 4) + +#define WLAN_FCS_LEN 4 + +/* ftcl in HOST order */ +inline static UINT16 p80211_headerlen(UINT16 fctl) +{ + UINT16 hdrlen = 0; + + switch ( WLAN_GET_FC_FTYPE(fctl) ) { + case WLAN_FTYPE_MGMT: + hdrlen = WLAN_HDR_A3_LEN; + break; + case WLAN_FTYPE_DATA: + hdrlen = WLAN_HDR_A3_LEN; + if ( WLAN_GET_FC_TODS(fctl) && WLAN_GET_FC_FROMDS(fctl) ) { + hdrlen += WLAN_ADDR_LEN; + } + break; + case WLAN_FTYPE_CTL: + hdrlen = WLAN_CTL_FRAMELEN(WLAN_GET_FC_FSTYPE(fctl)) - + WLAN_FCS_LEN; + break; + default: + hdrlen = WLAN_HDR_A3_LEN; + } + + return hdrlen; +} + +#endif /* _P80211HDR_H */ --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/wlan/version.h +++ linux-2.6.27/ubuntu/misc/wireless/p80211/wlan/version.h @@ -0,0 +1,64 @@ +/* src/include/wlan/version.h +* +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +*/ +#ifndef _WLAN_VERSION_H +#define _WLAN_VERSION_H +#ifndef KERNEL_VERSION +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + +/* WLAN_HOSTIF (generally set on the command line, not detected) */ +#define WLAN_NONE 0 +#define WLAN_PCMCIA 1 +#define WLAN_ISA 2 +#define WLAN_PCI 3 +#define WLAN_USB 4 +#define WLAN_PLX 5 +#define WLAN_SLAVE 6 +#define WLAN_RELEASE "0.2.9" +#define WLAN_RELEASE_CODE 0x000209 +#define WLAN_BUILD_DATE "Sun Jul 27 23:23:32 CEST 2008" + +#endif --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/wlan/p80211metamsg.h +++ linux-2.6.27/ubuntu/misc/wireless/p80211/wlan/p80211metamsg.h @@ -0,0 +1,105 @@ +/* src/include/wlan/p80211metamsg.h +* +* Macros, const, types, and funcs for p80211 msg metadata +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* This file declares some of the constants and types used in various +* parts of the linux-wlan system. +* +* Notes: +* - Constant values are always in HOST byte order. +* +* All functions and statics declared here are implemented in p80211types.c +* -------------------------------------------------------------------- +*/ + +#ifndef _P80211METAMSG_H +#define _P80211METAMSG_H + +/*================================================================*/ +/* System Includes */ + +/*================================================================*/ +/* Project Includes */ + +#ifndef _WLAN_COMPAT_H +#include +#endif + +/*================================================================*/ +/* Constants */ + +/*----------------------------------------------------------------*/ +/* */ + +/*================================================================*/ +/* Macros */ + +/*----------------------------------------------------------------*/ +/* */ + +/*================================================================*/ +/* Types */ + +/*----------------------------------------------------------------*/ +/* */ + +/*================================================================*/ +/* Extern Declarations */ + +/*----------------------------------------------------------------*/ +/* The following is the external declaration for the message */ +/* category metadata list */ + +extern catlistitem_t msg_catlist[]; +extern UINT32 msg_catlist_size; + + +/*================================================================*/ +/* Function Declarations */ + +/*----------------------------------------------------------------*/ +/* */ + +#endif /* _P80211METAMSG_H */ --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/wlan/p80211types.h +++ linux-2.6.27/ubuntu/misc/wireless/p80211/wlan/p80211types.h @@ -0,0 +1,675 @@ +/* src/include/wlan/p80211types.h +* +* Macros, constants, types, and funcs for p80211 data types +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* This file declares some of the constants and types used in various +* parts of the linux-wlan system. +* +* Notes: +* - Constant values are always in HOST byte order. +* +* All functions and statics declared here are implemented in p80211types.c +* -------------------------------------------------------------------- +*/ + +#ifndef _P80211TYPES_H +#define _P80211TYPES_H + +/*================================================================*/ +/* System Includes */ +/*================================================================*/ + +/*================================================================*/ +/* Project Includes */ +/*================================================================*/ + +#ifndef _WLAN_COMPAT_H +#include +#endif + +/*================================================================*/ +/* Constants */ +/*================================================================*/ + +/*----------------------------------------------------------------*/ +/* p80211 data type codes used for MIB items and message */ +/* arguments. The various metadata structures provide additional */ +/* information about these types. */ + +#define P80211_TYPE_OCTETSTR 1 /* pascal array of bytes */ +#define P80211_TYPE_DISPLAYSTR 2 /* pascal array of bytes containing ascii */ +#define P80211_TYPE_INT 4 /* UINT32 min and max limited by 32 bits */ +#define P80211_TYPE_ENUMINT 5 /* UINT32 holding a numeric + code that can be mapped + to a textual name */ +#define P80211_TYPE_UNKDATA 6 /* Data item containing an + unknown data type */ +#define P80211_TYPE_INTARRAY 7 /* Array of 32-bit integers. */ +#define P80211_TYPE_BITARRAY 8 /* Array of bits. */ +#define P80211_TYPE_MACARRAY 9 /* Array of MAC addresses. */ + +/*----------------------------------------------------------------*/ +/* The following constants are indexes into the Mib Category List */ +/* and the Message Category List */ + +/* Mib Category List */ +#define P80211_MIB_CAT_DOT11SMT 1 +#define P80211_MIB_CAT_DOT11MAC 2 +#define P80211_MIB_CAT_DOT11PHY 3 + +#define P80211SEC_DOT11SMT P80211_MIB_CAT_DOT11SMT +#define P80211SEC_DOT11MAC P80211_MIB_CAT_DOT11MAC +#define P80211SEC_DOT11PHY P80211_MIB_CAT_DOT11PHY + +/* Message Category List */ +#define P80211_MSG_CAT_DOT11REQ 1 +#define P80211_MSG_CAT_DOT11IND 2 +/* #define P80211_MSG_CAT_DOT11CFM 3 (doesn't exist at this time) */ + +#define P80211SEC_DOT11REQ P80211_MSG_CAT_DOT11REQ +#define P80211SEC_DOT11IND P80211_MSG_CAT_DOT11IND +/* #define P80211SEC_DOT11CFM P80211_MSG_CAT_DOT11CFM (doesn't exist at this time */ + + + +/*----------------------------------------------------------------*/ +/* p80211 DID field codes that represent access type and */ +/* is_table status. */ + +#define P80211DID_ACCESS_READ 0x10000000 +#define P80211DID_ACCESS_WRITE 0x08000000 +#define P80211DID_WRITEONLY 0x00000001 +#define P80211DID_READONLY 0x00000002 +#define P80211DID_READWRITE 0x00000003 +#define P80211DID_ISTABLE_FALSE 0 +#define P80211DID_ISTABLE_TRUE 1 + +/*----------------------------------------------------------------*/ +/* p80211 enumeration constants. The value to text mappings for */ +/* these is in p80211types.c. These defines were generated */ +/* from the mappings. */ + +/* error codes for lookups */ +#define P80211ENUM_BAD 0xffffffffUL +#define P80211ENUM_BADSTR "P80211ENUM_BAD" + +#define P80211ENUM_truth_false 0 +#define P80211ENUM_truth_true 1 +#define P80211ENUM_ifstate_disable 0 +#define P80211ENUM_ifstate_fwload 1 +#define P80211ENUM_ifstate_enable 2 +#define P80211ENUM_powermgmt_active 1 +#define P80211ENUM_powermgmt_powersave 2 +#define P80211ENUM_bsstype_infrastructure 1 +#define P80211ENUM_bsstype_independent 2 +#define P80211ENUM_bsstype_any 3 +#define P80211ENUM_authalg_opensystem 1 +#define P80211ENUM_authalg_sharedkey 2 +#define P80211ENUM_phytype_fhss 1 +#define P80211ENUM_phytype_dsss 2 +#define P80211ENUM_phytype_irbaseband 3 +#define P80211ENUM_temptype_commercial 1 +#define P80211ENUM_temptype_industrial 2 +#define P80211ENUM_regdomain_fcc 16 +#define P80211ENUM_regdomain_doc 32 +#define P80211ENUM_regdomain_etsi 48 +#define P80211ENUM_regdomain_spain 49 +#define P80211ENUM_regdomain_france 50 +#define P80211ENUM_regdomain_mkk 64 +#define P80211ENUM_ccamode_edonly 1 +#define P80211ENUM_ccamode_csonly 2 +#define P80211ENUM_ccamode_edandcs 4 +#define P80211ENUM_ccamode_cswithtimer 8 +#define P80211ENUM_ccamode_hrcsanded 16 +#define P80211ENUM_diversity_fixedlist 1 +#define P80211ENUM_diversity_notsupported 2 +#define P80211ENUM_diversity_dynamic 3 +#define P80211ENUM_scantype_active 1 +#define P80211ENUM_scantype_passive 2 +#define P80211ENUM_scantype_both 3 +#define P80211ENUM_resultcode_success 1 +#define P80211ENUM_resultcode_invalid_parameters 2 +#define P80211ENUM_resultcode_not_supported 3 +#define P80211ENUM_resultcode_timeout 4 +#define P80211ENUM_resultcode_too_many_req 5 +#define P80211ENUM_resultcode_refused 6 +#define P80211ENUM_resultcode_bss_already 7 +#define P80211ENUM_resultcode_invalid_access 8 +#define P80211ENUM_resultcode_invalid_mibattribute 9 +#define P80211ENUM_resultcode_cant_set_readonly_mib 10 +#define P80211ENUM_resultcode_implementation_failure 11 +#define P80211ENUM_resultcode_cant_get_writeonly_mib 12 +#define P80211ENUM_reason_unspec_reason 1 +#define P80211ENUM_reason_auth_not_valid 2 +#define P80211ENUM_reason_deauth_lv_ss 3 +#define P80211ENUM_reason_inactivity 4 +#define P80211ENUM_reason_ap_overload 5 +#define P80211ENUM_reason_class23_err 6 +#define P80211ENUM_reason_class3_err 7 +#define P80211ENUM_reason_disas_lv_ss 8 +#define P80211ENUM_reason_asoc_not_auth 9 +#define P80211ENUM_status_successful 0 +#define P80211ENUM_status_unspec_failure 1 +#define P80211ENUM_status_unsup_cap 10 +#define P80211ENUM_status_reasoc_no_asoc 11 +#define P80211ENUM_status_fail_other 12 +#define P80211ENUM_status_unspt_alg 13 +#define P80211ENUM_status_auth_seq_fail 14 +#define P80211ENUM_status_chlng_fail 15 +#define P80211ENUM_status_auth_timeout 16 +#define P80211ENUM_status_ap_full 17 +#define P80211ENUM_status_unsup_rate 18 +#define P80211ENUM_status_unsup_shortpreamble 19 +#define P80211ENUM_status_unsup_pbcc 20 +#define P80211ENUM_status_unsup_agility 21 +#define P80211ENUM_msgitem_status_data_ok 0 +#define P80211ENUM_msgitem_status_no_value 1 +#define P80211ENUM_msgitem_status_invalid_itemname 2 +#define P80211ENUM_msgitem_status_invalid_itemdata 3 +#define P80211ENUM_msgitem_status_missing_itemdata 4 +#define P80211ENUM_msgitem_status_incomplete_itemdata 5 +#define P80211ENUM_msgitem_status_invalid_msg_did 6 +#define P80211ENUM_msgitem_status_invalid_mib_did 7 +#define P80211ENUM_msgitem_status_missing_conv_func 8 +#define P80211ENUM_msgitem_status_string_too_long 9 +#define P80211ENUM_msgitem_status_data_out_of_range 10 +#define P80211ENUM_msgitem_status_string_too_short 11 +#define P80211ENUM_msgitem_status_missing_valid_func 12 +#define P80211ENUM_msgitem_status_unknown 13 +#define P80211ENUM_msgitem_status_invalid_did 14 +#define P80211ENUM_msgitem_status_missing_print_func 15 + +#define P80211ENUM_lnxroam_reason_unknown 0 +#define P80211ENUM_lnxroam_reason_beacon 1 +#define P80211ENUM_lnxroam_reason_signal 2 +#define P80211ENUM_lnxroam_reason_txretry 3 +#define P80211ENUM_lnxroam_reason_notjoined 4 + +#define P80211ENUM_p2preamble_long 0 +#define P80211ENUM_p2preamble_short 2 +#define P80211ENUM_p2preamble_mixed 3 + +/*----------------------------------------------------------------*/ +/* p80211 max length constants for the different pascal strings. */ + +#define MAXLEN_PSTR6 (6) /* pascal array of 6 bytes */ +#define MAXLEN_PSTR14 (14) /* pascal array of 14 bytes */ +#define MAXLEN_PSTR32 (32) /* pascal array of 32 bytes */ +#define MAXLEN_PSTR255 (255) /* pascal array of 255 bytes */ +#define MAXLEN_MIBATTRIBUTE (392) /* maximum mibattribute */ + /* where the size of the DATA itself */ + /* is a DID-LEN-DATA triple */ + /* with a max size of 4+4+384 */ + +#define P80211_SET_INT(item, value) do { \ + (item).data = (value); \ + (item).status = P80211ENUM_msgitem_status_data_ok; \ + } while(0) +/*----------------------------------------------------------------*/ +/* string constants */ + +#define NOT_SET "NOT_SET" +#define NOT_SUPPORTED "NOT_SUPPORTED" +#define UNKNOWN_DATA "UNKNOWN_DATA" + + +/*--------------------------------------------------------------------*/ +/* Metadata flags */ + +/* MSM: Do these belong in p80211meta.h? I'm not sure. */ + +#define ISREQUIRED (0x80000000UL) +#define ISREQUEST (0x40000000UL) +#define ISCONFIRM (0x20000000UL) + + +/*================================================================*/ +/* Macros */ + +/*--------------------------------------------------------------------*/ +/* The following macros are used to manipulate the 'flags' field in */ +/* the metadata. These are only used when the metadata is for */ +/* command arguments to determine if the data item is required, and */ +/* whether the metadata item is for a request command, confirm */ +/* command or both. */ +/*--------------------------------------------------------------------*/ +/* MSM: Do these belong in p80211meta.h? I'm not sure */ + +#define P80211ITEM_SETFLAGS(q, r, c) ( q | r | c ) + +#define P80211ITEM_ISREQUIRED(flags) (((UINT32)(flags & ISREQUIRED)) >> 31 ) +#define P80211ITEM_ISREQUEST(flags) (((UINT32)(flags & ISREQUEST)) >> 30 ) +#define P80211ITEM_ISCONFIRM(flags) (((UINT32)(flags & ISCONFIRM)) >> 29 ) + +/*----------------------------------------------------------------*/ +/* The following macro creates a name for an enum */ + +#define MKENUMNAME(name) p80211enum_ ## name + +/*---------------------------------------------------------------- +* The following constants and macros are used to construct and +* deconstruct the Data ID codes. The coding is as follows: +* +* ...rwtnnnnnnnniiiiiiggggggssssss s - Section +* g - Group +* i - Item +* n - Index +* t - Table flag +* w - Write flag +* r - Read flag +* . - Unused +*/ + +#define P80211DID_INVALID 0xffffffffUL +#define P80211DID_VALID 0x00000000UL + +#define P80211DID_LSB_SECTION (0) +#define P80211DID_LSB_GROUP (6) +#define P80211DID_LSB_ITEM (12) +#define P80211DID_LSB_INDEX (18) +#define P80211DID_LSB_ISTABLE (26) +#define P80211DID_LSB_ACCESS (27) + +#define P80211DID_MASK_SECTION (0x0000003fUL) +#define P80211DID_MASK_GROUP (0x0000003fUL) +#define P80211DID_MASK_ITEM (0x0000003fUL) +#define P80211DID_MASK_INDEX (0x000000ffUL) +#define P80211DID_MASK_ISTABLE (0x00000001UL) +#define P80211DID_MASK_ACCESS (0x00000003UL) + + +#define P80211DID_MK(a,m,l) ((((UINT32)(a)) & (m)) << (l)) + +#define P80211DID_MKSECTION(a) P80211DID_MK(a, \ + P80211DID_MASK_SECTION, \ + P80211DID_LSB_SECTION ) +#define P80211DID_MKGROUP(a) P80211DID_MK(a, \ + P80211DID_MASK_GROUP, \ + P80211DID_LSB_GROUP ) +#define P80211DID_MKITEM(a) P80211DID_MK(a, \ + P80211DID_MASK_ITEM, \ + P80211DID_LSB_ITEM ) +#define P80211DID_MKINDEX(a) P80211DID_MK(a, \ + P80211DID_MASK_INDEX, \ + P80211DID_LSB_INDEX ) +#define P80211DID_MKISTABLE(a) P80211DID_MK(a, \ + P80211DID_MASK_ISTABLE, \ + P80211DID_LSB_ISTABLE ) + + +#define P80211DID_MKID(s,g,i,n,t,a) (P80211DID_MKSECTION(s) | \ + P80211DID_MKGROUP(g) | \ + P80211DID_MKITEM(i) | \ + P80211DID_MKINDEX(n) | \ + P80211DID_MKISTABLE(t) | \ + (a) ) + + +#define P80211DID_GET(a,m,l) ((((UINT32)(a)) >> (l)) & (m)) + +#define P80211DID_SECTION(a) P80211DID_GET(a, \ + P80211DID_MASK_SECTION, \ + P80211DID_LSB_SECTION) +#define P80211DID_GROUP(a) P80211DID_GET(a, \ + P80211DID_MASK_GROUP, \ + P80211DID_LSB_GROUP) +#define P80211DID_ITEM(a) P80211DID_GET(a, \ + P80211DID_MASK_ITEM, \ + P80211DID_LSB_ITEM) +#define P80211DID_INDEX(a) P80211DID_GET(a, \ + P80211DID_MASK_INDEX, \ + P80211DID_LSB_INDEX) +#define P80211DID_ISTABLE(a) P80211DID_GET(a, \ + P80211DID_MASK_ISTABLE, \ + P80211DID_LSB_ISTABLE) +#define P80211DID_ACCESS(a) P80211DID_GET(a, \ + P80211DID_MASK_ACCESS, \ + P80211DID_LSB_ACCESS) + +/*================================================================*/ +/* Types */ + +/*----------------------------------------------------------------*/ +/* The following structure types are used for the represenation */ +/* of ENUMINT type metadata. */ + +typedef struct p80211enumpair +{ + UINT32 val; + char *name; +} p80211enumpair_t; + +typedef struct p80211enum +{ + INT nitems; + p80211enumpair_t *list; +} p80211enum_t; + +/*----------------------------------------------------------------*/ +/* The following structure types are used to store data items in */ +/* messages. */ + +/* Template pascal string */ +typedef struct p80211pstr +{ + UINT8 len; +} __WLAN_ATTRIB_PACK__ p80211pstr_t; + +typedef struct p80211pstrd +{ + UINT8 len; + UINT8 data[0]; +} __WLAN_ATTRIB_PACK__ p80211pstrd_t; + +/* Maximum pascal string */ +typedef struct p80211pstr255 +{ + UINT8 len; + UINT8 data[MAXLEN_PSTR255]; +} __WLAN_ATTRIB_PACK__ p80211pstr255_t; + +/* pascal string for macaddress and bssid */ +typedef struct p80211pstr6 +{ + UINT8 len; + UINT8 data[MAXLEN_PSTR6]; +} __WLAN_ATTRIB_PACK__ p80211pstr6_t; + +/* pascal string for channel list */ +typedef struct p80211pstr14 +{ + UINT8 len; + UINT8 data[MAXLEN_PSTR14]; +} __WLAN_ATTRIB_PACK__ p80211pstr14_t; + +/* pascal string for ssid */ +typedef struct p80211pstr32 +{ + UINT8 len; + UINT8 data[MAXLEN_PSTR32]; +} __WLAN_ATTRIB_PACK__ p80211pstr32_t; + +/* MAC address array */ +typedef struct p80211macarray +{ + UINT32 cnt; + UINT8 data[1][MAXLEN_PSTR6]; +} __WLAN_ATTRIB_PACK__ p80211macarray_t; + +/* prototype template */ +typedef struct p80211item +{ + UINT32 did; + UINT16 status; + UINT16 len; +} __WLAN_ATTRIB_PACK__ p80211item_t; + +/* prototype template w/ data item */ +typedef struct p80211itemd +{ + UINT32 did; + UINT16 status; + UINT16 len; + UINT8 data[0]; +} __WLAN_ATTRIB_PACK__ p80211itemd_t; + +/* message data item for INT, BOUNDEDINT, ENUMINT */ +typedef struct p80211item_uint32 +{ + UINT32 did; + UINT16 status; + UINT16 len; + UINT32 data; +} __WLAN_ATTRIB_PACK__ p80211item_uint32_t; + +/* message data item for OCTETSTR, DISPLAYSTR */ +typedef struct p80211item_pstr6 +{ + UINT32 did; + UINT16 status; + UINT16 len; + p80211pstr6_t data; +} __WLAN_ATTRIB_PACK__ p80211item_pstr6_t; + +/* message data item for OCTETSTR, DISPLAYSTR */ +typedef struct p80211item_pstr14 +{ + UINT32 did; + UINT16 status; + UINT16 len; + p80211pstr14_t data; +} __WLAN_ATTRIB_PACK__ p80211item_pstr14_t; + +/* message data item for OCTETSTR, DISPLAYSTR */ +typedef struct p80211item_pstr32 +{ + UINT32 did; + UINT16 status; + UINT16 len; + p80211pstr32_t data; +} __WLAN_ATTRIB_PACK__ p80211item_pstr32_t; + +/* message data item for OCTETSTR, DISPLAYSTR */ +typedef struct p80211item_pstr255 +{ + UINT32 did; + UINT16 status; + UINT16 len; + p80211pstr255_t data; +} __WLAN_ATTRIB_PACK__ p80211item_pstr255_t; + +/* message data item for UNK 392, namely mib items */ +typedef struct p80211item_unk392 +{ + UINT32 did; + UINT16 status; + UINT16 len; + UINT8 data[MAXLEN_MIBATTRIBUTE]; +} __WLAN_ATTRIB_PACK__ p80211item_unk392_t; + +/* message data item for UNK 1025, namely p2 pdas */ +typedef struct p80211item_unk1024 +{ + UINT32 did; + UINT16 status; + UINT16 len; + UINT8 data[1024]; +} __WLAN_ATTRIB_PACK__ p80211item_unk1024_t; + +/* message data item for UNK 4096, namely p2 download chunks */ +typedef struct p80211item_unk4096 +{ + UINT32 did; + UINT16 status; + UINT16 len; + UINT8 data[4096]; +} __WLAN_ATTRIB_PACK__ p80211item_unk4096_t; + +struct catlistitem; + +/*----------------------------------------------------------------*/ +/* The following structure type is used to represent all of the */ +/* metadata items. Some components may choose to use more, */ +/* less or different metadata items. */ + +typedef void (*p80211_totext_t)( struct catlistitem *, UINT32 did, UINT8* itembuf, char *textbuf); +typedef void (*p80211_fromtext_t)( struct catlistitem *, UINT32 did, UINT8* itembuf, char *textbuf); +typedef UINT32 (*p80211_valid_t)( struct catlistitem *, UINT32 did, UINT8* itembuf); + + +/*================================================================*/ +/* Extern Declarations */ + +/*----------------------------------------------------------------*/ +/* Enumeration Lists */ +/* The following are the external declarations */ +/* for all enumerations */ + +extern p80211enum_t MKENUMNAME(truth); +extern p80211enum_t MKENUMNAME(ifstate); +extern p80211enum_t MKENUMNAME(powermgmt); +extern p80211enum_t MKENUMNAME(bsstype); +extern p80211enum_t MKENUMNAME(authalg); +extern p80211enum_t MKENUMNAME(phytype); +extern p80211enum_t MKENUMNAME(temptype); +extern p80211enum_t MKENUMNAME(regdomain); +extern p80211enum_t MKENUMNAME(ccamode); +extern p80211enum_t MKENUMNAME(diversity); +extern p80211enum_t MKENUMNAME(scantype); +extern p80211enum_t MKENUMNAME(resultcode); +extern p80211enum_t MKENUMNAME(reason); +extern p80211enum_t MKENUMNAME(status); +extern p80211enum_t MKENUMNAME(msgcode); +extern p80211enum_t MKENUMNAME(msgitem_status); + +extern p80211enum_t MKENUMNAME(lnxroam_reason); + +extern p80211enum_t MKENUMNAME(p2preamble); + +/*================================================================*/ +/* Function Declarations */ + +/*----------------------------------------------------------------*/ +/* The following declare some utility functions for use with the */ +/* p80211enum_t type. */ + +UINT32 p80211enum_text2int(p80211enum_t *ep, char *text); +UINT32 p80211enum_int2text(p80211enum_t *ep, UINT32 val, char *text); +void p80211_error2text(int err_code, char *err_str); + +/*----------------------------------------------------------------*/ +/* The following declare some utility functions for use with the */ +/* p80211item_t and p80211meta_t types. */ + +/*----------------------------------------------------------------*/ +/* The following declare functions that perform validation and */ +/* text to binary conversions based on the metadata for interface */ +/* and MIB data items. */ +/*----------------------------------------------------------------*/ + +/*-- DISPLAYSTR ------------------------------------------------------*/ +/* pstr ==> cstr */ +void p80211_totext_displaystr( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf, char *textbuf ); + +/* cstr ==> pstr */ +void p80211_fromtext_displaystr( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf, char *textbuf ); + +/* function that checks validity of a displaystr binary value */ +UINT32 p80211_isvalid_displaystr( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf ); + +/*-- OCTETSTR --------------------------------------------------------*/ +/* pstr ==> "xx:xx:...." */ +void p80211_totext_octetstr( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf, char *textbuf ); + +/* "xx:xx:...." ==> pstr */ +void p80211_fromtext_octetstr( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf, char *textbuf ); + +/* function that checks validity of an octetstr binary value */ +UINT32 p80211_isvalid_octetstr( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf ); + +/*-- INT -------------------------------------------------------------*/ +/* UINT32 ==> %d */ +void p80211_totext_int( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf, char *textbuf ); + +/* %d ==> UINT32 */ +void p80211_fromtext_int( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf, char *textbuf ); + +/* function that checks validity of an int's binary value (always successful) */ +UINT32 p80211_isvalid_int( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf ); + +/*-- ENUMINT ---------------------------------------------------------*/ +/* UINT32 ==> */ +void p80211_totext_enumint( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf, char *textbuf ); + +/* ==> UINT32 */ +void p80211_fromtext_enumint( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf, char *textbuf ); + +/* function that checks validity of an enum's binary value */ +UINT32 p80211_isvalid_enumint( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf ); + +/*-- INTARRAY --------------------------------------------------------*/ +/* UINT32[] => %d,%d,%d,... */ +void p80211_totext_intarray( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf, char *textbuf ); + +/* %d,%d,%d,... ==> UINT32[] */ +void p80211_fromtext_intarray( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf, char *textbuf ); + +/* function that checks validity of an integer array's value */ +UINT32 p80211_isvalid_intarray( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf ); + +/*-- BITARRAY --------------------------------------------------------*/ +/* UINT32 ==> %d,%d,%d,... */ +void p80211_totext_bitarray( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf, char *textbuf ); + +/* %d,%d,%d,... ==> UINT32 */ +void p80211_fromtext_bitarray( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf, char *textbuf ); + +/* function that checks validity of a bit array's value */ +UINT32 p80211_isvalid_bitarray( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf ); + +/*-- MACARRAY --------------------------------------------------------*/ +void p80211_totext_macarray( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf, char *textbuf ); + +void p80211_fromtext_macarray( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf, char *textbuf ); + +/* function that checks validity of a MAC address array's value */ +UINT32 p80211_isvalid_macarray( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf ); + +/*-- MIBATTRIUBTE ------------------------------------------------------*/ +/* ==> */ +void p80211_totext_getmibattribute( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf, char *textbuf ); +void p80211_totext_setmibattribute( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf, char *textbuf ); + + +/* ==> */ +void p80211_fromtext_getmibattribute( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf, char *textbuf ); +void p80211_fromtext_setmibattribute( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf, char *textbuf ); + +/* function that checks validity of a mibitem's binary value */ +UINT32 p80211_isvalid_getmibattribute( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf ); +UINT32 p80211_isvalid_setmibattribute( struct catlistitem *metalist, UINT32 did, UINT8 *itembuf ); + +#endif /* _P80211TYPES_H */ + --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/wlan/p80211metadef.h +++ linux-2.6.27/ubuntu/misc/wireless/p80211/wlan/p80211metadef.h @@ -0,0 +1,2524 @@ +/* This file is GENERATED AUTOMATICALLY. DO NOT EDIT OR MODIFY. +* -------------------------------------------------------------------- +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +*/ + +#ifndef _P80211MKMETADEF_H +#define _P80211MKMETADEF_H + + +#define DIDmsg_cat_dot11req \ + P80211DID_MKSECTION(1) +#define DIDmsg_dot11req_mibget \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(1)) +#define DIDmsg_dot11req_mibget_mibattribute \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11req_mibget_resultcode \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_dot11req_mibset \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2)) +#define DIDmsg_dot11req_mibset_mibattribute \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11req_mibset_resultcode \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_dot11req_powermgmt \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(3)) +#define DIDmsg_dot11req_powermgmt_powermgmtmode \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11req_powermgmt_wakeup \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_dot11req_powermgmt_receivedtims \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_dot11req_powermgmt_resultcode \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_dot11req_scan \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(4)) +#define DIDmsg_dot11req_scan_bsstype \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11req_scan_bssid \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_dot11req_scan_ssid \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_dot11req_scan_scantype \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_dot11req_scan_probedelay \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(5) | 0x00000000) +#define DIDmsg_dot11req_scan_channellist \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(6) | 0x00000000) +#define DIDmsg_dot11req_scan_minchanneltime \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(7) | 0x00000000) +#define DIDmsg_dot11req_scan_maxchanneltime \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(8) | 0x00000000) +#define DIDmsg_dot11req_scan_resultcode \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(9) | 0x00000000) +#define DIDmsg_dot11req_scan_numbss \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(10) | 0x00000000) +#define DIDmsg_dot11req_scan_append \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(11) | 0x00000000) +#define DIDmsg_dot11req_scan_results \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5)) +#define DIDmsg_dot11req_scan_results_bssindex \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11req_scan_results_resultcode \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_dot11req_scan_results_signal \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_dot11req_scan_results_noise \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_dot11req_scan_results_bssid \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(5) | 0x00000000) +#define DIDmsg_dot11req_scan_results_ssid \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(6) | 0x00000000) +#define DIDmsg_dot11req_scan_results_bsstype \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(7) | 0x00000000) +#define DIDmsg_dot11req_scan_results_beaconperiod \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(8) | 0x00000000) +#define DIDmsg_dot11req_scan_results_dtimperiod \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(9) | 0x00000000) +#define DIDmsg_dot11req_scan_results_timestamp \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(10) | 0x00000000) +#define DIDmsg_dot11req_scan_results_localtime \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(11) | 0x00000000) +#define DIDmsg_dot11req_scan_results_fhdwelltime \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(12) | 0x00000000) +#define DIDmsg_dot11req_scan_results_fhhopset \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(13) | 0x00000000) +#define DIDmsg_dot11req_scan_results_fhhoppattern \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(14) | 0x00000000) +#define DIDmsg_dot11req_scan_results_fhhopindex \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(15) | 0x00000000) +#define DIDmsg_dot11req_scan_results_dschannel \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(16) | 0x00000000) +#define DIDmsg_dot11req_scan_results_cfpcount \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(17) | 0x00000000) +#define DIDmsg_dot11req_scan_results_cfpperiod \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(18) | 0x00000000) +#define DIDmsg_dot11req_scan_results_cfpmaxduration \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(19) | 0x00000000) +#define DIDmsg_dot11req_scan_results_cfpdurremaining \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(20) | 0x00000000) +#define DIDmsg_dot11req_scan_results_ibssatimwindow \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(21) | 0x00000000) +#define DIDmsg_dot11req_scan_results_cfpollable \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(22) | 0x00000000) +#define DIDmsg_dot11req_scan_results_cfpollreq \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(23) | 0x00000000) +#define DIDmsg_dot11req_scan_results_privacy \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(24) | 0x00000000) +#define DIDmsg_dot11req_scan_results_basicrate1 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(25) | 0x00000000) +#define DIDmsg_dot11req_scan_results_basicrate2 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(26) | 0x00000000) +#define DIDmsg_dot11req_scan_results_basicrate3 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(27) | 0x00000000) +#define DIDmsg_dot11req_scan_results_basicrate4 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(28) | 0x00000000) +#define DIDmsg_dot11req_scan_results_basicrate5 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(29) | 0x00000000) +#define DIDmsg_dot11req_scan_results_basicrate6 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(30) | 0x00000000) +#define DIDmsg_dot11req_scan_results_basicrate7 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(31) | 0x00000000) +#define DIDmsg_dot11req_scan_results_basicrate8 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(32) | 0x00000000) +#define DIDmsg_dot11req_scan_results_supprate1 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(33) | 0x00000000) +#define DIDmsg_dot11req_scan_results_supprate2 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(34) | 0x00000000) +#define DIDmsg_dot11req_scan_results_supprate3 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(35) | 0x00000000) +#define DIDmsg_dot11req_scan_results_supprate4 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(36) | 0x00000000) +#define DIDmsg_dot11req_scan_results_supprate5 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(37) | 0x00000000) +#define DIDmsg_dot11req_scan_results_supprate6 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(38) | 0x00000000) +#define DIDmsg_dot11req_scan_results_supprate7 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(39) | 0x00000000) +#define DIDmsg_dot11req_scan_results_supprate8 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(40) | 0x00000000) +#define DIDmsg_dot11req_join \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6)) +#define DIDmsg_dot11req_join_bssid \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11req_join_joinfailuretimeout \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_dot11req_join_basicrate1 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_dot11req_join_basicrate2 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_dot11req_join_basicrate3 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(5) | 0x00000000) +#define DIDmsg_dot11req_join_basicrate4 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(6) | 0x00000000) +#define DIDmsg_dot11req_join_basicrate5 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(7) | 0x00000000) +#define DIDmsg_dot11req_join_basicrate6 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(8) | 0x00000000) +#define DIDmsg_dot11req_join_basicrate7 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(9) | 0x00000000) +#define DIDmsg_dot11req_join_basicrate8 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(10) | 0x00000000) +#define DIDmsg_dot11req_join_operationalrate1 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(11) | 0x00000000) +#define DIDmsg_dot11req_join_operationalrate2 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(12) | 0x00000000) +#define DIDmsg_dot11req_join_operationalrate3 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(13) | 0x00000000) +#define DIDmsg_dot11req_join_operationalrate4 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(14) | 0x00000000) +#define DIDmsg_dot11req_join_operationalrate5 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(15) | 0x00000000) +#define DIDmsg_dot11req_join_operationalrate6 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(16) | 0x00000000) +#define DIDmsg_dot11req_join_operationalrate7 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(17) | 0x00000000) +#define DIDmsg_dot11req_join_operationalrate8 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(18) | 0x00000000) +#define DIDmsg_dot11req_join_resultcode \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(19) | 0x00000000) +#define DIDmsg_dot11req_authenticate \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(7)) +#define DIDmsg_dot11req_authenticate_peerstaaddress \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11req_authenticate_authenticationtype \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_dot11req_authenticate_authenticationfailuretimeout \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_dot11req_authenticate_resultcode \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_dot11req_deauthenticate \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(8)) +#define DIDmsg_dot11req_deauthenticate_peerstaaddress \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(8) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11req_deauthenticate_reasoncode \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(8) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_dot11req_deauthenticate_resultcode \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(8) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_dot11req_associate \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(9)) +#define DIDmsg_dot11req_associate_peerstaaddress \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(9) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11req_associate_associatefailuretimeout \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(9) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_dot11req_associate_cfpollable \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(9) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_dot11req_associate_cfpollreq \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(9) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_dot11req_associate_privacy \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(9) | \ + P80211DID_MKITEM(5) | 0x00000000) +#define DIDmsg_dot11req_associate_listeninterval \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(9) | \ + P80211DID_MKITEM(6) | 0x00000000) +#define DIDmsg_dot11req_associate_resultcode \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(9) | \ + P80211DID_MKITEM(7) | 0x00000000) +#define DIDmsg_dot11req_reassociate \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(10)) +#define DIDmsg_dot11req_reassociate_newapaddress \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(10) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11req_reassociate_reassociatefailuretimeout \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(10) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_dot11req_reassociate_cfpollable \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(10) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_dot11req_reassociate_cfpollreq \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(10) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_dot11req_reassociate_privacy \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(10) | \ + P80211DID_MKITEM(5) | 0x00000000) +#define DIDmsg_dot11req_reassociate_listeninterval \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(10) | \ + P80211DID_MKITEM(6) | 0x00000000) +#define DIDmsg_dot11req_reassociate_resultcode \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(10) | \ + P80211DID_MKITEM(7) | 0x00000000) +#define DIDmsg_dot11req_disassociate \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(11)) +#define DIDmsg_dot11req_disassociate_peerstaaddress \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(11) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11req_disassociate_reasoncode \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(11) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_dot11req_disassociate_resultcode \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(11) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_dot11req_reset \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(12)) +#define DIDmsg_dot11req_reset_setdefaultmib \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(12) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11req_reset_macaddress \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(12) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_dot11req_reset_resultcode \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(12) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_dot11req_start \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13)) +#define DIDmsg_dot11req_start_ssid \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11req_start_bsstype \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_dot11req_start_beaconperiod \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_dot11req_start_dtimperiod \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_dot11req_start_cfpperiod \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(5) | 0x00000000) +#define DIDmsg_dot11req_start_cfpmaxduration \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(6) | 0x00000000) +#define DIDmsg_dot11req_start_fhdwelltime \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(7) | 0x00000000) +#define DIDmsg_dot11req_start_fhhopset \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(8) | 0x00000000) +#define DIDmsg_dot11req_start_fhhoppattern \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(9) | 0x00000000) +#define DIDmsg_dot11req_start_dschannel \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(10) | 0x00000000) +#define DIDmsg_dot11req_start_ibssatimwindow \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(11) | 0x00000000) +#define DIDmsg_dot11req_start_probedelay \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(12) | 0x00000000) +#define DIDmsg_dot11req_start_cfpollable \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(13) | 0x00000000) +#define DIDmsg_dot11req_start_cfpollreq \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(14) | 0x00000000) +#define DIDmsg_dot11req_start_basicrate1 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(15) | 0x00000000) +#define DIDmsg_dot11req_start_basicrate2 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(16) | 0x00000000) +#define DIDmsg_dot11req_start_basicrate3 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(17) | 0x00000000) +#define DIDmsg_dot11req_start_basicrate4 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(18) | 0x00000000) +#define DIDmsg_dot11req_start_basicrate5 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(19) | 0x00000000) +#define DIDmsg_dot11req_start_basicrate6 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(20) | 0x00000000) +#define DIDmsg_dot11req_start_basicrate7 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(21) | 0x00000000) +#define DIDmsg_dot11req_start_basicrate8 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(22) | 0x00000000) +#define DIDmsg_dot11req_start_operationalrate1 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(23) | 0x00000000) +#define DIDmsg_dot11req_start_operationalrate2 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(24) | 0x00000000) +#define DIDmsg_dot11req_start_operationalrate3 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(25) | 0x00000000) +#define DIDmsg_dot11req_start_operationalrate4 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(26) | 0x00000000) +#define DIDmsg_dot11req_start_operationalrate5 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(27) | 0x00000000) +#define DIDmsg_dot11req_start_operationalrate6 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(28) | 0x00000000) +#define DIDmsg_dot11req_start_operationalrate7 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(29) | 0x00000000) +#define DIDmsg_dot11req_start_operationalrate8 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(30) | 0x00000000) +#define DIDmsg_dot11req_start_resultcode \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(31) | 0x00000000) +#define DIDmsg_cat_dot11ind \ + P80211DID_MKSECTION(2) +#define DIDmsg_dot11ind_authenticate \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(1)) +#define DIDmsg_dot11ind_authenticate_peerstaaddress \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11ind_authenticate_authenticationtype \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_dot11ind_deauthenticate \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(2)) +#define DIDmsg_dot11ind_deauthenticate_peerstaaddress \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11ind_deauthenticate_reasoncode \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_dot11ind_associate \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3)) +#define DIDmsg_dot11ind_associate_peerstaaddress \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11ind_associate_aid \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_dot11ind_reassociate \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(4)) +#define DIDmsg_dot11ind_reassociate_peerstaaddress \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11ind_reassociate_aid \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_dot11ind_reassociate_oldapaddress \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_dot11ind_disassociate \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(5)) +#define DIDmsg_dot11ind_disassociate_peerstaaddress \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11ind_disassociate_reasoncode \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_cat_lnxreq \ + P80211DID_MKSECTION(3) +#define DIDmsg_lnxreq_ifstate \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(1)) +#define DIDmsg_lnxreq_ifstate_ifstate \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_lnxreq_ifstate_resultcode \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_lnxreq_wlansniff \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(2)) +#define DIDmsg_lnxreq_wlansniff_enable \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_lnxreq_wlansniff_channel \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_lnxreq_wlansniff_prismheader \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_lnxreq_wlansniff_wlanheader \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_lnxreq_wlansniff_keepwepflags \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(5) | 0x00000000) +#define DIDmsg_lnxreq_wlansniff_stripfcs \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(6) | 0x00000000) +#define DIDmsg_lnxreq_wlansniff_packet_trunc \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(7) | 0x00000000) +#define DIDmsg_lnxreq_wlansniff_resultcode \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(8) | 0x00000000) +#define DIDmsg_lnxreq_hostwep \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(3)) +#define DIDmsg_lnxreq_hostwep_resultcode \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_lnxreq_hostwep_decrypt \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_lnxreq_hostwep_encrypt \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_lnxreq_commsquality \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(4)) +#define DIDmsg_lnxreq_commsquality_resultcode \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_lnxreq_commsquality_dbm \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_lnxreq_commsquality_link \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_lnxreq_commsquality_level \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_lnxreq_commsquality_noise \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(5) | 0x00000000) +#define DIDmsg_lnxreq_autojoin \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(5)) +#define DIDmsg_lnxreq_autojoin_ssid \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_lnxreq_autojoin_authtype \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_lnxreq_autojoin_resultcode \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_cat_lnxind \ + P80211DID_MKSECTION(4) +#define DIDmsg_lnxind_wlansniffrm \ + (P80211DID_MKSECTION(4) | \ + P80211DID_MKGROUP(1)) +#define DIDmsg_lnxind_wlansniffrm_hosttime \ + (P80211DID_MKSECTION(4) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_lnxind_wlansniffrm_mactime \ + (P80211DID_MKSECTION(4) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_lnxind_wlansniffrm_channel \ + (P80211DID_MKSECTION(4) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_lnxind_wlansniffrm_rssi \ + (P80211DID_MKSECTION(4) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_lnxind_wlansniffrm_sq \ + (P80211DID_MKSECTION(4) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(5) | 0x00000000) +#define DIDmsg_lnxind_wlansniffrm_signal \ + (P80211DID_MKSECTION(4) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(6) | 0x00000000) +#define DIDmsg_lnxind_wlansniffrm_noise \ + (P80211DID_MKSECTION(4) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(7) | 0x00000000) +#define DIDmsg_lnxind_wlansniffrm_rate \ + (P80211DID_MKSECTION(4) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(8) | 0x00000000) +#define DIDmsg_lnxind_wlansniffrm_istx \ + (P80211DID_MKSECTION(4) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(9) | 0x00000000) +#define DIDmsg_lnxind_wlansniffrm_frmlen \ + (P80211DID_MKSECTION(4) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(10) | 0x00000000) +#define DIDmsg_lnxind_roam \ + (P80211DID_MKSECTION(4) | \ + P80211DID_MKGROUP(2)) +#define DIDmsg_lnxind_roam_reason \ + (P80211DID_MKSECTION(4) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_cat_p2req \ + P80211DID_MKSECTION(5) +#define DIDmsg_p2req_join \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1)) +#define DIDmsg_p2req_join_bssid \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_join_basicrate1 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_join_basicrate2 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_p2req_join_basicrate3 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_p2req_join_basicrate4 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(5) | 0x00000000) +#define DIDmsg_p2req_join_basicrate5 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(6) | 0x00000000) +#define DIDmsg_p2req_join_basicrate6 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(7) | 0x00000000) +#define DIDmsg_p2req_join_basicrate7 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(8) | 0x00000000) +#define DIDmsg_p2req_join_basicrate8 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(9) | 0x00000000) +#define DIDmsg_p2req_join_operationalrate1 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(10) | 0x00000000) +#define DIDmsg_p2req_join_operationalrate2 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(11) | 0x00000000) +#define DIDmsg_p2req_join_operationalrate3 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(12) | 0x00000000) +#define DIDmsg_p2req_join_operationalrate4 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(13) | 0x00000000) +#define DIDmsg_p2req_join_operationalrate5 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(14) | 0x00000000) +#define DIDmsg_p2req_join_operationalrate6 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(15) | 0x00000000) +#define DIDmsg_p2req_join_operationalrate7 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(16) | 0x00000000) +#define DIDmsg_p2req_join_operationalrate8 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(17) | 0x00000000) +#define DIDmsg_p2req_join_ssid \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(18) | 0x00000000) +#define DIDmsg_p2req_join_channel \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(19) | 0x00000000) +#define DIDmsg_p2req_join_authtype \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(20) | 0x00000000) +#define DIDmsg_p2req_join_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(21) | 0x00000000) +#define DIDmsg_p2req_readpda \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2)) +#define DIDmsg_p2req_readpda_pda \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_readpda_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_readcis \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3)) +#define DIDmsg_p2req_readcis_cis \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_readcis_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_auxport_state \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(4)) +#define DIDmsg_p2req_auxport_state_enable \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_auxport_state_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_auxport_read \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5)) +#define DIDmsg_p2req_auxport_read_addr \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_auxport_read_len \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_auxport_read_data \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_p2req_auxport_read_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_p2req_auxport_write \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6)) +#define DIDmsg_p2req_auxport_write_addr \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_auxport_write_len \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_auxport_write_data \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_p2req_auxport_write_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_p2req_low_level \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(7)) +#define DIDmsg_p2req_low_level_command \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_low_level_param0 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_low_level_param1 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_p2req_low_level_param2 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_p2req_low_level_resp0 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(5) | 0x00000000) +#define DIDmsg_p2req_low_level_resp1 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(6) | 0x00000000) +#define DIDmsg_p2req_low_level_resp2 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(7) | 0x00000000) +#define DIDmsg_p2req_low_level_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(8) | 0x00000000) +#define DIDmsg_p2req_test_command \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(8)) +#define DIDmsg_p2req_test_command_testcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(8) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_test_command_testparam \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(8) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_test_command_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(8) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_p2req_test_command_status \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(8) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_p2req_test_command_resp0 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(8) | \ + P80211DID_MKITEM(5) | 0x00000000) +#define DIDmsg_p2req_test_command_resp1 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(8) | \ + P80211DID_MKITEM(6) | 0x00000000) +#define DIDmsg_p2req_test_command_resp2 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(8) | \ + P80211DID_MKITEM(7) | 0x00000000) +#define DIDmsg_p2req_mmi_read \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(9)) +#define DIDmsg_p2req_mmi_read_addr \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(9) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_mmi_read_value \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(9) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_mmi_read_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(9) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_p2req_mmi_write \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(10)) +#define DIDmsg_p2req_mmi_write_addr \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(10) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_mmi_write_data \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(10) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_mmi_write_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(10) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_p2req_ramdl_state \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(11)) +#define DIDmsg_p2req_ramdl_state_enable \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(11) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_ramdl_state_exeaddr \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(11) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_ramdl_state_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(11) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_p2req_ramdl_write \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(12)) +#define DIDmsg_p2req_ramdl_write_addr \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(12) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_ramdl_write_len \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(12) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_ramdl_write_data \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(12) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_p2req_ramdl_write_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(12) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_p2req_flashdl_state \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(13)) +#define DIDmsg_p2req_flashdl_state_enable \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_flashdl_state_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(13) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_flashdl_write \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(14)) +#define DIDmsg_p2req_flashdl_write_addr \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(14) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_flashdl_write_len \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(14) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_flashdl_write_data \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(14) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_p2req_flashdl_write_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(14) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_p2req_mm_state \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(15)) +#define DIDmsg_p2req_mm_state_enable \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(15) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_mm_state_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(15) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_dump_state \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(16)) +#define DIDmsg_p2req_dump_state_level \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(16) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_dump_state_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(16) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_channel_info \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(17)) +#define DIDmsg_p2req_channel_info_channellist \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(17) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_channel_info_channeldwelltime \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(17) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_channel_info_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(17) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_p2req_channel_info_numchinfo \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(17) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_p2req_channel_info_results \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(18)) +#define DIDmsg_p2req_channel_info_results_channel \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(18) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_channel_info_results_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(18) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_channel_info_results_avgnoiselevel \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(18) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_p2req_channel_info_results_peaknoiselevel \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(18) | \ + P80211DID_MKITEM(4) | 0x00000000) +#define DIDmsg_p2req_channel_info_results_bssactive \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(18) | \ + P80211DID_MKITEM(5) | 0x00000000) +#define DIDmsg_p2req_channel_info_results_pcfactive \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(18) | \ + P80211DID_MKITEM(6) | 0x00000000) +#define DIDmsg_p2req_enable \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(19)) +#define DIDmsg_p2req_enable_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(19) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmib_cat_dot11smt \ + P80211DID_MKSECTION(1) +#define DIDmib_dot11smt_p80211Table \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(1)) +#define DIDmib_dot11smt_p80211Table_p80211_ifstate \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(1) | 0x10000000) +#define DIDmib_dot11smt_dot11StationConfigTable \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2)) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11StationID \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(1) | 0x18000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11MediumOccupancyLimit \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(2) | 0x18000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11CFPollable \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(3) | 0x10000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11CFPPeriod \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(4) | 0x18000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11CFPMaxDuration \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(5) | 0x18000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11AuthenticationResponseTimeOut \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(6) | 0x18000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11PrivacyOptionImplemented \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(7) | 0x10000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11PowerManagementMode \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(8) | 0x18000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11DesiredSSID \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(9) | 0x18000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11DesiredBSSType \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(10) | 0x18000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11OperationalRateSet \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(11) | 0x18000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11BeaconPeriod \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(12) | 0x18000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11DTIMPeriod \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(13) | 0x18000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11AssociationResponseTimeOut \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(14) | 0x10000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11DisassociateReason \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(15) | 0x10000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11DisassociateStation \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(16) | 0x10000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11DeauthenticateReason \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(17) | 0x10000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11DeauthenticateStation \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(18) | 0x10000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11AuthenticateFailStatus \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(19) | 0x10000000) +#define DIDmib_dot11smt_dot11StationConfigTable_dot11AuthenticateFailStation \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(20) | 0x10000000) +#define DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(3)) +#define DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithm1 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(1) | 0x14000000) +#define DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithmsEnable1 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(2) | 0x1c000000) +#define DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithm2 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(3) | 0x14000000) +#define DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithmsEnable2 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(4) | 0x1c000000) +#define DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithm3 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(5) | 0x14000000) +#define DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithmsEnable3 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(6) | 0x1c000000) +#define DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithm4 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(7) | 0x14000000) +#define DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithmsEnable4 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(8) | 0x1c000000) +#define DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithm5 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(9) | 0x14000000) +#define DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithmsEnable5 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(10) | 0x1c000000) +#define DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithm6 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(11) | 0x14000000) +#define DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithmsEnable6 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(12) | 0x1c000000) +#define DIDmib_dot11smt_dot11WEPDefaultKeysTable \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(4)) +#define DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(1) | 0x0c000000) +#define DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(2) | 0x0c000000) +#define DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(3) | 0x0c000000) +#define DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3 \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(4) | 0x0c000000) +#define DIDmib_dot11smt_dot11WEPKeyMappingsTable \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5)) +#define DIDmib_dot11smt_dot11WEPKeyMappingsTable_dot11WEPKeyMappingIndex \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(1) | 0x1c000000) +#define DIDmib_dot11smt_dot11WEPKeyMappingsTable_dot11WEPKeyMappingAddress \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(2) | 0x1c000000) +#define DIDmib_dot11smt_dot11WEPKeyMappingsTable_dot11WEPKeyMappingWEPOn \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(3) | 0x1c000000) +#define DIDmib_dot11smt_dot11WEPKeyMappingsTable_dot11WEPKeyMappingValue \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(4) | 0x1c000000) +#define DIDmib_dot11smt_dot11PrivacyTable \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6)) +#define DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(1) | 0x18000000) +#define DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(2) | 0x18000000) +#define DIDmib_dot11smt_dot11PrivacyTable_dot11WEPKeyMappingLength \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(3) | 0x18000000) +#define DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(4) | 0x18000000) +#define DIDmib_dot11smt_dot11PrivacyTable_dot11WEPICVErrorCount \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(5) | 0x10000000) +#define DIDmib_dot11smt_dot11PrivacyTable_dot11WEPExcludedCount \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(6) | 0x10000000) +#define DIDmib_cat_dot11mac \ + P80211DID_MKSECTION(2) +#define DIDmib_dot11mac_dot11OperationTable \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(1)) +#define DIDmib_dot11mac_dot11OperationTable_dot11MACAddress \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(1) | 0x18000000) +#define DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(2) | 0x18000000) +#define DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(3) | 0x10000000) +#define DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(4) | 0x10000000) +#define DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(5) | 0x18000000) +#define DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(6) | 0x10000000) +#define DIDmib_dot11mac_dot11OperationTable_dot11MaxReceiveLifetime \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(7) | 0x10000000) +#define DIDmib_dot11mac_dot11OperationTable_dot11ManufacturerID \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(8) | 0x10000000) +#define DIDmib_dot11mac_dot11OperationTable_dot11ProductID \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(9) | 0x10000000) +#define DIDmib_dot11mac_dot11CountersTable \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(2)) +#define DIDmib_dot11mac_dot11CountersTable_dot11TransmittedFragmentCount \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(1) | 0x10000000) +#define DIDmib_dot11mac_dot11CountersTable_dot11MulticastTransmittedFrameCount \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(2) | 0x10000000) +#define DIDmib_dot11mac_dot11CountersTable_dot11FailedCount \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(3) | 0x10000000) +#define DIDmib_dot11mac_dot11CountersTable_dot11RetryCount \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(4) | 0x10000000) +#define DIDmib_dot11mac_dot11CountersTable_dot11MultipleRetryCount \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(5) | 0x10000000) +#define DIDmib_dot11mac_dot11CountersTable_dot11FrameDuplicateCount \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(6) | 0x10000000) +#define DIDmib_dot11mac_dot11CountersTable_dot11RTSSuccessCount \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(7) | 0x10000000) +#define DIDmib_dot11mac_dot11CountersTable_dot11RTSFailureCount \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(8) | 0x10000000) +#define DIDmib_dot11mac_dot11CountersTable_dot11ACKFailureCount \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(9) | 0x10000000) +#define DIDmib_dot11mac_dot11CountersTable_dot11ReceivedFragmentCount \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(10) | 0x10000000) +#define DIDmib_dot11mac_dot11CountersTable_dot11MulticastReceivedFrameCount \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(11) | 0x10000000) +#define DIDmib_dot11mac_dot11CountersTable_dot11FCSErrorCount \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(12) | 0x10000000) +#define DIDmib_dot11mac_dot11CountersTable_dot11TransmittedFrameCount \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(13) | 0x10000000) +#define DIDmib_dot11mac_dot11CountersTable_dot11WEPUndecryptableCount \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(14) | 0x10000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3)) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address1 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(1) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address2 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(2) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address3 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(3) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address4 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(4) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address5 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(5) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address6 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(6) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address7 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(7) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address8 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(8) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address9 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(9) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address10 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(10) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address11 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(11) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address12 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(12) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address13 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(13) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address14 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(14) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address15 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(15) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address16 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(16) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address17 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(17) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address18 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(18) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address19 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(19) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address20 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(20) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address21 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(21) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address22 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(22) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address23 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(23) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address24 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(24) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address25 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(25) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address26 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(26) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address27 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(27) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address28 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(28) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address29 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(29) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address30 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(30) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address31 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(31) | 0x1c000000) +#define DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address32 \ + (P80211DID_MKSECTION(2) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(32) | 0x1c000000) +#define DIDmib_cat_dot11phy \ + P80211DID_MKSECTION(3) +#define DIDmib_dot11phy_dot11PhyOperationTable \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(1)) +#define DIDmib_dot11phy_dot11PhyOperationTable_dot11PHYType \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(1) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyOperationTable_dot11CurrentRegDomain \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(2) | 0x18000000) +#define DIDmib_dot11phy_dot11PhyOperationTable_dot11TempType \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(3) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyOperationTable_dot11ChannelAgilityPresent \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(4) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyOperationTable_dot11ChannelAgilityEnabled \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(5) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyOperationTable_dot11ShortPreambleEnabled \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(6) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyAntennaTable \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(2)) +#define DIDmib_dot11phy_dot11PhyAntennaTable_dot11CurrentTxAntenna \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(1) | 0x18000000) +#define DIDmib_dot11phy_dot11PhyAntennaTable_dot11DiversitySupport \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(2) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyAntennaTable_dot11CurrentRxAntenna \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(3) | 0x18000000) +#define DIDmib_dot11phy_dot11PhyTxPowerTable \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(3)) +#define DIDmib_dot11phy_dot11PhyTxPowerTable_dot11NumberSupportedPowerLevels \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(1) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel1 \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(2) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel2 \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(3) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel3 \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(4) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel4 \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(5) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel5 \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(6) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel6 \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(7) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel7 \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(8) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel8 \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(9) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(10) | 0x18000000) +#define DIDmib_dot11phy_dot11PhyFHSSTable \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(4)) +#define DIDmib_dot11phy_dot11PhyFHSSTable_dot11HopTime \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(1) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyFHSSTable_dot11CurrentChannelNumber \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(2) | 0x18000000) +#define DIDmib_dot11phy_dot11PhyFHSSTable_dot11MaxDwellTime \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(3) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyFHSSTable_dot11CurrentDwellTime \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(4) | 0x18000000) +#define DIDmib_dot11phy_dot11PhyFHSSTable_dot11CurrentSet \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(5) | 0x18000000) +#define DIDmib_dot11phy_dot11PhyFHSSTable_dot11CurrentPattern \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(6) | 0x18000000) +#define DIDmib_dot11phy_dot11PhyFHSSTable_dot11CurrentIndex \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(7) | 0x18000000) +#define DIDmib_dot11phy_dot11PhyDSSSTable \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(5)) +#define DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(1) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyDSSSTable_dot11CCAModeSupported \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(2) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentCCAMode \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(3) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyDSSSTable_dot11EDThreshold \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(4) | 0x18000000) +#define DIDmib_dot11phy_dot11PhyDSSSTable_dot11ShortPreambleOptionImplemented \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(5) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyDSSSTable_dot11PBCCOptionImplemented \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(6) | 0x10000000) +#define DIDmib_dot11phy_dot11PhyIRTable \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(6)) +#define DIDmib_dot11phy_dot11PhyIRTable_dot11CCAWatchdogTimerMax \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(1) | 0x18000000) +#define DIDmib_dot11phy_dot11PhyIRTable_dot11CCAWatchdogCountMax \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(2) | 0x18000000) +#define DIDmib_dot11phy_dot11PhyIRTable_dot11CCAWatchdogTimerMin \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(3) | 0x18000000) +#define DIDmib_dot11phy_dot11PhyIRTable_dot11CCAWatchdogCountMin \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(4) | 0x18000000) +#define DIDmib_dot11phy_dot11RegDomainsSupportedTable \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(7)) +#define DIDmib_dot11phy_dot11RegDomainsSupportedTable_dot11RegDomainsSupportIndex \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(1) | 0x1c000000) +#define DIDmib_dot11phy_dot11RegDomainsSupportedTable_dot11RegDomainsSupportValue \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(2) | 0x14000000) +#define DIDmib_dot11phy_dot11AntennasListTable \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(8)) +#define DIDmib_dot11phy_dot11AntennasListTable_dot11AntennaListIndex \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(8) | \ + P80211DID_MKITEM(1) | 0x1c000000) +#define DIDmib_dot11phy_dot11AntennasListTable_dot11SupportedTxAntenna \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(8) | \ + P80211DID_MKITEM(2) | 0x1c000000) +#define DIDmib_dot11phy_dot11AntennasListTable_dot11SupportedRxAntenna \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(8) | \ + P80211DID_MKITEM(3) | 0x1c000000) +#define DIDmib_dot11phy_dot11AntennasListTable_dot11DiversitySelectionRx \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(8) | \ + P80211DID_MKITEM(4) | 0x1c000000) +#define DIDmib_dot11phy_dot11SupportedDataRatesTxTable \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(9)) +#define DIDmib_dot11phy_dot11SupportedDataRatesTxTable_dot11SupportedDataRatesTxIndex \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(9) | \ + P80211DID_MKITEM(1) | 0x1c000000) +#define DIDmib_dot11phy_dot11SupportedDataRatesTxTable_dot11SupportedDataRatesTxValue \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(9) | \ + P80211DID_MKITEM(2) | 0x14000000) +#define DIDmib_dot11phy_dot11SupportedDataRatesRxTable \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(10)) +#define DIDmib_dot11phy_dot11SupportedDataRatesRxTable_dot11SupportedDataRatesRxIndex \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(10) | \ + P80211DID_MKITEM(1) | 0x1c000000) +#define DIDmib_dot11phy_dot11SupportedDataRatesRxTable_dot11SupportedDataRatesRxValue \ + (P80211DID_MKSECTION(3) | \ + P80211DID_MKGROUP(10) | \ + P80211DID_MKITEM(2) | 0x14000000) +#define DIDmib_cat_lnx \ + P80211DID_MKSECTION(4) +#define DIDmib_lnx_lnxConfigTable \ + (P80211DID_MKSECTION(4) | \ + P80211DID_MKGROUP(1)) +#define DIDmib_lnx_lnxConfigTable_lnxRSNAIE \ + (P80211DID_MKSECTION(4) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(1) | 0x18000000) +#define DIDmib_cat_p2 \ + P80211DID_MKSECTION(5) +#define DIDmib_p2_p2Table \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1)) +#define DIDmib_p2_p2Table_p2MMTx \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(1) | 0x18000000) +#define DIDmib_p2_p2Table_p2EarlyBeacon \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(2) | 0x18000000) +#define DIDmib_p2_p2Table_p2ReceivedFrameStatistics \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(3) | 0x10000000) +#define DIDmib_p2_p2Table_p2CommunicationTallies \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(4) | 0x10000000) +#define DIDmib_p2_p2Table_p2Authenticated \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(5) | 0x10000000) +#define DIDmib_p2_p2Table_p2Associated \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(6) | 0x10000000) +#define DIDmib_p2_p2Table_p2PowerSaveUserCount \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(7) | 0x10000000) +#define DIDmib_p2_p2Table_p2Comment \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(8) | 0x18000000) +#define DIDmib_p2_p2Table_p2AccessMode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(9) | 0x18000000) +#define DIDmib_p2_p2Table_p2AccessAllow \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(10) | 0x18000000) +#define DIDmib_p2_p2Table_p2AccessDeny \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(11) | 0x18000000) +#define DIDmib_p2_p2Table_p2ChannelInfoResults \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(12) | 0x10000000) +#define DIDmib_p2_p2Static \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2)) +#define DIDmib_p2_p2Static_p2CnfPortType \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(1) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfOwnMACAddress \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(2) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfDesiredSSID \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(3) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfOwnChannel \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(4) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfOwnSSID \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(5) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfOwnATIMWindow \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(6) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfSystemScale \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(7) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfMaxDataLength \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(8) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfWDSAddress \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(9) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfPMEnabled \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(10) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfPMEPS \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(11) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfMulticastReceive \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(12) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfMaxSleepDuration \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(13) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfPMHoldoverDuration \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(14) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfOwnName \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(15) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfOwnDTIMPeriod \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(16) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfWDSAddress1 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(17) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfWDSAddress2 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(18) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfWDSAddress3 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(19) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfWDSAddress4 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(20) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfWDSAddress5 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(21) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfWDSAddress6 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(22) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfMulticastPMBuffering \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(23) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfWEPDefaultKeyID \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(24) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfWEPDefaultKey0 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(25) | 0x08000000) +#define DIDmib_p2_p2Static_p2CnfWEPDefaultKey1 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(26) | 0x08000000) +#define DIDmib_p2_p2Static_p2CnfWEPDefaultKey2 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(27) | 0x08000000) +#define DIDmib_p2_p2Static_p2CnfWEPDefaultKey3 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(28) | 0x08000000) +#define DIDmib_p2_p2Static_p2CnfWEPFlags \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(29) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfAuthentication \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(30) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfMaxAssociatedStations \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(31) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfTxControl \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(32) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfRoamingMode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(33) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfHostAuthentication \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(34) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfRcvCrcError \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(35) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfAltRetryCount \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(36) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfBeaconInterval \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(37) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfMediumOccupancyLimit \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(38) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfCFPPeriod \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(39) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfCFPMaxDuration \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(40) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfCFPFlags \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(41) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfSTAPCFInfo \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(42) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfPriorityQUsage \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(43) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfTIMCtrl \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(44) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfThirty2Tally \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(45) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfEnhSecurity \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(46) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfShortPreamble \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(47) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfExcludeLongPreamble \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(48) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfAuthenticationRspTO \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(49) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfBasicRates \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(50) | 0x18000000) +#define DIDmib_p2_p2Static_p2CnfSupportedRates \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(51) | 0x18000000) +#define DIDmib_p2_p2Dynamic \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3)) +#define DIDmib_p2_p2Dynamic_p2CreateIBSS \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(1) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2FragmentationThreshold \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(2) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2RTSThreshold \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(3) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2TxRateControl \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(4) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2PromiscuousMode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(5) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2FragmentationThreshold0 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(6) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2FragmentationThreshold1 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(7) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2FragmentationThreshold2 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(8) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2FragmentationThreshold3 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(9) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2FragmentationThreshold4 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(10) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2FragmentationThreshold5 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(11) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2FragmentationThreshold6 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(12) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2RTSThreshold0 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(13) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2RTSThreshold1 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(14) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2RTSThreshold2 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(15) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2RTSThreshold3 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(16) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2RTSThreshold4 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(17) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2RTSThreshold5 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(18) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2RTSThreshold6 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(19) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2TxRateControl0 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(20) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2TxRateControl1 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(21) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2TxRateControl2 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(22) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2TxRateControl3 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(23) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2TxRateControl4 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(24) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2TxRateControl5 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(25) | 0x18000000) +#define DIDmib_p2_p2Dynamic_p2TxRateControl6 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(3) | \ + P80211DID_MKITEM(26) | 0x18000000) +#define DIDmib_p2_p2Behavior \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(4)) +#define DIDmib_p2_p2Behavior_p2TickTime \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(4) | \ + P80211DID_MKITEM(1) | 0x18000000) +#define DIDmib_p2_p2NIC \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5)) +#define DIDmib_p2_p2NIC_p2MaxLoadTime \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(1) | 0x10000000) +#define DIDmib_p2_p2NIC_p2DLBufferPage \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(2) | 0x10000000) +#define DIDmib_p2_p2NIC_p2DLBufferOffset \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(3) | 0x10000000) +#define DIDmib_p2_p2NIC_p2DLBufferLength \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(4) | 0x10000000) +#define DIDmib_p2_p2NIC_p2PRIIdentity \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(5) | 0x10000000) +#define DIDmib_p2_p2NIC_p2PRISupRange \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(6) | 0x10000000) +#define DIDmib_p2_p2NIC_p2CFIActRanges \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(7) | 0x10000000) +#define DIDmib_p2_p2NIC_p2NICSerialNumber \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(8) | 0x10000000) +#define DIDmib_p2_p2NIC_p2NICIdentity \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(9) | 0x10000000) +#define DIDmib_p2_p2NIC_p2MFISupRange \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(10) | 0x10000000) +#define DIDmib_p2_p2NIC_p2CFISupRange \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(11) | 0x10000000) +#define DIDmib_p2_p2NIC_p2ChannelList \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(12) | 0x10000000) +#define DIDmib_p2_p2NIC_p2RegulatoryDomains \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(13) | 0x10000000) +#define DIDmib_p2_p2NIC_p2TempType \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(14) | 0x10000000) +#define DIDmib_p2_p2NIC_p2STAIdentity \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(15) | 0x10000000) +#define DIDmib_p2_p2NIC_p2STASupRange \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(16) | 0x10000000) +#define DIDmib_p2_p2NIC_p2MFIActRanges \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(17) | 0x10000000) +#define DIDmib_p2_p2NIC_p2STACFIActRanges \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(18) | 0x10000000) +#define DIDmib_p2_p2NIC_p2BuildSequence \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(19) | 0x10000000) +#define DIDmib_p2_p2NIC_p2PrimaryFWID \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(20) | 0x10000000) +#define DIDmib_p2_p2NIC_p2SecondaryFWID \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(21) | 0x10000000) +#define DIDmib_p2_p2NIC_p2TertiaryFWID \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(22) | 0x10000000) +#define DIDmib_p2_p2MAC \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6)) +#define DIDmib_p2_p2MAC_p2PortStatus \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(1) | 0x10000000) +#define DIDmib_p2_p2MAC_p2CurrentSSID \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(2) | 0x10000000) +#define DIDmib_p2_p2MAC_p2CurrentBSSID \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(3) | 0x10000000) +#define DIDmib_p2_p2MAC_p2CommsQuality \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(4) | 0x10000000) +#define DIDmib_p2_p2MAC_p2CommsQualityCQ \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(5) | 0x10000000) +#define DIDmib_p2_p2MAC_p2CommsQualityASL \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(6) | 0x10000000) +#define DIDmib_p2_p2MAC_p2CommsQualityANL \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(7) | 0x10000000) +#define DIDmib_p2_p2MAC_p2dbmCommsQuality \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(8) | 0x10000000) +#define DIDmib_p2_p2MAC_p2dbmCommsQualityCQ \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(9) | 0x10000000) +#define DIDmib_p2_p2MAC_p2dbmCommsQualityASL \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(10) | 0x10000000) +#define DIDmib_p2_p2MAC_p2dbmCommsQualityANL \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(11) | 0x10000000) +#define DIDmib_p2_p2MAC_p2CurrentTxRate \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(12) | 0x10000000) +#define DIDmib_p2_p2MAC_p2CurrentBeaconInterval \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(13) | 0x10000000) +#define DIDmib_p2_p2MAC_p2StaCurrentScaleThresholds \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(14) | 0x10000000) +#define DIDmib_p2_p2MAC_p2APCurrentScaleThresholds \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(15) | 0x10000000) +#define DIDmib_p2_p2MAC_p2ProtocolRspTime \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(16) | 0x10000000) +#define DIDmib_p2_p2MAC_p2ShortRetryLimit \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(17) | 0x10000000) +#define DIDmib_p2_p2MAC_p2LongRetryLimit \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(18) | 0x10000000) +#define DIDmib_p2_p2MAC_p2MaxTransmitLifetime \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(19) | 0x10000000) +#define DIDmib_p2_p2MAC_p2MaxReceiveLifetime \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(20) | 0x10000000) +#define DIDmib_p2_p2MAC_p2CFPollable \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(21) | 0x10000000) +#define DIDmib_p2_p2MAC_p2AuthenticationAlgorithms \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(22) | 0x10000000) +#define DIDmib_p2_p2MAC_p2PrivacyOptionImplemented \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(23) | 0x10000000) +#define DIDmib_p2_p2MAC_p2CurrentTxRate1 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(24) | 0x10000000) +#define DIDmib_p2_p2MAC_p2CurrentTxRate2 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(25) | 0x10000000) +#define DIDmib_p2_p2MAC_p2CurrentTxRate3 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(26) | 0x10000000) +#define DIDmib_p2_p2MAC_p2CurrentTxRate4 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(27) | 0x10000000) +#define DIDmib_p2_p2MAC_p2CurrentTxRate5 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(28) | 0x10000000) +#define DIDmib_p2_p2MAC_p2CurrentTxRate6 \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(29) | 0x10000000) +#define DIDmib_p2_p2MAC_p2OwnMACAddress \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(6) | \ + P80211DID_MKITEM(30) | 0x10000000) +#define DIDmib_p2_p2Modem \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(7)) +#define DIDmib_p2_p2Modem_p2PHYType \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(1) | 0x10000000) +#define DIDmib_p2_p2Modem_p2CurrentChannel \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(2) | 0x10000000) +#define DIDmib_p2_p2Modem_p2CurrentPowerState \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(3) | 0x10000000) +#define DIDmib_p2_p2Modem_p2CCAMode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(4) | 0x10000000) +#define DIDmib_p2_p2Modem_p2SupportedDataRates \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(5) | 0x10000000) +#define DIDmib_p2_p2Modem_p2TxPowerMax \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(7) | \ + P80211DID_MKITEM(6) | 0x18000000) +#endif --- linux-2.6.27.orig/ubuntu/misc/wireless/p80211/wlan/wlan_compat.h +++ linux-2.6.27/ubuntu/misc/wireless/p80211/wlan/wlan_compat.h @@ -0,0 +1,784 @@ +/* src/include/wlan/wlan_compat.h +* +* Types and macros to aid in portability +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +*/ + +#ifndef _WLAN_COMPAT_H +#define _WLAN_COMPAT_H + +/*=============================================================*/ +/*------ Establish Platform Identity --------------------------*/ +/*=============================================================*/ +/* Key macros: */ +/* WLAN_CPU_FAMILY */ + #define WLAN_Ix86 1 + #define WLAN_PPC 2 + #define WLAN_Ix96 3 + #define WLAN_ARM 4 + #define WLAN_ALPHA 5 + #define WLAN_MIPS 6 + #define WLAN_HPPA 7 + #define WLAN_SPARC 8 + #define WLAN_SH 9 + #define WLAN_x86_64 10 +/* WLAN_SYSARCH */ + #define WLAN_PCAT 1 + #define WLAN_MBX 2 + #define WLAN_RPX 3 + #define WLAN_LWARCH 4 + #define WLAN_PMAC 5 + #define WLAN_SKIFF 6 + #define WLAN_BITSY 7 + #define WLAN_ALPHAARCH 7 + #define WLAN_MIPSARCH 9 + #define WLAN_HPPAARCH 10 + #define WLAN_SPARCARCH 11 + #define WLAN_SHARCH 12 + +/* Note: the PLX HOSTIF above refers to some vendors implementations for */ +/* PCI. It's a PLX chip that is a PCI to PCMCIA adapter, but it */ +/* isn't a real PCMCIA host interface adapter providing all the */ +/* card&socket services. */ + +#if (defined(CONFIG_PPC) || defined(CONFIG_8xx) || defined(__powerpc__)) +#ifndef __ppc__ +#define __ppc__ +#endif +#endif + +#if defined(__KERNEL__) + +#ifndef AUTOCONF_INCLUDED +#include +#endif + +#if defined(__x86_64__) + #define WLAN_CPU_FAMILY WLAN_x86_64 + #define WLAN_SYSARCH WLAN_PCAT +#elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) + #define WLAN_CPU_FAMILY WLAN_Ix86 + #define WLAN_SYSARCH WLAN_PCAT +#elif defined(__ppc__) + #define WLAN_CPU_FAMILY WLAN_PPC + #if defined(CONFIG_MBX) + #define WLAN_SYSARCH WLAN_MBX + #elif defined(CONFIG_RPXLITE) + #define WLAN_SYSARCH WLAN_RPX + #elif defined(CONFIG_RPXCLASSIC) + #define WLAN_SYSARCH WLAN_RPX + #else + #define WLAN_SYSARCH WLAN_PMAC + #endif +#elif defined(__arm__) + #define WLAN_CPU_FAMILY WLAN_ARM + #define WLAN_SYSARCH WLAN_SKIFF +#elif defined(__alpha__) + #define WLAN_CPU_FAMILY WLAN_ALPHA + #define WLAN_SYSARCH WLAN_ALPHAARCH +#elif defined(__mips__) + #define WLAN_CPU_FAMILY WLAN_MIPS + #define WLAN_SYSARCH WLAN_MIPSARCH +#elif defined(__hppa__) + #define WLAN_CPU_FAMILY WLAN_HPPA + #define WLAN_SYSARCH WLAN_HPPAARCH +#elif defined(__sparc__) + #define WLAN_CPU_FAMILY WLAN_SPARC + #define WLAN_SYSARCH WLAN_SPARC +#elif defined(__sh__) + #define WLAN_CPU_FAMILY WLAN_SH + #define WLAN_SYSARCH WLAN_SHARCH + #ifndef __LITTLE_ENDIAN__ + #define __LITTLE_ENDIAN__ + #endif +#else + #error "No CPU identified!" +#endif +#endif /* __KERNEL__ */ + +/* + Some big endian machines implicitly do all I/O in little endian mode. + + In particular: + Linux/PPC on PowerMacs (PCI) + Arm/Intel Xscale (PCI) + + This may also affect PLX boards and other BE &| PPC platforms; + as new ones are discovered, add them below. +*/ + +#if defined(WLAN_HOSTIF) +#if ((WLAN_HOSTIF == WLAN_PCI) || (WLAN_HOSTIF == WLAN_PLX)) +#if ((WLAN_SYSARCH == WLAN_SKIFF) || (WLAN_SYSARCH == WLAN_PMAC) || (WLAN_SYSARCH == WLAN_SPARC)) +#define REVERSE_ENDIAN +#endif +#endif +#endif + +/*=============================================================*/ +/*------ Bit settings -----------------------------------------*/ +/*=============================================================*/ + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +#include + +typedef u_int8_t UINT8; +typedef u_int16_t UINT16; +typedef u_int32_t UINT32; + +typedef int8_t INT8; +typedef int16_t INT16; +typedef int32_t INT32; + +typedef unsigned int UINT; +typedef signed int INT; + +typedef u_int64_t UINT64; +typedef int64_t INT64; + +#define UINT8_MAX (0xffUL) +#define UINT16_MAX (0xffffUL) +#define UINT32_MAX (0xffffffffUL) + +#define INT8_MAX (0x7fL) +#define INT16_MAX (0x7fffL) +#define INT32_MAX (0x7fffffffL) + +/*=============================================================*/ +/*------ Compiler Portability Macros --------------------------*/ +/*=============================================================*/ +#define __WLAN_ATTRIB_PACK__ __attribute__ ((packed)) + +/*=============================================================*/ +/*------ OS Portability Macros --------------------------------*/ +/*=============================================================*/ + +#ifndef WLAN_DBVAR +#define WLAN_DBVAR wlan_debug +#endif + +#ifndef KERNEL_VERSION +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) +# if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)) +# include +# else +# include +# endif +#elif defined(__KERNEL__) +# define PREEMPT_MASK (0x000000FFUL) +# define preempt_count() (0UL) +#endif + +#define WLAN_LOG_ERROR(x,args...) printk(KERN_ERR "%s: " x , __FUNCTION__ , ##args); + +#define WLAN_LOG_WARNING(x,args...) printk(KERN_WARNING "%s: " x , __FUNCTION__ , ##args); + +#define WLAN_LOG_NOTICE(x,args...) printk(KERN_NOTICE "%s: " x , __FUNCTION__ , ##args); + +#define WLAN_LOG_INFO(args... ) printk(KERN_INFO args) + +#if defined(WLAN_INCLUDE_DEBUG) + #define WLAN_ASSERT(c) if ((!(c)) && WLAN_DBVAR >= 1) { \ + WLAN_LOG_DEBUG(1, "Assertion failure!\n"); } + #define WLAN_HEX_DUMP( l, x, p, n) if( WLAN_DBVAR >= (l) ){ \ + int __i__; \ + printk(KERN_DEBUG x ":"); \ + for( __i__=0; __i__ < (n); __i__++) \ + printk( " %02x", ((UINT8*)(p))[__i__]); \ + printk("\n"); } + #define DBFENTER { if ( WLAN_DBVAR >= 5 ){ WLAN_LOG_DEBUG(3,"---->\n"); } } + #define DBFEXIT { if ( WLAN_DBVAR >= 5 ){ WLAN_LOG_DEBUG(3,"<----\n"); } } + + #define WLAN_LOG_DEBUG(l,x,args...) if ( WLAN_DBVAR >= (l)) printk(KERN_DEBUG "%s(%lu): " x , __FUNCTION__, (preempt_count() & PREEMPT_MASK), ##args ); +#else + #define WLAN_ASSERT(c) + #define WLAN_HEX_DUMP( l, s, p, n) + #define DBFENTER + #define DBFEXIT + + #define WLAN_LOG_DEBUG(l, s, args...) +#endif + +#ifdef CONFIG_SMP +#define __SMP__ 1 +#endif + +#if defined(__KERNEL__) + +#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19))) +#define URB_ONLY_CALLBACK +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) +#define PT_REGS , struct pt_regs *regs +#else +#define PT_REGS +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7)) +# define del_singleshot_timer_sync(a) del_timer_sync(a) +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)) +#define CONFIG_NETLINK 1 +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) +#define kfree_s(a, b) kfree((a)) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) +#ifndef init_waitqueue_head +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,0,16)) +#define init_waitqueue_head(p) (*(p) = NULL) +#else +#define init_waitqueue_head(p) init_waitqueue(p) +#endif +typedef struct wait_queue *wait_queue_head_t; +typedef struct wait_queue wait_queue_t; +#define set_current_state(b) { current->state = (b); mb(); } +#define init_waitqueue_entry(a, b) { (a)->task = current; } +#endif +#endif + +#ifndef wait_event_interruptible_timeout +// retval == 0; signal met; we're good. +// retval < 0; interrupted by signal. +// retval > 0; timed out. + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) // fixme? + +#define __wait_event_interruptible_timeout(wq, condition, ret) \ +do { \ + wait_queue_t __wait; \ + init_waitqueue_entry(&__wait, current); \ + \ + add_wait_queue(&wq, &__wait); \ + for (;;) { \ + set_current_state(TASK_INTERRUPTIBLE); \ + if (condition) \ + break; \ + if (!signal_pending(current)) { \ + ret = schedule_timeout(ret) ; \ + if (!ret) \ + break; \ + continue; \ + } \ + ret = -ERESTARTSYS; \ + break; \ + } \ + set_current_state(TASK_RUNNING); \ + remove_wait_queue(&wq, &__wait); \ +} while (0) + +#else // 2.2 + + +#define __wait_event_interruptible_timeout(wq, condition, ret) \ +do { \ + struct wait_queue __wait; \ + \ + __wait.task = current; \ + add_wait_queue(&wq, &__wait); \ + for (;;) { \ + current->state = TASK_INTERRUPTIBLE; \ + if (condition) \ + break; \ + if (!signal_pending(current)) { \ + ret = schedule_timeout(ret); \ + if (!ret) \ + break; \ + continue; \ + } \ + ret = -ERESTARTSYS; \ + break; \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&wq, &__wait); \ +} while (0) + +#endif // version >= 2.4 + +#define wait_event_interruptible_timeout(wq, condition, timeout) \ +({ \ + long __ret = timeout; \ + if (!(condition)) \ + __wait_event_interruptible_timeout(wq, condition, __ret); \ + __ret; \ +}) + +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20)) +#ifdef _LINUX_LIST_H + +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + + +#endif // LIST_H +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) +#define SET_MODULE_OWNER(x) do { } while (0) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,90)) +#define spin_lock(l) do { } while (0) +#define spin_unlock(l) do { } while (0) +#define spin_lock_irqsave(l,f) do { save_flags(f); cli(); } while (0) +#define spin_unlock_irqrestore(l,f) do { restore_flags(f); } while (0) +#define spin_lock_init(s) do { } while (0) +#define spin_trylock(l) (1) +typedef int spinlock_t; +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) // XXX ??? +#define spin_lock_bh spin_lock +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) +#ifdef CONFIG_SMP +#define spin_is_locked(x) (*(volatile char *)(&(x)->lock) <= 0) +#else +#define spin_is_locked(l) (0) +#endif +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,28)) +#define __user +#define __iomem +#endif + +#ifdef _LINUX_PROC_FS_H + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) +#define PROC_NET proc_net +#else +#define PROC_NET init_net.proc_net +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,25)) + +extern inline struct proc_dir_entry * +create_proc_read_entry(const char *name, mode_t mode, + struct proc_dir_entry *base, + read_proc_t *read_proc, void *data) +{ + struct proc_dir_entry *res = create_proc_entry(name, mode, base); + if (res) { + res->read_proc = read_proc; + res->data = data; + } + return res; +} +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,29)) +#ifndef proc_mkdir +#define proc_mkdir(name, root) create_proc_entry(name, S_IFDIR, root) +#endif +#endif +#endif /* _LINUX_PROC_FS_H */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) +#define skb_reset_mac_header(__a) (__a)->mac.raw = (__a)->data +#define SKB_MAC_HEADER(__a) (__a)->mac.raw +#else +#define SKB_MAC_HEADER(__a) (__a)->mac_header +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) +#define IRQF_DISABLED SA_INTERRUPT +#define IRQF_SHARED SA_SHIRQ +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#ifndef INIT_TQUEUE +#define PREPARE_TQUEUE(_tq, _routine, _data) \ + do { \ + (_tq)->routine = _routine; \ + (_tq)->data = _data; \ + } while (0) +#define INIT_TQUEUE(_tq, _routine, _data) \ + do { \ + INIT_LIST_HEAD(&(_tq)->list); \ + (_tq)->sync = 0; \ + PREPARE_TQUEUE((_tq), (_routine), (_data)); \ + } while (0) +#endif + +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) +#endif + +#ifndef INIT_WORK +#define work_struct tq_struct + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) +#define schedule_work(a) queue_task(a, &tq_scheduler) +#else +#define schedule_work(a) schedule_task(a) +#endif + +#define flush_scheduled_work flush_scheduled_tasks +#define INIT_WORK2(_wq, _routine) INIT_TQUEUE(_wq, (void (*)(void *))_routine, _wq) +#endif + +#else // >= 2.5 kernel + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +#define INIT_WORK2(_wq, _routine) INIT_WORK(_wq, (void (*)(void *))_routine, _wq) +#else +#define INIT_WORK2(_wq, _routine) INIT_WORK(_wq, _routine) +#endif + +#endif // >= 2.5 kernel + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,38)) +typedef struct device netdevice_t; +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)) +typedef struct net_device netdevice_t; +#else +#undef netdevice_t +typedef struct net_device netdevice_t; +#endif + +#ifdef WIRELESS_EXT +#if (WIRELESS_EXT < 13) +struct iw_request_info +{ + __u16 cmd; /* Wireless Extension command */ + __u16 flags; /* More to come ;-) */ +}; +#endif +#endif + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,18)) +#define MODULE_PARM(a,b) extern int __bogus_decl +#define MODULE_AUTHOR(a) extern int __bogus_decl +#define MODULE_DESCRIPTION(a) extern int __bogus_decl +#define MODULE_SUPPORTED_DEVICE(a) extern int __bogus_decl +#undef GET_USE_COUNT +#define GET_USE_COUNT(m) mod_use_count_ +#endif + +#ifndef MODULE_OWNER +#define MODULE_OWNER(a) extern int __bogus_decl +#define ANCIENT_MODULE_CODE +#endif + +#ifndef MODULE_LICENSE +#define MODULE_LICENSE(m) extern int __bogus_decl +#endif + +/* TODO: Do we care about this? */ +#ifndef MODULE_DEVICE_TABLE +#define MODULE_DEVICE_TABLE(foo,bar) +#endif + +#define wlan_minutes2ticks(a) ((a)*(wlan_ticks_per_sec * 60)) +#define wlan_seconds2ticks(a) ((a)*(wlan_ticks_per_sec)) + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,47)) +#define NEW_MODULE_CODE +#ifdef ANCIENT_MODULE_CODE +#undef ANCIENT_MODULE_CODE +#endif +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,25)) +#define module_param(name, type, perm) \ + static inline void *__check_existence_##name(void) { return &name; } \ + MODULE_PARM(name, _MODULE_PARM_STRING_ ## type) + +#define _MODULE_PARM_STRING_byte "b" +#define _MODULE_PARM_STRING_short "h" +#define _MODULE_PARM_STRING_ushort "h" +#define _MODULE_PARM_STRING_int "i" +#define _MODULE_PARM_STRING_uint "i" +#define _MODULE_PARM_STRING_long "l" +#define _MODULE_PARM_STRING_ulong "l" +#define _MODULE_PARM_STRING_bool "i" +#endif + +/* linux < 2.5.69 */ +#ifndef IRQ_NONE +typedef void irqreturn_t; +#define IRQ_NONE +#define IRQ_HANDLED +#define IRQ_RETVAL(x) +#endif + +#ifndef in_atomic +#define in_atomic() 0 +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)) +#define URB_ASYNC_UNLINK 0 +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7)) +#define URB_ASYNC_UNLINK USB_ASYNC_UNLINK +#define usb_fill_bulk_urb FILL_BULK_URB +#define usb_kill_urb usb_unlink_urb +#else +#define USB_QUEUE_BULK 0 +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)) +typedef u32 pm_message_t; +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)) +#define hotplug_path "/etc/hotplug/wlan.agent" +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) +#define free_netdev(x) kfree(x) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)) +#define eth_hdr(x) (x)->mac.ethernet +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) +#define del_timer_sync(a) del_timer(a) +#endif + +#ifndef might_sleep +#define might_sleep(a) do { } while (0) +#endif + +/* Apparently 2.4.2 ethtool is quite different, maybe newer too? */ +#if (defined(SIOETHTOOL) && !defined(ETHTOOL_GDRVINFO)) +#undef SIOETHTOOL +#endif + +// pcmcia-cs stuff +#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68)) && \ + !defined(pcmcia_access_configuration_register)) +#define pcmcia_access_configuration_register(handle, reg) \ + CardServices(AccessConfigurationRegister, handle, reg) +#define pcmcia_register_client(handle, reg) \ + CardServices(RegisterClient, handle, reg) +#define pcmcia_deregister_client(handle) \ + CardServices(DeregisterClient, handle) +#define pcmcia_get_first_tuple(handle, tuple) \ + CardServices(GetFirstTuple, handle, tuple) +#define pcmcia_get_next_tuple(handle, tuple) \ + CardServices(GetNextTuple, handle, tuple) +#define pcmcia_get_tuple_data(handle, tuple) \ + CardServices(GetTupleData, handle, tuple) +#define pcmcia_parse_tuple(handle, tuple, parse) \ + CardServices(ParseTuple, handle, tuple, parse) +#define pcmcia_get_configuration_info(handle, config) \ + CardServices(GetConfigurationInfo, handle, config) +#define pcmcia_request_io(handle, req) \ + CardServices(RequestIO, handle, req) +#define pcmcia_request_irq(handle, req) \ + CardServices(RequestIRQ, handle, req) +#define pcmcia_request_configuration(handle, req) \ + CardServices(RequestConfiguration, handle, req) +#define pcmcia_release_configuration(handle) \ + CardServices(ReleaseConfiguration, handle) +#define pcmcia_release_io(handle, req) \ + CardServices(ReleaseIO, handle, req) +#define pcmcia_release_irq(handle, req) \ + CardServices(ReleaseIRQ, handle, req) +#define pcmcia_release_window(win) \ + CardServices(ReleaseWindow, win) +#define pcmcia_get_card_services_info(info) \ + CardServices(GetCardServicesInfo, info) +#define pcmcia_report_error(handle, err) \ + CardServices(ReportError, handle, err) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) +#define round_jiffies(a) (a) +#endif + +#endif /* __KERNEL__ */ + +/*=============================================================*/ +/*------ Hardware Portability Macros --------------------------*/ +/*=============================================================*/ + +#define ieee2host16(n) __le16_to_cpu(n) +#define ieee2host32(n) __le32_to_cpu(n) +#define host2ieee16(n) __cpu_to_le16(n) +#define host2ieee32(n) __cpu_to_le32(n) + +#if (WLAN_CPU_FAMILY != WLAN_MIPS) +typedef UINT32 phys_t; +#endif + +#if (WLAN_CPU_FAMILY == WLAN_PPC) + #define wlan_inw(a) in_be16((unsigned short *)((a)+_IO_BASE)) + #define wlan_inw_le16_to_cpu(a) inw((a)) + #define wlan_outw(v,a) out_be16((unsigned short *)((a)+_IO_BASE), (v)) + #define wlan_outw_cpu_to_le16(v,a) outw((v),(a)) +#else + #define wlan_inw(a) inw((a)) + #define wlan_inw_le16_to_cpu(a) __cpu_to_le16(inw((a))) + #define wlan_outw(v,a) outw((v),(a)) + #define wlan_outw_cpu_to_le16(v,a) outw(__cpu_to_le16((v)),(a)) +#endif + +/*=============================================================*/ +/*--- General Macros ------------------------------------------*/ +/*=============================================================*/ + +#define wlan_max(a, b) (((a) > (b)) ? (a) : (b)) +#define wlan_min(a, b) (((a) < (b)) ? (a) : (b)) + +#define wlan_isprint(c) (((c) > (0x19)) && ((c) < (0x7f))) + +#define wlan_hexchar(x) (((x) < 0x0a) ? ('0' + (x)) : ('a' + ((x) - 0x0a))) + +/* Create a string of printable chars from something that might not be */ +/* It's recommended that the str be 4*len + 1 bytes long */ +#define wlan_mkprintstr(buf, buflen, str, strlen) \ +{ \ + int i = 0; \ + int j = 0; \ + memset(str, 0, (strlen)); \ + for (i = 0; i < (buflen); i++) { \ + if ( wlan_isprint((buf)[i]) ) { \ + (str)[j] = (buf)[i]; \ + j++; \ + } else { \ + (str)[j] = '\\'; \ + (str)[j+1] = 'x'; \ + (str)[j+2] = wlan_hexchar(((buf)[i] & 0xf0) >> 4); \ + (str)[j+3] = wlan_hexchar(((buf)[i] & 0x0f)); \ + j += 4; \ + } \ + } \ +} + +/*=============================================================*/ +/*--- Variables -----------------------------------------------*/ +/*=============================================================*/ + +#ifdef WLAN_INCLUDE_DEBUG +extern int wlan_debug; +#endif + +extern int wlan_ethconv; /* What's the default ethconv? */ + +/*=============================================================*/ +/*--- Functions -----------------------------------------------*/ +/*=============================================================*/ +#endif /* _WLAN_COMPAT_H */ + --- linux-2.6.27.orig/ubuntu/misc/wireless/at76/at76_usbdfu.c +++ linux-2.6.27/ubuntu/misc/wireless/at76/at76_usbdfu.c @@ -0,0 +1,315 @@ +/* -*- linux-c -*- */ +/* + * USB Device Firmware Upgrade (DFU) handler + * + * Copyright (c) 2003 Oliver Kurth + * Copyright (c) 2004 Jörg Albert + * + * This file is part of the driver for WLAN USB devices based on the Atmel + * AT76C503A/505/505A. See at76c503.h for details. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * 2003_01_19 0.1: + * - initial release + * + * TODO: + * (someday) + * - make a way for drivers to feed firmware data at download time (instead of + * providing it all at once during register) + * - procfs support for userland firmware downloaders + * - Firmware upload (device-to-host) support + */ + +#include +#include +#include "at76c503.h" + +/* DFU states */ + +#define STATE_IDLE 0x00 +#define STATE_DETACH 0x01 +#define STATE_DFU_IDLE 0x02 +#define STATE_DFU_DOWNLOAD_SYNC 0x03 +#define STATE_DFU_DOWNLOAD_BUSY 0x04 +#define STATE_DFU_DOWNLOAD_IDLE 0x05 +#define STATE_DFU_MANIFEST_SYNC 0x06 +#define STATE_DFU_MANIFEST 0x07 +#define STATE_DFU_MANIFEST_WAIT_RESET 0x08 +#define STATE_DFU_UPLOAD_IDLE 0x09 +#define STATE_DFU_ERROR 0x0a + +/* DFU commands */ +#define DFU_DETACH 0 +#define DFU_DNLOAD 1 +#define DFU_UPLOAD 2 +#define DFU_GETSTATUS 3 +#define DFU_CLRSTATUS 4 +#define DFU_GETSTATE 5 +#define DFU_ABORT 6 + +struct dfu_status { + unsigned char bStatus; + unsigned char bwPollTimeout[3]; + unsigned char bState; + unsigned char iString; +} __attribute__ ((packed)); + + +/* driver independent download context */ +struct dfu_ctx { + struct usb_device *udev; + u8 dfu_state; + struct dfu_status dfu_status; + u8 *buf; +}; + +#define USB_SUCCESS(a) ((a) >= 0) + +#define DFU_PACKETSIZE 1024 + +static +int dfu_download_block(struct dfu_ctx *ctx, u8 *buffer, + int bytes, int block) +{ + int result; + u8 *tmpbuf = ctx->buf; + struct usb_device *udev = ctx->udev; + + dbg(DBG_DFU, "dfu_download_block(): buffer=%p, bytes=%d, block=%d", buffer, bytes, block); + + if(tmpbuf == NULL) + return -ENOMEM; + + memcpy(tmpbuf, buffer, bytes); + + result = usb_control_msg(udev, usb_sndctrlpipe(udev,0), + DFU_DNLOAD, + USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE, + block, /* Value */ + 0, /* Index */ + tmpbuf, /* Buffer */ + bytes, /* Size */ + HZ); + return result; +} + +static +int dfu_get_status(struct dfu_ctx *ctx, struct dfu_status *status) +{ + int result; + struct usb_device *udev = ctx->udev; + +// dbg(DBG_DFU, "dfu_get_status()"); + + result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + DFU_GETSTATUS, + USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE, + 0, /* Value */ + 0, /* Index */ + status, /* Buffer */ + sizeof(struct dfu_status), /* Size */ + HZ); + + return result; +} + +static +u8 dfu_get_state(struct usb_device *udev, u8 *state) +{ + int result; + +// dbg(DBG_DFU, "dfu_get_state()"); + + result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + DFU_GETSTATE, /* Request */ + USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE, + 0, /* Value */ + 0, /* Index */ + state, /* Buffer */ + 1, /* Size */ + HZ); + + return result; +} + +static inline +u32 __get_timeout(struct dfu_status *s) +{ + unsigned long ret = 0; + + ret = (unsigned long) (s->bwPollTimeout[2] << 16); + ret |= (unsigned long) (s->bwPollTimeout[1] << 8); + ret |= (unsigned long) (s->bwPollTimeout[0]); + + return ret; +} + +static +struct dfu_ctx *dfu_alloc_ctx(struct usb_device *udev) +{ + struct dfu_ctx *ctx; + + ctx = kmalloc(sizeof(struct dfu_ctx) + DFU_PACKETSIZE, GFP_KERNEL|GFP_DMA); + if(ctx){ + ctx->udev = udev; + ctx->buf = (u8 *)&(ctx[1]); + } + return ctx; +} + +/* == PROC usbdfu_download == + if manifest_sync_timeout > 0 use this timeout (in msec) instead of the + one reported by the device in state MANIFEST_SYNC */ +int usbdfu_download(struct usb_device *udev, u8 *dfu_buffer, u32 dfu_len, + int manifest_sync_timeout) +{ + struct dfu_ctx *ctx; + struct dfu_status *dfu_stat_buf; + int status = 0; + int need_dfu_state = 1; + int is_done = 0; + u8 dfu_state = 0; + u32 dfu_timeout = 0; + int dfu_block_bytes = 0, dfu_bytes_left = dfu_len, dfu_buffer_offset = 0; + int dfu_block_cnt = 0; + + dbg(DBG_DFU, "%s( %p, %u, %d)", __FUNCTION__, dfu_buffer, + dfu_len, manifest_sync_timeout); + + if (dfu_len == 0) { + err("FW Buffer length invalid!"); + return -EINVAL; + } + + ctx = dfu_alloc_ctx(udev); + if(ctx == NULL) + return -ENOMEM; + + dfu_stat_buf = &ctx->dfu_status; + + do { + if (need_dfu_state) { + status = dfu_get_state(ctx->udev, &ctx->dfu_state); + if (!USB_SUCCESS(status)) { + err("DFU: Failed to get DFU state: %d", status); + goto exit; + } + dfu_state = ctx->dfu_state; + need_dfu_state = 0; + } + + switch (dfu_state) { + case STATE_DFU_DOWNLOAD_SYNC: + dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_SYNC"); + status = dfu_get_status(ctx, dfu_stat_buf); + if (USB_SUCCESS(status)) { + dfu_state = dfu_stat_buf->bState; + dfu_timeout = __get_timeout(dfu_stat_buf); + need_dfu_state = 0; + } else + err("dfu_get_status failed with %d", status); + break; + + case STATE_DFU_DOWNLOAD_BUSY: + dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_BUSY"); + need_dfu_state = 1; + + if (dfu_timeout >= 0){ + dbg(DBG_DFU, "DFU: Resetting device"); + set_current_state( TASK_INTERRUPTIBLE ); + schedule_timeout(1+dfu_timeout*HZ/1000); + }else + dbg(DBG_DFU, "DFU: In progress"); + + break; + + case STATE_DFU_DOWNLOAD_IDLE: + dbg(DBG_DFU, "DOWNLOAD..."); + /* fall through */ + case STATE_DFU_IDLE: + dbg(DBG_DFU, "DFU IDLE"); + + if (dfu_bytes_left <= DFU_PACKETSIZE) + dfu_block_bytes = dfu_bytes_left; + else + dfu_block_bytes = DFU_PACKETSIZE; + + dfu_bytes_left -= dfu_block_bytes; + status = dfu_download_block(ctx, + dfu_buffer + + dfu_buffer_offset, + dfu_block_bytes, + dfu_block_cnt); + dfu_buffer_offset += dfu_block_bytes; + dfu_block_cnt++; + + if (!USB_SUCCESS(status)) + err("dfu_download_block failed with %d", status); + need_dfu_state = 1; + break; + + case STATE_DFU_MANIFEST_SYNC: + dbg(DBG_DFU, "STATE_DFU_MANIFEST_SYNC"); + + status = dfu_get_status(ctx, dfu_stat_buf); + + if (USB_SUCCESS(status)) { + dfu_state = dfu_stat_buf->bState; + dfu_timeout = __get_timeout(dfu_stat_buf); + need_dfu_state = 0; + + /* override the timeout from the status response, + needed for AT76C505A */ + if (manifest_sync_timeout > 0) + dfu_timeout = manifest_sync_timeout; + + if (dfu_timeout >= 0){ + dbg(DBG_DFU, "DFU: Waiting for manifest phase"); + + set_current_state( TASK_INTERRUPTIBLE ); + schedule_timeout((dfu_timeout*HZ+999)/1000); + }else + dbg(DBG_DFU, "DFU: In progress"); + } + break; + + case STATE_DFU_MANIFEST: + dbg(DBG_DFU, "STATE_DFU_MANIFEST"); + is_done = 1; + break; + + case STATE_DFU_MANIFEST_WAIT_RESET: + dbg(DBG_DFU, "STATE_DFU_MANIFEST_WAIT_RESET"); +// usb_reset_device(udev); + is_done = 1; + break; + + case STATE_DFU_UPLOAD_IDLE: + dbg(DBG_DFU, "STATE_DFU_UPLOAD_IDLE"); + break; + + case STATE_DFU_ERROR: + dbg(DBG_DFU, "STATE_DFU_ERROR"); +// usb_reset_device(udev); + status = -EPIPE; + break; + + default: + dbg(DBG_DFU, "DFU UNKNOWN STATE (%d)", dfu_state); + status = -EINVAL; + break; + } + } while (!is_done && USB_SUCCESS(status)); + + exit: + kfree(ctx); + if (status < 0) + return status; + else + return 0; +} + --- linux-2.6.27.orig/ubuntu/misc/wireless/at76/at76c503.c +++ linux-2.6.27/ubuntu/misc/wireless/at76/at76c503.c @@ -0,0 +1,7138 @@ +/* -*- linux-c -*- */ +/* + * USB at76c503/at76c505 driver + * + * Copyright (c) 2002 - 2003 Oliver Kurth + * Copyright (c) 2004 Joerg Albert + * Copyright (c) 2004 Nick Jones + * Copyright (c) 2004 Balint Seeber + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This file is part of the Berlios driver for WLAN USB devices based on the + * Atmel AT76C503A/505/505A. See at76c503.h for details. + * + * Some iw_handler code was taken from airo.c, (C) 1999 Benjamin Reed + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for rtnl_lock() */ +#include + +#ifdef CONFIG_IPAQ_HANDHELD +#include +#include +#include +#include +#endif + +#include "at76c503.h" + +#if WIRELESS_EXT < 17 +#define IW_QUAL_QUAL_UPDATED 0x01 +#define IW_QUAL_LEVEL_UPDATED 0x02 +#define IW_QUAL_NOISE_UPDATED 0x04 +#define IW_QUAL_QUAL_INVALID 0x10 +#define IW_QUAL_LEVEL_INVALID 0x20 +#define IW_QUAL_NOISE_INVALID 0x40 +#endif + +#if WIRELESS_EXT < 19 +#define IW_QUAL_ALL_UPDATED 0x07 +#define IW_QUAL_DBM 0x08 +#define IW_QUAL_ALL_INVALID 0x70 +#endif + +/* timeout in seconds for the usb_control_msg in get_cmd_status + * and set_card_command + */ +#ifndef USB_CTRL_GET_TIMEOUT +# define USB_CTRL_GET_TIMEOUT 5 +#endif + +/* number of endpoints of an interface */ +#define NUM_EP(intf) (intf)->altsetting[0].desc.bNumEndpoints +#define EP(intf,nr) (intf)->altsetting[0].endpoint[(nr)].desc +#define GET_DEV(udev) usb_get_dev((udev)) +#define PUT_DEV(udev) usb_put_dev((udev)) +#define SET_NETDEV_OWNER(ndev,owner) /* not needed anymore ??? */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) +#define gfp_t int +#endif + +/* Backwards compatibility for usb_kill_urb() */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) +# define usb_kill_urb usb_unlink_urb +#endif + +/* wireless extension level this source currently supports */ +#define WIRELESS_EXT_SUPPORTED 16 + +#ifndef USB_ASYNC_UNLINK +#ifdef URB_ASYNC_UNLINK +#define USB_ASYNC_UNLINK URB_ASYNC_UNLINK +#else +#define USB_ASYNC_UNLINK 0 +#endif +#endif + +#ifndef FILL_BULK_URB +#define FILL_BULK_URB(a,b,c,d,e,f,g) usb_fill_bulk_urb(a,b,c,d,e,f,g) +#endif + +int at76_debug = DBG_DEFAULTS; + +/* uncond. debug output */ +#define dbg_uc(format, arg...) \ + printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg) + +#ifndef min +#define min(x,y) ((x) < (y) ? (x) : (y)) +#endif + +#define assert(x) \ + do {\ + if (!(x)) \ + err("%d: assertion " #x " failed", __LINE__);\ + } while (0) + +/* how often do we re-try these packets ? */ +#define AUTH_RETRIES 3 +#define ASSOC_RETRIES 3 +#define DISASSOC_RETRIES 3 + + + +static unsigned long spin_l_istate_flags; +#define LOCK_ISTATE() spin_lock_irqsave(&dev->istate_spinlock,spin_l_istate_flags); +#define UNLOCK_ISTATE() spin_unlock_irqrestore(&dev->istate_spinlock,spin_l_istate_flags); + + +#define NEW_STATE(dev,newstate) \ + do {\ + scan_hook(newstate == SCANNING); \ + LOCK_ISTATE() \ + dbg(DBG_PROGRESS, "%s: state %d -> %d (" #newstate ")",\ + dev->netdev->name, dev->istate, newstate);\ + dev->istate = newstate;\ + UNLOCK_ISTATE() \ + } while (0) + +/* the beacon timeout in infra mode when we are connected (in seconds) */ +#define BEACON_TIMEOUT 10 + +/* the interval in ticks we poll if scan is completed */ +#define SCAN_POLL_INTERVAL (HZ/4) + + +/* Version Information */ +#define DRIVER_NAME "at76_usb" +#define DRIVER_AUTHOR \ +"Oliver Kurth , Joerg Albert , " \ +"Alex , Nick Jones, Balint Seeber " +#define DRIVER_DESC "Atmel at76c50x USB Wireless LAN Driver" + + +/* Module paramaters */ +module_param_named(debug, at76_debug, int, 0600); +MODULE_PARM_DESC(debug, "Debugging level"); + +static int rx_copybreak = 200; +module_param(rx_copybreak, int, 0400); +MODULE_PARM_DESC(rx_copybreak, "rx packet copy threshold"); + +static int scan_min_time = 10; +module_param(scan_min_time, int, 0400); +MODULE_PARM_DESC(scan_min_time, "scan min channel time (default: 10)"); + +static int scan_max_time = 120; +module_param(scan_max_time, int, 0400); +MODULE_PARM_DESC(scan_max_time, "scan max channel time (default: 120)"); + +static int scan_mode = SCAN_TYPE_ACTIVE; +module_param(scan_mode, int, 0400); +MODULE_PARM_DESC(scan_mode, "scan mode: 0 active (with ProbeReq, default), 1 passive"); + +static int preamble_type = PREAMBLE_TYPE_LONG; +module_param(preamble_type, int, 0400); +MODULE_PARM_DESC(preamble_type, "preamble type: 0 long (default), 1 short"); + +static int auth_mode = 0; +module_param(auth_mode, int, 0400); +MODULE_PARM_DESC(auth_mode, "authentication mode: 0 open system (default), " + "1 shared secret"); + +static int pm_mode = PM_ACTIVE; +module_param(pm_mode, int, 0400); +MODULE_PARM_DESC(pm_mode, "power management mode: 1 active (def.), 2 powersave, 3 smart save"); + +static int pm_period = 0; +module_param(pm_period, int, 0400); +MODULE_PARM_DESC(pm_period, "period of waking up the device in usec"); + +static int international_roaming = IR_OFF; +module_param(international_roaming, int, 0400); +MODULE_PARM_DESC(international_roaming, "enable international roaming: 0 (no, default), 1 (yes)"); + +static int default_iw_mode = IW_MODE_INFRA; +module_param(default_iw_mode, int, 0400); +MODULE_PARM_DESC(default_iw_mode, "default IW mode for a new device: " + "1 (ad-hoc), 2 (infrastructure, def.), 6 (monitor mode)"); + +static int monitor_scan_min_time = 50; +module_param(monitor_scan_min_time, int, 0400); +MODULE_PARM_DESC(monitor_scan_min_time, "scan min channel time in MONITOR MODE (default: 50)"); + +static int monitor_scan_max_time = 600; +module_param(monitor_scan_max_time, int, 0400); +MODULE_PARM_DESC(monitor_scan_max_time, "scan max channel time in MONITOR MODE (default: 600)"); + +static char* netdev_name = "wlan%d"; +module_param(netdev_name, charp, 0400); +MODULE_PARM_DESC(netdev_name, "network device name (default is wlan%d)"); + + +#define DEF_RTS_THRESHOLD 1536 +#define DEF_FRAG_THRESHOLD 1536 +#define DEF_SHORT_RETRY_LIMIT 8 +//#define DEF_LONG_RETRY_LIMIT 4 +#define DEF_CHANNEL 10 + +#define MAX_RTS_THRESHOLD (MAX_FRAG_THRESHOLD + 1) + +/* The frequency of each channel in MHz */ +static const long channel_frequency[] = { + 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 +}; +#define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) ) + +/* the broadcast address */ +static const u8 bc_addr[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; +static const u8 off_addr[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/* the supported rates of this hardware, bit7 marks a basic rate */ +static const u8 hw_rates[4] = {0x82,0x84,0x0b,0x16}; + +/* the max padding size for tx in bytes (see calc_padding)*/ +#define MAX_PADDING_SIZE 53 + +/* the size of the ieee802.11 header (excl. the at76c503 tx header) */ +#define IEEE802_11_MGMT_HEADER_SIZE offsetof(struct ieee80211_hdr_3addr, payload) + +#define BEACON_MAX_DATA_LENGTH 1500 +/* beacon in ieee80211_hdr_3addr.payload */ +struct ieee802_11_beacon_data { + u8 timestamp[8]; // TSFTIMER + __le16 beacon_interval; // Kms between TBTTs (Target Beacon Transmission Times) + __le16 capability_information; + u8 data[BEACON_MAX_DATA_LENGTH]; /* contains: SSID (tag,length,value), + Supported Rates (tlv), channel */ +} __attribute__ ((packed)); + +/* disassoc frame in ieee80211_hdr_3addr.payload */ +struct ieee802_11_disassoc_frame { + __le16 reason; +} __attribute__ ((packed)); +#define DISASSOC_FRAME_SIZE \ + (AT76C503_TX_HDRLEN + IEEE802_11_MGMT_HEADER_SIZE +\ + sizeof(struct ieee802_11_disassoc_frame)) + +/* assoc request in ieee80211_hdr_3addr.payload */ +struct ieee802_11_assoc_req { + __le16 capability; + __le16 listen_interval; + u8 data[1]; /* variable number of bytes for SSID + and supported rates (tlv coded) */ +}; +/* the maximum size of an AssocReq packet */ +#define ASSOCREQ_MAX_SIZE \ + (AT76C503_TX_HDRLEN + IEEE802_11_MGMT_HEADER_SIZE +\ + offsetof(struct ieee802_11_assoc_req,data) +\ + 1+1+IW_ESSID_MAX_SIZE + 1+1+4) + +/* reassoc request in ieee80211_hdr_3addr.payload */ +struct ieee802_11_reassoc_req { + __le16 capability; + __le16 listen_interval; + u8 curr_ap[ETH_ALEN]; /* the bssid of the AP we are + currently associated to */ + u8 data[1]; /* variable number of bytes for SSID + and supported rates (tlv coded) */ +} __attribute__ ((packed)); + +/* the maximum size of an AssocReq packet */ +#define REASSOCREQ_MAX_SIZE \ + (AT76C503_TX_HDRLEN + IEEE802_11_MGMT_HEADER_SIZE +\ + offsetof(struct ieee802_11_reassoc_req,data) +\ + 1+1+IW_ESSID_MAX_SIZE + 1+1+4) + + +/* assoc/reassoc response */ +struct ieee802_11_assoc_resp { + __le16 capability; + __le16 status; + __le16 assoc_id; + u8 data[1]; /* variable number of bytes for + supported rates (tlv coded) */ +} __attribute__ ((packed)); + +/* auth. request/response in ieee80211_hdr_3addr.payload */ +struct ieee802_11_auth_frame { + __le16 algorithm; + __le16 seq_nr; + __le16 status; + u8 challenge[0]; +} __attribute__ ((packed)); +/* for shared secret auth, add the challenge text size */ +#define AUTH_FRAME_SIZE \ + (AT76C503_TX_HDRLEN + IEEE802_11_MGMT_HEADER_SIZE +\ + sizeof(struct ieee802_11_auth_frame)) + +/* deauth frame in ieee80211_hdr_3addr.payload */ +struct ieee802_11_deauth_frame { + __le16 reason; +} __attribute__ ((packed)); +#define DEAUTH_FRAME_SIZE \ + (AT76C503_TX_HDRLEN + IEEE802_11_MGMT_HEADER_SIZE +\ + sizeof(struct ieee802_11_disauth_frame)) + + +#define KEVENT_CTRL_HALT 1 +#define KEVENT_NEW_BSS 2 +#define KEVENT_SET_PROMISC 3 +#define KEVENT_MGMT_TIMEOUT 4 +#define KEVENT_SCAN 5 +#define KEVENT_JOIN 6 +#define KEVENT_STARTIBSS 7 +#define KEVENT_SUBMIT_RX 8 +#define KEVENT_RESTART 9 /* restart the device */ +#define KEVENT_ASSOC_DONE 10 /* execute the power save settings: + listen interval, pm mode, assoc id */ +#define KEVENT_EXTERNAL_FW 11 +#define KEVENT_INTERNAL_FW 12 +#define KEVENT_RESET_DEVICE 13 + + +static u8 snapsig[] = {0xaa, 0xaa, 0x03}; +//#ifdef COLLAPSE_RFC1042 +/* RFC 1042 encapsulates Ethernet frames in 802.2 SNAP (0xaa, 0xaa, 0x03) with + * a SNAP OID of 0 (0x00, 0x00, 0x00) */ +static u8 rfc1042sig[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; +//#endif /* COLLAPSE_RFC1042 */ + +/* local function prototypes */ +static void iwspy_update(struct at76c503 *dev, struct at76c503_rx_buffer *buf); + +static void at76c503_read_bulk_callback (struct urb *urb); +static void at76c503_write_bulk_callback(struct urb *urb); +static void defer_kevent (struct at76c503 *dev, int flag); +static struct bss_info *find_matching_bss(struct at76c503 *dev, + struct bss_info *curr); +static int auth_req(struct at76c503 *dev, struct bss_info *bss, int seq_nr, + u8 *challenge); +static int disassoc_req(struct at76c503 *dev, struct bss_info *bss); +static int assoc_req(struct at76c503 *dev, struct bss_info *bss); +static int reassoc_req(struct at76c503 *dev, struct bss_info *curr, + struct bss_info *new); +static void dump_bss_table(struct at76c503 *dev, int force_output); +static int submit_rx_urb(struct at76c503 *dev); +static int startup_device(struct at76c503 *dev); + +static int set_iroaming(struct at76c503 *dev, int onoff); +static void set_monitor_mode(struct at76c503 *dev, int use_prism); + +/* second step of initialization (after fw download) */ +static int init_new_device(struct at76c503 *dev); + +/* some abbrev. for wireless events */ +static inline void iwevent_scan_complete(struct net_device *dev) +{ + union iwreq_data wrqu; + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); + dbg(DBG_WE_EVENTS, "%s: SIOCGIWSCAN sent", dev->name); +} +static inline void iwevent_bss_connect(struct net_device *dev, u8 *bssid) +{ + union iwreq_data wrqu; + wrqu.data.length = 0; + wrqu.data.flags = 0; + memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); + dbg(DBG_WE_EVENTS, "%s: %s: SIOCGIWAP sent", dev->name, __FUNCTION__); +} + +static inline void iwevent_bss_disconnect(struct net_device *dev) +{ + union iwreq_data wrqu; + wrqu.data.length = 0; + wrqu.data.flags = 0; + memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); + dbg(DBG_WE_EVENTS, "%s: %s: SIOCGIWAP sent", dev->name, __FUNCTION__); +} + + +/* hexdump len many bytes from buf into obuf, separated by delim, + add a trailing \0 into obuf */ +static char *hex2str(char *obuf, u8 *buf, int len, char delim) +{ +#define BIN2HEX(x) ((x) < 10 ? '0'+(x) : (x)+'A'-10) + + char *ret = obuf; + while (len--) { + *obuf++ = BIN2HEX(*buf>>4); + *obuf++ = BIN2HEX(*buf&0xf); + if (delim != '\0') + *obuf++ = delim; + buf++; + } + if (delim != '\0' && obuf > ret) + obuf--; // remove last inserted delimiter + *obuf = '\0'; + + return ret; +} + +/* == PROC is_cloaked_ssid == + returns != 0, if the given SSID is a cloaked one: + - length 0 + - length > 0, all bytes are \0 + - length == 1, SSID ' ' +*/ +static inline int is_cloaked_ssid(u8 *ssid, int length) +{ + static const u8 zeros[32]; + + return (length == 0) || + (length == 1 && *ssid == ' ') || + (length > 0 && !memcmp(ssid,zeros,length)); +} + +static inline void free_bss_list(struct at76c503 *dev) +{ + struct list_head *next, *ptr; + unsigned long flags; + + spin_lock_irqsave(&dev->bss_list_spinlock, flags); + + dev->curr_bss = dev->new_bss = NULL; + + list_for_each_safe(ptr, next, &dev->bss_list) { + list_del(ptr); + kfree(list_entry(ptr, struct bss_info, list)); + } + + spin_unlock_irqrestore(&dev->bss_list_spinlock, flags); +} + +static inline char *mac2str(u8 *mac) +{ + static char str [6*3]; + + sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return str; +} + +static void scan_hook(int blink) +{ +#ifdef CONFIG_IPAQ_HANDHELD + if (machine_is_h5400()) { + if (blink) + ipaq_led_blink (RED_LED, 1, 2); + else + ipaq_led_off (RED_LED); + } +#endif +} + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) + +/* == PROC analyze_usb_config == + This procedure analyzes the configuration after the + USB device got reset and find the start of the interface and the + two endpoint descriptors. + Returns < 0 if the descriptors seems to be wrong. */ +static int analyze_usb_config(u8 *cfgd, int cfgd_len, + int *intf_idx, int *ep0_idx, int *ep1_idx) +{ + u8 *cfgd_start = cfgd; + u8 *cfgd_end = cfgd + cfgd_len; /* first byte after config descriptor */ + int nr_intf=0, nr_ep=0; /* number of interface, number of endpoint descr. + found */ + + assert(cfgd_len >= 2); + if (cfgd_len < 2) + return -1; + + if (*(cfgd+1) != USB_DT_CONFIG) { + err("not a config descriptor"); + return -2; + } + + if (*cfgd != USB_DT_CONFIG_SIZE) { + err("invalid length for config descriptor: %d", *cfgd); + return -3; + } + + /* scan the config descr */ + while ((cfgd+1) < cfgd_end) { + + switch (*(cfgd+1)) { + + case USB_DT_INTERFACE: + nr_intf++; + if (nr_intf == 1) + *intf_idx = cfgd - cfgd_start; + break; + + case USB_DT_ENDPOINT: + nr_ep++; + if (nr_ep == 1) + *ep0_idx = cfgd - cfgd_start; + else + if (nr_ep == 2) + *ep1_idx = cfgd - cfgd_start; + break; + default: + ; + } + cfgd += *cfgd; + } /* while ((cfgd+1) < cfgd_end) */ + + if (nr_ep != 2 || nr_intf != 1) { + err("unexpected nr of intf (%d) or endpoints (%d)", + nr_intf, nr_ep); + return -4; + } + + return 0; +} /* end of analyze_usb_config */ + + + +/* == PROC update_usb_intf_descr == + currently (2.6.0-test2) usb_reset_device() does not recognize that + the interface descr. are changed. + This procedure reads the configuration and does a limited parsing of + the interface and endpoint descriptors. + This is IMHO needed until usb_reset_device() is changed inside the + kernel's USB subsystem. + Copied from usb/core/config.c:usb_get_configuration() + + THIS IS VERY UGLY CODE - DO NOT COPY IT ! */ + +#define AT76C503A_USB_CONFDESCR_LEN 0x20 +/* the short configuration descriptor before reset */ +//#define AT76C503A_USB_SHORT_CONFDESCR_LEN 0x19 + +static int update_usb_intf_descr(struct at76c503 *dev) +{ + int intf0; /* begin of intf descriptor in configuration */ + int ep0, ep1; /* begin of endpoint descriptors */ + + struct usb_device *udev = dev->udev; + struct usb_config_descriptor *cfg_desc; + int result = 0, size; + u8 *buffer; + struct usb_host_interface *ifp; + int i; + + dbg(DBG_DEVSTART, "%s: ENTER", __FUNCTION__); + + cfg_desc = (struct usb_config_descriptor *) + kmalloc(AT76C503A_USB_CONFDESCR_LEN, GFP_KERNEL); + if (!cfg_desc) { + err("cannot kmalloc config desc"); + return -ENOMEM; + } + + result = usb_get_descriptor(udev, USB_DT_CONFIG, 0, + cfg_desc, AT76C503A_USB_CONFDESCR_LEN); + if (result < AT76C503A_USB_CONFDESCR_LEN) { + if (result < 0) + err("unable to get descriptor"); + else { + err("config descriptor too short (expected >= %i, got %i)", + AT76C503A_USB_CONFDESCR_LEN, result); + result = -EINVAL; + } + goto err; + } + + /* now check the config descriptor */ + le16_to_cpus(&cfg_desc->wTotalLength); + size = cfg_desc->wTotalLength; + buffer = (u8 *)cfg_desc; + + if (cfg_desc->bNumInterfaces > 1) { + err("found %d interfaces", cfg_desc->bNumInterfaces); + result = - EINVAL; + goto err; + } + + if ((result=analyze_usb_config(buffer, size, &intf0, &ep0, &ep1))) { + + err("analyze_usb_config returned %d for config desc %s", + result, + hex2str(dev->obuf, (u8 *)cfg_desc, + min((int)(sizeof(dev->obuf)-1)/2,size), '\0')); + result=-EINVAL; + goto err; + } + + /* we got the correct config descriptor - update the interface's endpoints */ + ifp = &udev->actconfig->interface[0]->altsetting[0]; + + if (ifp->endpoint) + kfree(ifp->endpoint); + + memcpy(&ifp->desc, buffer+intf0, USB_DT_INTERFACE_SIZE); + + if (!(ifp->endpoint = kmalloc(2 * sizeof(struct usb_host_endpoint), + GFP_KERNEL))) { + result = -ENOMEM; + goto err; + } + memset(ifp->endpoint, 0, 2 * sizeof(struct usb_host_endpoint)); + memcpy(&ifp->endpoint[0].desc, buffer+ep0, USB_DT_ENDPOINT_SIZE); + le16_to_cpus(&ifp->endpoint[0].desc.wMaxPacketSize); + memcpy(&ifp->endpoint[1].desc, buffer+ep1, USB_DT_ENDPOINT_SIZE); + le16_to_cpus(&ifp->endpoint[1].desc.wMaxPacketSize); + + /* we must set the max packet for the new ep (see usb_set_maxpacket() ) */ + +#define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) + for(i=0; i < ifp->desc.bNumEndpoints; i++) { + struct usb_endpoint_descriptor *d = &ifp->endpoint[i].desc; + int b = d->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + if (usb_endpoint_out(d->bEndpointAddress)) { + if (d->wMaxPacketSize > udev->epmaxpacketout[b]) + udev->epmaxpacketout[b] = d->wMaxPacketSize; + } else { + if (d->wMaxPacketSize > udev->epmaxpacketin[b]) + udev->epmaxpacketin[b] = d->wMaxPacketSize; + } + } + + dbg(DBG_DEVSTART, "%s: ifp %p num_altsetting %d " + "endpoint addr x%x, x%x", __FUNCTION__, + ifp, udev->actconfig->interface[0]->num_altsetting, + ifp->endpoint[0].desc.bEndpointAddress, + ifp->endpoint[1].desc.bEndpointAddress); + result = 0; +err: + kfree(cfg_desc); + dbg(DBG_DEVSTART, "%s: EXIT with %d", __FUNCTION__, result); + return result; +} /* update_usb_intf_descr */ + +#endif /* #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) */ + + +static int at76c503_remap(struct usb_device *udev) +{ + int ret; + ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0), + 0x0a, INTERFACE_VENDOR_REQUEST_OUT, + 0, 0, + NULL, 0, HZ * USB_CTRL_GET_TIMEOUT); + if (ret < 0) + return ret; + + return 0; +} + + +static int get_op_mode(struct usb_device *udev) +{ + int ret; + u8 op_mode; + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x33, INTERFACE_VENDOR_REQUEST_IN, + 0x01, 0, + &op_mode, 1, HZ * USB_CTRL_GET_TIMEOUT); + if(ret < 0) + return ret; + return op_mode; +} + +/* this loads a block of the second part of the firmware */ +static inline int load_ext_fw_block(struct usb_device *udev, + int i, unsigned char *buf, int bsize) +{ + return usb_control_msg(udev, usb_sndctrlpipe(udev,0), + 0x0e, DEVICE_VENDOR_REQUEST_OUT, + 0x0802, i, + buf, bsize, HZ * USB_CTRL_GET_TIMEOUT); +} + +static inline int get_hw_cfg_rfmd(struct usb_device *udev, + unsigned char *buf, int buf_size) +{ + return usb_control_msg(udev, usb_rcvctrlpipe(udev,0), + 0x33, INTERFACE_VENDOR_REQUEST_IN, + ((0x0a << 8) | 0x02), 0, + buf, buf_size, HZ * USB_CTRL_GET_TIMEOUT); +} + +/* Intersil boards use a different "value" for GetHWConfig requests */ +static inline +int get_hw_cfg_intersil(struct usb_device *udev, + unsigned char *buf, int buf_size) +{ + return usb_control_msg(udev, usb_rcvctrlpipe(udev,0), + 0x33, INTERFACE_VENDOR_REQUEST_IN, + ((0x09 << 8) | 0x02), 0, + buf, buf_size, HZ * USB_CTRL_GET_TIMEOUT); +} + +/* Get the hardware configuration for the adapter and place the appropriate + * data in the appropriate fields of 'dev' (the GetHWConfig request and + * interpretation of the result depends on the type of board we're dealing + * with) */ +static int get_hw_config(struct at76c503 *dev) +{ + int ret; + union { + struct hwcfg_intersil i; + struct hwcfg_rfmd r3; + struct hwcfg_r505 r5; + } *hwcfg = kmalloc(sizeof(*hwcfg), GFP_KERNEL); + + if (!hwcfg) + return -ENOMEM; + + switch (dev->board_type) { + + case BOARDTYPE_503_INTERSIL_3861: + case BOARDTYPE_503_INTERSIL_3863: + ret = get_hw_cfg_intersil(dev->udev, (unsigned char *)&hwcfg->i, sizeof(hwcfg->i)); + if (ret < 0) break; + memcpy(dev->mac_addr, hwcfg->i.mac_addr, ETH_ALEN); + memcpy(dev->cr31_values, hwcfg->i.cr31_values, 14); + memcpy(dev->cr58_values, hwcfg->i.cr58_values, 14); + memcpy(dev->pidvid, hwcfg->i.pidvid, 4); + dev->regulatory_domain = hwcfg->i.regulatory_domain; + break; + + case BOARDTYPE_503_RFMD: + case BOARDTYPE_503_RFMD_ACC: + ret = get_hw_cfg_rfmd(dev->udev, (unsigned char *)&hwcfg->r3, sizeof(hwcfg->r3)); + if (ret < 0) break; + memcpy(dev->cr20_values, hwcfg->r3.cr20_values, 14); + memcpy(dev->cr21_values, hwcfg->r3.cr21_values, 14); + memcpy(dev->bb_cr, hwcfg->r3.bb_cr, 14); + memcpy(dev->pidvid, hwcfg->r3.pidvid, 4); + memcpy(dev->mac_addr, hwcfg->r3.mac_addr, ETH_ALEN); + dev->regulatory_domain = hwcfg->r3.regulatory_domain; + memcpy(dev->low_power_values, hwcfg->r3.low_power_values, 14); + memcpy(dev->normal_power_values, hwcfg->r3.normal_power_values, 14); + break; + + case BOARDTYPE_505_RFMD: + case BOARDTYPE_505_RFMD_2958: + case BOARDTYPE_505A_RFMD_2958: + ret = get_hw_cfg_rfmd(dev->udev, (unsigned char *)&hwcfg->r5, sizeof(hwcfg->r5)); + if (ret < 0) break; + memcpy(dev->cr39_values, hwcfg->r5.cr39_values, 14); + memcpy(dev->bb_cr, hwcfg->r5.bb_cr, 14); + memcpy(dev->pidvid, hwcfg->r5.pidvid, 4); + memcpy(dev->mac_addr, hwcfg->r5.mac_addr, ETH_ALEN); + dev->regulatory_domain = hwcfg->r5.regulatory_domain; + memcpy(dev->cr15_values, hwcfg->r5.cr15_values, 14); + break; + + default: + err("Bad board type set (%d). Unable to get hardware config.", dev->board_type); + ret = -EINVAL; + } + + kfree(hwcfg); + + if (ret < 0) { + err("Get HW Config failed (%d)", ret); + } + return ret; +} + +/* == PROC getRegDomain == */ +static struct reg_domain const *getRegDomain(u16 code) +{ + static struct reg_domain const fd_tab[] = { + {0x10, "FCC (U.S)", 0x7ff}, /* ch 1-11 */ + {0x20, "IC (Canada)", 0x7ff}, /* ch 1-11 */ + {0x30, "ETSI (Europe - (Spain+France)", 0x1fff}, /* ch 1-13 */ + {0x31, "Spain", 0x600}, /* ch 10,11 */ + {0x32, "France", 0x1e00}, /* ch 10-13 */ + {0x40, "MKK (Japan)", 0x2000}, /* ch 14 */ + {0x41, "MKK1 (Japan)", 0x3fff}, /* ch 1-14 */ + {0x50, "Israel", 0x3fc}, /* ch 3-9 */ + }; + static int const tab_len = sizeof(fd_tab) / sizeof(struct reg_domain); + + /* use this if an unknown code comes in */ + static struct reg_domain const unknown = + {0, "", 0xffffffff}; + + int i; + + for(i=0; i < tab_len; i++) + if (code == fd_tab[i].code) + break; + + return (i >= tab_len) ? &unknown : &fd_tab[i]; +} /* getFreqDomain */ + +static inline int get_mib(struct usb_device *udev, + u16 mib, u8 *buf, int buf_size) +{ + return usb_control_msg(udev, usb_rcvctrlpipe(udev,0), + 0x33, INTERFACE_VENDOR_REQUEST_IN, + mib << 8, 0, + buf, buf_size, HZ * USB_CTRL_GET_TIMEOUT); +} + +static inline int get_cmd_status(struct usb_device *udev, + u8 cmd, u8 *cmd_status) +{ + return usb_control_msg(udev, usb_rcvctrlpipe(udev,0), + 0x22, INTERFACE_VENDOR_REQUEST_IN, + cmd, 0, + cmd_status, 40, HZ * USB_CTRL_GET_TIMEOUT); +} + +#define EXT_FW_BLOCK_SIZE 1024 +static int download_external_fw(struct usb_device *udev, u8 *buf, int size) +{ + int i = 0, ret = 0; + u8 *block; + + if (size < 0) return -EINVAL; + if ((size > 0) && (buf == NULL)) return -EFAULT; + + block = kmalloc(EXT_FW_BLOCK_SIZE, GFP_KERNEL); + if (block == NULL) return -ENOMEM; + + dbg(DBG_DEVSTART, "downloading external firmware"); + + while(size > 0){ + int bsize = size > EXT_FW_BLOCK_SIZE ? EXT_FW_BLOCK_SIZE : size; + + memcpy(block, buf, bsize); + dbg(DBG_DEVSTART, + "ext fw, size left = %5d, bsize = %4d, i = %2d", size, bsize, i); + if((ret = load_ext_fw_block(udev, i, block, bsize)) < 0){ + err("load_ext_fw_block failed: %d, i = %d", ret, i); + goto exit; + } + buf += bsize; + size -= bsize; + i++; + } + + /* for fw >= 0.100, the device needs + an extra empty block: */ + if((ret = load_ext_fw_block(udev, i, block, 0)) < 0){ + err("load_ext_fw_block failed: %d, i = %d", ret, i); + goto exit; + } + + exit: + kfree(block); + return ret; +} + +static int set_card_command(struct usb_device *udev, int cmd, + unsigned char *buf, int buf_size) +{ + int ret; + struct at76c503_command *cmd_buf = + (struct at76c503_command *)kmalloc( + sizeof(struct at76c503_command) + buf_size, + GFP_KERNEL); + + if(cmd_buf){ + cmd_buf->cmd = cmd; + cmd_buf->reserved = 0; + cmd_buf->size = cpu_to_le16(buf_size); + if(buf_size > 0) + memcpy(&(cmd_buf[1]), buf, buf_size); + ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0), + 0x0e, DEVICE_VENDOR_REQUEST_OUT, + 0, 0, + cmd_buf, + sizeof(struct at76c503_command) + buf_size, + HZ * USB_CTRL_GET_TIMEOUT); + kfree(cmd_buf); + return ret; + } + + return -ENOMEM; +} + +#define MAKE_CMD_STATUS_CASE(c) case (c): return #c + +static const char* get_cmd_status_string(u8 cmd_status) +{ + switch (cmd_status) + { + MAKE_CMD_STATUS_CASE(CMD_STATUS_IDLE); + MAKE_CMD_STATUS_CASE(CMD_STATUS_COMPLETE); + MAKE_CMD_STATUS_CASE(CMD_STATUS_UNKNOWN); + MAKE_CMD_STATUS_CASE(CMD_STATUS_INVALID_PARAMETER); + MAKE_CMD_STATUS_CASE(CMD_STATUS_FUNCTION_NOT_SUPPORTED); + MAKE_CMD_STATUS_CASE(CMD_STATUS_TIME_OUT); + MAKE_CMD_STATUS_CASE(CMD_STATUS_IN_PROGRESS); + MAKE_CMD_STATUS_CASE(CMD_STATUS_HOST_FAILURE); + MAKE_CMD_STATUS_CASE(CMD_STATUS_SCAN_FAILED); + } + + return "UNKNOWN"; +} + +/* TODO: should timeout */ +static int wait_completion(struct at76c503 *dev, int cmd) +{ + u8 *cmd_status = kmalloc(40, GFP_KERNEL); + struct net_device *netdev = dev->netdev; + int ret = 0; + + do{ + ret = get_cmd_status(dev->udev, cmd, cmd_status); + if(ret < 0){ + err("%s: get_cmd_status failed: %d", netdev->name, ret); + break; + } + + dbg(DBG_WAIT_COMPLETE, "%s: Waiting on cmd %d, cmd_status[5] = %d (%s)", + dev->netdev->name, cmd, cmd_status[5], get_cmd_status_string(cmd_status[5])); + + if(cmd_status[5] == CMD_STATUS_IN_PROGRESS || + cmd_status[5] == CMD_STATUS_IDLE){ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/10); // 100 ms + }else break; + }while(1); + + if (ret >= 0) + /* if get_cmd_status did not fail, return the status + retrieved */ + ret = cmd_status[5]; + kfree(cmd_status); + return ret; +} + +static int set_mib(struct at76c503 *dev, struct set_mib_buffer *buf) +{ + struct usb_device *udev = dev->udev; + int ret; + struct at76c503_command *cmd_buf = + (struct at76c503_command *)kmalloc( + sizeof(struct at76c503_command) + buf->size + 4, + GFP_KERNEL); + + if(cmd_buf){ + cmd_buf->cmd = CMD_SET_MIB; + cmd_buf->reserved = 0; + cmd_buf->size = cpu_to_le16(buf->size + 4); + memcpy(&(cmd_buf[1]), buf, buf->size + 4); + ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0), + 0x0e, DEVICE_VENDOR_REQUEST_OUT, + 0, 0, + cmd_buf, + sizeof(struct at76c503_command) + buf->size + 4, + HZ * USB_CTRL_GET_TIMEOUT); + if (ret >= 0) + if ((ret=wait_completion(dev, CMD_SET_MIB)) != + CMD_STATUS_COMPLETE) { + info("%s: set_mib: wait_completion failed with %d", + dev->netdev->name, ret); + ret = -156; /* ??? */ + } + kfree(cmd_buf); + return ret; + } + + return -ENOMEM; +} + +/* return < 0 on error, == 0 if no command sent, == 1 if cmd sent */ +static int set_radio(struct at76c503 *dev, int on_off) +{ + int ret; + + if(dev->radio_on != on_off){ + ret = set_card_command(dev->udev, CMD_RADIO, NULL, 0); + if(ret < 0){ + err("%s: set_card_command(CMD_RADIO) failed: %d", dev->netdev->name, ret); + } else + ret = 1; + dev->radio_on = on_off; + } else + ret = 0; + return ret; +} + + +/* == PROC set_pm_mode == + sets power save modi (PM_ACTIVE/PM_SAVE/PM_SMART_SAVE) */ +static int set_pm_mode(struct at76c503 *dev, u8 mode) +{ + int ret = 0; + + memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); + dev->mib_buf.type = MIB_MAC_MGMT; + dev->mib_buf.size = 1; + dev->mib_buf.index = POWER_MGMT_MODE_OFFSET; + + dev->mib_buf.data[0] = mode; + + ret = set_mib(dev, &dev->mib_buf); + if(ret < 0){ + err("%s: set_mib (pm_mode) failed: %d", dev->netdev->name, ret); + } + return ret; +} + +/* == PROC set_associd == + sets the assoc id for power save mode */ +static int set_associd(struct at76c503 *dev, u16 id) +{ + int ret = 0; + + memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); + dev->mib_buf.type = MIB_MAC_MGMT; + dev->mib_buf.size = 2; + dev->mib_buf.index = STATION_ID_OFFSET; + + dev->mib_buf.data[0] = id & 0xff; + dev->mib_buf.data[1] = id >> 8; + + ret = set_mib(dev, &dev->mib_buf); + if(ret < 0){ + err("%s: set_mib (associd) failed: %d", dev->netdev->name, ret); + } + return ret; +} + +/* == PROC set_listen_interval == + sets the listen interval for power save mode. + really needed, as we have a similar parameter in the assocreq ??? */ +static int set_listen_interval(struct at76c503 *dev, u16 interval) +{ + int ret = 0; + + memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); + dev->mib_buf.type = MIB_MAC; + dev->mib_buf.size = 2; + dev->mib_buf.index = STATION_ID_OFFSET; + + dev->mib_buf.data[0] = interval & 0xff; + dev->mib_buf.data[1] = interval >> 8; + + ret = set_mib(dev, &dev->mib_buf); + if(ret < 0){ + err("%s: set_mib (listen_interval) failed: %d", + dev->netdev->name, ret); + } + return ret; +} + +static int set_preamble(struct at76c503 *dev, u8 type) +{ + int ret = 0; + + memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); + dev->mib_buf.type = MIB_LOCAL; + dev->mib_buf.size = 1; + dev->mib_buf.index = PREAMBLE_TYPE_OFFSET; + dev->mib_buf.data[0] = type; + ret = set_mib(dev, &dev->mib_buf); + if(ret < 0){ + err("%s: set_mib (preamble) failed: %d", dev->netdev->name, ret); + } + return ret; +} + +static int set_frag(struct at76c503 *dev, u16 size) +{ + int ret = 0; + + memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); + dev->mib_buf.type = MIB_MAC; + dev->mib_buf.size = 2; + dev->mib_buf.index = FRAGMENTATION_OFFSET; + *(__le16*)dev->mib_buf.data = cpu_to_le16(size); + ret = set_mib(dev, &dev->mib_buf); + if(ret < 0){ + err("%s: set_mib (frag threshold) failed: %d", dev->netdev->name, ret); + } + return ret; +} + +static int set_rts(struct at76c503 *dev, u16 size) +{ + int ret = 0; + + memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); + dev->mib_buf.type = MIB_MAC; + dev->mib_buf.size = 2; + dev->mib_buf.index = RTS_OFFSET; + *(__le16*)dev->mib_buf.data = cpu_to_le16(size); + ret = set_mib(dev, &dev->mib_buf); + if(ret < 0){ + err("%s: set_mib (rts) failed: %d", dev->netdev->name, ret); + } + return ret; +} + +static int set_autorate_fallback(struct at76c503 *dev, int onoff) +{ + int ret = 0; + + memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); + dev->mib_buf.type = MIB_LOCAL; + dev->mib_buf.size = 1; + dev->mib_buf.index = TX_AUTORATE_FALLBACK_OFFSET; + dev->mib_buf.data[0] = onoff; + ret = set_mib(dev, &dev->mib_buf); + if(ret < 0){ + err("%s: set_mib (autorate fallback) failed: %d", dev->netdev->name, ret); + } + return ret; +} + +static int set_mac_address(struct at76c503 *dev, void *addr) +{ + int ret = 0; + + memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); + dev->mib_buf.type = MIB_MAC_ADD; + dev->mib_buf.size = ETH_ALEN; + dev->mib_buf.index = offsetof(struct mib_mac_addr, mac_addr); + memcpy(dev->mib_buf.data, addr, ETH_ALEN); + ret = set_mib(dev, &dev->mib_buf); + if(ret < 0){ + err("%s: set_mib (MAC_ADDR, mac_addr) failed: %d", + dev->netdev->name, ret); + } + return ret; +} + +#if 0 +/* implemented to get promisc. mode working, but does not help. + May still be useful for multicast eventually. */ +static int set_group_address(struct at76c503 *dev, u8 *addr, int n) +{ + int ret = 0; + + memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); + dev->mib_buf.type = MIB_MAC_ADD; + dev->mib_buf.size = ETH_ALEN; + dev->mib_buf.index = offsetof(struct mib_mac_addr, group_addr) + n*ETH_ALEN; + memcpy(dev->mib_buf.data, addr, ETH_ALEN); + ret = set_mib(dev, &dev->mib_buf); + if(ret < 0){ + err("%s: set_mib (MIB_MAC_ADD, group_addr) failed: %d", + dev->netdev->name, ret); + } + +#if 1 + /* I do not know anything about the group_addr_status field... (oku) */ + memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); + dev->mib_buf.type = MIB_MAC_ADD; + dev->mib_buf.size = 1; + dev->mib_buf.index = offsetof(struct mib_mac_addr, group_addr_status) + n; + dev->mib_buf.data[0] = 1; + ret = set_mib(dev, &dev->mib_buf); + if(ret < 0){ + err("%s: set_mib (MIB_MAC_ADD, group_addr_status) failed: %d", + dev->netdev->name, ret); + } +#endif + return ret; +} +#endif + +static int set_promisc(struct at76c503 *dev, int onoff) +{ + int ret = 0; + + memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); + dev->mib_buf.type = MIB_LOCAL; + dev->mib_buf.size = 1; + dev->mib_buf.index = offsetof(struct mib_local, promiscuous_mode); + dev->mib_buf.data[0] = onoff ? 1 : 0; + ret = set_mib(dev, &dev->mib_buf); + if(ret < 0){ + err("%s: set_mib (promiscuous_mode) failed: %d", dev->netdev->name, ret); + } + return ret; +} + +static int dump_mib_mac_addr(struct at76c503 *dev) +{ + int ret = 0; + struct mib_mac_addr *mac_addr = + kmalloc(sizeof(struct mib_mac_addr), GFP_KERNEL); + + if(!mac_addr){ + ret = -ENOMEM; + goto exit; + } + + ret = get_mib(dev->udev, MIB_MAC_ADD, + (u8*)mac_addr, sizeof(struct mib_mac_addr)); + if(ret < 0){ + err("%s: get_mib (MAC_ADDR) failed: %d", dev->netdev->name, ret); + goto err; + } + + dbg_uc("%s: MIB MAC_ADDR: mac_addr %s res 0x%x 0x%x group_addr %s status %d %d %d %d", + dev->netdev->name, mac2str(mac_addr->mac_addr), + mac_addr->res[0], mac_addr->res[1], + hex2str(dev->obuf, (u8 *)mac_addr->group_addr, + min((int)(sizeof(dev->obuf)-1)/2, 4*ETH_ALEN), '\0'), + mac_addr->group_addr_status[0], mac_addr->group_addr_status[1], + mac_addr->group_addr_status[2], mac_addr->group_addr_status[3]); + + err: + kfree(mac_addr); + exit: + return ret; +} + +static int dump_mib_mac_wep(struct at76c503 *dev) +{ + int ret = 0; + struct mib_mac_wep *mac_wep = + kmalloc(sizeof(struct mib_mac_wep), GFP_KERNEL); + + if(!mac_wep){ + ret = -ENOMEM; + goto exit; + } + + ret = get_mib(dev->udev, MIB_MAC_WEP, + (u8*)mac_wep, sizeof(struct mib_mac_wep)); + if(ret < 0){ + err("%s: get_mib (MAC_WEP) failed: %d", dev->netdev->name, ret); + goto err; + } + + dbg_uc("%s: MIB MAC_WEP: priv_invoked %u def_key_id %u key_len %u " + "excl_unencr %u wep_icv_err %u wep_excluded %u encr_level %u key %d: %s", + dev->netdev->name, mac_wep->privacy_invoked, + mac_wep->wep_default_key_id, mac_wep->wep_key_mapping_len, + mac_wep->exclude_unencrypted,le32_to_cpu( mac_wep->wep_icv_error_count), + le32_to_cpu(mac_wep->wep_excluded_count), + mac_wep->encryption_level, mac_wep->wep_default_key_id, + mac_wep->wep_default_key_id < 4 ? + hex2str(dev->obuf, + mac_wep->wep_default_keyvalue[mac_wep->wep_default_key_id], + min((int)(sizeof(dev->obuf)-1)/2, + mac_wep->encryption_level == 2 ? 13 : 5), '\0') : + ""); + + err: + kfree(mac_wep); + exit: + return ret; +} + +static int dump_mib_mac_mgmt(struct at76c503 *dev) +{ + int ret = 0; + struct mib_mac_mgmt *mac_mgmt = + kmalloc(sizeof(struct mib_mac_mgmt), GFP_KERNEL); + char country_string[4]; + + if(!mac_mgmt){ + ret = -ENOMEM; + goto exit; + } + + ret = get_mib(dev->udev, MIB_MAC_MGMT, + (u8*)mac_mgmt, sizeof(struct mib_mac_mgmt)); + if(ret < 0){ + err("%s: get_mib failed: %d", dev->netdev->name, ret); + goto err; + } + + memcpy(&country_string, mac_mgmt->country_string, 3); + country_string[3] = '\0'; + + dbg_uc("%s: MIB MAC_MGMT: beacon_period %d CFP_max_duration %d " + "medium_occupancy_limit %d station_id 0x%x ATIM_window %d " + "CFP_mode %d privacy_opt_impl %d DTIM_period %d CFP_period %d " + "current_bssid %s current_essid %s current_bss_type %d " + "pm_mode %d ibss_change %d res %d " + "multi_domain_capability_implemented %d " + "international_roaming %d country_string %s", + dev->netdev->name, + le16_to_cpu(mac_mgmt->beacon_period), + le16_to_cpu(mac_mgmt->CFP_max_duration), + le16_to_cpu(mac_mgmt->medium_occupancy_limit), + le16_to_cpu(mac_mgmt->station_id), + le16_to_cpu(mac_mgmt->ATIM_window), + mac_mgmt->CFP_mode, + mac_mgmt->privacy_option_implemented, + mac_mgmt->DTIM_period, + mac_mgmt->CFP_period, + mac2str(mac_mgmt->current_bssid), + hex2str(dev->obuf, (u8 *)mac_mgmt->current_essid, + min((int)(sizeof(dev->obuf)-1)/2, + IW_ESSID_MAX_SIZE), '\0'), + mac_mgmt->current_bss_type, + mac_mgmt->power_mgmt_mode, + mac_mgmt->ibss_change, + mac_mgmt->res, + mac_mgmt->multi_domain_capability_implemented, + mac_mgmt->multi_domain_capability_enabled, + country_string); + err: + kfree(mac_mgmt); + exit: + return ret; +} + +static int dump_mib_mac(struct at76c503 *dev) +{ + int ret = 0; + struct mib_mac *mac = + kmalloc(sizeof(struct mib_mac), GFP_KERNEL); + + if(!mac){ + ret = -ENOMEM; + goto exit; + } + + ret = get_mib(dev->udev, MIB_MAC, + (u8*)mac, sizeof(struct mib_mac)); + if(ret < 0){ + err("%s: get_mib failed: %d", dev->netdev->name, ret); + goto err; + } + + dbg_uc("%s: MIB MAC: max_tx_msdu_lifetime %d max_rx_lifetime %d " + "frag_threshold %d rts_threshold %d cwmin %d cwmax %d " + "short_retry_time %d long_retry_time %d scan_type %d " + "scan_channel %d probe_delay %u min_channel_time %d " + "max_channel_time %d listen_int %d desired_ssid %s " + "desired_bssid %s desired_bsstype %d", + dev->netdev->name, + le32_to_cpu(mac->max_tx_msdu_lifetime), + le32_to_cpu(mac->max_rx_lifetime), + le16_to_cpu(mac->frag_threshold), + le16_to_cpu(mac->rts_threshold), + le16_to_cpu(mac->cwmin), + le16_to_cpu(mac->cwmax), + mac->short_retry_time, + mac->long_retry_time, + mac->scan_type, + mac->scan_channel, + le16_to_cpu(mac->probe_delay), + le16_to_cpu(mac->min_channel_time), + le16_to_cpu(mac->max_channel_time), + le16_to_cpu(mac->listen_interval), + hex2str(dev->obuf, mac->desired_ssid, + min((int)(sizeof(dev->obuf)-1)/2, + IW_ESSID_MAX_SIZE), '\0'), + mac2str(mac->desired_bssid), + mac->desired_bsstype); + err: + kfree(mac); + exit: + return ret; +} + +static int dump_mib_phy(struct at76c503 *dev) +{ + int ret = 0; + struct mib_phy *phy = + kmalloc(sizeof(struct mib_phy), GFP_KERNEL); + + if(!phy){ + ret = -ENOMEM; + goto exit; + } + + ret = get_mib(dev->udev, MIB_PHY, + (u8*)phy, sizeof(struct mib_phy)); + if(ret < 0){ + err("%s: get_mib failed: %d", dev->netdev->name, ret); + goto err; + } + + dbg_uc("%s: MIB PHY: ed_threshold %d slot_time %d sifs_time %d " + "preamble_length %d plcp_header_length %d mpdu_max_length %d " + "cca_mode_supported %d operation_rate_set " + "0x%x 0x%x 0x%x 0x%x channel_id %d current_cca_mode %d " + "phy_type %d current_reg_domain %d", + dev->netdev->name, + le32_to_cpu(phy->ed_threshold), + le16_to_cpu(phy->slot_time), + le16_to_cpu(phy->sifs_time), + le16_to_cpu(phy->preamble_length), + le16_to_cpu(phy->plcp_header_length), + le16_to_cpu(phy->mpdu_max_length), + le16_to_cpu(phy->cca_mode_supported), + phy->operation_rate_set[0], phy->operation_rate_set[1], + phy->operation_rate_set[2], phy->operation_rate_set[3], + phy->channel_id, + phy->current_cca_mode, + phy->phy_type, + phy->current_reg_domain); + err: + kfree(phy); + exit: + return ret; +} + +static int dump_mib_local(struct at76c503 *dev) +{ + int ret = 0; + struct mib_local *local = + kmalloc(sizeof(struct mib_phy), GFP_KERNEL); + + if(!local){ + ret = -ENOMEM; + goto exit; + } + + ret = get_mib(dev->udev, MIB_LOCAL, + (u8*)local, sizeof(struct mib_local)); + if(ret < 0){ + err("%s: get_mib failed: %d", dev->netdev->name, ret); + goto err; + } + + dbg_uc("%s: MIB PHY: beacon_enable %d txautorate_fallback %d " + "ssid_size %d promiscuous_mode %d preamble_type %d", + dev->netdev->name, + local->beacon_enable, + local->txautorate_fallback, + local->ssid_size, + local->promiscuous_mode, + local->preamble_type); + err: + kfree(local); + exit: + return ret; +} + + +static int get_mib_mdomain(struct at76c503 *dev, struct mib_mdomain *val) +{ + int ret = 0; + struct mib_mdomain *mdomain = + kmalloc(sizeof(struct mib_mdomain), GFP_KERNEL); + + if(!mdomain){ + ret = -ENOMEM; + goto exit; + } + + ret = get_mib(dev->udev, MIB_MDOMAIN, + (u8*)mdomain, sizeof(struct mib_mdomain)); + if(ret < 0){ + err("%s: get_mib failed: %d", dev->netdev->name, ret); + goto err; + } + + memcpy(val, mdomain, sizeof(*val)); + + err: + kfree(mdomain); + exit: + return ret; +} + +static void dump_mib_mdomain(struct at76c503 *dev) +{ + char obuf1[2*14+1], obuf2[2*14+1]; /* to hexdump tx_powerlevel, + channel_list */ + int ret; + struct mib_mdomain mdomain; + + if ((ret=get_mib_mdomain(dev, &mdomain)) < 0) { + err("%s: get_mib_mdomain returned %d", __FUNCTION__, ret); + return; + } + + dbg(DBG_MIB, "%s: MIB MDOMAIN: channel_list %s tx_powerlevel %s", + dev->netdev->name, + hex2str(obuf1, mdomain.channel_list, + (sizeof(obuf1)-1)/2,'\0'), + hex2str(obuf2, mdomain.tx_powerlevel, + (sizeof(obuf2)-1)/2,'\0')); +} + +static +int get_current_bssid(struct at76c503 *dev) +{ + int ret = 0; + struct mib_mac_mgmt *mac_mgmt = + kmalloc(sizeof(struct mib_mac_mgmt), GFP_KERNEL); + + if(!mac_mgmt){ + ret = -ENOMEM; + goto exit; + } + + ret = get_mib(dev->udev, MIB_MAC_MGMT, + (u8*)mac_mgmt, sizeof(struct mib_mac_mgmt)); + if(ret < 0){ + err("%s: get_mib failed: %d", dev->netdev->name, ret); + goto err; + } + memcpy(dev->bssid, mac_mgmt->current_bssid, ETH_ALEN); + info("using BSSID %s", mac2str(dev->bssid)); + err: + kfree(mac_mgmt); + exit: + return ret; +} + +static int get_current_channel(struct at76c503 *dev) +{ + int ret = 0; + struct mib_phy *phy = + kmalloc(sizeof(struct mib_phy), GFP_KERNEL); + + if(!phy){ + ret = -ENOMEM; + goto exit; + } + ret = get_mib(dev->udev, MIB_PHY, (u8*)phy, + sizeof(struct mib_phy)); + if(ret < 0){ + err("%s: get_mib(MIB_PHY) failed: %d", dev->netdev->name, ret); + goto err; + } + dev->channel = phy->channel_id; + err: + kfree(phy); + exit: + return ret; +} + +/* == PROC start_scan == + start a scan. use_essid is != 0 if any probe_delay (if scan mode is not + passive) should contain the ESSID configured. ir_step describes the + international roaming step (0, 1) */ +static int start_scan(struct at76c503 *dev, int use_essid, int ir_step) +{ + struct at76c503_start_scan scan; + + memset(&scan, 0, sizeof(struct at76c503_start_scan)); + memset(scan.bssid, 0xff, ETH_ALEN); + + if (use_essid) { + memcpy(scan.essid, dev->essid, IW_ESSID_MAX_SIZE); + scan.essid_size = dev->essid_size; + } else + scan.essid_size = 0; + + //jal: why should we start at a certain channel? we do scan the whole range + //allowed by reg domain. + scan.channel = dev->channel; + + /* atmelwlandriver differs between scan type 0 and 1 (active/passive) + For ad-hoc mode, it uses type 0 only.*/ + if ((dev->international_roaming == IR_ON && ir_step == 0) || + dev->iw_mode == IW_MODE_MONITOR) + scan.scan_type = SCAN_TYPE_PASSIVE; + else + scan.scan_type = dev->scan_mode; + + /* INFO: For probe_delay, not multiplying by 1024 as this will be + slightly less than min_channel_time + (per spec: probe delay < min. channel time) */ + LOCK_ISTATE() + if (dev->istate == MONITORING) { + scan.min_channel_time = cpu_to_le16(dev->monitor_scan_min_time); + scan.max_channel_time = cpu_to_le16(dev->monitor_scan_max_time); + scan.probe_delay = cpu_to_le16(dev->monitor_scan_min_time * 1000); + } else { + scan.min_channel_time = cpu_to_le16(dev->scan_min_time); + scan.max_channel_time = cpu_to_le16(dev->scan_max_time); + scan.probe_delay = cpu_to_le16(dev->scan_min_time * 1000); + } + UNLOCK_ISTATE() + if (dev->international_roaming == IR_ON && ir_step == 1) + scan.international_scan = 0; + else + scan.international_scan = dev->international_roaming; + + /* other values are set to 0 for type 0 */ + + dbg(DBG_PROGRESS, "%s: start_scan (use_essid = %d, intl = %d, " + "channel = %d, probe_delay = %d, scan_min_time = %d, " + "scan_max_time = %d)", + dev->netdev->name, use_essid, + scan.international_scan, scan.channel, + le16_to_cpu(scan.probe_delay), + le16_to_cpu(scan.min_channel_time), + le16_to_cpu(scan.max_channel_time)); + + return set_card_command(dev->udev, CMD_SCAN, + (unsigned char*)&scan, sizeof(scan)); +} + +static int start_ibss(struct at76c503 *dev) +{ + struct at76c503_start_bss bss; + + memset(&bss, 0, sizeof(struct at76c503_start_bss)); + memset(bss.bssid, 0xff, ETH_ALEN); + memcpy(bss.essid, dev->essid, IW_ESSID_MAX_SIZE); + bss.essid_size = dev->essid_size; + bss.bss_type = ADHOC_MODE; + bss.channel = dev->channel; + + return set_card_command(dev->udev, CMD_START_IBSS, + (unsigned char*)&bss, sizeof(struct at76c503_start_bss)); +} + +/* idx points into dev->bss */ +static int join_bss(struct at76c503 *dev, struct bss_info *ptr) +{ + struct at76c503_join join; + + assert(ptr != NULL); + + memset(&join, 0, sizeof(struct at76c503_join)); + memcpy(join.bssid, ptr->bssid, ETH_ALEN); + memcpy(join.essid, ptr->ssid, ptr->ssid_len); + join.essid_size = ptr->ssid_len; + join.bss_type = (dev->iw_mode == IW_MODE_ADHOC ? 1 : 2); + join.channel = ptr->channel; + join.timeout = cpu_to_le16(2000); + + dbg(DBG_PROGRESS, "%s join addr %s ssid %s type %d ch %d timeout %d", + dev->netdev->name, mac2str(join.bssid), + join.essid, join.bss_type, join.channel, le16_to_cpu(join.timeout)); + return set_card_command(dev->udev, CMD_JOIN, + (unsigned char*)&join, + sizeof(struct at76c503_join)); +} /* join_bss */ + +/* the firmware download timeout (after remap) */ +static void fw_dl_timeout(unsigned long par) +{ + struct at76c503 *dev = (struct at76c503 *)par; + defer_kevent(dev, KEVENT_RESET_DEVICE); +} + + +/* the restart timer timed out */ +static void restart_timeout(unsigned long par) +{ + struct at76c503 *dev = (struct at76c503 *)par; + defer_kevent(dev, KEVENT_RESTART); +} + +/* we got to check the bss_list for old entries */ +static void bss_list_timeout(unsigned long par) +{ + struct at76c503 *dev = (struct at76c503 *)par; + unsigned long flags; + struct list_head *lptr, *nptr; + struct bss_info *ptr; + + spin_lock_irqsave(&dev->bss_list_spinlock, flags); + + list_for_each_safe(lptr, nptr, &dev->bss_list) { + + ptr = list_entry(lptr, struct bss_info, list); + + if (ptr != dev->curr_bss && ptr != dev->new_bss && + time_after(jiffies, ptr->last_rx+BSS_LIST_TIMEOUT)) { + dbg(DBG_BSS_TABLE_RM, + "%s: bss_list: removing old BSS %s ch %d", + dev->netdev->name, mac2str(ptr->bssid), ptr->channel); + list_del(&ptr->list); + kfree(ptr); + } + } + spin_unlock_irqrestore(&dev->bss_list_spinlock, flags); + /* restart the timer */ + mod_timer(&dev->bss_list_timer, jiffies+BSS_LIST_TIMEOUT); + +} + +/* we got a timeout for a infrastructure mgmt packet */ +static void mgmt_timeout(unsigned long par) +{ + struct at76c503 *dev = (struct at76c503 *)par; + defer_kevent(dev, KEVENT_MGMT_TIMEOUT); +} + +/* == PROC handle_mgmt_timeout_scan == */ +/* called in istate SCANNING on expiry of the mgmt_timer, when a scan was run before + (dev->scan_runs > 0) */ +static void handle_mgmt_timeout_scan(struct at76c503 *dev) +{ + + u8 *cmd_status; + int ret; + struct mib_mdomain mdomain; + + cmd_status = kmalloc(40, GFP_KERNEL); + if (cmd_status == NULL) { + err("%s: %s: cmd_status kmalloc returned NULL", + dev->netdev->name, __FUNCTION__); + return; + } + + + if ((ret=get_cmd_status(dev->udev, CMD_SCAN, cmd_status)) < 0) { + err("%s: %s: get_cmd_status failed with %d", + dev->netdev->name, __FUNCTION__, ret); + cmd_status[5] = CMD_STATUS_IN_PROGRESS; + /* INFO: Hope it was a one off error - if not, scanning + further down the line and stop this cycle */ + } + LOCK_ISTATE() + dbg(DBG_PROGRESS, "%s %s:%d got cmd_status %d (istate %d, " + "scan_runs %d)", + dev->netdev->name, __FUNCTION__, __LINE__, cmd_status[5], + dev->istate, dev->scan_runs); + UNLOCK_ISTATE() + if (cmd_status[5] == CMD_STATUS_COMPLETE) { + LOCK_ISTATE() + if (dev->istate == SCANNING) { + UNLOCK_ISTATE() + dump_bss_table(dev,0); + switch (dev->scan_runs) { + + case 1: + assert(dev->international_roaming); + if ((ret=get_mib_mdomain(dev, &mdomain)) < 0) { + err("get_mib_mdomain returned %d", ret); + } else { + char obuf1[2*14+1], obuf2[2*14+1]; + + dbg(DBG_MIB, "%s: MIB MDOMAIN: channel_list %s " + "tx_powerlevel %s", + dev->netdev->name, + hex2str(obuf1, mdomain.channel_list, + (sizeof(obuf1)-1)/2,'\0'), + hex2str(obuf2, mdomain.tx_powerlevel, + (sizeof(obuf2)-1)/2,'\0')); + } + if ((ret = start_scan(dev, 0, 1)) < 0) { + err("%s: %s: start_scan (ANY) failed with %d", + dev->netdev->name, __FUNCTION__, ret); + } + dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer for %d ticks", + __FUNCTION__, __LINE__, SCAN_POLL_INTERVAL); + mod_timer(&dev->mgmt_timer, jiffies + SCAN_POLL_INTERVAL); + break; + + case 2: + if ((ret = start_scan(dev, 1, 1)) < 0) { + err("%s: %s: start_scan (SSID) failed with %d", + dev->netdev->name, __FUNCTION__, ret); + } + dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer for %d ticks", + __FUNCTION__, __LINE__, SCAN_POLL_INTERVAL); + mod_timer(&dev->mgmt_timer, jiffies + SCAN_POLL_INTERVAL); + break; + + case 3: + dev->site_survey_state = SITE_SURVEY_COMPLETED; + /* report the end of scan to user space */ + iwevent_scan_complete(dev->netdev); + NEW_STATE(dev,JOINING); + assert(dev->curr_bss == NULL); /* done in free_bss_list, + find_bss will start with first bss */ + /* call join_bss immediately after + re-run of all other threads in kevent */ + defer_kevent(dev,KEVENT_JOIN); + break; + + default: + err("unexpected dev->scan_runs %d", dev->scan_runs); + } /* switch (dev->scan_runs)*/ + dev->scan_runs++; + } else { + + assert(dev->istate == MONITORING); + UNLOCK_ISTATE() + dbg(DBG_MONITOR_MODE, "%s: MONITOR MODE: restart scan", + dev->netdev->name); + start_scan(dev, 0, 0); + dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer for %d ticks", + __FUNCTION__, __LINE__, SCAN_POLL_INTERVAL); + mod_timer(&dev->mgmt_timer, jiffies + SCAN_POLL_INTERVAL); + } + + } else { + if ((cmd_status[5] != CMD_STATUS_IN_PROGRESS) && + (cmd_status[5] != CMD_STATUS_IDLE)) + err("%s: %s: Bad scan status: %s", + dev->netdev->name, __FUNCTION__, + get_cmd_status_string(cmd_status[5])); + + /* the first cmd status after scan start is always a IDLE -> + start the timer to poll again until COMPLETED */ + dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer for %d ticks", + __FUNCTION__, __LINE__, SCAN_POLL_INTERVAL); + mod_timer(&dev->mgmt_timer, jiffies + SCAN_POLL_INTERVAL); + } + + kfree(cmd_status); +} + +/* the deferred procedure called from kevent() */ +static void handle_mgmt_timeout(struct at76c503 *dev) +{ + LOCK_ISTATE() + if ((dev->istate != SCANNING && dev->istate != MONITORING) || + (at76_debug & DBG_MGMT_TIMER)) + /* this is normal behavior in states MONITORING, SCANNING ... */ + dbg(DBG_PROGRESS, "%s: timeout, state %d", dev->netdev->name, + dev->istate); + + switch(dev->istate) { + + case MONITORING: + case SCANNING: + UNLOCK_ISTATE() + handle_mgmt_timeout_scan(dev); + break; + + case JOINING: + UNLOCK_ISTATE() + assert(0); + break; + + case CONNECTED: /* we haven't received the beacon of this BSS for + BEACON_TIMEOUT seconds */ + UNLOCK_ISTATE() + info("%s: lost beacon bssid %s", + dev->netdev->name, mac2str(dev->curr_bss->bssid)); + /* jal: starting mgmt_timer in ad-hoc mode is questionable, + but I'll leave it here to track down another lockup problem */ + if (dev->iw_mode != IW_MODE_ADHOC) { + netif_carrier_off(dev->netdev); + netif_stop_queue(dev->netdev); + iwevent_bss_disconnect(dev->netdev); + NEW_STATE(dev,SCANNING); + defer_kevent(dev,KEVENT_SCAN); + } + break; + + case AUTHENTICATING: + UNLOCK_ISTATE() + if (dev->retries-- >= 0) { + auth_req(dev, dev->curr_bss, 1, NULL); + dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ", + __FUNCTION__, __LINE__); + mod_timer(&dev->mgmt_timer, jiffies+HZ); + } else { + /* try to get next matching BSS */ + NEW_STATE(dev,JOINING); + defer_kevent(dev,KEVENT_JOIN); + } + break; + + case ASSOCIATING: + UNLOCK_ISTATE() + if (dev->retries-- >= 0) { + assoc_req(dev,dev->curr_bss); + dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ", + __FUNCTION__, __LINE__); + mod_timer(&dev->mgmt_timer, jiffies+HZ); + } else { + /* jal: TODO: we may be authenticated to several + BSS and may try to associate to the next of them here + in the future ... */ + + /* try to get next matching BSS */ + NEW_STATE(dev,JOINING); + defer_kevent(dev,KEVENT_JOIN); + } + break; + + case REASSOCIATING: + UNLOCK_ISTATE() + if (dev->retries-- >= 0) + reassoc_req(dev, dev->curr_bss, dev->new_bss); + else { + /* we disassociate from the curr_bss and + scan again ... */ + NEW_STATE(dev,DISASSOCIATING); + dev->retries = DISASSOC_RETRIES; + disassoc_req(dev, dev->curr_bss); + } + dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ", + __FUNCTION__, __LINE__); + mod_timer(&dev->mgmt_timer, jiffies+HZ); + break; + + case DISASSOCIATING: + UNLOCK_ISTATE() + if (dev->retries-- >= 0) { + disassoc_req(dev, dev->curr_bss); + dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ", + __FUNCTION__, __LINE__); + mod_timer(&dev->mgmt_timer,jiffies+HZ); + } else { + /* we scan again ... */ + NEW_STATE(dev,SCANNING); + defer_kevent(dev,KEVENT_SCAN); + } + break; + + case INIT: + UNLOCK_ISTATE() + break; + + default: + UNLOCK_ISTATE() + assert(0); + } /* switch (dev->istate) */ + +}/* handle_mgmt_timeout */ + +/* calc. the padding from txbuf->wlength (which excludes the USB TX header) + guess this is needed to compensate a flaw in the AT76C503A USB part ... */ +static inline int calc_padding(int wlen) +{ + /* add the USB TX header */ + wlen += AT76C503_TX_HDRLEN; + + wlen = wlen % 64; + + if (wlen < 50) + return 50 - wlen; + + if (wlen >=61) + return 64 + 50 - wlen; + + return 0; +} + +/* send a management frame on bulk-out. + txbuf->wlength must be set (in LE format !) */ +static int send_mgmt_bulk(struct at76c503 *dev, struct at76c503_tx_buffer *txbuf) +{ + unsigned long flags; + int ret = 0; + int urb_status; + void *oldbuf = NULL; + + netif_carrier_off(dev->netdev); /* disable running netdev watchdog */ + netif_stop_queue(dev->netdev); /* stop tx data packets */ + + spin_lock_irqsave(&dev->mgmt_spinlock, flags); + + if ((urb_status=dev->write_urb->status) == -EINPROGRESS) { + oldbuf=dev->next_mgmt_bulk; /* to kfree below */ + dev->next_mgmt_bulk = txbuf; + txbuf = NULL; + } + spin_unlock_irqrestore(&dev->mgmt_spinlock, flags); + + if (oldbuf) { + /* a data/mgmt tx is already pending in the URB - + if this is no error in some situations we must + implement a queue or silently modify the old msg */ + err("%s: %s removed pending mgmt buffer %s", + dev->netdev->name, __FUNCTION__, + hex2str(dev->obuf, (u8 *)dev->next_mgmt_bulk, + min((int)(sizeof(dev->obuf))/3, 64),' ')); + kfree(dev->next_mgmt_bulk); + } + + if (txbuf) { + + txbuf->tx_rate = 0; +// txbuf->padding = 0; + txbuf->padding = calc_padding(le16_to_cpu(txbuf->wlength)); + + if (dev->next_mgmt_bulk) { + err("%s: %s URB status %d, but mgmt is pending", + dev->netdev->name, __FUNCTION__, urb_status); + } + + dbg(DBG_TX_MGMT, "%s: tx mgmt: wlen %d tx_rate %d pad %d %s", + dev->netdev->name, le16_to_cpu(txbuf->wlength), + txbuf->tx_rate, txbuf->padding, + hex2str(dev->obuf, txbuf->packet, + min((sizeof(dev->obuf)-1)/2, + (size_t)le16_to_cpu(txbuf->wlength)),'\0')); + + /* txbuf was not consumed above -> send mgmt msg immediately */ + memcpy(dev->bulk_out_buffer, txbuf, + le16_to_cpu(txbuf->wlength) + AT76C503_TX_HDRLEN); + FILL_BULK_URB(dev->write_urb, dev->udev, + usb_sndbulkpipe(dev->udev, + dev->bulk_out_endpointAddr), + dev->bulk_out_buffer, + le16_to_cpu(txbuf->wlength) + + txbuf->padding + + AT76C503_TX_HDRLEN, + (usb_complete_t)at76c503_write_bulk_callback, dev); + ret = usb_submit_urb(dev->write_urb, GFP_ATOMIC); + if (ret) { + err("%s: %s error in tx submit urb: %d", + dev->netdev->name, __FUNCTION__, ret); + } + kfree(txbuf); + } /* if (txbuf) */ + + return ret; + +} /* send_mgmt_bulk */ + +static int disassoc_req(struct at76c503 *dev, struct bss_info *bss) +{ + struct at76c503_tx_buffer *tx_buffer; + struct ieee80211_hdr_3addr *mgmt; + struct ieee802_11_disassoc_frame *req; + + assert(bss != NULL); + if (bss == NULL) + return -EFAULT; + + tx_buffer = kmalloc(DISASSOC_FRAME_SIZE + MAX_PADDING_SIZE, + GFP_ATOMIC); + if (!tx_buffer) + return -ENOMEM; + + mgmt = (struct ieee80211_hdr_3addr *)&(tx_buffer->packet); + req = (struct ieee802_11_disassoc_frame *)&(mgmt->payload); + + /* make wireless header */ + mgmt->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT|IEEE80211_STYPE_AUTH); + mgmt->duration_id = cpu_to_le16(0x8000); + memcpy(mgmt->addr1, bss->bssid, ETH_ALEN); + memcpy(mgmt->addr2, dev->netdev->dev_addr, ETH_ALEN); + memcpy(mgmt->addr3, bss->bssid, ETH_ALEN); + mgmt->seq_ctl = cpu_to_le16(0); + + req->reason = 0; + + /* init. at76c503 tx header */ + tx_buffer->wlength = cpu_to_le16(DISASSOC_FRAME_SIZE - + AT76C503_TX_HDRLEN); + + dbg(DBG_TX_MGMT, "%s: DisAssocReq bssid %s", + dev->netdev->name, mac2str(mgmt->addr3)); + + /* either send immediately (if no data tx is pending + or put it in pending list */ + return send_mgmt_bulk(dev, tx_buffer); + +} /* disassoc_req */ + +/* challenge is the challenge string (in TLV format) + we got with seq_nr 2 for shared secret authentication only and + send in seq_nr 3 WEP encrypted to prove we have the correct WEP key; + otherwise it is NULL */ +static int auth_req(struct at76c503 *dev, struct bss_info *bss, int seq_nr, u8 *challenge) +{ + struct at76c503_tx_buffer *tx_buffer; + struct ieee80211_hdr_3addr *mgmt; + struct ieee802_11_auth_frame *req; + + int buf_len = (seq_nr != 3 ? AUTH_FRAME_SIZE : + AUTH_FRAME_SIZE + 1 + 1 + challenge[1]); + + assert(bss != NULL); + assert(seq_nr != 3 || challenge != NULL); + + tx_buffer = kmalloc(buf_len + MAX_PADDING_SIZE, GFP_ATOMIC); + if (!tx_buffer) + return -ENOMEM; + + mgmt = (struct ieee80211_hdr_3addr *)&(tx_buffer->packet); + req = (struct ieee802_11_auth_frame *)&(mgmt->payload); + + /* make wireless header */ + /* first auth msg is not encrypted, only the second (seq_nr == 3) */ + mgmt->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH | + (seq_nr == 3 ? IEEE80211_FCTL_PROTECTED : 0)); + + mgmt->duration_id = cpu_to_le16(0x8000); + memcpy(mgmt->addr1, bss->bssid, ETH_ALEN); + memcpy(mgmt->addr2, dev->netdev->dev_addr, ETH_ALEN); + memcpy(mgmt->addr3, bss->bssid, ETH_ALEN); + mgmt->seq_ctl = cpu_to_le16(0); + + req->algorithm = cpu_to_le16(dev->auth_mode); + req->seq_nr = cpu_to_le16(seq_nr); + req->status = cpu_to_le16(0); + + if (seq_nr == 3) + memcpy(req->challenge, challenge, 1+1+challenge[1]); + + /* init. at76c503 tx header */ + tx_buffer->wlength = cpu_to_le16(buf_len - AT76C503_TX_HDRLEN); + + dbg(DBG_TX_MGMT, "%s: AuthReq bssid %s alg %d seq_nr %d", + dev->netdev->name, mac2str(mgmt->addr3), + le16_to_cpu(req->algorithm), le16_to_cpu(req->seq_nr)); + if (seq_nr == 3) { + dbg(DBG_TX_MGMT, "%s: AuthReq challenge: %s ...", + dev->netdev->name, + hex2str(dev->obuf, req->challenge, + min((int)sizeof(dev->obuf)/3, 18),' ')); + } + + /* either send immediately (if no data tx is pending + or put it in pending list */ + return send_mgmt_bulk(dev, tx_buffer); + +} /* auth_req */ + +static int assoc_req(struct at76c503 *dev, struct bss_info *bss) +{ + struct at76c503_tx_buffer *tx_buffer; + struct ieee80211_hdr_3addr *mgmt; + struct ieee802_11_assoc_req *req; + u8 *tlv; + + assert(bss != NULL); + + tx_buffer = kmalloc(ASSOCREQ_MAX_SIZE + MAX_PADDING_SIZE, + GFP_ATOMIC); + if (!tx_buffer) + return -ENOMEM; + + mgmt = (struct ieee80211_hdr_3addr *)&(tx_buffer->packet); + req = (struct ieee802_11_assoc_req *)&(mgmt->payload); + tlv = req->data; + + /* make wireless header */ + mgmt->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT|IEEE80211_STYPE_ASSOC_REQ); + + mgmt->duration_id = cpu_to_le16(0x8000); + memcpy(mgmt->addr1, bss->bssid, ETH_ALEN); + memcpy(mgmt->addr2, dev->netdev->dev_addr, ETH_ALEN); + memcpy(mgmt->addr3, bss->bssid, ETH_ALEN); + mgmt->seq_ctl = cpu_to_le16(0); + + /* we must set the Privacy bit in the capabilities to assure an + Agere-based AP with optional WEP transmits encrypted frames + to us. AP only set the Privacy bit in their capabilities + if WEP is mandatory in the BSS! */ + req->capability = cpu_to_le16(bss->capa | + (dev->wep_enabled ? WLAN_CAPABILITY_PRIVACY : 0) | + (dev->preamble_type == PREAMBLE_TYPE_SHORT ? + WLAN_CAPABILITY_SHORT_PREAMBLE : 0)); + + req->listen_interval = cpu_to_le16(2 * bss->beacon_interval); + + /* write TLV data elements */ + + *tlv++ = MFIE_TYPE_SSID; + *tlv++ = bss->ssid_len; + memcpy(tlv, bss->ssid, bss->ssid_len); + tlv += bss->ssid_len; + + *tlv++ = MFIE_TYPE_RATES; + *tlv++ = sizeof(hw_rates); + memcpy(tlv, hw_rates, sizeof(hw_rates)); + tlv += sizeof(hw_rates); /* tlv points behind the supp_rates field */ + + /* init. at76c503 tx header */ + tx_buffer->wlength = cpu_to_le16(tlv-(u8 *)mgmt); + + { + /* output buffer for ssid and rates */ + char orates[4*2+1]; + int len; + + tlv = req->data; + len = min(IW_ESSID_MAX_SIZE, (int)*(tlv+1)); + memcpy(dev->obuf, tlv+2, len); + dev->obuf[len] = '\0'; + tlv += (1 + 1 + *(tlv+1)); /* points to IE of rates now */ + dbg(DBG_TX_MGMT, "%s: AssocReq bssid %s capa x%04x ssid %s rates %s", + dev->netdev->name, mac2str(mgmt->addr3), + le16_to_cpu(req->capability), dev->obuf, + hex2str(orates,tlv+2,min((sizeof(orates)-1)/2,(size_t)*(tlv+1)), + '\0')); + } + + /* either send immediately (if no data tx is pending + or put it in pending list */ + return send_mgmt_bulk(dev, tx_buffer); + +} /* assoc_req */ + +/* we are currently associated to curr_bss and + want to reassoc to new_bss */ +static int reassoc_req(struct at76c503 *dev, struct bss_info *curr_bss, + struct bss_info *new_bss) +{ + struct at76c503_tx_buffer *tx_buffer; + struct ieee80211_hdr_3addr *mgmt; + struct ieee802_11_reassoc_req *req; + + u8 *tlv; + + assert(curr_bss != NULL); + assert(new_bss != NULL); + if (curr_bss == NULL || new_bss == NULL) + return -EFAULT; + + tx_buffer = kmalloc(REASSOCREQ_MAX_SIZE + MAX_PADDING_SIZE, + GFP_ATOMIC); + if (!tx_buffer) + return -ENOMEM; + + mgmt = (struct ieee80211_hdr_3addr *)&(tx_buffer->packet); + req = (struct ieee802_11_reassoc_req *)&(mgmt->payload); + tlv = req->data; + + /* make wireless header */ + /* jal: encrypt this packet if wep_enabled is TRUE ??? */ + mgmt->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT|IEEE80211_STYPE_REASSOC_REQ); + mgmt->duration_id = cpu_to_le16(0x8000); + memcpy(mgmt->addr1, new_bss->bssid, ETH_ALEN); + memcpy(mgmt->addr2, dev->netdev->dev_addr, ETH_ALEN); + memcpy(mgmt->addr3, new_bss->bssid, ETH_ALEN); + mgmt->seq_ctl = cpu_to_le16(0); + + /* we must set the Privacy bit in the capabilities to assure an + Agere-based AP with optional WEP transmits encrypted frames + to us. AP only set the Privacy bit in their capabilities + if WEP is mandatory in the BSS! */ + req->capability = cpu_to_le16(new_bss->capa | + (dev->wep_enabled ? WLAN_CAPABILITY_PRIVACY : 0) | + (dev->preamble_type == PREAMBLE_TYPE_SHORT ? + WLAN_CAPABILITY_SHORT_PREAMBLE : 0)); + + req->listen_interval = cpu_to_le16(2 * new_bss->beacon_interval); + + memcpy(req->curr_ap, curr_bss->bssid, ETH_ALEN); + + /* write TLV data elements */ + + *tlv++ = MFIE_TYPE_SSID; + *tlv++ = new_bss->ssid_len; + memcpy(tlv,new_bss->ssid, new_bss->ssid_len); + tlv += new_bss->ssid_len; + + *tlv++ = MFIE_TYPE_RATES; + *tlv++ = sizeof(hw_rates); + memcpy(tlv, hw_rates, sizeof(hw_rates)); + tlv += sizeof(hw_rates); /* tlv points behind the supp_rates field */ + + /* init. at76c503 tx header */ + tx_buffer->wlength = cpu_to_le16(tlv-(u8 *)mgmt); + + { + /* output buffer for rates and bssid */ + char orates[4*2+1]; + char ocurr[6*3+1]; + tlv = req->data; + memcpy(dev->obuf, tlv+2, min(sizeof(dev->obuf),(size_t)*(tlv+1))); + dev->obuf[IW_ESSID_MAX_SIZE] = '\0'; + tlv += (1 + 1 + *(tlv+1)); /* points to IE of rates now */ + dbg(DBG_TX_MGMT, "%s: ReAssocReq curr %s new %s capa x%04x ssid %s rates %s", + dev->netdev->name, + hex2str(ocurr, req->curr_ap, ETH_ALEN, ':'), + mac2str(mgmt->addr3), le16_to_cpu(req->capability), dev->obuf, + hex2str(orates,tlv+2,min((sizeof(orates)-1)/2,(size_t)*(tlv+1)), + '\0')); + } + + /* either send immediately (if no data tx is pending + or put it in pending list */ + return send_mgmt_bulk(dev, tx_buffer); + +} /* reassoc_req */ + + +/* shamelessly copied from usbnet.c (oku) */ +static void defer_kevent (struct at76c503 *dev, int flag) +{ + set_bit (flag, &dev->kevent_flags); + if (!schedule_work (&dev->kevent)) + dbg(DBG_KEVENT, "%s: kevent %d may have been dropped", + dev->netdev->name, flag); + else + dbg(DBG_KEVENT, "%s: kevent %d scheduled", + dev->netdev->name, flag); +} + +static void kevent(struct work_struct *ws) +{ + struct at76c503 *dev = container_of(ws, struct at76c503, kevent); + int ret; + unsigned long flags; + + /* on errors, bits aren't cleared, but no reschedule + is done. So work will be done next time something + else has to be done. This is ugly. TODO! (oku) */ + + dbg(DBG_KEVENT, "%s: kevent entry flags: 0x%lx", dev->netdev->name, + dev->kevent_flags); + + down(&dev->sem); + + if(test_bit(KEVENT_CTRL_HALT, &dev->kevent_flags)){ + /* this never worked... but it seems + that it's rarely necessary, if at all (oku) */ + ret = usb_clear_halt(dev->udev, + usb_sndctrlpipe (dev->udev, 0)); + if(ret < 0) + err("usb_clear_halt() failed: %d", ret); + else{ + clear_bit(KEVENT_CTRL_HALT, &dev->kevent_flags); + info("usb_clear_halt() successful"); + } + } + if(test_bit(KEVENT_NEW_BSS, &dev->kevent_flags)){ + struct net_device *netdev = dev->netdev; + struct mib_mac_mgmt *mac_mgmt = kmalloc(sizeof(struct mib_mac_mgmt), GFP_KERNEL); + + ret = get_mib(dev->udev, MIB_MAC_MGMT, (u8*)mac_mgmt, + sizeof(struct mib_mac_mgmt)); + if(ret < 0){ + err("%s: get_mib failed: %d", netdev->name, ret); + goto new_bss_clean; + } + + dbg(DBG_PROGRESS, "ibss_change = 0x%2x", mac_mgmt->ibss_change); + memcpy(dev->bssid, mac_mgmt->current_bssid, ETH_ALEN); + dbg(DBG_PROGRESS, "using BSSID %s", mac2str(dev->bssid)); + + iwevent_bss_connect(dev->netdev, dev->bssid); + + memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); + dev->mib_buf.type = MIB_MAC_MGMT; + dev->mib_buf.size = 1; + dev->mib_buf.index = IBSS_CHANGE_OK_OFFSET; + ret = set_mib(dev, &dev->mib_buf); + if(ret < 0){ + err("%s: set_mib (ibss change ok) failed: %d", netdev->name, ret); + goto new_bss_clean; + } + clear_bit(KEVENT_NEW_BSS, &dev->kevent_flags); + new_bss_clean: + kfree(mac_mgmt); + } + + if(test_bit(KEVENT_SET_PROMISC, &dev->kevent_flags)){ + info("%s: KEVENT_SET_PROMISC", dev->netdev->name); + + set_promisc(dev, dev->promisc); + clear_bit(KEVENT_SET_PROMISC, &dev->kevent_flags); + } + + /* check this _before_ KEVENT_JOIN, 'cause _JOIN sets _STARTIBSS bit */ + if (test_bit(KEVENT_STARTIBSS, &dev->kevent_flags)) { + clear_bit(KEVENT_STARTIBSS, &dev->kevent_flags); + LOCK_ISTATE() + assert(dev->istate == STARTIBSS); + UNLOCK_ISTATE() + ret = start_ibss(dev); + if(ret < 0){ + err("%s: start_ibss failed: %d", dev->netdev->name, ret); + goto end_startibss; + } + + ret = wait_completion(dev, CMD_START_IBSS); + if (ret != CMD_STATUS_COMPLETE) { + err("%s start_ibss failed to complete,%d", + dev->netdev->name, ret); + goto end_startibss; + } + + ret = get_current_bssid(dev); + if(ret < 0) goto end_startibss; + + ret = get_current_channel(dev); + if(ret < 0) goto end_startibss; + + /* not sure what this is good for ??? */ + memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); + dev->mib_buf.type = MIB_MAC_MGMT; + dev->mib_buf.size = 1; + dev->mib_buf.index = IBSS_CHANGE_OK_OFFSET; + ret = set_mib(dev, &dev->mib_buf); + if(ret < 0){ + err("%s: set_mib (ibss change ok) failed: %d", dev->netdev->name, ret); + goto end_startibss; + } + + netif_carrier_on(dev->netdev); + netif_start_queue(dev->netdev); + } +end_startibss: + + /* check this _before_ KEVENT_SCAN, 'cause _SCAN sets _JOIN bit */ + if (test_bit(KEVENT_JOIN, &dev->kevent_flags)) { + clear_bit(KEVENT_JOIN, &dev->kevent_flags); + LOCK_ISTATE() + if (dev->istate == INIT){ + UNLOCK_ISTATE() + goto end_join; + } + assert(dev->istate == JOINING); + UNLOCK_ISTATE() + /* dev->curr_bss == NULL signals a new round, + starting with list_entry(dev->bss_list.next, ...) */ + + /* secure the access to dev->curr_bss ! */ + spin_lock_irqsave(&dev->bss_list_spinlock, flags); + dev->curr_bss=find_matching_bss(dev, dev->curr_bss); + spin_unlock_irqrestore(&dev->bss_list_spinlock, flags); + + if (dev->curr_bss != NULL) { + if ((ret=join_bss(dev,dev->curr_bss)) < 0) { + err("%s: join_bss failed with %d", + dev->netdev->name, ret); + goto end_join; + } + + ret=wait_completion(dev,CMD_JOIN); + if (ret != CMD_STATUS_COMPLETE) { + if (ret != CMD_STATUS_TIME_OUT) + err("%s join_bss completed with %d", + dev->netdev->name, ret); + else + info("%s join_bss ssid %s timed out", + dev->netdev->name, + mac2str(dev->curr_bss->bssid)); + + /* retry next BSS immediately */ + defer_kevent(dev,KEVENT_JOIN); + goto end_join; + } + + /* here we have joined the (I)BSS */ + if (dev->iw_mode == IW_MODE_ADHOC) { + struct bss_info *bptr = dev->curr_bss; + NEW_STATE(dev,CONNECTED); + /* get ESSID, BSSID and channel for dev->curr_bss */ + dev->essid_size = bptr->ssid_len; + memcpy(dev->essid, bptr->ssid, bptr->ssid_len); + memcpy(dev->bssid, bptr->bssid, ETH_ALEN); + dev->channel = bptr->channel; + iwevent_bss_connect(dev->netdev,bptr->bssid); + netif_carrier_on(dev->netdev); + netif_start_queue(dev->netdev); + /* just to be sure */ + del_timer_sync(&dev->mgmt_timer); + } else { + /* send auth req */ + NEW_STATE(dev,AUTHENTICATING); + auth_req(dev, dev->curr_bss, 1, NULL); + dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ", + __FUNCTION__, __LINE__); + mod_timer(&dev->mgmt_timer, jiffies+HZ); + } + goto end_join; + } /* if (dev->curr_bss != NULL) */ + + /* here we haven't found a matching (i)bss ... */ + if (dev->iw_mode == IW_MODE_ADHOC) { + NEW_STATE(dev,STARTIBSS); + defer_kevent(dev,KEVENT_STARTIBSS); + goto end_join; + } + /* haven't found a matching BSS in infra mode - try again */ + NEW_STATE(dev,SCANNING); + defer_kevent(dev, KEVENT_SCAN); + } /* if (test_bit(KEVENT_JOIN, &dev->kevent_flags)) */ +end_join: + + if(test_bit(KEVENT_MGMT_TIMEOUT, &dev->kevent_flags)){ + clear_bit(KEVENT_MGMT_TIMEOUT, &dev->kevent_flags); + handle_mgmt_timeout(dev); + } + + if (test_bit(KEVENT_SCAN, &dev->kevent_flags)) { + clear_bit(KEVENT_SCAN, &dev->kevent_flags); + LOCK_ISTATE() + assert(dev->istate == SCANNING); + + /* only clear the bss list when a scan is actively initiated, + * otherwise simply rely on bss_list_timeout */ + if( dev->site_survey_state == SITE_SURVEY_IN_PROGRESS) + free_bss_list(dev); + UNLOCK_ISTATE() + + dev->scan_runs=3; + if ((ret=start_scan(dev, 0, 1)) < 0) { + err("%s: %s: start_scan failed with %d", + dev->netdev->name, __FUNCTION__, ret); + } else { + dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer for %d ticks", + __FUNCTION__, __LINE__, SCAN_POLL_INTERVAL); + mod_timer(&dev->mgmt_timer, jiffies + SCAN_POLL_INTERVAL); + } + + } /* if (test_bit(KEVENT_SCAN, &dev->kevent_flags)) */ + + + if (test_bit(KEVENT_SUBMIT_RX, &dev->kevent_flags)) { + clear_bit(KEVENT_SUBMIT_RX, &dev->kevent_flags); + submit_rx_urb(dev); + } + + + if (test_bit(KEVENT_RESTART, &dev->kevent_flags)) { + clear_bit(KEVENT_RESTART, &dev->kevent_flags); + LOCK_ISTATE() + assert(dev->istate == INIT); + UNLOCK_ISTATE() + startup_device(dev); + + /* call it here for default_iw_mode == IW_MODE_MONITOR and + no subsequent "iwconfig wlanX mode monitor" or + "iwpriv wlanX monitor 1|2 C" to set dev->netdev->type + correctly */ + set_monitor_mode(dev, dev->monitor_prism_header); + + + netif_carrier_off(dev->netdev); /* disable running netdev watchdog */ + netif_stop_queue(dev->netdev); /* stop tx data packets */ + if (dev->iw_mode != IW_MODE_MONITOR) { + NEW_STATE(dev,SCANNING); + defer_kevent(dev,KEVENT_SCAN); + } else { + NEW_STATE(dev,MONITORING); + start_scan(dev,0,0); + dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer for %d ticks", + __FUNCTION__, __LINE__, SCAN_POLL_INTERVAL); + mod_timer(&dev->mgmt_timer, jiffies + SCAN_POLL_INTERVAL); + } + } + + if (test_bit(KEVENT_ASSOC_DONE, &dev->kevent_flags)) { + clear_bit(KEVENT_ASSOC_DONE, &dev->kevent_flags); + LOCK_ISTATE() + assert(dev->istate == ASSOCIATING || + dev->istate == REASSOCIATING); + UNLOCK_ISTATE() + if (dev->iw_mode == IW_MODE_INFRA) { + assert(dev->curr_bss != NULL); + if (dev->curr_bss != NULL && + dev->pm_mode != PM_ACTIVE) { + /* calc the listen interval in units of + beacon intervals of the curr_bss */ + dev->pm_period_beacon = (dev->pm_period_us >> 10) / + dev->curr_bss->beacon_interval; + +#ifdef DEBUG /* only to check if we need to set the listen interval here + or could do it in the (re)assoc_req parameter */ + dump_mib_mac(dev); +#endif + + if (dev->pm_period_beacon < 2) + dev->pm_period_beacon = 2; + else + if ( dev->pm_period_beacon > 0xffff) + dev->pm_period_beacon = 0xffff; + + dbg(DBG_PM, "%s: pm_mode %d assoc id x%x listen int %d", + dev->netdev->name, dev->pm_mode, + dev->curr_bss->assoc_id, dev->pm_period_beacon); + + set_associd(dev, dev->curr_bss->assoc_id); + set_listen_interval(dev, (u16)dev->pm_period_beacon); + set_pm_mode(dev, dev->pm_mode); +#ifdef DEBUG + dump_mib_mac(dev); + dump_mib_mac_mgmt(dev); +#endif + } + } + + netif_carrier_on(dev->netdev); + netif_wake_queue(dev->netdev); /* _start_queue ??? */ + NEW_STATE(dev,CONNECTED); + iwevent_bss_connect(dev->netdev,dev->curr_bss->bssid); + dbg(DBG_PROGRESS, "%s: connected to BSSID %s", + dev->netdev->name, mac2str(dev->curr_bss->bssid)); + } + + + if (test_bit(KEVENT_RESET_DEVICE, &dev->kevent_flags)) { + + clear_bit(KEVENT_RESET_DEVICE, &dev->kevent_flags); + + dbg(DBG_DEVSTART, "resetting the device"); + + usb_reset_device(dev->udev); + +/* with 2.6.8 the reset above will cause a disconnect as the USB subsys + recognizes the change in the config descriptors. Subsequently the device + will be registered again. */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) + + //jal: patch the state (patch by Dmitri) + dev->udev->state = USB_STATE_CONFIGURED; + + /* jal: currently (2.6.0-test2 and 2.4.23) + usb_reset_device() does not recognize that + the interface descr. are changed. + This procedure reads the configuration and does a limited parsing of + the interface and endpoint descriptors */ + update_usb_intf_descr(dev); + + /* continue immediately with external fw download */ + set_bit (KEVENT_EXTERNAL_FW, &dev->kevent_flags); +#else + /* kernel >= 2.6.8 */ + NEW_STATE(dev, WAIT_FOR_DISCONNECT); +#endif + } + + if (test_bit(KEVENT_EXTERNAL_FW, &dev->kevent_flags)) { + u8 op_mode; + + clear_bit(KEVENT_EXTERNAL_FW, &dev->kevent_flags); + + op_mode = get_op_mode(dev->udev); + dbg(DBG_DEVSTART, "opmode %d", op_mode); + + if (op_mode != OPMODE_NORMAL_NIC_WITHOUT_FLASH) { + err("unexpected opmode %d", op_mode); + goto end_external_fw; + } + + if (dev->extfw && dev->extfw_size) { + ret = download_external_fw(dev->udev, dev->extfw, + dev->extfw_size); + if (ret < 0) { + err("Downloading external firmware failed: %d", ret); + goto end_external_fw; + } + if (dev->board_type == BOARDTYPE_505A_RFMD_2958) { + info("200 ms delay for board type 7"); + /* jal: can I do this in kevent ??? */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/5+1); + } + } + NEW_STATE(dev,INIT); + init_new_device(dev); + } +end_external_fw: + + if (test_bit(KEVENT_INTERNAL_FW, &dev->kevent_flags)) { + clear_bit(KEVENT_INTERNAL_FW, &dev->kevent_flags); + + dbg(DBG_DEVSTART, "downloading internal firmware"); + + ret=usbdfu_download(dev->udev, dev->intfw, + dev->intfw_size, + dev->board_type == BOARDTYPE_505A_RFMD_2958 ? 2000: 0); + + if (ret < 0) { + err("downloading internal fw failed with %d",ret); + goto end_internal_fw; + } + + dbg(DBG_DEVSTART, "sending REMAP"); + + /* no REMAP for 505A (see SF driver) */ + if (dev->board_type != BOARDTYPE_505A_RFMD_2958) + if ((ret=at76c503_remap(dev->udev)) < 0) { + err("sending REMAP failed with %d",ret); + goto end_internal_fw; + } + + dbg(DBG_DEVSTART, "sleeping for 2 seconds"); + NEW_STATE(dev,EXTFW_DOWNLOAD); + mod_timer(&dev->fw_dl_timer, jiffies+2*HZ+1); + } +end_internal_fw: + + up(&dev->sem); + + dbg(DBG_KEVENT, "%s: kevent exit flags: 0x%lx", dev->netdev->name, + dev->kevent_flags); + + return; +} + +static int essid_matched(struct at76c503 *dev, struct bss_info *ptr) +{ + /* common criteria for both modi */ + + int retval = (dev->essid_size == 0 /* ANY ssid */ || + (dev->essid_size == ptr->ssid_len && + !memcmp(dev->essid, ptr->ssid, ptr->ssid_len))); + if (!retval) + dbg(DBG_BSS_MATCH, "%s bss table entry %p: essid didn't match", + dev->netdev->name, ptr); + return retval; +} + +static inline int mode_matched(struct at76c503 *dev, struct bss_info *ptr) +{ + int retval; + + if (dev->iw_mode == IW_MODE_ADHOC) + retval = ptr->capa & WLAN_CAPABILITY_IBSS; + else + retval = ptr->capa & WLAN_CAPABILITY_ESS; + if (!retval) + dbg(DBG_BSS_MATCH, "%s bss table entry %p: mode didn't match", + dev->netdev->name, ptr); + return retval; +} + +static int rates_matched(struct at76c503 *dev, struct bss_info *ptr) +{ + int i; + u8 *rate; + + for(i=0,rate=ptr->rates; i < ptr->rates_len; i++,rate++) + if (*rate & 0x80) { + /* this is a basic rate we have to support + (see IEEE802.11, ch. 7.3.2.2) */ + if (*rate != (0x80|hw_rates[0]) && *rate != (0x80|hw_rates[1]) && + *rate != (0x80|hw_rates[2]) && *rate != (0x80|hw_rates[3])) { + dbg(DBG_BSS_MATCH, + "%s: bss table entry %p: basic rate %02x not supported", + dev->netdev->name, ptr, *rate); + return 0; + } + } + /* if we use short preamble, the bss must support it */ + if (dev->preamble_type == PREAMBLE_TYPE_SHORT && + !(ptr->capa & WLAN_CAPABILITY_SHORT_PREAMBLE)) { + dbg(DBG_BSS_MATCH, "%s: %p does not support short preamble", + dev->netdev->name, ptr); + return 0; + } else + return 1; +} + +static inline int wep_matched(struct at76c503 *dev, struct bss_info *ptr) +{ + if (!dev->wep_enabled && + ptr->capa & WLAN_CAPABILITY_PRIVACY) { + /* we have disabled WEP, but the BSS signals privacy */ + dbg(DBG_BSS_MATCH, "%s: bss table entry %p: requires encryption", + dev->netdev->name, ptr); + return 0; + } + /* otherwise if the BSS does not signal privacy it may well + accept encrypted packets from us ... */ + return 1; +} + +static inline int bssid_matched(struct at76c503 *dev, struct bss_info *ptr) +{ + if (!dev->wanted_bssid_valid || + !memcmp(ptr->bssid, dev->wanted_bssid, ETH_ALEN)) { + return 1; + } else { + if (at76_debug & DBG_BSS_MATCH) { + dbg_uc("%s: requested bssid - %s does not match", + dev->netdev->name, mac2str(dev->wanted_bssid)); + dbg_uc(" AP bssid - %s of bss table entry %p", + mac2str(ptr->bssid), ptr); + } + return 0; + } +} + +static void dump_bss_table(struct at76c503 *dev, int force_output) +{ + struct bss_info *ptr; + /* hex dump output buffer for debug */ + unsigned long flags; + struct list_head *lptr; + + if ((at76_debug & DBG_BSS_TABLE) || (force_output)) { + spin_lock_irqsave(&dev->bss_list_spinlock, flags); + + dbg_uc("%s BSS table (curr=%p, new=%p):", dev->netdev->name, + dev->curr_bss, dev->new_bss); + + list_for_each(lptr, &dev->bss_list) { + ptr = list_entry(lptr, struct bss_info, list); + dbg_uc("0x%p: bssid %s channel %d ssid %s (%s)" + " capa x%04x rates %s rssi %d link %d noise %d", + ptr, mac2str(ptr->bssid), + ptr->channel, + ptr->ssid, + hex2str(dev->obuf, ptr->ssid, + min((sizeof(dev->obuf)-1)/2, + (size_t)ptr->ssid_len),'\0'), + ptr->capa, + hex2str(dev->obuf_s, ptr->rates, + min(sizeof(dev->obuf_s)/3, + (size_t)ptr->rates_len), ' '), + ptr->rssi, ptr->link_qual, ptr->noise_level); + } + + spin_unlock_irqrestore(&dev->bss_list_spinlock, flags); + } +} + +/* try to find a matching bss in dev->bss, starting at position start. + returns the ptr to a matching bss in the list or + NULL if none found */ +/* last is the last bss tried, last == NULL signals a new round, + starting with list_entry(dev->bss_list.next, ...) */ +/* this proc must be called inside an acquired dev->bss_list_spinlock + otherwise the timeout on bss may remove the newly chosen entry ! */ +static struct bss_info *find_matching_bss(struct at76c503 *dev, + struct bss_info *last) +{ + struct bss_info *ptr = NULL; + struct list_head *curr; + + curr = last != NULL ? last->list.next : dev->bss_list.next; + while (curr != &dev->bss_list) { + ptr = list_entry(curr, struct bss_info, list); + if (essid_matched(dev,ptr) && + mode_matched(dev,ptr) && + wep_matched(dev,ptr) && + rates_matched(dev,ptr) && + bssid_matched(dev,ptr)) + break; + curr = curr->next; + } + + if (curr == &dev->bss_list) + ptr = NULL; + /* otherwise ptr points to the struct bss_info we have chosen */ + + dbg(DBG_BSS_TABLE, "%s %s: returned %p", dev->netdev->name, + __FUNCTION__, ptr); + return ptr; +} /* find_matching_bss */ + + +/* we got an association response */ +static void rx_mgmt_assoc(struct at76c503 *dev, + struct at76c503_rx_buffer *buf) +{ + struct ieee80211_hdr_3addr *mgmt = + (struct ieee80211_hdr_3addr *)buf->packet; + struct ieee802_11_assoc_resp *resp = + (struct ieee802_11_assoc_resp *)mgmt->payload; + u16 assoc_id = le16_to_cpu(resp->assoc_id); + u16 status = le16_to_cpu(resp->status); + u16 capa = le16_to_cpu(resp->capability); + dbg(DBG_RX_MGMT, "%s: rx AssocResp bssid %s capa x%04x status x%04x " + "assoc_id x%04x rates %s", + dev->netdev->name, mac2str(mgmt->addr3), capa, status, assoc_id, + hex2str(dev->obuf, resp->data+2, + min((size_t)*(resp->data+1),(sizeof(dev->obuf)-1)/2), '\0')); + LOCK_ISTATE() + if (dev->istate == ASSOCIATING) { + UNLOCK_ISTATE() + assert(dev->curr_bss != NULL); + if (dev->curr_bss == NULL) + return; + + if (status == WLAN_STATUS_SUCCESS) { + struct bss_info *ptr = dev->curr_bss; + ptr->assoc_id = assoc_id & 0x3fff; + /* update iwconfig params */ + memcpy(dev->bssid, ptr->bssid, ETH_ALEN); + memcpy(dev->essid, ptr->ssid, ptr->ssid_len); + dev->essid_size = ptr->ssid_len; + dev->channel = ptr->channel; + defer_kevent(dev,KEVENT_ASSOC_DONE); + } else { + NEW_STATE(dev,JOINING); + defer_kevent(dev,KEVENT_JOIN); + } + del_timer_sync(&dev->mgmt_timer); + } else { + UNLOCK_ISTATE() + info("%s: AssocResp in state %d ignored", + dev->netdev->name, dev->istate); + } +} /* rx_mgmt_assoc */ + +static void rx_mgmt_reassoc(struct at76c503 *dev, + struct at76c503_rx_buffer *buf) +{ + struct ieee80211_hdr_3addr *mgmt = + (struct ieee80211_hdr_3addr *)buf->packet; + struct ieee802_11_assoc_resp *resp = + (struct ieee802_11_assoc_resp *)mgmt->payload; + unsigned long flags; + u16 capa = le16_to_cpu(resp->capability); + u16 status = le16_to_cpu(resp->status); + u16 assoc_id = le16_to_cpu(resp->assoc_id); + + dbg(DBG_RX_MGMT, "%s: rx ReAssocResp bssid %s capa x%04x status x%04x " + "assoc_id x%04x rates %s", + dev->netdev->name, mac2str(mgmt->addr3), capa, status, assoc_id, + hex2str(dev->obuf, resp->data+2, + min((size_t)*(resp->data+1),(sizeof(dev->obuf)-1)/2), '\0')); + LOCK_ISTATE() + if (dev->istate == REASSOCIATING) { + UNLOCK_ISTATE() + assert(dev->new_bss != NULL); + if (dev->new_bss == NULL) + return; + + if (status == WLAN_STATUS_SUCCESS) { + struct bss_info *bptr = dev->new_bss; + bptr->assoc_id = assoc_id; + NEW_STATE(dev,CONNECTED); + + iwevent_bss_connect(dev->netdev,bptr->bssid); + + spin_lock_irqsave(&dev->bss_list_spinlock, flags); + dev->curr_bss = dev->new_bss; + dev->new_bss = NULL; + spin_unlock_irqrestore(&dev->bss_list_spinlock, flags); + + /* get ESSID, BSSID and channel for dev->curr_bss */ + dev->essid_size = bptr->ssid_len; + memcpy(dev->essid, bptr->ssid, bptr->ssid_len); + memcpy(dev->bssid, bptr->bssid, ETH_ALEN); + dev->channel = bptr->channel; + dbg(DBG_PROGRESS, "%s: reassociated to BSSID %s", + dev->netdev->name, mac2str(dev->bssid)); + defer_kevent(dev, KEVENT_ASSOC_DONE); + } else { + del_timer_sync(&dev->mgmt_timer); + NEW_STATE(dev,JOINING); + defer_kevent(dev,KEVENT_JOIN); + } + } else { + info("%s: ReAssocResp in state %d ignored", + dev->netdev->name, dev->istate); + UNLOCK_ISTATE() + } +} /* rx_mgmt_reassoc */ + +static void rx_mgmt_disassoc(struct at76c503 *dev, + struct at76c503_rx_buffer *buf) +{ + struct ieee80211_hdr_3addr *mgmt = + (struct ieee80211_hdr_3addr *)buf->packet; + struct ieee802_11_disassoc_frame *resp = + (struct ieee802_11_disassoc_frame *)mgmt->payload; + + dbg(DBG_RX_MGMT, "%s: rx DisAssoc bssid %s reason x%04x destination %s", + dev->netdev->name, mac2str(mgmt->addr3), + le16_to_cpu(resp->reason), + hex2str(dev->obuf, mgmt->addr1, + min((int)sizeof(dev->obuf)/3, ETH_ALEN), ':')); + LOCK_ISTATE() + if (dev->istate == SCANNING || dev->istate == INIT) { + UNLOCK_ISTATE() + return; + } + UNLOCK_ISTATE() + + assert(dev->curr_bss != NULL); + if (dev->curr_bss == NULL) + return; + LOCK_ISTATE() + if (dev->istate == REASSOCIATING) { + UNLOCK_ISTATE() + assert(dev->new_bss != NULL); + if (dev->new_bss == NULL) + return; + } else + UNLOCK_ISTATE() + if (!memcmp(mgmt->addr3, dev->curr_bss->bssid, ETH_ALEN) && + (!memcmp(dev->netdev->dev_addr, mgmt->addr1, ETH_ALEN) || + !memcmp(bc_addr, mgmt->addr1, ETH_ALEN))) { + /* this is a DisAssoc from the BSS we are connected or + trying to connect to, directed to us or broadcasted */ + /* jal: TODO: can the DisAssoc also come from the BSS + we've sent a ReAssocReq to (i.e. from dev->new_bss) ? */ + LOCK_ISTATE() + if (dev->istate == DISASSOCIATING || + dev->istate == ASSOCIATING || + dev->istate == REASSOCIATING || + dev->istate == CONNECTED || + dev->istate == JOINING) + { + if (dev->istate == CONNECTED) { + UNLOCK_ISTATE() + netif_carrier_off(dev->netdev); + netif_stop_queue(dev->netdev); + iwevent_bss_disconnect(dev->netdev); + } else UNLOCK_ISTATE() + del_timer_sync(&dev->mgmt_timer); + NEW_STATE(dev,JOINING); + defer_kevent(dev,KEVENT_JOIN); + } else { + + /* ignore DisAssoc in states AUTH, ASSOC */ + info("%s: DisAssoc in state %d ignored", + dev->netdev->name, dev->istate); + UNLOCK_ISTATE() + } + } + /* ignore DisAssoc to other STA or from other BSSID */ +} /* rx_mgmt_disassoc */ + +static void rx_mgmt_auth(struct at76c503 *dev, + struct at76c503_rx_buffer *buf) +{ + struct ieee80211_hdr_3addr *mgmt = + (struct ieee80211_hdr_3addr *)buf->packet; + struct ieee802_11_auth_frame *resp = + (struct ieee802_11_auth_frame *)mgmt->payload; + int seq_nr = le16_to_cpu(resp->seq_nr); + int alg = le16_to_cpu(resp->algorithm); + int status = le16_to_cpu(resp->status); + + dbg(DBG_RX_MGMT, "%s: rx AuthFrame bssid %s alg %d seq_nr %d status %d " + "destination %s", + dev->netdev->name, mac2str(mgmt->addr3), + alg, seq_nr, status, + hex2str(dev->obuf, mgmt->addr1, + min((int)sizeof(dev->obuf)/3, ETH_ALEN), ':')); + + if (alg == WLAN_AUTH_SHARED_KEY && + seq_nr == 2) { + dbg(DBG_RX_MGMT, "%s: AuthFrame challenge %s ...", + dev->netdev->name, + hex2str(dev->obuf, resp->challenge, + min((int)sizeof(dev->obuf)/3,18), ' ')); + } + LOCK_ISTATE() + if (dev->istate != AUTHENTICATING) { + info("%s: ignored AuthFrame in state %d", + dev->netdev->name, dev->istate); + UNLOCK_ISTATE() + return; + } + UNLOCK_ISTATE() + if (dev->auth_mode != alg) { + info("%s: ignored AuthFrame for alg %d", + dev->netdev->name, alg); + return; + } + + assert(dev->curr_bss != NULL); + if (dev->curr_bss == NULL) + return; + + if (!memcmp(mgmt->addr3, dev->curr_bss->bssid, ETH_ALEN) && + !memcmp(dev->netdev->dev_addr, mgmt->addr1, ETH_ALEN)) { + /* this is a AuthFrame from the BSS we are connected or + trying to connect to, directed to us */ + if (status != WLAN_STATUS_SUCCESS) { + del_timer_sync(&dev->mgmt_timer); + /* try to join next bss */ + NEW_STATE(dev,JOINING); + defer_kevent(dev,KEVENT_JOIN); + return; + } + + if (dev->auth_mode == WLAN_AUTH_OPEN || + seq_nr == 4) { + dev->retries = ASSOC_RETRIES; + NEW_STATE(dev,ASSOCIATING); + assoc_req(dev, dev->curr_bss); + dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ", + __FUNCTION__, __LINE__); + mod_timer(&dev->mgmt_timer,jiffies+HZ); + return; + } + + assert(seq_nr == 2); + auth_req(dev, dev->curr_bss, seq_nr+1, resp->challenge); + dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ", + __FUNCTION__, __LINE__); + mod_timer(&dev->mgmt_timer,jiffies+HZ); + } + /* else: ignore AuthFrames to other recipients */ +} /* rx_mgmt_auth */ + +static void rx_mgmt_deauth(struct at76c503 *dev, + struct at76c503_rx_buffer *buf) +{ + struct ieee80211_hdr_3addr *mgmt = + (struct ieee80211_hdr_3addr *)buf->packet; + struct ieee802_11_deauth_frame *resp = + (struct ieee802_11_deauth_frame *)mgmt->payload; + + dbg(DBG_RX_MGMT|DBG_PROGRESS, + "%s: rx DeAuth bssid %s reason x%04x destination %s", + dev->netdev->name, mac2str(mgmt->addr3), + le16_to_cpu(resp->reason), + hex2str(dev->obuf, mgmt->addr1, + min((int)sizeof(dev->obuf)/3,ETH_ALEN), ':')); + LOCK_ISTATE() + if (dev->istate == DISASSOCIATING || + dev->istate == AUTHENTICATING || + dev->istate == ASSOCIATING || + dev->istate == REASSOCIATING || + dev->istate == CONNECTED) { + UNLOCK_ISTATE() + assert(dev->curr_bss != NULL); + if (dev->curr_bss == NULL) + return; + + if (!memcmp(mgmt->addr3, dev->curr_bss->bssid, ETH_ALEN) && + (!memcmp(dev->netdev->dev_addr, mgmt->addr1, ETH_ALEN) || + !memcmp(bc_addr, mgmt->addr1, ETH_ALEN))) { + /* this is a DeAuth from the BSS we are connected or + trying to connect to, directed to us or broadcasted */ + LOCK_ISTATE() + if (dev->istate == CONNECTED) { + UNLOCK_ISTATE() + iwevent_bss_disconnect(dev->netdev); + } else UNLOCK_ISTATE() + NEW_STATE(dev,JOINING); + defer_kevent(dev,KEVENT_JOIN); + del_timer_sync(&dev->mgmt_timer); + } + /* ignore DeAuth to other STA or from other BSSID */ + } else { + /* ignore DeAuth in states SCANNING */ + info("%s: DeAuth in state %d ignored", + dev->netdev->name, dev->istate); + UNLOCK_ISTATE() + } +} /* rx_mgmt_deauth */ + +static void rx_mgmt_beacon(struct at76c503 *dev, + struct at76c503_rx_buffer *buf) +{ + struct ieee80211_hdr_3addr *mgmt = + (struct ieee80211_hdr_3addr *)buf->packet; + + /* beacon content */ + struct ieee802_11_beacon_data *bdata = + (struct ieee802_11_beacon_data *)mgmt->payload; + + /* length of var length beacon parameters */ + int varpar_len = min(le16_to_cpu(buf->wlength) - + (int)(IEEE802_11_MGMT_HEADER_SIZE + + offsetof(struct ieee802_11_beacon_data, data)), + BEACON_MAX_DATA_LENGTH); + + struct list_head *lptr; + struct bss_info *match; /* entry matching addr3 with its bssid */ + int new_entry = 0; + int len; + struct data_element { + u8 type; + u8 length; + u8 data_head; + } *element; + int have_ssid = 0; + int have_rates = 0; + int have_channel = 0; + int keep_going = 1; + unsigned long flags; + + spin_lock_irqsave(&dev->bss_list_spinlock, flags); + LOCK_ISTATE() + if (dev->istate == CONNECTED) { + UNLOCK_ISTATE() + /* in state CONNECTED we use the mgmt_timer to control + the beacon of the BSS */ + assert(dev->curr_bss != NULL); + if (dev->curr_bss == NULL) + goto rx_mgmt_beacon_end; + if (!memcmp(dev->curr_bss->bssid, mgmt->addr3, ETH_ALEN)) { + //dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer " + // "+BEACON_TIMEOUT*HZ", __FUNCTION__, __LINE__); + mod_timer(&dev->mgmt_timer, jiffies+BEACON_TIMEOUT*HZ); + dev->curr_bss->rssi = buf->rssi; + dev->beacons_received++; + goto rx_mgmt_beacon_end; + } + } else + UNLOCK_ISTATE() + + /* look if we have this BSS already in the list */ + match = NULL; + + if (!list_empty(&dev->bss_list)) { + list_for_each(lptr, &dev->bss_list) { + struct bss_info *bss_ptr = + list_entry(lptr, struct bss_info, list); + if (!memcmp(bss_ptr->bssid, mgmt->addr3, ETH_ALEN)) { + match = bss_ptr; + break; + } + } + } + + if (match == NULL) { + /* haven't found the bss in the list */ + if ((match=kmalloc(sizeof(struct bss_info), GFP_ATOMIC)) == NULL) { + dbg(DBG_BSS_TABLE, "%s: cannot kmalloc new bss info (%zd byte)", + dev->netdev->name, sizeof(struct bss_info)); + goto rx_mgmt_beacon_end; + } + memset(match,0,sizeof(*match)); + new_entry = 1; + /* append new struct into list */ + list_add_tail(&match->list, &dev->bss_list); + } + + /* we either overwrite an existing entry or append a new one + match points to the entry in both cases */ + + match->capa = le16_to_cpu(bdata->capability_information); + + /* while beacon_interval is not (!) */ + match->beacon_interval = le16_to_cpu(bdata->beacon_interval); + + match->rssi = buf->rssi; + match->link_qual = buf->link_quality; + match->noise_level = buf->noise_level; + + memcpy(match->mac,mgmt->addr2,ETH_ALEN); //just for info + memcpy(match->bssid,mgmt->addr3,ETH_ALEN); + dbg(DBG_RX_BEACON, "%s: bssid %s", dev->netdev->name, + mac2str(match->bssid)); + + element = (struct data_element*)bdata->data; + +#define data_end(element) (&(element->data_head) + element->length) + + // This routine steps through the bdata->data array to try and get + // some useful information about the access point. + // Currently, this implementation supports receipt of: SSID, + // supported transfer rates and channel, in any order, with some + // tolerance for intermittent unknown codes (although this + // functionality may not be necessary as the useful information will + // usually arrive in consecutively, but there have been some + // reports of some of the useful information fields arriving in a + // different order). + // It does not support any more IE types although MFIE_TYPE_TIM may + // be supported (on my AP at least). + // The bdata->data array is about 1500 bytes long but only ~36 of those + // bytes are useful, hence the have_ssid etc optimizations. + + while (keep_going && + ((int)(data_end(element) - bdata->data) <= varpar_len)) { + + switch (element->type) { + + case MFIE_TYPE_SSID: + len = min(IW_ESSID_MAX_SIZE, (int)element->length); + if (!have_ssid && ((new_entry) || + !is_cloaked_ssid(&(element->data_head), len))) { + /* we copy only if this is a new entry, + or the incoming SSID is not a cloaked SSID. This + will protect us from overwriting a real SSID read + in a ProbeResponse with a cloaked one from a + following beacon. */ + + match->ssid_len = len; + memcpy(match->ssid, &(element->data_head), len); + match->ssid[len] = '\0'; /* terminate the + string for + printing */ + dbg(DBG_RX_BEACON, "%s: SSID - %s", + dev->netdev->name, match->ssid); + } + have_ssid = 1; + break; + + case MFIE_TYPE_RATES: + if (!have_rates) { + match->rates_len = + min((int)sizeof(match->rates), + (int)element->length); + memcpy(match->rates, &(element->data_head), + match->rates_len); + have_rates = 1; + dbg(DBG_RX_BEACON, + "%s: SUPPORTED RATES %s", + dev->netdev->name, + hex2str(dev->obuf, &(element->data_head), + min((sizeof(dev->obuf)-1)/2, + (size_t)element->length), '\0')); + } + break; + + case MFIE_TYPE_DS_SET: + if (!have_channel) { + match->channel = element->data_head; + have_channel = 1; + dbg(DBG_RX_BEACON, "%s: CHANNEL - %d", + dev->netdev->name, match->channel); + } + break; + + case MFIE_TYPE_CF_SET: + case MFIE_TYPE_TIM: + case MFIE_TYPE_IBSS_SET: + default: + { + dbg(DBG_RX_BEACON, "%s: beacon IE id %d len %d %s", + dev->netdev->name, element->type, element->length, + hex2str(dev->obuf,&(element->data_head), + min((sizeof(dev->obuf)-1)/2, + (size_t)element->length),'\0')); + break; + } + + } // switch (element->type) + + // advance to the next 'element' of data + element = (struct data_element*)data_end(element); + + // Optimization: after all, the bdata->data array is + // varpar_len bytes long, whereas we get all of the useful + // information after only ~36 bytes, this saves us a lot of + // time (and trouble as the remaining portion of the array + // could be full of junk) + // Comment this out if you want to see what other information + // comes from the AP - although little of it may be useful + + //if (have_ssid && have_rates && have_channel) + // keep_going = 0; + } + + dbg(DBG_RX_BEACON, "%s: Finished processing beacon data", + dev->netdev->name); + + match->last_rx = jiffies; /* record last rx of beacon */ + +rx_mgmt_beacon_end: + spin_unlock_irqrestore(&dev->bss_list_spinlock, flags); +} /* rx_mgmt_beacon */ + + +/* calc the link level from a given rx_buffer */ +static void calc_level(struct at76c503 *dev, struct at76c503_rx_buffer *buf, struct iw_quality* qual) +{ int max_rssi = 42; /* just a gues for now, might be different for other chips */ + + qual->level = (buf->rssi * 100 / max_rssi); + if (qual->level > 100) + qual->level = 100; + qual->updated |= IW_QUAL_LEVEL_UPDATED; +} + + +/* calc the link quality from a given rx_buffer */ +static void calc_qual(struct at76c503 *dev, struct at76c503_rx_buffer *buf, struct iw_quality* qual) +{ + if((dev->board_type == BOARDTYPE_503_INTERSIL_3861) || + (dev->board_type == BOARDTYPE_503_INTERSIL_3863)) { + qual->qual=buf->link_quality; + } else { + qual->qual = qual->level * dev->beacons_received * + dev->beacon_period / + (jiffies_to_msecs(jiffies) - dev->beacons_last_qual); + + dev->beacons_last_qual = jiffies_to_msecs(jiffies); + dev->beacons_received = 0; + } + qual->qual = (qual->qual > 100) ? 100 : qual->qual; + qual->updated |= IW_QUAL_QUAL_UPDATED; +} + + +/* calc the noise quality from a given rx_buffer */ +static void calc_noise(struct at76c503 *dev, struct at76c503_rx_buffer *buf, struct iw_quality* qual) +{ + qual->noise = 0; + qual->updated |= IW_QUAL_NOISE_INVALID; +} + + +static void update_wstats(struct at76c503 *dev, struct at76c503_rx_buffer *buf) +{ + struct iw_quality *qual = &dev->wstats.qual; + + if (buf->rssi && dev->istate == CONNECTED) { + qual->updated = 0; + calc_level(dev, buf, qual); + calc_qual(dev, buf, qual); + calc_noise(dev, buf, qual); + } else { + qual->qual = 0; + qual->level = 0; + qual->noise = 0; + qual->updated = IW_QUAL_ALL_INVALID; + } +} + +static void rx_mgmt(struct at76c503 *dev, struct at76c503_rx_buffer *buf) +{ + struct ieee80211_hdr_3addr *mgmt = + (struct ieee80211_hdr_3addr *)buf->packet; + u16 subtype = le16_to_cpu(mgmt->frame_ctl) & IEEE80211_FCTL_STYPE; + + /* update wstats */ + LOCK_ISTATE() + if (dev->istate != INIT && dev->istate != SCANNING) { + UNLOCK_ISTATE() + /* jal: this is a dirty hack needed by Tim in ad-hoc mode */ + if (dev->iw_mode == IW_MODE_ADHOC || + (dev->curr_bss != NULL && + !memcmp(mgmt->addr3, dev->curr_bss->bssid, ETH_ALEN))) { + /* Data packets always seem to have a 0 link level, so we + only read link quality info from management packets. + Atmel driver actually averages the present, and previous + values, we just present the raw value at the moment - TJS */ + + update_wstats(dev, buf); + } + } else UNLOCK_ISTATE() + + if (at76_debug & DBG_RX_MGMT_CONTENT) { + dbg_uc("%s rx mgmt subtype x%x %s", + dev->netdev->name, subtype, + hex2str(dev->obuf, (u8 *)mgmt, + min((sizeof(dev->obuf)-1)/2, + (size_t)le16_to_cpu(buf->wlength)), '\0')); + } + + switch (subtype) { + case IEEE80211_STYPE_BEACON: + case IEEE80211_STYPE_PROBE_RESP: + rx_mgmt_beacon(dev,buf); + break; + + case IEEE80211_STYPE_ASSOC_RESP: + rx_mgmt_assoc(dev,buf); + break; + + case IEEE80211_STYPE_REASSOC_RESP: + rx_mgmt_reassoc(dev,buf); + break; + + case IEEE80211_STYPE_DISASSOC: + rx_mgmt_disassoc(dev,buf); + break; + + case IEEE80211_STYPE_AUTH: + rx_mgmt_auth(dev,buf); + break; + + case IEEE80211_STYPE_DEAUTH: + rx_mgmt_deauth(dev,buf); + break; + + default: + info("%s: mgmt, but not beacon, subtype = %x", + dev->netdev->name, subtype); + } + + return; +} + +static void dbg_dumpbuf(const char *tag, const u8 *buf, int size) +{ + int i; + + if (!at76_debug) return; + + for (i=0; i <-- 6 --> <-- 2 --> <-46-1500-> + + Type 0x80 0x00 = TCP/IP + Type 0x06 0x00 = XNS + Type 0x81 0x37 = Novell NetWare + + +802.3 + + +---------+---------+---------+---------- + | Dst | Src | Length | Data... + +---------+---------+---------+---------- + + <-- 6 --> <-- 6 --> <-- 2 --> <-46-1500-> + +802.2 (802.3 with 802.2 header) + + +---------+---------+---------+-------+-------+-------+---------- + | Dst | Src | Length | DSAP | SSAP |Control| Data... + +---------+---------+---------+-------+-------+-------+---------- + + <- 1 -> <- 1 -> <- 1 -> <-43-1497-> + +SNAP (802.3 with 802.2 and SNAP headers) + + +---------+---------+---------+-------+-------+-------+-----------+---------+----------- + | Dst | Src | Length | 0xAA | 0xAA | 0x03 | Org Code | Type | Data... + +---------+---------+---------+-------+-------+-------+-----------+---------+----------- + + <-- 3 --> <-- 2 --> <-38-1492-> + +*/ + +/* Convert the 802.11 header on a packet into an ethernet-style header + * (basically, pretend we're an ethernet card receiving ethernet packets) + * + * This routine returns with the skbuff pointing to the actual data (just past + * the end of the newly-created ethernet header). + */ +static void ieee80211_to_eth(struct sk_buff *skb, int iw_mode) +{ + struct ieee80211_hdr_3addr *i802_11_hdr; + struct ethhdr *eth_hdr_p; + u8 *src_addr; + u8 *dest_addr; + __be16 proto = 0; + int build_ethhdr = 1; + + i802_11_hdr = (struct ieee80211_hdr_3addr *)skb->data; + +#ifdef DEBUG + { + dbg_uc("%s: ENTRY skb len %d data %s", __FUNCTION__, + skb->len, hex2str(dev->obuf, skb->data, + min((int)sizeof(dev->obuf)/3,64), ' ')); + } +#endif + + skb_pull(skb, sizeof(struct ieee80211_hdr_3addr)); +// skb_trim(skb, skb->len - 4); /* Trim CRC */ + + src_addr = iw_mode == IW_MODE_ADHOC ? i802_11_hdr->addr2 + : i802_11_hdr->addr3; + dest_addr = i802_11_hdr->addr1; + + eth_hdr_p = (struct ethhdr *)skb->data; + if (!memcmp(eth_hdr_p->h_source, src_addr, ETH_ALEN) && + !memcmp(eth_hdr_p->h_dest, dest_addr, ETH_ALEN)) { + /* An ethernet frame is encapsulated within the data portion. + * Just use its header instead. */ + skb_pull(skb, sizeof(struct ethhdr)); + build_ethhdr = 0; + } else if (!memcmp(skb->data, snapsig, sizeof(snapsig))) { + /* SNAP frame - collapse it */ + skb_pull(skb, sizeof(rfc1042sig)+2); + proto = *(__be16 *)(skb->data - 2); + } else { +#ifdef IEEE_STANDARD + /* According to all standards, we should assume the data + * portion contains 802.2 LLC information, so we should give it + * an 802.3 header (which has the same implications) */ + proto = htons(skb->len); +#else /* IEEE_STANDARD */ + /* Unfortunately, it appears no actual 802.11 implementations + * follow any standards specs. They all appear to put a + * 16-bit ethertype after the 802.11 header instead, so we take + * that value and make it into an Ethernet-II packet. */ + /* Note that this means we can never support non-SNAP 802.2 + * frames (because we can't tell when we get one) */ + + /* jal: This isn't true. My WRT54G happily sends SNAP. + Difficult to speak for all APs, so I don't dare to define + IEEE_STANDARD ... */ + proto = *(__be16 *)(skb->data); + skb_pull(skb, 2); +#endif /* IEEE_STANDARD */ + } + + skb_reset_mac_header(skb); + eth_hdr_p = eth_hdr(skb); + if (build_ethhdr) { + /* This needs to be done in this order (eth_hdr_p->h_dest may + * overlap src_addr) */ + memcpy(eth_hdr_p->h_source, src_addr, ETH_ALEN); + memcpy(eth_hdr_p->h_dest, dest_addr, ETH_ALEN); + /* make an 802.3 header (proto = length) */ + eth_hdr_p->h_proto = proto; + } + + if (ntohs(eth_hdr_p->h_proto) > 1518) { + skb->protocol = eth_hdr_p->h_proto; + } else if (*(unsigned short *)skb->data == 0xFFFF) { + /* Magic hack for Novell IPX-in-802.3 packets */ + skb->protocol = htons(ETH_P_802_3); + } else { + /* Assume it's an 802.2 packet (it should be, and we have no + * good way to tell if it isn't) */ + skb->protocol = htons(ETH_P_802_2); + } + +#ifdef DEBUG + { + char da[3*ETH_ALEN], sa[3*ETH_ALEN]; + dbg_uc("%s: EXIT skb da %s sa %s proto x%04x len %d data %s", __FUNCTION__, + hex2str(da, eth_hdr(skb)->h_dest, ETH_ALEN, ':'), + hex2str(sa, eth_hdr(skb)->h_source, ETH_ALEN, ':'), + ntohs(skb->protocol), skb->len, + hex2str(dev->obuf, skb->data, + min((int)sizeof(dev->obuf)/3,64), ' ')); + } +#endif + +} + +/* Adjust the skb to trim the hardware header and CRC, and set up skb->mac, + * skb->protocol, etc. + */ +static void ieee80211_fixup(struct sk_buff *skb, int iw_mode) +{ + struct ieee80211_hdr_3addr *i802_11_hdr; + struct ethhdr *eth_hdr_p; + u8 *src_addr; + u8 *dest_addr; + __be16 proto = 0; + + i802_11_hdr = (struct ieee80211_hdr_3addr *)eth_hdr(skb); + skb_pull(skb, sizeof(struct ieee80211_hdr_3addr)); +// skb_trim(skb, skb->len - 4); /* Trim CRC */ + + src_addr = iw_mode == IW_MODE_ADHOC ? i802_11_hdr->addr2 + : i802_11_hdr->addr3; + dest_addr = i802_11_hdr->addr1; + + skb_reset_mac_header(skb); + eth_hdr_p = eth_hdr(skb); + if (!memcmp(eth_hdr_p->h_source, src_addr, ETH_ALEN) && + !memcmp(eth_hdr_p->h_dest, dest_addr, ETH_ALEN)) { + /* There's an ethernet header encapsulated within the data + * portion, count it as part of the hardware header */ + skb_pull(skb, sizeof(struct ethhdr)); + proto = eth_hdr_p->h_proto; + } else if (!memcmp(skb->data, snapsig, sizeof(snapsig))) { + /* SNAP frame - collapse it */ + /* RFC1042/802.1h encapsulated packet. Treat the SNAP header + * as part of the HW header and note the protocol. */ + /* NOTE: prism2 doesn't collapse Appletalk frames (why?). */ + skb_pull(skb, sizeof(rfc1042sig) + 2); + proto = *(__be16 *)(skb->data - 2); + } + + if (ntohs(proto) > 1518) { + skb->protocol = proto; + } else { +#ifdef IEEE_STANDARD + /* According to all standards, we should assume the data + * portion contains 802.2 LLC information */ + skb->protocol = htons(ETH_P_802_2); +#else /* IEEE_STANDARD */ + /* Unfortunately, it appears no actual 802.11 implementations + * follow any standards specs. They all appear to put a + * 16-bit ethertype after the 802.11 header instead, so we'll + * use that (and consider it part of the hardware header). */ + /* Note that this means we can never support non-SNAP 802.2 + * frames (because we can't tell when we get one) */ + skb->protocol = *(__be16 *)skb->data; + skb_pull(skb, 2); +#endif /* IEEE_STANDARD */ + } +} + +/* check for fragmented data in dev->rx_skb. If the packet was no fragment + or it was the last of a fragment set a skb containing the whole packet + is returned for further processing. Otherwise we get NULL and are + done and the packet is either stored inside the fragment buffer + or thrown away. The check for rx_copybreak is moved here. + Every returned skb starts with the ieee802_11 header and contains + _no_ FCS at the end */ +static struct sk_buff *check_for_rx_frags(struct at76c503 *dev) +{ + struct sk_buff *skb = (struct sk_buff *)dev->rx_skb; + struct at76c503_rx_buffer *buf = (struct at76c503_rx_buffer *)skb->data; + struct ieee80211_hdr_3addr *i802_11_hdr = + (struct ieee80211_hdr_3addr *)buf->packet; + /* seq_ctrl, fragment_number, sequence number of new packet */ + u16 sctl = le16_to_cpu(i802_11_hdr->seq_ctl); + u16 fragnr = sctl & 0xf; + u16 seqnr = sctl>>4; + u16 frame_ctl = le16_to_cpu(i802_11_hdr->frame_ctl); + + /* length including the IEEE802.11 header, excl. the trailing FCS, + excl. the struct at76c503_rx_buffer */ + int length = le16_to_cpu(buf->wlength) - dev->rx_data_fcs_len; + + /* where does the data payload start in skb->data ? */ + u8 *data = (u8 *)i802_11_hdr + sizeof(struct ieee80211_hdr_3addr); + + /* length of payload, excl. the trailing FCS */ + int data_len = length - (data - (u8 *)i802_11_hdr); + + int i; + struct rx_data_buf *bptr, *optr; + unsigned long oldest = ~0UL; + + dbg(DBG_RX_FRAGS, "%s: rx data frame_ctl %04x addr2 %s seq/frag %d/%d " + "length %d data %d: %s ...", + dev->netdev->name, frame_ctl, + mac2str(i802_11_hdr->addr2), + seqnr, fragnr, length, data_len, + hex2str(dev->obuf, data, + min((int)(sizeof(dev->obuf)-1)/2,32), '\0')); + + dbg(DBG_RX_FRAGS_SKB, "%s: incoming skb: head %p data %p " + "tail %lu end %lu len %d", + dev->netdev->name, skb->head, skb->data, (unsigned long)skb->tail, + (unsigned long)skb->end, skb->len); + + if (data_len <= 0) { + /* buffers contains no data */ + info("%s: rx skb without data", dev->netdev->name); + return NULL; + } + + if (fragnr == 0 && !(frame_ctl & IEEE80211_FCTL_MOREFRAGS)) { + /* unfragmented packet received */ + if (length < rx_copybreak && (skb = dev_alloc_skb(length)) != NULL) { + memcpy(skb_put(skb, length), + dev->rx_skb->data + AT76C503_RX_HDRLEN, length); + } else { + skb_pull(skb, AT76C503_RX_HDRLEN); + skb_trim(skb, length); + /* Use a new skb for the next receive */ + dev->rx_skb = NULL; + } + + dbg(DBG_RX_FRAGS, "%s: unfragmented", dev->netdev->name); + + return skb; + } + + /* remove the at76c503_rx_buffer header - we don't need it anymore */ + /* we need the IEEE802.11 header (for the addresses) if this packet + is the first of a chain */ + + assert(length > AT76C503_RX_HDRLEN); + skb_pull(skb, AT76C503_RX_HDRLEN); + /* remove FCS at end */ + skb_trim(skb, length); + + dbg(DBG_RX_FRAGS_SKB, "%s: trimmed skb: head %p data %p tail %lu " + "end %lu len %d data %p data_len %d", + dev->netdev->name, skb->head, skb->data, (unsigned long)skb->tail, + (unsigned long)skb->end, skb->len, data, data_len); + + /* look if we've got a chain for the sender address. + afterwards optr points to first free or the oldest entry, + or, if i < NR_RX_DATA_BUF, bptr points to the entry for the + sender address */ + /* determining the oldest entry doesn't cope with jiffies wrapping + but I don't care to delete a young entry at these rare moments ... */ + + for(i=0,bptr=dev->rx_data,optr=NULL; i < NR_RX_DATA_BUF; i++,bptr++) { + if (bptr->skb != NULL) { + if (!memcmp(i802_11_hdr->addr2, bptr->sender,ETH_ALEN)) + break; + else + if (optr == NULL) { + optr = bptr; + oldest = bptr->last_rx; + } else { + if (bptr->last_rx < oldest) + optr = bptr; + } + } else { + optr = bptr; + oldest = 0UL; + } + } + + if (i < NR_RX_DATA_BUF) { + + dbg(DBG_RX_FRAGS, "%s: %d. cacheentry (seq/frag=%d/%d) " + "matched sender addr", + dev->netdev->name, i, bptr->seqnr, bptr->fragnr); + + /* bptr points to an entry for the sender address */ + if (bptr->seqnr == seqnr) { + int left; + /* the fragment has the current sequence number */ + if (((bptr->fragnr+1)&0xf) == fragnr) { + bptr->last_rx = jiffies; + /* the next following fragment number -> + add the data at the end */ + /* is & 0xf necessary above ??? */ + + // for test only ??? + if ((left=skb_tailroom(bptr->skb)) < data_len) { + info("%s: only %d byte free (need %d)", + dev->netdev->name, left, data_len); + } else + memcpy(skb_put(bptr->skb, data_len), + data, data_len); + bptr->fragnr = fragnr; + if (!(frame_ctl & + IEEE80211_FCTL_MOREFRAGS)) { + /* this was the last fragment - send it */ + skb = bptr->skb; + bptr->skb = NULL; /* free the entry */ + dbg(DBG_RX_FRAGS, "%s: last frag of seq %d", + dev->netdev->name, seqnr); + return skb; + } else + return NULL; + } else { + /* wrong fragment number -> ignore it */ + dbg(DBG_RX_FRAGS, "%s: frag nr does not match: %d+1 != %d", + dev->netdev->name, bptr->fragnr, fragnr); + return NULL; + } + } else { + /* got another sequence number */ + if (fragnr == 0) { + /* it's the start of a new chain - replace the + old one by this */ + /* bptr->sender has the correct value already */ + dbg(DBG_RX_FRAGS, "%s: start of new seq %d, " + "removing old seq %d", dev->netdev->name, + seqnr, bptr->seqnr); + bptr->seqnr = seqnr; + bptr->fragnr = 0; + bptr->last_rx = jiffies; + /* swap bptr->skb and dev->rx_skb */ + skb = bptr->skb; + bptr->skb = dev->rx_skb; + dev->rx_skb = skb; + } else { + /* it from the middle of a new chain -> + delete the old entry and skip the new one */ + dbg(DBG_RX_FRAGS, "%s: middle of new seq %d (%d) " + "removing old seq %d", dev->netdev->name, + seqnr, fragnr, bptr->seqnr); + dev_kfree_skb(bptr->skb); + bptr->skb = NULL; + } + return NULL; + } + } else { + /* if we didn't find a chain for the sender address optr + points either to the first free or the oldest entry */ + + if (fragnr != 0) { + /* this is not the begin of a fragment chain ... */ + dbg(DBG_RX_FRAGS, "%s: no chain for non-first fragment (%d)", + dev->netdev->name, fragnr); + return NULL; + } + assert(optr != NULL); + if (optr == NULL) + return NULL; + + if (optr->skb != NULL) { + /* swap the skb's */ + skb = optr->skb; + optr->skb = dev->rx_skb; + dev->rx_skb = skb; + + dbg(DBG_RX_FRAGS, "%s: free old contents: sender %s seq/frag %d/%d", + dev->netdev->name, mac2str(optr->sender), + optr->seqnr, optr->fragnr); + + } else { + /* take the skb from dev->rx_skb */ + optr->skb = dev->rx_skb; + dev->rx_skb = NULL; /* let submit_rx_urb() allocate a new skb */ + + dbg(DBG_RX_FRAGS, "%s: use a free entry", dev->netdev->name); + } + memcpy(optr->sender, i802_11_hdr->addr2, ETH_ALEN); + optr->seqnr = seqnr; + optr->fragnr = 0; + optr->last_rx = jiffies; + + return NULL; + } +} /* check_for_rx_frags */ + +/* rx interrupt: we expect the complete data buffer in dev->rx_skb */ +static void rx_data(struct at76c503 *dev) +{ + struct net_device *netdev = (struct net_device *)dev->netdev; + struct net_device_stats *stats = &dev->stats; + struct sk_buff *skb = dev->rx_skb; + struct at76c503_rx_buffer *buf = (struct at76c503_rx_buffer *)skb->data; + struct ieee80211_hdr_3addr *i802_11_hdr; + int length = le16_to_cpu(buf->wlength); + + if (at76_debug & DBG_RX_DATA) { + dbg_uc("%s received data packet:", netdev->name); + dbg_dumpbuf(" rxhdr", skb->data, AT76C503_RX_HDRLEN); + } + if (at76_debug & DBG_RX_DATA_CONTENT) + dbg_dumpbuf("packet", skb->data + AT76C503_RX_HDRLEN, + length); + + if ((skb=check_for_rx_frags(dev)) == NULL) + return; + + /* if an skb is returned, the at76c503a_rx_header and the FCS is already removed */ + i802_11_hdr = (struct ieee80211_hdr_3addr *)skb->data; + + skb->dev = netdev; + skb->ip_summed = CHECKSUM_NONE; /* TODO: should check CRC */ + + if (i802_11_hdr->addr1[0] & 1) { + if (!memcmp(i802_11_hdr->addr1, netdev->broadcast, ETH_ALEN)) + skb->pkt_type = PACKET_BROADCAST; + else + skb->pkt_type = PACKET_MULTICAST; + } else if (memcmp(i802_11_hdr->addr1, netdev->dev_addr, ETH_ALEN)) { + skb->pkt_type=PACKET_OTHERHOST; + } + + if (netdev->type == ARPHRD_ETHER) { + ieee80211_to_eth(skb, dev->iw_mode); + } else { + ieee80211_fixup(skb, dev->iw_mode); + } + + netdev->last_rx = jiffies; + netif_rx(skb); + stats->rx_packets++; + stats->rx_bytes += length; + + return; +} + +static int submit_rx_urb(struct at76c503 *dev) +{ + int ret, size; + struct sk_buff *skb = dev->rx_skb; + + if (dev->read_urb == NULL) { + err("%s: dev->read_urb is NULL", __FUNCTION__); + return -EFAULT; + } + + if (skb == NULL) { + skb = dev_alloc_skb(sizeof(struct at76c503_rx_buffer)); + if (skb == NULL) { + err("%s: unable to allocate rx skbuff.", dev->netdev->name); + ret = -ENOMEM; + goto exit; + } + dev->rx_skb = skb; + } else { + skb_push(skb, skb_headroom(skb)); + skb_trim(skb, 0); + } + + size = skb_tailroom(skb); + FILL_BULK_URB(dev->read_urb, dev->udev, + usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr), + skb_put(skb, size), size, + (usb_complete_t)at76c503_read_bulk_callback, dev); + ret = usb_submit_urb(dev->read_urb, GFP_ATOMIC); + if (ret < 0) { + if (ret == -ENODEV) + dbg(DBG_DEVSTART, "usb_submit_urb returned -ENODEV"); + else + err("%s: rx, usb_submit_urb failed: %d", dev->netdev->name, ret); + } + +exit: + if (ret < 0) { + if (ret != -ENODEV) { + /* If we can't submit the URB, the adapter becomes completely + * useless, so try again later */ + if (--dev->nr_submit_rx_tries > 0) + defer_kevent(dev, KEVENT_SUBMIT_RX); + else { + err("%s: giving up to submit rx urb after %d failures -" + " please unload the driver and/or power cycle the device", + dev->netdev->name, NR_SUBMIT_RX_TRIES); + } + } + } else + /* reset counter to initial value */ + dev->nr_submit_rx_tries = NR_SUBMIT_RX_TRIES; + return ret; +} + + +/* we are doing a lot of things here in an interrupt. Need + a bh handler (Watching TV with a TV card is probably + a good test: if you see flickers, we are doing too much. + Currently I do see flickers... even with our tasklet :-( ) + Maybe because the bttv driver and usb-uhci use the same interrupt +*/ +/* Or maybe because our BH handler is preempting bttv's BH handler.. BHs don't + * solve everything.. (alex) */ +static void at76c503_read_bulk_callback (struct urb *urb) +{ + struct at76c503 *dev = (struct at76c503 *)urb->context; + + dev->rx_urb = urb; + tasklet_schedule(&dev->tasklet); + + return; +} + +static void rx_monitor_mode(struct at76c503 *dev) +{ + struct net_device *netdev = (struct net_device *)dev->netdev; + struct at76c503_rx_buffer *buf = + (struct at76c503_rx_buffer *)dev->rx_skb->data; + /* length including the IEEE802.11 header, excl. the trailing FCS, + excl. the struct at76c503_rx_buffer */ + int length = le16_to_cpu(buf->wlength) - dev->rx_data_fcs_len; + struct sk_buff *skb = dev->rx_skb; + struct net_device_stats *stats = &dev->stats; + struct iw_statistics *wstats = &dev->wstats; + + update_wstats(dev, buf); + + if (length < 0) { + /* buffer contains no data */ + dbg(DBG_MONITOR_MODE, "%s: MONITOR MODE: rx skb without data", + dev->netdev->name); + return; + } + + if (netdev->type == ARPHRD_IEEE80211_PRISM) { + int skblen = sizeof(p80211msg_lnxind_wlansniffrm_t) + length; + p80211msg_lnxind_wlansniffrm_t *prism; + u8* payload; + + if ((skb = dev_alloc_skb(skblen)) == NULL) { + err("%s: MONITOR MODE: dev_alloc_skb for Prism header " + "returned NULL", dev->netdev->name); + return; + } + + skb_put(skb, skblen); + + prism = (p80211msg_lnxind_wlansniffrm_t*)skb->data; + payload = skb->data + sizeof(p80211msg_lnxind_wlansniffrm_t); + + prism->msgcode = DIDmsg_lnxind_wlansniffrm; + prism->msglen = sizeof(p80211msg_lnxind_wlansniffrm_t); + strcpy(prism->devname, netdev->name); + + prism->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime; + prism->hosttime.status = 0; + prism->hosttime.len = 4; + prism->hosttime.data = jiffies; + + prism->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime; + prism->mactime.status = 0; + prism->mactime.len = 4; + memcpy(&prism->mactime.data, buf->rx_time, 4); + + prism->channel.did = DIDmsg_lnxind_wlansniffrm_channel; + prism->channel.status = P80211ENUM_msgitem_status_no_value; + prism->channel.len = 4; + /* INFO: The channel is encoded in the beacon info. + (Kismet can figure it out, so less processing here) */ + prism->channel.data = 0; + + prism->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi; + prism->rssi.status = 0; + prism->rssi.len = 4; + prism->rssi.data = buf->rssi; + + prism->sq.did = DIDmsg_lnxind_wlansniffrm_sq; + prism->sq.status = 0; + prism->sq.len = 4; + prism->sq.data = wstats->qual.qual; + + prism->signal.did = DIDmsg_lnxind_wlansniffrm_signal; + prism->signal.status = 0; + prism->signal.len = 4; + prism->signal.data = wstats->qual.level; + + prism->noise.did = DIDmsg_lnxind_wlansniffrm_noise; + prism->noise.status = 0; + prism->noise.len = 4; + prism->noise.data = wstats->qual.noise; + + prism->rate.did = DIDmsg_lnxind_wlansniffrm_rate; + prism->rate.status = 0; + prism->rate.len = 4; + prism->rate.data = hw_rates[buf->rx_rate] & (~0x80); + + prism->istx.did = DIDmsg_lnxind_wlansniffrm_istx; + prism->istx.status = 0; + prism->istx.len = 4; + prism->istx.data = P80211ENUM_truth_false; + + prism->frmlen.did = DIDmsg_lnxind_wlansniffrm_frmlen; + prism->frmlen.status = 0; + prism->frmlen.len = 4; + prism->frmlen.data = length; + + memcpy(payload, buf->packet, length); + } else { + /* netdev->type != ARPHRD_IEEE80211_PRISM */ + skb_pull(skb, AT76C503_RX_HDRLEN); + skb_trim(skb, length); + dev->rx_skb = NULL; + } + + skb->dev = netdev; + skb->ip_summed = CHECKSUM_NONE; + skb_reset_mac_header(skb); + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_80211_RAW); + + netdev->last_rx = jiffies; + netif_rx(skb); + stats->rx_packets++; + stats->rx_bytes += length; +} /* end of rx_monitor_mode */ + + +static void rx_tasklet(unsigned long param) +{ + struct at76c503 *dev = (struct at76c503 *)param; + struct urb *urb; + struct net_device *netdev; + struct at76c503_rx_buffer *buf; + struct ieee80211_hdr_3addr *i802_11_hdr; + u16 frame_ctl; + + if (!dev) return; + urb = dev->rx_urb; + netdev = (struct net_device *)dev->netdev; + + if (dev->device_unplugged) { + dbg(DBG_DEVSTART, "device unplugged"); + if (urb) + dbg(DBG_DEVSTART, "urb status %d", urb->status); + return; + } + + + if(!urb || !dev->rx_skb || !netdev || !dev->rx_skb->data) return; + + buf = (struct at76c503_rx_buffer *)dev->rx_skb->data; + + if (!buf) return; + + i802_11_hdr = (struct ieee80211_hdr_3addr *)buf->packet; + if (!i802_11_hdr) return; + + frame_ctl = le16_to_cpu(i802_11_hdr->frame_ctl); + + if(urb->status != 0){ + if ((urb->status != -ENOENT) && + (urb->status != -ECONNRESET)) { + dbg(DBG_URB,"%s %s: - nonzero read bulk status received: %d", + __FUNCTION__, netdev->name, urb->status); + goto no_more_urb; + } + return; + } + + if (at76_debug & DBG_RX_ATMEL_HDR) { + dbg_uc("%s: rx frame: rate %d rssi %d noise %d link %d %s", + dev->netdev->name, + buf->rx_rate, buf->rssi, buf->noise_level, + buf->link_quality, + hex2str(dev->obuf,(u8 *)i802_11_hdr, + min((int)(sizeof(dev->obuf)-1)/2,48),'\0')); + } + LOCK_ISTATE() + if (dev->istate == MONITORING) { + UNLOCK_ISTATE() + rx_monitor_mode(dev); + goto finish; + } + UNLOCK_ISTATE() + + /* there is a new bssid around, accept it: */ + if(buf->newbss && dev->iw_mode == IW_MODE_ADHOC) { + dbg(DBG_PROGRESS, "%s: rx newbss", netdev->name); + defer_kevent(dev, KEVENT_NEW_BSS); + } + + switch (frame_ctl & IEEE80211_FCTL_FTYPE) { + case IEEE80211_FTYPE_DATA: + rx_data(dev); + break; + + case IEEE80211_FTYPE_MGMT: + /* jal: TODO: find out if we can update iwspy also on + other frames than management (might depend on the + radio chip / firmware version !) */ + + iwspy_update(dev, buf); + + rx_mgmt(dev, buf); + break; + + case IEEE80211_FTYPE_CTL: + dbg(DBG_RX_CTRL, "%s: ignored ctrl frame: %04x", dev->netdev->name, + frame_ctl); + break; + + default: + info("%s: it's a frame from mars: %2x", dev->netdev->name, + frame_ctl); + } /* switch (frame_ctl & IEEE80211_FCTL_FTYPE) */ +finish: + submit_rx_urb(dev); + no_more_urb: + return; +} + +static void at76c503_write_bulk_callback (struct urb *urb) +{ + struct at76c503 *dev = (struct at76c503 *)urb->context; + struct net_device_stats *stats = &dev->stats; + unsigned long flags; + struct at76c503_tx_buffer *mgmt_buf; + int ret; + + if(urb->status != 0){ + if((urb->status != -ENOENT) && + (urb->status != -ECONNRESET)) { + dbg(DBG_URB, "%s - nonzero write bulk status received: %d", + __FUNCTION__, urb->status); + }else + return; /* urb has been unlinked */ + stats->tx_errors++; + }else + stats->tx_packets++; + + spin_lock_irqsave(&dev->mgmt_spinlock, flags); + mgmt_buf = dev->next_mgmt_bulk; + dev->next_mgmt_bulk = NULL; + spin_unlock_irqrestore(&dev->mgmt_spinlock, flags); + + if (mgmt_buf) { + /* we don't copy the padding bytes, but add them + to the length */ + memcpy(dev->bulk_out_buffer, mgmt_buf, + le16_to_cpu(mgmt_buf->wlength) + + offsetof(struct at76c503_tx_buffer,packet)); + FILL_BULK_URB(dev->write_urb, dev->udev, + usb_sndbulkpipe(dev->udev, + dev->bulk_out_endpointAddr), + dev->bulk_out_buffer, + le16_to_cpu(mgmt_buf->wlength) + + mgmt_buf->padding + AT76C503_TX_HDRLEN, + (usb_complete_t)at76c503_write_bulk_callback, dev); + ret = usb_submit_urb(dev->write_urb, GFP_ATOMIC); + if (ret) { + err("%s: %s error in tx submit urb: %d", + dev->netdev->name, __FUNCTION__, ret); + } + kfree(mgmt_buf); + } else + netif_wake_queue(dev->netdev); + +} + +#ifdef CONFIG_IPAQ_HANDHELD + +static struct timer_list led_timer; + +static void +ipaq_clear_led (unsigned long time) +{ + ipaq_led_off (RED_LED_2); +} + +static void +ipaq_blink_led (void) +{ + ipaq_led_on (RED_LED_2); + + mod_timer (&led_timer, jiffies + (HZ / 25)); +} + +static void +ipaq_init_led (void) +{ + led_timer.function = ipaq_clear_led; + + init_timer (&led_timer); +} + +#endif + +static int at76c503_tx(struct sk_buff *skb, struct net_device *netdev) +{ + struct at76c503 *dev = (struct at76c503 *)(netdev->priv); + struct net_device_stats *stats = &dev->stats; + int ret = 0; + int wlen; + int submit_len; + struct at76c503_tx_buffer *tx_buffer = + (struct at76c503_tx_buffer *)dev->bulk_out_buffer; + struct ieee80211_hdr_3addr *i802_11_hdr = + (struct ieee80211_hdr_3addr *)&(tx_buffer->packet); + u8 *payload = tx_buffer->packet + sizeof(struct ieee80211_hdr_3addr); + + if (netif_queue_stopped(netdev)) { + err("%s: %s called while netdev is stopped", netdev->name, + __FUNCTION__); + //skip this packet + dev_kfree_skb(skb); + return 0; + } + + if (dev->write_urb->status == -EINPROGRESS) { + err("%s: %s called while dev->write_urb is pending for tx", + netdev->name, __FUNCTION__); + //skip this packet + dev_kfree_skb(skb); + return 0; + } + + if (skb->len < 2*ETH_ALEN) { + err("%s: %s: skb too short (%d)", dev->netdev->name, + __FUNCTION__, skb->len); + dev_kfree_skb(skb); + return 0; + } + +#ifdef CONFIG_IPAQ_HANDHELD + if (machine_is_h5400 ()) + ipaq_blink_led (); +#endif + + /* we can get rid of memcpy, if we set netdev->hard_header_len + to 8 + sizeof(struct ieee80211_hdr_3addr), because then we have + enough space */ + // dbg(DBG_TX, "skb->data - skb->head = %d", skb->data - skb->head); + + if (ntohs(*(__be16 *)(skb->data + 2*ETH_ALEN)) <= 1518) { + /* this is a 802.3 packet */ + if (skb->data[2*ETH_ALEN+2] == rfc1042sig[0] && + skb->data[2*ETH_ALEN+2+1] == rfc1042sig[1]) { + /* higher layer delivered SNAP header - keep it */ + memcpy(payload, skb->data + 2*ETH_ALEN+2, skb->len - 2*ETH_ALEN -2); + wlen = sizeof(struct ieee80211_hdr_3addr) + skb->len - 2*ETH_ALEN -2; + } else { + err("%s: %s: no support for non-SNAP 802.2 packets " + "(DSAP x%02x SSAP x%02x cntrl x%02x)", + dev->netdev->name, __FUNCTION__, + skb->data[2*ETH_ALEN+2], skb->data[2*ETH_ALEN+2+1], + skb->data[2*ETH_ALEN+2+2]); + dev_kfree_skb(skb); + return 0; + } + } else { + /* add RFC 1042 header in front */ + memcpy(payload, rfc1042sig, sizeof(rfc1042sig)); + memcpy(payload + sizeof(rfc1042sig), + skb->data + 2*ETH_ALEN, skb->len - 2*ETH_ALEN); + wlen = sizeof(struct ieee80211_hdr_3addr) + sizeof(rfc1042sig) + + skb->len - 2*ETH_ALEN; + } + + /* make wireless header */ + i802_11_hdr->frame_ctl = + cpu_to_le16(IEEE80211_FTYPE_DATA | + (dev->wep_enabled ? IEEE80211_FCTL_PROTECTED : 0) | + (dev->iw_mode == IW_MODE_INFRA ? IEEE80211_FCTL_TODS : 0)); + + if(dev->iw_mode == IW_MODE_ADHOC){ + memcpy(i802_11_hdr->addr1, skb->data, ETH_ALEN); /* destination */ + memcpy(i802_11_hdr->addr2, skb->data+ETH_ALEN, ETH_ALEN); /* source */ + memcpy(i802_11_hdr->addr3, dev->bssid, ETH_ALEN); + }else if(dev->iw_mode == IW_MODE_INFRA){ + memcpy(i802_11_hdr->addr1, dev->bssid, ETH_ALEN); + memcpy(i802_11_hdr->addr2, skb->data+ETH_ALEN, ETH_ALEN); /* source */ + memcpy(i802_11_hdr->addr3, skb->data, ETH_ALEN); /* destination */ + } + + i802_11_hdr->duration_id = cpu_to_le16(0); + i802_11_hdr->seq_ctl = cpu_to_le16(0); + + /* setup 'Atmel' header */ + tx_buffer->wlength = cpu_to_le16(wlen); + tx_buffer->tx_rate = dev->txrate; + /* for broadcast destination addresses, the firmware 0.100.x + seems to choose the highest rate set with CMD_STARTUP in + basic_rate_set replacing this value */ + + memset(tx_buffer->reserved, 0, 4); + + tx_buffer->padding = calc_padding(wlen); + submit_len = wlen + AT76C503_TX_HDRLEN + tx_buffer->padding; + + { + dbg(DBG_TX_DATA_CONTENT, "%s skb->data %s", dev->netdev->name, + hex2str(dev->obuf, skb->data, + min((int)(sizeof(dev->obuf)-1)/2,32),'\0')); + dbg(DBG_TX_DATA, "%s tx wlen x%x pad x%x rate %d hdr %s", + dev->netdev->name, + le16_to_cpu(tx_buffer->wlength), + tx_buffer->padding, tx_buffer->tx_rate, + hex2str(dev->obuf, (u8 *)i802_11_hdr, + min((sizeof(dev->obuf)-1)/2, + sizeof(struct ieee80211_hdr_3addr)),'\0')); + dbg(DBG_TX_DATA_CONTENT, "%s payload %s", dev->netdev->name, + hex2str(dev->obuf, payload, + min((int)(sizeof(dev->obuf)-1)/2,48),'\0')); + } + + /* send stuff */ + netif_stop_queue(netdev); + netdev->trans_start = jiffies; + + FILL_BULK_URB(dev->write_urb, dev->udev, + usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), + tx_buffer, submit_len, + (usb_complete_t)at76c503_write_bulk_callback, dev); + ret = usb_submit_urb(dev->write_urb, GFP_ATOMIC); + if(ret){ + stats->tx_errors++; + err("%s: error in tx submit urb: %d", netdev->name, ret); + if (ret == -EINVAL) + err("-EINVAL: urb %p urb->hcpriv %p urb->complete %p", + dev->write_urb, + dev->write_urb ? dev->write_urb->hcpriv : (void *)-1, + dev->write_urb ? dev->write_urb->complete : (void *)-1); + goto err; + } + + stats->tx_bytes += skb->len; + + dev_kfree_skb(skb); + return 0; + + err: + return ret; +} + + +static void at76c503_tx_timeout(struct net_device *netdev) +{ + struct at76c503 *dev = (struct at76c503 *)(netdev->priv); + + if (!dev) + return; + warn("%s: tx timeout.", netdev->name); +#if WIRELESS_EXT < 17 + dev->write_urb->transfer_flags |= USB_ASYNC_UNLINK; +#endif + usb_unlink_urb(dev->write_urb); + dev->stats.tx_errors++; +} + +static int startup_device(struct at76c503 *dev) +{ + struct at76c503_card_config *ccfg = &dev->card_config; + int ret; + + if (at76_debug & DBG_PARAMS) { + char ossid[IW_ESSID_MAX_SIZE+1]; + + /* make dev->essid printable */ + assert(dev->essid_size <= IW_ESSID_MAX_SIZE); + memcpy(ossid, dev->essid, dev->essid_size); + ossid[dev->essid_size] = '\0'; + + dbg_uc("%s param: ssid %s (%s) mode %s ch %d wep %s key %d keylen %d", + dev->netdev->name, ossid, + hex2str(dev->obuf, dev->essid, + min((int)(sizeof(dev->obuf)-1)/2, + IW_ESSID_MAX_SIZE), '\0'), + dev->iw_mode == IW_MODE_ADHOC ? "adhoc" : "infra", + dev->channel, + dev->wep_enabled ? "enabled" : "disabled", + dev->wep_key_id, dev->wep_keys_len[dev->wep_key_id]); + dbg_uc("%s param: preamble %s rts %d retry %d frag %d " + "txrate %s auth_mode %d", + dev->netdev->name, + dev->preamble_type == PREAMBLE_TYPE_SHORT ? "short" : "long", + dev->rts_threshold, dev->short_retry_limit, + dev->frag_threshold, + dev->txrate == TX_RATE_1MBIT ? "1MBit" : + dev->txrate == TX_RATE_2MBIT ? "2MBit" : + dev->txrate == TX_RATE_5_5MBIT ? "5.5MBit" : + dev->txrate == TX_RATE_11MBIT ? "11MBit" : + dev->txrate == TX_RATE_AUTO ? "auto" : "", + dev->auth_mode); + dbg_uc("%s param: pm_mode %d pm_period %d auth_mode %s " + "scan_times %d %d scan_mode %s international_roaming %d", + dev->netdev->name, + dev->pm_mode, dev->pm_period_us, + dev->auth_mode == WLAN_AUTH_OPEN ? + "open" : "shared_secret", + dev->scan_min_time, dev->scan_max_time, + dev->scan_mode == SCAN_TYPE_ACTIVE ? "active" : "passive", + dev->international_roaming); + } + + memset(ccfg, 0, sizeof(struct at76c503_card_config)); + ccfg->promiscuous_mode = 0; + ccfg->short_retry_limit = dev->short_retry_limit; + //ccfg->long_retry_limit = dev->long_retry_limit; + + if (dev->wep_enabled) { + if (dev->wep_keys_len[dev->wep_key_id] > WEP_SMALL_KEY_LEN) + ccfg->encryption_type = 2; + else + ccfg->encryption_type = 1; + + /* jal: always exclude unencrypted if WEP is active */ + ccfg->exclude_unencrypted = 1; + } else { + ccfg->exclude_unencrypted = 0; + ccfg->encryption_type = 0; + } + + ccfg->rts_threshold = cpu_to_le16(dev->rts_threshold); + ccfg->fragmentation_threshold = cpu_to_le16(dev->frag_threshold); + + memcpy(ccfg->basic_rate_set, hw_rates, 4); + /* jal: really needed, we do a set_mib for autorate later ??? */ + ccfg->auto_rate_fallback = (dev->txrate == TX_RATE_AUTO ? 1 : 0); + ccfg->channel = dev->channel; + ccfg->privacy_invoked = dev->wep_enabled; + memcpy(ccfg->current_ssid, dev->essid, IW_ESSID_MAX_SIZE); + ccfg->ssid_len = dev->essid_size; + + ccfg->wep_default_key_id = dev->wep_key_id; + memcpy(ccfg->wep_default_key_value, dev->wep_keys, 4 * WEP_KEY_LEN); + + ccfg->short_preamble = dev->preamble_type; + ccfg->beacon_period = cpu_to_le16(dev->beacon_period); + + ret = set_card_command(dev->udev, CMD_STARTUP, (unsigned char *)&dev->card_config, + sizeof(struct at76c503_card_config)); + if(ret < 0){ + err("%s: set_card_command failed: %d", dev->netdev->name, ret); + return ret; + } + + wait_completion(dev, CMD_STARTUP); + + /* remove BSSID from previous run */ + memset(dev->bssid, 0, ETH_ALEN); + + if (set_radio(dev, 1) == 1) + wait_completion(dev, CMD_RADIO); + + if ((ret=set_preamble(dev, dev->preamble_type)) < 0) + return ret; + if ((ret=set_frag(dev, dev->frag_threshold)) < 0) + return ret; + + if ((ret=set_rts(dev, dev->rts_threshold)) < 0) + return ret; + + if ((ret=set_autorate_fallback(dev, dev->txrate == TX_RATE_AUTO ? 1 : 0)) < 0) + return ret; + + if ((ret=set_pm_mode(dev, dev->pm_mode)) < 0) + return ret; + + if ((ret=set_iroaming(dev, dev->international_roaming)) < 0) + return ret; + + if (at76_debug & DBG_MIB) + { + dump_mib_mac(dev); + dump_mib_mac_addr(dev); + dump_mib_mac_mgmt(dev); + dump_mib_mac_wep(dev); + dump_mib_mdomain(dev); + dump_mib_phy(dev); + dump_mib_local(dev); + } + + return 0; +} + +static int at76c503_open(struct net_device *netdev) +{ + struct at76c503 *dev = (struct at76c503 *)(netdev->priv); + int ret = 0; + + dbg(DBG_PROC_ENTRY, "at76c503_open entry"); + + if(down_interruptible(&dev->sem)) + return -EINTR; + + /* if netdev->dev_addr != dev->mac_addr we must + set the mac address in the device ! */ + if (memcmp(netdev->dev_addr, dev->mac_addr, ETH_ALEN)) { + if (set_mac_address(dev,netdev->dev_addr) >= 0) + dbg(DBG_PROGRESS, "%s: set new MAC addr %s", + netdev->name, mac2str(netdev->dev_addr)); + } + +#ifdef DEBUG //test only !!! + dump_mib_mac_addr(dev); +#endif + + dev->site_survey_state=SITE_SURVEY_IDLE; + dev->last_survey = jiffies; + dev->nr_submit_rx_tries = NR_SUBMIT_RX_TRIES; /* init counter */ + + if((ret=submit_rx_urb(dev)) < 0){ + err("%s: open: submit_rx_urb failed: %d", netdev->name, ret); + goto err; + } + + dev->open_count++; + + defer_kevent(dev, KEVENT_RESTART); + + dbg(DBG_PROC_ENTRY, "at76c503_open end"); + err: + up(&dev->sem); + return ret < 0 ? ret : 0; +} + +static int at76c503_stop(struct net_device *netdev) +{ + struct at76c503 *dev = (struct at76c503 *)(netdev->priv); + unsigned long flags; + + dbg(DBG_DEVSTART, "%s: ENTER", __FUNCTION__); + + if (down_interruptible(&dev->sem)) + return -EINTR; + + netif_stop_queue(netdev); + + NEW_STATE(dev,INIT); + + if (!(dev->device_unplugged)) { + /* we are called by "ifconfig wlanX down", not because the + device isn't avail. anymore */ + set_radio(dev, 0); + + /* we unlink the read urb, because the _open() + submits it again. _delete_device() takes care of the + read_urb otherwise. */ + usb_kill_urb(dev->read_urb); + } + + del_timer_sync(&dev->mgmt_timer); + + spin_lock_irqsave(&dev->mgmt_spinlock,flags); + if (dev->next_mgmt_bulk) { + kfree(dev->next_mgmt_bulk); + dev->next_mgmt_bulk = NULL; + } + spin_unlock_irqrestore(&dev->mgmt_spinlock,flags); + + /* free the bss_list */ + free_bss_list(dev); + + assert(dev->open_count > 0); + dev->open_count--; + + up(&dev->sem); + + dbg(DBG_DEVSTART, "%s: EXIT", __FUNCTION__); + + return 0; +} + +static struct net_device_stats *at76c503_get_stats(struct net_device *netdev) +{ + struct at76c503 *dev = (struct at76c503 *)netdev->priv; + + return &dev->stats; +} + +static struct iw_statistics *at76c503_get_wireless_stats(struct net_device *netdev) +{ + struct at76c503 *dev = (struct at76c503 *)netdev->priv; + + dbg(DBG_IOCTL, "RETURN qual %d level %d noise %d updated %d", + dev->wstats.qual.qual, dev->wstats.qual.level, + dev->wstats.qual.noise, dev->wstats.qual.updated); + + return &dev->wstats; +} + +static void at76c503_set_multicast(struct net_device *netdev) +{ + struct at76c503 *dev = (struct at76c503 *)netdev->priv; + int promisc; + + promisc = ((netdev->flags & IFF_PROMISC) != 0); + if(promisc != dev->promisc){ + /* grmbl. This gets called in interrupt. */ + dev->promisc = promisc; + defer_kevent(dev, KEVENT_SET_PROMISC); + } +} + +/* we only store the new mac address in netdev struct, + it got set when the netdev gets opened. */ +static int at76c503_set_mac_address(struct net_device *netdev, void *addr) +{ + struct sockaddr *mac = addr; + memcpy(netdev->dev_addr, mac->sa_data, ETH_ALEN); + return 1; +} + +/* == PROC iwspy_update == + check if we spy on the sender address of buf and update statistics */ +static void iwspy_update(struct at76c503 *dev, struct at76c503_rx_buffer *buf) +{ + struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)buf->packet; + struct iw_quality qual; + + /* We can only set the level here */ + qual.updated = IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID; + qual.level = 0; + qual.noise = 0; + calc_level(dev, buf, &qual); + + spin_lock_bh(&(dev->spy_spinlock)); + + if (dev->spy_data.spy_number > 0) { + wireless_spy_update(dev->netdev, hdr->addr2, &qual); + } + spin_unlock_bh(&(dev->spy_spinlock)); +} /* iwspy_update */ + + +/******************************************************************************* + * structure that describes the private ioctls/iw handlers of this driver + */ +static const struct iw_priv_args at76c503_priv_args[] = { + { PRIV_IOCTL_SET_SHORT_PREAMBLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "short_preamble" }, // 0 - long, 1 -short + + { PRIV_IOCTL_SET_DEBUG, + // we must pass the new debug mask as a string, + // 'cause iwpriv cannot parse hex numbers + // starting with 0x :-( + IW_PRIV_TYPE_CHAR | 10, 0, + "set_debug"}, // set debug value + + { PRIV_IOCTL_SET_POWERSAVE_MODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "powersave_mode"}, // 1 - active, 2 - power save, + // 3 - smart power save + { PRIV_IOCTL_SET_SCAN_TIMES, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, + "scan_times"}, // min_channel_time, + // max_channel_time + { PRIV_IOCTL_SET_SCAN_MODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "scan_mode"}, // 0 - active, 1 - passive scan + + { PRIV_IOCTL_SET_INTL_ROAMING, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "intl_roaming"}, + + /* needed for Kismet, orinoco mode */ + { PRIV_IOCTL_SET_MONITOR_MODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, + "monitor"}, /* param1: monitor mode: 0 (off), 1 (on,Prism header), + 2 (on, no Prism header) + param2: channel (to start scan at) */ +}; + + +/******************************************************************************* + * at76c503 implementations of iw_handler functions: + */ +static int at76c503_iw_handler_commit(struct net_device *netdev, + struct iw_request_info *info, + void *null, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + unsigned long flags; + + dbg(DBG_IOCTL, "%s %s: restarting the device", netdev->name, + __FUNCTION__); + + // stop any pending tx bulk urb + //TODO + + // jal: TODO: protect access to dev->istate by a spinlock + // (ISR's on other processors may read/write it) + LOCK_ISTATE() + if (dev->istate != INIT) { + UNLOCK_ISTATE() + NEW_STATE(dev,INIT); + // stop pending management stuff + del_timer_sync(&dev->mgmt_timer); + + spin_lock_irqsave(&dev->mgmt_spinlock,flags); + if (dev->next_mgmt_bulk) { + kfree(dev->next_mgmt_bulk); + dev->next_mgmt_bulk = NULL; + } + spin_unlock_irqrestore(&dev->mgmt_spinlock,flags); + + netif_carrier_off(dev->netdev); + netif_stop_queue(dev->netdev); + } else UNLOCK_ISTATE() + + // do the restart after two seconds to catch + // following ioctl's (from more params of iwconfig) + // in _one_ restart + mod_timer(&dev->restart_timer, jiffies+2*HZ); + + return 0; +} + +static int at76c503_iw_handler_get_name(struct net_device *netdev, + struct iw_request_info *info, + char *name, + char *extra) +{ + strcpy(name, "IEEE 802.11b"); + + dbg(DBG_IOCTL, "%s: SIOCGIWNAME - name %s", netdev->name, name); + + return 0; +} + +static int at76c503_iw_handler_set_freq(struct net_device *netdev, + struct iw_request_info *info, + struct iw_freq *freq, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int chan = -1; + int ret = -EIWCOMMIT; + + dbg(DBG_IOCTL, "%s: SIOCSIWFREQ - freq.m %d freq.e %d", netdev->name, + freq->m, freq->e); + + // modelled on orinoco.c + if ((freq->e == 0) && (freq->m <= 1000)) + { + // Setting by channel number + chan = freq->m; + } + else + { + // Setting by frequency - search the table + int mult = 1; + int i; + + for (i = 0; i < (6 - freq->e); i++) { + mult *= 10; + } + + for (i = 0; i < NUM_CHANNELS; i++) { + if (freq->m == (channel_frequency[i] * mult)) + chan = i + 1; + } + } + + if (chan < 1 || !dev->domain ) { + // non-positive channels are invalid + // we need a domain info to set the channel + // either that or an invalid frequency was + // provided by the user + ret = -EINVAL; + } else if (!dev->international_roaming) { + if (!(dev->domain->channel_map & (1 << (chan-1)))) { + info("%s: channel %d not allowed for domain %s " + "(and international_roaming is OFF)", + dev->netdev->name, chan, dev->domain->name); + ret = -EINVAL; + } + } + + if (ret == -EIWCOMMIT) { + dev->channel = chan; + dbg(DBG_IOCTL, "%s: SIOCSIWFREQ - ch %d", netdev->name, chan); + } + + return ret; +} + +static int at76c503_iw_handler_get_freq(struct net_device *netdev, + struct iw_request_info *info, + struct iw_freq *freq, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + freq->m = dev->channel; + freq->e = 0; + + if (dev->channel) + { + dbg(DBG_IOCTL, "%s: SIOCGIWFREQ - freq %ld x 10e%d", netdev->name, + channel_frequency[dev->channel - 1], 6); + } + dbg(DBG_IOCTL, "%s: SIOCGIWFREQ - ch %d", netdev->name, dev->channel); + + return 0; +} + +static int at76c503_iw_handler_set_mode(struct net_device *netdev, + struct iw_request_info *info, + __u32 *mode, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret = -EIWCOMMIT; + + dbg(DBG_IOCTL, "%s: SIOCSIWMODE - %d", netdev->name, *mode); + + if ((*mode != IW_MODE_ADHOC) && (*mode != IW_MODE_INFRA) && + (*mode != IW_MODE_MONITOR)) { + ret = -EINVAL; + } else { + dev->iw_mode = *mode; + } + return ret; +} + +static int at76c503_iw_handler_get_mode(struct net_device *netdev, + struct iw_request_info *info, + __u32 *mode, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + *mode = dev->iw_mode; + + dbg(DBG_IOCTL, "%s: SIOCGIWMODE - %d", netdev->name, *mode); + + return 0; +} + +static int at76c503_iw_handler_get_range(struct net_device *netdev, + struct iw_request_info *info, + struct iw_point *data, + char *extra) +{ + // inspired by atmel.c + struct at76c503 *dev = (struct at76c503*)netdev->priv; + struct iw_range *range = (struct iw_range*)extra; + int i; + + data->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + + + //TODO: range->throughput = xxxxxx; + + range->min_nwid = 0x0000; + range->max_nwid = 0x0000; + + // this driver doesn't maintain sensitivity information + range->sensitivity = 0; + + range->max_qual.qual = 100; + range->max_qual.level = 100; + range->max_qual.noise = 0; + range->max_qual.updated = IW_QUAL_NOISE_INVALID; + + range->avg_qual.qual = 50; + range->avg_qual.level = 50; + range->avg_qual.noise = 0; + range->avg_qual.updated = IW_QUAL_NOISE_INVALID; + + range->bitrate[0] = 1000000; + range->bitrate[1] = 2000000; + range->bitrate[2] = 5500000; + range->bitrate[3] = 11000000; + range->num_bitrates = 4; + + + range->min_rts = 0; + range->max_rts = MAX_RTS_THRESHOLD; + + range->min_frag = MIN_FRAG_THRESHOLD; + range->max_frag = MAX_FRAG_THRESHOLD; + + + //range->min_pmp = 0; + //range->max_pmp = 5000000; + //range->min_pmt = 0; + //range->max_pnt = 0; + //range->pmp_flags = IW_POWER_PERIOD; + //range->pmt_flags = 0; + //range->pm_capa = IW_POWER_PERIOD; + //TODO: find out what values we can use to describe PM capabilities + range->pmp_flags = IW_POWER_ON; + range->pmt_flags = IW_POWER_ON; + range->pm_capa = 0; + + + range->encoding_size[0] = WEP_SMALL_KEY_LEN; + range->encoding_size[1] = WEP_LARGE_KEY_LEN; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = WEP_KEYS; + //TODO: do we need this? what is a valid value if we don't support? + //range->encoding_login_index = -1; + + /* both WL-240U and Linksys WUSB11 v2.6 specify 15 dBm as output power + - take this for all (ignore antenna gains) */ + range->txpower[0] = 15; + range->num_txpower = 1; + range->txpower_capa = IW_TXPOW_DBM; + + // at time of writing (22/Feb/2004), version we intend to support + // is v16, + range->we_version_source = WIRELESS_EXT_SUPPORTED; + range->we_version_compiled = WIRELESS_EXT; + + // same as the values used in atmel.c + range->retry_capa = IW_RETRY_LIMIT ; + range->retry_flags = IW_RETRY_LIMIT; + range->r_time_flags = 0; + range->min_retry = 1; + range->max_retry = 255; + + + range->num_channels = NUM_CHANNELS; + range->num_frequency = 0; + + for (i = 0; + i < 32; //number of bits in reg_domain.channel_map + i++) + { + // test if channel map bit is raised + if (dev->domain->channel_map & (0x1 << i)) + { + range->num_frequency += 1; + + range->freq[i].i = i + 1; + range->freq[i].m = channel_frequency[i] * 100000; + range->freq[i].e = 1; // channel frequency*100000 * 10^1 + } + } + + dbg(DBG_IOCTL, "%s: SIOCGIWRANGE", netdev->name); + + return 0; +} + +static int at76c503_iw_handler_set_spy(struct net_device *netdev, + struct iw_request_info *info, + struct iw_point *data, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret = 0; + + dbg(DBG_IOCTL, "%s: SIOCSIWSPY - number of addresses %d", + netdev->name, data->length); + + spin_lock_bh(&(dev->spy_spinlock)); + ret = iw_handler_set_spy(dev->netdev, info, (union iwreq_data *)data, + extra); + spin_unlock_bh(&(dev->spy_spinlock)); + + return ret; +} + +static int at76c503_iw_handler_get_spy(struct net_device *netdev, + struct iw_request_info *info, + struct iw_point *data, + char *extra) +{ + + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret = 0; + + spin_lock_bh(&(dev->spy_spinlock)); + ret = iw_handler_get_spy(dev->netdev, info, + (union iwreq_data *)data, extra); + spin_unlock_bh(&(dev->spy_spinlock)); + + dbg(DBG_IOCTL, "%s: SIOCGIWSPY - number of addresses %d", + netdev->name, data->length); + + return ret; +} + +static int at76c503_iw_handler_set_thrspy(struct net_device *netdev, + struct iw_request_info *info, + struct iw_point *data, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret; + + dbg(DBG_IOCTL, "%s: SIOCSIWTHRSPY - number of addresses %d)", + netdev->name, data->length); + + spin_lock_bh(&(dev->spy_spinlock)); + ret = iw_handler_set_thrspy(netdev, info, (union iwreq_data *)data, + extra); + spin_unlock_bh(&(dev->spy_spinlock)); + + return ret; +} + +static int at76c503_iw_handler_get_thrspy(struct net_device *netdev, + struct iw_request_info *info, + struct iw_point *data, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret; + + spin_lock_bh(&(dev->spy_spinlock)); + ret = iw_handler_get_thrspy(netdev, info, (union iwreq_data *)data, + extra); + spin_unlock_bh(&(dev->spy_spinlock)); + + dbg(DBG_IOCTL, "%s: SIOCGIWTHRSPY - number of addresses %d)", + netdev->name, data->length); + + return ret; +} + +static int at76c503_iw_handler_set_wap(struct net_device *netdev, + struct iw_request_info *info, + struct sockaddr *ap_addr, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + dbg(DBG_IOCTL, "%s: SIOCSIWAP - wap/bssid %s", netdev->name, + mac2str(ap_addr->sa_data)); + + // if the incoming address == ff:ff:ff:ff:ff:ff, the user has + // chosen any or auto AP preference + if (!memcmp(ap_addr->sa_data, bc_addr, ETH_ALEN) + || !memcmp(ap_addr->sa_data, off_addr, ETH_ALEN)) { + dev->wanted_bssid_valid = 0; + } else { + // user wants to set a preferred AP address + dev->wanted_bssid_valid = 1; + memcpy(dev->wanted_bssid, ap_addr->sa_data, ETH_ALEN); + } + + return -EIWCOMMIT; +} + +static int at76c503_iw_handler_get_wap(struct net_device *netdev, + struct iw_request_info *info, + struct sockaddr *ap_addr, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + ap_addr->sa_family = ARPHRD_ETHER; + memcpy(ap_addr->sa_data, dev->bssid, ETH_ALEN); + + dbg(DBG_IOCTL, "%s: SIOCGIWAP - wap/bssid %s", netdev->name, + mac2str(ap_addr->sa_data)); + + return 0; +} + + +static int at76c503_iw_handler_set_scan(struct net_device *netdev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + unsigned long flags; + int ret = 0; +#if WIRELESS_EXT > 19 + struct iw_scan_req *req = NULL; +#endif + + dbg(DBG_IOCTL, "%s: SIOCSIWSCAN", netdev->name); + + if (!netif_running(netdev)) + return -ENETDOWN; + + /* jal: we don't allow "iwlist wlanX scan" while we are + in monitor mode */ + if (dev->iw_mode == IW_MODE_MONITOR) + return -EBUSY; + + /* Timeout old surveys. */ + if ((jiffies - dev->last_survey) > (20 * HZ)) + dev->site_survey_state = SITE_SURVEY_IDLE; + dev->last_survey = jiffies; + + /* Initiate a scan command */ + if (dev->site_survey_state == SITE_SURVEY_IN_PROGRESS) + return -EBUSY; + + dev->site_survey_state = SITE_SURVEY_IN_PROGRESS; + + // stop pending management stuff + del_timer_sync(&(dev->mgmt_timer)); + + spin_lock_irqsave(&(dev->mgmt_spinlock), flags); + if (dev->next_mgmt_bulk) { + kfree(dev->next_mgmt_bulk); + dev->next_mgmt_bulk = NULL; + } + spin_unlock_irqrestore(&(dev->mgmt_spinlock), flags); + + if (netif_running(dev->netdev)) { + // pause network activity + netif_carrier_off(dev->netdev); + netif_stop_queue(dev->netdev); + } +// Try to do passive or active scan if WE asks as. +#if WIRELESS_EXT > 19 + if (wrqu->data.length + && wrqu->data.length == sizeof(struct iw_scan_req)) { + req = (struct iw_scan_req *)extra; + + if (req->scan_type == IW_SCAN_TYPE_PASSIVE) + dev->scan_mode = SCAN_TYPE_PASSIVE; + else if (req->scan_type == IW_SCAN_TYPE_ACTIVE) + dev->scan_mode = SCAN_TYPE_ACTIVE; + + /* Sanity check values? */ + LOCK_ISTATE() + if (req->min_channel_time > 0) { + if (dev->istate == MONITORING) + dev->monitor_scan_min_time = req->min_channel_time; + else + dev->scan_min_time = req->min_channel_time; + } + if (req->max_channel_time > 0) { + if (dev->istate == MONITORING) + dev->monitor_scan_max_time = req->max_channel_time; + else + dev->scan_max_time = req->max_channel_time; + } + UNLOCK_ISTATE() + } +#endif + + // change to scanning state + NEW_STATE(dev, SCANNING); + defer_kevent(dev, KEVENT_SCAN); + + return ret; +} + +static int at76c503_iw_handler_get_scan(struct net_device *netdev, + struct iw_request_info *info, + struct iw_point *data, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + unsigned long flags; + struct list_head *lptr, *nptr; + struct bss_info *curr_bss; + struct iw_event *iwe = kmalloc(sizeof(struct iw_event), GFP_KERNEL); + char *curr_val, *curr_pos = extra; + int i; + + dbg(DBG_IOCTL, "%s: SIOCGIWSCAN", netdev->name); + + if (!iwe) + return -ENOMEM; + + if (dev->site_survey_state != SITE_SURVEY_COMPLETED) + /* scan not yet finished */ + return -EAGAIN; + + spin_lock_irqsave(&(dev->bss_list_spinlock), flags); + + list_for_each_safe(lptr, nptr, &(dev->bss_list)) { + curr_bss = list_entry(lptr, struct bss_info, list); + + iwe->cmd = SIOCGIWAP; + iwe->u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe->u.ap_addr.sa_data, curr_bss->bssid, 6); + curr_pos = iwe_stream_add_event(info, curr_pos, + extra + IW_SCAN_MAX_DATA, iwe, IW_EV_ADDR_LEN); + + iwe->u.data.length = curr_bss->ssid_len; + iwe->cmd = SIOCGIWESSID; + iwe->u.data.flags = 1; + + curr_pos = iwe_stream_add_point(info, curr_pos, + extra + IW_SCAN_MAX_DATA, iwe, curr_bss->ssid); + + iwe->cmd = SIOCGIWMODE; + iwe->u.mode = (curr_bss->capa & WLAN_CAPABILITY_IBSS) ? + IW_MODE_ADHOC : + (curr_bss->capa & WLAN_CAPABILITY_ESS) ? + IW_MODE_MASTER : + IW_MODE_AUTO; + // IW_MODE_AUTO = 0 which I thought is + // the most logical value to return in this case + curr_pos = iwe_stream_add_event(info, curr_pos, + extra + IW_SCAN_MAX_DATA, iwe, IW_EV_UINT_LEN); + + iwe->cmd = SIOCGIWFREQ; + iwe->u.freq.m = curr_bss->channel; + iwe->u.freq.e = 0; + curr_pos = iwe_stream_add_event(info, curr_pos, + extra + IW_SCAN_MAX_DATA, iwe, IW_EV_FREQ_LEN); + + iwe->cmd = SIOCGIWENCODE; + if (curr_bss->capa & WLAN_CAPABILITY_PRIVACY) { + iwe->u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + } else { + iwe->u.data.flags = IW_ENCODE_DISABLED; + } + iwe->u.data.length = 0; + curr_pos = iwe_stream_add_point(info, curr_pos, + extra + IW_SCAN_MAX_DATA, iwe, NULL); + + /* Add quality statistics */ + iwe->cmd = IWEVQUAL; + iwe->u.qual.noise=0; + iwe->u.qual.updated=IW_QUAL_NOISE_INVALID | IW_QUAL_LEVEL_UPDATED; + iwe->u.qual.level = (curr_bss->rssi * 100 / 42); + if (iwe->u.qual.level > 100) + iwe->u.qual.level = 100; + if((dev->board_type == BOARDTYPE_503_INTERSIL_3861) || + (dev->board_type == BOARDTYPE_503_INTERSIL_3863)) { + iwe->u.qual.qual=curr_bss->link_qual; + } else { + iwe->u.qual.qual=0; + iwe->u.qual.updated |= IW_QUAL_QUAL_INVALID; + } + /* Add new value to event */ + curr_pos = iwe_stream_add_event(info, curr_pos, + extra + IW_SCAN_MAX_DATA, iwe, IW_EV_QUAL_LEN); + + /* Rate : stuffing multiple values in a single event require a bit + * more of magic - Jean II */ + curr_val = curr_pos + IW_EV_LCP_LEN; + + iwe->cmd = SIOCGIWRATE; + /* Those two flags are ignored... */ + iwe->u.bitrate.fixed = iwe->u.bitrate.disabled = 0; + /* Max 8 values */ + for(i=0; i < curr_bss->rates_len; i++) { + /* Bit rate given in 500 kb/s units (+ 0x80) */ + iwe->u.bitrate.value = + ((curr_bss->rates[i] & 0x7f) * 500000); + /* Add new value to event */ + curr_val = iwe_stream_add_value(info, curr_pos, curr_val, + extra + IW_SCAN_MAX_DATA, + iwe, IW_EV_PARAM_LEN); + } + + /* Check if we added any event */ + if ((curr_val - curr_pos) > IW_EV_LCP_LEN) + curr_pos = curr_val; + + + // more information may be sent back using IWECUSTOM + + } + + spin_unlock_irqrestore(&(dev->bss_list_spinlock), flags); + + data->length = (curr_pos - extra); + data->flags = 0; + + kfree(iwe); + return 0; +} + + +static int at76c503_iw_handler_set_essid(struct net_device *netdev, + struct iw_request_info *info, + struct iw_point *data, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + dbg(DBG_IOCTL, "%s: SIOCSIWESSID - %s", netdev->name, extra); + + if (data->flags) + { + memcpy(dev->essid, extra, data->length); + dev->essid_size = data->length; +#if WIRELESS_EXT < 21 + /* For historic reasons, the SSID length used to include one + * extra character, C string nul termination, even though SSID is + * really an octet string that should not be presented as a C + * string. WE-21 changes this to explicitly require the length + * _not_ to include nul termination, but for WE < 21, decrement + * the length count here to remove the nul termination. */ + dev->essid_size = max(dev->essid_size - 1, 0); +#endif + } + else + { + /* Use any SSID */ + dev->essid_size = 0; + } + + return -EIWCOMMIT; +} + +static int at76c503_iw_handler_get_essid(struct net_device *netdev, + struct iw_request_info *info, + struct iw_point *data, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + if (dev->essid_size) { + // not the ANY ssid in dev->essid + data->flags = 1; + data->length = dev->essid_size; + memcpy(extra, dev->essid, data->length); + extra[data->length] = '\0'; + data->length += 1; + } else { + // the ANY ssid was specified + LOCK_ISTATE() + if (dev->istate == CONNECTED && + dev->curr_bss != NULL) { + UNLOCK_ISTATE() + // report the SSID we have found + data->flags = 1; + data->length = dev->curr_bss->ssid_len; + memcpy(extra, dev->curr_bss->ssid, data->length); + extra[dev->curr_bss->ssid_len] = '\0'; + data->length += 1; + } else { + UNLOCK_ISTATE() + // report ANY back + data->flags=0; + data->length=0; + } + } + + dbg(DBG_IOCTL, "%s: SIOCGIWESSID - %s", netdev->name, extra); + + return 0; +} + +static int at76c503_iw_handler_set_nickname(struct net_device *netdev, + struct iw_request_info *info, + struct iw_point *data, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + dbg(DBG_IOCTL, "%s: SIOCSIWNICKN - %s", netdev->name, extra); + + // iwconfig gives length including 0 byte like in the case of essid + memcpy(dev->nickn, extra, data->length); + + return 0; +} + +static int at76c503_iw_handler_get_nickname(struct net_device *netdev, + struct iw_request_info *info, + struct iw_point *data, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + data->length = strlen(dev->nickn); + memcpy(extra, dev->nickn, data->length); + extra[data->length] = '\0'; + data->length += 1; + + dbg(DBG_IOCTL, "%s: SIOCGIWNICKN - %s", netdev->name, extra); + + return 0; +} + +static int at76c503_iw_handler_set_rate(struct net_device *netdev, + struct iw_request_info *info, + struct iw_param *bitrate, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret = -EIWCOMMIT; + + dbg(DBG_IOCTL, "%s: SIOCSIWRATE - %d", netdev->name, + bitrate->value); + + switch (bitrate->value) + { + case -1: dev->txrate = TX_RATE_AUTO; break; // auto rate + case 1000000: dev->txrate = TX_RATE_1MBIT; break; + case 2000000: dev->txrate = TX_RATE_2MBIT; break; + case 5500000: dev->txrate = TX_RATE_5_5MBIT; break; + case 11000000: dev->txrate = TX_RATE_11MBIT; break; + default: ret = -EINVAL; + } + + return ret; +} + +static int at76c503_iw_handler_get_rate(struct net_device *netdev, + struct iw_request_info *info, + struct iw_param *bitrate, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret = 0; + + switch (dev->txrate) + { + // return max rate if RATE_AUTO + case TX_RATE_AUTO: bitrate->value = 11000000; break; + case TX_RATE_1MBIT: bitrate->value = 1000000; break; + case TX_RATE_2MBIT: bitrate->value = 2000000; break; + case TX_RATE_5_5MBIT: bitrate->value = 5500000; break; + case TX_RATE_11MBIT: bitrate->value = 11000000; break; + default: ret = -EINVAL; + } + + bitrate->fixed = (dev->txrate != TX_RATE_AUTO); + bitrate->disabled = 0; + + dbg(DBG_IOCTL, "%s: SIOCGIWRATE - %d", netdev->name, + bitrate->value); + + return ret; +} + +static int at76c503_iw_handler_set_rts(struct net_device *netdev, + struct iw_request_info *info, + struct iw_param *rts, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret = -EIWCOMMIT; + int rthr = rts->value; + + dbg(DBG_IOCTL, "%s: SIOCSIWRTS - value %d disabled %s", + netdev->name, rts->value, + (rts->disabled) ? "true" : "false"); + + if (rts->disabled) + rthr = MAX_RTS_THRESHOLD; + + if ((rthr < 0) || (rthr > MAX_RTS_THRESHOLD)) { + ret = -EINVAL; + } else { + dev->rts_threshold = rthr; + } + + return ret; +} + +static int at76c503_iw_handler_get_rts(struct net_device *netdev, + struct iw_request_info *info, + struct iw_param *rts, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + rts->value = dev->rts_threshold; + rts->disabled = (rts->value >= MAX_RTS_THRESHOLD); + rts->fixed = 1; + + dbg(DBG_IOCTL, "%s: SIOCGIWRTS - value %d disabled %s", + netdev->name, rts->value, + (rts->disabled) ? "true" : "false"); + + return 0; +} + +static int at76c503_iw_handler_set_frag(struct net_device *netdev, + struct iw_request_info *info, + struct iw_param *frag, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret = -EIWCOMMIT; + int fthr = frag->value; + + dbg(DBG_IOCTL, "%s: SIOCSIWFRAG - value %d, disabled %s", + netdev->name, frag->value, + (frag->disabled) ? "true" : "false"); + + if(frag->disabled) + fthr = MAX_FRAG_THRESHOLD; + + if ((fthr < MIN_FRAG_THRESHOLD) || (fthr > MAX_FRAG_THRESHOLD)) { + ret = -EINVAL; + } else { + dev->frag_threshold = fthr & ~0x1; // get an even value + } + + return ret; +} + +static int at76c503_iw_handler_get_frag(struct net_device *netdev, + struct iw_request_info *info, + struct iw_param *frag, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + frag->value = dev->frag_threshold; + frag->disabled = (frag->value >= MAX_FRAG_THRESHOLD); + frag->fixed = 1; + + dbg(DBG_IOCTL, "%s: SIOCGIWFRAG - value %d, disabled %s", + netdev->name, frag->value, + (frag->disabled) ? "true" : "false"); + + return 0; +} + +static int at76c503_iw_handler_get_txpow(struct net_device *netdev, + struct iw_request_info *info, + struct iw_param *power, + char *extra) +{ + power->value = 15; + power->fixed = 1; /* No power control */ + power->disabled = 0; + power->flags = IW_TXPOW_DBM; + + dbg(DBG_IOCTL, "%s: SIOCGIWTXPOW - txpow %d dBm", netdev->name, + power->value); + + return 0; +} + +/* jal: short retry is handled by the firmware (at least 0.90.x), + while long retry is not (?) */ +static int at76c503_iw_handler_set_retry(struct net_device *netdev, + struct iw_request_info *info, + struct iw_param *retry, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret = -EIWCOMMIT; + + dbg(DBG_IOCTL, "%s: SIOCSIWRETRY disabled %d flags x%x val %d", + netdev->name, retry->disabled, retry->flags, retry->value); + + if(!retry->disabled && (retry->flags & IW_RETRY_LIMIT)) { + if ((retry->flags & IW_RETRY_MIN) || + !(retry->flags & IW_RETRY_MAX)) { + dev->short_retry_limit = retry->value; + } else + ret = -EINVAL; + } else { + ret = -EINVAL; + } + + return ret; +} + +// adapted (ripped) from atmel.c +static int at76c503_iw_handler_get_retry(struct net_device *netdev, + struct iw_request_info *info, + struct iw_param *retry, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + dbg(DBG_IOCTL, "%s: SIOCGIWRETRY", netdev->name); + + retry->disabled = 0; // Can't be disabled + + // Note : by default, display the min retry number + //if((retry->flags & IW_RETRY_MAX)) { + // retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + // retry->value = dev->long_retry_limit; + //} else { + retry->flags = IW_RETRY_LIMIT; + retry->value = dev->short_retry_limit; + + //if(dev->long_retry_limit != dev->short_retry_limit) { + // dev->retry.flags |= IW_RETRY_MIN; + //} + //} + + return 0; +} + +static int at76c503_iw_handler_set_encode(struct net_device *netdev, + struct iw_request_info *info, + struct iw_point *encoding, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int index = (encoding->flags & IW_ENCODE_INDEX) - 1; + int len = encoding->length; + + dbg(DBG_IOCTL, "%s: SIOCSIWENCODE - enc.flags %08x " + "pointer %p len %d", netdev->name, encoding->flags, + encoding->pointer, encoding->length); + dbg(DBG_IOCTL, "%s: SIOCSIWENCODE - old wepstate: enabled %s key_id %d " + "auth_mode %s", + netdev->name, (dev->wep_enabled) ? "true" : "false", + dev->wep_key_id, + (dev->auth_mode == WLAN_AUTH_SHARED_KEY) ? + "restricted" : "open"); + + // take the old default key if index is invalid + if ((index < 0) || (index >= WEP_KEYS)) + index = dev->wep_key_id; + + if (len > 0) + { + if (len > WEP_LARGE_KEY_LEN) + len = WEP_LARGE_KEY_LEN; + + memset(dev->wep_keys[index], 0, WEP_KEY_LEN); + memcpy(dev->wep_keys[index], extra, len); + dev->wep_keys_len[index] = (len <= WEP_SMALL_KEY_LEN) ? + WEP_SMALL_KEY_LEN : WEP_LARGE_KEY_LEN; + dev->wep_enabled = 1; + } + + dev->wep_key_id = index; + dev->wep_enabled = ((encoding->flags & IW_ENCODE_DISABLED) == 0); + + if (encoding->flags & IW_ENCODE_RESTRICTED) + dev->auth_mode = WLAN_AUTH_SHARED_KEY; + if (encoding->flags & IW_ENCODE_OPEN) + dev->auth_mode = WLAN_AUTH_OPEN; + + dbg(DBG_IOCTL, "%s: SIOCSIWENCODE - new wepstate: enabled %s key_id %d " + "key_len %d auth_mode %s", + netdev->name, (dev->wep_enabled) ? "true" : "false", + dev->wep_key_id + 1, dev->wep_keys_len[dev->wep_key_id], + (dev->auth_mode == WLAN_AUTH_SHARED_KEY) ? + "restricted" : "open"); + + return -EIWCOMMIT; +} + +static int at76c503_iw_handler_get_encode(struct net_device *netdev, + struct iw_request_info *info, + struct iw_point *encoding, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int index = (encoding->flags & IW_ENCODE_INDEX) - 1; + + if ((index < 0) || (index >= WEP_KEYS)) + index = dev->wep_key_id; + + encoding->flags = + (dev->auth_mode == WLAN_AUTH_SHARED_KEY) ? + IW_ENCODE_RESTRICTED : IW_ENCODE_OPEN; + + if (!dev->wep_enabled) + encoding->flags |= IW_ENCODE_DISABLED; + + if (encoding->pointer) + { + encoding->length = dev->wep_keys_len[index]; + + memcpy(extra, dev->wep_keys[index], dev->wep_keys_len[index]); + + encoding->flags |= (index + 1); + } + + dbg(DBG_IOCTL, "%s: SIOCGIWENCODE - enc.flags %08x " + "pointer %p len %d", netdev->name, encoding->flags, + encoding->pointer, encoding->length); + dbg(DBG_IOCTL, "%s: SIOCGIWENCODE - wepstate: enabled %s key_id %d " + "key_len %d auth_mode %s", + netdev->name, (dev->wep_enabled) ? "true" : "false", + dev->wep_key_id + 1, dev->wep_keys_len[dev->wep_key_id], + (dev->auth_mode == WLAN_AUTH_SHARED_KEY) ? + "restricted" : "open"); + + return 0; +} + +static int at76c503_iw_handler_set_power(struct net_device *netdev, + struct iw_request_info *info, + struct iw_param *power, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + dbg(DBG_IOCTL, "%s: SIOCSIWPOWER - disabled %s flags x%x value x%x", + netdev->name, (power->disabled) ? "true" : "false", + power->flags, power->value); + + if (power->disabled) + { + dev->pm_mode = PM_ACTIVE; + } + else + { + // we set the listen_interval based on the period given + // no idea how to handle the timeout of iwconfig ??? + if (power->flags & IW_POWER_PERIOD) + { + dev->pm_period_us = power->value; + } + + dev->pm_mode = PM_SAVE; // use iw_priv to select SMART_SAVE + } + + return -EIWCOMMIT; +} + +static int at76c503_iw_handler_get_power(struct net_device *netdev, + struct iw_request_info *info, + struct iw_param *power, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + power->disabled = dev->pm_mode == PM_ACTIVE; + + if ((power->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) + { + power->flags = IW_POWER_TIMEOUT; + power->value = 0; + } + else + { + unsigned long flags; + u16 beacon_int; // of the current bss + + power->flags = IW_POWER_PERIOD; + + spin_lock_irqsave(&dev->bss_list_spinlock, flags); + beacon_int = dev->curr_bss != NULL ? + dev->curr_bss->beacon_interval : 0; + spin_unlock_irqrestore(&dev->bss_list_spinlock, flags); + + if (beacon_int != 0) + { + power->value = + (beacon_int * dev->pm_period_beacon) << 10; + } + else + { + power->value = dev->pm_period_us; + } + } + + power->flags |= IW_POWER_ALL_R; + + dbg(DBG_IOCTL, "%s: SIOCGIWPOWER - disabled %s flags x%x value x%x", + netdev->name, (power->disabled) ? "true" : "false", + power->flags, power->value); + + return 0; +} + + +/******************************************************************************* + * Private IOCTLS + */ +static int at76c503_iw_handler_PRIV_IOCTL_SET_SHORT_PREAMBLE + (struct net_device *netdev, struct iw_request_info *info, + char *name, char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int val = *((int *)name); + int ret = -EIWCOMMIT; + + dbg(DBG_IOCTL, "%s: PRIV_IOCTL_SET_SHORT_PREAMBLE, %d", + netdev->name, val); + + if (val < 0 || val > 2) { + //allow value of 2 - in the win98 driver it stands + //for "auto preamble" ...? + ret = -EINVAL; + } else { + dev->preamble_type = val; + } + + return ret; +} + +static int at76c503_iw_handler_PRIV_IOCTL_SET_DEBUG + (struct net_device *netdev, struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + char *ptr; + u32 val; + + if (data->length > 0) { + val = simple_strtol(extra, &ptr, 0); + + if (ptr == extra) { + val = DBG_DEFAULTS; + } + + dbg_uc("%s: PRIV_IOCTL_SET_DEBUG input %d: %s -> x%x", + netdev->name, data->length, extra, val); + } else { + val = DBG_DEFAULTS; + } + + dbg_uc("%s: PRIV_IOCTL_SET_DEBUG, old 0x%x new 0x%x", + netdev->name, at76_debug, val); + + /* jal: some more output to pin down lockups */ + dbg_uc("%s: netif running %d queue_stopped %d carrier_ok %d", + netdev->name, + netif_running(netdev), + netif_queue_stopped(netdev), + netif_carrier_ok(netdev)); + + at76_debug = val; + + return 0; +} + +static int at76c503_iw_handler_PRIV_IOCTL_SET_POWERSAVE_MODE + (struct net_device *netdev, struct iw_request_info *info, + char *name, char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int val = *((int *)name); + int ret = -EIWCOMMIT; + + dbg(DBG_IOCTL, "%s: PRIV_IOCTL_SET_POWERSAVE_MODE, %d (%s)", + netdev->name, val, + val == PM_ACTIVE ? "active" : val == PM_SAVE ? "save" : + val == PM_SMART_SAVE ? "smart save" : ""); + if (val < PM_ACTIVE || val > PM_SMART_SAVE) { + ret = -EINVAL; + } else { + dev->pm_mode = val; + } + + return ret; +} + +static int at76c503_iw_handler_PRIV_IOCTL_SET_SCAN_TIMES + (struct net_device *netdev, struct iw_request_info *info, + char *name, char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int mint = *((int *)name); + int maxt = *((int *)name + 1); + int ret = -EIWCOMMIT; + + dbg(DBG_IOCTL, "%s: PRIV_IOCTL_SET_SCAN_TIMES - min %d max %d", + netdev->name, mint, maxt); + if (mint <= 0 || maxt <= 0 || mint > maxt) { + ret = -EINVAL; + } else { + LOCK_ISTATE() + if (dev->istate == MONITORING) { + dev->monitor_scan_min_time = mint; + dev->monitor_scan_max_time = maxt; + ret = 0; + } else { + dev->scan_min_time = mint; + dev->scan_max_time = maxt; + } + UNLOCK_ISTATE() + } + + return ret; +} + +static int at76c503_iw_handler_PRIV_IOCTL_SET_SCAN_MODE + (struct net_device *netdev, struct iw_request_info *info, + char *name, char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int val = *((int *)name); + int ret = -EIWCOMMIT; + + dbg(DBG_IOCTL, "%s: PRIV_IOCTL_SET_SCAN_MODE - mode %s", + netdev->name, (val = SCAN_TYPE_ACTIVE) ? "active" : + (val = SCAN_TYPE_PASSIVE) ? "passive" : ""); + + if (val != SCAN_TYPE_ACTIVE && val != SCAN_TYPE_PASSIVE) { + ret = -EINVAL; + } else { + dev->scan_mode = val; + } + + return ret; +} + +static int set_iroaming(struct at76c503 *dev, int onoff) +{ + int ret = 0; + + memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer)); + dev->mib_buf.type = MIB_MAC_MGMT; + dev->mib_buf.size = 1; + dev->mib_buf.index = IROAMING_OFFSET; + dev->mib_buf.data[0] = (dev->international_roaming ? 1 : 0); + ret = set_mib(dev, &dev->mib_buf); + if(ret < 0){ + err("%s: set_mib (intl_roaming_enable) failed: %d", dev->netdev->name, ret); + } + + return ret; +} + +static int at76c503_iw_handler_PRIV_IOCTL_SET_INTL_ROAMING + (struct net_device *netdev, struct iw_request_info *info, + char *name, char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int val = *((int *)name); + int ret = -EIWCOMMIT; + + dbg(DBG_IOCTL, "%s: PRIV_IOCTL_SET_INTL_ROAMING - mode %s", + netdev->name, (val == IR_OFF) ? "off" : + (val == IR_ON) ? "on" : ""); + + if (val != IR_OFF && val != IR_ON) { + ret = -EINVAL; + } else { + if (dev->international_roaming != val) { + dev->international_roaming = val; + set_iroaming(dev, val); + } + } + + return ret; +} + +/* == PROC set_monitor_mode == + sets dev->netdev->type */ +static void set_monitor_mode(struct at76c503 *dev, int use_prism) +{ + if (dev->iw_mode == IW_MODE_MONITOR) { + if (use_prism) { + dbg(DBG_MONITOR_MODE, "%s: MONITOR MODE ON: " + "Prism headers ARE used", dev->netdev->name); + dev->netdev->type = ARPHRD_IEEE80211_PRISM; + } else { + dbg(DBG_MONITOR_MODE, "%s: MONITOR MODE ON: " + "Prism headers NOT used", dev->netdev->name); + dev->netdev->type = ARPHRD_IEEE80211; + } + } else { + dbg(DBG_MONITOR_MODE, "%s: MONITOR MODE OFF", + dev->netdev->name); + dev->netdev->type = ARPHRD_ETHER; + } +} /* set_monitor_mode */ + +static int at76c503_iw_handler_PRIV_IOCTL_SET_MONITOR_MODE + (struct net_device *netdev, struct iw_request_info *info, + char *name, char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int *params = ((int *)name); + int mode = params[0]; + int channel = params[1]; + int ret = 0; + + dbg(DBG_IOCTL, "%s: PRIV_IOCTL_SET_MONITOR_MODE - mode %d ch %d", + netdev->name, mode, channel); + + if (mode != MM_OFF && mode != MM_ON && mode != MM_ON_NO_PRISM) + ret = -EINVAL; + else { + if (mode != MM_OFF) { + if ((channel >= 1) && + (channel <= (sizeof(channel_frequency) / + sizeof(channel_frequency[0])))) + // INFO: This doesn't actually affect the scan + dev->channel = channel; + + dev->monitor_prism_header = (mode == MM_ON); + + if (dev->iw_mode != IW_MODE_MONITOR) { + ret = -EIWCOMMIT; + dev->iw_mode = IW_MODE_MONITOR; + } + } else { + /* mode == MM_OFF */ + if (dev->iw_mode == IW_MODE_MONITOR) { + ret = -EIWCOMMIT; + dev->iw_mode = IW_MODE_INFRA; + } + } + set_monitor_mode(dev, dev->monitor_prism_header); + } + + return ret; +} + +/******************************************************************************* + * structure that advertises the iw handlers of this driver + */ +static const iw_handler at76c503_handlers[] = +{ + [SIOCSIWCOMMIT-SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_commit, + [SIOCGIWNAME -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_get_name, + [SIOCSIWFREQ -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_set_freq, + [SIOCGIWFREQ -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_get_freq, + [SIOCSIWMODE -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_set_mode, + [SIOCGIWMODE -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_get_mode, + [SIOCGIWRANGE -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_get_range, + [SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_set_spy, + [SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_get_spy, + [SIOCSIWTHRSPY-SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_set_thrspy, + [SIOCGIWTHRSPY-SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_get_thrspy, + [SIOCSIWAP -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_set_wap, + [SIOCGIWAP -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_get_wap, + [SIOCSIWSCAN -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_set_scan, + [SIOCGIWSCAN -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_get_scan, + [SIOCSIWESSID -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_set_essid, + [SIOCGIWESSID -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_get_essid, + [SIOCSIWNICKN -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_set_nickname, + [SIOCGIWNICKN -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_get_nickname, + [SIOCSIWRATE -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_set_rate, + [SIOCGIWRATE -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_get_rate, + [SIOCSIWRTS -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_set_rts, + [SIOCGIWRTS -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_get_rts, + [SIOCSIWFRAG -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_set_frag, + [SIOCGIWFRAG -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_get_frag, + [SIOCGIWTXPOW -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_get_txpow, + [SIOCGIWRETRY -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_set_retry, + [SIOCGIWRETRY -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_get_retry, + [SIOCSIWENCODE-SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_set_encode, + [SIOCGIWENCODE-SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_get_encode, + [SIOCSIWPOWER -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_set_power, + [SIOCGIWPOWER -SIOCIWFIRST] = (iw_handler) at76c503_iw_handler_get_power, +}; + +/******************************************************************************* + * structure that advertises the private iw handlers of this driver + */ +static const iw_handler at76c503_priv_handlers[] = +{ + (iw_handler) at76c503_iw_handler_PRIV_IOCTL_SET_SHORT_PREAMBLE, + (iw_handler) NULL, + (iw_handler) at76c503_iw_handler_PRIV_IOCTL_SET_DEBUG, + (iw_handler) NULL, + (iw_handler) at76c503_iw_handler_PRIV_IOCTL_SET_POWERSAVE_MODE, + (iw_handler) NULL, + (iw_handler) at76c503_iw_handler_PRIV_IOCTL_SET_SCAN_TIMES, + (iw_handler) NULL, + (iw_handler) at76c503_iw_handler_PRIV_IOCTL_SET_SCAN_MODE, + (iw_handler) NULL, + (iw_handler) at76c503_iw_handler_PRIV_IOCTL_SET_INTL_ROAMING, + (iw_handler) NULL, + (iw_handler) at76c503_iw_handler_PRIV_IOCTL_SET_MONITOR_MODE, + (iw_handler) NULL, +}; + +static const struct iw_handler_def at76c503_handler_def = +{ + .num_standard = sizeof(at76c503_handlers)/sizeof(iw_handler), + .num_private = sizeof(at76c503_priv_handlers)/sizeof(iw_handler), + .num_private_args = sizeof(at76c503_priv_args)/ + sizeof(struct iw_priv_args), + .standard = (iw_handler *) at76c503_handlers, + .private = (iw_handler *) at76c503_priv_handlers, + .private_args = (struct iw_priv_args *) at76c503_priv_args, +#if WIRELESS_EXT > 16 + .get_wireless_stats = at76c503_get_wireless_stats, +#endif +#if WIRELESS_EXT == 15 || WIRELESS_EXT == 16 + .spy_offset = offsetof(struct at76c503, spy_data), +#endif +}; + + +static void at76c503_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *info) +{ + struct at76c503 *dev = (struct at76c503 *)netdev->priv; + + strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1); + + strncpy(info->version, DRIVER_VERSION, sizeof(info->version)); + info->version[sizeof(info->version)-1] = '\0'; + + snprintf(info->bus_info, sizeof(info->bus_info) - 1, "usb%d:%d", + dev->udev->bus->busnum, dev->udev->devnum); + + snprintf(info->fw_version, sizeof(info->fw_version) - 1, + "%d.%d.%d-%d", + dev->fw_version.major, dev->fw_version.minor, + dev->fw_version.patch, dev->fw_version.build); +} + +static struct ethtool_ops at76c503_ethtool_ops = { + .get_drvinfo = at76c503_get_drvinfo, +}; + + +static void at76c503_delete_device(struct at76c503 *dev) +{ + int i; + + if (!dev) + return; + + /* signal to _stop() that the device is gone */ + dev->device_unplugged = 1; + + dbg(DBG_PROC_ENTRY, "%s: ENTER",__FUNCTION__); + + if (dev->netdev_registered) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) + if (down_trylock(&rtnl_sem) != 0) { +#else + if (rtnl_trylock() == 0) { +#endif + info("%s: rtnl_sem already down'ed", __FUNCTION__); + } else { + /* synchronously calls at76c503_stop() */ + unregister_netdevice(dev->netdev); + rtnl_unlock(); + } + } + + PUT_DEV(dev->udev); + + // assuming we used keventd, it must quiesce too + flush_scheduled_work (); + + if(dev->bulk_out_buffer != NULL) + kfree(dev->bulk_out_buffer); + + kfree(dev->ctrl_buffer); + + if(dev->write_urb != NULL) { + usb_kill_urb(dev->write_urb); + usb_free_urb(dev->write_urb); + } + if(dev->read_urb != NULL) { + usb_kill_urb(dev->read_urb); + usb_free_urb(dev->read_urb); + } + if(dev->ctrl_buffer != NULL) { + usb_kill_urb(dev->ctrl_urb); + usb_free_urb(dev->ctrl_urb); + } + + dbg(DBG_PROC_ENTRY,"%s: unlinked urbs",__FUNCTION__); + + if(dev->rx_skb != NULL) + kfree_skb(dev->rx_skb); + + free_bss_list(dev); + del_timer_sync(&dev->bss_list_timer); + + LOCK_ISTATE() + if (dev->istate == CONNECTED) { + UNLOCK_ISTATE() + iwevent_bss_disconnect(dev->netdev); + } else UNLOCK_ISTATE() + + for(i=0; i < NR_RX_DATA_BUF; i++) + if (dev->rx_data[i].skb != NULL) { + dev_kfree_skb(dev->rx_data[i].skb); + dev->rx_data[i].skb = NULL; + } + dbg(DBG_PROC_ENTRY, "%s: before freeing dev/netdev", __FUNCTION__); + free_netdev(dev->netdev); /* dev is in net_dev */ +#ifdef CONFIG_IPAQ_HANDHELD + if (machine_is_h5400()) { + ipaq_led_off (RED_LED); + ipaq_led_off (RED_LED_2); + } +#endif + dbg(DBG_PROC_ENTRY, "%s: EXIT", __FUNCTION__); +} + +static int at76c503_alloc_urbs(struct at76c503 *dev) +{ + struct usb_interface *interface = dev->interface; +// struct usb_host_interface *iface_desc = &interface->altsetting[0]; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev = dev->udev; + int i, buffer_size; + + dbg(DBG_PROC_ENTRY, "%s: ENTER", __FUNCTION__); + + dbg(DBG_URB, "%s: NumEndpoints %d ", __FUNCTION__, NUM_EP(interface)); + + for(i = 0; i < NUM_EP(interface); i++) { + endpoint = &EP(interface,i); + + dbg(DBG_URB, "%s: %d. endpoint: addr x%x attr x%x", + __FUNCTION__, + i, + endpoint->bEndpointAddress, + endpoint->bmAttributes); + + if ((endpoint->bEndpointAddress & 0x80) && + ((endpoint->bmAttributes & 3) == 0x02)) { + /* we found a bulk in endpoint */ + + dev->read_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->read_urb) { + err("No free urbs available"); + return -1; + } + dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; + } + + if (((endpoint->bEndpointAddress & 0x80) == 0x00) && + ((endpoint->bmAttributes & 3) == 0x02)) { + /* we found a bulk out endpoint */ + dev->write_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->write_urb) { + err("no free urbs available"); + return -1; + } + buffer_size = sizeof(struct at76c503_tx_buffer) + + MAX_PADDING_SIZE; + dev->bulk_out_size = buffer_size; + dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; + dev->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL); + if (!dev->bulk_out_buffer) { + err("couldn't allocate bulk_out_buffer"); + return -1; + } + FILL_BULK_URB(dev->write_urb, udev, + usb_sndbulkpipe(udev, + endpoint->bEndpointAddress), + dev->bulk_out_buffer, buffer_size, + (usb_complete_t)at76c503_write_bulk_callback, dev); + } + } + + dev->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->ctrl_urb) { + err("no free urbs available"); + return -1; + } + dev->ctrl_buffer = kmalloc(1024, GFP_KERNEL); + if (!dev->ctrl_buffer) { + err("couldn't allocate ctrl_buffer"); + return -1; + } + + dbg(DBG_PROC_ENTRY, "%s: EXIT", __FUNCTION__); + + return 0; +} + +static struct at76c503 *alloc_new_device(struct usb_device *udev, + int board_type, + const char *netdev_name) +{ + struct net_device *netdev; + struct at76c503 *dev = NULL; + int i; + + /* allocate memory for our device state and initialize it */ + netdev = alloc_etherdev(sizeof(struct at76c503)); + if (netdev == NULL) { + err("out of memory"); + return NULL; + } + + dev = (struct at76c503 *)netdev->priv; + memset(dev, 0, sizeof(*dev)); + + dev->udev = udev; + dev->netdev = netdev; + + init_MUTEX (&dev->sem); + INIT_WORK (&dev->kevent, kevent); + + dev->open_count = 0; + + init_timer(&dev->restart_timer); + dev->restart_timer.data = (unsigned long)dev; + dev->restart_timer.function = restart_timeout; + + init_timer(&dev->mgmt_timer); + dev->mgmt_timer.data = (unsigned long)dev; + dev->mgmt_timer.function = mgmt_timeout; + + init_timer(&dev->fw_dl_timer); + dev->fw_dl_timer.data = (unsigned long)dev; + dev->fw_dl_timer.function = fw_dl_timeout; + + + spin_lock_init(&dev->mgmt_spinlock); + spin_lock_init(&dev->istate_spinlock); + dev->next_mgmt_bulk = NULL; + dev->istate = INTFW_DOWNLOAD; + + /* initialize empty BSS list */ + dev->curr_bss = dev->new_bss = NULL; + INIT_LIST_HEAD(&dev->bss_list); + spin_lock_init(&dev->bss_list_spinlock); + + init_timer(&dev->bss_list_timer); + dev->bss_list_timer.data = (unsigned long)dev; + dev->bss_list_timer.function = bss_list_timeout; + + spin_lock_init(&dev->spy_spinlock); + + /* mark all rx data entries as unused */ + for(i=0; i < NR_RX_DATA_BUF; i++) + dev->rx_data[i].skb = NULL; + + dev->tasklet.func = rx_tasklet; + dev->tasklet.data = (unsigned long)dev; + + dev->board_type = board_type; + + dev->pm_mode = pm_mode; + dev->pm_period_us = pm_period; + + dev_alloc_name(netdev, netdev_name); + + return dev; +} /* alloc_new_device */ + +/* == PROC init_new_device == + firmware got downloaded, we can continue with init */ +/* We may have to move the register_netdev into alloc_new_device, + because hotplug may try to configure the netdev _before_ + (or parallel to) the download of firmware */ +static int init_new_device(struct at76c503 *dev) +{ + struct net_device *netdev = dev->netdev; + int ret; + + /* set up the endpoint information */ + /* check out the endpoints */ + + dev->interface = dev->udev->actconfig->interface[0]; + + dbg(DBG_DEVSTART, "USB interface: %d endpoints", + NUM_EP(dev->interface)); + + /* we let this timer run the whole time this driver instance lives */ + mod_timer(&dev->bss_list_timer, jiffies+BSS_LIST_TIMEOUT); + +#ifdef CONFIG_IPAQ_HANDHELD + if (machine_is_h5400 ()) + ipaq_init_led (); +#endif + + if(at76c503_alloc_urbs(dev) < 0) + goto error; + + /* get firmware version */ + ret = get_mib(dev->udev, MIB_FW_VERSION, (u8*)&dev->fw_version, sizeof(dev->fw_version)); + if((ret < 0) || ((dev->fw_version.major == 0) && + (dev->fw_version.minor == 0) && + (dev->fw_version.patch == 0) && + (dev->fw_version.build == 0))){ + err("getting firmware failed with %d, or version is 0", ret); + err("this probably means that the ext. fw was not loaded correctly"); + goto error; + } + + /* fw 0.84 doesn't send FCS with rx data */ + if (dev->fw_version.major == 0 && dev->fw_version.minor <= 84) + dev->rx_data_fcs_len = 0; + else + dev->rx_data_fcs_len = 4; + + info("firmware version %d.%d.%d #%d (fcs_len %d)", + dev->fw_version.major, dev->fw_version.minor, + dev->fw_version.patch, dev->fw_version.build, + dev->rx_data_fcs_len); + + /* MAC address */ + ret = get_hw_config(dev); + if(ret < 0){ + err("could not get MAC address"); + goto error; + } + + dev->domain = getRegDomain(dev->regulatory_domain); + /* init. netdev->dev_addr */ + memcpy(netdev->dev_addr, dev->mac_addr, ETH_ALEN); + info("device's MAC %s, regulatory domain %s (id %d)", + mac2str(dev->mac_addr), dev->domain->name, + dev->regulatory_domain); + + /* initializing */ + dev->international_roaming = international_roaming; + dev->channel = DEF_CHANNEL; + dev->iw_mode = default_iw_mode; + dev->monitor_prism_header = 1; + memset(dev->essid, 0, IW_ESSID_MAX_SIZE); + memset(dev->nickn, 0, sizeof(dev->nickn)); + dev->rts_threshold = DEF_RTS_THRESHOLD; + dev->frag_threshold = DEF_FRAG_THRESHOLD; + dev->short_retry_limit = DEF_SHORT_RETRY_LIMIT; + //dev->long_retr_limit = DEF_LONG_RETRY_LIMIT; + dev->txrate = TX_RATE_AUTO; + dev->preamble_type = preamble_type; + dev->beacon_period = 100; + dev->beacons_last_qual=jiffies_to_msecs(jiffies); + dev->auth_mode = auth_mode ? WLAN_AUTH_SHARED_KEY : + WLAN_AUTH_OPEN; + dev->scan_min_time = scan_min_time; + dev->scan_max_time = scan_max_time; + dev->scan_mode = scan_mode; + dev->monitor_scan_min_time = monitor_scan_min_time; + dev->monitor_scan_max_time = monitor_scan_max_time; + + netdev->flags &= ~IFF_MULTICAST; /* not yet or never */ + netdev->open = at76c503_open; + netdev->stop = at76c503_stop; + netdev->get_stats = at76c503_get_stats; + netdev->ethtool_ops = &at76c503_ethtool_ops; + +#if WIRELESS_EXT > 16 + /* Add pointers to enable iwspy support. */ + dev->wireless_data.spy_data = &dev->spy_data; + netdev->wireless_data = &dev->wireless_data; +#else /* WIRELESS_EXT > 16 */ + netdev->get_wireless_stats = at76c503_get_wireless_stats; +#endif /* WIRELESS_EXT > 16 */ + + netdev->hard_start_xmit = at76c503_tx; + netdev->tx_timeout = at76c503_tx_timeout; + netdev->watchdog_timeo = 2 * HZ; + netdev->wireless_handlers = + (struct iw_handler_def*)&at76c503_handler_def; + netdev->set_multicast_list = at76c503_set_multicast; + netdev->set_mac_address = at76c503_set_mac_address; + // netdev->hard_header_len = 8 + sizeof(struct ieee80211_hdr_3addr); + /* +// netdev->hard_header = at76c503_header; +*/ + + /* putting this inside rtnl_lock() - rtnl_unlock() hangs modprobe ...? */ + ret = register_netdev(dev->netdev); + if (ret) { + err("unable to register netdevice %s (status %d)!", + dev->netdev->name, ret); + return -1; + } + info("registered %s", dev->netdev->name); + dev->netdev_registered = 1; + + return 0; + + error: + at76c503_delete_device(dev); + return -1; + +} /* init_new_device */ + + +/* == PROC at76c503_get_fw_info == + disassembles the firmware image into version, str, + internal and external fw part. returns 0 on success, < 0 on error */ +static int at76c503_get_fw_info(u8 *fw_data, int fw_size, + u32 *board, u32 *version, char **str, + u8 **int_fw, int *int_fw_size, + u8 **ext_fw, int *ext_fw_size) +{ +/* fw structure (all numbers are little_endian) + offset length description + 0 4 crc 32 (seed ~0, no post, all gaps are zeros, header included) + 4 4 board type (see at76c503.h) + 8 4 version (major<<24|middle<<16|minor<<8|build) + c 4 offset of printable string (id) area from begin of image + (must be \0 terminated !) + 10 4 offset of internal fw part area + 14 4 length of internal fw part + 18 4 offset of external fw part area (may be first byte _behind_ + image in case we have no external part) + 1c 4 length of external fw part +*/ + + __le32 val; + + if (fw_size < 0x21) { + err("fw too short (x%x)",fw_size); + return -EFAULT; + } + + /* crc currently not checked */ + + memcpy(&val,fw_data+4,4); + *board = le32_to_cpu(val); + + memcpy(&val,fw_data+8,4); + *version = le32_to_cpu(val); + + memcpy(&val,fw_data+0xc,4); + *str = fw_data + le32_to_cpu(val); + + memcpy(&val,fw_data+0x10,4); + *int_fw = fw_data + le32_to_cpu(val); + memcpy(&val,fw_data+0x14,4); + *int_fw_size = le32_to_cpu(val); + + memcpy(&val,fw_data+0x18,4); + *ext_fw = fw_data + le32_to_cpu(val); + memcpy(&val,fw_data+0x1c,4); + *ext_fw_size = le32_to_cpu(val); + + return 0; +} + +/* == PROC at76c503_do_probe == */ +static int at76c503_do_probe(struct module *mod, struct usb_device *udev, + const u8 *fw_data, int fw_size, u32 board_type, + const char *netdev_name) +{ + struct usb_interface *intf = udev->actconfig->interface[0]; + int ret; + struct at76c503 *dev = NULL; + int op_mode; + char *id_str; + u32 version; + + GET_DEV(udev); + + if ((dev=alloc_new_device(udev, (u8)board_type, netdev_name)) == NULL) { + ret = -ENOMEM; + goto error; + } + + op_mode = get_op_mode(udev); + + usb_set_intfdata(intf, dev); + dev->interface = intf; + + dbg(DBG_DEVSTART, "opmode %d", op_mode); + + /* we get OPMODE_NONE with 2.4.23, SMC2662W-AR ??? + we get 204 with 2.4.23, Fiberline FL-WL240u (505A+RFMD2958) ??? */ + + if (op_mode == OPMODE_HW_CONFIG_MODE) { + err("cannot handle a device in HW_CONFIG_MODE (opmode %d)", op_mode); + ret = -ENODEV; + goto error; + } + + if (op_mode != OPMODE_NORMAL_NIC_WITH_FLASH && + op_mode != OPMODE_NORMAL_NIC_WITHOUT_FLASH) { + + dbg(DBG_DEVSTART, "need to download firmware"); + + /* disassem. the firmware */ + if ((ret=at76c503_get_fw_info(fw_data, fw_size, &dev->board_type, + &version, &id_str, + &dev->intfw, &dev->intfw_size, + &dev->extfw, &dev->extfw_size))) { + goto error; + } + + dbg(DBG_DEVSTART, "firmware board %u version %u.%u.%u#%u " + "(int %x:%tx, ext %x:%tx)", + dev->board_type, version>>24,(version>>16)&0xff, + (version>>8)&0xff, version&0xff, + dev->intfw_size, dev->intfw-fw_data, + dev->extfw_size, dev->extfw-fw_data); + if (*id_str) + dbg(DBG_DEVSTART, "firmware id %s",id_str); + + if (dev->board_type != board_type) { + err("inconsistent board types %u != %u", + board_type, dev->board_type); + at76c503_delete_device(dev); + goto error; + } + + /* download internal firmware part */ + dbg(DBG_DEVSTART, "downloading internal firmware"); + NEW_STATE(dev,INTFW_DOWNLOAD); + defer_kevent(dev,KEVENT_INTERNAL_FW); + + } else { + /* internal firmware already inside the device */ + /* get firmware version to test if external firmware is loaded */ + /* This works only for newer firmware, e.g. the Intersil 0.90.x + says "control timeout on ep0in" and subsequent get_op_mode() fail + too :-( */ + int force_fw_dwl = 0; + + /* disassem. the firmware */ + if ((ret=at76c503_get_fw_info(fw_data, fw_size, &dev->board_type, + &version, &id_str, + &dev->intfw, &dev->intfw_size, + &dev->extfw, &dev->extfw_size))) { + goto error; + } + + /* if version >= 0.100.x.y or device with built-in flash we can query the device + * for the fw version */ + if (version >= ((0<<24)|(100<<16)) || (op_mode == OPMODE_NORMAL_NIC_WITH_FLASH)) { + ret = get_mib(udev, MIB_FW_VERSION, (u8*)&dev->fw_version, + sizeof(dev->fw_version)); + } else { + /* force fw download only if the device has no flash inside */ + force_fw_dwl = 1; + } + + if ((force_fw_dwl) || (ret < 0) || ((dev->fw_version.major == 0) && + (dev->fw_version.minor == 0) && + (dev->fw_version.patch == 0) && + (dev->fw_version.build == 0))) { + if (force_fw_dwl) + dbg(DBG_DEVSTART, "forced download of external firmware part"); + else + dbg(DBG_DEVSTART, "cannot get firmware (ret %d) or all zeros " + "- download external firmware", ret); + dbg(DBG_DEVSTART, "firmware board %u version %u.%u.%u#%u " + "(int %x:%tx, ext %x:%tx)", + dev->board_type, version>>24,(version>>16)&0xff, + (version>>8)&0xff, version&0xff, + dev->intfw_size, dev->intfw-fw_data, + dev->extfw_size, dev->extfw-fw_data); + if (*id_str) + dbg(DBG_DEVSTART, "firmware id %s",id_str); + + if (dev->board_type != board_type) { + err("inconsistent board types %u != %u", + board_type, dev->board_type); + at76c503_delete_device(dev); + goto error; + } + + NEW_STATE(dev,EXTFW_DOWNLOAD); + defer_kevent(dev,KEVENT_EXTERNAL_FW); + } else { + NEW_STATE(dev,INIT); + if (init_new_device(dev) < 0) { + ret = -ENODEV; + goto error; + } + } + } + + SET_NETDEV_DEV(dev->netdev, &intf->dev); + return 0; + +error: + PUT_DEV(udev); + return ret; +} + + +/* Firmware names - this must be in sync with boardtype definitions */ +static struct fwentry { + const char *const fwname; + const struct firmware *fw; +} firmwares[] = { + { "" }, + { "atmel_at76c503-i3861.bin" }, + { "atmel_at76c503-i3863.bin" }, + { "atmel_at76c503-rfmd.bin" }, + { "atmel_at76c503-rfmd-acc.bin" }, + { "atmel_at76c505-rfmd.bin" }, + { "atmel_at76c505-rfmd2958.bin" }, + { "atmel_at76c505a-rfmd2958.bin" }, + { "atmel_at76c505amx-rfmd.bin" } +}; + +/* USB Device IDs supported by this driver */ + +/* at76c503-i3861 */ +#define VENDOR_ID_ATMEL 0x03eb +#define PRODUCT_ID_ATMEL_503I 0x7603 /* Generic AT76C503/3861 device */ + +#define VENDOR_ID_LINKSYS_OLD 0x066b +#define PRODUCT_ID_LINKSYS_WUSB11_V21 0x2211 /* Linksys WUSB11 v2.1/v2.6 */ + +#define VENDOR_ID_NETGEAR 0x0864 +#define PRODUCT_ID_NETGEAR_MA101A 0x4100 /* Netgear MA 101 Rev. A */ + +#define VENDOR_ID_TEKRAM 0x0b3b +#define PRODUCT_ID_TEKRAM_U300C 0x1612 /* Tekram U-300C / Allnet ALL0193 */ + +#define VENDOR_ID_HP 0x03f0 +#define PRODUCT_ID_HP_HN210W 0x011c /* HP HN210W PKW-J7801A */ + +#define VENDOR_ID_M4Y750 0x0cde /* Unknown Vendor ID! */ +#define PRODUCT_ID_M4Y750 0x0001 /* Sitecom/Z-Com/Zyxel M4Y-750 */ + +#define VENDOR_ID_DYNALINK 0x069a +#define PRODUCT_ID_DYNALINK_WLL013_I 0x0320 /* Dynalink/Askey WLL013 (intersil) */ + +#define VENDOR_ID_SMC_OLD 0x0d5c +#define PRODUCT_ID_SMC2662W_V1 0xa001 /* EZ connect 11Mpbs +Wireless USB Adapter SMC2662W (v1) */ + +#define VENDOR_ID_BENQ 0x04a5 /* BenQ (Acer) */ +#define PRODUCT_ID_BENQ_AWL_300 0x9000 /* AWL-300 */ + +/* this adapter contains flash */ +#define VENDOR_ID_ADDTRON 0x05dd /* Addtron */ +#define PRODUCT_ID_ADDTRON_AWU120 0xff31 /* AWU-120 */ +/* also Compex WLU11 */ + +#define VENDOR_ID_INTEL 0x8086 /* Intel */ +#define PRODUCT_ID_INTEL_AP310 0x0200 /* AP310 AnyPoint II USB */ + +#define VENDOR_ID_CONCEPTRONIC 0x0d8e +#define PRODUCT_ID_CONCEPTRONIC_C11U 0x7100 /* also Dynalink L11U */ + +#define VENDOR_ID_ARESCOM 0xd8e +#define PRODUCT_ID_WL_210 0x7110 /* Arescom WL-210, + FCC id 07J-GL2411USB */ +#define VENDOR_ID_IO_DATA 0x04bb +#define PRODUCT_ID_IO_DATA_WN_B11_USB 0x0919 /* IO-DATA WN-B11/USB */ + +#define VENDOR_ID_BT 0x069a +#define PRODUCT_ID_BT_VOYAGER_1010 0x0821 /* BT Voyager 1010 */ + + +/* at76c503-i3863 */ +#define VENDOR_ID_ATMEL 0x03eb +#define PRODUCT_ID_ATMEL_503_I3863 0x7604 /* Generic AT76C503/3863 device */ + +#define VENDOR_ID_SAMSUNG 0x055d +#define PRODUCT_ID_SAMSUNG_SWL2100U 0xa000 /* Samsung SWL-2100U */ + + +/* at76c503-rfmd */ +#define VENDOR_ID_ATMEL 0x03eb +#define PRODUCT_ID_ATMEL_503R 0x7605 /* Generic AT76C503/RFMD device */ +#define PRODUCT_ID_W_BUDDIE_WN210 0x4102 /* AirVast W-Buddie WN210 */ + +#define VENDOR_ID_DYNALINK 0x069a +#define PRODUCT_ID_DYNALINK_WLL013_R 0x0321 /* Dynalink/Askey WLL013 (rfmd) */ + +#define VENDOR_ID_LINKSYS 0x077b +#define PRODUCT_ID_LINKSYS_WUSB11_V26 0x2219 /* Linksys WUSB11 v2.6 */ +#define PRODUCT_ID_NE_NWU11B 0x2227 /* Network Everywhere NWU11B */ + +#define VENDOR_ID_NETGEAR 0x0864 +#define PRODUCT_ID_NETGEAR_MA101B 0x4102 /* Netgear MA 101 Rev. B */ + +#define VENDOR_ID_ACTIONTEC 0x1668 +#define PRODUCT_ID_ACTIONTEC_802UAT1 0x7605 /* Actiontec 802UAT1, HWU01150-01UK */ + +#define VENDOR_ID_DLINK 0x2001 /* D-Link */ +#define PRODUCT_ID_DLINK_DWL120 0x3200 /* DWL-120 rev. E */ + +#define VENDOR_ID_DICK_SMITH_ELECTR 0x1371 /* Dick Smith Electronics */ +#define PRODUCT_ID_DSE_XH1153 0x5743 /* XH1153 802.11b USB adapter */ + /* also: CNet CNUSB611 (D) */ +#define PRODUCT_ID_WL_200U 0x0002 /* WL-200U */ + +#define VENDOR_ID_BENQ 0x04a5 /* BenQ (Acer) */ +#define PRODUCT_ID_BENQ_AWL_400 0x9001 /* BenQ AWL-400 USB stick */ + +#define VENDOR_ID_3COM 0x506 +#define PRODUCT_ID_3COM_3CRSHEW696 0xa01 /* 3COM 3CRSHEW696 */ + +#define VENDOR_ID_SIEMENS 0x681 +#define PRODUCT_ID_SIEMENS_SANTIS_WLL013 0x1b /* Siemens Santis ADSL WLAN + USB adapter WLL 013 */ + +#define VENDOR_ID_BELKIN_2 0x50d +#define PRODUCT_ID_BELKIN_F5D6050_V2 0x50 /* Belkin F5D6050, version 2 */ + +#define VENDOR_ID_BLITZ 0x07b8 +#define PRODUCT_ID_BLITZ_NETWAVE_BWU613 0xb000 /* iBlitzz, BWU613 (not *B or *SB !) */ + +#define VENDOR_ID_GIGABYTE 0x1044 +#define PRODUCT_ID_GIGABYTE_GN_WLBM101 0x8003 /* Gigabyte GN-WLBM101 */ + +#define VENDOR_ID_PLANEX 0x2019 +#define PRODUCT_ID_PLANEX_GW_US11S 0x3220 /* Planex GW-US11S */ + +#define VENDOR_ID_COMPAQ 0x049f +#define PRODUCT_ID_IPAQ_INT_WLAN 0x0032 /* internal WLAN adapter in h5[4,5]xx series iPAQs */ + + +/* at76c503-rfmd-acc */ +#define VENDOR_ID_BELKIN 0x0d5c +#define PRODUCT_ID_BELKIN_F5D6050 0xa002 /* Belkin F5D6050 / SMC 2662W v2 / SMC 2662W-AR */ + +#define VENDOR_ID_SMC 0x083a +#define PRODUCT_ID_SMC_2664W 0x3501 + + +/* at76c505-rfmd */ +#define VENDOR_ID_ATMEL 0x03eb +#define PRODUCT_ID_ATMEL_505R 0x7606 /* Generic AT76C505/RFMD device */ + + +/* at76c505-rfmd2958 */ +#define VENDOR_ID_ATMEL 0x03eb +#define PRODUCT_ID_ATMEL_505R2958 0x7613 /* Generic AT76C505/RFMD device + also OvisLink WL-1130USB */ + +#define VENDOR_ID_CNET 0x1371 +#define PRODUCT_ID_CNET_CNUSB611G 0x0013 /* CNet CNUSB 611G */ +#define PRODUCT_ID_FL_WL240U 0x0014 /* Fiberline WL-240U with the + CNet vendor id */ + +#define VENDOR_ID_LINKSYS_1915 0x1915 +#define PRODUCT_ID_LINKSYS_WUSB11V28 0x2233 /* Linksys WUSB11 v2.8 */ + +#define VENDOR_ID_XTERASYS 0x12fd +#define PRODUCT_ID_XTERASYS_XN_2122B 0x1001 /* Xterasys XN-2122B, also + IBlitzz BWU613B / BWU613SB */ + +#define VENDOR_ID_COREGA 0x07aa +#define PRODUCT_ID_COREGA_USB_STICK_11_KK 0x7613 /* Corega WLAN USB Stick 11 (K.K.) */ + +#define VENDOR_ID_MSI 0x0db0 +#define PRODUCT_ID_MSI_MS6978_WLAN_BOX_PC2PC 0x1020 + + +/* at76c505a-rfmd2958 */ +#define VENDOR_ID_ATMEL 0x03eb +#define PRODUCT_ID_ATMEL_505A 0x7614 /* Generic AT76C505A device */ +#define PRODUCT_ID_ATMEL_505AS 0x7617 /* Generic AT76C505AS device */ + +#define VENDOR_ID_GIGASET 0x1690 +#define PRODUCT_ID_GIGASET_11 0x0701 + + +/* at76c505amx-rfmd */ +#define VENDOR_ID_ATMEL 0x03eb +#define PRODUCT_ID_ATMEL_505AMX 0x7615 /* Generic AT76C505AMX device */ + + +static struct usb_device_id dev_table[] = { + { USB_DEVICE(VENDOR_ID_ATMEL, PRODUCT_ID_ATMEL_503I ), + .driver_info = BOARDTYPE_503_INTERSIL_3861 }, + { USB_DEVICE(VENDOR_ID_LINKSYS_OLD, PRODUCT_ID_LINKSYS_WUSB11_V21), + .driver_info = BOARDTYPE_503_INTERSIL_3861 }, + { USB_DEVICE(VENDOR_ID_NETGEAR, PRODUCT_ID_NETGEAR_MA101A ), + .driver_info = BOARDTYPE_503_INTERSIL_3861 }, + { USB_DEVICE(VENDOR_ID_TEKRAM, PRODUCT_ID_TEKRAM_U300C ), + .driver_info = BOARDTYPE_503_INTERSIL_3861 }, + { USB_DEVICE(VENDOR_ID_HP, PRODUCT_ID_HP_HN210W ), + .driver_info = BOARDTYPE_503_INTERSIL_3861 }, + { USB_DEVICE(VENDOR_ID_M4Y750, PRODUCT_ID_M4Y750 ), + .driver_info = BOARDTYPE_503_INTERSIL_3861 }, + { USB_DEVICE(VENDOR_ID_DYNALINK, PRODUCT_ID_DYNALINK_WLL013_I ), + .driver_info = BOARDTYPE_503_INTERSIL_3861 }, + { USB_DEVICE(VENDOR_ID_SMC_OLD, PRODUCT_ID_SMC2662W_V1 ), + .driver_info = BOARDTYPE_503_INTERSIL_3861 }, + { USB_DEVICE(VENDOR_ID_BENQ, PRODUCT_ID_BENQ_AWL_300 ), + .driver_info = BOARDTYPE_503_INTERSIL_3861 }, + { USB_DEVICE(VENDOR_ID_ADDTRON, PRODUCT_ID_ADDTRON_AWU120 ), + .driver_info = BOARDTYPE_503_INTERSIL_3861 }, + { USB_DEVICE(VENDOR_ID_INTEL, PRODUCT_ID_INTEL_AP310 ), + .driver_info = BOARDTYPE_503_INTERSIL_3861 }, + { USB_DEVICE(VENDOR_ID_CONCEPTRONIC,PRODUCT_ID_CONCEPTRONIC_C11U), + .driver_info = BOARDTYPE_503_INTERSIL_3861 }, + { USB_DEVICE(VENDOR_ID_ARESCOM, PRODUCT_ID_WL_210), + .driver_info = BOARDTYPE_503_INTERSIL_3861 }, + { USB_DEVICE(VENDOR_ID_IO_DATA, PRODUCT_ID_IO_DATA_WN_B11_USB), + .driver_info = BOARDTYPE_503_INTERSIL_3861 }, + { USB_DEVICE(VENDOR_ID_BT, PRODUCT_ID_BT_VOYAGER_1010 ), + .driver_info = BOARDTYPE_503_INTERSIL_3861 }, + + { USB_DEVICE(VENDOR_ID_ATMEL, PRODUCT_ID_ATMEL_503_I3863 ), + .driver_info = BOARDTYPE_503_INTERSIL_3863 }, + { USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG_SWL2100U), + .driver_info = BOARDTYPE_503_INTERSIL_3863 }, + + { USB_DEVICE(VENDOR_ID_ATMEL, PRODUCT_ID_ATMEL_503R ), + .driver_info = BOARDTYPE_503_RFMD }, + { USB_DEVICE(VENDOR_ID_DYNALINK, PRODUCT_ID_DYNALINK_WLL013_R ), + .driver_info = BOARDTYPE_503_RFMD }, + { USB_DEVICE(VENDOR_ID_LINKSYS, PRODUCT_ID_LINKSYS_WUSB11_V26), + .driver_info = BOARDTYPE_503_RFMD }, + { USB_DEVICE(VENDOR_ID_LINKSYS, PRODUCT_ID_NE_NWU11B ), + .driver_info = BOARDTYPE_503_RFMD }, + { USB_DEVICE(VENDOR_ID_NETGEAR, PRODUCT_ID_NETGEAR_MA101B ), + .driver_info = BOARDTYPE_503_RFMD }, + { USB_DEVICE(VENDOR_ID_DLINK, PRODUCT_ID_DLINK_DWL120 ), + .driver_info = BOARDTYPE_503_RFMD }, + { USB_DEVICE(VENDOR_ID_ACTIONTEC,PRODUCT_ID_ACTIONTEC_802UAT1 ), + .driver_info = BOARDTYPE_503_RFMD }, + { USB_DEVICE(VENDOR_ID_ATMEL, PRODUCT_ID_W_BUDDIE_WN210 ), + .driver_info = BOARDTYPE_503_RFMD }, + { USB_DEVICE(VENDOR_ID_DICK_SMITH_ELECTR, PRODUCT_ID_DSE_XH1153), + .driver_info = BOARDTYPE_503_RFMD }, + { USB_DEVICE(VENDOR_ID_DICK_SMITH_ELECTR, PRODUCT_ID_WL_200U), + .driver_info = BOARDTYPE_503_RFMD }, + { USB_DEVICE(VENDOR_ID_BENQ, PRODUCT_ID_BENQ_AWL_400), + .driver_info = BOARDTYPE_503_RFMD }, + { USB_DEVICE(VENDOR_ID_3COM, PRODUCT_ID_3COM_3CRSHEW696), + .driver_info = BOARDTYPE_503_RFMD }, + { USB_DEVICE(VENDOR_ID_SIEMENS, PRODUCT_ID_SIEMENS_SANTIS_WLL013), + .driver_info = BOARDTYPE_503_RFMD }, + { USB_DEVICE(VENDOR_ID_BELKIN_2, PRODUCT_ID_BELKIN_F5D6050_V2 ), + .driver_info = BOARDTYPE_503_RFMD }, + { USB_DEVICE(VENDOR_ID_BLITZ, PRODUCT_ID_BLITZ_NETWAVE_BWU613 ), + .driver_info = BOARDTYPE_503_RFMD }, + { USB_DEVICE(VENDOR_ID_GIGABYTE, PRODUCT_ID_GIGABYTE_GN_WLBM101 ), + .driver_info = BOARDTYPE_503_RFMD }, + { USB_DEVICE(VENDOR_ID_PLANEX, PRODUCT_ID_PLANEX_GW_US11S ), + .driver_info = BOARDTYPE_503_RFMD }, + { USB_DEVICE(VENDOR_ID_COMPAQ, PRODUCT_ID_IPAQ_INT_WLAN), + .driver_info = BOARDTYPE_503_RFMD }, + + { USB_DEVICE(VENDOR_ID_SMC, PRODUCT_ID_SMC_2664W), + .driver_info = BOARDTYPE_503_RFMD_ACC }, + { USB_DEVICE(VENDOR_ID_BELKIN, PRODUCT_ID_BELKIN_F5D6050 ), + .driver_info = BOARDTYPE_503_RFMD_ACC }, + + { USB_DEVICE(VENDOR_ID_ATMEL, PRODUCT_ID_ATMEL_505R ), + .driver_info = BOARDTYPE_505_RFMD }, + + { USB_DEVICE(VENDOR_ID_ATMEL, PRODUCT_ID_ATMEL_505R2958 ), + .driver_info = BOARDTYPE_505_RFMD_2958 }, + { USB_DEVICE(VENDOR_ID_CNET, PRODUCT_ID_FL_WL240U ), + .driver_info = BOARDTYPE_505_RFMD_2958 }, + { USB_DEVICE(VENDOR_ID_CNET, PRODUCT_ID_CNET_CNUSB611G ), + .driver_info = BOARDTYPE_505_RFMD_2958 }, + { USB_DEVICE(VENDOR_ID_LINKSYS_1915, PRODUCT_ID_LINKSYS_WUSB11V28 ), + .driver_info = BOARDTYPE_505_RFMD_2958 }, + { USB_DEVICE(VENDOR_ID_XTERASYS, PRODUCT_ID_XTERASYS_XN_2122B ), + .driver_info = BOARDTYPE_505_RFMD_2958 }, + { USB_DEVICE(VENDOR_ID_COREGA, PRODUCT_ID_COREGA_USB_STICK_11_KK ), + .driver_info = BOARDTYPE_505_RFMD_2958 }, + { USB_DEVICE(VENDOR_ID_MSI, PRODUCT_ID_MSI_MS6978_WLAN_BOX_PC2PC), + .driver_info = BOARDTYPE_505_RFMD_2958 }, + + { USB_DEVICE(VENDOR_ID_ATMEL, PRODUCT_ID_ATMEL_505A ), + .driver_info = BOARDTYPE_505A_RFMD_2958 }, + { USB_DEVICE(VENDOR_ID_ATMEL, PRODUCT_ID_ATMEL_505AS ), + .driver_info = BOARDTYPE_505A_RFMD_2958 }, + { USB_DEVICE(VENDOR_ID_GIGASET, PRODUCT_ID_GIGASET_11 ), + .driver_info = BOARDTYPE_505A_RFMD_2958 }, + + { USB_DEVICE(VENDOR_ID_ATMEL, PRODUCT_ID_ATMEL_505AMX ), + .driver_info = BOARDTYPE_505AMX_RFMD }, + + { } +}; + +MODULE_DEVICE_TABLE (usb, dev_table); + + +static int at76c50x_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + int retval; + + struct usb_device *udev; + int boardtype = (int)id->driver_info; + const char *const fw_name = firmwares[boardtype].fwname; + const struct firmware *fw = firmwares[boardtype].fw; + udev = interface_to_usbdev(interface); + + if (fw == NULL) { + dbg(DBG_FW, "downloading firmware %s", fw_name); + retval = request_firmware(&fw, fw_name, &udev->dev); + if (retval == 0) { + dbg(DBG_FW, "got it."); + } else { + err("firmware %s not found.", fw_name); + err("You may need to download the firmware from " + "https://developer.berlios.de/projects/at76c503a/"); + return retval; + } + } else + dbg(DBG_FW, "re-using previously loaded fw"); + + retval = at76c503_do_probe(THIS_MODULE, udev, + fw->data, fw->size, + boardtype, netdev_name); + return retval; +} + +static void at76c50x_disconnect(struct usb_interface *interface) +{ + struct at76c503 *ptr; + + ptr = usb_get_intfdata (interface); + usb_set_intfdata(interface, NULL); + + info("%s disconnecting", ((struct at76c503 *)ptr)->netdev->name); + at76c503_delete_device(ptr); + info(DRIVER_NAME " disconnected"); +} + +/* structure for registering this driver with the USB subsystem */ +static struct usb_driver module_usb = { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) + .owner = THIS_MODULE, +#endif + .name = DRIVER_NAME, + .probe = at76c50x_probe, + .disconnect = at76c50x_disconnect, + .id_table = dev_table, +}; + + +static int __init mod_init(void) +{ + int result; + + info(DRIVER_DESC " " DRIVER_VERSION " loading"); + +#ifdef CONFIG_IPAQ_HANDHELD + if (machine_is_h5400()) { + /* turn WLAN power on */ + /* both needed? */ + SET_H5400_ASIC_GPIO (GPB, RF_POWER_ON, 1); + SET_H5400_ASIC_GPIO (GPB, WLAN_POWER_ON, 1); + } +#endif + + /* register this driver with the USB subsystem */ + result = usb_register(&module_usb); + if (result < 0) { + err("usb_register failed (status %d)", result); + return -1; + } + + return 0; +} + +static void __exit mod_exit(void) +{ + int i; + + info(DRIVER_DESC " " DRIVER_VERSION " unloading"); + usb_deregister(&module_usb); + for (i = 0; i < ARRAY_SIZE(firmwares); i++) { + if (firmwares[i].fw) + release_firmware(firmwares[i].fw); + } + +#ifdef CONFIG_IPAQ_HANDHELD + if (machine_is_h5400()) { + /* turn WLAN power off */ + SET_H5400_ASIC_GPIO (GPB, RF_POWER_ON, 0); + SET_H5400_ASIC_GPIO (GPB, WLAN_POWER_ON, 0); + } +#endif +} + +module_init(mod_init); +module_exit(mod_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); --- linux-2.6.27.orig/ubuntu/misc/wireless/at76/Makefile +++ linux-2.6.27/ubuntu/misc/wireless/at76/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_WIRELESS_AT76) += at76_usb.o + +at76_usb-objs := at76c503.o at76_usbdfu.o --- linux-2.6.27.orig/ubuntu/misc/wireless/at76/at76c503.h +++ linux-2.6.27/ubuntu/misc/wireless/at76/at76c503.h @@ -0,0 +1,729 @@ +/* -*- linux-c -*- */ +/* + * Copyright (c) 2002 - 2003 Oliver Kurth + * (c) 2003 - 2004 Jörg Albert + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This driver was based on information from the Sourceforge driver + * released and maintained by Atmel: + * + * http://sourceforge.net/projects/atmelwlandriver/ + * + * Although the code was completely re-written, + * it would have been impossible without Atmel's decision to + * release an Open Source driver (unfortunately the firmware was + * kept binary only). Thanks for that decision to Atmel! + * + * For the latest version of this driver, mailinglists + * and other info, please check + * http://at76c503a.berlios.de/ + */ + +#ifndef _AT76C503_H +#define _AT76C503_H + +#include + +/* current driver version */ +#define DRIVER_VERSION "0.14beta1" + + +/* our private ioctl's */ +/* set preamble length*/ +#define PRIV_IOCTL_SET_SHORT_PREAMBLE (SIOCIWFIRSTPRIV + 0x0) +/* set debug parameter */ +#define PRIV_IOCTL_SET_DEBUG (SIOCIWFIRSTPRIV + 0x2) +/* set power save mode (incl. the Atmel proprietary smart save mode */ +#define PRIV_IOCTL_SET_POWERSAVE_MODE (SIOCIWFIRSTPRIV + 0x4) +/* set min and max channel times for scan */ +#define PRIV_IOCTL_SET_SCAN_TIMES (SIOCIWFIRSTPRIV + 0x6) +/* set scan mode */ +#define PRIV_IOCTL_SET_SCAN_MODE (SIOCIWFIRSTPRIV + 0x8) +/* set international roaming */ +#define PRIV_IOCTL_SET_INTL_ROAMING (SIOCIWFIRSTPRIV + 0x10) +/* set monitor mode */ +#define PRIV_IOCTL_SET_MONITOR_MODE (SIOCIWFIRSTPRIV + 0x12) + +#define DEVICE_VENDOR_REQUEST_OUT 0x40 +#define DEVICE_VENDOR_REQUEST_IN 0xc0 +#define INTERFACE_VENDOR_REQUEST_OUT 0x41 +#define INTERFACE_VENDOR_REQUEST_IN 0xc1 +#define CLASS_REQUEST_OUT 0x21 +#define CLASS_REQUEST_IN 0xa1 + +#define CMD_STATUS_IDLE 0x00 +#define CMD_STATUS_COMPLETE 0x01 +#define CMD_STATUS_UNKNOWN 0x02 +#define CMD_STATUS_INVALID_PARAMETER 0x03 +#define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x04 +#define CMD_STATUS_TIME_OUT 0x07 +#define CMD_STATUS_IN_PROGRESS 0x08 +#define CMD_STATUS_HOST_FAILURE 0xff +#define CMD_STATUS_SCAN_FAILED 0xf0 + +/* answers to get op mode */ +#define OPMODE_NONE 0x00 +#define OPMODE_NORMAL_NIC_WITH_FLASH 0x01 +#define OPMODE_HW_CONFIG_MODE 0x02 +#define OPMODE_DFU_MODE_WITH_FLASH 0x03 +#define OPMODE_NORMAL_NIC_WITHOUT_FLASH 0x04 + +#define CMD_SET_MIB 0x01 +#define CMD_GET_MIB 0x02 +#define CMD_SCAN 0x03 +#define CMD_JOIN 0x04 +#define CMD_START_IBSS 0x05 +#define CMD_RADIO 0x06 +#define CMD_STARTUP 0x0B +#define CMD_GETOPMODE 0x33 + +#define MIB_LOCAL 0x01 +#define MIB_MAC_ADD 0x02 +#define MIB_MAC 0x03 +#define MIB_MAC_MGMT 0x05 +#define MIB_MAC_WEP 0x06 +#define MIB_PHY 0x07 +#define MIB_FW_VERSION 0x08 +#define MIB_MDOMAIN 0x09 + +#define ADHOC_MODE 1 +#define INFRASTRUCTURE_MODE 2 + +/* values for struct mib_local, field preamble_type */ +#define PREAMBLE_TYPE_SHORT 1 +#define PREAMBLE_TYPE_LONG 0 + +/* values for tx_rate */ +#define TX_RATE_1MBIT 0 +#define TX_RATE_2MBIT 1 +#define TX_RATE_5_5MBIT 2 +#define TX_RATE_11MBIT 3 +#define TX_RATE_AUTO 4 + +/* power management modes */ +#define PM_ACTIVE 1 +#define PM_SAVE 2 +#define PM_SMART_SAVE 3 + +/* international roaming state */ +#define IR_OFF 0 +#define IR_ON 1 + +/* monitor mode - param of private ioctl */ +#define MM_OFF 0 +#define MM_ON 1 +#define MM_ON_NO_PRISM 2 + + +/* offsets into the MIBs we use to configure the device */ +#define TX_AUTORATE_FALLBACK_OFFSET offsetof(struct mib_local,txautorate_fallback) +#define FRAGMENTATION_OFFSET offsetof(struct mib_mac,frag_threshold) +#define PREAMBLE_TYPE_OFFSET offsetof(struct mib_local,preamble_type) +#define RTS_OFFSET offsetof(struct mib_mac, rts_threshold) + +/* valid only for rfmd and 505 !*/ +#define IBSS_CHANGE_OK_OFFSET offsetof(struct mib_mac_mgmt, ibss_change) +#define IROAMING_IMPL_OFFSET offsetof(struct mib_mac_mgmt, multi_domain_capability_implemented) +#define IROAMING_OFFSET \ + offsetof(struct mib_mac_mgmt, multi_domain_capability_enabled) +/* the AssocID */ +#define STATION_ID_OFFSET offsetof(struct mib_mac_mgmt, station_id) +#define POWER_MGMT_MODE_OFFSET offsetof(struct mib_mac_mgmt, power_mgmt_mode) +#define LISTEN_INTERVAL_OFFSET offsetof(struct mib_mac, listen_interval) + +#define PRIVACY_OPT_IMPL offsetof(struct mib_mac_mgmt, privacy_option_implemented) + +#define BOARDTYPE_503_INTERSIL_3861 1 +#define BOARDTYPE_503_INTERSIL_3863 2 +#define BOARDTYPE_503_RFMD 3 +#define BOARDTYPE_503_RFMD_ACC 4 +#define BOARDTYPE_505_RFMD 5 +#define BOARDTYPE_505_RFMD_2958 6 +#define BOARDTYPE_505A_RFMD_2958 7 +#define BOARDTYPE_505AMX_RFMD 8 + +struct hwcfg_r505 { + u8 cr39_values[14]; + u8 reserved1[14]; + u8 bb_cr[14]; + u8 pidvid[4]; + u8 mac_addr[ETH_ALEN]; + u8 regulatory_domain; + u8 reserved2[14]; + u8 cr15_values[14]; + u8 reserved3[3]; +} __attribute__ ((packed)); + +struct hwcfg_rfmd { + u8 cr20_values[14]; + u8 cr21_values[14]; + u8 bb_cr[14]; + u8 pidvid[4]; + u8 mac_addr[ETH_ALEN]; + u8 regulatory_domain; + u8 low_power_values[14]; + u8 normal_power_values[14]; + u8 reserved1[3]; +} __attribute__ ((packed)); + +struct hwcfg_intersil { + u8 mac_addr[ETH_ALEN]; + u8 cr31_values[14]; + u8 cr58_values[14]; + u8 pidvid[4]; + u8 regulatory_domain; + u8 reserved[1]; +} __attribute__ ((packed)); + +#define WEP_SMALL_KEY_LEN (40/8) +#define WEP_LARGE_KEY_LEN (104/8) + +struct at76c503_card_config{ + u8 exclude_unencrypted; + u8 promiscuous_mode; + u8 short_retry_limit; + u8 encryption_type; + __le16 rts_threshold; + __le16 fragmentation_threshold; // 256..2346 + u8 basic_rate_set[4]; + u8 auto_rate_fallback; //0,1 + u8 channel; + u8 privacy_invoked; + u8 wep_default_key_id; // 0..3 + u8 current_ssid[32]; + u8 wep_default_key_value[4][WEP_KEY_LEN]; + u8 ssid_len; + u8 short_preamble; + __le16 beacon_period; +} __attribute__ ((packed)); + +struct at76c503_command{ + u8 cmd; + u8 reserved; + __le16 size; +} __attribute__ ((packed)); + +/* the length of the Atmel firmware specific rx header before IEEE 802.11 starts */ +#define AT76C503_RX_HDRLEN offsetof(struct at76c503_rx_buffer, packet) + +struct at76c503_rx_buffer { + __le16 wlength; + u8 rx_rate; + u8 newbss; + u8 fragmentation; + u8 rssi; + u8 link_quality; + u8 noise_level; + u8 rx_time[4]; + u8 packet[IEEE80211_FRAME_LEN + IEEE80211_FCS_LEN]; +} __attribute__ ((packed)); + +/* the length of the Atmel firmware specific tx header before IEEE 802.11 starts */ +#define AT76C503_TX_HDRLEN offsetof(struct at76c503_tx_buffer, packet) + +struct at76c503_tx_buffer { + __le16 wlength; + u8 tx_rate; + u8 padding; + u8 reserved[4]; + u8 packet[IEEE80211_FRAME_LEN + IEEE80211_FCS_LEN]; +} __attribute__ ((packed)); + +/* defines for scan_type below */ +#define SCAN_TYPE_ACTIVE 0 +#define SCAN_TYPE_PASSIVE 1 + +struct at76c503_start_scan { + u8 bssid[ETH_ALEN]; + u8 essid[32]; + u8 scan_type; + u8 channel; + __le16 probe_delay; + __le16 min_channel_time; + __le16 max_channel_time; + u8 essid_size; + u8 international_scan; +} __attribute__ ((packed)); + +struct at76c503_start_bss { + u8 bssid[ETH_ALEN]; + u8 essid[32]; + u8 bss_type; + u8 channel; + u8 essid_size; + u8 reserved[3]; +} __attribute__ ((packed)); + +struct at76c503_join { + u8 bssid[ETH_ALEN]; + u8 essid[32]; + u8 bss_type; + u8 channel; + __le16 timeout; + u8 essid_size; + u8 reserved; +} __attribute__ ((packed)); + +struct set_mib_buffer { + u8 type; + u8 size; + u8 index; + u8 reserved; + u8 data[72]; +} __attribute__ ((packed)); + +struct mib_local { + u16 reserved0; + u8 beacon_enable; + u8 txautorate_fallback; + u8 reserved1; + u8 ssid_size; + u8 promiscuous_mode; + u16 reserved2; + u8 preamble_type; + u16 reserved3; +} __attribute__ ((packed)); + +struct mib_mac_addr { + u8 mac_addr[ETH_ALEN]; + u8 res[2]; /* ??? */ + u8 group_addr[4][ETH_ALEN]; + u8 group_addr_status[4]; +} __attribute__ ((packed)); + +struct mib_mac { + __le32 max_tx_msdu_lifetime; + __le32 max_rx_lifetime; + __le16 frag_threshold; + __le16 rts_threshold; + __le16 cwmin; + __le16 cwmax; + u8 short_retry_time; + u8 long_retry_time; + u8 scan_type; /* active or passive */ + u8 scan_channel; + __le16 probe_delay; /* delay before sending a ProbeReq in active scan, RO */ + __le16 min_channel_time; + __le16 max_channel_time; + __le16 listen_interval; + u8 desired_ssid[32]; + u8 desired_bssid[ETH_ALEN]; + u8 desired_bsstype; /* ad-hoc or infrastructure */ + u8 reserved2; +} __attribute__ ((packed)); + +struct mib_mac_mgmt { + __le16 beacon_period; + __le16 CFP_max_duration; + __le16 medium_occupancy_limit; + __le16 station_id; /* assoc id */ + __le16 ATIM_window; + u8 CFP_mode; + u8 privacy_option_implemented; + u8 DTIM_period; + u8 CFP_period; + u8 current_bssid[ETH_ALEN]; + u8 current_essid[32]; + u8 current_bss_type; + u8 power_mgmt_mode; + /* rfmd and 505 */ + u8 ibss_change; + u8 res; + u8 multi_domain_capability_implemented; + u8 multi_domain_capability_enabled; + u8 country_string[3]; + u8 reserved[3]; +} __attribute__ ((packed)); + +struct mib_mac_wep { + u8 privacy_invoked; /* 0 disable encr., 1 enable encr */ + u8 wep_default_key_id; + u8 wep_key_mapping_len; + u8 exclude_unencrypted; + __le32 wep_icv_error_count; + __le32 wep_excluded_count; + u8 wep_default_keyvalue[WEP_KEYS][WEP_KEY_LEN]; + u8 encryption_level; /* 1 for 40bit, 2 for 104bit encryption */ +} __attribute__ ((packed)); + +struct mib_phy { + __le32 ed_threshold; + + __le16 slot_time; + __le16 sifs_time; + __le16 preamble_length; + __le16 plcp_header_length; + __le16 mpdu_max_length; + __le16 cca_mode_supported; + + u8 operation_rate_set[4]; + u8 channel_id; + u8 current_cca_mode; + u8 phy_type; + u8 current_reg_domain; +} __attribute__ ((packed)); + +struct mib_fw_version { + u8 major; + u8 minor; + u8 patch; + u8 build; +} __attribute__ ((packed)); + +struct mib_mdomain { + u8 tx_powerlevel[14]; + u8 channel_list[14]; /* 0 for invalid channels */ +} __attribute__ ((packed)); + +/* states in infrastructure mode */ +enum infra_state { + INIT, + SCANNING, + AUTHENTICATING, + ASSOCIATING, + REASSOCIATING, + DISASSOCIATING, + JOINING, + CONNECTED, + STARTIBSS, + INTFW_DOWNLOAD, + EXTFW_DOWNLOAD, + WAIT_FOR_DISCONNECT, + MONITORING, +}; + +/* a description of a regulatory domain and the allowed channels */ +struct reg_domain { + u16 code; + char const *name; + u32 channel_map; /* if bit N is set, channel (N+1) is allowed */ +}; + +/* how long do we keep a (I)BSS in the bss_list in jiffies + this should be long enough for the user to retrieve the table + (by iwlist ?) after the device started, because all entries from + other channels than the one the device locks on get removed, too */ +#define BSS_LIST_TIMEOUT (120*HZ) + +/* struct to store BSS info found during scan */ +#define BSS_LIST_MAX_RATE_LEN 32 /* 32 rates should be enough ... */ + +struct bss_info{ + struct list_head list; + + u8 mac[ETH_ALEN]; /* real mac address, differs + for ad-hoc from bssid */ + u8 bssid[ETH_ALEN]; /* bssid */ + u8 ssid[IW_ESSID_MAX_SIZE+1]; /* ssid, +1 for trailing \0 + to make it printable */ + u8 ssid_len; /* length of ssid above */ + u8 channel; + u16 capa; /* the capabilities of the BSS (in original endianess - + we only check IEEE802_11 bits in it) */ + u16 beacon_interval; /* the beacon interval in units of TU (1.024 ms) + (in CPU endianess - we must calc. values from it) */ + u8 rates[BSS_LIST_MAX_RATE_LEN]; /* supported rates (list of bytes: + (basic_rate ? 0x80 : 0) + rate/(500 Kbit/s); e.g. + x82,x84,x8b,x96 for basic rates 1,2,5.5,11 MBit/s) */ + u8 rates_len; + + /* quality of received beacon */ + u8 rssi; + u8 link_qual; + u8 noise_level; + + unsigned long last_rx; /* time (jiffies) of last beacon received */ + u16 assoc_id; /* if this is dev->curr_bss this is the assoc id we got + in a successful AssocResponse */ +}; + +/* a rx data buffer to collect rx fragments */ +struct rx_data_buf { + u8 sender[ETH_ALEN]; /* sender address */ + u16 seqnr; /* sequence number */ + u16 fragnr; /* last fragment received */ + unsigned long last_rx; /* jiffies of last rx */ + struct sk_buff *skb; /* == NULL if entry is free */ +}; + +#define NR_RX_DATA_BUF 8 + +/* how often do we try to submit a rx urb until giving up */ +#define NR_SUBMIT_RX_TRIES 8 + +struct at76c503 { + struct usb_device *udev; /* USB device pointer */ + struct net_device *netdev; /* net device pointer */ + struct net_device_stats stats; + struct iw_statistics wstats; + struct usb_interface *interface; /* the interface for this device */ + +// unsigned char num_ports; /* the number of ports this device has */ +// char num_interrupt_in; /* number of interrupt in endpoints we have */ +// char num_bulk_in; /* number of bulk in endpoints we have */ +// char num_bulk_out; /* number of bulk out endpoints we have */ + + struct sk_buff * rx_skb; /* skbuff for receiving packets */ + __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ + + unsigned char * bulk_out_buffer; /* the buffer to send data */ + int bulk_out_size; /* the size of the send buffer */ + struct urb * write_urb; /* the urb used to send data */ + struct urb * read_urb; + __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ + +// struct work_struct tqueue; /* task queue for line discipline waking up */ + int open_count; /* number of times this port has been opened */ + struct semaphore sem; /* locks this structure */ + + + unsigned long kevent_flags; + struct work_struct kevent; + int nr_submit_rx_tries; /* number of tries to submit an rx urb left */ + struct tasklet_struct tasklet; + struct urb *rx_urb; /* tmp urb pointer for rx_tasklet */ + + unsigned char *ctrl_buffer; + struct urb *ctrl_urb; + + u8 op_mode; + + /* the WEP stuff */ + int wep_enabled; /* 1 if WEP is enabled */ + int wep_key_id; /* key id to be used */ + u8 wep_keys[WEP_KEYS][WEP_KEY_LEN]; /* the four WEP keys, + 5 or 13 bytes are used */ + u8 wep_keys_len[WEP_KEYS]; /* the length of the above keys */ + + int channel; + int iw_mode; + int curr_ap; + u8 bssid[ETH_ALEN]; + u8 essid[IW_ESSID_MAX_SIZE]; + char nickn[IW_ESSID_MAX_SIZE+1]; /* nickname, only used in the iwconfig i/f */ + int essid_size; + int radio_on; + int promisc; + + int preamble_type; /* 0 - long preamble, 1 - short preamble */ + int auth_mode; /* authentication type: 0 open, 1 shared key */ + int txrate; /* 0,1,2,3 = 1,2,5.5,11 MBit, 4 is auto-fallback */ + int frag_threshold; /* threshold for fragmentation of tx packets */ + int rts_threshold; /* threshold for RTS mechanism */ + int short_retry_limit; + //int long_retry_limit; + + int scan_min_time; /* scan min channel time */ + int scan_max_time; /* scan max channel time */ + int scan_mode; /* SCAN_TYPE_ACTIVE, SCAN_TYPE_PASSIVE */ + int scan_runs; /* counts how many scans are started */ + + /* the list we got from scanning */ + spinlock_t bss_list_spinlock; /* protects bss_list operations and setting + curr_bss and new_bss */ + struct list_head bss_list; /* the list of bss we received beacons from */ + struct timer_list bss_list_timer; /* a timer removing old entries from + the bss_list. It must acquire bss_list_spinlock + before and must not remove curr_bss nor + new_bss ! */ + struct bss_info *curr_bss; /* if istate == AUTH, ASSOC, REASSOC, JOIN or CONN + dev->bss[curr_bss] is the currently selected BSS + we operate on */ + struct bss_info *new_bss; /* if istate == REASSOC dev->new_bss + is the new bss we want to reassoc to */ + + u8 wanted_bssid[ETH_ALEN]; + int wanted_bssid_valid; /* != 0 if wanted_bssid is to be used */ + + /* some data for infrastructure mode only */ + spinlock_t mgmt_spinlock; /* this spinlock protects access to + next_mgmt_bulk */ + spinlock_t istate_spinlock; /* this spinlock protects access to + istate */ + + + struct at76c503_tx_buffer *next_mgmt_bulk; /* pending management msg to + send via bulk out */ + enum infra_state istate; + enum { + SITE_SURVEY_IDLE, + SITE_SURVEY_IN_PROGRESS, + SITE_SURVEY_COMPLETED + } site_survey_state; + time_t last_survey; + + struct timer_list restart_timer; /* the timer we use to delay the restart a bit */ + + struct timer_list mgmt_timer; /* the timer we use to repeat auth_req etc. */ + int retries; /* counts backwards while re-trying to send auth/assoc_req's */ + u16 assoc_id; /* the assoc_id for states JOINING, REASSOCIATING, CONNECTED */ + u8 pm_mode ; /* power management mode: ACTIVE, SAVE, SMART_SAVE */ + u32 pm_period_us; /* power manag. period (in us ?) - set by iwconfig */ + u32 pm_period_beacon; /* power manag. period (in beacon intervals + of the curr_bss) */ + u32 board_type; /* BOARDTYPE_* defined above*/ + + struct reg_domain const *domain; /* the description of the regulatory domain */ + + /* iwspy support */ + spinlock_t spy_spinlock; + struct iw_spy_data spy_data; + +#if WIRELESS_EXT > 16 + struct iw_public_data wireless_data; +#endif /* WIRELESS_EXT > 16 */ + + /* These fields contain HW config provided by the device (not all of + * these fields are used by all board types) */ + u8 mac_addr[ETH_ALEN]; + u8 bb_cr[14]; + u8 pidvid[4]; + u8 regulatory_domain; + u8 cr15_values[14]; + u8 cr20_values[14]; + u8 cr21_values[14]; + u8 cr31_values[14]; + u8 cr39_values[14]; + u8 cr58_values[14]; + u8 low_power_values[14]; + u8 normal_power_values[14]; + + struct at76c503_card_config card_config; + struct mib_fw_version fw_version; + + int rx_data_fcs_len; /* length of the trailing FCS + (0 for fw <= 0.84.x, 4 otherwise) */ + + /* store rx fragments until complete */ + struct rx_data_buf rx_data[NR_RX_DATA_BUF]; + + /* firmware downloading stuff */ + struct timer_list fw_dl_timer; /* timer used to wait after REMAP + until device is reset */ + int extfw_size; + int intfw_size; + /* these point into a buffer managed by at76c503-xxx.o, no need to dealloc */ + u8 *extfw; /* points to external firmware part, extfw_size bytes long */ + u8 *intfw; /* points to internal firmware part, intfw_size bytes long */ + struct usb_driver *calling_driver; /* the calling driver: at76c503-{rfmd,i3861,i3863,...} */ + unsigned int device_unplugged:1; + unsigned int netdev_registered:1; + char obuf[2*256+1]; /* global debug output buffer to reduce stack usage */ + char obuf_s[3*32]; /* small global debug output buffer to reduce stack usage */ + struct set_mib_buffer mib_buf; /* global buffer for set_mib calls */ + + /* new whiz-bang feature flags */ + int international_roaming; + int monitor_prism_header; /* if iw_mode == IW_MODE_MONITOR, + use Prism header */ + int monitor_scan_min_time; + int monitor_scan_max_time; + + int beacon_period; /* period of mgmt beacons */ + int beacons_received; + unsigned long beacons_last_qual; /* last time we reset beacons_received = 0 */ +}; + +/* Quasi-monitor mode defs (copied from /drivers/net/wireless/orinoco.h) */ + +/* message data item for INT, BOUNDEDINT, ENUMINT */ +typedef struct p80211item_uint32 +{ + uint32_t did __attribute__ ((packed)); + uint16_t status __attribute__ ((packed)); + uint16_t len __attribute__ ((packed)); + uint32_t data __attribute__ ((packed)); +} __attribute__ ((packed)) p80211item_uint32_t; + +typedef struct p80211msg +{ + uint32_t msgcode __attribute__ ((packed)); + uint32_t msglen __attribute__ ((packed)); + uint8_t devname[IFNAMSIZ]; +} __attribute__ ((packed)) p80211msg_t; + +#define P80211ENUM_msgitem_status_data_ok 0 +#define P80211ENUM_msgitem_status_no_value 1 +#define P80211ENUM_truth_false 0 +#define P80211ENUM_truth_true 1 + +#define DIDmsg_lnxind_wlansniffrm 0x0041 +#define DIDmsg_lnxind_wlansniffrm_hosttime 0x1041 +#define DIDmsg_lnxind_wlansniffrm_mactime 0x2041 +#define DIDmsg_lnxind_wlansniffrm_channel 0x3041 +#define DIDmsg_lnxind_wlansniffrm_rssi 0x4041 +#define DIDmsg_lnxind_wlansniffrm_sq 0x5041 +#define DIDmsg_lnxind_wlansniffrm_signal 0x6041 +#define DIDmsg_lnxind_wlansniffrm_noise 0x7041 +#define DIDmsg_lnxind_wlansniffrm_rate 0x8041 +#define DIDmsg_lnxind_wlansniffrm_istx 0x9041 +#define DIDmsg_lnxind_wlansniffrm_frmlen 0xA041 + +typedef struct p80211msg_lnxind_wlansniffrm +{ + uint32_t msgcode; + uint32_t msglen; + uint8_t devname[IFNAMSIZ]; + p80211item_uint32_t hosttime; + p80211item_uint32_t mactime; + p80211item_uint32_t channel; + p80211item_uint32_t rssi; + p80211item_uint32_t sq; + p80211item_uint32_t signal; + p80211item_uint32_t noise; + p80211item_uint32_t rate; + p80211item_uint32_t istx; + p80211item_uint32_t frmlen; +} __attribute__ ((packed)) p80211msg_lnxind_wlansniffrm_t; + +/* at76_debug bits */ +#define DBG_PROGRESS 0x00000001 /* progress of scan-join-(auth-assoc)-connected */ +#define DBG_BSS_TABLE 0x00000002 /* show the bss table after scans */ +#define DBG_IOCTL 0x00000004 /* ioctl calls / settings */ +#define DBG_KEVENT 0x00000008 /* kevents */ +#define DBG_TX_DATA 0x00000010 /* tx header */ +#define DBG_TX_DATA_CONTENT 0x00000020 /* tx content */ +#define DBG_TX_MGMT 0x00000040 +#define DBG_RX_DATA 0x00000080 /* rx data header */ +#define DBG_RX_DATA_CONTENT 0x00000100 /* rx data content */ +#define DBG_RX_MGMT 0x00000200 /* rx mgmt header except beacon and probe responses */ +#define DBG_RX_BEACON 0x00000400 /* rx beacon */ +#define DBG_RX_CTRL 0x00000800 /* rx control */ +#define DBG_RX_MGMT_CONTENT 0x00001000 /* rx mgmt content */ +#define DBG_RX_FRAGS 0x00002000 /* rx data fragment handling */ +#define DBG_DEVSTART 0x00004000 /* fw download, device start */ +#define DBG_URB 0x00008000 /* rx urb status, ... */ +#define DBG_RX_ATMEL_HDR 0x00010000 /* the Atmel specific header of each rx packet */ +#define DBG_PROC_ENTRY 0x00020000 /* procedure entries and exits */ +#define DBG_PM 0x00040000 /* power management settings */ +#define DBG_BSS_MATCH 0x00080000 /* show why a certain bss did not match */ +#define DBG_PARAMS 0x00100000 /* show the configured parameters */ +#define DBG_WAIT_COMPLETE 0x00200000 /* show the wait_completion progress */ +#define DBG_RX_FRAGS_SKB 0x00400000 /* show skb header for incoming rx fragments */ +#define DBG_BSS_TABLE_RM 0x00800000 /* inform on removal of old bss table entries */ +#define DBG_MONITOR_MODE 0x01000000 /* debugs from monitor mode */ +#define DBG_MIB 0x02000000 /* dump all MIBs in startup_device */ +#define DBG_MGMT_TIMER 0x04000000 /* dump mgmt_timer ops */ +#define DBG_WE_EVENTS 0x08000000 /* dump wireless events */ +#define DBG_FW 0x10000000 /* firmware download */ +#define DBG_DFU 0x20000000 /* device firmware upgrade */ + +#define DBG_DEFAULTS 0 +extern int at76_debug; + +/* Use our own dbg macro */ +#undef dbg +#define dbg(bits, format, arg...) \ + do { \ + if (at76_debug & (bits)) \ + printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg);\ + } while (0) + +int usbdfu_download(struct usb_device *udev, u8 *fw_buf, u32 fw_len, + int manifest_sync_timeout); + +#endif /* _AT76C503_H */ --- linux-2.6.27.orig/ubuntu/misc/wireless/prism2_usb/hfa384x_usb.c +++ linux-2.6.27/ubuntu/misc/wireless/prism2_usb/hfa384x_usb.c @@ -0,0 +1,5068 @@ +/* src/prism2/driver/hfa384x_usb.c +* +* Functions that talk to the USB variantof the Intersil hfa384x MAC +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* This file implements functions that correspond to the prism2/hfa384x +* 802.11 MAC hardware and firmware host interface. +* +* The functions can be considered to represent several levels of +* abstraction. The lowest level functions are simply C-callable wrappers +* around the register accesses. The next higher level represents C-callable +* prism2 API functions that match the Intersil documentation as closely +* as is reasonable. The next higher layer implements common sequences +* of invokations of the API layer (e.g. write to bap, followed by cmd). +* +* Common sequences: +* hfa384x_drvr_xxx Highest level abstractions provided by the +* hfa384x code. They are driver defined wrappers +* for common sequences. These functions generally +* use the services of the lower levels. +* +* hfa384x_drvr_xxxconfig An example of the drvr level abstraction. These +* functions are wrappers for the RID get/set +* sequence. They call copy_[to|from]_bap() and +* cmd_access(). These functions operate on the +* RIDs and buffers without validation. The caller +* is responsible for that. +* +* API wrapper functions: +* hfa384x_cmd_xxx functions that provide access to the f/w commands. +* The function arguments correspond to each command +* argument, even command arguments that get packed +* into single registers. These functions _just_ +* issue the command by setting the cmd/parm regs +* & reading the status/resp regs. Additional +* activities required to fully use a command +* (read/write from/to bap, get/set int status etc.) +* are implemented separately. Think of these as +* C-callable prism2 commands. +* +* Lowest Layer Functions: +* hfa384x_docmd_xxx These functions implement the sequence required +* to issue any prism2 command. Primarily used by the +* hfa384x_cmd_xxx functions. +* +* hfa384x_bap_xxx BAP read/write access functions. +* Note: we usually use BAP0 for non-interrupt context +* and BAP1 for interrupt context. +* +* hfa384x_dl_xxx download related functions. +* +* Driver State Issues: +* Note that there are two pairs of functions that manage the +* 'initialized' and 'running' states of the hw/MAC combo. The four +* functions are create(), destroy(), start(), and stop(). create() +* sets up the data structures required to support the hfa384x_* +* functions and destroy() cleans them up. The start() function gets +* the actual hardware running and enables the interrupts. The stop() +* function shuts the hardware down. The sequence should be: +* create() +* start() +* . +* . Do interesting things w/ the hardware +* . +* stop() +* destroy() +* +* Note that destroy() can be called without calling stop() first. +* -------------------------------------------------------------------- +*/ + +/*================================================================*/ +/* System Includes */ +#define WLAN_DBVAR prism2_debug + +#include + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if (WLAN_HOSTIF != WLAN_USB) +#error "This file is specific to USB" +#endif + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) +static int +wait_for_completion_interruptible(struct completion *x) +{ + int ret = 0; + + might_sleep(); + + spin_lock_irq(&x->wait.lock); + if (!x->done) { + DECLARE_WAITQUEUE(wait, current); + + wait.flags |= WQ_FLAG_EXCLUSIVE; + __add_wait_queue_tail(&x->wait, &wait); + do { + if (signal_pending(current)) { + ret = -ERESTARTSYS; + __remove_wait_queue(&x->wait, &wait); + goto out; + } + __set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irq(&x->wait.lock); + schedule(); + spin_lock_irq(&x->wait.lock); + } while (!x->done); + __remove_wait_queue(&x->wait, &wait); + } + x->done--; +out: + spin_unlock_irq(&x->wait.lock); + + return ret; +} +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,69) +static void +usb_init_urb(struct urb *urb) +{ + memset(urb, 0, sizeof(*urb)); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) /* tune me! */ + urb->count = (atomic_t)ATOMIC_INIT(1); +#endif + spin_lock_init(&urb->lock); +} +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) /* tune me! */ +# define SUBMIT_URB(u,f) usb_submit_urb(u,f) +#else +# define SUBMIT_URB(u,f) usb_submit_urb(u) +#endif + +/*================================================================*/ +/* Project Includes */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*================================================================*/ +/* Local Constants */ + +enum cmd_mode +{ + DOWAIT = 0, + DOASYNC +}; +typedef enum cmd_mode CMD_MODE; + +#define THROTTLE_JIFFIES (HZ/8) + +/*================================================================*/ +/* Local Macros */ + +#define ROUNDUP64(a) (((a)+63)&~63) + +/*================================================================*/ +/* Local Types */ + +/*================================================================*/ +/* Local Static Definitions */ +extern int prism2_debug; + +/*================================================================*/ +/* Local Function Declarations */ + +#ifdef DEBUG_USB +static void +dbprint_urb(struct urb* urb); +#endif + +static void +hfa384x_int_rxmonitor( + wlandevice_t *wlandev, + hfa384x_usb_rxfrm_t *rxfrm); + +static void +hfa384x_usb_defer(struct work_struct *data); + +static int +submit_rx_urb(hfa384x_t *hw, gfp_t flags); + +static int +submit_tx_urb(hfa384x_t *hw, struct urb *tx_urb, gfp_t flags); + +/*---------------------------------------------------*/ +/* Callbacks */ +#ifdef URB_ONLY_CALLBACK +static void +hfa384x_usbout_callback(struct urb *urb); +static void +hfa384x_ctlxout_callback(struct urb *urb); +static void +hfa384x_usbin_callback(struct urb *urb); +#else +static void +hfa384x_usbout_callback(struct urb *urb, struct pt_regs *regs); +static void +hfa384x_ctlxout_callback(struct urb *urb, struct pt_regs *regs); +static void +hfa384x_usbin_callback(struct urb *urb, struct pt_regs *regs); +#endif + +static void +hfa384x_usbin_txcompl(wlandevice_t *wlandev, hfa384x_usbin_t *usbin); + +static void +hfa384x_usbin_rx(wlandevice_t *wlandev, struct sk_buff *skb); + +static void +hfa384x_usbin_info(wlandevice_t *wlandev, hfa384x_usbin_t *usbin); + +static void +hfa384x_usbout_tx(wlandevice_t *wlandev, hfa384x_usbout_t *usbout); + +static void hfa384x_usbin_ctlx(hfa384x_t *hw, hfa384x_usbin_t *usbin, + int urb_status); + +/*---------------------------------------------------*/ +/* Functions to support the prism2 usb command queue */ + +static void +hfa384x_usbctlxq_run(hfa384x_t *hw); + +static void +hfa384x_usbctlx_reqtimerfn(unsigned long data); + +static void +hfa384x_usbctlx_resptimerfn(unsigned long data); + +static void +hfa384x_usb_throttlefn(unsigned long data); + +static void +hfa384x_usbctlx_completion_task(unsigned long data); + +static void +hfa384x_usbctlx_reaper_task(unsigned long data); + +static int +hfa384x_usbctlx_submit(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx); + +static void +unlocked_usbctlx_complete(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx); + +struct usbctlx_completor +{ + int (*complete)(struct usbctlx_completor*); +}; +typedef struct usbctlx_completor usbctlx_completor_t; + +static int +hfa384x_usbctlx_complete_sync(hfa384x_t *hw, + hfa384x_usbctlx_t *ctlx, + usbctlx_completor_t *completor); + +static int +unlocked_usbctlx_cancel_async(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx); + +static void +hfa384x_cb_status(hfa384x_t *hw, const hfa384x_usbctlx_t *ctlx); + +static void +hfa384x_cb_rrid(hfa384x_t *hw, const hfa384x_usbctlx_t *ctlx); + +static int +usbctlx_get_status(const hfa384x_usb_cmdresp_t *cmdresp, + hfa384x_cmdresult_t *result); + +static void +usbctlx_get_rridresult(const hfa384x_usb_rridresp_t *rridresp, + hfa384x_rridresult_t *result); + +/*---------------------------------------------------*/ +/* Low level req/resp CTLX formatters and submitters */ +static int +hfa384x_docmd( + hfa384x_t *hw, + CMD_MODE mode, + hfa384x_metacmd_t *cmd, + ctlx_cmdcb_t cmdcb, + ctlx_usercb_t usercb, + void *usercb_data); + +static int +hfa384x_dorrid( + hfa384x_t *hw, + CMD_MODE mode, + UINT16 rid, + void *riddata, + UINT riddatalen, + ctlx_cmdcb_t cmdcb, + ctlx_usercb_t usercb, + void *usercb_data); + +static int +hfa384x_dowrid( + hfa384x_t *hw, + CMD_MODE mode, + UINT16 rid, + void *riddata, + UINT riddatalen, + ctlx_cmdcb_t cmdcb, + ctlx_usercb_t usercb, + void *usercb_data); + +static int +hfa384x_dormem( + hfa384x_t *hw, + CMD_MODE mode, + UINT16 page, + UINT16 offset, + void *data, + UINT len, + ctlx_cmdcb_t cmdcb, + ctlx_usercb_t usercb, + void *usercb_data); + +static int +hfa384x_dowmem( + hfa384x_t *hw, + CMD_MODE mode, + UINT16 page, + UINT16 offset, + void *data, + UINT len, + ctlx_cmdcb_t cmdcb, + ctlx_usercb_t usercb, + void *usercb_data); + +static int +hfa384x_isgood_pdrcode(UINT16 pdrcode); + +/*================================================================*/ +/* Function Definitions */ +static inline const char* ctlxstr(CTLX_STATE s) +{ + static const char* ctlx_str[] = { + "Initial state", + "Complete", + "Request failed", + "Request pending", + "Request packet submitted", + "Request packet completed", + "Response packet completed" + }; + + return ctlx_str[s]; +}; + + +static inline hfa384x_usbctlx_t* +get_active_ctlx(hfa384x_t *hw) +{ + return list_entry(hw->ctlxq.active.next, hfa384x_usbctlx_t, list); +} + + +#ifdef DEBUG_USB +void +dbprint_urb(struct urb* urb) +{ + WLAN_LOG_DEBUG(3,"urb->pipe=0x%08x\n", urb->pipe); + WLAN_LOG_DEBUG(3,"urb->status=0x%08x\n", urb->status); + WLAN_LOG_DEBUG(3,"urb->transfer_flags=0x%08x\n", urb->transfer_flags); + WLAN_LOG_DEBUG(3,"urb->transfer_buffer=0x%08x\n", (UINT)urb->transfer_buffer); + WLAN_LOG_DEBUG(3,"urb->transfer_buffer_length=0x%08x\n", urb->transfer_buffer_length); + WLAN_LOG_DEBUG(3,"urb->actual_length=0x%08x\n", urb->actual_length); + WLAN_LOG_DEBUG(3,"urb->bandwidth=0x%08x\n", urb->bandwidth); + WLAN_LOG_DEBUG(3,"urb->setup_packet(ctl)=0x%08x\n", (UINT)urb->setup_packet); + WLAN_LOG_DEBUG(3,"urb->start_frame(iso/irq)=0x%08x\n", urb->start_frame); + WLAN_LOG_DEBUG(3,"urb->interval(irq)=0x%08x\n", urb->interval); + WLAN_LOG_DEBUG(3,"urb->error_count(iso)=0x%08x\n", urb->error_count); + WLAN_LOG_DEBUG(3,"urb->timeout=0x%08x\n", urb->timeout); + WLAN_LOG_DEBUG(3,"urb->context=0x%08x\n", (UINT)urb->context); + WLAN_LOG_DEBUG(3,"urb->complete=0x%08x\n", (UINT)urb->complete); +} +#endif + + +/*---------------------------------------------------------------- +* submit_rx_urb +* +* Listen for input data on the BULK-IN pipe. If the pipe has +* stalled then schedule it to be reset. +* +* Arguments: +* hw device struct +* memflags memory allocation flags +* +* Returns: +* error code from submission +* +* Call context: +* Any +----------------------------------------------------------------*/ +static int +submit_rx_urb(hfa384x_t *hw, gfp_t memflags) +{ + struct sk_buff *skb; + int result; + + DBFENTER; + + skb = dev_alloc_skb(sizeof(hfa384x_usbin_t)); + if (skb == NULL) { + result = -ENOMEM; + goto done; + } + + /* Post the IN urb */ + usb_fill_bulk_urb(&hw->rx_urb, hw->usb, + hw->endp_in, + skb->data, sizeof(hfa384x_usbin_t), + hfa384x_usbin_callback, hw->wlandev); + + hw->rx_urb_skb = skb; + + result = -ENOLINK; + if ( !hw->wlandev->hwremoved && !test_bit(WORK_RX_HALT, &hw->usb_flags)) { + result = SUBMIT_URB(&hw->rx_urb, memflags); + + /* Check whether we need to reset the RX pipe */ + if (result == -EPIPE) { + WLAN_LOG_WARNING("%s rx pipe stalled: requesting reset\n", + hw->wlandev->netdev->name); + if ( !test_and_set_bit(WORK_RX_HALT, &hw->usb_flags) ) + schedule_work(&hw->usb_work); + } + } + + /* Don't leak memory if anything should go wrong */ + if (result != 0) { + dev_kfree_skb(skb); + hw->rx_urb_skb = NULL; + } + + done: + + DBFEXIT; + return result; +} + +/*---------------------------------------------------------------- +* submit_tx_urb +* +* Prepares and submits the URB of transmitted data. If the +* submission fails then it will schedule the output pipe to +* be reset. +* +* Arguments: +* hw device struct +* tx_urb URB of data for tranmission +* memflags memory allocation flags +* +* Returns: +* error code from submission +* +* Call context: +* Any +----------------------------------------------------------------*/ +static int +submit_tx_urb(hfa384x_t *hw, struct urb *tx_urb, gfp_t memflags) +{ + struct net_device *netdev = hw->wlandev->netdev; + int result; + + DBFENTER; + + result = -ENOLINK; + if ( netif_running(netdev) ) { + + if ( !hw->wlandev->hwremoved && !test_bit(WORK_TX_HALT, &hw->usb_flags) ) { + result = SUBMIT_URB(tx_urb, memflags); + + /* Test whether we need to reset the TX pipe */ + if (result == -EPIPE) { + WLAN_LOG_WARNING("%s tx pipe stalled: requesting reset\n", + netdev->name); + set_bit(WORK_TX_HALT, &hw->usb_flags); + schedule_work(&hw->usb_work); + } else if (result == 0) { + netif_stop_queue(netdev); + } + } + } + + DBFEXIT; + + return result; +} + +/*---------------------------------------------------------------- +* hfa394x_usb_defer +* +* There are some things that the USB stack cannot do while +* in interrupt context, so we arrange this function to run +* in process context. +* +* Arguments: +* hw device structure +* +* Returns: +* nothing +* +* Call context: +* process (by design) +----------------------------------------------------------------*/ +static void +hfa384x_usb_defer(struct work_struct *data) +{ + hfa384x_t *hw = container_of(data, struct hfa384x, usb_work); + struct net_device *netdev = hw->wlandev->netdev; + + DBFENTER; + + /* Don't bother trying to reset anything if the plug + * has been pulled ... + */ + if ( hw->wlandev->hwremoved ) { + DBFEXIT; + return; + } + + /* Reception has stopped: try to reset the input pipe */ + if (test_bit(WORK_RX_HALT, &hw->usb_flags)) { + int ret; + + usb_kill_urb(&hw->rx_urb); /* Cannot be holding spinlock! */ + + ret = usb_clear_halt(hw->usb, hw->endp_in); + if (ret != 0) { + printk(KERN_ERR + "Failed to clear rx pipe for %s: err=%d\n", + netdev->name, ret); + } else { + printk(KERN_INFO "%s rx pipe reset complete.\n", + netdev->name); + clear_bit(WORK_RX_HALT, &hw->usb_flags); + set_bit(WORK_RX_RESUME, &hw->usb_flags); + } + } + + /* Resume receiving data back from the device. */ + if ( test_bit(WORK_RX_RESUME, &hw->usb_flags) ) { + int ret; + + ret = submit_rx_urb(hw, GFP_KERNEL); + if (ret != 0) { + printk(KERN_ERR + "Failed to resume %s rx pipe.\n", netdev->name); + } else { + clear_bit(WORK_RX_RESUME, &hw->usb_flags); + } + } + + /* Transmission has stopped: try to reset the output pipe */ + if (test_bit(WORK_TX_HALT, &hw->usb_flags)) { + int ret; + + usb_kill_urb(&hw->tx_urb); + ret = usb_clear_halt(hw->usb, hw->endp_out); + if (ret != 0) { + printk(KERN_ERR + "Failed to clear tx pipe for %s: err=%d\n", + netdev->name, ret); + } else { + printk(KERN_INFO "%s tx pipe reset complete.\n", + netdev->name); + clear_bit(WORK_TX_HALT, &hw->usb_flags); + set_bit(WORK_TX_RESUME, &hw->usb_flags); + + /* Stopping the BULK-OUT pipe also blocked + * us from sending any more CTLX URBs, so + * we need to re-run our queue ... + */ + hfa384x_usbctlxq_run(hw); + } + } + + /* Resume transmitting. */ + if ( test_and_clear_bit(WORK_TX_RESUME, &hw->usb_flags) ) { + p80211netdev_wake_queue(hw->wlandev); + } + + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* hfa384x_create +* +* Sets up the hfa384x_t data structure for use. Note this +* does _not_ intialize the actual hardware, just the data structures +* we use to keep track of its state. +* +* Arguments: +* hw device structure +* irq device irq number +* iobase i/o base address for register access +* membase memory base address for register access +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +void +hfa384x_create( hfa384x_t *hw, struct usb_device *usb) +{ + DBFENTER; + + memset(hw, 0, sizeof(hfa384x_t)); + hw->usb = usb; + + /* set up the endpoints */ + hw->endp_in = usb_rcvbulkpipe(usb, 1); + hw->endp_out = usb_sndbulkpipe(usb, 2); + + /* Set up the waitq */ + init_waitqueue_head(&hw->cmdq); + + /* Initialize the command queue */ + spin_lock_init(&hw->ctlxq.lock); + INIT_LIST_HEAD(&hw->ctlxq.pending); + INIT_LIST_HEAD(&hw->ctlxq.active); + INIT_LIST_HEAD(&hw->ctlxq.completing); + INIT_LIST_HEAD(&hw->ctlxq.reapable); + + /* Initialize the authentication queue */ + skb_queue_head_init(&hw->authq); + + tasklet_init(&hw->reaper_bh, + hfa384x_usbctlx_reaper_task, + (unsigned long)hw); + tasklet_init(&hw->completion_bh, + hfa384x_usbctlx_completion_task, + (unsigned long)hw); + INIT_WORK2(&hw->link_bh, prism2sta_processing_defer); + INIT_WORK2(&hw->usb_work, hfa384x_usb_defer); + + init_timer(&hw->throttle); + hw->throttle.function = hfa384x_usb_throttlefn; + hw->throttle.data = (unsigned long)hw; + + init_timer(&hw->resptimer); + hw->resptimer.function = hfa384x_usbctlx_resptimerfn; + hw->resptimer.data = (unsigned long)hw; + + init_timer(&hw->reqtimer); + hw->reqtimer.function = hfa384x_usbctlx_reqtimerfn; + hw->reqtimer.data = (unsigned long)hw; + + usb_init_urb(&hw->rx_urb); + usb_init_urb(&hw->tx_urb); + usb_init_urb(&hw->ctlx_urb); + + hw->link_status = HFA384x_LINK_NOTCONNECTED; + hw->state = HFA384x_STATE_INIT; + + INIT_WORK2(&hw->commsqual_bh, prism2sta_commsqual_defer); + init_timer(&hw->commsqual_timer); + hw->commsqual_timer.data = (unsigned long) hw; + hw->commsqual_timer.function = prism2sta_commsqual_timer; + + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* hfa384x_destroy +* +* Partner to hfa384x_create(). This function cleans up the hw +* structure so that it can be freed by the caller using a simple +* kfree. Currently, this function is just a placeholder. If, at some +* point in the future, an hw in the 'shutdown' state requires a 'deep' +* kfree, this is where it should be done. Note that if this function +* is called on a _running_ hw structure, the drvr_stop() function is +* called. +* +* Arguments: +* hw device structure +* +* Returns: +* nothing, this function is not allowed to fail. +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +void +hfa384x_destroy( hfa384x_t *hw) +{ + struct sk_buff *skb; + + DBFENTER; + + if ( hw->state == HFA384x_STATE_RUNNING ) { + hfa384x_drvr_stop(hw); + } + hw->state = HFA384x_STATE_PREINIT; + + if (hw->scanresults) { + kfree(hw->scanresults); + hw->scanresults = NULL; + } + + /* Now to clean out the auth queue */ + while ( (skb = skb_dequeue(&hw->authq)) ) { + dev_kfree_skb(skb); + } + + DBFEXIT; +} + + +/*---------------------------------------------------------------- + */ +static hfa384x_usbctlx_t* usbctlx_alloc(void) +{ + hfa384x_usbctlx_t *ctlx; + + ctlx = kmalloc(sizeof(*ctlx), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); + if (ctlx != NULL) + { + memset(ctlx, 0, sizeof(*ctlx)); + init_completion(&ctlx->done); + } + + return ctlx; +} + + +/*---------------------------------------------------------------- + * +----------------------------------------------------------------*/ +static int +usbctlx_get_status(const hfa384x_usb_cmdresp_t *cmdresp, + hfa384x_cmdresult_t *result) +{ + DBFENTER; + + result->status = hfa384x2host_16(cmdresp->status); + result->resp0 = hfa384x2host_16(cmdresp->resp0); + result->resp1 = hfa384x2host_16(cmdresp->resp1); + result->resp2 = hfa384x2host_16(cmdresp->resp2); + + WLAN_LOG_DEBUG(4, "cmdresult:status=0x%04x " + "resp0=0x%04x resp1=0x%04x resp2=0x%04x\n", + result->status, + result->resp0, + result->resp1, + result->resp2); + + DBFEXIT; + return (result->status & HFA384x_STATUS_RESULT); +} + +static void +usbctlx_get_rridresult(const hfa384x_usb_rridresp_t *rridresp, + hfa384x_rridresult_t *result) +{ + DBFENTER; + + result->rid = hfa384x2host_16(rridresp->rid); + result->riddata = rridresp->data; + result->riddata_len = ((hfa384x2host_16(rridresp->frmlen) - 1) * 2); + + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* Completor object: +* This completor must be passed to hfa384x_usbctlx_complete_sync() +* when processing a CTLX that returns a hfa384x_cmdresult_t structure. +----------------------------------------------------------------*/ +struct usbctlx_cmd_completor +{ + usbctlx_completor_t head; + + const hfa384x_usb_cmdresp_t *cmdresp; + hfa384x_cmdresult_t *result; +}; +typedef struct usbctlx_cmd_completor usbctlx_cmd_completor_t; + +static int usbctlx_cmd_completor_fn(usbctlx_completor_t *head) +{ + usbctlx_cmd_completor_t *complete = (usbctlx_cmd_completor_t*)head; + return usbctlx_get_status(complete->cmdresp, complete->result); +} + +static inline usbctlx_completor_t* +init_cmd_completor(usbctlx_cmd_completor_t *completor, + const hfa384x_usb_cmdresp_t *cmdresp, + hfa384x_cmdresult_t *result) +{ + completor->head.complete = usbctlx_cmd_completor_fn; + completor->cmdresp = cmdresp; + completor->result = result; + return &(completor->head); +} + +/*---------------------------------------------------------------- +* Completor object: +* This completor must be passed to hfa384x_usbctlx_complete_sync() +* when processing a CTLX that reads a RID. +----------------------------------------------------------------*/ +struct usbctlx_rrid_completor +{ + usbctlx_completor_t head; + + const hfa384x_usb_rridresp_t *rridresp; + void *riddata; + UINT riddatalen; +}; +typedef struct usbctlx_rrid_completor usbctlx_rrid_completor_t; + +static int usbctlx_rrid_completor_fn(usbctlx_completor_t *head) +{ + usbctlx_rrid_completor_t *complete = (usbctlx_rrid_completor_t*)head; + hfa384x_rridresult_t rridresult; + + usbctlx_get_rridresult(complete->rridresp, &rridresult); + + /* Validate the length, note body len calculation in bytes */ + if ( rridresult.riddata_len != complete->riddatalen ) { + WLAN_LOG_WARNING( + "RID len mismatch, rid=0x%04x hlen=%d fwlen=%d\n", + rridresult.rid, + complete->riddatalen, + rridresult.riddata_len); + return -ENODATA; + } + + memcpy(complete->riddata, + rridresult.riddata, + complete->riddatalen); + return 0; +} + +static inline usbctlx_completor_t* +init_rrid_completor(usbctlx_rrid_completor_t *completor, + const hfa384x_usb_rridresp_t *rridresp, + void *riddata, + UINT riddatalen) +{ + completor->head.complete = usbctlx_rrid_completor_fn; + completor->rridresp = rridresp; + completor->riddata = riddata; + completor->riddatalen = riddatalen; + return &(completor->head); +} + +/*---------------------------------------------------------------- +* Completor object: +* Interprets the results of a synchronous RID-write +----------------------------------------------------------------*/ +typedef usbctlx_cmd_completor_t usbctlx_wrid_completor_t; +#define init_wrid_completor init_cmd_completor + +/*---------------------------------------------------------------- +* Completor object: +* Interprets the results of a synchronous memory-write +----------------------------------------------------------------*/ +typedef usbctlx_cmd_completor_t usbctlx_wmem_completor_t; +#define init_wmem_completor init_cmd_completor + +/*---------------------------------------------------------------- +* Completor object: +* Interprets the results of a synchronous memory-read +----------------------------------------------------------------*/ +struct usbctlx_rmem_completor +{ + usbctlx_completor_t head; + + const hfa384x_usb_rmemresp_t *rmemresp; + void *data; + UINT len; +}; +typedef struct usbctlx_rmem_completor usbctlx_rmem_completor_t; + +static int usbctlx_rmem_completor_fn(usbctlx_completor_t *head) +{ + usbctlx_rmem_completor_t *complete = (usbctlx_rmem_completor_t*)head; + + WLAN_LOG_DEBUG(4,"rmemresp:len=%d\n", complete->rmemresp->frmlen); + memcpy(complete->data, complete->rmemresp->data, complete->len); + return 0; +} + +static inline usbctlx_completor_t* +init_rmem_completor(usbctlx_rmem_completor_t *completor, + hfa384x_usb_rmemresp_t *rmemresp, + void *data, + UINT len) +{ + completor->head.complete = usbctlx_rmem_completor_fn; + completor->rmemresp = rmemresp; + completor->data = data; + completor->len = len; + return &(completor->head); +} + +/*---------------------------------------------------------------- +* hfa384x_cb_status +* +* Ctlx_complete handler for async CMD type control exchanges. +* mark the hw struct as such. +* +* Note: If the handling is changed here, it should probably be +* changed in docmd as well. +* +* Arguments: +* hw hw struct +* ctlx completed CTLX +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void +hfa384x_cb_status(hfa384x_t *hw, const hfa384x_usbctlx_t *ctlx) +{ + DBFENTER; + + if ( ctlx->usercb != NULL ) { + hfa384x_cmdresult_t cmdresult; + + if (ctlx->state != CTLX_COMPLETE) { + memset(&cmdresult, 0, sizeof(cmdresult)); + cmdresult.status = HFA384x_STATUS_RESULT_SET(HFA384x_CMD_ERR); + } else { + usbctlx_get_status(&ctlx->inbuf.cmdresp, &cmdresult); + } + + ctlx->usercb(hw, &cmdresult, ctlx->usercb_data); + } + + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* hfa384x_cb_rrid +* +* CTLX completion handler for async RRID type control exchanges. +* +* Note: If the handling is changed here, it should probably be +* changed in dorrid as well. +* +* Arguments: +* hw hw struct +* ctlx completed CTLX +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void +hfa384x_cb_rrid(hfa384x_t *hw, const hfa384x_usbctlx_t *ctlx) +{ + DBFENTER; + + if ( ctlx->usercb != NULL ) { + hfa384x_rridresult_t rridresult; + + if (ctlx->state != CTLX_COMPLETE) { + memset(&rridresult, 0, sizeof(rridresult)); + rridresult.rid = hfa384x2host_16(ctlx->outbuf.rridreq.rid); + } else { + usbctlx_get_rridresult(&ctlx->inbuf.rridresp, &rridresult); + } + + ctlx->usercb(hw, &rridresult, ctlx->usercb_data); + } + + DBFEXIT; +} + +static inline int +hfa384x_docmd_wait(hfa384x_t *hw, hfa384x_metacmd_t *cmd) +{ + return hfa384x_docmd(hw, DOWAIT, cmd, NULL, NULL, NULL); +} + +static inline int +hfa384x_docmd_async(hfa384x_t *hw, + hfa384x_metacmd_t *cmd, + ctlx_cmdcb_t cmdcb, + ctlx_usercb_t usercb, + void *usercb_data) +{ + return hfa384x_docmd(hw, DOASYNC, cmd, + cmdcb, usercb, usercb_data); +} + +static inline int +hfa384x_dorrid_wait(hfa384x_t *hw, UINT16 rid, void *riddata, UINT riddatalen) +{ + return hfa384x_dorrid(hw, DOWAIT, + rid, riddata, riddatalen, + NULL, NULL, NULL); +} + +static inline int +hfa384x_dorrid_async(hfa384x_t *hw, + UINT16 rid, void *riddata, UINT riddatalen, + ctlx_cmdcb_t cmdcb, + ctlx_usercb_t usercb, + void *usercb_data) +{ + return hfa384x_dorrid(hw, DOASYNC, + rid, riddata, riddatalen, + cmdcb, usercb, usercb_data); +} + +static inline int +hfa384x_dowrid_wait(hfa384x_t *hw, UINT16 rid, void *riddata, UINT riddatalen) +{ + return hfa384x_dowrid(hw, DOWAIT, + rid, riddata, riddatalen, + NULL, NULL, NULL); +} + +static inline int +hfa384x_dowrid_async(hfa384x_t *hw, + UINT16 rid, void *riddata, UINT riddatalen, + ctlx_cmdcb_t cmdcb, + ctlx_usercb_t usercb, + void *usercb_data) +{ + return hfa384x_dowrid(hw, DOASYNC, + rid, riddata, riddatalen, + cmdcb, usercb, usercb_data); +} + +static inline int +hfa384x_dormem_wait(hfa384x_t *hw, + UINT16 page, UINT16 offset, void *data, UINT len) +{ + return hfa384x_dormem(hw, DOWAIT, + page, offset, data, len, + NULL, NULL, NULL); +} + +static inline int +hfa384x_dormem_async(hfa384x_t *hw, + UINT16 page, UINT16 offset, void *data, UINT len, + ctlx_cmdcb_t cmdcb, + ctlx_usercb_t usercb, + void *usercb_data) +{ + return hfa384x_dormem(hw, DOASYNC, + page, offset, data, len, + cmdcb, usercb, usercb_data); +} + +static inline int +hfa384x_dowmem_wait( + hfa384x_t *hw, + UINT16 page, + UINT16 offset, + void *data, + UINT len) +{ + return hfa384x_dowmem(hw, DOWAIT, + page, offset, data, len, + NULL, NULL, NULL); +} + +static inline int +hfa384x_dowmem_async( + hfa384x_t *hw, + UINT16 page, + UINT16 offset, + void *data, + UINT len, + ctlx_cmdcb_t cmdcb, + ctlx_usercb_t usercb, + void *usercb_data) +{ + return hfa384x_dowmem(hw, DOASYNC, + page, offset, data, len, + cmdcb, usercb, usercb_data); +} + +/*---------------------------------------------------------------- +* hfa384x_cmd_initialize +* +* Issues the initialize command and sets the hw->state based +* on the result. +* +* Arguments: +* hw device structure +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int +hfa384x_cmd_initialize(hfa384x_t *hw) +{ + int result = 0; + int i; + hfa384x_metacmd_t cmd; + + DBFENTER; + + + cmd.cmd = HFA384x_CMDCODE_INIT; + cmd.parm0 = 0; + cmd.parm1 = 0; + cmd.parm2 = 0; + + result = hfa384x_docmd_wait(hw, &cmd); + + + WLAN_LOG_DEBUG(3,"cmdresp.init: " + "status=0x%04x, resp0=0x%04x, " + "resp1=0x%04x, resp2=0x%04x\n", + cmd.result.status, + cmd.result.resp0, + cmd.result.resp1, + cmd.result.resp2); + if ( result == 0 ) { + for ( i = 0; i < HFA384x_NUMPORTS_MAX; i++) { + hw->port_enabled[i] = 0; + } + } + + hw->link_status = HFA384x_LINK_NOTCONNECTED; + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_cmd_disable +* +* Issues the disable command to stop communications on one of +* the MACs 'ports'. +* +* Arguments: +* hw device structure +* macport MAC port number (host order) +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int hfa384x_cmd_disable(hfa384x_t *hw, UINT16 macport) +{ + int result = 0; + hfa384x_metacmd_t cmd; + + DBFENTER; + + cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_DISABLE) | + HFA384x_CMD_MACPORT_SET(macport); + cmd.parm0 = 0; + cmd.parm1 = 0; + cmd.parm2 = 0; + + result = hfa384x_docmd_wait(hw, &cmd); + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_cmd_enable +* +* Issues the enable command to enable communications on one of +* the MACs 'ports'. +* +* Arguments: +* hw device structure +* macport MAC port number +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int hfa384x_cmd_enable(hfa384x_t *hw, UINT16 macport) +{ + int result = 0; + hfa384x_metacmd_t cmd; + + DBFENTER; + + cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ENABLE) | + HFA384x_CMD_MACPORT_SET(macport); + cmd.parm0 = 0; + cmd.parm1 = 0; + cmd.parm2 = 0; + + result = hfa384x_docmd_wait(hw, &cmd); + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_cmd_notify +* +* Sends an info frame to the firmware to alter the behavior +* of the f/w asynch processes. Can only be called when the MAC +* is in the enabled state. +* +* Arguments: +* hw device structure +* reclaim [0|1] indicates whether the given FID will +* be handed back (via Alloc event) for reuse. +* (host order) +* fid FID of buffer containing the frame that was +* previously copied to MAC memory via the bap. +* (host order) +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* hw->resp0 will contain the FID being used by async notify +* process. If reclaim==0, resp0 will be the same as the fid +* argument. If reclaim==1, resp0 will be the different. +* +* Call context: +* process +----------------------------------------------------------------*/ +int hfa384x_cmd_notify(hfa384x_t *hw, UINT16 reclaim, UINT16 fid, + void *buf, UINT16 len) +{ +#if 0 + int result = 0; + UINT16 cmd; + DBFENTER; + cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_NOTIFY) | + HFA384x_CMD_RECL_SET(reclaim); + result = hfa384x_docmd_wait(hw, cmd); + + DBFEXIT; + return result; +#endif +return 0; +} + + +#if 0 +/*---------------------------------------------------------------- +* hfa384x_cmd_inquiry +* +* Requests an info frame from the firmware. The info frame will +* be delivered asynchronously via the Info event. +* +* Arguments: +* hw device structure +* fid FID of the info frame requested. (host order) +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int hfa384x_cmd_inquiry(hfa384x_t *hw, UINT16 fid) +{ + int result = 0; + hfa384x_metacmd_t cmd; + + DBFENTER; + + cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_INQ); + cmd.parm0 = 0; + cmd.parm1 = 0; + cmd.parm2 = 0; + + result = hfa384x_docmd_wait(hw, &cmd); + + DBFEXIT; + return result; +} +#endif + + +/*---------------------------------------------------------------- +* hfa384x_cmd_monitor +* +* Enables the 'monitor mode' of the MAC. Here's the description of +* monitor mode that I've received thus far: +* +* "The "monitor mode" of operation is that the MAC passes all +* frames for which the PLCP checks are correct. All received +* MPDUs are passed to the host with MAC Port = 7, with a +* receive status of good, FCS error, or undecryptable. Passing +* certain MPDUs is a violation of the 802.11 standard, but useful +* for a debugging tool." Normal communication is not possible +* while monitor mode is enabled. +* +* Arguments: +* hw device structure +* enable a code (0x0b|0x0f) that enables/disables +* monitor mode. (host order) +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int hfa384x_cmd_monitor(hfa384x_t *hw, UINT16 enable) +{ + int result = 0; + hfa384x_metacmd_t cmd; + + DBFENTER; + + cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_MONITOR) | + HFA384x_CMD_AINFO_SET(enable); + cmd.parm0 = 0; + cmd.parm1 = 0; + cmd.parm2 = 0; + + result = hfa384x_docmd_wait(hw, &cmd); + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_cmd_download +* +* Sets the controls for the MAC controller code/data download +* process. The arguments set the mode and address associated +* with a download. Note that the aux registers should be enabled +* prior to setting one of the download enable modes. +* +* Arguments: +* hw device structure +* mode 0 - Disable programming and begin code exec +* 1 - Enable volatile mem programming +* 2 - Enable non-volatile mem programming +* 3 - Program non-volatile section from NV download +* buffer. +* (host order) +* lowaddr +* highaddr For mode 1, sets the high & low order bits of +* the "destination address". This address will be +* the execution start address when download is +* subsequently disabled. +* For mode 2, sets the high & low order bits of +* the destination in NV ram. +* For modes 0 & 3, should be zero. (host order) +* NOTE: these are CMD format. +* codelen Length of the data to write in mode 2, +* zero otherwise. (host order) +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int hfa384x_cmd_download(hfa384x_t *hw, UINT16 mode, UINT16 lowaddr, + UINT16 highaddr, UINT16 codelen) +{ + int result = 0; + hfa384x_metacmd_t cmd; + + DBFENTER; + WLAN_LOG_DEBUG(5, + "mode=%d, lowaddr=0x%04x, highaddr=0x%04x, codelen=%d\n", + mode, lowaddr, highaddr, codelen); + + cmd.cmd = (HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_DOWNLD) | + HFA384x_CMD_PROGMODE_SET(mode)); + + cmd.parm0 = lowaddr; + cmd.parm1 = highaddr; + cmd.parm2 = codelen; + + result = hfa384x_docmd_wait(hw, &cmd); + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_copy_from_aux +* +* Copies a collection of bytes from the controller memory. The +* Auxiliary port MUST be enabled prior to calling this function. +* We _might_ be in a download state. +* +* Arguments: +* hw device structure +* cardaddr address in hfa384x data space to read +* auxctl address space select +* buf ptr to destination host buffer +* len length of data to transfer (in bytes) +* +* Returns: +* nothing +* +* Side effects: +* buf contains the data copied +* +* Call context: +* process +* interrupt +----------------------------------------------------------------*/ +void +hfa384x_copy_from_aux( + hfa384x_t *hw, UINT32 cardaddr, UINT32 auxctl, void *buf, UINT len) +{ + DBFENTER; + WLAN_LOG_ERROR("not used in USB.\n"); + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* hfa384x_copy_to_aux +* +* Copies a collection of bytes to the controller memory. The +* Auxiliary port MUST be enabled prior to calling this function. +* We _might_ be in a download state. +* +* Arguments: +* hw device structure +* cardaddr address in hfa384x data space to read +* auxctl address space select +* buf ptr to destination host buffer +* len length of data to transfer (in bytes) +* +* Returns: +* nothing +* +* Side effects: +* Controller memory now contains a copy of buf +* +* Call context: +* process +* interrupt +----------------------------------------------------------------*/ +void +hfa384x_copy_to_aux( + hfa384x_t *hw, UINT32 cardaddr, UINT32 auxctl, void *buf, UINT len) +{ + DBFENTER; + WLAN_LOG_ERROR("not used in USB.\n"); + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* hfa384x_corereset +* +* Perform a reset of the hfa38xx MAC core. We assume that the hw +* structure is in its "created" state. That is, it is initialized +* with proper values. Note that if a reset is done after the +* device has been active for awhile, the caller might have to clean +* up some leftover cruft in the hw structure. +* +* Arguments: +* hw device structure +* holdtime how long (in ms) to hold the reset +* settletime how long (in ms) to wait after releasing +* the reset +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int hfa384x_corereset(hfa384x_t *hw, int holdtime, int settletime, int genesis) +{ +#if 0 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + struct usb_device *parent = hw->usb->parent; + int i; + int port = -1; +#endif +#endif + int result = 0; + + +#define P2_USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER) +#define P2_USB_FEAT_RESET 4 +#define P2_USB_FEAT_C_RESET 20 + + DBFENTER; + +#if 0 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + /* Find the hub port */ + for ( i = 0; i < parent->maxchild; i++) { + if (parent->children[i] == hw->usb) { + port = i; + break; + } + } + if (port < 0) return -ENOENT; + + /* Set and clear the reset */ + usb_control_msg(parent, usb_sndctrlpipe(parent, 0), + USB_REQ_SET_FEATURE, P2_USB_RT_PORT, P2_USB_FEAT_RESET, + port+1, NULL, 0, 1*HZ); + wait_ms(holdtime); + usb_control_msg(parent, usb_sndctrlpipe(parent, 0), + USB_REQ_CLEAR_FEATURE, P2_USB_RT_PORT, P2_USB_FEAT_C_RESET, + port+1, NULL, 0, 1*HZ); + wait_ms(settletime); + + /* Set the device address */ + result=usb_set_address(hw->usb); + if (result < 0) { + WLAN_LOG_ERROR("reset_usbdev: Dev not accepting address, " + "result=%d\n", result); + clear_bit(hw->usb->devnum, &hw->usb->bus->devmap.devicemap); + hw->usb->devnum = -1; + goto done; + } + /* Let the address settle */ + wait_ms(20); + + /* Assume we're reusing the original descriptor data */ + + /* Set the configuration. */ + WLAN_LOG_DEBUG(3, "Setting Configuration %d\n", + hw->usb->config[0].bConfigurationValue); + result=usb_set_configuration(hw->usb, hw->usb->config[0].bConfigurationValue); + if ( result ) { + WLAN_LOG_ERROR("usb_set_configuration() failed, result=%d.\n", + result); + goto done; + } + /* Let the configuration settle */ + wait_ms(20); + + done: +#else + result=usb_reset_device(hw->usb); + if(result<0) { + WLAN_LOG_ERROR("usb_reset_device() failed, result=%d.\n",result); + } +#endif +#endif + + result=usb_reset_device(hw->usb); + if(result<0) { + WLAN_LOG_ERROR("usb_reset_device() failed, result=%d.\n",result); + } + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_usbctlx_complete_sync +* +* Waits for a synchronous CTLX object to complete, +* and then handles the response. +* +* Arguments: +* hw device structure +* ctlx CTLX ptr +* completor functor object to decide what to +* do with the CTLX's result. +* +* Returns: +* 0 Success +* -ERESTARTSYS Interrupted by a signal +* -EIO CTLX failed +* -ENODEV Adapter was unplugged +* ??? Result from completor +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +static int hfa384x_usbctlx_complete_sync(hfa384x_t *hw, + hfa384x_usbctlx_t *ctlx, + usbctlx_completor_t *completor) +{ + unsigned long flags; + int result; + + DBFENTER; + + result = wait_for_completion_interruptible(&ctlx->done); + + spin_lock_irqsave(&hw->ctlxq.lock, flags); + + /* + * We can only handle the CTLX if the USB disconnect + * function has not run yet ... + */ + cleanup: + if ( hw->wlandev->hwremoved ) + { + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + result = -ENODEV; + } + else if ( result != 0 ) + { + int runqueue = 0; + + /* + * We were probably interrupted, so delete + * this CTLX asynchronously, kill the timers + * and the URB, and then start the next + * pending CTLX. + * + * NOTE: We can only delete the timers and + * the URB if this CTLX is active. + */ + if (ctlx == get_active_ctlx(hw)) + { + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + + del_singleshot_timer_sync(&hw->reqtimer); + del_singleshot_timer_sync(&hw->resptimer); + hw->req_timer_done = 1; + hw->resp_timer_done = 1; + usb_kill_urb(&hw->ctlx_urb); + + spin_lock_irqsave(&hw->ctlxq.lock, flags); + + runqueue = 1; + + /* + * This scenario is so unlikely that I'm + * happy with a grubby "goto" solution ... + */ + if ( hw->wlandev->hwremoved ) + goto cleanup; + } + + /* + * The completion task will send this CTLX + * to the reaper the next time it runs. We + * are no longer in a hurry. + */ + ctlx->reapable = 1; + ctlx->state = CTLX_REQ_FAILED; + list_move_tail(&ctlx->list, &hw->ctlxq.completing); + + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + + if (runqueue) + hfa384x_usbctlxq_run(hw); + } else { + if (ctlx->state == CTLX_COMPLETE) { + result = completor->complete(completor); + } else { + WLAN_LOG_WARNING("CTLX[%d] error: state(%s)\n", + hfa384x2host_16(ctlx->outbuf.type), + ctlxstr(ctlx->state)); + result = -EIO; + } + + list_del(&ctlx->list); + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + kfree(ctlx); + } + + DBFEXIT; + return result; +} + +/*---------------------------------------------------------------- +* hfa384x_docmd +* +* Constructs a command CTLX and submits it. +* +* NOTE: Any changes to the 'post-submit' code in this function +* need to be carried over to hfa384x_cbcmd() since the handling +* is virtually identical. +* +* Arguments: +* hw device structure +* mode DOWAIT or DOASYNC +* cmd cmd structure. Includes all arguments and result +* data points. All in host order. in host order +* cmdcb command-specific callback +* usercb user callback for async calls, NULL for DOWAIT calls +* usercb_data user supplied data pointer for async calls, NULL +* for DOASYNC calls +* +* Returns: +* 0 success +* -EIO CTLX failure +* -ERESTARTSYS Awakened on signal +* >0 command indicated error, Status and Resp0-2 are +* in hw structure. +* +* Side effects: +* +* +* Call context: +* process +----------------------------------------------------------------*/ +static int +hfa384x_docmd( + hfa384x_t *hw, + CMD_MODE mode, + hfa384x_metacmd_t *cmd, + ctlx_cmdcb_t cmdcb, + ctlx_usercb_t usercb, + void *usercb_data) +{ + int result; + hfa384x_usbctlx_t *ctlx; + + DBFENTER; + ctlx = usbctlx_alloc(); + if ( ctlx == NULL ) { + result = -ENOMEM; + goto done; + } + + /* Initialize the command */ + ctlx->outbuf.cmdreq.type = host2hfa384x_16(HFA384x_USB_CMDREQ); + ctlx->outbuf.cmdreq.cmd = host2hfa384x_16(cmd->cmd); + ctlx->outbuf.cmdreq.parm0 = host2hfa384x_16(cmd->parm0); + ctlx->outbuf.cmdreq.parm1 = host2hfa384x_16(cmd->parm1); + ctlx->outbuf.cmdreq.parm2 = host2hfa384x_16(cmd->parm2); + + ctlx->outbufsize = sizeof(ctlx->outbuf.cmdreq); + + WLAN_LOG_DEBUG(4, "cmdreq: cmd=0x%04x " + "parm0=0x%04x parm1=0x%04x parm2=0x%04x\n", + cmd->cmd, + cmd->parm0, + cmd->parm1, + cmd->parm2); + + ctlx->reapable = mode; + ctlx->cmdcb = cmdcb; + ctlx->usercb = usercb; + ctlx->usercb_data = usercb_data; + + result = hfa384x_usbctlx_submit(hw, ctlx); + if (result != 0) { + kfree(ctlx); + } else if (mode == DOWAIT) { + usbctlx_cmd_completor_t completor; + + result = hfa384x_usbctlx_complete_sync( + hw, ctlx, init_cmd_completor(&completor, + &ctlx->inbuf.cmdresp, + &cmd->result) ); + } + +done: + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_dorrid +* +* Constructs a read rid CTLX and issues it. +* +* NOTE: Any changes to the 'post-submit' code in this function +* need to be carried over to hfa384x_cbrrid() since the handling +* is virtually identical. +* +* Arguments: +* hw device structure +* mode DOWAIT or DOASYNC +* rid Read RID number (host order) +* riddata Caller supplied buffer that MAC formatted RID.data +* record will be written to for DOWAIT calls. Should +* be NULL for DOASYNC calls. +* riddatalen Buffer length for DOWAIT calls. Zero for DOASYNC calls. +* cmdcb command callback for async calls, NULL for DOWAIT calls +* usercb user callback for async calls, NULL for DOWAIT calls +* usercb_data user supplied data pointer for async calls, NULL +* for DOWAIT calls +* +* Returns: +* 0 success +* -EIO CTLX failure +* -ERESTARTSYS Awakened on signal +* -ENODATA riddatalen != macdatalen +* >0 command indicated error, Status and Resp0-2 are +* in hw structure. +* +* Side effects: +* +* Call context: +* interrupt (DOASYNC) +* process (DOWAIT or DOASYNC) +----------------------------------------------------------------*/ +static int +hfa384x_dorrid( + hfa384x_t *hw, + CMD_MODE mode, + UINT16 rid, + void *riddata, + UINT riddatalen, + ctlx_cmdcb_t cmdcb, + ctlx_usercb_t usercb, + void *usercb_data) +{ + int result; + hfa384x_usbctlx_t *ctlx; + + DBFENTER; + ctlx = usbctlx_alloc(); + if ( ctlx == NULL ) { + result = -ENOMEM; + goto done; + } + + /* Initialize the command */ + ctlx->outbuf.rridreq.type = host2hfa384x_16(HFA384x_USB_RRIDREQ); + ctlx->outbuf.rridreq.frmlen = + host2hfa384x_16(sizeof(ctlx->outbuf.rridreq.rid)); + ctlx->outbuf.rridreq.rid = host2hfa384x_16(rid); + + ctlx->outbufsize = sizeof(ctlx->outbuf.rridreq); + + ctlx->reapable = mode; + ctlx->cmdcb = cmdcb; + ctlx->usercb = usercb; + ctlx->usercb_data = usercb_data; + + /* Submit the CTLX */ + result = hfa384x_usbctlx_submit(hw, ctlx); + if (result != 0) { + kfree(ctlx); + } else if (mode == DOWAIT) { + usbctlx_rrid_completor_t completor; + + result = hfa384x_usbctlx_complete_sync( + hw, ctlx, init_rrid_completor(&completor, + &ctlx->inbuf.rridresp, + riddata, + riddatalen) ); + } + +done: + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_dowrid +* +* Constructs a write rid CTLX and issues it. +* +* NOTE: Any changes to the 'post-submit' code in this function +* need to be carried over to hfa384x_cbwrid() since the handling +* is virtually identical. +* +* Arguments: +* hw device structure +* CMD_MODE DOWAIT or DOASYNC +* rid RID code +* riddata Data portion of RID formatted for MAC +* riddatalen Length of the data portion in bytes +* cmdcb command callback for async calls, NULL for DOWAIT calls +* usercb user callback for async calls, NULL for DOWAIT calls +* usercb_data user supplied data pointer for async calls +* +* Returns: +* 0 success +* -ETIMEDOUT timed out waiting for register ready or +* command completion +* >0 command indicated error, Status and Resp0-2 are +* in hw structure. +* +* Side effects: +* +* Call context: +* interrupt (DOASYNC) +* process (DOWAIT or DOASYNC) +----------------------------------------------------------------*/ +static int +hfa384x_dowrid( + hfa384x_t *hw, + CMD_MODE mode, + UINT16 rid, + void *riddata, + UINT riddatalen, + ctlx_cmdcb_t cmdcb, + ctlx_usercb_t usercb, + void *usercb_data) +{ + int result; + hfa384x_usbctlx_t *ctlx; + + DBFENTER; + ctlx = usbctlx_alloc(); + if ( ctlx == NULL ) { + result = -ENOMEM; + goto done; + } + + /* Initialize the command */ + ctlx->outbuf.wridreq.type = host2hfa384x_16(HFA384x_USB_WRIDREQ); + ctlx->outbuf.wridreq.frmlen = host2hfa384x_16( + (sizeof(ctlx->outbuf.wridreq.rid) + + riddatalen + 1) / 2); + ctlx->outbuf.wridreq.rid = host2hfa384x_16(rid); + memcpy(ctlx->outbuf.wridreq.data, riddata, riddatalen); + + ctlx->outbufsize = sizeof(ctlx->outbuf.wridreq.type) + + sizeof(ctlx->outbuf.wridreq.frmlen) + + sizeof(ctlx->outbuf.wridreq.rid) + + riddatalen; + + ctlx->reapable = mode; + ctlx->cmdcb = cmdcb; + ctlx->usercb = usercb; + ctlx->usercb_data = usercb_data; + + /* Submit the CTLX */ + result = hfa384x_usbctlx_submit(hw, ctlx); + if (result != 0) { + kfree(ctlx); + } else if (mode == DOWAIT) { + usbctlx_wrid_completor_t completor; + hfa384x_cmdresult_t wridresult; + + result = hfa384x_usbctlx_complete_sync( + hw, + ctlx, + init_wrid_completor(&completor, + &ctlx->inbuf.wridresp, + &wridresult) ); + } + +done: + DBFEXIT; + return result; +} + +/*---------------------------------------------------------------- +* hfa384x_dormem +* +* Constructs a readmem CTLX and issues it. +* +* NOTE: Any changes to the 'post-submit' code in this function +* need to be carried over to hfa384x_cbrmem() since the handling +* is virtually identical. +* +* Arguments: +* hw device structure +* mode DOWAIT or DOASYNC +* page MAC address space page (CMD format) +* offset MAC address space offset +* data Ptr to data buffer to receive read +* len Length of the data to read (max == 2048) +* cmdcb command callback for async calls, NULL for DOWAIT calls +* usercb user callback for async calls, NULL for DOWAIT calls +* usercb_data user supplied data pointer for async calls +* +* Returns: +* 0 success +* -ETIMEDOUT timed out waiting for register ready or +* command completion +* >0 command indicated error, Status and Resp0-2 are +* in hw structure. +* +* Side effects: +* +* Call context: +* interrupt (DOASYNC) +* process (DOWAIT or DOASYNC) +----------------------------------------------------------------*/ +static int +hfa384x_dormem( + hfa384x_t *hw, + CMD_MODE mode, + UINT16 page, + UINT16 offset, + void *data, + UINT len, + ctlx_cmdcb_t cmdcb, + ctlx_usercb_t usercb, + void *usercb_data) +{ + int result; + hfa384x_usbctlx_t *ctlx; + + DBFENTER; + ctlx = usbctlx_alloc(); + if ( ctlx == NULL ) { + result = -ENOMEM; + goto done; + } + + /* Initialize the command */ + ctlx->outbuf.rmemreq.type = host2hfa384x_16(HFA384x_USB_RMEMREQ); + ctlx->outbuf.rmemreq.frmlen = host2hfa384x_16( + sizeof(ctlx->outbuf.rmemreq.offset) + + sizeof(ctlx->outbuf.rmemreq.page) + + len); + ctlx->outbuf.rmemreq.offset = host2hfa384x_16(offset); + ctlx->outbuf.rmemreq.page = host2hfa384x_16(page); + + ctlx->outbufsize = sizeof(ctlx->outbuf.rmemreq); + + WLAN_LOG_DEBUG(4, + "type=0x%04x frmlen=%d offset=0x%04x page=0x%04x\n", + ctlx->outbuf.rmemreq.type, + ctlx->outbuf.rmemreq.frmlen, + ctlx->outbuf.rmemreq.offset, + ctlx->outbuf.rmemreq.page); + + WLAN_LOG_DEBUG(4,"pktsize=%zd\n", + ROUNDUP64(sizeof(ctlx->outbuf.rmemreq))); + + ctlx->reapable = mode; + ctlx->cmdcb = cmdcb; + ctlx->usercb = usercb; + ctlx->usercb_data = usercb_data; + + result = hfa384x_usbctlx_submit(hw, ctlx); + if (result != 0) { + kfree(ctlx); + } else if ( mode == DOWAIT ) { + usbctlx_rmem_completor_t completor; + + result = hfa384x_usbctlx_complete_sync( + hw, ctlx, init_rmem_completor(&completor, + &ctlx->inbuf.rmemresp, + data, + len) ); + } + +done: + DBFEXIT; + return result; +} + + + +/*---------------------------------------------------------------- +* hfa384x_dowmem +* +* Constructs a writemem CTLX and issues it. +* +* NOTE: Any changes to the 'post-submit' code in this function +* need to be carried over to hfa384x_cbwmem() since the handling +* is virtually identical. +* +* Arguments: +* hw device structure +* mode DOWAIT or DOASYNC +* page MAC address space page (CMD format) +* offset MAC address space offset +* data Ptr to data buffer containing write data +* len Length of the data to read (max == 2048) +* cmdcb command callback for async calls, NULL for DOWAIT calls +* usercb user callback for async calls, NULL for DOWAIT calls +* usercb_data user supplied data pointer for async calls. +* +* Returns: +* 0 success +* -ETIMEDOUT timed out waiting for register ready or +* command completion +* >0 command indicated error, Status and Resp0-2 are +* in hw structure. +* +* Side effects: +* +* Call context: +* interrupt (DOWAIT) +* process (DOWAIT or DOASYNC) +----------------------------------------------------------------*/ +static int +hfa384x_dowmem( + hfa384x_t *hw, + CMD_MODE mode, + UINT16 page, + UINT16 offset, + void *data, + UINT len, + ctlx_cmdcb_t cmdcb, + ctlx_usercb_t usercb, + void *usercb_data) +{ + int result; + hfa384x_usbctlx_t *ctlx; + + DBFENTER; + WLAN_LOG_DEBUG(5, "page=0x%04x offset=0x%04x len=%d\n", + page,offset,len); + + ctlx = usbctlx_alloc(); + if ( ctlx == NULL ) { + result = -ENOMEM; + goto done; + } + + /* Initialize the command */ + ctlx->outbuf.wmemreq.type = host2hfa384x_16(HFA384x_USB_WMEMREQ); + ctlx->outbuf.wmemreq.frmlen = host2hfa384x_16( + sizeof(ctlx->outbuf.wmemreq.offset) + + sizeof(ctlx->outbuf.wmemreq.page) + + len); + ctlx->outbuf.wmemreq.offset = host2hfa384x_16(offset); + ctlx->outbuf.wmemreq.page = host2hfa384x_16(page); + memcpy(ctlx->outbuf.wmemreq.data, data, len); + + ctlx->outbufsize = sizeof(ctlx->outbuf.wmemreq.type) + + sizeof(ctlx->outbuf.wmemreq.frmlen) + + sizeof(ctlx->outbuf.wmemreq.offset) + + sizeof(ctlx->outbuf.wmemreq.page) + + len; + + ctlx->reapable = mode; + ctlx->cmdcb = cmdcb; + ctlx->usercb = usercb; + ctlx->usercb_data = usercb_data; + + result = hfa384x_usbctlx_submit(hw, ctlx); + if (result != 0) { + kfree(ctlx); + } else if ( mode == DOWAIT ) { + usbctlx_wmem_completor_t completor; + hfa384x_cmdresult_t wmemresult; + + result = hfa384x_usbctlx_complete_sync( + hw, + ctlx, + init_wmem_completor(&completor, + &ctlx->inbuf.wmemresp, + &wmemresult) ); + } + +done: + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_commtallies +* +* Send a commtallies inquiry to the MAC. Note that this is an async +* call that will result in an info frame arriving sometime later. +* +* Arguments: +* hw device structure +* +* Returns: +* zero success. +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int hfa384x_drvr_commtallies( hfa384x_t *hw ) +{ + hfa384x_metacmd_t cmd; + + DBFENTER; + + cmd.cmd = HFA384x_CMDCODE_INQ; + cmd.parm0 = HFA384x_IT_COMMTALLIES; + cmd.parm1 = 0; + cmd.parm2 = 0; + + hfa384x_docmd_async(hw, &cmd, NULL, NULL, NULL); + + DBFEXIT; + return 0; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_disable +* +* Issues the disable command to stop communications on one of +* the MACs 'ports'. Only macport 0 is valid for stations. +* APs may also disable macports 1-6. Only ports that have been +* previously enabled may be disabled. +* +* Arguments: +* hw device structure +* macport MAC port number (host order) +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int hfa384x_drvr_disable(hfa384x_t *hw, UINT16 macport) +{ + int result = 0; + + DBFENTER; + if ((!hw->isap && macport != 0) || + (hw->isap && !(macport <= HFA384x_PORTID_MAX)) || + !(hw->port_enabled[macport]) ){ + result = -EINVAL; + } else { + result = hfa384x_cmd_disable(hw, macport); + if ( result == 0 ) { + hw->port_enabled[macport] = 0; + } + } + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_enable +* +* Issues the enable command to enable communications on one of +* the MACs 'ports'. Only macport 0 is valid for stations. +* APs may also enable macports 1-6. Only ports that are currently +* disabled may be enabled. +* +* Arguments: +* hw device structure +* macport MAC port number +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int hfa384x_drvr_enable(hfa384x_t *hw, UINT16 macport) +{ + int result = 0; + + DBFENTER; + if ((!hw->isap && macport != 0) || + (hw->isap && !(macport <= HFA384x_PORTID_MAX)) || + (hw->port_enabled[macport]) ){ + result = -EINVAL; + } else { + result = hfa384x_cmd_enable(hw, macport); + if ( result == 0 ) { + hw->port_enabled[macport] = 1; + } + } + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_flashdl_enable +* +* Begins the flash download state. Checks to see that we're not +* already in a download state and that a port isn't enabled. +* Sets the download state and retrieves the flash download +* buffer location, buffer size, and timeout length. +* +* Arguments: +* hw device structure +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int hfa384x_drvr_flashdl_enable(hfa384x_t *hw) +{ + int result = 0; + int i; + + DBFENTER; + /* Check that a port isn't active */ + for ( i = 0; i < HFA384x_PORTID_MAX; i++) { + if ( hw->port_enabled[i] ) { + WLAN_LOG_DEBUG(1,"called when port enabled.\n"); + return -EINVAL; + } + } + + /* Check that we're not already in a download state */ + if ( hw->dlstate != HFA384x_DLSTATE_DISABLED ) { + return -EINVAL; + } + + /* Retrieve the buffer loc&size and timeout */ + if ( (result = hfa384x_drvr_getconfig(hw, HFA384x_RID_DOWNLOADBUFFER, + &(hw->bufinfo), sizeof(hw->bufinfo))) ) { + return result; + } + hw->bufinfo.page = hfa384x2host_16(hw->bufinfo.page); + hw->bufinfo.offset = hfa384x2host_16(hw->bufinfo.offset); + hw->bufinfo.len = hfa384x2host_16(hw->bufinfo.len); + if ( (result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_MAXLOADTIME, + &(hw->dltimeout))) ) { + return result; + } + hw->dltimeout = hfa384x2host_16(hw->dltimeout); + + WLAN_LOG_DEBUG(1,"flashdl_enable\n"); + + hw->dlstate = HFA384x_DLSTATE_FLASHENABLED; + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_flashdl_disable +* +* Ends the flash download state. Note that this will cause the MAC +* firmware to restart. +* +* Arguments: +* hw device structure +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int hfa384x_drvr_flashdl_disable(hfa384x_t *hw) +{ + DBFENTER; + /* Check that we're already in the download state */ + if ( hw->dlstate != HFA384x_DLSTATE_FLASHENABLED ) { + return -EINVAL; + } + + WLAN_LOG_DEBUG(1,"flashdl_enable\n"); + + /* There isn't much we can do at this point, so I don't */ + /* bother w/ the return value */ + hfa384x_cmd_download(hw, HFA384x_PROGMODE_DISABLE, 0, 0 , 0); + hw->dlstate = HFA384x_DLSTATE_DISABLED; + + DBFEXIT; + return 0; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_flashdl_write +* +* Performs a FLASH download of a chunk of data. First checks to see +* that we're in the FLASH download state, then sets the download +* mode, uses the aux functions to 1) copy the data to the flash +* buffer, 2) sets the download 'write flash' mode, 3) readback and +* compare. Lather rinse, repeat as many times an necessary to get +* all the given data into flash. +* When all data has been written using this function (possibly +* repeatedly), call drvr_flashdl_disable() to end the download state +* and restart the MAC. +* +* Arguments: +* hw device structure +* daddr Card address to write to. (host order) +* buf Ptr to data to write. +* len Length of data (host order). +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int +hfa384x_drvr_flashdl_write( + hfa384x_t *hw, + UINT32 daddr, + void *buf, + UINT32 len) +{ + int result = 0; + UINT32 dlbufaddr; + int nburns; + UINT32 burnlen; + UINT32 burndaddr; + UINT16 burnlo; + UINT16 burnhi; + int nwrites; + UINT8 *writebuf; + UINT16 writepage; + UINT16 writeoffset; + UINT32 writelen; + int i; + int j; + + DBFENTER; + WLAN_LOG_DEBUG(5,"daddr=0x%08x len=%d\n", daddr, len); + + /* Check that we're in the flash download state */ + if ( hw->dlstate != HFA384x_DLSTATE_FLASHENABLED ) { + return -EINVAL; + } + + WLAN_LOG_INFO("Download %d bytes to flash @0x%06x\n", len, daddr); + + /* Convert to flat address for arithmetic */ + /* NOTE: dlbuffer RID stores the address in AUX format */ + dlbufaddr = HFA384x_ADDR_AUX_MKFLAT( + hw->bufinfo.page, hw->bufinfo.offset); + WLAN_LOG_DEBUG(5, + "dlbuf.page=0x%04x dlbuf.offset=0x%04x dlbufaddr=0x%08x\n", + hw->bufinfo.page, hw->bufinfo.offset, dlbufaddr); + +#if 0 +WLAN_LOG_WARNING("dlbuf@0x%06lx len=%d to=%d\n", dlbufaddr, hw->bufinfo.len, hw->dltimeout); +#endif + /* Calculations to determine how many fills of the dlbuffer to do + * and how many USB wmemreq's to do for each fill. At this point + * in time, the dlbuffer size and the wmemreq size are the same. + * Therefore, nwrites should always be 1. The extra complexity + * here is a hedge against future changes. + */ + + /* Figure out how many times to do the flash programming */ + nburns = len / hw->bufinfo.len; + nburns += (len % hw->bufinfo.len) ? 1 : 0; + + /* For each flash program cycle, how many USB wmemreq's are needed? */ + nwrites = hw->bufinfo.len / HFA384x_USB_RWMEM_MAXLEN; + nwrites += (hw->bufinfo.len % HFA384x_USB_RWMEM_MAXLEN) ? 1 : 0; + + /* For each burn */ + for ( i = 0; i < nburns; i++) { + /* Get the dest address and len */ + burnlen = (len - (hw->bufinfo.len * i)) > hw->bufinfo.len ? + hw->bufinfo.len : + (len - (hw->bufinfo.len * i)); + burndaddr = daddr + (hw->bufinfo.len * i); + burnlo = HFA384x_ADDR_CMD_MKOFF(burndaddr); + burnhi = HFA384x_ADDR_CMD_MKPAGE(burndaddr); + + WLAN_LOG_INFO("Writing %d bytes to flash @0x%06x\n", + burnlen, burndaddr); + + /* Set the download mode */ + result = hfa384x_cmd_download(hw, HFA384x_PROGMODE_NV, + burnlo, burnhi, burnlen); + if ( result ) { + WLAN_LOG_ERROR("download(NV,lo=%x,hi=%x,len=%x) " + "cmd failed, result=%d. Aborting d/l\n", + burnlo, burnhi, burnlen, result); + goto exit_proc; + } + + /* copy the data to the flash download buffer */ + for ( j=0; j < nwrites; j++) { + writebuf = buf + + (i*hw->bufinfo.len) + + (j*HFA384x_USB_RWMEM_MAXLEN); + + writepage = HFA384x_ADDR_CMD_MKPAGE( + dlbufaddr + + (j*HFA384x_USB_RWMEM_MAXLEN)); + writeoffset = HFA384x_ADDR_CMD_MKOFF( + dlbufaddr + + (j*HFA384x_USB_RWMEM_MAXLEN)); + + writelen = burnlen-(j*HFA384x_USB_RWMEM_MAXLEN); + writelen = writelen > HFA384x_USB_RWMEM_MAXLEN ? + HFA384x_USB_RWMEM_MAXLEN : + writelen; + + result = hfa384x_dowmem_wait( hw, + writepage, + writeoffset, + writebuf, + writelen ); +#if 0 + +Comment out for debugging, assume the write was successful. + if (result) { + WLAN_LOG_ERROR( + "Write to dl buffer failed, " + "result=0x%04x. Aborting.\n", + result); + goto exit_proc; + } +#endif + + } + + /* set the download 'write flash' mode */ + result = hfa384x_cmd_download(hw, + HFA384x_PROGMODE_NVWRITE, + 0,0,0); + if ( result ) { + WLAN_LOG_ERROR( + "download(NVWRITE,lo=%x,hi=%x,len=%x) " + "cmd failed, result=%d. Aborting d/l\n", + burnlo, burnhi, burnlen, result); + goto exit_proc; + } + + /* TODO: We really should do a readback and compare. */ + } + +exit_proc: + + /* Leave the firmware in the 'post-prog' mode. flashdl_disable will */ + /* actually disable programming mode. Remember, that will cause the */ + /* the firmware to effectively reset itself. */ + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_getconfig +* +* Performs the sequence necessary to read a config/info item. +* +* Arguments: +* hw device structure +* rid config/info record id (host order) +* buf host side record buffer. Upon return it will +* contain the body portion of the record (minus the +* RID and len). +* len buffer length (in bytes, should match record length) +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* -ENODATA length mismatch between argument and retrieved +* record. +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int hfa384x_drvr_getconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len) +{ + int result; + DBFENTER; + + result = hfa384x_dorrid_wait(hw, rid, buf, len); + + DBFEXIT; + return result; +} + +/*---------------------------------------------------------------- + * hfa384x_drvr_getconfig_async + * + * Performs the sequence necessary to perform an async read of + * of a config/info item. + * + * Arguments: + * hw device structure + * rid config/info record id (host order) + * buf host side record buffer. Upon return it will + * contain the body portion of the record (minus the + * RID and len). + * len buffer length (in bytes, should match record length) + * cbfn caller supplied callback, called when the command + * is done (successful or not). + * cbfndata pointer to some caller supplied data that will be + * passed in as an argument to the cbfn. + * + * Returns: + * nothing the cbfn gets a status argument identifying if + * any errors occur. + * Side effects: + * Queues an hfa384x_usbcmd_t for subsequent execution. + * + * Call context: + * Any + ----------------------------------------------------------------*/ +int +hfa384x_drvr_getconfig_async( + hfa384x_t *hw, + UINT16 rid, + ctlx_usercb_t usercb, + void *usercb_data) +{ + return hfa384x_dorrid_async(hw, rid, NULL, 0, + hfa384x_cb_rrid, usercb, usercb_data); +} + +/*---------------------------------------------------------------- + * hfa384x_drvr_setconfig_async + * + * Performs the sequence necessary to write a config/info item. + * + * Arguments: + * hw device structure + * rid config/info record id (in host order) + * buf host side record buffer + * len buffer length (in bytes) + * usercb completion callback + * usercb_data completion callback argument + * + * Returns: + * 0 success + * >0 f/w reported error - f/w status code + * <0 driver reported error + * + * Side effects: + * + * Call context: + * process + ----------------------------------------------------------------*/ +int +hfa384x_drvr_setconfig_async( + hfa384x_t *hw, + UINT16 rid, + void *buf, + UINT16 len, + ctlx_usercb_t usercb, + void *usercb_data) +{ + return hfa384x_dowrid_async(hw, rid, buf, len, + hfa384x_cb_status, usercb, usercb_data); +} + +/*---------------------------------------------------------------- +* hfa384x_drvr_handover +* +* Sends a handover notification to the MAC. +* +* Arguments: +* hw device structure +* addr address of station that's left +* +* Returns: +* zero success. +* -ERESTARTSYS received signal while waiting for semaphore. +* -EIO failed to write to bap, or failed in cmd. +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int hfa384x_drvr_handover( hfa384x_t *hw, UINT8 *addr) +{ + DBFENTER; + WLAN_LOG_ERROR("Not currently supported in USB!\n"); + DBFEXIT; + return -EIO; +} + +/*---------------------------------------------------------------- +* hfa384x_drvr_low_level +* +* Write test commands to the card. Some test commands don't make +* sense without prior set-up. For example, continous TX isn't very +* useful until you set the channel. That functionality should be +* +* Side effects: +* +* Call context: +* process thread +* -----------------------------------------------------------------*/ +int hfa384x_drvr_low_level(hfa384x_t *hw, hfa384x_metacmd_t *cmd) +{ + int result; + DBFENTER; + + /* Do i need a host2hfa... conversion ? */ + + result = hfa384x_docmd_wait(hw, cmd); + + DBFEXIT; + return result; +} + +/*---------------------------------------------------------------- +* hfa384x_drvr_mmi_read +* +* Read mmi registers. mmi is intersil-speak for the baseband +* processor registers. +* +* Arguments: +* hw device structure +* register The test register to be accessed (must be even #). +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int hfa384x_drvr_mmi_read(hfa384x_t *hw, UINT32 addr, UINT32 *resp) +{ +#if 0 + int result = 0; + UINT16 cmd_code = (UINT16) 0x30; + UINT16 param = (UINT16) addr; + DBFENTER; + + /* Do i need a host2hfa... conversion ? */ + result = hfa384x_docmd_wait(hw, cmd_code); + + DBFEXIT; + return result; +#endif +return 0; +} + +/*---------------------------------------------------------------- +* hfa384x_drvr_mmi_write +* +* Read mmi registers. mmi is intersil-speak for the baseband +* processor registers. +* +* Arguments: +* hw device structure +* addr The test register to be accessed (must be even #). +* data The data value to write to the register. +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ + +int +hfa384x_drvr_mmi_write(hfa384x_t *hw, UINT32 addr, UINT32 data) +{ +#if 0 + int result = 0; + UINT16 cmd_code = (UINT16) 0x31; + UINT16 param0 = (UINT16) addr; + UINT16 param1 = (UINT16) data; + DBFENTER; + + WLAN_LOG_DEBUG(1,"mmi write : addr = 0x%08lx\n", addr); + WLAN_LOG_DEBUG(1,"mmi write : data = 0x%08lx\n", data); + + /* Do i need a host2hfa... conversion ? */ + result = hfa384x_docmd_wait(hw, cmd_code); + + DBFEXIT; + return result; +#endif +return 0; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_ramdl_disable +* +* Ends the ram download state. +* +* Arguments: +* hw device structure +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int +hfa384x_drvr_ramdl_disable(hfa384x_t *hw) +{ + DBFENTER; + /* Check that we're already in the download state */ + if ( hw->dlstate != HFA384x_DLSTATE_RAMENABLED ) { + return -EINVAL; + } + + WLAN_LOG_DEBUG(3,"ramdl_disable()\n"); + + /* There isn't much we can do at this point, so I don't */ + /* bother w/ the return value */ + hfa384x_cmd_download(hw, HFA384x_PROGMODE_DISABLE, 0, 0 , 0); + hw->dlstate = HFA384x_DLSTATE_DISABLED; + + DBFEXIT; + return 0; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_ramdl_enable +* +* Begins the ram download state. Checks to see that we're not +* already in a download state and that a port isn't enabled. +* Sets the download state and calls cmd_download with the +* ENABLE_VOLATILE subcommand and the exeaddr argument. +* +* Arguments: +* hw device structure +* exeaddr the card execution address that will be +* jumped to when ramdl_disable() is called +* (host order). +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int +hfa384x_drvr_ramdl_enable(hfa384x_t *hw, UINT32 exeaddr) +{ + int result = 0; + UINT16 lowaddr; + UINT16 hiaddr; + int i; + DBFENTER; + /* Check that a port isn't active */ + for ( i = 0; i < HFA384x_PORTID_MAX; i++) { + if ( hw->port_enabled[i] ) { + WLAN_LOG_ERROR( + "Can't download with a macport enabled.\n"); + return -EINVAL; + } + } + + /* Check that we're not already in a download state */ + if ( hw->dlstate != HFA384x_DLSTATE_DISABLED ) { + WLAN_LOG_ERROR( + "Download state not disabled.\n"); + return -EINVAL; + } + + WLAN_LOG_DEBUG(3,"ramdl_enable, exeaddr=0x%08x\n", exeaddr); + + /* Call the download(1,addr) function */ + lowaddr = HFA384x_ADDR_CMD_MKOFF(exeaddr); + hiaddr = HFA384x_ADDR_CMD_MKPAGE(exeaddr); + + result = hfa384x_cmd_download(hw, HFA384x_PROGMODE_RAM, + lowaddr, hiaddr, 0); + + if ( result == 0) { + /* Set the download state */ + hw->dlstate = HFA384x_DLSTATE_RAMENABLED; + } else { + WLAN_LOG_DEBUG(1, + "cmd_download(0x%04x, 0x%04x) failed, result=%d.\n", + lowaddr, + hiaddr, + result); + } + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_ramdl_write +* +* Performs a RAM download of a chunk of data. First checks to see +* that we're in the RAM download state, then uses the [read|write]mem USB +* commands to 1) copy the data, 2) readback and compare. The download +* state is unaffected. When all data has been written using +* this function, call drvr_ramdl_disable() to end the download state +* and restart the MAC. +* +* Arguments: +* hw device structure +* daddr Card address to write to. (host order) +* buf Ptr to data to write. +* len Length of data (host order). +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int +hfa384x_drvr_ramdl_write(hfa384x_t *hw, UINT32 daddr, void* buf, UINT32 len) +{ + int result = 0; + int nwrites; + UINT8 *data = buf; + int i; + UINT32 curraddr; + UINT16 currpage; + UINT16 curroffset; + UINT16 currlen; + DBFENTER; + /* Check that we're in the ram download state */ + if ( hw->dlstate != HFA384x_DLSTATE_RAMENABLED ) { + return -EINVAL; + } + + WLAN_LOG_INFO("Writing %d bytes to ram @0x%06x\n", len, daddr); + + /* How many dowmem calls? */ + nwrites = len / HFA384x_USB_RWMEM_MAXLEN; + nwrites += len % HFA384x_USB_RWMEM_MAXLEN ? 1 : 0; + + /* Do blocking wmem's */ + for(i=0; i < nwrites; i++) { + /* make address args */ + curraddr = daddr + (i * HFA384x_USB_RWMEM_MAXLEN); + currpage = HFA384x_ADDR_CMD_MKPAGE(curraddr); + curroffset = HFA384x_ADDR_CMD_MKOFF(curraddr); + currlen = len - (i * HFA384x_USB_RWMEM_MAXLEN); + if ( currlen > HFA384x_USB_RWMEM_MAXLEN) { + currlen = HFA384x_USB_RWMEM_MAXLEN; + } + + /* Do blocking ctlx */ + result = hfa384x_dowmem_wait( hw, + currpage, + curroffset, + data + (i*HFA384x_USB_RWMEM_MAXLEN), + currlen ); + + if (result) break; + + /* TODO: We really should have a readback. */ + } + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_readpda +* +* Performs the sequence to read the PDA space. Note there is no +* drvr_writepda() function. Writing a PDA is +* generally implemented by a calling component via calls to +* cmd_download and writing to the flash download buffer via the +* aux regs. +* +* Arguments: +* hw device structure +* buf buffer to store PDA in +* len buffer length +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* -ETIMEOUT timout waiting for the cmd regs to become +* available, or waiting for the control reg +* to indicate the Aux port is enabled. +* -ENODATA the buffer does NOT contain a valid PDA. +* Either the card PDA is bad, or the auxdata +* reads are giving us garbage. + +* +* Side effects: +* +* Call context: +* process or non-card interrupt. +----------------------------------------------------------------*/ +int hfa384x_drvr_readpda(hfa384x_t *hw, void *buf, UINT len) +{ + int result = 0; + UINT16 *pda = buf; + int pdaok = 0; + int morepdrs = 1; + int currpdr = 0; /* word offset of the current pdr */ + size_t i; + UINT16 pdrlen; /* pdr length in bytes, host order */ + UINT16 pdrcode; /* pdr code, host order */ + UINT16 currpage; + UINT16 curroffset; + struct pdaloc { + UINT32 cardaddr; + UINT16 auxctl; + } pdaloc[] = + { + { HFA3842_PDA_BASE, 0}, + { HFA3841_PDA_BASE, 0}, + { HFA3841_PDA_BOGUS_BASE, 0} + }; + + DBFENTER; + + /* Read the pda from each known address. */ + for ( i = 0; i < ARRAY_SIZE(pdaloc); i++) { + /* Make address */ + currpage = HFA384x_ADDR_CMD_MKPAGE(pdaloc[i].cardaddr); + curroffset = HFA384x_ADDR_CMD_MKOFF(pdaloc[i].cardaddr); + + result = hfa384x_dormem_wait(hw, + currpage, + curroffset, + buf, + len); /* units of bytes */ + + if (result) { + WLAN_LOG_WARNING( + "Read from index %zd failed, continuing\n", + i ); + continue; + } + + /* Test for garbage */ + pdaok = 1; /* initially assume good */ + morepdrs = 1; + while ( pdaok && morepdrs ) { + pdrlen = hfa384x2host_16(pda[currpdr]) * 2; + pdrcode = hfa384x2host_16(pda[currpdr+1]); + /* Test the record length */ + if ( pdrlen > HFA384x_PDR_LEN_MAX || pdrlen == 0) { + WLAN_LOG_ERROR("pdrlen invalid=%d\n", + pdrlen); + pdaok = 0; + break; + } + /* Test the code */ + if ( !hfa384x_isgood_pdrcode(pdrcode) ) { + WLAN_LOG_ERROR("pdrcode invalid=%d\n", + pdrcode); + pdaok = 0; + break; + } + /* Test for completion */ + if ( pdrcode == HFA384x_PDR_END_OF_PDA) { + morepdrs = 0; + } + + /* Move to the next pdr (if necessary) */ + if ( morepdrs ) { + /* note the access to pda[], need words here */ + currpdr += hfa384x2host_16(pda[currpdr]) + 1; + } + } + if ( pdaok ) { + WLAN_LOG_INFO( + "PDA Read from 0x%08x in %s space.\n", + pdaloc[i].cardaddr, + pdaloc[i].auxctl == 0 ? "EXTDS" : + pdaloc[i].auxctl == 1 ? "NV" : + pdaloc[i].auxctl == 2 ? "PHY" : + pdaloc[i].auxctl == 3 ? "ICSRAM" : + ""); + break; + } + } + result = pdaok ? 0 : -ENODATA; + + if ( result ) { + WLAN_LOG_DEBUG(3,"Failure: pda is not okay\n"); + } + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_setconfig +* +* Performs the sequence necessary to write a config/info item. +* +* Arguments: +* hw device structure +* rid config/info record id (in host order) +* buf host side record buffer +* len buffer length (in bytes) +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int hfa384x_drvr_setconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len) +{ + return hfa384x_dowrid_wait(hw, rid, buf, len); +} + +/*---------------------------------------------------------------- +* hfa384x_drvr_start +* +* Issues the MAC initialize command, sets up some data structures, +* and enables the interrupts. After this function completes, the +* low-level stuff should be ready for any/all commands. +* +* Arguments: +* hw device structure +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int hfa384x_drvr_start(hfa384x_t *hw) +{ + int result, result1, result2; + u16 status; + DBFENTER; + + might_sleep(); + + /* Clear endpoint stalls - but only do this if the endpoint + * is showing a stall status. Some prism2 cards seem to behave + * badly if a clear_halt is called when the endpoint is already + * ok + */ + result = usb_get_status(hw->usb, USB_RECIP_ENDPOINT, hw->endp_in, &status); + if (result < 0) { + WLAN_LOG_ERROR( + "Cannot get bulk in endpoint status.\n"); + goto done; + } + if ((status == 1) && usb_clear_halt(hw->usb, hw->endp_in)) { + WLAN_LOG_ERROR( + "Failed to reset bulk in endpoint.\n"); + } + + result = usb_get_status(hw->usb, USB_RECIP_ENDPOINT, hw->endp_out, &status); + if (result < 0) { + WLAN_LOG_ERROR( + "Cannot get bulk out endpoint status.\n"); + goto done; + } + if ((status == 1) && usb_clear_halt(hw->usb, hw->endp_out)) { + WLAN_LOG_ERROR( + "Failed to reset bulk out endpoint.\n"); + } + + /* Synchronous unlink, in case we're trying to restart the driver */ + usb_kill_urb(&hw->rx_urb); + + /* Post the IN urb */ + result = submit_rx_urb(hw, GFP_KERNEL); + if (result != 0) { + WLAN_LOG_ERROR( + "Fatal, failed to submit RX URB, result=%d\n", + result); + goto done; + } + + /* Call initialize twice, with a 1 second sleep in between. + * This is a nasty work-around since many prism2 cards seem to + * need time to settle after an init from cold. The second + * call to initialize in theory is not necessary - but we call + * it anyway as a double insurance policy: + * 1) If the first init should fail, the second may well succeed + * and the card can still be used + * 2) It helps ensures all is well with the card after the first + * init and settle time. + */ + result1 = hfa384x_cmd_initialize(hw); + msleep(1000); + result = result2 = hfa384x_cmd_initialize(hw); + if (result1 != 0) { + if (result2 != 0) { + WLAN_LOG_ERROR( + "cmd_initialize() failed on two attempts, results %d and %d\n", + result1, result2); + usb_kill_urb(&hw->rx_urb); + goto done; + } else { + WLAN_LOG_DEBUG(0, "First cmd_initialize() failed (result %d),\n", + result1); + WLAN_LOG_DEBUG(0, "but second attempt succeeded. All should be ok\n"); + } + } else if (result2 != 0) { + WLAN_LOG_WARNING( + "First cmd_initialize() succeeded, but second attempt failed (result=%d)\n", + result2); + WLAN_LOG_WARNING("Most likely the card will be functional\n"); + goto done; + } + + hw->state = HFA384x_STATE_RUNNING; + +done: + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_stop +* +* Shuts down the MAC to the point where it is safe to unload the +* driver. Any subsystem that may be holding a data or function +* ptr into the driver must be cleared/deinitialized. +* +* Arguments: +* hw device structure +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int +hfa384x_drvr_stop(hfa384x_t *hw) +{ + int result = 0; + int i; + DBFENTER; + + might_sleep(); + + /* There's no need for spinlocks here. The USB "disconnect" + * function sets this "removed" flag and then calls us. + */ + if ( !hw->wlandev->hwremoved ) { + /* Call initialize to leave the MAC in its 'reset' state */ + hfa384x_cmd_initialize(hw); + + /* Cancel the rxurb */ + usb_kill_urb(&hw->rx_urb); + } + + hw->link_status = HFA384x_LINK_NOTCONNECTED; + hw->state = HFA384x_STATE_INIT; + + del_timer_sync(&hw->commsqual_timer); + + /* Clear all the port status */ + for ( i = 0; i < HFA384x_NUMPORTS_MAX; i++) { + hw->port_enabled[i] = 0; + } + + DBFEXIT; + return result; +} + +/*---------------------------------------------------------------- +* hfa384x_drvr_txframe +* +* Takes a frame from prism2sta and queues it for transmission. +* +* Arguments: +* hw device structure +* skb packet buffer struct. Contains an 802.11 +* data frame. +* p80211_hdr points to the 802.11 header for the packet. +* Returns: +* 0 Success and more buffs available +* 1 Success but no more buffs +* 2 Allocation failure +* 4 Buffer full or queue busy +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +int hfa384x_drvr_txframe(hfa384x_t *hw, struct sk_buff *skb, p80211_hdr_t *p80211_hdr, p80211_metawep_t *p80211_wep) + +{ + int usbpktlen = sizeof(hfa384x_tx_frame_t); + int result; + int ret; + char *ptr; + + DBFENTER; + + if (hw->tx_urb.status == -EINPROGRESS) { + WLAN_LOG_WARNING("TX URB already in use\n"); + result = 3; + goto exit; + } + + /* Build Tx frame structure */ + /* Set up the control field */ + memset(&hw->txbuff.txfrm.desc, 0, sizeof(hw->txbuff.txfrm.desc)); + + /* Setup the usb type field */ + hw->txbuff.type = host2hfa384x_16(HFA384x_USB_TXFRM); + + /* Set up the sw_support field to identify this frame */ + hw->txbuff.txfrm.desc.sw_support = 0x0123; + +/* Tx complete and Tx exception disable per dleach. Might be causing + * buf depletion + */ +//#define DOEXC SLP -- doboth breaks horribly under load, doexc less so. +#if defined(DOBOTH) + hw->txbuff.txfrm.desc.tx_control = + HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) | + HFA384x_TX_TXEX_SET(1) | HFA384x_TX_TXOK_SET(1); +#elif defined(DOEXC) + hw->txbuff.txfrm.desc.tx_control = + HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) | + HFA384x_TX_TXEX_SET(1) | HFA384x_TX_TXOK_SET(0); +#else + hw->txbuff.txfrm.desc.tx_control = + HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) | + HFA384x_TX_TXEX_SET(0) | HFA384x_TX_TXOK_SET(0); +#endif + hw->txbuff.txfrm.desc.tx_control = + host2hfa384x_16(hw->txbuff.txfrm.desc.tx_control); + + /* copy the header over to the txdesc */ + memcpy(&(hw->txbuff.txfrm.desc.frame_control), p80211_hdr, sizeof(p80211_hdr_t)); + + /* if we're using host WEP, increase size by IV+ICV */ + if (p80211_wep->data) { + hw->txbuff.txfrm.desc.data_len = host2hfa384x_16(skb->len+8); + // hw->txbuff.txfrm.desc.tx_control |= HFA384x_TX_NOENCRYPT_SET(1); + usbpktlen+=8; + } else { + hw->txbuff.txfrm.desc.data_len = host2hfa384x_16(skb->len); + } + + usbpktlen += skb->len; + + /* copy over the WEP IV if we are using host WEP */ + ptr = hw->txbuff.txfrm.data; + if (p80211_wep->data) { + memcpy(ptr, p80211_wep->iv, sizeof(p80211_wep->iv)); + ptr+= sizeof(p80211_wep->iv); + memcpy(ptr, p80211_wep->data, skb->len); + } else { + memcpy(ptr, skb->data, skb->len); + } + /* copy over the packet data */ + ptr+= skb->len; + + /* copy over the WEP ICV if we are using host WEP */ + if (p80211_wep->data) { + memcpy(ptr, p80211_wep->icv, sizeof(p80211_wep->icv)); + } + + /* Send the USB packet */ + usb_fill_bulk_urb( &(hw->tx_urb), hw->usb, + hw->endp_out, + &(hw->txbuff), ROUNDUP64(usbpktlen), + hfa384x_usbout_callback, hw->wlandev ); + hw->tx_urb.transfer_flags |= USB_QUEUE_BULK; + + result = 1; + ret = submit_tx_urb(hw, &hw->tx_urb, GFP_ATOMIC); + if ( ret != 0 ) { + WLAN_LOG_ERROR( + "submit_tx_urb() failed, error=%d\n", ret); + result = 3; + } + + exit: + DBFEXIT; + return result; +} + +void hfa384x_tx_timeout(wlandevice_t *wlandev) +{ + hfa384x_t *hw = wlandev->priv; + unsigned long flags; + + DBFENTER; + + spin_lock_irqsave(&hw->ctlxq.lock, flags); + + if ( !hw->wlandev->hwremoved && + /* Note the bitwise OR, not the logical OR. */ + ( !test_and_set_bit(WORK_TX_HALT, &hw->usb_flags) | + !test_and_set_bit(WORK_RX_HALT, &hw->usb_flags) ) ) + { + schedule_work(&hw->usb_work); + } + + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + + DBFEXIT; +} + +/*---------------------------------------------------------------- +* hfa384x_usbctlx_reaper_task +* +* Tasklet to delete dead CTLX objects +* +* Arguments: +* data ptr to a hfa384x_t +* +* Returns: +* +* Call context: +* Interrupt +----------------------------------------------------------------*/ +static void hfa384x_usbctlx_reaper_task(unsigned long data) +{ + hfa384x_t *hw = (hfa384x_t*)data; + struct list_head *entry; + struct list_head *temp; + unsigned long flags; + + DBFENTER; + + spin_lock_irqsave(&hw->ctlxq.lock, flags); + + /* This list is guaranteed to be empty if someone + * has unplugged the adapter. + */ + list_for_each_safe(entry, temp, &hw->ctlxq.reapable) { + hfa384x_usbctlx_t *ctlx; + + ctlx = list_entry(entry, hfa384x_usbctlx_t, list); + list_del(&ctlx->list); + kfree(ctlx); + } + + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + + DBFEXIT; +} + +/*---------------------------------------------------------------- +* hfa384x_usbctlx_completion_task +* +* Tasklet to call completion handlers for returned CTLXs +* +* Arguments: +* data ptr to hfa384x_t +* +* Returns: +* Nothing +* +* Call context: +* Interrupt +----------------------------------------------------------------*/ +static void hfa384x_usbctlx_completion_task(unsigned long data) +{ + hfa384x_t *hw = (hfa384x_t*)data; + struct list_head *entry; + struct list_head *temp; + unsigned long flags; + + int reap = 0; + + DBFENTER; + + spin_lock_irqsave(&hw->ctlxq.lock, flags); + + /* This list is guaranteed to be empty if someone + * has unplugged the adapter ... + */ + list_for_each_safe(entry, temp, &hw->ctlxq.completing) { + hfa384x_usbctlx_t *ctlx; + + ctlx = list_entry(entry, hfa384x_usbctlx_t, list); + + /* Call the completion function that this + * command was assigned, assuming it has one. + */ + if ( ctlx->cmdcb != NULL ) { + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + ctlx->cmdcb(hw, ctlx); + spin_lock_irqsave(&hw->ctlxq.lock, flags); + + /* Make sure we don't try and complete + * this CTLX more than once! + */ + ctlx->cmdcb = NULL; + + /* Did someone yank the adapter out + * while our list was (briefly) unlocked? + */ + if ( hw->wlandev->hwremoved ) + { + reap = 0; + break; + } + } + + /* + * "Reapable" CTLXs are ones which don't have any + * threads waiting for them to die. Hence they must + * be delivered to The Reaper! + */ + if ( ctlx->reapable ) { + /* Move the CTLX off the "completing" list (hopefully) + * on to the "reapable" list where the reaper task + * can find it. And "reapable" means that this CTLX + * isn't sitting on a wait-queue somewhere. + */ + list_move_tail(&ctlx->list, &hw->ctlxq.reapable); + reap = 1; + } + + complete(&ctlx->done); + } + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + + if (reap) + tasklet_schedule(&hw->reaper_bh); + + DBFEXIT; +} + +/*---------------------------------------------------------------- +* unlocked_usbctlx_cancel_async +* +* Mark the CTLX dead asynchronously, and ensure that the +* next command on the queue is run afterwards. +* +* Arguments: +* hw ptr to the hfa384x_t structure +* ctlx ptr to a CTLX structure +* +* Returns: +* 0 the CTLX's URB is inactive +* -EINPROGRESS the URB is currently being unlinked +* +* Call context: +* Either process or interrupt, but presumably interrupt +----------------------------------------------------------------*/ +static int unlocked_usbctlx_cancel_async(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx) +{ + int ret; + + DBFENTER; + + /* + * Try to delete the URB containing our request packet. + * If we succeed, then its completion handler will be + * called with a status of -ECONNRESET. + */ + hw->ctlx_urb.transfer_flags |= URB_ASYNC_UNLINK; + ret = usb_unlink_urb(&hw->ctlx_urb); + + if (ret != -EINPROGRESS) { + /* + * The OUT URB had either already completed + * or was still in the pending queue, so the + * URB's completion function will not be called. + * We will have to complete the CTLX ourselves. + */ + ctlx->state = CTLX_REQ_FAILED; + unlocked_usbctlx_complete(hw, ctlx); + ret = 0; + } + + DBFEXIT; + + return ret; +} + +/*---------------------------------------------------------------- +* unlocked_usbctlx_complete +* +* A CTLX has completed. It may have been successful, it may not +* have been. At this point, the CTLX should be quiescent. The URBs +* aren't active and the timers should have been stopped. +* +* The CTLX is migrated to the "completing" queue, and the completing +* tasklet is scheduled. +* +* Arguments: +* hw ptr to a hfa384x_t structure +* ctlx ptr to a ctlx structure +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* Either, assume interrupt +----------------------------------------------------------------*/ +static void unlocked_usbctlx_complete(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx) +{ + DBFENTER; + + /* Timers have been stopped, and ctlx should be in + * a terminal state. Retire it from the "active" + * queue. + */ + list_move_tail(&ctlx->list, &hw->ctlxq.completing); + tasklet_schedule(&hw->completion_bh); + + switch (ctlx->state) { + case CTLX_COMPLETE: + case CTLX_REQ_FAILED: + /* This are the correct terminating states. */ + break; + + default: + WLAN_LOG_ERROR("CTLX[%d] not in a terminating state(%s)\n", + hfa384x2host_16(ctlx->outbuf.type), + ctlxstr(ctlx->state)); + break; + } /* switch */ + + DBFEXIT; +} + +/*---------------------------------------------------------------- +* hfa384x_usbctlxq_run +* +* Checks to see if the head item is running. If not, starts it. +* +* Arguments: +* hw ptr to hfa384x_t +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* any +----------------------------------------------------------------*/ +static void +hfa384x_usbctlxq_run(hfa384x_t *hw) +{ + unsigned long flags; + DBFENTER; + + /* acquire lock */ + spin_lock_irqsave(&hw->ctlxq.lock, flags); + + /* Only one active CTLX at any one time, because there's no + * other (reliable) way to match the response URB to the + * correct CTLX. + * + * Don't touch any of these CTLXs if the hardware + * has been removed or the USB subsystem is stalled. + */ + if ( !list_empty(&hw->ctlxq.active) || + test_bit(WORK_TX_HALT, &hw->usb_flags) || + hw->wlandev->hwremoved ) + goto unlock; + + while ( !list_empty(&hw->ctlxq.pending) ) { + hfa384x_usbctlx_t *head; + int result; + + /* This is the first pending command */ + head = list_entry(hw->ctlxq.pending.next, + hfa384x_usbctlx_t, + list); + + /* We need to split this off to avoid a race condition */ + list_move_tail(&head->list, &hw->ctlxq.active); + + /* Fill the out packet */ + usb_fill_bulk_urb( &(hw->ctlx_urb), hw->usb, + hw->endp_out, + &(head->outbuf), ROUNDUP64(head->outbufsize), + hfa384x_ctlxout_callback, hw); + hw->ctlx_urb.transfer_flags |= USB_QUEUE_BULK; + + /* Now submit the URB and update the CTLX's state + */ + if ((result = SUBMIT_URB(&hw->ctlx_urb, GFP_ATOMIC)) == 0) { + /* This CTLX is now running on the active queue */ + head->state = CTLX_REQ_SUBMITTED; + + /* Start the OUT wait timer */ + hw->req_timer_done = 0; + hw->reqtimer.expires = jiffies + HZ; + add_timer(&hw->reqtimer); + + /* Start the IN wait timer */ + hw->resp_timer_done = 0; + hw->resptimer.expires = jiffies + 2*HZ; + add_timer(&hw->resptimer); + + break; + } + + if (result == -EPIPE) { + /* The OUT pipe needs resetting, so put + * this CTLX back in the "pending" queue + * and schedule a reset ... + */ + WLAN_LOG_WARNING("%s tx pipe stalled: requesting reset\n", + hw->wlandev->netdev->name); + list_move(&head->list, &hw->ctlxq.pending); + set_bit(WORK_TX_HALT, &hw->usb_flags); + schedule_work(&hw->usb_work); + break; + } + + if (result == -ESHUTDOWN) { + WLAN_LOG_WARNING("%s urb shutdown!\n", + hw->wlandev->netdev->name); + break; + } + + WLAN_LOG_ERROR("Failed to submit CTLX[%d]: error=%d\n", + hfa384x2host_16(head->outbuf.type), result); + unlocked_usbctlx_complete(hw, head); + } /* while */ + + unlock: + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* hfa384x_usbin_callback +* +* Callback for URBs on the BULKIN endpoint. +* +* Arguments: +* urb ptr to the completed urb +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +#ifdef URB_ONLY_CALLBACK +static void hfa384x_usbin_callback(struct urb *urb) +#else +static void hfa384x_usbin_callback(struct urb *urb, struct pt_regs *regs) +#endif +{ + wlandevice_t *wlandev = urb->context; + hfa384x_t *hw; + hfa384x_usbin_t *usbin = (hfa384x_usbin_t *) urb->transfer_buffer; + struct sk_buff *skb = NULL; + int result; + int urb_status; + UINT16 type; + + enum USBIN_ACTION { + HANDLE, + RESUBMIT, + ABORT + } action; + + DBFENTER; + + if ( !wlandev || + !wlandev->netdev || + wlandev->hwremoved ) + goto exit; + + hw = wlandev->priv; + if (!hw) + goto exit; + + skb = hw->rx_urb_skb; + if (!skb || (skb->data != urb->transfer_buffer)) { + BUG(); + } + hw->rx_urb_skb = NULL; + + /* Check for error conditions within the URB */ + switch (urb->status) { + case 0: + action = HANDLE; + + /* Check for short packet */ + if ( urb->actual_length == 0 ) { + ++(wlandev->linux_stats.rx_errors); + ++(wlandev->linux_stats.rx_length_errors); + action = RESUBMIT; + } + break; + + case -EPIPE: + WLAN_LOG_WARNING("%s rx pipe stalled: requesting reset\n", + wlandev->netdev->name); + if ( !test_and_set_bit(WORK_RX_HALT, &hw->usb_flags) ) + schedule_work(&hw->usb_work); + ++(wlandev->linux_stats.rx_errors); + action = ABORT; + break; + + case -EILSEQ: + case -ETIMEDOUT: + case -EPROTO: + if ( !test_and_set_bit(THROTTLE_RX, &hw->usb_flags) && + !timer_pending(&hw->throttle) ) { + mod_timer(&hw->throttle, jiffies + THROTTLE_JIFFIES); + } + ++(wlandev->linux_stats.rx_errors); + action = ABORT; + break; + + case -EOVERFLOW: + ++(wlandev->linux_stats.rx_over_errors); + action = RESUBMIT; + break; + + case -ENODEV: + case -ESHUTDOWN: + WLAN_LOG_DEBUG(3,"status=%d, device removed.\n", urb->status); + action = ABORT; + break; + + case -ENOENT: + case -ECONNRESET: + WLAN_LOG_DEBUG(3,"status=%d, urb explicitly unlinked.\n", urb->status); + action = ABORT; + break; + + default: + WLAN_LOG_DEBUG(3,"urb status=%d, transfer flags=0x%x\n", + urb->status, urb->transfer_flags); + ++(wlandev->linux_stats.rx_errors); + action = RESUBMIT; + break; + } + + urb_status = urb->status; + + if (action != ABORT) { + /* Repost the RX URB */ + result = submit_rx_urb(hw, GFP_ATOMIC); + + if (result != 0) { + WLAN_LOG_ERROR( + "Fatal, failed to resubmit rx_urb. error=%d\n", + result); + } + } + + /* Handle any USB-IN packet */ + /* Note: the check of the sw_support field, the type field doesn't + * have bit 12 set like the docs suggest. + */ + type = hfa384x2host_16(usbin->type); + if (HFA384x_USB_ISRXFRM(type)) { + if (action == HANDLE) { + if (usbin->txfrm.desc.sw_support == 0x0123) { + hfa384x_usbin_txcompl(wlandev, usbin); + } else { + skb_put(skb, sizeof(*usbin)); + hfa384x_usbin_rx(wlandev, skb); + skb = NULL; + } + } + goto exit; + } + if (HFA384x_USB_ISTXFRM(type)) { + if (action == HANDLE) + hfa384x_usbin_txcompl(wlandev, usbin); + goto exit; + } + switch (type) { + case HFA384x_USB_INFOFRM: + if (action == ABORT) + goto exit; + if (action == HANDLE) + hfa384x_usbin_info(wlandev, usbin); + break; + + case HFA384x_USB_CMDRESP: + case HFA384x_USB_WRIDRESP: + case HFA384x_USB_RRIDRESP: + case HFA384x_USB_WMEMRESP: + case HFA384x_USB_RMEMRESP: + /* ALWAYS, ALWAYS, ALWAYS handle this CTLX!!!! */ + hfa384x_usbin_ctlx(hw, usbin, urb_status); + break; + + case HFA384x_USB_BUFAVAIL: + WLAN_LOG_DEBUG(3,"Received BUFAVAIL packet, frmlen=%d\n", + usbin->bufavail.frmlen); + break; + + case HFA384x_USB_ERROR: + WLAN_LOG_DEBUG(3,"Received USB_ERROR packet, errortype=%d\n", + usbin->usberror.errortype); + break; + + default: + WLAN_LOG_DEBUG(3,"Unrecognized USBIN packet, type=%x, status=%d\n", + usbin->type, urb_status); + break; + } /* switch */ + +exit: + + if (skb) + dev_kfree_skb(skb); + + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* hfa384x_usbin_ctlx +* +* We've received a URB containing a Prism2 "response" message. +* This message needs to be matched up with a CTLX on the active +* queue and our state updated accordingly. +* +* Arguments: +* hw ptr to hfa384x_t +* usbin ptr to USB IN packet +* urb_status status of this Bulk-In URB +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void hfa384x_usbin_ctlx(hfa384x_t *hw, hfa384x_usbin_t *usbin, + int urb_status) +{ + hfa384x_usbctlx_t *ctlx; + int run_queue = 0; + unsigned long flags; + + DBFENTER; + +retry: + spin_lock_irqsave(&hw->ctlxq.lock, flags); + + /* There can be only one CTLX on the active queue + * at any one time, and this is the CTLX that the + * timers are waiting for. + */ + if ( list_empty(&hw->ctlxq.active) ) { + goto unlock; + } + + /* Remove the "response timeout". It's possible that + * we are already too late, and that the timeout is + * already running. And that's just too bad for us, + * because we could lose our CTLX from the active + * queue here ... + */ + if (del_timer(&hw->resptimer) == 0) { + if (hw->resp_timer_done == 0) { + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + goto retry; + } + } + else { + hw->resp_timer_done = 1; + } + + ctlx = get_active_ctlx(hw); + + if (urb_status != 0) { + /* + * Bad CTLX, so get rid of it. But we only + * remove it from the active queue if we're no + * longer expecting the OUT URB to complete. + */ + if (unlocked_usbctlx_cancel_async(hw, ctlx) == 0) + run_queue = 1; + } else { + const UINT16 intype = (usbin->type&~host2hfa384x_16(0x8000)); + + /* + * Check that our message is what we're expecting ... + */ + if (ctlx->outbuf.type != intype) { + WLAN_LOG_WARNING("Expected IN[%d], received IN[%d] - ignored.\n", + hfa384x2host_16(ctlx->outbuf.type), + hfa384x2host_16(intype)); + goto unlock; + } + + /* This URB has succeeded, so grab the data ... */ + memcpy(&ctlx->inbuf, usbin, sizeof(ctlx->inbuf)); + + switch (ctlx->state) { + case CTLX_REQ_SUBMITTED: + /* + * We have received our response URB before + * our request has been acknowledged. Odd, + * but our OUT URB is still alive... + */ + WLAN_LOG_DEBUG(0, "Causality violation: please reboot Universe, or email linux-wlan-devel@lists.linux-wlan.com\n"); + ctlx->state = CTLX_RESP_COMPLETE; + break; + + case CTLX_REQ_COMPLETE: + /* + * This is the usual path: our request + * has already been acknowledged, and + * now we have received the reply too. + */ + ctlx->state = CTLX_COMPLETE; + unlocked_usbctlx_complete(hw, ctlx); + run_queue = 1; + break; + + default: + /* + * Throw this CTLX away ... + */ + WLAN_LOG_ERROR("Matched IN URB, CTLX[%d] in invalid state(%s)." + " Discarded.\n", + hfa384x2host_16(ctlx->outbuf.type), + ctlxstr(ctlx->state)); + if (unlocked_usbctlx_cancel_async(hw, ctlx) == 0) + run_queue = 1; + break; + } /* switch */ + } + +unlock: + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + + if (run_queue) + hfa384x_usbctlxq_run(hw); + + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* hfa384x_usbin_txcompl +* +* At this point we have the results of a previous transmit. +* +* Arguments: +* wlandev wlan device +* usbin ptr to the usb transfer buffer +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void hfa384x_usbin_txcompl(wlandevice_t *wlandev, hfa384x_usbin_t *usbin) +{ + UINT16 status; + DBFENTER; + + status = hfa384x2host_16(usbin->type); /* yeah I know it says type...*/ + + /* Was there an error? */ + if (HFA384x_TXSTATUS_ISERROR(status)) { + prism2sta_ev_txexc(wlandev, status); + } else { + prism2sta_ev_tx(wlandev, status); + } + // prism2sta_ev_alloc(wlandev); + + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* hfa384x_usbin_rx +* +* At this point we have a successful received a rx frame packet. +* +* Arguments: +* wlandev wlan device +* usbin ptr to the usb transfer buffer +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void hfa384x_usbin_rx(wlandevice_t *wlandev, struct sk_buff *skb) +{ + hfa384x_usbin_t *usbin = (hfa384x_usbin_t *) skb->data; + hfa384x_t *hw = wlandev->priv; + int hdrlen; + p80211_rxmeta_t *rxmeta; + UINT16 data_len; + UINT16 fc; + + DBFENTER; + + /* Byte order convert once up front. */ + usbin->rxfrm.desc.status = + hfa384x2host_16(usbin->rxfrm.desc.status); + usbin->rxfrm.desc.time = + hfa384x2host_32(usbin->rxfrm.desc.time); + + /* Now handle frame based on port# */ + switch( HFA384x_RXSTATUS_MACPORT_GET(usbin->rxfrm.desc.status) ) + { + case 0: + fc = ieee2host16(usbin->rxfrm.desc.frame_control); + + /* If exclude and we receive an unencrypted, drop it */ + if ( (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED) && + !WLAN_GET_FC_ISWEP(fc)){ + goto done; + } + + data_len = hfa384x2host_16(usbin->rxfrm.desc.data_len); + + /* How much header data do we have? */ + hdrlen = p80211_headerlen(fc); + + /* Pull off the descriptor */ + skb_pull(skb, sizeof(hfa384x_rx_frame_t)); + + /* Now shunt the header block up against the data block + * with an "overlapping" copy + */ + memmove(skb_push(skb, hdrlen), + &usbin->rxfrm.desc.frame_control, + hdrlen); + + skb->dev = wlandev->netdev; + skb->dev->last_rx = jiffies; + + /* And set the frame length properly */ + skb_trim(skb, data_len + hdrlen); + + /* The prism2 series does not return the CRC */ + memset(skb_put(skb, WLAN_CRC_LEN), 0xff, WLAN_CRC_LEN); + + skb_reset_mac_header(skb); + + /* Attach the rxmeta, set some stuff */ + p80211skb_rxmeta_attach(wlandev, skb); + rxmeta = P80211SKB_RXMETA(skb); + rxmeta->mactime = usbin->rxfrm.desc.time; + rxmeta->rxrate = usbin->rxfrm.desc.rate; + rxmeta->signal = usbin->rxfrm.desc.signal - hw->dbmadjust; + rxmeta->noise = usbin->rxfrm.desc.silence - hw->dbmadjust; + + prism2sta_ev_rx(wlandev, skb); + + break; + + case 7: + if ( ! HFA384x_RXSTATUS_ISFCSERR(usbin->rxfrm.desc.status) ) { + /* Copy to wlansnif skb */ + hfa384x_int_rxmonitor( wlandev, &usbin->rxfrm); + dev_kfree_skb(skb); + } else { + WLAN_LOG_DEBUG(3,"Received monitor frame: FCSerr set\n"); + } + break; + + default: + WLAN_LOG_WARNING("Received frame on unsupported port=%d\n", + HFA384x_RXSTATUS_MACPORT_GET(usbin->rxfrm.desc.status) ); + goto done; + break; + } + +done: + DBFEXIT; + return; +} + +/*---------------------------------------------------------------- +* hfa384x_int_rxmonitor +* +* Helper function for int_rx. Handles monitor frames. +* Note that this function allocates space for the FCS and sets it +* to 0xffffffff. The hfa384x doesn't give us the FCS value but the +* higher layers expect it. 0xffffffff is used as a flag to indicate +* the FCS is bogus. +* +* Arguments: +* wlandev wlan device structure +* rxfrm rx descriptor read from card in int_rx +* +* Returns: +* nothing +* +* Side effects: +* Allocates an skb and passes it up via the PF_PACKET interface. +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void hfa384x_int_rxmonitor( wlandevice_t *wlandev, hfa384x_usb_rxfrm_t *rxfrm) +{ + hfa384x_rx_frame_t *rxdesc = &(rxfrm->desc); + UINT hdrlen = 0; + UINT datalen = 0; + UINT skblen = 0; + p80211msg_lnxind_wlansniffrm_t *msg; + UINT8 *datap; + UINT16 fc; + struct sk_buff *skb; + hfa384x_t *hw = wlandev->priv; + + + DBFENTER; + /* Don't forget the status, time, and data_len fields are in host order */ + /* Figure out how big the frame is */ + fc = ieee2host16(rxdesc->frame_control); + hdrlen = p80211_headerlen(fc); + datalen = hfa384x2host_16(rxdesc->data_len); + + /* Allocate an ind message+framesize skb */ + skblen = sizeof(p80211msg_lnxind_wlansniffrm_t) + + hdrlen + datalen + WLAN_CRC_LEN; + + /* sanity check the length */ + if ( skblen > + (sizeof(p80211msg_lnxind_wlansniffrm_t) + + WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN) ) { + WLAN_LOG_DEBUG(1, "overlen frm: len=%zd\n", + skblen - sizeof(p80211msg_lnxind_wlansniffrm_t)); + } + + if ( (skb = dev_alloc_skb(skblen)) == NULL ) { + WLAN_LOG_ERROR("alloc_skb failed trying to allocate %d bytes\n", skblen); + return; + } + + /* only prepend the prism header if in the right mode */ + if ((wlandev->netdev->type == ARPHRD_IEEE80211_PRISM) && + (hw->sniffhdr == 0)) { + datap = skb_put(skb, sizeof(p80211msg_lnxind_wlansniffrm_t)); + msg = (p80211msg_lnxind_wlansniffrm_t*) datap; + + /* Initialize the message members */ + msg->msgcode = DIDmsg_lnxind_wlansniffrm; + msg->msglen = sizeof(p80211msg_lnxind_wlansniffrm_t); + strcpy(msg->devname, wlandev->name); + + msg->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime; + msg->hosttime.status = 0; + msg->hosttime.len = 4; + msg->hosttime.data = jiffies; + + msg->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime; + msg->mactime.status = 0; + msg->mactime.len = 4; + msg->mactime.data = rxdesc->time; + + msg->channel.did = DIDmsg_lnxind_wlansniffrm_channel; + msg->channel.status = 0; + msg->channel.len = 4; + msg->channel.data = hw->sniff_channel; + + msg->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi; + msg->rssi.status = P80211ENUM_msgitem_status_no_value; + msg->rssi.len = 4; + msg->rssi.data = 0; + + msg->sq.did = DIDmsg_lnxind_wlansniffrm_sq; + msg->sq.status = P80211ENUM_msgitem_status_no_value; + msg->sq.len = 4; + msg->sq.data = 0; + + msg->signal.did = DIDmsg_lnxind_wlansniffrm_signal; + msg->signal.status = 0; + msg->signal.len = 4; + msg->signal.data = rxdesc->signal; + + msg->noise.did = DIDmsg_lnxind_wlansniffrm_noise; + msg->noise.status = 0; + msg->noise.len = 4; + msg->noise.data = rxdesc->silence; + + msg->rate.did = DIDmsg_lnxind_wlansniffrm_rate; + msg->rate.status = 0; + msg->rate.len = 4; + msg->rate.data = rxdesc->rate / 5; /* set to 802.11 units */ + + msg->istx.did = DIDmsg_lnxind_wlansniffrm_istx; + msg->istx.status = 0; + msg->istx.len = 4; + msg->istx.data = P80211ENUM_truth_false; + + msg->frmlen.did = DIDmsg_lnxind_wlansniffrm_frmlen; + msg->frmlen.status = 0; + msg->frmlen.len = 4; + msg->frmlen.data = hdrlen + datalen + WLAN_CRC_LEN; + } else if ((wlandev->netdev->type == ARPHRD_IEEE80211_PRISM) && + (hw->sniffhdr != 0)) { + p80211_caphdr_t *caphdr; + /* The NEW header format! */ + datap = skb_put(skb, sizeof(p80211_caphdr_t)); + caphdr = (p80211_caphdr_t*) datap; + + caphdr->version = htonl(P80211CAPTURE_VERSION); + caphdr->length = htonl(sizeof(p80211_caphdr_t)); + caphdr->mactime = __cpu_to_be64(rxdesc->time) * 1000; + caphdr->hosttime = __cpu_to_be64(jiffies); + caphdr->phytype = htonl(4); /* dss_dot11_b */ + caphdr->channel = htonl(hw->sniff_channel); + caphdr->datarate = htonl(rxdesc->rate); + caphdr->antenna = htonl(0); /* unknown */ + caphdr->priority = htonl(0); /* unknown */ + caphdr->ssi_type = htonl(3); /* rssi_raw */ + caphdr->ssi_signal = htonl(rxdesc->signal); + caphdr->ssi_noise = htonl(rxdesc->silence); + caphdr->preamble = htonl(0); /* unknown */ + caphdr->encoding = htonl(1); /* cck */ + } + + /* Copy the 802.11 header to the skb (ctl frames may be less than a full header) */ + datap = skb_put(skb, hdrlen); + memcpy( datap, &(rxdesc->frame_control), hdrlen); + + /* If any, copy the data from the card to the skb */ + if ( datalen > 0 ) + { + datap = skb_put(skb, datalen); + memcpy(datap, rxfrm->data, datalen); + + /* check for unencrypted stuff if WEP bit set. */ + if (*(datap - hdrlen + 1) & 0x40) // wep set + if ((*(datap) == 0xaa) && (*(datap+1) == 0xaa)) + *(datap - hdrlen + 1) &= 0xbf; // clear wep; it's the 802.2 header! + } + + if (hw->sniff_fcs) { + /* Set the FCS */ + datap = skb_put(skb, WLAN_CRC_LEN); + memset( datap, 0xff, WLAN_CRC_LEN); + } + + /* pass it back up */ + prism2sta_ev_rx(wlandev, skb); + + DBFEXIT; + return; +} + + + +/*---------------------------------------------------------------- +* hfa384x_usbin_info +* +* At this point we have a successful received a Prism2 info frame. +* +* Arguments: +* wlandev wlan device +* usbin ptr to the usb transfer buffer +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void hfa384x_usbin_info(wlandevice_t *wlandev, hfa384x_usbin_t *usbin) +{ + DBFENTER; + + usbin->infofrm.info.framelen = hfa384x2host_16(usbin->infofrm.info.framelen); + prism2sta_ev_info(wlandev, &usbin->infofrm.info); + + DBFEXIT; +} + + + +/*---------------------------------------------------------------- +* hfa384x_usbout_callback +* +* Callback for URBs on the BULKOUT endpoint. +* +* Arguments: +* urb ptr to the completed urb +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +#ifdef URB_ONLY_CALLBACK +static void hfa384x_usbout_callback(struct urb *urb) +#else +static void hfa384x_usbout_callback(struct urb *urb, struct pt_regs *regs) +#endif +{ + wlandevice_t *wlandev = urb->context; + hfa384x_usbout_t *usbout = urb->transfer_buffer; + DBFENTER; + +#ifdef DEBUG_USB + dbprint_urb(urb); +#endif + + if ( wlandev && + wlandev->netdev ) { + + switch(urb->status) { + case 0: + hfa384x_usbout_tx(wlandev, usbout); + break; + + case -EPIPE: + { + hfa384x_t *hw = wlandev->priv; + WLAN_LOG_WARNING("%s tx pipe stalled: requesting reset\n", + wlandev->netdev->name); + if ( !test_and_set_bit(WORK_TX_HALT, &hw->usb_flags) ) + schedule_work(&hw->usb_work); + ++(wlandev->linux_stats.tx_errors); + break; + } + + case -EPROTO: + case -ETIMEDOUT: + case -EILSEQ: + { + hfa384x_t *hw = wlandev->priv; + + if ( !test_and_set_bit(THROTTLE_TX, &hw->usb_flags) + && !timer_pending(&hw->throttle) ) { + mod_timer(&hw->throttle, + jiffies + THROTTLE_JIFFIES); + } + ++(wlandev->linux_stats.tx_errors); + netif_stop_queue(wlandev->netdev); + break; + } + + case -ENOENT: + case -ESHUTDOWN: + /* Ignorable errors */ + break; + + default: + WLAN_LOG_INFO("unknown urb->status=%d\n", urb->status); + ++(wlandev->linux_stats.tx_errors); + break; + } /* switch */ + } + + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* hfa384x_ctlxout_callback +* +* Callback for control data on the BULKOUT endpoint. +* +* Arguments: +* urb ptr to the completed urb +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +#ifdef URB_ONLY_CALLBACK +static void hfa384x_ctlxout_callback(struct urb *urb) +#else +static void hfa384x_ctlxout_callback(struct urb *urb, struct pt_regs *regs) +#endif +{ + hfa384x_t *hw = urb->context; + int delete_resptimer = 0; + int timer_ok = 1; + int run_queue = 0; + hfa384x_usbctlx_t *ctlx; + unsigned long flags; + + DBFENTER; + + WLAN_LOG_DEBUG(3,"urb->status=%d\n", urb->status); +#ifdef DEBUG_USB + dbprint_urb(urb); +#endif + if ( (urb->status == -ESHUTDOWN) || + (urb->status == -ENODEV) || + (hw == NULL) ) + goto done; + +retry: + spin_lock_irqsave(&hw->ctlxq.lock, flags); + + /* + * Only one CTLX at a time on the "active" list, and + * none at all if we are unplugged. However, we can + * rely on the disconnect function to clean everything + * up if someone unplugged the adapter. + */ + if ( list_empty(&hw->ctlxq.active) ) { + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + goto done; + } + + /* + * Having something on the "active" queue means + * that we have timers to worry about ... + */ + if (del_timer(&hw->reqtimer) == 0) { + if (hw->req_timer_done == 0) { + /* + * This timer was actually running while we + * were trying to delete it. Let it terminate + * gracefully instead. + */ + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + goto retry; + } + } + else { + hw->req_timer_done = 1; + } + + ctlx = get_active_ctlx(hw); + + if ( urb->status == 0 ) { + /* Request portion of a CTLX is successful */ + switch ( ctlx->state ) { + case CTLX_REQ_SUBMITTED: + /* This OUT-ACK received before IN */ + ctlx->state = CTLX_REQ_COMPLETE; + break; + + case CTLX_RESP_COMPLETE: + /* IN already received before this OUT-ACK, + * so this command must now be complete. + */ + ctlx->state = CTLX_COMPLETE; + unlocked_usbctlx_complete(hw, ctlx); + run_queue = 1; + break; + + default: + /* This is NOT a valid CTLX "success" state! */ + WLAN_LOG_ERROR( + "Illegal CTLX[%d] success state(%s, %d) in OUT URB\n", + hfa384x2host_16(ctlx->outbuf.type), + ctlxstr(ctlx->state), urb->status); + break; + } /* switch */ + } else { + /* If the pipe has stalled then we need to reset it */ + if ( (urb->status == -EPIPE) && + !test_and_set_bit(WORK_TX_HALT, &hw->usb_flags) ) { + WLAN_LOG_WARNING("%s tx pipe stalled: requesting reset\n", + hw->wlandev->netdev->name); + schedule_work(&hw->usb_work); + } + + /* If someone cancels the OUT URB then its status + * should be either -ECONNRESET or -ENOENT. + */ + ctlx->state = CTLX_REQ_FAILED; + unlocked_usbctlx_complete(hw, ctlx); + delete_resptimer = 1; + run_queue = 1; + } + + delresp: + if (delete_resptimer) { + if ((timer_ok = del_timer(&hw->resptimer)) != 0) { + hw->resp_timer_done = 1; + } + } + + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + + if ( !timer_ok && (hw->resp_timer_done == 0) ) { + spin_lock_irqsave(&hw->ctlxq.lock, flags); + goto delresp; + } + + if (run_queue) + hfa384x_usbctlxq_run(hw); + + done: + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* hfa384x_usbctlx_reqtimerfn +* +* Timer response function for CTLX request timeouts. If this +* function is called, it means that the callback for the OUT +* URB containing a Prism2.x XXX_Request was never called. +* +* Arguments: +* data a ptr to the hfa384x_t +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void +hfa384x_usbctlx_reqtimerfn(unsigned long data) +{ + hfa384x_t *hw = (hfa384x_t*)data; + unsigned long flags; + DBFENTER; + + spin_lock_irqsave(&hw->ctlxq.lock, flags); + + hw->req_timer_done = 1; + + /* Removing the hardware automatically empties + * the active list ... + */ + if ( !list_empty(&hw->ctlxq.active) ) + { + /* + * We must ensure that our URB is removed from + * the system, if it hasn't already expired. + */ + hw->ctlx_urb.transfer_flags |= URB_ASYNC_UNLINK; + if (usb_unlink_urb(&hw->ctlx_urb) == -EINPROGRESS) + { + hfa384x_usbctlx_t *ctlx = get_active_ctlx(hw); + + ctlx->state = CTLX_REQ_FAILED; + + /* This URB was active, but has now been + * cancelled. It will now have a status of + * -ECONNRESET in the callback function. + * + * We are cancelling this CTLX, so we're + * not going to need to wait for a response. + * The URB's callback function will check + * that this timer is truly dead. + */ + if (del_timer(&hw->resptimer) != 0) + hw->resp_timer_done = 1; + } + } + + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* hfa384x_usbctlx_resptimerfn +* +* Timer response function for CTLX response timeouts. If this +* function is called, it means that the callback for the IN +* URB containing a Prism2.x XXX_Response was never called. +* +* Arguments: +* data a ptr to the hfa384x_t +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void +hfa384x_usbctlx_resptimerfn(unsigned long data) +{ + hfa384x_t *hw = (hfa384x_t*)data; + unsigned long flags; + + DBFENTER; + + spin_lock_irqsave(&hw->ctlxq.lock, flags); + + hw->resp_timer_done = 1; + + /* The active list will be empty if the + * adapter has been unplugged ... + */ + if ( !list_empty(&hw->ctlxq.active) ) + { + hfa384x_usbctlx_t *ctlx = get_active_ctlx(hw); + + if ( unlocked_usbctlx_cancel_async(hw, ctlx) == 0 ) + { + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + hfa384x_usbctlxq_run(hw); + goto done; + } + } + + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + + done: + DBFEXIT; +} + +/*---------------------------------------------------------------- +* hfa384x_usb_throttlefn +* +* +* Arguments: +* data ptr to hw +* +* Returns: +* Nothing +* +* Side effects: +* +* Call context: +* Interrupt +----------------------------------------------------------------*/ +static void +hfa384x_usb_throttlefn(unsigned long data) +{ + hfa384x_t *hw = (hfa384x_t*)data; + unsigned long flags; + + DBFENTER; + + spin_lock_irqsave(&hw->ctlxq.lock, flags); + + /* + * We need to check BOTH the RX and the TX throttle controls, + * so we use the bitwise OR instead of the logical OR. + */ + WLAN_LOG_DEBUG(3, "flags=0x%lx\n", hw->usb_flags); + if ( !hw->wlandev->hwremoved && + ( + (test_and_clear_bit(THROTTLE_RX, &hw->usb_flags) && + !test_and_set_bit(WORK_RX_RESUME, &hw->usb_flags)) + | + (test_and_clear_bit(THROTTLE_TX, &hw->usb_flags) && + !test_and_set_bit(WORK_TX_RESUME, &hw->usb_flags)) + ) ) + { + schedule_work(&hw->usb_work); + } + + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* hfa384x_usbctlx_submit +* +* Called from the doxxx functions to submit a CTLX to the queue +* +* Arguments: +* hw ptr to the hw struct +* ctlx ctlx structure to enqueue +* +* Returns: +* -ENODEV if the adapter is unplugged +* 0 +* +* Side effects: +* +* Call context: +* process or interrupt +----------------------------------------------------------------*/ +static int +hfa384x_usbctlx_submit( + hfa384x_t *hw, + hfa384x_usbctlx_t *ctlx) +{ + unsigned long flags; + int ret; + + DBFENTER; + + spin_lock_irqsave(&hw->ctlxq.lock, flags); + + if (hw->wlandev->hwremoved) { + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + ret = -ENODEV; + } else { + ctlx->state = CTLX_PENDING; + list_add_tail(&ctlx->list, &hw->ctlxq.pending); + + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + hfa384x_usbctlxq_run(hw); + ret = 0; + } + + DBFEXIT; + return ret; +} + + +/*---------------------------------------------------------------- +* hfa384x_usbout_tx +* +* At this point we have finished a send of a frame. Mark the URB +* as available and call ev_alloc to notify higher layers we're +* ready for more. +* +* Arguments: +* wlandev wlan device +* usbout ptr to the usb transfer buffer +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void hfa384x_usbout_tx(wlandevice_t *wlandev, hfa384x_usbout_t *usbout) +{ + DBFENTER; + + prism2sta_ev_alloc(wlandev); + + DBFEXIT; +} + +/*---------------------------------------------------------------- +* hfa384x_isgood_pdrcore +* +* Quick check of PDR codes. +* +* Arguments: +* pdrcode PDR code number (host order) +* +* Returns: +* zero not good. +* one is good. +* +* Side effects: +* +* Call context: +----------------------------------------------------------------*/ +static int +hfa384x_isgood_pdrcode(UINT16 pdrcode) +{ + switch(pdrcode) { + case HFA384x_PDR_END_OF_PDA: + case HFA384x_PDR_PCB_PARTNUM: + case HFA384x_PDR_PDAVER: + case HFA384x_PDR_NIC_SERIAL: + case HFA384x_PDR_MKK_MEASUREMENTS: + case HFA384x_PDR_NIC_RAMSIZE: + case HFA384x_PDR_MFISUPRANGE: + case HFA384x_PDR_CFISUPRANGE: + case HFA384x_PDR_NICID: + case HFA384x_PDR_MAC_ADDRESS: + case HFA384x_PDR_REGDOMAIN: + case HFA384x_PDR_ALLOWED_CHANNEL: + case HFA384x_PDR_DEFAULT_CHANNEL: + case HFA384x_PDR_TEMPTYPE: + case HFA384x_PDR_IFR_SETTING: + case HFA384x_PDR_RFR_SETTING: + case HFA384x_PDR_HFA3861_BASELINE: + case HFA384x_PDR_HFA3861_SHADOW: + case HFA384x_PDR_HFA3861_IFRF: + case HFA384x_PDR_HFA3861_CHCALSP: + case HFA384x_PDR_HFA3861_CHCALI: + case HFA384x_PDR_3842_NIC_CONFIG: + case HFA384x_PDR_USB_ID: + case HFA384x_PDR_PCI_ID: + case HFA384x_PDR_PCI_IFCONF: + case HFA384x_PDR_PCI_PMCONF: + case HFA384x_PDR_RFENRGY: + case HFA384x_PDR_HFA3861_MANF_TESTSP: + case HFA384x_PDR_HFA3861_MANF_TESTI: + /* code is OK */ + return 1; + break; + default: + if ( pdrcode < 0x1000 ) { + /* code is OK, but we don't know exactly what it is */ + WLAN_LOG_DEBUG(3, + "Encountered unknown PDR#=0x%04x, " + "assuming it's ok.\n", + pdrcode); + return 1; + } else { + /* bad code */ + WLAN_LOG_DEBUG(3, + "Encountered unknown PDR#=0x%04x, " + "(>=0x1000), assuming it's bad.\n", + pdrcode); + return 0; + } + break; + } + return 0; /* avoid compiler warnings */ +} + --- linux-2.6.27.orig/ubuntu/misc/wireless/prism2_usb/prism2mib.c +++ linux-2.6.27/ubuntu/misc/wireless/prism2_usb/prism2mib.c @@ -0,0 +1,3794 @@ +/* src/prism2/driver/prism2mib.c +* +* Management request for mibset/mibget +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* The functions in this file handle the mibset/mibget management +* functions. +* +* -------------------------------------------------------------------- +*/ + +/*================================================================*/ +/* System Includes */ +#define WLAN_DBVAR prism2_debug + +#include + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if (WLAN_HOSTIF == WLAN_PCMCIA) +#include +#include +#include +#include +#include +#include +#endif + +#if ((WLAN_HOSTIF == WLAN_PLX) || (WLAN_HOSTIF == WLAN_PCI)) +#include +#include +#endif + +#if (WLAN_HOSTIF == WLAN_USB) +#include +#endif + +#include + +/*================================================================*/ +/* Project Includes */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*================================================================*/ +/* Local Constants */ + +#define MIB_TMP_MAXLEN 200 /* Max length of RID record (in bytes). */ + +/*================================================================*/ +/* Local Types */ + +#define F_AP 0x1 /* MIB is supported on Access Points. */ +#define F_STA 0x2 /* MIB is supported on stations. */ +#define F_READ 0x4 /* MIB may be read. */ +#define F_WRITE 0x8 /* MIB may be written. */ + +typedef struct mibrec +{ + UINT32 did; + UINT16 flag; + UINT16 parm1; + UINT16 parm2; + UINT16 parm3; + int (*func)(struct mibrec *mib, + int isget, + wlandevice_t *wlandev, + hfa384x_t *hw, + p80211msg_dot11req_mibset_t *msg, + void *data); +} mibrec_t; + +/*================================================================*/ +/* Local Function Declarations */ + +static int prism2mib_bytestr2pstr( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_bytearea2pstr( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_uint32( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_uint32array( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_uint32offset( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_truth( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_preamble( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_flag( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_appcfinfoflag( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_regulatorydomains( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_wepdefaultkey( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_powermanagement( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_privacyinvoked( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_excludeunencrypted( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_fragmentationthreshold( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_operationalrateset( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_groupaddress( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_fwid( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_authalg( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_authalgenable( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static int prism2mib_priv( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data); + +static void prism2mib_priv_authlist( +hfa384x_t *hw, +prism2sta_authlist_t *list); + +static void prism2mib_priv_accessmode( +hfa384x_t *hw, +UINT32 mode); + +static void prism2mib_priv_accessallow( +hfa384x_t *hw, +p80211macarray_t *macarray); + +static void prism2mib_priv_accessdeny( +hfa384x_t *hw, +p80211macarray_t *macarray); + +static void prism2mib_priv_deauthenticate( +hfa384x_t *hw, +UINT8 *addr); + +/*================================================================*/ +/* Local Static Definitions */ + +static mibrec_t mibtab[] = { + + /* dot11smt MIB's */ + + { DIDmib_dot11smt_dot11StationConfigTable_dot11StationID, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFOWNMACADDR, HFA384x_RID_CNFOWNMACADDR_LEN, 0, + prism2mib_bytearea2pstr }, + { DIDmib_dot11smt_dot11StationConfigTable_dot11MediumOccupancyLimit, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFAPPCFINFO, HFA384x_RID_CNFAPPCFINFO_LEN, 0, + prism2mib_uint32offset }, + { DIDmib_dot11smt_dot11StationConfigTable_dot11CFPollable, + F_STA | F_READ, + HFA384x_RID_CFPOLLABLE, 0, 0, + prism2mib_uint32 }, + { DIDmib_dot11smt_dot11StationConfigTable_dot11CFPPeriod, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFAPPCFINFO, HFA384x_RID_CNFAPPCFINFO_LEN, 1, + prism2mib_uint32offset }, + { DIDmib_dot11smt_dot11StationConfigTable_dot11CFPMaxDuration, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFAPPCFINFO, HFA384x_RID_CNFAPPCFINFO_LEN, 2, + prism2mib_uint32offset }, + { DIDmib_dot11smt_dot11StationConfigTable_dot11AuthenticationResponseTimeOut, + F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFAUTHRSPTIMEOUT, 0, 0, + prism2mib_uint32 }, + { DIDmib_dot11smt_dot11StationConfigTable_dot11PrivacyOptionImplemented, + F_AP | F_STA | F_READ, + HFA384x_RID_PRIVACYOPTIMP, 0, 0, + prism2mib_uint32 }, + { DIDmib_dot11smt_dot11StationConfigTable_dot11PowerManagementMode, + F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFPMENABLED, 0, 0, + prism2mib_powermanagement }, + { DIDmib_dot11smt_dot11StationConfigTable_dot11DesiredSSID, + F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFDESIREDSSID, HFA384x_RID_CNFDESIREDSSID_LEN, 0, + prism2mib_bytestr2pstr }, + { DIDmib_dot11smt_dot11StationConfigTable_dot11DesiredBSSType, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_priv }, + { DIDmib_dot11smt_dot11StationConfigTable_dot11OperationalRateSet, + F_STA | F_READ | F_WRITE, + HFA384x_RID_TXRATECNTL, 0, 0, + prism2mib_operationalrateset }, + { DIDmib_dot11smt_dot11StationConfigTable_dot11OperationalRateSet, + F_AP | F_READ | F_WRITE, + HFA384x_RID_TXRATECNTL0, 0, 0, + prism2mib_operationalrateset }, + { DIDmib_dot11smt_dot11StationConfigTable_dot11BeaconPeriod, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFAPBCNINT, 0, 0, + prism2mib_uint32 }, + { DIDmib_dot11smt_dot11StationConfigTable_dot11DTIMPeriod, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFOWNDTIMPER, 0, 0, + prism2mib_uint32 }, + { DIDmib_dot11smt_dot11StationConfigTable_dot11AssociationResponseTimeOut, + F_AP | F_STA | F_READ, + HFA384x_RID_PROTOCOLRSPTIME, 0, 0, + prism2mib_uint32 }, + { DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithm1, + F_AP | F_STA | F_READ, + 1, 0, 0, + prism2mib_authalg }, + { DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithm2, + F_AP | F_STA | F_READ, + 2, 0, 0, + prism2mib_authalg }, + { DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithm3, + F_AP | F_STA | F_READ, + 3, 0, 0, + prism2mib_authalg }, + { DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithm4, + F_AP | F_STA | F_READ, + 4, 0, 0, + prism2mib_authalg }, + { DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithm5, + F_AP | F_STA | F_READ, + 5, 0, 0, + prism2mib_authalg }, + { DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithm6, + F_AP | F_STA | F_READ, + 6, 0, 0, + prism2mib_authalg }, + { DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithmsEnable1, + F_AP | F_STA | F_READ | F_WRITE, + 1, 0, 0, + prism2mib_authalgenable }, + { DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithmsEnable2, + F_AP | F_STA | F_READ | F_WRITE, + 2, 0, 0, + prism2mib_authalgenable }, + { DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithmsEnable3, + F_AP | F_STA | F_READ | F_WRITE, + 3, 0, 0, + prism2mib_authalgenable }, + { DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithmsEnable4, + F_AP | F_STA | F_READ | F_WRITE, + 4, 0, 0, + prism2mib_authalgenable }, + { DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithmsEnable5, + F_AP | F_STA | F_READ | F_WRITE, + 5, 0, 0, + prism2mib_authalgenable }, + { DIDmib_dot11smt_dot11AuthenticationAlgorithmsTable_dot11AuthenticationAlgorithmsEnable6, + F_AP | F_STA | F_READ | F_WRITE, + 6, 0, 0, + prism2mib_authalgenable }, + { DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0, + F_AP | F_STA | F_WRITE, + HFA384x_RID_CNFWEPDEFAULTKEY0, 0, 0, + prism2mib_wepdefaultkey }, + { DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1, + F_AP | F_STA | F_WRITE, + HFA384x_RID_CNFWEPDEFAULTKEY1, 0, 0, + prism2mib_wepdefaultkey }, + { DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2, + F_AP | F_STA | F_WRITE, + HFA384x_RID_CNFWEPDEFAULTKEY2, 0, 0, + prism2mib_wepdefaultkey }, + { DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3, + F_AP | F_STA | F_WRITE, + HFA384x_RID_CNFWEPDEFAULTKEY3, 0, 0, + prism2mib_wepdefaultkey }, + { DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFWEPFLAGS, HFA384x_WEPFLAGS_PRIVINVOKED, 0, + prism2mib_privacyinvoked }, + { DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFWEPDEFAULTKEYID, 0, 0, + prism2mib_uint32 }, + { DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFWEPFLAGS, HFA384x_WEPFLAGS_EXCLUDE, 0, + prism2mib_excludeunencrypted }, + { DIDmib_dot11phy_dot11PhyOperationTable_dot11ShortPreambleEnabled, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFSHORTPREAMBLE, 0, 0, + prism2mib_preamble }, + + /* dot11mac MIB's */ + + { DIDmib_dot11mac_dot11OperationTable_dot11MACAddress, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFOWNMACADDR, HFA384x_RID_CNFOWNMACADDR_LEN, 0, + prism2mib_bytearea2pstr }, + { DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold, + F_STA | F_READ | F_WRITE, + HFA384x_RID_RTSTHRESH, 0, 0, + prism2mib_uint32 }, + { DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold, + F_AP | F_READ | F_WRITE, + HFA384x_RID_RTSTHRESH0, 0, 0, + prism2mib_uint32 }, + { DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit, + F_AP | F_STA | F_READ, + HFA384x_RID_SHORTRETRYLIMIT, 0, 0, + prism2mib_uint32 }, + { DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit, + F_AP | F_STA | F_READ, + HFA384x_RID_LONGRETRYLIMIT, 0, 0, + prism2mib_uint32 }, + { DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold, + F_STA | F_READ | F_WRITE, + HFA384x_RID_FRAGTHRESH, 0, 0, + prism2mib_fragmentationthreshold }, + { DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold, + F_AP | F_READ | F_WRITE, + HFA384x_RID_FRAGTHRESH0, 0, 0, + prism2mib_fragmentationthreshold }, + { DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime, + F_AP | F_STA | F_READ, + HFA384x_RID_MAXTXLIFETIME, 0, 0, + prism2mib_uint32 }, + { DIDmib_dot11mac_dot11OperationTable_dot11MaxReceiveLifetime, + F_AP | F_STA | F_READ, + HFA384x_RID_MAXRXLIFETIME, 0, 0, + prism2mib_uint32 }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address1, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address2, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address3, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address4, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address5, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address6, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address7, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address8, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address9, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address10, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address11, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address12, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address13, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address14, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address15, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address16, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address17, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address18, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address19, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address20, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address21, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address22, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address23, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address24, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address25, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address26, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address27, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address28, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address29, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address30, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address31, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + { DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address32, + F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_groupaddress }, + + /* dot11phy MIB's */ + + { DIDmib_dot11phy_dot11PhyOperationTable_dot11PHYType, + F_AP | F_STA | F_READ, + HFA384x_RID_PHYTYPE, 0, 0, + prism2mib_uint32 }, + { DIDmib_dot11phy_dot11PhyOperationTable_dot11TempType, + F_AP | F_STA | F_READ, + HFA384x_RID_TEMPTYPE, 0, 0, + prism2mib_uint32 }, + { DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel, + F_STA | F_READ, + HFA384x_RID_CURRENTCHANNEL, 0, 0, + prism2mib_uint32 }, + { DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel, + F_AP | F_READ, + HFA384x_RID_CNFOWNCHANNEL, 0, 0, + prism2mib_uint32 }, + { DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentCCAMode, + F_AP | F_STA | F_READ, + HFA384x_RID_CCAMODE, 0, 0, + prism2mib_uint32 }, + + /* p2Table MIB's */ + + { DIDmib_p2_p2Table_p2MMTx, + F_AP | F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_priv }, + { DIDmib_p2_p2Table_p2EarlyBeacon, + F_AP | F_READ | F_WRITE, + BIT7, 0, 0, + prism2mib_appcfinfoflag }, + { DIDmib_p2_p2Table_p2ReceivedFrameStatistics, + F_AP | F_STA | F_READ, + 0, 0, 0, + prism2mib_priv }, + { DIDmib_p2_p2Table_p2CommunicationTallies, + F_AP | F_STA | F_READ, + 0, 0, 0, + prism2mib_priv }, + { DIDmib_p2_p2Table_p2Authenticated, + F_AP | F_READ, + 0, 0, 0, + prism2mib_priv }, + { DIDmib_p2_p2Table_p2Associated, + F_AP | F_READ, + 0, 0, 0, + prism2mib_priv }, + { DIDmib_p2_p2Table_p2PowerSaveUserCount, + F_AP | F_READ, + 0, 0, 0, + prism2mib_priv }, + { DIDmib_p2_p2Table_p2Comment, + F_AP | F_STA | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_priv }, + { DIDmib_p2_p2Table_p2AccessMode, + F_AP | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_priv }, + { DIDmib_p2_p2Table_p2AccessAllow, + F_AP | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_priv }, + { DIDmib_p2_p2Table_p2AccessDeny, + F_AP | F_READ | F_WRITE, + 0, 0, 0, + prism2mib_priv }, + { DIDmib_p2_p2Table_p2ChannelInfoResults, + F_AP | F_READ, + 0, 0, 0, + prism2mib_priv }, + + /* p2Static MIB's */ + + { DIDmib_p2_p2Static_p2CnfPortType, + F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFPORTTYPE, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfOwnMACAddress, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFOWNMACADDR, HFA384x_RID_CNFOWNMACADDR_LEN, 0, + prism2mib_bytearea2pstr }, + { DIDmib_p2_p2Static_p2CnfDesiredSSID, + F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFDESIREDSSID, HFA384x_RID_CNFDESIREDSSID_LEN, 0, + prism2mib_bytestr2pstr }, + { DIDmib_p2_p2Static_p2CnfOwnChannel, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFOWNCHANNEL, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfOwnSSID, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFOWNSSID, HFA384x_RID_CNFOWNSSID_LEN, 0, + prism2mib_bytestr2pstr }, + { DIDmib_p2_p2Static_p2CnfOwnATIMWindow, + F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFOWNATIMWIN, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfSystemScale, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFSYSSCALE, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfMaxDataLength, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFMAXDATALEN, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfWDSAddress, + F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFWDSADDR, HFA384x_RID_CNFWDSADDR_LEN, 0, + prism2mib_bytearea2pstr }, + { DIDmib_p2_p2Static_p2CnfPMEnabled, + F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFPMENABLED, 0, 0, + prism2mib_truth }, + { DIDmib_p2_p2Static_p2CnfPMEPS, + F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFPMEPS, 0, 0, + prism2mib_truth }, + { DIDmib_p2_p2Static_p2CnfMulticastReceive, + F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFMULTICASTRX, 0, 0, + prism2mib_truth }, + { DIDmib_p2_p2Static_p2CnfMaxSleepDuration, + F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFMAXSLEEPDUR, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfPMHoldoverDuration, + F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFPMHOLDDUR, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfOwnName, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFOWNNAME, HFA384x_RID_CNFOWNNAME_LEN, 0, + prism2mib_bytestr2pstr }, + { DIDmib_p2_p2Static_p2CnfOwnDTIMPeriod, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFOWNDTIMPER, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfWDSAddress1, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFWDSADDR1, HFA384x_RID_CNFWDSADDR1_LEN, 0, + prism2mib_bytearea2pstr }, + { DIDmib_p2_p2Static_p2CnfWDSAddress2, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFWDSADDR2, HFA384x_RID_CNFWDSADDR2_LEN, 0, + prism2mib_bytearea2pstr }, + { DIDmib_p2_p2Static_p2CnfWDSAddress3, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFWDSADDR3, HFA384x_RID_CNFWDSADDR3_LEN, 0, + prism2mib_bytearea2pstr }, + { DIDmib_p2_p2Static_p2CnfWDSAddress4, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFWDSADDR4, HFA384x_RID_CNFWDSADDR4_LEN, 0, + prism2mib_bytearea2pstr }, + { DIDmib_p2_p2Static_p2CnfWDSAddress5, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFWDSADDR5, HFA384x_RID_CNFWDSADDR5_LEN, 0, + prism2mib_bytearea2pstr }, + { DIDmib_p2_p2Static_p2CnfWDSAddress6, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFWDSADDR6, HFA384x_RID_CNFWDSADDR6_LEN, 0, + prism2mib_bytearea2pstr }, + { DIDmib_p2_p2Static_p2CnfMulticastPMBuffering, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFMCASTPMBUFF, 0, 0, + prism2mib_truth }, + { DIDmib_p2_p2Static_p2CnfWEPDefaultKeyID, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFWEPDEFAULTKEYID, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfWEPDefaultKey0, + F_AP | F_STA | F_WRITE, + HFA384x_RID_CNFWEPDEFAULTKEY0, 0, 0, + prism2mib_wepdefaultkey }, + { DIDmib_p2_p2Static_p2CnfWEPDefaultKey1, + F_AP | F_STA | F_WRITE, + HFA384x_RID_CNFWEPDEFAULTKEY1, 0, 0, + prism2mib_wepdefaultkey }, + { DIDmib_p2_p2Static_p2CnfWEPDefaultKey2, + F_AP | F_STA | F_WRITE, + HFA384x_RID_CNFWEPDEFAULTKEY2, 0, 0, + prism2mib_wepdefaultkey }, + { DIDmib_p2_p2Static_p2CnfWEPDefaultKey3, + F_AP | F_STA | F_WRITE, + HFA384x_RID_CNFWEPDEFAULTKEY3, 0, 0, + prism2mib_wepdefaultkey }, + { DIDmib_p2_p2Static_p2CnfWEPFlags, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFWEPFLAGS, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfAuthentication, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFAUTHENTICATION, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfMaxAssociatedStations, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFMAXASSOCSTATIONS, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfTxControl, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFTXCONTROL, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfRoamingMode, + F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFROAMINGMODE, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfHostAuthentication, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFHOSTAUTHASSOC, 0, 0, + prism2mib_truth }, + { DIDmib_p2_p2Static_p2CnfRcvCrcError, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFRCVCRCERROR, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfAltRetryCount, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFALTRETRYCNT, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfBeaconInterval, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFAPBCNINT, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfMediumOccupancyLimit, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFAPPCFINFO, HFA384x_RID_CNFAPPCFINFO_LEN, 0, + prism2mib_uint32offset }, + { DIDmib_p2_p2Static_p2CnfCFPPeriod, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFAPPCFINFO, HFA384x_RID_CNFAPPCFINFO_LEN, 1, + prism2mib_uint32offset }, + { DIDmib_p2_p2Static_p2CnfCFPMaxDuration, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFAPPCFINFO, HFA384x_RID_CNFAPPCFINFO_LEN, 2, + prism2mib_uint32offset }, + { DIDmib_p2_p2Static_p2CnfCFPFlags, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFAPPCFINFO, HFA384x_RID_CNFAPPCFINFO_LEN, 3, + prism2mib_uint32offset }, + { DIDmib_p2_p2Static_p2CnfSTAPCFInfo, + F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFSTAPCFINFO, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfPriorityQUsage, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFPRIORITYQUSAGE, HFA384x_RID_CNFPRIOQUSAGE_LEN, 0, + prism2mib_uint32array }, + { DIDmib_p2_p2Static_p2CnfTIMCtrl, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFTIMCTRL, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfThirty2Tally, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFTHIRTY2TALLY, 0, 0, + prism2mib_truth }, + { DIDmib_p2_p2Static_p2CnfEnhSecurity, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFENHSECURITY, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfShortPreamble, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFSHORTPREAMBLE, 0, 0, + prism2mib_preamble }, + { DIDmib_p2_p2Static_p2CnfExcludeLongPreamble, + F_AP | F_READ | F_WRITE, + HFA384x_RID_CNFEXCLONGPREAMBLE, 0, 0, + prism2mib_truth }, + { DIDmib_p2_p2Static_p2CnfAuthenticationRspTO, + F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFAUTHRSPTIMEOUT, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfBasicRates, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFBASICRATES, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Static_p2CnfSupportedRates, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFSUPPRATES, 0, 0, + prism2mib_uint32 }, + + /* p2Dynamic MIB's */ + + { DIDmib_p2_p2Dynamic_p2CreateIBSS, + F_STA | F_READ | F_WRITE, + HFA384x_RID_CREATEIBSS, 0, 0, + prism2mib_truth }, + { DIDmib_p2_p2Dynamic_p2FragmentationThreshold, + F_STA | F_READ | F_WRITE, + HFA384x_RID_FRAGTHRESH, 0, 0, + prism2mib_fragmentationthreshold }, + { DIDmib_p2_p2Dynamic_p2RTSThreshold, + F_STA | F_READ | F_WRITE, + HFA384x_RID_RTSTHRESH, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Dynamic_p2TxRateControl, + F_STA | F_READ | F_WRITE, + HFA384x_RID_TXRATECNTL, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Dynamic_p2PromiscuousMode, + F_STA | F_READ | F_WRITE, + HFA384x_RID_PROMISCMODE, 0, 0, + prism2mib_truth }, + { DIDmib_p2_p2Dynamic_p2FragmentationThreshold0, + F_AP | F_READ | F_WRITE, + HFA384x_RID_FRAGTHRESH0, 0, 0, + prism2mib_fragmentationthreshold }, + { DIDmib_p2_p2Dynamic_p2FragmentationThreshold1, + F_AP | F_READ | F_WRITE, + HFA384x_RID_FRAGTHRESH1, 0, 0, + prism2mib_fragmentationthreshold }, + { DIDmib_p2_p2Dynamic_p2FragmentationThreshold2, + F_AP | F_READ | F_WRITE, + HFA384x_RID_FRAGTHRESH2, 0, 0, + prism2mib_fragmentationthreshold }, + { DIDmib_p2_p2Dynamic_p2FragmentationThreshold3, + F_AP | F_READ | F_WRITE, + HFA384x_RID_FRAGTHRESH3, 0, 0, + prism2mib_fragmentationthreshold }, + { DIDmib_p2_p2Dynamic_p2FragmentationThreshold4, + F_AP | F_READ | F_WRITE, + HFA384x_RID_FRAGTHRESH4, 0, 0, + prism2mib_fragmentationthreshold }, + { DIDmib_p2_p2Dynamic_p2FragmentationThreshold5, + F_AP | F_READ | F_WRITE, + HFA384x_RID_FRAGTHRESH5, 0, 0, + prism2mib_fragmentationthreshold }, + { DIDmib_p2_p2Dynamic_p2FragmentationThreshold6, + F_AP | F_READ | F_WRITE, + HFA384x_RID_FRAGTHRESH6, 0, 0, + prism2mib_fragmentationthreshold }, + { DIDmib_p2_p2Dynamic_p2RTSThreshold0, + F_AP | F_READ | F_WRITE, + HFA384x_RID_RTSTHRESH0, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Dynamic_p2RTSThreshold1, + F_AP | F_READ | F_WRITE, + HFA384x_RID_RTSTHRESH1, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Dynamic_p2RTSThreshold2, + F_AP | F_READ | F_WRITE, + HFA384x_RID_RTSTHRESH2, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Dynamic_p2RTSThreshold3, + F_AP | F_READ | F_WRITE, + HFA384x_RID_RTSTHRESH3, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Dynamic_p2RTSThreshold4, + F_AP | F_READ | F_WRITE, + HFA384x_RID_RTSTHRESH4, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Dynamic_p2RTSThreshold5, + F_AP | F_READ | F_WRITE, + HFA384x_RID_RTSTHRESH5, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Dynamic_p2RTSThreshold6, + F_AP | F_READ | F_WRITE, + HFA384x_RID_RTSTHRESH6, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Dynamic_p2TxRateControl0, + F_AP | F_READ | F_WRITE, + HFA384x_RID_TXRATECNTL0, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Dynamic_p2TxRateControl1, + F_AP | F_READ | F_WRITE, + HFA384x_RID_TXRATECNTL1, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Dynamic_p2TxRateControl2, + F_AP | F_READ | F_WRITE, + HFA384x_RID_TXRATECNTL2, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Dynamic_p2TxRateControl3, + F_AP | F_READ | F_WRITE, + HFA384x_RID_TXRATECNTL3, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Dynamic_p2TxRateControl4, + F_AP | F_READ | F_WRITE, + HFA384x_RID_TXRATECNTL4, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Dynamic_p2TxRateControl5, + F_AP | F_READ | F_WRITE, + HFA384x_RID_TXRATECNTL5, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Dynamic_p2TxRateControl6, + F_AP | F_READ | F_WRITE, + HFA384x_RID_TXRATECNTL6, 0, 0, + prism2mib_uint32 }, + + /* p2Behavior MIB's */ + + { DIDmib_p2_p2Behavior_p2TickTime, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_ITICKTIME, 0, 0, + prism2mib_uint32 }, + + /* p2NIC MIB's */ + + { DIDmib_p2_p2NIC_p2MaxLoadTime, + F_AP | F_STA | F_READ, + HFA384x_RID_MAXLOADTIME, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2NIC_p2DLBufferPage, + F_AP | F_STA | F_READ, + HFA384x_RID_DOWNLOADBUFFER, HFA384x_RID_DOWNLOADBUFFER_LEN, 0, + prism2mib_uint32offset }, + { DIDmib_p2_p2NIC_p2DLBufferOffset, + F_AP | F_STA | F_READ, + HFA384x_RID_DOWNLOADBUFFER, HFA384x_RID_DOWNLOADBUFFER_LEN, 1, + prism2mib_uint32offset }, + { DIDmib_p2_p2NIC_p2DLBufferLength, + F_AP | F_STA | F_READ, + HFA384x_RID_DOWNLOADBUFFER, HFA384x_RID_DOWNLOADBUFFER_LEN, 2, + prism2mib_uint32offset }, + { DIDmib_p2_p2NIC_p2PRIIdentity, + F_AP | F_STA | F_READ, + HFA384x_RID_PRIIDENTITY, HFA384x_RID_PRIIDENTITY_LEN, 0, + prism2mib_uint32array }, + { DIDmib_p2_p2NIC_p2PRISupRange, + F_AP | F_STA | F_READ, + HFA384x_RID_PRISUPRANGE, HFA384x_RID_PRISUPRANGE_LEN, 0, + prism2mib_uint32array }, + { DIDmib_p2_p2NIC_p2CFIActRanges, + F_AP | F_STA | F_READ, + HFA384x_RID_PRI_CFIACTRANGES, HFA384x_RID_CFIACTRANGES_LEN, 0, + prism2mib_uint32array }, + { DIDmib_p2_p2NIC_p2BuildSequence, + F_AP | F_STA | F_READ, + HFA384x_RID_BUILDSEQ, HFA384x_RID_BUILDSEQ_LEN, 0, + prism2mib_uint32array }, + { DIDmib_p2_p2NIC_p2PrimaryFWID, + F_AP | F_STA | F_READ, + 0, 0, 0, + prism2mib_fwid }, + { DIDmib_p2_p2NIC_p2SecondaryFWID, + F_AP | F_STA | F_READ, + 0, 0, 0, + prism2mib_fwid }, + { DIDmib_p2_p2NIC_p2TertiaryFWID, + F_AP | F_READ, + 0, 0, 0, + prism2mib_fwid }, + { DIDmib_p2_p2NIC_p2NICSerialNumber, + F_AP | F_STA | F_READ, + HFA384x_RID_NICSERIALNUMBER, HFA384x_RID_NICSERIALNUMBER_LEN, 0, + prism2mib_bytearea2pstr }, + { DIDmib_p2_p2NIC_p2NICIdentity, + F_AP | F_STA | F_READ, + HFA384x_RID_NICIDENTITY, HFA384x_RID_NICIDENTITY_LEN, 0, + prism2mib_uint32array }, + { DIDmib_p2_p2NIC_p2MFISupRange, + F_AP | F_STA | F_READ, + HFA384x_RID_MFISUPRANGE, HFA384x_RID_MFISUPRANGE_LEN, 0, + prism2mib_uint32array }, + { DIDmib_p2_p2NIC_p2CFISupRange, + F_AP | F_STA | F_READ, + HFA384x_RID_CFISUPRANGE, HFA384x_RID_CFISUPRANGE_LEN, 0, + prism2mib_uint32array }, + { DIDmib_p2_p2NIC_p2ChannelList, + F_AP | F_STA | F_READ, + HFA384x_RID_CHANNELLIST, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2NIC_p2RegulatoryDomains, + F_AP | F_STA | F_READ, + HFA384x_RID_REGULATORYDOMAINS, HFA384x_RID_REGULATORYDOMAINS_LEN, 0, + prism2mib_regulatorydomains }, + { DIDmib_p2_p2NIC_p2TempType, + F_AP | F_STA | F_READ, + HFA384x_RID_TEMPTYPE, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2NIC_p2STAIdentity, + F_AP | F_STA | F_READ, + HFA384x_RID_STAIDENTITY, HFA384x_RID_STAIDENTITY_LEN, 0, + prism2mib_uint32array }, + { DIDmib_p2_p2NIC_p2STASupRange, + F_AP | F_STA | F_READ, + HFA384x_RID_STASUPRANGE, HFA384x_RID_STASUPRANGE_LEN, 0, + prism2mib_uint32array }, + { DIDmib_p2_p2NIC_p2MFIActRanges, + F_AP | F_STA | F_READ, + HFA384x_RID_STA_MFIACTRANGES, HFA384x_RID_MFIACTRANGES_LEN, 0, + prism2mib_uint32array }, + { DIDmib_p2_p2NIC_p2STACFIActRanges, + F_AP | F_STA | F_READ, + HFA384x_RID_STA_CFIACTRANGES, HFA384x_RID_CFIACTRANGES2_LEN, 0, + prism2mib_uint32array }, + + /* p2MAC MIB's */ + + { DIDmib_p2_p2MAC_p2PortStatus, + F_STA | F_READ, + HFA384x_RID_PORTSTATUS, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2MAC_p2CurrentSSID, + F_STA | F_READ, + HFA384x_RID_CURRENTSSID, HFA384x_RID_CURRENTSSID_LEN, 0, + prism2mib_bytestr2pstr }, + { DIDmib_p2_p2MAC_p2CurrentBSSID, + F_STA | F_READ, + HFA384x_RID_CURRENTBSSID, HFA384x_RID_CURRENTBSSID_LEN, 0, + prism2mib_bytearea2pstr }, + { DIDmib_p2_p2MAC_p2CommsQuality, + F_STA | F_READ, + HFA384x_RID_COMMSQUALITY, HFA384x_RID_COMMSQUALITY_LEN, 0, + prism2mib_uint32array }, + { DIDmib_p2_p2MAC_p2CommsQualityCQ, + F_STA | F_READ, + HFA384x_RID_COMMSQUALITY, HFA384x_RID_COMMSQUALITY_LEN, 0, + prism2mib_uint32offset }, + { DIDmib_p2_p2MAC_p2CommsQualityASL, + F_STA | F_READ, + HFA384x_RID_COMMSQUALITY, HFA384x_RID_COMMSQUALITY_LEN, 1, + prism2mib_uint32offset }, + { DIDmib_p2_p2MAC_p2CommsQualityANL, + F_STA | F_READ, + HFA384x_RID_COMMSQUALITY, HFA384x_RID_COMMSQUALITY_LEN, 2, + prism2mib_uint32offset }, + { DIDmib_p2_p2MAC_p2dbmCommsQuality, + F_STA | F_READ, + HFA384x_RID_DBMCOMMSQUALITY, HFA384x_RID_DBMCOMMSQUALITY_LEN, 0, + prism2mib_uint32array }, + { DIDmib_p2_p2MAC_p2dbmCommsQualityCQ, + F_STA | F_READ, + HFA384x_RID_COMMSQUALITY, HFA384x_RID_COMMSQUALITY_LEN, 0, + prism2mib_uint32offset }, + { DIDmib_p2_p2MAC_p2dbmCommsQualityASL, + F_STA | F_READ, + HFA384x_RID_COMMSQUALITY, HFA384x_RID_COMMSQUALITY_LEN, 1, + prism2mib_uint32offset }, + { DIDmib_p2_p2MAC_p2dbmCommsQualityANL, + F_STA | F_READ, + HFA384x_RID_COMMSQUALITY, HFA384x_RID_COMMSQUALITY_LEN, 2, + prism2mib_uint32offset }, + { DIDmib_p2_p2MAC_p2CurrentTxRate, + F_STA | F_READ, + HFA384x_RID_CURRENTTXRATE, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2MAC_p2CurrentBeaconInterval, + F_AP | F_STA | F_READ, + HFA384x_RID_CURRENTBCNINT, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2MAC_p2StaCurrentScaleThresholds, + F_STA | F_READ, + HFA384x_RID_CURRENTSCALETHRESH, HFA384x_RID_STACURSCALETHRESH_LEN, 0, + prism2mib_uint32array }, + { DIDmib_p2_p2MAC_p2APCurrentScaleThresholds, + F_AP | F_READ, + HFA384x_RID_CURRENTSCALETHRESH, HFA384x_RID_APCURSCALETHRESH_LEN, 0, + prism2mib_uint32array }, + { DIDmib_p2_p2MAC_p2ProtocolRspTime, + F_AP | F_STA | F_READ, + HFA384x_RID_PROTOCOLRSPTIME, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2MAC_p2ShortRetryLimit, + F_AP | F_STA | F_READ, + HFA384x_RID_SHORTRETRYLIMIT, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2MAC_p2LongRetryLimit, + F_AP | F_STA | F_READ, + HFA384x_RID_LONGRETRYLIMIT, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2MAC_p2MaxTransmitLifetime, + F_AP | F_STA | F_READ, + HFA384x_RID_MAXTXLIFETIME, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2MAC_p2MaxReceiveLifetime, + F_AP | F_STA | F_READ, + HFA384x_RID_MAXRXLIFETIME, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2MAC_p2CFPollable, + F_STA | F_READ, + HFA384x_RID_CFPOLLABLE, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2MAC_p2AuthenticationAlgorithms, + F_AP | F_STA | F_READ, + HFA384x_RID_AUTHALGORITHMS, HFA384x_RID_AUTHALGORITHMS_LEN, 0, + prism2mib_uint32array }, + { DIDmib_p2_p2MAC_p2PrivacyOptionImplemented, + F_AP | F_STA | F_READ, + HFA384x_RID_PRIVACYOPTIMP, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2MAC_p2CurrentTxRate1, + F_AP | F_READ, + HFA384x_RID_CURRENTTXRATE1, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2MAC_p2CurrentTxRate2, + F_AP | F_READ, + HFA384x_RID_CURRENTTXRATE2, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2MAC_p2CurrentTxRate3, + F_AP | F_READ, + HFA384x_RID_CURRENTTXRATE3, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2MAC_p2CurrentTxRate4, + F_AP | F_READ, + HFA384x_RID_CURRENTTXRATE4, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2MAC_p2CurrentTxRate5, + F_AP | F_READ, + HFA384x_RID_CURRENTTXRATE5, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2MAC_p2CurrentTxRate6, + F_AP | F_READ, + HFA384x_RID_CURRENTTXRATE6, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2MAC_p2OwnMACAddress, + F_AP | F_READ, + HFA384x_RID_OWNMACADDRESS, HFA384x_RID_OWNMACADDRESS_LEN, 0, + prism2mib_bytearea2pstr }, + + /* p2Modem MIB's */ + + { DIDmib_p2_p2Modem_p2PHYType, + F_AP | F_STA | F_READ, + HFA384x_RID_PHYTYPE, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Modem_p2CurrentChannel, + F_AP | F_STA | F_READ, + HFA384x_RID_CURRENTCHANNEL, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Modem_p2CurrentPowerState, + F_AP | F_STA | F_READ, + HFA384x_RID_CURRENTPOWERSTATE, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Modem_p2CCAMode, + F_AP | F_STA | F_READ, + HFA384x_RID_CCAMODE, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Modem_p2TxPowerMax, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_TXPOWERMAX, 0, 0, + prism2mib_uint32 }, + { DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel, + F_AP | F_STA | F_READ | F_WRITE, + HFA384x_RID_TXPOWERMAX, 0, 0, + prism2mib_uint32 }, + { DIDmib_p2_p2Modem_p2SupportedDataRates, + F_AP | F_STA | F_READ, + HFA384x_RID_SUPPORTEDDATARATES, HFA384x_RID_SUPPORTEDDATARATES_LEN, 0, + prism2mib_bytestr2pstr }, + + /* And finally, lnx mibs */ + { DIDmib_lnx_lnxConfigTable_lnxRSNAIE, + F_STA | F_READ | F_WRITE, + HFA384x_RID_CNFWPADATA, 0, 0, + prism2mib_priv }, + { 0, 0, 0, 0, 0, NULL}}; + +/*---------------------------------------------------------------- +These MIB's are not supported at this time: + +DIDmib_dot11phy_dot11PhyOperationTable_dot11ChannelAgilityPresent +DIDmib_dot11phy_dot11PhyOperationTable_dot11ChannelAgilityEnabled +DIDmib_dot11phy_dot11PhyDSSSTable_dot11PBCCOptionImplemented +DIDmib_dot11phy_dot11RegDomainsSupportedTable_dot11RegDomainsSupportIndex +DIDmib_dot11phy_dot11SupportedDataRatesTxTable_dot11SupportedDataRatesTxIndex +DIDmib_dot11phy_dot11SupportedDataRatesTxTable_dot11SupportedDataRatesTxValue +DIDmib_dot11phy_dot11SupportedDataRatesRxTable_dot11SupportedDataRatesRxIndex +DIDmib_dot11phy_dot11SupportedDataRatesRxTable_dot11SupportedDataRatesRxValue + +DIDmib_dot11phy_dot11RegDomainsSupportedTable_dot11RegDomainsSupportValue +TODO: need to investigate why wlan has this as enumerated and Prism2 has this + as btye str. + +DIDmib_dot11phy_dot11PhyDSSSTable_dot11ShortPreambleOptionImplemented +TODO: Find out the firmware version number(s) for identifying + whether the firmware is capable of short preamble. TRUE or FALSE + will be returned based on the version of the firmware. + +WEP Key mappings aren't supported in the f/w. +DIDmib_dot11smt_dot11WEPKeyMappingsTable_dot11WEPKeyMappingIndex +DIDmib_dot11smt_dot11WEPKeyMappingsTable_dot11WEPKeyMappingAddress +DIDmib_dot11smt_dot11WEPKeyMappingsTable_dot11WEPKeyMappingWEPOn +DIDmib_dot11smt_dot11WEPKeyMappingsTable_dot11WEPKeyMappingValue +DIDmib_dot11smt_dot11PrivacyTable_dot11WEPKeyMappingLength + +TODO: implement counters. +DIDmib_dot11smt_dot11PrivacyTable_dot11WEPICVErrorCount +DIDmib_dot11smt_dot11PrivacyTable_dot11WEPExcludedCount +DIDmib_dot11mac_dot11CountersTable_dot11TransmittedFragmentCount +DIDmib_dot11mac_dot11CountersTable_dot11MulticastTransmittedFrameCount +DIDmib_dot11mac_dot11CountersTable_dot11FailedCount +DIDmib_dot11mac_dot11CountersTable_dot11RetryCount +DIDmib_dot11mac_dot11CountersTable_dot11MultipleRetryCount +DIDmib_dot11mac_dot11CountersTable_dot11FrameDuplicateCount +DIDmib_dot11mac_dot11CountersTable_dot11RTSSuccessCount +DIDmib_dot11mac_dot11CountersTable_dot11RTSFailureCount +DIDmib_dot11mac_dot11CountersTable_dot11ACKFailureCount +DIDmib_dot11mac_dot11CountersTable_dot11ReceivedFragmentCount +DIDmib_dot11mac_dot11CountersTable_dot11MulticastReceivedFrameCount +DIDmib_dot11mac_dot11CountersTable_dot11FCSErrorCount +DIDmib_dot11mac_dot11CountersTable_dot11TransmittedFrameCount +DIDmib_dot11mac_dot11CountersTable_dot11WEPUndecryptableCount + +TODO: implement sane values for these. +DIDmib_dot11mac_dot11OperationTable_dot11ManufacturerID +DIDmib_dot11mac_dot11OperationTable_dot11ProductID + +Not too worried about these at the moment. +DIDmib_dot11phy_dot11PhyAntennaTable_dot11CurrentTxAntenna +DIDmib_dot11phy_dot11PhyAntennaTable_dot11DiversitySupport +DIDmib_dot11phy_dot11PhyAntennaTable_dot11CurrentRxAntenna +DIDmib_dot11phy_dot11PhyTxPowerTable_dot11NumberSupportedPowerLevels +DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel1 +DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel2 +DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel3 +DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel4 +DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel5 +DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel6 +DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel7 +DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel8 +DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel + +Ummm, FH and IR don't apply +DIDmib_dot11phy_dot11PhyFHSSTable_dot11HopTime +DIDmib_dot11phy_dot11PhyFHSSTable_dot11CurrentChannelNumber +DIDmib_dot11phy_dot11PhyFHSSTable_dot11MaxDwellTime +DIDmib_dot11phy_dot11PhyFHSSTable_dot11CurrentDwellTime +DIDmib_dot11phy_dot11PhyFHSSTable_dot11CurrentSet +DIDmib_dot11phy_dot11PhyFHSSTable_dot11CurrentPattern +DIDmib_dot11phy_dot11PhyFHSSTable_dot11CurrentIndex +DIDmib_dot11phy_dot11PhyDSSSTable_dot11CCAModeSupported +DIDmib_dot11phy_dot11PhyDSSSTable_dot11EDThreshold +DIDmib_dot11phy_dot11PhyIRTable_dot11CCAWatchdogTimerMax +DIDmib_dot11phy_dot11PhyIRTable_dot11CCAWatchdogCountMax +DIDmib_dot11phy_dot11PhyIRTable_dot11CCAWatchdogTimerMin +DIDmib_dot11phy_dot11PhyIRTable_dot11CCAWatchdogCountMin + +We just don't have enough antennas right now to worry about this. +DIDmib_dot11phy_dot11AntennasListTable_dot11AntennaListIndex +DIDmib_dot11phy_dot11AntennasListTable_dot11SupportedTxAntenna +DIDmib_dot11phy_dot11AntennasListTable_dot11SupportedRxAntenna +DIDmib_dot11phy_dot11AntennasListTable_dot11DiversitySelectionRx + +------------------------------------------------------------------*/ + +/*================================================================*/ +/* Function Definitions */ + +/*---------------------------------------------------------------- +* prism2mgmt_mibset_mibget +* +* Set the value of a mib item. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ + +int prism2mgmt_mibset_mibget(wlandevice_t *wlandev, void *msgp) +{ + hfa384x_t *hw = wlandev->priv; + int result, isget; + mibrec_t *mib; + UINT16 which; + + p80211msg_dot11req_mibset_t *msg = msgp; + p80211itemd_t *mibitem; + + DBFENTER; + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_success; + + /* + ** Determine if this is an Access Point or a station. + */ + + which = hw->ap ? F_AP : F_STA; + + /* + ** Find the MIB in the MIB table. Note that a MIB may be in the + ** table twice...once for an AP and once for a station. Make sure + ** to get the correct one. Note that DID=0 marks the end of the + ** MIB table. + */ + + mibitem = (p80211itemd_t *) msg->mibattribute.data; + + for (mib = mibtab; mib->did != 0; mib++) + if (mib->did == mibitem->did && (mib->flag & which)) + break; + + if (mib->did == 0) { + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + goto done; + } + + /* + ** Determine if this is a "mibget" or a "mibset". If this is a + ** "mibget", then make sure that the MIB may be read. Otherwise, + ** this is a "mibset" so make make sure that the MIB may be written. + */ + + isget = (msg->msgcode == DIDmsg_dot11req_mibget); + + if (isget) { + if (!(mib->flag & F_READ)) { + msg->resultcode.data = + P80211ENUM_resultcode_cant_get_writeonly_mib; + goto done; + } + } else { + if (!(mib->flag & F_WRITE)) { + msg->resultcode.data = + P80211ENUM_resultcode_cant_set_readonly_mib; + goto done; + } + } + + /* + ** Execute the MIB function. If things worked okay, then make + ** sure that the MIB function also worked okay. If so, and this + ** is a "mibget", then the status value must be set for both the + ** "mibattribute" parameter and the mib item within the data + ** portion of the "mibattribute". + */ + + result = mib->func(mib, isget, wlandev, hw, msg, + (void *) mibitem->data); + + if (msg->resultcode.data == P80211ENUM_resultcode_success) { + if (result != 0) { + WLAN_LOG_DEBUG(1, "get/set failure, result=%d\n", + result); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + } else { + if (isget) { + msg->mibattribute.status = + P80211ENUM_msgitem_status_data_ok; + mibitem->status = + P80211ENUM_msgitem_status_data_ok; + } + } + } + +done: + DBFEXIT; + + return(0); +} + +/*---------------------------------------------------------------- +* prism2mib_bytestr2pstr +* +* Get/set pstr data to/from a byte string. +* +* MIB record parameters: +* parm1 Prism2 RID value. +* parm2 Number of bytes of RID data. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_bytestr2pstr( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + p80211pstrd_t *pstr = (p80211pstrd_t*) data; + UINT8 bytebuf[MIB_TMP_MAXLEN]; + hfa384x_bytestr_t *p2bytestr = (hfa384x_bytestr_t*) bytebuf; + + DBFENTER; + + if (isget) { + result = hfa384x_drvr_getconfig(hw, mib->parm1, bytebuf, mib->parm2); + prism2mgmt_bytestr2pstr(p2bytestr, pstr); + } else { + memset(bytebuf, 0, mib->parm2); + prism2mgmt_pstr2bytestr(p2bytestr, pstr); + result = hfa384x_drvr_setconfig(hw, mib->parm1, bytebuf, mib->parm2); + } + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_bytearea2pstr +* +* Get/set pstr data to/from a byte area. +* +* MIB record parameters: +* parm1 Prism2 RID value. +* parm2 Number of bytes of RID data. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_bytearea2pstr( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + p80211pstrd_t *pstr = (p80211pstrd_t*) data; + UINT8 bytebuf[MIB_TMP_MAXLEN]; + + DBFENTER; + + if (isget) { + result = hfa384x_drvr_getconfig(hw, mib->parm1, bytebuf, mib->parm2); + prism2mgmt_bytearea2pstr(bytebuf, pstr, mib->parm2); + } else { + memset(bytebuf, 0, mib->parm2); + prism2mgmt_pstr2bytearea(bytebuf, pstr); + result = hfa384x_drvr_setconfig(hw, mib->parm1, bytebuf, mib->parm2); + } + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_uint32 +* +* Get/set uint32 data. +* +* MIB record parameters: +* parm1 Prism2 RID value. +* parm2 Not used. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_uint32( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + UINT32 *uint32 = (UINT32*) data; + UINT8 bytebuf[MIB_TMP_MAXLEN]; + UINT16 *wordbuf = (UINT16*) bytebuf; + + DBFENTER; + + if (isget) { + result = hfa384x_drvr_getconfig16(hw, mib->parm1, wordbuf); + *uint32 = *wordbuf; + /* [MSM] Removed, getconfig16 returns the value in host order. + * prism2mgmt_prism2int2p80211int(wordbuf, uint32); + */ + } else { + /* [MSM] Removed, setconfig16 expects host order. + * prism2mgmt_p80211int2prism2int(wordbuf, uint32); + */ + *wordbuf = *uint32; + result = hfa384x_drvr_setconfig16(hw, mib->parm1, *wordbuf); + } + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_uint32array +* +* Get/set an array of uint32 data. +* +* MIB record parameters: +* parm1 Prism2 RID value. +* parm2 Number of bytes of RID data. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_uint32array( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + UINT32 *uint32 = (UINT32 *) data; + UINT8 bytebuf[MIB_TMP_MAXLEN]; + UINT16 *wordbuf = (UINT16*) bytebuf; + int i, cnt; + + DBFENTER; + + cnt = mib->parm2 / sizeof(UINT16); + + if (isget) { + result = hfa384x_drvr_getconfig(hw, mib->parm1, wordbuf, mib->parm2); + for (i = 0; i < cnt; i++) + prism2mgmt_prism2int2p80211int(wordbuf+i, uint32+i); + } else { + for (i = 0; i < cnt; i++) + prism2mgmt_p80211int2prism2int(wordbuf+i, uint32+i); + result = hfa384x_drvr_setconfig(hw, mib->parm1, wordbuf, mib->parm2); + } + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_uint32offset +* +* Get/set a single element in an array of uint32 data. +* +* MIB record parameters: +* parm1 Prism2 RID value. +* parm2 Number of bytes of RID data. +* parm3 Element index. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_uint32offset( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + UINT32 *uint32 = (UINT32*) data; + UINT8 bytebuf[MIB_TMP_MAXLEN]; + UINT16 *wordbuf = (UINT16*) bytebuf; + UINT16 cnt; + + DBFENTER; + + cnt = mib->parm2 / sizeof(UINT16); + + result = hfa384x_drvr_getconfig(hw, mib->parm1, wordbuf, mib->parm2); + if (result == 0) { + if (isget) { + if (mib->parm3 < cnt) + prism2mgmt_prism2int2p80211int(wordbuf+mib->parm3, uint32); + else + *uint32 = 0; + } else { + if (mib->parm3 < cnt) { + prism2mgmt_p80211int2prism2int(wordbuf+mib->parm3, uint32); + result = hfa384x_drvr_setconfig(hw, mib->parm1, wordbuf, mib->parm2); + } + } + } + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_truth +* +* Get/set truth data. +* +* MIB record parameters: +* parm1 Prism2 RID value. +* parm2 Not used. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_truth( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + UINT32 *uint32 = (UINT32*) data; + UINT8 bytebuf[MIB_TMP_MAXLEN]; + UINT16 *wordbuf = (UINT16*) bytebuf; + + DBFENTER; + + if (isget) { + result = hfa384x_drvr_getconfig16(hw, mib->parm1, wordbuf); + *uint32 = (*wordbuf) ? + P80211ENUM_truth_true : P80211ENUM_truth_false; + } else { + *wordbuf = ((*uint32) == P80211ENUM_truth_true) ? 1 : 0; + result = hfa384x_drvr_setconfig16(hw, mib->parm1, *wordbuf); + } + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_flag +* +* Get/set a flag. +* +* MIB record parameters: +* parm1 Prism2 RID value. +* parm2 Bit to get/set. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_flag( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + UINT32 *uint32 = (UINT32*) data; + UINT8 bytebuf[MIB_TMP_MAXLEN]; + UINT16 *wordbuf = (UINT16*) bytebuf; + UINT32 flags; + + DBFENTER; + + result = hfa384x_drvr_getconfig16(hw, mib->parm1, wordbuf); + if (result == 0) { + /* [MSM] Removed, getconfig16 returns the value in host order. + * prism2mgmt_prism2int2p80211int(wordbuf, &flags); + */ + flags = *wordbuf; + if (isget) { + *uint32 = (flags & mib->parm2) ? + P80211ENUM_truth_true : P80211ENUM_truth_false; + } else { + if ((*uint32) == P80211ENUM_truth_true) + flags |= mib->parm2; + else + flags &= ~mib->parm2; + /* [MSM] Removed, setconfig16 expects host order. + * prism2mgmt_p80211int2prism2int(wordbuf, &flags); + */ + *wordbuf = flags; + result = hfa384x_drvr_setconfig16(hw, mib->parm1, *wordbuf); + } + } + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_appcfinfoflag +* +* Get/set a single flag in the APPCFINFO record. +* +* MIB record parameters: +* parm1 Bit to get/set. +* parm2 Not used. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_appcfinfoflag( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + UINT32 *uint32 = (UINT32*) data; + UINT8 bytebuf[MIB_TMP_MAXLEN]; + UINT16 *wordbuf = (UINT16*) bytebuf; + UINT16 word; + + DBFENTER; + + result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CNFAPPCFINFO, + bytebuf, HFA384x_RID_CNFAPPCFINFO_LEN); + if (result == 0) { + if (isget) { + *uint32 = (hfa384x2host_16(wordbuf[3]) & mib->parm1) ? + P80211ENUM_truth_true : P80211ENUM_truth_false; + } else { + word = hfa384x2host_16(wordbuf[3]); + word = ((*uint32) == P80211ENUM_truth_true) ? + (word | mib->parm1) : (word & ~mib->parm1); + wordbuf[3] = host2hfa384x_16(word); + result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFAPPCFINFO, + bytebuf, HFA384x_RID_CNFAPPCFINFO_LEN); + } + } + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_regulatorydomains +* +* Get regulatory domain data. +* +* MIB record parameters: +* parm1 Prism2 RID value. +* parm2 Number of bytes of RID data. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_regulatorydomains( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + UINT32 cnt; + p80211pstrd_t *pstr = (p80211pstrd_t*) data; + UINT8 bytebuf[MIB_TMP_MAXLEN]; + UINT16 *wordbuf = (UINT16*) bytebuf; + + DBFENTER; + + result = 0; + + if (isget) { + result = hfa384x_drvr_getconfig(hw, mib->parm1, wordbuf, mib->parm2); + prism2mgmt_prism2int2p80211int(wordbuf, &cnt); + pstr->len = (UINT8) cnt; + memcpy(pstr->data, &wordbuf[1], pstr->len); + } + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_wepdefaultkey +* +* Get/set WEP default keys. +* +* MIB record parameters: +* parm1 Prism2 RID value. +* parm2 Number of bytes of RID data. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_wepdefaultkey( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + p80211pstrd_t *pstr = (p80211pstrd_t*) data; + UINT8 bytebuf[MIB_TMP_MAXLEN]; + UINT16 len; + + DBFENTER; + + if (isget) { + result = 0; /* Should never happen. */ + } else { + len = (pstr->len > 5) ? HFA384x_RID_CNFWEP128DEFAULTKEY_LEN : + HFA384x_RID_CNFWEPDEFAULTKEY_LEN; + memset(bytebuf, 0, len); + prism2mgmt_pstr2bytearea(bytebuf, pstr); + result = hfa384x_drvr_setconfig(hw, mib->parm1, bytebuf, len); + } + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_powermanagement +* +* Get/set 802.11 power management value. Note that this is defined differently +* by 802.11 and Prism2: +* +* Meaning 802.11 Prism2 +* active 1 false +* powersave 2 true +* +* MIB record parameters: +* parm1 Prism2 RID value. +* parm2 Not used. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_powermanagement( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + UINT32 *uint32 = (UINT32*) data; + UINT32 value; + + DBFENTER; + + if (isget) { + result = prism2mib_uint32(mib, isget, wlandev, hw, msg, &value); + *uint32 = (value == 0) ? 1 : 2; + } else { + value = ((*uint32) == 1) ? 0 : 1; + result = prism2mib_uint32(mib, isget, wlandev, hw, msg, &value); + } + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_preamble +* +* Get/set Prism2 short preamble +* +* MIB record parameters: +* parm1 Prism2 RID value. +* parm2 Not used. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_preamble( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + UINT32 *uint32 = (UINT32*) data; + UINT8 bytebuf[MIB_TMP_MAXLEN]; + UINT16 *wordbuf = (UINT16*) bytebuf; + + DBFENTER; + + if (isget) { + result = hfa384x_drvr_getconfig16(hw, mib->parm1, wordbuf); + *uint32 = *wordbuf; + } else { + *wordbuf = *uint32; + result = hfa384x_drvr_setconfig16(hw, mib->parm1, *wordbuf); + } + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_privacyinvoked +* +* Get/set the dot11PrivacyInvoked value. +* +* MIB record parameters: +* parm1 Prism2 RID value. +* parm2 Bit value for PrivacyInvoked flag. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_privacyinvoked( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + + DBFENTER; + + if (wlandev->hostwep & HOSTWEP_DECRYPT) { + if (wlandev->hostwep & HOSTWEP_DECRYPT) + mib->parm2 |= HFA384x_WEPFLAGS_DISABLE_RXCRYPT; + if (wlandev->hostwep & HOSTWEP_ENCRYPT) + mib->parm2 |= HFA384x_WEPFLAGS_DISABLE_TXCRYPT; + } + + result = prism2mib_flag(mib, isget, wlandev, hw, msg, data); + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_excludeunencrypted +* +* Get/set the dot11ExcludeUnencrypted value. +* +* MIB record parameters: +* parm1 Prism2 RID value. +* parm2 Bit value for ExcludeUnencrypted flag. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_excludeunencrypted( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + + DBFENTER; + + result = prism2mib_flag(mib, isget, wlandev, hw, msg, data); + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_fragmentationthreshold +* +* Get/set the fragmentation threshold. +* +* MIB record parameters: +* parm1 Prism2 RID value. +* parm2 Not used. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_fragmentationthreshold( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + UINT32 *uint32 = (UINT32*) data; + + DBFENTER; + + if (!isget) + if ((*uint32) % 2) { + WLAN_LOG_WARNING("Attempt to set odd number " + "FragmentationThreshold\n"); + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + return(0); + } + + result = prism2mib_uint32(mib, isget, wlandev, hw, msg, data); + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_operationalrateset +* +* Get/set the operational rate set. +* +* MIB record parameters: +* parm1 Prism2 RID value. +* parm2 Not used. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_operationalrateset( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + p80211pstrd_t *pstr = (p80211pstrd_t *) data; + UINT8 bytebuf[MIB_TMP_MAXLEN]; + UINT16 *wordbuf = (UINT16*) bytebuf; + + DBFENTER; + + if (isget) { + result = hfa384x_drvr_getconfig16(hw, mib->parm1, wordbuf); + prism2mgmt_get_oprateset(wordbuf, pstr); + } else { + prism2mgmt_set_oprateset(wordbuf, pstr); + result = hfa384x_drvr_setconfig16(hw, mib->parm1, *wordbuf); + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFSUPPRATES, *wordbuf); + } + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_groupaddress +* +* Get/set the dot11GroupAddressesTable. +* +* MIB record parameters: +* parm1 Not used. +* parm2 Not used. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_groupaddress( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + p80211pstrd_t *pstr = (p80211pstrd_t *) data; + UINT8 bytebuf[MIB_TMP_MAXLEN]; + UINT16 len; + + DBFENTER; + + /* TODO: fix this. f/w doesn't support mcast filters */ + + if (isget) { + prism2mgmt_get_grpaddr(mib->did, pstr, hw); + return(0); + } + + result = prism2mgmt_set_grpaddr(mib->did, bytebuf, pstr, hw); + if (result != 0) { + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + return(result); + } + + if (hw->dot11_grpcnt <= MAX_PRISM2_GRP_ADDR) { + len = hw->dot11_grpcnt * WLAN_ADDR_LEN; + memcpy(bytebuf, hw->dot11_grp_addr[0], len); + result = hfa384x_drvr_setconfig(hw, HFA384x_RID_GROUPADDR, bytebuf, len); + + /* + ** Turn off promiscuous mode if count is equal to MAX. We may + ** have been at a higher count in promiscuous mode and need to + ** turn it off. + */ + + /* but only if we're not already in promisc mode. :) */ + if ((hw->dot11_grpcnt == MAX_PRISM2_GRP_ADDR) && + !( wlandev->netdev->flags & IFF_PROMISC)) { + result = hfa384x_drvr_setconfig16(hw, + HFA384x_RID_PROMISCMODE, 0); + } + } else { + + /* + ** Clear group addresses in card and set to promiscuous mode. + */ + + memset(bytebuf, 0, sizeof(bytebuf)); + result = hfa384x_drvr_setconfig(hw, HFA384x_RID_GROUPADDR, + bytebuf, 0); + if (result == 0) { + result = hfa384x_drvr_setconfig16(hw, + HFA384x_RID_PROMISCMODE, 1); + } + } + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_fwid +* +* Get the firmware ID. +* +* MIB record parameters: +* parm1 Not used. +* parm2 Not used. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_fwid( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + p80211pstrd_t *pstr = (p80211pstrd_t *) data; + hfa384x_FWID_t fwid; + + DBFENTER; + + if (isget) { + result = hfa384x_drvr_getconfig(hw, HFA384x_RID_FWID, + &fwid, HFA384x_RID_FWID_LEN); + if (mib->did == DIDmib_p2_p2NIC_p2PrimaryFWID) { + fwid.primary[HFA384x_FWID_LEN - 1] = '\0'; + pstr->len = strlen(fwid.primary); + memcpy(pstr->data, fwid.primary, pstr->len); + } else { + fwid.secondary[HFA384x_FWID_LEN - 1] = '\0'; + pstr->len = strlen(fwid.secondary); + memcpy(pstr->data, fwid.secondary, pstr->len); + } + } else + result = 0; /* Should never happen. */ + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_authalg +* +* Get values from the AuhtenticationAlgorithmsTable. +* +* MIB record parameters: +* parm1 Table index (1-6). +* parm2 Not used. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_authalg( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + UINT32 *uint32 = (UINT32*) data; + + DBFENTER; + + /* MSM: pkx supplied code that code queries RID FD4D....but the f/w's + * results are bogus. Therefore, we have to simulate the appropriate + * results here in the driver based on our knowledge of existing MAC + * features. That's the whole point behind this ugly function. + */ + + if (isget) { + msg->resultcode.data = P80211ENUM_resultcode_success; + switch (mib->parm1) { + case 1: /* Open System */ + *uint32 = P80211ENUM_authalg_opensystem; + break; + case 2: /* SharedKey */ + *uint32 = P80211ENUM_authalg_sharedkey; + break; + default: + *uint32 = 0; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + break; + } + } + + DBFEXIT; + return(0); +} + +/*---------------------------------------------------------------- +* prism2mib_authalgenable +* +* Get/set the enable values from the AuhtenticationAlgorithmsTable. +* +* MIB record parameters: +* parm1 Table index (1-6). +* parm2 Not used. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_authalgenable( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + int result; + UINT32 *uint32 = (UINT32*) data; + + int index; + UINT16 cnf_auth; + UINT16 mask; + + DBFENTER; + + index = mib->parm1 - 1; + + result = hfa384x_drvr_getconfig16( hw, + HFA384x_RID_CNFAUTHENTICATION, &cnf_auth); + WLAN_LOG_DEBUG(2,"cnfAuthentication0=%d, index=%d\n", cnf_auth, index); + + if (isget) { + if ( index == 0 || index == 1 ) { + *uint32 = (cnf_auth & (1<resultcode.data = P80211ENUM_resultcode_not_supported; + } + } else { + if ( index == 0 || index == 1 ) { + mask = 1 << index; + if (*uint32==P80211ENUM_truth_true ) { + cnf_auth |= mask; + } else { + cnf_auth &= ~mask; + } + result = hfa384x_drvr_setconfig16( hw, + HFA384x_RID_CNFAUTHENTICATION, cnf_auth); + WLAN_LOG_DEBUG(2,"cnfAuthentication:=%d\n", cnf_auth); + if ( result ) { + WLAN_LOG_DEBUG(1,"Unable to set p2cnfAuthentication to %d\n", cnf_auth); + msg->resultcode.data = P80211ENUM_resultcode_implementation_failure; + } + } else { + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + } + } + + DBFEXIT; + return(result); +} + +/*---------------------------------------------------------------- +* prism2mib_priv +* +* Get/set values in the "priv" data structure. +* +* MIB record parameters: +* parm1 Not used. +* parm2 Not used. +* parm3 Not used. +* +* Arguments: +* mib MIB record. +* isget MIBGET/MIBSET flag. +* wlandev wlan device structure. +* priv "priv" structure. +* hw "hw" structure. +* msg Message structure. +* data Data buffer. +* +* Returns: +* 0 - Success. +* ~0 - Error. +* +----------------------------------------------------------------*/ + +static int prism2mib_priv( +mibrec_t *mib, +int isget, +wlandevice_t *wlandev, +hfa384x_t *hw, +p80211msg_dot11req_mibset_t *msg, +void *data) +{ + UINT32 *uint32 = (UINT32*) data; + p80211pstrd_t *pstr = (p80211pstrd_t*) data; + p80211macarray_t *macarray = (p80211macarray_t *) data; + + int i, cnt, result, done; + + DBFENTER; + + switch (mib->did) { + case DIDmib_p2_p2Table_p2ReceivedFrameStatistics: + + /* + ** Note: The values in this record are changed by the + ** interrupt handler and therefore cannot be guaranteed + ** to be stable while they are being copied. However, + ** the interrupt handler will take priority over this + ** code. Hence, if the same values are copied twice, + ** then we are ensured that the values have not been + ** changed. If they have, then just try again. Don't + ** try more than 10 times...if we still haven't got it, + ** then the values we do have are probably good enough. + ** This scheme for copying values is used in order to + ** prevent having to block the interrupt handler while + ** we copy the values. + */ + + if (isget) { + UINT8 test[sizeof(wlandev->rx)]; + for (i = 0; i < 10; i++) { + memcpy(data, &wlandev->rx, sizeof(wlandev->rx)); + memcpy(test, &wlandev->rx, sizeof(wlandev->rx)); + if (memcmp(data, test, sizeof(wlandev->rx)) == 0) break; + } + } + break; + + case DIDmib_p2_p2Table_p2CommunicationTallies: + + /* + ** Note: The values in this record are changed by the + ** interrupt handler and therefore cannot be guaranteed + ** to be stable while they are being copied. See the + ** note above about copying values. + */ + + if (isget) { + UINT8 test[sizeof(hw->tallies)]; + result = hfa384x_drvr_commtallies(hw); + + /* ?????? We need to wait a bit here for the */ + /* tallies to get updated. ?????? */ + /* MSM: TODO: The right way to do this is to + * add a "commtallie" wait queue to the + * priv structure that gets run every time + * we receive a commtally info frame. + * This process would sleep on that + * queue and get awakened when the + * the requested info frame arrives. + * Don't have time to do and test this + * right now. + */ + + /* Ugh, this is nasty. */ + for (i = 0; i < 10; i++) { + memcpy(data, + &hw->tallies, + sizeof(hw->tallies)); + memcpy(test, + &hw->tallies, + sizeof(hw->tallies)); + if ( memcmp(data, + test, + sizeof(hw->tallies)) == 0) + break; + } + } + + break; + + case DIDmib_p2_p2Table_p2Authenticated: + + if (isget) { + prism2sta_authlist_t old; + prism2mib_priv_authlist(hw, &old); + + macarray->cnt = 0; + for (i = 0; i < old.cnt; i++) { + if (!old.assoc[i]) { + memcpy(macarray->data[macarray->cnt], old.addr[i], WLAN_ADDR_LEN); + macarray->cnt++; + } + } + } + + break; + + case DIDmib_p2_p2Table_p2Associated: + + if (isget) { + prism2sta_authlist_t old; + prism2mib_priv_authlist(hw, &old); + + macarray->cnt = 0; + for (i = 0; i < old.cnt; i++) { + if (old.assoc[i]) { + memcpy(macarray->data[macarray->cnt], old.addr[i], WLAN_ADDR_LEN); + macarray->cnt++; + } + } + } + + break; + + case DIDmib_p2_p2Table_p2PowerSaveUserCount: + + if (isget) + *uint32 = hw->psusercount; + + break; + + case DIDmib_p2_p2Table_p2Comment: + + if (isget) { + pstr->len = strlen(hw->comment); + memcpy(pstr->data, hw->comment, pstr->len); + } else { + cnt = pstr->len; + if (cnt < 0) cnt = 0; + if (cnt >= sizeof(hw->comment)) + cnt = sizeof(hw->comment)-1; + memcpy(hw->comment, pstr->data, cnt); + pstr->data[cnt] = '\0'; + } + + break; + + case DIDmib_p2_p2Table_p2AccessMode: + + if (isget) + *uint32 = hw->accessmode; + else + prism2mib_priv_accessmode(hw, *uint32); + + break; + + case DIDmib_p2_p2Table_p2AccessAllow: + + if (isget) { + macarray->cnt = hw->allow.cnt; + memcpy(macarray->data, hw->allow.addr, + macarray->cnt*WLAN_ADDR_LEN); + } else { + prism2mib_priv_accessallow(hw, macarray); + } + + break; + + case DIDmib_p2_p2Table_p2AccessDeny: + + if (isget) { + macarray->cnt = hw->deny.cnt; + memcpy(macarray->data, hw->deny.addr, + macarray->cnt*WLAN_ADDR_LEN); + } else { + prism2mib_priv_accessdeny(hw, macarray); + } + + break; + + case DIDmib_p2_p2Table_p2ChannelInfoResults: + + if (isget) { + done = atomic_read(&hw->channel_info.done); + if (done == 0) { + msg->resultcode.status = P80211ENUM_msgitem_status_no_value; + break; + } + if (done == 1) { + msg->resultcode.status = P80211ENUM_msgitem_status_incomplete_itemdata; + break; + } + + for (i = 0; i < 14; i++, uint32 += 5) { + uint32[0] = i+1; + uint32[1] = hw->channel_info.results.result[i].anl; + uint32[2] = hw->channel_info.results.result[i].pnl; + uint32[3] = (hw->channel_info.results.result[i].active & HFA384x_CHINFORESULT_BSSACTIVE) ? 1 : 0; + uint32[4] = (hw->channel_info.results.result[i].active & HFA384x_CHINFORESULT_PCFACTIVE) ? 1 : 0; + } + } + + break; + + case DIDmib_dot11smt_dot11StationConfigTable_dot11DesiredBSSType: + + if (isget) + *uint32 = hw->dot11_desired_bss_type; + else + hw->dot11_desired_bss_type = *uint32; + + break; + + case DIDmib_lnx_lnxConfigTable_lnxRSNAIE: { + hfa384x_WPAData_t wpa; + if (isget) { + hfa384x_drvr_getconfig( hw, HFA384x_RID_CNFWPADATA, + (UINT8 *) &wpa, sizeof(wpa)); + pstr->len = hfa384x2host_16(wpa.datalen); + memcpy(pstr->data, wpa.data, pstr->len); + } else { + wpa.datalen = host2hfa384x_16(pstr->len); + memcpy(wpa.data, pstr->data, pstr->len); + + result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFWPADATA, + (UINT8 *) &wpa, sizeof(wpa)); + } + break; + } + default: + WLAN_LOG_ERROR("Unhandled DID 0x%08x\n", mib->did); + } + + DBFEXIT; + return(0); +} + +/*---------------------------------------------------------------- +* prism2mib_priv_authlist +* +* Get a copy of the list of authenticated stations. +* +* Arguments: +* priv "priv" structure. +* list List of authenticated stations. +* +* Returns: +* Nothing +* +----------------------------------------------------------------*/ + +static void prism2mib_priv_authlist( +hfa384x_t *hw, +prism2sta_authlist_t *list) +{ + prism2sta_authlist_t test; + int i; + + DBFENTER; + + /* + ** Note: The values in this record are changed by the interrupt + ** handler and therefore cannot be guaranteed to be stable while + ** they are being copied. However, the interrupt handler will + ** take priority over this code. Hence, if the same values are + ** copied twice, then we are ensured that the values have not + ** been changed. If they have, then just try again. Don't try + ** more than 10 times...the list of authenticated stations is + ** unlikely to be changing frequently enough that we can't get + ** a snapshot in 10 tries. Don't try more than this so that we + ** don't risk locking-up for long periods of time. If we still + ** haven't got the snapshot, then generate an error message and + ** return an empty list (since this is the only valid list that + ** we can guarentee). This scheme for copying values is used in + ** order to prevent having to block the interrupt handler while + ** we copy the values. + */ + + for (i = 0; i < 10; i++) { + memcpy(list, &hw->authlist, sizeof(prism2sta_authlist_t)); + memcpy(&test, &hw->authlist, sizeof(prism2sta_authlist_t)); + if (memcmp(list, &test, sizeof(prism2sta_authlist_t)) == 0) + break; + } + + if (i >= 10) { + list->cnt = 0; + WLAN_LOG_ERROR("Could not obtain snapshot of authenticated stations.\n"); + } + + DBFEXIT; + return; +} + +/*---------------------------------------------------------------- +* prism2mib_priv_accessmode +* +* Set the Access Mode. +* +* Arguments: +* priv "priv" structure. +* hw "hw" structure. +* mode New access mode. +* +* Returns: +* Nothing +* +----------------------------------------------------------------*/ + +static void prism2mib_priv_accessmode( +hfa384x_t *hw, +UINT32 mode) +{ + prism2sta_authlist_t old; + int i, j, deauth; + UINT8 *addr; + + DBFENTER; + + /* + ** If the mode is not changing or it is changing to "All", then it's + ** okay to go ahead without a lot of messing around. Otherwise, the + ** access mode is changing in a way that may leave some stations + ** authenticated which should not be authenticated. It will be + ** necessary to de-authenticate these stations. + */ + + if (mode == WLAN_ACCESS_ALL || mode == hw->accessmode) { + hw->accessmode = mode; + return; + } + + /* + ** Switch to the new access mode. Once this is done, then the interrupt + ** handler (which uses this value) will be prevented from authenticating + ** ADDITIONAL stations which should not be authenticated. Then get a + ** copy of the current list of authenticated stations. + */ + + hw->accessmode = mode; + + prism2mib_priv_authlist(hw, &old); + + /* + ** Now go through the list of previously authenticated stations (some + ** of which might de-authenticate themselves while we are processing it + ** but that is okay). Any station which no longer matches the access + ** mode, must be de-authenticated. + */ + + for (i = 0; i < old.cnt; i++) { + addr = old.addr[i]; + + if (mode == WLAN_ACCESS_NONE) + deauth = 1; + else { + if (mode == WLAN_ACCESS_ALLOW) { + for (j = 0; j < hw->allow.cnt; j++) + if (memcmp(addr, hw->allow.addr[j], + WLAN_ADDR_LEN) == 0) + break; + deauth = (j >= hw->allow.cnt); + } else { + for (j = 0; j < hw->deny.cnt; j++) + if (memcmp(addr, hw->deny.addr[j], + WLAN_ADDR_LEN) == 0) + break; + deauth = (j < hw->deny.cnt); + } + } + + if (deauth) prism2mib_priv_deauthenticate(hw, addr); + } + + DBFEXIT; + return; +} + +/*---------------------------------------------------------------- +* prism2mib_priv_accessallow +* +* Change the list of allowed MAC addresses. +* +* Arguments: +* priv "priv" structure. +* hw "hw" structure. +* macarray New array of MAC addresses. +* +* Returns: +* Nothing +* +----------------------------------------------------------------*/ + +static void prism2mib_priv_accessallow( +hfa384x_t *hw, +p80211macarray_t *macarray) +{ + prism2sta_authlist_t old; + int i, j; + + DBFENTER; + + /* + ** Change the access list. Note that the interrupt handler may be in + ** the middle of using the access list!!! Since the interrupt handler + ** will always have priority over this process and this is the only + ** process that will modify the list, this problem can be handled as + ** follows: + ** + ** 1. Set the "modify" flag. + ** 2. Change the first copy of the list. + ** 3. Clear the "modify" flag. + ** 4. Change the backup copy of the list. + ** + ** The interrupt handler will check the "modify" flag. If NOT set, then + ** the first copy of the list is valid and may be used. Otherwise, the + ** first copy is being changed but the backup copy is valid and may be + ** used. Doing things this way prevents having to have the interrupt + ** handler block while the list is being updated. + */ + + hw->allow.modify = 1; + + hw->allow.cnt = macarray->cnt; + memcpy(hw->allow.addr, macarray->data, macarray->cnt*WLAN_ADDR_LEN); + + hw->allow.modify = 0; + + hw->allow.cnt1 = macarray->cnt; + memcpy(hw->allow.addr1, macarray->data, macarray->cnt*WLAN_ADDR_LEN); + + /* + ** If the current access mode is "Allow", then changing the access + ** list may leave some stations authenticated which should not be + ** authenticated. It will be necessary to de-authenticate these + ** stations. Otherwise, the list can be changed without a lot of fuss. + */ + + if (hw->accessmode == WLAN_ACCESS_ALLOW) { + + /* + ** Go through the list of authenticated stations (some of + ** which might de-authenticate themselves while we are + ** processing it but that is okay). Any station which is + ** no longer in the list of allowed stations, must be + ** de-authenticated. + */ + + prism2mib_priv_authlist(hw, &old); + + for (i = 0; i < old.cnt; i++) { + for (j = 0; j < hw->allow.cnt; j++) + if (memcmp(old.addr[i], hw->allow.addr[j], + WLAN_ADDR_LEN) == 0) + break; + if (j >= hw->allow.cnt) + prism2mib_priv_deauthenticate(hw, old.addr[i]); + } + } + + DBFEXIT; + return; +} + +/*---------------------------------------------------------------- +* prism2mib_priv_accessdeny +* +* Change the list of denied MAC addresses. +* +* Arguments: +* priv "priv" structure. +* hw "hw" structure. +* macarray New array of MAC addresses. +* +* Returns: +* Nothing +* +----------------------------------------------------------------*/ + +static void prism2mib_priv_accessdeny( +hfa384x_t *hw, +p80211macarray_t *macarray) +{ + prism2sta_authlist_t old; + int i, j; + + DBFENTER; + + /* + ** Change the access list. Note that the interrupt handler may be in + ** the middle of using the access list!!! Since the interrupt handler + ** will always have priority over this process and this is the only + ** process that will modify the list, this problem can be handled as + ** follows: + ** + ** 1. Set the "modify" flag. + ** 2. Change the first copy of the list. + ** 3. Clear the "modify" flag. + ** 4. Change the backup copy of the list. + ** + ** The interrupt handler will check the "modify" flag. If NOT set, then + ** the first copy of the list is valid and may be used. Otherwise, the + ** first copy is being changed but the backup copy is valid and may be + ** used. Doing things this way prevents having to have the interrupt + ** handler block while the list is being updated. + */ + + hw->deny.modify = 1; + + hw->deny.cnt = macarray->cnt; + memcpy(hw->deny.addr, macarray->data, macarray->cnt*WLAN_ADDR_LEN); + + hw->deny.modify = 0; + + hw->deny.cnt1 = macarray->cnt; + memcpy(hw->deny.addr1, macarray->data, macarray->cnt*WLAN_ADDR_LEN); + + /* + ** If the current access mode is "Deny", then changing the access + ** list may leave some stations authenticated which should not be + ** authenticated. It will be necessary to de-authenticate these + ** stations. Otherwise, the list can be changed without a lot of fuss. + */ + + if (hw->accessmode == WLAN_ACCESS_DENY) { + + /* + ** Go through the list of authenticated stations (some of + ** which might de-authenticate themselves while we are + ** processing it but that is okay). Any station which is + ** now in the list of denied stations, must be de-authenticated. + */ + + prism2mib_priv_authlist(hw, &old); + + for (i = 0; i < old.cnt; i++) + for (j = 0; j < hw->deny.cnt; j++) + if (memcmp(old.addr[i], hw->deny.addr[j], + WLAN_ADDR_LEN) == 0) { + prism2mib_priv_deauthenticate(hw, old.addr[i]); + break; + } + } + + DBFEXIT; + return; +} + +/*---------------------------------------------------------------- +* prism2mib_priv_deauthenticate +* +* De-authenticate a station. This is done by sending a HandoverAddress +* information frame to the firmware. This should work, according to +* Intersil. +* +* Arguments: +* priv "priv" structure. +* hw "hw" structure. +* addr MAC address of station to be de-authenticated. +* +* Returns: +* Nothing +* +----------------------------------------------------------------*/ + +static void prism2mib_priv_deauthenticate( +hfa384x_t *hw, +UINT8 *addr) +{ + DBFENTER; + hfa384x_drvr_handover(hw, addr); + DBFEXIT; + return; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_pstr2bytestr +* +* Convert the pstr data in the WLAN message structure into an hfa384x +* byte string format. +* +* Arguments: +* bytestr hfa384x byte string data type +* pstr wlan message data +* +* Returns: +* Nothing +* +----------------------------------------------------------------*/ + +void prism2mgmt_pstr2bytestr(hfa384x_bytestr_t *bytestr, p80211pstrd_t *pstr) +{ + DBFENTER; + + bytestr->len = host2hfa384x_16((UINT16)(pstr->len)); + memcpy(bytestr->data, pstr->data, pstr->len); + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_pstr2bytearea +* +* Convert the pstr data in the WLAN message structure into an hfa384x +* byte area format. +* +* Arguments: +* bytearea hfa384x byte area data type +* pstr wlan message data +* +* Returns: +* Nothing +* +----------------------------------------------------------------*/ + +void prism2mgmt_pstr2bytearea(UINT8 *bytearea, p80211pstrd_t *pstr) +{ + DBFENTER; + + memcpy(bytearea, pstr->data, pstr->len); + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_bytestr2pstr +* +* Convert the data in an hfa384x byte string format into a +* pstr in the WLAN message. +* +* Arguments: +* bytestr hfa384x byte string data type +* msg wlan message +* +* Returns: +* Nothing +* +----------------------------------------------------------------*/ + +void prism2mgmt_bytestr2pstr(hfa384x_bytestr_t *bytestr, p80211pstrd_t *pstr) +{ + DBFENTER; + + pstr->len = (UINT8)(hfa384x2host_16((UINT16)(bytestr->len))); + memcpy(pstr->data, bytestr->data, pstr->len); + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_bytearea2pstr +* +* Convert the data in an hfa384x byte area format into a pstr +* in the WLAN message. +* +* Arguments: +* bytearea hfa384x byte area data type +* msg wlan message +* +* Returns: +* Nothing +* +----------------------------------------------------------------*/ + +void prism2mgmt_bytearea2pstr(UINT8 *bytearea, p80211pstrd_t *pstr, int len) +{ + DBFENTER; + + pstr->len = (UINT8)len; + memcpy(pstr->data, bytearea, len); + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_prism2int2p80211int +* +* Convert an hfa384x integer into a wlan integer +* +* Arguments: +* prism2enum pointer to hfa384x integer +* wlanenum pointer to p80211 integer +* +* Returns: +* Nothing +* +----------------------------------------------------------------*/ + +void prism2mgmt_prism2int2p80211int(UINT16 *prism2int, UINT32 *wlanint) +{ + DBFENTER; + + *wlanint = (UINT32)hfa384x2host_16(*prism2int); + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_p80211int2prism2int +* +* Convert a wlan integer into an hfa384x integer +* +* Arguments: +* prism2enum pointer to hfa384x integer +* wlanenum pointer to p80211 integer +* +* Returns: +* Nothing +* +----------------------------------------------------------------*/ + +void prism2mgmt_p80211int2prism2int(UINT16 *prism2int, UINT32 *wlanint) +{ + DBFENTER; + + *prism2int = host2hfa384x_16((UINT16)(*wlanint)); + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_prism2enum2p80211enum +* +* Convert the hfa384x enumerated int into a p80211 enumerated int +* +* Arguments: +* prism2enum pointer to hfa384x integer +* wlanenum pointer to p80211 integer +* rid hfa384x record id +* +* Returns: +* Nothing +* +----------------------------------------------------------------*/ +void prism2mgmt_prism2enum2p80211enum(UINT16 *prism2enum, UINT32 *wlanenum, UINT16 rid) +{ + DBFENTER; + + /* At the moment, the need for this functionality hasn't + presented itself. All the wlan enumerated values are + a 1-to-1 match against the Prism2 enumerated values*/ + DBFEXIT; + return; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_p80211enum2prism2enum +* +* Convert the p80211 enumerated int into an hfa384x enumerated int +* +* Arguments: +* prism2enum pointer to hfa384x integer +* wlanenum pointer to p80211 integer +* rid hfa384x record id +* +* Returns: +* Nothing +* +----------------------------------------------------------------*/ +void prism2mgmt_p80211enum2prism2enum(UINT16 *prism2enum, UINT32 *wlanenum, UINT16 rid) +{ + DBFENTER; + + /* At the moment, the need for this functionality hasn't + presented itself. All the wlan enumerated values are + a 1-to-1 match against the Prism2 enumerated values*/ + DBFEXIT; + return; +} + + + +/*---------------------------------------------------------------- +* prism2mgmt_get_oprateset +* +* Convert the hfa384x bit area into a wlan octet string. +* +* Arguments: +* rate Prism2 bit area +* pstr wlan octet string +* +* Returns: +* Nothing +* +----------------------------------------------------------------*/ +void prism2mgmt_get_oprateset(UINT16 *rate, p80211pstrd_t *pstr) +{ + UINT8 len; + UINT8 *datarate; + + DBFENTER; + + len = 0; + datarate = pstr->data; + + /* 1 Mbps */ + if ( BIT0 & (*rate) ) { + len += (UINT8)1; + *datarate = (UINT8)2; + datarate++; + } + + /* 2 Mbps */ + if ( BIT1 & (*rate) ) { + len += (UINT8)1; + *datarate = (UINT8)4; + datarate++; + } + + /* 5.5 Mbps */ + if ( BIT2 & (*rate) ) { + len += (UINT8)1; + *datarate = (UINT8)11; + datarate++; + } + + /* 11 Mbps */ + if ( BIT3 & (*rate) ) { + len += (UINT8)1; + *datarate = (UINT8)22; + datarate++; + } + + pstr->len = len; + + DBFEXIT; + return; +} + + + +/*---------------------------------------------------------------- +* prism2mgmt_set_oprateset +* +* Convert the wlan octet string into an hfa384x bit area. +* +* Arguments: +* rate Prism2 bit area +* pstr wlan octet string +* +* Returns: +* Nothing +* +----------------------------------------------------------------*/ +void prism2mgmt_set_oprateset(UINT16 *rate, p80211pstrd_t *pstr) +{ + UINT8 *datarate; + int i; + + DBFENTER; + + *rate = 0; + + datarate = pstr->data; + + for ( i=0; i < pstr->len; i++, datarate++ ) { + switch (*datarate) { + case 2: /* 1 Mbps */ + *rate |= BIT0; + break; + case 4: /* 2 Mbps */ + *rate |= BIT1; + break; + case 11: /* 5.5 Mbps */ + *rate |= BIT2; + break; + case 22: /* 11 Mbps */ + *rate |= BIT3; + break; + default: + WLAN_LOG_DEBUG(1, "Unrecoginzed Rate of %d\n", + *datarate); + break; + } + } + + DBFEXIT; + return; +} + + + +/*---------------------------------------------------------------- +* prism2mgmt_get_grpaddr +* +* Retrieves a particular group address from the list of +* group addresses. +* +* Arguments: +* did mibitem did +* pstr wlan octet string +* priv prism2 driver private data structure +* +* Returns: +* Nothing +* +----------------------------------------------------------------*/ +void prism2mgmt_get_grpaddr(UINT32 did, p80211pstrd_t *pstr, + hfa384x_t *hw ) +{ + int index; + + DBFENTER; + + index = prism2mgmt_get_grpaddr_index(did); + + if ( index >= 0 ) { + pstr->len = WLAN_ADDR_LEN; + memcpy(pstr->data, hw->dot11_grp_addr[index], + WLAN_ADDR_LEN); + } + + DBFEXIT; + return; +} + + + +/*---------------------------------------------------------------- +* prism2mgmt_set_grpaddr +* +* Convert the wlan octet string into an hfa384x bit area. +* +* Arguments: +* did mibitem did +* buf +* groups +* +* Returns: +* 0 Success +* !0 Error +* +----------------------------------------------------------------*/ +int prism2mgmt_set_grpaddr(UINT32 did, UINT8 *prism2buf, + p80211pstrd_t *pstr, hfa384x_t *hw ) +{ + UINT8 no_addr[WLAN_ADDR_LEN]; + int index; + + DBFENTER; + + memset(no_addr, 0, WLAN_ADDR_LEN); + if (memcmp(no_addr, pstr->data, WLAN_ADDR_LEN) != 0) { + + /* + ** The address is NOT 0 so we are "adding" an address to the + ** group address list. Check to make sure we aren't trying + ** to add more than the maximum allowed number of group + ** addresses in the list. The new address is added to the + ** end of the list regardless of the DID used to add the + ** address. + */ + + if (hw->dot11_grpcnt >= MAX_GRP_ADDR) return(-1); + + memcpy(hw->dot11_grp_addr[hw->dot11_grpcnt], pstr->data, + WLAN_ADDR_LEN); + hw->dot11_grpcnt += 1; + } else { + + /* + ** The address is 0. Interpret this as "deleting" an address + ** from the group address list. Get the address index from + ** the DID. If this is within the range of used addresses, + ** then delete the specified address by shifting all following + ** addresses down. Then clear the last address (which should + ** now be unused). If the address index is NOT within the + ** range of used addresses, then just ignore the address. + */ + + index = prism2mgmt_get_grpaddr_index(did); + if (index >= 0 && index < hw->dot11_grpcnt) { + hw->dot11_grpcnt -= 1; + memmove(hw->dot11_grp_addr[index], + hw->dot11_grp_addr[index + 1], + ((hw->dot11_grpcnt)-index) * WLAN_ADDR_LEN); + memset(hw->dot11_grp_addr[hw->dot11_grpcnt], 0, + WLAN_ADDR_LEN); + } + } + + DBFEXIT; + return(0); +} + + +/*---------------------------------------------------------------- +* prism2mgmt_get_grpaddr_index +* +* Gets the index in the group address list based on the did. +* +* Arguments: +* did mibitem did +* +* Returns: +* >= 0 If valid did +* < 0 If not valid did +* +----------------------------------------------------------------*/ +int prism2mgmt_get_grpaddr_index( UINT32 did ) +{ + int index; + + DBFENTER; + + index = -1; + + switch (did) { + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address1: + index = 0; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address2: + index = 1; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address3: + index = 2; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address4: + index = 3; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address5: + index = 4; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address6: + index = 5; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address7: + index = 6; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address8: + index = 7; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address9: + index = 8; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address10: + index = 9; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address11: + index = 10; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address12: + index = 11; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address13: + index = 12; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address14: + index = 13; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address15: + index = 14; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address16: + index = 15; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address17: + index = 16; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address18: + index = 17; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address19: + index = 18; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address20: + index = 19; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address21: + index = 20; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address22: + index = 21; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address23: + index = 22; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address24: + index = 23; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address25: + index = 24; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address26: + index = 25; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address27: + index = 26; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address28: + index = 27; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address29: + index = 28; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address30: + index = 29; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address31: + index = 30; + break; + case DIDmib_dot11mac_dot11GroupAddressesTable_dot11Address32: + index = 31; + break; + } + + DBFEXIT; + return index; +} --- linux-2.6.27.orig/ubuntu/misc/wireless/prism2_usb/hfa384x.c +++ linux-2.6.27/ubuntu/misc/wireless/prism2_usb/hfa384x.c @@ -0,0 +1,4018 @@ +/* src/prism2/driver/hfa384x.c +* +* Implements the functions of the Intersil hfa384x MAC +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* This file implements functions that correspond to the prism2/hfa384x +* 802.11 MAC hardware and firmware host interface. +* +* The functions can be considered to represent several levels of +* abstraction. The lowest level functions are simply C-callable wrappers +* around the register accesses. The next higher level represents C-callable +* prism2 API functions that match the Intersil documentation as closely +* as is reasonable. The next higher layer implements common sequences +* of invokations of the API layer (e.g. write to bap, followed by cmd). +* +* Common sequences: +* hfa384x_drvr_xxx Highest level abstractions provided by the +* hfa384x code. They are driver defined wrappers +* for common sequences. These functions generally +* use the services of the lower levels. +* +* hfa384x_drvr_xxxconfig An example of the drvr level abstraction. These +* functions are wrappers for the RID get/set +* sequence. They call copy_[to|from]_bap() and +* cmd_access(). These functions operate on the +* RIDs and buffers without validation. The caller +* is responsible for that. +* +* API wrapper functions: +* hfa384x_cmd_xxx functions that provide access to the f/w commands. +* The function arguments correspond to each command +* argument, even command arguments that get packed +* into single registers. These functions _just_ +* issue the command by setting the cmd/parm regs +* & reading the status/resp regs. Additional +* activities required to fully use a command +* (read/write from/to bap, get/set int status etc.) +* are implemented separately. Think of these as +* C-callable prism2 commands. +* +* Lowest Layer Functions: +* hfa384x_docmd_xxx These functions implement the sequence required +* to issue any prism2 command. Primarily used by the +* hfa384x_cmd_xxx functions. +* +* hfa384x_bap_xxx BAP read/write access functions. +* Note: we usually use BAP0 for non-interrupt context +* and BAP1 for interrupt context. +* +* hfa384x_dl_xxx download related functions. +* +* Driver State Issues: +* Note that there are two pairs of functions that manage the +* 'initialized' and 'running' states of the hw/MAC combo. The four +* functions are create(), destroy(), start(), and stop(). create() +* sets up the data structures required to support the hfa384x_* +* functions and destroy() cleans them up. The start() function gets +* the actual hardware running and enables the interrupts. The stop() +* function shuts the hardware down. The sequence should be: +* create() +* . +* . Self contained test routines can run here, particularly +* . corereset() and test_hostif(). +* . +* start() +* . +* . Do interesting things w/ the hardware +* . +* stop() +* destroy() +* +* Note that destroy() can be called without calling stop() first. +* -------------------------------------------------------------------- +*/ + +/*================================================================*/ + +/* System Includes */ +#define WLAN_DBVAR prism2_debug +#include + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#include +#else +#include +#endif + +#if (WLAN_HOSTIF == WLAN_PCMCIA) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) ) +#include +#endif +#include +#include +#include +#include +#include +#endif + +#if ((WLAN_HOSTIF == WLAN_PLX) || (WLAN_HOSTIF == WLAN_PCI)) +#include +#include +#endif + +#include + +// XXXX #define CMD_IRQ + +/*================================================================*/ +/* Project Includes */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*================================================================*/ +/* Local Constants */ + +static const UINT16 crc16tab[256] = +{ + 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, + 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, + 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, + 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, + 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, + 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, + 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, + 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, + 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, + 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, + 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, + 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, + 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, + 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, + 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, + 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, + 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, + 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, + 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, + 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, + 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, + 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, + 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, + 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, + 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, + 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, + 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, + 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, + 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, + 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, + 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, + 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040 +}; + +/*================================================================*/ +/* Local Macros */ + +/*================================================================*/ +/* Local Types */ + +/*================================================================*/ +/* Local Static Definitions */ +extern int prism2_debug; + +/*================================================================*/ +/* Local Function Declarations */ + +static void hfa384x_int_dtim(wlandevice_t *wlandev); +static void hfa384x_int_infdrop(wlandevice_t *wlandev); + +static void hfa384x_bap_tasklet(unsigned long data); + +static void hfa384x_int_info(wlandevice_t *wlandev); +static void hfa384x_int_txexc(wlandevice_t *wlandev); +static void hfa384x_int_tx(wlandevice_t *wlandev); +static void hfa384x_int_rx(wlandevice_t *wlandev); + +#ifdef CMD_IRQ +static void hfa384x_int_cmd(wlandevice_t *wlandev); +#endif +static void hfa384x_int_rxmonitor( wlandevice_t *wlandev, + UINT16 rxfid, hfa384x_rx_frame_t *rxdesc); +static void hfa384x_int_alloc(wlandevice_t *wlandev); + +static int hfa384x_docmd_wait( hfa384x_t *hw, hfa384x_metacmd_t *cmd); + +static int hfa384x_dl_docmd_wait( hfa384x_t *hw, hfa384x_metacmd_t *cmd); + +static UINT16 +hfa384x_mkcrc16(UINT8 *p, int len); + +int hfa384x_copy_to_bap4(hfa384x_t *hw, UINT16 bap, UINT16 id, UINT16 offset, + void *buf, UINT len, void* buf2, UINT len2, + void *buf3, UINT len3, void* buf4, UINT len4); + +/*================================================================*/ +/* Function Definitions */ + +static UINT16 +txfid_queue_empty(hfa384x_t *hw) +{ + return (hw->txfid_head == hw->txfid_tail) ? 1 : 0; +} + +static UINT16 +txfid_queue_remove(hfa384x_t *hw) +{ + UINT16 result= 0; + + if (txfid_queue_empty(hw)) { + WLAN_LOG_DEBUG(3,"queue empty.\n"); + } else { + result = hw->txfid_queue[hw->txfid_head]; + hw->txfid_head = (hw->txfid_head + 1) % hw->txfid_N; + } + + return (UINT16)result; +} + +static INT16 +txfid_queue_add(hfa384x_t *hw, UINT16 val) +{ + INT16 result = 0; + + if (hw->txfid_head == ((hw->txfid_tail + 1) % hw->txfid_N)) { + result = -1; + WLAN_LOG_DEBUG(3,"queue full.\n"); + } else { + hw->txfid_queue[hw->txfid_tail] = val; + result = hw->txfid_tail; + hw->txfid_tail = (hw->txfid_tail + 1) % hw->txfid_N; + } + + return result; +} + +/*---------------------------------------------------------------- +* hfa384x_create +* +* Initializes the hfa384x_t data structure for use. Note this +* does _not_ intialize the actual hardware, just the data structures +* we use to keep track of its state. +* +* Arguments: +* hw device structure +* irq device irq number +* iobase [pcmcia] i/o base address for register access +* [pci] zero +* [plx] i/o base address for register access +* membase [pcmcia] pcmcia_cs "link" pointer +* [pci] memory base address for register access +* [plx] memory base address for card attribute memory +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +void hfa384x_create(hfa384x_t *hw, UINT irq, UINT32 iobase, + UINT8 __iomem *membase) +{ + DBFENTER; + memset(hw, 0, sizeof(hfa384x_t)); + hw->irq = irq; + hw->iobase = iobase; + hw->membase = membase; + spin_lock_init(&(hw->cmdlock)); + + /* BAP setup */ + spin_lock_init(&(hw->baplock)); + tasklet_init(&hw->bap_tasklet, + hfa384x_bap_tasklet, + (unsigned long) hw); + + init_waitqueue_head(&hw->cmdq); + sema_init(&hw->infofid_sem, 1); + + hw->txfid_head = 0; + hw->txfid_tail = 0; + hw->txfid_N = HFA384x_DRVR_FIDSTACKLEN_MAX; + memset(hw->txfid_queue, 0, sizeof(hw->txfid_queue)); + + hw->isram16 = 1; + + /* Init the auth queue head */ + skb_queue_head_init(&hw->authq); + + INIT_WORK2(&hw->link_bh, prism2sta_processing_defer); + + INIT_WORK2(&hw->commsqual_bh, prism2sta_commsqual_defer); + + init_timer(&hw->commsqual_timer); + hw->commsqual_timer.data = (unsigned long) hw; + hw->commsqual_timer.function = prism2sta_commsqual_timer; + + hw->link_status = HFA384x_LINK_NOTCONNECTED; + hw->state = HFA384x_STATE_INIT; + + DBFEXIT; +} + +/*---------------------------------------------------------------- +* hfa384x_destroy +* +* Partner to hfa384x_create(). This function cleans up the hw +* structure so that it can be freed by the caller using a simple +* kfree. Currently, this function is just a placeholder. If, at some +* point in the future, an hw in the 'shutdown' state requires a 'deep' +* kfree, this is where it should be done. Note that if this function +* is called on a _running_ hw structure, the drvr_stop() function is +* called. +* +* Arguments: +* hw device structure +* +* Returns: +* nothing, this function is not allowed to fail. +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +void +hfa384x_destroy( hfa384x_t *hw) +{ + struct sk_buff *skb; + + DBFENTER; + + if ( hw->state == HFA384x_STATE_RUNNING ) { + hfa384x_drvr_stop(hw); + } + hw->state = HFA384x_STATE_PREINIT; + + if (hw->scanresults) { + kfree(hw->scanresults); + hw->scanresults = NULL; + } + + /* Now to clean out the auth queue */ + while ( (skb = skb_dequeue(&hw->authq)) ) { + dev_kfree_skb(skb); + } + + DBFEXIT; + return; +} + +/*---------------------------------------------------------------- +* hfa384x_drvr_getconfig +* +* Performs the sequence necessary to read a config/info item. +* +* Arguments: +* hw device structure +* rid config/info record id (host order) +* buf host side record buffer. Upon return it will +* contain the body portion of the record (minus the +* RID and len). +* len buffer length (in bytes, should match record length) +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* -ENODATA length mismatch between argument and retrieved +* record. +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_drvr_getconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len) +{ + int result = 0; + DBFENTER; + + result = hfa384x_cmd_access( hw, 0, rid, buf, len); + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_setconfig +* +* Performs the sequence necessary to write a config/info item. +* +* Arguments: +* hw device structure +* rid config/info record id (in host order) +* buf host side record buffer +* len buffer length (in bytes) +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_drvr_setconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len) +{ + int result = 0; + DBFENTER; + + result = hfa384x_cmd_access( hw, 1, rid, buf, len); + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_readpda +* +* Performs the sequence to read the PDA space. Note there is no +* drvr_writepda() function. Writing a PDA is +* generally implemented by a calling component via calls to +* cmd_download and writing to the flash download buffer via the +* aux regs. +* +* Arguments: +* hw device structure +* buf buffer to store PDA in +* len buffer length +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* -ETIMEOUT timout waiting for the cmd regs to become +* available, or waiting for the control reg +* to indicate the Aux port is enabled. +* -ENODATA the buffer does NOT contain a valid PDA. +* Either the card PDA is bad, or the auxdata +* reads are giving us garbage. + +* +* Side effects: +* +* Call context: +* process thread or non-card interrupt. +----------------------------------------------------------------*/ +int hfa384x_drvr_readpda(hfa384x_t *hw, void *buf, UINT len) +{ + int result = 0; + UINT16 *pda = buf; + int pdaok = 0; + int morepdrs = 1; + int currpdr = 0; /* word offset of the current pdr */ + int i; + UINT16 pdrlen; /* pdr length in bytes, host order */ + UINT16 pdrcode; /* pdr code, host order */ + UINT16 crc; + UINT16 pdacrc; + struct pdaloc { + UINT32 cardaddr; + UINT16 auxctl; + } pdaloc[] = + { + { HFA3842_PDA_BASE, HFA384x_AUX_CTL_NV}, + { HFA3842_PDA_BASE, HFA384x_AUX_CTL_EXTDS}, + { HFA3841_PDA_BASE, HFA384x_AUX_CTL_NV}, + { HFA3841_PDA_BASE, HFA384x_AUX_CTL_EXTDS}, + { HFA3841_PDA_BOGUS_BASE, HFA384x_AUX_CTL_NV} + }; + + DBFENTER; + /* Check for aux available */ + result = hfa384x_cmd_aux_enable(hw, 0); + if ( result ) { + WLAN_LOG_DEBUG(1,"aux_enable() failed. result=%d\n", result); + goto failed; + } + + /* Read the pda from each known address. */ + for ( i = 0; i < (sizeof(pdaloc)/sizeof(pdaloc[0])); i++) { + WLAN_LOG_DEBUG( 3, "Checking PDA@(0x%08x,%s)\n", + pdaloc[i].cardaddr, + pdaloc[i].auxctl == HFA384x_AUX_CTL_NV ? + "CTL_NV" : "CTL_EXTDS"); + + /* Copy bufsize bytes from our current pdaloc */ + hfa384x_copy_from_aux(hw, + pdaloc[i].cardaddr, + pdaloc[i].auxctl, + buf, + len); + + /* Test for garbage */ + /* Traverse the PDR list Looking for PDA-END */ + pdaok = 1; /* intially assume good */ + morepdrs = 1; + currpdr = 0; + while ( pdaok && morepdrs ) { + pdrlen = hfa384x2host_16(pda[currpdr]) * 2; + pdrcode = hfa384x2host_16(pda[currpdr+1]); + + /* Test for completion at END record */ + if ( pdrcode == HFA384x_PDR_END_OF_PDA ) { + if ( pdrlen == 4 ) { + morepdrs = 0; + /* Calculate CRC-16 and compare to PDA + * value. Note the addition of 2 words + * for ENDREC.len and ENDREC.code + * fields. + */ + crc = hfa384x_mkcrc16( (UINT8*)pda, + (currpdr + 2) * sizeof(UINT16)); + pdacrc =hfa384x2host_16(pda[currpdr+2]); + if ( crc != pdacrc ) { + WLAN_LOG_DEBUG(3, + "PDA crc failed:" + "calc_crc=0x%04x," + "pdr_crc=0x%04x.\n", + crc, pdacrc); + pdaok = 0; + } + } else { + WLAN_LOG_DEBUG(3, + "END record detected w/ " + "len(%d) != 2, assuming bad PDA\n", + pdrlen); + pdaok = 0; + + } + break; + } + + /* Test the record length */ + if ( pdrlen > HFA384x_PDR_LEN_MAX || pdrlen == 0) { + WLAN_LOG_DEBUG(3, + "pdrlen for address #%d " + "at %#x:%#x:%d\n", + i, pdaloc[i].cardaddr, + pdaloc[i].auxctl, pdrlen); + WLAN_LOG_DEBUG(3,"pdrlen invalid=%d\n", + pdrlen); + pdaok = 0; + break; + } + + /* Move to the next pdr */ + if ( morepdrs ) { + /* note the access to pda[], we need words */ + currpdr += hfa384x2host_16(pda[currpdr]) + 1; + if (currpdr*sizeof(UINT16) > len) { + WLAN_LOG_DEBUG(3, + "Didn't find PDA_END in buffer, " + "trying next location.\n"); + pdaok = 0; + break; + } + } + } + if ( pdaok ) { + WLAN_LOG_INFO( + "PDA Read from 0x%08x in %s space.\n", + pdaloc[i].cardaddr, + pdaloc[i].auxctl == 0 ? "EXTDS" : + pdaloc[i].auxctl == 1 ? "NV" : + pdaloc[i].auxctl == 2 ? "PHY" : + pdaloc[i].auxctl == 3 ? "ICSRAM" : + ""); + break; + } + } + result = pdaok ? 0 : -ENODATA; + + if ( result ) { + WLAN_LOG_DEBUG(3,"Failure: pda is not okay\n"); + } + + hfa384x_cmd_aux_disable(hw); +failed: + DBFEXIT; + return result; +} + + + +/*---------------------------------------------------------------- +* mkpda_crc +* +* Calculates the CRC16 for the given PDA and inserts the value +* into the end record. +* +* Arguments: +* pda ptr to the PDA data structure. +* +* Returns: +* 0 - success +* ~0 - failure (probably an errno) +----------------------------------------------------------------*/ +static UINT16 +hfa384x_mkcrc16(UINT8 *p, int len) +{ + UINT16 crc = 0; + UINT8 *lim = p + len; + + while (p < lim) { + crc = (crc >> 8 ) ^ crc16tab[(crc & 0xff) ^ *p++]; + } + + return crc; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_ramdl_enable +* +* Begins the ram download state. Checks to see that we're not +* already in a download state and that a port isn't enabled. +* Sets the download state and calls cmd_download with the +* ENABLE_VOLATILE subcommand and the exeaddr argument. +* +* Arguments: +* hw device structure +* exeaddr the card execution address that will be +* jumped to when ramdl_disable() is called +* (host order). +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_drvr_ramdl_enable(hfa384x_t *hw, UINT32 exeaddr) +{ + int result = 0; + UINT16 lowaddr; + UINT16 hiaddr; + int i; + DBFENTER; + /* Check that a port isn't active */ + for ( i = 0; i < HFA384x_PORTID_MAX; i++) { + if ( hw->port_enabled[i] ) { + WLAN_LOG_DEBUG(1,"Can't download with a port enabled.\n"); + result = -EINVAL; + goto done; + } + } + + /* Check that we're not already in a download state */ + if ( hw->dlstate != HFA384x_DLSTATE_DISABLED ) { + WLAN_LOG_DEBUG(1,"Download state not disabled.\n"); + result = -EINVAL; + goto done; + } + + /* Are we supposed to go into genesis mode? */ + if (exeaddr == 0x3f0000) { + UINT16 initseq[2] = { 0xe100, 0xffa1 }; + UINT16 readbuf[2]; + UINT8 hcr = 0x0f; /* Default to x16 SRAM */ + hw->isram16 = 1; + + WLAN_LOG_DEBUG(1, "Dropping into Genesis mode\n"); + + /* Issue card reset and enable aux port */ + hfa384x_corereset(hw, prism2_reset_holdtime, + prism2_reset_settletime, 0); + hfa384x_cmd_aux_enable(hw, 1); + + /* Genesis set */ + hfa384x_copy_to_aux(hw, 0x7E0038, HFA384x_AUX_CTL_EXTDS, + initseq, sizeof(initseq)); + + hfa384x_corereset(hw, prism2_reset_holdtime, + prism2_reset_settletime, hcr); + + /* Validate memory config */ + hfa384x_copy_to_aux(hw, 0x7E0038, HFA384x_AUX_CTL_EXTDS, + initseq, sizeof(initseq)); + hfa384x_copy_from_aux(hw, 0x7E0038, HFA384x_AUX_CTL_EXTDS, + readbuf, sizeof(initseq)); + WLAN_HEX_DUMP(3, "readback", readbuf, sizeof(readbuf)); + + if (memcmp(initseq, readbuf, sizeof(readbuf))) { + hcr = 0x1f; /* x8 SRAM */ + hw->isram16 = 0; + + hfa384x_copy_to_aux(hw, 0x7E0038, HFA384x_AUX_CTL_EXTDS, + initseq, sizeof(initseq)); + hfa384x_corereset(hw, prism2_reset_holdtime, + prism2_reset_settletime, hcr); + + hfa384x_copy_to_aux(hw, 0x7E0038, HFA384x_AUX_CTL_EXTDS, + initseq, sizeof(initseq)); + hfa384x_copy_from_aux(hw, 0x7E0038, HFA384x_AUX_CTL_EXTDS, + readbuf, sizeof(initseq)); + WLAN_HEX_DUMP(2, "readback", readbuf, sizeof(readbuf)); + + if (memcmp(initseq, readbuf, sizeof(readbuf))) { + WLAN_LOG_ERROR("Genesis mode failed\n"); + result = -1; + goto done; + } + } + + /* Now we're in genesis mode */ + hw->dlstate = HFA384x_DLSTATE_GENESIS; + goto done; + } + + /* Retrieve the buffer loc&size and timeout */ + if ( (result = hfa384x_drvr_getconfig(hw, HFA384x_RID_DOWNLOADBUFFER, + &(hw->bufinfo), sizeof(hw->bufinfo))) ) { + goto done; + } + hw->bufinfo.page = hfa384x2host_16(hw->bufinfo.page); + hw->bufinfo.offset = hfa384x2host_16(hw->bufinfo.offset); + hw->bufinfo.len = hfa384x2host_16(hw->bufinfo.len); + if ( (result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_MAXLOADTIME, + &(hw->dltimeout))) ) { + goto done; + } + hw->dltimeout = hfa384x2host_16(hw->dltimeout); + + /* Enable the aux port */ + if ( (result = hfa384x_cmd_aux_enable(hw, 0)) ) { + WLAN_LOG_DEBUG(1,"Aux enable failed, result=%d.\n", result); + goto done; + } + + /* Call the download(1,addr) function */ + lowaddr = HFA384x_ADDR_CMD_MKOFF(exeaddr); + hiaddr = HFA384x_ADDR_CMD_MKPAGE(exeaddr); + + result = hfa384x_cmd_download(hw, HFA384x_PROGMODE_RAM, + lowaddr, hiaddr, 0); + if ( result == 0) { + /* Set the download state */ + hw->dlstate = HFA384x_DLSTATE_RAMENABLED; + } else { + WLAN_LOG_DEBUG(1,"cmd_download(0x%04x, 0x%04x) failed, result=%d.\n", + lowaddr,hiaddr, result); + /* Disable the aux port */ + hfa384x_cmd_aux_disable(hw); + } + + done: + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_ramdl_disable +* +* Ends the ram download state. +* +* Arguments: +* hw device structure +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_drvr_ramdl_disable(hfa384x_t *hw) +{ + DBFENTER; + /* Check that we're already in the download state */ + if ( ( hw->dlstate != HFA384x_DLSTATE_RAMENABLED ) && + ( hw->dlstate != HFA384x_DLSTATE_GENESIS ) ) { + return -EINVAL; + } + + if (hw->dlstate == HFA384x_DLSTATE_GENESIS) { + hfa384x_corereset(hw, prism2_reset_holdtime, + prism2_reset_settletime, + hw->isram16 ? 0x07: 0x17); + goto done; + } + + /* Disable the aux port */ + hfa384x_cmd_download(hw, HFA384x_PROGMODE_DISABLE, 0, 0 , 0); + + done: + hw->dlstate = HFA384x_DLSTATE_DISABLED; + hfa384x_cmd_aux_disable(hw); + + DBFEXIT; + return 0; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_ramdl_write +* +* Performs a RAM download of a chunk of data. First checks to see +* that we're in the RAM download state, then uses the aux functions +* to 1) copy the data, 2) readback and compare. The download +* state is unaffected. When all data has been written using +* this function, call drvr_ramdl_disable() to end the download state +* and restart the MAC. +* +* Arguments: +* hw device structure +* daddr Card address to write to. (host order) +* buf Ptr to data to write. +* len Length of data (host order). +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_drvr_ramdl_write(hfa384x_t *hw, UINT32 daddr, void* buf, UINT32 len) +{ + int result = 0; + UINT8 *verbuf; + DBFENTER; + /* Check that we're in the ram download state */ + if ( ( hw->dlstate != HFA384x_DLSTATE_RAMENABLED ) && + ( hw->dlstate != HFA384x_DLSTATE_GENESIS ) ) { + return -EINVAL; + } + + WLAN_LOG_INFO("Writing %d bytes to ram @0x%06x\n", len, daddr); +#if 0 +WLAN_HEX_DUMP(1, "dldata", buf, len); +#endif + /* Copy the data via the aux port */ + hfa384x_copy_to_aux(hw, daddr, HFA384x_AUX_CTL_EXTDS, buf, len); + + /* Create a buffer for the verify */ + verbuf = kmalloc(len, GFP_KERNEL); + if (verbuf == NULL ) return 1; + + /* Read back and compare */ + hfa384x_copy_from_aux(hw, daddr, HFA384x_AUX_CTL_EXTDS, verbuf, len); + + if ( memcmp(buf, verbuf, len) ) { + WLAN_LOG_DEBUG(1,"ramdl verify failed!\n"); + result = -EINVAL; + } + + kfree_s(verbuf, len); + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_flashdl_enable +* +* Begins the flash download state. Checks to see that we're not +* already in a download state and that a port isn't enabled. +* Sets the download state and retrieves the flash download +* buffer location, buffer size, and timeout length. +* +* Arguments: +* hw device structure +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_drvr_flashdl_enable(hfa384x_t *hw) +{ + int result = 0; + int i; + + DBFENTER; + /* Check that a port isn't active */ + for ( i = 0; i < HFA384x_PORTID_MAX; i++) { + if ( hw->port_enabled[i] ) { + WLAN_LOG_DEBUG(1,"called when port enabled.\n"); + return -EINVAL; + } + } + + /* Check that we're not already in a download state */ + if ( hw->dlstate != HFA384x_DLSTATE_DISABLED ) { + return -EINVAL; + } + + /* Retrieve the buffer loc&size and timeout */ + if ( (result = hfa384x_drvr_getconfig(hw, HFA384x_RID_DOWNLOADBUFFER, + &(hw->bufinfo), sizeof(hw->bufinfo))) ) { + return result; + } + hw->bufinfo.page = hfa384x2host_16(hw->bufinfo.page); + hw->bufinfo.offset = hfa384x2host_16(hw->bufinfo.offset); + hw->bufinfo.len = hfa384x2host_16(hw->bufinfo.len); + if ( (result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_MAXLOADTIME, + &(hw->dltimeout))) ) { + return result; + } + hw->dltimeout = hfa384x2host_16(hw->dltimeout); + + /* Enable the aux port */ + if ( (result = hfa384x_cmd_aux_enable(hw, 0)) ) { + return result; + } + + hw->dlstate = HFA384x_DLSTATE_FLASHENABLED; + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_flashdl_disable +* +* Ends the flash download state. Note that this will cause the MAC +* firmware to restart. +* +* Arguments: +* hw device structure +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_drvr_flashdl_disable(hfa384x_t *hw) +{ + DBFENTER; + /* Check that we're already in the download state */ + if ( hw->dlstate != HFA384x_DLSTATE_FLASHENABLED ) { + return -EINVAL; + } + + /* There isn't much we can do at this point, so I don't */ + /* bother w/ the return value */ + hfa384x_cmd_download(hw, HFA384x_PROGMODE_DISABLE, 0, 0 , 0); + hw->dlstate = HFA384x_DLSTATE_DISABLED; + + /* Disable the aux port */ + hfa384x_cmd_aux_disable(hw); + + DBFEXIT; + return 0; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_flashdl_write +* +* Performs a FLASH download of a chunk of data. First checks to see +* that we're in the FLASH download state, then sets the download +* mode, uses the aux functions to 1) copy the data to the flash +* buffer, 2) sets the download 'write flash' mode, 3) readback and +* compare. Lather rinse, repeat as many times an necessary to get +* all the given data into flash. +* When all data has been written using this function (possibly +* repeatedly), call drvr_flashdl_disable() to end the download state +* and restart the MAC. +* +* Arguments: +* hw device structure +* daddr Card address to write to. (host order) +* buf Ptr to data to write. +* len Length of data (host order). +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_drvr_flashdl_write(hfa384x_t *hw, UINT32 daddr, void* buf, UINT32 len) +{ + int result = 0; + UINT8 *verbuf; + UINT32 dlbufaddr; + UINT32 currlen; + UINT32 currdaddr; + UINT16 destlo; + UINT16 desthi; + int nwrites; + int i; + + DBFENTER; + /* Check that we're in the flash download state */ + if ( hw->dlstate != HFA384x_DLSTATE_FLASHENABLED ) { + return -EINVAL; + } + + WLAN_LOG_INFO("Download %d bytes to flash @0x%06x\n", len, daddr); + + /* Need a flat address for arithmetic */ + dlbufaddr = HFA384x_ADDR_AUX_MKFLAT( + hw->bufinfo.page, + hw->bufinfo.offset); + verbuf = kmalloc(hw->bufinfo.len, GFP_KERNEL); + +#if 0 +WLAN_LOG_WARNING("dlbuf@0x%06lx len=%d to=%d\n", dlbufaddr, hw->bufinfo.len, hw->dltimeout); +#endif + /* Figure out how many times to to the flash prog */ + nwrites = len / hw->bufinfo.len; + nwrites += (len % hw->bufinfo.len) ? 1 : 0; + + if ( verbuf == NULL ) { + WLAN_LOG_ERROR("Failed to allocate flash verify buffer\n"); + return 1; + } + /* For each */ + for ( i = 0; i < nwrites; i++) { + /* Get the dest address and len */ + currlen = (len - (hw->bufinfo.len * i)) > hw->bufinfo.len ? + hw->bufinfo.len : + (len - (hw->bufinfo.len * i)); + currdaddr = daddr + (hw->bufinfo.len * i); + destlo = HFA384x_ADDR_CMD_MKOFF(currdaddr); + desthi = HFA384x_ADDR_CMD_MKPAGE(currdaddr); + WLAN_LOG_INFO("Writing %d bytes to flash @0x%06x\n", currlen, currdaddr); +#if 0 +WLAN_HEX_DUMP(1, "dldata", buf+(hw->bufinfo.len*i), currlen); +#endif + /* Set the download mode */ + result = hfa384x_cmd_download(hw, HFA384x_PROGMODE_NV, + destlo, desthi, currlen); + if ( result ) { + WLAN_LOG_ERROR("download(NV,lo=%x,hi=%x,len=%x) " + "cmd failed, result=%d. Aborting d/l\n", + destlo, desthi, currlen, result); + goto exit_proc; + } + /* copy the data to the flash buffer */ + hfa384x_copy_to_aux(hw, dlbufaddr, HFA384x_AUX_CTL_EXTDS, + buf+(hw->bufinfo.len*i), currlen); + /* set the download 'write flash' mode */ + result = hfa384x_cmd_download(hw, HFA384x_PROGMODE_NVWRITE, 0,0,0); + if ( result ) { + WLAN_LOG_ERROR( + "download(NVWRITE,lo=%x,hi=%x,len=%x) " + "cmd failed, result=%d. Aborting d/l\n", + destlo, desthi, currlen, result); + goto exit_proc; + } + /* readback and compare, if fail...bail */ + hfa384x_copy_from_aux(hw, + currdaddr, HFA384x_AUX_CTL_NV, + verbuf, currlen); + + if ( memcmp(buf+(hw->bufinfo.len*i), verbuf, currlen) ) { + return -EINVAL; + } + } + +exit_proc: + /* DOH! This kfree's for you Mark :-) My forehead hurts... */ + kfree(verbuf); + + /* Leave the firmware in the 'post-prog' mode. flashdl_disable will */ + /* actually disable programming mode. Remember, that will cause the */ + /* the firmware to effectively reset itself. */ + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_cmd_initialize +* +* Issues the initialize command and sets the hw->state based +* on the result. +* +* Arguments: +* hw device structure +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_cmd_initialize(hfa384x_t *hw) +{ + int result = 0; + int i; + hfa384x_metacmd_t cmd; + + DBFENTER; + + /* we don't want to be interrupted during the reset */ + hfa384x_setreg(hw, 0, HFA384x_INTEN); + hfa384x_setreg(hw, 0xffff, HFA384x_EVACK); + + cmd.cmd = HFA384x_CMDCODE_INIT; + cmd.parm0 = 0; + cmd.parm1 = 0; + cmd.parm2 = 0; + + spin_lock_bh(&hw->cmdlock); + result = hfa384x_docmd_wait(hw, &cmd); + spin_unlock_bh(&hw->cmdlock); + + if ( result == 0 ) { + for ( i = 0; i < HFA384x_NUMPORTS_MAX; i++) { + hw->port_enabled[i] = 0; + } + } + + hw->link_status = HFA384x_LINK_NOTCONNECTED; + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_commtallies +* +* Send a commtallies inquiry to the MAC. Note that this is an async +* call that will result in an info frame arriving sometime later. +* +* Arguments: +* hw device structure +* +* Returns: +* zero success. +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +int hfa384x_drvr_commtallies( hfa384x_t *hw ) +{ + hfa384x_metacmd_t cmd; + int result; + + DBFENTER; + + cmd.cmd = HFA384x_CMDCODE_INQ; + cmd.parm0 = HFA384x_IT_COMMTALLIES; + cmd.parm1 = 0; + cmd.parm2 = 0; + + spin_lock_bh(&hw->cmdlock); + result = hfa384x_docmd_wait(hw, &cmd); + spin_unlock_bh(&hw->cmdlock); + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_enable +* +* Issues the enable command to enable communications on one of +* the MACs 'ports'. Only macport 0 is valid for stations. +* APs may also enable macports 1-6. Only ports that are currently +* disabled may be enabled. +* +* Arguments: +* hw device structure +* macport MAC port number +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_drvr_enable(hfa384x_t *hw, UINT16 macport) +{ + int result = 0; + + DBFENTER; + if ((!hw->isap && macport != 0) || + (hw->isap && !(macport <= HFA384x_PORTID_MAX)) || + (hw->port_enabled[macport]) ){ + result = -EINVAL; + } else { + result = hfa384x_cmd_enable(hw, macport); + if ( result == 0 ) { + hw->port_enabled[macport] = 1; + } + } + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_cmd_enable +* +* Issues the the enable command to enable communications on one of the +* MACs 'ports'. +* +* Arguments: +* hw device structure +* macport MAC port number +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_cmd_enable(hfa384x_t *hw, UINT16 macport) +{ + int result = 0; + hfa384x_metacmd_t cmd; + + DBFENTER; + + cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ENABLE) | + HFA384x_CMD_MACPORT_SET(macport); + cmd.parm0 = 0; + cmd.parm1 = 0; + cmd.parm2 = 0; + + spin_lock_bh(&hw->cmdlock); + result = hfa384x_docmd_wait(hw, &cmd); + spin_unlock_bh(&hw->cmdlock); + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_disable +* +* Issues the disable command to stop communications on one of +* the MACs 'ports'. Only macport 0 is valid for stations. +* APs may also disable macports 1-6. Only ports that have been +* previously enabled may be disabled. +* +* Arguments: +* hw device structure +* macport MAC port number (host order) +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_drvr_disable(hfa384x_t *hw, UINT16 macport) +{ + int result = 0; + + DBFENTER; + if ((!hw->isap && macport != 0) || + (hw->isap && !(macport <= HFA384x_PORTID_MAX)) || + !(hw->port_enabled[macport]) ){ + result = -EINVAL; + } else { + result = hfa384x_cmd_disable(hw, macport); + if ( result == 0 ) { + hw->port_enabled[macport] = 0; + } + } + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_cmd_disable +* +* Issues the command to disable a port. +* +* Arguments: +* hw device structure +* macport MAC port number (host order) +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_cmd_disable(hfa384x_t *hw, UINT16 macport) +{ + int result = 0; + hfa384x_metacmd_t cmd; + + DBFENTER; + + cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_DISABLE) | + HFA384x_CMD_MACPORT_SET(macport); + cmd.parm0 = 0; + cmd.parm1 = 0; + cmd.parm2 = 0; + + spin_lock_bh(&hw->cmdlock); + result = hfa384x_docmd_wait(hw, &cmd); + spin_unlock_bh(&hw->cmdlock); + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_cmd_diagnose +* +* Issues the diagnose command to test the: register interface, +* MAC controller (including loopback), External RAM, Non-volatile +* memory integrity, and synthesizers. Following execution of this +* command, MAC/firmware are in the 'initial state'. Therefore, +* the Initialize command should be issued after successful +* completion of this command. This function may only be called +* when the MAC is in the 'communication disabled' state. +* +* Arguments: +* hw device structure +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +#define DIAG_PATTERNA ((UINT16)0xaaaa) +#define DIAG_PATTERNB ((UINT16)0x5555) + +int hfa384x_cmd_diagnose(hfa384x_t *hw) +{ + int result = 0; + hfa384x_metacmd_t cmd; + + DBFENTER; + + cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_DIAG); + cmd.parm0 = DIAG_PATTERNA; + cmd.parm1 = DIAG_PATTERNB; + cmd.parm2 = 0; + + spin_lock_bh(&hw->cmdlock); + result = hfa384x_docmd_wait(hw, &cmd); + spin_unlock_bh(&hw->cmdlock); + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_cmd_allocate +* +* Issues the allocate command instructing the firmware to allocate +* a 'frame structure buffer' in MAC controller RAM. This command +* does not provide the result, it only initiates one of the f/w's +* asynchronous processes to construct the buffer. When the +* allocation is complete, it will be indicated via the Alloc +* bit in the EvStat register and the FID identifying the allocated +* space will be available from the AllocFID register. Some care +* should be taken when waiting for the Alloc event. If a Tx or +* Notify command w/ Reclaim has been previously executed, it's +* possible the first Alloc event after execution of this command +* will be for the reclaimed buffer and not the one you asked for. +* This case must be handled in the Alloc event handler. +* +* Arguments: +* hw device structure +* len allocation length, must be an even value +* in the range [4-2400]. (host order) +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_cmd_allocate(hfa384x_t *hw, UINT16 len) +{ + int result = 0; + hfa384x_metacmd_t cmd; + + DBFENTER; + + if ( (len % 2) || + len < HFA384x_CMD_ALLOC_LEN_MIN || + len > HFA384x_CMD_ALLOC_LEN_MAX ) { + result = -EINVAL; + } else { + cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ALLOC); + cmd.parm0 = len; + cmd.parm1 = 0; + cmd.parm2 = 0; + + spin_lock_bh(&hw->cmdlock); + result = hfa384x_docmd_wait(hw, &cmd); + spin_unlock_bh(&hw->cmdlock); + } + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_cmd_transmit +* +* Instructs the firmware to transmit a frame previously copied +* to a given buffer. This function returns immediately, the Tx +* results are available via the Tx or TxExc events (if the frame +* control bits are set). The reclaim argument specifies if the +* FID passed will be used by the f/w tx process or returned for +* use w/ another transmit command. If reclaim is set, expect an +* Alloc event signalling the availibility of the FID for reuse. +* +* NOTE: hw->cmdlock MUST BE HELD before calling this function! +* +* Arguments: +* hw device structure +* reclaim [0|1] indicates whether the given FID will +* be handed back (via Alloc event) for reuse. +* (host order) +* qos [0-3] Value to put in the QoS field of the +* tx command, identifies a queue to place the +* outgoing frame in. +* (host order) +* fid FID of buffer containing the frame that was +* previously copied to MAC memory via the bap. +* (host order) +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* hw->resp0 will contain the FID being used by async tx +* process. If reclaim==0, resp0 will be the same as the fid +* argument. If reclaim==1, resp0 will be the different and +* is the value to watch for in the Tx|TxExc to indicate completion +* of the frame passed in fid. +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_cmd_transmit(hfa384x_t *hw, UINT16 reclaim, UINT16 qos, UINT16 fid) +{ + int result = 0; + hfa384x_metacmd_t cmd; + + DBFENTER; + cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_TX) | + HFA384x_CMD_RECL_SET(reclaim) | + HFA384x_CMD_QOS_SET(qos); + cmd.parm0 = fid; + cmd.parm1 = 0; + cmd.parm2 = 0; + + result = hfa384x_docmd_wait(hw, &cmd); + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_cmd_clearpersist +* +* Instructs the firmware to clear the persistence bit in a given +* FID. This has the effect of telling the firmware to drop the +* persistent frame. The FID must be one that was previously used +* to transmit a PRST frame. +* +* Arguments: +* hw device structure +* fid FID of the persistent frame (host order) +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_cmd_clearpersist(hfa384x_t *hw, UINT16 fid) +{ + int result = 0; + hfa384x_metacmd_t cmd; + + DBFENTER; + + cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_CLRPRST); + cmd.parm0 = fid; + cmd.parm1 = 0; + cmd.parm2 = 0; + + spin_lock_bh(&hw->cmdlock); + result = hfa384x_docmd_wait(hw, &cmd); + spin_unlock_bh(&hw->cmdlock); + + DBFEXIT; + return result; +} + +/*---------------------------------------------------------------- +* hfa384x_cmd_notify +* +* Sends an info frame to the firmware to alter the behavior +* of the f/w asynch processes. Can only be called when the MAC +* is in the enabled state. +* +* Arguments: +* hw device structure +* reclaim [0|1] indicates whether the given FID will +* be handed back (via Alloc event) for reuse. +* (host order) +* fid FID of buffer containing the frame that was +* previously copied to MAC memory via the bap. +* (host order) +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* hw->resp0 will contain the FID being used by async notify +* process. If reclaim==0, resp0 will be the same as the fid +* argument. If reclaim==1, resp0 will be the different. +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_cmd_notify(hfa384x_t *hw, UINT16 reclaim, UINT16 fid, + void *buf, UINT16 len) +{ + int result = 0; + hfa384x_metacmd_t cmd; + + DBFENTER; + cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_NOTIFY) | + HFA384x_CMD_RECL_SET(reclaim); + cmd.parm0 = fid; + cmd.parm1 = 0; + cmd.parm2 = 0; + + spin_lock_bh(&hw->cmdlock); + + /* Copy the record to FID */ + result = hfa384x_copy_to_bap(hw, HFA384x_BAP_PROC, hw->infofid, 0, buf, len); + if ( result ) { + WLAN_LOG_DEBUG(1, + "copy_to_bap(%04x, 0, %d) failed, result=0x%x\n", + hw->infofid, len, result); + result = -EIO; + goto failed; + } + + result = hfa384x_docmd_wait(hw, &cmd); + + failed: + spin_unlock_bh(&hw->cmdlock); + + DBFEXIT; + return result; +} + + +#if 0 +/*---------------------------------------------------------------- +* hfa384x_cmd_inquiry +* +* Requests an info frame from the firmware. The info frame will +* be delivered asynchronously via the Info event. +* +* Arguments: +* hw device structure +* fid FID of the info frame requested. (host order) +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +static int hfa384x_cmd_inquiry(hfa384x_t *hw, UINT16 fid) +{ + int result = 0; + hfa384x_metacmd_t cmd; + + DBFENTER; + + cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_INQ); + cmd.parm0 = fid; + cmd.parm1 = 0; + cmd.parm2 = 0; + + spin_lock_bh(&hw->cmdlock); + result = hfa384x_docmd_wait(hw, &cmd); + spin_unlock_bh(&hw->cmdlock); + + DBFEXIT; + return result; +} +#endif + + +/*---------------------------------------------------------------- +* hfa384x_cmd_access +* +* Requests that a given record be copied to/from the record +* buffer. If we're writing from the record buffer, the contents +* must previously have been written to the record buffer via the +* bap. If we're reading into the record buffer, the record can +* be read out of the record buffer after this call. +* +* Arguments: +* hw device structure +* write [0|1] copy the record buffer to the given +* configuration record. (host order) +* rid RID of the record to read/write. (host order) +* buf host side record buffer. Upon return it will +* contain the body portion of the record (minus the +* RID and len). +* len buffer length (in bytes, should match record length) +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_cmd_access(hfa384x_t *hw, UINT16 write, UINT16 rid, + void* buf, UINT16 len) +{ + int result = 0; + hfa384x_metacmd_t cmd; + hfa384x_rec_t rec; + + DBFENTER; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) + /* This should NOT be called in interrupt context! */ + if (in_irq()) { + WLAN_LOG_ERROR("Krap, in Interrupt context!"); +#ifdef WLAN_INCLUDE_DEBUG + BUG(); +#endif + } +#endif + spin_lock_bh(&hw->cmdlock); + + if (write) { + rec.rid = host2hfa384x_16(rid); + rec.reclen = host2hfa384x_16((len/2) + 1); /* note conversion to words, +1 for rid field */ + /* write the record */ + result = hfa384x_copy_to_bap4( hw, HFA384x_BAP_PROC, rid, 0, + &rec, sizeof(rec), + buf, len, + NULL, 0, NULL, 0); + if ( result ) { + WLAN_LOG_DEBUG(3,"Failure writing record header+data\n"); + goto fail; + } + + } + + cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ACCESS) | + HFA384x_CMD_WRITE_SET(write); + cmd.parm0 = rid; + cmd.parm1 = 0; + cmd.parm2 = 0; + + result = hfa384x_docmd_wait(hw, &cmd); + if ( result ) { + WLAN_LOG_ERROR("Call to hfa384x_docmd_wait failed (%d %d)\n", + result, cmd.result.resp0); + goto fail; + } + + if (!write) { + result = hfa384x_copy_from_bap( hw, HFA384x_BAP_PROC, rid, 0, &rec, sizeof(rec)); + if ( result ) { + WLAN_LOG_DEBUG(3,"Call to hfa384x_copy_from_bap failed\n"); + goto fail; + } + + /* Validate the record length */ + if ( ((hfa384x2host_16(rec.reclen)-1)*2) != len ) { /* note body len calculation in bytes */ + WLAN_LOG_DEBUG(1, "RID len mismatch, rid=0x%04x hlen=%d fwlen=%d\n", + rid, len, (hfa384x2host_16(rec.reclen)-1)*2); + result = -ENODATA; + goto fail; + } + + result = hfa384x_copy_from_bap( hw, HFA384x_BAP_PROC, rid, sizeof(rec), buf, len); + + } + + fail: + spin_unlock_bh(&hw->cmdlock); + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_cmd_monitor +* +* Enables the 'monitor mode' of the MAC. Here's the description of +* monitor mode that I've received thus far: +* +* "The "monitor mode" of operation is that the MAC passes all +* frames for which the PLCP checks are correct. All received +* MPDUs are passed to the host with MAC Port = 7, with a +* receive status of good, FCS error, or undecryptable. Passing +* certain MPDUs is a violation of the 802.11 standard, but useful +* for a debugging tool." Normal communication is not possible +* while monitor mode is enabled. +* +* Arguments: +* hw device structure +* enable a code (0x0b|0x0f) that enables/disables +* monitor mode. (host order) +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_cmd_monitor(hfa384x_t *hw, UINT16 enable) +{ + int result = 0; + hfa384x_metacmd_t cmd; + + DBFENTER; + + cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_MONITOR) | + HFA384x_CMD_AINFO_SET(enable); + cmd.parm0 = 0; + cmd.parm1 = 0; + cmd.parm2 = 0; + + spin_lock_bh(&hw->cmdlock); + result = hfa384x_docmd_wait(hw, &cmd); + spin_unlock_bh(&hw->cmdlock); + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_cmd_download +* +* Sets the controls for the MAC controller code/data download +* process. The arguments set the mode and address associated +* with a download. Note that the aux registers should be enabled +* prior to setting one of the download enable modes. +* +* Arguments: +* hw device structure +* mode 0 - Disable programming and begin code exec +* 1 - Enable volatile mem programming +* 2 - Enable non-volatile mem programming +* 3 - Program non-volatile section from NV download +* buffer. +* (host order) +* lowaddr +* highaddr For mode 1, sets the high & low order bits of +* the "destination address". This address will be +* the execution start address when download is +* subsequently disabled. +* For mode 2, sets the high & low order bits of +* the destination in NV ram. +* For modes 0 & 3, should be zero. (host order) +* NOTE: these address args are in CMD format +* codelen Length of the data to write in mode 2, +* zero otherwise. (host order) +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_cmd_download(hfa384x_t *hw, UINT16 mode, UINT16 lowaddr, + UINT16 highaddr, UINT16 codelen) +{ + int result = 0; + hfa384x_metacmd_t cmd; + + DBFENTER; + + cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_DOWNLD) | + HFA384x_CMD_PROGMODE_SET(mode); + cmd.parm0 = lowaddr; + cmd.parm1 = highaddr; + cmd.parm2 = codelen; + + spin_lock_bh(&hw->cmdlock); + result = hfa384x_dl_docmd_wait(hw, &cmd); + spin_unlock_bh(&hw->cmdlock); + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_cmd_aux_enable +* +* Goes through the process of enabling the auxilary port. This +* is necessary prior to raw reads/writes to card data space. +* Direct access to the card data space is only used for downloading +* code and debugging. +* Note that a call to this function is required before attempting +* a download. +* +* Arguments: +* hw device structure +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout) +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_cmd_aux_enable(hfa384x_t *hw, int force) +{ + int result = -ETIMEDOUT; + unsigned long flags; + UINT32 retries_remaining; + UINT16 reg; + UINT auxen_mirror = hw->auxen; + + DBFENTER; + + /* Check for existing enable */ + if ( hw->auxen ) { + hw->auxen++; + return 0; + } + + /* acquire the lock */ + spin_lock_irqsave( &(hw->cmdlock), flags); + /* wait for cmd register busy bit to clear */ + retries_remaining = 100000; + do { + reg = hfa384x_getreg(hw, HFA384x_CMD); + udelay(10); + } + while (HFA384x_CMD_ISBUSY(reg) && --retries_remaining); + if (retries_remaining != 0) { + /* busy bit clear, it's OK to write to ParamX regs */ + hfa384x_setreg(hw, HFA384x_AUXPW0, + HFA384x_PARAM0); + hfa384x_setreg(hw, HFA384x_AUXPW1, + HFA384x_PARAM1); + hfa384x_setreg(hw, HFA384x_AUXPW2, + HFA384x_PARAM2); + + /* Set the aux enable in the Control register */ + hfa384x_setreg(hw, HFA384x_CONTROL_AUX_DOENABLE, + HFA384x_CONTROL); + + /* Now wait for completion */ + retries_remaining = 100000; + do { + reg = hfa384x_getreg(hw, HFA384x_CONTROL); + udelay(10); + } + while ( ((reg & (BIT14|BIT15)) != HFA384x_CONTROL_AUX_ISENABLED) && + --retries_remaining ); + if (retries_remaining != 0) { + result = 0; + hw->auxen++; + } + } + + /* Force it enabled even if the command failed, if told.. */ + if ((hw->auxen == auxen_mirror) && force) + hw->auxen++; + + spin_unlock_irqrestore( &(hw->cmdlock), flags); + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_cmd_aux_disable +* +* Goes through the process of disabling the auxilary port +* enabled with aux_enable(). +* +* Arguments: +* hw device structure +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout) +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_cmd_aux_disable(hfa384x_t *hw) +{ + int result = -ETIMEDOUT; + unsigned long timeout; + UINT16 reg = 0; + + DBFENTER; + + /* See if there's more than one enable */ + if (hw->auxen) hw->auxen--; + if (hw->auxen) return 0; + + /* Clear the aux enable in the Control register */ + hfa384x_setreg(hw, 0, HFA384x_PARAM0); + hfa384x_setreg(hw, 0, HFA384x_PARAM1); + hfa384x_setreg(hw, 0, HFA384x_PARAM2); + hfa384x_setreg(hw, HFA384x_CONTROL_AUX_DODISABLE, + HFA384x_CONTROL); + + /* Now wait for completion */ + timeout = jiffies + 1*HZ; + reg = hfa384x_getreg(hw, HFA384x_CONTROL); + while ( ((reg & (BIT14|BIT15)) != HFA384x_CONTROL_AUX_ISDISABLED) && + time_before(jiffies,timeout) ){ + udelay(10); + reg = hfa384x_getreg(hw, HFA384x_CONTROL); + } + if ((reg & (BIT14|BIT15)) == HFA384x_CONTROL_AUX_ISDISABLED ) { + result = 0; + } + DBFEXIT; + return result; +} + +/*---------------------------------------------------------------- +* hfa384x_drvr_low_level +* +* Write test commands to the card. Some test commands don't make +* sense without prior set-up. For example, continous TX isn't very +* useful until you set the channel. That functionality should be +* +* Side effects: +* +* Call context: +* process thread +* -----------------------------------------------------------------*/ +int hfa384x_drvr_low_level(hfa384x_t *hw, hfa384x_metacmd_t *cmd) +{ + int result = 0; + DBFENTER; + + /* Do i need a host2hfa... conversion ? */ +#if 0 + printk(KERN_INFO "%#x %#x %#x %#x\n", cmd->cmd, cmd->parm0, cmd->parm1, cmd->parm2); +#endif + spin_lock_bh(&hw->cmdlock); + result = hfa384x_docmd_wait(hw, cmd); + spin_unlock_bh(&hw->cmdlock); + + DBFEXIT; + return result; +} + + +/* TODO: determine if these will ever be needed */ +#if 0 +int hfa384x_cmd_readmif(hfa384x_t *hw) +{ + DBFENTER; + DBFEXIT; + return 0; +} + + +int hfa384x_cmd_writemif(hfa384x_t *hw) +{ + DBFENTER; + DBFEXIT; + return 0; +} +#endif + +/*---------------------------------------------------------------- +* hfa384x_drvr_mmi_read +* +* Read mmi registers. mmi is intersil-speak for the baseband +* processor registers. +* +* Arguments: +* hw device structure +* register The test register to be accessed (must be even #). +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_drvr_mmi_read(hfa384x_t *hw, UINT32 addr, UINT32 *resp) +{ + int result = 0; + hfa384x_metacmd_t cmd; + + DBFENTER; + cmd.cmd = (UINT16) 0x30; + cmd.parm0 = (UINT16) addr; + cmd.parm1 = 0; + cmd.parm2 = 0; + + /* Do i need a host2hfa... conversion ? */ + spin_lock_bh(&hw->cmdlock); + result = hfa384x_docmd_wait(hw, &cmd); + spin_unlock_bh(&hw->cmdlock); + + *resp = (UINT32) cmd.result.resp0; + + DBFEXIT; + return result; +} + +/*---------------------------------------------------------------- +* hfa384x_drvr_mmi_write +* +* Read mmi registers. mmi is intersil-speak for the baseband +* processor registers. +* +* Arguments: +* hw device structure +* addr The test register to be accessed (must be even #). +* data The data value to write to the register. +* +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ + +int +hfa384x_drvr_mmi_write(hfa384x_t *hw, UINT32 addr, UINT32 data) +{ + int result = 0; + hfa384x_metacmd_t cmd; + + DBFENTER; + cmd.cmd = (UINT16) 0x31; + cmd.parm0 = (UINT16) addr; + cmd.parm1 = (UINT16) data; + cmd.parm2 = 0; + + WLAN_LOG_DEBUG(1,"mmi write : addr = 0x%08x\n", addr); + WLAN_LOG_DEBUG(1,"mmi write : data = 0x%08x\n", data); + + /* Do i need a host2hfa... conversion ? */ + spin_lock_bh(&hw->cmdlock); + result = hfa384x_docmd_wait(hw, &cmd); + spin_unlock_bh(&hw->cmdlock); + + DBFEXIT; + return result; +} + + +/* TODO: determine if these will ever be needed */ +#if 0 +int hfa384x_cmd_readmif(hfa384x_t *hw) +{ + DBFENTER; + DBFEXIT; + return 0; +} + + +int hfa384x_cmd_writemif(hfa384x_t *hw) +{ + DBFENTER; + DBFEXIT; + return 0; +} +#endif + + + +/*---------------------------------------------------------------- +* hfa384x_copy_from_bap +* +* Copies a collection of bytes from the MAC controller memory via +* one set of BAP registers. +* +* Arguments: +* hw device structure +* bap [0|1] which BAP to use +* id FID or RID, destined for the select register (host order) +* offset An _even_ offset into the buffer for the given +* FID/RID. We haven't the means to validate this, +* so be careful. (host order) +* buf ptr to array of bytes +* len length of data to transfer in bytes +* +* Returns: +* 0 success +* >0 f/w reported failure - value of offset reg. +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process thread +* interrupt +----------------------------------------------------------------*/ +int hfa384x_copy_from_bap(hfa384x_t *hw, UINT16 bap, UINT16 id, UINT16 offset, + void *buf, UINT len) +{ + int result = 0; + unsigned long flags = 0; + UINT8 *d = (UINT8*)buf; + UINT selectreg; + UINT offsetreg; + UINT datareg; + UINT i; + UINT16 reg = 0; + + DBFENTER; + + /* Validate bap, offset, buf, and len */ + if ( (bap > 1) || + (offset > HFA384x_BAP_OFFSET_MAX) || + (offset % 2) || + (buf == NULL) || + (len > HFA384x_BAP_DATALEN_MAX) ){ + result = -EINVAL; + } else { + selectreg = (bap == 1) ? HFA384x_SELECT1 : HFA384x_SELECT0 ; + offsetreg = (bap == 1) ? HFA384x_OFFSET1 : HFA384x_OFFSET0 ; + datareg = (bap == 1) ? HFA384x_DATA1 : HFA384x_DATA0 ; + + /* Obtain lock */ + spin_lock_irqsave( &(hw->baplock), flags); + + /* Write id to select reg */ + hfa384x_setreg(hw, id, selectreg); + /* Write offset to offset reg */ + hfa384x_setreg(hw, offset, offsetreg); + /* Wait for offset[busy] to clear (see BAP_TIMEOUT) */ + i = 0; + do { + reg = hfa384x_getreg(hw, offsetreg); + if ( i > 0 ) udelay(10); + i++; + } while ( i < prism2_bap_timeout && HFA384x_OFFSET_ISBUSY(reg)); +#if (WLAN_HOSTIF != WLAN_PCI) + /* Release lock */ + spin_unlock_irqrestore( &(hw->baplock), flags); +#endif + + if ( HFA384x_OFFSET_ISBUSY(reg) ){ + /* If timeout, return -ETIMEDOUT */ + result = reg; + } else if ( HFA384x_OFFSET_ISERR(reg) ){ + /* If offset[err] == 1, return -EINVAL */ + result = reg; + } else { + /* Read even(len) buf contents from data reg */ + for ( i = 0; i < (len & 0xfffe); i+=2 ) { + *(UINT16*)(&(d[i])) = + hfa384x_getreg_noswap(hw, datareg); + } + /* If len odd, handle last byte */ + if ( len % 2 ){ + reg = hfa384x_getreg_noswap(hw, datareg); + d[len-1] = ((UINT8*)(®))[0]; + } + } + + /* According to Intersil errata dated 9/16/02: + + "In PRISM PCI MAC host interface, if both BAPs are concurrently + requesing memory access, both will accept the Ack. There is no + firmware workaround possible. To prevent BAP access failures or + hang conditions the host MUST NOT access both BAPs in sucession + unless at least 5us elapses between accesses. The safest choice + is to USE ONLY ONE BAP for all data movement operations." + + What this means: + + We have to serialize ALL BAP accesses, and furthermore, add a 5us + delay after access if we're using a PCI platform. + + Unfortunately, this means we have to lock out interrupts througout + the entire BAP copy. + + It remains to be seen if "BAP access" means "BAP setup" or the more + literal definition of "copying data back and forth" I'm erring for + the latter, safer definition. -- SLP. + + */ + +#if (WLAN_HOSTIF == WLAN_PCI) + udelay(5); + /* Release lock */ + spin_unlock_irqrestore( &(hw->baplock), flags); +#endif + + } + + if (result) { + WLAN_LOG_DEBUG(1, + "copy_from_bap(0x%04x, 0, %d) failed, result=0x%x\n", + reg, len, result); + } + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_copy_to_bap +* +* Copies a collection of bytes to the MAC controller memory via +* one set of BAP registers. +* +* Arguments: +* hw device structure +* bap [0|1] which BAP to use +* id FID or RID, destined for the select register (host order) +* offset An _even_ offset into the buffer for the given +* FID/RID. We haven't the means to validate this, +* so be careful. (host order) +* buf ptr to array of bytes +* len length of data to transfer (in bytes) +* +* Returns: +* 0 success +* >0 f/w reported failure - value of offset reg. +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process thread +* interrupt +----------------------------------------------------------------*/ +int hfa384x_copy_to_bap(hfa384x_t *hw, UINT16 bap, UINT16 id, UINT16 offset, + void *buf, UINT len) +{ + return hfa384x_copy_to_bap4(hw, bap, id, offset, buf, len, NULL, 0, NULL, 0, NULL, 0); +} + +int hfa384x_copy_to_bap4(hfa384x_t *hw, UINT16 bap, UINT16 id, UINT16 offset, + void *buf, UINT len1, void* buf2, UINT len2, + void *buf3, UINT len3, void *buf4, UINT len4) +{ + int result = 0; + unsigned long flags = 0; + UINT8 *d; + UINT selectreg; + UINT offsetreg; + UINT datareg; + UINT i; + UINT16 reg; + + DBFENTER; + +// printk(KERN_DEBUG "ctb1 %d id %04x o %d %d %d %d %d\n", bap, id, offset, len1, len2, len3, len4); + + /* Validate bap, offset, buf, and len */ + if ( (bap > 1) || + (offset > HFA384x_BAP_OFFSET_MAX) || + (offset % 2) || + (buf == NULL) || + (len1+len2+len3+len4 > HFA384x_BAP_DATALEN_MAX) ){ + result = -EINVAL; + } else { + selectreg = (bap == 1) ? HFA384x_SELECT1 : HFA384x_SELECT0; + offsetreg = (bap == 1) ? HFA384x_OFFSET1 : HFA384x_OFFSET0; + datareg = (bap == 1) ? HFA384x_DATA1 : HFA384x_DATA0; + /* Obtain lock */ + spin_lock_irqsave( &(hw->baplock), flags); + + /* Write id to select reg */ + hfa384x_setreg(hw, id, selectreg); + udelay(10); + /* Write offset to offset reg */ + hfa384x_setreg(hw, offset, offsetreg); + /* Wait for offset[busy] to clear (see BAP_TIMEOUT) */ + i = 0; + do { + reg = hfa384x_getreg(hw, offsetreg); + if ( i > 0 ) udelay(10); + i++; + } while ( i < prism2_bap_timeout && HFA384x_OFFSET_ISBUSY(reg)); + +#if (WLAN_HOSTIF != WLAN_PCI) + /* Release lock */ + spin_unlock_irqrestore( &(hw->baplock), flags); +#endif + + if ( HFA384x_OFFSET_ISBUSY(reg) ){ + /* If timeout, return reg */ + result = reg; + } else if ( HFA384x_OFFSET_ISERR(reg) ){ + /* If offset[err] == 1, return reg */ + result = reg; + } else { + d = (UINT8*)buf; + /* Write even(len1) buf contents to data reg */ + for ( i = 0; i < (len1 & 0xfffe); i+=2 ) { + hfa384x_setreg_noswap(hw, + *(UINT16*)(&(d[i])), datareg); + } + if (len1 & 1) { + UINT16 data; + UINT8 *b = (UINT8 *) &data; + b[0] = d[len1-1]; + if (buf2 != NULL) { + d = (UINT8*)buf2; + b[1] = d[0]; + len2--; + buf2++; + } + hfa384x_setreg_noswap(hw, data, datareg); + } + if ((buf2 != NULL) && (len2 > 0)) { + /* Write even(len2) buf contents to data reg */ + d = (UINT8*)buf2; + for ( i = 0; i < (len2 & 0xfffe); i+=2 ) { + hfa384x_setreg_noswap(hw, *(UINT16*)(&(d[i])), datareg); + } + if (len2 & 1) { + UINT16 data; + UINT8 *b = (UINT8 *) &data; + b[0] = d[len2-1]; + if (buf3 != NULL) { + d = (UINT8*)buf3; + b[1] = d[0]; + len3--; + buf3++; + } + hfa384x_setreg_noswap(hw, data, datareg); + } + } + + if ((buf3 != NULL) && (len3 > 0)) { + /* Write even(len3) buf contents to data reg */ + d = (UINT8*)buf3; + for ( i = 0; i < (len3 & 0xfffe); i+=2 ) { + hfa384x_setreg_noswap(hw, *(UINT16*)(&(d[i])), datareg); + } + if (len3 & 1) { + UINT16 data; + UINT8 *b = (UINT8 *) &data; + b[0] = d[len3-1]; + if (buf4 != NULL) { + d = (UINT8*)buf4; + b[1] = d[0]; + len4--; + buf4++; + } + hfa384x_setreg_noswap(hw, data, datareg); + } + } + if ((buf4 != NULL) && (len4 > 0)) { + /* Write even(len4) buf contents to data reg */ + d = (UINT8*)buf4; + for ( i = 0; i < (len4 & 0xfffe); i+=2 ) { + hfa384x_setreg_noswap(hw, *(UINT16*)(&(d[i])), datareg); + } + if (len4 & 1) { + UINT16 data; + UINT8 *b = (UINT8 *) &data; + b[0] = d[len4-1]; + b[1] = 0; + + hfa384x_setreg_noswap(hw, data, datareg); + } + } +// printk(KERN_DEBUG "ctb2 %d id %04x o %d %d %d %d %d\n", bap, id, offset, len1, len2, len3, len4); + + } + +#if (WLAN_HOSTIF == WLAN_PCI) + udelay(5); + /* Release lock */ + spin_unlock_irqrestore( &(hw->baplock), flags); +#endif + + } + + if (result) + WLAN_LOG_ERROR("copy_to_bap() failed.\n"); + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_copy_from_aux +* +* Copies a collection of bytes from the controller memory. The +* Auxiliary port MUST be enabled prior to calling this function. +* We _might_ be in a download state. +* +* Arguments: +* hw device structure +* cardaddr address in hfa384x data space to read +* auxctl address space select +* buf ptr to destination host buffer +* len length of data to transfer (in bytes) +* +* Returns: +* nothing +* +* Side effects: +* buf contains the data copied +* +* Call context: +* process thread +* interrupt +----------------------------------------------------------------*/ +void +hfa384x_copy_from_aux( + hfa384x_t *hw, UINT32 cardaddr, UINT32 auxctl, void *buf, UINT len) +{ + UINT16 currpage; + UINT16 curroffset; + UINT i = 0; + + DBFENTER; + + if ( !(hw->auxen) ) { + WLAN_LOG_DEBUG(1, + "Attempt to read 0x%04x when aux not enabled\n", + cardaddr); + return; + + } + /* Build appropriate aux page and offset */ + currpage = HFA384x_AUX_MKPAGE(cardaddr); + curroffset = HFA384x_AUX_MKOFF(cardaddr, auxctl); + hfa384x_setreg(hw, currpage, HFA384x_AUXPAGE); + hfa384x_setreg(hw, curroffset, HFA384x_AUXOFFSET); + udelay(5); /* beat */ + + /* read the data */ + while ( i < len) { + *((UINT16*)(buf+i)) = hfa384x_getreg_noswap(hw, HFA384x_AUXDATA); + i+=2; + curroffset+=2; + if ( (curroffset&HFA384x_ADDR_AUX_OFF_MASK) > + HFA384x_ADDR_AUX_OFF_MAX ) { + currpage++; + curroffset = 0; + curroffset = HFA384x_AUX_MKOFF(curroffset, auxctl); + hfa384x_setreg(hw, currpage, HFA384x_AUXPAGE); + hfa384x_setreg(hw, curroffset, HFA384x_AUXOFFSET); + udelay(5); /* beat */ + } + } + /* Make sure the auxctl bits are clear */ + hfa384x_setreg(hw, 0, HFA384x_AUXOFFSET); + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* hfa384x_copy_to_aux +* +* Copies a collection of bytes to the controller memory. The +* Auxiliary port MUST be enabled prior to calling this function. +* We _might_ be in a download state. +* +* Arguments: +* hw device structure +* cardaddr address in hfa384x data space to read +* auxctl address space select +* buf ptr to destination host buffer +* len length of data to transfer (in bytes) +* +* Returns: +* nothing +* +* Side effects: +* Controller memory now contains a copy of buf +* +* Call context: +* process thread +* interrupt +----------------------------------------------------------------*/ +void +hfa384x_copy_to_aux( + hfa384x_t *hw, UINT32 cardaddr, UINT32 auxctl, void *buf, UINT len) +{ + UINT16 currpage; + UINT16 curroffset; + UINT i = 0; + + DBFENTER; + + if ( !(hw->auxen) ) { + WLAN_LOG_DEBUG(1, + "Attempt to read 0x%04x when aux not enabled\n", + cardaddr); + return; + + } + /* Build appropriate aux page and offset */ + currpage = HFA384x_AUX_MKPAGE(cardaddr); + curroffset = HFA384x_AUX_MKOFF(cardaddr, auxctl); + hfa384x_setreg(hw, currpage, HFA384x_AUXPAGE); + hfa384x_setreg(hw, curroffset, HFA384x_AUXOFFSET); + udelay(5); /* beat */ + + /* write the data */ + while ( i < len) { + hfa384x_setreg_noswap(hw, + *((UINT16*)(buf+i)), HFA384x_AUXDATA); + i+=2; + curroffset+=2; + if ( curroffset > HFA384x_ADDR_AUX_OFF_MAX ) { + currpage++; + curroffset = 0; + hfa384x_setreg(hw, currpage, HFA384x_AUXPAGE); + hfa384x_setreg(hw, curroffset, HFA384x_AUXOFFSET); + udelay(5); /* beat */ + } + } + DBFEXIT; +} + + +/*---------------------------------------------------------------- +* hfa384x_cmd_wait +* +* Waits for availability of the Command register, then +* issues the given command. Then polls the Evstat register +* waiting for command completion. Timeouts shouldn't be +* possible since we're preventing overlapping commands and all +* commands should be cleared and acknowledged. +* +* Arguments: +* wlandev device structure +* cmd cmd structure. Includes all arguments and result +* data points. All in host order. +* +* Returns: +* 0 success +* -ETIMEDOUT timed out waiting for register ready or +* command completion +* >0 command indicated error, Status and Resp0-2 are +* in hw structure. +* +* Side effects: +* +* +* Call context: +* process thread +----------------------------------------------------------------*/ +static int hfa384x_docmd_wait( hfa384x_t *hw, hfa384x_metacmd_t *cmd) +{ + int result = -ETIMEDOUT; + UINT16 reg = 0; + UINT16 counter; + + DBFENTER; + + hw->cmdflag = 0; + hw->cmddata = cmd; + + /* wait for the busy bit to clear */ + counter = 0; + reg = hfa384x_getreg(hw, HFA384x_CMD); + while ( HFA384x_CMD_ISBUSY(reg) && + (counter < 10)) { + reg = hfa384x_getreg(hw, HFA384x_CMD); + counter++; + udelay(10); + } + + if (HFA384x_CMD_ISBUSY(reg)) { + WLAN_LOG_ERROR("hfa384x_cmd timeout(1), reg=0x%0hx.\n", reg); + goto failed; + } + if (!HFA384x_CMD_ISBUSY(reg)) { + /* busy bit clear, write command */ + hfa384x_setreg(hw, cmd->parm0, HFA384x_PARAM0); + hfa384x_setreg(hw, cmd->parm1, HFA384x_PARAM1); + hfa384x_setreg(hw, cmd->parm2, HFA384x_PARAM2); + hfa384x_setreg(hw, cmd->cmd, HFA384x_CMD); + +#ifdef CMD_IRQ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)) + while (! hw->cmdflag) + interruptible_sleep_on(&hw->cmdq); +#else + wait_event_interruptible(hw->cmdq, hw->cmdflag); +#endif + result = HFA384x_STATUS_RESULT_GET(cmd->status); +#else // CMD_IRQ + /* Now wait for completion */ + counter = 0; + reg = hfa384x_getreg(hw, HFA384x_EVSTAT); + /* Initialization is the problem. It takes about + 100ms. "normal" commands are typically is about + 200-400 us (I've never seen less than 200). Longer + is better so that we're not hammering the bus. */ + while ( !HFA384x_EVSTAT_ISCMD(reg) && + (counter < 5000)) { + reg = hfa384x_getreg(hw, HFA384x_EVSTAT); + counter++; + udelay(200); + } + + if ( HFA384x_EVSTAT_ISCMD(reg) ) { + result = 0; + cmd->result.status = hfa384x_getreg(hw, HFA384x_STATUS); + cmd->result.resp0 = hfa384x_getreg(hw, HFA384x_RESP0); + cmd->result.resp1 = hfa384x_getreg(hw, HFA384x_RESP1); + cmd->result.resp2 = hfa384x_getreg(hw, HFA384x_RESP2); + hfa384x_setreg(hw, HFA384x_EVACK_CMD, + HFA384x_EVACK); + result = HFA384x_STATUS_RESULT_GET(cmd->result.status); + } else { + WLAN_LOG_ERROR("hfa384x_cmd timeout(2), reg=0x%0hx.\n", reg); + } +#endif /* CMD_IRQ */ + } + + failed: + hw->cmdflag = 0; + hw->cmddata = NULL; + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_dl_docmd_wait +* +* Waits for availability of the Command register, then +* issues the given command. Then polls the Evstat register +* waiting for command completion. Timeouts shouldn't be +* possible since we're preventing overlapping commands and all +* commands should be cleared and acknowledged. +* +* This routine is only used for downloads. Since it doesn't lock out +* interrupts the system response is much better. +* +* Arguments: +* wlandev device structure +* cmd cmd structure. Includes all arguments and result +* data points. All in host order. +* +* Returns: +* 0 success +* -ETIMEDOUT timed out waiting for register ready or +* command completion +* >0 command indicated error, Status and Resp0-2 are +* in hw structure. +* +* Side effects: +* +* +* Call context: +* process thread +----------------------------------------------------------------*/ +static int hfa384x_dl_docmd_wait( hfa384x_t *hw, hfa384x_metacmd_t *cmd) +{ + int result = -ETIMEDOUT; + unsigned long timeout; + UINT16 reg = 0; + + DBFENTER; + /* wait for the busy bit to clear */ + timeout = jiffies + 1*HZ; + reg = hfa384x_getreg(hw, HFA384x_CMD); + while ( HFA384x_CMD_ISBUSY(reg) && time_before( jiffies, timeout) ) { + reg = hfa384x_getreg(hw, HFA384x_CMD); + udelay(10); + } + if (HFA384x_CMD_ISBUSY(reg)) { + WLAN_LOG_WARNING("Timed out waiting for cmd register.\n"); + goto failed; + } + + if (!HFA384x_CMD_ISBUSY(reg)) { + /* busy bit clear, write command */ + hfa384x_setreg(hw, cmd->parm0, HFA384x_PARAM0); + hfa384x_setreg(hw, cmd->parm1, HFA384x_PARAM1); + hfa384x_setreg(hw, cmd->parm2, HFA384x_PARAM2); + hfa384x_setreg(hw, cmd->cmd, HFA384x_CMD); + + /* Now wait for completion */ + if ( (HFA384x_CMD_CMDCODE_GET(cmd->cmd) == HFA384x_CMDCODE_DOWNLD) ) { + /* dltimeout is in ms */ + timeout = (((UINT32)hw->dltimeout) / 1000UL) * HZ; + if ( timeout > 0 ) { + timeout += jiffies; + } else { + timeout = jiffies + 1*HZ; + } + } else { + timeout = jiffies + 1*HZ; + } + reg = hfa384x_getreg(hw, HFA384x_EVSTAT); + while ( !HFA384x_EVSTAT_ISCMD(reg) && time_before(jiffies,timeout) ) { + udelay(100); + reg = hfa384x_getreg(hw, HFA384x_EVSTAT); + } + if ( HFA384x_EVSTAT_ISCMD(reg) ) { + result = 0; + cmd->result.status = hfa384x_getreg(hw, HFA384x_STATUS); + cmd->result.resp0 = hfa384x_getreg(hw, HFA384x_RESP0); + cmd->result.resp1 = hfa384x_getreg(hw, HFA384x_RESP1); + cmd->result.resp2 = hfa384x_getreg(hw, HFA384x_RESP2); + hfa384x_setreg(hw, HFA384x_EVACK_CMD, HFA384x_EVACK); + result = HFA384x_STATUS_RESULT_GET(cmd->result.status); + } + } + +failed: + DBFEXIT; + return result; +} + +/*---------------------------------------------------------------- +* hfa384x_drvr_start +* +* Issues the MAC initialize command, sets up some data structures, +* and enables the interrupts. After this function completes, the +* low-level stuff should be ready for any/all commands. +* +* Arguments: +* hw device structure +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_drvr_start(hfa384x_t *hw) +{ + int result = 0; + UINT16 reg; + int i; + int j; + DBFENTER; + + /* call initialize */ + result = hfa384x_cmd_initialize(hw); + if (result != 0) { + WLAN_LOG_ERROR("Initialize command failed.\n"); + goto failed; + } + + /* make sure interrupts are disabled and any layabout events cleared */ + hfa384x_setreg(hw, 0, HFA384x_INTEN); + hfa384x_setreg(hw, 0xffff, HFA384x_EVACK); + + hw->txfid_head = 0; + hw->txfid_tail = 0; + hw->txfid_N = HFA384x_DRVR_FIDSTACKLEN_MAX; + memset(hw->txfid_queue, 0, sizeof(hw->txfid_queue)); + + /* Allocate tx and notify FIDs */ + /* First, tx */ + for ( i = 0; i < HFA384x_DRVR_FIDSTACKLEN_MAX-1; i++) { + result = hfa384x_cmd_allocate(hw, HFA384x_DRVR_TXBUF_MAX); + if (result != 0) { + WLAN_LOG_ERROR("Allocate(tx) command failed.\n"); + goto failed; + } + j = 0; + do { + reg = hfa384x_getreg(hw, HFA384x_EVSTAT); + udelay(10); + j++; + } while ( !HFA384x_EVSTAT_ISALLOC(reg) && j < 50); /* 50 is timeout */ + if ( j >= 50 ) { + WLAN_LOG_ERROR("Timed out waiting for evalloc(tx).\n"); + result = -ETIMEDOUT; + goto failed; + } + reg = hfa384x_getreg(hw, HFA384x_ALLOCFID); + + txfid_queue_add(hw, reg); + + WLAN_LOG_DEBUG(4,"hw->txfid_queue[%d]=0x%04x\n",i,reg); + + reg = HFA384x_EVACK_ALLOC_SET(1); + hfa384x_setreg(hw, reg, HFA384x_EVACK); + + } + + /* Now, the info frame fid */ + result = hfa384x_cmd_allocate(hw, HFA384x_INFOFRM_MAXLEN); + if (result != 0) { + WLAN_LOG_ERROR("Allocate(tx) command failed.\n"); + goto failed; + } + i = 0; + do { + reg = hfa384x_getreg(hw, HFA384x_EVSTAT); + udelay(10); + i++; + } while ( !HFA384x_EVSTAT_ISALLOC(reg) && i < 50); /* 50 is timeout */ + if ( i >= 50 ) { + WLAN_LOG_ERROR("Timed out waiting for evalloc(info).\n"); + result = -ETIMEDOUT; + goto failed; + } + hw->infofid = hfa384x_getreg(hw, HFA384x_ALLOCFID); + reg = HFA384x_EVACK_ALLOC_SET(1); + hfa384x_setreg(hw, reg, HFA384x_EVACK); + WLAN_LOG_DEBUG(4,"hw->infofid=0x%04x\n", hw->infofid); + + /* Set swsupport regs to magic # for card presence detection */ + hfa384x_setreg(hw, HFA384x_DRVR_MAGIC, HFA384x_SWSUPPORT0); + + /* Now enable the interrupts and set the running state */ + hfa384x_setreg(hw, 0xffff, HFA384x_EVSTAT); + hfa384x_events_all(hw); + + hw->state = HFA384x_STATE_RUNNING; + + goto done; +failed: + WLAN_LOG_ERROR("Failed, result=%d\n", result); +done: + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_stop +* +* Issues the initialize command to leave us in the 'reset' state. +* +* Arguments: +* hw device structure +* Returns: +* 0 success +* >0 f/w reported error - f/w status code +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_drvr_stop(hfa384x_t *hw) +{ + int result = 0; + int i; + DBFENTER; + + del_timer_sync(&hw->commsqual_timer); + + if ( hw->wlandev->hwremoved ) { + /* only flush when we're shutting down for good */ + flush_scheduled_work(); + } + + if (hw->state == HFA384x_STATE_RUNNING) { + /* + * Send the MAC initialize cmd. + */ + hfa384x_cmd_initialize(hw); + + /* + * Make absolutely sure interrupts are disabled and any + * layabout events cleared + */ + hfa384x_setreg(hw, 0, HFA384x_INTEN); + hfa384x_setreg(hw, 0xffff, HFA384x_EVACK); + } + + tasklet_kill(&hw->bap_tasklet); + + hw->link_status = HFA384x_LINK_NOTCONNECTED; + hw->state = HFA384x_STATE_INIT; + + /* Clear all the port status */ + for ( i = 0; i < HFA384x_NUMPORTS_MAX; i++) { + hw->port_enabled[i] = 0; + } + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_txframe +* +* Takes a frame from prism2sta and queues it for transmission. +* +* Arguments: +* hw device structure +* skb packet buffer struct. Contains an 802.11 +* data frame. +* p80211_hdr points to the 802.11 header for the packet. +* Returns: +* 0 Success and more buffs available +* 1 Success but no more buffs +* 2 Allocation failure +* 3 MAC Tx command failed +* 4 Buffer full or queue busy +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_drvr_txframe(hfa384x_t *hw, struct sk_buff *skb, p80211_hdr_t *p80211_hdr, p80211_metawep_t *p80211_wep) +{ + hfa384x_tx_frame_t txdesc; + UINT16 macq = 0; + UINT16 fid; + int result; + + DBFENTER; + + /* Build Tx frame structure */ + /* Set up the control field */ + memset(&txdesc, 0, sizeof(txdesc)); + +/* Tx complete and Tx exception disable per dleach. Might be causing + * buf depletion + */ +#define DOBOTH 1 +#if DOBOTH + txdesc.tx_control = + HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) | + HFA384x_TX_TXEX_SET(1) | HFA384x_TX_TXOK_SET(1); +#elif DOEXC + txdesc.tx_control = + HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) | + HFA384x_TX_TXEX_SET(1) | HFA384x_TX_TXOK_SET(0); +#else + txdesc.tx_control = + HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) | + HFA384x_TX_TXEX_SET(0) | HFA384x_TX_TXOK_SET(0); +#endif + + /* if we're using host WEP, increase size by IV+ICV */ + if (p80211_wep->data) { + txdesc.data_len = host2hfa384x_16(skb->len+8); + // txdesc.tx_control |= HFA384x_TX_NOENCRYPT_SET(1); + } else { + txdesc.data_len = host2hfa384x_16(skb->len); + } + + txdesc.tx_control = host2hfa384x_16(txdesc.tx_control); + /* copy the header over to the txdesc */ + memcpy(&(txdesc.frame_control), p80211_hdr, sizeof(p80211_hdr_t)); + + /* Since tbusy is set whenever the stack is empty, there should + * always be something on the stack if we get to this point. + * [MSM]: NOT TRUE!!!!! so I added the test of fid below. + */ + + /* Allocate FID */ + + fid = txfid_queue_remove(hw); + + if ( fid == 0 ) { /* stack or queue was empty */ + return 4; + } + + /* now let's get the cmdlock */ + spin_lock(&hw->cmdlock); + + /* Copy descriptor+payload to FID */ + if (p80211_wep->data) { + result = hfa384x_copy_to_bap4(hw, HFA384x_BAP_PROC, fid, 0, + &txdesc, sizeof(txdesc), + p80211_wep->iv, sizeof(p80211_wep->iv), + p80211_wep->data, skb->len, + p80211_wep->icv, sizeof(p80211_wep->icv)); + } else { + result = hfa384x_copy_to_bap4(hw, HFA384x_BAP_PROC, fid, 0, + &txdesc, sizeof(txdesc), + skb->data, skb->len, + NULL, 0, NULL, 0); + } + + if ( result ) { + WLAN_LOG_DEBUG(1, + "copy_to_bap(%04x, %d, %d) failed, result=0x%x\n", + fid, + sizeof(txdesc), + skb->len, + result); + + /* put the fid back in the queue */ + txfid_queue_add(hw, fid); + + result = 3; + goto failed; + } + + /* Issue Tx command */ + result = hfa384x_cmd_transmit(hw, HFA384x_TXCMD_RECL, macq, fid); + + if ( result != 0 ) { + txfid_queue_add(hw, fid); + + WLAN_LOG_DEBUG(1,"cmd_tx(%04x) failed, result=%d\n", + fid, result); + result = 3; + goto failed; + } + + /* indicate we haven't any buffers, int_alloc will clear */ + result = txfid_queue_empty(hw); +failed: + + spin_unlock(&hw->cmdlock); + + DBFEXIT; + return result; +} + +/*---------------------------------------------------------------- +* hfa384x_interrupt +* +* Driver interrupt handler. +* +* Arguments: +* irq irq number +* dev_id pointer to the device +* regs registers +* +* Returns: +* nothing +* +* Side effects: +* May result in a frame being passed up the stack or an info +* frame being handled. +* +* Call context: +* Ummm, could it be interrupt? +----------------------------------------------------------------*/ +irqreturn_t hfa384x_interrupt(int irq, void *dev_id PT_REGS) +{ + int reg; + wlandevice_t *wlandev = (wlandevice_t*)dev_id; + hfa384x_t *hw = wlandev->priv; + int ev_read = 0; + DBFENTER; + + if (!wlandev || wlandev->hwremoved) + return IRQ_NONE; /* Not much we can do w/o hardware */ +#if (WLAN_HOSTIF == WLAN_PCMCIA) + if (hw->iobase == 0) /* XXX FIXME Properly */ + return IRQ_NONE; +#endif + + for (;;ev_read++) { + if (ev_read >= prism2_irq_evread_max) + break; + + /* Check swsupport reg magic # for card presence */ + reg = hfa384x_getreg(hw, HFA384x_SWSUPPORT0); + if ( reg != HFA384x_DRVR_MAGIC) { + WLAN_LOG_DEBUG(2, "irq=%d, no magic. Card removed?.\n", irq); + break; + } + + /* read the EvStat register for interrupt enabled events */ + reg = hfa384x_getreg(hw, HFA384x_EVSTAT); + + /* AND with the enabled interrupts */ + reg &= hfa384x_getreg(hw, HFA384x_INTEN); + + /* Handle the events */ + if ( HFA384x_EVSTAT_ISWTERR(reg) ){ + WLAN_LOG_ERROR( + "Error: WTERR interrupt received (unhandled).\n"); + hfa384x_setreg(hw, HFA384x_EVACK_WTERR_SET(1), + HFA384x_EVACK); + } + + if ( HFA384x_EVSTAT_ISINFDROP(reg) ){ + hfa384x_int_infdrop(wlandev); + hfa384x_setreg(hw, HFA384x_EVACK_INFDROP_SET(1), + HFA384x_EVACK); + } + + if (HFA384x_EVSTAT_ISBAP_OP(reg)) { + /* Disable the BAP interrupts */ + hfa384x_events_nobap(hw); + tasklet_schedule(&hw->bap_tasklet); + } + + if ( HFA384x_EVSTAT_ISALLOC(reg) ){ + hfa384x_int_alloc(wlandev); + hfa384x_setreg(hw, HFA384x_EVACK_ALLOC_SET(1), + HFA384x_EVACK); + } + + if ( HFA384x_EVSTAT_ISDTIM(reg) ){ + hfa384x_int_dtim(wlandev); + hfa384x_setreg(hw, HFA384x_EVACK_DTIM_SET(1), + HFA384x_EVACK); + } +#ifdef CMD_IRQ + if ( HFA384x_EVSTAT_ISCMD(reg) ){ + hfa384x_int_cmd(wlandev); + hfa384x_setreg(hw, HFA384x_EVACK_CMD_SET(1), + HFA384x_EVACK); + } +#endif + + /* allow the evstat to be updated after the evack */ + udelay(20); + } + + DBFEXIT; + return IRQ_HANDLED; +} + +#ifdef CMD_IRQ +/*---------------------------------------------------------------- +* hfa384x_int_cmd +* +* Handles command completion event. +* +* Arguments: +* wlandev wlan device structure +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +void hfa384x_int_cmd(wlandevice_t *wlandev) +{ + hfa384x_t *hw = wlandev->priv; + DBFENTER; + + // check to make sure it's the right command? + if (hw->cmddata) { + hw->cmddata->status = hfa384x_getreg(hw, HFA384x_STATUS); + hw->cmddata->resp0 = hfa384x_getreg(hw, HFA384x_RESP0); + hw->cmddata->resp1 = hfa384x_getreg(hw, HFA384x_RESP1); + hw->cmddata->resp2 = hfa384x_getreg(hw, HFA384x_RESP2); + } + hw->cmdflag = 1; + + printk(KERN_INFO "um. int_cmd\n"); + + wake_up_interruptible(&hw->cmdq); + + // XXXX perform a bap copy too? + + DBFEXIT; + return; +} +#endif + +/*---------------------------------------------------------------- +* hfa384x_int_dtim +* +* Handles the DTIM early warning event. +* +* Arguments: +* wlandev wlan device structure +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void hfa384x_int_dtim(wlandevice_t *wlandev) +{ +#if 0 + hfa384x_t *hw = wlandev->priv; +#endif + DBFENTER; + prism2sta_ev_dtim(wlandev); + DBFEXIT; + return; +} + + +/*---------------------------------------------------------------- +* hfa384x_int_infdrop +* +* Handles the InfDrop event. +* +* Arguments: +* wlandev wlan device structure +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void hfa384x_int_infdrop(wlandevice_t *wlandev) +{ +#if 0 + hfa384x_t *hw = wlandev->priv; +#endif + DBFENTER; + prism2sta_ev_infdrop(wlandev); + DBFEXIT; + return; +} + + +/*---------------------------------------------------------------- +* hfa384x_int_info +* +* Handles the Info event. +* +* Arguments: +* wlandev wlan device structure +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* tasklet +----------------------------------------------------------------*/ +static void hfa384x_int_info(wlandevice_t *wlandev) +{ + hfa384x_t *hw = wlandev->priv; + UINT16 reg; + hfa384x_InfFrame_t inf; + int result; + DBFENTER; + /* Retrieve the FID */ + reg = hfa384x_getreg(hw, HFA384x_INFOFID); + + /* Retrieve the length */ + result = hfa384x_copy_from_bap( hw, + HFA384x_BAP_INT, reg, 0, &inf.framelen, sizeof(UINT16)); + if ( result ) { + WLAN_LOG_DEBUG(1, + "copy_from_bap(0x%04x, 0, %d) failed, result=0x%x\n", + reg, sizeof(inf), result); + goto failed; + } + inf.framelen = hfa384x2host_16(inf.framelen); + + /* Retrieve the rest */ + result = hfa384x_copy_from_bap( hw, + HFA384x_BAP_INT, reg, sizeof(UINT16), + &(inf.infotype), inf.framelen * sizeof(UINT16)); + if ( result ) { + WLAN_LOG_DEBUG(1, + "copy_from_bap(0x%04x, 0, %d) failed, result=0x%x\n", + reg, sizeof(inf), result); + goto failed; + } + + prism2sta_ev_info(wlandev, &inf); +failed: + DBFEXIT; + return; +} + + +/*---------------------------------------------------------------- +* hfa384x_int_txexc +* +* Handles the TxExc event. A Transmit Exception event indicates +* that the MAC's TX process was unsuccessful - so the packet did +* not get transmitted. +* +* Arguments: +* wlandev wlan device structure +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* tasklet +----------------------------------------------------------------*/ +static void hfa384x_int_txexc(wlandevice_t *wlandev) +{ + hfa384x_t *hw = wlandev->priv; + UINT16 status; + UINT16 fid; + int result = 0; + DBFENTER; + /* Collect the status and display */ + fid = hfa384x_getreg(hw, HFA384x_TXCOMPLFID); + result = hfa384x_copy_from_bap(hw, HFA384x_BAP_INT, fid, 0, &status, sizeof(status)); + if ( result ) { + WLAN_LOG_DEBUG(1, + "copy_from_bap(0x%04x, 0, %d) failed, result=0x%x\n", + fid, sizeof(status), result); + goto failed; + } + status = hfa384x2host_16(status); + prism2sta_ev_txexc(wlandev, status); +failed: + DBFEXIT; + return; +} + + +/*---------------------------------------------------------------- +* hfa384x_int_tx +* +* Handles the Tx event. +* +* Arguments: +* wlandev wlan device structure +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* tasklet +----------------------------------------------------------------*/ +static void hfa384x_int_tx(wlandevice_t *wlandev) +{ + hfa384x_t *hw = wlandev->priv; + UINT16 fid; + UINT16 status; + int result = 0; + DBFENTER; + fid = hfa384x_getreg(hw, HFA384x_TXCOMPLFID); + result = hfa384x_copy_from_bap(hw, HFA384x_BAP_INT, fid, 0, &status, sizeof(status)); + if ( result ) { + WLAN_LOG_DEBUG(1, + "copy_from_bap(0x%04x, 0, %d) failed, result=0x%x\n", + fid, sizeof(status), result); + goto failed; + } + status = hfa384x2host_16(status); + prism2sta_ev_tx(wlandev, status); +failed: + DBFEXIT; + return; +} + +/*---------------------------------------------------------------- +* hfa384x_int_rx +* +* Handles the Rx event. +* +* Arguments: +* wlandev wlan device structure +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* tasklet +----------------------------------------------------------------*/ +static void hfa384x_int_rx(wlandevice_t *wlandev) +{ + hfa384x_t *hw = wlandev->priv; + UINT16 rxfid; + hfa384x_rx_frame_t rxdesc; + int result; + int hdrlen; + UINT16 fc; + p80211_rxmeta_t *rxmeta; + struct sk_buff *skb = NULL; + UINT8 *datap; + + DBFENTER; + + /* Get the FID */ + rxfid = hfa384x_getreg(hw, HFA384x_RXFID); + /* Get the descriptor (including headers) */ + result = hfa384x_copy_from_bap(hw, + HFA384x_BAP_INT, + rxfid, + 0, + &rxdesc, + sizeof(rxdesc)); + if ( result ) { + WLAN_LOG_DEBUG(1, + "copy_from_bap(0x%04x, %d, %d) failed, result=0x%x\n", + rxfid, + 0, + sizeof(rxdesc), + result); + goto done; + } + + /* Byte order convert once up front. */ + rxdesc.status = hfa384x2host_16(rxdesc.status); + rxdesc.time = hfa384x2host_32(rxdesc.time); + + /* drop errors and whatnot in promisc mode */ + if (( wlandev->netdev->flags & IFF_PROMISC ) && + (HFA384x_RXSTATUS_ISFCSERR(rxdesc.status) || + HFA384x_RXSTATUS_ISUNDECR(rxdesc.status))) + goto done; + + /* Now handle frame based on port# */ + switch( HFA384x_RXSTATUS_MACPORT_GET(rxdesc.status) ) + { + case 0: + + fc = ieee2host16(rxdesc.frame_control); + + /* If exclude and we receive an unencrypted, drop it */ + if ( (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED) && + !WLAN_GET_FC_ISWEP(fc)) { + goto done; + } + + hdrlen = p80211_headerlen(fc); + + /* Allocate the buffer, note CRC (aka FCS). pballoc */ + /* assumes there needs to be space for one */ + skb = dev_alloc_skb(hfa384x2host_16(rxdesc.data_len) + hdrlen + WLAN_CRC_LEN + 2); /* a little extra */ + + if ( ! skb ) { + WLAN_LOG_ERROR("alloc_skb failed.\n"); + goto done; + } + + skb->dev = wlandev->netdev; + + /* theoretically align the IP header on a 32-bit word. */ + if ( hdrlen == WLAN_HDR_A4_LEN ) + skb_reserve(skb, 2); + + /* Copy the 802.11 hdr to the buffer */ + datap = skb_put(skb, WLAN_HDR_A3_LEN); + memcpy(datap, &rxdesc.frame_control, WLAN_HDR_A3_LEN); + + /* Snag the A4 address if present */ + if (hdrlen == WLAN_HDR_A4_LEN) { + datap = skb_put(skb, WLAN_ADDR_LEN); + memcpy(datap, &rxdesc.address4, WLAN_HDR_A3_LEN); + } + + /* we can convert the data_len as we passed the original on */ + rxdesc.data_len = hfa384x2host_16(rxdesc.data_len); + + /* Copy the payload data to the buffer */ + if ( rxdesc.data_len > 0 ) { + datap = skb_put(skb, rxdesc.data_len); + result = hfa384x_copy_from_bap(hw, + HFA384x_BAP_INT, rxfid, HFA384x_RX_DATA_OFF, + datap, rxdesc.data_len); + if ( result ) { + WLAN_LOG_DEBUG(1, + "copy_from_bap(0x%04x, %d, %d) failed, result=0x%x\n", + rxfid, + HFA384x_RX_DATA_OFF, + rxdesc.data_len, + result); + goto failed; + } + } + /* the prism2 cards don't return the FCS */ + datap = skb_put(skb, WLAN_CRC_LEN); + memset (datap, 0xff, WLAN_CRC_LEN); + skb_reset_mac_header(skb); + + /* Attach the rxmeta, set some stuff */ + p80211skb_rxmeta_attach(wlandev, skb); + rxmeta = P80211SKB_RXMETA(skb); + rxmeta->mactime = rxdesc.time; + rxmeta->rxrate = rxdesc.rate; + rxmeta->signal = rxdesc.signal - hw->dbmadjust; + rxmeta->noise = rxdesc.silence - hw->dbmadjust; + + prism2sta_ev_rx(wlandev, skb); + goto done; + case 7: + + if ( ! HFA384x_RXSTATUS_ISFCSERR(rxdesc.status) ) { + hfa384x_int_rxmonitor( wlandev, rxfid, &rxdesc); + } else { + WLAN_LOG_DEBUG(3,"Received monitor frame: FCSerr set\n"); + } + goto done; + + default: + + WLAN_LOG_WARNING("Received frame on unsupported port=%d\n", + HFA384x_RXSTATUS_MACPORT_GET(rxdesc.status) ); + goto done; + } + + failed: + dev_kfree_skb(skb); + + done: + DBFEXIT; + return; +} + + +/*---------------------------------------------------------------- +* hfa384x_int_rxmonitor +* +* Helper function for int_rx. Handles monitor frames. +* Note that this function allocates space for the FCS and sets it +* to 0xffffffff. The hfa384x doesn't give us the FCS value but the +* higher layers expect it. 0xffffffff is used as a flag to indicate +* the FCS is bogus. +* +* Arguments: +* wlandev wlan device structure +* rxfid received FID +* rxdesc rx descriptor read from card in int_rx +* +* Returns: +* nothing +* +* Side effects: +* Allocates an skb and passes it up via the PF_PACKET interface. +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void hfa384x_int_rxmonitor( wlandevice_t *wlandev, UINT16 rxfid, + hfa384x_rx_frame_t *rxdesc) +{ + hfa384x_t *hw = wlandev->priv; + UINT hdrlen = 0; + UINT datalen = 0; + UINT skblen = 0; + UINT truncated = 0; + UINT8 *datap; + UINT16 fc; + struct sk_buff *skb; + + DBFENTER; + /* Don't forget the status, time, and data_len fields are in host order */ + /* Figure out how big the frame is */ + fc = ieee2host16(rxdesc->frame_control); + hdrlen = p80211_headerlen(fc); + datalen = hfa384x2host_16(rxdesc->data_len); + + /* Allocate an ind message+framesize skb */ + skblen = sizeof(p80211msg_lnxind_wlansniffrm_t) + + hdrlen + datalen + WLAN_CRC_LEN; + + /* sanity check the length */ + if ( skblen > + (sizeof(p80211msg_lnxind_wlansniffrm_t) + + WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN) ) { + WLAN_LOG_DEBUG(1, "overlen frm: len=%d\n", + skblen - sizeof(p80211msg_lnxind_wlansniffrm_t)); + } + + if ( (skb = dev_alloc_skb(skblen)) == NULL ) { + WLAN_LOG_ERROR("alloc_skb failed trying to allocate %d bytes\n", skblen); + return; + } + + /* only prepend the prism header if in the right mode */ + if ((wlandev->netdev->type == ARPHRD_IEEE80211_PRISM) && + (hw->sniffhdr == 0)) { + p80211msg_lnxind_wlansniffrm_t *msg; + datap = skb_put(skb, sizeof(p80211msg_lnxind_wlansniffrm_t)); + msg = (p80211msg_lnxind_wlansniffrm_t*) datap; + + /* Initialize the message members */ + msg->msgcode = DIDmsg_lnxind_wlansniffrm; + msg->msglen = sizeof(p80211msg_lnxind_wlansniffrm_t); + strcpy(msg->devname, wlandev->name); + + msg->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime; + msg->hosttime.status = 0; + msg->hosttime.len = 4; + msg->hosttime.data = jiffies; + + msg->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime; + msg->mactime.status = 0; + msg->mactime.len = 4; + msg->mactime.data = rxdesc->time * 1000; + + msg->channel.did = DIDmsg_lnxind_wlansniffrm_channel; + msg->channel.status = 0; + msg->channel.len = 4; + msg->channel.data = hw->sniff_channel; + + msg->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi; + msg->rssi.status = P80211ENUM_msgitem_status_no_value; + msg->rssi.len = 4; + msg->rssi.data = 0; + + msg->sq.did = DIDmsg_lnxind_wlansniffrm_sq; + msg->sq.status = P80211ENUM_msgitem_status_no_value; + msg->sq.len = 4; + msg->sq.data = 0; + + msg->signal.did = DIDmsg_lnxind_wlansniffrm_signal; + msg->signal.status = 0; + msg->signal.len = 4; + msg->signal.data = rxdesc->signal; + + msg->noise.did = DIDmsg_lnxind_wlansniffrm_noise; + msg->noise.status = 0; + msg->noise.len = 4; + msg->noise.data = rxdesc->silence; + + msg->rate.did = DIDmsg_lnxind_wlansniffrm_rate; + msg->rate.status = 0; + msg->rate.len = 4; + msg->rate.data = rxdesc->rate / 5; /* set to 802.11 units */ + + msg->istx.did = DIDmsg_lnxind_wlansniffrm_istx; + msg->istx.status = 0; + msg->istx.len = 4; + msg->istx.data = P80211ENUM_truth_false; + + msg->frmlen.did = DIDmsg_lnxind_wlansniffrm_frmlen; + msg->frmlen.status = 0; + msg->frmlen.len = 4; + msg->frmlen.data = hdrlen + datalen + WLAN_CRC_LEN; + } else if ((wlandev->netdev->type == ARPHRD_IEEE80211_PRISM) && + (hw->sniffhdr != 0)) { + p80211_caphdr_t *caphdr; + /* The NEW header format! */ + datap = skb_put(skb, sizeof(p80211_caphdr_t)); + caphdr = (p80211_caphdr_t*) datap; + + caphdr->version = htonl(P80211CAPTURE_VERSION); + caphdr->length = htonl(sizeof(p80211_caphdr_t)); + caphdr->mactime = __cpu_to_be64(rxdesc->time); + caphdr->hosttime = __cpu_to_be64(jiffies); + caphdr->phytype = htonl(4); /* dss_dot11_b */ + caphdr->channel = htonl(hw->sniff_channel); + caphdr->datarate = htonl(rxdesc->rate); + caphdr->antenna = htonl(0); /* unknown */ + caphdr->priority = htonl(0); /* unknown */ + caphdr->ssi_type = htonl(3); /* rssi_raw */ + caphdr->ssi_signal = htonl(rxdesc->signal); + caphdr->ssi_noise = htonl(rxdesc->silence); + caphdr->preamble = htonl(0); /* unknown */ + caphdr->encoding = htonl(1); /* cck */ + } + /* Copy the 802.11 header to the skb (ctl frames may be less than a full header) */ + datap = skb_put(skb, hdrlen); + memcpy( datap, &(rxdesc->frame_control), hdrlen); + + /* If any, copy the data from the card to the skb */ + if ( datalen > 0 ) + { + /* Truncate the packet if the user wants us to */ + UINT dataread = datalen; + if(hw->sniff_truncate > 0 && dataread > hw->sniff_truncate) { + dataread = hw->sniff_truncate; + truncated = 1; + } + + datap = skb_put(skb, dataread); + hfa384x_copy_from_bap(hw, + HFA384x_BAP_INT, rxfid, HFA384x_RX_DATA_OFF, + datap, dataread); + + /* check for unencrypted stuff if WEP bit set. */ + if (*(datap - hdrlen + 1) & 0x40) // wep set + if ((*(datap) == 0xaa) && (*(datap+1) == 0xaa)) + *(datap - hdrlen + 1) &= 0xbf; // clear wep; it's the 802.2 header! + } + + if (!truncated && hw->sniff_fcs) { + /* Set the FCS */ + datap = skb_put(skb, WLAN_CRC_LEN); + memset( datap, 0xff, WLAN_CRC_LEN); + } + + /* pass it back up */ + prism2sta_ev_rx(wlandev, skb); + + DBFEXIT; + return; +} + +/*---------------------------------------------------------------- +* hfa384x_int_alloc +* +* Handles the Alloc event. +* +* Arguments: +* wlandev wlan device structure +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void hfa384x_int_alloc(wlandevice_t *wlandev) +{ + hfa384x_t *hw = wlandev->priv; + UINT16 fid; + INT16 result; + + DBFENTER; + + /* Handle the reclaimed FID */ + /* collect the FID and push it onto the stack */ + fid = hfa384x_getreg(hw, HFA384x_ALLOCFID); + + if ( fid != hw->infofid ) { /* It's a transmit fid */ + WLAN_LOG_DEBUG(5, "int_alloc(%#x)\n", fid); + result = txfid_queue_add(hw, fid); + if (result != -1) { + prism2sta_ev_alloc(wlandev); + WLAN_LOG_DEBUG(5, "q_add.\n"); + } else { + WLAN_LOG_DEBUG(5, "q_full.\n"); + } + } else { + /* unlock the info fid */ + up(&hw->infofid_sem); + } + + DBFEXIT; + return; +} + + +/*---------------------------------------------------------------- +* hfa384x_drvr_handover +* +* Sends a handover notification to the MAC. +* +* Arguments: +* hw device structure +* addr address of station that's left +* +* Returns: +* zero success. +* -ERESTARTSYS received signal while waiting for semaphore. +* -EIO failed to write to bap, or failed in cmd. +* +* Side effects: +* +* Call context: +* process thread, NOTE: this call may block on a semaphore! +----------------------------------------------------------------*/ +int hfa384x_drvr_handover( hfa384x_t *hw, UINT8 *addr) +{ + int result = 0; + hfa384x_HandoverAddr_t rec; + UINT len; + DBFENTER; + + /* Acquire the infofid */ + if ( down_interruptible(&hw->infofid_sem) ) { + result = -ERESTARTSYS; + goto failed; + } + + /* Set up the record */ + len = sizeof(hfa384x_HandoverAddr_t); + rec.framelen = host2hfa384x_16(len/2 - 1); + rec.infotype = host2hfa384x_16(HFA384x_IT_HANDOVERADDR); + memcpy(rec.handover_addr, addr, sizeof(rec.handover_addr)); + + /* Issue the command */ + result = hfa384x_cmd_notify(hw, 1, hw->infofid, &rec, len); + + if ( result != 0 ) { + WLAN_LOG_DEBUG(1,"cmd_notify(%04x) failed, result=%d", + hw->infofid, result); + result = -EIO; + goto failed; + } + +failed: + DBFEXIT; + return result; +} + +void hfa384x_tx_timeout(wlandevice_t *wlandev) +{ + DBFENTER; + + WLAN_LOG_WARNING("Implement me.\n"); + + DBFEXIT; +} + +/* Handles all "rx" BAP operations */ +static void hfa384x_bap_tasklet(unsigned long data) +{ + hfa384x_t *hw = (hfa384x_t *) data; + wlandevice_t *wlandev = hw->wlandev; + int counter = prism2_irq_evread_max; + int reg; + + DBFENTER; + + while (counter-- > 0) { + /* Get interrupt register */ + reg = hfa384x_getreg(hw, HFA384x_EVSTAT); + + if ((reg == 0xffff) || + !(reg & HFA384x_INT_BAP_OP)) { + break; + } + + if ( HFA384x_EVSTAT_ISINFO(reg) ){ + hfa384x_int_info(wlandev); + hfa384x_setreg(hw, HFA384x_EVACK_INFO_SET(1), + HFA384x_EVACK); + } + if ( HFA384x_EVSTAT_ISTXEXC(reg) ){ + hfa384x_int_txexc(wlandev); + hfa384x_setreg(hw, HFA384x_EVACK_TXEXC_SET(1), + HFA384x_EVACK); + } + if ( HFA384x_EVSTAT_ISTX(reg) ){ + hfa384x_int_tx(wlandev); + hfa384x_setreg(hw, HFA384x_EVACK_TX_SET(1), + HFA384x_EVACK); + } + if ( HFA384x_EVSTAT_ISRX(reg) ){ + hfa384x_int_rx(wlandev); + hfa384x_setreg(hw, HFA384x_EVACK_RX_SET(1), + HFA384x_EVACK); + } + } + + /* re-enable interrupts */ + hfa384x_events_all(hw); + + DBFEXIT; +} --- linux-2.6.27.orig/ubuntu/misc/wireless/prism2_usb/prism2_usb.c +++ linux-2.6.27/ubuntu/misc/wireless/prism2_usb/prism2_usb.c @@ -0,0 +1,367 @@ +#define WLAN_HOSTIF WLAN_USB +#include "hfa384x_usb.c" +#include "prism2mgmt.c" +#include "prism2mib.c" +#include "prism2sta.c" + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) +#error "prism2_usb requires at least a 2.4.x kernel!" +#endif + +#define PRISM_USB_DEVICE(vid, pid, name) \ + USB_DEVICE(vid, pid), \ + .driver_info = (unsigned long) name + +static struct usb_device_id usb_prism_tbl[] = { + {PRISM_USB_DEVICE(0x0707, 0xee04, "Intersil Americas USB 802.11b WLAN DEVICE")}, + {PRISM_USB_DEVICE(0x04bb, 0x0922, "IOData AirPort WN-B11/USBS")}, + {PRISM_USB_DEVICE(0x07aa, 0x0012, "Corega Wireless LAN USB Stick-11")}, + {PRISM_USB_DEVICE(0x09aa, 0x3642, "Prism2.x 11Mbps WLAN USB Adapter")}, + {PRISM_USB_DEVICE(0x1668, 0x0408, "Actiontec Prism2.5 11Mbps WLAN USB Adapter")}, + {PRISM_USB_DEVICE(0x1668, 0x0421, "Actiontec Prism2.5 11Mbps WLAN USB Adapter")}, + {PRISM_USB_DEVICE(0x1915, 0x2236, "Linksys WUSB11v3.0 11Mbps WLAN USB Adapter")}, + {PRISM_USB_DEVICE(0x066b, 0x2212, "Linksys WUSB11v2.5 11Mbps WLAN USB Adapter")}, + {PRISM_USB_DEVICE(0x066b, 0x2213, "Linksys WUSB12v1.1 11Mbps WLAN USB Adapter")}, + {PRISM_USB_DEVICE(0x067c, 0x1022, "Siemens SpeedStream 1022 11Mbps WLAN USB Adapter")}, + {PRISM_USB_DEVICE(0x049f, 0x0033, "Compaq/Intel W100 PRO/Wireless 11Mbps multiport WLAN Adapter")}, + {PRISM_USB_DEVICE(0x0411, 0x0016, "Melco WLI-USB-S11 11Mbps WLAN Adapter")}, + {PRISM_USB_DEVICE(0x08de, 0x7a01, "PRISM25 IEEE 802.11 Mini USB Adapter")}, + {PRISM_USB_DEVICE(0x8086, 0x1111, "Intel PRO/Wireless 2011B LAN USB Adapter")}, + {PRISM_USB_DEVICE(0x0d8e, 0x7a01, "PRISM25 IEEE 802.11 Mini USB Adapter")}, + {PRISM_USB_DEVICE(0x045e, 0x006e, "Microsoft MN510 Wireless USB Adapter")}, + {PRISM_USB_DEVICE(0x0967, 0x0204, "Acer Warplink USB Adapter")}, + {PRISM_USB_DEVICE(0x0cde, 0x0002, "Z-Com 725/726 Prism2.5 USB/USB Integrated")}, + {PRISM_USB_DEVICE(0x0cde, 0x0005, "Z-Com Xl735 Wireless 802.11b USB Adapter")}, + {PRISM_USB_DEVICE(0x413c, 0x8100, "Dell TrueMobile 1180 Wireless USB Adapter")}, + {PRISM_USB_DEVICE(0x0b3b, 0x1601, "ALLNET 0193 11Mbps WLAN USB Adapter")}, + {PRISM_USB_DEVICE(0x0b3b, 0x1602, "ZyXEL ZyAIR B200 Wireless USB Adapter")}, + {PRISM_USB_DEVICE(0x0baf, 0x00eb, "USRobotics USR1120 Wireless USB Adapter")}, + {PRISM_USB_DEVICE(0x0411, 0x0027, "Melco WLI-USB-KS11G 11Mbps WLAN Adapter")}, + {PRISM_USB_DEVICE(0x04f1, 0x3009, "JVC MP-XP7250 Builtin USB WLAN Adapter")}, + {PRISM_USB_DEVICE(0x0846, 0x4110, "NetGear MA111")}, + {PRISM_USB_DEVICE(0x03f3, 0x0020, "Adaptec AWN-8020 USB WLAN Adapter")}, +// {PRISM_USB_DEVICE(0x0ace, 0x1201, "ZyDAS ZD1201 Wireless USB Adapter")}, + {PRISM_USB_DEVICE(0x2821, 0x3300, "ASUS-WL140 Wireless USB Adapter")}, + {PRISM_USB_DEVICE(0x2001, 0x3700, "DWL-122 Wireless USB Adapter")}, + {PRISM_USB_DEVICE(0x2001, 0x3702, "DWL-120 Rev F Wireless USB Adapter")}, + {PRISM_USB_DEVICE(0x50c2, 0x4013, "Averatec USB WLAN Adapter")}, + {PRISM_USB_DEVICE(0x2c02, 0x14ea, "Planex GW-US11H WLAN USB Adapter")}, + {PRISM_USB_DEVICE(0x124a, 0x168b, "Airvast PRISM3 WLAN USB Adapter")}, + {PRISM_USB_DEVICE(0x083a, 0x3503, "T-Sinus 111 USB WLAN Adapter")}, + {PRISM_USB_DEVICE(0x2821, 0x3300, "Hawking HighDB USB Adapter")}, + {PRISM_USB_DEVICE(0x0411, 0x0044, "Melco WLI-USB-KB11 11Mbps WLAN Adapter")}, + {PRISM_USB_DEVICE(0x1668, 0x6106, "ROPEX FreeLan 802.11b USB Adapter")}, + {PRISM_USB_DEVICE(0x124a, 0x4017, "Pheenet WL-503IA 802.11b USB Adapter")}, + {PRISM_USB_DEVICE(0x0bb2, 0x0302, "Ambit Microsystems Corp.")}, + {PRISM_USB_DEVICE(0x9016, 0x182d, "Sitecom WL-022 802.11b USB Adapter")}, + {PRISM_USB_DEVICE(0x0543, 0x0f01, "ViewSonic Airsync USB Adapter 11Mbps (Prism2.5)")}, + { /* terminator */ } +}; + +MODULE_DEVICE_TABLE(usb, usb_prism_tbl); + +/*---------------------------------------------------------------- +* prism2sta_probe_usb +* +* Probe routine called by the USB subsystem. +* +* Arguments: +* dev ptr to the usb_device struct +* ifnum interface number being offered +* +* Returns: +* NULL - we're not claiming the device+interface +* non-NULL - we are claiming the device+interface and +* this is a ptr to the data we want back +* when disconnect is called. +* +* Side effects: +* +* Call context: +* I'm not sure, assume it's interrupt. +* +----------------------------------------------------------------*/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +static void __devinit *prism2sta_probe_usb( + struct usb_device *dev, + unsigned int ifnum, + const struct usb_device_id *id) +#else +static int prism2sta_probe_usb( + struct usb_interface *interface, + const struct usb_device_id *id) +#endif +{ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + struct usb_interface *interface; +#else + struct usb_device *dev; +#endif + + wlandevice_t *wlandev = NULL; + hfa384x_t *hw = NULL; + int result = 0; + + DBFENTER; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + interface = &dev->actconfig->interface[ifnum]; +#else + dev = interface_to_usbdev(interface); +#endif + + + if ((wlandev = create_wlan()) == NULL) { + WLAN_LOG_ERROR("%s: Memory allocation failure.\n", dev_info); + result = -EIO; + goto failed; + } + hw = wlandev->priv; + + if ( wlan_setup(wlandev) != 0 ) { + WLAN_LOG_ERROR("%s: wlan_setup() failed.\n", dev_info); + result = -EIO; + goto failed; + } + + /* Initialize the hw data */ + hfa384x_create(hw, dev); + hw->wlandev = wlandev; + + SET_MODULE_OWNER(wlandev->netdev); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) + SET_NETDEV_DEV(wlandev->netdev, &(interface->dev)); +#endif + + /* Do a chip-level reset on the MAC */ + if (prism2_doreset) { + result = hfa384x_corereset(hw, + prism2_reset_holdtime, + prism2_reset_settletime, 0); + if (result != 0) { + hfa384x_destroy(hw); + result = -EIO; + WLAN_LOG_ERROR( + "%s: hfa384x_corereset() failed.\n", + dev_info); + goto failed; + } + } + +#ifndef NEW_MODULE_CODE + usb_inc_dev_use(dev); +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) + usb_get_dev(dev); +#endif + + wlandev->msdstate = WLAN_MSD_HWPRESENT; + + /* Register the wlandev, this gets us a name and registers the + * linux netdevice. + */ + if ( register_wlandev(wlandev) != 0 ) { + WLAN_LOG_ERROR("%s: register_wlandev() failed.\n", dev_info); + result = -EIO; + goto failed; + } + + if (wlan_wext_write) + prism2sta_ifstate(wlandev, P80211ENUM_ifstate_enable); + + goto done; + + failed: + if (wlandev) kfree(wlandev); + if (hw) kfree(hw); + wlandev = NULL; + + done: + DBFEXIT; + + p80211_allow_ioctls(wlandev); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + return wlandev; +#else + usb_set_intfdata(interface, wlandev); + return result; +#endif +} + + +/*---------------------------------------------------------------- +* prism2sta_disconnect_usb +* +* Called when a device previously claimed by probe is removed +* from the USB. +* +* Arguments: +* dev ptr to the usb_device struct +* ptr ptr returned by probe() when the device +* was claimed. +* +* Returns: +* Nothing +* +* Side effects: +* +* Call context: +* process +----------------------------------------------------------------*/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +static void __devexit +prism2sta_disconnect_usb(struct usb_device *dev, void *ptr) +#else +static void +prism2sta_disconnect_usb(struct usb_interface *interface) +#endif +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) + wlandevice_t *wlandev; +#else + wlandevice_t *wlandev = (wlandevice_t*)ptr; +#endif + + DBFENTER; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) + wlandev = (wlandevice_t *) usb_get_intfdata(interface); +#endif + + if ( wlandev != NULL ) { + LIST_HEAD(cleanlist); + struct list_head *entry; + struct list_head *temp; + unsigned long flags; + + hfa384x_t *hw = wlandev->priv; + + if (!hw) + goto exit; + + spin_lock_irqsave(&hw->ctlxq.lock, flags); + + p80211netdev_hwremoved(wlandev); + list_splice_init(&hw->ctlxq.reapable, &cleanlist); + list_splice_init(&hw->ctlxq.completing, &cleanlist); + list_splice_init(&hw->ctlxq.pending, &cleanlist); + list_splice_init(&hw->ctlxq.active, &cleanlist); + + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + + /* There's no hardware to shutdown, but the driver + * might have some tasks or tasklets that must be + * stopped before we can tear everything down. + */ + prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable); + + del_singleshot_timer_sync(&hw->throttle); + del_singleshot_timer_sync(&hw->reqtimer); + del_singleshot_timer_sync(&hw->resptimer); + + /* Unlink all the URBs. This "removes the wheels" + * from the entire CTLX handling mechanism. + */ + usb_kill_urb(&hw->rx_urb); + usb_kill_urb(&hw->tx_urb); + usb_kill_urb(&hw->ctlx_urb); + + tasklet_kill(&hw->completion_bh); + tasklet_kill(&hw->reaper_bh); + + flush_scheduled_work(); + + /* Now we complete any outstanding commands + * and tell everyone who is waiting for their + * responses that we have shut down. + */ + list_for_each(entry, &cleanlist) { + hfa384x_usbctlx_t *ctlx; + + ctlx = list_entry(entry, hfa384x_usbctlx_t, list); + complete(&ctlx->done); + } + + /* Give any outstanding synchronous commands + * a chance to complete. All they need to do + * is "wake up", so that's easy. + * (I'd like a better way to do this, really.) + */ + msleep(100); + + /* Now delete the CTLXs, because no-one else can now. */ + list_for_each_safe(entry, temp, &cleanlist) { + hfa384x_usbctlx_t *ctlx; + + ctlx = list_entry(entry, hfa384x_usbctlx_t, list); + kfree(ctlx); + } + + /* Unhook the wlandev */ + unregister_wlandev(wlandev); + wlan_unsetup(wlandev); + +#ifndef NEW_MODULE_CODE + usb_dec_dev_use(hw->usb); +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) + usb_put_dev(hw->usb); +#endif + + hfa384x_destroy(hw); + kfree(hw); + + kfree(wlandev); + } + + exit: + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) + usb_set_intfdata(interface, NULL); +#endif + DBFEXIT; +} + + +static struct usb_driver prism2_usb_driver = { +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,19)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) + .owner = THIS_MODULE, +#endif + .name = "prism2_usb", + .probe = prism2sta_probe_usb, + .disconnect = prism2sta_disconnect_usb, + .id_table = usb_prism_tbl, + /* fops, minor? */ +}; + +#ifdef MODULE + +static int __init prism2usb_init(void) +{ + DBFENTER; + + WLAN_LOG_NOTICE("%s Loaded\n", version); + WLAN_LOG_NOTICE("dev_info is: %s\n", dev_info); + + /* This call will result in calls to prism2sta_probe_usb. */ + return usb_register(&prism2_usb_driver); + + DBFEXIT; +}; + +static void __exit prism2usb_cleanup(void) +{ + DBFENTER; + + usb_deregister(&prism2_usb_driver); + + printk(KERN_NOTICE "%s Unloaded\n", version); + + DBFEXIT; +}; + +module_init(prism2usb_init); +module_exit(prism2usb_cleanup); + +#endif // module --- linux-2.6.27.orig/ubuntu/misc/wireless/prism2_usb/Makefile +++ linux-2.6.27/ubuntu/misc/wireless/prism2_usb/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_PRISM2_USB) += prism2_usb.o + +EXTRA_CFLAGS += -I$(src)/../p80211 -I$(src) --- linux-2.6.27.orig/ubuntu/misc/wireless/prism2_usb/prism2sta.c +++ linux-2.6.27/ubuntu/misc/wireless/prism2_usb/prism2sta.c @@ -0,0 +1,2502 @@ +/* src/prism2/driver/prism2sta.c +* +* Implements the station functionality for prism2 +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* This file implements the module and linux pcmcia routines for the +* prism2 driver. +* +* -------------------------------------------------------------------- +*/ + +/*================================================================*/ +/* System Includes */ +#define WLAN_DBVAR prism2_debug + +#include + + +#include + +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,25)) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#include +#else +#include +#endif + +#include +#include +#include +#include + +#if (WLAN_HOSTIF == WLAN_PCMCIA) +#include +#include +#include +#include +#include +#include +#endif + +#include + +#if ((WLAN_HOSTIF == WLAN_PLX) || (WLAN_HOSTIF == WLAN_PCI)) +#include +#include +#endif + +/*================================================================*/ +/* Project Includes */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*================================================================*/ +/* Local Constants */ + +/*================================================================*/ +/* Local Macros */ + +/*================================================================*/ +/* Local Types */ + +/*================================================================*/ +/* Local Static Definitions */ + +#if (WLAN_HOSTIF == WLAN_PCMCIA) +#define DRIVER_SUFFIX "_cs" +#elif (WLAN_HOSTIF == WLAN_PLX) +#define DRIVER_SUFFIX "_plx" +typedef char* dev_info_t; +#elif (WLAN_HOSTIF == WLAN_PCI) +#define DRIVER_SUFFIX "_pci" +typedef char* dev_info_t; +#elif (WLAN_HOSTIF == WLAN_USB) +#define DRIVER_SUFFIX "_usb" +typedef char* dev_info_t; +#else +#error "HOSTIF unsupported or undefined!" +#endif + +static char *version = "prism2" DRIVER_SUFFIX ".o: " WLAN_RELEASE; +static dev_info_t dev_info = "prism2" DRIVER_SUFFIX; + +#if (WLAN_HOSTIF == WLAN_PLX || WLAN_HOSTIF == WLAN_PCI) +#ifdef CONFIG_PM +static int prism2sta_suspend_pci(struct pci_dev *pdev, pm_message_t state); +static int prism2sta_resume_pci(struct pci_dev *pdev); +#endif +#endif + +#if (WLAN_HOSTIF == WLAN_PCI) + +#endif /* WLAN_PCI */ + +static wlandevice_t *create_wlan(void); + +/*----------------------------------------------------------------*/ +/* --Module Parameters */ + +int prism2_reset_holdtime=30; /* Reset hold time in ms */ +int prism2_reset_settletime=100; /* Reset settle time in ms */ + +#if (WLAN_HOSTIF == WLAN_USB) +static int prism2_doreset=0; /* Do a reset at init? */ +#else +static int prism2_doreset=1; /* Do a reset at init? */ +int prism2_bap_timeout=1000; /* BAP timeout */ +int prism2_irq_evread_max=20; /* Maximum number of + * ev_reads (loops) + * in irq handler + */ +#endif + +#ifdef WLAN_INCLUDE_DEBUG +int prism2_debug=0; +module_param( prism2_debug, int, 0644); +MODULE_PARM_DESC(prism2_debug, "prism2 debugging"); +#endif + +module_param( prism2_doreset, int, 0644); +MODULE_PARM_DESC(prism2_doreset, "Issue a reset on initialization"); + +module_param( prism2_reset_holdtime, int, 0644); +MODULE_PARM_DESC( prism2_reset_holdtime, "reset hold time in ms"); +module_param( prism2_reset_settletime, int, 0644); +MODULE_PARM_DESC( prism2_reset_settletime, "reset settle time in ms"); + +#if (WLAN_HOSTIF != WLAN_USB) +module_param( prism2_bap_timeout, int, 0644); +MODULE_PARM_DESC(prism2_bap_timeout, "BufferAccessPath Timeout in 10*n us"); +module_param( prism2_irq_evread_max, int, 0644); +MODULE_PARM_DESC( prism2_irq_evread_max, "Maximim number of event reads in interrupt handler"); +#endif + +MODULE_LICENSE("Dual MPL/GPL"); + +/*================================================================*/ +/* Local Function Declarations */ + +static int prism2sta_open(wlandevice_t *wlandev); +static int prism2sta_close(wlandevice_t *wlandev); +static void prism2sta_reset(wlandevice_t *wlandev ); +static int prism2sta_txframe(wlandevice_t *wlandev, struct sk_buff *skb, p80211_hdr_t *p80211_hdr, p80211_metawep_t *p80211_wep); +static int prism2sta_mlmerequest(wlandevice_t *wlandev, p80211msg_t *msg); +static int prism2sta_getcardinfo(wlandevice_t *wlandev); +static int prism2sta_globalsetup(wlandevice_t *wlandev); +static int prism2sta_setmulticast(wlandevice_t *wlandev, + netdevice_t *dev); + +static void prism2sta_inf_handover( + wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); +static void prism2sta_inf_tallies( + wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); +static void prism2sta_inf_hostscanresults( + wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); +static void prism2sta_inf_scanresults( + wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); +static void prism2sta_inf_chinforesults( + wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); +static void prism2sta_inf_linkstatus( + wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); +static void prism2sta_inf_assocstatus( + wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); +static void prism2sta_inf_authreq( + wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); +static void prism2sta_inf_authreq_defer( + wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); +static void prism2sta_inf_psusercnt( + wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); + +#ifdef CONFIG_PROC_FS +static int +prism2sta_proc_read( + char *page, + char **start, + off_t offset, + int count, + int *eof, + void *data); +#endif + +/*================================================================*/ +/* Function Definitions */ + +/*---------------------------------------------------------------- +* dmpmem +* +* Debug utility function to dump memory to the kernel debug log. +* +* Arguments: +* buf ptr data we want dumped +* len length of data +* +* Returns: +* nothing +* Side effects: +* +* Call context: +* process thread +* interrupt +----------------------------------------------------------------*/ +inline void dmpmem(void *buf, int n) +{ + int c; + for ( c= 0; c < n; c++) { + if ( (c % 16) == 0 ) printk(KERN_DEBUG"dmp[%d]: ", c); + printk("%02x ", ((UINT8*)buf)[c]); + if ( (c % 16) == 15 ) printk("\n"); + } + if ( (c % 16) != 0 ) printk("\n"); +} + + +/*---------------------------------------------------------------- +* prism2sta_open +* +* WLAN device open method. Called from p80211netdev when kernel +* device open (start) method is called in response to the +* SIOCSIIFFLAGS ioctl changing the flags bit IFF_UP +* from clear to set. +* +* Arguments: +* wlandev wlan device structure +* +* Returns: +* 0 success +* >0 f/w reported error +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +static int prism2sta_open(wlandevice_t *wlandev) +{ + DBFENTER; + +#ifdef ANCIENT_MODULE_CODE + MOD_INC_USE_COUNT; +#endif + + /* We don't currently have to do anything else. + * The setup of the MAC should be subsequently completed via + * the mlme commands. + * Higher layers know we're ready from dev->start==1 and + * dev->tbusy==0. Our rx path knows to pass up received/ + * frames because of dev->flags&IFF_UP is true. + */ + + DBFEXIT; + return 0; +} + + +/*---------------------------------------------------------------- +* prism2sta_close +* +* WLAN device close method. Called from p80211netdev when kernel +* device close method is called in response to the +* SIOCSIIFFLAGS ioctl changing the flags bit IFF_UP +* from set to clear. +* +* Arguments: +* wlandev wlan device structure +* +* Returns: +* 0 success +* >0 f/w reported error +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +static int prism2sta_close(wlandevice_t *wlandev) +{ + DBFENTER; + +#ifdef ANCIENT_MODULE_CODE + MOD_DEC_USE_COUNT; +#endif + + /* We don't currently have to do anything else. + * Higher layers know we're not ready from dev->start==0 and + * dev->tbusy==1. Our rx path knows to not pass up received + * frames because of dev->flags&IFF_UP is false. + */ + + DBFEXIT; + return 0; +} + + +/*---------------------------------------------------------------- +* prism2sta_reset +* +* Not currently implented. +* +* Arguments: +* wlandev wlan device structure +* none +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +static void prism2sta_reset(wlandevice_t *wlandev ) +{ + DBFENTER; + DBFEXIT; + return; +} + + +/*---------------------------------------------------------------- +* prism2sta_txframe +* +* Takes a frame from p80211 and queues it for transmission. +* +* Arguments: +* wlandev wlan device structure +* pb packet buffer struct. Contains an 802.11 +* data frame. +* p80211_hdr points to the 802.11 header for the packet. +* Returns: +* 0 Success and more buffs available +* 1 Success but no more buffs +* 2 Allocation failure +* 4 Buffer full or queue busy +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +static int prism2sta_txframe(wlandevice_t *wlandev, struct sk_buff *skb, + p80211_hdr_t *p80211_hdr, + p80211_metawep_t *p80211_wep) +{ + hfa384x_t *hw = (hfa384x_t *)wlandev->priv; + int result; + DBFENTER; + + /* If necessary, set the 802.11 WEP bit */ + if ((wlandev->hostwep & (HOSTWEP_PRIVACYINVOKED | HOSTWEP_ENCRYPT)) == HOSTWEP_PRIVACYINVOKED) { + p80211_hdr->a3.fc |= host2ieee16(WLAN_SET_FC_ISWEP(1)); + } + + result = hfa384x_drvr_txframe(hw, skb, p80211_hdr, p80211_wep); + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* prism2sta_mlmerequest +* +* wlan command message handler. All we do here is pass the message +* over to the prism2sta_mgmt_handler. +* +* Arguments: +* wlandev wlan device structure +* msg wlan command message +* Returns: +* 0 success +* <0 successful acceptance of message, but we're +* waiting for an async process to finish before +* we're done with the msg. When the asynch +* process is done, we'll call the p80211 +* function p80211req_confirm() . +* >0 An error occurred while we were handling +* the message. +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +static int prism2sta_mlmerequest(wlandevice_t *wlandev, p80211msg_t *msg) +{ + hfa384x_t *hw = (hfa384x_t *)wlandev->priv; + + int result = 0; + DBFENTER; + + switch( msg->msgcode ) + { + case DIDmsg_dot11req_mibget : + WLAN_LOG_DEBUG(2,"Received mibget request\n"); + result = prism2mgmt_mibset_mibget(wlandev, msg); + break; + case DIDmsg_dot11req_mibset : + WLAN_LOG_DEBUG(2,"Received mibset request\n"); + result = prism2mgmt_mibset_mibget(wlandev, msg); + break; + case DIDmsg_dot11req_powermgmt : + WLAN_LOG_DEBUG(2,"Received powermgmt request\n"); + result = prism2mgmt_powermgmt(wlandev, msg); + break; + case DIDmsg_dot11req_scan : + WLAN_LOG_DEBUG(2,"Received scan request\n"); + result = prism2mgmt_scan(wlandev, msg); + break; + case DIDmsg_dot11req_scan_results : + WLAN_LOG_DEBUG(2,"Received scan_results request\n"); + result = prism2mgmt_scan_results(wlandev, msg); + break; + case DIDmsg_dot11req_join : + WLAN_LOG_DEBUG(2,"Received join request\n"); + result = prism2mgmt_join(wlandev, msg); + break; + case DIDmsg_dot11req_authenticate : + WLAN_LOG_DEBUG(2,"Received authenticate request\n"); + result = prism2mgmt_authenticate(wlandev, msg); + break; + case DIDmsg_dot11req_deauthenticate : + WLAN_LOG_DEBUG(2,"Received mlme deauthenticate request\n"); + result = prism2mgmt_deauthenticate(wlandev, msg); + break; + case DIDmsg_dot11req_associate : + WLAN_LOG_DEBUG(2,"Received mlme associate request\n"); + result = prism2mgmt_associate(wlandev, msg); + break; + case DIDmsg_dot11req_reassociate : + WLAN_LOG_DEBUG(2,"Received mlme reassociate request\n"); + result = prism2mgmt_reassociate(wlandev, msg); + break; + case DIDmsg_dot11req_disassociate : + WLAN_LOG_DEBUG(2,"Received mlme disassociate request\n"); + result = prism2mgmt_disassociate(wlandev, msg); + break; + case DIDmsg_dot11req_reset : + WLAN_LOG_DEBUG(2,"Received mlme reset request\n"); + result = prism2mgmt_reset(wlandev, msg); + break; + case DIDmsg_dot11req_start : + WLAN_LOG_DEBUG(2,"Received mlme start request\n"); + result = prism2mgmt_start(wlandev, msg); + break; + /* + * Prism2 specific messages + */ + case DIDmsg_p2req_join : + WLAN_LOG_DEBUG(2,"Received p2 join request\n"); + result = prism2mgmt_p2_join(wlandev, msg); + break; + case DIDmsg_p2req_readpda : + WLAN_LOG_DEBUG(2,"Received mlme readpda request\n"); + result = prism2mgmt_readpda(wlandev, msg); + break; + case DIDmsg_p2req_readcis : + WLAN_LOG_DEBUG(2,"Received mlme readcis request\n"); + result = prism2mgmt_readcis(wlandev, msg); + break; + case DIDmsg_p2req_auxport_state : + WLAN_LOG_DEBUG(2,"Received mlme auxport_state request\n"); + result = prism2mgmt_auxport_state(wlandev, msg); + break; + case DIDmsg_p2req_auxport_read : + WLAN_LOG_DEBUG(2,"Received mlme auxport_read request\n"); + result = prism2mgmt_auxport_read(wlandev, msg); + break; + case DIDmsg_p2req_auxport_write : + WLAN_LOG_DEBUG(2,"Received mlme auxport_write request\n"); + result = prism2mgmt_auxport_write(wlandev, msg); + break; + case DIDmsg_p2req_low_level : + WLAN_LOG_DEBUG(2,"Received mlme low_level request\n"); + result = prism2mgmt_low_level(wlandev, msg); + break; + case DIDmsg_p2req_test_command : + WLAN_LOG_DEBUG(2,"Received mlme test_command request\n"); + result = prism2mgmt_test_command(wlandev, msg); + break; + case DIDmsg_p2req_mmi_read : + WLAN_LOG_DEBUG(2,"Received mlme mmi_read request\n"); + result = prism2mgmt_mmi_read(wlandev, msg); + break; + case DIDmsg_p2req_mmi_write : + WLAN_LOG_DEBUG(2,"Received mlme mmi_write request\n"); + result = prism2mgmt_mmi_write(wlandev, msg); + break; + case DIDmsg_p2req_ramdl_state : + WLAN_LOG_DEBUG(2,"Received mlme ramdl_state request\n"); + result = prism2mgmt_ramdl_state(wlandev, msg); + break; + case DIDmsg_p2req_ramdl_write : + WLAN_LOG_DEBUG(2,"Received mlme ramdl_write request\n"); + result = prism2mgmt_ramdl_write(wlandev, msg); + break; + case DIDmsg_p2req_flashdl_state : + WLAN_LOG_DEBUG(2,"Received mlme flashdl_state request\n"); + result = prism2mgmt_flashdl_state(wlandev, msg); + break; + case DIDmsg_p2req_flashdl_write : + WLAN_LOG_DEBUG(2,"Received mlme flashdl_write request\n"); + result = prism2mgmt_flashdl_write(wlandev, msg); + break; + case DIDmsg_p2req_dump_state : + WLAN_LOG_DEBUG(2,"Received mlme dump_state request\n"); + result = prism2mgmt_dump_state(wlandev, msg); + break; + case DIDmsg_p2req_channel_info : + WLAN_LOG_DEBUG(2,"Received mlme channel_info request\n"); + result = prism2mgmt_channel_info(wlandev, msg); + break; + case DIDmsg_p2req_channel_info_results : + WLAN_LOG_DEBUG(2,"Received mlme channel_info_results request\n"); + result = prism2mgmt_channel_info_results(wlandev, msg); + break; + /* + * Linux specific messages + */ + case DIDmsg_lnxreq_hostwep : + break; // ignore me. + case DIDmsg_lnxreq_ifstate : + { + p80211msg_lnxreq_ifstate_t *ifstatemsg; + WLAN_LOG_DEBUG(2,"Received mlme ifstate request\n"); + ifstatemsg = (p80211msg_lnxreq_ifstate_t*)msg; + result = prism2sta_ifstate(wlandev, ifstatemsg->ifstate.data); + ifstatemsg->resultcode.status = + P80211ENUM_msgitem_status_data_ok; + ifstatemsg->resultcode.data = result; + result = 0; + } + break; + case DIDmsg_lnxreq_wlansniff : + WLAN_LOG_DEBUG(2,"Received mlme wlansniff request\n"); + result = prism2mgmt_wlansniff(wlandev, msg); + break; + case DIDmsg_lnxreq_autojoin : + WLAN_LOG_DEBUG(2,"Received mlme autojoin request\n"); + result = prism2mgmt_autojoin(wlandev, msg); + break; + case DIDmsg_p2req_enable : + WLAN_LOG_DEBUG(2,"Received mlme enable request\n"); + result = prism2mgmt_enable(wlandev, msg); + break; + case DIDmsg_lnxreq_commsquality: { + p80211msg_lnxreq_commsquality_t *qualmsg; + + WLAN_LOG_DEBUG(2,"Received commsquality request\n"); + + if (hw->ap) + break; + + qualmsg = (p80211msg_lnxreq_commsquality_t*) msg; + + qualmsg->link.status = P80211ENUM_msgitem_status_data_ok; + qualmsg->level.status = P80211ENUM_msgitem_status_data_ok; + qualmsg->noise.status = P80211ENUM_msgitem_status_data_ok; + + + qualmsg->link.data = hfa384x2host_16(hw->qual.CQ_currBSS); + qualmsg->level.data = hfa384x2host_16(hw->qual.ASL_currBSS); + qualmsg->noise.data = hfa384x2host_16(hw->qual.ANL_currFC); + + break; + } + default: + WLAN_LOG_WARNING("Unknown mgmt request message 0x%08x", msg->msgcode); + break; + } + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* prism2sta_ifstate +* +* Interface state. This is the primary WLAN interface enable/disable +* handler. Following the driver/load/deviceprobe sequence, this +* function must be called with a state of "enable" before any other +* commands will be accepted. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* A p80211 message resultcode value. +* +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ +UINT32 prism2sta_ifstate(wlandevice_t *wlandev, UINT32 ifstate) +{ + hfa384x_t *hw = (hfa384x_t *)wlandev->priv; + UINT32 result; + DBFENTER; + + result = P80211ENUM_resultcode_implementation_failure; + + WLAN_LOG_DEBUG(2, "Current MSD state(%d), requesting(%d)\n", + wlandev->msdstate, ifstate); + switch (ifstate) + { + case P80211ENUM_ifstate_fwload: + switch (wlandev->msdstate) { + case WLAN_MSD_HWPRESENT: + wlandev->msdstate = WLAN_MSD_FWLOAD_PENDING; + /* + * Initialize the device+driver sufficiently + * for firmware loading. + */ +#if (WLAN_HOSTIF != WLAN_USB) + result=hfa384x_cmd_initialize(hw); +#else + if ((result=hfa384x_drvr_start(hw))) { + WLAN_LOG_ERROR( + "hfa384x_drvr_start() failed," + "result=%d\n", (int)result); + result = + P80211ENUM_resultcode_implementation_failure; + wlandev->msdstate = WLAN_MSD_HWPRESENT; + break; + } +#endif + wlandev->msdstate = WLAN_MSD_FWLOAD; + result = P80211ENUM_resultcode_success; + break; + case WLAN_MSD_FWLOAD: + hfa384x_cmd_initialize(hw); + result = P80211ENUM_resultcode_success; + break; + case WLAN_MSD_RUNNING: + WLAN_LOG_WARNING( + "Cannot enter fwload state from enable state," + "you must disable first.\n"); + result = P80211ENUM_resultcode_invalid_parameters; + break; + case WLAN_MSD_HWFAIL: + default: + /* probe() had a problem or the msdstate contains + * an unrecognized value, there's nothing we can do. + */ + result = P80211ENUM_resultcode_implementation_failure; + break; + } + break; + case P80211ENUM_ifstate_enable: + switch (wlandev->msdstate) { + case WLAN_MSD_HWPRESENT: + case WLAN_MSD_FWLOAD: + wlandev->msdstate = WLAN_MSD_RUNNING_PENDING; + /* Initialize the device+driver for full + * operation. Note that this might me an FWLOAD to + * to RUNNING transition so we must not do a chip + * or board level reset. Note that on failure, + * the MSD state is set to HWPRESENT because we + * can't make any assumptions about the state + * of the hardware or a previous firmware load. + */ + if ((result=hfa384x_drvr_start(hw))) { + WLAN_LOG_ERROR( + "hfa384x_drvr_start() failed," + "result=%d\n", (int)result); + result = + P80211ENUM_resultcode_implementation_failure; + wlandev->msdstate = WLAN_MSD_HWPRESENT; + break; + } + + if ((result=prism2sta_getcardinfo(wlandev))) { + WLAN_LOG_ERROR( + "prism2sta_getcardinfo() failed," + "result=%d\n", (int)result); + result = + P80211ENUM_resultcode_implementation_failure; + hfa384x_drvr_stop(hw); + wlandev->msdstate = WLAN_MSD_HWPRESENT; + break; + } + if ((result=prism2sta_globalsetup(wlandev))) { + WLAN_LOG_ERROR( + "prism2sta_globalsetup() failed," + "result=%d\n", (int)result); + result = + P80211ENUM_resultcode_implementation_failure; + hfa384x_drvr_stop(hw); + wlandev->msdstate = WLAN_MSD_HWPRESENT; + break; + } + wlandev->msdstate = WLAN_MSD_RUNNING; + hw->join_ap = 0; + hw->join_retries = 60; + result = P80211ENUM_resultcode_success; + break; + case WLAN_MSD_RUNNING: + /* Do nothing, we're already in this state.*/ + result = P80211ENUM_resultcode_success; + break; + case WLAN_MSD_HWFAIL: + default: + /* probe() had a problem or the msdstate contains + * an unrecognized value, there's nothing we can do. + */ + result = P80211ENUM_resultcode_implementation_failure; + break; + } + break; + case P80211ENUM_ifstate_disable: + switch (wlandev->msdstate) { + case WLAN_MSD_HWPRESENT: + /* Do nothing, we're already in this state.*/ + result = P80211ENUM_resultcode_success; + break; + case WLAN_MSD_FWLOAD: + case WLAN_MSD_RUNNING: + wlandev->msdstate = WLAN_MSD_HWPRESENT_PENDING; + /* + * TODO: Shut down the MAC completely. Here a chip + * or board level reset is probably called for. + * After a "disable" _all_ results are lost, even + * those from a fwload. + */ + if (!wlandev->hwremoved) + netif_carrier_off(wlandev->netdev); + + hfa384x_drvr_stop(hw); + + wlandev->macmode = WLAN_MACMODE_NONE; + wlandev->msdstate = WLAN_MSD_HWPRESENT; + result = P80211ENUM_resultcode_success; + break; + case WLAN_MSD_HWFAIL: + default: + /* probe() had a problem or the msdstate contains + * an unrecognized value, there's nothing we can do. + */ + result = P80211ENUM_resultcode_implementation_failure; + break; + } + break; + default: + result = P80211ENUM_resultcode_invalid_parameters; + break; + } + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* prism2sta_getcardinfo +* +* Collect the NICID, firmware version and any other identifiers +* we'd like to have in host-side data structures. +* +* Arguments: +* wlandev wlan device structure +* +* Returns: +* 0 success +* >0 f/w reported error +* <0 driver reported error +* +* Side effects: +* +* Call context: +* Either. +----------------------------------------------------------------*/ +static int prism2sta_getcardinfo(wlandevice_t *wlandev) +{ + int result = 0; + hfa384x_t *hw = (hfa384x_t *)wlandev->priv; + UINT16 temp; + UINT8 snum[HFA384x_RID_NICSERIALNUMBER_LEN]; + char pstr[(HFA384x_RID_NICSERIALNUMBER_LEN * 4) + 1]; + + DBFENTER; + + /* Collect version and compatibility info */ + /* Some are critical, some are not */ + /* NIC identity */ + result = hfa384x_drvr_getconfig(hw, HFA384x_RID_NICIDENTITY, + &hw->ident_nic, sizeof(hfa384x_compident_t)); + if ( result ) { + WLAN_LOG_ERROR("Failed to retrieve NICIDENTITY\n"); + goto failed; + } + + /* get all the nic id fields in host byte order */ + hw->ident_nic.id = hfa384x2host_16(hw->ident_nic.id); + hw->ident_nic.variant = hfa384x2host_16(hw->ident_nic.variant); + hw->ident_nic.major = hfa384x2host_16(hw->ident_nic.major); + hw->ident_nic.minor = hfa384x2host_16(hw->ident_nic.minor); + + WLAN_LOG_INFO( "ident: nic h/w: id=0x%02x %d.%d.%d\n", + hw->ident_nic.id, hw->ident_nic.major, + hw->ident_nic.minor, hw->ident_nic.variant); + + /* Primary f/w identity */ + result = hfa384x_drvr_getconfig(hw, HFA384x_RID_PRIIDENTITY, + &hw->ident_pri_fw, sizeof(hfa384x_compident_t)); + if ( result ) { + WLAN_LOG_ERROR("Failed to retrieve PRIIDENTITY\n"); + goto failed; + } + + /* get all the private fw id fields in host byte order */ + hw->ident_pri_fw.id = hfa384x2host_16(hw->ident_pri_fw.id); + hw->ident_pri_fw.variant = hfa384x2host_16(hw->ident_pri_fw.variant); + hw->ident_pri_fw.major = hfa384x2host_16(hw->ident_pri_fw.major); + hw->ident_pri_fw.minor = hfa384x2host_16(hw->ident_pri_fw.minor); + + WLAN_LOG_INFO( "ident: pri f/w: id=0x%02x %d.%d.%d\n", + hw->ident_pri_fw.id, hw->ident_pri_fw.major, + hw->ident_pri_fw.minor, hw->ident_pri_fw.variant); + + /* Station (Secondary?) f/w identity */ + result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STAIDENTITY, + &hw->ident_sta_fw, sizeof(hfa384x_compident_t)); + if ( result ) { + WLAN_LOG_ERROR("Failed to retrieve STAIDENTITY\n"); + goto failed; + } + + if (hw->ident_nic.id < 0x8000) { + WLAN_LOG_ERROR("FATAL: Card is not an Intersil Prism2/2.5/3\n"); + result = -1; + goto failed; + } + + /* get all the station fw id fields in host byte order */ + hw->ident_sta_fw.id = hfa384x2host_16(hw->ident_sta_fw.id); + hw->ident_sta_fw.variant = hfa384x2host_16(hw->ident_sta_fw.variant); + hw->ident_sta_fw.major = hfa384x2host_16(hw->ident_sta_fw.major); + hw->ident_sta_fw.minor = hfa384x2host_16(hw->ident_sta_fw.minor); + + /* strip out the 'special' variant bits */ + hw->mm_mods = hw->ident_sta_fw.variant & (BIT14 | BIT15); + hw->ident_sta_fw.variant &= ~((UINT16)(BIT14 | BIT15)); + + if ( hw->ident_sta_fw.id == 0x1f ) { + hw->ap = 0; + WLAN_LOG_INFO( + "ident: sta f/w: id=0x%02x %d.%d.%d\n", + hw->ident_sta_fw.id, hw->ident_sta_fw.major, + hw->ident_sta_fw.minor, hw->ident_sta_fw.variant); + } else { + hw->ap = 1; + WLAN_LOG_INFO( + "ident: ap f/w: id=0x%02x %d.%d.%d\n", + hw->ident_sta_fw.id, hw->ident_sta_fw.major, + hw->ident_sta_fw.minor, hw->ident_sta_fw.variant); + } + + /* Compatibility range, Modem supplier */ + result = hfa384x_drvr_getconfig(hw, HFA384x_RID_MFISUPRANGE, + &hw->cap_sup_mfi, sizeof(hfa384x_caplevel_t)); + if ( result ) { + WLAN_LOG_ERROR("Failed to retrieve MFISUPRANGE\n"); + goto failed; + } + + /* get all the Compatibility range, modem interface supplier + fields in byte order */ + hw->cap_sup_mfi.role = hfa384x2host_16(hw->cap_sup_mfi.role); + hw->cap_sup_mfi.id = hfa384x2host_16(hw->cap_sup_mfi.id); + hw->cap_sup_mfi.variant = hfa384x2host_16(hw->cap_sup_mfi.variant); + hw->cap_sup_mfi.bottom = hfa384x2host_16(hw->cap_sup_mfi.bottom); + hw->cap_sup_mfi.top = hfa384x2host_16(hw->cap_sup_mfi.top); + + WLAN_LOG_INFO( + "MFI:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", + hw->cap_sup_mfi.role, hw->cap_sup_mfi.id, + hw->cap_sup_mfi.variant, hw->cap_sup_mfi.bottom, + hw->cap_sup_mfi.top); + + /* Compatibility range, Controller supplier */ + result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CFISUPRANGE, + &hw->cap_sup_cfi, sizeof(hfa384x_caplevel_t)); + if ( result ) { + WLAN_LOG_ERROR("Failed to retrieve CFISUPRANGE\n"); + goto failed; + } + + /* get all the Compatibility range, controller interface supplier + fields in byte order */ + hw->cap_sup_cfi.role = hfa384x2host_16(hw->cap_sup_cfi.role); + hw->cap_sup_cfi.id = hfa384x2host_16(hw->cap_sup_cfi.id); + hw->cap_sup_cfi.variant = hfa384x2host_16(hw->cap_sup_cfi.variant); + hw->cap_sup_cfi.bottom = hfa384x2host_16(hw->cap_sup_cfi.bottom); + hw->cap_sup_cfi.top = hfa384x2host_16(hw->cap_sup_cfi.top); + + WLAN_LOG_INFO( + "CFI:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", + hw->cap_sup_cfi.role, hw->cap_sup_cfi.id, + hw->cap_sup_cfi.variant, hw->cap_sup_cfi.bottom, + hw->cap_sup_cfi.top); + + /* Compatibility range, Primary f/w supplier */ + result = hfa384x_drvr_getconfig(hw, HFA384x_RID_PRISUPRANGE, + &hw->cap_sup_pri, sizeof(hfa384x_caplevel_t)); + if ( result ) { + WLAN_LOG_ERROR("Failed to retrieve PRISUPRANGE\n"); + goto failed; + } + + /* get all the Compatibility range, primary firmware supplier + fields in byte order */ + hw->cap_sup_pri.role = hfa384x2host_16(hw->cap_sup_pri.role); + hw->cap_sup_pri.id = hfa384x2host_16(hw->cap_sup_pri.id); + hw->cap_sup_pri.variant = hfa384x2host_16(hw->cap_sup_pri.variant); + hw->cap_sup_pri.bottom = hfa384x2host_16(hw->cap_sup_pri.bottom); + hw->cap_sup_pri.top = hfa384x2host_16(hw->cap_sup_pri.top); + + WLAN_LOG_INFO( + "PRI:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", + hw->cap_sup_pri.role, hw->cap_sup_pri.id, + hw->cap_sup_pri.variant, hw->cap_sup_pri.bottom, + hw->cap_sup_pri.top); + + /* Compatibility range, Station f/w supplier */ + result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STASUPRANGE, + &hw->cap_sup_sta, sizeof(hfa384x_caplevel_t)); + if ( result ) { + WLAN_LOG_ERROR("Failed to retrieve STASUPRANGE\n"); + goto failed; + } + + /* get all the Compatibility range, station firmware supplier + fields in byte order */ + hw->cap_sup_sta.role = hfa384x2host_16(hw->cap_sup_sta.role); + hw->cap_sup_sta.id = hfa384x2host_16(hw->cap_sup_sta.id); + hw->cap_sup_sta.variant = hfa384x2host_16(hw->cap_sup_sta.variant); + hw->cap_sup_sta.bottom = hfa384x2host_16(hw->cap_sup_sta.bottom); + hw->cap_sup_sta.top = hfa384x2host_16(hw->cap_sup_sta.top); + + if ( hw->cap_sup_sta.id == 0x04 ) { + WLAN_LOG_INFO( + "STA:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", + hw->cap_sup_sta.role, hw->cap_sup_sta.id, + hw->cap_sup_sta.variant, hw->cap_sup_sta.bottom, + hw->cap_sup_sta.top); + } else { + WLAN_LOG_INFO( + "AP:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", + hw->cap_sup_sta.role, hw->cap_sup_sta.id, + hw->cap_sup_sta.variant, hw->cap_sup_sta.bottom, + hw->cap_sup_sta.top); + } + + /* Compatibility range, primary f/w actor, CFI supplier */ + result = hfa384x_drvr_getconfig(hw, HFA384x_RID_PRI_CFIACTRANGES, + &hw->cap_act_pri_cfi, sizeof(hfa384x_caplevel_t)); + if ( result ) { + WLAN_LOG_ERROR("Failed to retrieve PRI_CFIACTRANGES\n"); + goto failed; + } + + /* get all the Compatibility range, primary f/w actor, CFI supplier + fields in byte order */ + hw->cap_act_pri_cfi.role = hfa384x2host_16(hw->cap_act_pri_cfi.role); + hw->cap_act_pri_cfi.id = hfa384x2host_16(hw->cap_act_pri_cfi.id); + hw->cap_act_pri_cfi.variant = hfa384x2host_16(hw->cap_act_pri_cfi.variant); + hw->cap_act_pri_cfi.bottom = hfa384x2host_16(hw->cap_act_pri_cfi.bottom); + hw->cap_act_pri_cfi.top = hfa384x2host_16(hw->cap_act_pri_cfi.top); + + WLAN_LOG_INFO( + "PRI-CFI:ACT:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", + hw->cap_act_pri_cfi.role, hw->cap_act_pri_cfi.id, + hw->cap_act_pri_cfi.variant, hw->cap_act_pri_cfi.bottom, + hw->cap_act_pri_cfi.top); + + /* Compatibility range, sta f/w actor, CFI supplier */ + result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STA_CFIACTRANGES, + &hw->cap_act_sta_cfi, sizeof(hfa384x_caplevel_t)); + if ( result ) { + WLAN_LOG_ERROR("Failed to retrieve STA_CFIACTRANGES\n"); + goto failed; + } + + /* get all the Compatibility range, station f/w actor, CFI supplier + fields in byte order */ + hw->cap_act_sta_cfi.role = hfa384x2host_16(hw->cap_act_sta_cfi.role); + hw->cap_act_sta_cfi.id = hfa384x2host_16(hw->cap_act_sta_cfi.id); + hw->cap_act_sta_cfi.variant = hfa384x2host_16(hw->cap_act_sta_cfi.variant); + hw->cap_act_sta_cfi.bottom = hfa384x2host_16(hw->cap_act_sta_cfi.bottom); + hw->cap_act_sta_cfi.top = hfa384x2host_16(hw->cap_act_sta_cfi.top); + + WLAN_LOG_INFO( + "STA-CFI:ACT:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", + hw->cap_act_sta_cfi.role, hw->cap_act_sta_cfi.id, + hw->cap_act_sta_cfi.variant, hw->cap_act_sta_cfi.bottom, + hw->cap_act_sta_cfi.top); + + /* Compatibility range, sta f/w actor, MFI supplier */ + result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STA_MFIACTRANGES, + &hw->cap_act_sta_mfi, sizeof(hfa384x_caplevel_t)); + if ( result ) { + WLAN_LOG_ERROR("Failed to retrieve STA_MFIACTRANGES\n"); + goto failed; + } + + /* get all the Compatibility range, station f/w actor, MFI supplier + fields in byte order */ + hw->cap_act_sta_mfi.role = hfa384x2host_16(hw->cap_act_sta_mfi.role); + hw->cap_act_sta_mfi.id = hfa384x2host_16(hw->cap_act_sta_mfi.id); + hw->cap_act_sta_mfi.variant = hfa384x2host_16(hw->cap_act_sta_mfi.variant); + hw->cap_act_sta_mfi.bottom = hfa384x2host_16(hw->cap_act_sta_mfi.bottom); + hw->cap_act_sta_mfi.top = hfa384x2host_16(hw->cap_act_sta_mfi.top); + + WLAN_LOG_INFO( + "STA-MFI:ACT:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", + hw->cap_act_sta_mfi.role, hw->cap_act_sta_mfi.id, + hw->cap_act_sta_mfi.variant, hw->cap_act_sta_mfi.bottom, + hw->cap_act_sta_mfi.top); + + /* Serial Number */ + result = hfa384x_drvr_getconfig(hw, HFA384x_RID_NICSERIALNUMBER, + snum, HFA384x_RID_NICSERIALNUMBER_LEN); + if ( !result ) { + wlan_mkprintstr(snum, HFA384x_RID_NICSERIALNUMBER_LEN, + pstr, sizeof(pstr)); + WLAN_LOG_INFO("Prism2 card SN: %s\n", pstr); + } else { + WLAN_LOG_ERROR("Failed to retrieve Prism2 Card SN\n"); + goto failed; + } + + /* Collect the MAC address */ + result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CNFOWNMACADDR, + wlandev->netdev->dev_addr, WLAN_ADDR_LEN); + if ( result != 0 ) { + WLAN_LOG_ERROR("Failed to retrieve mac address\n"); + goto failed; + } + + /* short preamble is always implemented */ + wlandev->nsdcaps |= P80211_NSDCAP_SHORT_PREAMBLE; + + /* find out if hardware wep is implemented */ + hfa384x_drvr_getconfig16(hw, HFA384x_RID_PRIVACYOPTIMP, &temp); + if (temp) + wlandev->nsdcaps |= P80211_NSDCAP_HARDWAREWEP; + + /* get the dBm Scaling constant */ + hfa384x_drvr_getconfig16(hw, HFA384x_RID_CNFDBMADJUST, &temp); + hw->dbmadjust = temp; + + /* Only enable scan by default on newer firmware */ + if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major, + hw->ident_sta_fw.minor, + hw->ident_sta_fw.variant) < + HFA384x_FIRMWARE_VERSION(1,5,5)) { + wlandev->nsdcaps |= P80211_NSDCAP_NOSCAN; + } + + /* TODO: Set any internally managed config items */ + + goto done; +failed: + WLAN_LOG_ERROR("Failed, result=%d\n", result); +done: + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* prism2sta_globalsetup +* +* Set any global RIDs that we want to set at device activation. +* +* Arguments: +* wlandev wlan device structure +* +* Returns: +* 0 success +* >0 f/w reported error +* <0 driver reported error +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +static int prism2sta_globalsetup(wlandevice_t *wlandev) +{ + hfa384x_t *hw = (hfa384x_t *)wlandev->priv; + + /* Set the maximum frame size */ + return hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN, + WLAN_DATA_MAXLEN); +} + +static int prism2sta_setmulticast(wlandevice_t *wlandev, netdevice_t *dev) +{ + int result = 0; + hfa384x_t *hw = (hfa384x_t *)wlandev->priv; + + UINT16 promisc; + + DBFENTER; + + /* If we're not ready, what's the point? */ + if ( hw->state != HFA384x_STATE_RUNNING ) + goto exit; + + /* If we're an AP, do nothing here */ + if (hw->ap) + goto exit; + + if ( (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0 ) + promisc = P80211ENUM_truth_true; + else + promisc = P80211ENUM_truth_false; + + result = hfa384x_drvr_setconfig16_async(hw, HFA384x_RID_PROMISCMODE, promisc); + + /* XXX TODO: configure the multicast list */ + // CLEAR_HW_MULTICAST_LIST + // struct dev_mc_list element = dev->mc_list; + // while (element != null) { + // HW_ADD_MULTICAST_ADDR(element->dmi_addr, dmi_addrlen) + // element = element->next; + // } + + exit: + DBFEXIT; + return result; +} + +/*---------------------------------------------------------------- +* prism2sta_inf_handover +* +* Handles the receipt of a Handover info frame. Should only be present +* in APs only. +* +* Arguments: +* wlandev wlan device structure +* inf ptr to info frame (contents in hfa384x order) +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void prism2sta_inf_handover(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf) +{ + DBFENTER; + WLAN_LOG_DEBUG(2,"received infoframe:HANDOVER (unhandled)\n"); + DBFEXIT; + return; +} + + +/*---------------------------------------------------------------- +* prism2sta_inf_tallies +* +* Handles the receipt of a CommTallies info frame. +* +* Arguments: +* wlandev wlan device structure +* inf ptr to info frame (contents in hfa384x order) +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void prism2sta_inf_tallies(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf) +{ + hfa384x_t *hw = (hfa384x_t *)wlandev->priv; + UINT16 *src16; + UINT32 *dst; + UINT32 *src32; + int i; + int cnt; + + DBFENTER; + + /* + ** Determine if these are 16-bit or 32-bit tallies, based on the + ** record length of the info record. + */ + + cnt = sizeof(hfa384x_CommTallies32_t) / sizeof(UINT32); + if (inf->framelen > 22) { + dst = (UINT32 *) &hw->tallies; + src32 = (UINT32 *) &inf->info.commtallies32; + for (i = 0; i < cnt; i++, dst++, src32++) + *dst += hfa384x2host_32(*src32); + } else { + dst = (UINT32 *) &hw->tallies; + src16 = (UINT16 *) &inf->info.commtallies16; + for (i = 0; i < cnt; i++, dst++, src16++) + *dst += hfa384x2host_16(*src16); + } + + DBFEXIT; + + return; +} + +/*---------------------------------------------------------------- +* prism2sta_inf_scanresults +* +* Handles the receipt of a Scan Results info frame. +* +* Arguments: +* wlandev wlan device structure +* inf ptr to info frame (contents in hfa384x order) +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void prism2sta_inf_scanresults(wlandevice_t *wlandev, + hfa384x_InfFrame_t *inf) +{ + + hfa384x_t *hw = (hfa384x_t *)wlandev->priv; + int nbss; + hfa384x_ScanResult_t *sr = &(inf->info.scanresult); + int i; + hfa384x_JoinRequest_data_t joinreq; + int result; + DBFENTER; + + /* Get the number of results, first in bytes, then in results */ + nbss = (inf->framelen * sizeof(UINT16)) - + sizeof(inf->infotype) - + sizeof(inf->info.scanresult.scanreason); + nbss /= sizeof(hfa384x_ScanResultSub_t); + + /* Print em */ + WLAN_LOG_DEBUG(1,"rx scanresults, reason=%d, nbss=%d:\n", + inf->info.scanresult.scanreason, nbss); + for ( i = 0; i < nbss; i++) { + WLAN_LOG_DEBUG(1, "chid=%d anl=%d sl=%d bcnint=%d\n", + sr->result[i].chid, + sr->result[i].anl, + sr->result[i].sl, + sr->result[i].bcnint); + WLAN_LOG_DEBUG(1, " capinfo=0x%04x proberesp_rate=%d\n", + sr->result[i].capinfo, + sr->result[i].proberesp_rate); + } + /* issue a join request */ + joinreq.channel = sr->result[0].chid; + memcpy( joinreq.bssid, sr->result[0].bssid, WLAN_BSSID_LEN); + result = hfa384x_drvr_setconfig( hw, + HFA384x_RID_JOINREQUEST, + &joinreq, HFA384x_RID_JOINREQUEST_LEN); + if (result) { + WLAN_LOG_ERROR("setconfig(joinreq) failed, result=%d\n", result); + } + + DBFEXIT; + return; +} + +/*---------------------------------------------------------------- +* prism2sta_inf_hostscanresults +* +* Handles the receipt of a Scan Results info frame. +* +* Arguments: +* wlandev wlan device structure +* inf ptr to info frame (contents in hfa384x order) +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void prism2sta_inf_hostscanresults(wlandevice_t *wlandev, + hfa384x_InfFrame_t *inf) +{ + hfa384x_t *hw = (hfa384x_t *)wlandev->priv; + int nbss; + DBFENTER; + + nbss = (inf->framelen - 3) / 32; + WLAN_LOG_DEBUG(1, "Received %d hostscan results\n", nbss); + + if (nbss > 32) + nbss = 32; + + if (hw->scanresults) + kfree(hw->scanresults); + + hw->scanresults = kmalloc(sizeof(hfa384x_InfFrame_t), GFP_ATOMIC); + memcpy(hw->scanresults, inf, sizeof(hfa384x_InfFrame_t)); + + if (nbss == 0) + nbss = -1; + + /* Notify/wake the sleeping caller. */ + hw->scanflag = nbss; + wake_up_interruptible(&hw->cmdq); + + DBFEXIT; +}; + +/*---------------------------------------------------------------- +* prism2sta_inf_chinforesults +* +* Handles the receipt of a Channel Info Results info frame. +* +* Arguments: +* wlandev wlan device structure +* inf ptr to info frame (contents in hfa384x order) +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void prism2sta_inf_chinforesults(wlandevice_t *wlandev, + hfa384x_InfFrame_t *inf) +{ + hfa384x_t *hw = (hfa384x_t *)wlandev->priv; + unsigned int i, n; + + DBFENTER; + hw->channel_info.results.scanchannels = + hfa384x2host_16(inf->info.chinforesult.scanchannels); +#if 0 + memcpy(&inf->info.chinforesult, &hw->channel_info.results, sizeof(hfa384x_ChInfoResult_t)); +#endif + + for (i=0, n=0; ichannel_info.results.scanchannels & (1<info.chinforesult.result[n].chid)-1; + hfa384x_ChInfoResultSub_t *chinforesult=&hw->channel_info.results.result[channel]; + chinforesult->chid = channel; + chinforesult->anl = hfa384x2host_16(inf->info.chinforesult.result[n].anl); + chinforesult->pnl = hfa384x2host_16(inf->info.chinforesult.result[n].pnl); + chinforesult->active = hfa384x2host_16(inf->info.chinforesult.result[n].active); + WLAN_LOG_DEBUG(2, "chinfo: channel %d, %s level (avg/peak)=%d/%d dB, pcf %d\n", + channel+1, + chinforesult->active & + HFA384x_CHINFORESULT_BSSACTIVE ? "signal" : "noise", + chinforesult->anl, chinforesult->pnl, + chinforesult->active & HFA384x_CHINFORESULT_PCFACTIVE ? 1 : 0 + ); + n++; + } + } + atomic_set(&hw->channel_info.done, 2); + + hw->channel_info.count = n; + DBFEXIT; + return; +} + +void prism2sta_processing_defer(struct work_struct *data) +{ + hfa384x_t *hw = container_of(data, struct hfa384x, link_bh); + wlandevice_t *wlandev = hw->wlandev; + hfa384x_bytestr32_t ssid; + int result; + + DBFENTER; + /* First let's process the auth frames */ + { + struct sk_buff *skb; + hfa384x_InfFrame_t *inf; + + while ( (skb = skb_dequeue(&hw->authq)) ) { + inf = (hfa384x_InfFrame_t *) skb->data; + prism2sta_inf_authreq_defer(wlandev, inf); + } + + } + + /* Now let's handle the linkstatus stuff */ + if (hw->link_status == hw->link_status_new) + goto failed; + + hw->link_status = hw->link_status_new; + + switch(hw->link_status) { + case HFA384x_LINK_NOTCONNECTED: + /* I'm currently assuming that this is the initial link + * state. It should only be possible immediately + * following an Enable command. + * Response: + * Block Transmits, Ignore receives of data frames + */ + netif_carrier_off(wlandev->netdev); + + WLAN_LOG_INFO("linkstatus=NOTCONNECTED (unhandled)\n"); + break; + + case HFA384x_LINK_CONNECTED: + /* This one indicates a successful scan/join/auth/assoc. + * When we have the full MLME complement, this event will + * signify successful completion of both mlme_authenticate + * and mlme_associate. State management will get a little + * ugly here. + * Response: + * Indicate authentication and/or association + * Enable Transmits, Receives and pass up data frames + */ + + netif_carrier_on(wlandev->netdev); + + /* If we are joining a specific AP, set our state and reset retries */ + if(hw->join_ap == 1) + hw->join_ap = 2; + hw->join_retries = 60; + + /* Don't call this in monitor mode */ + if ( wlandev->netdev->type == ARPHRD_ETHER ) { + UINT16 portstatus; + + WLAN_LOG_INFO("linkstatus=CONNECTED\n"); + + /* For non-usb devices, we can use the sync versions */ + /* Collect the BSSID, and set state to allow tx */ + + result = hfa384x_drvr_getconfig(hw, + HFA384x_RID_CURRENTBSSID, + wlandev->bssid, WLAN_BSSID_LEN); + if ( result ) { + WLAN_LOG_DEBUG(1, + "getconfig(0x%02x) failed, result = %d\n", + HFA384x_RID_CURRENTBSSID, result); + goto failed; + } + + result = hfa384x_drvr_getconfig(hw, + HFA384x_RID_CURRENTSSID, + &ssid, sizeof(ssid)); + if ( result ) { + WLAN_LOG_DEBUG(1, + "getconfig(0x%02x) failed, result = %d\n", + HFA384x_RID_CURRENTSSID, result); + goto failed; + } + prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *)&ssid, + (p80211pstrd_t *) &wlandev->ssid); + + /* Collect the port status */ + result = hfa384x_drvr_getconfig16(hw, + HFA384x_RID_PORTSTATUS, &portstatus); + if ( result ) { + WLAN_LOG_DEBUG(1, + "getconfig(0x%02x) failed, result = %d\n", + HFA384x_RID_PORTSTATUS, result); + goto failed; + } + wlandev->macmode = + (portstatus == HFA384x_PSTATUS_CONN_IBSS) ? + WLAN_MACMODE_IBSS_STA : WLAN_MACMODE_ESS_STA; + + /* Get the ball rolling on the comms quality stuff */ + prism2sta_commsqual_defer(&hw->commsqual_bh); + } + break; + + case HFA384x_LINK_DISCONNECTED: + /* This one indicates that our association is gone. We've + * lost connection with the AP and/or been disassociated. + * This indicates that the MAC has completely cleared it's + * associated state. We * should send a deauth indication + * (implying disassoc) up * to the MLME. + * Response: + * Indicate Deauthentication + * Block Transmits, Ignore receives of data frames + */ + if(hw->join_ap == 2) + { + hfa384x_JoinRequest_data_t joinreq; + joinreq = hw->joinreq; + /* Send the join request */ + hfa384x_drvr_setconfig( hw, + HFA384x_RID_JOINREQUEST, + &joinreq, HFA384x_RID_JOINREQUEST_LEN); + WLAN_LOG_INFO("linkstatus=DISCONNECTED (re-submitting join)\n"); + } else { + if (wlandev->netdev->type == ARPHRD_ETHER) + WLAN_LOG_INFO("linkstatus=DISCONNECTED (unhandled)\n"); + } + wlandev->macmode = WLAN_MACMODE_NONE; + + netif_carrier_off(wlandev->netdev); + + break; + + case HFA384x_LINK_AP_CHANGE: + /* This one indicates that the MAC has decided to and + * successfully completed a change to another AP. We + * should probably implement a reassociation indication + * in response to this one. I'm thinking that the the + * p80211 layer needs to be notified in case of + * buffering/queueing issues. User mode also needs to be + * notified so that any BSS dependent elements can be + * updated. + * associated state. We * should send a deauth indication + * (implying disassoc) up * to the MLME. + * Response: + * Indicate Reassociation + * Enable Transmits, Receives and pass up data frames + */ + WLAN_LOG_INFO("linkstatus=AP_CHANGE\n"); + + result = hfa384x_drvr_getconfig(hw, + HFA384x_RID_CURRENTBSSID, + wlandev->bssid, WLAN_BSSID_LEN); + if ( result ) { + WLAN_LOG_DEBUG(1, + "getconfig(0x%02x) failed, result = %d\n", + HFA384x_RID_CURRENTBSSID, result); + goto failed; + } + + result = hfa384x_drvr_getconfig(hw, + HFA384x_RID_CURRENTSSID, + &ssid, sizeof(ssid)); + if ( result ) { + WLAN_LOG_DEBUG(1, + "getconfig(0x%02x) failed, result = %d\n", + HFA384x_RID_CURRENTSSID, result); + goto failed; + } + prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *)&ssid, + (p80211pstrd_t *) &wlandev->ssid); + + + hw->link_status = HFA384x_LINK_CONNECTED; + netif_carrier_on(wlandev->netdev); + + break; + + case HFA384x_LINK_AP_OUTOFRANGE: + /* This one indicates that the MAC has decided that the + * AP is out of range, but hasn't found a better candidate + * so the MAC maintains its "associated" state in case + * we get back in range. We should block transmits and + * receives in this state. Do we need an indication here? + * Probably not since a polling user-mode element would + * get this status from from p2PortStatus(FD40). What about + * p80211? + * Response: + * Block Transmits, Ignore receives of data frames + */ + WLAN_LOG_INFO("linkstatus=AP_OUTOFRANGE (unhandled)\n"); + + netif_carrier_off(wlandev->netdev); + + break; + + case HFA384x_LINK_AP_INRANGE: + /* This one indicates that the MAC has decided that the + * AP is back in range. We continue working with our + * existing association. + * Response: + * Enable Transmits, Receives and pass up data frames + */ + WLAN_LOG_INFO("linkstatus=AP_INRANGE\n"); + + hw->link_status = HFA384x_LINK_CONNECTED; + netif_carrier_on(wlandev->netdev); + + break; + + case HFA384x_LINK_ASSOCFAIL: + /* This one is actually a peer to CONNECTED. We've + * requested a join for a given SSID and optionally BSSID. + * We can use this one to indicate authentication and + * association failures. The trick is going to be + * 1) identifying the failure, and 2) state management. + * Response: + * Disable Transmits, Ignore receives of data frames + */ + if(hw->join_ap && --hw->join_retries > 0) + { + hfa384x_JoinRequest_data_t joinreq; + joinreq = hw->joinreq; + /* Send the join request */ + hfa384x_drvr_setconfig( hw, + HFA384x_RID_JOINREQUEST, + &joinreq, HFA384x_RID_JOINREQUEST_LEN); + WLAN_LOG_INFO("linkstatus=ASSOCFAIL (re-submitting join)\n"); + } else { + WLAN_LOG_INFO("linkstatus=ASSOCFAIL (unhandled)\n"); + } + + netif_carrier_off(wlandev->netdev); + + break; + + default: + /* This is bad, IO port problems? */ + WLAN_LOG_WARNING( + "unknown linkstatus=0x%02x\n", hw->link_status); + goto failed; + break; + } + + wlandev->linkstatus = (hw->link_status == HFA384x_LINK_CONNECTED); +#ifdef WIRELESS_EXT + p80211wext_event_associated(wlandev, wlandev->linkstatus); +#endif + + failed: + DBFEXIT; +} + +/*---------------------------------------------------------------- +* prism2sta_inf_linkstatus +* +* Handles the receipt of a Link Status info frame. +* +* Arguments: +* wlandev wlan device structure +* inf ptr to info frame (contents in hfa384x order) +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void prism2sta_inf_linkstatus(wlandevice_t *wlandev, + hfa384x_InfFrame_t *inf) +{ + hfa384x_t *hw = (hfa384x_t *)wlandev->priv; + + DBFENTER; + + hw->link_status_new = hfa384x2host_16(inf->info.linkstatus.linkstatus); + + schedule_work(&hw->link_bh); + + DBFEXIT; + return; +} + +/*---------------------------------------------------------------- +* prism2sta_inf_assocstatus +* +* Handles the receipt of an Association Status info frame. Should +* be present in APs only. +* +* Arguments: +* wlandev wlan device structure +* inf ptr to info frame (contents in hfa384x order) +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void prism2sta_inf_assocstatus(wlandevice_t *wlandev, + hfa384x_InfFrame_t *inf) +{ + hfa384x_t *hw = (hfa384x_t *)wlandev->priv; + hfa384x_AssocStatus_t rec; + int i; + + DBFENTER; + + memcpy(&rec, &inf->info.assocstatus, sizeof(rec)); + rec.assocstatus = hfa384x2host_16(rec.assocstatus); + rec.reason = hfa384x2host_16(rec.reason); + + /* + ** Find the address in the list of authenticated stations. If it wasn't + ** found, then this address has not been previously authenticated and + ** something weird has happened if this is anything other than an + ** "authentication failed" message. If the address was found, then + ** set the "associated" flag for that station, based on whether the + ** station is associating or losing its association. Something weird + ** has also happened if we find the address in the list of authenticated + ** stations but we are getting an "authentication failed" message. + */ + + for (i = 0; i < hw->authlist.cnt; i++) + if (memcmp(rec.sta_addr, hw->authlist.addr[i], WLAN_ADDR_LEN) == 0) + break; + + if (i >= hw->authlist.cnt) { + if (rec.assocstatus != HFA384x_ASSOCSTATUS_AUTHFAIL) + WLAN_LOG_WARNING("assocstatus info frame received for non-authenticated station.\n"); + } else { + hw->authlist.assoc[i] = + (rec.assocstatus == HFA384x_ASSOCSTATUS_STAASSOC || + rec.assocstatus == HFA384x_ASSOCSTATUS_REASSOC); + + if (rec.assocstatus == HFA384x_ASSOCSTATUS_AUTHFAIL) + WLAN_LOG_WARNING("authfail assocstatus info frame received for authenticated station.\n"); + } + + DBFEXIT; + + return; +} + +/*---------------------------------------------------------------- +* prism2sta_inf_authreq +* +* Handles the receipt of an Authentication Request info frame. Should +* be present in APs only. +* +* Arguments: +* wlandev wlan device structure +* inf ptr to info frame (contents in hfa384x order) +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +* +----------------------------------------------------------------*/ +static void prism2sta_inf_authreq(wlandevice_t *wlandev, + hfa384x_InfFrame_t *inf) +{ + hfa384x_t *hw = (hfa384x_t *)wlandev->priv; + struct sk_buff *skb; + + DBFENTER; + + skb = dev_alloc_skb(sizeof(*inf)); + if (skb) { + skb_put(skb, sizeof(*inf)); + memcpy(skb->data, inf, sizeof(*inf)); + skb_queue_tail(&hw->authq, skb); + schedule_work(&hw->link_bh); + } + + DBFEXIT; +} + +static void prism2sta_inf_authreq_defer(wlandevice_t *wlandev, + hfa384x_InfFrame_t *inf) +{ + hfa384x_t *hw = (hfa384x_t *)wlandev->priv; + hfa384x_authenticateStation_data_t rec; + + int i, added, result, cnt; + UINT8 *addr; + + DBFENTER; + + /* + ** Build the AuthenticateStation record. Initialize it for denying + ** authentication. + */ + + memcpy(rec.address, inf->info.authreq.sta_addr, WLAN_ADDR_LEN); + rec.status = P80211ENUM_status_unspec_failure; + + /* + ** Authenticate based on the access mode. + */ + + switch (hw->accessmode) { + case WLAN_ACCESS_NONE: + + /* + ** Deny all new authentications. However, if a station + ** is ALREADY authenticated, then accept it. + */ + + for (i = 0; i < hw->authlist.cnt; i++) + if (memcmp(rec.address, hw->authlist.addr[i], + WLAN_ADDR_LEN) == 0) { + rec.status = P80211ENUM_status_successful; + break; + } + + break; + + case WLAN_ACCESS_ALL: + + /* + ** Allow all authentications. + */ + + rec.status = P80211ENUM_status_successful; + break; + + case WLAN_ACCESS_ALLOW: + + /* + ** Only allow the authentication if the MAC address + ** is in the list of allowed addresses. + ** + ** Since this is the interrupt handler, we may be here + ** while the access list is in the middle of being + ** updated. Choose the list which is currently okay. + ** See "prism2mib_priv_accessallow()" for details. + */ + + if (hw->allow.modify == 0) { + cnt = hw->allow.cnt; + addr = hw->allow.addr[0]; + } else { + cnt = hw->allow.cnt1; + addr = hw->allow.addr1[0]; + } + + for (i = 0; i < cnt; i++, addr += WLAN_ADDR_LEN) + if (memcmp(rec.address, addr, WLAN_ADDR_LEN) == 0) { + rec.status = P80211ENUM_status_successful; + break; + } + + break; + + case WLAN_ACCESS_DENY: + + /* + ** Allow the authentication UNLESS the MAC address is + ** in the list of denied addresses. + ** + ** Since this is the interrupt handler, we may be here + ** while the access list is in the middle of being + ** updated. Choose the list which is currently okay. + ** See "prism2mib_priv_accessdeny()" for details. + */ + + if (hw->deny.modify == 0) { + cnt = hw->deny.cnt; + addr = hw->deny.addr[0]; + } else { + cnt = hw->deny.cnt1; + addr = hw->deny.addr1[0]; + } + + rec.status = P80211ENUM_status_successful; + + for (i = 0; i < cnt; i++, addr += WLAN_ADDR_LEN) + if (memcmp(rec.address, addr, WLAN_ADDR_LEN) == 0) { + rec.status = P80211ENUM_status_unspec_failure; + break; + } + + break; + } + + /* + ** If the authentication is okay, then add the MAC address to the list + ** of authenticated stations. Don't add the address if it is already in + ** the list. (802.11b does not seem to disallow a station from issuing + ** an authentication request when the station is already authenticated. + ** Does this sort of thing ever happen? We might as well do the check + ** just in case.) + */ + + added = 0; + + if (rec.status == P80211ENUM_status_successful) { + for (i = 0; i < hw->authlist.cnt; i++) + if (memcmp(rec.address, hw->authlist.addr[i], WLAN_ADDR_LEN) == 0) + break; + + if (i >= hw->authlist.cnt) { + if (hw->authlist.cnt >= WLAN_AUTH_MAX) { + rec.status = P80211ENUM_status_ap_full; + } else { + memcpy(hw->authlist.addr[hw->authlist.cnt], + rec.address, WLAN_ADDR_LEN); + hw->authlist.cnt++; + added = 1; + } + } + } + + /* + ** Send back the results of the authentication. If this doesn't work, + ** then make sure to remove the address from the authenticated list if + ** it was added. + */ + + rec.status = host2hfa384x_16(rec.status); + rec.algorithm = inf->info.authreq.algorithm; + + result = hfa384x_drvr_setconfig(hw, HFA384x_RID_AUTHENTICATESTA, + &rec, sizeof(rec)); + if (result) { + if (added) hw->authlist.cnt--; + WLAN_LOG_ERROR("setconfig(authenticatestation) failed, result=%d\n", result); + } + + DBFEXIT; + + return; +} + + +/*---------------------------------------------------------------- +* prism2sta_inf_psusercnt +* +* Handles the receipt of a PowerSaveUserCount info frame. Should +* be present in APs only. +* +* Arguments: +* wlandev wlan device structure +* inf ptr to info frame (contents in hfa384x order) +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +static void prism2sta_inf_psusercnt(wlandevice_t *wlandev, + hfa384x_InfFrame_t *inf) +{ + hfa384x_t *hw = (hfa384x_t *)wlandev->priv; + + DBFENTER; + + hw->psusercount = hfa384x2host_16(inf->info.psusercnt.usercnt); + + DBFEXIT; + + return; +} + +/*---------------------------------------------------------------- +* prism2sta_ev_dtim +* +* Handles the DTIM early warning event. +* +* Arguments: +* wlandev wlan device structure +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +void prism2sta_ev_dtim(wlandevice_t *wlandev) +{ +#if 0 + hfa384x_t *hw = (hfa384x_t *)wlandev->priv; +#endif + DBFENTER; + WLAN_LOG_DEBUG(3, "DTIM event, currently unhandled.\n"); + DBFEXIT; + return; +} + + +/*---------------------------------------------------------------- +* prism2sta_ev_infdrop +* +* Handles the InfDrop event. +* +* Arguments: +* wlandev wlan device structure +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +void prism2sta_ev_infdrop(wlandevice_t *wlandev) +{ +#if 0 + hfa384x_t *hw = (hfa384x_t *)wlandev->priv; +#endif + DBFENTER; + WLAN_LOG_DEBUG(3, "Info frame dropped due to card mem low.\n"); + DBFEXIT; + return; +} + + +/*---------------------------------------------------------------- +* prism2sta_ev_info +* +* Handles the Info event. +* +* Arguments: +* wlandev wlan device structure +* inf ptr to a generic info frame +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +void prism2sta_ev_info(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf) +{ + DBFENTER; + inf->infotype = hfa384x2host_16(inf->infotype); + /* Dispatch */ + switch ( inf->infotype ) { + case HFA384x_IT_HANDOVERADDR: + prism2sta_inf_handover(wlandev, inf); + break; + case HFA384x_IT_COMMTALLIES: + prism2sta_inf_tallies(wlandev, inf); + break; + case HFA384x_IT_HOSTSCANRESULTS: + prism2sta_inf_hostscanresults(wlandev, inf); + break; + case HFA384x_IT_SCANRESULTS: + prism2sta_inf_scanresults(wlandev, inf); + break; + case HFA384x_IT_CHINFORESULTS: + prism2sta_inf_chinforesults(wlandev, inf); + break; + case HFA384x_IT_LINKSTATUS: + prism2sta_inf_linkstatus(wlandev, inf); + break; + case HFA384x_IT_ASSOCSTATUS: + prism2sta_inf_assocstatus(wlandev, inf); + break; + case HFA384x_IT_AUTHREQ: + prism2sta_inf_authreq(wlandev, inf); + break; + case HFA384x_IT_PSUSERCNT: + prism2sta_inf_psusercnt(wlandev, inf); + break; + case HFA384x_IT_KEYIDCHANGED: + WLAN_LOG_WARNING("Unhandled IT_KEYIDCHANGED\n"); + break; + case HFA384x_IT_ASSOCREQ: + WLAN_LOG_WARNING("Unhandled IT_ASSOCREQ\n"); + break; + case HFA384x_IT_MICFAILURE: + WLAN_LOG_WARNING("Unhandled IT_MICFAILURE\n"); + break; + default: + WLAN_LOG_WARNING( + "Unknown info type=0x%02x\n", inf->infotype); + break; + } + DBFEXIT; + return; +} + + +/*---------------------------------------------------------------- +* prism2sta_ev_txexc +* +* Handles the TxExc event. A Transmit Exception event indicates +* that the MAC's TX process was unsuccessful - so the packet did +* not get transmitted. +* +* Arguments: +* wlandev wlan device structure +* status tx frame status word +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +void prism2sta_ev_txexc(wlandevice_t *wlandev, UINT16 status) +{ + DBFENTER; + + WLAN_LOG_DEBUG(3, "TxExc status=0x%x.\n", status); + + DBFEXIT; + return; +} + + +/*---------------------------------------------------------------- +* prism2sta_ev_tx +* +* Handles the Tx event. +* +* Arguments: +* wlandev wlan device structure +* status tx frame status word +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +void prism2sta_ev_tx(wlandevice_t *wlandev, UINT16 status) +{ + DBFENTER; + WLAN_LOG_DEBUG(4, "Tx Complete, status=0x%04x\n", status); + /* update linux network stats */ + wlandev->linux_stats.tx_packets++; + DBFEXIT; + return; +} + + +/*---------------------------------------------------------------- +* prism2sta_ev_rx +* +* Handles the Rx event. +* +* Arguments: +* wlandev wlan device structure +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +void prism2sta_ev_rx(wlandevice_t *wlandev, struct sk_buff *skb) +{ + DBFENTER; + + p80211netdev_rx(wlandev, skb); + + DBFEXIT; + return; +} + +/*---------------------------------------------------------------- +* prism2sta_ev_alloc +* +* Handles the Alloc event. +* +* Arguments: +* wlandev wlan device structure +* +* Returns: +* nothing +* +* Side effects: +* +* Call context: +* interrupt +----------------------------------------------------------------*/ +void prism2sta_ev_alloc(wlandevice_t *wlandev) +{ + DBFENTER; + + p80211netdev_wake_queue(wlandev); + + DBFEXIT; + return; +} + +#if (WLAN_HOSTIF == WLAN_PLX || WLAN_HOSTIF == WLAN_PCI) +#ifdef CONFIG_PM +static int prism2sta_suspend_pci(struct pci_dev *pdev, pm_message_t state) +{ + wlandevice_t *wlandev; + + wlandev = (wlandevice_t *) pci_get_drvdata(pdev); + + /* reset hardware */ + if (wlandev) { + prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable); + p80211_suspend(wlandev); + } + + // call a netif_device_detach(wlandev->netdev) ? + + return 0; +} + +static int prism2sta_resume_pci (struct pci_dev *pdev) +{ + wlandevice_t *wlandev; + + wlandev = (wlandevice_t *) pci_get_drvdata(pdev); + + if (wlandev) { + p80211_resume(wlandev); + prism2sta_ifstate(wlandev, P80211ENUM_ifstate_enable); + } + + return 0; +} +#endif +#endif + +/*---------------------------------------------------------------- +* create_wlan +* +* Called at module init time. This creates the wlandevice_t structure +* and initializes it with relevant bits. +* +* Arguments: +* none +* +* Returns: +* the created wlandevice_t structure. +* +* Side effects: +* also allocates the priv/hw structures. +* +* Call context: +* process thread +* +----------------------------------------------------------------*/ +static wlandevice_t *create_wlan(void) +{ + wlandevice_t *wlandev = NULL; + hfa384x_t *hw = NULL; + + /* Alloc our structures */ + wlandev = kmalloc(sizeof(wlandevice_t), GFP_KERNEL); + hw = kmalloc(sizeof(hfa384x_t), GFP_KERNEL); + + if (!wlandev || !hw) { + WLAN_LOG_ERROR("%s: Memory allocation failure.\n", dev_info); + if (wlandev) kfree(wlandev); + if (hw) kfree(hw); + return NULL; + } + + /* Clear all the structs */ + memset(wlandev, 0, sizeof(wlandevice_t)); + memset(hw, 0, sizeof(hfa384x_t)); + + /* Initialize the network device object. */ + wlandev->nsdname = dev_info; + wlandev->msdstate = WLAN_MSD_HWPRESENT_PENDING; + wlandev->priv = hw; + wlandev->open = prism2sta_open; + wlandev->close = prism2sta_close; + wlandev->reset = prism2sta_reset; +#ifdef CONFIG_PROC_FS + wlandev->nsd_proc_read = prism2sta_proc_read; +#endif + wlandev->txframe = prism2sta_txframe; + wlandev->mlmerequest = prism2sta_mlmerequest; + wlandev->set_multicast_list = prism2sta_setmulticast; + wlandev->tx_timeout = hfa384x_tx_timeout; + + wlandev->nsdcaps = P80211_NSDCAP_HWFRAGMENT | + P80211_NSDCAP_AUTOJOIN; + + /* Initialize the device private data stucture. */ + hw->dot11_desired_bss_type = 1; + + return wlandev; +} + +#ifdef CONFIG_PROC_FS +static int +prism2sta_proc_read( + char *page, + char **start, + off_t offset, + int count, + int *eof, + void *data) +{ + char *p = page; + wlandevice_t *wlandev = (wlandevice_t *) data; + hfa384x_t *hw = (hfa384x_t *) wlandev->priv; + + UINT16 hwtype = 0; + + DBFENTER; + if (offset != 0) { + *eof = 1; + goto exit; + } + + // XXX 0x0001 for prism2.5/3, 0x0000 for prism2. + hwtype = BIT0; + +#if (WLAN_HOSTIF != WLAN_USB) + if (hw->isram16) + hwtype |= BIT1; +#endif + +#if (WLAN_HOSTIF == WLAN_PCI) + hwtype |= BIT2; +#endif + +#define PRISM2_CVS_ID "$Id: prism2sta.c 1858 2008-03-24 18:49:31Z pizza $" + + p += sprintf(p, "# %s version %s (%s) '%s'\n\n", + dev_info, + WLAN_RELEASE, WLAN_BUILD_DATE, PRISM2_CVS_ID); + + p += sprintf(p, "# nic h/w: id=0x%02x %d.%d.%d\n", + hw->ident_nic.id, hw->ident_nic.major, + hw->ident_nic.minor, hw->ident_nic.variant); + + p += sprintf(p, "# pri f/w: id=0x%02x %d.%d.%d\n", + hw->ident_pri_fw.id, hw->ident_pri_fw.major, + hw->ident_pri_fw.minor, hw->ident_pri_fw.variant); + + if (hw->ident_sta_fw.id == 0x1f) { + p += sprintf(p, "# sta f/w: id=0x%02x %d.%d.%d\n", + hw->ident_sta_fw.id, hw->ident_sta_fw.major, + hw->ident_sta_fw.minor, hw->ident_sta_fw.variant); + } else { + p += sprintf(p, "# ap f/w: id=0x%02x %d.%d.%d\n", + hw->ident_sta_fw.id, hw->ident_sta_fw.major, + hw->ident_sta_fw.minor, hw->ident_sta_fw.variant); + } + +#if (WLAN_HOSTIF != WLAN_USB) + p += sprintf(p, "# initial nic hw type, needed for SSF ramdl\n"); + p += sprintf(p, "initnichw=%04x\n", hwtype); +#endif + + exit: + DBFEXIT; + return (p - page); +} +#endif + +void prism2sta_commsqual_defer(struct work_struct *data) +{ + hfa384x_t *hw = container_of(data, struct hfa384x, commsqual_bh); + wlandevice_t *wlandev = hw->wlandev; + hfa384x_bytestr32_t ssid; + int result = 0; + + DBFENTER; + + if (hw->wlandev->hwremoved) + goto done; + + /* we don't care if we're in AP mode */ + if ((wlandev->macmode == WLAN_MACMODE_NONE) || + (wlandev->macmode == WLAN_MACMODE_ESS_AP)) { + goto done; + } + + /* It only makes sense to poll these in non-IBSS */ + if (wlandev->macmode != WLAN_MACMODE_IBSS_STA) { + result = hfa384x_drvr_getconfig(hw, HFA384x_RID_DBMCOMMSQUALITY, + &hw->qual, + HFA384x_RID_DBMCOMMSQUALITY_LEN); + + if (result) { + WLAN_LOG_ERROR("error fetching commsqual\n"); + goto done; + } + + // qual.CQ_currBSS; // link + // ASL_currBSS; // level + // qual.ANL_currFC; // noise + + WLAN_LOG_DEBUG(3, "commsqual %d %d %d\n", + hfa384x2host_16(hw->qual.CQ_currBSS), + hfa384x2host_16(hw->qual.ASL_currBSS), + hfa384x2host_16(hw->qual.ANL_currFC)); + } + + /* Lastly, we need to make sure the BSSID didn't change on us */ + result = hfa384x_drvr_getconfig(hw, + HFA384x_RID_CURRENTBSSID, + wlandev->bssid, WLAN_BSSID_LEN); + if ( result ) { + WLAN_LOG_DEBUG(1, + "getconfig(0x%02x) failed, result = %d\n", + HFA384x_RID_CURRENTBSSID, result); + goto done; + } + + result = hfa384x_drvr_getconfig(hw, + HFA384x_RID_CURRENTSSID, + &ssid, sizeof(ssid)); + if ( result ) { + WLAN_LOG_DEBUG(1, + "getconfig(0x%02x) failed, result = %d\n", + HFA384x_RID_CURRENTSSID, result); + goto done; + } + prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *)&ssid, + (p80211pstrd_t *) &wlandev->ssid); + + + /* Reschedule timer */ + mod_timer(&hw->commsqual_timer, round_jiffies(jiffies + HZ)); + + done: + DBFEXIT; +} + +void prism2sta_commsqual_timer(unsigned long data) +{ + hfa384x_t *hw = (hfa384x_t *) data; + + DBFENTER; + + schedule_work(&hw->commsqual_bh); + + DBFEXIT; +} --- linux-2.6.27.orig/ubuntu/misc/wireless/prism2_usb/prism2mgmt.c +++ linux-2.6.27/ubuntu/misc/wireless/prism2_usb/prism2mgmt.c @@ -0,0 +1,2956 @@ +/* src/prism2/driver/prism2mgmt.c +* +* Management request handler functions. +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* The functions in this file handle management requests sent from +* user mode. +* +* Most of these functions have two separate blocks of code that are +* conditional on whether this is a station or an AP. This is used +* to separate out the STA and AP responses to these management primitives. +* It's a choice (good, bad, indifferent?) to have the code in the same +* place so it's clear that the same primitive is implemented in both +* cases but has different behavior. +* +* -------------------------------------------------------------------- +*/ + +/*================================================================*/ +/* System Includes */ +#define WLAN_DBVAR prism2_debug + +#include + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if (WLAN_HOSTIF == WLAN_USB) +#include +#endif + +#if (WLAN_HOSTIF == WLAN_PCMCIA) +#include +#include +#include +#include +#include +#include +#endif + +#include + +/*================================================================*/ +/* Project Includes */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*================================================================*/ +/* Local Constants */ + + +/*================================================================*/ +/* Local Macros */ + +/* Converts 802.11 format rate specifications to prism2 */ +#define p80211rate_to_p2bit(n) ((((n)&~BIT7) == 2) ? BIT0 : \ + (((n)&~BIT7) == 4) ? BIT1 : \ + (((n)&~BIT7) == 11) ? BIT2 : \ + (((n)&~BIT7) == 22) ? BIT3 : 0) + +/*================================================================*/ +/* Local Types */ + + +/*================================================================*/ +/* Local Static Definitions */ + + +/*================================================================*/ +/* Local Function Declarations */ + + +/*================================================================*/ +/* Function Definitions */ + + +/*---------------------------------------------------------------- +* prism2mgmt_powermgmt +* +* Set the power management state of this station's MAC. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ +int prism2mgmt_powermgmt(wlandevice_t *wlandev, void *msgp) +{ + int result = 0; + hfa384x_t *hw = wlandev->priv; + p80211msg_dot11req_powermgmt_t *msg = msgp; + + DBFENTER; + + if (!hw->ap) { + + /*** STATION ***/ + + /* + * Set CNFPMENABLED (on or off) + * Set CNFMULTICASTRX (if PM on, otherwise clear) + * Spout a notice stating that SleepDuration and + * HoldoverDuration and PMEPS also have an impact. + */ + /* Powermgmt is currently unsupported for STA */ + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + } else { + + /*** ACCESS POINT ***/ + + /* Powermgmt is never supported for AP */ + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + } + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_scan +* +* Initiate a scan for BSSs. +* +* This function corresponds to MLME-scan.request and part of +* MLME-scan.confirm. As far as I can tell in the standard, there +* are no restrictions on when a scan.request may be issued. We have +* to handle in whatever state the driver/MAC happen to be. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ +int prism2mgmt_scan(wlandevice_t *wlandev, void *msgp) +{ + int result = 0; + hfa384x_t *hw = wlandev->priv; + p80211msg_dot11req_scan_t *msg = msgp; + UINT16 roamingmode, word; + int i, timeout; + int istmpenable = 0; + + hfa384x_HostScanRequest_data_t scanreq; + + DBFENTER; + + if (hw->ap) { + WLAN_LOG_ERROR("Prism2 in AP mode cannot perform scans.\n"); + result = 1; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + goto exit; + } + + /* gatekeeper check */ + if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major, + hw->ident_sta_fw.minor, + hw->ident_sta_fw.variant) < + HFA384x_FIRMWARE_VERSION(1,3,2)) { + WLAN_LOG_ERROR("HostScan not supported with current firmware (<1.3.2).\n"); + result = 1; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + goto exit; + } + + memset(&scanreq, 0, sizeof(scanreq)); + + /* save current roaming mode */ + result = hfa384x_drvr_getconfig16(hw, + HFA384x_RID_CNFROAMINGMODE, &roamingmode); + if ( result ) { + WLAN_LOG_ERROR("getconfig(ROAMMODE) failed. result=%d\n", + result); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + goto exit; + } + + /* drop into mode 3 for the scan */ + result = hfa384x_drvr_setconfig16(hw, + HFA384x_RID_CNFROAMINGMODE, + HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM); + if ( result ) { + WLAN_LOG_ERROR("setconfig(ROAMINGMODE) failed. result=%d\n", + result); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + goto exit; + } + + /* active or passive? */ + if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major, + hw->ident_sta_fw.minor, + hw->ident_sta_fw.variant) > + HFA384x_FIRMWARE_VERSION(1,5,0)) { + if (msg->scantype.data != P80211ENUM_scantype_active) { + word = host2hfa384x_16(msg->maxchanneltime.data); + } else { + word = 0; + } + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPASSIVESCANCTRL, word); + if ( result ) { + WLAN_LOG_WARNING("Passive scan not supported with " + "current firmware. (<1.5.1)\n"); + } + } + + /* set up the txrate to be 2MBPS. Should be fastest basicrate... */ + word = HFA384x_RATEBIT_2; + scanreq.txRate = host2hfa384x_16(word); + + /* set up the channel list */ + word = 0; + for (i = 0; i < msg->channellist.data.len; i++) { + UINT8 channel = msg->channellist.data.data[i]; + if (channel > 14) continue; + /* channel 1 is BIT0 ... channel 14 is BIT13 */ + word |= (1 << (channel-1)); + } + scanreq.channelList = host2hfa384x_16(word); + + /* set up the ssid, if present. */ + scanreq.ssid.len = host2hfa384x_16(msg->ssid.data.len); + memcpy(scanreq.ssid.data, msg->ssid.data.data, msg->ssid.data.len); + + /* Enable the MAC port if it's not already enabled */ + result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_PORTSTATUS, &word); + if ( result ) { + WLAN_LOG_ERROR("getconfig(PORTSTATUS) failed. " + "result=%d\n", result); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + goto exit; + } + if (word == HFA384x_PORTSTATUS_DISABLED) { + UINT16 wordbuf[17]; + + result = hfa384x_drvr_setconfig16(hw, + HFA384x_RID_CNFROAMINGMODE, + HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM); + if ( result ) { + WLAN_LOG_ERROR("setconfig(ROAMINGMODE) failed. result=%d\n", result); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + goto exit; + } + /* Construct a bogus SSID and assign it to OwnSSID and + * DesiredSSID + */ + wordbuf[0] = host2hfa384x_16(WLAN_SSID_MAXLEN); + get_random_bytes(&wordbuf[1], WLAN_SSID_MAXLEN); + result = hfa384x_drvr_setconfig( hw, HFA384x_RID_CNFOWNSSID, + wordbuf, HFA384x_RID_CNFOWNSSID_LEN); + if ( result ) { + WLAN_LOG_ERROR("Failed to set OwnSSID.\n"); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + goto exit; + } + result = hfa384x_drvr_setconfig( hw, HFA384x_RID_CNFDESIREDSSID, + wordbuf, HFA384x_RID_CNFDESIREDSSID_LEN); + if ( result ) { + WLAN_LOG_ERROR("Failed to set DesiredSSID.\n"); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + goto exit; + } + /* bsstype */ + result = hfa384x_drvr_setconfig16(hw, + HFA384x_RID_CNFPORTTYPE, + HFA384x_PORTTYPE_IBSS); + if ( result ) { + WLAN_LOG_ERROR("Failed to set CNFPORTTYPE.\n"); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + goto exit; + } + /* ibss options */ + result = hfa384x_drvr_setconfig16(hw, + HFA384x_RID_CREATEIBSS, + HFA384x_CREATEIBSS_JOINCREATEIBSS); + if ( result ) { + WLAN_LOG_ERROR("Failed to set CREATEIBSS.\n"); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + goto exit; + } + result = hfa384x_drvr_enable(hw, 0); + if ( result ) { + WLAN_LOG_ERROR("drvr_enable(0) failed. " + "result=%d\n", result); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + goto exit; + } + istmpenable = 1; + } + + /* Figure out our timeout first Kus, then HZ */ + timeout = msg->channellist.data.len * msg->maxchanneltime.data; + timeout = (timeout * HZ)/1000; + + /* Issue the scan request */ + hw->scanflag = 0; + + WLAN_HEX_DUMP(5,"hscanreq", &scanreq, sizeof(scanreq)); + + result = hfa384x_drvr_setconfig( hw, + HFA384x_RID_HOSTSCAN, &scanreq, + sizeof(hfa384x_HostScanRequest_data_t)); + if ( result ) { + WLAN_LOG_ERROR("setconfig(SCANREQUEST) failed. result=%d\n", + result); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + goto exit; + } + + /* sleep until info frame arrives */ + wait_event_interruptible_timeout(hw->cmdq, hw->scanflag, timeout); + + msg->numbss.status = P80211ENUM_msgitem_status_data_ok; + if (hw->scanflag == -1) + hw->scanflag = 0; + + msg->numbss.data = hw->scanflag; + + hw->scanflag = 0; + + /* Disable port if we temporarily enabled it. */ + if (istmpenable) { + result = hfa384x_drvr_disable(hw, 0); + if ( result ) { + WLAN_LOG_ERROR("drvr_disable(0) failed. " + "result=%d\n", result); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + goto exit; + } + } + + /* restore original roaming mode */ + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFROAMINGMODE, + roamingmode); + if ( result ) { + WLAN_LOG_ERROR("setconfig(ROAMMODE) failed. result=%d\n", + result); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + goto exit; + } + + result = 0; + msg->resultcode.data = P80211ENUM_resultcode_success; + + exit: + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_scan_results +* +* Retrieve the BSS description for one of the BSSs identified in +* a scan. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ +int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp) +{ + int result = 0; + p80211msg_dot11req_scan_results_t *req; + hfa384x_t *hw = wlandev->priv; + hfa384x_HScanResultSub_t *item = NULL; + + int count; + + DBFENTER; + + req = (p80211msg_dot11req_scan_results_t *) msgp; + + req->resultcode.status = P80211ENUM_msgitem_status_data_ok; + + if (hw->ap) { + result = 1; + req->resultcode.data = P80211ENUM_resultcode_not_supported; + goto exit; + } + + if (! hw->scanresults) { + WLAN_LOG_ERROR("dot11req_scan_results can only be used after a successful dot11req_scan.\n"); + result = 2; + req->resultcode.data = P80211ENUM_resultcode_invalid_parameters; + goto exit; + } + + count = (hw->scanresults->framelen - 3) / 32; + if (count > 32) count = 32; + + if (req->bssindex.data >= count) { + WLAN_LOG_DEBUG(0, "requested index (%d) out of range (%d)\n", + req->bssindex.data, count); + result = 2; + req->resultcode.data = P80211ENUM_resultcode_invalid_parameters; + goto exit; + } + + item = &(hw->scanresults->info.hscanresult.result[req->bssindex.data]); + /* signal and noise */ + req->signal.status = P80211ENUM_msgitem_status_data_ok; + req->noise.status = P80211ENUM_msgitem_status_data_ok; + req->signal.data = hfa384x2host_16(item->sl); + req->noise.data = hfa384x2host_16(item->anl); + + /* BSSID */ + req->bssid.status = P80211ENUM_msgitem_status_data_ok; + req->bssid.data.len = WLAN_BSSID_LEN; + memcpy(req->bssid.data.data, item->bssid, WLAN_BSSID_LEN); + + /* SSID */ + req->ssid.status = P80211ENUM_msgitem_status_data_ok; + req->ssid.data.len = hfa384x2host_16(item->ssid.len); + memcpy(req->ssid.data.data, item->ssid.data, req->ssid.data.len); + + /* supported rates */ + for (count = 0; count < 10 ; count++) + if (item->supprates[count] == 0) + break; + +#define REQBASICRATE(N) \ + if ((count >= N) && DOT11_RATE5_ISBASIC_GET(item->supprates[(N)-1])) { \ + req->basicrate ## N .data = item->supprates[(N)-1]; \ + req->basicrate ## N .status = P80211ENUM_msgitem_status_data_ok; \ + } + + REQBASICRATE(1); + REQBASICRATE(2); + REQBASICRATE(3); + REQBASICRATE(4); + REQBASICRATE(5); + REQBASICRATE(6); + REQBASICRATE(7); + REQBASICRATE(8); + +#define REQSUPPRATE(N) \ + if (count >= N) { \ + req->supprate ## N .data = item->supprates[(N)-1]; \ + req->supprate ## N .status = P80211ENUM_msgitem_status_data_ok; \ + } + + REQSUPPRATE(1); + REQSUPPRATE(2); + REQSUPPRATE(3); + REQSUPPRATE(4); + REQSUPPRATE(5); + REQSUPPRATE(6); + REQSUPPRATE(7); + REQSUPPRATE(8); + + /* beacon period */ + req->beaconperiod.status = P80211ENUM_msgitem_status_data_ok; + req->beaconperiod.data = hfa384x2host_16(item->bcnint); + + /* timestamps */ + req->timestamp.status = P80211ENUM_msgitem_status_data_ok; + req->timestamp.data = jiffies; + req->localtime.status = P80211ENUM_msgitem_status_data_ok; + req->localtime.data = jiffies; + + /* atim window */ + req->ibssatimwindow.status = P80211ENUM_msgitem_status_data_ok; + req->ibssatimwindow.data = hfa384x2host_16(item->atim); + + /* Channel */ + req->dschannel.status = P80211ENUM_msgitem_status_data_ok; + req->dschannel.data = hfa384x2host_16(item->chid); + + /* capinfo bits */ + count = hfa384x2host_16(item->capinfo); + + /* privacy flag */ + req->privacy.status = P80211ENUM_msgitem_status_data_ok; + req->privacy.data = WLAN_GET_MGMT_CAP_INFO_PRIVACY(count); + + /* cfpollable */ + req->cfpollable.status = P80211ENUM_msgitem_status_data_ok; + req->cfpollable.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLABLE(count); + + /* cfpollreq */ + req->cfpollreq.status = P80211ENUM_msgitem_status_data_ok; + req->cfpollreq.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLREQ(count); + + /* bsstype */ + req->bsstype.status = P80211ENUM_msgitem_status_data_ok; + req->bsstype.data = (WLAN_GET_MGMT_CAP_INFO_ESS(count)) ? + P80211ENUM_bsstype_infrastructure : + P80211ENUM_bsstype_independent; + + // item->proberesp_rate +/* + req->fhdwelltime + req->fhhopset + req->fhhoppattern + req->fhhopindex + req->cfpdurremaining +*/ + + result = 0; + req->resultcode.data = P80211ENUM_resultcode_success; + + exit: + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_join +* +* Join a BSS whose BSS description was previously obtained with +* a scan. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ +int prism2mgmt_join(wlandevice_t *wlandev, void *msgp) +{ + int result = 0; + hfa384x_t *hw = wlandev->priv; + p80211msg_dot11req_join_t *msg = msgp; + DBFENTER; + + if (!hw->ap) { + + /*** STATION ***/ + + /* TODO: Implement after scan */ + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + } else { + + /*** ACCESS POINT ***/ + + /* Never supported by APs */ + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + } + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_p2_join +* +* Join a specific BSS +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ +int prism2mgmt_p2_join(wlandevice_t *wlandev, void *msgp) +{ + int result = 0; + hfa384x_t *hw = wlandev->priv; + p80211msg_p2req_join_t *msg = msgp; + UINT16 reg; + p80211pstrd_t *pstr; + UINT8 bytebuf[256]; + hfa384x_bytestr_t *p2bytestr = (hfa384x_bytestr_t*)bytebuf; + hfa384x_JoinRequest_data_t joinreq; + DBFENTER; + + if (!hw->ap) { + + wlandev->macmode = WLAN_MACMODE_NONE; + + /*** STATION ***/ + /* Set the PortType */ + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_success; + + /* ess port */ + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, 1); + if ( result ) { + WLAN_LOG_ERROR("Failed to set Port Type\n"); + goto failed; + } + + /* Set the auth type */ + if ( msg->authtype.data == P80211ENUM_authalg_sharedkey ) { + reg = HFA384x_CNFAUTHENTICATION_SHAREDKEY; + } else { + reg = HFA384x_CNFAUTHENTICATION_OPENSYSTEM; + } + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAUTHENTICATION, reg); + if ( result ) { + WLAN_LOG_ERROR("Failed to set Authentication\n"); + goto failed; + } + + /* Turn off all roaming */ + hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFROAMINGMODE, 3); + if ( result ) { + WLAN_LOG_ERROR("Failed to Turn off Roaming\n"); + goto failed; + } + + /* Basic rates */ + reg = 0; + if ( msg->basicrate1.status == P80211ENUM_msgitem_status_data_ok ) { + reg = p80211rate_to_p2bit(msg->basicrate1.data); + } + if ( msg->basicrate2.status == P80211ENUM_msgitem_status_data_ok ) { + reg |= p80211rate_to_p2bit(msg->basicrate2.data); + } + if ( msg->basicrate3.status == P80211ENUM_msgitem_status_data_ok ) { + reg |= p80211rate_to_p2bit(msg->basicrate3.data); + } + if ( msg->basicrate4.status == P80211ENUM_msgitem_status_data_ok ) { + reg |= p80211rate_to_p2bit(msg->basicrate4.data); + } + if ( msg->basicrate5.status == P80211ENUM_msgitem_status_data_ok ) { + reg |= p80211rate_to_p2bit(msg->basicrate5.data); + } + if ( msg->basicrate6.status == P80211ENUM_msgitem_status_data_ok ) { + reg |= p80211rate_to_p2bit(msg->basicrate6.data); + } + if ( msg->basicrate7.status == P80211ENUM_msgitem_status_data_ok ) { + reg |= p80211rate_to_p2bit(msg->basicrate7.data); + } + if ( msg->basicrate8.status == P80211ENUM_msgitem_status_data_ok ) { + reg |= p80211rate_to_p2bit(msg->basicrate8.data); + } + if( reg == 0) + reg = 0x03; + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFBASICRATES, reg); + if ( result ) { + WLAN_LOG_ERROR("Failed to set basicrates=%d.\n", reg); + goto failed; + } + + /* Operational rates (supprates and txratecontrol) */ + reg = 0; + if ( msg->operationalrate1.status == P80211ENUM_msgitem_status_data_ok ) { + reg = p80211rate_to_p2bit(msg->operationalrate1.data); + } + if ( msg->operationalrate2.status == P80211ENUM_msgitem_status_data_ok ) { + reg |= p80211rate_to_p2bit(msg->operationalrate2.data); + } + if ( msg->operationalrate3.status == P80211ENUM_msgitem_status_data_ok ) { + reg |= p80211rate_to_p2bit(msg->operationalrate3.data); + } + if ( msg->operationalrate4.status == P80211ENUM_msgitem_status_data_ok ) { + reg |= p80211rate_to_p2bit(msg->operationalrate4.data); + } + if ( msg->operationalrate5.status == P80211ENUM_msgitem_status_data_ok ) { + reg |= p80211rate_to_p2bit(msg->operationalrate5.data); + } + if ( msg->operationalrate6.status == P80211ENUM_msgitem_status_data_ok ) { + reg |= p80211rate_to_p2bit(msg->operationalrate6.data); + } + if ( msg->operationalrate7.status == P80211ENUM_msgitem_status_data_ok ) { + reg |= p80211rate_to_p2bit(msg->operationalrate7.data); + } + if ( msg->operationalrate8.status == P80211ENUM_msgitem_status_data_ok ) { + reg |= p80211rate_to_p2bit(msg->operationalrate8.data); + } + if( reg == 0) + reg = 0x0f; + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFSUPPRATES, reg); + if ( result ) { + WLAN_LOG_ERROR("Failed to set supprates=%d.\n", reg); + goto failed; + } + + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, reg); + if ( result ) { + WLAN_LOG_ERROR("Failed to set txrates=%d.\n", reg); + goto failed; + } + + /* Set the ssid */ + memset(bytebuf, 0, 256); + pstr = (p80211pstrd_t*)&(msg->ssid.data); + prism2mgmt_pstr2bytestr(p2bytestr, pstr); + result = hfa384x_drvr_setconfig( + hw, HFA384x_RID_CNFDESIREDSSID, + bytebuf, HFA384x_RID_CNFDESIREDSSID_LEN); + if ( result ) { + WLAN_LOG_ERROR("Failed to set SSID\n"); + goto failed; + } + + /* Enable the Port */ + result = hfa384x_cmd_enable(hw, 0); + if ( result ) { + WLAN_LOG_ERROR("Enable macport failed, result=%d.\n", result); + goto failed; + } + + /* Fill in the join request */ + joinreq.channel = msg->channel.data; + memcpy( joinreq.bssid, ((unsigned char *) &msg->bssid.data) + 1, WLAN_BSSID_LEN); + hw->joinreq = joinreq; + hw->join_ap = 1; + + /* Send the join request */ + result = hfa384x_drvr_setconfig( hw, + HFA384x_RID_JOINREQUEST, + &joinreq, HFA384x_RID_JOINREQUEST_LEN); + if(result != 0) { + WLAN_LOG_ERROR("Join request failed, result=%d.\n", result); + goto failed; + } + + } else { + + /*** ACCESS POINT ***/ + + /* Never supported by APs */ + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + } + + goto done; +failed: + WLAN_LOG_DEBUG(1, "Failed to set a config option, result=%d\n", result); + msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters; + +done: + result = 0; + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_authenticate +* +* Station should be begin an authentication exchange. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ +int prism2mgmt_authenticate(wlandevice_t *wlandev, void *msgp) +{ + int result = 0; + hfa384x_t *hw = wlandev->priv; + p80211msg_dot11req_authenticate_t *msg = msgp; + DBFENTER; + + if (!hw->ap) { + + /*** STATION ***/ + + /* TODO: Decide how we're going to handle this one w/ Prism2 */ + /* It could be entertaining since Prism2 doesn't have */ + /* an explicit way to control this */ + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + } else { + + /*** ACCESS POINT ***/ + + /* Never supported by APs */ + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + } + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_deauthenticate +* +* Send a deauthenticate notification. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ +int prism2mgmt_deauthenticate(wlandevice_t *wlandev, void *msgp) +{ + int result = 0; + hfa384x_t *hw = wlandev->priv; + p80211msg_dot11req_deauthenticate_t *msg = msgp; + DBFENTER; + + if (!hw->ap) { + + /*** STATION ***/ + + /* TODO: Decide how we're going to handle this one w/ Prism2 */ + /* It could be entertaining since Prism2 doesn't have */ + /* an explicit way to control this */ + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + } else { + + /*** ACCESS POINT ***/ + hfa384x_drvr_handover(hw, msg->peerstaaddress.data.data); + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_success; + } + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_associate +* +* Associate with an ESS. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ +int prism2mgmt_associate(wlandevice_t *wlandev, void *msgp) +{ + hfa384x_t *hw = wlandev->priv; + int result = 0; + p80211msg_dot11req_associate_t *msg = msgp; + DBFENTER; + + if (!hw->ap) { + + /*** STATION ***/ + +#if 0 + /* Set the TxRates */ + reg = 0x000f; + hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, reg); +#endif + + /* Set the PortType */ + /* ess port */ + hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, 1); + + /* Enable the Port */ + hfa384x_drvr_enable(hw, 0); + + /* Set the resultcode */ + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_success; + + } else { + + /*** ACCESS POINT ***/ + + /* Never supported on AP */ + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + } + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_reassociate +* +* Renew association because of a BSS change. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ +int prism2mgmt_reassociate(wlandevice_t *wlandev, void *msgp) +{ + int result = 0; + hfa384x_t *hw = wlandev->priv; + p80211msg_dot11req_reassociate_t *msg = msgp; + DBFENTER; + + if (!hw->ap) { + + /*** STATION ***/ + + /* TODO: Not supported yet...not sure how we're going to do it */ + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + } else { + + /*** ACCESS POINT ***/ + + /* Never supported on AP */ + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + } + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_disassociate +* +* Send a disassociation notification. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ +int prism2mgmt_disassociate(wlandevice_t *wlandev, void *msgp) +{ + int result = 0; + hfa384x_t *hw = wlandev->priv; + p80211msg_dot11req_disassociate_t *msg = msgp; + DBFENTER; + + if (!hw->ap) { + + /*** STATION ***/ + + /* TODO: Not supported yet...not sure how to do it */ + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + } else { + + /*** ACCESS POINT ***/ + hfa384x_drvr_handover(hw, msg->peerstaaddress.data.data); + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_success; + } + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_reset +* +* Reset the MAC and MSD. The p80211 layer has it's own handling +* that should be done before and after this function. +* Procedure: +* - disable system interrupts ?? +* - disable MAC interrupts +* - restore system interrupts +* - issue the MAC initialize command +* - clear any MSD level state (including timers, queued events, +* etc.). Note that if we're removing timer'd/queue events, we may +* need to have remained in the system interrupt disabled state. +* We should be left in the same state that we're in following +* driver initialization. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer, MAY BE NULL! for a driver local +* call. +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread, commonly wlanctl, but might be rmmod/pci_close. +----------------------------------------------------------------*/ +int prism2mgmt_reset(wlandevice_t *wlandev, void *msgp) +{ + int result = 0; + hfa384x_t *hw = wlandev->priv; + p80211msg_dot11req_reset_t *msg = msgp; + DBFENTER; + + /* + * This is supported on both AP and STA and it's not allowed + * to fail. + */ + if ( msgp ) { + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_success; + WLAN_LOG_INFO("dot11req_reset: the macaddress and " + "setdefaultmib arguments are currently unsupported.\n"); + } + + /* + * If we got this far, the MSD must be in the MSDRUNNING state + * therefore, we must stop and then restart the hw/MAC combo. + */ + hfa384x_drvr_stop(hw); + result = hfa384x_drvr_start(hw); + if (result != 0) { + WLAN_LOG_ERROR("dot11req_reset: Initialize command failed," + " bad things will happen from here.\n"); + return 0; + } + + DBFEXIT; + return 0; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_start +* +* Start a BSS. Any station can do this for IBSS, only AP for ESS. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ +int prism2mgmt_start(wlandevice_t *wlandev, void *msgp) +{ + int result = 0; + hfa384x_t *hw = wlandev->priv; + p80211msg_dot11req_start_t *msg = msgp; + + p80211pstrd_t *pstr; + UINT8 bytebuf[80]; + hfa384x_bytestr_t *p2bytestr = (hfa384x_bytestr_t*)bytebuf; + hfa384x_PCFInfo_data_t *pcfinfo = (hfa384x_PCFInfo_data_t*)bytebuf; + UINT16 word; + DBFENTER; + + wlandev->macmode = WLAN_MACMODE_NONE; + + /* Set the SSID */ + memcpy(&wlandev->ssid, &msg->ssid.data, sizeof(msg->ssid.data)); + + if (!hw->ap) { + /*** ADHOC IBSS ***/ + /* see if current f/w is less than 8c3 */ + if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major, + hw->ident_sta_fw.minor, + hw->ident_sta_fw.variant) < + HFA384x_FIRMWARE_VERSION(0,8,3)) { + /* Ad-Hoc not quite supported on Prism2 */ + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + goto done; + } + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + + /*** STATION ***/ + /* Set the REQUIRED config items */ + /* SSID */ + pstr = (p80211pstrd_t*)&(msg->ssid.data); + prism2mgmt_pstr2bytestr(p2bytestr, pstr); + result = hfa384x_drvr_setconfig( hw, HFA384x_RID_CNFOWNSSID, + bytebuf, HFA384x_RID_CNFOWNSSID_LEN); + if ( result ) { + WLAN_LOG_ERROR("Failed to set CnfOwnSSID\n"); + goto failed; + } + result = hfa384x_drvr_setconfig( hw, HFA384x_RID_CNFDESIREDSSID, + bytebuf, HFA384x_RID_CNFDESIREDSSID_LEN); + if ( result ) { + WLAN_LOG_ERROR("Failed to set CnfDesiredSSID\n"); + goto failed; + } + + /* bsstype - we use the default in the ap firmware */ + /* IBSS port */ + hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, 0); + + /* beacon period */ + word = msg->beaconperiod.data; + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAPBCNINT, word); + if ( result ) { + WLAN_LOG_ERROR("Failed to set beacon period=%d.\n", word); + goto failed; + } + + /* dschannel */ + word = msg->dschannel.data; + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFOWNCHANNEL, word); + if ( result ) { + WLAN_LOG_ERROR("Failed to set channel=%d.\n", word); + goto failed; + } + /* Basic rates */ + word = p80211rate_to_p2bit(msg->basicrate1.data); + if ( msg->basicrate2.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->basicrate2.data); + } + if ( msg->basicrate3.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->basicrate3.data); + } + if ( msg->basicrate4.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->basicrate4.data); + } + if ( msg->basicrate5.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->basicrate5.data); + } + if ( msg->basicrate6.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->basicrate6.data); + } + if ( msg->basicrate7.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->basicrate7.data); + } + if ( msg->basicrate8.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->basicrate8.data); + } + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFBASICRATES, word); + if ( result ) { + WLAN_LOG_ERROR("Failed to set basicrates=%d.\n", word); + goto failed; + } + + /* Operational rates (supprates and txratecontrol) */ + word = p80211rate_to_p2bit(msg->operationalrate1.data); + if ( msg->operationalrate2.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->operationalrate2.data); + } + if ( msg->operationalrate3.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->operationalrate3.data); + } + if ( msg->operationalrate4.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->operationalrate4.data); + } + if ( msg->operationalrate5.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->operationalrate5.data); + } + if ( msg->operationalrate6.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->operationalrate6.data); + } + if ( msg->operationalrate7.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->operationalrate7.data); + } + if ( msg->operationalrate8.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->operationalrate8.data); + } + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFSUPPRATES, word); + if ( result ) { + WLAN_LOG_ERROR("Failed to set supprates=%d.\n", word); + goto failed; + } + + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, word); + if ( result ) { + WLAN_LOG_ERROR("Failed to set txrates=%d.\n", word); + goto failed; + } + + /* Set the macmode so the frame setup code knows what to do */ + if ( msg->bsstype.data == P80211ENUM_bsstype_independent ) { + wlandev->macmode = WLAN_MACMODE_IBSS_STA; + /* lets extend the data length a bit */ + hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN, 2304); + } + + /* Enable the Port */ + result = hfa384x_drvr_enable(hw, 0); + if ( result ) { + WLAN_LOG_ERROR("Enable macport failed, result=%d.\n", result); + goto failed; + } + + msg->resultcode.data = P80211ENUM_resultcode_success; + + goto done; + } + + /*** ACCESS POINT ***/ + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + + /* Validate the command, if BSStype=infra is the tertiary loaded? */ + if ( msg->bsstype.data == P80211ENUM_bsstype_independent ) { + WLAN_LOG_ERROR("AP driver cannot create IBSS.\n"); + goto failed; + } else if ( hw->cap_sup_sta.id != 5) { + WLAN_LOG_ERROR("AP driver failed to detect AP firmware.\n"); + goto failed; + } + + /* Set the REQUIRED config items */ + /* SSID */ + pstr = (p80211pstrd_t*)&(msg->ssid.data); + prism2mgmt_pstr2bytestr(p2bytestr, pstr); + result = hfa384x_drvr_setconfig( hw, HFA384x_RID_CNFOWNSSID, + bytebuf, HFA384x_RID_CNFOWNSSID_LEN); + if ( result ) { + WLAN_LOG_ERROR("Failed to set SSID, result=0x%04x\n", result); + goto failed; + } + + /* bsstype - we use the default in the ap firmware */ + + /* beacon period */ + word = msg->beaconperiod.data; + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAPBCNINT, word); + if ( result ) { + WLAN_LOG_ERROR("Failed to set beacon period=%d.\n", word); + goto failed; + } + + /* dschannel */ + word = msg->dschannel.data; + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFOWNCHANNEL, word); + if ( result ) { + WLAN_LOG_ERROR("Failed to set channel=%d.\n", word); + goto failed; + } + /* Basic rates */ + word = p80211rate_to_p2bit(msg->basicrate1.data); + if ( msg->basicrate2.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->basicrate2.data); + } + if ( msg->basicrate3.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->basicrate3.data); + } + if ( msg->basicrate4.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->basicrate4.data); + } + if ( msg->basicrate5.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->basicrate5.data); + } + if ( msg->basicrate6.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->basicrate6.data); + } + if ( msg->basicrate7.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->basicrate7.data); + } + if ( msg->basicrate8.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->basicrate8.data); + } + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFBASICRATES, word); + if ( result ) { + WLAN_LOG_ERROR("Failed to set basicrates=%d.\n", word); + goto failed; + } + + /* Operational rates (supprates and txratecontrol) */ + word = p80211rate_to_p2bit(msg->operationalrate1.data); + if ( msg->operationalrate2.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->operationalrate2.data); + } + if ( msg->operationalrate3.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->operationalrate3.data); + } + if ( msg->operationalrate4.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->operationalrate4.data); + } + if ( msg->operationalrate5.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->operationalrate5.data); + } + if ( msg->operationalrate6.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->operationalrate6.data); + } + if ( msg->operationalrate7.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->operationalrate7.data); + } + if ( msg->operationalrate8.status == P80211ENUM_msgitem_status_data_ok ) { + word |= p80211rate_to_p2bit(msg->operationalrate8.data); + } + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFSUPPRATES, word); + if ( result ) { + WLAN_LOG_ERROR("Failed to set supprates=%d.\n", word); + goto failed; + } + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL0, word); + if ( result ) { + WLAN_LOG_ERROR("Failed to set txrates=%d.\n", word); + goto failed; + } + + /* ibssatimwindow */ + if (msg->ibssatimwindow.status == P80211ENUM_msgitem_status_data_ok) { + WLAN_LOG_INFO("prism2mgmt_start: atimwindow not used in " + "Infrastructure mode, ignored.\n"); + } + + /* DTIM period */ + word = msg->dtimperiod.data; + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFOWNDTIMPER, word); + if ( result ) { + WLAN_LOG_ERROR("Failed to set dtim period=%d.\n", word); + goto failed; + } + + /* probedelay */ + if (msg->probedelay.status == P80211ENUM_msgitem_status_data_ok) { + WLAN_LOG_INFO("prism2mgmt_start: probedelay not " + "supported in prism2, ignored.\n"); + } + + /* cfpollable, cfpollreq, cfpperiod, cfpmaxduration */ + if (msg->cfpollable.data == P80211ENUM_truth_true && + msg->cfpollreq.data == P80211ENUM_truth_true ) { + WLAN_LOG_ERROR("cfpollable=cfpollreq=true is illegal.\n"); + result = -1; + goto failed; + } + + /* read the PCFInfo and update */ + result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CNFAPPCFINFO, + pcfinfo, HFA384x_RID_CNFAPPCFINFO_LEN); + if ( result ) { + WLAN_LOG_INFO("prism2mgmt_start: read(pcfinfo) failed, " + "assume it's " + "not supported, pcf settings ignored.\n"); + goto pcf_skip; + } + if ((msg->cfpollable.data == P80211ENUM_truth_false && + msg->cfpollreq.data == P80211ENUM_truth_false) ) { + pcfinfo->MediumOccupancyLimit = 0; + pcfinfo->CFPPeriod = 0; + pcfinfo->CFPMaxDuration = 0; + pcfinfo->CFPFlags &= host2hfa384x_16((UINT16)~BIT0); + + if ( msg->cfpperiod.status == P80211ENUM_msgitem_status_data_ok || + msg->cfpmaxduration.status == P80211ENUM_msgitem_status_data_ok ) { + WLAN_LOG_WARNING( + "Setting cfpperiod or cfpmaxduration when " + "cfpollable and cfreq are false is pointless.\n"); + } + } + if ((msg->cfpollable.data == P80211ENUM_truth_true || + msg->cfpollreq.data == P80211ENUM_truth_true) ) { + if ( msg->cfpollable.data == P80211ENUM_truth_true) { + pcfinfo->CFPFlags |= host2hfa384x_16((UINT16)BIT0); + } + + if ( msg->cfpperiod.status == P80211ENUM_msgitem_status_data_ok) { + pcfinfo->CFPPeriod = msg->cfpperiod.data; + pcfinfo->CFPPeriod = host2hfa384x_16(pcfinfo->CFPPeriod); + } + + if ( msg->cfpmaxduration.status == P80211ENUM_msgitem_status_data_ok) { + pcfinfo->CFPMaxDuration = msg->cfpmaxduration.data; + pcfinfo->CFPMaxDuration = host2hfa384x_16(pcfinfo->CFPMaxDuration); + pcfinfo->MediumOccupancyLimit = pcfinfo->CFPMaxDuration; + } + } + result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFAPPCFINFO, + pcfinfo, HFA384x_RID_CNFAPPCFINFO_LEN); + if ( result ) { + WLAN_LOG_ERROR("write(pcfinfo) failed.\n"); + goto failed; + } + +pcf_skip: + /* Set the macmode so the frame setup code knows what to do */ + if ( msg->bsstype.data == P80211ENUM_bsstype_infrastructure ) { + wlandev->macmode = WLAN_MACMODE_ESS_AP; + /* lets extend the data length a bit */ + hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN, 2304); + } + + /* Set the BSSID to the same as our MAC */ + memcpy( wlandev->bssid, wlandev->netdev->dev_addr, WLAN_BSSID_LEN); + + /* Enable the Port */ + result = hfa384x_drvr_enable(hw, 0); + if ( result ) { + WLAN_LOG_ERROR("Enable macport failed, result=%d.\n", result); + goto failed; + } + + msg->resultcode.data = P80211ENUM_resultcode_success; + + goto done; +failed: + WLAN_LOG_DEBUG(1, "Failed to set a config option, result=%d\n", result); + msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters; + +done: + result = 0; + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_enable +* +* Start a BSS. Any station can do this for IBSS, only AP for ESS. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ +int prism2mgmt_enable(wlandevice_t *wlandev, void *msgp) +{ + int result = 0; + hfa384x_t *hw = wlandev->priv; + p80211msg_p2req_enable_t *msg = msgp; + DBFENTER; + + if (!hw->ap) { + + /*** STATION ***/ + + /* Ad-Hoc not quite supported on Prism2 */ + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + goto done; + } + + /*** ACCESS POINT ***/ + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + + /* Is the tertiary loaded? */ + if ( hw->cap_sup_sta.id != 5) { + WLAN_LOG_ERROR("AP driver failed to detect AP firmware.\n"); + goto failed; + } + + /* Set the macmode so the frame setup code knows what to do */ + wlandev->macmode = WLAN_MACMODE_ESS_AP; + + /* Set the BSSID to the same as our MAC */ + memcpy( wlandev->bssid, wlandev->netdev->dev_addr, WLAN_BSSID_LEN); + + /* Enable the Port */ + result = hfa384x_drvr_enable(hw, 0); + if ( result ) { + WLAN_LOG_ERROR("Enable macport failed, result=%d.\n", result); + goto failed; + } + + msg->resultcode.data = P80211ENUM_resultcode_success; + + goto done; +failed: + msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters; + +done: + result = 0; + + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_readpda +* +* Collect the PDA data and put it in the message. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +----------------------------------------------------------------*/ +int prism2mgmt_readpda(wlandevice_t *wlandev, void *msgp) +{ + hfa384x_t *hw = wlandev->priv; + p80211msg_p2req_readpda_t *msg = msgp; + int result; + DBFENTER; + + /* We only support collecting the PDA when in the FWLOAD + * state. + */ + if (wlandev->msdstate != WLAN_MSD_FWLOAD) { + WLAN_LOG_ERROR( + "PDA may only be read " + "in the fwload state.\n"); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + } else { + /* Call drvr_readpda(), it handles the auxport enable + * and validating the returned PDA. + */ + result = hfa384x_drvr_readpda( + hw, + msg->pda.data, + HFA384x_PDA_LEN_MAX); + if (result) { + WLAN_LOG_ERROR( + "hfa384x_drvr_readpda() failed, " + "result=%d\n", + result); + + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + msg->resultcode.status = + P80211ENUM_msgitem_status_data_ok; + DBFEXIT; + return 0; + } + msg->pda.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_success; + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + } + + DBFEXIT; + return 0; +} + +/*---------------------------------------------------------------- +* prism2mgmt_readcis +* +* Collect the CIS data and put it in the message. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +----------------------------------------------------------------*/ +int prism2mgmt_readcis(wlandevice_t *wlandev, void *msgp) +{ + int result; + hfa384x_t *hw = wlandev->priv; + p80211msg_p2req_readcis_t *msg = msgp; + + DBFENTER; + + memset(msg->cis.data, 0, sizeof(msg->cis.data)); + + result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CIS, + msg->cis.data, HFA384x_RID_CIS_LEN); + if ( result ) { + WLAN_LOG_INFO("prism2mgmt_readcis: read(cis) failed.\n"); + msg->cis.status = P80211ENUM_msgitem_status_no_value; + msg->resultcode.data = P80211ENUM_resultcode_implementation_failure; + + } + else { + msg->cis.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_success; + } + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + + DBFEXIT; + return 0; +} + +/*---------------------------------------------------------------- +* prism2mgmt_auxport_state +* +* Enables/Disables the card's auxiliary port. Should be called +* before and after a sequence of auxport_read()/auxport_write() +* calls. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +----------------------------------------------------------------*/ +int prism2mgmt_auxport_state(wlandevice_t *wlandev, void *msgp) +{ + p80211msg_p2req_auxport_state_t *msg = msgp; + +#if (WLAN_HOSTIF != WLAN_USB) + hfa384x_t *hw = wlandev->priv; + DBFENTER; + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + if (msg->enable.data == P80211ENUM_truth_true) { + if ( hfa384x_cmd_aux_enable(hw, 0) ) { + msg->resultcode.data = P80211ENUM_resultcode_implementation_failure; + } else { + msg->resultcode.data = P80211ENUM_resultcode_success; + } + } else { + hfa384x_cmd_aux_disable(hw); + msg->resultcode.data = P80211ENUM_resultcode_success; + } + +#else /* !USB */ + DBFENTER; + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + +#endif /* WLAN_HOSTIF != WLAN_USB */ + + DBFEXIT; + return 0; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_auxport_read +* +* Copies data from the card using the auxport. The auxport must +* have previously been enabled. Note: this is not the way to +* do downloads, see the [ram|flash]dl functions. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +----------------------------------------------------------------*/ +int prism2mgmt_auxport_read(wlandevice_t *wlandev, void *msgp) +{ +#if (WLAN_HOSTIF != WLAN_USB) + hfa384x_t *hw = wlandev->priv; + p80211msg_p2req_auxport_read_t *msg = msgp; + UINT32 addr; + UINT32 len; + UINT8* buf; + UINT32 maxlen = sizeof(msg->data.data); + DBFENTER; + + if ( hw->auxen ) { + addr = msg->addr.data; + len = msg->len.data; + buf = msg->data.data; + if ( len <= maxlen ) { /* max read/write size */ + hfa384x_copy_from_aux(hw, addr, HFA384x_AUX_CTL_EXTDS, buf, len); + msg->resultcode.data = P80211ENUM_resultcode_success; + } else { + WLAN_LOG_DEBUG(1,"Attempt to read > maxlen from auxport.\n"); + msg->resultcode.data = P80211ENUM_resultcode_refused; + } + + } else { + msg->resultcode.data = P80211ENUM_resultcode_refused; + } + msg->data.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + + DBFEXIT; + return 0; +#else + DBFENTER; + + WLAN_LOG_ERROR("prism2mgmt_auxport_read: Not supported on USB.\n"); + + DBFEXIT; + return 0; +#endif +} + + +/*---------------------------------------------------------------- +* prism2mgmt_auxport_write +* +* Copies data to the card using the auxport. The auxport must +* have previously been enabled. Note: this is not the way to +* do downloads, see the [ram|flash]dl functions. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +----------------------------------------------------------------*/ +int prism2mgmt_auxport_write(wlandevice_t *wlandev, void *msgp) +{ +#if (WLAN_HOSTIF != WLAN_USB) + hfa384x_t *hw = wlandev->priv; + p80211msg_p2req_auxport_write_t *msg = msgp; + UINT32 addr; + UINT32 len; + UINT8* buf; + UINT32 maxlen = sizeof(msg->data.data); + DBFENTER; + + if ( hw->auxen ) { + addr = msg->addr.data; + len = msg->len.data; + buf = msg->data.data; + if ( len <= maxlen ) { /* max read/write size */ + hfa384x_copy_to_aux(hw, addr, HFA384x_AUX_CTL_EXTDS, buf, len); + } else { + WLAN_LOG_DEBUG(1,"Attempt to write > maxlen from auxport.\n"); + msg->resultcode.data = P80211ENUM_resultcode_refused; + } + + } else { + msg->resultcode.data = P80211ENUM_resultcode_refused; + } + msg->data.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + + DBFEXIT; + return 0; +#else + DBFENTER; + WLAN_LOG_ERROR("prism2mgmt_auxport_read: Not supported on USB.\n"); + DBFEXIT; + return 0; +#endif +} + +/*---------------------------------------------------------------- +* prism2mgmt_low_level +* +* Puts the card into the desired test mode. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +----------------------------------------------------------------*/ +int prism2mgmt_low_level(wlandevice_t *wlandev, void *msgp) +{ + hfa384x_t *hw = wlandev->priv; + p80211msg_p2req_low_level_t *msg = msgp; + hfa384x_metacmd_t cmd; + DBFENTER; + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + + /* call some routine to execute the test command */ + cmd.cmd = (UINT16) msg->command.data; + cmd.parm0 = (UINT16) msg->param0.data; + cmd.parm1 = (UINT16) msg->param1.data; + cmd.parm2 = (UINT16) msg->param2.data; + + hfa384x_drvr_low_level(hw,&cmd); + + msg->resp0.data = (UINT32) cmd.result.resp0; + msg->resp1.data = (UINT32) cmd.result.resp1; + msg->resp2.data = (UINT32) cmd.result.resp2; + + msg->resultcode.data = P80211ENUM_resultcode_success; + + DBFEXIT; + return 0; +} + +/*---------------------------------------------------------------- +* prism2mgmt_test_command +* +* Puts the card into the desired test mode. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +----------------------------------------------------------------*/ +int prism2mgmt_test_command(wlandevice_t *wlandev, void *msgp) +{ + hfa384x_t *hw = wlandev->priv; + p80211msg_p2req_test_command_t *msg = msgp; + hfa384x_metacmd_t cmd; + + DBFENTER; + + cmd.cmd = ((UINT16) msg->testcode.data) << 8 | 0x38; + cmd.parm0 = (UINT16) msg->testparam.data; + cmd.parm1 = 0; + cmd.parm2 = 0; + + /* call some routine to execute the test command */ + + hfa384x_drvr_low_level(hw,&cmd); + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_success; + + msg->status.status = P80211ENUM_msgitem_status_data_ok; + msg->status.data = cmd.result.status; + msg->resp0.status = P80211ENUM_msgitem_status_data_ok; + msg->resp0.data = cmd.result.resp0; + msg->resp1.status = P80211ENUM_msgitem_status_data_ok; + msg->resp1.data = cmd.result.resp1; + msg->resp2.status = P80211ENUM_msgitem_status_data_ok; + msg->resp2.data = cmd.result.resp2; + + DBFEXIT; + return 0; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_mmi_read +* +* Read from one of the MMI registers. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +----------------------------------------------------------------*/ +int prism2mgmt_mmi_read(wlandevice_t *wlandev, void *msgp) +{ + hfa384x_t *hw = wlandev->priv; + p80211msg_p2req_mmi_read_t *msg = msgp; + UINT32 resp = 0; + + DBFENTER; + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + + /* call some routine to execute the test command */ + + hfa384x_drvr_mmi_read(hw, msg->addr.data, &resp); + + /* I'm not sure if this is "architecturally" correct, but it + is expedient. */ + + msg->value.status = P80211ENUM_msgitem_status_data_ok; + msg->value.data = resp; + msg->resultcode.data = P80211ENUM_resultcode_success; + + DBFEXIT; + return 0; +} + +/*---------------------------------------------------------------- +* prism2mgmt_mmi_write +* +* Write a data value to one of the MMI registers. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +----------------------------------------------------------------*/ +int prism2mgmt_mmi_write(wlandevice_t *wlandev, void *msgp) +{ + hfa384x_t *hw = wlandev->priv; + p80211msg_p2req_mmi_write_t *msg = msgp; + DBFENTER; + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + + /* call some routine to execute the test command */ + + hfa384x_drvr_mmi_write(hw, msg->addr.data, msg->data.data); + + msg->resultcode.data = P80211ENUM_resultcode_success; + + DBFEXIT; + return 0; +} + +/*---------------------------------------------------------------- +* prism2mgmt_ramdl_state +* +* Establishes the beginning/end of a card RAM download session. +* +* It is expected that the ramdl_write() function will be called +* one or more times between the 'enable' and 'disable' calls to +* this function. +* +* Note: This function should not be called when a mac comm port +* is active. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +----------------------------------------------------------------*/ +int prism2mgmt_ramdl_state(wlandevice_t *wlandev, void *msgp) +{ + hfa384x_t *hw = wlandev->priv; + p80211msg_p2req_ramdl_state_t *msg = msgp; + DBFENTER; + + if (wlandev->msdstate != WLAN_MSD_FWLOAD) { + WLAN_LOG_ERROR( + "ramdl_state(): may only be called " + "in the fwload state.\n"); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + DBFEXIT; + return 0; + } + + /* + ** Note: Interrupts are locked out if this is an AP and are NOT + ** locked out if this is a station. + */ + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + if ( msg->enable.data == P80211ENUM_truth_true ) { + if ( hfa384x_drvr_ramdl_enable(hw, msg->exeaddr.data) ) { + msg->resultcode.data = P80211ENUM_resultcode_implementation_failure; + } else { + msg->resultcode.data = P80211ENUM_resultcode_success; + } + } else { + hfa384x_drvr_ramdl_disable(hw); + msg->resultcode.data = P80211ENUM_resultcode_success; + } + + DBFEXIT; + return 0; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_ramdl_write +* +* Writes a buffer to the card RAM using the download state. This +* is for writing code to card RAM. To just read or write raw data +* use the aux functions. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +----------------------------------------------------------------*/ +int prism2mgmt_ramdl_write(wlandevice_t *wlandev, void *msgp) +{ + hfa384x_t *hw = wlandev->priv; + p80211msg_p2req_ramdl_write_t *msg = msgp; + UINT32 addr; + UINT32 len; + UINT8 *buf; + DBFENTER; + + if (wlandev->msdstate != WLAN_MSD_FWLOAD) { + WLAN_LOG_ERROR( + "ramdl_write(): may only be called " + "in the fwload state.\n"); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + DBFEXIT; + return 0; + } + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + /* first validate the length */ + if ( msg->len.data > sizeof(msg->data.data) ) { + msg->resultcode.status = P80211ENUM_resultcode_invalid_parameters; + return 0; + } + /* call the hfa384x function to do the write */ + addr = msg->addr.data; + len = msg->len.data; + buf = msg->data.data; + if ( hfa384x_drvr_ramdl_write(hw, addr, buf, len) ) { + msg->resultcode.data = P80211ENUM_resultcode_refused; + + } + msg->resultcode.data = P80211ENUM_resultcode_success; + + DBFEXIT; + return 0; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_flashdl_state +* +* Establishes the beginning/end of a card Flash download session. +* +* It is expected that the flashdl_write() function will be called +* one or more times between the 'enable' and 'disable' calls to +* this function. +* +* Note: This function should not be called when a mac comm port +* is active. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +----------------------------------------------------------------*/ +int prism2mgmt_flashdl_state(wlandevice_t *wlandev, void *msgp) +{ + int result = 0; + hfa384x_t *hw = wlandev->priv; + p80211msg_p2req_flashdl_state_t *msg = msgp; + DBFENTER; + + if (wlandev->msdstate != WLAN_MSD_FWLOAD) { + WLAN_LOG_ERROR( + "flashdl_state(): may only be called " + "in the fwload state.\n"); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + DBFEXIT; + return 0; + } + + /* + ** Note: Interrupts are locked out if this is an AP and are NOT + ** locked out if this is a station. + */ + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + if ( msg->enable.data == P80211ENUM_truth_true ) { + if ( hfa384x_drvr_flashdl_enable(hw) ) { + msg->resultcode.data = P80211ENUM_resultcode_implementation_failure; + } else { + msg->resultcode.data = P80211ENUM_resultcode_success; + } + } else { + hfa384x_drvr_flashdl_disable(hw); + msg->resultcode.data = P80211ENUM_resultcode_success; + /* NOTE: At this point, the MAC is in the post-reset + * state and the driver is in the fwload state. + * We need to get the MAC back into the fwload + * state. To do this, we set the nsdstate to HWPRESENT + * and then call the ifstate function to redo everything + * that got us into the fwload state. + */ + wlandev->msdstate = WLAN_MSD_HWPRESENT; + result = prism2sta_ifstate(wlandev, P80211ENUM_ifstate_fwload); + if (result != P80211ENUM_resultcode_success) { + WLAN_LOG_ERROR("prism2sta_ifstate(fwload) failed," + "P80211ENUM_resultcode=%d\n", result); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + result = -1; + } + } + + DBFEXIT; + return 0; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_flashdl_write +* +* +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +----------------------------------------------------------------*/ +int prism2mgmt_flashdl_write(wlandevice_t *wlandev, void *msgp) +{ + hfa384x_t *hw = wlandev->priv; + p80211msg_p2req_flashdl_write_t *msg = msgp; + UINT32 addr; + UINT32 len; + UINT8 *buf; + DBFENTER; + + if (wlandev->msdstate != WLAN_MSD_FWLOAD) { + WLAN_LOG_ERROR( + "flashdl_write(): may only be called " + "in the fwload state.\n"); + msg->resultcode.data = + P80211ENUM_resultcode_implementation_failure; + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + DBFEXIT; + return 0; + } + + /* + ** Note: Interrupts are locked out if this is an AP and are NOT + ** locked out if this is a station. + */ + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + /* first validate the length */ + if ( msg->len.data > sizeof(msg->data.data) ) { + msg->resultcode.status = + P80211ENUM_resultcode_invalid_parameters; + return 0; + } + /* call the hfa384x function to do the write */ + addr = msg->addr.data; + len = msg->len.data; + buf = msg->data.data; + if ( hfa384x_drvr_flashdl_write(hw, addr, buf, len) ) { + msg->resultcode.data = P80211ENUM_resultcode_refused; + + } + msg->resultcode.data = P80211ENUM_resultcode_success; + + DBFEXIT; + return 0; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_dump_state +* +* Dumps the driver's and hardware's current state via the kernel +* log at KERN_NOTICE level. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +----------------------------------------------------------------*/ +int prism2mgmt_dump_state(wlandevice_t *wlandev, void *msgp) +{ + p80211msg_p2req_dump_state_t *msg = msgp; + int result = 0; + +#if (WLAN_HOSTIF != WLAN_USB) + hfa384x_t *hw = wlandev->priv; + UINT16 auxbuf[15]; + DBFENTER; + + WLAN_LOG_NOTICE("prism2 driver and hardware state:\n"); + if ( (result = hfa384x_cmd_aux_enable(hw, 0)) ) { + WLAN_LOG_ERROR("aux_enable failed, result=%d\n", result); + goto failed; + } + hfa384x_copy_from_aux(hw, + 0x01e2, + HFA384x_AUX_CTL_EXTDS, + auxbuf, + sizeof(auxbuf)); + hfa384x_cmd_aux_disable(hw); + WLAN_LOG_NOTICE(" cmac: FreeBlocks=%d\n", auxbuf[5]); + WLAN_LOG_NOTICE(" cmac: IntEn=0x%02x EvStat=0x%02x\n", + hfa384x_getreg(hw, HFA384x_INTEN), + hfa384x_getreg(hw, HFA384x_EVSTAT)); + + #ifdef USE_FID_STACK + WLAN_LOG_NOTICE(" drvr: txfid_top=%d stacksize=%d\n", + hw->txfid_top,HFA384x_DRVR_FIDSTACKLEN_MAX); + #else + WLAN_LOG_NOTICE(" drvr: txfid_head=%d txfid_tail=%d txfid_N=%d\n", + hw->txfid_head, hw->txfid_tail, hw->txfid_N); + #endif + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_success; + +#else /* (WLAN_HOSTIF == WLAN_USB) */ + + DBFENTER; + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + goto failed; + +#endif /* (WLAN_HOSTIF != WLAN_USB) */ + +failed: + DBFEXIT; + return result; +} + +/*---------------------------------------------------------------- +* prism2mgmt_channel_info +* +* Issues a ChannelInfoRequest. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +----------------------------------------------------------------*/ +int prism2mgmt_channel_info(wlandevice_t *wlandev, void *msgp) +{ + p80211msg_p2req_channel_info_t *msg=msgp; + hfa384x_t *hw = wlandev->priv; + int result, i, n=0; + UINT16 channel_mask=0; + hfa384x_ChannelInfoRequest_data_t chinforeq; + // unsigned long now; + + DBFENTER; + + if (!hw->ap) { + + /*** STATION ***/ + + /* Not supported in STA f/w */ + P80211_SET_INT(msg->resultcode, P80211ENUM_resultcode_not_supported); + goto done; + } + + /*** ACCESS POINT ***/ + +#define CHINFO_TIMEOUT 2 + + P80211_SET_INT(msg->resultcode, P80211ENUM_resultcode_success); + + /* setting default value for channellist = all channels */ + if (!msg->channellist.data) { + P80211_SET_INT(msg->channellist, 0x00007FFE); + } + /* setting default value for channeldwelltime = 100 ms */ + if (!msg->channeldwelltime.data) { + P80211_SET_INT(msg->channeldwelltime, 100); + } + channel_mask = (UINT16) (msg->channellist.data >> 1); + for (i=0, n=0; i < 14; i++) { + if (channel_mask & (1<numchinfo, n); + chinforeq.channelList = host2hfa384x_16(channel_mask); + chinforeq.channelDwellTime = host2hfa384x_16(msg->channeldwelltime.data); + + atomic_set(&hw->channel_info.done, 1); + + result = hfa384x_drvr_setconfig( hw, HFA384x_RID_CHANNELINFOREQUEST, + &chinforeq, HFA384x_RID_CHANNELINFOREQUEST_LEN); + if ( result ) { + WLAN_LOG_ERROR("setconfig(CHANNELINFOREQUEST) failed. result=%d\n", + result); + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + goto done; + } + /* + now = jiffies; + while (atomic_read(&hw->channel_info.done) != 1) { + if ((jiffies - now) > CHINFO_TIMEOUT*HZ) { + WLAN_LOG_NOTICE("ChannelInfo results not received in %d seconds, aborting.\n", + CHINFO_TIMEOUT); + msg->resultcode.data = P80211ENUM_resultcode_timeout; + goto done; + } + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/4); + current->state = TASK_RUNNING; + } + */ + +done: + + DBFEXIT; + return 0; +} + +/*---------------------------------------------------------------- +* prism2mgmt_channel_info_results +* +* Returns required ChannelInfo result. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +----------------------------------------------------------------*/ +int prism2mgmt_channel_info_results(wlandevice_t *wlandev, void *msgp) +{ + hfa384x_t *hw = wlandev->priv; + + p80211msg_p2req_channel_info_results_t *msg=msgp; + int result=0; + int channel; + + DBFENTER; + + if (!hw->ap) { + + /*** STATION ***/ + + /* Not supported in STA f/w */ + P80211_SET_INT(msg->resultcode, P80211ENUM_resultcode_not_supported); + goto done; + } + + /*** ACCESS POINT ***/ + + switch (atomic_read(&hw->channel_info.done)) { + case 0: msg->resultcode.status = P80211ENUM_msgitem_status_no_value; + goto done; + case 1: msg->resultcode.status = P80211ENUM_msgitem_status_incomplete_itemdata; + goto done; + } + + P80211_SET_INT(msg->resultcode, P80211ENUM_resultcode_success); + channel=msg->channel.data-1; + + if (channel < 0 || ! (hw->channel_info.results.scanchannels & 1<resultcode.data = P80211ENUM_resultcode_invalid_parameters; + goto done; + } + WLAN_LOG_DEBUG(2, "chinfo_results: channel %d, avg/peak level=%d/%d dB, active=%d\n", + channel+1, + hw->channel_info.results.result[channel].anl, + hw->channel_info.results.result[channel].pnl, + hw->channel_info.results.result[channel].active + ); + P80211_SET_INT(msg->avgnoiselevel, hw->channel_info.results.result[channel].anl); + P80211_SET_INT(msg->peaknoiselevel, hw->channel_info.results.result[channel].pnl); + P80211_SET_INT(msg->bssactive, hw->channel_info.results.result[channel].active & + HFA384x_CHINFORESULT_BSSACTIVE + ? P80211ENUM_truth_true + : P80211ENUM_truth_false) ; + P80211_SET_INT(msg->pcfactive, hw->channel_info.results.result[channel].active & + HFA384x_CHINFORESULT_PCFACTIVE + ? P80211ENUM_truth_true + : P80211ENUM_truth_false) ; + +done: + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_autojoin +* +* Associate with an ESS. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ +int prism2mgmt_autojoin(wlandevice_t *wlandev, void *msgp) +{ + hfa384x_t *hw = wlandev->priv; + int result = 0; + UINT16 reg; + UINT16 port_type; + p80211msg_lnxreq_autojoin_t *msg = msgp; + p80211pstrd_t *pstr; + UINT8 bytebuf[256]; + hfa384x_bytestr_t *p2bytestr = (hfa384x_bytestr_t*)bytebuf; + DBFENTER; + + wlandev->macmode = WLAN_MACMODE_NONE; + + /* Set the SSID */ + memcpy(&wlandev->ssid, &msg->ssid.data, sizeof(msg->ssid.data)); + + if (hw->ap) { + + /*** ACCESS POINT ***/ + + /* Never supported on AP */ + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_not_supported; + goto done; + } + + /* Disable the Port */ + hfa384x_drvr_disable(hw, 0); + + /*** STATION ***/ + /* Set the TxRates */ + hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, 0x000f); + + /* Set the auth type */ + if ( msg->authtype.data == P80211ENUM_authalg_sharedkey ) { + reg = HFA384x_CNFAUTHENTICATION_SHAREDKEY; + } else { + reg = HFA384x_CNFAUTHENTICATION_OPENSYSTEM; + } + hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAUTHENTICATION, reg); + + /* Set the ssid */ + memset(bytebuf, 0, 256); + pstr = (p80211pstrd_t*)&(msg->ssid.data); + prism2mgmt_pstr2bytestr(p2bytestr, pstr); + result = hfa384x_drvr_setconfig( + hw, HFA384x_RID_CNFDESIREDSSID, + bytebuf, HFA384x_RID_CNFDESIREDSSID_LEN); +#if 0 + /* we can use the new-fangled auto-unknown mode if the firmware + is 1.3.3 or newer */ + if (HFA384x_FIRMARE_VERSION(hw->ident_sta_fw.major, + hw->ident_sta_fw.minor, + hw->ident_sta_fw.variant) >= + HFA384x_FIRMWARE_VERSION(1,3,3)) { + /* Set up the IBSS options */ + reg = HFA384x_CREATEIBSS_JOINESS_JOINCREATEIBSS; + hfa384x_drvr_setconfig16(hw, HFA384x_RID_CREATEIBSS, reg); + + /* Set the PortType */ + port_type = HFA384x_PORTTYPE_IBSS; + } else { + port_type = HFA384x_PORTTYPE_BSS; + } +#else + port_type = HFA384x_PORTTYPE_BSS; +#endif + /* Set the PortType */ + hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, port_type); + + /* Enable the Port */ + hfa384x_drvr_enable(hw, 0); + + /* Set the resultcode */ + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + msg->resultcode.data = P80211ENUM_resultcode_success; + +done: + DBFEXIT; + return result; +} + + +/*---------------------------------------------------------------- +* prism2mgmt_wlansniff +* +* Start or stop sniffing. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ +int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) +{ + int result = 0; + p80211msg_lnxreq_wlansniff_t *msg = msgp; + + hfa384x_t *hw = wlandev->priv; + UINT16 word; + + DBFENTER; + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + switch (msg->enable.data) + { + case P80211ENUM_truth_false: + /* Confirm that we're in monitor mode */ + if ( wlandev->netdev->type == ARPHRD_ETHER ) { + msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters; + result = 0; + goto exit; + } + /* Disable monitor mode */ + result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_DISABLE); + if ( result ) { + WLAN_LOG_DEBUG(1, + "failed to disable monitor mode, result=%d\n", + result); + goto failed; + } + /* Disable port 0 */ + result = hfa384x_drvr_disable(hw, 0); + if ( result ) { + WLAN_LOG_DEBUG(1, + "failed to disable port 0 after sniffing, result=%d\n", + result); + goto failed; + } + /* Clear the driver state */ + wlandev->netdev->type = ARPHRD_ETHER; + + /* Restore the wepflags */ + result = hfa384x_drvr_setconfig16(hw, + HFA384x_RID_CNFWEPFLAGS, + hw->presniff_wepflags); + if ( result ) { + WLAN_LOG_DEBUG(1, + "failed to restore wepflags=0x%04x, result=%d\n", + hw->presniff_wepflags, + result); + goto failed; + } + + /* Set the port to its prior type and enable (if necessary) */ + if (hw->presniff_port_type != 0 ) { + word = hw->presniff_port_type; + result = hfa384x_drvr_setconfig16(hw, + HFA384x_RID_CNFPORTTYPE, word); + if ( result ) { + WLAN_LOG_DEBUG(1, + "failed to restore porttype, result=%d\n", + result); + goto failed; + } + + /* Enable the port */ + result = hfa384x_drvr_enable(hw, 0); + if ( result ) { + WLAN_LOG_DEBUG(1, "failed to enable port to presniff setting, result=%d\n", result); + goto failed; + } + } else { + result = hfa384x_drvr_disable(hw, 0); + + } + + WLAN_LOG_INFO("monitor mode disabled\n"); + msg->resultcode.data = P80211ENUM_resultcode_success; + result = 0; + goto exit; + break; + case P80211ENUM_truth_true: + /* Disable the port (if enabled), only check Port 0 */ + if ( hw->port_enabled[0]) { + if (wlandev->netdev->type == ARPHRD_ETHER) { + /* Save macport 0 state */ + result = hfa384x_drvr_getconfig16(hw, + HFA384x_RID_CNFPORTTYPE, + &(hw->presniff_port_type)); + if ( result ) { + WLAN_LOG_DEBUG(1,"failed to read porttype, result=%d\n", result); + goto failed; + } + /* Save the wepflags state */ + result = hfa384x_drvr_getconfig16(hw, + HFA384x_RID_CNFWEPFLAGS, + &(hw->presniff_wepflags)); + if ( result ) { + WLAN_LOG_DEBUG(1,"failed to read wepflags, result=%d\n", result); + goto failed; + } + hfa384x_drvr_stop(hw); + result = hfa384x_drvr_start(hw); + if ( result ) { + WLAN_LOG_DEBUG(1, + "failed to restart the card for sniffing, result=%d\n", + result); + goto failed; + } + } else { + /* Disable the port */ + result = hfa384x_drvr_disable(hw, 0); + if ( result ) { + WLAN_LOG_DEBUG(1, + "failed to enable port for sniffing, result=%d\n", + result); + goto failed; + } + } + } else { + hw->presniff_port_type = 0; + } + + /* Set the channel we wish to sniff */ + word = msg->channel.data; + result = hfa384x_drvr_setconfig16(hw, + HFA384x_RID_CNFOWNCHANNEL, word); + hw->sniff_channel=word; + + if ( result ) { + WLAN_LOG_DEBUG(1, + "failed to set channel %d, result=%d\n", + word, + result); + goto failed; + } + + /* Now if we're already sniffing, we can skip the rest */ + if (wlandev->netdev->type != ARPHRD_ETHER) { + /* Set the port type to pIbss */ + word = HFA384x_PORTTYPE_PSUEDOIBSS; + result = hfa384x_drvr_setconfig16(hw, + HFA384x_RID_CNFPORTTYPE, word); + if ( result ) { + WLAN_LOG_DEBUG(1, + "failed to set porttype %d, result=%d\n", + word, + result); + goto failed; + } + if ((msg->keepwepflags.status == P80211ENUM_msgitem_status_data_ok) && (msg->keepwepflags.data != P80211ENUM_truth_true)) { + /* Set the wepflags for no decryption */ + word = HFA384x_WEPFLAGS_DISABLE_TXCRYPT | + HFA384x_WEPFLAGS_DISABLE_RXCRYPT; + result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFWEPFLAGS, word); + } + + if ( result ) { + WLAN_LOG_DEBUG(1, + "failed to set wepflags=0x%04x, result=%d\n", + word, + result); + goto failed; + } + } + + /* Do we want to strip the FCS in monitor mode? */ + if ((msg->stripfcs.status == P80211ENUM_msgitem_status_data_ok) && (msg->stripfcs.data == P80211ENUM_truth_true)) { + hw->sniff_fcs = 0; + } else { + hw->sniff_fcs = 1; + } + + /* Do we want to truncate the packets? */ + if (msg->packet_trunc.status == P80211ENUM_msgitem_status_data_ok) { + hw->sniff_truncate = msg->packet_trunc.data; + } else { + hw->sniff_truncate = 0; + } + + /* Enable the port */ + result = hfa384x_drvr_enable(hw, 0); + if ( result ) { + WLAN_LOG_DEBUG(1, + "failed to enable port for sniffing, result=%d\n", + result); + goto failed; + } + /* Enable monitor mode */ + result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_ENABLE); + if ( result ) { + WLAN_LOG_DEBUG(1, + "failed to enable monitor mode, result=%d\n", + result); + goto failed; + } + + if (wlandev->netdev->type == ARPHRD_ETHER) { + WLAN_LOG_INFO("monitor mode enabled\n"); + } + + /* Set the driver state */ + /* Do we want the prism2 header? */ + if ((msg->prismheader.status == P80211ENUM_msgitem_status_data_ok) && (msg->prismheader.data == P80211ENUM_truth_true)) { + hw->sniffhdr = 0; + wlandev->netdev->type = ARPHRD_IEEE80211_PRISM; + } else if ((msg->wlanheader.status == P80211ENUM_msgitem_status_data_ok) && (msg->wlanheader.data == P80211ENUM_truth_true)) { + hw->sniffhdr = 1; + wlandev->netdev->type = ARPHRD_IEEE80211_PRISM; + } else { + wlandev->netdev->type = ARPHRD_IEEE80211; + } + + msg->resultcode.data = P80211ENUM_resultcode_success; + result = 0; + goto exit; + break; + default: + msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters; + result = 0; + goto exit; + break; + } + +failed: + msg->resultcode.data = P80211ENUM_resultcode_refused; + result = 0; +exit: + + DBFEXIT; + return result; +} --- linux-2.6.27.orig/ubuntu/misc/wireless/prism2_usb/BOM +++ linux-2.6.27/ubuntu/misc/wireless/prism2_usb/BOM @@ -0,0 +1,15 @@ +# Jul 29, 2008 +# Copied from the linux-wlan-ng 0.2.9+dfsg source package + +Run "make config" then "make" in src/mkmeta + +cp -a src/prism2/driver $KERNEL/ubuntu/misc/wireless/prism2_usb +cp -a src/p80211 $KERNEL/ubuntu/misc/wireless/ +cp -a src/include/wlan $KERNEL/ubuntu/misc/wireless/p80211/ +cp -a src/prism2/include/prism2 $KERNEL/ubuntu/misc/wireless/prism2_usb/ + +Strip down prism2_usb/Makefile and p80211/Makefile +rm prism2_usb/prism2_{cs,pci,plx} + +Use dev_net_set() for 2.6.26 in p80211/p80211netdev.c:wlan_setup() + --- linux-2.6.27.orig/ubuntu/misc/wireless/prism2_usb/prism2/hfa384x.h +++ linux-2.6.27/ubuntu/misc/wireless/prism2_usb/prism2/hfa384x.h @@ -0,0 +1,3067 @@ +/* src/prism2/include/prism2/hfa384x.h +* +* Defines the constants and data structures for the hfa384x +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* [Implementation and usage notes] +* +* [References] +* CW10 Programmer's Manual v1.5 +* IEEE 802.11 D10.0 +* +* -------------------------------------------------------------------- +*/ + +#ifndef _HFA384x_H +#define _HFA384x_H + +/*=============================================================*/ +#define HFA384x_FIRMWARE_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) + +#define HFA384x_LEVEL_TO_dBm(v) (0x100 + (v) * 100 / 255 - 100) + +/*------ Constants --------------------------------------------*/ +/*--- Mins & Maxs -----------------------------------*/ +#define HFA384x_CMD_ALLOC_LEN_MIN ((UINT16)4) +#define HFA384x_CMD_ALLOC_LEN_MAX ((UINT16)2400) +#define HFA384x_BAP_DATALEN_MAX ((UINT16)4096) +#define HFA384x_BAP_OFFSET_MAX ((UINT16)4096) +#define HFA384x_PORTID_MAX ((UINT16)7) +#define HFA384x_NUMPORTS_MAX ((UINT16)(HFA384x_PORTID_MAX+1)) +#define HFA384x_PDR_LEN_MAX ((UINT16)512) /* in bytes, from EK */ +#define HFA384x_PDA_RECS_MAX ((UINT16)200) /* a guess */ +#define HFA384x_PDA_LEN_MAX ((UINT16)1024) /* in bytes, from EK */ +#define HFA384x_SCANRESULT_MAX ((UINT16)31) +#define HFA384x_HSCANRESULT_MAX ((UINT16)31) +#define HFA384x_CHINFORESULT_MAX ((UINT16)16) +#define HFA384x_DRVR_FIDSTACKLEN_MAX (10) +#define HFA384x_DRVR_TXBUF_MAX (sizeof(hfa384x_tx_frame_t) + \ + WLAN_DATA_MAXLEN - \ + WLAN_WEP_IV_LEN - \ + WLAN_WEP_ICV_LEN + 2) +#define HFA384x_DRVR_MAGIC (0x4a2d) +#define HFA384x_INFODATA_MAXLEN (sizeof(hfa384x_infodata_t)) +#define HFA384x_INFOFRM_MAXLEN (sizeof(hfa384x_InfFrame_t)) +#define HFA384x_RID_GUESSING_MAXLEN 2048 /* I'm not really sure */ +#define HFA384x_RIDDATA_MAXLEN HFA384x_RID_GUESSING_MAXLEN +#define HFA384x_USB_RWMEM_MAXLEN 2048 + +/*--- Support Constants -----------------------------*/ +#define HFA384x_BAP_PROC ((UINT16)0) +#define HFA384x_BAP_INT ((UINT16)1) +#define HFA384x_PORTTYPE_IBSS ((UINT16)0) +#define HFA384x_PORTTYPE_BSS ((UINT16)1) +#define HFA384x_PORTTYPE_WDS ((UINT16)2) +#define HFA384x_PORTTYPE_PSUEDOIBSS ((UINT16)3) +#define HFA384x_PORTTYPE_HOSTAP ((UINT16)6) +#define HFA384x_WEPFLAGS_PRIVINVOKED ((UINT16)BIT0) +#define HFA384x_WEPFLAGS_EXCLUDE ((UINT16)BIT1) +#define HFA384x_WEPFLAGS_DISABLE_TXCRYPT ((UINT16)BIT4) +#define HFA384x_WEPFLAGS_DISABLE_RXCRYPT ((UINT16)BIT7) +#define HFA384x_WEPFLAGS_DISALLOW_MIXED ((UINT16)BIT11) +#define HFA384x_WEPFLAGS_IV_INTERVAL1 ((UINT16)0) +#define HFA384x_WEPFLAGS_IV_INTERVAL10 ((UINT16)BIT5) +#define HFA384x_WEPFLAGS_IV_INTERVAL50 ((UINT16)BIT6) +#define HFA384x_WEPFLAGS_IV_INTERVAL100 ((UINT16)(BIT5 | BIT6)) +#define HFA384x_WEPFLAGS_FIRMWARE_WPA ((UINT16)BIT8) +#define HFA384x_WEPFLAGS_HOST_MIC ((UINT16)BIT9) +#define HFA384x_ROAMMODE_FWSCAN_FWROAM ((UINT16)1) +#define HFA384x_ROAMMODE_FWSCAN_HOSTROAM ((UINT16)2) +#define HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM ((UINT16)3) +#define HFA384x_PORTSTATUS_DISABLED ((UINT16)1) +#define HFA384x_PORTSTATUS_INITSRCH ((UINT16)2) +#define HFA384x_PORTSTATUS_CONN_IBSS ((UINT16)3) +#define HFA384x_PORTSTATUS_CONN_ESS ((UINT16)4) +#define HFA384x_PORTSTATUS_OOR_ESS ((UINT16)5) +#define HFA384x_PORTSTATUS_CONN_WDS ((UINT16)6) +#define HFA384x_PORTSTATUS_HOSTAP ((UINT16)8) +#define HFA384x_RATEBIT_1 ((UINT16)1) +#define HFA384x_RATEBIT_2 ((UINT16)2) +#define HFA384x_RATEBIT_5dot5 ((UINT16)4) +#define HFA384x_RATEBIT_11 ((UINT16)8) + +/*--- Just some symbolic names for legibility -------*/ +#define HFA384x_TXCMD_NORECL ((UINT16)0) +#define HFA384x_TXCMD_RECL ((UINT16)1) + +/*--- MAC Internal memory constants and macros ------*/ +/* masks and macros used to manipulate MAC internal memory addresses. */ +/* MAC internal memory addresses are 23 bit quantities. The MAC uses + * a paged address space where the upper 16 bits are the page number + * and the lower 7 bits are the offset. There are various Host API + * elements that require two 16-bit quantities to specify a MAC + * internal memory address. Unfortunately, some of the API's use a + * page/offset format where the offset value is JUST the lower seven + * bits and the page is the remaining 16 bits. Some of the API's + * assume that the 23 bit address has been split at the 16th bit. We + * refer to these two formats as AUX format and CMD format. The + * macros below help handle some of this. + */ + +/* Handy constant */ +#define HFA384x_ADDR_AUX_OFF_MAX ((UINT16)0x007f) + +/* Mask bits for discarding unwanted pieces in a flat address */ +#define HFA384x_ADDR_FLAT_AUX_PAGE_MASK (0x007fff80) +#define HFA384x_ADDR_FLAT_AUX_OFF_MASK (0x0000007f) +#define HFA384x_ADDR_FLAT_CMD_PAGE_MASK (0xffff0000) +#define HFA384x_ADDR_FLAT_CMD_OFF_MASK (0x0000ffff) + +/* Mask bits for discarding unwanted pieces in AUX format 16-bit address parts */ +#define HFA384x_ADDR_AUX_PAGE_MASK (0xffff) +#define HFA384x_ADDR_AUX_OFF_MASK (0x007f) + +/* Mask bits for discarding unwanted pieces in CMD format 16-bit address parts */ +#define HFA384x_ADDR_CMD_PAGE_MASK (0x007f) +#define HFA384x_ADDR_CMD_OFF_MASK (0xffff) + +/* Make a 32-bit flat address from AUX format 16-bit page and offset */ +#define HFA384x_ADDR_AUX_MKFLAT(p,o) \ + (((UINT32)(((UINT16)(p))&HFA384x_ADDR_AUX_PAGE_MASK)) <<7) | \ + ((UINT32)(((UINT16)(o))&HFA384x_ADDR_AUX_OFF_MASK)) + +/* Make a 32-bit flat address from CMD format 16-bit page and offset */ +#define HFA384x_ADDR_CMD_MKFLAT(p,o) \ + (((UINT32)(((UINT16)(p))&HFA384x_ADDR_CMD_PAGE_MASK)) <<16) | \ + ((UINT32)(((UINT16)(o))&HFA384x_ADDR_CMD_OFF_MASK)) + +/* Make AUX format offset and page from a 32-bit flat address */ +#define HFA384x_ADDR_AUX_MKPAGE(f) \ + ((UINT16)((((UINT32)(f))&HFA384x_ADDR_FLAT_AUX_PAGE_MASK)>>7)) +#define HFA384x_ADDR_AUX_MKOFF(f) \ + ((UINT16)(((UINT32)(f))&HFA384x_ADDR_FLAT_AUX_OFF_MASK)) + +/* Make CMD format offset and page from a 32-bit flat address */ +#define HFA384x_ADDR_CMD_MKPAGE(f) \ + ((UINT16)((((UINT32)(f))&HFA384x_ADDR_FLAT_CMD_PAGE_MASK)>>16)) +#define HFA384x_ADDR_CMD_MKOFF(f) \ + ((UINT16)(((UINT32)(f))&HFA384x_ADDR_FLAT_CMD_OFF_MASK)) + +/*--- Aux register masks/tests ----------------------*/ +/* Some of the upper bits of the AUX offset register are used to */ +/* select address space. */ +#define HFA384x_AUX_CTL_EXTDS (0x00) +#define HFA384x_AUX_CTL_NV (0x01) +#define HFA384x_AUX_CTL_PHY (0x02) +#define HFA384x_AUX_CTL_ICSRAM (0x03) + +/* Make AUX register offset and page values from a flat address */ +#define HFA384x_AUX_MKOFF(f, c) \ + (HFA384x_ADDR_AUX_MKOFF(f) | (((UINT16)(c))<<12)) +#define HFA384x_AUX_MKPAGE(f) HFA384x_ADDR_AUX_MKPAGE(f) + + +/*--- Controller Memory addresses -------------------*/ +#define HFA3842_PDA_BASE (0x007f0000UL) +#define HFA3841_PDA_BASE (0x003f0000UL) +#define HFA3841_PDA_BOGUS_BASE (0x00390000UL) + +/*--- Driver Download states -----------------------*/ +#define HFA384x_DLSTATE_DISABLED 0 +#define HFA384x_DLSTATE_RAMENABLED 1 +#define HFA384x_DLSTATE_FLASHENABLED 2 +#define HFA384x_DLSTATE_FLASHWRITTEN 3 +#define HFA384x_DLSTATE_FLASHWRITEPENDING 4 +#define HFA384x_DLSTATE_GENESIS 5 + +/*--- Register I/O offsets --------------------------*/ +#if ((WLAN_HOSTIF == WLAN_PCMCIA) || (WLAN_HOSTIF == WLAN_PLX)) + +#define HFA384x_CMD_OFF (0x00) +#define HFA384x_PARAM0_OFF (0x02) +#define HFA384x_PARAM1_OFF (0x04) +#define HFA384x_PARAM2_OFF (0x06) +#define HFA384x_STATUS_OFF (0x08) +#define HFA384x_RESP0_OFF (0x0A) +#define HFA384x_RESP1_OFF (0x0C) +#define HFA384x_RESP2_OFF (0x0E) +#define HFA384x_INFOFID_OFF (0x10) +#define HFA384x_RXFID_OFF (0x20) +#define HFA384x_ALLOCFID_OFF (0x22) +#define HFA384x_TXCOMPLFID_OFF (0x24) +#define HFA384x_SELECT0_OFF (0x18) +#define HFA384x_OFFSET0_OFF (0x1C) +#define HFA384x_DATA0_OFF (0x36) +#define HFA384x_SELECT1_OFF (0x1A) +#define HFA384x_OFFSET1_OFF (0x1E) +#define HFA384x_DATA1_OFF (0x38) +#define HFA384x_EVSTAT_OFF (0x30) +#define HFA384x_INTEN_OFF (0x32) +#define HFA384x_EVACK_OFF (0x34) +#define HFA384x_CONTROL_OFF (0x14) +#define HFA384x_SWSUPPORT0_OFF (0x28) +#define HFA384x_SWSUPPORT1_OFF (0x2A) +#define HFA384x_SWSUPPORT2_OFF (0x2C) +#define HFA384x_AUXPAGE_OFF (0x3A) +#define HFA384x_AUXOFFSET_OFF (0x3C) +#define HFA384x_AUXDATA_OFF (0x3E) + +#elif (WLAN_HOSTIF == WLAN_PCI || WLAN_HOSTIF == WLAN_USB) + +#define HFA384x_CMD_OFF (0x00) +#define HFA384x_PARAM0_OFF (0x04) +#define HFA384x_PARAM1_OFF (0x08) +#define HFA384x_PARAM2_OFF (0x0c) +#define HFA384x_STATUS_OFF (0x10) +#define HFA384x_RESP0_OFF (0x14) +#define HFA384x_RESP1_OFF (0x18) +#define HFA384x_RESP2_OFF (0x1c) +#define HFA384x_INFOFID_OFF (0x20) +#define HFA384x_RXFID_OFF (0x40) +#define HFA384x_ALLOCFID_OFF (0x44) +#define HFA384x_TXCOMPLFID_OFF (0x48) +#define HFA384x_SELECT0_OFF (0x30) +#define HFA384x_OFFSET0_OFF (0x38) +#define HFA384x_DATA0_OFF (0x6c) +#define HFA384x_SELECT1_OFF (0x34) +#define HFA384x_OFFSET1_OFF (0x3c) +#define HFA384x_DATA1_OFF (0x70) +#define HFA384x_EVSTAT_OFF (0x60) +#define HFA384x_INTEN_OFF (0x64) +#define HFA384x_EVACK_OFF (0x68) +#define HFA384x_CONTROL_OFF (0x28) +#define HFA384x_SWSUPPORT0_OFF (0x50) +#define HFA384x_SWSUPPORT1_OFF (0x54) +#define HFA384x_SWSUPPORT2_OFF (0x58) +#define HFA384x_AUXPAGE_OFF (0x74) +#define HFA384x_AUXOFFSET_OFF (0x78) +#define HFA384x_AUXDATA_OFF (0x7c) +#define HFA384x_PCICOR_OFF (0x4c) +#define HFA384x_PCIHCR_OFF (0x5c) +#define HFA384x_PCI_M0_ADDRH_OFF (0x80) +#define HFA384x_PCI_M0_ADDRL_OFF (0x84) +#define HFA384x_PCI_M0_LEN_OFF (0x88) +#define HFA384x_PCI_M0_CTL_OFF (0x8c) +#define HFA384x_PCI_STATUS_OFF (0x98) +#define HFA384x_PCI_M1_ADDRH_OFF (0xa0) +#define HFA384x_PCI_M1_ADDRL_OFF (0xa4) +#define HFA384x_PCI_M1_LEN_OFF (0xa8) +#define HFA384x_PCI_M1_CTL_OFF (0xac) + +#endif + +/*--- Register Field Masks --------------------------*/ +#define HFA384x_CMD_BUSY ((UINT16)BIT15) +#define HFA384x_CMD_AINFO ((UINT16)(BIT14 | BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8)) +#define HFA384x_CMD_MACPORT ((UINT16)(BIT10 | BIT9 | BIT8)) +#define HFA384x_CMD_RECL ((UINT16)BIT8) +#define HFA384x_CMD_WRITE ((UINT16)BIT8) +#define HFA384x_CMD_PROGMODE ((UINT16)(BIT9 | BIT8)) +#define HFA384x_CMD_CMDCODE ((UINT16)(BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0)) + +#define HFA384x_STATUS_RESULT ((UINT16)(BIT14 | BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8)) +#define HFA384x_STATUS_CMDCODE ((UINT16)(BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0)) + +#define HFA384x_OFFSET_BUSY ((UINT16)BIT15) +#define HFA384x_OFFSET_ERR ((UINT16)BIT14) +#define HFA384x_OFFSET_DATAOFF ((UINT16)(BIT11 | BIT10 | BIT9 | BIT8 | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1)) + +#define HFA384x_EVSTAT_TICK ((UINT16)BIT15) +#define HFA384x_EVSTAT_WTERR ((UINT16)BIT14) +#define HFA384x_EVSTAT_INFDROP ((UINT16)BIT13) +#define HFA384x_EVSTAT_INFO ((UINT16)BIT7) +#define HFA384x_EVSTAT_DTIM ((UINT16)BIT5) +#define HFA384x_EVSTAT_CMD ((UINT16)BIT4) +#define HFA384x_EVSTAT_ALLOC ((UINT16)BIT3) +#define HFA384x_EVSTAT_TXEXC ((UINT16)BIT2) +#define HFA384x_EVSTAT_TX ((UINT16)BIT1) +#define HFA384x_EVSTAT_RX ((UINT16)BIT0) + +#define HFA384x_INT_BAP_OP (HFA384x_EVSTAT_INFO|HFA384x_EVSTAT_RX|HFA384x_EVSTAT_TX|HFA384x_EVSTAT_TXEXC) + +#define HFA384x_INT_NORMAL (HFA384x_EVSTAT_INFO|HFA384x_EVSTAT_RX|HFA384x_EVSTAT_TX|HFA384x_EVSTAT_TXEXC|HFA384x_EVSTAT_INFDROP|HFA384x_EVSTAT_ALLOC|HFA384x_EVSTAT_DTIM) + +#define HFA384x_INTEN_TICK ((UINT16)BIT15) +#define HFA384x_INTEN_WTERR ((UINT16)BIT14) +#define HFA384x_INTEN_INFDROP ((UINT16)BIT13) +#define HFA384x_INTEN_INFO ((UINT16)BIT7) +#define HFA384x_INTEN_DTIM ((UINT16)BIT5) +#define HFA384x_INTEN_CMD ((UINT16)BIT4) +#define HFA384x_INTEN_ALLOC ((UINT16)BIT3) +#define HFA384x_INTEN_TXEXC ((UINT16)BIT2) +#define HFA384x_INTEN_TX ((UINT16)BIT1) +#define HFA384x_INTEN_RX ((UINT16)BIT0) + +#define HFA384x_EVACK_TICK ((UINT16)BIT15) +#define HFA384x_EVACK_WTERR ((UINT16)BIT14) +#define HFA384x_EVACK_INFDROP ((UINT16)BIT13) +#define HFA384x_EVACK_INFO ((UINT16)BIT7) +#define HFA384x_EVACK_DTIM ((UINT16)BIT5) +#define HFA384x_EVACK_CMD ((UINT16)BIT4) +#define HFA384x_EVACK_ALLOC ((UINT16)BIT3) +#define HFA384x_EVACK_TXEXC ((UINT16)BIT2) +#define HFA384x_EVACK_TX ((UINT16)BIT1) +#define HFA384x_EVACK_RX ((UINT16)BIT0) + +#define HFA384x_CONTROL_AUXEN ((UINT16)(BIT15 | BIT14)) + + +/*--- Command Code Constants --------------------------*/ +/*--- Controller Commands --------------------------*/ +#define HFA384x_CMDCODE_INIT ((UINT16)0x00) +#define HFA384x_CMDCODE_ENABLE ((UINT16)0x01) +#define HFA384x_CMDCODE_DISABLE ((UINT16)0x02) +#define HFA384x_CMDCODE_DIAG ((UINT16)0x03) + +/*--- Buffer Mgmt Commands --------------------------*/ +#define HFA384x_CMDCODE_ALLOC ((UINT16)0x0A) +#define HFA384x_CMDCODE_TX ((UINT16)0x0B) +#define HFA384x_CMDCODE_CLRPRST ((UINT16)0x12) + +/*--- Regulate Commands --------------------------*/ +#define HFA384x_CMDCODE_NOTIFY ((UINT16)0x10) +#define HFA384x_CMDCODE_INQ ((UINT16)0x11) + +/*--- Configure Commands --------------------------*/ +#define HFA384x_CMDCODE_ACCESS ((UINT16)0x21) +#define HFA384x_CMDCODE_DOWNLD ((UINT16)0x22) + +/*--- Debugging Commands -----------------------------*/ +#define HFA384x_CMDCODE_MONITOR ((UINT16)(0x38)) +#define HFA384x_MONITOR_ENABLE ((UINT16)(0x0b)) +#define HFA384x_MONITOR_DISABLE ((UINT16)(0x0f)) + +/*--- Result Codes --------------------------*/ +#define HFA384x_SUCCESS ((UINT16)(0x00)) +#define HFA384x_CARD_FAIL ((UINT16)(0x01)) +#define HFA384x_NO_BUFF ((UINT16)(0x05)) +#define HFA384x_CMD_ERR ((UINT16)(0x7F)) + +/*--- Programming Modes -------------------------- + MODE 0: Disable programming + MODE 1: Enable volatile memory programming + MODE 2: Enable non-volatile memory programming + MODE 3: Program non-volatile memory section +--------------------------------------------------*/ +#define HFA384x_PROGMODE_DISABLE ((UINT16)0x00) +#define HFA384x_PROGMODE_RAM ((UINT16)0x01) +#define HFA384x_PROGMODE_NV ((UINT16)0x02) +#define HFA384x_PROGMODE_NVWRITE ((UINT16)0x03) + +/*--- AUX register enable --------------------------*/ +#define HFA384x_AUXPW0 ((UINT16)0xfe01) +#define HFA384x_AUXPW1 ((UINT16)0xdc23) +#define HFA384x_AUXPW2 ((UINT16)0xba45) + +#define HFA384x_CONTROL_AUX_ISDISABLED ((UINT16)0x0000) +#define HFA384x_CONTROL_AUX_ISENABLED ((UINT16)0xc000) +#define HFA384x_CONTROL_AUX_DOENABLE ((UINT16)0x8000) +#define HFA384x_CONTROL_AUX_DODISABLE ((UINT16)0x4000) + +/*--- Record ID Constants --------------------------*/ +/*-------------------------------------------------------------------- +Configuration RIDs: Network Parameters, Static Configuration Entities +--------------------------------------------------------------------*/ +#define HFA384x_RID_CNFPORTTYPE ((UINT16)0xFC00) +#define HFA384x_RID_CNFOWNMACADDR ((UINT16)0xFC01) +#define HFA384x_RID_CNFDESIREDSSID ((UINT16)0xFC02) +#define HFA384x_RID_CNFOWNCHANNEL ((UINT16)0xFC03) +#define HFA384x_RID_CNFOWNSSID ((UINT16)0xFC04) +#define HFA384x_RID_CNFOWNATIMWIN ((UINT16)0xFC05) +#define HFA384x_RID_CNFSYSSCALE ((UINT16)0xFC06) +#define HFA384x_RID_CNFMAXDATALEN ((UINT16)0xFC07) +#define HFA384x_RID_CNFWDSADDR ((UINT16)0xFC08) +#define HFA384x_RID_CNFPMENABLED ((UINT16)0xFC09) +#define HFA384x_RID_CNFPMEPS ((UINT16)0xFC0A) +#define HFA384x_RID_CNFMULTICASTRX ((UINT16)0xFC0B) +#define HFA384x_RID_CNFMAXSLEEPDUR ((UINT16)0xFC0C) +#define HFA384x_RID_CNFPMHOLDDUR ((UINT16)0xFC0D) +#define HFA384x_RID_CNFOWNNAME ((UINT16)0xFC0E) +#define HFA384x_RID_CNFOWNDTIMPER ((UINT16)0xFC10) +#define HFA384x_RID_CNFWDSADDR1 ((UINT16)0xFC11) +#define HFA384x_RID_CNFWDSADDR2 ((UINT16)0xFC12) +#define HFA384x_RID_CNFWDSADDR3 ((UINT16)0xFC13) +#define HFA384x_RID_CNFWDSADDR4 ((UINT16)0xFC14) +#define HFA384x_RID_CNFWDSADDR5 ((UINT16)0xFC15) +#define HFA384x_RID_CNFWDSADDR6 ((UINT16)0xFC16) +#define HFA384x_RID_CNFMCASTPMBUFF ((UINT16)0xFC17) + +/*-------------------------------------------------------------------- +Configuration RID lengths: Network Params, Static Config Entities + This is the length of JUST the DATA part of the RID (does not + include the len or code fields) +--------------------------------------------------------------------*/ +/* TODO: fill in the rest of these */ +#define HFA384x_RID_CNFPORTTYPE_LEN ((UINT16)2) +#define HFA384x_RID_CNFOWNMACADDR_LEN ((UINT16)6) +#define HFA384x_RID_CNFDESIREDSSID_LEN ((UINT16)34) +#define HFA384x_RID_CNFOWNCHANNEL_LEN ((UINT16)2) +#define HFA384x_RID_CNFOWNSSID_LEN ((UINT16)34) +#define HFA384x_RID_CNFOWNATIMWIN_LEN ((UINT16)2) +#define HFA384x_RID_CNFSYSSCALE_LEN ((UINT16)0) +#define HFA384x_RID_CNFMAXDATALEN_LEN ((UINT16)0) +#define HFA384x_RID_CNFWDSADDR_LEN ((UINT16)6) +#define HFA384x_RID_CNFPMENABLED_LEN ((UINT16)0) +#define HFA384x_RID_CNFPMEPS_LEN ((UINT16)0) +#define HFA384x_RID_CNFMULTICASTRX_LEN ((UINT16)0) +#define HFA384x_RID_CNFMAXSLEEPDUR_LEN ((UINT16)0) +#define HFA384x_RID_CNFPMHOLDDUR_LEN ((UINT16)0) +#define HFA384x_RID_CNFOWNNAME_LEN ((UINT16)34) +#define HFA384x_RID_CNFOWNDTIMPER_LEN ((UINT16)0) +#define HFA384x_RID_CNFWDSADDR1_LEN ((UINT16)6) +#define HFA384x_RID_CNFWDSADDR2_LEN ((UINT16)6) +#define HFA384x_RID_CNFWDSADDR3_LEN ((UINT16)6) +#define HFA384x_RID_CNFWDSADDR4_LEN ((UINT16)6) +#define HFA384x_RID_CNFWDSADDR5_LEN ((UINT16)6) +#define HFA384x_RID_CNFWDSADDR6_LEN ((UINT16)6) +#define HFA384x_RID_CNFMCASTPMBUFF_LEN ((UINT16)0) +#define HFA384x_RID_CNFAUTHENTICATION_LEN ((UINT16)sizeof(UINT16)) +#define HFA384x_RID_CNFMAXSLEEPDUR_LEN ((UINT16)0) + +/*-------------------------------------------------------------------- +Configuration RIDs: Network Parameters, Dynamic Configuration Entities +--------------------------------------------------------------------*/ +#define HFA384x_RID_GROUPADDR ((UINT16)0xFC80) +#define HFA384x_RID_CREATEIBSS ((UINT16)0xFC81) +#define HFA384x_RID_FRAGTHRESH ((UINT16)0xFC82) +#define HFA384x_RID_RTSTHRESH ((UINT16)0xFC83) +#define HFA384x_RID_TXRATECNTL ((UINT16)0xFC84) +#define HFA384x_RID_PROMISCMODE ((UINT16)0xFC85) +#define HFA384x_RID_FRAGTHRESH0 ((UINT16)0xFC90) +#define HFA384x_RID_FRAGTHRESH1 ((UINT16)0xFC91) +#define HFA384x_RID_FRAGTHRESH2 ((UINT16)0xFC92) +#define HFA384x_RID_FRAGTHRESH3 ((UINT16)0xFC93) +#define HFA384x_RID_FRAGTHRESH4 ((UINT16)0xFC94) +#define HFA384x_RID_FRAGTHRESH5 ((UINT16)0xFC95) +#define HFA384x_RID_FRAGTHRESH6 ((UINT16)0xFC96) +#define HFA384x_RID_RTSTHRESH0 ((UINT16)0xFC97) +#define HFA384x_RID_RTSTHRESH1 ((UINT16)0xFC98) +#define HFA384x_RID_RTSTHRESH2 ((UINT16)0xFC99) +#define HFA384x_RID_RTSTHRESH3 ((UINT16)0xFC9A) +#define HFA384x_RID_RTSTHRESH4 ((UINT16)0xFC9B) +#define HFA384x_RID_RTSTHRESH5 ((UINT16)0xFC9C) +#define HFA384x_RID_RTSTHRESH6 ((UINT16)0xFC9D) +#define HFA384x_RID_TXRATECNTL0 ((UINT16)0xFC9E) +#define HFA384x_RID_TXRATECNTL1 ((UINT16)0xFC9F) +#define HFA384x_RID_TXRATECNTL2 ((UINT16)0xFCA0) +#define HFA384x_RID_TXRATECNTL3 ((UINT16)0xFCA1) +#define HFA384x_RID_TXRATECNTL4 ((UINT16)0xFCA2) +#define HFA384x_RID_TXRATECNTL5 ((UINT16)0xFCA3) +#define HFA384x_RID_TXRATECNTL6 ((UINT16)0xFCA4) + +/*-------------------------------------------------------------------- +Configuration RID Lengths: Network Param, Dynamic Config Entities + This is the length of JUST the DATA part of the RID (does not + include the len or code fields) +--------------------------------------------------------------------*/ +/* TODO: fill in the rest of these */ +#define HFA384x_RID_GROUPADDR_LEN ((UINT16)16 * WLAN_ADDR_LEN) +#define HFA384x_RID_CREATEIBSS_LEN ((UINT16)0) +#define HFA384x_RID_FRAGTHRESH_LEN ((UINT16)0) +#define HFA384x_RID_RTSTHRESH_LEN ((UINT16)0) +#define HFA384x_RID_TXRATECNTL_LEN ((UINT16)4) +#define HFA384x_RID_PROMISCMODE_LEN ((UINT16)2) +#define HFA384x_RID_FRAGTHRESH0_LEN ((UINT16)0) +#define HFA384x_RID_FRAGTHRESH1_LEN ((UINT16)0) +#define HFA384x_RID_FRAGTHRESH2_LEN ((UINT16)0) +#define HFA384x_RID_FRAGTHRESH3_LEN ((UINT16)0) +#define HFA384x_RID_FRAGTHRESH4_LEN ((UINT16)0) +#define HFA384x_RID_FRAGTHRESH5_LEN ((UINT16)0) +#define HFA384x_RID_FRAGTHRESH6_LEN ((UINT16)0) +#define HFA384x_RID_RTSTHRESH0_LEN ((UINT16)0) +#define HFA384x_RID_RTSTHRESH1_LEN ((UINT16)0) +#define HFA384x_RID_RTSTHRESH2_LEN ((UINT16)0) +#define HFA384x_RID_RTSTHRESH3_LEN ((UINT16)0) +#define HFA384x_RID_RTSTHRESH4_LEN ((UINT16)0) +#define HFA384x_RID_RTSTHRESH5_LEN ((UINT16)0) +#define HFA384x_RID_RTSTHRESH6_LEN ((UINT16)0) +#define HFA384x_RID_TXRATECNTL0_LEN ((UINT16)0) +#define HFA384x_RID_TXRATECNTL1_LEN ((UINT16)0) +#define HFA384x_RID_TXRATECNTL2_LEN ((UINT16)0) +#define HFA384x_RID_TXRATECNTL3_LEN ((UINT16)0) +#define HFA384x_RID_TXRATECNTL4_LEN ((UINT16)0) +#define HFA384x_RID_TXRATECNTL5_LEN ((UINT16)0) +#define HFA384x_RID_TXRATECNTL6_LEN ((UINT16)0) + +/*-------------------------------------------------------------------- +Configuration RIDs: Behavior Parameters +--------------------------------------------------------------------*/ +#define HFA384x_RID_ITICKTIME ((UINT16)0xFCE0) + +/*-------------------------------------------------------------------- +Configuration RID Lengths: Behavior Parameters + This is the length of JUST the DATA part of the RID (does not + include the len or code fields) +--------------------------------------------------------------------*/ +#define HFA384x_RID_ITICKTIME_LEN ((UINT16)2) + +/*---------------------------------------------------------------------- +Information RIDs: NIC Information +--------------------------------------------------------------------*/ +#define HFA384x_RID_MAXLOADTIME ((UINT16)0xFD00) +#define HFA384x_RID_DOWNLOADBUFFER ((UINT16)0xFD01) +#define HFA384x_RID_PRIIDENTITY ((UINT16)0xFD02) +#define HFA384x_RID_PRISUPRANGE ((UINT16)0xFD03) +#define HFA384x_RID_PRI_CFIACTRANGES ((UINT16)0xFD04) +#define HFA384x_RID_NICSERIALNUMBER ((UINT16)0xFD0A) +#define HFA384x_RID_NICIDENTITY ((UINT16)0xFD0B) +#define HFA384x_RID_MFISUPRANGE ((UINT16)0xFD0C) +#define HFA384x_RID_CFISUPRANGE ((UINT16)0xFD0D) +#define HFA384x_RID_CHANNELLIST ((UINT16)0xFD10) +#define HFA384x_RID_REGULATORYDOMAINS ((UINT16)0xFD11) +#define HFA384x_RID_TEMPTYPE ((UINT16)0xFD12) +#define HFA384x_RID_CIS ((UINT16)0xFD13) +#define HFA384x_RID_STAIDENTITY ((UINT16)0xFD20) +#define HFA384x_RID_STASUPRANGE ((UINT16)0xFD21) +#define HFA384x_RID_STA_MFIACTRANGES ((UINT16)0xFD22) +#define HFA384x_RID_STA_CFIACTRANGES ((UINT16)0xFD23) +#define HFA384x_RID_BUILDSEQ ((UINT16)0xFFFE) +#define HFA384x_RID_FWID ((UINT16)0xFFFF) + +/*---------------------------------------------------------------------- +Information RID Lengths: NIC Information + This is the length of JUST the DATA part of the RID (does not + include the len or code fields) +--------------------------------------------------------------------*/ +#define HFA384x_RID_MAXLOADTIME_LEN ((UINT16)0) +#define HFA384x_RID_DOWNLOADBUFFER_LEN ((UINT16)sizeof(hfa384x_downloadbuffer_t)) +#define HFA384x_RID_PRIIDENTITY_LEN ((UINT16)8) +#define HFA384x_RID_PRISUPRANGE_LEN ((UINT16)10) +#define HFA384x_RID_CFIACTRANGES_LEN ((UINT16)10) +#define HFA384x_RID_NICSERIALNUMBER_LEN ((UINT16)12) +#define HFA384x_RID_NICIDENTITY_LEN ((UINT16)8) +#define HFA384x_RID_MFISUPRANGE_LEN ((UINT16)10) +#define HFA384x_RID_CFISUPRANGE_LEN ((UINT16)10) +#define HFA384x_RID_CHANNELLIST_LEN ((UINT16)0) +#define HFA384x_RID_REGULATORYDOMAINS_LEN ((UINT16)12) +#define HFA384x_RID_TEMPTYPE_LEN ((UINT16)0) +#define HFA384x_RID_CIS_LEN ((UINT16)480) +#define HFA384x_RID_STAIDENTITY_LEN ((UINT16)8) +#define HFA384x_RID_STASUPRANGE_LEN ((UINT16)10) +#define HFA384x_RID_MFIACTRANGES_LEN ((UINT16)10) +#define HFA384x_RID_CFIACTRANGES2_LEN ((UINT16)10) +#define HFA384x_RID_BUILDSEQ_LEN ((UINT16)sizeof(hfa384x_BuildSeq_t)) +#define HFA384x_RID_FWID_LEN ((UINT16)sizeof(hfa384x_FWID_t)) + +/*-------------------------------------------------------------------- +Information RIDs: MAC Information +--------------------------------------------------------------------*/ +#define HFA384x_RID_PORTSTATUS ((UINT16)0xFD40) +#define HFA384x_RID_CURRENTSSID ((UINT16)0xFD41) +#define HFA384x_RID_CURRENTBSSID ((UINT16)0xFD42) +#define HFA384x_RID_COMMSQUALITY ((UINT16)0xFD43) +#define HFA384x_RID_CURRENTTXRATE ((UINT16)0xFD44) +#define HFA384x_RID_CURRENTBCNINT ((UINT16)0xFD45) +#define HFA384x_RID_CURRENTSCALETHRESH ((UINT16)0xFD46) +#define HFA384x_RID_PROTOCOLRSPTIME ((UINT16)0xFD47) +#define HFA384x_RID_SHORTRETRYLIMIT ((UINT16)0xFD48) +#define HFA384x_RID_LONGRETRYLIMIT ((UINT16)0xFD49) +#define HFA384x_RID_MAXTXLIFETIME ((UINT16)0xFD4A) +#define HFA384x_RID_MAXRXLIFETIME ((UINT16)0xFD4B) +#define HFA384x_RID_CFPOLLABLE ((UINT16)0xFD4C) +#define HFA384x_RID_AUTHALGORITHMS ((UINT16)0xFD4D) +#define HFA384x_RID_PRIVACYOPTIMP ((UINT16)0xFD4F) +#define HFA384x_RID_DBMCOMMSQUALITY ((UINT16)0xFD51) +#define HFA384x_RID_CURRENTTXRATE1 ((UINT16)0xFD80) +#define HFA384x_RID_CURRENTTXRATE2 ((UINT16)0xFD81) +#define HFA384x_RID_CURRENTTXRATE3 ((UINT16)0xFD82) +#define HFA384x_RID_CURRENTTXRATE4 ((UINT16)0xFD83) +#define HFA384x_RID_CURRENTTXRATE5 ((UINT16)0xFD84) +#define HFA384x_RID_CURRENTTXRATE6 ((UINT16)0xFD85) +#define HFA384x_RID_OWNMACADDRESS ((UINT16)0xFD86) +// #define HFA384x_RID_PCFINFO ((UINT16)0xFD87) +#define HFA384x_RID_SCANRESULTS ((UINT16)0xFD88) // NEW +#define HFA384x_RID_HOSTSCANRESULTS ((UINT16)0xFD89) // NEW +#define HFA384x_RID_AUTHENTICATIONUSED ((UINT16)0xFD8A) // NEW +#define HFA384x_RID_ASSOCIATEFAILURE ((UINT16)0xFD8D) // 1.8.0 + +/*-------------------------------------------------------------------- +Information RID Lengths: MAC Information + This is the length of JUST the DATA part of the RID (does not + include the len or code fields) +--------------------------------------------------------------------*/ +#define HFA384x_RID_PORTSTATUS_LEN ((UINT16)0) +#define HFA384x_RID_CURRENTSSID_LEN ((UINT16)34) +#define HFA384x_RID_CURRENTBSSID_LEN ((UINT16)WLAN_BSSID_LEN) +#define HFA384x_RID_COMMSQUALITY_LEN ((UINT16)sizeof(hfa384x_commsquality_t)) +#define HFA384x_RID_DBMCOMMSQUALITY_LEN ((UINT16)sizeof(hfa384x_dbmcommsquality_t)) +#define HFA384x_RID_CURRENTTXRATE_LEN ((UINT16)0) +#define HFA384x_RID_CURRENTBCNINT_LEN ((UINT16)0) +#define HFA384x_RID_STACURSCALETHRESH_LEN ((UINT16)12) +#define HFA384x_RID_APCURSCALETHRESH_LEN ((UINT16)6) +#define HFA384x_RID_PROTOCOLRSPTIME_LEN ((UINT16)0) +#define HFA384x_RID_SHORTRETRYLIMIT_LEN ((UINT16)0) +#define HFA384x_RID_LONGRETRYLIMIT_LEN ((UINT16)0) +#define HFA384x_RID_MAXTXLIFETIME_LEN ((UINT16)0) +#define HFA384x_RID_MAXRXLIFETIME_LEN ((UINT16)0) +#define HFA384x_RID_CFPOLLABLE_LEN ((UINT16)0) +#define HFA384x_RID_AUTHALGORITHMS_LEN ((UINT16)4) +#define HFA384x_RID_PRIVACYOPTIMP_LEN ((UINT16)0) +#define HFA384x_RID_CURRENTTXRATE1_LEN ((UINT16)0) +#define HFA384x_RID_CURRENTTXRATE2_LEN ((UINT16)0) +#define HFA384x_RID_CURRENTTXRATE3_LEN ((UINT16)0) +#define HFA384x_RID_CURRENTTXRATE4_LEN ((UINT16)0) +#define HFA384x_RID_CURRENTTXRATE5_LEN ((UINT16)0) +#define HFA384x_RID_CURRENTTXRATE6_LEN ((UINT16)0) +#define HFA384x_RID_OWNMACADDRESS_LEN ((UINT16)6) +#define HFA384x_RID_PCFINFO_LEN ((UINT16)6) +#define HFA384x_RID_CNFAPPCFINFO_LEN ((UINT16)sizeof(hfa384x_PCFInfo_data_t)) +#define HFA384x_RID_SCANREQUEST_LEN ((UINT16)sizeof(hfa384x_ScanRequest_data_t)) +#define HFA384x_RID_JOINREQUEST_LEN ((UINT16)sizeof(hfa384x_JoinRequest_data_t)) +#define HFA384x_RID_AUTHENTICATESTA_LEN ((UINT16)sizeof(hfa384x_authenticateStation_data_t)) +#define HFA384x_RID_CHANNELINFOREQUEST_LEN ((UINT16)sizeof(hfa384x_ChannelInfoRequest_data_t)) +/*-------------------------------------------------------------------- +Information RIDs: Modem Information +--------------------------------------------------------------------*/ +#define HFA384x_RID_PHYTYPE ((UINT16)0xFDC0) +#define HFA384x_RID_CURRENTCHANNEL ((UINT16)0xFDC1) +#define HFA384x_RID_CURRENTPOWERSTATE ((UINT16)0xFDC2) +#define HFA384x_RID_CCAMODE ((UINT16)0xFDC3) +#define HFA384x_RID_SUPPORTEDDATARATES ((UINT16)0xFDC6) +#define HFA384x_RID_LFOSTATUS ((UINT16)0xFDC7) // 1.7.1 + +/*-------------------------------------------------------------------- +Information RID Lengths: Modem Information + This is the length of JUST the DATA part of the RID (does not + include the len or code fields) +--------------------------------------------------------------------*/ +#define HFA384x_RID_PHYTYPE_LEN ((UINT16)0) +#define HFA384x_RID_CURRENTCHANNEL_LEN ((UINT16)0) +#define HFA384x_RID_CURRENTPOWERSTATE_LEN ((UINT16)0) +#define HFA384x_RID_CCAMODE_LEN ((UINT16)0) +#define HFA384x_RID_SUPPORTEDDATARATES_LEN ((UINT16)10) + +/*-------------------------------------------------------------------- +API ENHANCEMENTS (NOT ALREADY IMPLEMENTED) +--------------------------------------------------------------------*/ +#define HFA384x_RID_CNFWEPDEFAULTKEYID ((UINT16)0xFC23) +#define HFA384x_RID_CNFWEPDEFAULTKEY0 ((UINT16)0xFC24) +#define HFA384x_RID_CNFWEPDEFAULTKEY1 ((UINT16)0xFC25) +#define HFA384x_RID_CNFWEPDEFAULTKEY2 ((UINT16)0xFC26) +#define HFA384x_RID_CNFWEPDEFAULTKEY3 ((UINT16)0xFC27) +#define HFA384x_RID_CNFWEPFLAGS ((UINT16)0xFC28) +#define HFA384x_RID_CNFWEPKEYMAPTABLE ((UINT16)0xFC29) +#define HFA384x_RID_CNFAUTHENTICATION ((UINT16)0xFC2A) +#define HFA384x_RID_CNFMAXASSOCSTATIONS ((UINT16)0xFC2B) +#define HFA384x_RID_CNFTXCONTROL ((UINT16)0xFC2C) +#define HFA384x_RID_CNFROAMINGMODE ((UINT16)0xFC2D) +#define HFA384x_RID_CNFHOSTAUTHASSOC ((UINT16)0xFC2E) +#define HFA384x_RID_CNFRCVCRCERROR ((UINT16)0xFC30) +// #define HFA384x_RID_CNFMMLIFE ((UINT16)0xFC31) +#define HFA384x_RID_CNFALTRETRYCNT ((UINT16)0xFC32) +#define HFA384x_RID_CNFAPBCNINT ((UINT16)0xFC33) +#define HFA384x_RID_CNFAPPCFINFO ((UINT16)0xFC34) +#define HFA384x_RID_CNFSTAPCFINFO ((UINT16)0xFC35) +#define HFA384x_RID_CNFPRIORITYQUSAGE ((UINT16)0xFC37) +#define HFA384x_RID_CNFTIMCTRL ((UINT16)0xFC40) +#define HFA384x_RID_CNFTHIRTY2TALLY ((UINT16)0xFC42) +#define HFA384x_RID_CNFENHSECURITY ((UINT16)0xFC43) +#define HFA384x_RID_CNFDBMADJUST ((UINT16)0xFC46) // NEW +#define HFA384x_RID_CNFWPADATA ((UINT16)0xFC48) // 1.7.0 +#define HFA384x_RID_CNFPROPOGATIONDELAY ((UINT16)0xFC49) // 1.7.6 +#define HFA384x_RID_CNFSHORTPREAMBLE ((UINT16)0xFCB0) +#define HFA384x_RID_CNFEXCLONGPREAMBLE ((UINT16)0xFCB1) +#define HFA384x_RID_CNFAUTHRSPTIMEOUT ((UINT16)0xFCB2) +#define HFA384x_RID_CNFBASICRATES ((UINT16)0xFCB3) +#define HFA384x_RID_CNFSUPPRATES ((UINT16)0xFCB4) +#define HFA384x_RID_CNFFALLBACKCTRL ((UINT16)0xFCB5) // NEW +#define HFA384x_RID_WEPKEYSTATUS ((UINT16)0xFCB6) // NEW +#define HFA384x_RID_WEPKEYMAPINDEX ((UINT16)0xFCB7) // NEW +#define HFA384x_RID_BROADCASTKEYID ((UINT16)0xFCB8) // NEW +#define HFA384x_RID_ENTSECFLAGEYID ((UINT16)0xFCB9) // NEW +#define HFA384x_RID_CNFPASSIVESCANCTRL ((UINT16)0xFCBA) // NEW STA +#define HFA384x_RID_CNFWPAHANDLING ((UINT16)0xFCBB) // 1.7.0 +#define HFA384x_RID_MDCCONTROL ((UINT16)0xFCBC) // 1.7.0/1.4.0 +#define HFA384x_RID_MDCCOUNTRY ((UINT16)0xFCBD) // 1.7.0/1.4.0 +#define HFA384x_RID_TXPOWERMAX ((UINT16)0xFCBE) // 1.7.0/1.4.0 +#define HFA384x_RID_CNFLFOENBLED ((UINT16)0xFCBF) // 1.6.3 +#define HFA384x_RID_CAPINFO ((UINT16)0xFCC0) // 1.7.0/1.3.7 +#define HFA384x_RID_LISTENINTERVAL ((UINT16)0xFCC1) // 1.7.0/1.3.7 +#define HFA384x_RID_DIVERSITYENABLED ((UINT16)0xFCC2) // 1.7.0/1.3.7 +#define HFA384x_RID_LED_CONTROL ((UINT16)0xFCC4) // 1.7.6 +#define HFA384x_RID_HFO_DELAY ((UINT16)0xFCC5) // 1.7.6 +#define HFA384x_RID_DISSALOWEDBSSID ((UINT16)0xFCC6) // 1.8.0 +#define HFA384x_RID_SCANREQUEST ((UINT16)0xFCE1) +#define HFA384x_RID_JOINREQUEST ((UINT16)0xFCE2) +#define HFA384x_RID_AUTHENTICATESTA ((UINT16)0xFCE3) +#define HFA384x_RID_CHANNELINFOREQUEST ((UINT16)0xFCE4) +#define HFA384x_RID_HOSTSCAN ((UINT16)0xFCE5) // NEW STA +#define HFA384x_RID_ASSOCIATESTA ((UINT16)0xFCE6) + +#define HFA384x_RID_CNFWEPDEFAULTKEY_LEN ((UINT16)6) +#define HFA384x_RID_CNFWEP128DEFAULTKEY_LEN ((UINT16)14) +#define HFA384x_RID_CNFPRIOQUSAGE_LEN ((UINT16)4) +/*-------------------------------------------------------------------- +PD Record codes +--------------------------------------------------------------------*/ +#define HFA384x_PDR_PCB_PARTNUM ((UINT16)0x0001) +#define HFA384x_PDR_PDAVER ((UINT16)0x0002) +#define HFA384x_PDR_NIC_SERIAL ((UINT16)0x0003) +#define HFA384x_PDR_MKK_MEASUREMENTS ((UINT16)0x0004) +#define HFA384x_PDR_NIC_RAMSIZE ((UINT16)0x0005) +#define HFA384x_PDR_MFISUPRANGE ((UINT16)0x0006) +#define HFA384x_PDR_CFISUPRANGE ((UINT16)0x0007) +#define HFA384x_PDR_NICID ((UINT16)0x0008) +//#define HFA384x_PDR_REFDAC_MEASUREMENTS ((UINT16)0x0010) +//#define HFA384x_PDR_VGDAC_MEASUREMENTS ((UINT16)0x0020) +//#define HFA384x_PDR_LEVEL_COMP_MEASUREMENTS ((UINT16)0x0030) +//#define HFA384x_PDR_MODEM_TRIMDAC_MEASUREMENTS ((UINT16)0x0040) +//#define HFA384x_PDR_COREGA_HACK ((UINT16)0x00ff) +#define HFA384x_PDR_MAC_ADDRESS ((UINT16)0x0101) +//#define HFA384x_PDR_MKK_CALLNAME ((UINT16)0x0102) +#define HFA384x_PDR_REGDOMAIN ((UINT16)0x0103) +#define HFA384x_PDR_ALLOWED_CHANNEL ((UINT16)0x0104) +#define HFA384x_PDR_DEFAULT_CHANNEL ((UINT16)0x0105) +//#define HFA384x_PDR_PRIVACY_OPTION ((UINT16)0x0106) +#define HFA384x_PDR_TEMPTYPE ((UINT16)0x0107) +//#define HFA384x_PDR_REFDAC_SETUP ((UINT16)0x0110) +//#define HFA384x_PDR_VGDAC_SETUP ((UINT16)0x0120) +//#define HFA384x_PDR_LEVEL_COMP_SETUP ((UINT16)0x0130) +//#define HFA384x_PDR_TRIMDAC_SETUP ((UINT16)0x0140) +#define HFA384x_PDR_IFR_SETTING ((UINT16)0x0200) +#define HFA384x_PDR_RFR_SETTING ((UINT16)0x0201) +#define HFA384x_PDR_HFA3861_BASELINE ((UINT16)0x0202) +#define HFA384x_PDR_HFA3861_SHADOW ((UINT16)0x0203) +#define HFA384x_PDR_HFA3861_IFRF ((UINT16)0x0204) +#define HFA384x_PDR_HFA3861_CHCALSP ((UINT16)0x0300) +#define HFA384x_PDR_HFA3861_CHCALI ((UINT16)0x0301) +#define HFA384x_PDR_MAX_TX_POWER ((UINT16)0x0302) +#define HFA384x_PDR_MASTER_CHAN_LIST ((UINT16)0x0303) +#define HFA384x_PDR_3842_NIC_CONFIG ((UINT16)0x0400) +#define HFA384x_PDR_USB_ID ((UINT16)0x0401) +#define HFA384x_PDR_PCI_ID ((UINT16)0x0402) +#define HFA384x_PDR_PCI_IFCONF ((UINT16)0x0403) +#define HFA384x_PDR_PCI_PMCONF ((UINT16)0x0404) +#define HFA384x_PDR_RFENRGY ((UINT16)0x0406) +#define HFA384x_PDR_USB_POWER_TYPE ((UINT16)0x0407) +//#define HFA384x_PDR_UNKNOWN408 ((UINT16)0x0408) +#define HFA384x_PDR_USB_MAX_POWER ((UINT16)0x0409) +#define HFA384x_PDR_USB_MANUFACTURER ((UINT16)0x0410) +#define HFA384x_PDR_USB_PRODUCT ((UINT16)0x0411) +#define HFA384x_PDR_ANT_DIVERSITY ((UINT16)0x0412) +#define HFA384x_PDR_HFO_DELAY ((UINT16)0x0413) +#define HFA384x_PDR_SCALE_THRESH ((UINT16)0x0414) + +#define HFA384x_PDR_HFA3861_MANF_TESTSP ((UINT16)0x0900) +#define HFA384x_PDR_HFA3861_MANF_TESTI ((UINT16)0x0901) +#define HFA384x_PDR_END_OF_PDA ((UINT16)0x0000) + + +/*=============================================================*/ +/*------ Macros -----------------------------------------------*/ + +/*--- Register ID macros ------------------------*/ + +#define HFA384x_CMD HFA384x_CMD_OFF +#define HFA384x_PARAM0 HFA384x_PARAM0_OFF +#define HFA384x_PARAM1 HFA384x_PARAM1_OFF +#define HFA384x_PARAM2 HFA384x_PARAM2_OFF +#define HFA384x_STATUS HFA384x_STATUS_OFF +#define HFA384x_RESP0 HFA384x_RESP0_OFF +#define HFA384x_RESP1 HFA384x_RESP1_OFF +#define HFA384x_RESP2 HFA384x_RESP2_OFF +#define HFA384x_INFOFID HFA384x_INFOFID_OFF +#define HFA384x_RXFID HFA384x_RXFID_OFF +#define HFA384x_ALLOCFID HFA384x_ALLOCFID_OFF +#define HFA384x_TXCOMPLFID HFA384x_TXCOMPLFID_OFF +#define HFA384x_SELECT0 HFA384x_SELECT0_OFF +#define HFA384x_OFFSET0 HFA384x_OFFSET0_OFF +#define HFA384x_DATA0 HFA384x_DATA0_OFF +#define HFA384x_SELECT1 HFA384x_SELECT1_OFF +#define HFA384x_OFFSET1 HFA384x_OFFSET1_OFF +#define HFA384x_DATA1 HFA384x_DATA1_OFF +#define HFA384x_EVSTAT HFA384x_EVSTAT_OFF +#define HFA384x_INTEN HFA384x_INTEN_OFF +#define HFA384x_EVACK HFA384x_EVACK_OFF +#define HFA384x_CONTROL HFA384x_CONTROL_OFF +#define HFA384x_SWSUPPORT0 HFA384x_SWSUPPORT0_OFF +#define HFA384x_SWSUPPORT1 HFA384x_SWSUPPORT1_OFF +#define HFA384x_SWSUPPORT2 HFA384x_SWSUPPORT2_OFF +#define HFA384x_AUXPAGE HFA384x_AUXPAGE_OFF +#define HFA384x_AUXOFFSET HFA384x_AUXOFFSET_OFF +#define HFA384x_AUXDATA HFA384x_AUXDATA_OFF +#define HFA384x_PCICOR HFA384x_PCICOR_OFF +#define HFA384x_PCIHCR HFA384x_PCIHCR_OFF + + +/*--- Register Test/Get/Set Field macros ------------------------*/ + +#define HFA384x_CMD_ISBUSY(value) ((UINT16)(((UINT16)value) & HFA384x_CMD_BUSY)) +#define HFA384x_CMD_AINFO_GET(value) ((UINT16)(((UINT16)(value) & HFA384x_CMD_AINFO) >> 8)) +#define HFA384x_CMD_AINFO_SET(value) ((UINT16)((UINT16)(value) << 8)) +#define HFA384x_CMD_MACPORT_GET(value) ((UINT16)(HFA384x_CMD_AINFO_GET((UINT16)(value) & HFA384x_CMD_MACPORT))) +#define HFA384x_CMD_MACPORT_SET(value) ((UINT16)HFA384x_CMD_AINFO_SET(value)) +#define HFA384x_CMD_ISRECL(value) ((UINT16)(HFA384x_CMD_AINFO_GET((UINT16)(value) & HFA384x_CMD_RECL))) +#define HFA384x_CMD_RECL_SET(value) ((UINT16)HFA384x_CMD_AINFO_SET(value)) +#define HFA384x_CMD_QOS_GET(value) ((UINT16((((UINT16)(value))&((UINT16)0x3000)) >> 12)) +#define HFA384x_CMD_QOS_SET(value) ((UINT16)((((UINT16)(value)) << 12) & 0x3000)) +#define HFA384x_CMD_ISWRITE(value) ((UINT16)(HFA384x_CMD_AINFO_GET((UINT16)(value) & HFA384x_CMD_WRITE))) +#define HFA384x_CMD_WRITE_SET(value) ((UINT16)HFA384x_CMD_AINFO_SET((UINT16)value)) +#define HFA384x_CMD_PROGMODE_GET(value) ((UINT16)(HFA384x_CMD_AINFO_GET((UINT16)(value) & HFA384x_CMD_PROGMODE))) +#define HFA384x_CMD_PROGMODE_SET(value) ((UINT16)HFA384x_CMD_AINFO_SET((UINT16)value)) +#define HFA384x_CMD_CMDCODE_GET(value) ((UINT16)(((UINT16)(value)) & HFA384x_CMD_CMDCODE)) +#define HFA384x_CMD_CMDCODE_SET(value) ((UINT16)(value)) + +#define HFA384x_STATUS_RESULT_GET(value) ((UINT16)((((UINT16)(value)) & HFA384x_STATUS_RESULT) >> 8)) +#define HFA384x_STATUS_RESULT_SET(value) (((UINT16)(value)) << 8) +#define HFA384x_STATUS_CMDCODE_GET(value) (((UINT16)(value)) & HFA384x_STATUS_CMDCODE) +#define HFA384x_STATUS_CMDCODE_SET(value) ((UINT16)(value)) + +#define HFA384x_OFFSET_ISBUSY(value) ((UINT16)(((UINT16)(value)) & HFA384x_OFFSET_BUSY)) +#define HFA384x_OFFSET_ISERR(value) ((UINT16)(((UINT16)(value)) & HFA384x_OFFSET_ERR)) +#define HFA384x_OFFSET_DATAOFF_GET(value) ((UINT16)(((UINT16)(value)) & HFA384x_OFFSET_DATAOFF)) +#define HFA384x_OFFSET_DATAOFF_SET(value) ((UINT16)(value)) + +#define HFA384x_EVSTAT_ISTICK(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_TICK)) +#define HFA384x_EVSTAT_ISWTERR(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_WTERR)) +#define HFA384x_EVSTAT_ISINFDROP(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_INFDROP)) +#define HFA384x_EVSTAT_ISINFO(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_INFO)) +#define HFA384x_EVSTAT_ISDTIM(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_DTIM)) +#define HFA384x_EVSTAT_ISCMD(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_CMD)) +#define HFA384x_EVSTAT_ISALLOC(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_ALLOC)) +#define HFA384x_EVSTAT_ISTXEXC(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_TXEXC)) +#define HFA384x_EVSTAT_ISTX(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_TX)) +#define HFA384x_EVSTAT_ISRX(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_RX)) + +#define HFA384x_EVSTAT_ISBAP_OP(value) ((UINT16)(((UINT16)(value)) & HFA384x_INT_BAP_OP)) + +#define HFA384x_INTEN_ISTICK(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_TICK)) +#define HFA384x_INTEN_TICK_SET(value) ((UINT16)(((UINT16)(value)) << 15)) +#define HFA384x_INTEN_ISWTERR(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_WTERR)) +#define HFA384x_INTEN_WTERR_SET(value) ((UINT16)(((UINT16)(value)) << 14)) +#define HFA384x_INTEN_ISINFDROP(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_INFDROP)) +#define HFA384x_INTEN_INFDROP_SET(value) ((UINT16)(((UINT16)(value)) << 13)) +#define HFA384x_INTEN_ISINFO(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_INFO)) +#define HFA384x_INTEN_INFO_SET(value) ((UINT16)(((UINT16)(value)) << 7)) +#define HFA384x_INTEN_ISDTIM(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_DTIM)) +#define HFA384x_INTEN_DTIM_SET(value) ((UINT16)(((UINT16)(value)) << 5)) +#define HFA384x_INTEN_ISCMD(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_CMD)) +#define HFA384x_INTEN_CMD_SET(value) ((UINT16)(((UINT16)(value)) << 4)) +#define HFA384x_INTEN_ISALLOC(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_ALLOC)) +#define HFA384x_INTEN_ALLOC_SET(value) ((UINT16)(((UINT16)(value)) << 3)) +#define HFA384x_INTEN_ISTXEXC(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_TXEXC)) +#define HFA384x_INTEN_TXEXC_SET(value) ((UINT16)(((UINT16)(value)) << 2)) +#define HFA384x_INTEN_ISTX(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_TX)) +#define HFA384x_INTEN_TX_SET(value) ((UINT16)(((UINT16)(value)) << 1)) +#define HFA384x_INTEN_ISRX(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_RX)) +#define HFA384x_INTEN_RX_SET(value) ((UINT16)(((UINT16)(value)) << 0)) + +#define HFA384x_EVACK_ISTICK(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_TICK)) +#define HFA384x_EVACK_TICK_SET(value) ((UINT16)(((UINT16)(value)) << 15)) +#define HFA384x_EVACK_ISWTERR(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_WTERR)) +#define HFA384x_EVACK_WTERR_SET(value) ((UINT16)(((UINT16)(value)) << 14)) +#define HFA384x_EVACK_ISINFDROP(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_INFDROP)) +#define HFA384x_EVACK_INFDROP_SET(value) ((UINT16)(((UINT16)(value)) << 13)) +#define HFA384x_EVACK_ISINFO(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_INFO)) +#define HFA384x_EVACK_INFO_SET(value) ((UINT16)(((UINT16)(value)) << 7)) +#define HFA384x_EVACK_ISDTIM(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_DTIM)) +#define HFA384x_EVACK_DTIM_SET(value) ((UINT16)(((UINT16)(value)) << 5)) +#define HFA384x_EVACK_ISCMD(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_CMD)) +#define HFA384x_EVACK_CMD_SET(value) ((UINT16)(((UINT16)(value)) << 4)) +#define HFA384x_EVACK_ISALLOC(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_ALLOC)) +#define HFA384x_EVACK_ALLOC_SET(value) ((UINT16)(((UINT16)(value)) << 3)) +#define HFA384x_EVACK_ISTXEXC(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_TXEXC)) +#define HFA384x_EVACK_TXEXC_SET(value) ((UINT16)(((UINT16)(value)) << 2)) +#define HFA384x_EVACK_ISTX(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_TX)) +#define HFA384x_EVACK_TX_SET(value) ((UINT16)(((UINT16)(value)) << 1)) +#define HFA384x_EVACK_ISRX(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_RX)) +#define HFA384x_EVACK_RX_SET(value) ((UINT16)(((UINT16)(value)) << 0)) + +#define HFA384x_CONTROL_AUXEN_SET(value) ((UINT16)(((UINT16)(value)) << 14)) +#define HFA384x_CONTROL_AUXEN_GET(value) ((UINT16)(((UINT16)(value)) >> 14)) + +/* Byte Order */ +#ifdef __KERNEL__ +#define hfa384x2host_16(n) (__le16_to_cpu((UINT16)(n))) +#define hfa384x2host_32(n) (__le32_to_cpu((UINT32)(n))) +#define host2hfa384x_16(n) (__cpu_to_le16((UINT16)(n))) +#define host2hfa384x_32(n) (__cpu_to_le32((UINT32)(n))) +#endif + +/* Host Maintained State Info */ +#define HFA384x_STATE_PREINIT 0 +#define HFA384x_STATE_INIT 1 +#define HFA384x_STATE_RUNNING 2 + +/*=============================================================*/ +/*------ Types and their related constants --------------------*/ + +#define HFA384x_HOSTAUTHASSOC_HOSTAUTH BIT0 +#define HFA384x_HOSTAUTHASSOC_HOSTASSOC BIT1 + +#define HFA384x_WHAHANDLING_DISABLED 0 +#define HFA384x_WHAHANDLING_PASSTHROUGH BIT1 + +/*-------------------------------------------------------------*/ +/* Commonly used basic types */ +typedef struct hfa384x_bytestr +{ + UINT16 len; + UINT8 data[0]; +} __WLAN_ATTRIB_PACK__ hfa384x_bytestr_t; + +typedef struct hfa384x_bytestr32 +{ + UINT16 len; + UINT8 data[32]; +} __WLAN_ATTRIB_PACK__ hfa384x_bytestr32_t; + +/*-------------------------------------------------------------------- +Configuration Record Structures: + Network Parameters, Static Configuration Entities +--------------------------------------------------------------------*/ +/* Prototype structure: all configuration record structures start with +these members */ + +typedef struct hfa384x_record +{ + UINT16 reclen; + UINT16 rid; +} __WLAN_ATTRIB_PACK__ hfa384x_rec_t; + +typedef struct hfa384x_record16 +{ + UINT16 reclen; + UINT16 rid; + UINT16 val; +} __WLAN_ATTRIB_PACK__ hfa384x_rec16_t; + +typedef struct hfa384x_record32 +{ + UINT16 reclen; + UINT16 rid; + UINT32 val; +} __WLAN_ATTRIB_PACK__ hfa384x_rec32; + +/*-- Hardware/Firmware Component Information ----------*/ +typedef struct hfa384x_compident +{ + UINT16 id; + UINT16 variant; + UINT16 major; + UINT16 minor; +} __WLAN_ATTRIB_PACK__ hfa384x_compident_t; + +typedef struct hfa384x_caplevel +{ + UINT16 role; + UINT16 id; + UINT16 variant; + UINT16 bottom; + UINT16 top; +} __WLAN_ATTRIB_PACK__ hfa384x_caplevel_t; + +/*-- Configuration Record: cnfPortType --*/ +typedef struct hfa384x_cnfPortType +{ + UINT16 cnfPortType; +} __WLAN_ATTRIB_PACK__ hfa384x_cnfPortType_t; + +/*-- Configuration Record: cnfOwnMACAddress --*/ +typedef struct hfa384x_cnfOwnMACAddress +{ + UINT8 cnfOwnMACAddress[6]; +} __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnMACAddress_t; + +/*-- Configuration Record: cnfDesiredSSID --*/ +typedef struct hfa384x_cnfDesiredSSID +{ + UINT8 cnfDesiredSSID[34]; +} __WLAN_ATTRIB_PACK__ hfa384x_cnfDesiredSSID_t; + +/*-- Configuration Record: cnfOwnChannel --*/ +typedef struct hfa384x_cnfOwnChannel +{ + UINT16 cnfOwnChannel; +} __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnChannel_t; + +/*-- Configuration Record: cnfOwnSSID --*/ +typedef struct hfa384x_cnfOwnSSID +{ + UINT8 cnfOwnSSID[34]; +} __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnSSID_t; + +/*-- Configuration Record: cnfOwnATIMWindow --*/ +typedef struct hfa384x_cnfOwnATIMWindow +{ + UINT16 cnfOwnATIMWindow; +} __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnATIMWindow_t; + +/*-- Configuration Record: cnfSystemScale --*/ +typedef struct hfa384x_cnfSystemScale +{ + UINT16 cnfSystemScale; +} __WLAN_ATTRIB_PACK__ hfa384x_cnfSystemScale_t; + +/*-- Configuration Record: cnfMaxDataLength --*/ +typedef struct hfa384x_cnfMaxDataLength +{ + UINT16 cnfMaxDataLength; +} __WLAN_ATTRIB_PACK__ hfa384x_cnfMaxDataLength_t; + +/*-- Configuration Record: cnfWDSAddress --*/ +typedef struct hfa384x_cnfWDSAddress +{ + UINT8 cnfWDSAddress[6]; +} __WLAN_ATTRIB_PACK__ hfa384x_cnfWDSAddress_t; + +/*-- Configuration Record: cnfPMEnabled --*/ +typedef struct hfa384x_cnfPMEnabled +{ + UINT16 cnfPMEnabled; +} __WLAN_ATTRIB_PACK__ hfa384x_cnfPMEnabled_t; + +/*-- Configuration Record: cnfPMEPS --*/ +typedef struct hfa384x_cnfPMEPS +{ + UINT16 cnfPMEPS; +} __WLAN_ATTRIB_PACK__ hfa384x_cnfPMEPS_t; + +/*-- Configuration Record: cnfMulticastReceive --*/ +typedef struct hfa384x_cnfMulticastReceive +{ + UINT16 cnfMulticastReceive; +} __WLAN_ATTRIB_PACK__ hfa384x_cnfMulticastReceive_t; + +/*-- Configuration Record: cnfAuthentication --*/ +#define HFA384x_CNFAUTHENTICATION_OPENSYSTEM 0x0001 +#define HFA384x_CNFAUTHENTICATION_SHAREDKEY 0x0002 +#define HFA384x_CNFAUTHENTICATION_LEAP 0x0004 + +/*-- Configuration Record: cnfMaxSleepDuration --*/ +typedef struct hfa384x_cnfMaxSleepDuration +{ + UINT16 cnfMaxSleepDuration; +} __WLAN_ATTRIB_PACK__ hfa384x_cnfMaxSleepDuration_t; + +/*-- Configuration Record: cnfPMHoldoverDuration --*/ +typedef struct hfa384x_cnfPMHoldoverDuration +{ + UINT16 cnfPMHoldoverDuration; +} __WLAN_ATTRIB_PACK__ hfa384x_cnfPMHoldoverDuration_t; + +/*-- Configuration Record: cnfOwnName --*/ +typedef struct hfa384x_cnfOwnName +{ + UINT8 cnfOwnName[34]; +} __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnName_t; + +/*-- Configuration Record: cnfOwnDTIMPeriod --*/ +typedef struct hfa384x_cnfOwnDTIMPeriod +{ + UINT16 cnfOwnDTIMPeriod; +} __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnDTIMPeriod_t; + +/*-- Configuration Record: cnfWDSAddress --*/ +typedef struct hfa384x_cnfWDSAddressN +{ + UINT8 cnfWDSAddress[6]; +} __WLAN_ATTRIB_PACK__ hfa384x_cnfWDSAddressN_t; + +/*-- Configuration Record: cnfMulticastPMBuffering --*/ +typedef struct hfa384x_cnfMulticastPMBuffering +{ + UINT16 cnfMulticastPMBuffering; +} __WLAN_ATTRIB_PACK__ hfa384x_cnfMulticastPMBuffering_t; + +/*-------------------------------------------------------------------- +Configuration Record Structures: + Network Parameters, Dynamic Configuration Entities +--------------------------------------------------------------------*/ + +/*-- Configuration Record: GroupAddresses --*/ +typedef struct hfa384x_GroupAddresses +{ + UINT8 MACAddress[16][6]; +} __WLAN_ATTRIB_PACK__ hfa384x_GroupAddresses_t; + +/*-- Configuration Record: CreateIBSS --*/ +typedef struct hfa384x_CreateIBSS +{ + UINT16 CreateIBSS; +} __WLAN_ATTRIB_PACK__ hfa384x_CreateIBSS_t; + +#define HFA384x_CREATEIBSS_JOINCREATEIBSS 0 +#define HFA384x_CREATEIBSS_JOINESS_JOINCREATEIBSS 1 +#define HFA384x_CREATEIBSS_JOINIBSS 2 +#define HFA384x_CREATEIBSS_JOINESS_JOINIBSS 3 + +/*-- Configuration Record: FragmentationThreshold --*/ +typedef struct hfa384x_FragmentationThreshold +{ + UINT16 FragmentationThreshold; +} __WLAN_ATTRIB_PACK__ hfa384x_FragmentationThreshold_t; + +/*-- Configuration Record: RTSThreshold --*/ +typedef struct hfa384x_RTSThreshold +{ + UINT16 RTSThreshold; +} __WLAN_ATTRIB_PACK__ hfa384x_RTSThreshold_t; + +/*-- Configuration Record: TxRateControl --*/ +typedef struct hfa384x_TxRateControl +{ + UINT16 TxRateControl; +} __WLAN_ATTRIB_PACK__ hfa384x_TxRateControl_t; + +/*-- Configuration Record: PromiscuousMode --*/ +typedef struct hfa384x_PromiscuousMode +{ + UINT16 PromiscuousMode; +} __WLAN_ATTRIB_PACK__ hfa384x_PromiscuousMode_t; + +/*-- Configuration Record: ScanRequest (data portion only) --*/ +typedef struct hfa384x_ScanRequest_data +{ + UINT16 channelList; + UINT16 txRate; +} __WLAN_ATTRIB_PACK__ hfa384x_ScanRequest_data_t; + +/*-- Configuration Record: HostScanRequest (data portion only) --*/ +typedef struct hfa384x_HostScanRequest_data +{ + UINT16 channelList; + UINT16 txRate; + hfa384x_bytestr32_t ssid; +} __WLAN_ATTRIB_PACK__ hfa384x_HostScanRequest_data_t; + +/*-- Configuration Record: JoinRequest (data portion only) --*/ +typedef struct hfa384x_JoinRequest_data +{ + UINT8 bssid[WLAN_BSSID_LEN]; + UINT16 channel; +} __WLAN_ATTRIB_PACK__ hfa384x_JoinRequest_data_t; + +/*-- Configuration Record: authenticateStation (data portion only) --*/ +typedef struct hfa384x_authenticateStation_data +{ + UINT8 address[WLAN_ADDR_LEN]; + UINT16 status; + UINT16 algorithm; +} __WLAN_ATTRIB_PACK__ hfa384x_authenticateStation_data_t; + +/*-- Configuration Record: associateStation (data portion only) --*/ +typedef struct hfa384x_associateStation_data +{ + UINT8 address[WLAN_ADDR_LEN]; + UINT16 status; + UINT16 type; +} __WLAN_ATTRIB_PACK__ hfa384x_associateStation_data_t; + +/*-- Configuration Record: ChannelInfoRequest (data portion only) --*/ +typedef struct hfa384x_ChannelInfoRequest_data +{ + UINT16 channelList; + UINT16 channelDwellTime; +} __WLAN_ATTRIB_PACK__ hfa384x_ChannelInfoRequest_data_t; + +/*-- Configuration Record: WEPKeyMapping (data portion only) --*/ +typedef struct hfa384x_WEPKeyMapping +{ + UINT8 address[WLAN_ADDR_LEN]; + UINT16 key_index; + UINT8 key[16]; + UINT8 mic_transmit_key[4]; + UINT8 mic_receive_key[4]; +} __WLAN_ATTRIB_PACK__ hfa384x_WEPKeyMapping_t; + +/*-- Configuration Record: WPAData (data portion only) --*/ +typedef struct hfa384x_WPAData +{ + UINT16 datalen; + UINT8 data[0]; // max 80 +} __WLAN_ATTRIB_PACK__ hfa384x_WPAData_t; + +/*-------------------------------------------------------------------- +Configuration Record Structures: Behavior Parameters +--------------------------------------------------------------------*/ + +/*-- Configuration Record: TickTime --*/ +typedef struct hfa384x_TickTime +{ + UINT16 TickTime; +} __WLAN_ATTRIB_PACK__ hfa384x_TickTime_t; + +/*-------------------------------------------------------------------- +Information Record Structures: NIC Information +--------------------------------------------------------------------*/ + +/*-- Information Record: MaxLoadTime --*/ +typedef struct hfa384x_MaxLoadTime +{ + UINT16 MaxLoadTime; +} __WLAN_ATTRIB_PACK__ hfa384x_MaxLoadTime_t; + +/*-- Information Record: DownLoadBuffer --*/ +/* NOTE: The page and offset are in AUX format */ +typedef struct hfa384x_downloadbuffer +{ + UINT16 page; + UINT16 offset; + UINT16 len; +} __WLAN_ATTRIB_PACK__ hfa384x_downloadbuffer_t; + +/*-- Information Record: PRIIdentity --*/ +typedef struct hfa384x_PRIIdentity +{ + UINT16 PRICompID; + UINT16 PRIVariant; + UINT16 PRIMajorVersion; + UINT16 PRIMinorVersion; +} __WLAN_ATTRIB_PACK__ hfa384x_PRIIdentity_t; + +/*-- Information Record: PRISupRange --*/ +typedef struct hfa384x_PRISupRange +{ + UINT16 PRIRole; + UINT16 PRIID; + UINT16 PRIVariant; + UINT16 PRIBottom; + UINT16 PRITop; +} __WLAN_ATTRIB_PACK__ hfa384x_PRISupRange_t; + +/*-- Information Record: CFIActRanges --*/ +typedef struct hfa384x_CFIActRanges +{ + UINT16 CFIRole; + UINT16 CFIID; + UINT16 CFIVariant; + UINT16 CFIBottom; + UINT16 CFITop; +} __WLAN_ATTRIB_PACK__ hfa384x_CFIActRanges_t; + +/*-- Information Record: NICSerialNumber --*/ +typedef struct hfa384x_NICSerialNumber +{ + UINT8 NICSerialNumber[12]; +} __WLAN_ATTRIB_PACK__ hfa384x_NICSerialNumber_t; + +/*-- Information Record: NICIdentity --*/ +typedef struct hfa384x_NICIdentity +{ + UINT16 NICCompID; + UINT16 NICVariant; + UINT16 NICMajorVersion; + UINT16 NICMinorVersion; +} __WLAN_ATTRIB_PACK__ hfa384x_NICIdentity_t; + +/*-- Information Record: MFISupRange --*/ +typedef struct hfa384x_MFISupRange +{ + UINT16 MFIRole; + UINT16 MFIID; + UINT16 MFIVariant; + UINT16 MFIBottom; + UINT16 MFITop; +} __WLAN_ATTRIB_PACK__ hfa384x_MFISupRange_t; + +/*-- Information Record: CFISupRange --*/ +typedef struct hfa384x_CFISupRange +{ + UINT16 CFIRole; + UINT16 CFIID; + UINT16 CFIVariant; + UINT16 CFIBottom; + UINT16 CFITop; +} __WLAN_ATTRIB_PACK__ hfa384x_CFISupRange_t; + +/*-- Information Record: BUILDSEQ:BuildSeq --*/ +typedef struct hfa384x_BuildSeq { + UINT16 primary; + UINT16 secondary; +} __WLAN_ATTRIB_PACK__ hfa384x_BuildSeq_t; + +/*-- Information Record: FWID --*/ +#define HFA384x_FWID_LEN 14 +typedef struct hfa384x_FWID { + UINT8 primary[HFA384x_FWID_LEN]; + UINT8 secondary[HFA384x_FWID_LEN]; +} __WLAN_ATTRIB_PACK__ hfa384x_FWID_t; + +/*-- Information Record: ChannelList --*/ +typedef struct hfa384x_ChannelList +{ + UINT16 ChannelList; +} __WLAN_ATTRIB_PACK__ hfa384x_ChannelList_t; + +/*-- Information Record: RegulatoryDomains --*/ +typedef struct hfa384x_RegulatoryDomains +{ + UINT8 RegulatoryDomains[12]; +} __WLAN_ATTRIB_PACK__ hfa384x_RegulatoryDomains_t; + +/*-- Information Record: TempType --*/ +typedef struct hfa384x_TempType +{ + UINT16 TempType; +} __WLAN_ATTRIB_PACK__ hfa384x_TempType_t; + +/*-- Information Record: CIS --*/ +typedef struct hfa384x_CIS +{ + UINT8 CIS[480]; +} __WLAN_ATTRIB_PACK__ hfa384x_CIS_t; + +/*-- Information Record: STAIdentity --*/ +typedef struct hfa384x_STAIdentity +{ + UINT16 STACompID; + UINT16 STAVariant; + UINT16 STAMajorVersion; + UINT16 STAMinorVersion; +} __WLAN_ATTRIB_PACK__ hfa384x_STAIdentity_t; + +/*-- Information Record: STASupRange --*/ +typedef struct hfa384x_STASupRange +{ + UINT16 STARole; + UINT16 STAID; + UINT16 STAVariant; + UINT16 STABottom; + UINT16 STATop; +} __WLAN_ATTRIB_PACK__ hfa384x_STASupRange_t; + +/*-- Information Record: MFIActRanges --*/ +typedef struct hfa384x_MFIActRanges +{ + UINT16 MFIRole; + UINT16 MFIID; + UINT16 MFIVariant; + UINT16 MFIBottom; + UINT16 MFITop; +} __WLAN_ATTRIB_PACK__ hfa384x_MFIActRanges_t; + +/*-------------------------------------------------------------------- +Information Record Structures: NIC Information +--------------------------------------------------------------------*/ + +/*-- Information Record: PortStatus --*/ +typedef struct hfa384x_PortStatus +{ + UINT16 PortStatus; +} __WLAN_ATTRIB_PACK__ hfa384x_PortStatus_t; + +#define HFA384x_PSTATUS_DISABLED ((UINT16)1) +#define HFA384x_PSTATUS_SEARCHING ((UINT16)2) +#define HFA384x_PSTATUS_CONN_IBSS ((UINT16)3) +#define HFA384x_PSTATUS_CONN_ESS ((UINT16)4) +#define HFA384x_PSTATUS_OUTOFRANGE ((UINT16)5) +#define HFA384x_PSTATUS_CONN_WDS ((UINT16)6) + +/*-- Information Record: CurrentSSID --*/ +typedef struct hfa384x_CurrentSSID +{ + UINT8 CurrentSSID[34]; +} __WLAN_ATTRIB_PACK__ hfa384x_CurrentSSID_t; + +/*-- Information Record: CurrentBSSID --*/ +typedef struct hfa384x_CurrentBSSID +{ + UINT8 CurrentBSSID[6]; +} __WLAN_ATTRIB_PACK__ hfa384x_CurrentBSSID_t; + +/*-- Information Record: commsquality --*/ +typedef struct hfa384x_commsquality +{ + UINT16 CQ_currBSS; + UINT16 ASL_currBSS; + UINT16 ANL_currFC; +} __WLAN_ATTRIB_PACK__ hfa384x_commsquality_t; + +/*-- Information Record: dmbcommsquality --*/ +typedef struct hfa384x_dbmcommsquality +{ + UINT16 CQdbm_currBSS; + UINT16 ASLdbm_currBSS; + UINT16 ANLdbm_currFC; +} __WLAN_ATTRIB_PACK__ hfa384x_dbmcommsquality_t; + +/*-- Information Record: CurrentTxRate --*/ +typedef struct hfa384x_CurrentTxRate +{ + UINT16 CurrentTxRate; +} __WLAN_ATTRIB_PACK__ hfa384x_CurrentTxRate_t; + +/*-- Information Record: CurrentBeaconInterval --*/ +typedef struct hfa384x_CurrentBeaconInterval +{ + UINT16 CurrentBeaconInterval; +} __WLAN_ATTRIB_PACK__ hfa384x_CurrentBeaconInterval_t; + +/*-- Information Record: CurrentScaleThresholds --*/ +typedef struct hfa384x_CurrentScaleThresholds +{ + UINT16 EnergyDetectThreshold; + UINT16 CarrierDetectThreshold; + UINT16 DeferDetectThreshold; + UINT16 CellSearchThreshold; /* Stations only */ + UINT16 DeadSpotThreshold; /* Stations only */ +} __WLAN_ATTRIB_PACK__ hfa384x_CurrentScaleThresholds_t; + +/*-- Information Record: ProtocolRspTime --*/ +typedef struct hfa384x_ProtocolRspTime +{ + UINT16 ProtocolRspTime; +} __WLAN_ATTRIB_PACK__ hfa384x_ProtocolRspTime_t; + +/*-- Information Record: ShortRetryLimit --*/ +typedef struct hfa384x_ShortRetryLimit +{ + UINT16 ShortRetryLimit; +} __WLAN_ATTRIB_PACK__ hfa384x_ShortRetryLimit_t; + +/*-- Information Record: LongRetryLimit --*/ +typedef struct hfa384x_LongRetryLimit +{ + UINT16 LongRetryLimit; +} __WLAN_ATTRIB_PACK__ hfa384x_LongRetryLimit_t; + +/*-- Information Record: MaxTransmitLifetime --*/ +typedef struct hfa384x_MaxTransmitLifetime +{ + UINT16 MaxTransmitLifetime; +} __WLAN_ATTRIB_PACK__ hfa384x_MaxTransmitLifetime_t; + +/*-- Information Record: MaxReceiveLifetime --*/ +typedef struct hfa384x_MaxReceiveLifetime +{ + UINT16 MaxReceiveLifetime; +} __WLAN_ATTRIB_PACK__ hfa384x_MaxReceiveLifetime_t; + +/*-- Information Record: CFPollable --*/ +typedef struct hfa384x_CFPollable +{ + UINT16 CFPollable; +} __WLAN_ATTRIB_PACK__ hfa384x_CFPollable_t; + +/*-- Information Record: AuthenticationAlgorithms --*/ +typedef struct hfa384x_AuthenticationAlgorithms +{ + UINT16 AuthenticationType; + UINT16 TypeEnabled; +} __WLAN_ATTRIB_PACK__ hfa384x_AuthenticationAlgorithms_t; + +/*-- Information Record: AuthenticationAlgorithms +(data only --*/ +typedef struct hfa384x_AuthenticationAlgorithms_data +{ + UINT16 AuthenticationType; + UINT16 TypeEnabled; +} __WLAN_ATTRIB_PACK__ hfa384x_AuthenticationAlgorithms_data_t; + +/*-- Information Record: PrivacyOptionImplemented --*/ +typedef struct hfa384x_PrivacyOptionImplemented +{ + UINT16 PrivacyOptionImplemented; +} __WLAN_ATTRIB_PACK__ hfa384x_PrivacyOptionImplemented_t; + +/*-- Information Record: OwnMACAddress --*/ +typedef struct hfa384x_OwnMACAddress +{ + UINT8 OwnMACAddress[6]; +} __WLAN_ATTRIB_PACK__ hfa384x_OwnMACAddress_t; + +/*-- Information Record: PCFInfo --*/ +typedef struct hfa384x_PCFInfo +{ + UINT16 MediumOccupancyLimit; + UINT16 CFPPeriod; + UINT16 CFPMaxDuration; + UINT16 CFPFlags; +} __WLAN_ATTRIB_PACK__ hfa384x_PCFInfo_t; + +/*-- Information Record: PCFInfo (data portion only) --*/ +typedef struct hfa384x_PCFInfo_data +{ + UINT16 MediumOccupancyLimit; + UINT16 CFPPeriod; + UINT16 CFPMaxDuration; + UINT16 CFPFlags; +} __WLAN_ATTRIB_PACK__ hfa384x_PCFInfo_data_t; + +/*-------------------------------------------------------------------- +Information Record Structures: Modem Information Records +--------------------------------------------------------------------*/ + +/*-- Information Record: PHYType --*/ +typedef struct hfa384x_PHYType +{ + UINT16 PHYType; +} __WLAN_ATTRIB_PACK__ hfa384x_PHYType_t; + +/*-- Information Record: CurrentChannel --*/ +typedef struct hfa384x_CurrentChannel +{ + UINT16 CurrentChannel; +} __WLAN_ATTRIB_PACK__ hfa384x_CurrentChannel_t; + +/*-- Information Record: CurrentPowerState --*/ +typedef struct hfa384x_CurrentPowerState +{ + UINT16 CurrentPowerState; +} __WLAN_ATTRIB_PACK__ hfa384x_CurrentPowerState_t; + +/*-- Information Record: CCAMode --*/ +typedef struct hfa384x_CCAMode +{ + UINT16 CCAMode; +} __WLAN_ATTRIB_PACK__ hfa384x_CCAMode_t; + +/*-- Information Record: SupportedDataRates --*/ +typedef struct hfa384x_SupportedDataRates +{ + UINT8 SupportedDataRates[10]; +} __WLAN_ATTRIB_PACK__ hfa384x_SupportedDataRates_t; + +/*-- Information Record: LFOStatus --*/ +typedef struct hfa384x_LFOStatus +{ + UINT16 TestResults; + UINT16 LFOResult; + UINT16 VRHFOResult; +} __WLAN_ATTRIB_PACK__ hfa384x_LFOStatus_t; + +#define HFA384x_TESTRESULT_ALLPASSED BIT0 +#define HFA384x_TESTRESULT_LFO_FAIL BIT1 +#define HFA384x_TESTRESULT_VR_HF0_FAIL BIT2 +#define HFA384x_HOST_FIRM_COORDINATE BIT7 +#define HFA384x_TESTRESULT_COORDINATE BIT15 + +/*-- Information Record: LEDControl --*/ +typedef struct hfa384x_LEDControl +{ + UINT16 searching_on; + UINT16 searching_off; + UINT16 assoc_on; + UINT16 assoc_off; + UINT16 activity; +} __WLAN_ATTRIB_PACK__ hfa384x_LEDControl_t; + +/*-------------------------------------------------------------------- + FRAME DESCRIPTORS AND FRAME STRUCTURES + +FRAME DESCRIPTORS: Offsets + +---------------------------------------------------------------------- +Control Info (offset 44-51) +--------------------------------------------------------------------*/ +#define HFA384x_FD_STATUS_OFF ((UINT16)0x44) +#define HFA384x_FD_TIME_OFF ((UINT16)0x46) +#define HFA384x_FD_SWSUPPORT_OFF ((UINT16)0x4A) +#define HFA384x_FD_SILENCE_OFF ((UINT16)0x4A) +#define HFA384x_FD_SIGNAL_OFF ((UINT16)0x4B) +#define HFA384x_FD_RATE_OFF ((UINT16)0x4C) +#define HFA384x_FD_RXFLOW_OFF ((UINT16)0x4D) +#define HFA384x_FD_RESERVED_OFF ((UINT16)0x4E) +#define HFA384x_FD_TXCONTROL_OFF ((UINT16)0x50) +/*-------------------------------------------------------------------- +802.11 Header (offset 52-6B) +--------------------------------------------------------------------*/ +#define HFA384x_FD_FRAMECONTROL_OFF ((UINT16)0x52) +#define HFA384x_FD_DURATIONID_OFF ((UINT16)0x54) +#define HFA384x_FD_ADDRESS1_OFF ((UINT16)0x56) +#define HFA384x_FD_ADDRESS2_OFF ((UINT16)0x5C) +#define HFA384x_FD_ADDRESS3_OFF ((UINT16)0x62) +#define HFA384x_FD_SEQCONTROL_OFF ((UINT16)0x68) +#define HFA384x_FD_ADDRESS4_OFF ((UINT16)0x6A) +#define HFA384x_FD_DATALEN_OFF ((UINT16)0x70) +/*-------------------------------------------------------------------- +802.3 Header (offset 72-7F) +--------------------------------------------------------------------*/ +#define HFA384x_FD_DESTADDRESS_OFF ((UINT16)0x72) +#define HFA384x_FD_SRCADDRESS_OFF ((UINT16)0x78) +#define HFA384x_FD_DATALENGTH_OFF ((UINT16)0x7E) + +/*-------------------------------------------------------------------- +FRAME STRUCTURES: Communication Frames +---------------------------------------------------------------------- +Communication Frames: Transmit Frames +--------------------------------------------------------------------*/ +/*-- Communication Frame: Transmit Frame Structure --*/ +typedef struct hfa384x_tx_frame +{ + UINT16 status; + UINT16 reserved1; + UINT16 reserved2; + UINT32 sw_support; + UINT8 tx_retrycount; + UINT8 tx_rate; + UINT16 tx_control; + + /*-- 802.11 Header Information --*/ + + UINT16 frame_control; + UINT16 duration_id; + UINT8 address1[6]; + UINT8 address2[6]; + UINT8 address3[6]; + UINT16 sequence_control; + UINT8 address4[6]; + UINT16 data_len; /* little endian format */ + + /*-- 802.3 Header Information --*/ + + UINT8 dest_addr[6]; + UINT8 src_addr[6]; + UINT16 data_length; /* big endian format */ +} __WLAN_ATTRIB_PACK__ hfa384x_tx_frame_t; +/*-------------------------------------------------------------------- +Communication Frames: Field Masks for Transmit Frames +--------------------------------------------------------------------*/ +/*-- Status Field --*/ +#define HFA384x_TXSTATUS_ACKERR ((UINT16)BIT5) +#define HFA384x_TXSTATUS_FORMERR ((UINT16)BIT3) +#define HFA384x_TXSTATUS_DISCON ((UINT16)BIT2) +#define HFA384x_TXSTATUS_AGEDERR ((UINT16)BIT1) +#define HFA384x_TXSTATUS_RETRYERR ((UINT16)BIT0) +/*-- Transmit Control Field --*/ +#define HFA384x_TX_CFPOLL ((UINT16)BIT12) +#define HFA384x_TX_PRST ((UINT16)BIT11) +#define HFA384x_TX_MACPORT ((UINT16)(BIT10 | BIT9 | BIT8)) +#define HFA384x_TX_NOENCRYPT ((UINT16)BIT7) +#define HFA384x_TX_RETRYSTRAT ((UINT16)(BIT6 | BIT5)) +#define HFA384x_TX_STRUCTYPE ((UINT16)(BIT4 | BIT3)) +#define HFA384x_TX_TXEX ((UINT16)BIT2) +#define HFA384x_TX_TXOK ((UINT16)BIT1) +/*-------------------------------------------------------------------- +Communication Frames: Test/Get/Set Field Values for Transmit Frames +--------------------------------------------------------------------*/ +/*-- Status Field --*/ +#define HFA384x_TXSTATUS_ISERROR(v) \ + (((UINT16)(v))&\ + (HFA384x_TXSTATUS_ACKERR|HFA384x_TXSTATUS_FORMERR|\ + HFA384x_TXSTATUS_DISCON|HFA384x_TXSTATUS_AGEDERR|\ + HFA384x_TXSTATUS_RETRYERR)) + +#define HFA384x_TXSTATUS_ISACKERR(v) ((UINT16)(((UINT16)(v)) & HFA384x_TXSTATUS_ACKERR)) +#define HFA384x_TXSTATUS_ISFORMERR(v) ((UINT16)(((UINT16)(v)) & HFA384x_TXSTATUS_FORMERR)) +#define HFA384x_TXSTATUS_ISDISCON(v) ((UINT16)(((UINT16)(v)) & HFA384x_TXSTATUS_DISCON)) +#define HFA384x_TXSTATUS_ISAGEDERR(v) ((UINT16)(((UINT16)(v)) & HFA384x_TXSTATUS_AGEDERR)) +#define HFA384x_TXSTATUS_ISRETRYERR(v) ((UINT16)(((UINT16)(v)) & HFA384x_TXSTATUS_RETRYERR)) + +#define HFA384x_TX_GET(v,m,s) ((((UINT16)(v))&((UINT16)(m)))>>((UINT16)(s))) +#define HFA384x_TX_SET(v,m,s) ((((UINT16)(v))<<((UINT16)(s)))&((UINT16)(m))) + +#define HFA384x_TX_CFPOLL_GET(v) HFA384x_TX_GET(v, HFA384x_TX_CFPOLL,12) +#define HFA384x_TX_CFPOLL_SET(v) HFA384x_TX_SET(v, HFA384x_TX_CFPOLL,12) +#define HFA384x_TX_PRST_GET(v) HFA384x_TX_GET(v, HFA384x_TX_PRST,11) +#define HFA384x_TX_PRST_SET(v) HFA384x_TX_SET(v, HFA384x_TX_PRST,11) +#define HFA384x_TX_MACPORT_GET(v) HFA384x_TX_GET(v, HFA384x_TX_MACPORT, 8) +#define HFA384x_TX_MACPORT_SET(v) HFA384x_TX_SET(v, HFA384x_TX_MACPORT, 8) +#define HFA384x_TX_NOENCRYPT_GET(v) HFA384x_TX_GET(v, HFA384x_TX_NOENCRYPT, 7) +#define HFA384x_TX_NOENCRYPT_SET(v) HFA384x_TX_SET(v, HFA384x_TX_NOENCRYPT, 7) +#define HFA384x_TX_RETRYSTRAT_GET(v) HFA384x_TX_GET(v, HFA384x_TX_RETRYSTRAT, 5) +#define HFA384x_TX_RETRYSTRAT_SET(v) HFA384x_TX_SET(v, HFA384x_TX_RETRYSTRAT, 5) +#define HFA384x_TX_STRUCTYPE_GET(v) HFA384x_TX_GET(v, HFA384x_TX_STRUCTYPE, 3) +#define HFA384x_TX_STRUCTYPE_SET(v) HFA384x_TX_SET(v, HFA384x_TX_STRUCTYPE, 3) +#define HFA384x_TX_TXEX_GET(v) HFA384x_TX_GET(v, HFA384x_TX_TXEX, 2) +#define HFA384x_TX_TXEX_SET(v) HFA384x_TX_SET(v, HFA384x_TX_TXEX, 2) +#define HFA384x_TX_TXOK_GET(v) HFA384x_TX_GET(v, HFA384x_TX_TXOK, 1) +#define HFA384x_TX_TXOK_SET(v) HFA384x_TX_SET(v, HFA384x_TX_TXOK, 1) +/*-------------------------------------------------------------------- +Communication Frames: Receive Frames +--------------------------------------------------------------------*/ +/*-- Communication Frame: Receive Frame Structure --*/ +typedef struct hfa384x_rx_frame +{ + /*-- MAC rx descriptor (hfa384x byte order) --*/ + UINT16 status; + UINT32 time; + UINT8 silence; + UINT8 signal; + UINT8 rate; + UINT8 rx_flow; + UINT16 reserved1; + UINT16 reserved2; + + /*-- 802.11 Header Information (802.11 byte order) --*/ + UINT16 frame_control; + UINT16 duration_id; + UINT8 address1[6]; + UINT8 address2[6]; + UINT8 address3[6]; + UINT16 sequence_control; + UINT8 address4[6]; + UINT16 data_len; /* hfa384x (little endian) format */ + + /*-- 802.3 Header Information --*/ + UINT8 dest_addr[6]; + UINT8 src_addr[6]; + UINT16 data_length; /* IEEE? (big endian) format */ +} __WLAN_ATTRIB_PACK__ hfa384x_rx_frame_t; +/*-------------------------------------------------------------------- +Communication Frames: Field Masks for Receive Frames +--------------------------------------------------------------------*/ +/*-- Offsets --------*/ +#define HFA384x_RX_DATA_LEN_OFF ((UINT16)44) +#define HFA384x_RX_80211HDR_OFF ((UINT16)14) +#define HFA384x_RX_DATA_OFF ((UINT16)60) + +/*-- Status Fields --*/ +#define HFA384x_RXSTATUS_MSGTYPE ((UINT16)(BIT15 | BIT14 | BIT13)) +#define HFA384x_RXSTATUS_MACPORT ((UINT16)(BIT10 | BIT9 | BIT8)) +#define HFA384x_RXSTATUS_UNDECR ((UINT16)BIT1) +#define HFA384x_RXSTATUS_FCSERR ((UINT16)BIT0) +/*-------------------------------------------------------------------- +Communication Frames: Test/Get/Set Field Values for Receive Frames +--------------------------------------------------------------------*/ +#define HFA384x_RXSTATUS_MSGTYPE_GET(value) ((UINT16)((((UINT16)(value)) & HFA384x_RXSTATUS_MSGTYPE) >> 13)) +#define HFA384x_RXSTATUS_MSGTYPE_SET(value) ((UINT16)(((UINT16)(value)) << 13)) +#define HFA384x_RXSTATUS_MACPORT_GET(value) ((UINT16)((((UINT16)(value)) & HFA384x_RXSTATUS_MACPORT) >> 8)) +#define HFA384x_RXSTATUS_MACPORT_SET(value) ((UINT16)(((UINT16)(value)) << 8)) +#define HFA384x_RXSTATUS_ISUNDECR(value) ((UINT16)(((UINT16)(value)) & HFA384x_RXSTATUS_UNDECR)) +#define HFA384x_RXSTATUS_ISFCSERR(value) ((UINT16)(((UINT16)(value)) & HFA384x_RXSTATUS_FCSERR)) +/*-------------------------------------------------------------------- + FRAME STRUCTURES: Information Types and Information Frame Structures +---------------------------------------------------------------------- +Information Types +--------------------------------------------------------------------*/ +#define HFA384x_IT_HANDOVERADDR ((UINT16)0xF000UL) +#define HFA384x_IT_HANDOVERDEAUTHADDRESS ((UINT16)0xF001UL)//AP 1.3.7 +#define HFA384x_IT_COMMTALLIES ((UINT16)0xF100UL) +#define HFA384x_IT_SCANRESULTS ((UINT16)0xF101UL) +#define HFA384x_IT_CHINFORESULTS ((UINT16)0xF102UL) +#define HFA384x_IT_HOSTSCANRESULTS ((UINT16)0xF103UL) +#define HFA384x_IT_LINKSTATUS ((UINT16)0xF200UL) +#define HFA384x_IT_ASSOCSTATUS ((UINT16)0xF201UL) +#define HFA384x_IT_AUTHREQ ((UINT16)0xF202UL) +#define HFA384x_IT_PSUSERCNT ((UINT16)0xF203UL) +#define HFA384x_IT_KEYIDCHANGED ((UINT16)0xF204UL) +#define HFA384x_IT_ASSOCREQ ((UINT16)0xF205UL) +#define HFA384x_IT_MICFAILURE ((UINT16)0xF206UL) + +/*-------------------------------------------------------------------- +Information Frames Structures +---------------------------------------------------------------------- +Information Frames: Notification Frame Structures +--------------------------------------------------------------------*/ +/*-- Notification Frame,MAC Mgmt: Handover Address --*/ +typedef struct hfa384x_HandoverAddr +{ + UINT16 framelen; + UINT16 infotype; + UINT8 handover_addr[WLAN_BSSID_LEN]; +} __WLAN_ATTRIB_PACK__ hfa384x_HandoverAddr_t; + +/*-- Inquiry Frame, Diagnose: Communication Tallies --*/ +typedef struct hfa384x_CommTallies16 +{ + UINT16 txunicastframes; + UINT16 txmulticastframes; + UINT16 txfragments; + UINT16 txunicastoctets; + UINT16 txmulticastoctets; + UINT16 txdeferredtrans; + UINT16 txsingleretryframes; + UINT16 txmultipleretryframes; + UINT16 txretrylimitexceeded; + UINT16 txdiscards; + UINT16 rxunicastframes; + UINT16 rxmulticastframes; + UINT16 rxfragments; + UINT16 rxunicastoctets; + UINT16 rxmulticastoctets; + UINT16 rxfcserrors; + UINT16 rxdiscardsnobuffer; + UINT16 txdiscardswrongsa; + UINT16 rxdiscardswepundecr; + UINT16 rxmsginmsgfrag; + UINT16 rxmsginbadmsgfrag; +} __WLAN_ATTRIB_PACK__ hfa384x_CommTallies16_t; + +typedef struct hfa384x_CommTallies32 +{ + UINT32 txunicastframes; + UINT32 txmulticastframes; + UINT32 txfragments; + UINT32 txunicastoctets; + UINT32 txmulticastoctets; + UINT32 txdeferredtrans; + UINT32 txsingleretryframes; + UINT32 txmultipleretryframes; + UINT32 txretrylimitexceeded; + UINT32 txdiscards; + UINT32 rxunicastframes; + UINT32 rxmulticastframes; + UINT32 rxfragments; + UINT32 rxunicastoctets; + UINT32 rxmulticastoctets; + UINT32 rxfcserrors; + UINT32 rxdiscardsnobuffer; + UINT32 txdiscardswrongsa; + UINT32 rxdiscardswepundecr; + UINT32 rxmsginmsgfrag; + UINT32 rxmsginbadmsgfrag; +} __WLAN_ATTRIB_PACK__ hfa384x_CommTallies32_t; + +/*-- Inquiry Frame, Diagnose: Scan Results & Subfields--*/ +typedef struct hfa384x_ScanResultSub +{ + UINT16 chid; + UINT16 anl; + UINT16 sl; + UINT8 bssid[WLAN_BSSID_LEN]; + UINT16 bcnint; + UINT16 capinfo; + hfa384x_bytestr32_t ssid; + UINT8 supprates[10]; /* 802.11 info element */ + UINT16 proberesp_rate; +} __WLAN_ATTRIB_PACK__ hfa384x_ScanResultSub_t; + +typedef struct hfa384x_ScanResult +{ + UINT16 rsvd; + UINT16 scanreason; + hfa384x_ScanResultSub_t + result[HFA384x_SCANRESULT_MAX]; +} __WLAN_ATTRIB_PACK__ hfa384x_ScanResult_t; + +/*-- Inquiry Frame, Diagnose: ChInfo Results & Subfields--*/ +typedef struct hfa384x_ChInfoResultSub +{ + UINT16 chid; + UINT16 anl; + UINT16 pnl; + UINT16 active; +} __WLAN_ATTRIB_PACK__ hfa384x_ChInfoResultSub_t; + +#define HFA384x_CHINFORESULT_BSSACTIVE BIT0 +#define HFA384x_CHINFORESULT_PCFACTIVE BIT1 + +typedef struct hfa384x_ChInfoResult +{ + UINT16 scanchannels; + hfa384x_ChInfoResultSub_t + result[HFA384x_CHINFORESULT_MAX]; +} __WLAN_ATTRIB_PACK__ hfa384x_ChInfoResult_t; + +/*-- Inquiry Frame, Diagnose: Host Scan Results & Subfields--*/ +typedef struct hfa384x_HScanResultSub +{ + UINT16 chid; + UINT16 anl; + UINT16 sl; + UINT8 bssid[WLAN_BSSID_LEN]; + UINT16 bcnint; + UINT16 capinfo; + hfa384x_bytestr32_t ssid; + UINT8 supprates[10]; /* 802.11 info element */ + UINT16 proberesp_rate; + UINT16 atim; +} __WLAN_ATTRIB_PACK__ hfa384x_HScanResultSub_t; + +typedef struct hfa384x_HScanResult +{ + UINT16 nresult; + UINT16 rsvd; + hfa384x_HScanResultSub_t + result[HFA384x_HSCANRESULT_MAX]; +} __WLAN_ATTRIB_PACK__ hfa384x_HScanResult_t; + +/*-- Unsolicited Frame, MAC Mgmt: LinkStatus --*/ + +#define HFA384x_LINK_NOTCONNECTED ((UINT16)0) +#define HFA384x_LINK_CONNECTED ((UINT16)1) +#define HFA384x_LINK_DISCONNECTED ((UINT16)2) +#define HFA384x_LINK_AP_CHANGE ((UINT16)3) +#define HFA384x_LINK_AP_OUTOFRANGE ((UINT16)4) +#define HFA384x_LINK_AP_INRANGE ((UINT16)5) +#define HFA384x_LINK_ASSOCFAIL ((UINT16)6) + +typedef struct hfa384x_LinkStatus +{ + UINT16 linkstatus; +} __WLAN_ATTRIB_PACK__ hfa384x_LinkStatus_t; + + +/*-- Unsolicited Frame, MAC Mgmt: AssociationStatus (--*/ + +#define HFA384x_ASSOCSTATUS_STAASSOC ((UINT16)1) +#define HFA384x_ASSOCSTATUS_REASSOC ((UINT16)2) +#define HFA384x_ASSOCSTATUS_DISASSOC ((UINT16)3) +#define HFA384x_ASSOCSTATUS_ASSOCFAIL ((UINT16)4) +#define HFA384x_ASSOCSTATUS_AUTHFAIL ((UINT16)5) + +typedef struct hfa384x_AssocStatus +{ + UINT16 assocstatus; + UINT8 sta_addr[WLAN_ADDR_LEN]; + /* old_ap_addr is only valid if assocstatus == 2 */ + UINT8 old_ap_addr[WLAN_ADDR_LEN]; + UINT16 reason; + UINT16 reserved; +} __WLAN_ATTRIB_PACK__ hfa384x_AssocStatus_t; + +/*-- Unsolicited Frame, MAC Mgmt: AuthRequest (AP Only) --*/ + +typedef struct hfa384x_AuthRequest +{ + UINT8 sta_addr[WLAN_ADDR_LEN]; + UINT16 algorithm; +} __WLAN_ATTRIB_PACK__ hfa384x_AuthReq_t; + +/*-- Unsolicited Frame, MAC Mgmt: AssocRequest (AP Only) --*/ + +typedef struct hfa384x_AssocRequest +{ + UINT8 sta_addr[WLAN_ADDR_LEN]; + UINT16 type; + UINT8 wpa_data[80]; +} __WLAN_ATTRIB_PACK__ hfa384x_AssocReq_t; + + +#define HFA384x_ASSOCREQ_TYPE_ASSOC 0 +#define HFA384x_ASSOCREQ_TYPE_REASSOC 1 + +/*-- Unsolicited Frame, MAC Mgmt: MIC Failure (AP Only) --*/ + +typedef struct hfa384x_MicFailure +{ + UINT8 sender[WLAN_ADDR_LEN]; + UINT8 dest[WLAN_ADDR_LEN]; +} __WLAN_ATTRIB_PACK__ hfa384x_MicFailure_t; + +/*-- Unsolicited Frame, MAC Mgmt: PSUserCount (AP Only) --*/ + +typedef struct hfa384x_PSUserCount +{ + UINT16 usercnt; +} __WLAN_ATTRIB_PACK__ hfa384x_PSUserCount_t; + +typedef struct hfa384x_KeyIDChanged +{ + UINT8 sta_addr[WLAN_ADDR_LEN]; + UINT16 keyid; +} __WLAN_ATTRIB_PACK__ hfa384x_KeyIDChanged_t; + +/*-- Collection of all Inf frames ---------------*/ +typedef union hfa384x_infodata { + hfa384x_CommTallies16_t commtallies16; + hfa384x_CommTallies32_t commtallies32; + hfa384x_ScanResult_t scanresult; + hfa384x_ChInfoResult_t chinforesult; + hfa384x_HScanResult_t hscanresult; + hfa384x_LinkStatus_t linkstatus; + hfa384x_AssocStatus_t assocstatus; + hfa384x_AuthReq_t authreq; + hfa384x_PSUserCount_t psusercnt; + hfa384x_KeyIDChanged_t keyidchanged; +} __WLAN_ATTRIB_PACK__ hfa384x_infodata_t; + +typedef struct hfa384x_InfFrame +{ + UINT16 framelen; + UINT16 infotype; + hfa384x_infodata_t info; +} __WLAN_ATTRIB_PACK__ hfa384x_InfFrame_t; + +#if (WLAN_HOSTIF == WLAN_USB) +/*-------------------------------------------------------------------- +USB Packet structures and constants. +--------------------------------------------------------------------*/ + +/* Should be sent to the ctrlout endpoint */ +#define HFA384x_USB_ENBULKIN 6 + +/* Should be sent to the bulkout endpoint */ +#define HFA384x_USB_TXFRM 0 +#define HFA384x_USB_CMDREQ 1 +#define HFA384x_USB_WRIDREQ 2 +#define HFA384x_USB_RRIDREQ 3 +#define HFA384x_USB_WMEMREQ 4 +#define HFA384x_USB_RMEMREQ 5 + +/* Received from the bulkin endpoint */ +#define HFA384x_USB_ISFRM(a) (!((a) & 0x8000)) +#define HFA384x_USB_ISTXFRM(a) (((a) & 0x9000) == 0x1000) +#define HFA384x_USB_ISRXFRM(a) (!((a) & 0x9000)) +#define HFA384x_USB_INFOFRM 0x8000 +#define HFA384x_USB_CMDRESP 0x8001 +#define HFA384x_USB_WRIDRESP 0x8002 +#define HFA384x_USB_RRIDRESP 0x8003 +#define HFA384x_USB_WMEMRESP 0x8004 +#define HFA384x_USB_RMEMRESP 0x8005 +#define HFA384x_USB_BUFAVAIL 0x8006 +#define HFA384x_USB_ERROR 0x8007 + +/*------------------------------------*/ +/* Request (bulk OUT) packet contents */ + +typedef struct hfa384x_usb_txfrm { + hfa384x_tx_frame_t desc; + UINT8 data[WLAN_DATA_MAXLEN]; +} __WLAN_ATTRIB_PACK__ hfa384x_usb_txfrm_t; + +typedef struct hfa384x_usb_cmdreq { + UINT16 type; + UINT16 cmd; + UINT16 parm0; + UINT16 parm1; + UINT16 parm2; + UINT8 pad[54]; +} __WLAN_ATTRIB_PACK__ hfa384x_usb_cmdreq_t; + +typedef struct hfa384x_usb_wridreq { + UINT16 type; + UINT16 frmlen; + UINT16 rid; + UINT8 data[HFA384x_RIDDATA_MAXLEN]; +} __WLAN_ATTRIB_PACK__ hfa384x_usb_wridreq_t; + +typedef struct hfa384x_usb_rridreq { + UINT16 type; + UINT16 frmlen; + UINT16 rid; + UINT8 pad[58]; +} __WLAN_ATTRIB_PACK__ hfa384x_usb_rridreq_t; + +typedef struct hfa384x_usb_wmemreq { + UINT16 type; + UINT16 frmlen; + UINT16 offset; + UINT16 page; + UINT8 data[HFA384x_USB_RWMEM_MAXLEN]; +} __WLAN_ATTRIB_PACK__ hfa384x_usb_wmemreq_t; + +typedef struct hfa384x_usb_rmemreq { + UINT16 type; + UINT16 frmlen; + UINT16 offset; + UINT16 page; + UINT8 pad[56]; +} __WLAN_ATTRIB_PACK__ hfa384x_usb_rmemreq_t; + +/*------------------------------------*/ +/* Response (bulk IN) packet contents */ + +typedef struct hfa384x_usb_rxfrm { + hfa384x_rx_frame_t desc; + UINT8 data[WLAN_DATA_MAXLEN]; +} __WLAN_ATTRIB_PACK__ hfa384x_usb_rxfrm_t; + +typedef struct hfa384x_usb_infofrm { + UINT16 type; + hfa384x_InfFrame_t info; +} __WLAN_ATTRIB_PACK__ hfa384x_usb_infofrm_t; + +typedef struct hfa384x_usb_statusresp { + UINT16 type; + UINT16 status; + UINT16 resp0; + UINT16 resp1; + UINT16 resp2; +} __WLAN_ATTRIB_PACK__ hfa384x_usb_cmdresp_t; + +typedef hfa384x_usb_cmdresp_t hfa384x_usb_wridresp_t; + +typedef struct hfa384x_usb_rridresp { + UINT16 type; + UINT16 frmlen; + UINT16 rid; + UINT8 data[HFA384x_RIDDATA_MAXLEN]; +} __WLAN_ATTRIB_PACK__ hfa384x_usb_rridresp_t; + +typedef hfa384x_usb_cmdresp_t hfa384x_usb_wmemresp_t; + +typedef struct hfa384x_usb_rmemresp { + UINT16 type; + UINT16 frmlen; + UINT8 data[HFA384x_USB_RWMEM_MAXLEN]; +} __WLAN_ATTRIB_PACK__ hfa384x_usb_rmemresp_t; + +typedef struct hfa384x_usb_bufavail { + UINT16 type; + UINT16 frmlen; +} __WLAN_ATTRIB_PACK__ hfa384x_usb_bufavail_t; + +typedef struct hfa384x_usb_error { + UINT16 type; + UINT16 errortype; +} __WLAN_ATTRIB_PACK__ hfa384x_usb_error_t; + +/*----------------------------------------------------------*/ +/* Unions for packaging all the known packet types together */ + +typedef union hfa384x_usbout { + UINT16 type; + hfa384x_usb_txfrm_t txfrm; + hfa384x_usb_cmdreq_t cmdreq; + hfa384x_usb_wridreq_t wridreq; + hfa384x_usb_rridreq_t rridreq; + hfa384x_usb_wmemreq_t wmemreq; + hfa384x_usb_rmemreq_t rmemreq; +} __WLAN_ATTRIB_PACK__ hfa384x_usbout_t; + +typedef union hfa384x_usbin { + UINT16 type; + hfa384x_usb_rxfrm_t rxfrm; + hfa384x_usb_txfrm_t txfrm; + hfa384x_usb_infofrm_t infofrm; + hfa384x_usb_cmdresp_t cmdresp; + hfa384x_usb_wridresp_t wridresp; + hfa384x_usb_rridresp_t rridresp; + hfa384x_usb_wmemresp_t wmemresp; + hfa384x_usb_rmemresp_t rmemresp; + hfa384x_usb_bufavail_t bufavail; + hfa384x_usb_error_t usberror; + UINT8 boguspad[3000]; +} __WLAN_ATTRIB_PACK__ hfa384x_usbin_t; + +#endif /* WLAN_USB */ + +/*-------------------------------------------------------------------- +PD record structures. +--------------------------------------------------------------------*/ + +typedef struct hfa384x_pdr_pcb_partnum +{ + UINT8 num[8]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_pcb_partnum_t; + +typedef struct hfa384x_pdr_pcb_tracenum +{ + UINT8 num[8]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_pcb_tracenum_t; + +typedef struct hfa384x_pdr_nic_serial +{ + UINT8 num[12]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_nic_serial_t; + +typedef struct hfa384x_pdr_mkk_measurements +{ + double carrier_freq; + double occupied_band; + double power_density; + double tx_spur_f1; + double tx_spur_f2; + double tx_spur_f3; + double tx_spur_f4; + double tx_spur_l1; + double tx_spur_l2; + double tx_spur_l3; + double tx_spur_l4; + double rx_spur_f1; + double rx_spur_f2; + double rx_spur_l1; + double rx_spur_l2; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_mkk_measurements_t; + +typedef struct hfa384x_pdr_nic_ramsize +{ + UINT8 size[12]; /* units of KB */ +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_nic_ramsize_t; + +typedef struct hfa384x_pdr_mfisuprange +{ + UINT16 id; + UINT16 variant; + UINT16 bottom; + UINT16 top; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_mfisuprange_t; + +typedef struct hfa384x_pdr_cfisuprange +{ + UINT16 id; + UINT16 variant; + UINT16 bottom; + UINT16 top; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_cfisuprange_t; + +typedef struct hfa384x_pdr_nicid +{ + UINT16 id; + UINT16 variant; + UINT16 major; + UINT16 minor; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_nicid_t; + + +typedef struct hfa384x_pdr_refdac_measurements +{ + UINT16 value[0]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_refdac_measurements_t; + +typedef struct hfa384x_pdr_vgdac_measurements +{ + UINT16 value[0]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_vgdac_measurements_t; + +typedef struct hfa384x_pdr_level_comp_measurements +{ + UINT16 value[0]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_level_compc_measurements_t; + +typedef struct hfa384x_pdr_mac_address +{ + UINT8 addr[6]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_mac_address_t; + +typedef struct hfa384x_pdr_mkk_callname +{ + UINT8 callname[8]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_mkk_callname_t; + +typedef struct hfa384x_pdr_regdomain +{ + UINT16 numdomains; + UINT16 domain[5]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_regdomain_t; + +typedef struct hfa384x_pdr_allowed_channel +{ + UINT16 ch_bitmap; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_allowed_channel_t; + +typedef struct hfa384x_pdr_default_channel +{ + UINT16 channel; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_default_channel_t; + +typedef struct hfa384x_pdr_privacy_option +{ + UINT16 available; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_privacy_option_t; + +typedef struct hfa384x_pdr_temptype +{ + UINT16 type; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_temptype_t; + +typedef struct hfa384x_pdr_refdac_setup +{ + UINT16 ch_value[14]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_refdac_setup_t; + +typedef struct hfa384x_pdr_vgdac_setup +{ + UINT16 ch_value[14]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_vgdac_setup_t; + +typedef struct hfa384x_pdr_level_comp_setup +{ + UINT16 ch_value[14]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_level_comp_setup_t; + +typedef struct hfa384x_pdr_trimdac_setup +{ + UINT16 trimidac; + UINT16 trimqdac; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_trimdac_setup_t; + +typedef struct hfa384x_pdr_ifr_setting +{ + UINT16 value[3]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_ifr_setting_t; + +typedef struct hfa384x_pdr_rfr_setting +{ + UINT16 value[3]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_rfr_setting_t; + +typedef struct hfa384x_pdr_hfa3861_baseline +{ + UINT16 value[50]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_baseline_t; + +typedef struct hfa384x_pdr_hfa3861_shadow +{ + UINT32 value[32]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_shadow_t; + +typedef struct hfa384x_pdr_hfa3861_ifrf +{ + UINT32 value[20]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_ifrf_t; + +typedef struct hfa384x_pdr_hfa3861_chcalsp +{ + UINT16 value[14]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_chcalsp_t; + +typedef struct hfa384x_pdr_hfa3861_chcali +{ + UINT16 value[17]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_chcali_t; + +typedef struct hfa384x_pdr_hfa3861_nic_config +{ + UINT16 config_bitmap; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_nic_config_t; + +typedef struct hfa384x_pdr_hfo_delay +{ + UINT8 hfo_delay; +} __WLAN_ATTRIB_PACK__ hfa384x_hfo_delay_t; + +typedef struct hfa384x_pdr_hfa3861_manf_testsp +{ + UINT16 value[30]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_manf_testsp_t; + +typedef struct hfa384x_pdr_hfa3861_manf_testi +{ + UINT16 value[30]; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_manf_testi_t; + +typedef struct hfa384x_end_of_pda +{ + UINT16 crc; +} __WLAN_ATTRIB_PACK__ hfa384x_pdr_end_of_pda_t; + +typedef struct hfa384x_pdrec +{ + UINT16 len; /* in words */ + UINT16 code; + union pdr { + hfa384x_pdr_pcb_partnum_t pcb_partnum; + hfa384x_pdr_pcb_tracenum_t pcb_tracenum; + hfa384x_pdr_nic_serial_t nic_serial; + hfa384x_pdr_mkk_measurements_t mkk_measurements; + hfa384x_pdr_nic_ramsize_t nic_ramsize; + hfa384x_pdr_mfisuprange_t mfisuprange; + hfa384x_pdr_cfisuprange_t cfisuprange; + hfa384x_pdr_nicid_t nicid; + hfa384x_pdr_refdac_measurements_t refdac_measurements; + hfa384x_pdr_vgdac_measurements_t vgdac_measurements; + hfa384x_pdr_level_compc_measurements_t level_compc_measurements; + hfa384x_pdr_mac_address_t mac_address; + hfa384x_pdr_mkk_callname_t mkk_callname; + hfa384x_pdr_regdomain_t regdomain; + hfa384x_pdr_allowed_channel_t allowed_channel; + hfa384x_pdr_default_channel_t default_channel; + hfa384x_pdr_privacy_option_t privacy_option; + hfa384x_pdr_temptype_t temptype; + hfa384x_pdr_refdac_setup_t refdac_setup; + hfa384x_pdr_vgdac_setup_t vgdac_setup; + hfa384x_pdr_level_comp_setup_t level_comp_setup; + hfa384x_pdr_trimdac_setup_t trimdac_setup; + hfa384x_pdr_ifr_setting_t ifr_setting; + hfa384x_pdr_rfr_setting_t rfr_setting; + hfa384x_pdr_hfa3861_baseline_t hfa3861_baseline; + hfa384x_pdr_hfa3861_shadow_t hfa3861_shadow; + hfa384x_pdr_hfa3861_ifrf_t hfa3861_ifrf; + hfa384x_pdr_hfa3861_chcalsp_t hfa3861_chcalsp; + hfa384x_pdr_hfa3861_chcali_t hfa3861_chcali; + hfa384x_pdr_nic_config_t nic_config; + hfa384x_hfo_delay_t hfo_delay; + hfa384x_pdr_hfa3861_manf_testsp_t hfa3861_manf_testsp; + hfa384x_pdr_hfa3861_manf_testi_t hfa3861_manf_testi; + hfa384x_pdr_end_of_pda_t end_of_pda; + + } data; +} __WLAN_ATTRIB_PACK__ hfa384x_pdrec_t; + + +#ifdef __KERNEL__ +/*-------------------------------------------------------------------- +--- MAC state structure, argument to all functions -- +--- Also, a collection of support types -- +--------------------------------------------------------------------*/ +typedef struct hfa384x_statusresult +{ + UINT16 status; + UINT16 resp0; + UINT16 resp1; + UINT16 resp2; +} hfa384x_cmdresult_t; + +#if (WLAN_HOSTIF == WLAN_USB) + +/* USB Control Exchange (CTLX): + * A queue of the structure below is maintained for all of the + * Request/Response type USB packets supported by Prism2. + */ +/* The following hfa384x_* structures are arguments to + * the usercb() for the different CTLX types. + */ +typedef hfa384x_cmdresult_t hfa384x_wridresult_t; +typedef hfa384x_cmdresult_t hfa384x_wmemresult_t; + +typedef struct hfa384x_rridresult +{ + UINT16 rid; + const void *riddata; + UINT riddata_len; +} hfa384x_rridresult_t; + +enum ctlx_state { + CTLX_START = 0, /* Start state, not queued */ + + CTLX_COMPLETE, /* CTLX successfully completed */ + CTLX_REQ_FAILED, /* OUT URB completed w/ error */ + + CTLX_PENDING, /* Queued, data valid */ + CTLX_REQ_SUBMITTED, /* OUT URB submitted */ + CTLX_REQ_COMPLETE, /* OUT URB complete */ + CTLX_RESP_COMPLETE /* IN URB received */ +}; +typedef enum ctlx_state CTLX_STATE; + +struct hfa384x_usbctlx; +struct hfa384x; + +typedef void (*ctlx_cmdcb_t)( struct hfa384x*, const struct hfa384x_usbctlx* ); + +typedef void (*ctlx_usercb_t)( + struct hfa384x *hw, + void *ctlxresult, + void *usercb_data); + +typedef struct hfa384x_usbctlx +{ + struct list_head list; + + size_t outbufsize; + hfa384x_usbout_t outbuf; /* pkt buf for OUT */ + hfa384x_usbin_t inbuf; /* pkt buf for IN(a copy) */ + + CTLX_STATE state; /* Tracks running state */ + + struct completion done; + volatile int reapable; /* Food for the reaper task */ + + ctlx_cmdcb_t cmdcb; /* Async command callback */ + ctlx_usercb_t usercb; /* Async user callback, */ + void *usercb_data; /* at CTLX completion */ + + int variant; /* Identifies cmd variant */ +} hfa384x_usbctlx_t; + +typedef struct hfa384x_usbctlxq +{ + spinlock_t lock; + struct list_head pending; + struct list_head active; + struct list_head completing; + struct list_head reapable; +} hfa384x_usbctlxq_t; +#endif + +typedef struct hfa484x_metacmd +{ + UINT16 cmd; + + UINT16 parm0; + UINT16 parm1; + UINT16 parm2; + +#if 0 //XXX cmd irq stuff + UINT16 bulkid; /* what RID/FID to copy down. */ + int bulklen; /* how much to copy from BAP */ + char *bulkdata; /* And to where? */ +#endif + + hfa384x_cmdresult_t result; +} hfa384x_metacmd_t; + +#define MAX_PRISM2_GRP_ADDR 16 +#define MAX_GRP_ADDR 32 +#define WLAN_COMMENT_MAX 80 /* Max. length of user comment string. */ + +#define MM_SAT_PCF (BIT14) +#define MM_GCSD_PCF (BIT15) +#define MM_GCSD_PCF_EB (BIT14 | BIT15) + +#define WLAN_STATE_STOPPED 0 /* Network is not active. */ +#define WLAN_STATE_STARTED 1 /* Network has been started. */ + +#define WLAN_AUTH_MAX 60 /* Max. # of authenticated stations. */ +#define WLAN_ACCESS_MAX 60 /* Max. # of stations in an access list. */ +#define WLAN_ACCESS_NONE 0 /* No stations may be authenticated. */ +#define WLAN_ACCESS_ALL 1 /* All stations may be authenticated. */ +#define WLAN_ACCESS_ALLOW 2 /* Authenticate only "allowed" stations. */ +#define WLAN_ACCESS_DENY 3 /* Do not authenticate "denied" stations. */ + +/* XXX These are going away ASAP */ +typedef struct prism2sta_authlist +{ + UINT cnt; + UINT8 addr[WLAN_AUTH_MAX][WLAN_ADDR_LEN]; + UINT8 assoc[WLAN_AUTH_MAX]; +} prism2sta_authlist_t; + +typedef struct prism2sta_accesslist +{ + UINT modify; + UINT cnt; + UINT8 addr[WLAN_ACCESS_MAX][WLAN_ADDR_LEN]; + UINT cnt1; + UINT8 addr1[WLAN_ACCESS_MAX][WLAN_ADDR_LEN]; +} prism2sta_accesslist_t; + +typedef struct hfa384x +{ +#if (WLAN_HOSTIF != WLAN_USB) + /* Resource config */ + UINT32 iobase; + char __iomem *membase; + UINT32 irq; +#else + /* USB support data */ + struct usb_device *usb; + struct urb rx_urb; + struct sk_buff *rx_urb_skb; + struct urb tx_urb; + struct urb ctlx_urb; + hfa384x_usbout_t txbuff; + hfa384x_usbctlxq_t ctlxq; + struct timer_list reqtimer; + struct timer_list resptimer; + + struct timer_list throttle; + + struct tasklet_struct reaper_bh; + struct tasklet_struct completion_bh; + + struct work_struct usb_work; + + unsigned long usb_flags; +#define THROTTLE_RX 0 +#define THROTTLE_TX 1 +#define WORK_RX_HALT 2 +#define WORK_TX_HALT 3 +#define WORK_RX_RESUME 4 +#define WORK_TX_RESUME 5 + + unsigned short req_timer_done:1; + unsigned short resp_timer_done:1; + + int endp_in; + int endp_out; +#endif /* !USB */ + +#if (WLAN_HOSTIF == WLAN_PCMCIA) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) + struct pcmcia_device *pdev; +#else + dev_link_t *link; +#endif + dev_node_t node; +#endif + + int sniff_fcs; + int sniff_channel; + int sniff_truncate; + int sniffhdr; + + wait_queue_head_t cmdq; /* wait queue itself */ + + /* Controller state */ + UINT32 state; + UINT32 isap; + UINT8 port_enabled[HFA384x_NUMPORTS_MAX]; +#if (WLAN_HOSTIF != WLAN_USB) + UINT auxen; + UINT isram16; +#endif /* !USB */ + + /* Download support */ + UINT dlstate; + hfa384x_downloadbuffer_t bufinfo; + UINT16 dltimeout; + +#if (WLAN_HOSTIF != WLAN_USB) + spinlock_t cmdlock; + volatile int cmdflag; /* wait queue flag */ + hfa384x_metacmd_t *cmddata; /* for our async callback */ + + /* BAP support */ + spinlock_t baplock; + struct tasklet_struct bap_tasklet; + + /* MAC buffer ids */ + UINT16 txfid_head; + UINT16 txfid_tail; + UINT txfid_N; + UINT16 txfid_queue[HFA384x_DRVR_FIDSTACKLEN_MAX]; + UINT16 infofid; + struct semaphore infofid_sem; +#endif /* !USB */ + + int scanflag; /* to signal scan comlete */ + int join_ap; /* are we joined to a specific ap */ + int join_retries; /* number of join retries till we fail */ + hfa384x_JoinRequest_data_t joinreq; /* join request saved data */ + + wlandevice_t *wlandev; + /* Timer to allow for the deferred processing of linkstatus messages */ + struct work_struct link_bh; + + struct work_struct commsqual_bh; + hfa384x_commsquality_t qual; + struct timer_list commsqual_timer; + + UINT16 link_status; + UINT16 link_status_new; + struct sk_buff_head authq; + + /* And here we have stuff that used to be in priv */ + + /* State variables */ + UINT presniff_port_type; + UINT16 presniff_wepflags; + UINT32 dot11_desired_bss_type; + int ap; /* AP flag: 0 - Station, 1 - Access Point. */ + + int dbmadjust; + + /* Group Addresses - right now, there are up to a total + of MAX_GRP_ADDR group addresses */ + UINT8 dot11_grp_addr[MAX_GRP_ADDR][WLAN_ADDR_LEN]; + UINT dot11_grpcnt; + + /* Component Identities */ + hfa384x_compident_t ident_nic; + hfa384x_compident_t ident_pri_fw; + hfa384x_compident_t ident_sta_fw; + hfa384x_compident_t ident_ap_fw; + UINT16 mm_mods; + + /* Supplier compatibility ranges */ + hfa384x_caplevel_t cap_sup_mfi; + hfa384x_caplevel_t cap_sup_cfi; + hfa384x_caplevel_t cap_sup_pri; + hfa384x_caplevel_t cap_sup_sta; + hfa384x_caplevel_t cap_sup_ap; + + /* Actor compatibility ranges */ + hfa384x_caplevel_t cap_act_pri_cfi; /* pri f/w to controller interface */ + hfa384x_caplevel_t cap_act_sta_cfi; /* sta f/w to controller interface */ + hfa384x_caplevel_t cap_act_sta_mfi; /* sta f/w to modem interface */ + hfa384x_caplevel_t cap_act_ap_cfi; /* ap f/w to controller interface */ + hfa384x_caplevel_t cap_act_ap_mfi; /* ap f/w to modem interface */ + + UINT32 psusercount; /* Power save user count. */ + hfa384x_CommTallies32_t tallies; /* Communication tallies. */ + UINT8 comment[WLAN_COMMENT_MAX+1]; /* User comment */ + + /* Channel Info request results (AP only) */ + struct { + atomic_t done; + UINT8 count; + hfa384x_ChInfoResult_t results; + } channel_info; + + hfa384x_InfFrame_t *scanresults; + + + prism2sta_authlist_t authlist; /* Authenticated station list. */ + UINT accessmode; /* Access mode. */ + prism2sta_accesslist_t allow; /* Allowed station list. */ + prism2sta_accesslist_t deny; /* Denied station list. */ + +} hfa384x_t; + +/*=============================================================*/ +/*--- Function Declarations -----------------------------------*/ +/*=============================================================*/ +#if (WLAN_HOSTIF == WLAN_USB) +void +hfa384x_create( + hfa384x_t *hw, + struct usb_device *usb); +#else +void +hfa384x_create( + hfa384x_t *hw, + UINT irq, + UINT32 iobase, + UINT8 __iomem *membase); +#endif + +void hfa384x_destroy(hfa384x_t *hw); + +irqreturn_t +hfa384x_interrupt(int irq, void *dev_id PT_REGS); +int +hfa384x_corereset( hfa384x_t *hw, int holdtime, int settletime, int genesis); +int +hfa384x_drvr_chinforesults( hfa384x_t *hw); +int +hfa384x_drvr_commtallies( hfa384x_t *hw); +int +hfa384x_drvr_disable(hfa384x_t *hw, UINT16 macport); +int +hfa384x_drvr_enable(hfa384x_t *hw, UINT16 macport); +int +hfa384x_drvr_flashdl_enable(hfa384x_t *hw); +int +hfa384x_drvr_flashdl_disable(hfa384x_t *hw); +int +hfa384x_drvr_flashdl_write(hfa384x_t *hw, UINT32 daddr, void* buf, UINT32 len); +int +hfa384x_drvr_getconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len); +int +hfa384x_drvr_handover( hfa384x_t *hw, UINT8 *addr); +int +hfa384x_drvr_hostscanresults( hfa384x_t *hw); +int +hfa384x_drvr_low_level(hfa384x_t *hw, hfa384x_metacmd_t *cmd); +int +hfa384x_drvr_mmi_read(hfa384x_t *hw, UINT32 address, UINT32 *result); +int +hfa384x_drvr_mmi_write(hfa384x_t *hw, UINT32 address, UINT32 data); +int +hfa384x_drvr_ramdl_enable(hfa384x_t *hw, UINT32 exeaddr); +int +hfa384x_drvr_ramdl_disable(hfa384x_t *hw); +int +hfa384x_drvr_ramdl_write(hfa384x_t *hw, UINT32 daddr, void* buf, UINT32 len); +int +hfa384x_drvr_readpda(hfa384x_t *hw, void *buf, UINT len); +int +hfa384x_drvr_scanresults( hfa384x_t *hw); + +int +hfa384x_drvr_setconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len); + +static inline int +hfa384x_drvr_getconfig16(hfa384x_t *hw, UINT16 rid, void *val) +{ + int result = 0; + result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(UINT16)); + if ( result == 0 ) { + *((UINT16*)val) = hfa384x2host_16(*((UINT16*)val)); + } + return result; +} + +static inline int +hfa384x_drvr_getconfig32(hfa384x_t *hw, UINT16 rid, void *val) +{ + int result = 0; + + result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(UINT32)); + if ( result == 0 ) { + *((UINT32*)val) = hfa384x2host_32(*((UINT32*)val)); + } + + return result; +} + +static inline int +hfa384x_drvr_setconfig16(hfa384x_t *hw, UINT16 rid, UINT16 val) +{ + UINT16 value = host2hfa384x_16(val); + return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(value)); +} + +static inline int +hfa384x_drvr_setconfig32(hfa384x_t *hw, UINT16 rid, UINT32 val) +{ + UINT32 value = host2hfa384x_32(val); + return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(value)); +} + +#if (WLAN_HOSTIF == WLAN_USB) +int +hfa384x_drvr_getconfig_async(hfa384x_t *hw, + UINT16 rid, + ctlx_usercb_t usercb, + void *usercb_data); + +int +hfa384x_drvr_setconfig_async(hfa384x_t *hw, + UINT16 rid, + void *buf, + UINT16 len, + ctlx_usercb_t usercb, + void *usercb_data); +#else +static inline int +hfa384x_drvr_setconfig_async(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len, + void *ptr1, void *ptr2) +{ + (void)ptr1; + (void)ptr2; + return hfa384x_drvr_setconfig(hw, rid, buf, len); +} +#endif + +static inline int +hfa384x_drvr_setconfig16_async(hfa384x_t *hw, UINT16 rid, UINT16 val) +{ + UINT16 value = host2hfa384x_16(val); + return hfa384x_drvr_setconfig_async(hw, rid, &value, sizeof(value), + NULL , NULL); +} + +static inline int +hfa384x_drvr_setconfig32_async(hfa384x_t *hw, UINT16 rid, UINT32 val) +{ + UINT32 value = host2hfa384x_32(val); + return hfa384x_drvr_setconfig_async(hw, rid, &value, sizeof(value), + NULL , NULL); +} + + +int +hfa384x_drvr_start(hfa384x_t *hw); +int +hfa384x_drvr_stop(hfa384x_t *hw); +int +hfa384x_drvr_txframe(hfa384x_t *hw, struct sk_buff *skb, p80211_hdr_t *p80211_hdr, p80211_metawep_t *p80211_wep); +void +hfa384x_tx_timeout(wlandevice_t *wlandev); + +int +hfa384x_cmd_initialize(hfa384x_t *hw); +int +hfa384x_cmd_enable(hfa384x_t *hw, UINT16 macport); +int +hfa384x_cmd_disable(hfa384x_t *hw, UINT16 macport); +int +hfa384x_cmd_diagnose(hfa384x_t *hw); +int +hfa384x_cmd_allocate(hfa384x_t *hw, UINT16 len); +int +hfa384x_cmd_transmit(hfa384x_t *hw, UINT16 reclaim, UINT16 qos, UINT16 fid); +int +hfa384x_cmd_clearpersist(hfa384x_t *hw, UINT16 fid); +int +hfa384x_cmd_notify(hfa384x_t *hw, UINT16 reclaim, UINT16 fid, void *buf, UINT16 len); +int +hfa384x_cmd_inquire(hfa384x_t *hw, UINT16 fid); +int +hfa384x_cmd_access(hfa384x_t *hw, UINT16 write, UINT16 rid, void *buf, UINT16 len); +int +hfa384x_cmd_monitor(hfa384x_t *hw, UINT16 enable); +int +hfa384x_cmd_download( + hfa384x_t *hw, + UINT16 mode, + UINT16 lowaddr, + UINT16 highaddr, + UINT16 codelen); +int +hfa384x_cmd_aux_enable(hfa384x_t *hw, int force); +int +hfa384x_cmd_aux_disable(hfa384x_t *hw); +int +hfa384x_copy_from_bap( + hfa384x_t *hw, + UINT16 bap, + UINT16 id, + UINT16 offset, + void *buf, + UINT len); +int +hfa384x_copy_to_bap( + hfa384x_t *hw, + UINT16 bap, + UINT16 id, + UINT16 offset, + void *buf, + UINT len); +void +hfa384x_copy_from_aux( + hfa384x_t *hw, + UINT32 cardaddr, + UINT32 auxctl, + void *buf, + UINT len); +void +hfa384x_copy_to_aux( + hfa384x_t *hw, + UINT32 cardaddr, + UINT32 auxctl, + void *buf, + UINT len); + +#if (WLAN_HOSTIF != WLAN_USB) + +/* + HFA384x is a LITTLE ENDIAN part. + + the get/setreg functions implicitly byte-swap the data to LE. + the _noswap variants do not perform a byte-swap on the data. +*/ + +static inline UINT16 +__hfa384x_getreg(hfa384x_t *hw, UINT reg); + +static inline void +__hfa384x_setreg(hfa384x_t *hw, UINT16 val, UINT reg); + +static inline UINT16 +__hfa384x_getreg_noswap(hfa384x_t *hw, UINT reg); + +static inline void +__hfa384x_setreg_noswap(hfa384x_t *hw, UINT16 val, UINT reg); + +#ifdef REVERSE_ENDIAN +#define hfa384x_getreg __hfa384x_getreg_noswap +#define hfa384x_setreg __hfa384x_setreg_noswap +#define hfa384x_getreg_noswap __hfa384x_getreg +#define hfa384x_setreg_noswap __hfa384x_setreg +#else +#define hfa384x_getreg __hfa384x_getreg +#define hfa384x_setreg __hfa384x_setreg +#define hfa384x_getreg_noswap __hfa384x_getreg_noswap +#define hfa384x_setreg_noswap __hfa384x_setreg_noswap +#endif + +/*---------------------------------------------------------------- +* hfa384x_getreg +* +* Retrieve the value of one of the MAC registers. Done here +* because different PRISM2 MAC parts use different buses and such. +* NOTE: This function returns the value in HOST ORDER!!!!!! +* +* Arguments: +* hw MAC part structure +* reg Register identifier (offset for I/O based i/f) +* +* Returns: +* Value from the register in HOST ORDER!!!! +----------------------------------------------------------------*/ +static inline UINT16 +__hfa384x_getreg(hfa384x_t *hw, UINT reg) +{ +/* printk(KERN_DEBUG "Reading from 0x%0x\n", hw->membase + reg); */ +#if ((WLAN_HOSTIF == WLAN_PCMCIA) || (WLAN_HOSTIF == WLAN_PLX)) + return wlan_inw_le16_to_cpu(hw->iobase+reg); +#elif (WLAN_HOSTIF == WLAN_PCI) + return __le16_to_cpu(readw(hw->membase + reg)); +#endif +} + +/*---------------------------------------------------------------- +* hfa384x_setreg +* +* Set the value of one of the MAC registers. Done here +* because different PRISM2 MAC parts use different buses and such. +* NOTE: This function assumes the value is in HOST ORDER!!!!!! +* +* Arguments: +* hw MAC part structure +* val Value, in HOST ORDER!!, to put in the register +* reg Register identifier (offset for I/O based i/f) +* +* Returns: +* Nothing +----------------------------------------------------------------*/ +static inline void +__hfa384x_setreg(hfa384x_t *hw, UINT16 val, UINT reg) +{ +#if ((WLAN_HOSTIF == WLAN_PCMCIA) || (WLAN_HOSTIF == WLAN_PLX)) + wlan_outw_cpu_to_le16( val, hw->iobase + reg); + return; +#elif (WLAN_HOSTIF == WLAN_PCI) + writew(__cpu_to_le16(val), hw->membase + reg); + return; +#endif +} + + +/*---------------------------------------------------------------- +* hfa384x_getreg_noswap +* +* Retrieve the value of one of the MAC registers. Done here +* because different PRISM2 MAC parts use different buses and such. +* +* Arguments: +* hw MAC part structure +* reg Register identifier (offset for I/O based i/f) +* +* Returns: +* Value from the register. +----------------------------------------------------------------*/ +static inline UINT16 +__hfa384x_getreg_noswap(hfa384x_t *hw, UINT reg) +{ +#if ((WLAN_HOSTIF == WLAN_PCMCIA) || (WLAN_HOSTIF == WLAN_PLX)) + return wlan_inw(hw->iobase+reg); +#elif (WLAN_HOSTIF == WLAN_PCI) + return readw(hw->membase + reg); +#endif +} + + +/*---------------------------------------------------------------- +* hfa384x_setreg_noswap +* +* Set the value of one of the MAC registers. Done here +* because different PRISM2 MAC parts use different buses and such. +* +* Arguments: +* hw MAC part structure +* val Value to put in the register +* reg Register identifier (offset for I/O based i/f) +* +* Returns: +* Nothing +----------------------------------------------------------------*/ +static inline void +__hfa384x_setreg_noswap(hfa384x_t *hw, UINT16 val, UINT reg) +{ +#if ((WLAN_HOSTIF == WLAN_PCMCIA) || (WLAN_HOSTIF == WLAN_PLX)) + wlan_outw( val, hw->iobase + reg); + return; +#elif (WLAN_HOSTIF == WLAN_PCI) + writew(val, hw->membase + reg); + return; +#endif +} + + +static inline void hfa384x_events_all(hfa384x_t *hw) +{ + hfa384x_setreg(hw, + HFA384x_INT_NORMAL +#ifdef CMD_IRQ + | HFA384x_INTEN_CMD_SET(1) +#endif + , + HFA384x_INTEN); + +} + +static inline void hfa384x_events_nobap(hfa384x_t *hw) +{ + hfa384x_setreg(hw, + (HFA384x_INT_NORMAL & ~HFA384x_INT_BAP_OP) +#ifdef CMD_IRQ + | HFA384x_INTEN_CMD_SET(1) +#endif + , + HFA384x_INTEN); + +} + +#endif /* WLAN_HOSTIF != WLAN_USB */ +#endif /* __KERNEL__ */ + +#endif /* _HFA384x_H */ --- linux-2.6.27.orig/ubuntu/misc/wireless/prism2_usb/prism2/prism2mgmt.h +++ linux-2.6.27/ubuntu/misc/wireless/prism2_usb/prism2/prism2mgmt.h @@ -0,0 +1,182 @@ +/* src/prism2/include/prism2/prism2mgmt.h +* +* Declares the mgmt command handler functions +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +* +* This file contains the constants and data structures for interaction +* with the hfa384x Wireless LAN (WLAN) Media Access Contoller (MAC). +* The hfa384x is a portion of the Harris PRISM(tm) WLAN chipset. +* +* [Implementation and usage notes] +* +* [References] +* CW10 Programmer's Manual v1.5 +* IEEE 802.11 D10.0 +* +* -------------------------------------------------------------------- +*/ + +#ifndef _PRISM2MGMT_H +#define _PRISM2MGMT_H + + +/*=============================================================*/ +/*------ Constants --------------------------------------------*/ + +/*=============================================================*/ +/*------ Macros -----------------------------------------------*/ + +/*=============================================================*/ +/*------ Types and their related constants --------------------*/ + +/*=============================================================*/ +/*------ Static variable externs ------------------------------*/ + +#if (WLAN_HOSTIF != WLAN_USB) +extern int prism2_bap_timeout; +extern int prism2_irq_evread_max; +#endif +extern int prism2_debug; +extern int prism2_reset_holdtime; +extern int prism2_reset_settletime; +/*=============================================================*/ +/*--- Function Declarations -----------------------------------*/ +/*=============================================================*/ + +UINT32 +prism2sta_ifstate(wlandevice_t *wlandev, UINT32 ifstate); + +void +prism2sta_ev_dtim(wlandevice_t *wlandev); +void +prism2sta_ev_infdrop(wlandevice_t *wlandev); +void +prism2sta_ev_info(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); +void +prism2sta_ev_txexc(wlandevice_t *wlandev, UINT16 status); +void +prism2sta_ev_tx(wlandevice_t *wlandev, UINT16 status); +void +prism2sta_ev_rx(wlandevice_t *wlandev, struct sk_buff *skb); +void +prism2sta_ev_alloc(wlandevice_t *wlandev); + + +int prism2mgmt_mibset_mibget(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_powermgmt(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_scan(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_join(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_p2_join(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_authenticate(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_deauthenticate(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_associate(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_reassociate(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_disassociate(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_reset(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_start(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_readpda(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_readcis(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_auxport_state(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_auxport_read(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_auxport_write(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_low_level(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_test_command(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_mmi_read(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_mmi_write(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_ramdl_state(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_ramdl_write(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_flashdl_state(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_flashdl_write(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_mm_state(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_dump_state(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_enable(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_channel_info(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_channel_info_results(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_autojoin(wlandevice_t *wlandev, void *msgp); + +/*--------------------------------------------------------------- +* conversion functions going between wlan message data types and +* Prism2 data types +---------------------------------------------------------------*/ +/* byte area conversion functions*/ +void prism2mgmt_pstr2bytearea(UINT8 *bytearea, p80211pstrd_t *pstr); +void prism2mgmt_bytearea2pstr(UINT8 *bytearea, p80211pstrd_t *pstr, int len); + +/* byte string conversion functions*/ +void prism2mgmt_pstr2bytestr(hfa384x_bytestr_t *bytestr, p80211pstrd_t *pstr); +void prism2mgmt_bytestr2pstr(hfa384x_bytestr_t *bytestr, p80211pstrd_t *pstr); + +/* integer conversion functions */ +void prism2mgmt_prism2int2p80211int(UINT16 *prism2int, UINT32 *wlanint); +void prism2mgmt_p80211int2prism2int(UINT16 *prism2int, UINT32 *wlanint); + +/* enumerated integer conversion functions */ +void prism2mgmt_prism2enum2p80211enum(UINT16 *prism2enum, UINT32 *wlanenum, UINT16 rid); +void prism2mgmt_p80211enum2prism2enum(UINT16 *prism2enum, UINT32 *wlanenum, UINT16 rid); + +/* functions to convert a bit area to/from an Operational Rate Set */ +void prism2mgmt_get_oprateset(UINT16 *rate, p80211pstrd_t *pstr); +void prism2mgmt_set_oprateset(UINT16 *rate, p80211pstrd_t *pstr); + +/* functions to convert Group Addresses */ +void prism2mgmt_get_grpaddr(UINT32 did, + p80211pstrd_t *pstr, hfa384x_t *priv ); +int prism2mgmt_set_grpaddr(UINT32 did, + UINT8 *prism2buf, p80211pstrd_t *pstr, hfa384x_t *priv ); +int prism2mgmt_get_grpaddr_index( UINT32 did ); + +void prism2sta_processing_defer(struct work_struct *data); + +void prism2sta_commsqual_defer(struct work_struct *data); +void prism2sta_commsqual_timer(unsigned long data); + +/*=============================================================*/ +/*--- Inline Function Definitions (if supported) --------------*/ +/*=============================================================*/ + + + +#endif --- linux-2.6.27.orig/ubuntu/misc/wireless/acx/wlan_hdr.h +++ linux-2.6.27/ubuntu/misc/wireless/acx/wlan_hdr.h @@ -0,0 +1,497 @@ +/*********************************************************************** +** Copyright (C) 2003 ACX100 Open Source Project +** +** The contents of this file are subject to the Mozilla Public +** License Version 1.1 (the "License"); you may not use this file +** except in compliance with the License. You may obtain a copy of +** the License at http://www.mozilla.org/MPL/ +** +** Software distributed under the License is distributed on an "AS +** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +** implied. See the License for the specific language governing +** rights and limitations under the License. +** +** Alternatively, the contents of this file may be used under the +** terms of the GNU Public License version 2 (the "GPL"), in which +** case the provisions of the GPL are applicable instead of the +** above. If you wish to allow the use of your version of this file +** only under the terms of the GPL and not to allow others to use +** your version of this file under the MPL, indicate your decision +** by deleting the provisions above and replace them with the notice +** and other provisions required by the GPL. If you do not delete +** the provisions above, a recipient may use your version of this +** file under either the MPL or the GPL. +** --------------------------------------------------------------------- +** Inquiries regarding the ACX100 Open Source Project can be +** made directly to: +** +** acx100-users@lists.sf.net +** http://acx100.sf.net +** --------------------------------------------------------------------- +*/ + +/*********************************************************************** +** This code is based on elements which are +** Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +** info@linux-wlan.com +** http://www.linux-wlan.com +*/ + +/* mini-doc + +Here are all 11b/11g/11a rates and modulations: + + 11b 11g 11a + --- --- --- + 1 |B |B | + 2 |Q |Q | + 5.5|Cp |C p| + 6 | |Od |O + 9 | |od |o +11 |Cp |C p| +12 | |Od |O +18 | |od |o +22 | | p| +24 | |Od |O +33 | | p| +36 | |od |o +48 | |od |o +54 | |od |o + +Mandatory: + B - DBPSK (Differential Binary Phase Shift Keying) + Q - DQPSK (Differential Quaternary Phase Shift Keying) + C - CCK (Complementary Code Keying, a form of DSSS + (Direct Sequence Spread Spectrum) modulation) + O - OFDM (Orthogonal Frequency Division Multiplexing) +Optional: + o - OFDM + d - CCK-OFDM (also known as DSSS-OFDM) + p - PBCC (Packet Binary Convolutional Coding) + +The term CCK-OFDM may be used interchangeably with DSSS-OFDM +(the IEEE 802.11g-2003 standard uses the latter terminology). +In the CCK-OFDM, the PLCP header of the frame uses the CCK form of DSSS, +while the PLCP payload (the MAC frame) is modulated using OFDM. + +Basically, you must use CCK-OFDM if you have mixed 11b/11g environment, +or else (pure OFDM) 11b equipment may not realize that AP +is sending a packet and start sending its own one. +Sadly, looks like acx111 does not support CCK-OFDM, only pure OFDM. + +Re PBCC: avoid using it. It makes sense only if you have +TI "11b+" hardware. You _must_ use PBCC in order to reach 22Mbps on it. + +Preambles: + +Long preamble (at 1Mbit rate, takes 144 us): + 16 bytes ones + 2 bytes 0xF3A0 (lsb sent first) +PLCP header follows (at 1Mbit also): + 1 byte Signal: speed, in 0.1Mbit units, except for: + 33Mbit: 33 (instead of 330 - doesn't fit in octet) + all CCK-OFDM rates: 30 + 1 byte Service + 0,1,4: reserved + 2: 1=locked clock + 3: 1=PBCC + 5: Length Extension (PBCC 22,33Mbit (11g only)) <- + 6: Length Extension (PBCC 22,33Mbit (11g only)) <- BLACK MAGIC HERE + 7: Length Extension <- + 2 bytes Length (time needed to tx this frame) + a) 5.5 Mbit/s CCK + Length = octets*8/5.5, rounded up to integer + b) 11 Mbit/s CCK + Length = octets*8/11, rounded up to integer + Service bit 7: + 0 = rounding took less than 8/11 + 1 = rounding took more than or equal to 8/11 + c) 5.5 Mbit/s PBCC + Length = (octets+1)*8/5.5, rounded up to integer + d) 11 Mbit/s PBCC + Length = (octets+1)*8/11, rounded up to integer + Service bit 7: + 0 = rounding took less than 8/11 + 1 = rounding took more than or equal to 8/11 + e) 22 Mbit/s PBCC + Length = (octets+1)*8/22, rounded up to integer + Service bits 6,7: + 00 = rounding took less than 8/22ths + 01 = rounding took 8/22...15/22ths + 10 = rounding took 16/22ths or more. + f) 33 Mbit/s PBCC + Length = (octets+1)*8/33, rounded up to integer + Service bits 5,6,7: + 000 rounding took less than 8/33 + 001 rounding took 8/33...15/33 + 010 rounding took 16/33...23/33 + 011 rounding took 24/33...31/33 + 100 rounding took 32/33 or more + 2 bytes CRC + +PSDU follows (up to 2346 bytes at selected rate) + +While Signal value alone is not enough to determine rate and modulation, +Signal+Service is always sufficient. + +Short preamble (at 1Mbit rate, takes 72 us): + 7 bytes zeroes + 2 bytes 0x05CF (lsb sent first) +PLCP header follows *at 2Mbit/s*. Format is the same as in long preamble. +PSDU follows (up to 2346 bytes at selected rate) + +OFDM preamble is completely different, uses OFDM +modulation from the start and thus easily identifiable. +Not shown here. +*/ + + +/*********************************************************************** +** Constants +*/ + +#define WLAN_HDR_A3_LEN 24 +#define WLAN_HDR_A4_LEN 30 +/* IV structure: +** 3 bytes: Initialization Vector (24 bits) +** 1 byte: 0..5: padding, must be 0; 6..7: key selector (0-3) +*/ +#define WLAN_WEP_IV_LEN 4 +/* 802.11 says 2312 but looks like 2312 is a max size of _WEPed data_ */ +#define WLAN_DATA_MAXLEN 2304 +#define WLAN_WEP_ICV_LEN 4 +#define WLAN_FCS_LEN 4 +#define WLAN_A3FR_MAXLEN (WLAN_HDR_A3_LEN + WLAN_DATA_MAXLEN) +#define WLAN_A4FR_MAXLEN (WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN) +#define WLAN_A3FR_MAXLEN_FCS (WLAN_HDR_A3_LEN + WLAN_DATA_MAXLEN + 4) +#define WLAN_A4FR_MAXLEN_FCS (WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + 4) +#define WLAN_A3FR_MAXLEN_WEP (WLAN_A3FR_MAXLEN + 8) +#define WLAN_A4FR_MAXLEN_WEP (WLAN_A4FR_MAXLEN + 8) +#define WLAN_A3FR_MAXLEN_WEP_FCS (WLAN_A3FR_MAXLEN_FCS + 8) +#define WLAN_A4FR_MAXLEN_WEP_FCS (WLAN_A4FR_MAXLEN_FCS + 8) + +#define WLAN_BSS_TS_LEN 8 +#define WLAN_SSID_MAXLEN 32 +#define WLAN_BEACON_FR_MAXLEN (WLAN_HDR_A3_LEN + 334) +#define WLAN_ATIM_FR_MAXLEN (WLAN_HDR_A3_LEN + 0) +#define WLAN_DISASSOC_FR_MAXLEN (WLAN_HDR_A3_LEN + 2) +#define WLAN_ASSOCREQ_FR_MAXLEN (WLAN_HDR_A3_LEN + 48) +#define WLAN_ASSOCRESP_FR_MAXLEN (WLAN_HDR_A3_LEN + 16) +#define WLAN_REASSOCREQ_FR_MAXLEN (WLAN_HDR_A3_LEN + 54) +#define WLAN_REASSOCRESP_FR_MAXLEN (WLAN_HDR_A3_LEN + 16) +#define WLAN_PROBEREQ_FR_MAXLEN (WLAN_HDR_A3_LEN + 44) +#define WLAN_PROBERESP_FR_MAXLEN (WLAN_HDR_A3_LEN + 78) +#define WLAN_AUTHEN_FR_MAXLEN (WLAN_HDR_A3_LEN + 261) +#define WLAN_DEAUTHEN_FR_MAXLEN (WLAN_HDR_A3_LEN + 2) +#define WLAN_CHALLENGE_IE_LEN 130 +#define WLAN_CHALLENGE_LEN 128 +#define WLAN_WEP_MAXKEYLEN 13 +#define WLAN_WEP_NKEYS 4 + +/*--- Frame Control Field -------------------------------------*/ +/* Frame Types */ +#define WLAN_FTYPE_MGMT 0x00 +#define WLAN_FTYPE_CTL 0x01 +#define WLAN_FTYPE_DATA 0x02 + +/* Frame subtypes */ +/* Management */ +#define WLAN_FSTYPE_ASSOCREQ 0x00 +#define WLAN_FSTYPE_ASSOCRESP 0x01 +#define WLAN_FSTYPE_REASSOCREQ 0x02 +#define WLAN_FSTYPE_REASSOCRESP 0x03 +#define WLAN_FSTYPE_PROBEREQ 0x04 +#define WLAN_FSTYPE_PROBERESP 0x05 +#define WLAN_FSTYPE_BEACON 0x08 +#define WLAN_FSTYPE_ATIM 0x09 +#define WLAN_FSTYPE_DISASSOC 0x0a +#define WLAN_FSTYPE_AUTHEN 0x0b +#define WLAN_FSTYPE_DEAUTHEN 0x0c + +/* Control */ +#define WLAN_FSTYPE_PSPOLL 0x0a +#define WLAN_FSTYPE_RTS 0x0b +#define WLAN_FSTYPE_CTS 0x0c +#define WLAN_FSTYPE_ACK 0x0d +#define WLAN_FSTYPE_CFEND 0x0e +#define WLAN_FSTYPE_CFENDCFACK 0x0f + +/* Data */ +#define WLAN_FSTYPE_DATAONLY 0x00 +#define WLAN_FSTYPE_DATA_CFACK 0x01 +#define WLAN_FSTYPE_DATA_CFPOLL 0x02 +#define WLAN_FSTYPE_DATA_CFACK_CFPOLL 0x03 +#define WLAN_FSTYPE_NULL 0x04 +#define WLAN_FSTYPE_CFACK 0x05 +#define WLAN_FSTYPE_CFPOLL 0x06 +#define WLAN_FSTYPE_CFACK_CFPOLL 0x07 + +/*--- FC Constants v. 2.0 ------------------------------------*/ +/* Each constant is defined twice: WF_CONST is in host */ +/* byteorder, WF_CONSTi is in ieee byteorder. */ +/* Usage: */ +/* printf("the frame subtype is %X", WF_FC_FTYPEi & rx.fc); */ +/* tx.fc = WF_FTYPE_CTLi | WF_FSTYPE_RTSi; */ +/*------------------------------------------------------------*/ + +enum { +/*--- Frame Control Field -------------------------------------*/ +/* Protocol version: always 0 for current 802.11 standards */ +IEEE16(WF_FC_PVER, 0x0003) +IEEE16(WF_FC_FTYPE, 0x000c) +IEEE16(WF_FC_FSTYPE, 0x00f0) +IEEE16(WF_FC_TODS, 0x0100) +IEEE16(WF_FC_FROMDS, 0x0200) +IEEE16(WF_FC_FROMTODS, 0x0300) +IEEE16(WF_FC_MOREFRAG, 0x0400) +IEEE16(WF_FC_RETRY, 0x0800) +/* Indicates PS mode in which STA will be after successful completion +** of current frame exchange sequence. Always 0 for AP frames */ +IEEE16(WF_FC_PWRMGT, 0x1000) +/* What MoreData=1 means: +** From AP to STA in PS mode: don't sleep yet, I have more frames for you +** From Contention-Free (CF) Pollable STA in response to a CF-Poll: +** STA has buffered frames for transmission in response to next CF-Poll +** Bcast/mcast frames transmitted from AP: +** when additional bcast/mcast frames remain to be transmitted by AP +** during this beacon interval +** In all other cases MoreData=0 */ +IEEE16(WF_FC_MOREDATA, 0x2000) +IEEE16(WF_FC_ISWEP, 0x4000) +IEEE16(WF_FC_ORDER, 0x8000) + +/* Frame Types */ +IEEE16(WF_FTYPE_MGMT, 0x00) +IEEE16(WF_FTYPE_CTL, 0x04) +IEEE16(WF_FTYPE_DATA, 0x08) + +/* Frame subtypes */ +/* Management */ +IEEE16(WF_FSTYPE_ASSOCREQ, 0x00) +IEEE16(WF_FSTYPE_ASSOCRESP, 0x10) +IEEE16(WF_FSTYPE_REASSOCREQ, 0x20) +IEEE16(WF_FSTYPE_REASSOCRESP, 0x30) +IEEE16(WF_FSTYPE_PROBEREQ, 0x40) +IEEE16(WF_FSTYPE_PROBERESP, 0x50) +IEEE16(WF_FSTYPE_BEACON, 0x80) +IEEE16(WF_FSTYPE_ATIM, 0x90) +IEEE16(WF_FSTYPE_DISASSOC, 0xa0) +IEEE16(WF_FSTYPE_AUTHEN, 0xb0) +IEEE16(WF_FSTYPE_DEAUTHEN, 0xc0) + +/* Control */ +IEEE16(WF_FSTYPE_PSPOLL, 0xa0) +IEEE16(WF_FSTYPE_RTS, 0xb0) +IEEE16(WF_FSTYPE_CTS, 0xc0) +IEEE16(WF_FSTYPE_ACK, 0xd0) +IEEE16(WF_FSTYPE_CFEND, 0xe0) +IEEE16(WF_FSTYPE_CFENDCFACK, 0xf0) + +/* Data */ +IEEE16(WF_FSTYPE_DATAONLY, 0x00) +IEEE16(WF_FSTYPE_DATA_CFACK, 0x10) +IEEE16(WF_FSTYPE_DATA_CFPOLL, 0x20) +IEEE16(WF_FSTYPE_DATA_CFACK_CFPOLL, 0x30) +IEEE16(WF_FSTYPE_NULL, 0x40) +IEEE16(WF_FSTYPE_CFACK, 0x50) +IEEE16(WF_FSTYPE_CFPOLL, 0x60) +IEEE16(WF_FSTYPE_CFACK_CFPOLL, 0x70) +}; + + +/*********************************************************************** +** Macros +*/ + +/*--- Duration Macros ----------------------------------------*/ +/* Macros to get/set the bitfields of the Duration Field */ +/* - the duration value is only valid when bit15 is zero */ +/* - the firmware handles these values, so I'm not going */ +/* to use these macros right now. */ +/*------------------------------------------------------------*/ + +/*--- Sequence Control Macros -------------------------------*/ +/* Macros to get/set the bitfields of the Sequence Control */ +/* Field. */ +/*------------------------------------------------------------*/ +#define WLAN_GET_SEQ_FRGNUM(n) ((u16)(n) & 0x000f) +#define WLAN_GET_SEQ_SEQNUM(n) (((u16)(n) & 0xfff0) >> 4) + +/*--- Data ptr macro -----------------------------------------*/ +/* Creates a u8* to the data portion of a frame */ +/* Assumes you're passing in a ptr to the beginning of the hdr*/ +/*------------------------------------------------------------*/ +#define WLAN_HDR_A3_DATAP(p) (((u8*)(p)) + WLAN_HDR_A3_LEN) +#define WLAN_HDR_A4_DATAP(p) (((u8*)(p)) + WLAN_HDR_A4_LEN) + + +/*********************************************************************** +** Types +*/ + +/* 802.11 header type +** +** Note the following: +** a1 *always* is receiver's mac or bcast/mcast +** a2 *always* is transmitter's mac, if a2 exists +** seq: [0:3] frag#, [4:15] seq# - used for dup detection +** (dups from retries have same seq#) */ +typedef struct wlan_hdr { + u16 fc; + u16 dur; + u8 a1[ETH_ALEN]; + u8 a2[ETH_ALEN]; + u8 a3[ETH_ALEN]; + u16 seq; + u8 a4[ETH_ALEN]; +} WLAN_PACKED wlan_hdr_t; + +/* Separate structs for use if frame type is known */ +typedef struct wlan_hdr_a3 { + u16 fc; + u16 dur; + u8 a1[ETH_ALEN]; + u8 a2[ETH_ALEN]; + u8 a3[ETH_ALEN]; + u16 seq; +} WLAN_PACKED wlan_hdr_a3_t; + +typedef struct wlan_hdr_mgmt { + u16 fc; + u16 dur; + u8 da[ETH_ALEN]; + u8 sa[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u16 seq; +} WLAN_PACKED wlan_hdr_mgmt_t; + +#ifdef NOT_NEEDED_YET +typedef struct { /* ad-hoc peer->peer (to/from DS = 0/0) */ + u16 fc; + u16 dur; + u8 da[ETH_ALEN]; + u8 sa[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u16 seq; +} WLAN_PACKED ibss; +typedef struct { /* ap->sta (to/from DS = 0/1) */ + u16 fc; + u16 dur; + u8 da[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u8 sa[ETH_ALEN]; + u16 seq; +} WLAN_PACKED fromap; +typedef struct { /* sta->ap (to/from DS = 1/0) */ + u16 fc; + u16 dur; + u8 bssid[ETH_ALEN]; + u8 sa[ETH_ALEN]; + u8 da[ETH_ALEN]; + u16 seq; +} WLAN_PACKED toap; +typedef struct { /* wds->wds (to/from DS = 1/1), the only 4addr pkt */ + u16 fc; + u16 dur; + u8 ra[ETH_ALEN]; + u8 ta[ETH_ALEN]; + u8 da[ETH_ALEN]; + u16 seq; + u8 sa[ETH_ALEN]; +} WLAN_PACKED wds; +typedef struct { /* all management packets */ + u16 fc; + u16 dur; + u8 da[ETH_ALEN]; + u8 sa[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u16 seq; +} WLAN_PACKED mgmt; +typedef struct { /* has no body, just a FCS */ + u16 fc; + u16 dur; + u8 ra[ETH_ALEN]; + u8 ta[ETH_ALEN]; +} WLAN_PACKED rts; +typedef struct { /* has no body, just a FCS */ + u16 fc; + u16 dur; + u8 ra[ETH_ALEN]; +} WLAN_PACKED cts; +typedef struct { /* has no body, just a FCS */ + u16 fc; + u16 dur; + u8 ra[ETH_ALEN]; +} WLAN_PACKED ack; +typedef struct { /* has no body, just a FCS */ + u16 fc; + /* NB: this one holds Assoc ID in dur field: */ + u16 aid; + u8 bssid[ETH_ALEN]; + u8 ta[ETH_ALEN]; +} WLAN_PACKED pspoll; +typedef struct { /* has no body, just a FCS */ + u16 fc; + u16 dur; + u8 ra[ETH_ALEN]; + u8 bssid[ETH_ALEN]; +} WLAN_PACKED cfend; +typedef struct { /* has no body, just a FCS */ + u16 fc; + u16 dur; + u8 ra[ETH_ALEN]; + u8 bssid[ETH_ALEN]; +} WLAN_PACKED cfendcfack; +#endif + +/* Prism header emulation (monitor mode) */ +typedef struct wlanitem_u32 { + u32 did; + u16 status; + u16 len; + u32 data; +} WLAN_PACKED wlanitem_u32_t; +#define WLANITEM_STATUS_data_ok 0 +#define WLANITEM_STATUS_no_value 1 +#define WLANITEM_STATUS_invalid_itemname 2 +#define WLANITEM_STATUS_invalid_itemdata 3 +#define WLANITEM_STATUS_missing_itemdata 4 +#define WLANITEM_STATUS_incomplete_itemdata 5 +#define WLANITEM_STATUS_invalid_msg_did 6 +#define WLANITEM_STATUS_invalid_mib_did 7 +#define WLANITEM_STATUS_missing_conv_func 8 +#define WLANITEM_STATUS_string_too_long 9 +#define WLANITEM_STATUS_data_out_of_range 10 +#define WLANITEM_STATUS_string_too_short 11 +#define WLANITEM_STATUS_missing_valid_func 12 +#define WLANITEM_STATUS_unknown 13 +#define WLANITEM_STATUS_invalid_did 14 +#define WLANITEM_STATUS_missing_print_func 15 + +#define WLAN_DEVNAMELEN_MAX 16 +typedef struct wlansniffrm { + u32 msgcode; + u32 msglen; + u8 devname[WLAN_DEVNAMELEN_MAX]; + wlanitem_u32_t hosttime; + wlanitem_u32_t mactime; + wlanitem_u32_t channel; + wlanitem_u32_t rssi; + wlanitem_u32_t sq; + wlanitem_u32_t signal; + wlanitem_u32_t noise; + wlanitem_u32_t rate; + wlanitem_u32_t istx; /* tx? 0:no 1:yes */ + wlanitem_u32_t frmlen; +} WLAN_PACKED wlansniffrm_t; +#define WLANSNIFFFRM 0x0041 +#define WLANSNIFFFRM_hosttime 0x1041 +#define WLANSNIFFFRM_mactime 0x2041 +#define WLANSNIFFFRM_channel 0x3041 +#define WLANSNIFFFRM_rssi 0x4041 +#define WLANSNIFFFRM_sq 0x5041 +#define WLANSNIFFFRM_signal 0x6041 +#define WLANSNIFFFRM_noise 0x7041 +#define WLANSNIFFFRM_rate 0x8041 +#define WLANSNIFFFRM_istx 0x9041 +#define WLANSNIFFFRM_frmlen 0xA041 --- linux-2.6.27.orig/ubuntu/misc/wireless/acx/usb.c +++ linux-2.6.27/ubuntu/misc/wireless/acx/usb.c @@ -0,0 +1,1725 @@ +/*********************************************************************** +** Copyright (C) 2003 ACX100 Open Source Project +** +** The contents of this file are subject to the Mozilla Public +** License Version 1.1 (the "License"); you may not use this file +** except in compliance with the License. You may obtain a copy of +** the License at http://www.mozilla.org/MPL/ +** +** Software distributed under the License is distributed on an "AS +** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +** implied. See the License for the specific language governing +** rights and limitations under the License. +** +** Alternatively, the contents of this file may be used under the +** terms of the GNU Public License version 2 (the "GPL"), in which +** case the provisions of the GPL are applicable instead of the +** above. If you wish to allow the use of your version of this file +** only under the terms of the GPL and not to allow others to use +** your version of this file under the MPL, indicate your decision +** by deleting the provisions above and replace them with the notice +** and other provisions required by the GPL. If you do not delete +** the provisions above, a recipient may use your version of this +** file under either the MPL or the GPL. +** --------------------------------------------------------------------- +** Inquiries regarding the ACX100 Open Source Project can be +** made directly to: +** +** acx100-users@lists.sf.net +** http://acx100.sf.net +** --------------------------------------------------------------------- +*/ + +/*********************************************************************** +** USB support for TI ACX100 based devices. Many parts are taken from +** the PCI driver. +** +** Authors: +** Martin Wawro +** Andreas Mohr +** +** LOCKING +** callback functions called by USB core are running in interrupt context +** and thus have names with _i_. +*/ +#define ACX_USB 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acx.h" + + +/*********************************************************************** +*/ +/* number of endpoints of an interface */ +#define NUM_EP(intf) (intf)->altsetting[0].desc.bNumEndpoints +#define EP(intf, nr) (intf)->altsetting[0].endpoint[(nr)].desc +#define GET_DEV(udev) usb_get_dev((udev)) +#define PUT_DEV(udev) usb_put_dev((udev)) +#define SET_NETDEV_OWNER(ndev, owner) /* not needed anymore ??? */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) +/* removed in 2.6.14. We will use fake value for now */ +#define URB_ASYNC_UNLINK 0 +#endif + + +/*********************************************************************** +*/ +/* ACX100 (TNETW1100) USB device: D-Link DWL-120+ */ +#define ACX100_VENDOR_ID 0x2001 +#define ACX100_PRODUCT_ID_UNBOOTED 0x3B01 +#define ACX100_PRODUCT_ID_BOOTED 0x3B00 + +/* TNETW1450 USB devices */ +#define VENDOR_ID_DLINK 0x07b8 /* D-Link Corp. */ +#define PRODUCT_ID_WUG2400 0xb21a /* AboCom WUG2400 or SafeCom SWLUT-54125 */ +#define VENDOR_ID_AVM_GMBH 0x057c +#define PRODUCT_ID_AVM_WLAN_USB 0x5601 +#define PRODUCT_ID_AVM_WLAN_USB_si 0x6201 /* "self install" named Version: driver kills kernel on inbound scans from fritz box ??? */ +#define VENDOR_ID_ZCOM 0x0cde +#define PRODUCT_ID_ZCOM_XG750 0x0017 /* not tested yet */ +#define VENDOR_ID_TI 0x0451 +#define PRODUCT_ID_TI_UNKNOWN 0x60c5 /* not tested yet */ + +#define ACX_USB_CTRL_TIMEOUT 5500 /* steps in ms */ + +/* Buffer size for fw upload, same for both ACX100 USB and TNETW1450 */ +#define ACX_USB_RWMEM_MAXLEN 2048 + +/* The number of bulk URBs to use */ +#define ACX_TX_URB_CNT 8 +#define ACX_RX_URB_CNT 2 + +/* Should be sent to the bulkout endpoint */ +#define ACX_USB_REQ_UPLOAD_FW 0x10 +#define ACX_USB_REQ_ACK_CS 0x11 +#define ACX_USB_REQ_CMD 0x12 + +/*********************************************************************** +** Prototypes +*/ +static int acxusb_e_probe(struct usb_interface *, const struct usb_device_id *); +static void acxusb_e_disconnect(struct usb_interface *); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) +static void acxusb_i_complete_tx(struct urb *); +static void acxusb_i_complete_rx(struct urb *); +#else +static void acxusb_i_complete_tx(struct urb *, struct pt_regs *); +static void acxusb_i_complete_rx(struct urb *, struct pt_regs *); +#endif +static int acxusb_e_open(struct net_device *); +static int acxusb_e_close(struct net_device *); +static void acxusb_i_set_rx_mode(struct net_device *); +static int acxusb_boot(struct usb_device *); + +static void acxusb_l_poll_rx(acx_device_t *adev, usb_rx_t* rx); + +static void acxusb_i_tx_timeout(struct net_device *); + +/* static void dump_device(struct usb_device *); */ +/* static void dump_device_descriptor(struct usb_device_descriptor *); */ +/* static void dump_config_descriptor(struct usb_config_descriptor *); */ + +/*********************************************************************** +** Module Data +*/ +#define TXBUFSIZE sizeof(usb_txbuffer_t) +/* + * Now, this is just plain lying, but the device insists in giving us + * huge packets. We supply extra space after rxbuffer. Need to understand + * it better... + */ +#define RXBUFSIZE (sizeof(rxbuffer_t) + \ + (sizeof(usb_rx_t) - sizeof(struct usb_rx_plain))) + +static const struct usb_device_id +acxusb_ids[] = { + { USB_DEVICE(ACX100_VENDOR_ID, ACX100_PRODUCT_ID_BOOTED) }, + { USB_DEVICE(ACX100_VENDOR_ID, ACX100_PRODUCT_ID_UNBOOTED) }, + {} +}; +MODULE_DEVICE_TABLE(usb, acxusb_ids); + +/* USB driver data structure as required by the kernel's USB core */ +static struct usb_driver +acxusb_driver = { + .name = "acx_usb", + .probe = acxusb_e_probe, + .disconnect = acxusb_e_disconnect, + .id_table = acxusb_ids +}; + + +/*********************************************************************** +** USB helper +** +** ldd3 ch13 says: +** When the function is usb_kill_urb, the urb lifecycle is stopped. This +** function is usually used when the device is disconnected from the system, +** in the disconnect callback. For some drivers, the usb_unlink_urb function +** should be used to tell the USB core to stop an urb. This function does not +** wait for the urb to be fully stopped before returning to the caller. +** This is useful for stoppingthe urb while in an interrupt handler or when +** a spinlock is held, as waiting for a urb to fully stop requires the ability +** for the USB core to put the calling process to sleep. This function requires +** that the URB_ASYNC_UNLINK flag value be set in the urb that is being asked +** to be stopped in order to work properly. +** +** (URB_ASYNC_UNLINK is obsolete, usb_unlink_urb will always be +** asynchronous while usb_kill_urb is synchronous and should be called +** directly (drivers/usb/core/urb.c)) +** +** In light of this, timeout is just for paranoid reasons... +* +* Actually, it's useful for debugging. If we reach timeout, we're doing +* something wrong with the urbs. +*/ +static void +acxusb_unlink_urb(struct urb* urb) +{ + if (!urb) + return; + + if (urb->status == -EINPROGRESS) { + int timeout = 10; + + usb_unlink_urb(urb); + while (--timeout && urb->status == -EINPROGRESS) { + mdelay(1); + } + if (!timeout) { + printk("acx_usb: urb unlink timeout!\n"); + } + } +} + + +/*********************************************************************** +** EEPROM and PHY read/write helpers +*/ +/*********************************************************************** +** acxusb_s_read_phy_reg +*/ +int +acxusb_s_read_phy_reg(acx_device_t *adev, u32 reg, u8 *charbuf) +{ + /* mem_read_write_t mem; */ + + FN_ENTER; + + printk("%s doesn't seem to work yet, disabled.\n", __func__); + + /* + mem.addr = cpu_to_le16(reg); + mem.type = cpu_to_le16(0x82); + mem.len = cpu_to_le32(4); + acx_s_issue_cmd(adev, ACX1xx_CMD_MEM_READ, &mem, sizeof(mem)); + *charbuf = mem.data; + log(L_DEBUG, "read radio PHY[0x%04X]=0x%02X\n", reg, *charbuf); + */ + + FN_EXIT1(OK); + return OK; +} + + +/*********************************************************************** +*/ +int +acxusb_s_write_phy_reg(acx_device_t *adev, u32 reg, u8 value) +{ + mem_read_write_t mem; + + FN_ENTER; + + mem.addr = cpu_to_le16(reg); + mem.type = cpu_to_le16(0x82); + mem.len = cpu_to_le32(4); + mem.data = value; + acx_s_issue_cmd(adev, ACX1xx_CMD_MEM_WRITE, &mem, sizeof(mem)); + log(L_DEBUG, "write radio PHY[0x%04X]=0x%02X\n", reg, value); + + FN_EXIT1(OK); + return OK; +} + + +/*********************************************************************** +** acxusb_s_issue_cmd_timeo +** Excecutes a command in the command mailbox +** +** buffer = a pointer to the data. +** The data must not include 4 byte command header +*/ + +/* TODO: ideally we shall always know how much we need +** and this shall be 0 */ +#define BOGUS_SAFETY_PADDING 0x40 + +#undef FUNC +#define FUNC "issue_cmd" + +#if !ACX_DEBUG +int +acxusb_s_issue_cmd_timeo( + acx_device_t *adev, + unsigned cmd, + void *buffer, + unsigned buflen, + unsigned timeout) +{ +#else +int +acxusb_s_issue_cmd_timeo_debug( + acx_device_t *adev, + unsigned cmd, + void *buffer, + unsigned buflen, + unsigned timeout, + const char* cmdstr) +{ +#endif + /* USB ignores timeout param */ + + struct usb_device *usbdev; + struct { + u16 cmd; + u16 status; + u8 data[1]; + } ACX_PACKED *loc; + const char *devname; + int acklen, blocklen, inpipe, outpipe; + int cmd_status; + int result; + + FN_ENTER; + + devname = adev->ndev->name; + /* no "wlan%%d: ..." please */ + if (!devname || !devname[0] || devname[4]=='%') + devname = "acx"; + + log(L_CTL, FUNC"(cmd:%s,buflen:%u,type:0x%04X)\n", + cmdstr, buflen, + buffer ? le16_to_cpu(((acx_ie_generic_t *)buffer)->type) : -1); + + loc = kmalloc(buflen + 4 + BOGUS_SAFETY_PADDING, GFP_KERNEL); + if (!loc) { + printk("%s: "FUNC"(): no memory for data buffer\n", devname); + goto bad; + } + + /* get context from acx_device */ + usbdev = adev->usbdev; + + /* check which kind of command was issued */ + loc->cmd = cpu_to_le16(cmd); + loc->status = 0; + +/* NB: buflen == frmlen + 4 +** +** Interrogate: write 8 bytes: (cmd,status,rid,frmlen), then +** read (cmd,status,rid,frmlen,data[frmlen]) back +** +** Configure: write (cmd,status,rid,frmlen,data[frmlen]) +** +** Possibly bogus special handling of ACX1xx_IE_SCAN_STATUS removed +*/ + + /* now write the parameters of the command if needed */ + acklen = buflen + 4 + BOGUS_SAFETY_PADDING; + blocklen = buflen; + if (buffer && buflen) { + /* if it's an INTERROGATE command, just pass the length + * of parameters to read, as data */ + if (cmd == ACX1xx_CMD_INTERROGATE) { + blocklen = 4; + acklen = buflen + 4; + } + memcpy(loc->data, buffer, blocklen); + } + blocklen += 4; /* account for cmd,status */ + + /* obtain the I/O pipes */ + outpipe = usb_sndctrlpipe(usbdev, 0); + inpipe = usb_rcvctrlpipe(usbdev, 0); + log(L_CTL, "ctrl inpipe=0x%X outpipe=0x%X\n", inpipe, outpipe); + log(L_CTL, "sending USB control msg (out) (blocklen=%d)\n", blocklen); + if (acx_debug & L_DATA) + acx_dump_bytes(loc, blocklen); + + result = usb_control_msg(usbdev, outpipe, + ACX_USB_REQ_CMD, /* request */ + USB_TYPE_VENDOR|USB_DIR_OUT, /* requesttype */ + 0, /* value */ + 0, /* index */ + loc, /* dataptr */ + blocklen, /* size */ + ACX_USB_CTRL_TIMEOUT /* timeout in ms */ + ); + + if (result == -ENODEV) { + log(L_CTL, "no device present (unplug?)\n"); + goto good; + } + + log(L_CTL, "wrote %d bytes\n", result); + if (result < 0) { + goto bad; + } + + /* check for device acknowledge */ + log(L_CTL, "sending USB control msg (in) (acklen=%d)\n", acklen); + loc->status = 0; /* delete old status flag -> set to IDLE */ + /* shall we zero out the rest? */ + result = usb_control_msg(usbdev, inpipe, + ACX_USB_REQ_CMD, /* request */ + USB_TYPE_VENDOR|USB_DIR_IN, /* requesttype */ + 0, /* value */ + 0, /* index */ + loc, /* dataptr */ + acklen, /* size */ + ACX_USB_CTRL_TIMEOUT /* timeout in ms */ + ); + if (result < 0) { + printk("%s: "FUNC"(): USB read error %d\n", devname, result); + goto bad; + } + if (acx_debug & L_CTL) { + printk("read %d bytes: ", result); + acx_dump_bytes(loc, result); + } + +/* + check for result==buflen+4? Was seen: + +interrogate(type:ACX100_IE_DOT11_ED_THRESHOLD,len:4) +issue_cmd(cmd:ACX1xx_CMD_INTERROGATE,buflen:8,type:4111) +ctrl inpipe=0x80000280 outpipe=0x80000200 +sending USB control msg (out) (blocklen=8) +01 00 00 00 0F 10 04 00 +wrote 8 bytes +sending USB control msg (in) (acklen=12) sizeof(loc->data +read 4 bytes <==== MUST BE 12!! +*/ + + cmd_status = le16_to_cpu(loc->status); + if (cmd_status != 1) { + printk("%s: "FUNC"(): cmd_status is not SUCCESS: %d (%s)\n", + devname, cmd_status, acx_cmd_status_str(cmd_status)); + /* TODO: goto bad; ? */ + } + if ((cmd == ACX1xx_CMD_INTERROGATE) && buffer && buflen) { + memcpy(buffer, loc->data, buflen); + log(L_CTL, "response frame: cmd=0x%04X status=%d\n", + le16_to_cpu(loc->cmd), + cmd_status); + } +good: + kfree(loc); + FN_EXIT1(OK); + return OK; +bad: + /* Give enough info so that callers can avoid + ** printing their own diagnostic messages */ +#if ACX_DEBUG + printk("%s: "FUNC"(cmd:%s) FAILED\n", devname, cmdstr); +#else + printk("%s: "FUNC"(cmd:0x%04X) FAILED\n", devname, cmd); +#endif + dump_stack(); + kfree(loc); + FN_EXIT1(NOT_OK); + return NOT_OK; +} + + +/*********************************************************************** +** acxusb_boot() +** Inputs: +** usbdev -> Pointer to kernel's usb_device structure +** +** Returns: +** (int) Errorcode or 0 on success +** +** This function triggers the loading of the firmware image from harddisk +** and then uploads the firmware to the USB device. After uploading the +** firmware and transmitting the checksum, the device resets and appears +** as a new device on the USB bus (the device we can finally deal with) +*/ +static int +acxusb_boot(struct usb_device *usbdev) +{ + char filename[256]; + char *firmware = NULL; + char *usbbuf; + unsigned int offset; + unsigned int len, inpipe, outpipe; + u32 checksum; + u32 size; + int result; + + FN_ENTER; + + usbbuf = kmalloc(ACX_USB_RWMEM_MAXLEN, GFP_KERNEL); + if (!usbbuf) { + printk(KERN_ERR "acx: no memory for USB transfer buffer (" + STRING(ACX_USB_RWMEM_MAXLEN)" bytes)\n"); + result = -ENOMEM; + goto end; + } + + snprintf(filename, sizeof(filename), "acx/%s/tiacx100usb", firmware_ver); + firmware = (char *)acx_s_read_fw(&usbdev->dev, filename, &size); + if (!firmware) { + result = -EIO; + goto end; + } + log(L_INIT, "firmware size: %d bytes\n", size); + + /* Obtain the I/O pipes */ + outpipe = usb_sndctrlpipe(usbdev, 0); + inpipe = usb_rcvctrlpipe(usbdev, 0); + + /* now upload the firmware, slice the data into blocks */ + offset = 8; + while (offset < size) { + len = size - offset; + if (len >= ACX_USB_RWMEM_MAXLEN) { + len = ACX_USB_RWMEM_MAXLEN; + } + log(L_INIT, "uploading firmware (%d bytes, offset=%d)\n", + len, offset); + result = 0; + memcpy(usbbuf, firmware + offset, len); + result = usb_control_msg(usbdev, outpipe, + ACX_USB_REQ_UPLOAD_FW, + USB_TYPE_VENDOR|USB_DIR_OUT, + size - 8, /* value */ + 0, /* index */ + usbbuf, /* dataptr */ + len, /* size */ + 3000 /* timeout in ms */ + ); + offset += len; + if (result < 0) { + printk(KERN_ERR "acx: error %d during upload " + "of firmware, aborting\n", result); + goto end; + } + } + + /* finally, send the checksum and reboot the device */ + /* does this trigger the reboot? */ + checksum = le32_to_cpu(*(u32 *)firmware); + result = usb_control_msg(usbdev, outpipe, + ACX_USB_REQ_UPLOAD_FW, + USB_TYPE_VENDOR|USB_DIR_OUT, + checksum & 0xffff, /* value */ + checksum >> 16, /* index */ + NULL, /* dataptr */ + 0, /* size */ + 3000 /* timeout in ms */ + ); + if (result < 0) { + printk(KERN_ERR "acx: error %d during tx of checksum, " + "aborting\n", result); + goto end; + } + result = usb_control_msg(usbdev, inpipe, + ACX_USB_REQ_ACK_CS, + USB_TYPE_VENDOR|USB_DIR_IN, + checksum & 0xffff, /* value */ + checksum >> 16, /* index */ + usbbuf, /* dataptr */ + 8, /* size */ + 3000 /* timeout in ms */ + ); + if (result < 0) { + printk(KERN_ERR "acx: error %d during ACK of checksum, " + "aborting\n", result); + goto end; + } + if (*usbbuf != 0x10) { + kfree(usbbuf); + printk(KERN_ERR "acx: invalid checksum?\n"); + result = -EINVAL; + goto end; + } + result = 0; + +end: + vfree(firmware); + kfree(usbbuf); + + FN_EXIT1(result); + return result; +} + + +/* FIXME: maybe merge it with usual eeprom reading, into common code? */ +static void +acxusb_s_read_eeprom_version(acx_device_t *adev) +{ + u8 eeprom_ver[0x8]; + + memset(eeprom_ver, 0, sizeof(eeprom_ver)); + acx_s_interrogate(adev, &eeprom_ver, ACX1FF_IE_EEPROM_VER); + + /* FIXME: which one of those values to take? */ + adev->eeprom_version = eeprom_ver[5]; +} + + +/* + * temporary helper function to at least fill important cfgopt members with + * useful replacement values until we figure out how one manages to fetch + * the configoption struct in the USB device case... + */ +static int +acxusb_s_fill_configoption(acx_device_t *adev) +{ + adev->cfgopt_probe_delay = 200; + adev->cfgopt_dot11CCAModes = 4; + adev->cfgopt_dot11Diversity = 1; + adev->cfgopt_dot11ShortPreambleOption = 1; + adev->cfgopt_dot11PBCCOption = 1; + adev->cfgopt_dot11ChannelAgility = 0; + adev->cfgopt_dot11PhyType = 5; + adev->cfgopt_dot11TempType = 1; + return OK; +} + + +/*********************************************************************** +** acxusb_e_probe() +** +** This function is invoked by the kernel's USB core whenever a new device is +** attached to the system or the module is loaded. It is presented a usb_device +** structure from which information regarding the device is obtained and evaluated. +** In case this driver is able to handle one of the offered devices, it returns +** a non-null pointer to a driver context and thereby claims the device. +*/ + +static void +dummy_netdev_init(struct net_device *ndev) {} + +static int +acxusb_e_probe(struct usb_interface *intf, const struct usb_device_id *devID) +{ + struct usb_device *usbdev = interface_to_usbdev(intf); + acx_device_t *adev = NULL; + struct net_device *ndev = NULL; + struct usb_config_descriptor *config; + struct usb_endpoint_descriptor *epdesc; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) + struct usb_host_endpoint *ep; +#endif + struct usb_interface_descriptor *ifdesc; + const char* msg; + int numconfigs, numfaces, numep; + int result = OK; + int i; + + FN_ENTER; + + /* First check if this is the "unbooted" hardware */ + if ((usbdev->descriptor.idVendor == ACX100_VENDOR_ID) + && (usbdev->descriptor.idProduct == ACX100_PRODUCT_ID_UNBOOTED)) { + /* Boot the device (i.e. upload the firmware) */ + acxusb_boot(usbdev); + + /* OK, we are done with booting. Normally, the + ** ID for the unbooted device should disappear + ** and it will not need a driver anyway...so + ** return a NULL + */ + log(L_INIT, "finished booting, returning from probe()\n"); + result = OK; /* success */ + goto end; + } + + if ((usbdev->descriptor.idVendor != ACX100_VENDOR_ID) + || (usbdev->descriptor.idProduct != ACX100_PRODUCT_ID_BOOTED)) { + goto end_nodev; + } + +/* Ok, so it's our device and it has already booted */ + + /* Allocate memory for a network device */ + + ndev = alloc_netdev(sizeof(*adev), "wlan%d", dummy_netdev_init); + /* (NB: memsets to 0 entire area) */ + if (!ndev) { + msg = "acx: no memory for netdev\n"; + goto end_nomem; + } + + /* Register the callbacks for the network device functions */ + + ether_setup(ndev); + ndev->open = &acxusb_e_open; + ndev->stop = &acxusb_e_close; + ndev->hard_start_xmit = (void *)&acx_i_start_xmit; + ndev->get_stats = (void *)&acx_e_get_stats; + ndev->set_multicast_list = (void *)&acxusb_i_set_rx_mode; +#ifdef HAVE_TX_TIMEOUT + ndev->tx_timeout = &acxusb_i_tx_timeout; + ndev->watchdog_timeo = 4 * HZ; +#endif + ndev->change_mtu = &acx_e_change_mtu; + + /* Setup private driver context */ + + adev = netdev_priv(ndev); + adev->ndev = ndev; + + adev->dev_type = DEVTYPE_USB; + adev->chip_type = CHIPTYPE_ACX100; + + /* FIXME: should be read from register (via firmware) using standard ACX code */ + adev->radio_type = RADIO_MAXIM_0D; + + adev->usbdev = usbdev; + spin_lock_init(&adev->lock); /* initial state: unlocked */ + sema_init(&adev->sem, 1); /* initial state: 1 (upped) */ + + /* Check that this is really the hardware we know about. + ** If not sure, at least notify the user that he + ** may be in trouble... + */ + numconfigs = (int)usbdev->descriptor.bNumConfigurations; + if (numconfigs != 1) + printk("acx: number of configurations is %d, " + "this driver only knows how to handle 1, " + "be prepared for surprises\n", numconfigs); + + config = &usbdev->config->desc; + numfaces = config->bNumInterfaces; + if (numfaces != 1) + printk("acx: number of interfaces is %d, " + "this driver only knows how to handle 1, " + "be prepared for surprises\n", numfaces); + + ifdesc = &intf->altsetting->desc; + numep = ifdesc->bNumEndpoints; + log(L_DEBUG, "# of endpoints: %d\n", numep); + + /* obtain information about the endpoint + ** addresses, begin with some default values + */ + adev->bulkoutep = 1; + adev->bulkinep = 1; + for (i = 0; i < numep; i++) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) + ep = usbdev->ep_in[i]; + if (!ep) + continue; + epdesc = &ep->desc; +#else + epdesc = usb_epnum_to_ep_desc(usbdev, i); + if (!epdesc) + continue; +#endif + if (epdesc->bmAttributes & USB_ENDPOINT_XFER_BULK) { + if (epdesc->bEndpointAddress & 0x80) + adev->bulkinep = epdesc->bEndpointAddress & 0xF; + else + adev->bulkoutep = epdesc->bEndpointAddress & 0xF; + } + } + log(L_DEBUG, "bulkout ep: 0x%X\n", adev->bulkoutep); + log(L_DEBUG, "bulkin ep: 0x%X\n", adev->bulkinep); + + /* already done by memset: adev->rxtruncsize = 0; */ + log(L_DEBUG, "TXBUFSIZE=%d RXBUFSIZE=%d\n", + (int) TXBUFSIZE, (int) RXBUFSIZE); + + /* Allocate the RX/TX containers. */ + adev->usb_tx = kmalloc(sizeof(usb_tx_t) * ACX_TX_URB_CNT, GFP_KERNEL); + if (!adev->usb_tx) { + msg = "acx: no memory for tx container"; + goto end_nomem; + } + adev->usb_rx = kmalloc(sizeof(usb_rx_t) * ACX_RX_URB_CNT, GFP_KERNEL); + if (!adev->usb_rx) { + msg = "acx: no memory for rx container"; + goto end_nomem; + } + + /* Setup URBs for bulk-in/out messages */ + for (i = 0; i < ACX_RX_URB_CNT; i++) { + adev->usb_rx[i].urb = usb_alloc_urb(0, GFP_KERNEL); + if (!adev->usb_rx[i].urb) { + msg = "acx: no memory for input URB\n"; + goto end_nomem; + } + adev->usb_rx[i].urb->status = 0; + adev->usb_rx[i].adev = adev; + adev->usb_rx[i].busy = 0; + } + + for (i = 0; i< ACX_TX_URB_CNT; i++) { + adev->usb_tx[i].urb = usb_alloc_urb(0, GFP_KERNEL); + if (!adev->usb_tx[i].urb) { + msg = "acx: no memory for output URB\n"; + goto end_nomem; + } + adev->usb_tx[i].urb->status = 0; + adev->usb_tx[i].adev = adev; + adev->usb_tx[i].busy = 0; + } + adev->tx_free = ACX_TX_URB_CNT; + + usb_set_intfdata(intf, adev); + SET_NETDEV_DEV(ndev, &intf->dev); + + /* TODO: move all of fw cmds to open()? But then we won't know our MAC addr + until ifup (it's available via reading ACX1xx_IE_DOT11_STATION_ID)... */ + + /* put acx out of sleep mode and initialize it */ + acx_s_issue_cmd(adev, ACX1xx_CMD_WAKE, NULL, 0); + + result = acx_s_init_mac(adev); + if (result) + goto end; + + /* TODO: see similar code in pci.c */ + acxusb_s_read_eeprom_version(adev); + acxusb_s_fill_configoption(adev); + acx_s_set_defaults(adev); + acx_s_get_firmware_version(adev); + acx_display_hardware_details(adev); + + /* Register the network device */ + log(L_INIT, "registering network device\n"); + result = register_netdev(ndev); + if (result) { + msg = "acx: failed to register USB network device " + "(error %d)\n"; + goto end_nomem; + } + + acx_proc_register_entries(ndev); + + acx_stop_queue(ndev, "on probe"); + acx_carrier_off(ndev, "on probe"); + + printk("acx: USB module " ACX_RELEASE " loaded successfully\n"); + +#if CMD_DISCOVERY + great_inquisitor(adev); +#endif + + /* Everything went OK, we are happy now */ + result = OK; + goto end; + +end_nomem: + printk(msg, result); + + if (ndev) { + if (adev->usb_rx) { + for (i = 0; i < ACX_RX_URB_CNT; i++) + usb_free_urb(adev->usb_rx[i].urb); + kfree(adev->usb_rx); + } + if (adev->usb_tx) { + for (i = 0; i < ACX_TX_URB_CNT; i++) + usb_free_urb(adev->usb_tx[i].urb); + kfree(adev->usb_tx); + } + free_netdev(ndev); + } + + result = -ENOMEM; + goto end; + +end_nodev: + /* no device we could handle, return error. */ + result = -EIO; + +end: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acxusb_e_disconnect() +** +** This function is invoked whenever the user pulls the plug from the USB +** device or the module is removed from the kernel. In these cases, the +** network devices have to be taken down and all allocated memory has +** to be freed. +*/ +static void +acxusb_e_disconnect(struct usb_interface *intf) +{ + acx_device_t *adev = usb_get_intfdata(intf); + unsigned long flags; + int i; + + FN_ENTER; + + /* No WLAN device... no sense */ + if (!adev) + goto end; + + /* Unregister network device + * + * If the interface is up, unregister_netdev() will take + * care of calling our close() function, which takes + * care of unlinking the urbs, sending the device to + * sleep, etc... + * This can't be called with sem or lock held because + * _close() will try to grab it as well if it's called, + * deadlocking the machine. + */ + unregister_netdev(adev->ndev); + + acx_sem_lock(adev); + acx_lock(adev, flags); + /* This device exists no more */ + usb_set_intfdata(intf, NULL); + acx_proc_unregister_entries(adev->ndev); + + /* + * Here we only free them. _close() took care of + * unlinking them. + */ + for (i = 0; i < ACX_RX_URB_CNT; ++i) { + usb_free_urb(adev->usb_rx[i].urb); + } + for (i = 0; i< ACX_TX_URB_CNT; ++i) { + usb_free_urb(adev->usb_tx[i].urb); + } + + /* Freeing containers */ + kfree(adev->usb_rx); + kfree(adev->usb_tx); + + acx_unlock(adev, flags); + acx_sem_unlock(adev); + + free_netdev(adev->ndev); +end: + FN_EXIT0; +} + + +/*********************************************************************** +** acxusb_e_open() +** This function is called when the user sets up the network interface. +** It initializes a management timer, sets up the USB card and starts +** the network tx queue and USB receive. +*/ +static int +acxusb_e_open(struct net_device *ndev) +{ + acx_device_t *adev = ndev2adev(ndev); + unsigned long flags; + int i; + + FN_ENTER; + + acx_sem_lock(adev); + + /* put the ACX100 out of sleep mode */ + acx_s_issue_cmd(adev, ACX1xx_CMD_WAKE, NULL, 0); + + acx_init_task_scheduler(adev); + + init_timer(&adev->mgmt_timer); + adev->mgmt_timer.function = acx_i_timer; + adev->mgmt_timer.data = (unsigned long)adev; + + /* acx_s_start needs it */ + SET_BIT(adev->dev_state_mask, ACX_STATE_IFACE_UP); + acx_s_start(adev); + + /* don't acx_start_queue() here, we need to associate first */ + + acx_lock(adev, flags); + for (i = 0; i < ACX_RX_URB_CNT; i++) { + adev->usb_rx[i].urb->status = 0; + } + + acxusb_l_poll_rx(adev, &adev->usb_rx[0]); + + acx_unlock(adev, flags); + + acx_sem_unlock(adev); + + FN_EXIT0; + return 0; +} + + +/*********************************************************************** +** acxusb_e_close() +** +** This function stops the network functionality of the interface (invoked +** when the user calls ifconfig down). The tx queue is halted and +** the device is marked as down. In case there were any pending USB bulk +** transfers, these are unlinked (asynchronously). The module in-use count +** is also decreased in this function. +*/ +static int +acxusb_e_close(struct net_device *ndev) +{ + acx_device_t *adev = ndev2adev(ndev); + unsigned long flags; + int i; + + FN_ENTER; + +#ifdef WE_STILL_DONT_CARE_ABOUT_IT + /* Transmit a disassociate frame */ + lock + acx_l_transmit_disassoc(adev, &client); + unlock +#endif + + acx_sem_lock(adev); + + CLEAR_BIT(adev->dev_state_mask, ACX_STATE_IFACE_UP); + +/* Code below is remarkably similar to acxpci_s_down(). Maybe we can merge them? */ + + /* Make sure we don't get any more rx requests */ + acx_s_issue_cmd(adev, ACX1xx_CMD_DISABLE_RX, NULL, 0); + acx_s_issue_cmd(adev, ACX1xx_CMD_DISABLE_TX, NULL, 0); + + /* + * We must do FLUSH *without* holding sem to avoid a deadlock. + * See pci.c:acxpci_s_down() for deails. + */ + acx_sem_unlock(adev); + FLUSH_SCHEDULED_WORK(); + acx_sem_lock(adev); + + /* Power down the device */ + acx_s_issue_cmd(adev, ACX1xx_CMD_SLEEP, NULL, 0); + + /* Stop the transmit queue, mark the device as DOWN */ + acx_lock(adev, flags); + acx_stop_queue(ndev, "on ifdown"); + acx_set_status(adev, ACX_STATUS_0_STOPPED); + /* stop pending rx/tx urb transfers */ + for (i = 0; i < ACX_TX_URB_CNT; i++) { + acxusb_unlink_urb(adev->usb_tx[i].urb); + adev->usb_tx[i].busy = 0; + } + for (i = 0; i < ACX_RX_URB_CNT; i++) { + acxusb_unlink_urb(adev->usb_rx[i].urb); + adev->usb_rx[i].busy = 0; + } + adev->tx_free = ACX_TX_URB_CNT; + acx_unlock(adev, flags); + + /* Must do this outside of lock */ + del_timer_sync(&adev->mgmt_timer); + + acx_sem_unlock(adev); + + FN_EXIT0; + return 0; +} + + +/*********************************************************************** +** acxusb_l_poll_rx +** This function (re)initiates a bulk-in USB transfer on a given urb +*/ +static void +acxusb_l_poll_rx(acx_device_t *adev, usb_rx_t* rx) +{ + struct usb_device *usbdev; + struct urb *rxurb; + int errcode, rxnum; + unsigned int inpipe; + + FN_ENTER; + + rxurb = rx->urb; + usbdev = adev->usbdev; + + rxnum = rx - adev->usb_rx; + + inpipe = usb_rcvbulkpipe(usbdev, adev->bulkinep); + if (unlikely(rxurb->status == -EINPROGRESS)) { + printk(KERN_ERR "acx: error, rx triggered while rx urb in progress\n"); + /* FIXME: this is nasty, receive is being cancelled by this code + * on the other hand, this should not happen anyway... + */ + usb_unlink_urb(rxurb); + } else + if (unlikely(rxurb->status == -ECONNRESET)) { + log(L_USBRXTX, "acx_usb: _poll_rx: connection reset\n"); + goto end; + } + rxurb->actual_length = 0; + usb_fill_bulk_urb(rxurb, usbdev, inpipe, + &rx->bulkin, /* dataptr */ + RXBUFSIZE, /* size */ + acxusb_i_complete_rx, /* handler */ + rx /* handler param */ + ); + rxurb->transfer_flags = URB_ASYNC_UNLINK; + + /* ATOMIC: we may be called from complete_rx() usb callback */ + errcode = usb_submit_urb(rxurb, GFP_ATOMIC); + /* FIXME: evaluate the error code! */ + log(L_USBRXTX, "SUBMIT RX (%d) inpipe=0x%X size=%d errcode=%d\n", + rxnum, inpipe, (int) RXBUFSIZE, errcode); +end: + FN_EXIT0; +} + + +/*********************************************************************** +** acxusb_i_complete_rx() +** Inputs: +** urb -> pointer to USB request block +** regs -> pointer to register-buffer for syscalls (see asm/ptrace.h) +** +** This function is invoked by USB subsystem whenever a bulk receive +** request returns. +** The received data is then committed to the network stack and the next +** USB receive is triggered. +*/ +static void +acxusb_i_complete_rx(struct urb *urb) +{ + acx_device_t *adev; + rxbuffer_t *ptr; + rxbuffer_t *inbuf; + usb_rx_t *rx; + unsigned long flags; + int size, remsize, packetsize, rxnum; + + FN_ENTER; + + BUG_ON(!urb->context); + + rx = (usb_rx_t *)urb->context; + adev = rx->adev; + + acx_lock(adev, flags); + + /* + * Happens on disconnect or close. Don't play with the urb. + * Don't resubmit it. It will get unlinked by close() + */ + if (unlikely(!(adev->dev_state_mask & ACX_STATE_IFACE_UP))) { + log(L_USBRXTX, "rx: device is down, not doing anything\n"); + goto end_unlock; + } + + inbuf = &rx->bulkin; + size = urb->actual_length; + remsize = size; + rxnum = rx - adev->usb_rx; + + log(L_USBRXTX, "RETURN RX (%d) status=%d size=%d\n", + rxnum, urb->status, size); + + /* Send the URB that's waiting. */ + log(L_USBRXTX, "rxnum=%d, sending=%d\n", rxnum, rxnum^1); + acxusb_l_poll_rx(adev, &adev->usb_rx[rxnum^1]); + + if (unlikely(size > sizeof(rxbuffer_t))) + printk("acx_usb: rx too large: %d, please report\n", size); + + /* check if the transfer was aborted */ + switch (urb->status) { + case 0: /* No error */ + break; + case -EOVERFLOW: + printk(KERN_ERR "acx: rx data overrun\n"); + adev->rxtruncsize = 0; /* Not valid anymore. */ + goto end_unlock; + case -ECONNRESET: + adev->rxtruncsize = 0; + goto end_unlock; + case -ESHUTDOWN: /* rmmod */ + adev->rxtruncsize = 0; + goto end_unlock; + default: + adev->rxtruncsize = 0; + adev->stats.rx_errors++; + printk("acx: rx error (urb status=%d)\n", urb->status); + goto end_unlock; + } + + if (unlikely(!size)) + printk("acx: warning, encountered zerolength rx packet\n"); + + if (urb->transfer_buffer != inbuf) + goto end_unlock; + + /* check if previous frame was truncated + ** FIXME: this code can only handle truncation + ** of consecutive packets! + */ + ptr = inbuf; + if (adev->rxtruncsize) { + int tail_size; + + ptr = &adev->rxtruncbuf; + packetsize = RXBUF_BYTES_USED(ptr); + if (acx_debug & L_USBRXTX) { + printk("handling truncated frame (truncsize=%d size=%d " + "packetsize(from trunc)=%d)\n", + adev->rxtruncsize, size, packetsize); + acx_dump_bytes(ptr, RXBUF_HDRSIZE); + acx_dump_bytes(inbuf, RXBUF_HDRSIZE); + } + + /* bytes needed for rxtruncbuf completion: */ + tail_size = packetsize - adev->rxtruncsize; + + if (size < tail_size) { + /* there is not enough data to complete this packet, + ** simply append the stuff to the truncation buffer + */ + memcpy(((char *)ptr) + adev->rxtruncsize, inbuf, size); + adev->rxtruncsize += size; + remsize = 0; + } else { + /* ok, this data completes the previously + ** truncated packet. copy it into a descriptor + ** and give it to the rest of the stack */ + + /* append tail to previously truncated part + ** NB: adev->rxtruncbuf (pointed to by ptr) can't + ** overflow because this is already checked before + ** truncation buffer was filled. See below, + ** "if (packetsize > sizeof(rxbuffer_t))..." code */ + memcpy(((char *)ptr) + adev->rxtruncsize, inbuf, tail_size); + + if (acx_debug & L_USBRXTX) { + printk("full trailing packet + 12 bytes:\n"); + acx_dump_bytes(inbuf, tail_size + RXBUF_HDRSIZE); + } + acx_l_process_rxbuf(adev, ptr); + adev->rxtruncsize = 0; + ptr = (rxbuffer_t *) (((char *)inbuf) + tail_size); + remsize -= tail_size; + } + log(L_USBRXTX, "post-merge size=%d remsize=%d\n", + size, remsize); + } + + /* size = USB data block size + ** remsize = unprocessed USB bytes left + ** ptr = current pos in USB data block + */ + while (remsize) { + if (remsize < RXBUF_HDRSIZE) { + printk("acx: truncated rx header (%d bytes)!\n", + remsize); + if (ACX_DEBUG) + acx_dump_bytes(ptr, remsize); + break; + } + + packetsize = RXBUF_BYTES_USED(ptr); + log(L_USBRXTX, "packet with packetsize=%d\n", packetsize); + + if (RXBUF_IS_TXSTAT(ptr)) { + /* do rate handling */ + usb_txstatus_t *stat = (void*)ptr; + u16 client_no = (u16)stat->hostdata; + + log(L_USBRXTX, "tx: stat: mac_cnt_rcvd:%04X " + "queue_index:%02X mac_status:%02X hostdata:%08X " + "rate:%u ack_failures:%02X rts_failures:%02X " + "rts_ok:%02X\n", + stat->mac_cnt_rcvd, + stat->queue_index, stat->mac_status, stat->hostdata, + stat->rate, stat->ack_failures, stat->rts_failures, + stat->rts_ok); + + if (adev->rate_auto && client_no < VEC_SIZE(adev->sta_list)) { + client_t *clt = &adev->sta_list[client_no]; + u16 cur = stat->hostdata >> 16; + + if (clt && clt->rate_cur == cur) { + acx_l_handle_txrate_auto(adev, clt, + cur, /* intended rate */ + stat->rate, 0, /* actually used rate */ + stat->mac_status, /* error? */ + ACX_TX_URB_CNT - adev->tx_free); + } + } + goto next; + } + + if (packetsize > sizeof(rxbuffer_t)) { + printk("acx: packet exceeds max wlan " + "frame size (%d > %d). size=%d\n", + packetsize, (int) sizeof(rxbuffer_t), size); + if (ACX_DEBUG) + acx_dump_bytes(ptr, 16); + /* FIXME: put some real error-handling in here! */ + break; + } + + if (packetsize > remsize) { + /* frame truncation handling */ + if (acx_debug & L_USBRXTX) { + printk("need to truncate packet, " + "packetsize=%d remsize=%d " + "size=%d bytes:", + packetsize, remsize, size); + acx_dump_bytes(ptr, RXBUF_HDRSIZE); + } + memcpy(&adev->rxtruncbuf, ptr, remsize); + adev->rxtruncsize = remsize; + break; + } + + /* packetsize <= remsize */ + /* now handle the received data */ + acx_l_process_rxbuf(adev, ptr); +next: + ptr = (rxbuffer_t *)(((char *)ptr) + packetsize); + remsize -= packetsize; + if ((acx_debug & L_USBRXTX) && remsize) { + printk("more than one packet in buffer, " + "second packet hdr:"); + acx_dump_bytes(ptr, RXBUF_HDRSIZE); + } + } + +end_unlock: + acx_unlock(adev, flags); +/* end: */ + FN_EXIT0; +} + + +/*********************************************************************** +** acxusb_i_complete_tx() +** Inputs: +** urb -> pointer to USB request block +** regs -> pointer to register-buffer for syscalls (see asm/ptrace.h) +** +** This function is invoked upon termination of a USB transfer. +*/ +static void +acxusb_i_complete_tx(struct urb *urb) +{ + acx_device_t *adev; + usb_tx_t *tx; + unsigned long flags; + int txnum; + + FN_ENTER; + + BUG_ON(!urb->context); + + tx = (usb_tx_t *)urb->context; + adev = tx->adev; + + txnum = tx - adev->usb_tx; + + acx_lock(adev, flags); + + /* + * If the iface isn't up, we don't have any right + * to play with them. The urb may get unlinked. + */ + if (unlikely(!(adev->dev_state_mask & ACX_STATE_IFACE_UP))) { + log(L_USBRXTX, "tx: device is down, not doing anything\n"); + goto end_unlock; + } + + log(L_USBRXTX, "RETURN TX (%d): status=%d size=%d\n", + txnum, urb->status, urb->actual_length); + + /* handle USB transfer errors */ + switch (urb->status) { + case 0: /* No error */ + break; + case -ESHUTDOWN: + goto end_unlock; + break; + case -ECONNRESET: + goto end_unlock; + break; + /* FIXME: real error-handling code here please */ + default: + printk(KERN_ERR "acx: tx error, urb status=%d\n", urb->status); + /* FIXME: real error-handling code here please */ + } + + /* free the URB and check for more data */ + tx->busy = 0; + adev->tx_free++; + if ((adev->tx_free >= TX_START_QUEUE) + && (adev->status == ACX_STATUS_4_ASSOCIATED) + && (acx_queue_stopped(adev->ndev)) + ) { + log(L_BUF, "tx: wake queue (%u free txbufs)\n", + adev->tx_free); + acx_wake_queue(adev->ndev, NULL); + } + +end_unlock: + acx_unlock(adev, flags); +/* end: */ + FN_EXIT0; +} + + +/*************************************************************** +** acxusb_l_alloc_tx +** Actually returns a usb_tx_t* ptr +*/ +tx_t* +acxusb_l_alloc_tx(acx_device_t *adev) +{ + usb_tx_t *tx; + unsigned head; + + FN_ENTER; + + head = adev->tx_head; + do { + head = (head + 1) % ACX_TX_URB_CNT; + if (!adev->usb_tx[head].busy) { + log(L_USBRXTX, "allocated tx %d\n", head); + tx = &adev->usb_tx[head]; + tx->busy = 1; + adev->tx_free--; + /* Keep a few free descs between head and tail of tx ring. + ** It is not absolutely needed, just feels safer */ + if (adev->tx_free < TX_STOP_QUEUE) { + log(L_BUF, "tx: stop queue " + "(%u free txbufs)\n", adev->tx_free); + acx_stop_queue(adev->ndev, NULL); + } + goto end; + } + } while (likely(head!=adev->tx_head)); + tx = NULL; + printk_ratelimited("acx: tx buffers full\n"); +end: + adev->tx_head = head; + FN_EXIT0; + return (tx_t*)tx; +} + + +/*************************************************************** +** Used if alloc_tx()'ed buffer needs to be cancelled without doing tx +*/ +void +acxusb_l_dealloc_tx(tx_t *tx_opaque) +{ + usb_tx_t* tx = (usb_tx_t*)tx_opaque; + tx->busy = 0; +} + + +/*************************************************************** +*/ +void* +acxusb_l_get_txbuf(acx_device_t *adev, tx_t* tx_opaque) +{ + usb_tx_t* tx = (usb_tx_t*)tx_opaque; + return &tx->bulkout.data; +} + + +/*************************************************************** +** acxusb_l_tx_data +** +** Can be called from IRQ (rx -> (AP bridging or mgmt response) -> tx). +** Can be called from acx_i_start_xmit (data frames from net core). +*/ +void +acxusb_l_tx_data(acx_device_t *adev, tx_t* tx_opaque, int wlanpkt_len) +{ + struct usb_device *usbdev; + struct urb* txurb; + usb_tx_t* tx; + usb_txbuffer_t* txbuf; + client_t *clt; + wlan_hdr_t* whdr; + unsigned int outpipe; + int ucode, txnum; + + FN_ENTER; + + tx = ((usb_tx_t *)tx_opaque); + txurb = tx->urb; + txbuf = &tx->bulkout; + whdr = (wlan_hdr_t *)txbuf->data; + txnum = tx - adev->usb_tx; + + log(L_DEBUG, "using buf#%d free=%d len=%d\n", + txnum, adev->tx_free, wlanpkt_len); + + switch (adev->mode) { + case ACX_MODE_0_ADHOC: + case ACX_MODE_3_AP: + clt = acx_l_sta_list_get(adev, whdr->a1); + break; + case ACX_MODE_2_STA: + clt = adev->ap_client; + break; + default: /* ACX_MODE_OFF, ACX_MODE_MONITOR */ + clt = NULL; + break; + } + + if (unlikely(clt && !clt->rate_cur)) { + printk("acx: driver bug! bad ratemask\n"); + goto end; + } + + /* fill the USB transfer header */ + txbuf->desc = cpu_to_le16(USB_TXBUF_TXDESC); + txbuf->mpdu_len = cpu_to_le16(wlanpkt_len); + txbuf->queue_index = 1; + if (clt) { + txbuf->rate = clt->rate_100; + txbuf->hostdata = (clt - adev->sta_list) | (clt->rate_cur << 16); + } else { + txbuf->rate = adev->rate_bcast100; + txbuf->hostdata = ((u16)-1) | (adev->rate_bcast << 16); + } + txbuf->ctrl1 = DESC_CTL_FIRSTFRAG; + if (1 == adev->preamble_cur) + SET_BIT(txbuf->ctrl1, DESC_CTL_SHORT_PREAMBLE); + txbuf->ctrl2 = 0; + txbuf->data_len = cpu_to_le16(wlanpkt_len); + + if (unlikely(acx_debug & L_DATA)) { + printk("dump of bulk out urb:\n"); + acx_dump_bytes(txbuf, wlanpkt_len + USB_TXBUF_HDRSIZE); + } + + if (unlikely(txurb->status == -EINPROGRESS)) { + printk("acx: trying to submit tx urb while already in progress\n"); + } + + /* now schedule the USB transfer */ + usbdev = adev->usbdev; + outpipe = usb_sndbulkpipe(usbdev, adev->bulkoutep); + + usb_fill_bulk_urb(txurb, usbdev, outpipe, + txbuf, /* dataptr */ + wlanpkt_len + USB_TXBUF_HDRSIZE, /* size */ + acxusb_i_complete_tx, /* handler */ + tx /* handler param */ + ); + + txurb->transfer_flags = URB_ASYNC_UNLINK|URB_ZERO_PACKET; + ucode = usb_submit_urb(txurb, GFP_ATOMIC); + log(L_USBRXTX, "SUBMIT TX (%d): outpipe=0x%X buf=%p txsize=%d " + "rate=%u errcode=%d\n", txnum, outpipe, txbuf, + wlanpkt_len + USB_TXBUF_HDRSIZE, txbuf->rate, ucode); + + if (unlikely(ucode)) { + printk(KERN_ERR "acx: submit_urb() error=%d txsize=%d\n", + ucode, wlanpkt_len + USB_TXBUF_HDRSIZE); + + /* on error, just mark the frame as done and update + ** the statistics + */ + adev->stats.tx_errors++; + tx->busy = 0; + adev->tx_free++; + /* needed? if (adev->tx_free > TX_START_QUEUE) acx_wake_queue(...) */ + } +end: + FN_EXIT0; +} + + +/*********************************************************************** +*/ +static void +acxusb_i_set_rx_mode(struct net_device *ndev) +{ +} + + +/*********************************************************************** +*/ +#ifdef HAVE_TX_TIMEOUT +static void +acxusb_i_tx_timeout(struct net_device *ndev) +{ + acx_device_t *adev = ndev2adev(ndev); + unsigned long flags; + int i; + + FN_ENTER; + + acx_lock(adev, flags); + /* unlink the URBs */ + for (i = 0; i < ACX_TX_URB_CNT; i++) { + acxusb_unlink_urb(adev->usb_tx[i].urb); + adev->usb_tx[i].busy = 0; + } + adev->tx_free = ACX_TX_URB_CNT; + /* TODO: stats update */ + acx_unlock(adev, flags); + + FN_EXIT0; +} +#endif + + +/*********************************************************************** +** init_module() +** +** This function is invoked upon loading of the kernel module. +** It registers itself at the kernel's USB subsystem. +** +** Returns: Errorcode on failure, 0 on success +*/ +int __init +acxusb_e_init_module(void) +{ + log(L_INIT, "USB module " ACX_RELEASE " initialized, " + "probing for devices...\n"); + return usb_register(&acxusb_driver); +} + + + +/*********************************************************************** +** cleanup_module() +** +** This function is invoked as last step of the module unloading. It simply +** deregisters this module at the kernel's USB subsystem. +*/ +void __exit +acxusb_e_cleanup_module() +{ + usb_deregister(&acxusb_driver); +} + + +/*********************************************************************** +** DEBUG STUFF +*/ +#if ACX_DEBUG + +#ifdef UNUSED +static void +dump_device(struct usb_device *usbdev) +{ + int i; + struct usb_config_descriptor *cd; + + printk("acx device dump:\n"); + printk(" devnum: %d\n", usbdev->devnum); + printk(" speed: %d\n", usbdev->speed); + printk(" tt: 0x%X\n", (unsigned int)(usbdev->tt)); + printk(" ttport: %d\n", (unsigned int)(usbdev->ttport)); + printk(" toggle[0]: 0x%X toggle[1]: 0x%X\n", (unsigned int)(usbdev->toggle[0]), (unsigned int)(usbdev->toggle[1])); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) + /* This saw a change after 2.6.10 */ + printk(" ep_in wMaxPacketSize: "); + for (i = 0; i < 16; ++i) + if (usbdev->ep_in[i] != NULL) + printk("%d:%d ", i, usbdev->ep_in[i]->desc.wMaxPacketSize); + printk("\n"); + printk(" ep_out wMaxPacketSize: "); + for (i = 0; i < VEC_SIZE(usbdev->ep_out); ++i) + if (usbdev->ep_out[i] != NULL) + printk("%d:%d ", i, usbdev->ep_out[i]->desc.wMaxPacketSize); + printk("\n"); +#else + printk(" epmaxpacketin: "); + for (i = 0; i < 16; i++) + printk("%d ", usbdev->epmaxpacketin[i]); + printk("\n"); + printk(" epmaxpacketout: "); + for (i = 0; i < 16; i++) + printk("%d ", usbdev->epmaxpacketout[i]); + printk("\n"); +#endif + printk(" parent: 0x%X\n", (unsigned int)usbdev->parent); + printk(" bus: 0x%X\n", (unsigned int)usbdev->bus); +#ifdef NO_DATATYPE + printk(" configs: "); + for (i = 0; i < usbdev->descriptor.bNumConfigurations; i++) + printk("0x%X ", usbdev->config[i]); + printk("\n"); +#endif + printk(" actconfig: %p\n", usbdev->actconfig); + dump_device_descriptor(&usbdev->descriptor); + + cd = &usbdev->config->desc; + dump_config_descriptor(cd); +} + + +/*********************************************************************** +*/ +static void +dump_config_descriptor(struct usb_config_descriptor *cd) +{ + printk("Configuration Descriptor:\n"); + if (!cd) { + printk("NULL\n"); + return; + } + printk(" bLength: %d (0x%X)\n", cd->bLength, cd->bLength); + printk(" bDescriptorType: %d (0x%X)\n", cd->bDescriptorType, cd->bDescriptorType); + printk(" bNumInterfaces: %d (0x%X)\n", cd->bNumInterfaces, cd->bNumInterfaces); + printk(" bConfigurationValue: %d (0x%X)\n", cd->bConfigurationValue, cd->bConfigurationValue); + printk(" iConfiguration: %d (0x%X)\n", cd->iConfiguration, cd->iConfiguration); + printk(" bmAttributes: %d (0x%X)\n", cd->bmAttributes, cd->bmAttributes); + /* printk(" MaxPower: %d (0x%X)\n", cd->bMaxPower, cd->bMaxPower); */ +} + + +static void +dump_device_descriptor(struct usb_device_descriptor *dd) +{ + printk("Device Descriptor:\n"); + if (!dd) { + printk("NULL\n"); + return; + } + printk(" bLength: %d (0x%X)\n", dd->bLength, dd->bLength); + printk(" bDescriptortype: %d (0x%X)\n", dd->bDescriptorType, dd->bDescriptorType); + printk(" bcdUSB: %d (0x%X)\n", dd->bcdUSB, dd->bcdUSB); + printk(" bDeviceClass: %d (0x%X)\n", dd->bDeviceClass, dd->bDeviceClass); + printk(" bDeviceSubClass: %d (0x%X)\n", dd->bDeviceSubClass, dd->bDeviceSubClass); + printk(" bDeviceProtocol: %d (0x%X)\n", dd->bDeviceProtocol, dd->bDeviceProtocol); + printk(" bMaxPacketSize0: %d (0x%X)\n", dd->bMaxPacketSize0, dd->bMaxPacketSize0); + printk(" idVendor: %d (0x%X)\n", dd->idVendor, dd->idVendor); + printk(" idProduct: %d (0x%X)\n", dd->idProduct, dd->idProduct); + printk(" bcdDevice: %d (0x%X)\n", dd->bcdDevice, dd->bcdDevice); + printk(" iManufacturer: %d (0x%X)\n", dd->iManufacturer, dd->iManufacturer); + printk(" iProduct: %d (0x%X)\n", dd->iProduct, dd->iProduct); + printk(" iSerialNumber: %d (0x%X)\n", dd->iSerialNumber, dd->iSerialNumber); + printk(" bNumConfigurations: %d (0x%X)\n", dd->bNumConfigurations, dd->bNumConfigurations); +} +#endif /* UNUSED */ + +#endif /* ACX_DEBUG */ --- linux-2.6.27.orig/ubuntu/misc/wireless/acx/pci.c +++ linux-2.6.27/ubuntu/misc/wireless/acx/pci.c @@ -0,0 +1,4260 @@ +/*********************************************************************** +** Copyright (C) 2003 ACX100 Open Source Project +** +** The contents of this file are subject to the Mozilla Public +** License Version 1.1 (the "License"); you may not use this file +** except in compliance with the License. You may obtain a copy of +** the License at http://www.mozilla.org/MPL/ +** +** Software distributed under the License is distributed on an "AS +** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +** implied. See the License for the specific language governing +** rights and limitations under the License. +** +** Alternatively, the contents of this file may be used under the +** terms of the GNU Public License version 2 (the "GPL"), in which +** case the provisions of the GPL are applicable instead of the +** above. If you wish to allow the use of your version of this file +** only under the terms of the GPL and not to allow others to use +** your version of this file under the MPL, indicate your decision +** by deleting the provisions above and replace them with the notice +** and other provisions required by the GPL. If you do not delete +** the provisions above, a recipient may use your version of this +** file under either the MPL or the GPL. +** --------------------------------------------------------------------- +** Inquiries regarding the ACX100 Open Source Project can be +** made directly to: +** +** acx100-users@lists.sf.net +** http://acx100.sf.net +** --------------------------------------------------------------------- +*/ +#define ACX_PCI 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acx.h" + + +/*********************************************************************** +*/ +#define PCI_TYPE (PCI_USES_MEM | PCI_ADDR0 | PCI_NO_ACPI_WAKE) +#define PCI_ACX100_REGION1 0x01 +#define PCI_ACX100_REGION1_SIZE 0x1000 /* Memory size - 4K bytes */ +#define PCI_ACX100_REGION2 0x02 +#define PCI_ACX100_REGION2_SIZE 0x10000 /* Memory size - 64K bytes */ + +#define PCI_ACX111_REGION1 0x00 +#define PCI_ACX111_REGION1_SIZE 0x2000 /* Memory size - 8K bytes */ +#define PCI_ACX111_REGION2 0x01 +#define PCI_ACX111_REGION2_SIZE 0x20000 /* Memory size - 128K bytes */ + +/* Texas Instruments Vendor ID */ +#define PCI_VENDOR_ID_TI 0x104c + +/* ACX100 22Mb/s WLAN controller */ +#define PCI_DEVICE_ID_TI_TNETW1100A 0x8400 +#define PCI_DEVICE_ID_TI_TNETW1100B 0x8401 + +/* ACX111 54Mb/s WLAN controller */ +#define PCI_DEVICE_ID_TI_TNETW1130 0x9066 + +/* PCI Class & Sub-Class code, Network-'Other controller' */ +#define PCI_CLASS_NETWORK_OTHERS 0x0280 + +#define CARD_EEPROM_ID_SIZE 6 + +#ifndef PCI_D0 +/* From include/linux/pci.h */ +#define PCI_D0 0 +#define PCI_D1 1 +#define PCI_D2 2 +#define PCI_D3hot 3 +#define PCI_D3cold 4 +#define PCI_UNKNOWN 5 +#define PCI_POWER_ERROR -1 +#endif + + +/*********************************************************************** +*/ +static void acxpci_i_tx_timeout(struct net_device *ndev); +static irqreturn_t acxpci_i_interrupt(int irq, void *dev_id); +static void acxpci_i_set_multicast_list(struct net_device *ndev); + +static int acxpci_e_open(struct net_device *ndev); +static int acxpci_e_close(struct net_device *ndev); +static void acxpci_s_up(struct net_device *ndev); +static void acxpci_s_down(struct net_device *ndev); + + +/*********************************************************************** +** Register access +*/ + +/* Pick one */ +/* #define INLINE_IO static */ +#define INLINE_IO static inline + +INLINE_IO u32 +read_reg32(acx_device_t *adev, unsigned int offset) +{ +#if ACX_IO_WIDTH == 32 + return readl((u8 *)adev->iobase + adev->io[offset]); +#else + return readw((u8 *)adev->iobase + adev->io[offset]) + + (readw((u8 *)adev->iobase + adev->io[offset] + 2) << 16); +#endif +} + +INLINE_IO u16 +read_reg16(acx_device_t *adev, unsigned int offset) +{ + return readw((u8 *)adev->iobase + adev->io[offset]); +} + +INLINE_IO u8 +read_reg8(acx_device_t *adev, unsigned int offset) +{ + return readb((u8 *)adev->iobase + adev->io[offset]); +} + +INLINE_IO void +write_reg32(acx_device_t *adev, unsigned int offset, u32 val) +{ +#if ACX_IO_WIDTH == 32 + writel(val, (u8 *)adev->iobase + adev->io[offset]); +#else + writew(val & 0xffff, (u8 *)adev->iobase + adev->io[offset]); + writew(val >> 16, (u8 *)adev->iobase + adev->io[offset] + 2); +#endif +} + +INLINE_IO void +write_reg16(acx_device_t *adev, unsigned int offset, u16 val) +{ + writew(val, (u8 *)adev->iobase + adev->io[offset]); +} + +INLINE_IO void +write_reg8(acx_device_t *adev, unsigned int offset, u8 val) +{ + writeb(val, (u8 *)adev->iobase + adev->io[offset]); +} + +/* Handle PCI posting properly: + * Make sure that writes reach the adapter in case they require to be executed + * *before* the next write, by reading a random (and safely accessible) register. + * This call has to be made if there is no read following (which would flush the data + * to the adapter), yet the written data has to reach the adapter immediately. */ +INLINE_IO void +write_flush(acx_device_t *adev) +{ + /* readb(adev->iobase + adev->io[IO_ACX_INFO_MAILBOX_OFFS]); */ + /* faster version (accesses the first register, IO_ACX_SOFT_RESET, + * which should also be safe): */ + readb(adev->iobase); +} + +INLINE_IO int +adev_present(acx_device_t *adev) +{ + /* fast version (accesses the first register, IO_ACX_SOFT_RESET, + * which should be safe): */ + return readl(adev->iobase) != 0xffffffff; +} + + +/*********************************************************************** +*/ +static inline txdesc_t* +get_txdesc(acx_device_t *adev, int index) +{ + return (txdesc_t*) (((u8*)adev->txdesc_start) + index * adev->txdesc_size); +} + +static inline txdesc_t* +advance_txdesc(acx_device_t *adev, txdesc_t* txdesc, int inc) +{ + return (txdesc_t*) (((u8*)txdesc) + inc * adev->txdesc_size); +} + +static txhostdesc_t* +get_txhostdesc(acx_device_t *adev, txdesc_t* txdesc) +{ + int index = (u8*)txdesc - (u8*)adev->txdesc_start; + if (unlikely(ACX_DEBUG && (index % adev->txdesc_size))) { + printk("bad txdesc ptr %p\n", txdesc); + return NULL; + } + index /= adev->txdesc_size; + if (unlikely(ACX_DEBUG && (index >= TX_CNT))) { + printk("bad txdesc ptr %p\n", txdesc); + return NULL; + } + return &adev->txhostdesc_start[index*2]; +} + +static inline client_t* +get_txc(acx_device_t *adev, txdesc_t* txdesc) +{ + int index = (u8*)txdesc - (u8*)adev->txdesc_start; + if (unlikely(ACX_DEBUG && (index % adev->txdesc_size))) { + printk("bad txdesc ptr %p\n", txdesc); + return NULL; + } + index /= adev->txdesc_size; + if (unlikely(ACX_DEBUG && (index >= TX_CNT))) { + printk("bad txdesc ptr %p\n", txdesc); + return NULL; + } + return adev->txc[index]; +} + +static inline u16 +get_txr(acx_device_t *adev, txdesc_t* txdesc) +{ + int index = (u8*)txdesc - (u8*)adev->txdesc_start; + index /= adev->txdesc_size; + return adev->txr[index]; +} + +static inline void +put_txcr(acx_device_t *adev, txdesc_t* txdesc, client_t* c, u16 r111) +{ + int index = (u8*)txdesc - (u8*)adev->txdesc_start; + if (unlikely(ACX_DEBUG && (index % adev->txdesc_size))) { + printk("bad txdesc ptr %p\n", txdesc); + return; + } + index /= adev->txdesc_size; + if (unlikely(ACX_DEBUG && (index >= TX_CNT))) { + printk("bad txdesc ptr %p\n", txdesc); + return; + } + adev->txc[index] = c; + adev->txr[index] = r111; +} + + +/*********************************************************************** +** EEPROM and PHY read/write helpers +*/ +/*********************************************************************** +** acxpci_read_eeprom_byte +** +** Function called to read an octet in the EEPROM. +** +** This function is used by acxpci_e_probe to check if the +** connected card is a legal one or not. +** +** Arguments: +** adev ptr to acx_device structure +** addr address to read in the EEPROM +** charbuf ptr to a char. This is where the read octet +** will be stored +*/ +int +acxpci_read_eeprom_byte(acx_device_t *adev, u32 addr, u8 *charbuf) +{ + int result; + int count; + + write_reg32(adev, IO_ACX_EEPROM_CFG, 0); + write_reg32(adev, IO_ACX_EEPROM_ADDR, addr); + write_flush(adev); + write_reg32(adev, IO_ACX_EEPROM_CTL, 2); + + count = 0xffff; + while (read_reg16(adev, IO_ACX_EEPROM_CTL)) { + /* scheduling away instead of CPU burning loop + * doesn't seem to work here at all: + * awful delay, sometimes also failure. + * Doesn't matter anyway (only small delay). */ + if (unlikely(!--count)) { + printk("%s: timeout waiting for EEPROM read\n", + adev->ndev->name); + result = NOT_OK; + goto fail; + } + cpu_relax(); + } + + *charbuf = read_reg8(adev, IO_ACX_EEPROM_DATA); + log(L_DEBUG, "EEPROM at 0x%04X = 0x%02X\n", addr, *charbuf); + result = OK; + +fail: + return result; +} + + +/*********************************************************************** +** We don't lock hw accesses here since we never r/w eeprom in IRQ +** Note: this function sleeps only because of GFP_KERNEL alloc +*/ +#ifdef UNUSED +int +acxpci_s_write_eeprom(acx_device_t *adev, u32 addr, u32 len, const u8 *charbuf) +{ + u8 *data_verify = NULL; + unsigned long flags; + int count, i; + int result = NOT_OK; + u16 gpio_orig; + + printk("acx: WARNING! I would write to EEPROM now. " + "Since I really DON'T want to unless you know " + "what you're doing (THIS CODE WILL PROBABLY " + "NOT WORK YET!), I will abort that now. And " + "definitely make sure to make a " + "/proc/driver/acx_wlan0_eeprom backup copy first!!! " + "(the EEPROM content includes the PCI config header!! " + "If you kill important stuff, then you WILL " + "get in trouble and people DID get in trouble already)\n"); + return OK; + + FN_ENTER; + + data_verify = kmalloc(len, GFP_KERNEL); + if (!data_verify) { + goto end; + } + + /* first we need to enable the OE (EEPROM Output Enable) GPIO line + * to be able to write to the EEPROM. + * NOTE: an EEPROM writing success has been reported, + * but you probably have to modify GPIO_OUT, too, + * and you probably need to activate a different GPIO + * line instead! */ + gpio_orig = read_reg16(adev, IO_ACX_GPIO_OE); + write_reg16(adev, IO_ACX_GPIO_OE, gpio_orig & ~1); + write_flush(adev); + + /* ok, now start writing the data out */ + for (i = 0; i < len; i++) { + write_reg32(adev, IO_ACX_EEPROM_CFG, 0); + write_reg32(adev, IO_ACX_EEPROM_ADDR, addr + i); + write_reg32(adev, IO_ACX_EEPROM_DATA, *(charbuf + i)); + write_flush(adev); + write_reg32(adev, IO_ACX_EEPROM_CTL, 1); + + count = 0xffff; + while (read_reg16(adev, IO_ACX_EEPROM_CTL)) { + if (unlikely(!--count)) { + printk("WARNING, DANGER!!! " + "Timeout waiting for EEPROM write\n"); + goto end; + } + cpu_relax(); + } + } + + /* disable EEPROM writing */ + write_reg16(adev, IO_ACX_GPIO_OE, gpio_orig); + write_flush(adev); + + /* now start a verification run */ + for (i = 0; i < len; i++) { + write_reg32(adev, IO_ACX_EEPROM_CFG, 0); + write_reg32(adev, IO_ACX_EEPROM_ADDR, addr + i); + write_flush(adev); + write_reg32(adev, IO_ACX_EEPROM_CTL, 2); + + count = 0xffff; + while (read_reg16(adev, IO_ACX_EEPROM_CTL)) { + if (unlikely(!--count)) { + printk("timeout waiting for EEPROM read\n"); + goto end; + } + cpu_relax(); + } + + data_verify[i] = read_reg16(adev, IO_ACX_EEPROM_DATA); + } + + if (0 == memcmp(charbuf, data_verify, len)) + result = OK; /* read data matches, success */ + +end: + kfree(data_verify); + FN_EXIT1(result); + return result; +} +#endif /* UNUSED */ + + +/*********************************************************************** +** acxpci_s_read_phy_reg +** +** Messing with rx/tx disabling and enabling here +** (write_reg32(adev, IO_ACX_ENABLE, 0b000000xx)) kills traffic +*/ +int +acxpci_s_read_phy_reg(acx_device_t *adev, u32 reg, u8 *charbuf) +{ + int result = NOT_OK; + int count; + + FN_ENTER; + + write_reg32(adev, IO_ACX_PHY_ADDR, reg); + write_flush(adev); + write_reg32(adev, IO_ACX_PHY_CTL, 2); + + count = 0xffff; + while (read_reg32(adev, IO_ACX_PHY_CTL)) { + /* scheduling away instead of CPU burning loop + * doesn't seem to work here at all: + * awful delay, sometimes also failure. + * Doesn't matter anyway (only small delay). */ + if (unlikely(!--count)) { + printk("%s: timeout waiting for phy read\n", + adev->ndev->name); + *charbuf = 0; + goto fail; + } + cpu_relax(); + } + + log(L_DEBUG, "count was %u\n", count); + *charbuf = read_reg8(adev, IO_ACX_PHY_DATA); + + log(L_DEBUG, "radio PHY at 0x%04X = 0x%02X\n", *charbuf, reg); + result = OK; + goto fail; /* silence compiler warning */ +fail: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +*/ +int +acxpci_s_write_phy_reg(acx_device_t *adev, u32 reg, u8 value) +{ + FN_ENTER; + + /* mprusko said that 32bit accesses result in distorted sensitivity + * on his card. Unconfirmed, looks like it's not true (most likely since we + * now properly flush writes). */ + write_reg32(adev, IO_ACX_PHY_DATA, value); + write_reg32(adev, IO_ACX_PHY_ADDR, reg); + write_flush(adev); + write_reg32(adev, IO_ACX_PHY_CTL, 1); + write_flush(adev); + log(L_DEBUG, "radio PHY write 0x%02X at 0x%04X\n", value, reg); + + FN_EXIT1(OK); + return OK; +} + + +#define NO_AUTO_INCREMENT 1 + +/*********************************************************************** +** acxpci_s_write_fw +** +** Write the firmware image into the card. +** +** Arguments: +** adev wlan device structure +** fw_image firmware image. +** +** Returns: +** 1 firmware image corrupted +** 0 success +*/ +static int +acxpci_s_write_fw(acx_device_t *adev, const firmware_image_t *fw_image, u32 offset) +{ + int len, size; + u32 sum, v32; + /* we skip the first four bytes which contain the control sum */ + const u8 *p = (u8*)fw_image + 4; + + /* start the image checksum by adding the image size value */ + sum = p[0]+p[1]+p[2]+p[3]; + p += 4; + + write_reg32(adev, IO_ACX_SLV_END_CTL, 0); + +#if NO_AUTO_INCREMENT + write_reg32(adev, IO_ACX_SLV_MEM_CTL, 0); /* use basic mode */ +#else + write_reg32(adev, IO_ACX_SLV_MEM_CTL, 1); /* use autoincrement mode */ + write_reg32(adev, IO_ACX_SLV_MEM_ADDR, offset); /* configure start address */ + write_flush(adev); +#endif + + len = 0; + size = le32_to_cpu(fw_image->size) & (~3); + + while (likely(len < size)) { + v32 = be32_to_cpu(*(u32*)p); + sum += p[0]+p[1]+p[2]+p[3]; + p += 4; + len += 4; + +#if NO_AUTO_INCREMENT + write_reg32(adev, IO_ACX_SLV_MEM_ADDR, offset + len - 4); + write_flush(adev); +#endif + write_reg32(adev, IO_ACX_SLV_MEM_DATA, v32); + } + + log(L_DEBUG, "firmware written, size:%d sum1:%x sum2:%x\n", + size, sum, le32_to_cpu(fw_image->chksum)); + + /* compare our checksum with the stored image checksum */ + return (sum != le32_to_cpu(fw_image->chksum)); +} + + +/*********************************************************************** +** acxpci_s_validate_fw +** +** Compare the firmware image given with +** the firmware image written into the card. +** +** Arguments: +** adev wlan device structure +** fw_image firmware image. +** +** Returns: +** NOT_OK firmware image corrupted or not correctly written +** OK success +*/ +static int +acxpci_s_validate_fw(acx_device_t *adev, const firmware_image_t *fw_image, + u32 offset) +{ + u32 sum, v32, w32; + int len, size; + int result = OK; + /* we skip the first four bytes which contain the control sum */ + const u8 *p = (u8*)fw_image + 4; + + /* start the image checksum by adding the image size value */ + sum = p[0]+p[1]+p[2]+p[3]; + p += 4; + + write_reg32(adev, IO_ACX_SLV_END_CTL, 0); + +#if NO_AUTO_INCREMENT + write_reg32(adev, IO_ACX_SLV_MEM_CTL, 0); /* use basic mode */ +#else + write_reg32(adev, IO_ACX_SLV_MEM_CTL, 1); /* use autoincrement mode */ + write_reg32(adev, IO_ACX_SLV_MEM_ADDR, offset); /* configure start address */ +#endif + + len = 0; + size = le32_to_cpu(fw_image->size) & (~3); + + while (likely(len < size)) { + v32 = be32_to_cpu(*(u32*)p); + p += 4; + len += 4; + +#if NO_AUTO_INCREMENT + write_reg32(adev, IO_ACX_SLV_MEM_ADDR, offset + len - 4); +#endif + w32 = read_reg32(adev, IO_ACX_SLV_MEM_DATA); + + if (unlikely(w32 != v32)) { + printk("acx: FATAL: firmware upload: " + "data parts at offset %d don't match (0x%08X vs. 0x%08X)! " + "I/O timing issues or defective memory, with DWL-xx0+? " + "ACX_IO_WIDTH=16 may help. Please report\n", + len, v32, w32); + result = NOT_OK; + break; + } + + sum += (u8)w32 + (u8)(w32>>8) + (u8)(w32>>16) + (u8)(w32>>24); + } + + /* sum control verification */ + if (result != NOT_OK) { + if (sum != le32_to_cpu(fw_image->chksum)) { + printk("acx: FATAL: firmware upload: " + "checksums don't match!\n"); + result = NOT_OK; + } + } + + return result; +} + +struct fw_match { + unsigned short vendor; + unsigned short device; + unsigned short subvendor; + unsigned short subdevice; + const char *verstr; + int announced; +}; + +/* NOTE: This is NOT the module device table. We're just abusing the + * pci_device_id struct for our own purposes */ +static struct fw_match fw_ver_table[] = { + { /* Abocom WG24500, reported by Franz Pletz */ + .vendor = PCI_VENDOR_ID_TI, + .device = PCI_DEVICE_ID_TI_TNETW1130, + .subvendor = 0x13d1, + .subdevice = 0xab80, + .verstr = "1.2.0.30", + }, + { /* Texas Instruments ACX 111 54Mbps Wireless Interface */ + .vendor = PCI_VENDOR_ID_TI, + .device = PCI_DEVICE_ID_TI_TNETW1130, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .verstr = "1.2.1.34", + }, + { 0 } +}; + +#define PCI_MATCH(a,b) (a == b || a == (unsigned short)PCI_ANY_ID) + +/* Returns an alternate version of the firmware for specific devices. The + * above table will _always_ be overriden by module param. */ +static const char *get_firmware_ver(struct pci_dev *dev) +{ + struct fw_match *dev_match; + + if (!dev || strcmp(firmware_ver, "default")) + goto use_default; + + for (dev_match = fw_ver_table; dev_match->vendor; dev_match++) { + if (PCI_MATCH(dev_match->vendor, dev->vendor) && + PCI_MATCH(dev_match->device, dev->device) && + PCI_MATCH(dev_match->subvendor, dev->subsystem_vendor) && + PCI_MATCH(dev_match->subdevice, dev->subsystem_device)) + return dev_match->verstr; + } + +use_default: + return firmware_ver; +} + + +/*********************************************************************** +** acxpci_s_upload_fw +** +** Called from acx_reset_dev +*/ +static int +acxpci_s_upload_fw(acx_device_t *adev) +{ + firmware_image_t *fw_image = NULL; + int res = NOT_OK; + int try; + u32 file_size; + char filename[256]; + + FN_ENTER; + + printk(KERN_INFO "acx: loading firmware for acx1%02d chipset with radio" + " ID %02X\n", IS_ACX111(adev)*111, adev->radio_type); + + /* Try combined, then main image */ + adev->need_radio_fw = 0; + snprintf(filename, sizeof(filename), "acx/%s/tiacx1%02dc%02X", + get_firmware_ver(adev->pdev), + IS_ACX111(adev)*11, adev->radio_type); + + fw_image = acx_s_read_fw(&adev->pdev->dev, filename, &file_size); + if (!fw_image) { + adev->need_radio_fw = 1; + filename[strlen(filename) - 3] = '\0'; + fw_image = acx_s_read_fw(&adev->pdev->dev, filename, &file_size); + if (!fw_image) { + FN_EXIT1(NOT_OK); + return NOT_OK; + } + } + + for (try = 1; try <= 5; try++) { + res = acxpci_s_write_fw(adev, fw_image, 0); + log(L_DEBUG|L_INIT, "acx_write_fw (main/combined): %d\n", res); + if (OK == res) { + res = acxpci_s_validate_fw(adev, fw_image, 0); + log(L_DEBUG|L_INIT, "acx_validate_fw " + "(main/combined): %d\n", res); + } + + if (OK == res) { + SET_BIT(adev->dev_state_mask, ACX_STATE_FW_LOADED); + break; + } + printk("acx: firmware upload attempt #%d FAILED, " + "retrying...\n", try); + acx_s_msleep(1000); /* better wait for a while... */ + } + + vfree(fw_image); + + FN_EXIT1(res); + return res; +} + + +/*********************************************************************** +** acxpci_s_upload_radio +** +** Uploads the appropriate radio module firmware into the card. +*/ +int +acxpci_s_upload_radio(acx_device_t *adev) +{ + acx_ie_memmap_t mm; + firmware_image_t *radio_image; + acx_cmd_radioinit_t radioinit; + int res = NOT_OK; + int try; + u32 offset; + u32 size; + char filename[256]; + + if (!adev->need_radio_fw) return OK; + + FN_ENTER; + + printk(KERN_INFO "acx: loading radio image for radio %02X\n", + adev->radio_type); + + acx_s_interrogate(adev, &mm, ACX1xx_IE_MEMORY_MAP); + offset = le32_to_cpu(mm.CodeEnd); + + snprintf(filename, sizeof(filename), "acx/%s/tiacx1%02dr%02X", + get_firmware_ver(adev->pdev), IS_ACX111(adev)*11, + adev->radio_type); + radio_image = acx_s_read_fw(&adev->pdev->dev, filename, &size); + if (!radio_image) { + printk("acx: can't load radio module '%s'\n", filename); + goto fail; + } + + acx_s_issue_cmd(adev, ACX1xx_CMD_SLEEP, NULL, 0); + + for (try = 1; try <= 5; try++) { + res = acxpci_s_write_fw(adev, radio_image, offset); + log(L_DEBUG|L_INIT, "acx_write_fw (radio): %d\n", res); + if (OK == res) { + res = acxpci_s_validate_fw(adev, radio_image, offset); + log(L_DEBUG|L_INIT, "acx_validate_fw (radio): %d\n", res); + } + + if (OK == res) + break; + printk("acx: radio firmware upload attempt #%d FAILED, " + "retrying...\n", try); + acx_s_msleep(1000); /* better wait for a while... */ + } + + acx_s_issue_cmd(adev, ACX1xx_CMD_WAKE, NULL, 0); + radioinit.offset = cpu_to_le32(offset); + /* no endian conversion needed, remains in card CPU area: */ + radioinit.len = radio_image->size; + + vfree(radio_image); + + if (OK != res) + goto fail; + + /* will take a moment so let's have a big timeout */ + acx_s_issue_cmd_timeo(adev, ACX1xx_CMD_RADIOINIT, + &radioinit, sizeof(radioinit), CMD_TIMEOUT_MS(1000)); + + res = acx_s_interrogate(adev, &mm, ACX1xx_IE_MEMORY_MAP); +fail: + FN_EXIT1(res); + return res; +} + + +/*********************************************************************** +** acxpci_l_reset_mac +** +** MAC will be reset +** Call context: reset_dev +*/ +static void +acxpci_l_reset_mac(acx_device_t *adev) +{ + u16 temp; + + FN_ENTER; + + /* halt eCPU */ + temp = read_reg16(adev, IO_ACX_ECPU_CTRL) | 0x1; + write_reg16(adev, IO_ACX_ECPU_CTRL, temp); + + /* now do soft reset of eCPU, set bit */ + temp = read_reg16(adev, IO_ACX_SOFT_RESET) | 0x1; + log(L_DEBUG, "%s: enable soft reset...\n", __func__); + write_reg16(adev, IO_ACX_SOFT_RESET, temp); + write_flush(adev); + + /* now clear bit again: deassert eCPU reset */ + log(L_DEBUG, "%s: disable soft reset and go to init mode...\n", __func__); + write_reg16(adev, IO_ACX_SOFT_RESET, temp & ~0x1); + + /* now start a burst read from initial EEPROM */ + temp = read_reg16(adev, IO_ACX_EE_START) | 0x1; + write_reg16(adev, IO_ACX_EE_START, temp); + write_flush(adev); + + FN_EXIT0; +} + + +/*********************************************************************** +** acxpci_s_verify_init +*/ +static int +acxpci_s_verify_init(acx_device_t *adev) +{ + int result = NOT_OK; + unsigned long timeout; + + FN_ENTER; + + timeout = jiffies + 2*HZ; + for (;;) { + u16 irqstat = read_reg16(adev, IO_ACX_IRQ_STATUS_NON_DES); + if (irqstat & HOST_INT_FCS_THRESHOLD) { + result = OK; + write_reg16(adev, IO_ACX_IRQ_ACK, HOST_INT_FCS_THRESHOLD); + break; + } + if (time_after(jiffies, timeout)) + break; + /* Init may take up to ~0.5 sec total */ + acx_s_msleep(50); + } + + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** A few low-level helpers +** +** Note: these functions are not protected by lock +** and thus are never allowed to be called from IRQ. +** Also they must not race with fw upload which uses same hw regs +*/ + +/*********************************************************************** +** acxpci_write_cmd_type_status +*/ + +static inline void +acxpci_write_cmd_type_status(acx_device_t *adev, u16 type, u16 status) +{ + writel(type | (status << 16), adev->cmd_area); + write_flush(adev); +} + + +/*********************************************************************** +** acxpci_read_cmd_type_status +*/ +static u32 +acxpci_read_cmd_type_status(acx_device_t *adev) +{ + u32 cmd_type, cmd_status; + + cmd_type = readl(adev->cmd_area); + cmd_status = (cmd_type >> 16); + cmd_type = (u16)cmd_type; + + log(L_CTL, "cmd_type:%04X cmd_status:%04X [%s]\n", + cmd_type, cmd_status, + acx_cmd_status_str(cmd_status)); + + return cmd_status; +} + + +/*********************************************************************** +** acxpci_s_reset_dev +** +** Arguments: +** netdevice that contains the adev variable +** Returns: +** NOT_OK on fail +** OK on success +** Side effects: +** device is hard reset +** Call context: +** acxpci_e_probe +** Comment: +** This resets the device using low level hardware calls +** as well as uploads and verifies the firmware to the card +*/ + +static inline void +init_mboxes(acx_device_t *adev) +{ + u32 cmd_offs, info_offs; + + cmd_offs = read_reg32(adev, IO_ACX_CMD_MAILBOX_OFFS); + info_offs = read_reg32(adev, IO_ACX_INFO_MAILBOX_OFFS); + adev->cmd_area = (u8 *)adev->iobase2 + cmd_offs; + adev->info_area = (u8 *)adev->iobase2 + info_offs; + log(L_DEBUG, "iobase2=%p\n" + "cmd_mbox_offset=%X cmd_area=%p\n" + "info_mbox_offset=%X info_area=%p\n", + adev->iobase2, + cmd_offs, adev->cmd_area, + info_offs, adev->info_area); +} + + +static inline void +read_eeprom_area(acx_device_t *adev) +{ +#if ACX_DEBUG > 1 + int offs; + u8 tmp; + + for (offs = 0x8c; offs < 0xb9; offs++) + acxpci_read_eeprom_byte(adev, offs, &tmp); +#endif +} + + +static int +acxpci_s_reset_dev(acx_device_t *adev) +{ + const char* msg = ""; + unsigned long flags; + int result = NOT_OK; + u16 hardware_info; + u16 ecpu_ctrl; + int count; + + FN_ENTER; + + /* reset the device to make sure the eCPU is stopped + * to upload the firmware correctly */ + + acx_lock(adev, flags); + + acxpci_l_reset_mac(adev); + + ecpu_ctrl = read_reg16(adev, IO_ACX_ECPU_CTRL) & 1; + if (!ecpu_ctrl) { + msg = "eCPU is already running. "; + goto end_unlock; + } + +#ifdef WE_DONT_NEED_THAT_DO_WE + if (read_reg16(adev, IO_ACX_SOR_CFG) & 2) { + /* eCPU most likely means "embedded CPU" */ + msg = "eCPU did not start after boot from flash. "; + goto end_unlock; + } + + /* check sense on reset flags */ + if (read_reg16(adev, IO_ACX_SOR_CFG) & 0x10) { + printk("%s: eCPU did not start after boot (SOR), " + "is this fatal?\n", adev->ndev->name); + } +#endif + /* scan, if any, is stopped now, setting corresponding IRQ bit */ + adev->irq_status |= HOST_INT_SCAN_COMPLETE; + + acx_unlock(adev, flags); + + /* need to know radio type before fw load */ + /* Need to wait for arrival of this information in a loop, + * most probably since eCPU runs some init code from EEPROM + * (started burst read in reset_mac()) which also + * sets the radio type ID */ + + count = 0xffff; + do { + hardware_info = read_reg16(adev, IO_ACX_EEPROM_INFORMATION); + if (!--count) { + msg = "eCPU didn't indicate radio type"; + goto end_fail; + } + cpu_relax(); + } while (!(hardware_info & 0xff00)); /* radio type still zero? */ + + /* printk("DEBUG: count %d\n", count); */ + adev->form_factor = hardware_info & 0xff; + adev->radio_type = hardware_info >> 8; + + /* load the firmware */ + if (OK != acxpci_s_upload_fw(adev)) + goto end_fail; + + /* acx_s_msleep(10); this one really shouldn't be required */ + + /* now start eCPU by clearing bit */ + write_reg16(adev, IO_ACX_ECPU_CTRL, ecpu_ctrl & ~0x1); + log(L_DEBUG, "booted eCPU up and waiting for completion...\n"); + + /* wait for eCPU bootup */ + if (OK != acxpci_s_verify_init(adev)) { + msg = "timeout waiting for eCPU. "; + goto end_fail; + } + log(L_DEBUG, "eCPU has woken up, card is ready to be configured\n"); + + init_mboxes(adev); + acxpci_write_cmd_type_status(adev, 0, 0); + + /* test that EEPROM is readable */ + read_eeprom_area(adev); + + result = OK; + goto end; + +/* Finish error message. Indicate which function failed */ +end_unlock: + acx_unlock(adev, flags); +end_fail: + printk("acx: %sreset_dev() FAILED\n", msg); +end: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acxpci_s_issue_cmd_timeo +** +** Sends command to fw, extract result +** +** NB: we do _not_ take lock inside, so be sure to not touch anything +** which may interfere with IRQ handler operation +** +** TODO: busy wait is a bit silly, so: +** 1) stop doing many iters - go to sleep after first +** 2) go to waitqueue based approach: wait, not poll! +*/ +#undef FUNC +#define FUNC "issue_cmd" + +#if !ACX_DEBUG +int +acxpci_s_issue_cmd_timeo( + acx_device_t *adev, + unsigned int cmd, + void *buffer, + unsigned buflen, + unsigned cmd_timeout) +{ +#else +int +acxpci_s_issue_cmd_timeo_debug( + acx_device_t *adev, + unsigned cmd, + void *buffer, + unsigned buflen, + unsigned cmd_timeout, + const char* cmdstr) +{ + unsigned long start = jiffies; +#endif + const char *devname; + unsigned counter; + u16 irqtype; + u16 cmd_status; + unsigned long timeout; + + FN_ENTER; + + devname = adev->ndev->name; + if (!devname || !devname[0] || devname[4]=='%') + devname = "acx"; + + log(L_CTL, FUNC"(cmd:%s,buflen:%u,timeout:%ums,type:0x%04X)\n", + cmdstr, buflen, cmd_timeout, + buffer ? le16_to_cpu(((acx_ie_generic_t *)buffer)->type) : -1); + + if (!(adev->dev_state_mask & ACX_STATE_FW_LOADED)) { + printk("%s: "FUNC"(): firmware is not loaded yet, " + "cannot execute commands!\n", devname); + goto bad; + } + + if ((acx_debug & L_DEBUG) && (cmd != ACX1xx_CMD_INTERROGATE)) { + printk("input buffer (len=%u):\n", buflen); + acx_dump_bytes(buffer, buflen); + } + + /* wait for firmware to become idle for our command submission */ + timeout = HZ/5; + counter = (timeout * 1000 / HZ) - 1; /* in ms */ + timeout += jiffies; + do { + cmd_status = acxpci_read_cmd_type_status(adev); + /* Test for IDLE state */ + if (!cmd_status) + break; + if (counter % 8 == 0) { + if (time_after(jiffies, timeout)) { + counter = 0; + break; + } + /* we waited 8 iterations, no luck. Sleep 8 ms */ + acx_s_msleep(8); + } + } while (likely(--counter)); + + if (!counter) { + /* the card doesn't get idle, we're in trouble */ + printk("%s: "FUNC"(): cmd_status is not IDLE: 0x%04X!=0\n", + devname, cmd_status); + goto bad; + } else if (counter < 190) { /* if waited >10ms... */ + log(L_CTL|L_DEBUG, FUNC"(): waited for IDLE %dms. " + "Please report\n", 199 - counter); + } + + /* now write the parameters of the command if needed */ + if (buffer && buflen) { + /* if it's an INTERROGATE command, just pass the length + * of parameters to read, as data */ +#if CMD_DISCOVERY + if (cmd == ACX1xx_CMD_INTERROGATE) + memset_io(adev->cmd_area + 4, 0xAA, buflen); +#endif + /* adev->cmd_area points to PCI device's memory, not to RAM! */ + memcpy_toio(adev->cmd_area + 4, buffer, + (cmd == ACX1xx_CMD_INTERROGATE) ? 4 : buflen); + } + /* now write the actual command type */ + acxpci_write_cmd_type_status(adev, cmd, 0); + /* execute command */ + write_reg16(adev, IO_ACX_INT_TRIG, INT_TRIG_CMD); + write_flush(adev); + + /* wait for firmware to process command */ + + /* Ensure nonzero and not too large timeout. + ** Also converts e.g. 100->99, 200->199 + ** which is nice but not essential */ + cmd_timeout = (cmd_timeout-1) | 1; + if (unlikely(cmd_timeout > 1199)) + cmd_timeout = 1199; + /* clear CMD_COMPLETE bit. can be set only by IRQ handler: */ + adev->irq_status &= ~HOST_INT_CMD_COMPLETE; + + /* we schedule away sometimes (timeout can be large) */ + counter = cmd_timeout; + timeout = jiffies + cmd_timeout * HZ / 1000; + do { + if (!adev->irqs_active) { /* IRQ disabled: poll */ + irqtype = read_reg16(adev, IO_ACX_IRQ_STATUS_NON_DES); + if (irqtype & HOST_INT_CMD_COMPLETE) { + write_reg16(adev, IO_ACX_IRQ_ACK, + HOST_INT_CMD_COMPLETE); + break; + } + } else { /* Wait when IRQ will set the bit */ + irqtype = adev->irq_status; + if (irqtype & HOST_INT_CMD_COMPLETE) + break; + } + + if (counter % 8 == 0) { + if (time_after(jiffies, timeout)) { + counter = 0; + break; + } + /* we waited 8 iterations, no luck. Sleep 8 ms */ + acx_s_msleep(8); + } + } while (likely(--counter)); + + /* save state for debugging */ + cmd_status = acxpci_read_cmd_type_status(adev); + + /* put the card in IDLE state */ + acxpci_write_cmd_type_status(adev, 0, 0); + + if (!counter) { /* timed out! */ + printk("%s: "FUNC"(): timed out %s for CMD_COMPLETE. " + "irq bits:0x%04X irq_status:0x%04X timeout:%dms " + "cmd_status:%d (%s)\n", + devname, (adev->irqs_active) ? "waiting" : "polling", + irqtype, adev->irq_status, cmd_timeout, + cmd_status, acx_cmd_status_str(cmd_status)); + goto bad; + } else if (cmd_timeout - counter > 30) { /* if waited >30ms... */ + log(L_CTL|L_DEBUG, FUNC"(): %s for CMD_COMPLETE %dms. " + "count:%d. Please report\n", + (adev->irqs_active) ? "waited" : "polled", + cmd_timeout - counter, counter); + } + + if (1 != cmd_status) { /* it is not a 'Success' */ + printk("%s: "FUNC"(): cmd_status is not SUCCESS: %d (%s). " + "Took %dms of %d\n", + devname, cmd_status, acx_cmd_status_str(cmd_status), + cmd_timeout - counter, cmd_timeout); + /* zero out result buffer + * WARNING: this will trash stack in case of illegally large input + * length! */ + if (buffer && buflen) + memset(buffer, 0, buflen); + goto bad; + } + + /* read in result parameters if needed */ + if (buffer && buflen && (cmd == ACX1xx_CMD_INTERROGATE)) { + /* adev->cmd_area points to PCI device's memory, not to RAM! */ + memcpy_fromio(buffer, adev->cmd_area + 4, buflen); + if (acx_debug & L_DEBUG) { + printk("output buffer (len=%u): ", buflen); + acx_dump_bytes(buffer, buflen); + } + } +/* ok: */ + log(L_CTL, FUNC"(%s): took %ld jiffies to complete\n", + cmdstr, jiffies - start); + FN_EXIT1(OK); + return OK; + +bad: + /* Give enough info so that callers can avoid + ** printing their own diagnostic messages */ +#if ACX_DEBUG + printk("%s: "FUNC"(cmd:%s) FAILED\n", devname, cmdstr); +#else + printk("%s: "FUNC"(cmd:0x%04X) FAILED\n", devname, cmd); +#endif + dump_stack(); + FN_EXIT1(NOT_OK); + return NOT_OK; +} + + +/*********************************************************************** +*/ +#ifdef NONESSENTIAL_FEATURES +typedef struct device_id { + unsigned char id[6]; + char *descr; + char *type; +} device_id_t; + +static const device_id_t +device_ids[] = +{ + { + {'G', 'l', 'o', 'b', 'a', 'l'}, + NULL, + NULL, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + "uninitialized", + "SpeedStream SS1021 or Gigafast WF721-AEX" + }, + { + {0x80, 0x81, 0x82, 0x83, 0x84, 0x85}, + "non-standard", + "DrayTek Vigor 520" + }, + { + {'?', '?', '?', '?', '?', '?'}, + "non-standard", + "Level One WPC-0200" + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + "empty", + "DWL-650+ variant" + } +}; + +static void +acx_show_card_eeprom_id(acx_device_t *adev) +{ + unsigned char buffer[CARD_EEPROM_ID_SIZE]; + int i; + + memset(&buffer, 0, CARD_EEPROM_ID_SIZE); + /* use direct EEPROM access */ + for (i = 0; i < CARD_EEPROM_ID_SIZE; i++) { + if (OK != acxpci_read_eeprom_byte(adev, + ACX100_EEPROM_ID_OFFSET + i, + &buffer[i])) { + printk("acx: reading EEPROM FAILED\n"); + break; + } + } + + for (i = 0; i < VEC_SIZE(device_ids); i++) { + if (!memcmp(&buffer, device_ids[i].id, CARD_EEPROM_ID_SIZE)) { + if (device_ids[i].descr) { + printk("acx: EEPROM card ID string check " + "found %s card ID: is this %s?\n", + device_ids[i].descr, device_ids[i].type); + } + break; + } + } + if (i == VEC_SIZE(device_ids)) { + printk("acx: EEPROM card ID string check found " + "unknown card: expected 'Global', got '%.*s\'. " + "Please report\n", CARD_EEPROM_ID_SIZE, buffer); + } +} +#endif /* NONESSENTIAL_FEATURES */ + + +/*********************************************************************** +** acxpci_free_desc_queues +** +** Releases the queues that have been allocated, the +** others have been initialised to NULL so this +** function can be used if only part of the queues were allocated. +*/ + +static inline void +free_coherent(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + dma_free_coherent(hwdev == NULL ? NULL : &hwdev->dev, + size, vaddr, dma_handle); +} + +void +acxpci_free_desc_queues(acx_device_t *adev) +{ +#define ACX_FREE_QUEUE(size, ptr, phyaddr) \ + if (ptr) { \ + free_coherent(0, size, ptr, phyaddr); \ + ptr = NULL; \ + size = 0; \ + } + + FN_ENTER; + + ACX_FREE_QUEUE(adev->txhostdesc_area_size, adev->txhostdesc_start, adev->txhostdesc_startphy); + ACX_FREE_QUEUE(adev->txbuf_area_size, adev->txbuf_start, adev->txbuf_startphy); + + adev->txdesc_start = NULL; + + ACX_FREE_QUEUE(adev->rxhostdesc_area_size, adev->rxhostdesc_start, adev->rxhostdesc_startphy); + ACX_FREE_QUEUE(adev->rxbuf_area_size, adev->rxbuf_start, adev->rxbuf_startphy); + + adev->rxdesc_start = NULL; + + FN_EXIT0; +} + + +/*********************************************************************** +** acxpci_s_delete_dma_regions +*/ +static void +acxpci_s_delete_dma_regions(acx_device_t *adev) +{ + unsigned long flags; + + FN_ENTER; + /* disable radio Tx/Rx. Shouldn't we use the firmware commands + * here instead? Or are we that much down the road that it's no + * longer possible here? */ + write_reg16(adev, IO_ACX_ENABLE, 0); + + acx_s_msleep(100); + + acx_lock(adev, flags); + acxpci_free_desc_queues(adev); + acx_unlock(adev, flags); + + FN_EXIT0; +} + + +/*********************************************************************** +** acxpci_e_probe +** +** Probe routine called when a PCI device w/ matching ID is found. +** Here's the sequence: +** - Allocate the PCI resources. +** - Read the PCMCIA attribute memory to make sure we have a WLAN card +** - Reset the MAC +** - Initialize the dev and wlan data +** - Initialize the MAC +** +** pdev - ptr to pci device structure containing info about pci configuration +** id - ptr to the device id entry that matched this device +*/ +static const u16 +IO_ACX100[] = +{ + 0x0000, /* IO_ACX_SOFT_RESET */ + + 0x0014, /* IO_ACX_SLV_MEM_ADDR */ + 0x0018, /* IO_ACX_SLV_MEM_DATA */ + 0x001c, /* IO_ACX_SLV_MEM_CTL */ + 0x0020, /* IO_ACX_SLV_END_CTL */ + + 0x0034, /* IO_ACX_FEMR */ + + 0x007c, /* IO_ACX_INT_TRIG */ + 0x0098, /* IO_ACX_IRQ_MASK */ + 0x00a4, /* IO_ACX_IRQ_STATUS_NON_DES */ + 0x00a8, /* IO_ACX_IRQ_STATUS_CLEAR */ + 0x00ac, /* IO_ACX_IRQ_ACK */ + 0x00b0, /* IO_ACX_HINT_TRIG */ + + 0x0104, /* IO_ACX_ENABLE */ + + 0x0250, /* IO_ACX_EEPROM_CTL */ + 0x0254, /* IO_ACX_EEPROM_ADDR */ + 0x0258, /* IO_ACX_EEPROM_DATA */ + 0x025c, /* IO_ACX_EEPROM_CFG */ + + 0x0268, /* IO_ACX_PHY_ADDR */ + 0x026c, /* IO_ACX_PHY_DATA */ + 0x0270, /* IO_ACX_PHY_CTL */ + + 0x0290, /* IO_ACX_GPIO_OE */ + + 0x0298, /* IO_ACX_GPIO_OUT */ + + 0x02a4, /* IO_ACX_CMD_MAILBOX_OFFS */ + 0x02a8, /* IO_ACX_INFO_MAILBOX_OFFS */ + 0x02ac, /* IO_ACX_EEPROM_INFORMATION */ + + 0x02d0, /* IO_ACX_EE_START */ + 0x02d4, /* IO_ACX_SOR_CFG */ + 0x02d8 /* IO_ACX_ECPU_CTRL */ +}; + +static const u16 +IO_ACX111[] = +{ + 0x0000, /* IO_ACX_SOFT_RESET */ + + 0x0014, /* IO_ACX_SLV_MEM_ADDR */ + 0x0018, /* IO_ACX_SLV_MEM_DATA */ + 0x001c, /* IO_ACX_SLV_MEM_CTL */ + 0x0020, /* IO_ACX_SLV_END_CTL */ + + 0x0034, /* IO_ACX_FEMR */ + + 0x00b4, /* IO_ACX_INT_TRIG */ + 0x00d4, /* IO_ACX_IRQ_MASK */ + /* we do mean NON_DES (0xf0), not NON_DES_MASK which is at 0xe0: */ + 0x00f0, /* IO_ACX_IRQ_STATUS_NON_DES */ + 0x00e4, /* IO_ACX_IRQ_STATUS_CLEAR */ + 0x00e8, /* IO_ACX_IRQ_ACK */ + 0x00ec, /* IO_ACX_HINT_TRIG */ + + 0x01d0, /* IO_ACX_ENABLE */ + + 0x0338, /* IO_ACX_EEPROM_CTL */ + 0x033c, /* IO_ACX_EEPROM_ADDR */ + 0x0340, /* IO_ACX_EEPROM_DATA */ + 0x0344, /* IO_ACX_EEPROM_CFG */ + + 0x0350, /* IO_ACX_PHY_ADDR */ + 0x0354, /* IO_ACX_PHY_DATA */ + 0x0358, /* IO_ACX_PHY_CTL */ + + 0x0374, /* IO_ACX_GPIO_OE */ + + 0x037c, /* IO_ACX_GPIO_OUT */ + + 0x0388, /* IO_ACX_CMD_MAILBOX_OFFS */ + 0x038c, /* IO_ACX_INFO_MAILBOX_OFFS */ + 0x0390, /* IO_ACX_EEPROM_INFORMATION */ + + 0x0100, /* IO_ACX_EE_START */ + 0x0104, /* IO_ACX_SOR_CFG */ + 0x0108, /* IO_ACX_ECPU_CTRL */ +}; + +static void +dummy_netdev_init(struct net_device *ndev) {} + +static int __devinit +acxpci_e_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + acx111_ie_configoption_t co; + unsigned long mem_region1 = 0; + unsigned long mem_region2 = 0; + unsigned long mem_region1_size; + unsigned long mem_region2_size; + unsigned long phymem1; + unsigned long phymem2; + void *mem1 = NULL; + void *mem2 = NULL; + acx_device_t *adev = NULL; + struct net_device *ndev = NULL; + const char *chip_name; + int result = -EIO; + int err; + u8 chip_type; + + FN_ENTER; + + /* Enable the PCI device */ + if (pci_enable_device(pdev)) { + printk("acx: pci_enable_device() FAILED\n"); + result = -ENODEV; + goto fail_pci_enable_device; + } + + /* enable busmastering (required for CardBus) */ + pci_set_master(pdev); + + /* FIXME: prism54 calls pci_set_mwi() here, + * should we do/support the same? */ + + /* chiptype is u8 but id->driver_data is ulong + ** Works for now (possible values are 1 and 2) */ + chip_type = (u8)id->driver_data; + /* acx100 and acx111 have different PCI memory regions */ + if (chip_type == CHIPTYPE_ACX100) { + chip_name = "ACX100"; + mem_region1 = PCI_ACX100_REGION1; + mem_region1_size = PCI_ACX100_REGION1_SIZE; + + mem_region2 = PCI_ACX100_REGION2; + mem_region2_size = PCI_ACX100_REGION2_SIZE; + } else if (chip_type == CHIPTYPE_ACX111) { + chip_name = "ACX111"; + mem_region1 = PCI_ACX111_REGION1; + mem_region1_size = PCI_ACX111_REGION1_SIZE; + + mem_region2 = PCI_ACX111_REGION2; + mem_region2_size = PCI_ACX111_REGION2_SIZE; + } else { + printk("acx: unknown chip type 0x%04X\n", chip_type); + goto fail_unknown_chiptype; + } + + /* Figure out our resources */ + phymem1 = pci_resource_start(pdev, mem_region1); + phymem2 = pci_resource_start(pdev, mem_region2); + if (!request_mem_region(phymem1, pci_resource_len(pdev, mem_region1), "acx_1")) { + printk("acx: cannot reserve PCI memory region 1 (are you sure " + "you have CardBus support in kernel?)\n"); + goto fail_request_mem_region1; + } + if (!request_mem_region(phymem2, pci_resource_len(pdev, mem_region2), "acx_2")) { + printk("acx: cannot reserve PCI memory region 2\n"); + goto fail_request_mem_region2; + } + + /* this used to be ioremap(), but ioremap_nocache() + * is much less risky, right? (and slower?) + * FIXME: we may want to go back to cached variant if it's + * certain that our code really properly handles + * cached operation (memory barriers, volatile?, ...) + * (but always keep this comment here regardless!) + * Possibly make this a driver config setting? */ + + mem1 = ioremap(phymem1, mem_region1_size); + if (!mem1) { + printk("acx: ioremap() FAILED\n"); + goto fail_ioremap1; + } + mem2 = ioremap(phymem2, mem_region2_size); + if (!mem2) { + printk("acx: ioremap() #2 FAILED\n"); + goto fail_ioremap2; + } + + printk("acx: found %s-based wireless network card at %s, irq:%d, " + "phymem1:0x%lX, phymem2:0x%lX, mem1:0x%p, mem1_size:%ld, " + "mem2:0x%p, mem2_size:%ld\n", + chip_name, pci_name(pdev), pdev->irq, phymem1, phymem2, + mem1, mem_region1_size, + mem2, mem_region2_size); + log(L_ANY, "initial debug setting is 0x%04X\n", acx_debug); + + if (0 == pdev->irq) { + printk("acx: can't use IRQ 0\n"); + goto fail_irq; + } + + ndev = alloc_netdev(sizeof(*adev), "wlan%d", dummy_netdev_init); + /* (NB: memsets to 0 entire area) */ + if (!ndev) { + printk("acx: no memory for netdevice struct\n"); + goto fail_alloc_netdev; + } + + ether_setup(ndev); + ndev->open = &acxpci_e_open; + ndev->stop = &acxpci_e_close; + ndev->hard_start_xmit = &acx_i_start_xmit; + ndev->get_stats = &acx_e_get_stats; +#if IW_HANDLER_VERSION <= 5 + ndev->get_wireless_stats = &acx_e_get_wireless_stats; +#endif + ndev->wireless_handlers = (struct iw_handler_def *)&acx_ioctl_handler_def; + ndev->set_multicast_list = &acxpci_i_set_multicast_list; + ndev->tx_timeout = &acxpci_i_tx_timeout; + ndev->change_mtu = &acx_e_change_mtu; + ndev->watchdog_timeo = 4 * HZ; + ndev->irq = pdev->irq; + ndev->base_addr = pci_resource_start(pdev, 0); + + adev = ndev2adev(ndev); + spin_lock_init(&adev->lock); /* initial state: unlocked */ + /* We do not start with downed sem: we want PARANOID_LOCKING to work */ + sema_init(&adev->sem, 1); /* initial state: 1 (upped) */ + /* since nobody can see new netdev yet, we can as well + ** just _presume_ that we're under sem (instead of actually taking it): */ + /* acx_sem_lock(adev); */ + adev->pdev = pdev; + adev->ndev = ndev; + adev->dev_type = DEVTYPE_PCI; + adev->chip_type = chip_type; + adev->chip_name = chip_name; + adev->io = (CHIPTYPE_ACX100 == chip_type) ? IO_ACX100 : IO_ACX111; + adev->membase = phymem1; + adev->iobase = mem1; + adev->membase2 = phymem2; + adev->iobase2 = mem2; + /* to find crashes due to weird driver access + * to unconfigured interface (ifup) */ + adev->mgmt_timer.function = (void (*)(unsigned long))0x0000dead; + +#ifdef NONESSENTIAL_FEATURES + acx_show_card_eeprom_id(adev); +#endif /* NONESSENTIAL_FEATURES */ + +#ifdef SET_MODULE_OWNER + SET_MODULE_OWNER(ndev); +#endif + SET_NETDEV_DEV(ndev, &pdev->dev); + + log(L_IRQ|L_INIT, "using IRQ %d\n", pdev->irq); + + /* need to be able to restore PCI state after a suspend */ + pci_save_state(pdev); + pci_set_drvdata(pdev, ndev); + + /* ok, pci setup is finished, now start initializing the card */ + + /* NB: read_reg() reads may return bogus data before reset_dev(), + * since the firmware which directly controls large parts of the I/O + * registers isn't initialized yet. + * acx100 seems to be more affected than acx111 */ + if (OK != acxpci_s_reset_dev(adev)) + goto fail_reset; + + if (IS_ACX100(adev)) { + /* ACX100: configopt struct in cmd mailbox - directly after reset */ + memcpy_fromio(&co, adev->cmd_area, sizeof(co)); + } + + if (OK != acx_s_init_mac(adev)) + goto fail_init_mac; + + if (IS_ACX111(adev)) { + /* ACX111: configopt struct needs to be queried after full init */ + acx_s_interrogate(adev, &co, ACX111_IE_CONFIG_OPTIONS); + } + +/* TODO: merge them into one function, they are called just once and are the same for pci & usb */ + if (OK != acxpci_read_eeprom_byte(adev, 0x05, &adev->eeprom_version)) + goto fail_read_eeprom_version; + + acx_s_parse_configoption(adev, &co); + acx_s_set_defaults(adev); + acx_s_get_firmware_version(adev); /* needs to be after acx_s_init_mac() */ + acx_display_hardware_details(adev); + + /* Register the card, AFTER everything else has been set up, + * since otherwise an ioctl could step on our feet due to + * firmware operations happening in parallel or uninitialized data */ + err = register_netdev(ndev); + if (OK != err) { + printk("acx: register_netdev() FAILED: %d\n", err); + goto fail_register_netdev; + } + + acx_proc_register_entries(ndev); + + /* Now we have our device, so make sure the kernel doesn't try + * to send packets even though we're not associated to a network yet */ + acx_stop_queue(ndev, "on probe"); + acx_carrier_off(ndev, "on probe"); + + /* after register_netdev() userspace may start working with dev + * (in particular, on other CPUs), we only need to up the sem */ + /* acx_sem_unlock(adev); */ + + printk("acx "ACX_RELEASE": net device %s, driver compiled " + "against wireless extensions %d and Linux %s\n", + ndev->name, WIRELESS_EXT, UTS_RELEASE); + +#if CMD_DISCOVERY + great_inquisitor(adev); +#endif + + result = OK; + goto done; + + /* error paths: undo everything in reverse order... */ + +fail_register_netdev: + + acxpci_s_delete_dma_regions(adev); + pci_set_drvdata(pdev, NULL); + +fail_init_mac: +fail_read_eeprom_version: +fail_reset: + + free_netdev(ndev); +fail_alloc_netdev: +fail_irq: + + iounmap(mem2); +fail_ioremap2: + + iounmap(mem1); +fail_ioremap1: + + release_mem_region(pci_resource_start(pdev, mem_region2), + pci_resource_len(pdev, mem_region2)); +fail_request_mem_region2: + + release_mem_region(pci_resource_start(pdev, mem_region1), + pci_resource_len(pdev, mem_region1)); +fail_request_mem_region1: +fail_unknown_chiptype: + + pci_disable_device(pdev); +fail_pci_enable_device: + + pci_set_power_state(pdev, PCI_D3hot); + +done: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acxpci_e_remove +** +** Shut device down (if not hot unplugged) +** and deallocate PCI resources for the acx chip. +** +** pdev - ptr to PCI device structure containing info about pci configuration +*/ +static void __devexit +acxpci_e_remove(struct pci_dev *pdev) +{ + struct net_device *ndev; + acx_device_t *adev; + unsigned long mem_region1, mem_region2; + unsigned long flags; + + FN_ENTER; + + ndev = (struct net_device*) pci_get_drvdata(pdev); + if (!ndev) { + log(L_DEBUG, "%s: card is unused. Skipping any release code\n", + __func__); + goto end; + } + + adev = ndev2adev(ndev); + + /* If device wasn't hot unplugged... */ + if (adev_present(adev)) { + + acx_sem_lock(adev); + + /* disable both Tx and Rx to shut radio down properly */ + acx_s_issue_cmd(adev, ACX1xx_CMD_DISABLE_TX, NULL, 0); + acx_s_issue_cmd(adev, ACX1xx_CMD_DISABLE_RX, NULL, 0); + +#ifdef REDUNDANT + /* put the eCPU to sleep to save power + * Halting is not possible currently, + * since not supported by all firmware versions */ + acx_s_issue_cmd(adev, ACX100_CMD_SLEEP, NULL, 0); +#endif + acx_lock(adev, flags); + /* disable power LED to save power :-) */ + log(L_INIT, "switching off power LED to save power\n"); + acxpci_l_power_led(adev, 0); + /* stop our eCPU */ + if (IS_ACX111(adev)) { + /* FIXME: does this actually keep halting the eCPU? + * I don't think so... + */ + acxpci_l_reset_mac(adev); + } else { + u16 temp; + /* halt eCPU */ + temp = read_reg16(adev, IO_ACX_ECPU_CTRL) | 0x1; + write_reg16(adev, IO_ACX_ECPU_CTRL, temp); + write_flush(adev); + } + acx_unlock(adev, flags); + + acx_sem_unlock(adev); + } + + /* unregister the device to not let the kernel + * (e.g. ioctls) access a half-deconfigured device + * NB: this will cause acxpci_e_close() to be called, + * thus we shouldn't call it under sem! */ + log(L_INIT, "removing device %s\n", ndev->name); + unregister_netdev(ndev); + + /* unregister_netdev ensures that no references to us left. + * For paranoid reasons we continue to follow the rules */ + acx_sem_lock(adev); + + if (adev->dev_state_mask & ACX_STATE_IFACE_UP) { + acxpci_s_down(ndev); + CLEAR_BIT(adev->dev_state_mask, ACX_STATE_IFACE_UP); + } + + acx_proc_unregister_entries(ndev); + + if (IS_ACX100(adev)) { + mem_region1 = PCI_ACX100_REGION1; + mem_region2 = PCI_ACX100_REGION2; + } else { + mem_region1 = PCI_ACX111_REGION1; + mem_region2 = PCI_ACX111_REGION2; + } + + /* finally, clean up PCI bus state */ + acxpci_s_delete_dma_regions(adev); + if (adev->iobase) iounmap(adev->iobase); + if (adev->iobase2) iounmap(adev->iobase2); + release_mem_region(pci_resource_start(pdev, mem_region1), + pci_resource_len(pdev, mem_region1)); + release_mem_region(pci_resource_start(pdev, mem_region2), + pci_resource_len(pdev, mem_region2)); + pci_disable_device(pdev); + + /* remove dev registration */ + pci_set_drvdata(pdev, NULL); + + acx_sem_unlock(adev); + + /* Free netdev (quite late, + * since otherwise we might get caught off-guard + * by a netdev timeout handler execution + * expecting to see a working dev...) */ + free_netdev(ndev); + + /* put device into ACPI D3 mode (shutdown) */ + pci_set_power_state(pdev, PCI_D3hot); + +end: + FN_EXIT0; +} + + +/*********************************************************************** +** TODO: PM code needs to be fixed / debugged / tested. +*/ +#ifdef CONFIG_PM +static int +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) +acxpci_e_suspend(struct pci_dev *pdev, pm_message_t state) +#else +acxpci_e_suspend(struct pci_dev *pdev, u32 state) +#endif +{ + struct net_device *ndev = pci_get_drvdata(pdev); + acx_device_t *adev; + + FN_ENTER; + printk("acx: suspend handler is experimental!\n"); + printk("sus: dev %p\n", ndev); + + if (!netif_running(ndev)) + goto end; + + adev = ndev2adev(ndev); + printk("sus: adev %p\n", adev); + + acx_sem_lock(adev); + + netif_device_detach(ndev); /* this one cannot sleep */ + acxpci_s_down(ndev); + /* down() does not set it to 0xffff, but here we really want that */ + write_reg16(adev, IO_ACX_IRQ_MASK, 0xffff); + write_reg16(adev, IO_ACX_FEMR, 0x0); + acxpci_s_delete_dma_regions(adev); + pci_save_state(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + acx_sem_unlock(adev); +end: + FN_EXIT0; + return OK; +} + + +static int +acxpci_e_resume(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + acx_device_t *adev; + + FN_ENTER; + + printk("acx: resume handler is experimental!\n"); + printk("rsm: got dev %p\n", ndev); + + if (!netif_running(ndev)) + goto end; + + adev = ndev2adev(ndev); + printk("rsm: got adev %p\n", adev); + + acx_sem_lock(adev); + + pci_set_power_state(pdev, PCI_D0); + printk("rsm: power state PCI_D0 set\n"); + pci_restore_state(pdev); + printk("rsm: PCI state restored\n"); + + if (OK != acxpci_s_reset_dev(adev)) + goto end_unlock; + printk("rsm: device reset done\n"); + if (OK != acx_s_init_mac(adev)) + goto end_unlock; + printk("rsm: init MAC done\n"); + + acxpci_s_up(ndev); + printk("rsm: acx up done\n"); + + /* now even reload all card parameters as they were before suspend, + * and possibly be back in the network again already :-) */ + if (ACX_STATE_IFACE_UP & adev->dev_state_mask) { + adev->set_mask = GETSET_ALL; + acx_s_update_card_settings(adev); + printk("rsm: settings updated\n"); + } + netif_device_attach(ndev); + printk("rsm: device attached\n"); + +end_unlock: + acx_sem_unlock(adev); +end: + /* we need to return OK here anyway, right? */ + FN_EXIT0; + return OK; +} +#endif /* CONFIG_PM */ + + +/*********************************************************************** +** acxpci_s_up +** +** This function is called by acxpci_e_open (when ifconfig sets the device as up) +** +** Side effects: +** - Enables on-card interrupt requests +** - calls acx_s_start +*/ + +static void +enable_acx_irq(acx_device_t *adev) +{ + FN_ENTER; + write_reg16(adev, IO_ACX_IRQ_MASK, adev->irq_mask); + write_reg16(adev, IO_ACX_FEMR, 0x8000); + adev->irqs_active = 1; + FN_EXIT0; +} + +static void +acxpci_s_up(struct net_device *ndev) +{ + acx_device_t *adev = ndev2adev(ndev); + unsigned long flags; + + FN_ENTER; + + acx_lock(adev, flags); + enable_acx_irq(adev); + acx_unlock(adev, flags); + + /* acx fw < 1.9.3.e has a hardware timer, and older drivers + ** used to use it. But we don't do that anymore, our OS + ** has reliable software timers */ + init_timer(&adev->mgmt_timer); + adev->mgmt_timer.function = acx_i_timer; + adev->mgmt_timer.data = (unsigned long)adev; + + /* Need to set ACX_STATE_IFACE_UP first, or else + ** timer won't be started by acx_set_status() */ + SET_BIT(adev->dev_state_mask, ACX_STATE_IFACE_UP); + switch (adev->mode) { + case ACX_MODE_0_ADHOC: + case ACX_MODE_2_STA: + /* actual scan cmd will happen in start() */ + acx_set_status(adev, ACX_STATUS_1_SCANNING); break; + case ACX_MODE_3_AP: + case ACX_MODE_MONITOR: + acx_set_status(adev, ACX_STATUS_4_ASSOCIATED); break; + } + + acx_s_start(adev); + + FN_EXIT0; +} + + +/*********************************************************************** +** acxpci_s_down +** +** NB: device may be already hot unplugged if called from acxpci_e_remove() +** +** Disables on-card interrupt request, stops softirq and timer, stops queue, +** sets status == STOPPED +*/ + +static void +disable_acx_irq(acx_device_t *adev) +{ + FN_ENTER; + + /* I guess mask is not 0xffff because acx100 won't signal + ** cmd completion then (needed for ifup). + ** Someone with acx100 please confirm */ + write_reg16(adev, IO_ACX_IRQ_MASK, adev->irq_mask_off); + write_reg16(adev, IO_ACX_FEMR, 0x0); + adev->irqs_active = 0; + FN_EXIT0; +} + +static void +acxpci_s_down(struct net_device *ndev) +{ + acx_device_t *adev = ndev2adev(ndev); + unsigned long flags; + + FN_ENTER; + + /* Disable IRQs first, so that IRQs cannot race with us */ + /* then wait until interrupts have finished executing on other CPUs */ + acx_lock(adev, flags); + disable_acx_irq(adev); + synchronize_irq(adev->pdev->irq); + acx_unlock(adev, flags); + + /* we really don't want to have an asynchronous tasklet disturb us + ** after something vital for its job has been shut down, so + ** end all remaining work now. + ** + ** NB: carrier_off (done by set_status below) would lead to + ** not yet fully understood deadlock in FLUSH_SCHEDULED_WORK(). + ** That's why we do FLUSH first. + ** + ** NB2: we have a bad locking bug here: FLUSH_SCHEDULED_WORK() + ** waits for acx_e_after_interrupt_task to complete if it is running + ** on another CPU, but acx_e_after_interrupt_task + ** will sleep on sem forever, because it is taken by us! + ** Work around that by temporary sem unlock. + ** This will fail miserably if we'll be hit by concurrent + ** iwconfig or something in between. TODO! */ + acx_sem_unlock(adev); + FLUSH_SCHEDULED_WORK(); + acx_sem_lock(adev); + + /* This is possible: + ** FLUSH_SCHEDULED_WORK -> acx_e_after_interrupt_task -> + ** -> set_status(ASSOCIATED) -> wake_queue() + ** That's why we stop queue _after_ FLUSH_SCHEDULED_WORK + ** lock/unlock is just paranoia, maybe not needed */ + acx_lock(adev, flags); + acx_stop_queue(ndev, "on ifdown"); + acx_set_status(adev, ACX_STATUS_0_STOPPED); + acx_unlock(adev, flags); + + /* kernel/timer.c says it's illegal to del_timer_sync() + ** a timer which restarts itself. We guarantee this cannot + ** ever happen because acx_i_timer() never does this if + ** status is ACX_STATUS_0_STOPPED */ + del_timer_sync(&adev->mgmt_timer); + + FN_EXIT0; +} + + +/*********************************************************************** +** acxpci_e_open +** +** Called as a result of SIOCSIFFLAGS ioctl changing the flags bit IFF_UP +** from clear to set. In other words: ifconfig up. +** +** Returns: +** 0 success +** >0 f/w reported error +** <0 driver reported error +*/ +static int +acxpci_e_open(struct net_device *ndev) +{ + acx_device_t *adev = ndev2adev(ndev); + int result = OK; + + FN_ENTER; + + acx_sem_lock(adev); + + acx_init_task_scheduler(adev); + +/* TODO: pci_set_power_state(pdev, PCI_D0); ? */ + + /* request shared IRQ handler */ + if (request_irq(ndev->irq, acxpci_i_interrupt, IRQF_SHARED, ndev->name, ndev)) { + printk("%s: request_irq FAILED\n", ndev->name); + result = -EAGAIN; + goto done; + } + log(L_DEBUG|L_IRQ, "request_irq %d successful\n", ndev->irq); + + /* ifup device */ + acxpci_s_up(ndev); + + /* We don't currently have to do anything else. + * The setup of the MAC should be subsequently completed via + * the mlme commands. + * Higher layers know we're ready from dev->start==1 and + * dev->tbusy==0. Our rx path knows to pass up received/ + * frames because of dev->flags&IFF_UP is true. + */ +done: + acx_sem_unlock(adev); + + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acxpci_e_close +** +** Called as a result of SIOCSIIFFLAGS ioctl changing the flags bit IFF_UP +** from set to clear. I.e. called by "ifconfig DEV down" +** +** Returns: +** 0 success +** >0 f/w reported error +** <0 driver reported error +*/ +static int +acxpci_e_close(struct net_device *ndev) +{ + acx_device_t *adev = ndev2adev(ndev); + + FN_ENTER; + + acx_sem_lock(adev); + + /* ifdown device */ + CLEAR_BIT(adev->dev_state_mask, ACX_STATE_IFACE_UP); + if (netif_device_present(ndev)) { + acxpci_s_down(ndev); + } + + /* disable all IRQs, release shared IRQ handler */ + write_reg16(adev, IO_ACX_IRQ_MASK, 0xffff); + write_reg16(adev, IO_ACX_FEMR, 0x0); + free_irq(ndev->irq, ndev); + +/* TODO: pci_set_power_state(pdev, PCI_D3hot); ? */ + + /* We currently don't have to do anything else. + * Higher layers know we're not ready from dev->start==0 and + * dev->tbusy==1. Our rx path knows to not pass up received + * frames because of dev->flags&IFF_UP is false. + */ + acx_sem_unlock(adev); + + log(L_INIT, "closed device\n"); + FN_EXIT0; + return OK; +} + + +/*********************************************************************** +** acxpci_i_tx_timeout +** +** Called from network core. Must not sleep! +*/ +static void +acxpci_i_tx_timeout(struct net_device *ndev) +{ + acx_device_t *adev = ndev2adev(ndev); + unsigned long flags; + unsigned int tx_num_cleaned; + + FN_ENTER; + + acx_lock(adev, flags); + + /* clean processed tx descs, they may have been completely full */ + tx_num_cleaned = acxpci_l_clean_txdesc(adev); + + /* nothing cleaned, yet (almost) no free buffers available? + * --> clean all tx descs, no matter which status!! + * Note that I strongly suspect that doing emergency cleaning + * may confuse the firmware. This is a last ditch effort to get + * ANYTHING to work again... + * + * TODO: it's best to simply reset & reinit hw from scratch... + */ + if ((adev->tx_free <= TX_EMERG_CLEAN) && (tx_num_cleaned == 0)) { + printk("%s: FAILED to free any of the many full tx buffers. " + "Switching to emergency freeing. " + "Please report!\n", ndev->name); + acxpci_l_clean_txdesc_emergency(adev); + } + + if (acx_queue_stopped(ndev) && (ACX_STATUS_4_ASSOCIATED == adev->status)) + acx_wake_queue(ndev, "after tx timeout"); + + /* stall may have happened due to radio drift, so recalib radio */ + acx_schedule_task(adev, ACX_AFTER_IRQ_CMD_RADIO_RECALIB); + + /* do unimportant work last */ + printk("%s: tx timeout!\n", ndev->name); + adev->stats.tx_errors++; + + acx_unlock(adev, flags); + + FN_EXIT0; +} + + +/*********************************************************************** +** acxpci_i_set_multicast_list +** FIXME: most likely needs refinement +*/ +static void +acxpci_i_set_multicast_list(struct net_device *ndev) +{ + acx_device_t *adev = ndev2adev(ndev); + unsigned long flags; + + FN_ENTER; + + acx_lock(adev, flags); + + /* firmwares don't have allmulti capability, + * so just use promiscuous mode instead in this case. */ + if (ndev->flags & (IFF_PROMISC|IFF_ALLMULTI)) { + SET_BIT(adev->rx_config_1, RX_CFG1_RCV_PROMISCUOUS); + CLEAR_BIT(adev->rx_config_1, RX_CFG1_FILTER_ALL_MULTI); + SET_BIT(adev->set_mask, SET_RXCONFIG); + /* let kernel know in case *we* needed to set promiscuous */ + ndev->flags |= (IFF_PROMISC|IFF_ALLMULTI); + } else { + CLEAR_BIT(adev->rx_config_1, RX_CFG1_RCV_PROMISCUOUS); + SET_BIT(adev->rx_config_1, RX_CFG1_FILTER_ALL_MULTI); + SET_BIT(adev->set_mask, SET_RXCONFIG); + ndev->flags &= ~(IFF_PROMISC|IFF_ALLMULTI); + } + + /* cannot update card settings directly here, atomic context */ + acx_schedule_task(adev, ACX_AFTER_IRQ_UPDATE_CARD_CFG); + + acx_unlock(adev, flags); + + FN_EXIT0; +} + + +/*************************************************************** +** acxpci_l_process_rxdesc +** +** Called directly and only from the IRQ handler +*/ + +#if !ACX_DEBUG +static inline void log_rxbuffer(const acx_device_t *adev) {} +#else +static void +log_rxbuffer(const acx_device_t *adev) +{ + register const struct rxhostdesc *rxhostdesc; + int i; + /* no FN_ENTER here, we don't want that */ + + rxhostdesc = adev->rxhostdesc_start; + if (unlikely(!rxhostdesc)) return; + for (i = 0; i < RX_CNT; i++) { + if ((rxhostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN)) + && (rxhostdesc->Status & cpu_to_le32(DESC_STATUS_FULL))) + printk("rx: buf %d full\n", i); + rxhostdesc++; + } +} +#endif + +static void +acxpci_l_process_rxdesc(acx_device_t *adev) +{ + register rxhostdesc_t *hostdesc; + unsigned count, tail; + + FN_ENTER; + + if (unlikely(acx_debug & L_BUFR)) + log_rxbuffer(adev); + + /* First, have a loop to determine the first descriptor that's + * full, just in case there's a mismatch between our current + * rx_tail and the full descriptor we're supposed to handle. */ + tail = adev->rx_tail; + count = RX_CNT; + while (1) { + hostdesc = &adev->rxhostdesc_start[tail]; + /* advance tail regardless of outcome of the below test */ + tail = (tail + 1) % RX_CNT; + + if ((hostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN)) + && (hostdesc->Status & cpu_to_le32(DESC_STATUS_FULL))) + break; /* found it! */ + + if (unlikely(!--count)) /* hmm, no luck: all descs empty, bail out */ + goto end; + } + + /* now process descriptors, starting with the first we figured out */ + while (1) { + log(L_BUFR, "rx: tail=%u Ctl_16=%04X Status=%08X\n", + tail, hostdesc->Ctl_16, hostdesc->Status); + + acx_l_process_rxbuf(adev, hostdesc->data); + + hostdesc->Status = 0; + /* flush all writes before adapter sees CTL_HOSTOWN change */ + wmb(); + /* Host no longer owns this, needs to be LAST */ + CLEAR_BIT(hostdesc->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN)); + + /* ok, descriptor is handled, now check the next descriptor */ + hostdesc = &adev->rxhostdesc_start[tail]; + + /* if next descriptor is empty, then bail out */ + if (!(hostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN)) + || !(hostdesc->Status & cpu_to_le32(DESC_STATUS_FULL))) + break; + + tail = (tail + 1) % RX_CNT; + } +end: + adev->rx_tail = tail; + FN_EXIT0; +} + + +/*********************************************************************** +** acxpci_i_interrupt +** +** IRQ handler (atomic context, must not sleep, blah, blah) +*/ + +/* scan is complete. all frames now on the receive queue are valid */ +#define INFO_SCAN_COMPLETE 0x0001 +#define INFO_WEP_KEY_NOT_FOUND 0x0002 +/* hw has been reset as the result of a watchdog timer timeout */ +#define INFO_WATCH_DOG_RESET 0x0003 +/* failed to send out NULL frame from PS mode notification to AP */ +/* recommended action: try entering 802.11 PS mode again */ +#define INFO_PS_FAIL 0x0004 +/* encryption/decryption process on a packet failed */ +#define INFO_IV_ICV_FAILURE 0x0005 + +/* Info mailbox format: +2 bytes: type +2 bytes: status +more bytes may follow + rumors say about status: + 0x0000 info available (set by hw) + 0x0001 information received (must be set by host) + 0x1000 info available, mailbox overflowed (messages lost) (set by hw) + but in practice we've seen: + 0x9000 when we did not set status to 0x0001 on prev message + 0x1001 when we did set it + 0x0000 was never seen + conclusion: this is really a bitfield: + 0x1000 is 'info available' bit + 'mailbox overflowed' bit is 0x8000, not 0x1000 + value of 0x0000 probably means that there are no messages at all + P.S. I dunno how in hell hw is supposed to notice that messages are lost - + it does NOT clear bit 0x0001, and this bit will probably stay forever set + after we set it once. Let's hope this will be fixed in firmware someday +*/ + +static void +handle_info_irq(acx_device_t *adev) +{ +#if ACX_DEBUG + static const char * const info_type_msg[] = { + "(unknown)", + "scan complete", + "WEP key not found", + "internal watchdog reset was done", + "failed to send powersave (NULL frame) notification to AP", + "encrypt/decrypt on a packet has failed", + "TKIP tx keys disabled", + "TKIP rx keys disabled", + "TKIP rx: key ID not found", + "???", + "???", + "???", + "???", + "???", + "???", + "???", + "TKIP IV value exceeds thresh" + }; +#endif + u32 info_type, info_status; + + info_type = readl(adev->info_area); + info_status = (info_type >> 16); + info_type = (u16)info_type; + + /* inform fw that we have read this info message */ + writel(info_type | 0x00010000, adev->info_area); + write_reg16(adev, IO_ACX_INT_TRIG, INT_TRIG_INFOACK); + write_flush(adev); + + log(L_CTL, "info_type:%04X info_status:%04X\n", + info_type, info_status); + + log(L_IRQ, "got Info IRQ: status %04X type %04X: %s\n", + info_status, info_type, + info_type_msg[(info_type >= VEC_SIZE(info_type_msg)) ? + 0 : info_type] + ); +} + + +static void +log_unusual_irq(u16 irqtype) { + /* + if (!printk_ratelimit()) + return; + */ + + printk("acx: got"); + if (irqtype & HOST_INT_RX_DATA) { + printk(" Rx_Data"); + } + /* HOST_INT_TX_COMPLETE */ + if (irqtype & HOST_INT_TX_XFER) { + printk(" Tx_Xfer"); + } + /* HOST_INT_RX_COMPLETE */ + if (irqtype & HOST_INT_DTIM) { + printk(" DTIM"); + } + if (irqtype & HOST_INT_BEACON) { + printk(" Beacon"); + } + if (irqtype & HOST_INT_TIMER) { + log(L_IRQ, " Timer"); + } + if (irqtype & HOST_INT_KEY_NOT_FOUND) { + printk(" Key_Not_Found"); + } + if (irqtype & HOST_INT_IV_ICV_FAILURE) { + printk(" IV_ICV_Failure (crypto)"); + } + /* HOST_INT_CMD_COMPLETE */ + /* HOST_INT_INFO */ + if (irqtype & HOST_INT_OVERFLOW) { + printk(" Overflow"); + } + if (irqtype & HOST_INT_PROCESS_ERROR) { + printk(" Process_Error"); + } + /* HOST_INT_SCAN_COMPLETE */ + if (irqtype & HOST_INT_FCS_THRESHOLD) { + printk(" FCS_Threshold"); + } + if (irqtype & HOST_INT_UNKNOWN) { + printk(" Unknown"); + } + printk(" IRQ(s)\n"); +} + + +static void +update_link_quality_led(acx_device_t *adev) +{ + int qual; + + qual = acx_signal_determine_quality(adev->wstats.qual.level, adev->wstats.qual.noise); + if (qual > adev->brange_max_quality) + qual = adev->brange_max_quality; + + if (time_after(jiffies, adev->brange_time_last_state_change + + (HZ/2 - HZ/2 * (unsigned long)qual / adev->brange_max_quality ) )) { + acxpci_l_power_led(adev, (adev->brange_last_state == 0)); + adev->brange_last_state ^= 1; /* toggle */ + adev->brange_time_last_state_change = jiffies; + } +} + + +#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* a la orinoco.c */ + +static irqreturn_t +acxpci_i_interrupt(int irq, void *dev_id) +{ + acx_device_t *adev; + unsigned long flags; + unsigned int irqcount = MAX_IRQLOOPS_PER_JIFFY; + register u16 irqtype; + u16 unmasked; + + adev = ndev2adev((struct net_device*)dev_id); + + /* LOCKING: can just spin_lock() since IRQs are disabled anyway. + * I am paranoid */ + acx_lock(adev, flags); + + unmasked = read_reg16(adev, IO_ACX_IRQ_STATUS_CLEAR); + if (unlikely(0xffff == unmasked)) { + /* 0xffff value hints at missing hardware, + * so don't do anything. + * Not very clean, but other drivers do the same... */ + log(L_IRQ, "IRQ type:FFFF - device removed? IRQ_NONE\n"); + goto none; + } + + /* We will check only "interesting" IRQ types */ + irqtype = unmasked & ~adev->irq_mask; + if (!irqtype) { + /* We are on a shared IRQ line and it wasn't our IRQ */ + log(L_IRQ, "IRQ type:%04X, mask:%04X - all are masked, IRQ_NONE\n", + unmasked, adev->irq_mask); + goto none; + } + + /* Done here because IRQ_NONEs taking three lines of log + ** drive me crazy */ + FN_ENTER; + +#define IRQ_ITERATE 1 +#if IRQ_ITERATE +if (jiffies != adev->irq_last_jiffies) { + adev->irq_loops_this_jiffy = 0; + adev->irq_last_jiffies = jiffies; +} + +/* safety condition; we'll normally abort loop below + * in case no IRQ type occurred */ +while (likely(--irqcount)) { +#endif + /* ACK all IRQs ASAP */ + write_reg16(adev, IO_ACX_IRQ_ACK, 0xffff); + + log(L_IRQ, "IRQ type:%04X, mask:%04X, type & ~mask:%04X\n", + unmasked, adev->irq_mask, irqtype); + + /* Handle most important IRQ types first */ + if (irqtype & HOST_INT_RX_COMPLETE) { + log(L_IRQ, "got Rx_Complete IRQ\n"); + acxpci_l_process_rxdesc(adev); + } + if (irqtype & HOST_INT_TX_COMPLETE) { + log(L_IRQ, "got Tx_Complete IRQ\n"); + /* don't clean up on each Tx complete, wait a bit + * unless we're going towards full, in which case + * we do it immediately, too (otherwise we might lockup + * with a full Tx buffer if we go into + * acxpci_l_clean_txdesc() at a time when we won't wakeup + * the net queue in there for some reason...) */ + if (adev->tx_free <= TX_START_CLEAN) { +#if TX_CLEANUP_IN_SOFTIRQ + acx_schedule_task(adev, ACX_AFTER_IRQ_TX_CLEANUP); +#else + acxpci_l_clean_txdesc(adev); +#endif + } + } + + /* Less frequent ones */ + if (irqtype & (0 + | HOST_INT_CMD_COMPLETE + | HOST_INT_INFO + | HOST_INT_SCAN_COMPLETE + )) { + if (irqtype & HOST_INT_CMD_COMPLETE) { + log(L_IRQ, "got Command_Complete IRQ\n"); + /* save the state for the running issue_cmd() */ + SET_BIT(adev->irq_status, HOST_INT_CMD_COMPLETE); + } + if (irqtype & HOST_INT_INFO) { + handle_info_irq(adev); + } + if (irqtype & HOST_INT_SCAN_COMPLETE) { + log(L_IRQ, "got Scan_Complete IRQ\n"); + /* need to do that in process context */ + acx_schedule_task(adev, ACX_AFTER_IRQ_COMPLETE_SCAN); + /* remember that fw is not scanning anymore */ + SET_BIT(adev->irq_status, HOST_INT_SCAN_COMPLETE); + } + } + + /* These we just log, but either they happen rarely + * or we keep them masked out */ + if (irqtype & (0 + | HOST_INT_RX_DATA + /* | HOST_INT_TX_COMPLETE */ + | HOST_INT_TX_XFER + /* | HOST_INT_RX_COMPLETE */ + | HOST_INT_DTIM + | HOST_INT_BEACON + | HOST_INT_TIMER + | HOST_INT_KEY_NOT_FOUND + | HOST_INT_IV_ICV_FAILURE + /* | HOST_INT_CMD_COMPLETE */ + /* | HOST_INT_INFO */ + | HOST_INT_OVERFLOW + | HOST_INT_PROCESS_ERROR + /* | HOST_INT_SCAN_COMPLETE */ + | HOST_INT_FCS_THRESHOLD + | HOST_INT_UNKNOWN + )) { + log_unusual_irq(irqtype); + } + +#if IRQ_ITERATE + unmasked = read_reg16(adev, IO_ACX_IRQ_STATUS_CLEAR); + irqtype = unmasked & ~adev->irq_mask; + /* Bail out if no new IRQ bits or if all are masked out */ + if (!irqtype) + break; + + if (unlikely(++adev->irq_loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY)) { + printk(KERN_ERR "acx: too many interrupts per jiffy!\n"); + /* Looks like card floods us with IRQs! Try to stop that */ + write_reg16(adev, IO_ACX_IRQ_MASK, 0xffff); + /* This will short-circuit all future attempts to handle IRQ. + * We cant do much more... */ + adev->irq_mask = 0; + break; + } +} +#endif + /* Routine to perform blink with range */ + if (unlikely(adev->led_power == 2)) + update_link_quality_led(adev); + +/* handled: */ + /* write_flush(adev); - not needed, last op was read anyway */ + acx_unlock(adev, flags); + FN_EXIT0; + return IRQ_HANDLED; + +none: + acx_unlock(adev, flags); + return IRQ_NONE; +} + + +/*********************************************************************** +** acxpci_l_power_led +*/ +void +acxpci_l_power_led(acx_device_t *adev, int enable) +{ + u16 gpio_pled = IS_ACX111(adev) ? 0x0040 : 0x0800; + + /* A hack. Not moving message rate limiting to adev->xxx + * (it's only a debug message after all) */ + static int rate_limit = 0; + + if (rate_limit++ < 3) + log(L_IOCTL, "Please report in case toggling the power " + "LED doesn't work for your card!\n"); + if (enable) + write_reg16(adev, IO_ACX_GPIO_OUT, + read_reg16(adev, IO_ACX_GPIO_OUT) & ~gpio_pled); + else + write_reg16(adev, IO_ACX_GPIO_OUT, + read_reg16(adev, IO_ACX_GPIO_OUT) | gpio_pled); +} + + +/*********************************************************************** +** Ioctls +*/ + +/*********************************************************************** +*/ +int +acx111pci_ioctl_info( + struct net_device *ndev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ +#if ACX_DEBUG > 1 + acx_device_t *adev = ndev2adev(ndev); + rxdesc_t *rxdesc; + txdesc_t *txdesc; + rxhostdesc_t *rxhostdesc; + txhostdesc_t *txhostdesc; + struct acx111_ie_memoryconfig memconf; + struct acx111_ie_queueconfig queueconf; + unsigned long flags; + int i; + char memmap[0x34]; + char rxconfig[0x8]; + char fcserror[0x8]; + char ratefallback[0x5]; + + if ( !(acx_debug & (L_IOCTL|L_DEBUG)) ) + return OK; + /* using printk() since we checked debug flag already */ + + acx_sem_lock(adev); + + if (!IS_ACX111(adev)) { + printk("acx111-specific function called " + "with non-acx111 chip, aborting\n"); + goto end_ok; + } + + /* get Acx111 Memory Configuration */ + memset(&memconf, 0, sizeof(memconf)); + /* BTW, fails with 12 (Write only) error code. + ** Retained for easy testing of issue_cmd error handling :) */ + acx_s_interrogate(adev, &memconf, ACX1xx_IE_QUEUE_CONFIG); + + /* get Acx111 Queue Configuration */ + memset(&queueconf, 0, sizeof(queueconf)); + acx_s_interrogate(adev, &queueconf, ACX1xx_IE_MEMORY_CONFIG_OPTIONS); + + /* get Acx111 Memory Map */ + memset(memmap, 0, sizeof(memmap)); + acx_s_interrogate(adev, &memmap, ACX1xx_IE_MEMORY_MAP); + + /* get Acx111 Rx Config */ + memset(rxconfig, 0, sizeof(rxconfig)); + acx_s_interrogate(adev, &rxconfig, ACX1xx_IE_RXCONFIG); + + /* get Acx111 fcs error count */ + memset(fcserror, 0, sizeof(fcserror)); + acx_s_interrogate(adev, &fcserror, ACX1xx_IE_FCS_ERROR_COUNT); + + /* get Acx111 rate fallback */ + memset(ratefallback, 0, sizeof(ratefallback)); + acx_s_interrogate(adev, &ratefallback, ACX1xx_IE_RATE_FALLBACK); + + /* force occurrence of a beacon interrupt */ + /* TODO: comment why is this necessary */ + write_reg16(adev, IO_ACX_HINT_TRIG, HOST_INT_BEACON); + + /* dump Acx111 Mem Configuration */ + printk("dump mem config:\n" + "data read: %d, struct size: %d\n" + "Number of stations: %1X\n" + "Memory block size: %1X\n" + "tx/rx memory block allocation: %1X\n" + "count rx: %X / tx: %X queues\n" + "options %1X\n" + "fragmentation %1X\n" + "Rx Queue 1 Count Descriptors: %X\n" + "Rx Queue 1 Host Memory Start: %X\n" + "Tx Queue 1 Count Descriptors: %X\n" + "Tx Queue 1 Attributes: %X\n", + memconf.len, (int) sizeof(memconf), + memconf.no_of_stations, + memconf.memory_block_size, + memconf.tx_rx_memory_block_allocation, + memconf.count_rx_queues, memconf.count_tx_queues, + memconf.options, + memconf.fragmentation, + memconf.rx_queue1_count_descs, + acx2cpu(memconf.rx_queue1_host_rx_start), + memconf.tx_queue1_count_descs, + memconf.tx_queue1_attributes); + + /* dump Acx111 Queue Configuration */ + printk("dump queue head:\n" + "data read: %d, struct size: %d\n" + "tx_memory_block_address (from card): %X\n" + "rx_memory_block_address (from card): %X\n" + "rx1_queue address (from card): %X\n" + "tx1_queue address (from card): %X\n" + "tx1_queue attributes (from card): %X\n", + queueconf.len, (int) sizeof(queueconf), + queueconf.tx_memory_block_address, + queueconf.rx_memory_block_address, + queueconf.rx1_queue_address, + queueconf.tx1_queue_address, + queueconf.tx1_attributes); + + /* dump Acx111 Mem Map */ + printk("dump mem map:\n" + "data read: %d, struct size: %d\n" + "Code start: %X\n" + "Code end: %X\n" + "WEP default key start: %X\n" + "WEP default key end: %X\n" + "STA table start: %X\n" + "STA table end: %X\n" + "Packet template start: %X\n" + "Packet template end: %X\n" + "Queue memory start: %X\n" + "Queue memory end: %X\n" + "Packet memory pool start: %X\n" + "Packet memory pool end: %X\n" + "iobase: %p\n" + "iobase2: %p\n", + *((u16 *)&memmap[0x02]), (int) sizeof(memmap), + *((u32 *)&memmap[0x04]), + *((u32 *)&memmap[0x08]), + *((u32 *)&memmap[0x0C]), + *((u32 *)&memmap[0x10]), + *((u32 *)&memmap[0x14]), + *((u32 *)&memmap[0x18]), + *((u32 *)&memmap[0x1C]), + *((u32 *)&memmap[0x20]), + *((u32 *)&memmap[0x24]), + *((u32 *)&memmap[0x28]), + *((u32 *)&memmap[0x2C]), + *((u32 *)&memmap[0x30]), + adev->iobase, + adev->iobase2); + + /* dump Acx111 Rx Config */ + printk("dump rx config:\n" + "data read: %d, struct size: %d\n" + "rx config: %X\n" + "rx filter config: %X\n", + *((u16 *)&rxconfig[0x02]), (int) sizeof(rxconfig), + *((u16 *)&rxconfig[0x04]), + *((u16 *)&rxconfig[0x06])); + + /* dump Acx111 fcs error */ + printk("dump fcserror:\n" + "data read: %d, struct size: %d\n" + "fcserrors: %X\n", + *((u16 *)&fcserror[0x02]), (int) sizeof(fcserror), + *((u32 *)&fcserror[0x04])); + + /* dump Acx111 rate fallback */ + printk("dump rate fallback:\n" + "data read: %d, struct size: %d\n" + "ratefallback: %X\n", + *((u16 *)&ratefallback[0x02]), (int) sizeof(ratefallback), + *((u8 *)&ratefallback[0x04])); + + /* protect against IRQ */ + acx_lock(adev, flags); + + /* dump acx111 internal rx descriptor ring buffer */ + rxdesc = adev->rxdesc_start; + + /* loop over complete receive pool */ + if (rxdesc) for (i = 0; i < RX_CNT; i++) { + printk("\ndump internal rxdesc %d:\n" + "mem pos %p\n" + "next 0x%X\n" + "acx mem pointer (dynamic) 0x%X\n" + "CTL (dynamic) 0x%X\n" + "Rate (dynamic) 0x%X\n" + "RxStatus (dynamic) 0x%X\n" + "Mod/Pre (dynamic) 0x%X\n", + i, + rxdesc, + acx2cpu(rxdesc->pNextDesc), + acx2cpu(rxdesc->ACXMemPtr), + rxdesc->Ctl_8, + rxdesc->rate, + rxdesc->error, + rxdesc->SNR); + rxdesc++; + } + + /* dump host rx descriptor ring buffer */ + + rxhostdesc = adev->rxhostdesc_start; + + /* loop over complete receive pool */ + if (rxhostdesc) for (i = 0; i < RX_CNT; i++) { + printk("\ndump host rxdesc %d:\n" + "mem pos %p\n" + "buffer mem pos 0x%X\n" + "buffer mem offset 0x%X\n" + "CTL 0x%X\n" + "Length 0x%X\n" + "next 0x%X\n" + "Status 0x%X\n", + i, + rxhostdesc, + acx2cpu(rxhostdesc->data_phy), + rxhostdesc->data_offset, + le16_to_cpu(rxhostdesc->Ctl_16), + le16_to_cpu(rxhostdesc->length), + acx2cpu(rxhostdesc->desc_phy_next), + rxhostdesc->Status); + rxhostdesc++; + } + + /* dump acx111 internal tx descriptor ring buffer */ + txdesc = adev->txdesc_start; + + /* loop over complete transmit pool */ + if (txdesc) for (i = 0; i < TX_CNT; i++) { + printk("\ndump internal txdesc %d:\n" + "size 0x%X\n" + "mem pos %p\n" + "next 0x%X\n" + "acx mem pointer (dynamic) 0x%X\n" + "host mem pointer (dynamic) 0x%X\n" + "length (dynamic) 0x%X\n" + "CTL (dynamic) 0x%X\n" + "CTL2 (dynamic) 0x%X\n" + "Status (dynamic) 0x%X\n" + "Rate (dynamic) 0x%X\n", + i, + (int) sizeof(struct txdesc), + txdesc, + acx2cpu(txdesc->pNextDesc), + acx2cpu(txdesc->AcxMemPtr), + acx2cpu(txdesc->HostMemPtr), + le16_to_cpu(txdesc->total_length), + txdesc->Ctl_8, + txdesc->Ctl2_8, txdesc->error, + txdesc->u.r1.rate); + txdesc = advance_txdesc(adev, txdesc, 1); + } + + /* dump host tx descriptor ring buffer */ + + txhostdesc = adev->txhostdesc_start; + + /* loop over complete host send pool */ + if (txhostdesc) for (i = 0; i < TX_CNT * 2; i++) { + printk("\ndump host txdesc %d:\n" + "mem pos %p\n" + "buffer mem pos 0x%X\n" + "buffer mem offset 0x%X\n" + "CTL 0x%X\n" + "Length 0x%X\n" + "next 0x%X\n" + "Status 0x%X\n", + i, + txhostdesc, + acx2cpu(txhostdesc->data_phy), + txhostdesc->data_offset, + le16_to_cpu(txhostdesc->Ctl_16), + le16_to_cpu(txhostdesc->length), + acx2cpu(txhostdesc->desc_phy_next), + le32_to_cpu(txhostdesc->Status)); + txhostdesc++; + } + + /* write_reg16(adev, 0xb4, 0x4); */ + + acx_unlock(adev, flags); +end_ok: + + acx_sem_unlock(adev); +#endif /* ACX_DEBUG */ + return OK; +} + + +/*********************************************************************** +*/ +int +acx100pci_ioctl_set_phy_amp_bias( + struct net_device *ndev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + unsigned long flags; + u16 gpio_old; + + if (!IS_ACX100(adev)) { + /* WARNING!!! + * Removing this check *might* damage + * hardware, since we're tweaking GPIOs here after all!!! + * You've been warned... + * WARNING!!! */ + printk("acx: sorry, setting bias level for non-acx100 " + "is not supported yet\n"); + return OK; + } + + if (*extra > 7) { + printk("acx: invalid bias parameter, range is 0-7\n"); + return -EINVAL; + } + + acx_sem_lock(adev); + + /* Need to lock accesses to [IO_ACX_GPIO_OUT]: + * IRQ handler uses it to update LED */ + acx_lock(adev, flags); + gpio_old = read_reg16(adev, IO_ACX_GPIO_OUT); + write_reg16(adev, IO_ACX_GPIO_OUT, (gpio_old & 0xf8ff) | ((u16)*extra << 8)); + acx_unlock(adev, flags); + + log(L_DEBUG, "gpio_old: 0x%04X\n", gpio_old); + printk("%s: PHY power amplifier bias: old:%d, new:%d\n", + ndev->name, + (gpio_old & 0x0700) >> 8, (unsigned char)*extra); + + acx_sem_unlock(adev); + + return OK; +} + + +/*************************************************************** +** acxpci_l_alloc_tx +** Actually returns a txdesc_t* ptr +** +** FIXME: in case of fragments, should allocate multiple descrs +** after figuring out how many we need and whether we still have +** sufficiently many. +*/ +tx_t* +acxpci_l_alloc_tx(acx_device_t *adev) +{ + struct txdesc *txdesc; + unsigned head; + u8 ctl8; + + FN_ENTER; + + if (unlikely(!adev->tx_free)) { + printk("acx: BUG: no free txdesc left\n"); + txdesc = NULL; + goto end; + } + + head = adev->tx_head; + txdesc = get_txdesc(adev, head); + ctl8 = txdesc->Ctl_8; + + /* 2005-10-11: there were several bug reports on this happening + ** but now cause seems to be understood & fixed */ + if (unlikely(DESC_CTL_HOSTOWN != (ctl8 & DESC_CTL_ACXDONE_HOSTOWN))) { + /* whoops, descr at current index is not free, so probably + * ring buffer already full */ + printk("acx: BUG: tx_head:%d Ctl8:0x%02X - failed to find " + "free txdesc\n", head, ctl8); + txdesc = NULL; + goto end; + } + + /* Needed in case txdesc won't be eventually submitted for tx */ + txdesc->Ctl_8 = DESC_CTL_ACXDONE_HOSTOWN; + + adev->tx_free--; + log(L_BUFT, "tx: got desc %u, %u remain\n", + head, adev->tx_free); + /* Keep a few free descs between head and tail of tx ring. + ** It is not absolutely needed, just feels safer */ + if (adev->tx_free < TX_STOP_QUEUE) { + log(L_BUF, "stop queue (%u tx desc left)\n", + adev->tx_free); + acx_stop_queue(adev->ndev, NULL); + } + + /* returning current descriptor, so advance to next free one */ + adev->tx_head = (head + 1) % TX_CNT; +end: + FN_EXIT0; + + return (tx_t*)txdesc; +} + + +/*********************************************************************** +*/ +void* +acxpci_l_get_txbuf(acx_device_t *adev, tx_t* tx_opaque) +{ + return get_txhostdesc(adev, (txdesc_t*)tx_opaque)->data; +} + + +/*********************************************************************** +** acxpci_l_tx_data +** +** Can be called from IRQ (rx -> (AP bridging or mgmt response) -> tx). +** Can be called from acx_i_start_xmit (data frames from net core). +** +** FIXME: in case of fragments, should loop over the number of +** pre-allocated tx descrs, properly setting up transfer data and +** CTL_xxx flags according to fragment number. +*/ +void +acxpci_l_tx_data(acx_device_t *adev, tx_t* tx_opaque, int len) +{ + txdesc_t *txdesc = (txdesc_t*)tx_opaque; + txhostdesc_t *hostdesc1, *hostdesc2; + client_t *clt; + u16 rate_cur; + u8 Ctl_8, Ctl2_8; + + FN_ENTER; + + /* fw doesn't tx such packets anyhow */ + if (unlikely(len < WLAN_HDR_A3_LEN)) + goto end; + + hostdesc1 = get_txhostdesc(adev, txdesc); + /* modify flag status in separate variable to be able to write it back + * in one big swoop later (also in order to have less device memory + * accesses) */ + Ctl_8 = txdesc->Ctl_8; + Ctl2_8 = 0; /* really need to init it to 0, not txdesc->Ctl2_8, it seems */ + + hostdesc2 = hostdesc1 + 1; + + /* DON'T simply set Ctl field to 0 here globally, + * it needs to maintain a consistent flag status (those are state flags!!), + * otherwise it may lead to severe disruption. Only set or reset particular + * flags at the exact moment this is needed... */ + + /* let chip do RTS/CTS handshaking before sending + * in case packet size exceeds threshold */ + if (len > adev->rts_threshold) + SET_BIT(Ctl2_8, DESC_CTL2_RTS); + else + CLEAR_BIT(Ctl2_8, DESC_CTL2_RTS); + + switch (adev->mode) { + case ACX_MODE_0_ADHOC: + case ACX_MODE_3_AP: + clt = acx_l_sta_list_get(adev, ((wlan_hdr_t*)hostdesc1->data)->a1); + break; + case ACX_MODE_2_STA: + clt = adev->ap_client; + break; +#if 0 +/* testing was done on acx111: */ + case ACX_MODE_MONITOR: + SET_BIT(Ctl2_8, 0 +/* sends CTS to self before packet */ + + DESC_CTL2_SEQ /* don't increase sequence field */ +/* not working (looks like good fcs is still added) */ + + DESC_CTL2_FCS /* don't add the FCS */ +/* not tested */ + + DESC_CTL2_MORE_FRAG +/* not tested */ + + DESC_CTL2_RETRY /* don't increase retry field */ +/* not tested */ + + DESC_CTL2_POWER /* don't increase power mgmt. field */ +/* no effect */ + + DESC_CTL2_WEP /* encrypt this frame */ +/* not tested */ + + DESC_CTL2_DUR /* don't increase duration field */ + ); + /* fallthrough */ +#endif + default: /* ACX_MODE_OFF, ACX_MODE_MONITOR */ + clt = NULL; + break; + } + + rate_cur = clt ? clt->rate_cur : adev->rate_bcast; + if (unlikely(!rate_cur)) { + printk("acx: driver bug! bad ratemask\n"); + goto end; + } + + /* used in tx cleanup routine for auto rate and accounting: */ + put_txcr(adev, txdesc, clt, rate_cur); + + txdesc->total_length = cpu_to_le16(len); + hostdesc2->length = cpu_to_le16(len - WLAN_HDR_A3_LEN); + if (IS_ACX111(adev)) { + /* note that if !txdesc->do_auto, txrate->cur + ** has only one nonzero bit */ + txdesc->u.r2.rate111 = cpu_to_le16( + rate_cur + /* WARNING: I was never able to make it work with prism54 AP. + ** It was falling down to 1Mbit where shortpre is not applicable, + ** and not working at all at "5,11 basic rates only" setting. + ** I even didn't see tx packets in radio packet capture. + ** Disabled for now --vda */ + /*| ((clt->shortpre && clt->cur!=RATE111_1) ? RATE111_SHORTPRE : 0) */ + ); +#ifdef TODO_FIGURE_OUT_WHEN_TO_SET_THIS + /* should add this to rate111 above as necessary */ + | (clt->pbcc511 ? RATE111_PBCC511 : 0) +#endif + hostdesc1->length = cpu_to_le16(len); + } else { /* ACX100 */ + u8 rate_100 = clt ? clt->rate_100 : adev->rate_bcast100; + txdesc->u.r1.rate = rate_100; +#ifdef TODO_FIGURE_OUT_WHEN_TO_SET_THIS + if (clt->pbcc511) { + if (n == RATE100_5 || n == RATE100_11) + n |= RATE100_PBCC511; + } + + if (clt->shortpre && (clt->cur != RATE111_1)) + SET_BIT(Ctl_8, DESC_CTL_SHORT_PREAMBLE); /* set Short Preamble */ +#endif + /* set autodma and reclaim and 1st mpdu */ + SET_BIT(Ctl_8, DESC_CTL_AUTODMA | DESC_CTL_RECLAIM | DESC_CTL_FIRSTFRAG); +#if ACX_FRAGMENTATION + /* SET_BIT(Ctl2_8, DESC_CTL2_MORE_FRAG); cannot set it unconditionally, needs to be set for all non-last fragments */ +#endif + hostdesc1->length = cpu_to_le16(WLAN_HDR_A3_LEN); + } + /* don't need to clean ack/rts statistics here, already + * done on descr cleanup */ + + /* clears HOSTOWN and ACXDONE bits, thus telling that the descriptors + * are now owned by the acx100; do this as LAST operation */ + CLEAR_BIT(Ctl_8, DESC_CTL_ACXDONE_HOSTOWN); + /* flush writes before we release hostdesc to the adapter here */ + wmb(); + CLEAR_BIT(hostdesc1->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN)); + CLEAR_BIT(hostdesc2->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN)); + + /* write back modified flags */ + txdesc->Ctl2_8 = Ctl2_8; + txdesc->Ctl_8 = Ctl_8; + /* unused: txdesc->tx_time = cpu_to_le32(jiffies); */ + + /* flush writes before we tell the adapter that it's its turn now */ + mmiowb(); + write_reg16(adev, IO_ACX_INT_TRIG, INT_TRIG_TXPRC); + write_flush(adev); + + /* log the packet content AFTER sending it, + * in order to not delay sending any further than absolutely needed + * Do separate logs for acx100/111 to have human-readable rates */ + if (unlikely(acx_debug & (L_XFER|L_DATA))) { + u16 fc = ((wlan_hdr_t*)hostdesc1->data)->fc; + if (IS_ACX111(adev)) + printk("tx: pkt (%s): len %d " + "rate %04X%s status %u\n", + acx_get_packet_type_string(le16_to_cpu(fc)), len, + le16_to_cpu(txdesc->u.r2.rate111), + (le16_to_cpu(txdesc->u.r2.rate111) & RATE111_SHORTPRE) ? "(SPr)" : "", + adev->status); + else + printk("tx: pkt (%s): len %d rate %03u%s status %u\n", + acx_get_packet_type_string(fc), len, + txdesc->u.r1.rate, + (Ctl_8 & DESC_CTL_SHORT_PREAMBLE) ? "(SPr)" : "", + adev->status); + + if (acx_debug & L_DATA) { + printk("tx: 802.11 [%d]: ", len); + acx_dump_bytes(hostdesc1->data, len); + } + } +end: + FN_EXIT0; +} + + +/*********************************************************************** +** acxpci_l_clean_txdesc +** +** This function resets the txdescs' status when the ACX100 +** signals the TX done IRQ (txdescs have been processed), starting with +** the pool index of the descriptor which we would use next, +** in order to make sure that we can be as fast as possible +** in filling new txdescs. +** Everytime we get called we know where the next packet to be cleaned is. +*/ + +#if !ACX_DEBUG +static inline void log_txbuffer(const acx_device_t *adev) {} +#else +static void +log_txbuffer(acx_device_t *adev) +{ + txdesc_t *txdesc; + int i; + + /* no FN_ENTER here, we don't want that */ + /* no locks here, since it's entirely non-critical code */ + txdesc = adev->txdesc_start; + if (unlikely(!txdesc)) return; + printk("tx: desc->Ctl8's:"); + for (i = 0; i < TX_CNT; i++) { + printk(" %02X", txdesc->Ctl_8); + txdesc = advance_txdesc(adev, txdesc, 1); + } + printk("\n"); +} +#endif + + +static void +handle_tx_error(acx_device_t *adev, u8 error, unsigned int finger) +{ + const char *err = "unknown error"; + + /* hmm, should we handle this as a mask + * of *several* bits? + * For now I think only caring about + * individual bits is ok... */ + switch (error) { + case 0x01: + err = "no Tx due to error in other fragment"; + adev->wstats.discard.fragment++; + break; + case 0x02: + err = "Tx aborted"; + adev->stats.tx_aborted_errors++; + break; + case 0x04: + err = "Tx desc wrong parameters"; + adev->wstats.discard.misc++; + break; + case 0x08: + err = "WEP key not found"; + adev->wstats.discard.misc++; + break; + case 0x10: + err = "MSDU lifetime timeout? - try changing " + "'iwconfig retry lifetime XXX'"; + adev->wstats.discard.misc++; + break; + case 0x20: + err = "excessive Tx retries due to either distance " + "too high or unable to Tx or Tx frame error - " + "try changing 'iwconfig txpower XXX' or " + "'sens'itivity or 'retry'"; + adev->wstats.discard.retries++; + /* Tx error 0x20 also seems to occur on + * overheating, so I'm not sure whether we + * actually want to do aggressive radio recalibration, + * since people maybe won't notice then that their hardware + * is slowly getting cooked... + * Or is it still a safe long distance from utter + * radio non-functionality despite many radio recalibs + * to final destructive overheating of the hardware? + * In this case we really should do recalib here... + * I guess the only way to find out is to do a + * potentially fatal self-experiment :-\ + * Or maybe only recalib in case we're using Tx + * rate auto (on errors switching to lower speed + * --> less heat?) or 802.11 power save mode? + * + * ok, just do it. */ + if (++adev->retry_errors_msg_ratelimit % 4 == 0) { + if (adev->retry_errors_msg_ratelimit <= 20) { + printk("%s: several excessive Tx " + "retry errors occurred, attempting " + "to recalibrate radio. Radio " + "drift might be caused by increasing " + "card temperature, please check the card " + "before it's too late!\n", + adev->ndev->name); + if (adev->retry_errors_msg_ratelimit == 20) + printk("disabling above message\n"); + } + + acx_schedule_task(adev, ACX_AFTER_IRQ_CMD_RADIO_RECALIB); + } + break; + case 0x40: + err = "Tx buffer overflow"; + adev->stats.tx_fifo_errors++; + break; + case 0x80: + /* possibly ACPI C-state powersaving related!!! + * (DMA timeout due to excessively high wakeup + * latency after C-state activation!?) + * Disable C-State powersaving and try again, + * then PLEASE REPORT, I'm VERY interested in + * whether my theory is correct that this is + * actually the problem here. + * In that case, use new Linux idle wakeup latency + * requirements kernel API to prevent this issue. */ + err = "DMA error"; + adev->wstats.discard.misc++; + break; + } + adev->stats.tx_errors++; + if (adev->stats.tx_errors <= 20) + printk("%s: tx error 0x%02X, buf %02u! (%s)\n", + adev->ndev->name, error, finger, err); + else + printk("%s: tx error 0x%02X, buf %02u!\n", + adev->ndev->name, error, finger); +} + + +unsigned int +acxpci_l_clean_txdesc(acx_device_t *adev) +{ + txdesc_t *txdesc; + unsigned finger; + int num_cleaned; + u16 r111; + u8 error, ack_failures, rts_failures, rts_ok, r100; + + FN_ENTER; + + if (unlikely(acx_debug & L_DEBUG)) + log_txbuffer(adev); + + log(L_BUFT, "tx: cleaning up bufs from %u\n", adev->tx_tail); + + /* We know first descr which is not free yet. We advance it as far + ** as we see correct bits set in following descs (if next desc + ** is NOT free, we shouldn't advance at all). We know that in + ** front of tx_tail may be "holes" with isolated free descs. + ** We will catch up when all intermediate descs will be freed also */ + + finger = adev->tx_tail; + num_cleaned = 0; + while (likely(finger != adev->tx_head)) { + txdesc = get_txdesc(adev, finger); + + /* If we allocated txdesc on tx path but then decided + ** to NOT use it, then it will be left as a free "bubble" + ** in the "allocated for tx" part of the ring. + ** We may meet it on the next ring pass here. */ + + /* stop if not marked as "tx finished" and "host owned" */ + if ((txdesc->Ctl_8 & DESC_CTL_ACXDONE_HOSTOWN) + != DESC_CTL_ACXDONE_HOSTOWN) { + if (unlikely(!num_cleaned)) { /* maybe remove completely */ + log(L_BUFT, "clean_txdesc: tail isn't free. " + "tail:%d head:%d\n", + adev->tx_tail, adev->tx_head); + } + break; + } + + /* remember desc values... */ + error = txdesc->error; + ack_failures = txdesc->ack_failures; + rts_failures = txdesc->rts_failures; + rts_ok = txdesc->rts_ok; + r100 = txdesc->u.r1.rate; + r111 = le16_to_cpu(txdesc->u.r2.rate111); + + /* need to check for certain error conditions before we + * clean the descriptor: we still need valid descr data here */ + if (unlikely(0x30 & error)) { + /* only send IWEVTXDROP in case of retry or lifetime exceeded; + * all other errors mean we screwed up locally */ + union iwreq_data wrqu; + wlan_hdr_t *hdr; + txhostdesc_t *hostdesc; + + hostdesc = get_txhostdesc(adev, txdesc); + hdr = (wlan_hdr_t *)hostdesc->data; + MAC_COPY(wrqu.addr.sa_data, hdr->a1); + wireless_send_event(adev->ndev, IWEVTXDROP, &wrqu, NULL); + } + + /* ...and free the desc */ + txdesc->error = 0; + txdesc->ack_failures = 0; + txdesc->rts_failures = 0; + txdesc->rts_ok = 0; + /* signal host owning it LAST, since ACX already knows that this + ** descriptor is finished since it set Ctl_8 accordingly. */ + txdesc->Ctl_8 = DESC_CTL_HOSTOWN; + + adev->tx_free++; + num_cleaned++; + + if ((adev->tx_free >= TX_START_QUEUE) + && (adev->status == ACX_STATUS_4_ASSOCIATED) + && (acx_queue_stopped(adev->ndev)) + ) { + log(L_BUF, "tx: wake queue (avail. Tx desc %u)\n", + adev->tx_free); + acx_wake_queue(adev->ndev, NULL); + } + + /* do error checking, rate handling and logging + * AFTER having done the work, it's faster */ + + /* do rate handling */ + if (adev->rate_auto) { + struct client *clt = get_txc(adev, txdesc); + if (clt) { + u16 cur = get_txr(adev, txdesc); + if (clt->rate_cur == cur) { + acx_l_handle_txrate_auto(adev, clt, + cur, /* intended rate */ + r100, r111, /* actually used rate */ + (error & 0x30), /* was there an error? */ + TX_CNT + TX_CLEAN_BACKLOG - adev->tx_free); + } + } + } + + if (unlikely(error)) + handle_tx_error(adev, error, finger); + + if (IS_ACX111(adev)) + log(L_BUFT, "tx: cleaned %u: !ACK=%u !RTS=%u RTS=%u r111=%04X\n", + finger, ack_failures, rts_failures, rts_ok, r111); + else + log(L_BUFT, "tx: cleaned %u: !ACK=%u !RTS=%u RTS=%u rate=%u\n", + finger, ack_failures, rts_failures, rts_ok, r100); + + /* update pointer for descr to be cleaned next */ + finger = (finger + 1) % TX_CNT; + } + + /* remember last position */ + adev->tx_tail = finger; +/* end: */ + FN_EXIT1(num_cleaned); + return num_cleaned; +} + +/* clean *all* Tx descriptors, and regardless of their previous state. + * Used for brute-force reset handling. */ +void +acxpci_l_clean_txdesc_emergency(acx_device_t *adev) +{ + txdesc_t *txdesc; + int i; + + FN_ENTER; + + for (i = 0; i < TX_CNT; i++) { + txdesc = get_txdesc(adev, i); + + /* free it */ + txdesc->ack_failures = 0; + txdesc->rts_failures = 0; + txdesc->rts_ok = 0; + txdesc->error = 0; + txdesc->Ctl_8 = DESC_CTL_HOSTOWN; + } + + adev->tx_free = TX_CNT; + + FN_EXIT0; +} + + +/*********************************************************************** +** acxpci_s_create_tx_host_desc_queue +*/ + +static void* +allocate(acx_device_t *adev, size_t size, dma_addr_t *phy, const char *msg) +{ + void *ptr; + + ptr = dma_alloc_coherent(adev->pdev ? &adev->pdev->dev : NULL, + size, phy, GFP_KERNEL); + + if (ptr) { + log(L_DEBUG, "%s sz=%d adr=0x%p phy=0x%08llx\n", + msg, (int)size, ptr, (unsigned long long)*phy); + memset(ptr, 0, size); + return ptr; + } + printk(KERN_ERR "acx: %s allocation FAILED (%d bytes)\n", + msg, (int)size); + return NULL; +} + + +static int +acxpci_s_create_tx_host_desc_queue(acx_device_t *adev) +{ + txhostdesc_t *hostdesc; + u8 *txbuf; + dma_addr_t hostdesc_phy; + dma_addr_t txbuf_phy; + int i; + + FN_ENTER; + + /* allocate TX buffer */ + adev->txbuf_area_size = TX_CNT * WLAN_A4FR_MAXLEN_WEP_FCS; + adev->txbuf_start = allocate(adev, adev->txbuf_area_size, + &adev->txbuf_startphy, "txbuf_start"); + if (!adev->txbuf_start) + goto fail; + + /* allocate the TX host descriptor queue pool */ + adev->txhostdesc_area_size = TX_CNT * 2*sizeof(*hostdesc); + adev->txhostdesc_start = allocate(adev, adev->txhostdesc_area_size, + &adev->txhostdesc_startphy, "txhostdesc_start"); + if (!adev->txhostdesc_start) + goto fail; + /* check for proper alignment of TX host descriptor pool */ + if ((long) adev->txhostdesc_start & 3) { + printk("acx: driver bug: dma alloc returns unaligned address\n"); + goto fail; + } + + hostdesc = adev->txhostdesc_start; + hostdesc_phy = adev->txhostdesc_startphy; + txbuf = adev->txbuf_start; + txbuf_phy = adev->txbuf_startphy; + +#if 0 +/* Each tx buffer is accessed by hardware via +** txdesc -> txhostdesc(s) -> txbuffer(s). +** We use only one txhostdesc per txdesc, but it looks like +** acx111 is buggy: it accesses second txhostdesc +** (via hostdesc.desc_phy_next field) even if +** txdesc->length == hostdesc->length and thus +** entire packet was placed into first txhostdesc. +** Due to this bug acx111 hangs unless second txhostdesc +** has le16_to_cpu(hostdesc.length) = 3 (or larger) +** Storing NULL into hostdesc.desc_phy_next +** doesn't seem to help. +** +** Update: although it worked on Xterasys XN-2522g +** with len=3 trick, WG311v2 is even more bogus, doesn't work. +** Keeping this code (#ifdef'ed out) for documentational purposes. +*/ + for (i = 0; i < TX_CNT*2; i++) { + hostdesc_phy += sizeof(*hostdesc); + if (!(i & 1)) { + hostdesc->data_phy = cpu2acx(txbuf_phy); + /* hostdesc->data_offset = ... */ + /* hostdesc->reserved = ... */ + hostdesc->Ctl_16 = cpu_to_le16(DESC_CTL_HOSTOWN); + /* hostdesc->length = ... */ + hostdesc->desc_phy_next = cpu2acx(hostdesc_phy); + hostdesc->pNext = ptr2acx(NULL); + /* hostdesc->Status = ... */ + /* below: non-hardware fields */ + hostdesc->data = txbuf; + + txbuf += WLAN_A4FR_MAXLEN_WEP_FCS; + txbuf_phy += WLAN_A4FR_MAXLEN_WEP_FCS; + } else { + /* hostdesc->data_phy = ... */ + /* hostdesc->data_offset = ... */ + /* hostdesc->reserved = ... */ + /* hostdesc->Ctl_16 = ... */ + hostdesc->length = cpu_to_le16(3); /* bug workaround */ + /* hostdesc->desc_phy_next = ... */ + /* hostdesc->pNext = ... */ + /* hostdesc->Status = ... */ + /* below: non-hardware fields */ + /* hostdesc->data = ... */ + } + hostdesc++; + } +#endif +/* We initialize two hostdescs so that they point to adjacent +** memory areas. Thus txbuf is really just a contiguous memory area */ + for (i = 0; i < TX_CNT*2; i++) { + hostdesc_phy += sizeof(*hostdesc); + + hostdesc->data_phy = cpu2acx(txbuf_phy); + /* done by memset(0): hostdesc->data_offset = 0; */ + /* hostdesc->reserved = ... */ + hostdesc->Ctl_16 = cpu_to_le16(DESC_CTL_HOSTOWN); + /* hostdesc->length = ... */ + hostdesc->desc_phy_next = cpu2acx(hostdesc_phy); + /* done by memset(0): hostdesc->pNext = ptr2acx(NULL); */ + /* hostdesc->Status = ... */ + /* ->data is a non-hardware field: */ + hostdesc->data = txbuf; + + if (!(i & 1)) { + txbuf += WLAN_HDR_A3_LEN; + txbuf_phy += WLAN_HDR_A3_LEN; + } else { + txbuf += WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_HDR_A3_LEN; + txbuf_phy += WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_HDR_A3_LEN; + } + hostdesc++; + } + hostdesc--; + hostdesc->desc_phy_next = cpu2acx(adev->txhostdesc_startphy); + + FN_EXIT1(OK); + return OK; +fail: + printk("acx: create_tx_host_desc_queue FAILED\n"); + /* dealloc will be done by free function on error case */ + FN_EXIT1(NOT_OK); + return NOT_OK; +} + + +/*************************************************************** +** acxpci_s_create_rx_host_desc_queue +*/ +/* the whole size of a data buffer (header plus data body) + * plus 32 bytes safety offset at the end */ +#define RX_BUFFER_SIZE (sizeof(rxbuffer_t) + 32) + +static int +acxpci_s_create_rx_host_desc_queue(acx_device_t *adev) +{ + rxhostdesc_t *hostdesc; + rxbuffer_t *rxbuf; + dma_addr_t hostdesc_phy; + dma_addr_t rxbuf_phy; + int i; + + FN_ENTER; + + /* allocate the RX host descriptor queue pool */ + adev->rxhostdesc_area_size = RX_CNT * sizeof(*hostdesc); + adev->rxhostdesc_start = allocate(adev, adev->rxhostdesc_area_size, + &adev->rxhostdesc_startphy, "rxhostdesc_start"); + if (!adev->rxhostdesc_start) + goto fail; + /* check for proper alignment of RX host descriptor pool */ + if ((long) adev->rxhostdesc_start & 3) { + printk("acx: driver bug: dma alloc returns unaligned address\n"); + goto fail; + } + + /* allocate Rx buffer pool which will be used by the acx + * to store the whole content of the received frames in it */ + adev->rxbuf_area_size = RX_CNT * RX_BUFFER_SIZE; + adev->rxbuf_start = allocate(adev, adev->rxbuf_area_size, + &adev->rxbuf_startphy, "rxbuf_start"); + if (!adev->rxbuf_start) + goto fail; + + rxbuf = adev->rxbuf_start; + rxbuf_phy = adev->rxbuf_startphy; + hostdesc = adev->rxhostdesc_start; + hostdesc_phy = adev->rxhostdesc_startphy; + + /* don't make any popular C programming pointer arithmetic mistakes + * here, otherwise I'll kill you... + * (and don't dare asking me why I'm warning you about that...) */ + for (i = 0; i < RX_CNT; i++) { + hostdesc->data = rxbuf; + hostdesc->data_phy = cpu2acx(rxbuf_phy); + hostdesc->length = cpu_to_le16(RX_BUFFER_SIZE); + CLEAR_BIT(hostdesc->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN)); + rxbuf++; + rxbuf_phy += sizeof(*rxbuf); + hostdesc_phy += sizeof(*hostdesc); + hostdesc->desc_phy_next = cpu2acx(hostdesc_phy); + hostdesc++; + } + hostdesc--; + hostdesc->desc_phy_next = cpu2acx(adev->rxhostdesc_startphy); + FN_EXIT1(OK); + return OK; +fail: + printk("acx: create_rx_host_desc_queue FAILED\n"); + /* dealloc will be done by free function on error case */ + FN_EXIT1(NOT_OK); + return NOT_OK; +} + + +/*************************************************************** +** acxpci_s_create_hostdesc_queues +*/ +int +acxpci_s_create_hostdesc_queues(acx_device_t *adev) +{ + int result; + result = acxpci_s_create_tx_host_desc_queue(adev); + if (OK != result) return result; + result = acxpci_s_create_rx_host_desc_queue(adev); + return result; +} + + +/*************************************************************** +** acxpci_create_tx_desc_queue +*/ +static void +acxpci_create_tx_desc_queue(acx_device_t *adev, u32 tx_queue_start) +{ + txdesc_t *txdesc; + txhostdesc_t *hostdesc; + dma_addr_t hostmemptr; + u32 mem_offs; + int i; + + FN_ENTER; + + if (IS_ACX100(adev)) + adev->txdesc_size = sizeof(*txdesc); + else + /* the acx111 txdesc is 4 bytes larger */ + adev->txdesc_size = sizeof(*txdesc) + 4; + + adev->txdesc_start = (txdesc_t *) (adev->iobase2 + tx_queue_start); + + log(L_DEBUG, "adev->iobase2=%p\n" + "tx_queue_start=%08X\n" + "adev->txdesc_start=%p\n", + adev->iobase2, + tx_queue_start, + adev->txdesc_start); + + adev->tx_free = TX_CNT; + /* done by memset: adev->tx_head = 0; */ + /* done by memset: adev->tx_tail = 0; */ + txdesc = adev->txdesc_start; + mem_offs = tx_queue_start; + hostmemptr = adev->txhostdesc_startphy; + hostdesc = adev->txhostdesc_start; + + if (IS_ACX111(adev)) { + /* ACX111 has a preinitialized Tx buffer! */ + /* loop over whole send pool */ + /* FIXME: do we have to do the hostmemptr stuff here?? */ + for (i = 0; i < TX_CNT; i++) { + txdesc->HostMemPtr = ptr2acx(hostmemptr); + txdesc->Ctl_8 = DESC_CTL_HOSTOWN; + /* reserve two (hdr desc and payload desc) */ + hostdesc += 2; + hostmemptr += 2 * sizeof(*hostdesc); + txdesc = advance_txdesc(adev, txdesc, 1); + } + } else { + /* ACX100 Tx buffer needs to be initialized by us */ + /* clear whole send pool. sizeof is safe here (we are acx100) */ + memset(adev->txdesc_start, 0, TX_CNT * sizeof(*txdesc)); + + /* loop over whole send pool */ + for (i = 0; i < TX_CNT; i++) { + log(L_DEBUG, "configure card tx descriptor: 0x%p, " + "size: 0x%X\n", txdesc, adev->txdesc_size); + + /* pointer to hostdesc memory */ + txdesc->HostMemPtr = ptr2acx(hostmemptr); + /* initialise ctl */ + txdesc->Ctl_8 = ( DESC_CTL_HOSTOWN | DESC_CTL_RECLAIM + | DESC_CTL_AUTODMA | DESC_CTL_FIRSTFRAG); + /* done by memset(0): txdesc->Ctl2_8 = 0; */ + /* point to next txdesc */ + txdesc->pNextDesc = cpu2acx(mem_offs + adev->txdesc_size); + /* reserve two (hdr desc and payload desc) */ + hostdesc += 2; + hostmemptr += 2 * sizeof(*hostdesc); + /* go to the next one */ + mem_offs += adev->txdesc_size; + /* ++ is safe here (we are acx100) */ + txdesc++; + } + /* go back to the last one */ + txdesc--; + /* and point to the first making it a ring buffer */ + txdesc->pNextDesc = cpu2acx(tx_queue_start); + } + FN_EXIT0; +} + + +/*************************************************************** +** acxpci_create_rx_desc_queue +*/ +static void +acxpci_create_rx_desc_queue(acx_device_t *adev, u32 rx_queue_start) +{ + rxdesc_t *rxdesc; + u32 mem_offs; + int i; + + FN_ENTER; + + /* done by memset: adev->rx_tail = 0; */ + + /* ACX111 doesn't need any further config: preconfigures itself. + * Simply print ring buffer for debugging */ + if (IS_ACX111(adev)) { + /* rxdesc_start already set here */ + + adev->rxdesc_start = (rxdesc_t *) ((u8 *)adev->iobase2 + rx_queue_start); + + rxdesc = adev->rxdesc_start; + for (i = 0; i < RX_CNT; i++) { + log(L_DEBUG, "rx descriptor %d @ 0x%p\n", i, rxdesc); + rxdesc = adev->rxdesc_start = (rxdesc_t *) + (adev->iobase2 + acx2cpu(rxdesc->pNextDesc)); + } + } else { + /* we didn't pre-calculate rxdesc_start in case of ACX100 */ + /* rxdesc_start should be right AFTER Tx pool */ + adev->rxdesc_start = (rxdesc_t *) + ((u8 *) adev->txdesc_start + (TX_CNT * sizeof(txdesc_t))); + /* NB: sizeof(txdesc_t) above is valid because we know + ** we are in if (acx100) block. Beware of cut-n-pasting elsewhere! + ** acx111's txdesc is larger! */ + + memset(adev->rxdesc_start, 0, RX_CNT * sizeof(*rxdesc)); + + /* loop over whole receive pool */ + rxdesc = adev->rxdesc_start; + mem_offs = rx_queue_start; + for (i = 0; i < RX_CNT; i++) { + log(L_DEBUG, "rx descriptor @ 0x%p\n", rxdesc); + rxdesc->Ctl_8 = DESC_CTL_RECLAIM | DESC_CTL_AUTODMA; + /* point to next rxdesc */ + rxdesc->pNextDesc = cpu2acx(mem_offs + sizeof(*rxdesc)); + /* go to the next one */ + mem_offs += sizeof(*rxdesc); + rxdesc++; + } + /* go to the last one */ + rxdesc--; + + /* and point to the first making it a ring buffer */ + rxdesc->pNextDesc = cpu2acx(rx_queue_start); + } + FN_EXIT0; +} + + +/*************************************************************** +** acxpci_create_desc_queues +*/ +void +acxpci_create_desc_queues(acx_device_t *adev, u32 tx_queue_start, u32 rx_queue_start) +{ + acxpci_create_tx_desc_queue(adev, tx_queue_start); + acxpci_create_rx_desc_queue(adev, rx_queue_start); +} + + +/*************************************************************** +** acxpci_s_proc_diag_output +*/ +char* +acxpci_s_proc_diag_output(char *p, acx_device_t *adev) +{ + const char *rtl, *thd, *ttl; + rxhostdesc_t *rxhostdesc; + txdesc_t *txdesc; + int i; + + FN_ENTER; + + p += sprintf(p, "** Rx buf **\n"); + rxhostdesc = adev->rxhostdesc_start; + if (rxhostdesc) for (i = 0; i < RX_CNT; i++) { + rtl = (i == adev->rx_tail) ? " [tail]" : ""; + if ((rxhostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN)) + && (rxhostdesc->Status & cpu_to_le32(DESC_STATUS_FULL)) ) + p += sprintf(p, "%02u FULL%s\n", i, rtl); + else + p += sprintf(p, "%02u empty%s\n", i, rtl); + rxhostdesc++; + } + p += sprintf(p, "** Tx buf (free %d, Linux netqueue %s) **\n", adev->tx_free, + acx_queue_stopped(adev->ndev) ? "STOPPED" : "running"); + txdesc = adev->txdesc_start; + if (txdesc) for (i = 0; i < TX_CNT; i++) { + thd = (i == adev->tx_head) ? " [head]" : ""; + ttl = (i == adev->tx_tail) ? " [tail]" : ""; + if (txdesc->Ctl_8 & DESC_CTL_ACXDONE) + p += sprintf(p, "%02u free (%02X)%s%s\n", i, txdesc->Ctl_8, thd, ttl); + else + p += sprintf(p, "%02u tx (%02X)%s%s\n", i, txdesc->Ctl_8, thd, ttl); + txdesc = advance_txdesc(adev, txdesc, 1); + } + p += sprintf(p, + "\n" + "** PCI data **\n" + "txbuf_start %p, txbuf_area_size %u, txbuf_startphy %08llx\n" + "txdesc_size %u, txdesc_start %p\n" + "txhostdesc_start %p, txhostdesc_area_size %u, txhostdesc_startphy %08llx\n" + "rxdesc_start %p\n" + "rxhostdesc_start %p, rxhostdesc_area_size %u, rxhostdesc_startphy %08llx\n" + "rxbuf_start %p, rxbuf_area_size %u, rxbuf_startphy %08llx\n", + adev->txbuf_start, adev->txbuf_area_size, + (unsigned long long)adev->txbuf_startphy, + adev->txdesc_size, adev->txdesc_start, + adev->txhostdesc_start, adev->txhostdesc_area_size, + (unsigned long long)adev->txhostdesc_startphy, + adev->rxdesc_start, + adev->rxhostdesc_start, adev->rxhostdesc_area_size, + (unsigned long long)adev->rxhostdesc_startphy, + adev->rxbuf_start, adev->rxbuf_area_size, + (unsigned long long)adev->rxbuf_startphy); + + FN_EXIT0; + return p; +} + + +/*********************************************************************** +*/ +int +acxpci_proc_eeprom_output(char *buf, acx_device_t *adev) +{ + char *p = buf; + int i; + + FN_ENTER; + + for (i = 0; i < 0x400; i++) { + acxpci_read_eeprom_byte(adev, i, p++); + } + + FN_EXIT1(p - buf); + return p - buf; +} + + +/*********************************************************************** +*/ +void +acxpci_set_interrupt_mask(acx_device_t *adev) +{ + if (IS_ACX111(adev)) { + adev->irq_mask = (u16) ~(0 + /* | HOST_INT_RX_DATA */ + | HOST_INT_TX_COMPLETE + /* | HOST_INT_TX_XFER */ + | HOST_INT_RX_COMPLETE + /* | HOST_INT_DTIM */ + /* | HOST_INT_BEACON */ + /* | HOST_INT_TIMER */ + /* | HOST_INT_KEY_NOT_FOUND */ + | HOST_INT_IV_ICV_FAILURE + | HOST_INT_CMD_COMPLETE + | HOST_INT_INFO + /* | HOST_INT_OVERFLOW */ + /* | HOST_INT_PROCESS_ERROR */ + | HOST_INT_SCAN_COMPLETE + | HOST_INT_FCS_THRESHOLD + /* | HOST_INT_UNKNOWN */ + ); + /* Or else acx100 won't signal cmd completion, right? */ + adev->irq_mask_off = (u16)~( HOST_INT_CMD_COMPLETE ); /* 0xfdff */ + } else { + adev->irq_mask = (u16) ~(0 + /* | HOST_INT_RX_DATA */ + | HOST_INT_TX_COMPLETE + /* | HOST_INT_TX_XFER */ + | HOST_INT_RX_COMPLETE + /* | HOST_INT_DTIM */ + /* | HOST_INT_BEACON */ + /* | HOST_INT_TIMER */ + /* | HOST_INT_KEY_NOT_FOUND */ + /* | HOST_INT_IV_ICV_FAILURE */ + | HOST_INT_CMD_COMPLETE + | HOST_INT_INFO + /* | HOST_INT_OVERFLOW */ + /* | HOST_INT_PROCESS_ERROR */ + | HOST_INT_SCAN_COMPLETE + /* | HOST_INT_FCS_THRESHOLD */ + /* | HOST_INT_UNKNOWN */ + ); + adev->irq_mask_off = (u16)~( HOST_INT_UNKNOWN ); /* 0x7fff */ + } +} + + +/*********************************************************************** +*/ +int +acx100pci_s_set_tx_level(acx_device_t *adev, u8 level_dbm) +{ + /* since it can be assumed that at least the Maxim radio has a + * maximum power output of 20dBm and since it also can be + * assumed that these values drive the DAC responsible for + * setting the linear Tx level, I'd guess that these values + * should be the corresponding linear values for a dBm value, + * in other words: calculate the values from that formula: + * Y [dBm] = 10 * log (X [mW]) + * then scale the 0..63 value range onto the 1..100mW range (0..20 dBm) + * and you're done... + * Hopefully that's ok, but you never know if we're actually + * right... (especially since Windows XP doesn't seem to show + * actual Tx dBm values :-P) */ + + /* NOTE: on Maxim, value 30 IS 30mW, and value 10 IS 10mW - so the + * values are EXACTLY mW!!! Not sure about RFMD and others, + * though... */ + static const u8 dbm2val_maxim[21] = { + 63, 63, 63, 62, + 61, 61, 60, 60, + 59, 58, 57, 55, + 53, 50, 47, 43, + 38, 31, 23, 13, + 0 + }; + static const u8 dbm2val_rfmd[21] = { + 0, 0, 0, 1, + 2, 2, 3, 3, + 4, 5, 6, 8, + 10, 13, 16, 20, + 25, 32, 41, 50, + 63 + }; + const u8 *table; + + switch (adev->radio_type) { + case RADIO_MAXIM_0D: + table = &dbm2val_maxim[0]; + break; + case RADIO_RFMD_11: + case RADIO_RALINK_15: + table = &dbm2val_rfmd[0]; + break; + default: + printk("%s: unknown/unsupported radio type, " + "cannot modify tx power level yet!\n", + adev->ndev->name); + return NOT_OK; + } + printk("%s: changing radio power level to %u dBm (%u)\n", + adev->ndev->name, level_dbm, table[level_dbm]); + acxpci_s_write_phy_reg(adev, 0x11, table[level_dbm]); + return OK; +} + + +/*********************************************************************** +** Data for init_module/cleanup_module +*/ +static DEFINE_PCI_DEVICE_TABLE(acxpci_id_tbl) = { + { + .vendor = PCI_VENDOR_ID_TI, + .device = PCI_DEVICE_ID_TI_TNETW1100A, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = CHIPTYPE_ACX100, + }, + { + .vendor = PCI_VENDOR_ID_TI, + .device = PCI_DEVICE_ID_TI_TNETW1100B, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = CHIPTYPE_ACX100, + }, + { + .vendor = PCI_VENDOR_ID_TI, + .device = PCI_DEVICE_ID_TI_TNETW1130, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = CHIPTYPE_ACX111, + }, + { + .vendor = 0, + .device = 0, + .subvendor = 0, + .subdevice = 0, + .driver_data = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, acxpci_id_tbl); + +static struct pci_driver acxpci_driver = { + .name = "acx_pci", + .id_table = acxpci_id_tbl, + .probe = acxpci_e_probe, + .remove = __devexit_p(acxpci_e_remove), +#ifdef CONFIG_PM + .suspend = acxpci_e_suspend, + .resume = acxpci_e_resume +#endif /* CONFIG_PM */ +}; + + +/*********************************************************************** +** acxpci_e_init_module +** +** Module initialization routine, called once at module load time +*/ +int __init +acxpci_e_init_module(void) +{ + int res; + + FN_ENTER; + +#if (ACX_IO_WIDTH==32) + printk("acx: compiled to use 32bit I/O access. " + "I/O timing issues might occur, such as " + "non-working firmware upload. Report them\n"); +#else + printk("acx: compiled to use 16bit I/O access only " + "(compatibility mode)\n"); +#endif + +#ifdef __LITTLE_ENDIAN +#define ENDIANNESS_STRING "running on a little-endian CPU\n" +#else +#define ENDIANNESS_STRING "running on a BIG-ENDIAN CPU\n" +#endif + log(L_INIT, + ENDIANNESS_STRING + "PCI module " ACX_RELEASE " initialized, " + "waiting for cards to probe...\n" + ); + + res = pci_register_driver(&acxpci_driver); + FN_EXIT1(res); + return res; +} + + +/*********************************************************************** +** acxpci_e_cleanup_module +** +** Called at module unload time. This is our last chance to +** clean up after ourselves. +*/ +void __exit +acxpci_e_cleanup_module(void) +{ + FN_ENTER; + + pci_unregister_driver(&acxpci_driver); + + FN_EXIT0; +} --- linux-2.6.27.orig/ubuntu/misc/wireless/acx/wlan.c +++ linux-2.6.27/ubuntu/misc/wireless/acx/wlan.c @@ -0,0 +1,421 @@ +/*********************************************************************** +** Copyright (C) 2003 ACX100 Open Source Project +** +** The contents of this file are subject to the Mozilla Public +** License Version 1.1 (the "License"); you may not use this file +** except in compliance with the License. You may obtain a copy of +** the License at http://www.mozilla.org/MPL/ +** +** Software distributed under the License is distributed on an "AS +** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +** implied. See the License for the specific language governing +** rights and limitations under the License. +** +** Alternatively, the contents of this file may be used under the +** terms of the GNU Public License version 2 (the "GPL"), in which +** case the provisions of the GPL are applicable instead of the +** above. If you wish to allow the use of your version of this file +** only under the terms of the GPL and not to allow others to use +** your version of this file under the MPL, indicate your decision +** by deleting the provisions above and replace them with the notice +** and other provisions required by the GPL. If you do not delete +** the provisions above, a recipient may use your version of this +** file under either the MPL or the GPL. +** --------------------------------------------------------------------- +** Inquiries regarding the ACX100 Open Source Project can be +** made directly to: +** +** acx100-users@lists.sf.net +** http://acx100.sf.net +** --------------------------------------------------------------------- +*/ + +/*********************************************************************** +** This code is based on elements which are +** Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +** info@linux-wlan.com +** http://www.linux-wlan.com +*/ + +#include +#include +#include +#include +#include + +#include "acx.h" + + +/*********************************************************************** +*/ +#define LOG_BAD_EID(hdr,len,ie_ptr) acx_log_bad_eid(hdr, len, ((wlan_ie_t*)ie_ptr)) + +#define IE_EID(ie_ptr) (((wlan_ie_t*)(ie_ptr))->eid) +#define IE_LEN(ie_ptr) (((wlan_ie_t*)(ie_ptr))->len) +#define OFFSET(hdr,off) (WLAN_HDR_A3_DATAP(hdr) + (off)) + + +/*********************************************************************** +** wlan_mgmt_decode_XXX +** +** Given a complete frame in f->hdr, sets the pointers in f to +** the areas that correspond to the parts of the frame. +** +** Assumptions: +** 1) f->len and f->hdr are already set +** 2) f->len is the length of the MAC header + data, the FCS +** is NOT included +** 3) all members except len and hdr are zero +** Arguments: +** f frame structure +** +** Returns: +** nothing +** +** Side effects: +** frame structure members are pointing at their +** respective portions of the frame buffer. +*/ +void +wlan_mgmt_decode_beacon(wlan_fr_beacon_t * f) +{ + u8 *ie_ptr; + u8 *end = (u8*)f->hdr + f->len; + + f->type = WLAN_FSTYPE_BEACON; + + /*-- Fixed Fields ----*/ + f->ts = (u64 *) OFFSET(f->hdr, WLAN_BEACON_OFF_TS); + f->bcn_int = (u16 *) OFFSET(f->hdr, WLAN_BEACON_OFF_BCN_INT); + f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_BEACON_OFF_CAPINFO); + + /*-- Information elements */ + ie_ptr = OFFSET(f->hdr, WLAN_BEACON_OFF_SSID); + while (ie_ptr < end) { + switch (IE_EID(ie_ptr)) { + case WLAN_EID_SSID: + f->ssid = (wlan_ie_ssid_t *) ie_ptr; + break; + case WLAN_EID_SUPP_RATES: + f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr; + break; + case WLAN_EID_EXT_RATES: + f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr; + break; + case WLAN_EID_FH_PARMS: + f->fh_parms = (wlan_ie_fh_parms_t *) ie_ptr; + break; + case WLAN_EID_DS_PARMS: + f->ds_parms = (wlan_ie_ds_parms_t *) ie_ptr; + break; + case WLAN_EID_CF_PARMS: + f->cf_parms = (wlan_ie_cf_parms_t *) ie_ptr; + break; + case WLAN_EID_IBSS_PARMS: + f->ibss_parms = (wlan_ie_ibss_parms_t *) ie_ptr; + break; + case WLAN_EID_TIM: + f->tim = (wlan_ie_tim_t *) ie_ptr; + break; + case WLAN_EID_ERP_INFO: + f->erp = (wlan_ie_erp_t *) ie_ptr; + break; + + case WLAN_EID_COUNTRY: + /* was seen: 07 06 47 42 20 01 0D 14 */ + case WLAN_EID_PWR_CONSTRAINT: + /* was seen by Ashwin Mansinghka from + Atheros-based PCI card in AP mode using madwifi drivers: */ + /* 20 01 00 */ + case WLAN_EID_NONERP: + /* was seen from WRT54GS with OpenWrt: 2F 01 07 */ + case WLAN_EID_UNKNOWN128: + /* was seen by Jacek Jablonski from Orinoco AP */ + /* 80 06 00 60 1D 2C 3B 00 */ + case WLAN_EID_UNKNOWN133: + /* was seen by David Bronaugh from ???? */ + /* 85 1E 00 00 84 12 07 00 FF 00 11 00 61 70 63 31 */ + /* 63 73 72 30 34 32 00 00 00 00 00 00 00 00 00 25 */ + case WLAN_EID_UNKNOWN223: + /* was seen by Carlos Martin from ???? */ + /* DF 20 01 1E 04 00 00 00 06 63 09 02 FF 0F 30 30 */ + /* 30 42 36 42 33 34 30 39 46 31 00 00 00 00 00 00 00 00 */ + case WLAN_EID_GENERIC: + /* WPA: hostap code: + if (pos[1] >= 4 && + pos[2] == 0x00 && pos[3] == 0x50 && + pos[4] == 0xf2 && pos[5] == 1) { + wpa = pos; + wpa_len = pos[1] + 2; + } + TI x4 mode: seen DD 04 08 00 28 00 + (08 00 28 is TI's OUI) + last byte is probably 0/1 - disabled/enabled + */ + case WLAN_EID_RSN: + /* hostap does something with it: + rsn = pos; + rsn_len = pos[1] + 2; + */ + break; + + default: + LOG_BAD_EID(f->hdr, f->len, ie_ptr); + break; + } + ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr); + } +} + + +#ifdef UNUSED +void wlan_mgmt_decode_ibssatim(wlan_fr_ibssatim_t * f) +{ + f->type = WLAN_FSTYPE_ATIM; + /*-- Fixed Fields ----*/ + /*-- Information elements */ +} +#endif /* UNUSED */ + +void +wlan_mgmt_decode_disassoc(wlan_fr_disassoc_t * f) +{ + f->type = WLAN_FSTYPE_DISASSOC; + + /*-- Fixed Fields ----*/ + f->reason = (u16 *) OFFSET(f->hdr, WLAN_DISASSOC_OFF_REASON); + + /*-- Information elements */ +} + + +void +wlan_mgmt_decode_assocreq(wlan_fr_assocreq_t * f) +{ + u8 *ie_ptr; + u8 *end = (u8*)f->hdr + f->len; + + + f->type = WLAN_FSTYPE_ASSOCREQ; + + /*-- Fixed Fields ----*/ + f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_ASSOCREQ_OFF_CAP_INFO); + f->listen_int = (u16 *) OFFSET(f->hdr, WLAN_ASSOCREQ_OFF_LISTEN_INT); + + /*-- Information elements */ + ie_ptr = OFFSET(f->hdr, WLAN_ASSOCREQ_OFF_SSID); + while (ie_ptr < end) { + switch (IE_EID(ie_ptr)) { + case WLAN_EID_SSID: + f->ssid = (wlan_ie_ssid_t *) ie_ptr; + break; + case WLAN_EID_SUPP_RATES: + f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr; + break; + case WLAN_EID_EXT_RATES: + f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr; + break; + default: + LOG_BAD_EID(f->hdr, f->len, ie_ptr); + break; + } + ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr); + } +} + + +void +wlan_mgmt_decode_assocresp(wlan_fr_assocresp_t * f) +{ + f->type = WLAN_FSTYPE_ASSOCRESP; + + /*-- Fixed Fields ----*/ + f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_ASSOCRESP_OFF_CAP_INFO); + f->status = (u16 *) OFFSET(f->hdr, WLAN_ASSOCRESP_OFF_STATUS); + f->aid = (u16 *) OFFSET(f->hdr, WLAN_ASSOCRESP_OFF_AID); + + /*-- Information elements */ + f->supp_rates = (wlan_ie_supp_rates_t *) + OFFSET(f->hdr, WLAN_ASSOCRESP_OFF_SUPP_RATES); +} + + +#ifdef UNUSED +void +wlan_mgmt_decode_reassocreq(wlan_fr_reassocreq_t * f) +{ + u8 *ie_ptr; + u8 *end = (u8*)f->hdr + f->len; + + f->type = WLAN_FSTYPE_REASSOCREQ; + + /*-- Fixed Fields ----*/ + f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_REASSOCREQ_OFF_CAP_INFO); + f->listen_int = (u16 *) OFFSET(f->hdr, WLAN_REASSOCREQ_OFF_LISTEN_INT); + f->curr_ap = (u8 *) OFFSET(f->hdr, WLAN_REASSOCREQ_OFF_CURR_AP); + + /*-- Information elements */ + ie_ptr = OFFSET(f->hdr, WLAN_REASSOCREQ_OFF_SSID); + while (ie_ptr < end) { + switch (IE_EID(ie_ptr)) { + case WLAN_EID_SSID: + f->ssid = (wlan_ie_ssid_t *) ie_ptr; + break; + case WLAN_EID_SUPP_RATES: + f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr; + break; + case WLAN_EID_EXT_RATES: + f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr; + break; + default: + LOG_BAD_EID(f->hdr, f->len, ie_ptr); + break; + } + ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr); + } +} + + +void +wlan_mgmt_decode_reassocresp(wlan_fr_reassocresp_t * f) +{ + f->type = WLAN_FSTYPE_REASSOCRESP; + + /*-- Fixed Fields ----*/ + f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_REASSOCRESP_OFF_CAP_INFO); + f->status = (u16 *) OFFSET(f->hdr, WLAN_REASSOCRESP_OFF_STATUS); + f->aid = (u16 *) OFFSET(f->hdr, WLAN_REASSOCRESP_OFF_AID); + + /*-- Information elements */ + f->supp_rates = (wlan_ie_supp_rates_t *) + OFFSET(f->hdr, WLAN_REASSOCRESP_OFF_SUPP_RATES); +} + + +void +wlan_mgmt_decode_probereq(wlan_fr_probereq_t * f) +{ + u8 *ie_ptr; + u8 *end = (u8*)f->hdr + f->len; + + f->type = WLAN_FSTYPE_PROBEREQ; + + /*-- Fixed Fields ----*/ + + /*-- Information elements */ + ie_ptr = OFFSET(f->hdr, WLAN_PROBEREQ_OFF_SSID); + while (ie_ptr < end) { + switch (IE_EID(ie_ptr)) { + case WLAN_EID_SSID: + f->ssid = (wlan_ie_ssid_t *) ie_ptr; + break; + case WLAN_EID_SUPP_RATES: + f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr; + break; + case WLAN_EID_EXT_RATES: + f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr; + break; + default: + LOG_BAD_EID(f->hdr, f->len, ie_ptr); + break; + } + ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr); + } +} +#endif /* UNUSED */ + + +/* TODO: decoding of beacon and proberesp can be merged (similar structure) */ +void +wlan_mgmt_decode_proberesp(wlan_fr_proberesp_t * f) +{ + u8 *ie_ptr; + u8 *end = (u8*)f->hdr + f->len; + + f->type = WLAN_FSTYPE_PROBERESP; + + /*-- Fixed Fields ----*/ + f->ts = (u64 *) OFFSET(f->hdr, WLAN_PROBERESP_OFF_TS); + f->bcn_int = (u16 *) OFFSET(f->hdr, WLAN_PROBERESP_OFF_BCN_INT); + f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_PROBERESP_OFF_CAP_INFO); + + /*-- Information elements */ + ie_ptr = OFFSET(f->hdr, WLAN_PROBERESP_OFF_SSID); + while (ie_ptr < end) { + switch (IE_EID(ie_ptr)) { + case WLAN_EID_SSID: + f->ssid = (wlan_ie_ssid_t *) ie_ptr; + break; + case WLAN_EID_SUPP_RATES: + f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr; + break; + case WLAN_EID_EXT_RATES: + f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr; + break; + case WLAN_EID_FH_PARMS: + f->fh_parms = (wlan_ie_fh_parms_t *) ie_ptr; + break; + case WLAN_EID_DS_PARMS: + f->ds_parms = (wlan_ie_ds_parms_t *) ie_ptr; + break; + case WLAN_EID_CF_PARMS: + f->cf_parms = (wlan_ie_cf_parms_t *) ie_ptr; + break; + case WLAN_EID_IBSS_PARMS: + f->ibss_parms = (wlan_ie_ibss_parms_t *) ie_ptr; + break; +#ifdef DONT_DO_IT_ADD_REAL_HANDLING_INSTEAD + case WLAN_EID_COUNTRY: + break; + ... +#endif +#ifdef SENT_HERE_BY_OPENWRT + /* should those be trapped or handled?? */ + case WLAN_EID_ERP_INFO: + break; + case WLAN_EID_NONERP: + break; + case WLAN_EID_GENERIC: + break; +#endif + default: + LOG_BAD_EID(f->hdr, f->len, ie_ptr); + break; + } + + ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr); + } +} + + +void +wlan_mgmt_decode_authen(wlan_fr_authen_t * f) +{ + u8 *ie_ptr; + u8 *end = (u8*)f->hdr + f->len; + + f->type = WLAN_FSTYPE_AUTHEN; + + /*-- Fixed Fields ----*/ + f->auth_alg = (u16 *) OFFSET(f->hdr, WLAN_AUTHEN_OFF_AUTH_ALG); + f->auth_seq = (u16 *) OFFSET(f->hdr, WLAN_AUTHEN_OFF_AUTH_SEQ); + f->status = (u16 *) OFFSET(f->hdr, WLAN_AUTHEN_OFF_STATUS); + + /*-- Information elements */ + ie_ptr = OFFSET(f->hdr, WLAN_AUTHEN_OFF_CHALLENGE); + if ((ie_ptr < end) && (IE_EID(ie_ptr) == WLAN_EID_CHALLENGE)) { + f->challenge = (wlan_ie_challenge_t *) ie_ptr; + } +} + + +void +wlan_mgmt_decode_deauthen(wlan_fr_deauthen_t * f) +{ + f->type = WLAN_FSTYPE_DEAUTHEN; + + /*-- Fixed Fields ----*/ + f->reason = (u16 *) OFFSET(f->hdr, WLAN_DEAUTHEN_OFF_REASON); + + /*-- Information elements */ +} --- linux-2.6.27.orig/ubuntu/misc/wireless/acx/conv.c +++ linux-2.6.27/ubuntu/misc/wireless/acx/conv.c @@ -0,0 +1,504 @@ +/*********************************************************************** +** Copyright (C) 2003 ACX100 Open Source Project +** +** The contents of this file are subject to the Mozilla Public +** License Version 1.1 (the "License"); you may not use this file +** except in compliance with the License. You may obtain a copy of +** the License at http://www.mozilla.org/MPL/ +** +** Software distributed under the License is distributed on an "AS +** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +** implied. See the License for the specific language governing +** rights and limitations under the License. +** +** Alternatively, the contents of this file may be used under the +** terms of the GNU Public License version 2 (the "GPL"), in which +** case the provisions of the GPL are applicable instead of the +** above. If you wish to allow the use of your version of this file +** only under the terms of the GPL and not to allow others to use +** your version of this file under the MPL, indicate your decision +** by deleting the provisions above and replace them with the notice +** and other provisions required by the GPL. If you do not delete +** the provisions above, a recipient may use your version of this +** file under either the MPL or the GPL. +** --------------------------------------------------------------------- +** Inquiries regarding the ACX100 Open Source Project can be +** made directly to: +** +** acx100-users@lists.sf.net +** http://acx100.sf.net +** --------------------------------------------------------------------- +*/ + +#include +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) +#include +#endif +#include +#include +#include +#include +#include + +#include "acx.h" + + +/*********************************************************************** +** proto_is_stt +** +** Searches the 802.1h Selective Translation Table for a given +** protocol. +** +** prottype - protocol number (in host order) to search for. +** +** Returns: +** 1 - if the table is empty or a match is found. +** 0 - if the table is non-empty and a match is not found. +** +** Based largely on p80211conv.c of the linux-wlan-ng project +*/ +static inline int +proto_is_stt(unsigned int proto) +{ + /* Always return found for now. This is the behavior used by the */ + /* Zoom Win95 driver when 802.1h mode is selected */ + /* TODO: If necessary, add an actual search we'll probably + need this to match the CMAC's way of doing things. + Need to do some testing to confirm. + */ + + if (proto == 0x80f3) /* APPLETALK */ + return 1; + + return 0; +/* return ((prottype == ETH_P_AARP) || (prottype == ETH_P_IPX)); */ +} + +/* Helpers */ + +static inline void +store_llc_snap(struct wlan_llc *llc) +{ + llc->dsap = 0xaa; /* SNAP, see IEEE 802 */ + llc->ssap = 0xaa; + llc->ctl = 0x03; +} +static inline int +llc_is_snap(const struct wlan_llc *llc) +{ + return (llc->dsap == 0xaa) + && (llc->ssap == 0xaa) + && (llc->ctl == 0x03); +} +static inline void +store_oui_rfc1042(struct wlan_snap *snap) +{ + snap->oui[0] = 0; + snap->oui[1] = 0; + snap->oui[2] = 0; +} +static inline int +oui_is_rfc1042(const struct wlan_snap *snap) +{ + return (snap->oui[0] == 0) + && (snap->oui[1] == 0) + && (snap->oui[2] == 0); +} +static inline void +store_oui_8021h(struct wlan_snap *snap) +{ + snap->oui[0] = 0; + snap->oui[1] = 0; + snap->oui[2] = 0xf8; +} +static inline int +oui_is_8021h(const struct wlan_snap *snap) +{ + return (snap->oui[0] == 0) + && (snap->oui[1] == 0) + && (snap->oui[2] == 0xf8); +} + + +/*********************************************************************** +** acx_ether_to_txbuf +** +** Uses the contents of the ether frame to build the elements of +** the 802.11 frame. +** +** We don't actually set up the frame header here. That's the +** MAC's job. We're only handling conversion of DIXII or 802.3+LLC +** frames to something that works with 802.11. +** +** Based largely on p80211conv.c of the linux-wlan-ng project +*/ +int +acx_ether_to_txbuf(acx_device_t *adev, void *txbuf, const struct sk_buff *skb) +{ + struct wlan_hdr_a3 *w_hdr; + struct wlan_ethhdr *e_hdr; + struct wlan_llc *e_llc; + struct wlan_snap *e_snap; + const u8 *a1, *a3; + int header_len, payload_len = -1; + /* protocol type or data length, depending on whether + * DIX or 802.3 ethernet format */ + u16 proto; + u16 fc; + + FN_ENTER; + + if (unlikely(!skb->len)) { + log(L_DEBUG, "zero-length skb!\n"); + goto end; + } + + w_hdr = (struct wlan_hdr_a3*)txbuf; + + switch (adev->mode) { + case ACX_MODE_MONITOR: + /* NB: one day we might want to play with DESC_CTL2_FCS + ** Will need to stop doing "- WLAN_FCS_LEN" here then */ + if (unlikely(skb->len >= WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_FCS_LEN)) { + printk("%s: can't tx oversized frame (%d bytes)\n", + adev->ndev->name, skb->len); + goto end; + } + memcpy(w_hdr, skb->data, skb->len); + payload_len = skb->len; + goto end; + } + + /* step 1: classify ether frame, DIX or 802.3? */ + e_hdr = (wlan_ethhdr_t *)skb->data; + proto = ntohs(e_hdr->type); + if (proto <= 1500) { + log(L_DEBUG, "tx: 802.3 len: %d\n", skb->len); + /* codes <= 1500 reserved for 802.3 lengths */ + /* it's 802.3, pass ether payload unchanged, */ + /* trim off ethernet header and copy payload to txdesc */ + header_len = WLAN_HDR_A3_LEN; + } else { + /* it's DIXII, time for some conversion */ + /* Create 802.11 packet. Header also contains llc and snap. */ + + log(L_DEBUG, "tx: DIXII len: %d\n", skb->len); + + /* size of header is 802.11 header + llc + snap */ + header_len = WLAN_HDR_A3_LEN + sizeof(wlan_llc_t) + sizeof(wlan_snap_t); + /* llc is located behind the 802.11 header */ + e_llc = (wlan_llc_t*)(w_hdr + 1); + /* snap is located behind the llc */ + e_snap = (wlan_snap_t*)(e_llc + 1); + + /* setup the LLC header */ + store_llc_snap(e_llc); + + /* setup the SNAP header */ + e_snap->type = htons(proto); + if (proto_is_stt(proto)) { + store_oui_8021h(e_snap); + } else { + store_oui_rfc1042(e_snap); + } + } + /* trim off ethernet header and copy payload to txbuf */ + payload_len = skb->len - sizeof(wlan_ethhdr_t); + /* TODO: can we just let acx DMA payload from skb instead? */ + memcpy((u8*)txbuf + header_len, skb->data + sizeof(wlan_ethhdr_t), payload_len); + payload_len += header_len; + + /* Set up the 802.11 header */ + switch (adev->mode) { + case ACX_MODE_0_ADHOC: + fc = (WF_FTYPE_DATAi | WF_FSTYPE_DATAONLYi); + a1 = e_hdr->daddr; + a3 = adev->bssid; + break; + case ACX_MODE_2_STA: + fc = (WF_FTYPE_DATAi | WF_FSTYPE_DATAONLYi | WF_FC_TODSi); + a1 = adev->bssid; + a3 = e_hdr->daddr; + break; + case ACX_MODE_3_AP: + fc = (WF_FTYPE_DATAi | WF_FSTYPE_DATAONLYi | WF_FC_FROMDSi); + a1 = e_hdr->daddr; + a3 = e_hdr->saddr; + break; + default: + printk("%s: error - converting eth to wlan in unknown mode\n", + adev->ndev->name); + payload_len = -1; + goto end; + } + if (adev->wep_enabled) + SET_BIT(fc, WF_FC_ISWEPi); + + w_hdr->fc = fc; + w_hdr->dur = 0; + MAC_COPY(w_hdr->a1, a1); + MAC_COPY(w_hdr->a2, adev->dev_addr); + MAC_COPY(w_hdr->a3, a3); + w_hdr->seq = 0; + +#ifdef DEBUG_CONVERT + if (acx_debug & L_DATA) { + printk("original eth frame [%d]: ", skb->len); + acx_dump_bytes(skb->data, skb->len); + printk("802.11 frame [%d]: ", payload_len); + acx_dump_bytes(w_hdr, payload_len); + } +#endif + +end: + FN_EXIT1(payload_len); + return payload_len; +} + + +/*********************************************************************** +** acx_rxbuf_to_ether +** +** Uses the contents of a received 802.11 frame to build an ether +** frame. +** +** This function extracts the src and dest address from the 802.11 +** frame to use in the construction of the eth frame. +** +** Based largely on p80211conv.c of the linux-wlan-ng project +*/ +struct sk_buff* +acx_rxbuf_to_ether(acx_device_t *adev, rxbuffer_t *rxbuf) +{ + struct wlan_hdr *w_hdr; + struct wlan_ethhdr *e_hdr; + struct wlan_llc *e_llc; + struct wlan_snap *e_snap; + struct sk_buff *skb; + const u8 *daddr; + const u8 *saddr; + const u8 *e_payload; + int buflen, payload_length; + unsigned int payload_offset, mtu; + u16 fc; + + FN_ENTER; + + /* This looks complex because it must handle possible + ** phy header in rxbuff */ + w_hdr = acx_get_wlan_hdr(adev, rxbuf); + payload_offset = WLAN_HDR_A3_LEN; /* it is relative to w_hdr */ + payload_length = RXBUF_BYTES_USED(rxbuf) /* entire rxbuff... */ + - ((u8*)w_hdr - (u8*)rxbuf) /* minus space before 802.11 frame */ + - WLAN_HDR_A3_LEN; /* minus 802.11 header */ + + /* setup some vars for convenience */ + fc = w_hdr->fc; + switch (WF_FC_FROMTODSi & fc) { + case 0: + daddr = w_hdr->a1; + saddr = w_hdr->a2; + break; + case WF_FC_FROMDSi: + daddr = w_hdr->a1; + saddr = w_hdr->a3; + break; + case WF_FC_TODSi: + daddr = w_hdr->a3; + saddr = w_hdr->a2; + break; + default: /* WF_FC_FROMTODSi */ + payload_offset += (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN); + payload_length -= (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN); + daddr = w_hdr->a3; + saddr = w_hdr->a4; + } + + if ((WF_FC_ISWEPi & fc) && IS_ACX100(adev)) { + /* chop off the IV+ICV WEP header and footer */ + log(L_DATA|L_DEBUG, "rx: WEP packet, " + "chopping off IV and ICV\n"); + payload_offset += WLAN_WEP_IV_LEN; + payload_length -= WLAN_WEP_IV_LEN + WLAN_WEP_ICV_LEN; + } + + if (unlikely(payload_length < 0)) { + printk("%s: rx frame too short, ignored\n", adev->ndev->name); + goto ret_null; + } + + e_hdr = (wlan_ethhdr_t*) ((u8*) w_hdr + payload_offset); + e_llc = (wlan_llc_t*) e_hdr; + e_snap = (wlan_snap_t*) (e_llc + 1); + mtu = adev->ndev->mtu; + e_payload = (u8*) (e_snap + 1); + + log(L_DATA, "rx: payload_offset %d, payload_length %d\n", + payload_offset, payload_length); + log(L_XFER|L_DATA, + "rx: frame info: llc=%02X%02X%02X " + "snap.oui=%02X%02X%02X snap.type=%04X\n", + e_llc->dsap, e_llc->ssap, e_llc->ctl, + e_snap->oui[0], e_snap->oui[1], e_snap->oui[2], + ntohs(e_snap->type)); + + /* Test for the various encodings */ + if ((payload_length >= sizeof(wlan_ethhdr_t)) + && ((e_llc->dsap != 0xaa) || (e_llc->ssap != 0xaa)) + && ( (mac_is_equal(daddr, e_hdr->daddr)) + || (mac_is_equal(saddr, e_hdr->saddr)) + ) + ) { + /* 802.3 Encapsulated: */ + /* wlan frame body contains complete eth frame (header+body) */ + log(L_DEBUG|L_DATA, "rx: 802.3 ENCAP len=%d\n", payload_length); + + if (unlikely(payload_length > (mtu + ETH_HLEN))) { + printk("%s: rx: ENCAP frame too large (%d > %d)\n", + adev->ndev->name, + payload_length, mtu + ETH_HLEN); + goto ret_null; + } + + /* allocate space and setup host buffer */ + buflen = payload_length; + /* Attempt to align IP header (14 bytes eth header + 2 = 16) */ + skb = dev_alloc_skb(buflen + 2); + if (unlikely(!skb)) + goto no_skb; + skb_reserve(skb, 2); + skb_put(skb, buflen); /* make room */ + + /* now copy the data from the 80211 frame */ + memcpy(skb->data, e_hdr, payload_length); + + } else if ( (payload_length >= sizeof(wlan_llc_t)+sizeof(wlan_snap_t)) + && llc_is_snap(e_llc) ) { + /* wlan frame body contains: AA AA 03 ... (it's a SNAP) */ + + if ( !oui_is_rfc1042(e_snap) + || (proto_is_stt(ieee2host16(e_snap->type)) /* && (ethconv == WLAN_ETHCONV_8021h) */)) { + log(L_DEBUG|L_DATA, "rx: SNAP+RFC1042 len=%d\n", payload_length); + /* wlan frame body contains: AA AA 03 !(00 00 00) ... -or- */ + /* wlan frame body contains: AA AA 03 00 00 00 0x80f3 ... */ + /* build eth hdr, type = len, copy AA AA 03... as eth body */ + /* it's a SNAP + RFC1042 frame && protocol is in STT */ + + if (unlikely(payload_length > mtu)) { + printk("%s: rx: SNAP frame too large (%d > %d)\n", + adev->ndev->name, + payload_length, mtu); + goto ret_null; + } + + /* allocate space and setup host buffer */ + buflen = payload_length + ETH_HLEN; + skb = dev_alloc_skb(buflen + 2); + if (unlikely(!skb)) + goto no_skb; + skb_reserve(skb, 2); + skb_put(skb, buflen); /* make room */ + + /* create 802.3 header */ + e_hdr = (wlan_ethhdr_t*) skb->data; + MAC_COPY(e_hdr->daddr, daddr); + MAC_COPY(e_hdr->saddr, saddr); + e_hdr->type = htons(payload_length); + + /* Now copy the data from the 80211 frame. + Make room in front for the eth header, and keep the + llc and snap from the 802.11 payload */ + memcpy(skb->data + ETH_HLEN, + e_llc, payload_length); + + } else { + /* wlan frame body contains: AA AA 03 00 00 00 [type] [tail] */ + /* build eth hdr, type=[type], copy [tail] as eth body */ + log(L_DEBUG|L_DATA, "rx: 802.1h/RFC1042 len=%d\n", + payload_length); + /* it's an 802.1h frame (an RFC1042 && protocol is not in STT) */ + /* build a DIXII + RFC894 */ + + payload_length -= sizeof(wlan_llc_t) + sizeof(wlan_snap_t); + if (unlikely(payload_length > mtu)) { + printk("%s: rx: DIXII frame too large (%d > %d)\n", + adev->ndev->name, + payload_length, mtu); + goto ret_null; + } + + /* allocate space and setup host buffer */ + buflen = payload_length + ETH_HLEN; + skb = dev_alloc_skb(buflen + 2); + if (unlikely(!skb)) + goto no_skb; + skb_reserve(skb, 2); + skb_put(skb, buflen); /* make room */ + + /* create 802.3 header */ + e_hdr = (wlan_ethhdr_t *) skb->data; + MAC_COPY(e_hdr->daddr, daddr); + MAC_COPY(e_hdr->saddr, saddr); + e_hdr->type = e_snap->type; + + /* Now copy the data from the 80211 frame. + Make room in front for the eth header, and cut off the + llc and snap from the 802.11 payload */ + memcpy(skb->data + ETH_HLEN, + e_payload, payload_length); + } + + } else { + log(L_DEBUG|L_DATA, "rx: NON-ENCAP len=%d\n", payload_length); + /* build eth hdr, type=len, copy wlan body as eth body */ + /* any NON-ENCAP */ + /* it's a generic 80211+LLC or IPX 'Raw 802.3' */ + /* build an 802.3 frame */ + + if (unlikely(payload_length > mtu)) { + printk("%s: rx: OTHER frame too large (%d > %d)\n", + adev->ndev->name, payload_length, mtu); + goto ret_null; + } + + /* allocate space and setup host buffer */ + buflen = payload_length + ETH_HLEN; + skb = dev_alloc_skb(buflen + 2); + if (unlikely(!skb)) + goto no_skb; + skb_reserve(skb, 2); + skb_put(skb, buflen); /* make room */ + + /* set up the 802.3 header */ + e_hdr = (wlan_ethhdr_t *) skb->data; + MAC_COPY(e_hdr->daddr, daddr); + MAC_COPY(e_hdr->saddr, saddr); + e_hdr->type = htons(payload_length); + + /* now copy the data from the 80211 frame */ + memcpy(skb->data + ETH_HLEN, e_llc, payload_length); + } + + skb->dev = adev->ndev; + skb->protocol = eth_type_trans(skb, adev->ndev); + +#ifdef DEBUG_CONVERT + if (acx_debug & L_DATA) { + int len = RXBUF_BYTES_RCVD(adev, rxbuf); + printk("p802.11 frame [%d]: ", len); + acx_dump_bytes(w_hdr, len); + printk("eth frame [%d]: ", skb->len); + acx_dump_bytes(skb->data, skb->len); + } +#endif + + FN_EXIT0; + return skb; + +no_skb: + printk("%s: rx: no memory for skb (%d bytes)\n", + adev->ndev->name, buflen + 2); +ret_null: + FN_EXIT1((int)NULL); + return NULL; +} --- linux-2.6.27.orig/ubuntu/misc/wireless/acx/setrate.c +++ linux-2.6.27/ubuntu/misc/wireless/acx/setrate.c @@ -0,0 +1,213 @@ +/* TODO: stop #including, move into wireless.c + * until then, keep in sync copies in prism54/ and acx/ dirs + * code+data size: less than 1k */ + +enum { + DOT11_RATE_1, + DOT11_RATE_2, + DOT11_RATE_5, + DOT11_RATE_11, + DOT11_RATE_22, + DOT11_RATE_33, + DOT11_RATE_6, + DOT11_RATE_9, + DOT11_RATE_12, + DOT11_RATE_18, + DOT11_RATE_24, + DOT11_RATE_36, + DOT11_RATE_48, + DOT11_RATE_54 +}; +enum { + DOT11_MOD_DBPSK, + DOT11_MOD_DQPSK, + DOT11_MOD_CCK, + DOT11_MOD_OFDM, + DOT11_MOD_CCKOFDM, + DOT11_MOD_PBCC +}; +static const u8 ratelist[] = { 1,2,5,11,22,33,6,9,12,18,24,36,48,54 }; +static const u8 dot11ratebyte[] = { 1*2,2*2,11,11*2,22*2,33*2,6*2,9*2,12*2,18*2,24*2,36*2,48*2,54*2 }; +static const u8 default_modulation[] = { + DOT11_MOD_DBPSK, + DOT11_MOD_DQPSK, + DOT11_MOD_CCK, + DOT11_MOD_CCK, + DOT11_MOD_PBCC, + DOT11_MOD_PBCC, + DOT11_MOD_OFDM, + DOT11_MOD_OFDM, + DOT11_MOD_OFDM, + DOT11_MOD_OFDM, + DOT11_MOD_OFDM, + DOT11_MOD_OFDM, + DOT11_MOD_OFDM, + DOT11_MOD_OFDM +}; + +static /* TODO: remove 'static' when moved to wireless.c */ +int +rate_mbit2enum(int n) { + int i=0; + while(i=DOT11_RATE_6) return DOT11_MOD_OFDM; */ + return default_modulation[r_enum]; + } + if(suffix=='c') { + if(r_enumDOT11_RATE_11) return -EINVAL; + return DOT11_MOD_CCK; + } + if(suffix=='p') { + if(r_enumDOT11_RATE_33) return -EINVAL; + return DOT11_MOD_PBCC; + } + if(suffix=='o') { + if(r_enumINT_MAX) return -EINVAL; + + rate_enum = rate_mbit2enum(rate_mbit); + if(rate_enum<0) return rate_enum; + + c = *str; + mod = get_modulation(rate_enum, c); + if(mod<0) return mod; + + if(c>='a' && c<='z') c = *++str; + if(c!=',' && c!=' ' && c!='\0') return -EINVAL; + + if(supported) { + int r = supported(rate_mbit, mod, opaque); + if(r) return r; + } + + *vector++ = dot11ratebyte[rate_enum] | or_mask; + + size--; + str++; + } while(size>0 && c==','); + + if(size<1) return -E2BIG; + *vector=0; /* TODO: sort, remove dups? */ + + *pstr = str-1; + return 0; +} + +static /* TODO: remove 'static' when moved to wireless.c */ +int +fill_ratevectors(const char *str, u8 *brate, u8 *orate, int size, + int (*supported)(int mbit, int mod, void *opaque), void *opaque) +{ + int r; + + r = fill_ratevector(&str, brate, size, supported, opaque, 0x80); + if(r) return r; + + orate[0] = 0; + if(*str==' ') { + str++; + r = fill_ratevector(&str, orate, size, supported, opaque, 0); + if(r) return r; + /* TODO: sanitize, e.g. remove/error on rates already in basic rate set? */ + } + if(*str) + return -EINVAL; + + return 0; +} +#endif + +/* TODO: use u64 masks? */ + +static int +fill_ratemask(const char **pstr, u32* mask, + int (*supported)(int mbit, int mod,void *opaque), + u32 (*gen_mask)(int mbit, int mod,void *opaque), + void *opaque) +{ + unsigned long rate_mbit; + int rate_enum,mod; + u32 m = 0; + const char *str = *pstr; + char c; + + do { + rate_mbit = simple_strtoul(str, (char**)&str, 10); + if(rate_mbit>INT_MAX) return -EINVAL; + + rate_enum = rate_mbit2enum(rate_mbit); + if(rate_enum<0) return rate_enum; + + c = *str; + mod = get_modulation(rate_enum, c); + if(mod<0) return mod; + + if(c>='a' && c<='z') c = *++str; + if(c!=',' && c!=' ' && c!='\0') return -EINVAL; + + if(supported) { + int r = supported(rate_mbit, mod, opaque); + if(r) return r; + } + + m |= gen_mask(rate_mbit, mod, opaque); + str++; + } while(c==','); + + *pstr = str-1; + *mask |= m; + return 0; +} + +static /* TODO: remove 'static' when moved to wireless.c */ +int +fill_ratemasks(const char *str, u32 *bmask, u32 *omask, + int (*supported)(int mbit, int mod,void *opaque), + u32 (*gen_mask)(int mbit, int mod,void *opaque), + void *opaque) +{ + int r; + + r = fill_ratemask(&str, bmask, supported, gen_mask, opaque); + if(r) return r; + + if(*str==' ') { + str++; + r = fill_ratemask(&str, omask, supported, gen_mask, opaque); + if(r) return r; + } + if(*str) + return -EINVAL; + return 0; +} --- linux-2.6.27.orig/ubuntu/misc/wireless/acx/acx_config.h +++ linux-2.6.27/ubuntu/misc/wireless/acx/acx_config.h @@ -0,0 +1,41 @@ +/* Driver version */ +#define ACX_RELEASE "v0.3.36" + +/* set to 0 if you don't want any debugging code to be compiled in */ +/* set to 1 if you want some debugging */ +/* set to 2 if you want extensive debug log */ +#define ACX_DEBUG 0 +#define ACX_DEFAULT_MSG (L_ASSOC|L_INIT) + +/* assume 32bit I/O width + * (16bit is also compatible with Compact Flash) */ +#define ACX_IO_WIDTH 32 + +/* Set this to 1 if you want monitor mode to use + * phy header. Currently it is not useful anyway since we + * don't know what useful info (if any) is in phy header. + * If you want faster/smaller code, say 0 here */ +#define WANT_PHY_HDR 0 + +/* whether to do Tx descriptor cleanup in softirq (i.e. not in IRQ + * handler) or not. Note that doing it later does slightly increase + * system load, so still do that stuff in the IRQ handler for now, + * even if that probably means worse latency */ +#define TX_CLEANUP_IN_SOFTIRQ 0 + +/* if you want very experimental 802.11 power save mode features */ +#define POWER_SAVE_80211 0 + +/* if you want very early packet fragmentation bits and pieces */ +#define ACX_FRAGMENTATION 0 + +/* Locking: */ +/* very talkative */ +/* #define PARANOID_LOCKING 1 */ +/* normal (use when bug-free) */ +#define DO_LOCKING 1 +/* else locking is disabled! */ + +/* 0 - normal mode */ +/* 1 - development/debug: probe for IEs on modprobe */ +#define CMD_DISCOVERY 0 --- linux-2.6.27.orig/ubuntu/misc/wireless/acx/Makefile +++ linux-2.6.27/ubuntu/misc/wireless/acx/Makefile @@ -0,0 +1,5 @@ +EXTRA_CFLAGS = -DCONFIG_NET_ACX_PCI -DCONFIG_NET_ACX_USB + +obj-$(CONFIG_WIRELESS_ACX) += acx.o + +acx-objs := wlan.o conv.o ioctl.o common.o pci.o usb.o --- linux-2.6.27.orig/ubuntu/misc/wireless/acx/ioctl.c +++ linux-2.6.27/ubuntu/misc/wireless/acx/ioctl.c @@ -0,0 +1,2745 @@ +/*********************************************************************** +** Copyright (C) 2003 ACX100 Open Source Project +** +** The contents of this file are subject to the Mozilla Public +** License Version 1.1 (the "License"); you may not use this file +** except in compliance with the License. You may obtain a copy of +** the License at http://www.mozilla.org/MPL/ +** +** Software distributed under the License is distributed on an "AS +** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +** implied. See the License for the specific language governing +** rights and limitations under the License. +** +** Alternatively, the contents of this file may be used under the +** terms of the GNU Public License version 2 (the "GPL"), in which +** case the provisions of the GPL are applicable instead of the +** above. If you wish to allow the use of your version of this file +** only under the terms of the GPL and not to allow others to use +** your version of this file under the MPL, indicate your decision +** by deleting the provisions above and replace them with the notice +** and other provisions required by the GPL. If you do not delete +** the provisions above, a recipient may use your version of this +** file under either the MPL or the GPL. +** --------------------------------------------------------------------- +** Inquiries regarding the ACX100 Open Source Project can be +** made directly to: +** +** acx100-users@lists.sf.net +** http://acx100.sf.net +** --------------------------------------------------------------------- +*/ + +#include +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) +#include +#endif +#include +#include +#include +/* #include */ /* required for 2.4.x kernels; verify_write() */ +#include +#include +#include + +#include "acx.h" + + +/*********************************************************************** +*/ + +/* channel frequencies + * TODO: Currently, every other 802.11 driver keeps its own copy of this. In + * the long run this should be integrated into ieee802_11.h or wireless.h or + * whatever IEEE802.11x framework evolves */ +static const u16 acx_channel_freq[] = { + 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484, +}; + + +/*********************************************************************** +** acx_ioctl_commit +*/ +static int +acx_ioctl_commit(struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + + FN_ENTER; + + acx_sem_lock(adev); + if (ACX_STATE_IFACE_UP & adev->dev_state_mask) + acx_s_update_card_settings(adev); + acx_sem_unlock(adev); + + FN_EXIT0; + return OK; +} + + +/*********************************************************************** +*/ +static int +acx_ioctl_get_name( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + static const char * const names[] = { "IEEE 802.11b+/g+", "IEEE 802.11b+" }; + + strcpy(wrqu->name, names[IS_ACX111(adev) ? 0 : 1]); + + return OK; +} + + +/*********************************************************************** +** acx_ioctl_set_freq +*/ +static int +acx_ioctl_set_freq( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + int channel = -1; + unsigned int mult = 1; + int result; + + FN_ENTER; + + if (wrqu->freq.e == 0 && wrqu->freq.m <= 1000) { + /* Setting by channel number */ + channel = wrqu->freq.m; + } else { + /* If setting by frequency, convert to a channel */ + int i; + + for (i = 0; i < (6 - wrqu->freq.e); i++) + mult *= 10; + + for (i = 1; i <= 14; i++) + if (wrqu->freq.m == acx_channel_freq[i - 1] * mult) + channel = i; + } + + if (channel > 14) { + result = -EINVAL; + goto end; + } + + acx_sem_lock(adev); + + adev->channel = channel; + /* hmm, the following code part is strange, but this is how + * it was being done before... */ + log(L_IOCTL, "Changing to channel %d\n", channel); + SET_BIT(adev->set_mask, GETSET_CHANNEL); + + result = -EINPROGRESS; /* need to call commit handler */ + + acx_sem_unlock(adev); +end: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +*/ +static inline int +acx_ioctl_get_freq( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + wrqu->freq.e = 0; + wrqu->freq.m = adev->channel; + return OK; +} + + +/*********************************************************************** +** acx_ioctl_set_mode +*/ +static int +acx_ioctl_set_mode( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + int result; + + FN_ENTER; + + acx_sem_lock(adev); + + switch (wrqu->mode) { + case IW_MODE_AUTO: + adev->mode = ACX_MODE_OFF; + break; + case IW_MODE_MONITOR: + adev->mode = ACX_MODE_MONITOR; + break; + case IW_MODE_ADHOC: + adev->mode = ACX_MODE_0_ADHOC; + break; + case IW_MODE_INFRA: + adev->mode = ACX_MODE_2_STA; + break; + case IW_MODE_MASTER: + printk("acx: master mode (HostAP) is very, very " + "experimental! It might work partially, but " + "better get prepared for nasty surprises " + "at any time\n"); + adev->mode = ACX_MODE_3_AP; + break; + case IW_MODE_REPEAT: + case IW_MODE_SECOND: + default: + result = -EOPNOTSUPP; + goto end_unlock; + } + + log(L_ASSOC, "new adev->mode=%d\n", adev->mode); + SET_BIT(adev->set_mask, GETSET_MODE); + result = -EINPROGRESS; + +end_unlock: + acx_sem_unlock(adev); + + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +*/ +static int +acx_ioctl_get_mode( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + int result = 0; + + switch (adev->mode) { + case ACX_MODE_OFF: + wrqu->mode = IW_MODE_AUTO; break; + case ACX_MODE_MONITOR: + wrqu->mode = IW_MODE_MONITOR; break; + case ACX_MODE_0_ADHOC: + wrqu->mode = IW_MODE_ADHOC; break; + case ACX_MODE_2_STA: + wrqu->mode = IW_MODE_INFRA; break; + case ACX_MODE_3_AP: + wrqu->mode = IW_MODE_MASTER; break; + default: + result = -EOPNOTSUPP; + } + return result; +} + + +/*********************************************************************** +*/ +static int +acx_ioctl_set_sens( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_param *vwrq = &wrqu->sens; + acx_device_t *adev = ndev2adev(ndev); + + acx_sem_lock(adev); + + adev->sensitivity = (1 == vwrq->disabled) ? 0 : vwrq->value; + SET_BIT(adev->set_mask, GETSET_SENSITIVITY); + + acx_sem_unlock(adev); + + return -EINPROGRESS; +} + + +/*********************************************************************** +*/ +static int +acx_ioctl_get_sens( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_param *vwrq = &wrqu->sens; + acx_device_t *adev = ndev2adev(ndev); + + if (IS_USB(adev)) + /* setting the PHY reg via fw cmd doesn't work yet */ + return -EOPNOTSUPP; + + /* acx_sem_lock(adev); */ + + vwrq->value = adev->sensitivity; + vwrq->disabled = (vwrq->value == 0); + vwrq->fixed = 1; + + /* acx_sem_unlock(adev); */ + + return OK; +} + + +/*********************************************************************** +** acx_ioctl_set_ap +** +** Sets the MAC address of the AP to associate with +*/ +static int +acx_ioctl_set_ap( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct sockaddr *awrq = &wrqu->ap_addr; + acx_device_t *adev = ndev2adev(ndev); + int result = 0; + const u8 *ap; + + FN_ENTER; + if (NULL == awrq) { + result = -EFAULT; + goto end; + } + if (ARPHRD_ETHER != awrq->sa_family) { + result = -EINVAL; + goto end; + } + + ap = awrq->sa_data; + acxlog_mac(L_IOCTL, "set AP=", ap, "\n"); + + MAC_COPY(adev->ap, ap); + + /* We want to start rescan in managed or ad-hoc mode, + ** otherwise just set adev->ap. + ** "iwconfig ap mode managed": we must be able + ** to set ap _first_ and _then_ set mode */ + switch (adev->mode) { + case ACX_MODE_0_ADHOC: + case ACX_MODE_2_STA: + /* FIXME: if there is a convention on what zero AP means, + ** please add a comment about that. I don't know of any --vda */ + if (mac_is_zero(ap)) { + /* "off" == 00:00:00:00:00:00 */ + MAC_BCAST(adev->ap); + log(L_IOCTL, "Not reassociating\n"); + } else { + log(L_IOCTL, "Forcing reassociation\n"); + SET_BIT(adev->set_mask, GETSET_RESCAN); + } + break; + } + result = -EINPROGRESS; +end: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +*/ +static int +acx_ioctl_get_ap( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct sockaddr *awrq = &wrqu->ap_addr; + acx_device_t *adev = ndev2adev(ndev); + + if (ACX_STATUS_4_ASSOCIATED == adev->status) { + /* as seen in Aironet driver, airo.c */ + MAC_COPY(awrq->sa_data, adev->bssid); + } else { + MAC_ZERO(awrq->sa_data); + } + awrq->sa_family = ARPHRD_ETHER; + return OK; +} + + +/*********************************************************************** +** acx_ioctl_get_aplist +** +** Deprecated in favor of iwscan. +** We simply return the list of currently available stations in range, +** don't do a new scan. +*/ +static int +acx_ioctl_get_aplist( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_point *dwrq = &wrqu->data; + acx_device_t *adev = ndev2adev(ndev); + struct sockaddr *address = (struct sockaddr *) extra; + struct iw_quality qual[IW_MAX_AP]; + int i, cur; + int result = OK; + + FN_ENTER; + + /* we have AP list only in STA mode */ + if (ACX_MODE_2_STA != adev->mode) { + result = -EOPNOTSUPP; + goto end; + } + + cur = 0; + for (i = 0; i < VEC_SIZE(adev->sta_list); i++) { + struct client *bss = &adev->sta_list[i]; + if (!bss->used) continue; + MAC_COPY(address[cur].sa_data, bss->bssid); + address[cur].sa_family = ARPHRD_ETHER; + qual[cur].level = bss->sir; + qual[cur].noise = bss->snr; +#ifndef OLD_QUALITY + qual[cur].qual = acx_signal_determine_quality(qual[cur].level, + qual[cur].noise); +#else + qual[cur].qual = (qual[cur].noise <= 100) ? + 100 - qual[cur].noise : 0; +#endif + /* no scan: level/noise/qual not updated: */ + qual[cur].updated = 0; + cur++; + } + if (cur) { + dwrq->flags = 1; + memcpy(extra + sizeof(struct sockaddr)*cur, &qual, + sizeof(struct iw_quality)*cur); + } + dwrq->length = cur; +end: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +*/ +static int +acx_ioctl_set_scan( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + int result; + + FN_ENTER; + + acx_sem_lock(adev); + + /* don't start scan if device is not up yet */ + if (!(adev->dev_state_mask & ACX_STATE_IFACE_UP)) { + result = -EAGAIN; + goto end_unlock; + } + + /* This is NOT a rescan for new AP! + ** Do not use SET_BIT(GETSET_RESCAN); */ + acx_s_cmd_start_scan(adev); + result = OK; + +end_unlock: + acx_sem_unlock(adev); +/* end: */ + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_s_scan_add_station +*/ +/* helper. not sure whether it's really a _s_leeping fn */ +static char* +acx_s_scan_add_station( + acx_device_t *adev, + char *ptr, + char *end_buf, + struct client *bss, + struct iw_request_info *info) +{ + struct iw_event iwe; + char *ptr_rate; + + FN_ENTER; + + /* MAC address has to be added first */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + MAC_COPY(iwe.u.ap_addr.sa_data, bss->bssid); + acxlog_mac(L_IOCTL, "scan, station address: ", bss->bssid, "\n"); + ptr = iwe_stream_add_event(info, ptr, end_buf, &iwe, IW_EV_ADDR_LEN); + + /* Add ESSID */ + iwe.cmd = SIOCGIWESSID; + iwe.u.data.length = bss->essid_len; + iwe.u.data.flags = 1; + log(L_IOCTL, "scan, essid: %s\n", bss->essid); + ptr = iwe_stream_add_point(info, ptr, end_buf, &iwe, bss->essid); + + /* Add mode */ + iwe.cmd = SIOCGIWMODE; + if (bss->cap_info & (WF_MGMT_CAP_ESS | WF_MGMT_CAP_IBSS)) { + if (bss->cap_info & WF_MGMT_CAP_ESS) + iwe.u.mode = IW_MODE_MASTER; + else + iwe.u.mode = IW_MODE_ADHOC; + log(L_IOCTL, "scan, mode: %d\n", iwe.u.mode); + ptr = iwe_stream_add_event(info, ptr, end_buf, &iwe, IW_EV_UINT_LEN); + } + + /* Add frequency */ + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = acx_channel_freq[bss->channel - 1] * 100000; + iwe.u.freq.e = 1; + log(L_IOCTL, "scan, frequency: %d\n", iwe.u.freq.m); + ptr = iwe_stream_add_event(info, ptr, end_buf, &iwe, IW_EV_FREQ_LEN); + + /* Add link quality */ + iwe.cmd = IWEVQUAL; + /* FIXME: these values should be expressed in dBm, but we don't know + * how to calibrate it yet */ + iwe.u.qual.level = bss->sir; + iwe.u.qual.noise = bss->snr; +#ifndef OLD_QUALITY + iwe.u.qual.qual = acx_signal_determine_quality(iwe.u.qual.level, + iwe.u.qual.noise); +#else + iwe.u.qual.qual = (iwe.u.qual.noise <= 100) ? + 100 - iwe.u.qual.noise : 0; +#endif + iwe.u.qual.updated = 7; + log(L_IOCTL, "scan, link quality: %d/%d/%d\n", + iwe.u.qual.level, iwe.u.qual.noise, iwe.u.qual.qual); + ptr = iwe_stream_add_event(info, ptr, end_buf, &iwe, IW_EV_QUAL_LEN); + + /* Add encryption */ + iwe.cmd = SIOCGIWENCODE; + if (bss->cap_info & WF_MGMT_CAP_PRIVACY) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + log(L_IOCTL, "scan, encryption flags: %X\n", iwe.u.data.flags); + ptr = iwe_stream_add_point(info, ptr, end_buf, &iwe, bss->essid); + + /* add rates */ + iwe.cmd = SIOCGIWRATE; + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + ptr_rate = ptr + IW_EV_LCP_LEN; + + { + u16 rate = bss->rate_cap; + const u8* p = acx_bitpos2ratebyte; + while (rate) { + if (rate & 1) { + iwe.u.bitrate.value = *p * 500000; /* units of 500kb/s */ + log(L_IOCTL, "scan, rate: %d\n", iwe.u.bitrate.value); + ptr_rate = iwe_stream_add_value(info, ptr, ptr_rate, end_buf, + &iwe, IW_EV_PARAM_LEN); + } + rate >>= 1; + p++; + }} + + if ((ptr_rate - ptr) > (ptrdiff_t)IW_EV_LCP_LEN) + ptr = ptr_rate; + + /* drop remaining station data items for now */ + + FN_EXIT0; + return ptr; +} + + +/*********************************************************************** + * acx_ioctl_get_scan + */ +static int +acx_ioctl_get_scan( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_point *dwrq = &wrqu->data; + acx_device_t *adev = ndev2adev(ndev); + char *ptr = extra; + int i; + int result = OK; + + FN_ENTER; + + acx_sem_lock(adev); + + /* no scan available if device is not up yet */ + if (!(adev->dev_state_mask & ACX_STATE_IFACE_UP)) { + log(L_IOCTL, "iface not up yet\n"); + result = -EAGAIN; + goto end_unlock; + } + +#ifdef ENODATA_TO_BE_USED_AFTER_SCAN_ERROR_ONLY + if (adev->bss_table_count == 0) { + /* no stations found */ + result = -ENODATA; + goto end_unlock; + } +#endif + + for (i = 0; i < VEC_SIZE(adev->sta_list); i++) { + struct client *bss = &adev->sta_list[i]; + if (!bss->used) continue; + ptr = acx_s_scan_add_station(adev, ptr, + extra + IW_SCAN_MAX_DATA, bss, info); + } + dwrq->length = ptr - extra; + dwrq->flags = 0; + +end_unlock: + acx_sem_unlock(adev); +/* end: */ + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_ioctl_set_essid +*/ +static int +acx_ioctl_set_essid( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_point *dwrq = &wrqu->essid; + acx_device_t *adev = ndev2adev(ndev); + int len = dwrq->length; + int result; + + FN_ENTER; + + if (len < 0) { + result = -EINVAL; + goto end; + } + + log(L_IOCTL, "set ESSID '%*s', length %d, flags 0x%04X\n", + len, extra, len, dwrq->flags); + +#if WIRELESS_EXT >= 21 + /* WE 21 gives real ESSID strlen, not +1 (trailing zero): + * see LKML "[patch] drivers/net/wireless: correct reported ssid lengths" */ + len += 1; +#endif + + acx_sem_lock(adev); + + /* ESSID disabled? */ + if (0 == dwrq->flags) { + adev->essid_active = 0; + + } else { + if (dwrq->length > IW_ESSID_MAX_SIZE+1) { + result = -E2BIG; + goto end_unlock; + } + + if (len > sizeof(adev->essid)) + len = sizeof(adev->essid); + memcpy(adev->essid, extra, len-1); + adev->essid[len-1] = '\0'; + /* Paranoia: just in case there is a '\0'... */ + adev->essid_len = strlen(adev->essid); + adev->essid_active = 1; + } + + SET_BIT(adev->set_mask, GETSET_RESCAN); + + result = -EINPROGRESS; + +end_unlock: + acx_sem_unlock(adev); +end: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +*/ +static int +acx_ioctl_get_essid( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_point *dwrq = &wrqu->essid; + acx_device_t *adev = ndev2adev(ndev); + + dwrq->flags = adev->essid_active; + if (adev->essid_active) { + memcpy(extra, adev->essid, adev->essid_len); + extra[adev->essid_len] = '\0'; + dwrq->length = adev->essid_len + 1; + dwrq->flags = 1; + } + return OK; +} + + +/*********************************************************************** +** acx_l_update_client_rates +*/ +static void +acx_l_update_client_rates(acx_device_t *adev, u16 rate) +{ + int i; + for (i = 0; i < VEC_SIZE(adev->sta_list); i++) { + client_t *clt = &adev->sta_list[i]; + if (!clt->used) continue; + clt->rate_cfg = (clt->rate_cap & rate); + if (!clt->rate_cfg) { + /* no compatible rates left: kick client */ + acxlog_mac(L_ASSOC, "client ",clt->address," kicked: " + "rates are not compatible anymore\n"); + acx_l_sta_list_del(adev, clt); + continue; + } + clt->rate_cur &= clt->rate_cfg; + if (!clt->rate_cur) { + /* current rate become invalid, choose a valid one */ + clt->rate_cur = 1 << lowest_bit(clt->rate_cfg); + } + if (IS_ACX100(adev)) + clt->rate_100 = acx_bitpos2rate100[highest_bit(clt->rate_cur)]; + clt->fallback_count = clt->stepup_count = 0; + clt->ignore_count = 16; + } + switch (adev->mode) { + case ACX_MODE_2_STA: + if (adev->ap_client && !adev->ap_client->used) { + /* Owwww... we kicked our AP!! :) */ + SET_BIT(adev->set_mask, GETSET_RESCAN); + } + } +} + + +/*********************************************************************** +*/ +/* maps bits from acx111 rate to rate in Mbits */ +static const unsigned int +acx111_rate_tbl[] = { + 1000000, /* 0 */ + 2000000, /* 1 */ + 5500000, /* 2 */ + 6000000, /* 3 */ + 9000000, /* 4 */ + 11000000, /* 5 */ + 12000000, /* 6 */ + 18000000, /* 7 */ + 22000000, /* 8 */ + 24000000, /* 9 */ + 36000000, /* 10 */ + 48000000, /* 11 */ + 54000000, /* 12 */ + 500000, /* 13, should not happen */ + 500000, /* 14, should not happen */ + 500000, /* 15, should not happen */ +}; + +/*********************************************************************** + * acx_ioctl_set_rate + */ +static int +acx_ioctl_set_rate( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_param *vwrq = &wrqu->param; + acx_device_t *adev = ndev2adev(ndev); + u16 txrate_cfg = 1; + unsigned long flags; + int autorate; + int result = -EINVAL; + + FN_ENTER; + log(L_IOCTL, "rate %d fixed 0x%X disabled 0x%X flags 0x%X\n", + vwrq->value, vwrq->fixed, vwrq->disabled, vwrq->flags); + + if ((0 == vwrq->fixed) || (1 == vwrq->fixed)) { + int i = VEC_SIZE(acx111_rate_tbl)-1; + if (vwrq->value == -1) + /* "iwconfig rate auto" --> choose highest */ + vwrq->value = IS_ACX100(adev) ? 22000000 : 54000000; + while (i >= 0) { + if (vwrq->value == acx111_rate_tbl[i]) { + txrate_cfg <<= i; + i = 0; + break; + } + i--; + } + if (i == -1) { /* no matching rate */ + result = -EINVAL; + goto end; + } + } else { /* rate N, N<1000 (driver specific): we don't use this */ + result = -EOPNOTSUPP; + goto end; + } + /* now: only one bit is set in txrate_cfg, corresponding to + ** indicated rate */ + + autorate = (vwrq->fixed == 0) && (RATE111_1 != txrate_cfg); + if (autorate) { + /* convert 00100000 -> 00111111 */ + txrate_cfg = (txrate_cfg<<1)-1; + } + + if (IS_ACX100(adev)) { + txrate_cfg &= RATE111_ACX100_COMPAT; + if (!txrate_cfg) { + result = -ENOTSUPP; /* rate is not supported by acx100 */ + goto end; + } + } + + acx_sem_lock(adev); + acx_lock(adev, flags); + + adev->rate_auto = autorate; + adev->rate_oper = txrate_cfg; + adev->rate_basic = txrate_cfg; + /* only do that in auto mode, non-auto will be able to use + * one specific Tx rate only anyway */ + if (autorate) { + /* only use 802.11b base rates, for standard 802.11b H/W + * compatibility */ + adev->rate_basic &= RATE111_80211B_COMPAT; + } + adev->rate_bcast = 1 << lowest_bit(txrate_cfg); + if (IS_ACX100(adev)) + adev->rate_bcast100 = acx_rate111to100(adev->rate_bcast); + acx_l_update_ratevector(adev); + acx_l_update_client_rates(adev, txrate_cfg); + + /* Do/don't do tx rate fallback; beacon contents and rate */ + SET_BIT(adev->set_mask, SET_RATE_FALLBACK|SET_TEMPLATES); + result = -EINPROGRESS; + + acx_unlock(adev, flags); + acx_sem_unlock(adev); +end: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_ioctl_get_rate +*/ +static int +acx_ioctl_get_rate( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_param *vwrq = &wrqu->param; + acx_device_t *adev = ndev2adev(ndev); + unsigned long flags; + u16 rate; + + acx_lock(adev, flags); + rate = adev->rate_oper; + if (adev->ap_client) + rate = adev->ap_client->rate_cur; + vwrq->value = acx111_rate_tbl[highest_bit(rate)]; + vwrq->fixed = !adev->rate_auto; + vwrq->disabled = 0; + acx_unlock(adev, flags); + + return OK; +} + +static int +acx_ioctl_set_rts( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_param *vwrq = &wrqu->rts; + acx_device_t *adev = ndev2adev(ndev); + int val = vwrq->value; + + if (vwrq->disabled) + val = 2312; + if ((val < 0) || (val > 2312)) + return -EINVAL; + + adev->rts_threshold = val; + return OK; +} + +static inline int +acx_ioctl_get_rts( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_param *vwrq = &wrqu->rts; + acx_device_t *adev = ndev2adev(ndev); + + vwrq->value = adev->rts_threshold; + vwrq->disabled = (vwrq->value >= 2312); + vwrq->fixed = 1; + return OK; +} + + +#if ACX_FRAGMENTATION +static int +acx_ioctl_set_frag( + struct net_device *ndev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + int val = vwrq->value; + + if (vwrq->disabled) + val = 32767; + else + if ((val < 256) || (val > 2347)) + return -EINVAL; + + adev->frag_threshold = val; + return OK; +} + +static inline int +acx_ioctl_get_frag( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_param *vwrq = &wrqu->frag; + acx_device_t *adev = ndev2adev(ndev); + + vwrq->value = adev->frag_threshold; + vwrq->disabled = (vwrq->value >= 2347); + vwrq->fixed = 1; + return OK; +} +#endif + + +/*********************************************************************** +** acx_ioctl_set_encode +*/ +static int +acx_ioctl_set_encode( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_point *dwrq = &wrqu->encoding; + acx_device_t *adev = ndev2adev(ndev); + int index; + int result; + + FN_ENTER; + + log(L_IOCTL, "set encoding flags=0x%04X, size=%d, key: %s\n", + dwrq->flags, dwrq->length, extra ? "set" : "No key"); + + acx_sem_lock(adev); + + index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + + if (dwrq->length > 0) { + /* if index is 0 or invalid, use default key */ + if ((index < 0) || (index > 3)) + index = (int)adev->wep_current_index; + + if (0 == (dwrq->flags & IW_ENCODE_NOKEY)) { + if (dwrq->length > 29) + dwrq->length = 29; /* restrict it */ + + if (dwrq->length > 13) { + /* 29*8 == 232, WEP256 */ + adev->wep_keys[index].size = 29; + } else if (dwrq->length > 5) { + /* 13*8 == 104bit, WEP128 */ + adev->wep_keys[index].size = 13; + } else if (dwrq->length > 0) { + /* 5*8 == 40bit, WEP64 */ + adev->wep_keys[index].size = 5; + } else { + /* disable key */ + adev->wep_keys[index].size = 0; + } + + memset(adev->wep_keys[index].key, 0, + sizeof(adev->wep_keys[index].key)); + memcpy(adev->wep_keys[index].key, extra, dwrq->length); + } + } else { + /* set transmit key */ + if ((index >= 0) && (index <= 3)) + adev->wep_current_index = index; + else if (0 == (dwrq->flags & IW_ENCODE_MODE)) { + /* complain if we were not just setting + * the key mode */ + result = -EINVAL; + goto end_unlock; + } + } + + adev->wep_enabled = !(dwrq->flags & IW_ENCODE_DISABLED); + + if (dwrq->flags & IW_ENCODE_OPEN) { + adev->auth_alg = WLAN_AUTH_ALG_OPENSYSTEM; + adev->wep_restricted = 0; + + } else if (dwrq->flags & IW_ENCODE_RESTRICTED) { + adev->auth_alg = WLAN_AUTH_ALG_SHAREDKEY; + adev->wep_restricted = 1; + } + + /* set flag to make sure the card WEP settings get updated */ + SET_BIT(adev->set_mask, GETSET_WEP); + + log(L_IOCTL, "len=%d, key at 0x%p, flags=0x%X\n", + dwrq->length, extra, dwrq->flags); + + for (index = 0; index <= 3; index++) { + if (adev->wep_keys[index].size) { + log(L_IOCTL, "index=%d, size=%d, key at 0x%p\n", + adev->wep_keys[index].index, + (int) adev->wep_keys[index].size, + adev->wep_keys[index].key); + } + } + result = -EINPROGRESS; + +end_unlock: + acx_sem_unlock(adev); + + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_ioctl_get_encode +*/ +static int +acx_ioctl_get_encode( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_point *dwrq = &wrqu->encoding; + acx_device_t *adev = ndev2adev(ndev); + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + + FN_ENTER; + + if (adev->wep_enabled == 0) { + dwrq->flags = IW_ENCODE_DISABLED; + } else { + if ((index < 0) || (index > 3)) + index = (int)adev->wep_current_index; + + dwrq->flags = (adev->wep_restricted == 1) ? + IW_ENCODE_RESTRICTED : IW_ENCODE_OPEN; + dwrq->length = adev->wep_keys[index].size; + + memcpy(extra, adev->wep_keys[index].key, + adev->wep_keys[index].size); + } + + /* set the current index */ + SET_BIT(dwrq->flags, index + 1); + + log(L_IOCTL, "len=%d, key=%p, flags=0x%X\n", + dwrq->length, dwrq->pointer, + dwrq->flags); + + FN_EXIT1(OK); + return OK; +} + + +/*********************************************************************** +*/ +static int +acx_ioctl_set_power( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_param *vwrq = &wrqu->power; + acx_device_t *adev = ndev2adev(ndev); + int result = -EINPROGRESS; + + FN_ENTER; + + log(L_IOCTL, "set 802.11 powersave flags=0x%04X\n", vwrq->flags); + + acx_sem_lock(adev); + + if (vwrq->disabled) { + CLEAR_BIT(adev->ps_wakeup_cfg, PS_CFG_ENABLE); + SET_BIT(adev->set_mask, GETSET_POWER_80211); + goto end; + } + if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { + u16 ps_timeout = (vwrq->value * 1024) / 1000; + + if (ps_timeout > 255) + ps_timeout = 255; + log(L_IOCTL, "setting PS timeout value to %d time units " + "due to %dus\n", ps_timeout, vwrq->value); + adev->ps_hangover_period = ps_timeout; + } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { + u16 ps_periods = vwrq->value / 1000000; + + if (ps_periods > 255) + ps_periods = 255; + log(L_IOCTL, "setting PS period value to %d periods " + "due to %dus\n", ps_periods, vwrq->value); + adev->ps_listen_interval = ps_periods; + CLEAR_BIT(adev->ps_wakeup_cfg, PS_CFG_WAKEUP_MODE_MASK); + SET_BIT(adev->ps_wakeup_cfg, PS_CFG_WAKEUP_EACH_ITVL); + } + + switch (vwrq->flags & IW_POWER_MODE) { + /* FIXME: are we doing the right thing here? */ + case IW_POWER_UNICAST_R: + CLEAR_BIT(adev->ps_options, PS_OPT_STILL_RCV_BCASTS); + break; + case IW_POWER_MULTICAST_R: + SET_BIT(adev->ps_options, PS_OPT_STILL_RCV_BCASTS); + break; + case IW_POWER_ALL_R: + SET_BIT(adev->ps_options, PS_OPT_STILL_RCV_BCASTS); + break; + case IW_POWER_ON: + break; + default: + log(L_IOCTL, "unknown PS mode\n"); + result = -EINVAL; + goto end; + } + + SET_BIT(adev->ps_wakeup_cfg, PS_CFG_ENABLE); + SET_BIT(adev->set_mask, GETSET_POWER_80211); +end: + acx_sem_unlock(adev); + + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +*/ +static int +acx_ioctl_get_power( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_param *vwrq = &wrqu->power; + acx_device_t *adev = ndev2adev(ndev); + + FN_ENTER; + + log(L_IOCTL, "Get 802.11 Power Save flags = 0x%04X\n", vwrq->flags); + vwrq->disabled = ((adev->ps_wakeup_cfg & PS_CFG_ENABLE) == 0); + if (vwrq->disabled) + goto end; + + if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { + vwrq->value = adev->ps_hangover_period * 1000 / 1024; + vwrq->flags = IW_POWER_TIMEOUT; + } else { + vwrq->value = adev->ps_listen_interval * 1000000; + vwrq->flags = IW_POWER_PERIOD|IW_POWER_RELATIVE; + } + if (adev->ps_options & PS_OPT_STILL_RCV_BCASTS) + SET_BIT(vwrq->flags, IW_POWER_ALL_R); + else + SET_BIT(vwrq->flags, IW_POWER_UNICAST_R); +end: + FN_EXIT1(OK); + return OK; +} + + +/*********************************************************************** +** acx_ioctl_get_txpow +*/ +static inline int +acx_ioctl_get_txpow( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_param *vwrq = &wrqu->power; + acx_device_t *adev = ndev2adev(ndev); + + FN_ENTER; + + vwrq->flags = IW_TXPOW_DBM; + vwrq->disabled = 0; + vwrq->fixed = 1; + vwrq->value = adev->tx_level_dbm; + + log(L_IOCTL, "get txpower:%d dBm\n", adev->tx_level_dbm); + + FN_EXIT1(OK); + return OK; +} + + +/*********************************************************************** +** acx_ioctl_set_txpow +*/ +static int +acx_ioctl_set_txpow( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_param *vwrq = &wrqu->power; + acx_device_t *adev = ndev2adev(ndev); + int result; + + FN_ENTER; + + log(L_IOCTL, "set txpower:%d, disabled:%d, flags:0x%04X\n", + vwrq->value, vwrq->disabled, vwrq->flags); + + acx_sem_lock(adev); + + if (vwrq->disabled != adev->tx_disabled) { + SET_BIT(adev->set_mask, GETSET_TX); + } + + adev->tx_disabled = vwrq->disabled; + if (vwrq->value == -1) { + if (vwrq->disabled) { + adev->tx_level_dbm = 0; + log(L_IOCTL, "disable radio tx\n"); + } else { + /* adev->tx_level_auto = 1; */ + log(L_IOCTL, "set tx power auto (NIY)\n"); + } + } else { + adev->tx_level_dbm = vwrq->value <= 20 ? vwrq->value : 20; + /* adev->tx_level_auto = 0; */ + log(L_IOCTL, "set txpower=%d dBm\n", adev->tx_level_dbm); + } + SET_BIT(adev->set_mask, GETSET_TXPOWER); + + result = -EINPROGRESS; + + acx_sem_unlock(adev); + + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_ioctl_get_range +*/ +static int +acx_ioctl_get_range( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_point *dwrq = &wrqu->data; + struct iw_range *range = (struct iw_range *)extra; + acx_device_t *adev = ndev2adev(ndev); + int i,n; + + FN_ENTER; + + if (!dwrq->pointer) + goto end; + + dwrq->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + n = 0; + for (i = 1; i <= 14; i++) { + if (adev->reg_dom_chanmask & (1 << (i - 1))) { + range->freq[n].i = i; + range->freq[n].m = acx_channel_freq[i - 1] * 100000; + range->freq[n].e = 1; /* units are MHz */ + n++; + } + } + range->num_channels = n; + range->num_frequency = n; + + range->min_rts = 0; + range->max_rts = 2312; + +#if ACX_FRAGMENTATION + range->min_frag = 256; + range->max_frag = 2312; +#endif + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + range->encoding_size[2] = 29; + range->num_encoding_sizes = 3; + range->max_encoding_tokens = 4; + + range->min_pmp = 0; + range->max_pmp = 5000000; + range->min_pmt = 0; + range->max_pmt = 65535 * 1000; + range->pmp_flags = IW_POWER_PERIOD; + range->pmt_flags = IW_POWER_TIMEOUT; + range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; + + if (IS_ACX100(adev)) { /* ACX100 has direct radio programming - arbitrary levels, so offer a lot */ + for (i = 0; i <= IW_MAX_TXPOWER - 1; i++) + range->txpower[i] = 20 * i / (IW_MAX_TXPOWER - 1); + range->num_txpower = IW_MAX_TXPOWER; + range->txpower_capa = IW_TXPOW_DBM; + } + else { + int count = min(IW_MAX_TXPOWER, (int)adev->cfgopt_power_levels.len); + for (i = 0; i <= count; i++) + range->txpower[i] = adev->cfgopt_power_levels.list[i]; + range->num_txpower = count; + /* this list is given in mW */ + range->txpower_capa = IW_TXPOW_MWATT; + } + + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 0x9; + + range->retry_capa = IW_RETRY_LIMIT; + range->retry_flags = IW_RETRY_LIMIT; + range->min_retry = 1; + range->max_retry = 255; + + range->r_time_flags = IW_RETRY_LIFETIME; + range->min_r_time = 0; + /* FIXME: lifetime ranges and orders of magnitude are strange?? */ + range->max_r_time = 65535; + + if (IS_USB(adev)) + range->sensitivity = 0; + else if (IS_ACX111(adev)) + range->sensitivity = 3; + else + range->sensitivity = 255; + + for (i=0; i < adev->rate_supported_len; i++) { + range->bitrate[i] = (adev->rate_supported[i] & ~0x80) * 500000; + /* never happens, but keep it, to be safe: */ + if (range->bitrate[i] == 0) + break; + } + range->num_bitrates = i; + + range->max_qual.qual = 100; + range->max_qual.level = 100; + range->max_qual.noise = 100; + /* TODO: better values */ + range->avg_qual.qual = 90; + range->avg_qual.level = 80; + range->avg_qual.noise = 2; + +end: + FN_EXIT1(OK); + return OK; +} + + +/*********************************************************************** +** Private functions +*/ + +/*********************************************************************** +** acx_ioctl_get_nick +*/ +static inline int +acx_ioctl_get_nick( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_point *dwrq = &wrqu->data; + acx_device_t *adev = ndev2adev(ndev); + + strcpy(extra, adev->nick); + dwrq->length = strlen(extra) + 1; + + return OK; +} + + +/*********************************************************************** +** acx_ioctl_set_nick +*/ +static int +acx_ioctl_set_nick( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_point *dwrq = &wrqu->data; + acx_device_t *adev = ndev2adev(ndev); + int result; + + FN_ENTER; + + acx_sem_lock(adev); + + if (dwrq->length > IW_ESSID_MAX_SIZE + 1) { + result = -E2BIG; + goto end_unlock; + } + + /* extra includes trailing \0, so it's ok */ + strcpy(adev->nick, extra); + result = OK; + +end_unlock: + acx_sem_unlock(adev); + + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_ioctl_get_retry +*/ +static int +acx_ioctl_get_retry( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_param *vwrq = &wrqu->retry; + acx_device_t *adev = ndev2adev(ndev); + unsigned int type = vwrq->flags & IW_RETRY_TYPE; + unsigned int modifier = vwrq->flags & IW_RETRY_MODIFIER; + int result; + + FN_ENTER; + + acx_sem_lock(adev); + + /* return the short retry number by default */ + if (type == IW_RETRY_LIFETIME) { + vwrq->flags = IW_RETRY_LIFETIME; + vwrq->value = adev->msdu_lifetime; + } else if (modifier == IW_RETRY_MAX) { + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + vwrq->value = adev->long_retry; + } else { + vwrq->flags = IW_RETRY_LIMIT; + if (adev->long_retry != adev->short_retry) + SET_BIT(vwrq->flags, IW_RETRY_MIN); + vwrq->value = adev->short_retry; + } + + /* can't be disabled */ + vwrq->disabled = (u8)0; + result = OK; + + acx_sem_unlock(adev); + + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_ioctl_set_retry +*/ +static int +acx_ioctl_set_retry( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_param *vwrq = &wrqu->retry; + acx_device_t *adev = ndev2adev(ndev); + int result; + + FN_ENTER; + + if (!vwrq) { + result = -EFAULT; + goto end; + } + if (vwrq->disabled) { + result = -EINVAL; + goto end; + } + + acx_sem_lock(adev); + + result = -EINVAL; + if (IW_RETRY_LIMIT == (vwrq->flags & IW_RETRY_TYPE)) { + printk("old retry limits: short %d long %d\n", + adev->short_retry, adev->long_retry); + if (vwrq->flags & IW_RETRY_MAX) { + adev->long_retry = vwrq->value; + } else if (vwrq->flags & IW_RETRY_MIN) { + adev->short_retry = vwrq->value; + } else { + /* no modifier: set both */ + adev->long_retry = vwrq->value; + adev->short_retry = vwrq->value; + } + printk("new retry limits: short %d long %d\n", + adev->short_retry, adev->long_retry); + SET_BIT(adev->set_mask, GETSET_RETRY); + result = -EINPROGRESS; + } + else if (vwrq->flags & IW_RETRY_LIFETIME) { + adev->msdu_lifetime = vwrq->value; + printk("new MSDU lifetime: %d\n", adev->msdu_lifetime); + SET_BIT(adev->set_mask, SET_MSDU_LIFETIME); + result = -EINPROGRESS; + } + + acx_sem_unlock(adev); +end: + FN_EXIT1(result); + return result; +} + + +/************************ private ioctls ******************************/ + + +/*********************************************************************** +** acx_ioctl_set_debug +*/ +#if ACX_DEBUG +static int +acx_ioctl_set_debug( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned int debug_new = *((unsigned int *)extra); + int result = -EINVAL; + + log(L_ANY, "setting debug from %04X to %04X\n", acx_debug, debug_new); + acx_debug = debug_new; + + result = OK; + return result; + +} +#endif + + +/*********************************************************************** +** acx_ioctl_list_reg_domain +*/ +static int +acx_ioctl_list_reg_domain( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int i = 1; + const char * const *entry = acx_reg_domain_strings; + + printk("dom# chan# domain/country\n"); + while (*entry) + printk("%4d %s\n", i++, *entry++); + return OK; +} + + +/*********************************************************************** +** acx_ioctl_set_reg_domain +*/ +static int +acx_ioctl_set_reg_domain( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + int result; + + FN_ENTER; + + if ((*extra < 1) || ((size_t)*extra > acx_reg_domain_ids_len)) { + result = -EINVAL; + goto end; + } + + acx_sem_lock(adev); + + adev->reg_dom_id = acx_reg_domain_ids[*extra - 1]; + SET_BIT(adev->set_mask, GETSET_REG_DOMAIN); + + result = -EINPROGRESS; + + acx_sem_unlock(adev); +end: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_ioctl_get_reg_domain +*/ +static int +acx_ioctl_get_reg_domain( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + int dom,i; + + /* no locking */ + dom = adev->reg_dom_id; + + for (i = 1; i <= acx_reg_domain_ids_len; i++) { + if (acx_reg_domain_ids[i-1] == dom) { + log(L_IOCTL, "regulatory domain is currently set " + "to %d (0x%X): %s\n", i, dom, + acx_reg_domain_strings[i-1]); + *extra = i; + break; + } + } + + return OK; +} + + +/*********************************************************************** +** acx_ioctl_set_short_preamble +*/ +static const char * const +preamble_modes[] = { + "off", + "on", + "auto (peer capability dependent)", + "unknown mode, error" +}; + +static int +acx_ioctl_set_short_preamble( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + int i; + int result; + + FN_ENTER; + + if ((unsigned char)*extra > 2) { + result = -EINVAL; + goto end; + } + + acx_sem_lock(adev); + + adev->preamble_mode = (u8)*extra; + switch (adev->preamble_mode) { + case 0: /* long */ + adev->preamble_cur = 0; + break; + case 1: + /* short, kick incapable peers */ + adev->preamble_cur = 1; + for (i = 0; i < VEC_SIZE(adev->sta_list); i++) { + client_t *clt = &adev->sta_list[i]; + if (!clt->used) continue; + if (!(clt->cap_info & WF_MGMT_CAP_SHORT)) { + clt->used = CLIENT_EMPTY_SLOT_0; + } + } + switch (adev->mode) { + case ACX_MODE_2_STA: + if (adev->ap_client && !adev->ap_client->used) { + /* We kicked our AP :) */ + SET_BIT(adev->set_mask, GETSET_RESCAN); + } + } + break; + case 2: /* auto. short only if all peers are short-capable */ + adev->preamble_cur = 1; + for (i = 0; i < VEC_SIZE(adev->sta_list); i++) { + client_t *clt = &adev->sta_list[i]; + if (!clt->used) continue; + if (!(clt->cap_info & WF_MGMT_CAP_SHORT)) { + adev->preamble_cur = 0; + break; + } + } + break; + } + printk("new short preamble setting: configured %s, active %s\n", + preamble_modes[adev->preamble_mode], + preamble_modes[adev->preamble_cur]); + result = OK; + + acx_sem_unlock(adev); +end: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_ioctl_get_short_preamble +*/ +static int +acx_ioctl_get_short_preamble( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + + acx_sem_lock(adev); + + printk("current short preamble setting: configured %s, active %s\n", + preamble_modes[adev->preamble_mode], + preamble_modes[adev->preamble_cur]); + + *extra = (char)adev->preamble_mode; + + acx_sem_unlock(adev); + + return OK; +} + + +/*********************************************************************** +** acx_ioctl_set_antenna +** +** TX and RX antenna can be set separately but this function good +** for testing 0-4 bits +*/ +static int +acx_ioctl_set_antenna( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + + acx_sem_lock(adev); + + printk("old antenna value: 0x%02X (COMBINED bit mask)\n" + "Rx antenna selection:\n" + "0x00 ant. 1\n" + "0x40 ant. 2\n" + "0x80 full diversity\n" + "0xc0 partial diversity\n" + "0x0f dwell time mask (in units of us)\n" + "Tx antenna selection:\n" + "0x00 ant. 2\n" /* yep, those ARE reversed! */ + "0x20 ant. 1\n" + "new antenna value: 0x%02X\n", + adev->antenna, (u8)*extra); + + adev->antenna = (u8)*extra; + SET_BIT(adev->set_mask, GETSET_ANTENNA); + + acx_sem_unlock(adev); + + return -EINPROGRESS; +} + + +/*********************************************************************** +** acx_ioctl_get_antenna +*/ +static int +acx_ioctl_get_antenna( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + + /* no locking. it's pointless to lock a single load */ + printk("current antenna value: 0x%02X (COMBINED bit mask)\n" + "Rx antenna selection:\n" + "0x00 ant. 1\n" + "0x40 ant. 2\n" + "0x80 full diversity\n" + "0xc0 partial diversity\n" + "Tx antenna selection:\n" + "0x00 ant. 2\n" /* yep, those ARE reversed! */ + "0x20 ant. 1\n", adev->antenna); + + return 0; +} + + +/*********************************************************************** +** acx_ioctl_set_rx_antenna +** +** 0 = antenna1; 1 = antenna2; 2 = full diversity; 3 = partial diversity +** Could anybody test which antenna is the external one? +*/ +static int +acx_ioctl_set_rx_antenna( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + int result; + + FN_ENTER; + + if (*extra > 3) { + result = -EINVAL; + goto end; + } + + printk("old antenna value: 0x%02X\n", adev->antenna); + + acx_sem_lock(adev); + + adev->antenna &= 0x3f; + SET_BIT(adev->antenna, (*extra << 6)); + SET_BIT(adev->set_mask, GETSET_ANTENNA); + printk("new antenna value: 0x%02X\n", adev->antenna); + result = -EINPROGRESS; + + acx_sem_unlock(adev); +end: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_ioctl_set_tx_antenna +** +** Arguments: 0 == antenna2; 1 == antenna1; +** Could anybody test which antenna is the external one? +*/ +static int +acx_ioctl_set_tx_antenna( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + int result; + + FN_ENTER; + + if (*extra > 1) { + result = -EINVAL; + goto end; + } + + printk("old antenna value: 0x%02X\n", adev->antenna); + + acx_sem_lock(adev); + + adev->antenna &= ~0x30; + SET_BIT(adev->antenna, ((*extra & 0x01) << 5)); + SET_BIT(adev->set_mask, GETSET_ANTENNA); + printk("new antenna value: 0x%02X\n", adev->antenna); + result = -EINPROGRESS; + + acx_sem_unlock(adev); +end: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_ioctl_wlansniff +** +** can we just remove this in favor of monitor mode? --vda +*/ +static int +acx_ioctl_wlansniff( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + unsigned int *params = (unsigned int*)extra; + unsigned int enable = (unsigned int)(params[0] > 0); + int result; + + FN_ENTER; + + acx_sem_lock(adev); + + /* not using printk() here, since it distorts kismet display + * when printk messages activated */ + log(L_IOCTL, "setting monitor to: 0x%02X\n", params[0]); + + switch (params[0]) { + case 0: + /* no monitor mode. hmm, should we simply ignore it + * or go back to enabling adev->netdev->type ARPHRD_ETHER? */ + break; + case 1: + adev->monitor_type = ARPHRD_IEEE80211_PRISM; + break; + case 2: + adev->monitor_type = ARPHRD_IEEE80211; + break; + } + + if (params[0]) { + adev->mode = ACX_MODE_MONITOR; + SET_BIT(adev->set_mask, GETSET_MODE); + } + + if (enable) { + adev->channel = params[1]; + SET_BIT(adev->set_mask, GETSET_RX); + } + result = -EINPROGRESS; + + acx_sem_unlock(adev); + + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_ioctl_unknown11 +** FIXME: looks like some sort of "iwpriv kick_sta MAC" but it's broken +*/ +static int +acx_ioctl_unknown11( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ +#ifdef BROKEN + struct iw_param *vwrq = &wrqu->param; + acx_device_t *adev = ndev2adev(ndev); + unsigned long flags; + client_t client; + int result; + + acx_sem_lock(adev); + acx_lock(adev, flags); + + acx_l_transmit_disassoc(adev, &client); + result = OK; + + acx_unlock(adev, flags); + acx_sem_unlock(adev); + + return result; +#endif + return -EINVAL; +} + + +/*********************************************************************** +** debug helper function to be able to debug various issues relatively easily +*/ +static int +acx_ioctl_dbg_set_masks( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + const unsigned int *params = (unsigned int*)extra; + int result; + + acx_sem_lock(adev); + + log(L_IOCTL, "setting flags in settings mask: " + "get_mask %08X set_mask %08X\n" + "before: get_mask %08X set_mask %08X\n", + params[0], params[1], + adev->get_mask, adev->set_mask); + SET_BIT(adev->get_mask, params[0]); + SET_BIT(adev->set_mask, params[1]); + log(L_IOCTL, "after: get_mask %08X set_mask %08X\n", + adev->get_mask, adev->set_mask); + result = -EINPROGRESS; /* immediately call commit handler */ + + acx_sem_unlock(adev); + + return result; +} + + +/*********************************************************************** +* acx_ioctl_set_rates +* +* This ioctl takes string parameter. Examples: +* iwpriv wlan0 SetRates "1,2" +* use 1 and 2 Mbit rates, both are in basic rate set +* iwpriv wlan0 SetRates "1,2 5,11" +* use 1,2,5.5,11 Mbit rates. 1 and 2 are basic +* iwpriv wlan0 SetRates "1,2 5c,11c" +* same ('c' means 'CCK modulation' and it is a default for 5 and 11) +* iwpriv wlan0 SetRates "1,2 5p,11p" +* use 1,2,5.5,11 Mbit, 1,2 are basic. 5 and 11 are using PBCC +* iwpriv wlan0 SetRates "1,2,5,11 22p" +* use 1,2,5.5,11,22 Mbit. 1,2,5.5 and 11 are basic. 22 is using PBCC +* (this is the maximum acx100 can do (modulo x4 mode)) +* iwpriv wlan0 SetRates "1,2,5,11 22" +* same. 802.11 defines only PBCC modulation +* for 22 and 33 Mbit rates, so there is no ambiguity +* iwpriv wlan0 SetRates "1,2,5,11 6o,9o,12o,18o,24o,36o,48o,54o" +* 1,2,5.5 and 11 are basic. 11g OFDM rates are enabled but +* they are not in basic rate set. 22 Mbit is disabled. +* iwpriv wlan0 SetRates "1,2,5,11 6,9,12,18,24,36,48,54" +* same. OFDM is default for 11g rates except 22 and 33 Mbit, +* thus 'o' is optional +* iwpriv wlan0 SetRates "1,2,5,11 6d,9d,12d,18d,24d,36d,48d,54d" +* 1,2,5.5 and 11 are basic. 11g CCK-OFDM rates are enabled +* (acx111 does not support CCK-OFDM, driver will reject this cmd) +* iwpriv wlan0 SetRates "6,9,12 18,24,36,48,54" +* 6,9,12 are basic, rest of 11g rates is enabled. Using OFDM +*/ +#include "setrate.c" + +/* disallow: 33Mbit (unsupported by hw) */ +/* disallow: CCKOFDM (unsupported by hw) */ +static int +acx111_supported(int mbit, int modulation, void *opaque) +{ + if (mbit==33) return -ENOTSUPP; + if (modulation==DOT11_MOD_CCKOFDM) return -ENOTSUPP; + return OK; +} + +static const u16 +acx111mask[] = { + [DOT11_RATE_1 ] = RATE111_1 , + [DOT11_RATE_2 ] = RATE111_2 , + [DOT11_RATE_5 ] = RATE111_5 , + [DOT11_RATE_11] = RATE111_11, + [DOT11_RATE_22] = RATE111_22, + /* [DOT11_RATE_33] = */ + [DOT11_RATE_6 ] = RATE111_6 , + [DOT11_RATE_9 ] = RATE111_9 , + [DOT11_RATE_12] = RATE111_12, + [DOT11_RATE_18] = RATE111_18, + [DOT11_RATE_24] = RATE111_24, + [DOT11_RATE_36] = RATE111_36, + [DOT11_RATE_48] = RATE111_48, + [DOT11_RATE_54] = RATE111_54, +}; + +static u32 +acx111_gen_mask(int mbit, int modulation, void *opaque) +{ + /* lower 16 bits show selected 1, 2, CCK and OFDM rates */ + /* upper 16 bits show selected PBCC rates */ + u32 m = acx111mask[rate_mbit2enum(mbit)]; + if (modulation==DOT11_MOD_PBCC) + return m<<16; + return m; +} + +static int +verify_rate(u32 rate, int chip_type) +{ + /* never happens. be paranoid */ + if (!rate) return -EINVAL; + + /* disallow: mixing PBCC and CCK at 5 and 11Mbit + ** (can be supported, but needs complicated handling in tx code) */ + if (( rate & ((RATE111_11+RATE111_5)<<16) ) + && ( rate & (RATE111_11+RATE111_5) ) + ) { + return -ENOTSUPP; + } + if (CHIPTYPE_ACX100 == chip_type) { + if ( rate & ~(RATE111_ACX100_COMPAT+(RATE111_ACX100_COMPAT<<16)) ) + return -ENOTSUPP; + } + return 0; +} + +static int +acx_ioctl_set_rates(struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + unsigned long flags; + int result; + u32 brate = 0, orate = 0; /* basic, operational rate set */ + + FN_ENTER; + + log(L_IOCTL, "set_rates %s\n", extra); + result = fill_ratemasks(extra, &brate, &orate, + acx111_supported, acx111_gen_mask, 0); + if (result) goto end; + SET_BIT(orate, brate); + log(L_IOCTL, "brate %08X orate %08X\n", brate, orate); + + result = verify_rate(brate, adev->chip_type); + if (result) goto end; + result = verify_rate(orate, adev->chip_type); + if (result) goto end; + + acx_sem_lock(adev); + acx_lock(adev, flags); + + adev->rate_basic = brate; + adev->rate_oper = orate; + /* TODO: ideally, we shall monitor highest basic rate + ** which was successfully sent to every peer + ** (say, last we checked, everybody could hear 5.5 Mbits) + ** and use that for bcasts when we want to reach all peers. + ** For beacons, we probably shall use lowest basic rate + ** because we want to reach all *potential* new peers too */ + adev->rate_bcast = 1 << lowest_bit(brate); + if (IS_ACX100(adev)) + adev->rate_bcast100 = acx_rate111to100(adev->rate_bcast); + adev->rate_auto = !has_only_one_bit(orate); + acx_l_update_client_rates(adev, orate); + /* TODO: get rid of ratevector, build it only when needed */ + acx_l_update_ratevector(adev); + + /* Do/don't do tx rate fallback; beacon contents and rate */ + SET_BIT(adev->set_mask, SET_RATE_FALLBACK|SET_TEMPLATES); + result = -EINPROGRESS; + + acx_unlock(adev, flags); + acx_sem_unlock(adev); +end: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_ioctl_get_phy_chan_busy_percentage +*/ +static int +acx_ioctl_get_phy_chan_busy_percentage( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + struct { + u16 type; + u16 len; + u32 busytime; + u32 totaltime; + } ACX_PACKED usage; + int result; + + acx_sem_lock(adev); + + if (OK != acx_s_interrogate(adev, &usage, ACX1xx_IE_MEDIUM_USAGE)) { + result = NOT_OK; + goto end_unlock; + } + + usage.busytime = le32_to_cpu(usage.busytime); + usage.totaltime = le32_to_cpu(usage.totaltime); + + /* yes, this is supposed to be "Medium" (singular of media), + not "average"! OK, reword the message to make it obvious... */ + printk("%s: busy percentage of medium (since last invocation): %d%% " + "(%u of %u microseconds)\n", + ndev->name, + usage.busytime / ((usage.totaltime / 100) + 1), + usage.busytime, usage.totaltime); + + result = OK; + +end_unlock: + acx_sem_unlock(adev); + + return result; +} + + +/*********************************************************************** +** acx_ioctl_set_ed_threshold +*/ +static inline int +acx_ioctl_set_ed_threshold( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + + acx_sem_lock(adev); + + printk("old ED threshold value: %d\n", adev->ed_threshold); + adev->ed_threshold = (unsigned char)*extra; + printk("new ED threshold value: %d\n", (unsigned char)*extra); + SET_BIT(adev->set_mask, GETSET_ED_THRESH); + + acx_sem_unlock(adev); + + return -EINPROGRESS; +} + + +/*********************************************************************** +** acx_ioctl_set_cca +*/ +static inline int +acx_ioctl_set_cca( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + int result; + + acx_sem_lock(adev); + + printk("old CCA value: 0x%02X\n", adev->cca); + adev->cca = (unsigned char)*extra; + printk("new CCA value: 0x%02X\n", (unsigned char)*extra); + SET_BIT(adev->set_mask, GETSET_CCA); + result = -EINPROGRESS; + + acx_sem_unlock(adev); + + return result; +} + + +/*********************************************************************** +*/ +static const char * const +scan_modes[] = { "active", "passive", "background" }; + +static void +acx_print_scan_params(acx_device_t *adev, const char* head) +{ + printk("%s: %smode %d (%s), min chan time %dTU, " + "max chan time %dTU, max scan rate byte: %d\n", + adev->ndev->name, head, + adev->scan_mode, scan_modes[adev->scan_mode], + adev->scan_probe_delay, adev->scan_duration, adev->scan_rate); +} + +static int +acx_ioctl_set_scan_params( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + int result; + const int *params = (int *)extra; + + acx_sem_lock(adev); + + acx_print_scan_params(adev, "old scan parameters: "); + if ((params[0] != -1) && (params[0] >= 0) && (params[0] <= 2)) + adev->scan_mode = params[0]; + if (params[1] != -1) + adev->scan_probe_delay = params[1]; + if (params[2] != -1) + adev->scan_duration = params[2]; + if ((params[3] != -1) && (params[3] <= 255)) + adev->scan_rate = params[3]; + acx_print_scan_params(adev, "new scan parameters: "); + SET_BIT(adev->set_mask, GETSET_RESCAN); + result = -EINPROGRESS; + + acx_sem_unlock(adev); + + return result; +} + +static int +acx_ioctl_get_scan_params( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + int result; + int *params = (int *)extra; + + acx_sem_lock(adev); + + acx_print_scan_params(adev, "current scan parameters: "); + params[0] = adev->scan_mode; + params[1] = adev->scan_probe_delay; + params[2] = adev->scan_duration; + params[3] = adev->scan_rate; + result = OK; + + acx_sem_unlock(adev); + + return result; +} + + +/*********************************************************************** +*/ +static int +acx100_ioctl_set_led_power( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + static const char * const led_modes[] = { "off", "on", "LinkQuality" }; + + acx_device_t *adev = ndev2adev(ndev); + int result; + + acx_sem_lock(adev); + + printk("%s: power LED status: old %d (%s), ", + ndev->name, + adev->led_power, + led_modes[adev->led_power]); + adev->led_power = extra[0]; + if (adev->led_power > 2) adev->led_power = 2; + printk("new %d (%s)\n", + adev->led_power, + led_modes[adev->led_power]); + + if (adev->led_power == 2) { + printk("%s: max link quality setting: old %d, ", + ndev->name, adev->brange_max_quality); + if (extra[1]) + adev->brange_max_quality = extra[1]; + printk("new %d\n", adev->brange_max_quality); + } + + SET_BIT(adev->set_mask, GETSET_LED_POWER); + + result = -EINPROGRESS; + + acx_sem_unlock(adev); + + return result; +} + + +/*********************************************************************** +*/ +static inline int +acx100_ioctl_get_led_power( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + acx_device_t *adev = ndev2adev(ndev); + + acx_sem_lock(adev); + + extra[0] = adev->led_power; + if (adev->led_power == 2) + extra[1] = adev->brange_max_quality; + else + extra[1] = -1; + + acx_sem_unlock(adev); + + return OK; +} + + +/*********************************************************************** +*/ +static int +acx111_ioctl_info( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_param *vwrq = &wrqu->param; + if (!IS_PCI(ndev2adev(ndev))) + return OK; + return acx111pci_ioctl_info(ndev, info, vwrq, extra); +} + + +/*********************************************************************** +*/ +static int +acx100_ioctl_set_phy_amp_bias( + struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_param *vwrq = &wrqu->param; + if (!IS_PCI(ndev2adev(ndev))) { + printk("acx: set_phy_amp_bias() is not supported on USB\n"); + return OK; + } + return acx100pci_ioctl_set_phy_amp_bias(ndev, info, vwrq, extra); +} + + +/*********************************************************************** +*/ +static const iw_handler acx_ioctl_handler[] = +{ + acx_ioctl_commit, /* SIOCSIWCOMMIT */ + acx_ioctl_get_name, /* SIOCGIWNAME */ + NULL, /* SIOCSIWNWID */ + NULL, /* SIOCGIWNWID */ + acx_ioctl_set_freq, /* SIOCSIWFREQ */ + acx_ioctl_get_freq, /* SIOCGIWFREQ */ + acx_ioctl_set_mode, /* SIOCSIWMODE */ + acx_ioctl_get_mode, /* SIOCGIWMODE */ + acx_ioctl_set_sens, /* SIOCSIWSENS */ + acx_ioctl_get_sens, /* SIOCGIWSENS */ + NULL, /* SIOCSIWRANGE */ + acx_ioctl_get_range, /* SIOCGIWRANGE */ + NULL, /* SIOCSIWPRIV */ + NULL, /* SIOCGIWPRIV */ + NULL, /* SIOCSIWSTATS */ + NULL, /* SIOCGIWSTATS */ +#if IW_HANDLER_VERSION > 4 + iw_handler_set_spy, /* SIOCSIWSPY */ + iw_handler_get_spy, /* SIOCGIWSPY */ + iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ + iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ +#else /* IW_HANDLER_VERSION > 4 */ +#ifdef WIRELESS_SPY + NULL /* acx_ioctl_set_spy FIXME */, /* SIOCSIWSPY */ + NULL /* acx_ioctl_get_spy */, /* SIOCGIWSPY */ +#else /* WSPY */ + NULL, /* SIOCSIWSPY */ + NULL, /* SIOCGIWSPY */ +#endif /* WSPY */ + NULL, /* [nothing] */ + NULL, /* [nothing] */ +#endif /* IW_HANDLER_VERSION > 4 */ + acx_ioctl_set_ap, /* SIOCSIWAP */ + acx_ioctl_get_ap, /* SIOCGIWAP */ + NULL, /* [nothing] */ + acx_ioctl_get_aplist, /* SIOCGIWAPLIST */ + acx_ioctl_set_scan, /* SIOCSIWSCAN */ + acx_ioctl_get_scan, /* SIOCGIWSCAN */ + acx_ioctl_set_essid, /* SIOCSIWESSID */ + acx_ioctl_get_essid, /* SIOCGIWESSID */ + acx_ioctl_set_nick, /* SIOCSIWNICKN */ + acx_ioctl_get_nick, /* SIOCGIWNICKN */ + NULL, /* [nothing] */ + NULL, /* [nothing] */ + acx_ioctl_set_rate, /* SIOCSIWRATE */ + acx_ioctl_get_rate, /* SIOCGIWRATE */ + acx_ioctl_set_rts, /* SIOCSIWRTS */ + acx_ioctl_get_rts, /* SIOCGIWRTS */ +#if ACX_FRAGMENTATION + acx_ioctl_set_frag, /* SIOCSIWFRAG */ + acx_ioctl_get_frag, /* SIOCGIWFRAG */ +#else + NULL, /* SIOCSIWFRAG */ + NULL, /* SIOCGIWFRAG */ +#endif + acx_ioctl_set_txpow, /* SIOCSIWTXPOW */ + acx_ioctl_get_txpow, /* SIOCGIWTXPOW */ + acx_ioctl_set_retry, /* SIOCSIWRETRY */ + acx_ioctl_get_retry, /* SIOCGIWRETRY */ + acx_ioctl_set_encode, /* SIOCSIWENCODE */ + acx_ioctl_get_encode, /* SIOCGIWENCODE */ + acx_ioctl_set_power, /* SIOCSIWPOWER */ + acx_ioctl_get_power, /* SIOCGIWPOWER */ +}; + + +/*********************************************************************** +*/ + +/* if you plan to reorder something, make sure to reorder all other places + * accordingly! */ +/* SET/GET convention: SETs must have even position, GETs odd */ +#define ACX100_IOCTL SIOCIWFIRSTPRIV +enum { + ACX100_IOCTL_DEBUG = ACX100_IOCTL, + ACX100_IOCTL_GET__________UNUSED1, + ACX100_IOCTL_SET_PLED, + ACX100_IOCTL_GET_PLED, + ACX100_IOCTL_SET_RATES, + ACX100_IOCTL_LIST_DOM, + ACX100_IOCTL_SET_DOM, + ACX100_IOCTL_GET_DOM, + ACX100_IOCTL_SET_SCAN_PARAMS, + ACX100_IOCTL_GET_SCAN_PARAMS, + ACX100_IOCTL_SET_PREAMB, + ACX100_IOCTL_GET_PREAMB, + ACX100_IOCTL_SET_ANT, + ACX100_IOCTL_GET_ANT, + ACX100_IOCTL_RX_ANT, + ACX100_IOCTL_TX_ANT, + ACX100_IOCTL_SET_PHY_AMP_BIAS, + ACX100_IOCTL_GET_PHY_CHAN_BUSY, + ACX100_IOCTL_SET_ED, + ACX100_IOCTL_GET__________UNUSED3, + ACX100_IOCTL_SET_CCA, + ACX100_IOCTL_GET__________UNUSED4, + ACX100_IOCTL_MONITOR, + ACX100_IOCTL_TEST, + ACX100_IOCTL_DBG_SET_MASKS, + ACX111_IOCTL_INFO, + ACX100_IOCTL_DBG_SET_IO, + ACX100_IOCTL_DBG_GET_IO +}; + + +static const iw_handler acx_ioctl_private_handler[] = +{ +#if ACX_DEBUG +[ACX100_IOCTL_DEBUG - ACX100_IOCTL] = acx_ioctl_set_debug, +#endif +[ACX100_IOCTL_SET_PLED - ACX100_IOCTL] = acx100_ioctl_set_led_power, +[ACX100_IOCTL_GET_PLED - ACX100_IOCTL] = acx100_ioctl_get_led_power, +[ACX100_IOCTL_SET_RATES - ACX100_IOCTL] = acx_ioctl_set_rates, +[ACX100_IOCTL_LIST_DOM - ACX100_IOCTL] = acx_ioctl_list_reg_domain, +[ACX100_IOCTL_SET_DOM - ACX100_IOCTL] = acx_ioctl_set_reg_domain, +[ACX100_IOCTL_GET_DOM - ACX100_IOCTL] = acx_ioctl_get_reg_domain, +[ACX100_IOCTL_SET_SCAN_PARAMS - ACX100_IOCTL] = acx_ioctl_set_scan_params, +[ACX100_IOCTL_GET_SCAN_PARAMS - ACX100_IOCTL] = acx_ioctl_get_scan_params, +[ACX100_IOCTL_SET_PREAMB - ACX100_IOCTL] = acx_ioctl_set_short_preamble, +[ACX100_IOCTL_GET_PREAMB - ACX100_IOCTL] = acx_ioctl_get_short_preamble, +[ACX100_IOCTL_SET_ANT - ACX100_IOCTL] = acx_ioctl_set_antenna, +[ACX100_IOCTL_GET_ANT - ACX100_IOCTL] = acx_ioctl_get_antenna, +[ACX100_IOCTL_RX_ANT - ACX100_IOCTL] = acx_ioctl_set_rx_antenna, +[ACX100_IOCTL_TX_ANT - ACX100_IOCTL] = acx_ioctl_set_tx_antenna, +[ACX100_IOCTL_SET_PHY_AMP_BIAS - ACX100_IOCTL] = acx100_ioctl_set_phy_amp_bias, +[ACX100_IOCTL_GET_PHY_CHAN_BUSY - ACX100_IOCTL] = acx_ioctl_get_phy_chan_busy_percentage, +[ACX100_IOCTL_SET_ED - ACX100_IOCTL] = acx_ioctl_set_ed_threshold, +[ACX100_IOCTL_SET_CCA - ACX100_IOCTL] = acx_ioctl_set_cca, +[ACX100_IOCTL_MONITOR - ACX100_IOCTL] = acx_ioctl_wlansniff, +[ACX100_IOCTL_TEST - ACX100_IOCTL] = acx_ioctl_unknown11, +[ACX100_IOCTL_DBG_SET_MASKS - ACX100_IOCTL] = acx_ioctl_dbg_set_masks, +[ACX111_IOCTL_INFO - ACX100_IOCTL] = acx111_ioctl_info, +}; + + +static const struct iw_priv_args acx_ioctl_private_args[] = { +#if ACX_DEBUG +{ cmd : ACX100_IOCTL_DEBUG, + set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + get_args : 0, + name : "SetDebug" }, +#endif +{ cmd : ACX100_IOCTL_SET_PLED, + set_args : IW_PRIV_TYPE_BYTE | 2, + get_args : 0, + name : "SetLEDPower" }, +{ cmd : ACX100_IOCTL_GET_PLED, + set_args : 0, + get_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 2, + name : "GetLEDPower" }, +{ cmd : ACX100_IOCTL_SET_RATES, + set_args : IW_PRIV_TYPE_CHAR | 256, + get_args : 0, + name : "SetRates" }, +{ cmd : ACX100_IOCTL_LIST_DOM, + set_args : 0, + get_args : 0, + name : "ListRegDomain" }, +{ cmd : ACX100_IOCTL_SET_DOM, + set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, + get_args : 0, + name : "SetRegDomain" }, +{ cmd : ACX100_IOCTL_GET_DOM, + set_args : 0, + get_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, + name : "GetRegDomain" }, +{ cmd : ACX100_IOCTL_SET_SCAN_PARAMS, + set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 4, + get_args : 0, + name : "SetScanParams" }, +{ cmd : ACX100_IOCTL_GET_SCAN_PARAMS, + set_args : 0, + get_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 4, + name : "GetScanParams" }, +{ cmd : ACX100_IOCTL_SET_PREAMB, + set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, + get_args : 0, + name : "SetSPreamble" }, +{ cmd : ACX100_IOCTL_GET_PREAMB, + set_args : 0, + get_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, + name : "GetSPreamble" }, +{ cmd : ACX100_IOCTL_SET_ANT, + set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, + get_args : 0, + name : "SetAntenna" }, +{ cmd : ACX100_IOCTL_GET_ANT, + set_args : 0, + get_args : 0, + name : "GetAntenna" }, +{ cmd : ACX100_IOCTL_RX_ANT, + set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, + get_args : 0, + name : "SetRxAnt" }, +{ cmd : ACX100_IOCTL_TX_ANT, + set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, + get_args : 0, + name : "SetTxAnt" }, +{ cmd : ACX100_IOCTL_SET_PHY_AMP_BIAS, + set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, + get_args : 0, + name : "SetPhyAmpBias"}, +{ cmd : ACX100_IOCTL_GET_PHY_CHAN_BUSY, + set_args : 0, + get_args : 0, + name : "GetPhyChanBusy" }, +{ cmd : ACX100_IOCTL_SET_ED, + set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + get_args : 0, + name : "SetED" }, +{ cmd : ACX100_IOCTL_SET_CCA, + set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, + get_args : 0, + name : "SetCCA" }, +{ cmd : ACX100_IOCTL_MONITOR, + set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + get_args : 0, + name : "monitor" }, +{ cmd : ACX100_IOCTL_TEST, + set_args : 0, + get_args : 0, + name : "Test" }, +{ cmd : ACX100_IOCTL_DBG_SET_MASKS, + set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + get_args : 0, + name : "DbgSetMasks" }, +{ cmd : ACX111_IOCTL_INFO, + set_args : 0, + get_args : 0, + name : "GetAcx111Info" }, +{ cmd : ACX100_IOCTL_DBG_SET_IO, + set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 4, + get_args : 0, + name : "DbgSetIO" }, +{ cmd : ACX100_IOCTL_DBG_GET_IO, + set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + get_args : 0, + name : "DbgGetIO" }, +}; + + +const struct iw_handler_def acx_ioctl_handler_def = +{ + .num_standard = VEC_SIZE(acx_ioctl_handler), + .num_private = VEC_SIZE(acx_ioctl_private_handler), + .num_private_args = VEC_SIZE(acx_ioctl_private_args), + .standard = (iw_handler *) acx_ioctl_handler, + .private = (iw_handler *) acx_ioctl_private_handler, + .private_args = (struct iw_priv_args *) acx_ioctl_private_args, +#if IW_HANDLER_VERSION > 5 + .get_wireless_stats = acx_e_get_wireless_stats +#endif /* IW > 5 */ +}; --- linux-2.6.27.orig/ubuntu/misc/wireless/acx/acx_func.h +++ linux-2.6.27/ubuntu/misc/wireless/acx/acx_func.h @@ -0,0 +1,651 @@ +/*********************************************************************** +** Copyright (C) 2003 ACX100 Open Source Project +** +** The contents of this file are subject to the Mozilla Public +** License Version 1.1 (the "License"); you may not use this file +** except in compliance with the License. You may obtain a copy of +** the License at http://www.mozilla.org/MPL/ +** +** Software distributed under the License is distributed on an "AS +** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +** implied. See the License for the specific language governing +** rights and limitations under the License. +** +** Alternatively, the contents of this file may be used under the +** terms of the GNU Public License version 2 (the "GPL"), in which +** case the provisions of the GPL are applicable instead of the +** above. If you wish to allow the use of your version of this file +** only under the terms of the GPL and not to allow others to use +** your version of this file under the MPL, indicate your decision +** by deleting the provisions above and replace them with the notice +** and other provisions required by the GPL. If you do not delete +** the provisions above, a recipient may use your version of this +** file under either the MPL or the GPL. +** --------------------------------------------------------------------- +** Inquiries regarding the ACX100 Open Source Project can be +** made directly to: +** +** acx100-users@lists.sf.net +** http://acx100.sf.net +** --------------------------------------------------------------------- +*/ + + +/*********************************************************************** +** LOGGING +** +** - Avoid SHOUTING needlessly. Avoid excessive verbosity. +** Gradually remove messages which are old debugging aids. +** +** - Use printk() for messages which are to be always logged. +** Supply either 'acx:' or ':' prefix so that user +** can figure out who's speaking among other kernel chatter. +** acx: is for general issues (e.g. "acx: no firmware image!") +** while : is related to a particular device +** (think about multi-card setup). Double check that message +** is not confusing to the average user. +** +** - use printk KERN_xxx level only if message is not a WARNING +** but is INFO, ERR etc. +** +** - Use printk_ratelimited() for messages which may flood +** (e.g. "rx DUP pkt!"). +** +** - Use log() for messages which may be omitted (and they +** _will_ be omitted in non-debug builds). Note that +** message levels may be disabled at compile-time selectively, +** thus select them wisely. Example: L_DEBUG is the lowest +** (most likely to be compiled out) -> use for less important stuff. +** +** - Do not print important stuff with log(), or else people +** will never build non-debug driver. +** +** Style: +** hex: capital letters, zero filled (e.g. 0x02AC) +** str: dont start from capitals, no trailing periods ("tx: queue is stopped") +*/ +#if ACX_DEBUG > 1 + +void log_fn_enter(const char *funcname); +void log_fn_exit(const char *funcname); +void log_fn_exit_v(const char *funcname, int v); + +#define FN_ENTER \ + do { \ + if (unlikely(acx_debug & L_FUNC)) { \ + log_fn_enter(__func__); \ + } \ + } while (0) + +#define FN_EXIT1(v) \ + do { \ + if (unlikely(acx_debug & L_FUNC)) { \ + log_fn_exit_v(__func__, v); \ + } \ + } while (0) +#define FN_EXIT0 \ + do { \ + if (unlikely(acx_debug & L_FUNC)) { \ + log_fn_exit(__func__); \ + } \ + } while (0) + +#else + +#define FN_ENTER +#define FN_EXIT1(v) +#define FN_EXIT0 + +#endif /* ACX_DEBUG > 1 */ + + +#if ACX_DEBUG + +#define log(chan, args...) \ + do { \ + if (acx_debug & (chan)) \ + printk(args); \ + } while (0) +#define printk_ratelimited(args...) printk(args) + +#else /* Non-debug build: */ + +#define log(chan, args...) +/* Standard way of log flood prevention */ +#define printk_ratelimited(args...) \ +do { \ + if (printk_ratelimit()) \ + printk(args); \ +} while (0) + +#endif /* ACX_DEBUG */ + +void acx_print_mac(const char *head, const u8 *mac, const char *tail); + +/* Optimized out to nothing in non-debug build */ +static inline void +acxlog_mac(int level, const char *head, const u8 *mac, const char *tail) +{ + if (acx_debug & level) { + acx_print_mac(head, mac, tail); + } +} + + +/*********************************************************************** +** MAC address helpers +*/ +static inline void +MAC_COPY(u8 *mac, const u8 *src) +{ + *(u32*)mac = *(u32*)src; + ((u16*)mac)[2] = ((u16*)src)[2]; + /* kernel's memcpy will do the same: memcpy(dst, src, ETH_ALEN); */ +} + +static inline void +MAC_FILL(u8 *mac, u8 val) +{ + memset(mac, val, ETH_ALEN); +} + +static inline void +MAC_BCAST(u8 *mac) +{ + ((u16*)mac)[2] = *(u32*)mac = -1; +} + +static inline void +MAC_ZERO(u8 *mac) +{ + ((u16*)mac)[2] = *(u32*)mac = 0; +} + +static inline int +mac_is_equal(const u8 *a, const u8 *b) +{ + /* can't beat this */ + return memcmp(a, b, ETH_ALEN) == 0; +} + +static inline int +mac_is_bcast(const u8 *mac) +{ + /* AND together 4 first bytes with sign-extended 2 last bytes + ** Only bcast address gives 0xffffffff. +1 gives 0 */ + return ( *(s32*)mac & ((s16*)mac)[2] ) + 1 == 0; +} + +static inline int +mac_is_zero(const u8 *mac) +{ + return ( *(u32*)mac | ((u16*)mac)[2] ) == 0; +} + +static inline int +mac_is_directed(const u8 *mac) +{ + return (mac[0] & 1)==0; +} + +static inline int +mac_is_mcast(const u8 *mac) +{ + return (mac[0] & 1) && !mac_is_bcast(mac); +} + +#define MACSTR "%02X:%02X:%02X:%02X:%02X:%02X" +#define MAC(bytevector) \ + ((unsigned char *)bytevector)[0], \ + ((unsigned char *)bytevector)[1], \ + ((unsigned char *)bytevector)[2], \ + ((unsigned char *)bytevector)[3], \ + ((unsigned char *)bytevector)[4], \ + ((unsigned char *)bytevector)[5] + + +/*********************************************************************** +** Random helpers +*/ +#define TO_STRING(x) #x +#define STRING(x) TO_STRING(x) + +#define CLEAR_BIT(val, mask) ((val) &= ~(mask)) +#define SET_BIT(val, mask) ((val) |= (mask)) + +/* undefined if v==0 */ +static inline unsigned int +lowest_bit(u16 v) +{ + unsigned int n = 0; + while (!(v & 0xf)) { v>>=4; n+=4; } + while (!(v & 1)) { v>>=1; n++; } + return n; +} + +/* undefined if v==0 */ +static inline unsigned int +highest_bit(u16 v) +{ + unsigned int n = 0; + while (v>0xf) { v>>=4; n+=4; } + while (v>1) { v>>=1; n++; } + return n; +} + +/* undefined if v==0 */ +static inline int +has_only_one_bit(u16 v) +{ + return ((v-1) ^ v) >= v; +} + + +static inline int +is_hidden_essid(char *essid) +{ + return (('\0' == essid[0]) || + ((' ' == essid[0]) && ('\0' == essid[1]))); +} + +/*********************************************************************** +** LOCKING +** We have adev->sem and adev->lock. +** +** We employ following naming convention in order to get locking right: +** +** acx_e_xxxx - external entry points called from process context. +** It is okay to sleep. adev->sem is to be taken on entry. +** acx_i_xxxx - external entry points possibly called from atomic context. +** Sleeping is not allowed (and thus down(sem) is not legal!) +** acx_s_xxxx - potentially sleeping functions. Do not ever call under lock! +** acx_l_xxxx - functions which expect lock to be already taken. +** rest - non-sleeping functions which do not require locking +** but may be run under lock +** +** A small number of local helpers do not have acx_[eisl]_ prefix. +** They are always close to caller and are to be reviewed locally. +** +** Theory of operation: +** +** All process-context entry points (_e_ functions) take sem +** immediately. IRQ handler and other 'atomic-context' entry points +** (_i_ functions) take lock immediately on entry, but dont take sem +** because that might sleep. +** +** Thus *all* code is either protected by sem or lock, or both. +** +** Code which must not run concurrently with IRQ takes lock. +** Such code is marked with _l_. +** +** This results in the following rules of thumb useful in code review: +** +** + If a function calls _s_ fn, it must be an _s_ itself. +** + You can call _l_ fn only (a) from another _l_ fn +** or (b) from _s_, _e_ or _i_ fn by taking lock, calling _l_, +** and dropping lock. +** + All IRQ code runs under lock. +** + Any _s_ fn is running under sem. +** + Code under sem can race only with IRQ code. +** + Code under sem+lock cannot race with anything. +*/ + +/* These functions *must* be inline or they will break horribly on SPARC, due + * to its weird semantics for save/restore flags */ + +#if defined(PARANOID_LOCKING) /* Lock debugging */ + +void acx_lock_debug(acx_device_t *adev, const char* where); +void acx_unlock_debug(acx_device_t *adev, const char* where); +void acx_down_debug(acx_device_t *adev, const char* where); +void acx_up_debug(acx_device_t *adev, const char* where); +void acx_lock_unhold(void); +void acx_sem_unhold(void); + +static inline void +acx_lock_helper(acx_device_t *adev, unsigned long *fp, const char* where) +{ + acx_lock_debug(adev, where); + spin_lock_irqsave(&adev->lock, *fp); +} +static inline void +acx_unlock_helper(acx_device_t *adev, unsigned long *fp, const char* where) +{ + acx_unlock_debug(adev, where); + spin_unlock_irqrestore(&adev->lock, *fp); +} +static inline void +acx_down_helper(acx_device_t *adev, const char* where) +{ + acx_down_debug(adev, where); +} +static inline void +acx_up_helper(acx_device_t *adev, const char* where) +{ + acx_up_debug(adev, where); +} +#define acx_lock(adev, flags) acx_lock_helper(adev, &(flags), __FILE__ ":" STRING(__LINE__)) +#define acx_unlock(adev, flags) acx_unlock_helper(adev, &(flags), __FILE__ ":" STRING(__LINE__)) +#define acx_sem_lock(adev) acx_down_helper(adev, __FILE__ ":" STRING(__LINE__)) +#define acx_sem_unlock(adev) acx_up_helper(adev, __FILE__ ":" STRING(__LINE__)) + +#elif defined(DO_LOCKING) + +#define acx_lock(adev, flags) spin_lock_irqsave(&adev->lock, flags) +#define acx_unlock(adev, flags) spin_unlock_irqrestore(&adev->lock, flags) +#define acx_sem_lock(adev) down(&adev->sem) +#define acx_sem_unlock(adev) up(&adev->sem) +#define acx_lock_unhold() ((void)0) +#define acx_sem_unhold() ((void)0) + +#else /* no locking! :( */ + +#define acx_lock(adev, flags) ((void)0) +#define acx_unlock(adev, flags) ((void)0) +#define acx_sem_lock(adev) ((void)0) +#define acx_sem_unlock(adev) ((void)0) +#define acx_lock_unhold() ((void)0) +#define acx_sem_unhold() ((void)0) + +#endif + + +/*********************************************************************** +*/ + +/* Can race with rx path (which is not protected by sem): +** rx -> process_[re]assocresp() -> set_status(ASSOCIATED) -> wake_queue() +** Can race with tx_complete IRQ: +** IRQ -> acxpci_l_clean_txdesc -> acx_wake_queue +** Review carefully all callsites */ +static inline void +acx_stop_queue(struct net_device *ndev, const char *msg) +{ + if (netif_queue_stopped(ndev)) + return; + + netif_stop_queue(ndev); + if (msg) + log(L_BUFT, "tx: stop queue %s\n", msg); +} + +static inline int +acx_queue_stopped(struct net_device *ndev) +{ + return netif_queue_stopped(ndev); +} + +/* +static inline void +acx_start_queue(struct net_device *ndev, const char *msg) +{ + netif_start_queue(ndev); + if (msg) + log(L_BUFT, "tx: start queue %s\n", msg); +} +*/ + +static inline void +acx_wake_queue(struct net_device *ndev, const char *msg) +{ + netif_wake_queue(ndev); + if (msg) + log(L_BUFT, "tx: wake queue %s\n", msg); +} + +static inline void +acx_carrier_off(struct net_device *ndev, const char *msg) +{ + netif_carrier_off(ndev); + if (msg) + log(L_BUFT, "tx: carrier off %s\n", msg); +} + +static inline void +acx_carrier_on(struct net_device *ndev, const char *msg) +{ + netif_carrier_on(ndev); + if (msg) + log(L_BUFT, "tx: carrier on %s\n", msg); +} + +/* This function does not need locking UNLESS you call it +** as acx_set_status(ACX_STATUS_4_ASSOCIATED), bacause this can +** wake queue. This can race with stop_queue elsewhere. */ +void acx_set_status(acx_device_t *adev, u16 status); + + +/*********************************************************************** +** Communication with firmware +*/ +#define CMD_TIMEOUT_MS(n) (n) +#define ACX_CMD_TIMEOUT_DEFAULT CMD_TIMEOUT_MS(50) + +#if ACX_DEBUG + +/* We want to log cmd names */ +int acxpci_s_issue_cmd_timeo_debug(acx_device_t *adev, unsigned cmd, void *param, unsigned len, unsigned timeout, const char* cmdstr); +int acxusb_s_issue_cmd_timeo_debug(acx_device_t *adev, unsigned cmd, void *param, unsigned len, unsigned timeout, const char* cmdstr); +static inline int +acx_s_issue_cmd_timeo_debug(acx_device_t *adev, unsigned cmd, void *param, unsigned len, unsigned timeout, const char* cmdstr) +{ + if (IS_PCI(adev)) + return acxpci_s_issue_cmd_timeo_debug(adev, cmd, param, len, timeout, cmdstr); + return acxusb_s_issue_cmd_timeo_debug(adev, cmd, param, len, timeout, cmdstr); +} +#define acx_s_issue_cmd(adev,cmd,param,len) \ + acx_s_issue_cmd_timeo_debug(adev,cmd,param,len,ACX_CMD_TIMEOUT_DEFAULT,#cmd) +#define acx_s_issue_cmd_timeo(adev,cmd,param,len,timeo) \ + acx_s_issue_cmd_timeo_debug(adev,cmd,param,len,timeo,#cmd) +int acx_s_configure_debug(acx_device_t *adev, void *pdr, int type, const char* str); +#define acx_s_configure(adev,pdr,type) \ + acx_s_configure_debug(adev,pdr,type,#type) +int acx_s_interrogate_debug(acx_device_t *adev, void *pdr, int type, const char* str); +#define acx_s_interrogate(adev,pdr,type) \ + acx_s_interrogate_debug(adev,pdr,type,#type) + +#else + +int acxpci_s_issue_cmd_timeo(acx_device_t *adev, unsigned cmd, void *param, unsigned len, unsigned timeout); +int acxusb_s_issue_cmd_timeo(acx_device_t *adev, unsigned cmd, void *param, unsigned len, unsigned timeout); +static inline int +acx_s_issue_cmd_timeo(acx_device_t *adev, unsigned cmd, void *param, unsigned len, unsigned timeout) +{ + if (IS_PCI(adev)) + return acxpci_s_issue_cmd_timeo(adev, cmd, param, len, timeout); + return acxusb_s_issue_cmd_timeo(adev, cmd, param, len, timeout); +} +static inline int +acx_s_issue_cmd(acx_device_t *adev, unsigned cmd, void *param, unsigned len) +{ + if (IS_PCI(adev)) + return acxpci_s_issue_cmd_timeo(adev, cmd, param, len, ACX_CMD_TIMEOUT_DEFAULT); + return acxusb_s_issue_cmd_timeo(adev, cmd, param, len, ACX_CMD_TIMEOUT_DEFAULT); +} +int acx_s_configure(acx_device_t *adev, void *pdr, int type); +int acx_s_interrogate(acx_device_t *adev, void *pdr, int type); + +#endif + +void acx_s_cmd_start_scan(acx_device_t *adev); + + +/*********************************************************************** +** Ioctls +*/ +int +acx111pci_ioctl_info( + struct net_device *ndev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra); +int +acx100pci_ioctl_set_phy_amp_bias( + struct net_device *ndev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra); + + +/*********************************************************************** +** /proc +*/ +#ifdef CONFIG_PROC_FS +int acx_proc_register_entries(const struct net_device *ndev); +int acx_proc_unregister_entries(const struct net_device *ndev); +#else +static inline int +acx_proc_register_entries(const struct net_device *ndev) { return OK; } +static inline int +acx_proc_unregister_entries(const struct net_device *ndev) { return OK; } +#endif + + +/*********************************************************************** +*/ +firmware_image_t *acx_s_read_fw(struct device *dev, const char *file, u32 *size); +int acxpci_s_upload_radio(acx_device_t *adev); + + +/*********************************************************************** +** Unsorted yet :) +*/ +int acxpci_s_read_phy_reg(acx_device_t *adev, u32 reg, u8 *charbuf); +int acxusb_s_read_phy_reg(acx_device_t *adev, u32 reg, u8 *charbuf); +static inline int +acx_s_read_phy_reg(acx_device_t *adev, u32 reg, u8 *charbuf) +{ + if (IS_PCI(adev)) + return acxpci_s_read_phy_reg(adev, reg, charbuf); + return acxusb_s_read_phy_reg(adev, reg, charbuf); +} + +int acxpci_s_write_phy_reg(acx_device_t *adev, u32 reg, u8 value); +int acxusb_s_write_phy_reg(acx_device_t *adev, u32 reg, u8 value); +static inline int +acx_s_write_phy_reg(acx_device_t *adev, u32 reg, u8 value) +{ + if (IS_PCI(adev)) + return acxpci_s_write_phy_reg(adev, reg, value); + return acxusb_s_write_phy_reg(adev, reg, value); +} + +tx_t* acxpci_l_alloc_tx(acx_device_t *adev); +tx_t* acxusb_l_alloc_tx(acx_device_t *adev); +static inline tx_t* +acx_l_alloc_tx(acx_device_t *adev) +{ + if (IS_PCI(adev)) + return acxpci_l_alloc_tx(adev); + return acxusb_l_alloc_tx(adev); +} + +void acxusb_l_dealloc_tx(tx_t *tx_opaque); +static inline void +acx_l_dealloc_tx(acx_device_t *adev, tx_t *tx_opaque) +{ + if (IS_USB(adev)) + acxusb_l_dealloc_tx(tx_opaque); +} + +void* acxpci_l_get_txbuf(acx_device_t *adev, tx_t *tx_opaque); +void* acxusb_l_get_txbuf(acx_device_t *adev, tx_t *tx_opaque); +static inline void* +acx_l_get_txbuf(acx_device_t *adev, tx_t *tx_opaque) +{ + if (IS_PCI(adev)) + return acxpci_l_get_txbuf(adev, tx_opaque); + return acxusb_l_get_txbuf(adev, tx_opaque); +} + +void acxpci_l_tx_data(acx_device_t *adev, tx_t *tx_opaque, int len); +void acxusb_l_tx_data(acx_device_t *adev, tx_t *tx_opaque, int len); +static inline void +acx_l_tx_data(acx_device_t *adev, tx_t *tx_opaque, int len) +{ + if (IS_PCI(adev)) + acxpci_l_tx_data(adev, tx_opaque, len); + else + acxusb_l_tx_data(adev, tx_opaque, len); +} + +static inline wlan_hdr_t* +acx_get_wlan_hdr(acx_device_t *adev, const rxbuffer_t *rxbuf) +{ + return (wlan_hdr_t*)((u8*)&rxbuf->hdr_a3 + adev->phy_header_len); +} + +void acxpci_l_power_led(acx_device_t *adev, int enable); +int acxpci_read_eeprom_byte(acx_device_t *adev, u32 addr, u8 *charbuf); +unsigned int acxpci_l_clean_txdesc(acx_device_t *adev); +void acxpci_l_clean_txdesc_emergency(acx_device_t *adev); +int acxpci_s_create_hostdesc_queues(acx_device_t *adev); +void acxpci_create_desc_queues(acx_device_t *adev, u32 tx_queue_start, u32 rx_queue_start); +void acxpci_free_desc_queues(acx_device_t *adev); +char* acxpci_s_proc_diag_output(char *p, acx_device_t *adev); +int acxpci_proc_eeprom_output(char *p, acx_device_t *adev); +void acxpci_set_interrupt_mask(acx_device_t *adev); +int acx100pci_s_set_tx_level(acx_device_t *adev, u8 level_dbm); + +void acx_s_msleep(int ms); +int acx_s_init_mac(acx_device_t *adev); +void acx_set_reg_domain(acx_device_t *adev, unsigned char reg_dom_id); +void acx_set_timer(acx_device_t *adev, int timeout_us); +void acx_update_capabilities(acx_device_t *adev); +void acx_s_start(acx_device_t *adev); + +void acx_s_update_card_settings(acx_device_t *adev); +void acx_s_parse_configoption(acx_device_t *adev, const acx111_ie_configoption_t *pcfg); +void acx_l_update_ratevector(acx_device_t *adev); + +void acx_init_task_scheduler(acx_device_t *adev); +void acx_schedule_task(acx_device_t *adev, unsigned int set_flag); + +int acx_e_ioctl_old(struct net_device *ndev, struct ifreq *ifr, int cmd); + +client_t *acx_l_sta_list_get(acx_device_t *adev, const u8 *address); +void acx_l_sta_list_del(acx_device_t *adev, client_t *clt); + +int acx_l_transmit_disassoc(acx_device_t *adev, client_t *clt); +void acx_i_timer(unsigned long a); +int acx_s_complete_scan(acx_device_t *adev); + +struct sk_buff *acx_rxbuf_to_ether(acx_device_t *adev, rxbuffer_t *rxbuf); +int acx_ether_to_txbuf(acx_device_t *adev, void *txbuf, const struct sk_buff *skb); + +u8 acx_signal_determine_quality(u8 signal, u8 noise); + +void acx_l_process_rxbuf(acx_device_t *adev, rxbuffer_t *rxbuf); +void acx_l_handle_txrate_auto(acx_device_t *adev, struct client *txc, + u16 intended_rate, u8 rate100, u16 rate111, u8 error, + int pkts_to_ignore); + +void acx_dump_bytes(const void *, int); +void acx_log_bad_eid(wlan_hdr_t* hdr, int len, wlan_ie_t* ie_ptr); + +u8 acx_rate111to100(u16); + +void acx_s_set_defaults(acx_device_t *adev); + +#if !ACX_DEBUG +static inline const char* acx_get_packet_type_string(u16 fc) { return ""; } +#else +const char* acx_get_packet_type_string(u16 fc); +#endif +const char* acx_cmd_status_str(unsigned int state); + +int acx_i_start_xmit(struct sk_buff *skb, struct net_device *ndev); + +void great_inquisitor(acx_device_t *adev); + +void acx_s_get_firmware_version(acx_device_t *adev); +void acx_display_hardware_details(acx_device_t *adev); + +int acx_e_change_mtu(struct net_device *ndev, int mtu); +struct net_device_stats* acx_e_get_stats(struct net_device *ndev); +struct iw_statistics* acx_e_get_wireless_stats(struct net_device *ndev); + +int __init acxpci_e_init_module(void); +int __init acxusb_e_init_module(void); +void __exit acxpci_e_cleanup_module(void); +void __exit acxusb_e_cleanup_module(void); --- linux-2.6.27.orig/ubuntu/misc/wireless/acx/acx_struct.h +++ linux-2.6.27/ubuntu/misc/wireless/acx/acx_struct.h @@ -0,0 +1,2049 @@ +/*********************************************************************** +** Copyright (C) 2003 ACX100 Open Source Project +** +** The contents of this file are subject to the Mozilla Public +** License Version 1.1 (the "License"); you may not use this file +** except in compliance with the License. You may obtain a copy of +** the License at http://www.mozilla.org/MPL/ +** +** Software distributed under the License is distributed on an "AS +** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +** implied. See the License for the specific language governing +** rights and limitations under the License. +** +** Alternatively, the contents of this file may be used under the +** terms of the GNU Public License version 2 (the "GPL"), in which +** case the provisions of the GPL are applicable instead of the +** above. If you wish to allow the use of your version of this file +** only under the terms of the GPL and not to allow others to use +** your version of this file under the MPL, indicate your decision +** by deleting the provisions above and replace them with the notice +** and other provisions required by the GPL. If you do not delete +** the provisions above, a recipient may use your version of this +** file under either the MPL or the GPL. +** --------------------------------------------------------------------- +** Inquiries regarding the ACX100 Open Source Project can be +** made directly to: +** +** acx100-users@lists.sf.net +** http://acx100.sf.net +** --------------------------------------------------------------------- +*/ + +/*********************************************************************** +** Forward declarations of types +*/ +typedef struct tx tx_t; +typedef struct acx_device acx_device_t; +typedef struct client client_t; +typedef struct rxdesc rxdesc_t; +typedef struct txdesc txdesc_t; +typedef struct rxhostdesc rxhostdesc_t; +typedef struct txhostdesc txhostdesc_t; + + +/*********************************************************************** +** Debug / log functionality +*/ +enum { + L_LOCK = (ACX_DEBUG>1)*0x0001, /* locking debug log */ + L_INIT = (ACX_DEBUG>0)*0x0002, /* special card initialization logging */ + L_IRQ = (ACX_DEBUG>0)*0x0004, /* interrupt stuff */ + L_ASSOC = (ACX_DEBUG>0)*0x0008, /* assocation (network join) and station log */ + L_FUNC = (ACX_DEBUG>1)*0x0020, /* logging of function enter / leave */ + L_XFER = (ACX_DEBUG>1)*0x0080, /* logging of transfers and mgmt */ + L_DATA = (ACX_DEBUG>1)*0x0100, /* logging of transfer data */ + L_DEBUG = (ACX_DEBUG>1)*0x0200, /* log of debug info */ + L_IOCTL = (ACX_DEBUG>0)*0x0400, /* log ioctl calls */ + L_CTL = (ACX_DEBUG>1)*0x0800, /* log of low-level ctl commands */ + L_BUFR = (ACX_DEBUG>1)*0x1000, /* debug rx buffer mgmt (ring buffer etc.) */ + L_XFER_BEACON = (ACX_DEBUG>1)*0x2000, /* also log beacon packets */ + L_BUFT = (ACX_DEBUG>1)*0x4000, /* debug tx buffer mgmt (ring buffer etc.) */ + L_USBRXTX = (ACX_DEBUG>0)*0x8000, /* debug USB rx/tx operations */ + L_BUF = L_BUFR + L_BUFT, + L_ANY = 0xffff +}; + +#if ACX_DEBUG +extern unsigned int acx_debug; +#else +enum { acx_debug = 0 }; +#endif + +extern char firmware_ver[]; + + +/*********************************************************************** +** Random helpers +*/ +#define ACX_PACKED __attribute__ ((packed)) + +#define VEC_SIZE(a) (sizeof(a)/sizeof(a[0])) + +/* Use worker_queues for 2.5/2.6 kernels and queue tasks for 2.4 kernels + (used for the 'bottom half' of the interrupt routine) */ + +#include +#define USE_WORKER_TASKS +#define WORK_STRUCT struct work_struct +#define SCHEDULE_WORK schedule_work +#define FLUSH_SCHEDULED_WORK flush_scheduled_work + + +/*********************************************************************** +** Constants +*/ +#define OK 0 +#define NOT_OK 1 + +/* The supported chip models */ +#define CHIPTYPE_ACX100 1 +#define CHIPTYPE_ACX111 2 + +#define IS_ACX100(adev) ((adev)->chip_type == CHIPTYPE_ACX100) +#define IS_ACX111(adev) ((adev)->chip_type == CHIPTYPE_ACX111) + +/* Supported interfaces */ +#define DEVTYPE_PCI 0 +#define DEVTYPE_USB 1 + +#if defined(CONFIG_NET_ACX_PCI) + #if !defined(CONFIG_NET_ACX_USB) + #define IS_PCI(adev) 1 + #else + #define IS_PCI(adev) ((adev)->dev_type == DEVTYPE_PCI) + #endif +#else + #define IS_PCI(adev) 0 +#endif + +#if defined(CONFIG_NET_ACX_USB) + #if !defined(CONFIG_NET_ACX_PCI) + #define IS_USB(adev) 1 + #else + #define IS_USB(adev) ((adev)->dev_type == DEVTYPE_USB) + #endif +#else + #define IS_USB(adev) 0 +#endif + +/* Driver defaults */ +#define DEFAULT_DTIM_INTERVAL 10 +/* used to be 2048, but FreeBSD driver changed it to 4096 to work properly +** in noisy wlans */ +#define DEFAULT_MSDU_LIFETIME 4096 +#define DEFAULT_RTS_THRESHOLD 2312 /* max. size: disable RTS mechanism */ +#define DEFAULT_BEACON_INTERVAL 100 + +#define ACX100_BAP_DATALEN_MAX 4096 +#define ACX100_RID_GUESSING_MAXLEN 2048 /* I'm not really sure */ +#define ACX100_RIDDATA_MAXLEN ACX100_RID_GUESSING_MAXLEN + +/* Support Constants */ +/* Radio type names, found in Win98 driver's TIACXLN.INF */ +#define RADIO_MAXIM_0D 0x0d +#define RADIO_RFMD_11 0x11 +#define RADIO_RALINK_15 0x15 +/* used in ACX111 cards (WG311v2, WL-121, ...): */ +#define RADIO_RADIA_16 0x16 +/* most likely *sometimes* used in ACX111 cards: */ +#define RADIO_UNKNOWN_17 0x17 +/* FwRad19.bin was found in a Safecom driver; must be an ACX111 radio: */ +#define RADIO_UNKNOWN_19 0x19 +#define RADIO_UNKNOWN_1B 0x1b /* radio in SafeCom SWLUT-54125 USB adapter; entirely unknown!! */ + +/* Controller Commands */ +/* can be found in table cmdTable in firmware "Rev. 1.5.0" (FW150) */ +#define ACX1xx_CMD_RESET 0x00 +#define ACX1xx_CMD_INTERROGATE 0x01 +#define ACX1xx_CMD_CONFIGURE 0x02 +#define ACX1xx_CMD_ENABLE_RX 0x03 +#define ACX1xx_CMD_ENABLE_TX 0x04 +#define ACX1xx_CMD_DISABLE_RX 0x05 +#define ACX1xx_CMD_DISABLE_TX 0x06 +#define ACX1xx_CMD_FLUSH_QUEUE 0x07 +#define ACX1xx_CMD_SCAN 0x08 +#define ACX1xx_CMD_STOP_SCAN 0x09 +#define ACX1xx_CMD_CONFIG_TIM 0x0a +#define ACX1xx_CMD_JOIN 0x0b +#define ACX1xx_CMD_WEP_MGMT 0x0c +#ifdef OLD_FIRMWARE_VERSIONS +#define ACX100_CMD_HALT 0x0e /* mapped to unknownCMD in FW150 */ +#else +#define ACX1xx_CMD_MEM_READ 0x0d +#define ACX1xx_CMD_MEM_WRITE 0x0e +#endif +#define ACX1xx_CMD_SLEEP 0x0f +#define ACX1xx_CMD_WAKE 0x10 +#define ACX1xx_CMD_UNKNOWN_11 0x11 /* mapped to unknownCMD in FW150 */ +#define ACX100_CMD_INIT_MEMORY 0x12 +#define ACX1FF_CMD_DISABLE_RADIO 0x12 /* new firmware? TNETW1450? */ +#define ACX1xx_CMD_CONFIG_BEACON 0x13 +#define ACX1xx_CMD_CONFIG_PROBE_RESPONSE 0x14 +#define ACX1xx_CMD_CONFIG_NULL_DATA 0x15 +#define ACX1xx_CMD_CONFIG_PROBE_REQUEST 0x16 +#define ACX1xx_CMD_FCC_TEST 0x17 +#define ACX1xx_CMD_RADIOINIT 0x18 +#define ACX111_CMD_RADIOCALIB 0x19 +#define ACX1FF_CMD_NOISE_HISTOGRAM 0x1c /* new firmware? TNETW1450? */ +#define ACX1FF_CMD_RX_RESET 0x1d /* new firmware? TNETW1450? */ +#define ACX1FF_CMD_LNA_CONTROL 0x20 /* new firmware? TNETW1450? */ +#define ACX1FF_CMD_CONTROL_DBG_TRACE 0x21 /* new firmware? TNETW1450? */ + +/* 'After Interrupt' Commands */ +#define ACX_AFTER_IRQ_CMD_STOP_SCAN 0x01 +#define ACX_AFTER_IRQ_CMD_ASSOCIATE 0x02 +#define ACX_AFTER_IRQ_CMD_RADIO_RECALIB 0x04 +#define ACX_AFTER_IRQ_UPDATE_CARD_CFG 0x08 +#define ACX_AFTER_IRQ_TX_CLEANUP 0x10 +#define ACX_AFTER_IRQ_COMPLETE_SCAN 0x20 +#define ACX_AFTER_IRQ_RESTART_SCAN 0x40 + +/*********************************************************************** +** Tx/Rx buffer sizes and watermarks +** +** This will alloc and use DMAable buffers of +** WLAN_A4FR_MAXLEN_WEP_FCS * (RX_CNT + TX_CNT) bytes +** RX/TX_CNT=32 -> ~150k DMA buffers +** RX/TX_CNT=16 -> ~75k DMA buffers +** +** 2005-10-10: reduced memory usage by lowering both to 16 +*/ +#define RX_CNT 16 +#define TX_CNT 16 + +/* we clean up txdescs when we have N free txdesc: */ +#define TX_CLEAN_BACKLOG (TX_CNT/4) +#define TX_START_CLEAN (TX_CNT - TX_CLEAN_BACKLOG) +#define TX_EMERG_CLEAN 2 +/* we stop queue if we have < N free txbufs: */ +#define TX_STOP_QUEUE 3 +/* we start queue if we have >= N free txbufs: */ +#define TX_START_QUEUE 5 + +/*********************************************************************** +** Interrogate/Configure cmd constants +** +** NB: length includes JUST the data part of the IE +** (does not include size of the (type,len) pair) +** +** TODO: seems that acx100, acx100usb, acx111 have some differences, +** fix code with regard to this! +*/ + +#define DEF_IE(name, val, len) enum { ACX##name=val, ACX##name##_LEN=len } + +/* Information Elements: Network Parameters, Static Configuration Entities */ +/* these are handled by real_cfgtable in firmware "Rev 1.5.0" (FW150) */ +DEF_IE(1xx_IE_UNKNOWN_00 ,0x0000, -1); /* mapped to cfgInvalid in FW150 */ +DEF_IE(100_IE_ACX_TIMER ,0x0001, 0x10); +DEF_IE(1xx_IE_POWER_MGMT ,0x0002, 0x06); /* TNETW1450: length 0x18!! */ +DEF_IE(1xx_IE_QUEUE_CONFIG ,0x0003, 0x1c); +DEF_IE(100_IE_BLOCK_SIZE ,0x0004, 0x02); +DEF_IE(1FF_IE_SLOT_TIME ,0x0004, 0x08); /* later firmware versions only? */ +DEF_IE(1xx_IE_MEMORY_CONFIG_OPTIONS ,0x0005, 0x14); +DEF_IE(1FF_IE_QUEUE_HEAD ,0x0005, 0x14 /* FIXME: length? */); +DEF_IE(1xx_IE_RATE_FALLBACK ,0x0006, 0x01); /* TNETW1450: length 2 */ +DEF_IE(100_IE_WEP_OPTIONS ,0x0007, 0x03); +DEF_IE(111_IE_RADIO_BAND ,0x0007, -1); +DEF_IE(1FF_IE_TIMING_CFG ,0x0007, -1); /* later firmware versions; TNETW1450 only? */ +DEF_IE(100_IE_SSID ,0x0008, 0x20); /* huh? */ +DEF_IE(1xx_IE_MEMORY_MAP ,0x0008, 0x28); /* huh? TNETW1450 has length 0x40!! */ +DEF_IE(1xx_IE_SCAN_STATUS ,0x0009, 0x04); /* mapped to cfgInvalid in FW150 */ +DEF_IE(1xx_IE_ASSOC_ID ,0x000a, 0x02); +DEF_IE(1xx_IE_UNKNOWN_0B ,0x000b, -1); /* mapped to cfgInvalid in FW150 */ +DEF_IE(1FF_IE_TX_POWER_LEVEL_TABLE ,0x000b, 0x18); /* later firmware versions; TNETW1450 only? */ +DEF_IE(100_IE_UNKNOWN_0C ,0x000c, -1); /* very small implementation in FW150! */ +/* ACX100 has an equivalent struct in the cmd mailbox directly after reset. + * 0x14c seems extremely large, will trash stack on failure (memset!) + * in case of small input struct --> OOPS! */ +DEF_IE(111_IE_CONFIG_OPTIONS ,0x000c, 0x14c); +DEF_IE(1xx_IE_FWREV ,0x000d, 0x18); +DEF_IE(1xx_IE_FCS_ERROR_COUNT ,0x000e, 0x04); +DEF_IE(1xx_IE_MEDIUM_USAGE ,0x000f, 0x08); +DEF_IE(1xx_IE_RXCONFIG ,0x0010, 0x04); +DEF_IE(100_IE_UNKNOWN_11 ,0x0011, -1); /* NONBINARY: large implementation in FW150! link quality readings or so? */ +DEF_IE(111_IE_QUEUE_THRESH ,0x0011, -1); +DEF_IE(100_IE_UNKNOWN_12 ,0x0012, -1); /* NONBINARY: VERY large implementation in FW150!! */ +DEF_IE(111_IE_BSS_POWER_SAVE ,0x0012, /* -1 */ 2); +DEF_IE(1xx_IE_FIRMWARE_STATISTICS ,0x0013, 0x9c); /* TNETW1450: length 0x134!! */ +DEF_IE(1FF_IE_RX_INTR_CONFIG ,0x0014, 0x14); /* later firmware versions, TNETW1450 only? */ +DEF_IE(1xx_IE_FEATURE_CONFIG ,0x0015, 0x08); +DEF_IE(111_IE_KEY_CHOOSE ,0x0016, 0x04); /* for rekeying. really len=4?? */ +DEF_IE(1FF_IE_MISC_CONFIG_TABLE ,0x0017, 0x04); /* later firmware versions, TNETW1450 only? */ +DEF_IE(1FF_IE_WONE_CONFIG ,0x0018, -1); /* later firmware versions, TNETW1450 only? */ +DEF_IE(1FF_IE_TID_CONFIG ,0x001a, 0x2c); /* later firmware versions, TNETW1450 only? */ +DEF_IE(1FF_IE_CALIB_ASSESSMENT ,0x001e, 0x04); /* later firmware versions, TNETW1450 only? */ +DEF_IE(1FF_IE_BEACON_FILTER_OPTIONS ,0x001f, 0x02); /* later firmware versions, TNETW1450 only? */ +DEF_IE(1FF_IE_LOW_RSSI_THRESH_OPT ,0x0020, 0x04); /* later firmware versions, TNETW1450 only? */ +DEF_IE(1FF_IE_NOISE_HISTOGRAM_RESULTS ,0x0021, 0x30); /* later firmware versions, TNETW1450 only? */ +DEF_IE(1FF_IE_PACKET_DETECT_THRESH ,0x0023, 0x04); /* later firmware versions, TNETW1450 only? */ +DEF_IE(1FF_IE_TX_CONFIG_OPTIONS ,0x0024, 0x04); /* later firmware versions, TNETW1450 only? */ +DEF_IE(1FF_IE_CCA_THRESHOLD ,0x0025, 0x02); /* later firmware versions, TNETW1450 only? */ +DEF_IE(1FF_IE_EVENT_MASK ,0x0026, 0x08); /* later firmware versions, TNETW1450 only? */ +DEF_IE(1FF_IE_DTIM_PERIOD ,0x0027, 0x02); /* later firmware versions, TNETW1450 only? */ +DEF_IE(1FF_IE_ACI_CONFIG_SET ,0x0029, 0x06); /* later firmware versions; maybe TNETW1450 only? */ +DEF_IE(1FF_IE_EEPROM_VER ,0x0030, 0x04); /* later firmware versions; maybe TNETW1450 only? */ +DEF_IE(1xx_IE_DOT11_STATION_ID ,0x1001, 0x06); +DEF_IE(100_IE_DOT11_UNKNOWN_1002 ,0x1002, -1); /* mapped to cfgInvalid in FW150 */ +DEF_IE(111_IE_DOT11_FRAG_THRESH ,0x1002, -1); /* mapped to cfgInvalid in FW150; TNETW1450 has length 2!! */ +DEF_IE(100_IE_DOT11_BEACON_PERIOD ,0x1003, 0x02); /* mapped to cfgInvalid in FW150 */ +DEF_IE(1xx_IE_DOT11_DTIM_PERIOD ,0x1004, -1); /* mapped to cfgInvalid in FW150 */ +DEF_IE(1FF_IE_DOT11_MAX_RX_LIFETIME ,0x1004, -1); /* later firmware versions; maybe TNETW1450 only? */ +DEF_IE(1xx_IE_DOT11_SHORT_RETRY_LIMIT ,0x1005, 0x01); /* TNETW1450: length 2 */ +DEF_IE(1xx_IE_DOT11_LONG_RETRY_LIMIT ,0x1006, 0x01); /* TNETW1450: length 2 */ +DEF_IE(100_IE_DOT11_WEP_DEFAULT_KEY_WRITE ,0x1007, 0x20); /* configure default keys; TNETW1450 has length 0x24!! */ +DEF_IE(1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME ,0x1008, 0x04); +DEF_IE(1xx_IE_DOT11_GROUP_ADDR ,0x1009, -1); +DEF_IE(1xx_IE_DOT11_CURRENT_REG_DOMAIN ,0x100a, 0x02); +/* It's harmless to have larger struct. Use USB case always. */ +DEF_IE(1xx_IE_DOT11_CURRENT_ANTENNA ,0x100b, 0x02); /* in fact len=1 for PCI */ +DEF_IE(1xx_IE_DOT11_UNKNOWN_100C ,0x100c, -1); /* mapped to cfgInvalid in FW150 */ +DEF_IE(1xx_IE_DOT11_TX_POWER_LEVEL ,0x100d, 0x01); /* TNETW1450 has length 2!! */ +DEF_IE(1xx_IE_DOT11_CURRENT_CCA_MODE ,0x100e, 0x02); /* in fact len=1 for PCI */ +/* USB doesn't return anything - len==0?! */ +DEF_IE(100_IE_DOT11_ED_THRESHOLD ,0x100f, 0x04); +DEF_IE(1xx_IE_DOT11_WEP_DEFAULT_KEY_SET ,0x1010, 0x01); /* set default key ID; TNETW1450: length 2 */ +DEF_IE(100_IE_DOT11_UNKNOWN_1011 ,0x1011, -1); /* mapped to cfgInvalid in FW150 */ +DEF_IE(1FF_IE_DOT11_CURR_5GHZ_REGDOM ,0x1011, -1); /* later firmware versions; maybe TNETW1450 only? */ +DEF_IE(100_IE_DOT11_UNKNOWN_1012 ,0x1012, -1); /* mapped to cfgInvalid in FW150 */ +DEF_IE(100_IE_DOT11_UNKNOWN_1013 ,0x1013, -1); /* mapped to cfgInvalid in FW150 */ + +#if 0 +/* Experimentally obtained on acx100, fw 1.9.8.b +** -1 means that fw returned 'invalid IE' +** 0200 FC00 nnnn... are test read contents: u16 type, u16 len, data +** (AA are poison bytes marking bytes not written by fw) +** +** Looks like acx100 fw does not update len field (thus len=256-4=FC here) +** A number of IEs seem to trash type,len fields +** IEs marked 'huge' return gobs of data (no poison bytes remain) +*/ +DEF_IE(100_IE_INVAL_00, 0x0000, -1); +DEF_IE(100_IE_INVAL_01, 0x0001, -1); /* IE_ACX_TIMER, len=16 on older fw */ +DEF_IE(100_IE_POWER_MGMT, 0x0002, 4); /* 0200FC00 00040000 AAAAAAAA */ +DEF_IE(100_IE_QUEUE_CONFIG, 0x0003, 28); /* 0300FC00 48060000 9CAD0000 0101AAAA DCB00000 E4B00000 9CAA0000 00AAAAAA */ +DEF_IE(100_IE_BLOCK_SIZE, 0x0004, 2); /* 0400FC00 0001AAAA AAAAAAAA AAAAAAAA */ +/* write only: */ +DEF_IE(100_IE_MEMORY_CONFIG_OPTIONS, 0x0005, 20); +DEF_IE(100_IE_RATE_FALLBACK, 0x0006, 1); /* 0600FC00 00AAAAAA AAAAAAAA AAAAAAAA */ +/* write only: */ +DEF_IE(100_IE_WEP_OPTIONS, 0x0007, 3); +DEF_IE(100_IE_MEMORY_MAP, 0x0008, 40); /* huge: 0800FC00 30000000 6CA20000 70A20000... */ +/* gives INVAL on read: */ +DEF_IE(100_IE_SCAN_STATUS, 0x0009, -1); +DEF_IE(100_IE_ASSOC_ID, 0x000a, 2); /* huge: 0A00FC00 00000000 01040800 00000000... */ +DEF_IE(100_IE_INVAL_0B, 0x000b, -1); +/* 'command rejected': */ +DEF_IE(100_IE_CONFIG_OPTIONS, 0x000c, -3); +DEF_IE(100_IE_FWREV, 0x000d, 24); /* 0D00FC00 52657620 312E392E 382E6200 AAAAAAAA AAAAAAAA 05050201 AAAAAAAA */ +DEF_IE(100_IE_FCS_ERROR_COUNT, 0x000e, 4); +DEF_IE(100_IE_MEDIUM_USAGE, 0x000f, 8); /* E41F0000 2D780300 FCC91300 AAAAAAAA */ +DEF_IE(100_IE_RXCONFIG, 0x0010, 4); /* 1000FC00 00280000 AAAAAAAA AAAAAAAA */ +DEF_IE(100_IE_QUEUE_THRESH, 0x0011, 12); /* 1100FC00 AAAAAAAA 00000000 00000000 */ +DEF_IE(100_IE_BSS_POWER_SAVE, 0x0012, 1); /* 1200FC00 00AAAAAA AAAAAAAA AAAAAAAA */ +/* read only, variable len */ +DEF_IE(100_IE_FIRMWARE_STATISTICS, 0x0013, 256); /* 0000AC00 00000000 ... */ +DEF_IE(100_IE_INT_CONFIG, 0x0014, 20); /* 00000000 00000000 00000000 00000000 5D74D105 00000000 AAAAAAAA AAAAAAAA */ +DEF_IE(100_IE_FEATURE_CONFIG, 0x0015, 8); /* 1500FC00 16000000 AAAAAAAA AAAAAAAA */ +/* returns 'invalid MAC': */ +DEF_IE(100_IE_KEY_CHOOSE, 0x0016, -4); +DEF_IE(100_IE_INVAL_17, 0x0017, -1); +DEF_IE(100_IE_UNKNOWN_18, 0x0018, 0); /* null len?! 1800FC00 AAAAAAAA AAAAAAAA AAAAAAAA */ +DEF_IE(100_IE_UNKNOWN_19, 0x0019, 256); /* huge: 1900FC00 9C1F00EA FEFFFFEA FEFFFFEA... */ +DEF_IE(100_IE_INVAL_1A, 0x001A, -1); + +DEF_IE(100_IE_DOT11_INVAL_1000, 0x1000, -1); +DEF_IE(100_IE_DOT11_STATION_ID, 0x1001, 6); /* huge: 0110FC00 58B10E2F 03000000 00000000... */ +DEF_IE(100_IE_DOT11_INVAL_1002, 0x1002, -1); +DEF_IE(100_IE_DOT11_INVAL_1003, 0x1003, -1); +DEF_IE(100_IE_DOT11_INVAL_1004, 0x1004, -1); +DEF_IE(100_IE_DOT11_SHORT_RETRY_LIMIT, 0x1005, 1); +DEF_IE(100_IE_DOT11_LONG_RETRY_LIMIT, 0x1006, 1); +/* write only: */ +DEF_IE(100_IE_DOT11_WEP_DEFAULT_KEY_WRITE, 0x1007, 32); +DEF_IE(100_IE_DOT11_MAX_XMIT_MSDU_LIFETIME, 0x1008, 4); /* huge: 0810FC00 00020000 F4010000 00000000... */ +/* undoc but returns something */ +DEF_IE(100_IE_DOT11_GROUP_ADDR, 0x1009, 12); /* huge: 0910FC00 00000000 00000000 00000000... */ +DEF_IE(100_IE_DOT11_CURRENT_REG_DOMAIN, 0x100a, 1); /* 0A10FC00 30AAAAAA AAAAAAAA AAAAAAAA */ +DEF_IE(100_IE_DOT11_CURRENT_ANTENNA, 0x100b, 1); /* 0B10FC00 8FAAAAAA AAAAAAAA AAAAAAAA */ +DEF_IE(100_IE_DOT11_INVAL_100C, 0x100c, -1); +DEF_IE(100_IE_DOT11_TX_POWER_LEVEL, 0x100d, 2); /* 00000000 0100AAAA AAAAAAAA AAAAAAAA */ +DEF_IE(100_IE_DOT11_CURRENT_CCA_MODE, 0x100e, 1); /* 0E10FC00 0DAAAAAA AAAAAAAA AAAAAAAA */ +DEF_IE(100_IE_DOT11_ED_THRESHOLD, 0x100f, 4); /* 0F10FC00 70000000 AAAAAAAA AAAAAAAA */ +/* set default key ID */ +DEF_IE(100_IE_DOT11_WEP_DEFAULT_KEY_SET, 0x1010, 1); /* 1010FC00 00AAAAAA AAAAAAAA AAAAAAAA */ +DEF_IE(100_IE_DOT11_INVAL_1011, 0x1011, -1); +DEF_IE(100_IE_DOT11_INVAL_1012, 0x1012, -1); +DEF_IE(100_IE_DOT11_INVAL_1013, 0x1013, -1); +DEF_IE(100_IE_DOT11_UNKNOWN_1014, 0x1014, 256); /* huge */ +DEF_IE(100_IE_DOT11_UNKNOWN_1015, 0x1015, 256); /* huge */ +DEF_IE(100_IE_DOT11_UNKNOWN_1016, 0x1016, 256); /* huge */ +DEF_IE(100_IE_DOT11_UNKNOWN_1017, 0x1017, 256); /* huge */ +DEF_IE(100_IE_DOT11_UNKNOWN_1018, 0x1018, 256); /* huge */ +DEF_IE(100_IE_DOT11_UNKNOWN_1019, 0x1019, 256); /* huge */ +#endif + +#if 0 +/* Experimentally obtained on PCI acx111 Xterasys XN-2522g, fw 1.2.1.34 +** -1 means that fw returned 'invalid IE' +** 0400 0800 nnnn... are test read contents: u16 type, u16 len, data +** (AA are poison bytes marking bytes not written by fw) +** +** Looks like acx111 fw reports real len! +*/ +DEF_IE(111_IE_INVAL_00, 0x0000, -1); +DEF_IE(111_IE_INVAL_01, 0x0001, -1); +DEF_IE(111_IE_POWER_MGMT, 0x0002, 12); +/* write only, variable len: 12 + rxqueue_cnt*8 + txqueue_cnt*4: */ +DEF_IE(111_IE_MEMORY_CONFIG, 0x0003, 24); +DEF_IE(111_IE_BLOCK_SIZE, 0x0004, 8); /* 04000800 AA00AAAA AAAAAAAA */ +/* variable len: 8 + rxqueue_cnt*8 + txqueue_cnt*8: */ +DEF_IE(111_IE_QUEUE_HEAD, 0x0005, 24); +DEF_IE(111_IE_RATE_FALLBACK, 0x0006, 1); +/* acx100 name:WEP_OPTIONS */ +/* said to have len:1 (not true, actually returns 12 bytes): */ +DEF_IE(111_IE_RADIO_BAND, 0x0007, 12); /* 07000C00 AAAA1F00 FF03AAAA AAAAAAAA */ +DEF_IE(111_IE_MEMORY_MAP, 0x0008, 48); +/* said to have len:4, but gives INVAL on read: */ +DEF_IE(111_IE_SCAN_STATUS, 0x0009, -1); +DEF_IE(111_IE_ASSOC_ID, 0x000a, 2); +/* write only, len is not known: */ +DEF_IE(111_IE_UNKNOWN_0B, 0x000b, 0); +/* read only, variable len. I see 67 byte reads: */ +DEF_IE(111_IE_CONFIG_OPTIONS, 0x000c, 67); /* 0C004300 01160500 ... */ +DEF_IE(111_IE_FWREV, 0x000d, 24); +DEF_IE(111_IE_FCS_ERROR_COUNT, 0x000e, 4); +DEF_IE(111_IE_MEDIUM_USAGE, 0x000f, 8); +DEF_IE(111_IE_RXCONFIG, 0x0010, 4); +DEF_IE(111_IE_QUEUE_THRESH, 0x0011, 12); +DEF_IE(111_IE_BSS_POWER_SAVE, 0x0012, 1); +/* read only, variable len. I see 240 byte reads: */ +DEF_IE(111_IE_FIRMWARE_STATISTICS, 0x0013, 240); /* 1300F000 00000000 ... */ +/* said to have len=17. looks like fw pads it to 20: */ +DEF_IE(111_IE_INT_CONFIG, 0x0014, 20); /* 14001400 00000000 00000000 00000000 00000000 00000000 */ +DEF_IE(111_IE_FEATURE_CONFIG, 0x0015, 8); +/* said to be name:KEY_INDICATOR, len:4, but gives INVAL on read: */ +DEF_IE(111_IE_KEY_CHOOSE, 0x0016, -1); +/* said to have len:4, but in fact returns 8: */ +DEF_IE(111_IE_MAX_USB_XFR, 0x0017, 8); /* 17000800 00014000 00000000 */ +DEF_IE(111_IE_INVAL_18, 0x0018, -1); +DEF_IE(111_IE_INVAL_19, 0x0019, -1); +/* undoc but returns something: */ +/* huh, fw indicates len=20 but uses 4 more bytes in buffer??? */ +DEF_IE(111_IE_UNKNOWN_1A, 0x001A, 20); /* 1A001400 AA00AAAA 0000020F FF030000 00020000 00000007 04000000 */ + +DEF_IE(111_IE_DOT11_INVAL_1000, 0x1000, -1); +DEF_IE(111_IE_DOT11_STATION_ID, 0x1001, 6); +DEF_IE(111_IE_DOT11_FRAG_THRESH, 0x1002, 2); +/* acx100 only? gives INVAL on read: */ +DEF_IE(111_IE_DOT11_BEACON_PERIOD, 0x1003, -1); +/* said to be MAX_RECV_MSDU_LIFETIME: */ +DEF_IE(111_IE_DOT11_DTIM_PERIOD, 0x1004, 4); +DEF_IE(111_IE_DOT11_SHORT_RETRY_LIMIT, 0x1005, 1); +DEF_IE(111_IE_DOT11_LONG_RETRY_LIMIT, 0x1006, 1); +/* acx100 only? gives INVAL on read: */ +DEF_IE(111_IE_DOT11_WEP_DEFAULT_KEY_WRITE, 0x1007, -1); +DEF_IE(111_IE_DOT11_MAX_XMIT_MSDU_LIFETIME, 0x1008, 4); +/* undoc but returns something. maybe it's 2 multicast MACs to listen to? */ +DEF_IE(111_IE_DOT11_GROUP_ADDR, 0x1009, 12); /* 09100C00 00000000 00000000 00000000 */ +DEF_IE(111_IE_DOT11_CURRENT_REG_DOMAIN, 0x100a, 1); +DEF_IE(111_IE_DOT11_CURRENT_ANTENNA, 0x100b, 2); +DEF_IE(111_IE_DOT11_INVAL_100C, 0x100c, -1); +DEF_IE(111_IE_DOT11_TX_POWER_LEVEL, 0x100d, 1); +/* said to have len=1 but gives INVAL on read: */ +DEF_IE(111_IE_DOT11_CURRENT_CCA_MODE, 0x100e, -1); +/* said to have len=4 but gives INVAL on read: */ +DEF_IE(111_IE_DOT11_ED_THRESHOLD, 0x100f, -1); +/* set default key ID. write only: */ +DEF_IE(111_IE_DOT11_WEP_DEFAULT_KEY_SET, 0x1010, 1); +/* undoc but returns something: */ +DEF_IE(111_IE_DOT11_UNKNOWN_1011, 0x1011, 1); /* 11100100 20 */ +DEF_IE(111_IE_DOT11_INVAL_1012, 0x1012, -1); +DEF_IE(111_IE_DOT11_INVAL_1013, 0x1013, -1); +#endif + + +/*********************************************************************** +**Information Frames Structures +*/ + +/* Used in beacon frames and the like */ +#define DOT11RATEBYTE_1 (1*2) +#define DOT11RATEBYTE_2 (2*2) +#define DOT11RATEBYTE_5_5 (5*2+1) +#define DOT11RATEBYTE_11 (11*2) +#define DOT11RATEBYTE_22 (22*2) +#define DOT11RATEBYTE_6_G (6*2) +#define DOT11RATEBYTE_9_G (9*2) +#define DOT11RATEBYTE_12_G (12*2) +#define DOT11RATEBYTE_18_G (18*2) +#define DOT11RATEBYTE_24_G (24*2) +#define DOT11RATEBYTE_36_G (36*2) +#define DOT11RATEBYTE_48_G (48*2) +#define DOT11RATEBYTE_54_G (54*2) +#define DOT11RATEBYTE_BASIC 0x80 /* flags rates included in basic rate set */ + + +/*********************************************************************** +** rxbuffer_t +** +** This is the format of rx data returned by acx +*/ + +/* I've hoped it's a 802.11 PHY header, but no... + * so far, I've seen on acx111: + * 0000 3a00 0000 0000 IBSS Beacons + * 0000 3c00 0000 0000 ESS Beacons + * 0000 2700 0000 0000 Probe requests + * --vda + */ +typedef struct phy_hdr { + u8 unknown[4]; + u8 acx111_unknown[4]; +} ACX_PACKED phy_hdr_t; + +/* seems to be a bit similar to hfa384x_rx_frame. + * These fields are still not quite obvious, though. + * Some seem to have different meanings... */ + +#define RXBUF_HDRSIZE 12 +#define RXBUF_BYTES_RCVD(adev, rxbuf) \ + ((le16_to_cpu((rxbuf)->mac_cnt_rcvd) & 0xfff) - (adev)->phy_header_len) +#define RXBUF_BYTES_USED(rxbuf) \ + ((le16_to_cpu((rxbuf)->mac_cnt_rcvd) & 0xfff) + RXBUF_HDRSIZE) +/* USBism */ +#define RXBUF_IS_TXSTAT(rxbuf) (le16_to_cpu((rxbuf)->mac_cnt_rcvd) & 0x8000) +/* +mac_cnt_rcvd: + 12 bits: length of frame from control field to first byte of FCS + 3 bits: reserved + 1 bit: 1 = it's a tx status info, not a rx packet (USB only) + +mac_cnt_mblks: + 6 bits: number of memory block used to store frame in adapter memory + 1 bit: Traffic Indicator bit in TIM of received Beacon was set + +mac_status: 1 byte (bitmap): + 7 Matching BSSID + 6 Matching SSID + 5 BDCST Address 1 field is a broadcast + 4 VBM received beacon frame has more than one set bit (?!) + 3 TIM Set bit representing this station is set in TIM of received beacon + 2 GROUP Address 1 is a multicast + 1 ADDR1 Address 1 matches our MAC + 0 FCSGD FSC is good + +phy_stat_baseband: 1 byte (bitmap): + 7 Preamble frame had a long preamble + 6 PLCP Error CRC16 error in PLCP header + 5 Unsup_Mod unsupported modulation + 4 Selected Antenna antenna 1 was used to receive this frame + 3 PBCC/CCK frame used: 1=PBCC, 0=CCK modulation + 2 OFDM frame used OFDM modulation + 1 TI Protection protection frame was detected + 0 Reserved + +phy_plcp_signal: 1 byte: + Receive PLCP Signal field from the Baseband Processor + +phy_level: 1 byte: + receive AGC gain level (can be used to measure receive signal strength) + +phy_snr: 1 byte: + estimated noise power of equalized receive signal + at input of FEC decoder (can be used to measure receive signal quality) + +time: 4 bytes: + timestamp sampled from either the Access Manager TSF counter + or free-running microsecond counter when the MAC receives + first byte of PLCP header. +*/ + +typedef struct rxbuffer { + u16 mac_cnt_rcvd; /* only 12 bits are len! (0xfff) */ + u8 mac_cnt_mblks; + u8 mac_status; + u8 phy_stat_baseband; /* bit 0x80: used LNA (Low-Noise Amplifier) */ + u8 phy_plcp_signal; + u8 phy_level; /* PHY stat */ + u8 phy_snr; /* PHY stat */ + u32 time; /* timestamp upon MAC rcv first byte */ +/* 4-byte (acx100) or 8-byte (acx111) phy header will be here +** if RX_CFG1_INCLUDE_PHY_HDR is in effect: +** phy_hdr_t phy */ + wlan_hdr_a3_t hdr_a3; + /* maximally sized data part of wlan packet */ + u8 data_a3[WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_HDR_A3_LEN]; + /* can add hdr/data_a4 if needed */ +} ACX_PACKED rxbuffer_t; + + +/*--- Firmware statistics ----------------------------------------------------*/ + +/* define a random 100 bytes more to catch firmware versions which + * provide a bigger struct */ +#define FW_STATS_FUTURE_EXTENSION 100 + +typedef struct fw_stats_tx { + u32 tx_desc_of; +} ACX_PACKED fw_stats_tx_t; + +typedef struct fw_stats_rx { + u32 rx_oom; + u32 rx_hdr_of; + u32 rx_hw_stuck; /* old: u32 rx_hdr_use_next */ + u32 rx_dropped_frame; + u32 rx_frame_ptr_err; + u32 rx_xfr_hint_trig; + u32 rx_aci_events; /* later versions only */ + u32 rx_aci_resets; /* later versions only */ +} ACX_PACKED fw_stats_rx_t; + +typedef struct fw_stats_dma { + u32 rx_dma_req; + u32 rx_dma_err; + u32 tx_dma_req; + u32 tx_dma_err; +} ACX_PACKED fw_stats_dma_t; + +typedef struct fw_stats_irq { + u32 cmd_cplt; + u32 fiq; + u32 rx_hdrs; + u32 rx_cmplt; + u32 rx_mem_of; + u32 rx_rdys; + u32 irqs; + u32 tx_procs; + u32 decrypt_done; + u32 dma_0_done; + u32 dma_1_done; + u32 tx_exch_complet; + u32 commands; + u32 rx_procs; + u32 hw_pm_mode_changes; + u32 host_acks; + u32 pci_pm; + u32 acm_wakeups; +} ACX_PACKED fw_stats_irq_t; + +typedef struct fw_stats_wep { + u32 wep_key_count; + u32 wep_default_key_count; + u32 dot11_def_key_mib; + u32 wep_key_not_found; + u32 wep_decrypt_fail; + u32 wep_pkt_decrypt; + u32 wep_decrypt_irqs; +} ACX_PACKED fw_stats_wep_t; + +typedef struct fw_stats_pwr { + u32 tx_start_ctr; + u32 no_ps_tx_too_short; + u32 rx_start_ctr; + u32 no_ps_rx_too_short; + u32 lppd_started; + u32 no_lppd_too_noisy; + u32 no_lppd_too_short; + u32 no_lppd_matching_frame; +} ACX_PACKED fw_stats_pwr_t; + +typedef struct fw_stats_mic { + u32 mic_rx_pkts; + u32 mic_calc_fail; +} ACX_PACKED fw_stats_mic_t; + +typedef struct fw_stats_aes { + u32 aes_enc_fail; + u32 aes_dec_fail; + u32 aes_enc_pkts; + u32 aes_dec_pkts; + u32 aes_enc_irq; + u32 aes_dec_irq; +} ACX_PACKED fw_stats_aes_t; + +typedef struct fw_stats_event { + u32 heartbeat; + u32 calibration; + u32 rx_mismatch; + u32 rx_mem_empty; + u32 rx_pool; + u32 oom_late; + u32 phy_tx_err; + u32 tx_stuck; +} ACX_PACKED fw_stats_event_t; + +/* mainly for size calculation only */ +typedef struct fw_stats { + u16 type; + u16 len; + fw_stats_tx_t tx; + fw_stats_rx_t rx; + fw_stats_dma_t dma; + fw_stats_irq_t irq; + fw_stats_wep_t wep; + fw_stats_pwr_t pwr; + fw_stats_mic_t mic; + fw_stats_aes_t aes; + fw_stats_event_t evt; + u8 _padding[FW_STATS_FUTURE_EXTENSION]; +} fw_stats_t; + +/* Firmware version struct */ + +typedef struct fw_ver { + u16 cmd; + u16 size; + char fw_id[20]; + u32 hw_id; +} ACX_PACKED fw_ver_t; + +#define FW_ID_SIZE 20 + + +/*--- WEP stuff --------------------------------------------------------------*/ +#define DOT11_MAX_DEFAULT_WEP_KEYS 4 + +/* non-firmware struct, no packing necessary */ +typedef struct wep_key { + size_t size; /* most often used member first */ + u8 index; + u8 key[29]; + u16 strange_filler; +} wep_key_t; /* size = 264 bytes (33*8) */ +/* FIXME: We don't have size 264! Or is there 2 bytes beyond the key + * (strange_filler)? */ + +/* non-firmware struct, no packing necessary */ +typedef struct key_struct { + u8 addr[ETH_ALEN]; /* 0x00 */ + u16 filler1; /* 0x06 */ + u32 filler2; /* 0x08 */ + u32 index; /* 0x0c */ + u16 len; /* 0x10 */ + u8 key[29]; /* 0x12; is this long enough??? */ +} key_struct_t; /* size = 276. FIXME: where is the remaining space?? */ + + +/*--- Client (peer) info -----------------------------------------------------*/ +/* adev->sta_list[] is used for: +** accumulating and processing of scan results +** keeping client info in AP mode +** keeping AP info in STA mode (AP is the only one 'client') +** keeping peer info in ad-hoc mode +** non-firmware struct --> no packing necessary */ +enum { + CLIENT_EMPTY_SLOT_0 = 0, + CLIENT_EXIST_1 = 1, + CLIENT_AUTHENTICATED_2 = 2, + CLIENT_ASSOCIATED_3 = 3, + CLIENT_JOIN_CANDIDATE = 4 +}; +struct client { + /* most frequent access first */ + u8 used; /* misnamed, more like 'status' */ + struct client* next; + unsigned long mtime; /* last time we heard it, in jiffies */ + size_t essid_len; /* length of ESSID (without '\0') */ + u32 sir; /* Standard IR */ + u32 snr; /* Signal to Noise Ratio */ + u16 aid; /* association ID */ + u16 seq; /* from client's auth req */ + u16 auth_alg; /* from client's auth req */ + u16 cap_info; /* from client's assoc req */ + u16 rate_cap; /* what client supports (all rates) */ + u16 rate_bas; /* what client supports (basic rates) */ + u16 rate_cfg; /* what is allowed (by iwconfig etc) */ + u16 rate_cur; /* currently used rate mask */ + u8 rate_100; /* currently used rate byte (acx100 only) */ + u8 address[ETH_ALEN]; + u8 bssid[ETH_ALEN]; /* ad-hoc hosts can have bssid != mac */ + u8 channel; + u8 auth_step; + u8 ignore_count; + u8 fallback_count; + u8 stepup_count; + char essid[IW_ESSID_MAX_SIZE + 1]; /* ESSID and trailing '\0' */ +/* FIXME: this one is too damn big */ + char challenge_text[WLAN_CHALLENGE_LEN]; +}; + + +/*********************************************************************** +** Hardware structures +*/ + +/* An opaque typesafe helper type + * + * Some hardware fields are actually pointers, + * but they have to remain u32, since using ptr instead + * (8 bytes on 64bit systems!) would disrupt the fixed descriptor + * format the acx firmware expects in the non-user area. + * Since we cannot cram an 8 byte ptr into 4 bytes, we need to + * enforce that pointed to data remains in low memory + * (address value needs to fit in 4 bytes) on 64bit systems. + * + * This is easy to get wrong, thus we are using a small struct + * and special macros to access it. Macros will check for + * attempts to overflow an acx_ptr with value > 0xffffffff. + * + * Attempts to use acx_ptr without macros result in compile-time errors */ + +typedef struct { + u32 v; +} ACX_PACKED acx_ptr; + +#if ACX_DEBUG +#define CHECK32(n) BUG_ON(sizeof(n)>4 && (long)(n)>0xffffff00) +#else +#define CHECK32(n) ((void)0) +#endif + +/* acx_ptr <-> integer conversion */ +#define cpu2acx(n) ({ CHECK32(n); ((acx_ptr){ .v = cpu_to_le32(n) }); }) +#define acx2cpu(a) (le32_to_cpu(a.v)) + +/* acx_ptr <-> pointer conversion */ +#define ptr2acx(p) ({ CHECK32(p); ((acx_ptr){ .v = cpu_to_le32((u32)(long)(p)) }); }) +#define acx2ptr(a) ((void*)le32_to_cpu(a.v)) + +/* Values for rate field (acx100 only) */ +#define RATE100_1 10 +#define RATE100_2 20 +#define RATE100_5 55 +#define RATE100_11 110 +#define RATE100_22 220 +/* This bit denotes use of PBCC: +** (PBCC encoding is usable with 11 and 22 Mbps speeds only) */ +#define RATE100_PBCC511 0x80 + +/* Bit values for rate111 field */ +#define RATE111_1 0x0001 /* DBPSK */ +#define RATE111_2 0x0002 /* DQPSK */ +#define RATE111_5 0x0004 /* CCK or PBCC */ +#define RATE111_6 0x0008 /* CCK-OFDM or OFDM */ +#define RATE111_9 0x0010 /* CCK-OFDM or OFDM */ +#define RATE111_11 0x0020 /* CCK or PBCC */ +#define RATE111_12 0x0040 /* CCK-OFDM or OFDM */ +#define RATE111_18 0x0080 /* CCK-OFDM or OFDM */ +#define RATE111_22 0x0100 /* PBCC */ +#define RATE111_24 0x0200 /* CCK-OFDM or OFDM */ +#define RATE111_36 0x0400 /* CCK-OFDM or OFDM */ +#define RATE111_48 0x0800 /* CCK-OFDM or OFDM */ +#define RATE111_54 0x1000 /* CCK-OFDM or OFDM */ +#define RATE111_RESERVED 0x2000 +#define RATE111_PBCC511 0x4000 /* PBCC mod at 5.5 or 11Mbit (else CCK) */ +#define RATE111_SHORTPRE 0x8000 /* short preamble */ +/* Special 'try everything' value */ +#define RATE111_ALL 0x1fff +/* These bits denote acx100 compatible settings */ +#define RATE111_ACX100_COMPAT 0x0127 +/* These bits denote 802.11b compatible settings */ +#define RATE111_80211B_COMPAT 0x0027 + +/* Descriptor Ctl field bits + * init value is 0x8e, "idle" value is 0x82 (in idle tx descs) + */ +#define DESC_CTL_SHORT_PREAMBLE 0x01 /* preamble type: 0 = long; 1 = short */ +#define DESC_CTL_FIRSTFRAG 0x02 /* this is the 1st frag of the frame */ +#define DESC_CTL_AUTODMA 0x04 +#define DESC_CTL_RECLAIM 0x08 /* ready to reuse */ +#define DESC_CTL_HOSTDONE 0x20 /* host has finished processing */ +#define DESC_CTL_ACXDONE 0x40 /* acx has finished processing */ +/* host owns the desc [has to be released last, AFTER modifying all other desc fields!] */ +#define DESC_CTL_HOSTOWN 0x80 +#define DESC_CTL_ACXDONE_HOSTOWN (DESC_CTL_ACXDONE | DESC_CTL_HOSTOWN) + +/* Descriptor Status field + */ +#define DESC_STATUS_FULL (1 << 31) + +/* NB: some bits may be interesting for Monitor mode tx (aka Raw tx): */ +#define DESC_CTL2_SEQ 0x01 /* don't increase sequence field */ +#define DESC_CTL2_FCS 0x02 /* don't add the FCS */ +#define DESC_CTL2_MORE_FRAG 0x04 +#define DESC_CTL2_RETRY 0x08 /* don't increase retry field */ +#define DESC_CTL2_POWER 0x10 /* don't increase power mgmt. field */ +#define DESC_CTL2_RTS 0x20 /* do RTS/CTS magic before sending */ +#define DESC_CTL2_WEP 0x40 /* encrypt this frame */ +#define DESC_CTL2_DUR 0x80 /* don't increase duration field */ + +/*********************************************************************** +** PCI structures +*/ +/* IRQ Constants +** (outside of "#ifdef PCI" because USB (mis)uses HOST_INT_SCAN_COMPLETE) */ +#define HOST_INT_RX_DATA 0x0001 +#define HOST_INT_TX_COMPLETE 0x0002 +#define HOST_INT_TX_XFER 0x0004 +#define HOST_INT_RX_COMPLETE 0x0008 +#define HOST_INT_DTIM 0x0010 +#define HOST_INT_BEACON 0x0020 +#define HOST_INT_TIMER 0x0040 +#define HOST_INT_KEY_NOT_FOUND 0x0080 +#define HOST_INT_IV_ICV_FAILURE 0x0100 +#define HOST_INT_CMD_COMPLETE 0x0200 +#define HOST_INT_INFO 0x0400 +#define HOST_INT_OVERFLOW 0x0800 +#define HOST_INT_PROCESS_ERROR 0x1000 +#define HOST_INT_SCAN_COMPLETE 0x2000 +#define HOST_INT_FCS_THRESHOLD 0x4000 +#define HOST_INT_UNKNOWN 0x8000 + +/* Outside of "#ifdef PCI" because USB needs to know sizeof() +** of txdesc and rxdesc: */ +struct txdesc { + acx_ptr pNextDesc; /* pointer to next txdesc */ + acx_ptr HostMemPtr; /* 0x04 */ + acx_ptr AcxMemPtr; /* 0x08 */ + u32 tx_time; /* 0x0c */ + u16 total_length; /* 0x10 */ + u16 Reserved; /* 0x12 */ + +/* The following 16 bytes do not change when acx100 owns the descriptor */ +/* BUG: fw clears last byte of this area which is supposedly reserved +** for driver use. amd64 blew up. We dare not use it now */ + u32 dummy[4]; + + u8 Ctl_8; /* 0x24, 8bit value */ + u8 Ctl2_8; /* 0x25, 8bit value */ + u8 error; /* 0x26 */ + u8 ack_failures; /* 0x27 */ + u8 rts_failures; /* 0x28 */ + u8 rts_ok; /* 0x29 */ + union { + struct { + u8 rate; /* 0x2a */ + u8 queue_ctrl; /* 0x2b */ + } ACX_PACKED r1; + struct { + u16 rate111; /* 0x2a */ + } ACX_PACKED r2; + } ACX_PACKED u; + u32 queue_info; /* 0x2c (acx100, reserved on acx111) */ +} ACX_PACKED; /* size : 48 = 0x30 */ +/* NB: acx111 txdesc structure is 4 byte larger */ +/* All these 4 extra bytes are reserved. tx alloc code takes them into account */ + +struct rxdesc { + acx_ptr pNextDesc; /* 0x00 */ + acx_ptr HostMemPtr; /* 0x04 */ + acx_ptr ACXMemPtr; /* 0x08 */ + u32 rx_time; /* 0x0c */ + u16 total_length; /* 0x10 */ + u16 WEP_length; /* 0x12 */ + u32 WEP_ofs; /* 0x14 */ + +/* the following 16 bytes do not change when acx100 owns the descriptor */ + u8 driverWorkspace[16]; /* 0x18 */ + + u8 Ctl_8; + u8 rate; + u8 error; + u8 SNR; /* Signal-to-Noise Ratio */ + u8 RxLevel; + u8 queue_ctrl; + u16 unknown; + u32 unknown2; +} ACX_PACKED; /* size 52 = 0x34 */ + +#ifdef ACX_PCI + +/* Register I/O offsets */ +#define ACX100_EEPROM_ID_OFFSET 0x380 + +/* please add further ACX hardware register definitions only when + it turns out you need them in the driver, and please try to use + firmware functionality instead, since using direct I/O access instead + of letting the firmware do it might confuse the firmware's state + machine */ + +/* ***** ABSOLUTELY ALWAYS KEEP OFFSETS IN SYNC WITH THE INITIALIZATION +** OF THE I/O ARRAYS!!!! (grep for '^IO_ACX') ***** */ +enum { + IO_ACX_SOFT_RESET = 0, + + IO_ACX_SLV_MEM_ADDR, + IO_ACX_SLV_MEM_DATA, + IO_ACX_SLV_MEM_CTL, + IO_ACX_SLV_END_CTL, + + IO_ACX_FEMR, /* Function Event Mask */ + + IO_ACX_INT_TRIG, + IO_ACX_IRQ_MASK, + IO_ACX_IRQ_STATUS_NON_DES, + IO_ACX_IRQ_STATUS_CLEAR, /* CLEAR = clear on read */ + IO_ACX_IRQ_ACK, + IO_ACX_HINT_TRIG, + + IO_ACX_ENABLE, + + IO_ACX_EEPROM_CTL, + IO_ACX_EEPROM_ADDR, + IO_ACX_EEPROM_DATA, + IO_ACX_EEPROM_CFG, + + IO_ACX_PHY_ADDR, + IO_ACX_PHY_DATA, + IO_ACX_PHY_CTL, + + IO_ACX_GPIO_OE, + + IO_ACX_GPIO_OUT, + + IO_ACX_CMD_MAILBOX_OFFS, + IO_ACX_INFO_MAILBOX_OFFS, + IO_ACX_EEPROM_INFORMATION, + + IO_ACX_EE_START, + IO_ACX_SOR_CFG, + IO_ACX_ECPU_CTRL +}; +/* ***** ABSOLUTELY ALWAYS KEEP OFFSETS IN SYNC WITH THE INITIALIZATION +** OF THE I/O ARRAYS!!!! (grep for '^IO_ACX') ***** */ + +/* Values for IO_ACX_INT_TRIG register: */ +/* inform hw that rxdesc in queue needs processing */ +#define INT_TRIG_RXPRC 0x08 +/* inform hw that txdesc in queue needs processing */ +#define INT_TRIG_TXPRC 0x04 +/* ack that we received info from info mailbox */ +#define INT_TRIG_INFOACK 0x02 +/* inform hw that we have filled command mailbox */ +#define INT_TRIG_CMD 0x01 + +struct txhostdesc { + acx_ptr data_phy; /* 0x00 [u8 *] */ + u16 data_offset; /* 0x04 */ + u16 reserved; /* 0x06 */ + u16 Ctl_16; /* 16bit value, endianness!! */ + u16 length; /* 0x0a */ + acx_ptr desc_phy_next; /* 0x0c [txhostdesc *] */ + acx_ptr pNext; /* 0x10 [txhostdesc *] */ + u32 Status; /* 0x14, unused on Tx */ +/* From here on you can use this area as you want (variable length, too!) */ + u8 *data; +} ACX_PACKED; + +struct rxhostdesc { + acx_ptr data_phy; /* 0x00 [rxbuffer_t *] */ + u16 data_offset; /* 0x04 */ + u16 reserved; /* 0x06 */ + u16 Ctl_16; /* 0x08; 16bit value, endianness!! */ + u16 length; /* 0x0a */ + acx_ptr desc_phy_next; /* 0x0c [rxhostdesc_t *] */ + acx_ptr pNext; /* 0x10 [rxhostdesc_t *] */ + u32 Status; /* 0x14 */ +/* From here on you can use this area as you want (variable length, too!) */ + rxbuffer_t *data; +} ACX_PACKED; + +#endif /* ACX_PCI */ + +/*********************************************************************** +** USB structures and constants +*/ +#ifdef ACX_USB + +/* Used for usb_txbuffer.desc field */ +#define USB_TXBUF_TXDESC 0xA +/* Size of header (everything up to data[]) */ +#define USB_TXBUF_HDRSIZE 14 +typedef struct usb_txbuffer { + u16 desc; + u16 mpdu_len; + u8 queue_index; + u8 rate; + u32 hostdata; + u8 ctrl1; + u8 ctrl2; + u16 data_len; + /* wlan packet content is placed here: */ + u8 data[WLAN_A4FR_MAXLEN_WEP_FCS]; +} ACX_PACKED usb_txbuffer_t; + +/* USB returns either rx packets (see rxbuffer) or +** these "tx status" structs: */ +typedef struct usb_txstatus { + u16 mac_cnt_rcvd; /* only 12 bits are len! (0xfff) */ + u8 queue_index; + u8 mac_status; /* seen 0x20 on tx failure */ + u32 hostdata; + u8 rate; + u8 ack_failures; + u8 rts_failures; + u8 rts_ok; +} ACX_PACKED usb_txstatus_t; + +typedef struct usb_tx { + unsigned busy:1; + struct urb *urb; + acx_device_t *adev; + /* actual USB bulk output data block is here: */ + usb_txbuffer_t bulkout; +} usb_tx_t; + +struct usb_rx_plain { + unsigned busy:1; + struct urb *urb; + acx_device_t *adev; + rxbuffer_t bulkin; +}; + +typedef struct usb_rx { + unsigned busy:1; + struct urb *urb; + acx_device_t *adev; + rxbuffer_t bulkin; + /* Make entire structure 4k. Report if it breaks something. */ + u8 padding[4*1024 - sizeof(struct usb_rx_plain)]; +} usb_rx_t; +#endif /* ACX_USB */ + + +/* Config Option structs */ + +typedef struct co_antennas { + u8 type; + u8 len; + u8 list[2]; +} ACX_PACKED co_antennas_t; + +typedef struct co_powerlevels { + u8 type; + u8 len; + u16 list[8]; +} ACX_PACKED co_powerlevels_t; + +typedef struct co_datarates { + u8 type; + u8 len; + u8 list[8]; +} ACX_PACKED co_datarates_t; + +typedef struct co_domains { + u8 type; + u8 len; + u8 list[6]; +} ACX_PACKED co_domains_t; + +typedef struct co_product_id { + u8 type; + u8 len; + u8 list[128]; +} ACX_PACKED co_product_id_t; + +typedef struct co_manuf_id { + u8 type; + u8 len; + u8 list[128]; +} ACX_PACKED co_manuf_t; + +typedef struct co_fixed { + char NVSv[8]; +/* u16 NVS_vendor_offs; ACX111-only */ +/* u16 unknown; ACX111-only */ + u8 MAC[6]; /* ACX100-only */ + u16 probe_delay; /* ACX100-only */ + u32 eof_memory; + u8 dot11CCAModes; + u8 dot11Diversity; + u8 dot11ShortPreambleOption; + u8 dot11PBCCOption; + u8 dot11ChannelAgility; + u8 dot11PhyType; /* FIXME: does 802.11 call it "dot11PHYType"? */ + u8 dot11TempType; + u8 table_count; +} ACX_PACKED co_fixed_t; + +typedef struct acx111_ie_configoption { + u16 type; + u16 len; +/* Do not access below members directly, they are in fact variable length */ + co_fixed_t fixed; + co_antennas_t antennas; + co_powerlevels_t power_levels; + co_datarates_t data_rates; + co_domains_t domains; + co_product_id_t product_id; + co_manuf_t manufacturer; + u8 _padding[4]; +} ACX_PACKED acx111_ie_configoption_t; + + +/*********************************************************************** +** Main acx per-device data structure +*/ +#define ACX_STATE_FW_LOADED 0x01 +#define ACX_STATE_IFACE_UP 0x02 + +/* MAC mode (BSS type) defines + * Note that they shouldn't be redefined, since they are also used + * during communication with firmware */ +#define ACX_MODE_0_ADHOC 0 +#define ACX_MODE_1_UNUSED 1 +#define ACX_MODE_2_STA 2 +#define ACX_MODE_3_AP 3 +/* These are our own inventions. Sending these to firmware +** makes it stop emitting beacons, which is exactly what we want +** for these modes */ +#define ACX_MODE_MONITOR 0xfe +#define ACX_MODE_OFF 0xff +/* 'Submode': identifies exact status of ADHOC/STA host */ +#define ACX_STATUS_0_STOPPED 0 +#define ACX_STATUS_1_SCANNING 1 +#define ACX_STATUS_2_WAIT_AUTH 2 +#define ACX_STATUS_3_AUTHENTICATED 3 +#define ACX_STATUS_4_ASSOCIATED 4 + +/* FIXME: this should be named something like struct acx_priv (typedef'd to + * acx_priv_t) */ + +/* non-firmware struct, no packing necessary */ +struct acx_device { + /* most frequent accesses first (dereferencing and cache line!) */ + + /*** Locking ***/ + /* FIXME: try to convert semaphore to more efficient mutex according + to Ingo Molnar's docs (but not before driver is in mainline or + pre-mutex Linux 2.6.10 is very outdated). */ + struct semaphore sem; + spinlock_t lock; +#if defined(PARANOID_LOCKING) /* Lock debugging */ + const char *last_sem; + const char *last_lock; + unsigned long sem_time; + unsigned long lock_time; +#endif + + /*** Linux network device ***/ + struct net_device *ndev; /* pointer to linux netdevice */ + + /*** Device statistics ***/ + struct net_device_stats stats; /* net device statistics */ +#ifdef WIRELESS_EXT + struct iw_statistics wstats; /* wireless statistics */ +#endif + /*** Power managment ***/ + struct pm_dev *pm; /* PM crap */ + + /*** Management timer ***/ + struct timer_list mgmt_timer; + + /*** Hardware identification ***/ + const char *chip_name; + u8 dev_type; + u8 chip_type; + u8 form_factor; + u8 radio_type; + u8 eeprom_version; + + /*** Config retrieved from EEPROM ***/ + char cfgopt_NVSv[8]; + u16 cfgopt_NVS_vendor_offs; + u8 cfgopt_MAC[6]; + u16 cfgopt_probe_delay; + u32 cfgopt_eof_memory; + u8 cfgopt_dot11CCAModes; + u8 cfgopt_dot11Diversity; + u8 cfgopt_dot11ShortPreambleOption; + u8 cfgopt_dot11PBCCOption; + u8 cfgopt_dot11ChannelAgility; + u8 cfgopt_dot11PhyType; + u8 cfgopt_dot11TempType; + co_antennas_t cfgopt_antennas; + co_powerlevels_t cfgopt_power_levels; + co_datarates_t cfgopt_data_rates; + co_domains_t cfgopt_domains; + co_product_id_t cfgopt_product_id; + co_manuf_t cfgopt_manufacturer; + + /*** Firmware identification ***/ + char firmware_version[FW_ID_SIZE+1]; + u32 firmware_numver; + u32 firmware_id; + const u16 *ie_len; + const u16 *ie_len_dot11; + + /*** Device state ***/ + u16 dev_state_mask; + u8 led_power; /* power LED status */ + u32 get_mask; /* mask of settings to fetch from the card */ + u32 set_mask; /* mask of settings to write to the card */ + + /* Barely used in USB case */ + u16 irq_status; + + u8 after_interrupt_jobs; /* mini job list for doing actions after an interrupt occurred */ + WORK_STRUCT after_interrupt_task; /* our task for after interrupt actions */ + + /*** scanning ***/ + u16 scan_count; /* number of times to do channel scan */ + u8 scan_mode; /* 0 == active, 1 == passive, 2 == background */ + u8 scan_rate; + u16 scan_duration; + u16 scan_probe_delay; +#if WIRELESS_EXT > 15 + struct iw_spy_data spy_data; /* FIXME: needs to be implemented! */ +#endif + + /*** Wireless network settings ***/ + /* copy of the device address (ifconfig hw ether) that we actually use + ** for 802.11; copied over from the network device's MAC address + ** (ifconfig) when it makes sense only */ + u8 dev_addr[MAX_ADDR_LEN]; + u8 bssid[ETH_ALEN]; /* the BSSID after having joined */ + u8 ap[ETH_ALEN]; /* The AP we want, FF:FF:FF:FF:FF:FF is any */ + u16 aid; /* The Association ID sent from the AP / last used AID if we're an AP */ + u16 mode; /* mode from iwconfig */ + int monitor_type; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_PRISM */ + u16 status; /* 802.11 association status */ + u8 essid_active; /* specific ESSID active, or select any? */ + u8 essid_len; /* to avoid dozens of strlen() */ + /* INCLUDES \0 termination for easy printf - but many places + ** simply want the string data memcpy'd plus a length indicator! + ** Keep that in mind... */ + char essid[IW_ESSID_MAX_SIZE+1]; + /* essid we are going to use for association, in case of "essid 'any'" + ** and in case of hidden ESSID (use configured ESSID then) */ + char essid_for_assoc[IW_ESSID_MAX_SIZE+1]; + char nick[IW_ESSID_MAX_SIZE+1]; /* see essid! */ + u8 channel; + u8 reg_dom_id; /* reg domain setting */ + u16 reg_dom_chanmask; + u16 auth_or_assoc_retries; + u16 scan_retries; + unsigned long scan_start; /* YES, jiffies is defined as "unsigned long" */ + + /* stations known to us (if we're an ap) */ + client_t sta_list[32]; /* tab is larger than list, so that */ + client_t *sta_hash_tab[64]; /* hash collisions are not likely */ + client_t *ap_client; /* this one is our AP (STA mode only) */ + + int dup_count; + int nondup_count; + unsigned long dup_msg_expiry; + u16 last_seq_ctrl; /* duplicate packet detection */ + + /* 802.11 power save mode */ + u8 ps_wakeup_cfg; + u8 ps_listen_interval; + u8 ps_options; + u8 ps_hangover_period; + u32 ps_enhanced_transition_time; + u32 ps_beacon_rx_time; + + /*** PHY settings ***/ + u8 fallback_threshold; + u8 stepup_threshold; + u16 rate_basic; + u16 rate_oper; + u16 rate_bcast; + u16 rate_bcast100; + u8 rate_auto; /* false if "iwconfig rate N" (WITHOUT 'auto'!) */ + u8 preamble_mode; /* 0 == Long Preamble, 1 == Short, 2 == Auto */ + u8 preamble_cur; + + u8 tx_disabled; + u8 tx_level_dbm; + /* u8 tx_level_val; */ + /* u8 tx_level_auto; whether to do automatic power adjustment */ + + unsigned long recalib_time_last_success; + unsigned long recalib_time_last_attempt; + int recalib_failure_count; + int recalib_msg_ratelimit; + int retry_errors_msg_ratelimit; + + unsigned long brange_time_last_state_change; /* time the power LED was last changed */ + u8 brange_last_state; /* last state of the LED */ + u8 brange_max_quality; /* maximum quality that equates to full speed */ + + u8 sensitivity; + u8 antenna; /* antenna settings */ + u8 ed_threshold; /* energy detect threshold */ + u8 cca; /* clear channel assessment */ + + u16 rts_threshold; + u16 frag_threshold; + u32 short_retry; + u32 long_retry; + u16 msdu_lifetime; + u16 listen_interval; /* given in units of beacon interval */ + u32 beacon_interval; + + u16 capabilities; + u8 rate_supported_len; + u8 rate_supported[13]; + + /*** Encryption settings (WEP) ***/ + u32 auth_alg; /* used in transmit_authen1 */ + u8 wep_enabled; + u8 wep_restricted; + u8 wep_current_index; + wep_key_t wep_keys[DOT11_MAX_DEFAULT_WEP_KEYS]; /* the default WEP keys */ + key_struct_t wep_key_struct[10]; + + /*** Unknown ***/ + u8 dtim_interval; + + /*** Card Rx/Tx management ***/ + u16 rx_config_1; + u16 rx_config_2; + u16 memblocksize; + unsigned int tx_free; + unsigned int tx_head; /* keep as close as possible to Tx stuff below (cache line) */ + u16 phy_header_len; + +/************************************************************************* + *** PCI/USB/... must be last or else hw agnostic code breaks horribly *** + *************************************************************************/ + + /* hack to let common code compile. FIXME */ + dma_addr_t rxhostdesc_startphy; + + /*** PCI stuff ***/ +#ifdef ACX_PCI + /* pointers to tx buffers, tx host descriptors (in host memory) + ** and tx descs in device memory */ + unsigned int tx_tail; + u8 *txbuf_start; + txhostdesc_t *txhostdesc_start; + txdesc_t *txdesc_start; /* points to PCI-mapped memory */ + dma_addr_t txbuf_startphy; + dma_addr_t txhostdesc_startphy; + /* sizes of above host memory areas */ + unsigned int txbuf_area_size; + unsigned int txhostdesc_area_size; + + unsigned int txdesc_size; /* size of txdesc; ACX111 = ACX100 + 4 */ + client_t *txc[TX_CNT]; + u16 txr[TX_CNT]; + + /* same for rx */ + unsigned int rx_tail; + rxbuffer_t *rxbuf_start; + rxhostdesc_t *rxhostdesc_start; + rxdesc_t *rxdesc_start; + /* physical addresses of above host memory areas */ + dma_addr_t rxbuf_startphy; + /* dma_addr_t rxhostdesc_startphy; */ + unsigned int rxbuf_area_size; + unsigned int rxhostdesc_area_size; + + u8 need_radio_fw; + u8 irqs_active; /* whether irq sending is activated */ + + const u16 *io; /* points to ACX100 or ACX111 PCI I/O register address set */ + + struct pci_dev *pdev; + + unsigned long membase; + unsigned long membase2; + void __iomem *iobase; + void __iomem *iobase2; + /* command interface */ + u8 __iomem *cmd_area; + u8 __iomem *info_area; + + u16 irq_mask; /* interrupt types to mask out (not wanted) with many IRQs activated */ + u16 irq_mask_off; /* interrupt types to mask out (not wanted) with IRQs off */ + unsigned int irq_loops_this_jiffy; + unsigned long irq_last_jiffies; +#endif + + /*** USB stuff ***/ +#ifdef ACX_USB + struct usb_device *usbdev; + + rxbuffer_t rxtruncbuf; + + usb_tx_t *usb_tx; + usb_rx_t *usb_rx; + + int bulkinep; /* bulk-in endpoint */ + int bulkoutep; /* bulk-out endpoint */ + int rxtruncsize; +#endif + +}; + +static inline acx_device_t* +ndev2adev(struct net_device *ndev) +{ + return netdev_priv(ndev); +} + + +/* For use with ACX1xx_IE_RXCONFIG */ +/* bit description + * 13 include additional header (length etc.) *required* + * struct is defined in 'struct rxbuffer' + * is this bit acx100 only? does acx111 always put the header, + * and bit setting is irrelevant? --vda + * 10 receive frames only with SSID used in last join cmd + * 9 discard broadcast + * 8 receive packets for multicast address 1 + * 7 receive packets for multicast address 0 + * 6 discard all multicast packets + * 5 discard frames from foreign BSSID + * 4 discard frames with foreign destination MAC address + * 3 promiscuous mode (receive ALL frames, disable filter) + * 2 include FCS + * 1 include phy header + * 0 ??? + */ +#define RX_CFG1_INCLUDE_RXBUF_HDR 0x2000 /* ACX100 only */ +#define RX_CFG1_FILTER_SSID 0x0400 +#define RX_CFG1_FILTER_BCAST 0x0200 +#define RX_CFG1_RCV_MC_ADDR1 0x0100 +#define RX_CFG1_RCV_MC_ADDR0 0x0080 +#define RX_CFG1_FILTER_ALL_MULTI 0x0040 +#define RX_CFG1_FILTER_BSSID 0x0020 +#define RX_CFG1_FILTER_MAC 0x0010 +#define RX_CFG1_RCV_PROMISCUOUS 0x0008 +#define RX_CFG1_INCLUDE_FCS 0x0004 +#define RX_CFG1_INCLUDE_PHY_HDR (WANT_PHY_HDR ? 0x0002 : 0) +/* bit description + * 11 receive association requests etc. + * 10 receive authentication frames + * 9 receive beacon frames + * 8 receive contention free packets + * 7 receive control frames + * 6 receive data frames + * 5 receive broken frames + * 4 receive management frames + * 3 receive probe requests + * 2 receive probe responses + * 1 receive RTS/CTS/ACK frames + * 0 receive other + */ +#define RX_CFG2_RCV_ASSOC_REQ 0x0800 +#define RX_CFG2_RCV_AUTH_FRAMES 0x0400 +#define RX_CFG2_RCV_BEACON_FRAMES 0x0200 +#define RX_CFG2_RCV_CONTENTION_FREE 0x0100 +#define RX_CFG2_RCV_CTRL_FRAMES 0x0080 +#define RX_CFG2_RCV_DATA_FRAMES 0x0040 +#define RX_CFG2_RCV_BROKEN_FRAMES 0x0020 +#define RX_CFG2_RCV_MGMT_FRAMES 0x0010 +#define RX_CFG2_RCV_PROBE_REQ 0x0008 +#define RX_CFG2_RCV_PROBE_RESP 0x0004 +#define RX_CFG2_RCV_ACK_FRAMES 0x0002 +#define RX_CFG2_RCV_OTHER 0x0001 + +/* For use with ACX1xx_IE_FEATURE_CONFIG */ +#define FEATURE1_80MHZ_CLOCK 0x00000040L +#define FEATURE1_4X 0x00000020L +#define FEATURE1_LOW_RX 0x00000008L +#define FEATURE1_EXTRA_LOW_RX 0x00000001L + +#define FEATURE2_SNIFFER 0x00000080L +#define FEATURE2_NO_TXCRYPT 0x00000001L + +/*-- get and set mask values --*/ +#define GETSET_LED_POWER 0x00000001L +#define GETSET_STATION_ID 0x00000002L +#define SET_TEMPLATES 0x00000004L +#define SET_STA_LIST 0x00000008L +#define GETSET_TX 0x00000010L +#define GETSET_RX 0x00000020L +#define SET_RXCONFIG 0x00000040L +#define GETSET_ANTENNA 0x00000080L +#define GETSET_SENSITIVITY 0x00000100L +#define GETSET_TXPOWER 0x00000200L +#define GETSET_ED_THRESH 0x00000400L +#define GETSET_CCA 0x00000800L +#define GETSET_POWER_80211 0x00001000L +#define GETSET_RETRY 0x00002000L +#define GETSET_REG_DOMAIN 0x00004000L +#define GETSET_CHANNEL 0x00008000L +/* Used when ESSID changes etc and we need to scan for AP anew */ +#define GETSET_RESCAN 0x00010000L +#define GETSET_MODE 0x00020000L +#define GETSET_WEP 0x00040000L +#define SET_WEP_OPTIONS 0x00080000L +#define SET_MSDU_LIFETIME 0x00100000L +#define SET_RATE_FALLBACK 0x00200000L + +/* keep in sync with the above */ +#define GETSET_ALL (0 \ +/* GETSET_LED_POWER */ | 0x00000001L \ +/* GETSET_STATION_ID */ | 0x00000002L \ +/* SET_TEMPLATES */ | 0x00000004L \ +/* SET_STA_LIST */ | 0x00000008L \ +/* GETSET_TX */ | 0x00000010L \ +/* GETSET_RX */ | 0x00000020L \ +/* SET_RXCONFIG */ | 0x00000040L \ +/* GETSET_ANTENNA */ | 0x00000080L \ +/* GETSET_SENSITIVITY */| 0x00000100L \ +/* GETSET_TXPOWER */ | 0x00000200L \ +/* GETSET_ED_THRESH */ | 0x00000400L \ +/* GETSET_CCA */ | 0x00000800L \ +/* GETSET_POWER_80211 */| 0x00001000L \ +/* GETSET_RETRY */ | 0x00002000L \ +/* GETSET_REG_DOMAIN */ | 0x00004000L \ +/* GETSET_CHANNEL */ | 0x00008000L \ +/* GETSET_RESCAN */ | 0x00010000L \ +/* GETSET_MODE */ | 0x00020000L \ +/* GETSET_WEP */ | 0x00040000L \ +/* SET_WEP_OPTIONS */ | 0x00080000L \ +/* SET_MSDU_LIFETIME */ | 0x00100000L \ +/* SET_RATE_FALLBACK */ | 0x00200000L \ + ) + + +/*********************************************************************** +** Firmware loading +*/ +#include /* request_firmware() */ +#include /* struct pci_device */ + + +/*********************************************************************** +*/ +typedef struct acx100_ie_memblocksize { + u16 type; + u16 len; + u16 size; +} ACX_PACKED acx100_ie_memblocksize_t; + +typedef struct acx100_ie_queueconfig { + u16 type; + u16 len; + u32 AreaSize; + u32 RxQueueStart; + u8 QueueOptions; + u8 NumTxQueues; + u8 NumRxDesc; /* for USB only */ + u8 pad1; + u32 QueueEnd; + u32 HostQueueEnd; /* QueueEnd2 */ + u32 TxQueueStart; + u8 TxQueuePri; + u8 NumTxDesc; + u16 pad2; +} ACX_PACKED acx100_ie_queueconfig_t; + +typedef struct acx111_ie_queueconfig { + u16 type; + u16 len; + u32 tx_memory_block_address; + u32 rx_memory_block_address; + u32 rx1_queue_address; + u32 reserved1; + u32 tx1_queue_address; + u8 tx1_attributes; + u16 reserved2; + u8 reserved3; +} ACX_PACKED acx111_ie_queueconfig_t; + +typedef struct acx100_ie_memconfigoption { + u16 type; + u16 len; + u32 DMA_config; + acx_ptr pRxHostDesc; + u32 rx_mem; + u32 tx_mem; + u16 RxBlockNum; + u16 TxBlockNum; +} ACX_PACKED acx100_ie_memconfigoption_t; + +typedef struct acx111_ie_memoryconfig { + u16 type; + u16 len; + u16 no_of_stations; + u16 memory_block_size; + u8 tx_rx_memory_block_allocation; + u8 count_rx_queues; + u8 count_tx_queues; + u8 options; + u8 fragmentation; + u16 reserved1; + u8 reserved2; + + /* start of rx1 block */ + u8 rx_queue1_count_descs; + u8 rx_queue1_reserved1; + u8 rx_queue1_type; /* must be set to 7 */ + u8 rx_queue1_prio; /* must be set to 0 */ + acx_ptr rx_queue1_host_rx_start; + /* end of rx1 block */ + + /* start of tx1 block */ + u8 tx_queue1_count_descs; + u8 tx_queue1_reserved1; + u8 tx_queue1_reserved2; + u8 tx_queue1_attributes; + /* end of tx1 block */ +} ACX_PACKED acx111_ie_memoryconfig_t; + +typedef struct acx_ie_memmap { + u16 type; + u16 len; + u32 CodeStart; + u32 CodeEnd; + u32 WEPCacheStart; + u32 WEPCacheEnd; + u32 PacketTemplateStart; + u32 PacketTemplateEnd; + u32 QueueStart; + u32 QueueEnd; + u32 PoolStart; + u32 PoolEnd; +} ACX_PACKED acx_ie_memmap_t; + +typedef struct acx111_ie_feature_config { + u16 type; + u16 len; + u32 feature_options; + u32 data_flow_options; +} ACX_PACKED acx111_ie_feature_config_t; + +typedef struct acx111_ie_tx_level { + u16 type; + u16 len; + u8 level; +} ACX_PACKED acx111_ie_tx_level_t; + +#define PS_CFG_ENABLE 0x80 +#define PS_CFG_PENDING 0x40 /* status flag when entering PS */ +#define PS_CFG_WAKEUP_MODE_MASK 0x07 +#define PS_CFG_WAKEUP_BY_HOST 0x03 +#define PS_CFG_WAKEUP_EACH_ITVL 0x02 +#define PS_CFG_WAKEUP_ON_DTIM 0x01 +#define PS_CFG_WAKEUP_ALL_BEAC 0x00 + +/* Enhanced PS mode: sleep until Rx Beacon w/ the STA's AID bit set +** in the TIM; newer firmwares only(?) */ +#define PS_OPT_ENA_ENHANCED_PS 0x04 +#define PS_OPT_TX_PSPOLL 0x02 /* send PSPoll frame to fetch waiting frames from AP (on frame with matching AID) */ +#define PS_OPT_STILL_RCV_BCASTS 0x01 + +typedef struct acx100_ie_powersave { + u16 type; + u16 len; + u8 wakeup_cfg; + u8 listen_interval; /* for EACH_ITVL: wake up every "beacon units" interval */ + u8 options; + u8 hangover_period; /* remaining wake time after Tx MPDU w/ PS bit, in values of 1/1024 seconds */ + u16 enhanced_ps_transition_time; /* rem. wake time for Enh. PS */ +} ACX_PACKED acx100_ie_powersave_t; + +typedef struct acx111_ie_powersave { + u16 type; + u16 len; + u8 wakeup_cfg; + u8 listen_interval; /* for EACH_ITVL: wake up every "beacon units" interval */ + u8 options; + u8 hangover_period; /* remaining wake time after Tx MPDU w/ PS bit, in values of 1/1024 seconds */ + u32 beacon_rx_time; + u32 enhanced_ps_transition_time; /* rem. wake time for Enh. PS */ +} ACX_PACKED acx111_ie_powersave_t; + + +/*********************************************************************** +** Commands and template structures +*/ + +/* +** SCAN command structure +** +** even though acx100 scan rates match RATE100 constants, +** acx111 ones do not match! Therefore we do not use RATE100 #defines */ +#define ACX_SCAN_RATE_1 10 +#define ACX_SCAN_RATE_2 20 +#define ACX_SCAN_RATE_5 55 +#define ACX_SCAN_RATE_11 110 +#define ACX_SCAN_RATE_22 220 +#define ACX_SCAN_RATE_PBCC 0x80 /* OR with this if needed */ +#define ACX_SCAN_OPT_ACTIVE 0x00 /* a bit mask */ +#define ACX_SCAN_OPT_PASSIVE 0x01 +/* Background scan: we go into Power Save mode (by transmitting +** NULL data frame to AP with the power mgmt bit set), do the scan, +** and then exit Power Save mode. A plus is that AP buffers frames +** for us while we do background scan. Thus we avoid frame losses. +** Background scan can be active or passive, just like normal one */ +#define ACX_SCAN_OPT_BACKGROUND 0x02 +typedef struct acx100_scan { + u16 count; /* number of scans to do, 0xffff == continuous */ + u16 start_chan; + u16 flags; /* channel list mask; 0x8000 == all channels? */ + u8 max_rate; /* max. probe rate */ + u8 options; /* bit mask, see defines above */ + u16 chan_duration; + u16 max_probe_delay; +} ACX_PACKED acx100_scan_t; /* length 0xc */ + +#define ACX111_SCAN_RATE_6 0x0B +#define ACX111_SCAN_RATE_9 0x0F +#define ACX111_SCAN_RATE_12 0x0A +#define ACX111_SCAN_RATE_18 0x0E +#define ACX111_SCAN_RATE_24 0x09 +#define ACX111_SCAN_RATE_36 0x0D +#define ACX111_SCAN_RATE_48 0x08 +#define ACX111_SCAN_RATE_54 0x0C +#define ACX111_SCAN_OPT_5GHZ 0x04 /* else 2.4GHZ */ +#define ACX111_SCAN_MOD_SHORTPRE 0x01 /* you can combine SHORTPRE and PBCC */ +#define ACX111_SCAN_MOD_PBCC 0x80 +#define ACX111_SCAN_MOD_OFDM 0x40 +typedef struct acx111_scan { + u16 count; /* number of scans to do */ + u8 channel_list_select; /* 0: scan all channels, 1: from chan_list only */ + u16 reserved1; + u8 reserved2; + u8 rate; /* rate for probe requests (if active scan) */ + u8 options; /* bit mask, see defines above */ + u16 chan_duration; /* min time to wait for reply on one channel (in TU) */ + /* (active scan only) (802.11 section 11.1.3.2.2) */ + u16 max_probe_delay; /* max time to wait for reply on one channel (active scan) */ + /* time to listen on a channel (passive scan) */ + u8 modulation; + u8 channel_list[26]; /* bits 7:0 first byte: channels 8:1 */ + /* bits 7:0 second byte: channels 16:9 */ + /* 26 bytes is enough to cover 802.11a */ +} ACX_PACKED acx111_scan_t; + + +/* +** Radio calibration command structure +*/ +typedef struct acx111_cmd_radiocalib { +/* 0x80000000 == automatic calibration by firmware, according to interval; + * bits 0..3: select calibration methods to go through: + * calib based on DC, AfeDC, Tx mismatch, Tx equilization */ + u32 methods; + u32 interval; +} ACX_PACKED acx111_cmd_radiocalib_t; + + +/* +** Packet template structures +** +** Packet templates store contents of Beacon, Probe response, Probe request, +** Null data frame, and TIM data frame. Firmware automatically transmits +** contents of template at appropriate time: +** - Beacon: when configured as AP or Ad-hoc +** - Probe response: when configured as AP or Ad-hoc, whenever +** a Probe request frame is received +** - Probe request: when host issues SCAN command (active) +** - Null data frame: when entering 802.11 power save mode +** - TIM data: at the end of Beacon frames (if no TIM template +** is configured, then transmits default TIM) +** NB: +** - size field must be set to size of actual template +** (NOT sizeof(struct) - templates are variable in length), +** size field is not itself counted. +** - members flagged with an asterisk must be initialized with host, +** rest must be zero filled. +** - variable length fields shown only in comments */ +typedef struct acx_template_tim { + u16 size; + u8 tim_eid; /* 00 1 TIM IE ID * */ + u8 len; /* 01 1 Length * */ + u8 dtim_cnt; /* 02 1 DTIM Count */ + u8 dtim_period; /* 03 1 DTIM Period */ + u8 bitmap_ctrl; /* 04 1 Bitmap Control * (except bit0) */ + /* 05 n Partial Virtual Bitmap * */ + u8 variable[0x100 - 1-1-1-1-1]; +} ACX_PACKED acx_template_tim_t; + +typedef struct acx_template_probereq { + u16 size; + u16 fc; /* 00 2 fc * */ + u16 dur; /* 02 2 Duration */ + u8 da[6]; /* 04 6 Destination Address * */ + u8 sa[6]; /* 0A 6 Source Address * */ + u8 bssid[6]; /* 10 6 BSSID * */ + u16 seq; /* 16 2 Sequence Control */ + /* 18 n SSID * */ + /* nn n Supported Rates * */ + u8 variable[0x44 - 2-2-6-6-6-2]; +} ACX_PACKED acx_template_probereq_t; + +typedef struct acx_template_proberesp { + u16 size; + u16 fc; /* 00 2 fc * (bits [15:12] and [10:8] per 802.11 section 7.1.3.1) */ + u16 dur; /* 02 2 Duration */ + u8 da[6]; /* 04 6 Destination Address */ + u8 sa[6]; /* 0A 6 Source Address */ + u8 bssid[6]; /* 10 6 BSSID */ + u16 seq; /* 16 2 Sequence Control */ + u8 timestamp[8];/* 18 8 Timestamp */ + u16 beacon_interval; /* 20 2 Beacon Interval * */ + u16 cap; /* 22 2 Capability Information * */ + /* 24 n SSID * */ + /* nn n Supported Rates * */ + /* nn 1 DS Parameter Set * */ + u8 variable[0x54 - 2-2-6-6-6-2-8-2-2]; +} ACX_PACKED acx_template_proberesp_t; +#define acx_template_beacon_t acx_template_proberesp_t +#define acx_template_beacon acx_template_proberesp + +typedef struct acx_template_nullframe { + u16 size; + struct wlan_hdr_a3 hdr; +} ACX_PACKED acx_template_nullframe_t; + + +/* +** JOIN command structure +** +** as opposed to acx100, acx111 dtim interval is AFTER rates_basic111. +** NOTE: took me about an hour to get !@#$%^& packing right --> struct packing is eeeeevil... */ +typedef struct acx_joinbss { + u8 bssid[ETH_ALEN]; + u16 beacon_interval; + union { + struct { + u8 dtim_interval; + u8 rates_basic; + u8 rates_supported; + } ACX_PACKED acx100; + struct { + u16 rates_basic; + u8 dtim_interval; + } ACX_PACKED acx111; + } ACX_PACKED u; + u8 genfrm_txrate; /* generated frame (bcn, proberesp, RTS, PSpoll) tx rate */ + u8 genfrm_mod_pre; /* generated frame modulation/preamble: + ** bit7: PBCC, bit6: OFDM (else CCK/DQPSK/DBPSK) + ** bit5: short pre */ + u8 macmode; /* BSS Type, must be one of ACX_MODE_xxx */ + u8 channel; + u8 essid_len; + char essid[IW_ESSID_MAX_SIZE]; +} ACX_PACKED acx_joinbss_t; + +#define JOINBSS_RATES_1 0x01 +#define JOINBSS_RATES_2 0x02 +#define JOINBSS_RATES_5 0x04 +#define JOINBSS_RATES_11 0x08 +#define JOINBSS_RATES_22 0x10 + +/* Looks like missing bits are used to indicate 11g rates! +** (it follows from the fact that constants below match 1:1 to RATE111_nn) +** This was actually seen! Look at that Assoc Request sent by acx111, +** it _does_ contain 11g rates in basic set: +01:30:20.070772 Beacon (xxx) [1.0* 2.0* 5.5* 11.0* 6.0* 9.0* 12.0* 18.0* 24.0* 36.0* 48.0* 54.0* Mbit] ESS CH: 1 +01:30:20.074425 Authentication (Open System)-1: Succesful +01:30:20.076539 Authentication (Open System)-2: +01:30:20.076620 Acknowledgment +01:30:20.088546 Assoc Request (xxx) [1.0* 2.0* 5.5* 6.0* 9.0* 11.0* 12.0* 18.0* 24.0* 36.0* 48.0* 54.0* Mbit] +01:30:20.122413 Assoc Response AID(1) :: Succesful +01:30:20.122679 Acknowledgment +01:30:20.173204 Beacon (xxx) [1.0* 2.0* 5.5* 11.0* 6.0* 9.0* 12.0* 18.0* 24.0* 36.0* 48.0* 54.0* Mbit] ESS CH: 1 +*/ +#define JOINBSS_RATES_BASIC111_1 0x0001 +#define JOINBSS_RATES_BASIC111_2 0x0002 +#define JOINBSS_RATES_BASIC111_5 0x0004 +#define JOINBSS_RATES_BASIC111_11 0x0020 +#define JOINBSS_RATES_BASIC111_22 0x0100 + + +/*********************************************************************** +*/ +typedef struct mem_read_write { + u16 addr; + u16 type; /* 0x0 int. RAM / 0xffff MAC reg. / 0x81 PHY RAM / 0x82 PHY reg.; or maybe it's actually 0x30 for MAC? Better verify it by writing and reading back and checking whether the value holds! */ + u32 len; + u32 data; +} ACX_PACKED mem_read_write_t; + +typedef struct firmware_image { + u32 chksum; + u32 size; + u8 data[1]; /* the byte array of the actual firmware... */ +} ACX_PACKED firmware_image_t; + +typedef struct acx_cmd_radioinit { + u32 offset; + u32 len; +} ACX_PACKED acx_cmd_radioinit_t; + +typedef struct acx100_ie_wep_options { + u16 type; + u16 len; + u16 NumKeys; /* max # of keys */ + u8 WEPOption; /* 0 == decrypt default key only, 1 == override decrypt */ + u8 Pad; /* used only for acx111 */ +} ACX_PACKED acx100_ie_wep_options_t; + +typedef struct ie_dot11WEPDefaultKey { + u16 type; + u16 len; + u8 action; + u8 keySize; + u8 defaultKeyNum; + u8 key[29]; /* check this! was Key[19] */ +} ACX_PACKED ie_dot11WEPDefaultKey_t; + +typedef struct acx111WEPDefaultKey { + u8 MacAddr[ETH_ALEN]; + u16 action; /* NOTE: this is a u16, NOT a u8!! */ + u16 reserved; + u8 keySize; + u8 type; + u8 index; + u8 defaultKeyNum; + u8 counter[6]; + u8 key[32]; /* up to 32 bytes (for TKIP!) */ +} ACX_PACKED acx111WEPDefaultKey_t; + +typedef struct ie_dot11WEPDefaultKeyID { + u16 type; + u16 len; + u8 KeyID; +} ACX_PACKED ie_dot11WEPDefaultKeyID_t; + +typedef struct acx100_cmd_wep_mgmt { + u8 MacAddr[ETH_ALEN]; + u16 Action; + u16 KeySize; + u8 Key[29]; /* 29*8 == 232bits == WEP256 */ +} ACX_PACKED acx100_cmd_wep_mgmt_t; + +typedef struct acx_ie_generic { + u16 type; + u16 len; + union { + /* Association ID IE: just a 16bit value: */ + u16 aid; + /* generic member for quick implementation of commands */ + u8 bytes[32]; + } ACX_PACKED m; +} ACX_PACKED acx_ie_generic_t; + +/*********************************************************************** +*/ +#define CHECK_SIZEOF(type,size) { \ + extern void BUG_bad_size_for_##type(void); \ + if (sizeof(type)!=(size)) BUG_bad_size_for_##type(); \ +} + +static inline void +acx_struct_size_check(void) +{ + CHECK_SIZEOF(txdesc_t, 0x30); + CHECK_SIZEOF(acx100_ie_memconfigoption_t, 24); + CHECK_SIZEOF(acx100_ie_queueconfig_t, 0x20); + CHECK_SIZEOF(acx_joinbss_t, 0x30); + /* IEs need 4 bytes for (type,len) tuple */ + CHECK_SIZEOF(acx111_ie_configoption_t, ACX111_IE_CONFIG_OPTIONS_LEN + 4); +} + + +/*********************************************************************** +** Global data +*/ +extern const u8 acx_bitpos2ratebyte[]; +extern const u8 acx_bitpos2rate100[]; + +extern const u8 acx_reg_domain_ids[]; +extern const char * const acx_reg_domain_strings[]; +enum { + acx_reg_domain_ids_len = 8 +}; + +extern const struct iw_handler_def acx_ioctl_handler_def; --- linux-2.6.27.orig/ubuntu/misc/wireless/acx/wlan_mgmt.h +++ linux-2.6.27/ubuntu/misc/wireless/acx/wlan_mgmt.h @@ -0,0 +1,582 @@ +/*********************************************************************** +** Copyright (C) 2003 ACX100 Open Source Project +** +** The contents of this file are subject to the Mozilla Public +** License Version 1.1 (the "License"); you may not use this file +** except in compliance with the License. You may obtain a copy of +** the License at http://www.mozilla.org/MPL/ +** +** Software distributed under the License is distributed on an "AS +** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +** implied. See the License for the specific language governing +** rights and limitations under the License. +** +** Alternatively, the contents of this file may be used under the +** terms of the GNU Public License version 2 (the "GPL"), in which +** case the provisions of the GPL are applicable instead of the +** above. If you wish to allow the use of your version of this file +** only under the terms of the GPL and not to allow others to use +** your version of this file under the MPL, indicate your decision +** by deleting the provisions above and replace them with the notice +** and other provisions required by the GPL. If you do not delete +** the provisions above, a recipient may use your version of this +** file under either the MPL or the GPL. +** --------------------------------------------------------------------- +** Inquiries regarding the ACX100 Open Source Project can be +** made directly to: +** +** acx100-users@lists.sf.net +** http://acx100.sf.net +** --------------------------------------------------------------------- +*/ + +/*********************************************************************** +** This code is based on elements which are +** Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +** info@linux-wlan.com +** http://www.linux-wlan.com +*/ + +/*********************************************************************** +** Constants +*/ + +/*-- Information Element IDs --------------------*/ +#define WLAN_EID_SSID 0 +#define WLAN_EID_SUPP_RATES 1 +#define WLAN_EID_FH_PARMS 2 +#define WLAN_EID_DS_PARMS 3 +#define WLAN_EID_CF_PARMS 4 +#define WLAN_EID_TIM 5 +#define WLAN_EID_IBSS_PARMS 6 +#define WLAN_EID_COUNTRY 7 /* 802.11d */ +#define WLAN_EID_FH_HOP_PARMS 8 /* 802.11d */ +#define WLAN_EID_FH_TABLE 9 /* 802.11d */ +#define WLAN_EID_REQUEST 10 /* 802.11d */ +/*-- values 11-15 reserved --*/ +#define WLAN_EID_CHALLENGE 16 +/*-- values 17-31 reserved for challenge text extension --*/ +#define WLAN_EID_PWR_CONSTRAINT 32 /* 11h PowerConstraint */ +#define WLAN_EID_ERP_INFO 42 /* was seen from WRT54GS with OpenWrt */ +#define WLAN_EID_NONERP 47 /* was seen from WRT54GS with OpenWrt */ +#define WLAN_EID_RSN 48 +#define WLAN_EID_EXT_RATES 50 +#define WLAN_EID_UNKNOWN128 128 +#define WLAN_EID_UNKNOWN133 133 +#define WLAN_EID_GENERIC 221 /* was seen from WRT54GS with OpenWrt */ +#define WLAN_EID_UNKNOWN223 223 + +#if 0 +#define WLAN_EID_PWR_CAP 33 /* 11h PowerCapability */ +#define WLAN_EID_TPC_REQUEST 34 /* 11h TPC Request */ +#define WLAN_EID_TPC_REPORT 35 /* 11h TPC Report */ +#define WLAN_EID_SUPP_CHANNELS 36 /* 11h Supported Channels */ +#define WLAN_EID_CHANNEL_SWITCH 37 /* 11h ChannelSwitch */ +#define WLAN_EID_MEASURE_REQUEST 38 /* 11h MeasurementRequest */ +#define WLAN_EID_MEASURE_REPORT 39 /* 11h MeasurementReport */ +#define WLAN_EID_QUIET_ID 40 /* 11h Quiet */ +#define WLAN_EID_IBSS_DFS_ID 41 /* 11h IBSS_DFS */ +#endif + +/*-- Reason Codes -------------------------------*/ +#define WLAN_MGMT_REASON_RSVD 0 +#define WLAN_MGMT_REASON_UNSPEC 1 +#define WLAN_MGMT_REASON_PRIOR_AUTH_INVALID 2 +#define WLAN_MGMT_REASON_DEAUTH_LEAVING 3 +#define WLAN_MGMT_REASON_DISASSOC_INACTIVE 4 +#define WLAN_MGMT_REASON_DISASSOC_AP_BUSY 5 +#define WLAN_MGMT_REASON_CLASS2_NONAUTH 6 +#define WLAN_MGMT_REASON_CLASS3_NONASSOC 7 +#define WLAN_MGMT_REASON_DISASSOC_STA_HASLEFT 8 +#define WLAN_MGMT_REASON_CANT_ASSOC_NONAUTH 9 + +/*-- Status Codes -------------------------------*/ +#define WLAN_MGMT_STATUS_SUCCESS 0 +#define WLAN_MGMT_STATUS_UNSPEC_FAILURE 1 +#define WLAN_MGMT_STATUS_CAPS_UNSUPPORTED 10 +#define WLAN_MGMT_STATUS_REASSOC_NO_ASSOC 11 +#define WLAN_MGMT_STATUS_ASSOC_DENIED_UNSPEC 12 +#define WLAN_MGMT_STATUS_UNSUPPORTED_AUTHALG 13 +#define WLAN_MGMT_STATUS_RX_AUTH_NOSEQ 14 +#define WLAN_MGMT_STATUS_CHALLENGE_FAIL 15 +#define WLAN_MGMT_STATUS_AUTH_TIMEOUT 16 +#define WLAN_MGMT_STATUS_ASSOC_DENIED_BUSY 17 +#define WLAN_MGMT_STATUS_ASSOC_DENIED_RATES 18 +/* p80211b additions */ +#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOSHORT 19 +#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOPBCC 20 +#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOAGILITY 21 + +/*-- Auth Algorithm Field ---------------------------*/ +#define WLAN_AUTH_ALG_OPENSYSTEM 0 +#define WLAN_AUTH_ALG_SHAREDKEY 1 + +/*-- Management Frame Field Offsets -------------*/ +/* Note: Not all fields are listed because of variable lengths */ +/* Note: These offsets are from the start of the frame data */ + +#define WLAN_BEACON_OFF_TS 0 +#define WLAN_BEACON_OFF_BCN_INT 8 +#define WLAN_BEACON_OFF_CAPINFO 10 +#define WLAN_BEACON_OFF_SSID 12 + +#define WLAN_DISASSOC_OFF_REASON 0 + +#define WLAN_ASSOCREQ_OFF_CAP_INFO 0 +#define WLAN_ASSOCREQ_OFF_LISTEN_INT 2 +#define WLAN_ASSOCREQ_OFF_SSID 4 + +#define WLAN_ASSOCRESP_OFF_CAP_INFO 0 +#define WLAN_ASSOCRESP_OFF_STATUS 2 +#define WLAN_ASSOCRESP_OFF_AID 4 +#define WLAN_ASSOCRESP_OFF_SUPP_RATES 6 + +#define WLAN_REASSOCREQ_OFF_CAP_INFO 0 +#define WLAN_REASSOCREQ_OFF_LISTEN_INT 2 +#define WLAN_REASSOCREQ_OFF_CURR_AP 4 +#define WLAN_REASSOCREQ_OFF_SSID 10 + +#define WLAN_REASSOCRESP_OFF_CAP_INFO 0 +#define WLAN_REASSOCRESP_OFF_STATUS 2 +#define WLAN_REASSOCRESP_OFF_AID 4 +#define WLAN_REASSOCRESP_OFF_SUPP_RATES 6 + +#define WLAN_PROBEREQ_OFF_SSID 0 + +#define WLAN_PROBERESP_OFF_TS 0 +#define WLAN_PROBERESP_OFF_BCN_INT 8 +#define WLAN_PROBERESP_OFF_CAP_INFO 10 +#define WLAN_PROBERESP_OFF_SSID 12 + +#define WLAN_AUTHEN_OFF_AUTH_ALG 0 +#define WLAN_AUTHEN_OFF_AUTH_SEQ 2 +#define WLAN_AUTHEN_OFF_STATUS 4 +#define WLAN_AUTHEN_OFF_CHALLENGE 6 + +#define WLAN_DEAUTHEN_OFF_REASON 0 + +enum { +IEEE16(WF_MGMT_CAP_ESS, 0x0001) +IEEE16(WF_MGMT_CAP_IBSS, 0x0002) +/* In (re)assoc request frames by STA: +** Pollable=0, PollReq=0: STA is not CF-Pollable +** 0 1: STA is CF-Pollable, not requesting to be placed on the CF-Polling list +** 1 0: STA is CF-Pollable, requesting to be placed on the CF-Polling list +** 1 1: STA is CF-Pollable, requesting never to be polled +** In beacon, proberesp, (re)assoc resp frames by AP: +** 0 0: No point coordinator at AP +** 0 1: Point coordinator at AP for delivery only (no polling) +** 1 0: Point coordinator at AP for delivery and polling +** 1 1: Reserved */ +IEEE16(WF_MGMT_CAP_CFPOLLABLE, 0x0004) +IEEE16(WF_MGMT_CAP_CFPOLLREQ, 0x0008) +/* 1=non-WEP data frames are disallowed */ +IEEE16(WF_MGMT_CAP_PRIVACY, 0x0010) +/* In beacon, proberesp, (re)assocresp by AP/AdHoc: +** 1=use of shortpre is allowed ("I can receive shortpre") */ +IEEE16(WF_MGMT_CAP_SHORT, 0x0020) +IEEE16(WF_MGMT_CAP_PBCC, 0x0040) +IEEE16(WF_MGMT_CAP_AGILITY, 0x0080) +/* In (re)assoc request frames by STA: +** 1=short slot time implemented and enabled +** NB: AP shall use long slot time beginning at the next Beacon after assoc +** of STA with this bit set to 0 +** In beacon, proberesp, (re)assoc resp frames by AP: +** currently used slot time value: 0/1 - long/short */ +IEEE16(WF_MGMT_CAP_SHORTSLOT, 0x0400) +/* In (re)assoc request frames by STA: 1=CCK-OFDM is implemented and enabled +** In beacon, proberesp, (re)assoc resp frames by AP/AdHoc: +** 1=CCK-OFDM is allowed */ +IEEE16(WF_MGMT_CAP_CCKOFDM, 0x2000) +}; + + +/*********************************************************************** +** Types +*/ + +/* Information Element types */ + +/* prototype structure, all IEs start with these members */ +typedef struct wlan_ie { + u8 eid; + u8 len; +} WLAN_PACKED wlan_ie_t; + +/*-- Service Set Identity (SSID) -----------------*/ +typedef struct wlan_ie_ssid { + u8 eid; + u8 len; + u8 ssid[1]; /* may be zero */ +} WLAN_PACKED wlan_ie_ssid_t; + +/*-- Supported Rates -----------------------------*/ +typedef struct wlan_ie_supp_rates { + u8 eid; + u8 len; + u8 rates[1]; /* had better be at LEAST one! */ +} WLAN_PACKED wlan_ie_supp_rates_t; + +/*-- FH Parameter Set ----------------------------*/ +typedef struct wlan_ie_fh_parms { + u8 eid; + u8 len; + u16 dwell; + u8 hopset; + u8 hoppattern; + u8 hopindex; +} WLAN_PACKED wlan_ie_fh_parms_t; + +/*-- DS Parameter Set ----------------------------*/ +typedef struct wlan_ie_ds_parms { + u8 eid; + u8 len; + u8 curr_ch; +} WLAN_PACKED wlan_ie_ds_parms_t; + +/*-- CF Parameter Set ----------------------------*/ +typedef struct wlan_ie_cf_parms { + u8 eid; + u8 len; + u8 cfp_cnt; + u8 cfp_period; + u16 cfp_maxdur; + u16 cfp_durremaining; +} WLAN_PACKED wlan_ie_cf_parms_t; + +/*-- TIM ------------------------------------------*/ +typedef struct wlan_ie_tim { + u8 eid; + u8 len; + u8 dtim_cnt; + u8 dtim_period; + u8 bitmap_ctl; + u8 virt_bm[1]; +} WLAN_PACKED wlan_ie_tim_t; + +/*-- IBSS Parameter Set ---------------------------*/ +typedef struct wlan_ie_ibss_parms { + u8 eid; + u8 len; + u16 atim_win; +} WLAN_PACKED wlan_ie_ibss_parms_t; + +/*-- Challenge Text ------------------------------*/ +typedef struct wlan_ie_challenge { + u8 eid; + u8 len; + u8 challenge[1]; +} WLAN_PACKED wlan_ie_challenge_t; + +/*-- ERP (42) -------------------------------------*/ +typedef struct wlan_ie_erp { + u8 eid; + u8 len; + /* bit 0:Non ERP present + ** 1:Use Protection + ** 2:Barker Preamble mode + ** 3-7:reserved */ + u8 erp; +} WLAN_PACKED wlan_ie_erp_t; + +/* Types for parsing mgmt frames */ + +/* prototype structure, all mgmt frame types will start with these members */ +typedef struct wlan_fr_mgmt { + u16 type; + u16 len; /* DOES NOT include FCS */ + wlan_hdr_t *hdr; + /* used for target specific data, skb in Linux */ + /*-- fixed fields -----------*/ + /*-- info elements ----------*/ +} WLAN_PACKED wlan_fr_mgmt_t; + +/*-- Beacon ---------------------------------------*/ +typedef struct wlan_fr_beacon { + u16 type; + u16 len; + wlan_hdr_t *hdr; + /*-- fixed fields -----------*/ + u64 *ts; + u16 *bcn_int; + u16 *cap_info; + /*-- info elements ----------*/ + wlan_ie_ssid_t *ssid; + wlan_ie_supp_rates_t *supp_rates; + wlan_ie_supp_rates_t *ext_rates; + wlan_ie_fh_parms_t *fh_parms; + wlan_ie_ds_parms_t *ds_parms; + wlan_ie_cf_parms_t *cf_parms; + wlan_ie_ibss_parms_t *ibss_parms; + wlan_ie_tim_t *tim; /* in beacon only, not proberesp */ + wlan_ie_erp_t *erp; /* in beacon only, not proberesp */ +} wlan_fr_beacon_t; +#define wlan_fr_proberesp wlan_fr_beacon +#define wlan_fr_proberesp_t wlan_fr_beacon_t + +/*-- IBSS ATIM ------------------------------------*/ +typedef struct wlan_fr_ibssatim { + u16 type; + u16 len; + wlan_hdr_t *hdr; + /*-- fixed fields -----------*/ + /*-- info elements ----------*/ + /* this frame type has a null body */ +} wlan_fr_ibssatim_t; + +/*-- Disassociation -------------------------------*/ +typedef struct wlan_fr_disassoc { + u16 type; + u16 len; + wlan_hdr_t *hdr; + /*-- fixed fields -----------*/ + u16 *reason; + /*-- info elements ----------*/ +} wlan_fr_disassoc_t; + +/*-- Association Request --------------------------*/ +typedef struct wlan_fr_assocreq { + u16 type; + u16 len; + wlan_hdr_t *hdr; + /*-- fixed fields -----------*/ + u16 *cap_info; + u16 *listen_int; + /*-- info elements ----------*/ + wlan_ie_ssid_t *ssid; + wlan_ie_supp_rates_t *supp_rates; + wlan_ie_supp_rates_t *ext_rates; +} wlan_fr_assocreq_t; + +/*-- Association Response -------------------------*/ +typedef struct wlan_fr_assocresp { + u16 type; + u16 len; + wlan_hdr_t *hdr; + /*-- fixed fields -----------*/ + u16 *cap_info; + u16 *status; + u16 *aid; + /*-- info elements ----------*/ + wlan_ie_supp_rates_t *supp_rates; + wlan_ie_supp_rates_t *ext_rates; +} wlan_fr_assocresp_t; + +/*-- Reassociation Request ------------------------*/ +typedef struct wlan_fr_reassocreq { + u16 type; + u16 len; + wlan_hdr_t *hdr; + /*-- fixed fields -----------*/ + u16 *cap_info; + u16 *listen_int; + u8 *curr_ap; + /*-- info elements ----------*/ + wlan_ie_ssid_t *ssid; + wlan_ie_supp_rates_t *supp_rates; + wlan_ie_supp_rates_t *ext_rates; +} wlan_fr_reassocreq_t; + +/*-- Reassociation Response -----------------------*/ +typedef struct wlan_fr_reassocresp { + u16 type; + u16 len; + wlan_hdr_t *hdr; + /*-- fixed fields -----------*/ + u16 *cap_info; + u16 *status; + u16 *aid; + /*-- info elements ----------*/ + wlan_ie_supp_rates_t *supp_rates; + wlan_ie_supp_rates_t *ext_rates; +} wlan_fr_reassocresp_t; + +/*-- Probe Request --------------------------------*/ +typedef struct wlan_fr_probereq { + u16 type; + u16 len; + wlan_hdr_t *hdr; + /*-- fixed fields -----------*/ + /*-- info elements ----------*/ + wlan_ie_ssid_t *ssid; + wlan_ie_supp_rates_t *supp_rates; + wlan_ie_supp_rates_t *ext_rates; +} wlan_fr_probereq_t; + +/*-- Authentication -------------------------------*/ +typedef struct wlan_fr_authen { + u16 type; + u16 len; + wlan_hdr_t *hdr; + /*-- fixed fields -----------*/ + u16 *auth_alg; + u16 *auth_seq; + u16 *status; + /*-- info elements ----------*/ + wlan_ie_challenge_t *challenge; +} wlan_fr_authen_t; + +/*-- Deauthenication -----------------------------*/ +typedef struct wlan_fr_deauthen { + u16 type; + u16 len; + wlan_hdr_t *hdr; + /*-- fixed fields -----------*/ + u16 *reason; + /*-- info elements ----------*/ +} wlan_fr_deauthen_t; + +/* Types for building mgmt frames */ + +/* Warning. Several types used in below structs are +** in fact variable length. Use structs with such fields with caution */ +typedef struct auth_frame_body { + u16 auth_alg; + u16 auth_seq; + u16 status; + wlan_ie_challenge_t challenge; +} WLAN_PACKED auth_frame_body_t; + +typedef struct assocresp_frame_body { + u16 cap_info; + u16 status; + u16 aid; + wlan_ie_supp_rates_t rates; +} WLAN_PACKED assocresp_frame_body_t; + +typedef struct reassocreq_frame_body { + u16 cap_info; + u16 listen_int; + u8 current_ap[ETH_ALEN]; + wlan_ie_ssid_t ssid; +/* access to this one is disabled since ssid_t is variable length: */ + /* wlan_ie_supp_rates_t rates; */ +} WLAN_PACKED reassocreq_frame_body_t; + +typedef struct reassocresp_frame_body { + u16 cap_info; + u16 status; + u16 aid; + wlan_ie_supp_rates_t rates; +} WLAN_PACKED reassocresp_frame_body_t; + +typedef struct deauthen_frame_body { + u16 reason; +} WLAN_PACKED deauthen_frame_body_t; + +typedef struct disassoc_frame_body { + u16 reason; +} WLAN_PACKED disassoc_frame_body_t; + +typedef struct probereq_frame_body { + wlan_ie_ssid_t ssid; + wlan_ie_supp_rates_t rates; +} WLAN_PACKED probereq_frame_body_t; + +typedef struct proberesp_frame_body { + u8 timestamp[8]; + u16 beacon_int; + u16 cap_info; + wlan_ie_ssid_t ssid; +/* access to these is disabled since ssid_t is variable length: */ + /* wlan_ie_supp_rates_t rates; */ + /* fhps_t fhps; */ + /* dsps_t dsps; */ + /* cfps_t cfps; */ +} WLAN_PACKED proberesp_frame_body_t; + + +/*********************************************************************** +** Functions +*/ + +/* Helpers for parsing mgmt frames */ +void wlan_mgmt_decode_ibssatim(wlan_fr_ibssatim_t *f); +void wlan_mgmt_decode_assocreq(wlan_fr_assocreq_t *f); +void wlan_mgmt_decode_assocresp(wlan_fr_assocresp_t *f); +void wlan_mgmt_decode_authen(wlan_fr_authen_t *f); +void wlan_mgmt_decode_beacon(wlan_fr_beacon_t *f); +void wlan_mgmt_decode_deauthen(wlan_fr_deauthen_t *f); +void wlan_mgmt_decode_disassoc(wlan_fr_disassoc_t *f); +void wlan_mgmt_decode_probereq(wlan_fr_probereq_t *f); +void wlan_mgmt_decode_proberesp(wlan_fr_proberesp_t *f); +void wlan_mgmt_decode_reassocreq(wlan_fr_reassocreq_t *f); +void wlan_mgmt_decode_reassocresp(wlan_fr_reassocresp_t *f); + +/* Helpers for building mgmt frames */ +static inline u8* +wlan_fill_ie_ssid(u8 *p, int len, const char *ssid) +{ + struct wlan_ie_ssid *ie = (void*)p; + ie->eid = WLAN_EID_SSID; + ie->len = len; + memcpy(ie->ssid, ssid, len); + return p + len + 2; +} +/* This controls whether we create 802.11g 'ext supported rates' IEs +** or just create overlong 'supported rates' IEs instead +** (non-11g compliant) */ +#define WE_OBEY_802_11G 1 +static inline u8* +wlan_fill_ie_rates(u8 *p, int len, const u8 *rates) +{ + struct wlan_ie_supp_rates *ie = (void*)p; +#if WE_OBEY_802_11G + if (len > 8 ) len = 8; +#endif + /* supported rates (1 to 8 octets) */ + ie->eid = WLAN_EID_SUPP_RATES; + ie->len = len; + memcpy(ie->rates, rates, len); + return p + len + 2; +} +/* This one wouldn't create an IE at all if not needed */ +static inline u8* +wlan_fill_ie_rates_ext(u8 *p, int len, const u8 *rates) +{ + struct wlan_ie_supp_rates *ie = (void*)p; +#if !WE_OBEY_802_11G + return p; +#endif + len -= 8; + if (len <= 0) return p; + /* ext supported rates */ + ie->eid = WLAN_EID_EXT_RATES; + ie->len = len; + memcpy(ie->rates, rates+8, len); + return p + len + 2; +} +static inline u8* +wlan_fill_ie_ds_parms(u8 *p, int channel) +{ + struct wlan_ie_ds_parms *ie = (void*)p; + ie->eid = WLAN_EID_DS_PARMS; + ie->len = 1; + ie->curr_ch = channel; + return p + sizeof(*ie); +} +static inline u8* +wlan_fill_ie_ibss_parms(u8 *p, int atim_win) +{ + struct wlan_ie_ibss_parms *ie = (void*)p; + ie->eid = WLAN_EID_IBSS_PARMS; + ie->len = 2; + ie->atim_win = atim_win; + return p + sizeof(*ie); +} +static inline u8* +wlan_fill_ie_tim(u8 *p, int rem, int period, int bcast, + int ofs, int len, const u8 *vbm) +{ + struct wlan_ie_tim *ie = (void*)p; + ie->eid = WLAN_EID_TIM; + ie->len = len + 3; + ie->dtim_cnt = rem; + ie->dtim_period = period; + ie->bitmap_ctl = ofs | (bcast!=0); + if (vbm) + memcpy(ie->virt_bm, vbm, len); /* min 1 byte */ + else + ie->virt_bm[0] = 0; + return p + len + 3 + 2; +} --- linux-2.6.27.orig/ubuntu/misc/wireless/acx/acx.h +++ linux-2.6.27/ubuntu/misc/wireless/acx/acx.h @@ -0,0 +1,6 @@ +#include "acx_config.h" +#include "wlan_compat.h" +#include "wlan_hdr.h" +#include "wlan_mgmt.h" +#include "acx_struct.h" +#include "acx_func.h" --- linux-2.6.27.orig/ubuntu/misc/wireless/acx/wlan_compat.h +++ linux-2.6.27/ubuntu/misc/wireless/acx/wlan_compat.h @@ -0,0 +1,264 @@ +/*********************************************************************** +** Copyright (C) 2003 ACX100 Open Source Project +** +** The contents of this file are subject to the Mozilla Public +** License Version 1.1 (the "License"); you may not use this file +** except in compliance with the License. You may obtain a copy of +** the License at http://www.mozilla.org/MPL/ +** +** Software distributed under the License is distributed on an "AS +** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +** implied. See the License for the specific language governing +** rights and limitations under the License. +** +** Alternatively, the contents of this file may be used under the +** terms of the GNU Public License version 2 (the "GPL"), in which +** case the provisions of the GPL are applicable instead of the +** above. If you wish to allow the use of your version of this file +** only under the terms of the GPL and not to allow others to use +** your version of this file under the MPL, indicate your decision +** by deleting the provisions above and replace them with the notice +** and other provisions required by the GPL. If you do not delete +** the provisions above, a recipient may use your version of this +** file under either the MPL or the GPL. +** --------------------------------------------------------------------- +** Inquiries regarding the ACX100 Open Source Project can be +** made directly to: +** +** acx100-users@lists.sf.net +** http://acx100.sf.net +** --------------------------------------------------------------------- +*/ + +/*********************************************************************** +** This code is based on elements which are +** Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +** info@linux-wlan.com +** http://www.linux-wlan.com +*/ + +/*=============================================================*/ +/*------ Establish Platform Identity --------------------------*/ +/*=============================================================*/ +/* Key macros: */ +/* WLAN_CPU_FAMILY */ +#define WLAN_Ix86 1 +#define WLAN_PPC 2 +#define WLAN_Ix96 3 +#define WLAN_ARM 4 +#define WLAN_ALPHA 5 +#define WLAN_MIPS 6 +#define WLAN_HPPA 7 +#define WLAN_SPARC 8 +#define WLAN_SH 9 +#define WLAN_x86_64 10 +#define WLAN_IA64 11 +/* WLAN_CPU_CORE */ +#define WLAN_I386CORE 1 +#define WLAN_PPCCORE 2 +#define WLAN_I296 3 +#define WLAN_ARMCORE 4 +#define WLAN_ALPHACORE 5 +#define WLAN_MIPSCORE 6 +#define WLAN_HPPACORE 7 +/* WLAN_CPU_PART */ +#define WLAN_I386PART 1 +#define WLAN_MPC860 2 +#define WLAN_MPC823 3 +#define WLAN_I296SA 4 +#define WLAN_PPCPART 5 +#define WLAN_ARMPART 6 +#define WLAN_ALPHAPART 7 +#define WLAN_MIPSPART 8 +#define WLAN_HPPAPART 9 +/* WLAN_SYSARCH */ +#define WLAN_PCAT 1 +#define WLAN_MBX 2 +#define WLAN_RPX 3 +#define WLAN_LWARCH 4 +#define WLAN_PMAC 5 +#define WLAN_SKIFF 6 +#define WLAN_BITSY 7 +#define WLAN_ALPHAARCH 7 +#define WLAN_MIPSARCH 9 +#define WLAN_HPPAARCH 10 +/* WLAN_HOSTIF (generally set on the command line, not detected) */ +#define WLAN_PCMCIA 1 +#define WLAN_ISA 2 +#define WLAN_PCI 3 +#define WLAN_USB 4 +#define WLAN_PLX 5 + +/* Note: the PLX HOSTIF above refers to some vendors implementations for */ +/* PCI. It's a PLX chip that is a PCI to PCMCIA adapter, but it */ +/* isn't a real PCMCIA host interface adapter providing all the */ +/* card&socket services. */ + +#ifdef __powerpc__ +#ifndef __ppc__ +#define __ppc__ +#endif +#endif + +#if (defined(CONFIG_PPC) || defined(CONFIG_8xx)) +#ifndef __ppc__ +#define __ppc__ +#endif +#endif + +#if defined(__x86_64__) + #define WLAN_CPU_FAMILY WLAN_x86_64 + #define WLAN_SYSARCH WLAN_PCAT +#elif defined (__ia64__) + #define WLAN_CPU_FAMILY WLAN_IA64 + #define WLAN_SYSARCH WLAN_PCAT +#elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) + #define WLAN_CPU_FAMILY WLAN_Ix86 + #define WLAN_CPU_CORE WLAN_I386CORE + #define WLAN_CPU_PART WLAN_I386PART + #define WLAN_SYSARCH WLAN_PCAT +#elif defined(__ppc__) + #define WLAN_CPU_FAMILY WLAN_PPC + #define WLAN_CPU_CORE WLAN_PPCCORE + #if defined(CONFIG_MBX) + #define WLAN_CPU_PART WLAN_MPC860 + #define WLAN_SYSARCH WLAN_MBX + #elif defined(CONFIG_RPXLITE) + #define WLAN_CPU_PART WLAN_MPC823 + #define WLAN_SYSARCH WLAN_RPX + #elif defined(CONFIG_RPXCLASSIC) + #define WLAN_CPU_PART WLAN_MPC860 + #define WLAN_SYSARCH WLAN_RPX + #else + #define WLAN_CPU_PART WLAN_PPCPART + #define WLAN_SYSARCH WLAN_PMAC + #endif +#elif defined(__arm__) + #define WLAN_CPU_FAMILY WLAN_ARM + #define WLAN_CPU_CORE WLAN_ARMCORE + #define WLAN_CPU_PART WLAN_ARM_PART + #define WLAN_SYSARCH WLAN_SKIFF +#elif defined(__alpha__) + #define WLAN_CPU_FAMILY WLAN_ALPHA + #define WLAN_CPU_CORE WLAN_ALPHACORE + #define WLAN_CPU_PART WLAN_ALPHAPART + #define WLAN_SYSARCH WLAN_ALPHAARCH +#elif defined(__mips__) + #define WLAN_CPU_FAMILY WLAN_MIPS + #define WLAN_CPU_CORE WLAN_MIPSCORE + #define WLAN_CPU_PART WLAN_MIPSPART + #define WLAN_SYSARCH WLAN_MIPSARCH +#elif defined(__hppa__) + #define WLAN_CPU_FAMILY WLAN_HPPA + #define WLAN_CPU_CORE WLAN_HPPACORE + #define WLAN_CPU_PART WLAN_HPPAPART + #define WLAN_SYSARCH WLAN_HPPAARCH +#elif defined(__sparc__) + #define WLAN_CPU_FAMILY WLAN_SPARC + #define WLAN_SYSARCH WLAN_SPARC +#elif defined(__sh__) + #define WLAN_CPU_FAMILY WLAN_SH + #define WLAN_SYSARCH WLAN_SHARCH + #ifndef __LITTLE_ENDIAN__ + #define __LITTLE_ENDIAN__ + #endif +#else + #error "No CPU identified!" +#endif + +/* + Some big endian machines implicitly do all I/O in little endian mode. + + In particular: + Linux/PPC on PowerMacs (PCI) + Arm/Intel Xscale (PCI) + + This may also affect PLX boards and other BE &| PPC platforms; + as new ones are discovered, add them below. +*/ + +#if ((WLAN_SYSARCH == WLAN_SKIFF) || (WLAN_SYSARCH == WLAN_PMAC)) +#define REVERSE_ENDIAN +#endif + +/*=============================================================*/ +/*------ Hardware Portability Macros --------------------------*/ +/*=============================================================*/ +#if (WLAN_CPU_FAMILY == WLAN_PPC) +#define wlan_inw(a) in_be16((unsigned short *)((a)+_IO_BASE)) +#define wlan_inw_le16_to_cpu(a) inw((a)) +#define wlan_outw(v,a) out_be16((unsigned short *)((a)+_IO_BASE), (v)) +#define wlan_outw_cpu_to_le16(v,a) outw((v),(a)) +#else +#define wlan_inw(a) inw((a)) +#define wlan_inw_le16_to_cpu(a) __cpu_to_le16(inw((a))) +#define wlan_outw(v,a) outw((v),(a)) +#define wlan_outw_cpu_to_le16(v,a) outw(__cpu_to_le16((v)),(a)) +#endif + +/*=============================================================*/ +/*------ Bit settings -----------------------------------------*/ +/*=============================================================*/ +#define ieee2host16(n) __le16_to_cpu(n) +#define ieee2host32(n) __le32_to_cpu(n) +#define host2ieee16(n) __cpu_to_le16(n) +#define host2ieee32(n) __cpu_to_le32(n) + +/* for constants */ +#ifdef __LITTLE_ENDIAN + #define IEEE16(a,n) a = n, a##i = n, +#else + #ifdef __BIG_ENDIAN + /* shifts would produce gcc warnings. Oh well... */ + #define IEEE16(a,n) a = n, a##i = ((n&0xff)*256 + ((n&0xff00)/256)), + #else + #error give me endianness or give me death + #endif +#endif + +/*=============================================================*/ +/*------ Compiler Portability Macros --------------------------*/ +/*=============================================================*/ +#define WLAN_PACKED __attribute__ ((packed)) + +/* Interrupt handler backwards compatibility stuff */ +#ifndef IRQ_NONE +#define IRQ_NONE +#define IRQ_HANDLED +typedef void irqreturn_t; +#endif + +#ifndef ARPHRD_IEEE80211_PRISM +#define ARPHRD_IEEE80211_PRISM 802 +#endif + +#define ETH_P_80211_RAW (ETH_P_ECONET + 1) + +/*============================================================================* + * Constants * + *============================================================================*/ +#define WLAN_IEEE_OUI_LEN 3 + +/*============================================================================* + * Types * + *============================================================================*/ + +/* local ether header type */ +typedef struct wlan_ethhdr { + u8 daddr[ETH_ALEN]; + u8 saddr[ETH_ALEN]; + u16 type; +} WLAN_PACKED wlan_ethhdr_t; + +/* local llc header type */ +typedef struct wlan_llc { + u8 dsap; + u8 ssap; + u8 ctl; +} WLAN_PACKED wlan_llc_t; + +/* local snap header type */ +typedef struct wlan_snap { + u8 oui[WLAN_IEEE_OUI_LEN]; + u16 type; +} WLAN_PACKED wlan_snap_t; --- linux-2.6.27.orig/ubuntu/misc/wireless/acx/common.c +++ linux-2.6.27/ubuntu/misc/wireless/acx/common.c @@ -0,0 +1,7220 @@ +/*********************************************************************** +** Copyright (C) 2003 ACX100 Open Source Project +** +** The contents of this file are subject to the Mozilla Public +** License Version 1.1 (the "License"); you may not use this file +** except in compliance with the License. You may obtain a copy of +** the License at http://www.mozilla.org/MPL/ +** +** Software distributed under the License is distributed on an "AS +** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +** implied. See the License for the specific language governing +** rights and limitations under the License. +** +** Alternatively, the contents of this file may be used under the +** terms of the GNU Public License version 2 (the "GPL"), in which +** case the provisions of the GPL are applicable instead of the +** above. If you wish to allow the use of your version of this file +** only under the terms of the GPL and not to allow others to use +** your version of this file under the MPL, indicate your decision +** by deleting the provisions above and replace them with the notice +** and other provisions required by the GPL. If you do not delete +** the provisions above, a recipient may use your version of this +** file under either the MPL or the GPL. +** --------------------------------------------------------------------- +** Inquiries regarding the ACX100 Open Source Project can be +** made directly to: +** +** acx100-users@lists.sf.net +** http://acx100.sf.net +** --------------------------------------------------------------------- +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acx.h" + + +/*********************************************************************** +*/ +static client_t *acx_l_sta_list_alloc(acx_device_t *adev); +static client_t *acx_l_sta_list_get_from_hash(acx_device_t *adev, const u8 *address); + +static int acx_l_process_data_frame_master(acx_device_t *adev, rxbuffer_t *rxbuf); +static int acx_l_process_data_frame_client(acx_device_t *adev, rxbuffer_t *rxbuf); +/* static int acx_l_process_NULL_frame(acx_device_t *adev, rxbuffer_t *rxbuf, int vala); */ +static int acx_l_process_mgmt_frame(acx_device_t *adev, rxbuffer_t *rxbuf); +static void acx_l_process_disassoc_from_sta(acx_device_t *adev, const wlan_fr_disassoc_t *req); +static void acx_l_process_disassoc_from_ap(acx_device_t *adev, const wlan_fr_disassoc_t *req); +static void acx_l_process_deauth_from_sta(acx_device_t *adev, const wlan_fr_deauthen_t *req); +static void acx_l_process_deauth_from_ap(acx_device_t *adev, const wlan_fr_deauthen_t *req); +static int acx_l_process_probe_response(acx_device_t *adev, wlan_fr_proberesp_t *req, const rxbuffer_t *rxbuf); +static int acx_l_process_assocresp(acx_device_t *adev, const wlan_fr_assocresp_t *req); +static int acx_l_process_reassocresp(acx_device_t *adev, const wlan_fr_reassocresp_t *req); +static int acx_l_process_authen(acx_device_t *adev, const wlan_fr_authen_t *req); +static int acx_l_transmit_assocresp(acx_device_t *adev, const wlan_fr_assocreq_t *req); +static int acx_l_transmit_reassocresp(acx_device_t *adev, const wlan_fr_reassocreq_t *req); +static int acx_l_transmit_deauthen(acx_device_t *adev, const u8 *addr, u16 reason); +static int acx_l_transmit_authen1(acx_device_t *adev); +static int acx_l_transmit_authen2(acx_device_t *adev, const wlan_fr_authen_t *req, client_t *clt); +static int acx_l_transmit_authen3(acx_device_t *adev, const wlan_fr_authen_t *req); +static int acx_l_transmit_authen4(acx_device_t *adev, const wlan_fr_authen_t *req); +static int acx_l_transmit_assoc_req(acx_device_t *adev); + + +/*********************************************************************** +*/ +#if ACX_DEBUG +unsigned int acx_debug = ACX_DEFAULT_MSG; +#endif + +char firmware_ver[33] = "default"; +module_param_string(firmware_ver, firmware_ver, sizeof(firmware_ver), 0444); +MODULE_PARM_DESC(firmware_ver, "Alternate firmware version."); + +#if ACX_DEBUG +module_param_named(debug, acx_debug, uint, 0); +#endif + +#if ACX_DEBUG +MODULE_PARM_DESC(debug, "Debug level mask (see L_xxx constants)"); +#endif + +#ifdef MODULE_LICENSE +MODULE_LICENSE("Dual MPL/GPL"); +#endif +/* USB had this: MODULE_AUTHOR("Martin Wawro "); */ +MODULE_AUTHOR("ACX100 Open Source Driver development team"); +MODULE_DESCRIPTION("Driver for TI ACX1xx based wireless cards (CardBus/PCI/USB)"); + + +/*********************************************************************** +*/ +/* Probably a number of acx's intermediate buffers for USB transfers, +** not to be confused with number of descriptors in tx/rx rings +** (which are not directly accessible to host in USB devices) */ +#define USB_RX_CNT 10 +#define USB_TX_CNT 10 + + +/*********************************************************************** +*/ + +/* minutes to wait until next radio recalibration: */ +#define RECALIB_PAUSE 5 + +/* Please keep acx_reg_domain_ids_len in sync... */ +const u8 acx_reg_domain_ids[acx_reg_domain_ids_len] = + { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40, 0x41, 0x51 }; +static const u16 reg_domain_channel_masks[acx_reg_domain_ids_len] = + { 0x07ff, 0x07ff, 0x1fff, 0x0600, 0x1e00, 0x2000, 0x3fff, 0x01fc }; +const char * const +acx_reg_domain_strings[] = { + /* 0 */ " 1-11 FCC (USA)", + /* 1 */ " 1-11 DOC/IC (Canada)", +/* BTW: WLAN use in ETSI is regulated by ETSI standard EN 300 328-2 V1.1.2 */ + /* 2 */ " 1-13 ETSI (Europe)", + /* 3 */ "10-11 Spain", + /* 4 */ "10-13 France", + /* 5 */ " 14 MKK (Japan)", + /* 6 */ " 1-14 MKK1", + /* 7 */ " 3-9 Israel (not all firmware versions)", + NULL /* needs to remain as last entry */ +}; + + + +/*********************************************************************** +** Debugging support +*/ +#ifdef PARANOID_LOCKING +static unsigned max_lock_time; +static unsigned max_sem_time; + +void +acx_lock_unhold() { max_lock_time = 0; } +void +acx_sem_unhold() { max_sem_time = 0; } + +static inline const char* +sanitize_str(const char *s) +{ + const char* t = strrchr(s, '/'); + if (t) return t + 1; + return s; +} + +void +acx_lock_debug(acx_device_t *adev, const char* where) +{ + unsigned int count = 100*1000*1000; + where = sanitize_str(where); + while (--count) { + if (!spin_is_locked(&adev->lock)) break; + cpu_relax(); + } + if (!count) { + printk(KERN_EMERG "LOCKUP: already taken at %s!\n", adev->last_lock); + BUG(); + } + adev->last_lock = where; + rdtscl(adev->lock_time); +} +void +acx_unlock_debug(acx_device_t *adev, const char* where) +{ +#ifdef SMP + if (!spin_is_locked(&adev->lock)) { + where = sanitize_str(where); + printk(KERN_EMERG "STRAY UNLOCK at %s!\n", where); + BUG(); + } +#endif + if (acx_debug & L_LOCK) { + unsigned long diff; + rdtscl(diff); + diff -= adev->lock_time; + if (diff > max_lock_time) { + where = sanitize_str(where); + printk("max lock hold time %ld CPU ticks from %s " + "to %s\n", diff, adev->last_lock, where); + max_lock_time = diff; + } + } +} +void +acx_down_debug(acx_device_t *adev, const char* where) +{ + int sem_count; + unsigned long timeout = jiffies + 5*HZ; + + where = sanitize_str(where); + + for (;;) { + sem_count = atomic_read(&adev->sem.count); + if (sem_count) break; + if (time_after(jiffies, timeout)) + break; + msleep(5); + } + if (!sem_count) { + printk(KERN_EMERG "D STATE at %s! last sem at %s\n", + where, adev->last_sem); + dump_stack(); + } + adev->last_sem = where; + adev->sem_time = jiffies; + down(&adev->sem); + if (acx_debug & L_LOCK) { + printk("%s: sem_down %d -> %d\n", + where, sem_count, atomic_read(&adev->sem.count)); + } +} +void +acx_up_debug(acx_device_t *adev, const char* where) +{ + int sem_count = atomic_read(&adev->sem.count); + if (sem_count) { + where = sanitize_str(where); + printk(KERN_EMERG "STRAY UP at %s! sem.count=%d\n", where, sem_count); + dump_stack(); + } + if (acx_debug & L_LOCK) { + unsigned long diff = jiffies - adev->sem_time; + if (diff > max_sem_time) { + where = sanitize_str(where); + printk("max sem hold time %ld jiffies from %s " + "to %s\n", diff, adev->last_sem, where); + max_sem_time = diff; + } + } + up(&adev->sem); + if (acx_debug & L_LOCK) { + where = sanitize_str(where); + printk("%s: sem_up %d -> %d\n", + where, sem_count, atomic_read(&adev->sem.count)); + } +} +#endif /* PARANOID_LOCKING */ + + +/*********************************************************************** +*/ +#if ACX_DEBUG > 1 + +static int acx_debug_func_indent; +#define DEBUG_TSC 0 +#define FUNC_INDENT_INCREMENT 2 + +#if DEBUG_TSC +#define TIMESTAMP(d) unsigned long d; rdtscl(d) +#else +#define TIMESTAMP(d) unsigned long d = jiffies +#endif + +static const char +spaces[] = " " " "; /* Nx10 spaces */ + +void +log_fn_enter(const char *funcname) +{ + int indent; + TIMESTAMP(d); + + indent = acx_debug_func_indent; + if (indent >= sizeof(spaces)) + indent = sizeof(spaces)-1; + + printk("%08ld %s==> %s\n", + d % 100000000, + spaces + (sizeof(spaces)-1) - indent, + funcname + ); + + acx_debug_func_indent += FUNC_INDENT_INCREMENT; +} +void +log_fn_exit(const char *funcname) +{ + int indent; + TIMESTAMP(d); + + acx_debug_func_indent -= FUNC_INDENT_INCREMENT; + + indent = acx_debug_func_indent; + if (indent >= sizeof(spaces)) + indent = sizeof(spaces)-1; + + printk("%08ld %s<== %s\n", + d % 100000000, + spaces + (sizeof(spaces)-1) - indent, + funcname + ); +} +void +log_fn_exit_v(const char *funcname, int v) +{ + int indent; + TIMESTAMP(d); + + acx_debug_func_indent -= FUNC_INDENT_INCREMENT; + + indent = acx_debug_func_indent; + if (indent >= sizeof(spaces)) + indent = sizeof(spaces)-1; + + printk("%08ld %s<== %s: %08X\n", + d % 100000000, + spaces + (sizeof(spaces)-1) - indent, + funcname, + v + ); +} +#endif /* ACX_DEBUG > 1 */ + + +/*********************************************************************** +** Basically a msleep with logging +*/ +void +acx_s_msleep(int ms) +{ + FN_ENTER; + msleep(ms); + FN_EXIT0; +} + + +/*********************************************************************** +** Not inlined: it's larger than it seems +*/ +void +acx_print_mac(const char *head, const u8 *mac, const char *tail) +{ + printk("%s"MACSTR"%s", head, MAC(mac), tail); +} + + +/*********************************************************************** +** acx_get_status_name +*/ +static const char* +acx_get_status_name(u16 status) +{ + static const char * const str[] = { + "STOPPED", "SCANNING", "WAIT_AUTH", + "AUTHENTICATED", "ASSOCIATED", "INVALID??" + }; + if (status > VEC_SIZE(str)-1) + status = VEC_SIZE(str)-1; + + return str[status]; +} + + +/*********************************************************************** +** acx_get_packet_type_string +*/ +#if ACX_DEBUG +const char* +acx_get_packet_type_string(u16 fc) +{ + static const char * const mgmt_arr[] = { + "MGMT/AssocReq", "MGMT/AssocResp", "MGMT/ReassocReq", + "MGMT/ReassocResp", "MGMT/ProbeReq", "MGMT/ProbeResp", + "MGMT/UNKNOWN", "MGMT/UNKNOWN", "MGMT/Beacon", "MGMT/ATIM", + "MGMT/Disassoc", "MGMT/Authen", "MGMT/Deauthen" + }; + static const char * const ctl_arr[] = { + "CTL/PSPoll", "CTL/RTS", "CTL/CTS", "CTL/Ack", "CTL/CFEnd", + "CTL/CFEndCFAck" + }; + static const char * const data_arr[] = { + "DATA/DataOnly", "DATA/Data CFAck", "DATA/Data CFPoll", + "DATA/Data CFAck/CFPoll", "DATA/Null", "DATA/CFAck", + "DATA/CFPoll", "DATA/CFAck/CFPoll" + }; + const char *str; + u8 fstype = (WF_FC_FSTYPE & fc) >> 4; + u8 ctl; + + switch (WF_FC_FTYPE & fc) { + case WF_FTYPE_MGMT: + if (fstype < VEC_SIZE(mgmt_arr)) + str = mgmt_arr[fstype]; + else + str = "MGMT/UNKNOWN"; + break; + case WF_FTYPE_CTL: + ctl = fstype - 0x0a; + if (ctl < VEC_SIZE(ctl_arr)) + str = ctl_arr[ctl]; + else + str = "CTL/UNKNOWN"; + break; + case WF_FTYPE_DATA: + if (fstype < VEC_SIZE(data_arr)) + str = data_arr[fstype]; + else + str = "DATA/UNKNOWN"; + break; + default: + str = "UNKNOWN"; + break; + } + return str; +} +#endif + + +/*********************************************************************** +** acx_wlan_reason_str +*/ +static inline const char* +acx_wlan_reason_str(u16 reason) +{ + static const char* const reason_str[] = { + /* 0 */ "?", + /* 1 */ "unspecified", + /* 2 */ "prev auth is not valid", + /* 3 */ "leaving BBS", + /* 4 */ "due to inactivity", + /* 5 */ "AP is busy", + /* 6 */ "got class 2 frame from non-auth'ed STA", + /* 7 */ "got class 3 frame from non-assoc'ed STA", + /* 8 */ "STA has left BSS", + /* 9 */ "assoc without auth is not allowed", + /* 10 */ "bad power setting (802.11h)", + /* 11 */ "bad channel (802.11i)", + /* 12 */ "?", + /* 13 */ "invalid IE", + /* 14 */ "MIC failure", + /* 15 */ "four-way handshake timeout", + /* 16 */ "group key handshake timeout", + /* 17 */ "IE is different", + /* 18 */ "invalid group cipher", + /* 19 */ "invalid pairwise cipher", + /* 20 */ "invalid AKMP", + /* 21 */ "unsupported RSN version", + /* 22 */ "invalid RSN IE cap", + /* 23 */ "802.1x failed", + /* 24 */ "cipher suite rejected" + }; + return reason < VEC_SIZE(reason_str) ? reason_str[reason] : "?"; +} + + +/*********************************************************************** +** acx_cmd_status_str +*/ +const char* +acx_cmd_status_str(unsigned int state) +{ + static const char * const cmd_error_strings[] = { + "Idle", + "Success", + "Unknown Command", + "Invalid Information Element", + "Channel rejected", + "Channel invalid in current regulatory domain", + "MAC invalid", + "Command rejected (read-only information element)", + "Command rejected", + "Already asleep", + "TX in progress", + "Already awake", + "Write only", + "RX in progress", + "Invalid parameter", + "Scan in progress", + "Failed" + }; + return state < VEC_SIZE(cmd_error_strings) ? + cmd_error_strings[state] : "?"; +} + + +/*********************************************************************** +** get_status_string +*/ +static inline const char* +get_status_string(unsigned int status) +{ + /* A bit shortened, but hopefully still understandable */ + static const char * const status_str[] = { + /* 0 */ "Successful", + /* 1 */ "Unspecified failure", + /* 2 */ "reserved", + /* 3 */ "reserved", + /* 4 */ "reserved", + /* 5 */ "reserved", + /* 6 */ "reserved", + /* 7 */ "reserved", + /* 8 */ "reserved", + /* 9 */ "reserved", + /*10 */ "Cannot support all requested capabilities in Capability Information field", + /*11 */ "Reassoc denied (reason outside of 802.11b scope)", + /*12 */ "Assoc denied (reason outside of 802.11b scope) -- maybe MAC filtering by peer?", + /*13 */ "Responding station doesnt support specified auth algorithm -- maybe WEP auth Open vs. Restricted?", + /*14 */ "Auth rejected: wrong transaction sequence number", + /*15 */ "Auth rejected: challenge failure", + /*16 */ "Auth rejected: timeout for next frame in sequence", + /*17 */ "Assoc denied: too many STAs on this AP", + /*18 */ "Assoc denied: requesting STA doesnt support all data rates in basic set", + /*19 */ "Assoc denied: requesting STA doesnt support Short Preamble", + /*20 */ "Assoc denied: requesting STA doesnt support PBCC Modulation", + /*21 */ "Assoc denied: requesting STA doesnt support Channel Agility" + /*22 */ "reserved", + /*23 */ "reserved", + /*24 */ "reserved", + /*25 */ "Assoc denied: requesting STA doesnt support Short Slot Time", + /*26 */ "Assoc denied: requesting STA doesnt support DSSS-OFDM" + }; + + return status_str[status < VEC_SIZE(status_str) ? status : 2]; +} + + +/*********************************************************************** +*/ +void +acx_log_bad_eid(wlan_hdr_t* hdr, int len, wlan_ie_t* ie_ptr) +{ + if (acx_debug & L_ASSOC) { + int offset = (u8*)ie_ptr - (u8*)hdr; + printk("acx: unknown EID %d in mgmt frame at offset %d. IE: ", + ie_ptr->eid, offset); + /* IE len can be bogus, IE can extend past packet end. Oh well... */ + acx_dump_bytes(ie_ptr, ie_ptr->len + 2); + if (acx_debug & L_DATA) { + printk("frame (%s): ", + acx_get_packet_type_string(le16_to_cpu(hdr->fc))); + acx_dump_bytes(hdr, len); + } + } +} + + +/*********************************************************************** +*/ +#if ACX_DEBUG +void +acx_dump_bytes(const void *data, int num) +{ + const u8* ptr = (const u8*)data; + + if (num <= 0) { + printk("\n"); + return; + } + + while (num >= 16) { + printk( "%02X %02X %02X %02X %02X %02X %02X %02X " + "%02X %02X %02X %02X %02X %02X %02X %02X\n", + ptr[0], ptr[1], ptr[2], ptr[3], + ptr[4], ptr[5], ptr[6], ptr[7], + ptr[8], ptr[9], ptr[10], ptr[11], + ptr[12], ptr[13], ptr[14], ptr[15]); + num -= 16; + ptr += 16; + } + if (num > 0) { + while (--num > 0) + printk("%02X ", *ptr++); + printk("%02X\n", *ptr); + } +} +#endif + + +/*********************************************************************** +** acx_s_get_firmware_version +*/ +void +acx_s_get_firmware_version(acx_device_t *adev) +{ + fw_ver_t fw; + u8 hexarr[4] = { 0, 0, 0, 0 }; + int hexidx = 0, val = 0; + const char *num; + char c; + + FN_ENTER; + + memset(fw.fw_id, 'E', FW_ID_SIZE); + acx_s_interrogate(adev, &fw, ACX1xx_IE_FWREV); + memcpy(adev->firmware_version, fw.fw_id, FW_ID_SIZE); + adev->firmware_version[FW_ID_SIZE] = '\0'; + + log(L_DEBUG, "fw_ver: fw_id='%s' hw_id=%08X\n", + adev->firmware_version, fw.hw_id); + + if (strncmp(fw.fw_id, "Rev ", 4) != 0) { + printk("acx: strange firmware version string " + "'%s', please report\n", adev->firmware_version); + adev->firmware_numver = 0x01090407; /* assume 1.9.4.7 */ + } else { + num = &fw.fw_id[4]; + while (1) { + c = *num++; + if ((c == '.') || (c == '\0')) { + hexarr[hexidx++] = val; + if ((hexidx > 3) || (c == '\0')) /* end? */ + break; + val = 0; + continue; + } + if ((c >= '0') && (c <= '9')) + c -= '0'; + else + c = c - 'a' + (char)10; + val = val*16 + c; + } + + adev->firmware_numver = (u32)( + (hexarr[0] << 24) | (hexarr[1] << 16) + | (hexarr[2] << 8) | hexarr[3]); + log(L_DEBUG, "firmware_numver 0x%08X\n", adev->firmware_numver); + } + if (IS_ACX111(adev)) { + if (adev->firmware_numver == 0x00010011) { + /* This one does not survive floodpinging */ + printk("acx: firmware '%s' is known to be buggy, " + "please upgrade\n", adev->firmware_version); + } + } + + adev->firmware_id = le32_to_cpu(fw.hw_id); + + /* we're able to find out more detailed chip names now */ + switch (adev->firmware_id & 0xffff0000) { + case 0x01010000: + case 0x01020000: + adev->chip_name = "TNETW1100A"; + break; + case 0x01030000: + adev->chip_name = "TNETW1100B"; + break; + case 0x03000000: + case 0x03010000: + adev->chip_name = "TNETW1130"; + break; + case 0x04030000: /* 0x04030101 is TNETW1450 */ + adev->chip_name = "TNETW1450"; + break; + default: + printk("acx: unknown chip ID 0x%08X, " + "please report\n", adev->firmware_id); + break; + } + + FN_EXIT0; +} + + +/*********************************************************************** +** acx_display_hardware_details +** +** Displays hw/fw version, radio type etc... +*/ +void +acx_display_hardware_details(acx_device_t *adev) +{ + const char *radio_str, *form_str; + + FN_ENTER; + + switch (adev->radio_type) { + case RADIO_MAXIM_0D: + radio_str = "Maxim"; + break; + case RADIO_RFMD_11: + radio_str = "RFMD"; + break; + case RADIO_RALINK_15: + radio_str = "Ralink"; + break; + case RADIO_RADIA_16: + radio_str = "Radia"; + break; + case RADIO_UNKNOWN_17: + /* TI seems to have a radio which is + * additionally 802.11a capable, too */ + radio_str = "802.11a/b/g radio?! Please report"; + break; + case RADIO_UNKNOWN_19: + radio_str = "A radio used by Safecom cards?! Please report"; + break; + case RADIO_UNKNOWN_1B: + radio_str = "An unknown radio used by TNETW1450 USB adapters"; + break; + default: + radio_str = "UNKNOWN, please report radio type name!"; + break; + } + + switch (adev->form_factor) { + case 0x00: + form_str = "unspecified"; + break; + case 0x01: + form_str = "(mini-)PCI / CardBus"; + break; + case 0x02: + form_str = "USB"; + break; + case 0x03: + form_str = "Compact Flash"; + break; + default: + form_str = "UNKNOWN, please report"; + break; + } + + printk("acx: === chipset %s, radio type 0x%02X (%s), " + "form factor 0x%02X (%s), EEPROM version 0x%02X: " + "uploaded firmware '%s' ===\n", + adev->chip_name, adev->radio_type, radio_str, + adev->form_factor, form_str, adev->eeprom_version, + adev->firmware_version); + + FN_EXIT0; +} + + +/*********************************************************************** +*/ +int +acx_e_change_mtu(struct net_device *ndev, int mtu) +{ + enum { + MIN_MTU = 256, + MAX_MTU = WLAN_DATA_MAXLEN - (ETH_HLEN) + }; + + if (mtu < MIN_MTU || mtu > MAX_MTU) + return -EINVAL; + + ndev->mtu = mtu; + return 0; +} + + +/*********************************************************************** +** acx_e_get_stats, acx_e_get_wireless_stats +*/ +struct net_device_stats* +acx_e_get_stats(struct net_device *ndev) +{ + acx_device_t *adev = ndev2adev(ndev); + return &adev->stats; +} + +struct iw_statistics* +acx_e_get_wireless_stats(struct net_device *ndev) +{ + acx_device_t *adev = ndev2adev(ndev); + return &adev->wstats; +} + + +/*********************************************************************** +** maps acx111 tx descr rate field to acx100 one +*/ +const u8 +acx_bitpos2rate100[] = { + RATE100_1 ,/* 0 */ + RATE100_2 ,/* 1 */ + RATE100_5 ,/* 2 */ + RATE100_2 ,/* 3, should not happen */ + RATE100_2 ,/* 4, should not happen */ + RATE100_11 ,/* 5 */ + RATE100_2 ,/* 6, should not happen */ + RATE100_2 ,/* 7, should not happen */ + RATE100_22 ,/* 8 */ + RATE100_2 ,/* 9, should not happen */ + RATE100_2 ,/* 10, should not happen */ + RATE100_2 ,/* 11, should not happen */ + RATE100_2 ,/* 12, should not happen */ + RATE100_2 ,/* 13, should not happen */ + RATE100_2 ,/* 14, should not happen */ + RATE100_2 ,/* 15, should not happen */ +}; + +u8 +acx_rate111to100(u16 r) { + return acx_bitpos2rate100[highest_bit(r)]; +} + + +/*********************************************************************** +** Calculate level like the feb 2003 windows driver seems to do +*/ +static u8 +acx_signal_to_winlevel(u8 rawlevel) +{ + /* u8 winlevel = (u8) (0.5 + 0.625 * rawlevel); */ + u8 winlevel = ((4 + (rawlevel * 5)) / 8); + + if (winlevel > 100) + winlevel = 100; + return winlevel; +} + +u8 +acx_signal_determine_quality(u8 signal, u8 noise) +{ + int qual; + + qual = (((signal - 30) * 100 / 70) + (100 - noise * 4)) / 2; + + if (qual > 100) + return 100; + if (qual < 0) + return 0; + return qual; +} + + +/*********************************************************************** +** Interrogate/configure commands +*/ + +/* FIXME: the lengths given here probably aren't always correct. + * They should be gradually replaced by proper "sizeof(acx1XX_ie_XXXX)-4", + * unless the firmware actually expects a different length than the struct length */ +static const u16 +acx100_ie_len[] = { + 0, + ACX100_IE_ACX_TIMER_LEN, + sizeof(acx100_ie_powersave_t)-4, /* is that 6 or 8??? */ + ACX1xx_IE_QUEUE_CONFIG_LEN, + ACX100_IE_BLOCK_SIZE_LEN, + ACX1xx_IE_MEMORY_CONFIG_OPTIONS_LEN, + ACX1xx_IE_RATE_FALLBACK_LEN, + ACX100_IE_WEP_OPTIONS_LEN, + ACX1xx_IE_MEMORY_MAP_LEN, /* ACX1xx_IE_SSID_LEN, */ + 0, + ACX1xx_IE_ASSOC_ID_LEN, + 0, + ACX111_IE_CONFIG_OPTIONS_LEN, + ACX1xx_IE_FWREV_LEN, + ACX1xx_IE_FCS_ERROR_COUNT_LEN, + ACX1xx_IE_MEDIUM_USAGE_LEN, + ACX1xx_IE_RXCONFIG_LEN, + 0, + 0, + sizeof(fw_stats_t)-4, + 0, + ACX1xx_IE_FEATURE_CONFIG_LEN, + ACX111_IE_KEY_CHOOSE_LEN, + ACX1FF_IE_MISC_CONFIG_TABLE_LEN, + ACX1FF_IE_WONE_CONFIG_LEN, + 0, + ACX1FF_IE_TID_CONFIG_LEN, + 0, + 0, + 0, + ACX1FF_IE_CALIB_ASSESSMENT_LEN, + ACX1FF_IE_BEACON_FILTER_OPTIONS_LEN, + ACX1FF_IE_LOW_RSSI_THRESH_OPT_LEN, + ACX1FF_IE_NOISE_HISTOGRAM_RESULTS_LEN, + 0, + ACX1FF_IE_PACKET_DETECT_THRESH_LEN, + ACX1FF_IE_TX_CONFIG_OPTIONS_LEN, + ACX1FF_IE_CCA_THRESHOLD_LEN, + ACX1FF_IE_EVENT_MASK_LEN, + ACX1FF_IE_DTIM_PERIOD_LEN, + 0, + ACX1FF_IE_ACI_CONFIG_SET_LEN, + 0, + 0, + 0, + 0, + 0, + 0, + ACX1FF_IE_EEPROM_VER_LEN, +}; + +static const u16 +acx100_ie_len_dot11[] = { + 0, + ACX1xx_IE_DOT11_STATION_ID_LEN, + 0, + ACX100_IE_DOT11_BEACON_PERIOD_LEN, + ACX1xx_IE_DOT11_DTIM_PERIOD_LEN, + ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT_LEN, + ACX1xx_IE_DOT11_LONG_RETRY_LIMIT_LEN, + ACX100_IE_DOT11_WEP_DEFAULT_KEY_WRITE_LEN, + ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME_LEN, + 0, + ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN_LEN, + ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN, + 0, + ACX1xx_IE_DOT11_TX_POWER_LEVEL_LEN, + ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN, + ACX100_IE_DOT11_ED_THRESHOLD_LEN, + ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET_LEN, + 0, + 0, + 0, +}; + +static const u16 +acx111_ie_len[] = { + 0, + ACX100_IE_ACX_TIMER_LEN, + sizeof(acx111_ie_powersave_t)-4, + ACX1xx_IE_QUEUE_CONFIG_LEN, + ACX100_IE_BLOCK_SIZE_LEN, + ACX1xx_IE_MEMORY_CONFIG_OPTIONS_LEN, + ACX1xx_IE_RATE_FALLBACK_LEN, + ACX100_IE_WEP_OPTIONS_LEN, + ACX1xx_IE_MEMORY_MAP_LEN, /* ACX1xx_IE_SSID_LEN, */ + 0, + ACX1xx_IE_ASSOC_ID_LEN, + 0, + ACX111_IE_CONFIG_OPTIONS_LEN, + ACX1xx_IE_FWREV_LEN, + ACX1xx_IE_FCS_ERROR_COUNT_LEN, + ACX1xx_IE_MEDIUM_USAGE_LEN, + ACX1xx_IE_RXCONFIG_LEN, + 0, + 0, + sizeof(fw_stats_t)-4, + 0, + ACX1xx_IE_FEATURE_CONFIG_LEN, + ACX111_IE_KEY_CHOOSE_LEN, + ACX1FF_IE_MISC_CONFIG_TABLE_LEN, + ACX1FF_IE_WONE_CONFIG_LEN, + 0, + ACX1FF_IE_TID_CONFIG_LEN, + 0, + 0, + 0, + ACX1FF_IE_CALIB_ASSESSMENT_LEN, + ACX1FF_IE_BEACON_FILTER_OPTIONS_LEN, + ACX1FF_IE_LOW_RSSI_THRESH_OPT_LEN, + ACX1FF_IE_NOISE_HISTOGRAM_RESULTS_LEN, + 0, + ACX1FF_IE_PACKET_DETECT_THRESH_LEN, + ACX1FF_IE_TX_CONFIG_OPTIONS_LEN, + ACX1FF_IE_CCA_THRESHOLD_LEN, + ACX1FF_IE_EVENT_MASK_LEN, + ACX1FF_IE_DTIM_PERIOD_LEN, + 0, + ACX1FF_IE_ACI_CONFIG_SET_LEN, + 0, + 0, + 0, + 0, + 0, + 0, + ACX1FF_IE_EEPROM_VER_LEN, +}; + +static const u16 +acx111_ie_len_dot11[] = { + 0, + ACX1xx_IE_DOT11_STATION_ID_LEN, + 0, + ACX100_IE_DOT11_BEACON_PERIOD_LEN, + ACX1xx_IE_DOT11_DTIM_PERIOD_LEN, + ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT_LEN, + ACX1xx_IE_DOT11_LONG_RETRY_LIMIT_LEN, + ACX100_IE_DOT11_WEP_DEFAULT_KEY_WRITE_LEN, + ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME_LEN, + 0, + ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN_LEN, + ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN, + 0, + ACX1xx_IE_DOT11_TX_POWER_LEVEL_LEN, + ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN, + ACX100_IE_DOT11_ED_THRESHOLD_LEN, + ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET_LEN, + 0, + 0, + 0, +}; + + +#undef FUNC +#define FUNC "configure" +#if !ACX_DEBUG +int +acx_s_configure(acx_device_t *adev, void *pdr, int type) +{ +#else +int +acx_s_configure_debug(acx_device_t *adev, void *pdr, int type, const char* typestr) +{ +#endif + u16 len; + int res; + + if (type < 0x1000) + len = adev->ie_len[type]; + else + len = adev->ie_len_dot11[type - 0x1000]; + + log(L_CTL, FUNC"(type:%s,len:%u)\n", typestr, len); + if (unlikely(!len)) { + log(L_DEBUG, "zero-length type %s?!\n", typestr); + } + + ((acx_ie_generic_t *)pdr)->type = cpu_to_le16(type); + ((acx_ie_generic_t *)pdr)->len = cpu_to_le16(len); + res = acx_s_issue_cmd(adev, ACX1xx_CMD_CONFIGURE, pdr, len + 4); + if (unlikely(OK != res)) { +#if ACX_DEBUG + printk("%s: "FUNC"(type:%s) FAILED\n", adev->ndev->name, typestr); +#else + printk("%s: "FUNC"(type:0x%X) FAILED\n", adev->ndev->name, type); +#endif + /* dump_stack() is already done in issue_cmd() */ + } + return res; +} + +#undef FUNC +#define FUNC "interrogate" +#if !ACX_DEBUG +int +acx_s_interrogate(acx_device_t *adev, void *pdr, int type) +{ +#else +int +acx_s_interrogate_debug(acx_device_t *adev, void *pdr, int type, + const char* typestr) +{ +#endif + u16 len; + int res; + + /* FIXME: no check whether this exceeds the array yet. + * We should probably remember the number of entries... */ + if (type < 0x1000) + len = adev->ie_len[type]; + else + len = adev->ie_len_dot11[type-0x1000]; + + log(L_CTL, FUNC"(type:%s,len:%u)\n", typestr, len); + + ((acx_ie_generic_t *)pdr)->type = cpu_to_le16(type); + ((acx_ie_generic_t *)pdr)->len = cpu_to_le16(len); + res = acx_s_issue_cmd(adev, ACX1xx_CMD_INTERROGATE, pdr, len + 4); + if (unlikely(OK != res)) { +#if ACX_DEBUG + printk("%s: "FUNC"(type:%s) FAILED\n", adev->ndev->name, typestr); +#else + printk("%s: "FUNC"(type:0x%X) FAILED\n", adev->ndev->name, type); +#endif + /* dump_stack() is already done in issue_cmd() */ + } + return res; +} + +#if CMD_DISCOVERY +void +great_inquisitor(acx_device_t *adev) +{ + static struct { + u16 type; + u16 len; + /* 0x200 was too large here: */ + u8 data[0x100 - 4]; + } ACX_PACKED ie; + u16 type; + + FN_ENTER; + + /* 0..0x20, 0x1000..0x1020 */ + for (type = 0; type <= 0x1020; type++) { + if (type == 0x21) + type = 0x1000; + ie.type = cpu_to_le16(type); + ie.len = cpu_to_le16(sizeof(ie) - 4); + acx_s_issue_cmd(adev, ACX1xx_CMD_INTERROGATE, &ie, sizeof(ie)); + } + FN_EXIT0; +} +#endif + + +#ifdef CONFIG_PROC_FS +/*********************************************************************** +** /proc files +*/ +/*********************************************************************** +** acx_l_proc_output +** Generate content for our /proc entry +** +** Arguments: +** buf is a pointer to write output to +** adev is the usual pointer to our private struct acx_device +** Returns: +** number of bytes actually written to buf +** Side effects: +** none +*/ +static int +acx_l_proc_output(char *buf, acx_device_t *adev) +{ + char *p = buf; + int i; + + FN_ENTER; + + p += sprintf(p, + "acx driver version:\t\t" ACX_RELEASE "\n" + "Wireless extension version:\t" STRING(WIRELESS_EXT) "\n" + "chip name:\t\t\t%s (0x%08X)\n" + "radio type:\t\t\t0x%02X\n" + "form factor:\t\t\t0x%02X\n" + "EEPROM version:\t\t\t0x%02X\n" + "firmware version:\t\t%s (0x%08X)\n", + adev->chip_name, adev->firmware_id, + adev->radio_type, + adev->form_factor, + adev->eeprom_version, + adev->firmware_version, adev->firmware_numver); + + for (i = 0; i < VEC_SIZE(adev->sta_list); i++) { + struct client *bss = &adev->sta_list[i]; + if (!bss->used) continue; + p += sprintf(p, "BSS %u BSSID "MACSTR" ESSID %s channel %u " + "Cap 0x%X SIR %u SNR %u\n", + i, MAC(bss->bssid), (char*)bss->essid, bss->channel, + bss->cap_info, bss->sir, bss->snr); + } + p += sprintf(p, "status:\t\t\t%u (%s)\n", + adev->status, acx_get_status_name(adev->status)); + + FN_EXIT1(p - buf); + return p - buf; +} + + +/*********************************************************************** +*/ +static int +acx_s_proc_diag_output(char *buf, acx_device_t *adev) +{ + char *p = buf; + unsigned long flags; + unsigned int len = 0, partlen; + u32 temp1, temp2; + u8 *st, *st_end; +#ifdef __BIG_ENDIAN + u8 *st2; +#endif + fw_stats_t *fw_stats; + char *part_str = NULL; + fw_stats_tx_t *tx = NULL; + fw_stats_rx_t *rx = NULL; + fw_stats_dma_t *dma = NULL; + fw_stats_irq_t *irq = NULL; + fw_stats_wep_t *wep = NULL; + fw_stats_pwr_t *pwr = NULL; + fw_stats_mic_t *mic = NULL; + fw_stats_aes_t *aes = NULL; + fw_stats_event_t *evt = NULL; + + FN_ENTER; + + acx_lock(adev, flags); + + if (IS_PCI(adev)) + p = acxpci_s_proc_diag_output(p, adev); + + p += sprintf(p, + "\n" + "** network status **\n" + "dev_state_mask 0x%04X\n" + "status %u (%s), " + "mode %u, channel %u, " + "reg_dom_id 0x%02X, reg_dom_chanmask 0x%04X, ", + adev->dev_state_mask, + adev->status, acx_get_status_name(adev->status), + adev->mode, adev->channel, + adev->reg_dom_id, adev->reg_dom_chanmask + ); + p += sprintf(p, + "ESSID \"%s\", essid_active %d, essid_len %d, " + "essid_for_assoc \"%s\", nick \"%s\"\n" + "WEP ena %d, restricted %d, idx %d\n", + adev->essid, adev->essid_active, (int)adev->essid_len, + adev->essid_for_assoc, adev->nick, + adev->wep_enabled, adev->wep_restricted, + adev->wep_current_index); + p += sprintf(p, "dev_addr "MACSTR"\n", MAC(adev->dev_addr)); + p += sprintf(p, "bssid "MACSTR"\n", MAC(adev->bssid)); + p += sprintf(p, "ap_filter "MACSTR"\n", MAC(adev->ap)); + + p += sprintf(p, + "\n" + "** PHY status **\n" + "tx_disabled %d, tx_level_dbm %d\n" /* "tx_level_val %d, tx_level_auto %d\n" */ + "sensitivity %d, antenna 0x%02X, ed_threshold %d, cca %d, preamble_mode %d\n" + "rate_basic 0x%04X, rate_oper 0x%04X\n" + "rts_threshold %d, frag_threshold %d, short_retry %d, long_retry %d\n" + "msdu_lifetime %d, listen_interval %d, beacon_interval %d\n", + adev->tx_disabled, adev->tx_level_dbm, /* adev->tx_level_val, adev->tx_level_auto, */ + adev->sensitivity, adev->antenna, adev->ed_threshold, adev->cca, adev->preamble_mode, + adev->rate_basic, adev->rate_oper, + adev->rts_threshold, adev->frag_threshold, adev->short_retry, adev->long_retry, + adev->msdu_lifetime, adev->listen_interval, adev->beacon_interval); + + acx_unlock(adev, flags); + + p += sprintf(p, + "\n" + "** Firmware **\n" + "NOTE: version dependent statistics layout, " + "please report if you suspect wrong parsing!\n" + "\n" + "version \"%s\"\n", adev->firmware_version); + + /* TODO: may replace kmalloc/memset with kzalloc once + * Linux 2.6.14 is widespread */ + fw_stats = kmalloc(sizeof(*fw_stats), GFP_KERNEL); + if (!fw_stats) { + FN_EXIT1(0); + return 0; + } + memset(fw_stats, 0, sizeof(*fw_stats)); + + st = (u8 *)fw_stats; + + part_str = "statistics query command"; + + if (OK != acx_s_interrogate(adev, st, ACX1xx_IE_FIRMWARE_STATISTICS)) + goto fw_stats_end; + + st += sizeof(u16); + len = *(u16 *)st; + + if (len > sizeof(*fw_stats)) { + p += sprintf(p, + "firmware version with bigger fw_stats struct detected\n" + "(%u vs. %zu), please report\n", len, sizeof(fw_stats_t)); + if (len > sizeof(*fw_stats)) { + p += sprintf(p, "struct size exceeded allocation!\n"); + len = sizeof(*fw_stats); + } + } + st += sizeof(u16); + st_end = st - 2*sizeof(u16) + len; + +#ifdef __BIG_ENDIAN + /* let's make one bold assumption here: + * (hopefully!) *all* statistics fields are u32 only, + * thus if we need to make endianness corrections + * we can simply do them in one go, in advance */ + st2 = (u8 *)fw_stats; + for (temp1 = 0; temp1 < len; temp1 += 4, st2 += 4) + *(u32 *)st2 = le32_to_cpu(*(u32 *)st2); +#endif + + part_str = "Rx/Tx"; + + /* directly at end of a struct part? --> no error! */ + if (st == st_end) + goto fw_stats_end; + + tx = (fw_stats_tx_t *)st; + st += sizeof(fw_stats_tx_t); + rx = (fw_stats_rx_t *)st; + st += sizeof(fw_stats_rx_t); + partlen = sizeof(fw_stats_tx_t) + sizeof(fw_stats_rx_t); + + if (IS_ACX100(adev)) { + /* at least ACX100 PCI F/W 1.9.8.b + * and ACX100 USB F/W 1.0.7-USB + * don't have those two fields... */ + st -= 2*sizeof(u32); + + /* our parsing doesn't quite match this firmware yet, + * log failure */ + if (st > st_end) + goto fw_stats_fail; + temp1 = temp2 = 999999999; + } else { + if (st > st_end) + goto fw_stats_fail; + temp1 = rx->rx_aci_events; + temp2 = rx->rx_aci_resets; + } + + p += sprintf(p, + "%s:\n" + " tx_desc_overfl %u\n" + " rx_OutOfMem %u, rx_hdr_overfl %u, rx_hw_stuck %u\n" + " rx_dropped_frame %u, rx_frame_ptr_err %u, rx_xfr_hint_trig %u\n" + " rx_aci_events %u, rx_aci_resets %u\n", + part_str, + tx->tx_desc_of, + rx->rx_oom, + rx->rx_hdr_of, + rx->rx_hw_stuck, + rx->rx_dropped_frame, + rx->rx_frame_ptr_err, + rx->rx_xfr_hint_trig, + temp1, + temp2); + + part_str = "DMA"; + + if (st == st_end) + goto fw_stats_end; + + dma = (fw_stats_dma_t *)st; + partlen = sizeof(fw_stats_dma_t); + st += partlen; + + if (st > st_end) + goto fw_stats_fail; + + p += sprintf(p, + "%s:\n" + " rx_dma_req %u, rx_dma_err %u, tx_dma_req %u, tx_dma_err %u\n", + part_str, + dma->rx_dma_req, + dma->rx_dma_err, + dma->tx_dma_req, + dma->tx_dma_err); + + part_str = "IRQ"; + + if (st == st_end) + goto fw_stats_end; + + irq = (fw_stats_irq_t *)st; + partlen = sizeof(fw_stats_irq_t); + st += partlen; + + if (st > st_end) + goto fw_stats_fail; + + p += sprintf(p, + "%s:\n" + " cmd_cplt %u, fiq %u\n" + " rx_hdrs %u, rx_cmplt %u, rx_mem_overfl %u, rx_rdys %u\n" + " irqs %u, tx_procs %u, decrypt_done %u\n" + " dma_0_done %u, dma_1_done %u, tx_exch_complet %u\n" + " commands %u, rx_procs %u, hw_pm_mode_changes %u\n" + " host_acks %u, pci_pm %u, acm_wakeups %u\n", + part_str, + irq->cmd_cplt, + irq->fiq, + irq->rx_hdrs, + irq->rx_cmplt, + irq->rx_mem_of, + irq->rx_rdys, + irq->irqs, + irq->tx_procs, + irq->decrypt_done, + irq->dma_0_done, + irq->dma_1_done, + irq->tx_exch_complet, + irq->commands, + irq->rx_procs, + irq->hw_pm_mode_changes, + irq->host_acks, + irq->pci_pm, + irq->acm_wakeups); + + part_str = "WEP"; + + if (st == st_end) + goto fw_stats_end; + + wep = (fw_stats_wep_t *)st; + partlen = sizeof(fw_stats_wep_t); + st += partlen; + + if ( + (IS_PCI(adev) && IS_ACX100(adev)) + || (IS_USB(adev) && IS_ACX100(adev)) + ) { + /* at least ACX100 PCI F/W 1.9.8.b + * and ACX100 USB F/W 1.0.7-USB + * don't have those two fields... */ + st -= 2*sizeof(u32); + if (st > st_end) + goto fw_stats_fail; + temp1 = temp2 = 999999999; + } else { + if (st > st_end) + goto fw_stats_fail; + temp1 = wep->wep_pkt_decrypt; + temp2 = wep->wep_decrypt_irqs; + } + + p += sprintf(p, + "%s:\n" + " wep_key_count %u, wep_default_key_count %u, dot11_def_key_mib %u\n" + " wep_key_not_found %u, wep_decrypt_fail %u\n" + " wep_pkt_decrypt %u, wep_decrypt_irqs %u\n", + part_str, + wep->wep_key_count, + wep->wep_default_key_count, + wep->dot11_def_key_mib, + wep->wep_key_not_found, + wep->wep_decrypt_fail, + temp1, + temp2); + + part_str = "power"; + + if (st == st_end) + goto fw_stats_end; + + pwr = (fw_stats_pwr_t *)st; + partlen = sizeof(fw_stats_pwr_t); + st += partlen; + + if (st > st_end) + goto fw_stats_fail; + + p += sprintf(p, + "%s:\n" + " tx_start_ctr %u, no_ps_tx_too_short %u\n" + " rx_start_ctr %u, no_ps_rx_too_short %u\n" + " lppd_started %u\n" + " no_lppd_too_noisy %u, no_lppd_too_short %u, no_lppd_matching_frame %u\n", + part_str, + pwr->tx_start_ctr, + pwr->no_ps_tx_too_short, + pwr->rx_start_ctr, + pwr->no_ps_rx_too_short, + pwr->lppd_started, + pwr->no_lppd_too_noisy, + pwr->no_lppd_too_short, + pwr->no_lppd_matching_frame); + + part_str = "MIC"; + + if (st == st_end) + goto fw_stats_end; + + mic = (fw_stats_mic_t *)st; + partlen = sizeof(fw_stats_mic_t); + st += partlen; + + if (st > st_end) + goto fw_stats_fail; + + p += sprintf(p, + "%s:\n" + " mic_rx_pkts %u, mic_calc_fail %u\n", + part_str, + mic->mic_rx_pkts, + mic->mic_calc_fail); + + part_str = "AES"; + + if (st == st_end) + goto fw_stats_end; + + aes = (fw_stats_aes_t *)st; + partlen = sizeof(fw_stats_aes_t); + st += partlen; + + if (st > st_end) + goto fw_stats_fail; + + p += sprintf(p, + "%s:\n" + " aes_enc_fail %u, aes_dec_fail %u\n" + " aes_enc_pkts %u, aes_dec_pkts %u\n" + " aes_enc_irq %u, aes_dec_irq %u\n", + part_str, + aes->aes_enc_fail, + aes->aes_dec_fail, + aes->aes_enc_pkts, + aes->aes_dec_pkts, + aes->aes_enc_irq, + aes->aes_dec_irq); + + part_str = "event"; + + if (st == st_end) + goto fw_stats_end; + + evt = (fw_stats_event_t *)st; + partlen = sizeof(fw_stats_event_t); + st += partlen; + + if (st > st_end) + goto fw_stats_fail; + + p += sprintf(p, + "%s:\n" + " heartbeat %u, calibration %u\n" + " rx_mismatch %u, rx_mem_empty %u, rx_pool %u\n" + " oom_late %u\n" + " phy_tx_err %u, tx_stuck %u\n", + part_str, + evt->heartbeat, + evt->calibration, + evt->rx_mismatch, + evt->rx_mem_empty, + evt->rx_pool, + evt->oom_late, + evt->phy_tx_err, + evt->tx_stuck); + + if (st < st_end) + goto fw_stats_bigger; + + goto fw_stats_end; + +fw_stats_fail: + st -= partlen; + p += sprintf(p, + "failed at %s part (size %u), offset %lu (struct size %u), " + "please report\n", part_str, partlen, + (unsigned long)st - (unsigned long)fw_stats, len); + +fw_stats_bigger: + for (; st < st_end; st += 4) + p += sprintf(p, + "UNKN%3lu: %u\n", (unsigned long)st - (unsigned long)fw_stats, *(u32 *)st); + +fw_stats_end: + kfree(fw_stats); + + FN_EXIT1(p - buf); + return p - buf; +} + + +/*********************************************************************** +*/ +static int +acx_s_proc_phy_output(char *buf, acx_device_t *adev) +{ + char *p = buf; + int i; + + FN_ENTER; + + /* + if (RADIO_RFMD_11 != adev->radio_type) { + printk("sorry, not yet adapted for radio types " + "other than RFMD, please verify " + "PHY size etc. first!\n"); + goto end; + } + */ + + /* The PHY area is only 0x80 bytes long; further pages after that + * only have some page number registers with altered value, + * all other registers remain the same. */ + for (i = 0; i < 0x80; i++) { + acx_s_read_phy_reg(adev, i, p++); + } + + FN_EXIT1(p - buf); + return p - buf; +} + + +/*********************************************************************** +** acx_e_read_proc_XXXX +** Handle our /proc entry +** +** Arguments: +** standard kernel read_proc interface +** Returns: +** number of bytes written to buf +** Side effects: +** none +*/ +static int +acx_e_read_proc(char *buf, char **start, off_t offset, int count, + int *eof, void *data) +{ + acx_device_t *adev = (acx_device_t*)data; + unsigned long flags; + int length; + + FN_ENTER; + + acx_sem_lock(adev); + acx_lock(adev, flags); + /* fill buf */ + length = acx_l_proc_output(buf, adev); + acx_unlock(adev, flags); + acx_sem_unlock(adev); + + /* housekeeping */ + if (length <= offset + count) + *eof = 1; + *start = buf + offset; + length -= offset; + if (length > count) + length = count; + if (length < 0) + length = 0; + FN_EXIT1(length); + return length; +} + +static int +acx_e_read_proc_diag(char *buf, char **start, off_t offset, int count, + int *eof, void *data) +{ + acx_device_t *adev = (acx_device_t*)data; + int length; + + FN_ENTER; + + acx_sem_lock(adev); + /* fill buf */ + length = acx_s_proc_diag_output(buf, adev); + acx_sem_unlock(adev); + + /* housekeeping */ + if (length <= offset + count) + *eof = 1; + *start = buf + offset; + length -= offset; + if (length > count) + length = count; + if (length < 0) + length = 0; + FN_EXIT1(length); + return length; +} + +static int +acx_e_read_proc_eeprom(char *buf, char **start, off_t offset, int count, + int *eof, void *data) +{ + acx_device_t *adev = (acx_device_t*)data; + int length; + + FN_ENTER; + + /* fill buf */ + length = 0; + if (IS_PCI(adev)) { + acx_sem_lock(adev); + length = acxpci_proc_eeprom_output(buf, adev); + acx_sem_unlock(adev); + } + + /* housekeeping */ + if (length <= offset + count) + *eof = 1; + *start = buf + offset; + length -= offset; + if (length > count) + length = count; + if (length < 0) + length = 0; + FN_EXIT1(length); + return length; +} + +static int +acx_e_read_proc_phy(char *buf, char **start, off_t offset, int count, + int *eof, void *data) +{ + acx_device_t *adev = (acx_device_t*)data; + int length; + + FN_ENTER; + + acx_sem_lock(adev); + /* fill buf */ + length = acx_s_proc_phy_output(buf, adev); + acx_sem_unlock(adev); + + /* housekeeping */ + if (length <= offset + count) + *eof = 1; + *start = buf + offset; + length -= offset; + if (length > count) + length = count; + if (length < 0) + length = 0; + FN_EXIT1(length); + return length; +} + + +/*********************************************************************** +** /proc files registration +*/ +static const char * const +proc_files[] = { "", "_diag", "_eeprom", "_phy" }; + +static read_proc_t * const +proc_funcs[] = { + acx_e_read_proc, + acx_e_read_proc_diag, + acx_e_read_proc_eeprom, + acx_e_read_proc_phy +}; + +static int +manage_proc_entries(const struct net_device *ndev, int remove) +{ + acx_device_t *adev = ndev2adev((struct net_device *)ndev); + char procbuf[80]; + int i; + + for (i = 0; i < VEC_SIZE(proc_files); i++) { + snprintf(procbuf, sizeof(procbuf), + "driver/acx_%s%s", ndev->name, proc_files[i]); + log(L_INIT, "%sing /proc entry %s\n", + remove ? "remov" : "creat", procbuf); + if (!remove) { + if (!create_proc_read_entry(procbuf, 0, 0, proc_funcs[i], adev)) { + printk("acx: cannot register /proc entry %s\n", procbuf); + return NOT_OK; + } + } else { + remove_proc_entry(procbuf, NULL); + } + } + return OK; +} + +int +acx_proc_register_entries(const struct net_device *ndev) +{ + return manage_proc_entries(ndev, 0); +} + +int +acx_proc_unregister_entries(const struct net_device *ndev) +{ + return manage_proc_entries(ndev, 1); +} +#endif /* CONFIG_PROC_FS */ + + +/*********************************************************************** +** acx_cmd_join_bssid +** +** Common code for both acx100 and acx111. +*/ +/* NB: does NOT match RATE100_nn but matches ACX[111]_SCAN_RATE_n */ +static const u8 +bitpos2genframe_txrate[] = { + 10, /* 0. 1 Mbit/s */ + 20, /* 1. 2 Mbit/s */ + 55, /* 2. 5.5 Mbit/s */ + 0x0B, /* 3. 6 Mbit/s */ + 0x0F, /* 4. 9 Mbit/s */ + 110, /* 5. 11 Mbit/s */ + 0x0A, /* 6. 12 Mbit/s */ + 0x0E, /* 7. 18 Mbit/s */ + 220, /* 8. 22 Mbit/s */ + 0x09, /* 9. 24 Mbit/s */ + 0x0D, /* 10. 36 Mbit/s */ + 0x08, /* 11. 48 Mbit/s */ + 0x0C, /* 12. 54 Mbit/s */ + 10, /* 13. 1 Mbit/s, should never happen */ + 10, /* 14. 1 Mbit/s, should never happen */ + 10, /* 15. 1 Mbit/s, should never happen */ +}; + +/* Looks scary, eh? +** Actually, each one compiled into one AND and one SHIFT, +** 31 bytes in x86 asm (more if uints are replaced by u16/u8) */ +static inline unsigned int +rate111to5bits(unsigned int rate) +{ + return (rate & 0x7) + | ( (rate & RATE111_11) / (RATE111_11/JOINBSS_RATES_11) ) + | ( (rate & RATE111_22) / (RATE111_22/JOINBSS_RATES_22) ) + ; +} + +static void +acx_s_cmd_join_bssid(acx_device_t *adev, const u8 *bssid) +{ + acx_joinbss_t tmp; + int dtim_interval; + int i; + + if (mac_is_zero(bssid)) + return; + + FN_ENTER; + + dtim_interval = (ACX_MODE_0_ADHOC == adev->mode) ? + 1 : adev->dtim_interval; + + memset(&tmp, 0, sizeof(tmp)); + + for (i = 0; i < ETH_ALEN; i++) { + tmp.bssid[i] = bssid[ETH_ALEN-1 - i]; + } + + tmp.beacon_interval = cpu_to_le16(adev->beacon_interval); + + /* Basic rate set. Control frame responses (such as ACK or CTS frames) + ** are sent with one of these rates */ + if (IS_ACX111(adev)) { + /* It was experimentally determined that rates_basic + ** can take 11g rates as well, not only rates + ** defined with JOINBSS_RATES_BASIC111_nnn. + ** Just use RATE111_nnn constants... */ + tmp.u.acx111.dtim_interval = dtim_interval; + tmp.u.acx111.rates_basic = cpu_to_le16(adev->rate_basic); + log(L_ASSOC, "rates_basic:%04X, rates_supported:%04X\n", + adev->rate_basic, adev->rate_oper); + } else { + tmp.u.acx100.dtim_interval = dtim_interval; + tmp.u.acx100.rates_basic = rate111to5bits(adev->rate_basic); + tmp.u.acx100.rates_supported = rate111to5bits(adev->rate_oper); + log(L_ASSOC, "rates_basic:%04X->%02X, " + "rates_supported:%04X->%02X\n", + adev->rate_basic, tmp.u.acx100.rates_basic, + adev->rate_oper, tmp.u.acx100.rates_supported); + } + + /* Setting up how Beacon, Probe Response, RTS, and PS-Poll frames + ** will be sent (rate/modulation/preamble) */ + tmp.genfrm_txrate = bitpos2genframe_txrate[lowest_bit(adev->rate_basic)]; + tmp.genfrm_mod_pre = 0; /* FIXME: was = adev->capab_short (which was always 0); */ + /* we can use short pre *if* all peers can understand it */ + /* FIXME #2: we need to correctly set PBCC/OFDM bits here too */ + + /* we switch fw to STA mode in MONITOR mode, it seems to be + ** the only mode where fw does not emit beacons by itself + ** but allows us to send anything (we really want to retain + ** ability to tx arbitrary frames in MONITOR mode) + */ + tmp.macmode = (adev->mode != ACX_MODE_MONITOR ? adev->mode : ACX_MODE_2_STA); + tmp.channel = adev->channel; + tmp.essid_len = adev->essid_len; + /* NOTE: the code memcpy'd essid_len + 1 before, which is WRONG! */ + memcpy(tmp.essid, adev->essid, tmp.essid_len); + acx_s_issue_cmd(adev, ACX1xx_CMD_JOIN, &tmp, tmp.essid_len + 0x11); + + log(L_ASSOC|L_DEBUG, "BSS_Type = %u\n", tmp.macmode); + acxlog_mac(L_ASSOC|L_DEBUG, "JoinBSSID MAC:", adev->bssid, "\n"); + + acx_update_capabilities(adev); + FN_EXIT0; +} + + +/*********************************************************************** +** acx_s_cmd_start_scan +** +** Issue scan command to the hardware +** +** unified function for both ACX111 and ACX100 +*/ +static void +acx_s_scan_chan(acx_device_t *adev) +{ + union { + acx111_scan_t acx111; + acx100_scan_t acx100; + } s; + + FN_ENTER; + + memset(&s, 0, sizeof(s)); + + /* first common positions... */ + + s.acx111.count = cpu_to_le16(adev->scan_count); + s.acx111.rate = adev->scan_rate; + s.acx111.options = adev->scan_mode; + s.acx111.chan_duration = cpu_to_le16(adev->scan_duration); + s.acx111.max_probe_delay = cpu_to_le16(adev->scan_probe_delay); + + /* ...then differences */ + + if (IS_ACX111(adev)) { + s.acx111.channel_list_select = 0; /* scan every allowed channel */ + /*s.acx111.channel_list_select = 1;*/ /* scan given channels */ + /*s.acx111.modulation = 0x40;*/ /* long preamble? OFDM? -> only for active scan */ + s.acx111.modulation = 0; + /*s.acx111.channel_list[0] = 6; + s.acx111.channel_list[1] = 4;*/ + } else { + s.acx100.start_chan = cpu_to_le16(1); + s.acx100.flags = cpu_to_le16(0x8000); + } + + acx_s_issue_cmd(adev, ACX1xx_CMD_SCAN, &s, sizeof(s)); + FN_EXIT0; +} + + +void +acx_s_cmd_start_scan(acx_device_t *adev) +{ + /* time_before check is 'just in case' thing */ + if (!(adev->irq_status & HOST_INT_SCAN_COMPLETE) + && time_before(jiffies, adev->scan_start + 10*HZ) + ) { + log(L_INIT, "start_scan: seems like previous scan " + "is still running. Not starting anew. Please report\n"); + return; + } + + log(L_INIT, "starting radio scan\n"); + /* remember that fw is commanded to do scan */ + adev->scan_start = jiffies; + CLEAR_BIT(adev->irq_status, HOST_INT_SCAN_COMPLETE); + /* issue it */ + acx_s_scan_chan(adev); +} + + +/*********************************************************************** +** acx111 feature config +*/ +static int +acx111_s_get_feature_config(acx_device_t *adev, + u32 *feature_options, u32 *data_flow_options) +{ + struct acx111_ie_feature_config feat; + + if (!IS_ACX111(adev)) { + return NOT_OK; + } + + memset(&feat, 0, sizeof(feat)); + + if (OK != acx_s_interrogate(adev, &feat, ACX1xx_IE_FEATURE_CONFIG)) { + return NOT_OK; + } + log(L_DEBUG, + "got Feature option:0x%X, DataFlow option: 0x%X\n", + feat.feature_options, + feat.data_flow_options); + + if (feature_options) + *feature_options = le32_to_cpu(feat.feature_options); + if (data_flow_options) + *data_flow_options = le32_to_cpu(feat.data_flow_options); + + return OK; +} + +static int +acx111_s_set_feature_config(acx_device_t *adev, + u32 feature_options, u32 data_flow_options, + unsigned int mode /* 0 == remove, 1 == add, 2 == set */) +{ + struct acx111_ie_feature_config feat; + + if (!IS_ACX111(adev)) { + return NOT_OK; + } + + if ((mode < 0) || (mode > 2)) + return NOT_OK; + + if (mode != 2) + /* need to modify old data */ + acx111_s_get_feature_config(adev, &feat.feature_options, &feat.data_flow_options); + else { + /* need to set a completely new value */ + feat.feature_options = 0; + feat.data_flow_options = 0; + } + + if (mode == 0) { /* remove */ + CLEAR_BIT(feat.feature_options, cpu_to_le32(feature_options)); + CLEAR_BIT(feat.data_flow_options, cpu_to_le32(data_flow_options)); + } else { /* add or set */ + SET_BIT(feat.feature_options, cpu_to_le32(feature_options)); + SET_BIT(feat.data_flow_options, cpu_to_le32(data_flow_options)); + } + + log(L_DEBUG, + "old: feature 0x%08X dataflow 0x%08X. mode: %u\n" + "new: feature 0x%08X dataflow 0x%08X\n", + feature_options, data_flow_options, mode, + le32_to_cpu(feat.feature_options), + le32_to_cpu(feat.data_flow_options)); + + if (OK != acx_s_configure(adev, &feat, ACX1xx_IE_FEATURE_CONFIG)) { + return NOT_OK; + } + + return OK; +} + +static inline int +acx111_s_feature_off(acx_device_t *adev, u32 f, u32 d) +{ + return acx111_s_set_feature_config(adev, f, d, 0); +} +static inline int +acx111_s_feature_on(acx_device_t *adev, u32 f, u32 d) +{ + return acx111_s_set_feature_config(adev, f, d, 1); +} +static inline int +acx111_s_feature_set(acx_device_t *adev, u32 f, u32 d) +{ + return acx111_s_set_feature_config(adev, f, d, 2); +} + + +/*********************************************************************** +** acx100_s_init_memory_pools +*/ +static int +acx100_s_init_memory_pools(acx_device_t *adev, const acx_ie_memmap_t *mmt) +{ + acx100_ie_memblocksize_t MemoryBlockSize; + acx100_ie_memconfigoption_t MemoryConfigOption; + int TotalMemoryBlocks; + int RxBlockNum; + int TotalRxBlockSize; + int TxBlockNum; + int TotalTxBlockSize; + + FN_ENTER; + + /* Let's see if we can follow this: + first we select our memory block size (which I think is + completely arbitrary) */ + MemoryBlockSize.size = cpu_to_le16(adev->memblocksize); + + /* Then we alert the card to our decision of block size */ + if (OK != acx_s_configure(adev, &MemoryBlockSize, ACX100_IE_BLOCK_SIZE)) { + goto bad; + } + + /* We figure out how many total blocks we can create, using + the block size we chose, and the beginning and ending + memory pointers, i.e.: end-start/size */ + TotalMemoryBlocks = (le32_to_cpu(mmt->PoolEnd) - le32_to_cpu(mmt->PoolStart)) / adev->memblocksize; + + log(L_DEBUG, "TotalMemoryBlocks=%u (%u bytes)\n", + TotalMemoryBlocks, TotalMemoryBlocks*adev->memblocksize); + + /* MemoryConfigOption.DMA_config bitmask: + access to ACX memory is to be done: + 0x00080000 using PCI conf space?! + 0x00040000 using IO instructions? + 0x00000000 using memory access instructions + 0x00020000 using local memory block linked list (else what?) + 0x00010000 using host indirect descriptors (else host must access ACX memory?) + */ + if (IS_PCI(adev)) { + MemoryConfigOption.DMA_config = cpu_to_le32(0x30000); + /* Declare start of the Rx host pool */ + MemoryConfigOption.pRxHostDesc = cpu2acx(adev->rxhostdesc_startphy); + log(L_DEBUG, "pRxHostDesc 0x%08X, rxhostdesc_startphy 0x%lX\n", + acx2cpu(MemoryConfigOption.pRxHostDesc), + (long)adev->rxhostdesc_startphy); + } else { + MemoryConfigOption.DMA_config = cpu_to_le32(0x20000); + } + + /* 50% of the allotment of memory blocks go to tx descriptors */ + TxBlockNum = TotalMemoryBlocks / 2; + MemoryConfigOption.TxBlockNum = cpu_to_le16(TxBlockNum); + + /* and 50% go to the rx descriptors */ + RxBlockNum = TotalMemoryBlocks - TxBlockNum; + MemoryConfigOption.RxBlockNum = cpu_to_le16(RxBlockNum); + + /* size of the tx and rx descriptor queues */ + TotalTxBlockSize = TxBlockNum * adev->memblocksize; + TotalRxBlockSize = RxBlockNum * adev->memblocksize; + log(L_DEBUG, "TxBlockNum %u RxBlockNum %u TotalTxBlockSize %u " + "TotalTxBlockSize %u\n", TxBlockNum, RxBlockNum, + TotalTxBlockSize, TotalRxBlockSize); + + + /* align the tx descriptor queue to an alignment of 0x20 (32 bytes) */ + MemoryConfigOption.rx_mem = + cpu_to_le32((le32_to_cpu(mmt->PoolStart) + 0x1f) & ~0x1f); + + /* align the rx descriptor queue to units of 0x20 + * and offset it by the tx descriptor queue */ + MemoryConfigOption.tx_mem = + cpu_to_le32((le32_to_cpu(mmt->PoolStart) + TotalRxBlockSize + 0x1f) & ~0x1f); + log(L_DEBUG, "rx_mem %08X rx_mem %08X\n", + MemoryConfigOption.tx_mem, MemoryConfigOption.rx_mem); + + /* alert the device to our decision */ + if (OK != acx_s_configure(adev, &MemoryConfigOption, ACX1xx_IE_MEMORY_CONFIG_OPTIONS)) { + goto bad; + } + + /* and tell the device to kick it into gear */ + if (OK != acx_s_issue_cmd(adev, ACX100_CMD_INIT_MEMORY, NULL, 0)) { + goto bad; + } + FN_EXIT1(OK); + return OK; +bad: + FN_EXIT1(NOT_OK); + return NOT_OK; +} + + +/*********************************************************************** +** acx100_s_create_dma_regions +** +** Note that this fn messes up heavily with hardware, but we cannot +** lock it (we need to sleep). Not a problem since IRQs can't happen +*/ +static int +acx100_s_create_dma_regions(acx_device_t *adev) +{ + acx100_ie_queueconfig_t queueconf; + acx_ie_memmap_t memmap; + int res = NOT_OK; + u32 tx_queue_start, rx_queue_start; + + FN_ENTER; + + /* read out the acx100 physical start address for the queues */ + if (OK != acx_s_interrogate(adev, &memmap, ACX1xx_IE_MEMORY_MAP)) { + goto fail; + } + + tx_queue_start = le32_to_cpu(memmap.QueueStart); + rx_queue_start = tx_queue_start + TX_CNT * sizeof(txdesc_t); + + log(L_DEBUG, "initializing Queue Indicator\n"); + + memset(&queueconf, 0, sizeof(queueconf)); + + /* Not needed for PCI, so we can avoid setting them altogether */ + if (IS_USB(adev)) { + queueconf.NumTxDesc = USB_TX_CNT; + queueconf.NumRxDesc = USB_RX_CNT; + } + + /* calculate size of queues */ + queueconf.AreaSize = cpu_to_le32( + TX_CNT * sizeof(txdesc_t) + + RX_CNT * sizeof(rxdesc_t) + 8 + ); + queueconf.NumTxQueues = 1; /* number of tx queues */ + /* sets the beginning of the tx descriptor queue */ + queueconf.TxQueueStart = memmap.QueueStart; + /* done by memset: queueconf.TxQueuePri = 0; */ + queueconf.RxQueueStart = cpu_to_le32(rx_queue_start); + queueconf.QueueOptions = 1; /* auto reset descriptor */ + /* sets the end of the rx descriptor queue */ + queueconf.QueueEnd = cpu_to_le32( + rx_queue_start + RX_CNT * sizeof(rxdesc_t) + ); + /* sets the beginning of the next queue */ + queueconf.HostQueueEnd = cpu_to_le32(le32_to_cpu(queueconf.QueueEnd) + 8); + if (OK != acx_s_configure(adev, &queueconf, ACX1xx_IE_QUEUE_CONFIG)) { + goto fail; + } + + if (IS_PCI(adev)) { + /* sets the beginning of the rx descriptor queue, after the tx descrs */ + if (OK != acxpci_s_create_hostdesc_queues(adev)) + goto fail; + acxpci_create_desc_queues(adev, tx_queue_start, rx_queue_start); + } + + if (OK != acx_s_interrogate(adev, &memmap, ACX1xx_IE_MEMORY_MAP)) { + goto fail; + } + + memmap.PoolStart = cpu_to_le32( + (le32_to_cpu(memmap.QueueEnd) + 4 + 0x1f) & ~0x1f + ); + + if (OK != acx_s_configure(adev, &memmap, ACX1xx_IE_MEMORY_MAP)) { + goto fail; + } + + if (OK != acx100_s_init_memory_pools(adev, &memmap)) { + goto fail; + } + + res = OK; + goto end; + +fail: + acx_s_msleep(1000); /* ? */ + if (IS_PCI(adev)) + acxpci_free_desc_queues(adev); +end: + FN_EXIT1(res); + return res; +} + + +/*********************************************************************** +** acx111_s_create_dma_regions +** +** Note that this fn messes heavily with hardware, but we cannot +** lock it (we need to sleep). Not a problem since IRQs can't happen +*/ +#define ACX111_PERCENT(percent) ((percent)/5) + +static int +acx111_s_create_dma_regions(acx_device_t *adev) +{ + struct acx111_ie_memoryconfig memconf; + struct acx111_ie_queueconfig queueconf; + u32 tx_queue_start, rx_queue_start; + + FN_ENTER; + + /* Calculate memory positions and queue sizes */ + + /* Set up our host descriptor pool + data pool */ + if (IS_PCI(adev)) { + if (OK != acxpci_s_create_hostdesc_queues(adev)) + goto fail; + } + + memset(&memconf, 0, sizeof(memconf)); + /* the number of STAs (STA contexts) to support + ** NB: was set to 1 and everything seemed to work nevertheless... */ + memconf.no_of_stations = cpu_to_le16(VEC_SIZE(adev->sta_list)); + /* specify the memory block size. Default is 256 */ + memconf.memory_block_size = cpu_to_le16(adev->memblocksize); + /* let's use 50%/50% for tx/rx (specify percentage, units of 5%) */ + memconf.tx_rx_memory_block_allocation = ACX111_PERCENT(50); + /* set the count of our queues + ** NB: struct acx111_ie_memoryconfig shall be modified + ** if we ever will switch to more than one rx and/or tx queue */ + memconf.count_rx_queues = 1; + memconf.count_tx_queues = 1; + /* 0 == Busmaster Indirect Memory Organization, which is what we want + * (using linked host descs with their allocated mem). + * 2 == Generic Bus Slave */ + /* done by memset: memconf.options = 0; */ + /* let's use 25% for fragmentations and 75% for frame transfers + * (specified in units of 5%) */ + memconf.fragmentation = ACX111_PERCENT(75); + /* Rx descriptor queue config */ + memconf.rx_queue1_count_descs = RX_CNT; + memconf.rx_queue1_type = 7; /* must be set to 7 */ + /* done by memset: memconf.rx_queue1_prio = 0; low prio */ + if (IS_PCI(adev)) { + memconf.rx_queue1_host_rx_start = cpu2acx(adev->rxhostdesc_startphy); + } + /* Tx descriptor queue config */ + memconf.tx_queue1_count_descs = TX_CNT; + /* done by memset: memconf.tx_queue1_attributes = 0; lowest priority */ + + /* NB1: this looks wrong: (memconf,ACX1xx_IE_QUEUE_CONFIG), + ** (queueconf,ACX1xx_IE_MEMORY_CONFIG_OPTIONS) look swapped, eh? + ** But it is actually correct wrt IE numbers. + ** NB2: sizeof(memconf) == 28 == 0x1c but configure(ACX1xx_IE_QUEUE_CONFIG) + ** writes 0x20 bytes (because same IE for acx100 uses struct acx100_ie_queueconfig + ** which is 4 bytes larger. what a mess. TODO: clean it up) */ + if (OK != acx_s_configure(adev, &memconf, ACX1xx_IE_QUEUE_CONFIG)) { + goto fail; + } + + acx_s_interrogate(adev, &queueconf, ACX1xx_IE_MEMORY_CONFIG_OPTIONS); + + tx_queue_start = le32_to_cpu(queueconf.tx1_queue_address); + rx_queue_start = le32_to_cpu(queueconf.rx1_queue_address); + + log(L_INIT, "dump queue head (from card):\n" + "len: %u\n" + "tx_memory_block_address: %X\n" + "rx_memory_block_address: %X\n" + "tx1_queue address: %X\n" + "rx1_queue address: %X\n", + le16_to_cpu(queueconf.len), + le32_to_cpu(queueconf.tx_memory_block_address), + le32_to_cpu(queueconf.rx_memory_block_address), + tx_queue_start, + rx_queue_start); + + if (IS_PCI(adev)) + acxpci_create_desc_queues(adev, tx_queue_start, rx_queue_start); + + FN_EXIT1(OK); + return OK; +fail: + if (IS_PCI(adev)) + acxpci_free_desc_queues(adev); + + FN_EXIT1(NOT_OK); + return NOT_OK; +} + + +/*********************************************************************** +*/ +static void +acx_s_initialize_rx_config(acx_device_t *adev) +{ + struct { + u16 id; + u16 len; + u16 rx_cfg1; + u16 rx_cfg2; + } ACX_PACKED cfg; + + switch (adev->mode) { + case ACX_MODE_OFF: + adev->rx_config_1 = (u16) (0 + /* | RX_CFG1_INCLUDE_RXBUF_HDR */ + /* | RX_CFG1_FILTER_SSID */ + /* | RX_CFG1_FILTER_BCAST */ + /* | RX_CFG1_RCV_MC_ADDR1 */ + /* | RX_CFG1_RCV_MC_ADDR0 */ + /* | RX_CFG1_FILTER_ALL_MULTI */ + /* | RX_CFG1_FILTER_BSSID */ + /* | RX_CFG1_FILTER_MAC */ + /* | RX_CFG1_RCV_PROMISCUOUS */ + /* | RX_CFG1_INCLUDE_FCS */ + /* | RX_CFG1_INCLUDE_PHY_HDR */ + ); + adev->rx_config_2 = (u16) (0 + /*| RX_CFG2_RCV_ASSOC_REQ */ + /*| RX_CFG2_RCV_AUTH_FRAMES */ + /*| RX_CFG2_RCV_BEACON_FRAMES */ + /*| RX_CFG2_RCV_CONTENTION_FREE */ + /*| RX_CFG2_RCV_CTRL_FRAMES */ + /*| RX_CFG2_RCV_DATA_FRAMES */ + /*| RX_CFG2_RCV_BROKEN_FRAMES */ + /*| RX_CFG2_RCV_MGMT_FRAMES */ + /*| RX_CFG2_RCV_PROBE_REQ */ + /*| RX_CFG2_RCV_PROBE_RESP */ + /*| RX_CFG2_RCV_ACK_FRAMES */ + /*| RX_CFG2_RCV_OTHER */ + ); + break; + case ACX_MODE_MONITOR: + adev->rx_config_1 = (u16) (0 + /* | RX_CFG1_INCLUDE_RXBUF_HDR */ + /* | RX_CFG1_FILTER_SSID */ + /* | RX_CFG1_FILTER_BCAST */ + /* | RX_CFG1_RCV_MC_ADDR1 */ + /* | RX_CFG1_RCV_MC_ADDR0 */ + /* | RX_CFG1_FILTER_ALL_MULTI */ + /* | RX_CFG1_FILTER_BSSID */ + /* | RX_CFG1_FILTER_MAC */ + | RX_CFG1_RCV_PROMISCUOUS + /* | RX_CFG1_INCLUDE_FCS */ + /* | RX_CFG1_INCLUDE_PHY_HDR */ + ); + adev->rx_config_2 = (u16) (0 + | RX_CFG2_RCV_ASSOC_REQ + | RX_CFG2_RCV_AUTH_FRAMES + | RX_CFG2_RCV_BEACON_FRAMES + | RX_CFG2_RCV_CONTENTION_FREE + | RX_CFG2_RCV_CTRL_FRAMES + | RX_CFG2_RCV_DATA_FRAMES + | RX_CFG2_RCV_BROKEN_FRAMES + | RX_CFG2_RCV_MGMT_FRAMES + | RX_CFG2_RCV_PROBE_REQ + | RX_CFG2_RCV_PROBE_RESP + | RX_CFG2_RCV_ACK_FRAMES + | RX_CFG2_RCV_OTHER + ); + break; + default: + adev->rx_config_1 = (u16) (0 + /* | RX_CFG1_INCLUDE_RXBUF_HDR */ + /* | RX_CFG1_FILTER_SSID */ + /* | RX_CFG1_FILTER_BCAST */ + /* | RX_CFG1_RCV_MC_ADDR1 */ + /* | RX_CFG1_RCV_MC_ADDR0 */ + /* | RX_CFG1_FILTER_ALL_MULTI */ + /* | RX_CFG1_FILTER_BSSID */ + | RX_CFG1_FILTER_MAC + /* | RX_CFG1_RCV_PROMISCUOUS */ + /* | RX_CFG1_INCLUDE_FCS */ + /* | RX_CFG1_INCLUDE_PHY_HDR */ + ); + adev->rx_config_2 = (u16) (0 + | RX_CFG2_RCV_ASSOC_REQ + | RX_CFG2_RCV_AUTH_FRAMES + | RX_CFG2_RCV_BEACON_FRAMES + | RX_CFG2_RCV_CONTENTION_FREE + | RX_CFG2_RCV_CTRL_FRAMES + | RX_CFG2_RCV_DATA_FRAMES + /*| RX_CFG2_RCV_BROKEN_FRAMES */ + | RX_CFG2_RCV_MGMT_FRAMES + | RX_CFG2_RCV_PROBE_REQ + | RX_CFG2_RCV_PROBE_RESP + /*| RX_CFG2_RCV_ACK_FRAMES */ + | RX_CFG2_RCV_OTHER + ); + break; + } + adev->rx_config_1 |= RX_CFG1_INCLUDE_RXBUF_HDR; + + if ((adev->rx_config_1 & RX_CFG1_INCLUDE_PHY_HDR) + || (adev->firmware_numver >= 0x02000000)) + adev->phy_header_len = IS_ACX111(adev) ? 8 : 4; + else + adev->phy_header_len = 0; + + log(L_INIT, "setting RXconfig to %04X:%04X\n", + adev->rx_config_1, adev->rx_config_2); + cfg.rx_cfg1 = cpu_to_le16(adev->rx_config_1); + cfg.rx_cfg2 = cpu_to_le16(adev->rx_config_2); + acx_s_configure(adev, &cfg, ACX1xx_IE_RXCONFIG); +} + + +/*********************************************************************** +** acx_s_set_defaults +*/ +void +acx_s_set_defaults(acx_device_t *adev) +{ + unsigned long flags; + + FN_ENTER; + + /* do it before getting settings, prevent bogus channel 0 warning */ + adev->channel = 1; + + /* query some settings from the card. + * NOTE: for some settings, e.g. CCA and ED (ACX100!), an initial + * query is REQUIRED, otherwise the card won't work correctly! */ + adev->get_mask = GETSET_ANTENNA|GETSET_SENSITIVITY|GETSET_STATION_ID|GETSET_REG_DOMAIN; + /* Only ACX100 supports ED and CCA */ + if (IS_ACX100(adev)) + adev->get_mask |= GETSET_CCA|GETSET_ED_THRESH; + + acx_s_update_card_settings(adev); + + acx_lock(adev, flags); + + /* set our global interrupt mask */ + if (IS_PCI(adev)) + acxpci_set_interrupt_mask(adev); + + adev->led_power = 1; /* LED is active on startup */ + adev->brange_max_quality = 60; /* LED blink max quality is 60 */ + adev->brange_time_last_state_change = jiffies; + + /* copy the MAC address we just got from the card + * into our MAC address used during current 802.11 session */ + MAC_COPY(adev->dev_addr, adev->ndev->dev_addr); + MAC_BCAST(adev->ap); + + adev->essid_len = + snprintf(adev->essid, sizeof(adev->essid), "STA%02X%02X%02X", + adev->dev_addr[3], adev->dev_addr[4], adev->dev_addr[5]); + adev->essid_active = 1; + + /* we have a nick field to waste, so why not abuse it + * to announce the driver version? ;-) */ + strncpy(adev->nick, "acx " ACX_RELEASE, IW_ESSID_MAX_SIZE); + + if (IS_PCI(adev)) { /* FIXME: this should be made to apply to USB, too! */ + /* first regulatory domain entry in EEPROM == default reg. domain */ + adev->reg_dom_id = adev->cfgopt_domains.list[0]; + } + + /* 0xffff would be better, but then we won't get a "scan complete" + * interrupt, so our current infrastructure will fail: */ + adev->scan_count = 1; + adev->scan_mode = ACX_SCAN_OPT_ACTIVE; + adev->scan_duration = 100; + adev->scan_probe_delay = 200; + /* reported to break scanning: adev->scan_probe_delay = adev->cfgopt_probe_delay; */ + adev->scan_rate = ACX_SCAN_RATE_1; + + adev->mode = ACX_MODE_2_STA; + adev->auth_alg = WLAN_AUTH_ALG_OPENSYSTEM; + adev->listen_interval = 100; + adev->beacon_interval = DEFAULT_BEACON_INTERVAL; + adev->dtim_interval = DEFAULT_DTIM_INTERVAL; + + adev->msdu_lifetime = DEFAULT_MSDU_LIFETIME; + + adev->rts_threshold = DEFAULT_RTS_THRESHOLD; + adev->frag_threshold = 2346; + + /* use standard default values for retry limits */ + adev->short_retry = 7; /* max. retries for (short) non-RTS packets */ + adev->long_retry = 4; /* max. retries for long (RTS) packets */ + + adev->preamble_mode = 2; /* auto */ + adev->fallback_threshold = 3; + adev->stepup_threshold = 10; + adev->rate_bcast = RATE111_1; + adev->rate_bcast100 = RATE100_1; + adev->rate_basic = RATE111_1 | RATE111_2; + adev->rate_auto = 1; + if (IS_ACX111(adev)) { + adev->rate_oper = RATE111_ALL; + } else { + adev->rate_oper = RATE111_ACX100_COMPAT; + } + + /* Supported Rates element - the rates here are given in units of + * 500 kbit/s, plus 0x80 added. See 802.11-1999.pdf item 7.3.2.2 */ + acx_l_update_ratevector(adev); + + /* set some more defaults */ + if (IS_ACX111(adev)) { + /* 30mW (15dBm) is default, at least in my acx111 card: */ + adev->tx_level_dbm = 15; + } else { + /* don't use max. level, since it might be dangerous + * (e.g. WRT54G people experience + * excessive Tx power damage!) */ + adev->tx_level_dbm = 18; + } + /* adev->tx_level_auto = 1; */ + if (IS_ACX111(adev)) { + /* start with sensitivity level 1 out of 3: */ + adev->sensitivity = 1; + } + +/* #define ENABLE_POWER_SAVE */ +#ifdef ENABLE_POWER_SAVE + adev->ps_wakeup_cfg = PS_CFG_ENABLE | PS_CFG_WAKEUP_ALL_BEAC; + adev->ps_listen_interval = 1; + adev->ps_options = PS_OPT_ENA_ENHANCED_PS | PS_OPT_TX_PSPOLL | PS_OPT_STILL_RCV_BCASTS; + adev->ps_hangover_period = 30; + adev->ps_enhanced_transition_time = 0; +#else + adev->ps_wakeup_cfg = 0; + adev->ps_listen_interval = 0; + adev->ps_options = 0; + adev->ps_hangover_period = 0; + adev->ps_enhanced_transition_time = 0; +#endif + + /* These settings will be set in fw on ifup */ + adev->set_mask = 0 + | GETSET_RETRY + | SET_MSDU_LIFETIME + /* configure card to do rate fallback when in auto rate mode */ + | SET_RATE_FALLBACK + | SET_RXCONFIG + | GETSET_TXPOWER + /* better re-init the antenna value we got above */ + | GETSET_ANTENNA +#if POWER_SAVE_80211 + | GETSET_POWER_80211 +#endif + ; + + acx_unlock(adev, flags); + acx_lock_unhold(); /* hold time 844814 CPU ticks @2GHz */ + + acx_s_initialize_rx_config(adev); + + FN_EXIT0; +} + + +/*********************************************************************** +** FIXME: this should be solved in a general way for all radio types +** by decoding the radio firmware module, +** since it probably has some standard structure describing how to +** set the power level of the radio module which it controls. +** Or maybe not, since the radio module probably has a function interface +** instead which then manages Tx level programming :-\ +*/ +static int +acx111_s_set_tx_level(acx_device_t *adev, u8 level_dbm) +{ + struct acx111_ie_tx_level tx_level; + + /* my acx111 card has two power levels in its configoptions (== EEPROM): + * 1 (30mW) [15dBm] + * 2 (10mW) [10dBm] + * For now, just assume all other acx111 cards have the same. + * FIXME: Ideally we would query it here, but we first need a + * standard way to query individual configoptions easily. + * Well, now we have proper cfgopt txpower variables, but this still + * hasn't been done yet, since it also requires dBm <-> mW conversion here... */ + if (level_dbm <= 12) { + tx_level.level = 2; /* 10 dBm */ + adev->tx_level_dbm = 10; + } else { + tx_level.level = 1; /* 15 dBm */ + adev->tx_level_dbm = 15; + } + if (level_dbm != adev->tx_level_dbm) + log(L_INIT, "acx111 firmware has specific " + "power levels only: adjusted %d dBm to %d dBm!\n", + level_dbm, adev->tx_level_dbm); + + return acx_s_configure(adev, &tx_level, ACX1xx_IE_DOT11_TX_POWER_LEVEL); +} + +static int +acx_s_set_tx_level(acx_device_t *adev, u8 level_dbm) +{ + if (IS_ACX111(adev)) { + return acx111_s_set_tx_level(adev, level_dbm); + } + if (IS_PCI(adev)) { + return acx100pci_s_set_tx_level(adev, level_dbm); + } + return OK; +} + + +/*********************************************************************** +*/ +#ifdef UNUSED +/* Returns the current tx level (ACX111) */ +static u8 +acx111_s_get_tx_level(acx_device_t *adev) +{ + struct acx111_ie_tx_level tx_level; + + tx_level.level = 0; + acx_s_interrogate(adev, &tx_level, ACX1xx_IE_DOT11_TX_POWER_LEVEL); + return tx_level.level; +} +#endif + + +/*********************************************************************** +** acx_l_rxmonitor +** Called from IRQ context only +*/ +static void +acx_l_rxmonitor(acx_device_t *adev, const rxbuffer_t *rxbuf) +{ + wlansniffrm_t *msg; + struct sk_buff *skb; + void *datap; + unsigned int skb_len; + int payload_offset; + + FN_ENTER; + + /* we are in big luck: the acx100 doesn't modify any of the fields */ + /* in the 802.11 frame. just pass this packet into the PF_PACKET */ + /* subsystem. yeah. */ + payload_offset = ((u8*)acx_get_wlan_hdr(adev, rxbuf) - (u8*)rxbuf); + skb_len = RXBUF_BYTES_USED(rxbuf) - payload_offset; + + /* sanity check */ + if (unlikely(skb_len > WLAN_A4FR_MAXLEN_WEP)) { + printk("%s: monitor mode panic: oversized frame!\n", + adev->ndev->name); + goto end; + } + + if (adev->ndev->type == ARPHRD_IEEE80211_PRISM) + skb_len += sizeof(*msg); + + /* allocate skb */ + skb = dev_alloc_skb(skb_len); + if (unlikely(!skb)) { + printk("%s: no memory for skb (%u bytes)\n", + adev->ndev->name, skb_len); + goto end; + } + + skb_put(skb, skb_len); + + if (adev->ndev->type == ARPHRD_IEEE80211) { + /* when in raw 802.11 mode, just copy frame as-is */ + datap = skb->data; + } else if (adev->ndev->type == ARPHRD_IEEE80211_PRISM) { + /* emulate prism header */ + msg = (wlansniffrm_t*)skb->data; + datap = msg + 1; + + msg->msgcode = WLANSNIFFFRM; + msg->msglen = sizeof(*msg); + strncpy(msg->devname, adev->ndev->name, sizeof(msg->devname)-1); + msg->devname[sizeof(msg->devname)-1] = '\0'; + + msg->hosttime.did = WLANSNIFFFRM_hosttime; + msg->hosttime.status = WLANITEM_STATUS_data_ok; + msg->hosttime.len = 4; + msg->hosttime.data = jiffies; + + msg->mactime.did = WLANSNIFFFRM_mactime; + msg->mactime.status = WLANITEM_STATUS_data_ok; + msg->mactime.len = 4; + msg->mactime.data = rxbuf->time; + + msg->channel.did = WLANSNIFFFRM_channel; + msg->channel.status = WLANITEM_STATUS_data_ok; + msg->channel.len = 4; + msg->channel.data = adev->channel; + + msg->rssi.did = WLANSNIFFFRM_rssi; + msg->rssi.status = WLANITEM_STATUS_no_value; + msg->rssi.len = 4; + msg->rssi.data = 0; + + msg->sq.did = WLANSNIFFFRM_sq; + msg->sq.status = WLANITEM_STATUS_no_value; + msg->sq.len = 4; + msg->sq.data = 0; + + msg->signal.did = WLANSNIFFFRM_signal; + msg->signal.status = WLANITEM_STATUS_data_ok; + msg->signal.len = 4; + msg->signal.data = rxbuf->phy_snr; + + msg->noise.did = WLANSNIFFFRM_noise; + msg->noise.status = WLANITEM_STATUS_data_ok; + msg->noise.len = 4; + msg->noise.data = rxbuf->phy_level; + + msg->rate.did = WLANSNIFFFRM_rate; + msg->rate.status = WLANITEM_STATUS_data_ok; + msg->rate.len = 4; + msg->rate.data = rxbuf->phy_plcp_signal / 5; + + msg->istx.did = WLANSNIFFFRM_istx; + msg->istx.status = WLANITEM_STATUS_data_ok; + msg->istx.len = 4; + msg->istx.data = 0; /* tx=0: it's not a tx packet */ + + skb_len -= sizeof(*msg); + + msg->frmlen.did = WLANSNIFFFRM_signal; + msg->frmlen.status = WLANITEM_STATUS_data_ok; + msg->frmlen.len = 4; + msg->frmlen.data = skb_len; + } else { + printk("acx: unsupported netdev type %d!\n", adev->ndev->type); + dev_kfree_skb(skb); + return; + } + + /* sanity check (keep it here) */ + if (unlikely((int)skb_len < 0)) { + printk("acx: skb_len=%d. Driver bug, please report\n", (int)skb_len); + dev_kfree_skb(skb); + return; + } + memcpy(datap, ((unsigned char*)rxbuf)+payload_offset, skb_len); + + skb->dev = adev->ndev; + skb->dev->last_rx = jiffies; + + skb_reset_mac_header(skb); + skb->ip_summed = CHECKSUM_NONE; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_80211_RAW); + netif_rx(skb); + + adev->stats.rx_packets++; + adev->stats.rx_bytes += skb->len; + +end: + FN_EXIT0; +} + + +/*********************************************************************** +** acx_l_rx_ieee802_11_frame +** +** Called from IRQ context only +*/ + +/* All these contortions are for saner dup logging +** +** We want: (a) to know about excessive dups +** (b) to not spam kernel log about occasional dups +** +** 1/64 threshold was chosen by running "ping -A" +** It gave "rx: 59 DUPs in 2878 packets" only with 4 parallel +** "ping -A" streams running. */ +/* 2005-10-11: bumped up to 1/8 +** subtract a $smallint from dup_count in order to +** avoid "2 DUPs in 19 packets" messages */ +static inline int +acx_l_handle_dup(acx_device_t *adev, u16 seq) +{ + if (adev->dup_count) { + adev->nondup_count++; + if (time_after(jiffies, adev->dup_msg_expiry)) { + /* Log only if more than 1 dup in 64 packets */ + if (adev->nondup_count/8 < adev->dup_count-5) { + printk(KERN_INFO "%s: rx: %d DUPs in " + "%d packets received in 10 secs\n", + adev->ndev->name, + adev->dup_count, + adev->nondup_count); + } + adev->dup_count = 0; + adev->nondup_count = 0; + } + } + if (unlikely(seq == adev->last_seq_ctrl)) { + if (!adev->dup_count++) + adev->dup_msg_expiry = jiffies + 10*HZ; + adev->stats.rx_errors++; + return 1; /* a dup */ + } + adev->last_seq_ctrl = seq; + return 0; +} + +static int +acx_l_rx_ieee802_11_frame(acx_device_t *adev, rxbuffer_t *rxbuf) +{ + unsigned int ftype, fstype; + const wlan_hdr_t *hdr; + int result = NOT_OK; + + FN_ENTER; + + hdr = acx_get_wlan_hdr(adev, rxbuf); + + /* see IEEE 802.11-1999.pdf chapter 7 "MAC frame formats" */ + if (unlikely((hdr->fc & WF_FC_PVERi) != 0)) { + printk_ratelimited(KERN_INFO "rx: unsupported 802.11 protocol\n"); + goto end; + } + + ftype = hdr->fc & WF_FC_FTYPEi; + fstype = hdr->fc & WF_FC_FSTYPEi; + + switch (ftype) { + /* check data frames first, for speed */ + case WF_FTYPE_DATAi: + switch (fstype) { + case WF_FSTYPE_DATAONLYi: + if (acx_l_handle_dup(adev, hdr->seq)) + break; /* a dup, simply discard it */ + + /* TODO: + if (WF_FC_FROMTODSi == (hdr->fc & WF_FC_FROMTODSi)) { + result = acx_l_process_data_frame_wds(adev, rxbuf); + break; + } + */ + + switch (adev->mode) { + case ACX_MODE_3_AP: + result = acx_l_process_data_frame_master(adev, rxbuf); + break; + case ACX_MODE_0_ADHOC: + case ACX_MODE_2_STA: + result = acx_l_process_data_frame_client(adev, rxbuf); + break; + } + case WF_FSTYPE_DATA_CFACKi: + case WF_FSTYPE_DATA_CFPOLLi: + case WF_FSTYPE_DATA_CFACK_CFPOLLi: + case WF_FSTYPE_CFPOLLi: + case WF_FSTYPE_CFACK_CFPOLLi: + /* see above. + acx_process_class_frame(adev, rxbuf, 3); */ + break; + case WF_FSTYPE_NULLi: + /* acx_l_process_NULL_frame(adev, rxbuf, 3); */ + break; + /* FIXME: same here, see above */ + case WF_FSTYPE_CFACKi: + default: + break; + } + break; + case WF_FTYPE_MGMTi: + result = acx_l_process_mgmt_frame(adev, rxbuf); + break; + case WF_FTYPE_CTLi: + if (fstype == WF_FSTYPE_PSPOLLi) + result = OK; + /* this call is irrelevant, since + * acx_process_class_frame is a stub, so return + * immediately instead. + * return acx_process_class_frame(adev, rxbuf, 3); */ + break; + default: + break; + } +end: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_l_process_rxbuf +** +** NB: used by USB code also +*/ +void +acx_l_process_rxbuf(acx_device_t *adev, rxbuffer_t *rxbuf) +{ + struct wlan_hdr *hdr; + unsigned int qual; + int buf_len; + u16 fc; + + hdr = acx_get_wlan_hdr(adev, rxbuf); + fc = le16_to_cpu(hdr->fc); + /* length of frame from control field to first byte of FCS */ + buf_len = RXBUF_BYTES_RCVD(adev, rxbuf); + + if ( ((WF_FC_FSTYPE & fc) != WF_FSTYPE_BEACON) + || (acx_debug & L_XFER_BEACON) + ) { + log(L_XFER|L_DATA, "rx: %s " + "time:%u len:%u signal:%u SNR:%u macstat:%02X " + "phystat:%02X phyrate:%u status:%u\n", + acx_get_packet_type_string(fc), + le32_to_cpu(rxbuf->time), + buf_len, + acx_signal_to_winlevel(rxbuf->phy_level), + acx_signal_to_winlevel(rxbuf->phy_snr), + rxbuf->mac_status, + rxbuf->phy_stat_baseband, + rxbuf->phy_plcp_signal, + adev->status); + } + + if (unlikely(acx_debug & L_DATA)) { + printk("rx: 802.11 buf[%u]: ", buf_len); + acx_dump_bytes(hdr, buf_len); + } + + /* FIXME: should check for Rx errors (rxbuf->mac_status? + * discard broken packets - but NOT for monitor!) + * and update Rx packet statistics here */ + + if (unlikely(adev->mode == ACX_MODE_MONITOR)) { + acx_l_rxmonitor(adev, rxbuf); + } else if (likely(buf_len >= WLAN_HDR_A3_LEN)) { + acx_l_rx_ieee802_11_frame(adev, rxbuf); + } else { + log(L_DEBUG|L_XFER|L_DATA, + "rx: NOT receiving packet (%s): " + "size too small (%u)\n", + acx_get_packet_type_string(fc), + buf_len); + } + + /* Now check Rx quality level, AFTER processing packet. + * I tried to figure out how to map these levels to dBm + * values, but for the life of me I really didn't + * manage to get it. Either these values are not meant to + * be expressed in dBm, or it's some pretty complicated + * calculation. */ + +#ifdef FROM_SCAN_SOURCE_ONLY + /* only consider packets originating from the MAC + * address of the device that's managing our BSSID. + * Disable it for now, since it removes information (levels + * from different peers) and slows the Rx path. */ + if (adev->ap_client + && mac_is_equal(hdr->a2, adev->ap_client->address)) { +#endif + adev->wstats.qual.level = acx_signal_to_winlevel(rxbuf->phy_level); + adev->wstats.qual.noise = acx_signal_to_winlevel(rxbuf->phy_snr); +#ifndef OLD_QUALITY + qual = acx_signal_determine_quality(adev->wstats.qual.level, + adev->wstats.qual.noise); +#else + qual = (adev->wstats.qual.noise <= 100) ? + 100 - adev->wstats.qual.noise : 0; +#endif + adev->wstats.qual.qual = qual; + adev->wstats.qual.updated = 7; /* all 3 indicators updated */ +#ifdef FROM_SCAN_SOURCE_ONLY + } +#endif +} + + +/*********************************************************************** +** acx_l_handle_txrate_auto +** +** Theory of operation: +** client->rate_cap is a bitmask of rates client is capable of. +** client->rate_cfg is a bitmask of allowed (configured) rates. +** It is set as a result of iwconfig rate N [auto] +** or iwpriv set_rates "N,N,N N,N,N" commands. +** It can be fixed (e.g. 0x0080 == 18Mbit only), +** auto (0x00ff == 18Mbit or any lower value), +** and code handles any bitmask (0x1081 == try 54Mbit,18Mbit,1Mbit _only_). +** +** client->rate_cur is a value for rate111 field in tx descriptor. +** It is always set to txrate_cfg sans zero or more most significant +** bits. This routine handles selection of new rate_cur value depending on +** outcome of last tx event. +** +** client->rate_100 is a precalculated rate value for acx100 +** (we can do without it, but will need to calculate it on each tx). +** +** You cannot configure mixed usage of 5.5 and/or 11Mbit rate +** with PBCC and CCK modulation. Either both at CCK or both at PBCC. +** In theory you can implement it, but so far it is considered not worth doing. +** +** 22Mbit, of course, is PBCC always. */ + +/* maps acx100 tx descr rate field to acx111 one */ +static u16 +rate100to111(u8 r) +{ + switch (r) { + case RATE100_1: return RATE111_1; + case RATE100_2: return RATE111_2; + case RATE100_5: + case (RATE100_5 | RATE100_PBCC511): return RATE111_5; + case RATE100_11: + case (RATE100_11 | RATE100_PBCC511): return RATE111_11; + case RATE100_22: return RATE111_22; + default: + printk("acx: unexpected acx100 txrate: %u! " + "Please report\n", r); + return RATE111_1; + } +} + + +void +acx_l_handle_txrate_auto(acx_device_t *adev, struct client *txc, + u16 cur, u8 rate100, u16 rate111, + u8 error, int pkts_to_ignore) +{ + u16 sent_rate; + int slower_rate_was_used; + + /* vda: hmm. current code will do this: + ** 1. send packets at 11 Mbit, stepup++ + ** 2. will try to send at 22Mbit. hardware will see no ACK, + ** retries at 11Mbit, success. code notes that used rate + ** is lower. stepup = 0, fallback++ + ** 3. repeat step 2 fallback_count times. Fall back to + ** 11Mbit. go to step 1. + ** If stepup_count is large (say, 16) and fallback_count + ** is small (3), this wouldn't be too bad wrt throughput */ + + if (unlikely(!cur)) { + printk("acx: BUG! ratemask is empty\n"); + return; /* or else we may lock up the box */ + } + + /* do some preparations, i.e. calculate the one rate that was + * used to send this packet */ + if (IS_ACX111(adev)) { + sent_rate = 1 << highest_bit(rate111 & RATE111_ALL); + } else { + sent_rate = rate100to111(rate100); + } + /* sent_rate has only one bit set now, corresponding to tx rate + * which was used by hardware to tx this particular packet */ + + /* now do the actual auto rate management */ + log(L_XFER, "tx: %sclient=%p/"MACSTR" used=%04X cur=%04X cfg=%04X " + "__=%u/%u ^^=%u/%u\n", + (txc->ignore_count > 0) ? "[IGN] " : "", + txc, MAC(txc->address), sent_rate, cur, txc->rate_cfg, + txc->fallback_count, adev->fallback_threshold, + txc->stepup_count, adev->stepup_threshold + ); + + /* we need to ignore old packets already in the tx queue since + * they use older rate bytes configured before our last rate change, + * otherwise our mechanism will get confused by interpreting old data. + * Do it after logging above */ + if (txc->ignore_count) { + txc->ignore_count--; + return; + } + + /* true only if the only nonzero bit in sent_rate is + ** less significant than highest nonzero bit in cur */ + slower_rate_was_used = ( cur > ((sent_rate<<1)-1) ); + + if (slower_rate_was_used || error) { + txc->stepup_count = 0; + if (++txc->fallback_count <= adev->fallback_threshold) + return; + txc->fallback_count = 0; + + /* clear highest 1 bit in cur */ + sent_rate = RATE111_54; + while (!(cur & sent_rate)) sent_rate >>= 1; + CLEAR_BIT(cur, sent_rate); + if (!cur) /* we can't disable all rates! */ + cur = sent_rate; + log(L_XFER, "tx: falling back to ratemask %04X\n", cur); + + } else { /* there was neither lower rate nor error */ + txc->fallback_count = 0; + if (++txc->stepup_count <= adev->stepup_threshold) + return; + txc->stepup_count = 0; + + /* Sanitize. Sort of not needed, but I dont trust hw that much... + ** what if it can report bogus tx rates sometimes? */ + while (!(cur & sent_rate)) sent_rate >>= 1; + + /* try to find a higher sent_rate that isn't yet in our + * current set, but is an allowed cfg */ + while (1) { + sent_rate <<= 1; + if (sent_rate > txc->rate_cfg) + /* no higher rates allowed by config */ + return; + if (!(cur & sent_rate) && (txc->rate_cfg & sent_rate)) + /* found */ + break; + /* not found, try higher one */ + } + SET_BIT(cur, sent_rate); + log(L_XFER, "tx: stepping up to ratemask %04X\n", cur); + } + + txc->rate_cur = cur; + txc->ignore_count = pkts_to_ignore; + /* calculate acx100 style rate byte if needed */ + if (IS_ACX100(adev)) { + txc->rate_100 = acx_bitpos2rate100[highest_bit(cur)]; + } +} + + +/*********************************************************************** +** acx_i_start_xmit +** +** Called by network core. Can be called outside of process context. +*/ +int +acx_i_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + acx_device_t *adev = ndev2adev(ndev); + tx_t *tx; + void *txbuf; + unsigned long flags; + int txresult = NOT_OK; + int len; + + FN_ENTER; + + if (unlikely(!skb)) { + /* indicate success */ + txresult = OK; + goto end_no_unlock; + } + if (unlikely(!adev)) { + goto end_no_unlock; + } + + acx_lock(adev, flags); + + if (unlikely(!(adev->dev_state_mask & ACX_STATE_IFACE_UP))) { + goto end; + } + if (unlikely(adev->mode == ACX_MODE_OFF)) { + goto end; + } + if (unlikely(acx_queue_stopped(ndev))) { + log(L_DEBUG, "%s: called when queue stopped\n", __func__); + goto end; + } + if (unlikely(ACX_STATUS_4_ASSOCIATED != adev->status)) { + log(L_XFER, "trying to xmit, but not associated yet: " + "aborting...\n"); + /* silently drop the packet, since we're not connected yet */ + txresult = OK; + /* ...but indicate an error nevertheless */ + adev->stats.tx_errors++; + goto end; + } + + tx = acx_l_alloc_tx(adev); + if (unlikely(!tx)) { + printk_ratelimited("%s: start_xmit: txdesc ring is full, " + "dropping tx\n", ndev->name); + txresult = NOT_OK; + goto end; + } + + txbuf = acx_l_get_txbuf(adev, tx); + if (unlikely(!txbuf)) { + /* Card was removed */ + txresult = NOT_OK; + acx_l_dealloc_tx(adev, tx); + goto end; + } + len = acx_ether_to_txbuf(adev, txbuf, skb); + if (unlikely(len < 0)) { + /* Error in packet conversion */ + txresult = NOT_OK; + acx_l_dealloc_tx(adev, tx); + goto end; + } + acx_l_tx_data(adev, tx, len); + ndev->trans_start = jiffies; + + txresult = OK; + adev->stats.tx_packets++; + adev->stats.tx_bytes += skb->len; + +end: + acx_unlock(adev, flags); + +end_no_unlock: + if ((txresult == OK) && skb) + dev_kfree_skb_any(skb); + + FN_EXIT1(txresult); + return txresult; +} + + +/*********************************************************************** +** acx_l_update_ratevector +** +** Updates adev->rate_supported[_len] according to rate_{basic,oper} +*/ +const u8 +acx_bitpos2ratebyte[] = { + DOT11RATEBYTE_1, + DOT11RATEBYTE_2, + DOT11RATEBYTE_5_5, + DOT11RATEBYTE_6_G, + DOT11RATEBYTE_9_G, + DOT11RATEBYTE_11, + DOT11RATEBYTE_12_G, + DOT11RATEBYTE_18_G, + DOT11RATEBYTE_22, + DOT11RATEBYTE_24_G, + DOT11RATEBYTE_36_G, + DOT11RATEBYTE_48_G, + DOT11RATEBYTE_54_G, +}; + +void +acx_l_update_ratevector(acx_device_t *adev) +{ + u16 bcfg = adev->rate_basic; + u16 ocfg = adev->rate_oper; + u8 *supp = adev->rate_supported; + const u8 *dot11 = acx_bitpos2ratebyte; + + FN_ENTER; + + while (ocfg) { + if (ocfg & 1) { + *supp = *dot11; + if (bcfg & 1) { + *supp |= 0x80; + } + supp++; + } + dot11++; + ocfg >>= 1; + bcfg >>= 1; + } + adev->rate_supported_len = supp - adev->rate_supported; + if (acx_debug & L_ASSOC) { + printk("new ratevector: "); + acx_dump_bytes(adev->rate_supported, adev->rate_supported_len); + } + FN_EXIT0; +} + + +/*********************************************************************** +** acx_l_sta_list_init +*/ +static void +acx_l_sta_list_init(acx_device_t *adev) +{ + FN_ENTER; + memset(adev->sta_hash_tab, 0, sizeof(adev->sta_hash_tab)); + memset(adev->sta_list, 0, sizeof(adev->sta_list)); + FN_EXIT0; +} + + +/*********************************************************************** +** acx_l_sta_list_get_from_hash +*/ +static inline client_t* +acx_l_sta_list_get_from_hash(acx_device_t *adev, const u8 *address) +{ + return adev->sta_hash_tab[address[5] % VEC_SIZE(adev->sta_hash_tab)]; +} + + +/*********************************************************************** +** acx_l_sta_list_get +*/ +client_t* +acx_l_sta_list_get(acx_device_t *adev, const u8 *address) +{ + client_t *client; + FN_ENTER; + client = acx_l_sta_list_get_from_hash(adev, address); + while (client) { + if (mac_is_equal(address, client->address)) { + client->mtime = jiffies; + break; + } + client = client->next; + } + FN_EXIT0; + return client; +} + + +/*********************************************************************** +** acx_l_sta_list_del +*/ +void +acx_l_sta_list_del(acx_device_t *adev, client_t *victim) +{ + client_t *client, *next; + + client = acx_l_sta_list_get_from_hash(adev, victim->address); + next = client; + /* tricky. next = client on first iteration only, + ** on all other iters next = client->next */ + while (next) { + if (next == victim) { + client->next = victim->next; + /* Overkill */ + memset(victim, 0, sizeof(*victim)); + break; + } + client = next; + next = client->next; + } +} + + +/*********************************************************************** +** acx_l_sta_list_alloc +** +** Never fails - will evict oldest client if needed +*/ +static client_t* +acx_l_sta_list_alloc(acx_device_t *adev) +{ + int i; + unsigned long age, oldest_age; + client_t *client, *oldest; + + FN_ENTER; + + oldest = &adev->sta_list[0]; + oldest_age = 0; + for (i = 0; i < VEC_SIZE(adev->sta_list); i++) { + client = &adev->sta_list[i]; + + if (!client->used) { + goto found; + } else { + age = jiffies - client->mtime; + if (oldest_age < age) { + oldest_age = age; + oldest = client; + } + } + } + acx_l_sta_list_del(adev, oldest); + client = oldest; +found: + memset(client, 0, sizeof(*client)); + FN_EXIT0; + return client; +} + + +/*********************************************************************** +** acx_l_sta_list_add +** +** Never fails - will evict oldest client if needed +*/ +/* In case we will reimplement it differently... */ +#define STA_LIST_ADD_CAN_FAIL 0 + +static client_t* +acx_l_sta_list_add(acx_device_t *adev, const u8 *address) +{ + client_t *client; + int index; + + FN_ENTER; + + client = acx_l_sta_list_alloc(adev); + + client->mtime = jiffies; + MAC_COPY(client->address, address); + client->used = CLIENT_EXIST_1; + client->auth_alg = WLAN_AUTH_ALG_SHAREDKEY; + client->auth_step = 1; + /* give some tentative peer rate values + ** (needed because peer may do auth without probing us first, + ** thus we'll have no idea of peer's ratevector yet). + ** Will be overwritten by scanning or assoc code */ + client->rate_cap = adev->rate_basic; + client->rate_cfg = adev->rate_basic; + client->rate_cur = 1 << lowest_bit(adev->rate_basic); + + index = address[5] % VEC_SIZE(adev->sta_hash_tab); + client->next = adev->sta_hash_tab[index]; + adev->sta_hash_tab[index] = client; + + acxlog_mac(L_ASSOC, "sta_list_add: sta=", address, "\n"); + + FN_EXIT0; + return client; +} + + +/*********************************************************************** +** acx_l_sta_list_get_or_add +** +** Never fails - will evict oldest client if needed +*/ +static client_t* +acx_l_sta_list_get_or_add(acx_device_t *adev, const u8 *address) +{ + client_t *client = acx_l_sta_list_get(adev, address); + if (!client) + client = acx_l_sta_list_add(adev, address); + return client; +} + + +/*********************************************************************** +** acx_set_status +** +** This function is called in many atomic regions, must not sleep +** +** This function does not need locking UNLESS you call it +** as acx_set_status(ACX_STATUS_4_ASSOCIATED), bacause this can +** wake queue. This can race with stop_queue elsewhere. +** See acx_stop_queue comment. */ +void +acx_set_status(acx_device_t *adev, u16 new_status) +{ +#define QUEUE_OPEN_AFTER_ASSOC 1 /* this really seems to be needed now */ + u16 old_status = adev->status; + + FN_ENTER; + + log(L_ASSOC, "%s(%d):%s\n", + __func__, new_status, acx_get_status_name(new_status)); + + /* wireless_send_event never sleeps */ + if (ACX_STATUS_4_ASSOCIATED == new_status) { + union iwreq_data wrqu; + + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(adev->ndev, SIOCGIWSCAN, &wrqu, NULL); + + wrqu.data.length = 0; + wrqu.data.flags = 0; + MAC_COPY(wrqu.ap_addr.sa_data, adev->bssid); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(adev->ndev, SIOCGIWAP, &wrqu, NULL); + } else { + union iwreq_data wrqu; + + /* send event with empty BSSID to indicate we're not associated */ + MAC_ZERO(wrqu.ap_addr.sa_data); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(adev->ndev, SIOCGIWAP, &wrqu, NULL); + } + + adev->status = new_status; + + switch (new_status) { + case ACX_STATUS_1_SCANNING: + adev->scan_retries = 0; + /* 1.0 s initial scan time */ + acx_set_timer(adev, 1000000); + break; + case ACX_STATUS_2_WAIT_AUTH: + case ACX_STATUS_3_AUTHENTICATED: + adev->auth_or_assoc_retries = 0; + acx_set_timer(adev, 1500000); /* 1.5 s */ + break; + } + +#if QUEUE_OPEN_AFTER_ASSOC + if (new_status == ACX_STATUS_4_ASSOCIATED) { + if (old_status < ACX_STATUS_4_ASSOCIATED) { + /* ah, we're newly associated now, + * so let's indicate carrier */ + acx_carrier_on(adev->ndev, "after association"); + acx_wake_queue(adev->ndev, "after association"); + } + } else { + /* not associated any more, so let's kill carrier */ + if (old_status >= ACX_STATUS_4_ASSOCIATED) { + acx_carrier_off(adev->ndev, "after losing association"); + acx_stop_queue(adev->ndev, "after losing association"); + } + } +#endif + FN_EXIT0; +} + + +/*********************************************************************** +** acx_i_timer +** +** Fires up periodically. Used to kick scan/auth/assoc if something goes wrong +*/ +void +acx_i_timer(unsigned long address) +{ + unsigned long flags; + acx_device_t *adev = (acx_device_t*)address; + + FN_ENTER; + + acx_lock(adev, flags); + + log(L_DEBUG|L_ASSOC, "%s: adev->status=%d (%s)\n", + __func__, adev->status, acx_get_status_name(adev->status)); + + switch (adev->status) { + case ACX_STATUS_1_SCANNING: + /* was set to 0 by set_status() */ + if (++adev->scan_retries < 7) { + acx_set_timer(adev, 1000000); + /* used to interrogate for scan status. + ** We rely on SCAN_COMPLETE IRQ instead */ + log(L_ASSOC, "continuing scan (%d sec)\n", + adev->scan_retries); + } else { + log(L_ASSOC, "stopping scan\n"); + /* send stop_scan cmd when we leave the interrupt context, + * and make a decision what to do next (COMPLETE_SCAN) */ + acx_schedule_task(adev, + ACX_AFTER_IRQ_CMD_STOP_SCAN + ACX_AFTER_IRQ_COMPLETE_SCAN); + } + break; + case ACX_STATUS_2_WAIT_AUTH: + /* was set to 0 by set_status() */ + if (++adev->auth_or_assoc_retries < 10) { + log(L_ASSOC, "resend authen1 request (attempt %d)\n", + adev->auth_or_assoc_retries + 1); + acx_l_transmit_authen1(adev); + } else { + /* time exceeded: fall back to scanning mode */ + log(L_ASSOC, + "authen1 request reply timeout, giving up\n"); + /* we are a STA, need to find AP anyhow */ + acx_set_status(adev, ACX_STATUS_1_SCANNING); + acx_schedule_task(adev, ACX_AFTER_IRQ_RESTART_SCAN); + } + /* used to be 1500000, but some other driver uses 2.5s */ + acx_set_timer(adev, 2500000); + break; + case ACX_STATUS_3_AUTHENTICATED: + /* was set to 0 by set_status() */ + if (++adev->auth_or_assoc_retries < 10) { + log(L_ASSOC, "resend assoc request (attempt %d)\n", + adev->auth_or_assoc_retries + 1); + acx_l_transmit_assoc_req(adev); + } else { + /* time exceeded: give up */ + log(L_ASSOC, + "association request reply timeout, giving up\n"); + /* we are a STA, need to find AP anyhow */ + acx_set_status(adev, ACX_STATUS_1_SCANNING); + acx_schedule_task(adev, ACX_AFTER_IRQ_RESTART_SCAN); + } + acx_set_timer(adev, 2500000); /* see above */ + break; + case ACX_STATUS_4_ASSOCIATED: + default: + break; + } + + acx_unlock(adev, flags); + + FN_EXIT0; +} + + +/*********************************************************************** +** acx_set_timer +** +** Sets the 802.11 state management timer's timeout. +*/ +void +acx_set_timer(acx_device_t *adev, int timeout_us) +{ + FN_ENTER; + + log(L_DEBUG|L_IRQ, "%s(%u ms)\n", __func__, timeout_us/1000); + if (!(adev->dev_state_mask & ACX_STATE_IFACE_UP)) { + printk("attempt to set the timer " + "when the card interface is not up!\n"); + goto end; + } + + /* first check if the timer was already initialized, THEN modify it */ + if (adev->mgmt_timer.function) { + mod_timer(&adev->mgmt_timer, + jiffies + (timeout_us * HZ / 1000000)); + } +end: + FN_EXIT0; +} + + +/*********************************************************************** +** acx_l_transmit_assocresp +** +** We are an AP here +*/ +static const u8 +dot11ratebyte[] = { + DOT11RATEBYTE_1, + DOT11RATEBYTE_2, + DOT11RATEBYTE_5_5, + DOT11RATEBYTE_6_G, + DOT11RATEBYTE_9_G, + DOT11RATEBYTE_11, + DOT11RATEBYTE_12_G, + DOT11RATEBYTE_18_G, + DOT11RATEBYTE_22, + DOT11RATEBYTE_24_G, + DOT11RATEBYTE_36_G, + DOT11RATEBYTE_48_G, + DOT11RATEBYTE_54_G, +}; + +static inline int +find_pos(const u8 *p, int size, u8 v) +{ + int i; + for (i = 0; i < size; i++) + if (p[i] == v) + return i; + /* printk a message about strange byte? */ + return 0; +} + +static void +add_bits_to_ratemasks(u8* ratevec, int len, u16* brate, u16* orate) +{ + while (len--) { + int n = 1 << find_pos(dot11ratebyte, + sizeof(dot11ratebyte), *ratevec & 0x7f); + if (*ratevec & 0x80) + *brate |= n; + *orate |= n; + ratevec++; + } +} + +static int +acx_l_transmit_assocresp(acx_device_t *adev, const wlan_fr_assocreq_t *req) +{ + struct tx *tx; + struct wlan_hdr_mgmt *head; + struct assocresp_frame_body *body; + u8 *p; + const u8 *da; + /* const u8 *sa; */ + const u8 *bssid; + client_t *clt; + + FN_ENTER; + + /* sa = req->hdr->a1; */ + da = req->hdr->a2; + bssid = req->hdr->a3; + + clt = acx_l_sta_list_get(adev, da); + if (!clt) + goto ok; + + /* Assoc without auth is a big no-no */ + /* Let's be liberal: if already assoc'ed STA sends assoc req again, + ** we won't be rude */ + if (clt->used != CLIENT_AUTHENTICATED_2 + && clt->used != CLIENT_ASSOCIATED_3) { + acx_l_transmit_deauthen(adev, da, WLAN_MGMT_REASON_CLASS2_NONAUTH); + goto bad; + } + + clt->used = CLIENT_ASSOCIATED_3; + + if (clt->aid == 0) + clt->aid = ++adev->aid; + clt->cap_info = ieee2host16(*(req->cap_info)); + + /* We cheat here a bit. We don't really care which rates are flagged + ** as basic by the client, so we stuff them in single ratemask */ + clt->rate_cap = 0; + if (req->supp_rates) + add_bits_to_ratemasks(req->supp_rates->rates, + req->supp_rates->len, &clt->rate_cap, &clt->rate_cap); + if (req->ext_rates) + add_bits_to_ratemasks(req->ext_rates->rates, + req->ext_rates->len, &clt->rate_cap, &clt->rate_cap); + /* We can check that client supports all basic rates, + ** and deny assoc if not. But let's be liberal, right? ;) */ + clt->rate_cfg = clt->rate_cap & adev->rate_oper; + if (!clt->rate_cfg) clt->rate_cfg = 1 << lowest_bit(adev->rate_oper); + clt->rate_cur = 1 << lowest_bit(clt->rate_cfg); + if (IS_ACX100(adev)) + clt->rate_100 = acx_bitpos2rate100[lowest_bit(clt->rate_cfg)]; + clt->fallback_count = clt->stepup_count = 0; + clt->ignore_count = 16; + + tx = acx_l_alloc_tx(adev); + if (!tx) + goto bad; + head = acx_l_get_txbuf(adev, tx); + if (!head) { + acx_l_dealloc_tx(adev, tx); + goto bad; + } + body = (void*)(head + 1); + + head->fc = WF_FSTYPE_ASSOCRESPi; + head->dur = req->hdr->dur; + MAC_COPY(head->da, da); + MAC_COPY(head->sa, adev->dev_addr); + MAC_COPY(head->bssid, bssid); + head->seq = req->hdr->seq; + + body->cap_info = host2ieee16(adev->capabilities); + body->status = host2ieee16(0); + body->aid = host2ieee16(clt->aid); + p = wlan_fill_ie_rates((u8*)&body->rates, adev->rate_supported_len, + adev->rate_supported); + p = wlan_fill_ie_rates_ext(p, adev->rate_supported_len, + adev->rate_supported); + + acx_l_tx_data(adev, tx, p - (u8*)head); +ok: + FN_EXIT1(OK); + return OK; +bad: + FN_EXIT1(NOT_OK); + return NOT_OK; +} + + +/*********************************************************************** +* acx_l_transmit_reassocresp + +You may be wondering, just like me, what the hell ReAuth is. +In practice it was seen sent by STA when STA feels like losing connection. + +[802.11] + +5.4.2.3 Reassociation + +Association is sufficient for no-transition message delivery between +IEEE 802.11 stations. Additional functionality is needed to support +BSS-transition mobility. The additional required functionality +is provided by the reassociation service. Reassociation is a DSS. +The reassociation service is invoked to 'move' a current association +from one AP to another. This keeps the DS informed of the current +mapping between AP and STA as the station moves from BSS to BSS within +an ESS. Reassociation also enables changing association attributes +of an established association while the STA remains associated with +the same AP. Reassociation is always initiated by the mobile STA. + +5.4.3.1 Authentication +... +A STA may be authenticated with many other STAs at any given instant. + +5.4.3.1.1 Preauthentication + +Because the authentication process could be time-consuming (depending +on the authentication protocol in use), the authentication service can +be invoked independently of the association service. Preauthentication +is typically done by a STA while it is already associated with an AP +(with which it previously authenticated). IEEE 802.11 does not require +that STAs preauthenticate with APs. However, authentication is required +before an association can be established. If the authentication is left +until reassociation time, this may impact the speed with which a STA can +reassociate between APs, limiting BSS-transition mobility performance. +The use of preauthentication takes the authentication service overhead +out of the time-critical reassociation process. + +5.7.3 Reassociation + +For a STA to reassociate, the reassociation service causes the following +message to occur: + + Reassociation request + +* Message type: Management +* Message subtype: Reassociation request +* Information items: + - IEEE address of the STA + - IEEE address of the AP with which the STA will reassociate + - IEEE address of the AP with which the STA is currently associated + - ESSID +* Direction of message: From STA to 'new' AP + +The address of the current AP is included for efficiency. The inclusion +of the current AP address facilitates MAC reassociation to be independent +of the DS implementation. + + Reassociation response +* Message type: Management +* Message subtype: Reassociation response +* Information items: + - Result of the requested reassociation. (success/failure) + - If the reassociation is successful, the response shall include the AID. +* Direction of message: From AP to STA + +7.2.3.6 Reassociation Request frame format + +The frame body of a management frame of subtype Reassociation Request +contains the information shown in Table 9. + +Table 9 Reassociation Request frame body +Order Information +1 Capability information +2 Listen interval +3 Current AP address +4 SSID +5 Supported rates + +7.2.3.7 Reassociation Response frame format + +The frame body of a management frame of subtype Reassociation Response +contains the information shown in Table 10. + +Table 10 Reassociation Response frame body +Order Information +1 Capability information +2 Status code +3 Association ID (AID) +4 Supported rates + +*/ +static int +acx_l_transmit_reassocresp(acx_device_t *adev, const wlan_fr_reassocreq_t *req) +{ + struct tx *tx; + struct wlan_hdr_mgmt *head; + struct reassocresp_frame_body *body; + u8 *p; + const u8 *da; + /* const u8 *sa; */ + const u8 *bssid; + client_t *clt; + + FN_ENTER; + + /* sa = req->hdr->a1; */ + da = req->hdr->a2; + bssid = req->hdr->a3; + + /* Must be already authenticated, so it must be in the list */ + clt = acx_l_sta_list_get(adev, da); + if (!clt) + goto ok; + + /* Assoc without auth is a big no-no */ + /* Already assoc'ed STAs sending ReAssoc req are ok per 802.11 */ + if (clt->used != CLIENT_AUTHENTICATED_2 + && clt->used != CLIENT_ASSOCIATED_3) { + acx_l_transmit_deauthen(adev, da, WLAN_MGMT_REASON_CLASS2_NONAUTH); + goto bad; + } + + clt->used = CLIENT_ASSOCIATED_3; + if (clt->aid == 0) { + clt->aid = ++adev->aid; + } + if (req->cap_info) + clt->cap_info = ieee2host16(*(req->cap_info)); + + /* We cheat here a bit. We don't really care which rates are flagged + ** as basic by the client, so we stuff them in single ratemask */ + clt->rate_cap = 0; + if (req->supp_rates) + add_bits_to_ratemasks(req->supp_rates->rates, + req->supp_rates->len, &clt->rate_cap, &clt->rate_cap); + if (req->ext_rates) + add_bits_to_ratemasks(req->ext_rates->rates, + req->ext_rates->len, &clt->rate_cap, &clt->rate_cap); + /* We can check that client supports all basic rates, + ** and deny assoc if not. But let's be liberal, right? ;) */ + clt->rate_cfg = clt->rate_cap & adev->rate_oper; + if (!clt->rate_cfg) clt->rate_cfg = 1 << lowest_bit(adev->rate_oper); + clt->rate_cur = 1 << lowest_bit(clt->rate_cfg); + if (IS_ACX100(adev)) + clt->rate_100 = acx_bitpos2rate100[lowest_bit(clt->rate_cfg)]; + + clt->fallback_count = clt->stepup_count = 0; + clt->ignore_count = 16; + + tx = acx_l_alloc_tx(adev); + if (!tx) + goto ok; + head = acx_l_get_txbuf(adev, tx); + if (!head) { + acx_l_dealloc_tx(adev, tx); + goto ok; + } + body = (void*)(head + 1); + + head->fc = WF_FSTYPE_REASSOCRESPi; + head->dur = req->hdr->dur; + MAC_COPY(head->da, da); + MAC_COPY(head->sa, adev->dev_addr); + MAC_COPY(head->bssid, bssid); + head->seq = req->hdr->seq; + + /* IEs: 1. caps */ + body->cap_info = host2ieee16(adev->capabilities); + /* 2. status code */ + body->status = host2ieee16(0); + /* 3. AID */ + body->aid = host2ieee16(clt->aid); + /* 4. supp rates */ + p = wlan_fill_ie_rates((u8*)&body->rates, adev->rate_supported_len, + adev->rate_supported); + /* 5. ext supp rates */ + p = wlan_fill_ie_rates_ext(p, adev->rate_supported_len, + adev->rate_supported); + + acx_l_tx_data(adev, tx, p - (u8*)head); +ok: + FN_EXIT1(OK); + return OK; +bad: + FN_EXIT1(NOT_OK); + return NOT_OK; +} + + +/*********************************************************************** +** acx_l_process_disassoc_from_sta +*/ +static void +acx_l_process_disassoc_from_sta(acx_device_t *adev, const wlan_fr_disassoc_t *req) +{ + const u8 *ta; + client_t *clt; + + FN_ENTER; + + ta = req->hdr->a2; + clt = acx_l_sta_list_get(adev, ta); + if (!clt) + goto end; + + if (clt->used != CLIENT_ASSOCIATED_3 + && clt->used != CLIENT_AUTHENTICATED_2) { + /* it's disassociating, but it's + ** not even authenticated! Let it know that */ + acxlog_mac(L_ASSOC|L_XFER, "peer ", ta, "has sent disassoc " + "req but it is not even auth'ed! sending deauth\n"); + acx_l_transmit_deauthen(adev, ta, + WLAN_MGMT_REASON_CLASS2_NONAUTH); + clt->used = CLIENT_EXIST_1; + } else { + /* mark it as auth'ed only */ + clt->used = CLIENT_AUTHENTICATED_2; + } +end: + FN_EXIT0; +} + + +/*********************************************************************** +** acx_l_process_deauthen_from_sta +*/ +static void +acx_l_process_deauth_from_sta(acx_device_t *adev, const wlan_fr_deauthen_t *req) +{ + const wlan_hdr_t *hdr; + client_t *client; + + FN_ENTER; + + hdr = req->hdr; + + if (acx_debug & L_ASSOC) { + acx_print_mac("got deauth from sta:", hdr->a2, " "); + acx_print_mac("a1:", hdr->a1, " "); + acx_print_mac("a3:", hdr->a3, " "); + acx_print_mac("adev->addr:", adev->dev_addr, " "); + acx_print_mac("adev->bssid:", adev->bssid, "\n"); + } + + if (!mac_is_equal(adev->dev_addr, hdr->a1)) { + goto end; + } + + client = acx_l_sta_list_get(adev, hdr->a2); + if (!client) { + goto end; + } + client->used = CLIENT_EXIST_1; +end: + FN_EXIT0; +} + + +/*********************************************************************** +** acx_l_process_disassoc_from_ap +*/ +static void +acx_l_process_disassoc_from_ap(acx_device_t *adev, const wlan_fr_disassoc_t *req) +{ + FN_ENTER; + + if (!adev->ap_client) { + /* Hrm, we aren't assoc'ed yet anyhow... */ + goto end; + } + + printk("%s: got disassoc frame with reason %d (%s)\n", + adev->ndev->name, *req->reason, + acx_wlan_reason_str(*req->reason)); + + if (mac_is_equal(adev->dev_addr, req->hdr->a1)) { + acx_l_transmit_deauthen(adev, adev->bssid, + WLAN_MGMT_REASON_DEAUTH_LEAVING); + SET_BIT(adev->set_mask, GETSET_RESCAN); + acx_schedule_task(adev, ACX_AFTER_IRQ_UPDATE_CARD_CFG); + } +end: + FN_EXIT0; +} + + +/*********************************************************************** +** acx_l_process_deauth_from_ap +*/ +static void +acx_l_process_deauth_from_ap(acx_device_t *adev, const wlan_fr_deauthen_t *req) +{ + FN_ENTER; + + if (!adev->ap_client) { + /* Hrm, we aren't assoc'ed yet anyhow... */ + goto end; + } + + printk("%s: got deauth frame with reason %d (%s)\n", + adev->ndev->name, *req->reason, + acx_wlan_reason_str(*req->reason)); + + /* Chk: is ta verified to be from our AP? */ + if (mac_is_equal(adev->dev_addr, req->hdr->a1)) { + log(L_DEBUG, "AP sent us deauth packet\n"); + SET_BIT(adev->set_mask, GETSET_RESCAN); + acx_schedule_task(adev, ACX_AFTER_IRQ_UPDATE_CARD_CFG); + } +end: + FN_EXIT0; +} + + +/*********************************************************************** +** acx_l_rx +** +** The end of the Rx path. Pulls data from a rxhostdesc into a socket +** buffer and feeds it to the network stack via netif_rx(). +*/ +static void +acx_l_rx(acx_device_t *adev, rxbuffer_t *rxbuf) +{ + FN_ENTER; + if (likely(adev->dev_state_mask & ACX_STATE_IFACE_UP)) { + struct sk_buff *skb; + skb = acx_rxbuf_to_ether(adev, rxbuf); + if (likely(skb)) { + netif_rx(skb); + adev->ndev->last_rx = jiffies; + adev->stats.rx_packets++; + adev->stats.rx_bytes += skb->len; + } + } + FN_EXIT0; +} + + +/*********************************************************************** +** acx_l_process_data_frame_master +*/ +static int +acx_l_process_data_frame_master(acx_device_t *adev, rxbuffer_t *rxbuf) +{ + struct wlan_hdr *hdr; + struct tx *tx; + void *txbuf; + int len; + int result = NOT_OK; + + FN_ENTER; + + hdr = acx_get_wlan_hdr(adev, rxbuf); + + switch (WF_FC_FROMTODSi & hdr->fc) { + case 0: + case WF_FC_FROMDSi: + log(L_DEBUG, "ap->sta or adhoc->adhoc data frame ignored\n"); + goto done; + case WF_FC_TODSi: + break; + default: /* WF_FC_FROMTODSi */ + log(L_DEBUG, "wds data frame ignored (TODO)\n"); + goto done; + } + + /* check if it is our BSSID, if not, leave */ + if (!mac_is_equal(adev->bssid, hdr->a1)) { + goto done; + } + + if (mac_is_equal(adev->dev_addr, hdr->a3)) { + /* this one is for us */ + acx_l_rx(adev, rxbuf); + } else { + if (mac_is_bcast(hdr->a3)) { + /* this one is bcast, rx it too */ + acx_l_rx(adev, rxbuf); + } + tx = acx_l_alloc_tx(adev); + if (!tx) { + goto fail; + } + /* repackage, tx, and hope it someday reaches its destination */ + /* order is important, we do it in-place */ + MAC_COPY(hdr->a1, hdr->a3); + MAC_COPY(hdr->a3, hdr->a2); + MAC_COPY(hdr->a2, adev->bssid); + /* To_DS = 0, From_DS = 1 */ + hdr->fc = WF_FC_FROMDSi + WF_FTYPE_DATAi; + + txbuf = acx_l_get_txbuf(adev, tx); + if (txbuf) { + len = RXBUF_BYTES_RCVD(adev, rxbuf); + memcpy(txbuf, hdr, len); + acx_l_tx_data(adev, tx, len); + } else { + acx_l_dealloc_tx(adev, tx); + } + } +done: + result = OK; +fail: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_l_process_data_frame_client +*/ +static int +acx_l_process_data_frame_client(acx_device_t *adev, rxbuffer_t *rxbuf) +{ + const u8 *da, *bssid; + const wlan_hdr_t *hdr; + struct net_device *ndev = adev->ndev; + int result = NOT_OK; + + FN_ENTER; + + if (ACX_STATUS_4_ASSOCIATED != adev->status) + goto drop; + + hdr = acx_get_wlan_hdr(adev, rxbuf); + + switch (WF_FC_FROMTODSi & hdr->fc) { + case 0: + if (adev->mode != ACX_MODE_0_ADHOC) { + log(L_DEBUG, "adhoc->adhoc data frame ignored\n"); + goto drop; + } + bssid = hdr->a3; + break; + case WF_FC_FROMDSi: + if (adev->mode != ACX_MODE_2_STA) { + log(L_DEBUG, "ap->sta data frame ignored\n"); + goto drop; + } + bssid = hdr->a2; + break; + case WF_FC_TODSi: + log(L_DEBUG, "sta->ap data frame ignored\n"); + goto drop; + default: /* WF_FC_FROMTODSi: wds->wds */ + log(L_DEBUG, "wds data frame ignored (todo)\n"); + goto drop; + } + + da = hdr->a1; + + if (unlikely(acx_debug & L_DEBUG)) { + acx_print_mac("rx: da=", da, ""); + acx_print_mac(" bssid=", bssid, ""); + acx_print_mac(" adev->bssid=", adev->bssid, ""); + acx_print_mac(" adev->addr=", adev->dev_addr, "\n"); + } + + /* promiscuous mode --> receive all packets */ + if (unlikely(ndev->flags & IFF_PROMISC)) + goto process; + + /* FIRST, check if it is our BSSID */ + if (!mac_is_equal(adev->bssid, bssid)) { + /* is not our BSSID, so bail out */ + goto drop; + } + + /* then, check if it is our address */ + if (mac_is_equal(adev->dev_addr, da)) { + goto process; + } + + /* then, check if it is broadcast */ + if (mac_is_bcast(da)) { + goto process; + } + + if (mac_is_mcast(da)) { + /* unconditionally receive all multicasts */ + if (ndev->flags & IFF_ALLMULTI) + goto process; + + /* FIXME: need to check against the list of + * multicast addresses that are configured + * for the interface (ifconfig) */ + log(L_XFER, "FIXME: multicast packet, need to check " + "against a list of multicast addresses " + "(to be created!); accepting packet for now\n"); + /* for now, just accept it here */ + goto process; + } + + log(L_DEBUG, "rx: foreign packet, dropping\n"); + goto drop; +process: + /* receive packet */ + acx_l_rx(adev, rxbuf); + + result = OK; +drop: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_l_process_mgmt_frame +** +** Theory of operation: mgmt packet gets parsed (to make it easy +** to access variable-sized IEs), results stored in 'parsed'. +** Then we react to the packet. +*/ +typedef union parsed_mgmt_req { + wlan_fr_mgmt_t mgmt; + wlan_fr_assocreq_t assocreq; + wlan_fr_reassocreq_t reassocreq; + wlan_fr_assocresp_t assocresp; + wlan_fr_reassocresp_t reassocresp; + wlan_fr_beacon_t beacon; + wlan_fr_disassoc_t disassoc; + wlan_fr_authen_t authen; + wlan_fr_deauthen_t deauthen; + wlan_fr_proberesp_t proberesp; +} parsed_mgmt_req_t; + +void BUG_excessive_stack_usage(void); + +static int +acx_l_process_mgmt_frame(acx_device_t *adev, rxbuffer_t *rxbuf) +{ + parsed_mgmt_req_t parsed; /* takes ~100 bytes of stack */ + wlan_hdr_t *hdr; + int adhoc, sta_scan, sta, ap; + int len; + + if (sizeof(parsed) > 256) + BUG_excessive_stack_usage(); + + FN_ENTER; + + hdr = acx_get_wlan_hdr(adev, rxbuf); + + /* Management frames never have these set */ + if (WF_FC_FROMTODSi & hdr->fc) { + FN_EXIT1(NOT_OK); + return NOT_OK; + } + + len = RXBUF_BYTES_RCVD(adev, rxbuf); + if (WF_FC_ISWEPi & hdr->fc) + len -= 0x10; + + adhoc = (adev->mode == ACX_MODE_0_ADHOC); + sta_scan = ((adev->mode == ACX_MODE_2_STA) + && (adev->status != ACX_STATUS_4_ASSOCIATED)); + sta = ((adev->mode == ACX_MODE_2_STA) + && (adev->status == ACX_STATUS_4_ASSOCIATED)); + ap = (adev->mode == ACX_MODE_3_AP); + + switch (WF_FC_FSTYPEi & hdr->fc) { + /* beacons first, for speed */ + case WF_FSTYPE_BEACONi: + memset(&parsed.beacon, 0, sizeof(parsed.beacon)); + parsed.beacon.hdr = hdr; + parsed.beacon.len = len; + if (acx_debug & L_DATA) { + printk("beacon len:%d fc:%04X dur:%04X seq:%04X", + len, hdr->fc, hdr->dur, hdr->seq); + acx_print_mac(" a1:", hdr->a1, ""); + acx_print_mac(" a2:", hdr->a2, ""); + acx_print_mac(" a3:", hdr->a3, "\n"); + } + wlan_mgmt_decode_beacon(&parsed.beacon); + /* beacon and probe response are very similar, so... */ + acx_l_process_probe_response(adev, &parsed.beacon, rxbuf); + break; + case WF_FSTYPE_ASSOCREQi: + if (!ap) + break; + memset(&parsed.assocreq, 0, sizeof(parsed.assocreq)); + parsed.assocreq.hdr = hdr; + parsed.assocreq.len = len; + wlan_mgmt_decode_assocreq(&parsed.assocreq); + if (mac_is_equal(hdr->a1, adev->bssid) + && mac_is_equal(hdr->a3, adev->bssid)) { + acx_l_transmit_assocresp(adev, &parsed.assocreq); + } + break; + case WF_FSTYPE_REASSOCREQi: + if (!ap) + break; + memset(&parsed.assocreq, 0, sizeof(parsed.assocreq)); + parsed.assocreq.hdr = hdr; + parsed.assocreq.len = len; + wlan_mgmt_decode_assocreq(&parsed.assocreq); + /* reassocreq and assocreq are equivalent */ + acx_l_transmit_reassocresp(adev, &parsed.reassocreq); + break; + case WF_FSTYPE_ASSOCRESPi: + if (!sta_scan) + break; + memset(&parsed.assocresp, 0, sizeof(parsed.assocresp)); + parsed.assocresp.hdr = hdr; + parsed.assocresp.len = len; + wlan_mgmt_decode_assocresp(&parsed.assocresp); + acx_l_process_assocresp(adev, &parsed.assocresp); + break; + case WF_FSTYPE_REASSOCRESPi: + if (!sta_scan) + break; + memset(&parsed.assocresp, 0, sizeof(parsed.assocresp)); + parsed.assocresp.hdr = hdr; + parsed.assocresp.len = len; + wlan_mgmt_decode_assocresp(&parsed.assocresp); + acx_l_process_reassocresp(adev, &parsed.reassocresp); + break; + case WF_FSTYPE_PROBEREQi: + if (ap || adhoc) { + /* FIXME: since we're supposed to be an AP, + ** we need to return a Probe Response packet. + ** Currently firmware is doing it for us, + ** but firmware is buggy! See comment elsewhere --vda */ + } + break; + case WF_FSTYPE_PROBERESPi: + memset(&parsed.proberesp, 0, sizeof(parsed.proberesp)); + parsed.proberesp.hdr = hdr; + parsed.proberesp.len = len; + wlan_mgmt_decode_proberesp(&parsed.proberesp); + acx_l_process_probe_response(adev, &parsed.proberesp, rxbuf); + break; + case 6: + case 7: + /* exit */ + break; + case WF_FSTYPE_ATIMi: + /* exit */ + break; + case WF_FSTYPE_DISASSOCi: + if (!sta && !ap) + break; + memset(&parsed.disassoc, 0, sizeof(parsed.disassoc)); + parsed.disassoc.hdr = hdr; + parsed.disassoc.len = len; + wlan_mgmt_decode_disassoc(&parsed.disassoc); + if (sta) + acx_l_process_disassoc_from_ap(adev, &parsed.disassoc); + else + acx_l_process_disassoc_from_sta(adev, &parsed.disassoc); + break; + case WF_FSTYPE_AUTHENi: + if (!sta_scan && !ap) + break; + memset(&parsed.authen, 0, sizeof(parsed.authen)); + parsed.authen.hdr = hdr; + parsed.authen.len = len; + wlan_mgmt_decode_authen(&parsed.authen); + acx_l_process_authen(adev, &parsed.authen); + break; + case WF_FSTYPE_DEAUTHENi: + if (!sta && !ap) + break; + memset(&parsed.deauthen, 0, sizeof(parsed.deauthen)); + parsed.deauthen.hdr = hdr; + parsed.deauthen.len = len; + wlan_mgmt_decode_deauthen(&parsed.deauthen); + if (sta) + acx_l_process_deauth_from_ap(adev, &parsed.deauthen); + else + acx_l_process_deauth_from_sta(adev, &parsed.deauthen); + break; + } + + FN_EXIT1(OK); + return OK; +} + + +#ifdef UNUSED +/*********************************************************************** +** acx_process_class_frame +** +** Called from IRQ context only +*/ +static int +acx_process_class_frame(acx_device_t *adev, rxbuffer_t *rxbuf, int vala) +{ + return OK; +} +#endif + + +/*********************************************************************** +** acx_l_process_NULL_frame +*/ +#ifdef BOGUS_ITS_NOT_A_NULL_FRAME_HANDLER_AT_ALL +static int +acx_l_process_NULL_frame(acx_device_t *adev, rxbuffer_t *rxbuf, int vala) +{ + const signed char *esi; + const u8 *ebx; + const wlan_hdr_t *hdr; + const client_t *client; + int result = NOT_OK; + + hdr = acx_get_wlan_hdr(adev, rxbuf); + + switch (WF_FC_FROMTODSi & hdr->fc) { + case 0: + esi = hdr->a1; + ebx = hdr->a2; + break; + case WF_FC_FROMDSi: + esi = hdr->a1; + ebx = hdr->a3; + break; + case WF_FC_TODSi: + esi = hdr->a1; + ebx = hdr->a2; + break; + default: /* WF_FC_FROMTODSi */ + esi = hdr->a1; /* added by me! --vda */ + ebx = hdr->a2; + } + + if (esi[0x0] < 0) { + result = OK; + goto done; + } + + client = acx_l_sta_list_get(adev, ebx); + if (client) + result = NOT_OK; + else { +#ifdef IS_IT_BROKEN + log(L_DEBUG|L_XFER, "\n"); + acx_l_transmit_deauthen(adev, ebx, + WLAN_MGMT_REASON_CLASS2_NONAUTH); +#else + log(L_DEBUG, "received NULL frame from unknown client! " + "We really shouldn't send deauthen here, right?\n"); +#endif + result = OK; + } +done: + return result; +} +#endif + + +/*********************************************************************** +** acx_l_process_probe_response +*/ +static int +acx_l_process_probe_response(acx_device_t *adev, wlan_fr_proberesp_t *req, + const rxbuffer_t *rxbuf) +{ + struct client *bss; + wlan_hdr_t *hdr; + + FN_ENTER; + + hdr = req->hdr; + + if (mac_is_equal(hdr->a3, adev->dev_addr)) { + log(L_ASSOC, "huh, scan found our own MAC!?\n"); + goto ok; /* just skip this one silently */ + } + + bss = acx_l_sta_list_get_or_add(adev, hdr->a2); + + /* NB: be careful modifying bss data! It may be one + ** of the already known clients (like our AP if we are a STA) + ** Thus do not blindly modify e.g. current ratemask! */ + + if (STA_LIST_ADD_CAN_FAIL && !bss) { + /* uh oh, we found more sites/stations than we can handle with + * our current setup: pull the emergency brake and stop scanning! */ + acx_schedule_task(adev, ACX_AFTER_IRQ_CMD_STOP_SCAN); + /* TODO: a nice comment what below call achieves --vda */ + acx_set_status(adev, ACX_STATUS_2_WAIT_AUTH); + goto ok; + } + /* NB: get_or_add already filled bss->address = hdr->a2 */ + MAC_COPY(bss->bssid, hdr->a3); + + /* copy the ESSID element */ + if (req->ssid && req->ssid->len <= IW_ESSID_MAX_SIZE) { + bss->essid_len = req->ssid->len; + memcpy(bss->essid, req->ssid->ssid, req->ssid->len); + bss->essid[req->ssid->len] = '\0'; + } else { + /* Either no ESSID IE or oversized one */ + printk("%s: received packet has bogus ESSID\n", + adev->ndev->name); + } + + if (req->ds_parms) + bss->channel = req->ds_parms->curr_ch; + if (req->cap_info) + bss->cap_info = ieee2host16(*req->cap_info); + + bss->sir = acx_signal_to_winlevel(rxbuf->phy_level); + bss->snr = acx_signal_to_winlevel(rxbuf->phy_snr); + + bss->rate_cap = 0; /* operational mask */ + bss->rate_bas = 0; /* basic mask */ + if (req->supp_rates) + add_bits_to_ratemasks(req->supp_rates->rates, + req->supp_rates->len, &bss->rate_bas, &bss->rate_cap); + if (req->ext_rates) + add_bits_to_ratemasks(req->ext_rates->rates, + req->ext_rates->len, &bss->rate_bas, &bss->rate_cap); + /* Fix up any possible bogosity - code elsewhere + * is not expecting empty masks */ + if (!bss->rate_cap) + bss->rate_cap = adev->rate_basic; + if (!bss->rate_bas) + bss->rate_bas = 1 << lowest_bit(bss->rate_cap); + if (!bss->rate_cur) + bss->rate_cur = 1 << lowest_bit(bss->rate_bas); + + /* People moan about this being too noisy at L_ASSOC */ + log(L_DEBUG, + "found %s: ESSID=\"%s\" ch=%d " + "BSSID="MACSTR" caps=0x%04X SIR=%d SNR=%d\n", + (bss->cap_info & WF_MGMT_CAP_IBSS) ? "Ad-Hoc peer" : "AP", + bss->essid, bss->channel, MAC(bss->bssid), bss->cap_info, + bss->sir, bss->snr); +ok: + FN_EXIT0; + return OK; +} + + +/*********************************************************************** +** acx_l_process_assocresp +*/ +static int +acx_l_process_assocresp(acx_device_t *adev, const wlan_fr_assocresp_t *req) +{ + const wlan_hdr_t *hdr; + int res = OK; + + FN_ENTER; + + hdr = req->hdr; + + if ((ACX_MODE_2_STA == adev->mode) + && mac_is_equal(adev->dev_addr, hdr->a1)) { + u16 st = ieee2host16(*(req->status)); + if (WLAN_MGMT_STATUS_SUCCESS == st) { + adev->aid = ieee2host16(*(req->aid)); + /* tell the card we are associated when + ** we are out of interrupt context */ + acx_schedule_task(adev, ACX_AFTER_IRQ_CMD_ASSOCIATE); + } else { + + /* TODO: we shall delete peer from sta_list, and try + ** other candidates... */ + + printk("%s: association FAILED: peer sent " + "Status Code %d (%s)\n", + adev->ndev->name, st, get_status_string(st)); + res = NOT_OK; + } + } + + FN_EXIT1(res); + return res; +} + + +/*********************************************************************** +** acx_l_process_reassocresp +*/ +static int +acx_l_process_reassocresp(acx_device_t *adev, const wlan_fr_reassocresp_t *req) +{ + const wlan_hdr_t *hdr; + int result = NOT_OK; + u16 st; + + FN_ENTER; + + hdr = req->hdr; + + if (!mac_is_equal(adev->dev_addr, hdr->a1)) { + goto end; + } + st = ieee2host16(*(req->status)); + if (st == WLAN_MGMT_STATUS_SUCCESS) { + acx_set_status(adev, ACX_STATUS_4_ASSOCIATED); + result = OK; + } else { + printk("%s: reassociation FAILED: peer sent " + "response code %d (%s)\n", + adev->ndev->name, st, get_status_string(st)); + } +end: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_l_process_authen +** +** Called only in STA_SCAN or AP mode +*/ +static int +acx_l_process_authen(acx_device_t *adev, const wlan_fr_authen_t *req) +{ + const wlan_hdr_t *hdr; + client_t *clt; + wlan_ie_challenge_t *chal; + u16 alg, seq, status; + int ap, result; + + FN_ENTER; + + hdr = req->hdr; + + if (acx_debug & L_ASSOC) { + acx_print_mac("AUTHEN adev->addr=", adev->dev_addr, " "); + acx_print_mac("a1=", hdr->a1, " "); + acx_print_mac("a2=", hdr->a2, " "); + acx_print_mac("a3=", hdr->a3, " "); + acx_print_mac("adev->bssid=", adev->bssid, "\n"); + } + + if (!mac_is_equal(adev->dev_addr, hdr->a1) + || !mac_is_equal(adev->bssid, hdr->a3)) { + result = OK; + goto end; + } + + alg = ieee2host16(*(req->auth_alg)); + seq = ieee2host16(*(req->auth_seq)); + status = ieee2host16(*(req->status)); + + log(L_ASSOC, "auth algorithm %d, auth sequence %d, status %d\n", alg, seq, status); + + ap = (adev->mode == ACX_MODE_3_AP); + + if (adev->auth_alg <= 1) { + if (adev->auth_alg != alg) { + log(L_ASSOC, "auth algorithm mismatch: " + "our:%d peer:%d\n", adev->auth_alg, alg); + result = NOT_OK; + goto end; + } + } + if (ap) { + clt = acx_l_sta_list_get_or_add(adev, hdr->a2); + if (STA_LIST_ADD_CAN_FAIL && !clt) { + log(L_ASSOC, "could not allocate room for client\n"); + result = NOT_OK; + goto end; + } + } else { + clt = adev->ap_client; + if (!mac_is_equal(clt->address, hdr->a2)) { + printk("%s: malformed auth frame from AP?!\n", + adev->ndev->name); + result = NOT_OK; + goto end; + } + } + + /* now check which step in the authentication sequence we are + * currently in, and act accordingly */ + switch (seq) { + case 1: + if (!ap) + break; + acx_l_transmit_authen2(adev, req, clt); + break; + case 2: + if (ap) + break; + if (status == WLAN_MGMT_STATUS_SUCCESS) { + if (alg == WLAN_AUTH_ALG_OPENSYSTEM) { + acx_set_status(adev, ACX_STATUS_3_AUTHENTICATED); + acx_l_transmit_assoc_req(adev); + } else + if (alg == WLAN_AUTH_ALG_SHAREDKEY) { + acx_l_transmit_authen3(adev, req); + } + } else { + printk("%s: auth FAILED: peer sent " + "response code %d (%s), " + "still waiting for authentication\n", + adev->ndev->name, + status, get_status_string(status)); + acx_set_status(adev, ACX_STATUS_2_WAIT_AUTH); + } + break; + case 3: + if (!ap) + break; + if ((clt->auth_alg != WLAN_AUTH_ALG_SHAREDKEY) + || (alg != WLAN_AUTH_ALG_SHAREDKEY) + || (clt->auth_step != 2)) + break; + chal = req->challenge; + if (!chal + || memcmp(chal->challenge, clt->challenge_text, WLAN_CHALLENGE_LEN) + || (chal->eid != WLAN_EID_CHALLENGE) + || (chal->len != WLAN_CHALLENGE_LEN) + ) + break; + acx_l_transmit_authen4(adev, req); + MAC_COPY(clt->address, hdr->a2); + clt->used = CLIENT_AUTHENTICATED_2; + clt->auth_step = 4; + clt->seq = ieee2host16(hdr->seq); + break; + case 4: + if (ap) + break; + /* ok, we're through: we're authenticated. Woohoo!! */ + acx_set_status(adev, ACX_STATUS_3_AUTHENTICATED); + log(L_ASSOC, "Authenticated!\n"); + /* now that we're authenticated, request association */ + acx_l_transmit_assoc_req(adev); + break; + } + result = OK; +end: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_gen_challenge +*/ +static inline void +acx_gen_challenge(wlan_ie_challenge_t* d) +{ + FN_ENTER; + d->eid = WLAN_EID_CHALLENGE; + d->len = WLAN_CHALLENGE_LEN; + get_random_bytes(d->challenge, WLAN_CHALLENGE_LEN); + FN_EXIT0; +} + + +/*********************************************************************** +** acx_l_transmit_deauthen +*/ +static int +acx_l_transmit_deauthen(acx_device_t *adev, const u8 *addr, u16 reason) +{ + struct tx *tx; + struct wlan_hdr_mgmt *head; + struct deauthen_frame_body *body; + + FN_ENTER; + + tx = acx_l_alloc_tx(adev); + if (!tx) + goto bad; + head = acx_l_get_txbuf(adev, tx); + if (!head) { + acx_l_dealloc_tx(adev, tx); + goto bad; + } + body = (void*)(head + 1); + + head->fc = (WF_FTYPE_MGMTi | WF_FSTYPE_DEAUTHENi); + head->dur = 0; + MAC_COPY(head->da, addr); + MAC_COPY(head->sa, adev->dev_addr); + MAC_COPY(head->bssid, adev->bssid); + head->seq = 0; + + log(L_DEBUG|L_ASSOC|L_XFER, + "sending deauthen to "MACSTR" for %d\n", + MAC(addr), reason); + + body->reason = host2ieee16(reason); + + /* body is fixed size here, but beware of cutting-and-pasting this - + ** do not use sizeof(*body) for variable sized mgmt packets! */ + acx_l_tx_data(adev, tx, WLAN_HDR_A3_LEN + sizeof(*body)); + + FN_EXIT1(OK); + return OK; +bad: + FN_EXIT1(NOT_OK); + return NOT_OK; +} + + +/*********************************************************************** +** acx_l_transmit_authen1 +*/ +static int +acx_l_transmit_authen1(acx_device_t *adev) +{ + struct tx *tx; + struct wlan_hdr_mgmt *head; + struct auth_frame_body *body; + + FN_ENTER; + + log(L_ASSOC, "sending authentication1 request (auth algo %d), " + "awaiting response\n", adev->auth_alg); + + tx = acx_l_alloc_tx(adev); + if (!tx) + goto bad; + head = acx_l_get_txbuf(adev, tx); + if (!head) { + acx_l_dealloc_tx(adev, tx); + goto bad; + } + body = (void*)(head + 1); + + head->fc = WF_FSTYPE_AUTHENi; + /* duration should be 0 instead of 0x8000 to have + * the firmware calculate the value, right? */ + head->dur = 0; + MAC_COPY(head->da, adev->bssid); + MAC_COPY(head->sa, adev->dev_addr); + MAC_COPY(head->bssid, adev->bssid); + head->seq = 0; + + body->auth_alg = host2ieee16(adev->auth_alg); + body->auth_seq = host2ieee16(1); + body->status = host2ieee16(0); + + acx_l_tx_data(adev, tx, WLAN_HDR_A3_LEN + 2 + 2 + 2); + + FN_EXIT1(OK); + return OK; +bad: + FN_EXIT1(NOT_OK); + return NOT_OK; +} + + +/*********************************************************************** +** acx_l_transmit_authen2 +*/ +static int +acx_l_transmit_authen2(acx_device_t *adev, const wlan_fr_authen_t *req, + client_t *clt) +{ + struct tx *tx; + struct wlan_hdr_mgmt *head; + struct auth_frame_body *body; + unsigned int packet_len; + + FN_ENTER; + + if (!clt) + goto ok; + + MAC_COPY(clt->address, req->hdr->a2); +#ifdef UNUSED + clt->ps = ((WF_FC_PWRMGTi & req->hdr->fc) != 0); +#endif + clt->auth_alg = ieee2host16(*(req->auth_alg)); + clt->auth_step = 2; + clt->seq = ieee2host16(req->hdr->seq); + + tx = acx_l_alloc_tx(adev); + if (!tx) + goto bad; + head = acx_l_get_txbuf(adev, tx); + if (!head) { + acx_l_dealloc_tx(adev, tx); + goto bad; + } + body = (void*)(head + 1); + + head->fc = WF_FSTYPE_AUTHENi; + head->dur = 0 /* req->hdr->dur */; + MAC_COPY(head->da, req->hdr->a2); + MAC_COPY(head->sa, adev->dev_addr); + MAC_COPY(head->bssid, req->hdr->a3); + head->seq = 0 /* req->hdr->seq */; + + /* already in IEEE format, no endianness conversion */ + body->auth_alg = *(req->auth_alg); + body->auth_seq = host2ieee16(2); + body->status = host2ieee16(0); + + packet_len = WLAN_HDR_A3_LEN + 2 + 2 + 2; + if (ieee2host16(*(req->auth_alg)) == WLAN_AUTH_ALG_OPENSYSTEM) { + clt->used = CLIENT_AUTHENTICATED_2; + } else { /* shared key */ + acx_gen_challenge(&body->challenge); + memcpy(&clt->challenge_text, body->challenge.challenge, WLAN_CHALLENGE_LEN); + packet_len += 2 + 2 + 2 + 1+1+WLAN_CHALLENGE_LEN; + } + + acxlog_mac(L_ASSOC|L_XFER, + "transmit_auth2: BSSID=", head->bssid, "\n"); + + acx_l_tx_data(adev, tx, packet_len); +ok: + FN_EXIT1(OK); + return OK; +bad: + FN_EXIT1(NOT_OK); + return NOT_OK; +} + + +/*********************************************************************** +** acx_l_transmit_authen3 +*/ +static int +acx_l_transmit_authen3(acx_device_t *adev, const wlan_fr_authen_t *req) +{ + struct tx *tx; + struct wlan_hdr_mgmt *head; + struct auth_frame_body *body; + unsigned int packet_len; + + FN_ENTER; + + tx = acx_l_alloc_tx(adev); + if (!tx) + goto ok; + head = acx_l_get_txbuf(adev, tx); + if (!head) { + acx_l_dealloc_tx(adev, tx); + goto ok; + } + body = (void*)(head + 1); + + /* add WF_FC_ISWEPi: auth step 3 needs to be encrypted */ + head->fc = WF_FC_ISWEPi + WF_FSTYPE_AUTHENi; + /* FIXME: is this needed?? authen4 does it... + * I think it's even wrong since we shouldn't re-use old + * values but instead let the firmware calculate proper ones + head->dur = req->hdr->dur; + head->seq = req->hdr->seq; + */ + MAC_COPY(head->da, adev->bssid); + MAC_COPY(head->sa, adev->dev_addr); + MAC_COPY(head->bssid, adev->bssid); + + /* already in IEEE format, no endianness conversion */ + body->auth_alg = *(req->auth_alg); + body->auth_seq = host2ieee16(3); + body->status = host2ieee16(0); + memcpy(&body->challenge, req->challenge, req->challenge->len + 2); + packet_len = WLAN_HDR_A3_LEN + 8 + req->challenge->len; + + log(L_ASSOC|L_XFER, "transmit_authen3!\n"); + + acx_l_tx_data(adev, tx, packet_len); +ok: + FN_EXIT1(OK); + return OK; +} + + +/*********************************************************************** +** acx_l_transmit_authen4 +*/ +static int +acx_l_transmit_authen4(acx_device_t *adev, const wlan_fr_authen_t *req) +{ + struct tx *tx; + struct wlan_hdr_mgmt *head; + struct auth_frame_body *body; + + FN_ENTER; + + tx = acx_l_alloc_tx(adev); + if (!tx) + goto ok; + head = acx_l_get_txbuf(adev, tx); + if (!head) { + acx_l_dealloc_tx(adev, tx); + goto ok; + } + body = (void*)(head + 1); + + head->fc = WF_FSTYPE_AUTHENi; /* 0xb0 */ + head->dur = 0 /* req->hdr->dur */; + MAC_COPY(head->da, req->hdr->a2); + MAC_COPY(head->sa, adev->dev_addr); + MAC_COPY(head->bssid, req->hdr->a3); + head->seq = 0 /* req->hdr->seq */; + + /* already in IEEE format, no endianness conversion */ + body->auth_alg = *(req->auth_alg); + body->auth_seq = host2ieee16(4); + body->status = host2ieee16(0); + + acx_l_tx_data(adev, tx, WLAN_HDR_A3_LEN + 2 + 2 + 2); +ok: + FN_EXIT1(OK); + return OK; +} + + +/*********************************************************************** +** acx_l_transmit_assoc_req +** +** adev->ap_client is a current candidate AP here +*/ +static int +acx_l_transmit_assoc_req(acx_device_t *adev) +{ + struct tx *tx; + struct wlan_hdr_mgmt *head; + u8 *body, *p, *prate; + unsigned int packet_len; + u16 cap; + + FN_ENTER; + + log(L_ASSOC, "sending association request, " + "awaiting response. NOT ASSOCIATED YET\n"); + tx = acx_l_alloc_tx(adev); + if (!tx) + goto bad; + head = acx_l_get_txbuf(adev, tx); + if (!head) { + acx_l_dealloc_tx(adev, tx); + goto bad; + } + body = (void*)(head + 1); + + head->fc = WF_FSTYPE_ASSOCREQi; + head->dur = host2ieee16(0x8000); + MAC_COPY(head->da, adev->bssid); + MAC_COPY(head->sa, adev->dev_addr); + MAC_COPY(head->bssid, adev->bssid); + head->seq = 0; + + p = body; + /* now start filling the AssocReq frame body */ + + /* since this assoc request will most likely only get + * sent in the STA to AP case (and not when Ad-Hoc IBSS), + * the cap combination indicated here will thus be + * WF_MGMT_CAP_ESSi *always* (no IBSS ever) + * The specs are more than non-obvious on all that: + * + * 802.11 7.3.1.4 Capability Information field + ** APs set the ESS subfield to 1 and the IBSS subfield to 0 within + ** Beacon or Probe Response management frames. STAs within an IBSS + ** set the ESS subfield to 0 and the IBSS subfield to 1 in transmitted + ** Beacon or Probe Response management frames + ** + ** APs set the Privacy subfield to 1 within transmitted Beacon, + ** Probe Response, Association Response, and Reassociation Response + ** if WEP is required for all data type frames within the BSS. + ** STAs within an IBSS set the Privacy subfield to 1 in Beacon + ** or Probe Response management frames if WEP is required + ** for all data type frames within the IBSS */ + + /* note that returning 0 will be refused by several APs... + * (so this indicates that you're probably supposed to + * "confirm" the ESS mode) */ + cap = WF_MGMT_CAP_ESSi; + + /* this one used to be a check on wep_restricted, + * but more likely it's wep_enabled instead */ + if (adev->wep_enabled) + SET_BIT(cap, WF_MGMT_CAP_PRIVACYi); + + /* Probably we can just set these always, because our hw is + ** capable of shortpre and PBCC --vda */ + /* only ask for short preamble if the peer station supports it */ + if (adev->ap_client->cap_info & WF_MGMT_CAP_SHORT) + SET_BIT(cap, WF_MGMT_CAP_SHORTi); + /* only ask for PBCC support if the peer station supports it */ + if (adev->ap_client->cap_info & WF_MGMT_CAP_PBCC) + SET_BIT(cap, WF_MGMT_CAP_PBCCi); + + /* IEs: 1. caps */ + *(u16*)p = cap; p += 2; + /* 2. listen interval */ + *(u16*)p = host2ieee16(adev->listen_interval); p += 2; + /* 3. ESSID */ + p = wlan_fill_ie_ssid(p, + strlen(adev->essid_for_assoc), adev->essid_for_assoc); + /* 4. supp rates */ + prate = p; + p = wlan_fill_ie_rates(p, + adev->rate_supported_len, adev->rate_supported); + /* 5. ext supp rates */ + p = wlan_fill_ie_rates_ext(p, + adev->rate_supported_len, adev->rate_supported); + + if (acx_debug & L_DEBUG) { + printk("association: rates element\n"); + acx_dump_bytes(prate, p - prate); + } + + /* calculate lengths */ + packet_len = WLAN_HDR_A3_LEN + (p - body); + + log(L_ASSOC, "association: requesting caps 0x%04X, ESSID \"%s\"\n", + cap, adev->essid_for_assoc); + + acx_l_tx_data(adev, tx, packet_len); + FN_EXIT1(OK); + return OK; +bad: + FN_EXIT1(NOT_OK); + return NOT_OK; +} + + +/*********************************************************************** +** acx_l_transmit_disassoc +** +** FIXME: looks like incomplete implementation of a helper: +** acx_l_transmit_disassoc(adev, clt) - kick this client (we're an AP) +** acx_l_transmit_disassoc(adev, NULL) - leave BSSID (we're a STA) +*/ +#ifdef BROKEN +int +acx_l_transmit_disassoc(acx_device_t *adev, client_t *clt) +{ + struct tx *tx; + struct wlan_hdr_mgmt *head; + struct disassoc_frame_body *body; + + FN_ENTER; +/* if (clt != NULL) { */ + tx = acx_l_alloc_tx(adev); + if (!tx) + goto bad; + head = acx_l_get_txbuf(adev, tx); + if (!head) { + acx_l_dealloc_tx(adev, tx); + goto bad; + } + body = (void*)(head + 1); + +/* clt->used = CLIENT_AUTHENTICATED_2; - not (yet?) associated */ + + head->fc = WF_FSTYPE_DISASSOCi; + head->dur = 0; + /* huh? It muchly depends on whether we're STA or AP... + ** sta->ap: da=bssid, sa=own, bssid=bssid + ** ap->sta: da=sta, sa=bssid, bssid=bssid. FIXME! */ + MAC_COPY(head->da, adev->bssid); + MAC_COPY(head->sa, adev->dev_addr); + MAC_COPY(head->bssid, adev->dev_addr); + head->seq = 0; + + /* "Class 3 frame received from nonassociated station." */ + body->reason = host2ieee16(7); + + /* fixed size struct, ok to sizeof */ + acx_l_tx_data(adev, tx, WLAN_HDR_A3_LEN + sizeof(*body)); +/* } */ + FN_EXIT1(OK); + return OK; +bad: + FN_EXIT1(NOT_OK); + return NOT_OK; +} +#endif + + +/*********************************************************************** +** acx_s_complete_scan +** +** Called either from after_interrupt_task() if: +** 1) there was Scan_Complete IRQ, or +** 2) scanning expired in timer() +** We need to decide which ESS or IBSS to join. +** Iterates thru adev->sta_list: +** if adev->ap is not bcast, will join only specified +** ESS or IBSS with this bssid +** checks peers' caps for ESS/IBSS bit +** checks peers' SSID, allows exact match or hidden SSID +** If station to join is chosen: +** points adev->ap_client to the chosen struct client +** sets adev->essid_for_assoc for future assoc attempt +** Auth/assoc is not yet performed +** Returns OK if there is no need to restart scan +*/ +int +acx_s_complete_scan(acx_device_t *adev) +{ + struct client *bss; + unsigned long flags; + u16 needed_cap; + int i; + int idx_found = -1; + int result = OK; + + FN_ENTER; + + switch (adev->mode) { + case ACX_MODE_0_ADHOC: + needed_cap = WF_MGMT_CAP_IBSS; /* 2, we require Ad-Hoc */ + break; + case ACX_MODE_2_STA: + needed_cap = WF_MGMT_CAP_ESS; /* 1, we require Managed */ + break; + default: + printk("acx: driver bug: mode=%d in complete_scan()\n", adev->mode); + dump_stack(); + goto end; + } + + acx_lock(adev, flags); + + /* TODO: sta_iterator hiding implementation would be nice here... */ + + for (i = 0; i < VEC_SIZE(adev->sta_list); i++) { + bss = &adev->sta_list[i]; + if (!bss->used) continue; + + log(L_ASSOC, "scan table: SSID=\"%s\" CH=%d SIR=%d SNR=%d\n", + bss->essid, bss->channel, bss->sir, bss->snr); + + if (!mac_is_bcast(adev->ap)) + if (!mac_is_equal(bss->bssid, adev->ap)) + continue; /* keep looking */ + + /* broken peer with no mode flags set? */ + if (unlikely(!(bss->cap_info & (WF_MGMT_CAP_ESS | WF_MGMT_CAP_IBSS)))) { + printk("%s: strange peer "MACSTR" found with " + "neither ESS (AP) nor IBSS (Ad-Hoc) " + "capability - skipped\n", + adev->ndev->name, MAC(bss->address)); + continue; + } + log(L_ASSOC, "peer_cap 0x%04X, needed_cap 0x%04X\n", + bss->cap_info, needed_cap); + + /* does peer station support what we need? */ + if ((bss->cap_info & needed_cap) != needed_cap) + continue; /* keep looking */ + + /* strange peer with NO basic rates?! */ + if (unlikely(!bss->rate_bas)) { + printk("%s: strange peer "MACSTR" with empty rate set " + "- skipped\n", + adev->ndev->name, MAC(bss->address)); + continue; + } + + /* do we support all basic rates of this peer? */ + if ((bss->rate_bas & adev->rate_oper) != bss->rate_bas) { +/* we probably need to have all rates as operational rates, + even in case of an 11M-only configuration */ +#ifdef THIS_IS_TROUBLESOME + printk("%s: peer "MACSTR": incompatible basic rates " + "(AP requests 0x%04X, we have 0x%04X) " + "- skipped\n", + adev->ndev->name, MAC(bss->address), + bss->rate_bas, adev->rate_oper); + continue; +#else + printk("%s: peer "MACSTR": incompatible basic rates " + "(AP requests 0x%04X, we have 0x%04X). " + "Considering anyway...\n", + adev->ndev->name, MAC(bss->address), + bss->rate_bas, adev->rate_oper); +#endif + } + + if ( !(adev->reg_dom_chanmask & (1<<(bss->channel-1))) ) { + printk("%s: warning: peer "MACSTR" is on channel %d " + "outside of channel range of current " + "regulatory domain - couldn't join " + "even if other settings match. " + "You might want to adapt your config\n", + adev->ndev->name, MAC(bss->address), + bss->channel); + continue; /* keep looking */ + } + + if (!adev->essid_active || !strcmp(bss->essid, adev->essid)) { + log(L_ASSOC, + "found station with matching ESSID! ('%s' " + "station, '%s' config)\n", + bss->essid, + (adev->essid_active) ? adev->essid : "[any]"); + /* TODO: continue looking for peer with better SNR */ + bss->used = CLIENT_JOIN_CANDIDATE; + idx_found = i; + + /* stop searching if this station is + * on the current channel, otherwise + * keep looking for an even better match */ + if (bss->channel == adev->channel) + break; + } else + if (is_hidden_essid(bss->essid)) { + /* hmm, station with empty or single-space SSID: + * using hidden SSID broadcast? + */ + /* This behaviour is broken: which AP from zillion + ** of APs with hidden SSID you'd try? + ** We should use Probe requests to get Probe responses + ** and check for real SSID (are those never hidden?) */ + bss->used = CLIENT_JOIN_CANDIDATE; + if (idx_found == -1) + idx_found = i; + log(L_ASSOC, "found station with empty or " + "single-space (hidden) SSID, considering " + "for assoc attempt\n"); + /* ...and keep looking for better matches */ + } else { + log(L_ASSOC, "ESSID doesn't match! ('%s' " + "station, '%s' config)\n", + bss->essid, + (adev->essid_active) ? adev->essid : "[any]"); + } + } + + /* TODO: iterate thru join candidates instead */ + /* TODO: rescan if not associated within some timeout */ + if (idx_found != -1) { + char *essid_src; + size_t essid_len; + + bss = &adev->sta_list[idx_found]; + adev->ap_client = bss; + + if (is_hidden_essid(bss->essid)) { + /* if the ESSID of the station we found is empty + * (no broadcast), then use user-configured ESSID + * instead */ + essid_src = adev->essid; + essid_len = adev->essid_len; + } else { + essid_src = bss->essid; + essid_len = strlen(bss->essid); + } + + acx_update_capabilities(adev); + + memcpy(adev->essid_for_assoc, essid_src, essid_len); + adev->essid_for_assoc[essid_len] = '\0'; + adev->channel = bss->channel; + MAC_COPY(adev->bssid, bss->bssid); + + bss->rate_cfg = (bss->rate_cap & adev->rate_oper); + bss->rate_cur = 1 << lowest_bit(bss->rate_cfg); + bss->rate_100 = acx_rate111to100(bss->rate_cur); + + acxlog_mac(L_ASSOC, + "matching station found: ", adev->bssid, ", joining\n"); + + /* TODO: do we need to switch to the peer's channel first? */ + + if (ACX_MODE_0_ADHOC == adev->mode) { + acx_set_status(adev, ACX_STATUS_4_ASSOCIATED); + } else { + acx_l_transmit_authen1(adev); + acx_set_status(adev, ACX_STATUS_2_WAIT_AUTH); + } + } else { /* idx_found == -1 */ + /* uh oh, no station found in range */ + if (ACX_MODE_0_ADHOC == adev->mode) { + printk("%s: no matching station found in range, " + "generating our own IBSS instead\n", + adev->ndev->name); + /* we do it the HostAP way: */ + MAC_COPY(adev->bssid, adev->dev_addr); + adev->bssid[0] |= 0x02; /* 'local assigned addr' bit */ + /* add IBSS bit to our caps... */ + acx_update_capabilities(adev); + acx_set_status(adev, ACX_STATUS_4_ASSOCIATED); + /* In order to cmd_join be called below */ + idx_found = 0; + } else { + /* we shall scan again, AP can be + ** just temporarily powered off */ + log(L_ASSOC, + "no matching station found in range yet\n"); + acx_set_status(adev, ACX_STATUS_1_SCANNING); + result = NOT_OK; + } + } + + acx_unlock(adev, flags); + + if (idx_found != -1) { + if (ACX_MODE_0_ADHOC == adev->mode) { + /* need to update channel in beacon template */ + SET_BIT(adev->set_mask, SET_TEMPLATES); + if (ACX_STATE_IFACE_UP & adev->dev_state_mask) + acx_s_update_card_settings(adev); + } + /* Inform firmware on our decision to start or join BSS */ + acx_s_cmd_join_bssid(adev, adev->bssid); + } + +end: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_s_read_fw +** +** Loads a firmware image +** +** Returns: +** 0 unable to load file +** pointer to firmware success +*/ +firmware_image_t* +acx_s_read_fw(struct device *dev, const char *file, u32 *size) +{ + firmware_image_t *res; + const struct firmware *fw_entry; + + res = NULL; + log(L_INIT, "requesting firmware image '%s'\n", file); + if (!request_firmware(&fw_entry, file, dev)) { + *size = 8; + if (fw_entry->size >= 8) + *size = 8 + le32_to_cpu(*(u32 *)(fw_entry->data + 4)); + if (fw_entry->size != *size) { + printk("acx: firmware size does not match " + "firmware header: %d != %d, " + "aborting fw upload\n", + (int) fw_entry->size, (int) *size); + goto release_ret; + } + res = vmalloc(*size); + if (!res) { + printk("acx: no memory for firmware " + "(%u bytes)\n", *size); + goto release_ret; + } + memcpy(res, fw_entry->data, fw_entry->size); +release_ret: + release_firmware(fw_entry); + return res; + } + printk("acx: firmware image '%s' was not provided. " + "Check your hotplug scripts\n", file); + + /* checksum will be verified in write_fw, so don't bother here */ + return res; +} + + +/*********************************************************************** +** acx_s_set_wepkey +*/ +static void +acx100_s_set_wepkey(acx_device_t *adev) +{ + ie_dot11WEPDefaultKey_t dk; + int i; + + for (i = 0; i < DOT11_MAX_DEFAULT_WEP_KEYS; i++) { + if (adev->wep_keys[i].size != 0) { + log(L_INIT, "setting WEP key: %d with " + "total size: %d\n", i, (int) adev->wep_keys[i].size); + dk.action = 1; + dk.keySize = adev->wep_keys[i].size; + dk.defaultKeyNum = i; + memcpy(dk.key, adev->wep_keys[i].key, dk.keySize); + acx_s_configure(adev, &dk, ACX100_IE_DOT11_WEP_DEFAULT_KEY_WRITE); + } + } +} + +static void +acx111_s_set_wepkey(acx_device_t *adev) +{ + acx111WEPDefaultKey_t dk; + int i; + + for (i = 0; i < DOT11_MAX_DEFAULT_WEP_KEYS; i++) { + if (adev->wep_keys[i].size != 0) { + log(L_INIT, "setting WEP key: %d with " + "total size: %d\n", i, (int) adev->wep_keys[i].size); + memset(&dk, 0, sizeof(dk)); + dk.action = cpu_to_le16(1); /* "add key"; yes, that's a 16bit value */ + dk.keySize = adev->wep_keys[i].size; + + /* are these two lines necessary? */ + dk.type = 0; /* default WEP key */ + dk.index = 0; /* ignored when setting default key */ + + dk.defaultKeyNum = i; + memcpy(dk.key, adev->wep_keys[i].key, dk.keySize); + acx_s_issue_cmd(adev, ACX1xx_CMD_WEP_MGMT, &dk, sizeof(dk)); + } + } +} + +static void +acx_s_set_wepkey(acx_device_t *adev) +{ + if (IS_ACX111(adev)) + acx111_s_set_wepkey(adev); + else + acx100_s_set_wepkey(adev); +} + + +/*********************************************************************** +** acx100_s_init_wep +** +** FIXME: this should probably be moved into the new card settings +** management, but since we're also modifying the memory map layout here +** due to the WEP key space we want, we should take care... +*/ +static int +acx100_s_init_wep(acx_device_t *adev) +{ + acx100_ie_wep_options_t options; + ie_dot11WEPDefaultKeyID_t dk; + acx_ie_memmap_t pt; + int res = NOT_OK; + + FN_ENTER; + + if (OK != acx_s_interrogate(adev, &pt, ACX1xx_IE_MEMORY_MAP)) { + goto fail; + } + + log(L_DEBUG, "CodeEnd:%X\n", pt.CodeEnd); + + pt.WEPCacheStart = cpu_to_le32(le32_to_cpu(pt.CodeEnd) + 0x4); + pt.WEPCacheEnd = cpu_to_le32(le32_to_cpu(pt.CodeEnd) + 0x4); + + if (OK != acx_s_configure(adev, &pt, ACX1xx_IE_MEMORY_MAP)) { + goto fail; + } + + /* let's choose maximum setting: 4 default keys, plus 10 other keys: */ + options.NumKeys = cpu_to_le16(DOT11_MAX_DEFAULT_WEP_KEYS + 10); + options.WEPOption = 0x00; + + log(L_ASSOC, "%s: writing WEP options\n", __func__); + acx_s_configure(adev, &options, ACX100_IE_WEP_OPTIONS); + + acx100_s_set_wepkey(adev); + + if (adev->wep_keys[adev->wep_current_index].size != 0) { + log(L_ASSOC, "setting active default WEP key number: %d\n", + adev->wep_current_index); + dk.KeyID = adev->wep_current_index; + acx_s_configure(adev, &dk, ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET); /* 0x1010 */ + } + /* FIXME!!! wep_key_struct is filled nowhere! But adev + * is initialized to 0, and we don't REALLY need those keys either */ +/* for (i = 0; i < 10; i++) { + if (adev->wep_key_struct[i].len != 0) { + MAC_COPY(wep_mgmt.MacAddr, adev->wep_key_struct[i].addr); + wep_mgmt.KeySize = cpu_to_le16(adev->wep_key_struct[i].len); + memcpy(&wep_mgmt.Key, adev->wep_key_struct[i].key, le16_to_cpu(wep_mgmt.KeySize)); + wep_mgmt.Action = cpu_to_le16(1); + log(L_ASSOC, "writing WEP key %d (len %d)\n", i, le16_to_cpu(wep_mgmt.KeySize)); + if (OK == acx_s_issue_cmd(adev, ACX1xx_CMD_WEP_MGMT, &wep_mgmt, sizeof(wep_mgmt))) { + adev->wep_key_struct[i].index = i; + } + } + } +*/ + + /* now retrieve the updated WEPCacheEnd pointer... */ + if (OK != acx_s_interrogate(adev, &pt, ACX1xx_IE_MEMORY_MAP)) { + printk("%s: ACX1xx_IE_MEMORY_MAP read #2 FAILED\n", + adev->ndev->name); + goto fail; + } + /* ...and tell it to start allocating templates at that location */ + /* (no endianness conversion needed) */ + pt.PacketTemplateStart = pt.WEPCacheEnd; + + if (OK != acx_s_configure(adev, &pt, ACX1xx_IE_MEMORY_MAP)) { + printk("%s: ACX1xx_IE_MEMORY_MAP write #2 FAILED\n", + adev->ndev->name); + goto fail; + } + res = OK; + +fail: + FN_EXIT1(res); + return res; +} + + +static int +acx_s_init_max_template_generic(acx_device_t *adev, unsigned int len, unsigned int cmd) +{ + int res; + union { + acx_template_nullframe_t null; + acx_template_beacon_t b; + acx_template_tim_t tim; + acx_template_probereq_t preq; + acx_template_proberesp_t presp; + } templ; + + memset(&templ, 0, len); + templ.null.size = cpu_to_le16(len - 2); + res = acx_s_issue_cmd(adev, cmd, &templ, len); + return res; +} + +static inline int +acx_s_init_max_null_data_template(acx_device_t *adev) +{ + return acx_s_init_max_template_generic( + adev, sizeof(acx_template_nullframe_t), ACX1xx_CMD_CONFIG_NULL_DATA + ); +} + +static inline int +acx_s_init_max_beacon_template(acx_device_t *adev) +{ + return acx_s_init_max_template_generic( + adev, sizeof(acx_template_beacon_t), ACX1xx_CMD_CONFIG_BEACON + ); +} + +static inline int +acx_s_init_max_tim_template(acx_device_t *adev) +{ + return acx_s_init_max_template_generic( + adev, sizeof(acx_template_tim_t), ACX1xx_CMD_CONFIG_TIM + ); +} + +static inline int +acx_s_init_max_probe_response_template(acx_device_t *adev) +{ + return acx_s_init_max_template_generic( + adev, sizeof(acx_template_proberesp_t), ACX1xx_CMD_CONFIG_PROBE_RESPONSE + ); +} + +static inline int +acx_s_init_max_probe_request_template(acx_device_t *adev) +{ + return acx_s_init_max_template_generic( + adev, sizeof(acx_template_probereq_t), ACX1xx_CMD_CONFIG_PROBE_REQUEST + ); +} + +/*********************************************************************** +** acx_s_set_tim_template +** +** FIXME: In full blown driver we will regularly update partial virtual bitmap +** by calling this function +** (it can be done by irq handler on each DTIM irq or by timer...) + +[802.11 7.3.2.6] TIM information element: +- 1 EID +- 1 Length +1 1 DTIM Count + indicates how many beacons (including this) appear before next DTIM + (0=this one is a DTIM) +2 1 DTIM Period + number of beacons between successive DTIMs + (0=reserved, 1=all TIMs are DTIMs, 2=every other, etc) +3 1 Bitmap Control + bit0: Traffic Indicator bit associated with Assoc ID 0 (Bcast AID?) + set to 1 in TIM elements with a value of 0 in the DTIM Count field + when one or more broadcast or multicast frames are buffered at the AP. + bit1-7: Bitmap Offset (logically Bitmap_Offset = Bitmap_Control & 0xFE). +4 n Partial Virtual Bitmap + Visible part of traffic-indication bitmap. + Full bitmap consists of 2008 bits (251 octets) such that bit number N + (0<=N<=2007) in the bitmap corresponds to bit number (N mod 8) + in octet number N/8 where the low-order bit of each octet is bit0, + and the high order bit is bit7. + Each set bit in virtual bitmap corresponds to traffic buffered by AP + for a specific station (with corresponding AID?). + Partial Virtual Bitmap shows a part of bitmap which has non-zero. + Bitmap Offset is a number of skipped zero octets (see above). + 'Missing' octets at the tail are also assumed to be zero. + Example: Length=6, Bitmap_Offset=2, Partial_Virtual_Bitmap=55 55 55 + This means that traffic-indication bitmap is: + 00000000 00000000 01010101 01010101 01010101 00000000 00000000... + (is bit0 in the map is always 0 and real value is in Bitmap Control bit0?) +*/ +static int +acx_s_set_tim_template(acx_device_t *adev) +{ +/* For now, configure smallish test bitmap, all zero ("no pending data") */ + enum { bitmap_size = 5 }; + + acx_template_tim_t t; + int result; + + FN_ENTER; + + memset(&t, 0, sizeof(t)); + t.size = 5 + bitmap_size; /* eid+len+count+period+bmap_ctrl + bmap */ + t.tim_eid = WLAN_EID_TIM; + t.len = 3 + bitmap_size; /* count+period+bmap_ctrl + bmap */ + result = acx_s_issue_cmd(adev, ACX1xx_CMD_CONFIG_TIM, &t, sizeof(t)); + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_fill_beacon_or_proberesp_template +** +** For frame format info, please see 802.11-1999.pdf item 7.2.3.9 and below!! +** +** NB: we use the fact that +** struct acx_template_proberesp and struct acx_template_beacon are the same +** (well, almost...) +** +** [802.11] Beacon's body consist of these IEs: +** 1 Timestamp +** 2 Beacon interval +** 3 Capability information +** 4 SSID +** 5 Supported rates (up to 8 rates) +** 6 FH Parameter Set (frequency-hopping PHYs only) +** 7 DS Parameter Set (direct sequence PHYs only) +** 8 CF Parameter Set (only if PCF is supported) +** 9 IBSS Parameter Set (ad-hoc only) +** +** Beacon only: +** 10 TIM (AP only) (see 802.11 7.3.2.6) +** 11 Country Information (802.11d) +** 12 FH Parameters (802.11d) +** 13 FH Pattern Table (802.11d) +** ... (?!! did not yet find relevant PDF file... --vda) +** 19 ERP Information (extended rate PHYs) +** 20 Extended Supported Rates (if more than 8 rates) +** +** Proberesp only: +** 10 Country information (802.11d) +** 11 FH Parameters (802.11d) +** 12 FH Pattern Table (802.11d) +** 13-n Requested information elements (802.11d) +** ???? +** 18 ERP Information (extended rate PHYs) +** 19 Extended Supported Rates (if more than 8 rates) +*/ +static int +acx_fill_beacon_or_proberesp_template(acx_device_t *adev, + struct acx_template_beacon *templ, + u16 fc /* in host order! */) +{ + int len; + u8 *p; + + FN_ENTER; + + memset(templ, 0, sizeof(*templ)); + MAC_BCAST(templ->da); + MAC_COPY(templ->sa, adev->dev_addr); + MAC_COPY(templ->bssid, adev->bssid); + + templ->beacon_interval = cpu_to_le16(adev->beacon_interval); + acx_update_capabilities(adev); + templ->cap = cpu_to_le16(adev->capabilities); + + p = templ->variable; + p = wlan_fill_ie_ssid(p, adev->essid_len, adev->essid); + p = wlan_fill_ie_rates(p, adev->rate_supported_len, adev->rate_supported); + p = wlan_fill_ie_ds_parms(p, adev->channel); + /* NB: should go AFTER tim, but acx seem to keep tim last always */ + p = wlan_fill_ie_rates_ext(p, adev->rate_supported_len, adev->rate_supported); + + switch (adev->mode) { + case ACX_MODE_0_ADHOC: + /* ATIM window */ + p = wlan_fill_ie_ibss_parms(p, 0); break; + case ACX_MODE_3_AP: + /* TIM IE is set up as separate template */ + break; + } + + len = p - (u8*)templ; + templ->fc = cpu_to_le16(WF_FTYPE_MGMT | fc); + /* - 2: do not count 'u16 size' field */ + templ->size = cpu_to_le16(len - 2); + + FN_EXIT1(len); + return len; +} + + +#if POWER_SAVE_80211 +/*********************************************************************** +** acx_s_set_null_data_template +*/ +static int +acx_s_set_null_data_template(acx_device_t *adev) +{ + struct acx_template_nullframe b; + int result; + + FN_ENTER; + + /* memset(&b, 0, sizeof(b)); not needed, setting all members */ + + b.size = cpu_to_le16(sizeof(b) - 2); + b.hdr.fc = WF_FTYPE_MGMTi | WF_FSTYPE_NULLi; + b.hdr.dur = 0; + MAC_BCAST(b.hdr.a1); + MAC_COPY(b.hdr.a2, adev->dev_addr); + MAC_COPY(b.hdr.a3, adev->bssid); + b.hdr.seq = 0; + + result = acx_s_issue_cmd(adev, ACX1xx_CMD_CONFIG_NULL_DATA, &b, sizeof(b)); + + FN_EXIT1(result); + return result; +} +#endif + + +/*********************************************************************** +** acx_s_set_beacon_template +*/ +static int +acx_s_set_beacon_template(acx_device_t *adev) +{ + struct acx_template_beacon bcn; + int len, result; + + FN_ENTER; + + len = acx_fill_beacon_or_proberesp_template(adev, &bcn, WF_FSTYPE_BEACON); + result = acx_s_issue_cmd(adev, ACX1xx_CMD_CONFIG_BEACON, &bcn, len); + + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_s_set_probe_response_template +*/ +static int +acx_s_set_probe_response_template(acx_device_t *adev) +{ + struct acx_template_proberesp pr; + int len, result; + + FN_ENTER; + + len = acx_fill_beacon_or_proberesp_template(adev, &pr, WF_FSTYPE_PROBERESP); + result = acx_s_issue_cmd(adev, ACX1xx_CMD_CONFIG_PROBE_RESPONSE, &pr, len); + + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +** acx_s_init_packet_templates() +** +** NOTE: order is very important here, to have a correct memory layout! +** init templates: max Probe Request (station mode), max NULL data, +** max Beacon, max TIM, max Probe Response. +*/ +static int +acx_s_init_packet_templates(acx_device_t *adev) +{ + acx_ie_memmap_t mm; /* ACX100 only */ + int result = NOT_OK; + + FN_ENTER; + + log(L_DEBUG|L_INIT, "initializing max packet templates\n"); + + if (OK != acx_s_init_max_probe_request_template(adev)) + goto failed; + + if (OK != acx_s_init_max_null_data_template(adev)) + goto failed; + + if (OK != acx_s_init_max_beacon_template(adev)) + goto failed; + + if (OK != acx_s_init_max_tim_template(adev)) + goto failed; + + if (OK != acx_s_init_max_probe_response_template(adev)) + goto failed; + + if (IS_ACX111(adev)) { + /* ACX111 doesn't need the memory map magic below, + * and the other templates will be set later (acx_start) */ + result = OK; + goto success; + } + + /* ACX100 will have its TIM template set, + * and we also need to update the memory map */ + + if (OK != acx_s_set_tim_template(adev)) + goto failed_acx100; + + log(L_DEBUG, "sizeof(memmap)=%d bytes\n", (int)sizeof(mm)); + + if (OK != acx_s_interrogate(adev, &mm, ACX1xx_IE_MEMORY_MAP)) + goto failed_acx100; + + mm.QueueStart = cpu_to_le32(le32_to_cpu(mm.PacketTemplateEnd) + 4); + if (OK != acx_s_configure(adev, &mm, ACX1xx_IE_MEMORY_MAP)) + goto failed_acx100; + + result = OK; + goto success; + +failed_acx100: + log(L_DEBUG|L_INIT, + /* "cb=0x%X\n" */ + "ACXMemoryMap:\n" + ".CodeStart=0x%X\n" + ".CodeEnd=0x%X\n" + ".WEPCacheStart=0x%X\n" + ".WEPCacheEnd=0x%X\n" + ".PacketTemplateStart=0x%X\n" + ".PacketTemplateEnd=0x%X\n", + /* len, */ + le32_to_cpu(mm.CodeStart), + le32_to_cpu(mm.CodeEnd), + le32_to_cpu(mm.WEPCacheStart), + le32_to_cpu(mm.WEPCacheEnd), + le32_to_cpu(mm.PacketTemplateStart), + le32_to_cpu(mm.PacketTemplateEnd)); + +failed: + printk("%s: %s() FAILED\n", adev->ndev->name, __func__); + +success: + FN_EXIT1(result); + return result; +} + + +/*********************************************************************** +*/ +static int +acx_s_set_probe_request_template(acx_device_t *adev) +{ + struct acx_template_probereq probereq; + char *p; + int res; + int frame_len; + + FN_ENTER; + + memset(&probereq, 0, sizeof(probereq)); + + probereq.fc = WF_FTYPE_MGMTi | WF_FSTYPE_PROBEREQi; + MAC_BCAST(probereq.da); + MAC_COPY(probereq.sa, adev->dev_addr); + MAC_BCAST(probereq.bssid); + + p = probereq.variable; + p = wlan_fill_ie_ssid(p, adev->essid_len, adev->essid); + p = wlan_fill_ie_rates(p, adev->rate_supported_len, adev->rate_supported); + p = wlan_fill_ie_rates_ext(p, adev->rate_supported_len, adev->rate_supported); + frame_len = p - (char*)&probereq; + probereq.size = cpu_to_le16(frame_len - 2); + + res = acx_s_issue_cmd(adev, ACX1xx_CMD_CONFIG_PROBE_REQUEST, &probereq, frame_len); + FN_EXIT0; + return res; +} + + +/*********************************************************************** +** acx_s_init_mac +*/ +int +acx_s_init_mac(acx_device_t *adev) +{ + int result = NOT_OK; + + FN_ENTER; + + if (IS_ACX111(adev)) { + adev->ie_len = acx111_ie_len; + adev->ie_len_dot11 = acx111_ie_len_dot11; + } else { + adev->ie_len = acx100_ie_len; + adev->ie_len_dot11 = acx100_ie_len_dot11; + } + + if (IS_PCI(adev)) { + adev->memblocksize = 256; /* 256 is default */ + /* try to load radio for both ACX100 and ACX111, since both + * chips have at least some firmware versions making use of an + * external radio module */ + acxpci_s_upload_radio(adev); + } else { + adev->memblocksize = 128; + } + + if (IS_ACX111(adev)) { + /* for ACX111, the order is different from ACX100 + 1. init packet templates + 2. create station context and create dma regions + 3. init wep default keys + */ + if (OK != acx_s_init_packet_templates(adev)) + goto fail; + if (OK != acx111_s_create_dma_regions(adev)) { + printk("%s: acx111_create_dma_regions FAILED\n", + adev->ndev->name); + goto fail; + } + } else { + if (OK != acx100_s_init_wep(adev)) + goto fail; + if (OK != acx_s_init_packet_templates(adev)) + goto fail; + if (OK != acx100_s_create_dma_regions(adev)) { + printk("%s: acx100_create_dma_regions FAILED\n", + adev->ndev->name); + goto fail; + } + } + + MAC_COPY(adev->ndev->dev_addr, adev->dev_addr); + result = OK; + +fail: + if (result) + printk("acx: init_mac() FAILED\n"); + FN_EXIT1(result); + return result; +} + + +void +acx_s_set_sane_reg_domain(acx_device_t *adev, int do_set) +{ + unsigned mask; + + unsigned int i; + + for (i = 0; i < sizeof(acx_reg_domain_ids); i++) + if (acx_reg_domain_ids[i] == adev->reg_dom_id) + break; + + if (sizeof(acx_reg_domain_ids) == i) { + log(L_INIT, "Invalid or unsupported regulatory domain" + " 0x%02X specified, falling back to FCC (USA)!" + " Please report if this sounds fishy!\n", + adev->reg_dom_id); + i = 0; + adev->reg_dom_id = acx_reg_domain_ids[i]; + + /* since there was a mismatch, we need to force updating */ + do_set = 1; + } + + if (do_set) { + acx_ie_generic_t dom; + dom.m.bytes[0] = adev->reg_dom_id; + acx_s_configure(adev, &dom, ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN); + } + + adev->reg_dom_chanmask = reg_domain_channel_masks[i]; + + mask = (1 << (adev->channel - 1)); + if (!(adev->reg_dom_chanmask & mask)) { + /* hmm, need to adjust our channel to reside within domain */ + mask = 1; + for (i = 1; i <= 14; i++) { + if (adev->reg_dom_chanmask & mask) { + printk("%s: adjusting selected channel from %d " + "to %d due to new regulatory domain\n", + adev->ndev->name, adev->channel, i); + adev->channel = i; + break; + } + mask <<= 1; + } + } +} + + +#if POWER_SAVE_80211 +static void +acx_s_update_80211_powersave_mode(acx_device_t *adev) +{ + /* merge both structs in a union to be able to have common code */ + union { + acx111_ie_powersave_t acx111; + acx100_ie_powersave_t acx100; + } pm; + + /* change 802.11 power save mode settings */ + log(L_INIT, "updating 802.11 power save mode settings: " + "wakeup_cfg 0x%02X, listen interval %u, " + "options 0x%02X, hangover period %u, " + "enhanced_ps_transition_time %u\n", + adev->ps_wakeup_cfg, adev->ps_listen_interval, + adev->ps_options, adev->ps_hangover_period, + adev->ps_enhanced_transition_time); + acx_s_interrogate(adev, &pm, ACX1xx_IE_POWER_MGMT); + log(L_INIT, "Previous PS mode settings: wakeup_cfg 0x%02X, " + "listen interval %u, options 0x%02X, " + "hangover period %u, " + "enhanced_ps_transition_time %u, beacon_rx_time %u\n", + pm.acx111.wakeup_cfg, + pm.acx111.listen_interval, + pm.acx111.options, + pm.acx111.hangover_period, + IS_ACX111(adev) ? + pm.acx111.enhanced_ps_transition_time + : pm.acx100.enhanced_ps_transition_time, + IS_ACX111(adev) ? + pm.acx111.beacon_rx_time + : (u32)-1 + ); + pm.acx111.wakeup_cfg = adev->ps_wakeup_cfg; + pm.acx111.listen_interval = adev->ps_listen_interval; + pm.acx111.options = adev->ps_options; + pm.acx111.hangover_period = adev->ps_hangover_period; + if (IS_ACX111(adev)) { + pm.acx111.beacon_rx_time = cpu_to_le32(adev->ps_beacon_rx_time); + pm.acx111.enhanced_ps_transition_time = cpu_to_le32(adev->ps_enhanced_transition_time); + } else { + pm.acx100.enhanced_ps_transition_time = cpu_to_le16(adev->ps_enhanced_transition_time); + } + acx_s_configure(adev, &pm, ACX1xx_IE_POWER_MGMT); + acx_s_interrogate(adev, &pm, ACX1xx_IE_POWER_MGMT); + log(L_INIT, "wakeup_cfg: 0x%02X\n", pm.acx111.wakeup_cfg); + acx_s_msleep(40); + acx_s_interrogate(adev, &pm, ACX1xx_IE_POWER_MGMT); + log(L_INIT, "wakeup_cfg: 0x%02X\n", pm.acx111.wakeup_cfg); + log(L_INIT, "power save mode change %s\n", + (pm.acx111.wakeup_cfg & PS_CFG_PENDING) ? "FAILED" : "was successful"); + /* FIXME: maybe verify via PS_CFG_PENDING bit here + * that power save mode change was successful. */ + /* FIXME: we shouldn't trigger a scan immediately after + * fiddling with power save mode (since the firmware is sending + * a NULL frame then). */ +} +#endif + + +/*********************************************************************** +** acx_s_update_card_settings +** +** Applies accumulated changes in various adev->xxxx members +** Called by ioctl commit handler, acx_start, acx_set_defaults, +** acx_s_after_interrupt_task (if IRQ_CMD_UPDATE_CARD_CFG), +*/ +static void +acx111_s_sens_radio_16_17(acx_device_t *adev) +{ + u32 feature1, feature2; + + if ((adev->sensitivity < 1) || (adev->sensitivity > 3)) { + printk("%s: invalid sensitivity setting (1..3), " + "setting to 1\n", adev->ndev->name); + adev->sensitivity = 1; + } + acx111_s_get_feature_config(adev, &feature1, &feature2); + CLEAR_BIT(feature1, FEATURE1_LOW_RX|FEATURE1_EXTRA_LOW_RX); + if (adev->sensitivity > 1) + SET_BIT(feature1, FEATURE1_LOW_RX); + if (adev->sensitivity > 2) + SET_BIT(feature1, FEATURE1_EXTRA_LOW_RX); + acx111_s_feature_set(adev, feature1, feature2); +} + + +void +acx_s_update_card_settings(acx_device_t *adev) +{ + unsigned long flags; + unsigned int start_scan = 0; + int i; + + FN_ENTER; + + log(L_INIT, "get_mask 0x%08X, set_mask 0x%08X\n", + adev->get_mask, adev->set_mask); + + /* Track dependencies betweed various settings */ + + if (adev->set_mask & (GETSET_MODE|GETSET_RESCAN|GETSET_WEP)) { + log(L_INIT, "important setting has been changed. " + "Need to update packet templates, too\n"); + SET_BIT(adev->set_mask, SET_TEMPLATES); + } + if (adev->set_mask & GETSET_CHANNEL) { + /* This will actually tune RX/TX to the channel */ + SET_BIT(adev->set_mask, GETSET_RX|GETSET_TX); + switch (adev->mode) { + case ACX_MODE_0_ADHOC: + case ACX_MODE_3_AP: + /* Beacons contain channel# - update them */ + SET_BIT(adev->set_mask, SET_TEMPLATES); + } + switch (adev->mode) { + case ACX_MODE_0_ADHOC: + case ACX_MODE_2_STA: + start_scan = 1; + } + } + + /* Apply settings */ + +#ifdef WHY_SHOULD_WE_BOTHER /* imagine we were just powered off */ + /* send a disassoc request in case it's required */ + if (adev->set_mask & (GETSET_MODE|GETSET_RESCAN|GETSET_CHANNEL|GETSET_WEP)) { + if (ACX_MODE_2_STA == adev->mode) { + if (ACX_STATUS_4_ASSOCIATED == adev->status) { + log(L_ASSOC, "we were ASSOCIATED - " + "sending disassoc request\n"); + acx_lock(adev, flags); + acx_l_transmit_disassoc(adev, NULL); + /* FIXME: deauth? */ + acx_unlock(adev, flags); + } + /* need to reset some other stuff as well */ + log(L_DEBUG, "resetting bssid\n"); + MAC_ZERO(adev->bssid); + SET_BIT(adev->set_mask, SET_TEMPLATES|SET_STA_LIST); + start_scan = 1; + } + } +#endif + + if (adev->get_mask & GETSET_STATION_ID) { + u8 stationID[4 + ACX1xx_IE_DOT11_STATION_ID_LEN]; + const u8 *paddr; + + acx_s_interrogate(adev, &stationID, ACX1xx_IE_DOT11_STATION_ID); + paddr = &stationID[4]; + for (i = 0; i < ETH_ALEN; i++) { + /* we copy the MAC address (reversed in + * the card) to the netdevice's MAC + * address, and on ifup it will be + * copied into iwadev->dev_addr */ + adev->ndev->dev_addr[ETH_ALEN - 1 - i] = paddr[i]; + } + CLEAR_BIT(adev->get_mask, GETSET_STATION_ID); + } + + if (adev->get_mask & GETSET_SENSITIVITY) { + if ((RADIO_RFMD_11 == adev->radio_type) + || (RADIO_MAXIM_0D == adev->radio_type) + || (RADIO_RALINK_15 == adev->radio_type)) { + acx_s_read_phy_reg(adev, 0x30, &adev->sensitivity); + } else { + log(L_INIT, "don't know how to get sensitivity " + "for radio type 0x%02X\n", adev->radio_type); + adev->sensitivity = 0; + } + log(L_INIT, "got sensitivity value %u\n", adev->sensitivity); + + CLEAR_BIT(adev->get_mask, GETSET_SENSITIVITY); + } + + if (adev->get_mask & GETSET_ANTENNA) { + u8 antenna[4 + ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN]; + + memset(antenna, 0, sizeof(antenna)); + acx_s_interrogate(adev, antenna, ACX1xx_IE_DOT11_CURRENT_ANTENNA); + adev->antenna = antenna[4]; + log(L_INIT, "got antenna value 0x%02X\n", adev->antenna); + CLEAR_BIT(adev->get_mask, GETSET_ANTENNA); + } + + if (adev->get_mask & GETSET_ED_THRESH) { + if (IS_ACX100(adev)) { + u8 ed_threshold[4 + ACX100_IE_DOT11_ED_THRESHOLD_LEN]; + + memset(ed_threshold, 0, sizeof(ed_threshold)); + acx_s_interrogate(adev, ed_threshold, ACX100_IE_DOT11_ED_THRESHOLD); + adev->ed_threshold = ed_threshold[4]; + } else { + log(L_INIT, "acx111 doesn't support ED\n"); + adev->ed_threshold = 0; + } + log(L_INIT, "got Energy Detect (ED) threshold %u\n", adev->ed_threshold); + CLEAR_BIT(adev->get_mask, GETSET_ED_THRESH); + } + + if (adev->get_mask & GETSET_CCA) { + if (IS_ACX100(adev)) { + u8 cca[4 + ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN]; + + memset(cca, 0, sizeof(adev->cca)); + acx_s_interrogate(adev, cca, ACX1xx_IE_DOT11_CURRENT_CCA_MODE); + adev->cca = cca[4]; + } else { + log(L_INIT, "acx111 doesn't support CCA\n"); + adev->cca = 0; + } + log(L_INIT, "got Channel Clear Assessment (CCA) value %u\n", adev->cca); + CLEAR_BIT(adev->get_mask, GETSET_CCA); + } + + if (adev->get_mask & GETSET_REG_DOMAIN) { + acx_ie_generic_t dom; + + acx_s_interrogate(adev, &dom, ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN); + adev->reg_dom_id = dom.m.bytes[0]; + acx_s_set_sane_reg_domain(adev, 0); + log(L_INIT, "got regulatory domain 0x%02X\n", adev->reg_dom_id); + CLEAR_BIT(adev->get_mask, GETSET_REG_DOMAIN); + } + + if (adev->set_mask & GETSET_STATION_ID) { + u8 stationID[4 + ACX1xx_IE_DOT11_STATION_ID_LEN]; + u8 *paddr; + + paddr = &stationID[4]; + memcpy(adev->dev_addr, adev->ndev->dev_addr, ETH_ALEN); + for (i = 0; i < ETH_ALEN; i++) { + /* copy the MAC address we obtained when we noticed + * that the ethernet iface's MAC changed + * to the card (reversed in + * the card!) */ + paddr[i] = adev->dev_addr[ETH_ALEN - 1 - i]; + } + acx_s_configure(adev, &stationID, ACX1xx_IE_DOT11_STATION_ID); + CLEAR_BIT(adev->set_mask, GETSET_STATION_ID); + } + + if (adev->set_mask & SET_TEMPLATES) { + log(L_INIT, "updating packet templates\n"); + switch (adev->mode) { + case ACX_MODE_2_STA: + acx_s_set_probe_request_template(adev); +#if POWER_SAVE_80211 + acx_s_set_null_data_template(adev); +#endif + break; + case ACX_MODE_0_ADHOC: + acx_s_set_probe_request_template(adev); +#if POWER_SAVE_80211 + /* maybe power save functionality is somehow possible + * for Ad-Hoc mode, too... FIXME: verify it somehow? firmware debug fields? */ + acx_s_set_null_data_template(adev); +#endif + /* fall through */ + case ACX_MODE_3_AP: + acx_s_set_beacon_template(adev); + acx_s_set_tim_template(adev); + /* BTW acx111 firmware would not send probe responses + ** if probe request does not have all basic rates flagged + ** by 0x80! Thus firmware does not conform to 802.11, + ** it should ignore 0x80 bit in ratevector from STA. + ** We can 'fix' it by not using this template and + ** sending probe responses by hand. TODO --vda */ + acx_s_set_probe_response_template(adev); + } + /* Needed if generated frames are to be emitted at different tx rate now */ + log(L_IRQ, "redoing cmd_join_bssid() after template cfg\n"); + acx_s_cmd_join_bssid(adev, adev->bssid); + CLEAR_BIT(adev->set_mask, SET_TEMPLATES); + } + if (adev->set_mask & SET_STA_LIST) { + acx_lock(adev, flags); + acx_l_sta_list_init(adev); + CLEAR_BIT(adev->set_mask, SET_STA_LIST); + acx_unlock(adev, flags); + } + if (adev->set_mask & SET_RATE_FALLBACK) { + u8 rate[4 + ACX1xx_IE_RATE_FALLBACK_LEN]; + + /* configure to not do fallbacks when not in auto rate mode */ + rate[4] = (adev->rate_auto) ? /* adev->txrate_fallback_retries */ 1 : 0; + log(L_INIT, "updating Tx fallback to %u retries\n", rate[4]); + acx_s_configure(adev, &rate, ACX1xx_IE_RATE_FALLBACK); + CLEAR_BIT(adev->set_mask, SET_RATE_FALLBACK); + } + if (adev->set_mask & GETSET_TXPOWER) { + log(L_INIT, "updating transmit power: %u dBm\n", + adev->tx_level_dbm); + acx_s_set_tx_level(adev, adev->tx_level_dbm); + CLEAR_BIT(adev->set_mask, GETSET_TXPOWER); + } + + if (adev->set_mask & GETSET_SENSITIVITY) { + log(L_INIT, "updating sensitivity value: %u\n", + adev->sensitivity); + switch (adev->radio_type) { + case RADIO_RFMD_11: + case RADIO_MAXIM_0D: + case RADIO_RALINK_15: + acx_s_write_phy_reg(adev, 0x30, adev->sensitivity); + break; + case RADIO_RADIA_16: + case RADIO_UNKNOWN_17: + acx111_s_sens_radio_16_17(adev); + break; + default: + log(L_INIT, "don't know how to modify sensitivity " + "for radio type 0x%02X\n", adev->radio_type); + } + CLEAR_BIT(adev->set_mask, GETSET_SENSITIVITY); + } + + if (adev->set_mask & GETSET_ANTENNA) { + /* antenna */ + u8 antenna[4 + ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN]; + + memset(antenna, 0, sizeof(antenna)); + antenna[4] = adev->antenna; + log(L_INIT, "updating antenna value: 0x%02X\n", + adev->antenna); + acx_s_configure(adev, &antenna, ACX1xx_IE_DOT11_CURRENT_ANTENNA); + CLEAR_BIT(adev->set_mask, GETSET_ANTENNA); + } + + if (adev->set_mask & GETSET_ED_THRESH) { + /* ed_threshold */ + log(L_INIT, "updating Energy Detect (ED) threshold: %u\n", + adev->ed_threshold); + if (IS_ACX100(adev)) { + u8 ed_threshold[4 + ACX100_IE_DOT11_ED_THRESHOLD_LEN]; + + memset(ed_threshold, 0, sizeof(ed_threshold)); + ed_threshold[4] = adev->ed_threshold; + acx_s_configure(adev, &ed_threshold, ACX100_IE_DOT11_ED_THRESHOLD); + } + else + log(L_INIT, "acx111 doesn't support ED!\n"); + CLEAR_BIT(adev->set_mask, GETSET_ED_THRESH); + } + + if (adev->set_mask & GETSET_CCA) { + /* CCA value */ + log(L_INIT, "updating Channel Clear Assessment " + "(CCA) value: 0x%02X\n", adev->cca); + if (IS_ACX100(adev)) { + u8 cca[4 + ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN]; + + memset(cca, 0, sizeof(cca)); + cca[4] = adev->cca; + acx_s_configure(adev, &cca, ACX1xx_IE_DOT11_CURRENT_CCA_MODE); + } + else + log(L_INIT, "acx111 doesn't support CCA!\n"); + CLEAR_BIT(adev->set_mask, GETSET_CCA); + } + + if (adev->set_mask & GETSET_LED_POWER) { + /* Enable Tx */ + log(L_INIT, "updating power LED status: %u\n", adev->led_power); + + acx_lock(adev, flags); + if (IS_PCI(adev)) + acxpci_l_power_led(adev, adev->led_power); + CLEAR_BIT(adev->set_mask, GETSET_LED_POWER); + acx_unlock(adev, flags); + } + + if (adev->set_mask & GETSET_POWER_80211) { +#if POWER_SAVE_80211 + acx_s_update_80211_powersave_mode(adev); +#endif + CLEAR_BIT(adev->set_mask, GETSET_POWER_80211); + } + + if (adev->set_mask & GETSET_CHANNEL) { + /* channel */ + log(L_INIT, "updating channel to: %u\n", adev->channel); + CLEAR_BIT(adev->set_mask, GETSET_CHANNEL); + } + + if (adev->set_mask & GETSET_TX) { + /* set Tx */ + log(L_INIT, "updating: %s Tx\n", + adev->tx_disabled ? "disable" : "enable"); + if (adev->tx_disabled) + acx_s_issue_cmd(adev, ACX1xx_CMD_DISABLE_TX, NULL, 0); + else + acx_s_issue_cmd(adev, ACX1xx_CMD_ENABLE_TX, &adev->channel, 1); + CLEAR_BIT(adev->set_mask, GETSET_TX); + } + + if (adev->set_mask & GETSET_RX) { + /* Enable Rx */ + log(L_INIT, "updating: enable Rx on channel: %u\n", + adev->channel); + acx_s_issue_cmd(adev, ACX1xx_CMD_ENABLE_RX, &adev->channel, 1); + CLEAR_BIT(adev->set_mask, GETSET_RX); + } + + if (adev->set_mask & GETSET_RETRY) { + u8 short_retry[4 + ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT_LEN]; + u8 long_retry[4 + ACX1xx_IE_DOT11_LONG_RETRY_LIMIT_LEN]; + + log(L_INIT, "updating short retry limit: %u, long retry limit: %u\n", + adev->short_retry, adev->long_retry); + short_retry[0x4] = adev->short_retry; + long_retry[0x4] = adev->long_retry; + acx_s_configure(adev, &short_retry, ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT); + acx_s_configure(adev, &long_retry, ACX1xx_IE_DOT11_LONG_RETRY_LIMIT); + CLEAR_BIT(adev->set_mask, GETSET_RETRY); + } + + if (adev->set_mask & SET_MSDU_LIFETIME) { + u8 xmt_msdu_lifetime[4 + ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME_LEN]; + + log(L_INIT, "updating tx MSDU lifetime: %u\n", + adev->msdu_lifetime); + *(u32 *)&xmt_msdu_lifetime[4] = cpu_to_le32((u32)adev->msdu_lifetime); + acx_s_configure(adev, &xmt_msdu_lifetime, ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME); + CLEAR_BIT(adev->set_mask, SET_MSDU_LIFETIME); + } + + if (adev->set_mask & GETSET_REG_DOMAIN) { + log(L_INIT, "updating regulatory domain: 0x%02X\n", + adev->reg_dom_id); + acx_s_set_sane_reg_domain(adev, 1); + CLEAR_BIT(adev->set_mask, GETSET_REG_DOMAIN); + } + + if (adev->set_mask & GETSET_MODE) { + adev->ndev->type = (adev->mode == ACX_MODE_MONITOR) ? + adev->monitor_type : ARPHRD_ETHER; + + switch (adev->mode) { + case ACX_MODE_3_AP: + + acx_lock(adev, flags); + acx_l_sta_list_init(adev); + adev->aid = 0; + adev->ap_client = NULL; + MAC_COPY(adev->bssid, adev->dev_addr); + /* this basically says "we're connected" */ + acx_set_status(adev, ACX_STATUS_4_ASSOCIATED); + acx_unlock(adev, flags); + + acx111_s_feature_off(adev, 0, FEATURE2_NO_TXCRYPT|FEATURE2_SNIFFER); + /* start sending beacons */ + acx_s_cmd_join_bssid(adev, adev->bssid); + break; + case ACX_MODE_MONITOR: + acx111_s_feature_on(adev, 0, FEATURE2_NO_TXCRYPT|FEATURE2_SNIFFER); + /* this stops beacons */ + acx_s_cmd_join_bssid(adev, adev->bssid); + /* this basically says "we're connected" */ + acx_set_status(adev, ACX_STATUS_4_ASSOCIATED); + SET_BIT(adev->set_mask, SET_RXCONFIG|SET_WEP_OPTIONS); + break; + case ACX_MODE_0_ADHOC: + case ACX_MODE_2_STA: + acx111_s_feature_off(adev, 0, FEATURE2_NO_TXCRYPT|FEATURE2_SNIFFER); + + acx_lock(adev, flags); + adev->aid = 0; + adev->ap_client = NULL; + acx_unlock(adev, flags); + + /* we want to start looking for peer or AP */ + start_scan = 1; + break; + case ACX_MODE_OFF: + /* TODO: disable RX/TX, stop any scanning activity etc: */ + /* adev->tx_disabled = 1; */ + /* SET_BIT(adev->set_mask, GETSET_RX|GETSET_TX); */ + + /* This stops beacons (invalid macmode...) */ + acx_s_cmd_join_bssid(adev, adev->bssid); + acx_set_status(adev, ACX_STATUS_0_STOPPED); + break; + } + CLEAR_BIT(adev->set_mask, GETSET_MODE); + } + + if (adev->set_mask & SET_RXCONFIG) { + acx_s_initialize_rx_config(adev); + CLEAR_BIT(adev->set_mask, SET_RXCONFIG); + } + + if (adev->set_mask & GETSET_RESCAN) { + switch (adev->mode) { + case ACX_MODE_0_ADHOC: + case ACX_MODE_2_STA: + start_scan = 1; + break; + } + CLEAR_BIT(adev->set_mask, GETSET_RESCAN); + } + + if (adev->set_mask & GETSET_WEP) { + /* encode */ + + ie_dot11WEPDefaultKeyID_t dkey; +#ifdef DEBUG_WEP + struct { + u16 type; + u16 len; + u8 val; + } ACX_PACKED keyindic; +#endif + log(L_INIT, "updating WEP key settings\n"); + + acx_s_set_wepkey(adev); + + dkey.KeyID = adev->wep_current_index; + log(L_INIT, "setting WEP key %u as default\n", dkey.KeyID); + acx_s_configure(adev, &dkey, ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET); +#ifdef DEBUG_WEP + keyindic.val = 3; + acx_s_configure(adev, &keyindic, ACX111_IE_KEY_CHOOSE); +#endif + start_scan = 1; + CLEAR_BIT(adev->set_mask, GETSET_WEP); + } + + if (adev->set_mask & SET_WEP_OPTIONS) { + acx100_ie_wep_options_t options; + + if (IS_ACX111(adev)) { + log(L_DEBUG, "setting WEP Options for acx111 is not supported\n"); + } else { + log(L_INIT, "setting WEP Options\n"); + + /* let's choose maximum setting: 4 default keys, + * plus 10 other keys: */ + options.NumKeys = cpu_to_le16(DOT11_MAX_DEFAULT_WEP_KEYS + 10); + /* don't decrypt default key only, + * don't override decryption: */ + options.WEPOption = 0; + if (adev->mode == ACX_MODE_MONITOR) { + /* don't decrypt default key only, + * override decryption mechanism: */ + options.WEPOption = 2; + } + + acx_s_configure(adev, &options, ACX100_IE_WEP_OPTIONS); + } + CLEAR_BIT(adev->set_mask, SET_WEP_OPTIONS); + } + + /* Rescan was requested */ + if (start_scan) { + switch (adev->mode) { + case ACX_MODE_0_ADHOC: + case ACX_MODE_2_STA: + /* We can avoid clearing list if join code + ** will be a bit more clever about not picking + ** 'bad' AP over and over again */ + acx_lock(adev, flags); + adev->ap_client = NULL; + acx_l_sta_list_init(adev); + acx_set_status(adev, ACX_STATUS_1_SCANNING); + acx_unlock(adev, flags); + + acx_s_cmd_start_scan(adev); + } + } + + /* debug, rate, and nick don't need any handling */ + /* what about sniffing mode?? */ + + log(L_INIT, "get_mask 0x%08X, set_mask 0x%08X - after update\n", + adev->get_mask, adev->set_mask); + +/* end: */ + FN_EXIT0; +} + + +/*********************************************************************** +** acx_e_after_interrupt_task +*/ +static int +acx_s_recalib_radio(acx_device_t *adev) +{ + if (IS_ACX111(adev)) { + acx111_cmd_radiocalib_t cal; + + printk("%s: recalibrating radio\n", adev->ndev->name); + /* automatic recalibration, choose all methods: */ + cal.methods = cpu_to_le32(0x8000000f); + /* automatic recalibration every 60 seconds (value in TUs) + * I wonder what the firmware default here is? */ + cal.interval = cpu_to_le32(58594); + return acx_s_issue_cmd_timeo(adev, ACX111_CMD_RADIOCALIB, + &cal, sizeof(cal), CMD_TIMEOUT_MS(100)); + } else { + /* On ACX100, we need to recalibrate the radio + * by issuing a GETSET_TX|GETSET_RX */ + if (/* (OK == acx_s_issue_cmd(adev, ACX1xx_CMD_DISABLE_TX, NULL, 0)) && + (OK == acx_s_issue_cmd(adev, ACX1xx_CMD_DISABLE_RX, NULL, 0)) && */ + (OK == acx_s_issue_cmd(adev, ACX1xx_CMD_ENABLE_TX, &adev->channel, 1)) && + (OK == acx_s_issue_cmd(adev, ACX1xx_CMD_ENABLE_RX, &adev->channel, 1)) ) + return OK; + return NOT_OK; + } +} + +static void +acx_s_after_interrupt_recalib(acx_device_t *adev) +{ + int res; + + /* this helps with ACX100 at least; + * hopefully ACX111 also does a + * recalibration here */ + + /* clear flag beforehand, since we want to make sure + * it's cleared; then only set it again on specific circumstances */ + CLEAR_BIT(adev->after_interrupt_jobs, ACX_AFTER_IRQ_CMD_RADIO_RECALIB); + + /* better wait a bit between recalibrations to + * prevent overheating due to torturing the card + * into working too long despite high temperature + * (just a safety measure) */ + if (adev->recalib_time_last_success + && time_before(jiffies, adev->recalib_time_last_success + + RECALIB_PAUSE * 60 * HZ)) { + if (adev->recalib_msg_ratelimit <= 4) { + printk("%s: less than " STRING(RECALIB_PAUSE) + " minutes since last radio recalibration, " + "not recalibrating (maybe card is too hot?)\n", + adev->ndev->name); + adev->recalib_msg_ratelimit++; + if (adev->recalib_msg_ratelimit == 5) + printk("disabling above message until next recalib\n"); + } + return; + } + + adev->recalib_msg_ratelimit = 0; + + /* note that commands sometimes fail (card busy), + * so only clear flag if we were fully successful */ + res = acx_s_recalib_radio(adev); + if (res == OK) { + printk("%s: successfully recalibrated radio\n", + adev->ndev->name); + adev->recalib_time_last_success = jiffies; + adev->recalib_failure_count = 0; + } else { + /* failed: resubmit, but only limited + * amount of times within some time range + * to prevent endless loop */ + + adev->recalib_time_last_success = 0; /* we failed */ + + /* if some time passed between last + * attempts, then reset failure retry counter + * to be able to do next recalib attempt */ + if (time_after(jiffies, adev->recalib_time_last_attempt + 5*HZ)) + adev->recalib_failure_count = 0; + + if (adev->recalib_failure_count < 5) { + /* increment inside only, for speedup of outside path */ + adev->recalib_failure_count++; + adev->recalib_time_last_attempt = jiffies; + acx_schedule_task(adev, ACX_AFTER_IRQ_CMD_RADIO_RECALIB); + } + } +} + +static void +acx_e_after_interrupt_task(struct work_struct *work) +{ + acx_device_t *adev = container_of(work, acx_device_t, after_interrupt_task); + + FN_ENTER; + + acx_sem_lock(adev); + + if (!adev->after_interrupt_jobs) + goto end; /* no jobs to do */ + +#if TX_CLEANUP_IN_SOFTIRQ + /* can happen only on PCI */ + if (adev->after_interrupt_jobs & ACX_AFTER_IRQ_TX_CLEANUP) { + acx_lock(adev, flags); + acxpci_l_clean_txdesc(adev); + CLEAR_BIT(adev->after_interrupt_jobs, ACX_AFTER_IRQ_TX_CLEANUP); + acx_unlock(adev, flags); + } +#endif + /* we see lotsa tx errors */ + if (adev->after_interrupt_jobs & ACX_AFTER_IRQ_CMD_RADIO_RECALIB) { + acx_s_after_interrupt_recalib(adev); + } + + /* a poor interrupt code wanted to do update_card_settings() */ + if (adev->after_interrupt_jobs & ACX_AFTER_IRQ_UPDATE_CARD_CFG) { + if (ACX_STATE_IFACE_UP & adev->dev_state_mask) + acx_s_update_card_settings(adev); + CLEAR_BIT(adev->after_interrupt_jobs, ACX_AFTER_IRQ_UPDATE_CARD_CFG); + } + + /* 1) we detected that no Scan_Complete IRQ came from fw, or + ** 2) we found too many STAs */ + if (adev->after_interrupt_jobs & ACX_AFTER_IRQ_CMD_STOP_SCAN) { + log(L_IRQ, "sending a stop scan cmd...\n"); + acx_s_issue_cmd(adev, ACX1xx_CMD_STOP_SCAN, NULL, 0); + /* HACK: set the IRQ bit, since we won't get a + * scan complete IRQ any more on ACX111 (works on ACX100!), + * since _we_, not a fw, have stopped the scan */ + SET_BIT(adev->irq_status, HOST_INT_SCAN_COMPLETE); + CLEAR_BIT(adev->after_interrupt_jobs, ACX_AFTER_IRQ_CMD_STOP_SCAN); + } + + /* either fw sent Scan_Complete or we detected that + ** no Scan_Complete IRQ came from fw. Finish scanning, + ** pick join partner if any */ + if (adev->after_interrupt_jobs & ACX_AFTER_IRQ_COMPLETE_SCAN) { + if (adev->status == ACX_STATUS_1_SCANNING) { + if (OK != acx_s_complete_scan(adev)) { + SET_BIT(adev->after_interrupt_jobs, + ACX_AFTER_IRQ_RESTART_SCAN); + } + } else { + /* + scan kills current join status - restore it + ** (do we need it for STA?) */ + /* + does it happen only with active scans? + ** active and passive scans? ALL scans including + ** background one? */ + /* + was not verified that everything is restored + ** (but at least we start to emit beacons again) */ + switch (adev->mode) { + case ACX_MODE_0_ADHOC: + case ACX_MODE_3_AP: + log(L_IRQ, "redoing cmd_join_bssid() after scan\n"); + acx_s_cmd_join_bssid(adev, adev->bssid); + } + } + CLEAR_BIT(adev->after_interrupt_jobs, ACX_AFTER_IRQ_COMPLETE_SCAN); + } + + /* STA auth or assoc timed out, start over again */ + if (adev->after_interrupt_jobs & ACX_AFTER_IRQ_RESTART_SCAN) { + log(L_IRQ, "sending a start_scan cmd...\n"); + acx_s_cmd_start_scan(adev); + CLEAR_BIT(adev->after_interrupt_jobs, ACX_AFTER_IRQ_RESTART_SCAN); + } + + /* whee, we got positive assoc response! 8) */ + if (adev->after_interrupt_jobs & ACX_AFTER_IRQ_CMD_ASSOCIATE) { + acx_ie_generic_t pdr; + /* tiny race window exists, checking that we still a STA */ + switch (adev->mode) { + case ACX_MODE_2_STA: + pdr.m.aid = cpu_to_le16(adev->aid); + acx_s_configure(adev, &pdr, ACX1xx_IE_ASSOC_ID); + acx_set_status(adev, ACX_STATUS_4_ASSOCIATED); + log(L_ASSOC|L_DEBUG, "ASSOCIATED!\n"); + CLEAR_BIT(adev->after_interrupt_jobs, ACX_AFTER_IRQ_CMD_ASSOCIATE); + } + } +end: + acx_sem_unlock(adev); + FN_EXIT0; +} + + +/*********************************************************************** +** acx_schedule_task +** +** Schedule the call of the after_interrupt method after leaving +** the interrupt context. +*/ +void +acx_schedule_task(acx_device_t *adev, unsigned int set_flag) +{ + SET_BIT(adev->after_interrupt_jobs, set_flag); + SCHEDULE_WORK(&adev->after_interrupt_task); +} + + +/*********************************************************************** +*/ +void +acx_init_task_scheduler(acx_device_t *adev) +{ + /* configure task scheduler */ + INIT_WORK(&adev->after_interrupt_task, acx_e_after_interrupt_task); +} + + +/*********************************************************************** +** acx_s_start +*/ +void +acx_s_start(acx_device_t *adev) +{ + FN_ENTER; + + /* + * Ok, now we do everything that can possibly be done with ioctl + * calls to make sure that when it was called before the card + * was up we get the changes asked for + */ + + SET_BIT(adev->set_mask, SET_TEMPLATES|SET_STA_LIST|GETSET_WEP + |GETSET_TXPOWER|GETSET_ANTENNA|GETSET_ED_THRESH|GETSET_CCA + |GETSET_REG_DOMAIN|GETSET_MODE|GETSET_CHANNEL + |GETSET_TX|GETSET_RX|GETSET_STATION_ID); + + log(L_INIT, "updating initial settings on iface activation\n"); + acx_s_update_card_settings(adev); + + FN_EXIT0; +} + + +/*********************************************************************** +** acx_update_capabilities +*/ +void +acx_update_capabilities(acx_device_t *adev) +{ + u16 cap = 0; + + switch (adev->mode) { + case ACX_MODE_3_AP: + SET_BIT(cap, WF_MGMT_CAP_ESS); break; + case ACX_MODE_0_ADHOC: + SET_BIT(cap, WF_MGMT_CAP_IBSS); break; + /* other types of stations do not emit beacons */ + } + + if (adev->wep_restricted) { + SET_BIT(cap, WF_MGMT_CAP_PRIVACY); + } + if (adev->cfgopt_dot11ShortPreambleOption) { + SET_BIT(cap, WF_MGMT_CAP_SHORT); + } + if (adev->cfgopt_dot11PBCCOption) { + SET_BIT(cap, WF_MGMT_CAP_PBCC); + } + if (adev->cfgopt_dot11ChannelAgility) { + SET_BIT(cap, WF_MGMT_CAP_AGILITY); + } + log(L_DEBUG, "caps updated from 0x%04X to 0x%04X\n", + adev->capabilities, cap); + adev->capabilities = cap; +} + +/*********************************************************************** +** Common function to parse ALL configoption struct formats +** (ACX100 and ACX111; FIXME: how to make it work with ACX100 USB!?!?). +** FIXME: logging should be removed here and added to a /proc file instead +*/ +void +acx_s_parse_configoption(acx_device_t *adev, const acx111_ie_configoption_t *pcfg) +{ + const u8 *pEle; + int i; + int is_acx111 = IS_ACX111(adev); + + if (acx_debug & L_DEBUG) { + printk("configoption struct content:\n"); + acx_dump_bytes(pcfg, sizeof(*pcfg)); + } + + if (( is_acx111 && (adev->eeprom_version == 5)) + || (!is_acx111 && (adev->eeprom_version == 4)) + || (!is_acx111 && (adev->eeprom_version == 5))) { + /* these versions are known to be supported */ + } else { + printk("unknown chip and EEPROM version combination (%s, v%d), " + "don't know how to parse config options yet. " + "Please report\n", is_acx111 ? "ACX111" : "ACX100", + adev->eeprom_version); + return; + } + + /* first custom-parse the first part which has chip-specific layout */ + + pEle = (const u8 *) pcfg; + + pEle += 4; /* skip (type,len) header */ + + memcpy(adev->cfgopt_NVSv, pEle, sizeof(adev->cfgopt_NVSv)); + pEle += sizeof(adev->cfgopt_NVSv); + + if (is_acx111) { + adev->cfgopt_NVS_vendor_offs = le16_to_cpu(*(u16 *)pEle); + pEle += sizeof(adev->cfgopt_NVS_vendor_offs); + + adev->cfgopt_probe_delay = 200; /* good default value? */ + pEle += 2; /* FIXME: unknown, value 0x0001 */ + } else { + memcpy(adev->cfgopt_MAC, pEle, sizeof(adev->cfgopt_MAC)); + pEle += sizeof(adev->cfgopt_MAC); + + adev->cfgopt_probe_delay = le16_to_cpu(*(u16 *)pEle); + pEle += sizeof(adev->cfgopt_probe_delay); + if ((adev->cfgopt_probe_delay < 100) || (adev->cfgopt_probe_delay > 500)) { + printk("strange probe_delay value %d, " + "tweaking to 200\n", adev->cfgopt_probe_delay); + adev->cfgopt_probe_delay = 200; + } + } + + adev->cfgopt_eof_memory = le32_to_cpu(*(u32 *)pEle); + pEle += sizeof(adev->cfgopt_eof_memory); + + printk("NVS_vendor_offs:%04X probe_delay:%d eof_memory:%d\n", + adev->cfgopt_NVS_vendor_offs, + adev->cfgopt_probe_delay, + adev->cfgopt_eof_memory); + + adev->cfgopt_dot11CCAModes = *pEle++; + adev->cfgopt_dot11Diversity = *pEle++; + adev->cfgopt_dot11ShortPreambleOption = *pEle++; + adev->cfgopt_dot11PBCCOption = *pEle++; + adev->cfgopt_dot11ChannelAgility = *pEle++; + adev->cfgopt_dot11PhyType = *pEle++; + adev->cfgopt_dot11TempType = *pEle++; + printk("CCAModes:%02X Diversity:%02X ShortPreOpt:%02X " + "PBCC:%02X ChanAgil:%02X PHY:%02X Temp:%02X\n", + adev->cfgopt_dot11CCAModes, + adev->cfgopt_dot11Diversity, + adev->cfgopt_dot11ShortPreambleOption, + adev->cfgopt_dot11PBCCOption, + adev->cfgopt_dot11ChannelAgility, + adev->cfgopt_dot11PhyType, + adev->cfgopt_dot11TempType); + + /* then use common parsing for next part which has common layout */ + + pEle++; /* skip table_count (6) */ + + adev->cfgopt_antennas.type = pEle[0]; + adev->cfgopt_antennas.len = pEle[1]; + printk("AntennaID:%02X Len:%02X Data:", + adev->cfgopt_antennas.type, adev->cfgopt_antennas.len); + for (i = 0; i < pEle[1]; i++) { + adev->cfgopt_antennas.list[i] = pEle[i+2]; + printk("%02X ", pEle[i+2]); + } + printk("\n"); + + pEle += pEle[1] + 2; + adev->cfgopt_power_levels.type = pEle[0]; + adev->cfgopt_power_levels.len = pEle[1]; + printk("PowerLevelID:%02X Len:%02X Data:", + adev->cfgopt_power_levels.type, adev->cfgopt_power_levels.len); + for (i = 0; i < pEle[1]; i++) { + adev->cfgopt_power_levels.list[i] = le16_to_cpu(*(u16 *)&pEle[i*2+2]); + printk("%04X ", adev->cfgopt_power_levels.list[i]); + } + printk("\n"); + + pEle += pEle[1]*2 + 2; + adev->cfgopt_data_rates.type = pEle[0]; + adev->cfgopt_data_rates.len = pEle[1]; + printk("DataRatesID:%02X Len:%02X Data:", + adev->cfgopt_data_rates.type, adev->cfgopt_data_rates.len); + for (i = 0; i < pEle[1]; i++) { + adev->cfgopt_data_rates.list[i] = pEle[i+2]; + printk("%02X ", pEle[i+2]); + } + printk("\n"); + + pEle += pEle[1] + 2; + adev->cfgopt_domains.type = pEle[0]; + adev->cfgopt_domains.len = pEle[1]; + printk("DomainID:%02X Len:%02X Data:", + adev->cfgopt_domains.type, adev->cfgopt_domains.len); + for (i = 0; i < pEle[1]; i++) { + adev->cfgopt_domains.list[i] = pEle[i+2]; + printk("%02X ", pEle[i+2]); + } + printk("\n"); + + pEle += pEle[1] + 2; + adev->cfgopt_product_id.type = pEle[0]; + adev->cfgopt_product_id.len = pEle[1]; + for (i = 0; i < pEle[1]; i++) { + adev->cfgopt_product_id.list[i] = pEle[i+2]; + } + printk("ProductID:%02X Len:%02X Data:%.*s\n", + adev->cfgopt_product_id.type, adev->cfgopt_product_id.len, + adev->cfgopt_product_id.len, (char *)adev->cfgopt_product_id.list); + + pEle += pEle[1] + 2; + adev->cfgopt_manufacturer.type = pEle[0]; + adev->cfgopt_manufacturer.len = pEle[1]; + for (i = 0; i < pEle[1]; i++) { + adev->cfgopt_manufacturer.list[i] = pEle[i+2]; + } + printk("ManufacturerID:%02X Len:%02X Data:%.*s\n", + adev->cfgopt_manufacturer.type, adev->cfgopt_manufacturer.len, + adev->cfgopt_manufacturer.len, (char *)adev->cfgopt_manufacturer.list); +/* + printk("EEPROM part:\n"); + for (i=0; i<58; i++) { + printk("%02X =======> 0x%02X\n", + i, (u8 *)adev->cfgopt_NVSv[i-2]); + } +*/ +} + + +/*********************************************************************** +*/ +static int __init +acx_e_init_module(void) +{ + int r1,r2; + + acx_struct_size_check(); +#if 0 + printk("acx: this driver is still EXPERIMENTAL\n" + "acx: reading README file and/or Craig's HOWTO is " + "recommended, visit http://acx100.sf.net in case " + "of further questions/discussion\n"); +#endif + printk(KERN_INFO "acx: Loaded combined PCI/USB driver, firmware_ver=%s\n", + firmware_ver); +#if defined(CONFIG_NET_ACX_PCI) + r1 = acxpci_e_init_module(); +#else + r1 = -EINVAL; +#endif +#if defined(CONFIG_NET_ACX_USB) + r2 = acxusb_e_init_module(); +#else + r2 = -EINVAL; +#endif + if (r2 && r1) /* both failed! */ + return r2 ? r2 : r1; + /* return success if at least one succeeded */ + return 0; +} + +static void __exit +acx_e_cleanup_module(void) +{ +#if defined(CONFIG_NET_ACX_PCI) + acxpci_e_cleanup_module(); +#endif +#if defined(CONFIG_NET_ACX_USB) + acxusb_e_cleanup_module(); +#endif +} + +module_init(acx_e_init_module) +module_exit(acx_e_cleanup_module) --- linux-2.6.27.orig/ubuntu/aufs/dentry.h +++ linux-2.6.27/ubuntu/aufs/dentry.h @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * lookup and dentry operations + * + * $Id: dentry.h,v 1.7 2008/09/01 02:54:54 sfjro Exp $ + */ + +#ifndef __AUFS_DENTRY_H__ +#define __AUFS_DENTRY_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include "misc.h" +#include "super.h" +#include "vfsub.h" + +/* nameidata open_intent */ +enum { + AuIntent_AUFS, + AuIntent_BRANCH, + AuIntent_Last +}; + +struct au_hdintent { + struct list_head hdi_list; + struct file *hdi_file[AuIntent_Last]; +}; + +struct au_hdentry { + struct dentry *hd_dentry; + +#ifdef CONFIG_AUFS_BR_NFS + spinlock_t hd_lock; /* intest_list */ + struct list_head *hd_intent_list; +#endif +}; + +struct au_dinfo { + atomic_t di_generation; + + struct au_rwsem di_rwsem; + aufs_bindex_t di_bstart, di_bend, di_bwh, di_bdiropq; + struct au_hdentry *di_hdentry; +}; + +/* nameidata extension flags */ +#define AuNdx_DLGT 1 +#define AuNdx_DIRPERM1 (1 << 1) +#define au_ftest_ndx(flags, name) ((flags) & AuNdx_##name) +#define au_fset_ndx(flags, name) { (flags) |= AuNdx_##name; } +#define au_fclr_ndx(flags, name) { (flags) &= ~AuNdx_##name; } +#ifndef CONFIG_AUFS_DLGT +#undef AuNdx_DLGT +#define AuNdx_DLGT 0 +#undef AuNdx_DIRPERM1 +#define AuNdx_DIRPERM1 0 +#endif + +struct au_ndx { + struct vfsmount *nfsmnt; + unsigned int flags; + struct nameidata *nd; + struct au_branch *br; + struct file *nd_file; +}; + +/* ---------------------------------------------------------------------- */ + +static inline void au_do_h_dentry_init(struct au_hdentry *hdentry) +{ + hdentry->hd_dentry = NULL; +} + +#ifdef CONFIG_AUFS_BR_NFS +static inline void au_h_dentry_init(struct au_hdentry *hdentry) +{ + au_do_h_dentry_init(hdentry); + spin_lock_init(&hdentry->hd_lock); +} + +static inline void au_h_dentry_init_all(struct au_hdentry *hdentry, int n) +{ + while (n--) + spin_lock_init(&hdentry[n].hd_lock); +} + +/* br_nfs.c */ +struct file *au_h_intent(struct dentry *dentry, aufs_bindex_t bindex, + struct file *file); +int au_br_nfs_h_intent(struct file *nd_file, struct dentry *dentry, + aufs_bindex_t bindex, struct nameidata *nd); +void au_hintent_put(struct au_hdentry *hd, int do_free); +int au_fake_intent(struct nameidata *nd, int perm); +int au_hin_after_reval(struct nameidata *nd, struct dentry *dentry, + aufs_bindex_t bindex, struct file *file); +struct dentry *au_lkup_hash(const char *name, struct dentry *parent, int len, + struct au_ndx *ndx); +#else + +static inline void au_h_dentry_init(struct au_hdentry *hdentry) +{ + au_do_h_dentry_init(hdentry); +} + +static inline void au_h_dentry_init_all(struct au_hdentry *hdentry, int n) +{ + /* nothing */ +} + +static inline +struct file *au_h_intent(struct dentry *dentry, aufs_bindex_t bindex, + struct file *file) +{ + /* return ERR_PTR(-ENOSYS); */ + return NULL; +} + +static inline +int au_br_nfs_h_intent(struct file *nd_file, struct dentry *dentry, + aufs_bindex_t bindex, struct nameidata *nd) +{ + return 0; +} + +static inline void au_hintent_put(struct au_hdentry *hd, int do_free) +{ + /* empty */ +} + +static inline int au_fake_intent(struct nameidata *nd, int perm) +{ + return 0; +} + +static inline +int au_hin_after_reval(struct nameidata *nd, struct dentry *dentry, + aufs_bindex_t bindex, struct file *file) +{ + return 0; +} + +#ifdef CONFIG_AUFS_DLGT +static inline +struct dentry *au_lkup_hash(const char *name, struct dentry *parent, int len, + struct au_ndx *ndx) +{ + /* return ERR_PTR(-ENOSYS); */ + return vfsub_lookup_one_len(name, parent, len); +} +#endif +#endif /* CONFIG_AUFS_BR_NFS */ + +#ifdef CONFIG_AUFS_DLGT +/* dlgt.c */ +struct dentry *au_lkup_one_dlgt(const char *name, struct dentry *parent, + int len, unsigned int flags); +#elif defined(CONFIG_AUFS_BR_NFS) +/* regardelss kernel version */ +static inline +struct dentry *au_lkup_one_dlgt(const char *name, struct dentry *parent, + int len, unsigned int flags) +{ + return vfsub_lookup_one_len(name, parent, len); +} +#endif + +/* dentry.c */ +extern struct dentry_operations aufs_dop; +#if defined(CONFIG_AUFS_BR_NFS) || defined(CONFIG_AUFS_DLGT) +struct dentry *au_lkup_one(const char *name, struct dentry *parent, int len, + struct au_ndx *ndx); +#else +static inline +struct dentry *au_lkup_one(const char *name, struct dentry *parent, int len, + struct au_ndx *ndx) +{ + /* todo? ndx->nd_file = NULL; */ + return vfsub_lookup_one_len(name, parent, len); +} +#endif +struct dentry *au_sio_lkup_one(const char *name, struct dentry *parent, int len, + struct au_ndx *ndx); +int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type, + struct nameidata *nd); +int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex); +int au_refresh_hdentry(struct dentry *dentry, mode_t type); +int au_reval_dpath(struct dentry *dentry, au_gen_t sgen); + +/* dinfo.c */ +int au_alloc_dinfo(struct dentry *dentry); +struct au_dinfo *au_di(struct dentry *dentry); + +void di_read_lock(struct dentry *d, int flags, unsigned int lsc); +void di_read_unlock(struct dentry *d, int flags); +void di_downgrade_lock(struct dentry *d, int flags); +void di_write_lock(struct dentry *d, unsigned int lsc); +void di_write_unlock(struct dentry *d); +void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir); +void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir); +void di_write_unlock2(struct dentry *d1, struct dentry *d2); + +struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex); + +aufs_bindex_t au_dbtail(struct dentry *dentry); +aufs_bindex_t au_dbtaildir(struct dentry *dentry); +#if 0 /* reserved for future use */ +aufs_bindex_t au_dbtail_generic(struct dentry *dentry); +#endif + +void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex); +void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_dentry); + +void au_update_dbrange(struct dentry *dentry, int do_put_zero); +void au_update_dbstart(struct dentry *dentry); +void au_update_dbend(struct dentry *dentry); +int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry); + +/* ---------------------------------------------------------------------- */ + +/* todo: memory barrier? */ +static inline au_gen_t au_digen(struct dentry *d) +{ + return atomic_read(&au_di(d)->di_generation); +} + +#ifdef CONFIG_AUFS_HINOTIFY +static inline au_gen_t au_digen_dec(struct dentry *d) +{ + return atomic_dec_return(&au_di(d)->di_generation); +} + +static inline void au_hin_di_reinit(struct dentry *d) +{ + d->d_fsdata = NULL; +} +#else +static inline void au_hin_di_reinit(struct dentry *d) +{ + /* empty */ +} +#endif /* CONFIG_AUFS_HINOTIFY */ + +/* ---------------------------------------------------------------------- */ + +/* lock subclass for dinfo */ +enum { + AuLsc_DI_CHILD, /* child first */ + AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hinotify */ + AuLsc_DI_CHILD3, /* copyup dirs */ + AuLsc_DI_PARENT, + AuLsc_DI_PARENT2, + AuLsc_DI_PARENT3, + AuLsc_DI_PARENT4 +}; + +/* + * di_read_lock_child, di_write_lock_child, + * di_read_lock_child2, di_write_lock_child2, + * di_read_lock_child3, di_write_lock_child3, + * di_read_lock_parent, di_write_lock_parent, + * di_read_lock_parent2, di_write_lock_parent2, + * di_read_lock_parent3, di_write_lock_parent3, + * di_read_lock_parent4, di_write_lock_parent4, + */ +#define AuReadLockFunc(name, lsc) \ +static inline void di_read_lock_##name(struct dentry *d, int flags) \ +{ di_read_lock(d, flags, AuLsc_DI_##lsc); } + +#define AuWriteLockFunc(name, lsc) \ +static inline void di_write_lock_##name(struct dentry *d) \ +{ di_write_lock(d, AuLsc_DI_##lsc); } + +#define AuRWLockFuncs(name, lsc) \ + AuReadLockFunc(name, lsc) \ + AuWriteLockFunc(name, lsc) + +AuRWLockFuncs(child, CHILD); +AuRWLockFuncs(child2, CHILD2); +AuRWLockFuncs(child3, CHILD3); +AuRWLockFuncs(parent, PARENT); +AuRWLockFuncs(parent2, PARENT2); +AuRWLockFuncs(parent3, PARENT3); +AuRWLockFuncs(parent4, PARENT4); + +#undef AuReadLockFunc +#undef AuWriteLockFunc +#undef AuRWLockFuncs + +/* to debug easier, do not make them inlined functions */ +#define DiMustReadLock(d) do { \ + SiMustAnyLock((d)->d_sb); \ + AuRwMustReadLock(&au_di(d)->di_rwsem); \ +} while (0) + +#define DiMustWriteLock(d) do { \ + SiMustAnyLock((d)->d_sb); \ + AuRwMustWriteLock(&au_di(d)->di_rwsem); \ +} while (0) + +#define DiMustAnyLock(d) do { \ + SiMustAnyLock((d)->d_sb); \ + AuRwMustAnyLock(&au_di(d)->di_rwsem); \ +} while (0) + +#define DiMustNoWaiters(d) AuRwMustNoWaiters(&au_di(d)->di_rwsem) + +/* ---------------------------------------------------------------------- */ + +static inline aufs_bindex_t au_dbstart(struct dentry *dentry) +{ + DiMustAnyLock(dentry); + return au_di(dentry)->di_bstart; +} + +static inline aufs_bindex_t au_dbend(struct dentry *dentry) +{ + DiMustAnyLock(dentry); + return au_di(dentry)->di_bend; +} + +static inline aufs_bindex_t au_dbwh(struct dentry *dentry) +{ + DiMustAnyLock(dentry); + return au_di(dentry)->di_bwh; +} + +static inline aufs_bindex_t au_dbdiropq(struct dentry *dentry) +{ + DiMustAnyLock(dentry); + AuDebugOn(dentry->d_inode + && dentry->d_inode->i_mode + && !S_ISDIR(dentry->d_inode->i_mode)); + return au_di(dentry)->di_bdiropq; +} + +/* todo: hard/soft set? */ +static inline void au_set_dbstart(struct dentry *dentry, aufs_bindex_t bindex) +{ + DiMustWriteLock(dentry); + AuDebugOn(au_sbend(dentry->d_sb) < bindex); + /* */ + au_di(dentry)->di_bstart = bindex; +} + +static inline void au_set_dbend(struct dentry *dentry, aufs_bindex_t bindex) +{ + DiMustWriteLock(dentry); + AuDebugOn(au_sbend(dentry->d_sb) < bindex + || bindex < au_dbstart(dentry)); + au_di(dentry)->di_bend = bindex; +} + +static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex) +{ + DiMustWriteLock(dentry); + AuDebugOn(au_sbend(dentry->d_sb) < bindex); + /* dbwh can be outside of bstart - bend range */ + au_di(dentry)->di_bwh = bindex; +} + +static inline void au_hdput(struct au_hdentry *hd, int do_free) +{ + au_hintent_put(hd, do_free); + dput(hd->hd_dentry); +} + +static inline void au_update_digen(struct dentry *dentry) +{ + AuDebugOn(!dentry->d_sb); + atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb)); + /* smp_mb(); */ /* atomic_set */ +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DENTRY_H__ */ --- linux-2.6.27.orig/ubuntu/aufs/wbr_policy.c +++ linux-2.6.27/ubuntu/aufs/wbr_policy.c @@ -0,0 +1,699 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * policies for selecting one among multiple writable branches + * + * $Id: wbr_policy.c,v 1.12 2008/09/01 02:55:35 sfjro Exp $ + */ + +#include +#include "aufs.h" + +static int au_cpdown_attr(struct au_hinode *hdir, struct dentry *h_dst, + struct dentry *h_src) +{ + int err, sbits; + struct iattr ia; + struct inode *h_idst, *h_isrc; + + LKTRTrace("%.*s\n", AuDLNPair(h_dst)); + h_idst = h_dst->d_inode; + /* todo? IMustLock(h_idst); */ + h_isrc = h_src->d_inode; + /* todo? IMustLock(h_isrc); */ + + ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID; + ia.ia_mode = h_isrc->i_mode; + ia.ia_uid = h_isrc->i_uid; + ia.ia_gid = h_isrc->i_gid; + sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID)); + + err = vfsub_sio_notify_change(hdir, h_dst, &ia); + + /* is this nfs only? */ + if (!err && sbits && au_test_nfs(h_dst->d_sb)) { + ia.ia_valid = ATTR_FORCE | ATTR_MODE; + ia.ia_mode = h_isrc->i_mode; + err = vfsub_sio_notify_change(hdir, h_dst, &ia); + } + + /* todo: necessary? */ + if (!err) + h_idst->i_flags = h_isrc->i_flags; + + AuTraceErr(err); + return err; +} + +struct au_cpdown_dir_args { + struct dentry *parent; + unsigned int parent_opq; /* bit-flags */ +}; + +static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst, + struct dentry *h_parent, void *arg) +{ + int err, rerr; + struct au_cpdown_dir_args *args = arg; + aufs_bindex_t bend, bopq, bstart; + unsigned char parent_opq, whed, dlgt, do_opq, made_dir, diropq; + struct dentry *h_dentry, *opq_dentry, *wh_dentry, *parent; + struct inode *h_dir, *h_inode, *inode, *dir; + + LKTRTrace("%.*s, b%d\n", AuDLNPair(dentry), bdst); + bstart = au_dbstart(dentry); + AuDebugOn(bstart <= bdst + && bdst <= au_dbend(dentry) + && au_h_dptr(dentry, bdst)); + AuDebugOn(!h_parent); + /* todo: safe? */ + parent = dget_parent(dentry); + dir = parent->d_inode; + dput(parent); + h_dir = h_parent->d_inode; + AuDebugOn(!h_dir); + AuDebugOn(h_dir != au_h_iptr(dir, bdst)); + IMustLock(h_dir); + + err = au_lkup_neg(dentry, bdst); + if (unlikely(err < 0)) + goto out; + h_dentry = au_h_dptr(dentry, bdst); + dlgt = !!au_test_dlgt(au_mntflags(dentry->d_sb)); + err = vfsub_sio_mkdir(au_hi(dir, bdst), h_dentry, S_IRWXU | S_IRUGO | S_IXUGO, + dlgt); + if (unlikely(err)) + goto out_put; + + made_dir = 1; + bend = au_dbend(dentry); + bopq = au_dbdiropq(dentry); + whed = (au_dbwh(dentry) == bdst); + if (!args->parent_opq) + args->parent_opq |= (bopq <= bdst); + parent_opq = (args->parent_opq && args->parent == dentry); + do_opq = 0; + diropq = 0; + h_inode = h_dentry->d_inode; + mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); + if (whed || (parent_opq && do_opq)) { + opq_dentry = au_diropq_create(dentry, bdst, dlgt); + err = PTR_ERR(opq_dentry); + if (IS_ERR(opq_dentry)) { + mutex_unlock(&h_inode->i_mutex); + goto out_dir; + } + dput(opq_dentry); + diropq = 1; + } + + err = au_cpdown_attr(au_hi(dir, bdst), h_dentry, au_h_dptr(dentry, bstart)); + mutex_unlock(&h_inode->i_mutex); + if (unlikely(err)) + goto out_opq; + + wh_dentry = NULL; + if (whed) { + wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, /*ndx*/NULL); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out_opq; + err = 0; + if (wh_dentry->d_inode) + err = au_wh_unlink_dentry(au_hi(dir, bdst), wh_dentry, + dentry, dlgt); + dput(wh_dentry); + if (unlikely(err)) + goto out_opq; + } + + inode = dentry->d_inode; + if (au_ibend(inode) < bdst) + au_set_ibend(inode, bdst); + au_set_h_iptr(inode, bdst, au_igrab(h_inode), au_hi_flags(inode, 1)); + goto out; /* success */ + + /* revert */ + out_opq: + if (diropq) { + mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); + rerr = au_diropq_remove(dentry, bdst, dlgt); + mutex_unlock(&h_inode->i_mutex); + if (unlikely(rerr)) { + AuIOErr("failed removing diropq for %.*s b%d (%d)\n", + AuDLNPair(dentry), bdst, rerr); + err = -EIO; + goto out; + } + } + out_dir: + if (made_dir) { + rerr = vfsub_sio_rmdir(au_hi(dir, bdst), h_dentry, dlgt); + if (unlikely(rerr)) { + AuIOErr("failed removing %.*s b%d (%d)\n", + AuDLNPair(dentry), bdst, rerr); + err = -EIO; + } + } + out_put: + au_set_h_dptr(dentry, bdst, NULL); + if (au_dbend(dentry) == bdst) + au_update_dbend(dentry); + out: + AuTraceErr(err); + return err; +} + +int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst) +{ + int err; + struct au_cpdown_dir_args args = { + .parent = dget_parent(dentry), + .parent_opq = 0 + }; + + LKTRTrace("%.*s, b%d\n", AuDLNPair(dentry), bdst); + + err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &args); + dput(args.parent); + + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* policies for create */ + +static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex) +{ + for (; bindex >= 0; bindex--) + if (!au_br_rdonly(au_sbr(sb, bindex))) + return bindex; + return -EROFS; +} + +/* top down parent */ +static int au_wbr_create_tdp(struct dentry *dentry, int isdir) +{ + int err; + struct super_block *sb; + aufs_bindex_t bstart, bindex; + unsigned char dirperm1; + struct dentry *parent, *h_parent; + struct inode *h_dir; + + LKTRTrace("%.*s, dir %d\n", AuDLNPair(dentry), isdir); + + sb = dentry->d_sb; + dirperm1 = !!au_test_dirperm1(au_mntflags(sb)); + bstart = au_dbstart(dentry); + AuDebugOn(bstart < 0); + err = bstart; + /* todo: can 'err' be an illegal? */ + if (/* err >= 0 && */ !au_br_rdonly(au_sbr(sb, bstart))) + goto out; + + err = -EROFS; + parent = dget_parent(dentry); + for (bindex = au_dbstart(parent); bindex < bstart; bindex++) { + h_parent = au_h_dptr(parent, bindex); + if (!h_parent) + continue; + h_dir = h_parent->d_inode; + if (!h_dir) + continue; + + if (!au_br_rdonly(au_sbr(sb, bindex)) + && (!dirperm1 + || au_test_h_perm(h_dir, MAY_WRITE | MAY_EXEC, + /*dlgt*/0))) { + err = bindex; + break; + } + } + dput(parent); + + /* bottom up here */ + if (unlikely(err < 0)) + err = au_wbr_bu(sb, bstart - 1); + + out: + LKTRTrace("b%d\n", err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* an exception for the policy other than tdp */ +static int au_wbr_create_exp(struct dentry *dentry) +{ + int err; + struct dentry *parent; + aufs_bindex_t bwh, bdiropq; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + + err = -1; + bwh = au_dbwh(dentry); + parent = dget_parent(dentry); + bdiropq = au_dbdiropq(parent); + if (bwh >= 0) { + if (bdiropq >= 0) + err = min(bdiropq, bwh); + else + err = bwh; + LKTRTrace("%d\n", err); + } else if (bdiropq >= 0) { + err = bdiropq; + LKTRTrace("%d\n", err); + } + dput(parent); + + if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err))) + err = -1; + + LKTRTrace("%d\n", err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* round robin */ +static int au_wbr_create_init_rr(struct super_block *sb) +{ + int err; + + err = au_wbr_bu(sb, au_sbend(sb)); + atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */ + + LKTRTrace("b%d\n", err); + return err; +} + +static int au_wbr_create_rr(struct dentry *dentry, int isdir) +{ + int err, nbr; + struct super_block *sb; + atomic_t *next; + unsigned int u; + aufs_bindex_t bindex, bend; + + LKTRTrace("%.*s, dir %d\n", AuDLNPair(dentry), isdir); + + sb = dentry->d_sb; + next = NULL; + err = au_wbr_create_exp(dentry); + if (err >= 0) + goto out; + + next = &au_sbi(sb)->si_wbr_rr_next; + bend = au_sbend(sb); + nbr = bend + 1; + for (bindex = 0; bindex <= bend; bindex++) { + if (!isdir) { + err = atomic_dec_return(next) + 1; + /* modulo for 0 is meaningless */ + if (unlikely(!err)) + err = atomic_dec_return(next) + 1; + } else + err = atomic_read(next); + LKTRTrace("%d\n", err); + u = err; + err = u % nbr; + LKTRTrace("%d\n", err); + if (!au_br_rdonly(au_sbr(sb, err))) + break; + err = -EROFS; + } + + out: + LKTRTrace("%d\n", err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* most free space */ +static void *au_wbr_statfs_arg(struct au_branch *br, struct super_block *sb, + aufs_bindex_t bindex) +{ + struct super_block *h_sb; + + h_sb = br->br_mnt->mnt_sb; + + if (!au_test_nfs(h_sb)) + return h_sb->s_root; + + /* sigh,,, why nfs s_root has wrong inode? */ + return au_di(sb->s_root)->di_hdentry[0 + bindex].hd_dentry; +} + +static void au_mfs(struct dentry *dentry) +{ + struct super_block *sb; + aufs_bindex_t bindex, bend; + unsigned char dlgt; + int err; + struct kstatfs st; + unsigned long long b, bavail; + void *arg; + struct au_branch *br; + struct au_wbr_mfs *mfs; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + + bavail = 0; + sb = dentry->d_sb; + mfs = &au_sbi(sb)->si_wbr_mfs; + mfs->mfs_bindex = -EROFS; + mfs->mfsrr_bytes = 0; + dlgt = !!au_test_dlgt(au_mntflags(sb)); + bend = au_sbend(sb); + for (bindex = 0; bindex <= bend; bindex++) { + br = au_sbr(sb, bindex); + if (au_br_rdonly(br)) + continue; + AuDebugOn(!br->br_wbr); + arg = au_wbr_statfs_arg(br, sb, bindex); + if (!arg) + continue; + + err = vfsub_statfs(arg, &st, dlgt); + LKTRTrace("b%d, %d, %llu\n", + bindex, err, (unsigned long long)st.f_bavail); + if (unlikely(err)) { + AuWarn1("failed statfs, b%d, %d\n", bindex, err); + continue; + } + + /* when the available size is equal, select lower one */ + b = st.f_bavail * st.f_bsize; + br->br_wbr->wbr_bytes = b; + if (b >= bavail) { + bavail = b; + mfs->mfs_bindex = bindex; + mfs->mfs_jiffy = jiffies; + } + } + + mfs->mfsrr_bytes = bavail; + LKTRTrace("b%d\n", mfs->mfs_bindex); +} + +static int au_wbr_create_mfs(struct dentry *dentry, int isdir) +{ + int err; + struct super_block *sb; + struct au_wbr_mfs *mfs; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + + sb = dentry->d_sb; + err = au_wbr_create_exp(dentry); + if (err >= 0) + goto out; + + mfs = &au_sbi(sb)->si_wbr_mfs; + mutex_lock(&mfs->mfs_lock); + if (unlikely(time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) + || mfs->mfs_bindex < 0 + || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex)))) + au_mfs(dentry); + mutex_unlock(&mfs->mfs_lock); + err = mfs->mfs_bindex; + + out: + LKTRTrace("b%d\n", err); + return err; +} + +static int au_wbr_create_init_mfs(struct super_block *sb) +{ + struct au_wbr_mfs *mfs; + + mfs = &au_sbi(sb)->si_wbr_mfs; + LKTRTrace("expire %lu\n", mfs->mfs_expire); + + mutex_init(&mfs->mfs_lock); + mfs->mfs_jiffy = 0; + mfs->mfs_bindex = -EROFS; + + return 0; +} + +static int au_wbr_create_fin_mfs(struct super_block *sb) +{ + AuTraceEnter(); + mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock); + return 0; +} + +/* ---------------------------------------------------------------------- */ + +/* most free space and then round robin */ +static int au_wbr_create_mfsrr(struct dentry *dentry, int isdir) +{ + int err; + struct au_wbr_mfs *mfs; + + LKTRTrace("%.*s, %d\n", AuDLNPair(dentry), isdir); + + err = au_wbr_create_mfs(dentry, isdir); + if (err >= 0) { + mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs; + LKTRTrace("%llu bytes, %llu wmark\n", + mfs->mfsrr_bytes, mfs->mfsrr_watermark); + if (unlikely(mfs->mfsrr_bytes < mfs->mfsrr_watermark)) + err = au_wbr_create_rr(dentry, isdir); + } + + LKTRTrace("b%d\n", err); + return err; +} + +static int au_wbr_create_init_mfsrr(struct super_block *sb) +{ + int err; + + au_wbr_create_init_mfs(sb); /* ignore */ + err = au_wbr_create_init_rr(sb); + + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* top down parent and most free space */ +static int au_wbr_create_pmfs(struct dentry *dentry, int isdir) +{ + int err, e2; + struct super_block *sb; + struct dentry *parent, *h_parent; + aufs_bindex_t bindex, bstart, bend; + unsigned char dirperm1; + struct au_branch *br; + unsigned long long b; + struct inode *h_dir; + + LKTRTrace("%.*s, %d\n", AuDLNPair(dentry), isdir); + + err = au_wbr_create_tdp(dentry, isdir); + if (unlikely(err < 0)) + goto out; + parent = dget_parent(dentry); + bstart = au_dbstart(parent); + bend = au_dbtaildir(parent); + if (bstart == bend) + goto out_parent; /* success */ + + e2 = au_wbr_create_mfs(dentry, isdir); + if (e2 < 0) + goto out_parent; /* success */ + + /* when the available size is equal, select upper one */ + sb = dentry->d_sb; + br = au_sbr(sb, err); + AuDebugOn(!br->br_wbr); + dirperm1 = !!au_test_dirperm1(au_mntflags(sb)); + b = br->br_wbr->wbr_bytes; + LKTRTrace("b%d, %llu\n", err, b); + + if (unlikely(dirperm1)) { + for (bindex = bstart; bindex <= bend; bindex++) { + h_parent = au_h_dptr(parent, bindex); + if (!h_parent) + continue; + h_dir = h_parent->d_inode; + if (!h_dir) + continue; + + br = au_sbr(sb, bindex); + if (!au_br_rdonly(br) + && au_test_h_perm(h_dir, MAY_WRITE | MAY_EXEC, + /*dlgt*/0) + && br->br_wbr->wbr_bytes > b) { + b = br->br_wbr->wbr_bytes; + err = bindex; + LKTRTrace("b%d, %llu\n", err, b); + } + } + if (err >= 0) + goto out_parent; + } + for (bindex = bstart; bindex <= bend; bindex++) { + h_parent = au_h_dptr(parent, bindex); + if (!h_parent || !h_parent->d_inode) + continue; + + br = au_sbr(sb, bindex); + if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) { + b = br->br_wbr->wbr_bytes; + err = bindex; + LKTRTrace("b%d, %llu\n", err, b); + } + } + + out_parent: + dput(parent); + out: + LKTRTrace("b%d\n", err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* policies for copyup */ + +/* top down parent */ +static int au_wbr_copyup_tdp(struct dentry *dentry) +{ + return au_wbr_create_tdp(dentry, /*isdir, anything is ok*/0); +} + +/* bottom up parent */ +static int au_wbr_copyup_bup(struct dentry *dentry) +{ + int err; + struct dentry *parent, *h_parent; + aufs_bindex_t bindex, bstart; + unsigned char dirperm1; + struct super_block *sb; + struct inode *h_dir; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + + err = -EROFS; + sb = dentry->d_sb; + dirperm1 = !!au_test_dirperm1(au_mntflags(sb)); + parent = dget_parent(dentry); + bstart = au_dbstart(parent); + for (bindex = au_dbstart(dentry); bindex >= bstart; bindex--) { + h_parent = au_h_dptr(parent, bindex); + if (!h_parent) + continue; + h_dir = h_parent->d_inode; + if (!h_dir) + continue; + + if (!au_br_rdonly(au_sbr(sb, bindex)) + && (!dirperm1 + || au_test_h_perm(h_dir, MAY_WRITE | MAY_EXEC, + /*dlgt*/0))) { + err = bindex; + break; + } + } + dput(parent); + + /* bottom up here */ + if (unlikely(err < 0)) + err = au_wbr_bu(sb, bstart - 1); + + LKTRTrace("b%d\n", err); + return err; +} + +/* bottom up */ +static int au_wbr_copyup_bu(struct dentry *dentry) +{ + int err; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + + err = au_wbr_bu(dentry->d_sb, au_dbstart(dentry)); + + LKTRTrace("b%d\n", err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct au_wbr_copyup_operations au_wbr_copyup_ops[] = { + [AuWbrCopyup_TDP] = { + .copyup = au_wbr_copyup_tdp + }, + [AuWbrCopyup_BUP] = { + .copyup = au_wbr_copyup_bup + }, + [AuWbrCopyup_BU] = { + .copyup = au_wbr_copyup_bu + } +}; + +struct au_wbr_create_operations au_wbr_create_ops[] = { + [AuWbrCreate_TDP] = { + .create = au_wbr_create_tdp + }, + [AuWbrCreate_RR] = { + .create = au_wbr_create_rr, + .init = au_wbr_create_init_rr + }, + [AuWbrCreate_MFS] = { + .create = au_wbr_create_mfs, + .init = au_wbr_create_init_mfs, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_MFSV] = { + .create = au_wbr_create_mfs, + .init = au_wbr_create_init_mfs, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_MFSRR] = { + .create = au_wbr_create_mfsrr, + .init = au_wbr_create_init_mfsrr, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_MFSRRV] = { + .create = au_wbr_create_mfsrr, + .init = au_wbr_create_init_mfsrr, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_PMFS] = { + .create = au_wbr_create_pmfs, + .init = au_wbr_create_init_mfs, + .fin = au_wbr_create_fin_mfs + }, + [AuWbrCreate_PMFSV] = { + .create = au_wbr_create_pmfs, + .init = au_wbr_create_init_mfs, + .fin = au_wbr_create_fin_mfs + } +}; --- linux-2.6.27.orig/ubuntu/aufs/hinotify.c +++ linux-2.6.27/ubuntu/aufs/hinotify.c @@ -0,0 +1,1133 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * internal/hidden inotify handler + * + * $Id: hinotify.c,v 1.16 2008/09/08 02:39:54 sfjro Exp $ + */ + +#include "aufs.h" + +/* +#ifdef DbgInotify +#define AuDbgHin(args...) AuDbg(##args) +#else +#define AuDbgHin(args...) do {} while () +#endif +*/ + +static struct inotify_handle *in_handle; + +AuCacheFuncs(hinotify, AuCache_HINOTIFY); + +int au_hin_alloc(struct au_hinode *hinode, struct inode *inode, + struct inode *h_inode) +{ + int err; + struct au_hinotify *hin; + s32 wd; + + LKTRTrace("i%lu, hi%lu\n", inode->i_ino, h_inode->i_ino); + + err = -ENOMEM; + hin = au_cache_alloc_hinotify(); + if (hin) { + AuDebugOn(hinode->hi_notify); + hinode->hi_notify = hin; + spin_lock_init(&hin->hin_ignore_lock); + INIT_LIST_HEAD(&hin->hin_ignore_list); + hin->hin_aufs_inode = inode; + + inotify_init_watch(&hin->hin_watch); + wd = inotify_add_watch(in_handle, &hin->hin_watch, h_inode, + AuInMask); + if (wd >= 0) + return 0; /* success */ + + err = wd; + put_inotify_watch(&hin->hin_watch); + au_cache_free_hinotify(hin); + hinode->hi_notify = NULL; + } + + AuTraceErr(err); + return err; +} + +void au_hin_free(struct au_hinode *hinode) +{ + int err; + struct au_hinotify *hin; + + AuTraceEnter(); + + hin = hinode->hi_notify; + if (unlikely(hin)) { + err = 0; + if (atomic_read(&hin->hin_watch.count)) + err = inotify_rm_watch(in_handle, &hin->hin_watch); + if (unlikely(err)) + /* it means the watch is already removed */ + LKTRTrace("failed inotify_rm_watch() %d\n", err); + au_cache_free_hinotify(hin); + hinode->hi_notify = NULL; + } +} + +/* ---------------------------------------------------------------------- */ + +void au_hin_ctl(struct au_hinode *hinode, const __u32 mask) +{ + struct inode *h_inode; + struct inotify_watch *watch; + + h_inode = hinode->hi_inode; + LKTRTrace("hi%lu, sb %p, 0x%x\n", h_inode->i_ino, h_inode->i_sb, mask); + IMustLock(h_inode); + if (!hinode->hi_notify) + return; + + watch = &hinode->hi_notify->hin_watch; +#if 0 /* reserved for future use */ + { + u32 wd; + wd = inotify_find_update_watch(in_handle, h_inode, mask); + AuTraceErr(wd); + /* ignore an err; */ + } +#else + /* struct inotify_handle is hidden */ + mutex_lock(&h_inode->inotify_mutex); + /* mutex_lock(&watch->ih->mutex); */ + watch->mask = mask; + /* mutex_unlock(&watch->ih->mutex); */ + mutex_unlock(&h_inode->inotify_mutex); +#endif + LKTRTrace("watch %p, mask %u\n", watch, watch->mask); +} + +void au_reset_hinotify(struct inode *inode, unsigned int flags) +{ + aufs_bindex_t bindex, bend; + struct inode *hi; + struct dentry *iwhdentry; + + LKTRTrace("i%lu, 0x%x\n", inode->i_ino, flags); + + bend = au_ibend(inode); + for (bindex = au_ibstart(inode); bindex <= bend; bindex++) { + hi = au_h_iptr(inode, bindex); + if (hi) { + /* mutex_lock_nested(&hi->i_mutex, AuLsc_I_CHILD); */ + iwhdentry = au_hi_wh(inode, bindex); + if (unlikely(iwhdentry)) + dget(iwhdentry); + au_igrab(hi); + au_set_h_iptr(inode, bindex, NULL, 0); + au_set_h_iptr(inode, bindex, au_igrab(hi), + flags & ~AuHi_XINO); + iput(hi); + dput(iwhdentry); + /* mutex_unlock(&hi->i_mutex); */ + } + } +} + +/* ---------------------------------------------------------------------- */ + +void au_unpin_gp(struct au_pin *args) +{ + struct au_pin1 *gp; + + gp = au_pin_gp(args); + AuDebugOn(!gp); + if (gp->dentry) + LKTRTrace("%.*s\n", AuDLNPair(gp->dentry)); + else + AuTraceEnter(); + + au_do_unpin(gp, NULL); +} + +int au_hin_verify_gen(struct dentry *dentry) +{ + struct super_block *sb = dentry->d_sb; + au_gen_t sigen; + struct inode *inode; + + if (!au_opt_test(au_mntflags(sb), UDBA_INOTIFY)) + return 0; + + sigen = au_sigen(dentry->d_sb); + inode = dentry->d_inode; + return (au_digen(dentry) != sigen + || (inode && au_iigen(inode) != sigen)); +} + +/* ---------------------------------------------------------------------- */ + +/* cf. fsnotify_change() */ +__u32 vfsub_events_notify_change(struct iattr *ia) +{ + __u32 events; + const unsigned int amtime = (ATTR_ATIME | ATTR_MTIME); + + events = 0; + if ((ia->ia_valid & (ATTR_UID | ATTR_GID | ATTR_MODE)) + || (ia->ia_valid & amtime) == amtime) + events |= IN_ATTRIB; + if ((ia->ia_valid & ATTR_SIZE) + || (ia->ia_valid & amtime) == ATTR_MTIME) + events |= IN_MODIFY; + return events; +} + +void vfsub_ign_hinode(struct vfsub_args *vargs, __u32 events, + struct au_hinode *hinode) +{ + struct au_hinotify *hin; + struct super_block *sb; + struct au_hin_ignore *ign; + + if (!hinode) + return; + + hin = hinode->hi_notify; + if (!hin || !hin->hin_watch.mask) + return; + + sb = hin->hin_aufs_inode->i_sb; + AuDebugOn(!au_opt_test(au_mntflags(sb), UDBA_INOTIFY)); + + ign = vargs->ignore + vargs->nignore++; + ign->ign_events = events; + ign->ign_handled = 0; + ign->ign_hinode = hinode; + + { + struct inode *h_inode; + h_inode = hinode->hi_inode; + if (!mutex_is_locked(&h_inode->i_mutex)) + au_dbg_blocked(); + IMustLock(h_inode); + } +} + +static void au_hin_ignore(struct au_hin_ignore *ign) +{ + struct au_hinode *hinode; + __u32 events; + struct au_hinotify *hin; + struct inode *h_inode; + + hinode = ign->ign_hinode; + events = ign->ign_events; + LKTRTrace("0x%x\n", events); + AuDebugOn(!hinode || !events); + + hin = hinode->hi_notify; + h_inode = hinode->hi_inode; + if (h_inode && hin) { + LKTRTrace("hi%lu\n", h_inode->i_ino); +#ifdef DbgInotify + AuDbg("hi%lu, 0x%x\n", h_inode->i_ino, events); +#endif + + spin_lock(&hin->hin_ignore_lock); + list_add(&ign->ign_list, &hin->hin_ignore_list); + spin_unlock(&hin->hin_ignore_lock); + /* AuDbg("list_add %p, 0x%x\n", ign, events); */ + } +#if 1 /* todo: test dlgt */ + else + /* + * it may happen by this scenario. + * - a file and its parent dir exist on two branches + * - a file on the upper branch is opened + * - the parent dir and the file are removed by udba + * - the parent is re-accessed, and new dentry/inode in + * aufs is generated for it, based upon the one on the lower + * branch + * - the opened file is re-accessed, re-validated, and it may be + * re-connected to the new parent dentry + * it means the file in aufs cannot get the actual removed + * parent dir on the branch. + */ + INIT_LIST_HEAD(&ign->ign_list); +#endif +} + +static void au_hin_unignore(struct au_hin_ignore *ign) +{ + struct au_hinode *hinode; + __u32 events; + struct au_hinotify *hin; + struct inode *h_inode; + + hinode = ign->ign_hinode; + events = ign->ign_events; + LKTRTrace("0x%x\n", events); + /* AuDbg("0x%x\n", events); */ + AuDebugOn(!hinode || !events); + + hin = hinode->hi_notify; + h_inode = hinode->hi_inode; + if (unlikely(!h_inode || !hin)) + return; + LKTRTrace("hi%lu\n", h_inode->i_ino); +#ifdef DbgInotify + AuDbg("hi%lu, 0x%x\n", h_inode->i_ino, events); +#endif + + spin_lock(&hin->hin_ignore_lock); + au_hin_list_del(&ign->ign_list); + spin_unlock(&hin->hin_ignore_lock); + /* AuDbg("list_del %p, 0x%x\n", ign, events); */ +} + +static int au_hin_test_ignore(u32 mask, struct au_hinotify *hin) +{ + int do_ignore; + struct au_hin_ignore *ign, *tmp; + u32 events; + + do_ignore = 0; + spin_lock(&hin->hin_ignore_lock); + list_for_each_entry_safe(ign, tmp, &hin->hin_ignore_list, ign_list) { + /* AuDbg("ign %p\n", ign); */ + if (ign->ign_pid == current->pid) { + events = (mask & ign->ign_events); + if (events) { + do_ignore = 1; + ign->ign_handled |= events; + if (ign->ign_events == ign->ign_handled) { + list_del_init(&ign->ign_list); + /* + AuDbg("list_del %p, 0x%x\n", + ign, events); + */ + } + break; + } + } + } + spin_unlock(&hin->hin_ignore_lock); + + return do_ignore; +} + +void vfsub_ignore(struct vfsub_args *vargs) +{ + int n; + struct au_hin_ignore *ign; + struct super_block *sb; + struct au_hinode *hinode; + struct inode *h_inode; + + n = vargs->nignore; + if (!n) + return; + + ign = vargs->ignore; + hinode = ign->ign_hinode; + sb = hinode->hi_notify->hin_aufs_inode->i_sb; + h_inode = hinode->hi_inode; + if (unlikely(au_opt_test(au_mntflags(sb), UDBA_INOTIFY))) { + if (!mutex_is_locked(&h_inode->i_mutex)) + au_dbg_blocked(); + IMustLock(h_inode); + } + while (n-- > 0) { + ign->ign_pid = current->pid; + au_hin_ignore(ign++); + } +} + +void vfsub_unignore(struct vfsub_args *vargs) +{ + int n; + struct au_hin_ignore *ign; + + n = vargs->nignore; + if (!n) + return; + + ign = vargs->ignore; + while (n-- > 0) + au_hin_unignore(ign++); +} + +#ifdef CONFIG_AUFS_DEBUG +void au_dbg_hin_list(struct vfsub_args *vargs) +{ + int n; + struct au_hin_ignore *ign; + + n = vargs->nignore; + if (!n) + return; + + ign = vargs->ignore; + while (n-- > 0) { + /* AuDebugOn(!list_empty(&ign++->ign_list)); */ + if (list_empty(&ign++->ign_list)) + continue; + ign--; + AuDbg("%d: pid %d, 0x%x\n", + n + 1, ign->ign_pid, ign->ign_events); + ign++; + au_dbg_blocked(); + } +} +#endif + +/* ---------------------------------------------------------------------- */ + +static char *in_name(u32 mask) +{ +#ifdef CONFIG_AUFS_DEBUG +#define test_ret(flag) if (mask & flag) return #flag; + test_ret(IN_ACCESS); + test_ret(IN_MODIFY); + test_ret(IN_ATTRIB); + test_ret(IN_CLOSE_WRITE); + test_ret(IN_CLOSE_NOWRITE); + test_ret(IN_OPEN); + test_ret(IN_MOVED_FROM); + test_ret(IN_MOVED_TO); + test_ret(IN_CREATE); + test_ret(IN_DELETE); + test_ret(IN_DELETE_SELF); + test_ret(IN_MOVE_SELF); + test_ret(IN_UNMOUNT); + test_ret(IN_Q_OVERFLOW); + test_ret(IN_IGNORED); + return ""; +#undef test_ret +#else + return "??"; +#endif +} + +/* ---------------------------------------------------------------------- */ + +static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen, + struct inode *dir) +{ + struct dentry *dentry, *d, *parent; + struct qstr *dname; + + LKTRTrace("%.*s, dir%lu\n", nlen, name, dir->i_ino); + + parent = d_find_alias(dir); + if (!parent) + return NULL; + + dentry = NULL; + spin_lock(&dcache_lock); + list_for_each_entry(d, &parent->d_subdirs, d_u.d_child) { + LKTRTrace("%.*s\n", AuDLNPair(d)); + dname = &d->d_name; + if (dname->len != nlen || memcmp(dname->name, name, nlen)) + continue; + if (!atomic_read(&d->d_count) || !d->d_fsdata) { + spin_lock(&d->d_lock); + __d_drop(d); + spin_unlock(&d->d_lock); + continue; + } + + dentry = dget(d); + break; + } + spin_unlock(&dcache_lock); + dput(parent); + + if (dentry) { +#if 0 + lktr_set_pid(current->pid, LktrArrayPid); + AuDbgDentry(dentry); + lktr_clear_pid(current->pid, LktrArrayPid); +#endif + di_write_lock_child(dentry); + } + return dentry; +} + +static struct inode *lookup_wlock_by_ino(struct super_block *sb, + aufs_bindex_t bindex, ino_t h_ino) +{ + struct inode *inode; + struct au_xino_entry xinoe; + int err; + + LKTRTrace("b%d, hi%lu\n", bindex, (unsigned long)h_ino); + AuDebugOn(!au_opt_test_xino(au_mntflags(sb))); + + inode = NULL; + err = au_xino_read(sb, bindex, h_ino, &xinoe); + if (!err && xinoe.ino) + inode = ilookup(sb, xinoe.ino); + if (!inode) + goto out; + if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { + AuWarn("wrong root branch\n"); + iput(inode); + inode = NULL; + goto out; + } + + ii_write_lock_child(inode); + + out: + return inode; +} + +static int hin_xino(struct inode *inode, struct inode *h_inode) +{ + int err; + aufs_bindex_t bindex, bend, bfound, bstart; + struct inode *h_i; + + LKTRTrace("i%lu, hi%lu\n", inode->i_ino, h_inode->i_ino); + + err = 0; + if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { + AuWarn("branch root dir was changed\n"); + goto out; + } + + bfound = -1; + bend = au_ibend(inode); + bstart = au_ibstart(inode); +#if 0 /* reserved for future use */ + if (bindex == bend) { + /* keep this ino in rename case */ + goto out; + } +#endif + for (bindex = bstart; bindex <= bend; bindex++) { + if (au_h_iptr(inode, bindex) == h_inode) { + bfound = bindex; + break; + } + } + if (bfound < 0) + goto out; + + for (bindex = bstart; bindex <= bend; bindex++) { + h_i = au_h_iptr(inode, bindex); + if (h_i) + err = au_xino_write0(inode->i_sb, bindex, h_i->i_ino, + 0); + /* ignore this error */ + /* bad action? */ + } + + /* children inode number will be broken */ + + out: + AuTraceErr(err); + return err; +} + +static int hin_gen_tree(struct dentry *dentry) +{ + int err, i, j, ndentry; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + struct dentry **dentries; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + + err = au_dpages_init(&dpages, GFP_NOFS); + if (unlikely(err)) + goto out; + err = au_dcsub_pages(&dpages, dentry, NULL, NULL); + if (unlikely(err)) + goto out_dpages; + + for (i = 0; i < dpages.ndpage; i++) { + dpage = dpages.dpages + i; + dentries = dpage->dentries; + ndentry = dpage->ndentry; + for (j = 0; j < ndentry; j++) { + struct dentry *d; + d = dentries[j]; + LKTRTrace("%.*s\n", AuDLNPair(d)); + if (IS_ROOT(d)) + continue; + + d_drop(d); + au_digen_dec(d); + if (d->d_inode) + /* todo: reset children xino? + cached children only? */ + au_iigen_dec(d->d_inode); + } + } + + out_dpages: + au_dpages_free(&dpages); + + /* discard children */ + dentry_unhash(dentry); + dput(dentry); + out: + AuTraceErr(err); + return err; +} + +/* + * return 0 if processed. + */ +static int hin_gen_by_inode(char *name, unsigned int nlen, struct inode *inode, + const unsigned int isdir) +{ + int err; + struct dentry *d; + struct qstr *dname; + + LKTRTrace("%.*s, i%lu\n", nlen, name, inode->i_ino); + + err = 1; + if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { + AuWarn("branch root dir was changed\n"); + err = 0; + goto out; + } + + if (!isdir) { + AuDebugOn(!name); + au_iigen_dec(inode); + spin_lock(&dcache_lock); + list_for_each_entry(d, &inode->i_dentry, d_alias) { + dname = &d->d_name; + if (dname->len != nlen + && memcmp(dname->name, name, nlen)) + continue; + err = 0; + spin_lock(&d->d_lock); + __d_drop(d); + au_digen_dec(d); + spin_unlock(&d->d_lock); + break; + } + spin_unlock(&dcache_lock); + } else { + au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIRS); + d = d_find_alias(inode); + if (!d) { + au_iigen_dec(inode); + goto out; + } + + dname = &d->d_name; + if (dname->len == nlen && !memcmp(dname->name, name, nlen)) + err = hin_gen_tree(d); + dput(d); + } + + out: + AuTraceErr(err); + return err; +} + +static int hin_gen_by_name(struct dentry *dentry, const unsigned int isdir) +{ + int err; + struct inode *inode; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + + inode = dentry->d_inode; + if (IS_ROOT(dentry) + /* || (inode && inode->i_ino == AUFS_ROOT_INO) */ + ) { + AuWarn("branch root dir was changed\n"); + return 0; + } + + err = 0; + if (!isdir) { + d_drop(dentry); + au_digen_dec(dentry); + if (inode) + au_iigen_dec(inode); + } else { + au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIRS); + if (inode) + err = hin_gen_tree(dentry); + } + + AuTraceErr(err); + return err; +} + +static void hin_attr(struct inode *inode, struct inode *h_inode) +{ + struct dentry *h_dentry; + + LKTRTrace("i%lu, hi%lu\n", inode->i_ino, h_inode->i_ino); + + if (au_h_iptr(inode, au_ibstart(inode)) != h_inode) + return; + + h_dentry = d_find_alias(h_inode); + if (h_dentry) { + au_update_fuse_h_inode(NULL, h_dentry); + /* ignore an error*/ + dput(h_dentry); + } + + au_cpup_attr_all(inode); +} + +/* ---------------------------------------------------------------------- */ + +/* hinotify job flags */ +#define AuHinJob_XINO0 1 +#define AuHinJob_GEN (1 << 1) +#define AuHinJob_DIRENT (1 << 2) +#define AuHinJob_ATTR (1 << 3) +#define AuHinJob_ISDIR (1 << 4) +#define AuHinJob_TRYXINO0 (1 << 5) +#define AuHinJob_MNTPNT (1 << 6) +#define au_ftest_hinjob(flags, name) ((flags) & AuHinJob_##name) +#define au_fset_hinjob(flags, name) { (flags) |= AuHinJob_##name; } +#define au_fclr_hinjob(flags, name) { (flags) &= ~AuHinJob_##name; } + +struct hin_job_args { + unsigned int flags; + struct inode *inode, *h_inode, *dir, *h_dir; + struct dentry *dentry; + char *h_name; + int h_nlen; +}; + +static int hin_job(struct hin_job_args *a) +{ + const unsigned int isdir = au_ftest_hinjob(a->flags, ISDIR); + + /* reset xino */ + if (au_ftest_hinjob(a->flags, XINO0) && a->inode) + hin_xino(a->inode, a->h_inode); + /* ignore this error */ + + if (au_ftest_hinjob(a->flags, TRYXINO0) + && a->inode + && a->h_inode) { + mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); + if (!a->h_inode->i_nlink) + hin_xino(a->inode, a->h_inode); + /* ignore this error */ + mutex_unlock(&a->h_inode->i_mutex); + } + + /* make the generation obsolete */ + if (au_ftest_hinjob(a->flags, GEN)) { + int err = -1; + if (a->inode) + err = hin_gen_by_inode(a->h_name, a->h_nlen, a->inode, + isdir); + if (err && a->dentry) + hin_gen_by_name(a->dentry, isdir); + /* ignore this error */ + } + + /* make dir entries obsolete */ + if (au_ftest_hinjob(a->flags, DIRENT) && a->inode) { + struct au_vdir *vdir; + IiMustWriteLock(a->inode); + vdir = au_ivdir(a->inode); + if (vdir) + vdir->vd_jiffy = 0; + /* IMustLock(a->inode); */ + /* a->inode->i_version++; */ + } + + /* update the attr */ + if (au_ftest_hinjob(a->flags, ATTR) && a->inode && a->h_inode) + hin_attr(a->inode, a->h_inode); + + /* can do nothing but warn */ + if (au_ftest_hinjob(a->flags, MNTPNT) + && a->dentry + && d_mountpoint(a->dentry)) + AuWarn("mount-point %.*s is removed or renamed\n", + AuDLNPair(a->dentry)); + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +enum { CHILD, PARENT }; +struct postproc_args { + struct inode *h_dir, *dir, *h_child_inode; + u32 mask; + unsigned int flags[2]; + unsigned int h_child_nlen; + char h_child_name[]; +}; + +static void postproc(void *_args) +{ + struct postproc_args *a = _args; + struct super_block *sb; + aufs_bindex_t bindex, bend, bfound; + unsigned char xino, try_iput; + int err; + struct inode *inode; + ino_t h_ino; + struct hin_job_args args; + struct dentry *dentry; + struct au_sbinfo *sbinfo; + + AuDebugOn(!_args); + AuDebugOn(!a->h_dir); + AuDebugOn(!a->dir); + AuDebugOn(!a->mask); + LKTRTrace("mask 0x%x %s, i%lu, hi%lu, hci%lu\n", + a->mask, in_name(a->mask), a->dir->i_ino, a->h_dir->i_ino, + a->h_child_inode ? a->h_child_inode->i_ino : 0); + + inode = NULL; + dentry = NULL; + /* + * do not lock a->dir->i_mutex here + * because of d_revalidate() may cause a deadlock. + */ + sb = a->dir->i_sb; + AuDebugOn(!sb); + sbinfo = au_sbi(sb); + AuDebugOn(!sbinfo); + /* big aufs lock */ + si_noflush_write_lock(sb); + + ii_read_lock_parent(a->dir); + bfound = -1; + bend = au_ibend(a->dir); + for (bindex = au_ibstart(a->dir); bindex <= bend; bindex++) + if (au_h_iptr(a->dir, bindex) == a->h_dir) { + bfound = bindex; + break; + } + ii_read_unlock(a->dir); + if (unlikely(bfound < 0)) + goto out; + + xino = !!au_opt_test_xino(au_mntflags(sb)); + h_ino = 0; + if (a->h_child_inode) + h_ino = a->h_child_inode->i_ino; + + if (a->h_child_nlen + && (au_ftest_hinjob(a->flags[CHILD], GEN) + || au_ftest_hinjob(a->flags[CHILD], MNTPNT))) + dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen, + a->dir); + try_iput = 0; + if (dentry) + inode = dentry->d_inode; + if (xino && !inode && h_ino + && (au_ftest_hinjob(a->flags[CHILD], XINO0) + || au_ftest_hinjob(a->flags[CHILD], TRYXINO0) + || au_ftest_hinjob(a->flags[CHILD], GEN) + || au_ftest_hinjob(a->flags[CHILD], ATTR))) { + inode = lookup_wlock_by_ino(sb, bfound, h_ino); + try_iput = 1; + } + + args.flags = a->flags[CHILD]; + args.dentry = dentry; + args.inode = inode; + args.h_inode = a->h_child_inode; + args.dir = a->dir; + args.h_dir = a->h_dir; + args.h_name = a->h_child_name; + args.h_nlen = a->h_child_nlen; + err = hin_job(&args); + if (dentry) { + if (dentry->d_fsdata) + di_write_unlock(dentry); + dput(dentry); + } + if (inode && try_iput) { + ii_write_unlock(inode); + iput(inode); + } + + ii_write_lock_parent(a->dir); + args.flags = a->flags[PARENT]; + args.dentry = NULL; + args.inode = a->dir; + args.h_inode = a->h_dir; + args.dir = NULL; + args.h_dir = NULL; + args.h_name = NULL; + args.h_nlen = 0; + err = hin_job(&args); + ii_write_unlock(a->dir); + + out: + au_nwt_done(&sbinfo->si_nowait); + si_write_unlock(sb); + + iput(a->h_child_inode); + iput(a->h_dir); + iput(a->dir); + kfree(a); +} + +static void aufs_inotify(struct inotify_watch *watch, u32 wd, u32 mask, + u32 cookie, const char *h_child_name, + struct inode *h_child_inode) +{ + struct au_hinotify *hinotify; + struct postproc_args *args; + int len, wkq_err; + unsigned char isdir, isroot, wh; + char *p; + struct inode *dir; + unsigned int flags[2]; + + LKTRTrace("i%lu, wd %d, mask 0x%x %s, cookie 0x%x, hcname %s, hi%lu\n", + watch->inode->i_ino, wd, mask, in_name(mask), cookie, + h_child_name ? h_child_name : "", + h_child_inode ? h_child_inode->i_ino : 0); + + /* if IN_UNMOUNT happens, there must be another bug */ + if (mask & (IN_IGNORED | IN_UNMOUNT)) { + put_inotify_watch(watch); + return; + } + +#ifdef DbgInotify + if (!h_child_name || strcmp(h_child_name, AUFS_XINO_FNAME)) + AuDbg("i%lu, wd %d, mask 0x%x %s, cookie 0x%x, hcname %s," + " hi%lu\n", + watch->inode->i_ino, wd, mask, in_name(mask), cookie, + h_child_name ? h_child_name : "", + h_child_inode ? h_child_inode->i_ino : 0); +#endif + + hinotify = container_of(watch, struct au_hinotify, hin_watch); + AuDebugOn(!hinotify || !hinotify->hin_aufs_inode); + if (au_hin_test_ignore(mask, hinotify)) { +#ifdef DbgInotify + AuDbg("ignored\n"); +#endif + return; + } +#if 0 /* tmp debug */ + if (h_child_name && !strcmp(h_child_name, AUFS_XINO_FNAME)) + { + AuDbg("i%lu, wd %d, mask 0x%x %s, cookie 0x%x, hcname %s, hi%lu\n", + watch->inode->i_ino, wd, mask, in_name(mask), cookie, + h_child_name ? h_child_name : "", + h_child_inode ? h_child_inode->i_ino : 0); + //au_dbg_blocked(); + } +#endif + + dir = igrab(hinotify->hin_aufs_inode); + if (!dir) + return; + isroot = (dir->i_ino == AUFS_ROOT_INO); + len = 0; + wh = 0; + if (h_child_name) { + len = strlen(h_child_name); + if (!memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { + h_child_name += AUFS_WH_PFX_LEN; + len -= AUFS_WH_PFX_LEN; + wh = 1; + } + } + + isdir = 0; + if (h_child_inode) + isdir = !!S_ISDIR(h_child_inode->i_mode); + flags[PARENT] = AuHinJob_ISDIR; + flags[CHILD] = 0; + if (isdir) + flags[CHILD] = AuHinJob_ISDIR; + switch (mask & IN_ALL_EVENTS) { + case IN_MODIFY: + /*FALLTHROUGH*/ + case IN_ATTRIB: + if (h_child_inode) { + if (!wh) + au_fset_hinjob(flags[CHILD], ATTR); + } else + au_fset_hinjob(flags[PARENT], ATTR); + break; + + /* IN_MOVED_FROM is the first event in rename(2) */ + case IN_MOVED_FROM: + case IN_MOVED_TO: + AuDebugOn(!h_child_name || !h_child_inode); + au_fset_hinjob(flags[CHILD], GEN); + au_fset_hinjob(flags[CHILD], ATTR); + if (1 || isdir) + au_fset_hinjob(flags[CHILD], XINO0); + au_fset_hinjob(flags[CHILD], MNTPNT); + + au_fset_hinjob(flags[PARENT], ATTR); + au_fset_hinjob(flags[PARENT], DIRENT); + break; + + case IN_CREATE: + AuDebugOn(!h_child_name || !h_child_inode); + au_fset_hinjob(flags[PARENT], ATTR); + au_fset_hinjob(flags[PARENT], DIRENT); + au_fset_hinjob(flags[CHILD], GEN); + /* hard link */ + if (!isdir && h_child_inode->i_nlink > 1) + au_fset_hinjob(flags[CHILD], ATTR); + break; + + case IN_DELETE: + /* + * aufs never be able to get this child inode. + * revalidation should be in d_revalidate() + * by checking i_nlink, i_generation or d_unhashed(). + */ + AuDebugOn(!h_child_name); + au_fset_hinjob(flags[PARENT], ATTR); + au_fset_hinjob(flags[PARENT], DIRENT); + au_fset_hinjob(flags[CHILD], GEN); + au_fset_hinjob(flags[CHILD], TRYXINO0); + au_fset_hinjob(flags[CHILD], MNTPNT); + break; + + case IN_DELETE_SELF: +#if 0 + if (!isroot) + au_fset_hinjob(flags[PARENT], GEN); + /*FALLTHROUGH*/ +#endif + + case IN_MOVE_SELF: +#if 0 + /* + * when an inotify is set to an aufs inode, + * such inode can be isolated and this event can be fired + * solely. + */ + AuDebugOn(h_child_name || h_child_inode); + if (unlikely(isroot)) { + AuWarn("root branch was moved\n"); + iput(dir); + return; + } + au_fset_hinjob(flags[PARENT], XINO0); + au_fset_hinjob(flags[PARENT], GEN); + au_fset_hinjob(flags[PARENT], ATTR); + au_fset_hinjob(flags[PARENT], DIRENT); + /* au_fset_hinjob(flags[PARENT], MNTPNT); */ + break; +#endif + + case IN_ACCESS: + default: + AuDebugOn(1); + } + + if (wh) + h_child_inode = NULL; + + /* iput() and kfree() will be called in postproc() */ + /* + * inotify_mutex is already acquired and kmalloc/prune_icache may lock + * iprune_mutex. strange. + */ + lockdep_off(); + args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS); + lockdep_on(); + if (unlikely(!args)) { + AuErr1("no memory\n"); + iput(dir); + return; + } + args->flags[PARENT] = flags[PARENT]; + args->flags[CHILD] = flags[CHILD]; + args->mask = mask; + args->dir = dir; + args->h_dir = igrab(watch->inode); + if (h_child_inode) + h_child_inode = igrab(h_child_inode); /* can be NULL */ + args->h_child_inode = h_child_inode; + args->h_child_nlen = len; + if (len) { + p = (void *)args; + p += sizeof(*args); + memcpy(p, h_child_name, len + 1); + } + + lockdep_off(); + wkq_err = au_wkq_nowait(postproc, args, dir->i_sb, /*dlgt*/0); + lockdep_on(); + if (unlikely(wkq_err)) + AuErr("wkq %d\n", wkq_err); +} + +static void aufs_inotify_destroy(struct inotify_watch *watch) +{ + return; +} + +static struct inotify_operations aufs_inotify_ops = { + .handle_event = aufs_inotify, + .destroy_watch = aufs_inotify_destroy +}; + +/* ---------------------------------------------------------------------- */ + +static void au_hin_destroy_cache(void) +{ + kmem_cache_destroy(au_cachep[AuCache_HINOTIFY]); + au_cachep[AuCache_HINOTIFY] = NULL; +} + +int __init au_inotify_init(void) +{ + int err; + + err = -ENOMEM; + au_cachep[AuCache_HINOTIFY] = AuCache(au_hinotify); + if (au_cachep[AuCache_HINOTIFY]) { + err = 0; + in_handle = inotify_init(&aufs_inotify_ops); + if (IS_ERR(in_handle)) { + err = PTR_ERR(in_handle); + au_hin_destroy_cache(); + } + } + AuTraceErr(err); + return err; +} + +void au_inotify_fin(void) +{ + inotify_destroy(in_handle); + if (au_cachep[AuCache_HINOTIFY]) + au_hin_destroy_cache(); +} --- linux-2.6.27.orig/ubuntu/aufs/export.c +++ linux-2.6.27/ubuntu/aufs/export.c @@ -0,0 +1,797 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * export via nfs + * + * $Id: export.c,v 1.15 2008/09/22 03:52:19 sfjro Exp $ + */ + +#include +#include +#include +#include "aufs.h" + +union conv { +#ifdef CONFIG_AUFS_INO_T_64 + __u32 a[2]; +#else + __u32 a[1]; +#endif + ino_t ino; +}; + +static ino_t decode_ino(__u32 *a) +{ + union conv u; + + BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a)); + u.a[0] = a[0]; +#ifdef CONFIG_AUFS_INO_T_64 + u.a[1] = a[1]; +#endif + return u.ino; +} + +static void encode_ino(__u32 *a, ino_t ino) +{ + union conv u; + + u.ino = ino; + a[0] = u.a[0]; +#ifdef CONFIG_AUFS_INO_T_64 + a[1] = u.a[1]; +#endif +} + +/* NFS file handle */ +enum { + Fh_br_id, + Fh_sigen, +#ifdef CONFIG_AUFS_INO_T_64 + /* support 64bit inode number */ + Fh_ino1, + Fh_ino2, + Fh_dir_ino1, + Fh_dir_ino2, +#else + Fh_ino1, + Fh_dir_ino1, +#endif + Fh_igen, + Fh_h_type, + Fh_tail, + + Fh_ino = Fh_ino1, + Fh_dir_ino = Fh_dir_ino1 +}; + +static int au_test_anon(struct dentry *dentry) +{ + return !!(dentry->d_flags & DCACHE_DISCONNECTED); +} + +/* ---------------------------------------------------------------------- */ +/* inode generation external table */ + +int au_xigen_inc(struct inode *inode) +{ + int err; + loff_t pos; + ssize_t sz; + __u32 igen; + struct super_block *sb; + struct au_sbinfo *sbinfo; + + LKTRTrace("i%lu\n", (unsigned long)inode->i_ino); + + err = 0; + sb = inode->i_sb; + if (unlikely(!au_opt_test_xino(au_mntflags(sb)))) + goto out; + + pos = inode->i_ino; + pos *= sizeof(igen); + igen = inode->i_generation + 1; + sbinfo = au_sbi(sb); + sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xigen, &igen, + sizeof(igen), &pos); + if (sz == sizeof(igen)) + goto out; /* success */ + + err = sz; + if (unlikely(sz >= 0)) { + err = -EIO; + AuIOErr("xigen error (%ld)\n", (long)sz); + } + + out: + AuTraceErr(err); + return err; +} + +int au_xigen_new(struct inode *inode) +{ + int err; + loff_t pos; + ssize_t sz; + struct super_block *sb; + struct au_sbinfo *sbinfo; + struct file *file; + + LKTRTrace("i%lu\n", (unsigned long)inode->i_ino); + + err = 0; + sb = inode->i_sb; + if (unlikely(!au_opt_test_xino(au_mntflags(sb)))) + goto out; + + err = -EFBIG; + pos = inode->i_ino; + if (unlikely(Au_LOFF_MAX / sizeof(inode->i_generation) - 1 < pos)) { + AuIOErr1("too large i%lld\n", pos); + goto out; + } + pos *= sizeof(inode->i_generation); + + err = 0; + sbinfo = au_sbi(sb); + file = sbinfo->si_xigen; + /* todo: dirty, at mount time */ + if (unlikely(!file)) { + if (inode->i_ino == AUFS_ROOT_INO) + goto out; + else + BUG(); + } + + if (i_size_read(file->f_dentry->d_inode) + < pos + sizeof(inode->i_generation)) { + spin_lock(&sbinfo->si_xigen_lock); + inode->i_generation = sbinfo->si_xigen_next++; + spin_unlock(&sbinfo->si_xigen_lock); + sz = xino_fwrite(sbinfo->si_xwrite, file, &inode->i_generation, + sizeof(inode->i_generation), &pos); + } else + sz = xino_fread(sbinfo->si_xread, file, &inode->i_generation, + sizeof(inode->i_generation), &pos); + if (sz == sizeof(inode->i_generation)) + goto out; /* success */ + + err = sz; + if (unlikely(sz >= 0)) { + err = -EIO; + AuIOErr("xigen error (%ld)\n", (long)sz); + } + + out: + AuTraceErr(err); + return err; +} + +int au_xigen_set(struct super_block *sb, struct file *base) +{ + int err; + struct au_sbinfo *sbinfo; + struct file *file; + + LKTRTrace("%.*s\n", AuDLNPair(base->f_dentry)); + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + file = au_xino_create2(sb, base, sbinfo->si_xigen); + err = PTR_ERR(file); + if (IS_ERR(file)) + goto out; + err = 0; + if (sbinfo->si_xigen) + fput(sbinfo->si_xigen); + sbinfo->si_xigen = file; + + out: + AuTraceErr(err); + return err; +} + +void au_xigen_clr(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + + sbinfo = au_sbi(sb); + if (sbinfo->si_xigen) { + fput(sbinfo->si_xigen); + sbinfo->si_xigen = NULL; + } +} + +/* ---------------------------------------------------------------------- */ + +static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino, + ino_t dir_ino) +{ + struct dentry *dentry, *d; + struct inode *inode; + + LKTRTrace("i%lu, diri%lu\n", + (unsigned long)ino, (unsigned long)dir_ino); + + dentry = NULL; + inode = ilookup(sb, ino); + if (unlikely(!inode)) + goto out; + + dentry = ERR_PTR(-ESTALE); + if (unlikely(is_bad_inode(inode) || IS_DEADDIR(inode))) + goto out_iput; + AuDbgInode(inode); + + dentry = NULL; + if (!dir_ino || S_ISDIR(inode->i_mode)) + dentry = d_find_alias(inode); + else { + spin_lock(&dcache_lock); + list_for_each_entry(d, &inode->i_dentry, d_alias) + if (!au_test_anon(d) + && d->d_parent->d_inode->i_ino == dir_ino) { + dentry = dget_locked(d); + break; + } + spin_unlock(&dcache_lock); + } + AuDbgDentry(dentry); + + out_iput: + iput(inode); + out: + AuTraceErrPtr(dentry); + return dentry; +} + +/* ---------------------------------------------------------------------- */ + +/* todo: dirty? */ +/* + * when you mntput() for the return value of this function, + * you have to store it to your local var. + * ie. never mntput si_mntcache directly. + */ +static struct vfsmount *au_do_mnt_get(struct super_block *sb) +{ + struct mnt_namespace *ns; + struct vfsmount *pos, *mnt; + + AuTraceEnter(); + + /* vfsmount_lock is not exported */ + /* no get/put ?? */ + AuDebugOn(!current->nsproxy); + ns = current->nsproxy->mnt_ns; + AuDebugOn(!ns); + mnt = NULL; + /* the order (reverse) will not be a problem */ + list_for_each_entry(pos, &ns->list, mnt_list) + if (pos->mnt_sb == sb) { + mnt = pos; + break; + } + AuDebugOn(!mnt); + + return mntget(mnt); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) +static struct vfsmount *au_mnt_get(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + struct vfsmount *mnt; + + sbinfo = au_sbi(sb); + spin_lock(&sbinfo->si_mntcache_lock); + if (sbinfo->si_mntcache) + mnt = mntget(sbinfo->si_mntcache); + else { + sbinfo->si_mntcache = au_do_mnt_get(sb); + mnt = sbinfo->si_mntcache; + } + spin_unlock(&sbinfo->si_mntcache_lock); + return mnt; +} +#else +static struct vfsmount *au_mnt_get(struct super_block *sb) +{ + return au_do_mnt_get(sb); +} +#endif + +struct find_name_by_ino { + int called, found; + ino_t ino; + char *name; + int namelen; +}; + +static int +find_name_by_ino(void *arg, const char *name, int namelen, loff_t offset, + u64 ino, unsigned int d_type) +{ + struct find_name_by_ino *a = arg; + + a->called++; + if (a->ino != ino) + return 0; + + memcpy(a->name, name, namelen); + a->namelen = namelen; + a->found = 1; + return 1; +} + +static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino) +{ + struct dentry *dentry, *parent; + struct file *file; + struct inode *dir, *inode; + struct find_name_by_ino arg; + int err; + + parent = path->dentry; + LKTRTrace("%.*s, i%lu\n", AuDLNPair(parent), (unsigned long )ino); + + path_get(path); + file = dentry_open(parent, path->mnt, au_dir_roflags); + dentry = (void *)file; + if (IS_ERR(file)) + goto out; + + dentry = ERR_PTR(-ENOMEM); + arg.name = __getname(); + if (unlikely(!arg.name)) + goto out_file; + arg.ino = ino; + arg.found = 0; + do { + arg.called = 0; + /* smp_mb(); */ + err = vfsub_readdir(file, find_name_by_ino, &arg, /*dlgt*/0); + } while (!err && !arg.found && arg.called); + dentry = ERR_PTR(err); + if (unlikely(err)) + goto out_name; + dentry = ERR_PTR(-ENOENT); + if (!arg.found) + goto out_name; + + /* do not call au_lkup_one(), nor dlgt */ + dir = parent->d_inode; + mutex_lock(&dir->i_mutex); + dentry = vfsub_lookup_one_len(arg.name, parent, arg.namelen); + mutex_unlock(&dir->i_mutex); + AuTraceErrPtr(dentry); + if (IS_ERR(dentry)) + goto out_name; + AuDebugOn(au_test_anon(dentry)); + inode = dentry->d_inode; + if (unlikely(!inode)) { + dput(dentry); + dentry = ERR_PTR(-ENOENT); + } + + out_name: + __putname(arg.name); + out_file: + fput(file); + out: + AuTraceErrPtr(dentry); + return dentry; +} + +static /* noinline_for_stack */ +struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino, + ino_t dir_ino) +{ + struct dentry *dentry, *parent; + struct path path; + + LKTRTrace("i%lu, diri%lu\n", + (unsigned long)ino, (unsigned long)dir_ino); + + parent = sb->s_root; + if (dir_ino != AUFS_ROOT_INO) { + parent = decode_by_ino(sb, dir_ino, 0); + AuDbgDentry(parent); + dentry = parent; + if (unlikely(!parent)) + goto out; + if (IS_ERR(parent)) + goto out; + AuDebugOn(au_test_anon(parent)); + } else + dget(parent); + + path.dentry = parent; + path.mnt = au_mnt_get(sb); + dentry = au_lkup_by_ino(&path, ino); + path_put(&path); + + out: + AuTraceErrPtr(dentry); + return dentry; +} + +/* ---------------------------------------------------------------------- */ + +static int h_acceptable(void *expv, struct dentry *dentry) +{ + return 1; +} + +static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath, + char *buf, int len, struct super_block *sb) +{ + char *p; + int n; + struct path path; + + AuTraceEnter(); + + p = d_path(h_rootpath, buf, len); + if (IS_ERR(p)) + goto out; + n = strlen(p); + + path.mnt = h_rootpath->mnt; + path.dentry = h_parent; + p = d_path(&path, buf, len); + if (IS_ERR(p)) + goto out; + LKTRTrace("%s\n", p); + if (n != 1) + p += n; + LKTRTrace("%p, %s, %ld\n", + p, p, (long)(p - buf)); + + path.mnt = au_mnt_get(sb); + path.dentry = sb->s_root; + p = d_path(&path, buf, len - strlen(p)); + mntput(path.mnt); + if (IS_ERR(p)) + goto out; + if (n != 1) + p[strlen(p)] = '/'; + LKTRTrace("%s\n", p); + + out: + AuTraceErrPtr(p); + return p; +} + +static noinline_for_stack +struct dentry *decode_by_path(struct super_block *sb, aufs_bindex_t bindex, + ino_t ino, __u32 *fh, int fh_len) +{ + struct dentry *dentry, *h_parent, *root; + struct super_block *h_sb; + char *pathname, *p; + struct vfsmount *h_mnt; + struct au_branch *br; + int err; + struct nameidata nd; + + LKTRTrace("b%d\n", bindex); + SiMustAnyLock(sb); + + br = au_sbr(sb, bindex); + /* au_br_get(br); */ + h_mnt = br->br_mnt; + h_sb = h_mnt->mnt_sb; + LKTRTrace("%s, h_decode_fh\n", au_sbtype(h_sb)); + /* in linux-2.6.24, it takes struct fid * as file handle */ + /* todo: call lower fh_to_dentry()? fh_to_parent()? */ + h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail), + fh_len - Fh_tail, fh[Fh_h_type], + h_acceptable, /*context*/NULL); + dentry = h_parent; + if (unlikely(!h_parent || IS_ERR(h_parent))) { + AuWarn1("%s decode_fh failed, %ld\n", + au_sbtype(h_sb), PTR_ERR(h_parent)); + goto out; + } + dentry = NULL; + if (unlikely(au_test_anon(h_parent))) { + AuWarn1("%s decode_fh returned a disconnected dentry\n", + au_sbtype(h_sb)); + goto out_h_parent; + } + + dentry = ERR_PTR(-ENOMEM); + pathname = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!pathname)) + goto out_h_parent; + + root = sb->s_root; + nd.path.mnt = h_mnt; + di_read_lock_parent(root, !AuLock_IR); + nd.path.dentry = au_h_dptr(root, bindex); + di_read_unlock(root, !AuLock_IR); + p = au_build_path(h_parent, &nd.path, pathname, PAGE_SIZE, sb); + dentry = (void *)p; + if (IS_ERR(p)) + goto out_pathname; + + LKTRTrace("%s\n", p); + err = vfsub_path_lookup(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd); + dentry = ERR_PTR(err); + if (unlikely(err)) + goto out_pathname; + + dentry = ERR_PTR(-ENOENT); + AuDebugOn(au_test_anon(nd.path.dentry)); + if (unlikely(!nd.path.dentry->d_inode)) + goto out_nd; + + if (ino != nd.path.dentry->d_inode->i_ino) + dentry = au_lkup_by_ino(&nd.path, ino); + else + dentry = dget(nd.path.dentry); + + out_nd: + path_put(&nd.path); + out_pathname: + free_page((unsigned long)pathname); + out_h_parent: + dput(h_parent); + out: + /* au_br_put(br); */ + AuTraceErrPtr(dentry); + return dentry; +} + +/* ---------------------------------------------------------------------- */ + +static struct dentry * +aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, + int fh_type) +{ + struct dentry *dentry; + struct inode *inode; + __u32 *fh = fid->raw; + ino_t ino, dir_ino; + aufs_bindex_t bindex, br_id; + au_gen_t sigen; + + LKTRTrace("%d, fh{br_id %u, sigen %u, i%u, diri%u, g%u}\n", + fh_type, fh[Fh_br_id], fh[Fh_sigen], fh[Fh_ino], + fh[Fh_dir_ino], fh[Fh_igen]); + AuDebugOn(fh_len < Fh_tail); + + si_read_lock(sb, AuLock_FLUSH); + lockdep_off(); + + /* branch id may be wrapped around */ + dentry = ERR_PTR(-ESTALE); + br_id = fh[Fh_br_id]; + sigen = fh[Fh_sigen]; + bindex = au_br_index(sb, br_id); + LKTRTrace("b%d\n", bindex); + if (unlikely(bindex < 0 + || (0 && sigen != au_sigen(sb)) + || (1 && sigen + AUFS_BRANCH_MAX <= au_sigen(sb)) + )) + goto out; + + /* is this inode still cached? */ + ino = decode_ino(fh + Fh_ino); + AuDebugOn(ino == AUFS_ROOT_INO); + dir_ino = decode_ino(fh + Fh_dir_ino); + dentry = decode_by_ino(sb, ino, dir_ino); + if (IS_ERR(dentry)) + goto out; + if (dentry) + goto accept; + + /* is the parent dir cached? */ + dentry = decode_by_dir_ino(sb, ino, dir_ino); + if (IS_ERR(dentry)) + goto out; + if (dentry) + goto accept; + + /* lookup path */ + dentry = decode_by_path(sb, bindex, ino, fh, fh_len); + if (IS_ERR(dentry)) + goto out; + if (unlikely(!dentry)) + goto out; + + accept: + LKTRLabel(accept); + inode = dentry->d_inode; +#if 0 + /* support branch manupilation and udba on nfs server */ + sigen = au_sigen(sb); + if (unlikely(au_digen(dentry) != sigen + || au_iigen(inode) != sigen)) { + int err; + + //lktr_set_pid(current->pid, LktrArrayPid); + //au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIRS); + di_write_lock_child(dentry); + err = au_reval_dpath(dentry, sigen); + di_write_unlock(dentry); + //lktr_clear_pid(current->pid, LktrArrayPid); + if (unlikely(err < 0)) + goto out_dput; + } +#endif + + if (unlikely(inode->i_generation != fh[Fh_igen])) { + LKTRLabel(stale); + dput(dentry); + dentry = ERR_PTR(-ESTALE); + } + + out: + LKTRLabel(out); + lockdep_on(); + si_read_unlock(sb); + AuTraceErrPtr(dentry); + return dentry; +} + +#if 0 /* reserved for future use */ +/* support subtreecheck option */ +static struct dentry *aufs_fh_to_parent(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type) +{ + struct dentry *parent; + __u32 *fh = fid->raw; + ino_t dir_ino; + + dir_ino = decode_ino(fh + Fh_dir_ino); + parent = decode_by_ino(sb, dir_ino, 0); + if (IS_ERR(parent)) + goto out; + if (!parent) + parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]), + dir_ino, fh, fh_len); + + out: + AuTraceErrPtr(parent); + return parent; +} +#endif + +/* ---------------------------------------------------------------------- */ + +static int aufs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, + int connectable) +{ + int err; + aufs_bindex_t bindex, bend; + struct super_block *sb, *h_sb; + struct inode *inode; + struct dentry *parent, *h_parent; + struct au_branch *br; + + LKTRTrace("%.*s, max %d, conn %d\n", + AuDLNPair(dentry), *max_len, connectable); + AuDebugOn(au_test_anon(dentry)); + + parent = NULL; + err = -ENOSPC; + if (unlikely(*max_len <= Fh_tail)) { + AuWarn1("NFSv2 client (max_len %d)?\n", *max_len); + goto out; + } + + err = FILEID_ROOT; + inode = dentry->d_inode; + AuDebugOn(!inode); + if (inode->i_ino == AUFS_ROOT_INO) + goto out; + + err = -EIO; + h_parent = NULL; + sb = dentry->d_sb; + parent = dget_parent(dentry); + aufs_read_lock(parent, AuLock_FLUSH | AuLock_IR); +#ifdef CONFIG_AUFS_DEBUG + { + unsigned int mnt_flags = au_mntflags(sb); + + if (unlikely(!au_opt_test_xino(mnt_flags))) + AuWarn1("NFS-exporting requires xino\n"); + if (unlikely(0 && !au_opt_test(mnt_flags, UDBA_INOTIFY))) + AuWarn1("udba=inotify is recommended " + "for NFS-exporting\n"); + } +#endif + + bend = au_dbtaildir(parent); + for (bindex = au_dbstart(parent); bindex <= bend; bindex++) { + h_parent = au_h_dptr(parent, bindex); + if (h_parent) { + dget(h_parent); + break; + } + } + if (unlikely(!h_parent)) + goto out_unlock; + LKTRTrace("b%d\n", bindex); + + err = -EPERM; + br = au_sbr(sb, bindex); + h_sb = br->br_mnt->mnt_sb; + if (unlikely(!h_sb->s_export_op)) { + AuErr1("%s branch is not exportable\n", au_sbtype(h_sb)); + goto out_dput; + } + + fh[Fh_br_id] = br->br_id; + fh[Fh_sigen] = au_sigen(sb); + encode_ino(fh + Fh_ino, inode->i_ino); + encode_ino(fh + Fh_dir_ino, parent->d_inode->i_ino); + fh[Fh_igen] = inode->i_generation; + + *max_len -= Fh_tail; + /* in linux-2.6.24, it takes struct fid * as file handle */ + fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail), + max_len, connectable); + err = fh[Fh_h_type]; + *max_len += Fh_tail; + /* todo: macros? */ + if (err != 255) + err = 99; + else + AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb)); + + out_dput: + dput(h_parent); + out_unlock: + aufs_read_unlock(parent, AuLock_IR); + dput(parent); + out: + AuTraceErr(err); + if (unlikely(err < 0)) + err = 255; + return err; +} + +/* ---------------------------------------------------------------------- */ + +static struct export_operations aufs_export_op = { + .fh_to_dentry = aufs_fh_to_dentry, + //.fh_to_parent = aufs_fh_to_parent, + .encode_fh = aufs_encode_fh +}; + +void au_export_init(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + + AuTraceEnter(); + SiMustWriteLock(sb); + + sb->s_export_op = &aufs_export_op; + sbinfo = au_sbi(sb); + sbinfo->si_xigen = NULL; + spin_lock_init(&sbinfo->si_xigen_lock); + /* todo: meaningless? */ + get_random_bytes(&sbinfo->si_xigen_next, sizeof(sbinfo->si_xigen_next)); + memset(&sbinfo->si_xinodir, 0, sizeof(struct path)); +} --- linux-2.6.27.orig/ubuntu/aufs/whout.h +++ linux-2.6.27/ubuntu/aufs/whout.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * whiteout for logical deletion and opaque directory + * + * $Id: whout.h,v 1.3 2008/06/30 03:57:35 sfjro Exp $ + */ + +#ifndef __AUFS_WHOUT_H__ +#define __AUFS_WHOUT_H__ + +#ifdef __KERNEL__ + +#include +#include +#include "dir.h" +#include "opts.h" +#include "super.h" + +int au_wh_name_alloc(const char *name, int len, struct qstr *wh); +void au_wh_name_free(struct qstr *wh); + +struct au_ndx; +int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio, + struct au_ndx *ndx); +int au_diropq_test(struct dentry *h_dentry, struct au_ndx *ndx); + +struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct qstr *prefix, + struct au_ndx *ndx); +int au_whtmp_ren(struct inode *dir, aufs_bindex_t bindex, + struct dentry *h_dentry); +int au_wh_unlink_dentry(struct au_hinode *dir, struct dentry *wh_dentry, + struct dentry *dentry, int dlgt); + +struct au_branch; +int au_wh_init(struct dentry *h_parent, struct au_branch *br, + struct vfsmount *nfsmnt, struct super_block *sb, + aufs_bindex_t bindex); + +/* diropq flags */ +#define AuDiropq_CREATE 1 +#define AuDiropq_DLGT (1 << 1) +#define au_ftest_diropq(flags, name) ((flags) & AuDiropq_##name) +#define au_fset_diropq(flags, name) { (flags) |= AuDiropq_##name; } +#define au_fclr_diropq(flags, name) { (flags) &= ~AuDiropq_##name; } +#ifndef CONFIG_AUFS_DLGT +#undef AuDiropq_DLGT +#define AuDiropq_DLGT 0 +#endif + +struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, + unsigned int flags); + +struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, + struct au_ndx *ndx); +struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_parent, struct au_ndx *ndx); + +/* real rmdir the whiteout-ed dir */ +struct au_whtmp_rmdir_args { + struct inode *dir; + aufs_bindex_t bindex; + struct dentry *wh_dentry; + struct au_nhash whlist; +}; + +struct au_nhash; +int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, + struct dentry *wh_dentry, struct au_nhash *whlist); +void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, + struct dentry *wh_dentry, struct au_nhash *whlist, + struct au_whtmp_rmdir_args *args); + +/* ---------------------------------------------------------------------- */ + +static inline +struct dentry *au_diropq_create(struct dentry *dentry, aufs_bindex_t bindex, + int dlgt) +{ + unsigned int flags = AuDiropq_CREATE; + if (unlikely(dlgt)) + au_fset_diropq(flags, DLGT); + return au_diropq_sio(dentry, bindex, flags); +} + +static inline +int au_diropq_remove(struct dentry *dentry, aufs_bindex_t bindex, int dlgt) +{ + unsigned int flags = !AuDiropq_CREATE; + if (unlikely(dlgt)) + au_fset_diropq(flags, DLGT); + return PTR_ERR(au_diropq_sio(dentry, bindex, flags)); +} + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_ROBR +/* robr.c */ +int au_test_robr_wh(struct qstr *name, struct dentry *h_parent, + struct qstr *wh_name, int try_sio, struct au_ndx *ndx); +int au_test_robr_shwh(struct super_block *sb, const struct qstr *name); +#else +static inline +int au_test_robr_wh(struct qstr *name, struct dentry *h_parent, + struct qstr *wh_name, int try_sio, struct au_ndx *ndx) +{ + return au_wh_test(h_parent, wh_name, try_sio, ndx); +} + +static inline +int au_test_robr_shwh(struct super_block *sb, const struct qstr *name) +{ + if (unlikely(!au_opt_test(au_mntflags(sb), SHWH) + && !strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))) + return -EPERM; + return 0; +} +#endif /* CONFIG_AUFS_ROBR */ + +#endif /* __KERNEL__ */ +#endif /* __AUFS_WHOUT_H__ */ --- linux-2.6.27.orig/ubuntu/aufs/sysfs.c +++ linux-2.6.27/ubuntu/aufs/sysfs.c @@ -0,0 +1,520 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * sysfs interface + * + * $Id: sysfs.c,v 1.13 2008/09/15 03:14:55 sfjro Exp $ + */ + +#include +#include +#include +#include +#include "aufs.h" + + +#ifdef CONFIG_AUFS_LOCAL +static ssize_t config_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ +#define conf_bool(name) "CONFIG_AUFS_" #name "=y\n" + static const char opt[] = +#ifdef CONFIG_AUFS + "CONFIG_AUFS=y\n" +#else + "CONFIG_AUFS=m\n" +#endif +#ifdef CONFIG_AUFS_BRANCH_MAX_127 + conf_bool(BRANCH_MAX_127) +#elif defined(CONFIG_AUFS_BRANCH_MAX_511) + conf_bool(BRANCH_MAX_511) +#elif defined(CONFIG_AUFS_BRANCH_MAX_1023) + conf_bool(BRANCH_MAX_1023) +#elif defined(CONFIG_AUFS_BRANCH_MAX_32767) + conf_bool(BRANCH_MAX_32767) +#endif +#ifdef CONFIG_AUFS_HINOTIFY + conf_bool(HINOTIFY) +#endif +#ifdef CONFIG_AUFS_EXPORT + conf_bool(EXPORT) +#endif +#ifdef CONFIG_AUFS_ROBR + conf_bool(ROBR) +#endif +#ifdef CONFIG_AUFS_SHWH + conf_bool(SHWH) +#endif +#ifdef CONFIG_AUFS_DLGT + conf_bool(DLGT) +#endif +#ifdef CONFIG_AUFS_HIN_OR_DLGT + conf_bool(HIN_OR_DLGT) +#endif +#ifdef CONFIG_AUFS_RR_SQUASHFS + conf_bool(RR_SQUASHFS) +#endif +#ifdef CONFIG_AUFS_SEC_PERM_PATCH + conf_bool(SEC_PERM_PATCH) +#endif +#ifdef CONFIG_AUFS_SPLICE_PATCH + conf_bool(SPLICE_PATCH) +#endif +#ifdef CONFIG_AUFS_PUT_FILP_PATCH + conf_bool(PUT_FILP_PATCH) +#endif +#ifdef CONFIG_AUFS_LHASH_PATCH + conf_bool(LHASH_PATCH) +#endif +#ifdef CONFIG_AUFS_BR_NFS + conf_bool(BR_NFS) +#endif +#ifdef CONFIG_AUFS_BR_XFS + conf_bool(BR_XFS) +#endif +#ifdef CONFIG_AUFS_FSYNC_SUPER_PATCH + conf_bool(FSYNC_SUPER_PATCH) +#endif +#ifdef CONFIG_AUFS_DENY_WRITE_ACCESS_PATCH + conf_bool(DENY_WRITE_ACCESS_PATCH) +#endif +#ifdef CONFIG_AUFS_KSIZE_PATCH + conf_bool(KSIZE_PATCH) +#endif +#ifdef CONFIG_AUFS_WORKAROUND_FUSE + conf_bool(WORKAROUND_FUSE) +#endif +#ifdef CONFIG_AUFS_HIN_OR_FUSE + conf_bool(HIN_OR_FUSE) +#endif +#ifdef CONFIG_AUFS_STAT + conf_bool(STAT) +#endif +#ifdef CONFIG_AUFS_DEBUG + conf_bool(DEBUG) +#endif +#ifdef CONFIG_AUFS_MAGIC_SYSRQ + conf_bool(MAGIC_SYSRQ) +#endif +#ifdef CONFIG_AUFS_COMPAT + conf_bool(COMPAT) +#endif +#ifdef CONFIG_AUFS_UNIONFS22_PATCH + conf_bool(UNIONFS22_PATCH) +#endif +#ifdef CONFIG_AUFS_UNIONFS23_PATCH + conf_bool(UNIONFS23_PATCH) +#endif + ; +#undef conf_bool + + char *p = buf; + const char *end = buf + PAGE_SIZE; + + p += snprintf(p, end - p, "%s", opt); +#ifdef DbgUdbaRace + if (p < end) + p += snprintf(p, end - p, "DbgUdbaRace=%d\n", DbgUdbaRace); +#endif + if (p < end) + return p - buf; + else + return -EFBIG; +} + +static struct kobj_attribute au_config_attr = __ATTR_RO(config); +#endif + +#ifdef CONFIG_AUFS_STAT +static ssize_t stat_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + char *p = buf; + const char *end = buf + PAGE_SIZE; + int i; + + p += snprintf(p, end - p, "wkq max_busy:"); + for (i = 0; p < end && i < aufs_nwkq; i++) + p += snprintf(p, end - p, " %u", au_wkq[i].max_busy); + if (p < end) + p += snprintf(p, end - p, ", %u(generic)\n", + au_wkq[aufs_nwkq].max_busy); + + if (p < end) + return p - buf; + else + return -EFBIG; +} + +static struct kobj_attribute au_stat_attr = __ATTR_RO(stat); +#endif + +#ifdef CONFIG_AUFS_DEBUG +static ssize_t debug_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", au_debug_test()); +} + +static ssize_t debug_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t sz) +{ + LKTRTrace("%.*s\n", (unsigned int)sz, buf); + + if (unlikely(!sz || (*buf != '0' && *buf != '1'))) + return -EOPNOTSUPP; + + if (*buf == '0') + au_debug_off(); + else if (*buf == '1') + au_debug_on(); + return sz; +} + +static struct kobj_attribute au_debug_attr = __ATTR(debug, S_IRUGO | S_IWUSR, + debug_show, debug_store); +#endif + +static struct attribute *au_attr[] = { +#ifdef CONFIG_AUFS_LOCAL + &au_config_attr.attr, +#endif +#ifdef CONFIG_AUFS_STAT + &au_stat_attr.attr, +#endif +#ifdef CONFIG_AUFS_DEBUG + &au_debug_attr.attr, +#endif + NULL, /* need to NULL terminate the list of attributes */ +}; + +static struct attribute_group au_attr_group_body = { + .attrs = au_attr +}; + +struct attribute_group *au_attr_group = &au_attr_group_body; + +/* ---------------------------------------------------------------------- */ + +/* + * they are copied from linux/lib/kobject.c, + * and will be exported in the future. + */ +static ssize_t au_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct kobj_attribute *kattr; + ssize_t ret = -EIO; + + kattr = container_of(attr, struct kobj_attribute, attr); + if (kattr->show) + ret = kattr->show(kobj, kattr, buf); + return ret; +} + +#ifdef CONFIG_AUFS_DEBUG +static ssize_t au_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + struct kobj_attribute *kattr; + ssize_t ret = -EIO; + + kattr = container_of(attr, struct kobj_attribute, attr); + if (kattr->store) + ret = kattr->store(kobj, kattr, buf, count); + return ret; +} +#endif + +static struct sysfs_ops sysaufs_ops = { + .show = au_attr_show, +#ifdef CONFIG_AUFS_DEBUG + .store = au_attr_store +#endif +}; + +static struct kobj_type au_ktype_body = { + .sysfs_ops = &sysaufs_ops +}; +struct kobj_type *au_ktype = &au_ktype_body; + +/* ---------------------------------------------------------------------- */ + +static int sysaufs_sbi_xi(struct seq_file *seq, struct file *xf, int dlgt, + int print_path) +{ + int err; + struct kstat st; + struct path path; + + err = vfsub_getattr(xf->f_vfsmnt, xf->f_dentry, &st, dlgt); + if (!err) { + seq_printf(seq, "%llux%lu %lld", + st.blocks, st.blksize, (long long)st.size); + if (unlikely(print_path)) { + path.dentry = xf->f_dentry; + path.mnt = xf->f_vfsmnt; + seq_putc(seq, ' '); + seq_path(seq, &path, au_esc_chars); + } + seq_putc(seq, '\n'); + } else + seq_printf(seq, "err %d\n", err); + + AuTraceErr(err); + return err; +} + +int sysaufs_sbi_xino(struct seq_file *seq, struct super_block *sb) +{ + int err; + unsigned int mnt_flags; + aufs_bindex_t bend, bindex; + unsigned char dlgt, xinodir; + struct kstat st; + struct path path; + struct au_sbinfo *sbinfo; + struct file *xf; + + AuTraceEnter(); + + sbinfo = au_sbi(sb); + mnt_flags = au_mntflags(sb); + xinodir = !!au_opt_test(mnt_flags, XINODIR); + if (unlikely(!au_opt_test_xino(mnt_flags))) { +#ifdef CONFIG_AUFS_DEBUG + AuDebugOn(sbinfo->si_xib); + bend = au_sbend(sb); + for (bindex = 0; bindex <= bend; bindex++) + AuDebugOn(au_sbr(sb, bindex)->br_xino.xi_file); +#endif + err = 0; + goto out; /* success */ + } + + dlgt = !!au_test_dlgt(mnt_flags); + err = sysaufs_sbi_xi(seq, sbinfo->si_xib, dlgt, xinodir); + + bend = au_sbend(sb); + for (bindex = 0; !err && bindex <= bend; bindex++) { + xf = au_sbr(sb, bindex)->br_xino.xi_file; + if (!xf) + continue; + seq_printf(seq, "%d: ", bindex); + err = vfsub_getattr(xf->f_vfsmnt, xf->f_dentry, &st, dlgt); + if (!err) { + seq_printf(seq, "%ld, %llux%lu %lld", + (long)file_count(xf), st.blocks, st.blksize, + (long long)st.size); + if (unlikely(xinodir)) { + path.dentry = xf->f_dentry; + path.mnt = xf->f_vfsmnt; + seq_putc(seq, ' '); + seq_path(seq, &path, au_esc_chars); + } + seq_putc(seq, '\n'); + } else + seq_printf(seq, "err %d\n", err); + } + + out: + AuTraceErr(err); + return err; +} + +#ifdef CONFIG_AUFS_EXPORT +int sysaufs_sbi_xigen(struct seq_file *seq, struct super_block *sb) +{ + int err; + unsigned int mnt_flags; + struct au_sbinfo *sbinfo; + + AuTraceEnter(); + + err = 0; + sbinfo = au_sbi(sb); + mnt_flags = au_mntflags(sb); + if (au_opt_test_xino(mnt_flags)) + err = sysaufs_sbi_xi(seq, sbinfo->si_xigen, + !!au_opt_test(mnt_flags, DLGT), + !!au_opt_test(mnt_flags, XINODIR)); + + AuTraceErr(err); + return err; +} +#endif + +/* + * the lifetime of branch is independent from the entry under sysfs. + * sysfs handles the lifetime of the entry, and never call ->show() after it is + * unlinked. + */ +#define SysaufsBr_PREFIX "br" +static int sysaufs_sbi_br(struct seq_file *seq, struct super_block *sb, + aufs_bindex_t bindex) +{ + int err; + struct dentry *root; + struct au_branch *br; + struct path path; + + LKTRTrace("b%d\n", bindex); + + err = -ENOENT; + if (unlikely(au_sbend(sb) < bindex)) + goto out; + + err = 0; + root = sb->s_root; + di_read_lock_parent(root, !AuLock_IR); + br = au_sbr(sb, bindex); + path.mnt = br->br_mnt; + path.dentry = au_h_dptr(root, bindex); + seq_path(seq, &path, au_esc_chars); + di_read_unlock(root, !AuLock_IR); + seq_printf(seq, "=%s\n", au_optstr_br_perm(br->br_perm)); + + out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static struct seq_file *au_seq(char *p, ssize_t len) +{ + struct seq_file *seq; + + seq = kzalloc(sizeof(*seq), GFP_NOFS); + if (seq) { + /* todo: necessary? */ + /* mutex_init(&seq.lock); */ + seq->buf = p; + seq->size = len; + return seq; /* success */ + } + + seq = ERR_PTR(-ENOMEM); + AuTraceErrPtr(seq); + return seq; +} + +/* todo: file size may exceed PAGE_SIZE */ +ssize_t sysaufs_sbi_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + ssize_t err; + struct au_sbinfo *sbinfo; + struct super_block *sb; + struct seq_file *seq; + char *name; + struct attribute **cattr; + + LKTRTrace("%s/%s\n", kobject_name(kobj), attr->name); + + sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); + sb = sbinfo->si_sb; + si_noflush_read_lock(sb); + + seq = au_seq(buf, PAGE_SIZE); + err = PTR_ERR(seq); + if (IS_ERR(seq)) + goto out; + + name = (void *)attr->name; + cattr = au_sbi_attrs; + while (*cattr) { + if (!strcmp(name, (*cattr)->name)) { + err = container_of(*cattr, struct au_sbi_attr, attr) + ->show(seq, sb); + goto out_seq; + } + cattr++; + } + + if (!strncmp(name, SysaufsBr_PREFIX, sizeof(SysaufsBr_PREFIX) - 1)) { + name += sizeof(SysaufsBr_PREFIX) - 1; + err = sysaufs_sbi_br(seq, sb, simple_strtol(name, NULL, 10)); + goto out_seq; + } + BUG(); + + out_seq: + if (!err) { + err = seq->count; + /* sysfs limit */ + if (unlikely(err == PAGE_SIZE)) + err = -EFBIG; + } + kfree(seq); + out: + si_read_unlock(sb); + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +void sysaufs_br_init(struct au_branch *br) +{ + br->br_attr.name = br->br_name; + br->br_attr.mode = S_IRUGO; + br->br_attr.owner = THIS_MODULE; +} + +void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) +{ + struct au_sbinfo *sbinfo; + aufs_bindex_t bend; + + LKTRTrace("b%d\n", bindex); + + if (!sysaufs_brs) + return; + + sbinfo = au_sbi(sb); + bend = au_sbend(sb); + for (; bindex <= bend; bindex++) + sysfs_remove_file(&sbinfo->si_kobj, + &au_sbr(sb, bindex)->br_attr); +} + +void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) +{ + int err; + struct kobject *kobj; + aufs_bindex_t bend; + struct au_branch *br; + + LKTRTrace("b%d\n", bindex); + + if (!sysaufs_brs) + return; + + kobj = &au_sbi(sb)->si_kobj; + bend = au_sbend(sb); + for (; bindex <= bend; bindex++) { + br = au_sbr(sb, bindex); + snprintf(br->br_name, sizeof(br->br_name), + SysaufsBr_PREFIX "%d", bindex); + err = sysfs_create_file(kobj, &br->br_attr); + if (unlikely(err)) + AuWarn("failed %s under sysfs(%d)\n", br->br_name, err); + } +} --- linux-2.6.27.orig/ubuntu/aufs/misc.c +++ linux-2.6.27/ubuntu/aufs/misc.c @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * $Id: misc.c,v 1.17 2008/09/08 02:40:48 sfjro Exp $ + */ + +#include "aufs.h" + +void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp) +{ + void *q; + + LKTRTrace("p %p, nused %d, sz %d\n", p, nused, new_sz); + AuDebugOn(new_sz <= 0); + if (new_sz <= nused) + return p; + + q = krealloc(p, new_sz, gfp); + if (q) + memset(q + nused, 0, new_sz - nused); + return q; +} + +/* ---------------------------------------------------------------------- */ + +struct nameidata *au_dup_nd(struct au_sbinfo *sbinfo, struct nameidata *dst, + struct nameidata *src) +{ + LKTRTrace("src %p\n", src); + + if (src) { + *dst = *src; + dst->flags &= ~LOOKUP_PARENT; + if (sbinfo->si_wbr_create == AuWbrCreate_TDP) { + if ((dst->flags & LOOKUP_CREATE) + && !(dst->intent.open.flags & O_CREAT)) + dst->flags &= ~LOOKUP_CREATE; + } else { + dst->flags &= ~LOOKUP_CREATE; + dst->intent.open.flags &= ~O_CREAT; + } + } else + dst = NULL; + + return dst; +} + +struct nameidata *au_fake_dm(struct nameidata *fake_nd, struct nameidata *nd, + struct super_block *sb, aufs_bindex_t bindex) +{ + LKTRTrace("nd %p, b%d\n", nd, bindex); + + if (!nd) + return NULL; + + DiMustAnyLock(nd->path.dentry); + + fake_nd->path.dentry = NULL; + fake_nd->path.mnt = NULL; + + if (bindex <= au_dbend(nd->path.dentry)) + fake_nd->path.dentry = au_h_dptr(nd->path.dentry, bindex); + if (fake_nd->path.dentry) { + fake_nd->path.mnt = au_sbr_mnt(sb, bindex); + AuDebugOn(!fake_nd->path.mnt); + path_get(&fake_nd->path); + } else + fake_nd = ERR_PTR(-ENOENT); + + AuTraceErrPtr(fake_nd); + return fake_nd; +} + +void au_fake_dm_release(struct nameidata *fake_nd) +{ + if (fake_nd) + path_put(&fake_nd->path); +} + +int au_h_create(struct inode *h_dir, struct dentry *h_dentry, int mode, + struct vfsub_args *vargs, struct nameidata *nd, + struct vfsmount *nfsmnt) +{ + int err; + + LKTRTrace("hi%lu, %.*s, 0%o, nd %d, nfsmnt %d\n", + h_dir->i_ino, AuDLNPair(h_dentry), mode, !!nd, !!nfsmnt); + + err = -ENOSYS; + if (!nfsmnt) + err = vfsub_create(h_dir, h_dentry, mode, /*nd*/NULL, vargs); + else { + struct nameidata fake_nd; + + if (nd) + fake_nd = *nd; + else + memset(&fake_nd, 0, sizeof(fake_nd)); + fake_nd.path.dentry = h_dentry; + fake_nd.path.mnt = nfsmnt; + path_get(&fake_nd.path); + fake_nd.flags = LOOKUP_CREATE; + fake_nd.intent.open.flags = O_CREAT | FMODE_READ; + fake_nd.intent.open.create_mode = mode; + + err = vfsub_create(h_dir, h_dentry, mode, &fake_nd, vargs); + path_put(&fake_nd.path); + } + + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +int au_copy_file(struct file *dst, struct file *src, loff_t len, + struct au_hinode *hdir, struct super_block *sb, + struct vfsub_args *vargs) +{ + int err, all_zero, do_kfree; + unsigned long blksize; + char *buf, *zp; + /* reduce stack usage */ + struct iattr *ia; + + LKTRTrace("%.*s, %.*s\n", + AuDLNPair(dst->f_dentry), AuDLNPair(src->f_dentry)); + AuDebugOn(!(dst->f_mode & FMODE_WRITE)); +#ifdef CONFIG_AUFS_DEBUG + { + struct dentry *parent; + parent = dget_parent(dst->f_dentry); + IMustLock(parent->d_inode); + dput(parent); + } +#endif + + err = -ENOMEM; + blksize = dst->f_dentry->d_sb->s_blocksize; + if (!blksize || PAGE_SIZE < blksize) + blksize = PAGE_SIZE; + LKTRTrace("blksize %lu\n", blksize); + /* todo: use ZERO_PAGE(0) */ + BUILD_BUG_ON(KMALLOC_MAX_SIZE < 128 << 10); + do_kfree = 1; + if (blksize <= 64 << 10 && blksize * 2 >= sizeof(*ia)) { + buf = kmalloc(blksize * 2, GFP_NOFS); + if (unlikely(!buf)) + goto out; + zp = buf + blksize; + memset(zp, 0, blksize); + } else { + BUILD_BUG_ON(PAGE_SIZE * 2 < sizeof(*ia)); +#if 0 + buf = (void *)__get_free_pages(GFP_NOFS, 1); + zp = buf + PAGE_SIZE; +#endif + do_kfree = 0; + buf = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!buf)) + goto out; + zp = (void *)get_zeroed_page(GFP_NOFS); + if (unlikely(!zp)) + goto out_buf; + } + +#ifdef CONFIG_AUFS_DEBUG + if (len > (1 << 22)) + AuWarn("copying a large file %lld\n", (long long)len); +#endif + err = 0; + all_zero = 0; + src->f_pos = 0; + dst->f_pos = 0; + while (len) { + size_t sz, rbytes, wbytes; + char *p; + + LKTRTrace("len %lld\n", len); + sz = blksize; + if (len < blksize) + sz = len; + + /* support LSM and notify */ + rbytes = 0; + /* todo: signal_pending? */ + while (!rbytes || err == -EAGAIN || err == -EINTR) { + rbytes = vfsub_read_k(src, buf, sz, &src->f_pos, + vfsub_ftest(vargs->flags, DLGT)); + err = rbytes; + } + if (unlikely(err < 0)) + break; + + all_zero = 0; + if (len >= rbytes && rbytes == blksize) { +#if 1 + all_zero = !memcmp(buf, zp, rbytes); +#else /* reserved for future use */ + unsigned long long *ullp; + size_t n, i; + + all_zero = 1; + ullp = (void *)buf; + n = rbytes / sizeof(*ullp); + i = n; + while (n-- > 0 && all_zero) + all_zero = !*ullp++; + p = (void *)ullp; + i *= sizeof(*ullp); + for (; all_zero && i < rbytes; i++) + all_zero = !*p++; +#endif + } + if (!all_zero) { + wbytes = rbytes; + p = buf; + while (wbytes) { + size_t b; + /* support LSM and notify */ + vfsub_args_reinit(vargs); + vfsub_ign_hinode(vargs, IN_MODIFY, hdir); + b = vfsub_write_k(dst, p, wbytes, &dst->f_pos, + vargs); + err = b; + /* todo: signal_pending? */ + if (unlikely(err == -EAGAIN || err == -EINTR)) + continue; + if (unlikely(err < 0)) + break; + wbytes -= b; + p += b; + } + } else { + loff_t res; + LKTRLabel(hole); + res = vfsub_llseek(dst, rbytes, SEEK_CUR); + err = res; + if (unlikely(res < 0)) + break; + } + len -= rbytes; + err = 0; + } + + /* the last block may be a hole */ + if (unlikely(!err && all_zero)) { + struct dentry *h_d = dst->f_dentry; + struct inode *h_i = h_d->d_inode; + + LKTRLabel(last hole); + do { + /* todo: signal_pending? */ + vfsub_args_reinit(vargs); + vfsub_ign_hinode(vargs, IN_MODIFY, hdir); + err = vfsub_write_k(dst, "\0", 1, &dst->f_pos, vargs); + } while (err == -EAGAIN || err == -EINTR); + if (err == 1) { + ia = (void *)buf; + ia->ia_size = dst->f_pos; + ia->ia_valid = ATTR_SIZE | ATTR_FILE; + ia->ia_file = dst; + vfsub_args_reinit(vargs); + vfsub_ign_hinode(vargs, vfsub_events_notify_change(ia), + hdir); + mutex_lock_nested(&h_i->i_mutex, AuLsc_I_CHILD2); + err = vfsub_notify_change(h_d, ia, vargs); + mutex_unlock(&h_i->i_mutex); + } + } + if (do_kfree) + kfree(buf); + else + free_page((unsigned long)zp); + + out_buf: + if (unlikely(!do_kfree)) + free_page((unsigned long)buf); + out: + AuTraceErr(err); + return err; +} --- linux-2.6.27.orig/ubuntu/aufs/opts.c +++ linux-2.6.27/ubuntu/aufs/opts.c @@ -0,0 +1,1570 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * mount options/flags + * + * $Id: opts.c,v 1.15 2008/09/01 02:55:31 sfjro Exp $ + */ + +#include /* a distribution requires */ +#include +#include "aufs.h" + +/* ---------------------------------------------------------------------- */ + +enum { + Opt_br, + Opt_add, Opt_del, Opt_mod, Opt_reorder, Opt_append, Opt_prepend, + Opt_idel, Opt_imod, Opt_ireorder, + Opt_dirwh, Opt_rdcache, Opt_deblk, Opt_nhash, Opt_rendir, + Opt_xino, Opt_zxino, Opt_noxino, + Opt_trunc_xino, Opt_trunc_xino_v, Opt_notrunc_xino, + Opt_trunc_xino_path, Opt_itrunc_xino, + Opt_xinodir, + Opt_trunc_xib, Opt_notrunc_xib, + Opt_dirperm1, Opt_nodirperm1, + Opt_shwh, Opt_noshwh, + Opt_plink, Opt_noplink, Opt_list_plink, Opt_clean_plink, + Opt_udba, + /* Opt_lock, Opt_unlock, */ + Opt_cmd, Opt_cmd_args, + Opt_diropq_a, Opt_diropq_w, + Opt_warn_perm, Opt_nowarn_perm, + Opt_wbr_copyup, Opt_wbr_create, + Opt_coo, + Opt_dlgt, Opt_nodlgt, + Opt_refrof, Opt_norefrof, + Opt_verbose, Opt_noverbose, + Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err +}; + +static match_table_t options = { + {Opt_br, "br=%s"}, + {Opt_br, "br:%s"}, + + {Opt_add, "add=%d:%s"}, + {Opt_add, "add:%d:%s"}, + {Opt_add, "ins=%d:%s"}, + {Opt_add, "ins:%d:%s"}, + {Opt_append, "append=%s"}, + {Opt_append, "append:%s"}, + {Opt_prepend, "prepend=%s"}, + {Opt_prepend, "prepend:%s"}, + + {Opt_del, "del=%s"}, + {Opt_del, "del:%s"}, + /* {Opt_idel, "idel:%d"}, */ + {Opt_mod, "mod=%s"}, + {Opt_mod, "mod:%s"}, + {Opt_imod, "imod:%d:%s"}, + + {Opt_dirwh, "dirwh=%d"}, + {Opt_dirwh, "dirwh:%d"}, + + {Opt_xino, "xino=%s"}, + {Opt_xino, "xino:%s"}, +#if 0 /* def CONFIG_AUFS_EXPORT */ /* reserved for futur use */ + {Opt_xinodir, "xinodir=%s"}, + {Opt_xinodir, "xinodir:%s"}, +#endif + {Opt_noxino, "noxino"}, + {Opt_trunc_xino, "trunc_xino"}, + {Opt_trunc_xino_v, "trunc_xino_v=%d:%d"}, + {Opt_notrunc_xino, "notrunc_xino"}, + {Opt_trunc_xino_path, "trunc_xino=%s"}, + {Opt_trunc_xino_path, "trunc_xino:%s"}, + {Opt_itrunc_xino, "itrunc_xino=%d"}, + {Opt_itrunc_xino, "itrunc_xino:%d"}, + /* {Opt_zxino, "zxino=%s"}, */ + {Opt_trunc_xib, "trunc_xib"}, + {Opt_notrunc_xib, "notrunc_xib"}, + + {Opt_plink, "plink"}, + {Opt_noplink, "noplink"}, +#ifdef CONFIG_AUFS_DEBUG + {Opt_list_plink, "list_plink"}, +#endif + {Opt_clean_plink, "clean_plink"}, + + {Opt_udba, "udba=%s"}, + + {Opt_diropq_a, "diropq=always"}, + {Opt_diropq_a, "diropq=a"}, + {Opt_diropq_w, "diropq=whiteouted"}, + {Opt_diropq_w, "diropq=w"}, + + {Opt_warn_perm, "warn_perm"}, + {Opt_nowarn_perm, "nowarn_perm"}, + +#ifdef CONFIG_AUFS_DLGT + {Opt_dlgt, "dlgt"}, + {Opt_nodlgt, "nodlgt"}, + + {Opt_dirperm1, "dirperm1"}, + {Opt_nodirperm1, "nodirperm1"}, +#endif + +#ifdef CONFIG_AUFS_SHWH + {Opt_shwh, "shwh"}, + {Opt_noshwh, "noshwh"}, +#endif + + {Opt_rendir, "rendir=%d"}, + {Opt_rendir, "rendir:%d"}, + + {Opt_refrof, "refrof"}, + {Opt_norefrof, "norefrof"}, + + {Opt_verbose, "verbose"}, + {Opt_verbose, "v"}, + {Opt_noverbose, "noverbose"}, + {Opt_noverbose, "quiet"}, + {Opt_noverbose, "q"}, + {Opt_noverbose, "silent"}, + + {Opt_rdcache, "rdcache=%d"}, + {Opt_rdcache, "rdcache:%d"}, + + {Opt_coo, "coo=%s"}, + + {Opt_wbr_create, "create=%s"}, + {Opt_wbr_create, "create:%s"}, + {Opt_wbr_create, "create_policy=%s"}, + {Opt_wbr_create, "create_policy:%s"}, + {Opt_wbr_copyup, "cpup=%s"}, + {Opt_wbr_copyup, "cpup:%s"}, + {Opt_wbr_copyup, "copyup=%s"}, + {Opt_wbr_copyup, "copyup:%s"}, + {Opt_wbr_copyup, "copyup_policy=%s"}, + {Opt_wbr_copyup, "copyup_policy:%s"}, + + /* internal use for the scripts */ + {Opt_ignore_silent, "si=%s"}, + +#if 0 /* reserved for future use */ + {Opt_deblk, "deblk=%d"}, + {Opt_deblk, "deblk:%d"}, + {Opt_nhash, "nhash=%d"}, + {Opt_nhash, "nhash:%d"}, +#endif + + {Opt_br, "dirs=%s"}, + {Opt_ignore, "debug=%d"}, + {Opt_ignore, "delete=whiteout"}, + {Opt_ignore, "delete=all"}, + {Opt_ignore, "imap=%s"}, + + {Opt_err, NULL} +}; + +/* ---------------------------------------------------------------------- */ + +static const char *au_parser_pattern(int val, struct match_token *token) +{ + while (token->pattern) { + if (token->token == val) + return token->pattern; + token++; + } + BUG(); + return "??"; +} + +/* ---------------------------------------------------------------------- */ + +#define RW "rw" +#define RO "ro" +#define WH "wh" +#define RR "rr" +#define NoLinkWH "nolwh" + +static match_table_t brperms = { + {AuBrPerm_RR, RR}, + {AuBrPerm_RO, RO}, + {AuBrPerm_RW, RW}, + + {AuBrPerm_RRWH, RR "+" WH}, + {AuBrPerm_ROWH, RO "+" WH}, + {AuBrPerm_RWNoLinkWH, RW "+" NoLinkWH}, + + {AuBrPerm_ROWH, "nfsro"}, + {AuBrPerm_RO, NULL} +}; + +static noinline_for_stack int br_perm_val(char *perm) +{ + int val; + substring_t args[MAX_OPT_ARGS]; + + AuDebugOn(!perm || !*perm); + LKTRTrace("perm %s\n", perm); + val = match_token(perm, brperms, args); + AuTraceErr(val); + return val; +} + +const char *au_optstr_br_perm(int brperm) +{ + return au_parser_pattern(brperm, (void *)brperms); +} + +/* ---------------------------------------------------------------------- */ + +static match_table_t udbalevel = { + {AuOpt_UDBA_REVAL, "reval"}, +#ifdef CONFIG_AUFS_HINOTIFY + {AuOpt_UDBA_INOTIFY, "inotify"}, +#endif + {AuOpt_UDBA_NONE, "none"}, + {-1, NULL} +}; + +static noinline_for_stack int udba_val(char *str) +{ + substring_t args[MAX_OPT_ARGS]; + return match_token(str, udbalevel, args); +} + +const char *au_optstr_udba(int udba) +{ + return au_parser_pattern(udba, (void *)udbalevel); +} + +/* ---------------------------------------------------------------------- */ + +static match_table_t coolevel = { + {AuOpt_COO_NONE, "none"}, + {AuOpt_COO_LEAF, "leaf"}, + {AuOpt_COO_ALL, "all"}, + {-1, NULL} +}; + +static noinline_for_stack int coo_val(char *str) +{ + substring_t args[MAX_OPT_ARGS]; + return match_token(str, coolevel, args); +} + +const char *au_optstr_coo(int coo) +{ + return au_parser_pattern(coo, (void *)coolevel); +} + +/* ---------------------------------------------------------------------- */ + +static match_table_t au_wbr_create_policy = { + {AuWbrCreate_TDP, "tdp"}, + {AuWbrCreate_TDP, "top-down-parent"}, + {AuWbrCreate_RR, "rr"}, + {AuWbrCreate_RR, "round-robin"}, + {AuWbrCreate_MFS, "mfs"}, + {AuWbrCreate_MFS, "most-free-space"}, + {AuWbrCreate_MFSV, "mfs:%d"}, + {AuWbrCreate_MFSV, "most-free-space:%d"}, + + {AuWbrCreate_MFSRR, "mfsrr:%d"}, + {AuWbrCreate_MFSRRV, "mfsrr:%d:%d"}, + {AuWbrCreate_PMFS, "pmfs"}, + {AuWbrCreate_PMFSV, "pmfs:%d"}, + + {-1, NULL} +}; + +/* cf. linux/lib/parser.c */ +static int au_match_ull(substring_t *s, unsigned long long *result, int base) +{ + char *endp; + char *buf; + int ret; + + buf = kmalloc(s->to - s->from + 1, GFP_NOFS); + if (!buf) + return -ENOMEM; + memcpy(buf, s->from, s->to - s->from); + buf[s->to - s->from] = '\0'; + *result = simple_strtoull(buf, &endp, base); + ret = 0; + if (endp == buf) + ret = -EINVAL; + kfree(buf); + return ret; +} + +static int au_wbr_mfs_wmark(substring_t *arg, char *str, + struct au_opt_wbr_create *create) +{ + int err; + unsigned long long ull; + + err = 0; + if (!au_match_ull(arg, &ull, 0)) + create->mfsrr_watermark = ull; + else { + AuErr("bad integer in %s\n", str); + err = -EINVAL; + } + + AuTraceErr(err); + return err; +} + +static int au_wbr_mfs_sec(substring_t *arg, char *str, + struct au_opt_wbr_create *create) +{ + int n, err; + + err = 0; + if (!match_int(arg, &n) && 0 <= n) + create->mfs_second = n; + else { + AuErr("bad integer in %s\n", str); + err = -EINVAL; + } + + AuTraceErr(err); + return err; +} + +static noinline_for_stack +int au_wbr_create_val(char *str, struct au_opt_wbr_create *create) +{ + int err, e; + substring_t args[MAX_OPT_ARGS]; + + err = match_token(str, au_wbr_create_policy, args); + create->wbr_create = err; + switch (err) { + case AuWbrCreate_MFSRRV: + e = au_wbr_mfs_wmark(&args[0], str, create); + if (!e) + e = au_wbr_mfs_sec(&args[1], str, create); + if (unlikely(e)) + err = e; + break; + case AuWbrCreate_MFSRR: + e = au_wbr_mfs_wmark(&args[0], str, create); + if (unlikely(e)) { + err = e; + break; + } + /*FALLTHROUGH*/ + case AuWbrCreate_MFS: + case AuWbrCreate_PMFS: + create->mfs_second = AUFS_MFS_SECOND_DEF; + break; + case AuWbrCreate_MFSV: + case AuWbrCreate_PMFSV: + e = au_wbr_mfs_sec(&args[0], str, create); + if (unlikely(e)) + err = e; + break; + } + + return err; +} + +const char *au_optstr_wbr_create(int wbr_create) +{ + return au_parser_pattern(wbr_create, (void *)au_wbr_create_policy); +} + +static match_table_t au_wbr_copyup_policy = { + {AuWbrCopyup_TDP, "tdp"}, + {AuWbrCopyup_TDP, "top-down-parent"}, + {AuWbrCopyup_BUP, "bup"}, + {AuWbrCopyup_BUP, "bottom-up-parent"}, + {AuWbrCopyup_BU, "bu"}, + {AuWbrCopyup_BU, "bottom-up"}, + {-1, NULL} +}; + +static noinline_for_stack int au_wbr_copyup_val(char *str) +{ + substring_t args[MAX_OPT_ARGS]; + return match_token(str, au_wbr_copyup_policy, args); +} + +const char *au_optstr_wbr_copyup(int wbr_copyup) +{ + return au_parser_pattern(wbr_copyup, (void *)au_wbr_copyup_policy); +} + +/* ---------------------------------------------------------------------- */ + +static const int lkup_dirflags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; + +static void dump_opts(struct au_opts *opts) +{ +#ifdef CONFIG_AUFS_DEBUG + /* reduce stack space */ + union { + struct au_opt_add *add; + struct au_opt_del *del; + struct au_opt_mod *mod; + struct au_opt_xino *xino; + struct au_opt_xinodir *xinodir; + struct au_opt_xino_itrunc *xino_itrunc; + struct au_opt_wbr_create *create; + } u; + struct au_opt *opt; + + AuTraceEnter(); + + opt = opts->opt; + while (/* opt < opts_tail && */ opt->type != Opt_tail) { + switch (opt->type) { + case Opt_add: + u.add = &opt->add; + LKTRTrace("add {b%d, %s, 0x%x, %p}\n", + u.add->bindex, u.add->path, u.add->perm, + u.add->nd.path.dentry); + break; + case Opt_del: + case Opt_idel: + u.del = &opt->del; + LKTRTrace("del {%s, %p}\n", u.del->path, u.del->h_root); + break; + case Opt_mod: + case Opt_imod: + u.mod = &opt->mod; + LKTRTrace("mod {%s, 0x%x, %p}\n", + u.mod->path, u.mod->perm, u.mod->h_root); + break; + case Opt_append: + u.add = &opt->add; + LKTRTrace("append {b%d, %s, 0x%x, %p}\n", + u.add->bindex, u.add->path, u.add->perm, + u.add->nd.path.dentry); + break; + case Opt_prepend: + u.add = &opt->add; + LKTRTrace("prepend {b%d, %s, 0x%x, %p}\n", + u.add->bindex, u.add->path, u.add->perm, + u.add->nd.path.dentry); + break; + case Opt_dirwh: + LKTRTrace("dirwh %d\n", opt->dirwh); + break; + case Opt_rdcache: + LKTRTrace("rdcache %d\n", opt->rdcache); + break; + case Opt_xino: + u.xino = &opt->xino; + LKTRTrace("xino {%s %.*s}\n", + u.xino->path, + AuDLNPair(u.xino->file->f_dentry)); + break; + case Opt_xinodir: + u.xinodir = &opt->xinodir; + LKTRTrace("xinodir {%s %.*s}\n", + u.xinodir->name, + AuDLNPair(u.xinodir->path.dentry)); + break; + case Opt_trunc_xino: + LKTRLabel(trunc_xino); + break; + case Opt_notrunc_xino: + LKTRLabel(notrunc_xino); + break; + case Opt_trunc_xino_path: + case Opt_itrunc_xino: + u.xino_itrunc = &opt->xino_itrunc; + LKTRTrace("trunc_xino %d\n", u.xino_itrunc->bindex); + break; + + case Opt_noxino: + LKTRLabel(noxino); + break; + case Opt_trunc_xib: + LKTRLabel(trunc_xib); + break; + case Opt_notrunc_xib: + LKTRLabel(notrunc_xib); + break; + case Opt_dirperm1: + LKTRLabel(dirperm1); + break; + case Opt_nodirperm1: + LKTRLabel(nodirperm1); + break; + case Opt_shwh: + LKTRLabel(shwh); + break; + case Opt_noshwh: + LKTRLabel(noshwh); + break; + case Opt_plink: + LKTRLabel(plink); + break; + case Opt_noplink: + LKTRLabel(noplink); + break; + case Opt_list_plink: + LKTRLabel(list_plink); + break; + case Opt_clean_plink: + LKTRLabel(clean_plink); + break; + case Opt_udba: + LKTRTrace("udba %d, %s\n", + opt->udba, au_optstr_udba(opt->udba)); + break; + case Opt_diropq_a: + LKTRLabel(diropq_a); + break; + case Opt_diropq_w: + LKTRLabel(diropq_w); + break; + case Opt_warn_perm: + LKTRLabel(warn_perm); + break; + case Opt_nowarn_perm: + LKTRLabel(nowarn_perm); + break; + case Opt_dlgt: + LKTRLabel(dlgt); + break; + case Opt_nodlgt: + LKTRLabel(nodlgt); + break; + case Opt_refrof: + LKTRLabel(refrof); + break; + case Opt_norefrof: + LKTRLabel(norefrof); + break; + case Opt_verbose: + LKTRLabel(verbose); + break; + case Opt_noverbose: + LKTRLabel(noverbose); + break; + case Opt_coo: + LKTRTrace("coo %d, %s\n", + opt->coo, au_optstr_coo(opt->coo)); + break; + case Opt_wbr_create: + u.create = &opt->wbr_create; + LKTRTrace("create %d, %s\n", u.create->wbr_create, + au_optstr_wbr_create(u.create->wbr_create)); + switch (u.create->wbr_create) { + case AuWbrCreate_MFSV: + case AuWbrCreate_PMFSV: + LKTRTrace("%d sec\n", u.create->mfs_second); + break; + case AuWbrCreate_MFSRR: + LKTRTrace("%llu watermark\n", + u.create->mfsrr_watermark); + break; + case AuWbrCreate_MFSRRV: + LKTRTrace("%llu watermark, %d sec\n", + u.create->mfsrr_watermark, + u.create->mfs_second); + break; + } + break; + case Opt_wbr_copyup: + LKTRTrace("copyup %d, %s\n", opt->wbr_copyup, + au_optstr_wbr_copyup(opt->wbr_copyup)); + break; + default: + BUG(); + } + opt++; + } +#endif +} + +void au_opts_free(struct au_opts *opts) +{ + struct au_opt *opt; + + AuTraceEnter(); + + opt = opts->opt; + while (opt->type != Opt_tail) { + switch (opt->type) { + case Opt_add: + case Opt_append: + case Opt_prepend: + path_put(&opt->add.nd.path); + break; + case Opt_del: + case Opt_idel: + dput(opt->del.h_root); + break; + case Opt_mod: + case Opt_imod: + dput(opt->mod.h_root); + break; + case Opt_xino: + fput(opt->xino.file); + break; + case Opt_xinodir: + path_put(&opt->xinodir.path); + break; + } + opt++; + } +} + +static int opt_add(struct au_opt *opt, char *opt_str, struct super_block *sb, + aufs_bindex_t bindex) +{ + int err; + struct au_opt_add *add = &opt->add; + char *p; + + LKTRTrace("%s, b%d\n", opt_str, bindex); + + add->bindex = bindex; + add->perm = AuBrPerm_Last; + add->path = opt_str; + p = strchr(opt_str, '='); + if (unlikely(p)) { + *p++ = 0; + if (*p) + add->perm = br_perm_val(p); + } + + /* LSM may detect it */ + /* do not superio. */ + err = vfsub_path_lookup(add->path, lkup_dirflags, &add->nd); + if (!err) { + if (!p /* && add->perm == AuBrPerm_Last */) { + add->perm = AuBrPerm_RO; + if (au_test_def_rr(add->nd.path.dentry->d_sb)) + add->perm = AuBrPerm_RR; + if (!bindex && !(sb->s_flags & MS_RDONLY)) + add->perm = AuBrPerm_RW; +#ifdef CONFIG_AUFS_COMPAT + add->perm = AuBrPerm_RW; +#endif + } + opt->type = Opt_add; + goto out; + } + AuErr("lookup failed %s (%d)\n", add->path, err); + err = -EINVAL; + + out: + AuTraceErr(err); + return err; +} + +/* called without aufs lock */ +int au_opts_parse(struct super_block *sb, unsigned long flags, char *str, + struct au_opts *opts) +{ + int err, n, token; + struct dentry *root; + struct au_opt *opt, *opt_tail; + char *opt_str, *p; + aufs_bindex_t bindex, bend; + unsigned char skipped; + union { + struct au_opt_del *del; + struct au_opt_mod *mod; + struct au_opt_xino *xino; + struct au_opt_xinodir *xinodir; + struct au_opt_xino_itrunc *xino_itrunc; + struct au_opt_wbr_create *create; + } u; + struct file *file; + /* reduce the stack space */ + struct { + substring_t args[MAX_OPT_ARGS]; + struct nameidata nd; + } *a; + + LKTRTrace("%s, nopts %d\n", str, opts->max_opt); + + err = -ENOMEM; + a = kmalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + + root = sb->s_root; + err = 0; + bindex = 0; + opt = opts->opt; + opt_tail = opt + opts->max_opt - 1; + opt->type = Opt_tail; + while (!err && (opt_str = strsep(&str, ",")) && *opt_str) { + err = -EINVAL; + token = match_token(opt_str, options, a->args); + LKTRTrace("%s, token %d, a->args[0]{%p, %p}\n", + opt_str, token, a->args[0].from, a->args[0].to); + + skipped = 0; + switch (token) { + case Opt_br: + err = 0; + while (!err && (opt_str = strsep(&a->args[0].from, ":")) + && *opt_str) { + err = opt_add(opt, opt_str, sb, bindex++); + if (unlikely(!err && ++opt > opt_tail)) { + err = -E2BIG; + break; + } + opt->type = Opt_tail; + skipped = 1; + } + break; + case Opt_add: + if (unlikely(match_int(&a->args[0], &n))) { + AuErr("bad integer in %s\n", opt_str); + break; + } + bindex = n; + err = opt_add(opt, a->args[1].from, sb, bindex); + break; + case Opt_append: + err = opt_add(opt, a->args[0].from, sb, + /*dummy bindex*/1); + if (!err) + opt->type = token; + break; + case Opt_prepend: + err = opt_add(opt, a->args[0].from, sb, /*bindex*/0); + if (!err) + opt->type = token; + break; + case Opt_del: + u.del = &opt->del; + u.del->path = a->args[0].from; + LKTRTrace("del path %s\n", u.del->path); + /* LSM may detect it */ + /* do not superio. */ + err = vfsub_path_lookup(u.del->path, lkup_dirflags, + &a->nd); + if (unlikely(err)) { + AuErr("lookup failed %s (%d)\n", + u.del->path, err); + break; + } + u.del->h_root = dget(a->nd.path.dentry); + path_put(&a->nd.path); + opt->type = token; + break; +#if 0 /* reserved for future use */ + case Opt_idel: + u.del = &opt->del; + u.del->path = "(indexed)"; + if (unlikely(match_int(&a->args[0], &n))) { + AuErr("bad integer in %s\n", opt_str); + break; + } + bindex = n; + aufs_read_lock(root, AuLock_FLUSH); + if (bindex < 0 || au_sbend(sb) < bindex) { + AuErr("out of bounds, %d\n", bindex); + aufs_read_unlock(root, !AuLock_IR); + break; + } + err = 0; + u.del->h_root = dget(au_h_dptr(root, bindex)); + opt->type = token; + aufs_read_unlock(root, !AuLock_IR); + break; +#endif + case Opt_mod: + u.mod = &opt->mod; + u.mod->path = a->args[0].from; + p = strchr(u.mod->path, '='); + if (unlikely(!p)) { + AuErr("no permssion %s\n", opt_str); + break; + } + *p++ = 0; + u.mod->perm = br_perm_val(p); + LKTRTrace("mod path %s, perm 0x%x, %s\n", + u.mod->path, u.mod->perm, p); + /* LSM may detect it */ + /* do not superio. */ + err = vfsub_path_lookup(u.mod->path, lkup_dirflags, + &a->nd); + if (unlikely(err)) { + AuErr("lookup failed %s (%d)\n", + u.mod->path, err); + break; + } + u.mod->h_root = dget(a->nd.path.dentry); + path_put(&a->nd.path); + opt->type = token; + break; +#ifdef IMOD /* reserved for future use */ + case Opt_imod: + u.mod = &opt->mod; + u.mod->path = "(indexed)"; + if (unlikely(match_int(&a->args[0], &n))) { + AuErr("bad integer in %s\n", opt_str); + break; + } + bindex = n; + aufs_read_lock(root, AuLock_FLUSH); + if (bindex < 0 || au_sbend(sb) < bindex) { + AuErr("out of bounds, %d\n", bindex); + aufs_read_unlock(root, !AuLock_IR); + break; + } + u.mod->perm = br_perm_val(a->args[1].from); + LKTRTrace("mod path %s, perm 0x%x, %s\n", + u.mod->path, u.mod->perm, a->args[1].from); + err = 0; + u.mod->h_root = dget(au_h_dptr(root, bindex)); + opt->type = token; + aufs_read_unlock(root, !AuLock_IR); + break; +#endif + case Opt_xino: + u.xino = &opt->xino; + file = au_xino_create(sb, a->args[0].from, /*silent*/0); + err = PTR_ERR(file); + if (IS_ERR(file)) + break; + err = -EINVAL; + if (unlikely(file->f_dentry->d_sb == sb)) { + fput(file); + AuErr("%s must be outside\n", a->args[0].from); + break; + } + err = 0; + u.xino->file = file; + u.xino->path = a->args[0].from; + opt->type = token; + break; + +#if 0 /* def CONFIG_AUFS_EXPORT */ /* reserved for futur use */ + case Opt_xinodir: + u.xinodir = &opt->xinodir; + u.xinodir->name = a->args[0].from; + err = vfsub_path_lookup(u.xinodir->name, lkup_dirflags, + &a->nd); + if (unlikely(err)) { + AuErr("lookup failed %s (%d)\n", + u.xinodir->name, err); + break; + } + u.xinodir->path = a->nd.path; + /* do not path_put() */ + opt->type = token; + break; +#endif + + case Opt_trunc_xino_path: + u.xino_itrunc = &opt->xino_itrunc; + p = a->args[0].from; + LKTRTrace("trunc_xino path %s\n", p); + /* LSM may detect it */ + /* do not superio. */ + err = vfsub_path_lookup(p, lkup_dirflags, &a->nd); + if (unlikely(err)) { + AuErr("lookup failed %s (%d)\n", p , err); + break; + } + u.xino_itrunc->bindex = -1; + aufs_read_lock(root, AuLock_FLUSH); + bend = au_sbend(sb); + for (bindex = 0; bindex <= bend; bindex++) { + if (au_h_dptr(root, bindex) + == a->nd.path.dentry) { + u.xino_itrunc->bindex = bindex; + break; + } + } + aufs_read_unlock(root, !AuLock_IR); + path_put(&a->nd.path); + if (unlikely(u.xino_itrunc->bindex < 0)) { + AuErr("no such branch %s\n", p); + err = -EINVAL; + break; + } + opt->type = token; + break; + + case Opt_itrunc_xino: + u.xino_itrunc = &opt->xino_itrunc; + if (unlikely(match_int(&a->args[0], &n))) { + AuErr("bad integer in %s\n", opt_str); + break; + } + u.xino_itrunc->bindex = n; + aufs_read_lock(root, AuLock_FLUSH); + if (n < 0 || au_sbend(sb) < n) { + AuErr("out of bounds, %d\n", n); + aufs_read_unlock(root, !AuLock_IR); + break; + } + aufs_read_unlock(root, !AuLock_IR); + err = 0; + opt->type = token; + break; + + case Opt_dirwh: + if (unlikely(match_int(&a->args[0], &opt->dirwh))) + break; + err = 0; + opt->type = token; + break; + + case Opt_rdcache: + if (unlikely(match_int(&a->args[0], &opt->rdcache))) + break; + err = 0; + opt->type = token; + break; + + case Opt_shwh: + if (flags & MS_RDONLY) { + err = 0; + opt->type = token; + } else + AuErr("shwh requires ro\n"); + break; + + case Opt_trunc_xino: + case Opt_notrunc_xino: + case Opt_noxino: + case Opt_trunc_xib: + case Opt_notrunc_xib: + case Opt_dirperm1: + case Opt_nodirperm1: + case Opt_noshwh: + case Opt_plink: + case Opt_noplink: + case Opt_list_plink: + case Opt_clean_plink: + case Opt_diropq_a: + case Opt_diropq_w: + case Opt_warn_perm: + case Opt_nowarn_perm: + case Opt_dlgt: + case Opt_nodlgt: + case Opt_refrof: + case Opt_norefrof: + case Opt_verbose: + case Opt_noverbose: + err = 0; + opt->type = token; + break; + + case Opt_udba: + opt->udba = udba_val(a->args[0].from); + if (opt->udba >= 0) { + err = 0; + opt->type = token; + } else + AuErr("wrong value, %s\n", opt_str); + break; + + case Opt_wbr_create: + u.create = &opt->wbr_create; + u.create->wbr_create + = au_wbr_create_val(a->args[0].from, u.create); + if (u.create->wbr_create >= 0) { + err = 0; + opt->type = token; + } else + AuErr("wrong value, %s\n", opt_str); + break; + case Opt_wbr_copyup: + opt->wbr_copyup = au_wbr_copyup_val(a->args[0].from); + if (opt->wbr_copyup >= 0) { + err = 0; + opt->type = token; + } else + AuErr("wrong value, %s\n", opt_str); + break; + + case Opt_coo: + opt->coo = coo_val(a->args[0].from); + if (opt->coo >= 0) { + err = 0; + opt->type = token; + } else + AuErr("wrong value, %s\n", opt_str); + break; + + case Opt_ignore: +#ifndef CONFIG_AUFS_COMPAT + AuWarn("ignored %s\n", opt_str); +#endif + case Opt_ignore_silent: + skipped = 1; + err = 0; + break; + case Opt_err: + AuErr("unknown option %s\n", opt_str); + break; + } + + if (!err && !skipped) { + if (unlikely(++opt > opt_tail)) { + err = -E2BIG; + opt--; + opt->type = Opt_tail; + break; + } + opt->type = Opt_tail; + } + } + + kfree(a); + dump_opts(opts); + if (unlikely(err)) + au_opts_free(opts); + + out: + AuTraceErr(err); + return err; +} + +/* + * returns, + * plus: processed without an error + * zero: unprocessed + */ +static int au_opt_simple(struct super_block *sb, struct au_opt *opt, + struct au_opts *opts) +{ + int err; + struct au_sbinfo *sbinfo; + struct au_opt_wbr_create *create; + + AuTraceEnter(); + + err = 1; /* handled */ + sbinfo = au_sbi(sb); + switch (opt->type) { + case Opt_udba: + sbinfo->si_mntflags &= ~AuOptMask_UDBA; + sbinfo->si_mntflags |= opt->udba; + opts->given_udba |= opt->udba; + break; + + case Opt_plink: + au_opt_set(sbinfo->si_mntflags, PLINK); + break; + case Opt_noplink: + if (au_opt_test(sbinfo->si_mntflags, PLINK)) + au_plink_put(sb); + au_opt_clr(sbinfo->si_mntflags, PLINK); + break; + case Opt_list_plink: + if (au_opt_test(sbinfo->si_mntflags, PLINK)) + au_plink_list(sb); + break; + case Opt_clean_plink: + if (au_opt_test(sbinfo->si_mntflags, PLINK)) + au_plink_put(sb); + break; + + case Opt_diropq_a: + au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ); + break; + case Opt_diropq_w: + au_opt_clr(sbinfo->si_mntflags, ALWAYS_DIROPQ); + break; + + case Opt_dlgt: + au_opt_set(sbinfo->si_mntflags, DLGT); + break; + case Opt_nodlgt: + au_opt_clr(sbinfo->si_mntflags, DLGT); + break; + + case Opt_warn_perm: + au_opt_set(sbinfo->si_mntflags, WARN_PERM); + break; + case Opt_nowarn_perm: + au_opt_clr(sbinfo->si_mntflags, WARN_PERM); + break; + + case Opt_refrof: + au_opt_set(sbinfo->si_mntflags, REFROF); + break; + case Opt_norefrof: + /* au_opt_set(sbinfo->si_mntflags, COO_LEAF); */ + au_opt_clr(sbinfo->si_mntflags, REFROF); + break; + + case Opt_verbose: + au_opt_set(sbinfo->si_mntflags, VERBOSE); + break; + case Opt_noverbose: + au_opt_clr(sbinfo->si_mntflags, VERBOSE); + break; + + case Opt_wbr_create: + create = &opt->wbr_create; + if (sbinfo->si_wbr_create_ops->fin) { + err = sbinfo->si_wbr_create_ops->fin(sb); + if (!err) + err = 1; + } + sbinfo->si_wbr_create = create->wbr_create; + sbinfo->si_wbr_create_ops + = au_wbr_create_ops + create->wbr_create; + switch (create->wbr_create) { + case AuWbrCreate_MFSRRV: + case AuWbrCreate_MFSRR: + sbinfo->si_wbr_mfs.mfsrr_watermark + = create->mfsrr_watermark; + /*FALLTHROUGH*/ + case AuWbrCreate_MFS: + case AuWbrCreate_MFSV: + case AuWbrCreate_PMFS: + case AuWbrCreate_PMFSV: + sbinfo->si_wbr_mfs.mfs_expire = create->mfs_second * HZ; + break; + } + if (sbinfo->si_wbr_create_ops->init) + sbinfo->si_wbr_create_ops->init(sb); /* ignore */ + break; + case Opt_wbr_copyup: + sbinfo->si_wbr_copyup = opt->wbr_copyup; + sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup; + break; + + case Opt_coo: + sbinfo->si_mntflags &= ~AuOptMask_COO; + sbinfo->si_mntflags |= opt->coo; + break; + + case Opt_dirwh: + sbinfo->si_dirwh = opt->dirwh; + break; + + case Opt_rdcache: + sbinfo->si_rdcache = opt->rdcache * HZ; + break; + + case Opt_trunc_xino: + au_opt_set(sbinfo->si_mntflags, TRUNC_XINO); + break; + case Opt_notrunc_xino: + au_opt_clr(sbinfo->si_mntflags, TRUNC_XINO); + break; + + case Opt_dirperm1: + au_opt_set(sbinfo->si_mntflags, DIRPERM1); + break; + case Opt_nodirperm1: + au_opt_clr(sbinfo->si_mntflags, DIRPERM1); + break; + + case Opt_shwh: + au_opt_set(sbinfo->si_mntflags, SHWH); + break; + case Opt_noshwh: + au_opt_clr(sbinfo->si_mntflags, SHWH); + break; + + case Opt_trunc_xino_path: + case Opt_itrunc_xino: + err = au_xino_trunc(sb, opt->xino_itrunc.bindex); + if (!err) + err = 1; + break; + + case Opt_trunc_xib: + au_fset_opts(opts->flags, TRUNC_XIB); + break; + case Opt_notrunc_xib: + au_fclr_opts(opts->flags, TRUNC_XIB); + break; + + default: + err = 0; + break; + } + + AuTraceErr(err); + return err; +} + +/* + * returns tri-state. + * plus: processed without an error + * zero: unprocessed + * minus: error + */ +static int au_opt_br(struct super_block *sb, struct au_opt *opt, + struct au_opts *opts) +{ + int err, do_refresh; + + AuTraceEnter(); + + err = 0; + switch (opt->type) { + case Opt_append: + opt->add.bindex = au_sbend(sb) + 1; + if (unlikely(opt->add.bindex < 0)) + opt->add.bindex = 0; + goto add; + case Opt_prepend: + opt->add.bindex = 0; + add: + case Opt_add: + err = au_br_add(sb, &opt->add, + au_ftest_opts(opts->flags, REMOUNT)); + if (!err) { + err = 1; + au_fset_opts(opts->flags, REFRESH_DIR); + if (unlikely(au_br_whable(opt->add.perm))) + au_fset_opts(opts->flags, REFRESH_NONDIR); + } + break; + + case Opt_del: + case Opt_idel: + err = au_br_del(sb, &opt->del, + au_ftest_opts(opts->flags, REMOUNT)); + if (!err) { + err = 1; + au_fset_opts(opts->flags, TRUNC_XIB); + au_fset_opts(opts->flags, REFRESH_DIR); + au_fset_opts(opts->flags, REFRESH_NONDIR); + } + break; + + case Opt_mod: + case Opt_imod: + err = au_br_mod(sb, &opt->mod, + au_ftest_opts(opts->flags, REMOUNT), + &do_refresh); + if (!err) { + err = 1; + if (unlikely(do_refresh)) { + au_fset_opts(opts->flags, REFRESH_DIR); + au_fset_opts(opts->flags, REFRESH_NONDIR); + } + } + break; + } + + AuTraceErr(err); + return err; +} + +static int au_opt_xino(struct super_block *sb, struct au_opt *opt, + struct au_opt_xino **opt_xino, + struct au_opt_xinodir **opt_xinodir, + struct au_opts *opts) +{ + int err; + const int remount = !!au_ftest_opts(opts->flags, REMOUNT); + + AuTraceEnter(); + + err = 0; + switch (opt->type) { + case Opt_xino: + err = au_xino_set(sb, &opt->xino, remount); + if (!err) + *opt_xino = &opt->xino; + break; +#if 0 /* def CONFIG_AUFS_EXPORT */ /* reserved for futur use */ + case Opt_xinodir: + err = au_xinodir_set(sb, &opt->xinodir, remount); + if (!err) + *opt_xinodir = &opt->xinodir; + break; +#endif + case Opt_noxino: + au_xino_clr(sb); + *opt_xino = (void *)-1; + break; + } + + AuTraceErr(err); + return err; +} + +static int verify_opts(struct super_block *sb, unsigned int pending, + int remount) +{ + int err; + aufs_bindex_t bindex, bend; + unsigned char do_plink, skip, do_free; + struct au_branch *br; + struct au_wbr *wbr; + struct dentry *root; + struct inode *dir, *h_dir; + unsigned int mnt_flags; + + AuTraceEnter(); + mnt_flags = au_mntflags(sb); + AuDebugOn(!(mnt_flags & AuOptMask_COO)); + AuDebugOn(!(mnt_flags & AuOptMask_UDBA)); + + if (!(sb->s_flags & MS_RDONLY)) { + if (unlikely(!au_br_writable(au_sbr_perm(sb, 0)))) + AuWarn("first branch should be rw\n"); + if (unlikely(au_opt_test(mnt_flags, SHWH))) + AuWarn("shwh should be used with ro\n"); + } + + if (unlikely(au_opt_test((mnt_flags | pending), UDBA_INOTIFY) + && !au_opt_test_xino(mnt_flags))) + AuWarn("udba=inotify requires xino\n"); + + err = 0; + root = sb->s_root; + dir = sb->s_root->d_inode; + do_plink = !!au_opt_test(mnt_flags, PLINK); + bend = au_sbend(sb); + for (bindex = 0; !err && bindex <= bend; bindex++) { + skip = 0; + h_dir = au_h_iptr(dir, bindex); + br = au_sbr(sb, bindex); + do_free = 0; + wbr = br->br_wbr; + if (wbr) + wbr_wh_read_lock(wbr); + switch (br->br_perm) { + case AuBrPerm_RR: + case AuBrPerm_RO: + case AuBrPerm_RRWH: + case AuBrPerm_ROWH: + do_free = !!wbr; + skip = (!wbr + || (!wbr->wbr_whbase + && !wbr->wbr_plink + && !wbr->wbr_tmp)); + break; + + case AuBrPerm_RWNoLinkWH: + /* skip = (!br->br_whbase && !br->br_tmp); */ + skip = (!wbr || !wbr->wbr_whbase); + if (skip && wbr) { + if (do_plink) + skip = !!wbr->wbr_plink; + else + skip = !wbr->wbr_plink; + } + break; + + case AuBrPerm_RW: + /* skip = (br->br_whbase && br->br_tmp); */ + skip = (wbr && wbr->wbr_whbase); + if (skip) { + if (do_plink) + skip = !!wbr->wbr_plink; + else + skip = !wbr->wbr_plink; + } + break; + + default: + BUG(); + } + if (wbr) + wbr_wh_read_unlock(wbr); + + if (skip) + continue; + + mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); + if (wbr) + wbr_wh_write_lock(wbr); + err = au_wh_init(au_h_dptr(root, bindex), br, + au_nfsmnt(sb, bindex), sb, bindex); + if (wbr) + wbr_wh_write_unlock(wbr); + mutex_unlock(&h_dir->i_mutex); + + if (!err && do_free) { + kfree(wbr); + br->br_wbr = NULL; + } + } + + AuTraceErr(err); + return err; +} + +int au_opts_mount(struct super_block *sb, struct au_opts *opts) +{ + int err; + struct inode *dir; + struct au_opt *opt; + struct au_opt_xino *opt_xino, xino; + struct au_opt_xinodir *opt_xinodir; + aufs_bindex_t bend; + struct au_sbinfo *sbinfo; + unsigned int tmp; + struct au_branch *br; + + AuTraceEnter(); + SiMustWriteLock(sb); + DiMustWriteLock(sb->s_root); + dir = sb->s_root->d_inode; + IiMustWriteLock(dir); + + err = 0; + opt_xino = NULL; + opt_xinodir = NULL; + opt = opts->opt; + while (err >= 0 && opt->type != Opt_tail) + err = au_opt_simple(sb, opt++, opts); + if (err > 0) + err = 0; + else if (unlikely(err < 0)) + goto out; + + /* disable xino, xinodir, hinotify, dlgt temporary */ + sbinfo = au_sbi(sb); + tmp = sbinfo->si_mntflags; + au_opt_clr(sbinfo->si_mntflags, XINO); + au_opt_clr(sbinfo->si_mntflags, XINODIR); + au_opt_clr(sbinfo->si_mntflags, DLGT); + au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL); + + opt = opts->opt; + while (err >= 0 && opt->type != Opt_tail) + err = au_opt_br(sb, opt++, opts); + if (err > 0) + err = 0; + else if (unlikely(err < 0)) + goto out; + + bend = au_sbend(sb); + if (unlikely(bend < 0)) { + err = -EINVAL; + AuErr("no branches\n"); + goto out; + } + + if (au_opt_test(tmp, XINO)) + au_opt_set(sbinfo->si_mntflags, XINO); + else if (au_opt_test(tmp, XINODIR)) + au_opt_set(sbinfo->si_mntflags, XINODIR); + opt = opts->opt; + while (!err && opt->type != Opt_tail) + err = au_opt_xino(sb, opt++, &opt_xino, &opt_xinodir, opts); + if (unlikely(err)) + goto out; + + /* todo: test this error case? */ + err = verify_opts(sb, tmp, /*remount*/0); + if (unlikely(err)) + goto out; + + /* enable xino */ + if (au_opt_test(tmp, XINO) && !opt_xino) { + xino.file = au_xino_def(sb); + err = PTR_ERR(xino.file); + if (IS_ERR(xino.file)) + goto out; + + br = au_xino_def_br(sbinfo); + err = au_xino_set(sb, &xino, /*remount*/0); + fput(xino.file); + if (unlikely(err)) + goto out; + au_xino_def_br_set(br, sbinfo); + } + + /* restore hinotify */ + sbinfo->si_mntflags &= ~AuOptMask_UDBA; + sbinfo->si_mntflags |= (tmp & AuOptMask_UDBA); + if (au_opt_test(tmp, UDBA_INOTIFY)) + au_reset_hinotify(dir, au_hi_flags(dir, 1) & ~AuHi_XINO); + + /* restore dlgt */ + if (au_opt_test(tmp, DLGT)) + au_opt_set(sbinfo->si_mntflags, DLGT); + + out: + AuTraceErr(err); + return err; +} + +int au_opts_remount(struct super_block *sb, struct au_opts *opts) +{ + int err, rerr; + struct inode *dir; + struct au_opt_xino *opt_xino; + struct au_opt_xinodir *opt_xinodir; + struct au_opt *opt; + unsigned char dlgt; + struct au_sbinfo *sbinfo; + + AuTraceEnter(); + SiMustWriteLock(sb); + DiMustWriteLock(sb->s_root); + dir = sb->s_root->d_inode; + IiMustWriteLock(dir); + sbinfo = au_sbi(sb); + + err = 0; + dlgt = !!au_opt_test(sbinfo->si_mntflags, DLGT); + opt_xino = NULL; + opt_xinodir = NULL; + opt = opts->opt; + while (err >= 0 && opt->type != Opt_tail) { + err = au_opt_simple(sb, opt, opts); + + /* disable it temporary */ + dlgt = !!au_opt_test(sbinfo->si_mntflags, DLGT); + au_opt_clr(sbinfo->si_mntflags, DLGT); + + if (!err) + err = au_opt_br(sb, opt, opts); + if (!err) + err = au_opt_xino(sb, opt, &opt_xino, &opt_xinodir, + opts); + + /* restore it */ + if (unlikely(dlgt)) + au_opt_set(sbinfo->si_mntflags, DLGT); + opt++; + } + if (err > 0) + err = 0; + AuTraceErr(err); + + /* go on even err */ + + /* todo: test this error case? */ + au_opt_clr(sbinfo->si_mntflags, DLGT); + rerr = verify_opts(sb, sbinfo->si_mntflags, /*remount*/1); + if (unlikely(dlgt)) + au_opt_set(sbinfo->si_mntflags, DLGT); + if (unlikely(rerr && !err)) + err = rerr; + + if (unlikely(au_ftest_opts(opts->flags, TRUNC_XIB))) { + rerr = au_xib_trunc(sb); + if (unlikely(rerr && !err)) + err = rerr; + } + + /* they are handled by the caller */ + if (!au_ftest_opts(opts->flags, REFRESH_DIR) + && (opts->given_udba || au_opt_test_xino(sbinfo->si_mntflags))) + au_fset_opts(opts->flags, REFRESH_DIR); + + LKTRTrace("status 0x%x\n", opts->flags); + AuTraceErr(err); + return err; +} --- linux-2.6.27.orig/ubuntu/aufs/hin_or_dlgt.c +++ linux-2.6.27/ubuntu/aufs/hin_or_dlgt.c @@ -0,0 +1,737 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * sub-routines for vfs in hinotify or dlgt mode + * + * $Id: hin_or_dlgt.c,v 1.6 2008/07/14 00:15:10 sfjro Exp $ + */ + +#include +#include "aufs.h" + +#if !defined(CONFIG_AUFS_HINOTIFY) && !defined(CONFIG_AUFS_DLGT) +#error mis-configuraion or Makefile +#endif + +/* ---------------------------------------------------------------------- */ + +struct permission_args { + int *errp; + struct inode *inode; + int mask; + struct nameidata *nd; +}; + +static void call_permission(void *args) +{ + struct permission_args *a = args; + *a->errp = do_vfsub_permission(a->inode, a->mask, a->nd); +} + +int vfsub_permission(struct inode *inode, int mask, struct nameidata *nd, + int dlgt) +{ + if (!dlgt) + return do_vfsub_permission(inode, mask, nd); + else { + int err, wkq_err; + struct permission_args args = { + .errp = &err, + .inode = inode, + .mask = mask, + .nd = nd + }; + wkq_err = au_wkq_wait(call_permission, &args, /*dlgt*/1); + if (unlikely(wkq_err)) + err = wkq_err; + return err; + } +} + +/* ---------------------------------------------------------------------- */ + +struct create_args { + int *errp; + struct inode *dir; + struct dentry *dentry; + int mode; + struct nameidata *nd; + struct vfsub_args *vargs; +}; + +static void call_create(void *args) +{ + struct create_args *a = args; + vfsub_ignore(a->vargs); + *a->errp = do_vfsub_create(a->dir, a->dentry, a->mode, a->nd); + if (unlikely(*a->errp)) + vfsub_unignore(a->vargs); + au_dbg_hin_list(a->vargs); +} + +int vfsub_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd, struct vfsub_args *vargs) +{ + int err; + struct create_args args = { + .errp = &err, + .dir = dir, + .dentry = dentry, + .mode = mode, + .nd = nd, + .vargs = vargs + }; + + if (!vfsub_ftest(vargs->flags, DLGT)) + call_create(&args); + else { + int wkq_err; + wkq_err = au_wkq_wait(call_create, &args, /*dlgt*/1); + if (unlikely(wkq_err)) + err = wkq_err; + } + return err; +} + +struct symlink_args { + int *errp; + struct inode *dir; + struct dentry *dentry; + const char *symname; + int mode; + struct vfsub_args *vargs; +}; + +static void call_symlink(void *args) +{ + struct symlink_args *a = args; + vfsub_ignore(a->vargs); + *a->errp = do_vfsub_symlink(a->dir, a->dentry, a->symname, a->mode); + if (unlikely(*a->errp)) + vfsub_unignore(a->vargs); + au_dbg_hin_list(a->vargs); +} + +int vfsub_symlink(struct inode *dir, struct dentry *dentry, const char *symname, + int mode, struct vfsub_args *vargs) +{ + int err; + struct symlink_args args = { + .errp = &err, + .dir = dir, + .dentry = dentry, + .symname = symname, + .mode = mode, + .vargs = vargs + }; + + if (!vfsub_ftest(vargs->flags, DLGT)) + call_symlink(&args); + else { + int wkq_err; + wkq_err = au_wkq_wait(call_symlink, &args, /*dlgt*/1); + if (unlikely(wkq_err)) + err = wkq_err; + } + return err; +} + +struct mknod_args { + int *errp; + struct inode *dir; + struct dentry *dentry; + int mode; + dev_t dev; + struct vfsub_args *vargs; +}; + +static void call_mknod(void *args) +{ + struct mknod_args *a = args; + vfsub_ignore(a->vargs); + *a->errp = do_vfsub_mknod(a->dir, a->dentry, a->mode, a->dev); + if (unlikely(*a->errp)) + vfsub_unignore(a->vargs); + au_dbg_hin_list(a->vargs); +} + +int vfsub_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev, + struct vfsub_args *vargs) +{ + int err; + struct mknod_args args = { + .errp = &err, + .dir = dir, + .dentry = dentry, + .mode = mode, + .dev = dev, + .vargs = vargs + }; + + if (!vfsub_ftest(vargs->flags, DLGT)) + call_mknod(&args); + else { + int wkq_err; + wkq_err = au_wkq_wait(call_mknod, &args, /*dlgt*/1); + if (unlikely(wkq_err)) + err = wkq_err; + } + return err; +} + +struct mkdir_args { + int *errp; + struct inode *dir; + struct dentry *dentry; + int mode; + struct vfsub_args *vargs; +}; + +static void call_mkdir(void *args) +{ + struct mkdir_args *a = args; + vfsub_ignore(a->vargs); + *a->errp = do_vfsub_mkdir(a->dir, a->dentry, a->mode); + if (unlikely(*a->errp)) + vfsub_unignore(a->vargs); + au_dbg_hin_list(a->vargs); +} + +int vfsub_mkdir(struct inode *dir, struct dentry *dentry, int mode, + struct vfsub_args *vargs) +{ + int err; + struct mkdir_args args = { + .errp = &err, + .dir = dir, + .dentry = dentry, + .mode = mode, + .vargs = vargs + }; + + if (!vfsub_ftest(vargs->flags, DLGT)) + call_mkdir(&args); + else { + int wkq_err; + wkq_err = au_wkq_wait(call_mkdir, &args, /*dlgt*/1); + if (unlikely(wkq_err)) + err = wkq_err; + } + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct link_args { + int *errp; + struct inode *dir; + struct dentry *src_dentry, *dentry; + struct vfsub_args *vargs; +}; + +static void call_link(void *args) +{ + struct link_args *a = args; + vfsub_ignore(a->vargs); + *a->errp = do_vfsub_link(a->src_dentry, a->dir, a->dentry); + if (unlikely(*a->errp)) + vfsub_unignore(a->vargs); + au_dbg_hin_list(a->vargs); +} + +int vfsub_link(struct dentry *src_dentry, struct inode *dir, + struct dentry *dentry, struct vfsub_args *vargs) +{ + int err; + struct link_args args = { + .errp = &err, + .src_dentry = src_dentry, + .dir = dir, + .dentry = dentry, + .vargs = vargs + }; + + if (!vfsub_ftest(vargs->flags, DLGT)) + call_link(&args); + else { + int wkq_err; + wkq_err = au_wkq_wait(call_link, &args, /*dlgt*/1); + if (unlikely(wkq_err)) + err = wkq_err; + } + return err; +} + +struct rename_args { + int *errp; + struct inode *src_dir, *dir; + struct dentry *src_dentry, *dentry; + struct vfsub_args *vargs; +}; + +static void call_rename(void *args) +{ + struct rename_args *a = args; + vfsub_ignore(a->vargs); + *a->errp = do_vfsub_rename(a->src_dir, a->src_dentry, a->dir, + a->dentry); + if (unlikely(*a->errp)) + vfsub_unignore(a->vargs); + au_dbg_hin_list(a->vargs); +} + +int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, + struct inode *dir, struct dentry *dentry, + struct vfsub_args *vargs) +{ + int err; + struct rename_args args = { + .errp = &err, + .src_dir = src_dir, + .src_dentry = src_dentry, + .dir = dir, + .dentry = dentry, + .vargs = vargs + }; + + if (!vfsub_ftest(vargs->flags, DLGT)) + call_rename(&args); + else { + int wkq_err; + wkq_err = au_wkq_wait(call_rename, &args, /*dlgt*/1); + if (unlikely(wkq_err)) + err = wkq_err; + } + return err; +} + +struct rmdir_args { + int *errp; + struct inode *dir; + struct dentry *dentry; + struct vfsub_args *vargs; +}; + +static void call_rmdir(void *args) +{ + struct rmdir_args *a = args; + vfsub_ignore(a->vargs); + *a->errp = do_vfsub_rmdir(a->dir, a->dentry); + if (unlikely(*a->errp)) + vfsub_unignore(a->vargs); + au_dbg_hin_list(a->vargs); +} + +int vfsub_rmdir(struct inode *dir, struct dentry *dentry, + struct vfsub_args *vargs) +{ + int err; + struct rmdir_args args = { + .errp = &err, + .dir = dir, + .dentry = dentry, + .vargs = vargs + }; + + if (!vfsub_ftest(vargs->flags, DLGT)) + call_rmdir(&args); + else { + int wkq_err; + wkq_err = au_wkq_wait(call_rmdir, &args, /*dlgt*/1); + if (unlikely(wkq_err)) + err = wkq_err; + } + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct read_args { + ssize_t *errp; + struct file *file; + union { + void *kbuf; + char __user *ubuf; + }; + size_t count; + loff_t *ppos; +}; + +static void call_read_k(void *args) +{ + struct read_args *a = args; + LKTRTrace("%.*s, cnt %lu, pos %lld\n", + AuDLNPair(a->file->f_dentry), (unsigned long)a->count, + *a->ppos); + *a->errp = do_vfsub_read_k(a->file, a->kbuf, a->count, a->ppos); +} + +ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, + loff_t *ppos, int dlgt) +{ + if (!dlgt) + return do_vfsub_read_u(file, ubuf, count, ppos); + else { + int wkq_err; + ssize_t err, read; + struct read_args args = { + .errp = &err, + .file = file, + .count = count, + .ppos = ppos + }; + + if (unlikely(!count)) + return 0; + + /* + * workaround an application bug. + * generally, read(2) or write(2) may return the value shorter + * than requested. But many applications don't support it, + * for example bash. + */ + err = -ENOMEM; + if (args.count > PAGE_SIZE) + args.count = PAGE_SIZE; + args.kbuf = kmalloc(args.count, GFP_NOFS); + if (unlikely(!args.kbuf)) + goto out; + + read = 0; + do { + wkq_err = au_wkq_wait(call_read_k, &args, /*dlgt*/1); + if (unlikely(wkq_err)) + err = wkq_err; + if (unlikely(err > 0 + && copy_to_user(ubuf, args.kbuf, err))) { + err = -EFAULT; + goto out_free; + } else if (!err) + break; + else if (unlikely(err < 0)) + goto out_free; + count -= err; + /* do not read too much because of file i/o pointer */ + if (count < args.count) + args.count = count; + ubuf += err; + read += err; + } while (count); + smp_mb(); /* flush ubuf */ + err = read; + + out_free: + kfree(args.kbuf); + out: + return err; + } +} + +ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, loff_t *ppos, + int dlgt) +{ + if (!dlgt) + return do_vfsub_read_k(file, kbuf, count, ppos); + else { + ssize_t err; + int wkq_err; + struct read_args args = { + .errp = &err, + .file = file, + .count = count, + .ppos = ppos + }; + args.kbuf = kbuf; + wkq_err = au_wkq_wait(call_read_k, &args, /*dlgt*/1); + if (unlikely(wkq_err)) + err = wkq_err; + return err; + } +} + +struct write_args { + ssize_t *errp; + struct file *file; + union { + void *kbuf; + const char __user *ubuf; + }; + size_t count; + loff_t *ppos; + struct vfsub_args *vargs; +}; + +static void call_write_k(void *args) +{ + struct write_args *a = args; + vfsub_ignore(a->vargs); + *a->errp = do_vfsub_write_k(a->file, a->kbuf, a->count, a->ppos); + if (unlikely(*a->errp <= 0)) + vfsub_unignore(a->vargs); + au_dbg_hin_list(a->vargs); +} + +ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, + loff_t *ppos, struct vfsub_args *vargs) +{ + ssize_t err; + + if (!vfsub_ftest(vargs->flags, DLGT)) { + vfsub_ignore(vargs); + err = do_vfsub_write_u(file, ubuf, count, ppos); + if (unlikely(err <= 0)) + vfsub_unignore(vargs); + au_dbg_hin_list(vargs); + } else { + ssize_t written; + int wkq_err; + struct write_args args = { + .errp = &err, + .file = file, + .count = count, + .ppos = ppos, + .vargs = vargs + }; + + if (unlikely(!count)) + return 0; + + /* + * workaround an application bug. + * generally, read(2) or write(2) may return the value shorter + * than requested. But many applications don't support it, + * for example bash. + */ + err = -ENOMEM; + if (args.count > PAGE_SIZE) + args.count = PAGE_SIZE; + args.kbuf = kmalloc(args.count, GFP_NOFS); + if (unlikely(!args.kbuf)) + goto out; + + written = 0; + do { + if (unlikely(copy_from_user(args.kbuf, ubuf, + args.count))) { + err = -EFAULT; + goto out_free; + } + + wkq_err = au_wkq_wait(call_write_k, &args, /*dlgt*/1); + if (unlikely(wkq_err)) + err = wkq_err; + if (err > 0) { + count -= err; + if (count < args.count) + args.count = count; + ubuf += err; + written += err; + } else if (!err) + break; + else if (unlikely(err < 0)) + goto out_free; + } while (count); + err = written; + + out_free: + kfree(args.kbuf); + } + out: + return err; +} + +ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos, + struct vfsub_args *vargs) +{ + ssize_t err; + struct write_args args = { + .errp = &err, + .file = file, + .count = count, + .ppos = ppos, + .vargs = vargs + }; + + args.kbuf = kbuf; + if (!vfsub_ftest(vargs->flags, DLGT)) + call_write_k(&args); + else { + int wkq_err; + wkq_err = au_wkq_wait(call_write_k, &args, /*dlgt*/1); + if (unlikely(wkq_err)) + err = wkq_err; + } + return err; +} + +struct readdir_args { + int *errp; + struct file *file; + filldir_t filldir; + void *arg; +}; + +static void call_readdir(void *args) +{ + struct readdir_args *a = args; + *a->errp = do_vfsub_readdir(a->file, a->filldir, a->arg); +} + +int vfsub_readdir(struct file *file, filldir_t filldir, void *arg, int dlgt) +{ + if (!dlgt) + return do_vfsub_readdir(file, filldir, arg); + else { + int err, wkq_err; + struct readdir_args args = { + .errp = &err, + .file = file, + .filldir = filldir, + .arg = arg + }; + wkq_err = au_wkq_wait(call_readdir, &args, /*dlgt*/1); + if (unlikely(wkq_err)) + err = wkq_err; + return err; + } +} + +/* ---------------------------------------------------------------------- */ + +struct splice_to_args { + long *errp; + struct file *in; + loff_t *ppos; + struct pipe_inode_info *pipe; + size_t len; + unsigned int flags; +}; + +static void call_splice_to(void *args) +{ + struct splice_to_args *a = args; + *a->errp = do_vfsub_splice_to(a->in, a->ppos, a->pipe, a->len, + a->flags); +} + +long vfsub_splice_to(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags, int dlgt) +{ + if (!dlgt) + return do_vfsub_splice_to(in, ppos, pipe, len, flags); + else { + long err; + int wkq_err; + struct splice_to_args args = { + .errp = &err, + .in = in, + .ppos = ppos, + .pipe = pipe, + .len = len, + .flags = flags + }; + wkq_err = au_wkq_wait(call_splice_to, &args, /*dlgt*/1); + if (unlikely(wkq_err)) + err = wkq_err; + return err; + } +} + +struct splice_from_args { + long *errp; + struct pipe_inode_info *pipe; + struct file *out; + loff_t *ppos; + size_t len; + unsigned int flags; + struct vfsub_args *vargs; +}; + +static void call_splice_from(void *args) +{ + struct splice_from_args *a = args; + vfsub_ignore(a->vargs); + *a->errp = do_vfsub_splice_from(a->pipe, a->out, a->ppos, a->len, + a->flags); + if (unlikely(*a->errp < 0)) + vfsub_unignore(a->vargs); + au_dbg_hin_list(a->vargs); +} + +long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags, + struct vfsub_args *vargs) +{ + long err; + struct splice_from_args args = { + .errp = &err, + .pipe = pipe, + .out = out, + .ppos = ppos, + .len = len, + .flags = flags, + .vargs = vargs + }; + + if (!vfsub_ftest(vargs->flags, DLGT)) + call_splice_from(&args); + else { + int wkq_err; + wkq_err = au_wkq_wait(call_splice_from, &args, /*dlgt*/1); + if (unlikely(wkq_err)) + err = wkq_err; + } + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct getattr_args { + int *errp; + struct vfsmount *mnt; + struct dentry *dentry; + struct kstat *st; +}; + +static void call_getattr(void *args) +{ + struct getattr_args *a = args; + *a->errp = do_vfsub_getattr(a->mnt, a->dentry, a->st); +} + +int vfsub_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *st, + int dlgt) +{ + if (!dlgt) + return do_vfsub_getattr(mnt, dentry, st); + else { + int err, wkq_err; + struct getattr_args args = { + .errp = &err, + .mnt = mnt, + .dentry = dentry, + .st = st + }; + wkq_err = au_wkq_wait(call_getattr, &args, /*dlgt*/1); + if (unlikely(wkq_err)) + err = wkq_err; + return err; + } +} --- linux-2.6.27.orig/ubuntu/aufs/i_op_add.c +++ linux-2.6.27/ubuntu/aufs/i_op_add.c @@ -0,0 +1,754 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * inode operations (add entry) + * + * $Id: i_op_add.c,v 1.14 2008/09/22 03:52:19 sfjro Exp $ + */ + +#include "aufs.h" + +/* + * final procedure of adding a new entry, except link(2). + * remove whiteout, instantiate, copyup the parent dir's times and size + * and update version. + * if it failed, re-create the removed whiteout. + */ +static int epilog(struct inode *dir, aufs_bindex_t bindex, + struct dentry *wh_dentry, struct dentry *dentry) +{ + int err, rerr; + aufs_bindex_t bwh; + struct inode *inode, *h_dir; + struct dentry *wh; + struct au_ndx ndx; + struct super_block *sb; + + LKTRTrace("wh %p, %.*s\n", wh_dentry, AuDLNPair(dentry)); + + sb = dentry->d_sb; + bwh = -1; + if (wh_dentry) { + h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */ + IMustLock(h_dir); + AuDebugOn(au_h_iptr(dir, bindex) != h_dir); + bwh = au_dbwh(dentry); + err = au_wh_unlink_dentry(au_hi(dir, bindex), wh_dentry, dentry, + /*dlgt*/0); + if (unlikely(err)) + goto out; + } + + inode = au_new_inode(dentry); + if (!IS_ERR(inode)) { + d_instantiate(dentry, inode); + dir = dentry->d_parent->d_inode; /* dir inode is locked */ + IMustLock(dir); + /* or always cpup dir mtime? */ + if (au_ibstart(dir) == au_dbstart(dentry)) + au_cpup_attr_timesizes(dir); + dir->i_version++; + return 0; /* success */ + } + + err = PTR_ERR(inode); + if (!wh_dentry) + goto out; + + /* revert */ + ndx.flags = 0; + if (unlikely(au_test_dlgt(au_mntflags(sb)))) + au_fset_ndx(ndx.flags, DLGT); + ndx.nfsmnt = au_nfsmnt(sb, bwh); + ndx.nd = NULL; + /* ndx.br = NULL; */ + /* dir inode is locked */ + wh = au_wh_create(dentry, bwh, wh_dentry->d_parent, &ndx); + rerr = PTR_ERR(wh); + if (IS_ERR(wh)) { + AuIOErr("%.*s reverting whiteout failed(%d, %d)\n", + AuDLNPair(dentry), err, rerr); + err = -EIO; + } else { + err = 0; + dput(wh); + } + + out: + AuTraceErr(err); + return err; +} + +/* + * simple tests for the adding inode operations. + * following the checks in vfs, plus the parent-child relationship. + */ +int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_parent, int isdir, struct au_ndx *ndx) +{ + int err, exist; + struct dentry *h_dentry; + struct inode *h_inode; + umode_t h_mode; + + LKTRTrace("%.*s/%.*s, b%d, dir %d\n", + AuDLNPair(h_parent), AuDLNPair(dentry), bindex, isdir); + + exist = !!dentry->d_inode; + h_dentry = au_h_dptr(dentry, bindex); + h_inode = h_dentry->d_inode; + if (!exist) { + err = -EEXIST; + if (unlikely(h_inode)) + goto out; + } else { + /* rename(2) case */ + err = -EIO; + if (unlikely(!h_inode || !h_inode->i_nlink)) + goto out; + + h_mode = h_inode->i_mode; + if (!isdir) { + err = -EISDIR; + if (unlikely(S_ISDIR(h_mode))) + goto out; + } else if (unlikely(!S_ISDIR(h_mode))) { + err = -ENOTDIR; + goto out; + } + } + + err = -EIO; + /* expected parent dir is locked */ + if (unlikely(h_parent != h_dentry->d_parent)) + goto out; + err = 0; + + if (unlikely(au_opt_test(au_mntflags(dentry->d_sb), UDBA_INOTIFY))) { + struct dentry *h_latest; + struct qstr *qstr = &dentry->d_name; + + err = -EACCES; + if (unlikely(au_test_h_perm + (h_parent->d_inode, MAY_EXEC | MAY_WRITE, + au_ftest_ndx(ndx->flags, DLGT)))) + goto out; + + err = -EIO; + h_latest = au_sio_lkup_one(qstr->name, h_parent, qstr->len, + ndx); + err = PTR_ERR(h_latest); + if (IS_ERR(h_latest)) + goto out; + err = -EIO; + dput(h_latest); + if (h_latest == h_dentry) + err = 0; + } + + out: + AuTraceErr(err); + return err; +} + +/* + * initial procedure of adding a new entry. + * prepare writable branch and the parent dir, lock it, + * lookup whiteout for the new entry. + */ +static struct dentry* +lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt, + struct dentry *src_dentry, struct au_pin *pin, + struct au_wr_dir_args *wr_dir_args) +{ + struct dentry *wh_dentry, *h_parent; + int err; + aufs_bindex_t bstart, bcpup; + struct au_ndx ndx; + struct super_block *sb; + unsigned int mnt_flags; + + LKTRTrace("%.*s, src %p\n", AuDLNPair(dentry), src_dentry); + + bstart = au_dbstart(dentry); + err = au_wr_dir(dentry, src_dentry, wr_dir_args); + bcpup = err; + wh_dentry = ERR_PTR(err); + if (unlikely(err < 0)) + goto out; + + sb = dentry->d_sb; + mnt_flags = au_mntflags(sb); + err = au_pin(pin, dentry, bcpup, /*di_locked*/1, + /*do_gp*/dt && au_opt_test(mnt_flags, UDBA_INOTIFY)); + wh_dentry = ERR_PTR(err); + if (unlikely(err)) + goto out; + + ndx.nfsmnt = au_nfsmnt(sb, bcpup); + ndx.flags = 0; + if (unlikely(au_test_dlgt(mnt_flags))) + au_fset_ndx(ndx.flags, DLGT); + ndx.nd = NULL; + /* ndx.br = NULL; */ + /* ndx.nd_file = NULL; */ + + h_parent = au_pinned_h_parent(pin, bcpup); + if (!au_opt_test(mnt_flags, UDBA_NONE) && au_dbstart(dentry) == bcpup) { + struct nameidata nd; + + if (unlikely(ndx.nfsmnt)) { + /* todo: dirty? */ + ndx.nd = &nd; + ndx.br = au_sbr(sb, bcpup); + memset(&nd, 0, sizeof(nd)); + nd.flags = LOOKUP_CREATE; + nd.intent.open.flags = O_EXCL; + } + err = au_may_add(dentry, bcpup, h_parent, + au_ftest_wrdir(wr_dir_args->flags, ISDIR), + &ndx); + wh_dentry = ERR_PTR(err); + if (unlikely(err)) + goto out_unpin; + ndx.nd = NULL; + ndx.br = NULL; + } + + if (dt) + au_dtime_store(dt, au_pinned_parent(pin), h_parent, + au_pinned_hdir(pin, bcpup), + au_pinned_hgdir(pin, bcpup)); + + wh_dentry = NULL; + if (/* bcpup != bstart || */ bcpup != au_dbwh(dentry)) + goto out; /* success */ + + wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, &ndx); + + out_unpin: + if (IS_ERR(wh_dentry)) + au_unpin(pin); + out: + AuTraceErrPtr(wh_dentry); + return wh_dentry; +} + +/* ---------------------------------------------------------------------- */ + +enum { Mknod, Symlink, Creat }; +struct simple_arg { + int type; + union { + struct { + int mode; + struct nameidata *nd; + } c; + struct { + const char *symname; + } s; + struct { + int mode; + dev_t dev; + } m; + } u; +}; + +static int add_simple(struct inode *dir, struct dentry *dentry, + struct simple_arg *arg) +{ + int err; + struct dentry *h_dentry, *wh_dentry, *parent; + struct inode *h_dir; + struct au_dtime dt; + struct vfsub_args vargs; + struct super_block *sb; + aufs_bindex_t bstart; + unsigned char created; + struct au_hin_ignore ign; + struct au_pin pin; + struct au_wr_dir_args wr_dir_args = { + .force_btgt = -1, + .flags = AuWrDir_ADD_ENTRY + }; + + LKTRTrace("type %d, %.*s\n", arg->type, AuDLNPair(dentry)); + IMustLock(dir); + + sb = dir->i_sb; + parent = dentry->d_parent; /* dir inode is locked */ + aufs_read_lock(dentry, AuLock_DW); + vfsub_args_init(&vargs, &ign, !!au_test_dlgt(au_mntflags(sb)), 0); + di_write_lock_parent(parent); + wh_dentry = lock_hdir_lkup_wh(dentry, &dt, /*src_dentry*/NULL, &pin, + &wr_dir_args); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out; + + bstart = au_dbstart(dentry); + h_dentry = au_h_dptr(dentry, bstart); + h_dir = au_pinned_h_dir(&pin); + vfsub_ign_hinode(&vargs, IN_CREATE, au_pinned_hdir(&pin, bstart)); + + switch (arg->type) { + case Creat: + AuDebugOn(au_test_nfs(h_dir->i_sb) && !arg->u.c.nd); + err = au_h_create(h_dir, h_dentry, arg->u.c.mode, &vargs, + arg->u.c.nd, au_nfsmnt(sb, bstart)); + break; + case Symlink: + err = vfsub_symlink(h_dir, h_dentry, arg->u.s.symname, + S_IALLUGO, &vargs); + break; + case Mknod: + err = vfsub_mknod(h_dir, h_dentry, arg->u.m.mode, arg->u.m.dev, + &vargs); + break; + default: + BUG(); + } + created = !err; + if (!err) + err = epilog(dir, bstart, wh_dentry, dentry); + + /* revert */ + if (unlikely(created && err && h_dentry->d_inode)) { + int rerr; + vfsub_args_reinit(&vargs); + vfsub_ign_hinode(&vargs, IN_DELETE, + au_pinned_hdir(&pin, bstart)); + rerr = vfsub_unlink(h_dir, h_dentry, &vargs); + if (rerr) { + AuIOErr("%.*s revert failure(%d, %d)\n", + AuDLNPair(dentry), err, rerr); + err = -EIO; + } + /* todo: inotify will be fired to the grand parent dir? */ + au_dtime_revert(&dt); + d_drop(dentry); + } + + au_unpin(&pin); + dput(wh_dentry); + + out: + if (unlikely(err)) { + au_update_dbstart(dentry); + d_drop(dentry); + } + di_write_unlock(parent); + aufs_read_unlock(dentry, AuLock_DW); + AuTraceErr(err); + return err; +} + +int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +{ + struct simple_arg arg = { + .type = Mknod, + .u.m = { + .mode = mode, + .dev = dev + } + }; + return add_simple(dir, dentry, &arg); +} + +int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) +{ + struct simple_arg arg = { + .type = Symlink, + .u.s.symname = symname + }; + return add_simple(dir, dentry, &arg); +} + +int aufs_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) +{ + struct simple_arg arg = { + .type = Creat, + .u.c = { + .mode = mode, + .nd = nd + } + }; + return add_simple(dir, dentry, &arg); +} + +/* ---------------------------------------------------------------------- */ + +struct au_link_args { + aufs_bindex_t bdst, bsrc; + struct dentry *h_dentry; + struct dentry *src_parent, *parent; + struct au_pin pin; + struct au_hin_ignore ign; + struct vfsub_args vargs; + unsigned int mnt_flags; +}; + +static int au_cpup_before_link(struct dentry *src_dentry, struct inode *dir, + struct dentry *dentry, struct au_link_args *a) +{ + int err; + struct mutex *h_mtx; + const int hinotify = au_opt_test(a->mnt_flags, UDBA_INOTIFY); + + LKTRTrace("src %.*s, i%lu, dst %.*s\n", + AuDLNPair(src_dentry), dir->i_ino, AuDLNPair(dentry)); + + di_read_lock_parent(a->src_parent, AuLock_IR); + err = au_test_and_cpup_dirs(src_dentry, a->bdst); + if (unlikely(err)) + goto out; + + AuDebugOn(au_dbstart(src_dentry) != a->bsrc); + h_mtx = &au_h_dptr(src_dentry, a->bsrc)->d_inode->i_mutex; + err = au_pin(&a->pin, src_dentry, a->bdst, /*di_locked*/1, + /*do_gp*/hinotify); + if (unlikely(err)) + goto out; + mutex_lock_nested(h_mtx, AuLsc_I_CHILD); + /* todo: no KEEPLINO because of noplink? */ + err = au_sio_cpup_simple(src_dentry, a->bdst, -1, + AuCpup_DTIME /* | AuCpup_KEEPLINO */); + mutex_unlock(h_mtx); + au_unpin(&a->pin); + + out: + di_read_unlock(a->src_parent, AuLock_IR); + AuTraceErr(err); + return err; +} + +static int au_cpup_or_link(struct dentry *src_dentry, struct au_link_args *a) +{ + int err; + struct inode *h_inode; + aufs_bindex_t bstart; + struct dentry *h_src_dentry; + + AuTraceEnter(); + AuDebugOn(au_dbstart(src_dentry) != a->bsrc); + + bstart = au_ibstart(src_dentry->d_inode); + h_inode = NULL; + if (bstart <= a->bdst) + h_inode = au_h_iptr(src_dentry->d_inode, a->bdst); + if (!h_inode || !h_inode->i_nlink) { + /* copyup src_dentry as the name of dentry. */ + au_set_dbstart(src_dentry, a->bdst); + au_set_h_dptr(src_dentry, a->bdst, dget(a->h_dentry)); + h_inode = au_h_dptr(src_dentry, a->bsrc)->d_inode; + mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); + err = au_sio_cpup_single(src_dentry, a->bdst, a->bsrc, -1, + AuCpup_KEEPLINO, a->parent); + mutex_unlock(&h_inode->i_mutex); + au_set_h_dptr(src_dentry, a->bdst, NULL); + au_set_dbstart(src_dentry, a->bsrc); + } else { + /* the inode of src_dentry already exists on a.bdst branch */ + h_src_dentry = d_find_alias(h_inode); + if (h_src_dentry) { + /* vfsub_args_reinit(&a->vargs); */ + vfsub_ign_hinode(&a->vargs, IN_CREATE, + au_pinned_hdir(&a->pin, a->bdst)); + err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), + a->h_dentry, &a->vargs); + dput(h_src_dentry); + } else { + AuIOErr("no dentry found for i%lu on b%d\n", + h_inode->i_ino, a->bdst); + err = -EIO; + } + } + + if (!err) + au_plink_append(src_dentry->d_sb, src_dentry->d_inode, + a->h_dentry, a->bdst); + + AuTraceErr(err); + return err; +} + +int aufs_link(struct dentry *src_dentry, struct inode *dir, + struct dentry *dentry) +{ + int err, rerr; + struct dentry *wh_dentry, *h_src_dentry; + struct inode *inode; + struct au_dtime dt; + struct super_block *sb; + struct au_link_args *a; + struct au_wr_dir_args wr_dir_args = { + /* .force_btgt = -1, */ + .flags = AuWrDir_ADD_ENTRY + }; + + LKTRTrace("src %.*s, i%lu, dst %.*s\n", + AuDLNPair(src_dentry), dir->i_ino, AuDLNPair(dentry)); + IMustLock(dir); + inode = src_dentry->d_inode; + IMustLock(inode); + AuDebugOn(S_ISDIR(inode->i_mode)); + + err = -ENOMEM; + a = kzalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + + sb = dentry->d_sb; + a->parent = dentry->d_parent; /* dir inode is locked */ + aufs_read_and_write_lock2(dentry, src_dentry, /*AuLock_FLUSH*/0); + a->src_parent = dget_parent(src_dentry); + wr_dir_args.force_btgt = au_dbstart(src_dentry); + a->mnt_flags = au_mntflags(sb); + vfsub_args_init(&a->vargs, &a->ign, au_test_dlgt(a->mnt_flags), 0); + + di_write_lock_parent(a->parent); + wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt); + wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin, + &wr_dir_args); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out_unlock; + err = 0; + + a->bdst = au_dbstart(dentry); + a->h_dentry = au_h_dptr(dentry, a->bdst); + + /* todo: minor optimize, + their sb may be same while their bindex differs? */ + a->bsrc = au_dbstart(src_dentry); + if (au_opt_test(a->mnt_flags, PLINK)) { + if (a->bdst < a->bsrc + /* && h_src_dentry->d_sb != a->h_dentry->d_sb */) + err = au_cpup_or_link(src_dentry, a); + else { + h_src_dentry = au_h_dptr(src_dentry, a->bdst); + AuDebugOn(!h_src_dentry); + AuDebugOn(!h_src_dentry->d_inode); + vfsub_ign_hinode(&a->vargs, IN_CREATE, + au_pinned_hdir(&a->pin, a->bdst)); + err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), + a->h_dentry, &a->vargs); + } + } else { + /* + * copyup src_dentry to the branch we process, + * and then link(2) to it. + */ + if (a->bdst < a->bsrc + /* && h_src_dentry->d_sb != a->h_dentry->d_sb */) { + au_unpin(&a->pin); + di_write_unlock(a->parent); + err = au_cpup_before_link(src_dentry, dir, dentry, a); + if (!err) { + di_write_lock_parent(a->parent); + err = au_pin + (&a->pin, dentry, a->bdst, + /*di_locked*/1, + /*do_gp*/au_opt_test(a->mnt_flags, + UDBA_INOTIFY)); + if (unlikely(err)) + goto out_wh; + } + } + if (!err) { + /* vfsub_args_reinit(&a->vargs); */ + vfsub_ign_hinode(&a->vargs, IN_CREATE, + au_pinned_hdir(&a->pin, a->bdst)); + h_src_dentry = au_h_dptr(src_dentry, a->bdst); + err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), + a->h_dentry, &a->vargs); + } + } + if (unlikely(err)) + goto out_unpin; + + if (wh_dentry) { + err = au_wh_unlink_dentry(au_pinned_hdir(&a->pin, a->bdst), + wh_dentry, dentry, /*dlgt*/0); + if (unlikely(err)) + goto out_revert; + } + +#if 0 /* cannot support it */ + /* fuse has different memory inode for the same inode number */ + if (unlikely(au_test_fuse(a->h_dentry->d_sb))) { + LKTRLabel(here); + d_drop(a->h_dentry); + /*d_drop(h_src_dentry); + d_drop(src_dentry);*/ + inc_nlink(a->inode); + a->inode->i_ctime = dir->i_ctime; + } +#endif + + dir->i_version++; + if (au_ibstart(dir) == au_dbstart(dentry)) + au_cpup_attr_timesizes(dir); + if (!d_unhashed(a->h_dentry) + /* || h_old_inode->i_nlink <= nlink */ + /* || SB_NFS(h_src_dentry->d_sb) */) { + d_instantiate(dentry, au_igrab(inode)); + inc_nlink(inode); + inode->i_ctime = dir->i_ctime; + } else + /* nfs case (< 2.6.15) */ + d_drop(dentry); + goto out_unpin; /* success */ + + out_revert: + vfsub_args_reinit(&a->vargs); + vfsub_ign_hinode(&a->vargs, IN_DELETE, au_pinned_hdir(&a->pin, a->bdst)); + rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), a->h_dentry, &a->vargs); + if (!rerr) + goto out_dt; + AuIOErr("%.*s reverting failed(%d, %d)\n", + AuDLNPair(dentry), err, rerr); + err = -EIO; + out_dt: + d_drop(dentry); + au_dtime_revert(&dt); + out_unpin: + au_unpin(&a->pin); + out_wh: + dput(wh_dentry); + out_unlock: + if (unlikely(err)) { + au_update_dbstart(dentry); + d_drop(dentry); + } + di_write_unlock(a->parent); + dput(a->src_parent); + aufs_read_and_write_unlock2(dentry, src_dentry); + kfree(a); + out: + AuTraceErr(err); + return err; +} + +int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + int err, rerr; + struct dentry *h_dentry, *wh_dentry, *parent, *opq_dentry; + struct mutex *h_mtx; + struct au_dtime dt; + aufs_bindex_t bindex; + unsigned char diropq, dlgt; + unsigned int mnt_flags; + struct au_hin_ignore ign; + struct vfsub_args vargs; + struct au_pin pin; + struct au_wr_dir_args wr_dir_args = { + .force_btgt = -1, + .flags = AuWrDir_ADD_ENTRY | AuWrDir_ISDIR + }; + + LKTRTrace("i%lu, %.*s, mode 0%o\n", + dir->i_ino, AuDLNPair(dentry), mode); + IMustLock(dir); +#if 0 + if (IS_DEADDIR(dir)) { + AuDbg("here\n"); + return -ENOENT; + } +#endif + + aufs_read_lock(dentry, AuLock_DW); + parent = dentry->d_parent; /* dir inode is locked */ + mnt_flags = au_mntflags(dentry->d_sb); + dlgt = !!au_test_dlgt(mnt_flags); + vfsub_args_init(&vargs, &ign, dlgt, 0); + + di_write_lock_parent(parent); + wh_dentry = lock_hdir_lkup_wh(dentry, &dt, /*src_dentry*/NULL, &pin, + &wr_dir_args); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out; + + bindex = au_dbstart(dentry); + h_dentry = au_h_dptr(dentry, bindex); + vfsub_ign_hinode(&vargs, IN_CREATE, au_pinned_hdir(&pin, bindex)); + err = vfsub_mkdir(au_pinned_h_dir(&pin), h_dentry, mode, &vargs); + if (unlikely(err)) + goto out_unlock; + + /* make the dir opaque */ + diropq = 0; + h_mtx = &h_dentry->d_inode->i_mutex; + if (wh_dentry || au_opt_test(mnt_flags, ALWAYS_DIROPQ)) { + mutex_lock_nested(h_mtx, AuLsc_I_CHILD); + opq_dentry = au_diropq_create(dentry, bindex, /*dlgt*/0); + mutex_unlock(h_mtx); + err = PTR_ERR(opq_dentry); + if (IS_ERR(opq_dentry)) + goto out_dir; + dput(opq_dentry); + diropq = 1; + } + + err = epilog(dir, bindex, wh_dentry, dentry); + if (!err) { + inc_nlink(dir); + goto out_unlock; /* success */ + } + + /* revert */ + if (diropq) { + LKTRLabel(revert opq); + mutex_lock_nested(h_mtx, AuLsc_I_CHILD); + rerr = au_diropq_remove(dentry, bindex, dlgt); + mutex_unlock(h_mtx); + if (rerr) { + AuIOErr("%.*s reverting diropq failed(%d, %d)\n", + AuDLNPair(dentry), err, rerr); + err = -EIO; + } + } + + out_dir: + LKTRLabel(revert dir); + vfsub_args_reinit(&vargs); + vfsub_ign_hinode(&vargs, IN_DELETE, au_pinned_hdir(&pin, bindex)); + rerr = vfsub_rmdir(au_pinned_h_dir(&pin), h_dentry, &vargs); + if (rerr) { + AuIOErr("%.*s reverting dir failed(%d, %d)\n", + AuDLNPair(dentry), err, rerr); + err = -EIO; + } + d_drop(dentry); + au_dtime_revert(&dt); + out_unlock: + au_unpin(&pin); + dput(wh_dentry); + out: + if (unlikely(err)) { + au_update_dbstart(dentry); + d_drop(dentry); + } + di_write_unlock(parent); + aufs_read_unlock(dentry, AuLock_DW); + AuTraceErr(err); + return err; +} --- linux-2.6.27.orig/ubuntu/aufs/i_op_del.c +++ linux-2.6.27/ubuntu/aufs/i_op_del.c @@ -0,0 +1,575 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * inode operations (del entry) + * + * $Id: i_op_del.c,v 1.12 2008/09/22 03:52:19 sfjro Exp $ + */ + +#include "aufs.h" + +/* returns, + * 0: wh is unnecessary + * plus: wh is necessary + * minus: error + */ +int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup) +{ + int need_wh, err; + aufs_bindex_t bstart; + struct dentry *h_dentry; + struct super_block *sb; + + LKTRTrace("%.*s, isdir %d, *bcpup %d\n", + AuDLNPair(dentry), isdir, *bcpup); + sb = dentry->d_sb; + + bstart = au_dbstart(dentry); + LKTRTrace("bcpup %d, bstart %d\n", *bcpup, bstart); + h_dentry = au_h_dptr(dentry, bstart); + if (*bcpup < 0) { + *bcpup = bstart; + if (au_test_ro(sb, bstart, dentry->d_inode)) { + err = AuWbrCopyup(au_sbi(sb), dentry); + *bcpup = err; + if (unlikely(err < 0)) + goto out; + } + } else + AuDebugOn(bstart < *bcpup + || au_test_ro(sb, *bcpup, dentry->d_inode)); + LKTRTrace("bcpup %d, bstart %d\n", *bcpup, bstart); + + if (*bcpup != bstart) { + err = au_cpup_dirs(dentry, *bcpup); + if (unlikely(err)) + goto out; + need_wh = 1; + } else { + aufs_bindex_t old_bend, new_bend, bdiropq = -1; + old_bend = au_dbend(dentry); + if (isdir) { + bdiropq = au_dbdiropq(dentry); + au_set_dbdiropq(dentry, -1); + } + need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0, + /*nd*/NULL); + err = need_wh; + if (isdir) + au_set_dbdiropq(dentry, bdiropq); + if (unlikely(err < 0)) + goto out; + new_bend = au_dbend(dentry); + if (!need_wh && old_bend != new_bend) { + au_set_h_dptr(dentry, new_bend, NULL); + au_set_dbend(dentry, old_bend); +#if 0 /* todo: remove this? */ + } else if (!au_h_dptr(dentry, new_bend)->d_inode) { + LKTRTrace("negative\n"); + au_set_h_dptr(dentry, new_bend, NULL); + au_set_dbend(dentry, old_bend); + need_wh = 0; +#endif + } + } + LKTRTrace("need_wh %d\n", need_wh); + err = need_wh; + + out: + AuTraceErr(err); + return err; +} + +/* + * simple tests for the removal inode operations. + * following the checks in vfs, plus the parent-child relationship. + */ +int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_parent, int isdir, struct au_ndx *ndx) +{ + int err, exist; + struct super_block *sb; + struct dentry *h_dentry; + struct inode *h_inode; + umode_t h_mode; + + LKTRTrace("%.*s/%.*s, b%d, dir %d\n", + AuDLNPair(h_parent), AuDLNPair(dentry), bindex, isdir); + + sb = dentry->d_sb; + exist = !!dentry->d_inode; + h_dentry = au_h_dptr(dentry, bindex); + h_inode = h_dentry->d_inode; + if (exist) { + err = -ENOENT; + if (unlikely(!h_inode || !h_inode->i_nlink)) + goto out; + + h_mode = h_inode->i_mode; + if (!isdir) { + err = -EISDIR; + if (unlikely(S_ISDIR(h_mode))) + goto out; + } else if (unlikely(!S_ISDIR(h_mode))) { + err = -ENOTDIR; + goto out; + } + } else { + /* rename(2) case */ + err = -EIO; + if (unlikely(h_inode)) + goto out; + } + + err = -ENOENT; + /* expected parent dir is locked */ + if (unlikely(h_parent != h_dentry->d_parent)) + goto out; + err = 0; + + /* + * some filesystem may unlink a dir and corrupt its consistency. + * so let's try heavy test. + */ + if (1 /*unlikely(au_opt_test(au_mntflags(sb), UDBA_INOTIFY))*/) { + struct dentry *h_latest; + struct qstr *qstr = &dentry->d_name; + + err = -EACCES; + if (unlikely(au_test_h_perm(h_parent->d_inode, + MAY_EXEC | MAY_WRITE, + au_ftest_ndx(ndx->flags, DLGT)))) + goto out; + + h_latest = au_sio_lkup_one(qstr->name, h_parent, qstr->len, + ndx); + err = -EIO; + if (IS_ERR(h_latest)) + goto out; + dput(h_latest); + if (h_latest == h_dentry) + err = 0; + } + + out: + AuTraceErr(err); + return err; +} + +static struct dentry * +lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup, + struct au_dtime *dt, struct au_pin *pin) +{ + struct dentry *wh_dentry; + int err, need_wh; + struct dentry *h_parent; + struct au_ndx ndx; + struct super_block *sb; + aufs_bindex_t bcpup; + unsigned int mnt_flags; + + LKTRTrace("%.*s, isdir %d\n", AuDLNPair(dentry), isdir); + + need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup); + err = need_wh; + wh_dentry = ERR_PTR(err); + if (unlikely(err < 0)) + goto out; + + sb = dentry->d_sb; + mnt_flags = au_mntflags(sb); + bcpup = *rbcpup; + err = au_pin(pin, dentry, bcpup, /*di_locked*/1, + /*do_gp*/au_opt_test(mnt_flags, UDBA_INOTIFY)); + wh_dentry = ERR_PTR(err); + if (unlikely(err)) + goto out; + h_parent = au_pinned_h_parent(pin, bcpup); + if (!au_opt_test(mnt_flags, UDBA_NONE) && au_dbstart(dentry) == bcpup) { + ndx.nfsmnt = au_nfsmnt(sb, bcpup); + ndx.flags = 0; + if (unlikely(au_test_dlgt(mnt_flags))) + au_fset_ndx(ndx.flags, DLGT); + ndx.nd = NULL; + /* ndx.br = au_sbr(sb, bcpup); */ + /* ndx.nd_file = NULL; */ + err = au_may_del(dentry, bcpup, h_parent, isdir, &ndx); + wh_dentry = ERR_PTR(err); + if (unlikely(err)) + goto out_unpin; + } + + au_dtime_store(dt, au_pinned_parent(pin), h_parent, + au_pinned_hdir(pin, bcpup), au_pinned_hgdir(pin, bcpup)); + wh_dentry = NULL; + if (!need_wh) + goto out; /* success, no need to create whiteout */ + + ndx.nfsmnt = au_nfsmnt(sb, bcpup); + ndx.flags = 0; + if (unlikely(au_test_dlgt(mnt_flags))) + au_fset_ndx(ndx.flags, DLGT); + ndx.nd = NULL; + /* ndx.br = NULL; */ + wh_dentry = au_wh_create(dentry, bcpup, h_parent, &ndx); + if (!IS_ERR(wh_dentry)) + goto out; /* success */ + /* returns with the parent is locked and wh_dentry is DGETed */ + + out_unpin: + au_unpin(pin); + out: + AuTraceErrPtr(wh_dentry); + return wh_dentry; +} + +static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex, + struct au_nhash *whlist, struct inode *dir) +{ + int rmdir_later, err; + struct dentry *h_dentry; + struct inode *inode, *h_inode; + struct super_block *sb; + + LKTRTrace("%.*s, b%d\n", AuDLNPair(dentry), bindex); + + inode = NULL; + h_inode = NULL; + sb = dentry->d_sb; + if (unlikely(au_opt_test(au_mntflags(sb), UDBA_INOTIFY))) { + inode = dentry->d_inode; + h_inode = au_h_iptr(inode, bindex); + mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); + } + h_dentry = au_h_dptr(dentry, bindex); + err = au_whtmp_ren(dir, bindex, h_dentry); + if (unlikely(inode)) { + /* todo: bad approach? */ + if (!err) + au_hin_suspend(au_hi(inode, bindex)); + mutex_unlock(&h_inode->i_mutex); + } + if (unlikely(err)) + goto out; + + if (!au_test_nfs(h_dentry->d_sb)) { + const int dirwh = au_sbi(sb)->si_dirwh; + rmdir_later = (dirwh <= 1); + if (!rmdir_later) + rmdir_later = au_nhash_test_longer_wh(whlist, bindex, + dirwh); + if (rmdir_later) + return rmdir_later; + } + + err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist); + if (unlikely(err)) { + AuIOErr("rmdir %.*s, b%d failed, %d. ignored\n", + AuDLNPair(h_dentry), bindex, err); + /* we do not revert the inotify watch */ + err = 0; + } + + out: + AuTraceErr(err); + return err; +} + +static void epilog(struct inode *dir, struct dentry *dentry, + aufs_bindex_t bindex) +{ + /* todo: unnecessary? */ + d_drop(dentry); + dentry->d_inode->i_ctime = dir->i_ctime; + + if (atomic_read(&dentry->d_count) == 1) { + au_set_h_dptr(dentry, au_dbstart(dentry), NULL); + au_update_dbstart(dentry); + } + if (au_ibstart(dir) == bindex) + au_cpup_attr_timesizes(dir); + dir->i_version++; +} + +/* revert flags */ +#define AuRev_DLGT 1 +#define au_ftest_rev(flags, name) ((flags) & AuRev_##name) +#define au_fset_rev(flags, name) { (flags) |= AuRev_##name; } +#define au_fclr_rev(flags, name) { (flags) &= ~AuRev_##name; } +#ifndef CONFIG_AUFS_DLGT +#undef AuRev_DLGT +#define AuRev_DLGT 0 +#endif + +static int do_revert(int err, struct inode *dir, aufs_bindex_t bwh, + struct dentry *wh_dentry, struct dentry *dentry, + struct au_dtime *dt, unsigned int flags) +{ + int rerr; + + rerr = au_wh_unlink_dentry(au_hi(dir, bwh), wh_dentry, dentry, + au_ftest_rev(flags, DLGT)); + if (!rerr) { + au_set_dbwh(dentry, bwh); + au_dtime_revert(dt); + return 0; + } + + AuIOErr("%.*s reverting whiteout failed(%d, %d)\n", + AuDLNPair(dentry), err, rerr); + return -EIO; +} + +/* ---------------------------------------------------------------------- */ + +int aufs_unlink(struct inode *dir, struct dentry *dentry) +{ + int err; + struct inode *inode, *h_dir; + struct dentry *parent, *wh_dentry, *h_dentry; + struct au_dtime dt; + aufs_bindex_t bwh, bindex, bstart; + unsigned char dlgt; + struct super_block *sb; + struct au_hin_ignore ign; + struct vfsub_args vargs; + struct au_pin pin; + + LKTRTrace("i%lu, %.*s\n", dir->i_ino, AuDLNPair(dentry)); + IMustLock(dir); + inode = dentry->d_inode; + if (unlikely(!inode)) + return -ENOENT; /* possible? */ + IMustLock(inode); + + aufs_read_lock(dentry, AuLock_DW); + parent = dentry->d_parent; /* dir inode is locked */ + di_write_lock_parent(parent); + + bstart = au_dbstart(dentry); + bwh = au_dbwh(dentry); + bindex = -1; + wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &dt, &pin); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out; + + sb = dir->i_sb; + dlgt = !!au_test_dlgt(au_mntflags(sb)); + AuDebugOn(au_dbstart(dentry) != bstart); + h_dentry = au_h_dptr(dentry, bstart); + dget(h_dentry); + + if (bindex == bstart) { + vfsub_args_init(&vargs, &ign, dlgt, 0); + vfsub_ign_hinode(&vargs, IN_DELETE, au_pinned_hdir(&pin, + bstart)); + h_dir = au_pinned_h_dir(&pin); + err = vfsub_unlink(h_dir, h_dentry, &vargs); + } else { + /* dir inode is locked */ + AuDebugOn(!wh_dentry + || wh_dentry->d_parent != au_h_dptr(parent, bindex)); + h_dir = wh_dentry->d_parent->d_inode; + IMustLock(h_dir); + err = 0; + } + + if (!err) { + drop_nlink(inode); +#if 0 /* todo: update plink? */ + if (unlikely(!inode->i_nlink + && au_plink_test(sb, inode) + /* && atomic_read(&inode->i_count) == 2) */)) { + au_debug_on(); + DbgInode(inode); + au_debug_off(); + } +#endif +#if 0 + /* + * although this is not a dir, + * set it here since we need to detect + * the dead inode in d_revalidate(). + */ + if (!inode->i_nlink) + inode->i_flags |= S_DEAD; +#endif + epilog(dir, dentry, bindex); + + /* update target timestamps */ + if (bindex == bstart) { + au_update_fuse_h_inode(NULL, h_dentry); /*ignore*/ + inode->i_ctime = h_dentry->d_inode->i_ctime; + } else + /* todo: this timestamp may be reverted later */ + inode->i_ctime = h_dir->i_ctime; + goto out_unlock; /* success */ + } + + /* revert */ + if (wh_dentry) { + int rerr; + unsigned int rev_flags; + + rev_flags = 0; + if (unlikely(dlgt)) + au_fset_rev(rev_flags, DLGT); + rerr = do_revert(err, dir, bwh, wh_dentry, dentry, &dt, + rev_flags); + if (rerr) + err = rerr; + } + + out_unlock: + au_unpin(&pin); + dput(wh_dentry); + dput(h_dentry); + out: + di_write_unlock(parent); + aufs_read_unlock(dentry, AuLock_DW); + AuTraceErr(err); + return err; +} + +int aufs_rmdir(struct inode *dir, struct dentry *dentry) +{ + int err, rmdir_later; + struct inode *inode; + struct dentry *parent, *wh_dentry, *h_dentry; + struct au_dtime dt; + aufs_bindex_t bwh, bindex, bstart; + struct au_whtmp_rmdir_args *args; + struct au_nhash *whlist; + struct super_block *sb; + unsigned int mnt_flags; + struct au_pin pin; + + LKTRTrace("i%lu, %.*s\n", dir->i_ino, AuDLNPair(dentry)); + IMustLock(dir); +#if 0 + err = -ENOENT; /* possible? */ + if (unlikely(IS_DEADDIR(dir))) { + AuDbg("here\n"); + goto out; + } +#endif + inode = dentry->d_inode; + err = -ENOENT; /* possible? */ + if (unlikely(!inode + //|| IS_DEADDIR(inode) || IS_DEADDIR(dir) + )) { + //AuDbg("here\n"); + goto out; + } + IMustLock(inode); + + whlist = au_nhash_new(GFP_NOFS); + err = PTR_ERR(whlist); + if (IS_ERR(whlist)) + goto out; + + err = -ENOMEM; + args = kmalloc(sizeof(*args), GFP_NOFS); + if (unlikely(!args)) + goto out_whlist; + + aufs_read_lock(dentry, AuLock_DW); + parent = dentry->d_parent; /* dir inode is locked */ + di_write_lock_parent(parent); + err = au_test_empty(dentry, whlist); + if (unlikely(err)) + goto out_args; + + bstart = au_dbstart(dentry); + bwh = au_dbwh(dentry); + bindex = -1; + wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &dt, &pin); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out_args; + + AuDebugOn(au_dbstart(dentry) != bstart); + h_dentry = au_h_dptr(dentry, bstart); + dget(h_dentry); + + rmdir_later = 0; + if (bindex == bstart) { + err = renwh_and_rmdir(dentry, bstart, whlist, dir); + if (err > 0) { + rmdir_later = err; + err = 0; + } + } else { + /* dir inode is locked */ + AuDebugOn(!wh_dentry + || wh_dentry->d_parent != au_h_dptr(parent, bindex)); + IMustLock(wh_dentry->d_parent->d_inode); + err = 0; + } + + sb = dentry->d_sb; + mnt_flags = au_mntflags(sb); + if (!err) { + if (unlikely(au_opt_test(mnt_flags, UDBA_INOTIFY) + && rmdir_later)) + au_reset_hinotify(inode, /*flags*/0); + clear_nlink(inode); + //inode->i_flags |= S_DEAD; + au_set_dbdiropq(dentry, -1); + epilog(dir, dentry, bindex); + + if (rmdir_later) { + au_whtmp_kick_rmdir(dir, bstart, h_dentry, whlist, + args); + args = NULL; + } + + goto out_unlock; /* success */ + } + + /* revert */ + LKTRLabel(revert); + if (wh_dentry) { + int rerr; + unsigned int rev_flags; + + rev_flags = 0; + if (unlikely(au_test_dlgt(mnt_flags))) + au_fset_rev(rev_flags, DLGT); + rerr = do_revert(err, dir, bwh, wh_dentry, dentry, &dt, + rev_flags); + if (rerr) + err = rerr; + } + + out_unlock: + au_unpin(&pin); + dput(wh_dentry); + dput(h_dentry); + out_args: + di_write_unlock(parent); + aufs_read_unlock(dentry, AuLock_DW); + kfree(args); + out_whlist: + au_nhash_del(whlist); + out: + AuTraceErr(err); + return err; +} --- linux-2.6.27.orig/ubuntu/aufs/file.h +++ linux-2.6.27/ubuntu/aufs/file.h @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * file operations + * + * $Id: file.h,v 1.5 2008/06/30 03:53:43 sfjro Exp $ + */ + +#ifndef __AUFS_FILE_H__ +#define __AUFS_FILE_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include "dentry.h" +#include "misc.h" +#include "super.h" + +/* ---------------------------------------------------------------------- */ + +struct au_branch; +struct au_hfile { + struct file *hf_file; + struct au_branch *hf_br; +}; + +struct au_vdir; +struct au_finfo { + atomic_t fi_generation; + + struct au_rwsem fi_rwsem; + struct au_hfile *fi_hfile; + aufs_bindex_t fi_bstart, fi_bend; + + union { + struct vm_operations_struct *fi_h_vm_ops; + struct au_vdir *fi_vdir_cache; + }; +}; + +/* ---------------------------------------------------------------------- */ + +/* file.c */ +extern struct address_space_operations aufs_aop; +unsigned int au_file_roflags(unsigned int flags); +struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, + struct file *file); +int au_do_open(struct inode *inode, struct file *file, + int (*open)(struct file *file, int flags)); +int au_reopen_nondir(struct file *file); +struct au_pin; +int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin); +int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), + int wlock, int locked); + +/* f_op.c */ +extern struct file_operations aufs_file_fop; +int aufs_flush(struct file *file, fl_owner_t id); + +/* finfo.c */ +struct au_finfo *au_fi(struct file *file); +struct au_branch *au_fbr(struct file *file, aufs_bindex_t bindex); +struct file *au_h_fptr(struct file *file, aufs_bindex_t bindex); + +void au_hfput(struct au_hfile *hf); +void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, + struct file *h_file); + +void au_finfo_fin(struct file *file); +int au_finfo_init(struct file *file); + +#ifdef CONFIG_AUFS_ROBR +/* robr.c */ +struct file *au_robr_safe_file(struct vm_area_struct *vma); +void au_robr_reset_file(struct vm_area_struct *vma, struct file *file); +#else +static inline struct file *au_robr_safe_file(struct vm_area_struct *vma) +{ + struct file *file; + + file = vma->vm_file; + if (file->private_data && au_test_aufs(file->f_dentry->d_sb)) + return file; + return NULL; +} + +static inline +void au_robr_reset_file(struct vm_area_struct *vma, struct file *file) +{ + vma->vm_file = file; + /* smp_mb(); */ /* flush vm_file */ +} +#endif /* CONFIG_AUFS_ROBR */ + +/* ---------------------------------------------------------------------- */ + +/* todo: memory barrier? */ +static inline au_gen_t au_figen(struct file *f) +{ + return atomic_read(&au_fi(f)->fi_generation); +} + +static inline int au_test_mmapped(struct file *f) +{ + return !!(au_fi(f)->fi_h_vm_ops); +} + +static inline int au_test_aufs_file(struct file *f) +{ + return !(f->f_dentry->d_inode->i_mode + & (S_IFCHR | S_IFBLK | S_IFIFO | S_IFSOCK)); +} + +/* ---------------------------------------------------------------------- */ + +#if !defined(CONFIG_AUFS_MODULE) || defined(CONFIG_AUFS_DENY_WRITE_ACCESS_PATCH) +int au_store_fmode_exec(struct nameidata *nd, struct inode *inode); + +static inline int au_deny_write_access(struct file *h_file) +{ + LKTRTrace("%.*s\n", AuDLNPair(h_file->f_dentry)); + return deny_write_access(h_file); +} + +static inline void au_allow_write_access(struct file *h_file) +{ + allow_write_access(h_file); +} + +#else + +static inline int au_store_fmode_exec(struct nameidata *nd, struct inode *inode) +{ + /* nothing */ + return 0; +} + +static inline int au_deny_write_access(struct file *h_file) +{ + /* nothing */ + return 0; +} + +static inline void au_allow_write_access(struct file *h_file) +{ + /* nothing */ +} +#endif /* CONFIG_AUFS_DENY_WRITE_ACCESS_PATCH */ + +/* ---------------------------------------------------------------------- */ + +/* + * fi_read_lock, fi_write_lock, + * fi_read_unlock, fi_write_unlock, fi_downgrade_lock + */ +AuSimpleRwsemFuncs(fi, struct file *f, au_fi(f)->fi_rwsem); + +/* to debug easier, do not make them inlined functions */ +#define FiMustReadLock(f) do { \ + SiMustAnyLock((f)->f_dentry->d_sb); \ + AuRwMustReadLock(&au_fi(f)->fi_rwsem); \ +} while (0) + +#define FiMustWriteLock(f) do { \ + SiMustAnyLock((f)->f_dentry->d_sb); \ + AuRwMustWriteLock(&au_fi(f)->fi_rwsem); \ +} while (0) + +#define FiMustAnyLock(f) do { \ + SiMustAnyLock((f)->f_dentry->d_sb); \ + AuRwMustAnyLock(&au_fi(f)->fi_rwsem); \ +} while (0) + +#define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem) + +/* ---------------------------------------------------------------------- */ + +/* todo: hard/soft set? */ +static inline aufs_bindex_t au_fbstart(struct file *file) +{ + FiMustAnyLock(file); + return au_fi(file)->fi_bstart; +} + +static inline aufs_bindex_t au_fbend(struct file *file) +{ + FiMustAnyLock(file); + return au_fi(file)->fi_bend; +} + +static inline struct au_vdir *au_fvdir_cache(struct file *file) +{ + FiMustAnyLock(file); + return au_fi(file)->fi_vdir_cache; +} + +static inline void au_set_fbstart(struct file *file, aufs_bindex_t bindex) +{ + FiMustWriteLock(file); + AuDebugOn(au_sbend(file->f_dentry->d_sb) < bindex); + au_fi(file)->fi_bstart = bindex; +} + +static inline void au_set_fbend(struct file *file, aufs_bindex_t bindex) +{ + FiMustWriteLock(file); + AuDebugOn(au_sbend(file->f_dentry->d_sb) < bindex + || bindex < au_fbstart(file)); + au_fi(file)->fi_bend = bindex; +} + +static inline void au_set_fvdir_cache(struct file *file, + struct au_vdir *vdir_cache) +{ + FiMustWriteLock(file); + AuDebugOn(!S_ISDIR(file->f_dentry->d_inode->i_mode) + || (au_fi(file)->fi_vdir_cache && vdir_cache)); + au_fi(file)->fi_vdir_cache = vdir_cache; +} + +static inline void au_update_figen(struct file *file) +{ + atomic_set(&au_fi(file)->fi_generation, au_digen(file->f_dentry)); + /* smp_mb(); */ /* atomic_set */ +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_FILE_H__ */ --- linux-2.6.27.orig/ubuntu/aufs/f_op.c +++ linux-2.6.27/ubuntu/aufs/f_op.c @@ -0,0 +1,670 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * file and vm operations + * + * $Id: f_op.c,v 1.11 2008/09/01 02:55:44 sfjro Exp $ + */ + +#include +#include +#include "aufs.h" + +/* common function to regular file and dir */ +int aufs_flush(struct file *file, fl_owner_t id) +{ + int err; + struct dentry *dentry; + aufs_bindex_t bindex, bend; + struct file *h_file; + + dentry = file->f_dentry; + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + + si_noflush_read_lock(dentry->d_sb); + fi_read_lock(file); + di_read_lock_child(dentry, AuLock_IW); + + err = 0; + bend = au_fbend(file); + for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) { + h_file = au_h_fptr(file, bindex); + if (h_file && h_file->f_op && h_file->f_op->flush) { + err = h_file->f_op->flush(h_file, id); + if (!err) + au_update_fuse_h_inode + (h_file->f_vfsmnt, h_file->f_dentry); + /*ignore*/ + } + } + au_cpup_attr_timesizes(dentry->d_inode); + + di_read_unlock(dentry, AuLock_IW); + fi_read_unlock(file); + si_read_unlock(dentry->d_sb); + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int do_open_nondir(struct file *file, int flags) +{ + int err; + aufs_bindex_t bindex; + struct super_block *sb; + struct file *h_file; + struct dentry *dentry; + struct inode *inode; + struct au_finfo *finfo; + + dentry = file->f_dentry; + LKTRTrace("%.*s, flags 0%o\n", AuDLNPair(dentry), flags); + FiMustWriteLock(file); + inode = dentry->d_inode; + AuDebugOn(!inode || S_ISDIR(inode->i_mode)); + + err = 0; + finfo = au_fi(file); + finfo->fi_h_vm_ops = NULL; + sb = dentry->d_sb; + bindex = au_dbstart(dentry); + AuDebugOn(!au_h_dptr(dentry, bindex)->d_inode); + /* O_TRUNC is processed already */ + BUG_ON(au_test_ro(sb, bindex, inode) && (flags & O_TRUNC)); + + h_file = au_h_open(dentry, bindex, flags, file); + if (IS_ERR(h_file)) + err = PTR_ERR(h_file); + else { + au_set_fbstart(file, bindex); + au_set_fbend(file, bindex); + au_set_h_fptr(file, bindex, h_file); + au_update_figen(file); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + err = 0; + } + AuTraceErr(err); + return err; +} + +static int aufs_open_nondir(struct inode *inode, struct file *file) +{ + LKTRTrace("i%lu, %.*s\n", inode->i_ino, AuDLNPair(file->f_dentry)); + + return au_do_open(inode, file, do_open_nondir); +} + +static int aufs_release_nondir(struct inode *inode, struct file *file) +{ + struct super_block *sb = file->f_dentry->d_sb; + + LKTRTrace("i%lu, %.*s\n", inode->i_ino, AuDLNPair(file->f_dentry)); + + si_noflush_read_lock(sb); + au_finfo_fin(file); + si_read_unlock(sb); + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static ssize_t aufs_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + ssize_t err; + struct dentry *dentry; + struct file *h_file; + struct super_block *sb; + struct inode *h_inode; + + dentry = file->f_dentry; + LKTRTrace("%.*s, cnt %lu, pos %lld\n", + AuDLNPair(dentry), (unsigned long)count, *ppos); + + sb = dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0, + /*locked*/0); + if (unlikely(err)) + goto out; + + /* support LSM and notify */ + h_file = au_h_fptr(file, au_fbstart(file)); + h_inode = h_file->f_dentry->d_inode; + err = vfsub_read_u(h_file, buf, count, ppos, + au_test_dlgt(au_mntflags(sb))); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode); + + di_read_unlock(dentry, AuLock_IR); + fi_read_unlock(file); + out: + si_read_unlock(sb); + AuTraceErr(err); + return err; +} + +static ssize_t aufs_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + ssize_t err; + struct dentry *dentry; + struct inode *inode; + struct super_block *sb; + unsigned int mnt_flags; + struct file *h_file; + char __user *buf = (char __user *)ubuf; + struct au_hin_ignore ign; + struct vfsub_args vargs; + aufs_bindex_t bstart; + int hinotify; + struct au_pin pin; + + dentry = file->f_dentry; + LKTRTrace("%.*s, cnt %lu, pos %lld\n", + AuDLNPair(dentry), (unsigned long)count, *ppos); + + inode = dentry->d_inode; + mutex_lock(&inode->i_mutex); + sb = dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + mnt_flags = au_mntflags(sb); + hinotify = !!au_opt_test(mnt_flags, UDBA_INOTIFY); + vfsub_args_init(&vargs, &ign, au_test_dlgt(mnt_flags), 0); + + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1, + /*locked*/1); + if (unlikely(err)) + goto out; + err = au_ready_to_write(file, -1, &pin); + di_downgrade_lock(dentry, AuLock_IR); + if (unlikely(err)) + goto out_unlock; + + bstart = au_fbstart(file); + h_file = au_h_fptr(file, bstart); + if (!hinotify) { + au_unpin(&pin); + err = vfsub_write_u(h_file, buf, count, ppos, &vargs); + } else { + vfsub_ign_hinode(&vargs, IN_MODIFY, + au_pinned_hdir(&pin, bstart)); + err = vfsub_write_u(h_file, buf, count, ppos, &vargs); + au_unpin(&pin); + } + au_cpup_attr_timesizes(inode); + + out_unlock: + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); + out: + si_read_unlock(sb); + mutex_unlock(&inode->i_mutex); + AuTraceErr(err); + return err; +} + +#ifdef CONFIG_AUFS_SPLICE_PATCH +static int au_test_loopback(void) +{ + const char c = current->comm[4]; + /* true if a kernel thread named 'loop[0-9].*' accesses a file */ + const int loopback = (current->mm == NULL + && '0' <= c && c <= '9' + && strncmp(current->comm, "loop", 4) == 0); + return loopback; +} + +static ssize_t aufs_splice_read(struct file *file, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags) +{ + ssize_t err; + struct file *h_file; + struct dentry *dentry; + struct super_block *sb; + + dentry = file->f_dentry; + LKTRTrace("%.*s, pos %lld, len %lu\n", + AuDLNPair(dentry), *ppos, (unsigned long)len); + + sb = dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0, + /*locked*/0); + if (unlikely(err)) + goto out; + + err = -EINVAL; + /* support LSM and notify */ + h_file = au_h_fptr(file, au_fbstart(file)); + if (/* unlikely */(au_test_loopback())) { + file->f_mapping = h_file->f_mapping; + smp_mb(); /* unnecessary? */ + } + err = vfsub_splice_to(h_file, ppos, pipe, len, flags, + au_test_dlgt(au_mntflags(sb))); + /* todo: necessasry? */ + /* file->f_ra = h_file->f_ra; */ + fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode); + di_read_unlock(dentry, AuLock_IR); + fi_read_unlock(file); + + out: + si_read_unlock(sb); + AuTraceErr(err); + return err; +} + +static ssize_t +aufs_splice_write(struct pipe_inode_info *pipe, struct file *file, loff_t *ppos, + size_t len, unsigned int flags) +{ + ssize_t err; + struct dentry *dentry; + struct inode *inode, *h_inode; + struct super_block *sb; + struct file *h_file; + /* struct au_hin_ignore ign; */ + struct vfsub_args vargs; + unsigned int mnt_flags; + struct au_pin pin; + + dentry = file->f_dentry; + LKTRTrace("%.*s, len %lu, pos %lld\n", + AuDLNPair(dentry), (unsigned long)len, *ppos); + + inode = dentry->d_inode; + mutex_lock(&inode->i_mutex); + sb = dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + mnt_flags = au_mntflags(sb); + vfsub_args_init(&vargs, /*&ign*/NULL, au_test_dlgt(mnt_flags), 0); + + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1, + /*locked*/1); + if (unlikely(err)) + goto out; + err = au_ready_to_write(file, -1, &pin); + di_downgrade_lock(dentry, AuLock_IR); + if (unlikely(err)) + goto out_unlock; + + /* support LSM and notify */ + /* current vfs_splice_from() doesn't fire up the inotify event */ + h_file = au_h_fptr(file, au_fbstart(file)); + h_inode = h_file->f_dentry->d_inode; + if (1 || !au_opt_test(mnt_flags, UDBA_INOTIFY)) { + au_unpin(&pin); + err = vfsub_splice_from(pipe, h_file, ppos, len, flags, &vargs); + } +#if 0 /* reserved for future use */ + else { + struct dentry *parent = dget_parent(dentry); + vfsub_ign_hinode(&vargs, IN_MODIFY, + au_pinned_hdir(&pin, bstart)); + err = vfsub_splice_from(pipe, h_file, ppos, len, flags, &vargs); + au_unpin(&pin); + } +#endif + au_cpup_attr_timesizes(inode); + + out_unlock: + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); + out: + si_read_unlock(sb); + mutex_unlock(&inode->i_mutex); + AuTraceErr(err); + return err; +} +#endif /* CONFIG_AUFS_SPLICE_PATCH */ + +/* ---------------------------------------------------------------------- */ + +static int aufs_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + int err; + struct dentry *dentry; + struct file *file, *h_file; + struct inode *inode; + static DECLARE_WAIT_QUEUE_HEAD(wq); + struct au_finfo *finfo; + + AuTraceEnter(); + AuDebugOn(!vma || !vma->vm_file); + /* todo: non-robr mode, user vm_file as it is? */ + wait_event(wq, (file = au_robr_safe_file(vma))); + AuDebugOn(!au_test_aufs(file->f_dentry->d_sb)); + dentry = file->f_dentry; + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + inode = dentry->d_inode; + AuDebugOn(!S_ISREG(inode->i_mode)); + + /* do not revalidate, no si lock */ + finfo = au_fi(file); + h_file = finfo->fi_hfile[0 + finfo->fi_bstart].hf_file; + AuDebugOn(!h_file || !au_test_mmapped(file)); + fi_write_lock(file); + vma->vm_file = h_file; + err = finfo->fi_h_vm_ops->fault(vma, vmf); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + au_robr_reset_file(vma, file); + fi_write_unlock(file); +#if 0 /* def CONFIG_SMP */ + /* wake_up_nr(&wq, online_cpu - 1); */ + wake_up_all(&wq); +#else + wake_up(&wq); +#endif + + if (!(err & VM_FAULT_ERROR)) { +#if 0 /* debug */ + struct page *page; + page = vmf->page; + AuDbg("%p, %d\n", page, page_mapcount(page)); + + page->mapping = file->f_mapping; + get_page(page); + file->f_mapping = h_file->f_mapping; + touch_atime(NULL, dentry); + inode->i_atime = h_file->f_dentry->d_inode->i_atime; +#endif + } + AuTraceErr(err); + return err; +} + +static struct vm_operations_struct aufs_vm_ops = { + .fault = aufs_fault, +#if 0 /* reserved for future use */ + .open = aufs_vmaopen, + .close = aufs_vmaclose, + unsigned long (*nopfn)(struct vm_area_struct *area, + unsigned long address); + page_mkwrite(struct vm_area_struct *vma, struct page *page) +#endif +}; + +/* ---------------------------------------------------------------------- */ + +static struct vm_operations_struct *au_vm_ops(struct file *h_file, + struct vm_area_struct *vma) +{ + struct vm_operations_struct *vm_ops; + int err; + + AuTraceEnter(); + + au_br_nfs_lockdep_off(h_file->f_vfsmnt->mnt_sb); + err = h_file->f_op->mmap(h_file, vma); + au_br_nfs_lockdep_on(h_file->f_vfsmnt->mnt_sb); + vm_ops = ERR_PTR(err); + if (unlikely(err)) + goto out; + vm_ops = vma->vm_ops; + err = do_munmap(current->mm, vma->vm_start, + vma->vm_end - vma->vm_start); + if (unlikely(err)) { + AuIOErr("failed internal unmapping %.*s, %d\n", + AuDLNPair(h_file->f_dentry), err); + vm_ops = ERR_PTR(-EIO); + } + + out: + AuTraceErrPtr(vm_ops); + return vm_ops; +} + +static int aufs_mmap(struct file *file, struct vm_area_struct *vma) +{ + int err; + unsigned char wlock, mmapped; + struct dentry *dentry; + struct super_block *sb; + struct file *h_file; + struct vm_operations_struct *vm_ops; + + dentry = file->f_dentry; + LKTRTrace("%.*s, %lx, len %lu\n", + AuDLNPair(dentry), vma->vm_start, + vma->vm_end - vma->vm_start); + AuDebugOn(!S_ISREG(dentry->d_inode->i_mode)); + AuDebugOn(down_write_trylock(&vma->vm_mm->mmap_sem)); + + mmapped = au_test_mmapped(file); /* can be harmless race condition */ + wlock = !!(file->f_mode & FMODE_WRITE); + sb = dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + err = au_reval_and_lock_fdi(file, au_reopen_nondir, wlock | !mmapped, + /*locked*/0); + if (unlikely(err)) + goto out; + + if (wlock) { + struct au_pin pin; + + err = au_ready_to_write(file, -1, &pin); + di_downgrade_lock(dentry, AuLock_IR); + if (unlikely(err)) + goto out_unlock; + au_unpin(&pin); + } else if (!mmapped) + di_downgrade_lock(dentry, AuLock_IR); + + h_file = au_h_fptr(file, au_fbstart(file)); + if (unlikely(au_test_fuse(h_file->f_dentry->d_sb))) { + /* + * by this assignment, f_mapping will differs from aufs inode + * i_mapping. + * if someone else mixes the use of f_dentry->d_inode and + * f_mapping->host, then a problem may arise. + */ + file->f_mapping = h_file->f_mapping; + } + + if (0 && h_file->f_op->mmap == generic_file_mmap) { + err = generic_file_mmap(file, vma); /* instead of h_file */ + if (unlikely(err)) + goto out_unlock; + au_fi(file)->fi_h_vm_ops = vma->vm_ops; + } else { + vm_ops = NULL; + if (!mmapped) { + vm_ops = au_vm_ops(h_file, vma); + err = PTR_ERR(vm_ops); + if (IS_ERR(vm_ops)) + goto out_unlock; + } + + err = generic_file_mmap(file, vma); + if (unlikely(err)) + goto out_unlock; + vma->vm_ops = &aufs_vm_ops; + /* test again */ + if (!au_test_mmapped(file)) { + FiMustWriteLock(file); + au_fi(file)->fi_h_vm_ops = vm_ops; + } + } + + file_accessed(h_file); + au_update_fuse_h_inode(h_file->f_vfsmnt, h_file->f_dentry); /*ignore*/ + fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode); + + out_unlock: + di_read_unlock(dentry, AuLock_IR); + if (!wlock && mmapped) + fi_read_unlock(file); + else + fi_write_unlock(file); + out: + si_read_unlock(sb); + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static unsigned int aufs_poll(struct file *file, poll_table *wait) +{ + unsigned int mask; + struct file *h_file; + int err; + struct dentry *dentry; + struct super_block *sb; + + dentry = file->f_dentry; + LKTRTrace("%.*s, wait %p\n", AuDLNPair(dentry), wait); + AuDebugOn(S_ISDIR(dentry->d_inode->i_mode)); + + /* We should pretend an error happened. */ + mask = POLLERR /* | POLLIN | POLLOUT */; + sb = dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0, + /*locked*/0); + if (unlikely(err)) + goto out; + + /* it is not an error of hidden_file has no operation */ + mask = DEFAULT_POLLMASK; + h_file = au_h_fptr(file, au_fbstart(file)); + if (h_file->f_op && h_file->f_op->poll) + mask = h_file->f_op->poll(h_file, wait); + di_read_unlock(dentry, AuLock_IR); + fi_read_unlock(file); + + out: + si_read_unlock(sb); + AuTraceErr((int)mask); + return mask; +} + +static int aufs_fsync_nondir(struct file *file, struct dentry *dentry, + int datasync) +{ + int err; + struct inode *inode; + struct file *h_file; + struct super_block *sb; + struct au_pin pin; + + LKTRTrace("%.*s, %d\n", AuDLNPair(dentry), datasync); + inode = dentry->d_inode; + + IMustLock(file->f_mapping->host); + if (unlikely(inode != file->f_mapping->host)) { + mutex_unlock(&file->f_mapping->host->i_mutex); + mutex_lock(&inode->i_mutex); + } + IMustLock(inode); + + sb = dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + err = 0; /* -EBADF; */ /* posix? */ + if (unlikely(!(file->f_mode & FMODE_WRITE))) + goto out; + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1, + /*locked*/1); + if (unlikely(err)) + goto out; + err = au_ready_to_write(file, -1, &pin); + di_downgrade_lock(dentry, AuLock_IR); + if (unlikely(err)) + goto out_unlock; + au_unpin(&pin); + + err = -EINVAL; + h_file = au_h_fptr(file, au_fbstart(file)); + if (h_file->f_op && h_file->f_op->fsync) { + struct mutex *h_mtx = &h_file->f_dentry->d_inode->i_mutex; + + mutex_lock_nested(h_mtx, AuLsc_I_CHILD); + err = h_file->f_op->fsync(h_file, h_file->f_dentry, datasync); + if (!err) + au_update_fuse_h_inode(h_file->f_vfsmnt, + h_file->f_dentry); + au_cpup_attr_timesizes(inode); + mutex_unlock(h_mtx); + } + + out_unlock: + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); + out: + si_read_unlock(sb); + if (unlikely(inode != file->f_mapping->host)) { + mutex_unlock(&inode->i_mutex); + mutex_lock(&file->f_mapping->host->i_mutex); + } + AuTraceErr(err); + return err; +} + +static int aufs_fasync(int fd, struct file *file, int flag) +{ + int err; + struct file *h_file; + struct dentry *dentry; + struct super_block *sb; + + dentry = file->f_dentry; + LKTRTrace("%.*s, %d\n", AuDLNPair(dentry), flag); + + sb = dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0, + /*locked*/0); + if (unlikely(err)) + goto out; + + h_file = au_h_fptr(file, au_fbstart(file)); + if (h_file->f_op && h_file->f_op->fasync) + err = h_file->f_op->fasync(fd, h_file, flag); + di_read_unlock(dentry, AuLock_IR); + fi_read_unlock(file); + + out: + si_read_unlock(sb); + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct file_operations aufs_file_fop = { + .read = aufs_read, + .write = aufs_write, + .poll = aufs_poll, + .mmap = aufs_mmap, + .open = aufs_open_nondir, + .flush = aufs_flush, + .release = aufs_release_nondir, + .fsync = aufs_fsync_nondir, + .fasync = aufs_fasync, +#ifdef CONFIG_AUFS_SPLICE_PATCH + .splice_write = aufs_splice_write, + .splice_read = aufs_splice_read, +#endif +}; --- linux-2.6.27.orig/ubuntu/aufs/dentry.c +++ linux-2.6.27/ubuntu/aufs/dentry.c @@ -0,0 +1,1023 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * lookup and dentry operations + * + * $Id: dentry.c,v 1.15 2008/09/22 03:52:06 sfjro Exp $ + */ + +#include "aufs.h" + +/* ---------------------------------------------------------------------- */ + +/* + * au_lkup_one() is a generic abstract entry function which calls + * lookup_one_len() or __lookup_hash() finally. it is some condisions that makes + * lookup complicated, which are nfs branch, open-intent and dlgt mode. + */ + +#if defined(CONFIG_AUFS_BR_NFS) || defined(CONFIG_AUFS_DLGT) +/* cf. lookup_one_len() in linux/fs/namei.c */ +struct dentry *au_lkup_one(const char *name, struct dentry *parent, int len, + struct au_ndx *ndx) +{ + struct dentry *dentry; + + LKTRTrace("%.*s/%.*s, ndx{%d, 0x%x}\n", + AuDLNPair(parent), len, name, !!ndx->nfsmnt, ndx->flags); + + ndx->nd_file = NULL; + if (!ndx->nfsmnt) + dentry = au_lkup_one_dlgt(name, parent, len, ndx->flags); + else + dentry = au_lkup_hash(name, parent, len, ndx); + + AuTraceErrPtr(dentry); + return dentry; +} +#endif /* CONFIG_AUFS_BR_NFS || CONFIG_AUFS_DLGT */ + +struct au_lkup_one_args { + struct dentry **errp; + const char *name; + struct dentry *parent; + int len; + struct au_ndx *ndx; +}; + +static void au_call_lkup_one(void *args) +{ + struct au_lkup_one_args *a = args; + *a->errp = au_lkup_one(a->name, a->parent, a->len, a->ndx); +} + +#define AuLkup_ALLOW_NEG 1 +#define AuLkup_DLGT (1 << 1) +#define AuLkup_DIRPERM1 (1 << 2) +#define au_ftest_lkup(flags, name) ((flags) & AuLkup_##name) +#define au_fset_lkup(flags, name) { (flags) |= AuLkup_##name; } +#define au_fclr_lkup(flags, name) { (flags) &= ~AuLkup_##name; } +#ifndef CONFIG_AUFS_DLGT +#undef AuLkup_DLGT +#define AuLkup_DLGT 0 +#undef AuLkup_DIRPERM1 +#define AuLkup_DIRPERM1 0 +#endif + +struct au_do_lookup_args { + unsigned int flags; + mode_t type; + struct nameidata *nd; +}; + +/* + * returns positive/negative dentry, NULL or an error. + * NULL means whiteout-ed or not-found. + */ +static /* noinline_for_stack */ +struct dentry *au_do_lookup(struct dentry *h_parent, struct dentry *dentry, + aufs_bindex_t bindex, struct qstr *wh_name, + struct au_do_lookup_args *args) +{ + struct dentry *h_dentry; + int err, wh_found, opq; + unsigned char wh_able; + struct inode *h_dir, *h_inode, *inode; + struct qstr *name; + struct super_block *sb; + unsigned int nd_flags; + struct au_ndx ndx = { + .flags = 0, + .nd = args->nd + }; + const int allow_neg = au_ftest_lkup(args->flags, ALLOW_NEG); + + LKTRTrace("%.*s/%.*s, b%d, {flags 0x%x, type 0%o, nd %d}\n", + AuDLNPair(h_parent), AuDLNPair(dentry), bindex, + args->flags, args->type, !!args->nd); + if (args->nd) + LKTRTrace("nd{0x%x}\n", args->nd->flags); + AuDebugOn(IS_ROOT(dentry)); + h_dir = h_parent->d_inode; + + nd_flags = 0; + wh_found = 0; + sb = dentry->d_sb; + ndx.nfsmnt = au_nfsmnt(sb, bindex); + if (unlikely(au_ftest_lkup(args->flags, DLGT))) + au_fset_ndx(ndx.flags, DLGT); + if (unlikely(au_ftest_lkup(args->flags, DIRPERM1))) + au_fset_ndx(ndx.flags, DIRPERM1); + LKTRTrace("nfsmnt %p\n", ndx.nfsmnt); + ndx.br = au_sbr(sb, bindex); + wh_able = !!au_br_whable(ndx.br->br_perm); + name = &dentry->d_name; + if (unlikely(wh_able)) + wh_found = au_test_robr_wh(name, h_parent, wh_name, + /*try_sio*/0, &ndx); + h_dentry = ERR_PTR(wh_found); + if (!wh_found) + goto real_lookup; + if (unlikely(wh_found < 0)) + goto out; + + /* We found a whiteout */ + /* au_set_dbend(dentry, bindex); */ + au_set_dbwh(dentry, bindex); + if (!allow_neg) + return NULL; /* success */ + if (unlikely(ndx.nd + && au_test_nfs(h_parent->d_sb) + && (ndx.nd->flags & LOOKUP_CREATE))) { + nd_flags = ndx.nd->flags; + ndx.nd->flags &= ~(LOOKUP_OPEN | LOOKUP_CREATE); + } + + real_lookup: + /* do not superio. */ + h_dentry = au_lkup_one(name->name, h_parent, name->len, &ndx); + if (IS_ERR(h_dentry)) + goto out; + AuDebugOn(d_unhashed(h_dentry)); + h_inode = h_dentry->d_inode; + if (!h_inode) { + if (!allow_neg) + goto out_neg; + } else if (wh_found + || (args->type && args->type != (h_inode->i_mode & S_IFMT))) + goto out_neg; + + if (au_dbend(dentry) <= bindex) + au_set_dbend(dentry, bindex); + if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry)) + au_set_dbstart(dentry, bindex); + au_set_h_dptr(dentry, bindex, h_dentry); + + err = au_br_nfs_h_intent(ndx.nd_file, dentry, bindex, args->nd); + if (unlikely(err)) { + h_dentry = ERR_PTR(err); + goto out; + } + + inode = dentry->d_inode; + if (!h_inode || !S_ISDIR(h_inode->i_mode) || !wh_able + || (inode && !S_ISDIR(inode->i_mode))) + goto out; /* success */ + + mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); + opq = au_diropq_test(h_dentry, &ndx); + mutex_unlock(&h_inode->i_mutex); + if (opq > 0) + au_set_dbdiropq(dentry, bindex); + else if (unlikely(opq < 0)) { + au_set_h_dptr(dentry, bindex, NULL); + h_dentry = ERR_PTR(opq); + } + goto out; + + out_neg: + dput(h_dentry); + h_dentry = NULL; + out: + if (unlikely(nd_flags)) + ndx.nd->flags |= (nd_flags & (LOOKUP_OPEN | LOOKUP_CREATE)); + AuTraceErrPtr(h_dentry); + return h_dentry; +} + +/* + * returns the number of hidden positive dentries, + * otherwise an error. + * can be called at unlinking with @type is zero. + */ +int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type, + struct nameidata *nd) +{ + int npositive, err; + unsigned int mnt_flags; + aufs_bindex_t bindex, btail, bdiropq; + unsigned char isdir; + struct qstr whname; + struct au_do_lookup_args args = { + .type = type, + .nd = nd + }; + const struct qstr *name = &dentry->d_name; + struct dentry *parent; + struct super_block *sb; + struct inode *inode; + + LKTRTrace("%.*s, b%d, type 0%o\n", AuLNPair(name), bstart, type); + AuDebugOn(bstart < 0 || IS_ROOT(dentry)); + + /* dir may not be locked */ + parent = dget_parent(dentry); + + err = au_test_robr_shwh(dentry->d_sb, name); + if (unlikely(err)) + goto out; + + err = au_wh_name_alloc(name->name, name->len, &whname); + if (unlikely(err)) + goto out; + + sb = dentry->d_sb; + mnt_flags = au_mntflags(sb); + inode = dentry->d_inode; + isdir = !!(inode && S_ISDIR(inode->i_mode)); + args.flags = 0; + if (unlikely(au_test_dlgt(mnt_flags))) + au_fset_lkup(args.flags, DLGT); + if (unlikely(au_test_dirperm1(mnt_flags))) + au_fset_lkup(args.flags, DIRPERM1); + if (!type) + au_fset_lkup(args.flags, ALLOW_NEG); + npositive = 0; + btail = au_dbtaildir(parent); + for (bindex = bstart; bindex <= btail; bindex++) { + struct dentry *h_parent, *h_dentry; + struct inode *h_inode, *h_dir; + + h_dentry = au_h_dptr(dentry, bindex); + if (h_dentry) { + if (h_dentry->d_inode) + npositive++; + if (type != S_IFDIR) + break; + continue; + } + h_parent = au_h_dptr(parent, bindex); + if (!h_parent) + continue; + h_dir = h_parent->d_inode; + if (!h_dir || !S_ISDIR(h_dir->i_mode)) + continue; + + mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); + h_dentry = au_do_lookup(h_parent, dentry, bindex, &whname, + &args); + mutex_unlock(&h_dir->i_mutex); + err = PTR_ERR(h_dentry); + if (IS_ERR(h_dentry)) + goto out_wh; + au_fclr_lkup(args.flags, ALLOW_NEG); + + if (au_dbwh(dentry) >= 0) + break; + if (!h_dentry) + continue; + h_inode = h_dentry->d_inode; + if (!h_inode) + continue; + npositive++; + if (!args.type) + args.type = h_inode->i_mode & S_IFMT; + if (args.type != S_IFDIR) + break; + else if (isdir) { + /* the type of lowers may be different */ + bdiropq = au_dbdiropq(dentry); + if (bdiropq >= 0 && bdiropq <= bindex) + break; + } + } + + if (npositive) { + LKTRLabel(positive); + au_update_dbstart(dentry); + } + err = npositive; + if (unlikely(!au_opt_test(mnt_flags, UDBA_NONE) + && au_dbstart(dentry) < 0)) + /* both of real entry and whiteout found */ + err = -EIO; + + out_wh: + au_wh_name_free(&whname); + out: + dput(parent); + AuTraceErr(err); + return err; +} + +struct dentry *au_sio_lkup_one(const char *name, struct dentry *parent, int len, + struct au_ndx *ndx) +{ + struct dentry *dentry; + int wkq_err; + + LKTRTrace("%.*s/%.*s\n", AuDLNPair(parent), len, name); + + if (!au_test_h_perm_sio(parent->d_inode, MAY_EXEC, + au_ftest_ndx(ndx->flags, DLGT))) + dentry = au_lkup_one(name, parent, len, ndx); + else { + /* todo: ugly? */ + unsigned int flags = ndx->flags; + struct au_lkup_one_args args = { + .errp = &dentry, + .name = name, + .parent = parent, + .len = len, + .ndx = ndx + }; + + au_fclr_ndx(ndx->flags, DLGT); + au_fclr_ndx(ndx->flags, DIRPERM1); + wkq_err = au_wkq_wait(au_call_lkup_one, &args, /*dlgt*/0); + if (unlikely(wkq_err)) + dentry = ERR_PTR(wkq_err); + ndx->flags = flags; + } + + AuTraceErrPtr(dentry); + return dentry; +} + +/* + * lookup @dentry on @bindex which should be negative. + */ +int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex) +{ + int err; + struct dentry *parent, *h_parent, *h_dentry; + struct inode *h_dir; + struct au_ndx ndx = { + .flags = 0, + .nd = NULL, + /* .br = NULL */ + }; + struct super_block *sb; + unsigned int mnt_flags; + + LKTRTrace("%.*s, b%d\n", AuDLNPair(dentry), bindex); + /* dir may not be locked */ + parent = dget_parent(dentry); + AuDebugOn(!parent || !parent->d_inode + || !S_ISDIR(parent->d_inode->i_mode)); + h_parent = au_h_dptr(parent, bindex); + AuDebugOn(!h_parent); + h_dir = h_parent->d_inode; + AuDebugOn(!h_dir || !S_ISDIR(h_dir->i_mode)); + + sb = dentry->d_sb; + mnt_flags = au_mntflags(sb); + ndx.nfsmnt = au_nfsmnt(sb, bindex); + if (unlikely(au_test_dlgt(mnt_flags))) + au_fset_ndx(ndx.flags, DLGT); + if (unlikely(au_test_dirperm1(mnt_flags))) + au_fset_ndx(ndx.flags, DIRPERM1); + h_dentry = au_sio_lkup_one(dentry->d_name.name, h_parent, + dentry->d_name.len, &ndx); + err = PTR_ERR(h_dentry); + if (IS_ERR(h_dentry)) + goto out; + if (unlikely(h_dentry->d_inode)) { + err = -EIO; + AuIOErr("b%d %.*s should be negative.\n", + bindex, AuDLNPair(h_dentry)); + dput(h_dentry); + goto out; + } + + if (bindex < au_dbstart(dentry)) + au_set_dbstart(dentry, bindex); + if (au_dbend(dentry) < bindex) + au_set_dbend(dentry, bindex); + au_set_h_dptr(dentry, bindex, h_dentry); + err = 0; + + out: + dput(parent); + AuTraceErr(err); + return err; +} + +/* + * returns the number of found hidden positive dentries, + * otherwise an error. + */ +int au_refresh_hdentry(struct dentry *dentry, mode_t type) +{ + int npositive, new_sz; + struct au_dinfo *dinfo; + struct super_block *sb; + struct dentry *parent; + aufs_bindex_t bindex, parent_bend, parent_bstart, bwh, bdiropq, bend; + struct au_hdentry *p; + au_gen_t sgen; + + LKTRTrace("%.*s, type 0%o\n", AuDLNPair(dentry), type); + DiMustWriteLock(dentry); + sb = dentry->d_sb; + AuDebugOn(IS_ROOT(dentry)); + sgen = au_sigen(sb); + parent = dget_parent(dentry); + AuDebugOn(au_digen(parent) != sgen + || au_iigen(parent->d_inode) != sgen); + + npositive = -ENOMEM; + new_sz = sizeof(*dinfo->di_hdentry) * (au_sbend(sb) + 1); + dinfo = au_di(dentry); + p = au_kzrealloc(dinfo->di_hdentry, sizeof(*p) * (dinfo->di_bend + 1), + new_sz, GFP_NOFS); + if (unlikely(!p)) + goto out; + dinfo->di_hdentry = p; + + bend = dinfo->di_bend; + bwh = dinfo->di_bwh; + bdiropq = dinfo->di_bdiropq; + p += dinfo->di_bstart; + for (bindex = dinfo->di_bstart; bindex <= bend; bindex++, p++) { + struct dentry *hd, *hdp; + struct au_hdentry tmp, *q; + aufs_bindex_t new_bindex; + + hd = p->hd_dentry; + if (!hd) + continue; + hdp = dget_parent(hd); + if (hdp == au_h_dptr(parent, bindex)) { + dput(hdp); + continue; + } + + new_bindex = au_find_dbindex(parent, hdp); + dput(hdp); + AuDebugOn(new_bindex == bindex); + if (dinfo->di_bwh == bindex) + bwh = new_bindex; + if (dinfo->di_bdiropq == bindex) + bdiropq = new_bindex; + /* todo: test more? */ + if (new_bindex < 0) { + au_hdput(p, /*do_free*/0); + p->hd_dentry = NULL; + continue; + } + /* swap two hidden dentries, and loop again */ + q = dinfo->di_hdentry + new_bindex; + tmp = *q; + *q = *p; + *p = tmp; + if (tmp.hd_dentry) { + bindex--; + p--; + } + } + + /* todo: test more? */ + dinfo->di_bwh = -1; + if (unlikely(bwh >= 0 && bwh <= au_sbend(sb) && au_sbr_whable(sb, bwh))) + dinfo->di_bwh = bwh; + dinfo->di_bdiropq = -1; + if (unlikely(bdiropq >= 0 && bdiropq <= au_sbend(sb) + && au_sbr_whable(sb, bdiropq))) + dinfo->di_bdiropq = bdiropq; + parent_bend = au_dbend(parent); + p = dinfo->di_hdentry; + for (bindex = 0; bindex <= parent_bend; bindex++, p++) + if (p->hd_dentry) { + dinfo->di_bstart = bindex; + break; + } + p = dinfo->di_hdentry + parent_bend; + for (bindex = parent_bend; bindex >= 0; bindex--, p--) + if (p->hd_dentry) { + dinfo->di_bend = bindex; + break; + } + + npositive = 0; + parent_bstart = au_dbstart(parent); + if (type != S_IFDIR && dinfo->di_bstart == parent_bstart) + goto out_dgen; /* success */ + + npositive = au_lkup_dentry(dentry, parent_bstart, type, /*nd*/NULL); + if (npositive < 0) + goto out; + if (unlikely(dinfo->di_bwh >= 0 && dinfo->di_bwh <= dinfo->di_bstart)) + d_drop(dentry); + + out_dgen: + au_update_digen(dentry); + out: + dput(parent); + AuTraceErr(npositive); + return npositive; +} + +static int au_lock_nd(struct dentry *dentry, struct nameidata *nd) +{ + int locked = 0; + if (nd && dentry != nd->path.dentry) { + di_read_lock_parent(nd->path.dentry, 0); + locked = 1; + } + return locked; +} + +static void au_unlock_nd(int locked, struct nameidata *nd) +{ + if (locked) + di_read_unlock(nd->path.dentry, 0); +} + +/* #define TestingFuse */ +static noinline_for_stack +int au_do_h_d_reval(struct dentry *dentry, aufs_bindex_t bindex, + struct nameidata *nd, struct dentry *h_dentry) +{ + int err, valid, e; + int (*reval)(struct dentry *, struct nameidata *); + struct super_block *sb; + struct nameidata fake_nd, *p; + + LKTRTrace("%.*s, b%d, nd %d\n", AuDLNPair(dentry), bindex, !!nd); + + err = 0; + reval = NULL; + if (h_dentry->d_op) + reval = h_dentry->d_op->d_revalidate; + if (!reval) + goto out; + + sb = dentry->d_sb; + if (nd) { + memcpy(&fake_nd, nd, sizeof(*nd)); + err = au_fake_intent(&fake_nd, au_sbr_perm(sb, bindex)); + if (unlikely(err)) { + err = -EINVAL; + goto out; + } + } + p = au_fake_dm(&fake_nd, nd, sb, bindex); + AuDebugOn(IS_ERR(p)); + AuDebugOn(nd && p != &fake_nd); + LKTRTrace("b%d\n", bindex); + + /* it may return tri-state */ +#if 1 + valid = reval(h_dentry, p); +#else + if (p /*&& !IS_ROOT(h_dentry)*/) { + struct dentry *h_parent = dget_parent(h_dentry); + struct mutex *h_mtx = &h_parent->d_inode->i_mutex; +#if 0 + lktr_set_pid(current->pid, LktrArrayPid); + AuDbgDentry(p->path.dentry); + AuDbgDentry(h_dentry); + lktr_clear_pid(current->pid, LktrArrayPid); +#endif + mutex_lock_nested(h_mtx, AuLsc_I_PARENT); + valid = reval(h_dentry, p); + mutex_unlock(h_mtx); + dput(h_parent); + } else + valid = reval(h_dentry, p); +#endif + if (unlikely(valid < 0)) + err = valid; + else if (!valid) + err = -EINVAL; + else + AuDebugOn(err); + + if (p) { + AuDebugOn(!nd); + e = au_hin_after_reval(p, dentry, bindex, nd->intent.open.file); +#ifndef TestingFuse + au_update_fuse_h_inode(p->path.mnt, h_dentry); /*ignore*/ +#endif + if (unlikely(e && !err)) + err = e; + } +#ifndef TestingFuse + else + au_update_fuse_h_inode(NULL, h_dentry); /*ignore*/ +#endif + au_fake_dm_release(p); + + out: + AuTraceErr(err); + return err; +} + +static noinline_for_stack +int h_d_revalidate(struct dentry *dentry, struct inode *inode, + struct nameidata *nd, int do_udba) +{ + int err; + aufs_bindex_t bindex, btail, bstart, ibs, ibe; + unsigned char plus, locked, unhashed, is_root, h_plus; + struct super_block *sb; + struct inode *first, *h_inode, *h_cached_inode; + umode_t mode, h_mode; + struct dentry *h_dentry; + struct qstr *name; + + LKTRTrace("%.*s, nd %d\n", AuDLNPair(dentry), !!nd); + AuDebugOn(inode && au_digen(dentry) != au_iigen(inode)); + + err = 0; + sb = dentry->d_sb; + plus = 0; + mode = 0; + first = NULL; + ibs = -1; + ibe = -1; + unhashed = !!d_unhashed(dentry); + is_root = !!IS_ROOT(dentry); + name = &dentry->d_name; + + /* + * Theoretically, REVAL test should be unnecessary in case of INOTIFY. + * But inotify doesn't fire some necessary events, + * IN_ATTRIB for atime/nlink/pageio + * IN_DELETE for NFS dentry + * Let's do REVAL test too. + */ + if (do_udba && inode) { + mode = (inode->i_mode & S_IFMT); + plus = (inode->i_nlink > 0); + first = au_h_iptr(inode, au_ibstart(inode)); + ibs = au_ibstart(inode); + ibe = au_ibend(inode); + } + + bstart = au_dbstart(dentry); + btail = bstart; + if (inode && S_ISDIR(inode->i_mode)) + btail = au_dbtaildir(dentry); + locked = !!au_lock_nd(dentry, nd); + for (bindex = bstart; bindex <= btail; bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + + LKTRTrace("b%d, %.*s\n", bindex, AuDLNPair(h_dentry)); +#ifdef TestingFuse + /* force re-lookup for fuse, in order to update attributes */ + if (unlikely(au_test_fuse(h_dentry->d_sb))) + goto err; +#endif + + if (unlikely(do_udba + && !is_root + && (unhashed != !!d_unhashed(h_dentry) + || name->len != h_dentry->d_name.len + || memcmp(name->name, h_dentry->d_name.name, + name->len) + ))) { + LKTRTrace("unhash 0x%x 0x%x, %.*s %.*s\n", + unhashed, d_unhashed(h_dentry), + AuDLNPair(dentry), AuDLNPair(h_dentry)); + goto err; + } + + err = au_do_h_d_reval(dentry, bindex, nd, h_dentry); + if (unlikely(err)) + /* do not goto err, to keep the errno */ + break; + + /* todo: plink too? */ + if (unlikely(!do_udba)) + continue; + + /* UDBA tests */ + h_inode = h_dentry->d_inode; + if (unlikely(!!inode != !!h_inode)) + goto err; + + h_plus = plus; + h_mode = mode; + h_cached_inode = h_inode; + if (h_inode) { + h_mode = (h_inode->i_mode & S_IFMT); + h_plus = (h_inode->i_nlink > 0); + } + if (inode && ibs <= bindex && bindex <= ibe) + h_cached_inode = au_h_iptr(inode, bindex); + + LKTRTrace("{%d, 0%o, %p}, h{%d, 0%o, %p}\n", + plus, mode, h_cached_inode, + h_plus, h_mode, h_inode); + if (unlikely(plus != h_plus + || mode != h_mode + || h_cached_inode != h_inode)) + goto err; + continue; + + err: + err = -EINVAL; + break; + } + au_unlock_nd(locked, nd); + + /* + * judging by timestamps is meaningless since some filesystem uses + * CURRENT_TIME_SEC instead of CURRENT_TIME. + */ + /* + * NFS may stop IN_DELETE because of DCACHE_NFSFS_RENAMED. + */ + + AuTraceErr(err); + return err; +} + +static int simple_reval_dpath(struct dentry *dentry, au_gen_t sgen) +{ + int err; + mode_t type; + struct dentry *parent; + struct inode *inode; + + LKTRTrace("%.*s, sgen %d\n", AuDLNPair(dentry), sgen); + SiMustAnyLock(dentry->d_sb); + DiMustWriteLock(dentry); + inode = dentry->d_inode; + AuDebugOn(!inode); + + if (au_digen(dentry) == sgen && au_iigen(inode) == sgen) + return 0; + + parent = dget_parent(dentry); + di_read_lock_parent(parent, AuLock_IR); + AuDebugOn(au_digen(parent) != sgen + || au_iigen(parent->d_inode) != sgen); +#ifdef CONFIG_AUFS_DEBUG + { + int i, j; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + struct dentry **dentries; + + err = au_dpages_init(&dpages, GFP_NOFS); + AuDebugOn(err); + err = au_dcsub_pages_rev(&dpages, parent, /*do_include*/1, NULL, + NULL); + AuDebugOn(err); + for (i = dpages.ndpage - 1; !err && i >= 0; i--) { + dpage = dpages.dpages + i; + dentries = dpage->dentries; + for (j = dpage->ndentry - 1; !err && j >= 0; j--) + AuDebugOn(au_digen(dentries[j]) != sgen); + } + au_dpages_free(&dpages); + } +#endif + type = (inode->i_mode & S_IFMT); + /* returns a number of positive dentries */ + err = au_refresh_hdentry(dentry, type); + if (err >= 0) + err = au_refresh_hinode(inode, dentry); + di_read_unlock(parent, AuLock_IR); + dput(parent); + AuTraceErr(err); + return err; +} + +int au_reval_dpath(struct dentry *dentry, au_gen_t sgen) +{ + int err; + struct dentry *d, *parent; + struct inode *inode; + + LKTRTrace("%.*s, sgen %d\n", AuDLNPair(dentry), sgen); + AuDebugOn(!dentry->d_inode); + DiMustWriteLock(dentry); + + if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIRS)) + return simple_reval_dpath(dentry, sgen); + + /* slow loop, keep it simple and stupid */ + /* cf: au_cpup_dirs() */ + err = 0; + parent = NULL; + while (au_digen(dentry) != sgen || au_iigen(dentry->d_inode) != sgen) { + d = dentry; + while (1) { + dput(parent); + parent = dget_parent(d); + if (au_digen(parent) == sgen + && au_iigen(parent->d_inode) == sgen) + break; + d = parent; + } + + inode = d->d_inode; + if (d != dentry) + di_write_lock_child(d); + + /* someone might update our dentry while we were sleeping */ + if (au_digen(d) != sgen || au_iigen(d->d_inode) != sgen) { + di_read_lock_parent(parent, AuLock_IR); + /* returns a number of positive dentries */ + err = au_refresh_hdentry(d, inode->i_mode & S_IFMT); + if (err >= 0) + err = au_refresh_hinode(inode, d); + di_read_unlock(parent, AuLock_IR); + } + + if (d != dentry) + di_write_unlock(d); + dput(parent); + if (unlikely(err)) + break; + } + + AuTraceErr(err); + return err; +} + +/* + * THIS IS A BOOLEAN FUNCTION: returns 1 if valid, 0 otherwise. + * nfsd passes NULL as nameidata. + */ +static int aufs_d_revalidate(struct dentry *dentry, struct nameidata *nd) +{ + int valid, err; + au_gen_t sgen; + unsigned char do_udba; + struct nameidata tmp_nd, *ndp; + struct super_block *sb; + struct inode *inode; + + LKTRTrace("dentry %.*s\n", AuDLNPair(dentry)); + if (nd && nd->path.dentry) + LKTRTrace("nd{%.*s, 0x%x}\n", + AuDLNPair(nd->path.dentry), nd->flags); + /* + * dir case: AuDebugOn(dentry->d_parent != nd->dentry); + * remove failure case:AuDebugOn(!IS_ROOT(dentry) + * && d_unhashed(dentry)); + */ + AuDebugOn(!dentry->d_fsdata); + + err = -EINVAL; +#if 0 + if (d_unhashed(dentry)) + goto __out; +#endif + sb = dentry->d_sb; +#if 1 + aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW); + inode = dentry->d_inode; +#else + si_read_lock(sb, AuLock_FLUSH); + //lktr_set_pid(current->pid, LktrArrayPid); + AuDbgDentry(dentry); + AuDbgInode(dentry->d_inode); + au_rw_write_lock_nested(&au_di(dentry)->di_rwsem, AuLsc_DI_CHILD); + LKTRLabel(clean); + //lktr_clear_pid(current->pid, LktrArrayPid); + inode = dentry->d_inode; + if (unlikely(inode && (!inode->i_nlink || IS_DEADDIR(inode)))) { + AuDbg("here\n"); + au_rw_write_unlock(&au_di(dentry)->di_rwsem); + si_read_unlock(sb); + goto __out; + } + if (inode) { + //lktr_set_pid(current->pid, LktrArrayPid); + AuDbgDentry(dentry); + AuDbgInode(inode); + ii_write_lock_child(inode); + LKTRLabel(clean); + //lktr_clear_pid(current->pid, LktrArrayPid); + } +#endif + + sgen = au_sigen(sb); + if (unlikely(au_digen(dentry) != sgen)) { + AuDebugOn(IS_ROOT(dentry)); +#ifdef ForceInotify + AuDbg("UDBA or digen, %.*s\n", AuDLNPair(dentry)); +#endif + if (inode) + err = au_reval_dpath(dentry, sgen); + if (unlikely(err)) + goto out_dgrade; + AuDebugOn(au_digen(dentry) != sgen); + } + if (unlikely(inode && au_iigen(inode) != sgen)) { + AuDebugOn(IS_ROOT(dentry)); +#ifdef ForceInotify + AuDbg("UDBA or survived, %.*s\n", AuDLNPair(dentry)); +#endif + err = au_refresh_hinode(inode, dentry); + if (unlikely(err)) + goto out_dgrade; + AuDebugOn(au_iigen(inode) != sgen); + } + di_downgrade_lock(dentry, AuLock_IR); + +#if 0 /* todo: support it? */ + /* parent dir i_nlink is not updated in the case of setattr */ + if (S_ISDIR(inode->i_mode)) { + mutex_lock(&inode->i_mutex); + ii_write_lock(inode); + au_cpup_attr_nlink(inode); + ii_write_unlock(inode); + mutex_unlock(&inode->i_mutex); + } +#endif + + AuDebugOn(au_digen(dentry) != sgen); + AuDebugOn(inode && au_iigen(inode) != sgen); + err = -EINVAL; + do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE); + if (do_udba && inode) { + aufs_bindex_t bstart = au_ibstart(inode); + if (bstart >= 0 + && au_test_higen(inode, au_h_iptr(inode, bstart))) + goto out; + } + ndp = au_dup_nd(au_sbi(sb), &tmp_nd, nd); +#if 0 + if (nd) { + path = nd->path; + nd->path.dentry = au_h_dptr(nd->path.dentry, bindex); + if (fake_nd->path.dentry) { + fake_nd->path.mnt = au_sbr_mnt(sb, bindex); + AuDebugOn(!fake_nd->path.mnt); + path_get(&fake_nd->path); + nd->path. + } + } +#endif + err = h_d_revalidate(dentry, inode, ndp, do_udba); + if (unlikely(!err && do_udba && au_dbstart(dentry) < 0)) + /* both of real entry and whiteout found */ + err = -EIO; + goto out; + + out_dgrade: + di_downgrade_lock(dentry, AuLock_IR); + out: + au_store_fmode_exec(nd, inode); + + aufs_read_unlock(dentry, AuLock_IR); + //__out: + AuTraceErr(err); + valid = !err; + if (!valid) + LKTRTrace("%.*s invalid\n", AuDLNPair(dentry)); + return valid; +} + +static void aufs_d_release(struct dentry *dentry) +{ + struct au_dinfo *dinfo; + aufs_bindex_t bend, bindex; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + AuDebugOn(!d_unhashed(dentry)); + + dinfo = dentry->d_fsdata; + if (unlikely(!dinfo)) + return; + + /* dentry may not be revalidated */ + bindex = dinfo->di_bstart; + if (bindex >= 0) { + struct au_hdentry *p; + bend = dinfo->di_bend; + AuDebugOn(bend < bindex); + p = dinfo->di_hdentry + bindex; + while (bindex++ <= bend) { + if (p->hd_dentry) + au_hdput(p, /*do_free*/1); + p++; + } + } + kfree(dinfo->di_hdentry); + au_cache_free_dinfo(dinfo); + au_hin_di_reinit(dentry); + /* todo: tmp code */ + //dentry->d_fsdata = NULL; +} + +struct dentry_operations aufs_dop = { + .d_revalidate = aufs_d_revalidate, + .d_release = aufs_d_release, + /* never use d_delete, especially in case of nfs server */ +}; --- linux-2.6.27.orig/ubuntu/aufs/whout.c +++ linux-2.6.27/ubuntu/aufs/whout.c @@ -0,0 +1,1118 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * whiteout for logical deletion and opaque directory + * + * $Id: whout.c,v 1.13 2008/09/08 02:40:12 sfjro Exp $ + */ + +#include +#include +#include "aufs.h" + +#define WH_MASK S_IRUGO + +/* If a directory contains this file, then it is opaque. We start with the + * .wh. flag so that it is blocked by lookup. + */ +static struct qstr diropq_name = { + .name = AUFS_WH_DIROPQ, + .len = sizeof(AUFS_WH_DIROPQ) - 1 +}; + +/* + * generate whiteout name, which is NOT terminated by NULL. + * @name: original d_name.name + * @len: original d_name.len + * @wh: whiteout qstr + * returns zero when succeeds, otherwise error. + * succeeded value as wh->name should be freed by au_wh_name_free(). + */ +int au_wh_name_alloc(const char *name, int len, struct qstr *wh) +{ + char *p; + + AuDebugOn(!name || !len || !wh); + + if (unlikely(len > PATH_MAX - AUFS_WH_PFX_LEN)) + return -ENAMETOOLONG; + + wh->len = len + AUFS_WH_PFX_LEN; + p = kmalloc(wh->len, GFP_NOFS); + wh->name = p; + if (p) { + memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); + memcpy(p + AUFS_WH_PFX_LEN, name, len); + /* smp_mb(); */ + return 0; + } + return -ENOMEM; +} + +void au_wh_name_free(struct qstr *wh) +{ + AuDebugOn(!wh || !wh->name); + kfree(wh->name); +} + +/* ---------------------------------------------------------------------- */ + +/* + * test if the @wh_name exists under @h_parent. + * @try_sio specifies the necessary of super-io. + */ +int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio, + struct au_ndx *ndx) +{ + int err; + struct dentry *wh_dentry; + struct inode *h_dir; + unsigned int flags; + + LKTRTrace("%.*s/%.*s, ndx{%p, 0x%x}\n", AuDLNPair(h_parent), + wh_name->len, wh_name->name, ndx->nfsmnt, ndx->flags); + h_dir = h_parent->d_inode; + AuDebugOn(!S_ISDIR(h_dir->i_mode)); + + flags = 0; + if (ndx && ndx->nd) { + flags = ndx->nd->flags; + ndx->nd->flags &= ~(LOOKUP_OPEN | LOOKUP_CREATE); + } + + if (!try_sio) + wh_dentry = au_lkup_one(wh_name->name, h_parent, + wh_name->len, ndx); + else + wh_dentry = au_sio_lkup_one(wh_name->name, h_parent, + wh_name->len, ndx); + if (flags) + ndx->nd->flags = flags; + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out; + + err = 0; + if (!wh_dentry->d_inode) + goto out_wh; /* success */ + + err = 1; + if (S_ISREG(wh_dentry->d_inode->i_mode)) + goto out_wh; /* success */ + + err = -EIO; + AuIOErr("%.*s Invalid whiteout entry type 0%o.\n", + AuDLNPair(wh_dentry), wh_dentry->d_inode->i_mode); + + out_wh: + dput(wh_dentry); + out: + AuTraceErr(err); + return err; +} + +/* + * test if the @h_dentry sets opaque or not. + */ +int au_diropq_test(struct dentry *h_dentry, struct au_ndx *ndx) +{ + int err, try_sio; + struct inode *h_dir; + + LKTRTrace("dentry %.*s\n", AuDLNPair(h_dentry)); + h_dir = h_dentry->d_inode; + AuDebugOn(!S_ISDIR(h_dir->i_mode)); + + try_sio = au_test_h_perm_sio(h_dir, MAY_EXEC, + au_ftest_ndx(ndx->flags, DLGT)); + err = au_wh_test(h_dentry, &diropq_name, try_sio, ndx); + AuTraceErr(err); + return err; +} + +/* + * returns a negative dentry whose name is unique and temporary. + */ +struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct qstr *prefix, + struct au_ndx *ndx) +{ +#define HEX_LEN 4 + struct dentry *dentry; + int len, i; + char defname[AUFS_WH_PFX_LEN * 2 + DNAME_INLINE_LEN_MIN + 1 + + HEX_LEN + 1], *name, *p; + static unsigned char cnt; + + LKTRTrace("hp %.*s, prefix %.*s\n", + AuDLNPair(h_parent), prefix->len, prefix->name); + AuDebugOn(!h_parent->d_inode); + + name = defname; + len = sizeof(defname) - DNAME_INLINE_LEN_MIN + prefix->len - 1; + if (unlikely(prefix->len > DNAME_INLINE_LEN_MIN)) { + dentry = ERR_PTR(-ENAMETOOLONG); + if (unlikely(len >= PATH_MAX)) + goto out; + dentry = ERR_PTR(-ENOMEM); + name = kmalloc(len + 1, GFP_NOFS); + if (unlikely(!name)) + goto out; + } + + /* doubly whiteout-ed */ + memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2); + p = name + AUFS_WH_PFX_LEN * 2; + memcpy(p, prefix->name, prefix->len); + p += prefix->len; + *p++ = '.'; + AuDebugOn(name + len + 1 - p <= HEX_LEN); + + for (i = 0; i < 3; i++) { + sprintf(p, "%.*d", HEX_LEN, cnt++); + dentry = au_sio_lkup_one(name, h_parent, len, ndx); + if (IS_ERR(dentry) || !dentry->d_inode) + goto out_name; + dput(dentry); + } + /* AuWarn("could not get random name\n"); */ + dentry = ERR_PTR(-EEXIST); + AuDbg("%.*s\n", len, name); + BUG(); + + out_name: + if (unlikely(name != defname)) + kfree(name); + out: + AuTraceErrPtr(dentry); + return dentry; +#undef HEX_LEN +} + +/* + * rename the @dentry of @bindex to the whiteouted temporary name. + */ +int au_whtmp_ren(struct inode *dir, aufs_bindex_t bindex, + struct dentry *h_dentry) +{ + int err, dlgt; + struct inode *h_dir; + struct dentry *h_parent, *tmp_dentry; + struct super_block *sb; + unsigned int mnt_flags; + struct au_hin_ignore ign; + struct vfsub_args vargs; + struct au_ndx ndx = { + .flags = 0, + .nd = NULL, + /* .br = NULL */ + }; + + LKTRTrace("%.*s\n", AuDLNPair(h_dentry)); + AuDebugOn(!h_dentry->d_inode); + h_parent = h_dentry->d_parent; /* dir inode is locked */ + h_dir = h_parent->d_inode; + IMustLock(h_dir); + + sb = dir->i_sb; + mnt_flags = au_mntflags(sb); + dlgt = !!au_test_dlgt(mnt_flags); + if (unlikely(dlgt)) + au_fset_ndx(ndx.flags, DLGT); + ndx.nfsmnt = au_nfsmnt(sb, bindex); + tmp_dentry = au_whtmp_lkup(h_parent, &h_dentry->d_name, &ndx); + err = PTR_ERR(tmp_dentry); + if (IS_ERR(tmp_dentry)) + goto out; + + /* under the same dir, no need to lock_rename() */ + vfsub_args_init(&vargs, &ign, dlgt, 0); + AuDebugOn(!S_ISDIR(h_dentry->d_inode->i_mode)); + vfsub_ign_hinode(&vargs, IN_MOVED_FROM | IN_MOVED_TO, + au_hi(dir, bindex)); + err = vfsub_rename(h_dir, h_dentry, h_dir, tmp_dentry, &vargs); + AuTraceErr(err); + dput(tmp_dentry); + + out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int do_unlink_wh(struct au_hinode *hdir, struct inode *h_dir, + struct dentry *wh_dentry, const int dlgt) +{ + int err; + struct au_hin_ignore ign; + struct vfsub_args vargs; + + AuDebugOn(hdir && h_dir); + AuDebugOn(!hdir && !h_dir); + if (!h_dir) + h_dir = hdir->hi_inode; + LKTRTrace("hi%lu, wh %.*s\n", h_dir->i_ino, AuDLNPair(wh_dentry)); + AuDebugOn(!wh_dentry->d_inode || !S_ISREG(wh_dentry->d_inode->i_mode)); + + /* + * forces superio when the dir has a sticky bit. + * this may be a violation of unix fs semantics. + */ + vfsub_args_init(&vargs, &ign, dlgt, + (h_dir->i_mode & S_ISVTX) + && wh_dentry->d_inode->i_uid != current->fsuid); + vfsub_ign_hinode(&vargs, IN_DELETE, hdir); + err = vfsub_unlink(h_dir, wh_dentry, &vargs); + AuTraceErr(err); + return err; +} + +int au_wh_unlink_dentry(struct au_hinode *hdir, struct dentry *wh_dentry, + struct dentry *dentry, int dlgt) +{ + int err; + + LKTRTrace("i%lu, wh %.*s, d %p\n", + hdir->hi_inode->i_ino, AuDLNPair(wh_dentry), dentry); + AuDebugOn((dentry && au_dbwh(dentry) < 0) + || !wh_dentry->d_inode + || !S_ISREG(wh_dentry->d_inode->i_mode)); + + err = do_unlink_wh(hdir, /*h_dir*/NULL, wh_dentry, dlgt); + if (!err && dentry) + au_set_dbwh(dentry, -1); + + AuTraceErr(err); + return err; +} + +static int unlink_wh_name(struct dentry *h_parent, struct qstr *wh, + struct au_ndx *ndx) +{ + int err; + struct dentry *wh_dentry; + + LKTRTrace("%.*s/%.*s\n", AuDLNPair(h_parent), AuLNPair(wh)); + + /* au_test_h_perm() is already done */ + wh_dentry = au_lkup_one(wh->name, h_parent, wh->len, ndx); + if (IS_ERR(wh_dentry)) + err = PTR_ERR(wh_dentry); + else { + err = 0; + if (wh_dentry->d_inode && S_ISREG(wh_dentry->d_inode->i_mode)) + err = do_unlink_wh(/*hdir*/NULL, h_parent->d_inode, + wh_dentry, + au_ftest_ndx(ndx->flags, DLGT)); + dput(wh_dentry); + } + + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static void clean_wh(struct inode *h_dir, struct dentry *wh, + struct au_hinode *hdir, struct vfsub_args *vargs) +{ + int err; + + AuTraceEnter(); + + if (wh->d_inode) { + vfsub_args_reinit(vargs); + vfsub_ign_hinode(vargs, IN_DELETE, hdir); + err = vfsub_unlink(h_dir, wh, vargs); + if (unlikely(err)) + AuWarn("failed unlink %.*s (%d), ignored.\n", + AuDLNPair(wh), err); + } +} + +static void au_whdir_clean(struct inode *h_dir, struct dentry *dentry, + struct au_hinode *hdir, struct vfsub_args *vargs) +{ + int err; + + AuTraceEnter(); + + if (dentry->d_inode) { + vfsub_args_reinit(vargs); + vfsub_ign_hinode(vargs, IN_DELETE, hdir); + err = vfsub_rmdir(h_dir, dentry, vargs); + if (unlikely(err)) + AuWarn("failed rmdir %.*s (%d), ignored.\n", + AuDLNPair(dentry), err); + } +} + +static int test_linkable(struct inode *h_dir) +{ + if (h_dir->i_op && h_dir->i_op->link) + return 0; + return -ENOSYS; +} + +/* todo: should this mkdir be done in /sbin/mount.aufs script? */ +static int au_whdir(struct inode *h_dir, struct dentry *dentry, + struct au_hinode *hdir, struct vfsub_args *vargs) +{ + int err; + + err = -EEXIST; + if (!dentry->d_inode) { + int mode = S_IRWXU; + if (unlikely(au_test_nfs(dentry->d_sb))) + mode |= S_IXUGO; + vfsub_args_reinit(vargs); + vfsub_ign_hinode(vargs, IN_CREATE, hdir); + err = vfsub_mkdir(h_dir, dentry, mode, vargs); + } else if (S_ISDIR(dentry->d_inode->i_mode)) + err = 0; + else + AuErr("unknown %.*s exists\n", AuDLNPair(dentry)); + + return err; +} + +/* + * initialize the whiteout base file/dir for @br. + */ +int au_wh_init(struct dentry *h_root, struct au_branch *br, + struct vfsmount *nfsmnt, struct super_block *sb, + aufs_bindex_t bindex) +{ + int err, i; + struct inode *h_dir; + struct au_hin_ignore ign; + struct vfsub_args vargs; + struct au_hinode *hdir; + struct au_wbr *wbr = br->br_wbr; + static const struct qstr base_name[] = { + [AuBrWh_BASE] = { + .name = AUFS_WH_BASENAME, + .len = sizeof(AUFS_WH_BASENAME) - 1 + }, + [AuBrWh_PLINK] = { + .name = AUFS_WH_PLINKDIR, + .len = sizeof(AUFS_WH_PLINKDIR) - 1 + }, + [AuBrWh_TMP] = { + .name = AUFS_WH_TMPDIR, + .len = sizeof(AUFS_WH_TMPDIR) - 1 + } + }; + struct { + const struct qstr *name; + struct dentry *dentry; + } base[] = { + [AuBrWh_BASE] = { + .name = base_name + AuBrWh_BASE, + .dentry = NULL + }, + [AuBrWh_PLINK] = { + .name = base_name + AuBrWh_PLINK, + .dentry = NULL + }, + [AuBrWh_TMP] = { + .name = base_name + AuBrWh_TMP, + .dentry = NULL + } + }; + struct au_ndx ndx = { + .nfsmnt = nfsmnt, + .flags = 0, /* always no dlgt */ + .nd = NULL, + /* .br = NULL */ + }; + const unsigned int mnt_flags = au_mntflags(sb); + const int do_plink = au_opt_test(mnt_flags, PLINK); + const int do_hinotify = au_opt_test(mnt_flags, UDBA_INOTIFY); + + LKTRTrace("nfsmnt %p\n", nfsmnt); + WbrWhMustWriteLock(wbr); + SiMustWriteLock(sb); + h_dir = h_root->d_inode; + + for (i = 0; i < AuBrWh_Last; i++) { + /* doubly whiteouted */ + base[i].dentry = au_wh_lkup(h_root, (void *)base[i].name, &ndx); + err = PTR_ERR(base[i].dentry); + if (IS_ERR(base[i].dentry)) + goto out; + AuDebugOn(wbr + && wbr->wbr_wh[i] + && wbr->wbr_wh[i] != base[i].dentry); + } + + if (wbr) + for (i = 0; i < AuBrWh_Last; i++) { + dput(wbr->wbr_wh[i]); + wbr->wbr_wh[i] = NULL; + } + + err = 0; + hdir = NULL; + if (unlikely(bindex >= 0 && do_hinotify)) + hdir = au_hi(sb->s_root->d_inode, bindex); + vfsub_args_init(&vargs, &ign, au_test_dlgt(mnt_flags), 0); + + switch (br->br_perm) { + case AuBrPerm_RR: + case AuBrPerm_RO: + case AuBrPerm_RRWH: + case AuBrPerm_ROWH: + clean_wh(h_dir, base[AuBrWh_BASE].dentry, hdir, &vargs); + au_whdir_clean(h_dir, base[AuBrWh_PLINK].dentry, hdir, &vargs); + au_whdir_clean(h_dir, base[AuBrWh_TMP].dentry, hdir, &vargs); + break; + + case AuBrPerm_RWNoLinkWH: + clean_wh(h_dir, base[AuBrWh_BASE].dentry, hdir, &vargs); + if (do_plink) { + err = test_linkable(h_dir); + if (unlikely(err)) + goto out_nolink; + + err = au_whdir(h_dir, base[AuBrWh_PLINK].dentry, hdir, + &vargs); + if (unlikely(err)) + goto out_err; + wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); + } else + au_whdir_clean(h_dir, base[AuBrWh_PLINK].dentry, hdir, + &vargs); + err = au_whdir(h_dir, base[AuBrWh_TMP].dentry, hdir, &vargs); + if (unlikely(err)) + goto out_err; + wbr->wbr_tmp = dget(base[AuBrWh_TMP].dentry); + break; + + case AuBrPerm_RW: + /* + * for the moment, aufs supports the branch filesystem + * which does not support link(2). + * testing on FAT which does not support i_op->setattr() fully + * either, copyup failed. + * finally, such filesystem will not be used as the writable + * branch. + */ + err = test_linkable(h_dir); + if (unlikely(err)) + goto out_nolink; + + err = -EEXIST; + /* + * todo: should this create be done + * in /sbin/mount.aufs script? + */ + if (!base[AuBrWh_BASE].dentry->d_inode) { + vfsub_args_reinit(&vargs); + vfsub_ign_hinode(&vargs, IN_CREATE, hdir); + err = au_h_create(h_dir, base[AuBrWh_BASE].dentry, + WH_MASK, &vargs, /*nd*/NULL, nfsmnt); + } + else if (S_ISREG(base[AuBrWh_BASE].dentry->d_inode->i_mode)) + err = 0; + else + AuErr("unknown %.*s/%.*s exists\n", + AuDLNPair(h_root), + AuDLNPair(base[AuBrWh_BASE].dentry)); + if (unlikely(err)) + goto out_err; + + if (do_plink) { + err = au_whdir(h_dir, base[AuBrWh_PLINK].dentry, hdir, + &vargs); + if (unlikely(err)) + goto out_err; + wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); + } else + au_whdir_clean(h_dir, base[AuBrWh_PLINK].dentry, hdir, + &vargs); + wbr->wbr_whbase = dget(base[AuBrWh_BASE].dentry); + + err = au_whdir(h_dir, base[AuBrWh_TMP].dentry, hdir, &vargs); + if (unlikely(err)) + goto out_err; + wbr->wbr_tmp = dget(base[AuBrWh_TMP].dentry); + break; + + default: + BUG(); + } + + out: + for (i = 0; i < AuBrWh_Last; i++) + dput(base[i].dentry); + AuTraceErr(err); + return err; + out_nolink: + AuErr("%.*s doesn't support link(2), use noplink and rw+nolwh\n", + AuDLNPair(h_root)); + goto out; + out_err: + AuErr("an error(%d) on the writable branch %.*s(%s)\n", + err, AuDLNPair(h_root), au_sbtype(h_root->d_sb)); + goto out; +} + +struct reinit_br_wh { + struct super_block *sb; + struct au_branch *br; +}; + +static void reinit_br_wh(void *arg) +{ + int err; + struct reinit_br_wh *a = arg; + struct au_wbr *wbr; + struct inode *h_dir, *dir; + struct dentry *h_root; + aufs_bindex_t bindex; + struct au_hin_ignore ign; + struct vfsub_args vargs; + + AuTraceEnter(); + AuDebugOn(current->fsuid); + + err = 0; + wbr = a->br->br_wbr; + /* big aufs lock */ + si_noflush_write_lock(a->sb); + if (unlikely(!au_br_writable(a->br->br_perm))) + goto out; + bindex = au_br_index(a->sb, a->br->br_id); + if (unlikely(bindex < 0)) + goto out; + + AuDebugOn(!wbr); + AuDebugOn(!wbr->wbr_whbase || !wbr->wbr_whbase->d_inode); + + dir = a->sb->s_root->d_inode; + ii_read_lock_parent(dir); + h_root = dget_parent(wbr->wbr_whbase); + h_dir = h_root->d_inode; + AuDebugOn(!h_dir->i_op || !h_dir->i_op->link); + mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); + wbr_wh_write_lock(wbr); + if (!au_verify_parent(wbr->wbr_whbase, h_dir)) { + vfsub_args_init(&vargs, &ign, /*dlgt*/0, 0); + vfsub_ign_hinode(&vargs, IN_DELETE, au_hi(dir, bindex)); + err = vfsub_unlink(h_dir, wbr->wbr_whbase, &vargs); + } else { + AuWarn("%.*s is moved, ignored\n", AuDLNPair(wbr->wbr_whbase)); + err = 0; + } + dput(wbr->wbr_whbase); + wbr->wbr_whbase = NULL; + if (!err) + err = au_wh_init(h_root, a->br, au_do_nfsmnt(a->br->br_mnt), + a->sb, bindex); + wbr_wh_write_unlock(wbr); + mutex_unlock(&h_dir->i_mutex); + dput(h_root); + ii_read_unlock(dir); + + out: + if (wbr) + atomic_dec_return(&wbr->wbr_wh_running); + au_br_put(a->br); + au_nwt_done(&au_sbi(a->sb)->si_nowait); + si_write_unlock(a->sb); + kfree(arg); + if (unlikely(err)) + AuIOErr("err %d\n", err); +} + +static void kick_reinit_br_wh(struct super_block *sb, struct au_branch *br) +{ + int do_dec, wkq_err; + struct reinit_br_wh *arg; + + AuTraceEnter(); + AuDebugOn(!br->br_wbr); + + do_dec = 1; + if (atomic_inc_return(&br->br_wbr->wbr_wh_running) != 1) + goto out; + + /* ignore ENOMEM */ + arg = kmalloc(sizeof(*arg), GFP_NOFS); + if (arg) { + /* + * dec(wh_running), kfree(arg) and au_br_put() + * in reinit function + */ + arg->sb = sb; + arg->br = br; + au_br_get(br); + wkq_err = au_wkq_nowait(reinit_br_wh, arg, sb, /*dlgt*/0); + if (unlikely(wkq_err)) { + atomic_dec_return(&br->br_wbr->wbr_wh_running); + au_br_put(br); + kfree(arg); + } + do_dec = 0; + } + + out: + if (do_dec) + atomic_dec_return(&br->br_wbr->wbr_wh_running); +} + +/* + * create the whiteout @wh. + */ +static int link_or_create_wh(struct super_block *sb, aufs_bindex_t bindex, + struct dentry *wh, struct inode *dir) +{ + int err, dlgt; + struct au_branch *br; + struct au_wbr *wbr; + struct dentry *h_parent; + struct inode *h_dir; + struct au_hin_ignore ign; + struct vfsub_args vargs; + + LKTRTrace("%.*s\n", AuDLNPair(wh)); + h_parent = wh->d_parent; /* dir inode is locked */ + h_dir = h_parent->d_inode; + IMustLock(h_dir); + br = au_sbr(sb, bindex); + wbr = br->br_wbr; + AuDebugOn(!wbr); + + dlgt = !!au_test_dlgt(au_mntflags(sb)); + wbr_wh_read_lock(wbr); + if (wbr->wbr_whbase) { + vfsub_args_init(&vargs, &ign, dlgt, 0); + if (unlikely(dir)) + vfsub_ign_hinode(&vargs, IN_CREATE, au_hi(dir, bindex)); + err = vfsub_link(wbr->wbr_whbase, h_dir, wh, &vargs); + if (!err || err != -EMLINK) + goto out; + + /* link count full. re-initialize br_whbase. */ + kick_reinit_br_wh(sb, br); + } + + /* return this error in this context */ + vfsub_args_init(&vargs, &ign, dlgt, 0); + if (unlikely(dir)) + vfsub_ign_hinode(&vargs, IN_CREATE, au_hi(dir, bindex)); + err = au_h_create(h_dir, wh, WH_MASK, &vargs, /*nd*/NULL, + au_do_nfsmnt(br->br_mnt)); + + out: + wbr_wh_read_unlock(wbr); + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * create or remove the diropq. + */ +static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex, + unsigned int flags) +{ + struct dentry *opq_dentry, *h_dentry; + struct inode *h_dir; + int err, dlgt; + struct super_block *sb; + struct au_ndx ndx = { + .flags = 0, + .nd = NULL, + /* .br = NULL */ + }; + + LKTRTrace("%.*s, bindex %d, flags 0x%x\n", + AuDLNPair(dentry), bindex, flags); + h_dentry = au_h_dptr(dentry, bindex); + AuDebugOn(!h_dentry); + h_dir = h_dentry->d_inode; + AuDebugOn(!h_dir || !S_ISDIR(h_dir->i_mode)); + + /* already checked by au_test_h_perm(). */ + sb = dentry->d_sb; + ndx.nfsmnt = au_nfsmnt(sb, bindex); + dlgt = 0; + if (unlikely(au_ftest_diropq(flags, DLGT))) { + dlgt = 1; + au_fset_ndx(ndx.flags, DLGT); + } + opq_dentry = au_lkup_one(diropq_name.name, h_dentry, diropq_name.len, + &ndx); + if (IS_ERR(opq_dentry)) + goto out; + + if (au_ftest_diropq(flags, CREATE)) { + AuDebugOn(opq_dentry->d_inode); + err = link_or_create_wh(dentry->d_sb, bindex, opq_dentry, + dentry->d_inode); + if (!err) { + au_set_dbdiropq(dentry, bindex); + goto out; /* success */ + } + } else { + AuDebugOn(/* !S_ISDIR(dentry->d_inode->i_mode) + * || */!opq_dentry->d_inode); + err = do_unlink_wh(au_hi(dentry->d_inode, bindex), + /*h_dir*/NULL, opq_dentry, dlgt); + if (!err) + au_set_dbdiropq(dentry, -1); + } + dput(opq_dentry); + opq_dentry = ERR_PTR(err); + + out: + AuTraceErrPtr(opq_dentry); + return opq_dentry; +} + +struct do_diropq_args { + struct dentry **errp; + struct dentry *dentry; + aufs_bindex_t bindex; + unsigned int flags; +}; + +static void call_do_diropq(void *args) +{ + struct do_diropq_args *a = args; + *a->errp = do_diropq(a->dentry, a->bindex, a->flags); +} + +struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, + unsigned int flags) +{ + struct dentry *diropq, *h_dentry; + + LKTRTrace("%.*s, bindex %d, flags 0x%x\n", + AuDLNPair(dentry), bindex, flags); + + h_dentry = au_h_dptr(dentry, bindex); + if (!au_test_h_perm_sio(h_dentry->d_inode, MAY_EXEC | MAY_WRITE, + au_ftest_diropq(flags, DLGT))) + diropq = do_diropq(dentry, bindex, flags); + else { + int wkq_err; + struct do_diropq_args args = { + .errp = &diropq, + .dentry = dentry, + .bindex = bindex, + .flags = flags + }; + wkq_err = au_wkq_wait(call_do_diropq, &args, /*dlgt*/0); + if (unlikely(wkq_err)) + diropq = ERR_PTR(wkq_err); + } + + AuTraceErrPtr(diropq); + return diropq; +} + +/* ---------------------------------------------------------------------- */ + +/* + * lookup whiteout dentry. + * @h_parent: hidden parent dentry which must exist and be locked + * @base_name: name of dentry which will be whiteouted + * returns dentry for whiteout. + */ +struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, + struct au_ndx *ndx) +{ + int err; + struct qstr wh_name; + struct dentry *wh_dentry; + + LKTRTrace("%.*s/%.*s\n", AuDLNPair(h_parent), AuLNPair(base_name)); + + err = au_wh_name_alloc(base_name->name, base_name->len, &wh_name); + wh_dentry = ERR_PTR(err); + if (!err) { + /* do not superio. */ + wh_dentry = au_lkup_one(wh_name.name, h_parent, + wh_name.len, ndx); + au_wh_name_free(&wh_name); + } + AuTraceErrPtr(wh_dentry); + return wh_dentry; +} + +/* + * link/create a whiteout for @dentry on @bindex. + */ +struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_parent, struct au_ndx *ndx) +{ + struct dentry *wh_dentry; + struct inode *dir; + int err; + struct super_block *sb; + + LKTRTrace("%.*s/%.*s on b%d\n", AuDLNPair(h_parent), + AuDLNPair(dentry), bindex); + + sb = dentry->d_sb; + wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, ndx); + if (!IS_ERR(wh_dentry) && !wh_dentry->d_inode) { + dir = dentry->d_parent->d_inode; /* dir is locked */ + IMustLock(dir); + err = link_or_create_wh(sb, bindex, wh_dentry, dir); + if (!err) + au_set_dbwh(dentry, bindex); + else { + dput(wh_dentry); + wh_dentry = ERR_PTR(err); + } + } + + AuTraceErrPtr(wh_dentry); + return wh_dentry; +} + +/* ---------------------------------------------------------------------- */ + +/* Delete all whiteouts in this directory on branch bindex. */ +static int del_wh_children(struct dentry *h_dentry, struct au_nhash *whlist, + aufs_bindex_t bindex, struct au_ndx *ndx) +{ + int err, i; + struct qstr wh_name; + char *p; + struct inode *h_inode; + struct hlist_head *head; + struct au_vdir_wh *tpos; + struct hlist_node *pos; + struct au_vdir_destr *str; + + LKTRTrace("%.*s\n", AuDLNPair(h_dentry)); + h_inode = h_dentry->d_inode; + AuDebugOn(IS_RDONLY(h_inode)); + + err = -ENOMEM; + p = __getname(); + wh_name.name = p; + if (unlikely(!wh_name.name)) + goto out; + memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); + p += AUFS_WH_PFX_LEN; + + /* already checked by au_test_h_perm(). */ + err = 0; + for (i = 0; !err && i < AuSize_NHASH; i++) { + head = whlist->heads + i; + hlist_for_each_entry(tpos, pos, head, wh_hash) { + if (tpos->wh_bindex != bindex) + continue; + str = &tpos->wh_str; + if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) { + memcpy(p, str->name, str->len); + wh_name.len = AUFS_WH_PFX_LEN + str->len; + err = unlink_wh_name(h_dentry, &wh_name, ndx); + if (!err) + continue; + break; + } + AuIOErr("whiteout name too long %.*s\n", + str->len, str->name); + err = -EIO; + break; + } + } + __putname(wh_name.name); + + out: + AuTraceErr(err); + return err; +} + +struct del_wh_children_args { + int *errp; + struct dentry *h_dentry; + struct au_nhash *whlist; + aufs_bindex_t bindex; + struct au_ndx *ndx; +}; + +static void call_del_wh_children(void *args) +{ + struct del_wh_children_args *a = args; + *a->errp = del_wh_children(a->h_dentry, a->whlist, a->bindex, a->ndx); +} + +/* ---------------------------------------------------------------------- */ + +/* + * rmdir the whiteouted temporary named dir @h_dentry. + * @whlist: whiteouted children. + */ +int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, + struct dentry *wh_dentry, struct au_nhash *whlist) +{ + int err, dlgt; + struct inode *wh_inode, *h_dir; + struct super_block *sb; + unsigned int mnt_flags; + struct au_hin_ignore ign; + struct vfsub_args vargs; + struct au_ndx ndx = { + .flags = 0, + .nd = NULL, + /* .br = NULL */ + }; + + LKTRTrace("i%lu, %.*s, b%d\n", + dir->i_ino, AuDLNPair(wh_dentry), bindex); + /* IMustLock(dir); */ + IiMustAnyLock(dir); + h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */ + IMustLock(h_dir); + + sb = dir->i_sb; + mnt_flags = au_mntflags(sb); + dlgt = !!au_test_dlgt(mnt_flags); + if (unlikely(dlgt)) + au_fset_ndx(ndx.flags, DLGT); + ndx.nfsmnt = au_nfsmnt(sb, bindex); + wh_inode = wh_dentry->d_inode; + mutex_lock_nested(&wh_inode->i_mutex, AuLsc_I_CHILD); + + /* + * someone else might change some whiteouts while we were sleeping. + * it means this whlist may have an obsoleted entry. + */ + if (!au_test_h_perm_sio(wh_inode, MAY_EXEC | MAY_WRITE, dlgt)) + err = del_wh_children(wh_dentry, whlist, bindex, &ndx); + else { + int wkq_err; + /* ugly */ + unsigned int flags = ndx.flags; + struct del_wh_children_args args = { + .errp = &err, + .h_dentry = wh_dentry, + .whlist = whlist, + .bindex = bindex, + .ndx = &ndx + }; + + ndx.flags = 0; + wkq_err = au_wkq_wait(call_del_wh_children, &args, /*dlgt*/0); + if (unlikely(wkq_err)) + err = wkq_err; + ndx.flags = flags; + } + mutex_unlock(&wh_inode->i_mutex); + + if (!err) { + vfsub_args_init(&vargs, &ign, dlgt, 0); + vfsub_ign_hinode(&vargs, IN_DELETE, au_hi(dir, bindex)); + err = vfsub_rmdir(h_dir, wh_dentry, &vargs); + /* d_drop(h_dentry); */ + } + + if (!err) { + if (au_ibstart(dir) == bindex) { + au_cpup_attr_timesizes(dir); + /* au_cpup_attr_nlink(dir); */ + drop_nlink(dir); + } + return 0; /* success */ + } + + AuWarn("failed removing %.*s(%d), ignored\n", + AuDLNPair(wh_dentry), err); + return err; +} + +static void au_whtmp_rmdir_free_args(struct au_whtmp_rmdir_args *args) +{ + au_nhash_fin(&args->whlist); + dput(args->wh_dentry); + iput(args->dir); + kfree(args); +} + +static void call_rmdir_whtmp(void *args) +{ + int err; + struct au_whtmp_rmdir_args *a = args; + struct super_block *sb; + struct dentry *h_parent; + struct inode *h_dir; + + LKTRTrace("%.*s, b%d, dir i%lu\n", + AuDLNPair(a->wh_dentry), a->bindex, a->dir->i_ino); + + /* rmdir by nfsd may cause deadlock with this i_mutex */ + /* mutex_lock(&a->dir->i_mutex); */ + sb = a->dir->i_sb; + si_noflush_read_lock(sb); + err = au_test_ro(sb, a->bindex, NULL); + if (unlikely(err)) + goto out; + + err = -EIO; + ii_write_lock_parent(a->dir); + h_parent = dget_parent(a->wh_dentry); + h_dir = h_parent->d_inode; + mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); + if (!au_verify_parent(a->wh_dentry, h_dir)) + err = au_whtmp_rmdir(a->dir, a->bindex, a->wh_dentry, + &a->whlist); + mutex_unlock(&h_dir->i_mutex); + dput(h_parent); + ii_write_unlock(a->dir); + + out: + /* mutex_unlock(&a->dir->i_mutex); */ + au_nwt_done(&au_sbi(sb)->si_nowait); + si_read_unlock(sb); + au_whtmp_rmdir_free_args(a); + if (unlikely(err)) + AuIOErr("err %d\n", err); +} + +void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, + struct dentry *wh_dentry, struct au_nhash *whlist, + struct au_whtmp_rmdir_args *args) +{ + int wkq_err; + + LKTRTrace("%.*s\n", AuDLNPair(wh_dentry)); + IMustLock(dir); + + /* all post-process will be done in do_rmdir_whtmp(). */ + args->dir = au_igrab(dir); + args->bindex = bindex; + args->wh_dentry = dget(wh_dentry); + au_nhash_init(&args->whlist); + au_nhash_move(&args->whlist, whlist); + wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, dir->i_sb, /*dlgt*/0); + if (unlikely(wkq_err)) { + AuWarn("rmdir error %.*s (%d), ignored\n", + AuDLNPair(wh_dentry), wkq_err); + au_whtmp_rmdir_free_args(args); + } +} --- linux-2.6.27.orig/ubuntu/aufs/hinode.h +++ linux-2.6.27/ubuntu/aufs/hinode.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * lower (branch filesystem) inode and setting inotify + * + * $Id: hinode.h,v 1.9 2008/08/25 01:49:59 sfjro Exp $ + */ + +#ifndef __AUFS_HINODE_H__ +#define __AUFS_HINODE_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include "super.h" +#include "vfsub.h" + +/* ---------------------------------------------------------------------- */ + +struct au_hinotify { +#ifdef CONFIG_AUFS_HINOTIFY + spinlock_t hin_ignore_lock; + struct list_head hin_ignore_list; + + struct inotify_watch hin_watch; + struct inode *hin_aufs_inode; /* no get/put */ +#endif +}; + +struct au_hinode { + struct inode *hi_inode; + aufs_bindex_t hi_id; +#ifdef CONFIG_AUFS_HINOTIFY + struct au_hinotify *hi_notify; +#endif + + /* reference to the copied-up whiteout with get/put */ + struct dentry *hi_whdentry; +}; + +struct au_hin_ignore { +#ifdef CONFIG_AUFS_HINOTIFY + struct list_head ign_list; + + pid_t ign_pid; + __u32 ign_events, ign_handled; + struct au_hinode *ign_hinode; +#endif +}; + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_HINOTIFY +/* inotify events */ +static const __u32 AuInMask = (IN_MOVE | IN_DELETE | IN_CREATE + /* | IN_ACCESS */ + | IN_MODIFY | IN_ATTRIB + /* | IN_DELETE_SELF | IN_MOVE_SELF */ + ); + +static inline +void au_hin_init(struct au_hinode *hinode, struct au_hinotify *val) +{ + hinode->hi_notify = val; +} + +/* hinotify.c */ +int au_hin_alloc(struct au_hinode *hinode, struct inode *inode, + struct inode *h_inode); +void au_hin_free(struct au_hinode *hinode); +void au_hin_ctl(struct au_hinode *hinode, const __u32 mask); +void au_reset_hinotify(struct inode *inode, unsigned int flags); + +int au_hin_verify_gen(struct dentry *dentry); + +int __init au_inotify_init(void); +void au_inotify_fin(void); + +static inline void au_hin_suspend(struct au_hinode *hinode) +{ + au_hin_ctl(hinode, 0); +} + +static inline void au_hin_resume(struct au_hinode *hinode) +{ + au_hin_ctl(hinode, AuInMask); +} + +#else + +static inline +void au_hin_init(struct au_hinode *hinode, struct au_hinotify *val) +{ + /* empty */ +} + +static inline +int au_hin_alloc(struct au_hinode *hinode, struct inode *inode, + struct inode *h_inode) +{ + return -EOPNOTSUPP; +} + +static inline void au_hin_free(struct au_hinode *hinode) +{ + /* nothing */ +} + +static inline void au_reset_hinotify(struct inode *inode, unsigned int flags) +{ + /* nothing */ +} + +static inline int au_hin_verify_gen(struct dentry *dentry) +{ + return 0; +} + +static inline int au_inotify_init(void) +{ + return 0; +} + +#define au_inotify_fin() do {} while (0) + +static inline void au_hin_suspend(struct au_hinode *hinode) +{ + /* empty */ +} + +static inline void au_hin_resume(struct au_hinode *hinode) +{ + /* empty */ +} +#endif /* CONFIG_AUFS_HINOTIFY */ + +#if defined(CONFIG_AUFS_HINOTIFY) && defined(CONFIG_AUFS_DEBUG) +static inline void au_hin_list_del(struct list_head *e) +{ + list_del_init(e); +} + +void au_dbg_hin_list(struct vfsub_args *vargs); +#else +static inline void au_hin_list_del(struct list_head *e) +{ + list_del(e); +} + +static inline void au_dbg_hin_list(struct vfsub_args *vargs) +{ + /* empty */ +} +#endif /* CONFIG_AUFS_DEBUG */ + +/* ---------------------------------------------------------------------- */ + +#endif /* __KERNEL__ */ +#endif /* __AUFS_HINODE_H__ */ --- linux-2.6.27.orig/ubuntu/aufs/sysrq.c +++ linux-2.6.27/ubuntu/aufs/sysrq.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * magic sysrq hanlder + * + * $Id: sysrq.c,v 1.10 2008/09/08 02:40:48 sfjro Exp $ + */ + +#include +#include +#include +/* #include */ +#include "aufs.h" + +static void sysrq_sb(struct super_block *sb) +{ + char *plevel; + struct inode *i; + + plevel = au_plevel; + au_plevel = KERN_WARNING; + au_debug_on(); + + pr_warning("si=%lx\n", au_si_mask ^ (unsigned long)au_sbi(sb)); + pr_warning(AUFS_NAME ": superblock\n"); + au_dpri_sb(sb); + pr_warning(AUFS_NAME ": root dentry\n"); + au_dpri_dentry(sb->s_root); + pr_warning(AUFS_NAME ": root inode\n"); + au_dpri_inode(sb->s_root->d_inode); + pr_warning(AUFS_NAME ": isolated inode\n"); + list_for_each_entry(i, &sb->s_inodes, i_sb_list) + if (list_empty(&i->i_dentry)) + au_dpri_inode(i); + + au_plevel = plevel; + au_debug_off(); +} + +/* ---------------------------------------------------------------------- */ + +/* module parameter */ +static char *aufs_sysrq_key = "a"; +module_param_named(sysrq, aufs_sysrq_key, charp, S_IRUGO); +MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME); + +static void au_sysrq(int key, struct tty_struct *tty) +{ + struct kobject *kobj; + struct au_sbinfo *sbinfo; + + /* spin_lock(&au_kset->list_lock); */ + list_for_each_entry(kobj, &au_kset->list, entry) { + sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); + sysrq_sb(sbinfo->si_sb); + } + /* spin_unlock(&au_kset->list_lock); */ +} + +static struct sysrq_key_op au_sysrq_op = { + .handler = au_sysrq, + .help_msg = "Aufs", + .action_msg = "Aufs", + /* todo: test mask? */ + .enable_mask = SYSRQ_ENABLE_DUMP +}; + +/* ---------------------------------------------------------------------- */ + +int __init au_sysrq_init(void) +{ + int err; + char key; + + err = -1; + key = *aufs_sysrq_key; + if ('a' <= key && key <= 'z') + err = register_sysrq_key(key, &au_sysrq_op); + if (unlikely(err)) + AuErr("err %d, sysrq=%c\n", err, key); + return err; +} + +void au_sysrq_fin(void) +{ + int err; + err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op); + if (unlikely(err)) + AuErr("err %d (ignored)\n", err); +} --- linux-2.6.27.orig/ubuntu/aufs/xino.c +++ linux-2.6.27/ubuntu/aufs/xino.c @@ -0,0 +1,1259 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * external inode number translation table and bitmap + * + * $Id: xino.c,v 1.16 2008/09/15 03:16:30 sfjro Exp $ + */ + +#include +#include "aufs.h" + +/* ---------------------------------------------------------------------- */ + +ssize_t xino_fread(au_readf_t func, struct file *file, void *buf, size_t size, + loff_t *pos) +{ + ssize_t err; + mm_segment_t oldfs; + + LKTRTrace("%.*s, sz %lu, *pos %lld\n", + AuDLNPair(file->f_dentry), (unsigned long)size, *pos); + + oldfs = get_fs(); + set_fs(KERNEL_DS); + do { + /* todo: signal_pending? */ + err = func(file, (char __user *)buf, size, pos); + } while (err == -EAGAIN || err == -EINTR); + set_fs(oldfs); + +#if 0 /* reserved for future use */ + if (err > 0) + fsnotify_access(file->f_dentry); +#endif + + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static ssize_t do_xino_fwrite(au_writef_t func, struct file *file, void *buf, + size_t size, loff_t *pos) +{ + ssize_t err; + mm_segment_t oldfs; + + lockdep_off(); + oldfs = get_fs(); + set_fs(KERNEL_DS); + do { + /* todo: signal_pending? */ + err = func(file, (const char __user *)buf, size, pos); + } while (err == -EAGAIN || err == -EINTR); + set_fs(oldfs); + lockdep_on(); + + if (err >= 0) + au_update_fuse_h_inode(file->f_vfsmnt, file->f_dentry); + /*ignore*/ + +#if 0 /* reserved for future use */ + if (err > 0) + fsnotify_modify(file->f_dentry); +#endif + + AuTraceErr(err); + return err; +} + +struct do_xino_fwrite_args { + ssize_t *errp; + au_writef_t func; + struct file *file; + void *buf; + size_t size; + loff_t *pos; +}; + +static void call_do_xino_fwrite(void *args) +{ + struct do_xino_fwrite_args *a = args; + *a->errp = do_xino_fwrite(a->func, a->file, a->buf, a->size, a->pos); +} + +ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size, + loff_t *pos) +{ + ssize_t err; + + LKTRTrace("%.*s, sz %lu, *pos %lld\n", + AuDLNPair(file->f_dentry), (unsigned long)size, *pos); + + /* todo: signal block and no wkq? */ + /* + * it breaks RLIMIT_FSIZE and normal user's limit, + * users should care about quota and real 'filesystem full.' + */ + if (!au_test_wkq(current)) { + int wkq_err; + struct do_xino_fwrite_args args = { + .errp = &err, + .func = func, + .file = file, + .buf = buf, + .size = size, + .pos = pos + }; + wkq_err = au_wkq_wait(call_do_xino_fwrite, &args, /*dlgt*/0); + if (unlikely(wkq_err)) + err = wkq_err; + } else + err = do_xino_fwrite(func, file, buf, size, pos); + + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct xino_do_trunc_args { + struct super_block *sb; + struct au_branch *br; +}; + +static void xino_do_trunc(void *_args) +{ + struct xino_do_trunc_args *args = _args; + struct super_block *sb; + aufs_bindex_t bindex; + int err; + struct file *file; + struct inode *dir; + struct au_sbinfo *sbinfo; + struct kobject *kobj; + + err = 0; + sb = args->sb; + dir = sb->s_root->d_inode; + si_noflush_write_lock(sb); + ii_read_lock_parent(dir); + bindex = au_br_index(sb, args->br->br_id); + AuDebugOn(bindex < 0); + err = au_xino_trunc(sb, bindex); + if (unlikely(err)) + goto out; + + file = args->br->br_xino.xi_file; + au_update_fuse_h_inode(args->br->br_mnt, file->f_dentry); /*ignore*/ + if (file->f_dentry->d_inode->i_blocks >= args->br->br_xino_upper) + args->br->br_xino_upper += AUFS_XINO_TRUNC_STEP; + + out: + ii_read_unlock(dir); + if (unlikely(err)) + AuWarn("err b%d, (%d)\n", bindex, err); + atomic_dec_return(&args->br->br_xino_running); + au_br_put(args->br); + sbinfo = au_sbi(sb); + kobj = &sbinfo->si_kobj; + au_nwt_done(&sbinfo->si_nowait); + si_write_unlock(sb); + kobject_put(kobj); + kfree(args); +} + +static void xino_try_trunc(struct super_block *sb, struct au_branch *br) +{ + struct xino_do_trunc_args *args; + struct au_sbinfo *sbinfo; + struct file *file = br->br_xino.xi_file; + int wkq_err; + + au_update_fuse_h_inode(br->br_mnt, file->f_dentry); /*ignore*/ + if (file->f_dentry->d_inode->i_blocks < br->br_xino_upper) + return; + if (atomic_inc_return(&br->br_xino_running) > 1) + goto out; + + /* lock and kfree() will be called in trunc_xino() */ + args = kmalloc(sizeof(*args), GFP_NOFS); + if (unlikely(!args)) { + AuErr1("no memory\n"); + goto out_args; + } + + sbinfo = au_sbi(sb); + kobject_get(&sbinfo->si_kobj); + au_br_get(br); + args->sb = sb; + args->br = br; + wkq_err = au_wkq_nowait(xino_do_trunc, args, sb, /*dlgt*/0); + if (!wkq_err) + return; /* success */ + + AuErr("wkq %d\n", wkq_err); + au_br_put(br); + kobject_put(&sbinfo->si_kobj); + + out_args: + kfree(args); + out: + atomic_dec_return(&br->br_xino_running); +} + +/* ---------------------------------------------------------------------- */ + +static int au_xino_do_write(au_writef_t write, struct file *file, + ino_t h_ino, struct au_xino_entry *xinoe) +{ + loff_t pos; + ssize_t sz; + + AuTraceEnter(); + + pos = h_ino; + if (unlikely(Au_LOFF_MAX / sizeof(*xinoe) - 1 < pos)) { + AuIOErr1("too large hi%lu\n", (unsigned long)h_ino); + return -EFBIG; + } + pos *= sizeof(*xinoe); + sz = xino_fwrite(write, file, xinoe, sizeof(*xinoe), &pos); + if (sz == sizeof(*xinoe)) + return 0; /* success */ + + AuIOErr("write failed (%ld)\n", (long)sz); + return -EIO; +} + +/* + * write @ino to the xinofile for the specified branch{@sb, @bindex} + * at the position of @_ino. + * when @ino is zero, it is written to the xinofile and means no entry. + */ +int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + struct au_xino_entry *xinoe) +{ + int err; + struct file *file; + struct au_branch *br; + unsigned int mnt_flags; + + LKTRTrace("b%d, hi%lu, i%lu\n", + bindex, (unsigned long)h_ino, (unsigned long)xinoe->ino); + BUILD_BUG_ON(sizeof(long long) != sizeof(Au_LOFF_MAX) + || ((loff_t)-1) > 0); + + mnt_flags = au_mntflags(sb); + if (unlikely(!au_opt_test_xino(mnt_flags))) + return 0; + + br = au_sbr(sb, bindex); + file = br->br_xino.xi_file; + AuDebugOn(!file); + + err = au_xino_do_write(au_sbi(sb)->si_xwrite, file, h_ino, xinoe); + if (!err) { + if (unlikely(au_opt_test(mnt_flags, TRUNC_XINO) + && au_test_trunc_xino(br->br_mnt->mnt_sb))) + xino_try_trunc(sb, br); + return 0; /* success */ + } + + AuIOErr("write failed (%d)\n", err); + return -EIO; +} + +/* ---------------------------------------------------------------------- */ + +static const int page_bits = (int)PAGE_SIZE * BITS_PER_BYTE; +static ino_t xib_calc_ino(unsigned long pindex, int bit) +{ + ino_t ino; + + AuDebugOn(bit < 0 || page_bits <= bit); + ino = AUFS_FIRST_INO + pindex * page_bits + bit; + return ino; +} + +static void xib_calc_bit(ino_t ino, unsigned long *pindex, int *bit) +{ + AuDebugOn(ino < AUFS_FIRST_INO); + ino -= AUFS_FIRST_INO; + *pindex = ino / page_bits; + *bit = ino % page_bits; +} + +static int xib_pindex(struct super_block *sb, unsigned long pindex) +{ + int err; + struct au_sbinfo *sbinfo; + loff_t pos; + ssize_t sz; + struct file *xib; + unsigned long *p; + + LKTRTrace("pindex %lu\n", pindex); + sbinfo = au_sbi(sb); + MtxMustLock(&sbinfo->si_xib_mtx); + AuDebugOn(pindex > ULONG_MAX / PAGE_SIZE + || !au_opt_test_xino(sbinfo->si_mntflags)); + + if (pindex == sbinfo->si_xib_last_pindex) + return 0; + + xib = sbinfo->si_xib; + p = sbinfo->si_xib_buf; + pos = sbinfo->si_xib_last_pindex; + pos *= PAGE_SIZE; + sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos); + if (unlikely(sz != PAGE_SIZE)) + goto out; + + pos = pindex; + pos *= PAGE_SIZE; + if (i_size_read(xib->f_dentry->d_inode) >= pos + PAGE_SIZE) + sz = xino_fread(sbinfo->si_xread, xib, p, PAGE_SIZE, &pos); + else { + memset(p, 0, PAGE_SIZE); + sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos); + } + if (sz == PAGE_SIZE) { + sbinfo->si_xib_last_pindex = pindex; + return 0; /* success */ + } + + out: + AuIOErr1("write failed (%ld)\n", (long)sz); + err = sz; + if (sz >= 0) + err = -EIO; + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +int au_xino_write0(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + ino_t ino) +{ + int err, bit; + unsigned long pindex; + struct au_sbinfo *sbinfo; + struct au_xino_entry xinoe = { + .ino = 0 + }; + + LKTRTrace("b%d, hi%lu, i%lu\n", + bindex, (unsigned long)h_ino, (unsigned long)ino); + + if (unlikely(!au_opt_test_xino(au_mntflags(sb)))) + return 0; + + err = 0; + sbinfo = au_sbi(sb); + if (unlikely(ino)) { + AuDebugOn(ino < AUFS_FIRST_INO); + xib_calc_bit(ino, &pindex, &bit); + AuDebugOn(page_bits <= bit); + mutex_lock(&sbinfo->si_xib_mtx); + err = xib_pindex(sb, pindex); + if (!err) { + clear_bit(bit, sbinfo->si_xib_buf); + sbinfo->si_xib_next_bit = bit; + } + mutex_unlock(&sbinfo->si_xib_mtx); + } + + if (!err) + err = au_xino_write(sb, bindex, h_ino, &xinoe); + return err; +} + +ino_t au_xino_new_ino(struct super_block *sb) +{ + ino_t ino; + struct au_sbinfo *sbinfo; + int free_bit, err; + unsigned long *p, pindex, ul, pend; + struct file *file; + + AuTraceEnter(); + + if (unlikely(!au_opt_test_xino(au_mntflags(sb)))) + return iunique(sb, AUFS_FIRST_INO); + + sbinfo = au_sbi(sb); + mutex_lock(&sbinfo->si_xib_mtx); + p = sbinfo->si_xib_buf; + free_bit = sbinfo->si_xib_next_bit; + if (free_bit < page_bits && !test_bit(free_bit, p)) + goto out; /* success */ + free_bit = find_first_zero_bit(p, page_bits); + if (free_bit < page_bits) + goto out; /* success */ + + pindex = sbinfo->si_xib_last_pindex; + for (ul = pindex - 1; ul < ULONG_MAX; ul--) { + err = xib_pindex(sb, ul); + if (unlikely(err)) + goto out_err; + free_bit = find_first_zero_bit(p, page_bits); + if (free_bit < page_bits) + goto out; /* success */ + } + + file = sbinfo->si_xib; + pend = i_size_read(file->f_dentry->d_inode) / PAGE_SIZE; + for (ul = pindex + 1; ul <= pend; ul++) { + err = xib_pindex(sb, ul); + if (unlikely(err)) + goto out_err; + free_bit = find_first_zero_bit(p, page_bits); + if (free_bit < page_bits) + goto out; /* success */ + } + BUG(); + + out: + set_bit(free_bit, p); + sbinfo->si_xib_next_bit++; + pindex = sbinfo->si_xib_last_pindex; + mutex_unlock(&sbinfo->si_xib_mtx); + ino = xib_calc_ino(pindex, free_bit); + LKTRTrace("i%lu\n", (unsigned long)ino); + return ino; + out_err: + mutex_unlock(&sbinfo->si_xib_mtx); + LKTRTrace("i0\n"); + return 0; +} + +/* + * read @ino from xinofile for the specified branch{@sb, @bindex} + * at the position of @h_ino. + * if @ino does not exist and @do_new is true, get new one. + */ +int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + struct au_xino_entry *xinoe) +{ + int err; + struct file *file; + loff_t pos; + ssize_t sz; + struct au_sbinfo *sbinfo; + + LKTRTrace("b%d, hi%lu\n", bindex, (unsigned long)h_ino); + + xinoe->ino = 0; + if (unlikely(!au_opt_test_xino(au_mntflags(sb)))) + return 0; /* no ino */ + + err = 0; + sbinfo = au_sbi(sb); + pos = h_ino; + if (unlikely(Au_LOFF_MAX / sizeof(*xinoe) - 1 < pos)) { + AuIOErr1("too large hi%lu\n", (unsigned long)h_ino); + return -EFBIG; + } + pos *= sizeof(*xinoe); + + file = au_sbr(sb, bindex)->br_xino.xi_file; + AuDebugOn(!file); + if (i_size_read(file->f_dentry->d_inode) < pos + sizeof(*xinoe)) + return 0; /* no ino */ + + sz = xino_fread(sbinfo->si_xread, file, xinoe, sizeof(*xinoe), &pos); + if (sz == sizeof(*xinoe)) + return 0; /* success */ + + err = sz; + if (unlikely(sz >= 0)) { + err = -EIO; + AuIOErr("xino read error (%ld)\n", (long)sz); + } + + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct file *au_xino_create(struct super_block *sb, char *fname, int silent) +{ + struct file *file; + int err; + struct dentry *h_parent; + struct inode *h_dir; + struct vfsub_args vargs; + + LKTRTrace("%s\n", fname); + + /* + * at mount-time, and the xino file is the default path, + * hinotify is disabled so we have no inotify events to ignore. + * when a user specified the xino, we cannot get au_hdir to be ignored. + */ + vfsub_args_init(&vargs, /*ign*/NULL, /*dlgt*/0, 0); + file = vfsub_filp_open(fname, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE, + S_IRUGO | S_IWUGO); + if (IS_ERR(file)) { + if (!silent) + AuErr("open %s(%ld)\n", fname, PTR_ERR(file)); + return file; + } + + /* keep file count */ + h_parent = dget_parent(file->f_dentry); + h_dir = h_parent->d_inode; + mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); + err = vfsub_unlink(h_dir, file->f_dentry, &vargs); + mutex_unlock(&h_dir->i_mutex); + dput(h_parent); + if (unlikely(err)) { + if (!silent) + AuErr("unlink %s(%d)\n", fname, err); + goto out; + } + + if (sb != file->f_dentry->d_sb) + return file; /* success */ + + if (!silent) + AuErr("%s must be outside\n", fname); + err = -EINVAL; + + out: + fput(file); + file = ERR_PTR(err); + return file; +} + +/* + * find another branch who is on the same filesystem of the specified + * branch{@btgt}. search until @bend. + */ +static int is_sb_shared(struct super_block *sb, aufs_bindex_t btgt, + aufs_bindex_t bend) +{ + aufs_bindex_t bindex; + struct super_block *tgt_sb = au_sbr_sb(sb, btgt); + + for (bindex = 0; bindex < btgt; bindex++) + if (unlikely(tgt_sb == au_sbr_sb(sb, bindex))) + return bindex; + for (bindex++; bindex <= bend; bindex++) + if (unlikely(tgt_sb == au_sbr_sb(sb, bindex))) + return bindex; + return -1; +} + +/* + * create a new xinofile at the same place/path as @base_file. + */ +struct file *au_xino_create2(struct super_block *sb, struct file *base_file, + struct file *copy_src) +{ + struct file *file; + int err; + struct dentry *base, *dentry, *parent; + struct inode *dir, *inode; + struct qstr *name; + struct au_hinode *hdir; + struct au_branch *br; + aufs_bindex_t bindex; + struct au_hin_ignore ign; + struct vfsub_args vargs; + struct au_ndx ndx = { + .nfsmnt = NULL, + .flags = 0, + .nd = NULL, + /* .br = NULL */ + }; + + base = base_file->f_dentry; + LKTRTrace("%.*s\n", AuDLNPair(base)); + parent = base->d_parent; /* dir inode is locked */ + dir = parent->d_inode; + IMustLock(dir); + + file = ERR_PTR(-EINVAL); + if (unlikely(au_test_nfs(parent->d_sb))) + goto out; + + /* do not superio, nor NFS. */ + name = &base->d_name; + dentry = au_lkup_one(name->name, parent, name->len, &ndx); + if (IS_ERR(dentry)) { + file = (void *)dentry; + AuErr("%.*s lookup err %ld\n", AuLNPair(name), PTR_ERR(dentry)); + goto out; + } + + hdir = NULL; + br = au_xino_def_br(au_sbi(sb)); + if (br) { + bindex = au_find_bindex(sb, br); + if (bindex >= 0) + hdir = au_hi(sb->s_root->d_inode, bindex); + } + vfsub_args_init(&vargs, &ign, 0, 0); + vfsub_ign_hinode(&vargs, IN_CREATE, hdir); + err = vfsub_create(dir, dentry, S_IRUGO | S_IWUGO, NULL, &vargs); + if (unlikely(err)) { + file = ERR_PTR(err); + AuErr("%.*s create err %d\n", AuLNPair(name), err); + goto out_dput; + } + file = dentry_open(dget(dentry), mntget(base_file->f_vfsmnt), + O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE); + if (IS_ERR(file)) { + AuErr("%.*s open err %ld\n", AuLNPair(name), PTR_ERR(file)); + goto out_dput; + } + vfsub_args_reinit(&vargs); + vfsub_ign_hinode(&vargs, IN_DELETE, hdir); + err = vfsub_unlink(dir, dentry, &vargs); + if (unlikely(err)) { + AuErr("%.*s unlink err %d\n", AuLNPair(name), err); + goto out_fput; + } + + if (copy_src) { + inode = copy_src->f_dentry->d_inode; + err = au_copy_file(file, copy_src, i_size_read(inode), + hdir, sb, &vargs); + if (unlikely(err)) { + AuErr("%.*s copy err %d\n", AuLNPair(name), err); + goto out_fput; + } + } + goto out_dput; /* success */ + + out_fput: + fput(file); + file = ERR_PTR(err); + out_dput: + dput(dentry); + out: + AuTraceErrPtr(file); + return file; +} + +/* ---------------------------------------------------------------------- */ + +/* + * initialize the xinofile for the specified branch{@sb, @bindex} + * at the place/path where @base_file indicates. + * test whether another branch is on the same filesystem or not, + * if @do_test is true. + */ +int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t h_ino, + struct file *base_file, int do_test) +{ + int err; + struct au_branch *shared_br; + aufs_bindex_t bshared, bend, bindex; + unsigned char do_create; + struct inode *dir; + struct au_xino_entry xinoe; + struct dentry *parent; + struct file *file; + struct super_block *tgt_sb; + + LKTRTrace("base_file %p, do_test %d\n", base_file, do_test); + SiMustWriteLock(sb); + AuDebugOn(!au_opt_test_xino(au_mntflags(sb))); + AuDebugOn(br->br_xino.xi_file); + + do_create = 1; + bshared = -1; + shared_br = NULL; + bend = au_sbend(sb); + if (do_test) { + tgt_sb = br->br_mnt->mnt_sb; + for (bindex = 0; bindex <= bend; bindex++) + if (unlikely(tgt_sb == au_sbr_sb(sb, bindex))) { + bshared = bindex; + break; + } + } + if (unlikely(bshared >= 0)) { + shared_br = au_sbr(sb, bshared); + do_create = !shared_br->br_xino.xi_file; + } + + if (do_create) { + parent = dget_parent(base_file->f_dentry); + dir = parent->d_inode; + mutex_lock_nested(&dir->i_mutex, AuLsc_I_PARENT); + file = au_xino_create2(sb, base_file, NULL); + mutex_unlock(&dir->i_mutex); + dput(parent); + err = PTR_ERR(file); + if (IS_ERR(file)) + goto out; + br->br_xino.xi_file = file; + } else { + br->br_xino.xi_file = shared_br->br_xino.xi_file; + get_file(br->br_xino.xi_file); + } + + xinoe.ino = AUFS_ROOT_INO; +#if 0 /* reserved for future use */ + xinoe.h_gen = h_inode->i_generation; + WARN_ON(xinoe.h_gen == AuXino_INVALID_HGEN); +#endif + err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file, + h_ino, &xinoe); + if (!err) + return 0; /* success */ + + + out: + AuTraceErr(err); + return err; +} + +/* too slow */ +static int do_xib_restore(struct super_block *sb, struct file *file, void *page) +{ + int err, bit; + struct au_sbinfo *sbinfo; + au_readf_t func; + loff_t pos, pend; + ssize_t sz; + struct au_xino_entry *xinoe; + unsigned long pindex; + + AuTraceEnter(); + SiMustWriteLock(sb); + + err = 0; + sbinfo = au_sbi(sb); + func = sbinfo->si_xread; + pend = i_size_read(file->f_dentry->d_inode); +#ifdef CONFIG_AUFS_DEBUG + if (unlikely(pend > (1 << 22))) + AuWarn("testing a large xino file %lld\n", (long long)pend); +#endif + pos = 0; + while (pos < pend) { + sz = xino_fread(func, file, page, PAGE_SIZE, &pos); + err = sz; + if (unlikely(sz <= 0)) + goto out; + + err = 0; + for (xinoe = page; sz > 0; xinoe++, sz -= sizeof(xinoe)) { + if (unlikely(xinoe->ino < AUFS_FIRST_INO)) + continue; + + xib_calc_bit(xinoe->ino, &pindex, &bit); + AuDebugOn(page_bits <= bit); + err = xib_pindex(sb, pindex); + if (!err) + set_bit(bit, sbinfo->si_xib_buf); + else + goto out; + } + } + + out: + AuTraceErr(err); + return err; +} + +static int xib_restore(struct super_block *sb) +{ + int err; + aufs_bindex_t bindex, bend; + void *page; + + AuTraceEnter(); + + err = -ENOMEM; + page = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!page)) + goto out; + + err = 0; + bend = au_sbend(sb); + for (bindex = 0; !err && bindex <= bend; bindex++) + if (!bindex || is_sb_shared(sb, bindex, bindex - 1) < 0) + err = do_xib_restore + (sb, au_sbr(sb, bindex)->br_xino.xi_file, page); + else + LKTRTrace("b%d\n", bindex); + free_page((unsigned long)page); + + out: + AuTraceErr(err); + return err; +} + +int au_xib_trunc(struct super_block *sb) +{ + int err; + struct au_sbinfo *sbinfo; + unsigned long *p; + loff_t pos; + ssize_t sz; + struct dentry *parent; + struct inode *dir; + struct file *file; + unsigned int mnt_flags; + + AuTraceEnter(); + SiMustWriteLock(sb); + + mnt_flags = au_mntflags(sb); + if (unlikely(!au_opt_test_xino(mnt_flags))) + return 0; + + sbinfo = au_sbi(sb); + parent = dget_parent(sbinfo->si_xib->f_dentry); + dir = parent->d_inode; + mutex_lock_nested(&dir->i_mutex, AuLsc_I_PARENT); + file = au_xino_create2(sb, sbinfo->si_xib, NULL); + mutex_unlock(&dir->i_mutex); + dput(parent); + err = PTR_ERR(file); + if (IS_ERR(file)) + goto out; + fput(sbinfo->si_xib); + sbinfo->si_xib = file; + + p = sbinfo->si_xib_buf; + memset(p, 0, PAGE_SIZE); + pos = 0; + sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xib, p, PAGE_SIZE, &pos); + if (unlikely(sz != PAGE_SIZE)) { + err = sz; + AuIOErr("err %d\n", err); + if (sz >= 0) + err = -EIO; + goto out; + } + + if (au_opt_test_xino(mnt_flags)) { + mutex_lock(&sbinfo->si_xib_mtx); + err = xib_restore(sb); + mutex_unlock(&sbinfo->si_xib_mtx); +#if 0 /* reserved for future use */ + } else { + /* is it really safe? */ + /* dont trust BKL */ + AuDebugOn(!kernel_locked()); + ino = AUFS_FIRST_INO; + list_for_each_entry(inode, &sb->s_inodes, i_sb_list) + if (ino < inode->i_ino) + ino = inode->i_ino; + + /* make iunique to return larger than active max inode number */ + iunique(sb, ino); + err = 0; +#endif + } + +out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * xino mount option handlers + */ +static au_readf_t find_readf(struct file *h_file) +{ + const struct file_operations *fop = h_file->f_op; + + if (fop) { + if (fop->read) + return fop->read; + if (fop->aio_read) + return do_sync_read; + } + return ERR_PTR(-ENOSYS); +} + +static au_writef_t find_writef(struct file *h_file) +{ + const struct file_operations *fop = h_file->f_op; + + if (fop) { + if (fop->write) + return fop->write; + if (fop->aio_write) + return do_sync_write; + } + return ERR_PTR(-ENOSYS); +} + +/* xino bitmap */ +static void xino_clear_xib(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + + AuTraceEnter(); + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + sbinfo->si_xread = NULL; + sbinfo->si_xwrite = NULL; + if (sbinfo->si_xib) + fput(sbinfo->si_xib); + sbinfo->si_xib = NULL; + free_page((unsigned long)sbinfo->si_xib_buf); + sbinfo->si_xib_buf = NULL; +} + +static int au_xino_set_xib(struct super_block *sb, struct file *base) +{ + int err; + struct au_sbinfo *sbinfo; + struct file *file; + loff_t pos; + + LKTRTrace("%.*s\n", AuDLNPair(base->f_dentry)); + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + file = au_xino_create2(sb, base, sbinfo->si_xib); + err = PTR_ERR(file); + if (IS_ERR(file)) + goto out; + if (sbinfo->si_xib) + fput(sbinfo->si_xib); + sbinfo->si_xib = file; + sbinfo->si_xread = find_readf(file); + AuDebugOn(IS_ERR(sbinfo->si_xread)); + sbinfo->si_xwrite = find_writef(file); + AuDebugOn(IS_ERR(sbinfo->si_xwrite)); + + err = -ENOMEM; + if (!sbinfo->si_xib_buf) + sbinfo->si_xib_buf = (void *)get_zeroed_page(GFP_NOFS); + if (unlikely(!sbinfo->si_xib_buf)) + goto out_unset; + + sbinfo->si_xib_last_pindex = 0; + sbinfo->si_xib_next_bit = 0; + + /* no need to lock for i_size_read() */ + if (i_size_read(file->f_dentry->d_inode) < PAGE_SIZE) { + pos = 0; + err = xino_fwrite(sbinfo->si_xwrite, file, sbinfo->si_xib_buf, + PAGE_SIZE, &pos); + if (unlikely(err != PAGE_SIZE)) + goto out_free; + } + err = 0; + goto out; /* success */ + + out_free: + free_page((unsigned long)sbinfo->si_xib_buf); + sbinfo->si_xib_buf = NULL; + if (err >= 0) + err = -EIO; + out_unset: + fput(sbinfo->si_xib); + sbinfo->si_xib = NULL; + sbinfo->si_xread = NULL; + sbinfo->si_xwrite = NULL; + out: + AuTraceErr(err); + return err; +} + +/* xino for each branch */ +static void xino_clear_br(struct super_block *sb) +{ + aufs_bindex_t bindex, bend; + struct au_branch *br; + + AuTraceEnter(); + SiMustWriteLock(sb); + + bend = au_sbend(sb); + for (bindex = 0; bindex <= bend; bindex++) { + br = au_sbr(sb, bindex); + if (unlikely(!br || !br->br_xino.xi_file)) + continue; + + fput(br->br_xino.xi_file); + br->br_xino.xi_file = NULL; + } +} + +static int au_xino_set_br(struct super_block *sb, struct file *base) +{ + int err; + aufs_bindex_t bindex, bend, bshared; + struct { + struct file *old, *new; + } *fpair, *p; + struct au_branch *br; + struct au_xino_entry xinoe; + struct inode *inode; + au_writef_t writef; + + LKTRTrace("%.*s\n", AuDLNPair(base->f_dentry)); + SiMustWriteLock(sb); + + err = -ENOMEM; + bend = au_sbend(sb); + fpair = kcalloc(bend + 1, sizeof(*fpair), GFP_NOFS); + if (unlikely(!fpair)) + goto out; + + inode = sb->s_root->d_inode; + xinoe.ino = AUFS_ROOT_INO; + writef = au_sbi(sb)->si_xwrite; + for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) { + br = au_sbr(sb, bindex); + bshared = is_sb_shared(sb, bindex, bindex - 1); + if (bshared >= 0) { + /* shared xino */ + *p = fpair[bshared]; + get_file(p->new); + } + + if (!p->new) { + /* new xino */ + p->old = br->br_xino.xi_file; + p->new = au_xino_create2(sb, base, br->br_xino.xi_file); + err = PTR_ERR(p->new); + if (IS_ERR(p->new)) { + p->new = NULL; + goto out_pair; + } + } + + err = au_xino_do_write(writef, p->new, + au_h_iptr(inode, bindex)->i_ino, &xinoe); + if (unlikely(err)) + goto out_pair; + } + + for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) { + br = au_sbr(sb, bindex); + AuDebugOn(p->old != br->br_xino.xi_file); + if (br->br_xino.xi_file) + fput(br->br_xino.xi_file); + get_file(p->new); + br->br_xino.xi_file = p->new; + } + + out_pair: + for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) + if (p->new) + fput(p->new); + else + break; + kfree(fpair); + out: + AuTraceErr(err); + return err; +} + +void au_xino_clr(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + + AuTraceEnter(); + SiMustWriteLock(sb); + + au_xigen_clr(sb); + xino_clear_xib(sb); + xino_clear_br(sb); + sbinfo = au_sbi(sb); + /* lvalue, do not call au_mntflags() */ + au_opt_clr(sbinfo->si_mntflags, XINO); + au_xino_def_br_set(NULL, sbinfo); +} + +int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount) +{ + int err, skip; + struct dentry *parent, *cur_parent; + struct qstr *dname, *cur_name; + struct file *cur_xino; + struct inode *dir; + struct au_sbinfo *sbinfo; + + LKTRTrace("remount %d\n", remount); + SiMustWriteLock(sb); + + err = 0; + sbinfo = au_sbi(sb); + parent = dget_parent(xino->file->f_dentry); + if (remount) { + skip = 0; + dname = &xino->file->f_dentry->d_name; + cur_xino = sbinfo->si_xib; + if (cur_xino) { + cur_parent = dget_parent(cur_xino->f_dentry); + cur_name = &cur_xino->f_dentry->d_name; + skip = (cur_parent == parent + && dname->len == cur_name->len + && !memcmp(dname->name, cur_name->name, + dname->len)); + dput(cur_parent); + } + if (skip) + goto out; + } + + au_opt_set(sbinfo->si_mntflags, XINO); + au_xino_def_br_set(NULL, sbinfo); + dir = parent->d_inode; + mutex_lock_nested(&dir->i_mutex, AuLsc_I_PARENT); + err = au_xino_set_xib(sb, xino->file); + if (!err) + err = au_xigen_set(sb, xino->file); + if (!err) + err = au_xino_set_br(sb, xino->file); + mutex_unlock(&dir->i_mutex); + if (!err) + goto out; /* success */ + + /* reset all */ + AuIOErr("failed creating xino(%d).\n", err); + + out: + dput(parent); + AuTraceErr(err); + return err; +} + +int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex) +{ + int err; + struct au_branch *br; + struct file *new_xino; + struct super_block *h_sb; + aufs_bindex_t bi, bend; + struct dentry *parent; + struct inode *dir; + + LKTRTrace("b%d\n", bindex); + SiMustWriteLock(sb); + + err = -EINVAL; + bend = au_sbend(sb); + if (unlikely(bindex < 0 || bend < bindex)) + goto out; + br = au_sbr(sb, bindex); + if (unlikely(!br->br_xino.xi_file)) + goto out; + + parent = dget_parent(br->br_xino.xi_file->f_dentry); + dir = parent->d_inode; + mutex_lock_nested(&dir->i_mutex, AuLsc_I_PARENT); + new_xino = au_xino_create2(sb, br->br_xino.xi_file, + br->br_xino.xi_file); + mutex_unlock(&dir->i_mutex); + dput(parent); + err = PTR_ERR(new_xino); + if (IS_ERR(new_xino)) + goto out; + err = 0; + fput(br->br_xino.xi_file); + br->br_xino.xi_file = new_xino; + + h_sb = br->br_mnt->mnt_sb; + for (bi = 0; bi <= bend; bi++) { + if (unlikely(bi == bindex)) + continue; + br = au_sbr(sb, bi); + if (br->br_mnt->mnt_sb != h_sb) + continue; + + fput(br->br_xino.xi_file); + br->br_xino.xi_file = new_xino; + get_file(new_xino); + } + + out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * create a xinofile at the default place/path. + */ +struct file *au_xino_def(struct super_block *sb) +{ + struct file *file; + aufs_bindex_t bend, bindex, bwr; + char *page, *p; + struct path path; + struct dentry *root; + + AuTraceEnter(); + + root = sb->s_root; + bend = au_sbend(sb); + bwr = -1; + for (bindex = 0; bindex <= bend; bindex++) + if (au_br_writable(au_sbr_perm(sb, bindex)) + && !au_test_nfs(au_h_dptr(root, bindex)->d_sb)) { + bwr = bindex; + break; + } + + if (bwr >= 0) { + file = ERR_PTR(-ENOMEM); + page = __getname(); + if (unlikely(!page)) + goto out; + path.mnt = au_sbr_mnt(sb, bwr); + path.dentry = au_h_dptr(root, bwr); + p = d_path(&path, page, PATH_MAX - sizeof(AUFS_XINO_FNAME)); + file = (void *)p; + if (!IS_ERR(p)) { + strcat(p, "/" AUFS_XINO_FNAME); + LKTRTrace("%s\n", p); + file = au_xino_create(sb, p, /*silent*/0); + if (!IS_ERR(file)) + au_xino_def_br_set(au_sbr(sb, bwr), au_sbi(sb)); + } + __putname(page); + } else { + file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0); + if (unlikely(au_test_nfs(file->f_dentry->d_sb))) { + AuErr("xino or noxino option is required " + "since %s is NFS\n", AUFS_XINO_DEFPATH); + fput(file); + file = ERR_PTR(-EINVAL); + } + if (!IS_ERR(file)) + au_xino_def_br_set(NULL, au_sbi(sb)); + } + + out: + AuTraceErrPtr(file); + return file; +} --- linux-2.6.27.orig/ubuntu/aufs/vfsub.c +++ linux-2.6.27/ubuntu/aufs/vfsub.c @@ -0,0 +1,719 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * sub-routines for VFS + * + * $Id: vfsub.c,v 1.11 2008/08/04 00:32:35 sfjro Exp $ + */ + +#include +#include "aufs.h" + +/* ---------------------------------------------------------------------- */ + +void vfsub_args_init(struct vfsub_args *vargs, struct au_hin_ignore *ign, + int dlgt, int force_unlink) +{ + do_vfsub_args_reinit(vargs, ign); + vargs->flags = 0; + if (unlikely(dlgt)) + vfsub_fset(vargs->flags, DLGT); + if (force_unlink) + vfsub_fset(vargs->flags, FORCE_UNLINK); +} + +/* ---------------------------------------------------------------------- */ + +struct file *vfsub_filp_open(const char *path, int oflags, int mode) +{ + struct file *err; + + LKTRTrace("%s\n", path); + + lockdep_off(); + err = filp_open(path, oflags, mode); + lockdep_on(); + if (!IS_ERR(err)) + au_update_fuse_h_inode(err->f_vfsmnt, err->f_dentry); /*ignore*/ + return err; +} + +int vfsub_path_lookup(const char *name, unsigned int flags, + struct nameidata *nd) +{ + int err; + + LKTRTrace("%s\n", name); + + /* lockdep_off(); */ + err = path_lookup(name, flags, nd); + /* lockdep_on(); */ + if (!err) + au_update_fuse_h_inode(nd->path.mnt, nd->path.dentry); + /*ignore*/ + return err; +} + +struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, + int len) +{ + struct dentry *d; + + LKTRTrace("%.*s/%.*s\n", AuDLNPair(parent), len, name); + IMustLock(parent->d_inode); + + d = lookup_one_len(name, parent, len); + if (!IS_ERR(d)) + au_update_fuse_h_inode(NULL, d); /*ignore*/ + return d; +} + +#ifdef CONFIG_AUFS_LHASH_PATCH +struct dentry *vfsub__lookup_hash(struct qstr *name, struct dentry *parent, + struct nameidata *nd) +{ + struct dentry *d; + + LKTRTrace("%.*s/%.*s, nd %d\n", + AuDLNPair(parent), AuLNPair(name), !!nd); + if (nd) + LKTRTrace("nd{0x%x}\n", nd->flags); + IMustLock(parent->d_inode); + + d = __lookup_hash(name, parent, nd); + if (!IS_ERR(d)) + au_update_fuse_h_inode(NULL, d); /*ignore*/ + return d; +} +#endif + +/* ---------------------------------------------------------------------- */ + +int do_vfsub_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) +{ + int err; + struct vfsmount *mnt; + + LKTRTrace("i%lu, %.*s, 0x%x\n", dir->i_ino, AuDLNPair(dentry), mode); + IMustLock(dir); + + err = vfs_create(dir, dentry, mode, nd); + if (!err) { + mnt = NULL; + if (nd) + mnt = nd->path.mnt; + /* dir inode is locked */ + au_update_fuse_h_inode(mnt, dentry->d_parent); /*ignore*/ + au_update_fuse_h_inode(mnt, dentry); /*ignore*/ + } + return err; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) +#define VfsubSymlinkArgs dir, dentry, symname +#else +#define VfsubSymlinkArgs dir, dentry, symname, mode +#endif + +int do_vfsub_symlink(struct inode *dir, struct dentry *dentry, + const char *symname, int mode) +{ + int err; + + LKTRTrace("i%lu, %.*s, %s, 0x%x\n", + dir->i_ino, AuDLNPair(dentry), symname, mode); + IMustLock(dir); + + err = vfs_symlink(dir, dentry, NULL, symname); + if (!err) { + /* dir inode is locked */ + au_update_fuse_h_inode(NULL, dentry->d_parent); /*ignore*/ + au_update_fuse_h_inode(NULL, dentry); /*ignore*/ + } + return err; +} + +int do_vfsub_mknod(struct inode *dir, struct dentry *dentry, int mode, + dev_t dev) +{ + int err; + + LKTRTrace("i%lu, %.*s, 0x%x\n", dir->i_ino, AuDLNPair(dentry), mode); + IMustLock(dir); + + #ifdef CONFIG_VSERVER + err = vfs_mknod(dir, dentry, mode, dev, NULL); + #elif defined(CONFIG_SECURITY_APPARMOR) + err = vfs_mknod(dir, dentry, NULL, mode, dev); + #else + err = vfs_mknod(dir, dentry, mode, dev); + #endif + if (!err) { + /* dir inode is locked */ + au_update_fuse_h_inode(NULL, dentry->d_parent); /*ignore*/ + au_update_fuse_h_inode(NULL, dentry); /*ignore*/ + } + return err; +} + +int do_vfsub_link(struct dentry *src_dentry, struct inode *dir, + struct dentry *dentry) +{ + int err; + + LKTRTrace("%.*s, i%lu, %.*s\n", + AuDLNPair(src_dentry), dir->i_ino, AuDLNPair(dentry)); + IMustLock(dir); + + lockdep_off(); + #ifdef CONFIG_VSERVER + err = vfs_link(src_dentry, dir, dentry, NULL); + #elif defined(CONFIG_SECURITY_APPARMOR) + err = vfs_link(src_dentry, NULL, dir, dentry, NULL); + #else + err = vfs_link(src_dentry, dir, dentry); + #endif + + lockdep_on(); + if (!err) { + LKTRTrace("src_i %p, dst_i %p\n", + src_dentry->d_inode, dentry->d_inode); + /* fuse has different memory inode for the same inumber */ + au_update_fuse_h_inode(NULL, src_dentry); /*ignore*/ + /* dir inode is locked */ + au_update_fuse_h_inode(NULL, dentry->d_parent); /*ignore*/ + au_update_fuse_h_inode(NULL, dentry); /*ignore*/ + } + return err; +} + +int do_vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, + struct inode *dir, struct dentry *dentry) +{ + int err; + + LKTRTrace("i%lu, %.*s, i%lu, %.*s\n", + src_dir->i_ino, AuDLNPair(src_dentry), + dir->i_ino, AuDLNPair(dentry)); + IMustLock(dir); + IMustLock(src_dir); + + lockdep_off(); + #ifdef CONFIG_SECURITY_APPARMOR + err = vfs_rename(src_dir, src_dentry, NULL, dir, dentry, NULL); + #else + err = vfs_rename(src_dir, src_dentry, dir, dentry); + #endif + lockdep_on(); + if (!err) { + /* dir inode is locked */ + au_update_fuse_h_inode(NULL, dentry->d_parent); /*ignore*/ + au_update_fuse_h_inode(NULL, src_dentry->d_parent); /*ignore*/ + au_update_fuse_h_inode(NULL, src_dentry); /*ignore*/ + } + return err; +} + +int do_vfsub_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + int err; + + LKTRTrace("i%lu, %.*s, 0x%x\n", dir->i_ino, AuDLNPair(dentry), mode); + IMustLock(dir); + + #ifdef CONFIG_VSERVER + err = vfs_mkdir(dir, dentry, mode, NULL); + #elif defined(CONFIG_SECURITY_APPARMOR) + err = vfs_mkdir(dir, dentry, NULL, mode); + #else + err = vfs_mkdir(dir, dentry, mode); + #endif + + if (!err) { + /* dir inode is locked */ + au_update_fuse_h_inode(NULL, dentry->d_parent); /*ignore*/ + au_update_fuse_h_inode(NULL, dentry); /*ignore*/ + } + return err; +} + +int do_vfsub_rmdir(struct inode *dir, struct dentry *dentry) +{ + int err; + + LKTRTrace("i%lu, %.*s\n", dir->i_ino, AuDLNPair(dentry)); + IMustLock(dir); + + lockdep_off(); + #if defined(CONFIG_VSERVER) || defined(CONFIG_SECURITY_APPARMOR) + err = vfs_rmdir(dir, dentry, NULL); + #else + err = vfs_rmdir(dir, dentry); + #endif + + lockdep_on(); + /* dir inode is locked */ + if (!err) + au_update_fuse_h_inode(NULL, dentry->d_parent); /*ignore*/ + return err; +} + +int do_vfsub_unlink(struct inode *dir, struct dentry *dentry) +{ + int err; + + LKTRTrace("i%lu, %.*s\n", dir->i_ino, AuDLNPair(dentry)); + IMustLock(dir); + + /* vfs_unlink() locks inode */ + lockdep_off(); + #if defined(CONFIG_VSERVER) || defined(CONFIG_SECURITY_APPARMOR) + err = vfs_unlink(dir, dentry, NULL); + #else + err = vfs_unlink(dir, dentry); + #endif + + lockdep_on(); + /* dir inode is locked */ + if (!err) + au_update_fuse_h_inode(NULL, dentry->d_parent); /*ignore*/ + return err; +} + +/* ---------------------------------------------------------------------- */ + +ssize_t do_vfsub_read_u(struct file *file, char __user *ubuf, size_t count, + loff_t *ppos) +{ + ssize_t err; + + LKTRTrace("%.*s, cnt %lu, pos %lld\n", + AuDLNPair(file->f_dentry), (unsigned long)count, *ppos); + + /* todo: always off, regardless nfs branch? */ + au_br_nfs_lockdep_off(file->f_vfsmnt->mnt_sb); + err = vfs_read(file, ubuf, count, ppos); + au_br_nfs_lockdep_on(file->f_vfsmnt->mnt_sb); + if (err >= 0) + au_update_fuse_h_inode(file->f_vfsmnt, file->f_dentry); + /*ignore*/ + return err; +} + +/* todo: kernel_read()? */ +ssize_t do_vfsub_read_k(struct file *file, void *kbuf, size_t count, + loff_t *ppos) +{ + ssize_t err; + mm_segment_t oldfs; + + oldfs = get_fs(); + set_fs(KERNEL_DS); + err = do_vfsub_read_u(file, (char __user *)kbuf, count, ppos); + set_fs(oldfs); + return err; +} + +ssize_t do_vfsub_write_u(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + ssize_t err; + + LKTRTrace("%.*s, cnt %lu, pos %lld\n", + AuDLNPair(file->f_dentry), (unsigned long)count, *ppos); + + lockdep_off(); + err = vfs_write(file, ubuf, count, ppos); + lockdep_on(); + if (err >= 0) + au_update_fuse_h_inode(file->f_vfsmnt, file->f_dentry); + /*ignore*/ + return err; +} + +ssize_t do_vfsub_write_k(struct file *file, void *kbuf, size_t count, + loff_t *ppos) +{ + ssize_t err; + mm_segment_t oldfs; + + oldfs = get_fs(); + set_fs(KERNEL_DS); + err = do_vfsub_write_u(file, (const char __user *)kbuf, count, ppos); + set_fs(oldfs); + return err; +} + +int do_vfsub_readdir(struct file *file, filldir_t filldir, void *arg) +{ + int err; + + LKTRTrace("%.*s\n", AuDLNPair(file->f_dentry)); + + lockdep_off(); + err = vfs_readdir(file, filldir, arg); + lockdep_on(); + if (err >= 0) + au_update_fuse_h_inode(file->f_vfsmnt, file->f_dentry); + /*ignore*/ + return err; +} + +#ifdef CONFIG_AUFS_SPLICE_PATCH +long do_vfsub_splice_to(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags) +{ + long err; + + LKTRTrace("%.*s, pos %lld, len %lu, 0x%x\n", + AuDLNPair(in->f_dentry), *ppos, (unsigned long)len, flags); + + lockdep_off(); + err = vfs_splice_to(in, ppos, pipe, len, flags); + lockdep_on(); + if (err >= 0) + au_update_fuse_h_inode(in->f_vfsmnt, in->f_dentry); /*ignore*/ + return err; +} + +long do_vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags) +{ + long err; + + LKTRTrace("%.*s, pos %lld, len %lu, 0x%x\n", + AuDLNPair(out->f_dentry), *ppos, (unsigned long)len, flags); + + lockdep_off(); + err = vfs_splice_from(pipe, out, ppos, len, flags); + lockdep_on(); + if (err >= 0) + au_update_fuse_h_inode(out->f_vfsmnt, out->f_dentry); /*ignore*/ + return err; +} +#endif + +/* ---------------------------------------------------------------------- */ + +struct au_vfsub_mkdir_args { + int *errp; + struct inode *dir; + struct dentry *dentry; + int mode; + struct vfsub_args *vargs; +}; + +static void au_call_vfsub_mkdir(void *args) +{ + struct au_vfsub_mkdir_args *a = args; + *a->errp = vfsub_mkdir(a->dir, a->dentry, a->mode, a->vargs); +} + +int vfsub_sio_mkdir(struct au_hinode *hdir, struct dentry *dentry, int mode, + int dlgt) +{ + int err, do_sio, wkq_err; + struct inode *dir = hdir->hi_inode; + struct au_hin_ignore ign; + struct vfsub_args vargs; + + LKTRTrace("i%lu, %.*s\n", dir->i_ino, AuDLNPair(dentry)); + + vfsub_args_init(&vargs, &ign, dlgt, /*force_unlink*/0); + vfsub_ign_hinode(&vargs, IN_CREATE, hdir); + do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE, dlgt); + if (!do_sio) + err = vfsub_mkdir(dir, dentry, mode, &vargs); + else { + struct au_vfsub_mkdir_args args = { + .errp = &err, + .dir = dir, + .dentry = dentry, + .mode = mode, + .vargs = &vargs + }; + vfsub_fclr(vargs.flags, DLGT); + wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args, /*dlgt*/0); + if (unlikely(wkq_err)) + err = wkq_err; + } + + AuTraceErr(err); + return err; +} + +struct au_vfsub_rmdir_args { + int *errp; + struct inode *dir; + struct dentry *dentry; + struct vfsub_args *vargs; +}; + +static void au_call_vfsub_rmdir(void *args) +{ + struct au_vfsub_rmdir_args *a = args; + *a->errp = vfsub_rmdir(a->dir, a->dentry, a->vargs); +} + +int vfsub_sio_rmdir(struct au_hinode *hdir, struct dentry *dentry, int dlgt) +{ + int err, do_sio, wkq_err; + struct inode *dir = hdir->hi_inode; + struct au_hin_ignore ign; + struct vfsub_args vargs; + + LKTRTrace("i%lu, %.*s\n", dir->i_ino, AuDLNPair(dentry)); + + vfsub_args_init(&vargs, &ign, dlgt, /*force_unlink*/0); + vfsub_ign_hinode(&vargs, IN_DELETE, hdir); + do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE, dlgt); + if (!do_sio) + err = vfsub_rmdir(dir, dentry, &vargs); + else { + struct au_vfsub_rmdir_args args = { + .errp = &err, + .dir = dir, + .dentry = dentry, + .vargs = &vargs + }; + vfsub_fclr(vargs.flags, DLGT); + wkq_err = au_wkq_wait(au_call_vfsub_rmdir, &args, /*dlgt*/0); + if (unlikely(wkq_err)) + err = wkq_err; + } + + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct notify_change_args { + int *errp; + struct dentry *h_dentry; + struct iattr *ia; + struct vfsub_args *vargs; +}; + +static void call_notify_change(void *args) +{ + struct notify_change_args *a = args; + struct inode *h_inode; + + LKTRTrace("%.*s, ia_valid 0x%x\n", + AuDLNPair(a->h_dentry), a->ia->ia_valid); + h_inode = a->h_dentry->d_inode; + IMustLock(h_inode); + + *a->errp = -EPERM; + if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) { + vfsub_ignore(a->vargs); + lockdep_off(); + *a->errp = notify_change(a->h_dentry, NULL, a->ia); + lockdep_on(); + if (!*a->errp) + au_update_fuse_h_inode(NULL, a->h_dentry); /*ignore*/ + else + vfsub_unignore(a->vargs); + au_dbg_hin_list(a->vargs); + } + AuTraceErr(*a->errp); +} + +#ifdef CONFIG_AUFS_DLGT +static void vfsub_notify_change_dlgt(struct notify_change_args *args, + unsigned int flags) +{ + if (!vfsub_ftest(flags, DLGT)) + call_notify_change(args); + else { + int wkq_err; + wkq_err = au_wkq_wait(call_notify_change, args, /*dlgt*/1); + if (unlikely(wkq_err)) + *args->errp = wkq_err; + } +} +#else +static void vfsub_notify_change_dlgt(struct notify_change_args *args, + unsigned int flags) +{ + call_notify_change(args); +} +#endif + +int vfsub_notify_change(struct dentry *dentry, struct iattr *ia, + struct vfsub_args *vargs) +{ + int err; + struct notify_change_args args = { + .errp = &err, + .h_dentry = dentry, + .ia = ia, + .vargs = vargs + }; + + vfsub_notify_change_dlgt(&args, vargs->flags); + + AuTraceErr(err); + return err; +} + +int vfsub_sio_notify_change(struct au_hinode *hdir, struct dentry *dentry, + struct iattr *ia) +{ + int err, wkq_err; + struct au_hin_ignore ign; + struct vfsub_args vargs; + __u32 events; + struct notify_change_args args = { + .errp = &err, + .h_dentry = dentry, + .ia = ia, + .vargs = &vargs + }; + + LKTRTrace("%.*s, 0x%x\n", AuDLNPair(dentry), ia->ia_valid); + + vfsub_args_init(&vargs, &ign, /*dlgt*/0, /*force_unlink*/0); + events = vfsub_events_notify_change(ia); + if (events) + vfsub_ign_hinode(&vargs, events, hdir); + wkq_err = au_wkq_wait(call_notify_change, &args, /*dlgt*/0); + if (unlikely(wkq_err)) + err = wkq_err; + + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct unlink_args { + int *errp; + struct inode *dir; + struct dentry *dentry; + struct vfsub_args *vargs; +}; + +static void call_unlink(void *args) +{ + struct unlink_args *a = args; + struct inode *h_inode; + const int stop_sillyrename = (au_test_nfs(a->dentry->d_sb) + && atomic_read(&a->dentry->d_count) == 1); + + LKTRTrace("%.*s, stop_silly %d, cnt %d\n", + AuDLNPair(a->dentry), stop_sillyrename, + atomic_read(&a->dentry->d_count)); + + if (!stop_sillyrename) + dget(a->dentry); + h_inode = a->dentry->d_inode; + if (h_inode) + atomic_inc_return(&h_inode->i_count); + vfsub_ignore(a->vargs); + *a->errp = do_vfsub_unlink(a->dir, a->dentry); + if (unlikely(*a->errp || (a->dentry->d_flags & DCACHE_NFSFS_RENAMED))) + vfsub_unignore(a->vargs); + au_dbg_hin_list(a->vargs); + if (!stop_sillyrename) + dput(a->dentry); + if (h_inode) + iput(h_inode); + + AuTraceErr(*a->errp); +} + +/* + * @dir: must be locked. + * @dentry: target dentry. + */ +int vfsub_unlink(struct inode *dir, struct dentry *dentry, + struct vfsub_args *vargs) +{ + int err; + struct unlink_args args = { + .errp = &err, + .dir = dir, + .dentry = dentry, + .vargs = vargs + }; + + if (!vfsub_ftest(vargs->flags, DLGT) + && !vfsub_ftest(vargs->flags, FORCE_UNLINK)) + call_unlink(&args); + else { + int wkq_err; + wkq_err = au_wkq_wait(call_unlink, &args, + vfsub_ftest(vargs->flags, DLGT)); + if (unlikely(wkq_err)) + err = wkq_err; + } + + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct statfs_args { + int *errp; + void *arg; + struct kstatfs *buf; +}; + +static void call_statfs(void *args) +{ + struct statfs_args *a = args; + *a->errp = vfs_statfs(a->arg, a->buf); +} + +#ifdef CONFIG_AUFS_DLGT +static void vfsub_statfs_dlgt(struct statfs_args *args, int dlgt) +{ + if (!dlgt) + call_statfs(args); + else { + int wkq_err; + wkq_err = au_wkq_wait(call_statfs, args, /*dlgt*/1); + if (unlikely(wkq_err)) + *args->errp = wkq_err; + } +} +#else +static void vfsub_statfs_dlgt(struct statfs_args *args, int dlgt) +{ + call_statfs(args); +} +#endif + +int vfsub_statfs(void *arg, struct kstatfs *buf, int dlgt) +{ + int err; + struct statfs_args args = { + .errp = &err, + .arg = arg, + .buf = buf + }; + + vfsub_statfs_dlgt(&args, dlgt); + + return err; +} --- linux-2.6.27.orig/ubuntu/aufs/wkq.c +++ linux-2.6.27/ubuntu/aufs/wkq.c @@ -0,0 +1,363 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * workqueue for asynchronous/super-io/delegated operations + * + * $Id: wkq.c,v 1.13 2008/09/15 03:16:36 sfjro Exp $ + */ + +#include +#include "aufs.h" + +struct au_wkq *au_wkq; + +struct au_cred { +#ifdef CONFIG_AUFS_DLGT + int umask; + uid_t fsuid; + gid_t fsgid; + kernel_cap_t cap_effective, cap_inheritable, cap_permitted; +#if 0 /* reserved for future use */ + unsigned keep_capabilities:1; + struct user_struct *user; + struct fs_struct *fs; + struct nsproxy *nsproxy; +#endif +#endif +}; + +struct au_wkinfo { + struct work_struct wk; + struct super_block *sb; + + unsigned int flags; + struct au_cred cred; + + au_wkq_func_t func; + void *args; + + atomic_t *busyp; + struct completion *comp; +}; + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_DLGT +static void cred_store(struct au_cred *cred) +{ + cred->umask = current->fs->umask; + cred->fsuid = current->fsuid; + cred->fsgid = current->fsgid; + cred->cap_effective = current->cap_effective; + cred->cap_inheritable = current->cap_inheritable; + cred->cap_permitted = current->cap_permitted; +} + +static void cred_revert(struct au_cred *cred) +{ + AuDebugOn(!au_test_wkq(current)); + current->fs->umask = cred->umask; + current->fsuid = cred->fsuid; + current->fsgid = cred->fsgid; + current->cap_effective = cred->cap_effective; + current->cap_inheritable = cred->cap_inheritable; + current->cap_permitted = cred->cap_permitted; +} + +static void cred_switch(struct au_cred *old, struct au_cred *new) +{ + cred_store(old); + cred_revert(new); +} + +static void dlgt_cred_store(unsigned int flags, struct au_wkinfo *wkinfo) +{ + if (unlikely(au_ftest_wkq(flags, DLGT))) + cred_store(&wkinfo->cred); +} + +static void dlgt_func(struct au_wkinfo *wkinfo) +{ + if (!au_ftest_wkq(wkinfo->flags, DLGT)) + wkinfo->func(wkinfo->args); + else { + struct au_cred cred; + cred_switch(&cred, &wkinfo->cred); + wkinfo->func(wkinfo->args); + cred_revert(&cred); + } +} +#else +static void dlgt_cred_store(unsigned int flags, struct au_wkinfo *wkinfo) +{ + /* empty */ +} + +static void dlgt_func(struct au_wkinfo *wkinfo) +{ + wkinfo->func(wkinfo->args); +} +#endif /* CONFIG_AUFS_DLGT */ + +/* ---------------------------------------------------------------------- */ + +static void update_busy(struct au_wkq *wkq, struct au_wkinfo *wkinfo) +{ +#ifdef CONFIG_AUFS_STAT + unsigned int new, old; + + do { + new = atomic_read(wkinfo->busyp); + old = wkq->max_busy; + if (new <= old) + break; + } while (cmpxchg(&wkq->max_busy, old, new) == old); +#endif +} + +static int enqueue(struct au_wkq *wkq, struct au_wkinfo *wkinfo) +{ + AuTraceEnter(); + + wkinfo->busyp = &wkq->busy; + update_busy(wkq, wkinfo); + if (au_ftest_wkq(wkinfo->flags, WAIT)) + return !queue_work(wkq->q, &wkinfo->wk); + else + return !schedule_work(&wkinfo->wk); +} + +static void do_wkq(struct au_wkinfo *wkinfo) +{ + unsigned int idle, n; + int i, idle_idx; + + AuTraceEnter(); + + while (1) { + if (au_ftest_wkq(wkinfo->flags, WAIT)) { + idle_idx = 0; + idle = UINT_MAX; + for (i = 0; i < aufs_nwkq; i++) { + n = atomic_inc_return(&au_wkq[i].busy); + if (n == 1 && !enqueue(au_wkq + i, wkinfo)) + return; /* success */ + + if (n < idle) { + idle_idx = i; + idle = n; + } + atomic_dec_return(&au_wkq[i].busy); + } + } else + idle_idx = aufs_nwkq; + + atomic_inc_return(&au_wkq[idle_idx].busy); + if (!enqueue(au_wkq + idle_idx, wkinfo)) + return; /* success */ + + /* impossible? */ + AuWarn1("failed to queue_work()\n"); + yield(); + } +} + +static void wkq_func(struct work_struct *wk) +{ + struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk); + + LKTRTrace("wkinfo{0x%x, %p, %p, %p}\n", + wkinfo->flags, wkinfo->func, wkinfo->busyp, wkinfo->comp); + + dlgt_func(wkinfo); + atomic_dec_return(wkinfo->busyp); + if (au_ftest_wkq(wkinfo->flags, WAIT)) + complete(wkinfo->comp); + else { + kobject_put(&au_sbi(wkinfo->sb)->si_kobj); + module_put(THIS_MODULE); + kfree(wkinfo); + } +} + +#if defined(CONFIG_4KSTACKS) || defined(Test4KSTACKS) +#define AuWkqCompDeclare(name) struct completion *comp = NULL + +static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) +{ + *comp = kmalloc(sizeof(**comp), GFP_NOFS); + if (*comp) { + init_completion(*comp); + wkinfo->comp = *comp; + return 0; + } + return -ENOMEM; +} + +static void au_wkq_comp_free(struct completion *comp) +{ + kfree(comp); +} + +#else + +#define AuWkqCompDeclare(name) \ + DECLARE_COMPLETION_ONSTACK(_ ## name); \ + struct completion *comp = &_ ## name + +static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) +{ + wkinfo->comp = *comp; + return 0; +} + +static void au_wkq_comp_free(struct completion *comp) +{ + /* empty */ +} +#endif /* 4KSTACKS */ + +/* todo: break to three funcs */ +int au_wkq_run(au_wkq_func_t func, void *args, struct super_block *sb, + unsigned int flags) +{ + int err; + AuWkqCompDeclare(comp); + struct au_wkinfo _wkinfo = { + .flags = flags, + .func = func, + .args = args + }, *wkinfo = &_wkinfo; + const unsigned char do_wait = au_ftest_wkq(flags, WAIT); + + LKTRTrace("0x%x\n", flags); +#if 1 /* tmp debug */ + if (au_test_wkq(current)) + au_dbg_blocked(); +#endif + AuDebugOn(au_test_wkq(current)); + + if (do_wait) { + err = au_wkq_comp_alloc(wkinfo, &comp); + if (unlikely(err)) + goto out; + } else { + AuDebugOn(!sb); + /* + * wkq_func() must free this wkinfo. + * it highly depends upon the implementation of workqueue. + */ + err = -ENOMEM; + wkinfo = kmalloc(sizeof(*wkinfo), GFP_NOFS); + if (unlikely(!wkinfo)) + goto out; + + err = 0; + wkinfo->sb = sb; + wkinfo->flags = flags; + wkinfo->func = func; + wkinfo->args = args; + wkinfo->comp = NULL; + kobject_get(&au_sbi(sb)->si_kobj); + __module_get(THIS_MODULE); + } + + INIT_WORK(&wkinfo->wk, wkq_func); + dlgt_cred_store(flags, wkinfo); + do_wkq(wkinfo); + if (do_wait) { + /* no timeout, no interrupt */ + wait_for_completion(wkinfo->comp); + au_wkq_comp_free(comp); + } + out: + AuTraceErr(err); + return err; +} + +int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, + int dlgt) +{ + int err; + unsigned int flags = !AuWkq_WAIT; + + AuTraceEnter(); + + if (unlikely(dlgt)) + au_fset_wkq(flags, DLGT); + atomic_inc_return(&au_sbi(sb)->si_nowait.nw_len); + err = au_wkq_run(func, args, sb, flags); + if (unlikely(err)) + atomic_dec_return(&au_sbi(sb)->si_nowait.nw_len); + + return err; +} + +/* ---------------------------------------------------------------------- */ + +void au_wkq_fin(void) +{ + int i; + + AuTraceEnter(); + + for (i = 0; i < aufs_nwkq; i++) + if (au_wkq[i].q && !IS_ERR(au_wkq[i].q)) + destroy_workqueue(au_wkq[i].q); + kfree(au_wkq); +} + +int __init au_wkq_init(void) +{ + int err, i; + struct au_wkq *nowaitq; + + LKTRTrace("%d\n", aufs_nwkq); + + /* '+1' is for accounting of nowait queue */ + err = -ENOMEM; + au_wkq = kcalloc(aufs_nwkq + 1, sizeof(*au_wkq), GFP_NOFS); + if (unlikely(!au_wkq)) + goto out; + + err = 0; + for (i = 0; i < aufs_nwkq; i++) { + au_wkq[i].q = create_singlethread_workqueue(AUFS_WKQ_NAME); + if (au_wkq[i].q && !IS_ERR(au_wkq[i].q)) { + atomic_set(&au_wkq[i].busy, 0); + au_wkq_max_busy_init(au_wkq + i); + continue; + } + + err = PTR_ERR(au_wkq[i].q); + au_wkq_fin(); + break; + } + + /* nowait accounting */ + nowaitq = au_wkq + aufs_nwkq; + atomic_set(&nowaitq->busy, 0); + au_wkq_max_busy_init(nowaitq); + nowaitq->q = NULL; + /* smp_mb(); */ /* atomic_set */ + + out: + AuTraceErr(err); + return err; +} --- linux-2.6.27.orig/ubuntu/aufs/i_op.c +++ linux-2.6.27/ubuntu/aufs/i_op.c @@ -0,0 +1,1003 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * inode operations (except add/del/rename) + * + * $Id: i_op.c,v 1.19 2008/09/08 02:39:57 sfjro Exp $ + */ + +#include +#include +#include "aufs.h" + +static int silly_lock(struct inode *inode, struct nameidata *nd) +{ + int locked = 0; + struct super_block *sb = inode->i_sb; + + LKTRTrace("i%lu, nd %p\n", inode->i_ino, nd); + + if (!nd || !nd->path.dentry) { + si_read_lock(sb, AuLock_FLUSH); + ii_read_lock_child(inode); + } else if (nd->path.dentry->d_inode != inode) { + locked = 1; + /* lock child first, then parent */ + si_read_lock(sb, AuLock_FLUSH); + ii_read_lock_child(inode); + di_read_lock_parent(nd->path.dentry, 0); + } else { + locked = 2; + aufs_read_lock(nd->path.dentry, AuLock_FLUSH | AuLock_IR); + } + return locked; +} + +static void silly_unlock(int locked, struct inode *inode, struct nameidata *nd) +{ + struct super_block *sb = inode->i_sb; + + LKTRTrace("locked %d, i%lu, nd %p\n", locked, inode->i_ino, nd); + + switch (locked) { + case 0: + ii_read_unlock(inode); + si_read_unlock(sb); + break; + case 1: + di_read_unlock(nd->path.dentry, 0); + ii_read_unlock(inode); + si_read_unlock(sb); + break; + case 2: + aufs_read_unlock(nd->path.dentry, AuLock_IR); + break; + default: + BUG(); + } +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) +static int h_permission(struct inode *h_inode, int mask, + struct vfsmount *h_mnt, int brperm, int dlgt) +{ + int err, submask; + const int write_mask = (mask & (MAY_WRITE | MAY_APPEND)); + + LKTRTrace("ino %lu, mask 0x%x, brperm 0x%x\n", + h_inode->i_ino, mask, brperm); + + err = -EACCES; + if (unlikely((write_mask && IS_IMMUTABLE(h_inode)) + || ((mask & MAY_EXEC) && S_ISREG(h_inode->i_mode) + && (h_mnt->mnt_flags & MNT_NOEXEC)) + )) + goto out; + + /* + * - skip hidden fs test in the case of write to ro branch. + * - nfs dir permission write check is optimized, but a policy for + * link/rename requires a real check. + */ + submask = mask & ~MAY_APPEND; + if ((write_mask && !au_br_writable(brperm)) + || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode) + && write_mask && !(mask & MAY_READ)) + || !h_inode->i_op + || !h_inode->i_op->permission) { + /* LKTRLabel(generic_permission); */ + err = generic_permission(h_inode, submask, NULL); + } else { + /* LKTRLabel(h_inode->permission); */ + err = h_inode->i_op->permission(h_inode, submask); + AuTraceErr(err); + } + +#if 1 /* todo: export? */ + if (!err) + err = au_security_inode_permission(h_inode, mask, NULL, + dlgt); +#endif + + out: + AuTraceErr(err); + return err; +} + +static int aufs_permission(struct inode *inode, int mask) +{ + int err; + aufs_bindex_t bindex, bend; + unsigned char locked, dlgt; + const unsigned char isdir = S_ISDIR(inode->i_mode); + struct inode *h_inode; + struct super_block *sb; + unsigned int mnt_flags; + const int write_mask = (mask & (MAY_WRITE | MAY_APPEND)); + + LKTRTrace("ino %lu, mask 0x%x, isdir %d, write_mask %d\n", + inode->i_ino, mask, isdir, write_mask); + + sb = inode->i_sb; + locked = silly_lock(inode, NULL); + mnt_flags = au_mntflags(sb); + dlgt = !!au_test_dlgt(mnt_flags); + + if (/* unlikely */(!isdir || write_mask + || au_test_dirperm1(mnt_flags))) { + h_inode = au_h_iptr(inode, au_ibstart(inode)); + AuDebugOn(!h_inode + || ((h_inode->i_mode & S_IFMT) + != (inode->i_mode & S_IFMT))); + err = 0; + bindex = au_ibstart(inode); + LKTRTrace("b%d\n", bindex); + err = h_permission(h_inode, mask, au_sbr_mnt(sb, bindex), + au_sbr_perm(sb, bindex), dlgt); + + if (write_mask && !err) { + /* test whether the upper writable branch exists */ + err = -EROFS; + for (; bindex >= 0; bindex--) + if (!au_br_rdonly(au_sbr(sb, bindex))) { + err = 0; + break; + } + } + goto out; + } + + /* non-write to dir */ + err = 0; + bend = au_ibend(inode); + for (bindex = au_ibstart(inode); !err && bindex <= bend; bindex++) { + h_inode = au_h_iptr(inode, bindex); + if (!h_inode) + continue; + AuDebugOn(!S_ISDIR(h_inode->i_mode)); + + LKTRTrace("b%d\n", bindex); + err = h_permission(h_inode, mask, au_sbr_mnt(sb, bindex), + au_sbr_perm(sb, bindex), dlgt); + } + + out: + silly_unlock(locked, inode, NULL); + AuTraceErr(err); + return err; +} +#else + +static int h_permission(struct inode *h_inode, int mask, + struct nameidata *fake_nd, int brperm, int dlgt) +{ + int err, submask; + const int write_mask = (mask & (MAY_WRITE | MAY_APPEND)); + + LKTRTrace("ino %lu, mask 0x%x, brperm 0x%x\n", + h_inode->i_ino, mask, brperm); + + err = -EACCES; + if (unlikely((write_mask && IS_IMMUTABLE(h_inode)) + || ((mask & MAY_EXEC) && S_ISREG(h_inode->i_mode) + && fake_nd && fake_nd->path.mnt + && (fake_nd->path.mnt->mnt_flags & MNT_NOEXEC)) + )) + goto out; + + /* + * - skip hidden fs test in the case of write to ro branch. + * - nfs dir permission write check is optimized, but a policy for + * link/rename requires a real check. + */ + submask = mask & ~MAY_APPEND; + if ((write_mask && !au_br_writable(brperm)) + || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode) + && write_mask && !(mask & MAY_READ)) + || !h_inode->i_op + || !h_inode->i_op->permission) { + /* LKTRLabel(generic_permission); */ + err = generic_permission(h_inode, submask, NULL); + } else { + /* LKTRLabel(h_inode->permission); */ + err = h_inode->i_op->permission(h_inode, submask, fake_nd); + AuTraceErr(err); + } + +#if 1 /* todo: export? */ + if (!err) + err = au_security_inode_permission(h_inode, mask, fake_nd, + dlgt); +#endif + + out: + AuTraceErr(err); + return err; +} + +static int aufs_permission(struct inode *inode, int mask, struct nameidata *nd) +{ + int err; + aufs_bindex_t bindex, bend; + unsigned char locked, dlgt, do_nd; + const unsigned char isdir = S_ISDIR(inode->i_mode); + struct inode *h_inode; + struct super_block *sb; + unsigned int mnt_flags; + struct path path; + const int write_mask = (mask & (MAY_WRITE | MAY_APPEND)); + + LKTRTrace("ino %lu, mask 0x%x, isdir %d, write_mask %d, " + "nd %d{%d, %d}\n", + inode->i_ino, mask, isdir, write_mask, + !!nd, nd ? !!nd->path.dentry : 0, nd ? !!nd->path.mnt : 0); + + sb = inode->i_sb; + locked = silly_lock(inode, nd); + do_nd = (nd && locked >= 1); + mnt_flags = au_mntflags(sb); + dlgt = !!au_test_dlgt(mnt_flags); + + if (/* unlikely */(!isdir || write_mask + || au_test_dirperm1(mnt_flags))) { + h_inode = au_h_iptr(inode, au_ibstart(inode)); + AuDebugOn(!h_inode + || ((h_inode->i_mode & S_IFMT) + != (inode->i_mode & S_IFMT))); + err = 0; + bindex = au_ibstart(inode); + LKTRTrace("b%d\n", bindex); + if (do_nd) { + path = nd->path; + nd->path.mnt = au_sbr_mnt(sb, bindex); + nd->path.dentry = au_h_dptr(nd->path.dentry, bindex); + path_get(&nd->path); + err = h_permission(h_inode, mask, nd, + au_sbr_perm(sb, bindex), dlgt); + path_put(&nd->path); + nd->path = path; + } else { + AuDebugOn(nd && nd->path.mnt); + err = h_permission(h_inode, mask, nd, + au_sbr_perm(sb, bindex), dlgt); + } + + if (write_mask && !err) { + /* test whether the upper writable branch exists */ + err = -EROFS; + for (; bindex >= 0; bindex--) + if (!au_br_rdonly(au_sbr(sb, bindex))) { + err = 0; + break; + } + } + goto out; + } + + /* non-write to dir */ + if (do_nd) + path = nd->path; + else { + path.mnt = NULL; + path.dentry = NULL; + } + err = 0; + bend = au_ibend(inode); + for (bindex = au_ibstart(inode); !err && bindex <= bend; bindex++) { + h_inode = au_h_iptr(inode, bindex); + if (!h_inode) + continue; + AuDebugOn(!S_ISDIR(h_inode->i_mode)); + + LKTRTrace("b%d\n", bindex); + if (do_nd) { + nd->path.mnt = au_sbr_mnt(sb, bindex); + nd->path.dentry = au_h_dptr(path.dentry, bindex); + path_get(&nd->path); + err = h_permission(h_inode, mask, nd, + au_sbr_perm(sb, bindex), dlgt); + path_put(&nd->path); + } else { + AuDebugOn(nd && nd->path.mnt); + err = h_permission(h_inode, mask, nd, + au_sbr_perm(sb, bindex), dlgt); + } + } + if (do_nd) + nd->path = path; + + out: + silly_unlock(locked, inode, nd); + AuTraceErr(err); + return err; +} +#endif /* KERNEL_VERSION(2, 6, 27) */ + +/* ---------------------------------------------------------------------- */ + +static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +{ + struct dentry *ret, *parent; + int err, npositive; + struct inode *inode, *h_inode; + struct nameidata tmp_nd, *ndp; + aufs_bindex_t bstart; + struct mutex *mtx; + struct super_block *sb; + + LKTRTrace("dir %lu, %.*s, nd{0x%x}\n", + dir->i_ino, AuDLNPair(dentry), nd ? nd->flags : 0); + AuDebugOn(IS_ROOT(dentry)); + IMustLock(dir); + + sb = dir->i_sb; + si_read_lock(sb, AuLock_FLUSH); + err = au_alloc_dinfo(dentry); + ret = ERR_PTR(err); + if (unlikely(err)) + goto out; + + /* nd can be NULL */ + ndp = au_dup_nd(au_sbi(sb), &tmp_nd, nd); + parent = dentry->d_parent; /* dir inode is locked */ + di_read_lock_parent(parent, AuLock_IR); + npositive = au_lkup_dentry(dentry, au_dbstart(parent), /*type*/0, ndp); + di_read_unlock(parent, AuLock_IR); + err = npositive; + ret = ERR_PTR(err); + if (unlikely(err < 0)) + goto out_unlock; + + inode = NULL; + if (npositive) { + bstart = au_dbstart(dentry); + h_inode = au_h_dptr(dentry, bstart)->d_inode; + AuDebugOn(!h_inode); + if (!S_ISDIR(h_inode->i_mode)) { + /* + * stop 'race'-ing between hardlinks under different + * parents. + */ + mtx = &au_sbr(sb, bstart)->br_xino.xi_nondir_mtx; + mutex_lock(mtx); + inode = au_new_inode(dentry); + mutex_unlock(mtx); + } else + inode = au_new_inode(dentry); + ret = (void *)inode; + } + if (!IS_ERR(inode)) { + ret = d_splice_alias(inode, dentry); + if (unlikely(IS_ERR(ret) && inode)) + ii_write_unlock(inode); + AuDebugOn(nd + && (nd->flags & LOOKUP_OPEN) + && nd->intent.open.file + && nd->intent.open.file->f_dentry); + au_store_fmode_exec(nd, inode); + } + + out_unlock: + di_write_unlock(dentry); + out: + si_read_unlock(sb); + AuTraceErrPtr(ret); + return ret; +} + +/* ---------------------------------------------------------------------- */ + +/* + * decide the branch and the parent dir where we will create a new entry. + * returns new bindex or an error. + * copyup the parent dir if needed. + */ +int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, + struct au_wr_dir_args *args) +{ + int err; + aufs_bindex_t bcpup, bstart, src_bstart; + struct super_block *sb; + struct dentry *parent; + struct au_sbinfo *sbinfo; + const int add_entry = au_ftest_wrdir(args->flags, ADD_ENTRY); + + LKTRTrace("%.*s, src %p, {%d, 0x%x}\n", + AuDLNPair(dentry), src_dentry, args->force_btgt, args->flags); + + sb = dentry->d_sb; + sbinfo = au_sbi(sb); + parent = dget_parent(dentry); + bstart = au_dbstart(dentry); + bcpup = bstart; + if (args->force_btgt < 0) { + if (src_dentry) { + src_bstart = au_dbstart(src_dentry); + if (src_bstart < bstart) + bcpup = src_bstart; + } else if (add_entry) { + err = AuWbrCreate(sbinfo, dentry, + au_ftest_wrdir(args->flags, ISDIR)); + bcpup = err; + } + + if (bcpup < 0 || au_test_ro(sb, bcpup, dentry->d_inode)) { + if (add_entry) + err = AuWbrCopyup(sbinfo, dentry); + else { + di_read_lock_parent(parent, !AuLock_IR); + err = AuWbrCopyup(sbinfo, dentry); + di_read_unlock(parent, !AuLock_IR); + } + bcpup = err; + if (unlikely(err < 0)) + goto out; + } + } else { + bcpup = args->force_btgt; + AuDebugOn(au_test_ro(sb, bcpup, dentry->d_inode)); + } + LKTRTrace("bstart %d, bcpup %d\n", bstart, bcpup); + if (bstart < bcpup) + au_update_dbrange(dentry, /*do_put_zero*/1); + + err = bcpup; + if (bcpup == bstart) + goto out; /* success */ + + /* copyup the new parent into the branch we process */ + if (add_entry) { + au_update_dbstart(dentry); + IMustLock(parent->d_inode); + DiMustWriteLock(parent); + IiMustWriteLock(parent->d_inode); + } else + di_write_lock_parent(parent); + + err = 0; + if (!au_h_dptr(parent, bcpup)) { + if (bstart < bcpup) + err = au_cpdown_dirs(dentry, bcpup); + else + err = au_cpup_dirs(dentry, bcpup); + } + if (!err && add_entry) { + struct dentry *h_parent; + struct inode *h_dir; + + h_parent = au_h_dptr(parent, bcpup); + AuDebugOn(!h_parent); + h_dir = h_parent->d_inode; + AuDebugOn(!h_dir); + mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); + err = au_lkup_neg(dentry, bcpup); + mutex_unlock(&h_dir->i_mutex); + if (bstart < bcpup && au_dbstart(dentry) < 0) { + au_set_dbstart(dentry, 0); + au_update_dbrange(dentry, /*do_put_zero*/0); + } + } + + if (!add_entry) + di_write_unlock(parent); + if (!err) + err = bcpup; /* success */ + out: + dput(parent); + LKTRTrace("err %d\n", err); + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct dentry *au_do_pinned_h_parent(struct au_pin1 *pin, aufs_bindex_t bindex) +{ + if (pin && pin->parent) + return au_h_dptr(pin->parent, bindex); + return NULL; +} + +void au_do_unpin(struct au_pin1 *p, struct au_pin1 *gp) +{ + LKTRTrace("%p, %p\n", p, gp); + AuDebugOn(!p); + + if (unlikely(!p->h_dir)) + return; + + LKTRTrace("p{%.*s, %d, %d, %d, %d}\n", + AuDLNPair(p->dentry), p->lsc_di, p->lsc_hi, + !!p->parent, !!p->h_dir); + + mutex_unlock(&p->h_dir->i_mutex); + if (unlikely(gp)) + au_do_unpin(gp, NULL); + if (!p->di_locked) + di_read_unlock(p->parent, AuLock_IR); + iput(p->h_dir); + dput(p->parent); + p->parent = NULL; + p->h_dir = NULL; +} + +int au_do_pin(struct au_pin1 *p, struct au_pin1 *gp, const aufs_bindex_t bindex, + const int do_gp) +{ + int err; + struct dentry *h_dentry; + + LKTRTrace("%.*s, %d, b%d, %d\n", + AuDLNPair(p->dentry), !!gp, bindex, do_gp); + AuDebugOn(do_gp && !gp); + /* AuDebugOn(!do_gp && gp); */ + + err = 0; + if (unlikely(IS_ROOT(p->dentry))) + goto out; + + h_dentry = NULL; + if (bindex <= au_dbend(p->dentry)) + h_dentry = au_h_dptr(p->dentry, bindex); + + p->parent = dget_parent(p->dentry); + if (!p->di_locked) + di_read_lock(p->parent, AuLock_IR, p->lsc_di); + else + DiMustAnyLock(p->parent); + AuDebugOn(!p->parent->d_inode); + p->h_dir = au_igrab(au_h_iptr(p->parent->d_inode, bindex)); + /* udba case */ + if (unlikely(p->do_verify && !p->h_dir)) { + err = -EIO; + if (!p->di_locked) + di_read_unlock(p->parent, AuLock_IR); + dput(p->parent); + p->parent = NULL; + goto out; + } + + if (unlikely(do_gp)) { + gp->dentry = p->parent; + err = au_do_pin(gp, NULL, bindex, 0); + if (unlikely(err)) + gp->dentry = NULL; + } + mutex_lock_nested(&p->h_dir->i_mutex, p->lsc_hi); + if (!err) { + /* todo: call d_revalidate() here? */ + if (!h_dentry + || !p->do_verify + || !au_verify_parent(h_dentry, p->h_dir)) + goto out; /* success */ + else { + AuWarn1("bypassed %.*s/%.*s?\n", + AuDLNPair(p->parent), AuDLNPair(p->dentry)); + err = -EIO; + } + } + + AuDbgDentry(p->dentry); + AuDbgDentry(h_dentry); + AuDbgDentry(p->parent); + AuDbgInode(p->h_dir); + if (h_dentry) + AuDbgDentry(h_dentry->d_parent); + + au_do_unpin(p, gp); + if (unlikely(do_gp)) + gp->dentry = NULL; + + out: + AuTraceErr(err); + return err; +} + +void au_pin_init(struct au_pin *args, struct dentry *dentry, int di_locked, + int lsc_di, int lsc_hi, int do_gp) +{ + struct au_pin1 *p; + unsigned char do_verify; + + AuTraceEnter(); + + memset(args, 0, sizeof(*args)); + p = args->pin + AuPin_PARENT; + p->dentry = dentry; + p->di_locked = di_locked; + p->lsc_di = lsc_di; + p->lsc_hi = lsc_hi; + p->do_verify = !au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE); + if (!do_gp) + return; + + do_verify = p->do_verify; + p = au_pin_gp(args); + if (unlikely(p)) { + p->lsc_di = lsc_di + 1; /* child first */ + p->lsc_hi = lsc_hi - 1; /* parent first */ + p->do_verify = do_verify; + } +} + +int au_pin(struct au_pin *args, struct dentry *dentry, aufs_bindex_t bindex, + int di_locked, int do_gp) +{ + LKTRTrace("%.*s, b%d, di_locked %d, do_gp %d\n", + AuDLNPair(dentry), bindex, di_locked, do_gp); + + au_pin_init(args, dentry, di_locked, AuLsc_DI_PARENT, AuLsc_I_PARENT2, + do_gp); + return au_do_pin(args->pin + AuPin_PARENT, au_pin_gp(args), bindex, do_gp); +} + +/* ---------------------------------------------------------------------- */ + +struct au_icpup_args { + aufs_bindex_t btgt; + unsigned char isdir, hinotify, did_cpup; /* flags */ + struct dentry *h_dentry; + struct inode *h_inode; + struct au_pin pin; + struct au_hin_ignore ign[2]; + struct vfsub_args vargs; +}; + +/* todo: refine it */ +static int au_lock_and_icpup(struct dentry *dentry, loff_t sz, + struct au_icpup_args *a) +{ + int err; + aufs_bindex_t bstart; + struct super_block *sb; + struct dentry *hi_wh, *parent; + struct inode *inode; + struct au_wr_dir_args wr_dir_args = { + .force_btgt = -1, + .flags = 0 + }; + + LKTRTrace("%.*s, %lld\n", AuDLNPair(dentry), sz); + + di_write_lock_child(dentry); + bstart = au_dbstart(dentry); + sb = dentry->d_sb; + inode = dentry->d_inode; + a->isdir = !!S_ISDIR(inode->i_mode); + if (unlikely(a->isdir)) + au_fset_wrdir(wr_dir_args.flags, ISDIR); + /* plink or hi_wh() */ + if (bstart != au_ibstart(inode)) + wr_dir_args.force_btgt = au_ibstart(inode); + err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); + if (unlikely(err < 0)) + goto out_dentry; + a->btgt = err; + a->did_cpup = (err != bstart); + err = 0; + + /* crazy udba locks */ + a->hinotify = !!au_opt_test(au_mntflags(sb), UDBA_INOTIFY); + parent = NULL; + if (!IS_ROOT(dentry)) { + parent = dget_parent(dentry); + di_write_lock_parent(parent); + } + err = au_pin(&a->pin, dentry, a->btgt, /*di_locked*/!!parent, + /*dp_gp*/a->hinotify); + if (unlikely(err)) { + if (parent) { + di_write_unlock(parent); + dput(parent); + } + goto out_dentry; + } + a->h_dentry = au_h_dptr(dentry, bstart); + a->h_inode = a->h_dentry->d_inode; + AuDebugOn(!a->h_inode); + mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); + if (!a->did_cpup) { + au_unpin_gp(&a->pin); + if (parent) { + au_pin_set_parent_lflag(&a->pin, /*lflag*/0); + di_downgrade_lock(parent, AuLock_IR); + dput(parent); + } + goto out; /* success */ + } + + hi_wh = NULL; + if (!d_unhashed(dentry)) { + if (parent) { + au_pin_set_parent_lflag(&a->pin, /*lflag*/0); + di_downgrade_lock(parent, AuLock_IR); + dput(parent); + } + err = au_sio_cpup_simple(dentry, a->btgt, sz, AuCpup_DTIME); + if (!err) + a->h_dentry = au_h_dptr(dentry, a->btgt); + } else { + hi_wh = au_hi_wh(inode, a->btgt); + if (!hi_wh) { + err = au_sio_cpup_wh(dentry, a->btgt, sz, + /*file*/NULL); + if (!err) + hi_wh = au_hi_wh(inode, a->btgt); + /* todo: revalidate hi_wh? */ + } + if (parent) { + au_pin_set_parent_lflag(&a->pin, /*lflag*/0); + di_downgrade_lock(parent, AuLock_IR); + dput(parent); + } + if (!hi_wh) + a->h_dentry = au_h_dptr(dentry, a->btgt); + else + a->h_dentry = hi_wh; /* do not dget here */ + } + + mutex_unlock(&a->h_inode->i_mutex); + a->h_inode = a->h_dentry->d_inode; + AuDebugOn(!a->h_inode); + if (!err) { + mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); + au_unpin_gp(&a->pin); + goto out; /* success */ + } + + au_unpin(&a->pin); + + out_dentry: + di_write_unlock(dentry); + out: + AuTraceErr(err); + return err; +} + +static int aufs_setattr(struct dentry *dentry, struct iattr *ia) +{ + int err; + struct inode *inode; + struct super_block *sb; + __u32 events; + struct file *file; + loff_t sz; + struct au_icpup_args *a; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + inode = dentry->d_inode; + IMustLock(inode); + + err = -ENOMEM; + a = kzalloc(sizeof(*a), GFP_NOFS); + if (unlikely(!a)) + goto out; + + file = NULL; + sb = dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + vfsub_args_init(&a->vargs, a->ign, au_test_dlgt(au_mntflags(sb)), 0); + + if (ia->ia_valid & ATTR_FILE) { + /* currently ftruncate(2) only */ + file = ia->ia_file; + fi_write_lock(file); + ia->ia_file = au_h_fptr(file, au_fbstart(file)); + } + + sz = -1; + if ((ia->ia_valid & ATTR_SIZE) + && ia->ia_size < i_size_read(inode)) + sz = ia->ia_size; + err = au_lock_and_icpup(dentry, sz, a); + if (unlikely(err < 0)) + goto out_si; + if (a->did_cpup) { + ia->ia_file = NULL; + ia->ia_valid &= ~ATTR_FILE; + } + + if ((ia->ia_valid & ATTR_SIZE) + && ia->ia_size < i_size_read(inode)) { + err = vmtruncate(inode, ia->ia_size); + if (unlikely(err)) + goto out_unlock; + } + + if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) + ia->ia_valid &= ~ATTR_MODE; + + events = 0; + if (unlikely(a->hinotify)) { + events = vfsub_events_notify_change(ia); + if (events) { + if (unlikely(a->isdir)) + vfsub_ign_hinode(&a->vargs, events, + au_hi(inode, a->btgt)); + vfsub_ign_hinode(&a->vargs, events, + au_pinned_hdir(&a->pin, a->btgt)); + } + } + err = vfsub_notify_change(a->h_dentry, ia, &a->vargs); + if (!err) + au_cpup_attr_changeable(inode); + + out_unlock: + mutex_unlock(&a->h_inode->i_mutex); + au_unpin(&a->pin); + di_write_unlock(dentry); + out_si: + if (file) { + fi_write_unlock(file); + ia->ia_file = file; + ia->ia_valid |= ATTR_FILE; + } + si_read_unlock(sb); + kfree(a); + out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int h_readlink(struct dentry *dentry, int bindex, char __user *buf, + int bufsiz) +{ + struct super_block *sb; + struct dentry *h_dentry; + + LKTRTrace("%.*s, b%d, %d\n", AuDLNPair(dentry), bindex, bufsiz); + + h_dentry = au_h_dptr(dentry, bindex); + if (unlikely(/* !h_dentry + || !h_dentry->d_inode + || */ + !h_dentry->d_inode->i_op + || !h_dentry->d_inode->i_op->readlink)) + return -EINVAL; + + sb = dentry->d_sb; + if (!au_test_ro(sb, bindex, dentry->d_inode)) { + touch_atime(au_sbr_mnt(sb, bindex), h_dentry); + au_update_fuse_h_inode(NULL, h_dentry); /*ignore*/ + fsstack_copy_attr_atime(dentry->d_inode, h_dentry->d_inode); + } + return h_dentry->d_inode->i_op->readlink(h_dentry, buf, bufsiz); +} + +static int aufs_readlink(struct dentry *dentry, char __user *buf, int bufsiz) +{ + int err; + + LKTRTrace("%.*s, %d\n", AuDLNPair(dentry), bufsiz); + + aufs_read_lock(dentry, AuLock_IR); + err = h_readlink(dentry, au_dbstart(dentry), buf, bufsiz); + aufs_read_unlock(dentry, AuLock_IR); + AuTraceErr(err); + return err; +} + +static void *aufs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + int err; + char *buf; + mm_segment_t old_fs; + + LKTRTrace("%.*s, nd %.*s\n", + AuDLNPair(dentry), AuDLNPair(nd->path.dentry)); + + err = -ENOMEM; + buf = __getname(); + if (unlikely(!buf)) + goto out; + + aufs_read_lock(dentry, AuLock_IR); + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = h_readlink(dentry, au_dbstart(dentry), (char __user *)buf, + PATH_MAX); + set_fs(old_fs); + aufs_read_unlock(dentry, AuLock_IR); + + if (err >= 0) { + buf[err] = 0; + /* will be freed by put_link */ + nd_set_link(nd, buf); + return NULL; /* success */ + } + __putname(buf); + + out: + path_put(&nd->path); + AuTraceErr(err); + return ERR_PTR(err); +} + +static void aufs_put_link(struct dentry *dentry, struct nameidata *nd, + void *cookie) +{ + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + __putname(nd_get_link(nd)); +} + +/* ---------------------------------------------------------------------- */ + +static void aufs_truncate_range(struct inode *inode, loff_t start, loff_t end) +{ + AuUnsupport(); +} + +/* ---------------------------------------------------------------------- */ + +struct inode_operations aufs_symlink_iop = { + .permission = aufs_permission, + .setattr = aufs_setattr, +#ifdef CONFIG_AUFS_HIN_OR_FUSE + .getattr = aufs_getattr, +#endif + + .readlink = aufs_readlink, + .follow_link = aufs_follow_link, + .put_link = aufs_put_link +}; + +struct inode_operations aufs_dir_iop = { + .create = aufs_create, + .lookup = aufs_lookup, + .link = aufs_link, + .unlink = aufs_unlink, + .symlink = aufs_symlink, + .mkdir = aufs_mkdir, + .rmdir = aufs_rmdir, + .mknod = aufs_mknod, + .rename = aufs_rename, + + .permission = aufs_permission, + .setattr = aufs_setattr, +#ifdef CONFIG_AUFS_HIN_OR_FUSE + .getattr = aufs_getattr, +#endif + +#if 0 /* reserved for future use */ + .setxattr = aufs_setxattr, + .getxattr = aufs_getxattr, + .listxattr = aufs_listxattr, + .removexattr = aufs_removexattr +#endif +}; + +struct inode_operations aufs_iop = { + .permission = aufs_permission, + .setattr = aufs_setattr, +#ifdef CONFIG_AUFS_HIN_OR_FUSE + .getattr = aufs_getattr, +#endif + +#if 0 /* reserved for future use */ + .setxattr = aufs_setxattr, + .getxattr = aufs_getxattr, + .listxattr = aufs_listxattr, + .removexattr = aufs_removexattr, +#endif + + .truncate_range = aufs_truncate_range +}; --- linux-2.6.27.orig/ubuntu/aufs/Kconfig +++ linux-2.6.27/ubuntu/aufs/Kconfig @@ -0,0 +1,265 @@ +config AUFS + tristate "Another unionfs" + help + Aufs is a stackable unification filesystem such as Unionfs, + which unifies several directories and provides a merged single + directory. + In the early days, aufs was entirely re-designed and + re-implemented Unionfs Version 1.x series. After many original + ideas, approaches and improvements, it becomes totally + different from Unionfs while keeping the basic features. + See Unionfs for the basic features. +if AUFS +comment "These options are for 2.6.27-3-generic" +choice + prompt "Maximum number of branches" + default AUFS_BRANCH_MAX_127 + help + Specifies the maximum number of branches (or member directories) in a single aufs. The larger value consumes more system resources and has an impact to performance. +config AUFS_BRANCH_MAX_127 + bool "127" + help + Specifies the maximum number of branches (or member directories) in a single aufs. The larger value consumes more system resources and has an impact to performance. +config AUFS_BRANCH_MAX_511 + bool "511" + help + Specifies the maximum number of branches (or member directories) in a single aufs. The larger value consumes more system resources and has an impact to performance. +config AUFS_BRANCH_MAX_1023 + bool "1023" + help + Specifies the maximum number of branches (or member directories) in a single aufs. The larger value consumes more system resources and has an impact to performance. +config AUFS_BRANCH_MAX_32767 + bool "32767" + help + Specifies the maximum number of branches (or member directories) in a single aufs. The larger value consumes more system resources and has an impact to performance. +endchoice +config AUFS_STAT + bool "Use /fs/aufs/stat" + depends on SYSFS + help + Shows some statistic data via /fs/aufs/stat. + See detail in aufs.5. +comment "SYSFS and AUFS_STAT are disabled" + depends on SYSFS = n +config AUFS_HINOTIFY + bool "Use inotify to detect actions on a branch" + depends on INOTIFY + help + If you want to modify files on branches directly, eg. bypassing aufs, + and want aufs to detect the changes of them fully, then enable this + option and use 'udba=inotify' mount option. + It will have a negative impact to the performance. + See detail in aufs.5. +comment "INOTIFY and AUFS_HINOTIFY are disabled" + depends on INOTIFY = n +config AUFS_EXPORT + bool "NFS-exportable aufs" + depends on (AUFS = y && EXPORTFS = y) || (AUFS = m && EXPORTFS) + help + If you want to export your mounted aufs, then enable this + option. There are several requirements to export aufs. + See detail in aufs.5. +comment "EXPORTFS and AUFS_EXPORT are disabled" + depends on EXPORTFS = n +comment "AUFS_EXPORT is disabled since EXPORTFS is a module but AUFS" + depends on EXPORTFS = m && AUFS = y +config AUFS_INO_T_64 + bool + depends on 64BIT && !(ALPHA || S390) + default y +config AUFS_ROBR + bool "Aufs as an readonly branch of another aufs mount" + help + If you want make your aufs to be a part of another aufs, then + enable this option. In other words, you can specify your aufs + path in 'br:' mount option for another aufs, but cannot + specify 'rw' as the branch permission. + It will have a negative impact to the performance. + See detail in aufs.5. +config AUFS_DLGT + bool "Delegate the internal branch access the kernel thread" + help + If you want aufs to delegate + the internal access to the branches which is made by aufs, to + the kernel thread, in order to hide the access issued by your + application from your LSM or something or make your + application to be traced strictly by the task I/O accounting, + then enable this option and use 'dlgt' mount option. + It will have a negative impact to the performance. + See detail in aufs.5. +config AUFS_HIN_OR_DLGT + bool + depends on AUFS_HINOTIFY || AUFS_DLGT + default y + help + Automatic configuration for internal use. +config AUFS_SHWH + bool "Show whiteouts" + help + If you want to make the whiteouts in aufs visible, then enable + this option and specify 'shwh' mount option. Although it may + sounds like philosophy or something, but in technically it + simply shows the name of whiteout with keeping its behaviour. +config AUFS_RR_SQUASHFS + bool "Make squashfs branch RR (real readonly) by default" + default y + help + If you use squashfs or LZMA patched squashfs as an aufs branch + and want to set '=rr' to it by default, then enable this + configuration. + 'rr' stands for real readonly and it optimizes some aspects of + 'ro.' + See detail in aufs.5. +config AUFS_SEC_PERM_PATCH + bool "sec_perm-2.6.24.patch was applied or not" + depends on AUFS = m + depends on SECURITY + help + If you build aufs as a module and enabled CONFIG_SECURITY, + then you need to apply the patch + 'CVS_TREE/aufs/patch/sec_perm-2.6.24.patch' to your kernel + source, and enable this configuration. + The sec_perm-2.6.24.patch exports a kernel function + security_inode_permission() to modules. +comment "SECURITY and AUFS_SEC_PERM_PATCH are disabled" + depends on SECURITY = n +config AUFS_SPLICE_PATCH + bool "splice.patch for sendfile(2) and splice(2)" + help + If you use 'loopback mount' on a fs-image file, or use + splice(2) or sendfile(2) systemcall in aufs, then you need to + apply the patch 'CVS_TREE/aufs/patch/splice.patch' to your + kernel source, and enable this configuration. + The splice.patch makes the kernel function do_splice_to/from() + global and exports them to modules. +config AUFS_PUT_FILP_PATCH + bool "put_filp.patch for NFS branch" + depends on AUFS = m + depends on NFS_FS + help + If you build aufs as a module and use mounted NFS as an aufs + branch filesystem, then you need to apply the patch + 'CVS_TREE/aufs/patch/put_filp.patch' to your kernel source, + and enable this configuration. + The put_filp.patch exports a kernel function put_filp() to + modules. +comment "NFS_FS and AUFS_PUT_FILP_PATCH are disabled" + depends on NFS_FS = n +config AUFS_LHASH_PATCH + bool "lhash.patch for NFS branch" + depends on NFS_FS + help + If you use mounted NFS as an aufs branch filesystem, then you + need to apply the patch 'CVS_TREE/aufs/patch/lhash.patch' (or + lhash-2.6.22.patch for linux-2.6.22 and later) to your kernel + source, and enable this configuration. + The patch file makes the kernel function __lookup_hash() global + and exports it to modules. +comment "NFS_FS and AUFS_LHASH_PATCH are disabled" + depends on NFS_FS = n +config AUFS_BR_NFS + bool + depends on NFS_FS + default n if (!AUFS_LHASH_PATCH || !(AUFS = y || AUFS_PUT_FILP_PATCH)) + default y + help + Automatic configuration for internal use. + When aufs supports NFS branch, enabled automatically. +config AUFS_BR_XFS + bool + depends on XFS_FS + default y + help + Automatic configuration for internal use. + When aufs supports XFS branch, enabled automatically. +config AUFS_FSYNC_SUPER_PATCH + bool "fsync_super-2.6.xx.patch was applied or not" + depends on AUFS = m + help + If you build aufs as a module and want to flush everything for + branch filesystems which are not marked as 'rr' nor 'rr+wh' at + umount or remount time, then you need to apply the patch + 'CVS_TREE/aufs/patch/fsync_super-2.6.16.patch' or + '...-2.6.19.patch' to your kernel source, and enable this + configuration. + It may be helpful at shutdown time in case of your aufs is a + root filesystem. But this behaviour will not guarantee the + consistency of branch filesystems. To guarantee it, try the + approach described in the aufs manual, and do not forget + installing auplink script. + The fsync_super-2.6.xx.patch does nothing but exports a kernel + function fsync_super() to modules. +config AUFS_DENY_WRITE_ACCESS_PATCH + bool "deny_write_access.patch was applied or not" + depends on AUFS = m + help + A security enhancement to deny writing to a running executable + which exists on an aufs branch filesystem and executed through + aufs. If you applied + 'CVS_TREE/aufs/patch/deny_write_access.patch' to your kernel + and you are compiling aufs as a module, then enable this + option. + The write_deny_access.patch does nothing but export the + function. +config AUFS_WORKAROUND_FUSE + bool "Special handling for FUSE-based filesystem" + depends on FUSE_FS + help + A FUSE-based filesystem may not initialize its inode + attributes and the FUSE developer thinks the inode attributes + in a positive dentry which is returned by VFS lookup operation + are not reliable. + If you use a FUSE-based filesystem as an aufs branch, and it + customizes the inode attribute on it without overriding + fuse_lowlevel_ops.lookup, probably you need to enable this + configuration. + If you enable this configuration, aufs calls getattr operation + in every lookup and revalidate operation for the FUSE-based + filesystem branch. + It will have a negative impact to the performance even if you do + not use a FUSE-based filesystem branch. +config AUFS_HIN_OR_FUSE + bool + depends on AUFS_HINOTIFY || AUFS_WORKAROUND_FUSE + default y + help + Automatic configuration for internal use. +config AUFS_DEBUG + bool "Debug aufs" + default y + help + Enable this to compile aufs internal debug code. + It will have a negative impact to the performance. +config AUFS_MAGIC_SYSRQ + bool + depends on AUFS_DEBUG && MAGIC_SYSRQ + default y + help + Automatic configuration for internal use. + When aufs supports Magic SysRq, enabled automatically. +config AUFS_COMPAT + bool "Compatibility with Unionfs (obsolete)" + help + This makes aufs compatible with unionfs-style mount options and some + behaviours. + The dirs= mount option and =nfsro branch permission flag are always + interpreted as br: mount option and =ro flag respectively. The + 'debug', 'delete' and 'imap' mount options are ignored. + If you disable this option, you will get, + - aufs issues a warning about the ignored mount options + - the default branch permission flag is set. RW for the first branch, + and RO for the rests. + - the name of a internal file which represents the directory is + 'opaque', becomes '.wh..wh..opq' + - the 'diropq=w' mount option is set by default +config AUFS_UNIONFS22_PATCH + bool "Unionfs-2.2 or later patch is applied or not (obsolete)" + help + Unionfs version 2.2 (and later) patch introduces some changes in VFS layer which has an impact to aufs. If you have applied such patch to your kernel, you need to enable this configuration even if you disabled CONFIG_UNIONFS. +config AUFS_UNIONFS23_PATCH + bool "Unionfs-2.3 or later patch is applied or not (obsolete)" + select AUFS_SPLICE_PATCH + select AUFS_UNIONFS22_PATCH + help + Unionfs version 2.3 (and later) patch introduces some changes in VFS layer which has an impact to aufs. If you have applied such patch to your kernel, you need to enable this configuration even if you disabled CONFIG_UNIONFS. +endif --- linux-2.6.27.orig/ubuntu/aufs/module.h +++ linux-2.6.27/ubuntu/aufs/module.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * module initialization and module-global + * + * $Id: module.h,v 1.8 2008/08/25 01:50:37 sfjro Exp $ + */ + +#ifndef __AUFS_MODULE_H__ +#define __AUFS_MODULE_H__ + +#ifdef __KERNEL__ + +/* module parameters */ +extern short aufs_nwkq; +extern int sysaufs_brs; + +/* ---------------------------------------------------------------------- */ + +extern char au_esc_chars[]; +extern int au_dir_roflags; + +/* kmem cache */ +enum { + AuCache_DINFO, + AuCache_ICNTNR, + AuCache_FINFO, + AuCache_VDIR, + AuCache_DEHSTR, +#ifdef CONFIG_AUFS_HINOTIFY + AuCache_HINOTIFY, +#endif + AuCache_Last +}; + +extern struct kmem_cache *au_cachep[]; + +#define AuCacheArgs(type, sz) (type), (sz), 0, SLAB_RECLAIM_ACCOUNT, NULL +#define AuCache(type) \ + kmem_cache_create(AuCacheArgs(#type, sizeof(struct type))) + +/* ---------------------------------------------------------------------- */ + +#define AuCacheFuncs(name, index) \ +static inline void *au_cache_alloc_##name(void) \ +{ return kmem_cache_alloc(au_cachep[index], GFP_NOFS); } \ +static inline void au_cache_free_##name(void *p) \ +{ kmem_cache_free(au_cachep[index], p); } + +AuCacheFuncs(dinfo, AuCache_DINFO); +AuCacheFuncs(icntnr, AuCache_ICNTNR); +AuCacheFuncs(finfo, AuCache_FINFO); +AuCacheFuncs(vdir, AuCache_VDIR); +AuCacheFuncs(dehstr, AuCache_DEHSTR); + +#endif /* __KERNEL__ */ +#endif /* __AUFS_MODULE_H__ */ --- linux-2.6.27.orig/ubuntu/aufs/wkq.h +++ linux-2.6.27/ubuntu/aufs/wkq.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * workqueue for asynchronous/super-io/delegated operations + * + * $Id: wkq.h,v 1.7 2008/09/15 03:16:36 sfjro Exp $ + */ + +#ifndef __AUFS_WKQ_H__ +#define __AUFS_WKQ_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include + +/* ---------------------------------------------------------------------- */ + +/* internal workqueue named AUFS_WKQ_NAME */ +struct au_wkq { + struct workqueue_struct *q; + + /* balancing */ + atomic_t busy; + + /* accounting */ +#ifdef CONFIG_AUFS_STAT + unsigned int max_busy; +#endif +}; + +/* + * in the next operation, wait for the 'nowait' tasks in system-wide workqueue + */ +struct au_nowait_tasks { + atomic_t nw_len; + wait_queue_head_t nw_wq; +}; + +/* ---------------------------------------------------------------------- */ + +extern struct au_wkq *au_wkq; +typedef void (*au_wkq_func_t)(void *args); + +/* wkq flags */ +#define AuWkq_WAIT 1 +#define AuWkq_DLGT (1 << 1) +#define au_ftest_wkq(flags, name) ((flags) & AuWkq_##name) +#define au_fset_wkq(flags, name) { (flags) |= AuWkq_##name; } +#define au_fclr_wkq(flags, name) { (flags) &= ~AuWkq_##name; } +#ifndef CONFIG_AUFS_DLGT +#undef AuWkq_DLGT +#define AuWkq_DLGT 0 +#endif + +int au_wkq_run(au_wkq_func_t func, void *args, struct super_block *sb, + unsigned int flags); +int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, + int dlgt); +int __init au_wkq_init(void); +void au_wkq_fin(void); + +/* ---------------------------------------------------------------------- */ + +static inline int au_test_wkq(struct task_struct *tsk) +{ + return (!tsk->mm && !strcmp(tsk->comm, AUFS_WKQ_NAME)); +#if 0 /* reserved for future use, per-cpu workqueue */ + return (!tsk->mm + && !memcmp(tsk->comm, AUFS_WKQ_NAME "/", + sizeof(AUFS_WKQ_NAME))); +#endif +} + +static inline int au_wkq_wait(au_wkq_func_t func, void *args, int dlgt) +{ + unsigned int flags = AuWkq_WAIT; + if (unlikely(dlgt)) + au_fset_wkq(flags, DLGT); + return au_wkq_run(func, args, /*sb*/NULL, flags); +} + +static inline void au_wkq_max_busy_init(struct au_wkq *wkq) +{ +#ifdef CONFIG_AUFS_STAT + wkq->max_busy = 0; +#endif +} + +/* todo: memory barrier? */ +static inline void au_nwt_init(struct au_nowait_tasks *nwt) +{ + atomic_set(&nwt->nw_len, 0); + smp_mb(); /* atomic_set */ + init_waitqueue_head(&nwt->nw_wq); +} + +/* todo: make it void */ +static inline int au_nwt_done(struct au_nowait_tasks *nwt) +{ + int ret; + + AuTraceEnter(); + + ret = atomic_dec_return(&nwt->nw_len); + if (!ret) + wake_up_all(&nwt->nw_wq); + return ret; +} + +static inline int au_nwt_flush(struct au_nowait_tasks *nwt) +{ + wait_event(nwt->nw_wq, !atomic_read(&nwt->nw_len)); + return 0; +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_WKQ_H__ */ --- linux-2.6.27.orig/ubuntu/aufs/br_nfs.c +++ linux-2.6.27/ubuntu/aufs/br_nfs.c @@ -0,0 +1,347 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * lookup functions for NFS branch in linux-2.6.19 and later + * + * $Id: br_nfs.c,v 1.7 2008/07/21 02:54:22 sfjro Exp $ + */ + +#include "aufs.h" + +static struct file *au_find_h_intent(struct au_hdentry *hd, struct file *file) +{ + struct file *h_file, *hf; + struct au_hdintent *hdi, *tmp, *do_free; + + LKTRTrace("%.*s\n", AuDLNPair(hd->hd_dentry)); + + h_file = NULL; + do_free = NULL; + spin_lock(&hd->hd_lock); + list_for_each_entry_safe(hdi, tmp, hd->hd_intent_list, hdi_list) { + hf = hdi->hdi_file[AuIntent_BRANCH]; + if (hdi->hdi_file[AuIntent_AUFS] == file + && hf->f_dentry == hd->hd_dentry) { + h_file = hf; + do_free = hdi; + list_del(&hdi->hdi_list); + break; + } + } + spin_unlock(&hd->hd_lock); + kfree(do_free); + + return h_file; +} + +struct file *au_h_intent(struct dentry *dentry, aufs_bindex_t bindex, + struct file *file) +{ + struct file *h_file; + struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex; + + LKTRTrace("%.*s, b%d, f %p\n", AuDLNPair(dentry), bindex, file); + DiMustAnyLock(dentry); + AuDebugOn(bindex < au_di(dentry)->di_bstart + || bindex > au_di(dentry)->di_bend); + + h_file = NULL; + if (!hd->hd_intent_list || !file) + return h_file; /* success */ + + /* AuDebugOn(au_test_wkq(current)); */ + h_file = au_find_h_intent(hd, file); + return h_file; +} + +static int au_set_h_intent(struct dentry *dentry, aufs_bindex_t bindex, + struct file *file, struct file *h_file) +{ + int err; + struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex; + struct au_hdintent *hdi; + struct file *hf; + + LKTRTrace("%.*s, b%d, f %p\n", AuDLNPair(dentry), bindex, file); + /* d_revalidate() holds read_lock */ + /* DiMustWriteLock(dentry); */ + AuDebugOn(bindex < au_di(dentry)->di_bstart + || bindex > au_di(dentry)->di_bend + || !file + || !h_file + /* || au_test_wkq(current) */); + + err = -ENOMEM; + if (hd->hd_intent_list) { + while (1) { + hf = au_find_h_intent(hd, file); + if (!hf) + break; + fput(hf); + AuWarn("freed hfile %.*s b%d left\n", + AuDLNPair(dentry), bindex); + } + } else { + spin_lock(&hd->hd_lock); + if (!hd->hd_intent_list) { + hd->hd_intent_list + = kmalloc(sizeof(*hd->hd_intent_list), + GFP_ATOMIC); + if (unlikely(!hd->hd_intent_list)) { + spin_unlock(&hd->hd_lock); + goto out; + } + INIT_LIST_HEAD(hd->hd_intent_list); + } + spin_unlock(&hd->hd_lock); + } + + hdi = kmalloc(sizeof(*hdi), GFP_NOFS); + if (unlikely(!hdi)) + goto out; + + err = 0; + /* hdi->hdi_pid = current->pid; */ + hdi->hdi_file[AuIntent_AUFS] = file; + hdi->hdi_file[AuIntent_BRANCH] = h_file; + spin_lock(&hd->hd_lock); + list_add(&hdi->hdi_list, hd->hd_intent_list); + spin_unlock(&hd->hd_lock); + + out: + AuTraceErr(err); + return err; +} + +int au_br_nfs_h_intent(struct file *nd_file, struct dentry *dentry, + aufs_bindex_t bindex, struct nameidata *nd) +{ + int err; + + AuTraceEnter(); + + err = 0; + if (!nd_file) + goto out; + + AuDebugOn(!nd); + err = au_set_h_intent(dentry, bindex, nd->intent.open.file, nd_file); + if (unlikely(err)) { + fput(nd_file); + au_set_h_dptr(dentry, bindex, NULL); + /* todo: update bstart and bend? */ + } + + out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +void au_hintent_put(struct au_hdentry *hd, int do_free) +{ + struct au_hdintent *hdi, *tmp; + struct file *hf; + + if (unlikely(hd->hd_intent_list)) { + /* no spin lock */ + list_for_each_entry_safe(hdi, tmp, hd->hd_intent_list, + hdi_list) { + LKTRTrace("hdi %p\n", hdi); + hf = hdi->hdi_file[AuIntent_BRANCH]; + if (unlikely(hf)) + fput(hf); + /* list_del(&hdi->hdi_list); */ + kfree(hdi); + } + if (do_free) + kfree(hd->hd_intent_list); + } +} + +/* ---------------------------------------------------------------------- */ + +int au_fake_intent(/* struct au_ndsub *save, */struct nameidata *nd, + int perm) +{ + int err; + + LKTRTrace("perm %d\n", perm); + + err = 0; + nd->intent.open.file = NULL; + if (nd->flags & LOOKUP_OPEN) { + err = -ENFILE; + nd->intent.open.file = get_empty_filp(); + if (unlikely(!nd->intent.open.file)) + goto out; + + err = 0; + if (!au_br_writable(perm)) { + nd->intent.open.flags = FMODE_READ + | au_file_roflags(nd->intent.open.flags); + nd->flags &= ~LOOKUP_CREATE; + } + } + + out: + AuTraceErr(err); + return err; +} + +int au_hin_after_reval(struct nameidata *nd, struct dentry *dentry, + aufs_bindex_t bindex, struct file *file) +{ + int err; + + LKTRTrace("nd %p, %.*s, b%d, f %d\n", + nd, AuDLNPair(dentry), bindex, !!file); + + err = 0; + if ((nd->flags & LOOKUP_OPEN) + && nd->intent.open.file + && !IS_ERR(nd->intent.open.file)) { + if (nd->intent.open.file->f_dentry) { + err = au_set_h_intent(dentry, bindex, file, + nd->intent.open.file); + if (!err) + nd->intent.open.file = NULL; + } + if (unlikely(nd->intent.open.file)) + put_filp(nd->intent.open.file); + } + + return err; +} + +#ifdef CONFIG_AUFS_DLGT +struct au_lookup_hash_args { + struct dentry **errp; + struct qstr *name; + struct dentry *base; + struct nameidata *nd; +}; + +static void au_call_lookup_hash(void *args) +{ + struct au_lookup_hash_args *a = args; + *a->errp = vfsub__lookup_hash(a->name, a->base, a->nd); +} + +static struct dentry * +au_lkup_hash_dlgt(struct qstr *this, struct dentry *parent, + struct nameidata *nd, unsigned int flags) +{ + struct dentry *dentry; + int dirperm1; + + dirperm1 = au_ftest_ndx(flags, DIRPERM1); + if (!dirperm1 && !au_ftest_ndx(flags, DLGT)) + dentry = vfsub__lookup_hash(this, parent, nd); + else { + int wkq_err; + struct au_lookup_hash_args args = { + .errp = &dentry, + .name = this, + .base = parent, + .nd = nd + }; + wkq_err = au_wkq_wait(au_call_lookup_hash, &args, + /*dlgt*/!dirperm1); + if (unlikely(wkq_err)) + dentry = ERR_PTR(wkq_err); + } + + AuTraceErrPtr(dentry); + return dentry; +} +#else +static struct dentry * +au_lkup_hash_dlgt(struct qstr *this, struct dentry *parent, + struct nameidata *nd, unsigned int flags) +{ + return vfsub__lookup_hash(this, parent, nd); +} +#endif /* CONFIG_AUFS_DLGT */ + +struct dentry *au_lkup_hash(const char *name, struct dentry *parent, + int len, struct au_ndx *ndx) +{ + struct dentry *dentry; + char *p; + unsigned long hash; + struct qstr this; + unsigned int c; + struct nameidata tmp_nd, *ndo; + int err; + + LKTRTrace("%.*s/%.*s\n", AuDLNPair(parent), len, name); + + /* todo: export and call __lookup_one_len() in fs/namei.c? */ + dentry = ERR_PTR(-EACCES); + this.name = name; + this.len = len; + if (unlikely(!len)) + goto out; + + p = (void *)name; + hash = init_name_hash(); + while (len--) { + c = *p++; + if (unlikely(c == '/' || c == '\0')) + goto out; + hash = partial_name_hash(c, hash); + } + this.hash = end_name_hash(hash); + + ndo = ndx->nd; + if (ndo) { + tmp_nd = *ndo; + err = au_fake_intent(&tmp_nd, ndx->br->br_perm); + dentry = ERR_PTR(err); + if (unlikely(err)) + goto out_intent; + } else + memset(&tmp_nd, 0, sizeof(tmp_nd)); + + tmp_nd.path.dentry = parent; + tmp_nd.path.mnt = ndx->nfsmnt; + path_get(&tmp_nd.path); + dentry = au_lkup_hash_dlgt(&this, parent, &tmp_nd, ndx->flags); + if (!IS_ERR(dentry)) { + /* why negative dentry for a new dir was unhashed? */ + if (unlikely(d_unhashed(dentry))) + d_rehash(dentry); + if (tmp_nd.intent.open.file + && tmp_nd.intent.open.file->f_dentry) { + ndx->nd_file = tmp_nd.intent.open.file; + tmp_nd.intent.open.file = NULL; + /* au_br_get(ndx->br); */ + } + } + path_put(&tmp_nd.path); + + out_intent: + if (tmp_nd.intent.open.file) + put_filp(tmp_nd.intent.open.file); + out: + AuTraceErrPtr(dentry); + return dentry; +} --- linux-2.6.27.orig/ubuntu/aufs/debug.h +++ linux-2.6.27/ubuntu/aufs/debug.h @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * debug print functions + * + * $Id: debug.h,v 1.8 2008/09/22 03:52:03 sfjro Exp $ + */ + +#ifndef __AUFS_DEBUG_H__ +#define __AUFS_DEBUG_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include + +/* to debug easier, do not make it an inlined function */ +#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx)) + +#ifdef CONFIG_AUFS_DEBUG +/* sparse warns about pointer */ +#define AuDebugOn(a) BUG_ON(!!(a)) +extern atomic_t au_cond; +#define au_debug_on() atomic_inc_return(&au_cond) +#define au_debug_off() atomic_dec_return(&au_cond) +static inline int au_debug_test(void) +{ + return atomic_read(&au_cond); +} +#else +#define AuDebugOn(a) do {} while (0) +#define au_debug_on() do {} while (0) +#define au_debug_off() do {} while (0) +static inline int au_debug_test(void) +{ + return 0; +} +#endif /* CONFIG_AUFS_DEBUG */ + +/* ---------------------------------------------------------------------- */ + +/* debug print */ +#if defined(CONFIG_LKTR) || defined(CONFIG_LKTR_MODULE) +#include +#ifdef CONFIG_AUFS_DEBUG +#undef LktrCond +#define LktrCond unlikely(au_debug_test() || (lktr_cond && lktr_cond())) +#endif +#else +#define LktrCond au_debug_test() +#define LKTRDumpVma(pre, vma, suf) do {} while (0) +#define LKTRDumpStack() do {} while (0) +#define LKTRTrace(fmt, args...) do { \ + if (LktrCond) \ + AuDbg(fmt, ##args); \ +} while (0) +#define LKTRLabel(label) LKTRTrace("%s\n", #label) +#endif /* CONFIG_LKTR */ + +#define AuTraceErr(e) do { \ + if (unlikely((e) < 0)) \ + LKTRTrace("err %d\n", (int)(e)); \ +} while (0) + +#define AuTraceErrPtr(p) do { \ + if (IS_ERR(p)) \ + LKTRTrace("err %ld\n", PTR_ERR(p)); \ +} while (0) + +#define AuTraceEnter() LKTRLabel(enter) + +/* dirty macros for debug print, use with "%.*s" and caution */ +#define AuLNPair(qstr) (qstr)->len, (qstr)->name +#define AuDLNPair(d) AuLNPair(&(d)->d_name) + +/* ---------------------------------------------------------------------- */ + +#define AuDpri(lvl, fmt, arg...) \ + printk(lvl AUFS_NAME " %s:%d:%s[%d]: " fmt, \ + __func__, __LINE__, current->comm, current->pid, ##arg) +#define AuDbg(fmt, arg...) AuDpri(KERN_DEBUG, fmt, ##arg) +#define AuInfo(fmt, arg...) AuDpri(KERN_INFO, fmt, ##arg) +#define AuWarn(fmt, arg...) AuDpri(KERN_WARNING, fmt, ##arg) +#define AuErr(fmt, arg...) AuDpri(KERN_ERR, fmt, ##arg) +#define AuIOErr(fmt, arg...) AuErr("I/O Error, " fmt, ##arg) +#define AuIOErrWhck(fmt, arg...) AuErr("I/O Error, try whck. " fmt, ##arg) +#define AuWarn1(fmt, arg...) do { \ + static unsigned char _c; \ + if (!_c++) AuWarn(fmt, ##arg); \ +} while (0) + +#define AuErr1(fmt, arg...) do { \ + static unsigned char _c; \ + if (!_c++) AuErr(fmt, ##arg); \ +} while (0) + +#define AuIOErr1(fmt, arg...) do { \ + static unsigned char _c; \ + if (!_c++) AuIOErr(fmt, ##arg); \ +} while (0) + +#define AuUnsupportMsg "This operation is not supported." \ + " Please report this application to aufs-users ML." +#define AuUnsupport(fmt, args...) do { \ + AuErr(AuUnsupportMsg "\n" fmt, ##args); \ + dump_stack(); \ +} while (0) + +/* ---------------------------------------------------------------------- */ + +struct au_sbinfo; +#ifdef CONFIG_AUFS_DEBUG +extern char *au_plevel; +struct au_nhash; +void au_dpri_whlist(struct au_nhash *whlist); +struct au_vdir; +void au_dpri_vdir(struct au_vdir *vdir); +void au_dpri_inode(struct inode *inode); +void au_dpri_dentry(struct dentry *dentry); +void au_dpri_file(struct file *filp); +void au_dpri_sb(struct super_block *sb); +void au_dbg_sleep(int sec); +void au_dbg_sleep_jiffy(int jiffy); +#ifndef ATTR_TIMES_SET +#define ATTR_TIMES_SET 0 +#endif +void au_dbg_iattr(struct iattr *ia); +int __init au_debug_init(void); +void au_debug_sbinfo_init(struct au_sbinfo *sbinfo); +#define AuDbgWhlist(w) do { \ + LKTRTrace(#w "\n"); \ + au_dpri_whlist(w); \ +} while (0) + +#define AuDbgVdir(v) do { \ + LKTRTrace(#v "\n"); \ + au_dpri_vdir(v); \ +} while (0) + +#define AuDbgInode(i) do { \ + LKTRTrace(#i "\n"); \ + au_dpri_inode(i); \ +} while (0) + +#define AuDbgDentry(d) do { \ + LKTRTrace(#d "\n"); \ + au_dpri_dentry(d); \ +} while (0) + +#define AuDbgFile(f) do { \ + LKTRTrace(#f "\n"); \ + au_dpri_file(f); \ +} while (0) + +#define AuDbgSb(sb) do { \ + LKTRTrace(#sb "\n"); \ + au_dpri_sb(sb); \ +} while (0) + +#define AuDbgSleep(sec) do { \ + AuDbg("sleep %d sec\n", sec); \ + au_dbg_sleep(sec); \ +} while (0) + +#define AuDbgSleepJiffy(jiffy) do { \ + AuDbg("sleep %d jiffies\n", jiffy); \ + au_dbg_sleep_jiffy(jiffy); \ +} while (0) + +#define AuDbgIAttr(ia) do { \ + AuDbg("ia_valid 0x%x\n", (ia)->ia_valid); \ + au_dbg_iattr(ia); \ +} while (0) +#else +static inline int au_debug_init(void) +{ + return 0; +} +static inline void au_debug_sbinfo_init(struct au_sbinfo *sbinfo) +{ + /* empty */ +} +#define AuDbgWhlist(w) do {} while (0) +#define AuDbgVdir(v) do {} while (0) +#define AuDbgInode(i) do {} while (0) +#define AuDbgDentry(d) do {} while (0) +#define AuDbgFile(f) do {} while (0) +#define AuDbgSb(sb) do {} while (0) +#define AuDbgSleep(sec) do {} while (0) +#define AuDbgSleepJiffy(jiffy) do {} while (0) +#define AuDbgIAttr(ia) do {} while (0) +#endif /* CONFIG_AUFS_DEBUG */ + +#ifdef DbgUdbaRace +#define AuDbgSleep_UdbaRace() AuDbgSleep(DbgUdbaRace) +#else +#define AuDbgSleep_UdbaRace() do {} while (0) +#endif + +#ifdef CONFIG_AUFS_MAGIC_SYSRQ +int __init au_sysrq_init(void); +void au_sysrq_fin(void); + +#ifdef CONFIG_HW_CONSOLE +#define au_dbg_blocked() do { \ + WARN_ON(1); \ + handle_sysrq('w', vc_cons[fg_console].d->vc_tty); \ +} while (0) +#else +#define au_dbg_blocked() do {} while (0) +#endif + +#else +static inline int au_sysrq_init(void) +{ + return 0; +} +#define au_sysrq_fin() do {} while (0) +#define au_dbg_blocked() do {} while (0) +#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DEBUG_H__ */ --- linux-2.6.27.orig/ubuntu/aufs/misc.h +++ linux-2.6.27/ubuntu/aufs/misc.h @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * $Id: misc.h,v 1.7 2008/09/22 03:52:19 sfjro Exp $ + */ + +#ifndef __AUFS_MISC_H__ +#define __AUFS_MISC_H__ + +#ifdef __KERNEL__ + +#include +#include +#include + +/* ---------------------------------------------------------------------- */ + +typedef unsigned int au_gen_t; +/* see linux/include/linux/jiffies.h */ +#define AuGenYounger(a, b) ((int)(b) - (int)(a) < 0) +#define AuGenOlder(a, b) AufsGenYounger(b, a) + +/* ---------------------------------------------------------------------- */ + +struct au_rwsem { + struct rw_semaphore rwsem; +#ifdef CONFIG_AUFS_DEBUG + atomic_t rcnt; +#endif +}; + +#ifdef CONFIG_AUFS_DEBUG +#define AuDbgRcntInit(rw) do { \ + atomic_set(&(rw)->rcnt, 0); \ + smp_mb(); /* atomic set */ \ +} while (0) + +#define AuDbgRcntInc(rw) atomic_inc_return(&(rw)->rcnt) +#define AuDbgRcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->rcnt) < 0) +#else +#define AuDbgRcntInit(rw) do {} while (0) +#define AuDbgRcntInc(rw) do {} while (0) +#define AuDbgRcntDec(rw) do {} while (0) +#endif /* CONFIG_AUFS_DEBUG */ + +static inline void au_rw_init_nolock(struct au_rwsem *rw) +{ + AuDbgRcntInit(rw); + init_rwsem(&rw->rwsem); +} + +static inline void au_rw_init_wlock(struct au_rwsem *rw) +{ + au_rw_init_nolock(rw); + down_write(&rw->rwsem); +} + +static inline void au_rw_init_wlock_nested(struct au_rwsem *rw, + unsigned int lsc) +{ + au_rw_init_nolock(rw); + down_write_nested(&rw->rwsem, lsc); +} + +static inline void au_rw_read_lock(struct au_rwsem *rw) +{ + down_read(&rw->rwsem); + AuDbgRcntInc(rw); +} + +static inline void au_rw_read_lock_nested(struct au_rwsem *rw, unsigned int lsc) +{ + down_read_nested(&rw->rwsem, lsc); + AuDbgRcntInc(rw); +} + +static inline void au_rw_read_unlock(struct au_rwsem *rw) +{ + AuDbgRcntDec(rw); + up_read(&rw->rwsem); + //au_dbg_sleep_jiffy(1 * HZ / HZ); +} + +static inline void au_rw_dgrade_lock(struct au_rwsem *rw) +{ + AuDbgRcntInc(rw); + downgrade_write(&rw->rwsem); + //au_dbg_sleep_jiffy(1 * HZ / HZ); +} + +static inline void au_rw_write_lock(struct au_rwsem *rw) +{ + down_write(&rw->rwsem); +} + +static inline void au_rw_write_lock_nested(struct au_rwsem *rw, + unsigned int lsc) +{ + down_write_nested(&rw->rwsem, lsc); +} + +static inline void au_rw_write_unlock(struct au_rwsem *rw) +{ + up_write(&rw->rwsem); + //au_dbg_sleep_jiffy(1 * HZ / HZ); +} + +/* why is not _nested version defined */ +static inline int au_rw_read_trylock(struct au_rwsem *rw) +{ + int ret = down_read_trylock(&rw->rwsem); + if (ret) + AuDbgRcntInc(rw); + return ret; +} + +static inline int au_rw_write_trylock(struct au_rwsem *rw) +{ + return down_write_trylock(&rw->rwsem); +} + +#undef AuDbgRcntInit +#undef AuDbgRcntInc +#undef AuDbgRcntDec + +/* to debug easier, do not make them inlined functions */ +#define AuRwMustNoWaiters(rw) AuDebugOn(!list_empty(&(rw)->rwsem.wait_list)) +#define AuRwMustAnyLock(rw) AuDebugOn(down_write_trylock(&(rw)->rwsem)) +#ifdef CONFIG_AUFS_DEBUG +#define AuRwMustReadLock(rw) do { \ + AuRwMustAnyLock(rw); \ + AuDebugOn(!atomic_read(&(rw)->rcnt)); \ +} while (0) + +#define AuRwMustWriteLock(rw) do { \ + AuRwMustAnyLock(rw); \ + AuDebugOn(atomic_read(&(rw)->rcnt)); \ +} while (0) +#else +#define AuRwMustReadLock(rw) AuRwMustAnyLock(rw) +#define AuRwMustWriteLock(rw) AuRwMustAnyLock(rw) +#endif /* CONFIG_AUFS_DEBUG */ + +#define AuSimpleLockRwsemFuncs(prefix, param, rwsem) \ +static inline void prefix##_read_lock(param) \ +{ au_rw_read_lock(&(rwsem)); } \ +static inline void prefix##_write_lock(param) \ +{ au_rw_write_lock(&(rwsem)); } \ +static inline int prefix##_read_trylock(param) \ +{ return au_rw_read_trylock(&(rwsem)); } \ +static inline int prefix##_write_trylock(param) \ +{ return au_rw_write_trylock(&(rwsem)); } +/* static inline void prefix##_read_trylock_nested(param, lsc) +{au_rw_read_trylock_nested(&(rwsem, lsc));} +static inline void prefix##_write_trylock_nestd(param, lsc) +{au_rw_write_trylock_nested(&(rwsem), nested);} */ + +#define AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) \ +static inline void prefix##_read_unlock(param) \ +{ au_rw_read_unlock(&(rwsem)); } \ +static inline void prefix##_write_unlock(param) \ +{ au_rw_write_unlock(&(rwsem)); } \ +static inline void prefix##_downgrade_lock(param) \ +{ au_rw_dgrade_lock(&(rwsem)); } + +#define AuSimpleRwsemFuncs(prefix, param, rwsem) \ + AuSimpleLockRwsemFuncs(prefix, param, rwsem) \ + AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) + +/* ---------------------------------------------------------------------- */ + +void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp); + +struct au_nd_store { + unsigned int flags; + struct path path; + struct open_intent intent; +}; +struct au_sbinfo; +void au_nd_store(struct au_nd_store *store, struct nameidata *nd, + struct au_sbinfo *sbinfo); +void au_nd_revert(struct au_nd_store *store, struct nameidata *nd, + struct au_sbinfo *sbinfo); + +struct nameidata *au_dup_nd(struct au_sbinfo *sbinfo, struct nameidata *dst, + struct nameidata *src); + +struct nameidata *au_fake_dm(struct nameidata *fake_nd, struct nameidata *nd, + struct super_block *sb, aufs_bindex_t bindex); +void au_fake_dm_release(struct nameidata *fake_nd); +struct vfsub_args; +int au_h_create(struct inode *h_dir, struct dentry *h_dentry, int mode, + struct vfsub_args *vargs, struct nameidata *nd, + struct vfsmount *nfsmnt); + +struct au_hinode; +int au_copy_file(struct file *dst, struct file *src, loff_t len, + struct au_hinode *hdir, struct super_block *sb, + struct vfsub_args *vargs); + +#endif /* __KERNEL__ */ +#endif /* __AUFS_MISC_H__ */ --- linux-2.6.27.orig/ubuntu/aufs/iinfo.c +++ linux-2.6.27/ubuntu/aufs/iinfo.c @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * inode private data + * + * $Id: iinfo.c,v 1.8 2008/09/15 03:16:36 sfjro Exp $ + */ + +#include "aufs.h" + +struct au_iinfo *au_ii(struct inode *inode) +{ + struct au_iinfo *iinfo; + + iinfo = &(container_of(inode, struct aufs_icntnr, vfs_inode)->iinfo); + /* bad_inode case */ + if (unlikely(!iinfo->ii_hinode)) + return NULL; + AuDebugOn(!iinfo->ii_hinode + /* || au_sbi(inode->i_sb)->si_bend < iinfo->ii_bend */ + || iinfo->ii_bend < iinfo->ii_bstart); + return iinfo; +} + +struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex) +{ + struct inode *hidden_inode; + + IiMustAnyLock(inode); + AuDebugOn(bindex < 0 || au_ibend(inode) < bindex); + hidden_inode = au_ii(inode)->ii_hinode[0 + bindex].hi_inode; + AuDebugOn(hidden_inode && atomic_read(&hidden_inode->i_count) <= 0); + return hidden_inode; +} + +aufs_bindex_t au_ii_br_id(struct inode *inode, aufs_bindex_t bindex) +{ + IiMustAnyLock(inode); + AuDebugOn(bindex < 0 + || au_ibend(inode) < bindex + || !au_ii(inode)->ii_hinode[0 + bindex].hi_inode); + return au_ii(inode)->ii_hinode[0 + bindex].hi_id; +} + +/* todo: hard/soft set? */ +void au_set_ibstart(struct inode *inode, aufs_bindex_t bindex) +{ + struct au_iinfo *iinfo = au_ii(inode); + struct inode *h_inode; + + IiMustWriteLock(inode); + AuDebugOn(au_sbend(inode->i_sb) < bindex); + iinfo->ii_bstart = bindex; + h_inode = iinfo->ii_hinode[bindex + 0].hi_inode; + if (h_inode) + au_cpup_igen(inode, h_inode); +} + +unsigned int au_hi_flags(struct inode *inode, int isdir) +{ + unsigned int flags; + const unsigned int mnt_flags = au_mntflags(inode->i_sb); + + flags = 0; + if (au_opt_test_xino(mnt_flags)) + au_fset_hi(flags, XINO); + if (unlikely(isdir && au_opt_test(mnt_flags, UDBA_INOTIFY))) + au_fset_hi(flags, NOTIFY); + return flags; +} + +void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, + struct inode *h_inode, unsigned int flags) +{ + struct au_hinode *hinode; + struct inode *hi; + struct au_iinfo *iinfo = au_ii(inode); + + LKTRTrace("i%lu, b%d, hi%lu, flags 0x%x\n", + inode->i_ino, bindex, h_inode ? h_inode->i_ino : 0, flags); + IiMustWriteLock(inode); + hinode = iinfo->ii_hinode + bindex; + hi = hinode->hi_inode; + AuDebugOn(bindex < au_ibstart(inode) || au_ibend(inode) < bindex); + AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); + AuDebugOn(h_inode && hi); + + if (hi) + au_hiput(hinode); + hinode->hi_inode = h_inode; + if (h_inode) { + int err; + struct super_block *sb = inode->i_sb; + + if (bindex == iinfo->ii_bstart) + au_cpup_igen(inode, h_inode); + hinode->hi_id = au_sbr_id(sb, bindex); + if (au_ftest_hi(flags, XINO)) { + struct au_xino_entry xinoe = { + .ino = inode->i_ino, + /* .h_gen = h_inode->i_generation */ + }; + err = au_xino_write(sb, bindex, h_inode->i_ino, &xinoe); + if (unlikely(err)) + AuIOErr1("failed au_xino_write() %d\n", err); + } + + if (unlikely(au_ftest_hi(flags, NOTIFY) + && au_br_hinotifyable(au_sbr_perm(sb, bindex)))) { + err = au_hin_alloc(hinode, inode, h_inode); + if (unlikely(err)) + AuIOErr1("au_hin_alloc() %d\n", err); + } + } +} + +void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, + struct dentry *h_wh) +{ + struct au_hinode *hinode; + + IiMustWriteLock(inode); + hinode = au_ii(inode)->ii_hinode + bindex; + AuDebugOn(hinode->hi_whdentry); + hinode->hi_whdentry = h_wh; +} + +void au_update_iigen(struct inode *inode) +{ + AuDebugOn(!inode->i_sb); + atomic_set(&au_ii(inode)->ii_generation, au_sigen(inode->i_sb)); + /* smp_mb(); */ /* atomic_set */ +} + +/* it may be called at remount time, too */ +void au_update_brange(struct inode *inode, int do_put_zero) +{ + struct au_iinfo *iinfo; + + LKTRTrace("i%lu, %d\n", inode->i_ino, do_put_zero); + IiMustWriteLock(inode); + + iinfo = au_ii(inode); + if (unlikely(!iinfo) || iinfo->ii_bstart < 0) + return; + + if (do_put_zero) { + aufs_bindex_t bindex; + for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; + bindex++) { + struct inode *h_i; + h_i = iinfo->ii_hinode[0 + bindex].hi_inode; + if (h_i && !h_i->i_nlink) + au_set_h_iptr(inode, bindex, NULL, 0); + } + } + + iinfo->ii_bstart = -1; + while (++iinfo->ii_bstart <= iinfo->ii_bend) + if (iinfo->ii_hinode[0 + iinfo->ii_bstart].hi_inode) + break; + if (iinfo->ii_bstart > iinfo->ii_bend) { + iinfo->ii_bstart = -1; + iinfo->ii_bend = -1; + return; + } + + iinfo->ii_bend++; + while (0 <= --iinfo->ii_bend) + if (iinfo->ii_hinode[0 + iinfo->ii_bend].hi_inode) + break; + AuDebugOn(iinfo->ii_bstart > iinfo->ii_bend || iinfo->ii_bend < 0); +} + +/* ---------------------------------------------------------------------- */ + +int au_iinfo_init(struct inode *inode) +{ + struct au_iinfo *iinfo; + struct super_block *sb; + int nbr, i; + + sb = inode->i_sb; + AuDebugOn(!sb); + iinfo = &(container_of(inode, struct aufs_icntnr, vfs_inode)->iinfo); + AuDebugOn(iinfo->ii_hinode); + nbr = au_sbend(sb) + 1; + if (unlikely(nbr <= 0)) + nbr = 1; + iinfo->ii_hinode = kcalloc(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS); + if (iinfo->ii_hinode) { + for (i = 0; i < nbr; i++) + iinfo->ii_hinode[i].hi_id = -1; + atomic_set(&iinfo->ii_generation, au_sigen(sb)); + /* smp_mb(); */ /* atomic_set */ + au_rw_init_nolock(&iinfo->ii_rwsem); + iinfo->ii_bstart = -1; + iinfo->ii_bend = -1; + iinfo->ii_vdir = NULL; + return 0; + } + return -ENOMEM; +} + +static int au_iinfo_write0(struct super_block *sb, struct au_hinode *hinode, + ino_t ino) +{ + int err, locked; + aufs_bindex_t bindex; + + err = 0; + locked = si_noflush_read_trylock(sb); /* crucio! */ + bindex = au_br_index(sb, hinode->hi_id); + if (bindex >= 0) + err = au_xino_write0(sb, bindex, hinode->hi_inode->i_ino, ino); + /* error action? */ + if (locked) + si_read_unlock(sb); + return err; +} + +void au_iinfo_fin(struct inode *inode) +{ + struct au_iinfo *iinfo; + aufs_bindex_t bend; + unsigned char unlinked; + struct au_hinode *hi; + struct super_block *sb; + ino_t ino; + + iinfo = au_ii(inode); + /* bad_inode case */ + if (unlikely(!iinfo)) + return; + + if (unlikely(iinfo->ii_vdir)) + au_vdir_free(iinfo->ii_vdir); + + if (iinfo->ii_bstart >= 0) { + sb = inode->i_sb; + unlinked = !inode->i_nlink; + ino = 0; + if (unlinked) + ino = inode->i_ino; + hi = iinfo->ii_hinode + iinfo->ii_bstart; + bend = iinfo->ii_bend; + while (iinfo->ii_bstart++ <= bend) { + if (hi->hi_inode) { + if (unlinked || !hi->hi_inode->i_nlink) { + au_iinfo_write0(sb, hi, ino); + /* ignore this error */ + ino = 0; + } + au_hiput(hi); + } + hi++; + } + } + + kfree(iinfo->ii_hinode); +} --- linux-2.6.27.orig/ubuntu/aufs/file.c +++ linux-2.6.27/ubuntu/aufs/file.c @@ -0,0 +1,762 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * handling file/dir, and address_space operation + * + * $Id: file.c,v 1.16 2008/09/22 03:52:09 sfjro Exp $ + */ + +#include +#include "aufs.h" + +/* + * a dirty trick for handling FMODE_EXEC and deny_write_access(). + * because FMODE_EXEC flag is not passed to f_op->open(), + * set it to file->private_data temporary. + */ +#if !defined(CONFIG_AUFS_MODULE) || defined(CONFIG_AUFS_DENY_WRITE_ACCESS_PATCH) +int au_store_fmode_exec(struct nameidata *nd, struct inode *inode) +{ + int err; + union { + void *p; + unsigned long ul; + } u; + + err = 0; + if (nd + && (nd->flags & LOOKUP_OPEN) + && nd->intent.open.file + && (nd->intent.open.flags & FMODE_EXEC) + && inode + && S_ISREG(inode->i_mode)) { + u.ul = nd->intent.open.flags; + nd->intent.open.file->private_data = u.p; + /* smp_mb(); */ + err = 1; + } + + return err; +} +#endif + +/* drop flags for writing */ +unsigned int au_file_roflags(unsigned int flags) +{ + flags &= ~(O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC); + flags |= O_RDONLY | O_NOATIME; + return flags; +} + +/* common functions to regular file and dir */ +struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, + struct file *file) +{ + struct file *h_file; + struct dentry *h_dentry; + struct inode *h_inode; + struct super_block *sb; + struct au_branch *br; + int err; + + LKTRTrace("%.*s, b%d, flags 0%o, f %d\n", + AuDLNPair(dentry), bindex, flags, !!file); + h_dentry = au_h_dptr(dentry, bindex); + AuDebugOn(!h_dentry); + h_inode = h_dentry->d_inode; + + /* a race condition can happen between open and unlink/rmdir */ + h_file = ERR_PTR(-ENOENT); + if (unlikely((!d_unhashed(dentry) && d_unhashed(h_dentry)) + || !h_inode)) + goto out; + + sb = dentry->d_sb; + br = au_sbr(sb, bindex); + au_br_get(br); + /* drop flags for writing */ + if (au_test_ro(sb, bindex, dentry->d_inode)) + flags = au_file_roflags(flags); + flags &= ~O_CREAT; + + h_file = NULL; + if (unlikely(file && au_test_nfs(h_dentry->d_sb))) + h_file = au_h_intent(dentry, bindex, file); + if (!h_file) + h_file = dentry_open(dget(h_dentry), mntget(br->br_mnt), flags); + + /* + * a dirty trick for handling FMODE_EXEC and deny_write_access(). + */ + if (file && (file->f_mode & FMODE_EXEC)) { + h_file->f_mode |= FMODE_EXEC; + smp_mb(); /* flush f_mode */ + err = au_deny_write_access(h_file); + if (unlikely(err)) { + fput(h_file); + h_file = ERR_PTR(err); + } + } + if (IS_ERR(h_file)) + au_br_put(br); + +out: + AuTraceErrPtr(h_file); + return h_file; +} + +static int do_coo(struct dentry *dentry, aufs_bindex_t bstart) +{ + int err; + struct dentry *parent; + aufs_bindex_t bcpup; + struct mutex *h_mtx; + struct super_block *sb; + struct au_pin pin; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + AuDebugOn(IS_ROOT(dentry)); + DiMustWriteLock(dentry); + + parent = dget_parent(dentry); + di_write_lock_parent(parent); + sb = dentry->d_sb; + err = AuWbrCopyup(au_sbi(sb), dentry); + bcpup = err; + if (err < 0) { + err = 0; /* stop copyup, it is not an error */ + goto out_dgrade; + } + err = 0; + + if (!au_h_dptr(parent, bcpup)) { + err = au_cpup_dirs(dentry, bcpup); + if (unlikely(err)) + goto out_dgrade; + } + + di_downgrade_lock(parent, AuLock_IR); + err = au_pin(&pin, dentry, bcpup, /*di_locked*/1, + /*do_gp*/au_opt_test(au_mntflags(sb), UDBA_INOTIFY)); + if (unlikely(err)) + goto out; + h_mtx = &au_h_dptr(dentry, bstart)->d_inode->i_mutex; + mutex_lock_nested(h_mtx, AuLsc_I_CHILD); + AuDebugOn(au_h_dptr(dentry, bcpup)); + err = au_sio_cpup_simple(dentry, bcpup, -1, AuCpup_DTIME); + AuTraceErr(err); + mutex_unlock(h_mtx); + au_unpin(&pin); + goto out; + + out_dgrade: + di_downgrade_lock(parent, AuLock_IR); + out: + di_read_unlock(parent, AuLock_IR); + dput(parent); + AuTraceErr(err); + return err; +} + +int au_do_open(struct inode *inode, struct file *file, + int (*open)(struct file *file, int flags)) +{ + int err; + struct dentry *dentry; + struct super_block *sb; + aufs_bindex_t bstart; + unsigned char coo; + + dentry = file->f_dentry; + LKTRTrace("i%lu, %.*s\n", inode->i_ino, AuDLNPair(dentry)); + + sb = dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + coo = 0; + switch (au_mntflags(sb) & AuOptMask_COO) { + case AuOpt_COO_LEAF: + coo = !S_ISDIR(inode->i_mode); + break; + case AuOpt_COO_ALL: + coo = 1; + break; + } + err = au_finfo_init(file); + if (unlikely(err)) + goto out; + + if (!coo) + di_read_lock_child(dentry, AuLock_IR); + else { + di_write_lock_child(dentry); + bstart = au_dbstart(dentry); + if (au_test_ro(sb, bstart, dentry->d_inode)) { + err = do_coo(dentry, bstart); + if (err) { + di_write_unlock(dentry); + goto out_finfo; + } + } + di_downgrade_lock(dentry, AuLock_IR); + } + + err = open(file, file->f_flags); + di_read_unlock(dentry, AuLock_IR); + + out_finfo: + fi_write_unlock(file); + if (unlikely(err)) + au_finfo_fin(file); + out: + si_read_unlock(sb); + AuTraceErr(err); + return err; +} + +int au_reopen_nondir(struct file *file) +{ + int err; + aufs_bindex_t bstart, bindex, bend; + struct dentry *dentry; + struct file *h_file, *h_file_tmp; + + dentry = file->f_dentry; + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + bstart = au_dbstart(dentry); + //bstart = au_ibstart(inode); + AuDebugOn(S_ISDIR(dentry->d_inode->i_mode) + || !au_h_dptr(dentry, bstart)->d_inode); + + h_file_tmp = NULL; + if (au_fbstart(file) == bstart) { + h_file = au_h_fptr(file, bstart); + if (file->f_mode == h_file->f_mode) + return 0; /* success */ + h_file_tmp = h_file; + get_file(h_file_tmp); + au_set_h_fptr(file, bstart, NULL); + } + AuDebugOn(au_fbstart(file) < bstart + || au_fi(file)->fi_hfile[0 + bstart].hf_file); + + h_file = au_h_open(dentry, bstart, file->f_flags & ~O_TRUNC, file); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out; /* todo: close all? */ + err = 0; + /* cpup_file_flags(h_file, file); */ + au_set_fbstart(file, bstart); + au_set_h_fptr(file, bstart, h_file); + au_update_figen(file); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + + /* close lower files */ + bend = au_fbend(file); + for (bindex = bstart + 1; bindex <= bend; bindex++) + au_set_h_fptr(file, bindex, NULL); + au_set_fbend(file, bstart); + + out: + if (h_file_tmp) + fput(h_file_tmp); + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_ready_to_write_wh(struct file *file, loff_t len, + aufs_bindex_t bcpup) +{ + int err; + aufs_bindex_t old_bstart; + struct inode *inode; + struct dentry *dentry, *hi_wh, *old_h_dentry; + struct au_dinfo *dinfo; + struct super_block *sb; + + AuTraceEnter(); + + dentry = file->f_dentry; + inode = dentry->d_inode; + hi_wh = au_hi_wh(inode, bcpup); + if (!hi_wh) + err = au_sio_cpup_wh(dentry, bcpup, len, file); + else { + /* already copied-up after unlink */ + dinfo = au_di(dentry); + old_bstart = dinfo->di_bstart; + dinfo->di_bstart = bcpup; + old_h_dentry = dinfo->di_hdentry[0 + bcpup].hd_dentry; + dinfo->di_hdentry[0 + bcpup].hd_dentry = hi_wh; + err = au_reopen_nondir(file); + dinfo->di_hdentry[0 + bcpup].hd_dentry = old_h_dentry; + dinfo->di_bstart = old_bstart; + } + + sb = dentry->d_sb; + if (!err && inode->i_nlink > 1 && au_opt_test(au_mntflags(sb), PLINK)) + au_plink_append(sb, inode, au_h_dptr(dentry, bcpup), bcpup); + + AuTraceErr(err); + return err; +} + +/* + * prepare the @file for writing. + */ +int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin) +{ + int err; + struct dentry *dentry, *parent, *h_dentry; + struct inode *h_inode, *inode; + struct super_block *sb; + aufs_bindex_t bstart, bcpup; + + dentry = file->f_dentry; + LKTRTrace("%.*s, len %lld\n", AuDLNPair(dentry), len); + FiMustWriteLock(file); + + sb = dentry->d_sb; + bstart = au_fbstart(file); + AuDebugOn(au_fbr(file, bstart) != au_sbr(sb, bstart)); + + inode = dentry->d_inode; + AuDebugOn(S_ISDIR(inode->i_mode)); + LKTRTrace("rdonly %d, bstart %d\n", + au_test_ro(sb, bstart, inode), bstart); + + err = au_test_ro(sb, bstart, inode); + if (!err && (au_h_fptr(file, bstart)->f_mode & FMODE_WRITE)) { + err = au_pin(pin, dentry, bstart, /*di_locked*/0, /*dp_gp*/0); + goto out; + } + + /* need to cpup */ + parent = dget_parent(dentry); + di_write_lock_parent(parent); + err = AuWbrCopyup(au_sbi(sb), dentry); + bcpup = err; + if (unlikely(err < 0)) + goto out_dgrade; + err = 0; + + if (!au_h_dptr(parent, bcpup)) { + err = au_cpup_dirs(dentry, bcpup); + if (unlikely(err)) + goto out_dgrade; + } + + err = au_pin(pin, dentry, bcpup, /*di_locked*/1, + /*dp_gp*/au_opt_test(au_mntflags(sb), UDBA_INOTIFY)); + if (unlikely(err)) + goto out_dgrade; + + AuDebugOn(au_fbstart(file) != bstart); + h_dentry = au_h_fptr(file, bstart)->f_dentry; + h_inode = h_dentry->d_inode; + mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); + if (d_unhashed(dentry) /* || d_unhashed(h_dentry) */ + /* || !h_inode->i_nlink */) { + err = au_ready_to_write_wh(file, len, bcpup); + di_downgrade_lock(parent, AuLock_IR); + } else { + di_downgrade_lock(parent, AuLock_IR); + if (!au_h_dptr(dentry, bcpup)) + err = au_sio_cpup_simple(dentry, bcpup, len, + AuCpup_DTIME); + AuTraceErr(err); + if (!err) + err = au_reopen_nondir(file); + AuTraceErr(err); + } + mutex_unlock(&h_inode->i_mutex); + + if (!err) { + au_unpin_gp(pin); + au_pin_set_parent_lflag(pin, /*lflag*/0); + goto out_dput; /* success */ + } + au_unpin(pin); + goto out_unlock; + + out_dgrade: + di_downgrade_lock(parent, AuLock_IR); + out_unlock: + di_read_unlock(parent, AuLock_IR); + out_dput: + dput(parent); + out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_file_refresh_by_inode(struct file *file, int *need_reopen) +{ + int err; + struct au_finfo *finfo; + struct dentry *dentry, *parent, *old_h_dentry, *hi_wh; + struct inode *inode, *dir; + aufs_bindex_t bstart, new_bstart, old_bstart; + struct super_block *sb; + struct au_dinfo *dinfo; + unsigned int mnt_flags; + struct au_pin pin; + + dentry = file->f_dentry; + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + FiMustWriteLock(file); + + err = 0; + finfo = au_fi(file); + inode = dentry->d_inode; + sb = dentry->d_sb; + mnt_flags = au_mntflags(sb); + again: + bstart = au_ibstart(inode); + if (bstart == finfo->fi_bstart) + goto out; + + new_bstart = bstart; + parent = dget_parent(dentry); + dir = parent->d_inode; + if (au_test_ro(sb, bstart, inode)) { + di_read_lock_parent(parent, !AuLock_IR); + err = AuWbrCopyup(au_sbi(sb), dentry); + new_bstart = err; + di_read_unlock(parent, !AuLock_IR); + if (unlikely(err < 0)) + goto out_dput; + err = 0; + } + /* someone else might change our inode while we were sleeping */ + /* todo: test more? */ + if (bstart != au_ibstart(inode)) { + err = 0; + dput(parent); + goto again; + } + di_read_lock_parent(parent, AuLock_IR); + bstart = new_bstart; + + hi_wh = au_hi_wh(inode, bstart); + if (au_opt_test(mnt_flags, PLINK) + && au_plink_test(sb, inode) + && !d_unhashed(dentry)) { + err = au_test_and_cpup_dirs(dentry, bstart); + if (unlikely(err)) + goto out_unlock; + + /* always superio. */ +#if 1 + err = au_pin(&pin, dentry, bstart, /*di_locked*/1, + /*do_gp*/au_opt_test(mnt_flags, UDBA_INOTIFY)); + if (!err) + err = au_sio_cpup_simple(dentry, bstart, -1, AuCpup_DTIME); + au_unpin(&pin); +#else /* reserved for future use */ + if (!au_test_wkq(current)) { + int wkq_err; + struct cpup_pseudo_link_args args = { + .errp = &err, + .dentry = dentry, + .bdst = bstart, + .do_lock = 1 + }; + wkq_err = au_wkq_wait(call_cpup_pseudo_link, &args); + if (unlikely(wkq_err)) + err = wkq_err; + } else + err = cpup_pseudo_link(dentry, bstart, /*do_lock*/1); +#endif + } else if (hi_wh) { + /* already copied-up after unlink */ + dinfo = au_di(dentry); + old_bstart = dinfo->di_bstart; + dinfo->di_bstart = bstart; + old_h_dentry = dinfo->di_hdentry[0 + bstart].hd_dentry; + dinfo->di_hdentry[0 + bstart].hd_dentry = hi_wh; + err = au_reopen_nondir(file); + dinfo->di_hdentry[0 + bstart].hd_dentry = old_h_dentry; + dinfo->di_bstart = old_bstart; + *need_reopen = 0; + } + + out_unlock: + di_read_unlock(parent, AuLock_IR); + out_dput: + dput(parent); + out: + AuTraceErr(err); + return err; +} + +/* + * after branch manipulating, refresh the file. + */ +static int refresh_file(struct file *file, int (*reopen)(struct file *file)) +{ + int err, new_sz, need_reopen; + struct dentry *dentry; + aufs_bindex_t bend, bindex, brid; + struct au_hfile *p; + struct au_finfo *finfo; + struct super_block *sb; + struct inode *inode; + + dentry = file->f_dentry; + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + FiMustWriteLock(file); + DiMustAnyLock(dentry); + inode = dentry->d_inode; + IiMustAnyLock(inode); + + err = -ENOMEM; + sb = dentry->d_sb; + finfo = au_fi(file); + new_sz = sizeof(*finfo->fi_hfile) * (au_sbend(sb) + 1); + p = au_kzrealloc(finfo->fi_hfile, sizeof(*p) * (finfo->fi_bend + 1), + new_sz, GFP_NOFS); + if (unlikely(!p)) + goto out; + finfo->fi_hfile = p; + + p += finfo->fi_bstart; + brid = p->hf_br->br_id; + bend = finfo->fi_bend; + for (bindex = finfo->fi_bstart; bindex <= bend; bindex++, p++) { + struct au_hfile tmp, *q; + aufs_bindex_t new_bindex; + + if (!p->hf_file) + continue; + new_bindex = au_find_bindex(sb, p->hf_br); + if (new_bindex == bindex) + continue; + /* todo: test more? */ + if (new_bindex < 0) { + au_set_h_fptr(file, bindex, NULL); + continue; + } + + /* swap two hidden inode, and loop again */ + q = finfo->fi_hfile + new_bindex; + tmp = *q; + *q = *p; + *p = tmp; + if (tmp.hf_file) { + bindex--; + p--; + } + } + { + aufs_bindex_t s = finfo->fi_bstart, e = finfo->fi_bend; + finfo->fi_bstart = 0; + finfo->fi_bend = au_sbend(sb); + finfo->fi_bstart = s; + finfo->fi_bend = e; + } + + p = finfo->fi_hfile; + if (!au_test_mmapped(file) && !d_unhashed(dentry)) { + bend = au_sbend(sb); + for (finfo->fi_bstart = 0; finfo->fi_bstart <= bend; + finfo->fi_bstart++, p++) + if (p->hf_file) { + if (p->hf_file->f_dentry + && p->hf_file->f_dentry->d_inode) + break; + else + au_hfput(p); + } + } else { + bend = au_br_index(sb, brid); + for (finfo->fi_bstart = 0; finfo->fi_bstart < bend; + finfo->fi_bstart++, p++) + if (p->hf_file) + au_hfput(p); + bend = au_sbend(sb); + } + + p = finfo->fi_hfile + bend; + for (finfo->fi_bend = bend; finfo->fi_bend >= finfo->fi_bstart; + finfo->fi_bend--, p--) + if (p->hf_file) { + if (p->hf_file->f_dentry + && p->hf_file->f_dentry->d_inode) + break; + else + au_hfput(p); + } + AuDebugOn(finfo->fi_bend < finfo->fi_bstart); + + err = 0; + need_reopen = 1; + if (!au_test_mmapped(file)) + err = au_file_refresh_by_inode(file, &need_reopen); + if (!err && need_reopen && !d_unhashed(dentry)) + err = reopen(file); + if (!err) { + au_update_figen(file); + return 0; /* success */ + } + + /* error, close all hidden files */ + bend = au_fbend(file); + for (bindex = au_fbstart(file); bindex <= bend; bindex++) + au_set_h_fptr(file, bindex, NULL); + + out: + AuTraceErr(err); + return err; +} + +/* common function to regular file and dir */ +int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), + int wlock, int locked) +{ + int err; + struct dentry *dentry; + struct super_block *sb; + aufs_bindex_t bstart; + unsigned char pseudo_link; + au_gen_t sgen, fgen; + + dentry = file->f_dentry; + LKTRTrace("%.*s, w %d, l %d\n", AuDLNPair(dentry), wlock, locked); + sb = dentry->d_sb; + SiMustAnyLock(sb); + + err = 0; + sgen = au_sigen(sb); + fi_write_lock(file); + fgen = au_figen(file); + di_write_lock_child(dentry); + bstart = au_dbstart(dentry); + pseudo_link = (bstart != au_ibstart(dentry->d_inode)); + if (sgen == fgen && !pseudo_link && au_fbstart(file) == bstart) { + if (!wlock) { + di_downgrade_lock(dentry, AuLock_IR); + fi_downgrade_lock(file); + } + goto out; /* success */ + } + + LKTRTrace("sgen %d, fgen %d\n", sgen, fgen); + if (unlikely(sgen != au_digen(dentry) + || sgen != au_iigen(dentry->d_inode))) { + /* + * d_path() and path_lookup() is a simple and good approach + * to revalidate. but si_rwsem in DEBUG_RWSEM will cause a + * deadlock. removed the code. + */ + err = au_reval_dpath(dentry, sgen); + if (unlikely(err < 0)) + goto out; + AuDebugOn(au_digen(dentry) != sgen + || au_iigen(dentry->d_inode) != sgen); + } + + err = refresh_file(file, reopen + /* , au_opt_test(au_mnt_flags(sb), REFROF) */); + if (!err) { + if (!wlock) { + di_downgrade_lock(dentry, AuLock_IR); + fi_downgrade_lock(file); + } + } else { + di_write_unlock(dentry); + fi_write_unlock(file); + } + + out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* cf. aufs_nopage() */ +/* for madvise(2) */ +static int aufs_readpage(struct file *file, struct page *page) +{ + AuTraceEnter(); + unlock_page(page); + return 0; +} + +/* they will never be called. */ +#ifdef CONFIG_AUFS_DEBUG +static int aufs_prepare_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ AuUnsupport(); return 0; } +static int aufs_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ AuUnsupport(); return 0; } +static int aufs_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) +{ AuUnsupport(); return 0; } +static int aufs_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) +{ AuUnsupport(); return 0; } +static int aufs_writepage(struct page *page, struct writeback_control *wbc) +{ AuUnsupport(); return 0; } +static void aufs_sync_page(struct page *page) +{ AuUnsupport(); } + +static int aufs_set_page_dirty(struct page *page) +{ AuUnsupport(); return 0; } +static void aufs_invalidatepage(struct page *page, unsigned long offset) +{ AuUnsupport(); } +static int aufs_releasepage(struct page *page, gfp_t gfp) +{ AuUnsupport(); return 0; } +static ssize_t aufs_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, loff_t offset, + unsigned long nr_segs) +{ AuUnsupport(); return 0; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) +static struct page *aufs_get_xip_page(struct address_space *mapping, + sector_t offset, int create) +{ AuUnsupport(); return NULL; } +#endif +#endif /* CONFIG_AUFS_DEBUG */ + +struct address_space_operations aufs_aop = { + .readpage = aufs_readpage, +#ifdef CONFIG_AUFS_DEBUG + .writepage = aufs_writepage, + .sync_page = aufs_sync_page, + .set_page_dirty = aufs_set_page_dirty, + .prepare_write = aufs_prepare_write, + .commit_write = aufs_commit_write, + .write_begin = aufs_write_begin, + .write_end = aufs_write_end, + .invalidatepage = aufs_invalidatepage, + .releasepage = aufs_releasepage, + .direct_IO = aufs_direct_IO, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) + .get_xip_page = aufs_get_xip_page, +#endif +#endif /* CONFIG_AUFS_DEBUG */ +}; --- linux-2.6.27.orig/ubuntu/aufs/cpup.c +++ linux-2.6.27/ubuntu/aufs/cpup.c @@ -0,0 +1,1105 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * copy-up functions, see wbr_policy.c for copy-down + * + * $Id: cpup.c,v 1.17 2008/09/22 03:52:19 sfjro Exp $ + */ + +#include +#include +#include "aufs.h" + +/* todo? violent cpup_attr_*() functions don't care inode lock */ + +void au_cpup_attr_timesizes(struct inode *inode) +{ + struct inode *h_inode; + + LKTRTrace("i%lu\n", inode->i_ino); + /* todo? IMustLock(inode); */ + h_inode = au_h_iptr(inode, au_ibstart(inode)); + AuDebugOn(!h_inode); + /* todo? IMustLock(!h_inode); */ + + fsstack_copy_attr_times(inode, h_inode); + vfsub_copy_inode_size(inode, h_inode); +} + +void au_cpup_attr_nlink(struct inode *inode) +{ + struct inode *h_inode; + + LKTRTrace("i%lu\n", inode->i_ino); + /* todo? IMustLock(inode); */ + AuDebugOn(!inode->i_mode); + + h_inode = au_h_iptr(inode, au_ibstart(inode)); + inode->i_nlink = h_inode->i_nlink; + + /* + * fewer nlink makes find(1) noisy, but larger nlink doesn't. + * it may includes whplink directory. + */ + if (unlikely(S_ISDIR(h_inode->i_mode))) { + aufs_bindex_t bindex, bend; + bend = au_ibend(inode); + for (bindex = au_ibstart(inode) + 1; bindex <= bend; bindex++) { + h_inode = au_h_iptr(inode, bindex); + if (h_inode) + au_add_nlink(inode, h_inode); + } + } +} + +void au_cpup_attr_changeable(struct inode *inode) +{ + struct inode *h_inode; + + LKTRTrace("i%lu\n", inode->i_ino); + /* todo? IMustLock(inode); */ + h_inode = au_h_iptr(inode, au_ibstart(inode)); + AuDebugOn(!h_inode); + + inode->i_mode = h_inode->i_mode; + inode->i_uid = h_inode->i_uid; + inode->i_gid = h_inode->i_gid; + au_cpup_attr_timesizes(inode); + + /* todo: remove this? */ + inode->i_flags = h_inode->i_flags; +} + +void au_cpup_igen(struct inode *inode, struct inode *h_inode) +{ + struct au_iinfo *iinfo = au_ii(inode); + iinfo->ii_higen = h_inode->i_generation; + iinfo->ii_hsb1 = h_inode->i_sb; +} + +void au_cpup_attr_all(struct inode *inode) +{ + struct inode *h_inode; + + LKTRTrace("i%lu\n", inode->i_ino); + /* todo? IMustLock(inode); */ + h_inode = au_h_iptr(inode, au_ibstart(inode)); + AuDebugOn(!h_inode); + + au_cpup_attr_changeable(inode); + if (inode->i_nlink > 0) + au_cpup_attr_nlink(inode); + + switch (inode->i_mode & S_IFMT) { + case S_IFBLK: + case S_IFCHR: + inode->i_rdev = au_h_rdev(h_inode, /*h_mnt*/NULL, + /*h_dentry*/NULL); + } + inode->i_blkbits = h_inode->i_blkbits; + au_cpup_igen(inode, h_inode); +} + +/* ---------------------------------------------------------------------- */ + +/* Note: dt_dentry and dt_hidden_dentry are not dget/dput-ed */ + +/* keep the timestamps of the parent dir when cpup */ +void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, + struct dentry *h_dentry, struct au_hinode *hinode, + struct au_hinode *hdir) +{ + struct inode *h_inode; + + LKTRTrace("%.*s, hdir %d\n", AuDLNPair(dentry), !!hdir); + AuDebugOn(!dentry || !h_dentry || !h_dentry->d_inode); + + dt->dt_dentry = dentry; + dt->dt_h_dentry = h_dentry; + dt->dt_hinode = hinode; + dt->dt_hdir = hdir; + h_inode = h_dentry->d_inode; + dt->dt_atime = h_inode->i_atime; + dt->dt_mtime = h_inode->i_mtime; + /* smp_mb(); */ +} + +void au_dtime_revert(struct au_dtime *dt) +{ + struct iattr attr; + int err; + struct au_hin_ignore ign[2]; + struct vfsub_args vargs; + + LKTRTrace("%.*s\n", AuDLNPair(dt->dt_dentry)); + + attr.ia_atime = dt->dt_atime; + attr.ia_mtime = dt->dt_mtime; + attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET + | ATTR_ATIME | ATTR_ATIME_SET; + + vfsub_args_init(&vargs, ign, + au_test_dlgt(au_mntflags(dt->dt_dentry->d_sb)), 0); + /* + * IN_ATTRIB should be divided into + * IN_ATTRIB_ATIME, IN_ATTRIB_MTIME ..., + * and define all ORed new IN_ATTRIB macro. + */ + vfsub_ign_hinode(&vargs, IN_ATTRIB, dt->dt_hinode); + vfsub_ign_hinode(&vargs, IN_ATTRIB, dt->dt_hdir); + err = vfsub_notify_change(dt->dt_h_dentry, &attr, &vargs); + if (unlikely(err)) + AuWarn("restoring timestamps failed(%d). ignored\n", err); +} + +/* ---------------------------------------------------------------------- */ + +static noinline_for_stack +int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src, + struct au_hinode *hdir, struct vfsub_args *vargs) +{ + int err, sbits; + struct dentry *h_dst; + struct iattr ia; + struct inode *h_isrc, *h_idst; + + h_dst = au_h_dptr(dst, bindex); + LKTRTrace("%.*s\n", AuDLNPair(h_dst)); + h_idst = h_dst->d_inode; + /* todo? IMustLock(h_idst); */ + h_isrc = h_src->d_inode; + /* todo? IMustLock(h_isrc); */ + + ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID + | ATTR_ATIME | ATTR_MTIME + | ATTR_ATIME_SET | ATTR_MTIME_SET; + ia.ia_mode = h_isrc->i_mode; + ia.ia_uid = h_isrc->i_uid; + ia.ia_gid = h_isrc->i_gid; + ia.ia_atime = h_isrc->i_atime; + ia.ia_mtime = h_isrc->i_mtime; + sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID)); + + vfsub_args_reinit(vargs); + vfsub_ign_hinode(vargs, IN_ATTRIB, hdir); + err = vfsub_notify_change(h_dst, &ia, vargs); + + /* is this nfs only? */ + if (!err && sbits && au_test_nfs(h_dst->d_sb)) { + ia.ia_valid = ATTR_FORCE | ATTR_MODE; + ia.ia_mode = h_isrc->i_mode; + vfsub_args_reinit(vargs); + vfsub_ign_hinode(vargs, IN_ATTRIB, hdir); + err = vfsub_notify_change(h_dst, &ia, vargs); + } + + /* todo? remove this? */ + if (!err) + h_idst->i_flags = h_isrc->i_flags; + + AuTraceErr(err); + return err; +} + +/* + * to support a sparse file which is opened with O_APPEND, + * we need to close the file. + */ +static noinline_for_stack +int cpup_regular(struct dentry *dentry, aufs_bindex_t bdst, aufs_bindex_t bsrc, + loff_t len, struct au_hinode *hdir, struct vfsub_args *vargs) +{ + int err, i; + struct super_block *sb; + struct inode *h_inode; + enum { SRC, DST }; + struct { + aufs_bindex_t bindex; + unsigned int flags; + struct dentry *dentry; + struct file *file; + void *label, *label_file; + } *h, hidden[] = { + { + .bindex = bsrc, + .flags = O_RDONLY | O_NOATIME | O_LARGEFILE, + .file = NULL, + .label = &&out, + .label_file = &&out_src_file + }, + { + .bindex = bdst, + .flags = O_WRONLY | O_NOATIME | O_LARGEFILE, + .file = NULL, + .label = &&out_src_file, + .label_file = &&out_dst_file + } + }; + + LKTRTrace("dentry %.*s, bdst %d, bsrc %d, len %lld\n", + AuDLNPair(dentry), bdst, bsrc, len); + AuDebugOn(bsrc <= bdst); + AuDebugOn(!len); + sb = dentry->d_sb; + AuDebugOn(au_test_ro(sb, bdst, dentry->d_inode)); + /* bsrc branch can be ro/rw. */ + + h = hidden; + for (i = 0; i < 2; i++, h++) { + h->dentry = au_h_dptr(dentry, h->bindex); + AuDebugOn(!h->dentry); + h_inode = h->dentry->d_inode; + AuDebugOn(!h_inode || !S_ISREG(h_inode->i_mode)); + h->file = au_h_open(dentry, h->bindex, h->flags, /*file*/NULL); + err = PTR_ERR(h->file); + if (IS_ERR(h->file)) + goto *h->label; + err = -EINVAL; + if (unlikely(!h->file->f_op)) + goto *h->label_file; + } + + /* stop updating while we copyup */ + IMustLock(hidden[SRC].dentry->d_inode); + err = au_copy_file(hidden[DST].file, hidden[SRC].file, len, hdir, sb, + vargs); + + out_dst_file: + fput(hidden[DST].file); + au_sbr_put(sb, hidden[DST].bindex); + out_src_file: + fput(hidden[SRC].file); + au_sbr_put(sb, hidden[SRC].bindex); + out: + AuTraceErr(err); + return err; +} + +static int au_do_cpup_regular(struct dentry *dentry, aufs_bindex_t bdst, + aufs_bindex_t bsrc, loff_t len, + struct au_hinode *hdir, struct dentry *h_dst, + struct vfsub_args *vargs) +{ + int err, rerr; + loff_t l; + + AuTraceEnter(); + + err = 0; + l = i_size_read(au_h_iptr(dentry->d_inode, bsrc)); + if (len == -1 || l < len) + len = l; + if (len) + err = cpup_regular(dentry, bdst, bsrc, len, hdir, vargs); + if (!err) + goto out; /* success */ + + vfsub_args_reinit(vargs); + vfsub_ign_hinode(vargs, IN_DELETE, hdir); + rerr = vfsub_unlink(hdir->hi_inode, h_dst, vargs); + if (rerr) { + AuIOErr("failed unlinking cpup-ed %.*s(%d, %d)\n", + AuDLNPair(h_dst), err, rerr); + err = -EIO; + } + + out: + AuTraceErr(err); + return err; +} + +static int au_do_cpup_symlink(struct dentry *h_dst, struct dentry *h_src, + struct inode *h_dir, umode_t mode, + struct vfsub_args *vargs) +{ + int err, symlen; + char *sym; + mm_segment_t old_fs; + + AuTraceEnter(); + + err = -ENOMEM; + sym = __getname(); + if (unlikely(!sym)) + goto out; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + symlen = h_src->d_inode->i_op->readlink(h_src, (char __user *)sym, + PATH_MAX); + err = symlen; + set_fs(old_fs); + + if (symlen > 0) { + sym[symlen] = 0; + err = vfsub_symlink(h_dir, h_dst, sym, mode, vargs); + } + __putname(sym); + + out: + AuTraceErr(err); + return err; +} + +/* return with hidden dst inode is locked */ +static noinline_for_stack +int cpup_entry(struct dentry *dentry, aufs_bindex_t bdst, aufs_bindex_t bsrc, + loff_t len, unsigned int flags, struct dentry *dst_parent, + struct vfsub_args *vargs) +{ + int err; + unsigned char isdir, hinotify; + struct dentry *h_src, *h_dst, *h_parent, *gparent; + struct inode *h_inode, *h_dir; + struct au_dtime dt; + umode_t mode; + struct super_block *sb; + struct au_hinode *hgdir, *hdir; + unsigned int mnt_flags; + const int do_dt = au_ftest_cpup(flags, DTIME); + + LKTRTrace("%.*s, i%lu, bdst %d, bsrc %d, len %lld, dtime %u\n", + AuDLNPair(dentry), dentry->d_inode->i_ino, bdst, bsrc, len, + do_dt); + sb = dentry->d_sb; + AuDebugOn(bdst >= bsrc || au_test_ro(sb, bdst, NULL)); + /* bsrc branch can be ro/rw. */ + + h_src = au_h_dptr(dentry, bsrc); + AuDebugOn(!h_src); + h_inode = h_src->d_inode; + AuDebugOn(!h_inode); + AuDebugOn(h_inode != au_h_iptr(dentry->d_inode, bsrc)); + + /* stop referencing while we are creating */ + h_dst = au_h_dptr(dentry, bdst); + AuDebugOn(h_dst && h_dst->d_inode); + h_parent = h_dst->d_parent; /* dir inode is locked */ + h_dir = h_parent->d_inode; + IMustLock(h_dir); + AuDebugOn(h_parent != h_dst->d_parent); + + hdir = NULL; + mnt_flags = au_mntflags(sb); + hinotify = !!au_opt_test(mnt_flags, UDBA_INOTIFY); + if (unlikely(hinotify)) { + hdir = au_hi(dst_parent->d_inode, bdst); + AuDebugOn(hdir->hi_inode != h_dir); + } + + if (do_dt) { + hgdir = NULL; + if (unlikely(hinotify && !IS_ROOT(dst_parent))) { + gparent = dget_parent(dst_parent); + hgdir = au_hi(gparent->d_inode, bdst); + IMustLock(hgdir->hi_inode); + dput(gparent); + } + au_dtime_store(&dt, dst_parent, h_parent, hdir, hgdir); + } + + isdir = 0; + vfsub_args_reinit(vargs); + vfsub_ign_hinode(vargs, IN_CREATE, hdir); + mode = h_inode->i_mode; + switch (mode & S_IFMT) { + case S_IFREG: + /* stop updating while we are referencing */ + IMustLock(h_inode); + err = au_h_create(h_dir, h_dst, mode | S_IWUSR, vargs, NULL, + au_nfsmnt(sb, bdst)); + if (!err) + err = au_do_cpup_regular(dentry, bdst, bsrc, len, + hdir, h_dst, vargs); + break; + case S_IFDIR: + isdir = 1; + err = vfsub_mkdir(h_dir, h_dst, mode, vargs); + if (!err) { + /* setattr case: dir is not locked */ + if (0 && au_ibstart(dst_parent->d_inode) == bdst) + au_cpup_attr_nlink(dst_parent->d_inode); + au_cpup_attr_nlink(dentry->d_inode); + } + break; + case S_IFLNK: + err = au_do_cpup_symlink(h_dst, h_src, h_dir, mode, vargs); + break; + case S_IFCHR: + case S_IFBLK: + AuDebugOn(!capable(CAP_MKNOD)); + /*FALLTHROUGH*/ + case S_IFIFO: + case S_IFSOCK: + err = vfsub_mknod(h_dir, h_dst, mode, + au_h_rdev(h_inode, /*h_mnt*/NULL, h_src), + vargs); + break; + default: + AuIOErr("Unknown inode type 0%o\n", mode); + err = -EIO; + } + + if (unlikely(hinotify + && !isdir + && au_opt_test_xino(mnt_flags) + && h_inode->i_nlink == 1 + //&& dentry->d_inode->i_nlink == 1 + && bdst < bsrc + && !au_ftest_cpup(flags, KEEPLINO))) + au_xino_write0(sb, bsrc, h_inode->i_ino, /*ino*/0); + /* ignore this error */ + + if (do_dt) + au_dtime_revert(&dt); + AuTraceErr(err); + return err; +} + +/* + * copyup the @dentry from @bsrc to @bdst. + * the caller must set the both of hidden dentries. + * @len is for truncating when it is -1 copyup the entire file. + */ +static int au_cpup_single(struct dentry *dentry, aufs_bindex_t bdst, + aufs_bindex_t bsrc, loff_t len, unsigned int flags, + struct dentry *dst_parent, struct vfsub_args *vargs) +{ + int err, rerr; + unsigned int mnt_flags; + aufs_bindex_t old_ibstart; + unsigned char isdir, plink, hinotify; + struct au_dtime dt; + struct dentry *h_src, *h_dst, *h_parent, *gparent; + struct inode *dst_inode, *h_dir, *inode; + struct super_block *sb; + struct au_hinode *hgdir, *hdir; + + LKTRTrace("%.*s, i%lu, bdst %d, bsrc %d, len %lld, flags 0x%x\n", + AuDLNPair(dentry), dentry->d_inode->i_ino, bdst, bsrc, len, + flags); + sb = dentry->d_sb; + AuDebugOn(bsrc <= bdst); + h_dst = au_h_dptr(dentry, bdst); + AuDebugOn(!h_dst || h_dst->d_inode); + h_parent = h_dst->d_parent; /* dir inode is locked */ + h_dir = h_parent->d_inode; + IMustLock(h_dir); + h_src = au_h_dptr(dentry, bsrc); + AuDebugOn(!h_src || !h_src->d_inode); + inode = dentry->d_inode; + IiMustWriteLock(inode); + if (!dst_parent) + dst_parent = dget_parent(dentry); + else + dget(dst_parent); + + mnt_flags = au_mntflags(sb); + plink = !!au_opt_test(mnt_flags, PLINK); + hinotify = !!au_opt_test(mnt_flags, UDBA_INOTIFY); + hdir = NULL; + if (unlikely(hinotify)) + hdir = au_hi(dst_parent->d_inode, bdst); + dst_inode = au_h_iptr(inode, bdst); + if (unlikely(dst_inode)) { + if (unlikely(!plink)) { + err = -EIO; + AuIOErr("i%lu exists on a upper branch " + "but plink is disabled\n", inode->i_ino); + goto out; + } + + if (dst_inode->i_nlink) { + const int do_dt = au_ftest_cpup(flags, DTIME); + + h_src = au_plink_lkup(sb, bdst, inode); + err = PTR_ERR(h_src); + if (IS_ERR(h_src)) + goto out; + AuDebugOn(!h_src->d_inode); + + if (do_dt) { + hgdir = NULL; + if (unlikely(hinotify && !IS_ROOT(dst_parent))) { + gparent = dget_parent(dst_parent); + hgdir = au_hi(gparent->d_inode, bdst); + IMustLock(hgdir->hi_inode); + dput(gparent); + } + au_dtime_store(&dt, dst_parent, h_parent, hdir, + hgdir); + } + vfsub_args_reinit(vargs); + vfsub_ign_hinode(vargs, IN_CREATE, hdir); + err = vfsub_link(h_src, h_dir, h_dst, vargs); + if (do_dt) + au_dtime_revert(&dt); + dput(h_src); + goto out; + } else + /* todo: cpup_wh_file? */ + /* udba work */ + au_update_brange(inode, 1); + } + + old_ibstart = au_ibstart(inode); + err = cpup_entry(dentry, bdst, bsrc, len, flags, dst_parent, vargs); + if (unlikely(err)) + goto out; + dst_inode = h_dst->d_inode; + mutex_lock_nested(&dst_inode->i_mutex, AuLsc_I_CHILD2); + + /* todo: test dlgt? */ + err = cpup_iattr(dentry, bdst, h_src, hdir, vargs); +#if 0 /* reserved for future use */ + if (0 && !err) + err = cpup_xattrs(h_src, h_dst); +#endif + isdir = S_ISDIR(dst_inode->i_mode); + if (!err) { + if (bdst < old_ibstart) + au_set_ibstart(inode, bdst); + au_set_h_iptr(inode, bdst, au_igrab(dst_inode), + au_hi_flags(inode, isdir)); + mutex_unlock(&dst_inode->i_mutex); + if (!isdir + && h_src->d_inode->i_nlink > 1 + && plink) + au_plink_append(sb, inode, h_dst, bdst); + goto out; /* success */ + } + + /* revert */ + mutex_unlock(&dst_inode->i_mutex); + hgdir = NULL; + if (unlikely(au_opt_test(mnt_flags, UDBA_INOTIFY) + && !IS_ROOT(dst_parent))) { + gparent = dget_parent(dst_parent); + hgdir = au_hi(gparent->d_inode, bdst); + dput(gparent); + } + au_dtime_store(&dt, dst_parent, h_parent, hdir, hgdir); + vfsub_args_reinit(vargs); + vfsub_ign_hinode(vargs, IN_DELETE, hdir); + if (!isdir) + rerr = vfsub_unlink(h_dir, h_dst, vargs); + else + rerr = vfsub_rmdir(h_dir, h_dst, vargs); + au_dtime_revert(&dt); + if (rerr) { + AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr); + err = -EIO; + } + + out: + dput(dst_parent); + AuTraceErr(err); + return err; +} + +struct au_cpup_single_args { + int *errp; + struct dentry *dentry; + aufs_bindex_t bdst, bsrc; + loff_t len; + unsigned int flags; + struct dentry *dst_parent; + struct vfsub_args *vargs; +}; + +static void au_call_cpup_single(void *args) +{ + struct au_cpup_single_args *a = args; + *a->errp = au_cpup_single(a->dentry, a->bdst, a->bsrc, a->len, + a->flags, a->dst_parent, a->vargs); +} + +int au_sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst, + aufs_bindex_t bsrc, loff_t len, unsigned int flags, + struct dentry *dst_parent) +{ + int err, wkq_err; + struct dentry *h_dentry; + umode_t mode; + struct au_hin_ignore ign; + struct vfsub_args vargs; + + LKTRTrace("%.*s, i%lu, bdst %d, bsrc %d, len %lld, flags 0x%x\n", + AuDLNPair(dentry), dentry->d_inode->i_ino, bdst, bsrc, len, + flags); + + vfsub_args_init(&vargs, &ign, au_test_dlgt(au_mntflags(dentry->d_sb)), + /*force_unlink*/0); + h_dentry = au_h_dptr(dentry, bsrc); + mode = h_dentry->d_inode->i_mode & S_IFMT; + if ((mode != S_IFCHR && mode != S_IFBLK) + || capable(CAP_MKNOD)) + err = au_cpup_single(dentry, bdst, bsrc, len, flags, + dst_parent, &vargs); + else { + struct au_cpup_single_args args = { + .errp = &err, + .dentry = dentry, + .bdst = bdst, + .bsrc = bsrc, + .len = len, + .flags = flags, + .dst_parent = dst_parent, + .vargs = &vargs + }; + vfsub_fclr(vargs.flags, DLGT); + wkq_err = au_wkq_wait(au_call_cpup_single, &args, /*dlgt*/0); + if (unlikely(wkq_err)) + err = wkq_err; + } + + AuTraceErr(err); + return err; +} + +/* + * copyup the @dentry from the first active hidden branch to @bdst, + * using au_cpup_single(). + */ +static int au_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, + unsigned int flags, struct vfsub_args *vargs) +{ + int err; + struct inode *inode; + aufs_bindex_t bsrc, bend; + + LKTRTrace("%.*s, bdst %d, len %lld, flags 0x%x\n", + AuDLNPair(dentry), bdst, len, flags); + inode = dentry->d_inode; + AuDebugOn(!S_ISDIR(inode->i_mode) && au_dbstart(dentry) < bdst); + + bend = au_dbend(dentry); + for (bsrc = bdst + 1; bsrc <= bend; bsrc++) + if (au_h_dptr(dentry, bsrc)) + break; + AuDebugOn(!au_h_dptr(dentry, bsrc)); + + err = au_lkup_neg(dentry, bdst); + if (!err) { + err = au_cpup_single(dentry, bdst, bsrc, len, flags, NULL, + vargs); + if (!err) + return 0; /* success */ + + /* revert */ + au_set_h_dptr(dentry, bdst, NULL); + au_set_dbstart(dentry, bsrc); + } + + AuTraceErr(err); + return err; +} + +struct au_cpup_simple_args { + int *errp; + struct dentry *dentry; + aufs_bindex_t bdst; + loff_t len; + unsigned int flags; + struct vfsub_args *vargs; +}; + +static void au_call_cpup_simple(void *args) +{ + struct au_cpup_simple_args *a = args; + *a->errp = au_cpup_simple(a->dentry, a->bdst, a->len, a->flags, + a->vargs); +} + +int au_sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, + unsigned int flags) +{ + int err, wkq_err; + unsigned char do_sio, dlgt; + struct dentry *parent; + struct inode *h_dir, *dir; + struct au_hin_ignore ign; + struct vfsub_args vargs; + + LKTRTrace("%.*s, b%d, len %lld, flags 0x%x\n", + AuDLNPair(dentry), bdst, len, flags); + + parent = dget_parent(dentry); + dir = parent->d_inode; + h_dir = au_h_iptr(dir, bdst); + dlgt = !!au_test_dlgt(au_mntflags(dir->i_sb)); + do_sio = !!au_test_h_perm_sio(h_dir, MAY_EXEC | MAY_WRITE, dlgt); + if (!do_sio) { + /* + * testing CAP_MKNOD is for generic fs, + * but CAP_FSETID is for xfs only, currently. + */ + umode_t mode = dentry->d_inode->i_mode; + do_sio = (((mode & (S_IFCHR | S_IFBLK)) + && !capable(CAP_MKNOD)) + || ((mode & (S_ISUID | S_ISGID)) + && !capable(CAP_FSETID))); + } + vfsub_args_init(&vargs, &ign, dlgt, /*force_unlink*/0); + if (!do_sio) + err = au_cpup_simple(dentry, bdst, len, flags, &vargs); + else { + struct au_cpup_simple_args args = { + .errp = &err, + .dentry = dentry, + .bdst = bdst, + .len = len, + .flags = flags, + .vargs = &vargs + }; + vfsub_fclr(vargs.flags, DLGT); + wkq_err = au_wkq_wait(au_call_cpup_simple, &args, /*dlgt*/0); + if (unlikely(wkq_err)) + err = wkq_err; + } + + dput(parent); + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_do_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, + struct dentry *wh_dentry, struct file *file, + loff_t len, struct vfsub_args *vargs) +{ + int err; + struct au_dinfo *dinfo; + aufs_bindex_t bstart; + struct dentry *h_d_bdst, *h_d_bstart; + + AuTraceEnter(); + + dinfo = au_di(dentry); + bstart = dinfo->di_bstart; + h_d_bdst = dinfo->di_hdentry[0 + bdst].hd_dentry; + dinfo->di_bstart = bdst; + dinfo->di_hdentry[0 + bdst].hd_dentry = wh_dentry; + h_d_bstart = dinfo->di_hdentry[0 + bstart].hd_dentry; + if (file) + dinfo->di_hdentry[0 + bstart].hd_dentry + = au_h_fptr(file, au_fbstart(file))->f_dentry; + err = au_cpup_single(dentry, bdst, bstart, len, !AuCpup_DTIME, + /*h_parent*/NULL, vargs); + if (!err && file) { + err = au_reopen_nondir(file); + dinfo->di_hdentry[0 + bstart].hd_dentry = h_d_bstart; + } + dinfo->di_hdentry[0 + bdst].hd_dentry = h_d_bdst; + dinfo->di_bstart = bstart; + + AuTraceErr(err); + return err; +} + +/* + * copyup the deleted file for writing. + */ +static int au_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, + struct file *file) +{ + int err; + unsigned char dlgt; + struct dentry *parent, *h_parent, *wh_dentry; + struct super_block *sb; + unsigned int mnt_flags; + struct au_dtime dt; + struct au_hin_ignore ign; + struct vfsub_args vargs; + struct au_hinode *hgdir, *hdir; + struct au_ndx ndx = { + .nd = NULL, + .flags = 0, + /* .br = NULL */ + }; + + LKTRTrace("%.*s, bdst %d, len %llu\n", AuDLNPair(dentry), bdst, len); + AuDebugOn(S_ISDIR(dentry->d_inode->i_mode) + || (file && !(file->f_mode & FMODE_WRITE))); + DiMustWriteLock(dentry); + + parent = dget_parent(dentry); + IiMustAnyLock(parent->d_inode); + h_parent = au_h_dptr(parent, bdst); + AuDebugOn(!h_parent); + + sb = parent->d_sb; + mnt_flags = au_mntflags(sb); + dlgt = 0; + ndx.nfsmnt = au_nfsmnt(sb, bdst); + if (unlikely(au_test_dlgt(mnt_flags))) { + dlgt = 1; + au_fset_ndx(ndx.flags, DLGT); + } + wh_dentry = au_whtmp_lkup(h_parent, &dentry->d_name, &ndx); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out; + + hdir = NULL; + hgdir = NULL; + if (unlikely(au_opt_test(mnt_flags, UDBA_INOTIFY))) { + hdir = au_hi(parent->d_inode, bdst); + if (!IS_ROOT(parent)) { + struct dentry *gparent; + gparent = dget_parent(parent); + hgdir = au_hi(gparent->d_inode, bdst); + dput(gparent); + } + } + au_dtime_store(&dt, parent, h_parent, hdir, hgdir); + vfsub_args_init(&vargs, &ign, dlgt, /*force_unlink*/0); + err = au_do_cpup_wh(dentry, bdst, wh_dentry, file, len, &vargs); + if (unlikely(err)) + goto out_wh; + + AuDebugOn(!d_unhashed(dentry)); + /* dget first to force sillyrename on nfs */ + dget(wh_dentry); + vfsub_args_reinit(&vargs); + vfsub_ign_hinode(&vargs, IN_DELETE, hdir); + err = vfsub_unlink(h_parent->d_inode, wh_dentry, &vargs); + if (unlikely(err)) { + AuIOErr("failed remove copied-up tmp file %.*s(%d)\n", + AuDLNPair(wh_dentry), err); + err = -EIO; + } + au_dtime_revert(&dt); + au_set_hi_wh(dentry->d_inode, bdst, wh_dentry); + + out_wh: + dput(wh_dentry); + out: + dput(parent); + AuTraceErr(err); + return err; +} + +struct au_cpup_wh_args { + int *errp; + struct dentry *dentry; + aufs_bindex_t bdst; + loff_t len; + struct file *file; +}; + +static void au_call_cpup_wh(void *args) +{ + struct au_cpup_wh_args *a = args; + *a->errp = au_cpup_wh(a->dentry, a->bdst, a->len, a->file); +} + +int au_sio_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, + struct file *file) +{ + int err, wkq_err; + struct dentry *parent, *h_tmp, *h_parent; + struct inode *dir, *h_dir, *h_tmpdir; + struct au_wbr *wbr; + + AuTraceEnter(); + parent = dget_parent(dentry); + dir = parent->d_inode; + IiMustAnyLock(dir); + + h_tmp = NULL; + h_parent = NULL; + h_dir = au_igrab(au_h_iptr(dir, bdst)); + h_tmpdir = h_dir; + if (unlikely(!h_dir->i_nlink)) { + DiMustWriteLock(parent); + wbr = au_sbr(dentry->d_sb, bdst)->br_wbr; + AuDebugOn(!wbr); + h_tmp = wbr->wbr_tmp; + + h_parent = dget(au_h_dptr(parent, bdst)); + au_set_h_dptr(parent, bdst, NULL); + au_set_h_dptr(parent, bdst, dget(h_tmp)); + h_tmpdir = h_tmp->d_inode; + au_set_h_iptr(dir, bdst, NULL, 0); + au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0); + mutex_lock_nested(&h_tmpdir->i_mutex, AuLsc_I_PARENT3); + } + + if (!au_test_h_perm_sio + (h_tmpdir, MAY_EXEC | MAY_WRITE, + au_test_dlgt(au_mntflags(dentry->d_sb)))) + err = au_cpup_wh(dentry, bdst, len, file); + else { + struct au_cpup_wh_args args = { + .errp = &err, + .dentry = dentry, + .bdst = bdst, + .len = len, + .file = file + }; + wkq_err = au_wkq_wait(au_call_cpup_wh, &args, /*dlgt*/0); + if (unlikely(wkq_err)) + err = wkq_err; + } + + /* todo: is this restore safe? */ + if (unlikely(h_tmp)) { + mutex_unlock(&h_tmpdir->i_mutex); + au_set_h_iptr(dir, bdst, NULL, 0); + au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0); + au_set_h_dptr(parent, bdst, NULL); + au_set_h_dptr(parent, bdst, h_parent); + } + iput(h_dir); + dput(parent); + + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * generic routine for both of copy-up and copy-down. + * Although I've tried building a path by dcsub, I gave up this approach. + * Since the ancestor directory may be moved/renamed during copy. + */ +/* cf. revalidate function in file.c */ +int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, + int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, + struct dentry *h_parent, void *arg), + void *arg) +{ + int err, hinotify; + struct super_block *sb; + struct dentry *d, *parent, *h_parent, *real_parent; + struct au_pin pin; + + LKTRTrace("%.*s, b%d, parent i%lu\n", + AuDLNPair(dentry), bdst, (unsigned long)parent_ino(dentry)); + sb = dentry->d_sb; + AuDebugOn(au_test_ro(sb, bdst, NULL)); + err = 0; + parent = dget_parent(dentry); + IiMustWriteLock(parent->d_inode); + if (unlikely(IS_ROOT(parent))) + goto out; + + /* do not use au_dpage */ + real_parent = parent; + hinotify = !!au_opt_test(au_mntflags(sb), UDBA_INOTIFY); + while (1) { + dput(parent); + parent = dget_parent(dentry); + h_parent = au_h_dptr(parent, bdst); + if (h_parent) + goto out; /* success */ + + /* find top dir which is needed to cpup */ + do { + d = parent; + dput(parent); + parent = dget_parent(d); + di_read_lock_parent3(parent, !AuLock_IR); + h_parent = au_h_dptr(parent, bdst); + di_read_unlock(parent, !AuLock_IR); + } while (!h_parent); + + if (d != real_parent) + di_write_lock_child3(d); + + /* somebody else might create while we were sleeping */ + if (!au_h_dptr(d, bdst) || !au_h_dptr(d, bdst)->d_inode) { + if (au_h_dptr(d, bdst)) + au_update_dbstart(d); + + au_pin_init(&pin, d, /*di_locked*/0, + AuLsc_DI_PARENT3, AuLsc_I_PARENT2, hinotify); + err = au_do_pin(pin.pin + AuPin_PARENT, au_pin_gp(&pin), + bdst, hinotify); + if (!err) { + err = cp(d, bdst, h_parent, arg); + au_unpin(&pin); + } + } + + if (d != real_parent) + di_write_unlock(d); + if (unlikely(err)) + break; + } + + out: + dput(parent); + AuTraceErr(err); + return err; +} + +static int au_cpup_dir(struct dentry *dentry, aufs_bindex_t bdst, + struct dentry *h_parent, void *arg) +{ + int err; + + err = au_sio_cpup_simple(dentry, bdst, -1, AuCpup_DTIME); + + AuTraceErr(err); + return err; +} + +int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) +{ + int err; + + err = au_cp_dirs(dentry, bdst, au_cpup_dir, NULL); + + AuTraceErr(err); + return err; +} + +int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) +{ + int err; + struct dentry *parent; + struct inode *dir; + + parent = dget_parent(dentry); + dir = parent->d_inode; + LKTRTrace("%.*s, b%d, parent i%lu\n", + AuDLNPair(dentry), bdst, dir->i_ino); + DiMustReadLock(parent); + IiMustReadLock(dir); + + err = 0; + if (au_h_iptr(dir, bdst)) + goto out; + + di_read_unlock(parent, AuLock_IR); + di_write_lock_parent(parent); + /* someone else might change our inode while we were sleeping */ + if (unlikely(!au_h_iptr(dir, bdst))) + err = au_cpup_dirs(dentry, bdst); + di_downgrade_lock(parent, AuLock_IR); + + out: + dput(parent); + AuTraceErr(err); + return err; +} --- linux-2.6.27.orig/ubuntu/aufs/dlgt.c +++ linux-2.6.27/ubuntu/aufs/dlgt.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * lookup functions in 'delegate' mode + * + * $Id: dlgt.c,v 1.5 2008/08/11 02:50:34 sfjro Exp $ + */ + +#include "aufs.h" + +/* ---------------------------------------------------------------------- */ + +struct au_lookup_one_len_args { + struct dentry **errp; + const char *name; + struct dentry *parent; + int len; +}; + +static void au_call_lookup_one_len(void *args) +{ + struct au_lookup_one_len_args *a = args; + *a->errp = vfsub_lookup_one_len(a->name, a->parent, a->len); +} + +struct dentry *au_lkup_one_dlgt(const char *name, struct dentry *parent, + int len, unsigned int flags) +{ + struct dentry *dentry; + int dirperm1; + + LKTRTrace("%.*s/%.*s, 0x%x\n", AuDLNPair(parent), len, name, flags); + + dirperm1 = au_ftest_ndx(flags, DIRPERM1); + if (!dirperm1 && !au_ftest_ndx(flags, DLGT)) + dentry = vfsub_lookup_one_len(name, parent, len); + else { + int wkq_err; + struct au_lookup_one_len_args args = { + .errp = &dentry, + .name = name, + .parent = parent, + .len = len + }; + wkq_err = au_wkq_wait(au_call_lookup_one_len, &args, + /*dlgt*/!dirperm1); + if (unlikely(wkq_err)) + dentry = ERR_PTR(wkq_err); + } + + AuTraceErrPtr(dentry); + return dentry; +} + +/* ---------------------------------------------------------------------- */ + +struct security_inode_permission_args { + int *errp; + struct inode *h_inode; + int mask; + struct nameidata *fake_nd; +}; + +static void call_security_inode_permission(void *args) +{ + struct security_inode_permission_args *a = args; + LKTRTrace("fsuid %d\n", current->fsuid); + *a->errp = vfsub_security_inode_permission(a->h_inode, a->mask, + a->fake_nd); +} + +int au_security_inode_permission(struct inode *h_inode, int mask, + struct nameidata *fake_nd, int dlgt) +{ + int err; + + AuTraceEnter(); + + if (!dlgt) + err = vfsub_security_inode_permission(h_inode, mask, fake_nd); + else { + int wkq_err; + struct security_inode_permission_args args = { + .errp = &err, + .h_inode = h_inode, + .mask = mask, + .fake_nd = fake_nd + }; + wkq_err = au_wkq_wait(call_security_inode_permission, &args, + /*dlgt*/1); + if (unlikely(wkq_err)) + err = wkq_err; + } + + AuTraceErr(err); + return err; +} --- linux-2.6.27.orig/ubuntu/aufs/br_xfs.c +++ linux-2.6.27/ubuntu/aufs/br_xfs.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * special handling inode attributes on XFS branch in linux-2.6.24 and later + * + * $Id: br_xfs.c,v 1.3 2008/07/07 01:12:38 sfjro Exp $ + */ + +#include "aufs.h" + +/* h_mnt can be NULL, is it safe? */ +dev_t au_h_rdev(struct inode *h_inode, struct vfsmount *h_mnt, + struct dentry *h_dentry) +{ + dev_t rdev; + int err; + struct kstat st; + + LKTRTrace("hi%lu\n", h_inode->i_ino); + if (h_dentry) + LKTRTrace("%.*s\n", AuDLNPair(h_dentry)); + + rdev = h_inode->i_rdev; + if (!rdev || !au_test_xfs(h_inode->i_sb)) + goto out; + + rdev = 0; + if (!h_dentry) { + err = 0; + h_dentry = d_find_alias(h_inode); + if (unlikely(!h_dentry)) + goto failure; + err = PTR_ERR(h_dentry); + if (IS_ERR(h_dentry)) { + h_dentry = NULL; + goto failure; + } + LKTRTrace("%.*s\n", AuDLNPair(h_dentry)); + } else + dget(h_dentry); + + err = vfsub_getattr(h_mnt, h_dentry, &st, /*dlgt*/0); + dput(h_dentry); + if (!err) { + rdev = st.rdev; + goto out; /* success */ + } + + failure: + AuIOErr("failed rdev for XFS inode, hi%lu, %d\n", h_inode->i_ino, err); + out: + return rdev; +} --- linux-2.6.27.orig/ubuntu/aufs/dinfo.c +++ linux-2.6.27/ubuntu/aufs/dinfo.c @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * dentry private data + * + * $Id: dinfo.c,v 1.7 2008/09/22 03:52:19 sfjro Exp $ + */ + +#include "aufs.h" + +int au_alloc_dinfo(struct dentry *dentry) +{ + struct au_dinfo *dinfo; + struct super_block *sb; + int nbr; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + AuDebugOn(dentry->d_fsdata); + + dinfo = au_cache_alloc_dinfo(); + if (dinfo) { + sb = dentry->d_sb; + nbr = au_sbend(sb) + 1; + if (unlikely(nbr <= 0)) + nbr = 1; + dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), + GFP_NOFS); + if (dinfo->di_hdentry) { + au_h_dentry_init_all(dinfo->di_hdentry, nbr); + atomic_set(&dinfo->di_generation, au_sigen(sb)); + /* smp_mb(); */ /* atomic_set */ + au_rw_init_wlock_nested(&dinfo->di_rwsem, + AuLsc_DI_CHILD); + dinfo->di_bstart = -1; + dinfo->di_bend = -1; + dinfo->di_bwh = -1; + dinfo->di_bdiropq = -1; + + dentry->d_fsdata = dinfo; + dentry->d_op = &aufs_dop; + return 0; /* success */ + } + au_cache_free_dinfo(dinfo); + } + AuTraceErr(-ENOMEM); + return -ENOMEM; +} + +struct au_dinfo *au_di(struct dentry *dentry) +{ + struct au_dinfo *dinfo = dentry->d_fsdata; + AuDebugOn(!dinfo + || !dinfo->di_hdentry + /* || au_sbi(dentry->d_sb)->si_bend < dinfo->di_bend */ + || dinfo->di_bend < dinfo->di_bstart + /* dbwh can be outside of this range */ + || (0 <= dinfo->di_bdiropq + && (dinfo->di_bdiropq < dinfo->di_bstart + /* || dinfo->di_bend < dinfo->di_bdiropq */)) + ); + return dinfo; +} + +/* ---------------------------------------------------------------------- */ + +static void do_ii_write_lock(struct inode *inode, unsigned int lsc) +{ + switch (lsc) { + case AuLsc_DI_CHILD: + ii_write_lock_child(inode); + break; + case AuLsc_DI_CHILD2: + ii_write_lock_child2(inode); + break; + case AuLsc_DI_CHILD3: + ii_write_lock_child3(inode); + break; + case AuLsc_DI_PARENT: + ii_write_lock_parent(inode); + break; + case AuLsc_DI_PARENT2: + ii_write_lock_parent2(inode); + break; + case AuLsc_DI_PARENT3: + ii_write_lock_parent3(inode); + break; + case AuLsc_DI_PARENT4: + ii_write_lock_parent4(inode); + break; + default: + BUG(); + } +} + +static void do_ii_read_lock(struct inode *inode, unsigned int lsc) +{ + switch (lsc) { + case AuLsc_DI_CHILD: + ii_read_lock_child(inode); + break; + case AuLsc_DI_CHILD2: + ii_read_lock_child2(inode); + break; + case AuLsc_DI_CHILD3: + ii_read_lock_child3(inode); + break; + case AuLsc_DI_PARENT: + ii_read_lock_parent(inode); + break; + case AuLsc_DI_PARENT2: + ii_read_lock_parent2(inode); + break; + case AuLsc_DI_PARENT3: + ii_read_lock_parent3(inode); + break; + case AuLsc_DI_PARENT4: + ii_read_lock_parent4(inode); + break; + default: + BUG(); + } +} + +void di_read_lock(struct dentry *d, int flags, unsigned int lsc) +{ + LKTRTrace("%.*s, %u\n", AuDLNPair(d), lsc); + SiMustAnyLock(d->d_sb); + + /* todo: always nested? */ + au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc); + if (d->d_inode) { + if (au_ftest_lock(flags, IW)) + do_ii_write_lock(d->d_inode, lsc); + else if (au_ftest_lock(flags, IR)) + do_ii_read_lock(d->d_inode, lsc); + } +} + +void di_read_unlock(struct dentry *d, int flags) +{ + LKTRTrace("%.*s\n", AuDLNPair(d)); + SiMustAnyLock(d->d_sb); + + if (d->d_inode) { + if (au_ftest_lock(flags, IW)) + ii_write_unlock(d->d_inode); + else if (au_ftest_lock(flags, IR)) + ii_read_unlock(d->d_inode); + } + au_rw_read_unlock(&au_di(d)->di_rwsem); +} + +void di_downgrade_lock(struct dentry *d, int flags) +{ + SiMustAnyLock(d->d_sb); + + au_rw_dgrade_lock(&au_di(d)->di_rwsem); + if (d->d_inode && au_ftest_lock(flags, IR)) + ii_downgrade_lock(d->d_inode); +} + +void di_write_lock(struct dentry *d, unsigned int lsc) +{ + LKTRTrace("%.*s, %u\n", AuDLNPair(d), lsc); + SiMustAnyLock(d->d_sb); + + /* todo: always nested? */ + au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc); + if (d->d_inode) + do_ii_write_lock(d->d_inode, lsc); +} + +void di_write_unlock(struct dentry *d) +{ + LKTRTrace("%.*s\n", AuDLNPair(d)); + SiMustAnyLock(d->d_sb); + + if (d->d_inode) + ii_write_unlock(d->d_inode); + au_rw_write_unlock(&au_di(d)->di_rwsem); +} + +void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir) +{ + AuTraceEnter(); + AuDebugOn(d1 == d2 + || d1->d_inode == d2->d_inode + || d1->d_sb != d2->d_sb); + + if (isdir && au_test_subdir(d1, d2)) { + di_write_lock_child(d1); + di_write_lock_child2(d2); + } else { + /* there should be no races */ + di_write_lock_child(d2); + di_write_lock_child2(d1); + } +} + +void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir) +{ + AuTraceEnter(); + AuDebugOn(d1 == d2 + || d1->d_inode == d2->d_inode + || d1->d_sb != d2->d_sb); + + if (isdir && au_test_subdir(d1, d2)) { + di_write_lock_parent(d1); + di_write_lock_parent2(d2); + } else { + /* there should be no races */ + di_write_lock_parent(d2); + di_write_lock_parent2(d1); + } +} + +void di_write_unlock2(struct dentry *d1, struct dentry *d2) +{ + di_write_unlock(d1); + if (d1->d_inode == d2->d_inode) + au_rw_write_unlock(&au_di(d2)->di_rwsem); + else + di_write_unlock(d2); +} + +/* ---------------------------------------------------------------------- */ + +struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex) +{ + struct dentry *d; + + DiMustAnyLock(dentry); + if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry)) + return NULL; + AuDebugOn(bindex < 0 + /* || bindex > au_sbend(dentry->d_sb) */); + d = au_di(dentry)->di_hdentry[0 + bindex].hd_dentry; + AuDebugOn(d && (atomic_read(&d->d_count) <= 0)); + return d; +} + +aufs_bindex_t au_dbtail(struct dentry *dentry) +{ + aufs_bindex_t bend, bwh; + + bend = au_dbend(dentry); + if (0 <= bend) { + bwh = au_dbwh(dentry); + if (!bwh) + return bwh; + if (0 < bwh && bwh < bend) + return bwh - 1; + } + return bend; +} + +aufs_bindex_t au_dbtaildir(struct dentry *dentry) +{ + aufs_bindex_t bend, bopq; + + AuDebugOn(dentry->d_inode + && dentry->d_inode->i_mode + && !S_ISDIR(dentry->d_inode->i_mode)); + + bend = au_dbtail(dentry); + if (0 <= bend) { + bopq = au_dbdiropq(dentry); + AuDebugOn(bend < bopq); + if (0 <= bopq && bopq < bend) + bend = bopq; + } + return bend; +} + +#if 0 /* reserved for future use */ +aufs_bindex_t au_dbtail_generic(struct dentry *dentry) +{ + struct inode *inode; + + inode = dentry->d_inode; + if (inode && S_ISDIR(inode->i_mode)) + return au_dbtaildir(dentry); + else + return au_dbtail(dentry); +} +#endif + +/* ---------------------------------------------------------------------- */ + +void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex) +{ + DiMustWriteLock(dentry); + AuDebugOn(au_sbend(dentry->d_sb) < bindex); + AuDebugOn((bindex >= 0 + && (bindex < au_dbstart(dentry) + || au_dbend(dentry) < bindex)) + || (dentry->d_inode + && dentry->d_inode->i_mode + && !S_ISDIR(dentry->d_inode->i_mode))); + au_di(dentry)->di_bdiropq = bindex; +} + +void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_dentry) +{ + struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex; + DiMustWriteLock(dentry); + AuDebugOn(bindex < au_di(dentry)->di_bstart + || bindex > au_di(dentry)->di_bend + || (h_dentry && atomic_read(&h_dentry->d_count) <= 0) + || (h_dentry && hd->hd_dentry) + ); + if (hd->hd_dentry) + au_hdput(hd, /*do_free*/0); + hd->hd_dentry = h_dentry; +} + +/* ---------------------------------------------------------------------- */ + +void au_update_dbrange(struct dentry *dentry, int do_put_zero) +{ + struct au_dinfo *dinfo; + aufs_bindex_t bindex; + struct dentry *h_d; + + LKTRTrace("%.*s, %d\n", AuDLNPair(dentry), do_put_zero); + DiMustWriteLock(dentry); + + dinfo = au_di(dentry); + if (unlikely(!dinfo) || dinfo->di_bstart < 0) + return; + + if (do_put_zero) { + for (bindex = dinfo->di_bstart; bindex <= dinfo->di_bend; + bindex++) { + h_d = dinfo->di_hdentry[0 + bindex].hd_dentry; + if (h_d && !h_d->d_inode) + au_set_h_dptr(dentry, bindex, NULL); + } + } + + dinfo->di_bstart = -1; + while (++dinfo->di_bstart <= dinfo->di_bend) + if (dinfo->di_hdentry[0 + dinfo->di_bstart].hd_dentry) + break; + if (dinfo->di_bstart > dinfo->di_bend) { + dinfo->di_bstart = -1; + dinfo->di_bend = -1; + return; + } + + dinfo->di_bend++; + while (0 <= --dinfo->di_bend) + if (dinfo->di_hdentry[0 + dinfo->di_bend].hd_dentry) + break; + AuDebugOn(dinfo->di_bstart > dinfo->di_bend || dinfo->di_bend < 0); +} + +void au_update_dbstart(struct dentry *dentry) +{ + aufs_bindex_t bindex, + bstart = au_dbstart(dentry), + bend = au_dbend(dentry); + struct dentry *h_dentry; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + DiMustWriteLock(dentry); + + for (bindex = bstart; bindex <= bend; bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + if (h_dentry->d_inode) { + au_set_dbstart(dentry, bindex); + return; + } + au_set_h_dptr(dentry, bindex, NULL); + } +} + +void au_update_dbend(struct dentry *dentry) +{ + aufs_bindex_t bindex, + bstart = au_dbstart(dentry), + bend = au_dbend(dentry); + struct dentry *h_dentry; + + DiMustWriteLock(dentry); + for (bindex = bend; bindex <= bstart; bindex--) { + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + if (h_dentry->d_inode) { + au_set_dbend(dentry, bindex); + return; + } + au_set_h_dptr(dentry, bindex, NULL); + } +} + +int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry) +{ + aufs_bindex_t bindex, bend; + + bend = au_dbend(dentry); + for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) + if (au_h_dptr(dentry, bindex) == h_dentry) + return bindex; + return -1; +} --- linux-2.6.27.orig/ubuntu/aufs/dcsub.c +++ linux-2.6.27/ubuntu/aufs/dcsub.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * sub-routines for dentry cache + * + * $Id: dcsub.c,v 1.7 2008/07/21 02:54:22 sfjro Exp $ + */ + +#include "aufs.h" + +static void au_dpage_free(struct au_dpage *dpage) +{ + int i; + + AuTraceEnter(); + AuDebugOn(!dpage); + + for (i = 0; i < dpage->ndentry; i++) + dput(dpage->dentries[i]); + free_page((unsigned long)dpage->dentries); +} + +int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp) +{ + int err; + void *p; + + AuTraceEnter(); + + err = -ENOMEM; + dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp); + if (unlikely(!dpages->dpages)) + goto out; + p = (void *)__get_free_page(gfp); + if (unlikely(!p)) + goto out_dpages; + dpages->dpages[0].ndentry = 0; + dpages->dpages[0].dentries = p; + dpages->ndpage = 1; + return 0; /* success */ + + out_dpages: + kfree(dpages->dpages); + out: + AuTraceErr(err); + return err; +} + +void au_dpages_free(struct au_dcsub_pages *dpages) +{ + int i; + + AuTraceEnter(); + + for (i = 0; i < dpages->ndpage; i++) + au_dpage_free(dpages->dpages + i); + kfree(dpages->dpages); +} + +static int au_dpages_append(struct au_dcsub_pages *dpages, + struct dentry *dentry, gfp_t gfp) +{ + int err, sz; + struct au_dpage *dpage; + void *p; + + /* AuTraceEnter(); */ + + dpage = dpages->dpages + dpages->ndpage - 1; + AuDebugOn(!dpage); + sz = PAGE_SIZE / sizeof(dentry); + if (unlikely(dpage->ndentry >= sz)) { + LKTRLabel(new dpage); + err = -ENOMEM; + sz = dpages->ndpage * sizeof(*dpages->dpages); + p = au_kzrealloc(dpages->dpages, sz, + sz + sizeof(*dpages->dpages), gfp); + if (unlikely(!p)) + goto out; + dpages->dpages = p; + dpage = dpages->dpages + dpages->ndpage; + p = (void *)__get_free_page(gfp); + if (unlikely(!p)) + goto out; + dpage->ndentry = 0; + dpage->dentries = p; + dpages->ndpage++; + } + + dpage->dentries[dpage->ndentry++] = dget(dentry); + return 0; /* success */ + + out: + /* AuTraceErr(err); */ + return err; +} + +int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, + au_dpages_test test, void *arg) +{ + int err; + struct dentry *this_parent = root; + struct list_head *next; + struct super_block *sb = root->d_sb; + + AuTraceEnter(); + + err = 0; + spin_lock(&dcache_lock); + repeat: + next = this_parent->d_subdirs.next; + resume: + if (this_parent->d_sb == sb + && !IS_ROOT(this_parent) + && atomic_read(&this_parent->d_count) + && this_parent->d_inode + && (!test || test(this_parent, arg))) { + err = au_dpages_append(dpages, this_parent, GFP_ATOMIC); + if (unlikely(err)) + goto out; + } + + while (next != &this_parent->d_subdirs) { + struct list_head *tmp = next; + struct dentry *dentry = list_entry(tmp, struct dentry, + d_u.d_child); + next = tmp->next; + if (unlikely(/*d_unhashed(dentry) || */!dentry->d_inode)) + continue; + if (!list_empty(&dentry->d_subdirs)) { + this_parent = dentry; + goto repeat; + } + if (dentry->d_sb == sb + && atomic_read(&dentry->d_count) + && (!test || test(dentry, arg))) { + err = au_dpages_append(dpages, dentry, GFP_ATOMIC); + if (unlikely(err)) + goto out; + } + } + + if (this_parent != root) { + next = this_parent->d_u.d_child.next; + this_parent = this_parent->d_parent; /* dcache_lock is locked */ + goto resume; + } + out: + spin_unlock(&dcache_lock); +#if 0 /* debug */ + if (!err) { + int i, j; + j = 0; + for (i = 0; i < dpages->ndpage; i++) { + if ((dpages->dpages + i)->ndentry) + AuDbg("%d: %d\n", + i, (dpages->dpages + i)->ndentry); + j += (dpages->dpages + i)->ndentry; + } + if (j) + AuDbg("ndpage %d, %d\n", dpages->ndpage, j); + } +#endif + AuTraceErr(err); + return err; +} + +int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, + int do_include, au_dpages_test test, void *arg) +{ + int err; + + AuTraceEnter(); + + err = 0; + spin_lock(&dcache_lock); + if (do_include && (!test || test(dentry, arg))) { + err = au_dpages_append(dpages, dentry, GFP_ATOMIC); + if (unlikely(err)) + goto out; + } + while (!IS_ROOT(dentry)) { + dentry = dentry->d_parent; /* dcache_lock is locked */ + if (!test || test(dentry, arg)) { + err = au_dpages_append(dpages, dentry, GFP_ATOMIC); + if (unlikely(err)) + break; + } + } + + out: + spin_unlock(&dcache_lock); + + AuTraceErr(err); + return err; +} + +struct dentry *au_test_subdir(struct dentry *d1, struct dentry *d2) +{ + struct dentry *trap, **dentries; + int err, i, j; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + + LKTRTrace("%.*s, %.*s\n", AuDLNPair(d1), AuDLNPair(d2)); + + trap = ERR_PTR(-ENOMEM); + err = au_dpages_init(&dpages, GFP_NOFS); + if (unlikely(err)) + goto out; + err = au_dcsub_pages_rev(&dpages, d1, /*do_include*/1, NULL, NULL); + if (unlikely(err)) + goto out_dpages; + + trap = d1; + for (i = 0; !err && i < dpages.ndpage; i++) { + dpage = dpages.dpages + i; + dentries = dpage->dentries; + for (j = 0; !err && j < dpage->ndentry; j++) { + struct dentry *d; + d = dentries[j]; + err = (d == d2); + if (!err) + trap = d; + } + } + if (!err) + trap = NULL; + + out_dpages: + au_dpages_free(&dpages); + out: + AuTraceErrPtr(trap); + return trap; +} --- linux-2.6.27.orig/ubuntu/aufs/branch.c +++ linux-2.6.27/ubuntu/aufs/branch.c @@ -0,0 +1,1025 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * branch management + * + * $Id: branch.c,v 1.16 2008/09/08 02:39:41 sfjro Exp $ + */ + +#include +#include +#include +#include +#include "aufs.h" + +static void au_br_do_free(struct au_branch *br) +{ + int i; + struct au_wbr *wbr; + + AuTraceEnter(); + + if (br->br_xino.xi_file) + fput(br->br_xino.xi_file); + wbr = br->br_wbr; + if (wbr) + for (i = 0; i < AuBrWh_Last; i++) + dput(wbr->wbr_wh[i]); + /* do not call au_br_nfs_lockdep_off() here */ + if (!au_test_nfs(br->br_mnt->mnt_sb)) + mntput(br->br_mnt); + else { + lockdep_off(); + mntput(br->br_mnt); + lockdep_on(); + } + AuDebugOn(au_br_count(br)); + if (wbr) + AuDebugOn(atomic_read(&wbr->wbr_wh_running)); + kfree(wbr); + kfree(br); +} + +/* + * frees all branches + */ +void au_br_free(struct au_sbinfo *sbinfo) +{ + aufs_bindex_t bmax; + struct au_branch **br; + + AuTraceEnter(); + bmax = sbinfo->si_bend + 1; + br = sbinfo->si_branch; + while (bmax--) + au_br_do_free(*br++); +} + +/* + * find the index of a branch which is specified by @br_id. + */ +int au_br_index(struct super_block *sb, aufs_bindex_t br_id) +{ + aufs_bindex_t bindex, bend; + + AuTraceEnter(); + + bend = au_sbend(sb); + for (bindex = 0; bindex <= bend; bindex++) + if (au_sbr_id(sb, bindex) == br_id) + return bindex; + return -1; +} + +/* + * test if the @h_sb is real-readonly. + */ +int au_test_def_rr(struct super_block *h_sb) +{ + switch (h_sb->s_magic) { +#ifdef CONFIG_AUFS_RR_SQUASHFS + case SQUASHFS_MAGIC_LZMA: + case SQUASHFS_MAGIC: + case SQUASHFS_MAGIC_LZMA_SWAP: + case SQUASHFS_MAGIC_SWAP: + return 1; /* real readonly */ +#endif + +#if defined(CONFIG_ISO9660_FS) || defined(CONFIG_ISO9660_FS_MODULE) + case ISOFS_SUPER_MAGIC: + return 1; +#endif + +#if defined(CONFIG_CRAMFS) || defined(CONFIG_CRAMFS_MODULE) + case CRAMFS_MAGIC: + return 1; +#endif + +#if defined(CONFIG_ROMFS_FS) || defined(CONFIG_ROMFS_FS_MODULE) + case ROMFS_MAGIC: + return 1; +#endif + + default: + return 0; + } +} + +/* ---------------------------------------------------------------------- */ + +/* + * test if two hidden_dentries have overlapping branches. + */ +static int do_test_overlap(struct super_block *sb, struct dentry *h_d1, + struct dentry *h_d2) +{ + struct dentry *d; + + LKTRTrace("%.*s, %.*s\n", AuDLNPair(h_d1), AuDLNPair(h_d2)); + + d = au_test_subdir(h_d1, h_d2); + if (unlikely(d)) { + AuDbgDentry(h_d1); + AuDbgDentry(h_d2); + } + return !!d; +} + +static int test_overlap_loopback(struct super_block *sb, struct dentry *h_d1, + struct dentry *h_d2) +{ +#if defined(CONFIG_BLK_DEV_LOOP) || defined(CONFIG_BLK_DEV_LOOP_MODULE) + struct inode *h_inode; + struct loop_device *l; + + LKTRTrace("%.*s, %.*s\n", AuDLNPair(h_d1), AuDLNPair(h_d2)); + AuDbgDentry(h_d1); + AuDbgDentry(h_d2); + AuDbgSb(h_d1->d_sb); + AuDbgSb(h_d2->d_sb); + + h_inode = h_d1->d_inode; + if (MAJOR(h_inode->i_sb->s_dev) != LOOP_MAJOR) + return 0; + + l = h_inode->i_sb->s_bdev->bd_disk->private_data; + h_d1 = l->lo_backing_file->f_dentry; + /* h_d1 can be local NFS. in this case aufs cannot detect the loop */ + AuDbgDentry(h_d1); + AuDbgDentry(h_d2); + AuDbgSb(h_d1->d_sb); + AuDbgSb(h_d2->d_sb); + if (unlikely(h_d1->d_sb == sb)) + return 1; + return do_test_overlap(sb, h_d1, h_d2); +#else + return 0; +#endif +} + +static int test_overlap(struct super_block *sb, struct dentry *h_d1, + struct dentry *h_d2) +{ + LKTRTrace("d1 %.*s, d2 %.*s\n", AuDLNPair(h_d1), AuDLNPair(h_d2)); + + if (unlikely(h_d1 == h_d2)) { + AuDbgDentry(h_d1); + AuDbgDentry(h_d2); + return 1; + } + return do_test_overlap(sb, h_d1, h_d2) + || do_test_overlap(sb, h_d2, h_d1) + || test_overlap_loopback(sb, h_d1, h_d2) + || test_overlap_loopback(sb, h_d2, h_d1); +} + +/* ---------------------------------------------------------------------- */ + +static int au_br_init_wh(struct super_block *sb, aufs_bindex_t bindex, + struct au_branch *br, int new_perm, + struct dentry *h_root, struct vfsmount *h_mnt) +{ + int err, old_perm; + struct inode *h_dir; + struct au_wbr *wbr; + + LKTRTrace("b%d, new_perm %d\n", bindex, new_perm); + + wbr = br->br_wbr; + h_dir = h_root->d_inode; + old_perm = br->br_perm; + mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); + if (wbr) + wbr_wh_write_lock(wbr); + br->br_perm = new_perm; + err = au_wh_init(h_root, br, au_do_nfsmnt(h_mnt), sb, bindex); + br->br_perm = old_perm; + if (wbr) + wbr_wh_write_unlock(wbr); + mutex_unlock(&h_dir->i_mutex); + if (!err && wbr && !au_br_writable(new_perm)) { + AuDebugOn(wbr->wbr_whbase); + AuDebugOn(wbr->wbr_plink); + AuDebugOn(wbr->wbr_tmp); + kfree(wbr); + br->br_wbr = NULL; + } + + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +/* + * returns a newly allocated branch. @new_nbranch is a number of branches + * after adding a branch. + */ +static struct au_branch *alloc_addbr(struct super_block *sb, int new_nbranch, + int perm) +{ + struct au_branch **branchp, *add_branch; + int sz; + void *p; + struct dentry *root; + struct inode *inode; + struct au_hinode *hinodep; + struct au_hdentry *hdentryp; + + LKTRTrace("new_nbranch %d\n", new_nbranch); + SiMustWriteLock(sb); + root = sb->s_root; + DiMustWriteLock(root); + inode = root->d_inode; + IiMustWriteLock(inode); + + add_branch = kmalloc(sizeof(*add_branch), GFP_NOFS); + if (unlikely(!add_branch)) + goto out; + add_branch->br_wbr = NULL; + if (unlikely(au_br_writable(perm))) { + add_branch->br_wbr = kmalloc(sizeof(*add_branch->br_wbr), + GFP_NOFS); + if (unlikely(!add_branch->br_wbr)) + goto out_br; + } + + sz = sizeof(*branchp) * (new_nbranch - 1); + if (unlikely(!sz)) + sz = sizeof(*branchp); + p = au_sbi(sb)->si_branch; + branchp = au_kzrealloc(p, sz, sizeof(*branchp) * new_nbranch, GFP_NOFS); + if (unlikely(!branchp)) + goto out_wbr; + au_sbi(sb)->si_branch = branchp; + + sz = sizeof(*hdentryp) * (new_nbranch - 1); + if (unlikely(!sz)) + sz = sizeof(*hdentryp); + p = au_di(root)->di_hdentry; + hdentryp = au_kzrealloc(p, sz, sizeof(*hdentryp) * new_nbranch, + GFP_NOFS); + if (unlikely(!hdentryp)) + goto out_wbr; + au_di(root)->di_hdentry = hdentryp; + + sz = sizeof(*hinodep) * (new_nbranch - 1); + if (unlikely(!sz)) + sz = sizeof(*hinodep); + p = au_ii(inode)->ii_hinode; + hinodep = au_kzrealloc(p, sz, sizeof(*hinodep) * new_nbranch, GFP_NOFS); + if (unlikely(!hinodep)) + goto out_wbr; + au_ii(inode)->ii_hinode = hinodep; + return add_branch; /* success */ + + out_wbr: + kfree(add_branch->br_wbr); + out_br: + kfree(add_branch); + out: + AuTraceErr(-ENOMEM); + return ERR_PTR(-ENOMEM); +} + +/* + * test if the branch permission is legal or not. + */ +static int test_br(struct super_block *sb, struct inode *inode, int brperm, + char *path) +{ + int err; + + err = 0; + if (unlikely(au_br_writable(brperm) && IS_RDONLY(inode))) { + AuErr("write permission for readonly fs or inode, %s\n", path); + err = -EINVAL; + } + + AuTraceErr(err); + return err; +} + +static int au_unsupported_fs(struct super_block *sb) +{ + return (sb->s_magic == PROC_SUPER_MAGIC +#ifdef SYSFS_MAGIC + || sb->s_magic == SYSFS_MAGIC +#endif + || !strcmp(au_sbtype(sb), "unionfs")); +} + +/* + * returns: + * 0: success, the caller will add it + * plus: success, it is already unified, the caller should ignore it + * minus: error + */ +static int test_add(struct super_block *sb, struct au_opt_add *add, int remount) +{ + int err; + struct dentry *root; + struct inode *inode, *h_inode; + aufs_bindex_t bend, bindex; + + LKTRTrace("%s, remo%d\n", add->path, remount); + + root = sb->s_root; + bend = au_sbend(sb); + if (unlikely(bend >= 0 + && au_find_dbindex(root, add->nd.path.dentry) >= 0)) { + err = 1; + if (!remount) { + err = -EINVAL; + AuErr("%s duplicated\n", add->path); + } + goto out; + } + + err = -ENOSPC; /* -E2BIG; */ + if (unlikely(AUFS_BRANCH_MAX <= add->bindex + || AUFS_BRANCH_MAX - 1 <= bend)) { + AuErr("number of branches exceeded %s\n", add->path); + goto out; + } + + err = -EDOM; + if (unlikely(add->bindex < 0 || bend + 1 < add->bindex)) { + AuErr("bad index %d\n", add->bindex); + goto out; + } + + inode = add->nd.path.dentry->d_inode; + AuDebugOn(!inode || !S_ISDIR(inode->i_mode)); + err = -ENOENT; + if (unlikely(!inode->i_nlink)) { + AuErr("no existence %s\n", add->path); + goto out; + } + + err = -EINVAL; + if (unlikely(inode->i_sb == sb)) { + AuErr("%s must be outside\n", add->path); + goto out; + } + + if (unlikely(au_test_nested(inode->i_sb))) { + AuErr("nested " AUFS_NAME " %s\n", add->path); + goto out; + } + + if (unlikely(au_unsupported_fs(inode->i_sb))) { + AuErr("unsupported filesystem, %s\n", add->path); + goto out; + } + + if (unlikely(au_test_unsupported_nfs(inode->i_sb))) { + AuErr(AuNoNfsBranchMsg " %s\n", add->path); + goto out; + } + + err = test_br(sb, add->nd.path.dentry->d_inode, add->perm, add->path); + if (unlikely(err)) + goto out; + + if (bend < 0) + return 0; /* success */ + + err = -EINVAL; + for (bindex = 0; bindex <= bend; bindex++) + if (unlikely(test_overlap(sb, add->nd.path.dentry, + au_h_dptr(root, bindex)))) { + AuErr("%s is overlapped\n", add->path); + goto out; + } + + err = 0; + h_inode = au_h_dptr(root, 0)->d_inode; + if (unlikely(au_opt_test(au_mntflags(sb), WARN_PERM) + && ((h_inode->i_mode & S_IALLUGO) + != (inode->i_mode & S_IALLUGO) + || h_inode->i_uid != inode->i_uid + || h_inode->i_gid != inode->i_gid))) + AuWarn("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n", + add->path, + inode->i_uid, inode->i_gid, (inode->i_mode & S_IALLUGO), + h_inode->i_uid, h_inode->i_gid, + (h_inode->i_mode & S_IALLUGO)); + + out: + AuTraceErr(err); + return err; +} + +static int au_wbr_init(struct au_branch *br, struct super_block *sb, + int perm, struct path *path) +{ + int err; + struct au_wbr *wbr; + + AuTraceEnter(); + wbr = br->br_wbr; + AuDebugOn(!wbr); + + au_rw_init_nolock(&wbr->wbr_wh_rwsem); + memset(wbr->wbr_wh, 0, sizeof(wbr->wbr_wh)); + atomic_set(&wbr->wbr_wh_running, 0); + wbr->wbr_bytes = 0; + + err = au_br_init_wh(sb, /*bindex*/-1, br, perm, + path->dentry, path->mnt); + + AuTraceErr(err); + return err; +} + +static int au_br_init(struct au_branch *br, struct super_block *sb, + struct au_opt_add *add) +{ + int err; + unsigned int mnt_flags; + + AuTraceEnter(); + + err = 0; + if (unlikely(au_br_writable(add->perm))) { + err = au_wbr_init(br, sb, add->perm, &add->nd.path); + if (unlikely(err)) + goto out; + } + + br->br_xino.xi_file = NULL; + mutex_init(&br->br_xino.xi_nondir_mtx); + br->br_mnt = mntget(add->nd.path.mnt); + mnt_flags = au_mntflags(sb); + if (au_opt_test(mnt_flags, XINO)) { + err = au_xino_br(sb, br, add->nd.path.dentry->d_inode->i_ino, + au_sbr(sb, 0)->br_xino.xi_file, /*do_test*/1); + if (unlikely(err)) { + AuDebugOn(br->br_xino.xi_file); + goto out; + } +#if 0 /* reserved for future use */ + } else if (au_opt_test(mnt_flags, XINODIR)) { + err = au_xinodir_br(sb, br, add->nd.path.dentry->d_inode->i_ino, + /*do_test*/1); + if (unlikely(err)) { + AuDebugOn(br->br_xino.xi_file); + goto out; + } +#endif + } + + br->br_id = au_new_br_id(sb); + br->br_perm = add->perm; + atomic_set(&br->br_count, 0); + br->br_xino_upper = AUFS_XINO_TRUNC_INIT; + atomic_set(&br->br_xino_running, 0); + sysaufs_br_init(br); + br->br_generation = au_sigen(sb); + /* smp_mb(); */ /* atomic_set */ + + out: + AuTraceErr(err); + return err; +} + +int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount) +{ + int err, amount; + aufs_bindex_t bend, add_bindex; + struct dentry *root, *dentry; + struct au_iinfo *iinfo; + struct au_sbinfo *sbinfo; + struct au_dinfo *dinfo; + struct inode *root_inode; + unsigned long long maxb; + struct au_branch **branchp, *add_branch; + struct au_hdentry *hdentryp; + struct au_hinode *hinodep; + + dentry = add->nd.path.dentry; + LKTRTrace("b%d, %s, 0x%x, %.*s\n", + add->bindex, add->path, add->perm, AuDLNPair(dentry)); + SiMustWriteLock(sb); + root = sb->s_root; + DiMustWriteLock(root); + root_inode = root->d_inode; + IMustLock(root_inode); + IiMustWriteLock(root_inode); + + err = test_add(sb, add, remount); + if (unlikely(err < 0)) + goto out; + if (err) + return 0; /* success */ + + bend = au_sbend(sb); + add_branch = alloc_addbr(sb, bend + 2, add->perm); + err = PTR_ERR(add_branch); + if (IS_ERR(add_branch)) + goto out; + err = au_br_init(add_branch, sb, add); + if (unlikely(err)) { + au_br_do_free(add_branch); + goto out; + } + + add_bindex = add->bindex; + if (remount) + sysaufs_brs_del(sb, add_bindex); + + sbinfo = au_sbi(sb); + dinfo = au_di(root); + iinfo = au_ii(root_inode); + + amount = bend + 1 - add_bindex; + branchp = sbinfo->si_branch + add_bindex; + memmove(branchp + 1, branchp, sizeof(*branchp) * amount); + *branchp = add_branch; + hdentryp = dinfo->di_hdentry + add_bindex; + memmove(hdentryp + 1, hdentryp, sizeof(*hdentryp) * amount); + au_h_dentry_init(hdentryp); + hinodep = iinfo->ii_hinode + add_bindex; + memmove(hinodep + 1, hinodep, sizeof(*hinodep) * amount); + hinodep->hi_inode = NULL; + au_hin_init(hinodep, NULL); + + sbinfo->si_bend++; + dinfo->di_bend++; + iinfo->ii_bend++; + if (unlikely(bend < 0)) { + sbinfo->si_bend = 0; + dinfo->di_bstart = 0; + iinfo->ii_bstart = 0; + } + au_set_h_dptr(root, add_bindex, dget(dentry)); + au_set_h_iptr(root_inode, add_bindex, au_igrab(dentry->d_inode), 0); + if (remount) + sysaufs_brs_add(sb, add_bindex); + + if (!add_bindex) + au_cpup_attr_all(root_inode); + else + au_add_nlink(root_inode, dentry->d_inode); + maxb = dentry->d_sb->s_maxbytes; + if (sb->s_maxbytes < maxb) + sb->s_maxbytes = maxb; + + /* safe d_parent reference */ + if (!au_xino_def_br(sbinfo) + && add_branch->br_xino.xi_file + && add_branch->br_xino.xi_file->f_dentry->d_parent == dentry) + au_xino_def_br_set(add_branch, sbinfo); + + out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +#define AuVerbose(do_info, fmt, args...) do { \ + if (!do_info) \ + LKTRTrace(fmt, ##args); \ + else \ + AuInfo(fmt, ##args); \ +} while (0) + +/* + * test if the branch is deletable or not. + */ +static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex, + au_gen_t sigen) +{ + int err, i, j, ndentry; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + struct dentry *d; + aufs_bindex_t bstart, bend; + unsigned char verbose; + struct inode *inode; + + LKTRTrace("b%d, gen%d\n", bindex, sigen); + SiMustWriteLock(root->d_sb); + + err = au_dpages_init(&dpages, GFP_NOFS); + if (unlikely(err)) + goto out; + err = au_dcsub_pages(&dpages, root, NULL, NULL); + if (unlikely(err)) + goto out_dpages; + + verbose = !!au_opt_test(au_mntflags(root->d_sb), VERBOSE); + for (i = 0; !err && i < dpages.ndpage; i++) { + dpage = dpages.dpages + i; + ndentry = dpage->ndentry; + for (j = 0; !err && j < ndentry; j++) { + d = dpage->dentries[j]; + AuDebugOn(!atomic_read(&d->d_count)); + inode = d->d_inode; + AuDebugOn(!inode); + if (au_digen(d) == sigen + && au_iigen(inode) == sigen) + di_read_lock_child(d, AuLock_IR); + else { + di_write_lock_child(d); + err = au_reval_dpath(d, sigen); + if (!err) + di_downgrade_lock(d, AuLock_IR); + else { + di_write_unlock(d); + break; + } + } + + bstart = au_dbstart(d); + bend = au_dbend(d); + if (bstart <= bindex + && bindex <= bend + && au_h_dptr(d, bindex) + && (!S_ISDIR(d->d_inode->i_mode) + || bstart == bend)) { + err = -EBUSY; + AuVerbose(verbose, "busy %.*s\n", AuDLNPair(d)); + } + di_read_unlock(d, AuLock_IR); + } + } + + out_dpages: + au_dpages_free(&dpages); + out: + AuTraceErr(err); + return err; +} + +static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex, + au_gen_t sigen) +{ + int err; + struct inode *i; + aufs_bindex_t bstart, bend; + unsigned char verbose; + + LKTRTrace("b%d, gen%d\n", bindex, sigen); + SiMustWriteLock(sb); + + err = 0; + verbose = !!au_opt_test(au_mntflags(sb), VERBOSE); + list_for_each_entry(i, &sb->s_inodes, i_sb_list) { + AuDebugOn(!atomic_read(&i->i_count)); + if (!list_empty(&i->i_dentry)) + continue; + + if (au_iigen(i) == sigen) + ii_read_lock_child(i); + else { + ii_write_lock_child(i); + err = au_refresh_hinode_self(i); + if (!err) + ii_downgrade_lock(i); + else { + ii_write_unlock(i); + break; + } + } + + bstart = au_ibstart(i); + bend = au_ibend(i); + if (bstart <= bindex + && bindex <= bend + && au_h_iptr(i, bindex) + && (!S_ISDIR(i->i_mode) || bstart == bend)) { + err = -EBUSY; + AuVerbose(verbose, "busy i%lu\n", i->i_ino); + ii_read_unlock(i); + break; + } + ii_read_unlock(i); + } + + AuTraceErr(err); + return err; +} + +static int test_children_busy(struct dentry *root, aufs_bindex_t bindex) +{ + int err; + au_gen_t sigen; + + LKTRTrace("b%d\n", bindex); + SiMustWriteLock(root->d_sb); + DiMustWriteLock(root); + /* dont trust BKL */ + AuDebugOn(!kernel_locked()); + + sigen = au_sigen(root->d_sb); + DiMustNoWaiters(root); + IiMustNoWaiters(root->d_inode); + di_write_unlock(root); + err = test_dentry_busy(root, bindex, sigen); + if (!err) + err = test_inode_busy(root->d_sb, bindex, sigen); + di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ + + AuTraceErr(err); + return err; +} + +int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) +{ + int err, rerr, i; + aufs_bindex_t bindex, bend, br_id; + unsigned char do_wh, verbose; + struct au_sbinfo *sbinfo; + struct au_dinfo *dinfo; + struct au_iinfo *iinfo; + struct au_branch *br, **brp; + struct au_wbr *wbr; + struct au_hdentry *hdp; + struct au_hinode *hip; + + LKTRTrace("%s, %.*s\n", del->path, AuDLNPair(del->h_root)); + SiMustWriteLock(sb); + DiMustWriteLock(sb->s_root); + IiMustWriteLock(sb->s_root->d_inode); + + err = 0; + bindex = au_find_dbindex(sb->s_root, del->h_root); + if (bindex < 0) { + if (remount) + goto out; /* success */ + err = -ENOENT; + AuErr("%s no such branch\n", del->path); + goto out; + } + LKTRTrace("bindex b%d\n", bindex); + + err = -EBUSY; + verbose = !!au_opt_test(au_mntflags(sb), VERBOSE); + bend = au_sbend(sb); + if (unlikely(!bend)) { + AuVerbose(verbose, "no more branches left\n"); + goto out; + } + br = au_sbr(sb, bindex); + if (unlikely(au_br_count(br))) { + AuVerbose(verbose, "%d file(s) opened\n", au_br_count(br)); + goto out; + } + + wbr = br->br_wbr; + do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_tmp); + if (do_wh) { +#if 0 /* reserved for future use */ + /* remove whiteout base */ + err = au_br_init_wh(sb, bindex, br, AuBr_RO, del->h_root, + br->br_mnt); + if (unlikely(err)) + goto out; +#else + for (i = 0; i < AuBrWh_Last; i++) { + dput(wbr->wbr_wh[i]); + wbr->wbr_wh[i] = NULL; + } +#endif + } + + err = test_children_busy(sb->s_root, bindex); + if (unlikely(err)) { + if (unlikely(do_wh)) + goto out_wh; + goto out; + } + + err = 0; + if (remount) + sysaufs_brs_del(sb, bindex); + sbinfo = au_sbi(sb); + dinfo = au_di(sb->s_root); + iinfo = au_ii(sb->s_root->d_inode); + + dput(au_h_dptr(sb->s_root, bindex)); + au_hiput(iinfo->ii_hinode + bindex); + br_id = br->br_id; + au_br_do_free(br); + + /* todo: realloc and shrink memory? */ + if (bindex < bend) { + const aufs_bindex_t n = bend - bindex; + + brp = sbinfo->si_branch + bindex; + memmove(brp, brp + 1, sizeof(*brp) * n); + hdp = dinfo->di_hdentry + bindex; + memmove(hdp, hdp + 1, sizeof(*hdp) * n); + hip = iinfo->ii_hinode + bindex; + memmove(hip, hip + 1, sizeof(*hip) * n); + } + sbinfo->si_branch[0 + bend] = NULL; + dinfo->di_hdentry[0 + bend].hd_dentry = NULL; + iinfo->ii_hinode[0 + bend].hi_inode = NULL; + au_hin_init(iinfo->ii_hinode + bend, NULL); + + sbinfo->si_bend--; + dinfo->di_bend--; + iinfo->ii_bend--; + if (remount) + sysaufs_brs_add(sb, bindex); + + if (!bindex) + au_cpup_attr_all(sb->s_root->d_inode); + else + au_sub_nlink(sb->s_root->d_inode, del->h_root->d_inode); + if (au_opt_test(au_mntflags(sb), PLINK)) + au_plink_half_refresh(sb, br_id); + + if (sb->s_maxbytes == del->h_root->d_sb->s_maxbytes) { + bend--; + sb->s_maxbytes = 0; + for (bindex = 0; bindex <= bend; bindex++) { + unsigned long long maxb; + maxb = au_sbr_sb(sb, bindex)->s_maxbytes; + if (sb->s_maxbytes < maxb) + sb->s_maxbytes = maxb; + } + } + + if (au_xino_def_br(sbinfo) == br) + au_xino_def_br_set(NULL, sbinfo); + goto out; /* success */ + + out_wh: + /* revert */ + rerr = au_br_init_wh(sb, bindex, br, br->br_perm, del->h_root, + br->br_mnt); + if (rerr) + AuWarn("failed re-creating base whiteout, %s. (%d)\n", + del->path, rerr); + out: + AuTraceErr(err); + return err; +} + +static int do_need_sigen_inc(int a, int b) +{ + return (au_br_whable(a) && !au_br_whable(b)); +} + +static int need_sigen_inc(int old, int new) +{ + return (do_need_sigen_inc(old, new) + || do_need_sigen_inc(new, old)); +} + +static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex) +{ + int err; + struct file *file, *hf; + + AuTraceEnter(); + SiMustWriteLock(sb); + + /* no need file_list_lock() since sbinfo is locked */ + err = 0; + list_for_each_entry(file, &sb->s_files, f_u.fu_list) { + LKTRTrace("%.*s\n", AuDLNPair(file->f_dentry)); + if (!au_test_aufs_file(file)) + continue; + + fi_read_lock(file); + if (!S_ISREG(file->f_dentry->d_inode->i_mode) + || !(file->f_mode & FMODE_WRITE) + || au_fbstart(file) != bindex) { + FiMustNoWaiters(file); + fi_read_unlock(file); + continue; + } + + if (unlikely(au_test_mmapped(file))) { + err = -EBUSY; + FiMustNoWaiters(file); + fi_read_unlock(file); + break; + } + + /* todo: already flushed? */ + hf = au_h_fptr(file, au_fbstart(file)); + hf->f_flags = au_file_roflags(hf->f_flags); + hf->f_mode &= ~FMODE_WRITE; + put_write_access(hf->f_dentry->d_inode); + FiMustNoWaiters(file); + fi_read_unlock(file); + } + + AuTraceErr(err); + return err; +} + +int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, + int *do_update) +{ + int err; + struct dentry *root; + aufs_bindex_t bindex; + struct au_branch *br; + struct inode *hidden_dir; + + LKTRTrace("%s, %.*s, 0x%x\n", + mod->path, AuDLNPair(mod->h_root), mod->perm); + SiMustWriteLock(sb); + root = sb->s_root; + DiMustWriteLock(root); + IiMustWriteLock(root->d_inode); + + bindex = au_find_dbindex(root, mod->h_root); + if (bindex < 0) { + if (remount) + return 0; /* success */ + err = -ENOENT; + AuErr("%s no such branch\n", mod->path); + goto out; + } + LKTRTrace("bindex b%d\n", bindex); + + hidden_dir = mod->h_root->d_inode; + err = test_br(sb, hidden_dir, mod->perm, mod->path); + if (unlikely(err)) + goto out; + + br = au_sbr(sb, bindex); + if (br->br_perm == mod->perm) + return 0; /* success */ + + if (au_br_writable(br->br_perm)) { +#if 1 + /* remove whiteout base */ + err = au_br_init_wh(sb, bindex, br, mod->perm, mod->h_root, + br->br_mnt); + if (unlikely(err)) + goto out; +#else /* reserved for future use */ + struct au_wbr *wbr; + wbr = br->wbr; + if (wbr) + for (i = 0; i < AuBrWh_Last; i++) { + dput(wbr->wbr_wh[i]); + wbr->wbr_wh[i] = NULL; + } +#endif + + if (!au_br_writable(mod->perm)) { + /* rw --> ro, file might be mmapped */ + +#if 1 /* todo: test more? */ + DiMustNoWaiters(root); + IiMustNoWaiters(root->d_inode); + di_write_unlock(root); + err = au_br_mod_files_ro(sb, bindex); + /* aufs_write_lock() calls ..._child() */ + di_write_lock_child(root); +#endif + } + } else if (au_br_writable(mod->perm)) { + /* ro --> rw */ + err = -ENOMEM; + br->br_wbr = kmalloc(sizeof(*br->br_wbr), GFP_NOFS); + if (br->br_wbr) { + struct path path = { + .mnt = br->br_mnt, + .dentry = mod->h_root + }; + + err = au_wbr_init(br, sb, mod->perm, &path); + if (unlikely(err)) { + kfree(br->br_wbr); + br->br_wbr = NULL; + } + } + } + + if (!err) { + *do_update |= need_sigen_inc(br->br_perm, mod->perm); + br->br_perm = mod->perm; + } + + out: + AuTraceErr(err); + return err; +} --- linux-2.6.27.orig/ubuntu/aufs/aufs.h +++ linux-2.6.27/ubuntu/aufs/aufs.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * main header files + * + * $Id: aufs.h,v 1.4 2008/06/30 03:58:55 sfjro Exp $ + */ + +#ifndef __AUFS_H__ +#define __AUFS_H__ + +#ifdef __KERNEL__ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) +#error you got wrong version +#endif + +#include "debug.h" + +#include "branch.h" +#include "cpup.h" +#include "dcsub.h" +#include "dentry.h" +#include "dir.h" +#include "file.h" +#include "hinode.h" +#include "inode.h" +#include "misc.h" +#include "module.h" +#include "opts.h" +#include "super.h" +#include "sysaufs.h" +#include "vfsub.h" +#include "whout.h" +#include "wkq.h" +/* reserved for future use */ +/* #include "xattr.h" */ + +#ifdef AuNoInlineForStack +#undef noinline_for_stack +#define noinline_for_stack /* */ +#endif + +#endif /* __KERNEL__ */ +#endif /* __AUFS_H__ */ --- linux-2.6.27.orig/ubuntu/aufs/plink.c +++ linux-2.6.27/ubuntu/aufs/plink.c @@ -0,0 +1,360 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * pseudo-link + * + * $Id: plink.c,v 1.9 2008/09/01 02:55:35 sfjro Exp $ + */ + +#include "aufs.h" + +struct pseudo_link { + struct list_head list; + struct inode *inode; +}; + +#ifdef CONFIG_AUFS_DEBUG +void au_plink_list(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + struct list_head *plink_list; + struct pseudo_link *plink; + + AuTraceEnter(); + SiMustAnyLock(sb); + sbinfo = au_sbi(sb); + AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); + + plink_list = &sbinfo->si_plink; + spin_lock(&sbinfo->si_plink_lock); + list_for_each_entry(plink, plink_list, list) + AuDbg("%lu\n", plink->inode->i_ino); + spin_unlock(&sbinfo->si_plink_lock); +} +#endif + +int au_plink_test(struct super_block *sb, struct inode *inode) +{ + int found; + struct au_sbinfo *sbinfo; + struct list_head *plink_list; + struct pseudo_link *plink; + + LKTRTrace("i%lu\n", inode->i_ino); + SiMustAnyLock(sb); + sbinfo = au_sbi(sb); + AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); + + found = 0; + plink_list = &sbinfo->si_plink; + spin_lock(&sbinfo->si_plink_lock); + list_for_each_entry(plink, plink_list, list) + if (plink->inode == inode) { + found = 1; + break; + } + spin_unlock(&sbinfo->si_plink_lock); + return found; +} + +/* 20 is max digits length of ulong 64 */ +#define PLINK_NAME_LEN ((20 + 1) * 2) + +static int plink_name(char *name, int len, struct inode *inode, + aufs_bindex_t bindex) +{ + int rlen; + struct inode *h_inode; + + LKTRTrace("i%lu, b%d\n", inode->i_ino, bindex); + AuDebugOn(len != PLINK_NAME_LEN); + h_inode = au_h_iptr(inode, bindex); + AuDebugOn(!h_inode); + rlen = snprintf(name, len, "%lu.%lu", inode->i_ino, h_inode->i_ino); + AuDebugOn(rlen >= len); + return rlen; +} + +struct dentry *au_plink_lkup(struct super_block *sb, aufs_bindex_t bindex, + struct inode *inode) +{ + struct dentry *h_dentry, *h_parent; + struct au_branch *br; + struct au_wbr *wbr; + struct inode *h_dir; + char tgtname[PLINK_NAME_LEN]; + int len; + struct au_ndx ndx = { + .flags = 0, + .nd = NULL, + /* .br = NULL */ + }; + + LKTRTrace("b%d, i%lu\n", bindex, inode->i_ino); + br = au_sbr(sb, bindex); + wbr = br->br_wbr; + AuDebugOn(!wbr); + h_parent = wbr->wbr_plink; + AuDebugOn(!h_parent); + h_dir = h_parent->d_inode; + AuDebugOn(!h_dir); + + len = plink_name(tgtname, sizeof(tgtname), inode, bindex); + + /* always superio. */ + ndx.nfsmnt = au_do_nfsmnt(br->br_mnt); + mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_CHILD2); + h_dentry = au_sio_lkup_one(tgtname, h_parent, len, &ndx); + mutex_unlock(&h_dir->i_mutex); + return h_dentry; +} + +static int do_whplink(char *tgt, int len, struct dentry *h_parent, + struct dentry *h_dentry, struct vfsmount *nfsmnt, + struct super_block *sb) +{ + int err, dlgt; + struct dentry *h_tgt; + struct inode *h_dir; + struct vfsub_args vargs; + struct au_ndx ndx = { + .nfsmnt = nfsmnt, + .flags = 0, + .nd = NULL, + /* .br = NULL */ + }; + + AuTraceEnter(); + + dlgt = !!au_test_dlgt(au_mntflags(sb)); + if (unlikely(dlgt)) + au_fset_ndx(ndx.flags, DLGT); + h_tgt = au_lkup_one(tgt, h_parent, len, &ndx); + err = PTR_ERR(h_tgt); + if (IS_ERR(h_tgt)) + goto out; + + err = 0; + vfsub_args_init(&vargs, NULL, dlgt, 0); + /* wh.plink dir is not monitored */ + h_dir = h_parent->d_inode; + if (unlikely(h_tgt->d_inode && h_tgt->d_inode != h_dentry->d_inode)) + err = vfsub_unlink(h_dir, h_tgt, &vargs); + if (!err && !h_tgt->d_inode) { + err = vfsub_link(h_dentry, h_dir, h_tgt, &vargs); + /* todo: unnecessary? */ + /* inc_nlink(inode); */ + } + dput(h_tgt); + + out: + AuTraceErr(err); + return err; +} + +struct do_whplink_args { + int *errp; + char *tgt; + int len; + struct dentry *h_parent; + struct dentry *h_dentry; + struct vfsmount *nfsmnt; + struct super_block *sb; +}; + +static void call_do_whplink(void *args) +{ + struct do_whplink_args *a = args; + *a->errp = do_whplink(a->tgt, a->len, a->h_parent, a->h_dentry, + a->nfsmnt, a->sb); +} + +static int whplink(struct dentry *h_dentry, struct inode *inode, + aufs_bindex_t bindex, struct super_block *sb) +{ + int err, len, wkq_err; + struct au_branch *br; + struct au_wbr *wbr; + struct dentry *h_parent; + struct inode *h_dir; + char tgtname[PLINK_NAME_LEN]; + + LKTRTrace("%.*s\n", AuDLNPair(h_dentry)); + br = au_sbr(inode->i_sb, bindex); + wbr = br->br_wbr; + AuDebugOn(!wbr); + h_parent = wbr->wbr_plink; + AuDebugOn(!h_parent); + h_dir = h_parent->d_inode; + AuDebugOn(!h_dir); + + len = plink_name(tgtname, sizeof(tgtname), inode, bindex); + + /* always superio. */ + mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_CHILD2); + if (!au_test_wkq(current)) { + struct do_whplink_args args = { + .errp = &err, + .tgt = tgtname, + .len = len, + .h_parent = h_parent, + .h_dentry = h_dentry, + .nfsmnt = au_do_nfsmnt(br->br_mnt), + .sb = sb + }; + wkq_err = au_wkq_wait(call_do_whplink, &args, /*dlgt*/0); + if (unlikely(wkq_err)) + err = wkq_err; + } else + err = do_whplink(tgtname, len, h_parent, h_dentry, + au_do_nfsmnt(br->br_mnt), sb); + mutex_unlock(&h_dir->i_mutex); + + AuTraceErr(err); + return err; +} + +void au_plink_append(struct super_block *sb, struct inode *inode, + struct dentry *h_dentry, aufs_bindex_t bindex) +{ + struct au_sbinfo *sbinfo; + struct list_head *plink_list; + struct pseudo_link *plink; + int found, err, cnt; + + LKTRTrace("i%lu\n", inode->i_ino); + SiMustAnyLock(sb); + sbinfo = au_sbi(sb); + AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); + + cnt = 0; + found = 0; + plink_list = &sbinfo->si_plink; + spin_lock(&sbinfo->si_plink_lock); + list_for_each_entry(plink, plink_list, list) { + cnt++; + if (plink->inode == inode) { + found = 1; + break; + } + } + + err = 0; + if (!found) { + plink = kmalloc(sizeof(*plink), GFP_ATOMIC); + if (plink) { + plink->inode = au_igrab(inode); + list_add(&plink->list, plink_list); + cnt++; + } else + err = -ENOMEM; + } + spin_unlock(&sbinfo->si_plink_lock); + +#if 0 /* todo: test here */ + if (found) + return; /* success */ +#endif + + if (!err) + err = whplink(h_dentry, inode, bindex, sb); + + if (unlikely(cnt > AUFS_PLINK_WARN)) + AuWarn1("unexpectedly many pseudo links, %d\n", cnt); + if (unlikely(err)) + AuWarn("err %d, damaged pseudo link. ignored.\n", err); +} + +static void do_put_plink(struct pseudo_link *plink, int do_del) +{ + AuTraceEnter(); + + iput(plink->inode); + if (do_del) + list_del(&plink->list); + kfree(plink); +} + +void au_plink_put(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + struct list_head *plink_list; + struct pseudo_link *plink, *tmp; + + AuTraceEnter(); + SiMustWriteLock(sb); + sbinfo = au_sbi(sb); + AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); + + plink_list = &sbinfo->si_plink; + /* spin_lock(&sbinfo->si_plink_lock); */ + list_for_each_entry_safe(plink, tmp, plink_list, list) + do_put_plink(plink, 0); + INIT_LIST_HEAD(plink_list); + /* spin_unlock(&sbinfo->si_plink_lock); */ +} + +void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id) +{ + struct au_sbinfo *sbinfo; + struct list_head *plink_list; + struct pseudo_link *plink, *tmp; + struct inode *inode; + aufs_bindex_t bstart, bend, bindex; + int do_put; + + AuTraceEnter(); + SiMustWriteLock(sb); + sbinfo = au_sbi(sb); + AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); + + plink_list = &sbinfo->si_plink; + /* spin_lock(&sbinfo->si_plink_lock); */ + list_for_each_entry_safe(plink, tmp, plink_list, list) { + do_put = 0; + inode = au_igrab(plink->inode); + ii_write_lock_child(inode); + bstart = au_ibstart(inode); + bend = au_ibend(inode); + if (bstart >= 0) { + for (bindex = bstart; bindex <= bend; bindex++) { + if (!au_h_iptr(inode, bindex) + || au_ii_br_id(inode, bindex) != br_id) + continue; + au_set_h_iptr(inode, bindex, NULL, 0); + do_put = 1; + break; + } + } else + do_put_plink(plink, 1); + + if (do_put) { + for (bindex = bstart; bindex <= bend; bindex++) + if (au_h_iptr(inode, bindex)) { + do_put = 0; + break; + } + if (do_put) + do_put_plink(plink, 1); + } + ii_write_unlock(inode); + iput(inode); + } + /* spin_unlock(&sbinfo->si_plink_lock); */ +} --- linux-2.6.27.orig/ubuntu/aufs/inode.c +++ linux-2.6.27/ubuntu/aufs/inode.c @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * inode functions + * + * $Id: inode.c,v 1.13 2008/09/22 03:52:19 sfjro Exp $ + */ + +#include "aufs.h" + +int au_refresh_hinode_self(struct inode *inode) +{ + int err, new_sz, update; + struct inode *first; + struct au_hinode *p, *q, tmp; + struct super_block *sb; + struct au_iinfo *iinfo; + aufs_bindex_t bindex, bend, new_bindex; + + LKTRTrace("i%lu\n", inode->i_ino); + IiMustWriteLock(inode); + + err = -ENOMEM; + update = 0; + sb = inode->i_sb; + bend = au_sbend(sb); + new_sz = sizeof(*iinfo->ii_hinode) * (bend + 1); + iinfo = au_ii(inode); + p = au_kzrealloc(iinfo->ii_hinode, sizeof(*p) * (iinfo->ii_bend + 1), + new_sz, GFP_NOFS); + if (unlikely(!p)) + goto out; + + iinfo->ii_hinode = p; + p = iinfo->ii_hinode + iinfo->ii_bstart; + first = p->hi_inode; + err = 0; + for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; + bindex++, p++) { + if (!p->hi_inode) + continue; + + new_bindex = au_br_index(sb, p->hi_id); + if (new_bindex == bindex) + continue; + if (new_bindex < 0) { + update++; + au_hiput(p); + p->hi_inode = NULL; + continue; + } + + if (new_bindex < iinfo->ii_bstart) + iinfo->ii_bstart = new_bindex; + if (iinfo->ii_bend < new_bindex) + iinfo->ii_bend = new_bindex; + /* swap two hidden inode, and loop again */ + q = iinfo->ii_hinode + new_bindex; + tmp = *q; + *q = *p; + *p = tmp; + if (tmp.hi_inode) { + bindex--; + p--; + } + } + au_update_brange(inode, /*do_put_zero*/0); + + if (unlikely(err)) + goto out; + + if (1 || first != au_h_iptr(inode, iinfo->ii_bstart)) + au_cpup_attr_all(inode); + if (update && S_ISDIR(inode->i_mode)) + inode->i_version++; + au_update_iigen(inode); + + out: + AuTraceErr(err); + return err; +} + +int au_refresh_hinode(struct inode *inode, struct dentry *dentry) +{ + int err, update; + struct inode *first; + struct au_hinode *p; + struct super_block *sb; + struct au_iinfo *iinfo; + aufs_bindex_t bindex, bend; + unsigned char isdir; + unsigned int flags; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + IiMustWriteLock(inode); + + err = au_refresh_hinode_self(inode); + if (unlikely(err)) + goto out; + + sb = dentry->d_sb; + bend = au_sbend(sb); + iinfo = au_ii(inode); + update = 0; + p = iinfo->ii_hinode + iinfo->ii_bstart; + first = p->hi_inode; + isdir = S_ISDIR(inode->i_mode); + flags = au_hi_flags(inode, isdir); + bend = au_dbend(dentry); + for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) { + struct inode *hi; + struct dentry *hd; + + hd = au_h_dptr(dentry, bindex); + if (!hd || !hd->d_inode) + continue; + + if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) { + hi = au_h_iptr(inode, bindex); + if (hi) { + if (hi == hd->d_inode) + continue; + err = -ESTALE; + break; + } + } + if (bindex < iinfo->ii_bstart) + iinfo->ii_bstart = bindex; + if (iinfo->ii_bend < bindex) + iinfo->ii_bend = bindex; + au_set_h_iptr(inode, bindex, au_igrab(hd->d_inode), flags); + update++; + } + au_update_brange(inode, /*do_put_zero*/0); + + if (unlikely(err)) + goto out; + + if (1 || first != au_h_iptr(inode, iinfo->ii_bstart)) + au_cpup_attr_all(inode); + if (update && isdir) + inode->i_version++; + au_update_iigen(inode); + + out: + AuTraceErr(err); + return err; +} + +static int set_inode(struct inode *inode, struct dentry *dentry) +{ + int err; + struct dentry *h_dentry; + struct inode *h_inode; + umode_t mode; + aufs_bindex_t bindex, bstart, btail; + unsigned char isdir; + struct au_iinfo *iinfo; + unsigned int flags; + + LKTRTrace("i%lu, %.*s\n", inode->i_ino, AuDLNPair(dentry)); + AuDebugOn(!(inode->i_state & I_NEW)); + IiMustWriteLock(inode); + bstart = au_dbstart(dentry); + h_dentry = au_h_dptr(dentry, bstart); + AuDebugOn(!h_dentry); + h_inode = h_dentry->d_inode; + AuDebugOn(!h_inode); + + err = 0; + isdir = 0; + mode = h_inode->i_mode; + switch (mode & S_IFMT) { + case S_IFREG: + btail = au_dbtail(dentry); + inode->i_op = &aufs_iop; + inode->i_fop = &aufs_file_fop; + inode->i_mapping->a_ops = &aufs_aop; + break; + case S_IFDIR: + isdir = 1; + btail = au_dbtaildir(dentry); + inode->i_op = &aufs_dir_iop; + inode->i_fop = &aufs_dir_fop; + break; + case S_IFLNK: + btail = au_dbtail(dentry); + inode->i_op = &aufs_symlink_iop; + /* inode->i_fop = &aufs_file_fop; */ + break; + case S_IFBLK: + case S_IFCHR: + case S_IFIFO: + case S_IFSOCK: + btail = au_dbtail(dentry); + init_special_inode(inode, mode, + au_h_rdev(h_inode, /*h_mnt*/NULL, h_dentry)); + break; + default: + AuIOErr("Unknown file type 0%o\n", mode); + err = -EIO; + goto out; + } + + /* do not set inotify for whiteouted dirs (SHWH mode) */ + flags = au_hi_flags(inode, isdir); + if (unlikely(au_opt_test(au_mntflags(dentry->d_sb), SHWH) + && au_ftest_hi(flags, NOTIFY) + && dentry->d_name.len > AUFS_WH_PFX_LEN + && !memcmp(dentry->d_name.name, AUFS_WH_PFX, + AUFS_WH_PFX_LEN))) + au_fclr_hi(flags, NOTIFY); + iinfo = au_ii(inode); + iinfo->ii_bstart = bstart; + iinfo->ii_bend = btail; + for (bindex = bstart; bindex <= btail; bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + AuDebugOn(!h_dentry->d_inode); + au_set_h_iptr(inode, bindex, au_igrab(h_dentry->d_inode), + flags); + } + au_cpup_attr_all(inode); + + out: + AuTraceErr(err); + return err; +} + +/* successful returns with iinfo write_locked */ +/* todo: return with unlocked? */ +static int reval_inode(struct inode *inode, struct dentry *dentry, int *matched) +{ + int err; + struct inode *h_inode, *h_dinode; + aufs_bindex_t bindex, bend; + + LKTRTrace("i%lu, %.*s\n", inode->i_ino, AuDLNPair(dentry)); + + *matched = 0; + + /* + * before this function, if aufs got any iinfo lock, it must be only + * one, the parent dir. + * it can happen by UDBA and the obsoleted inode number. + */ + err = -EIO; + if (unlikely(inode->i_ino == parent_ino(dentry))) + goto out; + /* todo: test here */ + //AuDebugOn(IS_DEADDIR(inode)); + + err = 0; + h_dinode = au_h_dptr(dentry, au_dbstart(dentry))->d_inode; + /* mutex_lock_nested(&inode->i_mutex, AuLsc_I_CHILD); */ + ii_write_lock_new_child(inode); + bend = au_ibend(inode); + for (bindex = au_ibstart(inode); bindex <= bend; bindex++) { + h_inode = au_h_iptr(inode, bindex); + if (h_inode && h_inode == h_dinode) { + /* && (ibs != bstart + || !au_test_higen(inode, h_inode))); */ + *matched = 1; + err = 0; + if (unlikely(au_iigen(inode) != au_digen(dentry))) + err = au_refresh_hinode(inode, dentry); + break; + } + } + if (unlikely(err)) + ii_write_unlock(inode); + /* mutex_unlock(&inode->i_mutex); */ + + out: + AuTraceErr(err); + return err; +} + +/* successful returns with iinfo write_locked */ +/* todo: return with unlocked? */ +struct inode *au_new_inode(struct dentry *dentry) +{ + struct inode *inode, *h_inode; + struct dentry *h_dentry; + ino_t h_ino; + struct super_block *sb; + int err, match; + aufs_bindex_t bstart; + struct au_xino_entry xinoe; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + sb = dentry->d_sb; + bstart = au_dbstart(dentry); + h_dentry = au_h_dptr(dentry, bstart); + AuDebugOn(!h_dentry); + h_inode = h_dentry->d_inode; + AuDebugOn(!h_inode); + + h_ino = h_inode->i_ino; + err = au_xino_read(sb, bstart, h_ino, &xinoe); + inode = ERR_PTR(err); + if (unlikely(err)) + goto out; + new_ino: + if (!xinoe.ino) { + xinoe.ino = au_xino_new_ino(sb); + if (!xinoe.ino) { + inode = ERR_PTR(-EIO); + goto out; + } + } + + LKTRTrace("i%lu\n", (unsigned long)xinoe.ino); + inode = au_iget_locked(sb, xinoe.ino); + err = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out; + /* todo: test here */ + //AuDebugOn(IS_DEADDIR(inode)); + + LKTRTrace("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); + if (inode->i_state & I_NEW) { + ii_write_lock_new_child(inode); + err = set_inode(inode, dentry); + unlock_new_inode(inode); + if (!err) + goto out; /* success */ + iget_failed(inode); + ii_write_unlock(inode); + goto out_iput; + } else { + AuDebugOn(inode->i_state & I_LOCK); + err = reval_inode(inode, dentry, &match); + if (!err) + goto out; /* success */ + else if (match) + goto out_iput; + } + + if (unlikely(au_test_unique_ino(h_dentry, h_ino))) + AuWarn1("Un-notified UDBA or repeatedly renamed dir," + " b%d, %s, %.*s, hi%lu, i%lu.\n", + bstart, au_sbtype(h_dentry->d_sb), AuDLNPair(dentry), + (unsigned long)h_ino, (unsigned long)xinoe.ino); + xinoe.ino = 0; + err = au_xino_write0(sb, bstart, h_ino, 0); + if (!err) { + iput(inode); + goto new_ino; + } + /* force noxino? */ + + out_iput: + iput(inode); + inode = ERR_PTR(err); + out: + AuTraceErrPtr(inode); + return inode; +} + +/* ---------------------------------------------------------------------- */ + +int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, + struct inode *inode) +{ + int err; + + err = au_br_rdonly(au_sbr(sb, bindex)); + + /* pseudo-link after flushed may out of bounds */ + if (!err + && inode + && au_ibstart(inode) <= bindex + && bindex <= au_ibend(inode)) { + /* + * permission check is unnecessary since vfsub routine + * will be called later + */ + struct inode *hi = au_h_iptr(inode, bindex); + if (hi) + err = IS_IMMUTABLE(hi) ? -EROFS : 0; + } + + AuTraceErr(err); + return err; +} + +int au_test_h_perm(struct inode *h_inode, int mask, int dlgt) +{ + if (!current->fsuid) + return 0; + /* todo: fake nameidata? */ + return vfsub_permission(h_inode, mask, NULL, dlgt); +} + +int au_test_h_perm_sio(struct inode *h_inode, int mask, int dlgt) +{ + if (unlikely(au_test_nfs(h_inode->i_sb) + && (mask & MAY_WRITE) + && S_ISDIR(h_inode->i_mode))) + mask |= MAY_READ; /* force permission check */ + return au_test_h_perm(h_inode, mask, dlgt); +} --- linux-2.6.27.orig/ubuntu/aufs/finfo.c +++ linux-2.6.27/ubuntu/aufs/finfo.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * file private data + * + * $Id: finfo.c,v 1.4 2008/06/30 03:50:21 sfjro Exp $ + */ + +#include "aufs.h" + +struct au_finfo *au_fi(struct file *file) +{ + struct au_finfo *finfo = file->private_data; + AuDebugOn(!finfo + || !finfo->fi_hfile + || (0 < finfo->fi_bend + && (/* au_sbi(file->f_dentry->d_sb)->si_bend + < finfo->fi_bend + || */ finfo->fi_bend < finfo->fi_bstart))); + return finfo; +} + +struct au_branch *au_fbr(struct file *file, aufs_bindex_t bindex) +{ + struct au_finfo *finfo = au_fi(file); + struct au_hfile *hf; + + FiMustAnyLock(file); + AuDebugOn(!finfo + || finfo->fi_bstart < 0 + || bindex < finfo->fi_bstart + || finfo->fi_bend < bindex); + hf = finfo->fi_hfile + bindex; + AuDebugOn(hf->hf_br && au_br_count(hf->hf_br) <= 0); + return hf->hf_br; +} + +struct file *au_h_fptr(struct file *file, aufs_bindex_t bindex) +{ + struct au_finfo *finfo = au_fi(file); + struct au_hfile *hf; + + FiMustAnyLock(file); + AuDebugOn(!finfo + || finfo->fi_bstart < 0 + || bindex < finfo->fi_bstart + || finfo->fi_bend < bindex); + hf = finfo->fi_hfile + bindex; + AuDebugOn(hf->hf_file + && file_count(hf->hf_file) <= 0 + && au_br_count(hf->hf_br) <= 0); + return hf->hf_file; +} + +void au_hfput(struct au_hfile *hf) +{ + if (hf->hf_file->f_mode & FMODE_EXEC) + au_allow_write_access(hf->hf_file); + fput(hf->hf_file); + hf->hf_file = NULL; + AuDebugOn(!hf->hf_br); + au_br_put(hf->hf_br); + hf->hf_br = NULL; +} + +void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val) +{ + struct au_finfo *finfo = au_fi(file); + struct au_hfile *hf; + + FiMustWriteLock(file); + AuDebugOn(!finfo + || finfo->fi_bstart < 0 + || bindex < finfo->fi_bstart + || finfo->fi_bend < bindex); + AuDebugOn(val && file_count(val) <= 0); + hf = finfo->fi_hfile + bindex; + AuDebugOn(val && hf->hf_file); + if (hf->hf_file) + au_hfput(hf); + if (val) { + hf->hf_file = val; + hf->hf_br = au_sbr(file->f_dentry->d_sb, bindex); + } +} + +void au_finfo_fin(struct file *file) +{ + struct au_finfo *finfo; + struct dentry *dentry; + aufs_bindex_t bindex, bend; + + dentry = file->f_dentry; + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + SiMustAnyLock(dentry->d_sb); + + fi_write_lock(file); + bend = au_fbend(file); + bindex = au_fbstart(file); + if (bindex >= 0) + for (; bindex <= bend; bindex++) + au_set_h_fptr(file, bindex, NULL); + + finfo = au_fi(file); +#ifdef CONFIG_AUFS_DEBUG + if (finfo->fi_bstart >= 0) { + bend = au_fbend(file); + for (bindex = finfo->fi_bstart; bindex <= bend; bindex++) { + struct au_hfile *hf; + hf = finfo->fi_hfile + bindex; + AuDebugOn(hf->hf_file || hf->hf_br); + } + } +#endif + + kfree(finfo->fi_hfile); + fi_write_unlock(file); + au_cache_free_finfo(finfo); +} + +int au_finfo_init(struct file *file) +{ + struct au_finfo *finfo; + struct dentry *dentry; + union { + void *p; + unsigned long ul; + } u; + + dentry = file->f_dentry; + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + AuDebugOn(!dentry->d_inode); + + finfo = au_cache_alloc_finfo(); + if (finfo) { + finfo->fi_hfile = kcalloc(au_sbend(dentry->d_sb) + 1, + sizeof(*finfo->fi_hfile), GFP_NOFS); + if (finfo->fi_hfile) { + au_rw_init_wlock(&finfo->fi_rwsem); + finfo->fi_bstart = -1; + finfo->fi_bend = -1; + atomic_set(&finfo->fi_generation, au_digen(dentry)); + /* smp_mb(); */ /* atomic_set */ + + /* + * a dirty trick for handling FMODE_EXEC and + * deny_write_access(). + * because FMODE_EXEC flag is not passed to + * f_op->open(), + * aufs set it to file->private_data temporary in lookup + * or dentry revalidation operations. + * restore the flag to f_mode here. + */ + u.p = file->private_data; + if (u.ul & FMODE_EXEC) { + file->f_mode |= FMODE_EXEC; + smp_mb(); /* flush f_mode */ + } + + file->private_data = finfo; + return 0; /* success */ + } + au_cache_free_finfo(finfo); + } + + AuTraceErr(-ENOMEM); + return -ENOMEM; +} --- linux-2.6.27.orig/ubuntu/aufs/opts.h +++ linux-2.6.27/ubuntu/aufs/opts.h @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * mount options/flags + * + * $Id: opts.h,v 1.6 2008/08/17 23:03:27 sfjro Exp $ + */ + +#ifndef __AUFS_OPTS_H__ +#define __AUFS_OPTS_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include "wkq.h" + +/* ---------------------------------------------------------------------- */ +/* mount flags */ + +/* external inode number bitmap and translation table */ +#define AuOpt_XINO 1 +#define AuOpt_XINODIR (1 << 1) +#define AuOpt_TRUNC_XINO (1 << 2) +#define AuOpt_UDBA_NONE (1 << 3) /* users direct branch access */ +#define AuOpt_UDBA_REVAL (1 << 4) +#define AuOpt_UDBA_INOTIFY (1 << 5) +#define AuOpt_SHWH (1 << 6) +#define AuOpt_PLINK (1 << 7) +#define AuOpt_WARN_PERM (1 << 8) +#define AuOpt_DIRPERM1 (1 << 9) +#define AuOpt_DLGT (1 << 10) +#define AuOpt_COO_NONE (1 << 11) /* copyup on open */ +#define AuOpt_COO_LEAF (1 << 12) +#define AuOpt_COO_ALL (1 << 13) +#define AuOpt_ALWAYS_DIROPQ (1 << 14) +#define AuOpt_REFROF (1 << 15) +#define AuOpt_VERBOSE (1 << 16) + +#if 1 /* ndef CONFIG_AUFS_EXPORT */ /* reserved for future use */ +#undef AuOpt_XINODIR +#define AuOpt_XINODIR 0 +#endif +#ifndef CONFIG_AUFS_HINOTIFY +#undef AuOpt_UDBA_INOTIFY +#define AuOpt_UDBA_INOTIFY 0 +#endif +#ifndef CONFIG_AUFS_SHWH +#undef AuOpt_SHWH +#define AuOpt_SHWH 0 +#endif +#ifndef CONFIG_AUFS_DLGT +#undef AuOpt_DIRPERM1 +#define AuOpt_DIRPERM1 0 +#undef AuOpt_DLGT +#define AuOpt_DLGT 0 +#endif + +/* policies to select one among multiple writable branches */ +enum { + AuWbrCreate_TDP, /* top down parent */ + AuWbrCreate_RR, /* round robin */ + AuWbrCreate_MFS, /* most free space */ + AuWbrCreate_MFSV, /* mfs with seconds */ + AuWbrCreate_MFSRR, /* mfs then rr */ + AuWbrCreate_MFSRRV, /* mfs then rr with seconds */ + AuWbrCreate_PMFS, /* parent and mfs */ + AuWbrCreate_PMFSV, /* parent and mfs with seconds */ + + AuWbrCreate_Def = AuWbrCreate_TDP +}; + +enum { + AuWbrCopyup_TDP, /* top down parent */ + AuWbrCopyup_BUP, /* bottom up parent */ + AuWbrCopyup_BU, /* bottom up */ + + AuWbrCopyup_Def = AuWbrCopyup_TDP +}; + +#define AuOptMask_COO (AuOpt_COO_NONE \ + | AuOpt_COO_LEAF \ + | AuOpt_COO_ALL) +#define AuOptMask_UDBA (AuOpt_UDBA_NONE \ + | AuOpt_UDBA_REVAL \ + | AuOpt_UDBA_INOTIFY) + +#ifdef CONFIG_AUFS_COMPAT +#define AuOpt_DefExtra1 AuOpt_ALWAYS_DIROPQ +#else +#define AuOpt_DefExtra1 0 +#endif + +#define AuOpt_Def (AuOpt_XINO \ + | AuOpt_UDBA_REVAL \ + | AuOpt_WARN_PERM \ + | AuOpt_COO_NONE \ + | AuOpt_PLINK \ + | AuOpt_DefExtra1) + +/* ---------------------------------------------------------------------- */ + +struct au_opt_add { + aufs_bindex_t bindex; + char *path; + int perm; + struct nameidata nd; +}; + +struct au_opt_del { + char *path; + struct dentry *h_root; +}; + +struct au_opt_mod { + char *path; + int perm; + struct dentry *h_root; +}; + +struct au_opt_xino { + char *path; + struct file *file; +}; + +struct au_opt_xinodir { + char *name; + struct path path; +}; + +struct au_opt_xino_itrunc { + aufs_bindex_t bindex; +}; + +struct au_opt_xino_trunc_v { + unsigned long long upper; + int step; +}; + +struct au_opt_wbr_create { + int wbr_create; + int mfs_second; + unsigned long long mfsrr_watermark; +}; + +struct au_opt { + int type; + union { + struct au_opt_xino xino; + struct au_opt_xinodir xinodir; + struct au_opt_xino_itrunc xino_itrunc; + struct au_opt_add add; + struct au_opt_del del; + struct au_opt_mod mod; + int dirwh; + int rdcache; + int deblk; + int nhash; + int udba; + int coo; + struct au_opt_wbr_create wbr_create; + int wbr_copyup; + }; +}; + +/* opts flags */ +#define AuOpts_REMOUNT 1 +#define AuOpts_REFRESH_DIR (1 << 1) +#define AuOpts_REFRESH_NONDIR (1 << 2) +#define AuOpts_TRUNC_XIB (1 << 3) +#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name) +#define au_fset_opts(flags, name) { (flags) |= AuOpts_##name; } +#define au_fclr_opts(flags, name) { (flags) &= ~AuOpts_##name; } + +struct au_opts { + struct au_opt *opt; + int max_opt; + + unsigned int given_udba; + unsigned int flags; +}; + +/* ---------------------------------------------------------------------- */ + +const char *au_optstr_br_perm(int brperm); +const char *au_optstr_udba(int udba); +const char *au_optstr_coo(int coo); +const char *au_optstr_wbr_copyup(int wbr_copyup); +const char *au_optstr_wbr_create(int wbr_create); + +void au_opts_free(struct au_opts *opts); +int au_opts_parse(struct super_block *sb, unsigned long flags, char *str, + struct au_opts *opts); +int au_opts_mount(struct super_block *sb, struct au_opts *opts); +int au_opts_remount(struct super_block *sb, struct au_opts *opts); + +/* ---------------------------------------------------------------------- */ + +#define au_opt_test(flags, name) (flags & AuOpt_##name) + +static inline int au_opt_test_xino(unsigned int flags) +{ + return (flags & (AuOpt_XINO | AuOpt_XINODIR)); +} + +#define au_opt_set(flags, name) do { \ + BUILD_BUG_ON(AuOpt_##name & (AuOptMask_COO | AuOptMask_UDBA)); \ + ((flags) |= AuOpt_##name); \ +} while (0) + +#define au_opt_set_coo(flags, name) do { \ + (flags) &= ~AuOptMask_COO; \ + ((flags) |= AuOpt_##name); \ +} while (0) + +#define au_opt_set_udba(flags, name) do { \ + (flags) &= ~AuOptMask_UDBA; \ + ((flags) |= AuOpt_##name); \ +} while (0) + +#define au_opt_clr(flags, name) { ((flags) &= ~AuOpt_##name); } + +static inline int au_test_dlgt(unsigned int flags) +{ + return (au_opt_test(flags, DLGT) && !au_test_wkq(current)); +} + +static inline int au_test_dirperm1(unsigned int flags) +{ + return (au_opt_test(flags, DIRPERM1) && !au_test_wkq(current)); +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_OPTS_H__ */ --- linux-2.6.27.orig/ubuntu/aufs/Makefile +++ linux-2.6.27/ubuntu/aufs/Makefile @@ -0,0 +1,74 @@ +# AUFS Makefile for the Linux 2.6.25 and later +# $Id: Makefile,v 1.8 2008/08/04 00:32:21 sfjro Exp $ + +# the environment variables are not inherited since 2.6.23 +ifdef AUFS_EXTRA_CFLAGS +ccflags-y += ${AUFS_EXTRA_CFLAGS} +endif + +######################################## + +ifdef CONFIG_AUFS_RR_SQUASHFS +# cf. squashfs3.2-r2 and sqlzma patch. +ccflags-y += -DSQUASHFS_MAGIC=0x73717368 +ccflags-y += -DSQUASHFS_MAGIC_SWAP=0x68737173 +ccflags-y += -DSQUASHFS_MAGIC_LZMA=0x71736873 +ccflags-y += -DSQUASHFS_MAGIC_LZMA_SWAP=0x73687371 +endif + +# defined in ${srctree}/fs/fuse/inode.c +ccflags-$(CONFIG_AUFS_WORKAROUND_FUSE) += -DFUSE_SUPER_MAGIC=0x65735546 + +# defined in ${srctree}/fs/xfs/xfs_sb.h +# tristate +ifdef CONFIG_XFS_FS +ccflags-y += -DXFS_SB_MAGIC=0x58465342 +endif + +# defined in ${srctree}/mm/shmem.c in linux-2.6.26 and earlier +# tristate +ifdef CONFIG_TMPFS +ccflags-y += -DTMPFS_MAGIC=0x01021994 +endif + +# defined in ${srctree}fs/sysfs/mount.c +# bool +ccflags-$(CONFIG_SYSFS) += -DSYSFS_MAGIC=0x62656572 + +ifndef EXTRAVERSION +EXTRAVERSION = $(shell echo ${KERNELVERSION} | cut -f3- -d. | cut -f2- -d-) +endif +# for -mm tree, support the latest version only +ifneq ($(strip $(shell echo ${EXTRAVERSION} | fgrep -- mm)),) +ccflags-y += -DCONFIG_AUFS_UNIONFS22_PATCH -DCONFIG_AUFS_UNIONFS23_PATCH +endif + +-include $(dir $(lastword ${MAKEFILE_LIST}))priv.mk +#$(warning ${ccflags-y}) + +######################################## + +obj-$(CONFIG_AUFS) += aufs.o +aufs-y := module.o super.o sbinfo.o branch.o xino.o sysaufs.o opts.o \ + wkq.o vfsub.o dcsub.o \ + cpup.o whout.o plink.o wbr_policy.o \ + dentry.o dinfo.o \ + file.o f_op.o finfo.o \ + dir.o vdir.o \ + inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o iinfo.o \ + misc.o + +aufs-$(CONFIG_SYSFS) += sysfs.o +aufs-$(CONFIG_AUFS_BR_NFS) += br_nfs.o +aufs-$(CONFIG_AUFS_BR_XFS) += br_xfs.o +aufs-$(CONFIG_AUFS_WORKAROUND_FUSE) += br_fuse.o +aufs-$(CONFIG_AUFS_DLGT) += dlgt.o +aufs-$(CONFIG_AUFS_HINOTIFY) += hinotify.o +aufs-$(CONFIG_AUFS_HIN_OR_DLGT) += hin_or_dlgt.o +aufs-$(CONFIG_AUFS_HIN_OR_FUSE) += hin_or_fuse.o +aufs-$(CONFIG_AUFS_EXPORT) += export.o +aufs-$(CONFIG_AUFS_ROBR) += robr.o +# reserved for future use +#aufs-$(CONFIG_AUFS_XATTR) += xattr.o +aufs-$(CONFIG_AUFS_DEBUG) += debug.o +aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o --- linux-2.6.27.orig/ubuntu/aufs/hin_or_fuse.c +++ linux-2.6.27/ubuntu/aufs/hin_or_fuse.c @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * inode attributes on FUSE branch or HINOTIFY + * + * $Id: hin_or_fuse.c,v 1.6 2008/09/15 03:14:30 sfjro Exp $ + */ + +#include "aufs.h" + +static struct dentry * +au_h_dget_any(struct dentry *dentry, aufs_bindex_t *bindex) +{ + struct dentry *h_dentry; + struct inode *inode, *h_inode; + struct super_block *sb; + aufs_bindex_t ib, db; + + /* must be positive dentry */ + inode = dentry->d_inode; + LKTRTrace("%.*s, i%lu\n", AuDLNPair(dentry), inode->i_ino); + + sb = dentry->d_sb; + db = au_dbstart(dentry); + ib = au_ibstart(inode); + if (db == ib) { + *bindex = db; + h_dentry = dget(au_h_dptr(dentry, db)); + if (h_dentry) + goto out; /* success */ + } + + *bindex = ib; + h_inode = au_h_iptr(inode, ib); + h_dentry = d_find_alias(h_inode); + if (h_dentry) + goto out; /* success */ + +#if 0 + if (au_opt_test(au_mntflags(sb), PLINK) + && au_plink_test(sb, inode)) { + h_dentry = au_plink_lkup(sb, ib, inode); + if (IS_ERR(h_dentry)) + goto out; + AuDebugOn(!h_dentry->d_inode); + goto out; /* success */ + } +#endif + + h_dentry = dget(au_hi_wh(inode, ib)); + + out: + AuTraceErrPtr(h_dentry); + return h_dentry; +} + +int aufs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *st) +{ + int err; + unsigned int mnt_flags; + aufs_bindex_t bindex; + struct inode *inode; + struct dentry *h_dentry; + struct super_block *sb, *h_sb; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + + err = 0; + inode = dentry->d_inode; + sb = dentry->d_sb; + aufs_read_lock(dentry, AuLock_FLUSH | AuLock_IR); + + /* todo: nfs branch too? */ + /* todo: test bit inotify option too? */ + mnt_flags = au_mntflags(sb); + bindex = au_ibstart(inode); + h_sb = au_sbr_sb(sb, bindex); + if (!au_test_fuse(h_sb) + //&& !au_test_nfs(h_sb) /* todo: fix me */ + && (au_iigen(inode) == au_sigen(sb) + || (au_opt_test(mnt_flags, PLINK) && au_plink_test(sb, inode)))) + goto fill; + + h_dentry = au_h_dget_any(dentry, &bindex); + err = PTR_ERR(h_dentry); + if (IS_ERR(h_dentry)) + goto out; + + err = -EIO; + if (h_dentry && h_dentry->d_inode) + err = vfsub_getattr(au_sbr_mnt(sb, bindex), h_dentry, st, + au_test_dlgt(mnt_flags)); + dput(h_dentry); + if (!err) { + au_cpup_attr_all(inode); + fill: + generic_fillattr(inode, st); + } + + out: + aufs_read_unlock(dentry, AuLock_IR); + AuTraceErr(err); + return err; +} --- linux-2.6.27.orig/ubuntu/aufs/sysaufs.h +++ linux-2.6.27/ubuntu/aufs/sysaufs.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * sysfs interface and lifetime management + * + * $Id: sysaufs.h,v 1.11 2008/09/15 03:14:55 sfjro Exp $ + */ + +#ifndef __SYSAUFS_H__ +#define __SYSAUFS_H__ + +#ifdef __KERNEL__ + +#include +#include +#include "module.h" +#include "super.h" + +#define SysaufsSb_PREFIX "si_" /* followed by %p */ + +struct au_sbi_attr { + struct attribute attr; + int (*show)(struct seq_file *seq, struct super_block *sb); +}; + +/* ---------------------------------------------------------------------- */ + +/* sysaufs.c */ +extern unsigned long au_si_mask; +extern struct kset *au_kset; +extern struct attribute *au_sbi_attrs[]; +int sysaufs_si_init(struct au_sbinfo *sbinfo); +int __init sysaufs_init(void); +void sysaufs_fin(void); + +/* ---------------------------------------------------------------------- */ + +struct au_branch; +#ifdef CONFIG_SYSFS +/* sysfs.c */ +extern struct attribute_group *au_attr_group; +extern struct kobj_type *au_ktype; + +int sysaufs_sbi_xino(struct seq_file *seq, struct super_block *sb); +#ifdef CONFIG_AUFS_EXPORT +int sysaufs_sbi_xigen(struct seq_file *seq, struct super_block *sb); +#endif +int sysaufs_sbi_mntpnt1(struct seq_file *seq, struct super_block *sb); +ssize_t sysaufs_sbi_show(struct kobject *kobj, struct attribute *attr, + char *buf); + +void sysaufs_br_init(struct au_branch *br); +void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); +void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); +#else +#define au_attr_group NULL +#define au_ktype NULL + +static inline +int sysaufs_sbi_xino(struct seq_file *seq, struct super_block *sb) +{ + return 0; +} + +#ifdef CONFIG_AUFS_EXPORT +static inline +int sysaufs_sbi_xigen(struct seq_file *seq, struct super_block *sb) +{ + return 0; +} +#endif + +static inline +int sysaufs_sbi_mntpnt1(struct seq_file *seq, struct super_block *sb) +{ + return 0; +} + +static inline +ssize_t sysaufs_sbi_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + return 0; +} + +static inline void sysaufs_br_init(struct au_branch *br) +{ + /* empty */ +} + +static inline void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) +{ + /* nothing */ +} + +static inline void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) +{ + /* nothing */ +} +#endif /* CONFIG_SYSFS */ + +#endif /* __KERNEL__ */ +#endif /* __SYSAUFS_H__ */ --- linux-2.6.27.orig/ubuntu/aufs/vdir.c +++ linux-2.6.27/ubuntu/aufs/vdir.c @@ -0,0 +1,941 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * virtual or vertical directory + * + * $Id: vdir.c,v 1.11 2008/09/22 03:52:19 sfjro Exp $ + */ + +#include "aufs.h" + +static int calc_size(int namelen) +{ + int sz; + + sz = sizeof(struct au_vdir_de) + namelen; + if (sizeof(ino_t) == sizeof(long)) { + const int mask = sizeof(ino_t) - 1; + if (sz & mask) { + sz += sizeof(ino_t); + sz &= ~mask; + } + } + + AuDebugOn(sz % sizeof(ino_t)); + return sz; +} + +static int set_deblk_end(union au_vdir_deblk_p *p, + union au_vdir_deblk_p *deblk_end) +{ + if (calc_size(0) <= deblk_end->p - p->p) { + p->de->de_str.len = 0; + /* smp_mb(); */ + return 0; + } + return -1; /* error */ +} + +/* returns true or false */ +static int is_deblk_end(union au_vdir_deblk_p *p, + union au_vdir_deblk_p *deblk_end) +{ + if (calc_size(0) <= deblk_end->p - p->p) + return !p->de->de_str.len; + return 1; +} + +static au_vdir_deblk_t *last_deblk(struct au_vdir *vdir) +{ + return vdir->vd_deblk[vdir->vd_nblk - 1]; +} + +void au_nhash_init(struct au_nhash *nhash) +{ + int i; + for (i = 0; i < AuSize_NHASH; i++) + INIT_HLIST_HEAD(nhash->heads + i); +} + +struct au_nhash *au_nhash_new(gfp_t gfp) +{ + struct au_nhash *nhash; + + nhash = kmalloc(sizeof(*nhash), gfp); + if (nhash) { + au_nhash_init(nhash); + return nhash; + } + return ERR_PTR(-ENOMEM); +} + +void au_nhash_del(struct au_nhash *nhash) +{ + au_nhash_fin(nhash); + kfree(nhash); +} + +void au_nhash_move(struct au_nhash *dst, struct au_nhash *src) +{ + int i; + + AuTraceEnter(); + + *dst = *src; + for (i = 0; i < AuSize_NHASH; i++) { + struct hlist_head *h; + h = dst->heads + i; + if (h->first) + h->first->pprev = &h->first; + INIT_HLIST_HEAD(src->heads + i); + } + /* smp_mb(); */ +} + +/* ---------------------------------------------------------------------- */ + +void au_nhash_fin(struct au_nhash *whlist) +{ + int i; + struct hlist_head *head; + struct au_vdir_wh *tpos; + struct hlist_node *pos, *n; + + AuTraceEnter(); + + for (i = 0; i < AuSize_NHASH; i++) { + head = whlist->heads + i; + hlist_for_each_entry_safe(tpos, pos, n, head, wh_hash) { + /* hlist_del(pos); */ + kfree(tpos); + } + } +} + +int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, + int limit) +{ + int n, i; + struct hlist_head *head; + struct au_vdir_wh *tpos; + struct hlist_node *pos; + + LKTRTrace("limit %d\n", limit); + + n = 0; + for (i = 0; i < AuSize_NHASH; i++) { + head = whlist->heads + i; + hlist_for_each_entry(tpos, pos, head, wh_hash) + if (tpos->wh_bindex == btgt && ++n > limit) + return 1; + } + return 0; +} + +static unsigned int au_name_hash(const unsigned char *name, unsigned int len) +{ + return (full_name_hash(name, len) % AuSize_NHASH); +} + +/* returns found(true) or not */ +int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int namelen) +{ + struct hlist_head *head; + struct au_vdir_wh *tpos; + struct hlist_node *pos; + struct au_vdir_destr *str; + + LKTRTrace("%.*s\n", namelen, name); + + head = whlist->heads + au_name_hash(name, namelen); + hlist_for_each_entry(tpos, pos, head, wh_hash) { + str = &tpos->wh_str; + LKTRTrace("%.*s\n", str->len, str->name); + if (str->len == namelen && !memcmp(str->name, name, namelen)) + return 1; + } + return 0; +} + +int au_nhash_append_wh(struct au_nhash *whlist, char *name, int namelen, + ino_t ino, unsigned int d_type, aufs_bindex_t bindex, + unsigned char shwh) +{ + int err; + struct au_vdir_destr *str; + struct au_vdir_wh *wh; + + LKTRTrace("%.*s\n", namelen, name); + + err = -ENOMEM; + wh = kmalloc(sizeof(*wh) + namelen, GFP_NOFS); + if (unlikely(!wh)) + goto out; + err = 0; + wh->wh_bindex = bindex; + if (unlikely(shwh)) + au_shwh_init_wh(wh, ino, d_type); + str = &wh->wh_str; + str->len = namelen; + memcpy(str->name, name, namelen); + hlist_add_head(&wh->wh_hash, + whlist->heads + au_name_hash(name, namelen)); + /* smp_mb(); */ + + out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +void au_vdir_free(struct au_vdir *vdir) +{ + au_vdir_deblk_t **deblk; + + AuTraceEnter(); + + deblk = vdir->vd_deblk; + while (vdir->vd_nblk--) { + kfree(*deblk); + deblk++; + } + kfree(vdir->vd_deblk); + au_cache_free_vdir(vdir); +} + +static int append_deblk(struct au_vdir *vdir) +{ + int err, sz, i; + au_vdir_deblk_t **o; + union au_vdir_deblk_p p, deblk_end; + + AuTraceEnter(); + + err = -ENOMEM; + sz = sizeof(*o) * vdir->vd_nblk; + o = au_kzrealloc(vdir->vd_deblk, sz, sz + sizeof(*o), GFP_NOFS); + if (unlikely(!o)) + goto out; + vdir->vd_deblk = o; + p.deblk = kmalloc(sizeof(*p.deblk), GFP_NOFS); + if (p.deblk) { + i = vdir->vd_nblk++; + vdir->vd_deblk[i] = p.deblk; + vdir->vd_last.i = i; + vdir->vd_last.p.p = p.p; + deblk_end.deblk = p.deblk + 1; + err = set_deblk_end(&p, &deblk_end); + AuDebugOn(err); + } + + out: + AuTraceErr(err); + return err; +} + +static struct au_vdir *alloc_vdir(void) +{ + struct au_vdir *vdir; + int err; + + AuTraceEnter(); + + err = -ENOMEM; + vdir = au_cache_alloc_vdir(); + if (unlikely(!vdir)) + goto out; + vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS); + if (unlikely(!vdir->vd_deblk)) + goto out_free; + + vdir->vd_nblk = 0; + vdir->vd_version = 0; + vdir->vd_jiffy = 0; + err = append_deblk(vdir); + if (!err) + return vdir; /* success */ + + kfree(vdir->vd_deblk); + + out_free: + au_cache_free_vdir(vdir); + out: + vdir = ERR_PTR(err); + AuTraceErrPtr(vdir); + return vdir; +} + +static int reinit_vdir(struct au_vdir *vdir) +{ + int err; + union au_vdir_deblk_p p, deblk_end; + + AuTraceEnter(); + + while (vdir->vd_nblk > 1) { + kfree(vdir->vd_deblk[vdir->vd_nblk - 1]); + vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; + vdir->vd_nblk--; + } + p.deblk = vdir->vd_deblk[0]; + deblk_end.deblk = p.deblk + 1; + err = set_deblk_end(&p, &deblk_end); + AuDebugOn(err); + vdir->vd_version = 0; + vdir->vd_jiffy = 0; + vdir->vd_last.i = 0; + vdir->vd_last.p.deblk = vdir->vd_deblk[0]; + /* smp_mb(); */ + return err; +} + +/* ---------------------------------------------------------------------- */ + +static void free_dehlist(struct au_nhash *dehlist) +{ + int i; + struct hlist_head *head; + struct au_vdir_dehstr *tpos; + struct hlist_node *pos, *n; + + AuTraceEnter(); + + for (i = 0; i < AuSize_NHASH; i++) { + head = dehlist->heads + i; + hlist_for_each_entry_safe(tpos, pos, n, head, hash) { + /* hlist_del(pos); */ + au_cache_free_dehstr(tpos); + } + } +} + +/* returns found(true) or not */ +static int test_known(struct au_nhash *delist, char *name, int namelen) +{ + struct hlist_head *head; + struct au_vdir_dehstr *tpos; + struct hlist_node *pos; + struct au_vdir_destr *str; + + LKTRTrace("%.*s\n", namelen, name); + + head = delist->heads + au_name_hash(name, namelen); + hlist_for_each_entry(tpos, pos, head, hash) { + str = tpos->str; + LKTRTrace("%.*s\n", str->len, str->name); + if (str->len == namelen && !memcmp(str->name, name, namelen)) + return 1; + } + return 0; + +} + +static int append_de(struct au_vdir *vdir, char *name, int namelen, ino_t ino, + unsigned int d_type, struct au_nhash *delist) +{ + int err, sz; + union au_vdir_deblk_p p, *room, deblk_end; + struct au_vdir_dehstr *dehstr; + + LKTRTrace("%.*s %d, i%lu, dt%u\n", + namelen, name, namelen, (unsigned long)ino, d_type); + + p.deblk = last_deblk(vdir); + deblk_end.deblk = p.deblk + 1; + room = &vdir->vd_last.p; + AuDebugOn(room->p < p.p || deblk_end.p <= room->p + || !is_deblk_end(room, &deblk_end)); + + sz = calc_size(namelen); + if (unlikely(sz > deblk_end.p - room->p)) { + err = append_deblk(vdir); + if (unlikely(err)) + goto out; + p.deblk = last_deblk(vdir); + deblk_end.deblk = p.deblk + 1; + /* smp_mb(); */ + AuDebugOn(room->p != p.p); + } + + err = -ENOMEM; + dehstr = au_cache_alloc_dehstr(); + if (unlikely(!dehstr)) + goto out; + dehstr->str = &room->de->de_str; + hlist_add_head(&dehstr->hash, + delist->heads + au_name_hash(name, namelen)); + + room->de->de_ino = ino; + room->de->de_type = d_type; + room->de->de_str.len = namelen; + memcpy(room->de->de_str.name, name, namelen); + + err = 0; + room->p += sz; + if (unlikely(set_deblk_end(room, &deblk_end))) + err = append_deblk(vdir); + /* smp_mb(); */ + + out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + unsigned int d_type, ino_t *ino) +{ + int err; + struct au_xino_entry xinoe; + struct mutex *mtx; + const int isdir = (d_type == DT_DIR); + + /* prevent hardlinks from race condition */ + mtx = NULL; + if (!isdir) { + mtx = &au_sbr(sb, bindex)->br_xino.xi_nondir_mtx; + mutex_lock(mtx); + } + err = au_xino_read(sb, bindex, h_ino, &xinoe); + if (unlikely(err)) + goto out; + + if (!xinoe.ino) { + err = -EIO; + xinoe.ino = au_xino_new_ino(sb); + if (unlikely(!xinoe.ino)) + goto out; + +#if 0 /* reserved for future use */ + struct inode *h_inode; + xinoe.h_gen = AuXino_INVALID_HGEN; + h_inode = ilookup(au_sbr_sb(sb, bindex), h_ino); + if (h_inode) { + if (!is_bad_inode(h_inode)) { + xinoe.h_gen = h_inode->i_generation; + WARN_ON(xinoe.h_gen == AuXino_INVALID_HGEN); + } + iput(h_inode); + } +#endif + err = au_xino_write(sb, bindex, h_ino, &xinoe); + if (unlikely(err)) + goto out; + } + + *ino = xinoe.ino; + + out: + if (!isdir) + mutex_unlock(mtx); + AuTraceErr(err); + return err; +} + +static int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + unsigned int d_type, ino_t *ino) +{ +#ifdef CONFIG_AUFS_SHWH + return au_ino(sb, bindex, h_ino, d_type, ino); +#else + return 0; +#endif +} + +#define AuFillVdir_CALLED 1 +#define AuFillVdir_SHWH (1 << 1) +#define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name) +#define au_fset_fillvdir(flags, name) { (flags) |= AuFillVdir_##name; } +#define au_fclr_fillvdir(flags, name) { (flags) &= ~AuFillVdir_##name; } +#ifndef CONFIG_AUFS_SHWH +#undef AuFillVdir_SHWH +#define AuFillVdir_SHWH 0 +#endif + +struct fillvdir_arg { + struct file *file; + struct au_vdir *vdir; + struct au_nhash *delist; + struct au_nhash *whlist; + aufs_bindex_t bindex; + unsigned int flags; + int err; +}; + +static int fillvdir(void *__arg, const char *__name, int namelen, loff_t offset, + u64 h_ino, unsigned int d_type) +{ + struct fillvdir_arg *arg = __arg; + char *name = (void *)__name; + aufs_bindex_t bindex, bend; + struct super_block *sb; + ino_t ino; + + LKTRTrace("%.*s, namelen %d, i%llu, dt%u\n", + namelen, name, namelen, (unsigned long long)h_ino, d_type); + + sb = arg->file->f_dentry->d_sb; + bend = arg->bindex; + arg->err = 0; + au_fset_fillvdir(arg->flags, CALLED); + /* smp_mb(); */ + if (namelen <= AUFS_WH_PFX_LEN + || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { + for (bindex = 0; bindex < bend; bindex++) + if (test_known(arg->delist + bindex, name, namelen) + || au_nhash_test_known_wh(arg->whlist + bindex, + name, namelen)) + goto out; /* already exists or whiteouted */ + + ino = 1; /* why does gcc warns? */ + arg->err = au_ino(sb, bend, h_ino, d_type, &ino); + if (!arg->err) + arg->err = append_de(arg->vdir, name, namelen, ino, + d_type, arg->delist + bend); + } else { + name += AUFS_WH_PFX_LEN; + namelen -= AUFS_WH_PFX_LEN; + for (bindex = 0; bindex < bend; bindex++) + if (au_nhash_test_known_wh(arg->whlist + bend, name, + namelen)) + goto out; /* already whiteouted */ + + ino = 1; /* dummy */ + if (unlikely(au_ftest_fillvdir(arg->flags, SHWH))) + arg->err = au_wh_ino(sb, bend, h_ino, d_type, &ino); + if (!arg->err) + arg->err = au_nhash_append_wh + (arg->whlist + bend, name, namelen, ino, d_type, + bend, au_ftest_fillvdir(arg->flags, SHWH)); + } + + out: + if (!arg->err) + arg->vdir->vd_jiffy = jiffies; + /* smp_mb(); */ + AuTraceErr(arg->err); + return arg->err; +} + +static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir, + aufs_bindex_t bstart, aufs_bindex_t bend, + struct au_nhash *_whlist, struct au_nhash *_delist) +{ +#ifdef CONFIG_AUFS_SHWH + int err, i; + struct hlist_head *head; + struct au_vdir_wh *tpos; + struct hlist_node *pos, *n; + char *p, *o; + struct au_nhash *whlist, *delist; + struct au_vdir_destr *destr; + aufs_bindex_t bindex; + + AuTraceEnter(); + AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH)); + + err = -ENOMEM; + o = p = __getname(); + if (unlikely(!p)) + goto out; + + err = 0; + memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); + p += AUFS_WH_PFX_LEN; + for (bindex = bstart; !err && bindex <= bend; bindex++) { + whlist = _whlist + bindex; + delist = _delist + bindex; + + for (i = 0; i < AuSize_NHASH; i++) { + head = whlist->heads + i; + hlist_for_each_entry_safe(tpos, pos, n, head, wh_hash) { + destr = &tpos->wh_str; + memcpy(p, destr->name, destr->len); + err = append_de(vdir, o, + destr->len + AUFS_WH_PFX_LEN, + tpos->wh_ino, tpos->wh_type, + delist); + if (unlikely(err)) + break; + } + } + } + + __putname(o); + + out: + AuTraceErr(err); + return err; +#else + return 0; +#endif +} + +static int au_do_read_vdir(struct fillvdir_arg *arg) +{ + int err; + unsigned int mnt_flags; + loff_t offset; + aufs_bindex_t bend, bindex, bstart; + unsigned char dlgt, shwh; + struct super_block *sb; + struct file *hf; + + AuTraceEnter(); + + err = -ENOMEM; + bend = au_fbend(arg->file); + arg->delist = kmalloc(sizeof(*arg->delist) * (bend + 1), GFP_NOFS); + if (unlikely(!arg->delist)) + goto out; + arg->whlist = kmalloc(sizeof(*arg->whlist) * (bend + 1), GFP_NOFS); + if (unlikely(!arg->whlist)) + goto out_delist; + err = 0; + for (bindex = 0; bindex <= bend; bindex++) { + au_nhash_init(arg->delist + bindex); + au_nhash_init(arg->whlist + bindex); + } + + sb = arg->file->f_dentry->d_sb; + mnt_flags = au_mntflags(sb); + dlgt = !!au_test_dlgt(mnt_flags); + arg->flags = 0; + shwh = 0; + if (unlikely(au_opt_test(mnt_flags, SHWH))) { + shwh = 1; + au_fset_fillvdir(arg->flags, SHWH); + } + bstart = au_fbstart(arg->file); + for (bindex = bstart; !err && bindex <= bend; bindex++) { + hf = au_h_fptr(arg->file, bindex); + if (!hf) + continue; + + offset = vfsub_llseek(hf, 0, SEEK_SET); + err = offset; + if (unlikely(offset)) + break; + arg->bindex = bindex; + do { + arg->err = 0; + au_fclr_fillvdir(arg->flags, CALLED); + /* smp_mb(); */ + err = vfsub_readdir(hf, fillvdir, arg, dlgt); + if (err >= 0) + err = arg->err; + } while (!err && au_ftest_fillvdir(arg->flags, CALLED)); + } + + if (unlikely(!err && shwh)) + err = au_handle_shwh(sb, arg->vdir, bstart, bend, arg->whlist, + arg->delist); + + for (bindex = bstart; bindex <= bend; bindex++) { + free_dehlist(arg->delist + bindex); + au_nhash_fin(arg->whlist + bindex); + } + kfree(arg->whlist); + + out_delist: + kfree(arg->delist); + out: + AuTraceErr(err); + return err; +} + +static int read_vdir(struct file *file, int may_read) +{ + int err; + unsigned long expire; + struct fillvdir_arg arg; + unsigned char do_read; + struct dentry *dentry; + struct inode *inode; + struct au_vdir *vdir, *allocated; + struct super_block *sb; + + dentry = file->f_dentry; + LKTRTrace("%.*s, may %d\n", AuDLNPair(dentry), may_read); + FiMustWriteLock(file); + inode = dentry->d_inode; + IMustLock(inode); + IiMustWriteLock(inode); + AuDebugOn(!S_ISDIR(inode->i_mode)); + + err = 0; + allocated = NULL; + do_read = 0; + sb = inode->i_sb; + expire = au_sbi(sb)->si_rdcache; + vdir = au_ivdir(inode); + if (!vdir) { + AuDebugOn(au_fvdir_cache(file)); + do_read = 1; + vdir = alloc_vdir(); + err = PTR_ERR(vdir); + if (IS_ERR(vdir)) + goto out; + err = 0; + allocated = vdir; + } else if (may_read + && (inode->i_version != vdir->vd_version + || time_after(jiffies, vdir->vd_jiffy + expire))) { + LKTRTrace("iver %llu, vdver %lu, exp %lu\n", + (unsigned long long)inode->i_version, + vdir->vd_version, vdir->vd_jiffy + expire); + do_read = 1; + err = reinit_vdir(vdir); + if (unlikely(err)) + goto out; + } + + if (!do_read) + return 0; /* success */ + + arg.file = file; + arg.vdir = vdir; + err = au_do_read_vdir(&arg); + if (!err) { + /* todo: necessary? */ + /* file->f_pos = 0; */ + vdir->vd_version = inode->i_version; + vdir->vd_last.i = 0; + vdir->vd_last.p.deblk = vdir->vd_deblk[0]; + if (allocated) + au_set_ivdir(inode, allocated); + } else if (allocated) + au_vdir_free(allocated); + + out: + AuTraceErr(err); + return err; +} + +static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src) +{ + int err, i, rerr, n; + + AuTraceEnter(); + AuDebugOn(tgt->vd_nblk != 1); + + err = -ENOMEM; + if (tgt->vd_nblk < src->vd_nblk) { + au_vdir_deblk_t **p; + p = au_kzrealloc(tgt->vd_deblk, sizeof(*p) * tgt->vd_nblk, + sizeof(*p) * src->vd_nblk, GFP_NOFS); + if (unlikely(!p)) + goto out; + tgt->vd_deblk = p; + } + + tgt->vd_nblk = src->vd_nblk; + n = src->vd_nblk; + memcpy(tgt->vd_deblk[0], src->vd_deblk[0], AuSize_DEBLK); + /* tgt->vd_last.i = 0; */ + /* tgt->vd_last.p.deblk = tgt->vd_deblk[0]; */ + tgt->vd_version = src->vd_version; + tgt->vd_jiffy = src->vd_jiffy; + + for (i = 1; i < n; i++) { + tgt->vd_deblk[i] = kmalloc(AuSize_DEBLK, GFP_NOFS); + if (tgt->vd_deblk[i]) + memcpy(tgt->vd_deblk[i], src->vd_deblk[i], + AuSize_DEBLK); + else + goto out; + } + /* smp_mb(); */ + return 0; /* success */ + + out: + rerr = reinit_vdir(tgt); + BUG_ON(rerr); + AuTraceErr(err); + return err; +} + +int au_vdir_init(struct file *file) +{ + int err; + struct dentry *dentry; + struct inode *inode; + struct au_vdir *vdir_cache, *allocated; + + dentry = file->f_dentry; + LKTRTrace("%.*s, pos %lld\n", AuDLNPair(dentry), file->f_pos); + FiMustWriteLock(file); + inode = dentry->d_inode; + IiMustWriteLock(inode); + AuDebugOn(!S_ISDIR(inode->i_mode)); + + err = read_vdir(file, !file->f_pos); + if (unlikely(err)) + goto out; + + allocated = NULL; + vdir_cache = au_fvdir_cache(file); + if (!vdir_cache) { + vdir_cache = alloc_vdir(); + err = PTR_ERR(vdir_cache); + if (IS_ERR(vdir_cache)) + goto out; + allocated = vdir_cache; + } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) { + err = reinit_vdir(vdir_cache); + if (unlikely(err)) + goto out; + } else + return 0; /* success */ + + err = copy_vdir(vdir_cache, au_ivdir(inode)); + if (!err) { + file->f_version = inode->i_version; + if (allocated) + au_set_fvdir_cache(file, allocated); + } else if (allocated) + au_vdir_free(allocated); + + out: + AuTraceErr(err); + return err; +} + +static loff_t calc_offset(struct au_vdir *vdir) +{ + loff_t offset; + union au_vdir_deblk_p p; + + p.deblk = vdir->vd_deblk[vdir->vd_last.i]; + offset = vdir->vd_last.p.p - p.p; + offset += sizeof(*p.deblk) * vdir->vd_last.i; + return offset; +} + +/* returns true or false */ +static int seek_vdir(struct file *file) +{ + int valid, i, n; + struct dentry *dentry; + struct au_vdir *vdir_cache; + loff_t offset; + union au_vdir_deblk_p p, deblk_end; + + dentry = file->f_dentry; + LKTRTrace("%.*s, pos %lld\n", AuDLNPair(dentry), file->f_pos); + vdir_cache = au_fvdir_cache(file); + AuDebugOn(!vdir_cache); + + valid = 1; + offset = calc_offset(vdir_cache); + LKTRTrace("offset %lld\n", offset); + if (file->f_pos == offset) + goto out; + + vdir_cache->vd_last.i = 0; + vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0]; + if (!file->f_pos) + goto out; + + valid = 0; + i = file->f_pos / AuSize_DEBLK; + LKTRTrace("i %d\n", i); + if (i >= vdir_cache->vd_nblk) + goto out; + + n = vdir_cache->vd_nblk; + for (; i < n; i++) { + p.deblk = vdir_cache->vd_deblk[i]; + deblk_end.deblk = p.deblk + 1; + offset = i; + offset *= AuSize_DEBLK; + while (!is_deblk_end(&p, &deblk_end) && offset < file->f_pos) { + int l; + l = calc_size(p.de->de_str.len); + offset += l; + p.p += l; + } + if (!is_deblk_end(&p, &deblk_end)) { + valid = 1; + vdir_cache->vd_last.i = i; + vdir_cache->vd_last.p = p; + break; + } + } + + out: + /* smp_mb(); */ + AuTraceErr(!valid); + return valid; +} + +int au_vdir_fill_de(struct file *file, void *dirent, filldir_t filldir) +{ + int err, l; + struct dentry *dentry; + struct au_vdir *vdir_cache; + struct au_vdir_de *de; + union au_vdir_deblk_p deblk_end; + + dentry = file->f_dentry; + LKTRTrace("%.*s, pos %lld\n", AuDLNPair(dentry), file->f_pos); + vdir_cache = au_fvdir_cache(file); + AuDebugOn(!vdir_cache); + + if (!seek_vdir(file)) + return 0; + + while (1) { + deblk_end.deblk + = vdir_cache->vd_deblk[vdir_cache->vd_last.i] + 1; + while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) { + de = vdir_cache->vd_last.p.de; + LKTRTrace("%.*s, off%lld, i%lu, dt%d\n", + de->de_str.len, de->de_str.name, + file->f_pos, (unsigned long)de->de_ino, + de->de_type); + err = filldir(dirent, de->de_str.name, de->de_str.len, + file->f_pos, de->de_ino, de->de_type); + if (unlikely(err)) { + AuTraceErr(err); + /* todo: ignore the error caused by udba? */ + /* return err; */ + return 0; + } + + l = calc_size(de->de_str.len); + vdir_cache->vd_last.p.p += l; + file->f_pos += l; + } + if (vdir_cache->vd_last.i < vdir_cache->vd_nblk - 1) { + vdir_cache->vd_last.i++; + vdir_cache->vd_last.p.deblk + = vdir_cache->vd_deblk[vdir_cache->vd_last.i]; + file->f_pos = sizeof(*vdir_cache->vd_last.p.deblk) + * vdir_cache->vd_last.i; + continue; + } + break; + } + + /* smp_mb(); */ + return 0; +} --- linux-2.6.27.orig/ubuntu/aufs/module.c +++ linux-2.6.27/ubuntu/aufs/module.c @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * module global variables and operations + * + * $Id: module.c,v 1.10 2008/08/25 01:50:37 sfjro Exp $ + */ + +#include +#include "aufs.h" + +/* ---------------------------------------------------------------------- */ + +/* + * aufs caches + */ +struct kmem_cache *au_cachep[AuCache_Last]; +static int __init create_cache(void) +{ + au_cachep[AuCache_DINFO] = AuCache(au_dinfo); + if (au_cachep[AuCache_DINFO]) + au_cachep[AuCache_ICNTNR] = AuCache(aufs_icntnr); + if (au_cachep[AuCache_ICNTNR]) + au_cachep[AuCache_FINFO] = AuCache(au_finfo); + if (au_cachep[AuCache_FINFO]) + au_cachep[AuCache_VDIR] = AuCache(au_vdir); + if (au_cachep[AuCache_VDIR]) + au_cachep[AuCache_DEHSTR] = AuCache(au_vdir_dehstr); + if (au_cachep[AuCache_DEHSTR]) + return 0; + + return -ENOMEM; +} + +static void destroy_cache(void) +{ + int i; + for (i = 0; i < AuCache_Last; i++) + if (au_cachep[i]) { + kmem_cache_destroy(au_cachep[i]); + au_cachep[i] = NULL; + } +} + +/* ---------------------------------------------------------------------- */ + +char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */ +int au_dir_roflags; + +/* + * functions for module interface. + */ +MODULE_LICENSE("GPL"); +/* MODULE_LICENSE("GPL v2"); */ +MODULE_AUTHOR("Junjiro Okajima"); +MODULE_DESCRIPTION(AUFS_NAME " -- Another unionfs"); +MODULE_VERSION(AUFS_VERSION); + +/* it should be 'byte', but param_set_byte() prints it by "%c" */ +short aufs_nwkq = AUFS_NWKQ_DEF; +MODULE_PARM_DESC(nwkq, "the number of workqueue thread, " AUFS_WKQ_NAME); +module_param_named(nwkq, aufs_nwkq, short, S_IRUGO); + +int sysaufs_brs; +MODULE_PARM_DESC(brs, "use /fs/aufs/si_*/brN"); +module_param_named(brs, sysaufs_brs, int, S_IRUGO); + +/* ---------------------------------------------------------------------- */ + +static int __init aufs_init(void) +{ + int err, i; + char *p; + + au_debug_init(); +#ifdef CONFIG_AUFS_INO_T_64 + BUILD_BUG_ON(sizeof(ino_t) != sizeof(long long)); +#else + BUILD_BUG_ON(sizeof(ino_t) != sizeof(int)); +#endif + + p = au_esc_chars; + for (i = 1; i <= ' '; i++) + *p++ = i; + *p++ = '\\'; + *p++ = '\x7f'; + *p = 0; + + au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE); + + err = -EINVAL; + if (unlikely(aufs_nwkq <= 0)) + goto out; + + err = sysaufs_init(); + if (unlikely(err)) + goto out; + err = au_wkq_init(); + if (unlikely(err)) + goto out_sysaufs; + err = au_inotify_init(); + if (unlikely(err)) + goto out_wkq; + err = au_sysrq_init(); + if (unlikely(err)) + goto out_inotify; + + err = create_cache(); + if (unlikely(err)) + goto out_sysrq; + + err = register_filesystem(&aufs_fs_type); + if (unlikely(err)) + goto out_cache; + pr_info(AUFS_NAME " " AUFS_VERSION "\n"); + return 0; /* success */ + + out_cache: + destroy_cache(); + out_sysrq: + au_sysrq_fin(); + out_inotify: + au_inotify_fin(); + out_wkq: + au_wkq_fin(); + out_sysaufs: + sysaufs_fin(); + out: + AuTraceErr(err); + return err; +} + +static void __exit aufs_exit(void) +{ + unregister_filesystem(&aufs_fs_type); + destroy_cache(); + + au_sysrq_fin(); + au_inotify_fin(); + au_wkq_fin(); + sysaufs_fin(); +} + +module_init(aufs_init); +module_exit(aufs_exit); + +/* ---------------------------------------------------------------------- */ + +/* fake Kconfig */ +#if 1 + +#ifdef CONFIG_AUFS_HINOTIFY +#ifndef CONFIG_INOTIFY +#error enable CONFIG_INOTIFY to use CONFIG_AUFS_HINOTIFY. +#endif +#endif /* CONFIG_AUFS_HINOTIFY */ + +#if AUFS_BRANCH_MAX > 511 && PAGE_SIZE > 4096 +#warning pagesize is larger than 4kb, \ + CONFIG_AUFS_BRANCH_MAX_511 or smaller is recommended. +#endif + +#ifdef CONFIG_AUFS_STAT +#ifndef CONFIG_SYSFS +#error CONFIG_AUFS_STAT requires CONFIG_SYSFS. +#endif +#endif /* CONFIG_AUFS_STAT */ + +#ifdef CONFIG_AUFS_SYSAUFS +#warning CONFIG_AUFS_SYSAUFS is unnecessary for linux-2.6.25 and later. +#endif + +#ifdef CONFIG_AUFS_EXPORT +#if !defined(CONFIG_EXPORTFS) && !defined(CONFIG_EXPORTFS_MODULE) +#error CONFIG_AUFS_EXPORT requires CONFIG_EXPORTFS +#endif +#if defined(CONFIG_EXPORTFS_MODULE) && defined(CONFIG_AUFS) +#error need CONFIG_EXPORTFS = y to link aufs statically with CONFIG_AUFS_EXPORT +#endif +#endif /* CONFIG_AUFS_EXPORT */ + +#ifdef CONFIG_AUFS_SEC_PERM_PATCH +#ifndef CONFIG_SECURITY +#warning CONFIG_AUFS_SEC_PERM_PATCH is unnecessary since CONFIG_SECURITY is disabled. +#endif +#ifdef CONFIG_AUFS +#warning CONFIG_AUFS_SEC_PERM_PATCH is unnecessary since CONFIG_AUFS is not a module. +#endif +#endif + +#ifdef CONFIG_AUFS_PUT_FILP_PATCH +#if !defined(CONFIG_NFS_FS) && !defined(CONFIG_NFS_FS_MODULE) +#warning CONFIG_AUFS_PUT_FILP_PATCH is unnecessary since CONFIG_NFS_FS is disabled. +#endif +#ifdef CONFIG_AUFS +#warning CONFIG_AUFS_PUT_FILP_PATCH is unnecessary since CONFIG_AUFS is not a module. +#endif +#endif /* CONFIG_AUFS_PUT_FILP_PATCH */ + +#ifdef CONFIG_AUFS_LHASH_PATCH +#if !defined(CONFIG_NFS_FS) && !defined(CONFIG_NFS_FS_MODULE) +#warning CONFIG_AUFS_LHASH_PATCH is unnecessary since CONFIG_NFS_FS is disabled. +#endif +#endif + +#ifdef CONFIG_AUFS_KSIZE_PATCH +#warning CONFIG_AUFS_KSIZE_PATCH is unnecessary for linux-2.6.22 and later. +#endif + +#ifdef CONFIG_AUFS_WORKAROUND_FUSE +#if !defined(CONFIG_FUSE_FS) && !defined(CONFIG_FUSE_FS_MODULE) +#warning CONFIG_AUFS_WORKAROUND_FUSE is enabled while FUSE is disabled. +#endif +#endif + +#ifdef CONFIG_DEBUG_PROVE_LOCKING +#if MAX_LOCKDEP_SUBCLASSES < AuLsc_I_End +#warning lockdep will not work since aufs uses deeper locks. +#endif +#endif + +#ifdef CONFIG_AUFS_COMPAT +#warning CONFIG_AUFS_COMPAT will be removed in the near future. +#endif + +#if defined(CONFIG_AUFS_UNIONFS23_PATCH) \ + && !defined(CONFIG_AUFS_UNIONFS22_PATCH) +#error mis-configuration. CONFIG_AUFS_UNIONFS23_PATCH is enabled but CONFIG_AUFS_UNIONFS22_PATCH. +#endif + +#endif --- linux-2.6.27.orig/ubuntu/aufs/super.c +++ linux-2.6.27/ubuntu/aufs/super.c @@ -0,0 +1,863 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * mount and super_block operations + * + * $Id: super.c,v 1.16 2008/09/15 03:14:49 sfjro Exp $ + */ + +#include +#include +#include +#include +#include + +#include "aufs.h" + +/* + * super_operations + */ +static struct inode *aufs_alloc_inode(struct super_block *sb) +{ + struct aufs_icntnr *c; + + AuTraceEnter(); + + c = au_cache_alloc_icntnr(); + if (c) { + inode_init_once(&c->vfs_inode); + c->vfs_inode.i_version = 1; /* sigen(sb); */ + c->iinfo.ii_hinode = NULL; + return &c->vfs_inode; + } + return NULL; +} + +static void aufs_destroy_inode(struct inode *inode) +{ + int err; + + LKTRTrace("i%lu\n", inode->i_ino); + + if (!inode->i_nlink) { + struct super_block *sb = inode->i_sb; + int locked; + + /* in nowait task, sbi is write-locked */ + /* todo: test kernel thread */ + locked = si_noflush_read_trylock(sb); + err = au_xigen_inc(inode); + if (unlikely(err)) + AuWarn1("failed resetting i_generation, %d\n", err); + if (locked) + si_read_unlock(sb); + } + + au_iinfo_fin(inode); + au_cache_free_icntnr(container_of(inode, struct aufs_icntnr, + vfs_inode)); +} + +struct inode *au_iget_locked(struct super_block *sb, ino_t ino) +{ + struct inode *inode; + int err; + + LKTRTrace("i%lu\n", (unsigned long)ino); + + inode = iget_locked(sb, ino); + if (unlikely(!inode)) { + inode = ERR_PTR(-ENOMEM); + goto out; + } + AuDebugOn(IS_ERR(inode)); + if (unlikely(!(inode->i_state & I_NEW))) + goto out; + + err = au_xigen_new(inode); + if (!err) + err = au_iinfo_init(inode); + if (!err) + inode->i_version++; + else { + iget_failed(inode); + inode = ERR_PTR(err); + } + + out: + /* never return NULL */ + AuDebugOn(!inode); + AuTraceErrPtr(inode); + return inode; +} + +static int au_show_brs(struct seq_file *seq, struct super_block *sb) +{ + int err; + aufs_bindex_t bindex, bend; + struct dentry *root; + struct path path; + + AuTraceEnter(); + + err = 0; + root = sb->s_root; + bend = au_sbend(sb); + for (bindex = 0; !err && bindex <= bend; bindex++) { + path.mnt = au_sbr_mnt(sb, bindex); + path.dentry = au_h_dptr(root, bindex); + err = seq_path(seq, &path, au_esc_chars); + if (err > 0) + err = seq_printf + (seq, "=%s", + au_optstr_br_perm(au_sbr_perm(sb, bindex))); + if (!err && bindex != bend) + err = seq_putc(seq, ':'); + } + + AuTraceErr(err); + return err; +} + +static void au_show_wbr_create(struct seq_file *m, int v, + struct au_sbinfo *sbinfo) +{ + const char *pat; + + AuDebugOn(v == AuWbrCreate_Def); + + seq_printf(m, ",create="); + pat = au_optstr_wbr_create(v); + switch (v) { + case AuWbrCreate_TDP: + case AuWbrCreate_RR: + case AuWbrCreate_MFS: + case AuWbrCreate_PMFS: + seq_printf(m, pat); + break; + case AuWbrCreate_MFSV: + seq_printf(m, /*pat*/"mfs:%lu", + sbinfo->si_wbr_mfs.mfs_expire / HZ); + break; + case AuWbrCreate_PMFSV: + seq_printf(m, /*pat*/"pmfs:%lu", + sbinfo->si_wbr_mfs.mfs_expire / HZ); + break; + case AuWbrCreate_MFSRR: + seq_printf(m, /*pat*/"mfsrr:%llu", + sbinfo->si_wbr_mfs.mfsrr_watermark); + break; + case AuWbrCreate_MFSRRV: + seq_printf(m, /*pat*/"mfsrr:%llu:%lu", + sbinfo->si_wbr_mfs.mfsrr_watermark, + sbinfo->si_wbr_mfs.mfs_expire / HZ); + break; + } +} + +/* seq_file will re-call me in case of too long string */ +static int aufs_show_options(struct seq_file *m, struct vfsmount *mnt) +{ + int err, n; + struct super_block *sb; + struct au_sbinfo *sbinfo; + struct dentry *root; + struct file *xino; + unsigned int mnt_flags, v; + struct path path; + + AuTraceEnter(); + + sb = mnt->mnt_sb; + root = sb->s_root; + if (!sysaufs_brs) + aufs_read_lock(root, !AuLock_IR); + else + si_noflush_read_lock(sb); + sbinfo = au_sbi(sb); + seq_printf(m, ",si=%lx", au_si_mask ^ (unsigned long)sbinfo); + mnt_flags = au_mntflags(sb); + if (au_opt_test(mnt_flags, XINO)) { + seq_puts(m, ",xino="); + xino = sbinfo->si_xib; + path.mnt = xino->f_vfsmnt; + path.dentry = xino->f_dentry; + err = seq_path(m, &path, au_esc_chars); + if (unlikely(err <= 0)) + goto out; + err = 0; +#define Deleted "\\040(deleted)" + m->count -= sizeof(Deleted) - 1; + AuDebugOn(memcmp(m->buf + m->count, Deleted, + sizeof(Deleted) - 1)); +#undef Deleted +#ifdef CONFIG_AUFS_EXPORT /* reserved for future use */ + } else if (au_opt_test(mnt_flags, XINODIR)) { + seq_puts(m, ",xinodir="); + seq_path(m, &sbinfo->si_xinodir, au_esc_chars); +#endif + } else + seq_puts(m, ",noxino"); + +#define AuBool(name, str) do { \ + v = au_opt_test(mnt_flags, name); \ + if (v != au_opt_test(AuOpt_Def, name)) \ + seq_printf(m, ",%s" #str, v ? "" : "no"); \ +} while (0) + +#define AuStr(name, str) do { \ + v = mnt_flags & AuOptMask_##name; \ + if (v != (AuOpt_Def & AuOptMask_##name)) \ + seq_printf(m, "," #str "=%s", au_optstr_##str(v)); \ +} while (0) + +#ifdef CONFIG_AUFS_COMPAT +#define AuStr_BrOpt "dirs=" +#else +#define AuStr_BrOpt "br:" +#endif + + AuBool(TRUNC_XINO, trunc_xino); + AuBool(DIRPERM1, dirperm1); + AuBool(SHWH, shwh); + AuBool(PLINK, plink); + AuStr(UDBA, udba); + + v = sbinfo->si_wbr_create; + if (v != AuWbrCreate_Def) + au_show_wbr_create(m, v, sbinfo); + + v = sbinfo->si_wbr_copyup; + if (v != AuWbrCopyup_Def) + seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v)); + + v = au_opt_test(mnt_flags, ALWAYS_DIROPQ); + if (v != au_opt_test(AuOpt_Def, ALWAYS_DIROPQ)) + seq_printf(m, ",diropq=%c", v ? 'a' : 'w'); + AuBool(REFROF, refrof); + AuBool(DLGT, dlgt); + AuBool(WARN_PERM, warn_perm); + AuBool(VERBOSE, verbose); + + n = sbinfo->si_dirwh; + if (n != AUFS_DIRWH_DEF) + seq_printf(m, ",dirwh=%d", n); + n = sbinfo->si_rdcache / HZ; + if (n != AUFS_RDCACHE_DEF) + seq_printf(m, ",rdcache=%d", n); + + AuStr(COO, coo); + + out: + if (!sysaufs_brs) { + seq_puts(m, "," AuStr_BrOpt); + au_show_brs(m, sb); + aufs_read_unlock(root, !AuLock_IR); + } else + si_read_unlock(sb); + return 0; + +#undef AuBool +#undef AuStr +#undef AuStr_BrOpt +} + +/* todo: in case of round-robin policy, return the sum of all rw branches? */ +static int aufs_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + int err; + + AuTraceEnter(); + + aufs_read_lock(dentry->d_sb->s_root, 0); + err = vfsub_statfs(au_h_dptr(dentry->d_sb->s_root, 0), buf, + !!au_test_dlgt(au_mntflags(dentry->d_sb))); + aufs_read_unlock(dentry->d_sb->s_root, 0); + if (!err) { + buf->f_type = AUFS_SUPER_MAGIC; + buf->f_namelen -= AUFS_WH_PFX_LEN; + memset(&buf->f_fsid, 0, sizeof(buf->f_fsid)); + } + /* buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; */ + + AuTraceErr(err); + return err; +} + +static void au_fsync_br(struct super_block *sb) +{ +#ifdef CONFIG_AUFS_FSYNC_SUPER_PATCH + aufs_bindex_t bend, bindex; + int brperm; + struct super_block *h_sb; + + AuTraceEnter(); + + si_write_lock(sb); + bend = au_sbend(sb); + for (bindex = 0; bindex < bend; bindex++) { + brperm = au_sbr_perm(sb, bindex); + if (brperm == AuBrPerm_RR || brperm == AuBrPerm_RRWH) + continue; + h_sb = au_sbr_sb(sb, bindex); + if (bdev_read_only(h_sb->s_bdev)) + continue; + + lockdep_off(); + down_write(&h_sb->s_umount); + shrink_dcache_sb(h_sb); + fsync_super(h_sb); + up_write(&h_sb->s_umount); + lockdep_on(); + } + si_write_unlock(sb); +#endif +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) +/* this IS NOT for super_operations */ +static void aufs_umount_begin(struct super_block *arg) +#define AuUmountBeginSb(arg) (arg) +#else +/* this IS for super_operations */ +static void aufs_umount_begin(struct vfsmount *arg, int flags) +#define AuUmountBeginSb(arg) (arg)->mnt_sb +#endif +{ + struct super_block *sb = AuUmountBeginSb(arg); + struct au_sbinfo *sbinfo; + + AuTraceEnter(); + /* dont trust BKL */ + AuDebugOn(!kernel_locked()); + + sbinfo = au_sbi(sb); + if (unlikely(!sbinfo)) + return; + + au_fsync_br(sb); + + si_write_lock(sb); + if (au_opt_test(au_mntflags(sb), PLINK)) + au_plink_put(sb); + au_mnt_reset(sbinfo); +#if 0 /* reserved for future use */ + if (sbinfo->si_wbr_create_ops->fin) + sbinfo->si_wbr_create_ops->fin(sb); +#endif + si_write_unlock(sb); +} + +/* final actions when unmounting a file system */ +static void aufs_put_super(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + + AuTraceEnter(); + + sbinfo = au_sbi(sb); + if (unlikely(!sbinfo)) + return; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) + aufs_umount_begin(sb); +#endif + kobject_put(&sbinfo->si_kobj); +} + +/* ---------------------------------------------------------------------- */ + +/* + * refresh dentry and inode at remount time. + */ +static int do_refresh(struct dentry *dentry, mode_t type, + unsigned int dir_flags) +{ + int err; + struct dentry *parent; + struct inode *inode; + + LKTRTrace("%.*s, 0%o\n", AuDLNPair(dentry), type); + inode = dentry->d_inode; + AuDebugOn(!inode); + + di_write_lock_child(dentry); + parent = dget_parent(dentry); + di_read_lock_parent(parent, AuLock_IR); + /* returns a number of positive dentries */ + err = au_refresh_hdentry(dentry, type); + if (err >= 0) { + err = au_refresh_hinode(inode, dentry); + if (!err && type == S_IFDIR) + au_reset_hinotify(inode, dir_flags); + } + if (unlikely(err)) + AuErr("unrecoverable error %d, %.*s\n", err, AuDLNPair(dentry)); + di_read_unlock(parent, AuLock_IR); + dput(parent); + di_write_unlock(dentry); + + AuTraceErr(err); + return err; +} + +static int test_dir(struct dentry *dentry, void *arg) +{ + return S_ISDIR(dentry->d_inode->i_mode); +} + +/* todo: merge with refresh_nondir()? */ +static int refresh_dir(struct dentry *root, au_gen_t sgen) +{ + int err, i, j, ndentry, e; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + struct dentry **dentries; + struct inode *inode; + const unsigned int flags = au_hi_flags(root->d_inode, /*isdir*/1); + + LKTRTrace("sgen %d\n", sgen); + SiMustWriteLock(root->d_sb); + /* dont trust BKL */ + AuDebugOn(au_digen(root) != sgen || !kernel_locked()); + + err = 0; + list_for_each_entry(inode, &root->d_sb->s_inodes, i_sb_list) + if (S_ISDIR(inode->i_mode) && au_iigen(inode) != sgen) { + ii_write_lock_child(inode); + e = au_refresh_hinode_self(inode); + ii_write_unlock(inode); + if (unlikely(e)) { + LKTRTrace("e %d, i%lu\n", e, inode->i_ino); + if (!err) + err = e; + /* go on even if err */ + } + } + + e = au_dpages_init(&dpages, GFP_NOFS); + if (unlikely(e)) { + if (!err) + err = e; + goto out; + } + e = au_dcsub_pages(&dpages, root, test_dir, NULL); + if (unlikely(e)) { + if (!err) + err = e; + goto out_dpages; + } + + for (i = 0; !e && i < dpages.ndpage; i++) { + dpage = dpages.dpages + i; + dentries = dpage->dentries; + ndentry = dpage->ndentry; + for (j = 0; !e && j < ndentry; j++) { + struct dentry *d; + d = dentries[j]; +#ifdef CONFIG_AUFS_DEBUG + { + struct dentry *parent; + parent = dget_parent(d); + AuDebugOn(!S_ISDIR(d->d_inode->i_mode) + || IS_ROOT(d) + || au_digen(parent) != sgen); + dput(parent); + } +#endif + if (au_digen(d) != sgen) { + e = do_refresh(d, S_IFDIR, flags); + if (unlikely(e && !err)) + err = e; + /* break on err */ + } + } + } + + out_dpages: + au_dpages_free(&dpages); + out: + AuTraceErr(err); + return err; +} + +static int test_nondir(struct dentry *dentry, void *arg) +{ + return !S_ISDIR(dentry->d_inode->i_mode); +} + +static int refresh_nondir(struct dentry *root, au_gen_t sgen, int do_dentry) +{ + int err, i, j, ndentry, e; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + struct dentry **dentries; + struct inode *inode; + + LKTRTrace("sgen %d\n", sgen); + SiMustWriteLock(root->d_sb); + /* dont trust BKL */ + AuDebugOn(au_digen(root) != sgen || !kernel_locked()); + + err = 0; + list_for_each_entry(inode, &root->d_sb->s_inodes, i_sb_list) + if (!S_ISDIR(inode->i_mode) && au_iigen(inode) != sgen) { + ii_write_lock_child(inode); + e = au_refresh_hinode_self(inode); + ii_write_unlock(inode); + if (unlikely(e)) { + LKTRTrace("e %d, i%lu\n", e, inode->i_ino); + if (!err) + err = e; + /* go on even if err */ + } + } + + if (!do_dentry) + goto out; + + e = au_dpages_init(&dpages, GFP_NOFS); + if (unlikely(e)) { + if (!err) + err = e; + goto out; + } + e = au_dcsub_pages(&dpages, root, test_nondir, NULL); + if (unlikely(e)) { + if (!err) + err = e; + goto out_dpages; + } + + for (i = 0; i < dpages.ndpage; i++) { + dpage = dpages.dpages + i; + dentries = dpage->dentries; + ndentry = dpage->ndentry; + for (j = 0; j < ndentry; j++) { + struct dentry *d; + d = dentries[j]; +#ifdef CONFIG_AUFS_DEBUG + { + struct dentry *parent; + parent = dget_parent(d); + AuDebugOn(S_ISDIR(d->d_inode->i_mode) + || au_digen(parent) != sgen); + dput(parent); + } +#endif + inode = d->d_inode; + if (inode && au_digen(d) != sgen) { + e = do_refresh(d, inode->i_mode & S_IFMT, 0); + if (unlikely(e && !err)) + err = e; + /* go on even err */ + } + } + } + + out_dpages: + au_dpages_free(&dpages); + out: + AuTraceErr(err); + return err; +} + +/* stop extra interpretation of errno in mount(8), and strange error messages */ +static int cvt_err(int err) +{ + AuTraceErr(err); + + switch (err) { + case -ENOENT: + case -ENOTDIR: + case -EEXIST: + case -EIO: + err = -EINVAL; + } + return err; +} + +/* protected by s_umount */ +static int aufs_remount_fs(struct super_block *sb, int *flags, char *data) +{ + int err, rerr; + au_gen_t sigen; + struct dentry *root; + struct inode *inode; + struct au_opts opts; + struct au_sbinfo *sbinfo; + unsigned char dlgt; + + LKTRTrace("flags 0x%x, data %s, len %lu\n", + *flags, data ? data : "NULL", + (unsigned long)(data ? strlen(data) : 0)); + + au_fsync_br(sb); + + err = 0; + if (!data || !*data) + goto out; /* success */ + + err = -ENOMEM; + memset(&opts, 0, sizeof(opts)); + opts.opt = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!opts.opt)) + goto out; + opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); + opts.flags = AuOpts_REMOUNT; + + /* parse it before aufs lock */ + err = au_opts_parse(sb, *flags, data, &opts); + if (unlikely(err)) + goto out_opts; + + sbinfo = au_sbi(sb); + root = sb->s_root; + inode = root->d_inode; + mutex_lock(&inode->i_mutex); + aufs_write_lock(root); + + /* au_do_opts() may return an error */ + err = au_opts_remount(sb, &opts); + au_opts_free(&opts); + + if (au_ftest_opts(opts.flags, REFRESH_DIR) + || au_ftest_opts(opts.flags, REFRESH_NONDIR)) { + dlgt = !!au_opt_test(sbinfo->si_mntflags, DLGT); + au_opt_clr(sbinfo->si_mntflags, DLGT); + au_sigen_inc(sb); + au_reset_hinotify(inode, au_hi_flags(inode, /*isdir*/1)); + sigen = au_sigen(sb); + au_fclr_si(sbinfo, FAILED_REFRESH_DIRS); + + DiMustNoWaiters(root); + IiMustNoWaiters(root->d_inode); + di_write_unlock(root); + + rerr = refresh_dir(root, sigen); + if (unlikely(rerr)) { + au_fset_si(sbinfo, FAILED_REFRESH_DIRS); + AuWarn("Refreshing directories failed, ignores (%d)\n", + rerr); + } + + if (unlikely(au_ftest_opts(opts.flags, REFRESH_NONDIR))) { + rerr = refresh_nondir(root, sigen, !rerr); + if (unlikely(rerr)) + AuWarn("Refreshing non-directories failed," + " ignores (%d)\n", rerr); + } + + /* aufs_write_lock() calls ..._child() */ + di_write_lock_child(root); + + au_cpup_attr_all(inode); + if (unlikely(dlgt)) + au_opt_set(sbinfo->si_mntflags, DLGT); + } + + aufs_write_unlock(root); + mutex_unlock(&inode->i_mutex); + + out_opts: + free_page((unsigned long)opts.opt); + out: + err = cvt_err(err); + AuTraceErr(err); + return err; +} + +static struct super_operations aufs_sop = { + .alloc_inode = aufs_alloc_inode, + .destroy_inode = aufs_destroy_inode, + .drop_inode = generic_delete_inode, + + .show_options = aufs_show_options, + .statfs = aufs_statfs, + + .put_super = aufs_put_super, + .remount_fs = aufs_remount_fs, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) + .umount_begin = aufs_umount_begin +#endif +}; + +/* ---------------------------------------------------------------------- */ + +static int alloc_root(struct super_block *sb) +{ + int err; + struct inode *inode; + struct dentry *root; + + AuTraceEnter(); + + err = -ENOMEM; + inode = au_iget_locked(sb, AUFS_ROOT_INO); + err = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out; + inode->i_op = &aufs_dir_iop; + inode->i_fop = &aufs_dir_fop; + inode->i_mode = S_IFDIR; + unlock_new_inode(inode); + root = d_alloc_root(inode); + if (unlikely(!root)) + goto out_iput; + err = PTR_ERR(root); + if (IS_ERR(root)) + goto out_iput; + + err = au_alloc_dinfo(root); + if (!err) { + sb->s_root = root; + return 0; /* success */ + } + dput(root); + goto out; /* do not iput */ + + out_iput: + iget_failed(inode); + iput(inode); + out: + AuTraceErr(err); + return err; + +} + +static int aufs_fill_super(struct super_block *sb, void *raw_data, int silent) +{ + int err; + struct dentry *root; + struct inode *inode; + struct au_opts opts; + char *arg = raw_data; + + if (unlikely(!arg || !*arg)) { + err = -EINVAL; + AuErr("no arg\n"); + goto out; + } + LKTRTrace("%s, silent %d\n", arg, silent); + + err = -ENOMEM; + memset(&opts, 0, sizeof(opts)); + opts.opt = (void *)__get_free_page(GFP_NOFS); + if (unlikely(!opts.opt)) + goto out; + opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); + + err = au_si_alloc(sb); + if (unlikely(err)) + goto out_opts; + SiMustWriteLock(sb); + /* all timestamps always follow the ones on the branch */ + sb->s_flags |= MS_NOATIME | MS_NODIRATIME; + sb->s_op = &aufs_sop; + sb->s_magic = AUFS_SUPER_MAGIC; + au_export_init(sb); + + err = alloc_root(sb); + if (unlikely(err)) { + AuDebugOn(sb->s_root); + si_write_unlock(sb); + goto out_info; + } + root = sb->s_root; + DiMustWriteLock(root); + inode = root->d_inode; + inode->i_nlink = 2; + + /* + * actually we can parse options regardless aufs lock here. + * but at remount time, parsing must be done before aufs lock. + * so we follow the same rule. + */ + ii_write_lock_parent(inode); + aufs_write_unlock(root); + err = au_opts_parse(sb, sb->s_flags, arg, &opts); + if (unlikely(err)) + goto out_root; + + /* lock vfs_inode first, then aufs. */ + mutex_lock(&inode->i_mutex); + inode->i_op = &aufs_dir_iop; + inode->i_fop = &aufs_dir_fop; + aufs_write_lock(root); + + sb->s_maxbytes = 0; + err = au_opts_mount(sb, &opts); + au_opts_free(&opts); + if (unlikely(err)) + goto out_unlock; + AuDebugOn(!sb->s_maxbytes); + + aufs_write_unlock(root); + mutex_unlock(&inode->i_mutex); + goto out_opts; /* success */ + + out_unlock: + aufs_write_unlock(root); + mutex_unlock(&inode->i_mutex); + out_root: + dput(root); + sb->s_root = NULL; + out_info: + kobject_put(&au_sbi(sb)->si_kobj); + sb->s_fs_info = NULL; + out_opts: + free_page((unsigned long)opts.opt); + out: + AuTraceErr(err); + err = cvt_err(err); + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int aufs_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *raw_data, + struct vfsmount *mnt) +{ + int err; + struct super_block *sb; + + /* all timestamps always follow the ones on the branch */ + /* mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; */ + err = get_sb_nodev(fs_type, flags, raw_data, aufs_fill_super, mnt); + if (!err) { + sb = mnt->mnt_sb; + au_mnt_init(au_sbi(sb), mnt); + si_write_lock(sb); + sysaufs_brs_add(sb, 0); + si_write_unlock(sb); + } + return err; +} + +struct file_system_type aufs_fs_type = { + .name = AUFS_FSTYPE, + .fs_flags = + FS_RENAME_DOES_D_MOVE /* a race between rename and others*/ + | FS_REVAL_DOT, /* for NFS branch */ + .get_sb = aufs_get_sb, + .kill_sb = generic_shutdown_super, + /* no need to __module_get() and module_put(). */ + .owner = THIS_MODULE, +}; --- linux-2.6.27.orig/ubuntu/aufs/robr.c +++ linux-2.6.27/ubuntu/aufs/robr.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * 'robr', aufs as readonly branch of another aufs + * + * $Id: robr.c,v 1.6 2008/07/21 02:53:51 sfjro Exp $ + */ + +#include "aufs.h" + +/* ---------------------------------------------------------------------- */ + +int au_test_robr_wh(struct qstr *name, struct dentry *h_parent, + struct qstr *wh_name, int try_sio, struct au_ndx *ndx) +{ + if (strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) + return au_wh_test(h_parent, wh_name, try_sio, ndx); + return -EPERM; +} + +int au_test_robr_shwh(struct super_block *sb, const struct qstr *name) +{ + return 0; +} + +/* ---------------------------------------------------------------------- */ + +struct au_robr_lvma { + struct list_head list; + struct vm_area_struct *vma; +}; + +struct file *au_robr_safe_file(struct vm_area_struct *vma) +{ + struct file *file = vma->vm_file; + struct super_block *sb = file->f_dentry->d_sb; + struct au_robr_lvma *lvma, *entry; + struct au_sbinfo *sbinfo; + unsigned char found, warn; + + AuTraceEnter(); + AuDebugOn(!au_test_aufs(sb)); + + warn = 0; + found = 0; + sbinfo = au_sbi(sb); + spin_lock(&sbinfo->si_lvma_lock); + list_for_each_entry(entry, &sbinfo->si_lvma, list) { + found = (entry->vma == vma); + if (unlikely(found)) + break; + } + if (!found) { + lvma = kmalloc(sizeof(*lvma), GFP_ATOMIC); + if (lvma) { + lvma->vma = vma; + list_add(&lvma->list, &sbinfo->si_lvma); + } else { + warn = 1; + file = NULL; + } + } else + file = NULL; + spin_unlock(&sbinfo->si_lvma_lock); + + if (unlikely(warn)) + AuWarn1("no memory for lvma\n"); + return file; +} + +void au_robr_reset_file(struct vm_area_struct *vma, struct file *file) +{ + struct super_block *sb = file->f_dentry->d_sb; + struct au_robr_lvma *entry, *found; + struct au_sbinfo *sbinfo; + + AuTraceEnter(); + AuDebugOn(!au_test_aufs(sb)); + + vma->vm_file = file; + /* smp_mb(); */ /* flush vm_file */ + + found = NULL; + sbinfo = au_sbi(sb); + spin_lock(&sbinfo->si_lvma_lock); + list_for_each_entry(entry, &sbinfo->si_lvma, list) + if (entry->vma == vma) { + found = entry; + break; + } + AuDebugOn(!found); + list_del(&found->list); + spin_unlock(&sbinfo->si_lvma_lock); + kfree(found); +} --- linux-2.6.27.orig/ubuntu/aufs/dcsub.h +++ linux-2.6.27/ubuntu/aufs/dcsub.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * sub-routines for dentry cache + * + * $Id: dcsub.h,v 1.4 2008/07/21 02:54:22 sfjro Exp $ + */ + +#ifndef __AUFS_DCSUB_H__ +#define __AUFS_DCSUB_H__ + +#ifdef __KERNEL__ + +#include + +struct au_dpage { + int ndentry; + struct dentry **dentries; +}; + +struct au_dcsub_pages { + int ndpage; + struct au_dpage *dpages; +}; + +/* ---------------------------------------------------------------------- */ + +int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp); +void au_dpages_free(struct au_dcsub_pages *dpages); +typedef int (*au_dpages_test)(struct dentry *dentry, void *arg); +int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, + au_dpages_test test, void *arg); +int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, + int do_include, au_dpages_test test, void *arg); +struct dentry *au_test_subdir(struct dentry *d1, struct dentry *d2); + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DCSUB_H__ */ --- linux-2.6.27.orig/ubuntu/aufs/sbinfo.c +++ linux-2.6.27/ubuntu/aufs/sbinfo.c @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * superblock private data + * + * $Id: sbinfo.c,v 1.11 2008/07/27 22:49:36 sfjro Exp $ + */ + +#include +#include "aufs.h" + +/* + * they are necessary regardless sysfs is disabled. + */ +void au_si_free(struct kobject *kobj) +{ + struct au_sbinfo *sbinfo; + struct super_block *sb; + + LKTRTrace("kobj %p\n", kobj); + sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); + LKTRTrace("sbinfo %p\n", sbinfo); + AuDebugOn(!list_empty(&sbinfo->si_plink)); + + sb = sbinfo->si_sb; + si_write_lock(sb); + au_xino_clr(sb); + au_br_free(sbinfo); + kfree(sbinfo->si_branch); + au_export_put(sbinfo); + si_write_unlock(sb); + + kfree(sbinfo); +} + +int au_si_alloc(struct super_block *sb) +{ + int err; + struct au_sbinfo *sbinfo; + + AuTraceEnter(); + + err = -ENOMEM; + sbinfo = kmalloc(sizeof(*sbinfo), GFP_NOFS); + if (unlikely(!sbinfo)) + goto out; + sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS); + if (unlikely(!sbinfo->si_branch)) + goto out_sbinfo; + + memset(&sbinfo->si_kobj, 0, sizeof(sbinfo->si_kobj)); + err = sysaufs_si_init(sbinfo); + if (unlikely(err)) + goto out_br; + + au_rw_init_wlock(&sbinfo->si_rwsem); + sbinfo->si_generation = 0; + sbinfo->au_si_status = 0; + sbinfo->si_bend = -1; + sbinfo->si_last_br_id = 0; + + sbinfo->si_wbr_copyup = AuWbrCopyup_Def; + sbinfo->si_wbr_create = AuWbrCreate_Def; + sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + AuWbrCopyup_Def; + sbinfo->si_wbr_create_ops = au_wbr_create_ops + AuWbrCreate_Def; + + sbinfo->si_mntflags = AuOpt_Def; + + sbinfo->si_xread = NULL; + sbinfo->si_xwrite = NULL; + sbinfo->si_xib = NULL; + mutex_init(&sbinfo->si_xib_mtx); + sbinfo->si_xib_buf = NULL; + au_xino_def_br_set(NULL, sbinfo); + /* leave si_xib_last_pindex and si_xib_next_bit */ + + au_nwt_init(&sbinfo->si_nowait); + + sbinfo->si_rdcache = AUFS_RDCACHE_DEF * HZ; + sbinfo->si_dirwh = AUFS_DIRWH_DEF; + + spin_lock_init(&sbinfo->si_plink_lock); + INIT_LIST_HEAD(&sbinfo->si_plink); + + au_robr_lvma_init(sbinfo); + + /* leave other members for sysaufs and si_mnt. */ + sbinfo->si_sb = sb; + + sb->s_fs_info = sbinfo; + + au_debug_sbinfo_init(sbinfo); + return 0; /* success */ + + out_br: + kfree(sbinfo->si_branch); + out_sbinfo: + kfree(sbinfo); + out: + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct au_branch *au_sbr(struct super_block *sb, aufs_bindex_t bindex) +{ + struct au_branch *br; + + SiMustAnyLock(sb); + AuDebugOn(bindex < 0 || au_sbend(sb) < bindex); + br = au_sbi(sb)->si_branch[0 + bindex]; + AuDebugOn(!br); + return br; +} + +au_gen_t au_sigen_inc(struct super_block *sb) +{ + au_gen_t gen; + + SiMustWriteLock(sb); + gen = ++au_sbi(sb)->si_generation; + au_update_digen(sb->s_root); + au_update_iigen(sb->s_root->d_inode); + sb->s_root->d_inode->i_version++; + return gen; +} + +int au_find_bindex(struct super_block *sb, struct au_branch *br) +{ + aufs_bindex_t bindex, bend; + + bend = au_sbend(sb); + for (bindex = 0; bindex <= bend; bindex++) + if (au_sbr(sb, bindex) == br) + return bindex; + return -1; +} + +/* ---------------------------------------------------------------------- */ + +/* dentry and super_block lock. call at entry point */ +void aufs_read_lock(struct dentry *dentry, int flags) +{ + si_read_lock(dentry->d_sb, flags); + if (au_ftest_lock(flags, DW)) + di_write_lock_child(dentry); + else + di_read_lock_child(dentry, flags); +} + +void aufs_read_unlock(struct dentry *dentry, int flags) +{ + if (au_ftest_lock(flags, DW)) + di_write_unlock(dentry); + else + di_read_unlock(dentry, flags); + si_read_unlock(dentry->d_sb); +} + +void aufs_write_lock(struct dentry *dentry) +{ + si_write_lock(dentry->d_sb); + di_write_lock_child(dentry); +} + +void aufs_write_unlock(struct dentry *dentry) +{ + di_write_unlock(dentry); + si_write_unlock(dentry->d_sb); +} + +void aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags) +{ + AuDebugOn(d1 == d2 || d1->d_sb != d2->d_sb); + si_read_lock(d1->d_sb, flags); + di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIR)); +} + +void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2) +{ + AuDebugOn(d1 == d2 || d1->d_sb != d2->d_sb); + di_write_unlock2(d1, d2); + si_read_unlock(d1->d_sb); +} + +/* ---------------------------------------------------------------------- */ + +aufs_bindex_t au_new_br_id(struct super_block *sb) +{ + aufs_bindex_t br_id; + struct au_sbinfo *sbinfo; + + AuTraceEnter(); + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); + while (1) { + br_id = ++sbinfo->si_last_br_id; + if (br_id && au_br_index(sb, br_id) < 0) + return br_id; + } +} --- linux-2.6.27.orig/ubuntu/aufs/vfsub.h +++ linux-2.6.27/ubuntu/aufs/vfsub.h @@ -0,0 +1,518 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * sub-routines for VFS + * + * $Id: vfsub.h,v 1.11 2008/08/25 01:51:04 sfjro Exp $ + */ + +#ifndef __AUFS_VFSUB_H__ +#define __AUFS_VFSUB_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include +#include + +/* ---------------------------------------------------------------------- */ + +/* vfsub flags */ +#define Vfsub_DLGT 1 /* operation with delegation */ +#define Vfsub_FORCE_UNLINK (1 << 1) /* force unlinking */ +#define vfsub_ftest(flags, name) ((flags) & Vfsub_##name) +#define vfsub_fset(flags, name) { (flags) |= Vfsub_##name; } +#define vfsub_fclr(flags, name) { (flags) &= ~Vfsub_##name; } +#ifndef CONFIG_AUFS_DLGT +#undef Vfsub_DLGT +#define Vfsub_DLGT 0 +#endif + +struct au_hin_ignore; +struct vfsub_args { +#ifdef CONFIG_AUFS_HINOTIFY + /* inotify events to be ignored */ + int nignore; + struct au_hin_ignore *ignore; +#endif + + unsigned int flags; +}; + +struct au_hinode; +#ifdef CONFIG_AUFS_HINOTIFY +static inline +void do_vfsub_args_reinit(struct vfsub_args *vargs, struct au_hin_ignore *ign) +{ + vargs->nignore = 0; + vargs->ignore = ign; +} + +static inline void vfsub_args_reinit(struct vfsub_args *vargs) +{ + vargs->nignore = 0; +} + +__u32 vfsub_events_notify_change(struct iattr *ia); +void vfsub_ign_hinode(struct vfsub_args *vargs, __u32 events, + struct au_hinode *hinode); +void vfsub_ignore(struct vfsub_args *vargs); +void vfsub_unignore(struct vfsub_args *vargs); +#else +static inline +void do_vfsub_args_reinit(struct vfsub_args *vargs, struct au_hin_ignore *ign) +{ + /* empty */ +} + +static inline void vfsub_args_reinit(struct vfsub_args *vargs) +{ + /* empty */ +} + +static inline __u32 vfsub_events_notify_change(struct iattr *ia) +{ + return 0; +} + +static inline void vfsub_ign_hinode(struct vfsub_args *vargs, __u32 events, + struct au_hinode *hinode) +{ + /* empty */ +} + +static inline void vfsub_ignore(struct vfsub_args *vargs) +{ + /* empty */ +} + +static inline void vfsub_unignore(struct vfsub_args *vargs) +{ + /* empty */ +} +#endif /* CONFIG_AUFS_HINOTIFY */ + +void vfsub_args_init(struct vfsub_args *vargs, struct au_hin_ignore *ign, + int dlgt, int force_unlink); + +/* ---------------------------------------------------------------------- */ + +/* inotify_inode_watched() is not exported */ +static inline int au_test_inotify(struct inode *inode) +{ +#ifdef CONFIG_INOTIFY + return !list_empty(&inode->inotify_watches); +#endif + return 0; +} + +/* ---------------------------------------------------------------------- */ + +/* lock subclass for hidden inode */ +/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */ +/* reduce? gave up. */ +enum { + AuLsc_I_Begin = I_MUTEX_QUOTA, /* 4 */ + AuLsc_I_PARENT, /* hidden inode, parent first */ + AuLsc_I_PARENT2, /* copyup dirs */ + AuLsc_I_PARENT3, /* rename with hinotify */ + AuLsc_I_PARENT4, /* ditto */ + AuLsc_I_CHILD, + AuLsc_I_CHILD2, + AuLsc_I_End +}; + +#define IMustLock(i) MtxMustLock(&(i)->i_mutex) + +static inline void vfsub_lock_rename_mutex(struct super_block *sb) +{ + lockdep_off(); + mutex_lock(&sb->s_vfs_rename_mutex); + lockdep_on(); +} + +static inline void vfsub_unlock_rename_mutex(struct super_block *sb) +{ + lockdep_off(); + mutex_unlock(&sb->s_vfs_rename_mutex); + lockdep_on(); +} + +static inline +struct dentry *vfsub_lock_rename(struct dentry *d1, struct dentry *d2) +{ + struct dentry *d; + + lockdep_off(); + d = lock_rename(d1, d2); + lockdep_on(); + return d; +} + +static inline void vfsub_unlock_rename(struct dentry *d1, struct dentry *d2) +{ + lockdep_off(); + unlock_rename(d1, d2); + lockdep_on(); +} + +static inline int au_verify_parent(struct dentry *dentry, struct inode *dir) +{ + IMustLock(dir); + return (/* !dir->i_nlink || */ dentry->d_parent->d_inode != dir); +} + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_WORKAROUND_FUSE +/* br_fuse.c */ +int au_update_fuse_h_inode(struct vfsmount *h_mnt, struct dentry *h_dentry); +#else +static inline +int au_update_fuse_h_inode(struct vfsmount *h_mnt, struct dentry *h_dentry) +{ + return 0; +} +#endif + +#ifdef CONFIG_AUFS_BR_XFS +/* br_xfs.c */ +dev_t au_h_rdev(struct inode *h_inode, struct vfsmount *h_mnt, + struct dentry *h_dentry); +#else +static inline +dev_t au_h_rdev(struct inode *h_inode, struct vfsmount *h_mnt, + struct dentry *h_dentry) +{ + return h_inode->i_rdev; +} +#endif + +/* simple abstractions, for future use */ +static inline +int do_vfsub_permission(struct inode *inode, int mask, struct nameidata *nd) +{ + LKTRTrace("i%lu, mask 0x%x, nd %d\n", inode->i_ino, mask, !!nd); + IMustLock(inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + return inode_permission(inode, mask); +#else + return permission(inode, mask, nd); +#endif +} + +static inline +int vfsub_security_inode_permission(struct inode *inode, int mask, + struct nameidata *nd) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + return security_inode_permission(inode, mask); +#else + return security_inode_permission(inode, mask, nd); +#endif +} + +/* ---------------------------------------------------------------------- */ + +struct file *vfsub_filp_open(const char *path, int oflags, int mode); +int vfsub_path_lookup(const char *name, unsigned int flags, + struct nameidata *nd); +struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, + int len); + +#ifdef CONFIG_AUFS_LHASH_PATCH +struct dentry *vfsub__lookup_hash(struct qstr *name, struct dentry *parent, + struct nameidata *nd); +#endif + +/* ---------------------------------------------------------------------- */ + +int do_vfsub_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd); +int do_vfsub_symlink(struct inode *dir, struct dentry *dentry, + const char *symname, int mode); +int do_vfsub_mknod(struct inode *dir, struct dentry *dentry, int mode, + dev_t dev); +int do_vfsub_link(struct dentry *src_dentry, struct inode *dir, + struct dentry *dentry); +int do_vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, + struct inode *dir, struct dentry *dentry); +int do_vfsub_mkdir(struct inode *dir, struct dentry *dentry, int mode); +int do_vfsub_rmdir(struct inode *dir, struct dentry *dentry); +int do_vfsub_unlink(struct inode *dir, struct dentry *dentry); + +/* ---------------------------------------------------------------------- */ + +ssize_t do_vfsub_read_u(struct file *file, char __user *ubuf, size_t count, + loff_t *ppos); +/* todo: kernel_read()? */ +ssize_t do_vfsub_read_k(struct file *file, void *kbuf, size_t count, + loff_t *ppos); +ssize_t do_vfsub_write_u(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos); +ssize_t do_vfsub_write_k(struct file *file, void *kbuf, size_t count, + loff_t *ppos); +int do_vfsub_readdir(struct file *file, filldir_t filldir, void *arg); + +/* ---------------------------------------------------------------------- */ + +#ifndef CONFIG_AUFS_UNIONFS22_PATCH +static inline void vfsub_copy_inode_size(struct inode *inode, + struct inode *h_inode) +{ + spin_lock(&inode->i_lock); + fsstack_copy_inode_size(inode, h_inode); + spin_unlock(&inode->i_lock); +} +#else +static inline void vfsub_copy_inode_size(struct inode *inode, + struct inode *h_inode) +{ + fsstack_copy_inode_size(inode, h_inode); +} +#endif + +#ifndef CONFIG_AUFS_UNIONFS23_PATCH +#define vfs_splice_to do_splice_to +#define vfs_splice_from do_splice_from +#endif + +#ifdef CONFIG_AUFS_SPLICE_PATCH +long do_vfsub_splice_to(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags); +long do_vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags); +#else +static inline +long do_vfsub_splice_to(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags) +{ + return -ENOSYS; +} + +static inline +long do_vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags) +{ + return -ENOSYS; +} +#endif /* CONFIG_AUFS_SPLICE_PATCH */ + +/* ---------------------------------------------------------------------- */ + +static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t err; + + LKTRTrace("%.*s\n", AuDLNPair(file->f_dentry)); + + lockdep_off(); + err = vfs_llseek(file, offset, origin); + lockdep_on(); + return err; +} + +static inline int do_vfsub_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *st) +{ + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + return vfs_getattr(mnt, dentry, st); +} + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_HIN_OR_DLGT +/* hin_or_dlgt.c */ +int vfsub_permission(struct inode *inode, int mask, struct nameidata *nd, + int dlgt); + +int vfsub_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd, struct vfsub_args *vargs); +int vfsub_symlink(struct inode *dir, struct dentry *dentry, const char *symname, + int mode, struct vfsub_args *vargs); +int vfsub_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev, + struct vfsub_args *vargs); +int vfsub_link(struct dentry *src_dentry, struct inode *dir, + struct dentry *dentry, struct vfsub_args *vargs); +int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, + struct inode *dir, struct dentry *dentry, + struct vfsub_args *vargs); +int vfsub_mkdir(struct inode *dir, struct dentry *dentry, int mode, + struct vfsub_args *vargs); +int vfsub_rmdir(struct inode *dir, struct dentry *dentry, + struct vfsub_args *vargs); + +ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, + loff_t *ppos, int dlgt); +ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, loff_t *ppos, + int dlgt); +ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, + loff_t *ppos, struct vfsub_args *vargs); +ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos, + struct vfsub_args *vargs); +int vfsub_readdir(struct file *file, filldir_t filldir, void *arg, int dlgt); +long vfsub_splice_to(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags, int dlgt); +long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags, + struct vfsub_args *vargs); + +int vfsub_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *st, + int dlgt); +#else + +static inline +int vfsub_permission(struct inode *inode, int mask, struct nameidata *nd, + int dlgt) +{ + return do_vfsub_permission(inode, mask, nd); +} + +static inline +int vfsub_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd, struct vfsub_args *vargs) +{ + return do_vfsub_create(dir, dentry, mode, nd); +} + +static inline +int vfsub_symlink(struct inode *dir, struct dentry *dentry, const char *symname, + int mode, struct vfsub_args *vargs) +{ + return do_vfsub_symlink(dir, dentry, symname, mode); +} + +static inline +int vfsub_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev, + struct vfsub_args *vargs) +{ + return do_vfsub_mknod(dir, dentry, mode, dev); +} + +static inline +int vfsub_link(struct dentry *src_dentry, struct inode *dir, + struct dentry *dentry, struct vfsub_args *vargs) +{ + return do_vfsub_link(src_dentry, dir, dentry); +} + +static inline +int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, + struct inode *dir, struct dentry *dentry, + struct vfsub_args *vargs) +{ + return do_vfsub_rename(src_dir, src_dentry, dir, dentry); +} + +static inline +int vfsub_mkdir(struct inode *dir, struct dentry *dentry, int mode, + struct vfsub_args *vargs) +{ + return do_vfsub_mkdir(dir, dentry, mode); +} + +static inline +int vfsub_rmdir(struct inode *dir, struct dentry *dentry, + struct vfsub_args *vargs) +{ + return do_vfsub_rmdir(dir, dentry); +} + +static inline +ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, + loff_t *ppos, int dlgt) +{ + return do_vfsub_read_u(file, ubuf, count, ppos); +} + +static inline +ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, loff_t *ppos, + int dlgt) +{ + return do_vfsub_read_k(file, kbuf, count, ppos); +} + +static inline +ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, + loff_t *ppos, struct vfsub_args *vargs) +{ + return do_vfsub_write_u(file, ubuf, count, ppos); +} + +static inline +ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos, + struct vfsub_args *vargs) +{ + return do_vfsub_write_k(file, kbuf, count, ppos); +} + +static inline +int vfsub_readdir(struct file *file, filldir_t filldir, void *arg, int dlgt) +{ + return do_vfsub_readdir(file, filldir, arg); +} + +static inline +long vfsub_splice_to(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags, int dlgt) +{ + return do_vfsub_splice_to(in, ppos, pipe, len, flags); +} + +static inline +long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags, + struct vfsub_args *vargs) +{ + return do_vfsub_splice_from(pipe, out, ppos, len, flags); +} + +static inline +int vfsub_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *st, + int dlgt) +{ + return do_vfsub_getattr(mnt, dentry, st); +} +#endif /* HIN_OR_DLGT */ + +/* ---------------------------------------------------------------------- */ + +int vfsub_sio_mkdir(struct au_hinode *hdir, struct dentry *dentry, int mode, + int dlgt); +int vfsub_sio_rmdir(struct au_hinode *hdir, struct dentry *dentry, int dlgt); +int vfsub_sio_notify_change(struct au_hinode *hdir, struct dentry *dentry, + struct iattr *ia); + +/* ---------------------------------------------------------------------- */ + +int vfsub_notify_change(struct dentry *dentry, struct iattr *ia, + struct vfsub_args *vargs); +int vfsub_unlink(struct inode *dir, struct dentry *dentry, + struct vfsub_args *vargs); +int vfsub_statfs(void *arg, struct kstatfs *buf, int dlgt); + +#endif /* __KERNEL__ */ +#endif /* __AUFS_VFSUB_H__ */ --- linux-2.6.27.orig/ubuntu/aufs/branch.h +++ linux-2.6.27/ubuntu/aufs/branch.h @@ -0,0 +1,393 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * branch filesystems and xino for them + * + * $Id: branch.h,v 1.12 2008/09/15 03:14:03 sfjro Exp $ + */ + +#ifndef __AUFS_BRANCH_H__ +#define __AUFS_BRANCH_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include "misc.h" +#include "super.h" + +/* ---------------------------------------------------------------------- */ + +/* an entry in a xino file */ +struct au_xino_entry { + ino_t ino; + /* __u32 h_gen; */ /* reserved for future use */ +} __packed; + +/* reserved for future use */ +/* #define AuXino_INVALID_HGEN (-1) */ + +/* a xino file */ +struct au_xino_file { + struct file *xi_file; + struct mutex xi_nondir_mtx; + + /* reserved for future use */ +#if 0 + struct file **xi_file; + + /* array management */ + unsigned long long xi_limit; /* Max xino file size */ + unsigned long long xi_size; /* s_maxbytes */ + + /* truncation */ + unsigned long long xi_upper; /* watermark in bytes */ + unsigned long long xi_step; /* to next watermark in bytes */ + + /* truncation */ + blkcnt_t xi_upper; /* watermark in blocks */ + atomic_t xi_running; +#endif +}; + +/* members for writable branch only */ +enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_TMP, AuBrWh_Last}; +struct au_wbr { + struct au_rwsem wbr_wh_rwsem; + struct dentry *wbr_wh[AuBrWh_Last]; + atomic_t wbr_wh_running; +#define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */ +#define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */ +#define wbr_tmp wbr_wh[AuBrWh_TMP] /* temporary dir */ + + /* mfs mode */ + unsigned long long wbr_bytes; +}; + +/* protected by superblock rwsem */ +struct au_branch { + struct au_xino_file br_xino; + + aufs_bindex_t br_id; + + int br_perm; + struct vfsmount *br_mnt; + atomic_t br_count; + + struct au_wbr *br_wbr; + +#if 1 /* reserved for future use */ + /* xino truncation */ + blkcnt_t br_xino_upper; /* watermark in blocks */ + atomic_t br_xino_running; +#endif + +#ifdef CONFIG_SYSFS + /* an entry under sysfs per mount-point */ + char br_name[8]; + struct attribute br_attr; +#endif + + au_gen_t br_generation; +}; + +/* ---------------------------------------------------------------------- */ + +/* branch permission and attribute */ +enum { + AuBrPerm_RW, /* writable, linkable wh */ + AuBrPerm_RO, /* readonly, no wh */ + AuBrPerm_RR, /* natively readonly, no wh */ + + AuBrPerm_RWNoLinkWH, /* un-linkable whiteouts */ + + AuBrPerm_ROWH, + AuBrPerm_RRWH, /* whiteout-able */ + + AuBrPerm_Last +}; + +static inline int au_br_writable(int brperm) +{ + return (brperm == AuBrPerm_RW || brperm == AuBrPerm_RWNoLinkWH); +} + +static inline int au_br_whable(int brperm) +{ + return (brperm == AuBrPerm_RW + || brperm == AuBrPerm_ROWH + || brperm == AuBrPerm_RRWH); +} + +#if 0 /* reserved for future use */ +static inline int au_br_linkable_wh(int brperm) +{ + return (brperm == AuBrPerm_RW); +} +#endif + +static inline int au_br_hinotifyable(int brperm) +{ +#ifdef CONFIG_AUFS_HINOTIFY + return (brperm != AuBrPerm_RR && brperm != AuBrPerm_RRWH); +#else + return 0; +#endif +} + +/* ---------------------------------------------------------------------- */ + +/* branch.c */ +struct au_sbinfo; +void au_br_free(struct au_sbinfo *sinfo); +int au_test_def_rr(struct super_block *h_sb); +int au_br_index(struct super_block *sb, aufs_bindex_t br_id); +struct au_opt_add; +int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount); +struct au_opt_del; +int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount); +struct au_opt_mod; +int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, + int *do_update); + +/* xino.c */ +#define Au_LOFF_MAX ((loff_t)LLONG_MAX) +int au_xib_trunc(struct super_block *sb); +ssize_t xino_fread(au_readf_t func, struct file *file, void *buf, size_t size, + loff_t *pos); +ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size, + loff_t *pos); +struct file *au_xino_create(struct super_block *sb, char *fname, int silent); +struct file *au_xino_create2(struct super_block *sb, struct file *base_file, + struct file *copy_src); +ino_t au_xino_new_ino(struct super_block *sb); +int au_xino_write0(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + ino_t ino); +int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + struct au_xino_entry *xinoe); +int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + struct au_xino_entry *xinoe); +int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t hino, + struct file *base_file, int do_test); +int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex); + +struct au_opt_xino; +int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount); +void au_xino_clr(struct super_block *sb); +struct file *au_xino_def(struct super_block *sb); + +struct au_opt_xinodir; +#if 0 /* def CONFIG_AUFS_EXPORT */ /* reserved for future use */ +/* export.c */ +int au_xinodir_br(struct super_block *sb, struct au_branch *br, ino_t hino, + int do_test); +int au_xinodir_set(struct super_block *sb, struct au_opt_xinodir *xinodir, + int remount); +#else +static inline +int au_xinodir_br(struct super_block *sb, struct au_branch *br, ino_t hino, + int do_test) +{ + return 0; +} + +static inline +int au_xinodir_set(struct super_block *sb, struct au_opt_xinodir *xinodir, + int remount) +{ + return 0; +} +#endif + +/* ---------------------------------------------------------------------- */ + +/* todo: memory barrier? */ +static inline int au_br_count(struct au_branch *br) +{ + return atomic_read(&br->br_count); +} + +static inline int au_br_get(struct au_branch *br) +{ + return atomic_inc_return(&br->br_count); +} + +static inline int au_br_put(struct au_branch *br) +{ + return atomic_dec_return(&br->br_count); +} + +static inline au_gen_t au_br_gen(struct au_branch *br) +{ + return br->br_generation; +} + +/* + * test if the @br is readonly or not. + */ +static inline int au_br_rdonly(struct au_branch *br) +{ + return ((br->br_mnt->mnt_sb->s_flags & MS_RDONLY) + || !au_br_writable(br->br_perm)) + ? -EROFS : 0; +} + +/* ---------------------------------------------------------------------- */ + +/* Superblock to branch */ +static inline +aufs_bindex_t au_sbr_id(struct super_block *sb, aufs_bindex_t bindex) +{ + return au_sbr(sb, bindex)->br_id; +} + +static inline +struct vfsmount *au_sbr_mnt(struct super_block *sb, aufs_bindex_t bindex) +{ + return au_sbr(sb, bindex)->br_mnt; +} + +static inline +struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex) +{ + return au_sbr_mnt(sb, bindex)->mnt_sb; +} + +#if 0 /* reserved for future use */ +static inline int au_sbr_count(struct super_block *sb, aufs_bindex_t bindex) +{ + return au_br_count(au_sbr(sb, bindex)); +} + +static inline void au_sbr_get(struct super_block *sb, aufs_bindex_t bindex) +{ + au_br_get(au_sbr(sb, bindex)); +} +#endif + +static inline void au_sbr_put(struct super_block *sb, aufs_bindex_t bindex) +{ + au_br_put(au_sbr(sb, bindex)); +} + +static inline int au_sbr_perm(struct super_block *sb, aufs_bindex_t bindex) +{ + return au_sbr(sb, bindex)->br_perm; +} + +static inline int au_sbr_whable(struct super_block *sb, aufs_bindex_t bindex) +{ + return au_br_whable(au_sbr_perm(sb, bindex)); +} + +static inline int au_test_trunc_xino(struct super_block *sb) +{ + return au_test_tmpfs(sb); +} + +/* temporary support for i#1 in cramfs */ +static inline int au_test_unique_ino(struct dentry *h_dentry, ino_t h_ino) +{ +#if defined(CONFIG_CRAMFS) || defined(CONFIG_CRAMFS_MODULE) + if (unlikely(h_dentry->d_sb->s_magic == CRAMFS_MAGIC)) + return (h_ino != 1); +#endif + return 1; +} + +static inline struct vfsmount *au_do_nfsmnt(struct vfsmount *h_mnt) +{ + if (!au_test_nfs(h_mnt->mnt_sb)) + return NULL; + return h_mnt; +} + +static inline void au_br_nfs_lockdep_off(struct super_block *sb) +{ + if (au_test_nfs(sb)) + lockdep_off(); +} + +static inline void au_br_nfs_lockdep_on(struct super_block *sb) +{ + /* hoping this condition will be optimized... */ + if (au_test_nfs(sb)) + lockdep_on(); +} + +#ifdef CONFIG_AUFS_BR_NFS +static inline int au_test_unsupported_nfs(struct super_block *h_sb) +{ + return 0; +} + +/* it doesn't mntget() */ +static inline +struct vfsmount *au_nfsmnt(struct super_block *sb, aufs_bindex_t bindex) +{ + return au_do_nfsmnt(au_sbr_mnt(sb, bindex)); +} + +#define AuNoNfsBranchMsg "dummy" + +#else +static inline int au_test_unsupported_nfs(struct super_block *h_sb) +{ + return (h_sb->s_magic == NFS_SUPER_MAGIC); +} + +static inline +struct vfsmount *au_nfsmnt(struct super_block *sb, aufs_bindex_t bindex) +{ + return NULL; +} + +#define AuNoNfsBranchMsg "NFS branch is not supported" \ + ", try some configurations and patches included in aufs source CVS." + +#endif /* CONFIG_AUFS_BR_NFS */ + +/* ---------------------------------------------------------------------- */ + +/* + * br_wh_read_lock, br_wh_write_lock + * br_wh_read_unlock, br_wh_write_unlock, br_wh_downgrade_lock + */ +AuSimpleRwsemFuncs(wbr_wh, struct au_wbr *wbr, wbr->wbr_wh_rwsem); + +/* to debug easier, do not make them inlined functions */ +#define WbrWhMustReadLock(wbr) do { \ + /* SiMustAnyLock(sb); */ \ + AuRwMustReadLock(&(wbr)->wbr_wh_rwsem); \ +} while (0) + +#define WbrWhMustWriteLock(wbr) do { \ + /* SiMustAnyLock(sb); */ \ + AuRwMustWriteLock(&(wbr)->wbr_wh_rwsem); \ +} while (0) + +#define WbrWhMustAnyLock(br) do { \ + /* SiMustAnyLock(sb); */ \ + AuRwMustAnyLock(&(wbr)->wbr_wh_rwsem); \ +} while (0) + +#endif /* __KERNEL__ */ +#endif /* __AUFS_BRANCH_H__ */ --- linux-2.6.27.orig/ubuntu/aufs/cpup.h +++ linux-2.6.27/ubuntu/aufs/cpup.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * copy-up/down functions + * + * $Id: cpup.h,v 1.5 2008/09/01 02:54:48 sfjro Exp $ + */ + +#ifndef __AUFS_CPUP_H__ +#define __AUFS_CPUP_H__ + +#ifdef __KERNEL__ + +#include +#include + +void au_cpup_attr_timesizes(struct inode *inode); +void au_cpup_attr_nlink(struct inode *inode); +void au_cpup_attr_changeable(struct inode *inode); +void au_cpup_igen(struct inode *inode, struct inode *h_inode); +void au_cpup_attr_all(struct inode *inode); + +/* ---------------------------------------------------------------------- */ + +/* cpup flags */ +#define AuCpup_DTIME 1 /* do dtime_store/revert */ +#define AuCpup_KEEPLINO (1 << 1) /* do not clear the lower xino, + for link(2) */ +#define au_ftest_cpup(flags, name) ((flags) & AuCpup_##name) +#define au_fset_cpup(flags, name) { (flags) |= AuCpup_##name; } +#define au_fclr_cpup(flags, name) { (flags) &= ~AuCpup_##name; } + +int au_sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst, + aufs_bindex_t bsrc, loff_t len, unsigned int flags, + struct dentry *dst_parent); +int au_sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, + unsigned int flags); +int au_sio_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, + struct file *file); + +int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, + int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, + struct dentry *h_parent, void *arg), + void *arg); +int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); +int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); + +/* ---------------------------------------------------------------------- */ + +/* keep timestamps when copyup */ +struct au_dtime { + struct dentry *dt_dentry, *dt_h_dentry; + struct au_hinode *dt_hinode, *dt_hdir; + struct timespec dt_atime, dt_mtime; +}; +void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, + struct dentry *h_dentry, struct au_hinode *hinode, + struct au_hinode *hdir); +void au_dtime_revert(struct au_dtime *dt); + +#endif /* __KERNEL__ */ +#endif /* __AUFS_CPUP_H__ */ --- linux-2.6.27.orig/ubuntu/aufs/br_fuse.c +++ linux-2.6.27/ubuntu/aufs/br_fuse.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * special handling for inode attributes on FUSE branch + * + * $Id: br_fuse.c,v 1.6 2008/07/27 22:49:28 sfjro Exp $ + */ + +#include "aufs.h" + +/* h_mnt can be NULL, is it safe? */ +int au_update_fuse_h_inode(struct vfsmount *h_mnt, struct dentry *h_dentry) +{ + int err; + struct kstat st; + + LKTRTrace("%.*s\n", AuDLNPair(h_dentry)); + + err = 0; + if (unlikely(h_dentry->d_inode + /* && atomic_read(&h_dentry->d_inode->i_count) */ + && au_test_fuse(h_dentry->d_sb))) { + err = vfsub_getattr(h_mnt, h_dentry, &st, /*dlgt*/0); + if (unlikely(err)) { + AuDbg("err %d\n", err); + au_debug_on(); + AuDbgDentry(h_dentry); + au_debug_off(); + WARN_ON(err); + } + } + return err; +} + +#if 0 /* temp */ +/* + * This function was born after a discussion with the FUSE developer. + * The inode attributes on a filesystem who defines i_op->getattr() + * is unreliable since such fs may not maintain the attributes at lookup. + * This function doesn't want the result of stat, instead wants the side-effect + * which refreshes the attributes. + * Hmm, there seems to be no such filesystem except fuse. + */ +int vfsub_i_attr(struct vfsmount *mnt, struct dentry *dentry, int dlgt) +{ + int err; + struct inode *inode; + struct inode_operations *op; + struct kstat st; + + inode = dentry->d_inode; + AuDebugOn(!inode); + + err = 0; + op = inode->i_op; + if (unlikely(op && op->getattr && !au_test_aufs(dentry->d_sb))) { + err = security_inode_getattr(mnt, dentry); + if (!err) + err = op->getattr(mnt, dentry, &st); + } + AuTraceErr(err); + return err; +} +#endif --- linux-2.6.27.orig/ubuntu/aufs/sysaufs.c +++ linux-2.6.27/ubuntu/aufs/sysaufs.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * sysfs interface and lifetime management + * they are necessary regardless sysfs is disabled. + * + * $Id: sysaufs.c,v 1.10 2008/09/15 03:14:55 sfjro Exp $ + */ + +#include +#include +#include +#include +#include "aufs.h" + +/* ---------------------------------------------------------------------- */ + +unsigned long au_si_mask; + +/* ---------------------------------------------------------------------- */ + +struct kset *au_kset; + +#define AuSbiAttr(_name) { \ + .attr = { .name = __stringify(_name), .mode = 0444 }, \ + .show = sysaufs_sbi_##_name, \ +} + +static struct au_sbi_attr au_sbi_attr_xino = AuSbiAttr(xino); +#ifdef CONFIG_AUFS_EXPORT +static struct au_sbi_attr au_sbi_attr_xigen = AuSbiAttr(xigen); +#endif +struct attribute *au_sbi_attrs[] = { + &au_sbi_attr_xino.attr, +#ifdef CONFIG_AUFS_EXPORT + &au_sbi_attr_xigen.attr, +#endif + NULL, +}; + +static struct sysfs_ops au_sbi_ops = { + .show = sysaufs_sbi_show +}; + +static struct kobj_type au_sbi_ktype = { + .release = au_si_free, + .sysfs_ops = &au_sbi_ops, + .default_attrs = au_sbi_attrs +}; + +/* ---------------------------------------------------------------------- */ + +int sysaufs_si_init(struct au_sbinfo *sbinfo) +{ + int err; + + sbinfo->si_kobj.kset = au_kset; + /* some people doesn't like to show a pointer in kernel */ + err = kobject_init_and_add(&sbinfo->si_kobj, &au_sbi_ktype, + NULL/*&au_kset->kobj*/, + SysaufsSb_PREFIX "%lx", + au_si_mask ^ (unsigned long)sbinfo); + AuTraceErr(err); + return err; +} + + +/* ---------------------------------------------------------------------- */ + +void sysaufs_fin(void) +{ + sysfs_remove_group(&au_kset->kobj, au_attr_group); + kset_unregister(au_kset); +} + +int __init sysaufs_init(void) +{ + int err; + + get_random_bytes(&au_si_mask, sizeof(au_si_mask)); + + au_kset = kset_create_and_add(AUFS_NAME, NULL, fs_kobj); + err = PTR_ERR(au_kset); + if (IS_ERR(au_kset)) + goto out; + err = sysfs_create_group(&au_kset->kobj, au_attr_group); + if (unlikely(err)) + kset_unregister(au_kset); + + out: + AuTraceErr(err); + return err; +} --- linux-2.6.27.orig/ubuntu/aufs/debug.c +++ linux-2.6.27/ubuntu/aufs/debug.c @@ -0,0 +1,512 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * debug print functions + * + * $Id: debug.c,v 1.14 2008/09/22 03:52:03 sfjro Exp $ + */ + +#include "aufs.h" + +atomic_t au_cond = ATOMIC_INIT(0); + +char *au_plevel = KERN_DEBUG; +#define dpri(fmt, arg...) do { \ + if (LktrCond) \ + printk("%s" fmt, au_plevel, ##arg); \ +} while (0) + +/* ---------------------------------------------------------------------- */ + +void au_dpri_whlist(struct au_nhash *whlist) +{ + int i; + struct hlist_head *head; + struct au_vdir_wh *tpos; + struct hlist_node *pos; + + for (i = 0; i < AuSize_NHASH; i++) { + head = whlist->heads + i; + hlist_for_each_entry(tpos, pos, head, wh_hash) + dpri("b%d, %.*s, %d\n", + tpos->wh_bindex, + tpos->wh_str.len, tpos->wh_str.name, + tpos->wh_str.len); + } +} + +void au_dpri_vdir(struct au_vdir *vdir) +{ + int i; + union au_vdir_deblk_p p; + unsigned char *o; + + if (!vdir || IS_ERR(vdir)) { + dpri("err %ld\n", PTR_ERR(vdir)); + return; + } + + dpri("nblk %d, deblk %p, last{%d, %p}, ver %lu\n", + vdir->vd_nblk, vdir->vd_deblk, + vdir->vd_last.i, vdir->vd_last.p.p, vdir->vd_version); + for (i = 0; i < vdir->vd_nblk; i++) { + p.deblk = vdir->vd_deblk[i]; + o = p.p; + dpri("[%d]: %p\n", i, o); + } +} + +static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode, + struct dentry *wh) +{ + char *n = NULL; + int l = 0, ntfy = 0; + + if (!inode || IS_ERR(inode)) { + dpri("i%d: err %ld\n", bindex, PTR_ERR(inode)); + return -1; + } + + /* the type of i_blocks depends upon CONFIG_LSF */ + BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long) + && sizeof(inode->i_blocks) != sizeof(u64)); + if (wh) { + n = (void *)wh->d_name.name; + l = wh->d_name.len; + } + + ntfy = au_test_inotify(inode); + dpri("i%d: i%lu, %s, cnt %d, nl %u, 0%o, ntfy %d, sz %llu, blk %llu," + " ct %lld, np %lu, st 0x%lx, f 0x%x, g %x%s%.*s\n", + bindex, + inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??", + atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode, + ntfy, + i_size_read(inode), (unsigned long long)inode->i_blocks, + (long long)timespec_to_ns(&inode->i_ctime) & 0x0ffff, + inode->i_mapping ? inode->i_mapping->nrpages : 0, + inode->i_state, inode->i_flags, inode->i_generation, + l ? ", wh " : "", l, n); + return 0; +} + +void au_dpri_inode(struct inode *inode) +{ + struct au_iinfo *iinfo; + aufs_bindex_t bindex; + int err; + + err = do_pri_inode(-1, inode, NULL); + if (err || !au_test_aufs(inode->i_sb)) + return; + + iinfo = au_ii(inode); + if (!iinfo) + return; + dpri("i-1: bstart %d, bend %d, gen %d\n", + iinfo->ii_bstart, iinfo->ii_bend, au_iigen(inode)); + if (iinfo->ii_bstart < 0) + return; + for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; bindex++) + do_pri_inode(bindex, iinfo->ii_hinode[0 + bindex].hi_inode, + iinfo->ii_hinode[0 + bindex].hi_whdentry); +} + +static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry, + struct list_head *intent) +{ + struct dentry *wh = NULL; + + if (!dentry || IS_ERR(dentry)) { + dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry)); + return -1; + } + /* do not call dget_parent() here */ + dpri("d%d: %.*s?/%.*s, %s, cnt %d, flags 0x%x, intent %d\n", + bindex, + AuDLNPair(dentry->d_parent), AuDLNPair(dentry), + dentry->d_sb ? au_sbtype(dentry->d_sb) : "??", + atomic_read(&dentry->d_count), dentry->d_flags, !!intent); + if (bindex >= 0 && dentry->d_inode && au_test_aufs(dentry->d_sb)) { + struct au_iinfo *iinfo = au_ii(dentry->d_inode); + if (iinfo) + wh = iinfo->ii_hinode[0 + bindex].hi_whdentry; + } + do_pri_inode(bindex, dentry->d_inode, wh); + return 0; +} + +static struct list_head *au_dbg_h_intent(struct au_dinfo *dinfo, + aufs_bindex_t bindex) +{ +#ifdef CONFIG_AUFS_BR_NFS + return dinfo->di_hdentry[0 + bindex].hd_intent_list; +#else + return NULL; +#endif +} + +void au_dpri_dentry(struct dentry *dentry) +{ + struct au_dinfo *dinfo; + aufs_bindex_t bindex; + int err; + + err = do_pri_dentry(-1, dentry, NULL); + if (err || !au_test_aufs(dentry->d_sb)) + return; + + dinfo = au_di(dentry); + if (!dinfo) + return; + dpri("d-1: bstart %d, bend %d, bwh %d, bdiropq %d, gen %d\n", + dinfo->di_bstart, dinfo->di_bend, + dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry)); + if (dinfo->di_bstart < 0) + return; + for (bindex = dinfo->di_bstart; bindex <= dinfo->di_bend; bindex++) + do_pri_dentry(bindex, dinfo->di_hdentry[0 + bindex].hd_dentry, + au_dbg_h_intent(dinfo, bindex)); +} + +static int do_pri_file(aufs_bindex_t bindex, struct file *file) +{ + char a[32]; + + if (!file || IS_ERR(file)) { + dpri("f%d: err %ld\n", bindex, PTR_ERR(file)); + return -1; + } + a[0] = 0; + if (bindex < 0 + && file->f_dentry + && au_test_aufs(file->f_dentry->d_sb) + && au_fi(file)) + snprintf(a, sizeof(a), ", mmapped %d", au_test_mmapped(file)); + dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, pos %llu%s\n", + bindex, file->f_mode, file->f_flags, (long)file_count(file), + file->f_pos, a); + if (file->f_dentry) + do_pri_dentry(bindex, file->f_dentry, NULL); + return 0; +} + +void au_dpri_file(struct file *file) +{ + struct au_finfo *finfo; + aufs_bindex_t bindex; + int err; + + err = do_pri_file(-1, file); + if (err || !file->f_dentry || !au_test_aufs(file->f_dentry->d_sb)) + return; + + finfo = au_fi(file); + if (!finfo) + return; + if (finfo->fi_bstart < 0) + return; + for (bindex = finfo->fi_bstart; bindex <= finfo->fi_bend; bindex++) { + struct au_hfile *hf; + hf = finfo->fi_hfile + bindex; + do_pri_file(bindex, hf ? hf->hf_file : NULL); + } +} + +static int do_pri_br(aufs_bindex_t bindex, struct au_branch *br) +{ + struct vfsmount *mnt; + struct super_block *sb; + + if (!br || IS_ERR(br) + || !(mnt = br->br_mnt) || IS_ERR(mnt) + || !(sb = mnt->mnt_sb) || IS_ERR(sb)) { + dpri("s%d: err %ld\n", bindex, PTR_ERR(br)); + return -1; + } + + dpri("s%d: {perm 0x%x, cnt %d, wbr %p}, " + "%s, dev 0x%02x%02x, flags 0x%lx, cnt(BIAS) %d, active %d, " + "xino %d\n", + bindex, br->br_perm, au_br_count(br), br->br_wbr, + au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev), + sb->s_flags, sb->s_count - S_BIAS, + atomic_read(&sb->s_active), !!br->br_xino.xi_file); + return 0; +} + +void au_dpri_sb(struct super_block *sb) +{ + struct au_sbinfo *sbinfo; + aufs_bindex_t bindex; + int err; + /* to reuduce stack size */ + struct { + struct vfsmount mnt; + struct au_branch fake; + } *a; + + /* this function can be called from magic sysrq */ + a = kzalloc(sizeof(*a), GFP_ATOMIC); + if (unlikely(!a)) { + dpri("no memory\n"); + return; + } + + a->mnt.mnt_sb = sb; + a->fake.br_perm = 0; + a->fake.br_mnt = &a->mnt; + a->fake.br_xino.xi_file = NULL; + atomic_set(&a->fake.br_count, 0); + smp_mb(); /* atomic_set */ + err = do_pri_br(-1, &a->fake); + kfree(a); + dpri("dev 0x%x\n", sb->s_dev); + if (err || !au_test_aufs(sb)) + return; + + sbinfo = au_sbi(sb); + if (!sbinfo) + return; + dpri("gen %u\n", sbinfo->si_generation); + for (bindex = 0; bindex <= sbinfo->si_bend; bindex++) + do_pri_br(bindex, sbinfo->si_branch[0 + bindex]); +} + +/* ---------------------------------------------------------------------- */ + +void au_dbg_sleep(int sec) +{ + static DECLARE_WAIT_QUEUE_HEAD(wq); + wait_event_timeout(wq, 0, sec * HZ); +} + +void au_dbg_sleep_jiffy(int jiffy) +{ + static DECLARE_WAIT_QUEUE_HEAD(wq); + wait_event_timeout(wq, 0, jiffy); +} + +void au_dbg_iattr(struct iattr *ia) +{ +#define AuBit(name) if (ia->ia_valid & ATTR_ ## name) dpri(#name "\n") + AuBit(MODE); + AuBit(UID); + AuBit(GID); + AuBit(SIZE); + AuBit(ATIME); + AuBit(MTIME); + AuBit(CTIME); + AuBit(ATIME_SET); + AuBit(MTIME_SET); + AuBit(FORCE); + AuBit(ATTR_FLAG); + AuBit(KILL_SUID); + AuBit(KILL_SGID); + AuBit(FILE); + AuBit(KILL_PRIV); + AuBit(OPEN); + AuBit(TIMES_SET); +#undef AuBit + dpri("ia_file %p\n", ia->ia_file); +} + +/* ---------------------------------------------------------------------- */ + +void au_debug_sbinfo_init(struct au_sbinfo *sbinfo) +{ +#ifdef ForceInotify + au_opt_set_udba(sbinfo->si_mntflags, UDBA_INOTIFY); +#endif +#ifdef ForceDlgt + au_opt_set(sbinfo->si_mntflags, DLGT); +#endif +#ifdef ForceNoPlink + au_opt_clr(sbinfo->si_mntflags, PLINK); +#endif +#ifdef ForceNoXino + au_opt_clr(sbinfo->si_mntflags, XINO); +#endif +#ifdef ForceNoRefrof + au_opt_clr(sbinfo->si_mntflags, REFROF); +#endif +#ifdef ForceShwh + au_opt_set(sbinfo->si_mntflags, SHWH); +#endif +} + +int __init au_debug_init(void) +{ + aufs_bindex_t bindex; + struct au_vdir_destr destr; + + bindex = -1; + AuDebugOn(bindex >= 0); + + destr.len = -1; + AuDebugOn(destr.len < NAME_MAX); + +#ifdef CONFIG_4KSTACKS + AuWarn("CONFIG_4KSTACKS is defined.\n"); +#endif + +#ifdef ForceBrs + sysaufs_brs = 1; +#endif + +#if 0 /* verbose debug */ + { + union { + struct au_branch *br; + struct au_dinfo *di; + struct au_finfo *fi; + struct au_iinfo *ii; + struct au_hinode *hi; + struct au_sbinfo *si; + struct au_vdir_destr *destr; + struct au_vdir_de *de; + struct au_vdir_wh *wh; + struct au_vdir *vd; + } u; + + pr_info("br{" + "xino %d, " + "id %d, perm %d, mnt %d, count %d, " + "wbr %d, " + "xup %d, xrun %d, " + "gen %d, " + "sa %d} %d\n", + offsetof(typeof(*u.br), br_xino), + offsetof(typeof(*u.br), br_id), + offsetof(typeof(*u.br), br_perm), + offsetof(typeof(*u.br), br_mnt), + offsetof(typeof(*u.br), br_count), + offsetof(typeof(*u.br), wbr), + offsetof(typeof(*u.br), br_xino_upper), + offsetof(typeof(*u.br), br_xino_running), + offsetof(typeof(*u.br), br_generation), + offsetof(typeof(*u.br), br_sabr), + sizeof(*u.br)); + pr_info("di{gen %d, rwsem %d, bstart %d, bend %d, bwh %d, " + "bdiropq %d, hdentry %d} %d\n", + offsetof(typeof(*u.di), di_generation), + offsetof(typeof(*u.di), di_rwsem), + offsetof(typeof(*u.di), di_bstart), + offsetof(typeof(*u.di), di_bend), + offsetof(typeof(*u.di), di_bwh), + offsetof(typeof(*u.di), di_bdiropq), + offsetof(typeof(*u.di), di_hdentry), + sizeof(*u.di)); + pr_info("fi{gen %d, rwsem %d, hfile %d, bstart %d, bend %d, " + "h_vm_ops %d, vdir_cach %d} %d\n", + offsetof(typeof(*u.fi), fi_generation), + offsetof(typeof(*u.fi), fi_rwsem), + offsetof(typeof(*u.fi), fi_hfile), + offsetof(typeof(*u.fi), fi_bstart), + offsetof(typeof(*u.fi), fi_bend), + offsetof(typeof(*u.fi), fi_h_vm_ops), + offsetof(typeof(*u.fi), fi_vdir_cache), + sizeof(*u.fi)); + pr_info("ii{gen %d, hsb %d, " + "rwsem %d, bstart %d, bend %d, hinode %d, vdir %d} " + "%d\n", + offsetof(typeof(*u.ii), ii_generation), + offsetof(typeof(*u.ii), ii_hsb1), + offsetof(typeof(*u.ii), ii_rwsem), + offsetof(typeof(*u.ii), ii_bstart), + offsetof(typeof(*u.ii), ii_bend), + offsetof(typeof(*u.ii), ii_hinode), + offsetof(typeof(*u.ii), ii_vdir), + sizeof(*u.ii)); + pr_info("hi{inode %d, id %d, notify %d, wh %d} %d\n", + offsetof(typeof(*u.hi), hi_inode), + offsetof(typeof(*u.hi), hi_id), + offsetof(typeof(*u.hi), hi_notify), + offsetof(typeof(*u.hi), hi_whdentry), + sizeof(*u.hi)); + pr_info("si{nwt %d, rwsem %d, gen %d, stat %d, " + "bend %d, last id %d, br %d, " + "cpup %d, creat %d, ops %d, ops %d, " + "rr %d, mfs %d, " + "mntflags %d, " + "xread %d, xwrite %d, xib %d, xmtx %d, buf %d, " + "xlast %d, xnext %d, " + "rdcache %d, " + "dirwh %d, " + "pl_lock %d, pl %d, " + "mnt %d, " + "sys %d, " + /* "lvma_l %d, lvma %d" */ + "} %d\n", + offsetof(typeof(*u.si), si_nowait), + offsetof(typeof(*u.si), si_rwsem), + offsetof(typeof(*u.si), si_generation), + offsetof(typeof(*u.si), au_si_status), + offsetof(typeof(*u.si), si_bend), + offsetof(typeof(*u.si), si_last_br_id), + offsetof(typeof(*u.si), si_branch), + offsetof(typeof(*u.si), si_wbr_copyup), + offsetof(typeof(*u.si), si_wbr_create), + offsetof(typeof(*u.si), si_wbr_copyup_ops), + offsetof(typeof(*u.si), si_wbr_create_ops), + offsetof(typeof(*u.si), si_wbr_rr_next), + offsetof(typeof(*u.si), si_wbr_mfs), + offsetof(typeof(*u.si), si_mntflags), + offsetof(typeof(*u.si), si_xread), + offsetof(typeof(*u.si), si_xwrite), + offsetof(typeof(*u.si), si_xib), + offsetof(typeof(*u.si), si_xib_mtx), + offsetof(typeof(*u.si), si_xib_buf), + offsetof(typeof(*u.si), si_xib_last_pindex), + offsetof(typeof(*u.si), si_xib_next_bit), + offsetof(typeof(*u.si), si_rdcache), + offsetof(typeof(*u.si), si_dirwh), + offsetof(typeof(*u.si), si_plink_lock), + offsetof(typeof(*u.si), si_plink), + offsetof(typeof(*u.si), si_mnt), + offsetof(typeof(*u.si), si_sa), + /*offsetof(typeof(*u.si), si_lvma_lock), + offsetof(typeof(*u.si), si_lvma),*/ + sizeof(*u.si)); + pr_info("destr{len %d, name %d} %d\n", + offsetof(typeof(*u.destr), len), + offsetof(typeof(*u.destr), name), + sizeof(*u.destr)); + pr_info("de{ino %d, type %d, str %d} %d\n", + offsetof(typeof(*u.de), de_ino), + offsetof(typeof(*u.de), de_type), + offsetof(typeof(*u.de), de_str), + sizeof(*u.de)); + pr_info("wh{hash %d, bindex %d, str %d} %d\n", + offsetof(typeof(*u.wh), wh_hash), + offsetof(typeof(*u.wh), wh_bindex), + offsetof(typeof(*u.wh), wh_str), + sizeof(*u.wh)); + pr_info("vd{deblk %d, nblk %d, last %d, ver %d, jiffy %d} %d\n", + offsetof(typeof(*u.vd), vd_deblk), + offsetof(typeof(*u.vd), vd_nblk), + offsetof(typeof(*u.vd), vd_last), + offsetof(typeof(*u.vd), vd_version), + offsetof(typeof(*u.vd), vd_jiffy), + sizeof(*u.vd)); + } +#endif + + return 0; +} --- linux-2.6.27.orig/ubuntu/aufs/dir.h +++ linux-2.6.27/ubuntu/aufs/dir.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * directory operations + * + * $Id: dir.h,v 1.3 2008/05/26 04:04:23 sfjro Exp $ + */ + +#ifndef __AUFS_DIR_H__ +#define __AUFS_DIR_H__ + +#ifdef __KERNEL__ + +#include +#include + +/* ---------------------------------------------------------------------- */ + +/* need to be faster and smaller */ + +/* todo: changeable? */ +#define AuSize_DEBLK 512 +#define AuSize_NHASH 32 +#if AuSize_DEBLK < NAME_MAX || PAGE_SIZE < AuSize_DEBLK +#error invalid size AuSize_DEBLK +#endif + +typedef char au_vdir_deblk_t[AuSize_DEBLK]; + +struct au_nhash { + struct hlist_head heads[AuSize_NHASH]; +}; + +struct au_vdir_destr { + unsigned char len; + char name[0]; +} __packed; + +struct au_vdir_dehstr { + struct hlist_node hash; + struct au_vdir_destr *str; +}; + +struct au_vdir_de { + ino_t de_ino; + unsigned char de_type; + /* caution: packed */ + struct au_vdir_destr de_str; +} __packed; + +struct au_vdir_wh { + struct hlist_node wh_hash; + aufs_bindex_t wh_bindex; +#ifdef CONFIG_AUFS_SHWH + ino_t wh_ino; + unsigned char wh_type; + /* caution: packed */ +#endif + struct au_vdir_destr wh_str; +} __packed; + +union au_vdir_deblk_p { + unsigned char *p; + au_vdir_deblk_t *deblk; + struct au_vdir_de *de; +}; + +struct au_vdir { + au_vdir_deblk_t **vd_deblk; + int vd_nblk; + struct { + int i; + union au_vdir_deblk_p p; + } vd_last; + + unsigned long vd_version; + unsigned long vd_jiffy; +}; + +/* ---------------------------------------------------------------------- */ + +/* dir.c */ +extern struct file_operations aufs_dir_fop; +int au_test_empty_lower(struct dentry *dentry); +int au_test_empty(struct dentry *dentry, struct au_nhash *whlist); + +/* vdir.c */ +struct au_nhash *au_nhash_new(gfp_t gfp); +void au_nhash_del(struct au_nhash *nhash); +void au_nhash_init(struct au_nhash *nhash); +void au_nhash_move(struct au_nhash *dst, struct au_nhash *src); +void au_nhash_fin(struct au_nhash *nhash); +int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, + int limit); +int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int namelen); +int au_nhash_append_wh(struct au_nhash *whlist, char *name, int namelen, + ino_t ino, unsigned int d_type, aufs_bindex_t bindex, + unsigned char shwh); +void au_vdir_free(struct au_vdir *vdir); +int au_vdir_init(struct file *file); +int au_vdir_fill_de(struct file *file, void *dirent, filldir_t filldir); + +/* ---------------------------------------------------------------------- */ + +static inline +void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino, unsigned char d_type) +{ +#ifdef CONFIG_AUFS_SHWH + wh->wh_ino = ino; + wh->wh_type = d_type; +#endif +} + +static inline void au_add_nlink(struct inode *dir, struct inode *h_dir) +{ + AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); + dir->i_nlink += h_dir->i_nlink - 2; + if (unlikely(h_dir->i_nlink < 2)) + dir->i_nlink += 2; +} + +static inline void au_sub_nlink(struct inode *dir, struct inode *h_dir) +{ + AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); + dir->i_nlink -= h_dir->i_nlink - 2; + if (unlikely(h_dir->i_nlink < 2)) + dir->i_nlink -= 2; +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DIR_H__ */ --- linux-2.6.27.orig/ubuntu/aufs/super.h +++ linux-2.6.27/ubuntu/aufs/super.h @@ -0,0 +1,494 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * super_block operations + * + * $Id: super.h,v 1.14 2008/09/15 03:14:52 sfjro Exp $ + */ + +#ifndef __AUFS_SUPER_H__ +#define __AUFS_SUPER_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include +#include "misc.h" +#include "wkq.h" + +typedef ssize_t (*au_readf_t)(struct file *, char __user *, size_t, loff_t *); +typedef ssize_t (*au_writef_t)(struct file *, const char __user *, size_t, + loff_t *); + +struct au_wbr_copyup_operations { + int (*copyup)(struct dentry *dentry); +}; + +struct au_wbr_create_operations { + int (*create)(struct dentry *dentry, int isdir); + int (*init)(struct super_block *sb); + int (*fin)(struct super_block *sb); +}; + +struct au_wbr_mfs { + struct mutex mfs_lock; /* protect this structure */ + unsigned long mfs_jiffy; + unsigned long mfs_expire; + aufs_bindex_t mfs_bindex; + + unsigned long long mfsrr_bytes; + unsigned long long mfsrr_watermark; +}; + +/* sbinfo status flags */ +/* + * set true when refresh_dirs() failed at remount time. + * then try refreshing dirs at access time again. + * if it is false, refreshing dirs at access time is unnecesary + */ +#define AuSi_FAILED_REFRESH_DIRS 1 +#define au_ftest_si(sbinfo, name) ((sbinfo)->au_si_status & AuSi_##name) +#define au_fset_si(sbinfo, name) \ + { (sbinfo)->au_si_status |= AuSi_##name; } +#define au_fclr_si(sbinfo, name) \ + { (sbinfo)->au_si_status &= ~AuSi_##name; } + +struct au_branch; +struct au_sbinfo { + /* nowait tasks in the system-wide workqueue */ + struct au_nowait_tasks si_nowait; + + struct au_rwsem si_rwsem; + + /* branch management */ + au_gen_t si_generation; + + /* see above flags */ + unsigned char au_si_status; + + aufs_bindex_t si_bend; + aufs_bindex_t si_last_br_id; + struct au_branch **si_branch; + + /* policy to select a writable branch */ + unsigned char si_wbr_copyup; + unsigned char si_wbr_create; + struct au_wbr_copyup_operations *si_wbr_copyup_ops; + struct au_wbr_create_operations *si_wbr_create_ops; + + /* round robin */ + atomic_t si_wbr_rr_next; + + /* most free space */ + struct au_wbr_mfs si_wbr_mfs; + + /* mount flags */ + /* include/asm-ia64/siginfo.h defines a macro named si_flags */ + unsigned int si_mntflags; + + /* external inode number (bitmap and translation table) */ + au_readf_t si_xread; + au_writef_t si_xwrite; + struct file *si_xib; + struct mutex si_xib_mtx; /* protect xib members */ + unsigned long *si_xib_buf; + unsigned long si_xib_last_pindex; + int si_xib_next_bit; + /* reserved for future use */ + /* unsigned long long si_xib_limit; */ /* Max xib file size */ + +#ifdef CONFIG_AUFS_HINOTIFY + struct au_branch *si_xino_def_br; +#endif + +#ifdef CONFIG_AUFS_EXPORT + /* i_generation */ + struct file *si_xigen; + /* todo: atomic_t? */ + spinlock_t si_xigen_lock; + __u32 si_xigen_next; +#endif + + /* readdir cache time, max, in HZ */ + unsigned long si_rdcache; + + /* + * If the number of whiteouts are larger than si_dirwh, leave all of + * them after au_whtmp_ren to reduce the cost of rmdir(2). + * future fsck.aufs or kernel thread will remove them later. + * Otherwise, remove all whiteouts and the dir in rmdir(2). + */ + unsigned int si_dirwh; + + /* + * rename(2) a directory with all children. + */ + /* reserved for future use */ + /* int si_rendir; */ + + /* pseudo_link list */ /* todo: dirty? */ + spinlock_t si_plink_lock; + struct list_head si_plink; + +#if defined(CONFIG_AUFS_EXPORT) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) + /* dirty, for export, async ops, and sysfs */ + spinlock_t si_mntcache_lock; + struct vfsmount *si_mntcache; /* no get/put */ +#endif + + /* + * sysfs and lifetime management. + * this is not a small structure and it may be a waste of memory in case + * of sysfs is disabled, particulary when many aufs-es are mounted. + */ + struct kobject si_kobj; + +#ifdef CONFIG_AUFS_ROBR + /* locked vma list for mmap() */ /* todo: dirty? */ + spinlock_t si_lvma_lock; + struct list_head si_lvma; +#endif + +#ifdef CONFIG_AUFS_EXPORT /* reserved for future use */ + struct path si_xinodir; +#endif + + /* dirty, necessary for unmounting, sysfs and sysrq */ + struct super_block *si_sb; +}; + +/* ---------------------------------------------------------------------- */ + +/* policy to select one among writable branches */ +#define AuWbrCopyup(sbinfo, args...) \ + (sbinfo)->si_wbr_copyup_ops->copyup(args) +#define AuWbrCreate(sbinfo, args...) \ + (sbinfo)->si_wbr_create_ops->create(args) + +/* flags for si_read_lock()/aufs_read_lock()/di_read_lock() */ +#define AuLock_DW 1 /* write-lock dentry */ +#define AuLock_IR (1 << 1) /* read-lock inode */ +#define AuLock_IW (1 << 2) /* write-lock inode */ +#define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */ +#define AuLock_DIR (1 << 4) /* target is a dir */ +#define au_ftest_lock(flags, name) ((flags) & AuLock_##name) +#define au_fset_lock(flags, name) { (flags) |= AuLock_##name; } +#define au_fclr_lock(flags, name) { (flags) &= ~AuLock_##name; } + +/* ---------------------------------------------------------------------- */ + +/* super.c */ +extern struct file_system_type aufs_fs_type; +struct inode *au_iget_locked(struct super_block *sb, ino_t ino); + +/* sbinfo.c */ +void au_si_free(struct kobject *kobj); +int au_si_alloc(struct super_block *sb); +struct au_branch *au_sbr(struct super_block *sb, aufs_bindex_t bindex); +au_gen_t au_sigen_inc(struct super_block *sb); +int au_find_bindex(struct super_block *sb, struct au_branch *br); + +void aufs_read_lock(struct dentry *dentry, int flags); +void aufs_read_unlock(struct dentry *dentry, int flags); +void aufs_write_lock(struct dentry *dentry); +void aufs_write_unlock(struct dentry *dentry); +void aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int isdir); +void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2); + +aufs_bindex_t au_new_br_id(struct super_block *sb); + +/* wbr_policy.c */ +extern struct au_wbr_copyup_operations au_wbr_copyup_ops[]; +extern struct au_wbr_create_operations au_wbr_create_ops[]; +int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst); + +/* ---------------------------------------------------------------------- */ + +#if defined(CONFIG_AUFS_EXPORT) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) +static inline void au_mnt_init(struct au_sbinfo *sbinfo, struct vfsmount *mnt) +{ + spin_lock_init(&sbinfo->si_mntcache_lock); + sbinfo->si_mntcache = mnt; +} + +static inline void au_mnt_reset(struct au_sbinfo *sbinfo) +{ + spin_lock(&sbinfo->si_mntcache_lock); + sbinfo->si_mntcache = NULL; + spin_unlock(&sbinfo->si_mntcache_lock); +} +#else +static inline void au_mnt_init(struct au_sbinfo *sbinfo, struct vfsmount *mnt) +{ + /* emptr */ +} + +static inline void au_mnt_reset(struct au_sbinfo *sbinfo) +{ + /* emptr */ +} +#endif /* EXPORT && < 2.6.26 */ + +/* ---------------------------------------------------------------------- */ + +static inline struct au_sbinfo *au_sbi(struct super_block *sb) +{ + return sb->s_fs_info; +} + +static inline const char *au_sbtype(struct super_block *sb) +{ + return sb->s_type->name; +} + +static inline int au_test_aufs(struct super_block *sb) +{ + return (sb->s_magic == AUFS_SUPER_MAGIC); +} + +static inline int au_test_nfs(struct super_block *sb) +{ +#ifdef CONFIG_AUFS_BR_NFS + return (sb->s_magic == NFS_SUPER_MAGIC); +#else + return 0; +#endif +} + +static inline int au_test_fuse(struct super_block *sb) +{ +#ifdef CONFIG_AUFS_WORKAROUND_FUSE + return (sb->s_magic == FUSE_SUPER_MAGIC); +#else + return 0; +#endif +} + +static inline int au_test_xfs(struct super_block *sb) +{ +#ifdef CONFIG_AUFS_BR_XFS + return (sb->s_magic == XFS_SB_MAGIC); +#else + return 0; +#endif +} + +static inline int au_test_tmpfs(struct super_block *sb) +{ +#ifdef CONFIG_TMPFS + return (sb->s_magic == TMPFS_MAGIC); +#else + return 0; +#endif +} + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_HINOTIFY +static inline void au_xino_def_br_set(struct au_branch *br, + struct au_sbinfo *sbinfo) +{ + sbinfo->si_xino_def_br = br; +} + +static inline struct au_branch *au_xino_def_br(struct au_sbinfo *sbinfo) +{ + return sbinfo->si_xino_def_br; +} +#else +static inline void au_xino_def_br_set(struct au_branch *br, + struct au_sbinfo *sbinfo) +{ + /* empty */ +} + +static inline struct au_branch *au_xino_def_br(struct au_sbinfo *sbinfo) +{ + return NULL; +} +#endif + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_EXPORT +void au_export_init(struct super_block *sb); + +static inline int au_test_nfsd(struct task_struct *tsk) +{ + return (!tsk->mm && !strcmp(tsk->comm, "nfsd")); +} + +static inline void au_nfsd_lockdep_off(void) +{ + if (au_test_nfsd(current)) + lockdep_off(); +} + +static inline void au_nfsd_lockdep_on(void) +{ + if (au_test_nfsd(current)) + lockdep_on(); +} + +static inline void au_export_put(struct au_sbinfo *sbinfo) +{ + path_put(&sbinfo->si_xinodir); +} + +int au_xigen_inc(struct inode *inode); +int au_xigen_new(struct inode *inode); +int au_xigen_set(struct super_block *sb, struct file *base); +void au_xigen_clr(struct super_block *sb); + +#else +static inline void au_export_init(struct super_block *sb) +{ + /* nothing */ +} + +static inline int au_test_nfsd(struct task_struct *tsk) +{ + return 0; +} + +#define au_nfsd_lockdep_off() do {} while (0) +#define au_nfsd_lockdep_on() do {} while (0) + +static inline void au_export_put(struct au_sbinfo *sbinfo) +{ + /* nothing */ +} + +static inline int au_xigen_inc(struct inode *inode) +{ + return 0; +} + +static inline int au_xigen_new(struct inode *inode) +{ + return 0; +} + +static inline int au_xigen_set(struct super_block *sb, struct file *base) +{ + return 0; +} + +static inline void au_xigen_clr(struct super_block *sb) +{ + /* empty */ +} +#endif /* CONFIG_AUFS_EXPORT */ + +#ifdef CONFIG_AUFS_ROBR +static inline int au_test_nested(struct super_block *h_sb) +{ + return 0; +} + +static inline void au_robr_lvma_init(struct au_sbinfo *sbinfo) +{ + spin_lock_init(&sbinfo->si_lvma_lock); + INIT_LIST_HEAD(&sbinfo->si_lvma); +} +#else +static inline int au_test_nested(struct super_block *h_sb) +{ + int err = 0; + if (unlikely(au_test_aufs(h_sb))) { + err = -EINVAL; + AuTraceErr(err); + } + return err; +} + +static inline void au_robr_lvma_init(struct au_sbinfo *sbinfo) +{ + /* empty */ +} +#endif /* CONFIG_AUFS_ROBR */ + +/* ---------------------------------------------------------------------- */ + +/* lock superblock. mainly for entry point functions */ +/* + * si_noflush_read_lock, si_noflush_write_lock, + * si_read_unlock, si_write_unlock, si_downgrade_lock + */ +AuSimpleLockRwsemFuncs(si_noflush, struct super_block *sb, + au_sbi(sb)->si_rwsem); +AuSimpleUnlockRwsemFuncs(si, struct super_block *sb, au_sbi(sb)->si_rwsem); + +static inline void si_read_lock(struct super_block *sb, int flags) +{ + if (au_ftest_lock(flags, FLUSH)) + au_nwt_flush(&au_sbi(sb)->si_nowait); + si_noflush_read_lock(sb); +} + +static inline void si_write_lock(struct super_block *sb) +{ + au_nwt_flush(&au_sbi(sb)->si_nowait); + si_noflush_write_lock(sb); +} + +static inline int si_read_trylock(struct super_block *sb, int flags) +{ + if (au_ftest_lock(flags, FLUSH)) + au_nwt_flush(&au_sbi(sb)->si_nowait); + return si_noflush_read_trylock(sb); +} + +static inline int si_write_trylock(struct super_block *sb, int flags) +{ + if (au_ftest_lock(flags, FLUSH)) + au_nwt_flush(&au_sbi(sb)->si_nowait); + return si_noflush_write_trylock(sb); +} + +/* to debug easier, do not make them inlined functions */ +#define SiMustReadLock(sb) AuRwMustReadLock(&au_sbi(sb)->si_rwsem) +#define SiMustWriteLock(sb) AuRwMustWriteLock(&au_sbi(sb)->si_rwsem) +#define SiMustAnyLock(sb) AuRwMustAnyLock(&au_sbi(sb)->si_rwsem) + +/* ---------------------------------------------------------------------- */ + +static inline aufs_bindex_t au_sbend(struct super_block *sb) +{ + SiMustAnyLock(sb); + return au_sbi(sb)->si_bend; +} + +static inline unsigned int au_mntflags(struct super_block *sb) +{ + SiMustAnyLock(sb); + return au_sbi(sb)->si_mntflags; +} + +static inline au_gen_t au_sigen(struct super_block *sb) +{ + SiMustAnyLock(sb); + return au_sbi(sb)->si_generation; +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_SUPER_H__ */ --- linux-2.6.27.orig/ubuntu/aufs/i_op_ren.c +++ linux-2.6.27/ubuntu/aufs/i_op_ren.c @@ -0,0 +1,1211 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * inode operation (rename entry) + * todo: this is crazy monster + * + * $Id: i_op_ren.c,v 1.14 2008/09/22 03:52:12 sfjro Exp $ + */ + +#include "aufs.h" + +enum { SRC, DST }; + +#define AuRen_ISDIR 1 +#define AuRen_ISSAMEDIR (1 << 1) +#define AuRen_WHSRC (1 << 2) +#define AuRen_WHDST (1 << 3) +#define AuRen_DLGT (1 << 4) +#define AuRen_VFSLOCK (1 << 5) +#define AuRen_PINNED (1 << 6) +#define au_ftest_ren(flags, name) ((flags) & AuRen_##name) +#define au_fset_ren(flags, name) { (flags) |= AuRen_##name; } +#define au_fclr_ren(flags, name) { (flags) &= ~AuRen_##name; } +#ifndef CONFIG_AUFS_DLGT +#undef AuRen_DLGT +#define AuRen_DLGT 0 +#endif + +struct au_ren_args { + /* original args */ + struct dentry *src_dentry, *dentry; + struct inode *src_dir, *dir; + + struct dentry *h_dentry[2], *h_parent[2], *h_trap, *h_locked[2]; + /* todo: remove them */ + struct dentry *parent[2], *gparent[2]; + struct au_pin pin[2]; + struct au_nhash whlist; + aufs_bindex_t btgt, bstart[2]; + /* do_rename() only */ + unsigned char need_diropq, bycpup; + struct super_block *sb; + unsigned int flags; + unsigned int mnt_flags; + struct au_ndx ndx; + + /* do_rename() only */ +#ifdef CONFIG_AUFS_BR_NFS + struct au_hin_ignore ign[3]; +#else + struct au_hin_ignore ign[2]; +#endif + struct vfsub_args vargs; + struct au_whtmp_rmdir_args *thargs; + struct dentry *wh_dentry[2], *h_dst, *h_src; +}; + +/* ---------------------------------------------------------------------- */ + +#define RevertFailure(fmt, args...) do { \ + AuIOErrWhck("revert failure: " fmt " (%d, %d)\n", \ + ##args, err, rerr); \ + err = -EIO; \ + } while (0) + +static noinline_for_stack +void au_ren_rev_diropq(int err, struct au_ren_args *a) +{ + int rerr; + struct mutex *h_mtx; + + /* lock inode simply since inotify is not set to h_inode. */ + h_mtx = &au_h_dptr(a->src_dentry, a->btgt)->d_inode->i_mutex; + mutex_lock_nested(h_mtx, AuLsc_I_CHILD); + rerr = au_diropq_remove(a->src_dentry, a->btgt, + au_ftest_ren(a->flags, DLGT)); + mutex_unlock(h_mtx); + if (rerr) + RevertFailure("remove diropq %.*s", AuDLNPair(a->src_dentry)); +} + +static noinline_for_stack +void au_ren_rev_rename(int err, struct au_ren_args *a) +{ + int rerr; + struct dentry *h_d; + struct qstr *name = &a->src_dentry->d_name; + + h_d = au_lkup_one(name->name, a->h_parent[SRC], name->len, &a->ndx); + rerr = PTR_ERR(h_d); + if (IS_ERR(h_d)) { + RevertFailure("au_lkup_one %.*s", AuDLNPair(a->src_dentry)); + return; + } + + AuDebugOn(h_d->d_inode); + vfsub_args_reinit(&a->vargs); + vfsub_ign_hinode(&a->vargs, IN_MOVED_FROM, au_pinned_hdir(a->pin + DST, + a->btgt)); + vfsub_ign_hinode(&a->vargs, IN_MOVED_TO, au_pinned_hdir(a->pin + SRC, + a->btgt)); + rerr = vfsub_rename(au_pinned_h_dir(a->pin + DST), + au_h_dptr(a->src_dentry, a->btgt), + au_pinned_h_dir(a->pin + SRC), h_d, &a->vargs); + d_drop(h_d); + dput(h_d); + /* au_set_h_dptr(a->src_dentry, a->btgt, NULL); */ + if (rerr) + RevertFailure("rename %.*s", AuDLNPair(a->src_dentry)); +} + +static noinline_for_stack +void au_ren_rev_cpup(int err, struct au_ren_args *a) +{ + int rerr; + + vfsub_args_reinit(&a->vargs); + vfsub_ign_hinode(&a->vargs, IN_DELETE, au_pinned_hdir(a->pin + DST, + a->btgt)); + rerr = vfsub_unlink(au_pinned_h_dir(a->pin + DST), a->h_dentry[DST], + &a->vargs); + au_set_h_dptr(a->src_dentry, a->btgt, NULL); + au_set_dbstart(a->src_dentry, a->bstart[SRC]); + if (rerr) + RevertFailure("unlink %.*s", AuDLNPair(a->h_dentry[DST])); +} + +static noinline_for_stack +void au_ren_rev_whtmp(int err, struct au_ren_args *a) +{ + int rerr; + struct dentry *h_d; + struct mutex *h_mtx; + struct qstr *name = &a->dentry->d_name; + + h_d = au_lkup_one(name->name, a->h_parent[DST], name->len, &a->ndx); + rerr = PTR_ERR(h_d); + if (IS_ERR(h_d)) { + RevertFailure("lookup %.*s", AuLNPair(name)); + return; + } + if (h_d->d_inode) { + d_drop(h_d); + dput(h_d); + return; + } + + h_mtx = &a->h_dst->d_inode->i_mutex; + mutex_lock_nested(h_mtx, AuLsc_I_CHILD); + au_hin_resume(au_hi(a->src_dentry->d_inode, a->btgt)); + mutex_unlock(h_mtx); + vfsub_args_reinit(&a->vargs); + vfsub_ign_hinode(&a->vargs, IN_MOVED_TO | IN_MOVED_FROM, + au_pinned_hdir(a->pin + DST, a->btgt)); + rerr = vfsub_rename(au_pinned_h_dir(a->pin + DST), a->h_dst, + au_pinned_h_dir(a->pin + DST), h_d, &a->vargs); + d_drop(h_d); + dput(h_d); + if (!rerr) { + au_set_h_dptr(a->dentry, a->btgt, NULL); + au_set_h_dptr(a->dentry, a->btgt, dget(a->h_dst)); + } else + RevertFailure("rename %.*s", AuDLNPair(a->h_dst)); +} + +static noinline_for_stack +void au_ren_rev_whsrc(int err, struct au_ren_args *a) +{ + int rerr; + + rerr = au_wh_unlink_dentry(au_pinned_hdir(a->pin + SRC, a->btgt), + a->wh_dentry[SRC], a->src_dentry, /*dlgt*/0); + if (rerr) + RevertFailure("unlink %.*s", AuDLNPair(a->wh_dentry[SRC])); +} +#undef RevertFailure + +/* ---------------------------------------------------------------------- */ + +static /* noinline_for_stack */ +int au_ren_or_cpup(struct au_ren_args *a) +{ + int err; + + AuTraceEnter(); + + if (au_dbstart(a->src_dentry) == a->btgt) { + if (a->need_diropq && au_dbdiropq(a->src_dentry) == a->btgt) + a->need_diropq = 0; + vfsub_ign_hinode(&a->vargs, IN_MOVED_FROM, + au_pinned_hdir(a->pin + SRC, a->btgt)); + vfsub_ign_hinode(&a->vargs, IN_MOVED_TO, + au_pinned_hdir(a->pin + DST, a->btgt)); + /* nfs_rename() calls d_delete() */ + if (au_test_nfs(au_pinned_h_dir(a->pin + DST)->i_sb) + && a->h_dentry[DST]->d_inode + && (S_ISDIR(a->h_dentry[DST]->d_inode->i_mode) + || atomic_read(&a->h_dentry[DST]->d_count) <= 2)) + vfsub_ign_hinode(&a->vargs, IN_DELETE, + au_pinned_hdir(a->pin + DST, a->btgt)); + AuDebugOn(au_dbstart(a->src_dentry) != a->btgt); + err = vfsub_rename(au_pinned_h_dir(a->pin + SRC), + au_h_dptr(a->src_dentry, a->btgt), + au_pinned_h_dir(a->pin + DST), + a->h_dentry[DST], &a->vargs); + } else { + struct mutex *h_mtx = &a->h_dentry[SRC]->d_inode->i_mutex; + + a->bycpup = 1; + mutex_lock_nested(h_mtx, AuLsc_I_CHILD); + au_set_dbstart(a->src_dentry, a->btgt); + au_set_h_dptr(a->src_dentry, a->btgt, dget(a->h_dentry[DST])); + err = au_sio_cpup_single(a->src_dentry, a->btgt, a->bstart[SRC], + -1, !AuCpup_DTIME, a->parent[DST]); + if (unlikely(err)) { + au_set_h_dptr(a->src_dentry, a->btgt, NULL); + au_set_dbstart(a->src_dentry, a->bstart[SRC]); + } + mutex_unlock(h_mtx); + } + + return err; +} + +static /* noinline_for_stack */ +int au_ren_del_whtmp(struct au_ren_args *a) +{ + int err; + + AuTraceEnter(); + + if (au_test_nfs(a->h_dst->d_sb) + || !au_nhash_test_longer_wh(&a->whlist, a->btgt, + au_sbi(a->sb)->si_dirwh)) { + err = au_whtmp_rmdir(a->dir, a->btgt, a->h_dst, &a->whlist); + if (unlikely(err)) + AuWarn("failed removing whtmp dir %.*s (%d), " + "ignored.\n", AuDLNPair(a->h_dst), err); + } else { + au_whtmp_kick_rmdir(a->dir, a->btgt, a->h_dst, &a->whlist, + a->thargs); + dput(a->h_dst); + a->thargs = NULL; + } + + return 0; +} + +static /* noinline_for_stack */ +int au_ren_diropq(struct au_ren_args *a) +{ + int err; + struct dentry *diropq; + struct mutex *h_mtx; + + AuTraceEnter(); + + err = 0; + h_mtx = &au_h_dptr(a->src_dentry, a->btgt)->d_inode->i_mutex; + mutex_lock_nested(h_mtx, AuLsc_I_CHILD); + diropq = au_diropq_create(a->src_dentry, a->btgt, + au_ftest_ren(a->flags, DLGT)); + mutex_unlock(h_mtx); + if (IS_ERR(diropq)) + err = PTR_ERR(diropq); + dput(diropq); + + return err; +} + +static /* noinline_for_stack */ +int do_rename(struct au_ren_args *a) +{ + int err; + aufs_bindex_t bindex, bend; + struct dentry *h_d; + + LKTRTrace("%.*s/%.*s, %.*s/%.*s, " + "hd{%p, %p}, hp{%p, %p}, wh %p, btgt %d, bstart{%d, %d}, " + "flags 0x%x\n", + AuDLNPair(a->parent[SRC]), AuDLNPair(a->src_dentry), + AuDLNPair(a->parent[DST]), AuDLNPair(a->dentry), + a->h_dentry[SRC], a->h_dentry[DST], + a->h_parent[SRC], a->h_parent[DST], + &a->whlist, a->btgt, + a->bstart[SRC], a->bstart[DST], + a->flags); + + /* prepare workqueue args */ + if (au_ftest_ren(a->flags, ISDIR) && a->h_dentry[DST]->d_inode) { + err = -ENOMEM; + a->thargs = kmalloc(sizeof(*a->thargs), GFP_NOFS); + if (unlikely(!a->thargs)) + goto out; + a->h_dst = dget(a->h_dentry[DST]); + } + + a->ndx.nfsmnt = au_nfsmnt(a->sb, a->btgt); + if (unlikely(au_ftest_ren(a->flags, DLGT))) + au_fset_ndx(a->ndx.flags, DLGT); + + /* create whiteout for src_dentry */ + if (au_ftest_ren(a->flags, WHSRC)) { + a->wh_dentry[SRC] = au_wh_create(a->src_dentry, a->btgt, + a->h_parent[SRC], &a->ndx); + err = PTR_ERR(a->wh_dentry[SRC]); + if (IS_ERR(a->wh_dentry[SRC])) + goto out_thargs; + } + + /* lookup whiteout for dentry */ + if (au_ftest_ren(a->flags, WHDST)) { + h_d = au_wh_lkup(a->h_parent[DST], &a->dentry->d_name, &a->ndx); + err = PTR_ERR(h_d); + if (IS_ERR(h_d)) + goto out_whsrc; + if (!h_d->d_inode) + dput(h_d); + else + a->wh_dentry[DST] = h_d; + } + + /* rename dentry to tmpwh */ + if (a->thargs) { + struct au_hinode *hinode; + + AuDbgDentry(a->h_dentry[DST]); + err = au_whtmp_ren(a->dir, a->btgt, a->h_dentry[DST]); + if (unlikely(err)) + goto out_whdst; + AuDbgDentry(a->h_dentry[DST]); + hinode = au_hi(a->dentry->d_inode, a->btgt); + /* todo: bad approach? */ + mutex_lock_nested(&hinode->hi_inode->i_mutex, AuLsc_I_CHILD); + au_hin_suspend(hinode); + mutex_unlock(&hinode->hi_inode->i_mutex); + au_set_h_dptr(a->dentry, a->btgt, NULL); + AuDbgDentry(a->h_dentry[DST]); + err = au_lkup_neg(a->dentry, a->btgt); + if (unlikely(err)) + goto out_whtmp; + a->h_dentry[DST] = au_h_dptr(a->dentry, a->btgt); + } + + /* cpup src */ + if (a->h_dentry[DST]->d_inode && a->bstart[SRC] != a->btgt) { + struct mutex *h_mtx = &a->h_dentry[SRC]->d_inode->i_mutex; + + mutex_lock_nested(h_mtx, AuLsc_I_CHILD); + err = au_sio_cpup_simple(a->src_dentry, a->btgt, -1, + !AuCpup_DTIME); + mutex_unlock(h_mtx); + if (unlikely(err)) + goto out_whtmp; + } + + /* rename by vfs_rename or cpup */ + a->need_diropq = au_ftest_ren(a->flags, ISDIR) + && (a->wh_dentry[DST] + || au_dbdiropq(a->dentry) == a->btgt + /* hide the lower to keep xino */ + || a->btgt < au_dbend(a->dentry) + || au_opt_test(a->mnt_flags, ALWAYS_DIROPQ)); + a->bycpup = 0; + vfsub_args_init(&a->vargs, a->ign, au_ftest_ren(a->flags, DLGT), 0); + err = au_ren_or_cpup(a); + if (unlikely(err)) + goto out_whtmp; + + /* make dir opaque */ + if (a->need_diropq) { + err = au_ren_diropq(a); + if (unlikely(err)) + goto out_rename; + } + + /* update target timestamps */ + AuDebugOn(au_dbstart(a->src_dentry) != a->btgt); + a->h_src = au_h_dptr(a->src_dentry, a->btgt); + au_update_fuse_h_inode(NULL, a->h_src); /*ignore*/ + /* fsstack_copy_attr_atime(a->src_dentry->d_inode, a->h_src->d_inode); */ + a->src_dentry->d_inode->i_ctime = a->h_src->d_inode->i_ctime; + + /* remove whiteout for dentry */ + if (a->wh_dentry[DST]) { + err = au_wh_unlink_dentry(au_pinned_hdir(a->pin + DST, a->btgt), + a->wh_dentry[DST], a->dentry, + /*dlgt*/0); + if (unlikely(err)) + goto out_diropq; + } + + /* remove whtmp */ + if (a->thargs) + /* ignore this error */ + au_ren_del_whtmp(a); + + err = 0; + goto out_success; + + out_diropq: + if (a->need_diropq) + au_ren_rev_diropq(err, a); + out_rename: + if (!a->bycpup) + au_ren_rev_rename(err, a); + else + au_ren_rev_cpup(err, a); + out_whtmp: + if (a->thargs) + au_ren_rev_whtmp(err, a); + out_whdst: + dput(a->wh_dentry[DST]); + a->wh_dentry[DST] = NULL; + out_whsrc: + if (a->wh_dentry[SRC]) + au_ren_rev_whsrc(err, a); + d_drop(a->src_dentry); + bend = au_dbend(a->src_dentry); + for (bindex = au_dbstart(a->src_dentry); bindex <= bend; bindex++) { + h_d = au_h_dptr(a->src_dentry, bindex); + if (h_d) + d_drop(h_d); + } + d_drop(a->dentry); + bend = au_dbend(a->dentry); + for (bindex = au_dbstart(a->dentry); bindex <= bend; bindex++) { + h_d = au_h_dptr(a->dentry, bindex); + if (h_d) + d_drop(h_d); + } + au_update_dbstart(a->dentry); + if (a->thargs) + d_drop(a->h_dst); + out_success: + dput(a->wh_dentry[SRC]); + dput(a->wh_dentry[DST]); + out_thargs: + if (a->thargs) { + dput(a->h_dst); + kfree(a->thargs); + } + out: + AuTraceErr(err); + return err; +} + +/* + * test if @dentry dir can be rename destination or not. + * success means, it is a logically empty dir. + */ +static int may_rename_dstdir(struct dentry *dentry, aufs_bindex_t btgt, + struct au_nhash *whlist) +{ + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + + return au_test_empty(dentry, whlist); +} + +/* + * test if @dentry dir can be rename source or not. + * if it can, return 0 and @children is filled. + * success means, + * - or, it is a logically empty dir. + * - or, it exists on writable branch and has no children including whiteouts + * on the lower branch. + */ +static int may_rename_srcdir(struct dentry *dentry, aufs_bindex_t btgt) +{ + int err; + aufs_bindex_t bstart; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + + bstart = au_dbstart(dentry); + if (bstart != btgt) { + struct au_nhash *whlist; + + whlist = au_nhash_new(GFP_NOFS); + err = PTR_ERR(whlist); + if (IS_ERR(whlist)) + goto out; + err = au_test_empty(dentry, whlist); + au_nhash_del(whlist); + goto out; + } + + if (bstart == au_dbtaildir(dentry)) + return 0; /* success */ + + err = au_test_empty_lower(dentry); + + out: + if (/* unlikely */(err == -ENOTEMPTY)) { + AuWarn1("renaming dir who has child(ren) on multiple branches," + " is not supported\n"); + err = -EXDEV; + } + AuTraceErr(err); + return err; +} + +/* mainly for link(2) and rename(2) */ +int au_wbr(struct dentry *dentry, aufs_bindex_t btgt) +{ + aufs_bindex_t bdiropq, bwh; + struct dentry *parent; + + LKTRTrace("%.*s, b%d\n", AuDLNPair(dentry), btgt); + parent = dentry->d_parent; + IMustLock(parent->d_inode); /* dir is locked */ + + bdiropq = au_dbdiropq(parent); + bwh = au_dbwh(dentry); + if (au_br_rdonly(au_sbr(dentry->d_sb, btgt)) + || (0 <= bdiropq && bdiropq < btgt) + || (0 <= bwh && bwh < btgt)) + btgt = -1; + + LKTRTrace("btgt %d\n", btgt); + return btgt; +} + +/* + * simple tests for rename. + * following the checks in vfs, plus the parent-child relationship. + */ +static int au_may_ren(struct au_ren_args *a) +{ + int err; + struct inode *h_inode; + + AuTraceEnter(); + + if (a->bstart[SRC] == a->btgt) { + err = au_may_del(a->src_dentry, a->btgt, a->h_parent[SRC], + au_ftest_ren(a->flags, ISDIR), &a->ndx); + if (unlikely(err)) + goto out; + err = -EINVAL; + if (unlikely(a->h_dentry[SRC] == a->h_trap)) + goto out; + } + + err = 0; + if (a->bstart[DST] != a->btgt) + goto out; + + err = -EIO; + h_inode = a->h_dentry[DST]->d_inode; + if (!a->dentry->d_inode) { + if (unlikely(h_inode)) + goto out; + err = au_may_add(a->dentry, a->btgt, a->h_parent[DST], + au_ftest_ren(a->flags, ISDIR), &a->ndx); + } else { + if (unlikely(!h_inode || !h_inode->i_nlink)) + goto out; + err = au_may_del(a->dentry, a->btgt, a->h_parent[DST], + au_ftest_ren(a->flags, ISDIR), &a->ndx); + if (unlikely(err)) + goto out; + err = -ENOTEMPTY; + if (unlikely(a->h_dentry[DST] == a->h_trap)) + goto out; + err = 0; + } + + out: + if (unlikely(err == -ENOENT || err == -EEXIST)) + err = -EIO; + AuTraceErr(err); + return err; +} + +/* + * locking order + * (VFS) + * - src_dir and dir by lock_rename() + * - inode if exitsts + * (aufs) + * - lock all + * + src_dentry and dentry by aufs_read_and_write_lock2() which calls, + * + si_read_lock + * + di_write_lock2_child() + * + di_write_lock_child() + * + ii_write_lock_child() + * + di_write_lock_child2() + * + ii_write_lock_child2() + * + src_parent and parent + * + di_write_lock_parent() + * + ii_write_lock_parent() + * + di_write_lock_parent2() + * + ii_write_lock_parent2() + * + if udab=inotify is specified, lock grand parents (crazy) + * + di_read_lock_gparent() + * + ii_read_lock_gparent() + * + di_read_lock_gparent2() + * + ii_read_lock_gparent2() + * + mutex_lock_gparent() + * + mutex_lock_gparent2() + * + lower src_dir and dir by vfsub_lock_rename()? + * + verify the every relations between child, parent and grand parent. if any + * of them failed, unlock all and return -EBUSY. + */ +static void au_ren_pin_init(struct au_pin *first, struct dentry *d1, + struct au_pin *next, struct dentry *d2) +{ + AuTraceEnter(); + + /* AuLsc_DI_PARENT3 is for higher gparent initially */ + au_pin_init(first, d1, /*di_locked*/1, AuLsc_DI_PARENT2, + AuLsc_I_PARENT2, /*do_gp*/1); + /* AuLsc_DI_PARENT4 is for lower gparent initially */ + au_pin_init(next, d2, /*di_locked*/1, AuLsc_DI_PARENT3, + AuLsc_I_PARENT4, /*do_gp*/1); +} + +static void au_ren_fake_pin(struct au_ren_args *a) +{ + int i; + struct au_pin1 *p; + struct inode *h_i; + + AuTraceEnter(); + + /* they increment the ref counter */ + for (i = 0; i < 2; i++) { + p = a->pin[i].pin + AuPin_PARENT; + au_pin_set_parent(a->pin + i, a->parent[i]); + dput(a->parent[i]); + h_i = a->h_parent[i]->d_inode; + au_pin_set_h_dir(a->pin + i, h_i); + iput(h_i); + + if (!a->gparent[i]) { + au_pin_set_gparent(a->pin + i, NULL); + au_pin_set_h_gdir(a->pin + i, NULL); + } else { + au_pin_set_gparent(a->pin + i, a->gparent[i]); + dput(a->gparent[i]); + h_i = au_h_iptr(a->gparent[i]->d_inode, a->btgt); + au_pin_set_h_gdir(a->pin + i, h_i); + iput(h_i); + } + } +} + +/* crazy */ +/* cf. i_op.c: au_do_pin() */ +static int au_ren_pin4(int higher, int lower, struct au_ren_args *a) +{ + int err, i, lsc; + struct au_pin *p; + struct au_pin1 *p4[4]; + struct inode *h_dir; + + LKTRTrace("%d, %d\n", higher, lower); + + p = a->pin + higher; + p4[0] = au_pin_gp(p); /* highest */ + p4[1] = p->pin + AuPin_PARENT; + p = a->pin + lower; + p4[2] = au_pin_gp(p); + p4[3] = p->pin + AuPin_PARENT; + + if (a->gparent[higher]) { + au_pin_do_set_parent(p4[0], a->gparent[higher]); + au_pin_do_set_dentry(p4[0], a->parent[higher]); + } + au_pin_do_set_parent(p4[1], a->parent[higher]); + if (a->gparent[lower]) { + au_pin_do_set_parent(p4[2], a->gparent[lower]); + au_pin_do_set_dentry(p4[2], a->parent[lower]); + } + au_pin_do_set_parent(p4[3], a->parent[lower]); + + DiMustWriteLock(p4[3]->parent); + di_write_unlock(p4[1]->parent); + if (p4[2]->parent) + di_read_lock_parent2(p4[2]->parent, AuLock_IR); + di_write_lock_parent3(p4[1]->parent); + if (p4[0]->parent) + di_read_lock_parent4(p4[0]->parent, AuLock_IR); + + lsc = AuLsc_I_PARENT; + for (i = 0; i < 4; i++, lsc++) { + if (p4[i]->parent) { + h_dir = au_h_iptr(p4[i]->parent->d_inode, a->btgt); + au_pin_do_set_h_dir(p4[i], h_dir); + mutex_lock_nested(&h_dir->i_mutex, lsc); + } + } + + err = 0; + AuTraceErr(err); + return err; +} + +static struct dentry *au_ren_pin3(int higher, int lower, struct au_ren_args *a) +{ + struct dentry *h_trap; + struct au_pin *p; + int err; + + LKTRTrace("%d, %d\n", higher, lower); + + p = a->pin + higher; + err = au_do_pin(p->pin + AuPin_PARENT, au_pin_gp(p), a->btgt, + /*do_gp*/1); + h_trap = ERR_PTR(err); + if (unlikely(err)) + goto out; + p = a->pin + lower; + err = au_do_pin(p->pin + AuPin_PARENT, NULL, a->btgt, /*do_gp*/0); + h_trap = ERR_PTR(err); + if (unlikely(err)) { + au_do_unpin(p->pin + AuPin_PARENT, au_pin_gp(p)); + goto out; + } + h_trap = au_pinned_h_parent(p, a->btgt); + + out: + AuTraceErrPtr(h_trap); + return h_trap; +} + +static struct dentry *au_ren_pin(struct au_ren_args *a) +{ + struct dentry *h_trap; + struct inode *h_gdir; + int err, i, same_gp; + + AuTraceEnter(); + AuDebugOn(!au_opt_test(a->mnt_flags, UDBA_INOTIFY)); + + vfsub_lock_rename_mutex(a->h_dentry[SRC]->d_sb); + au_fset_ren(a->flags, VFSLOCK); + + /* gdir is not locked */ + same_gp = 0; + if (!IS_ROOT(a->parent[SRC])) + a->gparent[SRC] = dget_parent(a->parent[SRC]); + if (!IS_ROOT(a->parent[DST])) { + a->gparent[DST] = dget_parent(a->parent[DST]); + same_gp = (a->gparent[SRC] == a->gparent[DST]); + } + + /* + * patterns + * - gparent[SRC] is parent[DST] + * - parent[SRC] is gparent[DST] + * - gparent[SRC] is gparent[DST] + * - gparent[SRC] is a descendant of parent[DST] + * - parent[SRC] is an ancestor of gparent[DST] + * - not within grand parent range + */ + err = 0; + h_trap = ERR_PTR(-EBUSY); + if (a->gparent[SRC] == a->parent[DST]) { + LKTRLabel(here); + au_ren_pin_init(a->pin + DST, a->dentry, a->pin + SRC, + a->src_dentry); + h_trap = au_ren_pin3(DST, SRC, a); + if (!IS_ERR(h_trap)) { + h_gdir = au_pinned_h_dir(a->pin + DST); + err = au_verify_parent(a->h_parent[SRC], h_gdir); + if (unlikely(err)) + h_trap = ERR_PTR(-EBUSY); + } + } else if (a->parent[SRC] == a->gparent[DST] || same_gp) { + LKTRLabel(here); + au_ren_pin_init(a->pin + SRC, a->src_dentry, a->pin + DST, + a->dentry); + h_trap = au_ren_pin3(SRC, DST, a); + if (!IS_ERR(h_trap)) { + if (!same_gp) + h_gdir = au_pinned_h_dir(a->pin + SRC); + else + h_gdir = au_pinned_h_gdir(a->pin + SRC); + err = au_verify_parent(a->h_parent[DST], h_gdir); + if (unlikely(err)) + h_trap = ERR_PTR(-EBUSY); + } + } else if (a->gparent[SRC] + && (h_trap = au_test_subdir(a->gparent[SRC], + a->parent[DST]))) { + LKTRLabel(here); + au_ren_pin_init(a->pin + DST, a->dentry, a->pin + SRC, + a->src_dentry); + if (a->gparent[DST]) { + err = au_ren_pin4(DST, SRC, a); + if (unlikely(err)) + h_trap = ERR_PTR(err); + } else { + struct dentry *t; + t = au_ren_pin3(DST, SRC, a); + AuDebugOn(t == h_trap); + } + } else /* if (a->gparent[DST] + && (h_trap = au_test_subdir(a->gparent[DST], + a->parent[SRC]))) */ { + LKTRLabel(here); + h_trap = NULL; + if (a->gparent[DST]) + h_trap = au_test_subdir(a->gparent[DST], + a->parent[SRC]); + au_ren_pin_init(a->pin + SRC, a->src_dentry, a->pin + DST, + a->dentry); + err = au_ren_pin4(SRC, DST, a); + if (unlikely(err)) + h_trap = ERR_PTR(err); + } + au_fset_ren(a->flags, PINNED); + + if (!IS_ERR(h_trap)) { + err = 0; + for (i = 0; !err && i < 2; i++) { + h_gdir = au_pinned_h_gdir(a->pin + i); + if (h_gdir) + err = au_verify_parent(a->h_parent[i], h_gdir); + } + if (unlikely(err)) + h_trap = ERR_PTR(err); + } + + dput(a->gparent[SRC]); + dput(a->gparent[DST]); + /* memset(a->gparent, 0, sizeof(a->gparent)); */ + AuTraceErrPtr(h_trap); + return h_trap; +} + +static void au_ren_unlock(struct au_ren_args *a) +{ + int i; + + AuTraceEnter(); + + if (a->h_locked[0]) + vfsub_unlock_rename(a->h_locked[0], a->h_locked[1]); + if (au_ftest_ren(a->flags, PINNED)) { + au_unpin(a->pin + SRC); + au_unpin(a->pin + DST); + memset(a->gparent, 0, sizeof(a->gparent)); + } + if (au_ftest_ren(a->flags, VFSLOCK)) + vfsub_unlock_rename_mutex(a->h_dentry[SRC]->d_sb); + for (i = 0; i < 2; i++) + if (unlikely(a->gparent[i])) { + di_read_unlock(a->gparent[i], AuLock_IR); + dput(a->gparent[i]); + } +} + +static int au_ren_lock(struct au_ren_args *a) +{ + int err; + const int hinotify = au_opt_test(a->mnt_flags, UDBA_INOTIFY); + + AuTraceEnter(); + + err = 0; + if (!hinotify + || (au_ftest_ren(a->flags, ISSAMEDIR) && IS_ROOT(a->parent[SRC]))) { + au_ren_pin_init(a->pin + SRC, a->src_dentry, a->pin + DST, + a->dentry); + LKTRLabel(here); + a->h_locked[0] = a->h_parent[SRC]; + a->h_locked[1] = a->h_parent[DST]; + a->h_trap = vfsub_lock_rename(a->h_locked[0], a->h_locked[1]); + au_ren_fake_pin(a); + } else if (au_ftest_ren(a->flags, ISSAMEDIR) + && !IS_ROOT(a->parent[SRC])) { + /* this and next block should not be compiled when + hinotify is not enabled */ + /* irregular/tricky rename lock */ + LKTRLabel(here); + au_ren_pin_init(a->pin + SRC, a->src_dentry, a->pin + DST, + a->dentry); + a->gparent[SRC] = dget_parent(a->parent[SRC]); + di_read_lock_parent2(a->gparent[SRC], AuLock_IR); + a->h_locked[0] = a->h_parent[SRC]; + a->h_locked[1] = dget_parent(a->h_parent[SRC]); + a->h_trap = vfsub_lock_rename(a->h_locked[0], a->h_locked[1]); + err = au_verify_parent(a->h_parent[SRC], + a->h_locked[1]->d_inode); + dput(a->h_locked[1]); + if (!err) + au_ren_fake_pin(a); + } else { + /* 3 or 4 dir locks. crazy */ + LKTRLabel(here); + a->h_trap = au_ren_pin(a); + if (IS_ERR(a->h_trap)) + err = PTR_ERR(a->h_trap); + } + + if (!err && au_dbstart(a->src_dentry) == a->btgt) + err = au_verify_parent(a->h_dentry[SRC], + a->h_parent[SRC]->d_inode); + if (!err && au_dbstart(a->dentry) == a->btgt) + err = au_verify_parent(a->h_dentry[DST], + a->h_parent[DST]->d_inode); + if (unlikely(err)) { + err = -EBUSY; + au_ren_unlock(a); + } + AuTraceErr(err); + return err; +} + +int aufs_rename(struct inode *src_dir, struct dentry *src_dentry, + struct inode *dir, struct dentry *dentry) +{ + int err; + aufs_bindex_t bend, bindex; + unsigned char do_dt_dstdir, hinotify; + struct inode *inode[2]; + enum { PARENT, CHILD }; + /* reduce stack space */ + struct { + struct au_ren_args a; + struct au_dtime dt[2][2]; + } *p; + struct au_wr_dir_args wr_dir_args = { + /* .force_btgt = -1, */ + .flags = AuWrDir_ADD_ENTRY + }; + + //lktr_set_pid(current->pid, LktrArrayPid); + LKTRTrace("i%lu, %.*s, i%lu, %.*s\n", + src_dir->i_ino, AuDLNPair(src_dentry), + dir->i_ino, AuDLNPair(dentry)); + AuDebugOn(IS_ROOT(src_dentry) || IS_ROOT(dentry)); + IMustLock(src_dir); + IMustLock(dir); + inode[DST] = dentry->d_inode; + if (inode[DST]) { + IMustLock(inode[DST]); + au_igrab(inode[DST]); + } + + err = -ENOMEM; + BUILD_BUG_ON(sizeof(*p) > PAGE_SIZE); + p = kzalloc(sizeof(*p), GFP_NOFS); + if (unlikely(!p)) + goto out; + + err = -ENOTDIR; + p->a.src_dir = src_dir; + p->a.src_dentry = src_dentry; + p->a.dir = dir; + p->a.dentry = dentry; + p->a.sb = src_dentry->d_sb; + inode[SRC] = src_dentry->d_inode; + p->a.flags = 0; + if (S_ISDIR(inode[SRC]->i_mode)) { + au_fset_ren(p->a.flags, ISDIR); + if (unlikely(inode[DST] && !S_ISDIR(inode[DST]->i_mode))) + goto out_free; + aufs_read_and_write_lock2(dentry, src_dentry, AuLock_DIR); + } else + aufs_read_and_write_lock2(dentry, src_dentry, 0); + + p->a.mnt_flags = au_mntflags(p->a.sb); + if (unlikely(au_test_dlgt(p->a.mnt_flags))) + au_fset_ren(p->a.flags, DLGT); + p->a.parent[SRC] = src_dentry->d_parent; /* dir inode is locked */ + p->a.parent[DST] = dentry->d_parent; /* dir inode is locked */ + au_fset_ren(p->a.flags, ISSAMEDIR); /* temporary */ + di_write_lock_parent(p->a.parent[DST]); + + /* which branch we process */ + p->a.bstart[SRC] = au_dbstart(src_dentry); + p->a.bstart[DST] = au_dbstart(dentry); + if (au_ftest_ren(p->a.flags, ISDIR)) + au_fset_wrdir(wr_dir_args.flags, ISDIR); + wr_dir_args.force_btgt = p->a.bstart[SRC]; + if (dentry->d_inode && p->a.bstart[DST] < p->a.bstart[SRC]) + wr_dir_args.force_btgt = p->a.bstart[DST]; + wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt); + err = au_wr_dir(dentry, src_dentry, &wr_dir_args); + p->a.btgt = err; + if (unlikely(err < 0)) + goto out_unlock; + + /* are they available to be renamed */ + err = 0; + au_nhash_init(&p->a.whlist); + if (au_ftest_ren(p->a.flags, ISDIR) && inode[DST]) { + au_set_dbstart(dentry, p->a.bstart[DST]); + err = may_rename_dstdir(dentry, p->a.btgt, &p->a.whlist); + au_set_dbstart(dentry, p->a.btgt); + } + p->a.h_dentry[DST] = au_h_dptr(dentry, au_dbstart(dentry)); + if (unlikely(err)) + goto out_unlock; + /* todo: minor optimize, + their sb may be same while their bindex differs? */ + p->a.h_dentry[SRC] = au_h_dptr(src_dentry, au_dbstart(src_dentry)); + if (au_ftest_ren(p->a.flags, ISDIR)) { + err = may_rename_srcdir(src_dentry, p->a.btgt); + if (unlikely(err)) + goto out_children; + } + + /* prepare the writable parent dir on the same branch */ + if (p->a.bstart[DST] == p->a.btgt) { + au_fset_ren(p->a.flags, WHDST); + } else { + err = au_cpup_dirs(dentry, p->a.btgt); + if (unlikely(err)) + goto out_children; + } + + if (src_dir != dir) { + /* + * this temporary unlock is safe, + * because dir->i_mutex is locked. + */ + di_write_unlock(p->a.parent[DST]); + di_write_lock_parent(p->a.parent[SRC]); + err = au_wr_dir_need_wh + (src_dentry, au_ftest_ren(p->a.flags, ISDIR), + &p->a.btgt); + di_write_unlock(p->a.parent[SRC]); + di_write_lock2_parent(p->a.parent[SRC], p->a.parent[DST], + /*isdir*/1); + au_fclr_ren(p->a.flags, ISSAMEDIR); + } else + err = au_wr_dir_need_wh + (src_dentry, au_ftest_ren(p->a.flags, ISDIR), + &p->a.btgt); + if (unlikely(err < 0)) + goto out_children; + if (err) + au_fset_ren(p->a.flags, WHSRC); + + hinotify = au_opt_test(p->a.mnt_flags, UDBA_INOTIFY); + p->a.h_parent[SRC] = au_h_dptr(p->a.parent[SRC], p->a.btgt); + p->a.h_parent[DST] = au_h_dptr(p->a.parent[DST], p->a.btgt); + err = au_ren_lock(&p->a); + if (unlikely(err)) + goto out_children; + + if (!au_opt_test(p->a.mnt_flags, UDBA_NONE)) { + p->a.ndx.nfsmnt = au_nfsmnt(p->a.sb, p->a.btgt); + if (unlikely(au_ftest_ren(p->a.flags, DLGT))) + au_fset_ndx(p->a.ndx.flags, DLGT); + err = au_may_ren(&p->a); + if (unlikely(err)) + goto out_hdir; + memset(&p->a.ndx, 0, sizeof(p->a.ndx)); + } + + /* store timestamps to be revertible */ + au_dtime_store(p->dt[PARENT] + SRC, p->a.parent[SRC], + p->a.h_parent[SRC], + au_pinned_hdir(p->a.pin + SRC, p->a.btgt), + au_pinned_hgdir(p->a.pin + SRC, p->a.btgt) + /* hgdir[SRC] */); + if (!au_ftest_ren(p->a.flags, ISSAMEDIR)) + au_dtime_store(p->dt[PARENT] + DST, p->a.parent[DST], + p->a.h_parent[DST], + au_pinned_hdir(p->a.pin + DST, p->a.btgt), + au_pinned_hgdir(p->a.pin + DST, p->a.btgt) + /* hgdir[DST] */); + do_dt_dstdir = 0; + if (au_ftest_ren(p->a.flags, ISDIR)) { + au_dtime_store(p->dt[CHILD] + SRC, src_dentry, + p->a.h_dentry[SRC], au_hi(inode[SRC], p->a.btgt), + au_pinned_hdir(p->a.pin + SRC, p->a.btgt)); + if (p->a.h_dentry[DST]->d_inode) { + do_dt_dstdir = 1; + au_dtime_store(p->dt[CHILD] + DST, dentry, + p->a.h_dentry[DST], + au_hi(inode[DST], p->a.btgt), + au_pinned_hdir(p->a.pin + DST, + p->a.btgt)); + } + } + + err = do_rename(&p->a); + if (unlikely(err)) + goto out_dt; + + /* update dir attributes */ + dir->i_version++; + if (au_ftest_ren(p->a.flags, ISDIR)) { + /* is this updating defined in POSIX? */ + /* mutex_lock(&inode[SRC]->i_mutex); */ + au_cpup_attr_timesizes(inode[SRC]); + /* mutex_unlock(&inode[SRC]->i_mutex); */ + + au_cpup_attr_nlink(dir); + if (inode[DST]) { + clear_nlink(inode[DST]); + au_cpup_attr_timesizes(inode[DST]); + } + } + if (au_ibstart(dir) == p->a.btgt) + au_cpup_attr_timesizes(dir); + + if (!au_ftest_ren(p->a.flags, ISSAMEDIR)) { + src_dir->i_version++; + if (au_ftest_ren(p->a.flags, ISDIR)) + au_cpup_attr_nlink(src_dir); + if (au_ibstart(src_dir) == p->a.btgt) + au_cpup_attr_timesizes(src_dir); + } + + /* todo: simple d_drop(src_dentry) is not enough? */ + /* dput/iput all lower dentries */ + au_set_dbwh(src_dentry, -1); + bend = au_dbend(src_dentry); + for (bindex = p->a.btgt + 1; bindex <= bend; bindex++) { + struct dentry *hd; + hd = au_h_dptr(src_dentry, bindex); + if (hd) + au_set_h_dptr(src_dentry, bindex, NULL); + } + au_set_dbend(src_dentry, p->a.btgt); + + if (au_opt_test(p->a.mnt_flags, PLINK) + && !au_plink_test(src_dentry->d_sb, inode[SRC])) { + bend = au_ibend(inode[SRC]); + for (bindex = p->a.btgt + 1; bindex <= bend; bindex++) { + struct inode *hi; + hi = au_h_iptr(inode[SRC], bindex); + if (hi) { + au_xino_write0(p->a.sb, bindex, hi->i_ino, 0); + /* ignore this error */ + au_set_h_iptr(inode[SRC], bindex, NULL, 0); + } + } + au_set_ibend(inode[SRC], p->a.btgt); + } + goto out_hdir; /* success */ + + out_dt: + au_dtime_revert(p->dt[PARENT] + SRC); + if (!au_ftest_ren(p->a.flags, ISSAMEDIR)) + au_dtime_revert(p->dt[PARENT] + DST); + if (au_ftest_ren(p->a.flags, ISDIR) && err != -EIO) { + struct dentry *hd; + + hd = p->dt[CHILD][SRC].dt_h_dentry; + mutex_lock_nested(&hd->d_inode->i_mutex, AuLsc_I_CHILD); + au_dtime_revert(p->dt[CHILD] + SRC); + mutex_unlock(&hd->d_inode->i_mutex); + if (do_dt_dstdir) { + hd = p->dt[CHILD][DST].dt_h_dentry; + mutex_lock_nested(&hd->d_inode->i_mutex, AuLsc_I_CHILD); + au_dtime_revert(p->dt[CHILD] + DST); + mutex_unlock(&hd->d_inode->i_mutex); + } + } + out_hdir: + au_ren_unlock(&p->a); + out_children: + au_nhash_fin(&p->a.whlist); + out_unlock: + if (unlikely(err && au_ftest_ren(p->a.flags, ISDIR))) { + au_update_dbstart(dentry); + d_drop(dentry); + } + if (!err) { + d_move(src_dentry, dentry); +#if 0 + lktr_set_pid(current->pid, LktrArrayPid); + AuDbgDentry(src_dentry); + AuDbgDentry(dentry); + lktr_clear_pid(current->pid, LktrArrayPid); +#endif +#if 0 + if (inode[DST]) { + inode[DST]->i_flags |= S_DEAD; + ii_write_unlock(inode[DST]); + } +#endif + } + if (au_ftest_ren(p->a.flags, ISSAMEDIR)) + di_write_unlock(p->a.parent[DST]); + else + di_write_unlock2(p->a.parent[SRC], p->a.parent[DST]); + aufs_read_and_write_unlock2(dentry, src_dentry); + out_free: + kfree(p); + out: + iput(inode[DST]); + AuTraceErr(err); + //lktr_clear_pid(current->pid, LktrArrayPid); + return err; +} --- linux-2.6.27.orig/ubuntu/aufs/BOM +++ linux-2.6.27/ubuntu/aufs/BOM @@ -0,0 +1,3 @@ +Downloaded from: pserver:anonymous@aufs.cvs.sourceforge.net:/cvsroot/aufs +Current Version: Mon, 22 Sep 2008 +Comments: Unmodified upstream checkout --- linux-2.6.27.orig/ubuntu/aufs/inode.h +++ linux-2.6.27/ubuntu/aufs/inode.h @@ -0,0 +1,545 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * inode operations + * + * $Id: inode.h,v 1.13 2008/09/15 03:14:44 sfjro Exp $ + */ + +#ifndef __AUFS_INODE_H__ +#define __AUFS_INODE_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include "hinode.h" +#include "misc.h" +#include "super.h" + +struct au_hinode; +struct au_vdir; +struct au_iinfo { + atomic_t ii_generation; + struct super_block *ii_hsb1; /* no get/put */ + + struct au_rwsem ii_rwsem; + aufs_bindex_t ii_bstart, ii_bend; + __u32 ii_higen; + struct au_hinode *ii_hinode; + struct au_vdir *ii_vdir; +}; + +struct aufs_icntnr { + struct au_iinfo iinfo; + struct inode vfs_inode; +}; + +struct au_pin1 { + /* input */ + struct dentry *dentry; + unsigned char di_locked, lsc_di, lsc_hi; + /* auto */ + unsigned char do_verify; + + /* output */ + struct dentry *parent; + struct inode *h_dir; +}; + +enum {AuPin_PARENT, AuPin_GPARENT}; +struct au_pin { +#ifdef CONFIG_AUFS_HINOTIFY + struct au_pin1 pin[2]; +#else + struct au_pin1 pin[1]; /* no grand parent */ +#endif +}; + +/* ---------------------------------------------------------------------- */ + +/* inode.c */ +int au_refresh_hinode_self(struct inode *inode); +int au_refresh_hinode(struct inode *inode, struct dentry *dentry); +struct inode *au_new_inode(struct dentry *dentry); +int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, + struct inode *inode); +int au_test_h_perm(struct inode *h_inode, int mask, int dlgt); +int au_test_h_perm_sio(struct inode *h_inode, int mask, int dlgt); + +/* i_op.c */ +extern struct inode_operations aufs_iop, aufs_symlink_iop, aufs_dir_iop; + +/* au_wr_dir flags */ +#define AuWrDir_ADD_ENTRY 1 +#define AuWrDir_ISDIR (1 << 1) +#define au_ftest_wrdir(flags, name) ((flags) & AuWrDir_##name) +#define au_fset_wrdir(flags, name) { (flags) |= AuWrDir_##name; } +#define au_fclr_wrdir(flags, name) { (flags) &= ~AuWrDir_##name; } + +struct au_wr_dir_args { + aufs_bindex_t force_btgt; + unsigned char flags; +}; +int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, + struct au_wr_dir_args *args); + +void au_pin_init(struct au_pin *args, struct dentry *dentry, int di_locked, + int lsc_di, int lsc_hi, int do_gp); +int au_pin(struct au_pin *args, struct dentry *dentry, aufs_bindex_t bindex, + int di_locked, int do_gp) __must_check; +int au_do_pin(struct au_pin1 *p, struct au_pin1 *gp, const aufs_bindex_t bindex, + const int do_gp) __must_check; +void au_do_unpin(struct au_pin1 *p, struct au_pin1 *gp); + +/* i_op_add.c */ +struct au_ndx; +int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_parent, int isdir, struct au_ndx *ndx); +int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev); +int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); +int aufs_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd); +int aufs_link(struct dentry *src_dentry, struct inode *dir, + struct dentry *dentry); +int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode); + +/* i_op_del.c */ +int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup); +int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, + struct dentry *h_parent, int isdir, struct au_ndx *ndx); +int aufs_unlink(struct inode *dir, struct dentry *dentry); +int aufs_rmdir(struct inode *dir, struct dentry *dentry); + +/* i_op_ren.c */ +int au_wbr(struct dentry *dentry, aufs_bindex_t btgt); +int aufs_rename(struct inode *src_dir, struct dentry *src_dentry, + struct inode *dir, struct dentry *dentry); + +#ifdef CONFIG_AUFS_DLGT +/* dlgt.c */ +int au_security_inode_permission(struct inode *h_inode, int mask, + struct nameidata *fake_nd, int dlgt); +#else +static inline +int au_security_inode_permission(struct inode *h_inode, int mask, + struct nameidata *fake_nd, int dlgt) +{ + return vfsub_security_inode_permission(h_inode, mask, fake_nd); +} +#endif /* CONFIG_AUFS_DLGT */ + +#ifdef CONFIG_AUFS_HIN_OR_FUSE +/* hin_or_fuse.c */ +int aufs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *st); +#endif + +#if 0 /* reserved for future use */ +/* xattr.c */ +int aufs_setxattr(struct dentry *dentry, const char *name, const void *value, + size_t sz, int flags); +ssize_t aufs_getxattr(struct dentry *dentry, const char *name, void *value, + size_t sz); +ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t sz); +int aufs_removexattr(struct dentry *dentry, const char *name); +#endif + +/* iinfo.c */ +struct au_iinfo *au_ii(struct inode *inode); +struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex); +aufs_bindex_t au_ii_br_id(struct inode *inode, aufs_bindex_t bindex); + +void au_set_ibstart(struct inode *inode, aufs_bindex_t bindex); +void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, + struct dentry *h_wh); +unsigned int au_hi_flags(struct inode *inode, int isdir); + +/* hinode flags */ +#define AuHi_XINO 1 +#define AuHi_NOTIFY (1 << 1) +#define au_ftest_hi(flags, name) ((flags) & AuHi_##name) +#define au_fset_hi(flags, name) { (flags) |= AuHi_##name; } +#define au_fclr_hi(flags, name) { (flags) &= ~AuHi_##name; } +#ifndef CONFIG_AUFS_HINOTIFY +#undef AuHi_NOTIFY +#define AuHi_NOTIFY 0 +#endif + +void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, + struct inode *h_inode, unsigned int flags); + +void au_update_iigen(struct inode *inode); +void au_update_brange(struct inode *inode, int do_put_zero); + +int au_iinfo_init(struct inode *inode); +void au_iinfo_fin(struct inode *inode); + +/* plink.c */ +#ifdef CONFIG_AUFS_DEBUG +void au_plink_list(struct super_block *sb); +#else +static inline void au_plink_list(struct super_block *sb) +{ + /* nothing */ +} +#endif +int au_plink_test(struct super_block *sb, struct inode *inode); +struct dentry *au_plink_lkup(struct super_block *sb, aufs_bindex_t bindex, + struct inode *inode); +void au_plink_append(struct super_block *sb, struct inode *inode, + struct dentry *h_dentry, aufs_bindex_t bindex); +void au_plink_put(struct super_block *sb); +void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id); + +/* ---------------------------------------------------------------------- */ + +/* lock subclass for iinfo */ +enum { + AuLsc_II_CHILD, /* child first */ + AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hinotify */ + AuLsc_II_CHILD3, /* copyup dirs */ + AuLsc_II_PARENT, /* see AuLsc_I_PARENT in vfsub.h */ + AuLsc_II_PARENT2, + AuLsc_II_PARENT3, + AuLsc_II_PARENT4, + AuLsc_II_NEW_CHILD, +}; + +/* + * ii_read_lock_child, ii_write_lock_child, + * ii_read_lock_child2, ii_write_lock_child2, + * ii_read_lock_child3, ii_write_lock_child3, + * ii_read_lock_parent, ii_write_lock_parent, + * ii_read_lock_parent2, ii_write_lock_parent2, + * ii_read_lock_parent3, ii_write_lock_parent3, + * ii_read_lock_parent4, ii_write_lock_parent4, + * ii_read_lock_new_child, ii_write_lock_new_child, + */ +#define AuReadLockFunc(name, lsc) \ +static inline void ii_read_lock_##name(struct inode *i) \ +{ au_rw_read_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); } + +#define AuWriteLockFunc(name, lsc) \ +static inline void ii_write_lock_##name(struct inode *i) \ +{ au_rw_write_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); } + +#define AuRWLockFuncs(name, lsc) \ + AuReadLockFunc(name, lsc) \ + AuWriteLockFunc(name, lsc) + +AuRWLockFuncs(child, CHILD); +AuRWLockFuncs(child2, CHILD2); +AuRWLockFuncs(child3, CHILD3); +AuRWLockFuncs(parent, PARENT); +AuRWLockFuncs(parent2, PARENT2); +AuRWLockFuncs(parent3, PARENT3); +AuRWLockFuncs(parent4, PARENT4); +AuRWLockFuncs(new_child, NEW_CHILD); + +#undef AuReadLockFunc +#undef AuWriteLockFunc +#undef AuRWLockFuncs + +/* + * ii_read_unlock, ii_write_unlock, ii_downgrade_lock + */ +AuSimpleUnlockRwsemFuncs(ii, struct inode *i, au_ii(i)->ii_rwsem); + +/* to debug easier, do not make them inlined functions */ +#define IiMustReadLock(i) do { \ + SiMustAnyLock((i)->i_sb); \ + AuRwMustReadLock(&au_ii(i)->ii_rwsem); \ +} while (0) + +#define IiMustWriteLock(i) do { \ + SiMustAnyLock((i)->i_sb); \ + AuRwMustWriteLock(&au_ii(i)->ii_rwsem); \ +} while (0) + +#define IiMustAnyLock(i) do { \ + SiMustAnyLock((i)->i_sb); \ + AuRwMustAnyLock(&au_ii(i)->ii_rwsem); \ +} while (0) + +#define IiMustNoWaiters(i) AuRwMustNoWaiters(&au_ii(i)->ii_rwsem) + +/* ---------------------------------------------------------------------- */ + +static inline struct inode *au_igrab(struct inode *inode) +{ + if (inode) { + AuDebugOn(!atomic_read(&inode->i_count)); + atomic_inc_return(&inode->i_count); + } + return inode; +} + +/* ---------------------------------------------------------------------- */ + +static inline aufs_bindex_t au_ibstart(struct inode *inode) +{ + IiMustAnyLock(inode); + return au_ii(inode)->ii_bstart; +} + +static inline aufs_bindex_t au_ibend(struct inode *inode) +{ + IiMustAnyLock(inode); + return au_ii(inode)->ii_bend; +} + +static inline struct au_vdir *au_ivdir(struct inode *inode) +{ + IiMustAnyLock(inode); + AuDebugOn(!S_ISDIR(inode->i_mode)); + return au_ii(inode)->ii_vdir; +} + +static inline struct dentry *au_hi_wh(struct inode *inode, aufs_bindex_t bindex) +{ + struct au_hinode *hinode; + IiMustAnyLock(inode); + hinode = au_ii(inode)->ii_hinode + bindex; + return hinode->hi_whdentry; +} + +static inline void au_set_ibend(struct inode *inode, aufs_bindex_t bindex) +{ + IiMustWriteLock(inode); + AuDebugOn(au_sbend(inode->i_sb) < bindex || bindex < au_ibstart(inode)); + au_ii(inode)->ii_bend = bindex; +} + +static inline void au_set_ivdir(struct inode *inode, struct au_vdir *vdir) +{ + IiMustWriteLock(inode); + AuDebugOn(!S_ISDIR(inode->i_mode) || (au_ii(inode)->ii_vdir && vdir)); + au_ii(inode)->ii_vdir = vdir; +} + +static inline void au_hiput(struct au_hinode *hinode) +{ + au_hin_free(hinode); + dput(hinode->hi_whdentry); + iput(hinode->hi_inode); +} + +static inline struct au_hinode *au_hi(struct inode *inode, aufs_bindex_t bindex) +{ + /* todo: this lock check causes some unnecessary locks in callers. */ + IiMustAnyLock(inode); + return au_ii(inode)->ii_hinode + bindex; +} + +/* tiny test for inode number */ +/* tmpfs generation is too rough */ +static inline int au_test_higen(struct inode *inode, struct inode *h_inode) +{ + struct au_iinfo *iinfo; + + IiMustAnyLock(inode); + + iinfo = au_ii(inode); + return !(iinfo->ii_hsb1 == h_inode->i_sb + && iinfo->ii_higen == h_inode->i_generation); +} + +static inline au_gen_t au_iigen(struct inode *inode) +{ + return atomic_read(&au_ii(inode)->ii_generation); +} + +#ifdef CONFIG_AUFS_HINOTIFY +static inline au_gen_t au_iigen_dec(struct inode *inode) +{ + /* AuDbg("i%lu\n", inode->i_ino); */ + return atomic_dec_return(&au_ii(inode)->ii_generation); +} +#endif + +/* ---------------------------------------------------------------------- */ + +#ifdef CONFIG_AUFS_HINOTIFY +static inline struct au_pin1 *au_pin_gp(struct au_pin *args) +{ + return args->pin + AuPin_GPARENT; +} + +/* hinotify.c */ +void au_unpin_gp(struct au_pin *args); + +#else + +static inline struct au_pin1 *au_pin_gp(struct au_pin *args) +{ + return NULL; +} + +static inline void au_unpin_gp(struct au_pin *args) +{ + /* empty */ +} +#endif /* HINOTIFY */ + +static inline void au_unpin(struct au_pin *args) +{ + au_do_unpin(args->pin + AuPin_PARENT, au_pin_gp(args)); +} + +static inline +struct au_hinode *au_do_pinned_hdir(struct au_pin1 *pin, aufs_bindex_t bindex) +{ + if (pin && pin->parent) + return au_hi(pin->parent->d_inode, bindex); + return NULL; +} + +struct dentry *au_do_pinned_h_parent(struct au_pin1 *pin, aufs_bindex_t bindex); + +static inline struct dentry *au_do_pinned_parent(struct au_pin1 *pin) +{ + if (pin) + return pin->parent; + return NULL; +} + +static inline struct inode *au_do_pinned_h_dir(struct au_pin1 *pin) +{ + if (pin) + return pin->h_dir; + return NULL; +} + +static inline +void au_pin_do_set_dentry(struct au_pin1 *pin, struct dentry *dentry) +{ + if (pin) + pin->dentry = dentry; +} + +static inline +void au_pin_do_set_parent(struct au_pin1 *pin, struct dentry *parent) +{ + if (pin) { + dput(pin->parent); + pin->parent = dget(parent); + } +} + +static inline void au_pin_do_set_h_dir(struct au_pin1 *pin, struct inode *h_dir) +{ + if (pin) { + iput(pin->h_dir); + pin->h_dir = au_igrab(h_dir); + } +} + +static inline +void au_pin_do_set_parent_lflag(struct au_pin1 *pin, unsigned char lflag) +{ + if (pin) + pin->di_locked = lflag; +} + +static inline +struct au_hinode *au_pinned_hdir(struct au_pin *args, aufs_bindex_t bindex) +{ + return au_do_pinned_hdir(args->pin + AuPin_PARENT, bindex); +} + +static inline +struct au_hinode *au_pinned_hgdir(struct au_pin *args, aufs_bindex_t bindex) +{ + return au_do_pinned_hdir(au_pin_gp(args), bindex); +} + +static inline +struct dentry *au_pinned_h_parent(struct au_pin *args, aufs_bindex_t bindex) +{ + return au_do_pinned_h_parent(args->pin + AuPin_PARENT, bindex); +} + +#if 0 /* reserved for future use */ +static inline +struct dentry *au_pinned_h_gparent(struct au_pin *args, aufs_bindex_t bindex) +{ + return au_do_pinned_h_parent(au_pin_gp(args), bindex); +} +#endif + +static inline +struct dentry *au_pinned_parent(struct au_pin *args) +{ + return au_do_pinned_parent(args->pin + AuPin_PARENT); +} + +static inline +struct dentry *au_pinned_gparent(struct au_pin *args) +{ + return au_do_pinned_parent(au_pin_gp(args)); +} + +static inline +struct inode *au_pinned_h_dir(struct au_pin *args) +{ + return au_do_pinned_h_dir(args->pin + AuPin_PARENT); +} + +static inline +struct inode *au_pinned_h_gdir(struct au_pin *args) +{ + return au_do_pinned_h_dir(au_pin_gp(args)); +} + +static inline void au_pin_set_parent(struct au_pin *args, struct dentry *d) +{ + au_pin_do_set_parent(args->pin + AuPin_PARENT, d); +} + +static inline void au_pin_set_gparent(struct au_pin *args, struct dentry *d) +{ + au_pin_do_set_parent(au_pin_gp(args), d); +} + +static inline void au_pin_set_h_dir(struct au_pin *args, struct inode *h_dir) +{ + au_pin_do_set_h_dir(args->pin + AuPin_PARENT, h_dir); +} + +static inline void au_pin_set_h_gdir(struct au_pin *args, struct inode *h_dir) +{ + au_pin_do_set_h_dir(au_pin_gp(args), h_dir); +} + +static inline +void au_pin_set_parent_lflag(struct au_pin *args, unsigned char lflag) +{ + au_pin_do_set_parent_lflag(args->pin + AuPin_PARENT, lflag); +} + +static inline +void au_pin_set_gparent_lflag(struct au_pin *args, unsigned char lflag) +{ + au_pin_do_set_parent_lflag(au_pin_gp(args), lflag); +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_INODE_H__ */ --- linux-2.6.27.orig/ubuntu/aufs/dir.c +++ linux-2.6.27/ubuntu/aufs/dir.c @@ -0,0 +1,547 @@ +/* + * Copyright (C) 2005-2008 Junjiro Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * directory operations + * + * $Id: dir.c,v 1.13 2008/09/22 03:52:19 sfjro Exp $ + */ + +#include +#include "aufs.h" + +static int reopen_dir(struct file *file) +{ + int err; + struct dentry *dentry, *h_dentry; + aufs_bindex_t bindex, btail, bstart; + struct file *h_file; + + dentry = file->f_dentry; + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode)); + + /* open all hidden dirs */ + bstart = au_dbstart(dentry); +#if 1 /* todo: necessary? */ + for (bindex = au_fbstart(file); bindex < bstart; bindex++) + au_set_h_fptr(file, bindex, NULL); +#endif + au_set_fbstart(file, bstart); + btail = au_dbtaildir(dentry); +#if 1 /* todo: necessary? */ + for (bindex = au_fbend(file); btail < bindex; bindex--) + au_set_h_fptr(file, bindex, NULL); +#endif + au_set_fbend(file, btail); + for (bindex = bstart; bindex <= btail; bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + h_file = au_h_fptr(file, bindex); + if (h_file) { + AuDebugOn(h_file->f_dentry != h_dentry); + continue; + } + + h_file = au_h_open(dentry, bindex, file->f_flags, file); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out; /* close all? */ + /* cpup_file_flags(h_file, file); */ + au_set_h_fptr(file, bindex, h_file); + } + au_update_figen(file); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + err = 0; + + out: + AuTraceErr(err); + return err; +} + +static int do_open_dir(struct file *file, int flags) +{ + int err; + aufs_bindex_t bindex, btail; + struct dentry *dentry, *h_dentry; + struct file *h_file; + + dentry = file->f_dentry; + LKTRTrace("%.*s, 0x%x\n", AuDLNPair(dentry), flags); + AuDebugOn(!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)); + + err = 0; + au_set_fvdir_cache(file, NULL); + file->f_version = dentry->d_inode->i_version; + bindex = au_dbstart(dentry); + au_set_fbstart(file, bindex); + btail = au_dbtaildir(dentry); + au_set_fbend(file, btail); + for (; !err && bindex <= btail; bindex++) { + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + + h_file = au_h_open(dentry, bindex, flags, file); + if (IS_ERR(h_file)) { + err = PTR_ERR(h_file); + break; + } + au_set_h_fptr(file, bindex, h_file); + } + au_update_figen(file); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + if (!err) + return 0; /* success */ + + /* close all */ + for (bindex = au_fbstart(file); bindex <= btail; bindex++) + au_set_h_fptr(file, bindex, NULL); + au_set_fbstart(file, -1); + au_set_fbend(file, -1); + return err; +} + +static int aufs_open_dir(struct inode *inode, struct file *file) +{ + LKTRTrace("i%lu, %.*s\n", inode->i_ino, AuDLNPair(file->f_dentry)); + + return au_do_open(inode, file, do_open_dir); +} + +static int aufs_release_dir(struct inode *inode, struct file *file) +{ + struct au_vdir *vdir_cache; + struct super_block *sb; + + LKTRTrace("i%lu, %.*s\n", inode->i_ino, AuDLNPair(file->f_dentry)); + + sb = file->f_dentry->d_sb; + si_noflush_read_lock(sb); + fi_write_lock(file); + vdir_cache = au_fvdir_cache(file); + if (vdir_cache) + au_vdir_free(vdir_cache); + fi_write_unlock(file); + au_finfo_fin(file); + si_read_unlock(sb); + return 0; +} + +static int fsync_dir(struct dentry *dentry, int datasync) +{ + int err; + struct inode *inode; + struct super_block *sb; + aufs_bindex_t bend, bindex; + + LKTRTrace("%.*s, %d\n", AuDLNPair(dentry), datasync); + DiMustAnyLock(dentry); + sb = dentry->d_sb; + SiMustAnyLock(sb); + inode = dentry->d_inode; + IMustLock(inode); + IiMustAnyLock(inode); + + err = 0; + bend = au_dbend(dentry); + for (bindex = au_dbstart(dentry); !err && bindex <= bend; bindex++) { + struct dentry *h_dentry; + struct inode *h_inode; + struct file_operations *fop; + + if (au_test_ro(sb, bindex, inode)) + continue; + h_dentry = au_h_dptr(dentry, bindex); + if (!h_dentry) + continue; + h_inode = h_dentry->d_inode; + if (!h_inode) + continue; + + /* cf. fs/nsfd/vfs.c and fs/nfsd/nfs4recover.c */ + /* todo: inotiry fired? */ + mutex_lock(&h_inode->i_mutex); + fop = (void *)h_inode->i_fop; + err = filemap_fdatawrite(h_inode->i_mapping); + if (!err && fop && fop->fsync) + err = fop->fsync(NULL, h_dentry, datasync); + if (!err) + err = filemap_fdatawrite(h_inode->i_mapping); + if (!err) + au_update_fuse_h_inode(NULL, h_dentry); /*ignore*/ + mutex_unlock(&h_inode->i_mutex); + } + + AuTraceErr(err); + return err; +} + +/* + * @file may be NULL + */ +static int aufs_fsync_dir(struct file *file, struct dentry *dentry, + int datasync) +{ + int err; + struct inode *inode; + struct file *h_file; + struct super_block *sb; + aufs_bindex_t bend, bindex; + + LKTRTrace("%.*s, %d\n", AuDLNPair(dentry), datasync); + inode = dentry->d_inode; + IMustLock(inode); + + err = 0; + sb = dentry->d_sb; + si_noflush_read_lock(sb); + if (file) { + err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1, + /*locked*/1); + if (unlikely(err)) + goto out; + } else + di_write_lock_child(dentry); + + if (file) { + bend = au_fbend(file); + for (bindex = au_fbstart(file); !err && bindex <= bend; + bindex++) { + h_file = au_h_fptr(file, bindex); + if (!h_file || au_test_ro(sb, bindex, inode)) + continue; + + err = -EINVAL; + if (h_file->f_op && h_file->f_op->fsync) { + /* todo: try do_fsync() in fs/sync.c? */ + mutex_lock(&h_file->f_mapping->host->i_mutex); + err = h_file->f_op->fsync + (h_file, h_file->f_dentry, datasync); + if (!err) + au_update_fuse_h_inode + (h_file->f_vfsmnt, + h_file->f_dentry); + /*ignore*/ + mutex_unlock(&h_file->f_mapping->host->i_mutex); + } + } + } else + err = fsync_dir(dentry, datasync); + au_cpup_attr_timesizes(inode); + di_write_unlock(dentry); + if (file) + fi_write_unlock(file); + + out: + si_read_unlock(sb); + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +static int aufs_readdir(struct file *file, void *dirent, filldir_t filldir) +{ + int err, iflag; + struct dentry *dentry; + struct inode *inode; + struct super_block *sb; + + dentry = file->f_dentry; + LKTRTrace("%.*s, pos %lld\n", AuDLNPair(dentry), file->f_pos); + inode = dentry->d_inode; + IMustLock(inode); + + au_nfsd_lockdep_off(); + sb = dentry->d_sb; + si_read_lock(sb, AuLock_FLUSH); + err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1, /*locked*/1); + if (unlikely(err)) + goto out; + + err = au_vdir_init(file); + if (unlikely(err)) { + di_write_unlock(dentry); + goto out_unlock; + } + + /* nfsd filldir calls lookup_one_len(). */ + iflag = AuLock_IW; + if (unlikely(au_test_nfsd(current))) + iflag = AuLock_IR; + di_downgrade_lock(dentry, iflag); + err = au_vdir_fill_de(file, dirent, filldir); + + fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibstart(inode))); + di_read_unlock(dentry, iflag); + + out_unlock: + fi_write_unlock(file); + out: + si_read_unlock(sb); + au_nfsd_lockdep_on(); + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +#define AuTestEmpty_WHONLY 1 +#define AuTestEmpty_DLGT (1 << 1) +#define AuTestEmpty_DIRPERM1 (1 << 2) +#define AuTestEmpty_CALLED (1 << 3) +#define AuTestEmpty_SHWH (1 << 4) +#define au_ftest_testempty(flags, name) ((flags) & AuTestEmpty_##name) +#define au_fset_testempty(flags, name) { (flags) |= AuTestEmpty_##name; } +#define au_fclr_testempty(flags, name) { (flags) &= ~AuTestEmpty_##name; } +#ifndef CONFIG_AUFS_DLGT +#undef AuTestEmpty_DLGT +#define AuTestEmpty_DLGT 0 +#undef AuTestEmpty_DIRPERM1 +#define AuTestEmpty_DIRPERM1 0 +#endif +#ifndef CONFIG_AUFS_SHWH +#undef AuTestEmpty_SHWH +#define AuTestEmpty_SHWH 0 +#endif + +struct test_empty_arg { + struct au_nhash *whlist; + unsigned int flags; + int err; + aufs_bindex_t bindex; +}; + +static int test_empty_cb(void *__arg, const char *__name, int namelen, + loff_t offset, u64 ino, unsigned int d_type) +{ + struct test_empty_arg *arg = __arg; + char *name = (void *)__name; + + LKTRTrace("%.*s\n", namelen, name); + + arg->err = 0; + au_fset_testempty(arg->flags, CALLED); + /* smp_mb(); */ + if (name[0] == '.' + && (namelen == 1 || (name[1] == '.' && namelen == 2))) + return 0; /* success */ + + if (namelen <= AUFS_WH_PFX_LEN + || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { + if (au_ftest_testempty(arg->flags, WHONLY) + && !au_nhash_test_known_wh(arg->whlist, name, namelen)) + arg->err = -ENOTEMPTY; + goto out; + } + + name += AUFS_WH_PFX_LEN; + namelen -= AUFS_WH_PFX_LEN; + if (!au_nhash_test_known_wh(arg->whlist, name, namelen)) + arg->err = au_nhash_append_wh + (arg->whlist, name, namelen, ino, d_type, arg->bindex, + au_ftest_testempty(arg->flags, SHWH)); + + out: + /* smp_mb(); */ + AuTraceErr(arg->err); + return arg->err; +} + +static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg) +{ + int err, dlgt; + struct file *h_file; + + LKTRTrace("%.*s, {%p, 0x%x, %d}\n", + AuDLNPair(dentry), arg->whlist, arg->flags, arg->bindex); + + h_file = au_h_open(dentry, arg->bindex, + O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_LARGEFILE, + /*file*/NULL); + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out; + err = 0; + if (unlikely(au_opt_test(au_mntflags(dentry->d_sb), UDBA_INOTIFY) + && !h_file->f_dentry->d_inode->i_nlink)) + goto out_put; + + dlgt = au_ftest_testempty(arg->flags, DLGT); + do { + arg->err = 0; + au_fclr_testempty(arg->flags, CALLED); + /* smp_mb(); */ + err = vfsub_readdir(h_file, test_empty_cb, arg, dlgt); + if (err >= 0) + err = arg->err; + } while (!err && au_ftest_testempty(arg->flags, CALLED)); + + out_put: + fput(h_file); + au_sbr_put(dentry->d_sb, arg->bindex); + out: + AuTraceErr(err); + return err; +} + +struct do_test_empty_args { + int *errp; + struct dentry *dentry; + struct test_empty_arg *arg; +}; + +static void call_do_test_empty(void *args) +{ + struct do_test_empty_args *a = args; + *a->errp = do_test_empty(a->dentry, a->arg); +} + +static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg) +{ + int err, wkq_err; + struct dentry *h_dentry; + struct inode *h_inode; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + h_dentry = au_h_dptr(dentry, arg->bindex); + AuDebugOn(!h_dentry); + h_inode = h_dentry->d_inode; + AuDebugOn(!h_inode); + + mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); + err = au_test_h_perm_sio(h_inode, MAY_EXEC | MAY_READ, + au_test_dlgt(au_mntflags(dentry->d_sb))); + mutex_unlock(&h_inode->i_mutex); + if (!err) + err = do_test_empty(dentry, arg); + else { + struct do_test_empty_args args = { + .errp = &err, + .dentry = dentry, + .arg = arg + }; + unsigned int flags = arg->flags; + + au_fclr_testempty(arg->flags, DLGT); + au_fclr_testempty(arg->flags, DIRPERM1); + wkq_err = au_wkq_wait(call_do_test_empty, &args, /*dlgt*/0); + if (unlikely(wkq_err)) + err = wkq_err; + arg->flags = flags; + } + + AuTraceErr(err); + return err; +} + +int au_test_empty_lower(struct dentry *dentry) +{ + int err; + struct inode *inode; + struct test_empty_arg arg; + struct au_nhash *whlist; + aufs_bindex_t bindex, bstart, btail; + unsigned int mnt_flags; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + inode = dentry->d_inode; + AuDebugOn(!inode || !S_ISDIR(inode->i_mode)); + + whlist = au_nhash_new(GFP_NOFS); + err = PTR_ERR(whlist); + if (IS_ERR(whlist)) + goto out; + + bstart = au_dbstart(dentry); + mnt_flags = au_mntflags(dentry->d_sb); + arg.whlist = whlist; + arg.flags = 0; + if (unlikely(au_test_dlgt(mnt_flags))) + au_fset_testempty(arg.flags, DLGT); + if (unlikely(au_opt_test(mnt_flags, SHWH))) + au_fset_testempty(arg.flags, SHWH); + arg.bindex = bstart; + err = do_test_empty(dentry, &arg); + if (unlikely(err)) + goto out_whlist; + + au_fset_testempty(arg.flags, WHONLY); + if (unlikely(au_test_dirperm1(mnt_flags))) + au_fset_testempty(arg.flags, DIRPERM1); + btail = au_dbtaildir(dentry); + for (bindex = bstart + 1; !err && bindex <= btail; bindex++) { + struct dentry *h_dentry; + h_dentry = au_h_dptr(dentry, bindex); + if (h_dentry && h_dentry->d_inode) { + arg.bindex = bindex; + err = do_test_empty(dentry, &arg); + } + } + + out_whlist: + au_nhash_del(whlist); + out: + AuTraceErr(err); + return err; +} + +int au_test_empty(struct dentry *dentry, struct au_nhash *whlist) +{ + int err; + struct inode *inode; + struct test_empty_arg arg; + aufs_bindex_t bindex, btail; + + LKTRTrace("%.*s\n", AuDLNPair(dentry)); + inode = dentry->d_inode; + AuDebugOn(!inode || !S_ISDIR(inode->i_mode)); + + err = 0; + arg.whlist = whlist; + arg.flags = AuTestEmpty_WHONLY; + if (unlikely(au_opt_test(au_mntflags(dentry->d_sb), SHWH))) + au_fset_testempty(arg.flags, SHWH); + btail = au_dbtaildir(dentry); + for (bindex = au_dbstart(dentry); !err && bindex <= btail; bindex++) { + struct dentry *h_dentry; + h_dentry = au_h_dptr(dentry, bindex); + if (h_dentry && h_dentry->d_inode) { + arg.bindex = bindex; + err = sio_test_empty(dentry, &arg); + } + } + + AuTraceErr(err); + return err; +} + +/* ---------------------------------------------------------------------- */ + +struct file_operations aufs_dir_fop = { + .read = generic_read_dir, + .readdir = aufs_readdir, + .open = aufs_open_dir, + .release = aufs_release_dir, + .flush = aufs_flush, + .fsync = aufs_fsync_dir, +}; --- linux-2.6.27.orig/ubuntu/ndiswrapper/ntoskernel_io.c +++ linux-2.6.27/ubuntu/ndiswrapper/ntoskernel_io.c @@ -0,0 +1,1106 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "ntoskernel.h" +#include "ndis.h" +#include "wrapndis.h" +#include "usb.h" +#include "loader.h" +#include "ntoskernel_io_exports.h" + +wstdcall void WIN_FUNC(IoAcquireCancelSpinLock,1) + (KIRQL *irql) __acquires(irql) +{ + spin_lock_bh(&irp_cancel_lock); + *irql = 0; +} + +wstdcall void WIN_FUNC(IoReleaseCancelSpinLock,1) + (KIRQL irql) __releases(irql) +{ + spin_unlock_bh(&irp_cancel_lock); +} + +wstdcall int WIN_FUNC(IoIsWdmVersionAvailable,2) + (UCHAR major, UCHAR minor) +{ + IOENTER("%d, %x", major, minor); + if (major == 1 && + (minor == 0x30 || // Windows 2003 + minor == 0x20 || // Windows XP + minor == 0x10)) // Windows 2000 + IOEXIT(return TRUE); + IOEXIT(return FALSE); +} + +wstdcall BOOLEAN WIN_FUNC(IoIs32bitProcess,1) + (struct irp *irp) +{ +#ifdef CONFIG_X86_64 + return FALSE; +#else + return TRUE; +#endif +} + +wstdcall void WIN_FUNC(IoInitializeIrp,3) + (struct irp *irp, USHORT size, CCHAR stack_count) +{ + IOENTER("irp: %p, %d, %d", irp, size, stack_count); + + memset(irp, 0, size); + irp->size = size; + irp->stack_count = stack_count; + irp->current_location = stack_count; + IoGetCurrentIrpStackLocation(irp) = IRP_SL(irp, stack_count); + IOEXIT(return); +} + +wstdcall void WIN_FUNC(IoReuseIrp,2) + (struct irp *irp, NTSTATUS status) +{ + IOENTER("%p, %d", irp, status); + if (irp) { + UCHAR alloc_flags; + + alloc_flags = irp->alloc_flags; + IoInitializeIrp(irp, irp->size, irp->stack_count); + irp->alloc_flags = alloc_flags; + irp->io_status.status = status; + } + IOEXIT(return); +} + +wstdcall struct irp *WIN_FUNC(IoAllocateIrp,2) + (char stack_count, BOOLEAN charge_quota) +{ + struct irp *irp; + int irp_size; + + IOENTER("count: %d", stack_count); + stack_count++; + irp_size = IoSizeOfIrp(stack_count); + irp = kmalloc(irp_size, irql_gfp()); + if (irp) + IoInitializeIrp(irp, irp_size, stack_count); + IOTRACE("irp %p", irp); + IOEXIT(return irp); +} + +wstdcall BOOLEAN WIN_FUNC(IoCancelIrp,1) + (struct irp *irp) +{ + typeof(irp->cancel_routine) cancel_routine; + + /* NB: this function may be called at DISPATCH_LEVEL */ + IOTRACE("irp: %p", irp); + if (!irp) + return FALSE; + DUMP_IRP(irp); + IoAcquireCancelSpinLock(&irp->cancel_irql); + cancel_routine = xchg(&irp->cancel_routine, NULL); + IOTRACE("%p", cancel_routine); + irp->cancel = TRUE; + if (cancel_routine) { + struct io_stack_location *irp_sl; + irp_sl = IoGetCurrentIrpStackLocation(irp); + IOTRACE("%p, %p", irp_sl, irp_sl->dev_obj); + /* cancel_routine will release the spin lock */ + __release(irp->cancel_irql); + LIN2WIN2(cancel_routine, irp_sl->dev_obj, irp); + /* in usb's cancel, irp->cancel is set to indicate + * status of cancel */ + IOEXIT(return xchg(&irp->cancel, TRUE)); + } else { + IOTRACE("irp %p already canceled", irp); + IoReleaseCancelSpinLock(irp->cancel_irql); + IOEXIT(return FALSE); + } +} + +wstdcall void IoQueueThreadIrp(struct irp *irp) +{ + struct nt_thread *thread; + KIRQL irql; + + thread = get_current_nt_thread(); + if (thread) { + IOTRACE("thread: %p, task: %p", thread, thread->task); + irp->flags |= IRP_SYNCHRONOUS_API; + irql = nt_spin_lock_irql(&thread->lock, DISPATCH_LEVEL); + InsertTailList(&thread->irps, &irp->thread_list); + IoIrpThread(irp) = thread; + nt_spin_unlock_irql(&thread->lock, irql); + } else + IoIrpThread(irp) = NULL; +} + +wstdcall void IoDequeueThreadIrp(struct irp *irp) +{ + struct nt_thread *thread; + KIRQL irql; + + thread = IoIrpThread(irp); + if (thread) { + irql = nt_spin_lock_irql(&thread->lock, DISPATCH_LEVEL); + RemoveEntryList(&irp->thread_list); + nt_spin_unlock_irql(&thread->lock, irql); + } +} + +wstdcall void WIN_FUNC(IoFreeIrp,1) + (struct irp *irp) +{ + IOENTER("irp = %p", irp); + if (irp->flags & IRP_SYNCHRONOUS_API) + IoDequeueThreadIrp(irp); + kfree(irp); + + IOEXIT(return); +} + +wstdcall struct irp *WIN_FUNC(IoBuildAsynchronousFsdRequest,6) + (ULONG major_fn, struct device_object *dev_obj, void *buffer, + ULONG length, LARGE_INTEGER *offset, + struct io_status_block *user_status) +{ + struct irp *irp; + struct io_stack_location *irp_sl; + + IOENTER("%p", dev_obj); + if (!dev_obj) + IOEXIT(return NULL); + irp = IoAllocateIrp(dev_obj->stack_count, FALSE); + if (irp == NULL) { + WARNING("couldn't allocate irp"); + IOEXIT(return NULL); + } + + irp_sl = IoGetNextIrpStackLocation(irp); + irp_sl->major_fn = major_fn; + IOTRACE("major_fn: %d", major_fn); + irp_sl->minor_fn = 0; + irp_sl->flags = 0; + irp_sl->control = 0; + irp_sl->dev_obj = dev_obj; + irp_sl->file_obj = NULL; + irp_sl->completion_routine = NULL; + + if (dev_obj->flags & DO_DIRECT_IO) { + irp->mdl = IoAllocateMdl(buffer, length, FALSE, FALSE, irp); + if (irp->mdl == NULL) { + IoFreeIrp(irp); + return NULL; + } + MmProbeAndLockPages(irp->mdl, KernelMode, + major_fn == IRP_MJ_WRITE ? + IoReadAccess : IoWriteAccess); + IOTRACE("mdl: %p", irp->mdl); + } else if (dev_obj->flags & DO_BUFFERED_IO) { + irp->associated_irp.system_buffer = buffer; + irp->flags = IRP_BUFFERED_IO; + irp->mdl = NULL; + IOTRACE("buffer: %p", buffer); + } + if (major_fn == IRP_MJ_READ) { + irp_sl->params.read.length = length; + irp_sl->params.read.byte_offset = *offset; + } else if (major_fn == IRP_MJ_WRITE) { + irp_sl->params.write.length = length; + irp_sl->params.write.byte_offset = *offset; + } + irp->user_status = user_status; + IOTRACE("irp: %p", irp); + return irp; +} + +wstdcall struct irp *WIN_FUNC(IoBuildSynchronousFsdRequest,7) + (ULONG major_fn, struct device_object *dev_obj, void *buf, + ULONG length, LARGE_INTEGER *offset, struct nt_event *event, + struct io_status_block *user_status) +{ + struct irp *irp; + + irp = IoBuildAsynchronousFsdRequest(major_fn, dev_obj, buf, length, + offset, user_status); + if (irp == NULL) + return NULL; + irp->user_event = event; + IoQueueThreadIrp(irp); + return irp; +} + +wstdcall struct irp *WIN_FUNC(IoBuildDeviceIoControlRequest,9) + (ULONG ioctl, struct device_object *dev_obj, + void *input_buf, ULONG input_buf_len, void *output_buf, + ULONG output_buf_len, BOOLEAN internal_ioctl, + struct nt_event *event, struct io_status_block *io_status) +{ + struct irp *irp; + struct io_stack_location *irp_sl; + ULONG buf_len; + + IOENTER("%p, 0x%08x, %d", dev_obj, ioctl, internal_ioctl); + if (!dev_obj) + IOEXIT(return NULL); + irp = IoAllocateIrp(dev_obj->stack_count, FALSE); + if (irp == NULL) { + WARNING("couldn't allocate irp"); + return NULL; + } + irp_sl = IoGetNextIrpStackLocation(irp); + irp_sl->params.dev_ioctl.code = ioctl; + irp_sl->params.dev_ioctl.input_buf_len = input_buf_len; + irp_sl->params.dev_ioctl.output_buf_len = output_buf_len; + irp_sl->major_fn = (internal_ioctl) ? + IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL; + IOTRACE("%d", IO_METHOD_FROM_CTL_CODE(ioctl)); + + switch (IO_METHOD_FROM_CTL_CODE(ioctl)) { + case METHOD_BUFFERED: + buf_len = max(input_buf_len, output_buf_len); + if (buf_len) { + irp->associated_irp.system_buffer = + ExAllocatePoolWithTag(NonPagedPool, buf_len, 0); + if (!irp->associated_irp.system_buffer) { + IoFreeIrp(irp); + IOEXIT(return NULL); + } + irp->associated_irp.system_buffer = input_buf; + if (input_buf) + memcpy(irp->associated_irp.system_buffer, + input_buf, input_buf_len); + irp->flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; + if (output_buf) + irp->flags = IRP_INPUT_OPERATION; + irp->user_buf = output_buf; + } else + irp->user_buf = NULL; + break; + case METHOD_IN_DIRECT: + case METHOD_OUT_DIRECT: + if (input_buf) { + irp->associated_irp.system_buffer = + ExAllocatePoolWithTag(NonPagedPool, + input_buf_len, 0); + if (!irp->associated_irp.system_buffer) { + IoFreeIrp(irp); + IOEXIT(return NULL); + } + memcpy(irp->associated_irp.system_buffer, + input_buf, input_buf_len); + irp->flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; + } + /* TODO: we are supposed to setup MDL, but USB layer + * doesn't use MDLs. Moreover, USB layer mirrors + * non-DMAable buffers, so no need to allocate + * DMAable buffer here */ + if (output_buf) { + irp->associated_irp.system_buffer = + ExAllocatePoolWithTag(NonPagedPool, + output_buf_len, 0); + if (!irp->associated_irp.system_buffer) { + IoFreeIrp(irp); + IOEXIT(return NULL); + } + irp->flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; + } + break; + case METHOD_NEITHER: + irp->user_buf = output_buf; + irp_sl->params.dev_ioctl.type3_input_buf = input_buf; + break; + } + + irp->user_status = io_status; + irp->user_event = event; + IoQueueThreadIrp(irp); + + IOTRACE("irp: %p", irp); + IOEXIT(return irp); +} + +wfastcall NTSTATUS WIN_FUNC(IofCallDriver,2) + (struct device_object *dev_obj, struct irp *irp) +{ + struct io_stack_location *irp_sl; + NTSTATUS status; + driver_dispatch_t *major_func; + struct driver_object *drv_obj; + + if (irp->current_location <= 0) { + ERROR("invalid irp: %p, %d", irp, irp->current_location); + return STATUS_INVALID_PARAMETER; + } + IOTRACE("%p, %p, %p, %d, %d, %p", dev_obj, irp, dev_obj->drv_obj, + irp->current_location, irp->stack_count, + IoGetCurrentIrpStackLocation(irp)); + IoSetNextIrpStackLocation(irp); + DUMP_IRP(irp); + irp_sl = IoGetCurrentIrpStackLocation(irp); + drv_obj = dev_obj->drv_obj; + irp_sl->dev_obj = dev_obj; + major_func = drv_obj->major_func[irp_sl->major_fn]; + IOTRACE("major_func: %p, dev_obj: %p", major_func, dev_obj); + if (major_func) + status = LIN2WIN2(major_func, dev_obj, irp); + else { + ERROR("major_function %d is not implemented", + irp_sl->major_fn); + status = STATUS_NOT_SUPPORTED; + } + IOEXIT(return status); +} + +wfastcall void WIN_FUNC(IofCompleteRequest,2) + (struct irp *irp, CHAR prio_boost) +{ + struct io_stack_location *irp_sl; + +#ifdef IO_DEBUG + DUMP_IRP(irp); + if (irp->io_status.status == STATUS_PENDING) { + ERROR("invalid irp: %p, STATUS_PENDING", irp); + return; + } + if (irp->current_location < 0 || + irp->current_location >= irp->stack_count) { + ERROR("invalid irp: %p, %d", irp, irp->current_location); + return; + } +#endif + for (irp_sl = IoGetCurrentIrpStackLocation(irp); + irp->current_location < irp->stack_count; irp_sl++) { + struct device_object *dev_obj; + NTSTATUS status; + + DUMP_IRP(irp); + if (irp_sl->control & SL_PENDING_RETURNED) + irp->pending_returned = TRUE; + + /* current_location and dev_obj must be same as when + * driver called IoSetCompletionRoutine, which sets + * completion routine at next (lower) location, which + * is what we are going to call below; so we set + * current_location and dev_obj for the previous + * (higher) location */ + IoSkipCurrentIrpStackLocation(irp); + if (irp->current_location < irp->stack_count) + dev_obj = IoGetCurrentIrpStackLocation(irp)->dev_obj; + else + dev_obj = NULL; + + IOTRACE("%d, %d, %p", irp->current_location, irp->stack_count, + dev_obj); + if (irp_sl->completion_routine && + ((irp->io_status.status == STATUS_SUCCESS && + irp_sl->control & SL_INVOKE_ON_SUCCESS) || + (irp->io_status.status != STATUS_SUCCESS && + irp_sl->control & SL_INVOKE_ON_ERROR) || + (irp->cancel == TRUE && + irp_sl->control & SL_INVOKE_ON_CANCEL))) { + IOTRACE("calling completion_routine at: %p, %p", + irp_sl->completion_routine, irp_sl->context); + status = LIN2WIN3(irp_sl->completion_routine, + dev_obj, irp, irp_sl->context); + IOTRACE("status: %08X", status); + if (status == STATUS_MORE_PROCESSING_REQUIRED) + IOEXIT(return); + } else { + /* propagate pending status to next irp_sl */ + if (irp->pending_returned && + irp->current_location < irp->stack_count) + IoMarkIrpPending(irp); + } + } + + if (irp->user_status) { + irp->user_status->status = irp->io_status.status; + irp->user_status->info = irp->io_status.info; + } + + if (irp->user_event) { + IOTRACE("setting event %p", irp->user_event); + KeSetEvent(irp->user_event, prio_boost, FALSE); + } + + if (irp->associated_irp.system_buffer && + (irp->flags & IRP_DEALLOCATE_BUFFER)) + ExFreePool(irp->associated_irp.system_buffer); + else { + struct mdl *mdl; + while ((mdl = irp->mdl)) { + irp->mdl = mdl->next; + MmUnlockPages(mdl); + IoFreeMdl(mdl); + } + } + IOTRACE("freeing irp %p", irp); + IoFreeIrp(irp); + IOEXIT(return); +} + +wstdcall NTSTATUS IoPassIrpDown(struct device_object *dev_obj, struct irp *irp) +{ + IoSkipCurrentIrpStackLocation(irp); + IOEXIT(return IoCallDriver(dev_obj, irp)); +} + +wstdcall NTSTATUS IoIrpSyncComplete(struct device_object *dev_obj, + struct irp *irp, void *context) +{ + if (irp->pending_returned == TRUE) + KeSetEvent(context, IO_NO_INCREMENT, FALSE); + IOEXIT(return STATUS_MORE_PROCESSING_REQUIRED); +} +WIN_FUNC_DECL(IoIrpSyncComplete,3) + +wstdcall NTSTATUS IoSyncForwardIrp(struct device_object *dev_obj, + struct irp *irp) +{ + struct nt_event event; + NTSTATUS status; + + IoCopyCurrentIrpStackLocationToNext(irp); + KeInitializeEvent(&event, SynchronizationEvent, FALSE); + /* completion function is called as Windows function */ + IoSetCompletionRoutine(irp, WIN_FUNC_PTR(IoIrpSyncComplete,3), &event, + TRUE, TRUE, TRUE); + status = IoCallDriver(dev_obj, irp); + IOTRACE("%08X", status); + if (status == STATUS_PENDING) { + KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, + NULL); + status = irp->io_status.status; + } + IOTRACE("%08X", status); + IOEXIT(return status); +} +WIN_FUNC_DECL(IoSyncForwardIrp,2) + +wstdcall NTSTATUS IoAsyncForwardIrp(struct device_object *dev_obj, + struct irp *irp) +{ + NTSTATUS status; + + IoCopyCurrentIrpStackLocationToNext(irp); + status = IoCallDriver(dev_obj, irp); + IOEXIT(return status); +} +WIN_FUNC_DECL(IoAsyncForwardIrp,2) + +wstdcall NTSTATUS IoInvalidDeviceRequest(struct device_object *dev_obj, + struct irp *irp) +{ + struct io_stack_location *irp_sl; + NTSTATUS status; + + irp_sl = IoGetCurrentIrpStackLocation(irp); + WARNING("%d:%d not implemented", irp_sl->major_fn, irp_sl->minor_fn); + irp->io_status.status = STATUS_SUCCESS; + irp->io_status.info = 0; + status = irp->io_status.status; + IoCompleteRequest(irp, IO_NO_INCREMENT); + IOEXIT(return status); +} +WIN_FUNC_DECL(IoInvalidDeviceRequest,2) + +static irqreturn_t io_irq_isr(int irq, void *data ISR_PT_REGS_PARAM_DECL) +{ + struct kinterrupt *interrupt = data; + BOOLEAN ret; + +#ifdef CONFIG_DEBUG_SHIRQ + if (!interrupt->u.enabled) + EXIT1(return IRQ_NONE); +#endif + TRACE6("%p", interrupt); + nt_spin_lock(interrupt->actual_lock); + ret = LIN2WIN2(interrupt->isr, interrupt, interrupt->isr_ctx); + nt_spin_unlock(interrupt->actual_lock); + if (ret == TRUE) + EXIT6(return IRQ_HANDLED); + else + EXIT6(return IRQ_NONE); +} + +wstdcall NTSTATUS WIN_FUNC(IoConnectInterrupt,11) + (struct kinterrupt **kinterrupt, PKSERVICE_ROUTINE isr, void *isr_ctx, + NT_SPIN_LOCK *lock, ULONG vector, KIRQL irql, KIRQL synch_irql, + enum kinterrupt_mode mode, BOOLEAN shared, KAFFINITY cpu_mask, + BOOLEAN save_fp) +{ + struct kinterrupt *interrupt; + IOENTER(""); + interrupt = kzalloc(sizeof(*interrupt), GFP_KERNEL); + if (!interrupt) + IOEXIT(return STATUS_INSUFFICIENT_RESOURCES); + interrupt->vector = vector; + interrupt->cpu_mask = cpu_mask; + nt_spin_lock_init(&interrupt->lock); + if (lock) + interrupt->actual_lock = lock; + else + interrupt->actual_lock = &interrupt->lock; + interrupt->shared = shared; + interrupt->save_fp = save_fp; + interrupt->isr = isr; + interrupt->isr_ctx = isr_ctx; + InitializeListHead(&interrupt->list); + interrupt->irql = irql; + interrupt->synch_irql = synch_irql; + interrupt->mode = mode; + if (request_irq(vector, io_irq_isr, shared ? IRQF_SHARED : 0, + "ndiswrapper", interrupt)) { + WARNING("request for irq %d failed", vector); + kfree(interrupt); + IOEXIT(return STATUS_INSUFFICIENT_RESOURCES); + } + *kinterrupt = interrupt; +#ifdef CONFIG_DEBUG_SHIRQ + interrupt->u.enabled = 1; +#endif + IOEXIT(return STATUS_SUCCESS); +} + +wstdcall void WIN_FUNC(IoDisconnectInterrupt,1) + (struct kinterrupt *interrupt) +{ +#ifdef CONFIG_DEBUG_SHIRQ + interrupt->u.enabled = 0; +#endif + free_irq(interrupt->vector, interrupt); + kfree(interrupt); +} + +wstdcall struct mdl *WIN_FUNC(IoAllocateMdl,5) + (void *virt, ULONG length, BOOLEAN second_buf, BOOLEAN charge_quota, + struct irp *irp) +{ + struct mdl *mdl; + mdl = allocate_init_mdl(virt, length); + if (!mdl) + return NULL; + if (irp) { + if (second_buf == TRUE) { + struct mdl *last; + + last = irp->mdl; + while (last->next) + last = last->next; + last->next = mdl; + } else + irp->mdl = mdl; + } + IOTRACE("%p", mdl); + return mdl; +} + +wstdcall void WIN_FUNC(IoFreeMdl,1) + (struct mdl *mdl) +{ + IOTRACE("%p", mdl); + free_mdl(mdl); +} + +wstdcall struct io_workitem *WIN_FUNC(IoAllocateWorkItem,1) + (struct device_object *dev_obj) +{ + struct io_workitem *io_workitem; + + IOENTER("%p", dev_obj); + io_workitem = kmalloc(sizeof(*io_workitem), irql_gfp()); + if (!io_workitem) + IOEXIT(return NULL); + io_workitem->dev_obj = dev_obj; + IOEXIT(return io_workitem); +} + +wstdcall void WIN_FUNC(IoFreeWorkItem,1) + (struct io_workitem *io_workitem) +{ + kfree(io_workitem); + IOEXIT(return); +} + +wstdcall void WIN_FUNC(IoQueueWorkItem,4) + (struct io_workitem *io_workitem, void *func, + enum work_queue_type queue_type, void *context) +{ + IOENTER("%p, %p", io_workitem, io_workitem->dev_obj); + io_workitem->worker_routine = func; + io_workitem->context = context; + schedule_ntos_work_item(func, io_workitem->dev_obj, context); + IOEXIT(return); +} + +wstdcall void WIN_FUNC(ExQueueWorkItem,2) + (struct io_workitem *io_workitem, enum work_queue_type queue_type) +{ + IOENTER("%p", io_workitem); + schedule_ntos_work_item(io_workitem->worker_routine, + io_workitem->dev_obj, io_workitem->context); +} + +wstdcall NTSTATUS WIN_FUNC(IoAllocateDriverObjectExtension,4) + (struct driver_object *drv_obj, void *client_id, ULONG extlen, + void **ext) +{ + struct custom_ext *ce; + + IOENTER("%p, %p", drv_obj, client_id); + ce = kmalloc(sizeof(*ce) + extlen, irql_gfp()); + if (ce == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + + IOTRACE("custom_ext: %p", ce); + ce->client_id = client_id; + spin_lock_bh(&ntoskernel_lock); + InsertTailList(&drv_obj->drv_ext->custom_ext, &ce->list); + spin_unlock_bh(&ntoskernel_lock); + + *ext = (void *)ce + sizeof(*ce); + IOTRACE("ext: %p", *ext); + IOEXIT(return STATUS_SUCCESS); +} + +wstdcall void *WIN_FUNC(IoGetDriverObjectExtension,2) + (struct driver_object *drv_obj, void *client_id) +{ + struct custom_ext *ce; + void *ret; + + IOENTER("drv_obj: %p, client_id: %p", drv_obj, client_id); + ret = NULL; + spin_lock_bh(&ntoskernel_lock); + nt_list_for_each_entry(ce, &drv_obj->drv_ext->custom_ext, list) { + if (ce->client_id == client_id) { + ret = (void *)ce + sizeof(*ce); + break; + } + } + spin_unlock_bh(&ntoskernel_lock); + IOTRACE("ret: %p", ret); + return ret; +} + +void free_custom_extensions(struct driver_extension *drv_ext) +{ + struct nt_list *ent; + + IOENTER("%p", drv_ext); + spin_lock_bh(&ntoskernel_lock); + while ((ent = RemoveHeadList(&drv_ext->custom_ext))) + kfree(ent); + spin_unlock_bh(&ntoskernel_lock); + IOEXIT(return); +} + +wstdcall NTSTATUS WIN_FUNC(IoCreateDevice,7) + (struct driver_object *drv_obj, ULONG dev_ext_length, + struct unicode_string *dev_name, DEVICE_TYPE dev_type, + ULONG dev_chars, BOOLEAN exclusive, struct device_object **newdev) +{ + struct device_object *dev; + struct dev_obj_ext *dev_obj_ext; + int size; + + IOENTER("%p, %u, %p", drv_obj, dev_ext_length, dev_name); + + size = sizeof(*dev) + dev_ext_length + sizeof(*dev_obj_ext); + dev = allocate_object(size, OBJECT_TYPE_DEVICE, dev_name); + if (!dev) + IOEXIT(return STATUS_INSUFFICIENT_RESOURCES); + if (dev_ext_length) + dev->dev_ext = dev + 1; + else + dev->dev_ext = NULL; + + dev_obj_ext = ((void *)(dev + 1)) + dev_ext_length; + dev_obj_ext->dev_obj = dev; + dev_obj_ext->size = 0; + dev_obj_ext->type = IO_TYPE_DEVICE; + dev->dev_obj_ext = dev_obj_ext; + + dev->type = dev_type; + dev->flags = 0; + dev->size = sizeof(*dev) + dev_ext_length; + dev->ref_count = 1; + dev->attached = NULL; + dev->stack_count = 1; + + dev->drv_obj = drv_obj; + dev->next = drv_obj->dev_obj; + drv_obj->dev_obj = dev; + + dev->align_req = 1; + dev->characteristics = dev_chars; + dev->io_timer = NULL; + KeInitializeEvent(&dev->lock, SynchronizationEvent, TRUE); + dev->vpb = NULL; + + IOTRACE("dev: %p, ext: %p", dev, dev->dev_ext); + *newdev = dev; + IOEXIT(return STATUS_SUCCESS); +} + +wstdcall NTSTATUS WIN_FUNC(IoCreateUnprotectedSymbolicLink,2) + (struct unicode_string *link, struct unicode_string *dev_name) +{ + struct ansi_string ansi; + + IOENTER("%p, %p", dev_name, link); + if (dev_name && (RtlUnicodeStringToAnsiString(&ansi, dev_name, TRUE) == + STATUS_SUCCESS)) { + IOTRACE("dev_name: %s", ansi.buf); + RtlFreeAnsiString(&ansi); + } + if (link && (RtlUnicodeStringToAnsiString(&ansi, link, TRUE) == + STATUS_SUCCESS)) { + IOTRACE("link: %s", ansi.buf); + RtlFreeAnsiString(&ansi); + } +// TODO(); + IOEXIT(return STATUS_SUCCESS); +} + +wstdcall NTSTATUS WIN_FUNC(IoCreateSymbolicLink,2) + (struct unicode_string *link, struct unicode_string *dev_name) +{ + IOEXIT(return IoCreateUnprotectedSymbolicLink(link, dev_name)); +} + +wstdcall NTSTATUS WIN_FUNC(IoDeleteSymbolicLink,1) + (struct unicode_string *link) +{ + struct ansi_string ansi; + + IOENTER("%p", link); + if (link && (RtlUnicodeStringToAnsiString(&ansi, link, TRUE) == + STATUS_SUCCESS)) { + IOTRACE("dev_name: %s", ansi.buf); + RtlFreeAnsiString(&ansi); + } + IOEXIT(return STATUS_SUCCESS); +} + +wstdcall void WIN_FUNC(IoDeleteDevice,1) + (struct device_object *dev) +{ + IOENTER("%p", dev); + if (dev == NULL) + IOEXIT(return); + IOTRACE("drv_obj: %p", dev->drv_obj); + if (dev->drv_obj) { + struct device_object *prev; + + prev = dev->drv_obj->dev_obj; + IOTRACE("dev_obj: %p", prev); + if (prev == dev) + dev->drv_obj->dev_obj = dev->next; + else if (prev) { + while (prev->next != dev) + prev = prev->next; + prev->next = dev->next; + } + } + ObDereferenceObject(dev); + IOEXIT(return); +} + +wstdcall void WIN_FUNC(IoDetachDevice,1) + (struct device_object *tgt) +{ + struct device_object *tail; + + IOENTER("%p", tgt); + if (!tgt) + IOEXIT(return); + tail = tgt->attached; + if (!tail) + IOEXIT(return); + IOTRACE("tail: %p", tail); + + spin_lock_bh(&ntoskernel_lock); + tgt->attached = tail->attached; + IOTRACE("attached:%p", tgt->attached); + for ( ; tail; tail = tail->attached) { + IOTRACE("tail:%p", tail); + tail->stack_count--; + } + spin_unlock_bh(&ntoskernel_lock); + IOEXIT(return); +} + +wstdcall struct device_object *WIN_FUNC(IoGetAttachedDevice,1) + (struct device_object *dev) +{ + IOENTER("%p", dev); + if (!dev) + IOEXIT(return NULL); + spin_lock_bh(&ntoskernel_lock); + while (dev->attached) + dev = dev->attached; + spin_unlock_bh(&ntoskernel_lock); + IOEXIT(return dev); +} + +wstdcall struct device_object *WIN_FUNC(IoGetAttachedDeviceReference,1) + (struct device_object *dev) +{ + IOENTER("%p", dev); + if (!dev) + IOEXIT(return NULL); + dev = IoGetAttachedDevice(dev); + ObReferenceObject(dev); + IOEXIT(return dev); +} + +wstdcall struct device_object *WIN_FUNC(IoAttachDeviceToDeviceStack,2) + (struct device_object *src, struct device_object *tgt) +{ + struct device_object *attached; + struct dev_obj_ext *src_dev_ext; + + IOENTER("%p, %p", src, tgt); + attached = IoGetAttachedDevice(tgt); + IOTRACE("%p", attached); + src_dev_ext = src->dev_obj_ext; + spin_lock_bh(&ntoskernel_lock); + if (attached) + attached->attached = src; + src->attached = NULL; + src->stack_count = attached->stack_count + 1; + src_dev_ext->attached_to = attached; + spin_unlock_bh(&ntoskernel_lock); + IOTRACE("stack_count: %d -> %d", attached->stack_count, + src->stack_count); + IOEXIT(return attached); +} + +wstdcall NTSTATUS WIN_FUNC(IoGetDeviceProperty,5) + (struct device_object *pdo, enum device_registry_property dev_property, + ULONG buffer_len, void *buffer, ULONG *result_len) +{ + struct ansi_string ansi; + struct unicode_string unicode; + struct wrap_device *wd; + ULONG need; + + IOENTER("dev_obj = %p, dev_property = %d, buffer_len = %u, " + "buffer = %p, result_len = %p", pdo, dev_property, + buffer_len, buffer, result_len); + + wd = pdo->reserved; + switch (dev_property) { + case DevicePropertyDeviceDescription: + case DevicePropertyFriendlyName: + case DevicePropertyDriverKeyName: + if (wrap_is_pci_bus(wd->dev_bus)) + RtlInitAnsiString(&ansi, "PCI"); + else // if (wrap_is_usb_bus(wd->dev_bus)) + RtlInitAnsiString(&ansi, "USB"); + need = sizeof(wchar_t) * (ansi.max_length + 1); + if (buffer_len < need) { + *result_len = need; + IOEXIT(return STATUS_BUFFER_TOO_SMALL); + } + unicode.max_length = buffer_len; + unicode.buf = buffer; + if (RtlAnsiStringToUnicodeString(&unicode, &ansi, + FALSE) != STATUS_SUCCESS) { + *result_len = unicode.length; + IOEXIT(return STATUS_BUFFER_TOO_SMALL); + } + IOEXIT(return STATUS_SUCCESS); + default: + WARNING("%d not implemented", dev_property); + IOEXIT(return STATUS_INVALID_PARAMETER_2); + } +} + +wstdcall NTSTATUS WIN_FUNC(IoGetDeviceObjectPointer,4) + (struct unicode_string *name, ACCESS_MASK desired_access, + void *file_obj, struct device_object *dev_obj) +{ + struct common_object_header *coh; + + dev_obj = NULL; + /* TODO: access is not checked and file_obj is set to NULL */ + file_obj = NULL; + spin_lock_bh(&ntoskernel_lock); + nt_list_for_each_entry(coh, &object_list, list) { + TRACE5("header: %p, type: %d", coh, coh->type); + if (coh->type != OBJECT_TYPE_DEVICE) + continue; + if (!RtlCompareUnicodeString(&coh->name, name, TRUE)) { + dev_obj = HEADER_TO_OBJECT(coh); + TRACE5("dev_obj: %p", dev_obj); + break; + } + } + spin_unlock_bh(&ntoskernel_lock); + if (dev_obj) + IOEXIT(return STATUS_SUCCESS); + else + IOEXIT(return STATUS_OBJECT_NAME_INVALID); +} + +/* NOTE: Make sure to compile with -freg-struct-return, so gcc will + * return union in register, like Windows */ +wstdcall union power_state WIN_FUNC(PoSetPowerState,3) + (struct device_object *dev_obj, enum power_state_type type, + union power_state state) +{ + IOEXIT(return state); +} + +wstdcall NTSTATUS WIN_FUNC(PoCallDriver,2) + (struct device_object *dev_obj, struct irp *irp) +{ + return IoCallDriver(dev_obj, irp); +} + +wstdcall NTSTATUS WIN_FUNC(PoRequestPowerIrp,6) + (struct device_object *dev_obj, UCHAR minor_fn, + union power_state power_state, void *completion_func, + void *context, struct irp **pirp) +{ + struct irp *irp; + struct io_stack_location *irp_sl; + + TRACE1("%p, %d, %p", dev_obj, dev_obj->stack_count, dev_obj->drv_obj); + irp = IoAllocateIrp(dev_obj->stack_count, FALSE); + if (!irp) + return STATUS_INSUFFICIENT_RESOURCES; + irp_sl = IoGetNextIrpStackLocation(irp); + irp_sl->major_fn = IRP_MJ_POWER; + irp_sl->minor_fn = minor_fn; + if (minor_fn == IRP_MN_WAIT_WAKE) + irp_sl->params.power.type = SystemPowerState; + else + irp_sl->params.power.type = DevicePowerState; + irp_sl->params.power.state = power_state; + irp_sl->completion_routine = completion_func; + irp->io_status.status = STATUS_NOT_SUPPORTED; + *pirp = irp; + return PoCallDriver(dev_obj, irp); +} + +wstdcall void WIN_FUNC(PoStartNextPowerIrp,1) + (struct irp *irp) +{ + IOENTER("irp = %p", irp); + IOEXIT(return); +} + +wstdcall void WIN_FUNC(IoInitializeRemoveLockEx,5) + (struct io_remove_lock *lock, ULONG alloc_tag, ULONG max_locked_min, + ULONG high_mark, ULONG lock_size) +{ + TODO(); +} + +wstdcall void *WIN_FUNC(IoAllocateErrorLogEntry,2) + (void *io_object, UCHAR entry_size) +{ + /* not implemented fully */ + void *ret = kmalloc(sizeof(struct io_error_log_packet) + entry_size, + irql_gfp()); + TRACE2("%p", ret); + if (ret) + return ret + sizeof(struct io_error_log_packet); + else + return NULL; +} + +wstdcall void WIN_FUNC(IoWriteErrorLogEntry,1) + (void *entry) +{ + /* TODO: log error with codes and message */ + ERROR(""); +} + +wstdcall void WIN_FUNC(IoFreeErrorLogEntry,1) + (void *entry) +{ + TRACE2("%p", entry); + kfree(entry - sizeof(struct io_error_log_packet)); +} + +wstdcall NTSTATUS WIN_FUNC(IoAcquireRemoveLockEx,5) + (struct io_remove_lock lock, void *tag, char *file, ULONG line, + ULONG lock_size) +{ + TODO(); + IOEXIT(return STATUS_SUCCESS); +} + +wstdcall NTSTATUS WIN_FUNC(IoReleaseRemoveLockEx,3) + (struct io_remove_lock lock, void *tag, ULONG lock_size) +{ + TODO(); + IOEXIT(return STATUS_SUCCESS); +} + +wstdcall NTSTATUS WIN_FUNC(IoRegisterDeviceInterface,4) + (struct device_object *pdo, struct guid *guid_class, + struct unicode_string *reference, struct unicode_string *link) +{ + struct ansi_string ansi; + + /* TODO: check if pdo is valid */ + RtlInitAnsiString(&ansi, "ndis"); + ENTER1("pdo: %p, ref: %p, link: %p, %x, %x, %x", pdo, reference, link, + guid_class->data1, guid_class->data2, guid_class->data3); + return RtlAnsiStringToUnicodeString(link, &ansi, TRUE); +} + +wstdcall NTSTATUS WIN_FUNC(IoSetDeviceInterfaceState,2) + (struct unicode_string *link, BOOLEAN enable) +{ + ENTER1("link: %p, enable: %d", link, enable); + return STATUS_SUCCESS; +} + +wstdcall NTSTATUS WIN_FUNC(IoOpenDeviceRegistryKey,4) + (struct device_object *dev_obj, ULONG type, ACCESS_MASK mask, + void **handle) +{ + ENTER1("dev_obj: %p", dev_obj); + *handle = dev_obj; + return STATUS_SUCCESS; +} + +wstdcall NTSTATUS WIN_FUNC(IoWMIRegistrationControl,2) + (struct device_object *dev_obj, ULONG action) +{ + ENTER2("%p, %d", dev_obj, action); + EXIT2(return STATUS_SUCCESS); +} + +wstdcall void WIN_FUNC(IoInvalidateDeviceRelations,2) + (struct device_object *dev_obj, enum device_relation_type type) +{ + INFO("%p, %d", dev_obj, type); + TODO(); +} + +wstdcall void WIN_FUNC(IoInvalidateDeviceState,1) + (struct device_object *pdo) +{ + INFO("%p", pdo); + TODO(); +} --- linux-2.6.27.orig/ubuntu/ndiswrapper/wrapmem.h +++ linux-2.6.27/ubuntu/ndiswrapper/wrapmem.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2006 Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _WRAPMEM_H_ + +/* set ALLOC_DEBUG to 1 to get information about memory used by both + * ndiswrapper and Windows driver by reading + * /proc/net/ndiswrapper/debug; this will also show memory leaks + * (memory allocated but not freed) when ndiswrapper module is + * unloaded. + + * ALLOC_DEBUG=2: details about individual allocations leaking is printed + * ALLOC_DEBUG=3: tags in ExAllocatePoolWithTag leaking printed +*/ + +//#ifndef ALLOC_DEBUG +//#define ALLOC_DEBUG 1 +//#endif + +enum alloc_type { ALLOC_TYPE_KMALLOC_ATOMIC, ALLOC_TYPE_KMALLOC_NON_ATOMIC, + ALLOC_TYPE_VMALLOC_ATOMIC, ALLOC_TYPE_VMALLOC_NON_ATOMIC, + ALLOC_TYPE_SLACK, ALLOC_TYPE_PAGES, ALLOC_TYPE_MAX }; + +int wrapmem_init(void); +void wrapmem_exit(void); +void *slack_kmalloc(size_t size); +void slack_kfree(void *ptr); +void wrapmem_info(void); + +#ifdef ALLOC_DEBUG +void *wrap_kmalloc(size_t size, gfp_t flags, const char *file, int line); +void *wrap_kzalloc(size_t size, gfp_t flags, const char *file, int line); +void wrap_kfree(void *ptr); +void *wrap_vmalloc(unsigned long size, const char *file, int line); +void *wrap__vmalloc(unsigned long size, gfp_t flags, pgprot_t prot, + const char *file, int line); +void wrap_vfree(void *ptr); +void *wrap_alloc_pages(gfp_t flags, unsigned int size, + const char *file, int line); +void wrap_free_pages(unsigned long ptr, int order); +int alloc_size(enum alloc_type type); + +#ifndef _WRAPMEM_C_ +#undef kmalloc +#undef kzalloc +#undef kfree +#undef vmalloc +#undef __vmalloc +#undef vfree +#define kmalloc(size, flags) \ + wrap_kmalloc(size, flags, __FILE__, __LINE__) +#define kzalloc(size, flags) \ + wrap_kzalloc(size, flags, __FILE__, __LINE__) +#define vmalloc(size) \ + wrap_vmalloc(size, __FILE__, __LINE__) +#define __vmalloc(size, flags, prot) \ + wrap__vmalloc(size, flags, prot, __FILE__, __LINE__) +#define kfree(ptr) wrap_kfree(ptr) +#define vfree(ptr) wrap_vfree(ptr) + +#define wrap_get_free_pages(flags, size) \ + wrap_alloc_pages(flags, size, __FILE__, __LINE__) +#undef free_pages +#define free_pages(ptr, order) wrap_free_pages(ptr, order) + +#if ALLOC_DEBUG > 1 +void *wrap_ExAllocatePoolWithTag(enum pool_type pool_type, SIZE_T size, + ULONG tag, const char *file, int line); +#define ExAllocatePoolWithTag(pool_type, size, tag) \ + wrap_ExAllocatePoolWithTag(pool_type, size, tag, __FILE__, __LINE__) +#endif + +#endif // _WRAPMEM_C_ + +#else + +#define wrap_get_free_pages(flags, size) \ + (void *)__get_free_pages(flags, get_order(size)) + +#endif // ALLOC_DEBUG + +#endif --- linux-2.6.27.orig/ubuntu/ndiswrapper/proc.c +++ linux-2.6.27/ubuntu/ndiswrapper/proc.c @@ -0,0 +1,565 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include + +#include "ndis.h" +#include "iw_ndis.h" +#include "wrapndis.h" +#include "pnp.h" +#include "wrapper.h" + +#define MAX_PROC_STR_LEN 32 + +static struct proc_dir_entry *wrap_procfs_entry; + +static int procfs_read_ndis_stats(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + struct ndis_device *wnd = (struct ndis_device *)data; + struct ndis_wireless_stats stats; + NDIS_STATUS res; + ndis_rssi rssi; + + if (off != 0) { + *eof = 1; + return 0; + } + + res = mp_query(wnd, OID_802_11_RSSI, &rssi, sizeof(rssi)); + if (!res) + p += sprintf(p, "signal_level=%d dBm\n", (s32)rssi); + + res = mp_query(wnd, OID_802_11_STATISTICS, &stats, sizeof(stats)); + if (!res) { + + p += sprintf(p, "tx_frames=%Lu\n", stats.tx_frag); + p += sprintf(p, "tx_multicast_frames=%Lu\n", + stats.tx_multi_frag); + p += sprintf(p, "tx_failed=%Lu\n", stats.failed); + p += sprintf(p, "tx_retry=%Lu\n", stats.retry); + p += sprintf(p, "tx_multi_rerty=%Lu\n", stats.multi_retry); + p += sprintf(p, "tx_rtss_success=%Lu\n", stats.rtss_succ); + p += sprintf(p, "tx_rtss_fail=%Lu\n", stats.rtss_fail); + p += sprintf(p, "ack_fail=%Lu\n", stats.ack_fail); + p += sprintf(p, "frame_duplicates=%Lu\n", stats.frame_dup); + p += sprintf(p, "rx_frames=%Lu\n", stats.rx_frag); + p += sprintf(p, "rx_multicast_frames=%Lu\n", + stats.rx_multi_frag); + p += sprintf(p, "fcs_errors=%Lu\n", stats.fcs_err); + } + + if (p - page > count) { + ERROR("wrote %lu bytes (limit is %u)\n", + (unsigned long)(p - page), count); + *eof = 1; + } + + return (p - page); +} + +static int procfs_read_ndis_encr(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + struct ndis_device *wnd = (struct ndis_device *)data; + int i, encr_status, auth_mode, infra_mode; + NDIS_STATUS res; + struct ndis_essid essid; + mac_address ap_address; + + if (off != 0) { + *eof = 1; + return 0; + } + + res = mp_query(wnd, OID_802_11_BSSID, + &ap_address, sizeof(ap_address)); + if (res) + memset(ap_address, 0, ETH_ALEN); + p += sprintf(p, "ap_address=%2.2X", ap_address[0]); + for (i = 1 ; i < ETH_ALEN ; i++) + p += sprintf(p, ":%2.2X", ap_address[i]); + p += sprintf(p, "\n"); + + res = mp_query(wnd, OID_802_11_SSID, &essid, sizeof(essid)); + if (!res) + p += sprintf(p, "essid=%.*s\n", essid.length, essid.essid); + + res = mp_query_int(wnd, OID_802_11_ENCRYPTION_STATUS, &encr_status); + if (!res) { + typeof(&wnd->encr_info.keys[0]) tx_key; + p += sprintf(p, "tx_key=%u\n", wnd->encr_info.tx_key_index); + p += sprintf(p, "key="); + tx_key = &wnd->encr_info.keys[wnd->encr_info.tx_key_index]; + if (tx_key->length > 0) + for (i = 0; i < tx_key->length; i++) + p += sprintf(p, "%2.2X", tx_key->key[i]); + else + p += sprintf(p, "off"); + p += sprintf(p, "\n"); + p += sprintf(p, "encr_mode=%d\n", encr_status); + } + res = mp_query_int(wnd, OID_802_11_AUTHENTICATION_MODE, &auth_mode); + if (!res) + p += sprintf(p, "auth_mode=%d\n", auth_mode); + res = mp_query_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, &infra_mode); + p += sprintf(p, "mode=%s\n", (infra_mode == Ndis802_11IBSS) ? + "adhoc" : (infra_mode == Ndis802_11Infrastructure) ? + "managed" : "auto"); + if (p - page > count) { + WARNING("wrote %lu bytes (limit is %u)", + (unsigned long)(p - page), count); + *eof = 1; + } + + return (p - page); +} + +static int procfs_read_ndis_hw(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + struct ndis_device *wnd = (struct ndis_device *)data; + struct ndis_configuration config; + unsigned int power_mode; + NDIS_STATUS res; + ndis_tx_power_level tx_power; + ULONG bit_rate; + ndis_rts_threshold rts_threshold; + ndis_fragmentation_threshold frag_threshold; + ndis_antenna antenna; + ULONG packet_filter; + int n; + mac_address mac; + char *hw_status[] = {"ready", "initializing", "resetting", "closing", + "not ready"}; + + if (off != 0) { + *eof = 1; + return 0; + } + + res = mp_query_int(wnd, OID_GEN_HARDWARE_STATUS, &n); + if (res == NDIS_STATUS_SUCCESS && + n >= 0 && n < sizeof(hw_status) / sizeof(hw_status[0])) + p += sprintf(p, "status=%s\n", hw_status[n]); + + res = mp_query(wnd, OID_802_3_CURRENT_ADDRESS, mac, sizeof(mac)); + if (!res) + p += sprintf(p, "mac: " MACSTRSEP "\n", MAC2STR(mac)); + res = mp_query(wnd, OID_802_11_CONFIGURATION, &config, sizeof(config)); + if (!res) { + p += sprintf(p, "beacon_period=%u msec\n", + config.beacon_period); + p += sprintf(p, "atim_window=%u msec\n", config.atim_window); + p += sprintf(p, "frequency=%u kHZ\n", config.ds_config); + p += sprintf(p, "hop_pattern=%u\n", + config.fh_config.hop_pattern); + p += sprintf(p, "hop_set=%u\n", + config.fh_config.hop_set); + p += sprintf(p, "dwell_time=%u msec\n", + config.fh_config.dwell_time); + } + + res = mp_query(wnd, OID_802_11_TX_POWER_LEVEL, + &tx_power, sizeof(tx_power)); + if (!res) + p += sprintf(p, "tx_power=%u mW\n", tx_power); + + res = mp_query(wnd, OID_GEN_LINK_SPEED, &bit_rate, sizeof(bit_rate)); + if (!res) + p += sprintf(p, "bit_rate=%u kBps\n", (u32)bit_rate / 10); + + res = mp_query(wnd, OID_802_11_RTS_THRESHOLD, + &rts_threshold, sizeof(rts_threshold)); + if (!res) + p += sprintf(p, "rts_threshold=%u bytes\n", rts_threshold); + + res = mp_query(wnd, OID_802_11_FRAGMENTATION_THRESHOLD, + &frag_threshold, sizeof(frag_threshold)); + if (!res) + p += sprintf(p, "frag_threshold=%u bytes\n", frag_threshold); + + res = mp_query_int(wnd, OID_802_11_POWER_MODE, &power_mode); + if (!res) + p += sprintf(p, "power_mode=%s\n", + (power_mode == NDIS_POWER_OFF) ? "always_on" : + (power_mode == NDIS_POWER_MAX) ? + "max_savings" : "min_savings"); + + res = mp_query(wnd, OID_802_11_NUMBER_OF_ANTENNAS, + &antenna, sizeof(antenna)); + if (!res) + p += sprintf(p, "num_antennas=%u\n", antenna); + + res = mp_query(wnd, OID_802_11_TX_ANTENNA_SELECTED, + &antenna, sizeof(antenna)); + if (!res) + p += sprintf(p, "tx_antenna=%u\n", antenna); + + res = mp_query(wnd, OID_802_11_RX_ANTENNA_SELECTED, + &antenna, sizeof(antenna)); + if (!res) + p += sprintf(p, "rx_antenna=%u\n", antenna); + + p += sprintf(p, "encryption_modes=%s%s%s%s%s%s%s\n", + test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr) ? + "WEP" : "none", + + test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr) ? + "; TKIP with WPA" : "", + test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ? + ", WPA2" : "", + test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ? + ", WPA2PSK" : "", + + test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr) ? + "; AES/CCMP with WPA" : "", + test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ? + ", WPA2" : "", + test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ? + ", WPA2PSK" : ""); + + res = mp_query_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, &packet_filter); + if (!res) { + if (packet_filter != wnd->packet_filter) + WARNING("wrong packet_filter? 0x%08x, 0x%08x\n", + packet_filter, wnd->packet_filter); + p += sprintf(p, "packet_filter: 0x%08x\n", packet_filter); + } + if (p - page > count) { + WARNING("wrote %lu bytes (limit is %u)", + (unsigned long)(p - page), count); + *eof = 1; + } + + return (p - page); +} + +static int procfs_read_ndis_settings(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + struct ndis_device *wnd = (struct ndis_device *)data; + struct wrap_device_setting *setting; + + if (off != 0) { + *eof = 1; + return 0; + } + + p += sprintf(p, "hangcheck_interval=%d\n", + hangcheck_interval == 0 ? + (int)(wnd->hangcheck_interval / HZ) : -1); + + list_for_each_entry(setting, &wnd->wd->settings, list) { + p += sprintf(p, "%s=%s\n", setting->name, setting->value); + } + + list_for_each_entry(setting, &wnd->wd->driver->settings, list) { + p += sprintf(p, "%s=%s\n", setting->name, setting->value); + } + + return (p - page); +} + +static int procfs_write_ndis_settings(struct file *file, const char __user *buf, + unsigned long count, void *data) +{ + struct ndis_device *wnd = (struct ndis_device *)data; + char setting[MAX_PROC_STR_LEN], *p; + unsigned int i; + NDIS_STATUS res; + + if (count > MAX_PROC_STR_LEN) + return -EINVAL; + + memset(setting, 0, sizeof(setting)); + if (copy_from_user(setting, buf, count)) + return -EFAULT; + + if ((p = strchr(setting, '\n'))) + *p = 0; + + if ((p = strchr(setting, '='))) + *p = 0; + + if (!strcmp(setting, "hangcheck_interval")) { + if (!p) + return -EINVAL; + p++; + i = simple_strtol(p, NULL, 10); + hangcheck_del(wnd); + if (i > 0) { + wnd->hangcheck_interval = i * HZ; + hangcheck_add(wnd); + } + } else if (!strcmp(setting, "suspend")) { + if (!p) + return -EINVAL; + p++; + i = simple_strtol(p, NULL, 10); + if (i <= 0 || i > 3) + return -EINVAL; + if (wrap_is_pci_bus(wnd->wd->dev_bus)) + i = wrap_pnp_suspend_pci_device(wnd->wd->pci.pdev, + PMSG_SUSPEND); + else +#ifdef ENABLE_USB + i = wrap_pnp_suspend_usb_device(wnd->wd->usb.intf, + PMSG_SUSPEND); +#else + i = -1; +#endif + if (i) + return -EINVAL; + } else if (!strcmp(setting, "resume")) { + if (wrap_is_pci_bus(wnd->wd->dev_bus)) + i = wrap_pnp_resume_pci_device(wnd->wd->pci.pdev); + else +#ifdef ENABLE_USB + i = wrap_pnp_resume_usb_device(wnd->wd->usb.intf); +#else + i = -1; +#endif + if (i) + return -EINVAL; + } else if (!strcmp(setting, "stats_enabled")) { + if (!p) + return -EINVAL; + p++; + i = simple_strtol(p, NULL, 10); + if (i > 0) + wnd->iw_stats_enabled = TRUE; + else + wnd->iw_stats_enabled = FALSE; + } else if (!strcmp(setting, "packet_filter")) { + if (!p) + return -EINVAL; + p++; + i = simple_strtol(p, NULL, 10); + res = mp_set_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, i); + if (res) + WARNING("setting packet_filter failed: %08X", res); + } else if (!strcmp(setting, "reinit")) { + if (ndis_reinit(wnd) != NDIS_STATUS_SUCCESS) + return -EFAULT; + } else { + struct ndis_configuration_parameter param; + struct unicode_string key; + struct ansi_string ansi; + + if (!p) + return -EINVAL; + p++; + RtlInitAnsiString(&ansi, p); + if (RtlAnsiStringToUnicodeString(¶m.data.string, &ansi, + TRUE) != STATUS_SUCCESS) + EXIT1(return -EFAULT); + param.type = NdisParameterString; + RtlInitAnsiString(&ansi, setting); + if (RtlAnsiStringToUnicodeString(&key, &ansi, + TRUE) != STATUS_SUCCESS) { + RtlFreeUnicodeString(¶m.data.string); + EXIT1(return -EINVAL); + } + NdisWriteConfiguration(&res, wnd->nmb, &key, ¶m); + RtlFreeUnicodeString(&key); + RtlFreeUnicodeString(¶m.data.string); + if (res != NDIS_STATUS_SUCCESS) + return -EFAULT; + } + return count; +} + +int wrap_procfs_add_ndis_device(struct ndis_device *wnd) +{ + struct proc_dir_entry *procfs_entry; + + if (wrap_procfs_entry == NULL) + return -ENOMEM; + + if (wnd->procfs_iface) { + ERROR("%s already registered?", wnd->netdev_name); + return -EINVAL; + } + wnd->procfs_iface = proc_mkdir(wnd->netdev_name, wrap_procfs_entry); + if (wnd->procfs_iface == NULL) { + ERROR("couldn't create proc directory"); + return -ENOMEM; + } + wnd->procfs_iface->uid = proc_uid; + wnd->procfs_iface->gid = proc_gid; + + procfs_entry = create_proc_entry("hw", S_IFREG | S_IRUSR | S_IRGRP, + wnd->procfs_iface); + if (procfs_entry == NULL) { + ERROR("couldn't create proc entry for 'hw'"); + goto err_hw; + } else { + procfs_entry->uid = proc_uid; + procfs_entry->gid = proc_gid; + procfs_entry->data = wnd; + procfs_entry->read_proc = procfs_read_ndis_hw; + } + + procfs_entry = create_proc_entry("stats", S_IFREG | S_IRUSR | S_IRGRP, + wnd->procfs_iface); + if (procfs_entry == NULL) { + ERROR("couldn't create proc entry for 'stats'"); + goto err_stats; + } else { + procfs_entry->uid = proc_uid; + procfs_entry->gid = proc_gid; + procfs_entry->data = wnd; + procfs_entry->read_proc = procfs_read_ndis_stats; + } + + procfs_entry = create_proc_entry("encr", S_IFREG | S_IRUSR | S_IRGRP, + wnd->procfs_iface); + if (procfs_entry == NULL) { + ERROR("couldn't create proc entry for 'encr'"); + goto err_encr; + } else { + procfs_entry->uid = proc_uid; + procfs_entry->gid = proc_gid; + procfs_entry->data = wnd; + procfs_entry->read_proc = procfs_read_ndis_encr; + } + + procfs_entry = create_proc_entry("settings", S_IFREG | + S_IRUSR | S_IRGRP | + S_IWUSR | S_IWGRP, wnd->procfs_iface); + if (procfs_entry == NULL) { + ERROR("couldn't create proc entry for 'settings'"); + goto err_settings; + } else { + procfs_entry->uid = proc_uid; + procfs_entry->gid = proc_gid; + procfs_entry->data = wnd; + procfs_entry->read_proc = procfs_read_ndis_settings; + procfs_entry->write_proc = procfs_write_ndis_settings; + } + return 0; + +err_settings: + remove_proc_entry("encr", wnd->procfs_iface); +err_encr: + remove_proc_entry("stats", wnd->procfs_iface); +err_stats: + remove_proc_entry("hw", wnd->procfs_iface); +err_hw: + remove_proc_entry(wnd->netdev_name, wrap_procfs_entry); + wnd->procfs_iface = NULL; + return -ENOMEM; +} + +void wrap_procfs_remove_ndis_device(struct ndis_device *wnd) +{ + struct proc_dir_entry *procfs_iface = xchg(&wnd->procfs_iface, NULL); + + if (procfs_iface == NULL) + return; + remove_proc_entry("hw", procfs_iface); + remove_proc_entry("stats", procfs_iface); + remove_proc_entry("encr", procfs_iface); + remove_proc_entry("settings", procfs_iface); + if (wrap_procfs_entry) + remove_proc_entry(wnd->netdev_name, wrap_procfs_entry); +} + +static int procfs_read_debug(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + enum alloc_type type; + + if (off != 0) { + *eof = 1; + return 0; + } + p += sprintf(p, "%d\n", debug); + type = 0; +#ifdef ALLOC_DEBUG + for (type = 0; type < ALLOC_TYPE_MAX; type++) + p += sprintf(p, "total size of allocations in %d: %d\n", + type, alloc_size(type)); +#endif + return (p - page); +} + +static int procfs_write_debug(struct file *file, const char __user *buf, + unsigned long count, void *data) +{ + int i; + char setting[MAX_PROC_STR_LEN], *p; + + if (count > MAX_PROC_STR_LEN) + return -EINVAL; + + memset(setting, 0, sizeof(setting)); + if (copy_from_user(setting, buf, count)) + return -EFAULT; + + if ((p = strchr(setting, '\n'))) + *p = 0; + + if ((p = strchr(setting, '='))) + *p = 0; + + i = simple_strtol(setting, NULL, 10); + if (i >= 0 && i < 10) + debug = i; + else + return -EINVAL; + return count; +} + +int wrap_procfs_init(void) +{ + struct proc_dir_entry *procfs_entry; + + wrap_procfs_entry = proc_mkdir(DRIVER_NAME, proc_net_root); + if (wrap_procfs_entry == NULL) { + ERROR("couldn't create procfs directory"); + return -ENOMEM; + } + wrap_procfs_entry->uid = proc_uid; + wrap_procfs_entry->gid = proc_gid; + + procfs_entry = create_proc_entry("debug", S_IFREG | S_IRUSR | S_IRGRP, + wrap_procfs_entry); + if (procfs_entry == NULL) { + ERROR("couldn't create proc entry for 'debug'"); + return -ENOMEM; + } else { + procfs_entry->uid = proc_uid; + procfs_entry->gid = proc_gid; + procfs_entry->read_proc = procfs_read_debug; + procfs_entry->write_proc = procfs_write_debug; + } + return 0; +} + +void wrap_procfs_remove(void) +{ + if (wrap_procfs_entry == NULL) + return; + remove_proc_entry("debug", wrap_procfs_entry); + remove_proc_entry(DRIVER_NAME, proc_net_root); +} --- linux-2.6.27.orig/ubuntu/ndiswrapper/ntoskernel.h +++ linux-2.6.27/ubuntu/ndiswrapper/ntoskernel.h @@ -0,0 +1,1165 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _NTOSKERNEL_H_ +#define _NTOSKERNEL_H_ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(CONFIG_X86) && !defined(CONFIG_X86_64) +#error "this module is for x86 or x86_64 architectures only" +#endif + +/* Interrupt backwards compatibility stuff */ +#include +#ifndef IRQ_HANDLED +#define IRQ_HANDLED +#define IRQ_NONE +#define irqreturn_t void +#endif + +/* pci functions in 2.6 kernels have problems allocating dma buffers, + * but seem to work fine with dma functions + */ +#include + +#define PCI_DMA_ALLOC_COHERENT(pci_dev,size,dma_handle) \ + dma_alloc_coherent(&pci_dev->dev,size,dma_handle, \ + GFP_KERNEL | __GFP_REPEAT) +#define PCI_DMA_FREE_COHERENT(pci_dev,size,cpu_addr,dma_handle) \ + dma_free_coherent(&pci_dev->dev,size,cpu_addr,dma_handle) +#define PCI_DMA_MAP_SINGLE(pci_dev,addr,size,direction) \ + dma_map_single(&pci_dev->dev,addr,size,direction) +#define PCI_DMA_UNMAP_SINGLE(pci_dev,dma_handle,size,direction) \ + dma_unmap_single(&pci_dev->dev,dma_handle,size,direction) +#define MAP_SG(pci_dev, sglist, nents, direction) \ + dma_map_sg(&pci_dev->dev, sglist, nents, direction) +#define UNMAP_SG(pci_dev, sglist, nents, direction) \ + dma_unmap_sg(&pci_dev->dev, sglist, nents, direction) +#define PCI_DMA_MAP_ERROR(dma_addr) dma_mapping_error(dma_addr) + + +#if defined(CONFIG_NET_RADIO) && !defined(CONFIG_WIRELESS_EXT) +#define CONFIG_WIRELESS_EXT +#endif + +#define prepare_wait_condition(task, var, value) \ +do { \ + var = value; \ + task = current; \ + barrier(); \ +} while (0) + +/* Wait in wait_state (e.g., TASK_INTERRUPTIBLE) for condition to + * become true; timeout is either jiffies (> 0) to wait or 0 to wait + * forever. + * When timeout == 0, return value is + * > 0 if condition becomes true, or + * < 0 if signal is pending on the thread. + * When timeout > 0, return value is + * > 0 if condition becomes true before timeout, + * < 0 if signal is pending on the thread before timeout, or + * 0 if timedout (condition may have become true at the same time) + */ + +#define wait_condition(condition, timeout, wait_state) \ +({ \ + long ret = timeout ? timeout : 1; \ + while (1) { \ + if (signal_pending(current)) { \ + ret = -ERESTARTSYS; \ + break; \ + } \ + set_current_state(wait_state); \ + if (condition) { \ + __set_current_state(TASK_RUNNING); \ + break; \ + } \ + if (timeout) { \ + ret = schedule_timeout(ret); \ + if (!ret) \ + break; \ + } else \ + schedule(); \ + } \ + ret; \ +}) + +#ifdef WRAP_WQ + +struct workqueue_struct; + +struct workqueue_thread { + spinlock_t lock; + struct task_struct *task; + struct completion *completion; + char name[16]; + int pid; + /* whether any work_structs pending? <0 implies quit */ + s8 pending; + /* list of work_structs pending */ + struct list_head work_list; +}; + +typedef struct workqueue_struct { + u8 singlethread; + u8 qon; + int num_cpus; + struct workqueue_thread threads[0]; +} workqueue_struct_t; + +typedef struct { + struct list_head list; + void (*func)(void *data); + void *data; + /* whether/on which thread scheduled */ + struct workqueue_thread *thread; +} work_struct_t; + +#define initialize_work(work, pfunc, pdata) \ + do { \ + (work)->func = (pfunc); \ + (work)->data = (pdata); \ + (work)->thread = NULL; \ + } while (0) + +#undef create_singlethread_workqueue +#define create_singlethread_workqueue(name) wrap_create_wq(name, 1, 0) +#undef create_workqueue +#define create_workqueue(name) wrap_create_wq(name, 0, 0) +#undef destroy_workqueue +#define destroy_workqueue wrap_destroy_wq +#undef queue_work +#define queue_work wrap_queue_work +#undef flush_workqueue +#define flush_workqueue wrap_flush_wq + +workqueue_struct_t *wrap_create_wq(const char *name, u8 singlethread, u8 freeze); +void wrap_destroy_wq_on(workqueue_struct_t *workq, int cpu); +void wrap_destroy_wq(workqueue_struct_t *workq); +int wrap_queue_work_on(workqueue_struct_t *workq, work_struct_t *work, + int cpu); +int wrap_queue_work(workqueue_struct_t *workq, work_struct_t *work); +void wrap_cancel_work(work_struct_t *work); +void wrap_flush_wq_on(workqueue_struct_t *workq, int cpu); +void wrap_flush_wq(workqueue_struct_t *workq); +typedef void *worker_param_t; +#define worker_param_data(param, type, member) param + +#else // WRAP_WQ + +typedef struct workqueue_struct workqueue_struct_t; +typedef struct work_struct work_struct_t; + +#if defined(INIT_WORK_NAR) || defined(INIT_DELAYED_WORK_DEFERRABLE) +#define initialize_work(work, func, data) INIT_WORK(work, func) +typedef struct work_struct *worker_param_t; +#define worker_param_data(param, type, member) \ + container_of(param, type, member) +#else +#define initialize_work(work, func, data) INIT_WORK(work, func, data) +typedef void *worker_param_t; +#define worker_param_data(param, type, member) param +#endif // INIT_WORK_NAR + +#endif // WRAP_WQ + +struct nt_thread *wrap_worker_init(workqueue_struct_t *wq); + +#ifdef module_param +#define WRAP_MODULE_PARM_INT(name, perm) module_param(name, int, perm) +#define WRAP_MODULE_PARM_STRING(name, perm) module_param(name, charp, perm) +#else +#define WRAP_MODULE_PARM_INT(name, perm) MODULE_PARM(name, "i") +#define WRAP_MODULE_PARM_STRING(name, perm) MODULE_PARM(name, "s") +#endif + +#ifndef LOCK_PREFIX +#ifdef LOCK +#define LOCK_PREFIX LOCK +#else +#ifdef CONFIG_SMP +#define LOCK_PREFIX "lock ; " +#else +#define LOCK_PREFIX "" +#endif +#endif +#endif + +#ifndef NETDEV_TX_OK +#define NETDEV_TX_OK 0 +#endif + +#ifndef NETDEV_TX_BUSY +#define NETDEV_TX_BUSY 1 +#endif + +#ifndef CHECKSUM_HW +#define CHECKSUM_HW CHECKSUM_PARTIAL +#endif + +#ifndef offset_in_page +#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK) +#endif + +#ifndef PMSG_SUSPEND +#ifdef PM_SUSPEND +/* this is not correct - the value of PM_SUSPEND is different from + * PMSG_SUSPEND, but ndiswrapper doesn't care about the value when + * suspending */ +#define PMSG_SUSPEND PM_SUSPEND +#define PSMG_ON PM_ON +#else +typedef u32 pm_message_t; +#define PMSG_SUSPEND 2 +#define PMSG_ON 0 +#endif +#endif + +#ifndef PCI_D0 +#define PCI_D0 0 +#endif + +#ifndef PCI_D3hot +#define PCI_D3hot 3 +#endif + +#ifndef PCI_D3cold +#define PCI_D3cold 3 +#endif + +#ifndef PM_EVENT_SUSPEND +#define PM_EVENT_SUSPEND 2 +#endif + +#if !defined(HAVE_NETDEV_PRIV) +#define netdev_priv(dev) ((dev)->priv) +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) +#define ISR_PT_REGS_PARAM_DECL +#define ISR_PT_REGS_ARG +#else +#define ISR_PT_REGS_PARAM_DECL , struct pt_regs *regs +#define ISR_PT_REGS_ARG , NULL +#endif + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16) +#define for_each_possible_cpu(_cpu) for_each_cpu(_cpu) +#endif + +#ifndef flush_icache_range +#define flush_icache_range(start, end) do { } while (0) +#endif + +#ifndef CHECKSUM_PARTIAL +#define CHECKSUM_PARTIAL CHECKSUM_HW +#endif + +#ifndef IRQF_SHARED +#define IRQF_SHARED SA_SHIRQ +#endif + +#define memcpy_skb(skb, from, length) \ + memcpy(skb_put(skb, length), from, length) + +#ifndef DMA_24BIT_MASK +#define DMA_24BIT_MASK 0x0000000000ffffffULL +#endif + +#ifndef DMA_30BIT_MASK +#define DMA_30BIT_MASK 0x000000003fffffffULL +#endif + +#ifndef DMA_31BIT_MASK +#define DMA_31BIT_MASK 0x000000007fffffffULL +#endif + +#ifndef DMA_32BIT_MASK +#define DMA_32BIT_MASK 0x00000000ffffffffULL +#endif + +#ifndef __GFP_DMA32 +#define __GFP_DMA32 GFP_DMA +#endif + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22) +#define wrap_kmem_cache_create(name, size, align, flags) \ + kmem_cache_create(name, size, align, flags, NULL, NULL) +#else +#define wrap_kmem_cache_create(name, size, align, flags) \ + kmem_cache_create(name, size, align, flags, NULL) +#endif + +#include "winnt_types.h" +#include "ndiswrapper.h" +#include "pe_linker.h" +#include "wrapmem.h" +#include "lin2win.h" +#include "loader.h" + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) +static inline void netif_tx_lock(struct net_device *dev) +{ + spin_lock(&dev->xmit_lock); +} +static inline void netif_tx_unlock(struct net_device *dev) +{ + spin_unlock(&dev->xmit_lock); +} +static inline void netif_tx_lock_bh(struct net_device *dev) +{ + spin_lock_bh(&dev->xmit_lock); +} +static inline void netif_tx_unlock_bh(struct net_device *dev) +{ + spin_unlock_bh(&dev->xmit_lock); +} +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) +static inline void netif_poll_enable(struct net_device *dev) +{ +} +static inline void netif_poll_disable(struct net_device *dev) +{ +} +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) +#define proc_net_root init_net.proc_net +#else +#define proc_net_root proc_net +#endif + +/* TICK is 100ns */ +#define TICKSPERSEC 10000000 +#define TICKSPERMSEC 10000 +#define SECSPERDAY 86400 +#define TICKSPERJIFFY ((TICKSPERSEC + HZ - 1) / HZ) + +#define int_div_round(x, y) (((x) + (y - 1)) / (y)) + +/* 1601 to 1970 is 369 years plus 89 leap days */ +#define SECS_1601_TO_1970 ((369 * 365 + 89) * (u64)SECSPERDAY) +#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC) + +/* 100ns units to HZ; if sys_time is negative, relative to current + * clock, otherwise from year 1601 */ +#define SYSTEM_TIME_TO_HZ(sys_time) \ + (((sys_time) <= 0) ? \ + int_div_round(((u64)HZ * (-(sys_time))), TICKSPERSEC) : \ + int_div_round(((s64)HZ * ((sys_time) - ticks_1601())), TICKSPERSEC)) + +#define MSEC_TO_HZ(ms) int_div_round((ms * HZ), 1000) +#define USEC_TO_HZ(us) int_div_round((us * HZ), 1000000) + +extern u64 wrap_ticks_to_boot; + +static inline u64 ticks_1601(void) +{ + return wrap_ticks_to_boot + (u64)jiffies * TICKSPERJIFFY; +} + +typedef void (*generic_func)(void); + +struct wrap_export { + const char *name; + generic_func func; +}; + +#ifdef CONFIG_X86_64 + +#define WIN_SYMBOL(name, argc) \ + {#name, (generic_func) win2lin_ ## name ## _ ## argc} +#define WIN_WIN_SYMBOL(name, argc) \ + {#name, (generic_func) win2lin__win_ ## name ## _ ## argc} +#define WIN_FUNC_DECL(name, argc) \ + extern typeof(name) win2lin_ ## name ## _ ## argc; +#define WIN_FUNC_PTR(name, argc) win2lin_ ## name ## _ ## argc + +#else + +#define WIN_SYMBOL(name, argc) {#name, (generic_func)name} +#define WIN_WIN_SYMBOL(name, argc) {#name, (generic_func)_win_ ## name} +#define WIN_FUNC_DECL(name, argc) +#define WIN_FUNC_PTR(name, argc) name + +#endif + +#define WIN_FUNC(name, argc) name +/* map name s to f - if f is different from s */ +#define WIN_SYMBOL_MAP(s, f) + +#define POOL_TAG(A, B, C, D) \ + ((ULONG)((A) + ((B) << 8) + ((C) << 16) + ((D) << 24))) + +struct pe_image { + char name[MAX_DRIVER_NAME_LEN]; + UINT (*entry)(struct driver_object *, struct unicode_string *) wstdcall; + void *image; + int size; + int type; + + IMAGE_NT_HEADERS *nt_hdr; + IMAGE_OPTIONAL_HEADER *opt_hdr; +}; + +struct ndis_mp_block; + +struct wrap_timer { + struct nt_slist slist; + struct timer_list timer; + struct nt_timer *nt_timer; + long repeat; +#ifdef TIMER_DEBUG + unsigned long wrap_timer_magic; +#endif +}; + +struct ntos_work_item { + struct nt_list list; + void *arg1; + void *arg2; + NTOS_WORK_FUNC func; +}; + +struct wrap_device_setting { + struct nt_list list; + char name[MAX_SETTING_NAME_LEN]; + char value[MAX_SETTING_VALUE_LEN]; + void *encoded; +}; + +struct wrap_bin_file { + char name[MAX_DRIVER_NAME_LEN]; + size_t size; + void *data; +}; + +#define WRAP_DRIVER_CLIENT_ID 1 + +struct wrap_driver { + struct nt_list list; + struct driver_object *drv_obj; + char name[MAX_DRIVER_NAME_LEN]; + char version[MAX_SETTING_VALUE_LEN]; + unsigned short num_pe_images; + struct pe_image pe_images[MAX_DRIVER_PE_IMAGES]; + unsigned short num_bin_files; + struct wrap_bin_file *bin_files; + struct nt_list wrap_devices; + struct nt_list settings; + int dev_type; + struct ndis_driver *ndis_driver; +}; + +enum hw_status { + HW_INITIALIZED = 1, HW_SUSPENDED, HW_HALTED, HW_PRESENT, +}; + +struct wrap_device { + /* first part is (de)initialized once by loader */ + struct nt_list list; + int dev_bus; + int vendor; + int device; + int subvendor; + int subdevice; + char conf_file_name[MAX_DRIVER_NAME_LEN]; + char driver_name[MAX_DRIVER_NAME_LEN]; + struct wrap_driver *driver; + struct nt_list settings; + + /* rest should be (de)initialized when a device is + * (un)plugged */ + struct cm_resource_list *resource_list; + unsigned long hw_status; + struct device_object *pdo; + union { + struct { + struct pci_dev *pdev; + enum device_power_state wake_state; + } pci; + struct { + struct usb_device *udev; + struct usb_interface *intf; + int num_alloc_urbs; + struct nt_list wrap_urb_list; + } usb; + }; + union { + struct ndis_device *wnd; + }; +}; + +#define wrap_is_pci_bus(dev_bus) \ + (WRAP_BUS(dev_bus) == WRAP_PCI_BUS || \ + WRAP_BUS(dev_bus) == WRAP_PCMCIA_BUS) +#ifdef ENABLE_USB +/* earlier versions of ndiswrapper used 0 as USB_BUS */ +#define wrap_is_usb_bus(dev_bus) \ + (WRAP_BUS(dev_bus) == WRAP_USB_BUS || \ + WRAP_BUS(dev_bus) == WRAP_INTERNAL_BUS) +#else +#define wrap_is_usb_bus(dev_bus) 0 +#endif +#define wrap_is_bluetooth_device(dev_bus) \ + (WRAP_DEVICE(dev_bus) == WRAP_BLUETOOTH_DEVICE1 || \ + WRAP_DEVICE(dev_bus) == WRAP_BLUETOOTH_DEVICE2) + +extern workqueue_struct_t *ntos_wq; +#define schedule_ntos_work(work_struct) queue_work(ntos_wq, work_struct) +#define schedule_work(work_struct) queue_work(ntos_wq, work_struct) + +extern workqueue_struct_t *ndis_wq; +#define schedule_ndis_work(work_struct) queue_work(ndis_wq, work_struct) + +extern workqueue_struct_t *wrapndis_wq; +#define schedule_wrapndis_work(work_struct) queue_work(wrapndis_wq, work_struct) + +#define atomic_unary_op(var, size, oper) \ +do { \ + if (size == 1) \ + __asm__ __volatile__( \ + LOCK_PREFIX oper "b %b0\n\t" : "+m" (var)); \ + else if (size == 2) \ + __asm__ __volatile__( \ + LOCK_PREFIX oper "w %w0\n\t" : "+m" (var)); \ + else if (size == 4) \ + __asm__ __volatile__( \ + LOCK_PREFIX oper "l %0\n\t" : "+m" (var)); \ + else if (size == 8) \ + __asm__ __volatile__( \ + LOCK_PREFIX oper "q %q0\n\t" : "+m" (var)); \ + else { \ + extern void _invalid_op_size_(void); \ + _invalid_op_size_(); \ + } \ +} while (0) + +#define atomic_inc_var_size(var, size) atomic_unary_op(var, size, "inc") + +#define atomic_inc_var(var) atomic_inc_var_size(var, sizeof(var)) + +#define atomic_dec_var_size(var, size) atomic_unary_op(var, size, "dec") + +#define atomic_dec_var(var) atomic_dec_var_size(var, sizeof(var)) + +#define pre_atomic_add(var, i) \ +({ \ + typeof(var) pre; \ + __asm__ __volatile__( \ + LOCK_PREFIX "xadd %0, %1\n\t" \ + : "=r"(pre), "+m"(var) \ + : "0"(i)); \ + pre; \ +}) + +#define post_atomic_add(var, i) (pre_atomic_add(var, i) + i) + +#ifndef in_atomic +#define in_atomic() in_interrupt() +#endif + +#ifndef preempt_enable_no_resched +#define preempt_enable_no_resched() preempt_enable() +#endif + +//#define DEBUG_IRQL 1 + +#ifdef DEBUG_IRQL +#define assert_irql(cond) \ +do { \ + KIRQL _irql_ = current_irql(); \ + if (!(cond)) { \ + WARNING("assertion '%s' failed: %d", #cond, _irql_); \ + DBG_BLOCK(4) { \ + dump_stack(); \ + } \ + } \ +} while (0) +#else +#define assert_irql(cond) do { } while (0) +#endif + +/* When preempt is enabled, we should preempt_disable to raise IRQL to + * DISPATCH_LEVEL, to be consistent with the semantics. However, using + * a mutex instead, so that only ndiswrapper threads run one at a time + * on a processor when at DISPATCH_LEVEL seems to be enough. So that + * is what we will use until we learn otherwise. If + * preempt_(en|dis)able is required for some reason, comment out + * following #define. */ + +#define WRAP_PREEMPT 1 + +#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PREEMPT_RT) +#ifndef WRAP_PREEMPT +#define WRAP_PREEMPT 1 +#endif +#endif + +//#undef WRAP_PREEMPT + +#ifdef WRAP_PREEMPT + +typedef struct { + int count; + struct mutex lock; +#ifdef CONFIG_SMP + typeof(current->cpus_allowed) cpus_allowed; +#endif + struct task_struct *task; +} irql_info_t; + +DECLARE_PER_CPU(irql_info_t, irql_info); + +static inline KIRQL raise_irql(KIRQL newirql) +{ + irql_info_t *info; + + assert(newirql == DISPATCH_LEVEL); + info = &get_cpu_var(irql_info); + if (info->task == current) { + assert(info->count > 0); + assert(mutex_is_locked(&info->lock)); +#if defined(CONFIG_SMP) && defined(DEBUG) + do { + cpumask_t cpumask; + cpumask = cpumask_of_cpu(smp_processor_id()); + cpus_xor(cpumask, cpumask, current->cpus_allowed); + assert(cpus_empty(cpumask)); + } while (0); +#endif + info->count++; + put_cpu_var(irql_info); + return DISPATCH_LEVEL; + } + /* TODO: is this enough to pin down to current cpu? */ +#ifdef CONFIG_SMP + assert(task_cpu(current) == smp_processor_id()); + info->cpus_allowed = current->cpus_allowed; + current->cpus_allowed = cpumask_of_cpu(smp_processor_id()); +#endif + put_cpu_var(irql_info); + mutex_lock(&info->lock); + assert(info->count == 0); + assert(info->task == NULL); + info->count = 1; + info->task = current; + return PASSIVE_LEVEL; +} + +static inline void lower_irql(KIRQL oldirql) +{ + irql_info_t *info; + + assert(oldirql <= DISPATCH_LEVEL); + info = &get_cpu_var(irql_info); + assert(info->task == current); + assert(mutex_is_locked(&info->lock)); + assert(info->count > 0); + if (--info->count == 0) { + info->task = NULL; +#ifdef CONFIG_SMP + current->cpus_allowed = info->cpus_allowed; +#endif + mutex_unlock(&info->lock); + } + put_cpu_var(irql_info); +} + +static inline KIRQL current_irql(void) +{ + int count; + if (in_irq() || irqs_disabled()) + EXIT4(return DIRQL); + if (in_atomic() || in_interrupt()) + EXIT4(return SOFT_IRQL); + count = get_cpu_var(irql_info).count; + put_cpu_var(irql_info); + if (count) + EXIT6(return DISPATCH_LEVEL); + else + EXIT6(return PASSIVE_LEVEL); +} + +#else + +static inline KIRQL current_irql(void) +{ + if (in_irq() || irqs_disabled()) + EXIT4(return DIRQL); + if (in_interrupt()) + EXIT4(return SOFT_IRQL); + if (in_atomic()) + EXIT6(return DISPATCH_LEVEL); + else + EXIT6(return PASSIVE_LEVEL); +} + +static inline KIRQL raise_irql(KIRQL newirql) +{ + KIRQL ret = in_atomic() ? DISPATCH_LEVEL : PASSIVE_LEVEL; + assert(newirql == DISPATCH_LEVEL); + assert(current_irql() <= DISPATCH_LEVEL); + preempt_disable(); + return ret; +} + +static inline void lower_irql(KIRQL oldirql) +{ + assert(current_irql() == DISPATCH_LEVEL); + preempt_enable(); +} + +#endif + +#define irql_gfp() (in_atomic() ? GFP_ATOMIC : GFP_KERNEL) + +/* Windows spinlocks are of type ULONG_PTR which is not big enough to + * store Linux spinlocks; so we implement Windows spinlocks using + * ULONG_PTR space with our own functions/macros */ + +/* Windows seems to use 0 for unlocked state of spinlock - if Linux + * convention of 1 for unlocked state is used, at least prism54 driver + * crashes */ + +#define NT_SPIN_LOCK_UNLOCKED 0 +#define NT_SPIN_LOCK_LOCKED 1 + +static inline void nt_spin_lock_init(NT_SPIN_LOCK *lock) +{ + *lock = NT_SPIN_LOCK_UNLOCKED; +} + +#ifdef CONFIG_SMP + +static inline void nt_spin_lock(NT_SPIN_LOCK *lock) +{ + __asm__ __volatile__( + "1:\t" + " xchgl %1, %0\n\t" + " testl %1, %1\n\t" + " jz 3f\n" + "2:\t" + " rep; nop\n\t" + " cmpl %2, %0\n\t" + " je 1b\n\t" + " jmp 2b\n" + "3:\n\t" + : "+m" (*lock) + : "r" (NT_SPIN_LOCK_LOCKED), "i" (NT_SPIN_LOCK_UNLOCKED)); +} + +static inline void nt_spin_unlock(NT_SPIN_LOCK *lock) +{ + *lock = NT_SPIN_LOCK_UNLOCKED; +} + +#else // CONFIG_SMP + +#define nt_spin_lock(lock) do { } while (0) + +#define nt_spin_unlock(lock) do { } while (0) + +#endif // CONFIG_SMP + +/* When kernel would've disabled preempt (e.g., in interrupt + * handlers), we need to fake preempt so driver thinks it is running + * at right IRQL */ + +/* raise IRQL to given (higher) IRQL if necessary before locking */ +static inline KIRQL nt_spin_lock_irql(NT_SPIN_LOCK *lock, KIRQL newirql) +{ + KIRQL oldirql = raise_irql(newirql); + nt_spin_lock(lock); + return oldirql; +} + +/* lower IRQL to given (lower) IRQL if necessary after unlocking */ +static inline void nt_spin_unlock_irql(NT_SPIN_LOCK *lock, KIRQL oldirql) +{ + nt_spin_unlock(lock); + lower_irql(oldirql); +} + +#define nt_spin_lock_irqsave(lock, flags) \ +do { \ + local_irq_save(flags); \ + preempt_disable(); \ + nt_spin_lock(lock); \ +} while (0) + +#define nt_spin_unlock_irqrestore(lock, flags) \ +do { \ + nt_spin_unlock(lock); \ + preempt_enable_no_resched(); \ + local_irq_restore(flags); \ + preempt_check_resched(); \ +} while (0) + +static inline ULONG SPAN_PAGES(void *ptr, SIZE_T length) +{ + return PAGE_ALIGN(((unsigned long)ptr & (PAGE_SIZE - 1)) + length) + >> PAGE_SHIFT; +} + +#ifdef CONFIG_X86_64 + +/* TODO: can these be implemented without using spinlock? */ + +static inline struct nt_slist *PushEntrySList(nt_slist_header *head, + struct nt_slist *entry, + NT_SPIN_LOCK *lock) +{ + KIRQL irql = nt_spin_lock_irql(lock, DISPATCH_LEVEL); + entry->next = head->next; + head->next = entry; + head->depth++; + nt_spin_unlock_irql(lock, irql); + TRACE4("%p, %p, %p", head, entry, entry->next); + return entry->next; +} + +static inline struct nt_slist *PopEntrySList(nt_slist_header *head, + NT_SPIN_LOCK *lock) +{ + struct nt_slist *entry; + KIRQL irql = nt_spin_lock_irql(lock, DISPATCH_LEVEL); + entry = head->next; + if (entry) { + head->next = entry->next; + head->depth--; + } + nt_spin_unlock_irql(lock, irql); + TRACE4("%p, %p", head, entry); + return entry; +} + +#else + +#define u64_low_32(x) ((u32)x) +#define u64_high_32(x) ((u32)(x >> 32)) + +static inline u64 cmpxchg8b(volatile u64 *ptr, u64 old, u64 new) +{ + u64 prev; + + __asm__ __volatile__( + "\n" + LOCK_PREFIX "cmpxchg8b %0\n" + : "+m" (*ptr), "=A" (prev) + : "A" (old), "b" (u64_low_32(new)), "c" (u64_high_32(new))); + return prev; +} + +/* slist routines below update slist atomically - no need for + * spinlocks */ + +static inline struct nt_slist *PushEntrySList(nt_slist_header *head, + struct nt_slist *entry, + NT_SPIN_LOCK *lock) +{ + nt_slist_header old, new; + do { + old.align = head->align; + entry->next = old.next; + new.next = entry; + new.depth = old.depth + 1; + } while (cmpxchg8b(&head->align, old.align, new.align) != old.align); + TRACE4("%p, %p, %p", head, entry, old.next); + return old.next; +} + +static inline struct nt_slist *PopEntrySList(nt_slist_header *head, + NT_SPIN_LOCK *lock) +{ + struct nt_slist *entry; + nt_slist_header old, new; + do { + old.align = head->align; + entry = old.next; + if (!entry) + break; + new.next = entry->next; + new.depth = old.depth - 1; + } while (cmpxchg8b(&head->align, old.align, new.align) != old.align); + TRACE4("%p, %p", head, entry); + return entry; +} + +#endif + +#define sleep_hz(n) \ +do { \ + set_current_state(TASK_INTERRUPTIBLE); \ + schedule_timeout(n); \ +} while (0) + +int ntoskernel_init(void); +void ntoskernel_exit(void); +int ntoskernel_init_device(struct wrap_device *wd); +void ntoskernel_exit_device(struct wrap_device *wd); +void *allocate_object(ULONG size, enum common_object_type type, + struct unicode_string *name); +void free_object(void *object); + +int usb_init(void); +void usb_exit(void); +int usb_init_device(struct wrap_device *wd); +void usb_exit_device(struct wrap_device *wd); +void usb_cancel_pending_urbs(void); + +int crt_init(void); +void crt_exit(void); +int rtl_init(void); +void rtl_exit(void); +int wrap_procfs_init(void); +void wrap_procfs_remove(void); + +int link_pe_images(struct pe_image *pe_image, unsigned short n); + +int stricmp(const char *s1, const char *s2); +void dump_bytes(const char *name, const u8 *from, int len); +struct mdl *allocate_init_mdl(void *virt, ULONG length); +void free_mdl(struct mdl *mdl); +struct driver_object *find_bus_driver(const char *name); +void free_custom_extensions(struct driver_extension *drv_obj_ext); +struct nt_thread *get_current_nt_thread(void); +u64 ticks_1601(void); +int schedule_ntos_work_item(NTOS_WORK_FUNC func, void *arg1, void *arg2); +void wrap_init_timer(struct nt_timer *nt_timer, enum timer_type type, + struct ndis_mp_block *nmb); +BOOLEAN wrap_set_timer(struct nt_timer *nt_timer, unsigned long expires_hz, + unsigned long repeat_hz, struct kdpc *kdpc); + +LONG InterlockedDecrement(LONG volatile *val) wfastcall; +LONG InterlockedIncrement(LONG volatile *val) wfastcall; +struct nt_list *ExInterlockedInsertHeadList + (struct nt_list *head, struct nt_list *entry, + NT_SPIN_LOCK *lock) wfastcall; +struct nt_list *ExInterlockedInsertTailList + (struct nt_list *head, struct nt_list *entry, + NT_SPIN_LOCK *lock) wfastcall; +struct nt_list *ExInterlockedRemoveHeadList + (struct nt_list *head, NT_SPIN_LOCK *lock) wfastcall; +NTSTATUS IofCallDriver(struct device_object *dev_obj, struct irp *irp) wfastcall; +KIRQL KfRaiseIrql(KIRQL newirql) wfastcall; +void KfLowerIrql(KIRQL oldirql) wfastcall; +KIRQL KfAcquireSpinLock(NT_SPIN_LOCK *lock) wfastcall; +void KfReleaseSpinLock(NT_SPIN_LOCK *lock, KIRQL oldirql) wfastcall; +void IofCompleteRequest(struct irp *irp, CHAR prio_boost) wfastcall; +void KefReleaseSpinLockFromDpcLevel(NT_SPIN_LOCK *lock) wfastcall; + +LONG ObfReferenceObject(void *object) wfastcall; +void ObfDereferenceObject(void *object) wfastcall; + +#define ObReferenceObject(object) ObfReferenceObject(object) +#define ObDereferenceObject(object) ObfDereferenceObject(object) + +void WRITE_PORT_UCHAR(ULONG_PTR port, UCHAR value) wstdcall; +UCHAR READ_PORT_UCHAR(ULONG_PTR port) wstdcall; + +#undef ExAllocatePoolWithTag +void *ExAllocatePoolWithTag(enum pool_type pool_type, SIZE_T size, + ULONG tag) wstdcall; +#if defined(ALLOC_DEBUG) && ALLOC_DEBUG > 1 +#define ExAllocatePoolWithTag(pool_type, size, tag) \ + wrap_ExAllocatePoolWithTag(pool_type, size, tag, __FILE__, __LINE__) +#endif + +void ExFreePool(void *p) wstdcall; +ULONG MmSizeOfMdl(void *base, ULONG length) wstdcall; +void __iomem *MmMapIoSpace(PHYSICAL_ADDRESS phys_addr, SIZE_T size, + enum memory_caching_type cache) wstdcall; +void MmUnmapIoSpace(void __iomem *addr, SIZE_T size) wstdcall; +void MmProbeAndLockPages(struct mdl *mdl, KPROCESSOR_MODE access_mode, + enum lock_operation operation) wstdcall; +void MmUnlockPages(struct mdl *mdl) wstdcall; +void KeInitializeEvent(struct nt_event *nt_event, + enum event_type type, BOOLEAN state) wstdcall; +LONG KeSetEvent(struct nt_event *nt_event, KPRIORITY incr, + BOOLEAN wait) wstdcall; +LONG KeResetEvent(struct nt_event *nt_event) wstdcall; +void KeClearEvent(struct nt_event *nt_event) wstdcall; +void KeInitializeDpc(struct kdpc *kdpc, void *func, void *ctx) wstdcall; +BOOLEAN queue_kdpc(struct kdpc *kdpc); +BOOLEAN dequeue_kdpc(struct kdpc *kdpc); + +void KeFlushQueuedDpcs(void) wstdcall; +NTSTATUS IoConnectInterrupt(struct kinterrupt **kinterrupt, + PKSERVICE_ROUTINE service_routine, + void *service_context, NT_SPIN_LOCK *lock, + ULONG vector, KIRQL irql, KIRQL synch_irql, + enum kinterrupt_mode interrupt_mode, + BOOLEAN shareable, KAFFINITY processor_enable_mask, + BOOLEAN floating_save) wstdcall; +void IoDisconnectInterrupt(struct kinterrupt *interrupt) wstdcall; +BOOLEAN KeSynchronizeExecution(struct kinterrupt *interrupt, + PKSYNCHRONIZE_ROUTINE synch_routine, + void *ctx) wstdcall; + +NTSTATUS KeWaitForSingleObject(void *object, KWAIT_REASON reason, + KPROCESSOR_MODE waitmode, BOOLEAN alertable, + LARGE_INTEGER *timeout) wstdcall; +struct mdl *IoAllocateMdl(void *virt, ULONG length, BOOLEAN second_buf, + BOOLEAN charge_quota, struct irp *irp) wstdcall; +void MmBuildMdlForNonPagedPool(struct mdl *mdl) wstdcall; +void IoFreeMdl(struct mdl *mdl) wstdcall; +NTSTATUS IoCreateDevice(struct driver_object *driver, ULONG dev_ext_length, + struct unicode_string *dev_name, DEVICE_TYPE dev_type, + ULONG dev_chars, BOOLEAN exclusive, + struct device_object **dev_obj) wstdcall; +NTSTATUS IoCreateSymbolicLink(struct unicode_string *link, + struct unicode_string *dev_name) wstdcall; +void IoDeleteDevice(struct device_object *dev) wstdcall; +void IoDetachDevice(struct device_object *topdev) wstdcall; +struct device_object *IoGetAttachedDevice(struct device_object *dev) wstdcall; +struct device_object *IoGetAttachedDeviceReference + (struct device_object *dev) wstdcall; +NTSTATUS IoAllocateDriverObjectExtension + (struct driver_object *drv_obj, void *client_id, ULONG extlen, + void **ext) wstdcall; +void *IoGetDriverObjectExtension(struct driver_object *drv, + void *client_id) wstdcall; +struct device_object *IoAttachDeviceToDeviceStack + (struct device_object *src, struct device_object *dst) wstdcall; +void KeInitializeEvent(struct nt_event *nt_event, enum event_type type, + BOOLEAN state) wstdcall; +struct irp *IoAllocateIrp(char stack_count, BOOLEAN charge_quota) wstdcall; +void IoFreeIrp(struct irp *irp) wstdcall; +BOOLEAN IoCancelIrp(struct irp *irp) wstdcall; +struct irp *IoBuildSynchronousFsdRequest + (ULONG major_func, struct device_object *dev_obj, void *buf, + ULONG length, LARGE_INTEGER *offset, struct nt_event *event, + struct io_status_block *status) wstdcall; +struct irp *IoBuildAsynchronousFsdRequest + (ULONG major_func, struct device_object *dev_obj, void *buf, + ULONG length, LARGE_INTEGER *offset, + struct io_status_block *status) wstdcall; +NTSTATUS PoCallDriver(struct device_object *dev_obj, struct irp *irp) wstdcall; + +NTSTATUS IoPassIrpDown(struct device_object *dev_obj, struct irp *irp) wstdcall; +WIN_FUNC_DECL(IoPassIrpDown,2); +NTSTATUS IoSyncForwardIrp(struct device_object *dev_obj, + struct irp *irp) wstdcall; +NTSTATUS IoAsyncForwardIrp(struct device_object *dev_obj, + struct irp *irp) wstdcall; +NTSTATUS IoInvalidDeviceRequest(struct device_object *dev_obj, + struct irp *irp) wstdcall; + +KIRQL KeGetCurrentIrql(void) wstdcall; +void KeInitializeSpinLock(NT_SPIN_LOCK *lock) wstdcall; +void KeAcquireSpinLock(NT_SPIN_LOCK *lock, KIRQL *irql) wstdcall; +void KeReleaseSpinLock(NT_SPIN_LOCK *lock, KIRQL oldirql) wstdcall; +KIRQL KeAcquireSpinLockRaiseToDpc(NT_SPIN_LOCK *lock) wstdcall; + +void IoAcquireCancelSpinLock(KIRQL *irql) wstdcall; +void IoReleaseCancelSpinLock(KIRQL irql) wstdcall; + +void RtlCopyMemory(void *dst, const void *src, SIZE_T length) wstdcall; +NTSTATUS RtlUnicodeStringToAnsiString + (struct ansi_string *dst, const struct unicode_string *src, + BOOLEAN dup) wstdcall; +NTSTATUS RtlAnsiStringToUnicodeString + (struct unicode_string *dst, const struct ansi_string *src, + BOOLEAN dup) wstdcall; +void RtlInitAnsiString(struct ansi_string *dst, const char *src) wstdcall; +void RtlInitString(struct ansi_string *dst, const char *src) wstdcall; +void RtlInitUnicodeString(struct unicode_string *dest, + const wchar_t *src) wstdcall; +void RtlFreeUnicodeString(struct unicode_string *string) wstdcall; +void RtlFreeAnsiString(struct ansi_string *string) wstdcall; +LONG RtlCompareUnicodeString(const struct unicode_string *s1, + const struct unicode_string *s2, + BOOLEAN case_insensitive) wstdcall; +void RtlCopyUnicodeString(struct unicode_string *dst, + struct unicode_string *src) wstdcall; +NTSTATUS RtlUpcaseUnicodeString(struct unicode_string *dst, + struct unicode_string *src, + BOOLEAN alloc) wstdcall; +void KeInitializeTimer(struct nt_timer *nt_timer) wstdcall; +void KeInitializeTimerEx(struct nt_timer *nt_timer, + enum timer_type type) wstdcall; +BOOLEAN KeSetTimerEx(struct nt_timer *nt_timer, LARGE_INTEGER duetime_ticks, + LONG period_ms, struct kdpc *kdpc) wstdcall; +BOOLEAN KeSetTimer(struct nt_timer *nt_timer, LARGE_INTEGER duetime_ticks, + struct kdpc *kdpc) wstdcall; +BOOLEAN KeCancelTimer(struct nt_timer *nt_timer) wstdcall; +void KeInitializeDpc(struct kdpc *kdpc, void *func, void *ctx) wstdcall; +struct nt_thread *KeGetCurrentThread(void) wstdcall; +NTSTATUS ObReferenceObjectByHandle(void *handle, ACCESS_MASK desired_access, + void *obj_type, KPROCESSOR_MODE access_mode, + void **object, void *handle_info) wstdcall; + +void adjust_user_shared_data_addr(char *driver, unsigned long length); + +extern spinlock_t ntoskernel_lock; +extern spinlock_t irp_cancel_lock; +extern struct nt_list object_list; +#ifdef CONFIG_X86_64 +extern struct kuser_shared_data kuser_shared_data; +#endif + +#define IoCompleteRequest(irp, prio) IofCompleteRequest(irp, prio) +#define IoCallDriver(dev, irp) IofCallDriver(dev, irp) + +#if defined(IO_DEBUG) +#define DUMP_IRP(_irp) \ +do { \ + struct io_stack_location *_irp_sl; \ + _irp_sl = IoGetCurrentIrpStackLocation(_irp); \ + IOTRACE("irp: %p, stack size: %d, cl: %d, sl: %p, dev_obj: %p, " \ + "mj_fn: %d, minor_fn: %d, nt_urb: %p, event: %p", \ + _irp, _irp->stack_count, (_irp)->current_location, \ + _irp_sl, _irp_sl->dev_obj, _irp_sl->major_fn, \ + _irp_sl->minor_fn, IRP_URB(_irp), \ + (_irp)->user_event); \ +} while (0) +#else +#define DUMP_IRP(_irp) do { } while (0) +#endif + +#endif // _NTOSKERNEL_H_ --- linux-2.6.27.orig/ubuntu/ndiswrapper/wrapper.c +++ linux-2.6.27/ubuntu/ndiswrapper/wrapper.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "ndis.h" +#include "iw_ndis.h" +#include "loader.h" +#include "pnp.h" +#include "wrapper.h" + +char *if_name = "wlan%d"; +int proc_uid, proc_gid; +int hangcheck_interval; +static char *utils_version = UTILS_VERSION; + +#if defined(DEBUG) && (DEBUG > 0) +int debug = DEBUG; +#else +int debug = 0; +#endif + +WRAP_MODULE_PARM_STRING(if_name, 0400); +MODULE_PARM_DESC(if_name, "Network interface name or template " + "(default: wlan%d)"); +WRAP_MODULE_PARM_INT(proc_uid, 0600); +MODULE_PARM_DESC(proc_uid, "The uid of the files created in /proc " + "(default: 0)."); +WRAP_MODULE_PARM_INT(proc_gid, 0600); +MODULE_PARM_DESC(proc_gid, "The gid of the files created in /proc " + "(default: 0)."); +WRAP_MODULE_PARM_INT(debug, 0600); +MODULE_PARM_DESC(debug, "debug level"); + +/* 0 - default value provided by NDIS driver, + * positive value - force hangcheck interval to that many seconds + * negative value - disable hangcheck + */ +WRAP_MODULE_PARM_INT(hangcheck_interval, 0600); +MODULE_PARM_DESC(hangcheck_interval, "The interval, in seconds, for checking" + " if driver is hung. (default: 0)"); + +WRAP_MODULE_PARM_STRING(utils_version, 0400); +MODULE_PARM_DESC(utils_version, "Compatible version of utils " + "(read only: " UTILS_VERSION ")"); + +MODULE_AUTHOR("ndiswrapper team "); +#ifdef MODULE_DESCRIPTION +MODULE_DESCRIPTION("NDIS wrapper driver"); +#endif +#ifdef MODULE_VERSION +MODULE_VERSION(DRIVER_VERSION); +#endif +MODULE_LICENSE("GPL"); + +static void module_cleanup(void) +{ + loader_exit(); +#ifdef ENABLE_USB + usb_exit(); +#endif + + wrap_procfs_remove(); + wrapndis_exit(); + ndis_exit(); + rtl_exit(); + crt_exit(); + ntoskernel_exit(); + wrapmem_exit(); +} + +static int __init wrapper_init(void) +{ + printk(KERN_INFO "%s version %s loaded (smp=%s, preempt=%s)\n", + DRIVER_NAME, DRIVER_VERSION, +#ifdef CONFIG_SMP + "yes" +#else + "no" +#endif + , +#ifdef CONFIG_PREEMPT_RT + "rt" +#elif defined(CONFIG_PREEMPT) + "yes" +#else + "no" +#endif + ); + + if (wrapmem_init() || ntoskernel_init() || crt_init() || + rtl_init() || ndis_init() || wrapndis_init() || +#ifdef ENABLE_USB + usb_init() || +#endif + wrap_procfs_init() || loader_init()) { + module_cleanup(); + ERROR("%s: initialization failed", DRIVER_NAME); + return -EINVAL; + } + EXIT1(return 0); +} + +static void __exit wrapper_exit(void) +{ + ENTER1(""); + module_cleanup(); +} + +module_init(wrapper_init); +module_exit(wrapper_exit); --- linux-2.6.27.orig/ubuntu/ndiswrapper/usb.c +++ linux-2.6.27/ubuntu/ndiswrapper/usb.c @@ -0,0 +1,1457 @@ +/* + * Copyright (C) 2004 Jan Kiszka + * Copyright (C) 2005 Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "ndis.h" +#include "usb.h" +#include "usb_exports.h" + +#ifdef USB_DEBUG +static unsigned int urb_id = 0; + +#define DUMP_WRAP_URB(wrap_urb, dir) \ + USBTRACE("urb %p (%d) %s: buf: %p, len: %d, pipe: 0x%x, %d", \ + (wrap_urb)->urb, (wrap_urb)->id, \ + (dir == USB_DIR_OUT) ? "going down" : "coming back", \ + (wrap_urb)->urb->transfer_buffer, \ + (wrap_urb)->urb->transfer_buffer_length, \ + (wrap_urb)->urb->pipe, (wrap_urb)->urb->status) + +#define DUMP_URB_BUFFER(urb, dir) \ + while (debug >= 2) { \ + int i; \ + char msg[20], *t; \ + if (!urb->transfer_buffer) \ + break; \ + if (!((usb_pipein(urb->pipe) && dir == USB_DIR_IN) || \ + (usb_pipeout(urb->pipe) && dir == USB_DIR_OUT))) \ + break; \ + t = msg; \ + t += sprintf(t, "%d: ", (urb)->actual_length); \ + for (i = 0; i < urb->actual_length && \ + t < &msg[sizeof(msg) - 4]; i++) \ + t += sprintf(t, "%02X ", \ + ((char *)urb->transfer_buffer)[i]); \ + *t = 0; \ + USBTRACE("%s", msg); \ + break; \ + } + +#else + +#define DUMP_WRAP_URB(wrap_urb, dir) (void)0 +#define DUMP_URB_BUFFER(urb, dir) (void)0 + +#endif + +#define CUR_ALT_SETTING(intf) (intf)->cur_altsetting + +#ifndef USB_CTRL_SET_TIMEOUT +#define USB_CTRL_SET_TIMEOUT 5000 +#endif + +#ifndef USB_CTRL_GET_TIMEOUT +#define USB_CTRL_GET_TIMEOUT 5000 +#endif + +#ifndef URB_NO_TRANSFER_DMA_MAP +#define URB_NO_TRANSFER_DMA_MAP 0 +#endif + +/* wrap_urb->flags */ +/* transfer_buffer for urb is allocated; free it in wrap_free_urb */ +#define WRAP_URB_COPY_BUFFER 0x01 + +static int inline wrap_cancel_urb(struct wrap_urb *wrap_urb) +{ + int ret; + USBTRACE("%p, %p, %d", wrap_urb, wrap_urb->urb, wrap_urb->state); + if (wrap_urb->state != URB_SUBMITTED) + USBEXIT(return -1); + ret = usb_unlink_urb(wrap_urb->urb); + USBTRACE("ret: %d", ret); + if (ret == -EINPROGRESS) + return 0; + else { + WARNING("unlink failed: %d", ret); + return ret; + } +} + +#define URB_STATUS(wrap_urb) (wrap_urb->urb->status) + +static struct nt_list wrap_urb_complete_list; +static spinlock_t wrap_urb_complete_list_lock; + +static work_struct_t wrap_urb_complete_work; +static void wrap_urb_complete_worker(worker_param_t dummy); + +static void kill_all_urbs(struct wrap_device *wd, int complete) +{ + struct nt_list *ent; + struct wrap_urb *wrap_urb; + KIRQL irql; + + USBTRACE("%d", wd->usb.num_alloc_urbs); + while (1) { + IoAcquireCancelSpinLock(&irql); + ent = RemoveHeadList(&wd->usb.wrap_urb_list); + IoReleaseCancelSpinLock(irql); + if (!ent) + break; + wrap_urb = container_of(ent, struct wrap_urb, list); + if (wrap_urb->state == URB_SUBMITTED) { + WARNING("Windows driver %s didn't free urb: %p", + wd->driver->name, wrap_urb->urb); + if (!complete) + wrap_urb->urb->complete = NULL; + usb_kill_urb(wrap_urb->urb); + } + USBTRACE("%p, %p", wrap_urb, wrap_urb->urb); + usb_free_urb(wrap_urb->urb); + kfree(wrap_urb); + } + wd->usb.num_alloc_urbs = 0; +} + +/* for a given Linux urb status code, return corresponding NT urb status */ +static USBD_STATUS wrap_urb_status(int urb_status) +{ + switch (urb_status) { + case 0: + return USBD_STATUS_SUCCESS; + case -EPROTO: + return USBD_STATUS_TIMEOUT; + case -EILSEQ: + return USBD_STATUS_CRC; + case -EPIPE: + return USBD_STATUS_INVALID_PIPE_HANDLE; + case -ECOMM: + return USBD_STATUS_DATA_OVERRUN; + case -ENOSR: + return USBD_STATUS_DATA_UNDERRUN; + case -EOVERFLOW: + return USBD_STATUS_BABBLE_DETECTED; + case -EREMOTEIO: + return USBD_STATUS_ERROR_SHORT_TRANSFER;; + case -ENODEV: + case -ESHUTDOWN: + case -ENOENT: + return USBD_STATUS_DEVICE_GONE; + case -ENOMEM: + return USBD_STATUS_NO_MEMORY; + case -EINVAL: + return USBD_STATUS_REQUEST_FAILED; + default: + return USBD_STATUS_NOT_SUPPORTED; + } +} + +/* for a given USBD_STATUS, return its corresponding NTSTATUS (for irp) */ +static NTSTATUS nt_urb_irp_status(USBD_STATUS nt_urb_status) +{ + switch (nt_urb_status) { + case USBD_STATUS_SUCCESS: + return STATUS_SUCCESS; + case USBD_STATUS_DEVICE_GONE: + return STATUS_DEVICE_REMOVED; + case USBD_STATUS_PENDING: + return STATUS_PENDING; + case USBD_STATUS_NOT_SUPPORTED: + return STATUS_NOT_IMPLEMENTED; + case USBD_STATUS_NO_MEMORY: + return STATUS_NO_MEMORY; + case USBD_STATUS_REQUEST_FAILED: + return STATUS_NOT_SUPPORTED; + default: + return STATUS_FAILURE; + } +} + +static void wrap_free_urb(struct urb *urb) +{ + struct irp *irp; + struct wrap_urb *wrap_urb; + + USBTRACE("freeing urb: %p", urb); + wrap_urb = urb->context; + irp = wrap_urb->irp; + if (wrap_urb->flags & WRAP_URB_COPY_BUFFER) { + USBTRACE("freeing DMA buffer for URB: %p %p", + urb, urb->transfer_buffer); + usb_buffer_free(IRP_WRAP_DEVICE(irp)->usb.udev, + urb->transfer_buffer_length, + urb->transfer_buffer, urb->transfer_dma); + } + if (urb->setup_packet) + kfree(urb->setup_packet); + if (IRP_WRAP_DEVICE(irp)->usb.num_alloc_urbs > MAX_ALLOCATED_URBS) { + IoAcquireCancelSpinLock(&irp->cancel_irql); + RemoveEntryList(&wrap_urb->list); + IRP_WRAP_DEVICE(irp)->usb.num_alloc_urbs--; + IoReleaseCancelSpinLock(irp->cancel_irql); + usb_free_urb(urb); + kfree(wrap_urb); + } else { + wrap_urb->state = URB_FREE; + wrap_urb->flags = 0; + wrap_urb->irp = NULL; + } + return; +} + +void wrap_suspend_urbs(struct wrap_device *wd) +{ + /* TODO: do we need to cancel urbs? */ + USBTRACE("%p, %d", wd, wd->usb.num_alloc_urbs); +} + +void wrap_resume_urbs(struct wrap_device *wd) +{ + /* TODO: do we need to resubmit urbs? */ + USBTRACE("%p, %d", wd, wd->usb.num_alloc_urbs); +} + +wstdcall void wrap_cancel_irp(struct device_object *dev_obj, struct irp *irp) +{ + struct urb *urb; + + /* NB: this function is called holding Cancel spinlock */ + USBENTER("irp: %p", irp); + urb = IRP_WRAP_URB(irp)->urb; + USBTRACE("canceling urb %p", urb); + if (wrap_cancel_urb(IRP_WRAP_URB(irp))) { + irp->cancel = FALSE; + ERROR("urb %p can't be canceld: %d", urb, + IRP_WRAP_URB(irp)->state); + } else + USBTRACE("urb %p canceled", urb); + IoReleaseCancelSpinLock(irp->cancel_irql); + return; +} +WIN_FUNC_DECL(wrap_cancel_irp,2) + +static struct urb *wrap_alloc_urb(struct irp *irp, unsigned int pipe, + void *buf, unsigned int buf_len) +{ + struct urb *urb; + gfp_t alloc_flags; + struct wrap_urb *wrap_urb; + struct wrap_device *wd; + + USBENTER("irp: %p", irp); + wd = IRP_WRAP_DEVICE(irp); + alloc_flags = irql_gfp(); + IoAcquireCancelSpinLock(&irp->cancel_irql); + urb = NULL; + nt_list_for_each_entry(wrap_urb, &wd->usb.wrap_urb_list, list) { + if (cmpxchg(&wrap_urb->state, URB_FREE, + URB_ALLOCATED) == URB_FREE) { + urb = wrap_urb->urb; + usb_init_urb(urb); + break; + } + } + if (!urb) { + IoReleaseCancelSpinLock(irp->cancel_irql); + wrap_urb = kzalloc(sizeof(*wrap_urb), alloc_flags); + if (!wrap_urb) { + WARNING("couldn't allocate memory"); + return NULL; + } + urb = usb_alloc_urb(0, alloc_flags); + if (!urb) { + WARNING("couldn't allocate urb"); + kfree(wrap_urb); + return NULL; + } + IoAcquireCancelSpinLock(&irp->cancel_irql); + wrap_urb->urb = urb; + wrap_urb->state = URB_ALLOCATED; + InsertTailList(&wd->usb.wrap_urb_list, &wrap_urb->list); + wd->usb.num_alloc_urbs++; + } + +#ifdef URB_ASYNC_UNLINK + urb->transfer_flags |= URB_ASYNC_UNLINK; +#elif defined(USB_ASYNC_UNLINK) + urb->transfer_flags |= USB_ASYNC_UNLINK; +#endif + urb->context = wrap_urb; + wrap_urb->irp = irp; + IRP_WRAP_URB(irp) = wrap_urb; + /* called as Windows function */ + irp->cancel_routine = WIN_FUNC_PTR(wrap_cancel_irp,2); + IoReleaseCancelSpinLock(irp->cancel_irql); + USBTRACE("urb: %p", urb); + + urb->transfer_buffer_length = buf_len; + if (buf_len && buf && (!virt_addr_valid(buf) +#if defined(CONFIG_HIGHMEM) || defined(CONFIG_HIGHMEM4G) + || PageHighMem(virt_to_page(buf)) +#endif + )) { + urb->transfer_buffer = + usb_buffer_alloc(wd->usb.udev, buf_len, alloc_flags, + &urb->transfer_dma); + if (!urb->transfer_buffer) { + WARNING("couldn't allocate dma buf"); + IoAcquireCancelSpinLock(&irp->cancel_irql); + wrap_urb->state = URB_FREE; + wrap_urb->irp = NULL; + IRP_WRAP_URB(irp) = NULL; + IoReleaseCancelSpinLock(irp->cancel_irql); + return NULL; + } + if (urb->transfer_dma) + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + wrap_urb->flags |= WRAP_URB_COPY_BUFFER; + if (usb_pipeout(pipe)) + memcpy(urb->transfer_buffer, buf, buf_len); + USBTRACE("DMA buf for urb %p: %p", urb, urb->transfer_buffer); + } else + urb->transfer_buffer = buf; + return urb; +} + +static USBD_STATUS wrap_submit_urb(struct irp *irp) +{ + int ret; + struct urb *urb; + union nt_urb *nt_urb; + + urb = IRP_WRAP_URB(irp)->urb; + nt_urb = IRP_URB(irp); +#ifdef USB_DEBUG + if (IRP_WRAP_URB(irp)->state != URB_ALLOCATED) { + ERROR("urb %p is in wrong state: %d", + urb, IRP_WRAP_URB(irp)->state); + NT_URB_STATUS(nt_urb) = USBD_STATUS_REQUEST_FAILED; + return NT_URB_STATUS(nt_urb); + } + IRP_WRAP_URB(irp)->id = pre_atomic_add(urb_id, 1); +#endif + DUMP_WRAP_URB(IRP_WRAP_URB(irp), USB_DIR_OUT); + irp->io_status.status = STATUS_PENDING; + irp->io_status.info = 0; + NT_URB_STATUS(nt_urb) = USBD_STATUS_PENDING; + IoMarkIrpPending(irp); + DUMP_URB_BUFFER(urb, USB_DIR_OUT); + USBTRACE("%p", urb); + IRP_WRAP_URB(irp)->state = URB_SUBMITTED; + ret = usb_submit_urb(urb, irql_gfp()); + if (ret) { + USBTRACE("ret: %d", ret); + wrap_free_urb(urb); + /* we assume that IRP was not in pending state before */ + IoUnmarkIrpPending(irp); + NT_URB_STATUS(nt_urb) = wrap_urb_status(ret); + USBEXIT(return NT_URB_STATUS(nt_urb)); + } else + USBEXIT(return USBD_STATUS_PENDING); +} + +static void wrap_urb_complete(struct urb *urb ISR_PT_REGS_PARAM_DECL) +{ + struct irp *irp; + struct wrap_urb *wrap_urb; + + wrap_urb = urb->context; + USBTRACE("%p (%p) completed", wrap_urb, urb); + irp = wrap_urb->irp; + DUMP_WRAP_URB(wrap_urb, USB_DIR_IN); + irp->cancel_routine = NULL; +#ifdef USB_DEBUG + if (wrap_urb->state != URB_SUBMITTED) { + WARNING("urb %p in wrong state: %d (%d)", urb, wrap_urb->state, + urb->status); + return; + } +#endif + wrap_urb->state = URB_COMPLETED; + spin_lock(&wrap_urb_complete_list_lock); + InsertTailList(&wrap_urb_complete_list, &wrap_urb->complete_list); + spin_unlock(&wrap_urb_complete_list_lock); + schedule_ntos_work(&wrap_urb_complete_work); +} + +/* one worker for all devices */ +static void wrap_urb_complete_worker(worker_param_t dummy) +{ + struct irp *irp; + struct urb *urb; + struct usbd_bulk_or_intr_transfer *bulk_int_tx; + struct usbd_vendor_or_class_request *vc_req; + union nt_urb *nt_urb; + struct wrap_urb *wrap_urb; + struct nt_list *ent; + unsigned long flags; + + USBENTER(""); + while (1) { + spin_lock_irqsave(&wrap_urb_complete_list_lock, flags); + ent = RemoveHeadList(&wrap_urb_complete_list); + spin_unlock_irqrestore(&wrap_urb_complete_list_lock, flags); + if (!ent) + break; + wrap_urb = container_of(ent, struct wrap_urb, complete_list); + urb = wrap_urb->urb; +#ifdef USB_DEBUG + if (wrap_urb->state != URB_COMPLETED && + wrap_urb->state != URB_INT_UNLINKED) + WARNING("urb %p in wrong state: %d", + urb, wrap_urb->state); +#endif + irp = wrap_urb->irp; + DUMP_IRP(irp); + nt_urb = IRP_URB(irp); + USBTRACE("urb: %p, nt_urb: %p, status: %d", + urb, nt_urb, urb->status); + switch (urb->status) { + case 0: + /* succesfully transferred */ + irp->io_status.info = urb->actual_length; + if (nt_urb->header.function == + URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER) { + bulk_int_tx = &nt_urb->bulk_int_transfer; + bulk_int_tx->transfer_buffer_length = + urb->actual_length; + DUMP_URB_BUFFER(urb, USB_DIR_IN); + if ((wrap_urb->flags & WRAP_URB_COPY_BUFFER) && + usb_pipein(urb->pipe)) + memcpy(bulk_int_tx->transfer_buffer, + urb->transfer_buffer, + urb->actual_length); + } else { // vendor or class request + vc_req = &nt_urb->vendor_class_request; + vc_req->transfer_buffer_length = + urb->actual_length; + DUMP_URB_BUFFER(urb, USB_DIR_IN); + if ((wrap_urb->flags & WRAP_URB_COPY_BUFFER) && + usb_pipein(urb->pipe)) + memcpy(vc_req->transfer_buffer, + urb->transfer_buffer, + urb->actual_length); + } + NT_URB_STATUS(nt_urb) = USBD_STATUS_SUCCESS; + irp->io_status.status = STATUS_SUCCESS; + break; + case -ENOENT: + case -ECONNRESET: + /* urb canceled */ + irp->io_status.info = 0; + TRACE2("urb %p canceled", urb); + NT_URB_STATUS(nt_urb) = USBD_STATUS_SUCCESS; + irp->io_status.status = STATUS_CANCELLED; + break; + default: + TRACE2("irp: %p, urb: %p, status: %d/%d", + irp, urb, urb->status, wrap_urb->state); + irp->io_status.info = 0; + NT_URB_STATUS(nt_urb) = wrap_urb_status(urb->status); + irp->io_status.status = + nt_urb_irp_status(NT_URB_STATUS(nt_urb)); + break; + } + wrap_free_urb(urb); + IoCompleteRequest(irp, IO_NO_INCREMENT); + } + USBEXIT(return); +} + +static USBD_STATUS wrap_bulk_or_intr_trans(struct irp *irp) +{ + usbd_pipe_handle pipe_handle; + struct urb *urb; + unsigned int pipe; + struct usbd_bulk_or_intr_transfer *bulk_int_tx; + USBD_STATUS status; + struct usb_device *udev; + union nt_urb *nt_urb; + + nt_urb = IRP_URB(irp); + udev = IRP_WRAP_DEVICE(irp)->usb.udev; + bulk_int_tx = &nt_urb->bulk_int_transfer; + pipe_handle = bulk_int_tx->pipe_handle; + USBTRACE("flags: 0x%x, length: %u, buffer: %p, handle: %p", + bulk_int_tx->transfer_flags, + bulk_int_tx->transfer_buffer_length, + bulk_int_tx->transfer_buffer, pipe_handle); + + if (USBD_IS_BULK_PIPE(pipe_handle)) { + if (bulk_int_tx->transfer_flags & USBD_TRANSFER_DIRECTION_IN) + pipe = usb_rcvbulkpipe(udev, + pipe_handle->bEndpointAddress); + else + pipe = usb_sndbulkpipe(udev, + pipe_handle->bEndpointAddress); + } else { + if (bulk_int_tx->transfer_flags & USBD_TRANSFER_DIRECTION_IN) + pipe = usb_rcvintpipe(udev, + pipe_handle->bEndpointAddress); + else + pipe = usb_sndintpipe(udev, + pipe_handle->bEndpointAddress); + } + + DUMP_IRP(irp); + urb = wrap_alloc_urb(irp, pipe, bulk_int_tx->transfer_buffer, + bulk_int_tx->transfer_buffer_length); + if (!urb) { + ERROR("couldn't allocate urb"); + return USBD_STATUS_NO_MEMORY; + } + if (usb_pipein(pipe) && + (!(bulk_int_tx->transfer_flags & USBD_SHORT_TRANSFER_OK))) { + USBTRACE("short not ok"); + urb->transfer_flags |= URB_SHORT_NOT_OK; + } + if (usb_pipebulk(pipe)) { + usb_fill_bulk_urb(urb, udev, pipe, urb->transfer_buffer, + bulk_int_tx->transfer_buffer_length, + wrap_urb_complete, urb->context); + USBTRACE("submitting bulk urb %p on pipe 0x%x (ep 0x%x)", + urb, urb->pipe, pipe_handle->bEndpointAddress); + } else { + usb_fill_int_urb(urb, udev, pipe, urb->transfer_buffer, + bulk_int_tx->transfer_buffer_length, + wrap_urb_complete, urb->context, + pipe_handle->bInterval); + USBTRACE("submitting interrupt urb %p on pipe 0x%x (ep 0x%x), " + "intvl: %d", urb, urb->pipe, + pipe_handle->bEndpointAddress, pipe_handle->bInterval); + } + status = wrap_submit_urb(irp); + USBTRACE("status: %08X", status); + USBEXIT(return status); +} + +static USBD_STATUS wrap_vendor_or_class_req(struct irp *irp) +{ + u8 req_type; + unsigned int pipe; + struct usbd_vendor_or_class_request *vc_req; + struct usb_device *udev; + union nt_urb *nt_urb; + USBD_STATUS status; + struct urb *urb; + struct usb_ctrlrequest *dr; + + nt_urb = IRP_URB(irp); + udev = IRP_WRAP_DEVICE(irp)->usb.udev; + vc_req = &nt_urb->vendor_class_request; + USBTRACE("bits: %x, req: %x, val: %08x, index: %08x, flags: %x," + "buf: %p, len: %d", vc_req->reserved_bits, vc_req->request, + vc_req->value, vc_req->index, vc_req->transfer_flags, + vc_req->transfer_buffer, vc_req->transfer_buffer_length); + + USBTRACE("%x", nt_urb->header.function); + switch (nt_urb->header.function) { + case URB_FUNCTION_VENDOR_DEVICE: + req_type = USB_TYPE_VENDOR | USB_RECIP_DEVICE; + break; + case URB_FUNCTION_VENDOR_INTERFACE: + req_type = USB_TYPE_VENDOR | USB_RECIP_INTERFACE; + break; + case URB_FUNCTION_VENDOR_ENDPOINT: + req_type = USB_TYPE_VENDOR | USB_RECIP_ENDPOINT; + break; + case URB_FUNCTION_VENDOR_OTHER: + req_type = USB_TYPE_VENDOR | USB_RECIP_OTHER; + break; + case URB_FUNCTION_CLASS_DEVICE: + req_type = USB_TYPE_CLASS | USB_RECIP_DEVICE; + break; + case URB_FUNCTION_CLASS_INTERFACE: + req_type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; + break; + case URB_FUNCTION_CLASS_ENDPOINT: + req_type = USB_TYPE_CLASS | USB_RECIP_ENDPOINT; + break; + case URB_FUNCTION_CLASS_OTHER: + req_type = USB_TYPE_CLASS | USB_RECIP_OTHER; + break; + default: + ERROR("unknown request type: %x", nt_urb->header.function); + req_type = 0; + break; + } + + req_type |= vc_req->reserved_bits; + USBTRACE("req type: %08x", req_type); + + if (vc_req->transfer_flags & USBD_TRANSFER_DIRECTION_IN) { + pipe = usb_rcvctrlpipe(udev, 0); + req_type |= USB_DIR_IN; + USBTRACE("pipe: %x, dir in", pipe); + } else { + pipe = usb_sndctrlpipe(udev, 0); + req_type |= USB_DIR_OUT; + USBTRACE("pipe: %x, dir out", pipe); + } + urb = wrap_alloc_urb(irp, pipe, vc_req->transfer_buffer, + vc_req->transfer_buffer_length); + if (!urb) { + ERROR("couldn't allocate urb"); + return USBD_STATUS_NO_MEMORY; + } + + if (usb_pipein(pipe) && + (!(vc_req->transfer_flags & USBD_SHORT_TRANSFER_OK))) { + USBTRACE("short not ok"); + urb->transfer_flags |= URB_SHORT_NOT_OK; + } + + dr = kzalloc(sizeof(*dr), GFP_ATOMIC); + if (!dr) { + ERROR("couldn't allocate memory"); + wrap_free_urb(urb); + return USBD_STATUS_NO_MEMORY; + } + dr->bRequestType = req_type; + dr->bRequest = vc_req->request; + dr->wValue = cpu_to_le16(vc_req->value); + dr->wIndex = cpu_to_le16((u16)vc_req->index); + dr->wLength = cpu_to_le16((u16)urb->transfer_buffer_length); + + usb_fill_control_urb(urb, udev, pipe, (unsigned char *)dr, + urb->transfer_buffer, urb->transfer_buffer_length, + wrap_urb_complete, urb->context); + status = wrap_submit_urb(irp); + USBTRACE("status: %08X", status); + USBEXIT(return status); +} + +static USBD_STATUS wrap_reset_pipe(struct usb_device *udev, struct irp *irp) +{ + int ret; + union nt_urb *nt_urb; + usbd_pipe_handle pipe_handle; + unsigned int pipe1, pipe2; + + nt_urb = IRP_URB(irp); + pipe_handle = nt_urb->pipe_req.pipe_handle; + /* TODO: not clear if both directions should be cleared? */ + if (USBD_IS_BULK_PIPE(pipe_handle)) { + pipe1 = usb_rcvbulkpipe(udev, pipe_handle->bEndpointAddress); + pipe2 = usb_sndbulkpipe(udev, pipe_handle->bEndpointAddress); + } else if (USBD_IS_INT_PIPE(pipe_handle)) { + pipe1 = usb_rcvintpipe(udev, pipe_handle->bEndpointAddress); + pipe2 = pipe1; + } else { + WARNING("invalid pipe %d", pipe_handle->bEndpointAddress); + return USBD_STATUS_INVALID_PIPE_HANDLE; + } + USBTRACE("ep: %d, pipe: 0x%x", pipe_handle->bEndpointAddress, pipe1); + ret = usb_clear_halt(udev, pipe1); + if (ret) + USBTRACE("resetting pipe %d failed: %d", pipe1, ret); + if (pipe2 != pipe1) { + ret = usb_clear_halt(udev, pipe2); + if (ret) + USBTRACE("resetting pipe %d failed: %d", pipe2, ret); + } +// return wrap_urb_status(ret); + return USBD_STATUS_SUCCESS; +} + +static USBD_STATUS wrap_abort_pipe(struct usb_device *udev, struct irp *irp) +{ + union nt_urb *nt_urb; + usbd_pipe_handle pipe_handle; + struct wrap_urb *wrap_urb; + struct wrap_device *wd; + KIRQL irql; + + wd = IRP_WRAP_DEVICE(irp); + nt_urb = IRP_URB(irp); + pipe_handle = nt_urb->pipe_req.pipe_handle; + USBENTER("%p, %x", irp, pipe_handle->bEndpointAddress); + IoAcquireCancelSpinLock(&irql); + nt_list_for_each_entry(wrap_urb, &wd->usb.wrap_urb_list, list) { + USBTRACE("%p, %p, %d, %x, %x", wrap_urb, wrap_urb->urb, + wrap_urb->state, wrap_urb->urb->pipe, + usb_pipeendpoint(wrap_urb->urb->pipe)); + /* for WG111T driver, urbs for endpoint 0 should also + * be canceled */ + if ((usb_pipeendpoint(wrap_urb->urb->pipe) == + pipe_handle->bEndpointAddress) || + (usb_pipeendpoint(wrap_urb->urb->pipe) == 0)) { + if (wrap_cancel_urb(wrap_urb) == 0) + USBTRACE("canceled wrap_urb: %p", wrap_urb); + } + } + IoReleaseCancelSpinLock(irql); + NT_URB_STATUS(nt_urb) = USBD_STATUS_CANCELED; + USBEXIT(return USBD_STATUS_SUCCESS); +} + +static USBD_STATUS wrap_set_clear_feature(struct usb_device *udev, + struct irp *irp) +{ + union nt_urb *nt_urb; + struct urb_control_feature_request *feat_req; + int ret = 0; + __u8 request, type; + __u16 feature; + + nt_urb = IRP_URB(irp); + feat_req = &nt_urb->feat_req; + feature = feat_req->feature_selector; + switch (nt_urb->header.function) { + case URB_FUNCTION_SET_FEATURE_TO_DEVICE: + request = USB_REQ_SET_FEATURE; + type = USB_DT_DEVICE; + break; + case URB_FUNCTION_SET_FEATURE_TO_INTERFACE: + request = USB_REQ_SET_FEATURE; + type = USB_DT_INTERFACE; + break; + case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT: + request = USB_REQ_SET_FEATURE; + type = USB_DT_ENDPOINT; + break; + case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE: + request = USB_REQ_CLEAR_FEATURE; + type = USB_DT_DEVICE; + break; + case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE: + request = USB_REQ_CLEAR_FEATURE; + type = USB_DT_INTERFACE; + break; + case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT: + request = USB_REQ_CLEAR_FEATURE; + type = USB_DT_ENDPOINT; + break; + default: + WARNING("invalid function: %x", nt_urb->header.function); + NT_URB_STATUS(nt_urb) = USBD_STATUS_NOT_SUPPORTED; + return NT_URB_STATUS(nt_urb); + } + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), request, type, + feature, feat_req->index, NULL, 0, 1000); + NT_URB_STATUS(nt_urb) = wrap_urb_status(ret); + USBEXIT(return NT_URB_STATUS(nt_urb)); +} + +static USBD_STATUS wrap_get_status_request(struct usb_device *udev, + struct irp *irp) +{ + union nt_urb *nt_urb; + struct urb_control_get_status_request *status_req; + int ret = 0; + __u8 type; + + nt_urb = IRP_URB(irp); + status_req = &nt_urb->status_req; + switch (nt_urb->header.function) { + case URB_FUNCTION_GET_STATUS_FROM_DEVICE: + type = USB_RECIP_DEVICE; + break; + case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: + type = USB_RECIP_INTERFACE; + break; + case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: + type = USB_RECIP_ENDPOINT; + break; + default: + WARNING("invalid function: %x", nt_urb->header.function); + NT_URB_STATUS(nt_urb) = USBD_STATUS_NOT_SUPPORTED; + return NT_URB_STATUS(nt_urb); + } + assert(status_req->transfer_buffer_length == sizeof(u16)); + ret = usb_get_status(udev, type, status_req->index, + status_req->transfer_buffer); + if (ret >= 0) { + assert(ret <= status_req->transfer_buffer_length); + status_req->transfer_buffer_length = ret; + NT_URB_STATUS(nt_urb) = USBD_STATUS_SUCCESS; + } else + NT_URB_STATUS(nt_urb) = wrap_urb_status(ret); + USBEXIT(return NT_URB_STATUS(nt_urb)); +} + +static void set_intf_pipe_info(struct wrap_device *wd, + struct usb_interface *usb_intf, + struct usbd_interface_information *intf) +{ + int i; + struct usb_endpoint_descriptor *ep; + struct usbd_pipe_information *pipe; + + for (i = 0; i < CUR_ALT_SETTING(usb_intf)->desc.bNumEndpoints; i++) { + ep = &(CUR_ALT_SETTING(usb_intf)->endpoint[i]).desc; + if (i >= intf->bNumEndpoints) { + ERROR("intf %p has only %d endpoints, " + "ignoring endpoints above %d", + intf, intf->bNumEndpoints, i); + break; + } + pipe = &intf->pipes[i]; + + if (pipe->flags & USBD_PF_CHANGE_MAX_PACKET) + USBTRACE("pkt_sz: %d: %d", pipe->wMaxPacketSize, + pipe->max_tx_size); + USBTRACE("driver wants max_tx_size to %d", + pipe->max_tx_size); + + pipe->wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize); + pipe->bEndpointAddress = ep->bEndpointAddress; + pipe->type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + if (pipe->type == UsbdPipeTypeInterrupt) { + /* Windows and Linux differ in how the + * bInterval is interpretted */ + /* for low speed: + interval (Windows) -> frames per ms (Linux) + 0 to 15 -> 8 + 16 to 35 -> 16 + 36 to 255 -> 32 + + for full speed: interval -> frames per ms + 1 -> 1 + 2 to 3 -> 2 + 4 to 7 -> 4 + 8 to 15 -> 8 + 16 to 31 -> 16 + 32 to 255 -> 32 + + for high speed: interval -> microframes + 1 -> 1 + 2 -> 2 + 3 -> 4 + 4 -> 8 + 5 -> 16 + 6 -> 32 + 7 to 255 -> 32 + */ + if (wd->usb.udev->speed == USB_SPEED_LOW) + pipe->bInterval = ep->bInterval + 5; + else if (wd->usb.udev->speed == USB_SPEED_FULL) + pipe->bInterval = ep->bInterval; + else { + int j, k; + for (j = k = 1; j < ep->bInterval; k++) + j *= 2; + pipe->bInterval = k; + } + } + pipe->handle = ep; + USBTRACE("%d: ep 0x%x, type %d, pkt_sz %d, intv %d (%d)," + "type: %d, handle %p", i, ep->bEndpointAddress, + ep->bmAttributes, pipe->wMaxPacketSize, ep->bInterval, + pipe->bInterval, pipe->type, pipe->handle); + } +} + +static USBD_STATUS wrap_select_configuration(struct wrap_device *wd, + union nt_urb *nt_urb, + struct irp *irp) +{ + int i, ret; + struct usbd_select_configuration *sel_conf; + struct usb_device *udev; + struct usbd_interface_information *intf; + struct usb_config_descriptor *config; + struct usb_interface *usb_intf; + + udev = wd->usb.udev; + sel_conf = &nt_urb->select_conf; + config = sel_conf->config; + USBTRACE("%p", config); + if (config == NULL) { + kill_all_urbs(wd, 1); + ret = usb_reset_configuration(udev); + return wrap_urb_status(ret); + } + + USBTRACE("conf: %d, type: %d, length: %d, numif: %d, attr: %08x", + config->bConfigurationValue, config->bDescriptorType, + config->wTotalLength, config->bNumInterfaces, + config->bmAttributes); + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_SET_CONFIGURATION, 0, + config->bConfigurationValue, 0, + NULL, 0, USB_CTRL_SET_TIMEOUT); + if (ret < 0) { + ERROR("ret: %d", ret); + return wrap_urb_status(ret); + } + sel_conf->handle = udev->actconfig; + intf = &sel_conf->intf; + for (i = 0; i < config->bNumInterfaces && intf->bLength > 0; + i++, intf = (((void *)intf) + intf->bLength)) { + + USBTRACE("intf: %d, alt setting: %d", + intf->bInterfaceNumber, intf->bAlternateSetting); + ret = usb_set_interface(udev, intf->bInterfaceNumber, + intf->bAlternateSetting); + if (ret < 0) { + ERROR("failed with %d", ret); + return wrap_urb_status(ret); + } + usb_intf = usb_ifnum_to_if(udev, intf->bInterfaceNumber); + if (!usb_intf) { + ERROR("couldn't obtain ifnum"); + return USBD_STATUS_REQUEST_FAILED; + } + USBTRACE("intf: %p, num ep: %d", intf, intf->bNumEndpoints); + set_intf_pipe_info(wd, usb_intf, intf); + } + return USBD_STATUS_SUCCESS; +} + +static USBD_STATUS wrap_select_interface(struct wrap_device *wd, + union nt_urb *nt_urb, + struct irp *irp) +{ + int ret; + struct usbd_select_interface *sel_intf; + struct usb_device *udev; + struct usbd_interface_information *intf; + struct usb_interface *usb_intf; + + udev = wd->usb.udev; + sel_intf = &nt_urb->select_intf; + intf = &sel_intf->intf; + + ret = usb_set_interface(udev, intf->bInterfaceNumber, + intf->bAlternateSetting); + if (ret < 0) { + ERROR("failed with %d", ret); + return wrap_urb_status(ret); + } + usb_intf = usb_ifnum_to_if(udev, intf->bInterfaceNumber); + if (!usb_intf) { + ERROR("couldn't get interface information"); + return USBD_STATUS_REQUEST_FAILED; + } + USBTRACE("intf: %p, num ep: %d", usb_intf, intf->bNumEndpoints); + set_intf_pipe_info(wd, usb_intf, intf); + return USBD_STATUS_SUCCESS; +} + +static int wrap_usb_get_string(struct usb_device *udev, unsigned short langid, + unsigned char index, void *buf, int size) +{ + int i, ret; + /* if langid is 0, return array of langauges supported in + * buf */ + for (i = 0; i < 3; i++) { + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, + (USB_DT_STRING << 8) + index, langid, + buf, size, USB_CTRL_GET_TIMEOUT); + if (ret > 0 || ret == -EPIPE) + break; + } + return ret; +} + +static USBD_STATUS wrap_get_descriptor(struct wrap_device *wd, + union nt_urb *nt_urb, struct irp *irp) +{ + struct usbd_control_descriptor_request *control_desc; + int ret = 0; + struct usb_device *udev; + + udev = wd->usb.udev; + control_desc = &nt_urb->control_desc; + USBTRACE("desctype = %d, descindex = %d, transfer_buffer = %p," + "transfer_buffer_length = %d", control_desc->desc_type, + control_desc->index, control_desc->transfer_buffer, + control_desc->transfer_buffer_length); + + if (control_desc->desc_type == USB_DT_STRING) { + USBTRACE("langid: %x", control_desc->language_id); + ret = wrap_usb_get_string(udev, control_desc->language_id, + control_desc->index, + control_desc->transfer_buffer, + control_desc->transfer_buffer_length); + } else { + ret = usb_get_descriptor(udev, control_desc->desc_type, + control_desc->index, + control_desc->transfer_buffer, + control_desc->transfer_buffer_length); + } + if (ret < 0) { + USBTRACE("request %d failed: %d", control_desc->desc_type, ret); + control_desc->transfer_buffer_length = 0; + return wrap_urb_status(ret); + } else { + USBTRACE("ret: %08x", ret); + control_desc->transfer_buffer_length = ret; + irp->io_status.info = ret; + return USBD_STATUS_SUCCESS; + } +} + +static USBD_STATUS wrap_process_nt_urb(struct irp *irp) +{ + union nt_urb *nt_urb; + struct usb_device *udev; + USBD_STATUS status; + struct wrap_device *wd; + + wd = IRP_WRAP_DEVICE(irp); + udev = wd->usb.udev; + nt_urb = IRP_URB(irp); + USBENTER("nt_urb = %p, irp = %p, length = %d, function = %x", + nt_urb, irp, nt_urb->header.length, nt_urb->header.function); + + DUMP_IRP(irp); + switch (nt_urb->header.function) { + /* bulk/int and vendor/class urbs are submitted to + * Linux USB core; if the call is sucessful, urb's + * completion worker will return IRP later */ + case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: + USBTRACE("submitting bulk/int irp: %p", irp); + status = wrap_bulk_or_intr_trans(irp); + break; + + case URB_FUNCTION_VENDOR_DEVICE: + case URB_FUNCTION_VENDOR_INTERFACE: + case URB_FUNCTION_VENDOR_ENDPOINT: + case URB_FUNCTION_VENDOR_OTHER: + case URB_FUNCTION_CLASS_DEVICE: + case URB_FUNCTION_CLASS_INTERFACE: + case URB_FUNCTION_CLASS_ENDPOINT: + case URB_FUNCTION_CLASS_OTHER: + USBTRACE("submitting vendor/class irp: %p", irp); + status = wrap_vendor_or_class_req(irp); + break; + + /* rest are synchronous */ + case URB_FUNCTION_SELECT_CONFIGURATION: + status = wrap_select_configuration(wd, nt_urb, irp); + NT_URB_STATUS(nt_urb) = status; + break; + + case URB_FUNCTION_SELECT_INTERFACE: + status = wrap_select_interface(wd, nt_urb, irp); + NT_URB_STATUS(nt_urb) = status; + break; + + case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: + status = wrap_get_descriptor(wd, nt_urb, irp); + NT_URB_STATUS(nt_urb) = status; + break; + + case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL: + status = wrap_reset_pipe(udev, irp); + NT_URB_STATUS(nt_urb) = status; + break; + + case URB_FUNCTION_ABORT_PIPE: + status = wrap_abort_pipe(udev, irp); + break; + + case URB_FUNCTION_SET_FEATURE_TO_DEVICE: + case URB_FUNCTION_SET_FEATURE_TO_INTERFACE: + case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT: + case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE: + case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE: + case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT: + status = wrap_set_clear_feature(udev, irp); + break; + + case URB_FUNCTION_GET_STATUS_FROM_DEVICE: + case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: + case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: + status = wrap_get_status_request(udev, irp); + break; + + default: + ERROR("function %x not implemented", nt_urb->header.function); + status = NT_URB_STATUS(nt_urb) = USBD_STATUS_NOT_SUPPORTED; + break; + } + USBTRACE("status: %08X", status); + return status; +} + +static USBD_STATUS wrap_reset_port(struct irp *irp) +{ + no_warn_unused int ret, lock = 0; + struct wrap_device *wd; + + wd = IRP_WRAP_DEVICE(irp); + USBENTER("%p, %p", wd, wd->usb.udev); + lock = usb_lock_device_for_reset(wd->usb.udev, wd->usb.intf); + if (lock < 0) { + WARNING("locking failed: %d", lock); +// return wrap_urb_status(lock); + return USBD_STATUS_SUCCESS; + } + ret = usb_reset_device(wd->usb.udev); + if (ret < 0) + USBTRACE("reset failed: %d", ret); + /* TODO: should reconfigure? */ + if (lock) + usb_unlock_device(wd->usb.udev); +// return wrap_urb_status(ret); + return USBD_STATUS_SUCCESS; +} + +static USBD_STATUS wrap_get_port_status(struct irp *irp) +{ + struct wrap_device *wd; + ULONG *status; + enum usb_device_state state; + + wd = IRP_WRAP_DEVICE(irp); + USBENTER("%p, %p", wd, wd->usb.udev); + status = IoGetCurrentIrpStackLocation(irp)->params.others.arg1; + state = wd->usb.udev->state; + if (state != USB_STATE_NOTATTACHED && + state != USB_STATE_SUSPENDED) { + *status |= USBD_PORT_CONNECTED; + if (state == USB_STATE_CONFIGURED) + *status |= USBD_PORT_ENABLED; + } + USBTRACE("state: %d, *status: %08X", state, *status); + return USBD_STATUS_SUCCESS; +} + +NTSTATUS wrap_submit_irp(struct device_object *pdo, struct irp *irp) +{ + struct io_stack_location *irp_sl; + struct wrap_device *wd; + USBD_STATUS status; + struct usbd_idle_callback *idle_callback; + + USBENTER("%p, %p", pdo, irp); + wd = pdo->reserved; + if (wd->usb.intf == NULL) { + USBTRACE("%p", irp); + irp->io_status.status = STATUS_DEVICE_REMOVED; + irp->io_status.info = 0; + USBEXIT(return STATUS_DEVICE_REMOVED); + } + IRP_WRAP_DEVICE(irp) = wd; + irp_sl = IoGetCurrentIrpStackLocation(irp); + switch (irp_sl->params.dev_ioctl.code) { + case IOCTL_INTERNAL_USB_SUBMIT_URB: + status = wrap_process_nt_urb(irp); + break; + case IOCTL_INTERNAL_USB_RESET_PORT: + status = wrap_reset_port(irp); + break; + case IOCTL_INTERNAL_USB_GET_PORT_STATUS: + status = wrap_get_port_status(irp); + break; + case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: + idle_callback = irp_sl->params.dev_ioctl.type3_input_buf; + USBTRACE("suspend function: %p", idle_callback->callback); + status = USBD_STATUS_NOT_SUPPORTED; + break; + default: + ERROR("ioctl %08X NOT IMPLEMENTED", + irp_sl->params.dev_ioctl.code); + status = USBD_STATUS_NOT_SUPPORTED; + break; + } + + USBTRACE("status: %08X", status); + if (status == USBD_STATUS_PENDING) { + /* don't touch this IRP - it may have been already + * completed/returned */ + return STATUS_PENDING; + } else { + irp->io_status.status = nt_urb_irp_status(status); + if (status != USBD_STATUS_SUCCESS) + irp->io_status.info = 0; + USBEXIT(return irp->io_status.status); + } +} + +/* TODO: The example on msdn in reference section suggests that second + * argument should be an array of usbd_interface_information, but + * description and examples elsewhere suggest that it should be + * usbd_interface_list_entry structre. Which is correct? */ + +wstdcall union nt_urb *WIN_FUNC(USBD_CreateConfigurationRequestEx,2) + (struct usb_config_descriptor *config, + struct usbd_interface_list_entry *intf_list) +{ + int size, i, n; + struct usbd_interface_information *intf; + struct usbd_pipe_information *pipe; + struct usb_interface_descriptor *intf_desc; + struct usbd_select_configuration *select_conf; + + USBENTER("config = %p, intf_list = %p", config, intf_list); + + /* calculate size required; select_conf already has space for + * one intf structure */ + size = sizeof(*select_conf) - sizeof(*intf); + for (n = 0; n < config->bNumInterfaces; n++) { + i = intf_list[n].intf_desc->bNumEndpoints; + /* intf already has space for one pipe */ + size += sizeof(*intf) + (i - 1) * sizeof(*pipe); + } + /* don't use kmalloc - driver frees it with ExFreePool */ + select_conf = ExAllocatePoolWithTag(NonPagedPool, size, + POOL_TAG('L', 'U', 'S', 'B')); + if (!select_conf) { + WARNING("couldn't allocate memory"); + return NULL; + } + memset(select_conf, 0, size); + intf = &select_conf->intf; + select_conf->handle = config; + for (n = 0; n < config->bNumInterfaces && intf_list[n].intf_desc; n++) { + /* initialize 'intf' fields in intf_list so they point + * to appropriate entry; these may be read/written by + * driver after this function returns */ + intf_list[n].intf = intf; + intf_desc = intf_list[n].intf_desc; + + i = intf_desc->bNumEndpoints; + intf->bLength = sizeof(*intf) + (i - 1) * sizeof(*pipe); + + intf->bInterfaceNumber = intf_desc->bInterfaceNumber; + intf->bAlternateSetting = intf_desc->bAlternateSetting; + intf->bInterfaceClass = intf_desc->bInterfaceClass; + intf->bInterfaceSubClass = intf_desc->bInterfaceSubClass; + intf->bInterfaceProtocol = intf_desc->bInterfaceProtocol; + intf->bNumEndpoints = intf_desc->bNumEndpoints; + + pipe = &intf->pipes[0]; + for (i = 0; i < intf->bNumEndpoints; i++) { + memset(&pipe[i], 0, sizeof(*pipe)); + pipe[i].max_tx_size = + USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE; + } + intf->handle = intf_desc; + intf = (((void *)intf) + intf->bLength); + } + select_conf->header.function = URB_FUNCTION_SELECT_CONFIGURATION; + select_conf->header.length = size; + select_conf->config = config; + USBEXIT(return (union nt_urb *)select_conf); +} + +WIN_SYMBOL_MAP("_USBD_CreateConfigurationRequestEx@8", USBD_CreateConfigurationRequestEx) + +wstdcall struct usb_interface_descriptor * +WIN_FUNC(USBD_ParseConfigurationDescriptorEx,7) + (struct usb_config_descriptor *config, void *start, + LONG bInterfaceNumber, LONG bAlternateSetting, LONG bInterfaceClass, + LONG bInterfaceSubClass, LONG bInterfaceProtocol) +{ + void *pos; + struct usb_interface_descriptor *intf; + + USBENTER("config = %p, start = %p, ifnum = %d, alt_setting = %d," + " class = %d, subclass = %d, proto = %d", config, start, + bInterfaceNumber, bAlternateSetting, bInterfaceClass, + bInterfaceSubClass, bInterfaceProtocol); + + for (pos = start; + pos < ((void *)config + le16_to_cpu(config->wTotalLength)); + pos += intf->bLength) { + + intf = pos; + + if ((intf->bDescriptorType == USB_DT_INTERFACE) && + ((bInterfaceNumber == -1) || + (intf->bInterfaceNumber == bInterfaceNumber)) && + ((bAlternateSetting == -1) || + (intf->bAlternateSetting == bAlternateSetting)) && + ((bInterfaceClass == -1) || + (intf->bInterfaceClass == bInterfaceClass)) && + ((bInterfaceSubClass == -1) || + (intf->bInterfaceSubClass == bInterfaceSubClass)) && + ((bInterfaceProtocol == -1) || + (intf->bInterfaceProtocol == bInterfaceProtocol))) { + USBTRACE("selected interface = %p", intf); + USBEXIT(return intf); + } + } + USBEXIT(return NULL); +} + +WIN_SYMBOL_MAP("_USBD_ParseConfigurationDescriptorEx@28", USBD_ParseConfigurationDescriptorEx) + +wstdcall union nt_urb *WIN_FUNC(USBD_CreateConfigurationRequest,2) + (struct usb_config_descriptor *config, USHORT *size) +{ + union nt_urb *nt_urb; + struct usbd_interface_list_entry intf_list[2]; + struct usb_interface_descriptor *intf_desc; + + USBENTER("config = %p, urb_size = %p", config, size); + + intf_desc = USBD_ParseConfigurationDescriptorEx(config, config, -1, -1, + -1, -1, -1); + intf_list[0].intf_desc = intf_desc; + intf_list[0].intf = NULL; + intf_list[1].intf_desc = NULL; + intf_list[1].intf = NULL; + nt_urb = USBD_CreateConfigurationRequestEx(config, intf_list); + if (!nt_urb) + return NULL; + + *size = nt_urb->select_conf.header.length; + USBEXIT(return nt_urb); +} + +wstdcall struct usb_interface_descriptor * +WIN_FUNC(USBD_ParseConfigurationDescriptor,3) + (struct usb_config_descriptor *config, UCHAR bInterfaceNumber, + UCHAR bAlternateSetting) +{ + return USBD_ParseConfigurationDescriptorEx(config, config, + bInterfaceNumber, + bAlternateSetting, + -1, -1, -1); +} + +wstdcall usb_common_descriptor_t *WIN_FUNC(USBD_ParseDescriptors,4) + (void *buf, ULONG length, void *start, LONG type) +{ + usb_common_descriptor_t *descr = start; + + while ((void *)descr < buf + length) { + if (descr->bDescriptorType == type) + return descr; + if (descr->bLength == 0) + break; + descr = (void *)descr + descr->bLength; + } + USBEXIT(return NULL); +} + +WIN_SYMBOL_MAP("_USBD_ParseDescriptors@16", USBD_ParseDescriptors) + +wstdcall void WIN_FUNC(USBD_GetUSBDIVersion,1) + (struct usbd_version_info *version_info) +{ + /* this function is obsolete in Windows XP */ + if (version_info) { + version_info->usbdi_version = USBDI_VERSION_XP; + /* TODO: how do we get this correctly? */ + version_info->supported_usb_version = 0x110; + } + USBEXIT(return); +} + +wstdcall void +USBD_InterfaceGetUSBDIVersion(void *context, + struct usbd_version_info *version_info, + ULONG *hcd_capa) +{ + struct wrap_device *wd = context; + + if (version_info) { + version_info->usbdi_version = USBDI_VERSION_XP; + if (wd->usb.udev->speed == USB_SPEED_HIGH) + version_info->supported_usb_version = 0x200; + else + version_info->supported_usb_version = 0x110; + } + *hcd_capa = USB_HCD_CAPS_SUPPORTS_RT_THREADS; + USBEXIT(return); +} + +wstdcall BOOLEAN USBD_InterfaceIsDeviceHighSpeed(void *context) +{ + struct wrap_device *wd = context; + + USBTRACE("wd: %p", wd); + if (wd->usb.udev->speed == USB_SPEED_HIGH) + USBEXIT(return TRUE); + else + USBEXIT(return FALSE); +} + +wstdcall void USBD_InterfaceReference(void *context) +{ + USBTRACE("%p", context); + TODO(); +} + +wstdcall void USBD_InterfaceDereference(void *context) +{ + USBTRACE("%p", context); + TODO(); +} + +wstdcall NTSTATUS USBD_InterfaceQueryBusTime(void *context, ULONG *frame) +{ + struct wrap_device *wd = context; + + *frame = usb_get_current_frame_number(wd->usb.udev); + USBEXIT(return STATUS_SUCCESS); +} + +wstdcall NTSTATUS USBD_InterfaceSubmitIsoOutUrb(void *context, + union nt_urb *nt_urb) +{ + /* TODO: implement this */ + TODO(); + USBEXIT(return STATUS_NOT_IMPLEMENTED); +} + +wstdcall NTSTATUS +USBD_InterfaceQueryBusInformation(void *context, ULONG level, void *buf, + ULONG *buf_length, ULONG *buf_actual_length) +{ + struct wrap_device *wd = context; + struct usb_bus_information_level *bus_info; + struct usb_bus *bus; + + bus = wd->usb.udev->bus; + bus_info = buf; + TODO(); + USBEXIT(return STATUS_NOT_IMPLEMENTED); +} + +wstdcall NTSTATUS +USBD_InterfaceLogEntry(void *context, ULONG driver_tag, ULONG enum_tag, + ULONG p1, ULONG p2) +{ + ERROR("%p, %x, %x, %x, %x", context, driver_tag, enum_tag, p1, p2); + USBEXIT(return STATUS_SUCCESS); +} + +int usb_init(void) +{ + InitializeListHead(&wrap_urb_complete_list); + spin_lock_init(&wrap_urb_complete_list_lock); + initialize_work(&wrap_urb_complete_work, wrap_urb_complete_worker, NULL); +#ifdef USB_DEBUG + urb_id = 0; +#endif + return 0; +} + +void usb_exit(void) +{ + USBEXIT(return); +} + +int usb_init_device(struct wrap_device *wd) +{ + InitializeListHead(&wd->usb.wrap_urb_list); + wd->usb.num_alloc_urbs = 0; + USBEXIT(return 0); +} + +void usb_exit_device(struct wrap_device *wd) +{ + kill_all_urbs(wd, 0); + USBEXIT(return); +} --- linux-2.6.27.orig/ubuntu/ndiswrapper/pnp.h +++ linux-2.6.27/ubuntu/ndiswrapper/pnp.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2005 Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _PNP_H_ +#define _PNP_H_ + +#include "ntoskernel.h" +#include "ndis.h" +#include "wrapndis.h" + +NTSTATUS pnp_start_device(struct wrap_device *wd); +NTSTATUS pnp_stop_device(struct wrap_device *wd); +NTSTATUS pnp_remove_device(struct wrap_device *wd); + +int wrap_pnp_start_pci_device(struct pci_dev *pdev, + const struct pci_device_id *ent); +void __devexit wrap_pnp_remove_pci_device(struct pci_dev *pdev); +int wrap_pnp_suspend_pci_device(struct pci_dev *pdev, pm_message_t state); +int wrap_pnp_resume_pci_device(struct pci_dev *pdev); + +#ifdef ENABLE_USB +int wrap_pnp_start_usb_device(struct usb_interface *intf, + const struct usb_device_id *usb_id); +void wrap_pnp_remove_usb_device(struct usb_interface *intf); +int wrap_pnp_suspend_usb_device(struct usb_interface *intf, + pm_message_t state); +int wrap_pnp_resume_usb_device(struct usb_interface *intf); +#endif + +#endif --- linux-2.6.27.orig/ubuntu/ndiswrapper/ntoskernel.c +++ linux-2.6.27/ubuntu/ndiswrapper/ntoskernel.c @@ -0,0 +1,2677 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "ntoskernel.h" +#include "ndis.h" +#include "usb.h" +#include "pnp.h" +#include "loader.h" +#include "ntoskernel_exports.h" + +/* MDLs describe a range of virtual address with an array of physical + * pages right after the header. For different ranges of virtual + * addresses, the number of entries of physical pages may be different + * (depending on number of entries required). If we want to allocate + * MDLs from a pool, the size has to be constant. So we assume that + * maximum range used by a driver is MDL_CACHE_PAGES; if a driver + * requests an MDL for a bigger region, we allocate it with kmalloc; + * otherwise, we allocate from the pool */ + +#define MDL_CACHE_PAGES 3 +#define MDL_CACHE_SIZE (sizeof(struct mdl) + \ + (sizeof(PFN_NUMBER) * MDL_CACHE_PAGES)) +struct wrap_mdl { + struct nt_list list; + struct mdl mdl[0]; +}; + +/* everything here is for all drivers/devices - not per driver/device */ +static spinlock_t dispatcher_lock; +spinlock_t ntoskernel_lock; +static void *mdl_cache; +static struct nt_list wrap_mdl_list; + +static work_struct_t kdpc_work; +static void kdpc_worker(worker_param_t dummy); + +static struct nt_list kdpc_list; +static spinlock_t kdpc_list_lock; + +static struct nt_list callback_objects; + +struct nt_list object_list; + +struct bus_driver { + struct nt_list list; + char name[MAX_DRIVER_NAME_LEN]; + struct driver_object drv_obj; +}; + +static struct nt_list bus_driver_list; + +static work_struct_t ntos_work; +static struct nt_list ntos_work_list; +static spinlock_t ntos_work_lock; +static void ntos_work_worker(worker_param_t dummy); +static struct nt_thread *ntos_worker_thread; +spinlock_t irp_cancel_lock; +static NT_SPIN_LOCK nt_list_lock; +static struct nt_slist wrap_timer_slist; + +/* compute ticks (100ns) since 1601 until when system booted into + * wrap_ticks_to_boot */ +u64 wrap_ticks_to_boot; + +#if defined(CONFIG_X86_64) +static struct timer_list shared_data_timer; +struct kuser_shared_data kuser_shared_data; +static void update_user_shared_data_proc(unsigned long data); +#endif + +WIN_SYMBOL_MAP("KeTickCount", &jiffies) + +WIN_SYMBOL_MAP("NlsMbCodePageTag", FALSE) + +workqueue_struct_t *ntos_wq; + +#ifdef WRAP_PREEMPT +DEFINE_PER_CPU(irql_info_t, irql_info); +#endif + +#if defined(CONFIG_X86_64) +static void update_user_shared_data_proc(unsigned long data) +{ + /* timer is supposed to be scheduled every 10ms, but bigger + * intervals seem to work (tried upto 50ms) */ + *((ULONG64 *)&kuser_shared_data.system_time) = ticks_1601(); + *((ULONG64 *)&kuser_shared_data.interrupt_time) = + jiffies * TICKSPERSEC / HZ; + *((ULONG64 *)&kuser_shared_data.tick) = jiffies; + + mod_timer(&shared_data_timer, jiffies + MSEC_TO_HZ(30)); +} +#endif + +void *allocate_object(ULONG size, enum common_object_type type, + struct unicode_string *name) +{ + struct common_object_header *hdr; + void *body; + + /* we pad header as prefix to body */ + hdr = ExAllocatePoolWithTag(NonPagedPool, OBJECT_SIZE(size), 0); + if (!hdr) { + WARNING("couldn't allocate memory"); + return NULL; + } + memset(hdr, 0, OBJECT_SIZE(size)); + if (name) { + hdr->name.buf = ExAllocatePoolWithTag(NonPagedPool, + name->max_length, 0); + if (!hdr->name.buf) { + ExFreePool(hdr); + return NULL; + } + memcpy(hdr->name.buf, name->buf, name->max_length); + hdr->name.length = name->length; + hdr->name.max_length = name->max_length; + } + hdr->type = type; + hdr->ref_count = 1; + spin_lock_bh(&ntoskernel_lock); + /* threads are looked up often (in KeWaitForXXX), so optimize + * for fast lookups of threads */ + if (type == OBJECT_TYPE_NT_THREAD) + InsertHeadList(&object_list, &hdr->list); + else + InsertTailList(&object_list, &hdr->list); + spin_unlock_bh(&ntoskernel_lock); + body = HEADER_TO_OBJECT(hdr); + TRACE3("allocated hdr: %p, body: %p", hdr, body); + return body; +} + +void free_object(void *object) +{ + struct common_object_header *hdr; + + hdr = OBJECT_TO_HEADER(object); + spin_lock_bh(&ntoskernel_lock); + RemoveEntryList(&hdr->list); + spin_unlock_bh(&ntoskernel_lock); + TRACE3("freed hdr: %p, body: %p", hdr, object); + if (hdr->name.buf) + ExFreePool(hdr->name.buf); + ExFreePool(hdr); +} + +static int add_bus_driver(const char *name) +{ + struct bus_driver *bus_driver; + + bus_driver = kzalloc(sizeof(*bus_driver), GFP_KERNEL); + if (!bus_driver) { + ERROR("couldn't allocate memory"); + return -ENOMEM; + } + strncpy(bus_driver->name, name, sizeof(bus_driver->name)); + bus_driver->name[sizeof(bus_driver->name)-1] = 0; + spin_lock_bh(&ntoskernel_lock); + InsertTailList(&bus_driver_list, &bus_driver->list); + spin_unlock_bh(&ntoskernel_lock); + TRACE1("bus driver %s is at %p", name, &bus_driver->drv_obj); + return STATUS_SUCCESS; +} + +struct driver_object *find_bus_driver(const char *name) +{ + struct bus_driver *bus_driver; + struct driver_object *drv_obj; + + spin_lock_bh(&ntoskernel_lock); + drv_obj = NULL; + nt_list_for_each_entry(bus_driver, &bus_driver_list, list) { + if (strcmp(bus_driver->name, name) == 0) { + drv_obj = &bus_driver->drv_obj; + break; + } + } + spin_unlock_bh(&ntoskernel_lock); + return drv_obj; +} + +wfastcall struct nt_list *WIN_FUNC(ExfInterlockedInsertHeadList,3) + (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock) +{ + struct nt_list *first; + unsigned long flags; + + ENTER5("head = %p, entry = %p", head, entry); + nt_spin_lock_irqsave(lock, flags); + first = InsertHeadList(head, entry); + nt_spin_unlock_irqrestore(lock, flags); + TRACE5("head = %p, old = %p", head, first); + return first; +} + +wfastcall struct nt_list *WIN_FUNC(ExInterlockedInsertHeadList,3) + (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock) +{ + ENTER5("%p", head); + return ExfInterlockedInsertHeadList(head, entry, lock); +} + +wfastcall struct nt_list *WIN_FUNC(ExfInterlockedInsertTailList,3) + (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock) +{ + struct nt_list *last; + unsigned long flags; + + ENTER5("head = %p, entry = %p", head, entry); + nt_spin_lock_irqsave(lock, flags); + last = InsertTailList(head, entry); + nt_spin_unlock_irqrestore(lock, flags); + TRACE5("head = %p, old = %p", head, last); + return last; +} + +wfastcall struct nt_list *WIN_FUNC(ExInterlockedInsertTailList,3) + (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock) +{ + ENTER5("%p", head); + return ExfInterlockedInsertTailList(head, entry, lock); +} + +wfastcall struct nt_list *WIN_FUNC(ExfInterlockedRemoveHeadList,2) + (struct nt_list *head, NT_SPIN_LOCK *lock) +{ + struct nt_list *ret; + unsigned long flags; + + ENTER5("head = %p", head); + nt_spin_lock_irqsave(lock, flags); + ret = RemoveHeadList(head); + nt_spin_unlock_irqrestore(lock, flags); + TRACE5("head = %p, ret = %p", head, ret); + return ret; +} + +wfastcall struct nt_list *WIN_FUNC(ExInterlockedRemoveHeadList,2) + (struct nt_list *head, NT_SPIN_LOCK *lock) +{ + ENTER5("%p", head); + return ExfInterlockedRemoveHeadList(head, lock); +} + +wfastcall struct nt_list *WIN_FUNC(ExfInterlockedRemoveTailList,2) + (struct nt_list *head, NT_SPIN_LOCK *lock) +{ + struct nt_list *ret; + unsigned long flags; + + ENTER5("head = %p", head); + nt_spin_lock_irqsave(lock, flags); + ret = RemoveTailList(head); + nt_spin_unlock_irqrestore(lock, flags); + TRACE5("head = %p, ret = %p", head, ret); + return ret; +} + +wfastcall struct nt_list *WIN_FUNC(ExInterlockedRemoveTailList,2) + (struct nt_list *head, NT_SPIN_LOCK *lock) +{ + ENTER5("%p", head); + return ExfInterlockedRemoveTailList(head, lock); +} + +wfastcall void WIN_FUNC(InitializeSListHead,1) + (nt_slist_header *head) +{ + memset(head, 0, sizeof(*head)); +} + +wfastcall struct nt_slist *WIN_FUNC(ExInterlockedPushEntrySList,3) + (nt_slist_header *head, struct nt_slist *entry, NT_SPIN_LOCK *lock) +{ + struct nt_slist *ret; + + ret = PushEntrySList(head, entry, lock); + return ret; +} + +wstdcall struct nt_slist *WIN_FUNC(ExpInterlockedPushEntrySList,2) + (nt_slist_header *head, struct nt_slist *entry) +{ + struct nt_slist *ret; + + ret = PushEntrySList(head, entry, &nt_list_lock); + return ret; +} + +wfastcall struct nt_slist *WIN_FUNC(InterlockedPushEntrySList,2) + (nt_slist_header *head, struct nt_slist *entry) +{ + struct nt_slist *ret; + + ret = PushEntrySList(head, entry, &nt_list_lock); + return ret; +} + +wfastcall struct nt_slist *WIN_FUNC(ExInterlockedPopEntrySList,2) + (nt_slist_header *head, NT_SPIN_LOCK *lock) +{ + struct nt_slist *ret; + + ret = PopEntrySList(head, lock); + return ret; +} + +wstdcall struct nt_slist *WIN_FUNC(ExpInterlockedPopEntrySList,1) + (nt_slist_header *head) +{ + struct nt_slist *ret; + + ret = PopEntrySList(head, &nt_list_lock); + return ret; +} + +wfastcall struct nt_slist *WIN_FUNC(InterlockedPopEntrySList,1) + (nt_slist_header *head) +{ + struct nt_slist *ret; + + ret = PopEntrySList(head, &nt_list_lock); + return ret; +} + +wstdcall USHORT WIN_FUNC(ExQueryDepthSList,1) + (nt_slist_header *head) +{ + USHORT depth; + ENTER5("%p", head); + depth = head->depth; + TRACE5("%d, %p", depth, head->next); + return depth; +} + +wfastcall LONG WIN_FUNC(InterlockedIncrement,1) + (LONG volatile *val) +{ + return post_atomic_add(*val, 1); +} + +wfastcall LONG WIN_FUNC(InterlockedDecrement,1) + (LONG volatile *val) +{ + return post_atomic_add(*val, -1); +} + +wfastcall LONG WIN_FUNC(InterlockedExchange,2) + (LONG volatile *target, LONG val) +{ + return xchg(target, val); +} + +wfastcall LONG WIN_FUNC(InterlockedCompareExchange,3) + (LONG volatile *dest, LONG new, LONG old) +{ + return cmpxchg(dest, old, new); +} + +wfastcall void WIN_FUNC(ExInterlockedAddLargeStatistic,2) + (LARGE_INTEGER volatile *plint, ULONG n) +{ + unsigned long flags; + + local_irq_save(flags); +#ifdef CONFIG_X86_64 + __asm__ __volatile__( + "\n" + LOCK_PREFIX "add %1, %0\n\t" + : "+m" (*plint) + : "r" (n)); +#else + __asm__ __volatile__( + "1:\t" + " movl %1, %%ebx\n\t" + " movl %%edx, %%ecx\n\t" + " addl %%eax, %%ebx\n\t" + " adcl $0, %%ecx\n\t" + LOCK_PREFIX "cmpxchg8b %0\n\t" + " jnz 1b\n\t" + : "+m" (*plint) + : "m" (n), "A" (*plint) + : "ebx", "ecx"); +#endif + local_irq_restore(flags); +} + +static void initialize_object(struct dispatcher_header *dh, enum dh_type type, + int state) +{ + memset(dh, 0, sizeof(*dh)); + set_object_type(dh, type); + dh->signal_state = state; + InitializeListHead(&dh->wait_blocks); +} + +static void timer_proc(unsigned long data) +{ + struct wrap_timer *wrap_timer = (struct wrap_timer *)data; + struct nt_timer *nt_timer; + struct kdpc *kdpc; + + nt_timer = wrap_timer->nt_timer; + TIMERENTER("%p(%p), %lu", wrap_timer, nt_timer, jiffies); +#ifdef TIMER_DEBUG + BUG_ON(wrap_timer->wrap_timer_magic != WRAP_TIMER_MAGIC); + BUG_ON(nt_timer->wrap_timer_magic != WRAP_TIMER_MAGIC); +#endif + kdpc = nt_timer->kdpc; + if (kdpc) + queue_kdpc(kdpc); + KeSetEvent((struct nt_event *)nt_timer, 0, FALSE); + if (wrap_timer->repeat) + mod_timer(&wrap_timer->timer, jiffies + wrap_timer->repeat); + TIMEREXIT(return); +} + +void wrap_init_timer(struct nt_timer *nt_timer, enum timer_type type, + struct ndis_mp_block *nmb) +{ + struct wrap_timer *wrap_timer; + + /* TODO: if a timer is initialized more than once, we allocate + * memory for wrap_timer more than once for the same nt_timer, + * wasting memory. We can check if nt_timer->wrap_timer_magic is + * set and not allocate, but it is not guaranteed always to be + * safe */ + TIMERENTER("%p", nt_timer); + /* we allocate memory for wrap_timer behind driver's back and + * there is no NDIS/DDK function where this memory can be + * freed, so we use slack_kmalloc so it gets freed when driver + * is unloaded */ + if (nmb) + wrap_timer = kmalloc(sizeof(*wrap_timer), irql_gfp()); + else + wrap_timer = slack_kmalloc(sizeof(*wrap_timer)); + if (!wrap_timer) { + ERROR("couldn't allocate memory for timer"); + return; + } + + memset(wrap_timer, 0, sizeof(*wrap_timer)); + init_timer(&wrap_timer->timer); + wrap_timer->timer.data = (unsigned long)wrap_timer; + wrap_timer->timer.function = timer_proc; + wrap_timer->nt_timer = nt_timer; +#ifdef TIMER_DEBUG + wrap_timer->wrap_timer_magic = WRAP_TIMER_MAGIC; +#endif + nt_timer->wrap_timer = wrap_timer; + nt_timer->kdpc = NULL; + initialize_object(&nt_timer->dh, type, 0); + nt_timer->wrap_timer_magic = WRAP_TIMER_MAGIC; + TIMERTRACE("timer %p (%p)", wrap_timer, nt_timer); + spin_lock_bh(&ntoskernel_lock); + if (nmb) { + wrap_timer->slist.next = nmb->wnd->wrap_timer_slist.next; + nmb->wnd->wrap_timer_slist.next = &wrap_timer->slist; + } else { + wrap_timer->slist.next = wrap_timer_slist.next; + wrap_timer_slist.next = &wrap_timer->slist; + } + spin_unlock_bh(&ntoskernel_lock); + TIMEREXIT(return); +} + +wstdcall void WIN_FUNC(KeInitializeTimerEx,2) + (struct nt_timer *nt_timer, enum timer_type type) +{ + TIMERENTER("%p", nt_timer); + wrap_init_timer(nt_timer, type, NULL); +} + +wstdcall void WIN_FUNC(KeInitializeTimer,1) + (struct nt_timer *nt_timer) +{ + TIMERENTER("%p", nt_timer); + wrap_init_timer(nt_timer, NotificationTimer, NULL); +} + +/* expires and repeat are in HZ */ +BOOLEAN wrap_set_timer(struct nt_timer *nt_timer, unsigned long expires_hz, + unsigned long repeat_hz, struct kdpc *kdpc) +{ + struct wrap_timer *wrap_timer; + + TIMERENTER("%p, %lu, %lu, %p, %lu", + nt_timer, expires_hz, repeat_hz, kdpc, jiffies); + + wrap_timer = nt_timer->wrap_timer; + TIMERTRACE("%p", wrap_timer); +#ifdef TIMER_DEBUG + if (wrap_timer->nt_timer != nt_timer) + WARNING("bad timers: %p, %p, %p", wrap_timer, nt_timer, + wrap_timer->nt_timer); + if (nt_timer->wrap_timer_magic != WRAP_TIMER_MAGIC) { + WARNING("buggy Windows timer didn't initialize timer %p", + nt_timer); + return FALSE; + } + if (wrap_timer->wrap_timer_magic != WRAP_TIMER_MAGIC) { + WARNING("timer %p is not initialized (%lx)?", + wrap_timer, wrap_timer->wrap_timer_magic); + wrap_timer->wrap_timer_magic = WRAP_TIMER_MAGIC; + } +#endif + KeClearEvent((struct nt_event *)nt_timer); + nt_timer->kdpc = kdpc; + wrap_timer->repeat = repeat_hz; + if (mod_timer(&wrap_timer->timer, jiffies + expires_hz)) + TIMEREXIT(return TRUE); + else + TIMEREXIT(return FALSE); +} + +wstdcall BOOLEAN WIN_FUNC(KeSetTimerEx,4) + (struct nt_timer *nt_timer, LARGE_INTEGER duetime_ticks, + LONG period_ms, struct kdpc *kdpc) +{ + unsigned long expires_hz, repeat_hz; + + TIMERENTER("%p, %Ld, %d", nt_timer, duetime_ticks, period_ms); + expires_hz = SYSTEM_TIME_TO_HZ(duetime_ticks); + repeat_hz = MSEC_TO_HZ(period_ms); + return wrap_set_timer(nt_timer, expires_hz, repeat_hz, kdpc); +} + +wstdcall BOOLEAN WIN_FUNC(KeSetTimer,3) + (struct nt_timer *nt_timer, LARGE_INTEGER duetime_ticks, + struct kdpc *kdpc) +{ + TIMERENTER("%p, %Ld, %p", nt_timer, duetime_ticks, kdpc); + return KeSetTimerEx(nt_timer, duetime_ticks, 0, kdpc); +} + +wstdcall BOOLEAN WIN_FUNC(KeCancelTimer,1) + (struct nt_timer *nt_timer) +{ + struct wrap_timer *wrap_timer; + int ret; + + TIMERENTER("%p", nt_timer); + wrap_timer = nt_timer->wrap_timer; + if (!wrap_timer) { + ERROR("invalid wrap_timer"); + return TRUE; + } +#ifdef TIMER_DEBUG + BUG_ON(wrap_timer->wrap_timer_magic != WRAP_TIMER_MAGIC); +#endif + TIMERTRACE("canceling timer %p(%p)", wrap_timer, nt_timer); + /* disable timer before deleting so if it is periodic timer, it + * won't be re-armed after deleting */ + wrap_timer->repeat = 0; + ret = del_timer(&wrap_timer->timer); + /* the documentation for KeCancelTimer suggests the DPC is + * deqeued, but actually DPC is left to run */ + if (ret) + TIMEREXIT(return TRUE); + else + TIMEREXIT(return FALSE); +} + +wstdcall BOOLEAN WIN_FUNC(KeReadStateTimer,1) + (struct nt_timer *nt_timer) +{ + if (nt_timer->dh.signal_state) + return TRUE; + else + return FALSE; +} + +wstdcall void WIN_FUNC(KeInitializeDpc,3) + (struct kdpc *kdpc, void *func, void *ctx) +{ + ENTER3("%p, %p, %p", kdpc, func, ctx); + memset(kdpc, 0, sizeof(*kdpc)); + kdpc->func = func; + kdpc->ctx = ctx; + InitializeListHead(&kdpc->list); +} + +static void kdpc_worker(worker_param_t dummy) +{ + struct nt_list *entry; + struct kdpc *kdpc; + unsigned long flags; + KIRQL irql; + + WORKENTER(""); + irql = raise_irql(DISPATCH_LEVEL); + while (1) { + spin_lock_irqsave(&kdpc_list_lock, flags); + entry = RemoveHeadList(&kdpc_list); + if (entry) { + kdpc = container_of(entry, struct kdpc, list); + assert(kdpc->queued); + kdpc->queued = 0; + } else + kdpc = NULL; + spin_unlock_irqrestore(&kdpc_list_lock, flags); + if (!kdpc) + break; + WORKTRACE("%p, %p, %p, %p, %p", kdpc, kdpc->func, kdpc->ctx, + kdpc->arg1, kdpc->arg2); + assert_irql(_irql_ == DISPATCH_LEVEL); + LIN2WIN4(kdpc->func, kdpc, kdpc->ctx, kdpc->arg1, kdpc->arg2); + assert_irql(_irql_ == DISPATCH_LEVEL); + } + lower_irql(irql); + WORKEXIT(return); +} + +wstdcall void WIN_FUNC(KeFlushQueuedDpcs,0) + (void) +{ + kdpc_worker(NULL); +} + +BOOLEAN queue_kdpc(struct kdpc *kdpc) +{ + BOOLEAN ret; + unsigned long flags; + + WORKENTER("%p", kdpc); + spin_lock_irqsave(&kdpc_list_lock, flags); + if (kdpc->queued) + ret = FALSE; + else { + if (unlikely(kdpc->importance == HighImportance)) + InsertHeadList(&kdpc_list, &kdpc->list); + else + InsertTailList(&kdpc_list, &kdpc->list); + kdpc->queued = 1; + ret = TRUE; + } + spin_unlock_irqrestore(&kdpc_list_lock, flags); + if (ret == TRUE) + schedule_ntos_work(&kdpc_work); + WORKTRACE("%d", ret); + return ret; +} + +BOOLEAN dequeue_kdpc(struct kdpc *kdpc) +{ + BOOLEAN ret; + unsigned long flags; + + WORKENTER("%p", kdpc); + spin_lock_irqsave(&kdpc_list_lock, flags); + if (kdpc->queued) { + RemoveEntryList(&kdpc->list); + kdpc->queued = 0; + ret = TRUE; + } else + ret = FALSE; + spin_unlock_irqrestore(&kdpc_list_lock, flags); + WORKTRACE("%d", ret); + return ret; +} + +wstdcall BOOLEAN WIN_FUNC(KeInsertQueueDpc,3) + (struct kdpc *kdpc, void *arg1, void *arg2) +{ + WORKENTER("%p, %p, %p", kdpc, arg1, arg2); + kdpc->arg1 = arg1; + kdpc->arg2 = arg2; + return queue_kdpc(kdpc); +} + +wstdcall BOOLEAN WIN_FUNC(KeRemoveQueueDpc,1) + (struct kdpc *kdpc) +{ + return dequeue_kdpc(kdpc); +} + +wstdcall void WIN_FUNC(KeSetImportanceDpc,2) + (struct kdpc *kdpc, enum kdpc_importance importance) +{ + kdpc->importance = importance; +} + +static void ntos_work_worker(worker_param_t dummy) +{ + struct ntos_work_item *ntos_work_item; + struct nt_list *cur; + + while (1) { + spin_lock_bh(&ntos_work_lock); + cur = RemoveHeadList(&ntos_work_list); + spin_unlock_bh(&ntos_work_lock); + if (!cur) + break; + ntos_work_item = container_of(cur, struct ntos_work_item, list); + WORKTRACE("%p: executing %p, %p, %p", current, + ntos_work_item->func, ntos_work_item->arg1, + ntos_work_item->arg2); + LIN2WIN2(ntos_work_item->func, ntos_work_item->arg1, + ntos_work_item->arg2); + kfree(ntos_work_item); + } + WORKEXIT(return); +} + +int schedule_ntos_work_item(NTOS_WORK_FUNC func, void *arg1, void *arg2) +{ + struct ntos_work_item *ntos_work_item; + + WORKENTER("adding work: %p, %p, %p", func, arg1, arg2); + ntos_work_item = kmalloc(sizeof(*ntos_work_item), irql_gfp()); + if (!ntos_work_item) { + ERROR("couldn't allocate memory"); + return -ENOMEM; + } + ntos_work_item->func = func; + ntos_work_item->arg1 = arg1; + ntos_work_item->arg2 = arg2; + spin_lock_bh(&ntos_work_lock); + InsertTailList(&ntos_work_list, &ntos_work_item->list); + spin_unlock_bh(&ntos_work_lock); + schedule_ntos_work(&ntos_work); + WORKEXIT(return 0); +} + +wstdcall void WIN_FUNC(KeInitializeSpinLock,1) + (NT_SPIN_LOCK *lock) +{ + ENTER6("%p", lock); + nt_spin_lock_init(lock); +} + +wstdcall void WIN_FUNC(KeAcquireSpinLock,2) + (NT_SPIN_LOCK *lock, KIRQL *irql) +{ + ENTER6("%p", lock); + *irql = nt_spin_lock_irql(lock, DISPATCH_LEVEL); +} + +wstdcall void WIN_FUNC(KeReleaseSpinLock,2) + (NT_SPIN_LOCK *lock, KIRQL oldirql) +{ + ENTER6("%p", lock); + nt_spin_unlock_irql(lock, oldirql); +} + +wstdcall void WIN_FUNC(KeAcquireSpinLockAtDpcLevel,1) + (NT_SPIN_LOCK *lock) +{ + ENTER6("%p", lock); + nt_spin_lock(lock); +} + +wstdcall void WIN_FUNC(KeReleaseSpinLockFromDpcLevel,1) + (NT_SPIN_LOCK *lock) +{ + ENTER6("%p", lock); + nt_spin_unlock(lock); +} + +wstdcall void WIN_FUNC(KeRaiseIrql,2) + (KIRQL newirql, KIRQL *oldirql) +{ + ENTER6("%d", newirql); + *oldirql = raise_irql(newirql); +} + +wstdcall KIRQL WIN_FUNC(KeRaiseIrqlToDpcLevel,0) + (void) +{ + return raise_irql(DISPATCH_LEVEL); +} + +wstdcall void WIN_FUNC(KeLowerIrql,1) + (KIRQL irql) +{ + ENTER6("%d", irql); + lower_irql(irql); +} + +wstdcall KIRQL WIN_FUNC(KeAcquireSpinLockRaiseToDpc,1) + (NT_SPIN_LOCK *lock) +{ + ENTER6("%p", lock); + return nt_spin_lock_irql(lock, DISPATCH_LEVEL); +} + +#undef ExAllocatePoolWithTag + +wstdcall void *WIN_FUNC(ExAllocatePoolWithTag,3) + (enum pool_type pool_type, SIZE_T size, ULONG tag) +{ + void *addr; + + ENTER4("pool_type: %d, size: %lu, tag: 0x%x", pool_type, size, tag); + assert_irql(_irql_ <= DISPATCH_LEVEL); + if (size < PAGE_SIZE) + addr = kmalloc(size, irql_gfp()); + else { + if (irql_gfp() & GFP_ATOMIC) { + addr = __vmalloc(size, GFP_ATOMIC | __GFP_HIGHMEM, + PAGE_KERNEL); + TRACE1("%p, %lu", addr, size); + } else { + addr = vmalloc(size); + TRACE1("%p, %lu", addr, size); + } + } + DBG_BLOCK(1) { + if (addr) + TRACE4("addr: %p, %lu", addr, size); + else + TRACE1("failed: %lu", size); + } + return addr; +} +WIN_FUNC_DECL(ExAllocatePoolWithTag,3) + +wstdcall void WIN_FUNC(ExFreePoolWithTag,2) + (void *addr, ULONG tag) +{ + TRACE4("%p", addr); + if ((unsigned long)addr < VMALLOC_START || + (unsigned long)addr >= VMALLOC_END) + kfree(addr); + else + vfree(addr); + + EXIT4(return); +} + +wstdcall void WIN_FUNC(ExFreePool,1) + (void *addr) +{ + ExFreePoolWithTag(addr, 0); +} +WIN_FUNC_DECL(ExFreePool,1) + +wstdcall void WIN_FUNC(ExInitializeNPagedLookasideList,7) + (struct npaged_lookaside_list *lookaside, + LOOKASIDE_ALLOC_FUNC *alloc_func, LOOKASIDE_FREE_FUNC *free_func, + ULONG flags, SIZE_T size, ULONG tag, USHORT depth) +{ + ENTER3("lookaside: %p, size: %lu, flags: %u, head: %p, " + "alloc: %p, free: %p", lookaside, size, flags, + lookaside, alloc_func, free_func); + + memset(lookaside, 0, sizeof(*lookaside)); + + lookaside->size = size; + lookaside->tag = tag; + lookaside->depth = 4; + lookaside->maxdepth = 256; + lookaside->pool_type = NonPagedPool; + + if (alloc_func) + lookaside->alloc_func = alloc_func; + else + lookaside->alloc_func = WIN_FUNC_PTR(ExAllocatePoolWithTag,3); + if (free_func) + lookaside->free_func = free_func; + else + lookaside->free_func = WIN_FUNC_PTR(ExFreePool,1); + +#ifndef CONFIG_X86_64 + nt_spin_lock_init(&lookaside->obsolete); +#endif + EXIT3(return); +} + +wstdcall void WIN_FUNC(ExDeleteNPagedLookasideList,1) + (struct npaged_lookaside_list *lookaside) +{ + struct nt_slist *entry; + + ENTER3("lookaside = %p", lookaside); + while ((entry = ExpInterlockedPopEntrySList(&lookaside->head))) + LIN2WIN1(lookaside->free_func, entry); + EXIT3(return); +} + +#if defined(ALLOC_DEBUG) && ALLOC_DEBUG > 1 +#define ExAllocatePoolWithTag(pool_type, size, tag) \ + wrap_ExAllocatePoolWithTag(pool_type, size, tag, __FILE__, __LINE__) +#endif + +wstdcall NTSTATUS WIN_FUNC(ExCreateCallback,4) + (struct callback_object **object, struct object_attributes *attributes, + BOOLEAN create, BOOLEAN allow_multiple_callbacks) +{ + struct callback_object *obj; + + ENTER2(""); + spin_lock_bh(&ntoskernel_lock); + nt_list_for_each_entry(obj, &callback_objects, callback_funcs) { + if (obj->attributes == attributes) { + spin_unlock_bh(&ntoskernel_lock); + *object = obj; + return STATUS_SUCCESS; + } + } + spin_unlock_bh(&ntoskernel_lock); + obj = allocate_object(sizeof(struct callback_object), + OBJECT_TYPE_CALLBACK, NULL); + if (!obj) + EXIT2(return STATUS_INSUFFICIENT_RESOURCES); + InitializeListHead(&obj->callback_funcs); + nt_spin_lock_init(&obj->lock); + obj->allow_multiple_callbacks = allow_multiple_callbacks; + obj->attributes = attributes; + *object = obj; + EXIT2(return STATUS_SUCCESS); +} + +wstdcall void *WIN_FUNC(ExRegisterCallback,3) + (struct callback_object *object, PCALLBACK_FUNCTION func, void *context) +{ + struct callback_func *callback; + KIRQL irql; + + ENTER2(""); + irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL); + if (object->allow_multiple_callbacks == FALSE && + !IsListEmpty(&object->callback_funcs)) { + nt_spin_unlock_irql(&object->lock, irql); + EXIT2(return NULL); + } + nt_spin_unlock_irql(&object->lock, irql); + callback = kmalloc(sizeof(*callback), GFP_KERNEL); + if (!callback) { + ERROR("couldn't allocate memory"); + return NULL; + } + callback->func = func; + callback->context = context; + callback->object = object; + irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL); + InsertTailList(&object->callback_funcs, &callback->list); + nt_spin_unlock_irql(&object->lock, irql); + EXIT2(return callback); +} + +wstdcall void WIN_FUNC(ExUnregisterCallback,1) + (struct callback_func *callback) +{ + struct callback_object *object; + KIRQL irql; + + ENTER3("%p", callback); + if (!callback) + return; + object = callback->object; + irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL); + RemoveEntryList(&callback->list); + nt_spin_unlock_irql(&object->lock, irql); + kfree(callback); + return; +} + +wstdcall void WIN_FUNC(ExNotifyCallback,3) + (struct callback_object *object, void *arg1, void *arg2) +{ + struct callback_func *callback; + KIRQL irql; + + ENTER3("%p", object); + irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL); + nt_list_for_each_entry(callback, &object->callback_funcs, list) { + LIN2WIN3(callback->func, callback->context, arg1, arg2); + } + nt_spin_unlock_irql(&object->lock, irql); + return; +} + +/* check and set signaled state; should be called with dispatcher_lock held */ +/* @grab indicates if the event should be grabbed or checked + * - note that a semaphore may stay in signaled state for multiple + * 'grabs' if the count is > 1 */ +static int grab_object(struct dispatcher_header *dh, + struct task_struct *thread, int grab) +{ + EVENTTRACE("%p, %p, %d, %d", dh, thread, grab, dh->signal_state); + if (unlikely(is_mutex_object(dh))) { + struct nt_mutex *nt_mutex; + nt_mutex = container_of(dh, struct nt_mutex, dh); + EVENTTRACE("%p, %p, %d, %p, %d", nt_mutex, + nt_mutex->owner_thread, dh->signal_state, + thread, grab); + /* either no thread owns the mutex or this thread owns + * it */ + assert(dh->signal_state == 1 && nt_mutex->owner_thread == NULL); + assert(dh->signal_state < 1 && nt_mutex->owner_thread != NULL); + if ((dh->signal_state == 1 && nt_mutex->owner_thread == NULL) || + nt_mutex->owner_thread == thread) { + if (grab) { + dh->signal_state--; + nt_mutex->owner_thread = thread; + } + EVENTEXIT(return 1); + } + } else if (dh->signal_state > 0) { + /* to grab, decrement signal_state for synchronization + * or semaphore objects */ + if (grab && (is_synch_object(dh) || is_semaphore_object(dh))) + dh->signal_state--; + EVENTEXIT(return 1); + } + EVENTEXIT(return 0); +} + +/* this function should be called holding dispatcher_lock */ +static void object_signalled(struct dispatcher_header *dh) +{ + struct nt_list *cur, *next; + struct wait_block *wb; + + EVENTENTER("%p", dh); + nt_list_for_each_safe(cur, next, &dh->wait_blocks) { + wb = container_of(cur, struct wait_block, list); + assert(wb->thread != NULL); + assert(wb->object == NULL); + if (!grab_object(dh, wb->thread, 1)) + continue; + EVENTTRACE("%p (%p): waking %p", dh, wb, wb->thread); + RemoveEntryList(cur); + wb->object = dh; + *(wb->wait_done) = 1; + wake_up_process(wb->thread); + } + EVENTEXIT(return); +} + +wstdcall NTSTATUS WIN_FUNC(KeWaitForMultipleObjects,8) + (ULONG count, void *object[], enum wait_type wait_type, + KWAIT_REASON wait_reason, KPROCESSOR_MODE wait_mode, + BOOLEAN alertable, LARGE_INTEGER *timeout, + struct wait_block *wait_block_array) +{ + int i, res = 0, wait_count, wait_done; + typeof(jiffies) wait_hz = 0; + struct wait_block *wb, wb_array[THREAD_WAIT_OBJECTS]; + struct dispatcher_header *dh; + + EVENTENTER("%p, %d, %u, %p", current, count, wait_type, timeout); + + if (count > MAX_WAIT_OBJECTS || + (count > THREAD_WAIT_OBJECTS && wait_block_array == NULL)) + EVENTEXIT(return STATUS_INVALID_PARAMETER); + + if (wait_block_array == NULL) + wb = wb_array; + else + wb = wait_block_array; + + /* If *timeout == 0: In the case of WaitAny, if an object can + * be grabbed (object is in signaled state), grab and + * return. In the case of WaitAll, we have to first make sure + * all objects can be grabbed. If any/some of them can't be + * grabbed, either we return STATUS_TIMEOUT or wait for them, + * depending on how to satisfy wait. If all of them can be + * grabbed, we will grab them in the next loop below */ + + spin_lock_bh(&dispatcher_lock); + for (i = wait_count = 0; i < count; i++) { + dh = object[i]; + EVENTTRACE("%p: event %p (%d)", current, dh, dh->signal_state); + /* wait_type == 1 for WaitAny, 0 for WaitAll */ + if (grab_object(dh, current, wait_type)) { + if (wait_type == WaitAny) { + spin_unlock_bh(&dispatcher_lock); + EVENTEXIT(return STATUS_WAIT_0 + i); + } + } else { + EVENTTRACE("%p: wait for %p", current, dh); + wait_count++; + } + } + + if (timeout && *timeout == 0 && wait_count) { + spin_unlock_bh(&dispatcher_lock); + EVENTEXIT(return STATUS_TIMEOUT); + } + + /* get the list of objects the thread needs to wait on and add + * the thread on the wait list for each such object */ + /* if *timeout == 0, this step will grab all the objects */ + wait_done = 0; + for (i = 0; i < count; i++) { + dh = object[i]; + EVENTTRACE("%p: event %p (%d)", current, dh, dh->signal_state); + wb[i].object = NULL; + if (grab_object(dh, current, 1)) { + EVENTTRACE("%p: no wait for %p (%d)", + current, dh, dh->signal_state); + /* mark that we are not waiting on this object */ + wb[i].thread = NULL; + } else { + wb[i].wait_done = &wait_done; + wb[i].thread = current; + EVENTTRACE("%p: wait for %p", current, dh); + InsertTailList(&dh->wait_blocks, &wb[i].list); + } + } + spin_unlock_bh(&dispatcher_lock); + if (wait_count == 0) + EVENTEXIT(return STATUS_SUCCESS); + + assert(timeout == NULL || *timeout != 0); + if (timeout == NULL) + wait_hz = 0; + else + wait_hz = SYSTEM_TIME_TO_HZ(*timeout); + + DBG_BLOCK(2) { + KIRQL irql = current_irql(); + if (irql >= DISPATCH_LEVEL) { + TRACE2("wait in atomic context: %lu, %d, %ld", + wait_hz, in_atomic(), in_interrupt()); + } + } + assert_irql(_irql_ < DISPATCH_LEVEL); + EVENTTRACE("%p: sleep for %ld on %p", current, wait_hz, &wait_done); + /* we don't honor 'alertable' - according to decription for + * this, even if waiting in non-alertable state, thread may be + * alerted in some circumstances */ + while (wait_count) { + res = wait_condition(wait_done, wait_hz, TASK_INTERRUPTIBLE); + spin_lock_bh(&dispatcher_lock); + EVENTTRACE("%p woke up: %d, %d", current, res, wait_done); + /* the event may have been set by the time + * wrap_wait_event returned and spinlock obtained, so + * don't rely on value of 'res' - check event status */ + if (!wait_done) { + assert(res <= 0); + /* timed out or interrupted; remove from wait list */ + for (i = 0; i < count; i++) { + if (!wb[i].thread) + continue; + EVENTTRACE("%p: timedout, dequeue %p (%p)", + current, object[i], wb[i].object); + assert(wb[i].object == NULL); + RemoveEntryList(&wb[i].list); + } + spin_unlock_bh(&dispatcher_lock); + if (res < 0) + EVENTEXIT(return STATUS_ALERTED); + else + EVENTEXIT(return STATUS_TIMEOUT); + } + assert(res > 0); + /* woken because object(s) signalled */ + for (i = 0; wait_count && i < count; i++) { + if (!wb[i].thread || !wb[i].object) + continue; + DBG_BLOCK(1) { + if (wb[i].object != object[i]) { + EVENTTRACE("oops %p != %p", + wb[i].object, object[i]); + continue; + } + } + wait_count--; + if (wait_type == WaitAny) { + int j; + /* done; remove from rest of wait list */ + for (j = i + 1; j < count; j++) { + if (wb[j].thread && !wb[j].object) + RemoveEntryList(&wb[j].list); + } + spin_unlock_bh(&dispatcher_lock); + EVENTEXIT(return STATUS_WAIT_0 + i); + } + } + wait_done = 0; + spin_unlock_bh(&dispatcher_lock); + if (wait_count == 0) + EVENTEXIT(return STATUS_SUCCESS); + + /* this thread is still waiting for more objects, so + * let it wait for remaining time and those objects */ + if (timeout) + wait_hz = res; + else + wait_hz = 0; + } + /* should never reach here, but compiler wants return value */ + ERROR("%p: wait_hz: %ld", current, wait_hz); + EVENTEXIT(return STATUS_SUCCESS); +} + +wstdcall NTSTATUS WIN_FUNC(KeWaitForSingleObject,5) + (void *object, KWAIT_REASON wait_reason, KPROCESSOR_MODE wait_mode, + BOOLEAN alertable, LARGE_INTEGER *timeout) +{ + return KeWaitForMultipleObjects(1, &object, WaitAny, wait_reason, + wait_mode, alertable, timeout, NULL); +} + +wstdcall void WIN_FUNC(KeInitializeEvent,3) + (struct nt_event *nt_event, enum event_type type, BOOLEAN state) +{ + EVENTENTER("event = %p, type = %d, state = %d", nt_event, type, state); + initialize_object(&nt_event->dh, type, state); + EVENTEXIT(return); +} + +wstdcall LONG WIN_FUNC(KeSetEvent,3) + (struct nt_event *nt_event, KPRIORITY incr, BOOLEAN wait) +{ + LONG old_state; + + EVENTENTER("%p, %d", nt_event, nt_event->dh.type); + if (wait == TRUE) + WARNING("wait = %d, not yet implemented", wait); + spin_lock_bh(&dispatcher_lock); + old_state = nt_event->dh.signal_state; + nt_event->dh.signal_state = 1; + if (old_state == 0) + object_signalled(&nt_event->dh); + spin_unlock_bh(&dispatcher_lock); + EVENTEXIT(return old_state); +} + +wstdcall void WIN_FUNC(KeClearEvent,1) + (struct nt_event *nt_event) +{ + EVENTENTER("%p", nt_event); + nt_event->dh.signal_state = 0; + EVENTEXIT(return); +} + +wstdcall LONG WIN_FUNC(KeResetEvent,1) + (struct nt_event *nt_event) +{ + LONG old_state; + + EVENTENTER("%p", nt_event); + old_state = xchg(&nt_event->dh.signal_state, 0); + EVENTEXIT(return old_state); +} + +wstdcall LONG WIN_FUNC(KeReadStateEvent,1) + (struct nt_event *nt_event) +{ + LONG state; + + state = nt_event->dh.signal_state; + EVENTTRACE("%d", state); + return state; +} + +wstdcall void WIN_FUNC(KeInitializeMutex,2) + (struct nt_mutex *mutex, ULONG level) +{ + EVENTENTER("%p", mutex); + initialize_object(&mutex->dh, MutexObject, 1); + mutex->dh.size = sizeof(*mutex); + InitializeListHead(&mutex->list); + mutex->abandoned = FALSE; + mutex->apc_disable = 1; + mutex->owner_thread = NULL; + EVENTEXIT(return); +} + +wstdcall LONG WIN_FUNC(KeReleaseMutex,2) + (struct nt_mutex *mutex, BOOLEAN wait) +{ + LONG ret; + struct task_struct *thread; + + EVENTENTER("%p, %d, %p", mutex, wait, current); + if (wait == TRUE) + WARNING("wait: %d", wait); + thread = current; + spin_lock_bh(&dispatcher_lock); + EVENTTRACE("%p, %p, %p, %d", mutex, thread, mutex->owner_thread, + mutex->dh.signal_state); + if ((mutex->owner_thread == thread) && (mutex->dh.signal_state <= 0)) { + ret = mutex->dh.signal_state++; + if (ret == 0) { + mutex->owner_thread = NULL; + object_signalled(&mutex->dh); + } + } else { + ret = STATUS_MUTANT_NOT_OWNED; + WARNING("invalid mutex: %p, %p, %p", mutex, mutex->owner_thread, + thread); + } + EVENTTRACE("%p, %p, %p, %d", mutex, thread, mutex->owner_thread, + mutex->dh.signal_state); + spin_unlock_bh(&dispatcher_lock); + EVENTEXIT(return ret); +} + +wstdcall void WIN_FUNC(KeInitializeSemaphore,3) + (struct nt_semaphore *semaphore, LONG count, LONG limit) +{ + EVENTENTER("%p: %d", semaphore, count); + /* if limit > 1, we need to satisfy as many waits (until count + * becomes 0); so we keep decrementing count everytime a wait + * is satisified */ + initialize_object(&semaphore->dh, SemaphoreObject, count); + semaphore->dh.size = sizeof(*semaphore); + semaphore->limit = limit; + EVENTEXIT(return); +} + +wstdcall LONG WIN_FUNC(KeReleaseSemaphore,4) + (struct nt_semaphore *semaphore, KPRIORITY incr, LONG adjustment, + BOOLEAN wait) +{ + LONG ret; + + EVENTENTER("%p", semaphore); + spin_lock_bh(&dispatcher_lock); + ret = semaphore->dh.signal_state; + assert(ret >= 0); + if (semaphore->dh.signal_state + adjustment <= semaphore->limit) + semaphore->dh.signal_state += adjustment; + else { + WARNING("releasing %d over limit %d", adjustment, + semaphore->limit); + semaphore->dh.signal_state = semaphore->limit; + } + if (semaphore->dh.signal_state > 0) + object_signalled(&semaphore->dh); + spin_unlock_bh(&dispatcher_lock); + EVENTEXIT(return ret); +} + +wstdcall NTSTATUS WIN_FUNC(KeDelayExecutionThread,3) + (KPROCESSOR_MODE wait_mode, BOOLEAN alertable, LARGE_INTEGER *interval) +{ + int res; + long timeout; + + if (wait_mode != 0) + ERROR("invalid wait_mode %d", wait_mode); + + timeout = SYSTEM_TIME_TO_HZ(*interval); + EVENTTRACE("%p, %Ld, %ld", current, *interval, timeout); + if (timeout <= 0) + EVENTEXIT(return STATUS_SUCCESS); + + if (alertable) + set_current_state(TASK_INTERRUPTIBLE); + else + set_current_state(TASK_UNINTERRUPTIBLE); + + res = schedule_timeout(timeout); + EVENTTRACE("%p, %d", current, res); + if (res == 0) + EVENTEXIT(return STATUS_SUCCESS); + else + EVENTEXIT(return STATUS_ALERTED); +} + +wstdcall ULONGLONG WIN_FUNC(KeQueryInterruptTime,0) + (void) +{ + EXIT5(return jiffies * TICKSPERJIFFY); +} + +wstdcall ULONG WIN_FUNC(KeQueryTimeIncrement,0) + (void) +{ + EXIT5(return TICKSPERSEC / HZ); +} + +wstdcall void WIN_FUNC(KeQuerySystemTime,1) + (LARGE_INTEGER *time) +{ + *time = ticks_1601(); + TRACE5("%Lu, %lu", *time, jiffies); +} + +wstdcall void WIN_FUNC(KeQueryTickCount,1) + (LARGE_INTEGER *count) +{ + *count = jiffies; +} + +wstdcall LARGE_INTEGER WIN_FUNC(KeQueryPerformanceCounter,1) + (LARGE_INTEGER *counter) +{ + if (counter) + *counter = HZ; + return jiffies; +} + +wstdcall KAFFINITY WIN_FUNC(KeQueryActiveProcessors,0) + (void) +{ + int i, n; + KAFFINITY bits = 0; +#ifdef num_online_cpus + n = num_online_cpus(); +#else + n = NR_CPUS; +#endif + for (i = 0; i < n; i++) + bits = (bits << 1) | 1; + return bits; +} + +struct nt_thread *get_current_nt_thread(void) +{ + struct task_struct *task = current; + struct nt_thread *thread; + struct common_object_header *header; + + TRACE6("task: %p", task); + thread = NULL; + spin_lock_bh(&ntoskernel_lock); + nt_list_for_each_entry(header, &object_list, list) { + TRACE6("%p, %d", header, header->type); + if (header->type != OBJECT_TYPE_NT_THREAD) + break; + thread = HEADER_TO_OBJECT(header); + TRACE6("%p, %p", thread, thread->task); + if (thread->task == task) + break; + else + thread = NULL; + } + spin_unlock_bh(&ntoskernel_lock); + if (thread == NULL) + TRACE4("couldn't find thread for task %p, %d", task, task->pid); + TRACE6("%p", thread); + return thread; +} + +static struct task_struct *get_nt_thread_task(struct nt_thread *thread) +{ + struct task_struct *task; + struct common_object_header *header; + + TRACE6("%p", thread); + task = NULL; + spin_lock_bh(&ntoskernel_lock); + nt_list_for_each_entry(header, &object_list, list) { + TRACE6("%p, %d", header, header->type); + if (header->type != OBJECT_TYPE_NT_THREAD) + break; + if (thread == HEADER_TO_OBJECT(header)) { + task = thread->task; + break; + } + } + spin_unlock_bh(&ntoskernel_lock); + if (task == NULL) + TRACE2("%p: couldn't find task for %p", current, thread); + return task; +} + +static struct nt_thread *create_nt_thread(struct task_struct *task) +{ + struct nt_thread *thread; + thread = allocate_object(sizeof(*thread), OBJECT_TYPE_NT_THREAD, NULL); + if (!thread) { + ERROR("couldn't allocate thread object"); + EXIT2(return NULL); + } + thread->task = task; + if (task) + thread->pid = task->pid; + else + thread->pid = 0; + nt_spin_lock_init(&thread->lock); + InitializeListHead(&thread->irps); + initialize_object(&thread->dh, ThreadObject, 0); + thread->dh.size = sizeof(*thread); + thread->prio = LOW_PRIORITY; + return thread; +} + +wstdcall struct nt_thread *WIN_FUNC(KeGetCurrentThread,0) + (void) +{ + struct nt_thread *thread = get_current_nt_thread(); + TRACE2("%p, %p", thread, current); + return thread; +} + +wstdcall KPRIORITY WIN_FUNC(KeQueryPriorityThread,1) + (struct nt_thread *thread) +{ + KPRIORITY prio; + struct task_struct *task; + + TRACE2("%p", thread); +#ifdef CONFIG_X86_64 + /* sis163u driver for amd64 passes 0x1f from thread created by + * PsCreateSystemThread - no idea what is 0x1f */ + if (thread == (void *)0x1f) + thread = get_current_nt_thread(); +#endif + if (!thread) { + TRACE2("invalid thread"); + EXIT2(return LOW_REALTIME_PRIORITY); + } + task = get_nt_thread_task(thread); + if (!task) { + TRACE2("couldn't find task for thread: %p", thread); + EXIT2(return LOW_REALTIME_PRIORITY); + } + + prio = thread->prio; + + TRACE2("%d", prio); + return prio; +} + +wstdcall KPRIORITY WIN_FUNC(KeSetPriorityThread,2) + (struct nt_thread *thread, KPRIORITY prio) +{ + KPRIORITY old_prio; + struct task_struct *task; + + TRACE2("thread: %p, priority = %u", thread, prio); +#ifdef CONFIG_X86_64 + if (thread == (void *)0x1f) + thread = get_current_nt_thread(); +#endif + if (!thread) { + TRACE2("invalid thread"); + EXIT2(return LOW_REALTIME_PRIORITY); + } + task = get_nt_thread_task(thread); + if (!task) { + TRACE2("couldn't find task for thread: %p", thread); + EXIT2(return LOW_REALTIME_PRIORITY); + } + + old_prio = thread->prio; + thread->prio = prio; + + TRACE2("%d, %d", old_prio, thread->prio); + return old_prio; +} + +struct thread_trampoline { + void (*func)(void *) wstdcall; + void *ctx; + struct nt_thread *thread; + struct completion started; +}; + +static int ntdriver_thread(void *data) +{ + struct thread_trampoline *thread_tramp = data; + /* yes, a tramp! */ + typeof(thread_tramp->func) func = thread_tramp->func; + typeof(thread_tramp->ctx) ctx = thread_tramp->ctx; + + thread_tramp->thread->task = current; + thread_tramp->thread->pid = current->pid; + TRACE2("thread: %p, task: %p (%d)", thread_tramp->thread, + current, current->pid); + complete(&thread_tramp->started); + +#ifdef PF_NOFREEZE + current->flags |= PF_NOFREEZE; +#endif + strncpy(current->comm, "ntdriver", sizeof(current->comm)); + current->comm[sizeof(current->comm)-1] = 0; + LIN2WIN1(func, ctx); + ERROR("task: %p", current); + return 0; +} + +wstdcall NTSTATUS WIN_FUNC(PsCreateSystemThread,7) + (void **handle, ULONG access, void *obj_attr, void *process, + void *client_id, void (*func)(void *) wstdcall, void *ctx) +{ + struct thread_trampoline thread_tramp; + + ENTER2("handle = %p, access = %u, obj_attr = %p, process = %p, " + "client_id = %p, func = %p, context = %p", handle, access, + obj_attr, process, client_id, func, ctx); + + thread_tramp.thread = create_nt_thread(NULL); + if (!thread_tramp.thread) { + ERROR("couldn't allocate thread object"); + EXIT2(return STATUS_RESOURCES); + } + TRACE2("thread: %p", thread_tramp.thread); + thread_tramp.func = func; + thread_tramp.ctx = ctx; + init_completion(&thread_tramp.started); + + thread_tramp.thread->task = kthread_run(ntdriver_thread, + &thread_tramp, "ntdriver"); + if (IS_ERR(thread_tramp.thread->task)) { + free_object(thread_tramp.thread); + EXIT2(return STATUS_FAILURE); + } + TRACE2("created task: %p", thread_tramp.thread->task); + + wait_for_completion(&thread_tramp.started); + *handle = OBJECT_TO_HEADER(thread_tramp.thread); + TRACE2("created thread: %p, %p", thread_tramp.thread, *handle); + EXIT2(return STATUS_SUCCESS); +} + +wstdcall NTSTATUS WIN_FUNC(PsTerminateSystemThread,1) + (NTSTATUS status) +{ + struct nt_thread *thread; + + TRACE2("%p, %08X", current, status); + thread = get_current_nt_thread(); + TRACE2("%p", thread); + if (thread) { + KeSetEvent((struct nt_event *)&thread->dh, 0, FALSE); + while (1) { + struct nt_list *ent; + struct irp *irp; + KIRQL irql; + irql = nt_spin_lock_irql(&thread->lock, DISPATCH_LEVEL); + ent = RemoveHeadList(&thread->irps); + nt_spin_unlock_irql(&thread->lock, irql); + if (!ent) + break; + irp = container_of(ent, struct irp, thread_list); + IOTRACE("%p", irp); + IoCancelIrp(irp); + } + /* the driver may later query this status with + * ZwQueryInformationThread */ + thread->status = status; + } else + ERROR("couldn't find thread for task: %p", current); + + complete_and_exit(NULL, status); + ERROR("oops: %p, %d", thread->task, thread->pid); + return STATUS_FAILURE; +} + +wstdcall BOOLEAN WIN_FUNC(KeRemoveEntryDeviceQueue,2) + (struct kdevice_queue *dev_queue, struct kdevice_queue_entry *entry) +{ + struct kdevice_queue_entry *e; + KIRQL irql; + + irql = nt_spin_lock_irql(&dev_queue->lock, DISPATCH_LEVEL); + nt_list_for_each_entry(e, &dev_queue->list, list) { + if (e == entry) { + RemoveEntryList(&e->list); + nt_spin_unlock_irql(&dev_queue->lock, irql); + return TRUE; + } + } + nt_spin_unlock_irql(&dev_queue->lock, irql); + return FALSE; +} + +wstdcall BOOLEAN WIN_FUNC(KeSynchronizeExecution,3) + (struct kinterrupt *interrupt, PKSYNCHRONIZE_ROUTINE synch_routine, + void *ctx) +{ + BOOLEAN ret; + unsigned long flags; + + nt_spin_lock_irqsave(interrupt->actual_lock, flags); + ret = LIN2WIN1(synch_routine, ctx); + nt_spin_unlock_irqrestore(interrupt->actual_lock, flags); + TRACE6("%d", ret); + return ret; +} + +wstdcall void *WIN_FUNC(MmAllocateContiguousMemorySpecifyCache,5) + (SIZE_T size, PHYSICAL_ADDRESS lowest, PHYSICAL_ADDRESS highest, + PHYSICAL_ADDRESS boundary, enum memory_caching_type cache_type) +{ + void *addr; + gfp_t flags; + + ENTER2("%lu, 0x%lx, 0x%lx, 0x%lx, %d", size, (long)lowest, + (long)highest, (long)boundary, cache_type); + flags = irql_gfp(); + addr = wrap_get_free_pages(flags, size); + TRACE2("%p, %lu, 0x%x", addr, size, flags); + if (addr && ((virt_to_phys(addr) + size) <= highest)) + EXIT2(return addr); +#ifdef CONFIG_X86_64 + /* GFP_DMA is really only 16MB even on x86-64, but there is no + * other zone available */ + if (highest <= DMA_31BIT_MASK) + flags |= __GFP_DMA; + else if (highest <= DMA_32BIT_MASK) + flags |= __GFP_DMA32; +#else + if (highest <= DMA_24BIT_MASK) + flags |= __GFP_DMA; + else if (highest > DMA_30BIT_MASK) + flags |= __GFP_HIGHMEM; +#endif + addr = wrap_get_free_pages(flags, size); + TRACE2("%p, %lu, 0x%x", addr, size, flags); + return addr; +} + +wstdcall void WIN_FUNC(MmFreeContiguousMemorySpecifyCache,3) + (void *base, SIZE_T size, enum memory_caching_type cache_type) +{ + TRACE2("%p, %lu", base, size); + free_pages((unsigned long)base, get_order(size)); +} + +wstdcall PHYSICAL_ADDRESS WIN_FUNC(MmGetPhysicalAddress,1) + (void *base) +{ + unsigned long phy = virt_to_phys(base); + TRACE2("%p, %p", base, (void *)phy); + return phy; +} + +/* Atheros card with pciid 168C:0014 calls this function with 0xf0000 + * and 0xf6ef0 address, and then check for things that seem to be + * related to ACPI: "_SM_" and "_DMI_". This may be the hack they do + * to check if this card is installed in IBM thinkpads; we can + * probably get this device to work if we create a buffer with the + * strings as required by the driver and return virtual address for + * that address instead */ +wstdcall void __iomem *WIN_FUNC(MmMapIoSpace,3) + (PHYSICAL_ADDRESS phys_addr, SIZE_T size, + enum memory_caching_type cache) +{ + void __iomem *virt; + ENTER1("cache type: %d", cache); + if (cache == MmCached) + virt = ioremap(phys_addr, size); + else + virt = ioremap_nocache(phys_addr, size); + TRACE1("%Lx, %lu, %p", phys_addr, size, virt); + return virt; +} + +wstdcall void WIN_FUNC(MmUnmapIoSpace,2) + (void __iomem *addr, SIZE_T size) +{ + ENTER1("%p, %lu", addr, size); + iounmap(addr); + return; +} + +wstdcall ULONG WIN_FUNC(MmSizeOfMdl,2) + (void *base, ULONG length) +{ + return (sizeof(struct mdl) + + (sizeof(PFN_NUMBER) * SPAN_PAGES(base, length))); +} + +struct mdl *allocate_init_mdl(void *virt, ULONG length) +{ + struct wrap_mdl *wrap_mdl; + struct mdl *mdl; + int mdl_size = MmSizeOfMdl(virt, length); + + if (mdl_size <= MDL_CACHE_SIZE) { + wrap_mdl = kmem_cache_alloc(mdl_cache, irql_gfp()); + if (!wrap_mdl) + return NULL; + spin_lock_bh(&dispatcher_lock); + InsertHeadList(&wrap_mdl_list, &wrap_mdl->list); + spin_unlock_bh(&dispatcher_lock); + mdl = wrap_mdl->mdl; + TRACE3("allocated mdl from cache: %p(%p), %p(%d)", + wrap_mdl, mdl, virt, length); + memset(mdl, 0, MDL_CACHE_SIZE); + MmInitializeMdl(mdl, virt, length); + /* mark the MDL as allocated from cache pool so when + * it is freed, we free it back to the pool */ + mdl->flags = MDL_ALLOCATED_FIXED_SIZE | MDL_CACHE_ALLOCATED; + } else { + wrap_mdl = + kmalloc(sizeof(*wrap_mdl) + mdl_size, irql_gfp()); + if (!wrap_mdl) + return NULL; + mdl = wrap_mdl->mdl; + TRACE3("allocated mdl from memory: %p(%p), %p(%d)", + wrap_mdl, mdl, virt, length); + spin_lock_bh(&dispatcher_lock); + InsertHeadList(&wrap_mdl_list, &wrap_mdl->list); + spin_unlock_bh(&dispatcher_lock); + memset(mdl, 0, mdl_size); + MmInitializeMdl(mdl, virt, length); + mdl->flags = MDL_ALLOCATED_FIXED_SIZE; + } + return mdl; +} + +void free_mdl(struct mdl *mdl) +{ + /* A driver may allocate Mdl with NdisAllocateBuffer and free + * with IoFreeMdl (e.g., 64-bit Broadcom). Since we need to + * treat buffers allocated with Ndis calls differently, we + * must call NdisFreeBuffer if it is allocated with Ndis + * function. We set 'pool' field in Ndis functions. */ + if (!mdl) + return; + if (mdl->pool) + NdisFreeBuffer(mdl); + else { + struct wrap_mdl *wrap_mdl = (struct wrap_mdl *) + ((char *)mdl - offsetof(struct wrap_mdl, mdl)); + spin_lock_bh(&dispatcher_lock); + RemoveEntryList(&wrap_mdl->list); + spin_unlock_bh(&dispatcher_lock); + + if (mdl->flags & MDL_CACHE_ALLOCATED) { + TRACE3("freeing mdl cache: %p, %p, %p", + wrap_mdl, mdl, mdl->mappedsystemva); + kmem_cache_free(mdl_cache, wrap_mdl); + } else { + TRACE3("freeing mdl: %p, %p, %p", + wrap_mdl, mdl, mdl->mappedsystemva); + kfree(wrap_mdl); + } + } + return; +} + +wstdcall void WIN_FUNC(IoBuildPartialMdl,4) + (struct mdl *source, struct mdl *target, void *virt, ULONG length) +{ + MmInitializeMdl(target, virt, length); + target->flags |= MDL_PARTIAL; +} + +wstdcall void WIN_FUNC(MmBuildMdlForNonPagedPool,1) + (struct mdl *mdl) +{ + PFN_NUMBER *mdl_pages; + int i, n; + + ENTER4("%p", mdl); + /* already mapped */ +// mdl->mappedsystemva = MmGetMdlVirtualAddress(mdl); + mdl->flags |= MDL_SOURCE_IS_NONPAGED_POOL; + TRACE4("%p, %p, %p, %d, %d", mdl, mdl->mappedsystemva, mdl->startva, + mdl->byteoffset, mdl->bytecount); + n = SPAN_PAGES(MmGetSystemAddressForMdl(mdl), MmGetMdlByteCount(mdl)); + if (n > MDL_CACHE_PAGES) + WARNING("%p, %d, %d", MmGetSystemAddressForMdl(mdl), + MmGetMdlByteCount(mdl), n); + mdl_pages = MmGetMdlPfnArray(mdl); + for (i = 0; i < n; i++) + mdl_pages[i] = (ULONG_PTR)mdl->startva + (i * PAGE_SIZE); + EXIT4(return); +} + +wstdcall void *WIN_FUNC(MmMapLockedPages,2) + (struct mdl *mdl, KPROCESSOR_MODE access_mode) +{ + /* already mapped */ +// mdl->mappedsystemva = MmGetMdlVirtualAddress(mdl); + mdl->flags |= MDL_MAPPED_TO_SYSTEM_VA; + /* what is the need for MDL_PARTIAL_HAS_BEEN_MAPPED? */ + if (mdl->flags & MDL_PARTIAL) + mdl->flags |= MDL_PARTIAL_HAS_BEEN_MAPPED; + return mdl->mappedsystemva; +} + +wstdcall void *WIN_FUNC(MmMapLockedPagesSpecifyCache,6) + (struct mdl *mdl, KPROCESSOR_MODE access_mode, + enum memory_caching_type cache_type, void *base_address, + ULONG bug_check, enum mm_page_priority priority) +{ + return MmMapLockedPages(mdl, access_mode); +} + +wstdcall void WIN_FUNC(MmUnmapLockedPages,2) + (void *base, struct mdl *mdl) +{ + mdl->flags &= ~MDL_MAPPED_TO_SYSTEM_VA; + return; +} + +wstdcall void WIN_FUNC(MmProbeAndLockPages,3) + (struct mdl *mdl, KPROCESSOR_MODE access_mode, + enum lock_operation operation) +{ + /* already locked */ + mdl->flags |= MDL_PAGES_LOCKED; + return; +} + +wstdcall void WIN_FUNC(MmUnlockPages,1) + (struct mdl *mdl) +{ + mdl->flags &= ~MDL_PAGES_LOCKED; + return; +} + +wstdcall BOOLEAN WIN_FUNC(MmIsAddressValid,1) + (void *virt_addr) +{ + if (virt_addr_valid(virt_addr)) + return TRUE; + else + return FALSE; +} + +wstdcall void *WIN_FUNC(MmLockPagableDataSection,1) + (void *address) +{ + return address; +} + +wstdcall void WIN_FUNC(MmUnlockPagableImageSection,1) + (void *handle) +{ + return; +} + +wstdcall NTSTATUS WIN_FUNC(ObReferenceObjectByHandle,6) + (void *handle, ACCESS_MASK desired_access, void *obj_type, + KPROCESSOR_MODE access_mode, void **object, void *handle_info) +{ + struct common_object_header *hdr; + + TRACE2("%p", handle); + hdr = HANDLE_TO_HEADER(handle); + atomic_inc_var(hdr->ref_count); + *object = HEADER_TO_OBJECT(hdr); + TRACE2("%p, %p, %d, %p", hdr, object, hdr->ref_count, *object); + return STATUS_SUCCESS; +} + +/* DDK doesn't say if return value should be before incrementing or + * after incrementing reference count, but according to #reactos + * devels, it should be return value after incrementing */ +wfastcall LONG WIN_FUNC(ObfReferenceObject,1) + (void *object) +{ + struct common_object_header *hdr; + LONG ret; + + hdr = OBJECT_TO_HEADER(object); + ret = post_atomic_add(hdr->ref_count, 1); + TRACE2("%p, %d, %p", hdr, hdr->ref_count, object); + return ret; +} + +static int dereference_object(void *object) +{ + struct common_object_header *hdr; + int ref_count; + + ENTER2("object: %p", object); + hdr = OBJECT_TO_HEADER(object); + TRACE2("hdr: %p", hdr); + ref_count = post_atomic_add(hdr->ref_count, -1); + TRACE2("object: %p, %d", object, ref_count); + if (ref_count < 0) + ERROR("invalid object: %p (%d)", object, ref_count); + if (ref_count <= 0) { + free_object(object); + return 1; + } else + return 0; +} + +wfastcall void WIN_FUNC(ObfDereferenceObject,1) + (void *object) +{ + TRACE2("%p", object); + dereference_object(object); +} + +wstdcall NTSTATUS WIN_FUNC(ZwCreateFile,11) + (void **handle, ACCESS_MASK access_mask, + struct object_attributes *obj_attr, struct io_status_block *iosb, + LARGE_INTEGER *size, ULONG file_attr, ULONG share_access, + ULONG create_disposition, ULONG create_options, void *ea_buffer, + ULONG ea_length) +{ + struct common_object_header *coh; + struct file_object *fo; + struct ansi_string ansi; + struct wrap_bin_file *bin_file; + char *file_basename; + NTSTATUS status; + + spin_lock_bh(&ntoskernel_lock); + nt_list_for_each_entry(coh, &object_list, list) { + if (coh->type != OBJECT_TYPE_FILE) + continue; + /* TODO: check if file is opened in shared mode */ + if (!RtlCompareUnicodeString(&coh->name, obj_attr->name, TRUE)) { + fo = HEADER_TO_OBJECT(coh); + bin_file = fo->wrap_bin_file; + *handle = coh; + spin_unlock_bh(&ntoskernel_lock); + ObReferenceObject(fo); + iosb->status = FILE_OPENED; + iosb->info = bin_file->size; + EXIT2(return STATUS_SUCCESS); + } + } + spin_unlock_bh(&ntoskernel_lock); + + if (RtlUnicodeStringToAnsiString(&ansi, obj_attr->name, TRUE) != + STATUS_SUCCESS) + EXIT2(return STATUS_INSUFFICIENT_RESOURCES); + + file_basename = strrchr(ansi.buf, '\\'); + if (file_basename) + file_basename++; + else + file_basename = ansi.buf; + TRACE2("file: '%s', '%s'", ansi.buf, file_basename); + + fo = allocate_object(sizeof(struct file_object), OBJECT_TYPE_FILE, + obj_attr->name); + if (!fo) { + RtlFreeAnsiString(&ansi); + iosb->status = STATUS_INSUFFICIENT_RESOURCES; + iosb->info = 0; + EXIT2(return STATUS_FAILURE); + } + coh = OBJECT_TO_HEADER(fo); + bin_file = get_bin_file(file_basename); + if (bin_file) { + TRACE2("%s, %s", bin_file->name, file_basename); + fo->flags = FILE_OPENED; + } else if (access_mask & FILE_WRITE_DATA) { + bin_file = kzalloc(sizeof(*bin_file), GFP_KERNEL); + if (bin_file) { + strncpy(bin_file->name, file_basename, + sizeof(bin_file->name)); + bin_file->name[sizeof(bin_file->name)-1] = 0; + bin_file->data = vmalloc(*size); + if (bin_file->data) { + memset(bin_file->data, 0, *size); + bin_file->size = *size; + fo->flags = FILE_CREATED; + } else { + kfree(bin_file); + bin_file = NULL; + } + } + } else + bin_file = NULL; + + RtlFreeAnsiString(&ansi); + if (!bin_file) { + iosb->status = FILE_DOES_NOT_EXIST; + iosb->info = 0; + free_object(fo); + EXIT2(return STATUS_FAILURE); + } + + fo->wrap_bin_file = bin_file; + fo->current_byte_offset = 0; + if (access_mask & FILE_READ_DATA) + fo->read_access = TRUE; + if (access_mask & FILE_WRITE_DATA) + fo->write_access = TRUE; + iosb->status = FILE_OPENED; + iosb->info = bin_file->size; + *handle = coh; + TRACE2("handle: %p", *handle); + status = STATUS_SUCCESS; + EXIT2(return status); +} + +wstdcall NTSTATUS WIN_FUNC(ZwOpenFile,6) + (void **handle, ACCESS_MASK access_mask, + struct object_attributes *obj_attr, struct io_status_block *iosb, + ULONG share_access, ULONG open_options) +{ + LARGE_INTEGER size; + return ZwCreateFile(handle, access_mask, obj_attr, iosb, &size, 0, + share_access, 0, open_options, NULL, 0); +} + +wstdcall NTSTATUS WIN_FUNC(ZwReadFile,9) + (void *handle, struct nt_event *event, void *apc_routine, + void *apc_context, struct io_status_block *iosb, void *buffer, + ULONG length, LARGE_INTEGER *byte_offset, ULONG *key) +{ + struct file_object *fo; + struct common_object_header *coh; + ULONG count; + size_t offset; + struct wrap_bin_file *file; + + TRACE2("%p", handle); + coh = handle; + if (coh->type != OBJECT_TYPE_FILE) { + ERROR("handle %p is invalid: %d", handle, coh->type); + EXIT2(return STATUS_FAILURE); + } + fo = HANDLE_TO_OBJECT(coh); + file = fo->wrap_bin_file; + TRACE2("file: %s (%zu)", file->name, file->size); + spin_lock_bh(&ntoskernel_lock); + if (byte_offset) + offset = *byte_offset; + else + offset = fo->current_byte_offset; + count = min((size_t)length, file->size - offset); + TRACE2("count: %u, offset: %zu, length: %u", count, offset, length); + memcpy(buffer, ((void *)file->data) + offset, count); + fo->current_byte_offset = offset + count; + spin_unlock_bh(&ntoskernel_lock); + iosb->status = STATUS_SUCCESS; + iosb->info = count; + EXIT2(return STATUS_SUCCESS); +} + +wstdcall NTSTATUS WIN_FUNC(ZwWriteFile,9) + (void *handle, struct nt_event *event, void *apc_routine, + void *apc_context, struct io_status_block *iosb, void *buffer, + ULONG length, LARGE_INTEGER *byte_offset, ULONG *key) +{ + struct file_object *fo; + struct common_object_header *coh; + struct wrap_bin_file *file; + unsigned long offset; + + TRACE2("%p", handle); + coh = handle; + if (coh->type != OBJECT_TYPE_FILE) { + ERROR("handle %p is invalid: %d", handle, coh->type); + EXIT2(return STATUS_FAILURE); + } + fo = HANDLE_TO_OBJECT(coh); + file = fo->wrap_bin_file; + TRACE2("file: %zu, %u", file->size, length); + spin_lock_bh(&ntoskernel_lock); + if (byte_offset) + offset = *byte_offset; + else + offset = fo->current_byte_offset; + if (length + offset > file->size) { + WARNING("%lu, %u", length + offset, (unsigned int)file->size); + /* TODO: implement writing past end of current size */ + iosb->status = STATUS_FAILURE; + iosb->info = 0; + } else { + memcpy(file->data + offset, buffer, length); + iosb->status = STATUS_SUCCESS; + iosb->info = length; + fo->current_byte_offset = offset + length; + } + spin_unlock_bh(&ntoskernel_lock); + EXIT2(return iosb->status); +} + +wstdcall NTSTATUS WIN_FUNC(ZwClose,1) + (void *handle) +{ + struct common_object_header *coh; + + TRACE2("%p", handle); + if (handle == NULL) { + TRACE1(""); + EXIT2(return STATUS_SUCCESS); + } + coh = handle; + if (coh->type == OBJECT_TYPE_FILE) { + struct file_object *fo; + struct wrap_bin_file *bin_file; + typeof(fo->flags) flags; + + fo = HANDLE_TO_OBJECT(handle); + flags = fo->flags; + bin_file = fo->wrap_bin_file; + if (dereference_object(fo)) { + if (flags == FILE_CREATED) { + vfree(bin_file->data); + kfree(bin_file); + } else + free_bin_file(bin_file); + } + } else if (coh->type == OBJECT_TYPE_NT_THREAD) { + struct nt_thread *thread = HANDLE_TO_OBJECT(handle); + TRACE2("thread: %p (%p)", thread, handle); + ObDereferenceObject(thread); + } else { + /* TODO: can we just dereference object here? */ + WARNING("closing handle 0x%x not implemented", coh->type); + } + EXIT2(return STATUS_SUCCESS); +} + +wstdcall NTSTATUS WIN_FUNC(ZwQueryInformationFile,5) + (void *handle, struct io_status_block *iosb, void *info, + ULONG length, enum file_info_class class) +{ + struct file_object *fo; + struct file_name_info *fni; + struct file_std_info *fsi; + struct wrap_bin_file *file; + struct common_object_header *coh; + + ENTER2("%p", handle); + coh = handle; + if (coh->type != OBJECT_TYPE_FILE) { + ERROR("handle %p is invalid: %d", coh, coh->type); + EXIT2(return STATUS_FAILURE); + } + fo = HANDLE_TO_OBJECT(handle); + TRACE2("fo: %p, %d", fo, class); + switch (class) { + case FileNameInformation: + fni = info; + fni->length = min(length, (typeof(length))coh->name.length); + memcpy(fni->name, coh->name.buf, fni->length); + iosb->status = STATUS_SUCCESS; + iosb->info = fni->length; + break; + case FileStandardInformation: + fsi = info; + file = fo->wrap_bin_file; + fsi->alloc_size = file->size; + fsi->eof = file->size; + fsi->num_links = 1; + fsi->delete_pending = FALSE; + fsi->dir = FALSE; + iosb->status = STATUS_SUCCESS; + iosb->info = 0; + break; + default: + WARNING("type %d not implemented yet", class); + iosb->status = STATUS_FAILURE; + iosb->info = 0; + break; + } + EXIT2(return iosb->status); +} + +wstdcall NTSTATUS WIN_FUNC(ZwOpenSection,3) + (void **handle, ACCESS_MASK access, struct object_attributes *obj_attrs) +{ + INFO("%p, 0x%x, %d", obj_attrs, obj_attrs->attributes, access); + TODO(); + *handle = obj_attrs; + return STATUS_SUCCESS; +} + +wstdcall NTSTATUS WIN_FUNC(ZwMapViewOfSection,10) + (void *secn_handle, void *process_handle, void **base_address, + ULONG zero_bits, LARGE_INTEGER *secn_offset, SIZE_T *view_size, + enum section_inherit inherit, ULONG alloc_type, ULONG protect) +{ + INFO("%p, %p, %p", secn_handle, process_handle, base_address); + TODO(); + *base_address = (void *)0xdeadbeef; + return STATUS_SUCCESS; +} + +wstdcall NTSTATUS WIN_FUNC(ZwUnmapViewOfSection,2) + (void *process_handle, void *base_address) +{ + INFO("%p, %p", process_handle, base_address); + TODO(); + return STATUS_SUCCESS; +} + +wstdcall NTSTATUS WIN_FUNC(ZwCreateKey,7) + (void **handle, ACCESS_MASK desired_access, + struct object_attributes *attr, ULONG title_index, + struct unicode_string *class, ULONG create_options, + ULONG *disposition) +{ + struct ansi_string ansi; + if (RtlUnicodeStringToAnsiString(&ansi, attr->name, TRUE) == + STATUS_SUCCESS) { + TRACE1("key: %s", ansi.buf); + RtlFreeAnsiString(&ansi); + } + *handle = NULL; + return STATUS_SUCCESS; +} + +wstdcall NTSTATUS WIN_FUNC(ZwOpenKey,3) + (void **handle, ACCESS_MASK desired_access, + struct object_attributes *attr) +{ + struct ansi_string ansi; + if (RtlUnicodeStringToAnsiString(&ansi, attr->name, TRUE) == + STATUS_SUCCESS) { + TRACE1("key: %s", ansi.buf); + RtlFreeAnsiString(&ansi); + } + *handle = NULL; + return STATUS_SUCCESS; +} + +wstdcall NTSTATUS WIN_FUNC(ZwSetValueKey,6) + (void *handle, struct unicode_string *name, ULONG title_index, + ULONG type, void *data, ULONG data_size) +{ + struct ansi_string ansi; + if (RtlUnicodeStringToAnsiString(&ansi, name, TRUE) == + STATUS_SUCCESS) { + TRACE1("key: %s", ansi.buf); + RtlFreeAnsiString(&ansi); + } + return STATUS_SUCCESS; +} + +wstdcall NTSTATUS WIN_FUNC(ZwQueryValueKey,6) + (void *handle, struct unicode_string *name, + enum key_value_information_class class, void *info, + ULONG length, ULONG *res_length) +{ + struct ansi_string ansi; + if (RtlUnicodeStringToAnsiString(&ansi, name, TRUE) == STATUS_SUCCESS) { + TRACE1("key: %s", ansi.buf); + RtlFreeAnsiString(&ansi); + } + TODO(); + return STATUS_INVALID_PARAMETER; +} + +wstdcall NTSTATUS WIN_FUNC(ZwDeleteKey,1) + (void *handle) +{ + ENTER2("%p", handle); + return STATUS_SUCCESS; +} + +wstdcall NTSTATUS WIN_FUNC(ZwPowerInformation,4) + (INT info_level, void *in_buf, ULONG in_buf_len, void *out_buf, + ULONG out_buf_len) +{ + INFO("%d, %u, %u", info_level, in_buf_len, out_buf_len); + TODO(); + return STATUS_ACCESS_DENIED; +} + +wstdcall NTSTATUS WIN_FUNC(WmiSystemControl,4) + (struct wmilib_context *info, struct device_object *dev_obj, + struct irp *irp, void *irp_disposition) +{ + TODO(); + return STATUS_SUCCESS; +} + +wstdcall NTSTATUS WIN_FUNC(WmiCompleteRequest,5) + (struct device_object *dev_obj, struct irp *irp, NTSTATUS status, + ULONG buffer_used, CCHAR priority_boost) +{ + TODO(); + return STATUS_SUCCESS; +} + +noregparm NTSTATUS WIN_FUNC(WmiTraceMessage,12) + (void *tracehandle, ULONG message_flags, + void *message_guid, USHORT message_no, ...) +{ + TODO(); + EXIT2(return STATUS_SUCCESS); +} + +wstdcall NTSTATUS WIN_FUNC(WmiQueryTraceInformation,4) + (enum trace_information_class trace_info_class, void *trace_info, + ULONG *req_length, void *buf) +{ + TODO(); + EXIT2(return STATUS_SUCCESS); +} + +/* this function can't be wstdcall as it takes variable number of args */ +noregparm ULONG WIN_FUNC(DbgPrint,12) + (char *format, ...) +{ +#ifdef DEBUG + va_list args; + static char buf[100]; + + va_start(args, format); + vsnprintf(buf, sizeof(buf), format, args); + printk(KERN_DEBUG "%s (%s): %s", DRIVER_NAME, __FUNCTION__, buf); + va_end(args); +#endif + return STATUS_SUCCESS; +} + +wstdcall void WIN_FUNC(KeBugCheckEx,5) + (ULONG code, ULONG_PTR param1, ULONG_PTR param2, + ULONG_PTR param3, ULONG_PTR param4) +{ + TODO(); + return; +} + +wstdcall void WIN_FUNC(ExSystemTimeToLocalTime,2) + (LARGE_INTEGER *system_time, LARGE_INTEGER *local_time) +{ + *local_time = *system_time; +} + +wstdcall ULONG WIN_FUNC(ExSetTimerResolution,2) + (ULONG time, BOOLEAN set) +{ + /* why a driver should change system wide timer resolution is + * beyond me */ + return time; +} + +wstdcall void WIN_FUNC(DbgBreakPoint,0) + (void) +{ + TODO(); +} + +wstdcall void WIN_FUNC(_except_handler3,0) + (void) +{ + TODO(); +} + +wstdcall void WIN_FUNC(__C_specific_handler,0) + (void) +{ + TODO(); +} + +wstdcall void WIN_FUNC(_purecall,0) + (void) +{ + TODO(); +} + +wstdcall void WIN_FUNC(__chkstk,0) + (void) +{ + TODO(); +} + +struct worker_init_struct { + work_struct_t work; + struct completion completion; + struct nt_thread *nt_thread; +}; + +static void wrap_worker_init_func(worker_param_t param) +{ + struct worker_init_struct *worker_init_struct; + + worker_init_struct = + worker_param_data(param, struct worker_init_struct, work); + TRACE1("%p", worker_init_struct); + worker_init_struct->nt_thread = create_nt_thread(current); + if (!worker_init_struct->nt_thread) + WARNING("couldn't create worker thread"); + complete(&worker_init_struct->completion); +} + +struct nt_thread *wrap_worker_init(workqueue_struct_t *wq) +{ + struct worker_init_struct worker_init_struct; + + TRACE1("%p", &worker_init_struct); + init_completion(&worker_init_struct.completion); + initialize_work(&worker_init_struct.work, wrap_worker_init_func, + &worker_init_struct); + worker_init_struct.nt_thread = NULL; + if (wq) + queue_work(wq, &worker_init_struct.work); + else + schedule_work(&worker_init_struct.work); + wait_for_completion(&worker_init_struct.completion); + TRACE1("%p", worker_init_struct.nt_thread); + return worker_init_struct.nt_thread; +} + +int ntoskernel_init(void) +{ + struct timeval now; + + spin_lock_init(&dispatcher_lock); + spin_lock_init(&ntoskernel_lock); + spin_lock_init(&ntos_work_lock); + spin_lock_init(&kdpc_list_lock); + spin_lock_init(&irp_cancel_lock); + InitializeListHead(&wrap_mdl_list); + InitializeListHead(&kdpc_list); + InitializeListHead(&callback_objects); + InitializeListHead(&bus_driver_list); + InitializeListHead(&object_list); + InitializeListHead(&ntos_work_list); + + nt_spin_lock_init(&nt_list_lock); + + initialize_work(&kdpc_work, kdpc_worker, NULL); + initialize_work(&ntos_work, ntos_work_worker, NULL); + wrap_timer_slist.next = NULL; + + do_gettimeofday(&now); + wrap_ticks_to_boot = TICKS_1601_TO_1970; + wrap_ticks_to_boot += (u64)now.tv_sec * TICKSPERSEC; + wrap_ticks_to_boot += now.tv_usec * 10; + wrap_ticks_to_boot -= jiffies * TICKSPERJIFFY; + TRACE2("%Lu", wrap_ticks_to_boot); + +#ifdef WRAP_PREEMPT + do { + int cpu; + for_each_possible_cpu(cpu) { + irql_info_t *info; + info = &per_cpu(irql_info, cpu); + mutex_init(&(info->lock)); + info->task = NULL; + info->count = 0; + } + } while (0); +#endif + + ntos_wq = create_singlethread_workqueue("ntos_wq"); + if (!ntos_wq) { + WARNING("couldn't create ntos_wq thread"); + return -ENOMEM; + } + ntos_worker_thread = wrap_worker_init(ntos_wq); + TRACE1("%p", ntos_worker_thread); + + if (add_bus_driver("PCI") +#ifdef ENABLE_USB + || add_bus_driver("USB") +#endif + ) { + ntoskernel_exit(); + return -ENOMEM; + } + mdl_cache = + wrap_kmem_cache_create("wrap_mdl", + sizeof(struct wrap_mdl) + MDL_CACHE_SIZE, + 0, 0); + TRACE2("%p", mdl_cache); + if (!mdl_cache) { + ERROR("couldn't allocate MDL cache"); + ntoskernel_exit(); + return -ENOMEM; + } + +#if defined(CONFIG_X86_64) + memset(&kuser_shared_data, 0, sizeof(kuser_shared_data)); + *((ULONG64 *)&kuser_shared_data.system_time) = ticks_1601(); + init_timer(&shared_data_timer); + shared_data_timer.function = update_user_shared_data_proc; + shared_data_timer.data = (unsigned long)0; +#endif + return 0; +} + +int ntoskernel_init_device(struct wrap_device *wd) +{ +#if defined(CONFIG_X86_64) + if (kuser_shared_data.reserved1) + mod_timer(&shared_data_timer, jiffies + MSEC_TO_HZ(30)); +#endif + return 0; +} + +void ntoskernel_exit_device(struct wrap_device *wd) +{ + ENTER2(""); + + KeFlushQueuedDpcs(); + EXIT2(return); +} + +void ntoskernel_exit(void) +{ + struct nt_list *cur; + + ENTER2(""); + + /* free kernel (Ke) timers */ + TRACE2("freeing timers"); + while (1) { + struct wrap_timer *wrap_timer; + struct nt_slist *slist; + + spin_lock_bh(&ntoskernel_lock); + if ((slist = wrap_timer_slist.next)) + wrap_timer_slist.next = slist->next; + spin_unlock_bh(&ntoskernel_lock); + TIMERTRACE("%p", slist); + if (!slist) + break; + wrap_timer = container_of(slist, struct wrap_timer, slist); + if (del_timer_sync(&wrap_timer->timer)) + WARNING("Buggy Windows driver left timer %p running", + wrap_timer->nt_timer); + memset(wrap_timer, 0, sizeof(*wrap_timer)); + slack_kfree(wrap_timer); + } + + TRACE2("freeing MDLs"); + if (mdl_cache) { + spin_lock_bh(&ntoskernel_lock); + if (!IsListEmpty(&wrap_mdl_list)) + ERROR("Windows driver didn't free all MDLs; " + "freeing them now"); + while ((cur = RemoveHeadList(&wrap_mdl_list))) { + struct wrap_mdl *wrap_mdl; + wrap_mdl = container_of(cur, struct wrap_mdl, list); + if (wrap_mdl->mdl->flags & MDL_CACHE_ALLOCATED) + kmem_cache_free(mdl_cache, wrap_mdl); + else + kfree(wrap_mdl); + } + spin_unlock_bh(&ntoskernel_lock); + kmem_cache_destroy(mdl_cache); + mdl_cache = NULL; + } + + TRACE2("freeing callbacks"); + spin_lock_bh(&ntoskernel_lock); + while ((cur = RemoveHeadList(&callback_objects))) { + struct callback_object *object; + struct nt_list *ent; + object = container_of(cur, struct callback_object, list); + while ((ent = RemoveHeadList(&object->callback_funcs))) { + struct callback_func *f; + f = container_of(ent, struct callback_func, list); + kfree(f); + } + kfree(object); + } + spin_unlock_bh(&ntoskernel_lock); + + spin_lock_bh(&ntoskernel_lock); + while ((cur = RemoveHeadList(&bus_driver_list))) { + struct bus_driver *bus_driver; + bus_driver = container_of(cur, struct bus_driver, list); + /* TODO: make sure all all drivers are shutdown/removed */ + kfree(bus_driver); + } + spin_unlock_bh(&ntoskernel_lock); + +#if defined(CONFIG_X86_64) + del_timer_sync(&shared_data_timer); +#endif + if (ntos_wq) + destroy_workqueue(ntos_wq); + TRACE1("%p", ntos_worker_thread); + if (ntos_worker_thread) + ObDereferenceObject(ntos_worker_thread); + ENTER2("freeing objects"); + spin_lock_bh(&ntoskernel_lock); + while ((cur = RemoveHeadList(&object_list))) { + struct common_object_header *hdr; + hdr = container_of(cur, struct common_object_header, list); + if (hdr->type == OBJECT_TYPE_NT_THREAD) + TRACE1("object %p(%d) was not freed, freeing it now", + HEADER_TO_OBJECT(hdr), hdr->type); + else + WARNING("object %p(%d) was not freed, freeing it now", + HEADER_TO_OBJECT(hdr), hdr->type); + ExFreePool(hdr); + } + spin_unlock_bh(&ntoskernel_lock); + + EXIT2(return); +} --- linux-2.6.27.orig/ubuntu/ndiswrapper/win2lin_stubs.S +++ linux-2.6.27/ubuntu/ndiswrapper/win2lin_stubs.S @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2005 Karl Vogel, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include + +#ifdef CONFIG_X86_64 + +/* +# Windows <---> Linux register usage conversion when calling functions +# V = Volatile +# NV = Non Volatile (needs to be saved) +# +# Win Lin +# --------------------------------------- +# Rax Return V Return V +# Rbx NV NV +# Rcx Arg1 V Arg4 V +# Rdx Arg2 V Arg3 V +# Rsi NV Arg2 V +# Rdi NV Arg1 V +# Rsp NV NV +# Rbp NV NV +# R8 Arg3 V Arg5 V +# R9 Arg4 V Arg6 V +# R10 V V +# R11 V V +# R12 NV NV +# R13 NV NV +# R14 NV NV +# R15 NV NV +# +# In addition, Linux uses %rax to indicate number of SSE registers used +# when variadic functions are called. Since there is no way to obtain this +# from Windows, for now, we just assume this is 0 (hence %rax is cleared). +# +# Windows pushes arguments 5 and higher onto stack in case of integer +# variables and 4 and higher in case of floating point variabes (passed +# in SSE registers). + +In a windows function, the stackframe/registers look like this: + +# 0x0048 .... +# 0x0040 arg8 +# 0x0038 arg7 +# 0x0030 arg6 +# 0x0028 arg5 +# 0x0020 shadow/spill space for arg4 +# 0x0018 shadow/spill space for arg3 +# 0x0010 shadow/spill space for arg2 +# 0x0008 shadow/spill space for arg1 +# 0x0000 ret + +# register spill space is same irrespective of number of arguments - even +# if Windows function takes less than 4 arguments, 32 bytes above return +# address is reserved for the function + +In Linux it should look like: + +# 0x0018 .... +# 0x0010 arg8 +# 0x0008 arg7 +# 0x0000 ret + +*/ + +# +# setup for Windows to Linux function call +# + + .text + +.macro win2lin_prolog + push %rsi + push %rdi +.endm + +.macro win2lin_epilog + pop %rdi + pop %rsi +.endm + +# when Windows function calls Linux function, the function address is in %r10 + +.macro call_lin_func + xor %rax, %rax # rax indicates number of SSE regs + call *%r10 +.endm + +# before prolog, 0(%rsp) is return address, 8(%rsp) would be arg1 +# (but it is in register) and so on, so n'th arg would be at n*8(%rsp) +# for n > 4. But in prolog, we push 2 registers that are non-volaile in +# Windows, but volatile in Linux. So after prolog, args are at (n+2)*8(%rsp) + +#define win2lin_win_arg(n) (n+2)*8(%rsp) + +#define win2lin_arg1 mov %rcx, %rdi +#define win2lin_arg2 mov %rdx, %rsi +#define win2lin_arg3 mov %r8, %rdx +#define win2lin_arg4 mov %r9, %rcx +#define win2lin_arg5 mov win2lin_win_arg(5), %r8 +#define win2lin_arg6 mov win2lin_win_arg(6), %r9 + + .type win2lin0, @function +win2lin0: + win2lin_prolog + call_lin_func + win2lin_epilog + ret + .size win2lin0, .-win2lin0 + + .type win2lin1, @function +win2lin1: + win2lin_prolog + win2lin_arg1 + call_lin_func + win2lin_epilog + ret + .size win2lin1, .-win2lin1 + + .type win2lin2, @function +win2lin2: + win2lin_prolog + win2lin_arg1 + win2lin_arg2 + call_lin_func + win2lin_epilog + ret + .size win2lin2, .-win2lin2 + + .type win2lin3, @function +win2lin3: + win2lin_prolog + win2lin_arg1 + win2lin_arg2 + win2lin_arg3 + call_lin_func + win2lin_epilog + ret + .size win2lin3, .-win2lin3 + + .type win2lin4, @function +win2lin4: + win2lin_prolog + win2lin_arg1 + win2lin_arg2 + win2lin_arg3 + win2lin_arg4 + call_lin_func + win2lin_epilog + ret + .size win2lin4, .-win2lin4 + + .type win2lin5, @function +win2lin5: + win2lin_prolog + win2lin_arg1 + win2lin_arg2 + win2lin_arg3 + win2lin_arg4 + win2lin_arg5 + call_lin_func + win2lin_epilog + ret + .size win2lin5, .-win2lin5 + + .type win2lin6, @function +win2lin6: + win2lin_prolog + win2lin_arg1 + win2lin_arg2 + win2lin_arg3 + win2lin_arg4 + win2lin_arg5 + win2lin_arg6 + call_lin_func + win2lin_epilog + ret + .size win2lin6, .-win2lin6 + +# Allocate stack frame for Linux arguments before calling function. +# First 6 args are passed through registers, so we need space for 7 and above. +# The arguments should have been copied onto stack already. + +.macro call_lin_func_args n + sub $(\n-6)*8, %rsp + call_lin_func + add $(\n-6)*8, %rsp + .endm + +# m is index of Linux arg required, n is total number of args to function +# After stack frame is allocated, Linux arg 7 should be at 0(%rsp), +# arg 8 should be at 1*8(%rsp) and so on. So Linux arg m should be at (m-7)*8 +# Stack frame starts at -(n-6)*8(%rsp), so before stack frame is allocated +# Linux arg m should be at (6-n+m-7)*8(%rsp) + +#define win2lin_lin_arg(m,n) (m-1-n)*8(%rsp) + + .type win2lin7, @function +win2lin7: + win2lin_prolog + + win2lin_arg1 + win2lin_arg2 + win2lin_arg3 + win2lin_arg4 + win2lin_arg5 + win2lin_arg6 + + # copy windows argument 7 onto stack for Linux function + mov win2lin_win_arg(7), %r11 + mov %r11, win2lin_lin_arg(7,7) + + call_lin_func_args(7) + win2lin_epilog + ret + .size win2lin7, .-win2lin7 + + .type win2lin8, @function +win2lin8: + win2lin_prolog + + win2lin_arg1 + win2lin_arg2 + win2lin_arg3 + win2lin_arg4 + win2lin_arg5 + win2lin_arg6 + + # copy windows arguments 7 and 8 onto stack for Linux function + mov win2lin_win_arg(7), %r11 + mov %r11, win2lin_lin_arg(7,8) + mov win2lin_win_arg(8), %r11 + mov %r11, win2lin_lin_arg(8,8) + + call_lin_func_args(8) + win2lin_epilog + ret + .size win2lin8, .-win2lin8 + + .type win2lin9, @function +win2lin9: +win2lin10: +win2lin11: +win2lin12: + win2lin_prolog + + # since we destroy rsi and rdi here, first copy windows + # arguments 7 through 12 onto stack for Linux function + mov %rcx, %r11 # save rcx + lea win2lin_win_arg(7), %rsi # source (windows arg 7 and up) + lea win2lin_lin_arg(7,12), %rdi # = destination + mov $6, %rcx # 6 arguments + rep + movsq + mov %r11, %rcx # restore rcx + + win2lin_arg1 + win2lin_arg2 + win2lin_arg3 + win2lin_arg4 + win2lin_arg5 + win2lin_arg6 + + call_lin_func_args(12) + win2lin_epilog + ret + .size win2lin9, .-win2lin9 + +#define win2lin(name, argc) \ +ENTRY(win2lin_ ## name ## _ ## argc) \ + lea name(%rip), %r10 ; \ + jmp win2lin ## argc + +#include "win2lin_stubs.h" + +#endif // CONFIG_X86_64 --- linux-2.6.27.orig/ubuntu/ndiswrapper/ndis.h +++ linux-2.6.27/ubuntu/ndiswrapper/ndis.h @@ -0,0 +1,1309 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _NDIS_H_ +#define _NDIS_H_ + +#include "ntoskernel.h" + +//#define ALLOW_POOL_OVERFLOW 1 + +#define NDIS_DMA_24BITS 0 +#define NDIS_DMA_32BITS 1 +#define NDIS_DMA_64BITS 2 + +#ifdef CONFIG_X86_64 +#define MAXIMUM_PROCESSORS 64 +#else +#define MAXIMUM_PROCESSORS 32 +#endif + +typedef UINT NDIS_STATUS; +typedef UCHAR NDIS_DMA_SIZE; +typedef LONG ndis_rssi; +typedef ULONG ndis_key_index; +typedef ULONG ndis_tx_power_level; +typedef ULONGULONG ndis_key_rsc; +typedef UCHAR ndis_rates[NDIS_MAX_RATES]; +typedef UCHAR ndis_rates_ex[NDIS_MAX_RATES_EX]; +typedef UCHAR mac_address[ETH_ALEN]; +typedef ULONG ndis_fragmentation_threshold; +typedef ULONG ndis_rts_threshold; +typedef ULONG ndis_antenna; +typedef ULONG ndis_oid; + +typedef UCHAR ndis_pmkid_vavlue[16]; + +typedef uint64_t NDIS_PHY_ADDRESS; + +struct ndis_sg_element { + PHYSICAL_ADDRESS address; + ULONG length; + ULONG_PTR reserved; +}; + +struct ndis_sg_list { + ULONG nent; + ULONG_PTR reserved; + struct ndis_sg_element elements[]; +}; + +/* when sending packets, ndiswrapper associates exactly one sg element + * in sg list */ +struct wrap_tx_sg_list { + ULONG nent; + ULONG_PTR reserved; + struct ndis_sg_element elements[1]; +}; + +struct ndis_phy_addr_unit { + NDIS_PHY_ADDRESS phy_addr; + UINT length; +}; + +typedef struct mdl ndis_buffer; + +struct ndis_buffer_pool { + ndis_buffer *free_descr; +// NT_SPIN_LOCK lock; + spinlock_t lock; + UINT max_descr; + UINT num_allocated_descr; +}; + +#define NDIS_PROTOCOL_ID_DEFAULT 0x00 +#define NDIS_PROTOCOL_ID_TCP_IP 0x02 +#define NDIS_PROTOCOL_ID_IPX 0x06 +#define NDIS_PROTOCOL_ID_NBF 0x07 +#define NDIS_PROTOCOL_ID_MAX 0x0F +#define NDIS_PROTOCOL_ID_MASK 0x0F + +#define fPACKET_WRAPPER_RESERVED 0x3F +#define fPACKET_CONTAINS_MEDIA_SPECIFIC_INFO 0x40 +#define fPACKET_ALLOCATED_BY_NDIS 0x80 + +#define PROTOCOL_RESERVED_SIZE_IN_PACKET (4 * sizeof(void *)) + +struct transport_header_offset { + USHORT protocol_type; + USHORT header_offset; +}; + +struct ndis_network_address { + USHORT length; + USHORT type; + UCHAR address[1]; +}; + +struct ndis_network_address_list { + LONG count; + USHORT type; + struct ndis_network_address address[1]; +}; + +struct ndis_tcp_ip_checksum_packet_info { + union { + struct { + ULONG v4:1; + ULONG v6:1; + ULONG tcp:1; + ULONG udp:1; + ULONG ip:1; + } tx; + struct { + ULONG tcp_failed:1; + ULONG udp_failed:1; + ULONG ip_failed:1; + ULONG tcp_succeeded:1; + ULONG udp_succeeded:1; + ULONG ip_succeeded:1; + ULONG loopback:1; + } rx; + ULONG value; + }; +}; + +enum ndis_task { + TcpIpChecksumNdisTask, IpSecNdisTask, TcpLargeSendNdisTask, MaxNdisTask +}; + +enum ndis_encapsulation { + UNSPECIFIED_Encapsulation, NULL_Encapsulation, + IEEE_802_3_Encapsulation, IEEE_802_5_Encapsulation, + LLC_SNAP_ROUTED_Encapsulation, LLC_SNAP_BRIDGED_Encapsulation +}; + +#define NDIS_TASK_OFFLOAD_VERSION 1 + +struct ndis_encapsulation_format { + enum ndis_encapsulation encap; + struct { + ULONG fixed_header_size:1; + ULONG reserved:31; + } flags; + ULONG header_size; +}; + +struct ndis_task_offload_header { + ULONG version; + ULONG size; + ULONG reserved; + ULONG offset_first_task; + struct ndis_encapsulation_format encap_format; +}; + +struct ndis_task_offload { + ULONG version; + ULONG size; + enum ndis_task task; + ULONG offset_next_task; + ULONG task_buf_length; + UCHAR task_buf[1]; +}; + +struct v4_checksum { + union { + struct { + ULONG ip_opts:1; + ULONG tcp_opts:1; + ULONG tcp_csum:1; + ULONG udp_csum:1; + ULONG ip_csum:1; + }; + ULONG value; + }; +}; + +struct v6_checksum { + ULONG ip_supported:1; + ULONG tcp_supported:1; + ULONG tcp_csum:1; + ULONG udp_csum:1; +}; + +struct ndis_task_tcp_ip_checksum { + struct v4_checksum v4_tx; + struct v4_checksum v4_rx; + struct v6_checksum v6_tx; + struct v6_checksum v6_rx; +}; + +struct ndis_task_tcp_large_send { + ULONG version; + ULONG max_size; + ULONG min_seg_count; + BOOLEAN tcp_opts; + BOOLEAN ip_opts; +}; + +struct ndis_packet; + +struct ndis_packet_pool { + struct ndis_packet *free_descr; +// NT_SPIN_LOCK lock; + spinlock_t lock; + UINT max_descr; + UINT num_allocated_descr; + UINT num_used_descr; + UINT proto_rsvd_length; +}; + +struct ndis_packet_stack { + ULONG_PTR IM_reserved[2]; + ULONG_PTR ndis_reserved[4]; +}; + +enum ndis_per_packet_info { + TcpIpChecksumPacketInfo, IpSecPacketInfo, TcpLargeSendPacketInfo, + ClassificationHandlePacketInfo, NdisReserved, + ScatterGatherListPacketInfo, Ieee8021QInfo, OriginalPacketInfo, + PacketCancelId, MaxPerPacketInfo +}; + +struct ndis_packet_extension { + void *info[MaxPerPacketInfo]; +}; + +struct ndis_packet_private { + UINT nr_pages; + UINT len; + ndis_buffer *buffer_head; + ndis_buffer *buffer_tail; + struct ndis_packet_pool *pool; + UINT count; + ULONG flags; + BOOLEAN valid_counts; + UCHAR packet_flags; + USHORT oob_offset; +}; + +struct ndis_packet { + struct ndis_packet_private private; + /* for use by miniport */ + union { + /* for connectionless mininports */ + struct { + UCHAR miniport_reserved[2 * sizeof(void *)]; + UCHAR wrapper_reserved[2 * sizeof(void *)]; + } cl_reserved; + /* for deserialized miniports */ + struct { + UCHAR miniport_reserved_ex[3 * sizeof(void *)]; + UCHAR wrapper_reserved_ex[sizeof(void *)]; + } deserailized_reserved; + struct { + UCHAR mac_reserved[4 * sizeof(void *)]; + } mac_reserved; + }; + ULONG_PTR reserved[2]; + UCHAR protocol_reserved[1]; +}; + +/* OOB data */ +struct ndis_packet_oob_data { + union { + ULONGLONG time_to_tx; + ULONGLONG time_txed; + }; + ULONGLONG time_rxed; + UINT header_size; + UINT media_size; + void *media; + NDIS_STATUS status; + + /* ndiswrapper specific info; extension should be right after + * ndis's oob_data */ + struct ndis_packet_extension ext; + union { + /* used for tx only */ + struct { + struct sk_buff *tx_skb; + union { + struct wrap_tx_sg_list wrap_tx_sg_list; + struct ndis_sg_list *tx_sg_list; + }; + }; + /* used for rx only */ + struct { + unsigned char header[ETH_HLEN]; + unsigned char *look_ahead; + UINT look_ahead_size; + }; + }; +}; + +#define NDIS_PACKET_OOB_DATA(packet) \ + (struct ndis_packet_oob_data *)(((void *)(packet)) + \ + (packet)->private.oob_offset) + +enum ndis_device_pnp_event { + NdisDevicePnPEventQueryRemoved, NdisDevicePnPEventRemoved, + NdisDevicePnPEventSurpriseRemoved, NdisDevicePnPEventQueryStopped, + NdisDevicePnPEventStopped, NdisDevicePnPEventPowerProfileChanged, + NdisDevicePnPEventMaximum +}; + +enum ndis_request_type { + NdisRequestQueryInformation, NdisRequestSetInformation, + NdisRequestQueryStatistics, NdisRequestOpen, NdisRequestClose, + NdisRequestSend, NdisRequestTransferData, NdisRequestReset, + NdisRequestGeneric1, NdisRequestGeneric2, NdisRequestGeneric3, + NdisRequestGeneric4 +}; + +struct ndis_request { + mac_address mac; + enum ndis_request_type request_type; + union data { + struct query_info { + UINT oid; + void *buf; + UINT buf_len; + UINT written; + UINT needed; + } query_info; + struct set_info { + UINT oid; + void *buf; + UINT buf_len; + UINT written; + UINT needed; + } set_info; + } data; +}; + +enum ndis_medium { + NdisMedium802_3, NdisMedium802_5, NdisMediumFddi, NdisMediumWan, + NdisMediumLocalTalk, NdisMediumDix, NdisMediumArcnetRaw, + NdisMediumArcnet878_2, NdisMediumAtm, NdisMediumWirelessWan, + NdisMediumIrda, NdisMediumBpc, NdisMediumCoWan, + NdisMedium1394, NdisMediumMax +}; + +enum ndis_physical_medium { + NdisPhysicalMediumUnspecified, NdisPhysicalMediumWirelessLan, + NdisPhysicalMediumCableModem, NdisPhysicalMediumPhoneLine, + NdisPhysicalMediumPowerLine, NdisPhysicalMediumDSL, + NdisPhysicalMediumFibreChannel, NdisPhysicalMedium1394, + NdisPhysicalMediumWirelessWan, NdisPhysicalMediumMax +}; + +enum ndis_power_state { + NdisDeviceStateUnspecified = 0, + NdisDeviceStateD0, NdisDeviceStateD1, NdisDeviceStateD2, + NdisDeviceStateD3, NdisDeviceStateMaximum +}; + +enum ndis_power_profile { + NdisPowerProfileBattery, NdisPowerProfileAcOnLine +}; + +struct ndis_pm_wakeup_capabilities { + enum ndis_power_state min_magic_packet_wakeup; + enum ndis_power_state min_pattern_wakeup; + enum ndis_power_state min_link_change_wakeup; +}; + +#define NDIS_PNP_WAKE_UP_MAGIC_PACKET 0x00000001 +#define NDIS_PNP_WAKE_UP_PATTERN_MATCH 0x00000002 +#define NDIS_PNP_WAKE_UP_LINK_CHANGE 0x00000004 + +enum net_pnp_event_code { + NetEventSetPower, NetEventQueryPower, NetEventQueryRemoveDevice, + NetEventCancelRemoveDevice, NetEventReconfigure, NetEventBindList, + NetEventBindsComplete, NetEventPnPCapabilities, NetEventMaximum +}; + +struct net_pnp_event { + enum net_pnp_event_code code; + void *buf; + ULONG buf_length; + ULONG_PTR ndis_reserved[4]; + ULONG_PTR transport_reserved[4]; + ULONG_PTR tdi_reserved[4]; + ULONG_PTR tdi_client_reserved[4]; +}; + +struct ndis_pnp_capabilities { + ULONG flags; + struct ndis_pm_wakeup_capabilities wakeup; +}; + +typedef void (*ndis_isr_handler)(BOOLEAN *recognized, BOOLEAN *queue_handler, + void *handle) wstdcall; +typedef void (*ndis_interrupt_handler)(void *ctx) wstdcall; + +struct miniport { + /* NDIS 3.0 */ + UCHAR major_version; + UCHAR minor_version; + USHORT filler; + UINT reserved; + BOOLEAN (*hangcheck)(void *ctx) wstdcall; + void (*disable_interrupt)(void *ctx) wstdcall; + void (*enable_interrupt)(void *ctx) wstdcall; + void (*mp_halt)(void *ctx) wstdcall; + ndis_interrupt_handler handle_interrupt; + NDIS_STATUS (*init)(NDIS_STATUS *error_status, UINT *medium_index, + enum ndis_medium medium[], UINT medium_array_size, + void *handle, void *conf_handle) wstdcall; + ndis_isr_handler isr; + NDIS_STATUS (*queryinfo)(void *ctx, ndis_oid oid, void *buffer, + ULONG buflen, ULONG *written, + ULONG *needed) wstdcall; + void *reconfig; + NDIS_STATUS (*reset)(BOOLEAN *reset_address, void *ctx) wstdcall; + NDIS_STATUS (*send)(void *ctx, struct ndis_packet *packet, + UINT flags) wstdcall; + NDIS_STATUS (*setinfo)(void *ctx, ndis_oid oid, void *buffer, + ULONG buflen, ULONG *written, + ULONG *needed) wstdcall; + NDIS_STATUS (*tx_data)(struct ndis_packet *ndis_packet, + UINT *bytes_txed, void *mp_ctx, void *rx_ctx, + UINT offset, UINT bytes_to_tx) wstdcall; + /* NDIS 4.0 extensions */ + void (*return_packet)(void *ctx, void *packet) wstdcall; + void (*send_packets)(void *ctx, struct ndis_packet **packets, + INT nr_of_packets) wstdcall; + void (*alloc_complete)(void *handle, void *virt, + NDIS_PHY_ADDRESS *phys, + ULONG size, void *ctx) wstdcall; + /* NDIS 5.0 extensions */ + NDIS_STATUS (*co_create_vc)(void *ctx, void *vc_handle, + void *vc_ctx) wstdcall; + NDIS_STATUS (*co_delete_vc)(void *vc_ctx) wstdcall; + NDIS_STATUS (*co_activate_vc)(void *vc_ctx, void *call_params) wstdcall; + NDIS_STATUS (*co_deactivate_vc)(void *vc_ctx) wstdcall; + NDIS_STATUS (*co_send_packets)(void *vc_ctx, void **packets, + UINT nr_of_packets) wstdcall; + NDIS_STATUS (*co_request)(void *ctx, void *vc_ctx, UINT *req) wstdcall; + /* NDIS 5.1 extensions */ + void (*cancel_send_packets)(void *ctx, void *id) wstdcall; + void (*pnp_event_notify)(void *ctx, enum ndis_device_pnp_event event, + void *inf_buf, ULONG inf_buf_len) wstdcall; + void (*shutdown)(void *ctx) wstdcall; + void *reserved1; + void *reserved2; + void *reserved3; + void *reserved4; +}; + +struct ndis_spinlock { + NT_SPIN_LOCK klock; + KIRQL irql; +}; + +union ndis_rw_lock_refcount { + UCHAR cache_line[16]; +}; + +struct ndis_rw_lock { + union { + struct { + NT_SPIN_LOCK klock; + void *context; + }; + UCHAR reserved[16]; + }; + union { + union ndis_rw_lock_refcount ref_count[MAXIMUM_PROCESSORS]; + /* ndiswrapper specific */ + volatile int count; + }; +}; + +struct lock_state { + USHORT state; + KIRQL irql; +}; + +struct ndis_work_item; +typedef void (*NDIS_PROC)(struct ndis_work_item *, void *) wstdcall; + +struct ndis_work_item { + void *ctx; + NDIS_PROC func; + union { + UCHAR reserved[8 * sizeof(void *)]; + /* ndiswrapper specific */ + struct nt_list list; + }; +}; + +struct alloc_shared_mem { + void *ctx; + ULONG size; + BOOLEAN cached; +}; + +struct ndis_mp_block; + +/* this is opaque to drivers, so we can use it as we please */ +struct ndis_mp_interrupt { + struct kinterrupt *kinterrupt; + NT_SPIN_LOCK lock; + union { + void *reserved; + unsigned int irq; + }; + ndis_isr_handler isr; + ndis_interrupt_handler mp_dpc; + struct kdpc intr_dpc; + struct ndis_mp_block *nmb; + UCHAR dpc_count; + BOOLEAN enable; + struct nt_event dpc_completed_event; + BOOLEAN shared; + BOOLEAN req_isr; +}; + +struct ndis_binary_data { + USHORT len; + void *buf; +}; + +enum ndis_parameter_type { + NdisParameterInteger, NdisParameterHexInteger, + NdisParameterString, NdisParameterMultiString, NdisParameterBinary, +}; + +typedef struct unicode_string NDIS_STRING; + +struct ndis_configuration_parameter { + enum ndis_parameter_type type; + union { + ULONG integer; + NDIS_STRING string; + } data; +}; + +struct ndis_driver { + struct miniport mp; +}; + +/* IDs used to store extensions in driver_object's custom extension */ +#define NDIS_DRIVER_CLIENT_ID 10 + +struct ndis_wireless_stats { + ULONG length; + LARGE_INTEGER tx_frag; + LARGE_INTEGER tx_multi_frag; + LARGE_INTEGER failed; + LARGE_INTEGER retry; + LARGE_INTEGER multi_retry; + LARGE_INTEGER rtss_succ; + LARGE_INTEGER rtss_fail; + LARGE_INTEGER ack_fail; + LARGE_INTEGER frame_dup; + LARGE_INTEGER rx_frag; + LARGE_INTEGER rx_multi_frag; + LARGE_INTEGER fcs_err; + LARGE_INTEGER tkip_local_mic_failures; + LARGE_INTEGER tkip_icv_errors; + LARGE_INTEGER tkip_counter_measures_invoked; + LARGE_INTEGER tkip_replays; + LARGE_INTEGER ccmp_format_errors; + LARGE_INTEGER ccmp_replays; + LARGE_INTEGER ccmp_decrypt_errors; + LARGE_INTEGER fourway_handshake_failures; + LARGE_INTEGER wep_undecryptable_count; + LARGE_INTEGER wep_icv_errorcount; + LARGE_INTEGER decrypt_success_count; + LARGE_INTEGER decrypt_failure_count; +}; + +enum ndis_status_type { + Ndis802_11StatusType_Authentication, + Ndis802_11StatusType_MediaStreamMode, + Ndis802_11StatusType_PMKID_CandidateList, + Ndis802_11StatusType_RadioState, +}; + +struct ndis_status_indication { + enum ndis_status_type status_type; +}; + +enum ndis_radio_status { + Ndis802_11RadioStatusOn, Ndis802_11RadioStatusHardwareOff, + Ndis802_11RadioStatusSoftwareOff, +}; + +struct ndis_radio_status_indication +{ + enum ndis_status_type status_type; + enum ndis_radio_status radio_state; +}; + +enum ndis_media_stream_mode { + Ndis802_11MediaStreamOff, Ndis802_11MediaStreamOn +}; + +enum wrapper_work { + LINK_STATUS_OFF, LINK_STATUS_ON, SET_MULTICAST_LIST, COLLECT_IW_STATS, + HANGCHECK, NETIF_WAKEQ, +}; + +struct encr_info { + struct encr_key { + ULONG length; + UCHAR key[NDIS_ENCODING_TOKEN_MAX]; + } keys[MAX_ENCR_KEYS]; + unsigned short tx_key_index; +}; + +struct ndis_essid { + ULONG length; + UCHAR essid[NDIS_ESSID_MAX_SIZE]; +}; + +enum ndis_infrastructure_mode { + Ndis802_11IBSS, Ndis802_11Infrastructure, Ndis802_11AutoUnknown, + Ndis802_11InfrastructureMax +}; + +enum authentication_mode { + Ndis802_11AuthModeOpen, Ndis802_11AuthModeShared, + Ndis802_11AuthModeAutoSwitch, Ndis802_11AuthModeWPA, + Ndis802_11AuthModeWPAPSK, Ndis802_11AuthModeWPANone, + Ndis802_11AuthModeWPA2, Ndis802_11AuthModeWPA2PSK, + Ndis802_11AuthModeMax +}; + +enum encryption_status { + Ndis802_11WEPEnabled, + Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, + Ndis802_11WEPDisabled, + Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, + Ndis802_11WEPKeyAbsent, + Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, + Ndis802_11WEPNotSupported, + Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, + Ndis802_11Encryption2Enabled, Ndis802_11Encryption2KeyAbsent, + Ndis802_11Encryption3Enabled, Ndis802_11Encryption3KeyAbsent +}; + +struct ndis_auth_encr_pair { + enum authentication_mode auth_mode; + enum encryption_status encr_mode; +}; + +struct ndis_capability { + ULONG length; + ULONG version; + ULONG num_PMKIDs; + ULONG num_auth_encr_pair; + struct ndis_auth_encr_pair auth_encr_pair[1]; +}; + +struct ndis_guid { + struct guid guid; + union { + ndis_oid oid; + NDIS_STATUS status; + }; + ULONG size; + ULONG flags; +}; + +struct ndis_timer { + struct nt_timer nt_timer; + struct kdpc kdpc; +}; + +struct ndis_mp_timer { + struct nt_timer nt_timer; + struct kdpc kdpc; + DPC func; + void *ctx; + struct ndis_mp_block *nmb; + struct ndis_mp_timer *next; +}; + +typedef struct cm_partial_resource_list NDIS_RESOURCE_LIST; + +struct ndis_event { + struct nt_event nt_event; +}; + +struct ndis_bind_paths { + UINT number; + struct unicode_string paths[1]; +}; + +struct ndis_reference { + NT_SPIN_LOCK lock; + USHORT ref_count; + BOOLEAN closing; +}; + +struct ndis_filterdbs { + union { + void *eth_db; + void *null_db; + }; + void *tr_db; + void *fddi_db; + void *arc_db; +}; + +enum ndis_interface_type { + NdisInterfaceInternal, NdisInterfaceIsa, NdisInterfaceEisa, + NdisInterfaceMca, NdisInterfaceTurboChannel, NdisInterfacePci, + NdisInterfacePcMcia, +}; + +struct auth_encr_capa { + unsigned long auth; + unsigned long encr; +}; + +struct ndis_pmkid_candidate { + mac_address bssid; + DWORD flags; +}; + +struct ndis_pmkid_candidate_list { + ULONG version; + ULONG num_candidates; + struct ndis_pmkid_candidate candidates[1]; +}; + +/* + * This struct contains function pointers that the drivers references + * directly via macros, so it's important that they are at the correct + * position. + */ +struct ndis_mp_block { + void *signature; + struct ndis_mp_block *next; + struct driver_object *drv_obj; + void *mp_ctx; + struct unicode_string name; + struct ndis_bind_paths *bindpaths; + void *openqueue; + struct ndis_reference reference; + void *device_ctx; + UCHAR padding; + UCHAR lock_acquired; + UCHAR pmode_opens; + UCHAR assigned_cpu; + NT_SPIN_LOCK lock; + enum ndis_request_type *mediarequest; + struct ndis_mp_interrupt *interrupt; + ULONG flags; + ULONG pnp_flags; + struct nt_list packet_list; + struct ndis_packet *first_pending_tx_packet; + struct ndis_packet *return_packet_queue; + ULONG request_buffer; + void *set_mcast_buffer; + struct ndis_mp_block *primary_mp; + void *wrapper_ctx; + void *bus_data_ctx; + ULONG pnp_capa; + void *resources; + struct ndis_timer wakeup_dpc_timer; + struct unicode_string basename; + struct unicode_string symlink_name; + ULONG ndis_hangcheck_interval; + USHORT hanghcheck_ticks; + USHORT hangcheck_tick; + NDIS_STATUS ndis_reset_status; + void *resetopen; + struct ndis_filterdbs filterdbs; + void *rx_packet; + void *send_complete; + void *send_resource_avail; + void *reset_complete; + + enum ndis_medium media_type; + ULONG bus_number; + enum ndis_interface_type bus_type; + enum ndis_interface_type adapter_type; + struct device_object *fdo; + struct device_object *pdo; + struct device_object *next_device; + void *mapreg; + void *call_mgraflist; + void *mp_thread; + void *setinfobuf; + USHORT setinfo_buf_len; + USHORT max_send_pkts; + NDIS_STATUS fake_status; + void *lock_handler; + struct unicode_string *adapter_instance_name; + void *timer_queue; + UINT mac_options; + void *pending_req; + UINT max_long_addrs; + UINT max_short_addrs; + UINT cur_lookahead; + UINT max_lookahead; + + ndis_interrupt_handler irq_bh; + void *disable_intr; + void *enable_intr; + void *send_pkts; + void *deferred_send; + void *eth_rx_indicate; + void *tr_rx_indicate; + void *fddi_rx_indicate; + void *eth_rx_complete; + void *tr_rx_complete; + void *fddi_rx_complete; + + void *status; + void *status_complete; + void *td_complete; + + void *queryinfo_complete; + void *setinfo_complete; + void *wan_tx_complete; + void *wan_rx; + void *wan_rx_complete; + /* ndiswrapper specific */ + struct ndis_device *wnd; +}; + +struct ndis_device { + struct ndis_mp_block *nmb; + struct wrap_device *wd; + struct net_device *net_dev; + void *shutdown_ctx; + struct ndis_mp_interrupt *mp_interrupt; + struct kdpc irq_kdpc; + unsigned long mem_start; + unsigned long mem_end; + + struct net_device_stats net_stats; + struct iw_statistics iw_stats; + BOOLEAN iw_stats_enabled; + struct ndis_wireless_stats ndis_stats; + + work_struct_t tx_work; + struct ndis_packet *tx_ring[TX_RING_SIZE]; + u8 tx_ring_start; + u8 tx_ring_end; + u8 is_tx_ring_full; + u8 tx_ok; + spinlock_t tx_ring_lock; + struct semaphore tx_ring_mutex; + unsigned int max_tx_packets; + struct semaphore ndis_req_mutex; + struct task_struct *ndis_req_task; + int ndis_req_done; + NDIS_STATUS ndis_req_status; + ULONG packet_filter; + + ULONG sg_dma_size; + ULONG dma_map_count; + dma_addr_t *dma_map_addr; + + int hangcheck_interval; + struct timer_list hangcheck_timer; + int iw_stats_interval; + struct timer_list iw_stats_timer; + unsigned long scan_timestamp; + struct encr_info encr_info; + char nick[IW_ESSID_MAX_SIZE + 1]; + struct ndis_essid essid; + struct auth_encr_capa capa; + enum ndis_infrastructure_mode infrastructure_mode; + int max_pmkids; + int num_pmkids; + struct ndis_pmkid *pmkids; + mac_address mac; + struct proc_dir_entry *procfs_iface; + + work_struct_t ndis_work; + unsigned long ndis_pending_work; + UINT attributes; + int iw_auth_wpa_version; + int iw_auth_cipher_pairwise; + int iw_auth_cipher_group; + int iw_auth_key_mgmt; + int iw_auth_80211_alg; + struct ndis_packet_pool *tx_packet_pool; + struct ndis_buffer_pool *tx_buffer_pool; + int multicast_size; + struct v4_checksum rx_csum; + struct v4_checksum tx_csum; + enum ndis_physical_medium physical_medium; + ULONG ndis_wolopts; + struct nt_slist wrap_timer_slist; + int drv_ndis_version; + struct ndis_pnp_capabilities pnp_capa; + char netdev_name[IFNAMSIZ]; +}; + +BOOLEAN ndis_isr(struct kinterrupt *kinterrupt, void *ctx) wstdcall; + +int ndis_init(void); +void ndis_exit(void); +int ndis_init_device(struct ndis_device *wnd); +void ndis_exit_device(struct ndis_device *wnd); + +int wrap_procfs_add_ndis_device(struct ndis_device *wnd); +void wrap_procfs_remove_ndis_device(struct ndis_device *wnd); + +void NdisAllocatePacketPoolEx(NDIS_STATUS *status, + struct ndis_packet_pool **pool_handle, + UINT num_descr, UINT overflowsize, + UINT proto_rsvd_length) wstdcall; +void NdisFreePacketPool(struct ndis_packet_pool *pool) wstdcall; +void NdisAllocatePacket(NDIS_STATUS *status, struct ndis_packet **packet, + struct ndis_packet_pool *pool) wstdcall; +void NdisFreePacket(struct ndis_packet *descr) wstdcall; +void NdisAllocateBufferPool(NDIS_STATUS *status, + struct ndis_buffer_pool **pool_handle, + UINT num_descr) wstdcall; +void NdisFreeBufferPool(struct ndis_buffer_pool *pool) wstdcall; +void NdisAllocateBuffer(NDIS_STATUS *status, ndis_buffer **buffer, + struct ndis_buffer_pool *pool, void *virt, + UINT length) wstdcall; +void NdisFreeBuffer(ndis_buffer *descr) wstdcall; +void NdisMIndicateReceivePacket(struct ndis_mp_block *nmb, + struct ndis_packet **packets, + UINT nr_packets) wstdcall; +void NdisMSendComplete(struct ndis_mp_block *nmb, struct ndis_packet *packet, + NDIS_STATUS status) wstdcall; +void NdisMSendResourcesAvailable(struct ndis_mp_block *nmb) wstdcall; +void NdisMIndicateStatus(struct ndis_mp_block *nmb, + NDIS_STATUS status, void *buf, UINT len) wstdcall; +void NdisMIndicateStatusComplete(struct ndis_mp_block *nmb) wstdcall; +void NdisMQueryInformationComplete(struct ndis_mp_block *nmb, + NDIS_STATUS status) wstdcall; +void NdisMSetInformationComplete(struct ndis_mp_block *nmb, + NDIS_STATUS status) wstdcall; +void NdisMResetComplete(struct ndis_mp_block *nmb, NDIS_STATUS status, + BOOLEAN address_reset) wstdcall; +ULONG NDIS_BUFFER_TO_SPAN_PAGES(ndis_buffer *buffer) wstdcall; +BOOLEAN NdisWaitEvent(struct ndis_event *event, UINT timeout) wstdcall; +void NdisSetEvent(struct ndis_event *event) wstdcall; +void NdisMDeregisterInterrupt(struct ndis_mp_interrupt *mp_interrupt) wstdcall; +void EthRxIndicateHandler(struct ndis_mp_block *nmb, void *rx_ctx, + char *header1, char *header, UINT header_size, + void *look_ahead, UINT look_ahead_size, + UINT packet_size) wstdcall; +void EthRxComplete(struct ndis_mp_block *nmb) wstdcall; +void NdisMTransferDataComplete(struct ndis_mp_block *nmb, + struct ndis_packet *packet, NDIS_STATUS status, + UINT bytes_txed) wstdcall; +void NdisWriteConfiguration(NDIS_STATUS *status, struct ndis_mp_block *nmb, + struct unicode_string *key, + struct ndis_configuration_parameter *param) wstdcall; +void NdisReadConfiguration(NDIS_STATUS *status, + struct ndis_configuration_parameter **param, + struct ndis_mp_block *nmb, + struct unicode_string *key, + enum ndis_parameter_type type) wstdcall; + +/* Required OIDs */ +#define OID_GEN_SUPPORTED_LIST 0x00010101 +#define OID_GEN_HARDWARE_STATUS 0x00010102 +#define OID_GEN_MEDIA_SUPPORTED 0x00010103 +#define OID_GEN_MEDIA_IN_USE 0x00010104 +#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105 +#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106 +#define OID_GEN_LINK_SPEED 0x00010107 +#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108 +#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109 +#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A +#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B +#define OID_GEN_VENDOR_ID 0x0001010C +#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D +#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E +#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F +#define OID_GEN_DRIVER_VERSION 0x00010110 +#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111 +#define OID_GEN_PROTOCOL_OPTIONS 0x00010112 +#define OID_GEN_MAC_OPTIONS 0x00010113 +#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114 +#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115 +#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116 +#define OID_GEN_SUPPORTED_GUIDS 0x00010117 +#define OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118 /* Set only */ +#define OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119 /* Set only */ +#define OID_GEN_MACHINE_NAME 0x0001021A +#define OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B /* Set only */ +#define OID_GEN_VLAN_ID 0x0001021C + +/* Optional OIDs. */ +#define OID_GEN_MEDIA_CAPABILITIES 0x00010201 +#define OID_GEN_PHYSICAL_MEDIUM 0x00010202 + +/* Required statistics OIDs. */ +#define OID_GEN_XMIT_OK 0x00020101 +#define OID_GEN_RCV_OK 0x00020102 +#define OID_GEN_XMIT_ERROR 0x00020103 +#define OID_GEN_RCV_ERROR 0x00020104 +#define OID_GEN_RCV_NO_BUFFER 0x00020105 + +/* Optional OID statistics */ +#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 +#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202 +#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 +#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204 +#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 +#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206 +#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207 +#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208 +#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209 +#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A +#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B +#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C +#define OID_GEN_RCV_CRC_ERROR 0x0002020D +#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E +#define OID_GEN_GET_TIME_CAPS 0x0002020F +#define OID_GEN_GET_NETCARD_TIME 0x00020210 +#define OID_GEN_NETCARD_LOAD 0x00020211 +#define OID_GEN_DEVICE_PROFILE 0x00020212 + +/* 802.3 (ethernet) OIDs */ +#define OID_802_3_PERMANENT_ADDRESS 0x01010101 +#define OID_802_3_CURRENT_ADDRESS 0x01010102 +#define OID_802_3_MULTICAST_LIST 0x01010103 +#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 +#define OID_802_3_MAC_OPTIONS 0x01010105 +#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001 +#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101 +#define OID_802_3_XMIT_ONE_COLLISION 0x01020102 +#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103 +#define OID_802_3_XMIT_DEFERRED 0x01020201 +#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202 +#define OID_802_3_RCV_OVERRUN 0x01020203 +#define OID_802_3_XMIT_UNDERRUN 0x01020204 +#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205 +#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206 +#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207 + +/* PnP and power management OIDs */ +#define OID_PNP_CAPABILITIES 0xFD010100 +#define OID_PNP_SET_POWER 0xFD010101 +#define OID_PNP_QUERY_POWER 0xFD010102 +#define OID_PNP_ADD_WAKE_UP_PATTERN 0xFD010103 +#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xFD010104 +#define OID_PNP_WAKE_UP_PATTERN_LIST 0xFD010105 +#define OID_PNP_ENABLE_WAKE_UP 0xFD010106 + +/* PnP/PM Statistics (Optional). */ +#define OID_PNP_WAKE_UP_OK 0xFD020200 +#define OID_PNP_WAKE_UP_ERROR 0xFD020201 + +/* The following bits are defined for OID_PNP_ENABLE_WAKE_UP */ +#define NDIS_PNP_WAKE_UP_MAGIC_PACKET 0x00000001 +#define NDIS_PNP_WAKE_UP_PATTERN_MATCH 0x00000002 +#define NDIS_PNP_WAKE_UP_LINK_CHANGE 0x00000004 + +/* 802.11 OIDs */ +#define OID_802_11_BSSID 0x0D010101 +#define OID_802_11_SSID 0x0D010102 +#define OID_802_11_NETWORK_TYPES_SUPPORTED 0x0D010203 +#define OID_802_11_NETWORK_TYPE_IN_USE 0x0D010204 +#define OID_802_11_TX_POWER_LEVEL 0x0D010205 +#define OID_802_11_RSSI 0x0D010206 +#define OID_802_11_RSSI_TRIGGER 0x0D010207 +#define OID_802_11_INFRASTRUCTURE_MODE 0x0D010108 +#define OID_802_11_FRAGMENTATION_THRESHOLD 0x0D010209 +#define OID_802_11_RTS_THRESHOLD 0x0D01020A +#define OID_802_11_NUMBER_OF_ANTENNAS 0x0D01020B +#define OID_802_11_RX_ANTENNA_SELECTED 0x0D01020C +#define OID_802_11_TX_ANTENNA_SELECTED 0x0D01020D +#define OID_802_11_SUPPORTED_RATES 0x0D01020E +#define OID_802_11_DESIRED_RATES 0x0D010210 +#define OID_802_11_CONFIGURATION 0x0D010211 +#define OID_802_11_STATISTICS 0x0D020212 +#define OID_802_11_ADD_WEP 0x0D010113 +#define OID_802_11_REMOVE_WEP 0x0D010114 +#define OID_802_11_DISASSOCIATE 0x0D010115 +#define OID_802_11_POWER_MODE 0x0D010216 +#define OID_802_11_BSSID_LIST 0x0D010217 +#define OID_802_11_AUTHENTICATION_MODE 0x0D010118 +#define OID_802_11_PRIVACY_FILTER 0x0D010119 +#define OID_802_11_BSSID_LIST_SCAN 0x0D01011A +#define OID_802_11_WEP_STATUS 0x0D01011B +#define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS +#define OID_802_11_RELOAD_DEFAULTS 0x0D01011C +#define OID_802_11_ADD_KEY 0x0D01011D +#define OID_802_11_REMOVE_KEY 0x0D01011E +#define OID_802_11_ASSOCIATION_INFORMATION 0x0D01011F +#define OID_802_11_TEST 0x0D010120 +#define OID_802_11_MEDIA_STREAM_MODE 0x0D010121 +#define OID_802_11_CAPABILITY 0x0D010122 +#define OID_802_11_PMKID 0x0D010123 + +#define NDIS_STATUS_SUCCESS 0 +#define NDIS_STATUS_PENDING 0x00000103 +#define NDIS_STATUS_NOT_RECOGNIZED 0x00010001 +#define NDIS_STATUS_NOT_COPIED 0x00010002 +#define NDIS_STATUS_NOT_ACCEPTED 0x00010003 +#define NDIS_STATUS_CALL_ACTIVE 0x00010007 +#define NDIS_STATUS_ONLINE 0x40010003 +#define NDIS_STATUS_RESET_START 0x40010004 +#define NDIS_STATUS_RESET_END 0x40010005 +#define NDIS_STATUS_RING_STATUS 0x40010006 +#define NDIS_STATUS_CLOSED 0x40010007 +#define NDIS_STATUS_WAN_LINE_UP 0x40010008 +#define NDIS_STATUS_WAN_LINE_DOWN 0x40010009 +#define NDIS_STATUS_WAN_FRAGMENT 0x4001000A +#define NDIS_STATUS_MEDIA_CONNECT 0x4001000B +#define NDIS_STATUS_MEDIA_DISCONNECT 0x4001000C +#define NDIS_STATUS_HARDWARE_LINE_UP 0x4001000D +#define NDIS_STATUS_HARDWARE_LINE_DOWN 0x4001000E +#define NDIS_STATUS_INTERFACE_UP 0x4001000F +#define NDIS_STATUS_INTERFACE_DOWN 0x40010010 +#define NDIS_STATUS_MEDIA_BUSY 0x40010011 +#define NDIS_STATUS_MEDIA_SPECIFIC_INDICATION 0x40010012 +#define NDIS_STATUS_WW_INDICATION NDIS_STATUS_MEDIA_SPECIFIC_INDICATION +#define NDIS_STATUS_LINK_SPEED_CHANGE 0x40010013 +#define NDIS_STATUS_WAN_GET_STATS 0x40010014 +#define NDIS_STATUS_WAN_CO_FRAGMENT 0x40010015 +#define NDIS_STATUS_WAN_CO_LINKPARAMS 0x40010016 +#define NDIS_STATUS_NOT_RESETTABLE 0x80010001 +#define NDIS_STATUS_SOFT_ERRORS 0x80010003 +#define NDIS_STATUS_HARD_ERRORS 0x80010004 +#define NDIS_STATUS_BUFFER_OVERFLOW 0x80000005 +#define NDIS_STATUS_FAILURE 0xC0000001 +#define NDIS_STATUS_INVALID_PARAMETER 0xC000000D +#define NDIS_STATUS_RESOURCES 0xC000009A +#define NDIS_STATUS_CLOSING 0xC0010002 +#define NDIS_STATUS_BAD_VERSION 0xC0010004 +#define NDIS_STATUS_BAD_CHARACTERISTICS 0xC0010005 +#define NDIS_STATUS_ADAPTER_NOT_FOUND 0xC0010006 +#define NDIS_STATUS_OPEN_FAILED 0xC0010007 +#define NDIS_STATUS_DEVICE_FAILED 0xC0010008 +#define NDIS_STATUS_MULTICAST_FULL 0xC0010009 +#define NDIS_STATUS_MULTICAST_EXISTS 0xC001000A +#define NDIS_STATUS_MULTICAST_NOT_FOUND 0xC001000B +#define NDIS_STATUS_REQUEST_ABORTED 0xC001000C +#define NDIS_STATUS_RESET_IN_PROGRESS 0xC001000D +#define NDIS_STATUS_CLOSING_INDICATING 0xC001000E +#define NDIS_STATUS_BAD_VERSION 0xC0010004 +#define NDIS_STATUS_NOT_SUPPORTED 0xC00000BB +#define NDIS_STATUS_INVALID_PACKET 0xC001000F +#define NDIS_STATUS_OPEN_LIST_FULL 0xC0010010 +#define NDIS_STATUS_ADAPTER_NOT_READY 0xC0010011 +#define NDIS_STATUS_ADAPTER_NOT_OPEN 0xC0010012 +#define NDIS_STATUS_NOT_INDICATING 0xC0010013 +#define NDIS_STATUS_INVALID_LENGTH 0xC0010014 +#define NDIS_STATUS_INVALID_DATA 0xC0010015 +#define NDIS_STATUS_BUFFER_TOO_SHORT 0xC0010016 +#define NDIS_STATUS_INVALID_OID 0xC0010017 +#define NDIS_STATUS_ADAPTER_REMOVED 0xC0010018 +#define NDIS_STATUS_UNSUPPORTED_MEDIA 0xC0010019 +#define NDIS_STATUS_GROUP_ADDRESS_IN_USE 0xC001001A +#define NDIS_STATUS_FILE_NOT_FOUND 0xC001001B +#define NDIS_STATUS_ERROR_READING_FILE 0xC001001C +#define NDIS_STATUS_ALREADY_MAPPED 0xC001001D +#define NDIS_STATUS_RESOURCE_CONFLICT 0xC001001E +#define NDIS_STATUS_NO_CABLE 0xC001001F +#define NDIS_STATUS_INVALID_SAP 0xC0010020 +#define NDIS_STATUS_SAP_IN_USE 0xC0010021 +#define NDIS_STATUS_INVALID_ADDRESS 0xC0010022 +#define NDIS_STATUS_VC_NOT_ACTIVATED 0xC0010023 +#define NDIS_STATUS_DEST_OUT_OF_ORDER 0xC0010024 +#define NDIS_STATUS_VC_NOT_AVAILABLE 0xC0010025 +#define NDIS_STATUS_CELLRATE_NOT_AVAILABLE 0xC0010026 +#define NDIS_STATUS_INCOMPATABLE_QOS 0xC0010027 +#define NDIS_STATUS_AAL_PARAMS_UNSUPPORTED 0xC0010028 +#define NDIS_STATUS_NO_ROUTE_TO_DESTINATION 0xC0010029 +#define NDIS_STATUS_TOKEN_RING_OPEN_ERROR 0xC0011000 +#define NDIS_STATUS_INVALID_DEVICE_REQUEST 0xC0000010 +#define NDIS_STATUS_NETWORK_UNREACHABLE 0xC000023C + +/* Event codes */ + +#define EVENT_NDIS_RESOURCE_CONFLICT 0xC0001388 +#define EVENT_NDIS_OUT_OF_RESOURCE 0xC0001389 +#define EVENT_NDIS_HARDWARE_FAILURE 0xC000138A +#define EVENT_NDIS_ADAPTER_NOT_FOUND 0xC000138B +#define EVENT_NDIS_INTERRUPT_CONNECT 0xC000138C +#define EVENT_NDIS_DRIVER_FAILURE 0xC000138D +#define EVENT_NDIS_BAD_VERSION 0xC000138E +#define EVENT_NDIS_TIMEOUT 0x8000138F +#define EVENT_NDIS_NETWORK_ADDRESS 0xC0001390 +#define EVENT_NDIS_UNSUPPORTED_CONFIGURATION 0xC0001391 +#define EVENT_NDIS_INVALID_VALUE_FROM_ADAPTER 0xC0001392 +#define EVENT_NDIS_MISSING_CONFIGURATION_PARAMETER 0xC0001393 +#define EVENT_NDIS_BAD_IO_BASE_ADDRESS 0xC0001394 +#define EVENT_NDIS_RECEIVE_SPACE_SMALL 0x40001395 +#define EVENT_NDIS_ADAPTER_DISABLED 0x80001396 +#define EVENT_NDIS_IO_PORT_CONFLICT 0x80001397 +#define EVENT_NDIS_PORT_OR_DMA_CONFLICT 0x80001398 +#define EVENT_NDIS_MEMORY_CONFLICT 0x80001399 +#define EVENT_NDIS_INTERRUPT_CONFLICT 0x8000139A +#define EVENT_NDIS_DMA_CONFLICT 0x8000139B +#define EVENT_NDIS_INVALID_DOWNLOAD_FILE_ERROR 0xC000139C +#define EVENT_NDIS_MAXRECEIVES_ERROR 0x8000139D +#define EVENT_NDIS_MAXTRANSMITS_ERROR 0x8000139E +#define EVENT_NDIS_MAXFRAMESIZE_ERROR 0x8000139F +#define EVENT_NDIS_MAXINTERNALBUFS_ERROR 0x800013A0 +#define EVENT_NDIS_MAXMULTICAST_ERROR 0x800013A1 +#define EVENT_NDIS_PRODUCTID_ERROR 0x800013A2 +#define EVENT_NDIS_LOBE_FAILUE_ERROR 0x800013A3 +#define EVENT_NDIS_SIGNAL_LOSS_ERROR 0x800013A4 +#define EVENT_NDIS_REMOVE_RECEIVED_ERROR 0x800013A5 +#define EVENT_NDIS_TOKEN_RING_CORRECTION 0x400013A6 +#define EVENT_NDIS_ADAPTER_CHECK_ERROR 0xC00013A7 +#define EVENT_NDIS_RESET_FAILURE_ERROR 0x800013A8 +#define EVENT_NDIS_CABLE_DISCONNECTED_ERROR 0x800013A9 +#define EVENT_NDIS_RESET_FAILURE_CORRECTION 0x800013AA + +/* packet filter bits used by NDIS_OID_PACKET_FILTER */ +#define NDIS_PACKET_TYPE_DIRECTED 0x00000001 +#define NDIS_PACKET_TYPE_MULTICAST 0x00000002 +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 +#define NDIS_PACKET_TYPE_BROADCAST 0x00000008 +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 +#define NDIS_PACKET_TYPE_SMT 0x00000040 +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080 +#define NDIS_PACKET_TYPE_GROUP 0x00001000 +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00002000 +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00004000 +#define NDIS_PACKET_TYPE_MAC_FRAME 0x00008000 + +/* memory allocation flags */ +#define NDIS_MEMORY_CONTIGUOUS 0x00000001 +#define NDIS_MEMORY_NONCACHED 0x00000002 + +/* Atrribute flags to NdisMSetAtrributesEx */ +#define NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT 0x00000001 +#define NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT 0x00000002 +#define NDIS_ATTRIBUTE_IGNORE_TOKEN_RING_ERRORS 0x00000004 +#define NDIS_ATTRIBUTE_BUS_MASTER 0x00000008 +#define NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER 0x00000010 +#define NDIS_ATTRIBUTE_DESERIALIZE 0x00000020 +#define NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND 0x00000040 +#define NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK 0x00000080 +#define NDIS_ATTRIBUTE_NOT_CO_NDIS 0x00000100 +#define NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS 0x00000200 + +#define OID_TCP_TASK_OFFLOAD 0xFC010201 + +#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA 0x00000001 +#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED 0x00000002 +#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND 0x00000004 +#define NDIS_MAC_OPTION_NO_LOOPBACK 0x00000008 +#define NDIS_MAC_OPTION_FULL_DUPLEX 0x00000010 +#define NDIS_MAC_OPTION_EOTX_INDICATION 0x00000020 +#define NDIS_MAC_OPTION_8021P_PRIORITY 0x00000040 +#define NDIS_MAC_OPTION_SUPPORTS_MAC_ADDRESS_OVERWRITE 0x00000080 +#define NDIS_MAC_OPTION_RECEIVE_AT_DPC 0x00000100 +#define NDIS_MAC_OPTION_8021Q_VLAN 0x00000200 +#define NDIS_MAC_OPTION_RESERVED 0x80000000 + +#define deserialized_driver(wnd) (wnd->attributes & NDIS_ATTRIBUTE_DESERIALIZE) + +static inline void serialize_lock(struct ndis_device *wnd) +{ + nt_spin_lock(&wnd->nmb->lock); +} + +static inline void serialize_unlock(struct ndis_device *wnd) +{ + nt_spin_unlock(&wnd->nmb->lock); +} + +static inline KIRQL serialize_lock_irql(struct ndis_device *wnd) +{ + if (deserialized_driver(wnd)) + return raise_irql(DISPATCH_LEVEL); + else + return nt_spin_lock_irql(&wnd->nmb->lock, DISPATCH_LEVEL); +} + +static inline void serialize_unlock_irql(struct ndis_device *wnd, + KIRQL irql) +{ + if (deserialized_driver(wnd)) + lower_irql(irql); + else + nt_spin_unlock_irql(&wnd->nmb->lock, irql); +} + +static inline void if_serialize_lock(struct ndis_device *wnd) +{ + if (!deserialized_driver(wnd)) + nt_spin_lock(&wnd->nmb->lock); +} + +static inline void if_serialize_unlock(struct ndis_device *wnd) +{ + if (!deserialized_driver(wnd)) + nt_spin_unlock(&wnd->nmb->lock); +} + +#endif /* NDIS_H */ --- linux-2.6.27.orig/ubuntu/ndiswrapper/ndiswrapper.h +++ linux-2.6.27/ubuntu/ndiswrapper/ndiswrapper.h @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _NDISWRAPPER_H_ +#define _NDISWRAPPER_H_ + +#define DRIVER_VERSION "1.53" +#define UTILS_VERSION "1.9" + +#define DRIVER_NAME "ndiswrapper" +#define DRIVER_CONFIG_DIR "/etc/ndiswrapper" + +#define SSID_MAX_WPA_IE_LEN 40 +#define NDIS_ESSID_MAX_SIZE 32 +#define NDIS_ENCODING_TOKEN_MAX 32 +#define MAX_ENCR_KEYS 4 +#define TX_RING_SIZE 16 +#define NDIS_MAX_RATES 8 +#define NDIS_MAX_RATES_EX 16 +#define WLAN_EID_GENERIC 221 +#define MAX_WPA_IE_LEN 64 +#define MAX_STR_LEN 512 + +#define WRAP_PCI_BUS 5 +#define WRAP_PCMCIA_BUS 8 +/* some USB devices, e.g., DWL-G120 have BusType as 0 */ +#define WRAP_INTERNAL_BUS 0 +/* documentation at msdn says 15 is PNP bus, but inf files from all + * vendors say 15 is USB; which is correct? */ +#define WRAP_USB_BUS 15 + +/* NDIS device must be 0, for compatability with old versions of + * ndiswrapper where device type for NDIS drivers is 0 */ +#define WRAP_NDIS_DEVICE 0 +#define WRAP_USB_DEVICE 1 +#define WRAP_BLUETOOTH_DEVICE1 2 +#define WRAP_BLUETOOTH_DEVICE2 3 + +#define WRAP_DEVICE_BUS(dev, bus) ((dev) << 8 | (bus)) +#define WRAP_BUS(dev_bus) ((dev_bus) & 0x000FF) +#define WRAP_DEVICE(dev_bus) ((dev_bus) >> 8) + +#define MAX_DRIVER_NAME_LEN 32 +#define MAX_VERSION_STRING_LEN 64 +#define MAX_SETTING_NAME_LEN 128 +#define MAX_SETTING_VALUE_LEN 256 + +#define MAX_DRIVER_PE_IMAGES 4 +#define MAX_DRIVER_BIN_FILES 5 +#define MAX_DEVICE_SETTINGS 512 + +#define MAX_ALLOCATED_URBS 15 + +#define DEV_ANY_ID -1 + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTRSEP "%02x:%02x:%02x:%02x:%02x:%02x" +#define MACSTR "%02x%02x%02x%02x%02x%02x" +#define MACINTADR(a) (int*)&((a)[0]), (int*)&((a)[1]), (int*)&((a)[2]), \ + (int*)&((a)[3]), (int*)&((a)[4]), (int*)&((a)[5]) + +#ifdef __KERNEL__ +/* DEBUG macros */ + +#define MSG(level, fmt, ...) \ + printk(level "ndiswrapper (%s:%d): " fmt "\n", \ + __FUNCTION__, __LINE__ , ## __VA_ARGS__) + +#define WARNING(fmt, ...) MSG(KERN_WARNING, fmt, ## __VA_ARGS__) +#define ERROR(fmt, ...) MSG(KERN_ERR, fmt , ## __VA_ARGS__) +#define INFO(fmt, ...) MSG(KERN_INFO, fmt , ## __VA_ARGS__) +#define TODO() WARNING("not fully implemented (yet)") + +#define TRACE(fmt, ...) do { } while (0) +#define TRACE1(fmt, ...) do { } while (0) +#define TRACE2(fmt, ...) do { } while (0) +#define TRACE3(fmt, ...) do { } while (0) +#define TRACE4(fmt, ...) do { } while (0) +#define TRACE5(fmt, ...) do { } while (0) +#define TRACE6(fmt, ...) do { } while (0) + +/* for a block of code */ +#define DBG_BLOCK(level) while (0) + +extern int debug; + +#if defined DEBUG +#undef TRACE +#define TRACE(level, fmt, ...) \ +do { \ + if (debug >= level) \ + printk(KERN_INFO "%s (%s:%d): " fmt "\n", DRIVER_NAME, \ + __FUNCTION__, __LINE__ , ## __VA_ARGS__); \ +} while (0) +#undef DBG_BLOCK +#define DBG_BLOCK(level) if (debug >= level) +#endif + +#if defined(DEBUG) && DEBUG >= 1 +#undef TRACE1 +#define TRACE1(fmt, ...) TRACE(1, fmt , ## __VA_ARGS__) +#endif + +#if defined(DEBUG) && DEBUG >= 2 +#undef TRACE2 +#define TRACE2(fmt, ...) TRACE(2, fmt , ## __VA_ARGS__) +#endif + +#if defined(DEBUG) && DEBUG >= 3 +#undef TRACE3 +#define TRACE3(fmt, ...) TRACE(3, fmt , ## __VA_ARGS__) +#endif + +#if defined(DEBUG) && DEBUG >= 4 +#undef TRACE4 +#define TRACE4(fmt, ...) TRACE(4, fmt , ## __VA_ARGS__) +#endif + +#if defined(DEBUG) && DEBUG >= 5 +#undef TRACE5 +#define TRACE5(fmt, ...) TRACE(5, fmt , ## __VA_ARGS__) +#endif + +#if defined(DEBUG) && DEBUG >= 6 +#undef TRACE6 +#define TRACE6(fmt, ...) TRACE(6, fmt , ## __VA_ARGS__) +#endif + +#define ENTER1(fmt, ...) TRACE1("Enter " fmt , ## __VA_ARGS__) +#define ENTER2(fmt, ...) TRACE2("Enter " fmt , ## __VA_ARGS__) +#define ENTER3(fmt, ...) TRACE3("Enter " fmt , ## __VA_ARGS__) +#define ENTER4(fmt, ...) TRACE4("Enter " fmt , ## __VA_ARGS__) +#define ENTER5(fmt, ...) TRACE5("Enter " fmt , ## __VA_ARGS__) +#define ENTER6(fmt, ...) TRACE6("Enter " fmt , ## __VA_ARGS__) + +#define EXIT1(stmt) do { TRACE1("Exit"); stmt; } while(0) +#define EXIT2(stmt) do { TRACE2("Exit"); stmt; } while(0) +#define EXIT3(stmt) do { TRACE3("Exit"); stmt; } while(0) +#define EXIT4(stmt) do { TRACE4("Exit"); stmt; } while(0) +#define EXIT5(stmt) do { TRACE5("Exit"); stmt; } while(0) +#define EXIT6(stmt) do { TRACE6("Exit"); stmt; } while(0) + +#if defined(USB_DEBUG) +#define USBTRACE TRACE1 +#define USBENTER ENTER1 +#define USBEXIT EXIT1 +#else +#define USBTRACE(fmt, ...) +#define USBENTER(fmt, ...) +#define USBEXIT(stmt) stmt +#endif + +#if defined(EVENT_DEBUG) +#define EVENTTRACE TRACE1 +#define EVENTENTER ENTER1 +#define EVENTEXIT EXIT1 +#else +#define EVENTTRACE(fmt, ...) +#define EVENTENTER(fmt, ...) +#define EVENTEXIT(stmt) stmt +#endif + +#if defined(TIMER_DEBUG) +#define TIMERTRACE TRACE1 +#define TIMERENTER ENTER1 +#define TIMEREXIT EXIT1 +#else +#define TIMERTRACE(fmt, ...) +#define TIMERENTER(fmt, ...) +#define TIMEREXIT(stmt) stmt +#endif + +#if defined(IO_DEBUG) +#define IOTRACE TRACE1 +#define IOENTER ENTER1 +#define IOEXIT EXIT1 +#else +#define IOTRACE(fmt, ...) +#define IOENTER(fmt, ...) +#define IOEXIT(stmt) stmt +#endif + +#if defined(WORK_DEBUG) +#define WORKTRACE TRACE1 +#define WORKENTER ENTER1 +#define WORKEXIT EXIT1 +#else +#define WORKTRACE(fmt, ...) +#define WORKENTER(fmt, ...) +#define WORKEXIT(stmt) stmt +#endif + +#ifdef DEBUG +#define assert(expr) \ +do { \ + if (!(expr)) { \ + ERROR("assertion '%s' failed", #expr); \ + dump_stack(); \ + } \ +} while (0) +#else +#define assert(expr) do { } while (0) +#endif + +#endif // __KERNEL__ + +#endif // NDISWRAPPER_H --- linux-2.6.27.orig/ubuntu/ndiswrapper/Kconfig +++ linux-2.6.27/ubuntu/ndiswrapper/Kconfig @@ -0,0 +1,4 @@ +config NDISWRAPPER + tristate "Wrapper for Windows NDIS network drivers" + depends on NET + default m --- linux-2.6.27.orig/ubuntu/ndiswrapper/hal.c +++ linux-2.6.27/ubuntu/ndiswrapper/hal.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "ntoskernel.h" +#include "hal_exports.h" + +wstdcall void WIN_FUNC(WRITE_PORT_ULONG,2) + (ULONG_PTR port, ULONG value) +{ + outl(value, port); +} + +wstdcall ULONG WIN_FUNC(READ_PORT_ULONG,1) + (ULONG_PTR port) +{ + return inl(port); +} + +wstdcall void WIN_FUNC(WRITE_PORT_USHORT,2) + (ULONG_PTR port, USHORT value) +{ + outw(value, port); +} + +wstdcall USHORT WIN_FUNC(READ_PORT_USHORT,1) + (ULONG_PTR port) +{ + return inw(port); +} + +wstdcall void WIN_FUNC(WRITE_PORT_UCHAR,2) + (ULONG_PTR port, UCHAR value) +{ + outb(value, port); +} + +wstdcall UCHAR WIN_FUNC(READ_PORT_UCHAR,1) + (ULONG_PTR port) +{ + return inb(port); +} + +wstdcall void WIN_FUNC(WRITE_PORT_BUFFER_USHORT,3) + (ULONG_PTR port, USHORT *buf, ULONG count) +{ + outsw(port, buf, count); +} + +wstdcall void WIN_FUNC(READ_PORT_BUFFER_USHORT,3) + (ULONG_PTR port, USHORT *buf, ULONG count) +{ + insw(port, buf, count); +} + +wstdcall void WIN_FUNC(WRITE_PORT_BUFFER_ULONG,3) + (ULONG_PTR port, ULONG *buf, ULONG count) +{ + outsl(port, buf, count); +} + +wstdcall void WIN_FUNC(READ_PORT_BUFFER_ULONG,3) + (ULONG_PTR port, ULONG *buf, ULONG count) +{ + insl(port, buf, count); +} + +wstdcall USHORT WIN_FUNC(READ_REGISTER_USHORT,1) + (void __iomem *reg) +{ + return readw(reg); +} + +wstdcall void WIN_FUNC(WRITE_REGISTER_ULONG,2) + (void __iomem *reg, UINT val) +{ + writel(val, reg); +} + +wstdcall void WIN_FUNC(WRITE_REGISTER_USHORT,2) + (void __iomem *reg, USHORT val) +{ + writew(val, reg); +} + +wstdcall void WIN_FUNC(WRITE_REGISTER_UCHAR,2) + (void __iomem *reg, UCHAR val) +{ + writeb(val, reg); +} + +wstdcall void WIN_FUNC(KeStallExecutionProcessor,1) + (ULONG usecs) +{ + udelay(usecs); +} + +wstdcall KIRQL WIN_FUNC(KeGetCurrentIrql,0) + (void) +{ + return current_irql(); +} + +wfastcall KIRQL WIN_FUNC(KfRaiseIrql,1) + (KIRQL newirql) +{ + return raise_irql(newirql); +} + +wfastcall void WIN_FUNC(KfLowerIrql,1) + (KIRQL oldirql) +{ + lower_irql(oldirql); +} + +wfastcall KIRQL WIN_FUNC(KfAcquireSpinLock,1) + (NT_SPIN_LOCK *lock) +{ + return nt_spin_lock_irql(lock, DISPATCH_LEVEL); +} + +wfastcall void WIN_FUNC(KfReleaseSpinLock,2) + (NT_SPIN_LOCK *lock, KIRQL oldirql) +{ + nt_spin_unlock_irql(lock, oldirql); +} + +wfastcall void WIN_FUNC(KefAcquireSpinLockAtDpcLevel,1) + (NT_SPIN_LOCK *lock) +{ +#ifdef DEBUG_IRQL + if (current_irql() != DISPATCH_LEVEL) + ERROR("irql != DISPATCH_LEVEL"); +#endif + nt_spin_lock(lock); +} + +wfastcall void WIN_FUNC(KefReleaseSpinLockFromDpcLevel,1) + (NT_SPIN_LOCK *lock) +{ +#ifdef DEBUG_IRQL + if (current_irql() != DISPATCH_LEVEL) + ERROR("irql != DISPATCH_LEVEL"); +#endif + nt_spin_unlock(lock); +} --- linux-2.6.27.orig/ubuntu/ndiswrapper/longlong.h +++ linux-2.6.27/ubuntu/ndiswrapper/longlong.h @@ -0,0 +1,1333 @@ +/* longlong.h -- definitions for mixed size 32/64 bit arithmetic. + Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000 + Free Software Foundation, Inc. + + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* You have to define the following before including this file: + + UWtype -- An unsigned type, default type for operations (typically a "word") + UHWtype -- An unsigned type, at least half the size of UWtype. + UDWtype -- An unsigned type, at least twice as large a UWtype + W_TYPE_SIZE -- size in bits of UWtype + + UQItype -- Unsigned 8 bit type. + SItype, USItype -- Signed and unsigned 32 bit types. + DItype, UDItype -- Signed and unsigned 64 bit types. + + On a 32 bit machine UWtype should typically be USItype; + on a 64 bit machine, UWtype should typically be UDItype. +*/ + +#define __BITS4 (W_TYPE_SIZE / 4) +#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) +#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) +#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) + +#ifndef W_TYPE_SIZE +#define W_TYPE_SIZE 32 +#define UWtype USItype +#define UHWtype USItype +#define UDWtype UDItype +#endif + +/* Define auxiliary asm macros. + + 1) umul_ppmm(high_prod, low_prod, multipler, multiplicand) multiplies two + UWtype integers MULTIPLER and MULTIPLICAND, and generates a two UWtype + word product in HIGH_PROD and LOW_PROD. + + 2) __umulsidi3(a,b) multiplies two UWtype integers A and B, and returns a + UDWtype product. This is just a variant of umul_ppmm. + + 3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator, + denominator) divides a UDWtype, composed by the UWtype integers + HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient + in QUOTIENT and the remainder in REMAINDER. HIGH_NUMERATOR must be less + than DENOMINATOR for correct operation. If, in addition, the most + significant bit of DENOMINATOR must be 1, then the pre-processor symbol + UDIV_NEEDS_NORMALIZATION is defined to 1. + + 4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator, + denominator). Like udiv_qrnnd but the numbers are signed. The quotient + is rounded towards 0. + + 5) count_leading_zeros(count, x) counts the number of zero-bits from the + msb to the first nonzero bit in the UWtype X. This is the number of + steps X needs to be shifted left to set the msb. Undefined for X == 0, + unless the symbol COUNT_LEADING_ZEROS_0 is defined to some value. + + 6) count_trailing_zeros(count, x) like count_leading_zeros, but counts + from the least significant end. + + 7) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1, + high_addend_2, low_addend_2) adds two UWtype integers, composed by + HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2 + respectively. The result is placed in HIGH_SUM and LOW_SUM. Overflow + (i.e. carry out) is not stored anywhere, and is lost. + + 8) sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend, + high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers, + composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and + LOW_SUBTRAHEND_2 respectively. The result is placed in HIGH_DIFFERENCE + and LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere, + and is lost. + + If any of these macros are left undefined for a particular CPU, + C macros are used. */ + +/* The CPUs come in alphabetical order below. + + Please add support for more CPUs here, or improve the current support + for the CPUs below! + (E.g. WE32100, IBM360.) */ + +#if defined (__GNUC__) && !defined (NO_ASM) + +/* We sometimes need to clobber "cc" with gcc2, but that would not be + understood by gcc1. Use cpp to avoid major code duplication. */ +#if __GNUC__ < 2 +#define __CLOBBER_CC +#define __AND_CLOBBER_CC +#else /* __GNUC__ >= 2 */ +#define __CLOBBER_CC : "cc" +#define __AND_CLOBBER_CC , "cc" +#endif /* __GNUC__ < 2 */ + +#if defined (__alpha) && W_TYPE_SIZE == 64 +#define umul_ppmm(ph, pl, m0, m1) \ + do { \ + UDItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("umulh %r1,%2,%0" \ + : "=r" ((UDItype) ph) \ + : "%rJ" (__m0), \ + "rI" (__m1)); \ + (pl) = __m0 * __m1; \ + } while (0) +#define UMUL_TIME 46 +#ifndef LONGLONG_STANDALONE +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { UDItype __r; \ + (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \ + (r) = __r; \ + } while (0) +extern UDItype __udiv_qrnnd (UDItype *, UDItype, UDItype, UDItype); +#define UDIV_TIME 220 +#endif /* LONGLONG_STANDALONE */ +#ifdef __alpha_cix__ +#define count_leading_zeros(COUNT,X) \ + __asm__("ctlz %1,%0" : "=r"(COUNT) : "r"(X)) +#define count_trailing_zeros(COUNT,X) \ + __asm__("cttz %1,%0" : "=r"(COUNT) : "r"(X)) +#define COUNT_LEADING_ZEROS_0 64 +#else +extern const UQItype __clz_tab[]; +#define count_leading_zeros(COUNT,X) \ + do { \ + UDItype __xr = (X), __t, __a; \ + __asm__("cmpbge $31,%1,%0" : "=r"(__t) : "r"(__xr)); \ + __a = __clz_tab[__t ^ 0xff] - 1; \ + __asm__("extbl %1,%2,%0" : "=r"(__t) : "r"(__xr), "r"(__a)); \ + (COUNT) = 64 - (__clz_tab[__t] + __a*8); \ + } while (0) +#define count_trailing_zeros(COUNT,X) \ + do { \ + UDItype __xr = (X), __t, __a; \ + __asm__("cmpbge $31,%1,%0" : "=r"(__t) : "r"(__xr)); \ + __t = ~__t & -~__t; \ + __a = ((__t & 0xCC) != 0) * 2; \ + __a += ((__t & 0xF0) != 0) * 4; \ + __a += ((__t & 0xAA) != 0); \ + __asm__("extbl %1,%2,%0" : "=r"(__t) : "r"(__xr), "r"(__a)); \ + __a <<= 3; \ + __t &= -__t; \ + __a += ((__t & 0xCC) != 0) * 2; \ + __a += ((__t & 0xF0) != 0) * 4; \ + __a += ((__t & 0xAA) != 0); \ + (COUNT) = __a; \ + } while (0) +#endif /* __alpha_cix__ */ +#endif /* __alpha */ + +#if defined (__arc__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add.f %1, %4, %5\n\tadc %0, %2, %3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "%r" ((USItype) (ah)), \ + "rIJ" ((USItype) (bh)), \ + "%r" ((USItype) (al)), \ + "rIJ" ((USItype) (bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub.f %1, %4, %5\n\tsbc %0, %2, %3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "r" ((USItype) (ah)), \ + "rIJ" ((USItype) (bh)), \ + "r" ((USItype) (al)), \ + "rIJ" ((USItype) (bl))) +/* Call libgcc routine. */ +#define umul_ppmm(w1, w0, u, v) \ +do { \ + DWunion __w; \ + __w.ll = __umulsidi3 (u, v); \ + w1 = __w.s.high; \ + w0 = __w.s.low; \ +} while (0) +#define __umulsidi3 __umulsidi3 +UDItype __umulsidi3 (USItype, USItype); +#endif + +#if defined (__arm__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("adds %1, %4, %5\n\tadc %0, %2, %3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "%r" ((USItype) (ah)), \ + "rI" ((USItype) (bh)), \ + "%r" ((USItype) (al)), \ + "rI" ((USItype) (bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subs %1, %4, %5\n\tsbc %0, %2, %3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "r" ((USItype) (ah)), \ + "rI" ((USItype) (bh)), \ + "r" ((USItype) (al)), \ + "rI" ((USItype) (bl))) +#define umul_ppmm(xh, xl, a, b) \ +{register USItype __t0, __t1, __t2; \ + __asm__ ("%@ Inlined umul_ppmm\n" \ + " mov %2, %5, lsr #16\n" \ + " mov %0, %6, lsr #16\n" \ + " bic %3, %5, %2, lsl #16\n" \ + " bic %4, %6, %0, lsl #16\n" \ + " mul %1, %3, %4\n" \ + " mul %4, %2, %4\n" \ + " mul %3, %0, %3\n" \ + " mul %0, %2, %0\n" \ + " adds %3, %4, %3\n" \ + " addcs %0, %0, #65536\n" \ + " adds %1, %1, %3, lsl #16\n" \ + " adc %0, %0, %3, lsr #16" \ + : "=&r" ((USItype) (xh)), \ + "=r" ((USItype) (xl)), \ + "=&r" (__t0), "=&r" (__t1), "=r" (__t2) \ + : "r" ((USItype) (a)), \ + "r" ((USItype) (b)));} +#define UMUL_TIME 20 +#define UDIV_TIME 100 +#endif /* __arm__ */ + +#if defined (__hppa) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add %4,%5,%1\n\taddc %2,%3,%0" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "%rM" ((USItype) (ah)), \ + "rM" ((USItype) (bh)), \ + "%rM" ((USItype) (al)), \ + "rM" ((USItype) (bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub %4,%5,%1\n\tsubb %2,%3,%0" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "rM" ((USItype) (ah)), \ + "rM" ((USItype) (bh)), \ + "rM" ((USItype) (al)), \ + "rM" ((USItype) (bl))) +#if defined (_PA_RISC1_1) +#define umul_ppmm(w1, w0, u, v) \ + do { \ + union \ + { \ + UDItype __f; \ + struct {USItype __w1, __w0;} __w1w0; \ + } __t; \ + __asm__ ("xmpyu %1,%2,%0" \ + : "=x" (__t.__f) \ + : "x" ((USItype) (u)), \ + "x" ((USItype) (v))); \ + (w1) = __t.__w1w0.__w1; \ + (w0) = __t.__w1w0.__w0; \ + } while (0) +#define UMUL_TIME 8 +#else +#define UMUL_TIME 30 +#endif +#define UDIV_TIME 40 +#define count_leading_zeros(count, x) \ + do { \ + USItype __tmp; \ + __asm__ ( \ + "ldi 1,%0\n" \ +" extru,= %1,15,16,%%r0 ; Bits 31..16 zero?\n" \ +" extru,tr %1,15,16,%1 ; No. Shift down, skip add.\n"\ +" ldo 16(%0),%0 ; Yes. Perform add.\n" \ +" extru,= %1,23,8,%%r0 ; Bits 15..8 zero?\n" \ +" extru,tr %1,23,8,%1 ; No. Shift down, skip add.\n"\ +" ldo 8(%0),%0 ; Yes. Perform add.\n" \ +" extru,= %1,27,4,%%r0 ; Bits 7..4 zero?\n" \ +" extru,tr %1,27,4,%1 ; No. Shift down, skip add.\n"\ +" ldo 4(%0),%0 ; Yes. Perform add.\n" \ +" extru,= %1,29,2,%%r0 ; Bits 3..2 zero?\n" \ +" extru,tr %1,29,2,%1 ; No. Shift down, skip add.\n"\ +" ldo 2(%0),%0 ; Yes. Perform add.\n" \ +" extru %1,30,1,%1 ; Extract bit 1.\n" \ +" sub %0,%1,%0 ; Subtract it.\n" \ + : "=r" (count), "=r" (__tmp) : "1" (x)); \ + } while (0) +#endif + +#if (defined (__i370__) || defined (__mvs__)) && W_TYPE_SIZE == 32 +#define umul_ppmm(xh, xl, m0, m1) \ + do { \ + union {UDItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mr %0,%3" \ + : "=r" (__xx.__i.__h), \ + "=r" (__xx.__i.__l) \ + : "%1" (__m0), \ + "r" (__m1)); \ + (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ + (xh) += ((((SItype) __m0 >> 31) & __m1) \ + + (((SItype) __m1 >> 31) & __m0)); \ + } while (0) +#define smul_ppmm(xh, xl, m0, m1) \ + do { \ + union {DItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + __asm__ ("mr %0,%3" \ + : "=r" (__xx.__i.__h), \ + "=r" (__xx.__i.__l) \ + : "%1" (m0), \ + "r" (m1)); \ + (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ + } while (0) +#define sdiv_qrnnd(q, r, n1, n0, d) \ + do { \ + union {DItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + __xx.__i.__h = n1; __xx.__i.__l = n0; \ + __asm__ ("dr %0,%2" \ + : "=r" (__xx.__ll) \ + : "0" (__xx.__ll), "r" (d)); \ + (q) = __xx.__i.__l; (r) = __xx.__i.__h; \ + } while (0) +#endif + +#if (defined (__i386__) || defined (__i486__)) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addl %5,%1\n\tadcl %3,%0" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "%0" ((USItype) (ah)), \ + "g" ((USItype) (bh)), \ + "%1" ((USItype) (al)), \ + "g" ((USItype) (bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subl %5,%1\n\tsbbl %3,%0" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "0" ((USItype) (ah)), \ + "g" ((USItype) (bh)), \ + "1" ((USItype) (al)), \ + "g" ((USItype) (bl))) +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("mull %3" \ + : "=a" ((USItype) (w0)), \ + "=d" ((USItype) (w1)) \ + : "%0" ((USItype) (u)), \ + "rm" ((USItype) (v))) +#define udiv_qrnnd(q, r, n1, n0, dv) \ + __asm__ ("divl %4" \ + : "=a" ((USItype) (q)), \ + "=d" ((USItype) (r)) \ + : "0" ((USItype) (n0)), \ + "1" ((USItype) (n1)), \ + "rm" ((USItype) (dv))) +#define count_leading_zeros(count, x) \ + do { \ + USItype __cbtmp; \ + __asm__ ("bsrl %1,%0" \ + : "=r" (__cbtmp) : "rm" ((USItype) (x))); \ + (count) = __cbtmp ^ 31; \ + } while (0) +#define count_trailing_zeros(count, x) \ + __asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x))) +#define UMUL_TIME 40 +#define UDIV_TIME 40 +#endif /* 80x86 */ + +#if defined (__i960__) && W_TYPE_SIZE == 32 +#define umul_ppmm(w1, w0, u, v) \ + ({union {UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __xx; \ + __asm__ ("emul %2,%1,%0" \ + : "=d" (__xx.__ll) \ + : "%dI" ((USItype) (u)), \ + "dI" ((USItype) (v))); \ + (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) +#define __umulsidi3(u, v) \ + ({UDItype __w; \ + __asm__ ("emul %2,%1,%0" \ + : "=d" (__w) \ + : "%dI" ((USItype) (u)), \ + "dI" ((USItype) (v))); \ + __w; }) +#endif /* __i960__ */ + +#if defined (__M32R__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + /* The cmp clears the condition bit. */ \ + __asm__ ("cmp %0,%0\n\taddx %%5,%1\n\taddx %%3,%0" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "%0" ((USItype) (ah)), \ + "r" ((USItype) (bh)), \ + "%1" ((USItype) (al)), \ + "r" ((USItype) (bl)) \ + : "cbit") +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + /* The cmp clears the condition bit. */ \ + __asm__ ("cmp %0,%0\n\tsubx %5,%1\n\tsubx %3,%0" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "0" ((USItype) (ah)), \ + "r" ((USItype) (bh)), \ + "1" ((USItype) (al)), \ + "r" ((USItype) (bl)) \ + : "cbit") +#endif /* __M32R__ */ + +#if defined (__mc68000__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add%.l %5,%1\n\taddx%.l %3,%0" \ + : "=d" ((USItype) (sh)), \ + "=&d" ((USItype) (sl)) \ + : "%0" ((USItype) (ah)), \ + "d" ((USItype) (bh)), \ + "%1" ((USItype) (al)), \ + "g" ((USItype) (bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub%.l %5,%1\n\tsubx%.l %3,%0" \ + : "=d" ((USItype) (sh)), \ + "=&d" ((USItype) (sl)) \ + : "0" ((USItype) (ah)), \ + "d" ((USItype) (bh)), \ + "1" ((USItype) (al)), \ + "g" ((USItype) (bl))) + +/* The '020, '030, '040 and CPU32 have 32x32->64 and 64/32->32q-32r. */ +#if defined (__mc68020__) || defined(mc68020) \ + || defined(__mc68030__) || defined(mc68030) \ + || defined(__mc68040__) || defined(mc68040) \ + || defined(__mcpu32__) || defined(mcpu32) +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("mulu%.l %3,%1:%0" \ + : "=d" ((USItype) (w0)), \ + "=d" ((USItype) (w1)) \ + : "%0" ((USItype) (u)), \ + "dmi" ((USItype) (v))) +#define UMUL_TIME 45 +#define udiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("divu%.l %4,%1:%0" \ + : "=d" ((USItype) (q)), \ + "=d" ((USItype) (r)) \ + : "0" ((USItype) (n0)), \ + "1" ((USItype) (n1)), \ + "dmi" ((USItype) (d))) +#define UDIV_TIME 90 +#define sdiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("divs%.l %4,%1:%0" \ + : "=d" ((USItype) (q)), \ + "=d" ((USItype) (r)) \ + : "0" ((USItype) (n0)), \ + "1" ((USItype) (n1)), \ + "dmi" ((USItype) (d))) + +#else /* not mc68020 */ +#if !defined(__mcf5200__) +/* %/ inserts REGISTER_PREFIX, %# inserts IMMEDIATE_PREFIX. */ +#define umul_ppmm(xh, xl, a, b) \ + __asm__ ("| Inlined umul_ppmm\n" \ + " move%.l %2,%/d0\n" \ + " move%.l %3,%/d1\n" \ + " move%.l %/d0,%/d2\n" \ + " swap %/d0\n" \ + " move%.l %/d1,%/d3\n" \ + " swap %/d1\n" \ + " move%.w %/d2,%/d4\n" \ + " mulu %/d3,%/d4\n" \ + " mulu %/d1,%/d2\n" \ + " mulu %/d0,%/d3\n" \ + " mulu %/d0,%/d1\n" \ + " move%.l %/d4,%/d0\n" \ + " eor%.w %/d0,%/d0\n" \ + " swap %/d0\n" \ + " add%.l %/d0,%/d2\n" \ + " add%.l %/d3,%/d2\n" \ + " jcc 1f\n" \ + " add%.l %#65536,%/d1\n" \ + "1: swap %/d2\n" \ + " moveq %#0,%/d0\n" \ + " move%.w %/d2,%/d0\n" \ + " move%.w %/d4,%/d2\n" \ + " move%.l %/d2,%1\n" \ + " add%.l %/d1,%/d0\n" \ + " move%.l %/d0,%0" \ + : "=g" ((USItype) (xh)), \ + "=g" ((USItype) (xl)) \ + : "g" ((USItype) (a)), \ + "g" ((USItype) (b)) \ + : "d0", "d1", "d2", "d3", "d4") +#define UMUL_TIME 100 +#define UDIV_TIME 400 +#endif /* not mcf5200 */ +#endif /* not mc68020 */ + +/* The '020, '030, '040 and '060 have bitfield insns. */ +#if defined (__mc68020__) || defined(mc68020) \ + || defined(__mc68030__) || defined(mc68030) \ + || defined(__mc68040__) || defined(mc68040) \ + || defined(__mc68060__) || defined(mc68060) +#define count_leading_zeros(count, x) \ + __asm__ ("bfffo %1{%b2:%b2},%0" \ + : "=d" ((USItype) (count)) \ + : "od" ((USItype) (x)), "n" (0)) +#endif +#endif /* mc68000 */ + +#if defined (__m88000__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addu.co %1,%r4,%r5\n\taddu.ci %0,%r2,%r3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "%rJ" ((USItype) (ah)), \ + "rJ" ((USItype) (bh)), \ + "%rJ" ((USItype) (al)), \ + "rJ" ((USItype) (bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subu.co %1,%r4,%r5\n\tsubu.ci %0,%r2,%r3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "rJ" ((USItype) (ah)), \ + "rJ" ((USItype) (bh)), \ + "rJ" ((USItype) (al)), \ + "rJ" ((USItype) (bl))) +#define count_leading_zeros(count, x) \ + do { \ + USItype __cbtmp; \ + __asm__ ("ff1 %0,%1" \ + : "=r" (__cbtmp) \ + : "r" ((USItype) (x))); \ + (count) = __cbtmp ^ 31; \ + } while (0) +#define COUNT_LEADING_ZEROS_0 63 /* sic */ +#if defined (__mc88110__) +#define umul_ppmm(wh, wl, u, v) \ + do { \ + union {UDItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + __asm__ ("mulu.d %0,%1,%2" \ + : "=r" (__xx.__ll) \ + : "r" ((USItype) (u)), \ + "r" ((USItype) (v))); \ + (wh) = __xx.__i.__h; \ + (wl) = __xx.__i.__l; \ + } while (0) +#define udiv_qrnnd(q, r, n1, n0, d) \ + ({union {UDItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + USItype __q; \ + __xx.__i.__h = (n1); __xx.__i.__l = (n0); \ + __asm__ ("divu.d %0,%1,%2" \ + : "=r" (__q) \ + : "r" (__xx.__ll), \ + "r" ((USItype) (d))); \ + (r) = (n0) - __q * (d); (q) = __q; }) +#define UMUL_TIME 5 +#define UDIV_TIME 25 +#else +#define UMUL_TIME 17 +#define UDIV_TIME 150 +#endif /* __mc88110__ */ +#endif /* __m88000__ */ + +#if defined (__mips__) && W_TYPE_SIZE == 32 +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("multu %2,%3" \ + : "=l" ((USItype) (w0)), \ + "=h" ((USItype) (w1)) \ + : "d" ((USItype) (u)), \ + "d" ((USItype) (v))) +#define UMUL_TIME 10 +#define UDIV_TIME 100 +#endif /* __mips__ */ + +#if defined (__ns32000__) && W_TYPE_SIZE == 32 +#define umul_ppmm(w1, w0, u, v) \ + ({union {UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __xx; \ + __asm__ ("meid %2,%0" \ + : "=g" (__xx.__ll) \ + : "%0" ((USItype) (u)), \ + "g" ((USItype) (v))); \ + (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) +#define __umulsidi3(u, v) \ + ({UDItype __w; \ + __asm__ ("meid %2,%0" \ + : "=g" (__w) \ + : "%0" ((USItype) (u)), \ + "g" ((USItype) (v))); \ + __w; }) +#define udiv_qrnnd(q, r, n1, n0, d) \ + ({union {UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __xx; \ + __xx.__i.__h = (n1); __xx.__i.__l = (n0); \ + __asm__ ("deid %2,%0" \ + : "=g" (__xx.__ll) \ + : "0" (__xx.__ll), \ + "g" ((USItype) (d))); \ + (r) = __xx.__i.__l; (q) = __xx.__i.__h; }) +#define count_trailing_zeros(count,x) \ + do { \ + __asm__ ("ffsd %2,%0" \ + : "=r" ((USItype) (count)) \ + : "0" ((USItype) 0), \ + "r" ((USItype) (x))); \ + } while (0) +#endif /* __ns32000__ */ + +/* FIXME: We should test _IBMR2 here when we add assembly support for the + system vendor compilers. + FIXME: What's needed for gcc PowerPC VxWorks? __vxworks__ is not good + enough, since that hits ARM and m68k too. */ +#if (defined (_ARCH_PPC) /* AIX */ \ + || defined (_ARCH_PWR) /* AIX */ \ + || defined (_ARCH_COM) /* AIX */ \ + || defined (__powerpc__) /* gcc */ \ + || defined (__POWERPC__) /* BEOS */ \ + || defined (__ppc__) /* Darwin */ \ + || defined (PPC) /* GNU/Linux, SysV */ \ + ) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + do { \ + if (__builtin_constant_p (bh) && (bh) == 0) \ + __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ + else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0) \ + __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ + else \ + __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ + : "=r" (sh), "=&r" (sl) \ + : "%r" (ah), "r" (bh), "%r" (al), "rI" (bl)); \ + } while (0) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + do { \ + if (__builtin_constant_p (ah) && (ah) == 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ + else if (__builtin_constant_p (ah) && (ah) == ~(USItype) 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ + else if (__builtin_constant_p (bh) && (bh) == 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ + else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ + else \ + __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ + : "=r" (sh), "=&r" (sl) \ + : "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \ + } while (0) +#define count_leading_zeros(count, x) \ + __asm__ ("{cntlz|cntlzw} %0,%1" : "=r" (count) : "r" (x)) +#define COUNT_LEADING_ZEROS_0 32 +#if defined (_ARCH_PPC) || defined (__powerpc__) || defined (__POWERPC__) \ + || defined (__ppc__) || defined (PPC) || defined (__vxworks__) +#define umul_ppmm(ph, pl, m0, m1) \ + do { \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mulhwu %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ + (pl) = __m0 * __m1; \ + } while (0) +#define UMUL_TIME 15 +#define smul_ppmm(ph, pl, m0, m1) \ + do { \ + SItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mulhw %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ + (pl) = __m0 * __m1; \ + } while (0) +#define SMUL_TIME 14 +#define UDIV_TIME 120 +#elif defined (_ARCH_PWR) +#define UMUL_TIME 8 +#define smul_ppmm(xh, xl, m0, m1) \ + __asm__ ("mul %0,%2,%3" : "=r" (xh), "=q" (xl) : "r" (m0), "r" (m1)) +#define SMUL_TIME 4 +#define sdiv_qrnnd(q, r, nh, nl, d) \ + __asm__ ("div %0,%2,%4" : "=r" (q), "=q" (r) : "r" (nh), "1" (nl), "r" (d)) +#define UDIV_TIME 100 +#endif +#endif /* 32-bit POWER architecture variants. */ + +/* We should test _IBMR2 here when we add assembly support for the system + vendor compilers. */ +#if (defined (_ARCH_PPC64) || defined (__powerpc64__)) && W_TYPE_SIZE == 64 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + do { \ + if (__builtin_constant_p (bh) && (bh) == 0) \ + __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ + else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \ + __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ + else \ + __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ + : "=r" (sh), "=&r" (sl) \ + : "%r" (ah), "r" (bh), "%r" (al), "rI" (bl)); \ + } while (0) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + do { \ + if (__builtin_constant_p (ah) && (ah) == 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ + else if (__builtin_constant_p (ah) && (ah) == ~(UDItype) 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ + else if (__builtin_constant_p (bh) && (bh) == 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ + else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ + else \ + __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ + : "=r" (sh), "=&r" (sl) \ + : "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \ + } while (0) +#define count_leading_zeros(count, x) \ + __asm__ ("cntlzd %0,%1" : "=r" (count) : "r" (x)) +#define COUNT_LEADING_ZEROS_0 64 +#define umul_ppmm(ph, pl, m0, m1) \ + do { \ + UDItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mulhdu %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ + (pl) = __m0 * __m1; \ + } while (0) +#define UMUL_TIME 15 +#define smul_ppmm(ph, pl, m0, m1) \ + do { \ + DItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mulhd %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ + (pl) = __m0 * __m1; \ + } while (0) +#define SMUL_TIME 14 /* ??? */ +#define UDIV_TIME 120 /* ??? */ +#endif /* 64-bit PowerPC. */ + +#if defined (__ibm032__) /* RT/ROMP */ && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("a %1,%5\n\tae %0,%3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "%0" ((USItype) (ah)), \ + "r" ((USItype) (bh)), \ + "%1" ((USItype) (al)), \ + "r" ((USItype) (bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("s %1,%5\n\tse %0,%3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "0" ((USItype) (ah)), \ + "r" ((USItype) (bh)), \ + "1" ((USItype) (al)), \ + "r" ((USItype) (bl))) +#define umul_ppmm(ph, pl, m0, m1) \ + do { \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ( \ + "s r2,r2\n" \ +" mts r10,%2\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" cas %0,r2,r0\n" \ +" mfs r10,%1" \ + : "=r" ((USItype) (ph)), \ + "=r" ((USItype) (pl)) \ + : "%r" (__m0), \ + "r" (__m1) \ + : "r2"); \ + (ph) += ((((SItype) __m0 >> 31) & __m1) \ + + (((SItype) __m1 >> 31) & __m0)); \ + } while (0) +#define UMUL_TIME 20 +#define UDIV_TIME 200 +#define count_leading_zeros(count, x) \ + do { \ + if ((x) >= 0x10000) \ + __asm__ ("clz %0,%1" \ + : "=r" ((USItype) (count)) \ + : "r" ((USItype) (x) >> 16)); \ + else \ + { \ + __asm__ ("clz %0,%1" \ + : "=r" ((USItype) (count)) \ + : "r" ((USItype) (x))); \ + (count) += 16; \ + } \ + } while (0) +#endif + +#if defined (__sh2__) && W_TYPE_SIZE == 32 +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ( \ + "dmulu.l %2,%3\n\tsts macl,%1\n\tsts mach,%0" \ + : "=r" ((USItype)(w1)), \ + "=r" ((USItype)(w0)) \ + : "r" ((USItype)(u)), \ + "r" ((USItype)(v)) \ + : "macl", "mach") +#define UMUL_TIME 5 +#endif + +#if defined (__SH5__) && __SHMEDIA__ && W_TYPE_SIZE == 32 +#define __umulsidi3(u,v) ((UDItype)(USItype)u*(USItype)v) +#define count_leading_zeros(count, x) \ + do \ + { \ + UDItype x_ = (USItype)(x); \ + SItype c_; \ + \ + __asm__ ("nsb %1, %0" : "=r" (c_) : "r" (x_)); \ + (count) = c_ - 31; \ + } \ + while (0) +#define COUNT_LEADING_ZEROS_0 32 +#endif + +#if defined (__sparc__) && !defined (__arch64__) && !defined (__sparcv9) \ + && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addcc %r4,%5,%1\n\taddx %r2,%3,%0" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "%rJ" ((USItype) (ah)), \ + "rI" ((USItype) (bh)), \ + "%rJ" ((USItype) (al)), \ + "rI" ((USItype) (bl)) \ + __CLOBBER_CC) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subcc %r4,%5,%1\n\tsubx %r2,%3,%0" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "rJ" ((USItype) (ah)), \ + "rI" ((USItype) (bh)), \ + "rJ" ((USItype) (al)), \ + "rI" ((USItype) (bl)) \ + __CLOBBER_CC) +#if defined (__sparc_v8__) +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("umul %2,%3,%1;rd %%y,%0" \ + : "=r" ((USItype) (w1)), \ + "=r" ((USItype) (w0)) \ + : "r" ((USItype) (u)), \ + "r" ((USItype) (v))) +#define udiv_qrnnd(__q, __r, __n1, __n0, __d) \ + __asm__ ("mov %2,%%y;nop;nop;nop;udiv %3,%4,%0;umul %0,%4,%1;sub %3,%1,%1"\ + : "=&r" ((USItype) (__q)), \ + "=&r" ((USItype) (__r)) \ + : "r" ((USItype) (__n1)), \ + "r" ((USItype) (__n0)), \ + "r" ((USItype) (__d))) +#else +#if defined (__sparclite__) +/* This has hardware multiply but not divide. It also has two additional + instructions scan (ffs from high bit) and divscc. */ +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("umul %2,%3,%1;rd %%y,%0" \ + : "=r" ((USItype) (w1)), \ + "=r" ((USItype) (w0)) \ + : "r" ((USItype) (u)), \ + "r" ((USItype) (v))) +#define udiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("! Inlined udiv_qrnnd\n" \ +" wr %%g0,%2,%%y ! Not a delayed write for sparclite\n" \ +" tst %%g0\n" \ +" divscc %3,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%0\n" \ +" rd %%y,%1\n" \ +" bl,a 1f\n" \ +" add %1,%4,%1\n" \ +"1: ! End of inline udiv_qrnnd" \ + : "=r" ((USItype) (q)), \ + "=r" ((USItype) (r)) \ + : "r" ((USItype) (n1)), \ + "r" ((USItype) (n0)), \ + "rI" ((USItype) (d)) \ + : "g1" __AND_CLOBBER_CC) +#define UDIV_TIME 37 +#define count_leading_zeros(count, x) \ + do { \ + __asm__ ("scan %1,1,%0" \ + : "=r" ((USItype) (count)) \ + : "r" ((USItype) (x))); \ + } while (0) +/* Early sparclites return 63 for an argument of 0, but they warn that future + implementations might change this. Therefore, leave COUNT_LEADING_ZEROS_0 + undefined. */ +#else +/* SPARC without integer multiplication and divide instructions. + (i.e. at least Sun4/20,40,60,65,75,110,260,280,330,360,380,470,490) */ +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("! Inlined umul_ppmm\n" \ +" wr %%g0,%2,%%y ! SPARC has 0-3 delay insn after a wr\n"\ +" sra %3,31,%%o5 ! Don't move this insn\n" \ +" and %2,%%o5,%%o5 ! Don't move this insn\n" \ +" andcc %%g0,0,%%g1 ! Don't move this insn\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,0,%%g1\n" \ +" add %%g1,%%o5,%0\n" \ +" rd %%y,%1" \ + : "=r" ((USItype) (w1)), \ + "=r" ((USItype) (w0)) \ + : "%rI" ((USItype) (u)), \ + "r" ((USItype) (v)) \ + : "g1", "o5" __AND_CLOBBER_CC) +#define UMUL_TIME 39 /* 39 instructions */ +/* It's quite necessary to add this much assembler for the sparc. + The default udiv_qrnnd (in C) is more than 10 times slower! */ +#define udiv_qrnnd(__q, __r, __n1, __n0, __d) \ + __asm__ ("! Inlined udiv_qrnnd\n" \ +" mov 32,%%g1\n" \ +" subcc %1,%2,%%g0\n" \ +"1: bcs 5f\n" \ +" addxcc %0,%0,%0 ! shift n1n0 and a q-bit in lsb\n" \ +" sub %1,%2,%1 ! this kills msb of n\n" \ +" addx %1,%1,%1 ! so this can't give carry\n" \ +" subcc %%g1,1,%%g1\n" \ +"2: bne 1b\n" \ +" subcc %1,%2,%%g0\n" \ +" bcs 3f\n" \ +" addxcc %0,%0,%0 ! shift n1n0 and a q-bit in lsb\n" \ +" b 3f\n" \ +" sub %1,%2,%1 ! this kills msb of n\n" \ +"4: sub %1,%2,%1\n" \ +"5: addxcc %1,%1,%1\n" \ +" bcc 2b\n" \ +" subcc %%g1,1,%%g1\n" \ +"! Got carry from n. Subtract next step to cancel this carry.\n" \ +" bne 4b\n" \ +" addcc %0,%0,%0 ! shift n1n0 and a 0-bit in lsb\n" \ +" sub %1,%2,%1\n" \ +"3: xnor %0,0,%0\n" \ +" ! End of inline udiv_qrnnd" \ + : "=&r" ((USItype) (__q)), \ + "=&r" ((USItype) (__r)) \ + : "r" ((USItype) (__d)), \ + "1" ((USItype) (__n1)), \ + "0" ((USItype) (__n0)) : "g1" __AND_CLOBBER_CC) +#define UDIV_TIME (3+7*32) /* 7 instructions/iteration. 32 iterations. */ +#endif /* __sparclite__ */ +#endif /* __sparc_v8__ */ +#endif /* sparc32 */ + +#if ((defined (__sparc__) && defined (__arch64__)) || defined (__sparcv9)) \ + && W_TYPE_SIZE == 64 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addcc %r4,%5,%1\n\t" \ + "add %r2,%3,%0\n\t" \ + "bcs,a,pn %%xcc, 1f\n\t" \ + "add %0, 1, %0\n" \ + "1:" \ + : "=r" ((UDItype)(sh)), \ + "=&r" ((UDItype)(sl)) \ + : "%rJ" ((UDItype)(ah)), \ + "rI" ((UDItype)(bh)), \ + "%rJ" ((UDItype)(al)), \ + "rI" ((UDItype)(bl)) \ + __CLOBBER_CC) + +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subcc %r4,%5,%1\n\t" \ + "sub %r2,%3,%0\n\t" \ + "bcs,a,pn %%xcc, 1f\n\t" \ + "sub %0, 1, %0\n\t" \ + "1:" \ + : "=r" ((UDItype)(sh)), \ + "=&r" ((UDItype)(sl)) \ + : "rJ" ((UDItype)(ah)), \ + "rI" ((UDItype)(bh)), \ + "rJ" ((UDItype)(al)), \ + "rI" ((UDItype)(bl)) \ + __CLOBBER_CC) + +#define umul_ppmm(wh, wl, u, v) \ + do { \ + UDItype tmp1, tmp2, tmp3, tmp4; \ + __asm__ __volatile__ ( \ + "srl %7,0,%3\n\t" \ + "mulx %3,%6,%1\n\t" \ + "srlx %6,32,%2\n\t" \ + "mulx %2,%3,%4\n\t" \ + "sllx %4,32,%5\n\t" \ + "srl %6,0,%3\n\t" \ + "sub %1,%5,%5\n\t" \ + "srlx %5,32,%5\n\t" \ + "addcc %4,%5,%4\n\t" \ + "srlx %7,32,%5\n\t" \ + "mulx %3,%5,%3\n\t" \ + "mulx %2,%5,%5\n\t" \ + "sethi %%hi(0x80000000),%2\n\t" \ + "addcc %4,%3,%4\n\t" \ + "srlx %4,32,%4\n\t" \ + "add %2,%2,%2\n\t" \ + "movcc %%xcc,%%g0,%2\n\t" \ + "addcc %5,%4,%5\n\t" \ + "sllx %3,32,%3\n\t" \ + "add %1,%3,%1\n\t" \ + "add %5,%2,%0" \ + : "=r" ((UDItype)(wh)), \ + "=&r" ((UDItype)(wl)), \ + "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4) \ + : "r" ((UDItype)(u)), \ + "r" ((UDItype)(v)) \ + __CLOBBER_CC); \ + } while (0) +#define UMUL_TIME 96 +#define UDIV_TIME 230 +#endif /* sparc64 */ + +#if defined (__vax__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addl2 %5,%1\n\tadwc %3,%0" \ + : "=g" ((USItype) (sh)), \ + "=&g" ((USItype) (sl)) \ + : "%0" ((USItype) (ah)), \ + "g" ((USItype) (bh)), \ + "%1" ((USItype) (al)), \ + "g" ((USItype) (bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subl2 %5,%1\n\tsbwc %3,%0" \ + : "=g" ((USItype) (sh)), \ + "=&g" ((USItype) (sl)) \ + : "0" ((USItype) (ah)), \ + "g" ((USItype) (bh)), \ + "1" ((USItype) (al)), \ + "g" ((USItype) (bl))) +#define umul_ppmm(xh, xl, m0, m1) \ + do { \ + union { \ + UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __xx; \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("emul %1,%2,$0,%0" \ + : "=r" (__xx.__ll) \ + : "g" (__m0), \ + "g" (__m1)); \ + (xh) = __xx.__i.__h; \ + (xl) = __xx.__i.__l; \ + (xh) += ((((SItype) __m0 >> 31) & __m1) \ + + (((SItype) __m1 >> 31) & __m0)); \ + } while (0) +#define sdiv_qrnnd(q, r, n1, n0, d) \ + do { \ + union {DItype __ll; \ + struct {SItype __l, __h;} __i; \ + } __xx; \ + __xx.__i.__h = n1; __xx.__i.__l = n0; \ + __asm__ ("ediv %3,%2,%0,%1" \ + : "=g" (q), "=g" (r) \ + : "g" (__xx.__ll), "g" (d)); \ + } while (0) +#endif /* __vax__ */ + +#if defined (__z8000__) && W_TYPE_SIZE == 16 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add %H1,%H5\n\tadc %H0,%H3" \ + : "=r" ((unsigned int)(sh)), \ + "=&r" ((unsigned int)(sl)) \ + : "%0" ((unsigned int)(ah)), \ + "r" ((unsigned int)(bh)), \ + "%1" ((unsigned int)(al)), \ + "rQR" ((unsigned int)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub %H1,%H5\n\tsbc %H0,%H3" \ + : "=r" ((unsigned int)(sh)), \ + "=&r" ((unsigned int)(sl)) \ + : "0" ((unsigned int)(ah)), \ + "r" ((unsigned int)(bh)), \ + "1" ((unsigned int)(al)), \ + "rQR" ((unsigned int)(bl))) +#define umul_ppmm(xh, xl, m0, m1) \ + do { \ + union {long int __ll; \ + struct {unsigned int __h, __l;} __i; \ + } __xx; \ + unsigned int __m0 = (m0), __m1 = (m1); \ + __asm__ ("mult %S0,%H3" \ + : "=r" (__xx.__i.__h), \ + "=r" (__xx.__i.__l) \ + : "%1" (__m0), \ + "rQR" (__m1)); \ + (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ + (xh) += ((((signed int) __m0 >> 15) & __m1) \ + + (((signed int) __m1 >> 15) & __m0)); \ + } while (0) +#endif /* __z8000__ */ + +#endif /* __GNUC__ */ + +/* If this machine has no inline assembler, use C macros. */ + +#if !defined (add_ssaaaa) +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + do { \ + UWtype __x; \ + __x = (al) + (bl); \ + (sh) = (ah) + (bh) + (__x < (al)); \ + (sl) = __x; \ + } while (0) +#endif + +#if !defined (sub_ddmmss) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + do { \ + UWtype __x; \ + __x = (al) - (bl); \ + (sh) = (ah) - (bh) - (__x > (al)); \ + (sl) = __x; \ + } while (0) +#endif + +#if !defined (umul_ppmm) +#define umul_ppmm(w1, w0, u, v) \ + do { \ + UWtype __x0, __x1, __x2, __x3; \ + UHWtype __ul, __vl, __uh, __vh; \ + \ + __ul = __ll_lowpart (u); \ + __uh = __ll_highpart (u); \ + __vl = __ll_lowpart (v); \ + __vh = __ll_highpart (v); \ + \ + __x0 = (UWtype) __ul * __vl; \ + __x1 = (UWtype) __ul * __vh; \ + __x2 = (UWtype) __uh * __vl; \ + __x3 = (UWtype) __uh * __vh; \ + \ + __x1 += __ll_highpart (__x0);/* this can't give carry */ \ + __x1 += __x2; /* but this indeed can */ \ + if (__x1 < __x2) /* did we get it? */ \ + __x3 += __ll_B; /* yes, add it in the proper pos. */ \ + \ + (w1) = __x3 + __ll_highpart (__x1); \ + (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \ + } while (0) +#endif + +#if !defined (__umulsidi3) +#define __umulsidi3(u, v) \ + ({DWunion __w; \ + umul_ppmm (__w.s.high, __w.s.low, u, v); \ + __w.ll; }) +#endif + +/* Define this unconditionally, so it can be used for debugging. */ +#define __udiv_qrnnd_c(q, r, n1, n0, d) \ + do { \ + UWtype __d1, __d0, __q1, __q0; \ + UWtype __r1, __r0, __m; \ + __d1 = __ll_highpart (d); \ + __d0 = __ll_lowpart (d); \ + \ + __r1 = (n1) % __d1; \ + __q1 = (n1) / __d1; \ + __m = (UWtype) __q1 * __d0; \ + __r1 = __r1 * __ll_B | __ll_highpart (n0); \ + if (__r1 < __m) \ + { \ + __q1--, __r1 += (d); \ + if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\ + if (__r1 < __m) \ + __q1--, __r1 += (d); \ + } \ + __r1 -= __m; \ + \ + __r0 = __r1 % __d1; \ + __q0 = __r1 / __d1; \ + __m = (UWtype) __q0 * __d0; \ + __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ + if (__r0 < __m) \ + { \ + __q0--, __r0 += (d); \ + if (__r0 >= (d)) \ + if (__r0 < __m) \ + __q0--, __r0 += (d); \ + } \ + __r0 -= __m; \ + \ + (q) = (UWtype) __q1 * __ll_B | __q0; \ + (r) = __r0; \ + } while (0) + +/* If the processor has no udiv_qrnnd but sdiv_qrnnd, go through + __udiv_w_sdiv (defined in libgcc or elsewhere). */ +#if !defined (udiv_qrnnd) && defined (sdiv_qrnnd) +#define udiv_qrnnd(q, r, nh, nl, d) \ + do { \ + USItype __r; \ + (q) = __udiv_w_sdiv (&__r, nh, nl, d); \ + (r) = __r; \ + } while (0) +#endif + +/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c. */ +#if !defined (udiv_qrnnd) +#define UDIV_NEEDS_NORMALIZATION 1 +#define udiv_qrnnd __udiv_qrnnd_c +#endif + +#if !defined (count_leading_zeros) +extern const UQItype __clz_tab[]; +#define count_leading_zeros(count, x) \ + do { \ + UWtype __xr = (x); \ + UWtype __a; \ + \ + if (W_TYPE_SIZE <= 32) \ + { \ + __a = __xr < ((UWtype)1<<2*__BITS4) \ + ? (__xr < ((UWtype)1<<__BITS4) ? 0 : __BITS4) \ + : (__xr < ((UWtype)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ + } \ + else \ + { \ + for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \ + if (((__xr >> __a) & 0xff) != 0) \ + break; \ + } \ + \ + (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \ + } while (0) +#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE +#endif + +#if !defined (count_trailing_zeros) +/* Define count_trailing_zeros using count_leading_zeros. The latter might be + defined in asm, but if it is not, the C version above is good enough. */ +#define count_trailing_zeros(count, x) \ + do { \ + UWtype __ctz_x = (x); \ + UWtype __ctz_c; \ + count_leading_zeros (__ctz_c, __ctz_x & -__ctz_x); \ + (count) = W_TYPE_SIZE - 1 - __ctz_c; \ + } while (0) +#endif + +#ifndef UDIV_NEEDS_NORMALIZATION +#define UDIV_NEEDS_NORMALIZATION 0 +#endif --- linux-2.6.27.orig/ubuntu/ndiswrapper/winnt_types.h +++ linux-2.6.27/ubuntu/ndiswrapper/winnt_types.h @@ -0,0 +1,1702 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _WINNT_TYPES_H_ +#define _WINNT_TYPES_H_ + +#define TRUE 1 +#define FALSE 0 + +#define PASSIVE_LEVEL 0 +#define APC_LEVEL 1 +#define DISPATCH_LEVEL 2 +#define DEVICE_LEVEL_BASE 4 + +/* soft interrupts / bottom-half's are disabled at SOFT_IRQL */ +#define SOFT_IRQL (DEVICE_LEVEL_BASE + 1) +#define DIRQL (DEVICE_LEVEL_BASE + 2) + +#define STATUS_WAIT_0 0 +#define STATUS_SUCCESS 0 +#define STATUS_ALERTED 0x00000101 +#define STATUS_TIMEOUT 0x00000102 +#define STATUS_PENDING 0x00000103 +#define STATUS_FAILURE 0xC0000001 +#define STATUS_NOT_IMPLEMENTED 0xC0000002 +#define STATUS_INVALID_PARAMETER 0xC000000D +#define STATUS_INVALID_DEVICE_REQUEST 0xC0000010 +#define STATUS_MORE_PROCESSING_REQUIRED 0xC0000016 +#define STATUS_ACCESS_DENIED 0xC0000022 +#define STATUS_BUFFER_TOO_SMALL 0xC0000023 +#define STATUS_OBJECT_NAME_INVALID 0xC0000023 +#define STATUS_MUTANT_NOT_OWNED 0xC0000046 +#define STATUS_RESOURCES 0xC000009A +#define STATUS_DELETE_PENDING 0xC0000056 +#define STATUS_INSUFFICIENT_RESOURCES 0xC000009A +#define STATUS_NOT_SUPPORTED 0xC00000BB +#define STATUS_INVALID_PARAMETER_2 0xC00000F0 +#define STATUS_NO_MEMORY 0xC0000017 +#define STATUS_CANCELLED 0xC0000120 +#define STATUS_DEVICE_REMOVED 0xC00002B6 +#define STATUS_DEVICE_NOT_CONNECTED 0xC000009D + +#define STATUS_BUFFER_OVERFLOW 0x80000005 + +#define SL_PENDING_RETURNED 0x01 +#define SL_INVOKE_ON_CANCEL 0x20 +#define SL_INVOKE_ON_SUCCESS 0x40 +#define SL_INVOKE_ON_ERROR 0x80 + +#define IRP_MJ_CREATE 0x00 +#define IRP_MJ_CREATE_NAMED_PIPE 0x01 +#define IRP_MJ_CLOSE 0x02 +#define IRP_MJ_READ 0x03 +#define IRP_MJ_WRITE 0x04 + +#define IRP_MJ_DEVICE_CONTROL 0x0E +#define IRP_MJ_INTERNAL_DEVICE_CONTROL 0x0F +#define IRP_MJ_POWER 0x16 +#define IRP_MJ_SYSTEM_CONTROL 0x0E +#define IRP_MJ_PNP 0x1b +#define IRP_MJ_MAXIMUM_FUNCTION 0x1b + +#define IRP_MN_WAIT_WAKE 0x00 +#define IRP_MN_POWER_SEQUENCE 0x01 +#define IRP_MN_SET_POWER 0x02 +#define IRP_MN_QUERY_POWER 0x03 + +#define IRP_MN_REGINFO 0x08 +#define IRP_MN_REGINFO_EX 0x0b + +#define IRP_MN_START_DEVICE 0x00 +#define IRP_MN_QUERY_REMOVE_DEVICE 0x01 +#define IRP_MN_REMOVE_DEVICE 0x02 +#define IRP_MN_CANCEL_REMOVE_DEVICE 0x03 +#define IRP_MN_STOP_DEVICE 0x04 +#define IRP_MN_QUERY_STOP_DEVICE 0x05 +#define IRP_MN_CANCEL_STOP_DEVICE 0x06 +#define IRP_MN_QUERY_DEVICE_RELATIONS 0x07 +#define IRP_MN_QUERY_INTERFACE 0x08 + +#define IRP_BUFFERED_IO 0x00000010 +#define IRP_DEALLOCATE_BUFFER 0x00000020 +#define IRP_INPUT_OPERATION 0x00000040 + +#define IRP_DEFFER_IO_COMPLETION 0x00000800 + +#define THREAD_WAIT_OBJECTS 3 +#define MAX_WAIT_OBJECTS 64 + +#define LOW_PRIORITY 0 +#define LOW_REALTIME_PRIORITY 16 +#define HIGH_PRIORITY 31 +#define MAXIMUM_PRIORITY 32 + +#define PROCESSOR_FEATURE_MAX 64 + +#define IO_NO_INCREMENT 0 + +#define WMIREG_ACTION_REGISTER 1 +#define WMIREG_ACTION_DEREGISTER 2 +#define WMIREG_ACTION_REREGISTER 3 +#define WMIREG_ACTION_UPDATE_GUIDS 4 + +#define WMIREGISTER 0 +#define WMIUPDATE 1 + +#ifdef CONFIG_X86_64 +#define wstdcall +#define wfastcall +#define noregparm + +#define KI_USER_SHARED_DATA 0xfffff78000000000UL + +#else + +#define noregparm __attribute__((regparm(0))) +#define wstdcall __attribute__((__stdcall__, regparm(0))) +#if defined(__GNUC__) && ((__GNUC__ == 3 && __GNUC_MINOR__ > 3) || __GNUC__ > 3) +#undef fastcall +#define wfastcall __attribute__((fastcall)) +#else +#error "gcc 3.4 or newer should be used for compiling this module" +#endif + +#define KI_USER_SHARED_DATA 0xffdf0000 + +#endif + +#define packed __attribute__((packed)) +#define no_warn_unused __attribute__((unused)) + +typedef u8 BOOLEAN; +typedef u8 BYTE; +typedef u8 *LPBYTE; +typedef s8 CHAR; +typedef u8 UCHAR; +typedef s16 SHORT; +typedef u16 USHORT; +typedef u16 WORD; +typedef s32 INT; +typedef u32 UINT; +typedef u32 DWORD; +typedef s32 LONG; +typedef u32 ULONG; +typedef s64 LONGLONG; +typedef u64 ULONGLONG; +typedef u64 ULONGULONG; +typedef u64 ULONG64; + +typedef CHAR CCHAR; +typedef USHORT wchar_t; +typedef SHORT CSHORT; +typedef LONGLONG LARGE_INTEGER; + +typedef LONG NTSTATUS; + +typedef LONG KPRIORITY; +typedef LARGE_INTEGER PHYSICAL_ADDRESS; +typedef UCHAR KIRQL; +typedef CHAR KPROCESSOR_MODE; + +/* ULONG_PTR is 32 bits on 32-bit platforms and 64 bits on 64-bit + * platform, which is same as 'unsigned long' in Linux */ +typedef unsigned long ULONG_PTR; + +typedef ULONG_PTR SIZE_T; +typedef ULONG_PTR KAFFINITY; +typedef ULONG ACCESS_MASK; + +typedef ULONG_PTR PFN_NUMBER; +typedef ULONG SECURITY_INFORMATION; + +/* non-negative numbers indicate success */ +#define NT_SUCCESS(status) ((NTSTATUS)(status) >= 0) + +struct ansi_string { + USHORT length; + USHORT max_length; + char *buf; +}; + +struct unicode_string { + USHORT length; + USHORT max_length; + wchar_t *buf; +}; + +struct nt_slist { + struct nt_slist *next; +}; + +#ifdef CONFIG_X86_64 +/* it is not clear how nt_slist_head is used to store pointer to + * slists and depth; here we assume 'align' field is used to store + * depth and 'region' field is used to store slist pointers */ +struct nt_slist_head { + union { + USHORT depth; + ULONGLONG align; + }; + union { + ULONGLONG region; + struct nt_slist *next; + }; +} __attribute__((aligned(16))); +typedef struct nt_slist_head nt_slist_header; +#else +union nt_slist_head { + ULONGLONG align; + struct { + struct nt_slist *next; + USHORT depth; + USHORT sequence; + }; +}; +typedef union nt_slist_head nt_slist_header; +#endif + +struct nt_list { + struct nt_list *next; + struct nt_list *prev; +}; + +typedef ULONG_PTR NT_SPIN_LOCK; + +enum kdpc_importance {LowImportance, MediumImportance, HighImportance}; + +struct kdpc; +typedef void (*DPC)(struct kdpc *kdpc, void *ctx, void *arg1, + void *arg2) wstdcall; +struct kdpc { + SHORT type; + UCHAR nr_cpu; + UCHAR importance; + struct nt_list list; + DPC func; + void *ctx; + void *arg1; + void *arg2; + union { + NT_SPIN_LOCK *lock; + /* 'lock' is not used; 'queued' represents whether + * kdpc is queued or not */ + int queued; + }; +}; + +enum pool_type { + NonPagedPool, PagedPool, NonPagedPoolMustSucceed, DontUseThisType, + NonPagedPoolCacheAligned, PagedPoolCacheAligned, + NonPagedPoolCacheAlignedMustS, MaxPoolType, + NonPagedPoolSession = 32, + PagedPoolSession = NonPagedPoolSession + 1, + NonPagedPoolMustSucceedSession = PagedPoolSession + 1, + DontUseThisTypeSession = NonPagedPoolMustSucceedSession + 1, + NonPagedPoolCacheAlignedSession = DontUseThisTypeSession + 1, + PagedPoolCacheAlignedSession = NonPagedPoolCacheAlignedSession + 1, + NonPagedPoolCacheAlignedMustSSession = PagedPoolCacheAlignedSession + 1 +}; + +enum memory_caching_type_orig { + MmFrameBufferCached = 2 +}; + +enum memory_caching_type { + MmNonCached = FALSE, MmCached = TRUE, + MmWriteCombined = MmFrameBufferCached, MmHardwareCoherentCached, + MmNonCachedUnordered, MmUSWCCached, MmMaximumCacheType +}; + +enum lock_operation { + IoReadAccess, IoWriteAccess, IoModifyAccess +}; + +enum mode { + KernelMode, UserMode, MaximumMode +}; + +struct mdl { + struct mdl *next; + CSHORT size; + CSHORT flags; + /* NdisFreeBuffer doesn't pass pool, so we store pool in + * unused field 'process' */ + union { + void *process; + void *pool; + }; + void *mappedsystemva; + void *startva; + ULONG bytecount; + ULONG byteoffset; +}; + +#define MDL_MAPPED_TO_SYSTEM_VA 0x0001 +#define MDL_PAGES_LOCKED 0x0002 +#define MDL_SOURCE_IS_NONPAGED_POOL 0x0004 +#define MDL_ALLOCATED_FIXED_SIZE 0x0008 +#define MDL_PARTIAL 0x0010 +#define MDL_PARTIAL_HAS_BEEN_MAPPED 0x0020 +#define MDL_IO_PAGE_READ 0x0040 +#define MDL_WRITE_OPERATION 0x0080 +#define MDL_PARENT_MAPPED_SYSTEM_VA 0x0100 +#define MDL_FREE_EXTRA_PTES 0x0200 +#define MDL_IO_SPACE 0x0800 +#define MDL_NETWORK_HEADER 0x1000 +#define MDL_MAPPING_CAN_FAIL 0x2000 +#define MDL_ALLOCATED_MUST_SUCCEED 0x4000 + +#define MDL_POOL_ALLOCATED 0x0400 +#define MDL_CACHE_ALLOCATED 0x8000 + +#define PAGE_START(ptr) ((void *)((ULONG_PTR)(ptr) & ~(PAGE_SIZE - 1))) +#define BYTE_OFFSET(ptr) ((ULONG)((ULONG_PTR)(ptr) & (PAGE_SIZE - 1))) + +#define MmGetMdlByteCount(mdl) ((mdl)->bytecount) +#define MmGetMdlVirtualAddress(mdl) ((mdl)->startva + (mdl)->byteoffset) +#define MmGetMdlByteOffset(mdl) ((mdl)->byteoffset) +#define MmGetSystemAddressForMdl(mdl) ((mdl)->mappedsystemva) +#define MmGetSystemAddressForMdlSafe(mdl, priority) ((mdl)->mappedsystemva) +#define MmGetMdlPfnArray(mdl) ((PFN_NUMBER *)(mdl + 1)) +#define MmInitializeMdl(mdl, baseva, length) \ +do { \ + (mdl)->next = NULL; \ + (mdl)->size = MmSizeOfMdl(baseva, length); \ + (mdl)->flags = 0; \ + (mdl)->startva = PAGE_START(baseva); \ + (mdl)->byteoffset = BYTE_OFFSET(baseva); \ + (mdl)->bytecount = length; \ + (mdl)->mappedsystemva = baseva; \ + TRACE4("%p %p %p %d %d", (mdl), baseva, (mdl)->startva, \ + (mdl)->byteoffset, length); \ +} while (0) + +struct kdevice_queue_entry { + struct nt_list list; + ULONG sort_key; + BOOLEAN inserted; +}; + +struct kdevice_queue { + USHORT type; + USHORT size; + struct nt_list list; + NT_SPIN_LOCK lock; + BOOLEAN busy; +}; + +struct wait_context_block { + struct kdevice_queue_entry wait_queue_entry; + void *device_routine; + void *device_context; + ULONG num_regs; + void *device_object; + void *current_irp; + void *buffer_chaining_dpc; +}; + +struct wait_block { + struct nt_list list; + struct task_struct *thread; + void *object; + int *wait_done; + USHORT wait_key; + USHORT wait_type; +}; + +struct dispatcher_header { + UCHAR type; + UCHAR absolute; + UCHAR size; + UCHAR inserted; + LONG signal_state; + struct nt_list wait_blocks; +}; + +enum event_type { + NotificationEvent, + SynchronizationEvent, +}; + +enum timer_type { + NotificationTimer = NotificationEvent, + SynchronizationTimer = SynchronizationEvent, +}; + +enum dh_type { + NotificationObject = NotificationEvent, + SynchronizationObject = SynchronizationEvent, + MutexObject, + SemaphoreObject, + ThreadObject, +}; + +enum wait_type { + WaitAll, WaitAny +}; + +/* objects that use dispatcher_header have it as the first field, so + * whenever we need to initialize dispatcher_header, we can convert + * that object into a nt_event and access dispatcher_header */ +struct nt_event { + struct dispatcher_header dh; +}; + +struct wrap_timer; + +#define WRAP_TIMER_MAGIC 47697249 + +struct nt_timer { + struct dispatcher_header dh; + /* We can't fit Linux timer in this structure. Instead of + * padding the nt_timer structure, we replace due_time field + * with *wrap_timer and allocate memory for it when nt_timer is + * initialized */ + union { + ULONGLONG due_time; + struct wrap_timer *wrap_timer; + }; + struct nt_list nt_timer_list; + struct kdpc *kdpc; + union { + LONG period; + LONG wrap_timer_magic; + }; +}; + +struct nt_mutex { + struct dispatcher_header dh; + struct nt_list list; + struct task_struct *owner_thread; + BOOLEAN abandoned; + BOOLEAN apc_disable; +}; + +struct nt_semaphore { + struct dispatcher_header dh; + LONG limit; +}; + +struct nt_thread { + struct dispatcher_header dh; + /* the rest in Windows is a long structure; since this + * structure is opaque to drivers, we just define what we + * need */ + int pid; + NTSTATUS status; + struct task_struct *task; + struct nt_list irps; + NT_SPIN_LOCK lock; + KPRIORITY prio; +}; + +#define set_object_type(dh, type) ((dh)->type = (type)) +#define is_notify_object(dh) ((dh)->type == NotificationObject) +#define is_synch_object(dh) ((dh)->type == SynchronizationObject) +#define is_mutex_object(dh) ((dh)->type == MutexObject) +#define is_semaphore_object(dh) ((dh)->type == SemaphoreObject) +#define is_nt_thread_object(dh) ((dh)->type == ThreadObject) + +#define IO_TYPE_ADAPTER 1 +#define IO_TYPE_CONTROLLER 2 +#define IO_TYPE_DEVICE 3 +#define IO_TYPE_DRIVER 4 +#define IO_TYPE_FILE 5 +#define IO_TYPE_IRP 6 +#define IO_TYPE_DEVICE_OBJECT_EXTENSION 13 + +struct irp; +struct dev_obj_ext; +struct driver_object; + +struct device_object { + CSHORT type; + USHORT size; + LONG ref_count; + struct driver_object *drv_obj; + struct device_object *next; + struct device_object *attached; + struct irp *current_irp; + void *io_timer; + ULONG flags; + ULONG characteristics; + void *vpb; + void *dev_ext; + CCHAR stack_count; + union { + struct nt_list queue_list; + struct wait_context_block wcb; + } queue; + ULONG align_req; + struct kdevice_queue dev_queue; + struct kdpc dpc; + ULONG active_threads; + void *security_desc; + struct nt_event lock; + USHORT sector_size; + USHORT spare1; + struct dev_obj_ext *dev_obj_ext; + void *reserved; +}; + +struct dev_obj_ext { + CSHORT type; + CSHORT size; + struct device_object *dev_obj; + struct device_object *attached_to; +}; + +struct io_status_block { + union { + NTSTATUS status; + void *pointer; + }; + ULONG_PTR info; +}; + +#ifdef CONFIG_X86_64 +struct io_status_block32 { + NTSTATUS status; + ULONG info; +}; +#endif + +#define DEVICE_TYPE ULONG + +struct driver_extension; + +typedef NTSTATUS driver_dispatch_t(struct device_object *dev_obj, + struct irp *irp) wstdcall; + +struct driver_object { + CSHORT type; + CSHORT size; + struct device_object *dev_obj; + ULONG flags; + void *start; + ULONG driver_size; + void *section; + struct driver_extension *drv_ext; + struct unicode_string name; + struct unicode_string *hardware_database; + void *fast_io_dispatch; + void *init; + void *start_io; + void (*unload)(struct driver_object *driver) wstdcall; + driver_dispatch_t *major_func[IRP_MJ_MAXIMUM_FUNCTION + 1]; +}; + +struct driver_extension { + struct driver_object *drv_obj; + NTSTATUS (*add_device)(struct driver_object *drv_obj, + struct device_object *dev_obj) wstdcall; + ULONG count; + struct unicode_string service_key_name; + struct nt_list custom_ext; +}; + +struct custom_ext { + struct nt_list list; + void *client_id; +}; + +struct wrap_bin_file; + +struct file_object { + CSHORT type; + CSHORT size; + struct device_object *dev_obj; + void *volume_parameter_block; + void *fs_context; + void *fs_context2; + void *section_object_pointer; + void *private_cache_map; + NTSTATUS final_status; + union { + struct file_object *related_file_object; + struct wrap_bin_file *wrap_bin_file; + }; + BOOLEAN lock_operation; + BOOLEAN delete_pending; + BOOLEAN read_access; + BOOLEAN write_access; + BOOLEAN delete_access; + BOOLEAN shared_read; + BOOLEAN shared_write; + BOOLEAN shared_delete; + ULONG flags; + struct unicode_string _name_; + LARGE_INTEGER current_byte_offset; + ULONG waiters; + ULONG busy; + void *last_lock; + struct nt_event lock; + struct nt_event event; + void *completion_context; +}; + +#ifdef CONFIG_X86_64 +#define POINTER_ALIGN __attribute__((aligned(8))) +#else +#define POINTER_ALIGN +#endif + +#define CACHE_ALIGN __attribute__((aligned(128))) + +enum system_power_state { + PowerSystemUnspecified = 0, + PowerSystemWorking, PowerSystemSleeping1, PowerSystemSleeping2, + PowerSystemSleeping3, PowerSystemHibernate, PowerSystemShutdown, + PowerSystemMaximum, +}; + +enum device_power_state { + PowerDeviceUnspecified = 0, + PowerDeviceD0, PowerDeviceD1, PowerDeviceD2, PowerDeviceD3, + PowerDeviceMaximum, +}; + +union power_state { + enum system_power_state system_state; + enum device_power_state device_state; +}; + +enum power_state_type { + SystemPowerState = 0, DevicePowerState, +}; + +enum power_action { + PowerActionNone = 0, + PowerActionReserved, PowerActionSleep, PowerActionHibernate, + PowerActionShutdown, PowerActionShutdownReset, PowerActionShutdownOff, + PowerActionWarmEject, +}; + +struct guid { + ULONG data1; + USHORT data2; + USHORT data3; + UCHAR data4[8]; +}; + +struct nt_interface { + USHORT size; + USHORT version; + void *context; + void (*reference)(void *context) wstdcall; + void (*dereference)(void *context) wstdcall; +}; + +enum interface_type { + InterfaceTypeUndefined = -1, Internal, Isa, Eisa, MicroChannel, + TurboChannel, PCIBus, VMEBus, NuBus, PCMCIABus, CBus, MPIBus, + MPSABus, ProcessorInternal, InternalPowerBus, PNPISABus, + PNPBus, MaximumInterfaceType, +}; + +#define CmResourceTypeNull 0 +#define CmResourceTypePort 1 +#define CmResourceTypeInterrupt 2 +#define CmResourceTypeMemory 3 +#define CmResourceTypeDma 4 +#define CmResourceTypeDeviceSpecific 5 +#define CmResourceTypeBusNumber 6 +#define CmResourceTypeMaximum 7 + +#define CmResourceTypeNonArbitrated 128 +#define CmResourceTypeConfigData 128 +#define CmResourceTypeDevicePrivate 129 +#define CmResourceTypePcCardConfig 130 +#define CmResourceTypeMfCardConfig 131 + +enum cm_share_disposition { + CmResourceShareUndetermined = 0, CmResourceShareDeviceExclusive, + CmResourceShareDriverExclusive, CmResourceShareShared +}; + +#define CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE 0 +#define CM_RESOURCE_INTERRUPT_LATCHED 1 +#define CM_RESOURCE_MEMORY_READ_WRITE 0x0000 +#define CM_RESOURCE_MEMORY_READ_ONLY 0x0001 +#define CM_RESOURCE_MEMORY_WRITE_ONLY 0x0002 +#define CM_RESOURCE_MEMORY_PREFETCHABLE 0x0004 + +#define CM_RESOURCE_MEMORY_COMBINEDWRITE 0x0008 +#define CM_RESOURCE_MEMORY_24 0x0010 +#define CM_RESOURCE_MEMORY_CACHEABLE 0x0020 + +#define CM_RESOURCE_PORT_MEMORY 0x0000 +#define CM_RESOURCE_PORT_IO 0x0001 +#define CM_RESOURCE_PORT_10_BIT_DECODE 0x0004 +#define CM_RESOURCE_PORT_12_BIT_DECODE 0x0008 +#define CM_RESOURCE_PORT_16_BIT_DECODE 0x0010 +#define CM_RESOURCE_PORT_POSITIVE_DECODE 0x0020 +#define CM_RESOURCE_PORT_PASSIVE_DECODE 0x0040 +#define CM_RESOURCE_PORT_WINDOW_DECODE 0x0080 + +#define CM_RESOURCE_DMA_8 0x0000 +#define CM_RESOURCE_DMA_16 0x0001 +#define CM_RESOURCE_DMA_32 0x0002 +#define CM_RESOURCE_DMA_8_AND_16 0x0004 +#define CM_RESOURCE_DMA_BUS_MASTER 0x0008 +#define CM_RESOURCE_DMA_TYPE_A 0x0010 +#define CM_RESOURCE_DMA_TYPE_B 0x0020 +#define CM_RESOURCE_DMA_TYPE_F 0x0040 + +#define MAX_RESOURCES 20 + +#pragma pack(push,4) +struct cm_partial_resource_descriptor { + UCHAR type; + UCHAR share; + USHORT flags; + union { + struct { + PHYSICAL_ADDRESS start; + ULONG length; + } generic; + struct { + PHYSICAL_ADDRESS start; + ULONG length; + } port; + struct { + ULONG level; + ULONG vector; + KAFFINITY affinity; + } interrupt; + struct { + PHYSICAL_ADDRESS start; + ULONG length; + } memory; + struct { + ULONG channel; + ULONG port; + ULONG reserved1; + } dma; + struct { + ULONG data[3]; + } device_private; + struct { + ULONG start; + ULONG length; + ULONG reserved; + } bus_number; + struct { + ULONG data_size; + ULONG reserved1; + ULONG reserved2; + } device_specific_data; + } u; +}; +#pragma pack(pop) + +struct cm_partial_resource_list { + USHORT version; + USHORT revision; + ULONG count; + struct cm_partial_resource_descriptor partial_descriptors[1]; +}; + +struct cm_full_resource_descriptor { + enum interface_type interface_type; + ULONG bus_number; + struct cm_partial_resource_list partial_resource_list; +}; + +struct cm_resource_list { + ULONG count; + struct cm_full_resource_descriptor list[1]; +}; + +enum file_info_class { + FileDirectoryInformation = 1, + FileBasicInformation = 4, + FileStandardInformation = 5, + FileNameInformation = 9, + FilePositionInformation = 14, + FileAlignmentInformation = 17, + FileNetworkOpenInformation = 34, + FileAttributeTagInformation = 35, + FileMaximumInformation = 41, +}; + +enum fs_info_class { + FileFsVolumeInformation = 1, + /* ... */ + FileFsMaximumInformation = 9, +}; + +enum device_relation_type { + BusRelations, EjectionRelations, PowerRelations, RemovalRelations, + TargetDeviceRelation, SingleBusRelations, +}; + +enum bus_query_id_type { + BusQueryDeviceID = 0, BusQueryHardwareIDs = 1, + BusQueryCompatibleIDs = 2, BusQueryInstanceID = 3, + BusQueryDeviceSerialNumber = 4, +}; + +enum device_text_type { + DeviceTextDescription = 0, DeviceTextLocationInformation = 1, +}; + +enum device_usage_notification_type { + DeviceUsageTypeUndefined, DeviceUsageTypePaging, + DeviceUsageTypeHibernation, DevbiceUsageTypeDumpFile, +}; + +#define METHOD_BUFFERED 0 +#define METHOD_IN_DIRECT 1 +#define METHOD_OUT_DIRECT 2 +#define METHOD_NEITHER 3 + +#define CTL_CODE(dev_type, func, method, access) \ + (((dev_type) << 16) | ((access) << 14) | ((func) << 2) | (method)) + +#define IO_METHOD_FROM_CTL_CODE(code) (code & 0x3) + +#ifndef CONFIG_X86_64 +#pragma pack(push,4) +#endif +struct io_stack_location { + UCHAR major_fn; + UCHAR minor_fn; + UCHAR flags; + UCHAR control; + union { + struct { + void *security_context; + ULONG options; + USHORT POINTER_ALIGN file_attributes; + USHORT share_access; + ULONG POINTER_ALIGN ea_length; + } create; + struct { + ULONG length; + ULONG POINTER_ALIGN key; + LARGE_INTEGER byte_offset; + } read; + struct { + ULONG length; + ULONG POINTER_ALIGN key; + LARGE_INTEGER byte_offset; + } write; + struct { + ULONG length; + enum file_info_class POINTER_ALIGN file_info_class; + } query_file; + struct { + ULONG length; + enum file_info_class POINTER_ALIGN file_info_class; + struct file_object *file_object; + union { + struct { + BOOLEAN replace_if_exists; + BOOLEAN advance_only; + }; + ULONG cluster_count; + void *delete_handle; + }; + } set_file; + struct { + ULONG length; + enum fs_info_class POINTER_ALIGN fs_info_class; + } query_volume; + struct { + ULONG output_buf_len; + ULONG POINTER_ALIGN input_buf_len; + ULONG POINTER_ALIGN code; + void *type3_input_buf; + } dev_ioctl; + struct { + SECURITY_INFORMATION security_info; + ULONG POINTER_ALIGN length; + } query_security; + struct { + SECURITY_INFORMATION security_info; + void *security_descriptor; + } set_security; + struct { + void *vpb; + struct device_object *device_object; + } mount_volume; + struct { + void *vpb; + struct device_object *device_object; + } verify_volume; + struct { + void *srb; + } scsi; + struct { + enum device_relation_type type; + } query_device_relations; + struct { + const struct guid *type; + USHORT size; + USHORT version; + struct nt_interface *intf; + void *intf_data; + } query_intf; + struct { + void *capabilities; + } device_capabilities; + struct { + void *io_resource_requirement_list; + } filter_resource_requirements; + struct { + ULONG which_space; + void *buffer; + ULONG offset; + ULONG POINTER_ALIGN length; + } read_write_config; + struct { + BOOLEAN lock; + } set_lock; + struct { + enum bus_query_id_type id_type; + } query_id; + struct { + enum device_text_type device_text_type; + ULONG POINTER_ALIGN locale_id; + } query_device_text; + struct { + BOOLEAN in_path; + BOOLEAN reserved[3]; + enum device_usage_notification_type POINTER_ALIGN type; + } usage_notification; + struct { + enum system_power_state power_state; + } wait_wake; + struct { + void *power_sequence; + } power_sequence; + struct { + ULONG sys_context; + enum power_state_type POINTER_ALIGN type; + union power_state POINTER_ALIGN state; + enum power_action POINTER_ALIGN shutdown_type; + } power; + struct { + struct cm_resource_list *allocated_resources; + struct cm_resource_list *allocated_resources_translated; + } start_device; + struct { + ULONG_PTR provider_id; + void *data_path; + ULONG buf_len; + void *buf; + } wmi; + struct { + void *arg1; + void *arg2; + void *arg3; + void *arg4; + } others; + } params; + struct device_object *dev_obj; + struct file_object *file_obj; + NTSTATUS (*completion_routine)(struct device_object *, + struct irp *, void *) wstdcall; + void *context; +}; +#ifndef CONFIG_X86_64 +#pragma pack(pop) +#endif + +struct kapc { + CSHORT type; + CSHORT size; + ULONG spare0; + struct nt_thread *thread; + struct nt_list list; + void *kernele_routine; + void *rundown_routine; + void *normal_routine; + void *normal_context; + void *sys_arg1; + void *sys_arg2; + CCHAR apc_state_index; + KPROCESSOR_MODE apc_mode; + BOOLEAN inserted; +}; + +#define IRP_NOCACHE 0x00000001 +#define IRP_SYNCHRONOUS_API 0x00000004 +#define IRP_ASSOCIATED_IRP 0x00000008 + +enum urb_state { + URB_INVALID = 1, URB_ALLOCATED, URB_SUBMITTED, + URB_COMPLETED, URB_FREE, URB_SUSPEND, URB_INT_UNLINKED }; + +struct wrap_urb { + struct nt_list list; + enum urb_state state; + struct nt_list complete_list; + unsigned int flags; + struct urb *urb; + struct irp *irp; +#ifdef USB_DEBUG + unsigned int id; +#endif +}; + +struct irp { + SHORT type; + USHORT size; + struct mdl *mdl; + ULONG flags; + union { + struct irp *master_irp; + LONG irp_count; + void *system_buffer; + } associated_irp; + struct nt_list thread_list; + struct io_status_block io_status; + KPROCESSOR_MODE requestor_mode; + BOOLEAN pending_returned; + CHAR stack_count; + CHAR current_location; + BOOLEAN cancel; + KIRQL cancel_irql; + CCHAR apc_env; + UCHAR alloc_flags; + struct io_status_block *user_status; + struct nt_event *user_event; + union { + struct { + void *user_apc_routine; + void *user_apc_context; + } async_params; + LARGE_INTEGER alloc_size; + } overlay; + void (*cancel_routine)(struct device_object *, struct irp *) wstdcall; + void *user_buf; + union { + struct { + union { + struct kdevice_queue_entry dev_q_entry; + struct { + void *driver_context[4]; + }; + }; + void *thread; + char *aux_buf; + struct { + struct nt_list list; + union { + struct io_stack_location *csl; + ULONG packet_type; + }; + }; + struct file_object *file_object; + } overlay; + union { + struct kapc apc; + /* space for apc is used for ndiswrapper + * specific fields */ + struct { + struct wrap_urb *wrap_urb; + struct wrap_device *wrap_device; + }; + }; + void *completion_key; + } tail; +}; + +#define IoSizeOfIrp(stack_count) \ + ((USHORT)(sizeof(struct irp) + \ + ((stack_count) * sizeof(struct io_stack_location)))) +#define IoGetCurrentIrpStackLocation(irp) \ + (irp)->tail.overlay.csl +#define IoGetNextIrpStackLocation(irp) \ + (IoGetCurrentIrpStackLocation(irp) - 1) +#define IoGetPreviousIrpStackLocation(irp) \ + (IoGetCurrentIrpStackLocation(irp) + 1) + +#define IoSetNextIrpStackLocation(irp) \ +do { \ + KIRQL _irql_; \ + IoAcquireCancelSpinLock(&_irql_); \ + (irp)->current_location--; \ + IoGetCurrentIrpStackLocation(irp)--; \ + IoReleaseCancelSpinLock(_irql_); \ +} while (0) + +#define IoSkipCurrentIrpStackLocation(irp) \ +do { \ + KIRQL _irql_; \ + IoAcquireCancelSpinLock(&_irql_); \ + (irp)->current_location++; \ + IoGetCurrentIrpStackLocation(irp)++; \ + IoReleaseCancelSpinLock(_irql_); \ +} while (0) + +static inline void +IoCopyCurrentIrpStackLocationToNext(struct irp *irp) +{ + struct io_stack_location *next; + next = IoGetNextIrpStackLocation(irp); + memcpy(next, IoGetCurrentIrpStackLocation(irp), + offsetof(struct io_stack_location, completion_routine)); + next->control = 0; +} + +static inline void +IoSetCompletionRoutine(struct irp *irp, void *routine, void *context, + BOOLEAN success, BOOLEAN error, BOOLEAN cancel) +{ + struct io_stack_location *irp_sl = IoGetNextIrpStackLocation(irp); + irp_sl->completion_routine = routine; + irp_sl->context = context; + irp_sl->control = 0; + if (success) + irp_sl->control |= SL_INVOKE_ON_SUCCESS; + if (error) + irp_sl->control |= SL_INVOKE_ON_ERROR; + if (cancel) + irp_sl->control |= SL_INVOKE_ON_CANCEL; +} + +#define IoMarkIrpPending(irp) \ + (IoGetCurrentIrpStackLocation((irp))->control |= SL_PENDING_RETURNED) +#define IoUnmarkIrpPending(irp) \ + (IoGetCurrentIrpStackLocation((irp))->control &= ~SL_PENDING_RETURNED) + +#define IRP_SL(irp, n) (((struct io_stack_location *)((irp) + 1)) + (n)) +#define IRP_DRIVER_CONTEXT(irp) (irp)->tail.overlay.driver_context +#define IoIrpThread(irp) ((irp)->tail.overlay.thread) + +#define IRP_URB(irp) \ + (union nt_urb *)(IoGetCurrentIrpStackLocation(irp)->params.others.arg1) + +#define IRP_WRAP_DEVICE(irp) (irp)->tail.wrap_device +#define IRP_WRAP_URB(irp) (irp)->tail.wrap_urb + +struct wmi_guid_reg_info { + struct guid *guid; + ULONG instance_count; + ULONG flags; +}; + +struct wmilib_context { + ULONG guid_count; + struct wmi_guid_reg_info *guid_list; + void *query_wmi_reg_info; + void *query_wmi_data_block; + void *set_wmi_data_block; + void *set_wmi_data_item; + void *execute_wmi_method; + void *wmi_function_control; +}; + +enum key_value_information_class { + KeyValueBasicInformation, KeyValueFullInformation, + KeyValuePartialInformation, KeyValueFullInformationAlign64, + KeyValuePartialInformationAlign64 +}; + +struct file_name_info { + ULONG length; + wchar_t *name; +}; + +struct file_std_info { + LARGE_INTEGER alloc_size; + LARGE_INTEGER eof; + ULONG num_links; + BOOLEAN delete_pending; + BOOLEAN dir; +}; + +enum nt_obj_type { + NT_OBJ_EVENT = 10, NT_OBJ_MUTEX, NT_OBJ_THREAD, NT_OBJ_TIMER, + NT_OBJ_SEMAPHORE, +}; + +enum common_object_type { + OBJECT_TYPE_NONE, OBJECT_TYPE_DEVICE, OBJECT_TYPE_DRIVER, + OBJECT_TYPE_NT_THREAD, OBJECT_TYPE_FILE, OBJECT_TYPE_CALLBACK, +}; + +struct common_object_header { + struct nt_list list; + enum common_object_type type; + UINT size; + UINT ref_count; + BOOLEAN close_in_process; + BOOLEAN permanent; + struct unicode_string name; +}; + +#define OBJECT_TO_HEADER(object) \ + (struct common_object_header *)((void *)(object) - \ + sizeof(struct common_object_header)) +#define OBJECT_SIZE(size) \ + ((size) + sizeof(struct common_object_header)) +#define HEADER_TO_OBJECT(hdr) \ + ((void *)(hdr) + sizeof(struct common_object_header)) +#define HANDLE_TO_OBJECT(handle) HEADER_TO_OBJECT(handle) +#define HANDLE_TO_HEADER(handle) (handle) + +enum work_queue_type { + CriticalWorkQueue, DelayedWorkQueue, HyperCriticalWorkQueue, + MaximumWorkQueue +}; + +typedef void (*NTOS_WORK_FUNC)(void *arg1, void *arg2) wstdcall; + +struct io_workitem { + enum work_queue_type type; + struct device_object *dev_obj; + NTOS_WORK_FUNC worker_routine; + void *context; +}; + +struct io_workitem_entry { + struct nt_list list; + struct io_workitem *io_workitem; +}; + +enum mm_page_priority { + LowPagePriority, NormalPagePriority = 16, HighPagePriority = 32 +}; + +enum kinterrupt_mode { + LevelSensitive, Latched +}; + +enum ntos_wait_reason { + Executive, FreePage, PageIn, PoolAllocation, DelayExecution, + Suspended, UserRequest, WrExecutive, WrFreePage, WrPageIn, + WrPoolAllocation, WrDelayExecution, WrSuspended, WrUserRequest, + WrEventPair, WrQueue, WrLpcReceive, WrLpcReply, WrVirtualMemory, + WrPageOut, WrRendezvous, Spare2, Spare3, Spare4, Spare5, Spare6, + WrKernel, MaximumWaitReason +}; + +typedef enum ntos_wait_reason KWAIT_REASON; + +typedef void *LOOKASIDE_ALLOC_FUNC(enum pool_type pool_type, + SIZE_T size, ULONG tag) wstdcall; +typedef void LOOKASIDE_FREE_FUNC(void *) wstdcall; + +struct npaged_lookaside_list { + nt_slist_header head; + USHORT depth; + USHORT maxdepth; + ULONG totalallocs; + union { + ULONG allocmisses; + ULONG allochits; + } u1; + ULONG totalfrees; + union { + ULONG freemisses; + ULONG freehits; + } u2; + enum pool_type pool_type; + ULONG tag; + ULONG size; + LOOKASIDE_ALLOC_FUNC *alloc_func; + LOOKASIDE_FREE_FUNC *free_func; + struct nt_list list; + ULONG lasttotallocs; + union { + ULONG lastallocmisses; + ULONG lastallochits; + } u3; + ULONG pad[2]; +#ifndef CONFIG_X86_64 + NT_SPIN_LOCK obsolete; +#endif +} +#ifdef CONFIG_X86_64 +CACHE_ALIGN +#endif +; + +enum device_registry_property { + DevicePropertyDeviceDescription, DevicePropertyHardwareID, + DevicePropertyCompatibleIDs, DevicePropertyBootConfiguration, + DevicePropertyBootConfigurationTranslated, + DevicePropertyClassName, DevicePropertyClassGuid, + DevicePropertyDriverKeyName, DevicePropertyManufacturer, + DevicePropertyFriendlyName, DevicePropertyLocationInformation, + DevicePropertyPhysicalDeviceObjectName, DevicePropertyBusTypeGuid, + DevicePropertyLegacyBusType, DevicePropertyBusNumber, + DevicePropertyEnumeratorName, DevicePropertyAddress, + DevicePropertyUINumber, DevicePropertyInstallState, + DevicePropertyRemovalPolicy +}; + +enum trace_information_class { + TraceIdClass, TraceHandleClass, TraceEnableFlagsClass, + TraceEnableLevelClass, GlobalLoggerHandleClass, EventLoggerHandleClass, + AllLoggerHandlesClass, TraceHandleByNameClass +}; + +struct kinterrupt; +typedef BOOLEAN (*PKSERVICE_ROUTINE)(struct kinterrupt *interrupt, + void *context) wstdcall; +typedef BOOLEAN (*PKSYNCHRONIZE_ROUTINE)(void *context) wstdcall; + +struct kinterrupt { + ULONG vector; + KAFFINITY cpu_mask; + NT_SPIN_LOCK lock; + NT_SPIN_LOCK *actual_lock; + BOOLEAN shared; + BOOLEAN save_fp; + union { + CHAR processor_number; +#ifdef CONFIG_DEBUG_SHIRQ + CHAR enabled; +#endif + } u; + PKSERVICE_ROUTINE isr; + void *isr_ctx; + struct nt_list list; + KIRQL irql; + KIRQL synch_irql; + enum kinterrupt_mode mode; +}; + +struct time_fields { + CSHORT year; + CSHORT month; + CSHORT day; + CSHORT hour; + CSHORT minute; + CSHORT second; + CSHORT milliseconds; + CSHORT weekday; +}; + +struct object_attributes { + ULONG length; + void *root_dir; + struct unicode_string *name; + ULONG attributes; + void *security_descr; + void *security_qos; +}; + +typedef void (*PCALLBACK_FUNCTION)(void *context, void *arg1, + void *arg2) wstdcall; + +struct callback_object; +struct callback_func { + PCALLBACK_FUNCTION func; + void *context; + struct nt_list list; + struct callback_object *object; +}; + +struct callback_object { + NT_SPIN_LOCK lock; + struct nt_list list; + struct nt_list callback_funcs; + BOOLEAN allow_multiple_callbacks; + struct object_attributes *attributes; +}; + +enum section_inherit { + ViewShare = 1, ViewUnmap = 2 +}; + +struct ksystem_time { + ULONG low_part; + LONG high1_time; + LONG high2_time; +}; + +enum nt_product_type { + nt_product_win_nt = 1, nt_product_lan_man_nt, nt_product_server +}; + +enum alt_arch_type { + arch_type_standard, arch_type_nex98x86, end_alternatives +}; + +struct kuser_shared_data { + ULONG tick_count; + ULONG tick_count_multiplier; + volatile struct ksystem_time interrupt_time; + volatile struct ksystem_time system_time; + volatile struct ksystem_time time_zone_bias; + USHORT image_number_low; + USHORT image_number_high; + wchar_t nt_system_root[260]; + ULONG max_stack_trace_depth; + ULONG crypto_exponent; + ULONG time_zone_id; + ULONG large_page_min; + ULONG reserved2[7]; + enum nt_product_type nt_product_type; + BOOLEAN product_type_is_valid; + ULONG nt_major_version; + ULONG nt_minor_version; + BOOLEAN processor_features[PROCESSOR_FEATURE_MAX]; + ULONG reserved1; + ULONG reserved3; + volatile LONG time_slip; + enum alt_arch_type alt_arch_type; + LARGE_INTEGER system_expiration_date; + ULONG suite_mask; + BOOLEAN kdbg_enabled; + volatile ULONG active_console; + volatile ULONG dismount_count; + ULONG com_plus_package; + ULONG last_system_rite_event_tick_count; + ULONG num_phys_pages; + BOOLEAN safe_boot_mode; + ULONG trace_log; + ULONGLONG fill0; + ULONGLONG sys_call[4]; + union { + volatile struct ksystem_time tick_count; + volatile ULONG64 tick_count_quad; + } tick; +}; + +#define REG_NONE (0) +#define REG_SZ (1) +#define REG_EXPAND_SZ (2) +#define REG_BINARY (3) +#define REG_DWORD (4) + +#define RTL_REGISTRY_ABSOLUTE 0 +#define RTL_REGISTRY_SERVICES 1 +#define RTL_REGISTRY_CONTROL 2 +#define RTL_REGISTRY_WINDOWS_NT 3 +#define RTL_REGISTRY_DEVICEMAP 4 +#define RTL_REGISTRY_USER 5 +#define RTL_REGISTRY_MAXIMUM 6 +#define RTL_REGISTRY_HANDLE 0x40000000 +#define RTL_REGISTRY_OPTIONAL 0x80000000 + +#define RTL_QUERY_REGISTRY_SUBKEY 0x00000001 +#define RTL_QUERY_REGISTRY_TOPKEY 0x00000002 +#define RTL_QUERY_REGISTRY_REQUIRED 0x00000004 +#define RTL_QUERY_REGISTRY_NOVALUE 0x00000008 +#define RTL_QUERY_REGISTRY_NOEXPAND 0x00000010 +#define RTL_QUERY_REGISTRY_DIRECT 0x00000020 +#define RTL_QUERY_REGISTRY_DELETE 0x00000040 + +typedef NTSTATUS (*PRTL_QUERY_REGISTRY_ROUTINE)(wchar_t *name, ULONG type, + void *data, ULONG length, + void *context, + void *entry) wstdcall; + +struct rtl_query_registry_table { + PRTL_QUERY_REGISTRY_ROUTINE query_func; + ULONG flags; + wchar_t *name; + void *context; + ULONG def_type; + void *def_data; + ULONG def_length; +}; + +struct io_remove_lock { + BOOLEAN removed; + BOOLEAN reserved[3]; + LONG io_count; + struct nt_event remove_event; +}; + +struct io_error_log_packet { + UCHAR major_fn_code; + UCHAR retry_count; + USHORT dump_data_size; + USHORT nr_of_strings; + USHORT string_offset; + USHORT event_category; + NTSTATUS error_code; + ULONG unique_error_value; + NTSTATUS final_status; + ULONG sequence_number; + ULONG io_control_code; + LARGE_INTEGER device_offset; + ULONG dump_data[1]; +}; + +/* some of the functions below are slightly different from DDK's + * implementation; e.g., Insert functions return appropriate + * pointer */ + +/* instead of using Linux's lists, we implement list manipulation + * functions because nt_list is used by drivers and we don't want to + * worry about Linux's list being different from nt_list (right now + * they are same, but in future they could be different) */ + +static inline void InitializeListHead(struct nt_list *head) +{ + head->next = head->prev = head; +} + +static inline BOOLEAN IsListEmpty(struct nt_list *head) +{ + if (head == head->next) + return TRUE; + else + return FALSE; +} + +static inline void RemoveEntryList(struct nt_list *entry) +{ + entry->prev->next = entry->next; + entry->next->prev = entry->prev; +} + +static inline struct nt_list *RemoveHeadList(struct nt_list *head) +{ + struct nt_list *entry; + + entry = head->next; + if (entry == head) + return NULL; + else { + RemoveEntryList(entry); + return entry; + } +} + +static inline struct nt_list *RemoveTailList(struct nt_list *head) +{ + struct nt_list *entry; + + entry = head->prev; + if (entry == head) + return NULL; + else { + RemoveEntryList(entry); + return entry; + } +} + +static inline void InsertListEntry(struct nt_list *entry, struct nt_list *prev, + struct nt_list *next) +{ + next->prev = entry; + entry->next = next; + entry->prev = prev; + prev->next = entry; +} + +static inline struct nt_list *InsertHeadList(struct nt_list *head, + struct nt_list *entry) +{ + struct nt_list *ret; + + if (IsListEmpty(head)) + ret = NULL; + else + ret = head->next; + + InsertListEntry(entry, head, head->next); + return ret; +} + +static inline struct nt_list *InsertTailList(struct nt_list *head, + struct nt_list *entry) +{ + struct nt_list *ret; + + if (IsListEmpty(head)) + ret = NULL; + else + ret = head->prev; + + InsertListEntry(entry, head->prev, head); + return ret; +} + +#define nt_list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +#define nt_list_for_each_entry(pos, head, member) \ + for (pos = container_of((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = container_of(pos->member.next, typeof(*pos), member)) + +#define nt_list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/* device object flags */ +#define DO_VERIFY_VOLUME 0x00000002 +#define DO_BUFFERED_IO 0x00000004 +#define DO_EXCLUSIVE 0x00000008 +#define DO_DIRECT_IO 0x00000010 +#define DO_MAP_IO_BUFFER 0x00000020 +#define DO_DEVICE_HAS_NAME 0x00000040 +#define DO_DEVICE_INITIALIZING 0x00000080 +#define DO_SYSTEM_BOOT_PARTITION 0x00000100 +#define DO_LONG_TERM_REQUESTS 0x00000200 +#define DO_NEVER_LAST_DEVICE 0x00000400 +#define DO_SHUTDOWN_REGISTERED 0x00000800 +#define DO_BUS_ENUMERATED_DEVICE 0x00001000 +#define DO_POWER_PAGABLE 0x00002000 +#define DO_POWER_INRUSH 0x00004000 +#define DO_LOW_PRIORITY_FILESYSTEM 0x00010000 + +/* Various supported device types (used with IoCreateDevice()) */ + +#define FILE_DEVICE_BEEP 0x00000001 +#define FILE_DEVICE_CD_ROM 0x00000002 +#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 +#define FILE_DEVICE_CONTROLLER 0x00000004 +#define FILE_DEVICE_DATALINK 0x00000005 +#define FILE_DEVICE_DFS 0x00000006 +#define FILE_DEVICE_DISK 0x00000007 +#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 +#define FILE_DEVICE_FILE_SYSTEM 0x00000009 +#define FILE_DEVICE_INPORT_PORT 0x0000000A +#define FILE_DEVICE_KEYBOARD 0x0000000B +#define FILE_DEVICE_MAILSLOT 0x0000000C +#define FILE_DEVICE_MIDI_IN 0x0000000D +#define FILE_DEVICE_MIDI_OUT 0x0000000E +#define FILE_DEVICE_MOUSE 0x0000000F +#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010 +#define FILE_DEVICE_NAMED_PIPE 0x00000011 +#define FILE_DEVICE_NETWORK 0x00000012 +#define FILE_DEVICE_NETWORK_BROWSER 0x00000013 +#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 +#define FILE_DEVICE_NULL 0x00000015 +#define FILE_DEVICE_PARALLEL_PORT 0x00000016 +#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017 +#define FILE_DEVICE_PRINTER 0x00000018 +#define FILE_DEVICE_SCANNER 0x00000019 +#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001A +#define FILE_DEVICE_SERIAL_PORT 0x0000001B +#define FILE_DEVICE_SCREEN 0x0000001C +#define FILE_DEVICE_SOUND 0x0000001D +#define FILE_DEVICE_STREAMS 0x0000001E +#define FILE_DEVICE_TAPE 0x0000001F +#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 +#define FILE_DEVICE_TRANSPORT 0x00000021 +#define FILE_DEVICE_UNKNOWN 0x00000022 +#define FILE_DEVICE_VIDEO 0x00000023 +#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 +#define FILE_DEVICE_WAVE_IN 0x00000025 +#define FILE_DEVICE_WAVE_OUT 0x00000026 +#define FILE_DEVICE_8042_PORT 0x00000027 +#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 +#define FILE_DEVICE_BATTERY 0x00000029 +#define FILE_DEVICE_BUS_EXTENDER 0x0000002A +#define FILE_DEVICE_MODEM 0x0000002B +#define FILE_DEVICE_VDM 0x0000002C +#define FILE_DEVICE_MASS_STORAGE 0x0000002D +#define FILE_DEVICE_SMB 0x0000002E +#define FILE_DEVICE_KS 0x0000002F +#define FILE_DEVICE_CHANGER 0x00000030 +#define FILE_DEVICE_SMARTCARD 0x00000031 +#define FILE_DEVICE_ACPI 0x00000032 +#define FILE_DEVICE_DVD 0x00000033 +#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034 +#define FILE_DEVICE_DFS_FILE_SYSTEM 0x00000035 +#define FILE_DEVICE_DFS_VOLUME 0x00000036 +#define FILE_DEVICE_SERENUM 0x00000037 +#define FILE_DEVICE_TERMSRV 0x00000038 +#define FILE_DEVICE_KSEC 0x00000039 +#define FILE_DEVICE_FIPS 0x0000003A + +/* Device characteristics */ + +#define FILE_REMOVABLE_MEDIA 0x00000001 +#define FILE_READ_ONLY_DEVICE 0x00000002 +#define FILE_FLOPPY_DISKETTE 0x00000004 +#define FILE_WRITE_ONCE_MEDIA 0x00000008 +#define FILE_REMOTE_DEVICE 0x00000010 +#define FILE_DEVICE_IS_MOUNTED 0x00000020 +#define FILE_VIRTUAL_VOLUME 0x00000040 +#define FILE_AUTOGENERATED_DEVICE_NAME 0x00000080 +#define FILE_DEVICE_SECURE_OPEN 0x00000100 + +#define FILE_READ_DATA 0x0001 +#define FILE_WRITE_DATA 0x0002 + +#define FILE_SUPERSEDED 0x00000000 +#define FILE_OPENED 0x00000001 +#define FILE_CREATED 0x00000002 +#define FILE_OVERWRITTEN 0x00000003 +#define FILE_EXISTS 0x00000004 +#define FILE_DOES_NOT_EXIST 0x00000005 + + +#endif /* WINNT_TYPES_H */ --- linux-2.6.27.orig/ubuntu/ndiswrapper/loader.c +++ linux-2.6.27/ubuntu/ndiswrapper/loader.c @@ -0,0 +1,877 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "ndis.h" +#include "loader.h" +#include "wrapndis.h" +#include "pnp.h" + +#include +#include +#include +#include + +/* + Network adapter: ClassGuid = {4d36e972-e325-11ce-bfc1-08002be10318} + Network client: ClassGuid = {4d36e973-e325-11ce-bfc1-08002be10318} + PCMCIA adapter: ClassGuid = {4d36e977-e325-11ce-bfc1-08002be10318} + USB: ClassGuid = {36fc9e60-c465-11cf-8056-444553540000} +*/ + +/* the indices used here must match macros WRAP_NDIS_DEVICE etc. */ +static struct guid class_guids[] = { + /* Network */ + {0x4d36e972, 0xe325, 0x11ce, }, + /* USB WDM */ + {0x36fc9e60, 0xc465, 0x11cf, }, + /* Bluetooth */ + {0xe0cbf06c, 0xcd8b, 0x4647, }, + /* ivtcorporatino.com's bluetooth device claims this is + * bluetooth guid */ + {0xf12d3cf8, 0xb11d, 0x457e, }, +}; + +struct semaphore loader_mutex; +static struct completion loader_complete; + +static struct nt_list wrap_devices; +static struct nt_list wrap_drivers; + +static int wrap_device_type(int data1) +{ + int i; + for (i = 0; i < sizeof(class_guids) / sizeof(class_guids[0]); i++) + if (data1 == class_guids[i].data1) + return i; + ERROR("unknown device: 0x%x\n", data1); + return -1; +} + +/* load driver for given device, if not already loaded */ +struct wrap_driver *load_wrap_driver(struct wrap_device *wd) +{ + int ret; + struct nt_list *cur; + struct wrap_driver *wrap_driver; + + ENTER1("device: %04X:%04X:%04X:%04X", wd->vendor, wd->device, + wd->subvendor, wd->subdevice); + if (down_interruptible(&loader_mutex)) { + WARNING("couldn't obtain loader_mutex"); + EXIT1(return NULL); + } + wrap_driver = NULL; + nt_list_for_each(cur, &wrap_drivers) { + wrap_driver = container_of(cur, struct wrap_driver, list); + if (!stricmp(wrap_driver->name, wd->driver_name)) { + TRACE1("driver %s already loaded", wrap_driver->name); + break; + } else + wrap_driver = NULL; + } + up(&loader_mutex); + + if (!wrap_driver) { + char *argv[] = {"loadndisdriver", WRAP_CMD_LOAD_DRIVER, +#if defined(DEBUG) && DEBUG >= 1 + "1", +#else + "0", +#endif + UTILS_VERSION, wd->driver_name, + wd->conf_file_name, NULL}; + char *env[] = {NULL}; + + TRACE1("loading driver %s", wd->driver_name); + if (down_interruptible(&loader_mutex)) { + WARNING("couldn't obtain loader_mutex"); + EXIT1(return NULL); + } + INIT_COMPLETION(loader_complete); + ret = call_usermodehelper("/sbin/loadndisdriver", argv, env, 1); + if (ret) { + up(&loader_mutex); + ERROR("couldn't load driver %s; check system log " + "for messages from 'loadndisdriver'", + wd->driver_name); + EXIT1(return NULL); + } + wait_for_completion(&loader_complete); + TRACE1("%s", wd->driver_name); + wrap_driver = NULL; + nt_list_for_each(cur, &wrap_drivers) { + wrap_driver = container_of(cur, struct wrap_driver, + list); + if (!stricmp(wrap_driver->name, wd->driver_name)) { + wd->driver = wrap_driver; + break; + } else + wrap_driver = NULL; + } + up(&loader_mutex); + if (wrap_driver) + TRACE1("driver %s is loaded", wrap_driver->name); + else + ERROR("couldn't load driver '%s'", wd->driver_name); + } + EXIT1(return wrap_driver); +} + +/* load the driver files from userspace. */ +static int load_sys_files(struct wrap_driver *driver, + struct load_driver *load_driver) +{ + int i, err; + + TRACE1("num_pe_images = %d", load_driver->num_sys_files); + TRACE1("loading driver: %s", load_driver->name); + strncpy(driver->name, load_driver->name, sizeof(driver->name)); + driver->name[sizeof(driver->name)-1] = 0; + TRACE1("driver: %s", driver->name); + err = 0; + driver->num_pe_images = 0; + for (i = 0; i < load_driver->num_sys_files; i++) { + struct pe_image *pe_image; + pe_image = &driver->pe_images[driver->num_pe_images]; + + strncpy(pe_image->name, load_driver->sys_files[i].name, + sizeof(pe_image->name)); + pe_image->name[sizeof(pe_image->name)-1] = 0; + TRACE1("image size: %lu bytes", + (unsigned long)load_driver->sys_files[i].size); + +#ifdef CONFIG_X86_64 +#ifdef PAGE_KERNEL_EXECUTABLE + pe_image->image = + __vmalloc(load_driver->sys_files[i].size, + GFP_KERNEL | __GFP_HIGHMEM, + PAGE_KERNEL_EXECUTABLE); +#elif defined PAGE_KERNEL_EXEC + pe_image->image = + __vmalloc(load_driver->sys_files[i].size, + GFP_KERNEL | __GFP_HIGHMEM, + PAGE_KERNEL_EXEC); +#else +#error x86_64 should have either PAGE_KERNEL_EXECUTABLE or PAGE_KERNEL_EXEC +#endif +#else + /* hate to play with kernel macros, but PAGE_KERNEL_EXEC is + * not available to modules! */ +#ifdef cpu_has_nx + if (cpu_has_nx) + pe_image->image = + __vmalloc(load_driver->sys_files[i].size, + GFP_KERNEL | __GFP_HIGHMEM, + __pgprot(__PAGE_KERNEL & ~_PAGE_NX)); + else + pe_image->image = + vmalloc(load_driver->sys_files[i].size); +#else + pe_image->image = + vmalloc(load_driver->sys_files[i].size); +#endif +#endif + if (!pe_image->image) { + ERROR("couldn't allocate memory"); + err = -ENOMEM; + break; + } + TRACE1("image is at %p", pe_image->image); + + if (copy_from_user(pe_image->image, + load_driver->sys_files[i].data, + load_driver->sys_files[i].size)) { + ERROR("couldn't load file %s", + load_driver->sys_files[i].name); + err = -EFAULT; + break; + } + pe_image->size = load_driver->sys_files[i].size; + driver->num_pe_images++; + } + + if (!err && link_pe_images(driver->pe_images, driver->num_pe_images)) { + ERROR("couldn't prepare driver '%s'", load_driver->name); + err = -EINVAL; + } + + if (driver->num_pe_images < load_driver->num_sys_files || err) { + for (i = 0; i < driver->num_pe_images; i++) + if (driver->pe_images[i].image) + vfree(driver->pe_images[i].image); + driver->num_pe_images = 0; + EXIT1(return err); + } else + EXIT1(return 0); +} + +struct wrap_bin_file *get_bin_file(char *bin_file_name) +{ + int i = 0; + struct wrap_driver *driver, *cur; + + ENTER1("%s", bin_file_name); + if (down_interruptible(&loader_mutex)) { + WARNING("couldn't obtain loader_mutex"); + EXIT1(return NULL); + } + driver = NULL; + nt_list_for_each_entry(cur, &wrap_drivers, list) { + for (i = 0; i < cur->num_bin_files; i++) + if (!stricmp(cur->bin_files[i].name, bin_file_name)) { + driver = cur; + break; + } + if (driver) + break; + } + up(&loader_mutex); + if (!driver) { + TRACE1("coudln't find bin file '%s'", bin_file_name); + return NULL; + } + + if (!driver->bin_files[i].data) { + char *argv[] = {"loadndisdriver", WRAP_CMD_LOAD_BIN_FILE, +#if defined(DEBUG) && DEBUG >= 1 + "1", +#else + "0", +#endif + UTILS_VERSION, driver->name, + driver->bin_files[i].name, NULL}; + char *env[] = {NULL}; + int ret; + + TRACE1("loading bin file %s/%s", driver->name, + driver->bin_files[i].name); + if (down_interruptible(&loader_mutex)) { + WARNING("couldn't obtain loader_mutex"); + EXIT1(return NULL); + } + INIT_COMPLETION(loader_complete); + ret = call_usermodehelper("/sbin/loadndisdriver", argv, env, 1); + if (ret) { + up(&loader_mutex); + ERROR("couldn't load file %s/%s; check system log " + "for messages from 'loadndisdriver' (%d)", + driver->name, driver->bin_files[i].name, ret); + EXIT1(return NULL); + } + wait_for_completion(&loader_complete); + up(&loader_mutex); + if (!driver->bin_files[i].data) { + WARNING("couldn't load binary file %s", + driver->bin_files[i].name); + EXIT1(return NULL); + } + } + EXIT2(return &(driver->bin_files[i])); +} + +/* called with loader_mutex down */ +static int add_bin_file(struct load_driver_file *driver_file) +{ + struct wrap_driver *driver, *cur; + struct wrap_bin_file *bin_file; + int i = 0; + + driver = NULL; + nt_list_for_each_entry(cur, &wrap_drivers, list) { + for (i = 0; i < cur->num_bin_files; i++) + if (!stricmp(cur->bin_files[i].name, + driver_file->name)) { + driver = cur; + break; + } + if (driver) + break; + } + if (!driver) { + ERROR("couldn't find %s", driver_file->name); + return -EINVAL; + } + bin_file = &driver->bin_files[i]; + strncpy(bin_file->name, driver_file->name, sizeof(bin_file->name)); + bin_file->name[sizeof(bin_file->name)-1] = 0; + bin_file->data = vmalloc(driver_file->size); + if (!bin_file->data) { + ERROR("couldn't allocate memory"); + return -ENOMEM; + } + bin_file->size = driver_file->size; + if (copy_from_user(bin_file->data, driver_file->data, bin_file->size)) { + ERROR("couldn't copy data"); + free_bin_file(bin_file); + return -EFAULT; + } + return 0; +} + +void free_bin_file(struct wrap_bin_file *bin_file) +{ + TRACE2("unloading %s", bin_file->name); + if (bin_file->data) + vfree(bin_file->data); + bin_file->data = NULL; + bin_file->size = 0; + EXIT2(return); +} + +/* load firmware files from userspace */ +static int load_bin_files_info(struct wrap_driver *driver, + struct load_driver *load_driver) +{ + struct wrap_bin_file *bin_files; + int i; + + ENTER1("%s, %d", load_driver->name, load_driver->num_bin_files); + driver->num_bin_files = 0; + driver->bin_files = NULL; + if (load_driver->num_bin_files == 0) + EXIT1(return 0); + bin_files = kzalloc(load_driver->num_bin_files * sizeof(*bin_files), + GFP_KERNEL); + if (!bin_files) { + ERROR("couldn't allocate memory"); + EXIT1(return -ENOMEM); + } + + for (i = 0; i < load_driver->num_bin_files; i++) { + strncpy(bin_files[i].name, load_driver->bin_files[i].name, + sizeof(bin_files[i].name)); + bin_files[i].name[sizeof(bin_files[i].name)-1] = 0; + TRACE2("loaded bin file %s", bin_files[i].name); + } + driver->num_bin_files = load_driver->num_bin_files; + driver->bin_files = bin_files; + EXIT1(return 0); +} + +/* load settnigs for a device. called with loader_mutex down */ +static int load_settings(struct wrap_driver *wrap_driver, + struct load_driver *load_driver) +{ + int i, num_settings; + + ENTER1("%p, %p", wrap_driver, load_driver); + + num_settings = 0; + for (i = 0; i < load_driver->num_settings; i++) { + struct load_device_setting *load_setting = + &load_driver->settings[i]; + struct wrap_device_setting *setting; + ULONG data1; + + setting = kzalloc(sizeof(*setting), GFP_KERNEL); + if (!setting) { + ERROR("couldn't allocate memory"); + break; + } + strncpy(setting->name, load_setting->name, + sizeof(setting->name)); + setting->name[sizeof(setting->name)-1] = 0; + strncpy(setting->value, load_setting->value, + sizeof(setting->value)); + setting->value[sizeof(setting->value)-1] = 0; + TRACE2("%p: %s=%s", setting, setting->name, setting->value); + + if (strcmp(setting->name, "driver_version") == 0) { + strncpy(wrap_driver->version, setting->value, + sizeof(wrap_driver->version)); + wrap_driver->version[sizeof(wrap_driver->version)-1] = 0; + } else if (strcmp(setting->name, "class_guid") == 0 && + sscanf(setting->value, "%x", &data1) == 1) { + wrap_driver->dev_type = wrap_device_type(data1); + if (wrap_driver->dev_type < 0) { + WARNING("unknown guid: %x", data1); + wrap_driver->dev_type = 0; + } + } + InsertTailList(&wrap_driver->settings, &setting->list); + num_settings++; + } + /* it is not a fatal error if some settings couldn't be loaded */ + if (num_settings > 0) + EXIT1(return 0); + else + EXIT1(return -EINVAL); +} + +void unload_wrap_device(struct wrap_device *wd) +{ + struct nt_list *cur; + ENTER1("unloading device %p (%04X:%04X:%04X:%04X), driver %s", wd, + wd->vendor, wd->device, wd->subvendor, wd->subdevice, + wd->driver_name); + if (down_interruptible(&loader_mutex)) + WARNING("couldn't obtain loader_mutex"); + while ((cur = RemoveHeadList(&wd->settings))) { + struct wrap_device_setting *setting; + setting = container_of(cur, struct wrap_device_setting, list); + kfree(setting); + } + RemoveEntryList(&wd->list); + up(&loader_mutex); + kfree(wd); + EXIT1(return); +} + +/* should be called with loader_mutex down */ +void unload_wrap_driver(struct wrap_driver *driver) +{ + int i; + struct driver_object *drv_obj; + struct nt_list *cur, *next; + + ENTER1("unloading driver: %s (%p)", driver->name, driver); + TRACE1("freeing %d images", driver->num_pe_images); + drv_obj = driver->drv_obj; + for (i = 0; i < driver->num_pe_images; i++) + if (driver->pe_images[i].image) { + TRACE1("freeing image at %p", + driver->pe_images[i].image); + vfree(driver->pe_images[i].image); + } + + TRACE1("freeing %d bin files", driver->num_bin_files); + for (i = 0; i < driver->num_bin_files; i++) { + TRACE1("freeing image at %p", driver->bin_files[i].data); + if (driver->bin_files[i].data) + vfree(driver->bin_files[i].data); + } + if (driver->bin_files) + kfree(driver->bin_files); + RtlFreeUnicodeString(&drv_obj->name); + RemoveEntryList(&driver->list); + nt_list_for_each_safe(cur, next, &driver->settings) { + struct wrap_device_setting *setting; + struct ndis_configuration_parameter *param; + + setting = container_of(cur, struct wrap_device_setting, list); + TRACE2("%p", setting); + param = setting->encoded; + if (param) { + TRACE2("%p", param); + if (param->type == NdisParameterString) + RtlFreeUnicodeString(¶m->data.string); + ExFreePool(param); + } + kfree(setting); + } + /* this frees driver */ + free_custom_extensions(drv_obj->drv_ext); + kfree(drv_obj->drv_ext); + TRACE1("drv_obj: %p", drv_obj); + + EXIT1(return); +} + +/* call the entry point of the driver */ +static int start_wrap_driver(struct wrap_driver *driver) +{ + int i; + NTSTATUS ret, res; + struct driver_object *drv_obj; + typeof(driver->pe_images[0].entry) entry; + + ENTER1("%s", driver->name); + drv_obj = driver->drv_obj; + for (ret = res = 0, i = 0; i < driver->num_pe_images; i++) + /* dlls are already started by loader */ + if (driver->pe_images[i].type == IMAGE_FILE_EXECUTABLE_IMAGE) { + entry = driver->pe_images[i].entry; + drv_obj->start = driver->pe_images[i].entry; + drv_obj->driver_size = driver->pe_images[i].size; + TRACE1("entry: %p, %p, drv_obj: %p", + entry, *entry, drv_obj); + res = LIN2WIN2(entry, drv_obj, &drv_obj->name); + ret |= res; + TRACE1("entry returns %08X", res); + break; + } + if (ret) { + ERROR("driver initialization failed: %08X", ret); + RtlFreeUnicodeString(&drv_obj->name); + /* this frees ndis_driver */ + free_custom_extensions(drv_obj->drv_ext); + kfree(drv_obj->drv_ext); + TRACE1("drv_obj: %p", drv_obj); + ObDereferenceObject(drv_obj); + EXIT1(return -EINVAL); + } + EXIT1(return 0); +} + +/* + * add driver to list of loaded driver but make sure this driver is + * not loaded before. called with loader_mutex down + */ +static int add_wrap_driver(struct wrap_driver *driver) +{ + struct wrap_driver *tmp; + + ENTER1("name: %s", driver->name); + nt_list_for_each_entry(tmp, &wrap_drivers, list) { + if (stricmp(tmp->name, driver->name) == 0) { + ERROR("cannot add duplicate driver"); + EXIT1(return -EBUSY); + } + } + InsertHeadList(&wrap_drivers, &driver->list); + EXIT1(return 0); +} + +/* load a driver from userspace and initialize it. called with + * loader_mutex down */ +static int load_user_space_driver(struct load_driver *load_driver) +{ + struct driver_object *drv_obj; + struct ansi_string ansi_reg; + struct wrap_driver *wrap_driver = NULL; + + ENTER1("%p", load_driver); + drv_obj = allocate_object(sizeof(*drv_obj), OBJECT_TYPE_DRIVER, NULL); + if (!drv_obj) { + ERROR("couldn't allocate memory"); + EXIT1(return -ENOMEM); + } + TRACE1("drv_obj: %p", drv_obj); + drv_obj->drv_ext = kzalloc(sizeof(*(drv_obj->drv_ext)), GFP_KERNEL); + if (!drv_obj->drv_ext) { + ERROR("couldn't allocate memory"); + ObDereferenceObject(drv_obj); + EXIT1(return -ENOMEM); + } + InitializeListHead(&drv_obj->drv_ext->custom_ext); + if (IoAllocateDriverObjectExtension(drv_obj, + (void *)WRAP_DRIVER_CLIENT_ID, + sizeof(*wrap_driver), + (void **)&wrap_driver) != + STATUS_SUCCESS) + EXIT1(return -ENOMEM); + TRACE1("driver: %p", wrap_driver); + memset(wrap_driver, 0, sizeof(*wrap_driver)); + InitializeListHead(&wrap_driver->list); + InitializeListHead(&wrap_driver->settings); + InitializeListHead(&wrap_driver->wrap_devices); + wrap_driver->drv_obj = drv_obj; + RtlInitAnsiString(&ansi_reg, "/tmp"); + if (RtlAnsiStringToUnicodeString(&drv_obj->name, &ansi_reg, TRUE) != + STATUS_SUCCESS) { + ERROR("couldn't initialize registry path"); + free_custom_extensions(drv_obj->drv_ext); + kfree(drv_obj->drv_ext); + TRACE1("drv_obj: %p", drv_obj); + ObDereferenceObject(drv_obj); + EXIT1(return -EINVAL); + } + strncpy(wrap_driver->name, load_driver->name, sizeof(wrap_driver->name)); + wrap_driver->name[sizeof(wrap_driver->name)-1] = 0; + if (load_sys_files(wrap_driver, load_driver) || + load_bin_files_info(wrap_driver, load_driver) || + load_settings(wrap_driver, load_driver) || + start_wrap_driver(wrap_driver) || + add_wrap_driver(wrap_driver)) { + unload_wrap_driver(wrap_driver); + EXIT1(return -EINVAL); + } else { + printk(KERN_INFO "%s: driver %s (%s) loaded\n", + DRIVER_NAME, wrap_driver->name, wrap_driver->version); + add_taint(TAINT_PROPRIETARY_MODULE); + EXIT1(return 0); + } +} + +static struct pci_device_id wrap_pci_id_table[] = { + {PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID}, +}; + +static struct pci_driver wrap_pci_driver = { + .name = DRIVER_NAME, + .id_table = wrap_pci_id_table, + .probe = wrap_pnp_start_pci_device, + .remove = __devexit_p(wrap_pnp_remove_pci_device), + .suspend = wrap_pnp_suspend_pci_device, + .resume = wrap_pnp_resume_pci_device, +}; + +#ifdef ENABLE_USB +static struct usb_device_id wrap_usb_id_table[] = { + { + .driver_info = 1 + }, +}; + +static struct usb_driver wrap_usb_driver = { + .name = DRIVER_NAME, + .id_table = wrap_usb_id_table, + .probe = wrap_pnp_start_usb_device, + .disconnect = __devexit_p(wrap_pnp_remove_usb_device), + .suspend = wrap_pnp_suspend_usb_device, + .resume = wrap_pnp_resume_usb_device, +}; +#endif + +/* register drivers for pci and usb */ +static void register_devices(void) +{ + int res; + + res = pci_register_driver(&wrap_pci_driver); + if (res < 0) { + ERROR("couldn't register pci driver: %d", res); + wrap_pci_driver.name = NULL; + } + +#ifdef ENABLE_USB + res = usb_register(&wrap_usb_driver); + if (res < 0) { + ERROR("couldn't register usb driver: %d", res); + wrap_usb_driver.name = NULL; + } +#endif + EXIT1(return); +} + +static void unregister_devices(void) +{ + struct nt_list *cur, *next; + + if (down_interruptible(&loader_mutex)) + WARNING("couldn't obtain loader_mutex"); + nt_list_for_each_safe(cur, next, &wrap_devices) { + struct wrap_device *wd; + wd = container_of(cur, struct wrap_device, list); + set_bit(HW_PRESENT, &wd->hw_status); + } + up(&loader_mutex); + + if (wrap_pci_driver.name) + pci_unregister_driver(&wrap_pci_driver); +#ifdef ENABLE_USB + if (wrap_usb_driver.name) + usb_deregister(&wrap_usb_driver); +#endif +} + +struct wrap_device *load_wrap_device(struct load_device *load_device) +{ + int ret; + struct nt_list *cur; + struct wrap_device *wd = NULL; + char vendor[5], device[5], subvendor[5], subdevice[5], bus[5]; + + ENTER1("%04x, %04x, %04x, %04x", load_device->vendor, + load_device->device, load_device->subvendor, + load_device->subdevice); + if (sprintf(vendor, "%04x", load_device->vendor) == 4 && + sprintf(device, "%04x", load_device->device) == 4 && + sprintf(subvendor, "%04x", load_device->subvendor) == 4 && + sprintf(subdevice, "%04x", load_device->subdevice) == 4 && + sprintf(bus, "%04x", load_device->bus) == 4) { + char *argv[] = {"loadndisdriver", WRAP_CMD_LOAD_DEVICE, +#if defined(DEBUG) && DEBUG >= 1 + "1", +#else + "0", +#endif + UTILS_VERSION, vendor, device, + subvendor, subdevice, bus, NULL}; + char *env[] = {NULL}; + TRACE2("%s, %s, %s, %s, %s", vendor, device, + subvendor, subdevice, bus); + if (down_interruptible(&loader_mutex)) { + WARNING("couldn't obtain loader_mutex"); + EXIT1(return NULL); + } + INIT_COMPLETION(loader_complete); + ret = call_usermodehelper("/sbin/loadndisdriver", argv, env, 1); + if (ret) { + up(&loader_mutex); + TRACE1("couldn't load device %04x:%04x; check system " + "log for messages from 'loadndisdriver'", + load_device->vendor, load_device->device); + EXIT1(return NULL); + } + wait_for_completion(&loader_complete); + wd = NULL; + nt_list_for_each(cur, &wrap_devices) { + wd = container_of(cur, struct wrap_device, list); + TRACE2("%p, %04x, %04x, %04x, %04x", wd, wd->vendor, + wd->device, wd->subvendor, wd->subdevice); + if (wd->vendor == load_device->vendor && + wd->device == load_device->device) + break; + else + wd = NULL; + } + up(&loader_mutex); + } else + wd = NULL; + EXIT1(return wd); +} + +struct wrap_device *get_wrap_device(void *dev, int bus) +{ + struct nt_list *cur; + struct wrap_device *wd; + + if (down_interruptible(&loader_mutex)) { + WARNING("couldn't obtain loader_mutex"); + return NULL; + } + wd = NULL; + nt_list_for_each(cur, &wrap_devices) { + wd = container_of(cur, struct wrap_device, list); + if (bus == WRAP_PCI_BUS && + wrap_is_pci_bus(wd->dev_bus) && wd->pci.pdev == dev) + break; + else if (bus == WRAP_USB_BUS && + wrap_is_usb_bus(wd->dev_bus) && wd->usb.udev == dev) + break; + else + wd = NULL; + } + up(&loader_mutex); + return wd; +} + +/* called with loader_mutex is down */ +static int wrapper_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct load_driver *load_driver; + struct load_device load_device; + struct load_driver_file load_bin_file; + int ret; + void __user *addr = (void __user *)arg; + + ENTER1("cmd: %u", cmd); + + ret = 0; + switch (cmd) { + case WRAP_IOCTL_LOAD_DEVICE: + if (copy_from_user(&load_device, addr, sizeof(load_device))) { + ret = -EFAULT; + break; + } + TRACE2("%04x, %04x, %04x, %04x", load_device.vendor, + load_device.device, load_device.subvendor, + load_device.subdevice); + if (load_device.vendor) { + struct wrap_device *wd; + wd = kzalloc(sizeof(*wd), GFP_KERNEL); + if (!wd) { + ret = -ENOMEM; + break; + } + InitializeListHead(&wd->settings); + wd->dev_bus = WRAP_BUS(load_device.bus); + wd->vendor = load_device.vendor; + wd->device = load_device.device; + wd->subvendor = load_device.subvendor; + wd->subdevice = load_device.subdevice; + strncpy(wd->conf_file_name, load_device.conf_file_name, + sizeof(wd->conf_file_name)); + wd->conf_file_name[sizeof(wd->conf_file_name)-1] = 0; + strncpy(wd->driver_name, load_device.driver_name, + sizeof(wd->driver_name)); + wd->driver_name[sizeof(wd->driver_name)-1] = 0; + InsertHeadList(&wrap_devices, &wd->list); + ret = 0; + } else + ret = -EINVAL; + break; + case WRAP_IOCTL_LOAD_DRIVER: + TRACE1("loading driver at %p", addr); + load_driver = vmalloc(sizeof(*load_driver)); + if (!load_driver) { + ret = -ENOMEM; + break; + } + if (copy_from_user(load_driver, addr, sizeof(*load_driver))) + ret = -EFAULT; + else + ret = load_user_space_driver(load_driver); + vfree(load_driver); + break; + case WRAP_IOCTL_LOAD_BIN_FILE: + if (copy_from_user(&load_bin_file, addr, sizeof(load_bin_file))) + ret = -EFAULT; + else + ret = add_bin_file(&load_bin_file); + break; + default: + ERROR("unknown ioctl %u", cmd); + ret = -EINVAL; + break; + } + complete(&loader_complete); + EXIT1(return ret); +} + +static int wrapper_ioctl_release(struct inode *inode, struct file *file) +{ + ENTER1(""); + return 0; +} + +static struct file_operations wrapper_fops = { + .owner = THIS_MODULE, + .ioctl = wrapper_ioctl, + .release = wrapper_ioctl_release, +}; + +static struct miscdevice wrapper_misc = { + .name = DRIVER_NAME, + .minor = MISC_DYNAMIC_MINOR, + .fops = &wrapper_fops +}; + +int loader_init(void) +{ + int err; + + InitializeListHead(&wrap_drivers); + InitializeListHead(&wrap_devices); + init_MUTEX(&loader_mutex); + init_completion(&loader_complete); + if ((err = misc_register(&wrapper_misc)) < 0 ) { + ERROR("couldn't register module (%d)", err); + unregister_devices(); + EXIT1(return err); + } + register_devices(); + EXIT1(return 0); +} + +void loader_exit(void) +{ + struct nt_list *cur, *next; + + ENTER1(""); + misc_deregister(&wrapper_misc); + unregister_devices(); + if (down_interruptible(&loader_mutex)) + WARNING("couldn't obtain loader_mutex"); + nt_list_for_each_safe(cur, next, &wrap_drivers) { + struct wrap_driver *driver; + driver = container_of(cur, struct wrap_driver, list); + unload_wrap_driver(driver); + } + up(&loader_mutex); + EXIT1(return); +} --- linux-2.6.27.orig/ubuntu/ndiswrapper/loader.h +++ linux-2.6.27/ubuntu/ndiswrapper/loader.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LOADER_H_ +#define _LOADER_H_ + +#include "ndiswrapper.h" + +#ifndef __KERNEL__ +#define __user +#endif + +struct load_driver_file { + char driver_name[MAX_DRIVER_NAME_LEN]; + char name[MAX_DRIVER_NAME_LEN]; + size_t size; + void __user *data; +}; + +struct load_device_setting { + char name[MAX_SETTING_NAME_LEN]; + char value[MAX_SETTING_VALUE_LEN]; +}; + +struct load_device { + int bus; + int vendor; + int device; + int subvendor; + int subdevice; + char conf_file_name[MAX_DRIVER_NAME_LEN]; + char driver_name[MAX_DRIVER_NAME_LEN]; +}; + +struct load_devices { + int count; + struct load_device *devices; +}; + +struct load_driver { + char name[MAX_DRIVER_NAME_LEN]; + char conf_file_name[MAX_DRIVER_NAME_LEN]; + unsigned int num_sys_files; + struct load_driver_file sys_files[MAX_DRIVER_PE_IMAGES]; + unsigned int num_settings; + struct load_device_setting settings[MAX_DEVICE_SETTINGS]; + unsigned int num_bin_files; + struct load_driver_file bin_files[MAX_DRIVER_BIN_FILES]; +}; + +#define WRAP_IOCTL_LOAD_DEVICE _IOW(('N' + 'd' + 'i' + 'S'), 0, \ + struct load_device *) +#define WRAP_IOCTL_LOAD_DRIVER _IOW(('N' + 'd' + 'i' + 'S'), 1, \ + struct load_driver *) +#define WRAP_IOCTL_LOAD_BIN_FILE _IOW(('N' + 'd' + 'i' + 'S'), 2, \ + struct load_driver_file *) + +#define WRAP_CMD_LOAD_DEVICE "load_device" +#define WRAP_CMD_LOAD_DRIVER "load_driver" +#define WRAP_CMD_LOAD_BIN_FILE "load_bin_file" + +int loader_init(void); +void loader_exit(void); + +#ifdef __KERNEL__ +struct wrap_device *load_wrap_device(struct load_device *load_device); +struct wrap_driver *load_wrap_driver(struct wrap_device *device); +struct wrap_bin_file *get_bin_file(char *bin_file_name); +void free_bin_file(struct wrap_bin_file *bin_file); +void unload_wrap_driver(struct wrap_driver *driver); +void unload_wrap_device(struct wrap_device *wd); +struct wrap_device *get_wrap_device(void *dev, int bus_type); + +extern struct semaphore loader_mutex; +#endif + +#endif /* LOADER_H */ + --- linux-2.6.27.orig/ubuntu/ndiswrapper/iw_ndis.h +++ linux-2.6.27/ubuntu/ndiswrapper/iw_ndis.h @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _IW_NDIS_H_ +#define _IW_NDIS_H_ + +#include "ndis.h" + +#define WL_NOISE -96 /* typical noise level in dBm */ +#define WL_SIGMAX -32 /* typical maximum signal level in dBm */ + +struct ndis_encr_key { + ULONG struct_size; + ULONG index; + ULONG length; + UCHAR key[NDIS_ENCODING_TOKEN_MAX]; +}; + +struct ndis_add_key { + ULONG struct_size; + ndis_key_index index; + ULONG length; + mac_address bssid; + UCHAR pad[6]; + ndis_key_rsc rsc; + UCHAR key[NDIS_ENCODING_TOKEN_MAX]; +}; + +struct ndis_remove_key { + ULONG struct_size; + ndis_key_index index; + mac_address bssid; +}; + +struct ndis_fixed_ies { + UCHAR time_stamp[8]; + USHORT beacon_interval; + USHORT capa; +}; + +struct ndis_variable_ies { + ULONG elem_id; + UCHAR length; + UCHAR data[1]; +}; + +enum ndis_reload_defaults { Ndis802_11ReloadWEPKeys }; + +struct ndis_assoc_info { + ULONG length; + USHORT req_ies; + struct req_ie { + USHORT capa; + USHORT listen_interval; + mac_address cur_ap_address; + } req_ie; + ULONG req_ie_length; + ULONG offset_req_ies; + USHORT resp_ies; + struct resp_ie { + USHORT capa; + USHORT status_code; + USHORT assoc_id; + } resp_ie; + ULONG resp_ie_length; + ULONG offset_resp_ies; +}; + +struct ndis_configuration_fh { + ULONG length; + ULONG hop_pattern; + ULONG hop_set; + ULONG dwell_time; +}; + +struct ndis_configuration { + ULONG length; + ULONG beacon_period; + ULONG atim_window; + ULONG ds_config; + struct ndis_configuration_fh fh_config; +}; + +struct ndis_wlan_bssid { + ULONG length; + mac_address mac; + UCHAR reserved[2]; + struct ndis_essid ssid; + ULONG privacy; + ndis_rssi rssi; + UINT net_type; + struct ndis_configuration config; + UINT mode; + ndis_rates rates; +}; + +struct ndis_wlan_bssid_ex { + ULONG length; + mac_address mac; + UCHAR reserved[2]; + struct ndis_essid ssid; + ULONG privacy; + ndis_rssi rssi; + UINT net_type; + struct ndis_configuration config; + UINT mode; + ndis_rates_ex rates_ex; + ULONG ie_length; + UCHAR ies[1]; +}; + +/* we use bssid_list as bssid_list_ex also */ +struct ndis_bssid_list { + ULONG num_items; + struct ndis_wlan_bssid bssid[1]; +}; + +enum ndis_priv_filter { + Ndis802_11PrivFilterAcceptAll, Ndis802_11PrivFilter8021xWEP +}; + +enum network_type { + Ndis802_11FH, Ndis802_11DS, Ndis802_11OFDM5, Ndis802_11OFDM24, + /* MSDN site uses Ndis802_11Automode, which is not mentioned + * in DDK, so add one and assign it to + * Ndis802_11NetworkTypeMax */ + Ndis802_11Automode, Ndis802_11NetworkTypeMax = Ndis802_11Automode +}; + +struct network_type_list { + ULONG num; + enum network_type types[1]; +}; + +enum ndis_power { + NDIS_POWER_OFF = 0, NDIS_POWER_MAX, NDIS_POWER_MIN, +}; + +struct ndis_auth_req { + ULONG length; + mac_address bssid; + ULONG flags; +}; + +struct ndis_bssid_info { + mac_address bssid; + ndis_pmkid_vavlue pmkid; +}; + +struct ndis_pmkid { + ULONG length; + ULONG bssid_info_count; + struct ndis_bssid_info bssid_info[1]; +}; + +int add_wep_key(struct ndis_device *wnd, char *key, int key_len, + int index); +int set_essid(struct ndis_device *wnd, const char *ssid, int ssid_len); +int set_infra_mode(struct ndis_device *wnd, + enum ndis_infrastructure_mode mode); +int get_ap_address(struct ndis_device *wnd, mac_address mac); +int set_ndis_auth_mode(struct ndis_device *wnd, ULONG auth_mode); +int set_iw_auth_mode(struct ndis_device *wnd, int wpa_version, + int auth_80211_alg); +int set_auth_mode(struct ndis_device *wnd); +int set_ndis_encr_mode(struct ndis_device *wnd, int cipher_pairwise, + int cipher_groupwise); +int get_ndis_encr_mode(struct ndis_device *wnd); +int set_encr_mode(struct ndis_device *wnd); +int set_iw_encr_mode(struct ndis_device *wnd, int cipher_pairwise, + int cipher_groupwise); +int get_ndis_auth_mode(struct ndis_device *wnd); +int set_priv_filter(struct ndis_device *wnd); +int set_scan(struct ndis_device *wnd); +NDIS_STATUS disassociate(struct ndis_device *wnd, int reset_ssid); +void set_default_iw_params(struct ndis_device *wnd); +extern const struct iw_handler_def ndis_handler_def; + +#define PRIV_RESET SIOCIWFIRSTPRIV+16 +#define PRIV_POWER_PROFILE SIOCIWFIRSTPRIV+17 +#define PRIV_NETWORK_TYPE SIOCIWFIRSTPRIV+18 +#define PRIV_DEAUTHENTICATE SIOCIWFIRSTPRIV+19 +#define PRIV_MEDIA_STREAM_MODE SIOCIWFIRSTPRIV+20 +#define PRIV_RELOAD_DEFAULTS SIOCIWFIRSTPRIV+23 + +#define RSN_INFO_ELEM 0x30 + +/* these have to match what is in wpa_supplicant */ + +typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg; +typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP, + CIPHER_WEP104 } wpa_cipher; +typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, + KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE } wpa_key_mgmt; + +#endif // IW_NDIS_H --- linux-2.6.27.orig/ubuntu/ndiswrapper/iw_ndis.c +++ linux-2.6.27/ubuntu/ndiswrapper/iw_ndis.c @@ -0,0 +1,1956 @@ + /* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "iw_ndis.h" +#include "wrapndis.h" + +static int freq_chan[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; + +static const char *network_names[] = {"IEEE 802.11FH", "IEEE 802.11b", + "IEEE 802.11a", "IEEE 802.11g", "Auto"}; + +int set_essid(struct ndis_device *wnd, const char *ssid, int ssid_len) +{ + NDIS_STATUS res; + struct ndis_essid req; + + if (ssid_len > NDIS_ESSID_MAX_SIZE) + return -EINVAL; + + memset(&req, 0, sizeof(req)); + req.length = ssid_len; + if (ssid_len) + memcpy(&req.essid, ssid, ssid_len); + + res = mp_set(wnd, OID_802_11_SSID, &req, sizeof(req)); + if (res) { + WARNING("setting essid failed (%08X)", res); + EXIT2(return -EINVAL); + } + memcpy(&wnd->essid, &req, sizeof(req)); + EXIT2(return 0); +} + +static int set_assoc_params(struct ndis_device *wnd) +{ + TRACE2("wpa_version=0x%x auth_alg=0x%x key_mgmt=0x%x " + "cipher_pairwise=0x%x cipher_group=0x%x", + wnd->iw_auth_wpa_version, wnd->iw_auth_80211_alg, + wnd->iw_auth_key_mgmt, wnd->iw_auth_cipher_pairwise, + wnd->iw_auth_cipher_group); + set_auth_mode(wnd); + set_priv_filter(wnd); + set_encr_mode(wnd); + return 0; +} + +static int iw_set_essid(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + char ssid[NDIS_ESSID_MAX_SIZE]; + int length; + + ENTER2(""); + memset(ssid, 0, sizeof(ssid)); + /* there is no way to turn off essid other than to set to + * random bytes; instead, we use off to mean any */ + if (wrqu->essid.flags) { + /* wireless-tools prior to version 20 add extra 1, and + * later than 20 don't! Deal with that mess */ + length = wrqu->essid.length - 1; + if (length > 0) + length--; + while (length < wrqu->essid.length && extra[length]) + length++; + TRACE2("%d", length); + if (length <= 0 || length > NDIS_ESSID_MAX_SIZE) + EXIT2(return -EINVAL); + } else + length = 0; + + set_assoc_params(wnd); + + memcpy(ssid, extra, length); + if (set_essid(wnd, ssid, length)) + EXIT2(return -EINVAL); + + EXIT2(return 0); +} + +static int iw_get_essid(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + NDIS_STATUS res; + struct ndis_essid req; + + ENTER2(""); + memset(&req, 0, sizeof(req)); + res = mp_query(wnd, OID_802_11_SSID, &req, sizeof(req)); + if (res) { + WARNING("getting essid failed (%08X)", res); + EXIT2(return -EOPNOTSUPP); + } + memcpy(extra, req.essid, req.length); + if (req.length > 0) + wrqu->essid.flags = 1; + else + wrqu->essid.flags = 0; + wrqu->essid.length = req.length; + EXIT2(return 0); +} + +int set_infra_mode(struct ndis_device *wnd, + enum ndis_infrastructure_mode mode) +{ + NDIS_STATUS res; + unsigned int i; + + ENTER2("%d", mode); + res = mp_query_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, + &wnd->infrastructure_mode); + if (res != NDIS_STATUS_SUCCESS) { + WARNING("getting operating mode to failed (%08X)", res); + EXIT2(return -EINVAL); + } + if (wnd->infrastructure_mode == mode) + EXIT2(return 0); + res = mp_set_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, mode); + if (res) { + WARNING("setting operating mode to %d failed (%08X)", + mode, res); + EXIT2(return -EINVAL); + } + /* NDIS drivers clear keys when infrastructure mode is + * changed. But Linux tools assume otherwise. So set the + * keys */ + if (wnd->iw_auth_key_mgmt == 0 || + wnd->iw_auth_key_mgmt == IW_AUTH_KEY_MGMT_802_1X) { + for (i = 0; i < MAX_ENCR_KEYS; i++) { + if (wnd->encr_info.keys[i].length > 0) + add_wep_key(wnd, wnd->encr_info.keys[i].key, + wnd->encr_info.keys[i].length, i); + } + } + wnd->infrastructure_mode = mode; + EXIT2(return 0); +} + +static int iw_set_infra_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + enum ndis_infrastructure_mode ndis_mode; + + ENTER2("%d", wrqu->mode); + switch (wrqu->mode) { + case IW_MODE_ADHOC: + ndis_mode = Ndis802_11IBSS; + break; + case IW_MODE_INFRA: + ndis_mode = Ndis802_11Infrastructure; + break; + case IW_MODE_AUTO: + ndis_mode = Ndis802_11AutoUnknown; + break; + default: + EXIT2(return -EINVAL); + } + + if (set_infra_mode(wnd, ndis_mode)) + EXIT2(return -EINVAL); + + EXIT2(return 0); +} + +static int iw_get_infra_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + int ndis_mode, iw_mode; + NDIS_STATUS res; + + ENTER2(""); + res = mp_query_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, &ndis_mode); + if (res) { + WARNING("getting operating mode failed (%08X)", res); + EXIT2(return -EOPNOTSUPP); + } + + switch(ndis_mode) { + case Ndis802_11IBSS: + iw_mode = IW_MODE_ADHOC; + break; + case Ndis802_11Infrastructure: + iw_mode = IW_MODE_INFRA; + break; + case Ndis802_11AutoUnknown: + iw_mode = IW_MODE_AUTO; + break; + default: + ERROR("invalid operating mode (%u)", ndis_mode); + EXIT2(return -EINVAL); + } + wrqu->mode = iw_mode; + EXIT2(return 0); +} + +static const char *network_type_to_name(int net_type) +{ + if (net_type >= 0 && + net_type < (sizeof(network_names)/sizeof(network_names[0]))) + return network_names[net_type]; + else + return network_names[sizeof(network_names) / + sizeof(network_names[0]) - 1]; +} + +static int iw_get_network_type(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + unsigned int network_type; + NDIS_STATUS res; + + ENTER2(""); + res = mp_query_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE, + &network_type); + if (res) { + WARNING("getting network type failed: %08X", res); + network_type = -1; + } + strncpy(wrqu->name, network_type_to_name(network_type), + sizeof(wrqu->name) - 1); + wrqu->name[sizeof(wrqu->name)-1] = 0; + return 0; +} + +static int iw_get_freq(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + NDIS_STATUS res; + struct ndis_configuration req; + + ENTER2(""); + memset(&req, 0, sizeof(req)); + res = mp_query(wnd, OID_802_11_CONFIGURATION, &req, sizeof(req)); + if (res) { + WARNING("getting configuration failed (%08X)", res); + EXIT2(return -EOPNOTSUPP); + } + + memset(&(wrqu->freq), 0, sizeof(struct iw_freq)); + + /* see comment in wireless.h above the "struct iw_freq" + definition for an explanation of this if + NOTE: 1000000 is due to the kHz + */ + if (req.ds_config > 1000000) { + wrqu->freq.m = req.ds_config / 10; + wrqu->freq.e = 1; + } + else + wrqu->freq.m = req.ds_config; + + /* convert from kHz to Hz */ + wrqu->freq.e += 3; + + return 0; +} + +static int iw_set_freq(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + NDIS_STATUS res; + struct ndis_configuration req; + + ENTER2(""); + /* this OID is valid only when not associated */ + if (netif_carrier_ok(wnd->net_dev)) + EXIT2(return 0); + memset(&req, 0, sizeof(req)); + res = mp_query(wnd, OID_802_11_CONFIGURATION, &req, sizeof(req)); + if (res) { + WARNING("getting configuration failed (%08X)", res); + EXIT2(return 0); + } + + if (wrqu->freq.m < 1000 && wrqu->freq.e == 0) { + if (wrqu->freq.m >= 1 && + wrqu->freq.m <= (sizeof(freq_chan) / sizeof(freq_chan[0]))) + req.ds_config = freq_chan[wrqu->freq.m - 1] * 1000; + else + return -EINVAL; + } else { + int i; + req.ds_config = wrqu->freq.m; + for (i = wrqu->freq.e; i > 0; i--) + req.ds_config *= 10; + req.ds_config /= 1000; + } + res = mp_set(wnd, OID_802_11_CONFIGURATION, &req, sizeof(req)); + if (res) + WARNING("setting configuration failed (%08X)", res); + return 0; +} + +static int iw_get_tx_power(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + ndis_tx_power_level ndis_power; + NDIS_STATUS res; + + ENTER2(""); + res = mp_query(wnd, OID_802_11_TX_POWER_LEVEL, + &ndis_power, sizeof(ndis_power)); + if (res) + return -EOPNOTSUPP; + wrqu->txpower.flags = IW_TXPOW_MWATT; + wrqu->txpower.disabled = 0; + wrqu->txpower.fixed = 0; + wrqu->txpower.value = ndis_power; + return 0; +} + +static int iw_set_tx_power(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + ndis_tx_power_level ndis_power; + NDIS_STATUS res; + + ENTER2(""); + if (wrqu->txpower.disabled) + ndis_power = 0; + else { + if (wrqu->txpower.flags == IW_TXPOW_MWATT) + ndis_power = wrqu->txpower.value; + else { // wrqu->txpower.flags == IW_TXPOW_DBM + if (wrqu->txpower.value > 20) + ndis_power = 128; + else if (wrqu->txpower.value < -43) + ndis_power = 127; + else { + signed char tmp; + tmp = wrqu->txpower.value; + tmp = -12 - tmp; + tmp <<= 2; + ndis_power = (unsigned char)tmp; + } + } + } + TRACE2("%d", ndis_power); + res = mp_set(wnd, OID_802_11_TX_POWER_LEVEL, + &ndis_power, sizeof(ndis_power)); + if (res) + EXIT2(return -EOPNOTSUPP); + if (ndis_power == 0) + res = disassociate(wnd, 0); + EXIT2(return 0); +} + +static int iw_get_bitrate(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + ULONG ndis_rate; + int res; + + ENTER2(""); + res = mp_query(wnd, OID_GEN_LINK_SPEED, &ndis_rate, sizeof(ndis_rate)); + if (res) { + WARNING("getting bitrate failed (%08X)", res); + ndis_rate = 0; + } + + wrqu->bitrate.value = ndis_rate * 100; + return 0; +} + +static int iw_set_bitrate(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + int i, n; + NDIS_STATUS res; + ndis_rates_ex rates; + + ENTER2(""); + if (wrqu->bitrate.fixed == 0) + EXIT2(return 0); + + res = mp_query_info(wnd, OID_802_11_SUPPORTED_RATES, &rates, + sizeof(rates), &n, NULL); + if (res) { + WARNING("getting bit rate failed (%08X)", res); + EXIT2(return 0); + } + for (i = 0; i < n; i++) { + if (rates[i] & 0x80) + continue; + if ((rates[i] & 0x7f) * 500000 > wrqu->bitrate.value) { + TRACE2("setting rate %d to 0", + (rates[i] & 0x7f) * 500000); + rates[i] = 0; + } + } + + res = mp_set(wnd, OID_802_11_DESIRED_RATES, &rates, n); + if (res) { + WARNING("setting bit rate failed (%08X)", res); + EXIT2(return 0); + } + + return 0; +} + +static int iw_set_dummy(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* Do nothing. Used for ioctls that are not implemented. */ + return 0; +} + +static int iw_get_rts_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + ndis_rts_threshold threshold; + NDIS_STATUS res; + + ENTER2(""); + res = mp_query(wnd, OID_802_11_RTS_THRESHOLD, + &threshold, sizeof(threshold)); + if (res) + return -EOPNOTSUPP; + + wrqu->rts.value = threshold; + return 0; +} + +static int iw_set_rts_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + ndis_rts_threshold threshold; + NDIS_STATUS res; + + ENTER2(""); + threshold = wrqu->rts.value; + res = mp_set(wnd, OID_802_11_RTS_THRESHOLD, + &threshold, sizeof(threshold)); + if (res == NDIS_STATUS_INVALID_DATA) + return -EINVAL; + if (res) + return -EOPNOTSUPP; + + return 0; +} + +static int iw_get_frag_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + ndis_fragmentation_threshold frag_threshold; + NDIS_STATUS res; + + ENTER2(""); + res = mp_query(wnd, OID_802_11_FRAGMENTATION_THRESHOLD, + &frag_threshold, sizeof(frag_threshold)); + if (res) + return -ENOTSUPP; + + wrqu->frag.value = frag_threshold; + return 0; +} + +static int iw_set_frag_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + ndis_rts_threshold threshold; + NDIS_STATUS res; + + ENTER2(""); + threshold = wrqu->frag.value; + res = mp_set(wnd, OID_802_11_FRAGMENTATION_THRESHOLD, + &threshold, sizeof(threshold)); + if (res == NDIS_STATUS_INVALID_DATA) + return -EINVAL; + if (res) + return -EOPNOTSUPP; + return 0; +} + +int get_ap_address(struct ndis_device *wnd, mac_address ap_addr) +{ + NDIS_STATUS res; + + res = mp_query(wnd, OID_802_11_BSSID, ap_addr, ETH_ALEN); + TRACE2(MACSTRSEP, MAC2STR(ap_addr)); + if (res) { + TRACE2("res: %08X", res); + memset(ap_addr, 0x0, ETH_ALEN); + EXIT2(return -EOPNOTSUPP); + } + EXIT2(return 0); +} + +static int iw_get_ap_address(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + mac_address ap_addr; + + ENTER2(""); + get_ap_address(wnd, ap_addr); + memcpy(wrqu->ap_addr.sa_data, ap_addr, ETH_ALEN); + wrqu->ap_addr.sa_family = ARPHRD_ETHER; + EXIT2(return 0); +} + +static int iw_set_ap_address(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + NDIS_STATUS res; + mac_address ap_addr; + + ENTER2(""); + memcpy(ap_addr, wrqu->ap_addr.sa_data, ETH_ALEN); + TRACE2(MACSTRSEP, MAC2STR(ap_addr)); + res = mp_set(wnd, OID_802_11_BSSID, ap_addr, ETH_ALEN); + /* user apps may set ap's mac address, which is not required; + * they may fail to work if this function fails, so return + * success */ + if (res) + WARNING("setting AP mac address failed (%08X)", res); + + EXIT2(return 0); +} + +int set_iw_auth_mode(struct ndis_device *wnd, int wpa_version, + int auth_80211_alg) +{ + NDIS_STATUS res; + ULONG auth_mode; + + ENTER2("%d, %d", wpa_version, auth_80211_alg); + if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) { + if (wnd->iw_auth_key_mgmt & IW_AUTH_KEY_MGMT_802_1X) + auth_mode = Ndis802_11AuthModeWPA2; + else + auth_mode = Ndis802_11AuthModeWPA2PSK; + } else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) { + if (wnd->iw_auth_key_mgmt & IW_AUTH_KEY_MGMT_802_1X) + auth_mode = Ndis802_11AuthModeWPA; + else if (wnd->iw_auth_key_mgmt & IW_AUTH_KEY_MGMT_PSK) + auth_mode = Ndis802_11AuthModeWPAPSK; + else + auth_mode = Ndis802_11AuthModeWPANone; + } else if (auth_80211_alg & IW_AUTH_ALG_SHARED_KEY) { + if (auth_80211_alg & IW_AUTH_ALG_OPEN_SYSTEM) + auth_mode = Ndis802_11AuthModeAutoSwitch; + else + auth_mode = Ndis802_11AuthModeShared; + } else + auth_mode = Ndis802_11AuthModeOpen; + + res = mp_set_int(wnd, OID_802_11_AUTHENTICATION_MODE, auth_mode); + if (res) { + WARNING("setting auth mode to %u failed (%08X)", + auth_mode, res); + if (res == NDIS_STATUS_INVALID_DATA) + EXIT2(return -EINVAL); + return -EOPNOTSUPP; + } + wnd->iw_auth_wpa_version = wpa_version; + wnd->iw_auth_80211_alg = auth_80211_alg; + EXIT2(return 0); +} + +int set_ndis_auth_mode(struct ndis_device *wnd, ULONG auth_mode) +{ + NDIS_STATUS res; + + ENTER2("%d", auth_mode); + res = mp_set_int(wnd, OID_802_11_AUTHENTICATION_MODE, auth_mode); + if (res) { + WARNING("setting auth mode to %u failed (%08X)", + auth_mode, res); + if (res == NDIS_STATUS_INVALID_DATA) + EXIT2(return -EINVAL); + return -EOPNOTSUPP; + } + switch (auth_mode) { + case Ndis802_11AuthModeWPA: + wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA; + wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_802_1X; + break; + case Ndis802_11AuthModeWPAPSK: + wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA; + wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_PSK; + case Ndis802_11AuthModeWPANone: + wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED; + wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_PSK; + break; + case Ndis802_11AuthModeWPA2: + wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA2; + wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_802_1X; + break; + case Ndis802_11AuthModeWPA2PSK: + wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA2; + wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_PSK; + break; + case Ndis802_11AuthModeOpen: + wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED; + wnd->iw_auth_80211_alg = IW_AUTH_ALG_OPEN_SYSTEM; + break; + case Ndis802_11AuthModeShared: + wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED; + wnd->iw_auth_80211_alg = IW_AUTH_ALG_SHARED_KEY; + break; + case Ndis802_11AuthModeAutoSwitch: + wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED; + wnd->iw_auth_80211_alg = IW_AUTH_ALG_SHARED_KEY; + wnd->iw_auth_80211_alg |= IW_AUTH_ALG_OPEN_SYSTEM; + break; + default: + WARNING("invalid authentication algorithm: %d", auth_mode); + break; + } + EXIT2(return 0); +} + +int set_auth_mode(struct ndis_device *wnd) +{ + return set_iw_auth_mode(wnd, wnd->iw_auth_wpa_version, + wnd->iw_auth_80211_alg); +} + +int get_ndis_auth_mode(struct ndis_device *wnd) +{ + ULONG mode; + NDIS_STATUS res; + + res = mp_query_int(wnd, OID_802_11_AUTHENTICATION_MODE, &mode); + if (res) { + WARNING("getting authentication mode failed (%08X)", res); + EXIT2(return -EOPNOTSUPP); + } + TRACE2("%d", mode); + return mode; +} + +int set_iw_encr_mode(struct ndis_device *wnd, int cipher_pairwise, + int cipher_groupwise) +{ + NDIS_STATUS res; + ULONG ndis_mode; + + ENTER2("%d, %d", cipher_pairwise, cipher_groupwise); + if (cipher_pairwise & IW_AUTH_CIPHER_CCMP) + ndis_mode = Ndis802_11Encryption3Enabled; + else if (cipher_pairwise & IW_AUTH_CIPHER_TKIP) + ndis_mode = Ndis802_11Encryption2Enabled; + else if (cipher_pairwise & + (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) + ndis_mode = Ndis802_11Encryption1Enabled; + else if (cipher_groupwise & IW_AUTH_CIPHER_CCMP) + ndis_mode = Ndis802_11Encryption3Enabled; + else if (cipher_groupwise & IW_AUTH_CIPHER_TKIP) + ndis_mode = Ndis802_11Encryption2Enabled; + else + ndis_mode = Ndis802_11EncryptionDisabled; + + res = mp_set_int(wnd, OID_802_11_ENCRYPTION_STATUS, ndis_mode); + if (res) { + WARNING("setting encryption mode to %u failed (%08X)", + ndis_mode, res); + if (res == NDIS_STATUS_INVALID_DATA) + EXIT2(return -EINVAL); + return -EOPNOTSUPP; + } + wnd->iw_auth_cipher_pairwise = cipher_pairwise; + wnd->iw_auth_cipher_group = cipher_groupwise; + EXIT2(return 0); +} + +int set_encr_mode(struct ndis_device *wnd) +{ + return set_iw_encr_mode(wnd, wnd->iw_auth_cipher_pairwise, + wnd->iw_auth_cipher_group); +} + +int get_ndis_encr_mode(struct ndis_device *wnd) +{ + ULONG mode; + NDIS_STATUS res; + + ENTER2(""); + res = mp_query_int(wnd, OID_802_11_ENCRYPTION_STATUS, &mode); + if (res) { + WARNING("getting encryption status failed (%08X)", res); + EXIT2(return -EOPNOTSUPP); + } else + EXIT2(return mode); +} + +static int iw_get_encr(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + int index, mode; + struct encr_info *encr_info = &wnd->encr_info; + + ENTER2("wnd = %p", wnd); + wrqu->data.length = 0; + extra[0] = 0; + + index = (wrqu->encoding.flags & IW_ENCODE_INDEX); + TRACE2("index = %u", index); + if (index > 0) + index--; + else + index = encr_info->tx_key_index; + + if (index < 0 || index >= MAX_ENCR_KEYS) { + WARNING("encryption index out of range (%u)", index); + EXIT2(return -EINVAL); + } + + if (index != encr_info->tx_key_index) { + if (encr_info->keys[index].length > 0) { + wrqu->data.flags |= IW_ENCODE_ENABLED; + wrqu->data.length = encr_info->keys[index].length; + memcpy(extra, encr_info->keys[index].key, + encr_info->keys[index].length); + } + else + wrqu->data.flags |= IW_ENCODE_DISABLED; + + EXIT2(return 0); + } + + /* transmit key */ + mode = get_ndis_encr_mode(wnd); + if (mode < 0) + EXIT2(return -EOPNOTSUPP); + + if (mode == Ndis802_11EncryptionDisabled || + mode == Ndis802_11EncryptionNotSupported) + wrqu->data.flags |= IW_ENCODE_DISABLED; + else { + if (mode == Ndis802_11Encryption1KeyAbsent || + mode == Ndis802_11Encryption2KeyAbsent || + mode == Ndis802_11Encryption3KeyAbsent) + wrqu->data.flags |= IW_ENCODE_NOKEY; + else { + wrqu->data.flags |= IW_ENCODE_ENABLED; + wrqu->encoding.flags |= index+1; + wrqu->data.length = encr_info->keys[index].length; + memcpy(extra, encr_info->keys[index].key, + encr_info->keys[index].length); + } + } + mode = get_ndis_auth_mode(wnd); + if (mode < 0) + EXIT2(return -EOPNOTSUPP); + + if (mode == Ndis802_11AuthModeOpen) + wrqu->data.flags |= IW_ENCODE_OPEN; + else if (mode == Ndis802_11AuthModeAutoSwitch) + wrqu->data.flags |= IW_ENCODE_RESTRICTED; + else // Ndis802_11AuthModeAutoSwitch, Ndis802_11AuthModeWPA etc. + wrqu->data.flags |= IW_ENCODE_RESTRICTED; + + EXIT2(return 0); +} + +/* index must be 0 - N, as per NDIS */ +int add_wep_key(struct ndis_device *wnd, char *key, int key_len, + int index) +{ + struct ndis_encr_key ndis_key; + NDIS_STATUS res; + + ENTER2("key index: %d, length: %d", index, key_len); + if (key_len <= 0 || key_len > NDIS_ENCODING_TOKEN_MAX) { + WARNING("invalid key length (%d)", key_len); + EXIT2(return -EINVAL); + } + if (index < 0 || index >= MAX_ENCR_KEYS) { + WARNING("invalid key index (%d)", index); + EXIT2(return -EINVAL); + } + ndis_key.struct_size = sizeof(ndis_key); + ndis_key.length = key_len; + memcpy(&ndis_key.key, key, key_len); + ndis_key.index = index; + + if (index == wnd->encr_info.tx_key_index) { + ndis_key.index |= (1 << 31); + res = set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104, + IW_AUTH_CIPHER_NONE); + if (res) + WARNING("encryption couldn't be enabled (%08X)", res); + } + TRACE2("key %d: " MACSTRSEP, index, MAC2STR(key)); + res = mp_set(wnd, OID_802_11_ADD_WEP, &ndis_key, sizeof(ndis_key)); + if (res) { + WARNING("adding encryption key %d failed (%08X)", + index+1, res); + EXIT2(return -EINVAL); + } + + /* Atheros driver messes up ndis_key during ADD_WEP, so + * don't rely on that; instead use info in key and key_len */ + wnd->encr_info.keys[index].length = key_len; + memcpy(&wnd->encr_info.keys[index].key, key, key_len); + + EXIT2(return 0); +} + +/* remove_key is for both wep and wpa */ +static int remove_key(struct ndis_device *wnd, int index, + mac_address bssid) +{ + NDIS_STATUS res; + if (wnd->encr_info.keys[index].length == 0) + EXIT2(return 0); + wnd->encr_info.keys[index].length = 0; + memset(&wnd->encr_info.keys[index].key, 0, + sizeof(wnd->encr_info.keys[index].length)); + if (wnd->iw_auth_cipher_pairwise == IW_AUTH_CIPHER_TKIP || + wnd->iw_auth_cipher_pairwise == IW_AUTH_CIPHER_CCMP || + wnd->iw_auth_cipher_group == IW_AUTH_CIPHER_TKIP || + wnd->iw_auth_cipher_group == IW_AUTH_CIPHER_CCMP) { + struct ndis_remove_key remove_key; + remove_key.struct_size = sizeof(remove_key); + remove_key.index = index; + if (bssid) { + /* pairwise key */ + if (memcmp(bssid, "\xff\xff\xff\xff\xff\xff", + ETH_ALEN) != 0) + remove_key.index |= (1 << 30); + memcpy(remove_key.bssid, bssid, + sizeof(remove_key.bssid)); + } else + memset(remove_key.bssid, 0xff, + sizeof(remove_key.bssid)); + if (mp_set(wnd, OID_802_11_REMOVE_KEY, + &remove_key, sizeof(remove_key))) + EXIT2(return -EINVAL); + } else { + ndis_key_index keyindex = index; + res = mp_set_int(wnd, OID_802_11_REMOVE_WEP, keyindex); + if (res) { + WARNING("removing encryption key %d failed (%08X)", + keyindex, res); + EXIT2(return -EINVAL); + } + } + /* if it is transmit key, disable encryption */ + if (index == wnd->encr_info.tx_key_index) { + res = set_iw_encr_mode(wnd, IW_AUTH_CIPHER_NONE, + IW_AUTH_CIPHER_NONE); + if (res) + WARNING("changing encr status failed (%08X)", res); + } + TRACE2("key %d removed", index); + EXIT2(return 0); +} + +static int iw_set_wep(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + NDIS_STATUS res; + unsigned int index, key_len; + struct encr_info *encr_info = &wnd->encr_info; + unsigned char *key; + + ENTER2(""); + index = (wrqu->encoding.flags & IW_ENCODE_INDEX); + TRACE2("index = %u", index); + + /* iwconfig gives index as 1 - N */ + if (index > 0) + index--; + else + index = encr_info->tx_key_index; + + if (index < 0 || index >= MAX_ENCR_KEYS) { + WARNING("encryption index out of range (%u)", index); + EXIT2(return -EINVAL); + } + + /* remove key if disabled */ + if (wrqu->data.flags & IW_ENCODE_DISABLED) { + if (remove_key(wnd, index, NULL)) + EXIT2(return -EINVAL); + else + EXIT2(return 0); + } + + /* global encryption state (for all keys) */ + if (wrqu->data.flags & IW_ENCODE_OPEN) + res = set_ndis_auth_mode(wnd, Ndis802_11AuthModeOpen); + else // if (wrqu->data.flags & IW_ENCODE_RESTRICTED) + res = set_ndis_auth_mode(wnd, Ndis802_11AuthModeShared); + if (res) { + WARNING("setting authentication mode failed (%08X)", res); + EXIT2(return -EINVAL); + } + + TRACE2("key length: %d", wrqu->data.length); + + if (wrqu->data.length > 0) { + key_len = wrqu->data.length; + key = extra; + } else { // must be set as tx key + if (encr_info->keys[index].length == 0) { + WARNING("key %d is not set", index+1); + EXIT2(return -EINVAL); + } + key_len = encr_info->keys[index].length; + key = encr_info->keys[index].key; + encr_info->tx_key_index = index; + } + + if (add_wep_key(wnd, key, key_len, index)) + EXIT2(return -EINVAL); + + if (index == encr_info->tx_key_index) { + /* if transmit key is at index other than 0, some + * drivers, at least Atheros and TI, want another + * (global) non-transmit key to be set; don't know why */ + if (index != 0) { + int i; + for (i = 0; i < MAX_ENCR_KEYS; i++) + if (i != index && + encr_info->keys[i].length != 0) + break; + if (i == MAX_ENCR_KEYS) { + if (index == 0) + i = index + 1; + else + i = index - 1; + if (add_wep_key(wnd, key, key_len, i)) + WARNING("couldn't add broadcast key" + " at %d", i); + } + } + /* ndis drivers want essid to be set after setting encr */ + set_essid(wnd, wnd->essid.essid, wnd->essid.length); + } + EXIT2(return 0); +} + +static int iw_set_nick(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + + if (wrqu->data.length >= IW_ESSID_MAX_SIZE || wrqu->data.length <= 0) + return -EINVAL; + memcpy(wnd->nick, extra, wrqu->data.length); + wnd->nick[wrqu->data.length] = 0; + return 0; +} + +static int iw_get_nick(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + + wrqu->data.length = strlen(wnd->nick); + memcpy(extra, wnd->nick, wrqu->data.length); + return 0; +} + +static char *ndis_translate_scan(struct net_device *dev, char *event, + char *end_buf, void *item, + struct iw_request_info *info) +{ + struct iw_event iwe; + char *current_val; + int i, nrates; + unsigned char buf[MAX_WPA_IE_LEN * 2 + 30]; + struct ndis_wlan_bssid *bssid; + struct ndis_wlan_bssid_ex *bssid_ex; + + ENTER2("%p, %p", event, item); + bssid = item; + bssid_ex = item; + /* add mac address */ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + iwe.len = IW_EV_ADDR_LEN; + memcpy(iwe.u.ap_addr.sa_data, bssid->mac, ETH_ALEN); + event = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_ADDR_LEN); + + /* add essid */ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWESSID; + iwe.u.data.length = bssid->ssid.length; + if (iwe.u.data.length > IW_ESSID_MAX_SIZE) + iwe.u.data.length = IW_ESSID_MAX_SIZE; + iwe.u.data.flags = 1; + iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; + event = iwe_stream_add_point(info, event, end_buf, &iwe, bssid->ssid.essid); + + /* add protocol name */ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWNAME; + strncpy(iwe.u.name, network_type_to_name(bssid->net_type), IFNAMSIZ); + event = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_CHAR_LEN); + + /* add mode */ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWMODE; + if (bssid->mode == Ndis802_11IBSS) + iwe.u.mode = IW_MODE_ADHOC; + else if (bssid->mode == Ndis802_11Infrastructure) + iwe.u.mode = IW_MODE_INFRA; + else // if (bssid->mode == Ndis802_11AutoUnknown) + iwe.u.mode = IW_MODE_AUTO; + event = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_UINT_LEN); + + /* add freq */ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = bssid->config.ds_config; + if (bssid->config.ds_config > 1000000) { + iwe.u.freq.m = bssid->config.ds_config / 10; + iwe.u.freq.e = 1; + } + else + iwe.u.freq.m = bssid->config.ds_config; + /* convert from kHz to Hz */ + iwe.u.freq.e += 3; + iwe.len = IW_EV_FREQ_LEN; + event = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_FREQ_LEN); + + /* add qual */ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVQUAL; + i = 100 * (bssid->rssi - WL_NOISE) / (WL_SIGMAX - WL_NOISE); + if (i < 0) + i = 0; + else if (i > 100) + i = 100; + iwe.u.qual.level = bssid->rssi; + iwe.u.qual.noise = WL_NOISE; + iwe.u.qual.qual = i; + iwe.len = IW_EV_QUAL_LEN; + event = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_QUAL_LEN); + + /* add key info */ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWENCODE; + if (bssid->privacy == Ndis802_11PrivFilterAcceptAll) + iwe.u.data.flags = IW_ENCODE_DISABLED; + else + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + iwe.u.data.length = 0; + iwe.len = IW_EV_POINT_LEN; + event = iwe_stream_add_point(info, event, end_buf, &iwe, bssid->ssid.essid); + + /* add rate */ + memset(&iwe, 0, sizeof(iwe)); + current_val = event + IW_EV_LCP_LEN; + iwe.cmd = SIOCGIWRATE; + if (bssid->length > sizeof(*bssid)) + nrates = NDIS_MAX_RATES_EX; + else + nrates = NDIS_MAX_RATES; + for (i = 0 ; i < nrates ; i++) { + if (bssid->rates[i] & 0x7f) { + iwe.u.bitrate.value = ((bssid->rates[i] & 0x7f) * + 500000); + current_val = iwe_stream_add_value(info, event, current_val, + end_buf, &iwe, + IW_EV_PARAM_LEN); + } + } + + if ((current_val - event) > IW_EV_LCP_LEN) + event = current_val; + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + sprintf(buf, "bcn_int=%d", bssid->config.beacon_period); + iwe.u.data.length = strlen(buf); + event = iwe_stream_add_point(info, event, end_buf, &iwe, buf); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + sprintf(buf, "atim=%u", bssid->config.atim_window); + iwe.u.data.length = strlen(buf); + event = iwe_stream_add_point(info, event, end_buf, &iwe, buf); + + TRACE2("%d, %u", bssid->length, (unsigned int)sizeof(*bssid)); + if (bssid->length > sizeof(*bssid)) { + unsigned char *iep = (unsigned char *)bssid_ex->ies + + sizeof(struct ndis_fixed_ies); + no_warn_unused unsigned char *end = iep + bssid_ex->ie_length; + + while (iep + 1 < end && iep + 2 + iep[1] <= end) { + unsigned char ielen = 2 + iep[1]; + + if (ielen > SSID_MAX_WPA_IE_LEN) { + iep += ielen; + continue; + } + if ((iep[0] == WLAN_EID_GENERIC && iep[1] >= 4 && + memcmp(iep + 2, "\x00\x50\xf2\x01", 4) == 0) || + iep[0] == RSN_INFO_ELEM) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = ielen; + event = iwe_stream_add_point(info, event, end_buf, + &iwe, iep); + } + iep += ielen; + } + } + TRACE2("event = %p, current_val = %p", event, current_val); + EXIT2(return event); +} + +int set_scan(struct ndis_device *wnd) +{ + NDIS_STATUS res; + + ENTER2(""); + res = mp_set(wnd, OID_802_11_BSSID_LIST_SCAN, NULL, 0); + if (res) { + WARNING("scanning failed (%08X)", res); + EXIT2(return -EOPNOTSUPP); + } + wnd->scan_timestamp = jiffies; + EXIT2(return 0); +} + +static int iw_set_scan(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + return set_scan(wnd); +} + +static int iw_get_scan(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + unsigned int i, list_len, needed; + NDIS_STATUS res; + struct ndis_bssid_list *bssid_list = NULL; + char *event = extra; + struct ndis_wlan_bssid *cur_item ; + + ENTER2(""); + if (time_before(jiffies, wnd->scan_timestamp + 3 * HZ)) + return -EAGAIN; + /* try with space for a few scan items */ + list_len = sizeof(ULONG) + sizeof(struct ndis_wlan_bssid_ex) * 8; + bssid_list = kmalloc(list_len, GFP_KERNEL); + if (!bssid_list) { + ERROR("couldn't allocate memory"); + return -ENOMEM; + } + /* some drivers don't set bssid_list->num_items to 0 if + OID_802_11_BSSID_LIST returns no items (prism54 driver, e.g.,) */ + memset(bssid_list, 0, list_len); + + needed = 0; + res = mp_query_info(wnd, OID_802_11_BSSID_LIST, + bssid_list, list_len, NULL, &needed); + if (res == NDIS_STATUS_INVALID_LENGTH || + res == NDIS_STATUS_BUFFER_TOO_SHORT) { + /* now try with required space */ + kfree(bssid_list); + list_len = needed; + bssid_list = kmalloc(list_len, GFP_KERNEL); + if (!bssid_list) { + ERROR("couldn't allocate memory"); + return -ENOMEM; + } + memset(bssid_list, 0, list_len); + + res = mp_query(wnd, OID_802_11_BSSID_LIST, + bssid_list, list_len); + } + if (res) { + WARNING("getting BSSID list failed (%08X)", res); + kfree(bssid_list); + EXIT2(return -EOPNOTSUPP); + } + TRACE2("%d", bssid_list->num_items); + cur_item = &bssid_list->bssid[0]; + for (i = 0; i < bssid_list->num_items; i++) { + event = ndis_translate_scan(dev, event, + extra + IW_SCAN_MAX_DATA, cur_item, info); + cur_item = (struct ndis_wlan_bssid *)((char *)cur_item + + cur_item->length); + } + wrqu->data.length = event - extra; + wrqu->data.flags = 0; + kfree(bssid_list); + EXIT2(return 0); +} + +static int iw_set_power_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + NDIS_STATUS res; + ULONG power_mode; + + if (wrqu->power.disabled == 1) + power_mode = NDIS_POWER_OFF; + else if (wrqu->power.flags & IW_POWER_MIN) + power_mode = NDIS_POWER_MIN; + else // if (wrqu->power.flags & IW_POWER_MAX) + power_mode = NDIS_POWER_MAX; + + TRACE2("%d", power_mode); + res = mp_set(wnd, OID_802_11_POWER_MODE, + &power_mode, sizeof(power_mode)); + if (res) + WARNING("setting power mode failed (%08X)", res); + return 0; +} + +static int iw_get_power_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + NDIS_STATUS res; + ULONG power_mode; + + ENTER2(""); + res = mp_query(wnd, OID_802_11_POWER_MODE, + &power_mode, sizeof(power_mode)); + if (res) + return -ENOTSUPP; + + if (power_mode == NDIS_POWER_OFF) + wrqu->power.disabled = 1; + else { + if (wrqu->power.flags != 0) + return 0; + wrqu->power.flags |= IW_POWER_ALL_R; + wrqu->power.flags |= IW_POWER_TIMEOUT; + wrqu->power.value = 0; + wrqu->power.disabled = 0; + + if (power_mode == NDIS_POWER_MIN) + wrqu->power.flags |= IW_POWER_MIN; + else // if (power_mode == NDIS_POWER_MAX) + wrqu->power.flags |= IW_POWER_MAX; + } + return 0; +} + +static int iw_get_sensitivity(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + NDIS_STATUS res; + ndis_rssi rssi_trigger; + + ENTER2(""); + res = mp_query(wnd, OID_802_11_RSSI_TRIGGER, + &rssi_trigger, sizeof(rssi_trigger)); + if (res) + return -EOPNOTSUPP; + wrqu->param.value = rssi_trigger; + wrqu->param.disabled = (rssi_trigger == 0); + wrqu->param.fixed = 1; + return 0; +} + +static int iw_set_sensitivity(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + NDIS_STATUS res; + ndis_rssi rssi_trigger; + + ENTER2(""); + if (wrqu->param.disabled) + rssi_trigger = 0; + else + rssi_trigger = wrqu->param.value; + res = mp_set(wnd, OID_802_11_RSSI_TRIGGER, + &rssi_trigger, sizeof(rssi_trigger)); + if (res == NDIS_STATUS_INVALID_DATA) + return -EINVAL; + if (res) + return -EOPNOTSUPP; + return 0; +} + +static int iw_get_ndis_stats(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + struct iw_statistics *stats = &wnd->iw_stats; + memcpy(&wrqu->qual, &stats->qual, sizeof(stats->qual)); + return 0; +} + +static int iw_get_range(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iw_range *range = (struct iw_range *)extra; + struct iw_point *data = &wrqu->data; + struct ndis_device *wnd = netdev_priv(dev); + unsigned int i, n; + NDIS_STATUS res; + ndis_rates_ex rates; + ndis_tx_power_level tx_power; + + ENTER2(""); + data->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + + range->txpower_capa = IW_TXPOW_MWATT; + range->num_txpower = 0; + + res = mp_query(wnd, OID_802_11_TX_POWER_LEVEL, + &tx_power, sizeof(tx_power)); + if (!res) { + range->num_txpower = 1; + range->txpower[0] = tx_power; + } + + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 18; + + range->retry_capa = IW_RETRY_LIMIT; + range->retry_flags = IW_RETRY_LIMIT; + range->min_retry = 0; + range->max_retry = 255; + + range->num_channels = 1; + + range->max_qual.qual = 100; + range->max_qual.level = 154; + range->max_qual.noise = 154; + range->sensitivity = 3; + + range->max_encoding_tokens = 4; + range->num_encoding_sizes = 2; + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + + range->num_bitrates = 0; + memset(&rates, 0, sizeof(rates)); + res = mp_query_info(wnd, OID_802_11_SUPPORTED_RATES, + &rates, sizeof(rates), &n, NULL); + if (res) + WARNING("getting bit rates failed: %08X", res); + else { + for (i = 0; i < n && range->num_bitrates < IW_MAX_BITRATES; i++) + if (rates[i] & 0x80) + continue; + else if (rates[i] & 0x7f) { + range->bitrate[range->num_bitrates] = + (rates[i] & 0x7f) * 500000; + range->num_bitrates++; + } + } + + range->num_channels = (sizeof(freq_chan)/sizeof(freq_chan[0])); + + for (i = 0; i < (sizeof(freq_chan)/sizeof(freq_chan[0])) && + i < IW_MAX_FREQUENCIES; i++) { + range->freq[i].i = i + 1; + range->freq[i].m = freq_chan[i] * 100000; + range->freq[i].e = 1; + } + range->num_frequency = i; + + range->min_rts = 0; + range->max_rts = 2347; + range->min_frag = 256; + range->max_frag = 2346; + + /* Event capability (kernel + driver) */ + range->event_capa[0] = (IW_EVENT_CAPA_K_0 | + IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | + IW_EVENT_CAPA_MASK(SIOCGIWAP) | + IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); + range->event_capa[1] = IW_EVENT_CAPA_K_1; + range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVTXDROP) | + IW_EVENT_CAPA_MASK(IWEVCUSTOM) | + IW_EVENT_CAPA_MASK(IWEVREGISTERED) | + IW_EVENT_CAPA_MASK(IWEVEXPIRED)); + + range->enc_capa = 0; + + if (test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr)) + range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP; + if (test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr)) + range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP; + + if (test_bit(Ndis802_11AuthModeWPA, &wnd->capa.auth) || + test_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.auth)) + range->enc_capa |= IW_ENC_CAPA_WPA; + if (test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) || + test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth)) + range->enc_capa |= IW_ENC_CAPA_WPA2; + + return 0; +} + +void set_default_iw_params(struct ndis_device *wnd) +{ + wnd->iw_auth_key_mgmt = 0; + wnd->iw_auth_wpa_version = 0; + set_infra_mode(wnd, Ndis802_11Infrastructure); + set_ndis_auth_mode(wnd, Ndis802_11AuthModeOpen); + set_priv_filter(wnd); + set_iw_encr_mode(wnd, IW_AUTH_CIPHER_NONE, IW_AUTH_CIPHER_NONE); +} + +static int deauthenticate(struct ndis_device *wnd) +{ + int ret; + + ENTER2(""); + ret = disassociate(wnd, 1); + set_default_iw_params(wnd); + EXIT2(return ret); +} + +NDIS_STATUS disassociate(struct ndis_device *wnd, int reset_ssid) +{ + NDIS_STATUS res; + u8 buf[NDIS_ESSID_MAX_SIZE]; + int i; + + TRACE2(""); + res = mp_set(wnd, OID_802_11_DISASSOCIATE, NULL, 0); + /* disassociate causes radio to be turned off; if reset_ssid + * is given, set ssid to random to enable radio */ + if (reset_ssid) { + get_random_bytes(buf, sizeof(buf)); + for (i = 0; i < sizeof(buf); i++) + buf[i] = 'a' + (buf[i] % 26); + set_essid(wnd, buf, sizeof(buf)); + } + return res; +} + +static ULONG ndis_priv_mode(struct ndis_device *wnd) +{ + if (wnd->iw_auth_wpa_version & IW_AUTH_WPA_VERSION_WPA2 || + wnd->iw_auth_wpa_version & IW_AUTH_WPA_VERSION_WPA) + return Ndis802_11PrivFilter8021xWEP; + else + return Ndis802_11PrivFilterAcceptAll; +} + +int set_priv_filter(struct ndis_device *wnd) +{ + NDIS_STATUS res; + ULONG flags; + + flags = ndis_priv_mode(wnd); + ENTER2("filter: %d", flags); + res = mp_set_int(wnd, OID_802_11_PRIVACY_FILTER, flags); + if (res) + TRACE2("setting privacy filter to %d failed (%08X)", + flags, res); + EXIT2(return 0); +} + +static int iw_set_mlme(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + struct iw_mlme *mlme = (struct iw_mlme *)extra; + + ENTER2(""); + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + return deauthenticate(wnd); + case IW_MLME_DISASSOC: + TRACE2("cmd=%d reason_code=%d", mlme->cmd, mlme->reason_code); + return disassociate(wnd, 1); + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int iw_set_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * NDIS drivers do not allow IEs to be configured; this is + * done by the driver based on other configuration. Return 0 + * to avoid causing issues with user space programs that + * expect this function to succeed. + */ + return 0; +} + +static int iw_set_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + TRACE2("index=%d value=%d", wrqu->param.flags & IW_AUTH_INDEX, + wrqu->param.value); + switch (wrqu->param.flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + wnd->iw_auth_wpa_version = wrqu->param.value; + break; + case IW_AUTH_CIPHER_PAIRWISE: + wnd->iw_auth_cipher_pairwise = wrqu->param.value; + break; + case IW_AUTH_CIPHER_GROUP: + wnd->iw_auth_cipher_group = wrqu->param.value; + break; + case IW_AUTH_KEY_MGMT: + wnd->iw_auth_key_mgmt = wrqu->param.value; + break; + case IW_AUTH_80211_AUTH_ALG: + wnd->iw_auth_80211_alg = wrqu->param.value; + break; + case IW_AUTH_WPA_ENABLED: + if (wrqu->param.value) + deauthenticate(wnd); + break; + case IW_AUTH_TKIP_COUNTERMEASURES: + case IW_AUTH_DROP_UNENCRYPTED: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + case IW_AUTH_PRIVACY_INVOKED: + TRACE2("%d not implemented: %d", + wrqu->param.flags & IW_AUTH_INDEX, wrqu->param.value); + break; + default: + WARNING("invalid cmd %d", wrqu->param.flags & IW_AUTH_INDEX); + return -EOPNOTSUPP; + } + return 0; +} + +static int iw_get_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + + ENTER2("index=%d", wrqu->param.flags & IW_AUTH_INDEX); + switch (wrqu->param.flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + wrqu->param.value = wnd->iw_auth_wpa_version; + break; + case IW_AUTH_CIPHER_PAIRWISE: + wrqu->param.value = wnd->iw_auth_cipher_pairwise; + break; + case IW_AUTH_CIPHER_GROUP: + wrqu->param.value = wnd->iw_auth_cipher_group; + break; + case IW_AUTH_KEY_MGMT: + wrqu->param.value = wnd->iw_auth_key_mgmt; + break; + case IW_AUTH_80211_AUTH_ALG: + wrqu->param.value = wnd->iw_auth_80211_alg; + break; + default: + WARNING("invalid cmd %d", wrqu->param.flags & IW_AUTH_INDEX); + return -EOPNOTSUPP; + } + return 0; +} + +static int iw_set_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + struct ndis_device *wnd = netdev_priv(dev); + struct ndis_add_key ndis_key; + int i, keyidx; + NDIS_STATUS res; + u8 *addr; + + keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; + ENTER2("%d", keyidx); + if (keyidx) + keyidx--; + else + keyidx = wnd->encr_info.tx_key_index; + + if (keyidx < 0 || keyidx >= MAX_ENCR_KEYS) + return -EINVAL; + + if (ext->alg == WPA_ALG_WEP) { + if (!test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr)) + EXIT2(return -1); + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) + wnd->encr_info.tx_key_index = keyidx; + if (add_wep_key(wnd, ext->key, ext->key_len, keyidx)) + EXIT2(return -1); + else + EXIT2(return 0); + } + if ((wrqu->encoding.flags & IW_ENCODE_DISABLED) || + ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0) + EXIT2(return remove_key(wnd, keyidx, ndis_key.bssid)); + + if (ext->key_len > sizeof(ndis_key.key)) { + TRACE2("incorrect key length (%u)", ext->key_len); + EXIT2(return -1); + } + + memset(&ndis_key, 0, sizeof(ndis_key)); + + ndis_key.struct_size = + sizeof(ndis_key) - sizeof(ndis_key.key) + ext->key_len; + ndis_key.length = ext->key_len; + ndis_key.index = keyidx; + + if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { + for (i = 0; i < 6 ; i++) + ndis_key.rsc |= (((u64)ext->rx_seq[i]) << (i * 8)); + TRACE2("0x%Lx", ndis_key.rsc); + ndis_key.index |= 1 << 29; + } + + addr = ext->addr.sa_data; + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + /* group key */ + if (wnd->infrastructure_mode == Ndis802_11IBSS) + memset(ndis_key.bssid, 0xff, ETH_ALEN); + else + get_ap_address(wnd, ndis_key.bssid); + } else { + /* pairwise key */ + ndis_key.index |= (1 << 30); + memcpy(ndis_key.bssid, addr, ETH_ALEN); + } + TRACE2(MACSTRSEP, MAC2STR(ndis_key.bssid)); + + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) + ndis_key.index |= (1 << 31); + + if (ext->alg == IW_ENCODE_ALG_TKIP && ext->key_len == 32) { + /* wpa_supplicant gives us the Michael MIC RX/TX keys in + * different order than NDIS spec, so swap the order here. */ + memcpy(ndis_key.key, ext->key, 16); + memcpy(ndis_key.key + 16, ext->key + 24, 8); + memcpy(ndis_key.key + 24, ext->key + 16, 8); + } else + memcpy(ndis_key.key, ext->key, ext->key_len); + + res = mp_set(wnd, OID_802_11_ADD_KEY, &ndis_key, ndis_key.struct_size); + if (res) { + TRACE2("adding key failed (%08X), %u", + res, ndis_key.struct_size); + EXIT2(return -1); + } + wnd->encr_info.keys[keyidx].length = ext->key_len; + memcpy(&wnd->encr_info.keys[keyidx].key, ndis_key.key, ext->key_len); + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) + wnd->encr_info.tx_key_index = keyidx; + TRACE2("key %d added", keyidx); + + EXIT2(return 0); +} + +static int iw_get_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; */ + /* TODO */ + ENTER2(""); + return 0; +} + +static int iw_set_pmksa(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iw_pmksa *pmksa = (struct iw_pmksa *)extra; + struct ndis_pmkid pmkid; + NDIS_STATUS res; + struct ndis_device *wnd = netdev_priv(dev); + + /* TODO: must keep local list of PMKIDs since NDIS drivers + * expect that all PMKID entries are included whenever a new + * one is added. */ + + ENTER2("%d", pmksa->cmd); + if ((pmksa->cmd == IW_PMKSA_ADD || pmksa->cmd == IW_PMKSA_REMOVE) && + (!(wnd->iw_auth_wpa_version & IW_AUTH_WPA_VERSION_WPA2))) + EXIT2(return -EOPNOTSUPP); + + memset(&pmkid, 0, sizeof(pmkid)); + if (pmksa->cmd == IW_PMKSA_ADD) { + pmkid.bssid_info_count = 1; + memcpy(pmkid.bssid_info[0].bssid, pmksa->bssid.sa_data, + ETH_ALEN); + memcpy(pmkid.bssid_info[0].pmkid, pmksa->pmkid, IW_PMKID_LEN); + } + pmkid.length = sizeof(pmkid); + + res = mp_set(wnd, OID_802_11_PMKID, &pmkid, pmkid.length); + if (res == NDIS_STATUS_FAILURE) + EXIT2(return -EOPNOTSUPP); + TRACE2("OID_802_11_PMKID -> %d", res); + if (res) + return -EINVAL; + + return 0; +} + +#define WEXT(id) [id - SIOCIWFIRST] + +static const iw_handler ndis_handler[] = { + WEXT(SIOCGIWNAME) = iw_get_network_type, + WEXT(SIOCSIWESSID) = iw_set_essid, + WEXT(SIOCGIWESSID) = iw_get_essid, + WEXT(SIOCSIWMODE) = iw_set_infra_mode, + WEXT(SIOCGIWMODE) = iw_get_infra_mode, + WEXT(SIOCGIWFREQ) = iw_get_freq, + WEXT(SIOCSIWFREQ) = iw_set_freq, + WEXT(SIOCGIWTXPOW) = iw_get_tx_power, + WEXT(SIOCSIWTXPOW) = iw_set_tx_power, + WEXT(SIOCGIWRATE) = iw_get_bitrate, + WEXT(SIOCSIWRATE) = iw_set_bitrate, + WEXT(SIOCGIWRTS) = iw_get_rts_threshold, + WEXT(SIOCSIWRTS) = iw_set_rts_threshold, + WEXT(SIOCGIWFRAG) = iw_get_frag_threshold, + WEXT(SIOCSIWFRAG) = iw_set_frag_threshold, + WEXT(SIOCGIWAP) = iw_get_ap_address, + WEXT(SIOCSIWAP) = iw_set_ap_address, + WEXT(SIOCSIWENCODE) = iw_set_wep, + WEXT(SIOCGIWENCODE) = iw_get_encr, + WEXT(SIOCSIWSCAN) = iw_set_scan, + WEXT(SIOCGIWSCAN) = iw_get_scan, + WEXT(SIOCGIWPOWER) = iw_get_power_mode, + WEXT(SIOCSIWPOWER) = iw_set_power_mode, + WEXT(SIOCGIWRANGE) = iw_get_range, + WEXT(SIOCGIWSTATS) = iw_get_ndis_stats, + WEXT(SIOCGIWSENS) = iw_get_sensitivity, + WEXT(SIOCSIWSENS) = iw_set_sensitivity, + WEXT(SIOCGIWNICKN) = iw_get_nick, + WEXT(SIOCSIWNICKN) = iw_set_nick, + WEXT(SIOCSIWCOMMIT) = iw_set_dummy, + WEXT(SIOCSIWMLME) = iw_set_mlme, + WEXT(SIOCSIWGENIE) = iw_set_genie, + WEXT(SIOCSIWAUTH) = iw_set_auth, + WEXT(SIOCGIWAUTH) = iw_get_auth, + WEXT(SIOCSIWENCODEEXT) = iw_set_encodeext, + WEXT(SIOCGIWENCODEEXT) = iw_get_encodeext, + WEXT(SIOCSIWPMKSA) = iw_set_pmksa, +}; + +/* private ioctl's */ + +static int priv_reset(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int res; + ENTER2(""); + res = mp_reset(netdev_priv(dev)); + if (res) { + WARNING("reset failed: %08X", res); + return -EOPNOTSUPP; + } + return 0; +} + +static int priv_deauthenticate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int res; + ENTER2(""); + res = deauthenticate(netdev_priv(dev)); + return res; +} + +static int priv_power_profile(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + struct miniport *mp; + ULONG profile_inf; + + ENTER2(""); + mp = &wnd->wd->driver->ndis_driver->mp; + if (!mp->pnp_event_notify) + EXIT2(return -EOPNOTSUPP); + + /* 1 for AC and 0 for Battery */ + if (wrqu->param.value) + profile_inf = NdisPowerProfileAcOnLine; + else + profile_inf = NdisPowerProfileBattery; + + LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx, + NdisDevicePnPEventPowerProfileChanged, + &profile_inf, sizeof(profile_inf)); + EXIT2(return 0); +} + +static int priv_network_type(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + enum network_type network_type; + NDIS_STATUS res; + char type; + + ENTER2(""); + type = wrqu->param.value; + if (type == 'f') + network_type = Ndis802_11FH; + else if (type == 'b') + network_type = Ndis802_11DS; + else if (type == 'a') + network_type = Ndis802_11OFDM5; + else if (type == 'g' || type == 'n') + network_type = Ndis802_11OFDM24; + else + network_type = Ndis802_11Automode; + + res = mp_set_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE, network_type); + if (res) { + WARNING("setting network type to %d failed (%08X)", + network_type, res); + EXIT2(return -EINVAL); + } + + EXIT2(return 0); +} + +static int priv_media_stream_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + NDIS_STATUS res; + int mode; + + ENTER2(""); + if (wrqu->param.value > 0) + mode = Ndis802_11MediaStreamOn; + else + mode = Ndis802_11MediaStreamOff; + res = mp_set_int(wnd, OID_802_11_MEDIA_STREAM_MODE, mode); + if (res) { + WARNING("oid failed (%08X)", res); + EXIT2(return -EINVAL); + } + EXIT2(return 0); +} + +static int priv_reload_defaults(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ndis_device *wnd = netdev_priv(dev); + int res; + ENTER2(""); + res = mp_set_int(wnd, OID_802_11_RELOAD_DEFAULTS, + Ndis802_11ReloadWEPKeys); + if (res) { + WARNING("reloading defaults failed: %08X", res); + return -EOPNOTSUPP; + } + return 0; +} + +static const struct iw_priv_args priv_args[] = { + {PRIV_RESET, 0, 0, "ndis_reset"}, + {PRIV_POWER_PROFILE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "power_profile"}, + {PRIV_DEAUTHENTICATE, 0, 0, "deauthenticate"}, + {PRIV_NETWORK_TYPE, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, + "network_type"}, + {PRIV_MEDIA_STREAM_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "media_stream"}, + + {PRIV_RELOAD_DEFAULTS, 0, 0, "reload_defaults"}, +}; + +#define WEPRIV(id) [id - SIOCIWFIRSTPRIV] + +static const iw_handler priv_handler[] = { + WEPRIV(PRIV_RESET) = priv_reset, + WEPRIV(PRIV_POWER_PROFILE) = priv_power_profile, + WEPRIV(PRIV_DEAUTHENTICATE) = priv_deauthenticate, + WEPRIV(PRIV_NETWORK_TYPE) = priv_network_type, + WEPRIV(PRIV_MEDIA_STREAM_MODE) = priv_media_stream_mode, + WEPRIV(PRIV_RELOAD_DEFAULTS) = priv_reload_defaults, +}; + +const struct iw_handler_def ndis_handler_def = { + .num_standard = sizeof(ndis_handler) / sizeof(ndis_handler[0]), + .num_private = sizeof(priv_handler) / sizeof(priv_handler[0]), + .num_private_args = sizeof(priv_args) / sizeof(priv_args[0]), + + .standard = (iw_handler *)ndis_handler, + .private = (iw_handler *)priv_handler, + .private_args = (struct iw_priv_args *)priv_args, + .get_wireless_stats = get_iw_stats, +}; --- linux-2.6.27.orig/ubuntu/ndiswrapper/divdi3.c +++ linux-2.6.27/ubuntu/ndiswrapper/divdi3.c @@ -0,0 +1,329 @@ +/* 64-bit multiplication and division + Copyright (C) 1989, 1992-1999, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include + +#if BITS_PER_LONG != 32 +#error This is for 32-bit targets only +#endif + +typedef unsigned int UQItype __attribute__ ((mode (QI))); +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef unsigned int UDItype __attribute__ ((mode (DI))); +#define Wtype SItype +#define HWtype SItype +#define DWtype DItype +#define UWtype USItype +#define UHWtype USItype +#define UDWtype UDItype +#define W_TYPE_SIZE 32 + +#include "longlong.h" + +#if defined(__BIG_ENDIAN) +struct DWstruct { Wtype high, low;}; +#elif defined(__LITTLE_ENDIAN) +struct DWstruct { Wtype low, high;}; +#else +#error Unhandled endianity +#endif +typedef union { struct DWstruct s; DWtype ll; } DWunion; + +/* Prototypes of exported functions. */ +extern DWtype __divdi3 (DWtype u, DWtype v); +extern DWtype __moddi3 (DWtype u, DWtype v); +extern UDWtype __udivdi3 (UDWtype u, UDWtype v); +extern UDWtype __umoddi3 (UDWtype u, UDWtype v); + +static UDWtype +__udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp) +{ + DWunion ww; + DWunion nn, dd; + DWunion rr; + UWtype d0, d1, n0, n1, n2; + UWtype q0, q1; + UWtype b, bm; + + nn.ll = n; + dd.ll = d; + + d0 = dd.s.low; + d1 = dd.s.high; + n0 = nn.s.low; + n1 = nn.s.high; + +#if !UDIV_NEEDS_NORMALIZATION + if (d1 == 0) + { + if (d0 > n1) + { + /* 0q = nn / 0D */ + + udiv_qrnnd (q0, n0, n1, n0, d0); + q1 = 0; + + /* Remainder in n0. */ + } + else + { + /* qq = NN / 0d */ + + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ + + udiv_qrnnd (q1, n1, 0, n1, d0); + udiv_qrnnd (q0, n0, n1, n0, d0); + + /* Remainder in n0. */ + } + + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = 0; + *rp = rr.ll; + } + } + +#else /* UDIV_NEEDS_NORMALIZATION */ + + if (d1 == 0) + { + if (d0 > n1) + { + /* 0q = nn / 0D */ + + count_leading_zeros (bm, d0); + + if (bm != 0) + { + /* Normalize, i.e. make the most significant bit of the + denominator set. */ + + d0 = d0 << bm; + n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); + n0 = n0 << bm; + } + + udiv_qrnnd (q0, n0, n1, n0, d0); + q1 = 0; + + /* Remainder in n0 >> bm. */ + } + else + { + /* qq = NN / 0d */ + + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ + + count_leading_zeros (bm, d0); + + if (bm == 0) + { + /* From (n1 >= d0) /\ (the most significant bit of d0 is set), + conclude (the most significant bit of n1 is set) /\ (the + leading quotient digit q1 = 1). + + This special case is necessary, not an optimization. + (Shifts counts of W_TYPE_SIZE are undefined.) */ + + n1 -= d0; + q1 = 1; + } + else + { + /* Normalize. */ + + b = W_TYPE_SIZE - bm; + + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd (q1, n1, n2, n1, d0); + } + + /* n1 != d0... */ + + udiv_qrnnd (q0, n0, n1, n0, d0); + + /* Remainder in n0 >> bm. */ + } + + if (rp != 0) + { + rr.s.low = n0 >> bm; + rr.s.high = 0; + *rp = rr.ll; + } + } +#endif /* UDIV_NEEDS_NORMALIZATION */ + + else + { + if (d1 > n1) + { + /* 00 = nn / DD */ + + q0 = 0; + q1 = 0; + + /* Remainder in n1n0. */ + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } + else + { + /* 0q = NN / dd */ + + count_leading_zeros (bm, d1); + if (bm == 0) + { + /* From (n1 >= d1) /\ (the most significant bit of d1 is set), + conclude (the most significant bit of n1 is set) /\ (the + quotient digit q0 = 0 or 1). + + This special case is necessary, not an optimization. */ + + /* The condition on the next line takes advantage of that + n1 >= d1 (true due to program flow). */ + if (n1 > d1 || n0 >= d0) + { + q0 = 1; + sub_ddmmss (n1, n0, n1, n0, d1, d0); + } + else + q0 = 0; + + q1 = 0; + + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } + else + { + UWtype m1, m0; + /* Normalize. */ + + b = W_TYPE_SIZE - bm; + + d1 = (d1 << bm) | (d0 >> b); + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd (q0, n1, n2, n1, d1); + umul_ppmm (m1, m0, q0, d0); + + if (m1 > n1 || (m1 == n1 && m0 > n0)) + { + q0--; + sub_ddmmss (m1, m0, m1, m0, d1, d0); + } + + q1 = 0; + + /* Remainder in (n1n0 - m1m0) >> bm. */ + if (rp != 0) + { + sub_ddmmss (n1, n0, n1, n0, m1, m0); + rr.s.low = (n1 << b) | (n0 >> bm); + rr.s.high = n1 >> bm; + *rp = rr.ll; + } + } + } + } + + ww.s.low = q0; + ww.s.high = q1; + return ww.ll; +} + +DWtype +__divdi3 (DWtype u, DWtype v) +{ + Wtype c = 0; + DWtype w; + + if (u < 0) + { + c = ~c; + u = -u; + } + if (v < 0) + { + c = ~c; + v = -v; + } + w = __udivmoddi4 (u, v, NULL); + if (c) + w = -w; + return w; +} + +DWtype +__moddi3 (DWtype u, DWtype v) +{ + Wtype c = 0; + DWtype w; + + if (u < 0) + { + c = ~c; + u = -u; + } + if (v < 0) + v = -v; + __udivmoddi4 (u, v, &w); + if (c) + w = -w; + return w; +} + +UDWtype +__udivdi3 (UDWtype u, UDWtype v) +{ + return __udivmoddi4 (u, v, NULL); +} + +UDWtype +__umoddi3 (UDWtype u, UDWtype v) +{ + UDWtype w; + + __udivmoddi4 (u, v, &w); + return w; +} --- linux-2.6.27.orig/ubuntu/ndiswrapper/Makefile +++ linux-2.6.27/ubuntu/ndiswrapper/Makefile @@ -0,0 +1,38 @@ +ndiswrapper-objs := crt.o hal.o iw_ndis.o loader.o ndis.o ntoskernel.o ntoskernel_io.o \ + pe_linker.o pnp.o proc.o rtl.o wrapmem.o wrapndis.o wrapper.o usb.o + +EXPORTS = crt_exports.h hal_exports.h ndis_exports.h ntoskernel_exports.h \ + ntoskernel_io_exports.h rtl_exports.h usb_exports.h + +STUB_SRCS = crt.c hal.c ndis.c ntoskernel.c ntoskernel_io.c \ + pnp.c rtl.c wrapndis.c usb.c + + +EXTRA_CFLAGS += -DENABLE_USB -I$(obj) +EXTRA_AFLAGS += -I$(obj) + +# generate exports symbol table from C files +quiet_cmd_mkexport = MKEXPORT $@ +cmd_mkexport = $(SHELL) $(srctree)/$(src)/mkexport.sh $< $@ + +%_exports.h: %.c $(srctree)/$(src)/mkexport.sh FORCE + $(call if_changed,mkexport) + +$(addprefix $(obj)/,$(EXPORTS:_exports.h=.o)): %.o: %_exports.h +extra-y += $(EXPORTS) + +ifeq ($(CONFIG_X86_64),y) +quiet_cmd_mkstubs = MKSTUBS $@ +cmd_mkstubs = $(SHELL) $(srctree)/$(src)/mkstubs.sh $(addprefix $(srctree)/$(src)/,$(STUB_SRCS)) >$@ + +$(obj)/win2lin_stubs.h: $(addprefix $(srctree)/$(src)/,$(STUB_SRCS)) FORCE + $(call if_changed,mkstubs) + +$(obj)/win2lin_stubs.o: $(obj)/win2lin_stubs.h +extra-y += win2lin_stubs.h +ndiswrapper-objs += win2lin_stubs.o +else +ndiswrapper-objs += divdi3.o +endif + +obj-$(CONFIG_NDISWRAPPER) := ndiswrapper.o --- linux-2.6.27.orig/ubuntu/ndiswrapper/wrapmem.c +++ linux-2.6.27/ubuntu/ndiswrapper/wrapmem.c @@ -0,0 +1,360 @@ +/* + * Copyright (C) 2006 Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define _WRAPMEM_C_ + +#include "ntoskernel.h" + +struct slack_alloc_info { + struct nt_list list; + size_t size; +}; + +static struct nt_list allocs; +static struct nt_list slack_allocs; +static spinlock_t alloc_lock; + +struct vmem_block { + struct nt_list list; + int size; +}; + +static struct nt_list vmem_list; + +#if defined(ALLOC_DEBUG) +struct alloc_info { + enum alloc_type type; + size_t size; +#if ALLOC_DEBUG > 1 + struct nt_list list; + const char *file; + int line; + ULONG tag; +#endif +}; + +static atomic_t alloc_sizes[ALLOC_TYPE_MAX]; +#endif + +void wrapmem_info(void) +{ +#ifdef ALLOC_DEBUG + enum alloc_type type; + for (type = 0; type < ALLOC_TYPE_MAX; type++) + INFO("total size of allocations in %d: %d", + type, atomic_read(&alloc_sizes[type])); +#endif +} + +/* allocate memory and add it to list of allocated pointers; if a + * driver doesn't free this memory for any reason (buggy driver or we + * allocate space behind driver's back since we need more space than + * corresponding Windows structure provides etc.), this gets freed + * automatically when module is unloaded + */ +void *slack_kmalloc(size_t size) +{ + struct slack_alloc_info *info; + gfp_t flags; + + ENTER4("size = %lu", (unsigned long)size); + + if (irql_gfp() & GFP_ATOMIC) + flags = GFP_ATOMIC; + else + flags = GFP_KERNEL; + info = kmalloc(size + sizeof(*info), flags); + if (!info) + return NULL; + info->size = size; + spin_lock_bh(&alloc_lock); + InsertTailList(&slack_allocs, &info->list); + spin_unlock_bh(&alloc_lock); +#ifdef ALLOC_DEBUG + atomic_add(size, &alloc_sizes[ALLOC_TYPE_SLACK]); +#endif + TRACE4("%p, %p", info, info + 1); + EXIT4(return info + 1); +} + +/* free pointer and remove from list of allocated pointers */ +void slack_kfree(void *ptr) +{ + struct slack_alloc_info *info; + + ENTER4("%p", ptr); + info = ptr - sizeof(*info); + spin_lock_bh(&alloc_lock); + RemoveEntryList(&info->list); + spin_unlock_bh(&alloc_lock); +#ifdef ALLOC_DEBUG + atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]); +#endif + kfree(info); + EXIT4(return); +} + +#if defined(ALLOC_DEBUG) +void *wrap_kmalloc(size_t size, gfp_t flags, const char *file, int line) +{ + struct alloc_info *info; + + info = kmalloc(size + sizeof(*info), flags); + if (!info) + return NULL; + if (flags & GFP_ATOMIC) + info->type = ALLOC_TYPE_KMALLOC_ATOMIC; + else + info->type = ALLOC_TYPE_KMALLOC_NON_ATOMIC; + info->size = size; + atomic_add(size, &alloc_sizes[info->type]); +#if ALLOC_DEBUG > 1 + info->file = file; + info->line = line; + info->tag = 0; + spin_lock_bh(&alloc_lock); + InsertTailList(&allocs, &info->list); + spin_unlock_bh(&alloc_lock); +#endif + TRACE4("%p", info + 1); + return (info + 1); +} + +void *wrap_kzalloc(size_t size, gfp_t flags, const char *file, int line) +{ + void *ptr = wrap_kmalloc(size, flags, file, line); + if (ptr) + memset(ptr, 0, size); + return ptr; +} + +void wrap_kfree(void *ptr) +{ + struct alloc_info *info; + + TRACE4("%p", ptr); + if (!ptr) + return; + info = ptr - sizeof(*info); + atomic_sub(info->size, &alloc_sizes[info->type]); +#if ALLOC_DEBUG > 1 + spin_lock_bh(&alloc_lock); + RemoveEntryList(&info->list); + spin_unlock_bh(&alloc_lock); + if (!(info->type == ALLOC_TYPE_KMALLOC_ATOMIC || + info->type == ALLOC_TYPE_KMALLOC_NON_ATOMIC)) + WARNING("invliad type: %d", info->type); +#endif + kfree(info); +} + +void *wrap_vmalloc(unsigned long size, const char *file, int line) +{ + struct alloc_info *info; + + info = vmalloc(size + sizeof(*info)); + if (!info) + return NULL; + info->type = ALLOC_TYPE_VMALLOC_NON_ATOMIC; + info->size = size; + atomic_add(size, &alloc_sizes[info->type]); +#if ALLOC_DEBUG > 1 + info->file = file; + info->line = line; + info->tag = 0; + spin_lock_bh(&alloc_lock); + InsertTailList(&allocs, &info->list); + spin_unlock_bh(&alloc_lock); +#endif + return (info + 1); +} + +void *wrap__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot, + const char *file, int line) +{ + struct alloc_info *info; + + info = __vmalloc(size + sizeof(*info), gfp_mask, prot); + if (!info) + return NULL; + if (gfp_mask & GFP_ATOMIC) + info->type = ALLOC_TYPE_VMALLOC_ATOMIC; + else + info->type = ALLOC_TYPE_VMALLOC_NON_ATOMIC; + info->size = size; + atomic_add(size, &alloc_sizes[info->type]); +#if ALLOC_DEBUG > 1 + info->file = file; + info->line = line; + info->tag = 0; + spin_lock_bh(&alloc_lock); + InsertTailList(&allocs, &info->list); + spin_unlock_bh(&alloc_lock); +#endif + return (info + 1); +} + +void wrap_vfree(void *ptr) +{ + struct alloc_info *info; + + info = ptr - sizeof(*info); + atomic_sub(info->size, &alloc_sizes[info->type]); +#if ALLOC_DEBUG > 1 + spin_lock_bh(&alloc_lock); + RemoveEntryList(&info->list); + spin_unlock_bh(&alloc_lock); + if (!(info->type == ALLOC_TYPE_VMALLOC_ATOMIC || + info->type == ALLOC_TYPE_VMALLOC_NON_ATOMIC)) + WARNING("invliad type: %d", info->type); +#endif + vfree(info); +} + +void *wrap_alloc_pages(gfp_t flags, unsigned int size, + const char *file, int line) +{ + struct alloc_info *info; + + size += sizeof(*info); + info = (struct alloc_info *)__get_free_pages(flags, get_order(size)); + if (!info) + return NULL; + info->type = ALLOC_TYPE_PAGES; + info->size = size; + atomic_add(size, &alloc_sizes[info->type]); +#if ALLOC_DEBUG > 1 + info->file = file; + info->line = line; + info->tag = 0; + spin_lock_bh(&alloc_lock); + InsertTailList(&allocs, &info->list); + spin_unlock_bh(&alloc_lock); +#endif + return info + 1; +} + +void wrap_free_pages(unsigned long ptr, int order) +{ + struct alloc_info *info; + + info = (void *)ptr - sizeof(*info); + atomic_sub(info->size, &alloc_sizes[info->type]); +#if ALLOC_DEBUG > 1 + spin_lock_bh(&alloc_lock); + RemoveEntryList(&info->list); + spin_unlock_bh(&alloc_lock); + if (info->type != ALLOC_TYPE_PAGES) + WARNING("invliad type: %d", info->type); +#endif + free_pages((unsigned long)info, get_order(info->size)); +} + +#if ALLOC_DEBUG > 1 +#undef ExAllocatePoolWithTag +void *wrap_ExAllocatePoolWithTag(enum pool_type pool_type, SIZE_T size, + ULONG tag, const char *file, int line) +{ + void *addr; + struct alloc_info *info; + + ENTER4("pool_type: %d, size: %lu, tag: %u", pool_type, size, tag); + addr = ExAllocatePoolWithTag(pool_type, size, tag); + if (!addr) + return NULL; + info = addr - sizeof(*info); + info->file = file; + info->line = line; + info->tag = tag; + EXIT4(return addr); +} +#endif + +int alloc_size(enum alloc_type type) +{ + if (type >= 0 && type < ALLOC_TYPE_MAX) + return atomic_read(&alloc_sizes[type]); + else + return -EINVAL; +} + +#endif // ALLOC_DEBUG + +int wrapmem_init(void) +{ + InitializeListHead(&allocs); + InitializeListHead(&slack_allocs); + InitializeListHead(&vmem_list); + spin_lock_init(&alloc_lock); + return 0; +} + +void wrapmem_exit(void) +{ + enum alloc_type type; + struct nt_list *ent; + + /* free all pointers on the slack list */ + while (1) { + struct slack_alloc_info *info; + spin_lock_bh(&alloc_lock); + ent = RemoveHeadList(&slack_allocs); + spin_unlock_bh(&alloc_lock); + if (!ent) + break; + info = container_of(ent, struct slack_alloc_info, list); +#ifdef ALLOC_DEBUG + atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]); +#endif + kfree(info); + } + type = 0; +#ifdef ALLOC_DEBUG + for (type = 0; type < ALLOC_TYPE_MAX; type++) { + int n = atomic_read(&alloc_sizes[type]); + if (n) + WARNING("%d bytes of memory in %d leaking", n, type); + } + +#if ALLOC_DEBUG > 1 + while (1) { + struct alloc_info *info; + + spin_lock_bh(&alloc_lock); + ent = RemoveHeadList(&allocs); + spin_unlock_bh(&alloc_lock); + if (!ent) + break; + info = container_of(ent, struct alloc_info, list); + atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]); + WARNING("%p in %d of size %zu allocated at %s(%d) " + "with tag 0x%08X leaking; freeing it now", + info + 1, info->type, info->size, info->file, + info->line, info->tag); + if (info->type == ALLOC_TYPE_KMALLOC_ATOMIC || + info->type == ALLOC_TYPE_KMALLOC_NON_ATOMIC) + kfree(info); + else if (info->type == ALLOC_TYPE_VMALLOC_ATOMIC || + info->type == ALLOC_TYPE_VMALLOC_NON_ATOMIC) + vfree(info); + else if (info->type == ALLOC_TYPE_PAGES) + free_pages((unsigned long)info, get_order(info->size)); + else + WARNING("invalid type: %d; not freed", info->type); + } +#endif +#endif + return; +} --- linux-2.6.27.orig/ubuntu/ndiswrapper/pnp.c +++ linux-2.6.27/ubuntu/ndiswrapper/pnp.c @@ -0,0 +1,742 @@ +/* + * Copyright (C) 2005 Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "usb.h" +#include "pnp.h" +#include "wrapndis.h" +#include "loader.h" + +/* Functions callable from the NDIS driver */ +wstdcall NTSTATUS pdoDispatchDeviceControl(struct device_object *pdo, + struct irp *irp); +wstdcall NTSTATUS pdoDispatchPnp(struct device_object *pdo, struct irp *irp); +wstdcall NTSTATUS pdoDispatchPower(struct device_object *pdo, struct irp *irp); + +static NTSTATUS start_pdo(struct device_object *pdo) +{ + int i, ret, count, resources_size; + struct wrap_device *wd; + struct pci_dev *pdev; + struct cm_partial_resource_descriptor *entry; + struct cm_partial_resource_list *partial_resource_list; + + ENTER1("%p, %p", pdo, pdo->reserved); + wd = pdo->reserved; + if (ntoskernel_init_device(wd)) + EXIT1(return STATUS_FAILURE); + if (wrap_is_usb_bus(wd->dev_bus)) { +#ifdef ENABLE_USB + if (usb_init_device(wd)) { + ntoskernel_exit_device(wd); + EXIT1(return STATUS_FAILURE); + } +#endif + EXIT1(return STATUS_SUCCESS); + } + if (!wrap_is_pci_bus(wd->dev_bus)) + EXIT1(return STATUS_SUCCESS); + pdev = wd->pci.pdev; + ret = pci_enable_device(pdev); + if (ret) { + ERROR("couldn't enable PCI device: %x", ret); + return STATUS_FAILURE; + } + ret = pci_request_regions(pdev, DRIVER_NAME); + if (ret) { + ERROR("couldn't request PCI regions: %x", ret); + goto err_enable; + } + pci_set_power_state(pdev, PCI_D0); +#ifdef CONFIG_X86_64 + /* 64-bit broadcom driver doesn't work if DMA is allocated + * from over 1GB */ + if (wd->vendor == 0x14e4) { + if (pci_set_dma_mask(pdev, DMA_30BIT_MASK) || + pci_set_consistent_dma_mask(pdev, DMA_30BIT_MASK)) + WARNING("couldn't set DMA mask; this driver " + "may not work with more than 1GB RAM"); + } +#endif + /* IRQ resource entry is filled in from pdev, instead of + * pci_resource macros */ + for (i = count = 0; pci_resource_start(pdev, i); i++) + if ((pci_resource_flags(pdev, i) & IORESOURCE_MEM) || + (pci_resource_flags(pdev, i) & IORESOURCE_IO)) + count++; + /* space for entry for IRQ is already in + * cm_partial_resource_list */ + resources_size = sizeof(struct cm_resource_list) + + sizeof(struct cm_partial_resource_descriptor) * count; + TRACE2("resources: %d, %d", count, resources_size); + wd->resource_list = kzalloc(resources_size, GFP_KERNEL); + if (!wd->resource_list) { + WARNING("couldn't allocate memory"); + goto err_regions; + } + wd->resource_list->count = 1; + wd->resource_list->list[0].interface_type = PCIBus; + /* bus_number is not used by WDM drivers */ + wd->resource_list->list[0].bus_number = pdev->bus->number; + + partial_resource_list = + &wd->resource_list->list->partial_resource_list; + partial_resource_list->version = 1; + partial_resource_list->revision = 1; + partial_resource_list->count = count + 1; + + for (i = count = 0; pci_resource_start(pdev, i); i++) { + entry = &partial_resource_list->partial_descriptors[count]; + TRACE2("%d", count); + if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { + entry->type = CmResourceTypeMemory; + entry->flags = CM_RESOURCE_MEMORY_READ_WRITE; + entry->share = CmResourceShareDeviceExclusive; + } else if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { + entry->type = CmResourceTypePort; + entry->flags = CM_RESOURCE_PORT_IO; + entry->share = CmResourceShareDeviceExclusive; +#if 0 + } else if (pci_resource_flags(pdev, i) & IORESOURCE_DMA) { + /* it looks like no driver uses this resource */ + typeof(pci_resource_flags(pdev, 0)) flags; + entry->type = CmResourceTypeDma; + flags = pci_resource_flags(pdev, i); + if (flags & IORESOURCE_DMA_TYPEA) + entry->flags |= CM_RESOURCE_DMA_TYPE_A; + else if (flags & IORESOURCE_DMA_TYPEB) + entry->flags |= CM_RESOURCE_DMA_TYPE_B; + else if (flags & IORESOURCE_DMA_TYPEF) + entry->flags |= CM_RESOURCE_DMA_TYPE_F; + if (flags & IORESOURCE_DMA_8BIT) + entry->flags |= CM_RESOURCE_DMA_8; + else if (flags & IORESOURCE_DMA_16BIT) + entry->flags |= CM_RESOURCE_DMA_16; + /* what about 32bit DMA? */ + else if (flags & IORESOURCE_DMA_8AND16BIT) + entry->flags |= CM_RESOURCE_DMA_8_AND_16; + if (flags & IORESOURCE_DMA_MASTER) + entry->flags |= CM_RESOURCE_DMA_BUS_MASTER; + entry->u.dma.channel = pci_resource_start(pdev, i); + /* what should this be? */ + entry->u.dma.port = 1; +#endif + } else + continue; + /* TODO: Add other resource types? */ + entry->u.generic.start = + (ULONG_PTR)pci_resource_start(pdev, i); + entry->u.generic.length = pci_resource_len(pdev, i); + count++; + } + + /* put IRQ resource at the end */ + entry = &partial_resource_list->partial_descriptors[count++]; + entry->type = CmResourceTypeInterrupt; + entry->flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + /* we assume all devices use shared IRQ */ + entry->share = CmResourceShareShared; + /* as per documentation, interrupt level should be DIRQL, but + * examples from DDK as well some drivers, such as AR5211, + * RT8180L use interrupt level as interrupt vector also in + * NdisMRegisterInterrupt */ + entry->u.interrupt.level = pdev->irq; + entry->u.interrupt.vector = pdev->irq; + entry->u.interrupt.affinity = -1; + + TRACE2("resource list count %d, irq: %d", + partial_resource_list->count, pdev->irq); + pci_set_drvdata(pdev, wd); + EXIT1(return STATUS_SUCCESS); +err_regions: + pci_release_regions(pdev); +err_enable: + pci_disable_device(pdev); + wd->pci.pdev = NULL; + wd->pdo = NULL; + EXIT1(return STATUS_FAILURE); +} + +static void remove_pdo(struct device_object *pdo) +{ + struct wrap_device *wd = pdo->reserved; + + ntoskernel_exit_device(wd); + if (wrap_is_pci_bus(wd->dev_bus)) { + struct pci_dev *pdev = wd->pci.pdev; + pci_release_regions(pdev); + pci_disable_device(pdev); + wd->pci.pdev = NULL; + pci_set_drvdata(pdev, NULL); + } else if (wrap_is_usb_bus(wd->dev_bus)) { +#ifdef ENABLE_USB + usb_exit_device(wd); +#endif + } + if (wd->resource_list) + kfree(wd->resource_list); + wd->resource_list = NULL; + return; +} + +static NTSTATUS IoSendIrpTopDev(struct device_object *dev_obj, ULONG major_fn, + ULONG minor_fn, struct io_stack_location *sl) +{ + NTSTATUS status; + struct nt_event event; + struct irp *irp; + struct io_stack_location *irp_sl; + struct device_object *top_dev = IoGetAttachedDeviceReference(dev_obj); + + KeInitializeEvent(&event, NotificationEvent, FALSE); + irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, top_dev, NULL, 0, NULL, + &event, NULL); + irp->io_status.status = STATUS_NOT_IMPLEMENTED; + irp->io_status.info = 0; + irp_sl = IoGetNextIrpStackLocation(irp); + if (sl) + memcpy(irp_sl, sl, sizeof(*irp_sl)); + irp_sl->major_fn = major_fn; + irp_sl->minor_fn = minor_fn; + status = IoCallDriver(top_dev, irp); + if (status == STATUS_PENDING) { + KeWaitForSingleObject(&event, Executive, KernelMode, + FALSE, NULL); + status = irp->io_status.status; + } + ObDereferenceObject(top_dev); + return status; +} + +wstdcall NTSTATUS pdoDispatchDeviceControl(struct device_object *pdo, + struct irp *irp) +{ + struct io_stack_location *irp_sl; + NTSTATUS status; + + DUMP_IRP(irp); + irp_sl = IoGetCurrentIrpStackLocation(irp); +#ifdef ENABLE_USB + status = wrap_submit_irp(pdo, irp); + IOTRACE("status: %08X", status); + if (status != STATUS_PENDING) + IoCompleteRequest(irp, IO_NO_INCREMENT); +#else + status = irp->io_status.status = STATUS_NOT_IMPLEMENTED; + IoCompleteRequest(irp, IO_NO_INCREMENT); +#endif + IOEXIT(return status); +} +WIN_FUNC_DECL(pdoDispatchDeviceControl,2) + +wstdcall NTSTATUS pdoDispatchPnp(struct device_object *pdo, struct irp *irp) +{ + struct io_stack_location *irp_sl; + struct wrap_device *wd; + NTSTATUS status; +#ifdef ENABLE_USB + struct usbd_bus_interface_usbdi *usb_intf; +#endif + + irp_sl = IoGetCurrentIrpStackLocation(irp); + TRACE2("%p %d:%d", pdo, irp_sl->major_fn, irp_sl->minor_fn); + wd = pdo->reserved; + switch (irp_sl->minor_fn) { + case IRP_MN_START_DEVICE: + status = start_pdo(pdo); + break; + case IRP_MN_QUERY_STOP_DEVICE: + case IRP_MN_STOP_DEVICE: + case IRP_MN_QUERY_REMOVE_DEVICE: + status = STATUS_SUCCESS; + break; + case IRP_MN_REMOVE_DEVICE: + remove_pdo(pdo); + status = STATUS_SUCCESS; + break; + case IRP_MN_QUERY_INTERFACE: +#ifdef ENABLE_USB + if (!wrap_is_usb_bus(wd->dev_bus)) { + status = STATUS_NOT_IMPLEMENTED; + break; + } + TRACE2("type: %x, size: %d, version: %d", + irp_sl->params.query_intf.type->data1, + irp_sl->params.query_intf.size, + irp_sl->params.query_intf.version); + usb_intf = (struct usbd_bus_interface_usbdi *) + irp_sl->params.query_intf.intf; + usb_intf->Context = wd; + usb_intf->InterfaceReference = USBD_InterfaceReference; + usb_intf->InterfaceDereference = USBD_InterfaceDereference; + usb_intf->GetUSBDIVersion = USBD_InterfaceGetUSBDIVersion; + usb_intf->QueryBusTime = USBD_InterfaceQueryBusTime; + usb_intf->SubmitIsoOutUrb = USBD_InterfaceSubmitIsoOutUrb; + usb_intf->QueryBusInformation = + USBD_InterfaceQueryBusInformation; + if (irp_sl->params.query_intf.version >= + USB_BUSIF_USBDI_VERSION_1) + usb_intf->IsDeviceHighSpeed = + USBD_InterfaceIsDeviceHighSpeed; + if (irp_sl->params.query_intf.version >= + USB_BUSIF_USBDI_VERSION_2) + usb_intf->LogEntry = USBD_InterfaceLogEntry; + status = STATUS_SUCCESS; +#else + status = STATUS_NOT_IMPLEMENTED; +#endif + break; + default: + TRACE2("fn %d not implemented", irp_sl->minor_fn); + status = STATUS_SUCCESS; + break; + } + irp->io_status.status = status; + TRACE2("status: %08X", status); + IoCompleteRequest(irp, IO_NO_INCREMENT); + IOEXIT(return status); +} +WIN_FUNC_DECL(pdoDispatchPnp,2) + +wstdcall NTSTATUS pdoDispatchPower(struct device_object *pdo, struct irp *irp) +{ + struct io_stack_location *irp_sl; + struct wrap_device *wd; + union power_state power_state; + struct pci_dev *pdev; + NTSTATUS status; + + irp_sl = IoGetCurrentIrpStackLocation(irp); + wd = pdo->reserved; + TRACE2("pdo: %p, fn: %d:%d, wd: %p", + pdo, irp_sl->major_fn, irp_sl->minor_fn, wd); + switch (irp_sl->minor_fn) { + case IRP_MN_WAIT_WAKE: + /* TODO: this is not complete/correct */ + TRACE2("state: %d, completion: %p", + irp_sl->params.power.state.system_state, + irp_sl->completion_routine); + IoMarkIrpPending(irp); + status = STATUS_PENDING; + break; + case IRP_MN_SET_POWER: + power_state = irp_sl->params.power.state; + if (power_state.device_state == PowerDeviceD0) { + TRACE2("resuming %p", wd); + if (wrap_is_pci_bus(wd->dev_bus)) { + pdev = wd->pci.pdev; + pci_restore_state(pdev); + if (wd->pci.wake_state == PowerDeviceD3) { + pci_enable_wake(wd->pci.pdev, + PCI_D3hot, 0); + pci_enable_wake(wd->pci.pdev, + PCI_D3cold, 0); + } + pci_set_power_state(pdev, PCI_D0); + } else { // usb device +#ifdef ENABLE_USB + wrap_resume_urbs(wd); +#endif + } + } else { + TRACE2("suspending device %p", wd); + if (wrap_is_pci_bus(wd->dev_bus)) { + pdev = wd->pci.pdev; + pci_save_state(pdev); + TRACE2("%d", wd->pci.wake_state); + if (wd->pci.wake_state == PowerDeviceD3) { + pci_enable_wake(wd->pci.pdev, + PCI_D3hot, 1); + pci_enable_wake(wd->pci.pdev, + PCI_D3cold, 1); + } + pci_set_power_state(pdev, PCI_D3hot); + } else { // usb device +#ifdef ENABLE_USB + wrap_suspend_urbs(wd); +#endif + } + } + status = STATUS_SUCCESS; + break; + case IRP_MN_QUERY_POWER: + status = STATUS_SUCCESS; + break; + default: + TRACE2("fn %d not implemented", irp_sl->minor_fn); + status = STATUS_SUCCESS; + break; + } + irp->io_status.status = status; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return status; +} +WIN_FUNC_DECL(pdoDispatchPower,2) + +static NTSTATUS pnp_set_device_power_state(struct wrap_device *wd, + enum device_power_state state) +{ + NTSTATUS status; + struct device_object *pdo; + struct io_stack_location irp_sl; + + pdo = wd->pdo; + IOTRACE("%p, %p", pdo, IoGetAttachedDevice(pdo)); + memset(&irp_sl, 0, sizeof(irp_sl)); + irp_sl.params.power.state.device_state = state; + irp_sl.params.power.type = DevicePowerState; + if (state > PowerDeviceD0) { + status = IoSendIrpTopDev(pdo, IRP_MJ_POWER, IRP_MN_QUERY_POWER, + &irp_sl); + if (status != STATUS_SUCCESS) { + TRACE1("query of power to %d returns %08X", + state, status); + EXIT1(return status); + } + } + status = IoSendIrpTopDev(pdo, IRP_MJ_POWER, IRP_MN_SET_POWER, &irp_sl); + if (status != STATUS_SUCCESS) + WARNING("setting power to %d failed: %08X", state, status); + EXIT1(return status); +} + +NTSTATUS pnp_start_device(struct wrap_device *wd) +{ + struct device_object *fdo; + struct device_object *pdo; + struct io_stack_location irp_sl; + NTSTATUS status; + + pdo = wd->pdo; + /* TODO: for now we use same resources for both translated + * resources and raw resources */ + memset(&irp_sl, 0, sizeof(irp_sl)); + irp_sl.params.start_device.allocated_resources = + wd->resource_list; + irp_sl.params.start_device.allocated_resources_translated = + wd->resource_list; + status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_START_DEVICE, &irp_sl); + fdo = IoGetAttachedDevice(pdo); + if (status == STATUS_SUCCESS) + fdo->drv_obj->drv_ext->count++; + else + WARNING("Windows driver couldn't initialize the device (%08X)", + status); + EXIT1(return status); +} + +NTSTATUS pnp_stop_device(struct wrap_device *wd) +{ + struct device_object *pdo; + NTSTATUS status; + + pdo = wd->pdo; + status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_QUERY_STOP_DEVICE, + NULL); + if (status != STATUS_SUCCESS) + WARNING("status: %08X", status); + /* for now we ignore query status */ + status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_STOP_DEVICE, NULL); + if (status != STATUS_SUCCESS) + WARNING("status: %08X", status); + if (status != STATUS_SUCCESS) + WARNING("status: %08X", status); + EXIT2(return status); +} + +NTSTATUS pnp_remove_device(struct wrap_device *wd) +{ + struct device_object *pdo, *fdo; + struct driver_object *fdo_drv_obj; + NTSTATUS status; + + pdo = wd->pdo; + fdo = IoGetAttachedDevice(pdo); + fdo_drv_obj = fdo->drv_obj; + TRACE2("%p, %p, %p", pdo, fdo, fdo_drv_obj); + status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_QUERY_REMOVE_DEVICE, + NULL); + if (status != STATUS_SUCCESS) + WARNING("status: %08X", status); + + status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_REMOVE_DEVICE, NULL); + if (status != STATUS_SUCCESS) + WARNING("status: %08X", status); + /* TODO: should we use count in drv_ext or driver's Object + * header reference count to keep count of devices associated + * with a driver? */ + if (status == STATUS_SUCCESS) + fdo_drv_obj->drv_ext->count--; + TRACE1("count: %d", fdo_drv_obj->drv_ext->count); + if (fdo_drv_obj->drv_ext->count < 0) + WARNING("wrong count: %d", fdo_drv_obj->drv_ext->count); + if (fdo_drv_obj->drv_ext->count == 0) { + struct wrap_driver *wrap_driver; + TRACE1("unloading driver: %p", fdo_drv_obj); + wrap_driver = + IoGetDriverObjectExtension(fdo_drv_obj, + (void *)WRAP_DRIVER_CLIENT_ID); + if (fdo_drv_obj->unload) + LIN2WIN1(fdo_drv_obj->unload, fdo_drv_obj); + if (wrap_driver) { + if (down_interruptible(&loader_mutex)) + WARNING("couldn't obtain loader_mutex"); + unload_wrap_driver(wrap_driver); + up(&loader_mutex); + } else + ERROR("couldn't get wrap_driver"); + ObDereferenceObject(fdo_drv_obj); + } + IoDeleteDevice(pdo); + unload_wrap_device(wd); + EXIT1(return status); +} + +WIN_FUNC_DECL(IoInvalidDeviceRequest,2) + +static struct device_object *alloc_pdo(struct driver_object *drv_obj) +{ + struct device_object *pdo; + NTSTATUS status ; + int i; + struct ansi_string ansi_name; + struct unicode_string unicode_name; + + RtlInitAnsiString(&ansi_name, "NDISpdo"); + if (RtlAnsiStringToUnicodeString(&unicode_name, &ansi_name, TRUE) == + STATUS_SUCCESS) { + status = IoCreateDevice(drv_obj, 0, &unicode_name, + FILE_DEVICE_UNKNOWN, + FILE_AUTOGENERATED_DEVICE_NAME, + FALSE, &pdo); + RtlFreeUnicodeString(&unicode_name); + } else { + status = IoCreateDevice(drv_obj, 0, NULL, + FILE_DEVICE_UNKNOWN, + FILE_AUTOGENERATED_DEVICE_NAME, + FALSE, &pdo); + } + TRACE1("%p, %d, %p", drv_obj, status, pdo); + if (status != STATUS_SUCCESS) + return NULL; + /* dispatch routines are called as Windows functions */ + for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) + drv_obj->major_func[i] = WIN_FUNC_PTR(IoInvalidDeviceRequest,2); + drv_obj->major_func[IRP_MJ_INTERNAL_DEVICE_CONTROL] = + WIN_FUNC_PTR(pdoDispatchDeviceControl,2); + drv_obj->major_func[IRP_MJ_DEVICE_CONTROL] = + WIN_FUNC_PTR(pdoDispatchDeviceControl,2); + drv_obj->major_func[IRP_MJ_POWER] = WIN_FUNC_PTR(pdoDispatchPower,2); + drv_obj->major_func[IRP_MJ_PNP] = WIN_FUNC_PTR(pdoDispatchPnp,2); + return pdo; +} + +static int wrap_pnp_start_device(struct wrap_device *wd) +{ + struct wrap_driver *driver; + struct device_object *pdo; + struct driver_object *pdo_drv_obj; + + ENTER1("wd: %p", wd); + + if (!((wrap_is_pci_bus(wd->dev_bus)) || + (wrap_is_usb_bus(wd->dev_bus)))) { + ERROR("bus type %d (%d) not supported", + WRAP_BUS(wd->dev_bus), wd->dev_bus); + EXIT1(return -EINVAL); + } + driver = load_wrap_driver(wd); + if (!driver) + return -ENODEV; + + wd->driver = driver; + wd->dev_bus = WRAP_DEVICE_BUS(driver->dev_type, WRAP_BUS(wd->dev_bus)); + TRACE1("dev type: %d, bus type: %d, %d", WRAP_DEVICE(wd->dev_bus), + WRAP_BUS(wd->dev_bus), wd->dev_bus); + TRACE1("%d, %d", driver->dev_type, wrap_is_usb_bus(wd->dev_bus)); + /* first create pdo */ + if (wrap_is_pci_bus(wd->dev_bus)) + pdo_drv_obj = find_bus_driver("PCI"); + else // if (wrap_is_usb_bus(wd->dev_bus)) + pdo_drv_obj = find_bus_driver("USB"); + if (!pdo_drv_obj) + return -EINVAL; + pdo = alloc_pdo(pdo_drv_obj); + if (!pdo) + return -ENOMEM; + wd->pdo = pdo; + pdo->reserved = wd; + if (WRAP_DEVICE(wd->dev_bus) == WRAP_NDIS_DEVICE) { + if (init_ndis_driver(driver->drv_obj)) { + IoDeleteDevice(pdo); + return -EINVAL; + } + } + TRACE1("%p", driver->drv_obj->drv_ext->add_device); + if (driver->drv_obj->drv_ext->add_device(driver->drv_obj, pdo) != + STATUS_SUCCESS) { + IoDeleteDevice(pdo); + return -ENOMEM; + } + if (pnp_start_device(wd) != STATUS_SUCCESS) { + /* TODO: we need proper cleanup, to deallocate memory, + * for example */ + pnp_remove_device(wd); + return -EINVAL; + } + return 0; +} + +/* + * This function should not be marked __devinit because PCI IDs are + * added dynamically. + */ +int wrap_pnp_start_pci_device(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct load_device load_device; + struct wrap_device *wd; + + ENTER1("called for %04x:%04x:%04x:%04x", pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device); + + load_device.bus = WRAP_PCI_BUS; + load_device.vendor = pdev->vendor; + load_device.device = pdev->device; + load_device.subvendor = pdev->subsystem_vendor; + load_device.subdevice = pdev->subsystem_device; + wd = load_wrap_device(&load_device); + if (!wd) + EXIT1(return -ENODEV); + wd->pci.pdev = pdev; + return wrap_pnp_start_device(wd); +} + +void wrap_pnp_remove_pci_device(struct pci_dev *pdev) +{ + struct wrap_device *wd; + + wd = (struct wrap_device *)pci_get_drvdata(pdev); + ENTER1("%p, %p", pdev, wd); + if (!wd) + EXIT1(return); + pnp_remove_device(wd); +} + +int wrap_pnp_suspend_pci_device(struct pci_dev *pdev, pm_message_t state) +{ + struct wrap_device *wd; + + wd = (struct wrap_device *)pci_get_drvdata(pdev); + return pnp_set_device_power_state(wd, PowerDeviceD3); +} + +int wrap_pnp_resume_pci_device(struct pci_dev *pdev) +{ + struct wrap_device *wd; + + wd = (struct wrap_device *)pci_get_drvdata(pdev); + return pnp_set_device_power_state(wd, PowerDeviceD0); +} + +#ifdef ENABLE_USB +int wrap_pnp_start_usb_device(struct usb_interface *intf, + const struct usb_device_id *usb_id) +{ + struct wrap_device *wd; + int ret; + struct usb_device *udev = interface_to_usbdev(intf); + ENTER1("%04x, %04x, %04x", udev->descriptor.idVendor, + udev->descriptor.idProduct, udev->descriptor.bDeviceClass); + + /* USB device (e.g., RNDIS) may have multiple interfaces; + initialize one interface only (is there a way to know which + of these interfaces is for network?) */ + + if ((wd = get_wrap_device(udev, WRAP_USB_BUS))) { + TRACE1("device already initialized: %p", wd); + usb_set_intfdata(intf, NULL); + ret = 0; + } else { + struct load_device load_device; + + load_device.bus = WRAP_USB_BUS; + load_device.vendor = le16_to_cpu(udev->descriptor.idVendor); + load_device.device = le16_to_cpu(udev->descriptor.idProduct); + load_device.subvendor = 0; + load_device.subdevice = 0; + wd = load_wrap_device(&load_device); + TRACE2("%p", wd); + if (wd) { + /* some devices (e.g., TI 4150, RNDIS) need + * full reset */ + ret = usb_reset_device(udev); + if (ret) + WARNING("reset failed: %d", ret); + usb_set_intfdata(intf, wd); + wd->usb.intf = intf; + wd->usb.udev = udev; + ret = wrap_pnp_start_device(wd); + } else + ret = -ENODEV; + } + + TRACE2("ret: %d", ret); + if (ret) + EXIT1(return ret); + else + return 0; +} + +void __devexit wrap_pnp_remove_usb_device(struct usb_interface *intf) +{ + struct wrap_device *wd; + + wd = (struct wrap_device *)usb_get_intfdata(intf); + TRACE1("%p, %p", intf, wd); + if (wd == NULL) + EXIT1(return); + usb_set_intfdata(intf, NULL); + wd->usb.intf = NULL; + pnp_remove_device(wd); +} + +int wrap_pnp_suspend_usb_device(struct usb_interface *intf, pm_message_t state) +{ + struct wrap_device *wd; + struct device_object *pdo; + + wd = usb_get_intfdata(intf); + ENTER1("%p, %p", intf, wd); + if (!wd) + EXIT1(return 0); + pdo = wd->pdo; + if (pnp_set_device_power_state(wd, PowerDeviceD3)) + return -1; + return 0; +} + +int wrap_pnp_resume_usb_device(struct usb_interface *intf) +{ + struct wrap_device *wd; + wd = usb_get_intfdata(intf); + ENTER1("%p, %p", intf, wd); + if (!wd) + EXIT1(return 0); + if (pnp_set_device_power_state(wd, PowerDeviceD0)) + return -1; + return 0; +} + +#endif // USB --- linux-2.6.27.orig/ubuntu/ndiswrapper/mkstubs.sh +++ linux-2.6.27/ubuntu/ndiswrapper/mkstubs.sh @@ -0,0 +1,12 @@ +#! /bin/sh + +for file in "$@"; do + echo + echo "# automatically generated from $file" + sed -n \ + -e 's/.*WIN_FUNC(\([^\,]\+\) *\, *\([0-9]\+\)).*/\ + win2lin(\1, \2)/p' \ + -e 's/.*WIN_FUNC_PTR(\([^\,]\+\) *\, *\([0-9]\+\)).*/\ + win2lin(\1, \2)/p' \ + $file | sed -e 's/[ \t ]\+//' | sort -u; \ +done --- linux-2.6.27.orig/ubuntu/ndiswrapper/rtl.c +++ linux-2.6.27/ubuntu/ndiswrapper/rtl.c @@ -0,0 +1,716 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "ntoskernel.h" +#include "rtl_exports.h" + +wstdcall SIZE_T WIN_FUNC(RtlCompareMemory,3) + (const void *a, const void *b, SIZE_T len) +{ + size_t i; + char *x, *y; + + x = (char *)a; + y = (char *)b; + /* MSDN says this should return number of bytes that compare as + * equal. This can be interpretted as either all bytes that are + * equal in 'len' bytes or that only until the bytes compare as + * not equal. Initially we had it the former way, but Realtek driver + * doesn't like it that way - it takes many attempts to associate + * with WPA. ReactOS returns the number of bytes that are equal + * upto when they compare as not equal. + * According to lords at #reactos, that is the way it should be + * and that msdn is wrong about it! + */ + for (i = 0; i < len && x[i] == y[i]; i++) + ; + return i; +} + +wstdcall void WIN_FUNC(RtlCopyMemory,3) + (void *dst, const void *src, SIZE_T length) +{ + memcpy(dst, src, length); +} + +wstdcall void WIN_FUNC(RtlZeroMemory,2) + (void *dst, SIZE_T length) +{ + memset(dst, 0, length); +} + +wstdcall void WIN_FUNC(RtlSecureZeroMemory,2) + (void *dst, SIZE_T length) +{ + memset(dst, 0, length); +} + +wstdcall void WIN_FUNC(RtlFillMemory,3) + (void *dest, SIZE_T length, UCHAR fill) +{ + memset(dest, fill, length); +} + +wstdcall void WIN_FUNC(RtlMoveMemory,3) + (void *dest, const void *src, SIZE_T length) +{ + memmove(dest, src, length); +} + +wstdcall LONG WIN_FUNC(RtlCompareString,3) + (const struct ansi_string *s1, const struct ansi_string *s2, + BOOLEAN case_insensitive) +{ + unsigned int len; + LONG ret = 0; + const char *p1, *p2; + + ENTER2(""); + len = min(s1->length, s2->length); + p1 = s1->buf; + p2 = s2->buf; + if (case_insensitive) + while (!ret && len--) + ret = toupper(*p1++) - toupper(*p2++); + else + while (!ret && len--) + ret = *p1++ - *p2++; + if (!ret) + ret = s1->length - s2->length; + EXIT2(return ret); +} + +wstdcall LONG WIN_FUNC(RtlCompareUnicodeString,3) + (const struct unicode_string *s1, const struct unicode_string *s2, + BOOLEAN case_insensitive) +{ + unsigned int len; + LONG ret = 0; + const wchar_t *p1, *p2; + + ENTER2(""); + + len = min(s1->length, s2->length) / sizeof(wchar_t); + p1 = s1->buf; + p2 = s2->buf; + if (case_insensitive) + while (!ret && len--) + ret = toupper((u8)*p1++) - toupper((u8)*p2++); + else + while (!ret && len--) + ret = (u8)*p1++ - (u8)*p2++; + if (!ret) + ret = s1->length - s2->length; + TRACE2("len: %d, ret: %d", len, ret); + EXIT2(return ret); +} + +wstdcall BOOLEAN WIN_FUNC(RtlEqualString,3) + (const struct ansi_string *s1, const struct ansi_string *s2, + BOOLEAN case_insensitive) +{ + ENTER1(""); + if (s1->length != s2->length) + return FALSE; + return !RtlCompareString(s1, s2, case_insensitive); +} + +wstdcall BOOLEAN WIN_FUNC(RtlEqualUnicodeString,3) + (const struct unicode_string *s1, const struct unicode_string *s2, + BOOLEAN case_insensitive) +{ + if (s1->length != s2->length) + return FALSE; + return !RtlCompareUnicodeString(s1, s2, case_insensitive); +} + +wstdcall void WIN_FUNC(RtlCopyUnicodeString,2) + (struct unicode_string *dst, struct unicode_string *src) +{ + ENTER1("%p, %p", dst, src); + if (src && src->buf && dst->buf) { + dst->length = min(src->length, dst->max_length); + memcpy(dst->buf, src->buf, dst->length); + if (dst->length < dst->max_length) + dst->buf[dst->length / sizeof(dst->buf[0])] = 0; + } else + dst->length = 0; + EXIT1(return); +} + +wstdcall void WIN_FUNC(RtlCopyString,2) + (struct ansi_string *dst, struct ansi_string *src) +{ + ENTER1("%p, %p", dst, src); + if (src && src->buf && dst->buf) { + dst->length = min(src->length, dst->max_length); + memcpy(dst->buf, src->buf, dst->length); + if (dst->length < dst->max_length) + dst->buf[dst->length] = 0; + } else + dst->length = 0; + EXIT1(return); +} + +wstdcall NTSTATUS WIN_FUNC(RtlAppendUnicodeToString,2) + (struct unicode_string *dst, wchar_t *src) +{ + if (src) { + int len; + for (len = 0; src[len]; len++) + ; + if (dst->length + (len * sizeof(dst->buf[0])) > dst->max_length) + return STATUS_BUFFER_TOO_SMALL; + memcpy(&dst->buf[dst->length], src, len * sizeof(dst->buf[0])); + dst->length += len * sizeof(dst->buf[0]); + if (dst->max_length > dst->length) + dst->buf[dst->length / sizeof(dst->buf[0])] = 0; + } + return STATUS_SUCCESS; +} + +wstdcall NTSTATUS WIN_FUNC(RtlAppendUnicodeStringToString,2) + (struct unicode_string *dst, struct unicode_string *src) +{ + if (dst->max_length < src->length + dst->length) + return STATUS_BUFFER_TOO_SMALL; + if (src->length) { + memcpy(&dst->buf[dst->length], src->buf, src->length); + dst->length += src->length; + if (dst->max_length > dst->length) + dst->buf[dst->length / sizeof(dst->buf[0])] = 0; + } + EXIT2(return STATUS_SUCCESS); +} + +wstdcall ULONG WIN_FUNC(RtlxAnsiStringToUnicodeSize,1) + (const struct ansi_string *string) +{ + int i; + + for (i = 0; i < string->max_length && string->buf[i]; i++) + ; + return (i * sizeof(wchar_t)); +} + +wstdcall ULONG WIN_FUNC(RtlxUnicodeStringToAnsiSize,1) + (const struct unicode_string *string) +{ + int i; + + for (i = 0; i < string->max_length && string->buf[i]; i++) + ; + return i; +} + +wstdcall NTSTATUS WIN_FUNC(RtlAnsiStringToUnicodeString,3) + (struct unicode_string *dst, const struct ansi_string *src, + BOOLEAN alloc) +{ + int i, n; + + n = RtlxAnsiStringToUnicodeSize(src); + TRACE2("%d, %d, %d, %d, %p", n, dst->max_length, src->length, + src->max_length, src->buf); + if (alloc == TRUE) { +#if 0 + if (n == 0) { + dst->length = dst->max_length = 0; + dst->buf = NULL; + EXIT2(return STATUS_SUCCESS); + } +#endif + dst->max_length = n + sizeof(dst->buf[0]); + dst->buf = ExAllocatePoolWithTag(NonPagedPool, + dst->max_length, 0); + if (!dst->buf) { + dst->max_length = dst->length = 0; + EXIT2(return STATUS_NO_MEMORY); + } + } else if (dst->max_length < n) + EXIT2(return STATUS_BUFFER_TOO_SMALL); + + dst->length = n; + n /= sizeof(dst->buf[0]); + for (i = 0; i < n; i++) + dst->buf[i] = src->buf[i]; + if (i * sizeof(dst->buf[0]) < dst->max_length) + dst->buf[i] = 0; + TRACE2("dst: length: %d, max_length: %d, string: %p", + dst->length, dst->max_length, src->buf); + EXIT2(return STATUS_SUCCESS); +} + +wstdcall NTSTATUS WIN_FUNC(RtlUnicodeStringToAnsiString,3) + (struct ansi_string *dst, const struct unicode_string *src, + BOOLEAN alloc) +{ + int i, n; + + n = RtlxUnicodeStringToAnsiSize(src); + TRACE2("%d, %d, %d, %d, %p", n, dst->max_length, src->length, + src->max_length, src->buf); + if (alloc == TRUE) { +#if 0 + if (n == 0) { + dst->length = dst->max_length = 0; + dst->buf = NULL; + EXIT2(return STATUS_SUCCESS); + } +#endif + dst->max_length = n + sizeof(dst->buf[0]); + dst->buf = ExAllocatePoolWithTag(NonPagedPool, + dst->max_length, 0); + if (!dst->buf) { + dst->max_length = dst->length = 0; + EXIT1(return STATUS_NO_MEMORY); + } + } else if (dst->max_length < n) + EXIT2(return STATUS_BUFFER_TOO_SMALL); + + dst->length = n; + for (i = 0; i < n; i++) + dst->buf[i] = src->buf[i]; + if (i < dst->max_length) + dst->buf[i] = 0; + TRACE2("string: %p, len: %d(%d)", dst->buf, dst->length, + dst->max_length); + EXIT2(return STATUS_SUCCESS); +} + +wstdcall NTSTATUS WIN_FUNC(RtlUnicodeStringToInteger,3) + (struct unicode_string *ustring, ULONG base, ULONG *value) +{ + int i, sign = 1; + ULONG res; + typeof(ustring->buf) string; + + if (ustring->length == 0) { + *value = 0; + return STATUS_SUCCESS; + } + + string = ustring->buf; + i = 0; + while (i < (ustring->length / sizeof(*string)) && string[i] == ' ') + i++; + if (string[i] == '+') + i++; + else if (string[i] == '-') { + i++; + sign = -1; + } + if (base == 0) { + base = 10; + if (i <= ((ustring->length / sizeof(*string)) - 2) && + string[i] == '0') { + i++; + if (string[i] == 'b') { + base = 2; + i++; + } else if (string[i] == 'o') { + base = 8; + i++; + } else if (string[i] == 'x') { + base = 16; + i++; + } + } + } + if (!(base == 2 || base == 8 || base == 10 || base == 16)) + EXIT2(return STATUS_INVALID_PARAMETER); + + for (res = 0; i < (ustring->length / sizeof(*string)); i++) { + int v; + if (isdigit((char)string[i])) + v = string[i] - '0'; + else if (isxdigit((char)string[i])) + v = tolower((char)string[i]) - 'a' + 10; + else + v = base; + if (v >= base) + EXIT2(return STATUS_INVALID_PARAMETER); + res = res * base + v; + } + *value = sign * res; + EXIT3(return STATUS_SUCCESS); +} + +wstdcall NTSTATUS WIN_FUNC(RtlCharToInteger,3) + (const char *string, ULONG base, ULONG *value) +{ + int sign = 1; + ULONG res; + + if (!string || !value) + EXIT2(return STATUS_INVALID_PARAMETER); + while (*string == ' ') + string++; + if (*string == '+') + string++; + else if (*string == '-') { + string++; + sign = -1; + } + if (base == 0) { + base = 10; + if (*string == '0') { + string++; + if (*string == 'b') { + base = 2; + string++; + } else if (*string == 'o') { + base = 8; + string++; + } else if (*string == 'x') { + base = 16; + string++; + } + } + } + if (!(base == 2 || base == 8 || base == 10 || base == 16)) + EXIT2(return STATUS_INVALID_PARAMETER); + + for (res = 0; *string; string++) { + int v; + if (isdigit(*string)) + v = *string - '0'; + else if (isxdigit(*string)) + v = tolower(*string) - 'a' + 10; + else + v = base; + if (v >= base) + EXIT2(return STATUS_INVALID_PARAMETER); + res = res * base + v; + } + *value = sign * res; + EXIT3(return STATUS_SUCCESS); +} + +wstdcall NTSTATUS WIN_FUNC(RtlIntegerToUnicodeString,3) + (ULONG value, ULONG base, struct unicode_string *ustring) +{ + typeof(ustring->buf) buf = ustring->buf; + int i; + + if (base == 0) + base = 10; + if (!(base == 2 || base == 8 || base == 10 || base == 16)) + return STATUS_INVALID_PARAMETER; + for (i = 0; value && i < ustring->max_length / sizeof(*buf); i++) { + int r; + r = value % base; + value /= base; + if (r < 10) + buf[i] = r + '0'; + else + buf[i] = r + 'a' - 10; + } + if (value) + return STATUS_BUFFER_OVERFLOW; + ustring->length = i * sizeof(*buf); + return STATUS_SUCCESS; +} + +wstdcall LARGE_INTEGER WIN_FUNC(RtlConvertUlongToLargeInteger,1) + (ULONG ul) +{ + LARGE_INTEGER li = ul; + return li; +} + +wfastcall USHORT WIN_FUNC(RtlUshortByteSwap,1) + (USHORT src) +{ + return __swab16(src); +} + +wfastcall ULONG WIN_FUNC(RtlUlongByteSwap,1) + (ULONG src) +{ + /* ULONG is 32 bits for both 32-bit and 64-bit architectures */ + return __swab32(src); +} + +wstdcall NTSTATUS WIN_FUNC(RtlUpcaseUnicodeString,3) + (struct unicode_string *dst, struct unicode_string *src, BOOLEAN alloc) +{ + USHORT i, n; + + if (alloc) { + dst->buf = ExAllocatePoolWithTag(NonPagedPool, src->length, 0); + if (dst->buf) { + dst->max_length = src->length; + } else + EXIT2(return STATUS_NO_MEMORY); + } else { + if (dst->max_length < src->length) + EXIT2(return STATUS_BUFFER_OVERFLOW); + } + + n = src->length / sizeof(src->buf[0]); + for (i = 0; i < n; i++) + dst->buf[i] = toupper(src->buf[i]); + + dst->length = src->length; + EXIT3(return STATUS_SUCCESS); +} + +wstdcall void WIN_FUNC(RtlInitUnicodeString,2) + (struct unicode_string *dst, const wchar_t *src) +{ + ENTER2("%p", dst); + if (dst == NULL) + EXIT1(return); + if (src == NULL) { + dst->max_length = dst->length = 0; + dst->buf = NULL; + } else { + int i; + for (i = 0; (char)src[i]; i++) + ; + dst->buf = (typeof(dst->buf))src; + dst->length = i * sizeof(dst->buf[0]); + dst->max_length = (i + 1) * sizeof(dst->buf[0]); + } + EXIT1(return); +} + +wstdcall void WIN_FUNC(RtlInitAnsiString,2) + (struct ansi_string *dst, const char *src) +{ + ENTER2("%p", dst); + if (dst == NULL) + EXIT2(return); + if (src == NULL) { + dst->max_length = dst->length = 0; + dst->buf = NULL; + } else { + int i; + for (i = 0; src[i]; i++) + ; + dst->buf = (typeof(dst->buf))src; + dst->length = i; + dst->max_length = i + 1; + } + TRACE2("%p", dst->buf); + EXIT2(return); +} + +wstdcall void WIN_FUNC(RtlInitString,2) + (struct ansi_string *dst, const char *src) +{ + ENTER2("%p", dst); + RtlInitAnsiString(dst, src); + EXIT2(return); +} + +wstdcall void WIN_FUNC(RtlFreeUnicodeString,1) + (struct unicode_string *string) +{ + ENTER2("%p", string); + if (string == NULL) + return; + if (string->buf) + ExFreePool(string->buf); + string->length = string->max_length = 0; + string->buf = NULL; + return; +} + +wstdcall void WIN_FUNC(RtlFreeAnsiString,1) + (struct ansi_string *string) +{ + ENTER2("%p", string); + if (string == NULL) + return; + if (string->buf) + ExFreePool(string->buf); + string->length = string->max_length = 0; + string->buf = NULL; + return; +} + +/* guid string is of the form: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */ +wstdcall NTSTATUS WIN_FUNC(RtlGUIDFromString,2) + (struct unicode_string *guid_string, struct guid *guid) +{ + struct ansi_string ansi; + NTSTATUS ret; + int i, j, k, l, m; + + ret = RtlUnicodeStringToAnsiString(&ansi, guid_string, TRUE); + if (ret != STATUS_SUCCESS) + return ret; + if (ansi.length != 37 || ansi.buf[0] != '{' || + ansi.buf[36] != '}' || ansi.buf[9] != '-' || + ansi.buf[14] != '-' || ansi.buf[19] != '-' || + ansi.buf[24] != '-') { + RtlFreeAnsiString(&ansi); + EXIT2(return STATUS_INVALID_PARAMETER); + } + memcpy(&guid->data4, &ansi.buf[29], sizeof(guid->data3)); + /* set end of data3 for scanf */ + ansi.buf[29] = 0; + if (sscanf(&ansi.buf[1], "%x", &i) == 1 && + sscanf(&ansi.buf[10], "%x", &j) == 1 && + sscanf(&ansi.buf[15], "%x", &k) == 1 && + sscanf(&ansi.buf[20], "%x", &l) == 1 && + sscanf(&ansi.buf[25], "%x", &m) == 1) { + guid->data1 = (i << 16) | (j < 8) | k; + guid->data2 = l; + guid->data3 = m; + ret = STATUS_SUCCESS; + } else + ret = STATUS_INVALID_PARAMETER; + RtlFreeAnsiString(&ansi); + return ret; +} + +wstdcall NTSTATUS WIN_FUNC(RtlQueryRegistryValues,5) + (ULONG relative, wchar_t *path, struct rtl_query_registry_table *tbl, + void *context, void *env) +{ + struct ansi_string ansi; + struct unicode_string unicode; + NTSTATUS status, ret; + static int i = 0; + + ENTER3("%x, %p", relative, tbl); +// TODO(); + + RtlInitUnicodeString(&unicode, path); + if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) == + STATUS_SUCCESS) { + TRACE2("%s", ansi.buf); + RtlFreeAnsiString(&ansi); + } + ret = STATUS_SUCCESS; + for (; tbl->name; tbl++) { + RtlInitUnicodeString(&unicode, tbl->name); + if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) == + STATUS_SUCCESS) { + TRACE2("name: %s", ansi.buf); + RtlFreeAnsiString(&ansi); + } + TRACE2("flags: %08X", tbl->flags); + if (tbl->flags == RTL_QUERY_REGISTRY_DIRECT) { + TRACE2("type: %08X", tbl->def_type); + if (tbl->def_type == REG_DWORD) { + /* Atheros USB driver needs this, but + * don't know where and how to get its + * value */ + if (tbl->def_data) { + TRACE2("def_data: %x", + *(int *)tbl->def_data); + *(DWORD *)tbl->context = 0x5f292a + i++; +// *(DWORD *)tbl->def_data; + } else + *(DWORD *)tbl->context = 0x2345dbe; + } + } else { + void *data; + ULONG type, length; + + if (!tbl->query_func) { + ERROR("oops: no query_func"); + ret = STATUS_INVALID_PARAMETER; + break; + } + if (tbl->flags & RTL_QUERY_REGISTRY_NOVALUE) { + data = NULL; + type = REG_NONE; + length = 0; + } else { + data = tbl->def_data; + type = tbl->def_type; + length = tbl->def_length;; + } + TRACE2("calling query_func: %p", tbl->query_func); + status = LIN2WIN6(tbl->query_func, tbl->name, type, + data, length, context, env); + TRACE2("status: %08X", status); + if (status) { + if (status == STATUS_BUFFER_TOO_SMALL) + ret = STATUS_BUFFER_TOO_SMALL; + else + EXIT2(return STATUS_INVALID_PARAMETER); + } + } + } + EXIT3(return ret); +} + +wstdcall NTSTATUS WIN_FUNC(RtlWriteRegistryValue,6) + (ULONG relative, wchar_t *path, wchar_t *name, ULONG type, + void *data, ULONG length) +{ + struct ansi_string ansi; + struct unicode_string unicode; + + ENTER3("%d", relative); + TODO(); + + RtlInitUnicodeString(&unicode, path); + if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) == + STATUS_SUCCESS) { + TRACE2("%s", ansi.buf); + RtlFreeAnsiString(&ansi); + } + RtlInitUnicodeString(&unicode, name); + if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) == + STATUS_SUCCESS) { + TRACE2("%s", ansi.buf); + RtlFreeAnsiString(&ansi); + } + EXIT5(return STATUS_SUCCESS); +} + +wstdcall NTSTATUS WIN_FUNC(RtlDeleteRegistryValue,3) + (ULONG relative, wchar_t *path, wchar_t *name) +{ + return STATUS_SUCCESS; +} + +wstdcall void WIN_FUNC(RtlAssert,4) + (char *failed_assertion, char *file_name, ULONG line_num, char *message) +{ + ERROR("assertion '%s' failed at %s line %d%s", + failed_assertion, file_name, line_num, message ? message : ""); + return; +} + +wstdcall void WIN_FUNC(RtlUnwind,0) + (void) +{ + TODO(); +} + +wstdcall void WIN_FUNC(RtlRaiseException,1) + (void *exception_record) +{ + TODO(); +} + +int rtl_init(void) +{ + return 0; +} + +/* called when module is being removed */ +void rtl_exit(void) +{ + EXIT4(return); +} --- linux-2.6.27.orig/ubuntu/ndiswrapper/pe_linker.c +++ linux-2.6.27/ubuntu/ndiswrapper/pe_linker.c @@ -0,0 +1,609 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifdef TEST_LOADER + +#include "usr_linker.h" + +#else + +#include +#include + +//#define DEBUGLINKER 2 + +#include "ntoskernel.h" + +#endif + +struct pe_exports { + char *dll; + char *name; + generic_func addr; +}; + +static struct pe_exports pe_exports[40]; +static int num_pe_exports; + +#define RVA2VA(image, rva, type) (type)(ULONG_PTR)((void *)image + rva) +#define CHECK_SZ(a,b) { if (sizeof(a) != b) { \ + ERROR("%s is bad, got %zd, expected %d", \ + #a , sizeof(a), (b)); return -EINVAL; } } + +#if defined(DEBUGLINKER) && DEBUGLINKER > 0 +#define DBGLINKER(fmt, ...) printk(KERN_INFO "%s (%s:%d): " fmt "\n", \ + DRIVER_NAME, __FUNCTION__, \ + __LINE__ , ## __VA_ARGS__); +static const char *image_directory_name[] = { + "EXPORT", + "IMPORT", + "RESOURCE", + "EXCEPTION", + "SECURITY", + "BASERELOC", + "DEBUG", + "COPYRIGHT", + "GLOBALPTR", + "TLS", + "LOAD_CONFIG", + "BOUND_IMPORT", + "IAT", + "DELAY_IMPORT", + "COM_DESCRIPTOR" }; +#else +#define DBGLINKER(fmt, ...) do { } while (0) +#endif + +#ifndef TEST_LOADER +extern struct wrap_export ntoskernel_exports[], ntoskernel_io_exports[], + ndis_exports[], crt_exports[], hal_exports[], rtl_exports[]; +#ifdef ENABLE_USB +extern struct wrap_export usb_exports[]; +#endif + +static char *get_export(char *name) +{ + int i; + + for (i = 0 ; ntoskernel_exports[i].name != NULL; i++) + if (strcmp(ntoskernel_exports[i].name, name) == 0) + return (char *)ntoskernel_exports[i].func; + + for (i = 0 ; ntoskernel_io_exports[i].name != NULL; i++) + if (strcmp(ntoskernel_io_exports[i].name, name) == 0) + return (char *)ntoskernel_io_exports[i].func; + + for (i = 0 ; ndis_exports[i].name != NULL; i++) + if (strcmp(ndis_exports[i].name, name) == 0) + return (char *)ndis_exports[i].func; + + for (i = 0 ; crt_exports[i].name != NULL; i++) + if (strcmp(crt_exports[i].name, name) == 0) + return (char *)crt_exports[i].func; + + for (i = 0 ; hal_exports[i].name != NULL; i++) + if (strcmp(hal_exports[i].name, name) == 0) + return (char *)hal_exports[i].func; + + for (i = 0 ; rtl_exports[i].name != NULL; i++) + if (strcmp(rtl_exports[i].name, name) == 0) + return (char *)rtl_exports[i].func; + +#ifdef ENABLE_USB + for (i = 0 ; usb_exports[i].name != NULL; i++) + if (strcmp(usb_exports[i].name, name) == 0) + return (char *)usb_exports[i].func; +#endif + + for (i = 0; i < num_pe_exports; i++) + if (strcmp(pe_exports[i].name, name) == 0) + return (char *)pe_exports[i].addr; + + return NULL; +} +#endif // TEST_LOADER + +static void *get_dll_init(char *name) +{ + int i; + for (i = 0; i < num_pe_exports; i++) + if ((strcmp(pe_exports[i].dll, name) == 0) && + (strcmp(pe_exports[i].name, "DllInitialize") == 0)) + return (void *)pe_exports[i].addr; + return NULL; +} + +/* + * Find and validate the coff header + * + */ +static int check_nt_hdr(IMAGE_NT_HEADERS *nt_hdr) +{ + int i; + WORD attr; + PIMAGE_OPTIONAL_HEADER opt_hdr; + + /* Validate the "PE\0\0" signature */ + if (nt_hdr->Signature != IMAGE_NT_SIGNATURE) { + ERROR("is this driver file? bad signature %08x", + nt_hdr->Signature); + return -EINVAL; + } + + opt_hdr = &nt_hdr->OptionalHeader; + /* Make sure Image is PE32 or PE32+ */ +#ifdef CONFIG_X86_64 + if (opt_hdr->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + ERROR("kernel is 64-bit, but Windows driver is not 64-bit;" + "bad magic: %04X", opt_hdr->Magic); + return -EINVAL; + } +#else + if (opt_hdr->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + ERROR("kernel is 32-bit, but Windows driver is not 32-bit;" + "bad magic: %04X", opt_hdr->Magic); + return -EINVAL; + } +#endif + + /* Validate the image for the current architecture. */ +#ifdef CONFIG_X86_64 + if (nt_hdr->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) { + ERROR("kernel is 64-bit, but Windows driver is not 64-bit;" + " (PE signature is %04X)", nt_hdr->FileHeader.Machine); + return -EINVAL; + } +#else + if (nt_hdr->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) { + ERROR("kernel is 32-bit, but Windows driver is not 32-bit;" + " (PE signature is %04X)", nt_hdr->FileHeader.Machine); + return -EINVAL; + } +#endif + + /* Must have attributes */ +#ifdef CONFIG_X86_64 + attr = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE; +#else + attr = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE; +#endif + if ((nt_hdr->FileHeader.Characteristics & attr) != attr) + return -EINVAL; + + /* Must be relocatable */ + attr = IMAGE_FILE_RELOCS_STRIPPED; + if ((nt_hdr->FileHeader.Characteristics & attr)) + return -EINVAL; + + /* Make sure we have at least one section */ + if (nt_hdr->FileHeader.NumberOfSections == 0) + return -EINVAL; + + if (opt_hdr->SectionAlignment < opt_hdr->FileAlignment) { + ERROR("alignment mismatch: secion: 0x%x, file: 0x%x", + opt_hdr->SectionAlignment, opt_hdr->FileAlignment); + return -EINVAL; + } + + DBGLINKER("number of datadictionary entries %d", + opt_hdr->NumberOfRvaAndSizes); + for (i = 0; i < opt_hdr->NumberOfRvaAndSizes; i++) { + DBGLINKER("datadirectory %s RVA:%X Size:%d", + (i<=IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)? + image_directory_name[i] : "unknown", + opt_hdr->DataDirectory[i].VirtualAddress, + opt_hdr->DataDirectory[i].Size); + } + + if ((nt_hdr->FileHeader.Characteristics & IMAGE_FILE_DLL)) + return IMAGE_FILE_DLL; + if ((nt_hdr->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) + return IMAGE_FILE_EXECUTABLE_IMAGE; + return -EINVAL; +} + +static int import(void *image, IMAGE_IMPORT_DESCRIPTOR *dirent, char *dll) +{ + ULONG_PTR *lookup_tbl, *address_tbl; + char *symname = NULL; + int i; + int ret = 0; + void *adr; + + lookup_tbl = RVA2VA(image, dirent->u.OriginalFirstThunk, ULONG_PTR *); + address_tbl = RVA2VA(image, dirent->FirstThunk, ULONG_PTR *); + + for (i = 0; lookup_tbl[i]; i++) { + if (IMAGE_SNAP_BY_ORDINAL(lookup_tbl[i])) { + ERROR("ordinal import not supported: %Lu", + (uint64_t)lookup_tbl[i]); + return -1; + } + else { + symname = RVA2VA(image, + ((lookup_tbl[i] & + ~IMAGE_ORDINAL_FLAG) + 2), char *); + } + + adr = get_export(symname); + if (adr == NULL) { + ERROR("unknown symbol: %s:'%s'", dll, symname); + ret = -1; + } else { + DBGLINKER("found symbol: %s:%s: addr: %p, rva = %Lu", + dll, symname, adr, (uint64_t)address_tbl[i]); + address_tbl[i] = (ULONG_PTR)adr; + } + } + return ret; +} + +static int read_exports(struct pe_image *pe) +{ + IMAGE_EXPORT_DIRECTORY *export_dir_table; + uint32_t *export_addr_table; + int i; + uint32_t *name_table; + PIMAGE_OPTIONAL_HEADER opt_hdr; + IMAGE_DATA_DIRECTORY *export_data_dir; + + opt_hdr = &pe->nt_hdr->OptionalHeader; + export_data_dir = + &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; + + if (export_data_dir->Size == 0) { + DBGLINKER("no exports"); + return 0; + } + + export_dir_table = + RVA2VA(pe->image, export_data_dir->VirtualAddress, + IMAGE_EXPORT_DIRECTORY *); + + name_table = (unsigned int *)(pe->image + + export_dir_table->AddressOfNames); + export_addr_table = (uint32_t *) + (pe->image + export_dir_table->AddressOfFunctions); + + for (i = 0; i < export_dir_table->NumberOfNames; i++) { + + if (export_data_dir->VirtualAddress <= *export_addr_table || + *export_addr_table >= (export_data_dir->VirtualAddress + + export_data_dir->Size)) + DBGLINKER("forwarder rva"); + + DBGLINKER("export symbol: %s, at %p", + (char *)(pe->image + *name_table), + pe->image + *export_addr_table); + + pe_exports[num_pe_exports].dll = pe->name; + pe_exports[num_pe_exports].name = pe->image + *name_table; + pe_exports[num_pe_exports].addr = + pe->image + *export_addr_table; + + num_pe_exports++; + name_table++; + export_addr_table++; + } + return 0; +} + +static int fixup_imports(void *image, IMAGE_NT_HEADERS *nt_hdr) +{ + int i; + char *name; + int ret = 0; + IMAGE_IMPORT_DESCRIPTOR *dirent; + IMAGE_DATA_DIRECTORY *import_data_dir; + PIMAGE_OPTIONAL_HEADER opt_hdr; + + opt_hdr = &nt_hdr->OptionalHeader; + import_data_dir = + &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; + dirent = RVA2VA(image, import_data_dir->VirtualAddress, + IMAGE_IMPORT_DESCRIPTOR *); + + for (i = 0; dirent[i].Name; i++) { + name = RVA2VA(image, dirent[i].Name, char*); + + DBGLINKER("imports from dll: %s", name); + ret += import(image, &dirent[i], name); + } + return ret; +} + +static int fixup_reloc(void *image, IMAGE_NT_HEADERS *nt_hdr) +{ + ULONG_PTR base; + ULONG_PTR size; + IMAGE_BASE_RELOCATION *fixup_block; + IMAGE_DATA_DIRECTORY *base_reloc_data_dir; + PIMAGE_OPTIONAL_HEADER opt_hdr; + + opt_hdr = &nt_hdr->OptionalHeader; + base = opt_hdr->ImageBase; + base_reloc_data_dir = + &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; + if (base_reloc_data_dir->Size == 0) + return 0; + + fixup_block = RVA2VA(image, base_reloc_data_dir->VirtualAddress, + IMAGE_BASE_RELOCATION *); + DBGLINKER("fixup_block=%p, image=%p", fixup_block, image); + DBGLINKER("fixup_block info: %x %d", + fixup_block->VirtualAddress, fixup_block->SizeOfBlock); + + while (fixup_block->SizeOfBlock) { + int i; + WORD fixup, offset; + + size = (fixup_block->SizeOfBlock - + sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); + DBGLINKER("found %Lu relocations in this block", + (uint64_t)size); + + for (i = 0; i < size; i++) { + fixup = fixup_block->TypeOffset[i]; + offset = fixup & 0xfff; + switch ((fixup >> 12) & 0x0f) { + case IMAGE_REL_BASED_ABSOLUTE: + break; + + case IMAGE_REL_BASED_HIGHLOW: { + uint32_t addr; + uint32_t *loc = + RVA2VA(image, + fixup_block->VirtualAddress + + offset, uint32_t *); + addr = RVA2VA(image, (*loc - base), uint32_t); + DBGLINKER("relocation: *%p (Val:%X)= %X", + loc, *loc, addr); + *loc = addr; + } + break; + + case IMAGE_REL_BASED_DIR64: { + uint64_t addr; + uint64_t *loc = + RVA2VA(image, + fixup_block->VirtualAddress + + offset, uint64_t *); + addr = RVA2VA(image, (*loc - base), uint64_t); + DBGLINKER("relocation: *%p (Val:%llX)= %llx", + loc, *loc, addr); + *loc = addr; + } + break; + + default: + ERROR("unknown fixup: %08X", + (fixup >> 12) & 0x0f); + return -EOPNOTSUPP; + break; + } + } + DBGLINKER("finished relocating block"); + + fixup_block = (IMAGE_BASE_RELOCATION *) + ((void *)fixup_block + fixup_block->SizeOfBlock); + }; + DBGLINKER("done relocating all"); + + return 0; +} + +/* Expand the image in memroy if necessary. The image on disk does not + * necessarily maps the image of the driver in memory, so we have to + * re-write it in order to fullfill the sections alignements. The + * advantage to do that is that rva_to_va becomes a simple + * addition. */ +static int fix_pe_image(struct pe_image *pe) +{ + void *image; + IMAGE_SECTION_HEADER *sect_hdr; + int i, sections; + int image_size; + + if (pe->size == pe->opt_hdr->SizeOfImage) { + /* Nothing to do */ + return 0; + } + + image_size = pe->opt_hdr->SizeOfImage; +#ifdef CONFIG_X86_64 +#ifdef PAGE_KERNEL_EXECUTABLE + image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM, + PAGE_KERNEL_EXECUTABLE); +#elif defined PAGE_KERNEL_EXEC + image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM, + PAGE_KERNEL_EXEC); +#else +#error x86_64 should have either PAGE_KERNEL_EXECUTABLE or PAGE_KERNEL_EXEC +#endif +#else +#ifdef cpu_has_nx + /* hate to play with kernel macros, but PAGE_KERNEL_EXEC is + * not available to modules! */ + if (cpu_has_nx) + image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM, + __pgprot(__PAGE_KERNEL & ~_PAGE_NX)); + else + image = vmalloc(image_size); +#else + image = vmalloc(image_size); +#endif +#endif + if (image == NULL) { + ERROR("failed to allocate enough space for new image:" + " %d bytes", image_size); + return -ENOMEM; + } + + /* Copy all the headers, ie everything before the first section. */ + + sections = pe->nt_hdr->FileHeader.NumberOfSections; + sect_hdr = IMAGE_FIRST_SECTION(pe->nt_hdr); + + DBGLINKER("copying headers: %u bytes", sect_hdr->PointerToRawData); + + memcpy(image, pe->image, sect_hdr->PointerToRawData); + + /* Copy all the sections */ + for (i = 0; i < sections; i++) { + DBGLINKER("Copy section %s from %x to %x", + sect_hdr->Name, sect_hdr->PointerToRawData, + sect_hdr->VirtualAddress); + if (sect_hdr->VirtualAddress+sect_hdr->SizeOfRawData > + image_size) { + ERROR("Invalid section %s in driver", sect_hdr->Name); + vfree(image); + return -EINVAL; + } + + memcpy(image+sect_hdr->VirtualAddress, + pe->image + sect_hdr->PointerToRawData, + sect_hdr->SizeOfRawData); + sect_hdr++; + } + + vfree(pe->image); + pe->image = image; + pe->size = image_size; + + /* Update our internal pointers */ + pe->nt_hdr = (IMAGE_NT_HEADERS *) + (pe->image + ((IMAGE_DOS_HEADER *)pe->image)->e_lfanew); + pe->opt_hdr = &pe->nt_hdr->OptionalHeader; + + DBGLINKER("set nt headers: nt_hdr=%p, opt_hdr=%p, image=%p", + pe->nt_hdr, pe->opt_hdr, pe->image); + + return 0; +} + +#if defined(CONFIG_X86_64) +static void fix_user_shared_data_addr(char *driver, unsigned long length) +{ + unsigned long i, n, max_addr, *addr; + + n = length - sizeof(unsigned long); + max_addr = KI_USER_SHARED_DATA + sizeof(kuser_shared_data); + for (i = 0; i < n; i++) { + addr = (unsigned long *)(driver + i); + if (*addr >= KI_USER_SHARED_DATA && *addr < max_addr) { + *addr -= KI_USER_SHARED_DATA; + *addr += (unsigned long)&kuser_shared_data; + kuser_shared_data.reserved1 = 1; + } + } +} +#endif + +int link_pe_images(struct pe_image *pe_image, unsigned short n) +{ + int i; + struct pe_image *pe; + +#ifdef DEBUG + /* Sanity checkings */ + CHECK_SZ(IMAGE_SECTION_HEADER, IMAGE_SIZEOF_SECTION_HEADER); + CHECK_SZ(IMAGE_FILE_HEADER, IMAGE_SIZEOF_FILE_HEADER); + CHECK_SZ(IMAGE_OPTIONAL_HEADER, IMAGE_SIZEOF_NT_OPTIONAL_HEADER); + CHECK_SZ(IMAGE_NT_HEADERS, 4 + IMAGE_SIZEOF_FILE_HEADER + + IMAGE_SIZEOF_NT_OPTIONAL_HEADER); + CHECK_SZ(IMAGE_DOS_HEADER, 0x40); + CHECK_SZ(IMAGE_EXPORT_DIRECTORY, 40); + CHECK_SZ(IMAGE_BASE_RELOCATION, 8); + CHECK_SZ(IMAGE_IMPORT_DESCRIPTOR, 20); +#endif + + for (i = 0; i < n; i++) { + IMAGE_DOS_HEADER *dos_hdr; + pe = &pe_image[i]; + dos_hdr = pe->image; + + if (pe->size < sizeof(IMAGE_DOS_HEADER)) { + TRACE1("image too small: %d", pe->size); + return -EINVAL; + } + + pe->nt_hdr = + (IMAGE_NT_HEADERS *)(pe->image + dos_hdr->e_lfanew); + pe->opt_hdr = &pe->nt_hdr->OptionalHeader; + + pe->type = check_nt_hdr(pe->nt_hdr); + if (pe->type <= 0) { + TRACE1("type <= 0"); + return -EINVAL; + } + + if (fix_pe_image(pe)) { + TRACE1("bad PE image"); + return -EINVAL; + } + + if (read_exports(pe)) { + TRACE1("read exports failed"); + return -EINVAL; + } + } + + for (i = 0; i < n; i++) { + pe = &pe_image[i]; + + if (fixup_reloc(pe->image, pe->nt_hdr)) { + TRACE1("fixup reloc failed"); + return -EINVAL; + } + if (fixup_imports(pe->image, pe->nt_hdr)) { + TRACE1("fixup imports failed"); + return -EINVAL; + } +#if defined(CONFIG_X86_64) + INFO("fixing KI_USER_SHARED_DATA address in the driver"); + fix_user_shared_data_addr(pe_image[i].image, pe_image[i].size); +#endif + flush_icache_range(pe->image, pe->size); + + pe->entry = + RVA2VA(pe->image, + pe->opt_hdr->AddressOfEntryPoint, void *); + TRACE1("entry is at %p, rva at %08X", pe->entry, + pe->opt_hdr->AddressOfEntryPoint); + } + + for (i = 0; i < n; i++) { + pe = &pe_image[i]; + + if (pe->type == IMAGE_FILE_DLL) { + struct unicode_string ustring; + char *buf = "0/0t0m0p00"; + int (*dll_entry)(struct unicode_string *ustring) + wstdcall; + + memset(&ustring, 0, sizeof(ustring)); + ustring.buf = (wchar_t *)buf; + dll_entry = (void *)get_dll_init(pe->name); + + TRACE1("calling dll_init at %p", dll_entry); + if (!dll_entry || dll_entry(&ustring)) + ERROR("DLL initialize failed for %s", + pe->name); + } + else if (pe->type != IMAGE_FILE_EXECUTABLE_IMAGE) + ERROR("illegal image type: %d", pe->type); + } + return 0; +} --- linux-2.6.27.orig/ubuntu/ndiswrapper/crt.c +++ linux-2.6.27/ubuntu/ndiswrapper/crt.c @@ -0,0 +1,578 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "ntoskernel.h" +#include "crt_exports.h" + +#ifdef CONFIG_X86_64 +/* Windows long is 32-bit, so strip single 'l' in integer formats */ +static void strip_l_modifier(char *str) +{ + char *ptr = str; + int in_format = 0; + char *lptr = NULL; + char last = 0; + char *end_ptr; + char *wptr; + + /* Replace single 'l' inside integer formats with '\0' */ + for (ptr = str; *ptr; ptr++) { + if (!in_format) { + if (*ptr == '%') + in_format = 1; + last = *ptr; + continue; + } + switch (*ptr) { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + case 'p': + case 'n': + case 'm': + if (lptr) { + *lptr = '\0'; + lptr = NULL; + } + in_format = 0; + break; + case 'c': + case 'C': + case 's': + case 'S': + case 'f': + case 'e': + case 'E': + case 'g': + case 'G': + case 'a': + case 'A': + lptr = NULL; + in_format = 0; + break; + case '%': + lptr = NULL; + if (last == '%') + in_format = 0; + else + in_format = 1; /* ignore previous junk */ + break; + case 'l': + if (last == 'l') + lptr = NULL; + else + lptr = ptr; + break; + default: + break; + } + last = *ptr; + } + + /* Purge zeroes from the resulting string */ + end_ptr = ptr; + wptr = str; + for (ptr = str; ptr < end_ptr; ptr++) + if (*ptr != 0) + *(wptr++) = *ptr; + *wptr = 0; +} + +/* + * va_list on x86_64 Linux is designed to allow passing arguments in registers + * even to variadic functions. va_list is a structure holding pointers to the + * register save area, which holds the arguments passed in registers, and to + * the stack, which may have the arguments that did not fit the registers. + * va_list also holds offsets in the register save area for the next general + * purpose and floating point registers that the next va_arg() would fetch. + * + * Unlike Linux, the Windows va_list is just a pointer to the stack. No + * arguments are passed in the registers. That's why we construct the Linux + * va_list so that the register save area is never used. For that goal, we set + * the offsets to the maximal allowed values, meaning that the arguments passed + * in the registers have been exhausted. The values are 48 for general purpose + * registers (6 registers, 8 bytes each) and 304 for floating point registers + * (16 registers, 16 bytes each, on top of general purpose register). + */ + +struct x86_64_va_list { + int gp_offset; + int fp_offset; + void *overflow_arg_area; + void *reg_save_area; +}; + +#define VA_LIST_DECL(_args) \ + va_list _args##new; \ + struct x86_64_va_list *_args##x; +#define VA_LIST_PREP(_args) \ +do { \ + _args##x = (struct x86_64_va_list *)&_args##new; \ + _args##x->gp_offset = 6 * 8; /* GP registers exhausted */ \ + _args##x->fp_offset = 6 * 8 + 16 * 16; /* FP registers exhausted */ \ + _args##x->overflow_arg_area = (void *)_args; \ + _args##x->reg_save_area = NULL; \ +} while (0) +#define VA_LIST_CONV(_args) (_args##new) +#define VA_LIST_FREE(_args) +#define FMT_DECL(_fmt) \ + char *_fmt##copy; \ + int _fmt##len; +#define FMT_PREP(_fmt) \ +do { \ + _fmt##len = strlen(format) + 1; \ + _fmt##copy = kmalloc(_fmt##len, GFP_KERNEL); \ + if (_fmt##copy) { \ + memcpy(_fmt##copy, format, _fmt##len); \ + strip_l_modifier(_fmt##copy); \ + } \ +} while (0) +#define FMT_CONV(_fmt) (_fmt##copy ? _fmt##copy : format) +#define FMT_FREE(_fmt) kfree(_fmt##copy) + +#else /* !CONFIG_X86_64 */ + +#define VA_LIST_DECL(_args) +#define VA_LIST_PREP(_args) +#define VA_LIST_CONV(_args) (_args) +#define VA_LIST_FREE(_args) +#define FMT_DECL(_fmt) +#define FMT_PREP(_fmt) +#define FMT_CONV(_fmt) (format) +#define FMT_FREE(_fmt) + +#endif /* !CONFIG_X86_64 */ + +noregparm INT WIN_FUNC(_win_sprintf,12) + (char *buf, const char *format, ...) +{ + va_list args; + int res; + FMT_DECL(format) + + FMT_PREP(format); + va_start(args, format); + res = vsprintf(buf, FMT_CONV(format), args); + va_end(args); + FMT_FREE(format); + + TRACE2("buf: %p: %s", buf, buf); + return res; +} + +noregparm INT WIN_FUNC(swprintf,12) + (wchar_t *buf, const wchar_t *format, ...) +{ + TODO(); + EXIT2(return 0); +} + +noregparm INT WIN_FUNC(_win_vsprintf,3) + (char *str, const char *format, va_list ap) +{ + INT i; + VA_LIST_DECL(ap) + FMT_DECL(format) + + VA_LIST_PREP(ap); + FMT_PREP(format); + + i = vsprintf(str, FMT_CONV(format), VA_LIST_CONV(ap)); + TRACE2("str: %p: %s", str, str); + + FMT_FREE(format); + VA_LIST_FREE(ap); + EXIT2(return i); +} + +noregparm INT WIN_FUNC(_win_snprintf,12) + (char *buf, SIZE_T count, const char *format, ...) +{ + va_list args; + int res; + FMT_DECL(format) + + FMT_PREP(format); + va_start(args, format); + res = vsnprintf(buf, count, FMT_CONV(format), args); + va_end(args); + TRACE2("buf: %p: %s", buf, buf); + + FMT_FREE(format); + return res; +} + +noregparm INT WIN_FUNC(_win__snprintf,12) + (char *buf, SIZE_T count, const char *format, ...) +{ + va_list args; + int res; + FMT_DECL(format) + + FMT_PREP(format); + va_start(args, format); + res = vsnprintf(buf, count, FMT_CONV(format), args); + va_end(args); + TRACE2("buf: %p: %s", buf, buf); + + FMT_FREE(format); + return res; +} + +noregparm INT WIN_FUNC(_win_vsnprintf,4) + (char *str, SIZE_T size, const char *format, va_list ap) +{ + INT i; + VA_LIST_DECL(ap) + FMT_DECL(format) + + VA_LIST_PREP(ap); + FMT_PREP(format); + + i = vsnprintf(str, size, FMT_CONV(format), VA_LIST_CONV(ap)); + TRACE2("str: %p: %s", str, str); + + FMT_FREE(format); + VA_LIST_FREE(ap); + EXIT2(return i); +} + +noregparm INT WIN_FUNC(_win__vsnprintf,4) + (char *str, SIZE_T size, const char *format, va_list ap) +{ + INT i; + VA_LIST_DECL(ap) + FMT_DECL(format) + + VA_LIST_PREP(ap); + FMT_PREP(format); + + i = vsnprintf(str, size, FMT_CONV(format), VA_LIST_CONV(ap)); + TRACE2("str: %p: %s", str, str); + + FMT_FREE(format); + VA_LIST_FREE(ap); + EXIT2(return i); +} + +noregparm char *WIN_FUNC(_win_strncpy,3) + (char *dst, char *src, SIZE_T n) +{ + return strncpy(dst, src, n); +} + +noregparm SIZE_T WIN_FUNC(_win_strlen,1) + (const char *s) +{ + return strlen(s); +} + +noregparm INT WIN_FUNC(_win_strncmp,3) + (const char *s1, const char *s2, SIZE_T n) +{ + return strncmp(s1, s2, n); +} + +noregparm INT WIN_FUNC(_win_strcmp,2) + (const char *s1, const char *s2) +{ + return strcmp(s1, s2); +} + +noregparm INT WIN_FUNC(_win_stricmp,2) + (const char *s1, const char *s2) +{ + return stricmp(s1, s2); +} + +noregparm char *WIN_FUNC(_win_strncat,3) + (char *dest, const char *src, SIZE_T n) +{ + return strncat(dest, src, n); +} + +noregparm INT WIN_FUNC(_win_wcscmp,2) + (const wchar_t *s1, const wchar_t *s2) +{ + while (*s1 && *s1 == *s2) { + s1++; + s2++; + } + return *s1 - *s2; +} + +noregparm INT WIN_FUNC(_win_wcsicmp,2) + (const wchar_t *s1, const wchar_t *s2) +{ + while (*s1 && tolower((char)*s1) == tolower((char)*s2)) { + s1++; + s2++; + } + return tolower((char)*s1) - tolower((char)*s2); +} + +noregparm SIZE_T WIN_FUNC(_win_wcslen,1) + (const wchar_t *s) +{ + const wchar_t *t = s; + while (*t) + t++; + return t - s; +} + +noregparm wchar_t *WIN_FUNC(_win_wcsncpy,3) + (wchar_t *dest, const wchar_t *src, SIZE_T n) +{ + const wchar_t *s; + wchar_t *d; + s = src + n; + d = dest; + while (src < s && (*d++ = *src++)) + ; + if (s > src) + memset(d, 0, (s - src) * sizeof(wchar_t)); + return dest; +} + +noregparm wchar_t *WIN_FUNC(_win_wcscpy,2) + (wchar_t *dest, const wchar_t *src) +{ + wchar_t *d = dest; + while ((*d++ = *src++)) + ; + return dest; +} + +noregparm wchar_t *WIN_FUNC(_win_wcscat,2) + (wchar_t *dest, const wchar_t *src) +{ + wchar_t *d; + d = dest; + while (*d) + d++; + while ((*d++ = *src++)) + ; + return dest; +} + +noregparm INT WIN_FUNC(_win_towupper,1) + (wchar_t c) +{ + return toupper(c); +} + +noregparm INT WIN_FUNC(_win_towlower,1) + (wchar_t c) +{ + return tolower(c); +} + +noregparm INT WIN_FUNC(_win_tolower,1) + (INT c) +{ + return tolower(c); +} + +noregparm INT WIN_FUNC(_win_toupper,1) + (INT c) +{ + return toupper(c); +} + +noregparm void *WIN_FUNC(_win_strcpy,2) + (void *to, const void *from) +{ + return strcpy(to, from); +} + +noregparm char *WIN_FUNC(_win_strstr,2) + (const char *s1, const char *s2) +{ + return strstr(s1, s2); +} + +noregparm char *WIN_FUNC(_win_strchr,2) + (const char *s, int c) +{ + return strchr(s, c); +} + +noregparm char *WIN_FUNC(_win_strrchr,2) + (const char *s, int c) +{ + return strrchr(s, c); +} + +noregparm void *WIN_FUNC(_win_memmove,3) + (void *to, void *from, SIZE_T count) +{ + return memmove(to, from, count); +} + +noregparm void *WIN_FUNC(_win_memchr,3) + (const void *s, INT c, SIZE_T n) +{ + return memchr(s, c, n); +} + +noregparm void *WIN_FUNC(_win_memcpy,3) + (void *to, const void *from, SIZE_T n) +{ + return memcpy(to, from, n); +} + +noregparm void *WIN_FUNC(_win_memset,3) + (void *s, char c, SIZE_T count) +{ + return memset(s, c, count); +} + +noregparm int WIN_FUNC(_win_memcmp,3) + (void *s1, void *s2, SIZE_T n) +{ + return memcmp(s1, s2, n); +} + +noregparm void WIN_FUNC(_win_srand,1) + (UINT seed) +{ + net_srandom(seed); +} + +noregparm int WIN_FUNC(rand,0) + (void) +{ + char buf[6]; + int i, n; + + get_random_bytes(buf, sizeof(buf)); + for (n = i = 0; i < sizeof(buf) ; i++) + n += buf[i]; + return n; +} + +noregparm int WIN_FUNC(_win_atoi,1) + (const char *ptr) +{ + int i = simple_strtol(ptr, NULL, 10); + return i; +} + +noregparm int WIN_FUNC(_win_isprint,1) + (int c) +{ + return isprint(c); +} + +wstdcall s64 WIN_FUNC(_alldiv,2) + (s64 a, s64 b) +{ + return (a / b); +} + +wstdcall u64 WIN_FUNC(_aulldiv,2) + (u64 a, u64 b) +{ + return (a / b); +} + +wstdcall s64 WIN_FUNC(_allmul,2) + (s64 a, s64 b) +{ + return (a * b); +} + +wstdcall u64 WIN_FUNC(_aullmul,2) + (u64 a, u64 b) +{ + return (a * b); +} + +wstdcall s64 WIN_FUNC(_allrem,2) + (s64 a, s64 b) +{ + return (a % b); +} + +wstdcall u64 WIN_FUNC(_aullrem,2) + (u64 a, u64 b) +{ + return (a % b); +} + +__attribute__((regparm(3))) s64 WIN_FUNC(_allshl,2) + (s64 a, u8 b) +{ + return (a << b); +} + +__attribute__((regparm(3))) u64 WIN_FUNC(_aullshl,2) + (u64 a, u8 b) +{ + return (a << b); +} + +__attribute__((regparm(3))) s64 WIN_FUNC(_allshr,2) + (s64 a, u8 b) +{ + return (a >> b); +} + +__attribute__((regparm(3))) u64 WIN_FUNC(_aullshr,2) + (u64 a, u8 b) +{ + return (a >> b); +} + +int stricmp(const char *s1, const char *s2) +{ + while (*s1 && tolower(*s1) == tolower(*s2)) { + s1++; + s2++; + } + return *s1 - *s2; +} + +void dump_bytes(const char *ctx, const u8 *from, int len) +{ + int i, j; + u8 *buf; + + buf = kmalloc(len * 3 + 1, irql_gfp()); + if (!buf) { + ERROR("couldn't allocate memory"); + return; + } + for (i = j = 0; i < len; i++, j += 3) { + sprintf(&buf[j], "%02x ", from[i]); + } + buf[j] = 0; + printk(KERN_DEBUG "%s: %p: %s\n", ctx, from, buf); + kfree(buf); +} + +int crt_init(void) +{ + return 0; +} + +/* called when module is being removed */ +void crt_exit(void) +{ + EXIT4(return); +} --- linux-2.6.27.orig/ubuntu/ndiswrapper/wrapndis.c +++ linux-2.6.27/ubuntu/ndiswrapper/wrapndis.c @@ -0,0 +1,2085 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "ndis.h" +#include "iw_ndis.h" +#include "pnp.h" +#include "loader.h" +#include "wrapndis.h" +#include +#include +#include +#include +#include +#include "wrapper.h" + +/* Functions callable from the NDIS driver */ +wstdcall NTSTATUS NdisDispatchDeviceControl(struct device_object *fdo, + struct irp *irp); +wstdcall NTSTATUS NdisDispatchPnp(struct device_object *fdo, struct irp *irp); +wstdcall NTSTATUS NdisDispatchPower(struct device_object *fdo, struct irp *irp); + +workqueue_struct_t *wrapndis_wq; +static struct nt_thread *wrapndis_worker_thread; + +static int set_packet_filter(struct ndis_device *wnd, + ULONG packet_filter); +static void add_iw_stats_timer(struct ndis_device *wnd); +static void del_iw_stats_timer(struct ndis_device *wnd); +static NDIS_STATUS ndis_start_device(struct ndis_device *wnd); +static int ndis_remove_device(struct ndis_device *wnd); +static void set_multicast_list(struct ndis_device *wnd); +static int ndis_net_dev_open(struct net_device *net_dev); +static int ndis_net_dev_close(struct net_device *net_dev); + +/* MiniportReset */ +NDIS_STATUS mp_reset(struct ndis_device *wnd) +{ + NDIS_STATUS res; + struct miniport *mp; + BOOLEAN reset_address; + KIRQL irql; + + ENTER2("wnd: %p", wnd); + if (down_interruptible(&wnd->tx_ring_mutex)) + EXIT3(return NDIS_STATUS_FAILURE); + if (down_interruptible(&wnd->ndis_req_mutex)) { + up(&wnd->tx_ring_mutex); + EXIT3(return NDIS_STATUS_FAILURE); + } + mp = &wnd->wd->driver->ndis_driver->mp; + prepare_wait_condition(wnd->ndis_req_task, wnd->ndis_req_done, 0); + WARNING("%s is being reset", wnd->net_dev->name); + irql = serialize_lock_irql(wnd); + assert_irql(_irql_ == DISPATCH_LEVEL); + res = LIN2WIN2(mp->reset, &reset_address, wnd->nmb->mp_ctx); + serialize_unlock_irql(wnd, irql); + + TRACE2("%08X, %08X", res, reset_address); + if (res == NDIS_STATUS_PENDING) { + /* wait for NdisMResetComplete */ + if (wait_condition((wnd->ndis_req_done > 0), 0, + TASK_INTERRUPTIBLE) < 0) + res = NDIS_STATUS_FAILURE; + else { + res = wnd->ndis_req_status; + reset_address = wnd->ndis_req_done - 1; + } + TRACE2("%08X, %08X", res, reset_address); + } + up(&wnd->ndis_req_mutex); + if (res == NDIS_STATUS_SUCCESS && reset_address) { + set_packet_filter(wnd, wnd->packet_filter); + set_multicast_list(wnd); + } + up(&wnd->tx_ring_mutex); + EXIT3(return res); +} + +/* MiniportRequest(Query/Set)Information */ +NDIS_STATUS mp_request(enum ndis_request_type request, + struct ndis_device *wnd, ndis_oid oid, + void *buf, ULONG buflen, ULONG *written, ULONG *needed) +{ + NDIS_STATUS res; + ULONG w, n; + struct miniport *mp; + KIRQL irql; + + if (down_interruptible(&wnd->ndis_req_mutex)) + EXIT3(return NDIS_STATUS_FAILURE); + if (!written) + written = &w; + if (!needed) + needed = &n; + mp = &wnd->wd->driver->ndis_driver->mp; + prepare_wait_condition(wnd->ndis_req_task, wnd->ndis_req_done, 0); + irql = serialize_lock_irql(wnd); + assert_irql(_irql_ == DISPATCH_LEVEL); + switch (request) { + case NdisRequestQueryInformation: + TRACE2("%p, %08X, %p", mp->queryinfo, oid, wnd->nmb->mp_ctx); + res = LIN2WIN6(mp->queryinfo, wnd->nmb->mp_ctx, oid, buf, + buflen, written, needed); + break; + case NdisRequestSetInformation: + TRACE2("%p, %08X, %p", mp->setinfo, oid, wnd->nmb->mp_ctx); + res = LIN2WIN6(mp->setinfo, wnd->nmb->mp_ctx, oid, buf, + buflen, written, needed); + break; + default: + WARNING("invalid request %d, %08X", request, oid); + res = NDIS_STATUS_NOT_SUPPORTED; + break; + } + serialize_unlock_irql(wnd, irql); + TRACE2("%08X, %08X", res, oid); + if (res == NDIS_STATUS_PENDING) { + /* wait for NdisMQueryInformationComplete */ + if (wait_condition((wnd->ndis_req_done > 0), 0, + TASK_INTERRUPTIBLE) < 0) + res = NDIS_STATUS_FAILURE; + else + res = wnd->ndis_req_status; + TRACE2("%08X, %08X", res, oid); + } + up(&wnd->ndis_req_mutex); + DBG_BLOCK(2) { + if (res || needed) + TRACE2("%08X, %d, %d, %d", res, buflen, *written, + *needed); + } + EXIT3(return res); +} + +/* MiniportPnPEventNotify */ +static NDIS_STATUS mp_pnp_event(struct ndis_device *wnd, + enum ndis_device_pnp_event event, + ULONG power_profile) +{ + struct miniport *mp; + + ENTER1("%p, %d", wnd, event); + mp = &wnd->wd->driver->ndis_driver->mp; + if (!mp->pnp_event_notify) { + TRACE1("Windows driver %s doesn't support " + "MiniportPnpEventNotify", wnd->wd->driver->name); + return NDIS_STATUS_FAILURE; + } + /* RNDIS driver doesn't like to be notified if device is + * already halted */ + if (!test_bit(HW_INITIALIZED, &wnd->wd->hw_status)) + EXIT1(return NDIS_STATUS_SUCCESS); + switch (event) { + case NdisDevicePnPEventSurpriseRemoved: + TRACE1("%u, %p", + (wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK), + mp->pnp_event_notify); + if ((wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK) && + !test_bit(HW_PRESENT, &wnd->wd->hw_status) && + mp->pnp_event_notify) { + TRACE1("calling surprise_removed"); + LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx, + NdisDevicePnPEventSurpriseRemoved, NULL, 0); + } else + TRACE1("Windows driver %s doesn't support " + "MiniportPnpEventNotify for safe unplugging", + wnd->wd->driver->name); + return NDIS_STATUS_SUCCESS; + case NdisDevicePnPEventPowerProfileChanged: + if (power_profile) + power_profile = NdisPowerProfileAcOnLine; + LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx, + NdisDevicePnPEventPowerProfileChanged, + &power_profile, (ULONG)sizeof(power_profile)); + return NDIS_STATUS_SUCCESS; + default: + WARNING("event %d not yet implemented", event); + return NDIS_STATUS_SUCCESS; + } +} + +/* MiniportInitialize */ +static NDIS_STATUS mp_init(struct ndis_device *wnd) +{ + NDIS_STATUS error_status, status; + UINT medium_index; + enum ndis_medium medium_array[] = {NdisMedium802_3}; + struct miniport *mp; + + ENTER1("irql: %d", current_irql()); + if (test_bit(HW_INITIALIZED, &wnd->wd->hw_status)) { + WARNING("device %p already initialized!", wnd); + return NDIS_STATUS_FAILURE; + } + + if (!wnd->wd->driver->ndis_driver || + !wnd->wd->driver->ndis_driver->mp.init) { + WARNING("assuming WDM (non-NDIS) driver"); + EXIT1(return NDIS_STATUS_NOT_RECOGNIZED); + } + mp = &wnd->wd->driver->ndis_driver->mp; + status = LIN2WIN6(mp->init, &error_status, &medium_index, medium_array, + sizeof(medium_array) / sizeof(medium_array[0]), + wnd->nmb, wnd->nmb); + TRACE1("init returns: %08X, irql: %d", status, current_irql()); + if (status != NDIS_STATUS_SUCCESS) { + WARNING("couldn't initialize device: %08X", status); + EXIT1(return NDIS_STATUS_FAILURE); + } + + /* Wait a little to let card power up otherwise ifup might + * fail after boot */ + sleep_hz(HZ / 5); + status = mp_pnp_event(wnd, NdisDevicePnPEventPowerProfileChanged, + NdisPowerProfileAcOnLine); + if (status != NDIS_STATUS_SUCCESS) + TRACE1("setting power failed: %08X", status); + set_bit(HW_INITIALIZED, &wnd->wd->hw_status); + /* the description about NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND is + * misleading/confusing */ + status = mp_query(wnd, OID_PNP_CAPABILITIES, + &wnd->pnp_capa, sizeof(wnd->pnp_capa)); + if (status == NDIS_STATUS_SUCCESS) { + TRACE1("%d, %d", wnd->pnp_capa.wakeup.min_magic_packet_wakeup, + wnd->pnp_capa.wakeup.min_pattern_wakeup); + wnd->attributes |= NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND; + status = mp_query_int(wnd, OID_PNP_ENABLE_WAKE_UP, + &wnd->ndis_wolopts); + TRACE1("%08X, %x", status, wnd->ndis_wolopts); + } else if (status == NDIS_STATUS_NOT_SUPPORTED) + wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND; + TRACE1("%d", wnd->pnp_capa.wakeup.min_magic_packet_wakeup); + /* although some NDIS drivers support suspend, Linux kernel + * has issues with suspending USB devices */ + if (wrap_is_usb_bus(wnd->wd->dev_bus)) { + wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND; + wnd->ndis_wolopts = 0; + } + mp_set_int(wnd, OID_802_11_POWER_MODE, NDIS_POWER_OFF); + EXIT1(return NDIS_STATUS_SUCCESS); +} + +/* MiniportHalt */ +static void mp_halt(struct ndis_device *wnd) +{ + struct miniport *mp; + + ENTER1("%p", wnd); + if (!test_and_clear_bit(HW_INITIALIZED, &wnd->wd->hw_status)) { + WARNING("device %p is not initialized - not halting", wnd); + return; + } + hangcheck_del(wnd); + del_iw_stats_timer(wnd); + if (wnd->physical_medium == NdisPhysicalMediumWirelessLan && + wrap_is_pci_bus(wnd->wd->dev_bus)) { + up(&wnd->ndis_req_mutex); + disassociate(wnd, 0); + if (down_interruptible(&wnd->ndis_req_mutex)) + WARNING("couldn't obtain ndis_req_mutex"); + } + mp = &wnd->wd->driver->ndis_driver->mp; + TRACE1("halt: %p", mp->mp_halt); + LIN2WIN1(mp->mp_halt, wnd->nmb->mp_ctx); + /* if a driver doesn't call NdisMDeregisterInterrupt during + * halt, deregister it now */ + if (wnd->mp_interrupt) + NdisMDeregisterInterrupt(wnd->mp_interrupt); + /* cancel any timers left by bugyy windows driver; also free + * the memory for timers */ + while (1) { + struct nt_slist *slist; + struct wrap_timer *wrap_timer; + + spin_lock_bh(&ntoskernel_lock); + if ((slist = wnd->wrap_timer_slist.next)) + wnd->wrap_timer_slist.next = slist->next; + spin_unlock_bh(&ntoskernel_lock); + TIMERTRACE("%p", slist); + if (!slist) + break; + wrap_timer = container_of(slist, struct wrap_timer, slist); + wrap_timer->repeat = 0; + /* ktimer that this wrap_timer is associated to can't + * be touched, as it may have been freed by the driver + * already */ + if (del_timer_sync(&wrap_timer->timer)) + WARNING("Buggy Windows driver left timer %p " + "running", wrap_timer->nt_timer); + memset(wrap_timer, 0, sizeof(*wrap_timer)); + kfree(wrap_timer); + } + EXIT1(return); +} + +static NDIS_STATUS mp_set_power_state(struct ndis_device *wnd, + enum ndis_power_state state) +{ + NDIS_STATUS status; + + TRACE1("%d", state); + if (state == NdisDeviceStateD0) { + status = NDIS_STATUS_SUCCESS; + up(&wnd->ndis_req_mutex); + if (test_and_clear_bit(HW_HALTED, &wnd->wd->hw_status)) { + status = mp_init(wnd); + if (status == NDIS_STATUS_SUCCESS) { + set_packet_filter(wnd, wnd->packet_filter); + set_multicast_list(wnd); + } + } else if (test_and_clear_bit(HW_SUSPENDED, + &wnd->wd->hw_status)) { + status = mp_set_int(wnd, OID_PNP_SET_POWER, state); + if (status != NDIS_STATUS_SUCCESS) + WARNING("%s: setting power to state %d failed? " + "%08X", wnd->net_dev->name, state, + status); + } else + return NDIS_STATUS_FAILURE; + + if (wrap_is_pci_bus(wnd->wd->dev_bus)) { + pci_enable_wake(wnd->wd->pci.pdev, PCI_D3hot, 0); + pci_enable_wake(wnd->wd->pci.pdev, PCI_D3cold, 0); + } + if (status == NDIS_STATUS_SUCCESS) { + up(&wnd->tx_ring_mutex); + netif_device_attach(wnd->net_dev); + hangcheck_add(wnd); + add_iw_stats_timer(wnd); + } else + WARNING("%s: couldn't set power to state %d; device not" + " resumed", wnd->net_dev->name, state); + EXIT1(return status); + } else { + if (down_interruptible(&wnd->tx_ring_mutex)) + EXIT1(return NDIS_STATUS_FAILURE); + netif_device_detach(wnd->net_dev); + hangcheck_del(wnd); + del_iw_stats_timer(wnd); + status = NDIS_STATUS_NOT_SUPPORTED; + if (wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND) { + status = mp_set_int(wnd, OID_PNP_ENABLE_WAKE_UP, + wnd->ndis_wolopts); + TRACE2("0x%x, 0x%x", status, wnd->ndis_wolopts); + if (status == NDIS_STATUS_SUCCESS) { + if (wnd->ndis_wolopts) + wnd->wd->pci.wake_state = + PowerDeviceD3; + else + wnd->wd->pci.wake_state = + PowerDeviceUnspecified; + } else + WARNING("couldn't set wake-on-lan options: " + "0x%x, %08X", wnd->ndis_wolopts, status); + status = mp_set_int(wnd, OID_PNP_SET_POWER, state); + if (status == NDIS_STATUS_SUCCESS) + set_bit(HW_SUSPENDED, &wnd->wd->hw_status); + else + WARNING("suspend failed: %08X", status); + } + if (status != NDIS_STATUS_SUCCESS) { + WARNING("%s does not support power management; " + "halting the device", wnd->net_dev->name); + mp_halt(wnd); + set_bit(HW_HALTED, &wnd->wd->hw_status); + status = STATUS_SUCCESS; + } + if (down_interruptible(&wnd->ndis_req_mutex)) + WARNING("couldn't lock ndis_req_mutex"); + EXIT1(return status); + } +} + +static int ndis_set_mac_address(struct net_device *dev, void *p) +{ + struct ndis_device *wnd = netdev_priv(dev); + struct sockaddr *addr = p; + struct ndis_configuration_parameter param; + struct unicode_string key; + struct ansi_string ansi; + NDIS_STATUS res; + unsigned char mac_string[2 * ETH_ALEN + 1]; + mac_address mac; + + memcpy(mac, addr->sa_data, sizeof(mac)); + memset(mac_string, 0, sizeof(mac_string)); + res = snprintf(mac_string, sizeof(mac_string), MACSTR, MAC2STR(mac)); + if (res != (sizeof(mac_string) - 1)) + EXIT1(return -EINVAL); + TRACE1("new mac: %s", mac_string); + + RtlInitAnsiString(&ansi, mac_string); + if (RtlAnsiStringToUnicodeString(¶m.data.string, &ansi, + TRUE) != STATUS_SUCCESS) + EXIT1(return -EINVAL); + + param.type = NdisParameterString; + RtlInitAnsiString(&ansi, "NetworkAddress"); + if (RtlAnsiStringToUnicodeString(&key, &ansi, TRUE) != STATUS_SUCCESS) { + RtlFreeUnicodeString(¶m.data.string); + EXIT1(return -EINVAL); + } + NdisWriteConfiguration(&res, wnd->nmb, &key, ¶m); + RtlFreeUnicodeString(&key); + RtlFreeUnicodeString(¶m.data.string); + + if (res != NDIS_STATUS_SUCCESS) + EXIT1(return -EFAULT); + if (ndis_reinit(wnd) == NDIS_STATUS_SUCCESS) { + res = mp_query(wnd, OID_802_3_CURRENT_ADDRESS, + mac, sizeof(mac)); + if (res == NDIS_STATUS_SUCCESS) { + TRACE1("mac:" MACSTRSEP, MAC2STR(mac)); + memcpy(dev->dev_addr, mac, sizeof(mac)); + } else + ERROR("couldn't get mac address: %08X", res); + } + EXIT1(return 0); +} + +static int setup_tx_sg_list(struct ndis_device *wnd, struct sk_buff *skb, + struct ndis_packet_oob_data *oob_data) +{ + struct ndis_sg_element *sg_element; + struct ndis_sg_list *sg_list; + int i; + + ENTER3("%p, %d", skb, skb_shinfo(skb)->nr_frags); + if (skb_shinfo(skb)->nr_frags <= 1) { + sg_element = &oob_data->wrap_tx_sg_list.elements[0]; + sg_element->address = + PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); + sg_element->length = skb->len; + oob_data->wrap_tx_sg_list.nent = 1; + oob_data->ext.info[ScatterGatherListPacketInfo] = + &oob_data->wrap_tx_sg_list; + TRACE3("%Lx, %u", sg_element->address, sg_element->length); + return 0; + } + sg_list = kmalloc(sizeof(*sg_list) + + (skb_shinfo(skb)->nr_frags + 1) * sizeof(*sg_element), + GFP_ATOMIC); + if (!sg_list) + return -ENOMEM; + sg_list->nent = skb_shinfo(skb)->nr_frags + 1; + TRACE3("%p, %d", sg_list, sg_list->nent); + sg_element = sg_list->elements; + sg_element->length = skb_headlen(skb); + sg_element->address = + PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, skb->data, + skb_headlen(skb), PCI_DMA_TODEVICE); + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + sg_element++; + sg_element->length = frag->size; + sg_element->address = + pci_map_page(wnd->wd->pci.pdev, frag->page, + frag->page_offset, frag->size, + PCI_DMA_TODEVICE); + TRACE3("%Lx, %u", sg_element->address, sg_element->length); + } + oob_data->ext.info[ScatterGatherListPacketInfo] = sg_list; + return 0; +} + +static void free_tx_sg_list(struct ndis_device *wnd, + struct ndis_packet_oob_data *oob_data) +{ + int i; + struct ndis_sg_element *sg_element; + struct ndis_sg_list *sg_list = + oob_data->ext.info[ScatterGatherListPacketInfo]; + sg_element = sg_list->elements; + TRACE3("%p, %d", sg_list, sg_list->nent); + PCI_DMA_UNMAP_SINGLE(wnd->wd->pci.pdev, sg_element->address, + sg_element->length, PCI_DMA_TODEVICE); + if (sg_list->nent == 1) + EXIT3(return); + for (i = 1; i < sg_list->nent; i++, sg_element++) { + TRACE3("%Lx, %u", sg_element->address, sg_element->length); + pci_unmap_page(wnd->wd->pci.pdev, sg_element->address, + sg_element->length, PCI_DMA_TODEVICE); + } + TRACE3("%p", sg_list); + kfree(sg_list); +} + +static struct ndis_packet *alloc_tx_packet(struct ndis_device *wnd, + struct sk_buff *skb) +{ + struct ndis_packet *packet; + ndis_buffer *buffer; + struct ndis_packet_oob_data *oob_data; + NDIS_STATUS status; + + NdisAllocatePacket(&status, &packet, wnd->tx_packet_pool); + if (status != NDIS_STATUS_SUCCESS) + return NULL; + NdisAllocateBuffer(&status, &buffer, wnd->tx_buffer_pool, + skb->data, skb->len); + if (status != NDIS_STATUS_SUCCESS) { + NdisFreePacket(packet); + return NULL; + } + packet->private.buffer_head = buffer; + packet->private.buffer_tail = buffer; + + oob_data = NDIS_PACKET_OOB_DATA(packet); + oob_data->tx_skb = skb; + if (wnd->sg_dma_size) { + if (setup_tx_sg_list(wnd, skb, oob_data)) { + NdisFreeBuffer(buffer); + NdisFreePacket(packet); + return NULL; + } + } + if (skb->ip_summed == CHECKSUM_PARTIAL) { + struct ndis_tcp_ip_checksum_packet_info csum; + int protocol; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21) + protocol = ntohs(skb->protocol); +#else + protocol = skb->nh.iph->protocol; +#endif + csum.value = 0; + csum.tx.v4 = 1; + if (protocol == IPPROTO_TCP) + csum.tx.tcp = 1; + else if (protocol == IPPROTO_UDP) + csum.tx.udp = 1; +// csum->tx.ip = 1; + packet->private.flags |= NDIS_PROTOCOL_ID_TCP_IP; + oob_data->ext.info[TcpIpChecksumPacketInfo] = + (void *)(ULONG_PTR)csum.value; + } + DBG_BLOCK(4) { + dump_bytes(__FUNCTION__, skb->data, skb->len); + } + TRACE4("%p, %p, %p", packet, buffer, skb); + return packet; +} + +void free_tx_packet(struct ndis_device *wnd, struct ndis_packet *packet, + NDIS_STATUS status) +{ + ndis_buffer *buffer; + struct ndis_packet_oob_data *oob_data; + struct sk_buff *skb; + struct ndis_packet_pool *pool; + + assert_irql(_irql_ <= DISPATCH_LEVEL); + assert(packet->private.packet_flags); + oob_data = NDIS_PACKET_OOB_DATA(packet); + skb = oob_data->tx_skb; + buffer = packet->private.buffer_head; + TRACE4("%p, %p, %p, %08X", packet, buffer, skb, status); + if (status == NDIS_STATUS_SUCCESS) { + pre_atomic_add(wnd->net_stats.tx_bytes, packet->private.len); + atomic_inc_var(wnd->net_stats.tx_packets); + } else { + TRACE1("packet dropped: %08X", status); + atomic_inc_var(wnd->net_stats.tx_dropped); + } + if (wnd->sg_dma_size) + free_tx_sg_list(wnd, oob_data); + NdisFreeBuffer(buffer); + dev_kfree_skb_any(skb); + pool = packet->private.pool; + NdisFreePacket(packet); + if (netif_queue_stopped(wnd->net_dev) && + ((pool->max_descr - pool->num_used_descr) >= + (wnd->max_tx_packets / 4))) { + set_bit(NETIF_WAKEQ, &wnd->ndis_pending_work); + schedule_wrapndis_work(&wnd->ndis_work); + } + EXIT4(return); +} + +/* MiniportSend and MiniportSendPackets */ +/* this function is called holding tx_ring_mutex. start and n are such + * that start + n < TX_RING_SIZE; i.e., packets don't wrap around + * ring */ +static u8 mp_tx_packets(struct ndis_device *wnd, u8 start, u8 n) +{ + NDIS_STATUS res; + struct miniport *mp; + struct ndis_packet *packet; + u8 sent; + KIRQL irql; + + ENTER3("%d, %d", start, n); + mp = &wnd->wd->driver->ndis_driver->mp; + if (mp->send_packets) { + if (deserialized_driver(wnd)) { + LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx, + &wnd->tx_ring[start], n); + sent = n; + } else { + irql = serialize_lock_irql(wnd); + LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx, + &wnd->tx_ring[start], n); + serialize_unlock_irql(wnd, irql); + for (sent = 0; sent < n && wnd->tx_ok; sent++) { + struct ndis_packet_oob_data *oob_data; + packet = wnd->tx_ring[start + sent]; + oob_data = NDIS_PACKET_OOB_DATA(packet); + switch ((res = + xchg(&oob_data->status, + NDIS_STATUS_NOT_RECOGNIZED))) { + case NDIS_STATUS_SUCCESS: + free_tx_packet(wnd, packet, + NDIS_STATUS_SUCCESS); + break; + case NDIS_STATUS_PENDING: + break; + case NDIS_STATUS_RESOURCES: + wnd->tx_ok = 0; + /* resubmit this packet and + * the rest when resources + * become available */ + sent--; + break; + case NDIS_STATUS_FAILURE: + free_tx_packet(wnd, packet, + NDIS_STATUS_FAILURE); + break; + default: + ERROR("%p: invalid status: %08X", + packet, res); + free_tx_packet(wnd, packet, + oob_data->status); + break; + } + TRACE3("%p, %d", packet, res); + } + } + TRACE3("sent: %d(%d)", sent, n); + } else { + for (sent = 0; sent < n && wnd->tx_ok; sent++) { + struct ndis_packet_oob_data *oob_data; + packet = wnd->tx_ring[start + sent]; + oob_data = NDIS_PACKET_OOB_DATA(packet); + oob_data->status = NDIS_STATUS_NOT_RECOGNIZED; + irql = serialize_lock_irql(wnd); + res = LIN2WIN3(mp->send, wnd->nmb->mp_ctx, + packet, packet->private.flags); + serialize_unlock_irql(wnd, irql); + switch (res) { + case NDIS_STATUS_SUCCESS: + free_tx_packet(wnd, packet, res); + break; + case NDIS_STATUS_PENDING: + break; + case NDIS_STATUS_RESOURCES: + wnd->tx_ok = 0; + /* resend this packet when resources + * become available */ + sent--; + break; + case NDIS_STATUS_FAILURE: + free_tx_packet(wnd, packet, res); + break; + default: + ERROR("packet %p: invalid status: %08X", + packet, res); + break; + } + } + } + EXIT3(return sent); +} + +static void tx_worker(worker_param_t param) +{ + struct ndis_device *wnd; + s8 n; + + wnd = worker_param_data(param, struct ndis_device, tx_work); + ENTER3("tx_ok %d", wnd->tx_ok); + while (wnd->tx_ok) { + if (down_interruptible(&wnd->tx_ring_mutex)) + break; + spin_lock_bh(&wnd->tx_ring_lock); + n = wnd->tx_ring_end - wnd->tx_ring_start; + TRACE3("%d, %d, %d", wnd->tx_ring_start, wnd->tx_ring_end, n); + /* end == start if either ring is empty or full; in + * the latter case is_tx_ring_full is set */ + if (n == 0) { + if (wnd->is_tx_ring_full) + n = TX_RING_SIZE - wnd->tx_ring_start; + else { + spin_unlock_bh(&wnd->tx_ring_lock); + up(&wnd->tx_ring_mutex); + break; + } + } else if (n < 0) + n = TX_RING_SIZE - wnd->tx_ring_start; + spin_unlock_bh(&wnd->tx_ring_lock); + if (unlikely(n > wnd->max_tx_packets)) + n = wnd->max_tx_packets; + n = mp_tx_packets(wnd, wnd->tx_ring_start, n); + if (n) { + wnd->net_dev->trans_start = jiffies; + wnd->tx_ring_start = + (wnd->tx_ring_start + n) % TX_RING_SIZE; + wnd->is_tx_ring_full = 0; + } + up(&wnd->tx_ring_mutex); + TRACE3("%d, %d, %d", wnd->tx_ring_start, wnd->tx_ring_end, n); + } + EXIT3(return); +} + +static int tx_skbuff(struct sk_buff *skb, struct net_device *dev) +{ + struct ndis_device *wnd = netdev_priv(dev); + struct ndis_packet *packet; + + packet = alloc_tx_packet(wnd, skb); + if (!packet) { + TRACE2("couldn't allocate packet"); + netif_tx_lock(dev); + netif_stop_queue(dev); + netif_tx_unlock(dev); + return NETDEV_TX_BUSY; + } + spin_lock(&wnd->tx_ring_lock); + wnd->tx_ring[wnd->tx_ring_end++] = packet; + if (wnd->tx_ring_end == TX_RING_SIZE) + wnd->tx_ring_end = 0; + if (wnd->tx_ring_end == wnd->tx_ring_start) { + netif_tx_lock(dev); + wnd->is_tx_ring_full = 1; + netif_stop_queue(dev); + netif_tx_unlock(dev); + } + spin_unlock(&wnd->tx_ring_lock); + TRACE4("ring: %d, %d", wnd->tx_ring_start, wnd->tx_ring_end); + schedule_wrapndis_work(&wnd->tx_work); + return NETDEV_TX_OK; +} + +static int set_packet_filter(struct ndis_device *wnd, ULONG packet_filter) +{ + NDIS_STATUS res; + + while (1) { + res = mp_set_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, + packet_filter); + if (res == NDIS_STATUS_SUCCESS) + break; + TRACE2("couldn't set filter 0x%08x", packet_filter); + /* NDIS_PACKET_TYPE_PROMISCUOUS may not work with 802.11 */ + if (packet_filter & NDIS_PACKET_TYPE_PROMISCUOUS) { + packet_filter &= ~NDIS_PACKET_TYPE_PROMISCUOUS; + continue; + } + if (packet_filter & NDIS_PACKET_TYPE_ALL_LOCAL) { + packet_filter &= ~NDIS_PACKET_TYPE_ALL_LOCAL; + continue; + } + if (packet_filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) { + packet_filter &= ~NDIS_PACKET_TYPE_ALL_FUNCTIONAL; + continue; + } + if (packet_filter & NDIS_PACKET_TYPE_MULTICAST) { + packet_filter &= ~NDIS_PACKET_TYPE_MULTICAST; + packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; + continue; + } + if (packet_filter & NDIS_PACKET_TYPE_ALL_MULTICAST) { + packet_filter &= ~NDIS_PACKET_TYPE_ALL_MULTICAST; + continue; + } + break; + } + + wnd->packet_filter = packet_filter; + res = mp_query_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, &packet_filter); + if (packet_filter != wnd->packet_filter) { + WARNING("filter not set: 0x%08x, 0x%08x", + packet_filter, wnd->packet_filter); + wnd->packet_filter = packet_filter; + } + if (wnd->packet_filter) + EXIT3(return 0); + else + EXIT3(return -1); +} + +static int ndis_net_dev_open(struct net_device *net_dev) +{ + ENTER1("%p", netdev_priv(net_dev)); + netif_start_queue(net_dev); + netif_poll_enable(net_dev); + EXIT1(return 0); +} + +static int ndis_net_dev_close(struct net_device *net_dev) +{ + ENTER1("%p", netdev_priv(net_dev)); + netif_poll_disable(net_dev); + netif_tx_disable(net_dev); + EXIT1(return 0); +} + +static int ndis_change_mtu(struct net_device *net_dev, int mtu) +{ + struct ndis_device *wnd = netdev_priv(net_dev); + int max; + + if (mtu < ETH_ZLEN) + return -EINVAL; + if (mp_query_int(wnd, OID_GEN_MAXIMUM_TOTAL_SIZE, &max) != + NDIS_STATUS_SUCCESS) + return -EOPNOTSUPP; + TRACE1("%d", max); + max -= ETH_HLEN; + if (max <= ETH_ZLEN) + return -EINVAL; + if (mtu + ETH_HLEN > max) + return -EINVAL; + net_dev->mtu = mtu; + return 0; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void ndis_poll_controller(struct net_device *dev) +{ + struct ndis_device *wnd = netdev_priv(dev); + + disable_irq(dev->irq); + ndis_isr(wnd->mp_interrupt->kinterrupt, wnd->mp_interrupt); + enable_irq(dev->irq); +} +#endif + +/* called from BH context */ +static struct net_device_stats *ndis_get_stats(struct net_device *dev) +{ + struct ndis_device *wnd = netdev_priv(dev); + return &wnd->net_stats; +} + +/* called from BH context */ +static void ndis_set_multicast_list(struct net_device *dev) +{ + struct ndis_device *wnd = netdev_priv(dev); + set_bit(SET_MULTICAST_LIST, &wnd->ndis_pending_work); + schedule_wrapndis_work(&wnd->ndis_work); +} + +/* called from BH context */ +struct iw_statistics *get_iw_stats(struct net_device *dev) +{ + struct ndis_device *wnd = netdev_priv(dev); + return &wnd->iw_stats; +} + +static void update_iw_stats(struct ndis_device *wnd) +{ + struct iw_statistics *iw_stats = &wnd->iw_stats; + struct ndis_wireless_stats ndis_stats; + NDIS_STATUS res; + ndis_rssi rssi; + int qual; + + ENTER2("%p", wnd); + if (wnd->iw_stats_enabled == FALSE || !netif_carrier_ok(wnd->net_dev)) { + memset(iw_stats, 0, sizeof(*iw_stats)); + EXIT2(return); + } + res = mp_query(wnd, OID_802_11_RSSI, &rssi, sizeof(rssi)); + if (res == NDIS_STATUS_SUCCESS) + iw_stats->qual.level = rssi; + + qual = 100 * (rssi - WL_NOISE) / (WL_SIGMAX - WL_NOISE); + if (qual < 0) + qual = 0; + else if (qual > 100) + qual = 100; + + iw_stats->qual.noise = WL_NOISE; + iw_stats->qual.qual = qual; + + res = mp_query(wnd, OID_802_11_STATISTICS, + &ndis_stats, sizeof(ndis_stats)); + if (res != NDIS_STATUS_SUCCESS) + EXIT2(return); + iw_stats->discard.retries = (unsigned long)ndis_stats.retry + + (unsigned long)ndis_stats.multi_retry; + iw_stats->discard.misc = (unsigned long)ndis_stats.fcs_err + + (unsigned long)ndis_stats.rtss_fail + + (unsigned long)ndis_stats.ack_fail + + (unsigned long)ndis_stats.frame_dup; + + EXIT2(return); +} + +static void set_multicast_list(struct ndis_device *wnd) +{ + struct net_device *net_dev; + ULONG packet_filter; + NDIS_STATUS res; + + net_dev = wnd->net_dev; + packet_filter = wnd->packet_filter; + + TRACE2("0x%08x", packet_filter); + if (net_dev->flags & IFF_PROMISC) { + packet_filter |= NDIS_PACKET_TYPE_PROMISCUOUS | + NDIS_PACKET_TYPE_ALL_LOCAL; + } else if (net_dev->flags & IFF_ALLMULTI || + net_dev->mc_count > wnd->multicast_size) { + packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; + TRACE2("0x%08x", packet_filter); + } else if (net_dev->mc_count > 0) { + int i, size; + char *buf; + struct dev_mc_list *mclist; + size = min(wnd->multicast_size, net_dev->mc_count); + TRACE2("%d, %d", wnd->multicast_size, net_dev->mc_count); + buf = kmalloc(size * ETH_ALEN, GFP_KERNEL); + if (!buf) { + WARNING("couldn't allocate memory"); + EXIT2(return); + } + mclist = net_dev->mc_list; + for (i = 0; i < size && mclist; mclist = mclist->next) { + if (mclist->dmi_addrlen != ETH_ALEN) + continue; + memcpy(buf + i * ETH_ALEN, mclist->dmi_addr, ETH_ALEN); + TRACE2(MACSTRSEP, MAC2STR(mclist->dmi_addr)); + i++; + } + res = mp_set(wnd, OID_802_3_MULTICAST_LIST, buf, i * ETH_ALEN); + if (res == NDIS_STATUS_SUCCESS && i > 0) + packet_filter |= NDIS_PACKET_TYPE_MULTICAST; + else + packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; + kfree(buf); + } + TRACE2("0x%08x", packet_filter); + res = set_packet_filter(wnd, packet_filter); + if (res) + TRACE1("couldn't set packet filter (%08X)", res); + EXIT2(return); +} + +static void link_status_off(struct ndis_device *wnd) +{ +#ifdef CONFIG_WIRELESS_EXT + union iwreq_data wrqu; + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(wnd->net_dev, SIOCGIWAP, &wrqu, NULL); +#endif + EXIT2(return); +} + +static void link_status_on(struct ndis_device *wnd) +{ +#ifdef CONFIG_WIRELESS_EXT + struct ndis_assoc_info *ndis_assoc_info; + union iwreq_data wrqu; + NDIS_STATUS res; + const int assoc_size = sizeof(*ndis_assoc_info) + IW_CUSTOM_MAX + 32; +#endif + + ENTER2(""); +#ifdef CONFIG_WIRELESS_EXT + memset(&wrqu, 0, sizeof(wrqu)); + ndis_assoc_info = kzalloc(assoc_size, GFP_KERNEL); + if (!ndis_assoc_info) { + ERROR("couldn't allocate memory"); + goto send_assoc_event; + } + res = mp_query(wnd, OID_802_11_ASSOCIATION_INFORMATION, + ndis_assoc_info, assoc_size); + if (res) { + TRACE2("query assoc_info failed (%08X)", res); + kfree(ndis_assoc_info); + goto send_assoc_event; + } + TRACE2("%u, 0x%x, %u, 0x%x, %u", ndis_assoc_info->length, + ndis_assoc_info->req_ies, ndis_assoc_info->req_ie_length, + ndis_assoc_info->resp_ies, ndis_assoc_info->resp_ie_length); + if (ndis_assoc_info->req_ie_length > 0) { + wrqu.data.length = ndis_assoc_info->req_ie_length; + wireless_send_event(wnd->net_dev, IWEVASSOCREQIE, &wrqu, + ((char *)ndis_assoc_info) + + ndis_assoc_info->offset_req_ies); + } + if (ndis_assoc_info->resp_ie_length > 0) { + wrqu.data.length = ndis_assoc_info->resp_ie_length; + wireless_send_event(wnd->net_dev, IWEVASSOCRESPIE, &wrqu, + ((char *)ndis_assoc_info) + + ndis_assoc_info->offset_resp_ies); + } + kfree(ndis_assoc_info); + +send_assoc_event: + get_ap_address(wnd, wrqu.ap_addr.sa_data); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + TRACE2(MACSTRSEP, MAC2STR(wrqu.ap_addr.sa_data)); + wireless_send_event(wnd->net_dev, SIOCGIWAP, &wrqu, NULL); +#endif + EXIT2(return); +} + +static void iw_stats_timer_proc(unsigned long data) +{ + struct ndis_device *wnd = (struct ndis_device *)data; + + ENTER2("%d", wnd->iw_stats_interval); + if (wnd->iw_stats_interval > 0) { + set_bit(COLLECT_IW_STATS, &wnd->ndis_pending_work); + schedule_wrapndis_work(&wnd->ndis_work); + } + mod_timer(&wnd->iw_stats_timer, jiffies + wnd->iw_stats_interval); +} + +static void add_iw_stats_timer(struct ndis_device *wnd) +{ + if (wnd->physical_medium != NdisPhysicalMediumWirelessLan) + return; + if (wnd->iw_stats_interval < 0) + wnd->iw_stats_interval *= -1; + wnd->iw_stats_timer.data = (unsigned long)wnd; + wnd->iw_stats_timer.function = iw_stats_timer_proc; + mod_timer(&wnd->iw_stats_timer, jiffies + wnd->iw_stats_interval); +} + +static void del_iw_stats_timer(struct ndis_device *wnd) +{ + ENTER2("%d", wnd->iw_stats_interval); + wnd->iw_stats_interval *= -1; + del_timer_sync(&wnd->iw_stats_timer); + EXIT2(return); +} + +static void hangcheck_proc(unsigned long data) +{ + struct ndis_device *wnd = (struct ndis_device *)data; + + ENTER3("%d", wnd->hangcheck_interval); + if (wnd->hangcheck_interval > 0) { + set_bit(HANGCHECK, &wnd->ndis_pending_work); + schedule_wrapndis_work(&wnd->ndis_work); + } + mod_timer(&wnd->hangcheck_timer, jiffies + wnd->hangcheck_interval); + EXIT3(return); +} + +void hangcheck_add(struct ndis_device *wnd) +{ + if (!wnd->wd->driver->ndis_driver->mp.hangcheck || + hangcheck_interval < 0) + EXIT2(return); + + if (hangcheck_interval > 0) + wnd->hangcheck_interval = hangcheck_interval * HZ; + if (wnd->hangcheck_interval < 0) + wnd->hangcheck_interval *= -1; + wnd->hangcheck_timer.data = (unsigned long)wnd; + wnd->hangcheck_timer.function = hangcheck_proc; + mod_timer(&wnd->hangcheck_timer, jiffies + wnd->hangcheck_interval); + EXIT2(return); +} + +void hangcheck_del(struct ndis_device *wnd) +{ + ENTER2("%d", wnd->hangcheck_interval); + if (wnd->hangcheck_interval > 0) + wnd->hangcheck_interval *= -1; + del_timer_sync(&wnd->hangcheck_timer); + EXIT2(return); +} + +/* worker procedure to take care of setting/checking various states */ +static void ndis_worker(worker_param_t param) +{ + struct ndis_device *wnd; + + wnd = worker_param_data(param, struct ndis_device, ndis_work); + WORKTRACE("0x%lx", wnd->ndis_pending_work); + + if (test_and_clear_bit(NETIF_WAKEQ, &wnd->ndis_pending_work)) { + netif_tx_lock_bh(wnd->net_dev); + netif_wake_queue(wnd->net_dev); + netif_tx_unlock_bh(wnd->net_dev); + } + + if (test_and_clear_bit(LINK_STATUS_OFF, &wnd->ndis_pending_work)) + link_status_off(wnd); + + if (test_and_clear_bit(LINK_STATUS_ON, &wnd->ndis_pending_work)) + link_status_on(wnd); + + if (test_and_clear_bit(COLLECT_IW_STATS, &wnd->ndis_pending_work)) + update_iw_stats(wnd); + + if (test_and_clear_bit(SET_MULTICAST_LIST, + &wnd->ndis_pending_work)) + set_multicast_list(wnd); + + if (test_and_clear_bit(HANGCHECK, &wnd->ndis_pending_work)) { + struct miniport *mp; + BOOLEAN reset; + KIRQL irql; + + mp = &wnd->wd->driver->ndis_driver->mp; + irql = serialize_lock_irql(wnd); + reset = LIN2WIN1(mp->hangcheck, wnd->nmb->mp_ctx); + serialize_unlock_irql(wnd, irql); + if (reset) { + TRACE2("%s needs reset", wnd->net_dev->name); + mp_reset(wnd); + } + } + WORKEXIT(return); +} + +NDIS_STATUS ndis_reinit(struct ndis_device *wnd) +{ + NDIS_STATUS status; + + wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND; + status = mp_set_power_state(wnd, NdisDeviceStateD3); + if (status != NDIS_STATUS_SUCCESS) { + ERROR("halting device %s failed: %08X", wnd->net_dev->name, + status); + return status; + } + status = mp_set_power_state(wnd, NdisDeviceStateD0); + if (status != NDIS_STATUS_SUCCESS) + ERROR("starting device %s failed: %08X", wnd->net_dev->name, + status); + return status; +} + +static void get_encryption_capa(struct ndis_device *wnd, char *buf, + const int buf_len) +{ + int i, mode; + NDIS_STATUS res; + struct ndis_assoc_info ndis_assoc_info; + struct ndis_add_key ndis_key; + struct ndis_capability *c; + + ENTER1("%p", wnd); + /* set network type to g, b, or a, in that order */ + res = mp_query(wnd, OID_802_11_NETWORK_TYPES_SUPPORTED, buf, buf_len); + if (res == NDIS_STATUS_SUCCESS) { + struct network_type_list *net_types; + unsigned long types = 0; + net_types = (typeof(net_types))buf; + for (i = 0; i < net_types->num; i++) { + TRACE2("%d", net_types->types[i]); + set_bit(net_types->types[i], &types); + } + if (types & Ndis802_11OFDM24) + mode = Ndis802_11OFDM24; + else if (types & Ndis802_11DS) + mode = Ndis802_11DS; + else if (types & Ndis802_11OFDM5) + mode = Ndis802_11OFDM5; + else + mode = Ndis802_11DS; + mp_set_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE, mode); + } + /* check if WEP is supported */ + if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104, + IW_AUTH_CIPHER_NONE) == 0 && + get_ndis_encr_mode(wnd) == Ndis802_11Encryption1KeyAbsent) + set_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr); + + /* check if WPA is supported */ + if (set_ndis_auth_mode(wnd, Ndis802_11AuthModeWPA) == 0 && + get_ndis_auth_mode(wnd) == Ndis802_11AuthModeWPA) + set_bit(Ndis802_11AuthModeWPA, &wnd->capa.encr); + else + EXIT1(return); + + if (set_ndis_auth_mode(wnd, Ndis802_11AuthModeWPAPSK) == 0 && + get_ndis_auth_mode(wnd) == Ndis802_11AuthModeWPAPSK) + set_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.encr); + + /* check for highest encryption */ + mode = 0; + if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_CCMP, + IW_AUTH_CIPHER_NONE) == 0 && + (i = get_ndis_encr_mode(wnd)) > 0 && + (i == Ndis802_11Encryption3KeyAbsent || + i == Ndis802_11Encryption3Enabled)) + mode = Ndis802_11Encryption3Enabled; + else if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_TKIP, + IW_AUTH_CIPHER_NONE) == 0 && + (i = get_ndis_encr_mode(wnd)) > 0 && + (i == Ndis802_11Encryption2KeyAbsent || + i == Ndis802_11Encryption2Enabled)) + mode = Ndis802_11Encryption2Enabled; + else if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104, + IW_AUTH_CIPHER_NONE) == 0 && + (i = get_ndis_encr_mode(wnd)) > 0 && + (i == Ndis802_11Encryption1KeyAbsent || + i == Ndis802_11Encryption1Enabled)) + mode = Ndis802_11Encryption1Enabled; + + TRACE1("mode: %d", mode); + if (mode == 0) + EXIT1(return); + set_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr); + if (mode == Ndis802_11Encryption1Enabled) + EXIT1(return); + + ndis_key.length = 32; + ndis_key.index = 0xC0000001; + ndis_key.struct_size = sizeof(ndis_key); + res = mp_set(wnd, OID_802_11_ADD_KEY, &ndis_key, ndis_key.struct_size); + TRACE2("%08X, %lu", res, (unsigned long)sizeof(ndis_key)); + if (res && res != NDIS_STATUS_INVALID_DATA) + EXIT1(return); + res = mp_query(wnd, OID_802_11_ASSOCIATION_INFORMATION, + &ndis_assoc_info, sizeof(ndis_assoc_info)); + TRACE1("%08X", res); + if (res == NDIS_STATUS_NOT_SUPPORTED) + EXIT1(return); + + set_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr); + if (mode == Ndis802_11Encryption3Enabled) + set_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr); + /* not all drivers support OID_802_11_CAPABILITY, so we don't + * know for sure if driver support WPA or WPAPSK; assume + * WPAPSK */ + set_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.auth); + wnd->max_pmkids = 1; + + memset(buf, 0, buf_len); + c = (struct ndis_capability *)buf; + res = mp_query(wnd, OID_802_11_CAPABILITY, buf, buf_len); + if (!(res == NDIS_STATUS_SUCCESS && c->version == 2)) + EXIT1(return); + wnd->max_pmkids = c->num_PMKIDs; + + for (i = 0; i < c->num_auth_encr_pair; i++) { + struct ndis_auth_encr_pair *ae; + + ae = &c->auth_encr_pair[i]; + if ((char *)(ae + 1) > buf + buf_len) + break; + switch (ae->auth_mode) { + case Ndis802_11AuthModeOpen: + case Ndis802_11AuthModeShared: + case Ndis802_11AuthModeWPA: + case Ndis802_11AuthModeWPAPSK: + case Ndis802_11AuthModeWPANone: + case Ndis802_11AuthModeWPA2: + case Ndis802_11AuthModeWPA2PSK: + set_bit(ae->auth_mode, &wnd->capa.auth); + break; + default: + WARNING("unknown auth_mode: %d", ae->auth_mode); + break; + } + switch (ae->encr_mode) { + case Ndis802_11EncryptionDisabled: + case Ndis802_11Encryption1Enabled: + case Ndis802_11Encryption2Enabled: + case Ndis802_11Encryption3Enabled: + set_bit(ae->encr_mode, &wnd->capa.encr); + break; + default: + WARNING("unknown encr_mode: %d", ae->encr_mode); + break; + } + } + EXIT1(return); +} + +wstdcall NTSTATUS NdisDispatchDeviceControl(struct device_object *fdo, + struct irp *irp) +{ + struct ndis_device *wnd; + + TRACE3("fdo: %p", fdo); + /* for now, we don't have anything intresting here, so pass it + * down to bus driver */ + wnd = fdo->reserved; + return IoPassIrpDown(wnd->nmb->pdo, irp); +} +WIN_FUNC_DECL(NdisDispatchDeviceControl,2) + +wstdcall NTSTATUS NdisDispatchPower(struct device_object *fdo, struct irp *irp) +{ + struct io_stack_location *irp_sl; + struct ndis_device *wnd; + enum ndis_power_state state; + NTSTATUS status; + NDIS_STATUS ndis_status; + + irp_sl = IoGetCurrentIrpStackLocation(irp); + wnd = fdo->reserved; + IOTRACE("fdo: %p, fn: %d:%d, wnd: %p", fdo, irp_sl->major_fn, + irp_sl->minor_fn, wnd); + if ((irp_sl->params.power.type == SystemPowerState && + irp_sl->params.power.state.system_state > PowerSystemWorking) || + (irp_sl->params.power.type == DevicePowerState && + irp_sl->params.power.state.device_state > PowerDeviceD0)) + state = NdisDeviceStateD3; + else + state = NdisDeviceStateD0; + switch (irp_sl->minor_fn) { + case IRP_MN_SET_POWER: + if (state == NdisDeviceStateD0) { + status = IoSyncForwardIrp(wnd->nmb->pdo, irp); + if (status != STATUS_SUCCESS) + break; + ndis_status = mp_set_power_state(wnd, state); + if (ndis_status != NDIS_STATUS_SUCCESS) + WARNING("couldn't set power to %d: %08X", + state, ndis_status); + TRACE2("%s: device resumed", wnd->net_dev->name); + irp->io_status.status = status = STATUS_SUCCESS; + IoCompleteRequest(irp, IO_NO_INCREMENT); + break; + } else { + ndis_status = mp_set_power_state(wnd, state); + /* TODO: handle error case */ + if (ndis_status != NDIS_STATUS_SUCCESS) + WARNING("setting power to %d failed: %08X", + state, ndis_status); + status = IoAsyncForwardIrp(wnd->nmb->pdo, irp); + } + break; + case IRP_MN_QUERY_POWER: + if (wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND) { + ndis_status = mp_query(wnd, OID_PNP_QUERY_POWER, + &state, sizeof(state)); + TRACE2("%d, %08X", state, ndis_status); + /* this OID must always succeed */ + if (ndis_status != NDIS_STATUS_SUCCESS) + TRACE1("query power returns %08X", ndis_status); + irp->io_status.status = STATUS_SUCCESS; + } else + irp->io_status.status = STATUS_SUCCESS; + status = IoPassIrpDown(wnd->nmb->pdo, irp); + break; + case IRP_MN_WAIT_WAKE: + case IRP_MN_POWER_SEQUENCE: + /* TODO: implement WAIT_WAKE */ + status = IoPassIrpDown(wnd->nmb->pdo, irp); + break; + default: + status = IoPassIrpDown(wnd->nmb->pdo, irp); + break; + } + IOEXIT(return status); +} +WIN_FUNC_DECL(NdisDispatchPower,2) + +wstdcall NTSTATUS NdisDispatchPnp(struct device_object *fdo, struct irp *irp) +{ + struct io_stack_location *irp_sl; + struct ndis_device *wnd; + struct device_object *pdo; + NTSTATUS status; + + IOTRACE("fdo: %p, irp: %p", fdo, irp); + irp_sl = IoGetCurrentIrpStackLocation(irp); + wnd = fdo->reserved; + pdo = wnd->nmb->pdo; + switch (irp_sl->minor_fn) { + case IRP_MN_START_DEVICE: + status = IoSyncForwardIrp(pdo, irp); + if (status != STATUS_SUCCESS) + break; + if (ndis_start_device(wnd) == NDIS_STATUS_SUCCESS) + status = STATUS_SUCCESS; + else + status = STATUS_FAILURE; + irp->io_status.status = status; + IoCompleteRequest(irp, IO_NO_INCREMENT); + break; + case IRP_MN_QUERY_STOP_DEVICE: + /* TODO: implement in NDIS */ + status = IoPassIrpDown(wnd->nmb->pdo, irp); + break; + case IRP_MN_STOP_DEVICE: + mp_halt(wnd); + irp->io_status.status = STATUS_SUCCESS; + status = IoAsyncForwardIrp(pdo, irp); + break; + case IRP_MN_REMOVE_DEVICE: + TRACE1("%s", wnd->net_dev->name); + mp_pnp_event(wnd, NdisDevicePnPEventSurpriseRemoved, 0); + if (ndis_remove_device(wnd)) { + status = STATUS_FAILURE; + break; + } + /* wnd is already freed */ + status = IoAsyncForwardIrp(pdo, irp); + IoDetachDevice(fdo); + IoDeleteDevice(fdo); + break; + default: + status = IoAsyncForwardIrp(pdo, irp); + break; + } + IOTRACE("status: %08X", status); + IOEXIT(return status); +} +WIN_FUNC_DECL(NdisDispatchPnp,2) + +static void set_task_offload(struct ndis_device *wnd, void *buf, + const int buf_size) +{ + struct ndis_task_offload_header *task_offload_header; + struct ndis_task_offload *task_offload; + struct ndis_task_tcp_ip_checksum *csum = NULL; + struct ndis_task_tcp_large_send *tso = NULL; + NDIS_STATUS status; + + memset(buf, 0, buf_size); + task_offload_header = buf; + task_offload_header->version = NDIS_TASK_OFFLOAD_VERSION; + task_offload_header->size = sizeof(*task_offload_header); + task_offload_header->encap_format.flags.fixed_header_size = 1; + task_offload_header->encap_format.header_size = sizeof(struct ethhdr); + task_offload_header->encap_format.encap = IEEE_802_3_Encapsulation; + status = mp_query(wnd, OID_TCP_TASK_OFFLOAD, buf, buf_size); + TRACE1("%08X", status); + if (status != NDIS_STATUS_SUCCESS) + EXIT1(return); + if (task_offload_header->offset_first_task == 0) + EXIT1(return); + task_offload = ((void *)task_offload_header + + task_offload_header->offset_first_task); + while (1) { + TRACE1("%d, %d", task_offload->version, task_offload->task); + switch(task_offload->task) { + case TcpIpChecksumNdisTask: + csum = (void *)task_offload->task_buf; + break; + case TcpLargeSendNdisTask: + tso = (void *)task_offload->task_buf; + break; + default: + TRACE1("%d", task_offload->task); + break; + } + if (task_offload->offset_next_task == 0) + break; + task_offload = (void *)task_offload + + task_offload->offset_next_task; + } + if (tso) + TRACE1("%u, %u, %d, %d", tso->max_size, tso->min_seg_count, + tso->tcp_opts, tso->ip_opts); + if (!csum) + EXIT1(return); + TRACE1("%08x, %08x", csum->v4_tx.value, csum->v4_rx.value); + task_offload_header->encap_format.flags.fixed_header_size = 1; + task_offload_header->encap_format.header_size = sizeof(struct ethhdr); + task_offload_header->offset_first_task = sizeof(*task_offload_header); + task_offload = ((void *)task_offload_header + + task_offload_header->offset_first_task); + task_offload->offset_next_task = 0; + task_offload->size = sizeof(*task_offload); + task_offload->task = TcpIpChecksumNdisTask; + memcpy(task_offload->task_buf, csum, sizeof(*csum)); + task_offload->task_buf_length = sizeof(*csum); + status = mp_set(wnd, OID_TCP_TASK_OFFLOAD, task_offload_header, + sizeof(*task_offload_header) + + sizeof(*task_offload) + sizeof(*csum)); + TRACE1("%08X", status); + if (status != NDIS_STATUS_SUCCESS) + EXIT2(return); + wnd->tx_csum = csum->v4_tx; + if (csum->v4_tx.tcp_csum && csum->v4_tx.udp_csum) { + if (csum->v4_tx.ip_csum) { + wnd->net_dev->features |= NETIF_F_HW_CSUM; + TRACE1("hw checksum enabled"); + } else { + wnd->net_dev->features |= NETIF_F_IP_CSUM; + TRACE1("IP checksum enabled"); + } + if (wnd->sg_dma_size) + wnd->net_dev->features |= NETIF_F_SG; + } + wnd->rx_csum = csum->v4_rx; + EXIT1(return); +} + +static void get_supported_oids(struct ndis_device *wnd) +{ + NDIS_STATUS res; + int i, n, needed; + ndis_oid *oids; + + res = mp_query_info(wnd, OID_GEN_SUPPORTED_LIST, NULL, 0, NULL, + &needed); + if (!(res == NDIS_STATUS_BUFFER_TOO_SHORT || + res == NDIS_STATUS_INVALID_LENGTH)) + EXIT1(return); + oids = kmalloc(needed, GFP_KERNEL); + if (!oids) { + TRACE1("couldn't allocate memory"); + EXIT1(return); + } + res = mp_query(wnd, OID_GEN_SUPPORTED_LIST, oids, needed); + if (res) { + TRACE1("failed: %08X", res); + kfree(oids); + EXIT1(return); + } + for (i = 0, n = needed / sizeof(*oids); i < n; i++) { + TRACE1("oid: %08X", oids[i]); + /* if a wireless device didn't say so for + * OID_GEN_PHYSICAL_MEDIUM (they should, but in case) */ + if (wnd->physical_medium != NdisPhysicalMediumWirelessLan && + oids[i] == OID_802_11_SSID) + wnd->physical_medium = NdisPhysicalMediumWirelessLan; + } + kfree(oids); + EXIT1(return); +} + +static void ndis_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct ndis_device *wnd = netdev_priv(dev); + strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 2); + strcat(info->driver, "+"); + strncat(info->driver, wnd->wd->driver->name, + sizeof(info->driver) - strlen(DRIVER_NAME) - 1); + strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 2); + strcat(info->version, "+"); + strncat(info->version, wnd->wd->driver->version, + sizeof(info->version) - strlen(DRIVER_VERSION) - 1); + if (wrap_is_pci_bus(wnd->wd->dev_bus)) + strncpy(info->bus_info, pci_name(wnd->wd->pci.pdev), + sizeof(info->bus_info) - 1); +#ifdef ENABLE_USB + else + usb_make_path(wnd->wd->usb.udev, info->bus_info, + sizeof(info->bus_info) - 1); +#endif + return; +} + +static u32 ndis_get_link(struct net_device *dev) +{ + struct ndis_device *wnd = netdev_priv(dev); + return netif_carrier_ok(wnd->net_dev); +} + +static void ndis_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct ndis_device *wnd = netdev_priv(dev); + + wol->supported = 0; + wol->wolopts = 0; + if (!(wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND)) + EXIT2(return); + if (!wrap_is_pci_bus(wnd->wd->dev_bus)) + EXIT2(return); + /* we always suspend to D3 */ + if (wnd->pnp_capa.wakeup.min_magic_packet_wakeup < NdisDeviceStateD3) + return; + wol->supported |= WAKE_MAGIC; + if (wnd->ndis_wolopts & NDIS_PNP_WAKE_UP_MAGIC_PACKET) + wol->wolopts |= WAKE_MAGIC; + return; +} + +static int ndis_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct ndis_device *wnd = netdev_priv(dev); + + if (!(wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND)) + return -EOPNOTSUPP; + if (wnd->pnp_capa.wakeup.min_magic_packet_wakeup < NdisDeviceStateD3) + EXIT2(return -EOPNOTSUPP); + TRACE2("0x%x", wol->wolopts); + if (wol->wolopts & WAKE_MAGIC) { + wnd->ndis_wolopts |= NDIS_PNP_WAKE_UP_MAGIC_PACKET; + if (wol->wolopts != WAKE_MAGIC) + WARNING("ignored wake-on-lan options: 0x%x", + wol->wolopts & ~WAKE_MAGIC); + } else if (!wol->wolopts) + wnd->ndis_wolopts = 0; + else + return -EOPNOTSUPP; + TRACE2("0x%x", wnd->ndis_wolopts); + return 0; +} + +static u32 ndis_get_tx_csum(struct net_device *dev) +{ + struct ndis_device *wnd = netdev_priv(dev); + if (wnd->tx_csum.tcp_csum && wnd->tx_csum.udp_csum) + return 1; + else + return 0; +} + +static u32 ndis_get_rx_csum(struct net_device *dev) +{ + struct ndis_device *wnd = netdev_priv(dev); + if (wnd->rx_csum.value) + return 1; + else + return 0; +} + +static int ndis_set_tx_csum(struct net_device *dev, u32 data) +{ + struct ndis_device *wnd = netdev_priv(dev); + + if (data && (wnd->tx_csum.value == 0)) + return -EOPNOTSUPP; + + if (wnd->tx_csum.ip_csum) { + ethtool_op_set_tx_hw_csum(dev, data); + } else + ethtool_op_set_tx_csum(dev, data); + return 0; +} + +static int ndis_set_rx_csum(struct net_device *dev, u32 data) +{ + struct ndis_device *wnd = netdev_priv(dev); + + if (data && (wnd->tx_csum.value == 0)) + return -EOPNOTSUPP; + + /* TODO: enable/disable rx csum through NDIS */ + return 0; +} + +static u32 ndis_get_sg(struct net_device *dev) +{ + struct ndis_device *wnd = netdev_priv(dev); + if (wnd->sg_dma_size) + return ethtool_op_get_sg(dev); + else + return 0; +} + +static int ndis_set_sg(struct net_device *dev, u32 data) +{ + struct ndis_device *wnd = netdev_priv(dev); + if (wnd->sg_dma_size) + return ethtool_op_set_sg(dev, data); + else + return -EOPNOTSUPP; +} + +static struct ethtool_ops ndis_ethtool_ops = { + .get_drvinfo = ndis_get_drvinfo, + .get_link = ndis_get_link, + .get_wol = ndis_get_wol, + .set_wol = ndis_set_wol, + .get_tx_csum = ndis_get_tx_csum, + .get_rx_csum = ndis_get_rx_csum, + .set_tx_csum = ndis_set_tx_csum, + .set_rx_csum = ndis_set_rx_csum, + .get_sg = ndis_get_sg, + .set_sg = ndis_set_sg, +}; + +static int notifier_event(struct notifier_block *notifier, unsigned long event, + void *ptr) +{ + struct net_device *net_dev = ptr; + + ENTER2("0x%lx", event); + if (net_dev->open == ndis_net_dev_open && event == NETDEV_CHANGENAME) { + struct ndis_device *wnd = netdev_priv(net_dev); + /* called with rtnl lock held, so no need to lock */ + wrap_procfs_remove_ndis_device(wnd); + printk(KERN_INFO "%s: changing interface name from '%s' to " + "'%s'\n", DRIVER_NAME, wnd->netdev_name, net_dev->name); + memcpy(wnd->netdev_name, net_dev->name, + sizeof(wnd->netdev_name)); + wrap_procfs_add_ndis_device(wnd); + } + return NOTIFY_DONE; +} + +static struct notifier_block netdev_notifier = { + .notifier_call = notifier_event, +}; + +static NDIS_STATUS ndis_start_device(struct ndis_device *wnd) +{ + struct wrap_device *wd; + struct net_device *net_dev; + NDIS_STATUS status; + char *buf; + const int buf_len = 256; + mac_address mac; + struct transport_header_offset *tx_header_offset; + int n; + + ENTER2("%d", in_atomic()); + status = mp_init(wnd); + if (status == NDIS_STATUS_NOT_RECOGNIZED) + EXIT1(return NDIS_STATUS_SUCCESS); + if (status != NDIS_STATUS_SUCCESS) + EXIT1(return status); + wd = wnd->wd; + net_dev = wnd->net_dev; + + get_supported_oids(wnd); + memset(mac, 0, sizeof(mac)); + status = mp_query(wnd, OID_802_3_CURRENT_ADDRESS, mac, sizeof(mac)); + if (memcmp(mac, "\x00\x00\x00\x00\x00\x00", sizeof(mac)) == 0) { + status = mp_query(wnd, OID_802_3_PERMANENT_ADDRESS, mac, + sizeof(mac)); + if (status != NDIS_STATUS_SUCCESS) { + ERROR("couldn't get mac address: %08X", status); + goto err_start; + } + } + TRACE1("mac:" MACSTRSEP, MAC2STR(mac)); + memcpy(net_dev->dev_addr, mac, ETH_ALEN); + + strncpy(net_dev->name, if_name, IFNAMSIZ - 1); + net_dev->name[IFNAMSIZ - 1] = 0; + + wnd->packet_filter = NDIS_PACKET_TYPE_DIRECTED | + NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_MULTICAST; + net_dev->open = ndis_net_dev_open; + net_dev->hard_start_xmit = tx_skbuff; + net_dev->stop = ndis_net_dev_close; + net_dev->get_stats = ndis_get_stats; + net_dev->change_mtu = ndis_change_mtu; + net_dev->do_ioctl = NULL; + if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) { + net_dev->wireless_handlers = &ndis_handler_def; + } + net_dev->set_multicast_list = ndis_set_multicast_list; + net_dev->set_mac_address = ndis_set_mac_address; + net_dev->ethtool_ops = &ndis_ethtool_ops; + if (wnd->mp_interrupt) + net_dev->irq = wnd->mp_interrupt->irq; + net_dev->mem_start = wnd->mem_start; + net_dev->mem_end = wnd->mem_end; + status = mp_query_int(wnd, OID_802_3_MAXIMUM_LIST_SIZE, + &wnd->multicast_size); + if (status != NDIS_STATUS_SUCCESS || wnd->multicast_size < 0) + wnd->multicast_size = 0; + if (wnd->multicast_size > 0) + net_dev->flags |= IFF_MULTICAST; + else + net_dev->flags &= ~IFF_MULTICAST; +#ifdef CONFIG_NET_POLL_CONTROLLER + net_dev->poll_controller = ndis_poll_controller; +#endif + + buf = kmalloc(buf_len, GFP_KERNEL); + if (!buf) { + WARNING("couldn't allocate memory"); + goto err_start; + } + + set_task_offload(wnd, buf, buf_len); +#ifdef NETIF_F_LLTX + net_dev->features |= NETIF_F_LLTX; +#endif + + if (register_netdev(net_dev)) { + ERROR("cannot register net device %s", net_dev->name); + goto err_register; + } + memcpy(wnd->netdev_name, net_dev->name, sizeof(wnd->netdev_name)); + memset(buf, 0, buf_len); + status = mp_query(wnd, OID_GEN_VENDOR_DESCRIPTION, buf, buf_len); + if (status != NDIS_STATUS_SUCCESS) { + WARNING("couldn't get vendor information: 0x%x", status); + buf[0] = 0; + } + wnd->drv_ndis_version = n = 0; + mp_query_int(wnd, OID_GEN_DRIVER_VERSION, &wnd->drv_ndis_version); + mp_query_int(wnd, OID_GEN_VENDOR_DRIVER_VERSION, &n); + + printk(KERN_INFO "%s: ethernet device " MACSTRSEP " using %sNDIS " + "driver: %s, version: 0x%x, NDIS version: 0x%x, vendor: '%s', " + "%s\n", net_dev->name, MAC2STR(net_dev->dev_addr), + deserialized_driver(wnd) ? "" : "serialized ", + wnd->wd->driver->name, n, wnd->drv_ndis_version, buf, + wnd->wd->conf_file_name); + + if (deserialized_driver(wnd)) { + /* deserialized drivers don't have a limit, but we + * keep max at TX_RING_SIZE */ + wnd->max_tx_packets = TX_RING_SIZE; + } else { + status = mp_query_int(wnd, OID_GEN_MAXIMUM_SEND_PACKETS, + &wnd->max_tx_packets); + if (status != NDIS_STATUS_SUCCESS) + wnd->max_tx_packets = 1; + if (wnd->max_tx_packets > TX_RING_SIZE) + wnd->max_tx_packets = TX_RING_SIZE; + } + TRACE2("maximum send packets: %d", wnd->max_tx_packets); + NdisAllocatePacketPoolEx(&status, &wnd->tx_packet_pool, + wnd->max_tx_packets, 0, + PROTOCOL_RESERVED_SIZE_IN_PACKET); + if (status != NDIS_STATUS_SUCCESS) { + ERROR("couldn't allocate packet pool"); + goto packet_pool_err; + } + NdisAllocateBufferPool(&status, &wnd->tx_buffer_pool, + wnd->max_tx_packets + 4); + if (status != NDIS_STATUS_SUCCESS) { + ERROR("couldn't allocate buffer pool"); + goto buffer_pool_err; + } + TRACE1("pool: %p", wnd->tx_buffer_pool); + + if (mp_query_int(wnd, OID_GEN_MAXIMUM_TOTAL_SIZE, &n) == + NDIS_STATUS_SUCCESS && n > ETH_HLEN) + ndis_change_mtu(wnd->net_dev, n - ETH_HLEN); + + if (mp_query_int(wnd, OID_GEN_MAC_OPTIONS, &n) == NDIS_STATUS_SUCCESS) + TRACE2("mac options supported: 0x%x", n); + + tx_header_offset = (typeof(tx_header_offset))buf; + tx_header_offset->protocol_type = NDIS_PROTOCOL_ID_TCP_IP; + tx_header_offset->header_offset = sizeof(ETH_HLEN); + status = mp_set(wnd, OID_GEN_TRANSPORT_HEADER_OFFSET, + tx_header_offset, sizeof(*tx_header_offset)); + TRACE2("%08X", status); + + status = mp_query_int(wnd, OID_GEN_PHYSICAL_MEDIUM, + &wnd->physical_medium); + if (status != NDIS_STATUS_SUCCESS) + wnd->physical_medium = NdisPhysicalMediumUnspecified; + + if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) { + mp_set_int(wnd, OID_802_11_POWER_MODE, NDIS_POWER_OFF); + get_encryption_capa(wnd, buf, buf_len); + TRACE1("capbilities = %ld", wnd->capa.encr); + printk(KERN_INFO "%s: encryption modes supported: " + "%s%s%s%s%s%s%s\n", net_dev->name, + test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr) ? + "WEP" : "none", + + test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr) ? + "; TKIP with WPA" : "", + test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ? + ", WPA2" : "", + test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ? + ", WPA2PSK" : "", + + test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr) ? + "; AES/CCMP with WPA" : "", + test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ? + ", WPA2" : "", + test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ? + ", WPA2PSK" : ""); + + set_default_iw_params(wnd); + } + kfree(buf); + wrap_procfs_add_ndis_device(wnd); + hangcheck_add(wnd); + add_iw_stats_timer(wnd); + EXIT1(return NDIS_STATUS_SUCCESS); + +buffer_pool_err: + wnd->tx_buffer_pool = NULL; + if (wnd->tx_packet_pool) { + NdisFreePacketPool(wnd->tx_packet_pool); + wnd->tx_packet_pool = NULL; + } +packet_pool_err: +err_register: + kfree(buf); +err_start: + ndis_remove_device(wnd); + EXIT1(return NDIS_STATUS_FAILURE); +} + +static int ndis_remove_device(struct ndis_device *wnd) +{ + s8 tx_pending; + + /* prevent setting essid during disassociation */ + memset(&wnd->essid, 0, sizeof(wnd->essid)); + wnd->tx_ok = 0; + if (wnd->max_tx_packets) + unregister_netdev(wnd->net_dev); + netif_carrier_off(wnd->net_dev); + /* if device is suspended, but resume failed, tx_ring_mutex + * may already be locked */ + if (down_trylock(&wnd->tx_ring_mutex)) + WARNING("couldn't obtain tx_ring_mutex"); + spin_lock_bh(&wnd->tx_ring_lock); + tx_pending = wnd->tx_ring_end - wnd->tx_ring_start; + if (tx_pending < 0) + tx_pending += TX_RING_SIZE; + else if (tx_pending == 0 && wnd->is_tx_ring_full) + tx_pending = TX_RING_SIZE - 1; + wnd->is_tx_ring_full = 0; + /* throw away pending packets */ + while (tx_pending-- > 0) { + struct ndis_packet *packet; + + packet = wnd->tx_ring[wnd->tx_ring_start]; + free_tx_packet(wnd, packet, NDIS_STATUS_CLOSING); + wnd->tx_ring_start = (wnd->tx_ring_start + 1) % TX_RING_SIZE; + } + spin_unlock_bh(&wnd->tx_ring_lock); + up(&wnd->tx_ring_mutex); + wrap_procfs_remove_ndis_device(wnd); + mp_halt(wnd); + ndis_exit_device(wnd); + + if (wnd->tx_packet_pool) { + NdisFreePacketPool(wnd->tx_packet_pool); + wnd->tx_packet_pool = NULL; + } + if (wnd->tx_buffer_pool) { + NdisFreeBufferPool(wnd->tx_buffer_pool); + wnd->tx_buffer_pool = NULL; + } + if (wnd->pmkids) + kfree(wnd->pmkids); + printk(KERN_INFO "%s: device %s removed\n", DRIVER_NAME, + wnd->net_dev->name); + kfree(wnd->nmb); + free_netdev(wnd->net_dev); + EXIT2(return 0); +} + +static wstdcall NTSTATUS NdisAddDevice(struct driver_object *drv_obj, + struct device_object *pdo) +{ + struct device_object *fdo; + struct ndis_mp_block *nmb; + NTSTATUS status; + struct ndis_device *wnd; + struct net_device *net_dev; + struct wrap_device *wd; + unsigned long i; + + ENTER2("%p, %p", drv_obj, pdo); + if (strlen(if_name) >= IFNAMSIZ) { + ERROR("interface name '%s' is too long", if_name); + return STATUS_INVALID_PARAMETER; + } + net_dev = alloc_etherdev(sizeof(*wnd)); + if (!net_dev) { + ERROR("couldn't allocate device"); + return STATUS_RESOURCES; + } + wd = pdo->reserved; + if (wrap_is_pci_bus(wd->dev_bus)) + SET_NETDEV_DEV(net_dev, &wd->pci.pdev->dev); + if (wrap_is_usb_bus(wd->dev_bus)) + SET_NETDEV_DEV(net_dev, &wd->usb.intf->dev); + status = IoCreateDevice(drv_obj, 0, NULL, FILE_DEVICE_UNKNOWN, 0, + FALSE, &fdo); + if (status != STATUS_SUCCESS) { + free_netdev(net_dev); + EXIT2(return status); + } + wnd = netdev_priv(net_dev); + TRACE1("wnd: %p", wnd); + + nmb = kmalloc(sizeof(*nmb), GFP_KERNEL); + if (!nmb) { + WARNING("couldn't allocate memory"); + IoDeleteDevice(fdo); + free_netdev(net_dev); + return STATUS_RESOURCES; + } +#if defined(DEBUG) && DEBUG >= 6 + /* poison nmb so if a driver accesses uninitialized pointers, we + * know what it is */ + for (i = 0; i < sizeof(*nmb) / sizeof(unsigned long); i++) + ((unsigned long *)nmb)[i] = i + 0x8a3fc1; +#endif + + wnd->nmb = nmb; + nmb->wnd = wnd; + nmb->pdo = pdo; + wd->wnd = wnd; + wnd->wd = wd; + wnd->net_dev = net_dev; + fdo->reserved = wnd; + nmb->fdo = fdo; + if (ndis_init_device(wnd)) { + IoDeleteDevice(fdo); + kfree(nmb); + free_netdev(net_dev); + EXIT1(return STATUS_RESOURCES); + } + nmb->next_device = IoAttachDeviceToDeviceStack(fdo, pdo); + spin_lock_init(&wnd->tx_ring_lock); + init_MUTEX(&wnd->tx_ring_mutex); + init_MUTEX(&wnd->ndis_req_mutex); + wnd->ndis_req_done = 0; + initialize_work(&wnd->tx_work, tx_worker, wnd); + wnd->tx_ring_start = 0; + wnd->tx_ring_end = 0; + wnd->is_tx_ring_full = 0; + wnd->capa.encr = 0; + wnd->capa.auth = 0; + wnd->attributes = 0; + wnd->dma_map_count = 0; + wnd->dma_map_addr = NULL; + wnd->nick[0] = 0; + init_timer(&wnd->hangcheck_timer); + wnd->scan_timestamp = 0; + init_timer(&wnd->iw_stats_timer); + wnd->iw_stats_interval = 10 * HZ; + wnd->ndis_pending_work = 0; + memset(&wnd->essid, 0, sizeof(wnd->essid)); + memset(&wnd->encr_info, 0, sizeof(wnd->encr_info)); + wnd->infrastructure_mode = Ndis802_11Infrastructure; + initialize_work(&wnd->ndis_work, ndis_worker, wnd); + wnd->iw_stats_enabled = TRUE; + + TRACE1("nmb: %p, pdo: %p, fdo: %p, attached: %p, next: %p", + nmb, pdo, fdo, fdo->attached, nmb->next_device); + + /* dispatch routines are called as Windows functions */ + for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) + drv_obj->major_func[i] = WIN_FUNC_PTR(IoPassIrpDown,2); + + drv_obj->major_func[IRP_MJ_PNP] = WIN_FUNC_PTR(NdisDispatchPnp,2); + drv_obj->major_func[IRP_MJ_POWER] = WIN_FUNC_PTR(NdisDispatchPower,2); + drv_obj->major_func[IRP_MJ_INTERNAL_DEVICE_CONTROL] = + WIN_FUNC_PTR(NdisDispatchDeviceControl,2); +// drv_obj->major_func[IRP_MJ_DEVICE_CONTROL] = +// WIN_FUNC_PTR(NdisDispatchDeviceControl,2); + EXIT2(return STATUS_SUCCESS); +} + +int init_ndis_driver(struct driver_object *drv_obj) +{ + ENTER1("%p", drv_obj); + drv_obj->drv_ext->add_device = NdisAddDevice; + return 0; +} + +int wrapndis_init(void) +{ + wrapndis_wq = create_singlethread_workqueue("wrapndis_wq"); + if (!wrapndis_wq) + EXIT1(return -ENOMEM); + wrapndis_worker_thread = wrap_worker_init(wrapndis_wq); + TRACE1("%p", wrapndis_worker_thread); + register_netdevice_notifier(&netdev_notifier); + return 0; +} + +void wrapndis_exit(void) +{ + unregister_netdevice_notifier(&netdev_notifier); + if (wrapndis_wq) + destroy_workqueue(wrapndis_wq); + TRACE1("%p", wrapndis_worker_thread); + if (wrapndis_worker_thread) + ObDereferenceObject(wrapndis_worker_thread); +} --- linux-2.6.27.orig/ubuntu/ndiswrapper/lin2win.h +++ linux-2.6.27/ubuntu/ndiswrapper/lin2win.h @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2006 Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifdef CONFIG_X86_64 + +/* Windows functions must have 32 bytes of shadow space for arguments + * above return address, irrespective of number of args. So argc >= 4 + */ + +#define alloc_win_stack_frame(argc) \ + "sub $(" #argc "+1)*8, %%rsp\n\t" +#define free_win_stack_frame(argc) \ + "add $(" #argc "+1)*8, %%rsp\n\t" + +/* m is index of Windows arg required; Windows arg 1 should be at + * 0(%rsp), arg 2 at 8(%rsp) and so on after the frame is allocated. +*/ + +#define lin2win_win_arg(m) "(" #m "-1)*8(%%rsp)" + +/* args for Windows function must be in clobber / output list */ + +#define outputs() \ + "=a" (_ret), "=c" (_dummy), "=d" (_dummy), \ + "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11) + +#define clobbers() "cc" + +#define LIN2WIN0(func) \ +({ \ + u64 _ret, _dummy; \ + register u64 r8 __asm__("r8"); \ + register u64 r9 __asm__("r9"); \ + register u64 r10 __asm__("r10"); \ + register u64 r11 __asm__("r11"); \ + __asm__ __volatile__( \ + alloc_win_stack_frame(4) \ + "callq *%[fptr]\n\t" \ + free_win_stack_frame(4) \ + : outputs() \ + : [fptr] "r" (func) \ + : clobbers()); \ + _ret; \ +}) + +#define LIN2WIN1(func, arg1) \ +({ \ + u64 _ret, _dummy; \ + register u64 r8 __asm__("r8"); \ + register u64 r9 __asm__("r9"); \ + register u64 r10 __asm__("r10"); \ + register u64 r11 __asm__("r11"); \ + __asm__ __volatile__( \ + alloc_win_stack_frame(4) \ + "callq *%[fptr]\n\t" \ + free_win_stack_frame(4) \ + : outputs() \ + : "c" (arg1), [fptr] "r" (func) \ + : clobbers()); \ + _ret; \ +}) + +#define LIN2WIN2(func, arg1, arg2) \ +({ \ + u64 _ret, _dummy; \ + register u64 r8 __asm__("r8"); \ + register u64 r9 __asm__("r9"); \ + register u64 r10 __asm__("r10"); \ + register u64 r11 __asm__("r11"); \ + __asm__ __volatile__( \ + alloc_win_stack_frame(4) \ + "callq *%[fptr]\n\t" \ + free_win_stack_frame(4) \ + : outputs() \ + : "c" (arg1), "d" (arg2), [fptr] "r" (func) \ + : clobbers()); \ + _ret; \ +}) + +#define LIN2WIN3(func, arg1, arg2, arg3) \ +({ \ + u64 _ret, _dummy; \ + register u64 r8 __asm__("r8") = (u64)arg3; \ + register u64 r9 __asm__("r9"); \ + register u64 r10 __asm__("r10"); \ + register u64 r11 __asm__("r11"); \ + __asm__ __volatile__( \ + alloc_win_stack_frame(4) \ + "callq *%[fptr]\n\t" \ + free_win_stack_frame(4) \ + : outputs() \ + : "c" (arg1), "d" (arg2), "r" (r8), \ + [fptr] "r" (func) \ + : clobbers()); \ + _ret; \ +}) + +#define LIN2WIN4(func, arg1, arg2, arg3, arg4) \ +({ \ + u64 _ret, _dummy; \ + register u64 r8 __asm__("r8") = (u64)arg3; \ + register u64 r9 __asm__("r9") = (u64)arg4; \ + register u64 r10 __asm__("r10"); \ + register u64 r11 __asm__("r11"); \ + __asm__ __volatile__( \ + alloc_win_stack_frame(4) \ + "callq *%[fptr]\n\t" \ + free_win_stack_frame(4) \ + : outputs() \ + : "c" (arg1), "d" (arg2), "r" (r8), "r" (r9), \ + [fptr] "r" (func) \ + : clobbers()); \ + _ret; \ +}) + +#define LIN2WIN5(func, arg1, arg2, arg3, arg4, arg5) \ +({ \ + u64 _ret, _dummy; \ + register u64 r8 __asm__("r8") = (u64)arg3; \ + register u64 r9 __asm__("r9") = (u64)arg4; \ + register u64 r10 __asm__("r10"); \ + register u64 r11 __asm__("r11"); \ + __asm__ __volatile__( \ + alloc_win_stack_frame(5) \ + "movq %[rarg5], " lin2win_win_arg(5) "\n\t" \ + "callq *%[fptr]\n\t" \ + free_win_stack_frame(5) \ + : outputs() \ + : "c" (arg1), "d" (arg2), "r" (r8), "r" (r9), \ + [rarg5] "ri" ((u64)arg5), \ + [fptr] "r" (func) \ + : clobbers()); \ + _ret; \ +}) + +#define LIN2WIN6(func, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + u64 _ret, _dummy; \ + register u64 r8 __asm__("r8") = (u64)arg3; \ + register u64 r9 __asm__("r9") = (u64)arg4; \ + register u64 r10 __asm__("r10"); \ + register u64 r11 __asm__("r11"); \ + __asm__ __volatile__( \ + alloc_win_stack_frame(6) \ + "movq %[rarg5], " lin2win_win_arg(5) "\n\t" \ + "movq %[rarg6], " lin2win_win_arg(6) "\n\t" \ + "callq *%[fptr]\n\t" \ + free_win_stack_frame(6) \ + : outputs() \ + : "c" (arg1), "d" (arg2), "r" (r8), "r" (r9), \ + [rarg5] "ri" ((u64)arg5), [rarg6] "ri" ((u64)arg6), \ + [fptr] "r" (func) \ + : clobbers()); \ + _ret; \ +}) + +#else // CONFIG_X86_64 + +#define LIN2WIN1(func, arg1) \ +({ \ + TRACE6("calling %p", func); \ + func(arg1); \ +}) +#define LIN2WIN2(func, arg1, arg2) \ +({ \ + TRACE6("calling %p", func); \ + func(arg1, arg2); \ +}) +#define LIN2WIN3(func, arg1, arg2, arg3) \ +({ \ + TRACE6("calling %p", func); \ + func(arg1, arg2, arg3); \ +}) +#define LIN2WIN4(func, arg1, arg2, arg3, arg4) \ +({ \ + TRACE6("calling %p", func); \ + func(arg1, arg2, arg3, arg4); \ +}) +#define LIN2WIN5(func, arg1, arg2, arg3, arg4, arg5) \ +({ \ + TRACE6("calling %p", func); \ + func(arg1, arg2, arg3, arg4, arg5); \ +}) +#define LIN2WIN6(func, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + TRACE6("calling %p", func); \ + func(arg1, arg2, arg3, arg4, arg5, arg6); \ +}) + +#endif // CONFIG_X86_64 --- linux-2.6.27.orig/ubuntu/ndiswrapper/usb.h +++ linux-2.6.27/ubuntu/ndiswrapper/usb.h @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2004 Jan Kiszka + * Copyright (C) 2005 Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _USB_H_ +#define _USB_H_ + +#include "ntoskernel.h" + +#define IOCTL_INTERNAL_USB_SUBMIT_URB 0x00220003 +#define IOCTL_INTERNAL_USB_RESET_PORT 0x00220007 +#define IOCTL_INTERNAL_USB_GET_PORT_STATUS 0x00220013 +#define IOCTL_INTERNAL_USB_CYCLE_PORT 0x0022001F +#define IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION 0x00220027 + +#define URB_FUNCTION_SELECT_CONFIGURATION 0x0000 +#define URB_FUNCTION_SELECT_INTERFACE 0x0001 +#define URB_FUNCTION_ABORT_PIPE 0x0002 +#define URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL 0x0003 +#define URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL 0x0004 +#define URB_FUNCTION_GET_FRAME_LENGTH 0x0005 +#define URB_FUNCTION_SET_FRAME_LENGTH 0x0006 +#define URB_FUNCTION_GET_CURRENT_FRAME_NUMBER 0x0007 +#define URB_FUNCTION_CONTROL_TRANSFER 0x0008 +#define URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER 0x0009 +#define URB_FUNCTION_ISOCH_TRANSFER 0x000A +#define URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE 0x000B +#define URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE 0x000C +#define URB_FUNCTION_SET_FEATURE_TO_DEVICE 0x000D +#define URB_FUNCTION_SET_FEATURE_TO_INTERFACE 0x000E +#define URB_FUNCTION_SET_FEATURE_TO_ENDPOINT 0x000F +#define URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE 0x0010 +#define URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE 0x0011 +#define URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT 0x0012 +#define URB_FUNCTION_GET_STATUS_FROM_DEVICE 0x0013 +#define URB_FUNCTION_GET_STATUS_FROM_INTERFACE 0x0014 +#define URB_FUNCTION_GET_STATUS_FROM_ENDPOINT 0x0015 +#define URB_FUNCTION_RESERVED_0X0016 0x0016 +#define URB_FUNCTION_VENDOR_DEVICE 0x0017 +#define URB_FUNCTION_VENDOR_INTERFACE 0x0018 +#define URB_FUNCTION_VENDOR_ENDPOINT 0x0019 +#define URB_FUNCTION_CLASS_DEVICE 0x001A +#define URB_FUNCTION_CLASS_INTERFACE 0x001B +#define URB_FUNCTION_CLASS_ENDPOINT 0x001C +#define URB_FUNCTION_RESERVE_0X001D 0x001D +#define URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL 0x001E +#define URB_FUNCTION_CLASS_OTHER 0x001F +#define URB_FUNCTION_VENDOR_OTHER 0x0020 +#define URB_FUNCTION_GET_STATUS_FROM_OTHER 0x0021 +#define URB_FUNCTION_CLEAR_FEATURE_TO_OTHER 0x0022 +#define URB_FUNCTION_SET_FEATURE_TO_OTHER 0x0023 +#define URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT 0x0024 +#define URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT 0x0025 +#define URB_FUNCTION_GET_CONFIGURATION 0x0026 +#define URB_FUNCTION_GET_INTERFACE 0x0027 +#define URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE 0x0028 +#define URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE 0x0029 +#define URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR 0x002A +#define URB_FUNCTION_RESERVE_0X002B 0x002B +#define URB_FUNCTION_RESERVE_0X002C 0x002C +#define URB_FUNCTION_RESERVE_0X002D 0x002D +#define URB_FUNCTION_RESERVE_0X002E 0x002E +#define URB_FUNCTION_RESERVE_0X002F 0x002F +// USB 2.0 calls start at 0x0030 +#define URB_FUNCTION_SYNC_RESET_PIPE 0x0030 +#define URB_FUNCTION_SYNC_CLEAR_STALL 0x0031 +#define URB_FUNCTION_CONTROL_TRANSFER_EX 0x0032 + +#define USBD_PF_CHANGE_MAX_PACKET 0x00000001 + +#define USBD_TRANSFER_DIRECTION_OUT 0 +#define USBD_TRANSFER_DIRECTION_IN 1 + +#define USBD_SHORT_TRANSFER_OK 0x00000002 +#define USBD_START_ISO_TRANSFER_ASAP 0x00000004 +#define USBD_DEFAULT_PIPE_TRANSFER 0x00000008 + +#define USBD_TRANSFER_DIRECTION(flags) \ + ((flags) & USBD_TRANSFER_DIRECTION_IN) + +enum pipe_type {UsbdPipeTypeControl = USB_ENDPOINT_XFER_CONTROL, + UsbdPipeTypeIsochronous = USB_ENDPOINT_XFER_ISOC, + UsbdPipeTypeBulk = USB_ENDPOINT_XFER_BULK, + UsbdPipeTypeInterrupt = USB_ENDPOINT_XFER_INT}; + +#define USBD_IS_BULK_PIPE(pipe_handle) \ + (((pipe_handle)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) \ + == USB_ENDPOINT_XFER_BULK) + +#define USBD_IS_INT_PIPE(pipe_handle) \ + (((pipe_handle)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) \ + == USB_ENDPOINT_XFER_INT) + +#define USBD_PORT_ENABLED 0x00000001 +#define USBD_PORT_CONNECTED 0x00000002 + +typedef LONG USBD_STATUS; + +#define USBD_STATUS_SUCCESS 0x0 +#define USBD_STATUS_PENDING 0x40000000 +#define USBD_STATUS_CANCELED 0x00010000 + +#define USBD_STATUS_CRC 0xC0000001 +#define USBD_STATUS_BTSTUFF 0xC0000002 +#define USBD_STATUS_DATA_TOGGLE_MISMATCH 0xC0000003 +#define USBD_STATUS_STALL_PID 0xC0000004 +#define USBD_STATUS_DEV_NOT_RESPONDING 0xC0000005 +#define USBD_STATUS_PID_CHECK_FAILURE 0xC0000006 +#define USBD_STATUS_UNEXPECTED_PID 0xC0000007 +#define USBD_STATUS_DATA_OVERRUN 0xC0000008 +#define USBD_STATUS_DATA_UNDERRUN 0xC0000009 +#define USBD_STATUS_RESERVED1 0xC000000A +#define USBD_STATUS_RESERVED2 0xC000000B +#define USBD_STATUS_BUFFER_OVERRUN 0xC000000C +#define USBD_STATUS_BUFFER_UNDERRUN 0xC000000D +#define USBD_STATUS_NOT_ACCESSED 0xC000000F +#define USBD_STATUS_FIFO 0xC0000010 +#define USBD_STATUS_XACT_ERROR 0xC0000011 +#define USBD_STATUS_BABBLE_DETECTED 0xC0000012 +#define USBD_STATUS_DATA_BUFFER_ERROR 0xC0000013 + +#define USBD_STATUS_NOT_SUPPORTED 0xC0000E00 +#define USBD_STATUS_BUFFER_TOO_SMALL 0xC0003000 +#define USBD_STATUS_TIMEOUT 0xC0006000 +#define USBD_STATUS_DEVICE_GONE 0xC0007000 + +#define USBD_STATUS_NO_MEMORY 0x80000100 +#define USBD_STATUS_INVALID_URB_FUNCTION 0x80000200 +#define USBD_STATUS_INVALID_PARAMETER 0x80000300 +#define USBD_STATUS_REQUEST_FAILED 0x80000500 +#define USBD_STATUS_INVALID_PIPE_HANDLE 0x80000600 +#define USBD_STATUS_ERROR_SHORT_TRANSFER 0x80000900 + +#define USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE PAGE_SIZE + +struct urb_hcd_area { + void *reserved8[8]; +}; + +typedef struct usb_endpoint_descriptor *usbd_pipe_handle; +typedef struct usb_descriptor_header usb_common_descriptor_t; + +struct usbd_pipe_information { + USHORT wMaxPacketSize; + UCHAR bEndpointAddress; + UCHAR bInterval; + enum pipe_type type; + usbd_pipe_handle handle; + ULONG max_tx_size; + ULONG flags; +}; + +struct usbd_interface_information { + USHORT bLength; + UCHAR bInterfaceNumber; + UCHAR bAlternateSetting; + UCHAR bInterfaceClass; + UCHAR bInterfaceSubClass; + UCHAR bInterfaceProtocol; + UCHAR reserved; + void *handle; + ULONG bNumEndpoints; + struct usbd_pipe_information pipes[1]; +}; + +struct usbd_interface_list_entry { + struct usb_interface_descriptor *intf_desc; + struct usbd_interface_information *intf; +}; + +struct nt_urb_header { + USHORT length; + USHORT function; + USBD_STATUS status; + void *usbd_dev_handle; + ULONG usbd_flags; +}; + +struct usbd_select_interface { + struct nt_urb_header header; + void *handle; + struct usbd_interface_information intf; +}; + +struct usbd_select_configuration { + struct nt_urb_header header; + struct usb_config_descriptor *config; + void *handle; + struct usbd_interface_information intf; +}; + +struct usbd_control_descriptor_request { + struct nt_urb_header header; + void *reserved; + ULONG reserved0; + ULONG transfer_buffer_length; + void *transfer_buffer; + struct mdl *mdl; + union nt_urb *urb_link; + struct urb_hcd_area hca; + USHORT reserved1; + UCHAR index; + UCHAR desc_type; + USHORT language_id; + USHORT reserved2; +}; + +struct usbd_bulk_or_intr_transfer { + struct nt_urb_header header; + usbd_pipe_handle pipe_handle; + ULONG transfer_flags; + ULONG transfer_buffer_length; + void *transfer_buffer; + struct mdl *mdl; + union nt_urb *urb_link; + struct urb_hcd_area hca; +}; + +struct usbd_pipe_request { + struct nt_urb_header header; + usbd_pipe_handle pipe_handle; +}; + +struct usbd_vendor_or_class_request { + struct nt_urb_header header; + void *reserved; + ULONG transfer_flags; + ULONG transfer_buffer_length; + void *transfer_buffer; + struct mdl *mdl; + union nt_urb *link; + struct urb_hcd_area hca; + UCHAR reserved_bits; + UCHAR request; + USHORT value; + USHORT index; + USHORT reserved1; +}; + +struct urb_control_feature_request { + struct nt_urb_header header; + void *reserved; + ULONG reserved2; + ULONG reserved3; + void *reserved4; + struct mdl *reserved5; + union nt_urb *link; + struct urb_hcd_area hca; + USHORT reserved0; + USHORT feature_selector; + USHORT index; + USHORT reserved1; +}; + +struct urb_control_get_status_request { + struct nt_urb_header header; + void *reserved; + ULONG reserved0; + ULONG transfer_buffer_length; + void *transfer_buffer; + struct mdl *mdl; + union nt_urb *link; + struct urb_hcd_area hca; + UCHAR reserved1[4]; + USHORT index; + USHORT reserved2; +}; + +struct usbd_iso_packet_desc { + ULONG offset; + ULONG length; + USBD_STATUS status; +}; + +struct usbd_isochronous_transfer { + struct nt_urb_header header; + usbd_pipe_handle pipe_handle; + ULONG transfer_flags; + ULONG transfer_buffer_length; + void *transfer_buffer; + struct mdl *mdl; + union nt_urb *urb_link; + struct urb_hcd_area hca; + ULONG start_frame; + ULONG number_of_packets; + ULONG error_count; + struct usbd_iso_packet_desc iso_packet[1]; +}; + +union nt_urb { + struct nt_urb_header header; + struct usbd_select_interface select_intf; + struct usbd_select_configuration select_conf; + struct usbd_bulk_or_intr_transfer bulk_int_transfer; + struct usbd_control_descriptor_request control_desc; + struct usbd_vendor_or_class_request vendor_class_request; + struct usbd_isochronous_transfer isochronous; + struct usbd_pipe_request pipe_req; + struct urb_control_feature_request feat_req; + struct urb_control_get_status_request status_req; +}; + +struct usbd_bus_interface_usbdi { + USHORT Size; + USHORT Version; + void *Context; + void *InterfaceReference; + void *InterfaceDereference; + void *GetUSBDIVersion; + void *QueryBusTime; + void *SubmitIsoOutUrb; + void *QueryBusInformation; + /* version 1 and above have following field */ + void *IsDeviceHighSpeed; + /* version 2 (and above) have following field */ + void *LogEntry; +}; + +struct usbd_bus_information_level { + ULONG TotalBandwidth; + ULONG ConsumedBandwidth; + /* level 1 and above have following fields */ + ULONG ControllerNameLength; + wchar_t ControllerName[1]; +}; + +#define USBDI_VERSION_XP 0x00000500 // Windows XP +#define USB_HCD_CAPS_SUPPORTS_RT_THREADS 0x00000001 +#define USB_BUSIF_USBDI_VERSION_0 0x0000 +#define USB_BUSIF_USBDI_VERSION_1 0x0001 +#define USB_BUSIF_USBDI_VERSION_2 0x0002 + +struct usbd_version_info { + ULONG usbdi_version; + ULONG supported_usb_version; +}; + +struct usbd_idle_callback { + void *callback; + void *context; +}; + +#define NT_URB_STATUS(nt_urb) ((nt_urb)->header.status) + +NTSTATUS wrap_submit_irp(struct device_object *pdo, struct irp *irp); +void wrap_suspend_urbs(struct wrap_device *wd); +void wrap_resume_urbs(struct wrap_device *wd); + +void USBD_InterfaceGetUSBDIVersion(void *context, + struct usbd_version_info *version_info, + ULONG *hcd_capa) wstdcall; +BOOLEAN USBD_InterfaceIsDeviceHighSpeed(void *context) wstdcall; +void USBD_InterfaceReference(void *context) wstdcall; +void USBD_InterfaceDereference(void *context) wstdcall; +NTSTATUS USBD_InterfaceQueryBusTime(void *context, ULONG *frame) wstdcall; +NTSTATUS USBD_InterfaceSubmitIsoOutUrb(void *context, + union nt_urb *nt_urb) wstdcall; +NTSTATUS USBD_InterfaceQueryBusInformation(void *context, ULONG level, void *buf, + ULONG *buf_length, + ULONG *buf_actual_length) wstdcall; +NTSTATUS USBD_InterfaceLogEntry(void *context, ULONG driver_tag, ULONG enum_tag, + ULONG p1, ULONG p2) wstdcall; + +#endif /* USB_H */ --- linux-2.6.27.orig/ubuntu/ndiswrapper/mkexport.sh +++ linux-2.6.27/ubuntu/ndiswrapper/mkexport.sh @@ -0,0 +1,42 @@ +#! /bin/sh + +# Generate exports symbol table from C files + +input="$1" +output="$2" +exports=$(basename "$output" .h) +exec >"$output" + +echo "/* automatically generated from src */"; + +sed -n -e '/^\(wstdcall\|wfastcall\|noregparm\|__attribute__\)/{ +:more +N +s/\([^{]\)$/\1/ +t more +s/\n{$/;/ +p +}' $input + +echo "#ifdef CONFIG_X86_64"; + +sed -n \ + -e 's/.*WIN_FUNC(\([^\,]\+\) *\, *\([0-9]\+\)).*/'\ +'WIN_FUNC_DECL(\1, \2)/p' \ + -e 's/.*WIN_FUNC_PTR(\([^\,]\+\) *\, *\([0-9]\+\)).*/'\ +'WIN_FUNC_DECL(\1, \2)/p' $input | sort -u + +echo "#endif" +echo "extern struct wrap_export $exports[];" +echo "struct wrap_export $exports[] = {" + +sed -n \ + -e 's/.*WIN_FUNC(_win_\([^\,]\+\) *\, *\([0-9]\+\)).*/'\ +' WIN_WIN_SYMBOL(\1, \2),/p' \ + -e 's/.*WIN_FUNC(\([^\,]\+\) *\, *\([0-9]\+\)).*/'\ +' WIN_SYMBOL(\1, \2),/p' \ + -e 's/.*WIN_SYMBOL_MAP(\("[^"]\+"\)[ ,\n]\+\([^)]\+\)).*/'\ +' {\1, (generic_func)\2},/p' $input | sort -u + +echo " {NULL, NULL}" +echo "};" --- linux-2.6.27.orig/ubuntu/ndiswrapper/wrapper.h +++ linux-2.6.27/ubuntu/ndiswrapper/wrapper.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef WRAPPER_H +#define WRAPPER_H + +extern char *if_name; +extern int proc_uid; +extern int proc_gid; +extern int hangcheck_interval; + +#endif /* WRAPPER_H */ --- linux-2.6.27.orig/ubuntu/ndiswrapper/pe_linker.h +++ linux-2.6.27/ubuntu/ndiswrapper/pe_linker.h @@ -0,0 +1,993 @@ +/* + * This file is an excerpt of winnt.h from WINE, which bears the + * following copyright: + * + * Win32 definitions for Windows NT + * + * Copyright 1996 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * File formats definitions + */ +typedef struct _IMAGE_DOS_HEADER { + WORD e_magic; /* 00: MZ Header signature */ + WORD e_cblp; /* 02: Bytes on last page of file */ + WORD e_cp; /* 04: Pages in file */ + WORD e_crlc; /* 06: Relocations */ + WORD e_cparhdr; /* 08: Size of header in paragraphs */ + WORD e_minalloc; /* 0a: Minimum extra paragraphs needed */ + WORD e_maxalloc; /* 0c: Maximum extra paragraphs needed */ + WORD e_ss; /* 0e: Initial (relative) SS value */ + WORD e_sp; /* 10: Initial SP value */ + WORD e_csum; /* 12: Checksum */ + WORD e_ip; /* 14: Initial IP value */ + WORD e_cs; /* 16: Initial (relative) CS value */ + WORD e_lfarlc; /* 18: File address of relocation table */ + WORD e_ovno; /* 1a: Overlay number */ + WORD e_res[4]; /* 1c: Reserved words */ + WORD e_oemid; /* 24: OEM identifier (for e_oeminfo) */ + WORD e_oeminfo; /* 26: OEM information; e_oemid specific */ + WORD e_res2[10]; /* 28: Reserved words */ + DWORD e_lfanew; /* 3c: Offset to extended header */ +} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; + +#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */ +#define IMAGE_OS2_SIGNATURE 0x454E /* NE */ +#define IMAGE_OS2_SIGNATURE_LE 0x454C /* LE */ +#define IMAGE_OS2_SIGNATURE_LX 0x584C /* LX */ +#define IMAGE_VXD_SIGNATURE 0x454C /* LE */ +#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ + +/* + * This is the Windows executable (NE) header. + * the name IMAGE_OS2_HEADER is misleading, but in the SDK this way. + */ +typedef struct +{ + WORD ne_magic; /* 00 NE signature 'NE' */ + BYTE ne_ver; /* 02 Linker version number */ + BYTE ne_rev; /* 03 Linker revision number */ + WORD ne_enttab; /* 04 Offset to entry table relative to NE */ + WORD ne_cbenttab; /* 06 Length of entry table in bytes */ + LONG ne_crc; /* 08 Checksum */ + WORD ne_flags; /* 0c Flags about segments in this file */ + WORD ne_autodata; /* 0e Automatic data segment number */ + WORD ne_heap; /* 10 Initial size of local heap */ + WORD ne_stack; /* 12 Initial size of stack */ + DWORD ne_csip; /* 14 Initial CS:IP */ + DWORD ne_sssp; /* 18 Initial SS:SP */ + WORD ne_cseg; /* 1c # of entries in segment table */ + WORD ne_cmod; /* 1e # of entries in module reference tab. */ + WORD ne_cbnrestab; /* 20 Length of nonresident-name table */ + WORD ne_segtab; /* 22 Offset to segment table */ + WORD ne_rsrctab; /* 24 Offset to resource table */ + WORD ne_restab; /* 26 Offset to resident-name table */ + WORD ne_modtab; /* 28 Offset to module reference table */ + WORD ne_imptab; /* 2a Offset to imported name table */ + DWORD ne_nrestab; /* 2c Offset to nonresident-name table */ + WORD ne_cmovent; /* 30 # of movable entry points */ + WORD ne_align; /* 32 Logical sector alignment shift count */ + WORD ne_cres; /* 34 # of resource segments */ + BYTE ne_exetyp; /* 36 Flags indicating target OS */ + BYTE ne_flagsothers; /* 37 Additional information flags */ + WORD ne_pretthunks; /* 38 Offset to return thunks */ + WORD ne_psegrefbytes; /* 3a Offset to segment ref. bytes */ + WORD ne_swaparea; /* 3c Reserved by Microsoft */ + WORD ne_expver; /* 3e Expected Windows version number */ +} IMAGE_OS2_HEADER, *PIMAGE_OS2_HEADER; + +typedef struct _IMAGE_VXD_HEADER { + WORD e32_magic; + BYTE e32_border; + BYTE e32_worder; + DWORD e32_level; + WORD e32_cpu; + WORD e32_os; + DWORD e32_ver; + DWORD e32_mflags; + DWORD e32_mpages; + DWORD e32_startobj; + DWORD e32_eip; + DWORD e32_stackobj; + DWORD e32_esp; + DWORD e32_pagesize; + DWORD e32_lastpagesize; + DWORD e32_fixupsize; + DWORD e32_fixupsum; + DWORD e32_ldrsize; + DWORD e32_ldrsum; + DWORD e32_objtab; + DWORD e32_objcnt; + DWORD e32_objmap; + DWORD e32_itermap; + DWORD e32_rsrctab; + DWORD e32_rsrccnt; + DWORD e32_restab; + DWORD e32_enttab; + DWORD e32_dirtab; + DWORD e32_dircnt; + DWORD e32_fpagetab; + DWORD e32_frectab; + DWORD e32_impmod; + DWORD e32_impmodcnt; + DWORD e32_impproc; + DWORD e32_pagesum; + DWORD e32_datapage; + DWORD e32_preload; + DWORD e32_nrestab; + DWORD e32_cbnrestab; + DWORD e32_nressum; + DWORD e32_autodata; + DWORD e32_debuginfo; + DWORD e32_debuglen; + DWORD e32_instpreload; + DWORD e32_instdemand; + DWORD e32_heapsize; + BYTE e32_res3[12]; + DWORD e32_winresoff; + DWORD e32_winreslen; + WORD e32_devid; + WORD e32_ddkver; +} IMAGE_VXD_HEADER, *PIMAGE_VXD_HEADER; + +/* These defines describe the meanings of the bits in the + Characteristics field */ + +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 /* No relocation info */ +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 +#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 +#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 +#define IMAGE_FILE_16BIT_MACHINE 0x0040 +#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 +#define IMAGE_FILE_32BIT_MACHINE 0x0100 +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 +#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 +#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 +#define IMAGE_FILE_SYSTEM 0x1000 +#define IMAGE_FILE_DLL 0x2000 +#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 + +/* These are the settings of the Machine field. */ +#define IMAGE_FILE_MACHINE_UNKNOWN 0 +#define IMAGE_FILE_MACHINE_I860 0x014d +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_R3000 0x0162 +#define IMAGE_FILE_MACHINE_R4000 0x0166 +#define IMAGE_FILE_MACHINE_R10000 0x0168 +#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 +#define IMAGE_FILE_MACHINE_ALPHA 0x0184 +#define IMAGE_FILE_MACHINE_SH3 0x01a2 +#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 +#define IMAGE_FILE_MACHINE_SH3E 0x01a4 +#define IMAGE_FILE_MACHINE_SH4 0x01a6 +#define IMAGE_FILE_MACHINE_SH5 0x01a8 +#define IMAGE_FILE_MACHINE_ARM 0x01c0 +#define IMAGE_FILE_MACHINE_THUMB 0x01c2 +#define IMAGE_FILE_MACHINE_AM33 0x01d3 +#define IMAGE_FILE_MACHINE_POWERPC 0x01f0 +#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 +#define IMAGE_FILE_MACHINE_IA64 0x0200 +#define IMAGE_FILE_MACHINE_MIPS16 0x0266 +#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 +#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 +#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 +#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 +#define IMAGE_FILE_MACHINE_TRICORE 0x0520 +#define IMAGE_FILE_MACHINE_CEF 0x0cef +#define IMAGE_FILE_MACHINE_EBC 0x0ebc +#define IMAGE_FILE_MACHINE_AMD64 0x8664 +#define IMAGE_FILE_MACHINE_M32R 0x9041 +#define IMAGE_FILE_MACHINE_CEE 0xc0ee + +#define IMAGE_SIZEOF_FILE_HEADER 20 +#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56 +#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28 +#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER32 224 +#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER64 240 +#define IMAGE_SIZEOF_SHORT_NAME 8 +#define IMAGE_SIZEOF_SECTION_HEADER 40 +#define IMAGE_SIZEOF_SYMBOL 18 +#define IMAGE_SIZEOF_AUX_SYMBOL 18 +#define IMAGE_SIZEOF_RELOCATION 10 +#define IMAGE_SIZEOF_BASE_RELOCATION 8 +#define IMAGE_SIZEOF_LINENUMBER 6 +#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + +/* Possible Magic values */ +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x010b +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x020b +#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x0107 + +#ifdef CONFIG_X86_64 +#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL_HEADER64 +#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR64_MAGIC +#else +#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL_HEADER32 +#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR32_MAGIC +#endif + +/* These are indexes into the DataDirectory array */ +#define IMAGE_FILE_EXPORT_DIRECTORY 0 +#define IMAGE_FILE_IMPORT_DIRECTORY 1 +#define IMAGE_FILE_RESOURCE_DIRECTORY 2 +#define IMAGE_FILE_EXCEPTION_DIRECTORY 3 +#define IMAGE_FILE_SECURITY_DIRECTORY 4 +#define IMAGE_FILE_BASE_RELOCATION_TABLE 5 +#define IMAGE_FILE_DEBUG_DIRECTORY 6 +#define IMAGE_FILE_DESCRIPTION_STRING 7 +#define IMAGE_FILE_MACHINE_VALUE 8 /* Mips */ +#define IMAGE_FILE_THREAD_LOCAL_STORAGE 9 +#define IMAGE_FILE_CALLBACK_DIRECTORY 10 + +/* Directory Entries, indices into the DataDirectory array */ + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* (MIPS GP) */ +#define IMAGE_DIRECTORY_ENTRY_TLS 9 +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 +#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */ +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 + +/* Subsystem Values */ + +#define IMAGE_SUBSYSTEM_UNKNOWN 0 +#define IMAGE_SUBSYSTEM_NATIVE 1 +#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 /* Windows GUI subsystem */ +#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 /* Windows character subsystem */ +#define IMAGE_SUBSYSTEM_OS2_CUI 5 +#define IMAGE_SUBSYSTEM_POSIX_CUI 7 +#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 /* native Win9x driver */ +#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 /* Windows CE subsystem */ +#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 +#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 +#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 +#define IMAGE_SUBSYSTEM_EFI_ROM 13 +#define IMAGE_SUBSYSTEM_XBOX 14 + +typedef struct _IMAGE_FILE_HEADER { + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; + +typedef struct _IMAGE_DATA_DIRECTORY { + DWORD VirtualAddress; + DWORD Size; +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + +typedef struct _IMAGE_OPTIONAL_HEADER32 { + + /* Standard fields */ + + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + + /* NT additional fields */ + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; + +typedef struct _IMAGE_OPTIONAL_HEADER64 { + + /* Standard fields */ + + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + + /* NT additional fields */ + ULONGLONG ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + ULONGLONG SizeOfStackReserve; + ULONGLONG SizeOfStackCommit; + ULONGLONG SizeOfHeapReserve; + ULONGLONG SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; + +#ifdef CONFIG_X86_64 +typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER; +typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER; +#else +typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER; +typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER; +#endif + +typedef struct _IMAGE_NT_HEADERS32 { + DWORD Signature; /* "PE"\0\0 */ /* 0x00 */ + IMAGE_FILE_HEADER FileHeader; /* 0x04 */ + IMAGE_OPTIONAL_HEADER32 OptionalHeader; /* 0x18 */ +} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; + +typedef struct _IMAGE_NT_HEADERS64 { + DWORD Signature; /* "PE"\0\0 */ /* 0x00 */ + IMAGE_FILE_HEADER FileHeader; /* 0x04 */ + IMAGE_OPTIONAL_HEADER64 OptionalHeader; /* 0x18 */ +} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64; + +#ifdef CONFIG_X86_64 +typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS; +typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS; +#else +typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; +typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; +#endif + +#define IMAGE_SIZEOF_SHORT_NAME 8 + +typedef struct _IMAGE_SECTION_HEADER { + BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; + union { + DWORD PhysicalAddress; + DWORD VirtualSize; + } Misc; + DWORD VirtualAddress; + DWORD SizeOfRawData; + DWORD PointerToRawData; + DWORD PointerToRelocations; + DWORD PointerToLinenumbers; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD Characteristics; +} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; + +#define IMAGE_SIZEOF_SECTION_HEADER 40 + +#define IMAGE_FIRST_SECTION(ntheader) \ +((PIMAGE_SECTION_HEADER)((LPBYTE)&((PIMAGE_NT_HEADERS)(ntheader))->OptionalHeader + \ +((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader)) + +/* These defines are for the Characteristics bitfield. */ +/* #define IMAGE_SCN_TYPE_REG 0x00000000 - Reserved */ +/* #define IMAGE_SCN_TYPE_DSECT 0x00000001 - Reserved */ +/* #define IMAGE_SCN_TYPE_NOLOAD 0x00000002 - Reserved */ +/* #define IMAGE_SCN_TYPE_GROUP 0x00000004 - Reserved */ +#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* Reserved */ +/* #define IMAGE_SCN_TYPE_COPY 0x00000010 - Reserved */ + +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 + +#define IMAGE_SCN_LNK_OTHER 0x00000100 +#define IMAGE_SCN_LNK_INFO 0x00000200 +/* #define IMAGE_SCN_TYPE_OVER 0x00000400 - Reserved */ +#define IMAGE_SCN_LNK_REMOVE 0x00000800 +#define IMAGE_SCN_LNK_COMDAT 0x00001000 + +/* 0x00002000 - Reserved */ +/* #define IMAGE_SCN_MEM_PROTECTED 0x00004000 - Obsolete */ +#define IMAGE_SCN_MEM_FARDATA 0x00008000 + +/* #define IMAGE_SCN_MEM_SYSHEAP 0x00010000 - Obsolete */ +#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 +#define IMAGE_SCN_MEM_16BIT 0x00020000 +#define IMAGE_SCN_MEM_LOCKED 0x00040000 +#define IMAGE_SCN_MEM_PRELOAD 0x00080000 + +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 +#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 +#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 /* Default */ +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 +#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 +#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 +#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 +#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 +#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 +#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 +#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 +/* 0x00F00000 - Unused */ +#define IMAGE_SCN_ALIGN_MASK 0x00F00000 + +#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 + + +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 +#define IMAGE_SCN_MEM_SHARED 0x10000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 + +typedef struct _IMAGE_SYMBOL { + union { + BYTE ShortName[8]; + struct { + DWORD Short; + DWORD Long; + } Name; + DWORD LongName[2]; + } N; + DWORD Value; + SHORT SectionNumber; + WORD Type; + BYTE StorageClass; + BYTE NumberOfAuxSymbols; +} IMAGE_SYMBOL; +typedef IMAGE_SYMBOL *PIMAGE_SYMBOL; + +#define IMAGE_SIZEOF_SYMBOL 18 + +typedef struct _IMAGE_LINENUMBER { + union { + DWORD SymbolTableIndex; + DWORD VirtualAddress; + } Type; + WORD Linenumber; +} IMAGE_LINENUMBER; +typedef IMAGE_LINENUMBER *PIMAGE_LINENUMBER; + +#define IMAGE_SIZEOF_LINENUMBER 6 + +typedef union _IMAGE_AUX_SYMBOL { + struct { + DWORD TagIndex; + union { + struct { + WORD Linenumber; + WORD Size; + } LnSz; + DWORD TotalSize; + } Misc; + union { + struct { + DWORD PointerToLinenumber; + DWORD PointerToNextFunction; + } Function; + struct { + WORD Dimension[4]; + } Array; + } FcnAry; + WORD TvIndex; + } Sym; + struct { + BYTE Name[IMAGE_SIZEOF_SYMBOL]; + } File; + struct { + DWORD Length; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD CheckSum; + SHORT Number; + BYTE Selection; + } Section; +} IMAGE_AUX_SYMBOL; +typedef IMAGE_AUX_SYMBOL *PIMAGE_AUX_SYMBOL; + +#define IMAGE_SIZEOF_AUX_SYMBOL 18 + +#define IMAGE_SYM_UNDEFINED (SHORT)0 +#define IMAGE_SYM_ABSOLUTE (SHORT)-1 +#define IMAGE_SYM_DEBUG (SHORT)-2 + +#define IMAGE_SYM_TYPE_NULL 0x0000 +#define IMAGE_SYM_TYPE_VOID 0x0001 +#define IMAGE_SYM_TYPE_CHAR 0x0002 +#define IMAGE_SYM_TYPE_SHORT 0x0003 +#define IMAGE_SYM_TYPE_INT 0x0004 +#define IMAGE_SYM_TYPE_LONG 0x0005 +#define IMAGE_SYM_TYPE_FLOAT 0x0006 +#define IMAGE_SYM_TYPE_DOUBLE 0x0007 +#define IMAGE_SYM_TYPE_STRUCT 0x0008 +#define IMAGE_SYM_TYPE_UNION 0x0009 +#define IMAGE_SYM_TYPE_ENUM 0x000A +#define IMAGE_SYM_TYPE_MOE 0x000B +#define IMAGE_SYM_TYPE_BYTE 0x000C +#define IMAGE_SYM_TYPE_WORD 0x000D +#define IMAGE_SYM_TYPE_UINT 0x000E +#define IMAGE_SYM_TYPE_DWORD 0x000F +#define IMAGE_SYM_TYPE_PCODE 0x8000 + +#define IMAGE_SYM_DTYPE_NULL 0 +#define IMAGE_SYM_DTYPE_POINTER 1 +#define IMAGE_SYM_DTYPE_FUNCTION 2 +#define IMAGE_SYM_DTYPE_ARRAY 3 + +#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE )-1 +#define IMAGE_SYM_CLASS_NULL 0x0000 +#define IMAGE_SYM_CLASS_AUTOMATIC 0x0001 +#define IMAGE_SYM_CLASS_EXTERNAL 0x0002 +#define IMAGE_SYM_CLASS_STATIC 0x0003 +#define IMAGE_SYM_CLASS_REGISTER 0x0004 +#define IMAGE_SYM_CLASS_EXTERNAL_DEF 0x0005 +#define IMAGE_SYM_CLASS_LABEL 0x0006 +#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 0x0007 +#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 0x0008 +#define IMAGE_SYM_CLASS_ARGUMENT 0x0009 +#define IMAGE_SYM_CLASS_STRUCT_TAG 0x000A +#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 0x000B +#define IMAGE_SYM_CLASS_UNION_TAG 0x000C +#define IMAGE_SYM_CLASS_TYPE_DEFINITION 0x000D +#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 0x000E +#define IMAGE_SYM_CLASS_ENUM_TAG 0x000F +#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 0x0010 +#define IMAGE_SYM_CLASS_REGISTER_PARAM 0x0011 +#define IMAGE_SYM_CLASS_BIT_FIELD 0x0012 + +#define IMAGE_SYM_CLASS_FAR_EXTERNAL 0x0044 +#define IMAGE_SYM_CLASS_BLOCK 0x0064 +#define IMAGE_SYM_CLASS_FUNCTION 0x0065 +#define IMAGE_SYM_CLASS_END_OF_STRUCT 0x0066 +#define IMAGE_SYM_CLASS_FILE 0x0067 +#define IMAGE_SYM_CLASS_SECTION 0x0068 +#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069 + +#define N_BTMASK 0x000F +#define N_TMASK 0x0030 +#define N_TMASK1 0x00C0 +#define N_TMASK2 0x00F0 +#define N_BTSHFT 4 +#define N_TSHIFT 2 + +#define BTYPE(x) ((x) & N_BTMASK) + +#ifndef ISPTR +#define ISPTR(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT)) +#endif + +#ifndef ISFCN +#define ISFCN(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT)) +#endif + +#ifndef ISARY +#define ISARY(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT)) +#endif + +#ifndef ISTAG +#define ISTAG(x) ((x)==IMAGE_SYM_CLASS_STRUCT_TAG || (x)==IMAGE_SYM_CLASS_UNION_TAG || (x)==IMAGE_SYM_CLASS_ENUM_TAG) +#endif + +#ifndef INCREF +#define INCREF(x) ((((x)&~N_BTMASK)<>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK)) +#endif + +#define IMAGE_COMDAT_SELECT_NODUPLICATES 1 +#define IMAGE_COMDAT_SELECT_ANY 2 +#define IMAGE_COMDAT_SELECT_SAME_SIZE 3 +#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4 +#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 +#define IMAGE_COMDAT_SELECT_LARGEST 6 +#define IMAGE_COMDAT_SELECT_NEWEST 7 + +#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 +#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 +#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 + +/* Export module directory */ + +typedef struct _IMAGE_EXPORT_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Name; + DWORD Base; + DWORD NumberOfFunctions; + DWORD NumberOfNames; + DWORD AddressOfFunctions; + DWORD AddressOfNames; + DWORD AddressOfNameOrdinals; +} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; + +/* Import name entry */ +typedef struct _IMAGE_IMPORT_BY_NAME { + WORD Hint; + BYTE Name[1]; +} IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME; + +/* Import thunk */ +typedef struct _IMAGE_THUNK_DATA32 { + union { + DWORD ForwarderString; + DWORD Function; + DWORD Ordinal; + DWORD AddressOfData; + } u1; +} IMAGE_THUNK_DATA32,*PIMAGE_THUNK_DATA32; + +typedef struct _IMAGE_THUNK_DATA64 { + union { + ULONGLONG ForwarderString; + ULONGLONG Function; + ULONGLONG Ordinal; + ULONGLONG AddressOfData; + } u1; +} IMAGE_THUNK_DATA64,*PIMAGE_THUNK_DATA64; + +#ifdef CONFIG_X86_64 +typedef IMAGE_THUNK_DATA32 IMAGE_THUNK_DATA; +typedef PIMAGE_THUNK_DATA32 PIMAGE_THUNK_DATA; +#else +typedef IMAGE_THUNK_DATA64 IMAGE_THUNK_DATA; +typedef PIMAGE_THUNK_DATA64 PIMAGE_THUNK_DATA; +#endif + +/* Import module directory */ + +typedef struct packed _IMAGE_IMPORT_DESCRIPTOR { + union { + DWORD Characteristics; /* 0 for terminating null + * import descriptor */ + DWORD OriginalFirstThunk; /* RVA to original unbound + * IAT */ + } u; + DWORD TimeDateStamp; /* 0 if not bound, + * -1 if bound, and real date\time stamp + * in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT + * (new BIND) + * otherwise date/time stamp of DLL bound to + * (Old BIND) + */ + DWORD ForwarderChain; /* -1 if no forwarders */ + DWORD Name; + /* RVA to IAT (if bound this IAT has actual addresses) */ + DWORD FirstThunk; +} IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR; + +#define IMAGE_ORDINAL_FLAG32 0x80000000 +#define IMAGE_ORDINAL_FLAG64 0x8000000000000000UL +#define IMAGE_SNAP_BY_ORDINAL32(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG32) != 0) +#define IMAGE_SNAP_BY_ORDINAL64(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG64) != 0) +#define IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) + +#ifdef CONFIG_X86_64 +#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG64 +#define IMAGE_SNAP_BY_ORDINAL IMAGE_SNAP_BY_ORDINAL64 +#else +#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG32 +#define IMAGE_SNAP_BY_ORDINAL IMAGE_SNAP_BY_ORDINAL32 +#endif + +typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR +{ + DWORD TimeDateStamp; + WORD OffsetModuleName; + WORD NumberOfModuleForwarderRefs; +/* Array of zero or more IMAGE_BOUND_FORWARDER_REF follows */ +} IMAGE_BOUND_IMPORT_DESCRIPTOR, *PIMAGE_BOUND_IMPORT_DESCRIPTOR; + +typedef struct _IMAGE_BOUND_FORWARDER_REF +{ + DWORD TimeDateStamp; + WORD OffsetModuleName; + WORD Reserved; +} IMAGE_BOUND_FORWARDER_REF, *PIMAGE_BOUND_FORWARDER_REF; + +typedef struct _IMAGE_BASE_RELOCATION +{ + DWORD VirtualAddress; + DWORD SizeOfBlock; + WORD TypeOffset[0]; +} IMAGE_BASE_RELOCATION,*PIMAGE_BASE_RELOCATION; + +typedef struct _IMAGE_RELOCATION +{ + union { + DWORD VirtualAddress; + DWORD RelocCount; + } DUMMYUNIONNAME; + DWORD SymbolTableIndex; + WORD Type; +} IMAGE_RELOCATION, *PIMAGE_RELOCATION; + +#define IMAGE_SIZEOF_RELOCATION 10 + +/* generic relocation types */ +#define IMAGE_REL_BASED_ABSOLUTE 0 +#define IMAGE_REL_BASED_HIGH 1 +#define IMAGE_REL_BASED_LOW 2 +#define IMAGE_REL_BASED_HIGHLOW 3 +#define IMAGE_REL_BASED_HIGHADJ 4 +#define IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define IMAGE_REL_BASED_SECTION 6 +#define IMAGE_REL_BASED_REL 7 +#define IMAGE_REL_BASED_MIPS_JMPADDR16 9 +#define IMAGE_REL_BASED_IA64_IMM64 9 /* yes, 9 too */ +#define IMAGE_REL_BASED_DIR64 10 +#define IMAGE_REL_BASED_HIGH3ADJ 11 + +/* I386 relocation types */ +#define IMAGE_REL_I386_ABSOLUTE 0 +#define IMAGE_REL_I386_DIR16 1 +#define IMAGE_REL_I386_REL16 2 +#define IMAGE_REL_I386_DIR32 6 +#define IMAGE_REL_I386_DIR32NB 7 +#define IMAGE_REL_I386_SEG12 9 +#define IMAGE_REL_I386_SECTION 10 +#define IMAGE_REL_I386_SECREL 11 +#define IMAGE_REL_I386_REL32 20 + +/* MIPS relocation types */ +#define IMAGE_REL_MIPS_ABSOLUTE 0x0000 +#define IMAGE_REL_MIPS_REFHALF 0x0001 +#define IMAGE_REL_MIPS_REFWORD 0x0002 +#define IMAGE_REL_MIPS_JMPADDR 0x0003 +#define IMAGE_REL_MIPS_REFHI 0x0004 +#define IMAGE_REL_MIPS_REFLO 0x0005 +#define IMAGE_REL_MIPS_GPREL 0x0006 +#define IMAGE_REL_MIPS_LITERAL 0x0007 +#define IMAGE_REL_MIPS_SECTION 0x000A +#define IMAGE_REL_MIPS_SECREL 0x000B +#define IMAGE_REL_MIPS_SECRELLO 0x000C +#define IMAGE_REL_MIPS_SECRELHI 0x000D +#define IMAGE_REL_MIPS_JMPADDR16 0x0010 +#define IMAGE_REL_MIPS_REFWORDNB 0x0022 +#define IMAGE_REL_MIPS_PAIR 0x0025 + +/* ALPHA relocation types */ +#define IMAGE_REL_ALPHA_ABSOLUTE 0x0000 +#define IMAGE_REL_ALPHA_REFLONG 0x0001 +#define IMAGE_REL_ALPHA_REFQUAD 0x0002 +#define IMAGE_REL_ALPHA_GPREL 0x0003 +#define IMAGE_REL_ALPHA_LITERAL 0x0004 +#define IMAGE_REL_ALPHA_LITUSE 0x0005 +#define IMAGE_REL_ALPHA_GPDISP 0x0006 +#define IMAGE_REL_ALPHA_BRADDR 0x0007 +#define IMAGE_REL_ALPHA_HINT 0x0008 +#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x0009 +#define IMAGE_REL_ALPHA_REFHI 0x000A +#define IMAGE_REL_ALPHA_REFLO 0x000B +#define IMAGE_REL_ALPHA_PAIR 0x000C +#define IMAGE_REL_ALPHA_MATCH 0x000D +#define IMAGE_REL_ALPHA_SECTION 0x000E +#define IMAGE_REL_ALPHA_SECREL 0x000F +#define IMAGE_REL_ALPHA_REFLONGNB 0x0010 +#define IMAGE_REL_ALPHA_SECRELLO 0x0011 +#define IMAGE_REL_ALPHA_SECRELHI 0x0012 +#define IMAGE_REL_ALPHA_REFQ3 0x0013 +#define IMAGE_REL_ALPHA_REFQ2 0x0014 +#define IMAGE_REL_ALPHA_REFQ1 0x0015 +#define IMAGE_REL_ALPHA_GPRELLO 0x0016 +#define IMAGE_REL_ALPHA_GPRELHI 0x0017 + +/* PowerPC relocation types */ +#define IMAGE_REL_PPC_ABSOLUTE 0x0000 +#define IMAGE_REL_PPC_ADDR64 0x0001 +#define IMAGE_REL_PPC_ADDR 0x0002 +#define IMAGE_REL_PPC_ADDR24 0x0003 +#define IMAGE_REL_PPC_ADDR16 0x0004 +#define IMAGE_REL_PPC_ADDR14 0x0005 +#define IMAGE_REL_PPC_REL24 0x0006 +#define IMAGE_REL_PPC_REL14 0x0007 +#define IMAGE_REL_PPC_TOCREL16 0x0008 +#define IMAGE_REL_PPC_TOCREL14 0x0009 +#define IMAGE_REL_PPC_ADDR32NB 0x000A +#define IMAGE_REL_PPC_SECREL 0x000B +#define IMAGE_REL_PPC_SECTION 0x000C +#define IMAGE_REL_PPC_IFGLUE 0x000D +#define IMAGE_REL_PPC_IMGLUE 0x000E +#define IMAGE_REL_PPC_SECREL16 0x000F +#define IMAGE_REL_PPC_REFHI 0x0010 +#define IMAGE_REL_PPC_REFLO 0x0011 +#define IMAGE_REL_PPC_PAIR 0x0012 +#define IMAGE_REL_PPC_SECRELLO 0x0013 +#define IMAGE_REL_PPC_SECRELHI 0x0014 +#define IMAGE_REL_PPC_GPREL 0x0015 +#define IMAGE_REL_PPC_TYPEMASK 0x00FF +/* modifier bits */ +#define IMAGE_REL_PPC_NEG 0x0100 +#define IMAGE_REL_PPC_BRTAKEN 0x0200 +#define IMAGE_REL_PPC_BRNTAKEN 0x0400 +#define IMAGE_REL_PPC_TOCDEFN 0x0800 + +/* SH3 ? relocation type */ +#define IMAGE_REL_SH3_ABSOLUTE 0x0000 +#define IMAGE_REL_SH3_DIRECT16 0x0001 +#define IMAGE_REL_SH3_DIRECT 0x0002 +#define IMAGE_REL_SH3_DIRECT8 0x0003 +#define IMAGE_REL_SH3_DIRECT8_WORD 0x0004 +#define IMAGE_REL_SH3_DIRECT8_LONG 0x0005 +#define IMAGE_REL_SH3_DIRECT4 0x0006 +#define IMAGE_REL_SH3_DIRECT4_WORD 0x0007 +#define IMAGE_REL_SH3_DIRECT4_LONG 0x0008 +#define IMAGE_REL_SH3_PCREL8_WORD 0x0009 +#define IMAGE_REL_SH3_PCREL8_LONG 0x000A +#define IMAGE_REL_SH3_PCREL12_WORD 0x000B +#define IMAGE_REL_SH3_STARTOF_SECTION 0x000C +#define IMAGE_REL_SH3_SIZEOF_SECTION 0x000D +#define IMAGE_REL_SH3_SECTION 0x000E +#define IMAGE_REL_SH3_SECREL 0x000F +#define IMAGE_REL_SH3_DIRECT32_NB 0x0010 + +/* ARM (Archimedes?) relocation types */ +#define IMAGE_REL_ARM_ABSOLUTE 0x0000 +#define IMAGE_REL_ARM_ADDR 0x0001 +#define IMAGE_REL_ARM_ADDR32NB 0x0002 +#define IMAGE_REL_ARM_BRANCH24 0x0003 +#define IMAGE_REL_ARM_BRANCH11 0x0004 +#define IMAGE_REL_ARM_SECTION 0x000E +#define IMAGE_REL_ARM_SECREL 0x000F + +/* IA64 relocation types */ +#define IMAGE_REL_IA64_ABSOLUTE 0x0000 +#define IMAGE_REL_IA64_IMM14 0x0001 +#define IMAGE_REL_IA64_IMM22 0x0002 +#define IMAGE_REL_IA64_IMM64 0x0003 +#define IMAGE_REL_IA64_DIR 0x0004 +#define IMAGE_REL_IA64_DIR64 0x0005 +#define IMAGE_REL_IA64_PCREL21B 0x0006 +#define IMAGE_REL_IA64_PCREL21M 0x0007 +#define IMAGE_REL_IA64_PCREL21F 0x0008 +#define IMAGE_REL_IA64_GPREL22 0x0009 +#define IMAGE_REL_IA64_LTOFF22 0x000A +#define IMAGE_REL_IA64_SECTION 0x000B +#define IMAGE_REL_IA64_SECREL22 0x000C +#define IMAGE_REL_IA64_SECREL64I 0x000D +#define IMAGE_REL_IA64_SECREL 0x000E +#define IMAGE_REL_IA64_LTOFF64 0x000F +#define IMAGE_REL_IA64_DIR32NB 0x0010 +#define IMAGE_REL_IA64_RESERVED_11 0x0011 +#define IMAGE_REL_IA64_RESERVED_12 0x0012 +#define IMAGE_REL_IA64_RESERVED_13 0x0013 +#define IMAGE_REL_IA64_RESERVED_14 0x0014 +#define IMAGE_REL_IA64_RESERVED_15 0x0015 +#define IMAGE_REL_IA64_RESERVED_16 0x0016 +#define IMAGE_REL_IA64_ADDEND 0x001F + +/* archive format */ + +#define IMAGE_ARCHIVE_START_SIZE 8 +#define IMAGE_ARCHIVE_START "!\n" +#define IMAGE_ARCHIVE_END "`\n" +#define IMAGE_ARCHIVE_PAD "\n" +#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " +#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " + +typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER +{ + BYTE Name[16]; + BYTE Date[12]; + BYTE UserID[6]; + BYTE GroupID[6]; + BYTE Mode[8]; + BYTE Size[10]; + BYTE EndHeader[2]; +} IMAGE_ARCHIVE_MEMBER_HEADER, *PIMAGE_ARCHIVE_MEMBER_HEADER; + +#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + +/* + * Resource directory stuff + */ +typedef struct _IMAGE_RESOURCE_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + WORD NumberOfNamedEntries; + WORD NumberOfIdEntries; + /* IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; */ +} IMAGE_RESOURCE_DIRECTORY,*PIMAGE_RESOURCE_DIRECTORY; + +#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 +#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 + +typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { + union { + struct { +#ifdef BITFIELDS_BIGENDIAN + unsigned NameIsString:1; + unsigned NameOffset:31; +#else + unsigned NameOffset:31; + unsigned NameIsString:1; +#endif + } DUMMYSTRUCTNAME1; + DWORD Name; + struct { +#ifdef WORDS_BIGENDIAN + WORD __pad; + WORD Id; +#else + WORD Id; + WORD __pad; +#endif + } DUMMYSTRUCTNAME2; + } DUMMYUNIONNAME1; + union { + DWORD OffsetToData; + struct { +#ifdef BITFIELDS_BIGENDIAN + unsigned DataIsDirectory:1; + unsigned OffsetToDirectory:31; +#else + unsigned OffsetToDirectory:31; + unsigned DataIsDirectory:1; +#endif + } DUMMYSTRUCTNAME3; + } DUMMYUNIONNAME2; +} IMAGE_RESOURCE_DIRECTORY_ENTRY,*PIMAGE_RESOURCE_DIRECTORY_ENTRY; + + +typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING { + WORD Length; + CHAR NameString[ 1 ]; +} IMAGE_RESOURCE_DIRECTORY_STRING,*PIMAGE_RESOURCE_DIRECTORY_STRING; + --- linux-2.6.27.orig/ubuntu/ndiswrapper/wrapndis.h +++ linux-2.6.27/ubuntu/ndiswrapper/wrapndis.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _WRAPNDIS_H_ +#define _WRAPNDIS_H_ + +#include "ndis.h" +#include "pnp.h" + +int wrapndis_init(void); +void wrapndis_exit(void); + +NDIS_STATUS mp_reset(struct ndis_device *wnd); + +NDIS_STATUS mp_request(enum ndis_request_type request, + struct ndis_device *wnd, ndis_oid oid, + void *buf, ULONG buflen, ULONG *written, ULONG *needed); + +static inline NDIS_STATUS mp_query_info(struct ndis_device *wnd, + ndis_oid oid, void *buf, ULONG buflen, + ULONG *written, ULONG *needed) +{ + return mp_request(NdisRequestQueryInformation, wnd, oid, + buf, buflen, written, needed); +} + +static inline NDIS_STATUS mp_set_info(struct ndis_device *wnd, + ndis_oid oid, void *buf, ULONG buflen, + ULONG *written, ULONG *needed) +{ + return mp_request(NdisRequestSetInformation, wnd, oid, + buf, buflen, written, needed); +} + +static inline NDIS_STATUS mp_query(struct ndis_device *wnd, ndis_oid oid, + void *buf, ULONG buflen) +{ + return mp_request(NdisRequestQueryInformation, wnd, oid, + buf, buflen, NULL, NULL); +} + +static inline NDIS_STATUS mp_query_int(struct ndis_device *wnd, + ndis_oid oid, ULONG *data) +{ + return mp_request(NdisRequestQueryInformation, wnd, oid, + data, sizeof(ULONG), NULL, NULL); +} + +static inline NDIS_STATUS mp_set(struct ndis_device *wnd, ndis_oid oid, + void *buf, ULONG buflen) +{ + return mp_request(NdisRequestSetInformation, wnd, oid, + buf, buflen, NULL, NULL); +} + +static inline NDIS_STATUS mp_set_int(struct ndis_device *wnd, + ndis_oid oid, ULONG data) +{ + return mp_request(NdisRequestSetInformation, wnd, oid, + &data, sizeof(ULONG), NULL, NULL); +} + +void free_tx_packet(struct ndis_device *wnd, struct ndis_packet *packet, + NDIS_STATUS status); +int init_ndis_driver(struct driver_object *drv_obj); +NDIS_STATUS ndis_reinit(struct ndis_device *wnd); + +void hangcheck_add(struct ndis_device *wnd); +void hangcheck_del(struct ndis_device *wnd); + +driver_dispatch_t winNdisDispatchPnp; +driver_dispatch_t winNdisDispatchPower; +driver_dispatch_t winNdisDispatchDeviceControl; + +struct iw_statistics *get_iw_stats(struct net_device *dev); + +#endif --- linux-2.6.27.orig/ubuntu/ndiswrapper/BOM +++ linux-2.6.27/ubuntu/ndiswrapper/BOM @@ -0,0 +1,2 @@ +Downloaded from: http://sourceforge.net/project/showfiles.php?group_id=93482 +Current Version: 1.53 --- linux-2.6.27.orig/ubuntu/ndiswrapper/ndis.c +++ linux-2.6.27/ubuntu/ndiswrapper/ndis.c @@ -0,0 +1,2988 @@ +/* + * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "ndis.h" +#include "iw_ndis.h" +#include "wrapndis.h" +#include "pnp.h" +#include "loader.h" +#include +#include +#include "ndis_exports.h" + +#define MAX_ALLOCATED_NDIS_PACKETS TX_RING_SIZE +#define MAX_ALLOCATED_NDIS_BUFFERS TX_RING_SIZE + +static void ndis_worker(worker_param_t dummy); +static work_struct_t ndis_work; +static struct nt_list ndis_work_list; +static spinlock_t ndis_work_list_lock; + +workqueue_struct_t *ndis_wq; +static struct nt_thread *ndis_worker_thread; + +static void *ndis_get_routine_address(char *name); + +wstdcall void WIN_FUNC(NdisInitializeWrapper,4) + (void **driver_handle, struct driver_object *driver, + struct unicode_string *reg_path, void *unused) +{ + ENTER1("handle: %p, driver: %p", driver_handle, driver); + *driver_handle = driver; + EXIT1(return); +} + +wstdcall void WIN_FUNC(NdisTerminateWrapper,2) + (struct device_object *dev_obj, void *system_specific) +{ + EXIT1(return); +} + +wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterMiniport,3) + (struct driver_object *drv_obj, struct miniport *mp, UINT length) +{ + int min_length; + struct wrap_driver *wrap_driver; + struct ndis_driver *ndis_driver; + + min_length = ((char *)&mp->co_create_vc) - ((char *)mp); + + ENTER1("%p %p %d", drv_obj, mp, length); + + if (mp->major_version < 4) { + ERROR("Driver is using ndis version %d which is too old.", + mp->major_version); + EXIT1(return NDIS_STATUS_BAD_VERSION); + } + + if (length < min_length) { + ERROR("Characteristics length %d is too small", length); + EXIT1(return NDIS_STATUS_BAD_CHARACTERISTICS); + } + + TRACE1("%d.%d, %d, %u", mp->major_version, mp->minor_version, length, + (u32)sizeof(struct miniport)); + wrap_driver = IoGetDriverObjectExtension(drv_obj, + (void *)WRAP_DRIVER_CLIENT_ID); + if (!wrap_driver) { + ERROR("couldn't get wrap_driver"); + EXIT1(return NDIS_STATUS_RESOURCES); + } + if (IoAllocateDriverObjectExtension( + drv_obj, (void *)NDIS_DRIVER_CLIENT_ID, + sizeof(*ndis_driver), (void **)&ndis_driver) != + STATUS_SUCCESS) + EXIT1(return NDIS_STATUS_RESOURCES); + wrap_driver->ndis_driver = ndis_driver; + TRACE1("driver: %p", ndis_driver); + memcpy(&ndis_driver->mp, mp, min_t(int, sizeof(*mp), length)); + + DBG_BLOCK(2) { + int i; + void **func; + char *mp_funcs[] = { + "queryinfo", "reconfig", "reset", "send", "setinfo", + "tx_data", "return_packet", "send_packets", + "alloc_complete", "co_create_vc", "co_delete_vc", + "co_activate_vc", "co_deactivate_vc", + "co_send_packets", "co_request", "cancel_send_packets", + "pnp_event_notify", "shutdown", + }; + func = (void **)&ndis_driver->mp.queryinfo; + for (i = 0; i < (sizeof(mp_funcs) / sizeof(mp_funcs[0])); i++) + TRACE2("function '%s' is at %p", mp_funcs[i], func[i]); + } + EXIT1(return NDIS_STATUS_SUCCESS); +} + +wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterDevice,6) + (struct driver_object *drv_obj, struct unicode_string *dev_name, + struct unicode_string *link, void **funcs, + struct device_object **dev_obj, void **dev_obj_handle) +{ + NTSTATUS status; + struct device_object *tmp; + int i; + + ENTER1("%p, %p, %p", drv_obj, dev_name, link); + status = IoCreateDevice(drv_obj, 0, dev_name, FILE_DEVICE_NETWORK, 0, + FALSE, &tmp); + + if (status != STATUS_SUCCESS) + EXIT1(return NDIS_STATUS_RESOURCES); + if (link) + status = IoCreateSymbolicLink(link, dev_name); + if (status != STATUS_SUCCESS) { + IoDeleteDevice(tmp); + EXIT1(return NDIS_STATUS_RESOURCES); + } + + *dev_obj = tmp; + *dev_obj_handle = *dev_obj; + for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) + if (funcs[i] && i != IRP_MJ_PNP && i != IRP_MJ_POWER) { + drv_obj->major_func[i] = funcs[i]; + TRACE1("mj_fn for 0x%x is at %p", i, funcs[i]); + } + EXIT1(return NDIS_STATUS_SUCCESS); +} + +wstdcall NDIS_STATUS WIN_FUNC(NdisMDeregisterDevice,1) + (struct device_object *dev_obj) +{ + ENTER2("%p", dev_obj); + IoDeleteDevice(dev_obj); + return NDIS_STATUS_SUCCESS; +} + +wstdcall NDIS_STATUS WIN_FUNC(NdisAllocateMemoryWithTag,3) + (void **dest, UINT length, ULONG tag) +{ + void *addr; + + assert_irql(_irql_ <= DISPATCH_LEVEL); + addr = ExAllocatePoolWithTag(NonPagedPool, length, tag); + TRACE4("%p", addr); + if (addr) { + *dest = addr; + EXIT4(return NDIS_STATUS_SUCCESS); + } else + EXIT4(return NDIS_STATUS_FAILURE); +} + +wstdcall NDIS_STATUS WIN_FUNC(NdisAllocateMemory,4) + (void **dest, UINT length, UINT flags, NDIS_PHY_ADDRESS highest_address) +{ + return NdisAllocateMemoryWithTag(dest, length, 0); +} + +/* length_tag is either length or tag, depending on if + * NdisAllocateMemory or NdisAllocateMemoryTag is used to allocate + * memory */ +wstdcall void WIN_FUNC(NdisFreeMemory,3) + (void *addr, UINT length_tag, UINT flags) +{ + TRACE4("%p", addr); + ExFreePool(addr); +} + +noregparm void WIN_FUNC(NdisWriteErrorLogEntry,12) + (struct driver_object *drv_obj, ULONG error, ULONG count, ...) +{ + va_list args; + int i; + ULONG code; + + va_start(args, count); + ERROR("log: %08X, count: %d, return_address: %p", + error, count, __builtin_return_address(0)); + for (i = 0; i < count; i++) { + code = va_arg(args, ULONG); + ERROR("code: 0x%x", code); + } + va_end(args); + EXIT2(return); +} + +wstdcall void WIN_FUNC(NdisOpenConfiguration,3) + (NDIS_STATUS *status, struct ndis_mp_block **conf_handle, + struct ndis_mp_block *handle) +{ + ENTER2("%p", conf_handle); + *conf_handle = handle; + *status = NDIS_STATUS_SUCCESS; + EXIT2(return); +} + +wstdcall void WIN_FUNC(NdisOpenProtocolConfiguration,3) + (NDIS_STATUS *status, void **confhandle, + struct unicode_string *section) +{ + ENTER2("%p", confhandle); + *status = NDIS_STATUS_SUCCESS; + EXIT2(return); +} + +wstdcall void WIN_FUNC(NdisOpenConfigurationKeyByName,4) + (NDIS_STATUS *status, void *handle, + struct unicode_string *key, void **subkeyhandle) +{ + struct ansi_string ansi; + ENTER2(""); + if (RtlUnicodeStringToAnsiString(&ansi, key, TRUE) == STATUS_SUCCESS) { + TRACE2("%s", ansi.buf); + RtlFreeAnsiString(&ansi); + } + *subkeyhandle = handle; + *status = NDIS_STATUS_SUCCESS; + EXIT2(return); +} + +wstdcall void WIN_FUNC(NdisOpenConfigurationKeyByIndex,5) + (NDIS_STATUS *status, void *handle, ULONG index, + struct unicode_string *key, void **subkeyhandle) +{ + ENTER2("%u", index); +// *subkeyhandle = handle; + *status = NDIS_STATUS_FAILURE; + EXIT2(return); +} + +wstdcall void WIN_FUNC(NdisCloseConfiguration,1) + (void *handle) +{ + /* instead of freeing all configuration parameters as we are + * supposed to do here, we free them when the device is + * removed */ + ENTER2("%p", handle); + return; +} + +wstdcall void WIN_FUNC(NdisOpenFile,5) + (NDIS_STATUS *status, struct wrap_bin_file **file, + UINT *filelength, struct unicode_string *filename, + NDIS_PHY_ADDRESS highest_address) +{ + struct ansi_string ansi; + struct wrap_bin_file *bin_file; + + ENTER2("%p, %d, %llx, %p", status, *filelength, highest_address, *file); + if (RtlUnicodeStringToAnsiString(&ansi, filename, TRUE) != + STATUS_SUCCESS) { + *status = NDIS_STATUS_RESOURCES; + EXIT2(return); + } + TRACE2("%s", ansi.buf); + bin_file = get_bin_file(ansi.buf); + if (bin_file) { + *file = bin_file; + *filelength = bin_file->size; + *status = NDIS_STATUS_SUCCESS; + } else + *status = NDIS_STATUS_FILE_NOT_FOUND; + + RtlFreeAnsiString(&ansi); + EXIT2(return); +} + +wstdcall void WIN_FUNC(NdisMapFile,3) + (NDIS_STATUS *status, void **mappedbuffer, struct wrap_bin_file *file) +{ + ENTER2("%p", file); + + if (!file) { + *status = NDIS_STATUS_ALREADY_MAPPED; + EXIT2(return); + } + + *status = NDIS_STATUS_SUCCESS; + *mappedbuffer = file->data; + EXIT2(return); +} + +wstdcall void WIN_FUNC(NdisUnmapFile,1) + (struct wrap_bin_file *file) +{ + ENTER2("%p", file); + EXIT2(return); +} + +wstdcall void WIN_FUNC(NdisCloseFile,1) + (struct wrap_bin_file *file) +{ + ENTER2("%p", file); + free_bin_file(file); + EXIT2(return); +} + +wstdcall void WIN_FUNC(NdisGetSystemUpTime,1) + (ULONG *ms) +{ + *ms = 1000 * jiffies / HZ; + EXIT5(return); +} + +wstdcall ULONG WIN_FUNC(NDIS_BUFFER_TO_SPAN_PAGES,1) + (ndis_buffer *buffer) +{ + ULONG n, length; + + if (buffer == NULL) + EXIT2(return 0); + if (MmGetMdlByteCount(buffer) == 0) + EXIT2(return 1); + + length = MmGetMdlByteCount(buffer); + n = SPAN_PAGES(MmGetMdlVirtualAddress(buffer), length); + TRACE4("%p, %p, %d, %d", buffer->startva, buffer->mappedsystemva, + length, n); + EXIT3(return n); +} + +wstdcall void WIN_FUNC(NdisGetBufferPhysicalArraySize,2) + (ndis_buffer *buffer, UINT *arraysize) +{ + ENTER3("%p", buffer); + *arraysize = NDIS_BUFFER_TO_SPAN_PAGES(buffer); + EXIT3(return); +} + +static struct ndis_configuration_parameter * +ndis_encode_setting(struct wrap_device_setting *setting, + enum ndis_parameter_type type) +{ + struct ansi_string ansi; + struct ndis_configuration_parameter *param; + + param = setting->encoded; + if (param) { + if (param->type == type) + EXIT2(return param); + if (param->type == NdisParameterString) + RtlFreeUnicodeString(¶m->data.string); + setting->encoded = NULL; + } else + param = ExAllocatePoolWithTag(NonPagedPool, sizeof(*param), 0); + if (!param) { + ERROR("couldn't allocate memory"); + return NULL; + } + switch(type) { + case NdisParameterInteger: + param->data.integer = simple_strtol(setting->value, NULL, 0); + TRACE2("0x%x", (ULONG)param->data.integer); + break; + case NdisParameterHexInteger: + param->data.integer = simple_strtol(setting->value, NULL, 16); + TRACE2("0x%x", (ULONG)param->data.integer); + break; + case NdisParameterString: + RtlInitAnsiString(&ansi, setting->value); + TRACE2("'%s'", ansi.buf); + if (RtlAnsiStringToUnicodeString(¶m->data.string, + &ansi, TRUE)) { + ExFreePool(param); + EXIT2(return NULL); + } + break; + case NdisParameterBinary: + param->data.integer = simple_strtol(setting->value, NULL, 2); + TRACE2("0x%x", (ULONG)param->data.integer); + break; + default: + ERROR("unknown type: %d", type); + ExFreePool(param); + return NULL; + } + param->type = type; + setting->encoded = param; + EXIT2(return param); +} + +static int ndis_decode_setting(struct wrap_device_setting *setting, + struct ndis_configuration_parameter *param) +{ + struct ansi_string ansi; + struct ndis_configuration_parameter *prev; + + ENTER2("%p, %p", setting, param); + prev = setting->encoded; + if (prev && prev->type == NdisParameterString) { + RtlFreeUnicodeString(&prev->data.string); + setting->encoded = NULL; + } + switch(param->type) { + case NdisParameterInteger: + snprintf(setting->value, sizeof(u32), "%u", + param->data.integer); + setting->value[sizeof(ULONG)] = 0; + break; + case NdisParameterHexInteger: + snprintf(setting->value, sizeof(u32), "%x", + param->data.integer); + setting->value[sizeof(ULONG)] = 0; + break; + case NdisParameterString: + ansi.buf = setting->value; + ansi.max_length = MAX_SETTING_VALUE_LEN; + if ((RtlUnicodeStringToAnsiString(&ansi, ¶m->data.string, + FALSE) != STATUS_SUCCESS) + || ansi.length >= MAX_SETTING_VALUE_LEN) { + EXIT1(return -1); + } + if (ansi.length == ansi.max_length) + ansi.length--; + setting->value[ansi.length] = 0; + break; + case NdisParameterBinary: + snprintf(setting->value, sizeof(u32), "%u", + param->data.integer); + setting->value[sizeof(ULONG)] = 0; + break; + default: + TRACE2("unknown setting type: %d", param->type); + return -1; + } + TRACE2("setting changed %s='%s', %d", setting->name, setting->value, + ansi.length); + return 0; +} + +static int read_setting(struct nt_list *setting_list, char *keyname, int length, + struct ndis_configuration_parameter **param, + enum ndis_parameter_type type) +{ + struct wrap_device_setting *setting; + if (down_interruptible(&loader_mutex)) + WARNING("couldn't obtain loader_mutex"); + nt_list_for_each_entry(setting, setting_list, list) { + if (strnicmp(keyname, setting->name, length) == 0) { + TRACE2("setting %s='%s'", keyname, setting->value); + up(&loader_mutex); + *param = ndis_encode_setting(setting, type); + if (*param) + EXIT2(return 0); + else + EXIT2(return -1); + } + } + up(&loader_mutex); + EXIT2(return -1); +} + +wstdcall void WIN_FUNC(NdisReadConfiguration,5) + (NDIS_STATUS *status, struct ndis_configuration_parameter **param, + struct ndis_mp_block *nmb, struct unicode_string *key, + enum ndis_parameter_type type) +{ + struct ansi_string ansi; + int ret; + + ENTER2("nmb: %p", nmb); + ret = RtlUnicodeStringToAnsiString(&ansi, key, TRUE); + if (ret != STATUS_SUCCESS || ansi.buf == NULL) { + *param = NULL; + *status = NDIS_STATUS_FAILURE; + RtlFreeAnsiString(&ansi); + EXIT2(return); + } + TRACE2("%d, %s", type, ansi.buf); + + if (read_setting(&nmb->wnd->wd->settings, ansi.buf, + ansi.length, param, type) == 0 || + read_setting(&nmb->wnd->wd->driver->settings, ansi.buf, + ansi.length, param, type) == 0) + *status = NDIS_STATUS_SUCCESS; + else { + TRACE2("setting %s not found (type:%d)", ansi.buf, type); + *status = NDIS_STATUS_FAILURE; + } + RtlFreeAnsiString(&ansi); + EXIT2(return); + +} + +wstdcall void WIN_FUNC(NdisWriteConfiguration,4) + (NDIS_STATUS *status, struct ndis_mp_block *nmb, + struct unicode_string *key, struct ndis_configuration_parameter *param) +{ + struct ansi_string ansi; + char *keyname; + struct wrap_device_setting *setting; + + ENTER2("nmb: %p", nmb); + if (RtlUnicodeStringToAnsiString(&ansi, key, TRUE)) { + *status = NDIS_STATUS_FAILURE; + EXIT2(return); + } + keyname = ansi.buf; + TRACE2("%s", keyname); + + if (down_interruptible(&loader_mutex)) + WARNING("couldn't obtain loader_mutex"); + nt_list_for_each_entry(setting, &nmb->wnd->wd->settings, list) { + if (strnicmp(keyname, setting->name, ansi.length) == 0) { + up(&loader_mutex); + if (ndis_decode_setting(setting, param)) + *status = NDIS_STATUS_FAILURE; + else + *status = NDIS_STATUS_SUCCESS; + RtlFreeAnsiString(&ansi); + EXIT2(return); + } + } + up(&loader_mutex); + setting = kzalloc(sizeof(*setting), GFP_KERNEL); + if (setting) { + if (ansi.length == ansi.max_length) + ansi.length--; + memcpy(setting->name, keyname, ansi.length); + setting->name[ansi.length] = 0; + if (ndis_decode_setting(setting, param)) + *status = NDIS_STATUS_FAILURE; + else { + *status = NDIS_STATUS_SUCCESS; + if (down_interruptible(&loader_mutex)) + WARNING("couldn't obtain loader_mutex"); + InsertTailList(&nmb->wnd->wd->settings, &setting->list); + up(&loader_mutex); + } + } else + *status = NDIS_STATUS_RESOURCES; + + RtlFreeAnsiString(&ansi); + EXIT2(return); +} + +wstdcall void WIN_FUNC(NdisReadNetworkAddress,4) + (NDIS_STATUS *status, void **addr, UINT *len, + struct ndis_mp_block *nmb) +{ + struct ndis_device *wnd = nmb->wnd; + struct ndis_configuration_parameter *param; + struct unicode_string key; + struct ansi_string ansi; + typeof(wnd->mac) mac; + int i, ret; + + ENTER2("%p", nmb); + RtlInitAnsiString(&ansi, "NetworkAddress"); + *status = NDIS_STATUS_FAILURE; + if (RtlAnsiStringToUnicodeString(&key, &ansi, TRUE) != STATUS_SUCCESS) + EXIT1(return); + + NdisReadConfiguration(&ret, ¶m, nmb, &key, NdisParameterString); + RtlFreeUnicodeString(&key); + if (ret != NDIS_STATUS_SUCCESS) + EXIT1(return); + ret = RtlUnicodeStringToAnsiString(&ansi, ¶m->data.string, TRUE); + if (ret != STATUS_SUCCESS) + EXIT1(return); + + i = 0; + if (ansi.length >= 2 * sizeof(mac)) { + for (i = 0; i < sizeof(mac); i++) { + char c[3]; + int x; + c[0] = ansi.buf[i*2]; + c[1] = ansi.buf[i*2+1]; + c[2] = 0; + ret = sscanf(c, "%x", &x); + if (ret != 1) + break; + mac[i] = x; + } + } + TRACE2("%s, %d, " MACSTR, ansi.buf, i, MAC2STR(mac)); + RtlFreeAnsiString(&ansi); + if (i == sizeof(mac)) { + memcpy(wnd->mac, mac, sizeof(wnd->mac)); + *len = sizeof(mac); + *addr = wnd->mac; + *status = NDIS_STATUS_SUCCESS; + } + EXIT1(return); +} + +wstdcall void WIN_FUNC(NdisInitializeString,2) + (struct unicode_string *dest, UCHAR *src) +{ + struct ansi_string ansi; + + ENTER2(""); + if (src == NULL) { + dest->length = dest->max_length = 0; + dest->buf = NULL; + } else { + RtlInitAnsiString(&ansi, src); + /* the string is freed with NdisFreeMemory */ + RtlAnsiStringToUnicodeString(dest, &ansi, TRUE); + } + EXIT2(return); +} + +wstdcall void WIN_FUNC(NdisInitAnsiString,2) + (struct ansi_string *dst, CHAR *src) +{ + RtlInitAnsiString(dst, src); + EXIT2(return); +} + +wstdcall void WIN_FUNC(NdisInitUnicodeString,2) + (struct unicode_string *dest, const wchar_t *src) +{ + RtlInitUnicodeString(dest, src); + return; +} + +wstdcall NDIS_STATUS WIN_FUNC(NdisAnsiStringToUnicodeString,2) + (struct unicode_string *dst, struct ansi_string *src) +{ + ENTER2(""); + if (dst == NULL || src == NULL) + EXIT2(return NDIS_STATUS_FAILURE); + if (RtlAnsiStringToUnicodeString(dst, src, FALSE) == STATUS_SUCCESS) + return NDIS_STATUS_SUCCESS; + else + return NDIS_STATUS_FAILURE; +} + +wstdcall NDIS_STATUS WIN_FUNC(NdisUnicodeStringToAnsiString,2) + (struct ansi_string *dst, struct unicode_string *src) +{ + ENTER2(""); + if (dst == NULL || src == NULL) + EXIT2(return NDIS_STATUS_FAILURE); + if (RtlUnicodeStringToAnsiString(dst, src, FALSE) == STATUS_SUCCESS) + return NDIS_STATUS_SUCCESS; + else + return NDIS_STATUS_FAILURE; +} + +wstdcall NTSTATUS WIN_FUNC(NdisUpcaseUnicodeString,2) + (struct unicode_string *dst, struct unicode_string *src) +{ + EXIT2(return RtlUpcaseUnicodeString(dst, src, FALSE)); +} + +wstdcall void WIN_FUNC(NdisMSetAttributesEx,5) + (struct ndis_mp_block *nmb, void *mp_ctx, + UINT hangcheck_interval, UINT attributes, ULONG adaptertype) +{ + struct ndis_device *wnd; + + ENTER1("%p, %p, %d, %08x, %d", nmb, mp_ctx, hangcheck_interval, + attributes, adaptertype); + wnd = nmb->wnd; + nmb->mp_ctx = mp_ctx; + wnd->attributes = attributes; + + if ((attributes & NDIS_ATTRIBUTE_BUS_MASTER) && + wrap_is_pci_bus(wnd->wd->dev_bus)) + pci_set_master(wnd->wd->pci.pdev); + + if (hangcheck_interval > 0) + wnd->hangcheck_interval = 2 * hangcheck_interval * HZ; + else + wnd->hangcheck_interval = 2 * HZ; + + EXIT1(return); +} + +wstdcall ULONG WIN_FUNC(NdisReadPciSlotInformation,5) + (struct ndis_mp_block *nmb, ULONG slot, + ULONG offset, char *buf, ULONG len) +{ + struct wrap_device *wd = nmb->wnd->wd; + ULONG i; + for (i = 0; i < len; i++) + if (pci_read_config_byte(wd->pci.pdev, offset + i, &buf[i]) != + PCIBIOS_SUCCESSFUL) + break; + DBG_BLOCK(2) { + if (i != len) + WARNING("%u, %u", i, len); + } + return i; +} + +wstdcall ULONG WIN_FUNC(NdisImmediateReadPciSlotInformation,5) + (struct ndis_mp_block *nmb, ULONG slot, + ULONG offset, char *buf, ULONG len) +{ + return NdisReadPciSlotInformation(nmb, slot, offset, buf, len); +} + +wstdcall ULONG WIN_FUNC(NdisWritePciSlotInformation,5) + (struct ndis_mp_block *nmb, ULONG slot, + ULONG offset, char *buf, ULONG len) +{ + struct wrap_device *wd = nmb->wnd->wd; + ULONG i; + for (i = 0; i < len; i++) + if (pci_write_config_byte(wd->pci.pdev, offset + i, buf[i]) != + PCIBIOS_SUCCESSFUL) + break; + DBG_BLOCK(2) { + if (i != len) + WARNING("%u, %u", i, len); + } + return i; +} + +wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterIoPortRange,4) + (void **virt, struct ndis_mp_block *nmb, UINT start, UINT len) +{ + ENTER3("%08x %08x", start, len); + *virt = (void *)(ULONG_PTR)start; + return NDIS_STATUS_SUCCESS; +} + +wstdcall void WIN_FUNC(NdisMDeregisterIoPortRange,4) + (struct ndis_mp_block *nmb, UINT start, UINT len, void* virt) +{ + ENTER1("%08x %08x", start, len); +} + +wstdcall void WIN_FUNC(NdisReadPortUchar,3) + (struct ndis_mp_block *nmb, ULONG port, char *data) +{ + *data = inb(port); +} + +wstdcall void WIN_FUNC(NdisImmediateReadPortUchar,3) + (struct ndis_mp_block *nmb, ULONG port, char *data) +{ + *data = inb(port); +} + +wstdcall void WIN_FUNC(NdisWritePortUchar,3) + (struct ndis_mp_block *nmb, ULONG port, char data) +{ + outb(data, port); +} + +wstdcall void WIN_FUNC(NdisImmediateWritePortUchar,3) + (struct ndis_mp_block *nmb, ULONG port, char data) +{ + outb(data, port); +} + +wstdcall void WIN_FUNC(NdisMQueryAdapterResources,4) + (NDIS_STATUS *status, struct ndis_mp_block *nmb, + NDIS_RESOURCE_LIST *resource_list, UINT *size) +{ + struct ndis_device *wnd = nmb->wnd; + NDIS_RESOURCE_LIST *list; + UINT resource_length; + + list = &wnd->wd->resource_list->list->partial_resource_list; + resource_length = sizeof(struct cm_partial_resource_list) + + sizeof(struct cm_partial_resource_descriptor) * + (list->count - 1); + TRACE2("%p, %p,%d (%d), %p %d %d", wnd, resource_list, *size, + resource_length, &list->partial_descriptors[list->count-1], + list->partial_descriptors[list->count-1].u.interrupt.level, + list->partial_descriptors[list->count-1].u.interrupt.vector); + if (*size < sizeof(*list)) { + *size = resource_length; + *status = NDIS_STATUS_BUFFER_TOO_SHORT; + } else { + ULONG count; + if (*size >= resource_length) { + *size = resource_length; + count = list->count; + } else { + UINT n = sizeof(*list); + count = 1; + while (count++ < list->count && n < *size) + n += sizeof(list->partial_descriptors); + *size = n; + } + memcpy(resource_list, list, *size); + resource_list->count = count; + *status = NDIS_STATUS_SUCCESS; + } + EXIT2(return); +} + +wstdcall NDIS_STATUS WIN_FUNC(NdisMPciAssignResources,3) + (struct ndis_mp_block *nmb, ULONG slot_number, + NDIS_RESOURCE_LIST **resources) +{ + struct ndis_device *wnd = nmb->wnd; + + ENTER2("%p, %p", wnd, wnd->wd->resource_list); + *resources = &wnd->wd->resource_list->list->partial_resource_list; + EXIT2(return NDIS_STATUS_SUCCESS); +} + +wstdcall NDIS_STATUS WIN_FUNC(NdisMMapIoSpace,4) + (void __iomem **virt, struct ndis_mp_block *nmb, + NDIS_PHY_ADDRESS phy_addr, UINT len) +{ + struct ndis_device *wnd = nmb->wnd; + + ENTER2("%Lx, %d", phy_addr, len); + *virt = MmMapIoSpace(phy_addr, len, MmCached); + if (*virt == NULL) { + ERROR("ioremap failed"); + EXIT2(return NDIS_STATUS_FAILURE); + } + wnd->mem_start = phy_addr; + wnd->mem_end = phy_addr + len; + TRACE2("%p", *virt); + EXIT2(return NDIS_STATUS_SUCCESS); +} + +wstdcall void WIN_FUNC(NdisMUnmapIoSpace,3) + (struct ndis_mp_block *nmb, void __iomem *virt, UINT len) +{ + ENTER2("%p, %d", virt, len); + MmUnmapIoSpace(virt, len); + EXIT2(return); +} + +wstdcall void WIN_FUNC(NdisAllocateSpinLock,1) + (struct ndis_spinlock *lock) +{ + TRACE4("lock %p, %p", lock, &lock->klock); + KeInitializeSpinLock(&lock->klock); + lock->irql = PASSIVE_LEVEL; + return; +} + +wstdcall void WIN_FUNC(NdisFreeSpinLock,1) + (struct ndis_spinlock *lock) +{ + TRACE4("lock %p, %p", lock, &lock->klock); + return; +} + +wstdcall void WIN_FUNC(NdisAcquireSpinLock,1) + (struct ndis_spinlock *lock) +{ + ENTER6("lock %p, %p", lock, &lock->klock); +// assert_irql(_irql_ <= DISPATCH_LEVEL); + lock->irql = nt_spin_lock_irql(&lock->klock, DISPATCH_LEVEL); + return; +} + +wstdcall void WIN_FUNC(NdisReleaseSpinLock,1) + (struct ndis_spinlock *lock) +{ + ENTER6("lock %p, %p", lock, &lock->klock); +// assert_irql(_irql_ == DISPATCH_LEVEL); + nt_spin_unlock_irql(&lock->klock, lock->irql); + return; +} + +wstdcall void WIN_FUNC(NdisDprAcquireSpinLock,1) + (struct ndis_spinlock *lock) +{ + ENTER6("lock %p", &lock->klock); +// assert_irql(_irql_ == DISPATCH_LEVEL); + nt_spin_lock(&lock->klock); + return; +} + +wstdcall void WIN_FUNC(NdisDprReleaseSpinLock,1) + (struct ndis_spinlock *lock) +{ + ENTER6("lock %p", &lock->klock); +// assert_irql(_irql_ == DISPATCH_LEVEL); + nt_spin_unlock(&lock->klock); + return; +} + +wstdcall void WIN_FUNC(NdisInitializeReadWriteLock,1) + (struct ndis_rw_lock *rw_lock) +{ + ENTER3("%p", rw_lock); + memset(rw_lock, 0, sizeof(*rw_lock)); + KeInitializeSpinLock(&rw_lock->klock); + return; +} + +/* read/write locks are implemented in a rather simplisitic way - we + * should probably use Linux's rw_lock implementation */ + +wstdcall void WIN_FUNC(NdisAcquireReadWriteLock,3) + (struct ndis_rw_lock *rw_lock, BOOLEAN write, + struct lock_state *lock_state) +{ + if (write) { + while (1) { + if (cmpxchg(&rw_lock->count, 0, -1) == 0) + return; + while (rw_lock->count) + cpu_relax(); + } + return; + } + while (1) { + typeof(rw_lock->count) count; + while ((count = rw_lock->count) < 0) + cpu_relax(); + if (cmpxchg(&rw_lock->count, count, count + 1) == count) + return; + } +} + +wstdcall void WIN_FUNC(NdisReleaseReadWriteLock,2) + (struct ndis_rw_lock *rw_lock, struct lock_state *lock_state) +{ + if (rw_lock->count > 0) + pre_atomic_add(rw_lock->count, -1); + else if (rw_lock->count == -1) + rw_lock->count = 0; + else + WARNING("invalid state: %d", rw_lock->count); +} + +wstdcall NDIS_STATUS WIN_FUNC(NdisMAllocateMapRegisters,5) + (struct ndis_mp_block *nmb, UINT dmachan, + NDIS_DMA_SIZE dmasize, ULONG basemap, ULONG max_buf_size) +{ + struct ndis_device *wnd = nmb->wnd; + + ENTER2("%p, %d %d %d %d", wnd, dmachan, dmasize, basemap, max_buf_size); + if (wnd->dma_map_count > 0) { + WARNING("%s: map registers already allocated: %u", + wnd->net_dev->name, wnd->dma_map_count); + EXIT2(return NDIS_STATUS_RESOURCES); + } + if (dmasize == NDIS_DMA_24BITS) { + if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_24BIT_MASK) || + pci_set_consistent_dma_mask(wnd->wd->pci.pdev, + DMA_24BIT_MASK)) + WARNING("setting dma mask failed"); + } else if (dmasize == NDIS_DMA_32BITS) { + /* consistent dma is in low 32-bits by default */ + if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_32BIT_MASK)) + WARNING("setting dma mask failed"); +#ifdef CONFIG_X86_64 + } else if (dmasize == NDIS_DMA_64BITS) { + if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_64BIT_MASK) || + pci_set_consistent_dma_mask(wnd->wd->pci.pdev, + DMA_64BIT_MASK)) + WARNING("setting dma mask failed"); + else + wnd->net_dev->features |= NETIF_F_HIGHDMA; +#endif + } + /* since memory for buffer is allocated with kmalloc, buffer + * is physically contiguous, so entire map will fit in one + * register */ + if (basemap > 64) { + WARNING("Windows driver %s requesting too many (%u) " + "map registers", wnd->wd->driver->name, basemap); + /* As per NDIS, NDIS_STATUS_RESOURCES should be + * returned, but with that Atheros PCI driver fails - + * for now tolerate it */ +// EXIT2(return NDIS_STATUS_RESOURCES); + } + + wnd->dma_map_addr = kmalloc(basemap * sizeof(*(wnd->dma_map_addr)), + GFP_KERNEL); + if (!wnd->dma_map_addr) + EXIT2(return NDIS_STATUS_RESOURCES); + memset(wnd->dma_map_addr, 0, basemap * sizeof(*(wnd->dma_map_addr))); + wnd->dma_map_count = basemap; + TRACE2("%u", wnd->dma_map_count); + EXIT2(return NDIS_STATUS_SUCCESS); +} + +wstdcall void WIN_FUNC(NdisMFreeMapRegisters,1) + (struct ndis_mp_block *nmb) +{ + struct ndis_device *wnd = nmb->wnd; + int i; + + ENTER2("wnd: %p", wnd); + if (wnd->dma_map_addr) { + for (i = 0; i < wnd->dma_map_count; i++) { + if (wnd->dma_map_addr[i]) + WARNING("%s: dma addr %p not freed by " + "Windows driver", wnd->net_dev->name, + (void *)wnd->dma_map_addr[i]); + } + kfree(wnd->dma_map_addr); + wnd->dma_map_addr = NULL; + } else + WARNING("map registers already freed?"); + wnd->dma_map_count = 0; + EXIT2(return); +} + +wstdcall void WIN_FUNC(NdisMStartBufferPhysicalMapping,6) + (struct ndis_mp_block *nmb, ndis_buffer *buf, + ULONG index, BOOLEAN write_to_dev, + struct ndis_phy_addr_unit *phy_addr_array, UINT *array_size) +{ + struct ndis_device *wnd = nmb->wnd; + + ENTER3("%p, %p, %u, %u", wnd, buf, index, wnd->dma_map_count); + if (unlikely(wnd->sg_dma_size || !write_to_dev || + index >= wnd->dma_map_count)) { + WARNING("invalid request: %d, %d, %d, %d", wnd->sg_dma_size, + write_to_dev, index, wnd->dma_map_count); + phy_addr_array[0].phy_addr = 0; + phy_addr_array[0].length = 0; + *array_size = 0; + return; + } + if (wnd->dma_map_addr[index]) { + TRACE2("buffer %p at %d is already mapped: %lx", buf, index, + (unsigned long)wnd->dma_map_addr[index]); +// *array_size = 1; + return; + } + TRACE3("%p, %p, %u", buf, MmGetSystemAddressForMdl(buf), + MmGetMdlByteCount(buf)); + DBG_BLOCK(4) { + dump_bytes(__FUNCTION__, MmGetSystemAddressForMdl(buf), + MmGetMdlByteCount(buf)); + } + wnd->dma_map_addr[index] = + PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, + MmGetSystemAddressForMdl(buf), + MmGetMdlByteCount(buf), PCI_DMA_TODEVICE); + phy_addr_array[0].phy_addr = wnd->dma_map_addr[index]; + phy_addr_array[0].length = MmGetMdlByteCount(buf); + TRACE4("%Lx, %d, %d", phy_addr_array[0].phy_addr, + phy_addr_array[0].length, index); + *array_size = 1; +} + +wstdcall void WIN_FUNC(NdisMCompleteBufferPhysicalMapping,3) + (struct ndis_mp_block *nmb, ndis_buffer *buf, ULONG index) +{ + struct ndis_device *wnd = nmb->wnd; + + ENTER3("%p, %p %u (%u)", wnd, buf, index, wnd->dma_map_count); + + if (unlikely(wnd->sg_dma_size)) + WARNING("buffer %p may have been unmapped already", buf); + if (index >= wnd->dma_map_count) { + ERROR("invalid map register (%u >= %u)", + index, wnd->dma_map_count); + return; + } + TRACE4("%lx", (unsigned long)wnd->dma_map_addr[index]); + if (wnd->dma_map_addr[index]) { + PCI_DMA_UNMAP_SINGLE(wnd->wd->pci.pdev, wnd->dma_map_addr[index], + MmGetMdlByteCount(buf), PCI_DMA_TODEVICE); + wnd->dma_map_addr[index] = 0; + } else + WARNING("map registers at %u not used", index); +} + +wstdcall void WIN_FUNC(NdisMAllocateSharedMemory,5) + (struct ndis_mp_block *nmb, ULONG size, + BOOLEAN cached, void **virt, NDIS_PHY_ADDRESS *phys) +{ + dma_addr_t dma_addr; + struct wrap_device *wd = nmb->wnd->wd; + + ENTER3("size: %u, cached: %d", size, cached); + *virt = PCI_DMA_ALLOC_COHERENT(wd->pci.pdev, size, &dma_addr); + if (*virt) + *phys = dma_addr; + else + WARNING("couldn't allocate %d bytes of %scached DMA memory", + size, cached ? "" : "un-"); + EXIT3(return); +} + +wstdcall void WIN_FUNC(NdisMFreeSharedMemory,5) + (struct ndis_mp_block *nmb, ULONG size, BOOLEAN cached, + void *virt, NDIS_PHY_ADDRESS addr) +{ + struct wrap_device *wd = nmb->wnd->wd; + ENTER3("%p, %Lx, %u", virt, addr, size); + PCI_DMA_FREE_COHERENT(wd->pci.pdev, size, virt, addr); + EXIT3(return); +} + +wstdcall void alloc_shared_memory_async(void *arg1, void *arg2) +{ + struct ndis_device *wnd; + struct alloc_shared_mem *alloc_shared_mem; + struct miniport *mp; + void *virt; + NDIS_PHY_ADDRESS phys; + KIRQL irql; + + wnd = arg1; + alloc_shared_mem = arg2; + mp = &wnd->wd->driver->ndis_driver->mp; + NdisMAllocateSharedMemory(wnd->nmb, alloc_shared_mem->size, + alloc_shared_mem->cached, &virt, &phys); + irql = serialize_lock_irql(wnd); + assert_irql(_irql_ == DISPATCH_LEVEL); + LIN2WIN5(mp->alloc_complete, wnd->nmb, virt, + &phys, alloc_shared_mem->size, alloc_shared_mem->ctx); + serialize_unlock_irql(wnd, irql); + kfree(alloc_shared_mem); +} +WIN_FUNC_DECL(alloc_shared_memory_async,2) + +wstdcall NDIS_STATUS WIN_FUNC(NdisMAllocateSharedMemoryAsync,4) + (struct ndis_mp_block *nmb, ULONG size, BOOLEAN cached, void *ctx) +{ + struct ndis_device *wnd = nmb->wnd; + struct alloc_shared_mem *alloc_shared_mem; + + ENTER3("wnd: %p", wnd); + alloc_shared_mem = kmalloc(sizeof(*alloc_shared_mem), irql_gfp()); + if (!alloc_shared_mem) { + WARNING("couldn't allocate memory"); + return NDIS_STATUS_FAILURE; + } + + alloc_shared_mem->size = size; + alloc_shared_mem->cached = cached; + alloc_shared_mem->ctx = ctx; + if (schedule_ntos_work_item(WIN_FUNC_PTR(alloc_shared_memory_async,2), + wnd, alloc_shared_mem)) + EXIT3(return NDIS_STATUS_FAILURE); + EXIT3(return NDIS_STATUS_PENDING); +} + +/* Some drivers allocate NDIS_BUFFER (aka MDL) very often; instead of + * allocating and freeing with kernel functions, we chain them into + * ndis_buffer_pool. When an MDL is freed, it is added to the list of + * free MDLs. When allocated, we first check if there is one in free + * list and if so just return it; otherwise, we allocate a new one and + * return that. This reduces memory fragmentation. Windows DDK says + * that the driver itself shouldn't check what is returned in + * pool_handle, presumably because buffer pools are not used in + * XP. However, as long as driver follows rest of the semantics - that + * it should indicate maximum number of MDLs used with num_descr and + * pass the same pool_handle in other buffer functions, this should + * work. Sadly, though, NdisFreeBuffer doesn't pass the pool_handle, + * so we use 'process' field of MDL to store pool_handle. */ + +wstdcall void WIN_FUNC(NdisAllocateBufferPool,3) + (NDIS_STATUS *status, struct ndis_buffer_pool **pool_handle, + UINT num_descr) +{ + struct ndis_buffer_pool *pool; + + ENTER1("buffers: %d", num_descr); + pool = kmalloc(sizeof(*pool), irql_gfp()); + if (!pool) { + *status = NDIS_STATUS_RESOURCES; + EXIT3(return); + } + spin_lock_init(&pool->lock); + pool->max_descr = num_descr; + pool->num_allocated_descr = 0; + pool->free_descr = NULL; + *pool_handle = pool; + *status = NDIS_STATUS_SUCCESS; + TRACE1("pool: %p, num_descr: %d", pool, num_descr); + EXIT1(return); +} + +wstdcall void WIN_FUNC(NdisAllocateBuffer,5) + (NDIS_STATUS *status, ndis_buffer **buffer, + struct ndis_buffer_pool *pool, void *virt, UINT length) +{ + ndis_buffer *descr; + + ENTER4("pool: %p (%d)", pool, pool->num_allocated_descr); + /* NDIS drivers should call this at DISPATCH_LEVEL, but + * alloc_tx_packet calls at SOFT_IRQL */ + assert_irql(_irql_ <= SOFT_LEVEL); + if (!pool) { + *status = NDIS_STATUS_FAILURE; + *buffer = NULL; + EXIT4(return); + } + spin_lock_bh(&pool->lock); + if ((descr = pool->free_descr)) + pool->free_descr = descr->next; + spin_unlock_bh(&pool->lock); + if (descr) { + typeof(descr->flags) flags; + flags = descr->flags; + memset(descr, 0, sizeof(*descr)); + MmInitializeMdl(descr, virt, length); + if (flags & MDL_CACHE_ALLOCATED) + descr->flags |= MDL_CACHE_ALLOCATED; + } else { + if (pool->num_allocated_descr > pool->max_descr) { + TRACE2("pool %p is full: %d(%d)", pool, + pool->num_allocated_descr, pool->max_descr); +#ifndef ALLOW_POOL_OVERFLOW + *status = NDIS_STATUS_FAILURE; + *buffer = NULL; + return; +#endif + } + descr = allocate_init_mdl(virt, length); + if (!descr) { + WARNING("couldn't allocate buffer"); + *status = NDIS_STATUS_FAILURE; + *buffer = NULL; + EXIT4(return); + } + TRACE4("buffer %p for %p, %d", descr, virt, length); + atomic_inc_var(pool->num_allocated_descr); + } + /* TODO: make sure this mdl can map given buffer */ + MmBuildMdlForNonPagedPool(descr); +// descr->flags |= MDL_ALLOCATED_FIXED_SIZE | +// MDL_MAPPED_TO_SYSTEM_VA | MDL_PAGES_LOCKED; + descr->pool = pool; + *buffer = descr; + *status = NDIS_STATUS_SUCCESS; + TRACE4("buffer: %p", descr); + EXIT4(return); +} + +wstdcall void WIN_FUNC(NdisFreeBuffer,1) + (ndis_buffer *buffer) +{ + struct ndis_buffer_pool *pool; + + ENTER4("%p", buffer); + if (!buffer || !buffer->pool) { + ERROR("invalid buffer"); + EXIT4(return); + } + pool = buffer->pool; + if (pool->num_allocated_descr > MAX_ALLOCATED_NDIS_BUFFERS) { + /* NB NB NB: set mdl's 'pool' field to NULL before + * calling free_mdl; otherwise free_mdl calls + * NdisFreeBuffer back */ + atomic_dec_var(pool->num_allocated_descr); + buffer->pool = NULL; + free_mdl(buffer); + } else { + spin_lock_bh(&pool->lock); + buffer->next = pool->free_descr; + pool->free_descr = buffer; + spin_unlock_bh(&pool->lock); + } + EXIT4(return); +} + +wstdcall void WIN_FUNC(NdisFreeBufferPool,1) + (struct ndis_buffer_pool *pool) +{ + ndis_buffer *cur, *next; + + TRACE3("pool: %p", pool); + if (!pool) { + WARNING("invalid pool"); + EXIT3(return); + } + spin_lock_bh(&pool->lock); + cur = pool->free_descr; + while (cur) { + next = cur->next; + cur->pool = NULL; + free_mdl(cur); + cur = next; + } + spin_unlock_bh(&pool->lock); + kfree(pool); + pool = NULL; + EXIT3(return); +} + +wstdcall void WIN_FUNC(NdisAdjustBufferLength,2) + (ndis_buffer *buffer, UINT length) +{ + ENTER4("%p, %d", buffer, length); + buffer->bytecount = length; +} + +wstdcall void WIN_FUNC(NdisQueryBuffer,3) + (ndis_buffer *buffer, void **virt, UINT *length) +{ + ENTER4("buffer: %p", buffer); + if (virt) + *virt = MmGetSystemAddressForMdl(buffer); + *length = MmGetMdlByteCount(buffer); + TRACE4("%p, %u", virt? *virt : NULL, *length); + return; +} + +wstdcall void WIN_FUNC(NdisQueryBufferSafe,4) + (ndis_buffer *buffer, void **virt, UINT *length, + enum mm_page_priority priority) +{ + ENTER4("%p, %p, %p, %d", buffer, virt, length, priority); + if (virt) + *virt = MmGetSystemAddressForMdlSafe(buffer, priority); + *length = MmGetMdlByteCount(buffer); + TRACE4("%p, %u", virt? *virt : NULL, *length); +} + +wstdcall void *WIN_FUNC(NdisBufferVirtualAddress,1) + (ndis_buffer *buffer) +{ + ENTER3("%p", buffer); + return MmGetSystemAddressForMdl(buffer); +} + +wstdcall ULONG WIN_FUNC(NdisBufferLength,1) + (ndis_buffer *buffer) +{ + ENTER3("%p", buffer); + return MmGetMdlByteCount(buffer); +} + +wstdcall void WIN_FUNC(NdisQueryBufferOffset,3) + (ndis_buffer *buffer, UINT *offset, UINT *length) +{ + ENTER3("%p", buffer); + *offset = MmGetMdlByteOffset(buffer); + *length = MmGetMdlByteCount(buffer); + TRACE3("%d, %d", *offset, *length); +} + +wstdcall void WIN_FUNC(NdisUnchainBufferAtBack,2) + (struct ndis_packet *packet, ndis_buffer **buffer) +{ + ndis_buffer *b, *btail; + + ENTER3("%p", packet); + b = packet->private.buffer_head; + if (!b) { + /* no buffer in packet */ + *buffer = NULL; + EXIT3(return); + } + btail = packet->private.buffer_tail; + *buffer = btail; + if (b == btail) { + /* one buffer in packet */ + packet->private.buffer_head = NULL; + packet->private.buffer_tail = NULL; + } else { + while (b->next != btail) + b = b->next; + packet->private.buffer_tail = b; + b->next = NULL; + } + packet->private.valid_counts = FALSE; + EXIT3(return); +} + +wstdcall void WIN_FUNC(NdisUnchainBufferAtFront,2) + (struct ndis_packet *packet, ndis_buffer **buffer) +{ + ENTER3("%p", packet); + if (packet->private.buffer_head == NULL) { + /* no buffer in packet */ + *buffer = NULL; + EXIT3(return); + } + + *buffer = packet->private.buffer_head; + if (packet->private.buffer_head == packet->private.buffer_tail) { + /* one buffer in packet */ + packet->private.buffer_head = NULL; + packet->private.buffer_tail = NULL; + } else + packet->private.buffer_head = (*buffer)->next; + + packet->private.valid_counts = FALSE; + EXIT3(return); +} + +wstdcall void WIN_FUNC(NdisGetFirstBufferFromPacketSafe,6) + (struct ndis_packet *packet, ndis_buffer **first_buffer, + void **first_buffer_va, UINT *first_buffer_length, + UINT *total_buffer_length, enum mm_page_priority priority) +{ + ndis_buffer *b = packet->private.buffer_head; + + ENTER3("%p(%p)", packet, b); + *first_buffer = b; + if (b) { + *first_buffer_va = MmGetSystemAddressForMdlSafe(b, priority); + *first_buffer_length = *total_buffer_length = + MmGetMdlByteCount(b); + for (b = b->next; b; b = b->next) + *total_buffer_length += MmGetMdlByteCount(b); + } else { + *first_buffer_va = NULL; + *first_buffer_length = 0; + *total_buffer_length = 0; + } + TRACE3("%p, %d, %d", *first_buffer_va, *first_buffer_length, + *total_buffer_length); + EXIT3(return); +} + +wstdcall void WIN_FUNC(NdisGetFirstBufferFromPacket,6) + (struct ndis_packet *packet, ndis_buffer **first_buffer, + void **first_buffer_va, UINT *first_buffer_length, + UINT *total_buffer_length, enum mm_page_priority priority) +{ + NdisGetFirstBufferFromPacketSafe(packet, first_buffer, + first_buffer_va, first_buffer_length, + total_buffer_length, + NormalPagePriority); +} + +wstdcall void WIN_FUNC(NdisAllocatePacketPoolEx,5) + (NDIS_STATUS *status, struct ndis_packet_pool **pool_handle, + UINT num_descr, UINT overflowsize, UINT proto_rsvd_length) +{ + struct ndis_packet_pool *pool; + + ENTER3("buffers: %d, length: %d", num_descr, proto_rsvd_length); + pool = kzalloc(sizeof(*pool), irql_gfp()); + if (!pool) { + *status = NDIS_STATUS_RESOURCES; + EXIT3(return); + } + spin_lock_init(&pool->lock); + pool->max_descr = num_descr; + pool->num_allocated_descr = 0; + pool->num_used_descr = 0; + pool->free_descr = NULL; + pool->proto_rsvd_length = proto_rsvd_length; + *pool_handle = pool; + *status = NDIS_STATUS_SUCCESS; + TRACE3("pool: %p", pool); + EXIT3(return); +} + +wstdcall void WIN_FUNC(NdisAllocatePacketPool,4) + (NDIS_STATUS *status, struct ndis_packet_pool **pool_handle, + UINT num_descr, UINT proto_rsvd_length) +{ + NdisAllocatePacketPoolEx(status, pool_handle, num_descr, 0, + proto_rsvd_length); + EXIT3(return); +} + +wstdcall void WIN_FUNC(NdisFreePacketPool,1) + (struct ndis_packet_pool *pool) +{ + struct ndis_packet *packet, *next; + + ENTER3("pool: %p", pool); + if (!pool) { + WARNING("invalid pool"); + EXIT3(return); + } + spin_lock_bh(&pool->lock); + packet = pool->free_descr; + while (packet) { + next = (struct ndis_packet *)packet->reserved[0]; + kfree(packet); + packet = next; + } + pool->num_allocated_descr = 0; + pool->num_used_descr = 0; + pool->free_descr = NULL; + spin_unlock_bh(&pool->lock); + kfree(pool); + EXIT3(return); +} + +wstdcall UINT WIN_FUNC(NdisPacketPoolUsage,1) + (struct ndis_packet_pool *pool) +{ + EXIT4(return pool->num_used_descr); +} + +wstdcall void WIN_FUNC(NdisAllocatePacket,3) + (NDIS_STATUS *status, struct ndis_packet **ndis_packet, + struct ndis_packet_pool *pool) +{ + struct ndis_packet *packet; + int packet_length; + + ENTER4("pool: %p", pool); + if (!pool) { + *status = NDIS_STATUS_RESOURCES; + *ndis_packet = NULL; + EXIT4(return); + } + assert_irql(_irql_ <= SOFT_LEVEL); + if (pool->num_used_descr > pool->max_descr) { + TRACE3("pool %p is full: %d(%d)", pool, + pool->num_used_descr, pool->max_descr); +#ifndef ALLOW_POOL_OVERFLOW + *status = NDIS_STATUS_RESOURCES; + *ndis_packet = NULL; + return; +#endif + } + /* packet has space for 1 byte in protocol_reserved field */ + packet_length = sizeof(*packet) - 1 + pool->proto_rsvd_length + + sizeof(struct ndis_packet_oob_data); + spin_lock_bh(&pool->lock); + if ((packet = pool->free_descr)) + pool->free_descr = (void *)packet->reserved[0]; + spin_unlock_bh(&pool->lock); + if (!packet) { + packet = kmalloc(packet_length, irql_gfp()); + if (!packet) { + WARNING("couldn't allocate packet"); + *status = NDIS_STATUS_RESOURCES; + *ndis_packet = NULL; + return; + } + atomic_inc_var(pool->num_allocated_descr); + } + TRACE4("%p, %p", pool, packet); + atomic_inc_var(pool->num_used_descr); + memset(packet, 0, packet_length); + packet->private.oob_offset = + packet_length - sizeof(struct ndis_packet_oob_data); + packet->private.packet_flags = fPACKET_ALLOCATED_BY_NDIS; + packet->private.pool = pool; + *ndis_packet = packet; + *status = NDIS_STATUS_SUCCESS; + EXIT4(return); +} + +wstdcall void WIN_FUNC(NdisDprAllocatePacket,3) + (NDIS_STATUS *status, struct ndis_packet **packet, + struct ndis_packet_pool *pool) +{ + NdisAllocatePacket(status, packet, pool); +} + +wstdcall void WIN_FUNC(NdisFreePacket,1) + (struct ndis_packet *packet) +{ + struct ndis_packet_pool *pool; + + ENTER4("%p, %p", packet, packet->private.pool); + pool = packet->private.pool; + if (!pool) { + ERROR("invalid pool %p", packet); + EXIT4(return); + } + assert((int)pool->num_used_descr > 0); + atomic_dec_var(pool->num_used_descr); + if (packet->reserved[1]) { + TRACE3("%p, %p", packet, (void *)packet->reserved[1]); + kfree((void *)packet->reserved[1]); + packet->reserved[1] = 0; + } + if (pool->num_allocated_descr > MAX_ALLOCATED_NDIS_PACKETS) { + TRACE3("%p", pool); + atomic_dec_var(pool->num_allocated_descr); + kfree(packet); + } else { + TRACE4("%p, %p, %p", pool, packet, pool->free_descr); + spin_lock_bh(&pool->lock); + packet->reserved[0] = + (typeof(packet->reserved[0]))pool->free_descr; + pool->free_descr = packet; + spin_unlock_bh(&pool->lock); + } + EXIT4(return); +} + +wstdcall struct ndis_packet_stack *WIN_FUNC(NdisIMGetCurrentPacketStack,2) + (struct ndis_packet *packet, BOOLEAN *stacks_remain) +{ + struct ndis_packet_stack *stack; + + if (!packet->reserved[1]) { + stack = kzalloc(2 * sizeof(*stack), irql_gfp()); + TRACE3("%p, %p", packet, stack); + packet->reserved[1] = (typeof(packet->reserved[1]))stack; + } else { + stack = (void *)packet->reserved[1];; + if (xchg(&stack->ndis_reserved[0], 1)) { + stack++; + if (xchg(&stack->ndis_reserved[0], 1)) + stack = NULL; + } + TRACE3("%p", stack); + } + if (stack) + *stacks_remain = TRUE; + else + *stacks_remain = FALSE; + + EXIT3(return stack); +} + +wstdcall void WIN_FUNC(NdisCopyFromPacketToPacketSafe,7) + (struct ndis_packet *dst, UINT dst_offset, UINT num_to_copy, + struct ndis_packet *src, UINT src_offset, UINT *num_copied, + enum mm_page_priority priority) +{ + UINT dst_n, src_n, n, left; + ndis_buffer *dst_buf; + ndis_buffer *src_buf; + + ENTER4(""); + if (!dst || !src) { + *num_copied = 0; + EXIT4(return); + } + + dst_buf = dst->private.buffer_head; + src_buf = src->private.buffer_head; + + if (!dst_buf || !src_buf) { + *num_copied = 0; + EXIT4(return); + } + dst_n = MmGetMdlByteCount(dst_buf) - dst_offset; + src_n = MmGetMdlByteCount(src_buf) - src_offset; + + n = min(src_n, dst_n); + n = min(n, num_to_copy); + memcpy(MmGetSystemAddressForMdl(dst_buf) + dst_offset, + MmGetSystemAddressForMdl(src_buf) + src_offset, n); + + left = num_to_copy - n; + while (left > 0) { + src_offset += n; + dst_offset += n; + dst_n -= n; + src_n -= n; + if (dst_n == 0) { + dst_buf = dst_buf->next; + if (!dst_buf) + break; + dst_n = MmGetMdlByteCount(dst_buf); + dst_offset = 0; + } + if (src_n == 0) { + src_buf = src_buf->next; + if (!src_buf) + break; + src_n = MmGetMdlByteCount(src_buf); + src_offset = 0; + } + + n = min(src_n, dst_n); + n = min(n, left); + memcpy(MmGetSystemAddressForMdl(dst_buf) + dst_offset, + MmGetSystemAddressForMdl(src_buf) + src_offset, n); + left -= n; + } + *num_copied = num_to_copy - left; + EXIT4(return); +} + +wstdcall void WIN_FUNC(NdisCopyFromPacketToPacket,6) + (struct ndis_packet *dst, UINT dst_offset, UINT num_to_copy, + struct ndis_packet *src, UINT src_offset, UINT *num_copied) +{ + NdisCopyFromPacketToPacketSafe(dst, dst_offset, num_to_copy, + src, src_offset, num_copied, + NormalPagePriority); + return; +} + +wstdcall void WIN_FUNC(NdisIMCopySendPerPacketInfo,2) + (struct ndis_packet *dst, struct ndis_packet *src) +{ + struct ndis_packet_oob_data *dst_oob, *src_oob; + dst_oob = NDIS_PACKET_OOB_DATA(dst); + src_oob = NDIS_PACKET_OOB_DATA(src); + memcpy(&dst_oob->ext, &src_oob->ext, sizeof(dst_oob->ext)); + return; +} + +wstdcall void WIN_FUNC(NdisSend,3) + (NDIS_STATUS *status, struct ndis_mp_block *nmb, + struct ndis_packet *packet) +{ + struct ndis_device *wnd = nmb->wnd; + struct miniport *mp; + KIRQL irql; + + mp = &wnd->wd->driver->ndis_driver->mp; + if (mp->send_packets) { + irql = serialize_lock_irql(wnd); + assert_irql(_irql_ == DISPATCH_LEVEL); + LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx, &packet, 1); + serialize_unlock_irql(wnd, irql); + if (deserialized_driver(wnd)) + *status = NDIS_STATUS_PENDING; + else { + struct ndis_packet_oob_data *oob_data; + oob_data = NDIS_PACKET_OOB_DATA(packet); + *status = oob_data->status; + switch (*status) { + case NDIS_STATUS_SUCCESS: + free_tx_packet(wnd, packet, *status); + break; + case NDIS_STATUS_PENDING: + break; + case NDIS_STATUS_RESOURCES: + wnd->tx_ok = 0; + break; + case NDIS_STATUS_FAILURE: + default: + free_tx_packet(wnd, packet, *status); + break; + } + } + } else { + irql = serialize_lock_irql(wnd); + assert_irql(_irql_ == DISPATCH_LEVEL); + *status = LIN2WIN3(mp->send, wnd->nmb->mp_ctx, packet, 0); + serialize_unlock_irql(wnd, irql); + switch (*status) { + case NDIS_STATUS_SUCCESS: + free_tx_packet(wnd, packet, *status); + break; + case NDIS_STATUS_PENDING: + break; + case NDIS_STATUS_RESOURCES: + wnd->tx_ok = 0; + break; + case NDIS_STATUS_FAILURE: + default: + free_tx_packet(wnd, packet, *status); + break; + } + } + EXIT3(return); +} + +/* called for serialized drivers only */ +wstdcall void mp_timer_dpc(struct kdpc *kdpc, void *ctx, void *arg1, void *arg2) +{ + struct ndis_mp_timer *timer; + struct ndis_mp_block *nmb; + + timer = ctx; + TIMERENTER("%p, %p, %p, %p", timer, timer->func, timer->ctx, timer->nmb); + assert_irql(_irql_ == DISPATCH_LEVEL); + nmb = timer->nmb; + serialize_lock(nmb->wnd); + LIN2WIN4(timer->func, NULL, timer->ctx, NULL, NULL); + serialize_unlock(nmb->wnd); + TIMEREXIT(return); +} +WIN_FUNC_DECL(mp_timer_dpc,4) + +wstdcall void WIN_FUNC(NdisMInitializeTimer,4) + (struct ndis_mp_timer *timer, struct ndis_mp_block *nmb, + DPC func, void *ctx) +{ + TIMERENTER("%p, %p, %p, %p", timer, func, ctx, nmb); + assert_irql(_irql_ == PASSIVE_LEVEL); + timer->func = func; + timer->ctx = ctx; + timer->nmb = nmb; + if (deserialized_driver(nmb->wnd)) + KeInitializeDpc(&timer->kdpc, func, ctx); + else + KeInitializeDpc(&timer->kdpc, WIN_FUNC_PTR(mp_timer_dpc,4), + timer); + wrap_init_timer(&timer->nt_timer, NotificationTimer, nmb); + TIMEREXIT(return); +} + +wstdcall void WIN_FUNC(NdisMSetPeriodicTimer,2) + (struct ndis_mp_timer *timer, UINT period_ms) +{ + unsigned long expires = MSEC_TO_HZ(period_ms); + + TIMERENTER("%p, %u, %ld", timer, period_ms, expires); + assert_irql(_irql_ <= DISPATCH_LEVEL); + wrap_set_timer(&timer->nt_timer, expires, expires, &timer->kdpc); + TIMEREXIT(return); +} + +wstdcall void WIN_FUNC(NdisMCancelTimer,2) + (struct ndis_mp_timer *timer, BOOLEAN *canceled) +{ + TIMERENTER("%p", timer); + assert_irql(_irql_ <= DISPATCH_LEVEL); + *canceled = KeCancelTimer(&timer->nt_timer); + TIMERTRACE("%d", *canceled); + return; +} + +wstdcall void WIN_FUNC(NdisInitializeTimer,3) + (struct ndis_timer *timer, void *func, void *ctx) +{ + TIMERENTER("%p, %p, %p", timer, func, ctx); + assert_irql(_irql_ == PASSIVE_LEVEL); + KeInitializeDpc(&timer->kdpc, func, ctx); + wrap_init_timer(&timer->nt_timer, NotificationTimer, NULL); + TIMEREXIT(return); +} + +/* NdisMSetTimer is a macro that calls NdisSetTimer with + * ndis_mp_timer typecast to ndis_timer */ + +wstdcall void WIN_FUNC(NdisSetTimer,2) + (struct ndis_timer *timer, UINT duetime_ms) +{ + unsigned long expires = MSEC_TO_HZ(duetime_ms); + + TIMERENTER("%p, %p, %u, %ld", timer, timer->nt_timer.wrap_timer, + duetime_ms, expires); + assert_irql(_irql_ <= DISPATCH_LEVEL); + wrap_set_timer(&timer->nt_timer, expires, 0, &timer->kdpc); + TIMEREXIT(return); +} + +wstdcall void WIN_FUNC(NdisCancelTimer,2) + (struct ndis_timer *timer, BOOLEAN *canceled) +{ + TIMERENTER("%p", timer); + assert_irql(_irql_ <= DISPATCH_LEVEL); + *canceled = KeCancelTimer(&timer->nt_timer); + TIMEREXIT(return); +} + +wstdcall void WIN_FUNC(NdisMRegisterAdapterShutdownHandler,3) + (struct ndis_mp_block *nmb, void *ctx, void *func) +{ + struct ndis_device *wnd = nmb->wnd; + ENTER1("%p", func); + wnd->wd->driver->ndis_driver->mp.shutdown = func; + wnd->shutdown_ctx = ctx; +} + +wstdcall void WIN_FUNC(NdisMDeregisterAdapterShutdownHandler,1) + (struct ndis_mp_block *nmb) +{ + struct ndis_device *wnd = nmb->wnd; + wnd->wd->driver->ndis_driver->mp.shutdown = NULL; + wnd->shutdown_ctx = NULL; +} + +/* TODO: rt61 (serialized) driver doesn't want MiniportEnableInterrupt + * to be called in irq handler, but mrv800c (deserialized) driver + * wants. NDIS is confusing about when to call MiniportEnableInterrupt + * For now, handle these cases with two separate irq handlers based on + * observation of these two drivers. However, it is likely not + * correct. */ +wstdcall void deserialized_irq_handler(struct kdpc *kdpc, void *ctx, + void *arg1, void *arg2) +{ + struct ndis_device *wnd = ctx; + ndis_interrupt_handler irq_handler = arg1; + struct miniport *mp = arg2; + + TRACE6("%p", irq_handler); + assert_irql(_irql_ == DISPATCH_LEVEL); + LIN2WIN1(irq_handler, wnd->nmb->mp_ctx); + if (mp->enable_interrupt) + LIN2WIN1(mp->enable_interrupt, wnd->nmb->mp_ctx); + EXIT6(return); +} +WIN_FUNC_DECL(deserialized_irq_handler,4) + +wstdcall void serialized_irq_handler(struct kdpc *kdpc, void *ctx, + void *arg1, void *arg2) +{ + struct ndis_device *wnd = ctx; + ndis_interrupt_handler irq_handler = arg1; + + TRACE6("%p, %p, %p", wnd, irq_handler, arg2); + assert_irql(_irql_ == DISPATCH_LEVEL); + serialize_lock(wnd); + LIN2WIN1(irq_handler, arg2); + serialize_unlock(wnd); + EXIT6(return); +} +WIN_FUNC_DECL(serialized_irq_handler,4) + +wstdcall BOOLEAN ndis_isr(struct kinterrupt *kinterrupt, void *ctx) +{ + struct ndis_mp_interrupt *mp_interrupt = ctx; + struct ndis_device *wnd = mp_interrupt->nmb->wnd; + BOOLEAN recognized, queue_handler; + + TRACE6("%p", wnd); + /* kernel may call ISR when registering interrupt, in + * the same context if DEBUG_SHIRQ is enabled */ + assert_irql(_irql_ == DIRQL || _irql_ == PASSIVE_LEVEL); + if (mp_interrupt->shared) + LIN2WIN3(mp_interrupt->isr, &recognized, &queue_handler, + wnd->nmb->mp_ctx); + else { + struct miniport *mp; + mp = &wnd->wd->driver->ndis_driver->mp; + LIN2WIN1(mp->disable_interrupt, wnd->nmb->mp_ctx); + /* it is not shared interrupt, so handler must be called */ + recognized = queue_handler = TRUE; + } + if (recognized) { + if (queue_handler) { + TRACE5("%p", &wnd->irq_kdpc); + queue_kdpc(&wnd->irq_kdpc); + } + EXIT6(return TRUE); + } + EXIT6(return FALSE); +} +WIN_FUNC_DECL(ndis_isr,2) + +wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterInterrupt,7) + (struct ndis_mp_interrupt *mp_interrupt, + struct ndis_mp_block *nmb, UINT vector, UINT level, + BOOLEAN req_isr, BOOLEAN shared, enum kinterrupt_mode mode) +{ + struct ndis_device *wnd = nmb->wnd; + struct miniport *mp; + + ENTER1("%p, vector:%d, level:%d, req_isr:%d, shared:%d, mode:%d", + mp_interrupt, vector, level, req_isr, shared, mode); + + mp = &wnd->wd->driver->ndis_driver->mp; + nt_spin_lock_init(&mp_interrupt->lock); + mp_interrupt->irq = vector; + mp_interrupt->isr = mp->isr; + mp_interrupt->mp_dpc = mp->handle_interrupt; + mp_interrupt->nmb = nmb; + mp_interrupt->req_isr = req_isr; + if (shared && !req_isr) + WARNING("shared but dynamic interrupt!"); + mp_interrupt->shared = shared; + wnd->mp_interrupt = mp_interrupt; + if (mp->enable_interrupt) + mp_interrupt->enable = TRUE; + else + mp_interrupt->enable = FALSE; + + if (deserialized_driver(wnd)) { + KeInitializeDpc(&wnd->irq_kdpc, + WIN_FUNC_PTR(deserialized_irq_handler,4), + nmb->wnd); + wnd->irq_kdpc.arg1 = mp->handle_interrupt; + wnd->irq_kdpc.arg2 = mp; + TRACE2("%p, %p, %p, %p", wnd->irq_kdpc.arg1, wnd->irq_kdpc.arg2, + nmb->wnd, nmb->mp_ctx); + } else { + KeInitializeDpc(&wnd->irq_kdpc, + WIN_FUNC_PTR(serialized_irq_handler,4), + nmb->wnd); + wnd->irq_kdpc.arg1 = mp->handle_interrupt; + wnd->irq_kdpc.arg2 = nmb->mp_ctx; + TRACE2("%p, %p, %p", wnd->irq_kdpc.arg1, wnd->irq_kdpc.arg2, + nmb->wnd); + } + + if (IoConnectInterrupt(&mp_interrupt->kinterrupt, + WIN_FUNC_PTR(ndis_isr,2), mp_interrupt, NULL, + vector, DIRQL, DIRQL, mode, shared, 0, FALSE) != + STATUS_SUCCESS) { + printk(KERN_WARNING "%s: request for IRQ %d failed\n", + DRIVER_NAME, vector); + return NDIS_STATUS_RESOURCES; + } + printk(KERN_INFO "%s: using IRQ %d\n", DRIVER_NAME, vector); + EXIT1(return NDIS_STATUS_SUCCESS); +} + +wstdcall void WIN_FUNC(NdisMDeregisterInterrupt,1) + (struct ndis_mp_interrupt *mp_interrupt) +{ + struct ndis_mp_block *nmb; + + ENTER1("%p", mp_interrupt); + nmb = xchg(&mp_interrupt->nmb, NULL); + TRACE1("%p", nmb); + if (!nmb) { + WARNING("interrupt already freed?"); + return; + } + nmb->wnd->mp_interrupt = NULL; + if (dequeue_kdpc(&nmb->wnd->irq_kdpc)) + TRACE2("interrupt kdpc was pending"); + flush_workqueue(wrapndis_wq); + IoDisconnectInterrupt(mp_interrupt->kinterrupt); + EXIT1(return); +} + +wstdcall BOOLEAN WIN_FUNC(NdisMSynchronizeWithInterrupt,3) + (struct ndis_mp_interrupt *mp_interrupt, + PKSYNCHRONIZE_ROUTINE sync_func, void *ctx) +{ + return KeSynchronizeExecution(mp_interrupt->kinterrupt, sync_func, ctx); +} + +/* called via function pointer; but 64-bit RNDIS driver calls directly */ +wstdcall void WIN_FUNC(NdisMIndicateStatus,4) + (struct ndis_mp_block *nmb, NDIS_STATUS status, void *buf, UINT len) +{ + struct ndis_device *wnd = nmb->wnd; + struct ndis_status_indication *si; + + ENTER2("status=0x%x len=%d", status, len); + switch (status) { + case NDIS_STATUS_MEDIA_CONNECT: + netif_carrier_on(wnd->net_dev); + wnd->tx_ok = 1; + if (netif_queue_stopped(wnd->net_dev)) + netif_wake_queue(wnd->net_dev); + if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) { + set_bit(LINK_STATUS_ON, &wnd->ndis_pending_work); + schedule_wrapndis_work(&wnd->ndis_work); + } + break; + case NDIS_STATUS_MEDIA_DISCONNECT: + netif_carrier_off(wnd->net_dev); + netif_stop_queue(wnd->net_dev); + wnd->tx_ok = 0; + if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) { + memset(&wnd->essid, 0, sizeof(wnd->essid)); + set_bit(LINK_STATUS_OFF, &wnd->ndis_pending_work); + schedule_wrapndis_work(&wnd->ndis_work); + } + break; + case NDIS_STATUS_MEDIA_SPECIFIC_INDICATION: + if (!buf) + break; + si = buf; + TRACE2("status_type=%d", si->status_type); + switch (si->status_type) { + case Ndis802_11StatusType_MediaStreamMode: + break; +#ifdef CONFIG_WIRELESS_EXT + case Ndis802_11StatusType_Authentication: + buf = (char *)buf + sizeof(*si); + len -= sizeof(*si); + while (len > 0) { + int pairwise_error = 0, group_error = 0; + struct ndis_auth_req *auth_req = + (struct ndis_auth_req *)buf; + TRACE1(MACSTRSEP, MAC2STR(auth_req->bssid)); + if (auth_req->flags & 0x01) + TRACE2("reauth request"); + if (auth_req->flags & 0x02) + TRACE2("key update request"); + if (auth_req->flags & 0x06) { + pairwise_error = 1; + TRACE2("pairwise_error"); + } + if (auth_req->flags & 0x0E) { + group_error = 1; + TRACE2("group_error"); + } + if (pairwise_error || group_error) { + union iwreq_data wrqu; + struct iw_michaelmicfailure micfailure; + + memset(&micfailure, 0, sizeof(micfailure)); + if (pairwise_error) + micfailure.flags |= + IW_MICFAILURE_PAIRWISE; + if (group_error) + micfailure.flags |= + IW_MICFAILURE_GROUP; + memcpy(micfailure.src_addr.sa_data, + auth_req->bssid, ETH_ALEN); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(micfailure); + wireless_send_event(wnd->net_dev, + IWEVMICHAELMICFAILURE, + &wrqu, (u8 *)&micfailure); + } + len -= auth_req->length; + buf = (char *)buf + auth_req->length; + } + break; + case Ndis802_11StatusType_PMKID_CandidateList: + { + u8 *end; + unsigned long i; + struct ndis_pmkid_candidate_list *cand; + + cand = buf + sizeof(struct ndis_status_indication); + if (len < sizeof(struct ndis_status_indication) + + sizeof(struct ndis_pmkid_candidate_list) || + cand->version != 1) { + WARNING("unrecognized PMKID ignored"); + EXIT1(return); + } + + end = (u8 *)buf + len; + TRACE2("PMKID ver %d num_cand %d", + cand->version, cand->num_candidates); + for (i = 0; i < cand->num_candidates; i++) { + struct iw_pmkid_cand pcand; + union iwreq_data wrqu; + struct ndis_pmkid_candidate *c = + &cand->candidates[i]; + if ((u8 *)(c + 1) > end) { + TRACE2("truncated PMKID"); + break; + } + TRACE2("%ld: " MACSTRSEP " 0x%x", + i, MAC2STR(c->bssid), c->flags); + memset(&pcand, 0, sizeof(pcand)); + if (c->flags & 0x01) + pcand.flags |= IW_PMKID_CAND_PREAUTH; + pcand.index = i; + memcpy(pcand.bssid.sa_data, c->bssid, ETH_ALEN); + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(pcand); + wireless_send_event(wnd->net_dev, IWEVPMKIDCAND, + &wrqu, (u8 *)&pcand); + } + break; + } + case Ndis802_11StatusType_RadioState: + { + struct ndis_radio_status_indication *radio_status = buf; + if (radio_status->radio_state == + Ndis802_11RadioStatusOn) + INFO("radio is turned on"); + else if (radio_status->radio_state == + Ndis802_11RadioStatusHardwareOff) + INFO("radio is turned off by hardware"); + else if (radio_status->radio_state == + Ndis802_11RadioStatusSoftwareOff) + INFO("radio is turned off by software"); + break; + } +#endif + default: + /* is this RSSI indication? */ + TRACE2("unknown indication: %x", si->status_type); + break; + } + break; + default: + TRACE2("unknown status: %08X", status); + break; + } + + EXIT2(return); +} + +/* called via function pointer; but 64-bit RNDIS driver calls directly */ +wstdcall void WIN_FUNC(NdisMIndicateStatusComplete,1) + (struct ndis_mp_block *nmb) +{ + struct ndis_device *wnd = nmb->wnd; + ENTER2("%p", wnd); + if (wnd->tx_ok) + schedule_wrapndis_work(&wnd->tx_work); +} + +/* called via function pointer */ +wstdcall void NdisMSendComplete(struct ndis_mp_block *nmb, + struct ndis_packet *packet, NDIS_STATUS status) +{ + struct ndis_device *wnd = nmb->wnd; + ENTER4("%p, %08X", packet, status); + assert_irql(_irql_ <= DISPATCH_LEVEL); + if (deserialized_driver(wnd)) + free_tx_packet(wnd, packet, status); + else { + struct ndis_packet_oob_data *oob_data; + NDIS_STATUS pkt_status; + TRACE3("%p, %08x", packet, status); + oob_data = NDIS_PACKET_OOB_DATA(packet); + switch ((pkt_status = xchg(&oob_data->status, status))) { + case NDIS_STATUS_NOT_RECOGNIZED: + free_tx_packet(wnd, packet, status); + break; + case NDIS_STATUS_PENDING: + case 0: + break; + default: + WARNING("%p: invalid status: %08X", packet, pkt_status); + break; + } + /* In case a serialized driver has earlier requested a + * pause by returning NDIS_STATUS_RESOURCES during + * MiniportSend(Packets), wakeup tx worker now. + */ + if (xchg(&wnd->tx_ok, 1) == 0) { + TRACE3("%d, %d", wnd->tx_ring_start, wnd->tx_ring_end); + schedule_wrapndis_work(&wnd->tx_work); + } + } + EXIT3(return); +} + +/* called via function pointer */ +wstdcall void NdisMSendResourcesAvailable(struct ndis_mp_block *nmb) +{ + struct ndis_device *wnd = nmb->wnd; + ENTER3("%d, %d", wnd->tx_ring_start, wnd->tx_ring_end); + wnd->tx_ok = 1; + schedule_wrapndis_work(&wnd->tx_work); + EXIT3(return); +} + +wstdcall void return_packet(void *arg1, void *arg2) +{ + struct ndis_device *wnd; + struct ndis_packet *packet; + struct miniport *mp; + KIRQL irql; + + wnd = arg1; + packet = arg2; + ENTER4("%p, %p", wnd, packet); + mp = &wnd->wd->driver->ndis_driver->mp; + irql = serialize_lock_irql(wnd); + assert_irql(_irql_ == DISPATCH_LEVEL); + LIN2WIN2(mp->return_packet, wnd->nmb->mp_ctx, packet); + serialize_unlock_irql(wnd, irql); + EXIT4(return); +} +WIN_FUNC_DECL(return_packet,2) + +/* called via function pointer */ +wstdcall void NdisMIndicateReceivePacket(struct ndis_mp_block *nmb, + struct ndis_packet **packets, + UINT nr_packets) +{ + struct ndis_device *wnd; + ndis_buffer *buffer; + struct ndis_packet *packet; + struct sk_buff *skb; + ULONG i, length, total_length; + struct ndis_packet_oob_data *oob_data; + void *virt; + struct ndis_tcp_ip_checksum_packet_info csum; + + ENTER3("%p, %d", nmb, nr_packets); + assert_irql(_irql_ <= DISPATCH_LEVEL); + wnd = nmb->wnd; + for (i = 0; i < nr_packets; i++) { + packet = packets[i]; + if (!packet) { + WARNING("empty packet ignored"); + continue; + } + wnd->net_dev->last_rx = jiffies; + /* get total number of bytes in packet */ + NdisGetFirstBufferFromPacketSafe(packet, &buffer, &virt, + &length, &total_length, + NormalPagePriority); + TRACE3("%d, %d", length, total_length); + oob_data = NDIS_PACKET_OOB_DATA(packet); + TRACE3("0x%x, 0x%x, %Lu", packet->private.flags, + packet->private.packet_flags, oob_data->time_rxed); + skb = dev_alloc_skb(total_length); + if (skb) { + while (buffer) { + memcpy_skb(skb, MmGetSystemAddressForMdl(buffer), + MmGetMdlByteCount(buffer)); + buffer = buffer->next; + } + skb->dev = wnd->net_dev; + skb->protocol = eth_type_trans(skb, wnd->net_dev); + pre_atomic_add(wnd->net_stats.rx_bytes, total_length); + atomic_inc_var(wnd->net_stats.rx_packets); + csum.value = (typeof(csum.value))(ULONG_PTR) + oob_data->ext.info[TcpIpChecksumPacketInfo]; + TRACE3("0x%05x", csum.value); + if (wnd->rx_csum.value && + (csum.rx.tcp_succeeded || csum.rx.udp_succeeded || + csum.rx.ip_succeeded)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + + if (in_interrupt()) + netif_rx(skb); + else + netif_rx_ni(skb); + } else { + WARNING("couldn't allocate skb; packet dropped"); + atomic_inc_var(wnd->net_stats.rx_dropped); + } + + /* serialized drivers check the status upon return + * from this function */ + if (!deserialized_driver(wnd)) { + oob_data->status = NDIS_STATUS_SUCCESS; + continue; + } + + /* if a deserialized driver sets + * NDIS_STATUS_RESOURCES, then it reclaims the packet + * upon return from this function */ + if (oob_data->status == NDIS_STATUS_RESOURCES) + continue; + + assert(oob_data->status == NDIS_STATUS_SUCCESS); + /* deserialized driver doesn't check the status upon + * return from this function; we need to call + * MiniportReturnPacket later for this packet. Calling + * MiniportReturnPacket from here is not correct - the + * driver doesn't expect it (at least Centrino driver + * crashes) */ + schedule_ntos_work_item(WIN_FUNC_PTR(return_packet,2), + wnd, packet); + } + EXIT3(return); +} + +/* called via function pointer (by NdisMEthIndicateReceive macro); the + * first argument is nmb->eth_db */ +wstdcall void EthRxIndicateHandler(struct ndis_mp_block *nmb, void *rx_ctx, + char *header1, char *header, UINT header_size, + void *look_ahead, UINT look_ahead_size, + UINT packet_size) +{ + struct sk_buff *skb = NULL; + struct ndis_device *wnd; + unsigned int skb_size = 0; + KIRQL irql; + struct ndis_packet_oob_data *oob_data; + + ENTER3("nmb = %p, rx_ctx = %p, buf = %p, size = %d, buf = %p, " + "size = %d, packet = %d", nmb, rx_ctx, header, header_size, + look_ahead, look_ahead_size, packet_size); + + wnd = nmb->wnd; + TRACE3("wnd = %p", wnd); + if (!wnd) { + ERROR("nmb is NULL"); + EXIT3(return); + } + wnd->net_dev->last_rx = jiffies; + + if (look_ahead_size < packet_size) { + struct ndis_packet *packet; + struct miniport *mp; + unsigned int bytes_txed; + NDIS_STATUS res; + + NdisAllocatePacket(&res, &packet, wnd->tx_packet_pool); + if (res != NDIS_STATUS_SUCCESS) { + atomic_inc_var(wnd->net_stats.rx_dropped); + EXIT3(return); + } + oob_data = NDIS_PACKET_OOB_DATA(packet); + mp = &wnd->wd->driver->ndis_driver->mp; + irql = serialize_lock_irql(wnd); + assert_irql(_irql_ == DISPATCH_LEVEL); + res = LIN2WIN6(mp->tx_data, packet, &bytes_txed, nmb, + rx_ctx, look_ahead_size, packet_size); + serialize_unlock_irql(wnd, irql); + TRACE3("%d, %d, %d", header_size, look_ahead_size, bytes_txed); + if (res == NDIS_STATUS_SUCCESS) { + ndis_buffer *buffer; + struct ndis_tcp_ip_checksum_packet_info csum; + skb = dev_alloc_skb(header_size + look_ahead_size + + bytes_txed); + if (!skb) { + ERROR("couldn't allocate skb; packet dropped"); + atomic_inc_var(wnd->net_stats.rx_dropped); + NdisFreePacket(packet); + return; + } + memcpy_skb(skb, header, header_size); + memcpy_skb(skb, look_ahead, look_ahead_size); + buffer = packet->private.buffer_head; + while (buffer) { + memcpy_skb(skb, + MmGetSystemAddressForMdl(buffer), + MmGetMdlByteCount(buffer)); + buffer = buffer->next; + } + skb_size = header_size + look_ahead_size + bytes_txed; + csum.value = (typeof(csum.value))(ULONG_PTR) + oob_data->ext.info[TcpIpChecksumPacketInfo]; + TRACE3("0x%05x", csum.value); + if (wnd->rx_csum.value && + (csum.rx.tcp_succeeded || csum.rx.udp_succeeded)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + NdisFreePacket(packet); + } else if (res == NDIS_STATUS_PENDING) { + /* driver will call td_complete */ + oob_data->look_ahead = kmalloc(look_ahead_size, + GFP_ATOMIC); + if (!oob_data->look_ahead) { + NdisFreePacket(packet); + ERROR("packet dropped"); + atomic_inc_var(wnd->net_stats.rx_dropped); + EXIT3(return); + } + assert(sizeof(oob_data->header) == header_size); + memcpy(oob_data->header, header, + sizeof(oob_data->header)); + memcpy(oob_data->look_ahead, look_ahead, + look_ahead_size); + oob_data->look_ahead_size = look_ahead_size; + EXIT3(return); + } else { + WARNING("packet dropped: %08X", res); + atomic_inc_var(wnd->net_stats.rx_dropped); + NdisFreePacket(packet); + EXIT3(return); + } + } else { + skb_size = header_size + packet_size; + skb = dev_alloc_skb(skb_size); + if (skb) { + memcpy_skb(skb, header, header_size); + memcpy_skb(skb, look_ahead, packet_size); + } + } + + if (skb) { + skb->dev = wnd->net_dev; + skb->protocol = eth_type_trans(skb, wnd->net_dev); + pre_atomic_add(wnd->net_stats.rx_bytes, skb_size); + atomic_inc_var(wnd->net_stats.rx_packets); + if (in_interrupt()) + netif_rx(skb); + else + netif_rx_ni(skb); + } + + EXIT3(return); +} + +/* called via function pointer */ +wstdcall void NdisMTransferDataComplete(struct ndis_mp_block *nmb, + struct ndis_packet *packet, + NDIS_STATUS status, UINT bytes_txed) +{ + struct ndis_device *wnd = nmb->wnd; + struct sk_buff *skb; + unsigned int skb_size; + struct ndis_packet_oob_data *oob_data; + ndis_buffer *buffer; + struct ndis_tcp_ip_checksum_packet_info csum; + + ENTER3("wnd = %p, packet = %p, bytes_txed = %d", + wnd, packet, bytes_txed); + if (!packet) { + WARNING("illegal packet"); + EXIT3(return); + } + wnd->net_dev->last_rx = jiffies; + oob_data = NDIS_PACKET_OOB_DATA(packet); + skb_size = sizeof(oob_data->header) + oob_data->look_ahead_size + + bytes_txed; + skb = dev_alloc_skb(skb_size); + if (!skb) { + kfree(oob_data->look_ahead); + NdisFreePacket(packet); + ERROR("couldn't allocate skb; packet dropped"); + atomic_inc_var(wnd->net_stats.rx_dropped); + EXIT3(return); + } + memcpy_skb(skb, oob_data->header, sizeof(oob_data->header)); + memcpy_skb(skb, oob_data->look_ahead, oob_data->look_ahead_size); + buffer = packet->private.buffer_head; + while (buffer) { + memcpy_skb(skb, MmGetSystemAddressForMdl(buffer), + MmGetMdlByteCount(buffer)); + buffer = buffer->next; + } + kfree(oob_data->look_ahead); + NdisFreePacket(packet); + skb->dev = wnd->net_dev; + skb->protocol = eth_type_trans(skb, wnd->net_dev); + pre_atomic_add(wnd->net_stats.rx_bytes, skb_size); + atomic_inc_var(wnd->net_stats.rx_packets); + + csum.value = (typeof(csum.value))(ULONG_PTR) + oob_data->ext.info[TcpIpChecksumPacketInfo]; + TRACE3("0x%05x", csum.value); + if (wnd->rx_csum.value && + (csum.rx.tcp_succeeded || csum.rx.udp_succeeded)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + + if (in_interrupt()) + netif_rx(skb); + else + netif_rx_ni(skb); +} + +/* called via function pointer */ +wstdcall void EthRxComplete(struct ndis_mp_block *nmb) +{ + TRACE3(""); +} + +/* called via function pointer */ +wstdcall void NdisMQueryInformationComplete(struct ndis_mp_block *nmb, + NDIS_STATUS status) +{ + struct ndis_device *wnd = nmb->wnd; + typeof(wnd->ndis_req_task) task; + + ENTER2("nmb: %p, wnd: %p, %08X", nmb, wnd, status); + wnd->ndis_req_status = status; + wnd->ndis_req_done = 1; + if ((task = xchg(&wnd->ndis_req_task, NULL))) + wake_up_process(task); + else + WARNING("invalid task"); + EXIT2(return); +} + +/* called via function pointer */ +wstdcall void NdisMSetInformationComplete(struct ndis_mp_block *nmb, + NDIS_STATUS status) +{ + struct ndis_device *wnd = nmb->wnd; + typeof(wnd->ndis_req_task) task; + + ENTER2("status = %08X", status); + wnd->ndis_req_status = status; + wnd->ndis_req_done = 1; + if ((task = xchg(&wnd->ndis_req_task, NULL))) + wake_up_process(task); + else + WARNING("invalid task"); + EXIT2(return); +} + +/* called via function pointer */ +wstdcall void NdisMResetComplete(struct ndis_mp_block *nmb, + NDIS_STATUS status, BOOLEAN address_reset) +{ + struct ndis_device *wnd = nmb->wnd; + typeof(wnd->ndis_req_task) task; + + ENTER2("status: %08X, %u", status, address_reset); + wnd->ndis_req_status = status; + wnd->ndis_req_done = address_reset + 1; + if ((task = xchg(&wnd->ndis_req_task, NULL))) + wake_up_process(task); + else + WARNING("invalid task"); + EXIT2(return); +} + +wstdcall void WIN_FUNC(NdisMSleep,1) + (ULONG us) +{ + unsigned long delay; + + ENTER4("%p: us: %u", current, us); + delay = USEC_TO_HZ(us); + sleep_hz(delay); + TRACE4("%p: done", current); +} + +wstdcall void WIN_FUNC(NdisGetCurrentSystemTime,1) + (LARGE_INTEGER *time) +{ + *time = ticks_1601(); + TRACE5("%Lu, %lu", *time, jiffies); +} + +wstdcall LONG WIN_FUNC(NdisInterlockedDecrement,1) + (LONG *val) +{ + return InterlockedDecrement(val); +} + +wstdcall LONG WIN_FUNC(NdisInterlockedIncrement,1) + (LONG *val) +{ + return InterlockedIncrement(val); +} + +wstdcall struct nt_list *WIN_FUNC(NdisInterlockedInsertHeadList,3) + (struct nt_list *head, struct nt_list *entry, + struct ndis_spinlock *lock) +{ + return ExInterlockedInsertHeadList(head, entry, &lock->klock); +} + +wstdcall struct nt_list *WIN_FUNC(NdisInterlockedInsertTailList,3) + (struct nt_list *head, struct nt_list *entry, + struct ndis_spinlock *lock) +{ + return ExInterlockedInsertTailList(head, entry, &lock->klock); +} + +wstdcall struct nt_list *WIN_FUNC(NdisInterlockedRemoveHeadList,2) + (struct nt_list *head, struct ndis_spinlock *lock) +{ + return ExInterlockedRemoveHeadList(head, &lock->klock); +} + +wstdcall NDIS_STATUS WIN_FUNC(NdisMInitializeScatterGatherDma,3) + (struct ndis_mp_block *nmb, BOOLEAN dma_size, ULONG max_phy_map) +{ + struct ndis_device *wnd = nmb->wnd; + ENTER2("dma_size=%d, maxtransfer=%u", dma_size, max_phy_map); +#ifdef CONFIG_X86_64 + if (dma_size != NDIS_DMA_64BITS) { + TRACE1("DMA size is not 64-bits"); + if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_32BIT_MASK) || + pci_set_consistent_dma_mask(wnd->wd->pci.pdev, + DMA_32BIT_MASK)) + WARNING("setting dma mask failed"); + } +#endif + if ((wnd->attributes & NDIS_ATTRIBUTE_BUS_MASTER) && + wrap_is_pci_bus(wnd->wd->dev_bus)) { + wnd->sg_dma_size = max_phy_map; + return NDIS_STATUS_SUCCESS; + } else + EXIT1(return NDIS_STATUS_NOT_SUPPORTED); +} + +wstdcall ULONG WIN_FUNC(NdisMGetDmaAlignment,1) + (struct ndis_mp_block *nmb) +{ + ENTER3(""); + return dma_get_cache_alignment(); +} + +wstdcall CHAR WIN_FUNC(NdisSystemProcessorCount,0) + (void) +{ + return NR_CPUS; +} + +wstdcall void WIN_FUNC(NdisGetCurrentProcessorCounts,3) + (ULONG *idle, ULONG *kernel_user, ULONG *index) +{ + int cpu = smp_processor_id(); + *idle = kstat_cpu(cpu).cpustat.idle; + *kernel_user = kstat_cpu(cpu).cpustat.system + + kstat_cpu(cpu).cpustat.user; + *index = cpu; +} + +wstdcall void WIN_FUNC(NdisInitializeEvent,1) + (struct ndis_event *ndis_event) +{ + EVENTENTER("%p", ndis_event); + KeInitializeEvent(&ndis_event->nt_event, NotificationEvent, 0); +} + +wstdcall BOOLEAN WIN_FUNC(NdisWaitEvent,2) + (struct ndis_event *ndis_event, UINT ms) +{ + LARGE_INTEGER ticks; + NTSTATUS res; + + EVENTENTER("%p %u", ndis_event, ms); + ticks = -((LARGE_INTEGER)ms * TICKSPERMSEC); + res = KeWaitForSingleObject(&ndis_event->nt_event, 0, 0, TRUE, + ms == 0 ? NULL : &ticks); + if (res == STATUS_SUCCESS) + EXIT3(return TRUE); + else + EXIT3(return FALSE); +} + +wstdcall void WIN_FUNC(NdisSetEvent,1) + (struct ndis_event *ndis_event) +{ + EVENTENTER("%p", ndis_event); + KeSetEvent(&ndis_event->nt_event, 0, 0); +} + +wstdcall void WIN_FUNC(NdisResetEvent,1) + (struct ndis_event *ndis_event) +{ + EVENTENTER("%p", ndis_event); + KeResetEvent(&ndis_event->nt_event); +} + +static void ndis_worker(worker_param_t dummy) +{ + struct nt_list *ent; + struct ndis_work_item *ndis_work_item; + + WORKENTER(""); + while (1) { + spin_lock_bh(&ndis_work_list_lock); + ent = RemoveHeadList(&ndis_work_list); + spin_unlock_bh(&ndis_work_list_lock); + if (!ent) + break; + ndis_work_item = container_of(ent, struct ndis_work_item, list); + WORKTRACE("%p: %p, %p", ndis_work_item, + ndis_work_item->func, ndis_work_item->ctx); + LIN2WIN2(ndis_work_item->func, ndis_work_item, + ndis_work_item->ctx); + WORKTRACE("%p done", ndis_work_item); + } + WORKEXIT(return); +} + +wstdcall NDIS_STATUS WIN_FUNC(NdisScheduleWorkItem,1) + (struct ndis_work_item *ndis_work_item) +{ + ENTER3("%p", ndis_work_item); + spin_lock_bh(&ndis_work_list_lock); + InsertTailList(&ndis_work_list, &ndis_work_item->list); + spin_unlock_bh(&ndis_work_list_lock); + WORKTRACE("scheduling %p", ndis_work_item); + schedule_ndis_work(&ndis_work); + EXIT3(return NDIS_STATUS_SUCCESS); +} + +wstdcall void WIN_FUNC(NdisMGetDeviceProperty,6) + (struct ndis_mp_block *nmb, void **phy_dev, void **func_dev, + void **next_dev, void **alloc_res, void**trans_res) +{ + ENTER2("nmb: %p, phy_dev = %p, func_dev = %p, next_dev = %p, " + "alloc_res = %p, trans_res = %p", nmb, phy_dev, func_dev, + next_dev, alloc_res, trans_res); + if (phy_dev) + *phy_dev = nmb->pdo; + if (func_dev) + *func_dev = nmb->fdo; + if (next_dev) + *next_dev = nmb->next_device; +} + +wstdcall void WIN_FUNC(NdisMRegisterUnloadHandler,2) + (struct driver_object *drv_obj, void *unload) +{ + if (drv_obj) + drv_obj->unload = unload; + return; +} + +wstdcall UINT WIN_FUNC(NdisGetVersion,0) + (void) +{ + return 0x00050001; +} + +wstdcall NDIS_STATUS WIN_FUNC(NdisMQueryAdapterInstanceName,2) + (struct unicode_string *name, struct ndis_mp_block *nmb) +{ + struct ndis_device *wnd = nmb->wnd; + struct ansi_string ansi; + + if (wrap_is_pci_bus(wnd->wd->dev_bus)) + RtlInitAnsiString(&ansi, "PCI Ethernet Adapter"); + else + RtlInitAnsiString(&ansi, "USB Ethernet Adapter"); + + if (RtlAnsiStringToUnicodeString(name, &ansi, TRUE)) + EXIT2(return NDIS_STATUS_RESOURCES); + else + EXIT2(return NDIS_STATUS_SUCCESS); +} + +wstdcall NDIS_STATUS WIN_FUNC(NdisWriteEventLogEntry,7) + (void *handle, NDIS_STATUS code, ULONG value, USHORT n, + void *strings, ULONG datasize, void *data) +{ + TRACE1("0x%x, 0x%x, %u, %u", code, value, n, datasize); + return NDIS_STATUS_SUCCESS; +} + +wstdcall void *WIN_FUNC(NdisGetRoutineAddress,1) + (struct unicode_string *unicode_string) +{ + struct ansi_string ansi_string; + void *address; + + if (RtlUnicodeStringToAnsiString(&ansi_string, unicode_string, TRUE) != + STATUS_SUCCESS) + EXIT1(return NULL); + INFO("%s", ansi_string.buf); + address = ndis_get_routine_address(ansi_string.buf); + RtlFreeAnsiString(&ansi_string); + return address; +} + +wstdcall ULONG WIN_FUNC(NdisReadPcmciaAttributeMemory,4) + (struct ndis_mp_block *nmb, ULONG offset, void *buffer, + ULONG length) +{ + TODO(); + return 0; +} + +wstdcall ULONG WIN_FUNC(NdisWritePcmciaAttributeMemory,4) + (struct ndis_mp_block *nmb, ULONG offset, void *buffer, + ULONG length) +{ + TODO(); + return 0; +} + +wstdcall void WIN_FUNC(NdisMCoIndicateReceivePacket,3) + (struct ndis_mp_block *nmb, struct ndis_packet **packets, + UINT nr_packets) +{ + ENTER3("nmb = %p", nmb); + NdisMIndicateReceivePacket(nmb, packets, nr_packets); + EXIT3(return); +} + +wstdcall void WIN_FUNC(NdisMCoSendComplete,3) + (NDIS_STATUS status, struct ndis_mp_block *nmb, + struct ndis_packet *packet) +{ + ENTER3("%08x", status); + NdisMSendComplete(nmb, packet, status); + EXIT3(return); +} + +wstdcall void WIN_FUNC(NdisMCoRequestComplete,3) + (NDIS_STATUS status, struct ndis_mp_block *nmb, + struct ndis_request *ndis_request) +{ + struct ndis_device *wnd = nmb->wnd; + typeof(wnd->ndis_req_task) task; + + ENTER3("%08X", status); + wnd->ndis_req_status = status; + wnd->ndis_req_done = 1; + if ((task = xchg(&wnd->ndis_req_task, NULL))) + wake_up_process(task); + else + WARNING("invalid task"); + EXIT3(return); +} + +wstdcall NDIS_STATUS WIN_FUNC(NdisIMNotifiyPnPEvent,2) + (struct ndis_mp_block *nmb, struct net_pnp_event *event) +{ + ENTER2("%p, %d", nmb, event->code); + /* NdisWrapper never calls protocol's pnp event notifier, so + * nothing to do here */ + EXIT2(return NDIS_STATUS_SUCCESS); +} + +wstdcall void WIN_FUNC(NdisCompletePnPEvent,2) + (NDIS_STATUS status, void *handle, struct net_pnp_event *event) +{ + ENTER2("%d, %p, %d", status, handle, event->code); + /* NdisWrapper never calls protocol's pnp event notifier, so + * nothing to do here */ + EXIT2(return); +} + +wstdcall NDIS_STATUS WIN_FUNC(NdisMSetMiniportSecondary,2) + (struct ndis_mp_block *nmb2, struct ndis_mp_block *nmb1) +{ + ENTER3("%p, %p", nmb1, nmb2); + TODO(); + EXIT3(return NDIS_STATUS_SUCCESS); +} + +wstdcall NDIS_STATUS WIN_FUNC(NdisMPromoteMiniport,1) + (struct ndis_mp_block *nmb) +{ + ENTER3("%p", nmb); + TODO(); + EXIT3(return NDIS_STATUS_SUCCESS); +} + +wstdcall void WIN_FUNC(NdisMCoActivateVcComplete,3) + (NDIS_STATUS status, void *handle, void *params) +{ + TODO(); +} + +wstdcall void WIN_FUNC(NdisMCoDeactivateVcComplete,2) + (NDIS_STATUS status, void *handle) +{ + TODO(); +} + +wstdcall void WIN_FUNC(NdisMRemoveMiniport,1) + (void *handle) +{ + TODO(); +} + +static void *ndis_get_routine_address(char *name) +{ + int i; + ENTER2("%p", name); + for (i = 0; i < sizeof(ndis_exports) / sizeof(ndis_exports[0]); i++) { + if (strcmp(name, ndis_exports[i].name) == 0) { + TRACE2("%p", ndis_exports[i].func); + return ndis_exports[i].func; + } + } + EXIT2(return NULL); +} + +/* ndis_init_device is called for each device */ +int ndis_init_device(struct ndis_device *wnd) +{ + struct ndis_mp_block *nmb = wnd->nmb; + + KeInitializeSpinLock(&nmb->lock); + wnd->mp_interrupt = NULL; + wnd->wrap_timer_slist.next = NULL; + if (wnd->wd->driver->ndis_driver) + wnd->wd->driver->ndis_driver->mp.shutdown = NULL; + + nmb->filterdbs.eth_db = nmb; + nmb->filterdbs.tr_db = nmb; + nmb->filterdbs.fddi_db = nmb; + nmb->filterdbs.arc_db = nmb; + + nmb->rx_packet = WIN_FUNC_PTR(NdisMIndicateReceivePacket,3); + nmb->send_complete = WIN_FUNC_PTR(NdisMSendComplete,3); + nmb->send_resource_avail = WIN_FUNC_PTR(NdisMSendResourcesAvailable,1); + nmb->status = WIN_FUNC_PTR(NdisMIndicateStatus,4); + nmb->status_complete = WIN_FUNC_PTR(NdisMIndicateStatusComplete,1); + nmb->queryinfo_complete = WIN_FUNC_PTR(NdisMQueryInformationComplete,2); + nmb->setinfo_complete = WIN_FUNC_PTR(NdisMSetInformationComplete,2); + nmb->reset_complete = WIN_FUNC_PTR(NdisMResetComplete,3); + nmb->eth_rx_indicate = WIN_FUNC_PTR(EthRxIndicateHandler,8); + nmb->eth_rx_complete = WIN_FUNC_PTR(EthRxComplete,1); + nmb->td_complete = WIN_FUNC_PTR(NdisMTransferDataComplete,4); + return 0; +} + +/* ndis_exit_device is called for each device */ +void ndis_exit_device(struct ndis_device *wnd) +{ + struct wrap_device_setting *setting; + ENTER2("%p", wnd); + if (down_interruptible(&loader_mutex)) + WARNING("couldn't obtain loader_mutex"); + nt_list_for_each_entry(setting, &wnd->wd->settings, list) { + struct ndis_configuration_parameter *param; + param = setting->encoded; + if (param) { + if (param->type == NdisParameterString) + RtlFreeUnicodeString(¶m->data.string); + ExFreePool(param); + setting->encoded = NULL; + } + } + up(&loader_mutex); +} + +/* ndis_init is called once when module is loaded */ +int ndis_init(void) +{ + InitializeListHead(&ndis_work_list); + spin_lock_init(&ndis_work_list_lock); + initialize_work(&ndis_work, ndis_worker, NULL); + + ndis_wq = create_singlethread_workqueue("ndis_wq"); + if (!ndis_wq) { + WARNING("couldn't create worker thread"); + EXIT1(return -ENOMEM); + } + + ndis_worker_thread = wrap_worker_init(ndis_wq); + TRACE1("%p", ndis_worker_thread); + return 0; +} + +/* ndis_exit is called once when module is removed */ +void ndis_exit(void) +{ + ENTER1(""); + if (ndis_wq) + destroy_workqueue(ndis_wq); + TRACE1("%p", ndis_worker_thread); + if (ndis_worker_thread) + ObDereferenceObject(ndis_worker_thread); + EXIT1(return); +} --- linux-2.6.27.orig/ubuntu/atl2/atl2.h +++ linux-2.6.27/ubuntu/atl2/atl2.h @@ -0,0 +1,120 @@ +/* atl2.h -- atl2 driver definitions + * + * Copyright(c) 2007 Atheros Corporation. All rights reserved. + * Copyright(c) 2006 xiong huang + * Copyright(c) 2007 Chris Snook + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _ATL2_H_ +#define _ATL2_H_ + +#include +#include + +#include "atl2_hw.h" + +struct atl2_ring_header { + /* pointer to the descriptor ring memory */ + void *desc; + /* physical adress of the descriptor ring */ + dma_addr_t dma; + /* length of descriptor ring in bytes */ + unsigned int size; +}; + +/* board specific private data structure */ +struct atl2_adapter { + /* OS defined structs */ + struct net_device *netdev; + struct pci_dev *pdev; + struct net_device_stats net_stats; +#ifdef NETIF_F_HW_VLAN_TX + struct vlan_group *vlgrp; +#endif + u32 wol; + u16 link_speed; + u16 link_duplex; + + spinlock_t stats_lock; + spinlock_t tx_lock; + + struct work_struct reset_task; + struct work_struct link_chg_task; + struct timer_list watchdog_timer; + struct timer_list phy_config_timer; + + unsigned long cfg_phy; + bool mac_disabled; + + /* All Descriptor memory */ + dma_addr_t ring_dma; + void *ring_vir_addr; + int ring_size; + + tx_pkt_header_t *txd_ring; + dma_addr_t txd_dma; + + tx_pkt_status_t *txs_ring; + dma_addr_t txs_dma; + + rx_desc_t *rxd_ring; + dma_addr_t rxd_dma; + + u32 txd_ring_size; // bytes per unit + u32 txs_ring_size; // dwords per unit + u32 rxd_ring_size; // 1536bytes per unit + + // read /write ptr: + // host + u32 txd_write_ptr; + u32 txs_next_clear; + u32 rxd_read_ptr; + + // nic + atomic_t txd_read_ptr; + atomic_t txs_write_ptr; + u32 rxd_write_ptr; + + /* Interrupt Moderator timer ( 2us resolution) */ + u16 imt; + /* Interrupt Clear timer (2us resolution) */ + u16 ict; + + unsigned long flags; + /* structs defined in atl2_hw.h */ + u32 bd_number; // board number; + bool pci_using_64; + bool have_msi; + struct atl2_hw hw; + + u32 usr_cmd; +// u32 regs_buff[ATL2_REGS_LEN]; + u32 pci_state[16]; + + u32 *config_space; +}; + +enum atl2_state_t { + __ATL2_TESTING, + __ATL2_RESETTING, + __ATL2_DOWN +}; + +#endif /* _ATL2_H_ */ --- linux-2.6.27.orig/ubuntu/atl2/Kconfig +++ linux-2.6.27/ubuntu/atl2/Kconfig @@ -0,0 +1,10 @@ +config ATL2 + tristate "Atheros L2 Fast Ethernet support (EXPERIMENTAL)" + depends on PCI && EXPERIMENTAL + select CRC32 + select MII + help + This driver supports the Atheros L2 fast ethernet adapter. + + To compile this driver as a module, choose M here. The module + will be called atl2. --- linux-2.6.27.orig/ubuntu/atl2/atl2_ethtool.c +++ linux-2.6.27/ubuntu/atl2/atl2_ethtool.c @@ -0,0 +1,416 @@ +/* atl2_ethtool.c -- atl2 ethtool support + * + * Copyright(c) 2007 Atheros Corporation. All rights reserved. + * Copyright(c) 2006 xiong huang + * Copyright(c) 2007 Chris Snook + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "atl2.h" +#include "atl2_hw.h" + +extern char atl2_driver_name[]; +extern char atl2_driver_version[]; + +extern int atl2_up(struct atl2_adapter *adapter); +extern void atl2_down(struct atl2_adapter *adapter); +extern void atl2_reinit_locked(struct atl2_adapter *adapter); +extern s32 atl2_reset_hw(struct atl2_hw *hw); + +static int +atl2_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct atl2_hw *hw = &adapter->hw; + + ecmd->supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_TP); + ecmd->advertising = ADVERTISED_TP; + + ecmd->advertising |= ADVERTISED_Autoneg; + ecmd->advertising |= hw->autoneg_advertised; + + ecmd->port = PORT_TP; + ecmd->phy_address = 0; + ecmd->transceiver = XCVR_INTERNAL; + + if (adapter->link_speed != SPEED_0) { + ecmd->speed = adapter->link_speed; + if (adapter->link_duplex == FULL_DUPLEX) + ecmd->duplex = DUPLEX_FULL; + else + ecmd->duplex = DUPLEX_HALF; + } else { + ecmd->speed = -1; + ecmd->duplex = -1; + } + + ecmd->autoneg = AUTONEG_ENABLE; + return 0; +} + +static int +atl2_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct atl2_hw *hw = &adapter->hw; + + while (test_and_set_bit(__ATL2_RESETTING, &adapter->flags)) + msleep(1); + + if (ecmd->autoneg == AUTONEG_ENABLE) { +#define MY_ADV_MASK (ADVERTISE_10_HALF| \ + ADVERTISE_10_FULL| \ + ADVERTISE_100_HALF| \ + ADVERTISE_100_FULL) + + if ((ecmd->advertising&MY_ADV_MASK) == MY_ADV_MASK) { + hw->MediaType = MEDIA_TYPE_AUTO_SENSOR; + hw->autoneg_advertised = MY_ADV_MASK; + } else if ((ecmd->advertising&MY_ADV_MASK) == ADVERTISE_100_FULL) { + hw->MediaType = MEDIA_TYPE_100M_FULL; + hw->autoneg_advertised = ADVERTISE_100_FULL; + } else if ((ecmd->advertising&MY_ADV_MASK) == ADVERTISE_100_HALF) { + hw->MediaType = MEDIA_TYPE_100M_HALF; + hw->autoneg_advertised = ADVERTISE_100_HALF; + } else if ((ecmd->advertising&MY_ADV_MASK) == ADVERTISE_10_FULL) { + hw->MediaType = MEDIA_TYPE_10M_FULL; + hw->autoneg_advertised = ADVERTISE_10_FULL; + } else if ((ecmd->advertising&MY_ADV_MASK) == ADVERTISE_10_HALF) { + hw->MediaType = MEDIA_TYPE_10M_HALF; + hw->autoneg_advertised = ADVERTISE_10_HALF; + } else { + clear_bit(__ATL2_RESETTING, &adapter->flags); + return -EINVAL; + } + ecmd->advertising = hw->autoneg_advertised | + ADVERTISED_TP | ADVERTISED_Autoneg; + } else { + clear_bit(__ATL2_RESETTING, &adapter->flags); + return -EINVAL; + } + + /* reset the link */ + if (netif_running(adapter->netdev)) { + atl2_down(adapter); + atl2_up(adapter); + } else + atl2_reset_hw(&adapter->hw); + + clear_bit(__ATL2_RESETTING, &adapter->flags); + return 0; +} + +static u32 +atl2_get_tx_csum(struct net_device *netdev) +{ + return (netdev->features & NETIF_F_HW_CSUM) != 0; +} + +static u32 +atl2_get_msglevel(struct net_device *netdev) +{ + return 0; +} + +/* + * It's sane for this to be empty, but we might want to take advantage of this. + */ +static void +atl2_set_msglevel(struct net_device *netdev, u32 data) +{ +} + +static int +atl2_get_regs_len(struct net_device *netdev) +{ +#define ATL2_REGS_LEN 42 + return ATL2_REGS_LEN * sizeof(u32); +} + +static void +atl2_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct atl2_hw *hw = &adapter->hw; + u32 *regs_buff = p; + u16 phy_data; + + memset(p, 0, ATL2_REGS_LEN * sizeof(u32)); + + regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id; + + regs_buff[0] = ATL2_READ_REG(hw, REG_VPD_CAP); + regs_buff[1] = ATL2_READ_REG(hw, REG_SPI_FLASH_CTRL); + regs_buff[2] = ATL2_READ_REG(hw, REG_SPI_FLASH_CONFIG); + regs_buff[3] = ATL2_READ_REG(hw, REG_TWSI_CTRL); + regs_buff[4] = ATL2_READ_REG(hw, REG_PCIE_DEV_MISC_CTRL); + regs_buff[5] = ATL2_READ_REG(hw, REG_MASTER_CTRL); + regs_buff[6] = ATL2_READ_REG(hw, REG_MANUAL_TIMER_INIT); + regs_buff[7] = ATL2_READ_REG(hw, REG_IRQ_MODU_TIMER_INIT); + regs_buff[8] = ATL2_READ_REG(hw, REG_PHY_ENABLE); + regs_buff[9] = ATL2_READ_REG(hw, REG_CMBDISDMA_TIMER); + regs_buff[10] = ATL2_READ_REG(hw, REG_IDLE_STATUS); + regs_buff[11] = ATL2_READ_REG(hw, REG_MDIO_CTRL); + regs_buff[12] = ATL2_READ_REG(hw, REG_SERDES_LOCK); + regs_buff[13] = ATL2_READ_REG(hw, REG_MAC_CTRL); + regs_buff[14] = ATL2_READ_REG(hw, REG_MAC_IPG_IFG); + regs_buff[15] = ATL2_READ_REG(hw, REG_MAC_STA_ADDR); + regs_buff[16] = ATL2_READ_REG(hw, REG_MAC_STA_ADDR+4); + regs_buff[17] = ATL2_READ_REG(hw, REG_RX_HASH_TABLE); + regs_buff[18] = ATL2_READ_REG(hw, REG_RX_HASH_TABLE+4); + regs_buff[19] = ATL2_READ_REG(hw, REG_MAC_HALF_DUPLX_CTRL); + regs_buff[20] = ATL2_READ_REG(hw, REG_MTU); + regs_buff[21] = ATL2_READ_REG(hw, REG_WOL_CTRL); + regs_buff[22] = ATL2_READ_REG(hw, REG_SRAM_TXRAM_END); + regs_buff[23] = ATL2_READ_REG(hw, REG_DESC_BASE_ADDR_HI); + regs_buff[24] = ATL2_READ_REG(hw, REG_TXD_BASE_ADDR_LO); + regs_buff[25] = ATL2_READ_REG(hw, REG_TXD_MEM_SIZE); + regs_buff[26] = ATL2_READ_REG(hw, REG_TXS_BASE_ADDR_LO); + regs_buff[27] = ATL2_READ_REG(hw, REG_TXS_MEM_SIZE); + regs_buff[28] = ATL2_READ_REG(hw, REG_RXD_BASE_ADDR_LO); + regs_buff[29] = ATL2_READ_REG(hw, REG_RXD_BUF_NUM); + regs_buff[30] = ATL2_READ_REG(hw, REG_DMAR); + regs_buff[31] = ATL2_READ_REG(hw, REG_TX_CUT_THRESH); + regs_buff[32] = ATL2_READ_REG(hw, REG_DMAW); + regs_buff[33] = ATL2_READ_REG(hw, REG_PAUSE_ON_TH); + regs_buff[34] = ATL2_READ_REG(hw, REG_PAUSE_OFF_TH); + regs_buff[35] = ATL2_READ_REG(hw, REG_MB_TXD_WR_IDX); + regs_buff[36] = ATL2_READ_REG(hw, REG_MB_RXD_RD_IDX); + regs_buff[38] = ATL2_READ_REG(hw, REG_ISR); + regs_buff[39] = ATL2_READ_REG(hw, REG_IMR); + + atl2_read_phy_reg(hw, MII_BMCR, &phy_data); + regs_buff[40] = (u32)phy_data; + atl2_read_phy_reg(hw, MII_BMSR, &phy_data); + regs_buff[41] = (u32)phy_data; +} + +static int +atl2_get_eeprom_len(struct net_device *netdev) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + + if (!atl2_check_eeprom_exist(&adapter->hw)) { + return 512; + } else + return 0; +} + +static int +atl2_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct atl2_hw *hw = &adapter->hw; + u32 *eeprom_buff; + int first_dword, last_dword; + int ret_val = 0; + int i; + + if (eeprom->len == 0) + return -EINVAL; + + if (atl2_check_eeprom_exist(hw)) { + return -EINVAL; + } + + eeprom->magic = hw->vendor_id | (hw->device_id << 16); + + first_dword = eeprom->offset >> 2; + last_dword = (eeprom->offset + eeprom->len - 1) >> 2; + + eeprom_buff = kmalloc(sizeof(u32) * (last_dword - first_dword + 1), GFP_KERNEL); + if (!eeprom_buff) + return -ENOMEM; + + for (i=first_dword; i < last_dword; i++) { + if (!atl2_read_eeprom(hw, i*4, &(eeprom_buff[i-first_dword]))) + return -EIO; + } + + memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 3), + eeprom->len); + kfree(eeprom_buff); + + return ret_val; +} + +static int +atl2_set_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct atl2_hw *hw = &adapter->hw; + u32 *eeprom_buff; + u32 *ptr; + int max_len, first_dword, last_dword, ret_val = 0; + int i; + + if (eeprom->len == 0) + return -EOPNOTSUPP; + + if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) + return -EFAULT; + + max_len = 512; + + first_dword = eeprom->offset >> 2; + last_dword = (eeprom->offset + eeprom->len - 1) >> 2; + eeprom_buff = kmalloc(max_len, GFP_KERNEL); + if (!eeprom_buff) + return -ENOMEM; + + ptr = (u32 *)eeprom_buff; + + if (eeprom->offset & 3) { + /* need read/modify/write of first changed EEPROM word */ + /* only the second byte of the word is being modified */ + if (!atl2_read_eeprom(hw, first_dword*4, &(eeprom_buff[0]))) + return -EIO; + ptr++; + } + if (((eeprom->offset + eeprom->len) & 3) ) { + /* need read/modify/write of last changed EEPROM word */ + /* only the first byte of the word is being modified */ + + if (!atl2_read_eeprom(hw, last_dword*4, &(eeprom_buff[last_dword - first_dword]))) + return -EIO; + } + + /* Device's eeprom is always little-endian, word addressable */ + memcpy(ptr, bytes, eeprom->len); + + for (i = 0; i < last_dword - first_dword + 1; i++) { + if (!atl2_write_eeprom(hw, ((first_dword+i)*4), eeprom_buff[i])) + return -EIO; + } + + kfree(eeprom_buff); + return ret_val; +} + +static void +atl2_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + + strncpy(drvinfo->driver, atl2_driver_name, 32); + strncpy(drvinfo->version, atl2_driver_version, 32); + strncpy(drvinfo->fw_version, "L2", 32); + strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); + drvinfo->n_stats = 0; + drvinfo->testinfo_len = 0; + drvinfo->regdump_len = atl2_get_regs_len(netdev); + drvinfo->eedump_len = atl2_get_eeprom_len(netdev); +} + +static void +atl2_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + + wol->supported = WAKE_MAGIC; + wol->wolopts = 0; + + if (adapter->wol & ATL2_WUFC_EX) + wol->wolopts |= WAKE_UCAST; + if (adapter->wol & ATL2_WUFC_MC) + wol->wolopts |= WAKE_MCAST; + if (adapter->wol & ATL2_WUFC_BC) + wol->wolopts |= WAKE_BCAST; + if (adapter->wol & ATL2_WUFC_MAG) + wol->wolopts |= WAKE_MAGIC; + if (adapter->wol & ATL2_WUFC_LNKC) + wol->wolopts |= WAKE_PHY; +} + +static int +atl2_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + + if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE)) + return -EOPNOTSUPP; + + if (wol->wolopts & (WAKE_MCAST|WAKE_BCAST|WAKE_MCAST)) + return -EOPNOTSUPP; + + /* these settings will always override what we currently have */ + adapter->wol = 0; + + if (wol->wolopts & WAKE_MAGIC) + adapter->wol |= ATL2_WUFC_MAG; + if (wol->wolopts & WAKE_PHY) + adapter->wol |= ATL2_WUFC_LNKC; + + return 0; +} + +static int +atl2_nway_reset(struct net_device *netdev) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + if (netif_running(netdev)) + atl2_reinit_locked(adapter); + return 0; +} + +static struct ethtool_ops atl2_ethtool_ops = { + .get_settings = atl2_get_settings, + .set_settings = atl2_set_settings, + .get_drvinfo = atl2_get_drvinfo, + .get_regs_len = atl2_get_regs_len, + .get_regs = atl2_get_regs, + .get_wol = atl2_get_wol, + .set_wol = atl2_set_wol, + .get_msglevel = atl2_get_msglevel, + .set_msglevel = atl2_set_msglevel, + .nway_reset = atl2_nway_reset, + .get_link = ethtool_op_get_link, + .get_eeprom_len = atl2_get_eeprom_len, + .get_eeprom = atl2_get_eeprom, + .set_eeprom = atl2_set_eeprom, + .get_tx_csum = atl2_get_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, +#ifdef NETIF_F_TSO + .get_tso = ethtool_op_get_tso, +#endif +#if 0 //FIXME: not implemented? +//#ifdef ETHTOOL_GPERMADDR + .get_perm_addr = ethtool_op_get_perm_addr, +#endif +}; + +void +atl2_set_ethtool_ops(struct net_device *netdev) +{ + SET_ETHTOOL_OPS(netdev, &atl2_ethtool_ops); +} --- linux-2.6.27.orig/ubuntu/atl2/Makefile +++ linux-2.6.27/ubuntu/atl2/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_ATL2) += atl2.o + +atl2-objs += atl2_main.o atl2_hw.o atl2_ethtool.o atl2_param.o --- linux-2.6.27.orig/ubuntu/atl2/atl2_param.c +++ linux-2.6.27/ubuntu/atl2/atl2_param.c @@ -0,0 +1,317 @@ +/* atl2_param.c -- atl2 parameter processing + * + * Copyright(c) 2007 Atheros Corporation. All rights reserved. + * Copyright(c) 2006 xiong huang + * Copyright(c) 2007 Chris Snook + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include "atl2.h" + +/* This is the only thing that needs to be changed to adjust the + * maximum number of ports that the driver can manage. + */ +#define ATL2_MAX_NIC 4 + +#define OPTION_UNSET -1 +#define OPTION_DISABLED 0 +#define OPTION_ENABLED 1 + +/* All parameters are treated the same, as an integer array of values. + * This macro just reduces the need to repeat the same declaration code + * over and over (plus this helps to avoid typo bugs). + */ +#define ATL2_PARAM_INIT { [0 ... ATL2_MAX_NIC] = OPTION_UNSET } +#ifndef module_param_array +/* Module Parameters are always initialized to -1, so that the driver + * can tell the difference between no user specified value or the + * user asking for the default value. + * The true default values are loaded in when atl2_check_options is called. + * + * This is a GCC extension to ANSI C. + * See the item "Labeled Elements in Initializers" in the section + * "Extensions to the C Language Family" of the GCC documentation. + */ + +#define ATL2_PARAM(X, desc) \ + static const int __devinitdata X[ATL2_MAX_NIC + 1] = ATL2_PARAM_INIT; \ + MODULE_PARM(X, "1-" __MODULE_STRING(ATL2_MAX_NIC) "i"); \ + MODULE_PARM_DESC(X, desc); +#else +#define ATL2_PARAM(X, desc) \ + static int __devinitdata X[ATL2_MAX_NIC+1] = ATL2_PARAM_INIT; \ + static int num_##X = 0; \ + module_param_array_named(X, X, int, &num_##X, 0); \ + MODULE_PARM_DESC(X, desc); +#endif + +/* Transmit Memory Size + * + * Valid Range: 64-2048 + * + * Default Value: 128 + */ +#define ATL2_MIN_TX_MEMSIZE 4 // 4KB +#define ATL2_MAX_TX_MEMSIZE 64 // 64KB +#define ATL2_DEFAULT_TX_MEMSIZE 8 // 8KB +ATL2_PARAM(TxMemSize, "Bytes of Transmit Memory"); + +/* Receive Memory Block Count + * + * Valid Range: 16-512 + * + * Default Value: 128 + */ +#define ATL2_MIN_RXD_COUNT 16 +#define ATL2_MAX_RXD_COUNT 512 +#define ATL2_DEFAULT_RXD_COUNT 64 +ATL2_PARAM(RxMemBlock, "Number of receive memory block"); + +/* User Specified MediaType Override + * + * Valid Range: 0-5 + * - 0 - auto-negotiate at all supported speeds + * - 1 - only link at 1000Mbps Full Duplex + * - 2 - only link at 100Mbps Full Duplex + * - 3 - only link at 100Mbps Half Duplex + * - 4 - only link at 10Mbps Full Duplex + * - 5 - only link at 10Mbps Half Duplex + * Default Value: 0 + */ +ATL2_PARAM(MediaType, "MediaType Select"); + +/* Interrupt Moderate Timer in units of 2 us + * + * Valid Range: 10-65535 + * + * Default Value: 45000(90ms) + */ +#define INT_MOD_DEFAULT_CNT 100 // 200us +#define INT_MOD_MAX_CNT 65000 +#define INT_MOD_MIN_CNT 50 +ATL2_PARAM(IntModTimer, "Interrupt Moderator Timer"); + +/* FlashVendor + * Valid Range: 0-2 + * 0 - Atmel + * 1 - SST + * 2 - ST + */ +ATL2_PARAM(FlashVendor, "SPI Flash Vendor"); + +#define AUTONEG_ADV_DEFAULT 0x2F +#define AUTONEG_ADV_MASK 0x2F +#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL + +#define FLASH_VENDOR_DEFAULT 0 +#define FLASH_VENDOR_MIN 0 +#define FLASH_VENDOR_MAX 2 + +struct atl2_option { + enum { enable_option, range_option, list_option } type; + char *name; + char *err; + int def; + union { + struct { /* range_option info */ + int min; + int max; + } r; + struct { /* list_option info */ + int nr; + struct atl2_opt_list { int i; char *str; } *p; + } l; + } arg; +}; + +static int __devinit +atl2_validate_option(int *value, struct atl2_option *opt) +{ + int i; + struct atl2_opt_list *ent; + + if(*value == OPTION_UNSET) { + *value = opt->def; + return 0; + } + + switch (opt->type) { + case enable_option: + switch (*value) { + case OPTION_ENABLED: + printk(KERN_INFO "%s Enabled\n", opt->name); + return 0; + break; + case OPTION_DISABLED: + printk(KERN_INFO "%s Disabled\n", opt->name); + return 0; + break; + } + break; + case range_option: + if(*value >= opt->arg.r.min && *value <= opt->arg.r.max) { + printk(KERN_INFO "%s set to %i\n", opt->name, *value); + return 0; + } + break; + case list_option: + for(i = 0; i < opt->arg.l.nr; i++) { + ent = &opt->arg.l.p[i]; + if(*value == ent->i) { + if(ent->str[0] != '\0') + printk(KERN_INFO "%s\n", ent->str); + return 0; + } + } + break; + default: + BUG(); + } + + printk(KERN_INFO "Invalid %s specified (%i) %s\n", + opt->name, *value, opt->err); + *value = opt->def; + return -1; +} + +/** + * atl2_check_options - Range Checking for Command Line Parameters + * @adapter: board private structure + * + * This routine checks all command line parameters for valid user + * input. If an invalid value is given, or if no user specified + * value exists, a default value is used. The final value is stored + * in a variable in the adapter structure. + **/ +void __devinit +atl2_check_options(struct atl2_adapter *adapter) +{ + int val; + struct atl2_option opt; + int bd = adapter->bd_number; + if(bd >= ATL2_MAX_NIC) { + printk(KERN_NOTICE "Warning: no configuration for board #%i\n", bd); + printk(KERN_NOTICE "Using defaults for all values\n"); +#ifndef module_param_array + bd = ATL2_MAX_NIC; +#endif + } + + /* Bytes of Transmit Memory */ + opt.type = range_option; + opt.name = "Bytes of Transmit Memory"; + opt.err = "using default of " __MODULE_STRING(ATL2_DEFAULT_TX_MEMSIZE); + opt.def = ATL2_DEFAULT_TX_MEMSIZE; + opt.arg.r.min = ATL2_MIN_TX_MEMSIZE; + opt.arg.r.max = ATL2_MAX_TX_MEMSIZE; +#ifdef module_param_array + if(num_TxMemSize > bd) { +#endif + val = TxMemSize[bd]; + atl2_validate_option(&val, &opt); + adapter->txd_ring_size = ((u32) val) * 1024; +#ifdef module_param_array + } else { + adapter->txd_ring_size = ((u32)opt.def) * 1024; + } +#endif + // txs ring size: + adapter->txs_ring_size = adapter->txd_ring_size / 128; + if (adapter->txs_ring_size > 160) + adapter->txs_ring_size = 160; + + /* Receive Memory Block Count */ + opt.type = range_option; + opt.name = "Number of receive memory block"; + opt.err = "using default of " __MODULE_STRING(ATL2_DEFAULT_RXD_COUNT); + opt.def = ATL2_DEFAULT_RXD_COUNT; + opt.arg.r.min = ATL2_MIN_RXD_COUNT; + opt.arg.r.max = ATL2_MAX_RXD_COUNT; +#ifdef module_param_array + if(num_RxMemBlock > bd) { +#endif + val = RxMemBlock[bd]; + atl2_validate_option(&val, &opt); + adapter->rxd_ring_size = (u32)val; //((u16)val)&~1; // even number +#ifdef module_param_array + } else { + adapter->rxd_ring_size = (u32)opt.def; + } +#endif + // init RXD Flow control value + adapter->hw.fc_rxd_hi = (adapter->rxd_ring_size/8)*7; + adapter->hw.fc_rxd_lo = (ATL2_MIN_RXD_COUNT/8) > (adapter->rxd_ring_size/12) ? + (ATL2_MIN_RXD_COUNT/8) : (adapter->rxd_ring_size/12); + + /* Interrupt Moderate Timer */ + opt.type = range_option; + opt.name = "Interrupt Moderate Timer"; + opt.err = "using default of " __MODULE_STRING(INT_MOD_DEFAULT_CNT); + opt.def = INT_MOD_DEFAULT_CNT; + opt.arg.r.min = INT_MOD_MIN_CNT; + opt.arg.r.max = INT_MOD_MAX_CNT; +#ifdef module_param_array + if(num_IntModTimer > bd) { +#endif + val = IntModTimer[bd]; + atl2_validate_option(&val, &opt); + adapter->imt = (u16) val; +#ifdef module_param_array + } else { + adapter->imt = (u16)(opt.def); + } +#endif + /* Flash Vendor */ + opt.type = range_option; + opt.name = "SPI Flash Vendor"; + opt.err = "using default of " __MODULE_STRING(FLASH_VENDOR_DEFAULT); + opt.def = FLASH_VENDOR_DEFAULT; + opt.arg.r.min = FLASH_VENDOR_MIN; + opt.arg.r.max = FLASH_VENDOR_MAX; +#ifdef module_param_array + if(num_FlashVendor > bd) { +#endif + val = FlashVendor[bd]; + atl2_validate_option(&val, &opt); + adapter->hw.flash_vendor = (u8) val; +#ifdef module_param_array + } else { + adapter->hw.flash_vendor = (u8)(opt.def); + } +#endif + /* MediaType */ + opt.type = range_option; + opt.name = "Speed/Duplex Selection"; + opt.err = "using default of " __MODULE_STRING(MEDIA_TYPE_AUTO_SENSOR); + opt.def = MEDIA_TYPE_AUTO_SENSOR; + opt.arg.r.min = MEDIA_TYPE_AUTO_SENSOR; + opt.arg.r.max = MEDIA_TYPE_10M_HALF; +#ifdef module_param_array + if(num_MediaType > bd) { +#endif + val = MediaType[bd]; + atl2_validate_option(&val, &opt); + adapter->hw.MediaType = (u16) val; +#ifdef module_param_array + } else { + adapter->hw.MediaType = (u16)(opt.def); + } +#endif +} --- linux-2.6.27.orig/ubuntu/atl2/atl2_main.c +++ linux-2.6.27/ubuntu/atl2/atl2_main.c @@ -0,0 +1,1853 @@ +/* atl2_main.c -- atl2 driver main functions + * + * Copyright(c) 2007 Atheros Corporation. All rights reserved. + * Copyright(c) 2006 xiong huang + * Copyright(c) 2007 Chris Snook + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "atl2.h" + +#define ATL2_DRV_VERSION "2.0.4" + +char atl2_driver_name[] = "atl2"; +static const char atl2_driver_string[] = "Atheros(R) L2 Ethernet Driver"; +static char atl2_copyright[] = "Copyright (c) 2007 Atheros Corporation."; +char atl2_driver_version[] = ATL2_DRV_VERSION; + +MODULE_AUTHOR("Atheros Corporation , Chris Snook "); +MODULE_DESCRIPTION("Atheros Fast Ethernet Network Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(ATL2_DRV_VERSION); + +/* FIXME: remove this after merging, goes in pci_ids.h */ +#ifndef PCI_DEVICE_ID_ATTANSIC_L2 +#define PCI_DEVICE_ID_ATTANSIC_L2 0x2048 +#endif + +/* + * atl2_pci_tbl - PCI Device ID Table + */ +static struct pci_device_id atl2_pci_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2)}, + /* required last entry */ + {0,} +}; +MODULE_DEVICE_TABLE(pci, atl2_pci_tbl); + +extern void atl2_set_ethtool_ops(struct net_device *netdev); +#ifdef ETHTOOL_OPS_COMPAT +extern int ethtool_ioctl(struct ifreq *ifr); +#endif + +#define COPYBREAK_DEFAULT 256 +static unsigned int copybreak __read_mostly = COPYBREAK_DEFAULT; +module_param(copybreak, uint, 0644); +MODULE_PARM_DESC(copybreak, "Maximum size of packet that is copied to a new buffer on receive"); + +extern void atl2_check_options(struct atl2_adapter *adapter); +#ifdef SIOCDEVPRIVATE +extern int atl2_priv_ioctl(struct net_device* netdev, struct ifreq* ifr); +#endif + +/** + * atl2_sw_init - Initialize general software structures (struct atl2_adapter) + * @adapter: board private structure to initialize + * + * atl2_sw_init initializes the Adapter private data structure. + * Fields are initialized based on PCI device information and + * OS network device settings (MTU size). + **/ +static int __devinit +atl2_sw_init(struct atl2_adapter *adapter) +{ + struct atl2_hw *hw = &adapter->hw; + struct pci_dev *pdev = adapter->pdev; + + /* PCI config space info */ + hw->vendor_id = pdev->vendor; + hw->device_id = pdev->device; + hw->subsystem_vendor_id = pdev->subsystem_vendor; + hw->subsystem_id = pdev->subsystem_device; + + pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); + pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word); + + adapter->wol = 0; + adapter->ict = 50000; // 100ms + adapter->link_speed = SPEED_0; // hardware init + adapter->link_duplex = FULL_DUPLEX; + + hw->phy_configured = false; + hw->preamble_len = 7; + hw->ipgt = 0x60; + hw->min_ifg = 0x50; + hw->ipgr1 = 0x40; + hw->ipgr2 = 0x60; + hw->retry_buf = 2; + hw->max_retry = 0xf; + hw->lcol = 0x37; + hw->jam_ipg = 7; + hw->fc_rxd_hi = 0; + hw->fc_rxd_lo = 0; + hw->max_frame_size = adapter->netdev->mtu; + + spin_lock_init(&adapter->stats_lock); + spin_lock_init(&adapter->tx_lock); + + set_bit(__ATL2_DOWN, &adapter->flags); + + return 0; +} + +/** + * atl2_set_multi - Multicast and Promiscuous mode set + * @netdev: network interface device structure + * + * The set_multi entry point is called whenever the multicast address + * list or the network interface flags are updated. This routine is + * responsible for configuring the hardware for proper multicast, + * promiscuous mode, and all-multi behavior. + **/ +static void +atl2_set_multi(struct net_device *netdev) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct atl2_hw *hw = &adapter->hw; + struct dev_mc_list *mc_ptr; + u32 rctl; + u32 hash_value; + + /* Check for Promiscuous and All Multicast modes */ + rctl = ATL2_READ_REG(hw, REG_MAC_CTRL); + + if(netdev->flags & IFF_PROMISC) { + rctl |= MAC_CTRL_PROMIS_EN; + } else if(netdev->flags & IFF_ALLMULTI) { + rctl |= MAC_CTRL_MC_ALL_EN; + rctl &= ~MAC_CTRL_PROMIS_EN; + } else { + rctl &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN); + } + + ATL2_WRITE_REG(hw, REG_MAC_CTRL, rctl); + + /* clear the old settings from the multicast hash table */ + ATL2_WRITE_REG(hw, REG_RX_HASH_TABLE, 0); + ATL2_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0); + + /* comoute mc addresses' hash value ,and put it into hash table */ + for(mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { + hash_value = atl2_hash_mc_addr(hw, mc_ptr->dmi_addr); + atl2_hash_set(hw, hash_value); + } +} + +static void +init_ring_ptrs(struct atl2_adapter *adapter) +{ + // Read / Write Ptr Initialize: + adapter->txd_write_ptr = 0; + atomic_set(&adapter->txd_read_ptr, 0); + + adapter->rxd_read_ptr = 0; + adapter->rxd_write_ptr = 0; + + atomic_set(&adapter->txs_write_ptr, 0); + adapter->txs_next_clear = 0; +} + +/** + * atl2_configure - Configure Transmit&Receive Unit after Reset + * @adapter: board private structure + * + * Configure the Tx /Rx unit of the MAC after a reset. + **/ +static int +atl2_configure(struct atl2_adapter *adapter) +{ + struct atl2_hw * hw = &adapter->hw; + u32 value; + + // clear interrupt status + ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0xffffffff); + + // set MAC Address + value = (((u32)hw->mac_addr[2]) << 24) | + (((u32)hw->mac_addr[3]) << 16) | + (((u32)hw->mac_addr[4]) << 8 ) | + (((u32)hw->mac_addr[5]) ) ; + ATL2_WRITE_REG(hw, REG_MAC_STA_ADDR, value); + value = (((u32)hw->mac_addr[0]) << 8 ) | + (((u32)hw->mac_addr[1]) ) ; + ATL2_WRITE_REG(hw, (REG_MAC_STA_ADDR+4), value); + + // HI base address + ATL2_WRITE_REG(hw, REG_DESC_BASE_ADDR_HI, + (u32)((adapter->ring_dma & 0xffffffff00000000ULL) >> 32)); + + // LO base address + ATL2_WRITE_REG(hw, REG_TXD_BASE_ADDR_LO, + (u32)(adapter->txd_dma & 0x00000000ffffffffULL)); + ATL2_WRITE_REG(hw, REG_TXS_BASE_ADDR_LO, + (u32)(adapter->txs_dma & 0x00000000ffffffffULL)); + ATL2_WRITE_REG(hw, REG_RXD_BASE_ADDR_LO, + (u32)(adapter->rxd_dma & 0x00000000ffffffffULL)); + + // element count + ATL2_WRITE_REGW(hw, REG_TXD_MEM_SIZE, (u16)(adapter->txd_ring_size/4)); + ATL2_WRITE_REGW(hw, REG_TXS_MEM_SIZE, (u16)adapter->txs_ring_size); + ATL2_WRITE_REGW(hw, REG_RXD_BUF_NUM, (u16)adapter->rxd_ring_size); + + /* config Internal SRAM */ +/* + ATL2_WRITE_REGW(hw, REG_SRAM_TXRAM_END, sram_tx_end); + ATL2_WRITE_REGW(hw, REG_SRAM_TXRAM_END, sram_rx_end); +*/ + + /* config IPG/IFG */ + value = (((u32)hw->ipgt & MAC_IPG_IFG_IPGT_MASK) << MAC_IPG_IFG_IPGT_SHIFT) | + (((u32)hw->min_ifg & MAC_IPG_IFG_MIFG_MASK) << MAC_IPG_IFG_MIFG_SHIFT) | + (((u32)hw->ipgr1 & MAC_IPG_IFG_IPGR1_MASK) << MAC_IPG_IFG_IPGR1_SHIFT)| + (((u32)hw->ipgr2 & MAC_IPG_IFG_IPGR2_MASK) << MAC_IPG_IFG_IPGR2_SHIFT); + ATL2_WRITE_REG(hw, REG_MAC_IPG_IFG, value); + + /* config Half-Duplex Control */ + value = ((u32)hw->lcol & MAC_HALF_DUPLX_CTRL_LCOL_MASK) | + (((u32)hw->max_retry & MAC_HALF_DUPLX_CTRL_RETRY_MASK) << + MAC_HALF_DUPLX_CTRL_RETRY_SHIFT) | + MAC_HALF_DUPLX_CTRL_EXC_DEF_EN | + (0xa << MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT) | + (((u32)hw->jam_ipg & MAC_HALF_DUPLX_CTRL_JAMIPG_MASK) << + MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT); + ATL2_WRITE_REG(hw, REG_MAC_HALF_DUPLX_CTRL, value); + + /* set Interrupt Moderator Timer */ + ATL2_WRITE_REGW(hw, REG_IRQ_MODU_TIMER_INIT, adapter->imt); + ATL2_WRITE_REG(hw, REG_MASTER_CTRL, MASTER_CTRL_ITIMER_EN); + + /* set Interrupt Clear Timer */ + ATL2_WRITE_REGW(hw, REG_CMBDISDMA_TIMER, adapter->ict); + + /* set MTU */ + ATL2_WRITE_REG(hw, REG_MTU, adapter->netdev->mtu + + ENET_HEADER_SIZE + VLAN_SIZE + ETHERNET_FCS_SIZE); + + /* 1590 */ + ATL2_WRITE_REG(hw, REG_TX_CUT_THRESH, 0x177); + + /* flow control */ + ATL2_WRITE_REGW(hw, REG_PAUSE_ON_TH, hw->fc_rxd_hi); + ATL2_WRITE_REGW(hw, REG_PAUSE_OFF_TH, hw->fc_rxd_lo); + + /* Init mailbox */ + ATL2_WRITE_REGW(hw, REG_MB_TXD_WR_IDX, (u16)adapter->txd_write_ptr); + ATL2_WRITE_REGW(hw, REG_MB_RXD_RD_IDX, (u16)adapter->rxd_read_ptr); + + /* enable DMA read/write */ + ATL2_WRITE_REGB(hw, REG_DMAR, DMAR_EN); + ATL2_WRITE_REGB(hw, REG_DMAW, DMAW_EN); + + value = ATL2_READ_REG(&adapter->hw, REG_ISR); + if ((value & ISR_PHY_LINKDOWN) != 0) { + value = 1; // config failed + } else { + value = 0; + } + + // clear all interrupt status + ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0x3fffffff); + ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0); + return value; +} + +/** + * atl2_setup_ring_resources - allocate Tx / RX descriptor resources + * @adapter: board private structure + * + * Return 0 on success, negative on failure + **/ +static s32 +atl2_setup_ring_resources(struct atl2_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + int size; + u8 offset = 0; + + /* real ring DMA buffer */ + adapter->ring_size = size = + adapter->txd_ring_size * 1 + 7 + // dword align + adapter->txs_ring_size * 4 + 7 + // dword align + adapter->rxd_ring_size * 1536 + 127; // 128bytes align + + adapter->ring_vir_addr = pci_alloc_consistent(pdev, size, &adapter->ring_dma); + if (!adapter->ring_vir_addr) { + return -ENOMEM; + } +#if 0 + if (adapter->pci_using_64) { + // test whether HIDWORD dma buffer is not cross boundary + if ( ((adapter->ring_dma &0xffffffff00000000ULL)>>32) + != (((adapter->ring_dma+size)&0xffffffff00000000ULL)>>32) ) { + pci_free_consistent(pdev, adapter->ring_size, adapter->ring_vir_addr, adapter->ring_dma); + DEBUGOUT("memory allocated cross 32bit boundary !"); + return -ENOMEM; + } + } +#endif + memset(adapter->ring_vir_addr, 0, adapter->ring_size); + + // Init TXD Ring + adapter->txd_dma = adapter->ring_dma ; + offset = (adapter->txd_dma & 0x7) ? (8 - (adapter->txd_dma & 0x7)) : 0; + adapter->txd_dma += offset; + adapter->txd_ring = (tx_pkt_header_t*) (adapter->ring_vir_addr + offset); + + // Init TXS Ring + adapter->txs_dma = adapter->txd_dma + adapter->txd_ring_size; + offset = (adapter->txs_dma & 0x7) ? (8- (adapter->txs_dma & 0x7)) : 0; + adapter->txs_dma += offset; + adapter->txs_ring = (tx_pkt_status_t*) + (((u8*)adapter->txd_ring) + (adapter->txd_ring_size+offset)); + + // Init RXD Ring + adapter->rxd_dma = adapter->txs_dma + adapter->txs_ring_size*4; + offset = (adapter->rxd_dma & 127) ? (128 - (adapter->rxd_dma & 127)) : 0; + if (offset > 7) { + offset -= 8; + } else { + offset += (128 - 8); + } + adapter->rxd_dma += offset; + adapter->rxd_ring = (rx_desc_t*) (((u8*)adapter->txs_ring) + + (adapter->txs_ring_size*4 + offset)); + +// Read / Write Ptr Initialize: +// init_ring_ptrs(adapter); + + return ATL2_SUCCESS; +} + +/** + * atl2_irq_enable - Enable default interrupt generation settings + * @adapter: board private structure + **/ +static inline void +atl2_irq_enable(struct atl2_adapter *adapter) +{ + ATL2_WRITE_REG(&adapter->hw, REG_IMR, IMR_NORMAL_MASK); + ATL2_WRITE_FLUSH(&adapter->hw); +} + +/** + * atl2_irq_disable - Mask off interrupt generation on the NIC + * @adapter: board private structure + **/ +static inline void +atl2_irq_disable(struct atl2_adapter *adapter) +{ + ATL2_WRITE_REG(&adapter->hw, REG_IMR, 0); + ATL2_WRITE_FLUSH(&adapter->hw); + synchronize_irq(adapter->pdev->irq); +} + +#ifdef NETIF_F_HW_VLAN_TX +static void +atl2_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + u32 ctrl; + + atl2_irq_disable(adapter); + adapter->vlgrp = grp; + + if(grp) { + /* enable VLAN tag insert/strip */ + ctrl = ATL2_READ_REG(&adapter->hw, REG_MAC_CTRL); + ctrl |= MAC_CTRL_RMV_VLAN; + ATL2_WRITE_REG(&adapter->hw, REG_MAC_CTRL, ctrl); + } else { + /* disable VLAN tag insert/strip */ + ctrl = ATL2_READ_REG(&adapter->hw, REG_MAC_CTRL); + ctrl &= ~MAC_CTRL_RMV_VLAN; + ATL2_WRITE_REG(&adapter->hw, REG_MAC_CTRL, ctrl); + } + + atl2_irq_enable(adapter); +} + +static void +atl2_restore_vlan(struct atl2_adapter *adapter) +{ + atl2_vlan_rx_register(adapter->netdev, adapter->vlgrp); +} +#endif + +static void +atl2_intr_rx(struct atl2_adapter* adapter) +{ + struct net_device *netdev = adapter->netdev; + rx_desc_t* rxd; + struct sk_buff* skb; + + do { + rxd = adapter->rxd_ring+adapter->rxd_write_ptr; + if (!rxd->status.update) + break; // end of tx + + // clear this flag at once + rxd->status.update = 0; + + if (rxd->status.ok && rxd->status.pkt_size >= 60) { + int rx_size = (int)(rxd->status.pkt_size - 4); + // alloc new buffer + skb = netdev_alloc_skb(netdev, rx_size + NET_IP_ALIGN); + if (NULL == skb) { + printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n", + netdev->name); + /* We should check that some rx space is free. + * If not, free one and mark stats->rx_dropped++. */ + adapter->net_stats.rx_dropped++; + break; + } +/* FIXME: ??? + if (rx_size > 1400) { + int s,c; + c = 0; + printk("rx_size= %d\n", rx_size); + for (s=0; s < 800; s++) { + if (0 == c) { + printk("%04x ", s); + } + printk("%02x ", rxd->packet[s]); + if (++c == 16) { + c = 0; + printk("\n"); + } + } + printk(KERN_WARNING"\n"); + } +*/ + skb_reserve(skb, NET_IP_ALIGN); + skb->dev = netdev; +/* gone in 2.6.23, just use memcpy? -- CHS + eth_copy_and_sum(skb, rxd->packet, rx_size, 0); */ + memcpy(skb->data, rxd->packet, rx_size); /* totally untested -- CHS */ + skb_put(skb, rx_size); + /* FIXME ??? + memcpy(skb_put(skb, rx_size), + rxd->packet, + rx_size); + */ + skb->protocol = eth_type_trans(skb, netdev); +#ifdef NETIF_F_HW_VLAN_TX + if(adapter->vlgrp && (rxd->status.vlan)) { + u16 vlan_tag = (rxd->status.vtag>>4) | + ((rxd->status.vtag&7) << 13) | + ((rxd->status.vtag&8) << 9); + vlan_hwaccel_rx(skb, adapter->vlgrp, vlan_tag); + } else +#endif + netif_rx(skb); + adapter->net_stats.rx_bytes += rx_size; + adapter->net_stats.rx_packets++; + netdev->last_rx = jiffies; + } else { + adapter->net_stats.rx_errors++; + + if (rxd->status.ok && rxd->status.pkt_size <= 60) { + adapter->net_stats.rx_length_errors++; + } + if (rxd->status.mcast) adapter->net_stats.multicast++; + if (rxd->status.crc) adapter->net_stats.rx_crc_errors++; + if (rxd->status.align) adapter->net_stats.rx_frame_errors++; + } + + // advance write ptr + if (++adapter->rxd_write_ptr == adapter->rxd_ring_size) + adapter->rxd_write_ptr = 0; + } while (1); + + // update mailbox ? + adapter->rxd_read_ptr = adapter->rxd_write_ptr; + ATL2_WRITE_REGW(&adapter->hw, REG_MB_RXD_RD_IDX, adapter->rxd_read_ptr); +} + +static void +atl2_intr_tx(struct atl2_adapter* adapter) +{ + u32 txd_read_ptr; + u32 txs_write_ptr; + tx_pkt_status_t* txs; + tx_pkt_header_t* txph; + int free_hole = 0; + + do { + txs_write_ptr = (u32) atomic_read(&adapter->txs_write_ptr); + txs = adapter->txs_ring + txs_write_ptr; + if (!txs->update) + break; // tx stop here + + free_hole = 1; + txs->update = 0; + + if (++txs_write_ptr == adapter->txs_ring_size) + txs_write_ptr = 0; + atomic_set(&adapter->txs_write_ptr, (int)txs_write_ptr); + + txd_read_ptr = (u32) atomic_read(&adapter->txd_read_ptr); + txph = (tx_pkt_header_t*) (((u8*)adapter->txd_ring) + txd_read_ptr); + + if ( txph->pkt_size != txs->pkt_size) { + tx_pkt_status_t* old_txs = txs; + printk(KERN_WARNING + "%s: txs packet size do not coinsist with txd" + " txd_:0x%08x, txs_:0x%08x!\n", + adapter->netdev->name, + *(u32*)txph, *(u32*)txs); + printk(KERN_WARNING + "txd read ptr: 0x%x\n", + txd_read_ptr); + txs = adapter->txs_ring + txs_write_ptr; + printk(KERN_WARNING + "txs-behind:0x%08x\n", + *(u32*)txs); + if (txs_write_ptr < 2) { + txs = adapter->txs_ring + + (adapter->txs_ring_size + + txs_write_ptr - 2); + } else { + txs = adapter->txs_ring + (txs_write_ptr - 2); + } + printk(KERN_WARNING + "txs-before:0x%08x\n", + *(u32*)txs); + txs = old_txs; + } + + txd_read_ptr += (((u32)(txph->pkt_size)+7)& ~3);//4for TPH + if (txd_read_ptr >= adapter->txd_ring_size) + txd_read_ptr -= adapter->txd_ring_size; + + atomic_set(&adapter->txd_read_ptr, (int)txd_read_ptr); + + // tx statistics: + if (txs->ok) { + adapter->net_stats.tx_bytes += txs->pkt_size; + adapter->net_stats.tx_packets++; + } + else + adapter->net_stats.tx_errors++; + + if (txs->defer) adapter->net_stats.collisions++; + if (txs->abort_col) adapter->net_stats.tx_aborted_errors++; + if (txs->late_col) adapter->net_stats.tx_window_errors++; + if (txs->underun) adapter->net_stats.tx_fifo_errors++; + } while (1); + + if (free_hole) { + if(netif_queue_stopped(adapter->netdev) && + netif_carrier_ok(adapter->netdev)) + netif_wake_queue(adapter->netdev); + } +} + +static void +atl2_check_for_link(struct atl2_adapter* adapter) +{ + struct net_device *netdev = adapter->netdev; + u16 phy_data = 0; + + spin_lock(&adapter->stats_lock); + atl2_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); + atl2_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); + spin_unlock(&adapter->stats_lock); + + // notify upper layer link down ASAP + if (!(phy_data & BMSR_LSTATUS)) { // Link Down + if (netif_carrier_ok(netdev)) { // old link state: Up + printk(KERN_INFO "%s: %s NIC Link is Down\n", + atl2_driver_name, netdev->name); + adapter->link_speed = SPEED_0; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + } + schedule_work(&adapter->link_chg_task); +} + +static inline void +atl2_clear_phy_int(struct atl2_adapter *adapter) +{ + u16 phy_data; + spin_lock(&adapter->stats_lock); + atl2_read_phy_reg(&adapter->hw, 19, &phy_data); + spin_unlock(&adapter->stats_lock); +} + +/** + * atl2_intr - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + * @pt_regs: CPU registers structure + **/ +static irqreturn_t +atl2_intr(int irq, void *data) +{ + struct atl2_adapter *adapter = netdev_priv(data); + struct atl2_hw *hw = &adapter->hw; + u32 status; + + status = ATL2_READ_REG(hw, REG_ISR); + if (0 == status) + return IRQ_NONE; + + // link event + if (status & ISR_PHY) { + atl2_clear_phy_int(adapter); + } + + // clear ISR status, and Enable CMB DMA/Disable Interrupt + ATL2_WRITE_REG(hw, REG_ISR, status | ISR_DIS_INT); + + // FIXME: if PCIe link is down, how did we read the register? -- CHS + // check if PCIE PHY Link down + if (status & ISR_PHY_LINKDOWN) { + if(netif_running(adapter->netdev)) { // reset MAC + ATL2_WRITE_REG(hw, REG_ISR, 0); + ATL2_WRITE_REG(hw, REG_IMR, 0); + ATL2_WRITE_FLUSH(hw); + schedule_work(&adapter->reset_task); + return IRQ_HANDLED; + } + } + + // check if DMA read/write error ? + if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) + { + //ATL2_WRITE_REG(&adapter->hw, REG_MASTER_CTRL, MASTER_CTRL_SOFT_RST); + ATL2_WRITE_REG(hw, REG_ISR, 0); + ATL2_WRITE_REG(hw, REG_IMR, 0); + ATL2_WRITE_FLUSH(hw); + schedule_work(&adapter->reset_task); + return IRQ_HANDLED; + } + + // link event + if (status & (ISR_PHY | ISR_MANUAL)) + { + adapter->net_stats.tx_carrier_errors++; + atl2_check_for_link(adapter); + } + + // transmit event + if (status & ISR_TX_EVENT) { + atl2_intr_tx(adapter); + } + + // rx exception + if (status & ISR_RX_EVENT) { + atl2_intr_rx(adapter); + } + + // re-enable Interrupt + ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0); + return IRQ_HANDLED; +} + +static int +atl2_request_irq(struct atl2_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int flags, err = 0; + + flags = IRQF_SHARED; +#ifdef CONFIG_PCI_MSI + adapter->have_msi = true; + if ((err = pci_enable_msi(adapter->pdev))) + adapter->have_msi = false; + + if (adapter->have_msi) + flags &= ~IRQF_SHARED; +#endif + + return request_irq(adapter->pdev->irq, &atl2_intr, flags, netdev->name, netdev); +} + +/** + * atl2_free_ring_resources - Free Tx / RX descriptor Resources + * @adapter: board private structure + * + * Free all transmit software resources + **/ +static void +atl2_free_ring_resources(struct atl2_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + pci_free_consistent(pdev, adapter->ring_size, adapter->ring_vir_addr, adapter->ring_dma); +} + +/** + * atl2_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + **/ +static int +atl2_open(struct net_device *netdev) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + int err; + u32 val; + + /* disallow open during test */ + if (test_bit(__ATL2_TESTING, &adapter->flags)) + return -EBUSY; + + /* allocate transmit descriptors */ + if((err = atl2_setup_ring_resources(adapter))) + return err; + + if((err = atl2_init_hw(&adapter->hw))) { + err = -EIO; + goto err_init_hw; + } + + /* hardware has been reset, we need to reload some things */ + atl2_set_multi(netdev); + init_ring_ptrs(adapter); + +#ifdef NETIF_F_HW_VLAN_TX + atl2_restore_vlan(adapter); +#endif + + if (atl2_configure(adapter)) { + err = -EIO; + goto err_config; + } + + if ((err = atl2_request_irq(adapter))) + goto err_req_irq; + + clear_bit(__ATL2_DOWN, &adapter->flags); + + mod_timer(&adapter->watchdog_timer, jiffies + 4*HZ); + + val = ATL2_READ_REG(&adapter->hw, REG_MASTER_CTRL); + ATL2_WRITE_REG(&adapter->hw, REG_MASTER_CTRL, val | MASTER_CTRL_MANUAL_INT); + + atl2_irq_enable(adapter); + + return 0; + +err_init_hw: +err_req_irq: +err_config: + atl2_free_ring_resources(adapter); + atl2_reset_hw(&adapter->hw); + + return err; +} + +void +atl2_down(struct atl2_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + /* signal that we're down so the interrupt handler does not + * reschedule our watchdog timer */ + set_bit(__ATL2_DOWN, &adapter->flags); + +#ifdef NETIF_F_LLTX + netif_stop_queue(netdev); +#else + netif_tx_disable(netdev); +#endif + + /* reset MAC to disable all RX/TX */ + atl2_reset_hw(&adapter->hw); + msleep(1); + + atl2_irq_disable(adapter); + + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_config_timer); + clear_bit(0, &adapter->cfg_phy); + + netif_carrier_off(netdev); + adapter->link_speed = SPEED_0; + adapter->link_duplex = -1; + +// atl2_reset(adapter); +} + +static void +atl2_free_irq(struct atl2_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + free_irq(adapter->pdev->irq, netdev); + +#ifdef CONFIG_PCI_MSI + if (adapter->have_msi) + pci_disable_msi(adapter->pdev); +#endif +} + +/** + * atl2_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the drivers control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + **/ +static int +atl2_close(struct net_device *netdev) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + + WARN_ON(test_bit(__ATL2_RESETTING, &adapter->flags)); + + atl2_down(adapter); + atl2_free_irq(adapter); + atl2_free_ring_resources(adapter); + + return 0; +} + +static inline int +TxsFreeUnit(struct atl2_adapter *adapter) +{ + u32 txs_write_ptr = (u32) atomic_read(&adapter->txs_write_ptr); + + return (adapter->txs_next_clear >= txs_write_ptr) ? + (int) (adapter->txs_ring_size - adapter->txs_next_clear + + txs_write_ptr - 1) : + (int) (txs_write_ptr - adapter->txs_next_clear - 1); +} + +static inline int +TxdFreeBytes(struct atl2_adapter *adapter) +{ + u32 txd_read_ptr = (u32)atomic_read(&adapter->txd_read_ptr); + + return (adapter->txd_write_ptr >= txd_read_ptr) ? + (int) (adapter->txd_ring_size - adapter->txd_write_ptr + + txd_read_ptr - 1): + (int) (txd_read_ptr - adapter->txd_write_ptr - 1); +} + +static int +atl2_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + tx_pkt_header_t* txph; + u32 offset, copy_len; + int txs_unused; + int txbuf_unused; + + if (test_bit(__ATL2_DOWN, &adapter->flags)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + if (unlikely(skb->len <= 0)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + +#ifdef NETIF_F_LLTX + local_irq_save(flags); + if (!spin_trylock(&adapter->tx_lock)) { + /* Collision - tell upper layer to requeue */ + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } +#else + spin_lock_irqsave(&adapter->tx_lock, flags); +#endif + txs_unused = TxsFreeUnit(adapter); + txbuf_unused = TxdFreeBytes(adapter); + + if (txs_unused < 1 || skb->len > txbuf_unused) { + // no enough resource + netif_stop_queue(netdev); + spin_unlock_irqrestore(&adapter->tx_lock, flags); + return NETDEV_TX_BUSY; + } + + offset = adapter->txd_write_ptr; + + txph = (tx_pkt_header_t*) (((u8*)adapter->txd_ring)+offset); + + *(u32*)txph = 0; + txph->pkt_size = skb->len; + + offset += 4; + if (offset >= adapter->txd_ring_size) + offset -= adapter->txd_ring_size; + copy_len = adapter->txd_ring_size - offset; + if (copy_len >= skb->len) { + memcpy(((u8*)adapter->txd_ring)+offset, skb->data, skb->len); + offset += ((u32)(skb->len+3)&~3); + } else { + memcpy(((u8*)adapter->txd_ring)+offset, skb->data, copy_len); + memcpy((u8*)adapter->txd_ring, skb->data+copy_len, skb->len-copy_len); + offset = ((u32)(skb->len-copy_len+3)&~3); + } +#ifdef NETIF_F_HW_VLAN_TX + if (adapter->vlgrp && vlan_tx_tag_present(skb)) { + u16 vlan_tag = vlan_tx_tag_get(skb); + vlan_tag = (vlan_tag << 4) | + (vlan_tag >> 13) | + ((vlan_tag >>9) & 0x8); + txph->ins_vlan = 1; + txph->vlan = vlan_tag; + } +#endif + if (offset >= adapter->txd_ring_size) + offset -= adapter->txd_ring_size; + adapter->txd_write_ptr = offset; + + // clear txs before send + adapter->txs_ring[adapter->txs_next_clear].update = 0; + if (++adapter->txs_next_clear == adapter->txs_ring_size) + adapter->txs_next_clear = 0; + + ATL2_WRITE_REGW(&adapter->hw, REG_MB_TXD_WR_IDX, (adapter->txd_write_ptr >> 2)); + + spin_unlock_irqrestore(&adapter->tx_lock, flags); + + netdev->trans_start = jiffies; + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} + +/** + * atl2_get_stats - Get System Network Statistics + * @netdev: network interface device structure + * + * Returns the address of the device statistics structure. + * The statistics are actually updated from the timer callback. + **/ +static struct net_device_stats * +atl2_get_stats(struct net_device *netdev) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + + return &adapter->net_stats; +} + +/** + * atl2_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + **/ +static int +atl2_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct atl2_hw *hw = &adapter->hw; + + if ((new_mtu < 40) || (new_mtu > (ETH_DATA_LEN + VLAN_SIZE))) + return -EINVAL; + + /* set MTU */ + if (hw->max_frame_size != new_mtu) { +// while (test_and_set_bit(__ATL2_RESETTING, &adapter->flags)) +// msleep(1); + netdev->mtu = new_mtu; + + ATL2_WRITE_REG(hw, REG_MTU, + new_mtu + ENET_HEADER_SIZE + VLAN_SIZE + ETHERNET_FCS_SIZE); +// clear_bit(__ATL2_RESETTING, &adapter->flags); + } + + return 0; +} + +/** + * atl2_set_mac - Change the Ethernet Address of the NIC + * @netdev: network interface device structure + * @p: pointer to an address structure + * + * Returns 0 on success, negative on failure + **/ +static int +atl2_set_mac(struct net_device *netdev, void *p) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + if (netif_running(netdev)) + return -EBUSY; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len); + + atl2_set_mac_addr(&adapter->hw); + + return 0; +} + +/** + * atl2_mii_ioctl - + * @netdev: + * @ifreq: + * @cmd: + **/ +static int +atl2_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + struct mii_ioctl_data *data = if_mii(ifr); + unsigned long flags; + + switch (cmd) { + case SIOCGMIIPHY: + data->phy_id = 0; + break; + case SIOCGMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + spin_lock_irqsave(&adapter->stats_lock, flags); + if (atl2_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, &data->val_out)) { + spin_unlock_irqrestore(&adapter->stats_lock, flags); + return -EIO; + } + spin_unlock_irqrestore(&adapter->stats_lock, flags); + break; + case SIOCSMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (data->reg_num & ~(0x1F)) + return -EFAULT; + spin_lock_irqsave(&adapter->stats_lock, flags); + if (atl2_write_phy_reg(&adapter->hw, data->reg_num, data->val_in)) { + spin_unlock_irqrestore(&adapter->stats_lock, flags); + return -EIO; + } + spin_unlock_irqrestore(&adapter->stats_lock, flags); + break; + default: + return -EOPNOTSUPP; + } + return ATL2_SUCCESS; +} + +/** + * atl2_ioctl - + * @netdev: + * @ifreq: + * @cmd: + **/ +static int +atl2_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + return atl2_mii_ioctl(netdev, ifr, cmd); +#ifdef ETHTOOL_OPS_COMPAT + case SIOCETHTOOL: + return ethtool_ioctl(ifr); +#endif + default: + return -EOPNOTSUPP; + } +} + +/** + * atl2_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + **/ +static void +atl2_tx_timeout(struct net_device *netdev) +{ + struct atl2_adapter *adapter = netdev_priv(netdev); + + /* Do the reset outside of interrupt context */ + schedule_work(&adapter->reset_task); +} + +/** + * atl2_watchdog - Timer Call-back + * @data: pointer to netdev cast into an unsigned long + **/ +static void +atl2_watchdog(unsigned long data) +{ + struct atl2_adapter *adapter = (struct atl2_adapter *) data; + u32 drop_rxd, drop_rxs; + unsigned long flags; + + if (!test_bit(__ATL2_DOWN, &adapter->flags)) { + spin_lock_irqsave(&adapter->stats_lock, flags); + drop_rxd = ATL2_READ_REG(&adapter->hw, REG_STS_RXD_OV); + drop_rxs = ATL2_READ_REG(&adapter->hw, REG_STS_RXS_OV); + adapter->net_stats.rx_over_errors += (drop_rxd+drop_rxs); + spin_unlock_irqrestore(&adapter->stats_lock, flags); + + /* Reset the timer */ + mod_timer(&adapter->watchdog_timer, jiffies + 4 * HZ); + } +} + +/** + * atl2_phy_config - Timer Call-back + * @data: pointer to netdev cast into an unsigned long + **/ +static void +atl2_phy_config(unsigned long data) +{ + struct atl2_adapter *adapter = (struct atl2_adapter *) data; + struct atl2_hw *hw = &adapter->hw; + unsigned long flags; + + spin_lock_irqsave(&adapter->stats_lock, flags); + atl2_write_phy_reg(hw, MII_ADVERTISE, hw->mii_autoneg_adv_reg); + atl2_write_phy_reg(hw, MII_BMCR, MII_CR_RESET|MII_CR_AUTO_NEG_EN|MII_CR_RESTART_AUTO_NEG); + spin_unlock_irqrestore(&adapter->stats_lock, flags); + clear_bit(0, &adapter->cfg_phy); +} + +int +atl2_up(struct atl2_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int err = 0; + u32 val; + + /* hardware has been reset, we need to reload some things */ + + err = atl2_init_hw(&adapter->hw); + if (err) { + err = -EIO; + return err; + } + + atl2_set_multi(netdev); + init_ring_ptrs(adapter); + +#ifdef NETIF_F_HW_VLAN_TX + atl2_restore_vlan(adapter); +#endif + + if (atl2_configure(adapter)) { + err = -EIO; + goto err_up; + } + + clear_bit(__ATL2_DOWN, &adapter->flags); + + val = ATL2_READ_REG(&adapter->hw, REG_MASTER_CTRL); + ATL2_WRITE_REG(&adapter->hw, REG_MASTER_CTRL, val | MASTER_CTRL_MANUAL_INT); + + atl2_irq_enable(adapter); + +err_up: + return err; +} + +void +atl2_reinit_locked(struct atl2_adapter *adapter) +{ + WARN_ON(in_interrupt()); + while (test_and_set_bit(__ATL2_RESETTING, &adapter->flags)) + msleep(1); + atl2_down(adapter); + atl2_up(adapter); + clear_bit(__ATL2_RESETTING, &adapter->flags); +} + +static void +atl2_reset_task(struct work_struct *work) +{ + struct atl2_adapter *adapter; + adapter = container_of(work, struct atl2_adapter, reset_task); + + atl2_reinit_locked(adapter); +} + +static inline void +atl2_setup_mac_ctrl(struct atl2_adapter *adapter) +{ + u32 value; + struct atl2_hw* hw = &adapter->hw; + struct net_device* netdev = adapter->netdev; + + /* Config MAC CTRL Register */ + value = MAC_CTRL_TX_EN | MAC_CTRL_RX_EN | MAC_CTRL_MACLP_CLK_PHY; + + // duplex + if (FULL_DUPLEX == adapter->link_duplex) + value |= MAC_CTRL_DUPLX; + + // flow control + value |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW); + + // PAD & CRC + value |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD); + + // preamble length + value |= (((u32)adapter->hw.preamble_len & MAC_CTRL_PRMLEN_MASK) << + MAC_CTRL_PRMLEN_SHIFT); + + // vlan + if (adapter->vlgrp) + value |= MAC_CTRL_RMV_VLAN; + + // filter mode + value |= MAC_CTRL_BC_EN; + if (netdev->flags & IFF_PROMISC) + value |= MAC_CTRL_PROMIS_EN; + else if (netdev->flags & IFF_ALLMULTI) + value |= MAC_CTRL_MC_ALL_EN; + + // half retry buffer + value |= (((u32)(adapter->hw.retry_buf & MAC_CTRL_HALF_LEFT_BUF_MASK)) << + MAC_CTRL_HALF_LEFT_BUF_SHIFT); + + ATL2_WRITE_REG(hw, REG_MAC_CTRL, value); +} + +static int +atl2_check_link(struct atl2_adapter *adapter) +{ + struct atl2_hw *hw = &adapter->hw; + struct net_device * netdev = adapter->netdev; + int ret_val; + u16 speed, duplex, phy_data; + int reconfig = 0; + + // MII_BMSR must read twise + atl2_read_phy_reg(hw, MII_BMSR, &phy_data); + atl2_read_phy_reg(hw, MII_BMSR, &phy_data); + if (!(phy_data&BMSR_LSTATUS)) { // link down + if (netif_carrier_ok(netdev)) { // old link state: Up + u32 value; + //disable rx + value = ATL2_READ_REG(hw, REG_MAC_CTRL); + value &= ~MAC_CTRL_RX_EN; + ATL2_WRITE_REG(hw, REG_MAC_CTRL, value); + adapter->link_speed = SPEED_0; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + return ATL2_SUCCESS; + } + + // Link Up + ret_val = atl2_get_speed_and_duplex(hw, &speed, &duplex); + if (ret_val) + return ret_val; + switch( hw->MediaType ) { + case MEDIA_TYPE_100M_FULL: + if (speed != SPEED_100 || duplex != FULL_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_100M_HALF: + if (speed != SPEED_100 || duplex != HALF_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_10M_FULL: + if (speed != SPEED_10 || duplex != FULL_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_10M_HALF: + if (speed != SPEED_10 || duplex != HALF_DUPLEX) + reconfig = 1; + break; + } + // link result is our setting + if (0 == reconfig) { + if (adapter->link_speed != speed || adapter->link_duplex != duplex ) { + adapter->link_speed = speed; + adapter->link_duplex = duplex; + atl2_setup_mac_ctrl(adapter); + printk(KERN_INFO "%s: %s NIC Link is Up<%d Mbps %s>\n", + atl2_driver_name, netdev->name, + adapter->link_speed, + adapter->link_duplex == FULL_DUPLEX ? + "Full Duplex" : "Half Duplex"); + } + + if (!netif_carrier_ok(netdev)) { // Link down -> Up + netif_carrier_on(netdev); + netif_wake_queue(netdev); + } + return ATL2_SUCCESS; + } + + // change orignal link status + if (netif_carrier_ok(netdev)) { + u32 value; + // disable rx + value = ATL2_READ_REG(hw, REG_MAC_CTRL); + value &= ~MAC_CTRL_RX_EN; + ATL2_WRITE_REG(hw, REG_MAC_CTRL, value); + + adapter->link_speed = SPEED_0; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + + // auto-neg, insert timer to re-config phy (if interval smaller than 5 seconds, something strange) + if (!test_bit(__ATL2_DOWN, &adapter->flags)) { + if (!test_and_set_bit(0, &adapter->cfg_phy)) { + mod_timer(&adapter->phy_config_timer, jiffies + 5 * HZ); + } + } + + return ATL2_SUCCESS; +} + +/** + * atl2_link_chg_task - deal with link change event Out of interrupt context + * @netdev: network interface device structure + **/ +static void +atl2_link_chg_task(struct work_struct *work) +{ + struct atl2_adapter *adapter; + unsigned long flags; + + adapter = container_of(work, struct atl2_adapter, link_chg_task); + + spin_lock_irqsave(&adapter->stats_lock, flags); + atl2_check_link(adapter); + spin_unlock_irqrestore(&adapter->stats_lock, flags); +} + +static void +atl2_setup_pcicmd(struct pci_dev *pdev) +{ + u16 cmd; + + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + + if (cmd & PCI_COMMAND_INTX_DISABLE) + cmd &= ~PCI_COMMAND_INTX_DISABLE; + if (cmd & PCI_COMMAND_IO) + cmd &= ~PCI_COMMAND_IO; + if (0 == (cmd & PCI_COMMAND_MEMORY)) + cmd |= PCI_COMMAND_MEMORY; + if (0 == (cmd & PCI_COMMAND_MASTER)) + cmd |= PCI_COMMAND_MASTER; + pci_write_config_word(pdev, PCI_COMMAND, cmd); + + /* + * some motherboards BIOS(PXE/EFI) driver may set PME + * while they transfer control to OS (Windows/Linux) + * so we should clear this bit before NIC work normally + */ + pci_write_config_dword(pdev, REG_PM_CTRLSTAT, 0); +} + +/** + * atl2_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in atl2_pci_tbl + * + * Returns 0 on success, negative on failure + * + * atl2_probe initializes an adapter identified by a pci_dev structure. + * The OS initialization, configuring of the adapter private structure, + * and a hardware reset occur. + **/ +static int __devinit +atl2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct atl2_adapter *adapter; + static int cards_found = 0; + unsigned long mmio_start; + int mmio_len; + int err; + + if((err = pci_enable_device(pdev))) + return err; + + /* + * atl2 is a shared-high-32-bit device, so we're stuck with 32-bit DMA + * until the kernel has the proper infrastructure to support 64-bit DMA + * on these devices. + */ + if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) && + (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) { + printk(KERN_ERR "atl2: No usable DMA configuration, aborting\n"); + goto err_dma; + } + + // Mark all PCI regions associated with PCI device + // pdev as being reserved by owner atl2_driver_name + if((err = pci_request_regions(pdev, atl2_driver_name))) + goto err_pci_reg; + + // Enables bus-mastering on the device and calls + // pcibios_set_master to do the needed arch specific settings + pci_set_master(pdev); + + err = -ENOMEM; + netdev = alloc_etherdev(sizeof(struct atl2_adapter)); + if(!netdev) + goto err_alloc_etherdev; + + SET_NETDEV_DEV(netdev, &pdev->dev); + + pci_set_drvdata(pdev, netdev); + adapter = netdev_priv(netdev); + adapter->netdev = netdev; + adapter->pdev = pdev; + adapter->hw.back = adapter; + + mmio_start = pci_resource_start(pdev, 0x0); + mmio_len = pci_resource_len(pdev, 0x0); + + adapter->hw.mem_rang = (u32)mmio_len; + adapter->hw.hw_addr = ioremap(mmio_start, mmio_len); + if(!adapter->hw.hw_addr) { + err = -EIO; + goto err_ioremap; + } + + atl2_setup_pcicmd(pdev); + + netdev->open = &atl2_open; + netdev->stop = &atl2_close; + netdev->hard_start_xmit = &atl2_xmit_frame; + netdev->get_stats = &atl2_get_stats; + netdev->set_multicast_list = &atl2_set_multi; + netdev->set_mac_address = &atl2_set_mac; + netdev->change_mtu = &atl2_change_mtu; + netdev->do_ioctl = &atl2_ioctl; + atl2_set_ethtool_ops(netdev); + +#ifdef HAVE_TX_TIMEOUT + netdev->tx_timeout = &atl2_tx_timeout; + netdev->watchdog_timeo = 5 * HZ; //FIXME -- CHS +#endif +#ifdef NETIF_F_HW_VLAN_TX + netdev->vlan_rx_register = atl2_vlan_rx_register; +#endif + strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); + + netdev->mem_start = mmio_start; + netdev->mem_end = mmio_start + mmio_len; + //netdev->base_addr = adapter->io_base; + adapter->bd_number = cards_found; + adapter->pci_using_64 = false; + + /* setup the private structure */ + + if((err = atl2_sw_init(adapter))) + goto err_sw_init; + + err = -EIO; + +#ifdef NETIF_F_HW_VLAN_TX + netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX ); +#endif + +#ifdef NETIF_F_LLTX + netdev->features |= NETIF_F_LLTX; +#endif + + /* Init PHY as early as possible due to power saving issue */ + atl2_phy_init(&adapter->hw); + + /* reset the controller to + * put the device in a known good starting state */ + + if (atl2_reset_hw(&adapter->hw)) { + err = -EIO; + goto err_reset; + } + + /* copy the MAC address out of the EEPROM */ + atl2_read_mac_addr(&adapter->hw); + memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); +//FIXME: do we still need this? +#ifdef ETHTOOL_GPERMADDR + memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len); + + if (!is_valid_ether_addr(netdev->perm_addr)) { +#else + if (!is_valid_ether_addr(netdev->dev_addr)) { +#endif + err = -EIO; + goto err_eeprom; + } + + atl2_check_options(adapter); + + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &atl2_watchdog; + adapter->watchdog_timer.data = (unsigned long) adapter; + + init_timer(&adapter->phy_config_timer); + adapter->phy_config_timer.function = &atl2_phy_config; + adapter->phy_config_timer.data = (unsigned long) adapter; + + INIT_WORK(&adapter->reset_task, atl2_reset_task); + INIT_WORK(&adapter->link_chg_task, atl2_link_chg_task); + + strcpy(netdev->name, "eth%d"); // ?? + if((err = register_netdev(netdev))) + goto err_register; + + /* assume we have no link for now */ + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + cards_found++; + + return 0; + +//err_init_hw: +err_reset: +err_register: +err_sw_init: +err_eeprom: + iounmap(adapter->hw.hw_addr); +err_ioremap: + free_netdev(netdev); +err_alloc_etherdev: + pci_release_regions(pdev); +err_pci_reg: +err_dma: + pci_disable_device(pdev); + return err; +} + +/** + * atl2_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * atl2_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. The could be caused by a + * Hot-Plug event, or because the driver is going to be removed from + * memory. + **/ +/* FIXME: write the original MAC address back in case it was changed from a + * BIOS-set value, as in atl1 -- CHS */ +static void __devexit +atl2_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl2_adapter *adapter = netdev_priv(netdev); + + /* flush_scheduled work may reschedule our watchdog task, so + * explicitly disable watchdog tasks from being rescheduled */ + set_bit(__ATL2_DOWN, &adapter->flags); + + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_config_timer); + + flush_scheduled_work(); + + unregister_netdev(netdev); + + atl2_force_ps(&adapter->hw); + + iounmap(adapter->hw.hw_addr); + pci_release_regions(pdev); + + free_netdev(netdev); + + pci_disable_device(pdev); +} + +static int +atl2_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl2_adapter *adapter = netdev_priv(netdev); + struct atl2_hw * hw = &adapter->hw; + u16 speed, duplex; + u32 ctrl = 0; + u32 wufc = adapter->wol; + +#ifdef CONFIG_PM + int retval = 0; +#endif + + netif_device_detach(netdev); + + if (netif_running(netdev)) { + WARN_ON(test_bit(__ATL2_RESETTING, &adapter->flags)); + atl2_down(adapter); + } + +#ifdef CONFIG_PM + retval = pci_save_state(pdev); + if (retval) + return retval; +#endif + + atl2_read_phy_reg(hw, MII_BMSR, (u16*)&ctrl); + atl2_read_phy_reg(hw, MII_BMSR, (u16*)&ctrl); + if(ctrl & BMSR_LSTATUS) + wufc &= ~ATL2_WUFC_LNKC; + + if (0 != (ctrl & BMSR_LSTATUS) && 0 != wufc) { + u32 ret_val; + /* get current link speed & duplex */ + ret_val = atl2_get_speed_and_duplex(hw, &speed, &duplex); + if (ret_val) { + printk(KERN_DEBUG "%s: get speed&duplex error while suspend\n", atl2_driver_name); + goto wol_dis; + } + + ctrl = 0; + + /* turn on magic packet wol */ + if (wufc & ATL2_WUFC_MAG) + ctrl |= (WOL_MAGIC_EN | WOL_MAGIC_PME_EN); + + /* ignore Link Chg event when Link is up */ + ATL2_WRITE_REG(hw, REG_WOL_CTRL, ctrl); + + /* Config MAC CTRL Register */ + ctrl = MAC_CTRL_RX_EN | MAC_CTRL_MACLP_CLK_PHY; + if (FULL_DUPLEX == adapter->link_duplex) + ctrl |= MAC_CTRL_DUPLX; + ctrl |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD); + ctrl |= (((u32)adapter->hw.preamble_len & + MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT); + ctrl |= (((u32)(adapter->hw.retry_buf & + MAC_CTRL_HALF_LEFT_BUF_MASK)) << + MAC_CTRL_HALF_LEFT_BUF_SHIFT); + if (wufc & ATL2_WUFC_MAG) { + /* magic packet maybe Broadcast&multicast&Unicast frame */ + ctrl |= MAC_CTRL_BC_EN; + } + + ATL2_WRITE_REG(hw, REG_MAC_CTRL, ctrl); + + /* pcie patch */ + ctrl = ATL2_READ_REG(hw, REG_PCIE_PHYMISC); + ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; + ATL2_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl); + ctrl = ATL2_READ_REG(hw, REG_PCIE_DLL_TX_CTRL1); + ctrl |= PCIE_DLL_TX_CTRL1_SEL_NOR_CLK; + ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, ctrl); + + pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); + goto suspend_exit; + } + + if (0 == (ctrl&BMSR_LSTATUS) && 0 != (wufc&ATL2_WUFC_LNKC)) { + /* link is down, so only LINK CHG WOL event enable */ + ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN); + ATL2_WRITE_REG(hw, REG_WOL_CTRL, ctrl); + ATL2_WRITE_REG(hw, REG_MAC_CTRL, 0); + + /* pcie patch */ + ctrl = ATL2_READ_REG(hw, REG_PCIE_PHYMISC); + ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; + ATL2_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl); + ctrl = ATL2_READ_REG(hw, REG_PCIE_DLL_TX_CTRL1); + ctrl |= PCIE_DLL_TX_CTRL1_SEL_NOR_CLK; + ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, ctrl); + + hw->phy_configured = false; /* re-init PHY when resume */ + + pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); + + goto suspend_exit; + } + +wol_dis: + /* WOL disabled */ + ATL2_WRITE_REG(hw, REG_WOL_CTRL, 0); + + /* pcie patch */ + ctrl = ATL2_READ_REG(hw, REG_PCIE_PHYMISC); + ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; + ATL2_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl); + ctrl = ATL2_READ_REG(hw, REG_PCIE_DLL_TX_CTRL1); + ctrl |= PCIE_DLL_TX_CTRL1_SEL_NOR_CLK; + ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, ctrl); + + atl2_force_ps(hw); + hw->phy_configured = false; /* re-init PHY when resume */ + + pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); + +suspend_exit: + if (netif_running(netdev)) + atl2_free_irq(adapter); + + pci_disable_device(pdev); + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +#ifdef CONFIG_PM +static int +atl2_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl2_adapter *adapter = netdev_priv(netdev); + u32 err; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + if ((err = pci_enable_device(pdev))) { + printk(KERN_ERR "atl2: Cannot enable PCI device from suspend\n"); + return err; + } + + pci_set_master(pdev); + + ATL2_READ_REG(&adapter->hw, REG_WOL_CTRL); /* clear WOL status */ + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + ATL2_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0); + + if (netif_running(netdev) && (err = atl2_request_irq(adapter))) + return err; + + atl2_reset_hw(&adapter->hw); + + if(netif_running(netdev)) + atl2_up(adapter); + + netif_device_attach(netdev); + + return 0; +} +#endif + +static void +atl2_shutdown(struct pci_dev *pdev) +{ + atl2_suspend(pdev, PMSG_SUSPEND); +} + +static struct pci_driver atl2_driver = { + .name = atl2_driver_name, + .id_table = atl2_pci_tbl, + .probe = atl2_probe, + .remove = __devexit_p(atl2_remove), + /* Power Managment Hooks */ + .suspend = atl2_suspend, +#ifdef CONFIG_PM + .resume = atl2_resume, +#endif + .shutdown = atl2_shutdown, +}; + +/** + * atl2_init_module - Driver Registration Routine + * + * atl2_init_module is the first routine called when the driver is + * loaded. All it does is register with the PCI subsystem. + **/ +static int __init +atl2_init_module(void) +{ + int ret; + printk(KERN_INFO "%s - version %s\n", atl2_driver_string, atl2_driver_version); + printk(KERN_INFO "%s\n", atl2_copyright); + + ret = pci_register_driver(&atl2_driver); + if (copybreak != COPYBREAK_DEFAULT) { + if (copybreak == 0) + printk(KERN_INFO "atl2: copybreak disabled\n"); + else + printk(KERN_INFO "atl2: copybreak enabled for packets <= %u bytes\n", copybreak); + } + return ret; +} +module_init(atl2_init_module); + +/** + * atl2_exit_module - Driver Exit Cleanup Routine + * + * atl2_exit_module is called just before the driver is removed + * from memory. + **/ +static void __exit +atl2_exit_module(void) +{ + pci_unregister_driver(&atl2_driver); +} +module_exit(atl2_exit_module); + +void +atl2_read_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value) +{ + struct atl2_adapter *adapter = hw->back; + pci_read_config_word(adapter->pdev, reg, value); +} + +void +atl2_write_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value) +{ + struct atl2_adapter *adapter = hw->back; + pci_write_config_word(adapter->pdev, reg, *value); +} --- linux-2.6.27.orig/ubuntu/atl2/atl2_osdep.h +++ linux-2.6.27/ubuntu/atl2/atl2_osdep.h @@ -0,0 +1,72 @@ +/* atl2_osdep.h -- atl2 compat cruft + * + * Copyright(c) 2007 Atheros Corporation. All rights reserved. + * Copyright(c) 2006 xiong huang + * Copyright(c) 2007 Chris Snook + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _ATL2_OSDEP_H_ +#define _ATL2_OSDEP_H_ + +#include +#include +#include +#include + +#define usec_delay(x) udelay(x) +#ifndef msec_delay +#define msec_delay(x) do { \ + if(in_interrupt()) BUG(); \ + else msleep(x); \ + } while (0) + +/* Some workarounds require millisecond delays and are run during interrupt + * context. Most notably, when establishing link, the phy may need tweaking + * but cannot process phy register reads/writes faster than millisecond + * intervals...and we establish link due to a "link status change" interrupt. + */ +#define msec_delay_irq(x) mdelay(x) +#endif + +#define PCI_COMMAND_REGISTER PCI_COMMAND +#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE +#define ETH_ADDR_LEN ETH_ALEN + +#define ATL2_WRITE_REG(a, reg, value) (writel((value), ((a)->hw_addr + reg))) + +#define ATL2_WRITE_FLUSH(a) (readl((a)->hw_addr)) + +#define ATL2_READ_REG(a, reg) (readl((a)->hw_addr + reg)) + +#define ATL2_WRITE_REGB(a, reg, value) (writeb((value), ((a)->hw_addr + reg))) + +#define ATL2_READ_REGB(a, reg) (readb((a)->hw_addr + reg)) + +#define ATL2_WRITE_REGW(a, reg, value) (writew((value), ((a)->hw_addr + reg))) + +#define ATL2_READ_REGW(a, reg) (readw((a)->hw_addr + reg)) + +#define ATL2_WRITE_REG_ARRAY(a, reg, offset, value) \ + (writel((value), (((a)->hw_addr + reg) + ((offset) << 2)))) + +#define ATL2_READ_REG_ARRAY(a, reg, offset) \ + (readl(((a)->hw_addr + reg) + ((offset) << 2))) + +#endif /* _ATL2_OSDEP_H_ */ --- linux-2.6.27.orig/ubuntu/atl2/atl2_hw.c +++ linux-2.6.27/ubuntu/atl2/atl2_hw.c @@ -0,0 +1,760 @@ +/* atl2_hw.c -- atl2 hardware control functions + * + * Copyright(c) 2007 Atheros Corporation. All rights reserved. + * Copyright(c) 2006 xiong huang + * Copyright(c) 2007 Chris Snook + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include + +#include "atl2.h" +#include "atl2_hw.h" + +#define LBYTESWAP( a ) ( ( ( (a) & 0x00ff00ff ) << 8 ) | ( ( (a) & 0xff00ff00 ) >> 8 ) ) +#define LONGSWAP( a ) ( ( LBYTESWAP( a ) << 16 ) | ( LBYTESWAP( a ) >> 16 ) ) +#define SHORTSWAP( a ) ( ( (a) << 8 ) | ( (a) >> 8 ) ) + +/* + * Reset the transmit and receive units; mask and clear all interrupts. + * + * hw - Struct containing variables accessed by shared code + * return : ATL2_SUCCESS or idle status (if error) + */ +s32 +atl2_reset_hw(struct atl2_hw *hw) +{ + u32 icr; + u16 pci_cfg_cmd_word; + int i; + + /* Workaround for PCI problem when BIOS sets MMRBC incorrectly. */ + atl2_read_pci_cfg(hw, PCI_REG_COMMAND, &pci_cfg_cmd_word); + if ((pci_cfg_cmd_word & + (CMD_IO_SPACE|CMD_MEMORY_SPACE|CMD_BUS_MASTER)) != + (CMD_IO_SPACE|CMD_MEMORY_SPACE|CMD_BUS_MASTER)) { + pci_cfg_cmd_word |= + (CMD_IO_SPACE|CMD_MEMORY_SPACE|CMD_BUS_MASTER); + atl2_write_pci_cfg(hw, PCI_REG_COMMAND, &pci_cfg_cmd_word); + } + + /* Clear Interrupt mask to stop board from generating + * interrupts & Clear any pending interrupt events + */ +// ATL2_WRITE_REG(hw, REG_IMR, 0); +// ATL2_WRITE_REG(hw, REG_ISR, 0xffffffff); + + /* Issue Soft Reset to the MAC. This will reset the chip's + * transmit, receive, DMA. It will not effect + * the current PCI configuration. The global reset bit is self- + * clearing, and should clear within a microsecond. + */ + ATL2_WRITE_REG(hw, REG_MASTER_CTRL, MASTER_CTRL_SOFT_RST); + wmb(); + msec_delay(1); // delay about 1ms + + /* Wait at least 10ms for All module to be Idle */ + for (i=0; i < 10; i++) { + icr = ATL2_READ_REG(hw, REG_IDLE_STATUS); + if (!icr) + break; + msec_delay(1); // delay 1 ms + cpu_relax(); + } + + if (icr) + return icr; + + return ATL2_SUCCESS; +} + +#define CUSTOM_SPI_CS_SETUP 2 +#define CUSTOM_SPI_CLK_HI 2 +#define CUSTOM_SPI_CLK_LO 2 +#define CUSTOM_SPI_CS_HOLD 2 +#define CUSTOM_SPI_CS_HI 3 + +static struct atl2_spi_flash_dev flash_table[] = +{ +/* manu_name WRSR READ PROGRAM WREN WRDI RDSR RDID SECTOR_ERASE CHIP_ERASE */ + {"Atmel", 0x0, 0x03, 0x02, 0x06, 0x04, 0x05, 0x15, 0x52, 0x62 }, + {"SST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0x90, 0x20, 0x60 }, + {"ST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0xAB, 0xD8, 0xC7 }, +}; + +static bool +atl2_spi_read(struct atl2_hw* hw, u32 addr, u32* buf) +{ + int i; + u32 value; + + ATL2_WRITE_REG(hw, REG_SPI_DATA, 0); + ATL2_WRITE_REG(hw, REG_SPI_ADDR, addr); + + value = SPI_FLASH_CTRL_WAIT_READY | + (CUSTOM_SPI_CS_SETUP & SPI_FLASH_CTRL_CS_SETUP_MASK) << SPI_FLASH_CTRL_CS_SETUP_SHIFT | + (CUSTOM_SPI_CLK_HI & SPI_FLASH_CTRL_CLK_HI_MASK) << SPI_FLASH_CTRL_CLK_HI_SHIFT | + (CUSTOM_SPI_CLK_LO & SPI_FLASH_CTRL_CLK_LO_MASK) << SPI_FLASH_CTRL_CLK_LO_SHIFT | + (CUSTOM_SPI_CS_HOLD & SPI_FLASH_CTRL_CS_HOLD_MASK) << SPI_FLASH_CTRL_CS_HOLD_SHIFT | + (CUSTOM_SPI_CS_HI & SPI_FLASH_CTRL_CS_HI_MASK) << SPI_FLASH_CTRL_CS_HI_SHIFT | + (0x1 & SPI_FLASH_CTRL_INS_MASK) << SPI_FLASH_CTRL_INS_SHIFT; + + ATL2_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value); + + value |= SPI_FLASH_CTRL_START; + + ATL2_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value); + + for (i = 0; i < 10; i++) + { + msec_delay(1); // 1ms + value = ATL2_READ_REG(hw, REG_SPI_FLASH_CTRL); + if (!(value & SPI_FLASH_CTRL_START)) + break; + } + + if (value & SPI_FLASH_CTRL_START) + return false; + + *buf = ATL2_READ_REG(hw, REG_SPI_DATA); + + return true; +} + +/* + * get_permanent_address + * return 0 if get valid mac address, + */ +static int +get_permanent_address(struct atl2_hw *hw) +{ + u32 Addr[2]; + u32 i, Control; + u16 Register; + u8 EthAddr[NODE_ADDRESS_SIZE]; + bool KeyValid; + + if (is_valid_ether_addr(hw->perm_mac_addr)) + return 0; + + Addr[0] = 0; + Addr[1] = 0; + + if (!atl2_check_eeprom_exist(hw)) { /* eeprom exists */ + Register = 0; + KeyValid = false; + + /* Read out all EEPROM content */ + i = 0; + while (1) { + if (atl2_read_eeprom(hw, i + 0x100, &Control)) { + if (KeyValid) { + if (Register == REG_MAC_STA_ADDR) + Addr[0] = Control; + else if (Register == (REG_MAC_STA_ADDR + 4)) + Addr[1] = Control; + KeyValid = false; + } else if ((Control & 0xff) == 0x5A) { + KeyValid = true; + Register = (u16) (Control >> 16); + } else { + break; /* assume data end while encount an invalid KEYWORD */ + } + } else { + break; /* read error */ + } + i += 4; + } + + *(u32*) &EthAddr[2] = LONGSWAP(Addr[0]); + *(u16*) &EthAddr[0] = SHORTSWAP(*(u16*)&Addr[1]); + + if (is_valid_ether_addr(EthAddr)) { + memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE); + return 0; + } + return 1; + } + + // see if SPI FLAHS exist ? + Addr[0] = 0; + Addr[1] = 0; + Register = 0; + KeyValid = false; + i = 0; + while (1) { + if (atl2_spi_read(hw, i + 0x1f000, &Control)) { + if (KeyValid) { + if (Register == REG_MAC_STA_ADDR) + Addr[0] = Control; + else if (Register == (REG_MAC_STA_ADDR + 4)) + Addr[1] = Control; + KeyValid = false; + } else if ((Control & 0xff) == 0x5A) { + KeyValid = true; + Register = (u16) (Control >> 16); + } else { + break; /* data end */ + } + } else { + break; /* read error */ + } + i += 4; + } + + *(u32*) &EthAddr[2] = LONGSWAP(Addr[0]); + *(u16*) &EthAddr[0] = SHORTSWAP(*(u16*)&Addr[1]); + if (is_valid_ether_addr(EthAddr)) { + memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE); + return 0; + } + /* maybe MAC-address is from BIOS */ + Addr[0] = ATL2_READ_REG(hw,REG_MAC_STA_ADDR); + Addr[1] = ATL2_READ_REG(hw,REG_MAC_STA_ADDR+4); + *(u32*) &EthAddr[2] = LONGSWAP(Addr[0]); + *(u16*) &EthAddr[0] = SHORTSWAP(*(u16*)&Addr[1]); + + if (is_valid_ether_addr(EthAddr)) { + memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE); + return 0; + } + + return 1; +} + +/* + * Reads the adapter's MAC address from the EEPROM + * + * hw - Struct containing variables accessed by shared code + */ +s32 +atl2_read_mac_addr(struct atl2_hw *hw) +{ + u16 i; + + if (get_permanent_address(hw)) { + // for test + hw->perm_mac_addr[0] = 0x00; + hw->perm_mac_addr[1] = 0x13; + hw->perm_mac_addr[2] = 0x74; + hw->perm_mac_addr[3] = 0x00; + hw->perm_mac_addr[4] = 0x5c; + hw->perm_mac_addr[5] = 0x38; + } + + for(i = 0; i < NODE_ADDRESS_SIZE; i++) + hw->mac_addr[i] = hw->perm_mac_addr[i]; + + return ATL2_SUCCESS; +} + +/* + * Hashes an address to determine its location in the multicast table + * + * hw - Struct containing variables accessed by shared code + * mc_addr - the multicast address to hash + * + * atl2_hash_mc_addr + * purpose + * set hash value for a multicast address + * hash calcu processing : + * 1. calcu 32bit CRC for multicast address + * 2. reverse crc with MSB to LSB + */ +u32 +atl2_hash_mc_addr(struct atl2_hw *hw, u8 *mc_addr) +{ + u32 crc32, value=0; + int i; + + crc32 = ether_crc_le(6, mc_addr); + + for (i=0; i<32; i++) + value |= (((crc32>>i)&1)<<(31-i)); + + return value; +} + +/* + * Sets the bit in the multicast table corresponding to the hash value. + * + * hw - Struct containing variables accessed by shared code + * hash_value - Multicast address hash value + */ +void +atl2_hash_set(struct atl2_hw *hw, u32 hash_value) +{ + u32 hash_bit, hash_reg; + u32 mta; + + /* The HASH Table is a register array of 2 32-bit registers. + * It is treated like an array of 64 bits. We want to set + * bit BitArray[hash_value]. So we figure out what register + * the bit is in, read it, OR in the new bit, then write + * back the new value. The register is determined by the + * upper 7 bits of the hash value and the bit within that + * register are determined by the lower 5 bits of the value. + */ + hash_reg = (hash_value >> 31) & 0x1; + hash_bit = (hash_value >> 26) & 0x1F; + + mta = ATL2_READ_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg); + + mta |= (1 << hash_bit); + + ATL2_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg, mta); +} + +/* + * atl2_init_pcie - init PCIE module + */ +static void +atl2_init_pcie(struct atl2_hw *hw) +{ + u32 value; + value = LTSSM_TEST_MODE_DEF; + ATL2_WRITE_REG(hw, REG_LTSSM_TEST_MODE, value); + + value = PCIE_DLL_TX_CTRL1_DEF; + ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, value); +} + +void +atl2_init_flash_opcode(struct atl2_hw *hw) +{ + if (hw->flash_vendor >= ARRAY_SIZE(flash_table)) { + hw->flash_vendor = 0; // ATMEL + } + // Init OP table + ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_PROGRAM, flash_table[hw->flash_vendor].cmdPROGRAM); + ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_SC_ERASE, flash_table[hw->flash_vendor].cmdSECTOR_ERASE); + ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_CHIP_ERASE, flash_table[hw->flash_vendor].cmdCHIP_ERASE); + ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_RDID, flash_table[hw->flash_vendor].cmdRDID); + ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_WREN, flash_table[hw->flash_vendor].cmdWREN); + ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_RDSR, flash_table[hw->flash_vendor].cmdRDSR); + ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_WRSR, flash_table[hw->flash_vendor].cmdWRSR); + ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_READ, flash_table[hw->flash_vendor].cmdREAD); +} + +/******************************************************************** +* Performs basic configuration of the adapter. +* +* hw - Struct containing variables accessed by shared code +* Assumes that the controller has previously been reset and is in a +* post-reset uninitialized state. Initializes multicast table, +* and Calls routines to setup link +* Leaves the transmit and receive units disabled and uninitialized. +********************************************************************/ +s32 +atl2_init_hw(struct atl2_hw *hw) +{ + u32 ret_val = 0; + + atl2_init_pcie(hw); + + /* Zero out the Multicast HASH table */ + /* clear the old settings from the multicast hash table */ + ATL2_WRITE_REG(hw, REG_RX_HASH_TABLE, 0); + ATL2_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0); + + atl2_init_flash_opcode(hw); + + ret_val = atl2_phy_init(hw); + + return ret_val; +} + +/* + * Detects the current speed and duplex settings of the hardware. + * + * hw - Struct containing variables accessed by shared code + * speed - Speed of the connection + * duplex - Duplex setting of the connection + */ +s32 +atl2_get_speed_and_duplex(struct atl2_hw *hw, u16 *speed, u16 *duplex) +{ + s32 ret_val; + u16 phy_data; + + // ; --- Read PHY Specific Status Register (17) + ret_val = atl2_read_phy_reg(hw, MII_AT001_PSSR, &phy_data); + if (ret_val) + return ret_val; + + if (!(phy_data & MII_AT001_PSSR_SPD_DPLX_RESOLVED)) + return ATL2_ERR_PHY_RES; + + switch(phy_data & MII_AT001_PSSR_SPEED) { + case MII_AT001_PSSR_100MBS: + *speed = SPEED_100; + break; + case MII_AT001_PSSR_10MBS: + *speed = SPEED_10; + break; + default: + return ATL2_ERR_PHY_SPEED; + break; + } + + if (phy_data & MII_AT001_PSSR_DPLX) { + *duplex = FULL_DUPLEX; + } else { + *duplex = HALF_DUPLEX; + } + + return ATL2_SUCCESS; +} + +/* + * Reads the value from a PHY register + * hw - Struct containing variables accessed by shared code + * reg_addr - address of the PHY register to read + */ +s32 +atl2_read_phy_reg(struct atl2_hw *hw, u16 reg_addr, u16 *phy_data) +{ + u32 val; + int i; + + val = ((u32)(reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT | + MDIO_START | + MDIO_SUP_PREAMBLE | + MDIO_RW | + MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT; + ATL2_WRITE_REG(hw, REG_MDIO_CTRL, val); + + wmb(); + + for (i=0; iMediaType) { + case MEDIA_TYPE_AUTO_SENSOR: + mii_autoneg_adv_reg |= + (MII_AR_10T_HD_CAPS | + MII_AR_10T_FD_CAPS | + MII_AR_100TX_HD_CAPS | + MII_AR_100TX_FD_CAPS); + hw->autoneg_advertised = + ADVERTISE_10_HALF | + ADVERTISE_10_FULL | + ADVERTISE_100_HALF | + ADVERTISE_100_FULL; + break; + case MEDIA_TYPE_100M_FULL: + mii_autoneg_adv_reg |= MII_AR_100TX_FD_CAPS; + hw->autoneg_advertised = ADVERTISE_100_FULL; + break; + case MEDIA_TYPE_100M_HALF: + mii_autoneg_adv_reg |= MII_AR_100TX_HD_CAPS; + hw->autoneg_advertised = ADVERTISE_100_HALF; + break; + case MEDIA_TYPE_10M_FULL: + mii_autoneg_adv_reg |= MII_AR_10T_FD_CAPS; + hw->autoneg_advertised = ADVERTISE_10_FULL; + break; + default: + mii_autoneg_adv_reg |= MII_AR_10T_HD_CAPS; + hw->autoneg_advertised = ADVERTISE_10_HALF; + break; + } + + /* flow control fixed to enable all */ + mii_autoneg_adv_reg |= (MII_AR_ASM_DIR | MII_AR_PAUSE); + + hw->mii_autoneg_adv_reg = mii_autoneg_adv_reg; + + ret_val = atl2_write_phy_reg(hw, MII_ADVERTISE, mii_autoneg_adv_reg); + + if(ret_val) + return ret_val; + + return ATL2_SUCCESS; +} + +/* + * Resets the PHY and make all config validate + * + * hw - Struct containing variables accessed by shared code + * + * Sets bit 15 and 12 of the MII Control regiser (for F001 bug) + */ +static s32 +atl2_phy_commit(struct atl2_hw *hw) +{ + s32 ret_val; + u16 phy_data; + +/* FIXME: use or remove -- CHS + if (hw->MediaType == MEDIA_TYPE_AUTO_SENSOR) { + phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN; + } else { + switch (hw->MediaType) + { + case MEDIA_TYPE_100M_FULL: + phy_data = MII_CR_FULL_DUPLEX|MII_CR_SPEED_100|MII_CR_RESET; + break; + case MEDIA_TYPE_100M_HALF: + phy_data = MII_CR_SPEED_100|MII_CR_RESET; + break; + case MEDIA_TYPE_10M_FULL: + phy_data = MII_CR_FULL_DUPLEX|MII_CR_SPEED_10|MII_CR_RESET; + break; + default: // MEDIA_TYPE_10M_HALF: + phy_data = MII_CR_SPEED_10|MII_CR_RESET; + break; + } + } +*/ + phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG; + ret_val = atl2_write_phy_reg(hw, MII_BMCR, phy_data); + if (ret_val) { // bug fixed + u32 val; + int i; + /* pcie serdes link may be down ! */ + for (i=0; i < 25; i++) { + msec_delay(1); + val = ATL2_READ_REG(hw, REG_MDIO_CTRL); + if (!(val & (MDIO_START | MDIO_BUSY))) + break; + } + + if (0 != (val & (MDIO_START | MDIO_BUSY))) { + printk(KERN_ERR "atl2: PCIe link down for at least 25ms !\n"); + return ret_val; + } + } + return ATL2_SUCCESS; +} + +s32 +atl2_phy_init(struct atl2_hw *hw) +{ + s32 ret_val; + u16 phy_val; + + if (hw->phy_configured) + return 0; + + /* Enable PHY */ + ATL2_WRITE_REGW(hw, REG_PHY_ENABLE, 1); + ATL2_WRITE_FLUSH(hw); + msec_delay(1); + + /* check if the PHY is in powersaving mode */ + atl2_write_phy_reg(hw, MII_DBG_ADDR, 0); + atl2_read_phy_reg(hw, MII_DBG_DATA, &phy_val); + + /* 024E / 124E 0r 0274 / 1274 ? */ + if (phy_val & 0x1000) { + phy_val &= ~0x1000; + atl2_write_phy_reg(hw, MII_DBG_DATA, phy_val); + } + + msec_delay(1); + + + /*Enable PHY LinkChange Interrupt */ + ret_val = atl2_write_phy_reg(hw, 18, 0xC00); + if (ret_val) + return ret_val; + + /* setup AutoNeg parameters */ + ret_val = atl2_phy_setup_autoneg_adv(hw); + if(ret_val) + return ret_val; + + /* SW.Reset & En-Auto-Neg to restart Auto-Neg */ + ret_val = atl2_phy_commit(hw); + if (ret_val) + return ret_val; + + hw->phy_configured = true; + + return ret_val; +} + +void +atl2_set_mac_addr(struct atl2_hw *hw) +{ + u32 value; + // 00-0B-6A-F6-00-DC + // 0: 6AF600DC 1: 000B + // low dword + value = (((u32)hw->mac_addr[2]) << 24) | + (((u32)hw->mac_addr[3]) << 16) | + (((u32)hw->mac_addr[4]) << 8 ) | + (((u32)hw->mac_addr[5]) ) ; + ATL2_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 0, value); + // hight dword + value = (((u32)hw->mac_addr[0]) << 8 ) | + (((u32)hw->mac_addr[1]) ) ; + ATL2_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 1, value); +} + +/* + * check_eeprom_exist + * return 0 if eeprom exist + */ +int +atl2_check_eeprom_exist(struct atl2_hw *hw) +{ + u32 value; + + value = ATL2_READ_REG(hw, REG_SPI_FLASH_CTRL); + if (value & SPI_FLASH_CTRL_EN_VPD) { + value &= ~SPI_FLASH_CTRL_EN_VPD; + ATL2_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value); + } + value = ATL2_READ_REGW(hw, REG_PCIE_CAP_LIST); + return ((value & 0xFF00) == 0x6C00) ? 0 : 1; +} + +// FIXME: This doesn't look right. -- CHS +bool +atl2_write_eeprom(struct atl2_hw *hw, u32 offset, u32 value) +{ + return true; +} + +bool +atl2_read_eeprom(struct atl2_hw *hw, u32 Offset, u32 *pValue) +{ + int i; + u32 Control; + + if (Offset & 0x3) + return false; /* address do not align */ + + ATL2_WRITE_REG(hw, REG_VPD_DATA, 0); + Control = (Offset & VPD_CAP_VPD_ADDR_MASK) << VPD_CAP_VPD_ADDR_SHIFT; + ATL2_WRITE_REG(hw, REG_VPD_CAP, Control); + + for (i = 0; i < 10; i++) { + msec_delay(2); + Control = ATL2_READ_REG(hw, REG_VPD_CAP); + if (Control & VPD_CAP_VPD_FLAG) + break; + } + + if (Control & VPD_CAP_VPD_FLAG) { + *pValue = ATL2_READ_REG(hw, REG_VPD_DATA); + return true; + } + return false; /* timeout */ +} + +void +atl2_force_ps(struct atl2_hw *hw) +{ + u16 phy_val; + + atl2_write_phy_reg(hw, MII_DBG_ADDR, 0); + atl2_read_phy_reg(hw, MII_DBG_DATA, &phy_val); + atl2_write_phy_reg(hw, MII_DBG_DATA, phy_val | 0x1000); + + atl2_write_phy_reg(hw, MII_DBG_ADDR, 2); + atl2_write_phy_reg(hw, MII_DBG_DATA, 0x3000); + atl2_write_phy_reg(hw, MII_DBG_ADDR, 3); + atl2_write_phy_reg(hw, MII_DBG_DATA, 0); +} --- linux-2.6.27.orig/ubuntu/atl2/atl2_hw.h +++ linux-2.6.27/ubuntu/atl2/atl2_hw.h @@ -0,0 +1,758 @@ +/* atl2_hw.h -- atl2 hardware definitions + * + * Copyright(c) 2007 Atheros Corporation. All rights reserved. + * Copyright(c) 2006 xiong huang + * Copyright(c) 2007 Chris Snook + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Some of these defines are unused for various reasons. Some describe + * hardware features we don't yet use. Some are specific to the cousin atl1 + * hardware, which we may merge this driver with in the future. Please + * remember this is a surrogate for hardware specs, and don't unnecessarily + * abuse the content or formatting. -- CHS + */ + +#ifndef _ATL2_HW_H_ +#define _ATL2_HW_H_ + +#include "atl2_osdep.h" + +struct atl2_adapter; +struct atl2_hw; + +/* function prototype */ +s32 atl2_reset_hw(struct atl2_hw *hw); +s32 atl2_read_mac_addr(struct atl2_hw *hw); +s32 atl2_init_hw(struct atl2_hw *hw); +s32 atl2_get_speed_and_duplex(struct atl2_hw *hw, u16 *speed, u16 *duplex); +u32 atl2_auto_get_fc(struct atl2_adapter *adapter, u16 duplex); +u32 atl2_hash_mc_addr(struct atl2_hw *hw, u8 *mc_addr); +void atl2_hash_set(struct atl2_hw *hw, u32 hash_value); +s32 atl2_read_phy_reg(struct atl2_hw *hw, u16 reg_addr, u16 *phy_data); +s32 atl2_write_phy_reg(struct atl2_hw *hw, u32 reg_addr, u16 phy_data); +void atl2_read_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value); +void atl2_write_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value); +s32 atl2_validate_mdi_setting(struct atl2_hw *hw); +void atl2_set_mac_addr(struct atl2_hw *hw); +bool atl2_read_eeprom(struct atl2_hw *hw, u32 Offset, u32 *pValue); +bool atl2_write_eeprom(struct atl2_hw *hw, u32 offset, u32 value); +s32 atl2_phy_init(struct atl2_hw *hw); +int atl2_check_eeprom_exist(struct atl2_hw *hw); +void atl2_force_ps(struct atl2_hw *hw); + +/* register definition */ +#define REG_PM_CTRLSTAT 0x44 + +#define REG_PCIE_CAP_LIST 0x58 + +#define REG_VPD_CAP 0x6C +#define VPD_CAP_ID_MASK 0xff +#define VPD_CAP_ID_SHIFT 0 +#define VPD_CAP_NEXT_PTR_MASK 0xFF +#define VPD_CAP_NEXT_PTR_SHIFT 8 +#define VPD_CAP_VPD_ADDR_MASK 0x7FFF +#define VPD_CAP_VPD_ADDR_SHIFT 16 +#define VPD_CAP_VPD_FLAG 0x80000000 + +#define REG_VPD_DATA 0x70 + +#define REG_SPI_FLASH_CTRL 0x200 +#define SPI_FLASH_CTRL_STS_NON_RDY 0x1 +#define SPI_FLASH_CTRL_STS_WEN 0x2 +#define SPI_FLASH_CTRL_STS_WPEN 0x80 +#define SPI_FLASH_CTRL_DEV_STS_MASK 0xFF +#define SPI_FLASH_CTRL_DEV_STS_SHIFT 0 +#define SPI_FLASH_CTRL_INS_MASK 0x7 +#define SPI_FLASH_CTRL_INS_SHIFT 8 +#define SPI_FLASH_CTRL_START 0x800 +#define SPI_FLASH_CTRL_EN_VPD 0x2000 +#define SPI_FLASH_CTRL_LDSTART 0x8000 +#define SPI_FLASH_CTRL_CS_HI_MASK 0x3 +#define SPI_FLASH_CTRL_CS_HI_SHIFT 16 +#define SPI_FLASH_CTRL_CS_HOLD_MASK 0x3 +#define SPI_FLASH_CTRL_CS_HOLD_SHIFT 18 +#define SPI_FLASH_CTRL_CLK_LO_MASK 0x3 +#define SPI_FLASH_CTRL_CLK_LO_SHIFT 20 +#define SPI_FLASH_CTRL_CLK_HI_MASK 0x3 +#define SPI_FLASH_CTRL_CLK_HI_SHIFT 22 +#define SPI_FLASH_CTRL_CS_SETUP_MASK 0x3 +#define SPI_FLASH_CTRL_CS_SETUP_SHIFT 24 +#define SPI_FLASH_CTRL_EROM_PGSZ_MASK 0x3 +#define SPI_FLASH_CTRL_EROM_PGSZ_SHIFT 26 +#define SPI_FLASH_CTRL_WAIT_READY 0x10000000 + +#define REG_SPI_ADDR 0x204 + +#define REG_SPI_DATA 0x208 + +#define REG_SPI_FLASH_CONFIG 0x20C +#define SPI_FLASH_CONFIG_LD_ADDR_MASK 0xFFFFFF +#define SPI_FLASH_CONFIG_LD_ADDR_SHIFT 0 +#define SPI_FLASH_CONFIG_VPD_ADDR_MASK 0x3 +#define SPI_FLASH_CONFIG_VPD_ADDR_SHIFT 24 +#define SPI_FLASH_CONFIG_LD_EXIST 0x4000000 + +#define REG_SPI_FLASH_OP_PROGRAM 0x210 +#define REG_SPI_FLASH_OP_SC_ERASE 0x211 +#define REG_SPI_FLASH_OP_CHIP_ERASE 0x212 +#define REG_SPI_FLASH_OP_RDID 0x213 +#define REG_SPI_FLASH_OP_WREN 0x214 +#define REG_SPI_FLASH_OP_RDSR 0x215 +#define REG_SPI_FLASH_OP_WRSR 0x216 +#define REG_SPI_FLASH_OP_READ 0x217 + +#define REG_TWSI_CTRL 0x218 +#define TWSI_CTRL_LD_OFFSET_MASK 0xFF +#define TWSI_CTRL_LD_OFFSET_SHIFT 0 +#define TWSI_CTRL_LD_SLV_ADDR_MASK 0x7 +#define TWSI_CTRL_LD_SLV_ADDR_SHIFT 8 +#define TWSI_CTRL_SW_LDSTART 0x800 +#define TWSI_CTRL_HW_LDSTART 0x1000 +#define TWSI_CTRL_SMB_SLV_ADDR_MASK 0x0x7F +#define TWSI_CTRL_SMB_SLV_ADDR_SHIFT 15 +#define TWSI_CTRL_LD_EXIST 0x400000 +#define TWSI_CTRL_READ_FREQ_SEL_MASK 0x3 +#define TWSI_CTRL_READ_FREQ_SEL_SHIFT 23 +#define TWSI_CTRL_FREQ_SEL_100K 0 +#define TWSI_CTRL_FREQ_SEL_200K 1 +#define TWSI_CTRL_FREQ_SEL_300K 2 +#define TWSI_CTRL_FREQ_SEL_400K 3 +#define TWSI_CTRL_SMB_SLV_ADDR +#define TWSI_CTRL_WRITE_FREQ_SEL_MASK 0x3 +#define TWSI_CTRL_WRITE_FREQ_SEL_SHIFT 24 + +#define REG_PCIE_DEV_MISC_CTRL 0x21C +#define PCIE_DEV_MISC_CTRL_EXT_PIPE 0x2 +#define PCIE_DEV_MISC_CTRL_RETRY_BUFDIS 0x1 +#define PCIE_DEV_MISC_CTRL_SPIROM_EXIST 0x4 +#define PCIE_DEV_MISC_CTRL_SERDES_ENDIAN 0x8 +#define PCIE_DEV_MISC_CTRL_SERDES_SEL_DIN 0x10 + +#define REG_PCIE_PHYMISC 0x1000 +#define PCIE_PHYMISC_FORCE_RCV_DET 0x4 + +#define REG_PCIE_DLL_TX_CTRL1 0x1104 +#define PCIE_DLL_TX_CTRL1_SEL_NOR_CLK 0x0400 +#define PCIE_DLL_TX_CTRL1_DEF 0x0568 + +#define REG_LTSSM_TEST_MODE 0x12FC +#define LTSSM_TEST_MODE_DEF 0x6500 + +/* Master Control Register */ +#define REG_MASTER_CTRL 0x1400 +#define MASTER_CTRL_SOFT_RST 0x1 +#define MASTER_CTRL_MTIMER_EN 0x2 +#define MASTER_CTRL_ITIMER_EN 0x4 +#define MASTER_CTRL_MANUAL_INT 0x8 +#define MASTER_CTRL_REV_NUM_SHIFT 16 +#define MASTER_CTRL_REV_NUM_MASK 0xff +#define MASTER_CTRL_DEV_ID_SHIFT 24 +#define MASTER_CTRL_DEV_ID_MASK 0xff + +/* Timer Initial Value Register */ +#define REG_MANUAL_TIMER_INIT 0x1404 + +/* IRQ ModeratorTimer Initial Value Register */ +#define REG_IRQ_MODU_TIMER_INIT 0x1408 + +#define REG_PHY_ENABLE 0x140C +// IRQ Anti-Lost Timer Initial Value Register +//#define REG_IRQ_CLR_TIMER 0x140c // Maximum allowance for software to clear the interrupt. +// IRQ Anti-Lost Timer Initial Value Register +#define REG_CMBDISDMA_TIMER 0x140E + +/* Block IDLE Status Register */ +#define REG_IDLE_STATUS 0x1410 +#define IDLE_STATUS_RXMAC 1 /* 1: RXMAC state machine is in non-IDLE state. 0: RXMAC is idling */ +#define IDLE_STATUS_TXMAC 2 /* 1: TXMAC state machine is in non-IDLE state. 0: TXMAC is idling */ +#define IDLE_STATUS_DMAR 8 /* 1: DMAR state machine is in non-IDLE state. 0: DMAR is idling */ +#define IDLE_STATUS_DMAW 4 /* 1: DMAW state machine is in non-IDLE state. 0: DMAW is idling */ + +/* MDIO Control Register */ +#define REG_MDIO_CTRL 0x1414 +#define MDIO_DATA_MASK 0xffff /* On MDIO write, the 16-bit control data to write to PHY MII management register */ +#define MDIO_DATA_SHIFT 0 /* On MDIO read, the 16-bit status data that was read from the PHY MII management register. */ +#define MDIO_REG_ADDR_MASK 0x1f /* MDIO register address */ +#define MDIO_REG_ADDR_SHIFT 16 +#define MDIO_RW 0x200000 /* 1: read, 0: write */ +#define MDIO_SUP_PREAMBLE 0x400000 /* Suppress preamble */ +#define MDIO_START 0x800000 /* Write 1 to initiate the MDIO master. And this bit is self cleared after one cycle. */ +#define MDIO_CLK_SEL_SHIFT 24 +#define MDIO_CLK_25_4 0 +#define MDIO_CLK_25_6 2 +#define MDIO_CLK_25_8 3 +#define MDIO_CLK_25_10 4 +#define MDIO_CLK_25_14 5 +#define MDIO_CLK_25_20 6 +#define MDIO_CLK_25_28 7 +#define MDIO_BUSY 0x8000000 +#define MDIO_WAIT_TIMES 10 + +/* SerDes Lock Detect Control and Status Register */ +#define REG_SERDES_LOCK 0x1424 +#define SERDES_LOCK_DETECT 1 /* 1: SerDes lock detected. This signal comes from Analog SerDes. */ +#define SERDES_LOCK_DETECT_EN 2 /* 1: Enable SerDes Lock detect function. */ + +/* MAC Control Register */ +#define REG_MAC_CTRL 0x1480 +#define MAC_CTRL_TX_EN 1 /* 1: Transmit Enable */ +#define MAC_CTRL_RX_EN 2 /* 1: Receive Enable */ +#define MAC_CTRL_TX_FLOW 4 /* 1: Transmit Flow Control Enable */ +#define MAC_CTRL_RX_FLOW 8 /* 1: Receive Flow Control Enable */ +#define MAC_CTRL_LOOPBACK 0x10 /* 1: Loop back at G/MII Interface */ +#define MAC_CTRL_DUPLX 0x20 /* 1: Full-duplex mode 0: Half-duplex mode */ +#define MAC_CTRL_ADD_CRC 0x40 /* 1: Instruct MAC to attach CRC on all egress Ethernet frames */ +#define MAC_CTRL_PAD 0x80 /* 1: Instruct MAC to pad short frames to 60-bytes, and then attach CRC. This bit has higher priority over CRC_EN */ +#define MAC_CTRL_PRMLEN_SHIFT 10 /* Preamble length, it's 0x07 by standard */ +#define MAC_CTRL_PRMLEN_MASK 0xf +#define MAC_CTRL_RMV_VLAN 0x4000 /* 1: to remove VLAN Tag automatically from all receive packets */ +#define MAC_CTRL_PROMIS_EN 0x8000 /* 1: Promiscuous Mode Enable */ +#define MAC_CTRL_DBG_TX_BKPRESURE 0x100000 /* 1: transmit maximum backoff (half-duplex test bit) */ +#define MAC_CTRL_MC_ALL_EN 0x2000000 /* 1: upload all multicast frame without error to system */ +#define MAC_CTRL_BC_EN 0x4000000 /* 1: upload all broadcast frame without error to system */ +#define MAC_CTRL_MACLP_CLK_PHY 0x8000000 /* 1: MAC-LoopBack clock from phy, 0:from sys_25M */ +#define MAC_CTRL_HALF_LEFT_BUF_SHIFT 28 +#define MAC_CTRL_HALF_LEFT_BUF_MASK 0xF /* When half-duplex mode, should hold some bytes for mac retry . (8*4bytes unit) */ + +/* MAC IPG/IFG Control Register */ +#define REG_MAC_IPG_IFG 0x1484 +#define MAC_IPG_IFG_IPGT_SHIFT 0 /* Desired back to back inter-packet gap. The default is 96-bit time. */ +#define MAC_IPG_IFG_IPGT_MASK 0x7f +#define MAC_IPG_IFG_MIFG_SHIFT 8 /* Minimum number of IFG to enforce in between RX frames. */ +#define MAC_IPG_IFG_MIFG_MASK 0xff /* Frame gap below such IFP is dropped. */ +#define MAC_IPG_IFG_IPGR1_SHIFT 16 /* 64bit Carrier-Sense window */ +#define MAC_IPG_IFG_IPGR1_MASK 0x7f +#define MAC_IPG_IFG_IPGR2_SHIFT 24 /* 96-bit IPG window */ +#define MAC_IPG_IFG_IPGR2_MASK 0x7f + +/* MAC STATION ADDRESS */ +#define REG_MAC_STA_ADDR 0x1488 + +/* Hash table for multicast address */ +#define REG_RX_HASH_TABLE 0x1490 + +/* MAC Half-Duplex Control Register */ +#define REG_MAC_HALF_DUPLX_CTRL 0x1498 +#define MAC_HALF_DUPLX_CTRL_LCOL_SHIFT 0 /* Collision Window. */ +#define MAC_HALF_DUPLX_CTRL_LCOL_MASK 0x3ff +#define MAC_HALF_DUPLX_CTRL_RETRY_SHIFT 12 /* Retransmission maximum, afterwards the packet will be discarded. */ +#define MAC_HALF_DUPLX_CTRL_RETRY_MASK 0xf +#define MAC_HALF_DUPLX_CTRL_EXC_DEF_EN 0x10000 /* 1: Allow the transmission of a packet which has been excessively deferred */ +#define MAC_HALF_DUPLX_CTRL_NO_BACK_C 0x20000 /* 1: No back-off on collision, immediately start the retransmission. */ +#define MAC_HALF_DUPLX_CTRL_NO_BACK_P 0x40000 /* 1: No back-off on backpressure, immediately start the transmission after back pressure */ +#define MAC_HALF_DUPLX_CTRL_ABEBE 0x80000 /* 1: Alternative Binary Exponential Back-off Enabled */ +#define MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT 20 /* Maximum binary exponential number. */ +#define MAC_HALF_DUPLX_CTRL_ABEBT_MASK 0xf +#define MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT 24 /* IPG to start JAM for collision based flow control in half-duplex */ +#define MAC_HALF_DUPLX_CTRL_JAMIPG_MASK 0xf /* mode. In unit of 8-bit time. */ + +/* Maximum Frame Length Control Register */ +#define REG_MTU 0x149c + +/* Wake-On-Lan control register */ +#define REG_WOL_CTRL 0x14a0 +#define WOL_PATTERN_EN 0x00000001 +#define WOL_PATTERN_PME_EN 0x00000002 +#define WOL_MAGIC_EN 0x00000004 +#define WOL_MAGIC_PME_EN 0x00000008 +#define WOL_LINK_CHG_EN 0x00000010 +#define WOL_LINK_CHG_PME_EN 0x00000020 +#define WOL_PATTERN_ST 0x00000100 +#define WOL_MAGIC_ST 0x00000200 +#define WOL_LINKCHG_ST 0x00000400 +#define WOL_PT0_EN 0x00010000 +#define WOL_PT1_EN 0x00020000 +#define WOL_PT2_EN 0x00040000 +#define WOL_PT3_EN 0x00080000 +#define WOL_PT4_EN 0x00100000 +#define WOL_PT0_MATCH 0x01000000 +#define WOL_PT1_MATCH 0x02000000 +#define WOL_PT2_MATCH 0x04000000 +#define WOL_PT3_MATCH 0x08000000 +#define WOL_PT4_MATCH 0x10000000 + +/* Internal SRAM Partition Register */ +#define REG_SRAM_TXRAM_END 0x1500 /* Internal tail address of TXRAM default: 2byte*1024 */ +#define REG_SRAM_RXRAM_END 0x1502 /* Internal tail address of RXRAM default: 2byte*1024 */ + +/* +#define REG_SRAM_TCPH_PATH_ADDR (REG_SRAM_RFD_ADDR+48) +#define SRAM_TCPH_ADDR_MASK 0x0fff +#define SRAM_TCPH_ADDR_SHIFT 0 +#define SRAM_PATH_ADDR_MASK 0x0fff +#define SRAM_PATH_ADDR_SHIFT 16 +*/ + +/* Descriptor Control register */ +#define REG_DESC_BASE_ADDR_HI 0x1540 +#define REG_TXD_BASE_ADDR_LO 0x1544 /* The base address of the Transmit Data Memory low 32-bit(dword align) */ +#define REG_TXD_MEM_SIZE 0x1548 /* Transmit Data Memory size(by double word , max 256KB) */ +#define REG_TXS_BASE_ADDR_LO 0x154C /* The base address of the Transmit Status Memory low 32-bit(dword word align) */ +#define REG_TXS_MEM_SIZE 0x1550 /* double word unit, max 4*2047 bytes. */ +#define REG_RXD_BASE_ADDR_LO 0x1554 /* The base address of the Transmit Status Memory low 32-bit(unit 8 bytes) */ +#define REG_RXD_BUF_NUM 0x1558 /* Receive Data & Status Memory buffer number (unit 1536bytes, max 1536*2047) */ + +/* DMAR Control Register */ +#define REG_DMAR 0x1580 +#define DMAR_EN 0x1 /* 1: Enable DMAR */ + +/* TX Cur-Through (early tx threshold) Control Register */ +#define REG_TX_CUT_THRESH 0x1590 /* TxMac begin transmit packet threshold(unit word) */ + +/* DMAW Control Register */ +#define REG_DMAW 0x15A0 +#define DMAW_EN 0x1 + +/* Flow control register */ +#define REG_PAUSE_ON_TH 0x15A8 /* RXD high watermark of overflow threshold configuration register */ +#define REG_PAUSE_OFF_TH 0x15AA /* RXD lower watermark of overflow threshold configuration register */ + +/* Mailbox Register */ +#define REG_MB_TXD_WR_IDX 0x15f0 /* double word align */ +#define REG_MB_RXD_RD_IDX 0x15F4 /* RXD Read index (unit: 1536byets) */ + +/* Interrupt Status Register */ +#define REG_ISR 0x1600 +#define ISR_TIMER 1 /* Interrupt when Timer is counted down to zero */ +#define ISR_MANUAL 2 /* Software manual interrupt, for debug. Set when SW_MAN_INT_EN is set in Table 51 Selene Master Control Register (Offset 0x1400). */ +#define ISR_RXF_OV 4 /* RXF overflow interrupt */ +#define ISR_TXF_UR 8 /* TXF underrun interrupt */ +#define ISR_TXS_OV 0x10 /* Internal transmit status buffer full interrupt */ +#define ISR_RXS_OV 0x20 /* Internal receive status buffer ful interrupt */ +#define ISR_LINK_CHG 0x40 /* Link Status Change Interrupt */ +#define ISR_HOST_TXD_UR 0x80 +#define ISR_HOST_RXD_OV 0x100 /* Host rx data memory full , one pulse */ +//#define ISR_HOST_TXS_OV 0x200 /* Host tx status memory full , one pulse */ +#define ISR_DMAR_TO_RST 0x200 /* DMAR op timeout interrupt. SW should do Reset */ +#define ISR_DMAW_TO_RST 0x400 +#define ISR_PHY 0x800 /* phy interrupt */ +#define ISR_TS_UPDATE 0x10000 /* interrupt after new tx pkt status written to host */ +#define ISR_RS_UPDATE 0x20000 /* interrupt ater new rx pkt status written to host. */ +#define ISR_TX_EARLY 0x40000 /* interrupt when txmac begin transmit one packet */ +#define ISR_UR_DETECTED 0x1000000 +#define ISR_FERR_DETECTED 0x2000000 +#define ISR_NFERR_DETECTED 0x4000000 +#define ISR_CERR_DETECTED 0x8000000 +#define ISR_PHY_LINKDOWN 0x10000000 +#define ISR_DIS_INT 0x80000000 + +#define ISR_TX_EVENT (ISR_TXF_UR|ISR_TXS_OV|ISR_HOST_TXD_UR|ISR_TS_UPDATE|ISR_TX_EARLY) +#define ISR_RX_EVENT (ISR_RXF_OV|ISR_RXS_OV|ISR_HOST_RXD_OV|ISR_RS_UPDATE) + +/* Interrupt Mask Register */ +#define REG_IMR 0x1604 + +#define IMR_NORMAL_MASK (\ + /*ISR_LINK_CHG |*/\ + ISR_MANUAL |\ + ISR_DMAR_TO_RST |\ + ISR_DMAW_TO_RST |\ + ISR_PHY |\ + ISR_PHY_LINKDOWN |\ + ISR_TS_UPDATE |\ + ISR_RS_UPDATE ) + +/* Receive MAC Statistics Registers */ +#define REG_STS_RX_PAUSE 0x1700 /* The number of Pause packet received */ +#define REG_STS_RXD_OV 0x1704 /* The number of frame dropped due to occurrence of RX FIFO overflow */ +#define REG_STS_RXS_OV 0x1708 /* The number of frame dropped due to occerrence of RX Status Buffer Overflow */ +#define REG_STS_RX_FILTER 0x170C /* The number of packet dropped due to address filtering */ + +/* MII definitions */ + +/* PHY Common Register */ +#define MII_AT001_CR 0x09 +#define MII_AT001_SR 0x0A +#define MII_AT001_ESR 0x0F +#define MII_AT001_PSCR 0x10 +#define MII_AT001_PSSR 0x11 +#define MII_SMARTSPEED 0x14 +#define MII_DBG_ADDR 0x1D +#define MII_DBG_DATA 0x1E + +/* PHY Control Register */ +#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ +#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ +#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ +#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ +#define MII_CR_POWER_DOWN 0x0800 /* Power down */ +#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ +#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ +#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ +#define MII_CR_SPEED_MASK 0x2040 +#define MII_CR_SPEED_1000 0x0040 +#define MII_CR_SPEED_100 0x2000 +#define MII_CR_SPEED_10 0x0000 + +/* PHY Status Register */ +#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ +#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ +#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ +#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ +#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ +#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ +#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ +#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ +#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ +#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ +#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ +#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ +#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ +#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ +#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ + +/* Link partner ability register. */ +#define MII_LPA_SLCT 0x001f /* Same as advertise selector */ +#define MII_LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */ +#define MII_LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */ +#define MII_LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */ +#define MII_LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */ +#define MII_LPA_100BASE4 0x0200 /* 100BASE-T4 */ +#define MII_LPA_PAUSE 0x0400 /* PAUSE */ +#define MII_LPA_ASYPAUSE 0x0800 /* Asymmetrical PAUSE */ +#define MII_LPA_RFAULT 0x2000 /* Link partner faulted */ +#define MII_LPA_LPACK 0x4000 /* Link partner acked us */ +#define MII_LPA_NPAGE 0x8000 /* Next page bit */ + +/* Autoneg Advertisement Register */ +#define MII_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */ +#define MII_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ +#define MII_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ +#define MII_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ +#define MII_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ +#define MII_AR_100T4_CAPS 0x0200 /* 100T4 Capable */ +#define MII_AR_PAUSE 0x0400 /* Pause operation desired */ +#define MII_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ +#define MII_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */ +#define MII_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */ +#define MII_AR_SPEED_MASK 0x01E0 +#define MII_AR_DEFAULT_CAP_MASK 0x0DE0 + +/* 1000BASE-T Control Register */ +#define MII_AT001_CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ +#define MII_AT001_CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ +#define MII_AT001_CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port, 0=DTE device */ +#define MII_AT001_CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master, 0=Configure PHY as Slave */ +#define MII_AT001_CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value, 0=Automatic Master/Slave config */ +#define MII_AT001_CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ +#define MII_AT001_CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */ +#define MII_AT001_CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */ +#define MII_AT001_CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */ +#define MII_AT001_CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */ +#define MII_AT001_CR_1000T_SPEED_MASK 0x0300 +#define MII_AT001_CR_1000T_DEFAULT_CAP_MASK 0x0300 + +/* 1000BASE-T Status Register */ +#define MII_AT001_SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */ +#define MII_AT001_SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */ +#define MII_AT001_SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ +#define MII_AT001_SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ +#define MII_AT001_SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */ +#define MII_AT001_SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */ +#define MII_AT001_SR_1000T_REMOTE_RX_STATUS_SHIFT 12 +#define MII_AT001_SR_1000T_LOCAL_RX_STATUS_SHIFT 13 + +/* Extended Status Register */ +#define MII_AT001_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */ +#define MII_AT001_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */ +#define MII_AT001_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */ +#define MII_AT001_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */ + +/* AT001 PHY Specific Control Register */ +#define MII_AT001_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ +#define MII_AT001_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */ +#define MII_AT001_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled *// +#define MII_AT001_PSCR_MAC_POWERDOWN 0x0008 +#define MII_AT001_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low, 0=CLK125 toggling */ +#define MII_AT001_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5, Manual MDI configuration */ +#define MII_AT001_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ +#define MII_AT001_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */ +#define MII_AT001_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled all speeds. */ +#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE 0x0080 /* 1=Enable Extended 10BASE-T distance (Lower 10BASE-T RX Threshold), 0=Normal 10BASE-T RX Threshold */ +#define MII_AT001_PSCR_MII_5BIT_ENABLE 0x0100 /* 1=5-Bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */ +#define MII_AT001_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */ +#define MII_AT001_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */ +#define MII_AT001_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */ +#define MII_AT001_PSCR_POLARITY_REVERSAL_SHIFT 1 +#define MII_AT001_PSCR_AUTO_X_MODE_SHIFT 5 +#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7 + +/* AT001 PHY Specific Status Register */ +#define MII_AT001_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */ +#define MII_AT001_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */ +#define MII_AT001_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ +#define MII_AT001_PSSR_10MBS 0x0000 /* 00=10Mbs */ +#define MII_AT001_PSSR_100MBS 0x4000 /* 01=100Mbs */ +#define MII_AT001_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ + +/* PCI Command Register Bit Definitions */ +#define PCI_REG_COMMAND 0x04 +#define CMD_IO_SPACE 0x0001 +#define CMD_MEMORY_SPACE 0x0002 +#define CMD_BUS_MASTER 0x0004 + +/* Wake Up Filter Control */ +#define ATL2_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ +#define ATL2_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ +#define ATL2_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ +#define ATL2_WUFC_MC 0x00000008 /* Multicast Wakeup Enable */ +#define ATL2_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ + +/* Error Codes */ +#define ATL2_SUCCESS 0 +#define ATL2_ERR_EEPROM 1 +#define ATL2_ERR_PHY 2 +#define ATL2_ERR_CONFIG 3 +#define ATL2_ERR_PARAM 4 +#define ATL2_ERR_MAC_TYPE 5 +#define ATL2_ERR_PHY_TYPE 6 +#define ATL2_ERR_PHY_SPEED 7 +#define ATL2_ERR_PHY_RES 8 + +#define SPEED_0 0xffff +#define SPEED_10 10 +#define SPEED_100 100 +#define HALF_DUPLEX 1 +#define FULL_DUPLEX 2 + +#define MEDIA_TYPE_AUTO_SENSOR 0 +#define MEDIA_TYPE_100M_FULL 1 +#define MEDIA_TYPE_100M_HALF 2 +#define MEDIA_TYPE_10M_FULL 3 +#define MEDIA_TYPE_10M_HALF 4 + +#define ADVERTISE_10_HALF 0x0001 +#define ADVERTISE_10_FULL 0x0002 +#define ADVERTISE_100_HALF 0x0004 +#define ADVERTISE_100_FULL 0x0008 +#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */ +#define ADVERTISE_1000_FULL 0x0020 + +#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x000F /* Everything */ +#define AUTONEG_ADVERTISE_10_100_ALL 0x000F /* All 10/100 speeds*/ +#define AUTONEG_ADVERTISE_10_ALL 0x0003 /* 10Mbps Full & Half speeds*/ + +/* The size (in bytes) of a ethernet packet */ +#define ENET_HEADER_SIZE 14 +#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* with FCS */ +#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* with FCS */ +#define ETHERNET_FCS_SIZE 4 +#define MAX_JUMBO_FRAME_SIZE 0x2000 +#define VLAN_SIZE 4 + +#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */ +#define PHY_FORCE_TIME 20 /* 2.0 Seconds */ + +/* For checksumming , the sum of all words in the EEPROM should equal 0xBABA */ +#define EEPROM_SUM 0xBABA +#define NODE_ADDRESS_SIZE 6 + +typedef struct _tx_pkt_header { + unsigned pkt_size : 11; + unsigned : 4; // reserved + unsigned ins_vlan : 1; // txmac should insert vlan + unsigned short vlan ; // vlan tag +} tx_pkt_header_t; +/* FIXME: replace above bitfields with MASK/SHIFT defines below */ +#define TX_PKT_HEADER_SIZE_MASK 0x7FF +#define TX_PKT_HEADER_SIZE_SHIFT 0 +#define TX_PKT_HEADER_INS_VLAN_MASK 0x1 +#define TX_PKT_HEADER_INS_VLAN_SHIFT 15 +#define TX_PKT_HEADER_VLAN_TAG_MASK 0xFFFF +#define TX_PKT_HEADER_VLAN_TAG_SHIFT 16 + +typedef struct _tx_pkt_status { + unsigned pkt_size : 11; + unsigned : 5; // reserved + unsigned ok : 1; // current packet is transmitted ok without error + unsigned bcast : 1; // current packet is broadcast + unsigned mcast : 1; // current packet is multicast + unsigned pause : 1; // transmiited a pause frame + unsigned ctrl : 1; + unsigned defer : 1; // current packet is xmitted with defer. + unsigned exc_defer : 1; + unsigned single_col : 1; + unsigned multi_col : 1; + unsigned late_col : 1; + unsigned abort_col : 1; + unsigned underun : 1; // current packet is abort due to txram underrun. + unsigned : 3; // reserved + unsigned update : 1; // always 1'b1 in tx_status_buf. +} tx_pkt_status_t; +/* FIXME: replace above bitfields with MASK/SHIFT defines below */ +#define TX_PKT_STATUS_SIZE_MASK 0x7FF +#define TX_PKT_STATUS_SIZE_SHIFT 0 +#define TX_PKT_STATUS_OK_MASK 0x1 +#define TX_PKT_STATUS_OK_SHIFT 16 +#define TX_PKT_STATUS_BCAST_MASK 0x1 +#define TX_PKT_STATUS_BCAST_SHIFT 17 +#define TX_PKT_STATUS_MCAST_MASK 0x1 +#define TX_PKT_STATUS_MCAST_SHIFT 18 +#define TX_PKT_STATUS_PAUSE_MASK 0x1 +#define TX_PKT_STATUS_PAUSE_SHIFT 19 +#define TX_PKT_STATUS_CTRL_MASK 0x1 +#define TX_PKT_STATUS_CTRL_SHIFT 20 +#define TX_PKT_STATUS_DEFER_MASK 0x1 +#define TX_PKT_STATUS_DEFER_SHIFT 21 +#define TX_PKT_STATUS_EXC_DEFER_MASK 0x1 +#define TX_PKT_STATUS_EXC_DEFER_SHIFT 22 +#define TX_PKT_STATUS_SINGLE_COL_MASK 0x1 +#define TX_PKT_STATUS_SINGLE_COL_SHIFT 23 +#define TX_PKT_STATUS_MULTI_COL_MASK 0x1 +#define TX_PKT_STATUS_MULTI_COL_SHIFT 24 +#define TX_PKT_STATUS_LATE_COL_MASK 0x1 +#define TX_PKT_STATUS_LATE_COL_SHIFT 25 +#define TX_PKT_STATUS_ABORT_COL_MASK 0x1 +#define TX_PKT_STATUS_ABORT_COL_SHIFT 26 +#define TX_PKT_STATUS_UNDERRUN_MASK 0x1 +#define TX_PKT_STATUS_UNDERRUN_SHIFT 27 +#define TX_PKT_STATUS_UPDATE_MASK 0x1 +#define TX_PKT_STATUS_UPDATE_SHIFT 31 + +typedef struct _rx_pkt_status { + unsigned pkt_size : 11; // packet size, max 2047bytes + unsigned : 5; // reserved + unsigned ok : 1; // current packet is received ok without error. + unsigned bcast : 1; // current packet is broadcast. + unsigned mcast : 1; // current packet is multicast. + unsigned pause : 1; + unsigned ctrl : 1; + unsigned crc : 1; // received a packet with crc error. + unsigned code : 1; // received a packet with code error. + unsigned runt : 1; // received a packet less than 64bytes with good crc + unsigned frag : 1; // ....................................with bad crc + unsigned trunc : 1; // current frame is cutted due to rxram full. + unsigned align : 1; // this packet is alignment error. + unsigned vlan : 1; // this packet has vlan + unsigned : 3; // reserved + unsigned update : 1; + unsigned short vtag ; // vlan tag + unsigned : 16; +} rx_pkt_status_t; +/* FIXME: replace above bitfields with MASK/SHIFT defines below */ +#define RX_PKT_STATUS_SIZE_MASK 0x7FF +#define RX_PKT_STATUS_SIZE_SHIFT 0 +#define RX_PKT_STATUS_OK_MASK 0x1 +#define RX_PKT_STATUS_OK_SHIFT 16 +#define RX_PKT_STATUS_BCAST_MASK 0x1 +#define RX_PKT_STATUS_BCAST_SHIFT 17 +#define RX_PKT_STATUS_MCAST_MASK 0x1 +#define RX_PKT_STATUS_MCAST_SHIFT 18 +#define RX_PKT_STATUS_PAUSE_MASK 0x1 +#define RX_PKT_STATUS_PAUSE_SHIFT 19 +#define RX_PKT_STATUS_CTRL_MASK 0x1 +#define RX_PKT_STATUS_CTRL_SHIFT 20 +#define RX_PKT_STATUS_CRC_MASK 0x1 +#define RX_PKT_STATUS_CRC_SHIFT 21 +#define RX_PKT_STATUS_CODE_MASK 0x1 +#define RX_PKT_STATUS_CODE_SHIFT 22 +#define RX_PKT_STATUS_RUNT_MASK 0x1 +#define RX_PKT_STATUS_RUNT_SHIFT 23 +#define RX_PKT_STATUS_FRAG_MASK 0x1 +#define RX_PKT_STATUS_FRAG_SHIFT 24 +#define RX_PKT_STATUS_TRUNK_MASK 0x1 +#define RX_PKT_STATUS_TRUNK_SHIFT 25 +#define RX_PKT_STATUS_ALIGN_MASK 0x1 +#define RX_PKT_STATUS_ALIGN_SHIFT 26 +#define RX_PKT_STATUS_VLAN_MASK 0x1 +#define RX_PKT_STATUS_VLAN_SHIFT 27 +#define RX_PKT_STATUS_UPDATE_MASK 0x1 +#define RX_PKT_STATUS_UPDATE_SHIFT 31 +#define RX_PKT_STATUS_VLAN_TAG_MASK 0xFFFF +#define RX_PKT_STATUS_VLAN_TAG_SHIFT 32 + +typedef struct _rx_desc { + rx_pkt_status_t status; + unsigned char packet[1536-sizeof(rx_pkt_status_t)]; +} rx_desc_t; + +typedef enum { + atl2_10_half = 0, + atl2_10_full = 1, + atl2_100_half = 2, + atl2_100_full = 3 +} atl2_speed_duplex_type; + +struct atl2_spi_flash_dev { + const char *manu_name; /* manufacturer id */ + /* op-code */ + u8 cmdWRSR; + u8 cmdREAD; + u8 cmdPROGRAM; + u8 cmdWREN; + u8 cmdWRDI; + u8 cmdRDSR; + u8 cmdRDID; + u8 cmdSECTOR_ERASE; + u8 cmdCHIP_ERASE; +}; + +/* Structure containing variables used by the shared code (atl2_hw.c) */ +struct atl2_hw { + u8 *hw_addr; + void *back; + + u8 preamble_len; + u8 max_retry; // Retransmission maximum , afterwards the packet will be discarded. + u8 jam_ipg; // IPG to start JAM for collision based flow control in half-duplex mode. In unit of 8-bit time. + u8 ipgt; // Desired back to back inter-packet gap. The default is 96-bit time. + u8 min_ifg; // Minimum number of IFG to enforce in between RX frames. Frame gap below such IFP is dropped. + u8 ipgr1; // 64bit Carrier-Sense window + u8 ipgr2; // 96-bit IPG window + u8 retry_buf; // When half-duplex mode, should hold some bytes for mac retry . (8*4bytes unit) + + u16 fc_rxd_hi; + u16 fc_rxd_lo; + u16 lcol; // Collision Window + u16 max_frame_size; + + u16 MediaType; + u16 autoneg_advertised; + u16 pci_cmd_word; + + u16 mii_autoneg_adv_reg; + + u32 mem_rang; + u32 txcw; + u32 mc_filter_type; + u32 num_mc_addrs; + u32 collision_delta; + u32 tx_packet_delta; + u16 phy_spd_default; + + u16 device_id; + u16 vendor_id; + u16 subsystem_id; + u16 subsystem_vendor_id; + u8 revision_id; + + // spi flash + u8 flash_vendor; + + u8 dma_fairness; + u8 mac_addr[NODE_ADDRESS_SIZE]; + u8 perm_mac_addr[NODE_ADDRESS_SIZE]; + + // bool phy_preamble_sup; + bool phy_configured; +}; + +#endif /* _ATL2_HW_H_ */ --- linux-2.6.27.orig/ubuntu/atl2/BOM +++ linux-2.6.27/ubuntu/atl2/BOM @@ -0,0 +1,2 @@ +Downloaded from: http://people.redhat.com/csnook/atl2/ +Current Version: 2.0.4 --- linux-2.6.27.orig/ubuntu/iscsitarget/digest.h +++ linux-2.6.27/ubuntu/iscsitarget/digest.h @@ -0,0 +1,20 @@ +/* + * iSCSI digest handling. + * (C) 2004 Xiranet Communications GmbH + * This code is licensed under the GPL. + */ + +#ifndef __IET_DIGEST_H__ +#define __IET_DIGEST_H__ + +extern void digest_alg_available(unsigned int *val); +extern int digest_init(struct iscsi_conn *conn); +extern void digest_cleanup(struct iscsi_conn *conn); + +extern int digest_rx_header(struct iscsi_cmnd *cmnd); +extern int digest_rx_data(struct iscsi_cmnd *cmnd); + +extern void digest_tx_header(struct iscsi_cmnd *cmnd); +extern void digest_tx_data(struct iscsi_cmnd *cmnd); + +#endif /* __IET_DIGEST_H__ */ --- linux-2.6.27.orig/ubuntu/iscsitarget/conn.c +++ linux-2.6.27/ubuntu/iscsitarget/conn.c @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2002-2003 Ardis Technolgies + * + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include + +#include "iscsi.h" +#include "iscsi_dbg.h" +#include "digest.h" + +static void print_conn_state(char *p, size_t size, unsigned long state) +{ + if (test_bit(CONN_ACTIVE, &state)) + snprintf(p, size, "%s", "active"); + else if (test_bit(CONN_CLOSING, &state)) + snprintf(p, size, "%s", "closing"); + else + snprintf(p, size, "%s", "unknown"); +} + +static void print_digest_state(char *p, size_t size, unsigned long flags) +{ + if (DIGEST_NONE & flags) + snprintf(p, size, "%s", "none"); + else if (DIGEST_CRC32C & flags) + snprintf(p, size, "%s", "crc32c"); + else + snprintf(p, size, "%s", "unknown"); +} + +void conn_info_show(struct seq_file *seq, struct iscsi_session *session) +{ + struct iscsi_conn *conn; + struct sock *sk; + char buf[64]; + + list_for_each_entry(conn, &session->conn_list, list) { + sk = conn->sock->sk; + switch (sk->sk_family) { + case AF_INET: + snprintf(buf, sizeof(buf), + "%u.%u.%u.%u", NIPQUAD(inet_sk(sk)->daddr)); + break; + case AF_INET6: + snprintf(buf, sizeof(buf), + "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]", + NIP6(inet6_sk(sk)->daddr)); + break; + default: + break; + } + seq_printf(seq, "\t\tcid:%u ip:%s ", conn->cid, buf); + print_conn_state(buf, sizeof(buf), conn->state); + seq_printf(seq, "state:%s ", buf); + print_digest_state(buf, sizeof(buf), conn->hdigest_type); + seq_printf(seq, "hd:%s ", buf); + print_digest_state(buf, sizeof(buf), conn->ddigest_type); + seq_printf(seq, "dd:%s\n", buf); + } +} + +struct iscsi_conn *conn_lookup(struct iscsi_session *session, u16 cid) +{ + struct iscsi_conn *conn; + + list_for_each_entry(conn, &session->conn_list, list) { + if (conn->cid == cid) + return conn; + } + return NULL; +} + +static void iet_state_change(struct sock *sk) +{ + struct iscsi_conn *conn = sk->sk_user_data; + struct iscsi_target *target = conn->session->target; + + if (sk->sk_state != TCP_ESTABLISHED) + conn_close(conn); + else + nthread_wakeup(target); + + target->nthread_info.old_state_change(sk); +} + +static void iet_data_ready(struct sock *sk, int len) +{ + struct iscsi_conn *conn = sk->sk_user_data; + struct iscsi_target *target = conn->session->target; + + nthread_wakeup(target); + target->nthread_info.old_data_ready(sk, len); +} + +static void iet_socket_bind(struct iscsi_conn *conn) +{ + int opt = 1; + mm_segment_t oldfs; + struct iscsi_session *session = conn->session; + struct iscsi_target *target = session->target; + + dprintk(D_GENERIC, "%llu\n", (unsigned long long) session->sid); + + conn->sock = SOCKET_I(conn->file->f_dentry->d_inode); + conn->sock->sk->sk_user_data = conn; + + write_lock_bh(&conn->sock->sk->sk_callback_lock); + target->nthread_info.old_state_change = conn->sock->sk->sk_state_change; + conn->sock->sk->sk_state_change = iet_state_change; + + target->nthread_info.old_data_ready = conn->sock->sk->sk_data_ready; + conn->sock->sk->sk_data_ready = iet_data_ready; + write_unlock_bh(&conn->sock->sk->sk_callback_lock); + + oldfs = get_fs(); + set_fs(get_ds()); + conn->sock->ops->setsockopt(conn->sock, SOL_TCP, TCP_NODELAY, (void *)&opt, sizeof(opt)); + set_fs(oldfs); +} + +int conn_free(struct iscsi_conn *conn) +{ + dprintk(D_GENERIC, "%p %#Lx %u\n", conn->session, + (unsigned long long) conn->session->sid, conn->cid); + + assert(atomic_read(&conn->nr_cmnds) == 0); + assert(list_empty(&conn->pdu_list)); + assert(list_empty(&conn->write_list)); + + list_del(&conn->list); + list_del(&conn->poll_list); + + digest_cleanup(conn); + kfree(conn); + + return 0; +} + +static int iet_conn_alloc(struct iscsi_session *session, struct conn_info *info) +{ + struct iscsi_conn *conn; + + dprintk(D_SETUP, "%#Lx:%u\n", (unsigned long long) session->sid, info->cid); + + conn = kzalloc(sizeof(*conn), GFP_KERNEL); + if (!conn) + return -ENOMEM; + + conn->session = session; + conn->cid = info->cid; + conn->stat_sn = info->stat_sn; + conn->exp_stat_sn = info->exp_stat_sn; + + conn->hdigest_type = info->header_digest; + conn->ddigest_type = info->data_digest; + if (digest_init(conn) < 0) { + kfree(conn); + return -ENOMEM; + } + + spin_lock_init(&conn->list_lock); + atomic_set(&conn->nr_cmnds, 0); + atomic_set(&conn->nr_busy_cmnds, 0); + INIT_LIST_HEAD(&conn->pdu_list); + INIT_LIST_HEAD(&conn->write_list); + INIT_LIST_HEAD(&conn->poll_list); + + list_add(&conn->list, &session->conn_list); + + set_bit(CONN_ACTIVE, &conn->state); + + conn->file = fget(info->fd); + iet_socket_bind(conn); + + list_add(&conn->poll_list, &session->target->nthread_info.active_conns); + + nthread_wakeup(conn->session->target); + + return 0; +} + +void conn_close(struct iscsi_conn *conn) +{ + if (test_and_clear_bit(CONN_ACTIVE, &conn->state)) + set_bit(CONN_CLOSING, &conn->state); + + nthread_wakeup(conn->session->target); +} + +int conn_add(struct iscsi_session *session, struct conn_info *info) +{ + struct iscsi_conn *conn; + int err = -EEXIST; + + conn = conn_lookup(session, info->cid); + if (conn) + return err; + + return iet_conn_alloc(session, info); +} + +int conn_del(struct iscsi_session *session, struct conn_info *info) +{ + struct iscsi_conn *conn; + int err = -EEXIST; + + conn = conn_lookup(session, info->cid); + if (!conn) + return err; + + conn_close(conn); + + return 0; +} --- linux-2.6.27.orig/ubuntu/iscsitarget/param.c +++ linux-2.6.27/ubuntu/iscsitarget/param.c @@ -0,0 +1,194 @@ +/* + * (C) 2005 FUJITA Tomonori + * + * This code is licenced under the GPL. + */ + +#include "iscsi.h" +#include "iscsi_dbg.h" +#include "digest.h" + +struct target_type *target_type_array[] = { + &disk_ops, +}; + +#define CHECK_PARAM(info, iparam, word, min, max) \ +do { \ + if (!info->partial || (info->partial & 1 << key_##word)) \ + if (iparam[key_##word] < min || \ + iparam[key_##word] > max) { \ + eprintk("%s: %u is out of range (%u %u)\n", \ + #word, iparam[key_##word], min, max); \ + iparam[key_##word] = min; \ + } \ +} while (0) + +#define SET_PARAM(param, info, iparam, word) \ +({ \ + int changed = 0; \ + if (!info->partial || (info->partial & 1 << key_##word)) { \ + if (param->word != iparam[key_##word]) \ + changed = 1; \ + param->word = iparam[key_##word]; \ + } \ + changed; \ +}) + +#define GET_PARAM(param, info, iparam, word) \ +do { \ + iparam[key_##word] = param->word; \ +} while (0) + +static void sess_param_check(struct iscsi_param_info *info) +{ + u32 *iparam = info->session_param; + + CHECK_PARAM(info, iparam, max_connections, 1, 1); + CHECK_PARAM(info, iparam, max_recv_data_length, 512, + (u32) ((ISCSI_CONN_IOV_MAX - 1) * PAGE_CACHE_SIZE)); + CHECK_PARAM(info, iparam, max_xmit_data_length, 512, + (u32) ((ISCSI_CONN_IOV_MAX - 1) * PAGE_CACHE_SIZE)); + CHECK_PARAM(info, iparam, error_recovery_level, 0, 0); + CHECK_PARAM(info, iparam, data_pdu_inorder, 1, 1); + CHECK_PARAM(info, iparam, data_sequence_inorder, 1, 1); + + digest_alg_available(&iparam[key_header_digest]); + digest_alg_available(&iparam[key_data_digest]); + + CHECK_PARAM(info, iparam, ofmarker, 0, 0); + CHECK_PARAM(info, iparam, ifmarker, 0, 0); +} + +static void sess_param_set(struct iscsi_sess_param *param, struct iscsi_param_info *info) +{ + u32 *iparam = info->session_param; + + SET_PARAM(param, info, iparam, initial_r2t); + SET_PARAM(param, info, iparam, immediate_data); + SET_PARAM(param, info, iparam, max_connections); + SET_PARAM(param, info, iparam, max_recv_data_length); + SET_PARAM(param, info, iparam, max_xmit_data_length); + SET_PARAM(param, info, iparam, max_burst_length); + SET_PARAM(param, info, iparam, first_burst_length); + SET_PARAM(param, info, iparam, default_wait_time); + SET_PARAM(param, info, iparam, default_retain_time); + SET_PARAM(param, info, iparam, max_outstanding_r2t); + SET_PARAM(param, info, iparam, data_pdu_inorder); + SET_PARAM(param, info, iparam, data_sequence_inorder); + SET_PARAM(param, info, iparam, error_recovery_level); + SET_PARAM(param, info, iparam, header_digest); + SET_PARAM(param, info, iparam, data_digest); + SET_PARAM(param, info, iparam, ofmarker); + SET_PARAM(param, info, iparam, ifmarker); + SET_PARAM(param, info, iparam, ofmarkint); + SET_PARAM(param, info, iparam, ifmarkint); +} + +static void sess_param_get(struct iscsi_sess_param *param, struct iscsi_param_info *info) +{ + u32 *iparam = info->session_param; + + GET_PARAM(param, info, iparam, initial_r2t); + GET_PARAM(param, info, iparam, immediate_data); + GET_PARAM(param, info, iparam, max_connections); + GET_PARAM(param, info, iparam, max_recv_data_length); + GET_PARAM(param, info, iparam, max_xmit_data_length); + GET_PARAM(param, info, iparam, max_burst_length); + GET_PARAM(param, info, iparam, first_burst_length); + GET_PARAM(param, info, iparam, default_wait_time); + GET_PARAM(param, info, iparam, default_retain_time); + GET_PARAM(param, info, iparam, max_outstanding_r2t); + GET_PARAM(param, info, iparam, data_pdu_inorder); + GET_PARAM(param, info, iparam, data_sequence_inorder); + GET_PARAM(param, info, iparam, error_recovery_level); + GET_PARAM(param, info, iparam, header_digest); + GET_PARAM(param, info, iparam, data_digest); + GET_PARAM(param, info, iparam, ofmarker); + GET_PARAM(param, info, iparam, ifmarker); + GET_PARAM(param, info, iparam, ofmarkint); + GET_PARAM(param, info, iparam, ifmarkint); +} + +static void trgt_param_check(struct iscsi_param_info *info) +{ + u32 *iparam = info->target_param; + + CHECK_PARAM(info, iparam, wthreads, MIN_NR_WTHREADS, MAX_NR_WTHREADS); + CHECK_PARAM(info, iparam, target_type, 0, + (unsigned int) ARRAY_SIZE(target_type_array) - 1); + CHECK_PARAM(info, iparam, queued_cmnds, MIN_NR_QUEUED_CMNDS, MAX_NR_QUEUED_CMNDS); +} + +static void trgt_param_set(struct iscsi_target *target, struct iscsi_param_info *info) +{ + struct iscsi_trgt_param *param = &target->trgt_param; + u32 *iparam = info->target_param; + + if (SET_PARAM(param, info, iparam, wthreads)) + wthread_start(target); + SET_PARAM(param, info, iparam, target_type); + SET_PARAM(param, info, iparam, queued_cmnds); +} + +static void trgt_param_get(struct iscsi_trgt_param *param, struct iscsi_param_info *info) +{ + u32 *iparam = info->target_param; + + GET_PARAM(param, info, iparam, wthreads); + GET_PARAM(param, info, iparam, target_type); + GET_PARAM(param, info, iparam, queued_cmnds); +} + +static int trgt_param(struct iscsi_target *target, struct iscsi_param_info *info, int set) +{ + + if (set) { + trgt_param_check(info); + trgt_param_set(target, info); + } else + trgt_param_get(&target->trgt_param, info); + + return 0; +} + +static int sess_param(struct iscsi_target *target, struct iscsi_param_info *info, int set) +{ + struct iscsi_session *session = NULL; + struct iscsi_sess_param *param; + int err = -ENOENT; + + if (set) + sess_param_check(info); + + if (info->sid) { + if (!(session = session_lookup(target, info->sid))) + goto out; + param = &session->param; + } else { + param = &target->sess_param; + } + + if (set) { + sess_param_set(param, info); + show_param(param); + } else + sess_param_get(param, info); + + err = 0; +out: + return err; +} + +int iscsi_param_set(struct iscsi_target *target, struct iscsi_param_info *info, int set) +{ + int err; + + if (info->param_type == key_session) + err = sess_param(target, info, set); + else if (info->param_type == key_target) + err = trgt_param(target, info, set); + else + err = -EINVAL; + + return err; +} --- linux-2.6.27.orig/ubuntu/iscsitarget/null-io.c +++ linux-2.6.27/ubuntu/iscsitarget/null-io.c @@ -0,0 +1,113 @@ +/* + * Target device null I/O. + * (C) 2005 MING Zhang + * This code is licenced under the GPL. + * + * The nullio mode will not return any meaningful or previous written + * data. It is only for performance measurement purpose. + */ + +#include +#include +#include + +#include "iscsi.h" +#include "iscsi_dbg.h" +#include "iotype.h" + +struct nullio_data { + u64 sectors; +}; + +enum { + Opt_sectors, Opt_ignore, Opt_err, +}; + +static match_table_t tokens = { + {Opt_sectors, "Sectors=%u"}, + {Opt_ignore, "Type=%s"}, + {Opt_err, NULL}, +}; + +static int parse_nullio_params(struct iet_volume *volume, char *params) +{ + int err = 0; + char *p, *q; + struct nullio_data *data = volume->private; + + while ((p = strsep(¶ms, ",")) != NULL) { + substring_t args[MAX_OPT_ARGS]; + int token; + if (!*p) + continue; + token = match_token(p, tokens, args); + switch (token) { + case Opt_sectors: + q = match_strdup(&args[0]); + if (!q) + return -ENOMEM; + data->sectors = simple_strtoull(q, NULL, 10); + kfree(q); + break; + case Opt_ignore: + break; + default: + eprintk("Unknown %s\n", p); + return -EINVAL; + break; + } + } + return err; +} + +static void nullio_detach(struct iet_volume *lu) +{ + struct nullio_data *p = lu->private; + + kfree(p); + lu->private = NULL; +} + +static int nullio_attach(struct iet_volume *lu, char *args) +{ + int err = 0; + struct nullio_data *p; + + if (lu->private) { + printk("already attached ? %d\n", lu->lun); + return -EBUSY; + } + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + + lu->private = p; + + if ((err = parse_nullio_params(lu, args)) < 0) { + eprintk("%d\n", err); + goto out; + } + + lu->blk_shift = SECTOR_SIZE_BITS; + lu->blk_cnt = (p->sectors = p->sectors ? : 1 << 27); /* 64 GB */ + +out: + if (err < 0) + nullio_detach(lu); + return err; +} + +void nullio_show(struct iet_volume *lu, struct seq_file *seq) +{ + struct nullio_data *p = lu->private; + seq_printf(seq, " sectors:%llu\n", p->sectors); +} + +struct iotype nullio = +{ + .name = "nullio", + .attach = nullio_attach, + .detach = nullio_detach, + .show = nullio_show, +}; --- linux-2.6.27.orig/ubuntu/iscsitarget/target.c +++ linux-2.6.27/ubuntu/iscsitarget/target.c @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2002-2003 Ardis Technolgies + * + * Released under the terms of the GNU GPL v2.0. + */ + +#include "iscsi.h" +#include "digest.h" +#include "iscsi_dbg.h" + +#define MAX_NR_TARGETS (1UL << 30) + +static LIST_HEAD(target_list); +static DECLARE_MUTEX(target_list_sem); +static u32 next_target_id; +static u32 nr_targets; + +static struct iscsi_sess_param default_session_param = { + .initial_r2t = 1, + .immediate_data = 1, + .max_connections = 1, + .max_recv_data_length = 8192, + .max_xmit_data_length = 8192, + .max_burst_length = 262144, + .first_burst_length = 65536, + .default_wait_time = 2, + .default_retain_time = 20, + .max_outstanding_r2t = 1, + .data_pdu_inorder = 1, + .data_sequence_inorder = 1, + .error_recovery_level = 0, + .header_digest = DIGEST_NONE, + .data_digest = DIGEST_NONE, + .ofmarker = 0, + .ifmarker = 0, + .ofmarkint = 2048, + .ifmarkint = 2048, +}; + +static struct iscsi_trgt_param default_target_param = { + .wthreads = DEFAULT_NR_WTHREADS, + .target_type = 0, + .queued_cmnds = DEFAULT_NR_QUEUED_CMNDS, +}; + +inline int target_lock(struct iscsi_target *target, int interruptible) +{ + int err = 0; + + if (interruptible) + err = down_interruptible(&target->target_sem); + else + down(&target->target_sem); + + return err; +} + +inline void target_unlock(struct iscsi_target *target) +{ + up(&target->target_sem); +} + +static struct iscsi_target *__target_lookup_by_id(u32 id) +{ + struct iscsi_target *target; + + list_for_each_entry(target, &target_list, t_list) { + if (target->tid == id) + return target; + } + return NULL; +} + +static struct iscsi_target *__target_lookup_by_name(char *name) +{ + struct iscsi_target *target; + + list_for_each_entry(target, &target_list, t_list) { + if (!strcmp(target->name, name)) + return target; + } + return NULL; +} + +struct iscsi_target *target_lookup_by_id(u32 id) +{ + struct iscsi_target *target; + + down(&target_list_sem); + target = __target_lookup_by_id(id); + up(&target_list_sem); + + return target; +} + +static int target_thread_start(struct iscsi_target *target) +{ + int err; + + if ((err = nthread_start(target)) < 0) + return err; + + if ((err = wthread_start(target)) < 0) { + nthread_stop(target); + } + + return err; +} + +static void target_thread_stop(struct iscsi_target *target) +{ + wthread_stop(target); + nthread_stop(target); +} + +static int iscsi_target_create(struct target_info *info, u32 tid) +{ + int err = -EINVAL, len; + char *name = info->name; + struct iscsi_target *target; + + dprintk(D_SETUP, "%u %s\n", tid, name); + + if (!(len = strlen(name))) { + eprintk("The length of the target name is zero %u\n", tid); + return err; + } + + if (!try_module_get(THIS_MODULE)) { + eprintk("Fail to get module %u\n", tid); + return err; + } + + target = kzalloc(sizeof(*target), GFP_KERNEL); + if (!target) { + err = -ENOMEM; + goto out; + } + + target->tid = info->tid = tid; + + memcpy(&target->sess_param, &default_session_param, sizeof(default_session_param)); + memcpy(&target->trgt_param, &default_target_param, sizeof(default_target_param)); + + strncpy(target->name, name, sizeof(target->name) - 1); + + init_MUTEX(&target->target_sem); + + INIT_LIST_HEAD(&target->session_list); + INIT_LIST_HEAD(&target->volumes); + + atomic_set(&target->nr_volumes, 0); + + list_add(&target->t_list, &target_list); + + nthread_init(target); + wthread_init(target); + + if ((err = target_thread_start(target)) < 0) { + target_thread_stop(target); + goto out; + } + + return 0; +out: + kfree(target); + module_put(THIS_MODULE); + + return err; +} + +int target_add(struct target_info *info) +{ + int err = -EEXIST; + u32 tid = info->tid; + + down(&target_list_sem); + + if (nr_targets > MAX_NR_TARGETS) { + err = -EBUSY; + goto out; + } + + if (__target_lookup_by_name(info->name)) + goto out; + + if (tid && __target_lookup_by_id(tid)) + goto out; + + if (!tid) { + do { + if (!++next_target_id) + ++next_target_id; + } while (__target_lookup_by_id(next_target_id)); + + tid = next_target_id; + } + + if (!(err = iscsi_target_create(info, tid))) + nr_targets++; +out: + up(&target_list_sem); + + return err; +} + +static void target_destroy(struct iscsi_target *target) +{ + dprintk(D_SETUP, "%u\n", target->tid); + + target_thread_stop(target); + + while (!list_empty(&target->volumes)) { + struct iet_volume *volume; + volume = list_entry(target->volumes.next, struct iet_volume, list); + volume->l_state = IDEV_DEL; + iscsi_volume_destroy(volume); + } + + kfree(target); + + module_put(THIS_MODULE); +} + +int target_del(u32 id) +{ + struct iscsi_target *target; + int err; + + if ((err = down_interruptible(&target_list_sem)) < 0) + return err; + + if (!(target = __target_lookup_by_id(id))) { + err = -ENOENT; + goto out; + } + + target_lock(target, 0); + + if (!list_empty(&target->session_list)) { + err = -EBUSY; + target_unlock(target); + goto out; + } + + list_del(&target->t_list); + nr_targets--; + + target_unlock(target); + up(&target_list_sem); + + target_destroy(target); + return 0; +out: + up(&target_list_sem); + return err; +} + +int iet_info_show(struct seq_file *seq, iet_show_info_t *func) +{ + int err; + struct iscsi_target *target; + + if ((err = down_interruptible(&target_list_sem)) < 0) + return err; + + list_for_each_entry(target, &target_list, t_list) { + seq_printf(seq, "tid:%u name:%s\n", target->tid, target->name); + + if ((err = target_lock(target, 1)) < 0) + break; + + func(seq, target); + + target_unlock(target); + } + + up(&target_list_sem); + + return 0; +} --- linux-2.6.27.orig/ubuntu/iscsitarget/iscsi_hdr.h +++ linux-2.6.27/ubuntu/iscsitarget/iscsi_hdr.h @@ -0,0 +1,509 @@ +/* + * Copyright (C) 2002-2003 Ardis Technolgies + * + * Released under the terms of the GNU GPL v2.0. + */ + +#ifndef __ISCSI_HDR_H__ +#define __ISCSI_HDR_H__ + +#include +#include + +#define ISCSI_VERSION 0 + +#ifndef __packed +#define __packed __attribute__ ((packed)) +#endif + +struct iscsi_hdr { + u8 opcode; /* 0 */ + u8 flags; + u8 spec1[2]; +#if defined(__BIG_ENDIAN_BITFIELD) + struct { /* 4 */ + unsigned ahslength : 8; + unsigned datalength : 24; + } length; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + u32 length; /* 4 */ +#endif + u16 lun[4]; /* 8 */ + u32 itt; /* 16 */ + u32 ttt; /* 20 */ + u32 sn; /* 24 */ + u32 exp_sn; /* 28 */ + u32 max_sn; /* 32 */ + u32 spec3[3]; /* 36 */ +} __packed; /* 48 */ + +/* Opcode encoding bits */ +#define ISCSI_OP_RETRY 0x80 +#define ISCSI_OP_IMMEDIATE 0x40 +#define ISCSI_OPCODE_MASK 0x3F + +/* Client to Server Message Opcode values */ +#define ISCSI_OP_NOOP_OUT 0x00 +#define ISCSI_OP_SCSI_CMD 0x01 +#define ISCSI_OP_SCSI_TASK_MGT_MSG 0x02 +#define ISCSI_OP_LOGIN_CMD 0x03 +#define ISCSI_OP_TEXT_CMD 0x04 +#define ISCSI_OP_SCSI_DATA_OUT 0x05 +#define ISCSI_OP_LOGOUT_CMD 0x06 +#define ISCSI_OP_SNACK_CMD 0x10 + +#define ISCSI_OP_VENDOR1_CMD 0x1c +#define ISCSI_OP_VENDOR2_CMD 0x1d +#define ISCSI_OP_VENDOR3_CMD 0x1e +#define ISCSI_OP_VENDOR4_CMD 0x1f + +/* Server to Client Message Opcode values */ +#define ISCSI_OP_NOOP_IN 0x20 +#define ISCSI_OP_SCSI_RSP 0x21 +#define ISCSI_OP_SCSI_TASK_MGT_RSP 0x22 +#define ISCSI_OP_LOGIN_RSP 0x23 +#define ISCSI_OP_TEXT_RSP 0x24 +#define ISCSI_OP_SCSI_DATA_IN 0x25 +#define ISCSI_OP_LOGOUT_RSP 0x26 +#define ISCSI_OP_R2T 0x31 +#define ISCSI_OP_ASYNC_MSG 0x32 +#define ISCSI_OP_REJECT 0x3f + +struct iscsi_ahs_hdr { + u16 ahslength; + u8 ahstype; +} __packed; + +#define ISCSI_AHSTYPE_CDB 1 +#define ISCSI_AHSTYPE_RLENGTH 2 + +union iscsi_sid { + struct { + u8 isid[6]; /* Initiator Session ID */ + u16 tsih; /* Target Session ID */ + } id; + u64 id64; +} __packed; + +struct iscsi_scsi_cmd_hdr { + u8 opcode; + u8 flags; + u16 rsvd1; + u8 ahslength; + u8 datalength[3]; + u16 lun[4]; + u32 itt; + u32 data_length; + u32 cmd_sn; + u32 exp_stat_sn; + u8 scb[16]; +} __packed; + +#define ISCSI_CMD_FINAL 0x80 +#define ISCSI_CMD_READ 0x40 +#define ISCSI_CMD_WRITE 0x20 +#define ISCSI_CMD_ATTR_MASK 0x07 +#define ISCSI_CMD_UNTAGGED 0x00 +#define ISCSI_CMD_SIMPLE 0x01 +#define ISCSI_CMD_ORDERED 0x02 +#define ISCSI_CMD_HEAD_OF_QUEUE 0x03 +#define ISCSI_CMD_ACA 0x04 + +struct iscsi_cdb_ahdr { + u16 ahslength; + u8 ahstype; + u8 reserved; + u8 cdb[0]; +} __packed; + +struct iscsi_rlength_ahdr { + u16 ahslength; + u8 ahstype; + u8 reserved; + u32 read_length; +} __packed; + +struct iscsi_scsi_rsp_hdr { + u8 opcode; + u8 flags; + u8 response; + u8 cmd_status; + u8 ahslength; + u8 datalength[3]; + u32 rsvd1[2]; + u32 itt; + u32 snack; + u32 stat_sn; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u32 exp_data_sn; + u32 bi_residual_count; + u32 residual_count; +} __packed; + +#define ISCSI_FLG_RESIDUAL_UNDERFLOW 0x02 +#define ISCSI_FLG_RESIDUAL_OVERFLOW 0x04 +#define ISCSI_FLG_BIRESIDUAL_UNDERFLOW 0x08 +#define ISCSI_FLG_BIRESIDUAL_OVERFLOW 0x10 + +#define ISCSI_RESPONSE_COMMAND_COMPLETED 0x00 +#define ISCSI_RESPONSE_TARGET_FAILURE 0x01 + +struct iscsi_sense_data { + u16 length; + u8 data[0]; +} __packed; + +struct iscsi_task_mgt_hdr { + u8 opcode; + u8 function; + u16 rsvd1; + u8 ahslength; + u8 datalength[3]; + u16 lun[4]; + u32 itt; + u32 rtt; + u32 cmd_sn; + u32 exp_stat_sn; + u32 ref_cmd_sn; + u32 exp_data_sn; + u32 rsvd2[2]; +} __packed; + +#define ISCSI_FUNCTION_MASK 0x7f + +#define ISCSI_FUNCTION_ABORT_TASK 1 +#define ISCSI_FUNCTION_ABORT_TASK_SET 2 +#define ISCSI_FUNCTION_CLEAR_ACA 3 +#define ISCSI_FUNCTION_CLEAR_TASK_SET 4 +#define ISCSI_FUNCTION_LOGICAL_UNIT_RESET 5 +#define ISCSI_FUNCTION_TARGET_WARM_RESET 6 +#define ISCSI_FUNCTION_TARGET_COLD_RESET 7 +#define ISCSI_FUNCTION_TASK_REASSIGN 8 + +struct iscsi_task_rsp_hdr { + u8 opcode; + u8 flags; + u8 response; + u8 rsvd1; + u8 ahslength; + u8 datalength[3]; + u32 rsvd2[2]; + u32 itt; + u32 rsvd3; + u32 stat_sn; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u32 rsvd4[3]; +} __packed; + +#define ISCSI_RESPONSE_FUNCTION_COMPLETE 0 +#define ISCSI_RESPONSE_UNKNOWN_TASK 1 +#define ISCSI_RESPONSE_UNKNOWN_LUN 2 +#define ISCSI_RESPONSE_TASK_ALLEGIANT 3 +#define ISCSI_RESPONSE_FAILOVER_UNSUPPORTED 4 +#define ISCSI_RESPONSE_FUNCTION_UNSUPPORTED 5 +#define ISCSI_RESPONSE_NO_AUTHORIZATION 6 +#define ISCSI_RESPONSE_FUNCTION_REJECTED 255 + +struct iscsi_data_out_hdr { + u8 opcode; + u8 flags; + u16 rsvd1; + u8 ahslength; + u8 datalength[3]; + u16 lun[4]; + u32 itt; + u32 ttt; + u32 rsvd2; + u32 exp_stat_sn; + u32 rsvd3; + u32 data_sn; + u32 buffer_offset; + u32 rsvd4; +} __packed; + +struct iscsi_data_in_hdr { + u8 opcode; + u8 flags; + u8 rsvd1; + u8 cmd_status; + u8 ahslength; + u8 datalength[3]; + u32 rsvd2[2]; + u32 itt; + u32 ttt; + u32 stat_sn; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u32 data_sn; + u32 buffer_offset; + u32 residual_count; +} __packed; + +#define ISCSI_FLG_STATUS 0x01 + +struct iscsi_r2t_hdr { + u8 opcode; + u8 flags; + u16 rsvd1; + u8 ahslength; + u8 datalength[3]; + u16 lun[4]; + u32 itt; + u32 ttt; + u32 stat_sn; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u32 r2t_sn; + u32 buffer_offset; + u32 data_length; +} __packed; + +struct iscsi_async_msg_hdr { + u8 opcode; + u8 flags; + u16 rsvd1; + u8 ahslength; + u8 datalength[3]; + u16 lun[4]; + u32 ffffffff; + u32 rsvd2; + u32 stat_sn; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u8 async_event; + u8 async_vcode; + u16 param1; + u16 param2; + u16 param3; + u32 rsvd3; +} __packed; + +#define ISCSI_ASYNC_SCSI 0 +#define ISCSI_ASYNC_LOGOUT 1 +#define ISCSI_ASYNC_DROP_CONNECTION 2 +#define ISCSI_ASYNC_DROP_SESSION 3 +#define ISCSI_ASYNC_PARAM_REQUEST 4 +#define ISCSI_ASYNC_VENDOR 255 + +struct iscsi_text_req_hdr { + u8 opcode; + u8 flags; + u16 rsvd1; + u8 ahslength; + u8 datalength[3]; + u32 rsvd2[2]; + u32 itt; + u32 ttt; + u32 cmd_sn; + u32 exp_stat_sn; + u32 rsvd3[4]; +} __packed; + +struct iscsi_text_rsp_hdr { + u8 opcode; + u8 flags; + u16 rsvd1; + u8 ahslength; + u8 datalength[3]; + u32 rsvd2[2]; + u32 itt; + u32 ttt; + u32 stat_sn; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u32 rsvd3[3]; +} __packed; + +struct iscsi_login_req_hdr { + u8 opcode; + u8 flags; + u8 max_version; /* Max. version supported */ + u8 min_version; /* Min. version supported */ + u8 ahslength; + u8 datalength[3]; + union iscsi_sid sid; + u32 itt; /* Initiator Task Tag */ + u16 cid; /* Connection ID */ + u16 rsvd1; + u32 cmd_sn; + u32 exp_stat_sn; + u32 rsvd2[4]; +} __packed; + +struct iscsi_login_rsp_hdr { + u8 opcode; + u8 flags; + u8 max_version; /* Max. version supported */ + u8 active_version; /* Active version */ + u8 ahslength; + u8 datalength[3]; + union iscsi_sid sid; + u32 itt; /* Initiator Task Tag */ + u32 rsvd1; + u32 stat_sn; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u8 status_class; /* see Login RSP ststus classes below */ + u8 status_detail; /* see Login RSP Status details below */ + u8 rsvd2[10]; +} __packed; + +#define ISCSI_FLG_FINAL 0x80 +#define ISCSI_FLG_TRANSIT 0x80 +#define ISCSI_FLG_CSG_SECURITY 0x00 +#define ISCSI_FLG_CSG_LOGIN 0x04 +#define ISCSI_FLG_CSG_FULL_FEATURE 0x0c +#define ISCSI_FLG_CSG_MASK 0x0c +#define ISCSI_FLG_NSG_SECURITY 0x00 +#define ISCSI_FLG_NSG_LOGIN 0x01 +#define ISCSI_FLG_NSG_FULL_FEATURE 0x03 +#define ISCSI_FLG_NSG_MASK 0x03 + +/* Login Status response classes */ +#define ISCSI_STATUS_SUCCESS 0x00 +#define ISCSI_STATUS_REDIRECT 0x01 +#define ISCSI_STATUS_INITIATOR_ERR 0x02 +#define ISCSI_STATUS_TARGET_ERR 0x03 + +/* Login Status response detail codes */ +/* Class-0 (Success) */ +#define ISCSI_STATUS_ACCEPT 0x00 + +/* Class-1 (Redirection) */ +#define ISCSI_STATUS_TGT_MOVED_TEMP 0x01 +#define ISCSI_STATUS_TGT_MOVED_PERM 0x02 + +/* Class-2 (Initiator Error) */ +#define ISCSI_STATUS_INIT_ERR 0x00 +#define ISCSI_STATUS_AUTH_FAILED 0x01 +#define ISCSI_STATUS_TGT_FORBIDDEN 0x02 +#define ISCSI_STATUS_TGT_NOT_FOUND 0x03 +#define ISCSI_STATUS_TGT_REMOVED 0x04 +#define ISCSI_STATUS_NO_VERSION 0x05 +#define ISCSI_STATUS_TOO_MANY_CONN 0x06 +#define ISCSI_STATUS_MISSING_FIELDS 0x07 +#define ISCSI_STATUS_CONN_ADD_FAILED 0x08 +#define ISCSI_STATUS_INV_SESSION_TYPE 0x09 +#define ISCSI_STATUS_SESSION_NOT_FOUND 0x0a +#define ISCSI_STATUS_INV_REQ_TYPE 0x0b + +/* Class-3 (Target Error) */ +#define ISCSI_STATUS_TARGET_ERROR 0x00 +#define ISCSI_STATUS_SVC_UNAVAILABLE 0x01 +#define ISCSI_STATUS_NO_RESOURCES 0x02 + +struct iscsi_logout_req_hdr { + u8 opcode; + u8 flags; + u16 rsvd1; + u8 ahslength; + u8 datalength[3]; + u32 rsvd2[2]; + u32 itt; + u16 cid; + u16 rsvd3; + u32 cmd_sn; + u32 exp_stat_sn; + u32 rsvd4[4]; +} __packed; + +struct iscsi_logout_rsp_hdr { + u8 opcode; + u8 flags; + u8 response; + u8 rsvd1; + u8 ahslength; + u8 datalength[3]; + u32 rsvd2[2]; + u32 itt; + u32 rsvd3; + u32 stat_sn; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u32 rsvd4; + u16 time2wait; + u16 time2retain; + u32 rsvd5; +} __packed; + +struct iscsi_snack_req_hdr { + u8 opcode; + u8 flags; + u16 rsvd1; + u8 ahslength; + u8 datalength[3]; + u32 rsvd2[2]; + u32 itt; + u32 ttt; + u32 rsvd3; + u32 exp_stat_sn; + u32 rsvd4[2]; + u32 beg_run; + u32 run_length; +} __packed; + +struct iscsi_reject_hdr { + u8 opcode; + u8 flags; + u8 reason; + u8 rsvd1; + u8 ahslength; + u8 datalength[3]; + u32 rsvd2[2]; + u32 ffffffff; + u32 rsvd3; + u32 stat_sn; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u32 data_sn; + u32 rsvd4[2]; +} __packed; + +#define ISCSI_REASON_NO_FULL_FEATURE_PHASE 0x01 +#define ISCSI_REASON_DATA_DIGEST_ERROR 0x02 +#define ISCSI_REASON_DATA_SNACK_REJECT 0x03 +#define ISCSI_REASON_PROTOCOL_ERROR 0x04 +#define ISCSI_REASON_UNSUPPORTED_COMMAND 0x05 +#define ISCSI_REASON_IMMEDIATE_COMMAND_REJECT 0x06 +#define ISCSI_REASON_TASK_IN_PROGRESS 0x07 +#define ISCSI_REASON_INVALID_SNACK 0x08 +#define ISCSI_REASON_NO_BOOKMARK 0x09 +#define ISCSI_REASON_BOOKMARK_REJECT 0x0a +#define ISCSI_REASON_NEGOTIATION_RESET 0x0b +#define ISCSI_REASON_WAITING_LOGOUT 0x0c + + +struct iscsi_nop_out_hdr { + u8 opcode; + u8 flags; + u16 rsvd1; + u8 ahslength; + u8 datalength[3]; + u16 lun[4]; + u32 itt; + u32 ttt; + u32 cmd_sn; + u32 exp_stat_sn; + u32 rsvd2[4]; +} __packed; + +struct iscsi_nop_in_hdr { + u8 opcode; + u8 flags; + u16 rsvd1; + u8 ahslength; + u8 datalength[3]; + u16 lun[4]; + u32 itt; + u32 ttt; + u32 stat_sn; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u32 rsvd2[3]; +} __packed; + +#define ISCSI_RESERVED_TAG (0xffffffffU) + +#endif /* __ISCSI_HDR_H__ */ --- linux-2.6.27.orig/ubuntu/iscsitarget/iscsi_dbg.h +++ linux-2.6.27/ubuntu/iscsitarget/iscsi_dbg.h @@ -0,0 +1,130 @@ +#ifndef ISCSI_DBG_H +#define ISCSI_DBG_H + +#define D_SETUP (1UL << 0) +#define D_EXIT (1UL << 1) +#define D_GENERIC (1UL << 2) +#define D_READ (1UL << 3) +#define D_WRITE (1UL << 4) +#define D_IOD (1UL << 5) +#define D_THREAD (1UL << 6) +#define D_TASK_MGT (1UL << 7) +#define D_IOMODE (1UL << 8) + +#define D_DATA (D_READ | D_WRITE) + +extern unsigned long debug_enable_flags; + +#define PFX "iscsi_trgt: " + +#define dprintk(debug, fmt, args...) do { \ + if ((debug) & debug_enable_flags) { \ + printk(KERN_DEBUG PFX "%s(%d) " fmt, __FUNCTION__,\ + __LINE__, args);\ + } \ +} while (0) + +#define eprintk(fmt, args...) do { \ + printk(KERN_ERR PFX "%s(%d) " fmt, __FUNCTION__, \ + __LINE__, args);\ +} while (0) + +#define iprintk(X...) printk(KERN_INFO PFX X) + +#define assert(p) do { \ + if (!(p)) { \ + printk(KERN_CRIT PFX "BUG at %s:%d assert(%s)\n",\ + __FILE__, __LINE__, #p); \ + dump_stack(); \ + BUG(); \ + } \ +} while (0) + +#ifdef D_IOV +static inline void iscsi_dump_iov(struct msghdr *msg) +{ + int i; + printk(PFX "%p, %d\n", msg->msg_iov, msg->msg_iovlen); + for (i = 0; i < min_t(size_t, msg->msg_iovlen, ISCSI_CONN_IOV_MAX); i++) + printk(PFX "%d: %p,%d\n", i, msg->msg_iov[i].iov_base, + msg->msg_iov[i].iov_len); +} +#else +#define iscsi_dump_iov(x) do {} while (0) +#endif + +#ifdef D_DUMP_PDU +static void iscsi_dump_char(int ch) +{ + static unsigned char text[16]; + static int i = 0; + + if (ch < 0) { + while ((i % 16) != 0) { + printk(" "); + text[i] = ' '; + i++; + if ((i % 16) == 0) + printk(" | %.16s |\n", text); + else if ((i % 4) == 0) + printk(" |"); + } + i = 0; + return; + } + + text[i] = (ch < 0x20 || (ch >= 0x80 && ch <= 0xa0)) ? ' ' : ch; + printk(" %02x", ch); + i++; + if ((i % 16) == 0) { + printk(" | %.16s |\n", text); + i = 0; + } else if ((i % 4) == 0) + printk(" |"); +} + +static inline void iscsi_dump_pdu(struct iscsi_pdu *pdu) +{ + unsigned char *buf; + int i; + + buf = (void *)&pdu->bhs; + printk(PFX "BHS: (%p,%d)\n", buf, sizeof(pdu->bhs)); + for (i = 0; i < sizeof(pdu->bhs); i++) + iscsi_dump_char(*buf++); + iscsi_dump_char(-1); + + buf = (void *)pdu->ahs; + printk(PFX "AHS: (%p,%d)\n", buf, pdu->ahssize); + for (i = 0; i < pdu->ahssize; i++) + iscsi_dump_char(*buf++); + iscsi_dump_char(-1); + + printk(PFX "Data: (%d)\n", pdu->datasize); +} + +#else +#define iscsi_dump_pdu(x) do {} while (0) +#endif + +#define show_param(param)\ +{\ + dprintk(D_SETUP, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",\ + (param)->initial_r2t,\ + (param)->immediate_data,\ + (param)->max_connections,\ + (param)->max_recv_data_length,\ + (param)->max_xmit_data_length,\ + (param)->max_burst_length,\ + (param)->first_burst_length,\ + (param)->default_wait_time,\ + (param)->default_retain_time,\ + (param)->max_outstanding_r2t,\ + (param)->data_pdu_inorder,\ + (param)->data_sequence_inorder,\ + (param)->error_recovery_level,\ + (param)->header_digest,\ + (param)->data_digest);\ +} + +#endif --- linux-2.6.27.orig/ubuntu/iscsitarget/Kconfig +++ linux-2.6.27/ubuntu/iscsitarget/Kconfig @@ -0,0 +1,3 @@ +config SCSI_ISCSITARGET + tristate "iSCSI Target Driver" + depends on SCSI --- linux-2.6.27.orig/ubuntu/iscsitarget/target_disk.c +++ linux-2.6.27/ubuntu/iscsitarget/target_disk.c @@ -0,0 +1,482 @@ +/* + * (C) 2004 - 2005 FUJITA Tomonori + * This code is licenced under the GPL. + * + * heavily based on code from kernel/iscsi.c: + * Copyright (C) 2002-2003 Ardis Technolgies , + * licensed under the terms of the GNU GPL v2.0, + */ + +#include +#include + +#include "iscsi.h" +#include "iscsi_dbg.h" + +static int insert_disconnect_pg(u8 *ptr) +{ + unsigned char disconnect_pg[] = {0x02, 0x0e, 0x80, 0x80, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + memcpy(ptr, disconnect_pg, sizeof(disconnect_pg)); + return sizeof(disconnect_pg); +} + +static int insert_caching_pg(u8 *ptr, int async) +{ + unsigned char caching_pg[] = {0x08, 0x12, 0x10, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; + + memcpy(ptr, caching_pg, sizeof(caching_pg)); + if (async) + ptr[2] |= 0x04; /* set WCE bit if we're caching writes */ + return sizeof(caching_pg); +} + +static int insert_ctrl_m_pg(u8 *ptr) +{ + unsigned char ctrl_m_pg[] = {0x0a, 0x0a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x4b}; + + memcpy(ptr, ctrl_m_pg, sizeof(ctrl_m_pg)); + return sizeof(ctrl_m_pg); +} + +static int insert_iec_m_pg(u8 *ptr) +{ + unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00}; + + memcpy(ptr, iec_m_pg, sizeof(iec_m_pg)); + return sizeof(iec_m_pg); +} + +static int insert_format_m_pg(u8 *ptr) +{ + unsigned char format_m_pg[] = {0x03, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00}; + memcpy(ptr, format_m_pg, sizeof(format_m_pg)); + return sizeof(format_m_pg); +} + +static int insert_geo_m_pg(u8 *ptr, u64 sec) +{ + unsigned char geo_m_pg[] = {0x04, 0x16, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3a, 0x98, 0x00, 0x00}; + u32 ncyl; + u32 n; + + /* assume 0xff heads, 15krpm. */ + memcpy(ptr, geo_m_pg, sizeof(geo_m_pg)); + ncyl = sec >> 14; /* 256 * 64 */ + memcpy(&n, ptr+1, sizeof(u32)); + n = n | cpu_to_be32(ncyl); + memcpy(ptr+1, &n, sizeof(u32)); + return sizeof(geo_m_pg); +} + +static int build_mode_sense_response(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio = cmnd->tio; + u8 *data, *scb = req->scb; + int len = 4, err = 0; + u8 pcode; + + pcode = req->scb[2] & 0x3f; + + assert(!tio); + tio = cmnd->tio = tio_alloc(1); + data = page_address(tio->pvec[0]); + assert(data); + clear_page(data); + + if (LUReadonly(cmnd->lun)) + data[2] = 0x80; + + if ((scb[1] & 0x8)) + data[3] = 0; + else { + data[3] = 8; + len += 8; + *(u32 *)(data + 4) = (cmnd->lun->blk_cnt >> 32) ? + cpu_to_be32(0xffffffff) : cpu_to_be32(cmnd->lun->blk_cnt); + *(u32 *)(data + 8) = cpu_to_be32(1 << cmnd->lun->blk_shift); + } + + switch (pcode) { + case 0x0: + break; + case 0x2: + len += insert_disconnect_pg(data + len); + break; + case 0x3: + len += insert_format_m_pg(data + len); + break; + case 0x4: + len += insert_geo_m_pg(data + len, cmnd->lun->blk_cnt); + break; + case 0x8: + len += insert_caching_pg(data + len, LUAsync(cmnd->lun)); + break; + case 0xa: + len += insert_ctrl_m_pg(data + len); + break; + case 0x1c: + len += insert_iec_m_pg(data + len); + break; + case 0x3f: + len += insert_disconnect_pg(data + len); + len += insert_format_m_pg(data + len); + len += insert_geo_m_pg(data + len, cmnd->lun->blk_cnt); + len += insert_caching_pg(data + len, LUAsync(cmnd->lun)); + len += insert_ctrl_m_pg(data + len); + len += insert_iec_m_pg(data + len); + break; + default: + err = -1; + } + + data[0] = len - 1; + + tio_set(tio, len, 0); + + return err; +} + +static int build_inquiry_response(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio = cmnd->tio; + u8 *data; + u8 *scb = req->scb; + int err = -1; + + if (((req->scb[1] & 0x3) == 0x3) || (!(req->scb[1] & 0x3) && req->scb[2])) + return err; + + assert(!tio); + tio = cmnd->tio = tio_alloc(1); + data = page_address(tio->pvec[0]); + assert(data); + clear_page(data); + + if (!(scb[1] & 0x3)) { + data[2] = 4; + data[3] = 0x42; + data[4] = 59; + data[7] = 0x02; + memset(data + 8, 0x20, 28); + memcpy(data + 8, + VENDOR_ID, min_t(size_t, strlen(VENDOR_ID), 8)); + memcpy(data + 16, + PRODUCT_ID, min_t(size_t, strlen(PRODUCT_ID), 16)); + memcpy(data + 32, + PRODUCT_REV, min_t(size_t, strlen(PRODUCT_REV), 4)); + data[58] = 0x03; + data[59] = 0x20; + data[60] = 0x09; + data[61] = 0x60; + data[62] = 0x03; + data[63] = 0x00; + tio_set(tio, 64, 0); + err = 0; + } else if (scb[1] & 0x2) { + /* CmdDt bit is set */ + /* We do not support it now. */ + data[1] = 0x1; + data[5] = 0; + tio_set(tio, 6, 0); + err = 0; + } else if (scb[1] & 0x1) { + /* EVPD bit set */ + if (scb[2] == 0x0) { + data[1] = 0x0; + data[3] = 3; + data[4] = 0x0; + data[5] = 0x80; + data[6] = 0x83; + tio_set(tio, 7, 0); + err = 0; + } else if (scb[2] == 0x80) { + int len = (cmnd->lun && strlen(cmnd->lun->scsi_sn)) ? + SCSI_SN_LEN : 4; + + data[1] = 0x80; + data[3] = len; + memset(data + 4, 0x20, len); + tio_set(tio, len + 4, 0); + err = 0; + + if (len == SCSI_SN_LEN) { + char *p, *q; + + p = data + 4 + len - 1; + q = cmnd->lun->scsi_sn + len - 1; + + for (; len > 0; len--, q--) + if (isascii(*q) && isprint(*q)) + *(p--) = *q; + } + } else if (scb[2] == 0x83) { + u32 len = SCSI_ID_LEN * sizeof(u8); + + data[1] = 0x83; + data[3] = len + 4; + data[4] = 0x1; + data[5] = 0x1; + data[7] = len; + if (cmnd->lun) /* We need this ? */ + memcpy(data + 8, cmnd->lun->scsi_id, len); + tio_set(tio, len + 8, 0); + err = 0; + } + } + + tio_set(tio, min_t(u8, tio->size, scb[4]), 0); + if (!cmnd->lun) + data[0] = TYPE_NO_LUN; + + return err; +} + +static int build_report_luns_response(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio = cmnd->tio; + u32 *data, size, len; + struct iet_volume *lun; + int rest, idx = 0; + + size = (u32)req->scb[6] << 24 | (u32)req->scb[7] << 16 | + (u32)req->scb[8] << 8 | (u32)req->scb[9]; + if (size < 16) + return -1; + + len = atomic_read(&cmnd->conn->session->target->nr_volumes) * 8; + size = min(size & ~(8 - 1), len + 8); + + assert(!tio); + tio = cmnd->tio = tio_alloc(get_pgcnt(size, 0)); + tio_set(tio, size, 0); + + data = page_address(tio->pvec[idx]); + assert(data); + *data++ = cpu_to_be32(len); + *data++ = 0; + size -= 8; + rest = PAGE_CACHE_SIZE - 8; + list_for_each_entry(lun, &cmnd->conn->session->target->volumes, list) { + if (lun->l_state != IDEV_RUNNING) + continue; + + *data++ = cpu_to_be32((0x3ff & lun->lun) << 16 | + ((lun->lun > 0xff) ? (0x1 << 30) : 0)); + *data++ = 0; + if ((size -= 8) == 0) + break; + if ((rest -= 8) == 0) { + idx++; + data = page_address(tio->pvec[idx]); + rest = PAGE_CACHE_SIZE; + } + } + + return 0; +} + +static int build_read_capacity_response(struct iscsi_cmnd *cmnd) +{ + struct tio *tio = cmnd->tio; + u32 *data; + + assert(!tio); + tio = cmnd->tio = tio_alloc(1); + data = page_address(tio->pvec[0]); + assert(data); + clear_page(data); + + data[0] = (cmnd->lun->blk_cnt >> 32) ? + cpu_to_be32(0xffffffff) : cpu_to_be32(cmnd->lun->blk_cnt - 1); + data[1] = cpu_to_be32(1U << cmnd->lun->blk_shift); + + tio_set(tio, 8, 0); + return 0; +} + +static int build_request_sense_response(struct iscsi_cmnd *cmnd) +{ + struct tio *tio = cmnd->tio; + u8 *data; + + assert(!tio); + tio = cmnd->tio = tio_alloc(1); + data = page_address(tio->pvec[0]); + assert(data); + memset(data, 0, 18); + data[0] = 0xf0; + data[1] = 0; + data[2] = NO_SENSE; + data[7] = 10; + tio_set(tio, 18, 0); + + return 0; +} + +static int build_service_action_response(struct iscsi_cmnd *cmnd) +{ + struct tio *tio = cmnd->tio; + u32 *data; + u64 *data64; + +/* assert((req->scb[1] & 0x1f) == 0x10); */ + assert(!tio); + tio = cmnd->tio = tio_alloc(1); + data = page_address(tio->pvec[0]); + assert(data); + clear_page(data); + data64 = (u64*) data; + data64[0] = cpu_to_be64(cmnd->lun->blk_cnt - 1); + data[2] = cpu_to_be32(1UL << cmnd->lun->blk_shift); + + tio_set(tio, 12, 0); + return 0; +} + +static int build_read_response(struct iscsi_cmnd *cmnd) +{ + struct tio *tio = cmnd->tio; + + assert(tio); + assert(cmnd->lun); + + return tio_read(cmnd->lun, tio); +} + +static int build_write_response(struct iscsi_cmnd *cmnd) +{ + int err; + struct tio *tio = cmnd->tio; + + assert(tio); + assert(cmnd->lun); + + list_del_init(&cmnd->list); + err = tio_write(cmnd->lun, tio); + if (!err && !LUAsync(cmnd->lun)) + err = tio_sync(cmnd->lun, tio); + + return err; +} + +static int build_sync_cache_response(struct iscsi_cmnd *cmnd) +{ + assert(cmnd->lun); + return tio_sync(cmnd->lun, NULL); +} + +static int build_generic_response(struct iscsi_cmnd *cmnd) +{ + return 0; +} + +static int build_reserve_response(struct iscsi_cmnd *cmnd) +{ + return volume_reserve(cmnd->lun, cmnd->conn->session->sid); +} + +static int build_release_response(struct iscsi_cmnd *cmnd) +{ + return volume_release(cmnd->lun, + cmnd->conn->session->sid, 0); +} + +static int build_reservation_conflict_response(struct iscsi_cmnd *cmnd) +{ + return -EBUSY; +} + +static int disk_execute_cmnd(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + + req->opcode &= ISCSI_OPCODE_MASK; + + if (is_volume_reserved(cmnd->lun, + cmnd->conn->session->sid)) { + switch (req->scb[0]) { + case INQUIRY: + case RELEASE: + case REPORT_LUNS: + case REQUEST_SENSE: + /* allowed commands when reserved */ + break; + default: + /* return reservation conflict for all others */ + send_scsi_rsp(cmnd, + build_reservation_conflict_response); + return 0; + } + } + + switch (req->scb[0]) { + case INQUIRY: + send_data_rsp(cmnd, build_inquiry_response); + break; + case REPORT_LUNS: + send_data_rsp(cmnd, build_report_luns_response); + break; + case READ_CAPACITY: + send_data_rsp(cmnd, build_read_capacity_response); + break; + case MODE_SENSE: + send_data_rsp(cmnd, build_mode_sense_response); + break; + case REQUEST_SENSE: + send_data_rsp(cmnd, build_request_sense_response); + break; + case SERVICE_ACTION_IN: + send_data_rsp(cmnd, build_service_action_response); + break; + case READ_6: + case READ_10: + case READ_16: + send_data_rsp(cmnd, build_read_response); + break; + case WRITE_6: + case WRITE_10: + case WRITE_16: + case WRITE_VERIFY: + send_scsi_rsp(cmnd, build_write_response); + break; + case SYNCHRONIZE_CACHE: + send_scsi_rsp(cmnd, build_sync_cache_response); + break; + case RESERVE: + send_scsi_rsp(cmnd, build_reserve_response); + break; + case RELEASE: + send_scsi_rsp(cmnd, build_release_response); + break; + case START_STOP: + case TEST_UNIT_READY: + case VERIFY: + case VERIFY_16: + send_scsi_rsp(cmnd, build_generic_response); + break; + default: + eprintk("%s\n", "we should not come here!"); + break; + } + + return 0; +} + +struct target_type disk_ops = +{ + .id = 0, + .execute_cmnd = disk_execute_cmnd, +}; --- linux-2.6.27.orig/ubuntu/iscsitarget/nthread.c +++ linux-2.6.27/ubuntu/iscsitarget/nthread.c @@ -0,0 +1,700 @@ +/* + * Network thread. + * (C) 2004 - 2005 FUJITA Tomonori + * This code is licenced under the GPL. + */ + +#include +#include +#include +#include + +#include "iscsi.h" +#include "iscsi_dbg.h" +#include "digest.h" + +enum daemon_state_bit { + D_ACTIVE, + D_DATA_READY, +}; + +void nthread_wakeup(struct iscsi_target *target) +{ + struct network_thread_info *info = &target->nthread_info; + + spin_lock_bh(&info->nthread_lock); + set_bit(D_DATA_READY, &info->flags); + wake_up_process(info->task); + spin_unlock_bh(&info->nthread_lock); +} + +static inline void iscsi_conn_init_read(struct iscsi_conn *conn, void *data, size_t len) +{ + len = (len + 3) & -4; // XXX ??? + conn->read_iov[0].iov_base = data; + conn->read_iov[0].iov_len = len; + conn->read_msg.msg_iov = conn->read_iov; + conn->read_msg.msg_iovlen = 1; + conn->read_size = (len + 3) & -4; +} + +static void iscsi_conn_read_ahs(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd) +{ + cmnd->pdu.ahs = kmalloc(cmnd->pdu.ahssize, __GFP_NOFAIL|GFP_KERNEL); + assert(cmnd->pdu.ahs); + iscsi_conn_init_read(conn, cmnd->pdu.ahs, cmnd->pdu.ahssize); +} + +static struct iscsi_cmnd * iscsi_get_send_cmnd(struct iscsi_conn *conn) +{ + struct iscsi_cmnd *cmnd = NULL; + + spin_lock(&conn->list_lock); + if (!list_empty(&conn->write_list)) { + cmnd = list_entry(conn->write_list.next, struct iscsi_cmnd, list); + list_del_init(&cmnd->list); + } + spin_unlock(&conn->list_lock); + + return cmnd; +} + +static int is_data_available(struct iscsi_conn *conn) +{ + int avail, res; + mm_segment_t oldfs; + struct socket *sock = conn->sock; + + oldfs = get_fs(); + set_fs(get_ds()); + res = sock->ops->ioctl(sock, SIOCINQ, (unsigned long) &avail); + set_fs(oldfs); + return (res >= 0) ? avail : res; +} + +static void forward_iov(struct msghdr *msg, int len) +{ + while (msg->msg_iov->iov_len <= len) { + len -= msg->msg_iov->iov_len; + msg->msg_iov++; + msg->msg_iovlen--; + } + + msg->msg_iov->iov_base = (char *) msg->msg_iov->iov_base + len; + msg->msg_iov->iov_len -= len; +} + +static int do_recv(struct iscsi_conn *conn, int state) +{ + mm_segment_t oldfs; + struct msghdr msg; + struct iovec iov[ISCSI_CONN_IOV_MAX]; + int i, len, res; + + if (!test_bit(CONN_ACTIVE, &conn->state)) { + res = -EIO; + goto out; + } + + if (is_data_available(conn) <= 0) { + res = -EAGAIN; + goto out; + } + + msg.msg_iov = iov; + msg.msg_iovlen = min_t(size_t, conn->read_msg.msg_iovlen, ISCSI_CONN_IOV_MAX); + for (i = 0, len = 0; i < msg.msg_iovlen; i++) { + iov[i] = conn->read_msg.msg_iov[i]; + len += iov[i].iov_len; + } + + oldfs = get_fs(); + set_fs(get_ds()); + res = sock_recvmsg(conn->sock, &msg, len, MSG_DONTWAIT | MSG_NOSIGNAL); + set_fs(oldfs); + + if (res <= 0) { + switch (res) { + case -EAGAIN: + case -ERESTARTSYS: + break; + default: + eprintk("%d\n", res); + conn_close(conn); + break; + } + } else { + conn->read_size -= res; + if (conn->read_size) + forward_iov(&conn->read_msg, res); + else + conn->read_state = state; + } + +out: + dprintk(D_IOD, "%d\n", res); + + return res; +} + +enum rx_state { + RX_INIT_BHS, /* Must be zero. */ + RX_BHS, + + RX_INIT_AHS, + RX_AHS, + + RX_INIT_HDIGEST, + RX_HDIGEST, + RX_CHECK_HDIGEST, + + RX_INIT_DATA, + RX_DATA, + + RX_INIT_DDIGEST, + RX_DDIGEST, + RX_CHECK_DDIGEST, + + RX_END, +}; + +static void rx_ddigest(struct iscsi_conn *conn, int state) +{ + struct iscsi_cmnd *cmnd = conn->read_cmnd; + int res = digest_rx_data(cmnd); + + if (!res) + conn->read_state = state; + else + conn_close(conn); +} + +static void rx_hdigest(struct iscsi_conn *conn, int state) +{ + struct iscsi_cmnd *cmnd = conn->read_cmnd; + int res = digest_rx_header(cmnd); + + if (!res) + conn->read_state = state; + else + conn_close(conn); +} + +static struct iscsi_cmnd *create_cmnd(struct iscsi_conn *conn) +{ + struct iscsi_cmnd *cmnd; + + cmnd = cmnd_alloc(conn, 1); + iscsi_conn_init_read(cmnd->conn, &cmnd->pdu.bhs, sizeof(cmnd->pdu.bhs)); + conn->read_state = RX_BHS; + + return cmnd; +} + +static int recv(struct iscsi_conn *conn) +{ + struct iscsi_cmnd *cmnd = conn->read_cmnd; + int hdigest, ddigest, res = 1; + + if (!test_bit(CONN_ACTIVE, &conn->state)) + return -EIO; + + hdigest = conn->hdigest_type & DIGEST_NONE ? 0 : 1; + ddigest = conn->ddigest_type & DIGEST_NONE ? 0 : 1; + + switch (conn->read_state) { + case RX_INIT_BHS: + assert(!cmnd); + cmnd = conn->read_cmnd = create_cmnd(conn); + case RX_BHS: + res = do_recv(conn, RX_INIT_AHS); + if (res <= 0 || conn->read_state != RX_INIT_AHS) + break; + case RX_INIT_AHS: + iscsi_cmnd_get_length(&cmnd->pdu); + if (cmnd->pdu.ahssize) { + iscsi_conn_read_ahs(conn, cmnd); + conn->read_state = RX_AHS; + } else + conn->read_state = hdigest ? RX_INIT_HDIGEST : RX_INIT_DATA; + + if (conn->read_state != RX_AHS) + break; + case RX_AHS: + res = do_recv(conn, hdigest ? RX_INIT_HDIGEST : RX_INIT_DATA); + if (res <= 0 || conn->read_state != RX_INIT_HDIGEST) + break; + case RX_INIT_HDIGEST: + iscsi_conn_init_read(conn, &cmnd->hdigest, sizeof(u32)); + conn->read_state = RX_HDIGEST; + case RX_HDIGEST: + res = do_recv(conn, RX_CHECK_HDIGEST); + if (res <= 0 || conn->read_state != RX_CHECK_HDIGEST) + break; + case RX_CHECK_HDIGEST: + rx_hdigest(conn, RX_INIT_DATA); + if (conn->read_state != RX_INIT_DATA) + break; + case RX_INIT_DATA: + cmnd_rx_start(cmnd); + conn->read_state = cmnd->pdu.datasize ? RX_DATA : RX_END; + if (conn->read_state != RX_DATA) + break; + case RX_DATA: + res = do_recv(conn, ddigest ? RX_INIT_DDIGEST : RX_END); + if (res <= 0 || conn->read_state != RX_INIT_DDIGEST) + break; + case RX_INIT_DDIGEST: + iscsi_conn_init_read(conn, &cmnd->ddigest, sizeof(u32)); + conn->read_state = RX_DDIGEST; + case RX_DDIGEST: + res = do_recv(conn, RX_CHECK_DDIGEST); + if (res <= 0 || conn->read_state != RX_CHECK_DDIGEST) + break; + case RX_CHECK_DDIGEST: + rx_ddigest(conn, RX_END); + break; + default: + eprintk("%d %d %x\n", res, conn->read_state, cmnd_opcode(cmnd)); + assert(0); + } + + if (res <= 0) + return res; + + if (conn->read_state != RX_END) + return res; + + if (conn->read_size) { + eprintk("%d %x %d\n", res, cmnd_opcode(cmnd), conn->read_size); + assert(0); + } + + cmnd_rx_end(cmnd); + if (conn->read_size) { + eprintk("%x %d\n", cmnd_opcode(cmnd), conn->read_size); + conn->read_state = RX_DATA; + return 1; + } + + conn->read_cmnd = NULL; + conn->read_state = RX_INIT_BHS; + + return 0; +} + +/* This is taken from the Ardis code. */ +static int write_data(struct iscsi_conn *conn) +{ + mm_segment_t oldfs; + struct file *file; + struct socket *sock; + ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int); + struct tio *tio; + struct iovec *iop; + int saved_size, size, sendsize; + int offset, idx; + int flags, res; + + file = conn->file; + saved_size = size = conn->write_size; + iop = conn->write_iop; + + if (iop) while (1) { + loff_t off = 0; + unsigned long count; + struct iovec *vec; + int rest; + + vec = iop; + for (count = 0; vec->iov_len; count++, vec++) + ; + oldfs = get_fs(); + set_fs(KERNEL_DS); + res = vfs_writev(file, (struct iovec __user *) iop, count, &off); + set_fs(oldfs); + dprintk(D_DATA, "%#Lx:%u: %d(%ld)\n", + (unsigned long long) conn->session->sid, conn->cid, + res, (long) iop->iov_len); + if (unlikely(res <= 0)) { + if (res == -EAGAIN || res == -EINTR) { + conn->write_iop = iop; + goto out_iov; + } + goto err; + } + + rest = res; + size -= res; + while (iop->iov_len <= rest && rest) { + rest -= iop->iov_len; + iop++; + } + iop->iov_base += rest; + iop->iov_len -= rest; + + if (!iop->iov_len) { + conn->write_iop = NULL; + if (size) + break; + goto out_iov; + } + } + + if (!(tio = conn->write_tcmnd)) { + eprintk("%s\n", "warning data missing!"); + return 0; + } + offset = conn->write_offset; + idx = offset >> PAGE_CACHE_SHIFT; + offset &= ~PAGE_CACHE_MASK; + + sock = conn->sock; + sendpage = sock->ops->sendpage ? : sock_no_sendpage; + flags = MSG_DONTWAIT; + + while (1) { + sendsize = PAGE_CACHE_SIZE - offset; + if (size <= sendsize) { + res = sendpage(sock, tio->pvec[idx], offset, size, flags); + dprintk(D_DATA, "%s %#Lx:%u: %d(%lu,%u,%u)\n", + sock->ops->sendpage ? "sendpage" : "writepage", + (unsigned long long ) conn->session->sid, conn->cid, + res, tio->pvec[idx]->index, offset, size); + if (unlikely(res <= 0)) { + if (res == -EAGAIN || res == -EINTR) { + goto out; + } + goto err; + } + if (res == size) { + conn->write_tcmnd = NULL; + conn->write_size = 0; + return saved_size; + } + offset += res; + size -= res; + continue; + } + + res = sendpage(sock, tio->pvec[idx], offset,sendsize, flags | MSG_MORE); + dprintk(D_DATA, "%s %#Lx:%u: %d(%lu,%u,%u)\n", + sock->ops->sendpage ? "sendpage" : "writepage", + (unsigned long long ) conn->session->sid, conn->cid, + res, tio->pvec[idx]->index, offset, sendsize); + if (unlikely(res <= 0)) { + if (res == -EAGAIN || res == -EINTR) { + goto out; + } + goto err; + } + if (res == sendsize) { + idx++; + offset = 0; + } else + offset += res; + size -= res; + } + out: + conn->write_offset = (idx << PAGE_CACHE_SHIFT) + offset; + out_iov: + conn->write_size = size; + if ((saved_size == size) && res == -EAGAIN) + return res; + + return saved_size - size; + + err: + eprintk("error %d at %#Lx:%u\n", res, + (unsigned long long) conn->session->sid, conn->cid); + return res; +} + +static void exit_tx(struct iscsi_conn *conn, int res) +{ + if (res > 0) + return; + + switch (res) { + case -EAGAIN: + case -ERESTARTSYS: + break; + default: + eprintk("%d %d %d\n", conn->write_size, conn->write_state, res); + conn_close(conn); + break; + } +} + +static int tx_ddigest(struct iscsi_cmnd *cmnd, int state) +{ + int res, rest = cmnd->conn->write_size; + struct msghdr msg = {.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT}; + struct kvec iov; + + iov.iov_base = (char *) (&cmnd->ddigest) + (sizeof(u32) - rest); + iov.iov_len = rest; + + res = kernel_sendmsg(cmnd->conn->sock, &msg, &iov, 1, rest); + + if (res > 0) { + cmnd->conn->write_size -= res; + if (!cmnd->conn->write_size) + cmnd->conn->write_state = state; + } else + exit_tx(cmnd->conn, res); + + return res; +} + +static void init_tx_hdigest(struct iscsi_cmnd *cmnd) +{ + struct iscsi_conn *conn = cmnd->conn; + struct iovec *iop; + + if (conn->hdigest_type & DIGEST_NONE) + return; + + digest_tx_header(cmnd); + + for (iop = conn->write_iop; iop->iov_len; iop++) + ; + iop->iov_base = &(cmnd->hdigest); + iop->iov_len = sizeof(u32); + conn->write_size += sizeof(u32); + iop++; + iop->iov_len = 0; + + return; +} + +enum tx_state { + TX_INIT, /* Must be zero. */ + TX_BHS_DATA, + TX_INIT_DDIGEST, + TX_DDIGEST, + TX_END, +}; + +static int do_send(struct iscsi_conn *conn, int state) +{ + int res; + + res = write_data(conn); + + if (res > 0) { + if (!conn->write_size) + conn->write_state = state; + } else + exit_tx(conn, res); + + return res; +} + +static int send(struct iscsi_conn *conn) +{ + struct iscsi_cmnd *cmnd = conn->write_cmnd; + int ddigest, res = 0; + + ddigest = conn->ddigest_type != DIGEST_NONE ? 1 : 0; + + switch (conn->write_state) { + case TX_INIT: + assert(!cmnd); + cmnd = conn->write_cmnd = iscsi_get_send_cmnd(conn); + if (!cmnd) + return 0; + cmnd_tx_start(cmnd); + init_tx_hdigest(cmnd); + conn->write_state = TX_BHS_DATA; + case TX_BHS_DATA: + res = do_send(conn, ddigest && cmnd->pdu.datasize ? TX_INIT_DDIGEST : TX_END); + if (res <= 0 || conn->write_state != TX_INIT_DDIGEST) + break; + case TX_INIT_DDIGEST: + digest_tx_data(cmnd); + assert(!cmnd->conn->write_size); + cmnd->conn->write_size += sizeof(u32); + conn->write_state = TX_DDIGEST; + case TX_DDIGEST: + res = tx_ddigest(cmnd, TX_END); + break; + default: + eprintk("%d %d %x\n", res, conn->write_state, cmnd_opcode(cmnd)); + assert(0); + } + + if (res <= 0) + return res; + + if (conn->write_state != TX_END) + return res; + + if (conn->write_size) { + eprintk("%d %x %u\n", res, cmnd_opcode(cmnd), conn->write_size); + assert(!conn->write_size); + } + cmnd_tx_end(cmnd); + cmnd_release(cmnd, 0); + conn->write_cmnd = NULL; + conn->write_state = TX_INIT; + + return 0; +} + +static void process_io(struct iscsi_conn *conn) +{ + struct iscsi_target *target = conn->session->target; + int res, wakeup = 0; + + res = recv(conn); + + if (is_data_available(conn) > 0 || res > 0) + wakeup = 1; + + if (!test_bit(CONN_ACTIVE, &conn->state)) { + wakeup = 1; + goto out; + } + + res = send(conn); + + if (!list_empty(&conn->write_list) || conn->write_cmnd) + wakeup = 1; + +out: + if (wakeup) + nthread_wakeup(target); + + return; +} + +static void close_conn(struct iscsi_conn *conn) +{ + struct iscsi_session *session = conn->session; + struct iscsi_cmnd *cmnd; + + assert(conn); + + conn->sock->ops->shutdown(conn->sock, 2); + + write_lock_bh(&conn->sock->sk->sk_callback_lock); + conn->sock->sk->sk_state_change = session->target->nthread_info.old_state_change; + conn->sock->sk->sk_data_ready = session->target->nthread_info.old_data_ready; + write_unlock_bh(&conn->sock->sk->sk_callback_lock); + + fput(conn->file); + conn->file = NULL; + conn->sock = NULL; + + while (atomic_read(&conn->nr_busy_cmnds)) + yield(); + + while (!list_empty(&conn->pdu_list)) { + cmnd = list_entry(conn->pdu_list.next, struct iscsi_cmnd, conn_list); + + list_del_init(&cmnd->list); + cmnd_release(cmnd, 1); + } + + if (atomic_read(&conn->nr_cmnds)) { + eprintk("%u\n", atomic_read(&conn->nr_cmnds)); + list_for_each_entry(cmnd, &conn->pdu_list, conn_list) + eprintk("%x %x\n", cmnd_opcode(cmnd), cmnd_itt(cmnd)); + assert(0); + } + + event_send(session->target->tid, session->sid, conn->cid, E_CONN_CLOSE, 0); + conn_free(conn); + + if (list_empty(&session->conn_list)) + session_del(session->target, session->sid); +} + +static int istd(void *arg) +{ + struct iscsi_target *target = arg; + struct network_thread_info *info = &target->nthread_info; + struct iscsi_conn *conn, *tmp; + + __set_current_state(TASK_RUNNING); + do { + spin_lock_bh(&info->nthread_lock); + __set_current_state(TASK_INTERRUPTIBLE); + + if (!test_bit(D_DATA_READY, &info->flags)) { + spin_unlock_bh(&info->nthread_lock); + schedule(); + spin_lock_bh(&info->nthread_lock); + } + __set_current_state(TASK_RUNNING); + clear_bit(D_DATA_READY, &info->flags); + spin_unlock_bh(&info->nthread_lock); + + target_lock(target, 0); + list_for_each_entry_safe(conn, tmp, &info->active_conns, poll_list) { + if (test_bit(CONN_ACTIVE, &conn->state)) + process_io(conn); + else + close_conn(conn); + } + target_unlock(target); + + } while (!kthread_should_stop()); + + return 0; +} + +int nthread_init(struct iscsi_target *target) +{ + struct network_thread_info *info = &target->nthread_info; + + info->flags = 0; + info->task = NULL; + + info->old_state_change = NULL; + info->old_data_ready = NULL; + + INIT_LIST_HEAD(&info->active_conns); + + spin_lock_init(&info->nthread_lock); + + return 0; +} + +int nthread_start(struct iscsi_target *target) +{ + int err = 0; + struct network_thread_info *info = &target->nthread_info; + struct task_struct *task; + + if (info->task) { + eprintk("Target (%u) already runs\n", target->tid); + return -EALREADY; + } + + task = kthread_run(istd, target, "istd%d", target->tid); + + if (IS_ERR(task)) + err = PTR_ERR(task); + else + info->task = task; + + return err; +} + +int nthread_stop(struct iscsi_target *target) +{ + int err; + struct network_thread_info *info = &target->nthread_info; + + if (!info->task) + return -ESRCH; + + err = kthread_stop(info->task); + + if (!err) + info->task = NULL; + + return err; +} --- linux-2.6.27.orig/ubuntu/iscsitarget/event.c +++ linux-2.6.27/ubuntu/iscsitarget/event.c @@ -0,0 +1,97 @@ +/* + * Event notification code. + * (C) 2005 FUJITA Tomonori + * This code is licenced under the GPL. + * + * Some functions are based on audit code. + */ + +#include +#include "iet_u.h" +#include "iscsi_dbg.h" + +static struct sock *nl; +static u32 ietd_pid; + +static int event_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) +{ + u32 uid, pid, seq; + char *data; + + pid = NETLINK_CREDS(skb)->pid; + uid = NETLINK_CREDS(skb)->uid; + seq = nlh->nlmsg_seq; + data = NLMSG_DATA(nlh); + + ietd_pid = pid; + + return 0; +} + +static void event_recv_skb(struct sk_buff *skb) +{ + int err; + struct nlmsghdr *nlh; + u32 rlen; + + while (skb->len >= NLMSG_SPACE(0)) { + nlh = (struct nlmsghdr *)skb->data; + if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) + break; + rlen = NLMSG_ALIGN(nlh->nlmsg_len); + if (rlen > skb->len) + rlen = skb->len; + if ((err = event_recv_msg(skb, nlh))) { + netlink_ack(skb, nlh, -err); + } else if (nlh->nlmsg_flags & NLM_F_ACK) + netlink_ack(skb, nlh, 0); + skb_pull(skb, rlen); + } +} + +static int notify(void *data, int len, int gfp_mask) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + static u32 seq = 0; + + if (!(skb = alloc_skb(NLMSG_SPACE(len), gfp_mask))) + return -ENOMEM; + + nlh = __nlmsg_put(skb, ietd_pid, seq++, NLMSG_DONE, len - sizeof(*nlh), 0); + + memcpy(NLMSG_DATA(nlh), data, len); + + return netlink_unicast(nl, skb, ietd_pid, 0); +} + +int event_send(u32 tid, u64 sid, u32 cid, u32 state, int atomic) +{ + int err; + struct iet_event event; + + event.tid = tid; + event.sid = sid; + event.cid = cid; + event.state = state; + + err = notify(&event, NLMSG_SPACE(sizeof(struct iet_event)), 0); + + return err; +} + +int event_init(void) +{ + nl = netlink_kernel_create(&init_net, NETLINK_IET, 1, event_recv_skb, + NULL, THIS_MODULE); + if (!nl) + return -ENOMEM; + else + return 0; +} + +void event_exit(void) +{ + if (nl) + sock_release(nl->sk_socket); +} --- linux-2.6.27.orig/ubuntu/iscsitarget/wthread.c +++ linux-2.6.27/ubuntu/iscsitarget/wthread.c @@ -0,0 +1,187 @@ +/* + * Worker thread. + * (C) 2004 - 2005 FUJITA Tomonori + * This code is licenced under the GPL. + */ + +#include + +#include "iscsi.h" +#include "iscsi_dbg.h" + +void wthread_queue(struct iscsi_cmnd *cmnd) +{ + struct worker_thread_info *info = &cmnd->conn->session->target->wthread_info; + + if (!list_empty(&cmnd->list)) { + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + eprintk("%x %p %x %x %x %x %lx %x\n", + cmnd_itt(cmnd), req, req->opcode, req->scb[0], cmnd->pdu.datasize, + be32_to_cpu(req->data_length), cmnd->flags, req->flags); + + if (cmnd->lun) + eprintk("%u\n", cmnd->lun->lun); + assert(list_empty(&cmnd->list)); + } + + spin_lock(&info->wthread_lock); + list_add_tail(&cmnd->list, &info->work_queue); + spin_unlock(&info->wthread_lock); + + atomic_inc(&cmnd->conn->nr_busy_cmnds); + + wake_up(&info->wthread_sleep); +} + +static struct iscsi_cmnd * get_ready_cmnd(struct worker_thread_info *info) +{ + struct iscsi_cmnd *cmnd = NULL; + + spin_lock(&info->wthread_lock); + if (!list_empty(&info->work_queue)) { + cmnd = list_entry(info->work_queue.next, struct iscsi_cmnd, list); + list_del_init(&cmnd->list); + + assert(cmnd->conn); + } + spin_unlock(&info->wthread_lock); + + return cmnd; +} + +static int cmnd_execute(struct iscsi_cmnd *cmnd) +{ + int type = cmnd->conn->session->target->trgt_param.target_type; + + assert(target_type_array[type]->execute_cmnd); + return target_type_array[type]->execute_cmnd(cmnd); +} + +static int worker_thread(void *arg) +{ + struct worker_thread *wt = (struct worker_thread *) arg; + struct worker_thread_info *info = wt->w_info; + struct iscsi_cmnd *cmnd; + struct iscsi_conn *conn; + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&info->wthread_sleep, &wait); + + __set_current_state(TASK_RUNNING); + do { + while (!list_empty(&info->work_queue) && + (cmnd = get_ready_cmnd(info))) { + conn = cmnd->conn; + cmnd_execute(cmnd); + assert(conn); + atomic_dec(&conn->nr_busy_cmnds); + } + + __set_current_state(TASK_INTERRUPTIBLE); + if (list_empty(&info->work_queue)) + schedule(); + + __set_current_state(TASK_RUNNING); + } while (!kthread_should_stop()); + + remove_wait_queue(&info->wthread_sleep, &wait); + + return 0; +} + +static int start_one_worker_thread(struct iscsi_target *target) +{ + struct worker_thread_info *info = &target->wthread_info; + struct worker_thread *wt; + struct task_struct *task; + + if (!(wt = kmalloc(sizeof(struct worker_thread), GFP_KERNEL))) + return -ENOMEM; + + wt->w_info = info; + task = kthread_create(worker_thread, wt, "istiod%d", target->tid); + if (IS_ERR(task)) { + kfree(wt); + return PTR_ERR(task); + } + + wt->w_task = task; + list_add(&wt->w_list, &info->wthread_list); + info->nr_running_wthreads++; + + wake_up_process(task); + + return 0; +} + +static int stop_one_worker_thread(struct worker_thread *wt) +{ + struct worker_thread_info *info = wt->w_info; + int err; + + assert(wt->w_task); + if ((err = kthread_stop(wt->w_task)) < 0) + return err; + + list_del(&wt->w_list); + kfree(wt); + info->nr_running_wthreads--; + + return 0; +} + +int wthread_init(struct iscsi_target *target) +{ + struct worker_thread_info *info = &target->wthread_info; + + spin_lock_init(&info->wthread_lock); + + info->nr_running_wthreads = 0; + + INIT_LIST_HEAD(&info->work_queue); + INIT_LIST_HEAD(&info->wthread_list); + + init_waitqueue_head(&info->wthread_sleep); + + return 0; +} + +int wthread_start(struct iscsi_target *target) +{ + int err = 0; + struct worker_thread_info *info = &target->wthread_info; + + while (info->nr_running_wthreads < target->trgt_param.wthreads) { + if ((err = start_one_worker_thread(target)) < 0) { + eprintk("Fail to create a worker thread %d\n", err); + goto out; + } + } + + while (info->nr_running_wthreads > target->trgt_param.wthreads) { + struct worker_thread *wt; + wt = list_entry(info->wthread_list.next, struct worker_thread, w_list); + if ((err = stop_one_worker_thread(wt)) < 0) { + eprintk("Fail to stop a worker thread %d\n", err); + break; + } + } +out: + return err; +} + +int wthread_stop(struct iscsi_target *target) +{ + struct worker_thread *wt, *tmp; + int err = 0; + struct worker_thread_info *info = &target->wthread_info; + + list_for_each_entry_safe(wt, tmp, &info->wthread_list, w_list) { + if ((err = stop_one_worker_thread(wt)) < 0) { + eprintk("Fail to stop a worker thread %d\n", err); + return err; + } + } + + return err; +} --- linux-2.6.27.orig/ubuntu/iscsitarget/Makefile +++ linux-2.6.27/ubuntu/iscsitarget/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for the Linux kernel device drivers. +# + +obj-$(CONFIG_SCSI_ISCSITARGET) += iscsi_trgt.o +iscsi_trgt-objs := tio.o iscsi.o nthread.o wthread.o config.o digest.o \ + conn.o session.o target.o volume.o iotype.o \ + file-io.o null-io.o target_disk.o event.o param.o \ + block-io.o --- linux-2.6.27.orig/ubuntu/iscsitarget/file-io.c +++ linux-2.6.27/ubuntu/iscsitarget/file-io.c @@ -0,0 +1,307 @@ +/* + * Target device file I/O. + * (C) 2004 - 2005 FUJITA Tomonori + * This code is licenced under the GPL. + */ + +#include +#include +#include + +#include "iscsi.h" +#include "iscsi_dbg.h" +#include "iotype.h" + +struct fileio_data { + char *path; + struct file *filp; +}; + +static int fileio_make_request(struct iet_volume *lu, struct tio *tio, int rw) +{ + struct fileio_data *p = lu->private; + struct file *filp; + mm_segment_t oldfs; + struct page *page; + u32 offset, size; + loff_t ppos, count; + char *buf; + int i, err = 0; + ssize_t ret; + + assert(p); + filp = p->filp; + size = tio->size; + offset= tio->offset; + + ppos = (loff_t) tio->idx << PAGE_CACHE_SHIFT; + ppos += offset; + + for (i = 0; i < tio->pg_cnt; i++) { + page = tio->pvec[i]; + assert(page); + buf = page_address(page); + buf += offset; + + if (offset + size > PAGE_CACHE_SIZE) + count = PAGE_CACHE_SIZE - offset; + else + count = size; + + oldfs = get_fs(); + set_fs(get_ds()); + + if (rw == READ) + ret = do_sync_read(filp, buf, count, &ppos); + else + ret = do_sync_write(filp, buf, count, &ppos); + + set_fs(oldfs); + + if (ret != count) { + eprintk("I/O error %lld, %ld\n", count, (long) ret); + err = -EIO; + } + + size -= count; + offset = 0; + } + assert(!size); + + return err; +} + +static int fileio_sync(struct iet_volume *lu, struct tio *tio) +{ + struct fileio_data *p = lu->private; + struct inode *inode = p->filp->f_dentry->d_inode; + struct address_space *mapping = inode->i_mapping; + loff_t ppos, count; + int res; + + if (tio) { + ppos = (loff_t) tio->idx << PAGE_CACHE_SHIFT; + count = tio->size; + } else { + ppos = 0; + count = lu->blk_cnt << lu->blk_shift; + } + + res = sync_page_range(inode, mapping, ppos, count); + if (res) { + eprintk("I/O error: syncing pages failed: %d\n", res); + return -EIO; + } else + return 0; +} + +static int open_path(struct iet_volume *volume, const char *path) +{ + int err = 0; + struct fileio_data *info = volume->private; + struct file *filp; + mm_segment_t oldfs; + int flags; + + info->path = kstrdup(path, GFP_KERNEL); + if (!info->path) + return -ENOMEM; + + oldfs = get_fs(); + set_fs(get_ds()); + flags = (LUReadonly(volume) ? O_RDONLY : O_RDWR) | O_LARGEFILE; + filp = filp_open(path, flags, 0); + set_fs(oldfs); + + if (IS_ERR(filp)) { + err = PTR_ERR(filp); + eprintk("Can't open %s %d\n", path, err); + info->filp = NULL; + } else + info->filp = filp; + + return err; +} + +static int set_scsiid(struct iet_volume *volume, const char *id) +{ + size_t len; + + if ((len = strlen(id)) > SCSI_ID_LEN - VENDOR_ID_LEN) { + eprintk("SCSI ID too long, %zd provided, %u max\n", len, + SCSI_ID_LEN - VENDOR_ID_LEN); + return -EINVAL; + } + + memcpy(volume->scsi_id + VENDOR_ID_LEN, id, len); + + return 0; +} + +static void gen_scsiid(struct iet_volume *volume, struct inode *inode) +{ + int i; + u32 *p; + + strlcpy(volume->scsi_id, VENDOR_ID, VENDOR_ID_LEN); + + for (i = VENDOR_ID_LEN; i < SCSI_ID_LEN; i++) + if (volume->scsi_id[i]) + return; + + p = (u32 *) (volume->scsi_id + VENDOR_ID_LEN); + *(p + 0) = volume->target->trgt_param.target_type; + *(p + 1) = volume->target->tid; + *(p + 2) = (unsigned int) inode->i_ino; + *(p + 3) = (unsigned int) inode->i_sb->s_dev; +} + +static int set_scsisn(struct iet_volume *volume, const char *sn) +{ + size_t len; + + if ((len = strlen(sn)) > SCSI_SN_LEN) { + eprintk("SCSI SN too long, %zd provided, %u max\n", len, + SCSI_SN_LEN); + return -EINVAL; + } + memcpy(volume->scsi_sn, sn, len); + return 0; +} + +enum { + Opt_scsiid, Opt_scsisn, Opt_path, Opt_ignore, Opt_err, +}; + +static match_table_t tokens = { + {Opt_scsiid, "ScsiId=%s"}, + {Opt_scsisn, "ScsiSN=%s"}, + {Opt_path, "Path=%s"}, + {Opt_ignore, "Type=%s"}, + {Opt_ignore, "IOMode=%s"}, + {Opt_err, NULL}, +}; + +static int parse_fileio_params(struct iet_volume *volume, char *params) +{ + int err = 0; + char *p, *q; + + while ((p = strsep(¶ms, ",")) != NULL) { + substring_t args[MAX_OPT_ARGS]; + int token; + if (!*p) + continue; + token = match_token(p, tokens, args); + switch (token) { + case Opt_scsiid: + if (!(q = match_strdup(&args[0]))) { + err = -ENOMEM; + goto out; + } + err = set_scsiid(volume, q); + kfree(q); + if (err < 0) + goto out; + break; + case Opt_scsisn: + if (!(q = match_strdup(&args[0]))) { + err = -ENOMEM; + goto out; + } + err = set_scsisn(volume, q); + kfree(q); + if (err < 0) + goto out; + break; + case Opt_path: + if (!(q = match_strdup(&args[0]))) { + err = -ENOMEM; + goto out; + } + err = open_path(volume, q); + kfree(q); + if (err < 0) + goto out; + break; + case Opt_ignore: + break; + default: + eprintk("Unknown %s\n", p); + return -EINVAL; + } + } + +out: + return err; +} + +static void fileio_detach(struct iet_volume *lu) +{ + struct fileio_data *p = lu->private; + + kfree(p->path); + if (p->filp) + filp_close(p->filp, NULL); + kfree(p); + lu->private = NULL; +} + +static int fileio_attach(struct iet_volume *lu, char *args) +{ + int err = 0; + struct fileio_data *p; + struct inode *inode; + + if (lu->private) { + printk("already attached ? %d\n", lu->lun); + return -EBUSY; + } + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + + lu->private = p; + + if ((err = parse_fileio_params(lu, args)) < 0) { + eprintk("%d\n", err); + goto out; + } + inode = p->filp->f_dentry->d_inode; + + gen_scsiid(lu, inode); + + if (S_ISREG(inode->i_mode)) + ; + else if (S_ISBLK(inode->i_mode)) + inode = inode->i_bdev->bd_inode; + else { + err = -EINVAL; + goto out; + } + + lu->blk_shift = SECTOR_SIZE_BITS; + lu->blk_cnt = inode->i_size >> lu->blk_shift; + +out: + if (err < 0) + fileio_detach(lu); + return err; +} + +void fileio_show(struct iet_volume *lu, struct seq_file *seq) +{ + struct fileio_data *p = lu->private; + seq_printf(seq, " path:%s\n", p->path); +} + +struct iotype fileio = +{ + .name = "fileio", + .attach = fileio_attach, + .make_request = fileio_make_request, + .sync = fileio_sync, + .detach = fileio_detach, + .show = fileio_show, +}; --- linux-2.6.27.orig/ubuntu/iscsitarget/block-io.c +++ linux-2.6.27/ubuntu/iscsitarget/block-io.c @@ -0,0 +1,372 @@ +/* + * Target device block I/O. + * + * Based on file I/O driver from FUJITA Tomonori + * (C) 2004 - 2005 FUJITA Tomonori + * (C) 2006 Andre Brinkmann + * (C) 2007 Ross Walker + * (C) 2007 Ming Zhang + * This code is licenced under the GPL. + */ +#include +#include +#include +#include + +#include "iscsi.h" +#include "iscsi_dbg.h" +#include "iotype.h" + +struct blockio_data { + char *path; + struct block_device *bdev; +}; + +struct tio_work { + atomic_t error; + atomic_t bios_remaining; + struct completion tio_complete; +}; + +static void blockio_bio_endio(struct bio *bio, int error) +{ + struct tio_work *tio_work = bio->bi_private; + + error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? error : -EIO; + + if (error) + atomic_set(&tio_work->error, error); + + /* If last bio signal completion */ + if (atomic_dec_and_test(&tio_work->bios_remaining)) + complete(&tio_work->tio_complete); + + bio_put(bio); +} + +/* + * Blockio_make_request(): The function translates an iscsi-request into + * a number of requests to the corresponding block device. + */ +static int +blockio_make_request(struct iet_volume *volume, struct tio *tio, int rw) +{ + struct blockio_data *bio_data = volume->private; + struct request_queue *bdev_q = bdev_get_queue(bio_data->bdev); + struct tio_work *tio_work; + struct bio *tio_bio = NULL, *bio = NULL, *biotail = NULL; + + u32 offset = tio->offset; + u32 size = tio->size; + u32 tio_index = 0; + + int max_pages = 1; + int err = 0; + + loff_t ppos = ((loff_t) tio->idx << PAGE_SHIFT) + offset; + + /* Calculate max_pages for bio_alloc (memory saver) */ + if (bdev_q) + max_pages = bio_get_nr_vecs(bio_data->bdev); + + tio_work = kzalloc(sizeof (*tio_work), GFP_KERNEL); + if (!tio_work) + return -ENOMEM; + + atomic_set(&tio_work->error, 0); + atomic_set(&tio_work->bios_remaining, 0); + init_completion(&tio_work->tio_complete); + + /* Main processing loop, allocate and fill all bios */ + while (tio_index < tio->pg_cnt) { + bio = bio_alloc(GFP_KERNEL, min(max_pages, BIO_MAX_PAGES)); + if (!bio) { + err = -ENOMEM; + goto out; + } + + bio->bi_sector = ppos >> volume->blk_shift; + bio->bi_bdev = bio_data->bdev; + bio->bi_end_io = blockio_bio_endio; + bio->bi_private = tio_work; + + if (tio_bio) + biotail = biotail->bi_next = bio; + else + tio_bio = biotail = bio; + + atomic_inc(&tio_work->bios_remaining); + + /* Loop for filling bio */ + while (tio_index < tio->pg_cnt) { + unsigned int bytes = PAGE_SIZE - offset; + + if (bytes > size) + bytes = size; + + if (!bio_add_page(bio, tio->pvec[tio_index], bytes, offset)) + break; + + size -= bytes; + ppos += bytes; + + offset = 0; + + tio_index++; + } + } + + /* Walk the list, submitting bios 1 by 1 */ + while (tio_bio) { + bio = tio_bio; + tio_bio = tio_bio->bi_next; + bio->bi_next = NULL; + + submit_bio(rw, bio); + } + + if (bdev_q && bdev_q->unplug_fn) + bdev_q->unplug_fn(bdev_q); + + wait_for_completion(&tio_work->tio_complete); + + err = atomic_read(&tio_work->error); + + kfree(tio_work); + + return err; +out: + while (tio_bio) { + bio = tio_bio; + tio_bio = tio_bio->bi_next; + + bio_put(bio); + } + + kfree(tio_work); + + return err; +} + +static int +blockio_open_path(struct iet_volume *volume, const char *path) +{ + struct blockio_data *bio_data = volume->private; + struct block_device *bdev; + int flags = LUReadonly(volume) ? MS_RDONLY : 0; + int err = 0; + + bio_data->path = kstrdup(path, GFP_KERNEL); + if (!bio_data->path) + return -ENOMEM; + + bdev = open_bdev_excl(path, flags, THIS_MODULE); + if (IS_ERR(bdev)) { + err = PTR_ERR(bdev); + eprintk("Can't open device %s, error %d\n", path, err); + bio_data->bdev = NULL; + } else { + bio_data->bdev = bdev; + fsync_bdev(bio_data->bdev); + } + + return err; +} + +static int +set_scsiid(struct iet_volume *volume, const char *id) +{ + size_t len; + + if ((len = strlen(id)) > SCSI_ID_LEN - VENDOR_ID_LEN) { + eprintk("SCSI ID too long, %zd provided, %u max\n", len, + SCSI_ID_LEN - VENDOR_ID_LEN); + return -EINVAL; + } + + memcpy(volume->scsi_id + VENDOR_ID_LEN, id, len); + + return 0; +} + +static void +gen_scsiid(struct iet_volume *volume, struct inode *inode) +{ + int i; + u32 *p; + + strlcpy(volume->scsi_id, VENDOR_ID, VENDOR_ID_LEN); + + for (i = VENDOR_ID_LEN; i < SCSI_ID_LEN; i++) + if (volume->scsi_id[i]) + return; + + /* If a scsi id doesn't exist generate a 16 byte one: + * Bytes 1-4: target type + * Bytes 5-8: target id + * Bytes 9-12: inode number + * Bytes 13-16: device type + */ + p = (u32 *) (volume->scsi_id + VENDOR_ID_LEN); + *(p + 0) = volume->target->trgt_param.target_type; + *(p + 1) = volume->target->tid; + *(p + 2) = volume->lun; + *(p + 3) = (unsigned int) inode->i_sb->s_dev; +} + +static int +set_scsisn(struct iet_volume *volume, const char *sn) +{ + size_t len; + + if ((len = strlen(sn)) > SCSI_SN_LEN) { + eprintk("SCSI SN too long, %zd provided, %u max\n", len, + SCSI_SN_LEN); + return -EINVAL; + } + + memcpy(volume->scsi_sn, sn, len); + + return 0; +} + +/* Create an enumeration of our accepted actions */ +enum +{ + Opt_scsiid, Opt_scsisn, Opt_path, Opt_ignore, Opt_err, +}; + +/* Create a match table using our action enums and their matching options */ +static match_table_t tokens = { + {Opt_scsiid, "ScsiId=%s"}, + {Opt_scsisn, "ScsiSN=%s"}, + {Opt_path, "Path=%s"}, + {Opt_ignore, "Type=%s"}, + {Opt_ignore, "IOMode=%s"}, + {Opt_err, NULL}, +}; + +static int +parse_blockio_params (struct iet_volume *volume, char *params) +{ + int err = 0; + char *p, *q; + + /* Loop through parameters separated by commas, look up our + * parameter in match table, return enumeration and arguments + * select case based on the returned enum and run the action */ + while ((p = strsep(¶ms, ",")) != NULL) { + substring_t args[MAX_OPT_ARGS]; + int token; + if (!*p) + continue; + token = match_token(p, tokens, args); + switch (token) { + case Opt_scsiid: + if (!(q = match_strdup(&args[0]))) { + err = -ENOMEM; + goto out; + } + err = set_scsiid(volume, q); + kfree(q); + if (err < 0) + goto out; + break; + case Opt_scsisn: + if (!(q = match_strdup(&args[0]))) { + err = -ENOMEM; + goto out; + } + err = set_scsisn(volume, q); + kfree(q); + if (err < 0) + goto out; + break; + case Opt_path: + if (!(q = match_strdup(&args[0]))) { + err = -ENOMEM; + goto out; + } + err = blockio_open_path(volume, q); + kfree(q); + if (err < 0) + goto out; + break; + case Opt_ignore: + break; + default: + eprintk("Bad option %s for Lun %u on Target %s \n", + p, volume->lun, volume->target->name); + return -EINVAL; + } + } + + out: + return err; +} + +static void +blockio_detach(struct iet_volume *volume) +{ + struct blockio_data *bio_data = volume->private; + + if (bio_data->bdev) + close_bdev_excl(bio_data->bdev); + kfree(bio_data->path); + + kfree(volume->private); +} + +static int +blockio_attach (struct iet_volume *volume, char *args) +{ + struct blockio_data *bio_data; + int err = 0; + + if (volume->private) { + eprintk("Lun %u already attached on Target %s \n", + volume->lun, volume->target->name); + return -EBUSY; + } + + bio_data = kzalloc(sizeof (*bio_data), GFP_KERNEL); + if (!bio_data) + return -ENOMEM; + + volume->private = bio_data; + + if ((err = parse_blockio_params(volume, args)) < 0) { + eprintk("Error attaching Lun %u to Target %s \n", + volume->lun, volume->target->name); + goto out; + } + + /* Assign a vendor id, generate scsi id if none exists */ + gen_scsiid(volume, bio_data->bdev->bd_inode); + + volume->blk_shift = SECTOR_SIZE_BITS; + volume->blk_cnt = bio_data->bdev->bd_inode->i_size >> volume->blk_shift; + + out: + if (err < 0) + blockio_detach(volume); + + return err; +} + +static void +blockio_show(struct iet_volume *volume, struct seq_file *seq) +{ + struct blockio_data *bio_data = volume->private; + + /* Used to display blockio volume info in /proc/net/iet/volumes */ + seq_printf(seq, " path:%s\n", bio_data->path); +} + +struct iotype blockio = { + .name = "blockio", + .attach = blockio_attach, + .make_request = blockio_make_request, + .detach = blockio_detach, + .show = blockio_show, +}; --- linux-2.6.27.orig/ubuntu/iscsitarget/digest.c +++ linux-2.6.27/ubuntu/iscsitarget/digest.c @@ -0,0 +1,280 @@ +/* + * iSCSI digest handling. + * (C) 2004 - 2006 Xiranet Communications GmbH + * This code is licensed under the GPL. + */ + +#include +#include + +#include "iscsi.h" +#include "digest.h" +#include "iscsi_dbg.h" + +void digest_alg_available(unsigned int *val) +{ + if (*val & DIGEST_CRC32C && + !crypto_has_alg("crc32c", 0, CRYPTO_ALG_ASYNC)) { + printk("CRC32C digest algorithm not available in kernel\n"); + *val |= ~DIGEST_CRC32C; + } +} + +/** + * initialize support for digest calculation. + * + * digest_init - + * @conn: ptr to connection to make use of digests + * + * @return: 0 on success, < 0 on error + */ +int digest_init(struct iscsi_conn *conn) +{ + int err = 0; + + if (!(conn->hdigest_type & DIGEST_ALL)) + conn->hdigest_type = DIGEST_NONE; + + if (!(conn->ddigest_type & DIGEST_ALL)) + conn->ddigest_type = DIGEST_NONE; + + if (conn->hdigest_type & DIGEST_CRC32C || + conn->ddigest_type & DIGEST_CRC32C) { + conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0, + CRYPTO_ALG_ASYNC); + conn->rx_hash.flags = 0; + if (IS_ERR(conn->rx_hash.tfm)) { + conn->rx_hash.tfm = NULL; + err = -ENOMEM; + goto out; + } + + conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0, + CRYPTO_ALG_ASYNC); + conn->tx_hash.flags = 0; + if (IS_ERR(conn->tx_hash.tfm)) { + conn->tx_hash.tfm = NULL; + err = -ENOMEM; + goto out; + } + } + +out: + if (err) + digest_cleanup(conn); + + return err; +} + +/** + * free resources used for digest calculation. + * + * digest_cleanup - + * @conn: ptr to connection that made use of digests + */ +void digest_cleanup(struct iscsi_conn *conn) +{ + if (conn->tx_hash.tfm) + crypto_free_hash(conn->tx_hash.tfm); + if (conn->rx_hash.tfm) + crypto_free_hash(conn->rx_hash.tfm); +} + +/** + * debug handling of header digest errors: + * simulates a digest error after n PDUs / every n-th PDU of type + * HDIGEST_ERR_CORRUPT_PDU_TYPE. + */ +static inline void __dbg_simulate_header_digest_error(struct iscsi_cmnd *cmnd) +{ +#define HDIGEST_ERR_AFTER_N_CMNDS 1000 +#define HDIGEST_ERR_ONLY_ONCE 1 +#define HDIGEST_ERR_CORRUPT_PDU_TYPE ISCSI_OP_SCSI_CMD +#define HDIGEST_ERR_CORRUPT_PDU_WITH_DATA_ONLY 0 + + static int num_cmnds = 0; + static int num_errs = 0; + + if (cmnd_opcode(cmnd) == HDIGEST_ERR_CORRUPT_PDU_TYPE) { + if (HDIGEST_ERR_CORRUPT_PDU_WITH_DATA_ONLY) { + if (cmnd->pdu.datasize) + num_cmnds++; + } else + num_cmnds++; + } + + if ((num_cmnds == HDIGEST_ERR_AFTER_N_CMNDS) + && (!(HDIGEST_ERR_ONLY_ONCE && num_errs))) { + printk("*** Faking header digest error ***\n"); + printk("\tcmnd: 0x%x, itt 0x%x, sn 0x%x\n", + cmnd_opcode(cmnd), + be32_to_cpu(cmnd->pdu.bhs.itt), + be32_to_cpu(cmnd->pdu.bhs.sn)); + cmnd->hdigest = ~cmnd->hdigest; + /* make things even worse by manipulating header fields */ + cmnd->pdu.datasize += 8; + num_errs++; + num_cmnds = 0; + } + return; +} + +/** + * debug handling of data digest errors: + * simulates a digest error after n PDUs / every n-th PDU of type + * DDIGEST_ERR_CORRUPT_PDU_TYPE. + */ +static inline void __dbg_simulate_data_digest_error(struct iscsi_cmnd *cmnd) +{ +#define DDIGEST_ERR_AFTER_N_CMNDS 50 +#define DDIGEST_ERR_ONLY_ONCE 1 +#define DDIGEST_ERR_CORRUPT_PDU_TYPE ISCSI_OP_SCSI_DATA_OUT +#define DDIGEST_ERR_CORRUPT_UNSOL_DATA_ONLY 0 + + static int num_cmnds = 0; + static int num_errs = 0; + + if ((cmnd->pdu.datasize) + && (cmnd_opcode(cmnd) == DDIGEST_ERR_CORRUPT_PDU_TYPE)) { + switch (cmnd_opcode(cmnd)) { + case ISCSI_OP_SCSI_DATA_OUT: + if ((DDIGEST_ERR_CORRUPT_UNSOL_DATA_ONLY) + && (cmnd->pdu.bhs.ttt != ISCSI_RESERVED_TAG)) + break; + default: + num_cmnds++; + } + } + + if ((num_cmnds == DDIGEST_ERR_AFTER_N_CMNDS) + && (!(DDIGEST_ERR_ONLY_ONCE && num_errs)) + && (cmnd->pdu.datasize) + && (!cmnd->conn->read_overflow)) { + printk("*** Faking data digest error: ***"); + printk("\tcmnd 0x%x, itt 0x%x, sn 0x%x\n", + cmnd_opcode(cmnd), + be32_to_cpu(cmnd->pdu.bhs.itt), + be32_to_cpu(cmnd->pdu.bhs.sn)); + cmnd->ddigest = ~cmnd->ddigest; + num_errs++; + num_cmnds = 0; + } +} + +static void digest_header(struct hash_desc *hash, struct iscsi_pdu *pdu, + u8 *crc) +{ + struct scatterlist sg[2]; + unsigned int nbytes = sizeof(struct iscsi_hdr); + + sg_init_table(sg, pdu->ahssize ? 2 : 1); + + sg_set_buf(&sg[0], &pdu->bhs, nbytes); + if (pdu->ahssize) { + sg_set_buf(&sg[1], pdu->ahs, pdu->ahssize); + nbytes += pdu->ahssize; + } + + crypto_hash_init(hash); + crypto_hash_update(hash, sg, nbytes); + crypto_hash_final(hash, crc); +} + +int digest_rx_header(struct iscsi_cmnd *cmnd) +{ + u32 crc; + + digest_header(&cmnd->conn->rx_hash, &cmnd->pdu, (u8 *) &crc); + if (crc != cmnd->hdigest) + return -EIO; + + return 0; +} + +void digest_tx_header(struct iscsi_cmnd *cmnd) +{ + digest_header(&cmnd->conn->tx_hash, &cmnd->pdu, (u8 *) &cmnd->hdigest); +} + +static void digest_data(struct hash_desc *hash, struct iscsi_cmnd *cmnd, + struct tio *tio, u32 offset, u8 *crc) +{ + struct scatterlist *sg = cmnd->conn->hash_sg; + u32 size, length; + int i, idx, count; + unsigned int nbytes; + + size = cmnd->pdu.datasize; + nbytes = size = (size + 3) & ~3; + + offset += tio->offset; + idx = offset >> PAGE_CACHE_SHIFT; + offset &= ~PAGE_CACHE_MASK; + count = get_pgcnt(size, offset); + assert(idx + count <= tio->pg_cnt); + + assert(count <= ISCSI_CONN_IOV_MAX); + + sg_init_table(sg, ARRAY_SIZE(cmnd->conn->hash_sg)); + crypto_hash_init(hash); + + for (i = 0; size; i++) { + if (offset + size > PAGE_CACHE_SIZE) + length = PAGE_CACHE_SIZE - offset; + else + length = size; + + sg_set_page(&sg[i], tio->pvec[idx + i], length, offset); + size -= length; + offset = 0; + } + + sg_mark_end(&sg[i - 1]); + + crypto_hash_update(hash, sg, nbytes); + crypto_hash_final(hash, crc); +} + +int digest_rx_data(struct iscsi_cmnd *cmnd) +{ + struct tio *tio; + struct iscsi_cmnd *scsi_cmnd; + struct iscsi_data_out_hdr *req; + u32 offset, crc; + + switch (cmnd_opcode(cmnd)) { + case ISCSI_OP_SCSI_REJECT: + case ISCSI_OP_PDU_REJECT: + case ISCSI_OP_DATA_REJECT: + return 0; + case ISCSI_OP_SCSI_DATA_OUT: + scsi_cmnd = cmnd->req; + req = (struct iscsi_data_out_hdr *) &cmnd->pdu.bhs; + tio = scsi_cmnd->tio; + offset = be32_to_cpu(req->buffer_offset); + break; + default: + tio = cmnd->tio; + offset = 0; + } + + digest_data(&cmnd->conn->rx_hash, cmnd, tio, offset, (u8 *) &crc); + + if (!cmnd->conn->read_overflow && + (cmnd_opcode(cmnd) != ISCSI_OP_PDU_REJECT)) { + if (crc != cmnd->ddigest) + return -EIO; + } + + return 0; +} + +void digest_tx_data(struct iscsi_cmnd *cmnd) +{ + struct tio *tio = cmnd->tio; + struct iscsi_data_out_hdr *req = (struct iscsi_data_out_hdr *)&cmnd->pdu.bhs; + + assert(tio); + digest_data(&cmnd->conn->tx_hash, cmnd, tio, + be32_to_cpu(req->buffer_offset), (u8 *) &cmnd->ddigest); +} --- linux-2.6.27.orig/ubuntu/iscsitarget/volume.c +++ linux-2.6.27/ubuntu/iscsitarget/volume.c @@ -0,0 +1,262 @@ +/* + * Volume manager + * (C) 2004 - 2005 FUJITA Tomonori + * This code is licenced under the GPL. + */ + +#include "iscsi.h" +#include "iscsi_dbg.h" +#include "iotype.h" + +#include + +struct iet_volume *volume_lookup(struct iscsi_target *target, u32 lun) +{ + struct iet_volume *volume; + + list_for_each_entry(volume, &target->volumes, list) { + if (volume->lun == lun) + return volume; + } + return NULL; +} + +enum { + Opt_type, + Opt_iomode, + Opt_err, +}; + +static match_table_t tokens = { + {Opt_type, "Type=%s"}, + {Opt_iomode, "IOMode=%s"}, + {Opt_err, NULL}, +}; + +static int set_iotype(struct iet_volume *volume, char *params) +{ + int err = 0; + substring_t args[MAX_OPT_ARGS]; + char *p, *argp = NULL, *buf = (char *) get_zeroed_page(GFP_USER); + + if (!buf) + return -ENOMEM; + strncpy(buf, params, PAGE_CACHE_SIZE); + + while ((p = strsep(&buf, ",")) != NULL) { + int token; + + if (!*p) + continue; + token = match_token(p, tokens, args); + switch (token) { + case Opt_type: + if (!(argp = match_strdup(&args[0]))) + err = -ENOMEM; + if (argp && !(volume->iotype = get_iotype(argp))) + err = -ENOENT; + kfree(argp); + break; + case Opt_iomode: + if (!(argp = match_strdup(&args[0]))) + err = -ENOMEM; + if (argp && !strcmp(argp, "ro")) + SetLUReadonly(volume); + else if (argp && !strcmp(argp, "wb")) + SetLUAsync(volume); + kfree(argp); + break; + default: + break; + } + } + + if (!err && !volume->iotype && !(volume->iotype = get_iotype("fileio"))) { + eprintk("%s\n", "Cannot find fileio"); + err = -EINVAL; + } + + free_page((unsigned long) buf); + + return err; +} + +int volume_add(struct iscsi_target *target, struct volume_info *info) +{ + int ret; + struct iet_volume *volume; + char *args; + + volume = volume_lookup(target, info->lun); + if (volume) + return -EEXIST; + + if (info->lun > 0x3fff) + return -EINVAL; + + volume = kzalloc(sizeof(*volume), GFP_KERNEL); + if (!volume) + return -ENOMEM; + + volume->target = target; + volume->lun = info->lun; + + args = kzalloc(info->args_len + 1, GFP_KERNEL); + if (!args) { + ret = -ENOMEM; + goto free_volume; + } + + ret = copy_from_user(args, (void *)(unsigned long)info->args_ptr, + info->args_len); + if (ret) { + ret = -EFAULT; + goto free_args; + } + + ret = set_iotype(volume, args); + if (ret < 0) + goto free_args; + + ret = volume->iotype->attach(volume, args); + if (ret < 0) + goto free_args; + + INIT_LIST_HEAD(&volume->queue.wait_list); + spin_lock_init(&volume->queue.queue_lock); + spin_lock_init(&volume->reserve_lock); + + volume->l_state = IDEV_RUNNING; + atomic_set(&volume->l_count, 0); + + list_add_tail(&volume->list, &target->volumes); + atomic_inc(&target->nr_volumes); + + kfree(args); + + return 0; +free_args: + kfree(args); +free_volume: + put_iotype(volume->iotype); + kfree(volume); + + return ret; +} + +void iscsi_volume_destroy(struct iet_volume *volume) +{ + assert(volume->l_state == IDEV_DEL); + assert(!atomic_read(&volume->l_count)); + + volume->iotype->detach(volume); + put_iotype(volume->iotype); + list_del(&volume->list); + kfree(volume); +} + +int iscsi_volume_del(struct iscsi_target *target, struct volume_info *info) +{ + struct iet_volume *volume; + + eprintk("%x %x\n", target->tid, info->lun); + if (!(volume = volume_lookup(target, info->lun))) + return -ENOENT; + + volume->l_state = IDEV_DEL; + atomic_dec(&target->nr_volumes); + if (!atomic_read(&volume->l_count)) + iscsi_volume_destroy(volume); + + return 0; +} + +struct iet_volume *volume_get(struct iscsi_target *target, u32 lun) +{ + struct iet_volume *volume; + + if ((volume = volume_lookup(target, lun))) { + if (volume->l_state == IDEV_RUNNING) + atomic_inc(&volume->l_count); + else + volume = NULL; + } + return volume; +} + +void volume_put(struct iet_volume *volume) +{ + if (atomic_dec_and_test(&volume->l_count) && volume->l_state == IDEV_DEL) + iscsi_volume_destroy(volume); +} + +int volume_reserve(struct iet_volume *volume, u64 sid) +{ + if (!volume) + return -ENOENT; + + spin_lock(&volume->reserve_lock); + if (volume->reserve_sid && volume->reserve_sid != sid) { + spin_unlock(&volume->reserve_lock); + return -EBUSY; + } + + volume->reserve_sid = sid; + spin_unlock(&volume->reserve_lock); + + return 0; +} + +int is_volume_reserved(struct iet_volume *volume, u64 sid) +{ + if (!volume || !volume->reserve_sid || volume->reserve_sid == sid) + return 0; + + return -EBUSY; +} + +int volume_release(struct iet_volume *volume, u64 sid, int force) +{ + if (force || volume->reserve_sid == sid) + volume->reserve_sid = 0; + + return 0; +} + +static void iet_volume_info_show(struct seq_file *seq, struct iscsi_target *target) +{ + struct iet_volume *volume; + + list_for_each_entry(volume, &target->volumes, list) { + seq_printf(seq, "\tlun:%u state:%x iotype:%s", + volume->lun, volume->l_state, volume->iotype->name); + if (LUReadonly(volume)) + seq_printf(seq, " iomode:ro"); + else if (LUAsync(volume)) + seq_printf(seq, " iomode:wb"); + else + seq_printf(seq, " iomode:wt"); + if (volume->iotype->show) + volume->iotype->show(volume, seq); + else + seq_printf(seq, "\n"); + } +} + +static int iet_volumes_info_show(struct seq_file *seq, void *v) +{ + return iet_info_show(seq, iet_volume_info_show); +} + +static int iet_volume_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, iet_volumes_info_show, NULL); +} + +struct file_operations volume_seq_fops = { + .owner = THIS_MODULE, + .open = iet_volume_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; --- linux-2.6.27.orig/ubuntu/iscsitarget/iscsi.c +++ linux-2.6.27/ubuntu/iscsitarget/iscsi.c @@ -0,0 +1,1787 @@ +/* + * Copyright (C) 2002-2003 Ardis Technolgies + * + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include + +#include "iscsi.h" +#include "iscsi_dbg.h" +#include "iotype.h" + +unsigned long debug_enable_flags; + +static struct kmem_cache *iscsi_cmnd_cache; +static char dummy_data[1024]; + +static int ctr_major; +static char ctr_name[] = "ietctl"; +extern struct file_operations ctr_fops; + +static u32 cmnd_write_size(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *hdr = cmnd_hdr(cmnd); + + if (hdr->flags & ISCSI_CMD_WRITE) + return be32_to_cpu(hdr->data_length); + return 0; +} + +static u32 cmnd_read_size(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *hdr = cmnd_hdr(cmnd); + + if (hdr->flags & ISCSI_CMD_READ) { + struct iscsi_rlength_ahdr *ahdr = + (struct iscsi_rlength_ahdr *)cmnd->pdu.ahs; + + if (!(hdr->flags & ISCSI_CMD_WRITE)) + return be32_to_cpu(hdr->data_length); + if (ahdr && ahdr->ahstype == ISCSI_AHSTYPE_RLENGTH) + return be32_to_cpu(ahdr->read_length); + } + return 0; +} + +static void iscsi_device_queue_cmnd(struct iscsi_cmnd *cmnd) +{ + set_cmnd_waitio(cmnd); + wthread_queue(cmnd); +} + +static void iscsi_scsi_queuecmnd(struct iscsi_cmnd *cmnd) +{ + struct iscsi_queue *queue = &cmnd->lun->queue; + + dprintk(D_GENERIC, "%p\n", cmnd); + + if ((cmnd->pdu.bhs.flags & ISCSI_CMD_ATTR_MASK) != ISCSI_CMD_UNTAGGED && + (cmnd->pdu.bhs.flags & ISCSI_CMD_ATTR_MASK) != ISCSI_CMD_SIMPLE) { + cmnd->pdu.bhs.flags &= ~ISCSI_CMD_ATTR_MASK; + cmnd->pdu.bhs.flags |= ISCSI_CMD_UNTAGGED; + } + + spin_lock(&queue->queue_lock); + + set_cmnd_queued(cmnd); + + switch (cmnd->pdu.bhs.flags & ISCSI_CMD_ATTR_MASK) { + case ISCSI_CMD_UNTAGGED: + case ISCSI_CMD_SIMPLE: + if (!list_empty(&queue->wait_list) || queue->ordered_cmnd) + goto pending; + queue->active_cnt++; + break; + + default: + BUG(); + } + spin_unlock(&queue->queue_lock); + + iscsi_device_queue_cmnd(cmnd); + return; + pending: + assert(list_empty(&cmnd->list)); + + list_add_tail(&cmnd->list, &queue->wait_list); + spin_unlock(&queue->queue_lock); + return; +} + +static void iscsi_scsi_dequeuecmnd(struct iscsi_cmnd *cmnd) +{ + struct iscsi_queue *queue; + + if (!cmnd->lun) + return; + queue = &cmnd->lun->queue; + spin_lock(&queue->queue_lock); + switch (cmnd->pdu.bhs.flags & ISCSI_CMD_ATTR_MASK) { + case ISCSI_CMD_UNTAGGED: + case ISCSI_CMD_SIMPLE: + --queue->active_cnt; + break; + case ISCSI_CMD_ORDERED: + case ISCSI_CMD_HEAD_OF_QUEUE: + case ISCSI_CMD_ACA: + BUG(); + default: + /* Should the iscsi_scsi_queuecmnd func reject this ? */ + break; + } + + while (!list_empty(&queue->wait_list)) { + cmnd = list_entry(queue->wait_list.next, struct iscsi_cmnd, list); + switch ((cmnd->pdu.bhs.flags & ISCSI_CMD_ATTR_MASK)) { + case ISCSI_CMD_UNTAGGED: + case ISCSI_CMD_SIMPLE: + list_del_init(&cmnd->list); + queue->active_cnt++; + iscsi_device_queue_cmnd(cmnd); + break; + case ISCSI_CMD_ORDERED: + case ISCSI_CMD_HEAD_OF_QUEUE: + case ISCSI_CMD_ACA: + BUG(); + } + } + + spin_unlock(&queue->queue_lock); + + return; +} + +/** + * create a new command. + * + * iscsi_cmnd_create - + * @conn: ptr to connection (for i/o) + * + * @return ptr to command or NULL + */ + +struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *conn, int req) +{ + struct iscsi_cmnd *cmnd; + + /* TODO: async interface is necessary ? */ + cmnd = kmem_cache_alloc(iscsi_cmnd_cache, GFP_KERNEL|__GFP_NOFAIL); + + memset(cmnd, 0, sizeof(*cmnd)); + INIT_LIST_HEAD(&cmnd->list); + INIT_LIST_HEAD(&cmnd->pdu_list); + INIT_LIST_HEAD(&cmnd->conn_list); + INIT_LIST_HEAD(&cmnd->hash_list); + cmnd->conn = conn; + spin_lock(&conn->list_lock); + atomic_inc(&conn->nr_cmnds); + if (req) + list_add_tail(&cmnd->conn_list, &conn->pdu_list); + spin_unlock(&conn->list_lock); + cmnd->tio = NULL; + + dprintk(D_GENERIC, "%p:%p\n", conn, cmnd); + + return cmnd; +} + +/** + * create a new command used as response. + * + * iscsi_cmnd_create_rsp_cmnd - + * @cmnd: ptr to request command + * + * @return ptr to response command or NULL + */ + +static struct iscsi_cmnd *iscsi_cmnd_create_rsp_cmnd(struct iscsi_cmnd *cmnd, int final) +{ + struct iscsi_cmnd *rsp = cmnd_alloc(cmnd->conn, 0); + + if (final) + set_cmnd_final(rsp); + list_add_tail(&rsp->pdu_list, &cmnd->pdu_list); + rsp->req = cmnd; + return rsp; +} + +static struct iscsi_cmnd *get_rsp_cmnd(struct iscsi_cmnd *req) +{ + return list_entry(req->pdu_list.prev, struct iscsi_cmnd, pdu_list); +} + +static void iscsi_cmnds_init_write(struct list_head *send) +{ + struct iscsi_cmnd *cmnd = list_entry(send->next, struct iscsi_cmnd, list); + struct iscsi_conn *conn = cmnd->conn; + struct list_head *pos, *next; + + spin_lock(&conn->list_lock); + + list_for_each_safe(pos, next, send) { + cmnd = list_entry(pos, struct iscsi_cmnd, list); + + dprintk(D_GENERIC, "%p:%x\n", cmnd, cmnd_opcode(cmnd)); + + list_del_init(&cmnd->list); + assert(conn == cmnd->conn); + list_add_tail(&cmnd->list, &conn->write_list); + } + + spin_unlock(&conn->list_lock); + + nthread_wakeup(conn->session->target); +} + +static void iscsi_cmnd_init_write(struct iscsi_cmnd *cmnd) +{ + LIST_HEAD(head); + + if (!list_empty(&cmnd->list)) { + eprintk("%x %x %x %x %lx %u %u %u %u %u %u %u %d %d\n", + cmnd_itt(cmnd), cmnd_ttt(cmnd), cmnd_opcode(cmnd), + cmnd_scsicode(cmnd), cmnd->flags, cmnd->r2t_sn, + cmnd->r2t_length, cmnd->is_unsolicited_data, + cmnd->target_task_tag, cmnd->outstanding_r2t, + cmnd->hdigest, cmnd->ddigest, + list_empty(&cmnd->pdu_list), list_empty(&cmnd->hash_list)); + + assert(list_empty(&cmnd->list)); + } + list_add(&cmnd->list, &head); + iscsi_cmnds_init_write(&head); +} + +static void do_send_data_rsp(struct iscsi_cmnd *cmnd) +{ + struct iscsi_conn *conn = cmnd->conn; + struct iscsi_cmnd *data_cmnd; + struct tio *tio = cmnd->tio; + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct iscsi_data_in_hdr *rsp; + u32 pdusize, expsize, scsisize, size, offset, sn; + LIST_HEAD(send); + + dprintk(D_GENERIC, "%p\n", cmnd); + pdusize = conn->session->param.max_xmit_data_length; + expsize = cmnd_read_size(cmnd); + size = min(expsize, tio->size); + offset = 0; + sn = 0; + + while (1) { + data_cmnd = iscsi_cmnd_create_rsp_cmnd(cmnd, size <= pdusize); + tio_get(tio); + data_cmnd->tio = tio; + rsp = (struct iscsi_data_in_hdr *)&data_cmnd->pdu.bhs; + + rsp->opcode = ISCSI_OP_SCSI_DATA_IN; + rsp->itt = req->itt; + rsp->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); + rsp->buffer_offset = offset; + rsp->data_sn = cpu_to_be32(sn); + + if (size <= pdusize) { + data_cmnd->pdu.datasize = size; + rsp->flags = ISCSI_FLG_FINAL | ISCSI_FLG_STATUS; + + scsisize = tio->size; + if (scsisize < expsize) { + rsp->flags |= ISCSI_FLG_RESIDUAL_UNDERFLOW; + size = expsize - scsisize; + } else if (scsisize > expsize) { + rsp->flags |= ISCSI_FLG_RESIDUAL_OVERFLOW; + size = scsisize - expsize; + } else + size = 0; + rsp->residual_count = cpu_to_be32(size); + list_add_tail(&data_cmnd->list, &send); + + break; + } + + data_cmnd->pdu.datasize = pdusize; + + size -= pdusize; + offset += pdusize; + sn++; + + list_add_tail(&data_cmnd->list, &send); + } + + iscsi_cmnds_init_write(&send); +} + +static struct iscsi_cmnd *create_scsi_rsp(struct iscsi_cmnd *req) +{ + struct iscsi_cmnd *rsp; + struct iscsi_scsi_cmd_hdr *req_hdr = cmnd_hdr(req); + struct iscsi_scsi_rsp_hdr *rsp_hdr; + + rsp = iscsi_cmnd_create_rsp_cmnd(req, 1); + + rsp_hdr = (struct iscsi_scsi_rsp_hdr *)&rsp->pdu.bhs; + rsp_hdr->opcode = ISCSI_OP_SCSI_RSP; + rsp_hdr->flags = ISCSI_FLG_FINAL; + rsp_hdr->response = ISCSI_RESPONSE_COMMAND_COMPLETED; + rsp_hdr->cmd_status = SAM_STAT_GOOD; + rsp_hdr->itt = req_hdr->itt; + + return rsp; +} + +static struct iscsi_cmnd *create_sense_rsp(struct iscsi_cmnd *req, + u8 sense_key, u8 asc, u8 ascq) +{ + struct iscsi_cmnd *rsp; + struct iscsi_scsi_rsp_hdr *rsp_hdr; + struct tio *tio; + struct iscsi_sense_data *sense; + + rsp = iscsi_cmnd_create_rsp_cmnd(req, 1); + + rsp_hdr = (struct iscsi_scsi_rsp_hdr *)&rsp->pdu.bhs; + rsp_hdr->opcode = ISCSI_OP_SCSI_RSP; + rsp_hdr->flags = ISCSI_FLG_FINAL; + rsp_hdr->response = ISCSI_RESPONSE_COMMAND_COMPLETED; + rsp_hdr->cmd_status = SAM_STAT_CHECK_CONDITION; + rsp_hdr->itt = cmnd_hdr(req)->itt; + + tio = rsp->tio = tio_alloc(1); + sense = (struct iscsi_sense_data *) page_address(tio->pvec[0]); + assert(sense); + clear_page(sense); + sense->length = cpu_to_be16(14); + sense->data[0] = 0xf0; + sense->data[2] = sense_key; + sense->data[7] = 6; // Additional sense length + sense->data[12] = asc; + sense->data[13] = ascq; + + rsp->pdu.datasize = sizeof(struct iscsi_sense_data) + 14; + tio->size = (rsp->pdu.datasize + 3) & -4; + tio->offset = 0; + + return rsp; +} + +void send_scsi_rsp(struct iscsi_cmnd *req, int (*func)(struct iscsi_cmnd *)) +{ + struct iscsi_cmnd *rsp; + struct iscsi_scsi_rsp_hdr *rsp_hdr; + u32 size; + int ret = func(req); + + switch (ret) { + case 0: + case -EBUSY: + rsp = create_scsi_rsp(req); + rsp_hdr = (struct iscsi_scsi_rsp_hdr *) &rsp->pdu.bhs; + if ((size = cmnd_read_size(req)) != 0) { + rsp_hdr->flags |= ISCSI_FLG_RESIDUAL_UNDERFLOW; + rsp_hdr->residual_count = cpu_to_be32(size); + } + if (ret == -EBUSY) + rsp_hdr->cmd_status = SAM_STAT_RESERVATION_CONFLICT; + break; + case -EIO: + /* Medium Error/Write Fault */ + rsp = create_sense_rsp(req, MEDIUM_ERROR, 0x03, 0x0); + break; + default: + rsp = create_sense_rsp(req, ILLEGAL_REQUEST, 0x24, 0x0); + } + iscsi_cmnd_init_write(rsp); +} + +void send_data_rsp(struct iscsi_cmnd *req, int (*func)(struct iscsi_cmnd *)) +{ + struct iscsi_cmnd *rsp; + + switch (func(req)) { + case 0: + do_send_data_rsp(req); + return; + case -EIO: + /* Medium Error/Unrecovered Read Error */ + rsp = create_sense_rsp(req, MEDIUM_ERROR, 0x11, 0x0); + break; + default: + rsp = create_sense_rsp(req, ILLEGAL_REQUEST, 0x24, 0x0); + } + iscsi_cmnd_init_write(rsp); +} + +/** + * Free a command. + * Also frees the additional header. + * + * iscsi_cmnd_remove - + * @cmnd: ptr to command + */ + +static void iscsi_cmnd_remove(struct iscsi_cmnd *cmnd) +{ + struct iscsi_conn *conn; + + if (!cmnd) + return; + dprintk(D_GENERIC, "%p\n", cmnd); + conn = cmnd->conn; + kfree(cmnd->pdu.ahs); + + if (!list_empty(&cmnd->list)) { + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + + eprintk("cmnd %p still on some list?, %x, %x, %x, %x, %x, %x, %x %lx\n", + cmnd, req->opcode, req->scb[0], req->flags, req->itt, + be32_to_cpu(req->data_length), + req->cmd_sn, be32_to_cpu(cmnd->pdu.datasize), + conn->state); + + if (cmnd->req) { + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd->req); + eprintk("%p %x %u\n", req, req->opcode, req->scb[0]); + } + dump_stack(); + BUG(); + } + list_del(&cmnd->list); + spin_lock(&conn->list_lock); + atomic_dec(&conn->nr_cmnds); + list_del(&cmnd->conn_list); + spin_unlock(&conn->list_lock); + + if (cmnd->tio) + tio_put(cmnd->tio); + + kmem_cache_free(iscsi_cmnd_cache, cmnd); +} + +static void cmnd_skip_pdu(struct iscsi_cmnd *cmnd) +{ + struct iscsi_conn *conn = cmnd->conn; + struct tio *tio = cmnd->tio; + char *addr; + u32 size; + int i; + + eprintk("%x %x %x %u\n", cmnd_itt(cmnd), cmnd_opcode(cmnd), + cmnd_hdr(cmnd)->scb[0], cmnd->pdu.datasize); + + if (!(size = cmnd->pdu.datasize)) + return; + + if (tio) + assert(tio->pg_cnt > 0); + else + tio = cmnd->tio = tio_alloc(1); + + addr = page_address(tio->pvec[0]); + assert(addr); + size = (size + 3) & -4; + conn->read_size = size; + for (i = 0; size > PAGE_CACHE_SIZE; i++, size -= PAGE_CACHE_SIZE) { + assert(i < ISCSI_CONN_IOV_MAX); + conn->read_iov[i].iov_base = addr; + conn->read_iov[i].iov_len = PAGE_CACHE_SIZE; + } + conn->read_iov[i].iov_base = addr; + conn->read_iov[i].iov_len = size; + conn->read_msg.msg_iov = conn->read_iov; + conn->read_msg.msg_iovlen = ++i; +} + +static void iscsi_cmnd_reject(struct iscsi_cmnd *req, int reason) +{ + struct iscsi_cmnd *rsp; + struct iscsi_reject_hdr *rsp_hdr; + struct tio *tio; + char *addr; + + rsp = iscsi_cmnd_create_rsp_cmnd(req, 1); + rsp_hdr = (struct iscsi_reject_hdr *)&rsp->pdu.bhs; + + rsp_hdr->opcode = ISCSI_OP_REJECT; + rsp_hdr->ffffffff = ISCSI_RESERVED_TAG; + rsp_hdr->reason = reason; + + rsp->tio = tio = tio_alloc(1); + addr = page_address(tio->pvec[0]); + clear_page(addr); + memcpy(addr, &req->pdu.bhs, sizeof(struct iscsi_hdr)); + tio->size = rsp->pdu.datasize = sizeof(struct iscsi_hdr); + cmnd_skip_pdu(req); + + req->pdu.bhs.opcode = ISCSI_OP_PDU_REJECT; +} + +static void cmnd_set_sn(struct iscsi_cmnd *cmnd, int set_stat_sn) +{ + struct iscsi_conn *conn = cmnd->conn; + struct iscsi_session *sess = conn->session; + + if (set_stat_sn) + cmnd->pdu.bhs.sn = cpu_to_be32(conn->stat_sn++); + cmnd->pdu.bhs.exp_sn = cpu_to_be32(sess->exp_cmd_sn); + cmnd->pdu.bhs.max_sn = cpu_to_be32(sess->exp_cmd_sn + sess->max_queued_cmnds); +} + +static void update_stat_sn(struct iscsi_cmnd *cmnd) +{ + struct iscsi_conn *conn = cmnd->conn; + u32 exp_stat_sn; + + cmnd->pdu.bhs.exp_sn = exp_stat_sn = be32_to_cpu(cmnd->pdu.bhs.exp_sn); + dprintk(D_GENERIC, "%x,%x\n", cmnd_opcode(cmnd), exp_stat_sn); + if ((int)(exp_stat_sn - conn->exp_stat_sn) > 0 && + (int)(exp_stat_sn - conn->stat_sn) <= 0) { + // free pdu resources + cmnd->conn->exp_stat_sn = exp_stat_sn; + } +} + +static int check_cmd_sn(struct iscsi_cmnd *cmnd) +{ + struct iscsi_session *session = cmnd->conn->session; + u32 cmd_sn; + + cmnd->pdu.bhs.sn = cmd_sn = be32_to_cpu(cmnd->pdu.bhs.sn); + dprintk(D_GENERIC, "%d(%d)\n", cmd_sn, session->exp_cmd_sn); + if ((s32)(cmd_sn - session->exp_cmd_sn) >= 0) + return 0; + eprintk("sequence error (%x,%x)\n", cmd_sn, session->exp_cmd_sn); + return -ISCSI_REASON_PROTOCOL_ERROR; +} + +static struct iscsi_cmnd *__cmnd_find_hash(struct iscsi_session *session, u32 itt, u32 ttt) +{ + struct list_head *head; + struct iscsi_cmnd *cmnd; + + head = &session->cmnd_hash[cmnd_hashfn(itt)]; + + list_for_each_entry(cmnd, head, hash_list) { + if (cmnd->pdu.bhs.itt == itt) { + if ((ttt != ISCSI_RESERVED_TAG) && (ttt != cmnd->target_task_tag)) + continue; + return cmnd; + } + } + + return NULL; +} + +static struct iscsi_cmnd *cmnd_find_hash(struct iscsi_session *session, u32 itt, u32 ttt) +{ + struct iscsi_cmnd *cmnd; + + spin_lock(&session->cmnd_hash_lock); + + cmnd = __cmnd_find_hash(session, itt, ttt); + + spin_unlock(&session->cmnd_hash_lock); + + return cmnd; +} + +static int cmnd_insert_hash(struct iscsi_cmnd *cmnd) +{ + struct iscsi_session *session = cmnd->conn->session; + struct iscsi_cmnd *tmp; + struct list_head *head; + int err = 0; + u32 itt = cmnd->pdu.bhs.itt; + + dprintk(D_GENERIC, "%p:%x\n", cmnd, itt); + if (itt == ISCSI_RESERVED_TAG) { + err = -ISCSI_REASON_PROTOCOL_ERROR; + goto out; + } + + head = &session->cmnd_hash[cmnd_hashfn(cmnd->pdu.bhs.itt)]; + + spin_lock(&session->cmnd_hash_lock); + + tmp = __cmnd_find_hash(session, itt, ISCSI_RESERVED_TAG); + if (!tmp) { + list_add_tail(&cmnd->hash_list, head); + set_cmnd_hashed(cmnd); + } else + err = -ISCSI_REASON_TASK_IN_PROGRESS; + + spin_unlock(&session->cmnd_hash_lock); + + if (!err) { + update_stat_sn(cmnd); + err = check_cmd_sn(cmnd); + } + +out: + return err; +} + +static void __cmnd_remove_hash(struct iscsi_cmnd *cmnd) +{ + list_del(&cmnd->hash_list); +} + +static void cmnd_remove_hash(struct iscsi_cmnd *cmnd) +{ + struct iscsi_session *session = cmnd->conn->session; + struct iscsi_cmnd *tmp; + + spin_lock(&session->cmnd_hash_lock); + + tmp = __cmnd_find_hash(session, cmnd->pdu.bhs.itt, ISCSI_RESERVED_TAG); + + if (tmp && tmp == cmnd) + __cmnd_remove_hash(tmp); + else + eprintk("%p:%x not found\n", cmnd, cmnd_itt(cmnd)); + + spin_unlock(&session->cmnd_hash_lock); +} + +static void cmnd_skip_data(struct iscsi_cmnd *req) +{ + struct iscsi_cmnd *rsp; + struct iscsi_scsi_rsp_hdr *rsp_hdr; + u32 size; + + rsp = get_rsp_cmnd(req); + rsp_hdr = (struct iscsi_scsi_rsp_hdr *)&rsp->pdu.bhs; + if (cmnd_opcode(rsp) != ISCSI_OP_SCSI_RSP) { + eprintk("unexpected response command %u\n", cmnd_opcode(rsp)); + return; + } + + size = cmnd_write_size(req); + if (size) { + rsp_hdr->flags |= ISCSI_FLG_RESIDUAL_UNDERFLOW; + rsp_hdr->residual_count = cpu_to_be32(size); + } + size = cmnd_read_size(req); + if (size) { + if (cmnd_hdr(req)->flags & ISCSI_CMD_WRITE) { + rsp_hdr->flags |= ISCSI_FLG_BIRESIDUAL_UNDERFLOW; + rsp_hdr->bi_residual_count = cpu_to_be32(size); + } else { + rsp_hdr->flags |= ISCSI_FLG_RESIDUAL_UNDERFLOW; + rsp_hdr->residual_count = cpu_to_be32(size); + } + } + req->pdu.bhs.opcode = + (req->pdu.bhs.opcode & ~ISCSI_OPCODE_MASK) | ISCSI_OP_SCSI_REJECT; + + cmnd_skip_pdu(req); +} + +static int cmnd_recv_pdu(struct iscsi_conn *conn, struct tio *tio, u32 offset, u32 size) +{ + int idx, i; + char *addr; + + dprintk(D_GENERIC, "%p %u,%u\n", tio, offset, size); + offset += tio->offset; + + if (!(offset < tio->offset + tio->size) || + !(offset + size <= tio->offset + tio->size)) { + eprintk("%u %u %u %u", offset, size, tio->offset, tio->size); + return -EIO; + } + assert(offset < tio->offset + tio->size); + assert(offset + size <= tio->offset + tio->size); + + idx = offset >> PAGE_CACHE_SHIFT; + offset &= ~PAGE_CACHE_MASK; + + conn->read_msg.msg_iov = conn->read_iov; + conn->read_size = size = (size + 3) & -4; + conn->read_overflow = 0; + + i = 0; + while (1) { + assert(tio->pvec[idx]); + addr = page_address(tio->pvec[idx]); + assert(addr); + conn->read_iov[i].iov_base = addr + offset; + if (offset + size <= PAGE_CACHE_SIZE) { + conn->read_iov[i].iov_len = size; + conn->read_msg.msg_iovlen = ++i; + break; + } + conn->read_iov[i].iov_len = PAGE_CACHE_SIZE - offset; + size -= conn->read_iov[i].iov_len; + offset = 0; + if (++i >= ISCSI_CONN_IOV_MAX) { + conn->read_msg.msg_iovlen = i; + conn->read_overflow = size; + conn->read_size -= size; + break; + } + + idx++; + } + + return 0; +} + +static void set_offset_and_length(struct iet_volume *lu, u8 *cmd, loff_t *off, u32 *len) +{ + assert(lu); + + switch (cmd[0]) { + case READ_6: + case WRITE_6: + *off = ((cmd[1] & 0x1f) << 16) + (cmd[2] << 8) + cmd[3]; + *len = cmd[4]; + if (!*len) + *len = 256; + break; + case READ_10: + case WRITE_10: + case WRITE_VERIFY: + *off = (u32)cmd[2] << 24 | (u32)cmd[3] << 16 | + (u32)cmd[4] << 8 | (u32)cmd[5]; + *len = (cmd[7] << 8) + cmd[8]; + break; + case READ_16: + case WRITE_16: + *off = (u64)cmd[2] << 56 | (u64)cmd[3] << 48 | + (u64)cmd[4] << 40 | (u64)cmd[5] << 32 | + (u64)cmd[6] << 24 | (u64)cmd[7] << 16 | + (u64)cmd[8] << 8 | (u64)cmd[9]; + *len = (u32)cmd[10] << 24 | (u32)cmd[11] << 16 | + (u32)cmd[12] << 8 | (u32)cmd[13]; + break; + default: + BUG(); + } + + *off <<= lu->blk_shift; + *len <<= lu->blk_shift; +} + +static u32 translate_lun(u16 * data) +{ + u8 *p = (u8 *) data; + u32 lun = ~0U; + + switch (*p >> 6) { + case 0: + lun = p[1]; + break; + case 1: + lun = (0x3f & p[0]) << 8 | p[1]; + break; + case 2: + case 3: + default: + eprintk("%u %u %u %u\n", data[0], data[1], data[2], data[3]); + break; + } + + return lun; +} + +static void send_r2t(struct iscsi_cmnd *req) +{ + struct iscsi_cmnd *rsp; + struct iscsi_r2t_hdr *rsp_hdr; + u32 length, offset, burst; + LIST_HEAD(send); + + length = req->r2t_length; + burst = req->conn->session->param.max_burst_length; + offset = be32_to_cpu(cmnd_hdr(req)->data_length) - length; + + do { + rsp = iscsi_cmnd_create_rsp_cmnd(req, 0); + rsp->pdu.bhs.ttt = req->target_task_tag; + + rsp_hdr = (struct iscsi_r2t_hdr *)&rsp->pdu.bhs; + rsp_hdr->opcode = ISCSI_OP_R2T; + rsp_hdr->flags = ISCSI_FLG_FINAL; + memcpy(rsp_hdr->lun, cmnd_hdr(req)->lun, 8); + rsp_hdr->itt = cmnd_hdr(req)->itt; + rsp_hdr->r2t_sn = cpu_to_be32(req->r2t_sn++); + rsp_hdr->buffer_offset = cpu_to_be32(offset); + if (length > burst) { + rsp_hdr->data_length = cpu_to_be32(burst); + length -= burst; + offset += burst; + } else { + rsp_hdr->data_length = cpu_to_be32(length); + length = 0; + } + + dprintk(D_WRITE, "%x %u %u %u %u\n", cmnd_itt(req), + be32_to_cpu(rsp_hdr->data_length), + be32_to_cpu(rsp_hdr->buffer_offset), + be32_to_cpu(rsp_hdr->r2t_sn), req->outstanding_r2t); + + list_add_tail(&rsp->list, &send); + + if (++req->outstanding_r2t >= req->conn->session->param.max_outstanding_r2t) + break; + + } while (length); + + iscsi_cmnds_init_write(&send); +} + +static void scsi_cmnd_exec(struct iscsi_cmnd *cmnd) +{ + if (cmnd->r2t_length) { + if (!cmnd->is_unsolicited_data) + send_r2t(cmnd); + } else { + if (cmnd->lun) { + iscsi_scsi_queuecmnd(cmnd); + } else { + iscsi_device_queue_cmnd(cmnd); + } + } +} + +static int noop_out_start(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd) +{ + u32 size, tmp; + int i, err = 0; + + if (cmnd_ttt(cmnd) != cpu_to_be32(ISCSI_RESERVED_TAG)) { + /* + * We don't request a NOP-Out by sending a NOP-In. + * See 10.18.2 in the draft 20. + */ + eprintk("initiator bug %x\n", cmnd_itt(cmnd)); + err = -ISCSI_REASON_PROTOCOL_ERROR; + goto out; + } + + if (cmnd_itt(cmnd) == cpu_to_be32(ISCSI_RESERVED_TAG)) { + if (!(cmnd->pdu.bhs.opcode & ISCSI_OP_IMMEDIATE)) + eprintk("%s\n","initiator bug!"); + update_stat_sn(cmnd); + err = check_cmd_sn(cmnd); + if (err) + goto out; + } else if ((err = cmnd_insert_hash(cmnd)) < 0) { + eprintk("ignore this request %x\n", cmnd_itt(cmnd)); + goto out; + } + + if ((size = cmnd->pdu.datasize)) { + size = (size + 3) & -4; + conn->read_msg.msg_iov = conn->read_iov; + if (cmnd->pdu.bhs.itt != cpu_to_be32(ISCSI_RESERVED_TAG)) { + struct tio *tio; + int pg_cnt = get_pgcnt(size, 0); + + assert(pg_cnt < ISCSI_CONN_IOV_MAX); + cmnd->tio = tio = tio_alloc(pg_cnt); + tio_set(tio, size, 0); + + for (i = 0; i < pg_cnt; i++) { + conn->read_iov[i].iov_base + = page_address(tio->pvec[i]); + tmp = min_t(u32, size, PAGE_CACHE_SIZE); + conn->read_iov[i].iov_len = tmp; + conn->read_size += tmp; + size -= tmp; + } + } else { + for (i = 0; i < ISCSI_CONN_IOV_MAX; i++) { + conn->read_iov[i].iov_base = dummy_data; + tmp = min_t(u32, size, sizeof(dummy_data)); + conn->read_iov[i].iov_len = tmp; + conn->read_size += tmp; + size -= tmp; + } + } + assert(!size); + conn->read_overflow = size; + conn->read_msg.msg_iovlen = i; + } + +out: + return err; +} + +static u32 get_next_ttt(struct iscsi_session *session) +{ + u32 ttt; + + if (session->next_ttt == ISCSI_RESERVED_TAG) + session->next_ttt++; + ttt = session->next_ttt++; + + return cpu_to_be32(ttt); +} + +static void scsi_cmnd_start(struct iscsi_conn *conn, struct iscsi_cmnd *req) +{ + struct iscsi_scsi_cmd_hdr *req_hdr = cmnd_hdr(req); + + dprintk(D_GENERIC, "scsi command: %02x\n", req_hdr->scb[0]); + + req->lun = volume_get(conn->session->target, translate_lun(req_hdr->lun)); + if (!req->lun) { + switch (req_hdr->scb[0]) { + case INQUIRY: + case REPORT_LUNS: + break; + default: + eprintk("%x %x\n", cmnd_itt(req), req_hdr->scb[0]); + create_sense_rsp(req, ILLEGAL_REQUEST, 0x25, 0x0); + cmnd_skip_data(req); + goto out; + } + } else + set_cmnd_lunit(req); + + switch (req_hdr->scb[0]) { + case SERVICE_ACTION_IN: + if ((req_hdr->scb[1] & 0x1f) != 0x10) + goto error; + case INQUIRY: + case REPORT_LUNS: + case TEST_UNIT_READY: + case SYNCHRONIZE_CACHE: + case VERIFY: + case VERIFY_16: + case START_STOP: + case READ_CAPACITY: + case MODE_SENSE: + case REQUEST_SENSE: + case RESERVE: + case RELEASE: + { + if (!(req_hdr->flags & ISCSI_CMD_FINAL) || req->pdu.datasize) { + /* unexpected unsolicited data */ + eprintk("%x %x\n", cmnd_itt(req), req_hdr->scb[0]); + create_sense_rsp(req, ABORTED_COMMAND, 0xc, 0xc); + cmnd_skip_data(req); + } + break; + } + case READ_6: + case READ_10: + case READ_16: + { + loff_t offset; + u32 length; + + if (!(req_hdr->flags & ISCSI_CMD_FINAL) || req->pdu.datasize) { + /* unexpected unsolicited data */ + eprintk("%x %x\n", cmnd_itt(req), req_hdr->scb[0]); + create_sense_rsp(req, ABORTED_COMMAND, 0xc, 0xc); + cmnd_skip_data(req); + break; + } + + set_offset_and_length(req->lun, req_hdr->scb, &offset, &length); + req->tio = tio_alloc(get_pgcnt(length, offset)); + tio_set(req->tio, length, offset); + break; + } + case WRITE_6: + case WRITE_10: + case WRITE_16: + case WRITE_VERIFY: + { + struct iscsi_sess_param *param = &conn->session->param; + loff_t offset; + u32 length; + + req->r2t_length = be32_to_cpu(req_hdr->data_length) - req->pdu.datasize; + req->is_unsolicited_data = !(req_hdr->flags & ISCSI_CMD_FINAL); + req->target_task_tag = get_next_ttt(conn->session); + + if (LUReadonly(req->lun)) { + create_sense_rsp(req, DATA_PROTECT, 0x27, 0x0); + cmnd_skip_data(req); + break; + } + + if (!param->immediate_data && req->pdu.datasize) + eprintk("%x %x\n", cmnd_itt(req), req_hdr->scb[0]); + + if (param->initial_r2t && !(req_hdr->flags & ISCSI_CMD_FINAL)) + eprintk("%x %x\n", cmnd_itt(req), req_hdr->scb[0]); + + if (req_hdr->scb[0] == WRITE_VERIFY && req_hdr->scb[1] & 0x02) + eprintk("Verification is ignored %x\n", cmnd_itt(req)); + + set_offset_and_length(req->lun, req_hdr->scb, &offset, &length); + if (cmnd_write_size(req) != length) + eprintk("%x %u %u\n", cmnd_itt(req), cmnd_write_size(req), length); + + req->tio = tio_alloc(get_pgcnt(length, offset)); + tio_set(req->tio, length, offset); + + if (req->pdu.datasize) { + if (cmnd_recv_pdu(conn, req->tio, 0, req->pdu.datasize) < 0) + assert(0); + } + break; + } + error: + default: + eprintk("Unsupported %x\n", req_hdr->scb[0]); + create_sense_rsp(req, ILLEGAL_REQUEST, 0x20, 0x0); + cmnd_skip_data(req); + break; + } + +out: + return; +} + +static void data_out_start(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd) +{ + struct iscsi_data_out_hdr *req = (struct iscsi_data_out_hdr *)&cmnd->pdu.bhs; + struct iscsi_cmnd *scsi_cmnd = NULL; + u32 offset = be32_to_cpu(req->buffer_offset); + + update_stat_sn(cmnd); + + cmnd->req = scsi_cmnd = cmnd_find_hash(conn->session, req->itt, req->ttt); + if (!scsi_cmnd) { + eprintk("unable to find scsi task %x %x\n", + cmnd_itt(cmnd), cmnd_ttt(cmnd)); + goto skip_data; + } + + if (scsi_cmnd->r2t_length < cmnd->pdu.datasize) { + eprintk("invalid data len %x %u %u\n", + cmnd_itt(scsi_cmnd), cmnd->pdu.datasize, scsi_cmnd->r2t_length); + goto skip_data; + } + + if (scsi_cmnd->r2t_length + offset != cmnd_write_size(scsi_cmnd)) { + eprintk("%x %u %u %u\n", cmnd_itt(scsi_cmnd), scsi_cmnd->r2t_length, + offset, cmnd_write_size(scsi_cmnd)); + goto skip_data; + } + + scsi_cmnd->r2t_length -= cmnd->pdu.datasize; + + if (req->ttt == cpu_to_be32(ISCSI_RESERVED_TAG)) { + /* unsolicited burst data */ + if (scsi_cmnd->pdu.bhs.flags & ISCSI_FLG_FINAL) { + eprintk("unexpected data from %x %x\n", + cmnd_itt(cmnd), cmnd_ttt(cmnd)); + goto skip_data; + } + } + + dprintk(D_WRITE, "%u %p %p %p %u %u\n", req->ttt, cmnd, scsi_cmnd, + scsi_cmnd->tio, offset, cmnd->pdu.datasize); + + if (cmnd_recv_pdu(conn, scsi_cmnd->tio, offset, cmnd->pdu.datasize) < 0) + goto skip_data; + return; + +skip_data: + cmnd->pdu.bhs.opcode = ISCSI_OP_DATA_REJECT; + cmnd_skip_pdu(cmnd); + return; +} + +static void data_out_end(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd) +{ + struct iscsi_data_out_hdr *req = (struct iscsi_data_out_hdr *) &cmnd->pdu.bhs; + struct iscsi_cmnd *scsi_cmnd; + u32 offset; + + assert(cmnd); + scsi_cmnd = cmnd->req; + assert(scsi_cmnd); + + if (conn->read_overflow) { + eprintk("%x %u\n", cmnd_itt(cmnd), conn->read_overflow); + assert(scsi_cmnd->tio); + offset = be32_to_cpu(req->buffer_offset); + offset += cmnd->pdu.datasize - conn->read_overflow; + if (cmnd_recv_pdu(conn, scsi_cmnd->tio, offset, conn->read_overflow) < 0) + assert(0); + return; + } + + if (req->ttt == cpu_to_be32(ISCSI_RESERVED_TAG)) { + if (req->flags & ISCSI_FLG_FINAL) { + scsi_cmnd->is_unsolicited_data = 0; + if (!cmnd_pending(scsi_cmnd)) + scsi_cmnd_exec(scsi_cmnd); + } + } else { + /* TODO : proper error handling */ + if (!(req->flags & ISCSI_FLG_FINAL) && scsi_cmnd->r2t_length == 0) + eprintk("initiator error %x\n", cmnd_itt(scsi_cmnd)); + + if (!(req->flags & ISCSI_FLG_FINAL)) + goto out; + + scsi_cmnd->outstanding_r2t--; + + if (scsi_cmnd->r2t_length == 0) + assert(list_empty(&scsi_cmnd->pdu_list)); + + scsi_cmnd_exec(scsi_cmnd); + } + +out: + iscsi_cmnd_remove(cmnd); + return; +} + +static int __cmnd_abort(struct iscsi_cmnd *cmnd) +{ + if (cmnd_waitio(cmnd)) + return -ISCSI_RESPONSE_UNKNOWN_TASK; + + if (cmnd->conn->read_cmnd != cmnd) + cmnd_release(cmnd, 1); + else if (cmnd_rxstart(cmnd)) + set_cmnd_tmfabort(cmnd); + else + return -ISCSI_RESPONSE_UNKNOWN_TASK; + + return 0; +} + +static int cmnd_abort(struct iscsi_session *session, u32 itt) +{ + struct iscsi_cmnd *cmnd; + int err = -ISCSI_RESPONSE_UNKNOWN_TASK; + + if ((cmnd = cmnd_find_hash(session, itt, ISCSI_RESERVED_TAG))) { + eprintk("%x %x %x %u %u %u %u\n", cmnd_itt(cmnd), cmnd_opcode(cmnd), + cmnd->r2t_length, cmnd_scsicode(cmnd), + cmnd_write_size(cmnd), cmnd->is_unsolicited_data, + cmnd->outstanding_r2t); + err = __cmnd_abort(cmnd); + } + + return err; +} + +static int target_reset(struct iscsi_cmnd *req, u32 lun, int all) +{ + struct iscsi_target *target = req->conn->session->target; + struct iscsi_session *session; + struct iscsi_conn *conn; + struct iscsi_cmnd *cmnd, *tmp; + struct iet_volume *volumes; + + list_for_each_entry(session, &target->session_list, list) { + list_for_each_entry(conn, &session->conn_list, list) { + list_for_each_entry_safe(cmnd, tmp, &conn->pdu_list, conn_list) { + if (cmnd == req) + continue; + + if (all) + __cmnd_abort(cmnd); + else if (translate_lun(cmnd_hdr(cmnd)->lun) == lun) + __cmnd_abort(cmnd); + } + } + } + + list_for_each_entry(volumes, &target->volumes, list) + if (all || volumes->lun == lun) + /* force release */ + volume_release(volumes, 0, 1); + + return 0; +} + +static void task_set_abort(struct iscsi_cmnd *req) +{ + struct iscsi_session *session = req->conn->session; + struct iscsi_conn *conn; + struct iscsi_cmnd *cmnd, *tmp; + + list_for_each_entry(conn, &session->conn_list, list) { + list_for_each_entry_safe(cmnd, tmp, &conn->pdu_list, conn_list) { + if (cmnd != req) + __cmnd_abort(cmnd); + } + } +} + +static inline char *tmf_desc(int fun) +{ + static char *tmf_desc[] = { + "Unknown Function", + "Abort Task", + "Abort Task Set", + "Clear ACA", + "Clear Task Set", + "Logical Unit Reset", + "Target Warm Reset", + "Target Cold Reset", + "Task Reassign", + }; + + if ((fun < ISCSI_FUNCTION_ABORT_TASK) || + (fun > ISCSI_FUNCTION_TASK_REASSIGN)) + fun = 0; + + return tmf_desc[fun]; +} + +static inline char *rsp_desc(int rsp) +{ + static char *rsp_desc[] = { + "Function Complete", + "Unknown Task", + "Unknown LUN", + "Task Allegiant", + "Failover Unsupported", + "Function Unsupported", + "No Authorization", + "Function Rejected", + "Unknown Response", + }; + + if (((rsp < ISCSI_RESPONSE_FUNCTION_COMPLETE) || + (rsp > ISCSI_RESPONSE_NO_AUTHORIZATION)) && + (rsp != ISCSI_RESPONSE_FUNCTION_REJECTED)) + rsp = 8; + else if (rsp == ISCSI_RESPONSE_FUNCTION_REJECTED) + rsp = 7; + + return rsp_desc[rsp]; +} + +static void execute_task_management(struct iscsi_cmnd *req) +{ + struct iscsi_conn *conn = req->conn; + struct iscsi_session *session = conn->session; + struct iscsi_target *target = session->target; + struct iscsi_cmnd *rsp; + struct iscsi_task_mgt_hdr *req_hdr = (struct iscsi_task_mgt_hdr *)&req->pdu.bhs; + struct iscsi_task_rsp_hdr *rsp_hdr; + u32 lun; + int err, function = req_hdr->function & ISCSI_FUNCTION_MASK; + + rsp = iscsi_cmnd_create_rsp_cmnd(req, 1); + rsp_hdr = (struct iscsi_task_rsp_hdr *)&rsp->pdu.bhs; + + rsp_hdr->opcode = ISCSI_OP_SCSI_TASK_MGT_RSP; + rsp_hdr->flags = ISCSI_FLG_FINAL; + rsp_hdr->itt = req_hdr->itt; + rsp_hdr->response = ISCSI_RESPONSE_FUNCTION_COMPLETE; + + switch (function) { + case ISCSI_FUNCTION_ABORT_TASK: + case ISCSI_FUNCTION_ABORT_TASK_SET: + case ISCSI_FUNCTION_CLEAR_ACA: + case ISCSI_FUNCTION_CLEAR_TASK_SET: + case ISCSI_FUNCTION_LOGICAL_UNIT_RESET: + lun = translate_lun(req_hdr->lun); + if (!volume_lookup(target, lun)) { + rsp_hdr->response = ISCSI_RESPONSE_UNKNOWN_LUN; + goto out; + } + } + + switch (function) { + case ISCSI_FUNCTION_ABORT_TASK: + if ((err = cmnd_abort(conn->session, req_hdr->rtt)) < 0) + rsp_hdr->response = -err; + break; + case ISCSI_FUNCTION_ABORT_TASK_SET: + task_set_abort(req); + break; + case ISCSI_FUNCTION_CLEAR_ACA: + rsp_hdr->response = ISCSI_RESPONSE_FUNCTION_UNSUPPORTED; + break; + case ISCSI_FUNCTION_CLEAR_TASK_SET: + rsp_hdr->response = ISCSI_RESPONSE_FUNCTION_UNSUPPORTED; + break; + case ISCSI_FUNCTION_LOGICAL_UNIT_RESET: + target_reset(req, translate_lun(req_hdr->lun), 0); + break; + case ISCSI_FUNCTION_TARGET_WARM_RESET: + case ISCSI_FUNCTION_TARGET_COLD_RESET: + target_reset(req, 0, 1); + if (function == ISCSI_FUNCTION_TARGET_COLD_RESET) + set_cmnd_close(rsp); + break; + case ISCSI_FUNCTION_TASK_REASSIGN: + rsp_hdr->response = ISCSI_RESPONSE_FUNCTION_UNSUPPORTED; + break; + default: + rsp_hdr->response = ISCSI_RESPONSE_FUNCTION_REJECTED; + break; + } +out: + iprintk("%s (%02x) issued on tid:%d lun:%d by sid:%llu (%s)\n", + tmf_desc(function), function, target->tid, + translate_lun(req_hdr->lun), session->sid, + rsp_desc(rsp_hdr->response)); + + iscsi_cmnd_init_write(rsp); +} + +static void noop_out_exec(struct iscsi_cmnd *req) +{ + struct iscsi_cmnd *rsp; + struct iscsi_nop_in_hdr *rsp_hdr; + + if (cmnd_itt(req) != cpu_to_be32(ISCSI_RESERVED_TAG)) { + rsp = iscsi_cmnd_create_rsp_cmnd(req, 1); + + rsp_hdr = (struct iscsi_nop_in_hdr *)&rsp->pdu.bhs; + rsp_hdr->opcode = ISCSI_OP_NOOP_IN; + rsp_hdr->flags = ISCSI_FLG_FINAL; + rsp_hdr->itt = req->pdu.bhs.itt; + rsp_hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); + + if (req->pdu.datasize) + assert(req->tio); + else + assert(!req->tio); + + if (req->tio) { + tio_get(req->tio); + rsp->tio = req->tio; + } + + assert(get_pgcnt(req->pdu.datasize, 0) < ISCSI_CONN_IOV_MAX); + rsp->pdu.datasize = req->pdu.datasize; + iscsi_cmnd_init_write(rsp); + } else + iscsi_cmnd_remove(req); +} + +static void logout_exec(struct iscsi_cmnd *req) +{ + struct iscsi_logout_req_hdr *req_hdr; + struct iscsi_cmnd *rsp; + struct iscsi_logout_rsp_hdr *rsp_hdr; + + req_hdr = (struct iscsi_logout_req_hdr *)&req->pdu.bhs; + rsp = iscsi_cmnd_create_rsp_cmnd(req, 1); + rsp_hdr = (struct iscsi_logout_rsp_hdr *)&rsp->pdu.bhs; + rsp_hdr->opcode = ISCSI_OP_LOGOUT_RSP; + rsp_hdr->flags = ISCSI_FLG_FINAL; + rsp_hdr->itt = req_hdr->itt; + set_cmnd_close(rsp); + iscsi_cmnd_init_write(rsp); +} + +static void iscsi_cmnd_exec(struct iscsi_cmnd *cmnd) +{ + dprintk(D_GENERIC, "%p,%x,%u\n", cmnd, cmnd_opcode(cmnd), cmnd->pdu.bhs.sn); + + switch (cmnd_opcode(cmnd)) { + case ISCSI_OP_NOOP_OUT: + noop_out_exec(cmnd); + break; + case ISCSI_OP_SCSI_CMD: + scsi_cmnd_exec(cmnd); + break; + case ISCSI_OP_SCSI_TASK_MGT_MSG: + execute_task_management(cmnd); + break; + case ISCSI_OP_LOGOUT_CMD: + logout_exec(cmnd); + break; + case ISCSI_OP_SCSI_REJECT: + iscsi_cmnd_init_write(get_rsp_cmnd(cmnd)); + break; + case ISCSI_OP_TEXT_CMD: + case ISCSI_OP_SNACK_CMD: + break; + default: + eprintk("unexpected cmnd op %x\n", cmnd_opcode(cmnd)); + break; + } +} + +static void __cmnd_send_pdu(struct iscsi_conn *conn, struct tio *tio, u32 offset, u32 size) +{ + dprintk(D_GENERIC, "%p %u,%u\n", tio, offset, size); + offset += tio->offset; + + assert(offset <= tio->offset + tio->size); + assert(offset + size <= tio->offset + tio->size); + + conn->write_tcmnd = tio; + conn->write_offset = offset; + conn->write_size += size; +} + +static void cmnd_send_pdu(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd) +{ + u32 size; + struct tio *tio; + + if (!cmnd->pdu.datasize) + return; + + size = (cmnd->pdu.datasize + 3) & -4; + tio = cmnd->tio; + assert(tio); + assert(tio->size == size); + __cmnd_send_pdu(conn, tio, 0, size); +} + +static void set_cork(struct socket *sock, int on) +{ + int opt = on; + mm_segment_t oldfs; + + oldfs = get_fs(); + set_fs(get_ds()); + sock->ops->setsockopt(sock, SOL_TCP, TCP_CORK, (void *)&opt, sizeof(opt)); + set_fs(oldfs); +} + +void cmnd_release(struct iscsi_cmnd *cmnd, int force) +{ + struct iscsi_cmnd *req, *rsp; + int is_last = 0; + + if (!cmnd) + return; + +/* eprintk("%x %lx %d\n", cmnd_opcode(cmnd), cmnd->flags, force); */ + + req = cmnd->req; + is_last = cmnd_final(cmnd); + + if (force) { + while (!list_empty(&cmnd->pdu_list)) { + rsp = list_entry(cmnd->pdu_list.next, struct iscsi_cmnd, pdu_list); + list_del_init(&rsp->list); + list_del(&rsp->pdu_list); + iscsi_cmnd_remove(rsp); + } + list_del_init(&cmnd->list); + } else + if (cmnd_queued(cmnd)) + iscsi_scsi_dequeuecmnd(cmnd); + + if (cmnd_hashed(cmnd)) + cmnd_remove_hash(cmnd); + + if (cmnd_lunit(cmnd)) { + assert(cmnd->lun); + volume_put(cmnd->lun); + } + + list_del_init(&cmnd->pdu_list); + iscsi_cmnd_remove(cmnd); + + if (is_last) { + assert(!force); + assert(req); + cmnd_release(req, 0); + } + + return; +} + +void cmnd_tx_start(struct iscsi_cmnd *cmnd) +{ + struct iscsi_conn *conn = cmnd->conn; + struct iovec *iop; + + dprintk(D_GENERIC, "%p:%x\n", cmnd, cmnd_opcode(cmnd)); + assert(cmnd); + iscsi_cmnd_set_length(&cmnd->pdu); + + set_cork(conn->sock, 1); + + conn->write_iop = iop = conn->write_iov; + iop->iov_base = &cmnd->pdu.bhs; + iop->iov_len = sizeof(cmnd->pdu.bhs); + iop++; + conn->write_size = sizeof(cmnd->pdu.bhs); + + switch (cmnd_opcode(cmnd)) { + case ISCSI_OP_NOOP_IN: + cmnd_set_sn(cmnd, 1); + cmnd_send_pdu(conn, cmnd); + break; + case ISCSI_OP_SCSI_RSP: + cmnd_set_sn(cmnd, 1); + cmnd_send_pdu(conn, cmnd); + break; + case ISCSI_OP_SCSI_TASK_MGT_RSP: + cmnd_set_sn(cmnd, 1); + break; + case ISCSI_OP_TEXT_RSP: + cmnd_set_sn(cmnd, 1); + break; + case ISCSI_OP_SCSI_DATA_IN: + { + struct iscsi_data_in_hdr *rsp = (struct iscsi_data_in_hdr *)&cmnd->pdu.bhs; + u32 offset; + + cmnd_set_sn(cmnd, (rsp->flags & ISCSI_FLG_FINAL) ? 1 : 0); + offset = rsp->buffer_offset; + rsp->buffer_offset = cpu_to_be32(offset); + __cmnd_send_pdu(conn, cmnd->tio, offset, cmnd->pdu.datasize); + break; + } + case ISCSI_OP_LOGOUT_RSP: + cmnd_set_sn(cmnd, 1); + break; + case ISCSI_OP_R2T: + cmnd_set_sn(cmnd, 0); + cmnd->pdu.bhs.sn = cpu_to_be32(conn->stat_sn); + break; + case ISCSI_OP_ASYNC_MSG: + cmnd_set_sn(cmnd, 1); + break; + case ISCSI_OP_REJECT: + cmnd_set_sn(cmnd, 1); + cmnd_send_pdu(conn, cmnd); + break; + default: + eprintk("unexpected cmnd op %x\n", cmnd_opcode(cmnd)); + break; + } + + iop->iov_len = 0; + // move this? + conn->write_size = (conn->write_size + 3) & -4; + iscsi_dump_pdu(&cmnd->pdu); +} + +void cmnd_tx_end(struct iscsi_cmnd *cmnd) +{ + struct iscsi_conn *conn = cmnd->conn; + + dprintk(D_GENERIC, "%p:%x\n", cmnd, cmnd_opcode(cmnd)); + switch (cmnd_opcode(cmnd)) { + case ISCSI_OP_NOOP_IN: + case ISCSI_OP_SCSI_RSP: + case ISCSI_OP_SCSI_TASK_MGT_RSP: + case ISCSI_OP_TEXT_RSP: + case ISCSI_OP_R2T: + case ISCSI_OP_ASYNC_MSG: + case ISCSI_OP_REJECT: + case ISCSI_OP_SCSI_DATA_IN: + case ISCSI_OP_LOGOUT_RSP: + break; + default: + eprintk("unexpected cmnd op %x\n", cmnd_opcode(cmnd)); + assert(0); + break; + } + + if (cmnd_close(cmnd)) + conn_close(conn); + + list_del_init(&cmnd->list); + set_cork(cmnd->conn->sock, 0); +} + +/** + * Push the command for execution. + * This functions reorders the commands. + * Called from the read thread. + * + * iscsi_session_push_cmnd - + * @cmnd: ptr to command + */ + +static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd) +{ + struct iscsi_session *session = cmnd->conn->session; + struct list_head *entry; + u32 cmd_sn; + + dprintk(D_GENERIC, "%p:%x %u,%u\n", + cmnd, cmnd_opcode(cmnd), cmnd->pdu.bhs.sn, session->exp_cmd_sn); + + if (cmnd->pdu.bhs.opcode & ISCSI_OP_IMMEDIATE) { + iscsi_cmnd_exec(cmnd); + return; + } + + cmd_sn = cmnd->pdu.bhs.sn; + if (cmd_sn == session->exp_cmd_sn) { + while (1) { + session->exp_cmd_sn = ++cmd_sn; + iscsi_cmnd_exec(cmnd); + + if (list_empty(&session->pending_list)) + break; + cmnd = list_entry(session->pending_list.next, struct iscsi_cmnd, list); + if (cmnd->pdu.bhs.sn != cmd_sn) + break; +/* eprintk("find out-of-order %x %u %u\n", */ +/* cmnd_itt(cmnd), cmd_sn, cmnd->pdu.bhs.sn); */ + list_del_init(&cmnd->list); + clear_cmnd_pending(cmnd); + } + } else { +/* eprintk("out-of-order %x %u %u\n", */ +/* cmnd_itt(cmnd), cmd_sn, session->exp_cmd_sn); */ + + set_cmnd_pending(cmnd); + if (before(cmd_sn, session->exp_cmd_sn)) /* close the conn */ + eprintk("unexpected cmd_sn (%u,%u)\n", cmd_sn, session->exp_cmd_sn); + + if (after(cmd_sn, session->exp_cmd_sn + session->max_queued_cmnds)) + eprintk("too large cmd_sn (%u,%u)\n", cmd_sn, session->exp_cmd_sn); + + list_for_each(entry, &session->pending_list) { + struct iscsi_cmnd *tmp = list_entry(entry, struct iscsi_cmnd, list); + if (before(cmd_sn, tmp->pdu.bhs.sn)) + break; + } + + assert(list_empty(&cmnd->list)); + + list_add_tail(&cmnd->list, entry); + } +} + +static int check_segment_length(struct iscsi_cmnd *cmnd) +{ + struct iscsi_conn *conn = cmnd->conn; + struct iscsi_sess_param *param = &conn->session->param; + + if (cmnd->pdu.datasize > param->max_recv_data_length) { + eprintk("data too long %x %u %u\n", cmnd_itt(cmnd), + cmnd->pdu.datasize, param->max_recv_data_length); + + if (get_pgcnt(cmnd->pdu.datasize, 0) > ISCSI_CONN_IOV_MAX) { + conn_close(conn); + return -EINVAL; + } + } + + return 0; +} + +void cmnd_rx_start(struct iscsi_cmnd *cmnd) +{ + struct iscsi_conn *conn = cmnd->conn; + int err = 0; + + iscsi_dump_pdu(&cmnd->pdu); + + set_cmnd_rxstart(cmnd); + if (check_segment_length(cmnd) < 0) + return; + + switch (cmnd_opcode(cmnd)) { + case ISCSI_OP_NOOP_OUT: + err = noop_out_start(conn, cmnd); + break; + case ISCSI_OP_SCSI_CMD: + if (!(err = cmnd_insert_hash(cmnd))) + scsi_cmnd_start(conn, cmnd); + break; + case ISCSI_OP_SCSI_TASK_MGT_MSG: + err = cmnd_insert_hash(cmnd); + break; + case ISCSI_OP_SCSI_DATA_OUT: + data_out_start(conn, cmnd); + break; + case ISCSI_OP_LOGOUT_CMD: + err = cmnd_insert_hash(cmnd); + break; + case ISCSI_OP_TEXT_CMD: + case ISCSI_OP_SNACK_CMD: + err = -ISCSI_REASON_UNSUPPORTED_COMMAND; + break; + default: + err = -ISCSI_REASON_UNSUPPORTED_COMMAND; + break; + } + + if (err < 0) { + eprintk("%x %x %d\n", cmnd_opcode(cmnd), cmnd_itt(cmnd), err); + iscsi_cmnd_reject(cmnd, -err); + } +} + +void cmnd_rx_end(struct iscsi_cmnd *cmnd) +{ + struct iscsi_conn *conn = cmnd->conn; + + if (cmnd_tmfabort(cmnd)) { + cmnd_release(cmnd, 1); + return; + } + + dprintk(D_GENERIC, "%p:%x\n", cmnd, cmnd_opcode(cmnd)); + switch (cmnd_opcode(cmnd)) { + case ISCSI_OP_SCSI_REJECT: + case ISCSI_OP_NOOP_OUT: + case ISCSI_OP_SCSI_CMD: + case ISCSI_OP_SCSI_TASK_MGT_MSG: + case ISCSI_OP_TEXT_CMD: + case ISCSI_OP_LOGOUT_CMD: + iscsi_session_push_cmnd(cmnd); + break; + case ISCSI_OP_SCSI_DATA_OUT: + data_out_end(conn, cmnd); + break; + case ISCSI_OP_SNACK_CMD: + break; + case ISCSI_OP_PDU_REJECT: + iscsi_cmnd_init_write(get_rsp_cmnd(cmnd)); + break; + case ISCSI_OP_DATA_REJECT: + cmnd_release(cmnd, 0); + break; + default: + eprintk("unexpected cmnd op %x\n", cmnd_opcode(cmnd)); + BUG(); + break; + } +} + +static void iscsi_exit(void) +{ + unregister_chrdev(ctr_major, ctr_name); + + iet_procfs_exit(); + + event_exit(); + + tio_exit(); + + iotype_exit(); + + if (iscsi_cmnd_cache) + kmem_cache_destroy(iscsi_cmnd_cache); +} + +static int iscsi_init(void) +{ + int err = -ENOMEM; + + printk("iSCSI Enterprise Target Software - version %s\n", IET_VERSION_STRING); + + if ((ctr_major = register_chrdev(0, ctr_name, &ctr_fops)) < 0) { + eprintk("failed to register the control device %d\n", ctr_major); + return ctr_major; + } + + if ((err = iet_procfs_init()) < 0) + goto err; + + if ((err = event_init()) < 0) + goto err; + + iscsi_cmnd_cache = KMEM_CACHE(iscsi_cmnd, 0); + if (!iscsi_cmnd_cache) + goto err; + + if ((err = tio_init()) < 0) + goto err; + + if ((err = iotype_init()) < 0) + goto err; + + return 0; + +err: + iscsi_exit(); + return err; +} + +module_param(debug_enable_flags, ulong, S_IRUGO); + +module_init(iscsi_init); +module_exit(iscsi_exit); + +MODULE_LICENSE("GPL"); --- linux-2.6.27.orig/ubuntu/iscsitarget/tio.c +++ linux-2.6.27/ubuntu/iscsitarget/tio.c @@ -0,0 +1,121 @@ +/* + * Target I/O. + * (C) 2005 FUJITA Tomonori + * This code is licenced under the GPL. + */ + +#include "iscsi.h" +#include "iscsi_dbg.h" +#include "iotype.h" + +static int tio_add_pages(struct tio *tio, int count) +{ + int i; + struct page *page; + + dprintk(D_GENERIC, "%p %d (%d)\n", tio, count, tio->pg_cnt); + + tio->pg_cnt = count; + + count *= sizeof(struct page *); + + do { + tio->pvec = kzalloc(count, GFP_KERNEL); + if (!tio->pvec) + yield(); + } while (!tio->pvec); + + for (i = 0; i < tio->pg_cnt; i++) { + do { + if (!(page = alloc_page(GFP_KERNEL))) + yield(); + } while (!page); + tio->pvec[i] = page; + } + return 0; +} + +static struct kmem_cache *tio_cache; + +struct tio *tio_alloc(int count) +{ + struct tio *tio; + + tio = kmem_cache_alloc(tio_cache, GFP_KERNEL | __GFP_NOFAIL); + + tio->pg_cnt = 0; + tio->idx = 0; + tio->offset = 0; + tio->size = 0; + tio->pvec = NULL; + + atomic_set(&tio->count, 1); + + if (count) + tio_add_pages(tio, count); + + return tio; +} + +static void tio_free(struct tio *tio) +{ + int i; + for (i = 0; i < tio->pg_cnt; i++) { + assert(tio->pvec[i]); + __free_page(tio->pvec[i]); + } + kfree(tio->pvec); + kmem_cache_free(tio_cache, tio); +} + +void tio_put(struct tio *tio) +{ + assert(atomic_read(&tio->count)); + if (atomic_dec_and_test(&tio->count)) + tio_free(tio); +} + +void tio_get(struct tio *tio) +{ + atomic_inc(&tio->count); +} + +void tio_set(struct tio *tio, u32 size, loff_t offset) +{ + tio->idx = offset >> PAGE_CACHE_SHIFT; + tio->offset = offset & ~PAGE_CACHE_MASK; + tio->size = size; +} + +int tio_read(struct iet_volume *lu, struct tio *tio) +{ + struct iotype *iot = lu->iotype; + assert(iot); + return iot->make_request ? iot->make_request(lu, tio, READ) : 0; +} + +int tio_write(struct iet_volume *lu, struct tio *tio) +{ + struct iotype *iot = lu->iotype; + assert(iot); + return iot->make_request ? iot->make_request(lu, tio, WRITE) : 0; +} + +int tio_sync(struct iet_volume *lu, struct tio *tio) +{ + struct iotype *iot = lu->iotype; + assert(iot); + return iot->sync ? iot->sync(lu, tio) : 0; +} + +int tio_init(void) +{ + tio_cache = KMEM_CACHE(tio, 0); + return tio_cache ? 0 : -ENOMEM; +} + +void tio_exit(void) +{ + if (tio_cache) + kmem_cache_destroy(tio_cache); +} --- linux-2.6.27.orig/ubuntu/iscsitarget/session.c +++ linux-2.6.27/ubuntu/iscsitarget/session.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2002-2003 Ardis Technolgies + * + * Released under the terms of the GNU GPL v2.0. + */ + +#include "iscsi.h" +#include "iscsi_dbg.h" + +struct iscsi_session *session_lookup(struct iscsi_target *target, u64 sid) +{ + struct iscsi_session *session; + + list_for_each_entry(session, &target->session_list, list) { + if (session->sid == sid) + return session; + } + return NULL; +} + +static struct iscsi_session * +iet_session_alloc(struct iscsi_target *target, struct session_info *info) +{ + int i; + struct iscsi_session *session; + + dprintk(D_SETUP, "%p %u %#Lx\n", target, target->tid, + (unsigned long long) info->sid); + + session = kzalloc(sizeof(*session), GFP_KERNEL); + if (!session) + return NULL; + + session->target = target; + session->sid = info->sid; + memcpy(&session->param, &target->sess_param, sizeof(session->param)); + session->max_queued_cmnds = target->trgt_param.queued_cmnds; + + session->exp_cmd_sn = info->exp_cmd_sn; + session->max_cmd_sn = info->max_cmd_sn; + + session->initiator = kstrdup(info->initiator_name, GFP_KERNEL); + if (!session->initiator) { + kfree(session); + return NULL; + } + + INIT_LIST_HEAD(&session->conn_list); + INIT_LIST_HEAD(&session->pending_list); + + spin_lock_init(&session->cmnd_hash_lock); + for (i = 0; i < ARRAY_SIZE(session->cmnd_hash); i++) + INIT_LIST_HEAD(&session->cmnd_hash[i]); + + session->next_ttt = 1; + + list_add(&session->list, &target->session_list); + + return session; +} + +static int session_free(struct iscsi_session *session) +{ + int i; + + dprintk(D_SETUP, "%#Lx\n", (unsigned long long) session->sid); + + assert(list_empty(&session->conn_list)); + + for (i = 0; i < ARRAY_SIZE(session->cmnd_hash); i++) { + if (!list_empty(&session->cmnd_hash[i])) + BUG(); + } + + list_del(&session->list); + + kfree(session->initiator); + kfree(session); + + return 0; +} + +int session_add(struct iscsi_target *target, struct session_info *info) +{ + struct iscsi_session *session; + int err = -EEXIST; + + session = session_lookup(target, info->sid); + if (session) + return err; + + session = iet_session_alloc(target, info); + if (!session) + err = -ENOMEM; + + return err; +} + +int session_del(struct iscsi_target *target, u64 sid) +{ + struct iscsi_session *session; + + session = session_lookup(target, sid); + if (!session) + return -ENOENT; + + if (!list_empty(&session->conn_list)) { + eprintk("%llu still have connections\n", (unsigned long long) session->sid); + return -EBUSY; + } + + return session_free(session); +} + +static void iet_session_info_show(struct seq_file *seq, struct iscsi_target *target) +{ + struct iscsi_session *session; + + list_for_each_entry(session, &target->session_list, list) { + seq_printf(seq, "\tsid:%llu initiator:%s\n", + (unsigned long long) session->sid, session->initiator); + conn_info_show(seq, session); + } +} + +static int iet_sessions_info_show(struct seq_file *seq, void *v) +{ + return iet_info_show(seq, iet_session_info_show); +} + +static int iet_session_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, iet_sessions_info_show, NULL); +} + +struct file_operations session_seq_fops = { + .owner = THIS_MODULE, + .open = iet_session_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; --- linux-2.6.27.orig/ubuntu/iscsitarget/iotype.h +++ linux-2.6.27/ubuntu/iscsitarget/iotype.h @@ -0,0 +1,29 @@ +/* + * (C) 2004 - 2005 FUJITA Tomonori + * This code is licenced under the GPL. + */ + +#include "iscsi.h" + +#ifndef __IOTYPE_H__ +#define __IOTYPE_H__ + +struct iotype { + const char *name; + struct list_head iot_list; + + int (*attach)(struct iet_volume *dev, char *args); + int (*make_request)(struct iet_volume *dev, struct tio *tio, int rw); + int (*sync)(struct iet_volume *dev, struct tio *tio); + void (*detach)(struct iet_volume *dev); + void (*show)(struct iet_volume *dev, struct seq_file *seq); +}; + +extern struct iotype fileio; +extern struct iotype nullio; +extern struct iotype blockio; + +extern int iotype_init(void); +extern void iotype_exit(void); + +#endif --- linux-2.6.27.orig/ubuntu/iscsitarget/BOM +++ linux-2.6.27/ubuntu/iscsitarget/BOM @@ -0,0 +1,4 @@ +Main web page: http://iscsitarget.sourceforge.net/ +Mailing list: http://dir.gmane.org/gmane.linux.iscsi.iscsi-target.devel +Download: http://sourceforge.net/project/showfiles.php?group_id=108475 +Cur. version: 0.4.16 --- linux-2.6.27.orig/ubuntu/iscsitarget/iotype.c +++ linux-2.6.27/ubuntu/iscsitarget/iotype.c @@ -0,0 +1,110 @@ +/* + * Manager for various I/O types. + * (C) 2004 - 2005 FUJITA Tomonori + * This code is licenced under the GPL. + */ + +#include "iscsi.h" +#include "iotype.h" +#include "iscsi_dbg.h" + +static LIST_HEAD(iotypes); +static rwlock_t iotypes_lock = RW_LOCK_UNLOCKED; + +static struct iotype *find_iotype(const char *name) +{ + struct iotype *iot = NULL; + + list_for_each_entry(iot, &iotypes, iot_list) { + if (strcmp(iot->name, name) == 0) + return iot; + } + return NULL; +} + +struct iotype *get_iotype(const char *name) +{ + struct iotype *iot; + + read_lock(&iotypes_lock); + iot = find_iotype(name); + read_unlock(&iotypes_lock); + + return iot; +} + +void put_iotype(struct iotype *iot) +{ + if (!iot) + return; + return; +} + +static int register_iotype(struct iotype *iot) +{ + int err = 0; + struct iotype *p; + + write_lock(&iotypes_lock); + + p = find_iotype(iot->name); + if (p) + err = -EBUSY; + else + list_add_tail(&iot->iot_list, &iotypes); + + write_unlock(&iotypes_lock); + + return err; +} + +static int unregister_iotype(struct iotype *iot) +{ + int err = 0; + struct iotype *p; + + write_lock(&iotypes_lock); + + p = find_iotype(iot->name); + if (p && p == iot) + list_del_init(&iot->iot_list); + else + err = -EINVAL; + + write_unlock(&iotypes_lock); + + + return err; +} + +struct iotype *iotype_array[] = { + &fileio, + &blockio, + &nullio, +}; + +int iotype_init(void) +{ + int i, err; + + for (i = 0; i < ARRAY_SIZE(iotype_array); i++) { + if (!(err = register_iotype(iotype_array[i]))) + iprintk("Registered io type %s\n", + iotype_array[i]->name); + else { + eprintk("Failed to register io type %s\n", + iotype_array[i]->name); + break; + } + } + + return err; +} + +void iotype_exit(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(iotype_array); i++) + unregister_iotype(iotype_array[i]); +} --- linux-2.6.27.orig/ubuntu/iscsitarget/iet_u.h +++ linux-2.6.27/ubuntu/iscsitarget/iet_u.h @@ -0,0 +1,139 @@ +#ifndef _IET_U_H +#define _IET_U_H + +#define IET_VERSION_STRING "0.4.16" + +/* The maximum length of 223 bytes in the RFC. */ +#define ISCSI_NAME_LEN 256 +#define ISCSI_ARGS_LEN 2048 + +#define ISCSI_LISTEN_PORT 3260 + +#define VENDOR_ID_LEN 8 +#define SCSI_ID_LEN 24 +#define SCSI_SN_LEN 16 + +#ifndef aligned_u64 +#define aligned_u64 unsigned long long __attribute__((aligned(8))) +#endif + +struct target_info { + u32 tid; + char name[ISCSI_NAME_LEN]; +}; + +struct volume_info { + u32 tid; + u32 lun; + aligned_u64 args_ptr; + u32 args_len; +}; + +struct session_info { + u32 tid; + + aligned_u64 sid; + char initiator_name[ISCSI_NAME_LEN]; + u32 exp_cmd_sn; + u32 max_cmd_sn; +}; + +#define DIGEST_ALL (DIGEST_NONE | DIGEST_CRC32C) +#define DIGEST_NONE (1 << 0) +#define DIGEST_CRC32C (1 << 1) + +struct conn_info { + u32 tid; + aligned_u64 sid; + + u32 cid; + u32 stat_sn; + u32 exp_stat_sn; + int header_digest; + int data_digest; + int fd; +}; + +enum { + key_initial_r2t, + key_immediate_data, + key_max_connections, + key_max_recv_data_length, + key_max_xmit_data_length, + key_max_burst_length, + key_first_burst_length, + key_default_wait_time, + key_default_retain_time, + key_max_outstanding_r2t, + key_data_pdu_inorder, + key_data_sequence_inorder, + key_error_recovery_level, + key_header_digest, + key_data_digest, + key_ofmarker, + key_ifmarker, + key_ofmarkint, + key_ifmarkint, + session_key_last, +}; + +enum { + key_wthreads, + key_target_type, + key_queued_cmnds, + target_key_last, +}; + +enum { + key_session, + key_target, +}; + +struct iscsi_param_info { + u32 tid; + aligned_u64 sid; + + u32 param_type; + u32 partial; + + u32 session_param[session_key_last]; + u32 target_param[target_key_last]; +}; + +enum iet_event_state { + E_CONN_CLOSE, +}; + +struct iet_event { + u32 tid; + aligned_u64 sid; + u32 cid; + u32 state; +}; + +#define DEFAULT_NR_WTHREADS 8 +#define MIN_NR_WTHREADS 1 +#define MAX_NR_WTHREADS 128 + +#define DEFAULT_NR_QUEUED_CMNDS 32 +#define MIN_NR_QUEUED_CMNDS 1 +#define MAX_NR_QUEUED_CMNDS 256 + +#define NETLINK_IET 21 + +#define ADD_TARGET _IOW('i', 0, struct target_info) +#define DEL_TARGET _IOW('i', 1, struct target_info) +#define START_TARGET _IO('i', 2) +#define STOP_TARGET _IO('i', 3) +#define ADD_VOLUME _IOW('i', 4, struct volume_info) +#define DEL_VOLUME _IOW('i', 5, struct volume_info) +#define ADD_SESSION _IOW('i', 6, struct session_info) +#define DEL_SESSION _IOW('i', 7, struct session_info) +#define GET_SESSION_INFO _IOWR('i', 8, struct session_info) +#define ADD_CONN _IOW('i', 9, struct conn_info) +#define DEL_CONN _IOW('i', 10, struct conn_info) +#define GET_CONN_INFO _IOWR('i', 11, struct conn_info) +#define ISCSI_PARAM_SET _IOW('i', 12, struct iscsi_param_info) +#define ISCSI_PARAM_GET _IOWR('i', 13, struct iscsi_param_info) + +#endif --- linux-2.6.27.orig/ubuntu/iscsitarget/iscsi.h +++ linux-2.6.27/ubuntu/iscsitarget/iscsi.h @@ -0,0 +1,447 @@ +/* + * Copyright (C) 2002-2003 Ardis Technolgies + * + * Released under the terms of the GNU GPL v2.0. + */ + +#ifndef __ISCSI_H__ +#define __ISCSI_H__ + +#include +#include +#include +#include +#include +#include + +#include "iscsi_hdr.h" +#include "iet_u.h" + +struct iscsi_sess_param { + int initial_r2t; + int immediate_data; + int max_connections; + int max_recv_data_length; + int max_xmit_data_length; + int max_burst_length; + int first_burst_length; + int default_wait_time; + int default_retain_time; + int max_outstanding_r2t; + int data_pdu_inorder; + int data_sequence_inorder; + int error_recovery_level; + int header_digest; + int data_digest; + int ofmarker; + int ifmarker; + int ofmarkint; + int ifmarkint; +}; + +struct iscsi_trgt_param { + int wthreads; + int target_type; + int queued_cmnds; +}; + +struct tio { + u32 pg_cnt; + + pgoff_t idx; + u32 offset; + u32 size; + + struct page **pvec; + + atomic_t count; +}; + +struct network_thread_info { + struct task_struct *task; + unsigned long flags; + struct list_head active_conns; + + spinlock_t nthread_lock; + + void (*old_state_change)(struct sock *); + void (*old_data_ready)(struct sock *, int); +}; + +struct worker_thread_info; + +struct worker_thread { + struct task_struct *w_task; + struct list_head w_list; + struct worker_thread_info *w_info; +}; + +struct worker_thread_info { + spinlock_t wthread_lock; + + u32 nr_running_wthreads; + + struct list_head wthread_list; + struct list_head work_queue; + + wait_queue_head_t wthread_sleep; +}; + +struct iscsi_cmnd; + +struct target_type { + int id; + int (*execute_cmnd) (struct iscsi_cmnd *); +}; + +enum iscsi_device_state { + IDEV_RUNNING, + IDEV_DEL, +}; + +struct iscsi_target { + struct list_head t_list; + u32 tid; + + char name[ISCSI_NAME_LEN]; + + struct iscsi_sess_param sess_param; + struct iscsi_trgt_param trgt_param; + + atomic_t nr_volumes; + struct list_head volumes; + struct list_head session_list; + + struct network_thread_info nthread_info; + struct worker_thread_info wthread_info; + + struct semaphore target_sem; +}; + +struct iscsi_queue { + spinlock_t queue_lock; + struct iscsi_cmnd *ordered_cmnd; + struct list_head wait_list; + int active_cnt; +}; + +struct iet_volume { + u32 lun; + + enum iscsi_device_state l_state; + atomic_t l_count; + + struct iscsi_target *target; + struct list_head list; + + struct iscsi_queue queue; + + u8 scsi_id[SCSI_ID_LEN]; + u8 scsi_sn[SCSI_SN_LEN]; + + u32 blk_shift; + u64 blk_cnt; + + u64 reserve_sid; + spinlock_t reserve_lock; + + unsigned long flags; + + struct iotype *iotype; + void *private; +}; + +enum lu_flags { + LU_READONLY, + LU_ASYNC, +}; + +#define LUReadonly(lu) test_bit(LU_READONLY, &(lu)->flags) +#define SetLUReadonly(lu) set_bit(LU_READONLY, &(lu)->flags) + +#define LUAsync(lu) test_bit(LU_ASYNC, &(lu)->flags) +#define SetLUAsync(lu) set_bit(LU_ASYNC, &(lu)->flags) + +#define IET_HASH_ORDER 8 +#define cmnd_hashfn(itt) hash_long((itt), IET_HASH_ORDER) + +struct iscsi_session { + struct list_head list; + struct iscsi_target *target; + + char *initiator; + u64 sid; + + u32 exp_cmd_sn; + u32 max_cmd_sn; + + struct iscsi_sess_param param; + u32 max_queued_cmnds; + + struct list_head conn_list; + + struct list_head pending_list; + + spinlock_t cmnd_hash_lock; + struct list_head cmnd_hash[1 << IET_HASH_ORDER]; + + u32 next_ttt; +}; + +enum connection_state_bit { + CONN_ACTIVE, + CONN_CLOSING, +}; + +#define ISCSI_CONN_IOV_MAX (((256 << 10) >> PAGE_SHIFT) + 1) + +struct iscsi_conn { + struct list_head list; /* list entry in session list */ + struct iscsi_session *session; /* owning session */ + + u16 cid; + unsigned long state; + + u32 stat_sn; + u32 exp_stat_sn; + + int hdigest_type; + int ddigest_type; + + struct list_head poll_list; + + struct file *file; + struct socket *sock; + spinlock_t list_lock; + atomic_t nr_cmnds; + atomic_t nr_busy_cmnds; + struct list_head pdu_list; /* in/outcoming pdus */ + struct list_head write_list; /* list of data pdus to be sent */ + + struct iscsi_cmnd *read_cmnd; + struct msghdr read_msg; + struct iovec read_iov[ISCSI_CONN_IOV_MAX]; + u32 read_size; + u32 read_overflow; + int read_state; + + struct iscsi_cmnd *write_cmnd; + struct iovec write_iov[ISCSI_CONN_IOV_MAX]; + struct iovec *write_iop; + struct tio *write_tcmnd; + u32 write_size; + u32 write_offset; + int write_state; + + struct hash_desc rx_hash; + struct hash_desc tx_hash; + struct scatterlist hash_sg[ISCSI_CONN_IOV_MAX]; +}; + +struct iscsi_pdu { + struct iscsi_hdr bhs; + void *ahs; + unsigned int ahssize; + unsigned int datasize; +}; + +typedef void (iet_show_info_t)(struct seq_file *seq, struct iscsi_target *target); + +struct iscsi_cmnd { + struct list_head list; + struct list_head conn_list; + unsigned long flags; + struct iscsi_conn *conn; + struct iet_volume *lun; + + struct iscsi_pdu pdu; + struct list_head pdu_list; + + struct list_head hash_list; + + struct tio *tio; + + u32 r2t_sn; + u32 r2t_length; + u32 is_unsolicited_data; + u32 target_task_tag; + u32 outstanding_r2t; + + u32 hdigest; + u32 ddigest; + + struct iscsi_cmnd *req; +}; + +#define ISCSI_OP_SCSI_REJECT ISCSI_OP_VENDOR1_CMD +#define ISCSI_OP_PDU_REJECT ISCSI_OP_VENDOR2_CMD +#define ISCSI_OP_DATA_REJECT ISCSI_OP_VENDOR3_CMD +#define ISCSI_OP_SCSI_ABORT ISCSI_OP_VENDOR4_CMD + +/* iscsi.c */ +extern struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *, int); +extern void cmnd_rx_start(struct iscsi_cmnd *); +extern void cmnd_rx_end(struct iscsi_cmnd *); +extern void cmnd_tx_start(struct iscsi_cmnd *); +extern void cmnd_tx_end(struct iscsi_cmnd *); +extern void cmnd_release(struct iscsi_cmnd *, int); +extern void send_data_rsp(struct iscsi_cmnd *, int (*)(struct iscsi_cmnd *)); +extern void send_scsi_rsp(struct iscsi_cmnd *, int (*)(struct iscsi_cmnd *)); + +/* conn.c */ +extern struct iscsi_conn *conn_lookup(struct iscsi_session *, u16); +extern int conn_add(struct iscsi_session *, struct conn_info *); +extern int conn_del(struct iscsi_session *, struct conn_info *); +extern int conn_free(struct iscsi_conn *); +extern void conn_close(struct iscsi_conn *); +extern void conn_info_show(struct seq_file *, struct iscsi_session *); + +/* nthread.c */ +extern int nthread_init(struct iscsi_target *); +extern int nthread_start(struct iscsi_target *); +extern int nthread_stop(struct iscsi_target *); +extern void nthread_wakeup(struct iscsi_target *); + +/* wthread.c */ +extern int wthread_init(struct iscsi_target *); +extern int wthread_start(struct iscsi_target *); +extern int wthread_stop(struct iscsi_target *); +extern void wthread_queue(struct iscsi_cmnd *); +extern struct target_type *target_type_array[]; + +/* target.c */ +extern int target_lock(struct iscsi_target *, int); +extern void target_unlock(struct iscsi_target *); +struct iscsi_target *target_lookup_by_id(u32); +extern int target_add(struct target_info *); +extern int target_del(u32 id); + +/* config.c */ +extern int iet_procfs_init(void); +extern void iet_procfs_exit(void); +extern int iet_info_show(struct seq_file *, iet_show_info_t *); + +/* session.c */ +extern struct file_operations session_seq_fops; +extern struct iscsi_session *session_lookup(struct iscsi_target *, u64); +extern int session_add(struct iscsi_target *, struct session_info *); +extern int session_del(struct iscsi_target *, u64); + +/* volume.c */ +extern struct file_operations volume_seq_fops; +extern int volume_add(struct iscsi_target *, struct volume_info *); +extern int iscsi_volume_del(struct iscsi_target *, struct volume_info *); +extern void iscsi_volume_destroy(struct iet_volume *); +extern struct iet_volume *volume_lookup(struct iscsi_target *, u32); +extern struct iet_volume *volume_get(struct iscsi_target *, u32); +extern void volume_put(struct iet_volume *); +extern int volume_reserve(struct iet_volume *volume, u64 sid); +extern int volume_release(struct iet_volume *volume, u64 sid, int force); +extern int is_volume_reserved(struct iet_volume *volume, u64 sid); + +/* tio.c */ +extern int tio_init(void); +extern void tio_exit(void); +extern struct tio *tio_alloc(int); +extern void tio_get(struct tio *); +extern void tio_put(struct tio *); +extern void tio_set(struct tio *, u32, loff_t); +extern int tio_read(struct iet_volume *, struct tio *); +extern int tio_write(struct iet_volume *, struct tio *); +extern int tio_sync(struct iet_volume *, struct tio *); + +/* iotype.c */ +extern struct iotype *get_iotype(const char *name); +extern void put_iotype(struct iotype *iot); + +/* params.c */ +extern int iscsi_param_set(struct iscsi_target *, struct iscsi_param_info *, int); + +/* target_disk.c */ +extern struct target_type disk_ops; + +/* event.c */ +extern int event_send(u32, u64, u32, u32, int); +extern int event_init(void); +extern void event_exit(void); + +#define get_pgcnt(size, offset) ((((size) + ((offset) & ~PAGE_CACHE_MASK)) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) + +static inline void iscsi_cmnd_get_length(struct iscsi_pdu *pdu) +{ +#if defined(__BIG_ENDIAN) + pdu->ahssize = pdu->bhs.length.ahslength * 4; + pdu->datasize = pdu->bhs.length.datalength; +#elif defined(__LITTLE_ENDIAN) + pdu->ahssize = (pdu->bhs.length & 0xff) * 4; + pdu->datasize = be32_to_cpu(pdu->bhs.length & ~0xff); +#else +#error +#endif +} + +static inline void iscsi_cmnd_set_length(struct iscsi_pdu *pdu) +{ +#if defined(__BIG_ENDIAN) + pdu->bhs.length.ahslength = pdu->ahssize / 4; + pdu->bhs.length.datalength = pdu->datasize; +#elif defined(__LITTLE_ENDIAN) + pdu->bhs.length = cpu_to_be32(pdu->datasize) | (pdu->ahssize / 4); +#else +#error +#endif +} + +#define cmnd_hdr(cmnd) ((struct iscsi_scsi_cmd_hdr *) (&((cmnd)->pdu.bhs))) +#define cmnd_ttt(cmnd) cpu_to_be32((cmnd)->pdu.bhs.ttt) +#define cmnd_itt(cmnd) cpu_to_be32((cmnd)->pdu.bhs.itt) +#define cmnd_opcode(cmnd) ((cmnd)->pdu.bhs.opcode & ISCSI_OPCODE_MASK) +#define cmnd_scsicode(cmnd) cmnd_hdr(cmnd)->scb[0] + +#define SECTOR_SIZE_BITS 9 + +enum cmnd_flags { + CMND_hashed, + CMND_queued, + CMND_final, + CMND_waitio, + CMND_close, + CMND_lunit, + CMND_pending, + CMND_tmfabort, + CMND_rxstart, +}; + +#define set_cmnd_hashed(cmnd) set_bit(CMND_hashed, &(cmnd)->flags) +#define cmnd_hashed(cmnd) test_bit(CMND_hashed, &(cmnd)->flags) + +#define set_cmnd_queued(cmnd) set_bit(CMND_queued, &(cmnd)->flags) +#define cmnd_queued(cmnd) test_bit(CMND_queued, &(cmnd)->flags) + +#define set_cmnd_final(cmnd) set_bit(CMND_final, &(cmnd)->flags) +#define cmnd_final(cmnd) test_bit(CMND_final, &(cmnd)->flags) + +#define set_cmnd_waitio(cmnd) set_bit(CMND_waitio, &(cmnd)->flags) +#define cmnd_waitio(cmnd) test_bit(CMND_waitio, &(cmnd)->flags) + +#define set_cmnd_close(cmnd) set_bit(CMND_close, &(cmnd)->flags) +#define cmnd_close(cmnd) test_bit(CMND_close, &(cmnd)->flags) + +#define set_cmnd_lunit(cmnd) set_bit(CMND_lunit, &(cmnd)->flags) +#define cmnd_lunit(cmnd) test_bit(CMND_lunit, &(cmnd)->flags) + +#define set_cmnd_pending(cmnd) set_bit(CMND_pending, &(cmnd)->flags) +#define clear_cmnd_pending(cmnd) clear_bit(CMND_pending, &(cmnd)->flags) +#define cmnd_pending(cmnd) test_bit(CMND_pending, &(cmnd)->flags) + +#define set_cmnd_tmfabort(cmnd) set_bit(CMND_tmfabort, &(cmnd)->flags) +#define cmnd_tmfabort(cmnd) test_bit(CMND_tmfabort, &(cmnd)->flags) + +#define set_cmnd_rxstart(cmnd) set_bit(CMND_rxstart, &(cmnd)->flags) +#define cmnd_rxstart(cmnd) test_bit(CMND_rxstart, &(cmnd)->flags) + +#define VENDOR_ID "IET" +#define PRODUCT_ID "VIRTUAL-DISK" +#define PRODUCT_REV "0" + +#endif /* __ISCSI_H__ */ --- linux-2.6.27.orig/ubuntu/iscsitarget/config.c +++ linux-2.6.27/ubuntu/iscsitarget/config.c @@ -0,0 +1,316 @@ +/* + * (C) 2004 - 2005 FUJITA Tomonori + * + * This code is licenced under the GPL. + */ + +#include + +#include "iscsi.h" +#include "iscsi_dbg.h" + +struct proc_entries { + const char *name; + struct file_operations *fops; +}; + +static struct proc_entries iet_proc_entries[] = +{ + {"volume", &volume_seq_fops}, + {"session", &session_seq_fops}, +}; + +static struct proc_dir_entry *proc_iet_dir; + +void iet_procfs_exit(void) +{ + int i; + + if (!proc_iet_dir) + return; + + for (i = 0; i < ARRAY_SIZE(iet_proc_entries); i++) + remove_proc_entry(iet_proc_entries[i].name, proc_iet_dir); + + remove_proc_entry(proc_iet_dir->name, proc_iet_dir->parent); +} + +int iet_procfs_init(void) +{ + int i; + struct proc_dir_entry *ent; + + if (!(proc_iet_dir = proc_mkdir("iet", init_net.proc_net))) + goto err; + + proc_iet_dir->owner = THIS_MODULE; + + for (i = 0; i < ARRAY_SIZE(iet_proc_entries); i++) { + ent = create_proc_entry(iet_proc_entries[i].name, 0, proc_iet_dir); + if (ent) + ent->proc_fops = iet_proc_entries[i].fops; + else + goto err; + } + + return 0; + +err: + if (proc_iet_dir) + iet_procfs_exit(); + + return -ENOMEM; +} + +static int get_conn_info(struct iscsi_target *target, unsigned long ptr) +{ + int err; + struct iscsi_session *session; + struct conn_info info; + struct iscsi_conn *conn; + + if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) + return err; + + session = session_lookup(target, info.sid); + if (!session) + return -ENOENT; + conn = conn_lookup(session, info.cid); + + info.cid = conn->cid; + info.stat_sn = conn->stat_sn; + info.exp_stat_sn = conn->exp_stat_sn; + + if (copy_to_user((void *) ptr, &info, sizeof(info))) + return -EFAULT; + + return 0; +} + +static int add_conn(struct iscsi_target *target, unsigned long ptr) +{ + int err; + struct iscsi_session *session; + struct conn_info info; + + if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) + return err; + + if (!(session = session_lookup(target, info.sid))) + return -ENOENT; + + return conn_add(session, &info); +} + +static int del_conn(struct iscsi_target *target, unsigned long ptr) +{ + int err; + struct iscsi_session *session; + struct conn_info info; + + if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) + return err; + + if (!(session = session_lookup(target, info.sid))) + return -ENOENT; + + return conn_del(session, &info); +} + +static int get_session_info(struct iscsi_target *target, unsigned long ptr) +{ + int err; + struct iscsi_session *session; + struct session_info info; + + if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) + return err; + + session = session_lookup(target, info.sid); + + if (!session) + return -ENOENT; + + info.exp_cmd_sn = session->exp_cmd_sn; + info.max_cmd_sn = session->max_cmd_sn; + + if (copy_to_user((void *) ptr, &info, sizeof(info))) + return -EFAULT; + + return 0; +} + +static int add_session(struct iscsi_target *target, unsigned long ptr) +{ + int err; + struct session_info info; + + if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) + return err; + + return session_add(target, &info); +} + +static int del_session(struct iscsi_target *target, unsigned long ptr) +{ + int err; + struct session_info info; + + if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) + return err; + + return session_del(target, info.sid); +} + +static int add_volume(struct iscsi_target *target, unsigned long ptr) +{ + int err; + struct volume_info info; + + if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) + return err; + + return volume_add(target, &info); +} + +static int del_volume(struct iscsi_target *target, unsigned long ptr) +{ + int err; + struct volume_info info; + + if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) + return err; + + return iscsi_volume_del(target, &info); +} + +static int iscsi_param_config(struct iscsi_target *target, unsigned long ptr, int set) +{ + int err; + struct iscsi_param_info info; + + if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) + goto out; + + if ((err = iscsi_param_set(target, &info, set)) < 0) + goto out; + + if (!set) + err = copy_to_user((void *) ptr, &info, sizeof(info)); + +out: + return err; +} + +static int add_target(unsigned long ptr) +{ + int err; + struct target_info info; + + if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) + return err; + + if (!(err = target_add(&info))) + err = copy_to_user((void *) ptr, &info, sizeof(info)); + + return err; +} + +static long ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct iscsi_target *target = NULL; + long err; + u32 id; + + if ((err = get_user(id, (u32 *) arg)) != 0) + goto done; + + if (cmd == DEL_TARGET) { + err = target_del(id); + goto done; + } + + target = target_lookup_by_id(id); + + if (cmd == ADD_TARGET) + if (target) { + err = -EEXIST; + eprintk("Target %u already exist!\n", id); + goto done; + } + + switch (cmd) { + case ADD_TARGET: + assert(!target); + err = add_target(arg); + goto done; + } + + if (!target) { + eprintk("can't find the target %u\n", id); + err = -EINVAL; + goto done; + } + + if ((err = target_lock(target, 1)) < 0) { + eprintk("interrupted %ld %d\n", err, cmd); + goto done; + } + + switch (cmd) { + case ADD_VOLUME: + err = add_volume(target, arg); + break; + + case DEL_VOLUME: + err = del_volume(target, arg); + break; + + case ADD_SESSION: + err = add_session(target, arg); + break; + + case DEL_SESSION: + err = del_session(target, arg); + break; + + case GET_SESSION_INFO: + err = get_session_info(target, arg); + break; + + case ISCSI_PARAM_SET: + err = iscsi_param_config(target, arg, 1); + break; + + case ISCSI_PARAM_GET: + err = iscsi_param_config(target, arg, 0); + break; + + case ADD_CONN: + err = add_conn(target, arg); + break; + + case DEL_CONN: + err = del_conn(target, arg); + break; + + case GET_CONN_INFO: + err = get_conn_info(target, arg); + break; + default: + eprintk("invalid ioctl cmd %x\n", cmd); + err = -EINVAL; + } + + if (target) + target_unlock(target); + +done: + return err; +} + +struct file_operations ctr_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = ioctl, + .compat_ioctl = ioctl, +}; --- linux-2.6.27.orig/ubuntu/lirc/Kconfig +++ linux-2.6.27/ubuntu/lirc/Kconfig @@ -0,0 +1,94 @@ +config LIRC_DEV + tristate "LIRC Device support" + default m + +config LIRC_ATIUSB + tristate "LIRC ATI RF Remote" + default m + depends on LIRC_DEV + +config LIRC_BT829 + tristate "LIRC BT829" + default m + depends on LIRC_DEV + +config LIRC_CMDIR + tristate "LIRC CommandIR kernel support" + default m + depends on LIRC_DEV + +config LIRC_I2C + tristate "LIRC I2C interface remote" + default m + depends on LIRC_DEV + +config LIRC_IGORPLUGUSB + tristate "LIRC IGOR custom remote" + default m + depends on LIRC_DEV + +config LIRC_IMON + tristate "LIRC Imon remote or pad" + default m + depends on LIRC_DEV + +config LIRC_IT87 + tristate "LIRC IT87" + default m + depends on LIRC_DEV + +config LIRC_MCEUSB + tristate "LIRC Microsoft Media Center Remote" + default m + depends on LIRC_DEV + +config LIRC_MCEUSB2 + tristate "LIRC Microsoft Media Center Remote v2" + default m + depends on LIRC_DEV + +config LIRC_PVR150 + tristate "LIRC Hauppauge PVR-XXX remote" + default m + depends on LIRC_DEV + depends on VIDEO_IVTV + +config LIRC_PARALLEL + tristate "LIRC Parallel port custom remote" + default n + depends on LIRC_DEV + +config LIRC_SASEM + tristate "LIRC Sasem" + default m + depends on LIRC_DEV + +config LIRC_SERIAL + tristate "LIRC Serial port remote" + default m + depends on LIRC_DEV + +config LIRC_SERIAL_IGOR + tristate "LIRC Igor design serial remote" + default m + depends on LIRC_DEV + +config LIRC_SIR + tristate "LIRC Laptop port IR (SIR))" + default m + depends on LIRC_DEV + +config LIRC_STREAMZAP + tristate "LIRC Streamzap remote" + default m + depends on LIRC_DEV + +config LIRC_TTUSBIR + tristate "LIRC TT USB IR device" + default m + depends on LIRC_DEV + +config LIRC_GPIO + tristate "LIRC TV Card GPIO remote" + default n + depends on LIRC_DEV --- linux-2.6.27.orig/ubuntu/lirc/kcompat.h +++ linux-2.6.27/ubuntu/lirc/kcompat.h @@ -0,0 +1,369 @@ +/* $Id: kcompat.h,v 5.36 2008/05/14 16:37:49 lirc Exp $ */ + +#ifndef _KCOMPAT_H +#define _KCOMPAT_H + +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) +#define LIRC_THIS_MODULE(x) x, +#else /* >= 2.6.16 */ +#define LIRC_THIS_MODULE(x) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) +#define LIRC_HAVE_DEVFS +#define LIRC_HAVE_DEVFS_26 +#endif + +#define LIRC_HAVE_SYSFS + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13) + +typedef struct class_simple lirc_class_t; + +static inline lirc_class_t *class_create(struct module *owner, char *name) +{ + return class_simple_create(owner, name); +} + +static inline void class_destroy(lirc_class_t *cls) +{ + class_simple_destroy(cls); +} + +#define lirc_device_create(cs, parent, dev, fmt, args...) \ + class_simple_device_add(cs, dev, parent, fmt, ## args) + +static inline void lirc_device_destroy(lirc_class_t *cls, dev_t devt) +{ + class_simple_device_remove(devt); +} + +#else /* >= 2.6.13 */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15) + +#define lirc_device_create(cs, parent, dev, fmt, args...) \ + class_device_create(cs, dev, parent, fmt, ## args) + +#else /* >= 2.6.15 */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) + +#define lirc_device_create(cs, parent, dev, fmt, args...) \ + class_device_create(cs, NULL, dev, parent, fmt, ## args) + +#else /* >= 2.6.26 */ + +#define lirc_device_create device_create + +#endif /* >= 2.6.26 */ + +#define LIRC_DEVFS_PREFIX + +#endif /* >= 2.6.15 */ + +typedef struct class lirc_class_t; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) + +#define lirc_device_destroy class_device_destroy + +#else + +#define lirc_device_destroy device_destroy + +#endif + +#endif /* >= 2.6.13 */ + +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) +#define LIRC_HAVE_DEVFS +#define LIRC_HAVE_DEVFS_24 +#endif + +#ifndef LIRC_DEVFS_PREFIX +#define LIRC_DEVFS_PREFIX "usb/" +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) +#include +#include +static inline void del_timer_sync(struct timer_list *timerlist) +{ + start_bh_atomic(); + del_timer(timerlist); + end_bh_atomic(); +} +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +#ifdef daemonize +#undef daemonize +#endif +#define daemonize(name) do { \ + \ + lock_kernel(); \ + \ + exit_mm(current); \ + exit_files(current); \ + exit_fs(current); \ + current->session = 1; \ + current->pgrp = 1; \ + current->euid = 0; \ + current->tty = NULL; \ + sigfillset(¤t->blocked); \ + \ + strcpy(current->comm, name); \ + \ + unlock_kernel(); \ + \ +} while (0) + +/* Not sure when this was introduced, sometime during 2.5.X */ +#define MODULE_PARM_int(x) MODULE_PARM(x, "i") +#define MODULE_PARM_bool(x) MODULE_PARM(x, "i") +#define MODULE_PARM_long(x) MODULE_PARM(x, "l") +#define module_param(x, y, z) MODULE_PARM_##y(x) +#else +#include +#endif /* Linux < 2.6.0 */ + +/* DevFS header */ +#if defined(LIRC_HAVE_DEVFS) +#include +#endif + +#ifdef LIRC_HAVE_DEVFS_24 +#ifdef register_chrdev +#undef register_chrdev +#endif +#define register_chrdev devfs_register_chrdev +#ifdef unregister_chrdev +#undef unregister_chrdev +#endif +#define unregister_chrdev devfs_unregister_chrdev +#endif /* DEVFS 2.4 */ + +#ifndef LIRC_HAVE_SYSFS +#define class_destroy(x) do { } while (0) +#define class_create(x, y) NULL +#define lirc_class_destroy(x, y) do { } while (0) +#define lirc_class_create(x, y, z, xx, yy, zz) 0 +#define IS_ERR(x) 0 +typedef struct class_simple +{ + int notused; +} lirc_class_t; +#endif /* No SYSFS */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) +#define KERNEL_2_5 + +/* + * We still are using MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT in the set_use_inc + * function of all modules for 2.4 kernel compatibility. + * + * For 2.6 kernels reference counting is done in lirc_dev by + * try_module_get()/module_put() because the old approach is racy. + * + */ +#ifdef MOD_INC_USE_COUNT +#undef MOD_INC_USE_COUNT +#endif +#define MOD_INC_USE_COUNT + +#ifdef MOD_DEC_USE_COUNT +#undef MOD_DEC_USE_COUNT +#endif +#define MOD_DEC_USE_COUNT + +#ifdef EXPORT_NO_SYMBOLS +#undef EXPORT_NO_SYMBOLS +#endif +#define EXPORT_NO_SYMBOLS + +#else /* Kernel < 2.5.0 */ + +static inline int try_module_get(struct module *module) +{ + return 1; +} + +static inline void module_put(struct module *module) +{ +} + +#endif /* Kernel >= 2.5.0 */ + +#ifndef MODULE_LICENSE +#define MODULE_LICENSE(x) +#endif + +#ifndef MODULE_PARM_DESC +#define MODULE_PARM_DESC(x, y) +#endif + +#ifndef MODULE_ALIAS_CHARDEV_MAJOR +#define MODULE_ALIAS_CHARDEV_MAJOR(x) +#endif + +#ifndef MODULE_DEVICE_TABLE +#define MODULE_DEVICE_TABLE(x, y) +#endif + +#include +#ifndef IRQ_RETVAL +typedef void irqreturn_t; +#define IRQ_NONE +#define IRQ_HANDLED +#define IRQ_RETVAL(x) +#endif + +#ifndef MOD_IN_USE +#ifdef CONFIG_MODULE_UNLOAD +#define MOD_IN_USE module_refcount(THIS_MODULE) +#else +#error "LIRC modules currently require" +#error " 'Loadable module support ---> Module unloading'" +#error "to be enabled in the kernel" +#endif +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) +#if !defined(local_irq_save) +#define local_irq_save(flags) do { save_flags(flags); cli(); } while (0) +#endif +#if !defined(local_irq_restore) +#define local_irq_restore(flags) do { restore_flags(flags); } while (0) +#endif +#endif + +#if KERNEL_VERSION(2, 4, 0) <= LINUX_VERSION_CODE +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 22) +#include +static inline char *pci_name(struct pci_dev *pdev) +{ + return pdev->slot_name; +} +#endif /* kernel < 2.4.22 */ +#endif /* kernel >= 2.4.0 */ + +/*************************** I2C specific *****************************/ +#include + +#ifndef I2C_CLIENT_END +#error "********************************************************" +#error " Sorry, this driver needs the new I2C stack. " +#error " You can get it at http://www2.lm-sensors.nu/~lm78/. " +#error "********************************************************" +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) + +#undef i2c_get_clientdata +#define i2c_get_clientdata(client) ((client)->data) + + +#undef i2c_set_clientdata +#define i2c_set_clientdata(client_ptr, new_data) do { \ + (client_ptr)->data = new_data; \ +} while (0) + + +#endif + +/* removed in 2.6.14 */ +#ifndef I2C_ALGO_BIT +# define I2C_ALGO_BIT 0 +#endif + +/* removed in 2.6.16 */ +#ifndef I2C_DRIVERID_EXP3 +# define I2C_DRIVERID_EXP3 0xf003 +#endif + +/*************************** USB specific *****************************/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8) +static inline int usb_kill_urb(struct urb *urb) +{ + return usb_unlink_urb(urb); +} +#endif + +/* removed in 2.6.14 */ +#ifndef URB_ASYNC_UNLINK +#define URB_ASYNC_UNLINK 0 +#endif +#endif + +/*************************** bttv specific ****************************/ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15) /* BTTV_* -> BTTV_BOARD_* */ +#define BTTV_BOARD_UNKNOWN BTTV_UNKNOWN +#define BTTV_BOARD_PXELVWPLTVPAK BTTV_PXELVWPLTVPAK +#define BTTV_BOARD_PXELVWPLTVPRO BTTV_PXELVWPLTVPRO +#define BTTV_BOARD_PV_BT878P_9B BTTV_PV_BT878P_9B +#define BTTV_BOARD_PV_BT878P_PLUS BTTV_PV_BT878P_PLUS +#define BTTV_BOARD_AVERMEDIA BTTV_AVERMEDIA +#define BTTV_BOARD_AVPHONE98 BTTV_AVPHONE98 +#define BTTV_BOARD_AVERMEDIA98 BTTV_AVERMEDIA98 +#define BTTV_BOARD_CHRONOS_VS2 BTTV_CHRONOS_VS2 +#define BTTV_BOARD_MIRO BTTV_MIRO +#define BTTV_BOARD_DYNALINK BTTV_DYNALINK +#define BTTV_BOARD_WINVIEW_601 BTTV_WINVIEW_601 +#ifdef BTTV_KWORLD +#define BTTV_BOARD_KWORLD BTTV_KWORLD +#endif +#define BTTV_BOARD_MAGICTVIEW061 BTTV_MAGICTVIEW061 +#define BTTV_BOARD_MAGICTVIEW063 BTTV_MAGICTVIEW063 +#define BTTV_BOARD_PHOEBE_TVMAS BTTV_PHOEBE_TVMAS +#ifdef BTTV_BESTBUY_EASYTV2 +#define BTTV_BOARD_BESTBUY_EASYTV BTTV_BESTBUY_EASYTV +#define BTTV_BOARD_BESTBUY_EASYTV2 BTTV_BESTBUY_EASYTV2 +#endif +#define BTTV_BOARD_FLYVIDEO BTTV_FLYVIDEO +#define BTTV_BOARD_FLYVIDEO_98 BTTV_FLYVIDEO_98 +#define BTTV_BOARD_TYPHOON_TVIEW BTTV_TYPHOON_TVIEW +#ifdef BTTV_FLYVIDEO_98FM +#define BTTV_BOARD_FLYVIDEO_98FM BTTV_FLYVIDEO_98FM +#endif +#define BTTV_BOARD_WINFAST2000 BTTV_WINFAST2000 +#ifdef BTTV_GVBCTV5PCI +#define BTTV_BOARD_GVBCTV5PCI BTTV_GVBCTV5PCI +#endif +#endif /* end BTTV_* -> BTTV_BOARD_* */ + + +/******************************* pm.h *********************************/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11) +typedef u32 pm_message_t; +#endif /* kernel < 2.6.11 */ +#endif /* kernel >= 2.6.0 */ + +/*************************** interrupt.h ******************************/ +/* added in 2.6.18, old defines removed in 2.6.24 */ +#ifndef IRQF_DISABLED +#define IRQF_DISABLED SA_INTERRUPT +#endif +#ifndef IRQF_SHARED +#define IRQF_SHARED SA_SHIRQ +#endif + +/*************************** spinlock.h *******************************/ +/* added in 2.6.11 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11) +#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED +#endif + +#endif /* _KCOMPAT_H */ --- linux-2.6.27.orig/ubuntu/lirc/Makefile +++ linux-2.6.27/ubuntu/lirc/Makefile @@ -0,0 +1,24 @@ +#include $(src)/../../.config + +EXTRA_CFLAGS =-DIRCTL_DEV_MAJOR=61 -DLIRC_SERIAL_TRANSMITTER -DLIRC_SERIAL_SOFTCARRIER -I$(src) + +obj-$(CONFIG_LIRC_DEV) += lirc_dev/ +obj-$(CONFIG_LIRC_ATIUSB) += lirc_atiusb/ +obj-$(CONFIG_LIRC_BT829) += lirc_bt829/ +obj-$(CONFIG_LIRC_CMDIR) += lirc_cmdir/ +obj-$(CONFIG_LIRC_I2C) += lirc_i2c/ +obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb/ +obj-$(CONFIG_LIRC_IMON) += lirc_imon/ +obj-$(CONFIG_LIRC_IT87) += lirc_it87/ +obj-$(CONFIG_LIRC_MCEUSB) += lirc_mceusb/ +obj-$(CONFIG_LIRC_MCEUSB2) += lirc_mceusb2/ +obj-$(CONFIG_LIRC_PVR150) += lirc_pvr150/ +obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel/ +obj-$(CONFIG_LIRC_SASEM) += lirc_sasem/ +obj-$(CONFIG_LIRC_SERIAL) += lirc_serial/ +obj-$(CONFIG_LIRC_SERIAL_IGOR) += lirc_serial_igor/ +obj-$(CONFIG_LIRC_SIR) += lirc_sir/ +obj-$(CONFIG_LIRC_STREAMZAP) += lirc_streamzap/ +obj-$(CONFIG_LIRC_TTUSBIR) += lirc_ttusbir/ +obj-$(CONFIG_LIRC_GPIO) += lirc_gpio/ +obj-$(CONFIG_LIRC_TTUSBIR) += lirc_ttusbir/ --- linux-2.6.27.orig/ubuntu/lirc/lirc.h +++ linux-2.6.27/ubuntu/lirc/lirc.h @@ -0,0 +1,110 @@ +/* $Id: lirc.h,v 5.14 2008/01/12 21:57:57 lirc Exp $ */ + +#ifndef _LINUX_LIRC_H +#define _LINUX_LIRC_H + +#if defined(__linux__) +#include +#include +#else +#include +#if defined(__NetBSD__) +#include +#endif +typedef u_int32_t __u32; +#endif + +#define PULSE_BIT 0x01000000 +#define PULSE_MASK 0x00FFFFFF + +typedef int lirc_t; + +/* + * lirc compatible hardware features + */ + + +#define LIRC_MODE2SEND(x) (x) +#define LIRC_SEND2MODE(x) (x) +#define LIRC_MODE2REC(x) ((x) << 16) +#define LIRC_REC2MODE(x) ((x) >> 16) + +#define LIRC_MODE_RAW 0x00000001 +#define LIRC_MODE_PULSE 0x00000002 +#define LIRC_MODE_MODE2 0x00000004 +#define LIRC_MODE_CODE 0x00000008 +#define LIRC_MODE_LIRCCODE 0x00000010 +#define LIRC_MODE_STRING 0x00000020 + + +#define LIRC_CAN_SEND_RAW LIRC_MODE2SEND(LIRC_MODE_RAW) +#define LIRC_CAN_SEND_PULSE LIRC_MODE2SEND(LIRC_MODE_PULSE) +#define LIRC_CAN_SEND_MODE2 LIRC_MODE2SEND(LIRC_MODE_MODE2) +#define LIRC_CAN_SEND_CODE LIRC_MODE2SEND(LIRC_MODE_CODE) +#define LIRC_CAN_SEND_LIRCCODE LIRC_MODE2SEND(LIRC_MODE_LIRCCODE) +#define LIRC_CAN_SEND_STRING LIRC_MODE2SEND(LIRC_MODE_STRING) + +#define LIRC_CAN_SEND_MASK 0x0000003f + +#define LIRC_CAN_SET_SEND_CARRIER 0x00000100 +#define LIRC_CAN_SET_SEND_DUTY_CYCLE 0x00000200 +#define LIRC_CAN_SET_TRANSMITTER_MASK 0x00000400 + +#define LIRC_CAN_REC_RAW LIRC_MODE2REC(LIRC_MODE_RAW) +#define LIRC_CAN_REC_PULSE LIRC_MODE2REC(LIRC_MODE_PULSE) +#define LIRC_CAN_REC_MODE2 LIRC_MODE2REC(LIRC_MODE_MODE2) +#define LIRC_CAN_REC_CODE LIRC_MODE2REC(LIRC_MODE_CODE) +#define LIRC_CAN_REC_LIRCCODE LIRC_MODE2REC(LIRC_MODE_LIRCCODE) +#define LIRC_CAN_REC_STRING LIRC_MODE2REC(LIRC_MODE_STRING) + +#define LIRC_CAN_REC_MASK LIRC_MODE2REC(LIRC_CAN_SEND_MASK) + +#define LIRC_CAN_SET_REC_CARRIER (LIRC_CAN_SET_SEND_CARRIER << 16) +#define LIRC_CAN_SET_REC_DUTY_CYCLE (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16) + +#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000 +#define LIRC_CAN_SET_REC_CARRIER_RANGE 0x80000000 +#define LIRC_CAN_GET_REC_RESOLUTION 0x20000000 + +#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK) +#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK) + +#define LIRC_CAN_NOTIFY_DECODE 0x01000000 + +/* + * IOCTL commands for lirc driver + */ + +#define LIRC_GET_FEATURES _IOR('i', 0x00000000, __u32) + +#define LIRC_GET_SEND_MODE _IOR('i', 0x00000001, __u32) +#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, __u32) +#define LIRC_GET_SEND_CARRIER _IOR('i', 0x00000003, __u32) +#define LIRC_GET_REC_CARRIER _IOR('i', 0x00000004, __u32) +#define LIRC_GET_SEND_DUTY_CYCLE _IOR('i', 0x00000005, __u32) +#define LIRC_GET_REC_DUTY_CYCLE _IOR('i', 0x00000006, __u32) +#define LIRC_GET_REC_RESOLUTION _IOR('i', 0x00000007, __u32) + +/* code length in bits, currently only for LIRC_MODE_LIRCCODE */ +#define LIRC_GET_LENGTH _IOR('i', 0x0000000f, __u32) + +#define LIRC_SET_SEND_MODE _IOW('i', 0x00000011, __u32) +#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, __u32) +/* Note: these can reset the according pulse_width */ +#define LIRC_SET_SEND_CARRIER _IOW('i', 0x00000013, __u32) +#define LIRC_SET_REC_CARRIER _IOW('i', 0x00000014, __u32) +#define LIRC_SET_SEND_DUTY_CYCLE _IOW('i', 0x00000015, __u32) +#define LIRC_SET_REC_DUTY_CYCLE _IOW('i', 0x00000016, __u32) +#define LIRC_SET_TRANSMITTER_MASK _IOW('i', 0x00000017, __u32) + +/* to set a range use + LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE with the + lower bound first and later + LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER with the upper bound */ + +#define LIRC_SET_REC_DUTY_CYCLE_RANGE _IOW('i', 0x0000001e, __u32) +#define LIRC_SET_REC_CARRIER_RANGE _IOW('i', 0x0000001f, __u32) + +#define LIRC_NOTIFY_DECODE _IO('i', 0x00000020) + +#endif --- linux-2.6.27.orig/ubuntu/lirc/lirc_igorplugusb/Makefile +++ linux-2.6.27/ubuntu/lirc/lirc_igorplugusb/Makefile @@ -0,0 +1,3 @@ +EXTRA_CFLAGS =-DIRCTL_DEV_MAJOR=61 -DLIRC_SERIAL_TRANSMITTER -DLIRC_SERIAL_SOFTCARRIER -I$(src)/.. + +obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o --- linux-2.6.27.orig/ubuntu/lirc/lirc_igorplugusb/lirc_igorplugusb.c +++ linux-2.6.27/ubuntu/lirc/lirc_igorplugusb/lirc_igorplugusb.c @@ -0,0 +1,697 @@ +/* lirc_igorplugusb - USB remote support for LIRC + * + * Supports the standard homebrew IgorPlugUSB receiver with Igor's firmware. + * See http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm + * + * The device can only record bursts of up to 36 pulses/spaces. + * Works fine with RC5. Longer commands lead to device buffer overrun. + * (Maybe a better firmware or a microcontroller with more ram can help?) + * + * Version 0.1 [beta status] + * + * Copyright (C) 2004 Jan M. Hochstein + * + * + * This driver was derived from: + * Paul Miller + * "lirc_atiusb" module + * Vladimir Dergachev 's 2002 + * "USB ATI Remote support" (input device) + * Adrian Dewhurst 's 2002 + * "USB StreamZap remote driver" (LIRC) + * Artur Lipowski 's 2002 + * "lirc_dev" and "lirc_gpio" LIRC modules + * + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) +#error "*******************************************************" +#error "Sorry, this driver needs kernel version 2.4.0 or higher" +#error "*******************************************************" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kcompat.h" +#include "lirc.h" +#include "lirc_dev/lirc_dev.h" + +#if !defined(KERNEL_2_5) +#define USB_CTRL_GET_TIMEOUT 5 +#endif + +/* lock irctl structure */ +#define IRLOCK down_interruptible(&ir->lock) +#define IRUNLOCK up(&ir->lock) + +/* module identification */ +#define DRIVER_VERSION "0.1" +#define DRIVER_AUTHOR \ + "Jan M. Hochstein " +#define DRIVER_DESC "USB remote driver for LIRC" +#define DRIVER_NAME "lirc_igorplugusb" + +/* debugging support */ +#ifdef CONFIG_USB_DEBUG +static int debug = 1; +#else +static int debug; +#endif + +#define dprintk(fmt, args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG fmt, ## args); \ + } while (0) + +/* general constants */ +#define SUCCESS 0 + +/* One mode2 pulse/space has 4 bytes. */ +#define CODE_LENGTH sizeof(lirc_t) + +/* Igor's firmware cannot record bursts longer than 36. */ +#define DEVICE_BUFLEN 36 + +/** Header at the beginning of the device's buffer: + unsigned char data_length + unsigned char data_start (!=0 means ring-buffer overrun) + unsigned char counter (incremented by each burst) +**/ +#define DEVICE_HEADERLEN 3 + +/* This is for the gap */ +#define ADDITIONAL_LIRC_BYTES 2 + +/* times to poll per second */ +#define SAMPLE_RATE 100 + +static int sample_rate = SAMPLE_RATE; + +/**** Igor's USB Request Codes */ + +#define SET_INFRABUFFER_EMPTY 1 +/** + * Params: none + * Answer: empty + * +**/ + +#define GET_INFRACODE 2 +/** + * Params: + * wValue: offset to begin reading infra buffer + * + * Answer: infra data + * +**/ + +#define SET_DATAPORT_DIRECTION 3 +/** + * Params: + * wValue: (byte) 1 bit for each data port pin (0=in, 1=out) + * + * Answer: empty + * +**/ + +#define GET_DATAPORT_DIRECTION 4 +/** + * Params: none + * + * Answer: (byte) 1 bit for each data port pin (0=in, 1=out) + * +**/ + +#define SET_OUT_DATAPORT 5 +/** + * Params: + * wValue: byte to write to output data port + * + * Answer: empty + * +**/ + +#define GET_OUT_DATAPORT 6 +/** + * Params: none + * + * Answer: least significant 3 bits read from output data port + * +**/ + +#define GET_IN_DATAPORT 7 +/** + * Params: none + * + * Answer: least significant 3 bits read from input data port + * +**/ + +#define READ_EEPROM 8 +/** + * Params: + * wValue: offset to begin reading EEPROM + * + * Answer: EEPROM bytes + * +**/ + +#define WRITE_EEPROM 9 +/** + * Params: + * wValue: offset to EEPROM byte + * wIndex: byte to write + * + * Answer: empty + * +**/ + +#define SEND_RS232 10 +/** + * Params: + * wValue: byte to send + * + * Answer: empty + * +**/ + +#define RECV_RS232 11 +/** + * Params: none + * + * Answer: byte received + * +**/ + +#define SET_RS232_BAUD 12 +/** + * Params: + * wValue: byte to write to UART bit rate register (UBRR) + * + * Answer: empty + * +**/ + +#define GET_RS232_BAUD 13 +/** + * Params: none + * + * Answer: byte read from UART bit rate register (UBRR) + * +**/ + + +/* data structure for each usb remote */ +struct irctl { + + /* usb */ + struct usb_device *usbdev; + struct urb *urb_in; + int devnum; + + unsigned char *buf_in; + unsigned int len_in; + int in_space; + struct timeval last_time; + +#if defined(KERNEL_2_5) + dma_addr_t dma_in; +#endif + + /* lirc */ + struct lirc_plugin *p; + + /* handle sending (init strings) */ + int send_flags; + wait_queue_head_t wait_out; + + struct semaphore lock; +}; + +static int unregister_from_lirc(struct irctl *ir) +{ + struct lirc_plugin *p = ir->p; + int devnum; + + if (!ir->p) + return -EINVAL; + + devnum = ir->devnum; + dprintk(DRIVER_NAME "[%d]: unregister from lirc called\n", devnum); + + lirc_unregister_plugin(p->minor); + + printk(DRIVER_NAME "[%d]: usb remote disconnected\n", devnum); + + lirc_buffer_free(p->rbuf); + kfree(p->rbuf); + kfree(p); + kfree(ir); + ir->p = NULL; + return SUCCESS; +} + +static int set_use_inc(void *data) +{ + struct irctl *ir = data; + + if (!ir) { + printk(DRIVER_NAME "[?]: set_use_inc called with no context\n"); + return -EIO; + } + dprintk(DRIVER_NAME "[%d]: set use inc\n", ir->devnum); + + MOD_INC_USE_COUNT; + + if (!ir->usbdev) + return -ENODEV; + + return SUCCESS; +} + +static void set_use_dec(void *data) +{ + struct irctl *ir = data; + + if (!ir) { + printk(DRIVER_NAME "[?]: set_use_dec called with no context\n"); + return; + } + dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum); + + MOD_DEC_USE_COUNT; +} + + +/** + * Called in user context. + * return 0 if data was added to the buffer and + * -ENODATA if none was available. This should add some number of bits + * evenly divisible by code_length to the buffer +**/ +static int usb_remote_poll(void *data, struct lirc_buffer *buf) +{ + int ret; + struct irctl *ir = (struct irctl *)data; + + if (!ir->usbdev) /* Has the device been removed? */ + return -ENODEV; + + memset(ir->buf_in, 0, ir->len_in); + + ret = usb_control_msg( + ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), + GET_INFRACODE, USB_TYPE_VENDOR|USB_DIR_IN, + 0/* offset */, /*unused*/0, + ir->buf_in, ir->len_in, + /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); + if (ret > 0) { + int i = DEVICE_HEADERLEN; + lirc_t code, timediff; + struct timeval now; + + if (ret <= 1) /* ACK packet has 1 byte --> ignore */ + return -ENODATA; + + dprintk(DRIVER_NAME ": Got %d bytes. Header: %02x %02x %02x\n", + ret, ir->buf_in[0], ir->buf_in[1], ir->buf_in[2]); + + if (ir->buf_in[2] != 0) { + printk(DRIVER_NAME "[%d]: Device buffer overrun.\n", + ir->devnum); + /* start at earliest byte */ + i = DEVICE_HEADERLEN + ir->buf_in[2]; + /* where are we now? space, gap or pulse? */ + } + + do_gettimeofday(&now); + timediff = now.tv_sec - ir->last_time.tv_sec; + if (timediff + 1 > PULSE_MASK / 1000000) + timediff = PULSE_MASK; + else { + timediff *= 1000000; + timediff += now.tv_usec - ir->last_time.tv_usec; + } + ir->last_time.tv_sec = now.tv_sec; + ir->last_time.tv_usec = now.tv_usec; + + /* create leading gap */ + code = timediff; + lirc_buffer_write_n(buf, (unsigned char *)&code, 1); + ir->in_space = 1; /* next comes a pulse */ + + /* MODE2: pulse/space (PULSE_BIT) in 1us units */ + + while (i < ret) { + /* 1 Igor-tick = 85.333333 us */ + code = (unsigned int)ir->buf_in[i] * 85 + + (unsigned int)ir->buf_in[i] / 3; + ir->last_time.tv_usec += code; + if (ir->in_space) + code |= PULSE_BIT; + lirc_buffer_write_n(buf, (unsigned char *)&code, 1); + /* 1 chunk = CODE_LENGTH bytes */ + ir->in_space ^= 1; + ++i; + } + + ret = usb_control_msg( + ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), + SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN, + /*unused*/0, /*unused*/0, + /*dummy*/ir->buf_in, /*dummy*/ir->len_in, + /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); + if (ret < 0) + printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: " + "error %d\n", ir->devnum, ret); + return SUCCESS; + } else + printk(DRIVER_NAME "[%d]: GET_INFRACODE: error %d\n", + ir->devnum, ret); + + return -ENODATA; +} + + + +#if defined(KERNEL_2_5) +static int usb_remote_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *dev = NULL; + struct usb_host_interface *idesc = NULL; + struct usb_host_endpoint *ep_ctl2; +#else +static void *usb_remote_probe(struct usb_device *dev, unsigned int ifnum, + const struct usb_device_id *id) +{ + struct usb_interface *intf; + struct usb_interface_descriptor *idesc; + struct usb_endpoint_descriptor *ep_ctl2; +#endif + struct irctl *ir = NULL; + struct lirc_plugin *plugin = NULL; + struct lirc_buffer *rbuf = NULL; + int devnum, pipe, maxp, bytes_in_key; + int minor = 0; + char buf[63], name[128] = ""; + int mem_failure = 0; + int ret; + + dprintk(DRIVER_NAME ": usb probe called.\n"); + +#if defined(KERNEL_2_5) + dev = interface_to_usbdev(intf); + +# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 5) + idesc = &intf->altsetting[intf->act_altsetting]; /* in 2.6.4 */ +# else + idesc = intf->cur_altsetting; /* in 2.6.6 */ +# endif + + if (idesc->desc.bNumEndpoints != 1) + return -ENODEV; + ep_ctl2 = idesc->endpoint; + if (((ep_ctl2->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) + != USB_DIR_IN) + || (ep_ctl2->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + != USB_ENDPOINT_XFER_CONTROL) + return -ENODEV; + pipe = usb_rcvctrlpipe(dev, ep_ctl2->desc.bEndpointAddress); +#else + intf = &dev->actconfig->interface[ifnum]; + idesc = &intf->altsetting[intf->act_altsetting]; + if (idesc->bNumEndpoints != 1) + return NULL; + ep_ctl2 = idesc->endpoint; + if (((ep_ctl2->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + != USB_DIR_IN) + || (ep_ctl2->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + != USB_ENDPOINT_XFER_CONTROL) + return NULL; + pipe = usb_rcvctrlpipe(dev, ep_ctl2->bEndpointAddress); +#endif + devnum = dev->devnum; + maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + + bytes_in_key = CODE_LENGTH; + + dprintk(DRIVER_NAME "[%d]: bytes_in_key=%d maxp=%d\n", + devnum, bytes_in_key, maxp); + + + /* allocate kernel memory */ + mem_failure = 0; + ir = kmalloc(sizeof(struct irctl), GFP_KERNEL); + if (!ir) { + mem_failure = 1; + goto mem_failure_switch; + } + + memset(ir, 0, sizeof(struct irctl)); + + plugin = kmalloc(sizeof(struct lirc_plugin), GFP_KERNEL); + if (!plugin) { + mem_failure = 2; + goto mem_failure_switch; + } + + rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); + if (!rbuf) { + mem_failure = 3; + goto mem_failure_switch; + } + + if (lirc_buffer_init(rbuf, bytes_in_key, + DEVICE_BUFLEN+ADDITIONAL_LIRC_BYTES)) { + mem_failure = 4; + goto mem_failure_switch; + } + +#if defined(KERNEL_2_5) + ir->buf_in = usb_buffer_alloc(dev, + DEVICE_BUFLEN+DEVICE_HEADERLEN, + GFP_ATOMIC, &ir->dma_in); +#else + ir->buf_in = kmalloc(DEVICE_BUFLEN+DEVICE_HEADERLEN, + GFP_KERNEL); +#endif + if (!ir->buf_in) { + mem_failure = 5; + goto mem_failure_switch; + } + + memset(plugin, 0, sizeof(struct lirc_plugin)); + + strcpy(plugin->name, DRIVER_NAME " "); + plugin->minor = -1; + plugin->code_length = bytes_in_key*8; /* in bits */ + plugin->features = LIRC_CAN_REC_MODE2; + plugin->data = ir; + plugin->rbuf = rbuf; + plugin->set_use_inc = &set_use_inc; + plugin->set_use_dec = &set_use_dec; + plugin->sample_rate = sample_rate; /* per second */ + plugin->add_to_buf = &usb_remote_poll; +#ifdef LIRC_HAVE_SYSFS + plugin->dev = &dev->dev; +#endif + plugin->owner = THIS_MODULE; + + init_MUTEX(&ir->lock); + init_waitqueue_head(&ir->wait_out); + + minor = lirc_register_plugin(plugin); + if (minor < 0) + mem_failure = 9; + +mem_failure_switch: + + /* free allocated memory in case of failure */ + switch (mem_failure) { + case 9: +#if defined(KERNEL_2_5) + usb_buffer_free(dev, DEVICE_BUFLEN+DEVICE_HEADERLEN, + ir->buf_in, ir->dma_in); +#else + kfree(ir->buf_in); +#endif + case 5: + lirc_buffer_free(rbuf); + case 4: + kfree(rbuf); + case 3: + kfree(plugin); + case 2: + kfree(ir); + case 1: + printk(DRIVER_NAME "[%d]: out of memory (code=%d)\n", + devnum, mem_failure); +#if defined(KERNEL_2_5) + return -ENOMEM; +#else + return NULL; +#endif + } + + plugin->minor = minor; + ir->p = plugin; + ir->devnum = devnum; + ir->usbdev = dev; + ir->len_in = DEVICE_BUFLEN+DEVICE_HEADERLEN; + ir->in_space = 1; /* First mode2 event is a space. */ + do_gettimeofday(&ir->last_time); + + if (dev->descriptor.iManufacturer + && usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0) + strncpy(name, buf, 128); + if (dev->descriptor.iProduct + && usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0) + snprintf(name, 128, "%s %s", name, buf); + printk(DRIVER_NAME "[%d]: %s on usb%d:%d\n", devnum, name, + dev->bus->busnum, devnum); + + /* clear device buffer */ + ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), + SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN, + /*unused*/0, /*unused*/0, + /*dummy*/ir->buf_in, /*dummy*/ir->len_in, + /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); + if (ret < 0) + printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: error %d\n", + devnum, ret); + +#if defined(KERNEL_2_5) + usb_set_intfdata(intf, ir); + return SUCCESS; +#else + return ir; +#endif +} + + +#if defined(KERNEL_2_5) +static void usb_remote_disconnect(struct usb_interface *intf) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct irctl *ir = usb_get_intfdata(intf); + usb_set_intfdata(intf, NULL); +#else +static void usb_remote_disconnect(struct usb_device *dev, void *ptr) +{ + struct irctl *ir = ptr; +#endif + + if (!ir || !ir->p) + return; + + ir->usbdev = NULL; + wake_up_all(&ir->wait_out); + + IRLOCK; +#if defined(KERNEL_2_5) + usb_buffer_free(dev, ir->len_in, ir->buf_in, ir->dma_in); +#else + kfree(ir->buf_in); +#endif + IRUNLOCK; + + unregister_from_lirc(ir); +} + +static struct usb_device_id usb_remote_id_table [] = { + /* Igor Plug USB (Atmel's Manufact. ID) */ + { USB_DEVICE(0x03eb, 0x0002) }, + + /* Terminating entry */ + { } +}; + +static struct usb_driver usb_remote_driver = { + LIRC_THIS_MODULE(.owner = THIS_MODULE) + .name = DRIVER_NAME, + .probe = usb_remote_probe, + .disconnect = usb_remote_disconnect, + .id_table = usb_remote_id_table +}; + +static int __init usb_remote_init(void) +{ + int i; + + printk(KERN_INFO "\n" + DRIVER_NAME ": " DRIVER_DESC " v" DRIVER_VERSION "\n"); + printk(DRIVER_NAME ": " DRIVER_AUTHOR "\n"); + dprintk(DRIVER_NAME ": debug mode enabled\n"); + + request_module("lirc_dev"); + + i = usb_register(&usb_remote_driver); + if (i < 0) { + printk(DRIVER_NAME ": usb register failed, result = %d\n", i); + return -ENODEV; + } + + return SUCCESS; +} + +static void __exit usb_remote_exit(void) +{ + usb_deregister(&usb_remote_driver); +} + +module_init(usb_remote_init); +module_exit(usb_remote_exit); + +#if defined(KERNEL_2_5) +#include +MODULE_INFO(vermagic, VERMAGIC_STRING); +#endif + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(usb, usb_remote_id_table); + +module_param(sample_rate, int, 0644); +MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)"); + +EXPORT_NO_SYMBOLS; + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_i2c/lirc_i2c.c +++ linux-2.6.27/ubuntu/lirc/lirc_i2c/lirc_i2c.c @@ -0,0 +1,681 @@ +/* $Id: lirc_i2c.c,v 1.46 2008/05/04 13:49:53 lirc Exp $ */ + +/* + * i2c IR lirc plugin for Hauppauge and Pixelview cards - new 2.3.x i2c stack + * + * Copyright (c) 2000 Gerd Knorr + * modified for PixelView (BT878P+W/FM) by + * Michal Kochanowicz + * Christoph Bartelmus + * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by + * Ulrich Mueller + * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by + * Stefan Jahn + * modified for inclusion into kernel sources by + * Jerome Brock + * modified for Leadtek Winfast PVR2000 by + * Thomas Reitmayr (treitmayr@yahoo.com) + * modified for Hauppauge HVR-1300 by + * Jan Frey (jfrey@gmx.de) + * + * parts are cut&pasted from the old lirc_haup.c driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "kcompat.h" +#include "lirc_dev/lirc_dev.h" + +struct IR { + struct lirc_plugin l; + struct i2c_client c; + int nextkey; + unsigned char b[3]; + unsigned char bits; + unsigned char flag; +}; + +/* ----------------------------------------------------------------------- */ + +#define DEVICE_NAME "lirc_i2c" + +/* ----------------------------------------------------------------------- */ +/* insmod parameters */ + +static int debug; /* debug output */ +static int minor = -1; /* minor number */ + +#define dprintk(fmt, args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG DEVICE_NAME ": " fmt, \ + ## args); \ + } while (0) + +/* ----------------------------------------------------------------------- */ + +static inline int reverse(int data, int bits) +{ + int i; + int c; + + for (c = 0, i = 0; i < bits; i++) + c |= (((data & (1<c, keybuf, 1); + /* poll IR chip */ + if (i2c_master_recv(&ir->c, keybuf, sizeof(keybuf)) != sizeof(keybuf)) { + dprintk("read error\n"); + return -EIO; + } + + dprintk("key (0x%02x%02x%02x%02x)\n", + keybuf[0], keybuf[1], keybuf[2], keybuf[3]); + + /* key pressed ? */ + if (keybuf[2] == 0xff) + return -ENODATA; + + /* remove repeat bit */ + keybuf[2] &= 0x7f; + keybuf[3] |= 0x80; + + lirc_buffer_write_1(buf, keybuf); + return 0; +} + +static int add_to_buf_pcf8574(void *data, struct lirc_buffer *buf) +{ + struct IR *ir = data; + int rc; + unsigned char all, mask; + unsigned char key; + + /* compute all valid bits (key code + pressed/release flag) */ + all = ir->bits | ir->flag; + + /* save IR writable mask bits */ + mask = i2c_smbus_read_byte(&ir->c) & ~all; + + /* send bit mask */ + rc = i2c_smbus_write_byte(&ir->c, (0xff & all) | mask); + + /* receive scan code */ + rc = i2c_smbus_read_byte(&ir->c); + + if (rc == -1) { + dprintk("%s read error\n", ir->c.name); + return -EIO; + } + + /* drop duplicate polls */ + if (ir->b[0] == (rc & all)) + return -ENODATA; + + ir->b[0] = rc & all; + + dprintk("%s key 0x%02X %s\n", ir->c.name, rc & ir->bits, + (rc & ir->flag) ? "released" : "pressed"); + + if (rc & ir->flag) { + /* ignore released buttons */ + return -ENODATA; + } + + /* set valid key code */ + key = rc & ir->bits; + lirc_buffer_write_1(buf, &key); + return 0; +} + +/* common for Hauppauge IR receivers */ +static int add_to_buf_haup_common(void *data, struct lirc_buffer *buf, + unsigned char *keybuf, int size, int offset) +{ + struct IR *ir = data; + __u16 code; + unsigned char codes[2]; + + /* poll IR chip */ + if (size == i2c_master_recv(&ir->c, keybuf, size)) { + ir->b[0] = keybuf[offset]; + ir->b[1] = keybuf[offset+1]; + ir->b[2] = keybuf[offset+2]; + dprintk("key (0x%02x/0x%02x)\n", ir->b[0], ir->b[1]); + } else { + dprintk("read error\n"); + /* keep last successfull read buffer */ + } + + /* key pressed ? */ + if ((ir->b[0] & 0x80) == 0) + return -ENODATA; + + /* look what we have */ + code = (((__u16)ir->b[0]&0x7f)<<6) | (ir->b[1]>>2); + + codes[0] = (code >> 8) & 0xff; + codes[1] = code & 0xff; + + /* return it */ + lirc_buffer_write_1(buf, codes); + return 0; +} + +/* specific for the Hauppauge PVR150 IR receiver */ +static int add_to_buf_haup_pvr150(void *data, struct lirc_buffer *buf) +{ + unsigned char keybuf[6]; + /* fetch 6 bytes, first relevant is at offset 3 */ + return add_to_buf_haup_common(data, buf, keybuf, 6, 3); +} + +/* used for all Hauppauge IR receivers but the PVR150 */ +static int add_to_buf_haup(void *data, struct lirc_buffer *buf) +{ + unsigned char keybuf[3]; + /* fetch 3 bytes, first relevant is at offset 0 */ + return add_to_buf_haup_common(data, buf, keybuf, 3, 0); +} + + +static int add_to_buf_pvr2000(void *data, struct lirc_buffer *buf) +{ + struct IR *ir = data; + unsigned char key; + s32 flags; + s32 code; + + /* poll IR chip */ + flags = i2c_smbus_read_byte_data(&ir->c, 0x10); + if (-1 == flags) { + dprintk("read error\n"); + return -ENODATA; + } + /* key pressed ? */ + if (0 == (flags & 0x80)) + return -ENODATA; + + /* read actual key code */ + code = i2c_smbus_read_byte_data(&ir->c, 0x00); + if (-1 == code) { + dprintk("read error\n"); + return -ENODATA; + } + + key = code & 0xFF; + + dprintk("IR Key/Flags: (0x%02x/0x%02x)\n", key, flags & 0xFF); + + /* return it */ + lirc_buffer_write_1(buf, &key); + return 0; +} + +static int add_to_buf_pixelview(void *data, struct lirc_buffer *buf) +{ + struct IR *ir = data; + unsigned char key; + + /* poll IR chip */ + if (1 != i2c_master_recv(&ir->c, &key, 1)) { + dprintk("read error\n"); + return -1; + } + dprintk("key %02x\n", key); + + /* return it */ + lirc_buffer_write_1(buf, &key); + return 0; +} + +static int add_to_buf_pv951(void *data, struct lirc_buffer *buf) +{ + struct IR *ir = data; + unsigned char key; + unsigned char codes[4]; + + /* poll IR chip */ + if (1 != i2c_master_recv(&ir->c, &key, 1)) { + dprintk("read error\n"); + return -ENODATA; + } + /* ignore 0xaa */ + if (key == 0xaa) + return -ENODATA; + dprintk("key %02x\n", key); + + codes[0] = 0x61; + codes[1] = 0xD6; + codes[2] = reverse(key, 8); + codes[3] = (~codes[2])&0xff; + + lirc_buffer_write_1(buf, codes); + return 0; +} + +static int add_to_buf_knc1(void *data, struct lirc_buffer *buf) +{ + static unsigned char last_key = 0xFF; + struct IR *ir = data; + unsigned char key; + + /* poll IR chip */ + if (1 != i2c_master_recv(&ir->c, &key, 1)) { + dprintk("read error\n"); + return -ENODATA; + } + + /* it seems that 0xFE indicates that a button is still hold + down, while 0xFF indicates that no button is hold + down. 0xFE sequences are sometimes interrupted by 0xFF */ + + dprintk("key %02x\n", key); + + if (key == 0xFF) + return -ENODATA; + + if (key == 0xFE) + key = last_key; + + last_key = key; + lirc_buffer_write_1(buf, &key); + + return 0; +} + +static int set_use_inc(void *data) +{ + struct IR *ir = data; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) + i2c_use_client(&ir->c); +#else + int ret; + + /* lock bttv in memory while /dev/lirc is in use */ + ret = i2c_use_client(&ir->c); + if (ret != 0) + return ret; +#endif + + MOD_INC_USE_COUNT; + return 0; +} + +static void set_use_dec(void *data) +{ + struct IR *ir = data; + + i2c_release_client(&ir->c); + MOD_DEC_USE_COUNT; +} + +static struct lirc_plugin lirc_template = { + .name = "lirc_i2c", + .set_use_inc = set_use_inc, + .set_use_dec = set_use_dec, + .dev = NULL, + .owner = THIS_MODULE, +}; + +/* ----------------------------------------------------------------------- */ + +static int ir_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind); +static int ir_detach(struct i2c_client *client); +static int ir_probe(struct i2c_adapter *adap); +static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg); + +static struct i2c_driver driver = { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) + .name = "i2c ir driver", + .flags = I2C_DF_NOTIFY, +#else + .driver = { + .owner = THIS_MODULE, + .name = "i2c ir driver", + }, +#endif + .id = I2C_DRIVERID_EXP3, /* FIXME */ + .attach_adapter = ir_probe, + .detach_client = ir_detach, + .command = ir_command, +}; + +static struct i2c_client client_template = { + .name = "unset", + .driver = &driver +}; + +static int ir_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct IR *ir; + int err; + + client_template.adapter = adap; + client_template.addr = addr; + + ir = kmalloc(sizeof(struct IR), GFP_KERNEL); + if (!ir) + return -ENOMEM; + memcpy(&ir->l, &lirc_template, sizeof(struct lirc_plugin)); + memcpy(&ir->c, &client_template, sizeof(struct i2c_client)); + + ir->c.adapter = adap; + ir->c.addr = addr; + i2c_set_clientdata(&ir->c, ir); + ir->l.data = ir; + ir->l.minor = minor; + ir->l.sample_rate = 10; + ir->nextkey = -1; + + switch (addr) { + case 0x64: + strlcpy(ir->c.name, "Pixelview IR", I2C_NAME_SIZE); + ir->l.code_length = 8; + ir->l.add_to_buf = add_to_buf_pixelview; + break; + case 0x4b: + strlcpy(ir->c.name, "PV951 IR", I2C_NAME_SIZE); + ir->l.code_length = 32; + ir->l.add_to_buf = add_to_buf_pv951; + break; + case 0x71: +#ifdef I2C_HW_B_CX2341X + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848) || + adap->id == (I2C_ALGO_BIT | I2C_HW_B_CX2341X)) { +#else + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) { +#endif + /* The PVR150 IR receiver uses the same protocol as + * other Hauppauge cards, but the data flow is + * different, so we need to deal with it by its own. */ + strlcpy(ir->c.name, "Hauppauge PVR150", I2C_NAME_SIZE); + } else /* I2C_HW_B_CX2388x */ + strlcpy(ir->c.name, "Hauppauge HVR1300", I2C_NAME_SIZE); + ir->l.code_length = 13; + ir->l.add_to_buf = add_to_buf_haup_pvr150; + break; + case 0x6b: + strlcpy(ir->c.name, "Adaptec IR", I2C_NAME_SIZE); + ir->l.code_length = 32; + ir->l.add_to_buf = add_to_buf_adap; + break; + case 0x18: + case 0x1a: +#ifdef I2C_HW_B_CX2341X + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848) || + adap->id == (I2C_ALGO_BIT | I2C_HW_B_CX2341X)) { +#else + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) { +#endif + strlcpy(ir->c.name, "Hauppauge IR", I2C_NAME_SIZE); + ir->l.code_length = 13; + ir->l.add_to_buf = add_to_buf_haup; + } else { /* I2C_HW_B_CX2388x */ + strlcpy(ir->c.name, "Leadtek IR", I2C_NAME_SIZE); + ir->l.code_length = 8; + ir->l.add_to_buf = add_to_buf_pvr2000; + } + break; + case 0x30: + strlcpy(ir->c.name, "KNC ONE IR", I2C_NAME_SIZE); + ir->l.code_length = 8; + ir->l.add_to_buf = add_to_buf_knc1; + break; + case 0x21: + case 0x23: + strlcpy(ir->c.name, "TV-Box IR", I2C_NAME_SIZE); + ir->l.code_length = 8; + ir->l.add_to_buf = add_to_buf_pcf8574; + ir->bits = flags & 0xff; + ir->flag = (flags >> 8) & 0xff; + break; + default: + /* shouldn't happen */ + printk("lirc_i2c: Huh? unknown i2c address (0x%02x)?\n", addr); + kfree(ir); + return -1; + } + printk(KERN_INFO "lirc_i2c: chip 0x%x found @ 0x%02x (%s)\n", + adap->id, addr, ir->c.name); + + /* register device */ + err = i2c_attach_client(&ir->c); + if (err) { + kfree(ir); + return err; + } + ir->l.minor = lirc_register_plugin(&ir->l); + + return 0; +} + +static int ir_detach(struct i2c_client *client) +{ + struct IR *ir = i2c_get_clientdata(client); + + /* unregister device */ + lirc_unregister_plugin(ir->l.minor); + i2c_detach_client(&ir->c); + + /* free memory */ + kfree(ir); + return 0; +} + +static int ir_probe(struct i2c_adapter *adap) +{ + /* The external IR receiver is at i2c address 0x34 (0x35 for + * reads). Future Hauppauge cards will have an internal + * receiver at 0x30 (0x31 for reads). In theory, both can be + * fitted, and Hauppauge suggest an external overrides an + * internal. + * + * That's why we probe 0x1a (~0x34) first. CB + * + * The i2c address for the Hauppauge PVR-150 card is 0xe2, + * so we need to probe 0x71 as well. */ + + static const int probe[] = { + 0x1a, /* Hauppauge IR external */ + 0x18, /* Hauppauge IR internal */ + 0x71, /* Hauppauge IR (PVR150) */ + 0x4b, /* PV951 IR */ + 0x64, /* Pixelview IR */ + 0x30, /* KNC ONE IR */ + 0x6b, /* Adaptec IR */ + -1}; + +#ifdef I2C_HW_B_CX2388x + static const int probe_cx88[] = { + 0x18, /* Leadtek Winfast PVR2000 */ + 0x71, /* Hauppauge HVR-IR */ + -1}; +#endif + + struct i2c_client c; + char buf; + int i, rc; + +#ifdef I2C_HW_B_CX2341X + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848) || + adap->id == (I2C_ALGO_BIT | I2C_HW_B_CX2341X)) +#else + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) +#endif + { + memset(&c, 0, sizeof(c)); + c.adapter = adap; + for (i = 0; -1 != probe[i]; i++) { + c.addr = probe[i]; + rc = i2c_master_recv(&c, &buf, 1); + dprintk("probe 0x%02x @ %s: %s\n", + probe[i], adap->name, + (1 == rc) ? "yes" : "no"); + if (1 == rc) + ir_attach(adap, probe[i], 0, 0); + } + } + +#ifdef I2C_HW_B_CX2388x + /* Leadtek Winfast PVR2000 or Hauppauge HVR-1300 */ + else if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_CX2388x)) { + memset(&c, 0, sizeof(c)); + c.adapter = adap; + for (i = 0; -1 != probe_cx88[i]; i++) { + c.addr = probe_cx88[i]; + rc = i2c_master_recv(&c, &buf, 1); + dprintk("probe 0x%02x @ %s: %s\n", + c.addr, adap->name, + (1 == rc) ? "yes" : "no"); + if (1 == rc) + ir_attach(adap, c.addr, 0, 0); + } + } +#endif + + /* Asus TV-Box and Creative/VisionTek BreakOut-Box (PCF8574) */ + else if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_RIVA)) { + /* addresses to probe; + leave 0x24 and 0x25 because SAA7113H possibly uses it + 0x21 and 0x22 possibly used by SAA7108E + Asus: 0x21 is a correct address (channel 1 of PCF8574) + Creative: 0x23 is a correct address (channel 3 of PCF8574) + VisionTek: 0x23 is a correct address (channel 3 of PCF8574) + */ + static const int pcf_probe[] = { 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, -1 }; + int ret1, ret2, ret3, ret4; + unsigned char bits = 0, flag = 0; + + memset(&c, 0, sizeof(c)); + c.adapter = adap; + for (i = 0; -1 != pcf_probe[i]; i++) { + c.addr = pcf_probe[i]; + ret1 = i2c_smbus_write_byte(&c, 0xff); + ret2 = i2c_smbus_read_byte(&c); + ret3 = i2c_smbus_write_byte(&c, 0x00); + ret4 = i2c_smbus_read_byte(&c); + + /* ensure that the writable bitmask works correctly */ + rc = 0; + if (ret1 != -1 && ret2 != -1 && + ret3 != -1 && ret4 != -1) { + /* in the Asus TV-Box: bit 1-0 */ + if (((ret2 & 0x03) == 0x03) && + ((ret4 & 0x03) == 0x00)) { + bits = (unsigned char) ~0x07; + flag = 0x04; + rc = 1; + } + /* in the Creative/VisionTek BreakOut-Box: bit 7-6 */ + if (((ret2 & 0xc0) == 0xc0) && + ((ret4 & 0xc0) == 0x00)) { + bits = (unsigned char) ~0xe0; + flag = 0x20; + rc = 1; + } + } + dprintk("probe 0x%02x @ %s: %s\n", + c.addr, adap->name, rc ? "yes" : "no"); + if (rc) + ir_attach(adap, pcf_probe[i], + bits|(flag<<8), 0); + } + } + + return 0; +} + +static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + /* nothing */ + return 0; +} + +/* ----------------------------------------------------------------------- */ +#ifdef MODULE + +int init_module(void) +{ + request_module("bttv"); + request_module("rivatv"); + request_module("ivtv"); + request_module("cx8800"); + i2c_add_driver(&driver); + return 0; +} + +void cleanup_module(void) +{ + i2c_del_driver(&driver); +} + +MODULE_DESCRIPTION("Infrared receiver driver for Hauppauge and " + "Pixelview cards (i2c stack)"); +MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, " + "Ulrich Mueller, Stefan Jahn, Jerome Brock"); +MODULE_LICENSE("GPL"); + +module_param(minor, int, 0444); +MODULE_PARM_DESC(minor, "Preferred minor device number"); + +module_param(debug, bool, 0644); +MODULE_PARM_DESC(debug, "Enable debugging messages"); + +EXPORT_NO_SYMBOLS; + +#endif /* MODULE */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_i2c/Makefile +++ linux-2.6.27/ubuntu/lirc/lirc_i2c/Makefile @@ -0,0 +1,3 @@ +EXTRA_CFLAGS =-DIRCTL_DEV_MAJOR=61 -DLIRC_SERIAL_TRANSMITTER -DLIRC_SERIAL_SOFTCARRIER -I$(src)/.. + +obj-$(CONFIG_LIRC_I2C) += lirc_i2c.o --- linux-2.6.27.orig/ubuntu/lirc/lirc_mceusb/Makefile +++ linux-2.6.27/ubuntu/lirc/lirc_mceusb/Makefile @@ -0,0 +1,3 @@ +EXTRA_CFLAGS =-DIRCTL_DEV_MAJOR=61 -DLIRC_SERIAL_TRANSMITTER -DLIRC_SERIAL_SOFTCARRIER -I$(src)/.. + +obj-$(CONFIG_LIRC_MCEUSB) += lirc_mceusb.o --- linux-2.6.27.orig/ubuntu/lirc/lirc_mceusb/lirc_mceusb.c +++ linux-2.6.27/ubuntu/lirc/lirc_mceusb/lirc_mceusb.c @@ -0,0 +1,1000 @@ +/* + * USB Microsoft IR Transceiver driver - 0.2 + * + * Copyright (c) 2003-2004 Dan Conti (dconti@acm.wwu.edu) + * + * This driver is based on the USB skeleton driver packaged with the + * kernel, and the notice from that package has been retained below. + * + * The Microsoft IR Transceiver is a neat little IR receiver with two + * emitters on it designed for Windows Media Center. This driver might + * work for all media center remotes, but I have only tested it with + * the philips model. The first revision of this driver only supports + * the receive function - the transmit function will be much more + * tricky due to the nature of the hardware. Microsoft chose to build + * this device inexpensively, therefore making it extra dumb. + * There is no interrupt endpoint on this device; all usb traffic + * happens over two bulk endpoints. As a result of this, poll() for + * this device is an actual hardware poll (instead of a receive queue + * check) and is rather expensive. + * + * All trademarks property of their respective owners. This driver was + * originally based on the USB skeleton driver, although significant + * portions of that code have been removed as the driver has evolved. + * + * 2003_11_11 - Restructured to minimalize code interpretation in the + * driver. The normal use case will be with lirc. + * + * 2004_01_01 - Removed all code interpretation. Generate mode2 data + * for passing off to lirc. Cleanup + * + * 2004_01_04 - Removed devfs handle. Put in a temporary workaround + * for a known issue where repeats generate two + * sequential spaces (last_was_repeat_gap) + * + * 2004_02_17 - Changed top level api to no longer use fops, and + * instead use new interface for polling via + * lirc_thread. Restructure data read/mode2 generation to + * a single pass, reducing number of buffers. Rev to .2 + * + * 2004_02_27 - Last of fixups to plugin->add_to_buf API. Properly + * handle broken fragments from the receiver. Up the + * sample rate and remove any pacing from + * fetch_more_data. Fixes all known issues. + * + * TODO + * - Fix up minor number, registration of major/minor with usb subsystem + * + */ +/* + * USB Skeleton driver - 1.1 + * + * Copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + * + * This driver is to be used as a skeleton driver to be able to create a + * USB driver quickly. The design of it is based on the usb-serial and + * dc2xx drivers. + * + * Thanks to Oliver Neukum, David Brownell, and Alan Stern for their help + * in debugging this driver. + * + * + * History: + * + * 2003-05-06 - 1.1 - changes due to usb core changes with usb_register_dev() + * 2003-02-25 - 1.0 - fix races involving urb->status, unlink_urb(), and + * disconnect. Fix transfer amount in read(). Use + * macros instead of magic numbers in probe(). Change + * size variables to size_t. Show how to eliminate + * DMA bounce buffer. + * 2002_12_12 - 0.9 - compile fixes and got rid of fixed minor array. + * 2002_09_26 - 0.8 - changes due to USB core conversion to struct device + * driver. + * 2002_02_12 - 0.7 - zero out dev in probe function for devices that do + * not have both a bulk in and bulk out endpoint. + * Thanks to Holger Waechtler for the fix. + * 2001_11_05 - 0.6 - fix minor locking problem in skel_disconnect. + * Thanks to Pete Zaitcev for the fix. + * 2001_09_04 - 0.5 - fix devfs bug in skel_disconnect. Thanks to wim delvaux + * 2001_08_21 - 0.4 - more small bug fixes. + * 2001_05_29 - 0.3 - more bug fixes based on review from linux-usb-devel + * 2001_05_24 - 0.2 - bug fixes based on review from linux-usb-devel people + * 2001_05_01 - 0.1 - first version + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef KERNEL_2_5 +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +#include +#else +#include +#endif +#else +#include +#include +#include +#include +#include +#include +#endif + +#ifdef CONFIG_USB_DEBUG +static int debug = 1; +#else +static int debug; +#endif + +#include "kcompat.h" +#include "lirc.h" +#include "lirc_dev/lirc_dev.h" + +/* Use our own dbg macro */ +#define dprintk(fmt, args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG __FILE__ ": " \ + fmt "\n", ## args); \ + } while (0) + +/* Version Information */ +#define DRIVER_VERSION "v0.2" +#define DRIVER_AUTHOR "Dan Conti, dconti@acm.wwu.edu" +#define DRIVER_DESC "USB Microsoft IR Transceiver Driver" +#define DRIVER_NAME "lirc_mceusb" + +/* Define these values to match your device */ +#define USB_MCEUSB_VENDOR_ID 0x045e +#define USB_MCEUSB_PRODUCT_ID 0x006d + +/* table of devices that work with this driver */ +static struct usb_device_id mceusb_table[] = { + { USB_DEVICE(USB_MCEUSB_VENDOR_ID, USB_MCEUSB_PRODUCT_ID) }, + { } /* Terminating entry */ +}; + +/* we can have up to this number of device plugged in at once */ +#define MAX_DEVICES 16 + +/* Structure to hold all of our device specific stuff */ +struct usb_skel { + struct usb_device *udev; /* save off the usb device pointer */ + struct usb_interface *interface; /* the interface for this device */ + unsigned char minor; /* the starting minor number for this device */ + unsigned char num_ports; /* the number of ports this device has */ + char num_interrupt_in; /* number of interrupt in endpoints */ + char num_bulk_in; /* number of bulk in endpoints */ + char num_bulk_out; /* number of bulk out endpoints */ + + unsigned char *bulk_in_buffer; /* the buffer to receive data */ + int bulk_in_size; /* the size of the receive buffer */ + __u8 bulk_in_endpointAddr; /* the address of bulk in endpoint */ + + unsigned char *bulk_out_buffer; /* the buffer to send data */ + int bulk_out_size; /* the size of the send buffer */ + struct urb *write_urb; /* the urb used to send data */ + __u8 bulk_out_endpointAddr; /* the address of bulk out endpoint */ + + atomic_t write_busy; /* true iff write urb is busy */ + struct completion write_finished; /* wait for the write to finish */ + + wait_queue_head_t wait_q; /* for timeouts */ + int open_count; /* number of times this port has been opened */ + struct semaphore sem; /* locks this structure */ + + int present; /* if the device is not disconnected */ + + struct lirc_plugin *plugin; + + lirc_t lircdata[256]; /* place to store data until lirc processes it */ + int lircidx; /* current index */ + int lirccnt; /* remaining values */ + + int usb_valid_bytes_in_bulk_buffer; /* leftover data from prior read */ + int mce_bytes_left_in_packet; /* for packets split across reads */ + + /* Value to hold the last received space; 0 if last value + * received was a pulse */ + int last_space; + +#ifdef KERNEL_2_5 + dma_addr_t dma_in; + dma_addr_t dma_out; +#endif +}; + +#define MCE_TIME_UNIT 50 + +/* driver api */ +#ifdef KERNEL_2_5 +static int mceusb_probe(struct usb_interface *interface, + const struct usb_device_id *id); +static void mceusb_disconnect(struct usb_interface *interface); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void mceusb_write_bulk_callback(struct urb *urb, struct pt_regs *regs); +#else +static void mceusb_write_bulk_callback(struct urb *urb); +#endif +#else +static void *mceusb_probe(struct usb_device *dev, unsigned int ifnum, + const struct usb_device_id *id); +static void mceusb_disconnect(struct usb_device *dev, void *ptr); +static void mceusb_write_bulk_callback(struct urb *urb); +#endif + +/* read data from the usb bus; convert to mode2 */ +static int msir_fetch_more_data(struct usb_skel *dev, int dont_block); + +/* helper functions */ +static void msir_cleanup(struct usb_skel *dev); +static void set_use_dec(void *data); +static int set_use_inc(void *data); + +/* array of pointers to our devices that are currently connected */ +static struct usb_skel *minor_table[MAX_DEVICES]; + +/* lock to protect the minor_table structure */ +static DECLARE_MUTEX(minor_table_mutex); +static void mceusb_setup(struct usb_device *udev); + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver mceusb_driver = { + LIRC_THIS_MODULE(.owner = THIS_MODULE) + .name = DRIVER_NAME, + .probe = mceusb_probe, + .disconnect = mceusb_disconnect, + .id_table = mceusb_table, +}; + + +/** + * usb_mceusb_debug_data + */ +static inline void usb_mceusb_debug_data(const char *function, int size, + const unsigned char *data) +{ + int i; + if (!debug) + return; + + printk(KERN_DEBUG __FILE__": %s - length = %d, data = ", + function, size); + for (i = 0; i < size; ++i) + printk(KERN_DEBUG "%.2x ", data[i]); + printk(KERN_DEBUG "\n"); +} + +/** + *mceusb_delete + */ +static inline void mceusb_delete(struct usb_skel *dev) +{ + dprintk("%s", __func__); + minor_table[dev->minor] = NULL; +#ifdef KERNEL_2_5 + usb_buffer_free(dev->udev, dev->bulk_in_size, + dev->bulk_in_buffer, dev->dma_in); + usb_buffer_free(dev->udev, dev->bulk_out_size, + dev->bulk_out_buffer, dev->dma_out); +#else + if (dev->bulk_in_buffer != NULL) + kfree(dev->bulk_in_buffer); + if (dev->bulk_out_buffer != NULL) + kfree(dev->bulk_out_buffer); +#endif + if (dev->write_urb != NULL) + usb_free_urb(dev->write_urb); + kfree(dev); +} + +static void mceusb_setup(struct usb_device *udev) +{ + char data[8]; + int res; + + memset(data, 0, 8); + + /* Get Status */ + res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + USB_REQ_GET_STATUS, USB_DIR_IN, + 0, 0, data, 2, HZ * 3); + + /* res = usb_get_status( udev, 0, 0, data ); */ + dprintk("%s - res = %d status = 0x%x 0x%x", __func__, + res, data[0], data[1]); + + /* This is a strange one. They issue a set address to the device + * on the receive control pipe and expect a certain value pair back + */ + memset(data, 0, 8); + + res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 5, USB_TYPE_VENDOR, 0, 0, + data, 2, HZ * 3); + dprintk("%s - res = %d, devnum = %d", __func__, res, udev->devnum); + dprintk("%s - data[0] = %d, data[1] = %d", __func__, + data[0], data[1]); + + + /* set feature */ + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, + 0xc04e, 0x0000, NULL, 0, HZ * 3); + + dprintk("%s - res = %d", __func__, res); + + /* These two are sent by the windows driver, but stall for + * me. I dont have an analyzer on the linux side so i can't + * see what is actually different and why the device takes + * issue with them + */ +#if 0 + /* this is some custom control message they send */ + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, USB_TYPE_VENDOR, + 0x0808, 0x0000, NULL, 0, HZ * 3); + + dprintk("%s - res = %d", __func__, res); + + /* this is another custom control message they send */ + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x02, USB_TYPE_VENDOR, + 0x0000, 0x0100, NULL, 0, HZ * 3); + + dprintk("%s - res = %d", __func__, res); +#endif +} + +static void msir_cleanup(struct usb_skel *dev) +{ + memset(dev->bulk_in_buffer, 0, dev->bulk_in_size); + + dev->usb_valid_bytes_in_bulk_buffer = 0; + + dev->last_space = PULSE_MASK; + + dev->mce_bytes_left_in_packet = 0; + dev->lircidx = 0; + dev->lirccnt = 0; + memset(dev->lircdata, 0, sizeof(dev->lircdata)); +} + +static int set_use_inc(void *data) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static void set_use_dec(void *data) +{ + MOD_DEC_USE_COUNT; +} + +/* + * msir_fetch_more_data + * + * The goal here is to read in more remote codes from the remote. In + * the event that the remote isn't sending us anything, the caller + * will block until a key is pressed (i.e. this performs phys read, + * filtering, and queueing of data) unless dont_block is set to 1; in + * this situation, it will perform a few reads and will exit out if it + * does not see any appropriate data + * + * dev->sem should be locked when this function is called - fine grain + * locking isn't really important here anyways + * + * This routine always returns the number of words available + * + */ +static int msir_fetch_more_data(struct usb_skel *dev, int dont_block) +{ + int retries = 0; + int words_to_read = + (sizeof(dev->lircdata)/sizeof(lirc_t)) - dev->lirccnt; + int partial, this_read = 0; + int bulkidx = 0; + int bytes_left_in_packet = 0; + signed char *signedp = (signed char*)dev->bulk_in_buffer; + + if (words_to_read == 0) + return dev->lirccnt; + + /* this forces all existing data to be read by lirc before we + * issue another usb command. this is the only form of + * throttling we have + */ + if (dev->lirccnt) + return dev->lirccnt; + + /* reserve room for our leading space */ + if (dev->last_space) + words_to_read--; + + while (words_to_read) { + /* handle signals and USB disconnects */ + if (signal_pending(current)) + return dev->lirccnt ? dev->lirccnt : -EINTR; + if (!dev->udev) + return -ENODEV; + + bulkidx = 0; + + /* + * perform data read (phys or from previous buffer) + */ + + /* use leftovers if present, otherwise perform a read */ + if (dev->usb_valid_bytes_in_bulk_buffer) { + this_read = dev->usb_valid_bytes_in_bulk_buffer; + partial = this_read; + dev->usb_valid_bytes_in_bulk_buffer = 0; + } else { + int retval; + + this_read = dev->bulk_in_size; + partial = 0; + retval = usb_bulk_msg(dev->udev, + usb_rcvbulkpipe(dev->udev, + dev->bulk_in_endpointAddr), + (unsigned char *)dev->bulk_in_buffer, + this_read, &partial, HZ*10); + + /* retry a few times on overruns; map all + other errors to -EIO */ + if (retval) { + if (retval == -EOVERFLOW && retries < 5) { + retries++; + interruptible_sleep_on_timeout( + &dev->wait_q, HZ); + continue; + } else + return -EIO; + } + + retries = 0; + if (partial) + this_read = partial; + + /* skip the header */ + bulkidx += 2; + + /* check for empty reads (header only) */ + if (this_read == 2) { + /* assume no data */ + if (dont_block) + break; + + /* sleep for a bit before performing + another read */ + interruptible_sleep_on_timeout(&dev->wait_q, 1); + continue; + } + } + + /* + * process data + */ + + /* at this point this_read is > 0 */ + while (bulkidx < this_read && + (words_to_read > (dev->last_space ? 1 : 0))) { + /* while( bulkidx < this_read && words_to_read) */ + int keycode; + int pulse = 0; + + /* read packet length if needed */ + if (!bytes_left_in_packet) { + /* we assume we are on a packet length + * value. it is possible, in some + * cases, to get a packet that does + * not start with a length, apparently + * due to some sort of fragmenting, + * but occaisonally we do not receive + * the second half of a fragment + */ + bytes_left_in_packet = + 128 + signedp[bulkidx++]; + + /* unfortunately rather than keep all + * the data in the packetized format, + * the transceiver sends a trailing 8 + * bytes that aren't part of the + * transmittion from the remote, + * aren't packetized, and dont really + * have any value. we can basically + * tell we have hit them if 1) we have + * a loooong space currently stored + * up, and 2) the bytes_left value for + * this packet is obviously wrong + */ + if (bytes_left_in_packet > 4) { + if (dev->mce_bytes_left_in_packet) { + bytes_left_in_packet = + dev->mce_bytes_left_in_packet; + bulkidx--; + } + bytes_left_in_packet = 0; + bulkidx = this_read; + } + + /* always clear this if we have a + valid packet */ + dev->mce_bytes_left_in_packet = 0; + + /* continue here to verify we haven't + hit the end of the bulk_in */ + continue; + + } + + /* + * generate mode2 + */ + + keycode = signedp[bulkidx++]; + if (keycode < 0) { + pulse = 1; + keycode += 128; + } + keycode *= MCE_TIME_UNIT; + + bytes_left_in_packet--; + + if (pulse) { + if (dev->last_space) { + dev->lircdata[dev->lirccnt++] = + dev->last_space; + dev->last_space = 0; + words_to_read--; + + /* clear the lirc_t for the pulse */ + dev->lircdata[dev->lirccnt] = 0; + } + dev->lircdata[dev->lirccnt] += keycode; + dev->lircdata[dev->lirccnt] |= PULSE_BIT; + } else { + /* on pulse->space transition, add one + for the existing pulse */ + if (dev->lircdata[dev->lirccnt] && + !dev->last_space) { + dev->lirccnt++; + words_to_read--; + } + + dev->last_space += keycode; + } + } + } + + /* save off some info if we are exiting mid-packet, or with + leftovers */ + if (bytes_left_in_packet) + dev->mce_bytes_left_in_packet = bytes_left_in_packet; + if (bulkidx < this_read) { + dev->usb_valid_bytes_in_bulk_buffer = (this_read - bulkidx); + memcpy(dev->bulk_in_buffer, &(dev->bulk_in_buffer[bulkidx]), + dev->usb_valid_bytes_in_bulk_buffer); + } + return dev->lirccnt; +} + +/* mceusb_add_to_buf: called by lirc_dev to fetch all available keys + * this is used as a polling interface for us: since we set + * plugin->sample_rate we will periodically get the below call to + * check for new data returns 0 on success, or -ENODATA if nothing is + * available + */ +static int mceusb_add_to_buf(void *data, struct lirc_buffer *buf) +{ + struct usb_skel *dev = (struct usb_skel *) data; + + down(&dev->sem); + + /* verify device still present */ + if (dev->udev == NULL) { + up(&dev->sem); + return -ENODEV; + } + + if (!dev->lirccnt) { + int res; + dev->lircidx = 0; + + res = msir_fetch_more_data(dev, 1); + + if (res == 0) + res = -ENODATA; + if (res < 0) { + up(&dev->sem); + return res; + } + } + + if (dev->lirccnt) { + int keys_to_copy; + + /* determine available buffer space and available data */ + keys_to_copy = lirc_buffer_available(buf); + if (keys_to_copy > dev->lirccnt) + keys_to_copy = dev->lirccnt; + + lirc_buffer_write_n(buf, + (unsigned char *) &(dev->lircdata[dev->lircidx]), + keys_to_copy); + dev->lircidx += keys_to_copy; + dev->lirccnt -= keys_to_copy; + + up(&dev->sem); + return 0; + } + + up(&dev->sem); + return -ENODATA; +} + +/** + * mceusb_write_bulk_callback + */ +#if defined(KERNEL_2_5) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void mceusb_write_bulk_callback(struct urb *urb, struct pt_regs *regs) +#else +static void mceusb_write_bulk_callback(struct urb *urb) +#endif +{ + struct usb_skel *dev = (struct usb_skel *)urb->context; + + dprintk("%s - minor %d", __func__, dev->minor); + + if ((urb->status != -ENOENT) && + (urb->status != -ECONNRESET)) { + dprintk("%s - nonzero write buld status received: %d", + __func__, urb->status); + return; + } + + return; +} + +/** + * mceusb_probe + * + * Called by the usb core when a new device is connected that it + * thinks this driver might be interested in. + */ +#ifdef KERNEL_2_5 +static int mceusb_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(interface); + struct usb_host_interface *iface_desc; +#else +static void *mceusb_probe(struct usb_device *udev, unsigned int ifnum, + const struct usb_device_id *id) +{ + struct usb_interface *interface = &udev->actconfig->interface[ifnum]; + struct usb_interface_descriptor *iface_desc; +#endif + struct usb_skel *dev = NULL; + struct usb_endpoint_descriptor *endpoint; + + struct lirc_plugin *plugin; + struct lirc_buffer *rbuf; + + int minor; + size_t buffer_size; + int i; + int retval = -ENOMEM; + char junk[64]; + int partial = 0; + + /* See if the device offered us matches what we can accept */ + if (cpu_to_le16(udev->descriptor.idVendor) != USB_MCEUSB_VENDOR_ID || + cpu_to_le16(udev->descriptor.idProduct) != USB_MCEUSB_PRODUCT_ID) { + dprintk("Wrong Vendor/Product IDs"); +#ifdef KERNEL_2_5 + return -ENODEV; +#else + return NULL; +#endif + } + + /* select a "subminor" number (part of a minor number) */ + down(&minor_table_mutex); + for (minor = 0; minor < MAX_DEVICES; ++minor) { + if (minor_table[minor] == NULL) + break; + } + if (minor >= MAX_DEVICES) { + info("Too many devices plugged in, " + "can not handle this device."); + goto error; + } + + /* allocate memory for our device state and initialize it */ + dev = kmalloc(sizeof(struct usb_skel), GFP_KERNEL); + if (dev == NULL) { + err("Out of memory"); +#ifdef KERNEL_2_5 + retval = -ENOMEM; +#endif + goto error; + } + minor_table[minor] = dev; + + memset(dev, 0x00, sizeof(*dev)); + init_MUTEX(&dev->sem); + dev->udev = udev; + dev->interface = interface; + dev->minor = minor; + + /* set up the endpoint information */ + /* check out the endpoints */ + /* use only the first bulk-in and bulk-out endpoints */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 5) + iface_desc = &interface->altsetting[0]; +#else + iface_desc = interface->cur_altsetting; +#endif + +#ifdef KERNEL_2_5 + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; +#else + for (i = 0; i < iface_desc->bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i]; +#endif + if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_BULK)) { + dprintk("we found a bulk in endpoint"); + buffer_size = endpoint->wMaxPacketSize; + dev->bulk_in_size = buffer_size; + dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; +#ifdef KERNEL_2_5 + dev->bulk_in_buffer = + usb_buffer_alloc(udev, buffer_size, + GFP_ATOMIC, &dev->dma_in); +#else + dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); +#endif + if (!dev->bulk_in_buffer) { + err("Couldn't allocate bulk_in_buffer"); + goto error; + } + } + + if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + == 0x00) + && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_BULK)) { + dprintk("we found a bulk out endpoint"); +#ifdef KERNEL_2_5 + dev->write_urb = usb_alloc_urb(0, GFP_KERNEL); +#else + dev->write_urb = usb_alloc_urb(0); +#endif + if (!dev->write_urb) { + err("No free urbs available"); + goto error; + } + buffer_size = endpoint->wMaxPacketSize; + dev->bulk_out_size = buffer_size; + dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; +#ifdef KERNEL_2_5 + dev->bulk_out_buffer = + usb_buffer_alloc(udev, buffer_size, + GFP_ATOMIC, &dev->dma_out); +#else + dev->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL); +#endif + if (!dev->bulk_out_buffer) { + err("Couldn't allocate bulk_out_buffer"); + goto error; + } +#ifdef KERNEL_2_5 + usb_fill_bulk_urb(dev->write_urb, udev, + usb_sndbulkpipe + (udev, endpoint->bEndpointAddress), + dev->bulk_out_buffer, buffer_size, + mceusb_write_bulk_callback, dev); +#else + FILL_BULK_URB(dev->write_urb, udev, + usb_sndbulkpipe(udev, + endpoint->bEndpointAddress), + dev->bulk_out_buffer, buffer_size, + mceusb_write_bulk_callback, dev); +#endif + } + } + + if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { + err("Couldn't find both bulk-in and bulk-out endpoints"); + goto error; + } + + /* init the waitq */ + init_waitqueue_head(&dev->wait_q); + + + /* Set up our lirc plugin */ + plugin = kmalloc(sizeof(struct lirc_plugin), GFP_KERNEL); + if (!plugin) { + err("out of memory"); + goto error; + } + memset(plugin, 0, sizeof(struct lirc_plugin)); + + rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); + if (!rbuf) { + err("out of memory"); + kfree(plugin); + goto error; + } + + /* the lirc_atiusb module doesn't memset rbuf here ... ? */ + if (lirc_buffer_init(rbuf, sizeof(lirc_t), 128)) { + err("out of memory"); + kfree(plugin); + kfree(rbuf); + goto error; + } + + strcpy(plugin->name, DRIVER_NAME " "); + plugin->minor = minor; + plugin->code_length = sizeof(lirc_t) * 8; + plugin->features = LIRC_CAN_REC_MODE2; /* | LIRC_CAN_SEND_MODE2; */ + plugin->data = dev; + plugin->rbuf = rbuf; + plugin->ioctl = NULL; + plugin->set_use_inc = &set_use_inc; + plugin->set_use_dec = &set_use_dec; + plugin->sample_rate = 80; /* sample at 100hz (10ms) */ + plugin->add_to_buf = &mceusb_add_to_buf; + /* plugin->fops = &mceusb_fops; */ +#ifdef LIRC_HAVE_SYSFS + plugin->dev = &udev->dev; +#endif + plugin->owner = THIS_MODULE; + if (lirc_register_plugin(plugin) < 0) { + kfree(plugin); + lirc_buffer_free(rbuf); + kfree(rbuf); + goto error; + } + dev->plugin = plugin; + + /* clear off the first few messages. these look like + * calibration or test data, i can't really tell + * this also flushes in case we have random ir data queued up + */ + for (i = 0; i < 40; i++) + (void) usb_bulk_msg(udev, + usb_rcvbulkpipe(udev, + dev->bulk_in_endpointAddr), + junk, 64, &partial, HZ*10); + + msir_cleanup(dev); + mceusb_setup(udev); + +#ifdef KERNEL_2_5 + /* we can register the device now, as it is ready */ + usb_set_intfdata(interface, dev); +#endif + /* let the user know what node this device is now attached to */ + /* info("USB Microsoft IR Transceiver device now attached to msir%d", + dev->minor); */ + up(&minor_table_mutex); +#ifdef KERNEL_2_5 + return 0; +#else + return dev; +#endif +error: + mceusb_delete(dev); + dev = NULL; + dprintk("%s: retval = %x", __func__, retval); + up(&minor_table_mutex); +#ifdef KERNEL_2_5 + return retval; +#else + return NULL; +#endif +} + +/** + * mceusb_disconnect + * + * Called by the usb core when the device is removed from the system. + * + * This routine guarantees that the driver will not submit any more urbs + * by clearing dev->udev. It is also supposed to terminate any currently + * active urbs. Unfortunately, usb_bulk_msg(), used in skel_read(), does + * not provide any way to do this. But at least we can cancel an active + * write. + */ +#ifdef KERNEL_2_5 +static void mceusb_disconnect(struct usb_interface *interface) +#else +static void mceusb_disconnect(struct usb_device *udev, void *ptr) +#endif +{ + struct usb_skel *dev; + int minor; +#ifdef KERNEL_2_5 + dev = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); +#else + dev = (struct usb_skel *)ptr; +#endif + + down(&minor_table_mutex); + down(&dev->sem); + minor = dev->minor; + + /* unhook lirc things */ + lirc_unregister_plugin(minor); + lirc_buffer_free(dev->plugin->rbuf); + kfree(dev->plugin->rbuf); + kfree(dev->plugin); +#ifdef KERNEL_2_5 + /* terminate an ongoing write */ + if (atomic_read(&dev->write_busy)) { + usb_kill_urb(dev->write_urb); + wait_for_completion(&dev->write_finished); + } + + /* prevent device read, write and ioctl */ + dev->present = 0; +#endif + + mceusb_delete(dev); + + info("Microsoft IR Transceiver #%d now disconnected", minor); + up(&dev->sem); + up(&minor_table_mutex); +} + + + +/** + * usb_mceusb_init + */ +static int __init usb_mceusb_init(void) +{ + int result; + + /* register this driver with the USB subsystem */ + result = usb_register(&mceusb_driver); +#ifdef KERNEL_2_5 + if (result) { +#else + if (result < 0) { +#endif + err("usb_register failed for the " DRIVER_NAME + " driver. error number %d", result); +#ifdef KERNEL_2_5 + return result; +#else + return -1; +#endif + } + + info(DRIVER_DESC " " DRIVER_VERSION); + return 0; +} + + +/** + * usb_mceusb_exit + */ +static void __exit usb_mceusb_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&mceusb_driver); +} + +module_init(usb_mceusb_init); +module_exit(usb_mceusb_exit); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(usb, mceusb_table); + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +EXPORT_NO_SYMBOLS; --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/bttv_deprecated.c +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/bttv_deprecated.c @@ -0,0 +1,44 @@ +//Temporarily added until a resolution is reached upstream +//For kernel 2.6.22 + +#include +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,22) +#include "extra_2.6.22/bttv.h" +#include "extra_2.6.22/bttvp.h" +#else +#include "../drivers/media/video/bt8xx/bttv.h" +#include "../drivers/media/video/bt8xx/bttvp.h" +#endif + +struct bttv bttvs[BTTV_MAX]; +unsigned int bttv_debug; +unsigned int bttv_num; /* number of Bt848s in use */ + +int bttv_get_cardinfo(unsigned int card, int *type, unsigned *cardid) +{ + printk("The bttv_* interface is obsolete and will go away,\n" + "please use the new, sysfs based interface instead.\n"); + if (card >= bttv_num) { + return -1; + } + *type = bttvs[card].c.type; + *cardid = bttvs[card].cardid; + return 0; +} + +wait_queue_head_t* 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; +} + + --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/Makefile +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/Makefile @@ -0,0 +1,4 @@ +EXTRA_CFLAGS =-DIRCTL_DEV_MAJOR=61 -DLIRC_SERIAL_TRANSMITTER -DLIRC_SERIAL_SOFTCARRIER -I$(src)/.. + +obj-$(CONFIG_LIRC_GPIO) += lirc_gpio.o +lirc_gpio/lirc_gpio-objs += bttv_deprecated.o --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/bttv_deprecated.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/bttv_deprecated.h @@ -0,0 +1,6 @@ +//Temporarily re-added for Ubuntu Kernel 2.6.22 until upstream +//Resolution is reached. +extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card); +extern int bttv_get_cardinfo(unsigned int card, int *type, + unsigned int *cardid); + --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/lirc_gpio.c +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/lirc_gpio.c @@ -0,0 +1,630 @@ +/* + * Remote control driver for the TV-card + * key codes are obtained from GPIO port + * + * (L) by Artur Lipowski + * patch for the AverMedia by Santiago Garcia Mantinan + * and Christoph Bartelmus + * patch for the BestBuy by Miguel Angel Alvarez + * patch for the Winfast TV2000 by Juan Toledo + * + * patch for the I-O Data GV-BCTV5/PCI by Jens C. Rasmussen + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: lirc_gpio.c,v 1.50 2007/09/27 19:47:20 lirc Exp $ + * + */ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 4) +#error "*******************************************************" +#error "Sorry, this driver needs kernel version 2.2.4 or higher" +#error "*******************************************************" +#endif + +#include +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +#include +#endif +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) +#include "../drivers/char/bttv.h" +#include "../drivers/char/bttvp.h" +#elif LINUX_VERSION_CODE == KERNEL_VERSION(2,6,16) +#include "extra_2.6.16/bttv.h" +#include "extra_2.6.16/bttvp.h" +#elif LINUX_VERSION_CODE == KERNEL_VERSION(2,6,17) +#include "extra_2.6.17/bttv.h" +#include "extra_2.6.17/bttvp.h" +#elif LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18) +#include "extra_2.6.18/bttv.h" +#include "extra_2.6.18/bttvp.h" +#elif LINUX_VERSION_CODE == KERNEL_VERSION(2,6,20) +#include "extra_2.6.20/bttv.h" +#include "extra_2.6.20/bttvp.h" +#elif LINUX_VERSION_CODE == KERNEL_VERSION(2,6,22) +#include "extra_2.6.22/bttv.h" +#include "extra_2.6.22/bttvp.h" +#include "bttv_deprecated.h" +#endif + +#if BTTV_VERSION_CODE < KERNEL_VERSION(0, 7, 45) +#error "*******************************************************" +#error " Sorry, this driver needs bttv version 0.7.45 or " +#error " higher. If you are using the bttv package, copy it to " +#error " the kernel " +#error "*******************************************************" +#endif + +#include "kcompat.h" +#include "lirc_dev/lirc_dev.h" + +/* insmod parameters */ +static int debug; +static int card; +static int minor = -1; +static int bttv_id = BTTV_BOARD_UNKNOWN; +static unsigned long gpio_mask; +static unsigned long gpio_enable; +static unsigned long gpio_lock_mask; +static unsigned long gpio_xor_mask; +static int soft_gap; +static int sample_rate = 10; + +struct rcv_info { + int bttv_id; + int card_id; + unsigned long gpio_mask; + unsigned long gpio_enable; + unsigned long gpio_lock_mask; + unsigned long gpio_xor_mask; + int soft_gap; + int sample_rate; + unsigned char code_length; +}; + +static struct rcv_info rcv_infos[] = { + {BTTV_BOARD_UNKNOWN, + 0, 0, 0, 0, 0, 0, 1, 0}, + {BTTV_BOARD_PXELVWPLTVPAK, + 0, 0x00003e00, 0, 0x0010000, 0, 0, 15, 32}, + {BTTV_BOARD_PXELVWPLTVPRO, + 0, 0x00001f00, 0, 0x0008000, 0, 500, 12, 32}, + {BTTV_BOARD_PV_BT878P_9B, + 0, 0x00001f00, 0, 0x0008000, 0, 500, 12, 32}, + {BTTV_BOARD_PV_BT878P_PLUS, + 0, 0x00001f00, 0, 0x0008000, 0, 500, 12, 32}, +#ifdef BTTV_BOARD_PV_M4900 + {BTTV_BOARD_PV_M4900, + 0, 0x00001f00, 0, 0x0008000, 0, 500, 12, 32}, +#endif + {BTTV_BOARD_AVERMEDIA, + 0, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32}, + + /* mapped to Capture98 */ + {BTTV_BOARD_AVPHONE98, + 0x00011461, 0x003b8000, 0x00004000, + 0x0800000, 0x00800000, 0, 10, 0}, + {BTTV_BOARD_AVERMEDIA98, + 0x00021461, 0x003b8000, 0x00004000, + 0x0800000, 0x00800000, 0, 10, 0}, + + /* mapped to Phone98 */ + {BTTV_BOARD_AVPHONE98, + 0x00031461, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32}, + /* is this one correct? */ + {BTTV_BOARD_AVERMEDIA98, + 0x00041461, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32}, + /* work-around for VDOMATE */ + {BTTV_BOARD_AVERMEDIA98, + 0x03001461, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32}, + /* reported by Danijel Korzinek, AVerTV GOw/FM */ + {BTTV_BOARD_AVERMEDIA98, + 0x00000000, 0x00f88000, 0, 0x0010000, 0x00010000, 0, 10, 32}, + + {BTTV_BOARD_CHRONOS_VS2, + 0, 0x000000f8, 0, 0x0000100, 0, 0, 20, 0}, + /* CPH031 and CPH033 cards (?) */ + /* MIRO was just a work-around */ + {BTTV_BOARD_MIRO, + 0, 0x00001f00, 0, 0x0004000, 0, 0, 10, 32}, + {BTTV_BOARD_DYNALINK, + 0, 0x00001f00, 0, 0x0004000, 0, 0, 10, 32}, +#ifdef BTTV_BOARD_ASKEY_CPH03X + {BTTV_BOARD_ASKEY_CPH03X, + 0, 0x00001f00, 0, 0x0004000, 0, 0, 10, 32}, +#endif + {BTTV_BOARD_WINVIEW_601, + 0, 0x00001f00, 0, 0x0004000, 0, 0, 0, 32}, +#ifdef BTTV_BOARD_KWORLD + {BTTV_BOARD_KWORLD, + 0, 0x00007f00, 0, 0x0004000, 0, 0, 12, 32}, +#endif + /* just a guess */ + {BTTV_BOARD_MAGICTVIEW061, + 0, 0x0028e000, 0, 0x0020000, 0, 0, 20, 32}, + {BTTV_BOARD_MAGICTVIEW063, + 0, 0x0028e000, 0, 0x0020000, 0, 0, 20, 32}, + {BTTV_BOARD_PHOEBE_TVMAS, + 0, 0x0028e000, 0, 0x0020000, 0, 0, 20, 32}, +#ifdef BTTV_BOARD_BESTBUY_EASYTV2 + {BTTV_BOARD_BESTBUY_EASYTV, + 0, 0x00007F00, 0, 0x0004000, 0, 0, 10, 8}, + {BTTV_BOARD_BESTBUY_EASYTV2, + 0, 0x00007F00, 0, 0x0008000, 0, 0, 10, 8}, +#endif + /* lock_mask probably also 0x100, or maybe it is 0x0 for all others? */ + {BTTV_BOARD_FLYVIDEO, + 0, 0x000000f8, 0, 0, 0, 0, 0, 42}, + {BTTV_BOARD_FLYVIDEO_98, + 0, 0x000000f8, 0, 0x0000100, 0, 0, 0, 42}, + {BTTV_BOARD_TYPHOON_TVIEW, + 0, 0x000000f8, 0, 0x0000100, 0, 0, 0, 42}, +#ifdef BTTV_BOARD_FLYVIDEO_98FM + /* smorar@alfonzo.smuts.uct.ac.za */ + {BTTV_BOARD_FLYVIDEO_98FM, + 0, 0x000000f8, 0, 0x0000100, 0, 0, 0, 42}, +#endif + /* The Leadtek WinFast TV 2000 XP card (id 0x6606107d) uses an + * extra gpio bit compared to the original TV 2000 card (id + * 0x217d6606); as the bttv-0.7.100 driver does not + * distinguish between the two cards, we enable the extra bit + * based on the card id: */ + {BTTV_BOARD_WINFAST2000, + 0x6606107d, 0x000008f8, 0, 0x0000100, 0, 0, 0, 32}, + {BTTV_BOARD_WINFAST2000, + 0x6609107d, 0x000008f8, 0, 0x0000100, 0, 0, 0, 32}, + {BTTV_BOARD_WINFAST2000, + 0xff06107d, 0x000008f8, 0, 0x0000100, 0, 0, 0, 32}, + /* default: */ + {BTTV_BOARD_WINFAST2000, + 0, 0x000000f8, 0, 0x0000100, 0, 0, 0, 32}, +#ifdef BTTV_BOARD_GVBCTV5PCI + {BTTV_BOARD_GVBCTV5PCI, + 0, 0x00f0b000, 0, 0, 0, 0, 20, 8}, +#endif +}; + +static unsigned char code_length; +static unsigned char code_bytes = 1; + +#define MAX_BYTES 8 + +#define SUCCESS 0 +#define LOGHEAD "lirc_gpio (%d): " + +/* how many bits GPIO value can be shifted right before processing + * it is computed from the value of gpio_mask_parameter + */ +static unsigned char gpio_pre_shift; + +static inline int reverse(int data, int bits) +{ + int i; + int c; + + for (c = 0, i = 0; i < bits; i++) + c |= (((data & (1<>= gpio_pre_shift; + while (mask) { + if (mask & 1u) + codes[0] |= (gpio_val & 1u) << shift++; + mask >>= 1; + gpio_val >>= 1; + } + + dprintk(LOGHEAD "code is %lx\n", card, (unsigned long) codes[0]); + switch (bttv_id) { + case BTTV_BOARD_AVERMEDIA: + codes[2] = (codes[0]<<2)&0xff; + codes[3] = (~codes[2])&0xff; + codes[0] = 0x02; + codes[1] = 0xFD; + break; + case BTTV_BOARD_AVPHONE98: + codes[2] = ((codes[0]&(~0x1))<<2)&0xff; + codes[3] = (~codes[2])&0xff; + if (codes[0]&0x1) { + codes[0] = 0xc0; + codes[1] = 0x3f; + } else { + codes[0] = 0x40; + codes[1] = 0xbf; + } + break; + case BTTV_BOARD_AVERMEDIA98: + break; + case BTTV_BOARD_FLYVIDEO: + case BTTV_BOARD_FLYVIDEO_98: + case BTTV_BOARD_TYPHOON_TVIEW: +#ifdef BTTV_BOARD_FLYVIDEO_98FM + case BTTV_BOARD_FLYVIDEO_98FM: +#endif + codes[4] = codes[0]<<3; + codes[5] = ((~codes[4])&0xff); + + codes[0] = 0x00; + codes[1] = 0x1A; + codes[2] = 0x1F; + codes[3] = 0x2F; + break; + case BTTV_BOARD_MAGICTVIEW061: + case BTTV_BOARD_MAGICTVIEW063: + case BTTV_BOARD_PHOEBE_TVMAS: + codes[0] = (codes[0]&0x01) + | ((codes[0]&0x02)<<1) + | ((codes[0]&0x04)<<2) + | ((codes[0]&0x08)>>2) + | ((codes[0]&0x10)>>1); + /* FALLTHROUGH */ + case BTTV_BOARD_MIRO: + case BTTV_BOARD_DYNALINK: +#ifdef BTTV_BOARD_ASKEY_CPH03X + case BTTV_BOARD_ASKEY_CPH03X: +#endif + case BTTV_BOARD_PXELVWPLTVPAK: + case BTTV_BOARD_PXELVWPLTVPRO: + case BTTV_BOARD_PV_BT878P_9B: + case BTTV_BOARD_PV_BT878P_PLUS: +#ifdef BTTV_BOARD_PV_M4900 + case BTTV_BOARD_PV_M4900: +#endif +#ifdef BTTV_BOARD_KWORLD + case BTTV_BOARD_KWORLD: +#endif + codes[2] = reverse(codes[0], 8); + codes[3] = (~codes[2])&0xff; + codes[0] = 0x61; + codes[1] = 0xD6; + break; +#if 0 + /* derived from e-tech config file */ + /* 26 + 16 bits */ + /* won't apply it until it's confirmed with a fly98 */ + case BTTV_BOARD_FLYVIDEO_98: + case BTTV_BOARD_FLYVIDEO_98FM: + codes[4] = codes[0]<<3; + codes[5] = (~codes[4])&0xff; + + codes[0] = 0x00; + codes[1] = 0x1A; + codes[2] = 0x1F; + codes[3] = 0x2F; + break; +#endif + case BTTV_BOARD_WINFAST2000: + /* shift extra bit */ + codes[0] = (codes[0]&0x1f) | ((codes[0]&0x20) << 1); + case BTTV_BOARD_WINVIEW_601: + codes[2] = reverse(codes[0], 8); + codes[3] = (~codes[2])&0xff; + codes[0] = 0xC0; + codes[1] = 0x3F; + break; + default: + break; + } + + return SUCCESS; +} + +/* add_to_buf - copy a code to the buffer */ +static int add_to_buf(void *data, struct lirc_buffer *buf) +{ + static unsigned long next_time; + static unsigned char prev_codes[MAX_BYTES]; + unsigned long code = 0; + unsigned char cur_codes[MAX_BYTES]; + + if (bttv_read_gpio(card, &code)) { + dprintk(LOGHEAD "cannot read GPIO\n", card); + return -EIO; + } + + if (build_key(code, cur_codes)) + return -EFAULT; + + if (soft_gap) { + if (!memcmp(prev_codes, cur_codes, code_bytes) && + jiffies < next_time) + return -EAGAIN; + + next_time = jiffies + soft_gap; + } + memcpy(prev_codes, cur_codes, code_bytes); + + lirc_buffer_write_1(buf, cur_codes); + + return SUCCESS; +} + +static int set_use_inc(void *data) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static void set_use_dec(void *data) +{ + MOD_DEC_USE_COUNT; +} + +static wait_queue_head_t *get_queue(void *data) +{ + return bttv_get_gpio_queue(card); +} + +static struct lirc_plugin plugin = { + .name = "lirc_gpio ", + .add_to_buf = add_to_buf, + .get_queue = get_queue, + .set_use_inc = set_use_inc, + .set_use_dec = set_use_dec, + .dev = NULL, + .owner = THIS_MODULE, +}; + +/* + * + */ +static int gpio_remote_init(void) +{ + int ret; + unsigned int mask; + + /* "normalize" gpio_mask + * this means shift it right until first bit is set + */ + while (!(gpio_mask & 1u)) { + gpio_pre_shift++; + gpio_mask >>= 1; + } + + if (code_length) + plugin.code_length = code_length; + else { + /* calculate scan code length in bits if needed */ + plugin.code_length = 1; + mask = gpio_mask >> 1; + while (mask) { + if (mask & 1u) + plugin.code_length++; + mask >>= 1; + } + } + + code_bytes = (plugin.code_length/8) + (plugin.code_length % 8 ? 1 : 0); + if (MAX_BYTES < code_bytes) { + printk(LOGHEAD "scan code too long (%d bytes)\n", + minor, code_bytes); + return -EBADRQC; + } + + if (gpio_enable) { + if (bttv_gpio_enable(card, gpio_enable, gpio_enable)) { + printk(LOGHEAD "gpio_enable failure\n", minor); + return -EIO; + } + } + + + /* translate ms to jiffies */ + soft_gap = (soft_gap*HZ) / 1000; + + plugin.minor = minor; + plugin.sample_rate = sample_rate; + + ret = lirc_register_plugin(&plugin); + + if (0 > ret) { + printk(LOGHEAD "device registration failed with %d\n", + minor, ret); + return ret; + } + + minor = ret; + printk(LOGHEAD "driver registered\n", minor); + + return SUCCESS; +} + +#ifdef MODULE +/* + * + */ +int init_module(void) +{ + int type, cardid, card_type; + + if (MAX_IRCTL_DEVICES < minor) { + printk(KERN_INFO "lirc_gpio: parameter minor (%d) " + "must be less than %d!\n", + minor, MAX_IRCTL_DEVICES - 1); + return -EBADRQC; + } + + request_module("bttv"); + + /* if gpio_mask not zero then use module parameters + * instead of autodetecting TV card + */ + if (gpio_mask) { + if (sample_rate != 0 && + (2 > sample_rate || HZ < sample_rate)) { + printk(LOGHEAD "parameter sample_rate " + "must be between 2 and %d!\n", minor, HZ); + return -EBADRQC; + } + + if (sample_rate != 0 && soft_gap && + ((2000/sample_rate) > soft_gap || 1000 < soft_gap)) { + printk(LOGHEAD "parameter soft_gap " + "must be between %d and 1000!\n", + minor, 2000/sample_rate); + return -EBADRQC; + } + } else { + if (bttv_get_cardinfo(card, &type, &cardid) == -1) { + printk(LOGHEAD "could not get card type\n", minor); + return -EBADRQC; + } + printk(LOGHEAD "card type 0x%x, id 0x%x\n", minor, + type, cardid); + + if (type == BTTV_BOARD_UNKNOWN) { + printk(LOGHEAD "cannot detect TV card nr %d!\n", + minor, card); + return -EBADRQC; + } + for (card_type = 1; + card_type < sizeof(rcv_infos)/sizeof(struct rcv_info); + card_type++) { + if (rcv_infos[card_type].bttv_id == type && + (rcv_infos[card_type].card_id == 0 || + rcv_infos[card_type].card_id == cardid)) { + bttv_id = rcv_infos[card_type].bttv_id; + gpio_mask = rcv_infos[card_type].gpio_mask; + gpio_enable = rcv_infos[card_type].gpio_enable; + gpio_lock_mask = + rcv_infos[card_type].gpio_lock_mask; + gpio_xor_mask = + rcv_infos[card_type].gpio_xor_mask; + soft_gap = rcv_infos[card_type].soft_gap; + sample_rate = rcv_infos[card_type].sample_rate; + code_length = rcv_infos[card_type].code_length; + break; + } + } + if (type == BTTV_BOARD_AVPHONE98 && cardid == 0x00011461) + bttv_id = BTTV_BOARD_AVERMEDIA98; + + if (type == BTTV_BOARD_AVERMEDIA98 && cardid == 0x00041461) + bttv_id = BTTV_BOARD_AVPHONE98; + + if (type == BTTV_BOARD_AVERMEDIA98 && cardid == 0x03001461) + bttv_id = BTTV_BOARD_AVPHONE98; + + if (type == BTTV_BOARD_AVERMEDIA98 && cardid == 0x00000000) + bttv_id = BTTV_BOARD_AVPHONE98; + + if (card_type == sizeof(rcv_infos)/sizeof(struct rcv_info)) { + printk(LOGHEAD "TV card type 0x%x not supported!\n", + minor, type); + return -EBADRQC; + } + } + + request_module("lirc_dev"); + + return gpio_remote_init(); +} + +/* + * + */ +void cleanup_module(void) +{ + lirc_unregister_plugin(minor); + + dprintk(LOGHEAD "module successfully unloaded\n", minor); +} + +/* Dont try to use it as a static version ! */ +MODULE_DESCRIPTION("Driver module for remote control (data " + "from bt848 GPIO port)"); +MODULE_AUTHOR("Artur Lipowski"); +MODULE_LICENSE("GPL"); + +module_param(minor, int, 0444); +MODULE_PARM_DESC(minor, "Preferred minor device number"); + +module_param(card, int, 0444); +MODULE_PARM_DESC(card, "TV card number to attach to"); + +module_param(gpio_mask, long, 0444); +MODULE_PARM_DESC(gpio_mask, "gpio_mask"); + +module_param(gpio_lock_mask, long, 0444); +MODULE_PARM_DESC(gpio_lock_mask, "gpio_lock_mask"); + +module_param(gpio_xor_mask, long, 0444); +MODULE_PARM_DESC(gpio_xor_mask, "gpio_xor_mask"); + +module_param(soft_gap, int, 0444); +MODULE_PARM_DESC(soft_gap, "Time between keypresses (in ms)"); + +module_param(sample_rate, int, 0444); +MODULE_PARM_DESC(sample_rate, "Sample rate (between 2 and HZ)"); + +module_param(bttv_id, int, 0444); +MODULE_PARM_DESC(bttv_id, "BTTV card type"); + +module_param(debug, bool, 0644); +MODULE_PARM_DESC(debug, "Enable debugging messages"); + +EXPORT_NO_SYMBOLS; + +#endif /* MODULE */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.18/bttv.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.18/bttv.h @@ -0,0 +1,389 @@ +/* + * + * bttv - Bt848 frame grabber driver + * + * card ID's and external interfaces of the bttv driver + * basically stuff needed by other drivers (i2c, lirc, ...) + * and is supported not to change much over time. + * + * Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) + * (c) 1999,2000 Gerd Knorr + * + */ + +#ifndef _BTTV_H_ +#define _BTTV_H_ + +#include +#include +#include +#include +#include + +/* ---------------------------------------------------------- */ +/* exported by bttv-cards.c */ + +#define BTTV_BOARD_UNKNOWN 0x00 +#define BTTV_BOARD_MIRO 0x01 +#define BTTV_BOARD_HAUPPAUGE 0x02 +#define BTTV_BOARD_STB 0x03 +#define BTTV_BOARD_INTEL 0x04 +#define BTTV_BOARD_DIAMOND 0x05 +#define BTTV_BOARD_AVERMEDIA 0x06 +#define BTTV_BOARD_MATRIX_VISION 0x07 +#define BTTV_BOARD_FLYVIDEO 0x08 +#define BTTV_BOARD_TURBOTV 0x09 +#define BTTV_BOARD_HAUPPAUGE878 0x0a +#define BTTV_BOARD_MIROPRO 0x0b +#define BTTV_BOARD_ADSTECH_TV 0x0c +#define BTTV_BOARD_AVERMEDIA98 0x0d +#define BTTV_BOARD_VHX 0x0e +#define BTTV_BOARD_ZOLTRIX 0x0f +#define BTTV_BOARD_PIXVIEWPLAYTV 0x10 +#define BTTV_BOARD_WINVIEW_601 0x11 +#define BTTV_BOARD_AVEC_INTERCAP 0x12 +#define BTTV_BOARD_LIFE_FLYKIT 0x13 +#define BTTV_BOARD_CEI_RAFFLES 0x14 +#define BTTV_BOARD_CONFERENCETV 0x15 +#define BTTV_BOARD_PHOEBE_TVMAS 0x16 +#define BTTV_BOARD_MODTEC_205 0x17 +#define BTTV_BOARD_MAGICTVIEW061 0x18 +#define BTTV_BOARD_VOBIS_BOOSTAR 0x19 +#define BTTV_BOARD_HAUPPAUG_WCAM 0x1a +#define BTTV_BOARD_MAXI 0x1b +#define BTTV_BOARD_TERRATV 0x1c +#define BTTV_BOARD_PXC200 0x1d +#define BTTV_BOARD_FLYVIDEO_98 0x1e +#define BTTV_BOARD_IPROTV 0x1f +#define BTTV_BOARD_INTEL_C_S_PCI 0x20 +#define BTTV_BOARD_TERRATVALUE 0x21 +#define BTTV_BOARD_WINFAST2000 0x22 +#define BTTV_BOARD_CHRONOS_VS2 0x23 +#define BTTV_BOARD_TYPHOON_TVIEW 0x24 +#define BTTV_BOARD_PXELVWPLTVPRO 0x25 +#define BTTV_BOARD_MAGICTVIEW063 0x26 +#define BTTV_BOARD_PINNACLE 0x27 +#define BTTV_BOARD_STB2 0x28 +#define BTTV_BOARD_AVPHONE98 0x29 +#define BTTV_BOARD_PV951 0x2a +#define BTTV_BOARD_ONAIR_TV 0x2b +#define BTTV_BOARD_SIGMA_TVII_FM 0x2c +#define BTTV_BOARD_MATRIX_VISION2 0x2d +#define BTTV_BOARD_ZOLTRIX_GENIE 0x2e +#define BTTV_BOARD_TERRATVRADIO 0x2f +#define BTTV_BOARD_DYNALINK 0x30 +#define BTTV_BOARD_GVBCTV3PCI 0x31 +#define BTTV_BOARD_PXELVWPLTVPAK 0x32 +#define BTTV_BOARD_EAGLE 0x33 +#define BTTV_BOARD_PINNACLEPRO 0x34 +#define BTTV_BOARD_TVIEW_RDS_FM 0x35 +#define BTTV_BOARD_LIFETEC_9415 0x36 +#define BTTV_BOARD_BESTBUY_EASYTV 0x37 +#define BTTV_BOARD_FLYVIDEO_98FM 0x38 +#define BTTV_BOARD_GRANDTEC 0x39 +#define BTTV_BOARD_ASKEY_CPH060 0x3a +#define BTTV_BOARD_ASKEY_CPH03X 0x3b +#define BTTV_BOARD_MM100PCTV 0x3c +#define BTTV_BOARD_GMV1 0x3d +#define BTTV_BOARD_BESTBUY_EASYTV2 0x3e +#define BTTV_BOARD_ATI_TVWONDER 0x3f +#define BTTV_BOARD_ATI_TVWONDERVE 0x40 +#define BTTV_BOARD_FLYVIDEO2000 0x41 +#define BTTV_BOARD_TERRATVALUER 0x42 +#define BTTV_BOARD_GVBCTV4PCI 0x43 +#define BTTV_BOARD_VOODOOTV_FM 0x44 +#define BTTV_BOARD_AIMMS 0x45 +#define BTTV_BOARD_PV_BT878P_PLUS 0x46 +#define BTTV_BOARD_FLYVIDEO98EZ 0x47 +#define BTTV_BOARD_PV_BT878P_9B 0x48 +#define BTTV_BOARD_SENSORAY311 0x49 +#define BTTV_BOARD_RV605 0x4a +#define BTTV_BOARD_POWERCLR_MTV878 0x4b +#define BTTV_BOARD_WINDVR 0x4c +#define BTTV_BOARD_GRANDTEC_MULTI 0x4d +#define BTTV_BOARD_KWORLD 0x4e +#define BTTV_BOARD_DSP_TCVIDEO 0x4f +#define BTTV_BOARD_HAUPPAUGEPVR 0x50 +#define BTTV_BOARD_GVBCTV5PCI 0x51 +#define BTTV_BOARD_OSPREY1x0 0x52 +#define BTTV_BOARD_OSPREY1x0_848 0x53 +#define BTTV_BOARD_OSPREY101_848 0x54 +#define BTTV_BOARD_OSPREY1x1 0x55 +#define BTTV_BOARD_OSPREY1x1_SVID 0x56 +#define BTTV_BOARD_OSPREY2xx 0x57 +#define BTTV_BOARD_OSPREY2x0_SVID 0x58 +#define BTTV_BOARD_OSPREY2x0 0x59 +#define BTTV_BOARD_OSPREY500 0x5a +#define BTTV_BOARD_OSPREY540 0x5b +#define BTTV_BOARD_OSPREY2000 0x5c +#define BTTV_BOARD_IDS_EAGLE 0x5d +#define BTTV_BOARD_PINNACLESAT 0x5e +#define BTTV_BOARD_FORMAC_PROTV 0x5f +#define BTTV_BOARD_MACHTV 0x60 +#define BTTV_BOARD_EURESYS_PICOLO 0x61 +#define BTTV_BOARD_PV150 0x62 +#define BTTV_BOARD_AD_TVK503 0x63 +#define BTTV_BOARD_HERCULES_SM_TV 0x64 +#define BTTV_BOARD_PACETV 0x65 +#define BTTV_BOARD_IVC200 0x66 +#define BTTV_BOARD_XGUARD 0x67 +#define BTTV_BOARD_NEBULA_DIGITV 0x68 +#define BTTV_BOARD_PV143 0x69 +#define BTTV_BOARD_VD009X1_MINIDIN 0x6a +#define BTTV_BOARD_VD009X1_COMBI 0x6b +#define BTTV_BOARD_VD009_MINIDIN 0x6c +#define BTTV_BOARD_VD009_COMBI 0x6d +#define BTTV_BOARD_IVC100 0x6e +#define BTTV_BOARD_IVC120 0x6f +#define BTTV_BOARD_PC_HDTV 0x70 +#define BTTV_BOARD_TWINHAN_DST 0x71 +#define BTTV_BOARD_WINFASTVC100 0x72 +#define BTTV_BOARD_TEV560 0x73 +#define BTTV_BOARD_SIMUS_GVC1100 0x74 +#define BTTV_BOARD_NGSTV_PLUS 0x75 +#define BTTV_BOARD_LMLBT4 0x76 +#define BTTV_BOARD_TEKRAM_M205 0x77 +#define BTTV_BOARD_CONTVFMI 0x78 +#define BTTV_BOARD_PICOLO_TETRA_CHIP 0x79 +#define BTTV_BOARD_SPIRIT_TV 0x7a +#define BTTV_BOARD_AVDVBT_771 0x7b +#define BTTV_BOARD_AVDVBT_761 0x7c +#define BTTV_BOARD_MATRIX_VISIONSQ 0x7d +#define BTTV_BOARD_MATRIX_VISIONSLC 0x7e +#define BTTV_BOARD_APAC_VIEWCOMP 0x7f +#define BTTV_BOARD_DVICO_DVBT_LITE 0x80 +#define BTTV_BOARD_VGEAR_MYVCD 0x81 +#define BTTV_BOARD_SUPER_TV 0x82 +#define BTTV_BOARD_TIBET_CS16 0x83 +#define BTTV_BOARD_KODICOM_4400R 0x84 +#define BTTV_BOARD_KODICOM_4400R_SL 0x85 +#define BTTV_BOARD_ADLINK_RTV24 0x86 +#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 +#define BTTV_BOARD_ACORP_Y878F 0x88 +#define BTTV_BOARD_CONCEPTRONIC_CTVFMI2 0x89 +#define BTTV_BOARD_PV_BT878P_2E 0x8a +#define BTTV_BOARD_PV_M4900 0x8b +#define BTTV_BOARD_OSPREY440 0x8c +#define BTTV_BOARD_ASOUND_SKYEYE 0x8d +#define BTTV_BOARD_SABRENT_TVFM 0x8e +#define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f +#define BTTV_BOARD_MACHTV_MAGICTV 0x90 + +/* more card-specific defines */ +#define PT2254_L_CHANNEL 0x10 +#define PT2254_R_CHANNEL 0x08 +#define PT2254_DBS_IN_2 0x400 +#define PT2254_DBS_IN_10 0x20000 +#define WINVIEW_PT2254_CLK 0x40 +#define WINVIEW_PT2254_DATA 0x20 +#define WINVIEW_PT2254_STROBE 0x80 + +/* digital_mode */ +#define DIGITAL_MODE_VIDEO 1 +#define DIGITAL_MODE_CAMERA 2 + +struct bttv_core { + /* device structs */ + struct pci_dev *pci; + struct i2c_adapter i2c_adap; + struct list_head subs; /* struct bttv_sub_device */ + + /* device config */ + unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */ + unsigned int type; /* card type (pointer into tvcards[]) */ + char name[8]; /* dev name */ +}; + +struct bttv; + + +struct bttv_ir { + struct input_dev *dev; + struct ir_input_state ir; + char name[32]; + char phys[32]; + + /* Usual gpio signalling */ + + u32 mask_keycode; + u32 mask_keydown; + u32 mask_keyup; + u32 polling; + u32 last_gpio; + struct work_struct work; + struct timer_list timer; + + /* RC5 gpio */ + u32 rc5_gpio; + struct timer_list timer_end; /* timer_end for code completion */ + struct timer_list timer_keyup; /* timer_end for key release */ + u32 last_rc5; /* last good rc5 code */ + u32 last_bit; /* last raw bit seen */ + u32 code; /* raw code under construction */ + struct timeval base_time; /* time of last seen code */ + int active; /* building raw code */ +}; + +struct tvcard +{ + char *name; + unsigned int video_inputs; + unsigned int audio_inputs; + unsigned int tuner; + unsigned int svhs; + unsigned int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO + u32 gpiomask; + u32 muxsel[16]; + u32 gpiomux[4]; /* Tuner, Radio, external, internal */ + u32 gpiomute; /* GPIO mute setting */ + u32 gpiomask2; /* GPIO MUX mask */ + + /* i2c audio flags */ + unsigned int no_msp34xx:1; + unsigned int no_tda9875:1; + unsigned int no_tda7432:1; + unsigned int needs_tvaudio:1; + unsigned int msp34xx_alt:1; + + /* flag: video pci function is unused */ + unsigned int no_video:1; + unsigned int has_dvb:1; + unsigned int has_remote:1; + unsigned int no_gpioirq:1; + + /* other settings */ + unsigned int pll; +#define PLL_NONE 0 +#define PLL_28 1 +#define PLL_35 2 + + unsigned int tuner_type; + unsigned int tuner_addr; + unsigned int radio_addr; + + unsigned int has_radio; + void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); + void (*muxsel_hook)(struct bttv *btv, unsigned int input); +}; + +extern struct tvcard bttv_tvcards[]; + +/* identification / initialization of the card */ +extern void bttv_idcard(struct bttv *btv); +extern void bttv_init_card1(struct bttv *btv); +extern void bttv_init_card2(struct bttv *btv); + +/* card-specific funtions */ +extern void tea5757_set_freq(struct bttv *btv, unsigned short freq); +extern void bttv_tda9880_setnorm(struct bttv *btv, int norm); + +/* extra tweaks for some chipsets */ +extern void bttv_check_chipset(void); +extern int bttv_handle_chipset(struct bttv *btv); + +/* ---------------------------------------------------------- */ +/* exported by bttv-if.c */ + +/* this obsolete -- please use the sysfs-based + interface below for new code */ + +/* returns card type + card ID (for bt878-based ones) + for possible values see lines below beginning with #define BTTV_BOARD_UNKNOWN + returns negative value if error occurred +*/ +extern int bttv_get_cardinfo(unsigned int card, int *type, + unsigned int *cardid); +extern struct pci_dev* bttv_get_pcidev(unsigned int card); + +/* obsolete, use bttv_get_cardinfo instead */ +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 occurred +*/ +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 occurred +*/ +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 occurred +*/ +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 occurred or queue is not available + WARNING: because there is no buffer for GPIO data, one MUST + process data ASAP +*/ +extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card); + +/* call i2c clients +*/ +extern void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg); + + + +/* ---------------------------------------------------------- */ +/* sysfs/driver-moded based gpio access interface */ + + +struct bttv_sub_device { + struct device dev; + struct bttv_core *core; + struct list_head list; +}; +#define to_bttv_sub_dev(x) container_of((x), struct bttv_sub_device, dev) + +struct bttv_sub_driver { + struct device_driver drv; + char wanted[BUS_ID_SIZE]; + int (*probe)(struct bttv_sub_device *sub); + void (*remove)(struct bttv_sub_device *sub); +}; +#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) + +int bttv_sub_register(struct bttv_sub_driver *drv, char *wanted); +int bttv_sub_unregister(struct bttv_sub_driver *drv); + +/* gpio access functions */ +void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits); +u32 bttv_gpio_read(struct bttv_core *core); +void bttv_gpio_write(struct bttv_core *core, u32 value); +void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits); + +#define gpio_inout(mask,bits) bttv_gpio_inout(&btv->c, mask, bits) +#define gpio_read() bttv_gpio_read(&btv->c) +#define gpio_write(value) bttv_gpio_write(&btv->c, value) +#define gpio_bits(mask,bits) bttv_gpio_bits(&btv->c, mask, bits) + + +/* ---------------------------------------------------------- */ +/* i2c */ + +extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg); +extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for); +extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, + unsigned char b2, int both); +extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr); + +extern int bttv_input_init(struct bttv *dev); +extern void bttv_input_fini(struct bttv *dev); +extern void bttv_input_irq(struct bttv *dev); + +#endif /* _BTTV_H_ */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.18/btcx-risc.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.18/btcx-risc.h @@ -0,0 +1,34 @@ +/* + */ +struct btcx_riscmem { + unsigned int size; + u32 *cpu; + u32 *jmp; + dma_addr_t dma; +}; + +struct btcx_skiplist { + int start; + int end; +}; + +int btcx_riscmem_alloc(struct pci_dev *pci, + struct btcx_riscmem *risc, + unsigned int size); +void btcx_riscmem_free(struct pci_dev *pci, + struct btcx_riscmem *risc); + +int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, + struct v4l2_clip *clips, unsigned int n); +int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, + unsigned int n, int mask); +void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips); +void btcx_calc_skips(int line, int width, unsigned int *maxy, + struct btcx_skiplist *skips, unsigned int *nskips, + const struct v4l2_clip *clips, unsigned int nclips); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.18/bt848.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.18/bt848.h @@ -0,0 +1,366 @@ +/* + bt848.h - Bt848 register offsets + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _BT848_H_ +#define _BT848_H_ + +#ifndef PCI_VENDOR_ID_BROOKTREE +#define PCI_VENDOR_ID_BROOKTREE 0x109e +#endif +#ifndef PCI_DEVICE_ID_BT848 +#define PCI_DEVICE_ID_BT848 0x350 +#endif +#ifndef PCI_DEVICE_ID_BT849 +#define PCI_DEVICE_ID_BT849 0x351 +#endif +#ifndef PCI_DEVICE_ID_BT878 +#define PCI_DEVICE_ID_BT878 0x36e +#endif +#ifndef PCI_DEVICE_ID_BT879 +#define PCI_DEVICE_ID_BT879 0x36f +#endif + + +/* Brooktree 848 registers */ + +#define BT848_DSTATUS 0x000 +#define BT848_DSTATUS_PRES (1<<7) +#define BT848_DSTATUS_HLOC (1<<6) +#define BT848_DSTATUS_FIELD (1<<5) +#define BT848_DSTATUS_NUML (1<<4) +#define BT848_DSTATUS_CSEL (1<<3) +#define BT848_DSTATUS_PLOCK (1<<2) +#define BT848_DSTATUS_LOF (1<<1) +#define BT848_DSTATUS_COF (1<<0) + +#define BT848_IFORM 0x004 +#define BT848_IFORM_HACTIVE (1<<7) +#define BT848_IFORM_MUXSEL (3<<5) +#define BT848_IFORM_MUX0 (2<<5) +#define BT848_IFORM_MUX1 (3<<5) +#define BT848_IFORM_MUX2 (1<<5) +#define BT848_IFORM_XTSEL (3<<3) +#define BT848_IFORM_XT0 (1<<3) +#define BT848_IFORM_XT1 (2<<3) +#define BT848_IFORM_XTAUTO (3<<3) +#define BT848_IFORM_XTBOTH (3<<3) +#define BT848_IFORM_NTSC 1 +#define BT848_IFORM_NTSC_J 2 +#define BT848_IFORM_PAL_BDGHI 3 +#define BT848_IFORM_PAL_M 4 +#define BT848_IFORM_PAL_N 5 +#define BT848_IFORM_SECAM 6 +#define BT848_IFORM_PAL_NC 7 +#define BT848_IFORM_AUTO 0 +#define BT848_IFORM_NORM 7 + +#define BT848_TDEC 0x008 +#define BT848_TDEC_DEC_FIELD (1<<7) +#define BT848_TDEC_FLDALIGN (1<<6) +#define BT848_TDEC_DEC_RAT (0x1f) + +#define BT848_E_CROP 0x00C +#define BT848_O_CROP 0x08C + +#define BT848_E_VDELAY_LO 0x010 +#define BT848_O_VDELAY_LO 0x090 + +#define BT848_E_VACTIVE_LO 0x014 +#define BT848_O_VACTIVE_LO 0x094 + +#define BT848_E_HDELAY_LO 0x018 +#define BT848_O_HDELAY_LO 0x098 + +#define BT848_E_HACTIVE_LO 0x01C +#define BT848_O_HACTIVE_LO 0x09C + +#define BT848_E_HSCALE_HI 0x020 +#define BT848_O_HSCALE_HI 0x0A0 + +#define BT848_E_HSCALE_LO 0x024 +#define BT848_O_HSCALE_LO 0x0A4 + +#define BT848_BRIGHT 0x028 + +#define BT848_E_CONTROL 0x02C +#define BT848_O_CONTROL 0x0AC +#define BT848_CONTROL_LNOTCH (1<<7) +#define BT848_CONTROL_COMP (1<<6) +#define BT848_CONTROL_LDEC (1<<5) +#define BT848_CONTROL_CBSENSE (1<<4) +#define BT848_CONTROL_CON_MSB (1<<2) +#define BT848_CONTROL_SAT_U_MSB (1<<1) +#define BT848_CONTROL_SAT_V_MSB (1<<0) + +#define BT848_CONTRAST_LO 0x030 +#define BT848_SAT_U_LO 0x034 +#define BT848_SAT_V_LO 0x038 +#define BT848_HUE 0x03C + +#define BT848_E_SCLOOP 0x040 +#define BT848_O_SCLOOP 0x0C0 +#define BT848_SCLOOP_CAGC (1<<6) +#define BT848_SCLOOP_CKILL (1<<5) +#define BT848_SCLOOP_HFILT_AUTO (0<<3) +#define BT848_SCLOOP_HFILT_CIF (1<<3) +#define BT848_SCLOOP_HFILT_QCIF (2<<3) +#define BT848_SCLOOP_HFILT_ICON (3<<3) + +#define BT848_SCLOOP_PEAK (1<<7) +#define BT848_SCLOOP_HFILT_MINP (1<<3) +#define BT848_SCLOOP_HFILT_MEDP (2<<3) +#define BT848_SCLOOP_HFILT_MAXP (3<<3) + + +#define BT848_OFORM 0x048 +#define BT848_OFORM_RANGE (1<<7) +#define BT848_OFORM_CORE0 (0<<5) +#define BT848_OFORM_CORE8 (1<<5) +#define BT848_OFORM_CORE16 (2<<5) +#define BT848_OFORM_CORE32 (3<<5) + +#define BT848_E_VSCALE_HI 0x04C +#define BT848_O_VSCALE_HI 0x0CC +#define BT848_VSCALE_YCOMB (1<<7) +#define BT848_VSCALE_COMB (1<<6) +#define BT848_VSCALE_INT (1<<5) +#define BT848_VSCALE_HI 15 + +#define BT848_E_VSCALE_LO 0x050 +#define BT848_O_VSCALE_LO 0x0D0 +#define BT848_TEST 0x054 +#define BT848_ADELAY 0x060 +#define BT848_BDELAY 0x064 + +#define BT848_ADC 0x068 +#define BT848_ADC_RESERVED (2<<6) +#define BT848_ADC_SYNC_T (1<<5) +#define BT848_ADC_AGC_EN (1<<4) +#define BT848_ADC_CLK_SLEEP (1<<3) +#define BT848_ADC_Y_SLEEP (1<<2) +#define BT848_ADC_C_SLEEP (1<<1) +#define BT848_ADC_CRUSH (1<<0) + +#define BT848_WC_UP 0x044 +#define BT848_WC_DOWN 0x078 + +#define BT848_E_VTC 0x06C +#define BT848_O_VTC 0x0EC +#define BT848_VTC_HSFMT (1<<7) +#define BT848_VTC_VFILT_2TAP 0 +#define BT848_VTC_VFILT_3TAP 1 +#define BT848_VTC_VFILT_4TAP 2 +#define BT848_VTC_VFILT_5TAP 3 + +#define BT848_SRESET 0x07C + +#define BT848_COLOR_FMT 0x0D4 +#define BT848_COLOR_FMT_O_RGB32 (0<<4) +#define BT848_COLOR_FMT_O_RGB24 (1<<4) +#define BT848_COLOR_FMT_O_RGB16 (2<<4) +#define BT848_COLOR_FMT_O_RGB15 (3<<4) +#define BT848_COLOR_FMT_O_YUY2 (4<<4) +#define BT848_COLOR_FMT_O_BtYUV (5<<4) +#define BT848_COLOR_FMT_O_Y8 (6<<4) +#define BT848_COLOR_FMT_O_RGB8 (7<<4) +#define BT848_COLOR_FMT_O_YCrCb422 (8<<4) +#define BT848_COLOR_FMT_O_YCrCb411 (9<<4) +#define BT848_COLOR_FMT_O_RAW (14<<4) +#define BT848_COLOR_FMT_E_RGB32 0 +#define BT848_COLOR_FMT_E_RGB24 1 +#define BT848_COLOR_FMT_E_RGB16 2 +#define BT848_COLOR_FMT_E_RGB15 3 +#define BT848_COLOR_FMT_E_YUY2 4 +#define BT848_COLOR_FMT_E_BtYUV 5 +#define BT848_COLOR_FMT_E_Y8 6 +#define BT848_COLOR_FMT_E_RGB8 7 +#define BT848_COLOR_FMT_E_YCrCb422 8 +#define BT848_COLOR_FMT_E_YCrCb411 9 +#define BT848_COLOR_FMT_E_RAW 14 + +#define BT848_COLOR_FMT_RGB32 0x00 +#define BT848_COLOR_FMT_RGB24 0x11 +#define BT848_COLOR_FMT_RGB16 0x22 +#define BT848_COLOR_FMT_RGB15 0x33 +#define BT848_COLOR_FMT_YUY2 0x44 +#define BT848_COLOR_FMT_BtYUV 0x55 +#define BT848_COLOR_FMT_Y8 0x66 +#define BT848_COLOR_FMT_RGB8 0x77 +#define BT848_COLOR_FMT_YCrCb422 0x88 +#define BT848_COLOR_FMT_YCrCb411 0x99 +#define BT848_COLOR_FMT_RAW 0xee + +#define BT848_VTOTAL_LO 0xB0 +#define BT848_VTOTAL_HI 0xB4 + +#define BT848_COLOR_CTL 0x0D8 +#define BT848_COLOR_CTL_EXT_FRMRATE (1<<7) +#define BT848_COLOR_CTL_COLOR_BARS (1<<6) +#define BT848_COLOR_CTL_RGB_DED (1<<5) +#define BT848_COLOR_CTL_GAMMA (1<<4) +#define BT848_COLOR_CTL_WSWAP_ODD (1<<3) +#define BT848_COLOR_CTL_WSWAP_EVEN (1<<2) +#define BT848_COLOR_CTL_BSWAP_ODD (1<<1) +#define BT848_COLOR_CTL_BSWAP_EVEN (1<<0) + +#define BT848_CAP_CTL 0x0DC +#define BT848_CAP_CTL_DITH_FRAME (1<<4) +#define BT848_CAP_CTL_CAPTURE_VBI_ODD (1<<3) +#define BT848_CAP_CTL_CAPTURE_VBI_EVEN (1<<2) +#define BT848_CAP_CTL_CAPTURE_ODD (1<<1) +#define BT848_CAP_CTL_CAPTURE_EVEN (1<<0) + +#define BT848_VBI_PACK_SIZE 0x0E0 + +#define BT848_VBI_PACK_DEL 0x0E4 +#define BT848_VBI_PACK_DEL_VBI_HDELAY 0xfc +#define BT848_VBI_PACK_DEL_EXT_FRAME 2 +#define BT848_VBI_PACK_DEL_VBI_PKT_HI 1 + + +#define BT848_INT_STAT 0x100 +#define BT848_INT_MASK 0x104 + +#define BT848_INT_ETBF (1<<23) + +#define BT848_INT_RISCS (0xf<<28) +#define BT848_INT_RISC_EN (1<<27) +#define BT848_INT_RACK (1<<25) +#define BT848_INT_FIELD (1<<24) +#define BT848_INT_SCERR (1<<19) +#define BT848_INT_OCERR (1<<18) +#define BT848_INT_PABORT (1<<17) +#define BT848_INT_RIPERR (1<<16) +#define BT848_INT_PPERR (1<<15) +#define BT848_INT_FDSR (1<<14) +#define BT848_INT_FTRGT (1<<13) +#define BT848_INT_FBUS (1<<12) +#define BT848_INT_RISCI (1<<11) +#define BT848_INT_GPINT (1<<9) +#define BT848_INT_I2CDONE (1<<8) +#define BT848_INT_VPRES (1<<5) +#define BT848_INT_HLOCK (1<<4) +#define BT848_INT_OFLOW (1<<3) +#define BT848_INT_HSYNC (1<<2) +#define BT848_INT_VSYNC (1<<1) +#define BT848_INT_FMTCHG (1<<0) + + +#define BT848_GPIO_DMA_CTL 0x10C +#define BT848_GPIO_DMA_CTL_GPINTC (1<<15) +#define BT848_GPIO_DMA_CTL_GPINTI (1<<14) +#define BT848_GPIO_DMA_CTL_GPWEC (1<<13) +#define BT848_GPIO_DMA_CTL_GPIOMODE (3<<11) +#define BT848_GPIO_DMA_CTL_GPCLKMODE (1<<10) +#define BT848_GPIO_DMA_CTL_PLTP23_4 (0<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_8 (1<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_16 (2<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_32 (3<<6) +#define BT848_GPIO_DMA_CTL_PLTP1_4 (0<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_8 (1<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_16 (2<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_32 (3<<4) +#define BT848_GPIO_DMA_CTL_PKTP_4 (0<<2) +#define BT848_GPIO_DMA_CTL_PKTP_8 (1<<2) +#define BT848_GPIO_DMA_CTL_PKTP_16 (2<<2) +#define BT848_GPIO_DMA_CTL_PKTP_32 (3<<2) +#define BT848_GPIO_DMA_CTL_RISC_ENABLE (1<<1) +#define BT848_GPIO_DMA_CTL_FIFO_ENABLE (1<<0) + +#define BT848_I2C 0x110 +#define BT878_I2C_MODE (1<<7) +#define BT878_I2C_RATE (1<<6) +#define BT878_I2C_NOSTOP (1<<5) +#define BT878_I2C_NOSTART (1<<4) +#define BT848_I2C_DIV (0xf<<4) +#define BT848_I2C_SYNC (1<<3) +#define BT848_I2C_W3B (1<<2) +#define BT848_I2C_SCL (1<<1) +#define BT848_I2C_SDA (1<<0) + +#define BT848_RISC_STRT_ADD 0x114 +#define BT848_GPIO_OUT_EN 0x118 +#define BT848_GPIO_REG_INP 0x11C +#define BT848_RISC_COUNT 0x120 +#define BT848_GPIO_DATA 0x200 + + +/* Bt848 RISC commands */ + +/* only for the SYNC RISC command */ +#define BT848_FIFO_STATUS_FM1 0x06 +#define BT848_FIFO_STATUS_FM3 0x0e +#define BT848_FIFO_STATUS_SOL 0x02 +#define BT848_FIFO_STATUS_EOL4 0x01 +#define BT848_FIFO_STATUS_EOL3 0x0d +#define BT848_FIFO_STATUS_EOL2 0x09 +#define BT848_FIFO_STATUS_EOL1 0x05 +#define BT848_FIFO_STATUS_VRE 0x04 +#define BT848_FIFO_STATUS_VRO 0x0c +#define BT848_FIFO_STATUS_PXV 0x00 + +#define BT848_RISC_RESYNC (1<<15) + +/* WRITE and SKIP */ +/* disable which bytes of each DWORD */ +#define BT848_RISC_BYTE0 (1U<<12) +#define BT848_RISC_BYTE1 (1U<<13) +#define BT848_RISC_BYTE2 (1U<<14) +#define BT848_RISC_BYTE3 (1U<<15) +#define BT848_RISC_BYTE_ALL (0x0fU<<12) +#define BT848_RISC_BYTE_NONE 0 +/* cause RISCI */ +#define BT848_RISC_IRQ (1U<<24) +/* RISC command is last one in this line */ +#define BT848_RISC_EOL (1U<<26) +/* RISC command is first one in this line */ +#define BT848_RISC_SOL (1U<<27) + +#define BT848_RISC_WRITE (0x01U<<28) +#define BT848_RISC_SKIP (0x02U<<28) +#define BT848_RISC_WRITEC (0x05U<<28) +#define BT848_RISC_JUMP (0x07U<<28) +#define BT848_RISC_SYNC (0x08U<<28) + +#define BT848_RISC_WRITE123 (0x09U<<28) +#define BT848_RISC_SKIP123 (0x0aU<<28) +#define BT848_RISC_WRITE1S23 (0x0bU<<28) + + +/* Bt848A and higher only !! */ +#define BT848_TGLB 0x080 +#define BT848_TGCTRL 0x084 +#define BT848_FCAP 0x0E8 +#define BT848_PLL_F_LO 0x0F0 +#define BT848_PLL_F_HI 0x0F4 + +#define BT848_PLL_XCI 0x0F8 +#define BT848_PLL_X (1<<7) +#define BT848_PLL_C (1<<6) + +#define BT848_DVSIF 0x0FC + +/* Bt878 register */ + +#define BT878_DEVCTRL 0x40 +#define BT878_EN_TBFX 0x02 +#define BT878_EN_VSFX 0x04 + +#endif --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.18/bttvp.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.18/bttvp.h @@ -0,0 +1,413 @@ +/* + + bttv - Bt848 frame grabber driver + + bttv's *private* header file -- nobody other than bttv itself + should ever include this file. + + (c) 2000-2002 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _BTTVP_H_ +#define _BTTVP_H_ + +#include +#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,16) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include "bt848.h" +#include "bttv.h" +#include "btcx-risc.h" + +#ifdef __KERNEL__ + +#define FORMAT_FLAGS_DITHER 0x01 +#define FORMAT_FLAGS_PACKED 0x02 +#define FORMAT_FLAGS_PLANAR 0x04 +#define FORMAT_FLAGS_RAW 0x08 +#define FORMAT_FLAGS_CrCb 0x10 + +#define RISC_SLOT_O_VBI 4 +#define RISC_SLOT_O_FIELD 6 +#define RISC_SLOT_E_VBI 10 +#define RISC_SLOT_E_FIELD 12 +#define RISC_SLOT_LOOP 14 + +#define RESOURCE_OVERLAY 1 +#define RESOURCE_VIDEO 2 +#define RESOURCE_VBI 4 + +#define RAW_LINES 640 +#define RAW_BPL 1024 + +#define UNSET (-1U) + +#define clamp(x, low, high) min (max (low, x), high) + +/* ---------------------------------------------------------- */ + +struct bttv_tvnorm { + int v4l2_id; + char *name; + u32 Fsc; + u16 swidth, sheight; /* scaled standard width, height */ + u16 totalwidth; + u8 adelay, bdelay, iform; + u32 scaledtwidth; + u16 hdelayx1, hactivex1; + u16 vdelay; + u8 vbipack; + u16 vtotal; + int sram; + /* ITU-R frame line number of the first VBI line we can + capture, of the first and second field. */ + u16 vbistart[2]; +}; +extern const struct bttv_tvnorm bttv_tvnorms[]; + +struct bttv_format { + char *name; + int palette; /* video4linux 1 */ + int fourcc; /* video4linux 2 */ + int btformat; /* BT848_COLOR_FMT_* */ + int btswap; /* BT848_COLOR_CTL_* */ + int depth; /* bit/pixel */ + int flags; + int hshift,vshift; /* for planar modes */ +}; + +/* ---------------------------------------------------------- */ + +struct bttv_geometry { + u8 vtc,crop,comb; + u16 width,hscale,hdelay; + u16 sheight,vscale,vdelay,vtotal; +}; + +struct bttv_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* bttv specific */ + const struct bttv_format *fmt; + int tvnorm; + int btformat; + int btswap; + struct bttv_geometry geo; + struct btcx_riscmem top; + struct btcx_riscmem bottom; +}; + +struct bttv_buffer_set { + struct bttv_buffer *top; /* top field buffer */ + struct bttv_buffer *bottom; /* bottom field buffer */ + unsigned int top_irq; + unsigned int frame_irq; +}; + +struct bttv_overlay { + int tvnorm; + struct v4l2_rect w; + enum v4l2_field field; + struct v4l2_clip *clips; + int nclips; + int setup_ok; +}; + +struct bttv_fh { + struct bttv *btv; + int resources; +#ifdef VIDIOC_G_PRIORITY + enum v4l2_priority prio; +#endif + enum v4l2_buf_type type; + + /* video capture */ + struct videobuf_queue cap; + const struct bttv_format *fmt; + int width; + int height; + + /* current settings */ + const struct bttv_format *ovfmt; + struct bttv_overlay ov; + + /* video overlay */ + struct videobuf_queue vbi; + int lines; +}; + +/* ---------------------------------------------------------- */ +/* bttv-risc.c */ + +/* risc code generators - capture */ +int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int offset, unsigned int bpl, + unsigned int pitch, unsigned int lines); + +/* control dma register + risc main loop */ +void bttv_set_dma(struct bttv *btv, int override); +int bttv_risc_init_main(struct bttv *btv); +int bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, + int irqflags); + +/* capture buffer handling */ +int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf); +int bttv_buffer_activate_video(struct bttv *btv, + struct bttv_buffer_set *set); +int bttv_buffer_activate_vbi(struct bttv *btv, + struct bttv_buffer *vbi); +void bttv_dma_free(struct videobuf_queue *q, struct bttv *btv, + struct bttv_buffer *buf); + +/* overlay handling */ +int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov, + const struct bttv_format *fmt, + struct bttv_buffer *buf); + + +/* ---------------------------------------------------------- */ +/* bttv-vbi.c */ + +void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f); +void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f); +void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines); + +extern struct videobuf_queue_ops bttv_vbi_qops; + +/* ---------------------------------------------------------- */ +/* bttv-gpio.c */ + + +extern struct bus_type bttv_sub_bus_type; +int bttv_sub_add_device(struct bttv_core *core, char *name); +int bttv_sub_del_devices(struct bttv_core *core); + + +/* ---------------------------------------------------------- */ +/* bttv-driver.c */ + +/* insmod options */ +extern unsigned int bttv_verbose; +extern unsigned int bttv_debug; +extern unsigned int bttv_gpio; +extern void bttv_gpio_tracking(struct bttv *btv, char *comment); +extern int init_bttv_i2c(struct bttv *btv); +extern int fini_bttv_i2c(struct bttv *btv); + +#define bttv_printk if (bttv_verbose) printk +#define dprintk if (bttv_debug >= 1) printk +#define d2printk if (bttv_debug >= 2) printk + +#define BTTV_MAX_FBUF 0x208000 +#define VBIBUF_SIZE (2048*VBI_MAXLINES*2) +#define BTTV_TIMEOUT (HZ/2) /* 0.5 seconds */ +#define BTTV_FREE_IDLE (HZ) /* one second */ + + +struct bttv_pll_info { + unsigned int pll_ifreq; /* PLL input frequency */ + unsigned int pll_ofreq; /* PLL output frequency */ + unsigned int pll_crystal; /* Crystal used for input */ + unsigned int pll_current; /* Currently programmed ofreq */ +}; + +/* for gpio-connected remote control */ +struct bttv_input { + struct input_dev *dev; + struct ir_input_state ir; + char name[32]; + char phys[32]; + u32 mask_keycode; + u32 mask_keydown; +}; + +struct bttv_suspend_state { + u32 gpio_enable; + u32 gpio_data; + int disabled; + int loop_irq; + struct bttv_buffer_set video; + struct bttv_buffer *vbi; +}; + +struct bttv { + struct bttv_core c; + + /* pci device config */ + unsigned short id; + unsigned char revision; + unsigned char __iomem *bt848_mmio; /* pointer to mmio */ + + /* card configuration info */ + unsigned int cardid; /* pci subsystem id (bt878 based ones) */ + unsigned int tuner_type; /* tuner chip type */ + unsigned int tda9887_conf; + unsigned int svhs; + struct bttv_pll_info pll; + int triton1; + int gpioirq; + int (*custom_irq)(struct bttv *btv); + + int use_i2c_hw; + + /* old gpio interface */ + wait_queue_head_t gpioq; + int shutdown; + void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); + + /* new gpio interface */ + spinlock_t gpio_lock; + + /* i2c layer */ + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + int i2c_state, i2c_rc; + int i2c_done; + wait_queue_head_t i2c_queue; + struct i2c_client *i2c_msp34xx_client; + struct i2c_client *i2c_tvaudio_client; + + /* video4linux (1) */ + struct video_device *video_dev; + struct video_device *radio_dev; + struct video_device *vbi_dev; + + /* infrared remote */ + int has_remote; + struct bttv_ir *remote; + + /* locking */ + spinlock_t s_lock; + struct mutex lock; + int resources; + struct mutex reslock; +#ifdef VIDIOC_G_PRIORITY + struct v4l2_prio_state prio; +#endif + + /* video state */ + unsigned int input; + unsigned int audio; + unsigned int mute; + unsigned long freq; + int tvnorm,hue,contrast,bright,saturation; + struct v4l2_framebuffer fbuf; + unsigned int field_count; + + /* various options */ + int opt_combfilter; + int opt_lumafilter; + int opt_automute; + int opt_chroma_agc; + int opt_adc_crush; + int opt_vcr_hack; + int opt_whitecrush_upper; + int opt_whitecrush_lower; + int opt_uv_ratio; + int opt_full_luma_range; + int opt_coring; + + /* radio data/state */ + int has_radio; + int radio_user; + + /* miro/pinnacle + Aimslab VHX + philips matchbox (tea5757 radio tuner) support */ + int has_matchbox; + int mbox_we; + int mbox_data; + int mbox_clk; + int mbox_most; + int mbox_mask; + + /* ISA stuff (Terratec Active Radio Upgrade) */ + int mbox_ior; + int mbox_iow; + int mbox_csel; + + /* risc memory management data + - must acquire s_lock before changing these + - only the irq handler is supported to touch top + bottom + vcurr */ + struct btcx_riscmem main; + struct bttv_buffer *screen; /* overlay */ + struct list_head capture; /* video capture queue */ + struct list_head vcapture; /* vbi capture queue */ + struct bttv_buffer_set curr; /* active buffers */ + struct bttv_buffer *cvbi; /* active vbi buffer */ + int loop_irq; + int new_input; + + unsigned long cap_ctl; + unsigned long dma_on; + struct timer_list timeout; + struct bttv_suspend_state state; + + /* stats */ + unsigned int errors; + unsigned int framedrop; + unsigned int irq_total; + unsigned int irq_me; + + unsigned int users; + struct bttv_fh init; +}; + +/* our devices */ +#define BTTV_MAX 16 +extern unsigned int bttv_num; +extern struct bttv bttvs[BTTV_MAX]; + +/* private ioctls */ +#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int) +#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int) + +#endif + +#define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr)) +#define btread(adr) readl(btv->bt848_mmio+(adr)) + +#define btand(dat,adr) btwrite((dat) & btread(adr), adr) +#define btor(dat,adr) btwrite((dat) | btread(adr), adr) +#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) + +#endif /* _BTTVP_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.20/bttv.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.20/bttv.h @@ -0,0 +1,389 @@ +/* + * + * bttv - Bt848 frame grabber driver + * + * card ID's and external interfaces of the bttv driver + * basically stuff needed by other drivers (i2c, lirc, ...) + * and is supported not to change much over time. + * + * Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) + * (c) 1999,2000 Gerd Knorr + * + */ + +#ifndef _BTTV_H_ +#define _BTTV_H_ + +#include +#include +#include +#include +#include + +/* ---------------------------------------------------------- */ +/* exported by bttv-cards.c */ + +#define BTTV_BOARD_UNKNOWN 0x00 +#define BTTV_BOARD_MIRO 0x01 +#define BTTV_BOARD_HAUPPAUGE 0x02 +#define BTTV_BOARD_STB 0x03 +#define BTTV_BOARD_INTEL 0x04 +#define BTTV_BOARD_DIAMOND 0x05 +#define BTTV_BOARD_AVERMEDIA 0x06 +#define BTTV_BOARD_MATRIX_VISION 0x07 +#define BTTV_BOARD_FLYVIDEO 0x08 +#define BTTV_BOARD_TURBOTV 0x09 +#define BTTV_BOARD_HAUPPAUGE878 0x0a +#define BTTV_BOARD_MIROPRO 0x0b +#define BTTV_BOARD_ADSTECH_TV 0x0c +#define BTTV_BOARD_AVERMEDIA98 0x0d +#define BTTV_BOARD_VHX 0x0e +#define BTTV_BOARD_ZOLTRIX 0x0f +#define BTTV_BOARD_PIXVIEWPLAYTV 0x10 +#define BTTV_BOARD_WINVIEW_601 0x11 +#define BTTV_BOARD_AVEC_INTERCAP 0x12 +#define BTTV_BOARD_LIFE_FLYKIT 0x13 +#define BTTV_BOARD_CEI_RAFFLES 0x14 +#define BTTV_BOARD_CONFERENCETV 0x15 +#define BTTV_BOARD_PHOEBE_TVMAS 0x16 +#define BTTV_BOARD_MODTEC_205 0x17 +#define BTTV_BOARD_MAGICTVIEW061 0x18 +#define BTTV_BOARD_VOBIS_BOOSTAR 0x19 +#define BTTV_BOARD_HAUPPAUG_WCAM 0x1a +#define BTTV_BOARD_MAXI 0x1b +#define BTTV_BOARD_TERRATV 0x1c +#define BTTV_BOARD_PXC200 0x1d +#define BTTV_BOARD_FLYVIDEO_98 0x1e +#define BTTV_BOARD_IPROTV 0x1f +#define BTTV_BOARD_INTEL_C_S_PCI 0x20 +#define BTTV_BOARD_TERRATVALUE 0x21 +#define BTTV_BOARD_WINFAST2000 0x22 +#define BTTV_BOARD_CHRONOS_VS2 0x23 +#define BTTV_BOARD_TYPHOON_TVIEW 0x24 +#define BTTV_BOARD_PXELVWPLTVPRO 0x25 +#define BTTV_BOARD_MAGICTVIEW063 0x26 +#define BTTV_BOARD_PINNACLE 0x27 +#define BTTV_BOARD_STB2 0x28 +#define BTTV_BOARD_AVPHONE98 0x29 +#define BTTV_BOARD_PV951 0x2a +#define BTTV_BOARD_ONAIR_TV 0x2b +#define BTTV_BOARD_SIGMA_TVII_FM 0x2c +#define BTTV_BOARD_MATRIX_VISION2 0x2d +#define BTTV_BOARD_ZOLTRIX_GENIE 0x2e +#define BTTV_BOARD_TERRATVRADIO 0x2f +#define BTTV_BOARD_DYNALINK 0x30 +#define BTTV_BOARD_GVBCTV3PCI 0x31 +#define BTTV_BOARD_PXELVWPLTVPAK 0x32 +#define BTTV_BOARD_EAGLE 0x33 +#define BTTV_BOARD_PINNACLEPRO 0x34 +#define BTTV_BOARD_TVIEW_RDS_FM 0x35 +#define BTTV_BOARD_LIFETEC_9415 0x36 +#define BTTV_BOARD_BESTBUY_EASYTV 0x37 +#define BTTV_BOARD_FLYVIDEO_98FM 0x38 +#define BTTV_BOARD_GRANDTEC 0x39 +#define BTTV_BOARD_ASKEY_CPH060 0x3a +#define BTTV_BOARD_ASKEY_CPH03X 0x3b +#define BTTV_BOARD_MM100PCTV 0x3c +#define BTTV_BOARD_GMV1 0x3d +#define BTTV_BOARD_BESTBUY_EASYTV2 0x3e +#define BTTV_BOARD_ATI_TVWONDER 0x3f +#define BTTV_BOARD_ATI_TVWONDERVE 0x40 +#define BTTV_BOARD_FLYVIDEO2000 0x41 +#define BTTV_BOARD_TERRATVALUER 0x42 +#define BTTV_BOARD_GVBCTV4PCI 0x43 +#define BTTV_BOARD_VOODOOTV_FM 0x44 +#define BTTV_BOARD_AIMMS 0x45 +#define BTTV_BOARD_PV_BT878P_PLUS 0x46 +#define BTTV_BOARD_FLYVIDEO98EZ 0x47 +#define BTTV_BOARD_PV_BT878P_9B 0x48 +#define BTTV_BOARD_SENSORAY311 0x49 +#define BTTV_BOARD_RV605 0x4a +#define BTTV_BOARD_POWERCLR_MTV878 0x4b +#define BTTV_BOARD_WINDVR 0x4c +#define BTTV_BOARD_GRANDTEC_MULTI 0x4d +#define BTTV_BOARD_KWORLD 0x4e +#define BTTV_BOARD_DSP_TCVIDEO 0x4f +#define BTTV_BOARD_HAUPPAUGEPVR 0x50 +#define BTTV_BOARD_GVBCTV5PCI 0x51 +#define BTTV_BOARD_OSPREY1x0 0x52 +#define BTTV_BOARD_OSPREY1x0_848 0x53 +#define BTTV_BOARD_OSPREY101_848 0x54 +#define BTTV_BOARD_OSPREY1x1 0x55 +#define BTTV_BOARD_OSPREY1x1_SVID 0x56 +#define BTTV_BOARD_OSPREY2xx 0x57 +#define BTTV_BOARD_OSPREY2x0_SVID 0x58 +#define BTTV_BOARD_OSPREY2x0 0x59 +#define BTTV_BOARD_OSPREY500 0x5a +#define BTTV_BOARD_OSPREY540 0x5b +#define BTTV_BOARD_OSPREY2000 0x5c +#define BTTV_BOARD_IDS_EAGLE 0x5d +#define BTTV_BOARD_PINNACLESAT 0x5e +#define BTTV_BOARD_FORMAC_PROTV 0x5f +#define BTTV_BOARD_MACHTV 0x60 +#define BTTV_BOARD_EURESYS_PICOLO 0x61 +#define BTTV_BOARD_PV150 0x62 +#define BTTV_BOARD_AD_TVK503 0x63 +#define BTTV_BOARD_HERCULES_SM_TV 0x64 +#define BTTV_BOARD_PACETV 0x65 +#define BTTV_BOARD_IVC200 0x66 +#define BTTV_BOARD_XGUARD 0x67 +#define BTTV_BOARD_NEBULA_DIGITV 0x68 +#define BTTV_BOARD_PV143 0x69 +#define BTTV_BOARD_VD009X1_MINIDIN 0x6a +#define BTTV_BOARD_VD009X1_COMBI 0x6b +#define BTTV_BOARD_VD009_MINIDIN 0x6c +#define BTTV_BOARD_VD009_COMBI 0x6d +#define BTTV_BOARD_IVC100 0x6e +#define BTTV_BOARD_IVC120 0x6f +#define BTTV_BOARD_PC_HDTV 0x70 +#define BTTV_BOARD_TWINHAN_DST 0x71 +#define BTTV_BOARD_WINFASTVC100 0x72 +#define BTTV_BOARD_TEV560 0x73 +#define BTTV_BOARD_SIMUS_GVC1100 0x74 +#define BTTV_BOARD_NGSTV_PLUS 0x75 +#define BTTV_BOARD_LMLBT4 0x76 +#define BTTV_BOARD_TEKRAM_M205 0x77 +#define BTTV_BOARD_CONTVFMI 0x78 +#define BTTV_BOARD_PICOLO_TETRA_CHIP 0x79 +#define BTTV_BOARD_SPIRIT_TV 0x7a +#define BTTV_BOARD_AVDVBT_771 0x7b +#define BTTV_BOARD_AVDVBT_761 0x7c +#define BTTV_BOARD_MATRIX_VISIONSQ 0x7d +#define BTTV_BOARD_MATRIX_VISIONSLC 0x7e +#define BTTV_BOARD_APAC_VIEWCOMP 0x7f +#define BTTV_BOARD_DVICO_DVBT_LITE 0x80 +#define BTTV_BOARD_VGEAR_MYVCD 0x81 +#define BTTV_BOARD_SUPER_TV 0x82 +#define BTTV_BOARD_TIBET_CS16 0x83 +#define BTTV_BOARD_KODICOM_4400R 0x84 +#define BTTV_BOARD_KODICOM_4400R_SL 0x85 +#define BTTV_BOARD_ADLINK_RTV24 0x86 +#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 +#define BTTV_BOARD_ACORP_Y878F 0x88 +#define BTTV_BOARD_CONCEPTRONIC_CTVFMI2 0x89 +#define BTTV_BOARD_PV_BT878P_2E 0x8a +#define BTTV_BOARD_PV_M4900 0x8b +#define BTTV_BOARD_OSPREY440 0x8c +#define BTTV_BOARD_ASOUND_SKYEYE 0x8d +#define BTTV_BOARD_SABRENT_TVFM 0x8e +#define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f +#define BTTV_BOARD_MACHTV_MAGICTV 0x90 + +/* more card-specific defines */ +#define PT2254_L_CHANNEL 0x10 +#define PT2254_R_CHANNEL 0x08 +#define PT2254_DBS_IN_2 0x400 +#define PT2254_DBS_IN_10 0x20000 +#define WINVIEW_PT2254_CLK 0x40 +#define WINVIEW_PT2254_DATA 0x20 +#define WINVIEW_PT2254_STROBE 0x80 + +/* digital_mode */ +#define DIGITAL_MODE_VIDEO 1 +#define DIGITAL_MODE_CAMERA 2 + +struct bttv_core { + /* device structs */ + struct pci_dev *pci; + struct i2c_adapter i2c_adap; + struct list_head subs; /* struct bttv_sub_device */ + + /* device config */ + unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */ + unsigned int type; /* card type (pointer into tvcards[]) */ + char name[8]; /* dev name */ +}; + +struct bttv; + + +struct bttv_ir { + struct input_dev *dev; + struct ir_input_state ir; + char name[32]; + char phys[32]; + + /* Usual gpio signalling */ + + u32 mask_keycode; + u32 mask_keydown; + u32 mask_keyup; + u32 polling; + u32 last_gpio; + struct work_struct work; + struct timer_list timer; + + /* RC5 gpio */ + u32 rc5_gpio; + struct timer_list timer_end; /* timer_end for code completion */ + struct timer_list timer_keyup; /* timer_end for key release */ + u32 last_rc5; /* last good rc5 code */ + u32 last_bit; /* last raw bit seen */ + u32 code; /* raw code under construction */ + struct timeval base_time; /* time of last seen code */ + int active; /* building raw code */ +}; + +struct tvcard +{ + char *name; + unsigned int video_inputs; + unsigned int audio_inputs; + unsigned int tuner; + unsigned int svhs; + unsigned int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO + u32 gpiomask; + u32 muxsel[16]; + u32 gpiomux[4]; /* Tuner, Radio, external, internal */ + u32 gpiomute; /* GPIO mute setting */ + u32 gpiomask2; /* GPIO MUX mask */ + + /* i2c audio flags */ + unsigned int no_msp34xx:1; + unsigned int no_tda9875:1; + unsigned int no_tda7432:1; + unsigned int needs_tvaudio:1; + unsigned int msp34xx_alt:1; + + /* flag: video pci function is unused */ + unsigned int no_video:1; + unsigned int has_dvb:1; + unsigned int has_remote:1; + unsigned int no_gpioirq:1; + + /* other settings */ + unsigned int pll; +#define PLL_NONE 0 +#define PLL_28 1 +#define PLL_35 2 + + unsigned int tuner_type; + unsigned int tuner_addr; + unsigned int radio_addr; + + unsigned int has_radio; + void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); + void (*muxsel_hook)(struct bttv *btv, unsigned int input); +}; + +extern struct tvcard bttv_tvcards[]; + +/* identification / initialization of the card */ +extern void bttv_idcard(struct bttv *btv); +extern void bttv_init_card1(struct bttv *btv); +extern void bttv_init_card2(struct bttv *btv); + +/* card-specific funtions */ +extern void tea5757_set_freq(struct bttv *btv, unsigned short freq); +extern void bttv_tda9880_setnorm(struct bttv *btv, int norm); + +/* extra tweaks for some chipsets */ +extern void bttv_check_chipset(void); +extern int bttv_handle_chipset(struct bttv *btv); + +/* ---------------------------------------------------------- */ +/* exported by bttv-if.c */ + +/* this obsolete -- please use the sysfs-based + interface below for new code */ + +/* returns card type + card ID (for bt878-based ones) + for possible values see lines below beginning with #define BTTV_BOARD_UNKNOWN + returns negative value if error occurred +*/ +extern int bttv_get_cardinfo(unsigned int card, int *type, + unsigned int *cardid); +extern struct pci_dev* bttv_get_pcidev(unsigned int card); + +/* obsolete, use bttv_get_cardinfo instead */ +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 occurred +*/ +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 occurred +*/ +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 occurred +*/ +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 occurred or queue is not available + WARNING: because there is no buffer for GPIO data, one MUST + process data ASAP +*/ +extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card); + +/* call i2c clients +*/ +extern void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg); + + + +/* ---------------------------------------------------------- */ +/* sysfs/driver-moded based gpio access interface */ + + +struct bttv_sub_device { + struct device dev; + struct bttv_core *core; + struct list_head list; +}; +#define to_bttv_sub_dev(x) container_of((x), struct bttv_sub_device, dev) + +struct bttv_sub_driver { + struct device_driver drv; + char wanted[BUS_ID_SIZE]; + int (*probe)(struct bttv_sub_device *sub); + void (*remove)(struct bttv_sub_device *sub); +}; +#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) + +int bttv_sub_register(struct bttv_sub_driver *drv, char *wanted); +int bttv_sub_unregister(struct bttv_sub_driver *drv); + +/* gpio access functions */ +void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits); +u32 bttv_gpio_read(struct bttv_core *core); +void bttv_gpio_write(struct bttv_core *core, u32 value); +void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits); + +#define gpio_inout(mask,bits) bttv_gpio_inout(&btv->c, mask, bits) +#define gpio_read() bttv_gpio_read(&btv->c) +#define gpio_write(value) bttv_gpio_write(&btv->c, value) +#define gpio_bits(mask,bits) bttv_gpio_bits(&btv->c, mask, bits) + + +/* ---------------------------------------------------------- */ +/* i2c */ + +extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg); +extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for); +extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, + unsigned char b2, int both); +extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr); + +extern int bttv_input_init(struct bttv *dev); +extern void bttv_input_fini(struct bttv *dev); +extern void bttv_input_irq(struct bttv *dev); + +#endif /* _BTTV_H_ */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.20/btcx-risc.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.20/btcx-risc.h @@ -0,0 +1,34 @@ +/* + */ +struct btcx_riscmem { + unsigned int size; + u32 *cpu; + u32 *jmp; + dma_addr_t dma; +}; + +struct btcx_skiplist { + int start; + int end; +}; + +int btcx_riscmem_alloc(struct pci_dev *pci, + struct btcx_riscmem *risc, + unsigned int size); +void btcx_riscmem_free(struct pci_dev *pci, + struct btcx_riscmem *risc); + +int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, + struct v4l2_clip *clips, unsigned int n); +int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, + unsigned int n, int mask); +void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips); +void btcx_calc_skips(int line, int width, unsigned int *maxy, + struct btcx_skiplist *skips, unsigned int *nskips, + const struct v4l2_clip *clips, unsigned int nclips); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.20/bt848.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.20/bt848.h @@ -0,0 +1,366 @@ +/* + bt848.h - Bt848 register offsets + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _BT848_H_ +#define _BT848_H_ + +#ifndef PCI_VENDOR_ID_BROOKTREE +#define PCI_VENDOR_ID_BROOKTREE 0x109e +#endif +#ifndef PCI_DEVICE_ID_BT848 +#define PCI_DEVICE_ID_BT848 0x350 +#endif +#ifndef PCI_DEVICE_ID_BT849 +#define PCI_DEVICE_ID_BT849 0x351 +#endif +#ifndef PCI_DEVICE_ID_BT878 +#define PCI_DEVICE_ID_BT878 0x36e +#endif +#ifndef PCI_DEVICE_ID_BT879 +#define PCI_DEVICE_ID_BT879 0x36f +#endif + + +/* Brooktree 848 registers */ + +#define BT848_DSTATUS 0x000 +#define BT848_DSTATUS_PRES (1<<7) +#define BT848_DSTATUS_HLOC (1<<6) +#define BT848_DSTATUS_FIELD (1<<5) +#define BT848_DSTATUS_NUML (1<<4) +#define BT848_DSTATUS_CSEL (1<<3) +#define BT848_DSTATUS_PLOCK (1<<2) +#define BT848_DSTATUS_LOF (1<<1) +#define BT848_DSTATUS_COF (1<<0) + +#define BT848_IFORM 0x004 +#define BT848_IFORM_HACTIVE (1<<7) +#define BT848_IFORM_MUXSEL (3<<5) +#define BT848_IFORM_MUX0 (2<<5) +#define BT848_IFORM_MUX1 (3<<5) +#define BT848_IFORM_MUX2 (1<<5) +#define BT848_IFORM_XTSEL (3<<3) +#define BT848_IFORM_XT0 (1<<3) +#define BT848_IFORM_XT1 (2<<3) +#define BT848_IFORM_XTAUTO (3<<3) +#define BT848_IFORM_XTBOTH (3<<3) +#define BT848_IFORM_NTSC 1 +#define BT848_IFORM_NTSC_J 2 +#define BT848_IFORM_PAL_BDGHI 3 +#define BT848_IFORM_PAL_M 4 +#define BT848_IFORM_PAL_N 5 +#define BT848_IFORM_SECAM 6 +#define BT848_IFORM_PAL_NC 7 +#define BT848_IFORM_AUTO 0 +#define BT848_IFORM_NORM 7 + +#define BT848_TDEC 0x008 +#define BT848_TDEC_DEC_FIELD (1<<7) +#define BT848_TDEC_FLDALIGN (1<<6) +#define BT848_TDEC_DEC_RAT (0x1f) + +#define BT848_E_CROP 0x00C +#define BT848_O_CROP 0x08C + +#define BT848_E_VDELAY_LO 0x010 +#define BT848_O_VDELAY_LO 0x090 + +#define BT848_E_VACTIVE_LO 0x014 +#define BT848_O_VACTIVE_LO 0x094 + +#define BT848_E_HDELAY_LO 0x018 +#define BT848_O_HDELAY_LO 0x098 + +#define BT848_E_HACTIVE_LO 0x01C +#define BT848_O_HACTIVE_LO 0x09C + +#define BT848_E_HSCALE_HI 0x020 +#define BT848_O_HSCALE_HI 0x0A0 + +#define BT848_E_HSCALE_LO 0x024 +#define BT848_O_HSCALE_LO 0x0A4 + +#define BT848_BRIGHT 0x028 + +#define BT848_E_CONTROL 0x02C +#define BT848_O_CONTROL 0x0AC +#define BT848_CONTROL_LNOTCH (1<<7) +#define BT848_CONTROL_COMP (1<<6) +#define BT848_CONTROL_LDEC (1<<5) +#define BT848_CONTROL_CBSENSE (1<<4) +#define BT848_CONTROL_CON_MSB (1<<2) +#define BT848_CONTROL_SAT_U_MSB (1<<1) +#define BT848_CONTROL_SAT_V_MSB (1<<0) + +#define BT848_CONTRAST_LO 0x030 +#define BT848_SAT_U_LO 0x034 +#define BT848_SAT_V_LO 0x038 +#define BT848_HUE 0x03C + +#define BT848_E_SCLOOP 0x040 +#define BT848_O_SCLOOP 0x0C0 +#define BT848_SCLOOP_CAGC (1<<6) +#define BT848_SCLOOP_CKILL (1<<5) +#define BT848_SCLOOP_HFILT_AUTO (0<<3) +#define BT848_SCLOOP_HFILT_CIF (1<<3) +#define BT848_SCLOOP_HFILT_QCIF (2<<3) +#define BT848_SCLOOP_HFILT_ICON (3<<3) + +#define BT848_SCLOOP_PEAK (1<<7) +#define BT848_SCLOOP_HFILT_MINP (1<<3) +#define BT848_SCLOOP_HFILT_MEDP (2<<3) +#define BT848_SCLOOP_HFILT_MAXP (3<<3) + + +#define BT848_OFORM 0x048 +#define BT848_OFORM_RANGE (1<<7) +#define BT848_OFORM_CORE0 (0<<5) +#define BT848_OFORM_CORE8 (1<<5) +#define BT848_OFORM_CORE16 (2<<5) +#define BT848_OFORM_CORE32 (3<<5) + +#define BT848_E_VSCALE_HI 0x04C +#define BT848_O_VSCALE_HI 0x0CC +#define BT848_VSCALE_YCOMB (1<<7) +#define BT848_VSCALE_COMB (1<<6) +#define BT848_VSCALE_INT (1<<5) +#define BT848_VSCALE_HI 15 + +#define BT848_E_VSCALE_LO 0x050 +#define BT848_O_VSCALE_LO 0x0D0 +#define BT848_TEST 0x054 +#define BT848_ADELAY 0x060 +#define BT848_BDELAY 0x064 + +#define BT848_ADC 0x068 +#define BT848_ADC_RESERVED (2<<6) +#define BT848_ADC_SYNC_T (1<<5) +#define BT848_ADC_AGC_EN (1<<4) +#define BT848_ADC_CLK_SLEEP (1<<3) +#define BT848_ADC_Y_SLEEP (1<<2) +#define BT848_ADC_C_SLEEP (1<<1) +#define BT848_ADC_CRUSH (1<<0) + +#define BT848_WC_UP 0x044 +#define BT848_WC_DOWN 0x078 + +#define BT848_E_VTC 0x06C +#define BT848_O_VTC 0x0EC +#define BT848_VTC_HSFMT (1<<7) +#define BT848_VTC_VFILT_2TAP 0 +#define BT848_VTC_VFILT_3TAP 1 +#define BT848_VTC_VFILT_4TAP 2 +#define BT848_VTC_VFILT_5TAP 3 + +#define BT848_SRESET 0x07C + +#define BT848_COLOR_FMT 0x0D4 +#define BT848_COLOR_FMT_O_RGB32 (0<<4) +#define BT848_COLOR_FMT_O_RGB24 (1<<4) +#define BT848_COLOR_FMT_O_RGB16 (2<<4) +#define BT848_COLOR_FMT_O_RGB15 (3<<4) +#define BT848_COLOR_FMT_O_YUY2 (4<<4) +#define BT848_COLOR_FMT_O_BtYUV (5<<4) +#define BT848_COLOR_FMT_O_Y8 (6<<4) +#define BT848_COLOR_FMT_O_RGB8 (7<<4) +#define BT848_COLOR_FMT_O_YCrCb422 (8<<4) +#define BT848_COLOR_FMT_O_YCrCb411 (9<<4) +#define BT848_COLOR_FMT_O_RAW (14<<4) +#define BT848_COLOR_FMT_E_RGB32 0 +#define BT848_COLOR_FMT_E_RGB24 1 +#define BT848_COLOR_FMT_E_RGB16 2 +#define BT848_COLOR_FMT_E_RGB15 3 +#define BT848_COLOR_FMT_E_YUY2 4 +#define BT848_COLOR_FMT_E_BtYUV 5 +#define BT848_COLOR_FMT_E_Y8 6 +#define BT848_COLOR_FMT_E_RGB8 7 +#define BT848_COLOR_FMT_E_YCrCb422 8 +#define BT848_COLOR_FMT_E_YCrCb411 9 +#define BT848_COLOR_FMT_E_RAW 14 + +#define BT848_COLOR_FMT_RGB32 0x00 +#define BT848_COLOR_FMT_RGB24 0x11 +#define BT848_COLOR_FMT_RGB16 0x22 +#define BT848_COLOR_FMT_RGB15 0x33 +#define BT848_COLOR_FMT_YUY2 0x44 +#define BT848_COLOR_FMT_BtYUV 0x55 +#define BT848_COLOR_FMT_Y8 0x66 +#define BT848_COLOR_FMT_RGB8 0x77 +#define BT848_COLOR_FMT_YCrCb422 0x88 +#define BT848_COLOR_FMT_YCrCb411 0x99 +#define BT848_COLOR_FMT_RAW 0xee + +#define BT848_VTOTAL_LO 0xB0 +#define BT848_VTOTAL_HI 0xB4 + +#define BT848_COLOR_CTL 0x0D8 +#define BT848_COLOR_CTL_EXT_FRMRATE (1<<7) +#define BT848_COLOR_CTL_COLOR_BARS (1<<6) +#define BT848_COLOR_CTL_RGB_DED (1<<5) +#define BT848_COLOR_CTL_GAMMA (1<<4) +#define BT848_COLOR_CTL_WSWAP_ODD (1<<3) +#define BT848_COLOR_CTL_WSWAP_EVEN (1<<2) +#define BT848_COLOR_CTL_BSWAP_ODD (1<<1) +#define BT848_COLOR_CTL_BSWAP_EVEN (1<<0) + +#define BT848_CAP_CTL 0x0DC +#define BT848_CAP_CTL_DITH_FRAME (1<<4) +#define BT848_CAP_CTL_CAPTURE_VBI_ODD (1<<3) +#define BT848_CAP_CTL_CAPTURE_VBI_EVEN (1<<2) +#define BT848_CAP_CTL_CAPTURE_ODD (1<<1) +#define BT848_CAP_CTL_CAPTURE_EVEN (1<<0) + +#define BT848_VBI_PACK_SIZE 0x0E0 + +#define BT848_VBI_PACK_DEL 0x0E4 +#define BT848_VBI_PACK_DEL_VBI_HDELAY 0xfc +#define BT848_VBI_PACK_DEL_EXT_FRAME 2 +#define BT848_VBI_PACK_DEL_VBI_PKT_HI 1 + + +#define BT848_INT_STAT 0x100 +#define BT848_INT_MASK 0x104 + +#define BT848_INT_ETBF (1<<23) + +#define BT848_INT_RISCS (0xf<<28) +#define BT848_INT_RISC_EN (1<<27) +#define BT848_INT_RACK (1<<25) +#define BT848_INT_FIELD (1<<24) +#define BT848_INT_SCERR (1<<19) +#define BT848_INT_OCERR (1<<18) +#define BT848_INT_PABORT (1<<17) +#define BT848_INT_RIPERR (1<<16) +#define BT848_INT_PPERR (1<<15) +#define BT848_INT_FDSR (1<<14) +#define BT848_INT_FTRGT (1<<13) +#define BT848_INT_FBUS (1<<12) +#define BT848_INT_RISCI (1<<11) +#define BT848_INT_GPINT (1<<9) +#define BT848_INT_I2CDONE (1<<8) +#define BT848_INT_VPRES (1<<5) +#define BT848_INT_HLOCK (1<<4) +#define BT848_INT_OFLOW (1<<3) +#define BT848_INT_HSYNC (1<<2) +#define BT848_INT_VSYNC (1<<1) +#define BT848_INT_FMTCHG (1<<0) + + +#define BT848_GPIO_DMA_CTL 0x10C +#define BT848_GPIO_DMA_CTL_GPINTC (1<<15) +#define BT848_GPIO_DMA_CTL_GPINTI (1<<14) +#define BT848_GPIO_DMA_CTL_GPWEC (1<<13) +#define BT848_GPIO_DMA_CTL_GPIOMODE (3<<11) +#define BT848_GPIO_DMA_CTL_GPCLKMODE (1<<10) +#define BT848_GPIO_DMA_CTL_PLTP23_4 (0<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_8 (1<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_16 (2<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_32 (3<<6) +#define BT848_GPIO_DMA_CTL_PLTP1_4 (0<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_8 (1<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_16 (2<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_32 (3<<4) +#define BT848_GPIO_DMA_CTL_PKTP_4 (0<<2) +#define BT848_GPIO_DMA_CTL_PKTP_8 (1<<2) +#define BT848_GPIO_DMA_CTL_PKTP_16 (2<<2) +#define BT848_GPIO_DMA_CTL_PKTP_32 (3<<2) +#define BT848_GPIO_DMA_CTL_RISC_ENABLE (1<<1) +#define BT848_GPIO_DMA_CTL_FIFO_ENABLE (1<<0) + +#define BT848_I2C 0x110 +#define BT878_I2C_MODE (1<<7) +#define BT878_I2C_RATE (1<<6) +#define BT878_I2C_NOSTOP (1<<5) +#define BT878_I2C_NOSTART (1<<4) +#define BT848_I2C_DIV (0xf<<4) +#define BT848_I2C_SYNC (1<<3) +#define BT848_I2C_W3B (1<<2) +#define BT848_I2C_SCL (1<<1) +#define BT848_I2C_SDA (1<<0) + +#define BT848_RISC_STRT_ADD 0x114 +#define BT848_GPIO_OUT_EN 0x118 +#define BT848_GPIO_REG_INP 0x11C +#define BT848_RISC_COUNT 0x120 +#define BT848_GPIO_DATA 0x200 + + +/* Bt848 RISC commands */ + +/* only for the SYNC RISC command */ +#define BT848_FIFO_STATUS_FM1 0x06 +#define BT848_FIFO_STATUS_FM3 0x0e +#define BT848_FIFO_STATUS_SOL 0x02 +#define BT848_FIFO_STATUS_EOL4 0x01 +#define BT848_FIFO_STATUS_EOL3 0x0d +#define BT848_FIFO_STATUS_EOL2 0x09 +#define BT848_FIFO_STATUS_EOL1 0x05 +#define BT848_FIFO_STATUS_VRE 0x04 +#define BT848_FIFO_STATUS_VRO 0x0c +#define BT848_FIFO_STATUS_PXV 0x00 + +#define BT848_RISC_RESYNC (1<<15) + +/* WRITE and SKIP */ +/* disable which bytes of each DWORD */ +#define BT848_RISC_BYTE0 (1U<<12) +#define BT848_RISC_BYTE1 (1U<<13) +#define BT848_RISC_BYTE2 (1U<<14) +#define BT848_RISC_BYTE3 (1U<<15) +#define BT848_RISC_BYTE_ALL (0x0fU<<12) +#define BT848_RISC_BYTE_NONE 0 +/* cause RISCI */ +#define BT848_RISC_IRQ (1U<<24) +/* RISC command is last one in this line */ +#define BT848_RISC_EOL (1U<<26) +/* RISC command is first one in this line */ +#define BT848_RISC_SOL (1U<<27) + +#define BT848_RISC_WRITE (0x01U<<28) +#define BT848_RISC_SKIP (0x02U<<28) +#define BT848_RISC_WRITEC (0x05U<<28) +#define BT848_RISC_JUMP (0x07U<<28) +#define BT848_RISC_SYNC (0x08U<<28) + +#define BT848_RISC_WRITE123 (0x09U<<28) +#define BT848_RISC_SKIP123 (0x0aU<<28) +#define BT848_RISC_WRITE1S23 (0x0bU<<28) + + +/* Bt848A and higher only !! */ +#define BT848_TGLB 0x080 +#define BT848_TGCTRL 0x084 +#define BT848_FCAP 0x0E8 +#define BT848_PLL_F_LO 0x0F0 +#define BT848_PLL_F_HI 0x0F4 + +#define BT848_PLL_XCI 0x0F8 +#define BT848_PLL_X (1<<7) +#define BT848_PLL_C (1<<6) + +#define BT848_DVSIF 0x0FC + +/* Bt878 register */ + +#define BT878_DEVCTRL 0x40 +#define BT878_EN_TBFX 0x02 +#define BT878_EN_VSFX 0x04 + +#endif --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.20/bttvp.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.20/bttvp.h @@ -0,0 +1,413 @@ +/* + + bttv - Bt848 frame grabber driver + + bttv's *private* header file -- nobody other than bttv itself + should ever include this file. + + (c) 2000-2002 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _BTTVP_H_ +#define _BTTVP_H_ + +#include +#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,16) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include "bt848.h" +#include "bttv.h" +#include "btcx-risc.h" + +#ifdef __KERNEL__ + +#define FORMAT_FLAGS_DITHER 0x01 +#define FORMAT_FLAGS_PACKED 0x02 +#define FORMAT_FLAGS_PLANAR 0x04 +#define FORMAT_FLAGS_RAW 0x08 +#define FORMAT_FLAGS_CrCb 0x10 + +#define RISC_SLOT_O_VBI 4 +#define RISC_SLOT_O_FIELD 6 +#define RISC_SLOT_E_VBI 10 +#define RISC_SLOT_E_FIELD 12 +#define RISC_SLOT_LOOP 14 + +#define RESOURCE_OVERLAY 1 +#define RESOURCE_VIDEO 2 +#define RESOURCE_VBI 4 + +#define RAW_LINES 640 +#define RAW_BPL 1024 + +#define UNSET (-1U) + +#define clamp(x, low, high) min (max (low, x), high) + +/* ---------------------------------------------------------- */ + +struct bttv_tvnorm { + int v4l2_id; + char *name; + u32 Fsc; + u16 swidth, sheight; /* scaled standard width, height */ + u16 totalwidth; + u8 adelay, bdelay, iform; + u32 scaledtwidth; + u16 hdelayx1, hactivex1; + u16 vdelay; + u8 vbipack; + u16 vtotal; + int sram; + /* ITU-R frame line number of the first VBI line we can + capture, of the first and second field. */ + u16 vbistart[2]; +}; +extern const struct bttv_tvnorm bttv_tvnorms[]; + +struct bttv_format { + char *name; + int palette; /* video4linux 1 */ + int fourcc; /* video4linux 2 */ + int btformat; /* BT848_COLOR_FMT_* */ + int btswap; /* BT848_COLOR_CTL_* */ + int depth; /* bit/pixel */ + int flags; + int hshift,vshift; /* for planar modes */ +}; + +/* ---------------------------------------------------------- */ + +struct bttv_geometry { + u8 vtc,crop,comb; + u16 width,hscale,hdelay; + u16 sheight,vscale,vdelay,vtotal; +}; + +struct bttv_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* bttv specific */ + const struct bttv_format *fmt; + int tvnorm; + int btformat; + int btswap; + struct bttv_geometry geo; + struct btcx_riscmem top; + struct btcx_riscmem bottom; +}; + +struct bttv_buffer_set { + struct bttv_buffer *top; /* top field buffer */ + struct bttv_buffer *bottom; /* bottom field buffer */ + unsigned int top_irq; + unsigned int frame_irq; +}; + +struct bttv_overlay { + int tvnorm; + struct v4l2_rect w; + enum v4l2_field field; + struct v4l2_clip *clips; + int nclips; + int setup_ok; +}; + +struct bttv_fh { + struct bttv *btv; + int resources; +#ifdef VIDIOC_G_PRIORITY + enum v4l2_priority prio; +#endif + enum v4l2_buf_type type; + + /* video capture */ + struct videobuf_queue cap; + const struct bttv_format *fmt; + int width; + int height; + + /* current settings */ + const struct bttv_format *ovfmt; + struct bttv_overlay ov; + + /* video overlay */ + struct videobuf_queue vbi; + int lines; +}; + +/* ---------------------------------------------------------- */ +/* bttv-risc.c */ + +/* risc code generators - capture */ +int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int offset, unsigned int bpl, + unsigned int pitch, unsigned int lines); + +/* control dma register + risc main loop */ +void bttv_set_dma(struct bttv *btv, int override); +int bttv_risc_init_main(struct bttv *btv); +int bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, + int irqflags); + +/* capture buffer handling */ +int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf); +int bttv_buffer_activate_video(struct bttv *btv, + struct bttv_buffer_set *set); +int bttv_buffer_activate_vbi(struct bttv *btv, + struct bttv_buffer *vbi); +void bttv_dma_free(struct videobuf_queue *q, struct bttv *btv, + struct bttv_buffer *buf); + +/* overlay handling */ +int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov, + const struct bttv_format *fmt, + struct bttv_buffer *buf); + + +/* ---------------------------------------------------------- */ +/* bttv-vbi.c */ + +void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f); +void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f); +void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines); + +extern struct videobuf_queue_ops bttv_vbi_qops; + +/* ---------------------------------------------------------- */ +/* bttv-gpio.c */ + + +extern struct bus_type bttv_sub_bus_type; +int bttv_sub_add_device(struct bttv_core *core, char *name); +int bttv_sub_del_devices(struct bttv_core *core); + + +/* ---------------------------------------------------------- */ +/* bttv-driver.c */ + +/* insmod options */ +extern unsigned int bttv_verbose; +extern unsigned int bttv_debug; +extern unsigned int bttv_gpio; +extern void bttv_gpio_tracking(struct bttv *btv, char *comment); +extern int init_bttv_i2c(struct bttv *btv); +extern int fini_bttv_i2c(struct bttv *btv); + +#define bttv_printk if (bttv_verbose) printk +#define dprintk if (bttv_debug >= 1) printk +#define d2printk if (bttv_debug >= 2) printk + +#define BTTV_MAX_FBUF 0x208000 +#define VBIBUF_SIZE (2048*VBI_MAXLINES*2) +#define BTTV_TIMEOUT (HZ/2) /* 0.5 seconds */ +#define BTTV_FREE_IDLE (HZ) /* one second */ + + +struct bttv_pll_info { + unsigned int pll_ifreq; /* PLL input frequency */ + unsigned int pll_ofreq; /* PLL output frequency */ + unsigned int pll_crystal; /* Crystal used for input */ + unsigned int pll_current; /* Currently programmed ofreq */ +}; + +/* for gpio-connected remote control */ +struct bttv_input { + struct input_dev *dev; + struct ir_input_state ir; + char name[32]; + char phys[32]; + u32 mask_keycode; + u32 mask_keydown; +}; + +struct bttv_suspend_state { + u32 gpio_enable; + u32 gpio_data; + int disabled; + int loop_irq; + struct bttv_buffer_set video; + struct bttv_buffer *vbi; +}; + +struct bttv { + struct bttv_core c; + + /* pci device config */ + unsigned short id; + unsigned char revision; + unsigned char __iomem *bt848_mmio; /* pointer to mmio */ + + /* card configuration info */ + unsigned int cardid; /* pci subsystem id (bt878 based ones) */ + unsigned int tuner_type; /* tuner chip type */ + unsigned int tda9887_conf; + unsigned int svhs; + struct bttv_pll_info pll; + int triton1; + int gpioirq; + int (*custom_irq)(struct bttv *btv); + + int use_i2c_hw; + + /* old gpio interface */ + wait_queue_head_t gpioq; + int shutdown; + void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); + + /* new gpio interface */ + spinlock_t gpio_lock; + + /* i2c layer */ + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + int i2c_state, i2c_rc; + int i2c_done; + wait_queue_head_t i2c_queue; + struct i2c_client *i2c_msp34xx_client; + struct i2c_client *i2c_tvaudio_client; + + /* video4linux (1) */ + struct video_device *video_dev; + struct video_device *radio_dev; + struct video_device *vbi_dev; + + /* infrared remote */ + int has_remote; + struct bttv_ir *remote; + + /* locking */ + spinlock_t s_lock; + struct mutex lock; + int resources; + struct mutex reslock; +#ifdef VIDIOC_G_PRIORITY + struct v4l2_prio_state prio; +#endif + + /* video state */ + unsigned int input; + unsigned int audio; + unsigned int mute; + unsigned long freq; + int tvnorm,hue,contrast,bright,saturation; + struct v4l2_framebuffer fbuf; + unsigned int field_count; + + /* various options */ + int opt_combfilter; + int opt_lumafilter; + int opt_automute; + int opt_chroma_agc; + int opt_adc_crush; + int opt_vcr_hack; + int opt_whitecrush_upper; + int opt_whitecrush_lower; + int opt_uv_ratio; + int opt_full_luma_range; + int opt_coring; + + /* radio data/state */ + int has_radio; + int radio_user; + + /* miro/pinnacle + Aimslab VHX + philips matchbox (tea5757 radio tuner) support */ + int has_matchbox; + int mbox_we; + int mbox_data; + int mbox_clk; + int mbox_most; + int mbox_mask; + + /* ISA stuff (Terratec Active Radio Upgrade) */ + int mbox_ior; + int mbox_iow; + int mbox_csel; + + /* risc memory management data + - must acquire s_lock before changing these + - only the irq handler is supported to touch top + bottom + vcurr */ + struct btcx_riscmem main; + struct bttv_buffer *screen; /* overlay */ + struct list_head capture; /* video capture queue */ + struct list_head vcapture; /* vbi capture queue */ + struct bttv_buffer_set curr; /* active buffers */ + struct bttv_buffer *cvbi; /* active vbi buffer */ + int loop_irq; + int new_input; + + unsigned long cap_ctl; + unsigned long dma_on; + struct timer_list timeout; + struct bttv_suspend_state state; + + /* stats */ + unsigned int errors; + unsigned int framedrop; + unsigned int irq_total; + unsigned int irq_me; + + unsigned int users; + struct bttv_fh init; +}; + +/* our devices */ +#define BTTV_MAX 16 +extern unsigned int bttv_num; +extern struct bttv bttvs[BTTV_MAX]; + +/* private ioctls */ +#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int) +#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int) + +#endif + +#define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr)) +#define btread(adr) readl(btv->bt848_mmio+(adr)) + +#define btand(dat,adr) btwrite((dat) & btread(adr), adr) +#define btor(dat,adr) btwrite((dat) | btread(adr), adr) +#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) + +#endif /* _BTTVP_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.16/bttv.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.16/bttv.h @@ -0,0 +1,407 @@ +/* + * + * bttv - Bt848 frame grabber driver + * + * card ID's and external interfaces of the bttv driver + * basically stuff needed by other drivers (i2c, lirc, ...) + * and is supported not to change much over time. + * + * Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) + * (c) 1999,2000 Gerd Knorr + * + */ + +#ifndef _BTTV_H_ +#define _BTTV_H_ + +#include +#include +#include +#include + +/* ---------------------------------------------------------- */ +/* exported by bttv-cards.c */ + +#define BTTV_BOARD_UNKNOWN 0x00 +#define BTTV_BOARD_MIRO 0x01 +#define BTTV_BOARD_HAUPPAUGE 0x02 +#define BTTV_BOARD_STB 0x03 +#define BTTV_BOARD_INTEL 0x04 +#define BTTV_BOARD_DIAMOND 0x05 +#define BTTV_BOARD_AVERMEDIA 0x06 +#define BTTV_BOARD_MATRIX_VISION 0x07 +#define BTTV_BOARD_FLYVIDEO 0x08 +#define BTTV_BOARD_TURBOTV 0x09 +#define BTTV_BOARD_HAUPPAUGE878 0x0a +#define BTTV_BOARD_MIROPRO 0x0b +#define BTTV_BOARD_ADSTECH_TV 0x0c +#define BTTV_BOARD_AVERMEDIA98 0x0d +#define BTTV_BOARD_VHX 0x0e +#define BTTV_BOARD_ZOLTRIX 0x0f +#define BTTV_BOARD_PIXVIEWPLAYTV 0x10 +#define BTTV_BOARD_WINVIEW_601 0x11 +#define BTTV_BOARD_AVEC_INTERCAP 0x12 +#define BTTV_BOARD_LIFE_FLYKIT 0x13 +#define BTTV_BOARD_CEI_RAFFLES 0x14 +#define BTTV_BOARD_CONFERENCETV 0x15 +#define BTTV_BOARD_PHOEBE_TVMAS 0x16 +#define BTTV_BOARD_MODTEC_205 0x17 +#define BTTV_BOARD_MAGICTVIEW061 0x18 +#define BTTV_BOARD_VOBIS_BOOSTAR 0x19 +#define BTTV_BOARD_HAUPPAUG_WCAM 0x1a +#define BTTV_BOARD_MAXI 0x1b +#define BTTV_BOARD_TERRATV 0x1c +#define BTTV_BOARD_PXC200 0x1d +#define BTTV_BOARD_FLYVIDEO_98 0x1e +#define BTTV_BOARD_IPROTV 0x1f +#define BTTV_BOARD_INTEL_C_S_PCI 0x20 +#define BTTV_BOARD_TERRATVALUE 0x21 +#define BTTV_BOARD_WINFAST2000 0x22 +#define BTTV_BOARD_CHRONOS_VS2 0x23 +#define BTTV_BOARD_TYPHOON_TVIEW 0x24 +#define BTTV_BOARD_PXELVWPLTVPRO 0x25 +#define BTTV_BOARD_MAGICTVIEW063 0x26 +#define BTTV_BOARD_PINNACLE 0x27 +#define BTTV_BOARD_STB2 0x28 +#define BTTV_BOARD_AVPHONE98 0x29 +#define BTTV_BOARD_PV951 0x2a +#define BTTV_BOARD_ONAIR_TV 0x2b +#define BTTV_BOARD_SIGMA_TVII_FM 0x2c +#define BTTV_BOARD_MATRIX_VISION2 0x2d +#define BTTV_BOARD_ZOLTRIX_GENIE 0x2e +#define BTTV_BOARD_TERRATVRADIO 0x2f +#define BTTV_BOARD_DYNALINK 0x30 +#define BTTV_BOARD_GVBCTV3PCI 0x31 +#define BTTV_BOARD_PXELVWPLTVPAK 0x32 +#define BTTV_BOARD_EAGLE 0x33 +#define BTTV_BOARD_PINNACLEPRO 0x34 +#define BTTV_BOARD_TVIEW_RDS_FM 0x35 +#define BTTV_BOARD_LIFETEC_9415 0x36 +#define BTTV_BOARD_BESTBUY_EASYTV 0x37 +#define BTTV_BOARD_FLYVIDEO_98FM 0x38 +#define BTTV_BOARD_GRANDTEC 0x39 +#define BTTV_BOARD_ASKEY_CPH060 0x3a +#define BTTV_BOARD_ASKEY_CPH03X 0x3b +#define BTTV_BOARD_MM100PCTV 0x3c +#define BTTV_BOARD_GMV1 0x3d +#define BTTV_BOARD_BESTBUY_EASYTV2 0x3e +#define BTTV_BOARD_ATI_TVWONDER 0x3f +#define BTTV_BOARD_ATI_TVWONDERVE 0x40 +#define BTTV_BOARD_FLYVIDEO2000 0x41 +#define BTTV_BOARD_TERRATVALUER 0x42 +#define BTTV_BOARD_GVBCTV4PCI 0x43 +#define BTTV_BOARD_VOODOOTV_FM 0x44 +#define BTTV_BOARD_AIMMS 0x45 +#define BTTV_BOARD_PV_BT878P_PLUS 0x46 +#define BTTV_BOARD_FLYVIDEO98EZ 0x47 +#define BTTV_BOARD_PV_BT878P_9B 0x48 +#define BTTV_BOARD_SENSORAY311 0x49 +#define BTTV_BOARD_RV605 0x4a +#define BTTV_BOARD_POWERCLR_MTV878 0x4b +#define BTTV_BOARD_WINDVR 0x4c +#define BTTV_BOARD_GRANDTEC_MULTI 0x4d +#define BTTV_BOARD_KWORLD 0x4e +#define BTTV_BOARD_DSP_TCVIDEO 0x4f +#define BTTV_BOARD_HAUPPAUGEPVR 0x50 +#define BTTV_BOARD_GVBCTV5PCI 0x51 +#define BTTV_BOARD_OSPREY1x0 0x52 +#define BTTV_BOARD_OSPREY1x0_848 0x53 +#define BTTV_BOARD_OSPREY101_848 0x54 +#define BTTV_BOARD_OSPREY1x1 0x55 +#define BTTV_BOARD_OSPREY1x1_SVID 0x56 +#define BTTV_BOARD_OSPREY2xx 0x57 +#define BTTV_BOARD_OSPREY2x0_SVID 0x58 +#define BTTV_BOARD_OSPREY2x0 0x59 +#define BTTV_BOARD_OSPREY500 0x5a +#define BTTV_BOARD_OSPREY540 0x5b +#define BTTV_BOARD_OSPREY2000 0x5c +#define BTTV_BOARD_IDS_EAGLE 0x5d +#define BTTV_BOARD_PINNACLESAT 0x5e +#define BTTV_BOARD_FORMAC_PROTV 0x5f +#define BTTV_BOARD_MACHTV 0x60 +#define BTTV_BOARD_EURESYS_PICOLO 0x61 +#define BTTV_BOARD_PV150 0x62 +#define BTTV_BOARD_AD_TVK503 0x63 +#define BTTV_BOARD_HERCULES_SM_TV 0x64 +#define BTTV_BOARD_PACETV 0x65 +#define BTTV_BOARD_IVC200 0x66 +#define BTTV_BOARD_XGUARD 0x67 +#define BTTV_BOARD_NEBULA_DIGITV 0x68 +#define BTTV_BOARD_PV143 0x69 +#define BTTV_BOARD_VD009X1_MINIDIN 0x6a +#define BTTV_BOARD_VD009X1_COMBI 0x6b +#define BTTV_BOARD_VD009_MINIDIN 0x6c +#define BTTV_BOARD_VD009_COMBI 0x6d +#define BTTV_BOARD_IVC100 0x6e +#define BTTV_BOARD_IVC120 0x6f +#define BTTV_BOARD_PC_HDTV 0x70 +#define BTTV_BOARD_TWINHAN_DST 0x71 +#define BTTV_BOARD_WINFASTVC100 0x72 +#define BTTV_BOARD_TEV560 0x73 +#define BTTV_BOARD_SIMUS_GVC1100 0x74 +#define BTTV_BOARD_NGSTV_PLUS 0x75 +#define BTTV_BOARD_LMLBT4 0x76 +#define BTTV_BOARD_TEKRAM_M205 0x77 +#define BTTV_BOARD_CONTVFMI 0x78 +#define BTTV_BOARD_PICOLO_TETRA_CHIP 0x79 +#define BTTV_BOARD_SPIRIT_TV 0x7a +#define BTTV_BOARD_AVDVBT_771 0x7b +#define BTTV_BOARD_AVDVBT_761 0x7c +#define BTTV_BOARD_MATRIX_VISIONSQ 0x7d +#define BTTV_BOARD_MATRIX_VISIONSLC 0x7e +#define BTTV_BOARD_APAC_VIEWCOMP 0x7f +#define BTTV_BOARD_DVICO_DVBT_LITE 0x80 +#define BTTV_BOARD_VGEAR_MYVCD 0x81 +#define BTTV_BOARD_SUPER_TV 0x82 +#define BTTV_BOARD_TIBET_CS16 0x83 +#define BTTV_BOARD_KODICOM_4400R 0x84 +#define BTTV_BOARD_KODICOM_4400R_SL 0x85 +#define BTTV_BOARD_ADLINK_RTV24 0x86 +#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 +#define BTTV_BOARD_ACORP_Y878F 0x88 +#define BTTV_BOARD_CONCEPTRONIC_CTVFMI2 0x89 +#define BTTV_BOARD_PV_BT878P_2E 0x8a +#define BTTV_BOARD_PV_M4900 0x8b +#define BTTV_BOARD_OSPREY440 0x8c +#define BTTV_BOARD_ASOUND_SKYEYE 0x8d +#define BTTV_BOARD_SABRENT_TVFM 0x8e +#define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f +#define BTTV_BOARD_MACHTV_MAGICTV 0x90 + +/* i2c address list */ +#define I2C_TSA5522 0xc2 +#define I2C_TDA7432 0x8a +#define I2C_BT832_ALT1 0x88 +#define I2C_BT832_ALT2 0x8a // alternate setting +#define I2C_TDA8425 0x82 +#define I2C_TDA9840 0x84 +#define I2C_TDA9850 0xb6 /* also used by 9855,9873 */ +#define I2C_TDA9874 0xb0 /* also used by 9875 */ +#define I2C_TDA9875 0xb0 +#define I2C_HAUPEE 0xa0 +#define I2C_STBEE 0xae +#define I2C_VHX 0xc0 +#define I2C_MSP3400 0x80 +#define I2C_MSP3400_ALT 0x88 +#define I2C_TEA6300 0x80 /* also used by 6320 */ +#define I2C_DPL3518 0x84 +#define I2C_TDA9887 0x86 + +/* more card-specific defines */ +#define PT2254_L_CHANNEL 0x10 +#define PT2254_R_CHANNEL 0x08 +#define PT2254_DBS_IN_2 0x400 +#define PT2254_DBS_IN_10 0x20000 +#define WINVIEW_PT2254_CLK 0x40 +#define WINVIEW_PT2254_DATA 0x20 +#define WINVIEW_PT2254_STROBE 0x80 + +/* digital_mode */ +#define DIGITAL_MODE_VIDEO 1 +#define DIGITAL_MODE_CAMERA 2 + +struct bttv_core { + /* device structs */ + struct pci_dev *pci; + struct i2c_adapter i2c_adap; + struct list_head subs; /* struct bttv_sub_device */ + + /* device config */ + unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */ + unsigned int type; /* card type (pointer into tvcards[]) */ + char name[8]; /* dev name */ +}; + +struct bttv; + + +struct bttv_ir { + struct input_dev *dev; + struct ir_input_state ir; + char name[32]; + char phys[32]; + + /* Usual gpio signalling */ + + u32 mask_keycode; + u32 mask_keydown; + u32 mask_keyup; + u32 polling; + u32 last_gpio; + struct work_struct work; + struct timer_list timer; + + /* RC5 gpio */ + u32 rc5_gpio; + struct timer_list timer_end; /* timer_end for code completion */ + struct timer_list timer_keyup; /* timer_end for key release */ + u32 last_rc5; /* last good rc5 code */ + u32 last_bit; /* last raw bit seen */ + u32 code; /* raw code under construction */ + struct timeval base_time; /* time of last seen code */ + int active; /* building raw code */ +}; + +struct tvcard +{ + char *name; + unsigned int video_inputs; + unsigned int audio_inputs; + unsigned int tuner; + unsigned int svhs; + unsigned int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO + u32 gpiomask; + u32 muxsel[16]; + u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */ + u32 gpiomask2; /* GPIO MUX mask */ + + /* i2c audio flags */ + unsigned int no_msp34xx:1; + unsigned int no_tda9875:1; + unsigned int no_tda7432:1; + unsigned int needs_tvaudio:1; + unsigned int msp34xx_alt:1; + + /* flag: video pci function is unused */ + unsigned int no_video:1; + unsigned int has_dvb:1; + unsigned int has_remote:1; + unsigned int no_gpioirq:1; + + /* other settings */ + unsigned int pll; +#define PLL_NONE 0 +#define PLL_28 1 +#define PLL_35 2 + + unsigned int tuner_type; + unsigned int tuner_addr; + unsigned int radio_addr; + + unsigned int has_radio; + void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); + void (*muxsel_hook)(struct bttv *btv, unsigned int input); +}; + +extern struct tvcard bttv_tvcards[]; + +/* identification / initialization of the card */ +extern void bttv_idcard(struct bttv *btv); +extern void bttv_init_card1(struct bttv *btv); +extern void bttv_init_card2(struct bttv *btv); + +/* card-specific funtions */ +extern void tea5757_set_freq(struct bttv *btv, unsigned short freq); +extern void bttv_tda9880_setnorm(struct bttv *btv, int norm); + +/* extra tweaks for some chipsets */ +extern void bttv_check_chipset(void); +extern int bttv_handle_chipset(struct bttv *btv); + +/* ---------------------------------------------------------- */ +/* exported by bttv-if.c */ + +/* this obsolete -- please use the sysfs-based + interface below for new code */ + +/* returns card type + card ID (for bt878-based ones) + for possible values see lines below beginning with #define BTTV_BOARD_UNKNOWN + returns negative value if error occurred +*/ +extern int bttv_get_cardinfo(unsigned int card, int *type, + unsigned int *cardid); +extern struct pci_dev* bttv_get_pcidev(unsigned int card); + +/* obsolete, use bttv_get_cardinfo instead */ +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 occurred +*/ +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 occurred +*/ +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 occurred +*/ +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 occurred or queue is not available + WARNING: because there is no buffer for GPIO data, one MUST + process data ASAP +*/ +extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card); + +/* call i2c clients +*/ +extern void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg); + + + +/* ---------------------------------------------------------- */ +/* sysfs/driver-moded based gpio access interface */ + + +struct bttv_sub_device { + struct device dev; + struct bttv_core *core; + struct list_head list; +}; +#define to_bttv_sub_dev(x) container_of((x), struct bttv_sub_device, dev) + +struct bttv_sub_driver { + struct device_driver drv; + char wanted[BUS_ID_SIZE]; + int (*probe)(struct bttv_sub_device *sub); + void (*remove)(struct bttv_sub_device *sub); + void (*gpio_irq)(struct bttv_sub_device *sub); +}; +#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) + +int bttv_sub_register(struct bttv_sub_driver *drv, char *wanted); +int bttv_sub_unregister(struct bttv_sub_driver *drv); + +/* gpio access functions */ +void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits); +u32 bttv_gpio_read(struct bttv_core *core); +void bttv_gpio_write(struct bttv_core *core, u32 value); +void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits); + +#define gpio_inout(mask,bits) bttv_gpio_inout(&btv->c, mask, bits) +#define gpio_read() bttv_gpio_read(&btv->c) +#define gpio_write(value) bttv_gpio_write(&btv->c, value) +#define gpio_bits(mask,bits) bttv_gpio_bits(&btv->c, mask, bits) + + +/* ---------------------------------------------------------- */ +/* i2c */ + +extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg); +extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for); +extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, + unsigned char b2, int both); +extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr); + +extern int bttv_input_init(struct bttv *dev); +extern void bttv_input_fini(struct bttv *dev); +extern void bttv_input_irq(struct bttv *dev); + +#endif /* _BTTV_H_ */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.16/btcx-risc.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.16/btcx-risc.h @@ -0,0 +1,34 @@ +/* + */ +struct btcx_riscmem { + unsigned int size; + u32 *cpu; + u32 *jmp; + dma_addr_t dma; +}; + +struct btcx_skiplist { + int start; + int end; +}; + +int btcx_riscmem_alloc(struct pci_dev *pci, + struct btcx_riscmem *risc, + unsigned int size); +void btcx_riscmem_free(struct pci_dev *pci, + struct btcx_riscmem *risc); + +int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, + struct v4l2_clip *clips, unsigned int n); +int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, + unsigned int n, int mask); +void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips); +void btcx_calc_skips(int line, int width, unsigned int *maxy, + struct btcx_skiplist *skips, unsigned int *nskips, + const struct v4l2_clip *clips, unsigned int nclips); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.16/bt848.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.16/bt848.h @@ -0,0 +1,366 @@ +/* + bt848.h - Bt848 register offsets + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _BT848_H_ +#define _BT848_H_ + +#ifndef PCI_VENDOR_ID_BROOKTREE +#define PCI_VENDOR_ID_BROOKTREE 0x109e +#endif +#ifndef PCI_DEVICE_ID_BT848 +#define PCI_DEVICE_ID_BT848 0x350 +#endif +#ifndef PCI_DEVICE_ID_BT849 +#define PCI_DEVICE_ID_BT849 0x351 +#endif +#ifndef PCI_DEVICE_ID_BT878 +#define PCI_DEVICE_ID_BT878 0x36e +#endif +#ifndef PCI_DEVICE_ID_BT879 +#define PCI_DEVICE_ID_BT879 0x36f +#endif + + +/* Brooktree 848 registers */ + +#define BT848_DSTATUS 0x000 +#define BT848_DSTATUS_PRES (1<<7) +#define BT848_DSTATUS_HLOC (1<<6) +#define BT848_DSTATUS_FIELD (1<<5) +#define BT848_DSTATUS_NUML (1<<4) +#define BT848_DSTATUS_CSEL (1<<3) +#define BT848_DSTATUS_PLOCK (1<<2) +#define BT848_DSTATUS_LOF (1<<1) +#define BT848_DSTATUS_COF (1<<0) + +#define BT848_IFORM 0x004 +#define BT848_IFORM_HACTIVE (1<<7) +#define BT848_IFORM_MUXSEL (3<<5) +#define BT848_IFORM_MUX0 (2<<5) +#define BT848_IFORM_MUX1 (3<<5) +#define BT848_IFORM_MUX2 (1<<5) +#define BT848_IFORM_XTSEL (3<<3) +#define BT848_IFORM_XT0 (1<<3) +#define BT848_IFORM_XT1 (2<<3) +#define BT848_IFORM_XTAUTO (3<<3) +#define BT848_IFORM_XTBOTH (3<<3) +#define BT848_IFORM_NTSC 1 +#define BT848_IFORM_NTSC_J 2 +#define BT848_IFORM_PAL_BDGHI 3 +#define BT848_IFORM_PAL_M 4 +#define BT848_IFORM_PAL_N 5 +#define BT848_IFORM_SECAM 6 +#define BT848_IFORM_PAL_NC 7 +#define BT848_IFORM_AUTO 0 +#define BT848_IFORM_NORM 7 + +#define BT848_TDEC 0x008 +#define BT848_TDEC_DEC_FIELD (1<<7) +#define BT848_TDEC_FLDALIGN (1<<6) +#define BT848_TDEC_DEC_RAT (0x1f) + +#define BT848_E_CROP 0x00C +#define BT848_O_CROP 0x08C + +#define BT848_E_VDELAY_LO 0x010 +#define BT848_O_VDELAY_LO 0x090 + +#define BT848_E_VACTIVE_LO 0x014 +#define BT848_O_VACTIVE_LO 0x094 + +#define BT848_E_HDELAY_LO 0x018 +#define BT848_O_HDELAY_LO 0x098 + +#define BT848_E_HACTIVE_LO 0x01C +#define BT848_O_HACTIVE_LO 0x09C + +#define BT848_E_HSCALE_HI 0x020 +#define BT848_O_HSCALE_HI 0x0A0 + +#define BT848_E_HSCALE_LO 0x024 +#define BT848_O_HSCALE_LO 0x0A4 + +#define BT848_BRIGHT 0x028 + +#define BT848_E_CONTROL 0x02C +#define BT848_O_CONTROL 0x0AC +#define BT848_CONTROL_LNOTCH (1<<7) +#define BT848_CONTROL_COMP (1<<6) +#define BT848_CONTROL_LDEC (1<<5) +#define BT848_CONTROL_CBSENSE (1<<4) +#define BT848_CONTROL_CON_MSB (1<<2) +#define BT848_CONTROL_SAT_U_MSB (1<<1) +#define BT848_CONTROL_SAT_V_MSB (1<<0) + +#define BT848_CONTRAST_LO 0x030 +#define BT848_SAT_U_LO 0x034 +#define BT848_SAT_V_LO 0x038 +#define BT848_HUE 0x03C + +#define BT848_E_SCLOOP 0x040 +#define BT848_O_SCLOOP 0x0C0 +#define BT848_SCLOOP_CAGC (1<<6) +#define BT848_SCLOOP_CKILL (1<<5) +#define BT848_SCLOOP_HFILT_AUTO (0<<3) +#define BT848_SCLOOP_HFILT_CIF (1<<3) +#define BT848_SCLOOP_HFILT_QCIF (2<<3) +#define BT848_SCLOOP_HFILT_ICON (3<<3) + +#define BT848_SCLOOP_PEAK (1<<7) +#define BT848_SCLOOP_HFILT_MINP (1<<3) +#define BT848_SCLOOP_HFILT_MEDP (2<<3) +#define BT848_SCLOOP_HFILT_MAXP (3<<3) + + +#define BT848_OFORM 0x048 +#define BT848_OFORM_RANGE (1<<7) +#define BT848_OFORM_CORE0 (0<<5) +#define BT848_OFORM_CORE8 (1<<5) +#define BT848_OFORM_CORE16 (2<<5) +#define BT848_OFORM_CORE32 (3<<5) + +#define BT848_E_VSCALE_HI 0x04C +#define BT848_O_VSCALE_HI 0x0CC +#define BT848_VSCALE_YCOMB (1<<7) +#define BT848_VSCALE_COMB (1<<6) +#define BT848_VSCALE_INT (1<<5) +#define BT848_VSCALE_HI 15 + +#define BT848_E_VSCALE_LO 0x050 +#define BT848_O_VSCALE_LO 0x0D0 +#define BT848_TEST 0x054 +#define BT848_ADELAY 0x060 +#define BT848_BDELAY 0x064 + +#define BT848_ADC 0x068 +#define BT848_ADC_RESERVED (2<<6) +#define BT848_ADC_SYNC_T (1<<5) +#define BT848_ADC_AGC_EN (1<<4) +#define BT848_ADC_CLK_SLEEP (1<<3) +#define BT848_ADC_Y_SLEEP (1<<2) +#define BT848_ADC_C_SLEEP (1<<1) +#define BT848_ADC_CRUSH (1<<0) + +#define BT848_WC_UP 0x044 +#define BT848_WC_DOWN 0x078 + +#define BT848_E_VTC 0x06C +#define BT848_O_VTC 0x0EC +#define BT848_VTC_HSFMT (1<<7) +#define BT848_VTC_VFILT_2TAP 0 +#define BT848_VTC_VFILT_3TAP 1 +#define BT848_VTC_VFILT_4TAP 2 +#define BT848_VTC_VFILT_5TAP 3 + +#define BT848_SRESET 0x07C + +#define BT848_COLOR_FMT 0x0D4 +#define BT848_COLOR_FMT_O_RGB32 (0<<4) +#define BT848_COLOR_FMT_O_RGB24 (1<<4) +#define BT848_COLOR_FMT_O_RGB16 (2<<4) +#define BT848_COLOR_FMT_O_RGB15 (3<<4) +#define BT848_COLOR_FMT_O_YUY2 (4<<4) +#define BT848_COLOR_FMT_O_BtYUV (5<<4) +#define BT848_COLOR_FMT_O_Y8 (6<<4) +#define BT848_COLOR_FMT_O_RGB8 (7<<4) +#define BT848_COLOR_FMT_O_YCrCb422 (8<<4) +#define BT848_COLOR_FMT_O_YCrCb411 (9<<4) +#define BT848_COLOR_FMT_O_RAW (14<<4) +#define BT848_COLOR_FMT_E_RGB32 0 +#define BT848_COLOR_FMT_E_RGB24 1 +#define BT848_COLOR_FMT_E_RGB16 2 +#define BT848_COLOR_FMT_E_RGB15 3 +#define BT848_COLOR_FMT_E_YUY2 4 +#define BT848_COLOR_FMT_E_BtYUV 5 +#define BT848_COLOR_FMT_E_Y8 6 +#define BT848_COLOR_FMT_E_RGB8 7 +#define BT848_COLOR_FMT_E_YCrCb422 8 +#define BT848_COLOR_FMT_E_YCrCb411 9 +#define BT848_COLOR_FMT_E_RAW 14 + +#define BT848_COLOR_FMT_RGB32 0x00 +#define BT848_COLOR_FMT_RGB24 0x11 +#define BT848_COLOR_FMT_RGB16 0x22 +#define BT848_COLOR_FMT_RGB15 0x33 +#define BT848_COLOR_FMT_YUY2 0x44 +#define BT848_COLOR_FMT_BtYUV 0x55 +#define BT848_COLOR_FMT_Y8 0x66 +#define BT848_COLOR_FMT_RGB8 0x77 +#define BT848_COLOR_FMT_YCrCb422 0x88 +#define BT848_COLOR_FMT_YCrCb411 0x99 +#define BT848_COLOR_FMT_RAW 0xee + +#define BT848_VTOTAL_LO 0xB0 +#define BT848_VTOTAL_HI 0xB4 + +#define BT848_COLOR_CTL 0x0D8 +#define BT848_COLOR_CTL_EXT_FRMRATE (1<<7) +#define BT848_COLOR_CTL_COLOR_BARS (1<<6) +#define BT848_COLOR_CTL_RGB_DED (1<<5) +#define BT848_COLOR_CTL_GAMMA (1<<4) +#define BT848_COLOR_CTL_WSWAP_ODD (1<<3) +#define BT848_COLOR_CTL_WSWAP_EVEN (1<<2) +#define BT848_COLOR_CTL_BSWAP_ODD (1<<1) +#define BT848_COLOR_CTL_BSWAP_EVEN (1<<0) + +#define BT848_CAP_CTL 0x0DC +#define BT848_CAP_CTL_DITH_FRAME (1<<4) +#define BT848_CAP_CTL_CAPTURE_VBI_ODD (1<<3) +#define BT848_CAP_CTL_CAPTURE_VBI_EVEN (1<<2) +#define BT848_CAP_CTL_CAPTURE_ODD (1<<1) +#define BT848_CAP_CTL_CAPTURE_EVEN (1<<0) + +#define BT848_VBI_PACK_SIZE 0x0E0 + +#define BT848_VBI_PACK_DEL 0x0E4 +#define BT848_VBI_PACK_DEL_VBI_HDELAY 0xfc +#define BT848_VBI_PACK_DEL_EXT_FRAME 2 +#define BT848_VBI_PACK_DEL_VBI_PKT_HI 1 + + +#define BT848_INT_STAT 0x100 +#define BT848_INT_MASK 0x104 + +#define BT848_INT_ETBF (1<<23) + +#define BT848_INT_RISCS (0xf<<28) +#define BT848_INT_RISC_EN (1<<27) +#define BT848_INT_RACK (1<<25) +#define BT848_INT_FIELD (1<<24) +#define BT848_INT_SCERR (1<<19) +#define BT848_INT_OCERR (1<<18) +#define BT848_INT_PABORT (1<<17) +#define BT848_INT_RIPERR (1<<16) +#define BT848_INT_PPERR (1<<15) +#define BT848_INT_FDSR (1<<14) +#define BT848_INT_FTRGT (1<<13) +#define BT848_INT_FBUS (1<<12) +#define BT848_INT_RISCI (1<<11) +#define BT848_INT_GPINT (1<<9) +#define BT848_INT_I2CDONE (1<<8) +#define BT848_INT_VPRES (1<<5) +#define BT848_INT_HLOCK (1<<4) +#define BT848_INT_OFLOW (1<<3) +#define BT848_INT_HSYNC (1<<2) +#define BT848_INT_VSYNC (1<<1) +#define BT848_INT_FMTCHG (1<<0) + + +#define BT848_GPIO_DMA_CTL 0x10C +#define BT848_GPIO_DMA_CTL_GPINTC (1<<15) +#define BT848_GPIO_DMA_CTL_GPINTI (1<<14) +#define BT848_GPIO_DMA_CTL_GPWEC (1<<13) +#define BT848_GPIO_DMA_CTL_GPIOMODE (3<<11) +#define BT848_GPIO_DMA_CTL_GPCLKMODE (1<<10) +#define BT848_GPIO_DMA_CTL_PLTP23_4 (0<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_8 (1<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_16 (2<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_32 (3<<6) +#define BT848_GPIO_DMA_CTL_PLTP1_4 (0<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_8 (1<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_16 (2<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_32 (3<<4) +#define BT848_GPIO_DMA_CTL_PKTP_4 (0<<2) +#define BT848_GPIO_DMA_CTL_PKTP_8 (1<<2) +#define BT848_GPIO_DMA_CTL_PKTP_16 (2<<2) +#define BT848_GPIO_DMA_CTL_PKTP_32 (3<<2) +#define BT848_GPIO_DMA_CTL_RISC_ENABLE (1<<1) +#define BT848_GPIO_DMA_CTL_FIFO_ENABLE (1<<0) + +#define BT848_I2C 0x110 +#define BT878_I2C_MODE (1<<7) +#define BT878_I2C_RATE (1<<6) +#define BT878_I2C_NOSTOP (1<<5) +#define BT878_I2C_NOSTART (1<<4) +#define BT848_I2C_DIV (0xf<<4) +#define BT848_I2C_SYNC (1<<3) +#define BT848_I2C_W3B (1<<2) +#define BT848_I2C_SCL (1<<1) +#define BT848_I2C_SDA (1<<0) + +#define BT848_RISC_STRT_ADD 0x114 +#define BT848_GPIO_OUT_EN 0x118 +#define BT848_GPIO_REG_INP 0x11C +#define BT848_RISC_COUNT 0x120 +#define BT848_GPIO_DATA 0x200 + + +/* Bt848 RISC commands */ + +/* only for the SYNC RISC command */ +#define BT848_FIFO_STATUS_FM1 0x06 +#define BT848_FIFO_STATUS_FM3 0x0e +#define BT848_FIFO_STATUS_SOL 0x02 +#define BT848_FIFO_STATUS_EOL4 0x01 +#define BT848_FIFO_STATUS_EOL3 0x0d +#define BT848_FIFO_STATUS_EOL2 0x09 +#define BT848_FIFO_STATUS_EOL1 0x05 +#define BT848_FIFO_STATUS_VRE 0x04 +#define BT848_FIFO_STATUS_VRO 0x0c +#define BT848_FIFO_STATUS_PXV 0x00 + +#define BT848_RISC_RESYNC (1<<15) + +/* WRITE and SKIP */ +/* disable which bytes of each DWORD */ +#define BT848_RISC_BYTE0 (1U<<12) +#define BT848_RISC_BYTE1 (1U<<13) +#define BT848_RISC_BYTE2 (1U<<14) +#define BT848_RISC_BYTE3 (1U<<15) +#define BT848_RISC_BYTE_ALL (0x0fU<<12) +#define BT848_RISC_BYTE_NONE 0 +/* cause RISCI */ +#define BT848_RISC_IRQ (1U<<24) +/* RISC command is last one in this line */ +#define BT848_RISC_EOL (1U<<26) +/* RISC command is first one in this line */ +#define BT848_RISC_SOL (1U<<27) + +#define BT848_RISC_WRITE (0x01U<<28) +#define BT848_RISC_SKIP (0x02U<<28) +#define BT848_RISC_WRITEC (0x05U<<28) +#define BT848_RISC_JUMP (0x07U<<28) +#define BT848_RISC_SYNC (0x08U<<28) + +#define BT848_RISC_WRITE123 (0x09U<<28) +#define BT848_RISC_SKIP123 (0x0aU<<28) +#define BT848_RISC_WRITE1S23 (0x0bU<<28) + + +/* Bt848A and higher only !! */ +#define BT848_TGLB 0x080 +#define BT848_TGCTRL 0x084 +#define BT848_FCAP 0x0E8 +#define BT848_PLL_F_LO 0x0F0 +#define BT848_PLL_F_HI 0x0F4 + +#define BT848_PLL_XCI 0x0F8 +#define BT848_PLL_X (1<<7) +#define BT848_PLL_C (1<<6) + +#define BT848_DVSIF 0x0FC + +/* Bt878 register */ + +#define BT878_DEVCTRL 0x40 +#define BT878_EN_TBFX 0x02 +#define BT878_EN_VSFX 0x04 + +#endif --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.16/bttvp.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.16/bttvp.h @@ -0,0 +1,410 @@ +/* + + bttv - Bt848 frame grabber driver + + bttv's *private* header file -- nobody other than bttv itself + should ever include this file. + + (c) 2000-2002 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _BTTVP_H_ +#define _BTTVP_H_ + +#include +#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,16) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#include "bt848.h" +#include "bttv.h" +#include "btcx-risc.h" + +#ifdef __KERNEL__ + +#define FORMAT_FLAGS_DITHER 0x01 +#define FORMAT_FLAGS_PACKED 0x02 +#define FORMAT_FLAGS_PLANAR 0x04 +#define FORMAT_FLAGS_RAW 0x08 +#define FORMAT_FLAGS_CrCb 0x10 + +#define RISC_SLOT_O_VBI 4 +#define RISC_SLOT_O_FIELD 6 +#define RISC_SLOT_E_VBI 10 +#define RISC_SLOT_E_FIELD 12 +#define RISC_SLOT_LOOP 14 + +#define RESOURCE_OVERLAY 1 +#define RESOURCE_VIDEO 2 +#define RESOURCE_VBI 4 + +#define RAW_LINES 640 +#define RAW_BPL 1024 + +#define UNSET (-1U) + +#define clamp(x, low, high) min (max (low, x), high) + +/* ---------------------------------------------------------- */ + +struct bttv_tvnorm { + int v4l2_id; + char *name; + u32 Fsc; + u16 swidth, sheight; /* scaled standard width, height */ + u16 totalwidth; + u8 adelay, bdelay, iform; + u32 scaledtwidth; + u16 hdelayx1, hactivex1; + u16 vdelay; + u8 vbipack; + u16 vtotal; + int sram; + /* ITU-R frame line number of the first VBI line we can + capture, of the first and second field. */ + u16 vbistart[2]; +}; +extern const struct bttv_tvnorm bttv_tvnorms[]; + +struct bttv_format { + char *name; + int palette; /* video4linux 1 */ + int fourcc; /* video4linux 2 */ + int btformat; /* BT848_COLOR_FMT_* */ + int btswap; /* BT848_COLOR_CTL_* */ + int depth; /* bit/pixel */ + int flags; + int hshift,vshift; /* for planar modes */ +}; + +/* ---------------------------------------------------------- */ + +struct bttv_geometry { + u8 vtc,crop,comb; + u16 width,hscale,hdelay; + u16 sheight,vscale,vdelay,vtotal; +}; + +struct bttv_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* bttv specific */ + const struct bttv_format *fmt; + int tvnorm; + int btformat; + int btswap; + struct bttv_geometry geo; + struct btcx_riscmem top; + struct btcx_riscmem bottom; +}; + +struct bttv_buffer_set { + struct bttv_buffer *top; /* top field buffer */ + struct bttv_buffer *bottom; /* bottom field buffer */ + unsigned int top_irq; + unsigned int frame_irq; +}; + +struct bttv_overlay { + int tvnorm; + struct v4l2_rect w; + enum v4l2_field field; + struct v4l2_clip *clips; + int nclips; + int setup_ok; +}; + +struct bttv_fh { + struct bttv *btv; + int resources; +#ifdef VIDIOC_G_PRIORITY + enum v4l2_priority prio; +#endif + enum v4l2_buf_type type; + + /* video capture */ + struct videobuf_queue cap; + const struct bttv_format *fmt; + int width; + int height; + + /* current settings */ + const struct bttv_format *ovfmt; + struct bttv_overlay ov; + + /* video overlay */ + struct videobuf_queue vbi; + int lines; +}; + +/* ---------------------------------------------------------- */ +/* bttv-risc.c */ + +/* risc code generators - capture */ +int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int offset, unsigned int bpl, + unsigned int pitch, unsigned int lines); + +/* control dma register + risc main loop */ +void bttv_set_dma(struct bttv *btv, int override); +int bttv_risc_init_main(struct bttv *btv); +int bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, + int irqflags); + +/* capture buffer handling */ +int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf); +int bttv_buffer_activate_video(struct bttv *btv, + struct bttv_buffer_set *set); +int bttv_buffer_activate_vbi(struct bttv *btv, + struct bttv_buffer *vbi); +void bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf); + +/* overlay handling */ +int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov, + const struct bttv_format *fmt, + struct bttv_buffer *buf); + + +/* ---------------------------------------------------------- */ +/* bttv-vbi.c */ + +void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f); +void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f); +void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines); + +extern struct videobuf_queue_ops bttv_vbi_qops; + +/* ---------------------------------------------------------- */ +/* bttv-gpio.c */ + + +extern struct bus_type bttv_sub_bus_type; +int bttv_sub_add_device(struct bttv_core *core, char *name); +int bttv_sub_del_devices(struct bttv_core *core); +void bttv_gpio_irq(struct bttv_core *core); + + +/* ---------------------------------------------------------- */ +/* bttv-driver.c */ + +/* insmod options */ +extern unsigned int bttv_verbose; +extern unsigned int bttv_debug; +extern unsigned int bttv_gpio; +extern void bttv_gpio_tracking(struct bttv *btv, char *comment); +extern int init_bttv_i2c(struct bttv *btv); +extern int fini_bttv_i2c(struct bttv *btv); + +#define bttv_printk if (bttv_verbose) printk +#define dprintk if (bttv_debug >= 1) printk +#define d2printk if (bttv_debug >= 2) printk + +#define BTTV_MAX_FBUF 0x208000 +#define VBIBUF_SIZE (2048*VBI_MAXLINES*2) +#define BTTV_TIMEOUT (HZ/2) /* 0.5 seconds */ +#define BTTV_FREE_IDLE (HZ) /* one second */ + + +struct bttv_pll_info { + unsigned int pll_ifreq; /* PLL input frequency */ + unsigned int pll_ofreq; /* PLL output frequency */ + unsigned int pll_crystal; /* Crystal used for input */ + unsigned int pll_current; /* Currently programmed ofreq */ +}; + +/* for gpio-connected remote control */ +struct bttv_input { + struct input_dev *dev; + struct ir_input_state ir; + char name[32]; + char phys[32]; + u32 mask_keycode; + u32 mask_keydown; +}; + +struct bttv_suspend_state { + u32 gpio_enable; + u32 gpio_data; + int disabled; + int loop_irq; + struct bttv_buffer_set video; + struct bttv_buffer *vbi; +}; + +struct bttv { + struct bttv_core c; + + /* pci device config */ + unsigned short id; + unsigned char revision; + unsigned char __iomem *bt848_mmio; /* pointer to mmio */ + + /* card configuration info */ + unsigned int cardid; /* pci subsystem id (bt878 based ones) */ + unsigned int tuner_type; /* tuner chip type */ + unsigned int tda9887_conf; + unsigned int svhs; + struct bttv_pll_info pll; + int triton1; + int gpioirq; + int (*custom_irq)(struct bttv *btv); + + int use_i2c_hw; + + /* old gpio interface */ + wait_queue_head_t gpioq; + int shutdown; + void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); + + /* new gpio interface */ + spinlock_t gpio_lock; + + /* i2c layer */ + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + int i2c_state, i2c_rc; + int i2c_done; + wait_queue_head_t i2c_queue; + + /* video4linux (1) */ + struct video_device *video_dev; + struct video_device *radio_dev; + struct video_device *vbi_dev; + + /* infrared remote */ + int has_remote; + struct bttv_ir *remote; + + /* locking */ + spinlock_t s_lock; + struct mutex lock; + int resources; + struct mutex reslock; +#ifdef VIDIOC_G_PRIORITY + struct v4l2_prio_state prio; +#endif + + /* video state */ + unsigned int input; + unsigned int audio; + unsigned long freq; + int tvnorm,hue,contrast,bright,saturation; + struct v4l2_framebuffer fbuf; + unsigned int field_count; + + /* various options */ + int opt_combfilter; + int opt_lumafilter; + int opt_automute; + int opt_chroma_agc; + int opt_adc_crush; + int opt_vcr_hack; + int opt_whitecrush_upper; + int opt_whitecrush_lower; + int opt_uv_ratio; + int opt_full_luma_range; + int opt_coring; + + /* radio data/state */ + int has_radio; + int radio_user; + + /* miro/pinnacle + Aimslab VHX + philips matchbox (tea5757 radio tuner) support */ + int has_matchbox; + int mbox_we; + int mbox_data; + int mbox_clk; + int mbox_most; + int mbox_mask; + + /* ISA stuff (Terratec Active Radio Upgrade) */ + int mbox_ior; + int mbox_iow; + int mbox_csel; + + /* risc memory management data + - must aquire s_lock before changing these + - only the irq handler is supported to touch top + bottom + vcurr */ + struct btcx_riscmem main; + struct bttv_buffer *screen; /* overlay */ + struct list_head capture; /* video capture queue */ + struct list_head vcapture; /* vbi capture queue */ + struct bttv_buffer_set curr; /* active buffers */ + struct bttv_buffer *cvbi; /* active vbi buffer */ + int loop_irq; + int new_input; + + unsigned long cap_ctl; + unsigned long dma_on; + struct timer_list timeout; + struct bttv_suspend_state state; + + /* stats */ + unsigned int errors; + unsigned int framedrop; + unsigned int irq_total; + unsigned int irq_me; + + unsigned int users; + struct bttv_fh init; +}; + +/* our devices */ +#define BTTV_MAX 16 +extern unsigned int bttv_num; +extern struct bttv bttvs[BTTV_MAX]; + +/* private ioctls */ +#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int) +#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int) + +#endif + +#define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr)) +#define btread(adr) readl(btv->bt848_mmio+(adr)) + +#define btand(dat,adr) btwrite((dat) & btread(adr), adr) +#define btor(dat,adr) btwrite((dat) | btread(adr), adr) +#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) + +#endif /* _BTTVP_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.22/bttv.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.22/bttv.h @@ -0,0 +1,341 @@ +/* + * + * bttv - Bt848 frame grabber driver + * + * card ID's and external interfaces of the bttv driver + * basically stuff needed by other drivers (i2c, lirc, ...) + * and is supported not to change much over time. + * + * Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) + * (c) 1999,2000 Gerd Knorr + * + */ + +#ifndef _BTTV_H_ +#define _BTTV_H_ + +#include +#include +#include +#include +#include + +/* ---------------------------------------------------------- */ +/* exported by bttv-cards.c */ + +#define BTTV_BOARD_UNKNOWN 0x00 +#define BTTV_BOARD_MIRO 0x01 +#define BTTV_BOARD_HAUPPAUGE 0x02 +#define BTTV_BOARD_STB 0x03 +#define BTTV_BOARD_INTEL 0x04 +#define BTTV_BOARD_DIAMOND 0x05 +#define BTTV_BOARD_AVERMEDIA 0x06 +#define BTTV_BOARD_MATRIX_VISION 0x07 +#define BTTV_BOARD_FLYVIDEO 0x08 +#define BTTV_BOARD_TURBOTV 0x09 +#define BTTV_BOARD_HAUPPAUGE878 0x0a +#define BTTV_BOARD_MIROPRO 0x0b +#define BTTV_BOARD_ADSTECH_TV 0x0c +#define BTTV_BOARD_AVERMEDIA98 0x0d +#define BTTV_BOARD_VHX 0x0e +#define BTTV_BOARD_ZOLTRIX 0x0f +#define BTTV_BOARD_PIXVIEWPLAYTV 0x10 +#define BTTV_BOARD_WINVIEW_601 0x11 +#define BTTV_BOARD_AVEC_INTERCAP 0x12 +#define BTTV_BOARD_LIFE_FLYKIT 0x13 +#define BTTV_BOARD_CEI_RAFFLES 0x14 +#define BTTV_BOARD_CONFERENCETV 0x15 +#define BTTV_BOARD_PHOEBE_TVMAS 0x16 +#define BTTV_BOARD_MODTEC_205 0x17 +#define BTTV_BOARD_MAGICTVIEW061 0x18 +#define BTTV_BOARD_VOBIS_BOOSTAR 0x19 +#define BTTV_BOARD_HAUPPAUG_WCAM 0x1a +#define BTTV_BOARD_MAXI 0x1b +#define BTTV_BOARD_TERRATV 0x1c +#define BTTV_BOARD_PXC200 0x1d +#define BTTV_BOARD_FLYVIDEO_98 0x1e +#define BTTV_BOARD_IPROTV 0x1f +#define BTTV_BOARD_INTEL_C_S_PCI 0x20 +#define BTTV_BOARD_TERRATVALUE 0x21 +#define BTTV_BOARD_WINFAST2000 0x22 +#define BTTV_BOARD_CHRONOS_VS2 0x23 +#define BTTV_BOARD_TYPHOON_TVIEW 0x24 +#define BTTV_BOARD_PXELVWPLTVPRO 0x25 +#define BTTV_BOARD_MAGICTVIEW063 0x26 +#define BTTV_BOARD_PINNACLE 0x27 +#define BTTV_BOARD_STB2 0x28 +#define BTTV_BOARD_AVPHONE98 0x29 +#define BTTV_BOARD_PV951 0x2a +#define BTTV_BOARD_ONAIR_TV 0x2b +#define BTTV_BOARD_SIGMA_TVII_FM 0x2c +#define BTTV_BOARD_MATRIX_VISION2 0x2d +#define BTTV_BOARD_ZOLTRIX_GENIE 0x2e +#define BTTV_BOARD_TERRATVRADIO 0x2f +#define BTTV_BOARD_DYNALINK 0x30 +#define BTTV_BOARD_GVBCTV3PCI 0x31 +#define BTTV_BOARD_PXELVWPLTVPAK 0x32 +#define BTTV_BOARD_EAGLE 0x33 +#define BTTV_BOARD_PINNACLEPRO 0x34 +#define BTTV_BOARD_TVIEW_RDS_FM 0x35 +#define BTTV_BOARD_LIFETEC_9415 0x36 +#define BTTV_BOARD_BESTBUY_EASYTV 0x37 +#define BTTV_BOARD_FLYVIDEO_98FM 0x38 +#define BTTV_BOARD_GRANDTEC 0x39 +#define BTTV_BOARD_ASKEY_CPH060 0x3a +#define BTTV_BOARD_ASKEY_CPH03X 0x3b +#define BTTV_BOARD_MM100PCTV 0x3c +#define BTTV_BOARD_GMV1 0x3d +#define BTTV_BOARD_BESTBUY_EASYTV2 0x3e +#define BTTV_BOARD_ATI_TVWONDER 0x3f +#define BTTV_BOARD_ATI_TVWONDERVE 0x40 +#define BTTV_BOARD_FLYVIDEO2000 0x41 +#define BTTV_BOARD_TERRATVALUER 0x42 +#define BTTV_BOARD_GVBCTV4PCI 0x43 +#define BTTV_BOARD_VOODOOTV_FM 0x44 +#define BTTV_BOARD_AIMMS 0x45 +#define BTTV_BOARD_PV_BT878P_PLUS 0x46 +#define BTTV_BOARD_FLYVIDEO98EZ 0x47 +#define BTTV_BOARD_PV_BT878P_9B 0x48 +#define BTTV_BOARD_SENSORAY311 0x49 +#define BTTV_BOARD_RV605 0x4a +#define BTTV_BOARD_POWERCLR_MTV878 0x4b +#define BTTV_BOARD_WINDVR 0x4c +#define BTTV_BOARD_GRANDTEC_MULTI 0x4d +#define BTTV_BOARD_KWORLD 0x4e +#define BTTV_BOARD_DSP_TCVIDEO 0x4f +#define BTTV_BOARD_HAUPPAUGEPVR 0x50 +#define BTTV_BOARD_GVBCTV5PCI 0x51 +#define BTTV_BOARD_OSPREY1x0 0x52 +#define BTTV_BOARD_OSPREY1x0_848 0x53 +#define BTTV_BOARD_OSPREY101_848 0x54 +#define BTTV_BOARD_OSPREY1x1 0x55 +#define BTTV_BOARD_OSPREY1x1_SVID 0x56 +#define BTTV_BOARD_OSPREY2xx 0x57 +#define BTTV_BOARD_OSPREY2x0_SVID 0x58 +#define BTTV_BOARD_OSPREY2x0 0x59 +#define BTTV_BOARD_OSPREY500 0x5a +#define BTTV_BOARD_OSPREY540 0x5b +#define BTTV_BOARD_OSPREY2000 0x5c +#define BTTV_BOARD_IDS_EAGLE 0x5d +#define BTTV_BOARD_PINNACLESAT 0x5e +#define BTTV_BOARD_FORMAC_PROTV 0x5f +#define BTTV_BOARD_MACHTV 0x60 +#define BTTV_BOARD_EURESYS_PICOLO 0x61 +#define BTTV_BOARD_PV150 0x62 +#define BTTV_BOARD_AD_TVK503 0x63 +#define BTTV_BOARD_HERCULES_SM_TV 0x64 +#define BTTV_BOARD_PACETV 0x65 +#define BTTV_BOARD_IVC200 0x66 +#define BTTV_BOARD_XGUARD 0x67 +#define BTTV_BOARD_NEBULA_DIGITV 0x68 +#define BTTV_BOARD_PV143 0x69 +#define BTTV_BOARD_VD009X1_MINIDIN 0x6a +#define BTTV_BOARD_VD009X1_COMBI 0x6b +#define BTTV_BOARD_VD009_MINIDIN 0x6c +#define BTTV_BOARD_VD009_COMBI 0x6d +#define BTTV_BOARD_IVC100 0x6e +#define BTTV_BOARD_IVC120 0x6f +#define BTTV_BOARD_PC_HDTV 0x70 +#define BTTV_BOARD_TWINHAN_DST 0x71 +#define BTTV_BOARD_WINFASTVC100 0x72 +#define BTTV_BOARD_TEV560 0x73 +#define BTTV_BOARD_SIMUS_GVC1100 0x74 +#define BTTV_BOARD_NGSTV_PLUS 0x75 +#define BTTV_BOARD_LMLBT4 0x76 +#define BTTV_BOARD_TEKRAM_M205 0x77 +#define BTTV_BOARD_CONTVFMI 0x78 +#define BTTV_BOARD_PICOLO_TETRA_CHIP 0x79 +#define BTTV_BOARD_SPIRIT_TV 0x7a +#define BTTV_BOARD_AVDVBT_771 0x7b +#define BTTV_BOARD_AVDVBT_761 0x7c +#define BTTV_BOARD_MATRIX_VISIONSQ 0x7d +#define BTTV_BOARD_MATRIX_VISIONSLC 0x7e +#define BTTV_BOARD_APAC_VIEWCOMP 0x7f +#define BTTV_BOARD_DVICO_DVBT_LITE 0x80 +#define BTTV_BOARD_VGEAR_MYVCD 0x81 +#define BTTV_BOARD_SUPER_TV 0x82 +#define BTTV_BOARD_TIBET_CS16 0x83 +#define BTTV_BOARD_KODICOM_4400R 0x84 +#define BTTV_BOARD_KODICOM_4400R_SL 0x85 +#define BTTV_BOARD_ADLINK_RTV24 0x86 +#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 +#define BTTV_BOARD_ACORP_Y878F 0x88 +#define BTTV_BOARD_CONCEPTRONIC_CTVFMI2 0x89 +#define BTTV_BOARD_PV_BT878P_2E 0x8a +#define BTTV_BOARD_PV_M4900 0x8b +#define BTTV_BOARD_OSPREY440 0x8c +#define BTTV_BOARD_ASOUND_SKYEYE 0x8d +#define BTTV_BOARD_SABRENT_TVFM 0x8e +#define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f +#define BTTV_BOARD_MACHTV_MAGICTV 0x90 +#define BTTV_BOARD_SSAI_SECURITY 0x91 +#define BTTV_BOARD_SSAI_ULTRASOUND 0x92 + +/* more card-specific defines */ +#define PT2254_L_CHANNEL 0x10 +#define PT2254_R_CHANNEL 0x08 +#define PT2254_DBS_IN_2 0x400 +#define PT2254_DBS_IN_10 0x20000 +#define WINVIEW_PT2254_CLK 0x40 +#define WINVIEW_PT2254_DATA 0x20 +#define WINVIEW_PT2254_STROBE 0x80 + +/* digital_mode */ +#define DIGITAL_MODE_VIDEO 1 +#define DIGITAL_MODE_CAMERA 2 + +struct bttv_core { + /* device structs */ + struct pci_dev *pci; + struct i2c_adapter i2c_adap; + struct list_head subs; /* struct bttv_sub_device */ + + /* device config */ + unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */ + unsigned int type; /* card type (pointer into tvcards[]) */ + char name[8]; /* dev name */ +}; + +struct bttv; + + +struct tvcard +{ + char *name; + unsigned int video_inputs; + unsigned int audio_inputs; + unsigned int tuner; + unsigned int svhs; + unsigned int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO + u32 gpiomask; + u32 muxsel[16]; + u32 gpiomux[4]; /* Tuner, Radio, external, internal */ + u32 gpiomute; /* GPIO mute setting */ + u32 gpiomask2; /* GPIO MUX mask */ + + /* i2c audio flags */ + unsigned int no_msp34xx:1; + unsigned int no_tda9875:1; + unsigned int no_tda7432:1; + unsigned int needs_tvaudio:1; + unsigned int msp34xx_alt:1; + + /* flag: video pci function is unused */ + unsigned int no_video:1; + unsigned int has_dvb:1; + unsigned int has_remote:1; + unsigned int no_gpioirq:1; + + /* other settings */ + unsigned int pll; +#define PLL_NONE 0 +#define PLL_28 1 +#define PLL_35 2 + + unsigned int tuner_type; + unsigned int tuner_addr; + unsigned int radio_addr; + + unsigned int has_radio; + void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); + void (*muxsel_hook)(struct bttv *btv, unsigned int input); +}; + +extern struct tvcard bttv_tvcards[]; + +/* identification / initialization of the card */ +extern void bttv_idcard(struct bttv *btv); +extern void bttv_init_card1(struct bttv *btv); +extern void bttv_init_card2(struct bttv *btv); + +/* card-specific funtions */ +extern void tea5757_set_freq(struct bttv *btv, unsigned short freq); +extern void bttv_tda9880_setnorm(struct bttv *btv, int norm); + +/* extra tweaks for some chipsets */ +extern void bttv_check_chipset(void); +extern int bttv_handle_chipset(struct bttv *btv); + +/* ---------------------------------------------------------- */ +/* exported by bttv-if.c */ + +/* this obsolete -- please use the sysfs-based + interface below for new code */ + +extern struct pci_dev* bttv_get_pcidev(unsigned int card); + +/* sets GPOE register (BT848_GPIO_OUT_EN) to new value: + data | (current_GPOE_value & ~mask) + returns negative value if error occurred +*/ +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 occurred +*/ +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 occurred +*/ +extern int bttv_write_gpio(unsigned int card, + unsigned long mask, unsigned long data); + + + + +/* ---------------------------------------------------------- */ +/* sysfs/driver-moded based gpio access interface */ + + +struct bttv_sub_device { + struct device dev; + struct bttv_core *core; + struct list_head list; +}; +#define to_bttv_sub_dev(x) container_of((x), struct bttv_sub_device, dev) + +struct bttv_sub_driver { + struct device_driver drv; + char wanted[BUS_ID_SIZE]; + int (*probe)(struct bttv_sub_device *sub); + void (*remove)(struct bttv_sub_device *sub); +}; +#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) + +int bttv_sub_register(struct bttv_sub_driver *drv, char *wanted); +int bttv_sub_unregister(struct bttv_sub_driver *drv); + +/* gpio access functions */ +void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits); +u32 bttv_gpio_read(struct bttv_core *core); +void bttv_gpio_write(struct bttv_core *core, u32 value); +void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits); + +#define gpio_inout(mask,bits) bttv_gpio_inout(&btv->c, mask, bits) +#define gpio_read() bttv_gpio_read(&btv->c) +#define gpio_write(value) bttv_gpio_write(&btv->c, value) +#define gpio_bits(mask,bits) bttv_gpio_bits(&btv->c, mask, bits) + + +/* ---------------------------------------------------------- */ +/* i2c */ + +extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg); +extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for); +extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, + unsigned char b2, int both); +extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr); + +extern int bttv_input_init(struct bttv *dev); +extern void bttv_input_fini(struct bttv *dev); +extern void bttv_input_irq(struct bttv *dev); + +#endif /* _BTTV_H_ */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.22/btcx-risc.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.22/btcx-risc.h @@ -0,0 +1,34 @@ +/* + */ +struct btcx_riscmem { + unsigned int size; + u32 *cpu; + u32 *jmp; + dma_addr_t dma; +}; + +struct btcx_skiplist { + int start; + int end; +}; + +int btcx_riscmem_alloc(struct pci_dev *pci, + struct btcx_riscmem *risc, + unsigned int size); +void btcx_riscmem_free(struct pci_dev *pci, + struct btcx_riscmem *risc); + +int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, + struct v4l2_clip *clips, unsigned int n); +int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, + unsigned int n, int mask); +void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips); +void btcx_calc_skips(int line, int width, unsigned int *maxy, + struct btcx_skiplist *skips, unsigned int *nskips, + const struct v4l2_clip *clips, unsigned int nclips); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.22/bt848.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.22/bt848.h @@ -0,0 +1,366 @@ +/* + bt848.h - Bt848 register offsets + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _BT848_H_ +#define _BT848_H_ + +#ifndef PCI_VENDOR_ID_BROOKTREE +#define PCI_VENDOR_ID_BROOKTREE 0x109e +#endif +#ifndef PCI_DEVICE_ID_BT848 +#define PCI_DEVICE_ID_BT848 0x350 +#endif +#ifndef PCI_DEVICE_ID_BT849 +#define PCI_DEVICE_ID_BT849 0x351 +#endif +#ifndef PCI_DEVICE_ID_BT878 +#define PCI_DEVICE_ID_BT878 0x36e +#endif +#ifndef PCI_DEVICE_ID_BT879 +#define PCI_DEVICE_ID_BT879 0x36f +#endif + + +/* Brooktree 848 registers */ + +#define BT848_DSTATUS 0x000 +#define BT848_DSTATUS_PRES (1<<7) +#define BT848_DSTATUS_HLOC (1<<6) +#define BT848_DSTATUS_FIELD (1<<5) +#define BT848_DSTATUS_NUML (1<<4) +#define BT848_DSTATUS_CSEL (1<<3) +#define BT848_DSTATUS_PLOCK (1<<2) +#define BT848_DSTATUS_LOF (1<<1) +#define BT848_DSTATUS_COF (1<<0) + +#define BT848_IFORM 0x004 +#define BT848_IFORM_HACTIVE (1<<7) +#define BT848_IFORM_MUXSEL (3<<5) +#define BT848_IFORM_MUX0 (2<<5) +#define BT848_IFORM_MUX1 (3<<5) +#define BT848_IFORM_MUX2 (1<<5) +#define BT848_IFORM_XTSEL (3<<3) +#define BT848_IFORM_XT0 (1<<3) +#define BT848_IFORM_XT1 (2<<3) +#define BT848_IFORM_XTAUTO (3<<3) +#define BT848_IFORM_XTBOTH (3<<3) +#define BT848_IFORM_NTSC 1 +#define BT848_IFORM_NTSC_J 2 +#define BT848_IFORM_PAL_BDGHI 3 +#define BT848_IFORM_PAL_M 4 +#define BT848_IFORM_PAL_N 5 +#define BT848_IFORM_SECAM 6 +#define BT848_IFORM_PAL_NC 7 +#define BT848_IFORM_AUTO 0 +#define BT848_IFORM_NORM 7 + +#define BT848_TDEC 0x008 +#define BT848_TDEC_DEC_FIELD (1<<7) +#define BT848_TDEC_FLDALIGN (1<<6) +#define BT848_TDEC_DEC_RAT (0x1f) + +#define BT848_E_CROP 0x00C +#define BT848_O_CROP 0x08C + +#define BT848_E_VDELAY_LO 0x010 +#define BT848_O_VDELAY_LO 0x090 + +#define BT848_E_VACTIVE_LO 0x014 +#define BT848_O_VACTIVE_LO 0x094 + +#define BT848_E_HDELAY_LO 0x018 +#define BT848_O_HDELAY_LO 0x098 + +#define BT848_E_HACTIVE_LO 0x01C +#define BT848_O_HACTIVE_LO 0x09C + +#define BT848_E_HSCALE_HI 0x020 +#define BT848_O_HSCALE_HI 0x0A0 + +#define BT848_E_HSCALE_LO 0x024 +#define BT848_O_HSCALE_LO 0x0A4 + +#define BT848_BRIGHT 0x028 + +#define BT848_E_CONTROL 0x02C +#define BT848_O_CONTROL 0x0AC +#define BT848_CONTROL_LNOTCH (1<<7) +#define BT848_CONTROL_COMP (1<<6) +#define BT848_CONTROL_LDEC (1<<5) +#define BT848_CONTROL_CBSENSE (1<<4) +#define BT848_CONTROL_CON_MSB (1<<2) +#define BT848_CONTROL_SAT_U_MSB (1<<1) +#define BT848_CONTROL_SAT_V_MSB (1<<0) + +#define BT848_CONTRAST_LO 0x030 +#define BT848_SAT_U_LO 0x034 +#define BT848_SAT_V_LO 0x038 +#define BT848_HUE 0x03C + +#define BT848_E_SCLOOP 0x040 +#define BT848_O_SCLOOP 0x0C0 +#define BT848_SCLOOP_CAGC (1<<6) +#define BT848_SCLOOP_CKILL (1<<5) +#define BT848_SCLOOP_HFILT_AUTO (0<<3) +#define BT848_SCLOOP_HFILT_CIF (1<<3) +#define BT848_SCLOOP_HFILT_QCIF (2<<3) +#define BT848_SCLOOP_HFILT_ICON (3<<3) + +#define BT848_SCLOOP_PEAK (1<<7) +#define BT848_SCLOOP_HFILT_MINP (1<<3) +#define BT848_SCLOOP_HFILT_MEDP (2<<3) +#define BT848_SCLOOP_HFILT_MAXP (3<<3) + + +#define BT848_OFORM 0x048 +#define BT848_OFORM_RANGE (1<<7) +#define BT848_OFORM_CORE0 (0<<5) +#define BT848_OFORM_CORE8 (1<<5) +#define BT848_OFORM_CORE16 (2<<5) +#define BT848_OFORM_CORE32 (3<<5) + +#define BT848_E_VSCALE_HI 0x04C +#define BT848_O_VSCALE_HI 0x0CC +#define BT848_VSCALE_YCOMB (1<<7) +#define BT848_VSCALE_COMB (1<<6) +#define BT848_VSCALE_INT (1<<5) +#define BT848_VSCALE_HI 15 + +#define BT848_E_VSCALE_LO 0x050 +#define BT848_O_VSCALE_LO 0x0D0 +#define BT848_TEST 0x054 +#define BT848_ADELAY 0x060 +#define BT848_BDELAY 0x064 + +#define BT848_ADC 0x068 +#define BT848_ADC_RESERVED (2<<6) +#define BT848_ADC_SYNC_T (1<<5) +#define BT848_ADC_AGC_EN (1<<4) +#define BT848_ADC_CLK_SLEEP (1<<3) +#define BT848_ADC_Y_SLEEP (1<<2) +#define BT848_ADC_C_SLEEP (1<<1) +#define BT848_ADC_CRUSH (1<<0) + +#define BT848_WC_UP 0x044 +#define BT848_WC_DOWN 0x078 + +#define BT848_E_VTC 0x06C +#define BT848_O_VTC 0x0EC +#define BT848_VTC_HSFMT (1<<7) +#define BT848_VTC_VFILT_2TAP 0 +#define BT848_VTC_VFILT_3TAP 1 +#define BT848_VTC_VFILT_4TAP 2 +#define BT848_VTC_VFILT_5TAP 3 + +#define BT848_SRESET 0x07C + +#define BT848_COLOR_FMT 0x0D4 +#define BT848_COLOR_FMT_O_RGB32 (0<<4) +#define BT848_COLOR_FMT_O_RGB24 (1<<4) +#define BT848_COLOR_FMT_O_RGB16 (2<<4) +#define BT848_COLOR_FMT_O_RGB15 (3<<4) +#define BT848_COLOR_FMT_O_YUY2 (4<<4) +#define BT848_COLOR_FMT_O_BtYUV (5<<4) +#define BT848_COLOR_FMT_O_Y8 (6<<4) +#define BT848_COLOR_FMT_O_RGB8 (7<<4) +#define BT848_COLOR_FMT_O_YCrCb422 (8<<4) +#define BT848_COLOR_FMT_O_YCrCb411 (9<<4) +#define BT848_COLOR_FMT_O_RAW (14<<4) +#define BT848_COLOR_FMT_E_RGB32 0 +#define BT848_COLOR_FMT_E_RGB24 1 +#define BT848_COLOR_FMT_E_RGB16 2 +#define BT848_COLOR_FMT_E_RGB15 3 +#define BT848_COLOR_FMT_E_YUY2 4 +#define BT848_COLOR_FMT_E_BtYUV 5 +#define BT848_COLOR_FMT_E_Y8 6 +#define BT848_COLOR_FMT_E_RGB8 7 +#define BT848_COLOR_FMT_E_YCrCb422 8 +#define BT848_COLOR_FMT_E_YCrCb411 9 +#define BT848_COLOR_FMT_E_RAW 14 + +#define BT848_COLOR_FMT_RGB32 0x00 +#define BT848_COLOR_FMT_RGB24 0x11 +#define BT848_COLOR_FMT_RGB16 0x22 +#define BT848_COLOR_FMT_RGB15 0x33 +#define BT848_COLOR_FMT_YUY2 0x44 +#define BT848_COLOR_FMT_BtYUV 0x55 +#define BT848_COLOR_FMT_Y8 0x66 +#define BT848_COLOR_FMT_RGB8 0x77 +#define BT848_COLOR_FMT_YCrCb422 0x88 +#define BT848_COLOR_FMT_YCrCb411 0x99 +#define BT848_COLOR_FMT_RAW 0xee + +#define BT848_VTOTAL_LO 0xB0 +#define BT848_VTOTAL_HI 0xB4 + +#define BT848_COLOR_CTL 0x0D8 +#define BT848_COLOR_CTL_EXT_FRMRATE (1<<7) +#define BT848_COLOR_CTL_COLOR_BARS (1<<6) +#define BT848_COLOR_CTL_RGB_DED (1<<5) +#define BT848_COLOR_CTL_GAMMA (1<<4) +#define BT848_COLOR_CTL_WSWAP_ODD (1<<3) +#define BT848_COLOR_CTL_WSWAP_EVEN (1<<2) +#define BT848_COLOR_CTL_BSWAP_ODD (1<<1) +#define BT848_COLOR_CTL_BSWAP_EVEN (1<<0) + +#define BT848_CAP_CTL 0x0DC +#define BT848_CAP_CTL_DITH_FRAME (1<<4) +#define BT848_CAP_CTL_CAPTURE_VBI_ODD (1<<3) +#define BT848_CAP_CTL_CAPTURE_VBI_EVEN (1<<2) +#define BT848_CAP_CTL_CAPTURE_ODD (1<<1) +#define BT848_CAP_CTL_CAPTURE_EVEN (1<<0) + +#define BT848_VBI_PACK_SIZE 0x0E0 + +#define BT848_VBI_PACK_DEL 0x0E4 +#define BT848_VBI_PACK_DEL_VBI_HDELAY 0xfc +#define BT848_VBI_PACK_DEL_EXT_FRAME 2 +#define BT848_VBI_PACK_DEL_VBI_PKT_HI 1 + + +#define BT848_INT_STAT 0x100 +#define BT848_INT_MASK 0x104 + +#define BT848_INT_ETBF (1<<23) + +#define BT848_INT_RISCS (0xf<<28) +#define BT848_INT_RISC_EN (1<<27) +#define BT848_INT_RACK (1<<25) +#define BT848_INT_FIELD (1<<24) +#define BT848_INT_SCERR (1<<19) +#define BT848_INT_OCERR (1<<18) +#define BT848_INT_PABORT (1<<17) +#define BT848_INT_RIPERR (1<<16) +#define BT848_INT_PPERR (1<<15) +#define BT848_INT_FDSR (1<<14) +#define BT848_INT_FTRGT (1<<13) +#define BT848_INT_FBUS (1<<12) +#define BT848_INT_RISCI (1<<11) +#define BT848_INT_GPINT (1<<9) +#define BT848_INT_I2CDONE (1<<8) +#define BT848_INT_VPRES (1<<5) +#define BT848_INT_HLOCK (1<<4) +#define BT848_INT_OFLOW (1<<3) +#define BT848_INT_HSYNC (1<<2) +#define BT848_INT_VSYNC (1<<1) +#define BT848_INT_FMTCHG (1<<0) + + +#define BT848_GPIO_DMA_CTL 0x10C +#define BT848_GPIO_DMA_CTL_GPINTC (1<<15) +#define BT848_GPIO_DMA_CTL_GPINTI (1<<14) +#define BT848_GPIO_DMA_CTL_GPWEC (1<<13) +#define BT848_GPIO_DMA_CTL_GPIOMODE (3<<11) +#define BT848_GPIO_DMA_CTL_GPCLKMODE (1<<10) +#define BT848_GPIO_DMA_CTL_PLTP23_4 (0<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_8 (1<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_16 (2<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_32 (3<<6) +#define BT848_GPIO_DMA_CTL_PLTP1_4 (0<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_8 (1<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_16 (2<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_32 (3<<4) +#define BT848_GPIO_DMA_CTL_PKTP_4 (0<<2) +#define BT848_GPIO_DMA_CTL_PKTP_8 (1<<2) +#define BT848_GPIO_DMA_CTL_PKTP_16 (2<<2) +#define BT848_GPIO_DMA_CTL_PKTP_32 (3<<2) +#define BT848_GPIO_DMA_CTL_RISC_ENABLE (1<<1) +#define BT848_GPIO_DMA_CTL_FIFO_ENABLE (1<<0) + +#define BT848_I2C 0x110 +#define BT878_I2C_MODE (1<<7) +#define BT878_I2C_RATE (1<<6) +#define BT878_I2C_NOSTOP (1<<5) +#define BT878_I2C_NOSTART (1<<4) +#define BT848_I2C_DIV (0xf<<4) +#define BT848_I2C_SYNC (1<<3) +#define BT848_I2C_W3B (1<<2) +#define BT848_I2C_SCL (1<<1) +#define BT848_I2C_SDA (1<<0) + +#define BT848_RISC_STRT_ADD 0x114 +#define BT848_GPIO_OUT_EN 0x118 +#define BT848_GPIO_REG_INP 0x11C +#define BT848_RISC_COUNT 0x120 +#define BT848_GPIO_DATA 0x200 + + +/* Bt848 RISC commands */ + +/* only for the SYNC RISC command */ +#define BT848_FIFO_STATUS_FM1 0x06 +#define BT848_FIFO_STATUS_FM3 0x0e +#define BT848_FIFO_STATUS_SOL 0x02 +#define BT848_FIFO_STATUS_EOL4 0x01 +#define BT848_FIFO_STATUS_EOL3 0x0d +#define BT848_FIFO_STATUS_EOL2 0x09 +#define BT848_FIFO_STATUS_EOL1 0x05 +#define BT848_FIFO_STATUS_VRE 0x04 +#define BT848_FIFO_STATUS_VRO 0x0c +#define BT848_FIFO_STATUS_PXV 0x00 + +#define BT848_RISC_RESYNC (1<<15) + +/* WRITE and SKIP */ +/* disable which bytes of each DWORD */ +#define BT848_RISC_BYTE0 (1U<<12) +#define BT848_RISC_BYTE1 (1U<<13) +#define BT848_RISC_BYTE2 (1U<<14) +#define BT848_RISC_BYTE3 (1U<<15) +#define BT848_RISC_BYTE_ALL (0x0fU<<12) +#define BT848_RISC_BYTE_NONE 0 +/* cause RISCI */ +#define BT848_RISC_IRQ (1U<<24) +/* RISC command is last one in this line */ +#define BT848_RISC_EOL (1U<<26) +/* RISC command is first one in this line */ +#define BT848_RISC_SOL (1U<<27) + +#define BT848_RISC_WRITE (0x01U<<28) +#define BT848_RISC_SKIP (0x02U<<28) +#define BT848_RISC_WRITEC (0x05U<<28) +#define BT848_RISC_JUMP (0x07U<<28) +#define BT848_RISC_SYNC (0x08U<<28) + +#define BT848_RISC_WRITE123 (0x09U<<28) +#define BT848_RISC_SKIP123 (0x0aU<<28) +#define BT848_RISC_WRITE1S23 (0x0bU<<28) + + +/* Bt848A and higher only !! */ +#define BT848_TGLB 0x080 +#define BT848_TGCTRL 0x084 +#define BT848_FCAP 0x0E8 +#define BT848_PLL_F_LO 0x0F0 +#define BT848_PLL_F_HI 0x0F4 + +#define BT848_PLL_XCI 0x0F8 +#define BT848_PLL_X (1<<7) +#define BT848_PLL_C (1<<6) + +#define BT848_DVSIF 0x0FC + +/* Bt878 register */ + +#define BT878_DEVCTRL 0x40 +#define BT878_EN_TBFX 0x02 +#define BT878_EN_VSFX 0x04 + +#endif --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.22/bttvp.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.22/bttvp.h @@ -0,0 +1,480 @@ +/* + + bttv - Bt848 frame grabber driver + + bttv's *private* header file -- nobody other than bttv itself + should ever include this file. + + (c) 2000-2002 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _BTTVP_H_ +#define _BTTVP_H_ + +#include +#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,17) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include "bt848.h" +#include "bttv.h" +#include "btcx-risc.h" + +#ifdef __KERNEL__ + +#define FORMAT_FLAGS_DITHER 0x01 +#define FORMAT_FLAGS_PACKED 0x02 +#define FORMAT_FLAGS_PLANAR 0x04 +#define FORMAT_FLAGS_RAW 0x08 +#define FORMAT_FLAGS_CrCb 0x10 + +#define RISC_SLOT_O_VBI 4 +#define RISC_SLOT_O_FIELD 6 +#define RISC_SLOT_E_VBI 10 +#define RISC_SLOT_E_FIELD 12 +#define RISC_SLOT_LOOP 14 + +#define RESOURCE_OVERLAY 1 +#define RESOURCE_VIDEO_STREAM 2 +#define RESOURCE_VBI 4 +#define RESOURCE_VIDEO_READ 8 + +#define RAW_LINES 640 +#define RAW_BPL 1024 + +#define UNSET (-1U) + +/* Min. value in VDELAY register. */ +#define MIN_VDELAY 2 +/* Even to get Cb first, odd for Cr. */ +#define MAX_HDELAY (0x3FF & -2) +/* Limits scaled width, which must be a multiple of 4. */ +#define MAX_HACTIVE (0x3FF & -4) + +#define clamp(x, low, high) min (max (low, x), high) + +/* ---------------------------------------------------------- */ + +struct bttv_tvnorm { + int v4l2_id; + char *name; + u32 Fsc; + u16 swidth, sheight; /* scaled standard width, height */ + u16 totalwidth; + u8 adelay, bdelay, iform; + u32 scaledtwidth; + u16 hdelayx1, hactivex1; + u16 vdelay; + u8 vbipack; + u16 vtotal; + int sram; + /* ITU-R frame line number of the first VBI line we can + capture, of the first and second field. The last possible line + is determined by cropcap.bounds. */ + u16 vbistart[2]; + /* Horizontally this counts fCLKx1 samples following the leading + edge of the horizontal sync pulse, vertically ITU-R frame line + numbers of the first field times two (2, 4, 6, ... 524 or 624). */ + struct v4l2_cropcap cropcap; +}; +extern const struct bttv_tvnorm bttv_tvnorms[]; + +struct bttv_format { + char *name; + int palette; /* video4linux 1 */ + int fourcc; /* video4linux 2 */ + int btformat; /* BT848_COLOR_FMT_* */ + int btswap; /* BT848_COLOR_CTL_* */ + int depth; /* bit/pixel */ + int flags; + int hshift,vshift; /* for planar modes */ +}; + +/* ---------------------------------------------------------- */ + +struct bttv_geometry { + u8 vtc,crop,comb; + u16 width,hscale,hdelay; + u16 sheight,vscale,vdelay,vtotal; +}; + +struct bttv_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* bttv specific */ + const struct bttv_format *fmt; + int tvnorm; + int btformat; + int btswap; + struct bttv_geometry geo; + struct btcx_riscmem top; + struct btcx_riscmem bottom; + struct v4l2_rect crop; + unsigned int vbi_skip[2]; + unsigned int vbi_count[2]; +}; + +struct bttv_buffer_set { + struct bttv_buffer *top; /* top field buffer */ + struct bttv_buffer *bottom; /* bottom field buffer */ + unsigned int top_irq; + unsigned int frame_irq; +}; + +struct bttv_overlay { + int tvnorm; + struct v4l2_rect w; + enum v4l2_field field; + struct v4l2_clip *clips; + int nclips; + int setup_ok; +}; + +struct bttv_vbi_fmt { + struct v4l2_vbi_format fmt; + + /* fmt.start[] and count[] refer to this video standard. */ + const struct bttv_tvnorm *tvnorm; + + /* Earliest possible start of video capturing with this + v4l2_vbi_format, in struct bttv_crop.rect units. */ + __s32 end; +}; + +/* bttv-vbi.c */ +void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm); + +struct bttv_crop { + /* A cropping rectangle in struct bttv_tvnorm.cropcap units. */ + struct v4l2_rect rect; + + /* Scaled image size limits with this crop rect. Divide + max_height, but not min_height, by two when capturing + single fields. See also bttv_crop_reset() and + bttv_crop_adjust() in bttv-driver.c. */ + __s32 min_scaled_width; + __s32 min_scaled_height; + __s32 max_scaled_width; + __s32 max_scaled_height; +}; + +struct bttv_fh { + struct bttv *btv; + int resources; +#ifdef VIDIOC_G_PRIORITY + enum v4l2_priority prio; +#endif + enum v4l2_buf_type type; + + /* video capture */ + struct videobuf_queue cap; + const struct bttv_format *fmt; + int width; + int height; + + /* video overlay */ + const struct bttv_format *ovfmt; + struct bttv_overlay ov; + + /* Application called VIDIOC_S_CROP. */ + int do_crop; + + /* vbi capture */ + struct videobuf_queue vbi; + /* Current VBI capture window as seen through this fh (cannot + be global for compatibility with earlier drivers). Protected + by struct bttv.lock and struct bttv_fh.vbi.lock. */ + struct bttv_vbi_fmt vbi_fmt; +}; + +/* ---------------------------------------------------------- */ +/* bttv-risc.c */ + +/* risc code generators - capture */ +int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int offset, unsigned int bpl, + unsigned int pitch, unsigned int skip_lines, + unsigned int store_lines); + +/* control dma register + risc main loop */ +void bttv_set_dma(struct bttv *btv, int override); +int bttv_risc_init_main(struct bttv *btv); +int bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, + int irqflags); + +/* capture buffer handling */ +int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf); +int bttv_buffer_activate_video(struct bttv *btv, + struct bttv_buffer_set *set); +int bttv_buffer_activate_vbi(struct bttv *btv, + struct bttv_buffer *vbi); +void bttv_dma_free(struct videobuf_queue *q, struct bttv *btv, + struct bttv_buffer *buf); + +/* overlay handling */ +int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov, + const struct bttv_format *fmt, + struct bttv_buffer *buf); + + +/* ---------------------------------------------------------- */ +/* bttv-vbi.c */ + +int bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f); +void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f); +int bttv_vbi_set_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f); + +extern struct videobuf_queue_ops bttv_vbi_qops; + +/* ---------------------------------------------------------- */ +/* bttv-gpio.c */ + + +extern struct bus_type bttv_sub_bus_type; +int bttv_sub_add_device(struct bttv_core *core, char *name); +int bttv_sub_del_devices(struct bttv_core *core); + + +/* ---------------------------------------------------------- */ +/* bttv-driver.c */ + +/* insmod options */ +extern unsigned int bttv_verbose; +extern unsigned int bttv_debug; +extern unsigned int bttv_gpio; +extern void bttv_gpio_tracking(struct bttv *btv, char *comment); +extern int init_bttv_i2c(struct bttv *btv); +extern int fini_bttv_i2c(struct bttv *btv); + +#define bttv_printk if (bttv_verbose) printk +#define dprintk if (bttv_debug >= 1) printk +#define d2printk if (bttv_debug >= 2) printk + +#define BTTV_MAX_FBUF 0x208000 +#define BTTV_TIMEOUT (HZ/2) /* 0.5 seconds */ +#define BTTV_FREE_IDLE (HZ) /* one second */ + + +struct bttv_pll_info { + unsigned int pll_ifreq; /* PLL input frequency */ + unsigned int pll_ofreq; /* PLL output frequency */ + unsigned int pll_crystal; /* Crystal used for input */ + unsigned int pll_current; /* Currently programmed ofreq */ +}; + +/* for gpio-connected remote control */ +struct bttv_input { + struct input_dev *dev; + struct ir_input_state ir; + char name[32]; + char phys[32]; + u32 mask_keycode; + u32 mask_keydown; +}; + +struct bttv_suspend_state { + u32 gpio_enable; + u32 gpio_data; + int disabled; + int loop_irq; + struct bttv_buffer_set video; + struct bttv_buffer *vbi; +}; + +struct bttv { + struct bttv_core c; + + /* pci device config */ + unsigned short id; + unsigned char revision; + unsigned char __iomem *bt848_mmio; /* pointer to mmio */ + + /* card configuration info */ + unsigned int cardid; /* pci subsystem id (bt878 based ones) */ + unsigned int tuner_type; /* tuner chip type */ + unsigned int tda9887_conf; + unsigned int svhs; + struct bttv_pll_info pll; + int triton1; + int gpioirq; + int (*custom_irq)(struct bttv *btv); + + int use_i2c_hw; + + /* old gpio interface */ + wait_queue_head_t gpioq; + int shutdown; + void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); + + /* new gpio interface */ + spinlock_t gpio_lock; + + /* i2c layer */ + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + int i2c_state, i2c_rc; + int i2c_done; + wait_queue_head_t i2c_queue; + struct i2c_client *i2c_msp34xx_client; + struct i2c_client *i2c_tvaudio_client; + + /* video4linux (1) */ + struct video_device *video_dev; + struct video_device *radio_dev; + struct video_device *vbi_dev; + + /* infrared remote */ + int has_remote; + struct card_ir *remote; + + /* locking */ + spinlock_t s_lock; + struct mutex lock; + int resources; +#ifdef VIDIOC_G_PRIORITY + struct v4l2_prio_state prio; +#endif + + /* video state */ + unsigned int input; + unsigned int audio; + unsigned int mute; + unsigned long freq; + int tvnorm,hue,contrast,bright,saturation; + struct v4l2_framebuffer fbuf; + unsigned int field_count; + + /* various options */ + int opt_combfilter; + int opt_lumafilter; + int opt_automute; + int opt_chroma_agc; + int opt_adc_crush; + int opt_vcr_hack; + int opt_whitecrush_upper; + int opt_whitecrush_lower; + int opt_uv_ratio; + int opt_full_luma_range; + int opt_coring; + + /* radio data/state */ + int has_radio; + int radio_user; + + /* miro/pinnacle + Aimslab VHX + philips matchbox (tea5757 radio tuner) support */ + int has_matchbox; + int mbox_we; + int mbox_data; + int mbox_clk; + int mbox_most; + int mbox_mask; + + /* ISA stuff (Terratec Active Radio Upgrade) */ + int mbox_ior; + int mbox_iow; + int mbox_csel; + + /* risc memory management data + - must acquire s_lock before changing these + - only the irq handler is supported to touch top + bottom + vcurr */ + struct btcx_riscmem main; + struct bttv_buffer *screen; /* overlay */ + struct list_head capture; /* video capture queue */ + struct list_head vcapture; /* vbi capture queue */ + struct bttv_buffer_set curr; /* active buffers */ + struct bttv_buffer *cvbi; /* active vbi buffer */ + int loop_irq; + int new_input; + + unsigned long cap_ctl; + unsigned long dma_on; + struct timer_list timeout; + struct bttv_suspend_state state; + + /* stats */ + unsigned int errors; + unsigned int framedrop; + unsigned int irq_total; + unsigned int irq_me; + + unsigned int users; + struct bttv_fh init; + + /* used to make dvb-bt8xx autoloadable */ + struct work_struct request_module_wk; + + /* Default (0) and current (1) video capturing and overlay + cropping parameters in bttv_tvnorm.cropcap units. Protected + by bttv.lock. */ + struct bttv_crop crop[2]; + + /* Earliest possible start of video capturing in + bttv_tvnorm.cropcap line units. Set by check_alloc_btres() + and free_btres(). Protected by bttv.lock. */ + __s32 vbi_end; + + /* Latest possible end of VBI capturing (= crop[x].rect.top when + VIDEO_RESOURCES are locked). Set by check_alloc_btres() + and free_btres(). Protected by bttv.lock. */ + __s32 crop_start; +}; + +/* our devices */ +#define BTTV_MAX 16 +extern unsigned int bttv_num; +extern struct bttv bttvs[BTTV_MAX]; + +/* private ioctls */ +#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int) +#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int) + +#endif + +#define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr)) +#define btread(adr) readl(btv->bt848_mmio+(adr)) + +#define btand(dat,adr) btwrite((dat) & btread(adr), adr) +#define btor(dat,adr) btwrite((dat) | btread(adr), adr) +#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) + +#endif /* _BTTVP_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.17/bttv.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.17/bttv.h @@ -0,0 +1,390 @@ +/* + * + * bttv - Bt848 frame grabber driver + * + * card ID's and external interfaces of the bttv driver + * basically stuff needed by other drivers (i2c, lirc, ...) + * and is supported not to change much over time. + * + * Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) + * (c) 1999,2000 Gerd Knorr + * + */ + +#ifndef _BTTV_H_ +#define _BTTV_H_ + +#include +#include +#include +#include +#include + +/* ---------------------------------------------------------- */ +/* exported by bttv-cards.c */ + +#define BTTV_BOARD_UNKNOWN 0x00 +#define BTTV_BOARD_MIRO 0x01 +#define BTTV_BOARD_HAUPPAUGE 0x02 +#define BTTV_BOARD_STB 0x03 +#define BTTV_BOARD_INTEL 0x04 +#define BTTV_BOARD_DIAMOND 0x05 +#define BTTV_BOARD_AVERMEDIA 0x06 +#define BTTV_BOARD_MATRIX_VISION 0x07 +#define BTTV_BOARD_FLYVIDEO 0x08 +#define BTTV_BOARD_TURBOTV 0x09 +#define BTTV_BOARD_HAUPPAUGE878 0x0a +#define BTTV_BOARD_MIROPRO 0x0b +#define BTTV_BOARD_ADSTECH_TV 0x0c +#define BTTV_BOARD_AVERMEDIA98 0x0d +#define BTTV_BOARD_VHX 0x0e +#define BTTV_BOARD_ZOLTRIX 0x0f +#define BTTV_BOARD_PIXVIEWPLAYTV 0x10 +#define BTTV_BOARD_WINVIEW_601 0x11 +#define BTTV_BOARD_AVEC_INTERCAP 0x12 +#define BTTV_BOARD_LIFE_FLYKIT 0x13 +#define BTTV_BOARD_CEI_RAFFLES 0x14 +#define BTTV_BOARD_CONFERENCETV 0x15 +#define BTTV_BOARD_PHOEBE_TVMAS 0x16 +#define BTTV_BOARD_MODTEC_205 0x17 +#define BTTV_BOARD_MAGICTVIEW061 0x18 +#define BTTV_BOARD_VOBIS_BOOSTAR 0x19 +#define BTTV_BOARD_HAUPPAUG_WCAM 0x1a +#define BTTV_BOARD_MAXI 0x1b +#define BTTV_BOARD_TERRATV 0x1c +#define BTTV_BOARD_PXC200 0x1d +#define BTTV_BOARD_FLYVIDEO_98 0x1e +#define BTTV_BOARD_IPROTV 0x1f +#define BTTV_BOARD_INTEL_C_S_PCI 0x20 +#define BTTV_BOARD_TERRATVALUE 0x21 +#define BTTV_BOARD_WINFAST2000 0x22 +#define BTTV_BOARD_CHRONOS_VS2 0x23 +#define BTTV_BOARD_TYPHOON_TVIEW 0x24 +#define BTTV_BOARD_PXELVWPLTVPRO 0x25 +#define BTTV_BOARD_MAGICTVIEW063 0x26 +#define BTTV_BOARD_PINNACLE 0x27 +#define BTTV_BOARD_STB2 0x28 +#define BTTV_BOARD_AVPHONE98 0x29 +#define BTTV_BOARD_PV951 0x2a +#define BTTV_BOARD_ONAIR_TV 0x2b +#define BTTV_BOARD_SIGMA_TVII_FM 0x2c +#define BTTV_BOARD_MATRIX_VISION2 0x2d +#define BTTV_BOARD_ZOLTRIX_GENIE 0x2e +#define BTTV_BOARD_TERRATVRADIO 0x2f +#define BTTV_BOARD_DYNALINK 0x30 +#define BTTV_BOARD_GVBCTV3PCI 0x31 +#define BTTV_BOARD_PXELVWPLTVPAK 0x32 +#define BTTV_BOARD_EAGLE 0x33 +#define BTTV_BOARD_PINNACLEPRO 0x34 +#define BTTV_BOARD_TVIEW_RDS_FM 0x35 +#define BTTV_BOARD_LIFETEC_9415 0x36 +#define BTTV_BOARD_BESTBUY_EASYTV 0x37 +#define BTTV_BOARD_FLYVIDEO_98FM 0x38 +#define BTTV_BOARD_GRANDTEC 0x39 +#define BTTV_BOARD_ASKEY_CPH060 0x3a +#define BTTV_BOARD_ASKEY_CPH03X 0x3b +#define BTTV_BOARD_MM100PCTV 0x3c +#define BTTV_BOARD_GMV1 0x3d +#define BTTV_BOARD_BESTBUY_EASYTV2 0x3e +#define BTTV_BOARD_ATI_TVWONDER 0x3f +#define BTTV_BOARD_ATI_TVWONDERVE 0x40 +#define BTTV_BOARD_FLYVIDEO2000 0x41 +#define BTTV_BOARD_TERRATVALUER 0x42 +#define BTTV_BOARD_GVBCTV4PCI 0x43 +#define BTTV_BOARD_VOODOOTV_FM 0x44 +#define BTTV_BOARD_AIMMS 0x45 +#define BTTV_BOARD_PV_BT878P_PLUS 0x46 +#define BTTV_BOARD_FLYVIDEO98EZ 0x47 +#define BTTV_BOARD_PV_BT878P_9B 0x48 +#define BTTV_BOARD_SENSORAY311 0x49 +#define BTTV_BOARD_RV605 0x4a +#define BTTV_BOARD_POWERCLR_MTV878 0x4b +#define BTTV_BOARD_WINDVR 0x4c +#define BTTV_BOARD_GRANDTEC_MULTI 0x4d +#define BTTV_BOARD_KWORLD 0x4e +#define BTTV_BOARD_DSP_TCVIDEO 0x4f +#define BTTV_BOARD_HAUPPAUGEPVR 0x50 +#define BTTV_BOARD_GVBCTV5PCI 0x51 +#define BTTV_BOARD_OSPREY1x0 0x52 +#define BTTV_BOARD_OSPREY1x0_848 0x53 +#define BTTV_BOARD_OSPREY101_848 0x54 +#define BTTV_BOARD_OSPREY1x1 0x55 +#define BTTV_BOARD_OSPREY1x1_SVID 0x56 +#define BTTV_BOARD_OSPREY2xx 0x57 +#define BTTV_BOARD_OSPREY2x0_SVID 0x58 +#define BTTV_BOARD_OSPREY2x0 0x59 +#define BTTV_BOARD_OSPREY500 0x5a +#define BTTV_BOARD_OSPREY540 0x5b +#define BTTV_BOARD_OSPREY2000 0x5c +#define BTTV_BOARD_IDS_EAGLE 0x5d +#define BTTV_BOARD_PINNACLESAT 0x5e +#define BTTV_BOARD_FORMAC_PROTV 0x5f +#define BTTV_BOARD_MACHTV 0x60 +#define BTTV_BOARD_EURESYS_PICOLO 0x61 +#define BTTV_BOARD_PV150 0x62 +#define BTTV_BOARD_AD_TVK503 0x63 +#define BTTV_BOARD_HERCULES_SM_TV 0x64 +#define BTTV_BOARD_PACETV 0x65 +#define BTTV_BOARD_IVC200 0x66 +#define BTTV_BOARD_XGUARD 0x67 +#define BTTV_BOARD_NEBULA_DIGITV 0x68 +#define BTTV_BOARD_PV143 0x69 +#define BTTV_BOARD_VD009X1_MINIDIN 0x6a +#define BTTV_BOARD_VD009X1_COMBI 0x6b +#define BTTV_BOARD_VD009_MINIDIN 0x6c +#define BTTV_BOARD_VD009_COMBI 0x6d +#define BTTV_BOARD_IVC100 0x6e +#define BTTV_BOARD_IVC120 0x6f +#define BTTV_BOARD_PC_HDTV 0x70 +#define BTTV_BOARD_TWINHAN_DST 0x71 +#define BTTV_BOARD_WINFASTVC100 0x72 +#define BTTV_BOARD_TEV560 0x73 +#define BTTV_BOARD_SIMUS_GVC1100 0x74 +#define BTTV_BOARD_NGSTV_PLUS 0x75 +#define BTTV_BOARD_LMLBT4 0x76 +#define BTTV_BOARD_TEKRAM_M205 0x77 +#define BTTV_BOARD_CONTVFMI 0x78 +#define BTTV_BOARD_PICOLO_TETRA_CHIP 0x79 +#define BTTV_BOARD_SPIRIT_TV 0x7a +#define BTTV_BOARD_AVDVBT_771 0x7b +#define BTTV_BOARD_AVDVBT_761 0x7c +#define BTTV_BOARD_MATRIX_VISIONSQ 0x7d +#define BTTV_BOARD_MATRIX_VISIONSLC 0x7e +#define BTTV_BOARD_APAC_VIEWCOMP 0x7f +#define BTTV_BOARD_DVICO_DVBT_LITE 0x80 +#define BTTV_BOARD_VGEAR_MYVCD 0x81 +#define BTTV_BOARD_SUPER_TV 0x82 +#define BTTV_BOARD_TIBET_CS16 0x83 +#define BTTV_BOARD_KODICOM_4400R 0x84 +#define BTTV_BOARD_KODICOM_4400R_SL 0x85 +#define BTTV_BOARD_ADLINK_RTV24 0x86 +#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 +#define BTTV_BOARD_ACORP_Y878F 0x88 +#define BTTV_BOARD_CONCEPTRONIC_CTVFMI2 0x89 +#define BTTV_BOARD_PV_BT878P_2E 0x8a +#define BTTV_BOARD_PV_M4900 0x8b +#define BTTV_BOARD_OSPREY440 0x8c +#define BTTV_BOARD_ASOUND_SKYEYE 0x8d +#define BTTV_BOARD_SABRENT_TVFM 0x8e +#define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f +#define BTTV_BOARD_MACHTV_MAGICTV 0x90 + +/* more card-specific defines */ +#define PT2254_L_CHANNEL 0x10 +#define PT2254_R_CHANNEL 0x08 +#define PT2254_DBS_IN_2 0x400 +#define PT2254_DBS_IN_10 0x20000 +#define WINVIEW_PT2254_CLK 0x40 +#define WINVIEW_PT2254_DATA 0x20 +#define WINVIEW_PT2254_STROBE 0x80 + +/* digital_mode */ +#define DIGITAL_MODE_VIDEO 1 +#define DIGITAL_MODE_CAMERA 2 + +struct bttv_core { + /* device structs */ + struct pci_dev *pci; + struct i2c_adapter i2c_adap; + struct list_head subs; /* struct bttv_sub_device */ + + /* device config */ + unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */ + unsigned int type; /* card type (pointer into tvcards[]) */ + char name[8]; /* dev name */ +}; + +struct bttv; + + +struct bttv_ir { + struct input_dev *dev; + struct ir_input_state ir; + char name[32]; + char phys[32]; + + /* Usual gpio signalling */ + + u32 mask_keycode; + u32 mask_keydown; + u32 mask_keyup; + u32 polling; + u32 last_gpio; + struct work_struct work; + struct timer_list timer; + + /* RC5 gpio */ + u32 rc5_gpio; + struct timer_list timer_end; /* timer_end for code completion */ + struct timer_list timer_keyup; /* timer_end for key release */ + u32 last_rc5; /* last good rc5 code */ + u32 last_bit; /* last raw bit seen */ + u32 code; /* raw code under construction */ + struct timeval base_time; /* time of last seen code */ + int active; /* building raw code */ +}; + +struct tvcard +{ + char *name; + unsigned int video_inputs; + unsigned int audio_inputs; + unsigned int tuner; + unsigned int svhs; + unsigned int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO + u32 gpiomask; + u32 muxsel[16]; + u32 gpiomux[4]; /* Tuner, Radio, external, internal */ + u32 gpiomute; /* GPIO mute setting */ + u32 gpiomask2; /* GPIO MUX mask */ + + /* i2c audio flags */ + unsigned int no_msp34xx:1; + unsigned int no_tda9875:1; + unsigned int no_tda7432:1; + unsigned int needs_tvaudio:1; + unsigned int msp34xx_alt:1; + + /* flag: video pci function is unused */ + unsigned int no_video:1; + unsigned int has_dvb:1; + unsigned int has_remote:1; + unsigned int no_gpioirq:1; + + /* other settings */ + unsigned int pll; +#define PLL_NONE 0 +#define PLL_28 1 +#define PLL_35 2 + + unsigned int tuner_type; + unsigned int tuner_addr; + unsigned int radio_addr; + + unsigned int has_radio; + void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); + void (*muxsel_hook)(struct bttv *btv, unsigned int input); +}; + +extern struct tvcard bttv_tvcards[]; + +/* identification / initialization of the card */ +extern void bttv_idcard(struct bttv *btv); +extern void bttv_init_card1(struct bttv *btv); +extern void bttv_init_card2(struct bttv *btv); + +/* card-specific funtions */ +extern void tea5757_set_freq(struct bttv *btv, unsigned short freq); +extern void bttv_tda9880_setnorm(struct bttv *btv, int norm); + +/* extra tweaks for some chipsets */ +extern void bttv_check_chipset(void); +extern int bttv_handle_chipset(struct bttv *btv); + +/* ---------------------------------------------------------- */ +/* exported by bttv-if.c */ + +/* this obsolete -- please use the sysfs-based + interface below for new code */ + +/* returns card type + card ID (for bt878-based ones) + for possible values see lines below beginning with #define BTTV_BOARD_UNKNOWN + returns negative value if error occurred +*/ +extern int bttv_get_cardinfo(unsigned int card, int *type, + unsigned int *cardid); +extern struct pci_dev* bttv_get_pcidev(unsigned int card); + +/* obsolete, use bttv_get_cardinfo instead */ +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 occurred +*/ +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 occurred +*/ +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 occurred +*/ +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 occurred or queue is not available + WARNING: because there is no buffer for GPIO data, one MUST + process data ASAP +*/ +extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card); + +/* call i2c clients +*/ +extern void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg); + + + +/* ---------------------------------------------------------- */ +/* sysfs/driver-moded based gpio access interface */ + + +struct bttv_sub_device { + struct device dev; + struct bttv_core *core; + struct list_head list; +}; +#define to_bttv_sub_dev(x) container_of((x), struct bttv_sub_device, dev) + +struct bttv_sub_driver { + struct device_driver drv; + char wanted[BUS_ID_SIZE]; + int (*probe)(struct bttv_sub_device *sub); + void (*remove)(struct bttv_sub_device *sub); + void (*gpio_irq)(struct bttv_sub_device *sub); +}; +#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) + +int bttv_sub_register(struct bttv_sub_driver *drv, char *wanted); +int bttv_sub_unregister(struct bttv_sub_driver *drv); + +/* gpio access functions */ +void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits); +u32 bttv_gpio_read(struct bttv_core *core); +void bttv_gpio_write(struct bttv_core *core, u32 value); +void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits); + +#define gpio_inout(mask,bits) bttv_gpio_inout(&btv->c, mask, bits) +#define gpio_read() bttv_gpio_read(&btv->c) +#define gpio_write(value) bttv_gpio_write(&btv->c, value) +#define gpio_bits(mask,bits) bttv_gpio_bits(&btv->c, mask, bits) + + +/* ---------------------------------------------------------- */ +/* i2c */ + +extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg); +extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for); +extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, + unsigned char b2, int both); +extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr); + +extern int bttv_input_init(struct bttv *dev); +extern void bttv_input_fini(struct bttv *dev); +extern void bttv_input_irq(struct bttv *dev); + +#endif /* _BTTV_H_ */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.17/btcx-risc.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.17/btcx-risc.h @@ -0,0 +1,34 @@ +/* + */ +struct btcx_riscmem { + unsigned int size; + u32 *cpu; + u32 *jmp; + dma_addr_t dma; +}; + +struct btcx_skiplist { + int start; + int end; +}; + +int btcx_riscmem_alloc(struct pci_dev *pci, + struct btcx_riscmem *risc, + unsigned int size); +void btcx_riscmem_free(struct pci_dev *pci, + struct btcx_riscmem *risc); + +int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, + struct v4l2_clip *clips, unsigned int n); +int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, + unsigned int n, int mask); +void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips); +void btcx_calc_skips(int line, int width, unsigned int *maxy, + struct btcx_skiplist *skips, unsigned int *nskips, + const struct v4l2_clip *clips, unsigned int nclips); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.17/bt848.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.17/bt848.h @@ -0,0 +1,366 @@ +/* + bt848.h - Bt848 register offsets + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _BT848_H_ +#define _BT848_H_ + +#ifndef PCI_VENDOR_ID_BROOKTREE +#define PCI_VENDOR_ID_BROOKTREE 0x109e +#endif +#ifndef PCI_DEVICE_ID_BT848 +#define PCI_DEVICE_ID_BT848 0x350 +#endif +#ifndef PCI_DEVICE_ID_BT849 +#define PCI_DEVICE_ID_BT849 0x351 +#endif +#ifndef PCI_DEVICE_ID_BT878 +#define PCI_DEVICE_ID_BT878 0x36e +#endif +#ifndef PCI_DEVICE_ID_BT879 +#define PCI_DEVICE_ID_BT879 0x36f +#endif + + +/* Brooktree 848 registers */ + +#define BT848_DSTATUS 0x000 +#define BT848_DSTATUS_PRES (1<<7) +#define BT848_DSTATUS_HLOC (1<<6) +#define BT848_DSTATUS_FIELD (1<<5) +#define BT848_DSTATUS_NUML (1<<4) +#define BT848_DSTATUS_CSEL (1<<3) +#define BT848_DSTATUS_PLOCK (1<<2) +#define BT848_DSTATUS_LOF (1<<1) +#define BT848_DSTATUS_COF (1<<0) + +#define BT848_IFORM 0x004 +#define BT848_IFORM_HACTIVE (1<<7) +#define BT848_IFORM_MUXSEL (3<<5) +#define BT848_IFORM_MUX0 (2<<5) +#define BT848_IFORM_MUX1 (3<<5) +#define BT848_IFORM_MUX2 (1<<5) +#define BT848_IFORM_XTSEL (3<<3) +#define BT848_IFORM_XT0 (1<<3) +#define BT848_IFORM_XT1 (2<<3) +#define BT848_IFORM_XTAUTO (3<<3) +#define BT848_IFORM_XTBOTH (3<<3) +#define BT848_IFORM_NTSC 1 +#define BT848_IFORM_NTSC_J 2 +#define BT848_IFORM_PAL_BDGHI 3 +#define BT848_IFORM_PAL_M 4 +#define BT848_IFORM_PAL_N 5 +#define BT848_IFORM_SECAM 6 +#define BT848_IFORM_PAL_NC 7 +#define BT848_IFORM_AUTO 0 +#define BT848_IFORM_NORM 7 + +#define BT848_TDEC 0x008 +#define BT848_TDEC_DEC_FIELD (1<<7) +#define BT848_TDEC_FLDALIGN (1<<6) +#define BT848_TDEC_DEC_RAT (0x1f) + +#define BT848_E_CROP 0x00C +#define BT848_O_CROP 0x08C + +#define BT848_E_VDELAY_LO 0x010 +#define BT848_O_VDELAY_LO 0x090 + +#define BT848_E_VACTIVE_LO 0x014 +#define BT848_O_VACTIVE_LO 0x094 + +#define BT848_E_HDELAY_LO 0x018 +#define BT848_O_HDELAY_LO 0x098 + +#define BT848_E_HACTIVE_LO 0x01C +#define BT848_O_HACTIVE_LO 0x09C + +#define BT848_E_HSCALE_HI 0x020 +#define BT848_O_HSCALE_HI 0x0A0 + +#define BT848_E_HSCALE_LO 0x024 +#define BT848_O_HSCALE_LO 0x0A4 + +#define BT848_BRIGHT 0x028 + +#define BT848_E_CONTROL 0x02C +#define BT848_O_CONTROL 0x0AC +#define BT848_CONTROL_LNOTCH (1<<7) +#define BT848_CONTROL_COMP (1<<6) +#define BT848_CONTROL_LDEC (1<<5) +#define BT848_CONTROL_CBSENSE (1<<4) +#define BT848_CONTROL_CON_MSB (1<<2) +#define BT848_CONTROL_SAT_U_MSB (1<<1) +#define BT848_CONTROL_SAT_V_MSB (1<<0) + +#define BT848_CONTRAST_LO 0x030 +#define BT848_SAT_U_LO 0x034 +#define BT848_SAT_V_LO 0x038 +#define BT848_HUE 0x03C + +#define BT848_E_SCLOOP 0x040 +#define BT848_O_SCLOOP 0x0C0 +#define BT848_SCLOOP_CAGC (1<<6) +#define BT848_SCLOOP_CKILL (1<<5) +#define BT848_SCLOOP_HFILT_AUTO (0<<3) +#define BT848_SCLOOP_HFILT_CIF (1<<3) +#define BT848_SCLOOP_HFILT_QCIF (2<<3) +#define BT848_SCLOOP_HFILT_ICON (3<<3) + +#define BT848_SCLOOP_PEAK (1<<7) +#define BT848_SCLOOP_HFILT_MINP (1<<3) +#define BT848_SCLOOP_HFILT_MEDP (2<<3) +#define BT848_SCLOOP_HFILT_MAXP (3<<3) + + +#define BT848_OFORM 0x048 +#define BT848_OFORM_RANGE (1<<7) +#define BT848_OFORM_CORE0 (0<<5) +#define BT848_OFORM_CORE8 (1<<5) +#define BT848_OFORM_CORE16 (2<<5) +#define BT848_OFORM_CORE32 (3<<5) + +#define BT848_E_VSCALE_HI 0x04C +#define BT848_O_VSCALE_HI 0x0CC +#define BT848_VSCALE_YCOMB (1<<7) +#define BT848_VSCALE_COMB (1<<6) +#define BT848_VSCALE_INT (1<<5) +#define BT848_VSCALE_HI 15 + +#define BT848_E_VSCALE_LO 0x050 +#define BT848_O_VSCALE_LO 0x0D0 +#define BT848_TEST 0x054 +#define BT848_ADELAY 0x060 +#define BT848_BDELAY 0x064 + +#define BT848_ADC 0x068 +#define BT848_ADC_RESERVED (2<<6) +#define BT848_ADC_SYNC_T (1<<5) +#define BT848_ADC_AGC_EN (1<<4) +#define BT848_ADC_CLK_SLEEP (1<<3) +#define BT848_ADC_Y_SLEEP (1<<2) +#define BT848_ADC_C_SLEEP (1<<1) +#define BT848_ADC_CRUSH (1<<0) + +#define BT848_WC_UP 0x044 +#define BT848_WC_DOWN 0x078 + +#define BT848_E_VTC 0x06C +#define BT848_O_VTC 0x0EC +#define BT848_VTC_HSFMT (1<<7) +#define BT848_VTC_VFILT_2TAP 0 +#define BT848_VTC_VFILT_3TAP 1 +#define BT848_VTC_VFILT_4TAP 2 +#define BT848_VTC_VFILT_5TAP 3 + +#define BT848_SRESET 0x07C + +#define BT848_COLOR_FMT 0x0D4 +#define BT848_COLOR_FMT_O_RGB32 (0<<4) +#define BT848_COLOR_FMT_O_RGB24 (1<<4) +#define BT848_COLOR_FMT_O_RGB16 (2<<4) +#define BT848_COLOR_FMT_O_RGB15 (3<<4) +#define BT848_COLOR_FMT_O_YUY2 (4<<4) +#define BT848_COLOR_FMT_O_BtYUV (5<<4) +#define BT848_COLOR_FMT_O_Y8 (6<<4) +#define BT848_COLOR_FMT_O_RGB8 (7<<4) +#define BT848_COLOR_FMT_O_YCrCb422 (8<<4) +#define BT848_COLOR_FMT_O_YCrCb411 (9<<4) +#define BT848_COLOR_FMT_O_RAW (14<<4) +#define BT848_COLOR_FMT_E_RGB32 0 +#define BT848_COLOR_FMT_E_RGB24 1 +#define BT848_COLOR_FMT_E_RGB16 2 +#define BT848_COLOR_FMT_E_RGB15 3 +#define BT848_COLOR_FMT_E_YUY2 4 +#define BT848_COLOR_FMT_E_BtYUV 5 +#define BT848_COLOR_FMT_E_Y8 6 +#define BT848_COLOR_FMT_E_RGB8 7 +#define BT848_COLOR_FMT_E_YCrCb422 8 +#define BT848_COLOR_FMT_E_YCrCb411 9 +#define BT848_COLOR_FMT_E_RAW 14 + +#define BT848_COLOR_FMT_RGB32 0x00 +#define BT848_COLOR_FMT_RGB24 0x11 +#define BT848_COLOR_FMT_RGB16 0x22 +#define BT848_COLOR_FMT_RGB15 0x33 +#define BT848_COLOR_FMT_YUY2 0x44 +#define BT848_COLOR_FMT_BtYUV 0x55 +#define BT848_COLOR_FMT_Y8 0x66 +#define BT848_COLOR_FMT_RGB8 0x77 +#define BT848_COLOR_FMT_YCrCb422 0x88 +#define BT848_COLOR_FMT_YCrCb411 0x99 +#define BT848_COLOR_FMT_RAW 0xee + +#define BT848_VTOTAL_LO 0xB0 +#define BT848_VTOTAL_HI 0xB4 + +#define BT848_COLOR_CTL 0x0D8 +#define BT848_COLOR_CTL_EXT_FRMRATE (1<<7) +#define BT848_COLOR_CTL_COLOR_BARS (1<<6) +#define BT848_COLOR_CTL_RGB_DED (1<<5) +#define BT848_COLOR_CTL_GAMMA (1<<4) +#define BT848_COLOR_CTL_WSWAP_ODD (1<<3) +#define BT848_COLOR_CTL_WSWAP_EVEN (1<<2) +#define BT848_COLOR_CTL_BSWAP_ODD (1<<1) +#define BT848_COLOR_CTL_BSWAP_EVEN (1<<0) + +#define BT848_CAP_CTL 0x0DC +#define BT848_CAP_CTL_DITH_FRAME (1<<4) +#define BT848_CAP_CTL_CAPTURE_VBI_ODD (1<<3) +#define BT848_CAP_CTL_CAPTURE_VBI_EVEN (1<<2) +#define BT848_CAP_CTL_CAPTURE_ODD (1<<1) +#define BT848_CAP_CTL_CAPTURE_EVEN (1<<0) + +#define BT848_VBI_PACK_SIZE 0x0E0 + +#define BT848_VBI_PACK_DEL 0x0E4 +#define BT848_VBI_PACK_DEL_VBI_HDELAY 0xfc +#define BT848_VBI_PACK_DEL_EXT_FRAME 2 +#define BT848_VBI_PACK_DEL_VBI_PKT_HI 1 + + +#define BT848_INT_STAT 0x100 +#define BT848_INT_MASK 0x104 + +#define BT848_INT_ETBF (1<<23) + +#define BT848_INT_RISCS (0xf<<28) +#define BT848_INT_RISC_EN (1<<27) +#define BT848_INT_RACK (1<<25) +#define BT848_INT_FIELD (1<<24) +#define BT848_INT_SCERR (1<<19) +#define BT848_INT_OCERR (1<<18) +#define BT848_INT_PABORT (1<<17) +#define BT848_INT_RIPERR (1<<16) +#define BT848_INT_PPERR (1<<15) +#define BT848_INT_FDSR (1<<14) +#define BT848_INT_FTRGT (1<<13) +#define BT848_INT_FBUS (1<<12) +#define BT848_INT_RISCI (1<<11) +#define BT848_INT_GPINT (1<<9) +#define BT848_INT_I2CDONE (1<<8) +#define BT848_INT_VPRES (1<<5) +#define BT848_INT_HLOCK (1<<4) +#define BT848_INT_OFLOW (1<<3) +#define BT848_INT_HSYNC (1<<2) +#define BT848_INT_VSYNC (1<<1) +#define BT848_INT_FMTCHG (1<<0) + + +#define BT848_GPIO_DMA_CTL 0x10C +#define BT848_GPIO_DMA_CTL_GPINTC (1<<15) +#define BT848_GPIO_DMA_CTL_GPINTI (1<<14) +#define BT848_GPIO_DMA_CTL_GPWEC (1<<13) +#define BT848_GPIO_DMA_CTL_GPIOMODE (3<<11) +#define BT848_GPIO_DMA_CTL_GPCLKMODE (1<<10) +#define BT848_GPIO_DMA_CTL_PLTP23_4 (0<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_8 (1<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_16 (2<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_32 (3<<6) +#define BT848_GPIO_DMA_CTL_PLTP1_4 (0<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_8 (1<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_16 (2<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_32 (3<<4) +#define BT848_GPIO_DMA_CTL_PKTP_4 (0<<2) +#define BT848_GPIO_DMA_CTL_PKTP_8 (1<<2) +#define BT848_GPIO_DMA_CTL_PKTP_16 (2<<2) +#define BT848_GPIO_DMA_CTL_PKTP_32 (3<<2) +#define BT848_GPIO_DMA_CTL_RISC_ENABLE (1<<1) +#define BT848_GPIO_DMA_CTL_FIFO_ENABLE (1<<0) + +#define BT848_I2C 0x110 +#define BT878_I2C_MODE (1<<7) +#define BT878_I2C_RATE (1<<6) +#define BT878_I2C_NOSTOP (1<<5) +#define BT878_I2C_NOSTART (1<<4) +#define BT848_I2C_DIV (0xf<<4) +#define BT848_I2C_SYNC (1<<3) +#define BT848_I2C_W3B (1<<2) +#define BT848_I2C_SCL (1<<1) +#define BT848_I2C_SDA (1<<0) + +#define BT848_RISC_STRT_ADD 0x114 +#define BT848_GPIO_OUT_EN 0x118 +#define BT848_GPIO_REG_INP 0x11C +#define BT848_RISC_COUNT 0x120 +#define BT848_GPIO_DATA 0x200 + + +/* Bt848 RISC commands */ + +/* only for the SYNC RISC command */ +#define BT848_FIFO_STATUS_FM1 0x06 +#define BT848_FIFO_STATUS_FM3 0x0e +#define BT848_FIFO_STATUS_SOL 0x02 +#define BT848_FIFO_STATUS_EOL4 0x01 +#define BT848_FIFO_STATUS_EOL3 0x0d +#define BT848_FIFO_STATUS_EOL2 0x09 +#define BT848_FIFO_STATUS_EOL1 0x05 +#define BT848_FIFO_STATUS_VRE 0x04 +#define BT848_FIFO_STATUS_VRO 0x0c +#define BT848_FIFO_STATUS_PXV 0x00 + +#define BT848_RISC_RESYNC (1<<15) + +/* WRITE and SKIP */ +/* disable which bytes of each DWORD */ +#define BT848_RISC_BYTE0 (1U<<12) +#define BT848_RISC_BYTE1 (1U<<13) +#define BT848_RISC_BYTE2 (1U<<14) +#define BT848_RISC_BYTE3 (1U<<15) +#define BT848_RISC_BYTE_ALL (0x0fU<<12) +#define BT848_RISC_BYTE_NONE 0 +/* cause RISCI */ +#define BT848_RISC_IRQ (1U<<24) +/* RISC command is last one in this line */ +#define BT848_RISC_EOL (1U<<26) +/* RISC command is first one in this line */ +#define BT848_RISC_SOL (1U<<27) + +#define BT848_RISC_WRITE (0x01U<<28) +#define BT848_RISC_SKIP (0x02U<<28) +#define BT848_RISC_WRITEC (0x05U<<28) +#define BT848_RISC_JUMP (0x07U<<28) +#define BT848_RISC_SYNC (0x08U<<28) + +#define BT848_RISC_WRITE123 (0x09U<<28) +#define BT848_RISC_SKIP123 (0x0aU<<28) +#define BT848_RISC_WRITE1S23 (0x0bU<<28) + + +/* Bt848A and higher only !! */ +#define BT848_TGLB 0x080 +#define BT848_TGCTRL 0x084 +#define BT848_FCAP 0x0E8 +#define BT848_PLL_F_LO 0x0F0 +#define BT848_PLL_F_HI 0x0F4 + +#define BT848_PLL_XCI 0x0F8 +#define BT848_PLL_X (1<<7) +#define BT848_PLL_C (1<<6) + +#define BT848_DVSIF 0x0FC + +/* Bt878 register */ + +#define BT878_DEVCTRL 0x40 +#define BT878_EN_TBFX 0x02 +#define BT878_EN_VSFX 0x04 + +#endif --- linux-2.6.27.orig/ubuntu/lirc/lirc_gpio/extra_2.6.17/bttvp.h +++ linux-2.6.27/ubuntu/lirc/lirc_gpio/extra_2.6.17/bttvp.h @@ -0,0 +1,413 @@ +/* + + bttv - Bt848 frame grabber driver + + bttv's *private* header file -- nobody other than bttv itself + should ever include this file. + + (c) 2000-2002 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _BTTVP_H_ +#define _BTTVP_H_ + +#include +#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,16) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include "bt848.h" +#include "bttv.h" +#include "btcx-risc.h" + +#ifdef __KERNEL__ + +#define FORMAT_FLAGS_DITHER 0x01 +#define FORMAT_FLAGS_PACKED 0x02 +#define FORMAT_FLAGS_PLANAR 0x04 +#define FORMAT_FLAGS_RAW 0x08 +#define FORMAT_FLAGS_CrCb 0x10 + +#define RISC_SLOT_O_VBI 4 +#define RISC_SLOT_O_FIELD 6 +#define RISC_SLOT_E_VBI 10 +#define RISC_SLOT_E_FIELD 12 +#define RISC_SLOT_LOOP 14 + +#define RESOURCE_OVERLAY 1 +#define RESOURCE_VIDEO 2 +#define RESOURCE_VBI 4 + +#define RAW_LINES 640 +#define RAW_BPL 1024 + +#define UNSET (-1U) + +#define clamp(x, low, high) min (max (low, x), high) + +/* ---------------------------------------------------------- */ + +struct bttv_tvnorm { + int v4l2_id; + char *name; + u32 Fsc; + u16 swidth, sheight; /* scaled standard width, height */ + u16 totalwidth; + u8 adelay, bdelay, iform; + u32 scaledtwidth; + u16 hdelayx1, hactivex1; + u16 vdelay; + u8 vbipack; + u16 vtotal; + int sram; + /* ITU-R frame line number of the first VBI line we can + capture, of the first and second field. */ + u16 vbistart[2]; +}; +extern const struct bttv_tvnorm bttv_tvnorms[]; + +struct bttv_format { + char *name; + int palette; /* video4linux 1 */ + int fourcc; /* video4linux 2 */ + int btformat; /* BT848_COLOR_FMT_* */ + int btswap; /* BT848_COLOR_CTL_* */ + int depth; /* bit/pixel */ + int flags; + int hshift,vshift; /* for planar modes */ +}; + +/* ---------------------------------------------------------- */ + +struct bttv_geometry { + u8 vtc,crop,comb; + u16 width,hscale,hdelay; + u16 sheight,vscale,vdelay,vtotal; +}; + +struct bttv_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* bttv specific */ + const struct bttv_format *fmt; + int tvnorm; + int btformat; + int btswap; + struct bttv_geometry geo; + struct btcx_riscmem top; + struct btcx_riscmem bottom; +}; + +struct bttv_buffer_set { + struct bttv_buffer *top; /* top field buffer */ + struct bttv_buffer *bottom; /* bottom field buffer */ + unsigned int top_irq; + unsigned int frame_irq; +}; + +struct bttv_overlay { + int tvnorm; + struct v4l2_rect w; + enum v4l2_field field; + struct v4l2_clip *clips; + int nclips; + int setup_ok; +}; + +struct bttv_fh { + struct bttv *btv; + int resources; +#ifdef VIDIOC_G_PRIORITY + enum v4l2_priority prio; +#endif + enum v4l2_buf_type type; + + /* video capture */ + struct videobuf_queue cap; + const struct bttv_format *fmt; + int width; + int height; + + /* current settings */ + const struct bttv_format *ovfmt; + struct bttv_overlay ov; + + /* video overlay */ + struct videobuf_queue vbi; + int lines; +}; + +/* ---------------------------------------------------------- */ +/* bttv-risc.c */ + +/* risc code generators - capture */ +int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int offset, unsigned int bpl, + unsigned int pitch, unsigned int lines); + +/* control dma register + risc main loop */ +void bttv_set_dma(struct bttv *btv, int override); +int bttv_risc_init_main(struct bttv *btv); +int bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, + int irqflags); + +/* capture buffer handling */ +int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf); +int bttv_buffer_activate_video(struct bttv *btv, + struct bttv_buffer_set *set); +int bttv_buffer_activate_vbi(struct bttv *btv, + struct bttv_buffer *vbi); +void bttv_dma_free(struct videobuf_queue *q, struct bttv *btv, + struct bttv_buffer *buf); + +/* overlay handling */ +int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov, + const struct bttv_format *fmt, + struct bttv_buffer *buf); + + +/* ---------------------------------------------------------- */ +/* bttv-vbi.c */ + +void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f); +void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f); +void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines); + +extern struct videobuf_queue_ops bttv_vbi_qops; + +/* ---------------------------------------------------------- */ +/* bttv-gpio.c */ + + +extern struct bus_type bttv_sub_bus_type; +int bttv_sub_add_device(struct bttv_core *core, char *name); +int bttv_sub_del_devices(struct bttv_core *core); +void bttv_gpio_irq(struct bttv_core *core); + + +/* ---------------------------------------------------------- */ +/* bttv-driver.c */ + +/* insmod options */ +extern unsigned int bttv_verbose; +extern unsigned int bttv_debug; +extern unsigned int bttv_gpio; +extern void bttv_gpio_tracking(struct bttv *btv, char *comment); +extern int init_bttv_i2c(struct bttv *btv); +extern int fini_bttv_i2c(struct bttv *btv); + +#define bttv_printk if (bttv_verbose) printk +#define dprintk if (bttv_debug >= 1) printk +#define d2printk if (bttv_debug >= 2) printk + +#define BTTV_MAX_FBUF 0x208000 +#define VBIBUF_SIZE (2048*VBI_MAXLINES*2) +#define BTTV_TIMEOUT (HZ/2) /* 0.5 seconds */ +#define BTTV_FREE_IDLE (HZ) /* one second */ + + +struct bttv_pll_info { + unsigned int pll_ifreq; /* PLL input frequency */ + unsigned int pll_ofreq; /* PLL output frequency */ + unsigned int pll_crystal; /* Crystal used for input */ + unsigned int pll_current; /* Currently programmed ofreq */ +}; + +/* for gpio-connected remote control */ +struct bttv_input { + struct input_dev *dev; + struct ir_input_state ir; + char name[32]; + char phys[32]; + u32 mask_keycode; + u32 mask_keydown; +}; + +struct bttv_suspend_state { + u32 gpio_enable; + u32 gpio_data; + int disabled; + int loop_irq; + struct bttv_buffer_set video; + struct bttv_buffer *vbi; +}; + +struct bttv { + struct bttv_core c; + + /* pci device config */ + unsigned short id; + unsigned char revision; + unsigned char __iomem *bt848_mmio; /* pointer to mmio */ + + /* card configuration info */ + unsigned int cardid; /* pci subsystem id (bt878 based ones) */ + unsigned int tuner_type; /* tuner chip type */ + unsigned int tda9887_conf; + unsigned int svhs; + struct bttv_pll_info pll; + int triton1; + int gpioirq; + int (*custom_irq)(struct bttv *btv); + + int use_i2c_hw; + + /* old gpio interface */ + wait_queue_head_t gpioq; + int shutdown; + void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); + + /* new gpio interface */ + spinlock_t gpio_lock; + + /* i2c layer */ + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + int i2c_state, i2c_rc; + int i2c_done; + wait_queue_head_t i2c_queue; + struct i2c_client *i2c_msp34xx_client; + struct i2c_client *i2c_tvaudio_client; + + /* video4linux (1) */ + struct video_device *video_dev; + struct video_device *radio_dev; + struct video_device *vbi_dev; + + /* infrared remote */ + int has_remote; + struct bttv_ir *remote; + + /* locking */ + spinlock_t s_lock; + struct mutex lock; + int resources; + struct mutex reslock; +#ifdef VIDIOC_G_PRIORITY + struct v4l2_prio_state prio; +#endif + + /* video state */ + unsigned int input; + unsigned int audio; + unsigned int mute; + unsigned long freq; + int tvnorm,hue,contrast,bright,saturation; + struct v4l2_framebuffer fbuf; + unsigned int field_count; + + /* various options */ + int opt_combfilter; + int opt_lumafilter; + int opt_automute; + int opt_chroma_agc; + int opt_adc_crush; + int opt_vcr_hack; + int opt_whitecrush_upper; + int opt_whitecrush_lower; + int opt_uv_ratio; + int opt_full_luma_range; + int opt_coring; + + /* radio data/state */ + int has_radio; + int radio_user; + + /* miro/pinnacle + Aimslab VHX + philips matchbox (tea5757 radio tuner) support */ + int has_matchbox; + int mbox_we; + int mbox_data; + int mbox_clk; + int mbox_most; + int mbox_mask; + + /* ISA stuff (Terratec Active Radio Upgrade) */ + int mbox_ior; + int mbox_iow; + int mbox_csel; + + /* risc memory management data + - must aquire s_lock before changing these + - only the irq handler is supported to touch top + bottom + vcurr */ + struct btcx_riscmem main; + struct bttv_buffer *screen; /* overlay */ + struct list_head capture; /* video capture queue */ + struct list_head vcapture; /* vbi capture queue */ + struct bttv_buffer_set curr; /* active buffers */ + struct bttv_buffer *cvbi; /* active vbi buffer */ + int loop_irq; + int new_input; + + unsigned long cap_ctl; + unsigned long dma_on; + struct timer_list timeout; + struct bttv_suspend_state state; + + /* stats */ + unsigned int errors; + unsigned int framedrop; + unsigned int irq_total; + unsigned int irq_me; + + unsigned int users; + struct bttv_fh init; +}; + +/* our devices */ +#define BTTV_MAX 16 +extern unsigned int bttv_num; +extern struct bttv bttvs[BTTV_MAX]; + +/* private ioctls */ +#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int) +#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int) + +#endif + +#define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr)) +#define btread(adr) readl(btv->bt848_mmio+(adr)) + +#define btand(dat,adr) btwrite((dat) & btread(adr), adr) +#define btor(dat,adr) btwrite((dat) | btread(adr), adr) +#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) + +#endif /* _BTTVP_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_imon/lirc_imon.c +++ linux-2.6.27/ubuntu/lirc/lirc_imon/lirc_imon.c @@ -0,0 +1,1524 @@ +/* + * lirc_imon.c: LIRC plugin/VFD driver for Ahanix/Soundgraph IMON IR/VFD + * + * $Id: lirc_imon.c,v 1.23 2008/01/19 10:06:46 lirc Exp $ + * + * Version 0.3 + * Supports newer iMON models that send decoded IR signals. + * This includes the iMON PAD model. + * Removed module option for vfd_proto_6p. This driver supports + * multiple iMON devices so it is meaningless to have + * a global option to set protocol variants. + * + * Version 0.2 beta 2 [January 31, 2005] + * USB disconnect/reconnect no longer causes problems for lircd + * + * Version 0.2 beta 1 [January 29, 2005] + * Added support for original iMON receiver(ext USB) + * + * Version 0.2 alpha 2 [January 24, 2005] + * Added support for VFDs with 6-packet protocol + * + * Version 0.2 alpha 1 [January 23, 2005] + * Added support for 2.6 kernels + * Reworked disconnect handling + * Incorporated Changwoo Ryu's algorithm + * + * Version 0.1 alpha 1[July 5, 2004] + * + * Copyright(C) 2004 Venky Raju(dev@venky.ws) + * + * lirc_imon is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 22) +#error "*** Sorry, this driver requires kernel version 2.4.22 or higher" +#endif + +#include + +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) +#include +#else +#include +#endif +#include + +#include "kcompat.h" +#include "lirc.h" +#include "lirc_dev/lirc_dev.h" + + +#define MOD_AUTHOR "Venky Raju " +#define MOD_DESC "Driver for Soundgraph iMON MultiMedia IR/VFD w/imon pad2keys patch" +#define MOD_NAME "lirc_imon" +#define MOD_VERSION "0.3p2k" + +#define VFD_MINOR_BASE 144 /* Same as LCD */ +#define DEVFS_MODE (S_IFCHR | S_IRUSR | S_IWUSR | \ + S_IRGRP | S_IWGRP | S_IROTH) +#define DEVFS_NAME LIRC_DEVFS_PREFIX "lcd%d" + +#define BUF_CHUNK_SIZE 4 +#define BUF_SIZE 128 + +#define BIT_DURATION 250 /* each bit received is 250us */ + +#define SUCCESS 0 +#define TRUE 1 +#define FALSE 0 + +#define CURSOR_LIMIT 16 + +/* ------------------------------------------------------------ + * P R O T O T Y P E S + * ------------------------------------------------------------ + */ + +/* USB Callback prototypes */ +#ifdef KERNEL_2_5 +static int imon_probe(struct usb_interface *interface, + const struct usb_device_id *id); +static void imon_disconnect(struct usb_interface *interface); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void usb_rx_callback(struct urb *urb, struct pt_regs *regs); +static void usb_tx_callback(struct urb *urb, struct pt_regs *regs); +#else +static void usb_rx_callback(struct urb *urb); +static void usb_tx_callback(struct urb *urb); +#endif +#else +static void *imon_probe(struct usb_device *dev, unsigned int intf, + const struct usb_device_id *id); +static void imon_disconnect(struct usb_device *dev, void *data); +static void usb_rx_callback(struct urb *urb); +static void usb_tx_callback(struct urb *urb); +#endif + +/* VFD file_operations function prototypes */ +static int vfd_open(struct inode *inode, struct file *file); +static int vfd_close(struct inode *inode, struct file *file); +static ssize_t vfd_write(struct file *file, const char *buf, + size_t n_bytes, loff_t *pos); + +/* LCD file_operations override function prototypes */ +static ssize_t lcd_write(struct file *file, const char *buf, + size_t n_bytes, loff_t *pos); + +/* LIRC plugin function prototypes */ +static int ir_open(void *data); +static void ir_close(void *data); + +/* Driver init/exit prototypes */ +static int __init imon_init(void); +static void __exit imon_exit(void); + +/* ------------------------------------------------------------ + * G L O B A L S + * ------------------------------------------------------------ + */ + +struct imon_context { + struct usb_device *dev; + int vfd_supported; /* not all controllers do */ + int vfd_isopen; /* VFD port has been opened */ +#if !defined(KERNEL_2_5) + int subminor; /* index into minor_table */ + devfs_handle_t devfs; +#endif + int ir_isopen; /* IR port open */ + int ir_isassociating; /* IR port open for association */ + int dev_present; /* USB device presence */ + struct semaphore sem; /* to lock this object */ + wait_queue_head_t remove_ok; /* For unexpected USB disconnects */ + + int vfd_proto_6p; /* VFD requires 6th packet */ + int ir_onboard_decode; /* IR signals decoded onboard */ + + struct lirc_plugin *plugin; + struct usb_endpoint_descriptor *rx_endpoint; + struct usb_endpoint_descriptor *tx_endpoint; + struct urb *rx_urb; + struct urb *tx_urb; + unsigned char usb_rx_buf[8]; + unsigned char usb_tx_buf[8]; + + struct rx_data { + int count; /* length of 0 or 1 sequence */ + int prev_bit; /* logic level of sequence */ + int initial_space; /* initial space flag */ + } rx; + + struct tx_t { + unsigned char data_buf[35]; /* user data buffer */ + struct completion finished; /* wait for write to finish */ + atomic_t busy; /* write in progress */ + int status; /* status of tx completion */ + } tx; + + int key_x; + int key_y; + int last_count; /* number of times pressed */ +}; + +#define LOCK_CONTEXT down(&context->sem) +#define UNLOCK_CONTEXT up(&context->sem) + +/* VFD file operations */ +static struct file_operations vfd_fops = { + .owner = THIS_MODULE, + .open = &vfd_open, + .write = &vfd_write, + .release = &vfd_close +}; + +/* USB Device ID for IMON USB Control Board */ +static struct usb_device_id imon_usb_id_table[] = { + { USB_DEVICE(0x0aa8, 0xffda) }, /* IR & VFD */ + { USB_DEVICE(0x0aa8, 0x8001) }, /* IR only */ + { USB_DEVICE(0x15c2, 0xffda) }, /* IR & VFD */ + { USB_DEVICE(0x15c2, 0xffdc) }, /* IR & VFD */ + { USB_DEVICE(0x04e8, 0xff30) }, /* ext IR only */ + {} +}; + +/* Some iMON VFD models requires a 6th packet */ +static unsigned short vfd_proto_6p_vendor_list[] = { + /* terminate this list with a 0 */ + 0x15c2, + 0 }; +static unsigned char vfd_packet6[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }; + +/* Newer iMON models decode the signal onboard */ +static unsigned short ir_onboard_decode_product_list[] = { + /* terminate this list with a 0 */ + 0xffdc, + 0 }; + +/* USB Device data */ +static struct usb_driver imon_driver = { + LIRC_THIS_MODULE(.owner = THIS_MODULE) + .name = MOD_NAME, + .probe = imon_probe, + .disconnect = imon_disconnect, + .id_table = imon_usb_id_table, +#if !defined(KERNEL_2_5) + .fops = &vfd_fops, + .minor = VFD_MINOR_BASE, +#endif +}; + +#ifdef KERNEL_2_5 +static struct usb_class_driver imon_class = { + .name = DEVFS_NAME, + .fops = &vfd_fops, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15) + .mode = DEVFS_MODE, +#endif + .minor_base = VFD_MINOR_BASE, +}; +#endif + +/* to prevent races between open() and disconnect() */ +static DECLARE_MUTEX(disconnect_sem); + +static int debug; +#ifdef LIRC_IMON_LCD +static int is_lcd = 1; +#else +static int is_lcd; /* If LIRC_IMON_LCD not defined, default to non-LCD */ +#endif + +/* pad2keys module parameter. pad2keys patch active? */ +static int pad2keys_active = 0; + +#if !defined(KERNEL_2_5) + +#define MAX_DEVICES 4 /* In case there's more than one iMON device */ +static struct imon_context *minor_table[MAX_DEVICES]; + +/* +static DECLARE_MUTEX(minor_table_sem); +#define LOCK_MINOR_TABLE down(&minor_table_sem) +#define UNLOCK_MINOR_TABLE up(&minor_table_sem) +*/ + +/* the global usb devfs handle */ +extern devfs_handle_t usb_devfs_handle; + +#endif + +/* ------------------------------------------------------------ + * M O D U L E C O D E + * ------------------------------------------------------------ + */ + +MODULE_AUTHOR(MOD_AUTHOR); +MODULE_DESCRIPTION(MOD_DESC); +MODULE_VERSION(MOD_VERSION); /* MBr: was missing */ +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(usb, imon_usb_id_table); + +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)"); + +#ifdef LIRC_IMON_LCD +module_param(is_lcd, int, 1); +MODULE_PARM_DESC(is_lcd, "The device is an LCD: 0=no (it's a VFD), " + "1=yes (default:yes)"); +#else +module_param(is_lcd, int, 0); +MODULE_PARM_DESC(is_lcd, "The device is an LCD: 0=no (it's a VFD), " + "1=yes (default:no)"); +#endif +module_param (pad2keys_active, int, 0); +MODULE_PARM_DESC (pad2keys_active, "pad2keys patch active: 0=no, 1=yes (default: no)"); + +static inline void delete_context(struct imon_context *context) +{ + if (context->vfd_supported) + usb_free_urb(context->tx_urb); + usb_free_urb(context->rx_urb); + lirc_buffer_free(context->plugin->rbuf); + kfree(context->plugin->rbuf); + kfree(context->plugin); + kfree(context); + + if (debug) + info("%s: context deleted", __FUNCTION__); +} + +static inline void deregister_from_lirc(struct imon_context *context) +{ + int retval; + int minor = context->plugin->minor; + + retval = lirc_unregister_plugin(minor); + if (retval) + err("%s: unable to deregister from lirc(%d)", + __FUNCTION__, retval); + else + info("Deregistered iMON plugin(minor:%d)", minor); + +} + +/** + * Called when the VFD device(e.g. /dev/usb/lcd) + * is opened by the application. + */ +static int vfd_open(struct inode *inode, struct file *file) +{ +#ifdef KERNEL_2_5 + struct usb_interface *interface; +#endif + struct imon_context *context = NULL; + int subminor; + int retval = SUCCESS; + + /* prevent races with disconnect */ + down(&disconnect_sem); + +#ifdef KERNEL_2_5 + subminor = iminor(inode); + interface = usb_find_interface(&imon_driver, subminor); + if (!interface) { + err("%s: could not find interface for minor %d", + __FUNCTION__, subminor); + retval = -ENODEV; + goto exit; + } + context = usb_get_intfdata(interface); +#else + subminor = MINOR(inode->i_rdev) - VFD_MINOR_BASE; + if (subminor < 0 || subminor >= MAX_DEVICES) { + err("%s: no record of minor %d", __FUNCTION__, subminor); + retval = -ENODEV; + goto exit; + } + context = minor_table[subminor]; +#endif + + if (!context) { + err("%s: no context found for minor %d", + __FUNCTION__, subminor); + retval = -ENODEV; + goto exit; + } + + LOCK_CONTEXT; + + if (!context->vfd_supported) { + err("%s: VFD not supported by device", __FUNCTION__); + retval = -ENODEV; + } else if (context->vfd_isopen) { + err("%s: VFD port is already open", __FUNCTION__); + retval = -EBUSY; + } else { + MOD_INC_USE_COUNT; + context->vfd_isopen = TRUE; + file->private_data = context; + info("VFD port opened"); + } + + UNLOCK_CONTEXT; + +exit: + up(&disconnect_sem); + return retval; +} + +/** + * Called when the VFD device(e.g. /dev/usb/lcd) + * is closed by the application. + */ +static int vfd_close(struct inode *inode, struct file *file) +{ + struct imon_context *context = NULL; + int retval = SUCCESS; + + context = (struct imon_context *) file->private_data; + + if (!context) { + err("%s: no context for device", __FUNCTION__); + return -ENODEV; + } + + LOCK_CONTEXT; + + if (!context->vfd_supported) { + err("%s: VFD not supported by device", __FUNCTION__); + retval = -ENODEV; + } else if (!context->vfd_isopen) { + err("%s: VFD is not open", __FUNCTION__); + retval = -EIO; + } else { + context->vfd_isopen = FALSE; + MOD_DEC_USE_COUNT; + info("VFD port closed"); + if (!context->dev_present && !context->ir_isopen) { + /* Device disconnected before close and IR port is not + * open. If IR port is open, context will be deleted by + * ir_close. */ + UNLOCK_CONTEXT; + delete_context(context); + return retval; + } + } + + UNLOCK_CONTEXT; + return retval; +} + +/** + * Sends a packet to the VFD. + */ +static inline int send_packet(struct imon_context *context) +{ + unsigned int pipe; + int interval = 0; + int retval = SUCCESS; + + pipe = usb_sndintpipe(context->dev, + context->tx_endpoint->bEndpointAddress); +#ifdef KERNEL_2_5 + interval = context->tx_endpoint->bInterval; +#endif /* Use 0 for 2.4 kernels */ + + usb_fill_int_urb(context->tx_urb, context->dev, pipe, + context->usb_tx_buf, sizeof(context->usb_tx_buf), + usb_tx_callback, context, interval); + + context->tx_urb->actual_length = 0; + + init_completion(&context->tx.finished); + atomic_set(&(context->tx.busy), 1); + +#ifdef KERNEL_2_5 + retval = usb_submit_urb(context->tx_urb, GFP_KERNEL); +#else + retval = usb_submit_urb(context->tx_urb); +#endif + if (retval != SUCCESS) { + atomic_set(&(context->tx.busy), 0); + err("%s: error submitting urb(%d)", __FUNCTION__, retval); + } else { + /* Wait for tranmission to complete(or abort) */ + UNLOCK_CONTEXT; + wait_for_completion(&context->tx.finished); + LOCK_CONTEXT; + + retval = context->tx.status; + if (retval != SUCCESS) + err("%s: packet tx failed(%d)", __FUNCTION__, retval); + } + + return retval; +} + +/** + * Sends an associate packet to the iMON 2.4G. + * + * This might not be such a good idea, since it has an id + * collition with some versions of the "IR & VFD" combo. + * The only way to determine if it is a RF version is to look + * at the product description string.(Which we currently do + * not fetch). + */ +static inline int send_associate_24g(struct imon_context *context) +{ + int retval; + const unsigned char packet[8] = { 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20 }; + + if (!context) { + err("%s: no context for device", __FUNCTION__); + return -ENODEV; + } + + LOCK_CONTEXT; + + if (!context->dev_present) { + err("%s: no iMON device present", __FUNCTION__); + retval = -ENODEV; + goto exit; + } + + memcpy(context->usb_tx_buf, packet, sizeof(packet)); + retval = send_packet(context); + +exit: + UNLOCK_CONTEXT; + + return retval; +} + +#ifdef KERNEL_2_5 +/** + * This is the sysfs functions to handle the association og the iMON 2.4G LT. + * + * + */ + +static ssize_t show_associate_remote(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct imon_context *context = dev_get_drvdata(d); + + if (!context) + return -ENODEV; + + if (context->ir_isassociating) { + strcpy(buf, "The device it associating press some button " + "on the remote.\n"); + } else if (context->ir_isopen) { + strcpy(buf, "Device is open and ready to associate.\n" + "Echo something into this file to start " + "the process.\n"); + } else { + strcpy(buf, "Device is closed, you need to open it to " + "associate the remote(you can use irw).\n"); + } + return strlen(buf); +} + +static ssize_t store_associate_remote(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct imon_context *context; + + context = dev_get_drvdata(d); + + if (!context) + return -ENODEV; + + if (!context->ir_isopen) + return -EINVAL; + + if (context->ir_isopen) { + context->ir_isassociating = TRUE; + send_associate_24g(context); + } + + return count; +} + +static DEVICE_ATTR(associate_remote, S_IWUSR | S_IRUGO, show_associate_remote, + store_associate_remote); + +static struct attribute *imon_sysfs_entries[] = { + &dev_attr_associate_remote.attr, + NULL +}; + +static struct attribute_group imon_attribute_group = { + .attrs = imon_sysfs_entries +}; + +#endif + + + +/** + * Writes data to the VFD. The IMON VFD is 2x16 characters + * and requires data in 5 consecutive USB interrupt packets, + * each packet but the last carrying 7 bytes. + * + * I don't know if the VFD board supports features such as + * scrolling, clearing rows, blanking, etc. so at + * the caller must provide a full screen of data. If fewer + * than 32 bytes are provided spaces will be appended to + * generate a full screen. + */ +static ssize_t vfd_write(struct file *file, const char *buf, + size_t n_bytes, loff_t *pos) +{ + int i; + int offset; + int seq; + int retval = SUCCESS; + struct imon_context *context; + + context = (struct imon_context *) file->private_data; + if (!context) { + err("%s: no context for device", __FUNCTION__); + return -ENODEV; + } + + LOCK_CONTEXT; + + if (!context->dev_present) { + err("%s: no iMON device present", __FUNCTION__); + retval = -ENODEV; + goto exit; + } + + if (n_bytes <= 0 || n_bytes > 32) { + err("%s: invalid payload size", __FUNCTION__); + retval = -EINVAL; + goto exit; + } + + if (copy_from_user(context->tx.data_buf, buf, n_bytes)) + return -EFAULT; + + /* Pad with spaces */ + for (i = n_bytes; i < 32; ++i) + context->tx.data_buf[i] = ' '; + + for (i = 32; i < 35; ++i) + context->tx.data_buf[i] = 0xFF; + + offset = 0; + seq = 0; + + do { + memcpy(context->usb_tx_buf, context->tx.data_buf + offset, 7); + context->usb_tx_buf[7] = (unsigned char) seq; + + retval = send_packet(context); + if (retval != SUCCESS) { + err("%s: send packet failed for packet #%d", + __FUNCTION__, seq/2); + goto exit; + } else { + seq += 2; + offset += 7; + } + + } while (offset < 35); + + if (context->vfd_proto_6p) { + /* Send packet #6 */ + memcpy(context->usb_tx_buf, vfd_packet6, 7); + context->usb_tx_buf[7] = (unsigned char) seq; + retval = send_packet(context); + if (retval != SUCCESS) + err("%s: send packet failed for packet #%d", + __FUNCTION__, seq/2); + } + +exit: + UNLOCK_CONTEXT; + + return(retval == SUCCESS) ? n_bytes : retval; +} + +/** + * Writes data to the LCD. The iMON OEM LCD screen excepts 8-byte + * packets. We accept data as 16 hexadecimal digits, followed by a + * newline (to make it easy to drive the device from a command-line + * -- even though the actual binary data is a bit complicated). + * + * The device itself is not a "traditional" text-mode display. It's + * actually a 16x96 pixel bitmap display. That means if you want to + * display text, you've got to have your own "font" and translate the + * text into bitmaps for display. This is really flexible (you can + * display whatever diacritics you need, and so on), but it's also + * a lot more complicated than most LCDs... + */ +static ssize_t lcd_write(struct file *file, const char *buf, + size_t n_bytes, loff_t *pos) +{ + int retval = SUCCESS; + struct imon_context *context; + + context = (struct imon_context *) file->private_data; + if (!context) { + err("%s: no context for device", __FUNCTION__); + return -ENODEV; + } + + LOCK_CONTEXT; + + if (!context->dev_present) { + err("%s: no iMON device present", __FUNCTION__); + retval = -ENODEV; + goto exit; + } + + if (n_bytes != 8) { + err("%s: invalid payload size: %d (expecting 8)", + __FUNCTION__, (int) n_bytes); + retval = -EINVAL; + goto exit; + } + + if (copy_from_user(context->usb_tx_buf, buf, 8)) + return -EFAULT; + + retval = send_packet(context); + if (retval != SUCCESS) { + err("%s: send packet failed!", + __FUNCTION__); + goto exit; + } else if (debug) { + info("%s: write %d bytes to LCD", __FUNCTION__, (int) n_bytes); + } +exit: + UNLOCK_CONTEXT; + return (retval == SUCCESS) ? n_bytes : retval; +} + +/** + * Callback function for USB core API: transmit data + */ +#if defined(KERNEL_2_5) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void usb_tx_callback(struct urb *urb, struct pt_regs *regs) +#else +static void usb_tx_callback(struct urb *urb) +#endif +{ + struct imon_context *context; + + if (!urb) + return; + context = (struct imon_context *) urb->context; + if (!context) + return; + + context->tx.status = urb->status; + + /* notify waiters that write has finished */ + atomic_set(&context->tx.busy, 0); + complete(&context->tx.finished); + + return; +} + +/** + * Called by lirc_dev when the application opens /dev/lirc + */ +static int ir_open(void *data) +{ + int retval = SUCCESS; + struct imon_context *context; + + /* prevent races with disconnect */ + down(&disconnect_sem); + + context = (struct imon_context *) data; + + LOCK_CONTEXT; + + if (context->ir_isopen) { + err("%s: IR port is already open", __FUNCTION__); + retval = -EBUSY; + goto exit; + } + + /* initial IR protocol decode variables */ + context->rx.count = 0; + context->rx.initial_space = 1; + context->rx.prev_bit = 0; + + /* init pad context for pad2keys */ + context ->key_x = 0; + context ->key_y = 0; + context ->last_count = 0; + + usb_fill_int_urb(context->rx_urb, context->dev, + usb_rcvintpipe(context->dev, + context->rx_endpoint->bEndpointAddress), + context->usb_rx_buf, sizeof(context->usb_rx_buf), + usb_rx_callback, context, context->rx_endpoint->bInterval); + +#ifdef KERNEL_2_5 + retval = usb_submit_urb(context->rx_urb, GFP_KERNEL); +#else + retval = usb_submit_urb(context->rx_urb); +#endif + + if (retval) + err("%s: usb_submit_urb failed for ir_open(%d)", + __FUNCTION__, retval); + else { + MOD_INC_USE_COUNT; + context->ir_isopen = TRUE; + info("IR port opened"); + } + +exit: + UNLOCK_CONTEXT; + + up(&disconnect_sem); + return SUCCESS; +} + +/** + * Called by lirc_dev when the application closes /dev/lirc + */ +static void ir_close(void *data) +{ + struct imon_context *context; + + context = (struct imon_context *)data; + if (!context) { + err("%s: no context for device", __FUNCTION__); + return; + } + + LOCK_CONTEXT; + + usb_kill_urb(context->rx_urb); + context->ir_isopen = FALSE; + context->ir_isassociating = FALSE; + MOD_DEC_USE_COUNT; + info("IR port closed"); + + if (!context->dev_present) { + /* Device disconnected while IR port was + * still open. Plugin was not deregistered + * at disconnect time, so do it now. */ + deregister_from_lirc(context); + + if (!context->vfd_isopen) { + UNLOCK_CONTEXT; + delete_context(context); + return; + } + /* If VFD port is open, context will be deleted by vfd_close */ + } + + UNLOCK_CONTEXT; + return; +} + +/** + * Convert bit count to time duration(in us) and submit + * the value to lirc_dev. + */ +static inline void submit_data(struct imon_context *context) +{ + unsigned char buf[4]; + int value = context->rx.count; + int i; + + if (debug) + info("submitting data to LIRC\n"); + + value *= BIT_DURATION; + value &= PULSE_MASK; + if (context->rx.prev_bit) + value |= PULSE_BIT; + + for (i = 0; i < 4; ++i) + buf[i] = value>>(i*8); + + lirc_buffer_write_1(context->plugin->rbuf, buf); + wake_up(&context->plugin->rbuf->wait_poll); + return; +} + +/** + * Process the incoming packet + */ +static inline void incoming_packet(struct imon_context *context, + struct urb *urb) +{ + int len = urb->actual_length; + unsigned char *buf = urb->transfer_buffer; + int octet, bit; + unsigned char mask; + int chunk_num; +#ifdef DEBUG + int i; +#endif + + if (len != 8) { + warn("%s: invalid incoming packet size(%d)", + __FUNCTION__, len); + return; + } + + /* iMON 2.4G associate frame */ + if (buf[0] == 0x00 && + buf[2] == 0xFF && /* REFID */ + buf[3] == 0xFF && + buf[4] == 0xFF && + buf[5] == 0xFF && /* iMON 2.4G */ + ((buf[6] == 0x4E && buf[7] == 0xDF) || /* LT */ + (buf[6] == 0x5E && buf[7] == 0xDF))) { /* DT */ + warn("%s: remote associated refid=%02X", __FUNCTION__, buf[1]); + context->ir_isassociating = FALSE; + } + + chunk_num = buf[7]; + + if (chunk_num == 0xFF) + return; /* filler frame, no data here */ + + if (buf[0] == 0xFF && + buf[1] == 0xFF && + buf[2] == 0xFF && + buf[3] == 0xFF && + buf[4] == 0xFF && + buf[5] == 0xFF && /* iMON 2.4G */ + ((buf[6] == 0x4E && buf[7] == 0xAF) || /* LT */ + (buf[6] == 0x5E && buf[7] == 0xAF))) /* DT */ + return; /* filler frame, no data here */ + +#ifdef DEBUG + for (i = 0; i < 8; ++i) + printk(KERN_INFO "%02x ", buf[i]); + printk(KERN_INFO "\n"); +#endif + + if (context->ir_onboard_decode) { + /* The signals have been decoded onboard the iMON controller */ + + if (pad2keys_active) + { + /* imon pad2keys patch + * + * make PAD and mouse buttons available for use with VDR, + * based on pad-mouse-emu patch from venky's forum + * + * last change: M.Brakemeier 2007-10-14 + * + * generated PAD key codes: + * Mouse_N 0x690281B7 + * Mouse_S 0x688291B7 + * Mouse_W 0x6A8281B7 + * Mouse_E 0x688A81B7 + * + * mouse buttons (non-synthetic): + * MouseRightClick 0x688481B7 + * MouseLeftClick 0x688301B7 + */ + if((buf[0] & 0x40) && + !(buf[1] & 0x01 || buf[1] >> 2 & 0x01)) + { + int rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 | (buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6; + int rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 | (buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6; + + if(buf[0] & 0x02) + rel_x |= ~0x10+1; + if(buf[0] & 0x01) + rel_y |= ~0x10+1; + + /* keyboard direction key emulation */ + if( context->last_count > 32 ) + { /* Hopefully eliminate drift*/ + context->last_count=0; + context->key_y=0; + context->key_x=0; + } + context->last_count++; + + /* limit decoded events */ + if(abs(context->key_x) > CURSOR_LIMIT || abs(context->key_y) > CURSOR_LIMIT ) + { + if(abs(context->key_y ) > abs(context->key_x)) + { /* mouse s/n */ + if(context->key_y > 0 && rel_y > 0) + { /* mouse s */ + buf[0] = 0x68; + buf[1] = 0x82; + buf[2] = 0x91; + } + else if(context->key_y < 0 && rel_y < 0) + { /* mouse n */ + buf[0] = 0x69; + buf[1] = 0x02; + buf[2] = 0x81; + } + } + else + { /* mouse e/w*/ + if(context->key_x > 0 && rel_x > 0 ) + { /* mouse e */ + buf[0] = 0x68; + buf[1] = 0x8A; + buf[2] = 0x81; + } + else if(context->key_x < 0 && rel_x < 0 ) + { /* mouse w */ + buf[0] = 0x6A; + buf[1] = 0x82; + buf[2] = 0x81; + } + } + } + else + { + context->key_x += rel_x; + context->key_y += rel_y; + + return; /* discard those key codes */ + } + } + /* a key was pressed, reset count */ + context->key_x = 0; + context->key_y = 0; + context->last_count = 0; + } + + lirc_buffer_write_1(context->plugin->rbuf, buf); + wake_up(&context->plugin->rbuf->wait_poll); + return; + } + + /* Translate received data to pulse and space lengths. + * Received data is active low, i.e. pulses are 0 and + * spaces are 1. + * + * My original algorithm was essentially similar to + * Changwoo Ryu's with the exception that he switched + * the incoming bits to active high and also fed an + * initial space to LIRC at the start of a new sequence + * if the previous bit was a pulse. + * + * I've decided to adopt his algorithm. */ + + if (chunk_num == 1 && context->rx.initial_space) { + /* LIRC requires a leading space */ + context->rx.prev_bit = 0; + context->rx.count = 4; + submit_data(context); + context->rx.count = 0; + } + + for (octet = 0; octet < 5; ++octet) { + mask = 0x80; + for (bit = 0; bit < 8; ++bit) { + int curr_bit = !(buf[octet] & mask); + if (curr_bit != context->rx.prev_bit) { + if (context->rx.count) { + submit_data(context); + context->rx.count = 0; + } + context->rx.prev_bit = curr_bit; + } + ++context->rx.count; + mask >>= 1; + } + } + + if (chunk_num == 10) { + if (context->rx.count) { + submit_data(context); + context->rx.count = 0; + } + context->rx.initial_space = context->rx.prev_bit; + } +} + +/** + * Callback function for USB core API: receive data + */ +#if defined(KERNEL_2_5) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void usb_rx_callback(struct urb *urb, struct pt_regs *regs) +#else +static void usb_rx_callback(struct urb *urb) +#endif +{ + struct imon_context *context; + + if (!urb) + return; + context = (struct imon_context *) urb->context; + if (!context) + return; + + switch (urb->status) { + case -ENOENT: /* usbcore unlink successful! */ + return; + case SUCCESS: + if (context->ir_isopen) + incoming_packet(context, urb); + break; + default : + warn("%s: status(%d): ignored", __FUNCTION__, urb->status); + break; + } + +#ifdef KERNEL_2_5 + usb_submit_urb(context->rx_urb, GFP_ATOMIC); +#endif + return; +} + + + +/** + * Callback function for USB core API: Probe + */ +#ifdef KERNEL_2_5 +static int imon_probe(struct usb_interface *interface, + const struct usb_device_id *id) +#else +static void *imon_probe(struct usb_device *dev, unsigned int intf, + const struct usb_device_id *id) +#endif +{ +#ifdef KERNEL_2_5 + struct usb_device *dev = NULL; + struct usb_host_interface *iface_desc = NULL; +#else + struct usb_interface *interface = NULL; + struct usb_interface_descriptor *iface_desc = NULL; + char name[10]; + int subminor = 0; +#endif + struct usb_endpoint_descriptor *rx_endpoint = NULL; + struct usb_endpoint_descriptor *tx_endpoint = NULL; + struct urb *rx_urb = NULL; + struct urb *tx_urb = NULL; + struct lirc_plugin *plugin = NULL; + struct lirc_buffer *rbuf = NULL; + int lirc_minor = 0; + int num_endpoints; + int retval = SUCCESS; + int vfd_ep_found; + int ir_ep_found; + int alloc_status; + int vfd_proto_6p = FALSE; + int ir_onboard_decode = FALSE; + struct imon_context *context = NULL; + int i; + + info("%s: found IMON device", __FUNCTION__); + + /* + * If it's the LCD, as opposed to the VFD, we just need to replace + * the "write" file op. + */ + if (is_lcd) + vfd_fops.write = &lcd_write; + +#if !defined(KERNEL_2_5) + for (subminor = 0; subminor < MAX_DEVICES; ++subminor) { + if (minor_table[subminor] == NULL) + break; + } + if (subminor == MAX_DEVICES) { + err("%s: allowed max number of devices already present", + __FUNCTION__); + retval = -ENOMEM; + goto exit; + } +#endif + +#ifdef KERNEL_2_5 + dev = usb_get_dev(interface_to_usbdev(interface)); + iface_desc = interface->cur_altsetting; + num_endpoints = iface_desc->desc.bNumEndpoints; +#else + interface = &dev->actconfig->interface[intf]; + iface_desc = &interface->altsetting[interface->act_altsetting]; + num_endpoints = iface_desc->bNumEndpoints; +#endif + + /* + * Scan the endpoint list and set: + * first input endpoint = IR endpoint + * first output endpoint = VFD endpoint + */ + + ir_ep_found = FALSE; + vfd_ep_found = FALSE; + + for (i = 0; i < num_endpoints && !(ir_ep_found && vfd_ep_found); ++i) { + struct usb_endpoint_descriptor *ep; + int ep_dir; + int ep_type; +#ifdef KERNEL_2_5 + ep = &iface_desc->endpoint[i].desc; +#else + ep = &iface_desc->endpoint[i]; +#endif + ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; + ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + + if (!ir_ep_found && + ep_dir == USB_DIR_IN && + ep_type == USB_ENDPOINT_XFER_INT) { + + rx_endpoint = ep; + ir_ep_found = TRUE; + if (debug) + info("%s: found IR endpoint", __FUNCTION__); + + } else if (!vfd_ep_found && + ep_dir == USB_DIR_OUT && + ep_type == USB_ENDPOINT_XFER_INT) { + tx_endpoint = ep; + vfd_ep_found = TRUE; + if (debug) + info("%s: found VFD endpoint", __FUNCTION__); + } + } + + /* Input endpoint is mandatory */ + if (!ir_ep_found) { + err("%s: no valid input(IR) endpoint found.", __FUNCTION__); + retval = -ENODEV; + goto exit; + } else { + /* Determine if the IR signals are decoded onboard */ + unsigned short product_id; + unsigned short *id_list_item; + + product_id = cpu_to_le16(dev->descriptor.idProduct); + id_list_item = ir_onboard_decode_product_list; + while (*id_list_item) { + if (*id_list_item++ == product_id) { + ir_onboard_decode = TRUE; + break; + } + } + + if (debug) + info("ir_onboard_decode: %d", ir_onboard_decode); + } + + /* Determine if VFD requires 6 packets */ + if (vfd_ep_found) { + unsigned short vendor_id; + unsigned short *id_list_item; + + vendor_id = cpu_to_le16(dev->descriptor.idVendor); + id_list_item = vfd_proto_6p_vendor_list; + while (*id_list_item) { + if (*id_list_item++ == vendor_id) { + vfd_proto_6p = TRUE; + break; + } + } + + if (debug) + info("vfd_proto_6p: %d", vfd_proto_6p); + } + + + /* Allocate memory */ + + alloc_status = SUCCESS; + + context = kmalloc(sizeof(struct imon_context), GFP_KERNEL); + if (!context) { + err("%s: kmalloc failed for context", __FUNCTION__); + alloc_status = 1; + goto alloc_status_switch; + } + plugin = kmalloc(sizeof(struct lirc_plugin), GFP_KERNEL); + if (!plugin) { + err("%s: kmalloc failed for lirc_plugin", __FUNCTION__); + alloc_status = 2; + goto alloc_status_switch; + } + rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); + if (!rbuf) { + err("%s: kmalloc failed for lirc_buffer", __FUNCTION__); + alloc_status = 3; + goto alloc_status_switch; + } + if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) { + err("%s: lirc_buffer_init failed", __FUNCTION__); + alloc_status = 4; + goto alloc_status_switch; + } +#ifdef KERNEL_2_5 + rx_urb = usb_alloc_urb(0, GFP_KERNEL); +#else + rx_urb = usb_alloc_urb(0); +#endif + if (!rx_urb) { + err("%s: usb_alloc_urb failed for IR urb", __FUNCTION__); + alloc_status = 5; + goto alloc_status_switch; + } + if (vfd_ep_found) { +#ifdef KERNEL_2_5 + tx_urb = usb_alloc_urb(0, GFP_KERNEL); +#else + tx_urb = usb_alloc_urb(0); +#endif + if (!tx_urb) { + err("%s: usb_alloc_urb failed for VFD urb", + __FUNCTION__); + alloc_status = 6; + goto alloc_status_switch; + } + } + + /* clear all members of imon_context and lirc_plugin */ + memset(context, 0, sizeof(struct imon_context)); + init_MUTEX(&context->sem); + context->vfd_proto_6p = vfd_proto_6p; + context->ir_onboard_decode = ir_onboard_decode; + + memset(plugin, 0, sizeof(struct lirc_plugin)); + + strcpy(plugin->name, MOD_NAME); + plugin->minor = -1; + plugin->code_length = (ir_onboard_decode) ? + 32 : sizeof(lirc_t) * 8; + plugin->sample_rate = 0; + plugin->features = (ir_onboard_decode) ? + LIRC_CAN_REC_LIRCCODE : LIRC_CAN_REC_MODE2; + plugin->data = context; + plugin->rbuf = rbuf; + plugin->set_use_inc = ir_open; + plugin->set_use_dec = ir_close; +#ifdef LIRC_HAVE_SYSFS + plugin->dev = &dev->dev; +#endif + plugin->owner = THIS_MODULE; + + LOCK_CONTEXT; + + lirc_minor = lirc_register_plugin(plugin); + if (lirc_minor < 0) { + err("%s: lirc_register_plugin failed", __FUNCTION__); + alloc_status = 7; + UNLOCK_CONTEXT; + goto alloc_status_switch; + } else + info("%s: Registered iMON plugin(minor:%d)", + __FUNCTION__, lirc_minor); + +alloc_status_switch: + + switch (alloc_status) { + case 7: + if (vfd_ep_found) + usb_free_urb(tx_urb); + case 6: + usb_free_urb(rx_urb); + case 5: + lirc_buffer_free(rbuf); + case 4: + kfree(rbuf); + case 3: + kfree(plugin); + case 2: + kfree(context); + context = NULL; + case 1: + retval = -ENOMEM; + } + + /* Needed while unregistering! */ + plugin->minor = lirc_minor; + + context->dev = dev; + context->dev_present = TRUE; + context->rx_endpoint = rx_endpoint; + context->rx_urb = rx_urb; + if (vfd_ep_found) { + context->vfd_supported = TRUE; + context->tx_endpoint = tx_endpoint; + context->tx_urb = tx_urb; + } + context->plugin = plugin; + +#ifdef KERNEL_2_5 + usb_set_intfdata(interface, context); + + if (cpu_to_le16(dev->descriptor.idProduct) == 0xffdc) { + int err; + + err = sysfs_create_group(&interface->dev.kobj, + &imon_attribute_group); + if (err) + err("%s: Could not create sysfs entries(%d)", + __FUNCTION__, err); + } +#else + minor_table[subminor] = context; + context->subminor = subminor; +#endif + + if (vfd_ep_found) { + if (debug) + info("Registering VFD with devfs"); +#ifdef KERNEL_2_5 + if (usb_register_dev(interface, &imon_class)) { + /* Not a fatal error, so ignore */ + info("%s: could not get a minor number for VFD", + __FUNCTION__); + } +#else + sprintf(name, DEVFS_NAME, subminor); + if (!(context->devfs = devfs_register(usb_devfs_handle, name, + DEVFS_FL_DEFAULT, + USB_MAJOR, VFD_MINOR_BASE + subminor, + DEVFS_MODE, &vfd_fops, NULL))) { + /* not a fatal error so ignore */ + info("%s: devfs register failed for VFD", + __FUNCTION__); + } +#endif + } + + info("%s: iMON device on usb<%d:%d> initialized", + __FUNCTION__, dev->bus->busnum, dev->devnum); + + UNLOCK_CONTEXT; + + exit: +#ifdef KERNEL_2_5 + return retval; +#else + return (retval == SUCCESS) ? context : NULL; +#endif +} + +/** + * Callback function for USB core API: disonnect + */ +#ifdef KERNEL_2_5 +static void imon_disconnect(struct usb_interface *interface) +#else +static void imon_disconnect(struct usb_device *dev, void *data) +#endif +{ + struct imon_context *context; + + /* prevent races with ir_open()/vfd_open() */ + down(&disconnect_sem); + +#ifdef KERNEL_2_5 + context = usb_get_intfdata(interface); +#else + context = (struct imon_context *)data; +#endif + LOCK_CONTEXT; + + info("%s: iMON device disconnected", __FUNCTION__); + +#ifdef KERNEL_2_5 + /* sysfs_remove_group is safe to call even if sysfs_create_group + * hasn't been called */ + sysfs_remove_group(&interface->dev.kobj, + &imon_attribute_group); + usb_set_intfdata(interface, NULL); +#else + minor_table[context->subminor] = NULL; +#endif + context->dev_present = FALSE; + + /* Stop reception */ + usb_kill_urb(context->rx_urb); + + /* Abort ongoing write */ + if (atomic_read(&context->tx.busy)) { + usb_kill_urb(context->tx_urb); + wait_for_completion(&context->tx.finished); + } + + /* De-register from lirc_dev if IR port is not open */ + if (!context->ir_isopen) + deregister_from_lirc(context); + + if (context->vfd_supported) +#ifdef KERNEL_2_5 + usb_deregister_dev(interface, &imon_class); +#else + if (context->devfs) + devfs_unregister(context->devfs); +#endif + + UNLOCK_CONTEXT; + + if (!context->ir_isopen && !context->vfd_isopen) + delete_context(context); + + up(&disconnect_sem); +} + +static int __init imon_init(void) +{ + int rc; + + info(MOD_DESC ", v" MOD_VERSION); + info(MOD_AUTHOR); + + rc = usb_register(&imon_driver); + if (rc) { + err("%s: usb register failed(%d)", __FUNCTION__, rc); + return -ENODEV; + } + return SUCCESS; +} + +static void __exit imon_exit(void) +{ + usb_deregister(&imon_driver); + info("module removed. Goodbye!"); +} + + +module_init(imon_init); +module_exit(imon_exit); + +#if !defined(KERNEL_2_5) +EXPORT_NO_SYMBOLS; +#endif --- linux-2.6.27.orig/ubuntu/lirc/lirc_imon/Makefile +++ linux-2.6.27/ubuntu/lirc/lirc_imon/Makefile @@ -0,0 +1,3 @@ +EXTRA_CFLAGS =-DIRCTL_DEV_MAJOR=61 -DLIRC_SERIAL_TRANSMITTER -DLIRC_SERIAL_SOFTCARRIER -I$(src)/.. + +obj-$(CONFIG_LIRC_IMON) += lirc_imon.o --- linux-2.6.27.orig/ubuntu/lirc/lirc_serial_igor/Makefile +++ linux-2.6.27/ubuntu/lirc/lirc_serial_igor/Makefile @@ -0,0 +1,4 @@ + +EXTRA_CFLAGS =-DIRCTL_DEV_MAJOR=61 -DLIRC_SERIAL_TRANSMITTER -DLIRC_SERIAL_SOFTCARRIER -I$(src)/.. + +obj-$(CONFIG_LIRC_SERIAL_IGOR) += lirc_serial_igor.o --- linux-2.6.27.orig/ubuntu/lirc/lirc_serial_igor/lirc_serial_igor.c +++ linux-2.6.27/ubuntu/lirc/lirc_serial_igor/lirc_serial_igor.c @@ -0,0 +1,1341 @@ +/* $Id: lirc_serial.c,v 5.87 2007/12/15 17:28:01 lirc Exp $ */ + +/**************************************************************************** + ** lirc_serial.c *********************************************************** + **************************************************************************** + * + * lirc_serial - Device driver that records pulse- and pause-lengths + * (space-lengths) between DDCD event on a serial port. + * + * Copyright (C) 1996,97 Ralph Metzler + * Copyright (C) 1998 Trent Piepho + * Copyright (C) 1998 Ben Pfaff + * Copyright (C) 1999 Christoph Bartelmus + * Copyright (C) 2007 Andrei Tanas (suspend/resume support) + * Copyright (C) 2007 Mario Limonciello Compile for Ubuntu with igor support + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* Steve's changes to improve transmission fidelity: + - for systems with the rdtsc instruction and the clock counter, a + send_pule that times the pulses directly using the counter. + This means that the LIRC_SERIAL_TRANSMITTER_LATENCY fudge is + not needed. Measurement shows very stable waveform, even where + PCI activity slows the access to the UART, which trips up other + versions. + - For other system, non-integer-microsecond pulse/space lengths, + done using fixed point binary. So, much more accurate carrier + frequency. + - fine tuned transmitter latency, taking advantage of fractional + microseconds in previous change + - Fixed bug in the way transmitter latency was accounted for by + tuning the pulse lengths down - the send_pulse routine ignored + this overhead as it timed the overall pulse length - so the + pulse frequency was right but overall pulse length was too + long. Fixed by accounting for latency on each pulse/space + iteration. + + Steve Davies July 2001 +*/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) +#error "**********************************************************" +#error " Sorry, this driver needs kernel version 2.2.18 or higher " +#error "**********************************************************" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) +#include +#endif + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) +#include +#else +#include +#endif +#include +#include +#include + +#if defined(LIRC_SERIAL_NSLU2) +#include +/* From Intel IXP42X Developer's Manual (#252480-005): */ +/* ftp://download.intel.com/design/network/manuals/25248005.pdf */ +#define UART_IE_IXP42X_UUE 0x40 /* IXP42X UART Unit enable */ +#define UART_IE_IXP42X_RTOIE 0x10 /* IXP42X Receiver Data Timeout int.enable */ +#ifndef NSLU2_LED_GRN_GPIO +/* added in 2.6.22 */ +#define NSLU2_LED_GRN_GPIO NSLU2_LED_GRN +#endif +#endif + +#include "lirc.h" +#include "kcompat.h" +#include "lirc_dev/lirc_dev.h" + +#if defined(LIRC_SERIAL_SOFTCARRIER) && !defined(LIRC_SERIAL_TRANSMITTER) +#warning "Software carrier only affects transmitting" +#endif + +#if defined(rdtscl) + +#define USE_RDTSC +#warning "Note: using rdtsc instruction" +#endif + +#ifdef LIRC_SERIAL_ANIMAX +#ifdef LIRC_SERIAL_TRANSMITTER +#warning "******************************************" +#warning " This receiver does not have a " +#warning " transmitter diode " +#warning "******************************************" +#endif +#endif + +#define LIRC_DRIVER_NAME "lirc_serial_igor" + +struct lirc_serial_igor +{ + int signal_pin; + int signal_pin_change; + int on; + int off; + long (*send_pulse)(unsigned long length); + void (*send_space)(long length); + int features; +}; + +#define LIRC_HOMEBREW 0 +#define LIRC_IRDEO 1 +#define LIRC_IRDEO_REMOTE 2 +#define LIRC_ANIMAX 3 +#define LIRC_IGOR 4 +#define LIRC_NSLU2 5 + +static int type = LIRC_IGOR; + +/* Set defaults for NSLU2 */ +#if defined(LIRC_SERIAL_NSLU2) +#ifndef LIRC_IRQ +#define LIRC_IRQ IRQ_IXP4XX_UART2 +#endif +#ifndef LIRC_PORT +#define LIRC_PORT (IXP4XX_UART2_BASE_VIRT + REG_OFFSET) +#endif +#ifndef LIRC_IOMMAP +#define LIRC_IOMMAP IXP4XX_UART2_BASE_PHYS +#endif +#ifndef LIRC_IOSHIFT +#define LIRC_IOSHIFT 2 +#endif +#ifndef LIRC_ALLOW_MMAPPED_IO +#define LIRC_ALLOW_MMAPPED_IO +#endif +#endif + +#if defined(LIRC_ALLOW_MMAPPED_IO) +#ifndef LIRC_IOMMAP +#define LIRC_IOMMAP 0 +#endif +#ifndef LIRC_IOSHIFT +#define LIRC_IOSHIFT 0 +#endif +static int iommap = LIRC_IOMMAP; +static int ioshift = LIRC_IOSHIFT; +#endif + +static int softcarrier; + +static int share_irq; +static int debug; + +#define dprintk(fmt, args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ + fmt, ## args); \ + } while (0) + +/* forward declarations */ +static long send_pulse_irdeo(unsigned long length); +static long send_pulse_homebrew(unsigned long length); +static void send_space_irdeo(long length); +static void send_space_homebrew(long length); + +static struct lirc_serial_igor hardware[] = { + /* home-brew receiver/transmitter */ + { + UART_MSR_DCD, + UART_MSR_DDCD, + UART_MCR_RTS|UART_MCR_OUT2|UART_MCR_DTR, + UART_MCR_RTS|UART_MCR_OUT2, + send_pulse_homebrew, + send_space_homebrew, + ( +#ifdef LIRC_SERIAL_TRANSMITTER + LIRC_CAN_SET_SEND_DUTY_CYCLE| + LIRC_CAN_SET_SEND_CARRIER| + LIRC_CAN_SEND_PULSE| +#endif + LIRC_CAN_REC_MODE2) + }, + + /* IRdeo classic */ + { + UART_MSR_DSR, + UART_MSR_DDSR, + UART_MCR_OUT2, + UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2, + send_pulse_irdeo, + send_space_irdeo, + (LIRC_CAN_SET_SEND_DUTY_CYCLE| + LIRC_CAN_SEND_PULSE| + LIRC_CAN_REC_MODE2) + }, + + /* IRdeo remote */ + { + UART_MSR_DSR, + UART_MSR_DDSR, + UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2, + UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2, + send_pulse_irdeo, + send_space_irdeo, + (LIRC_CAN_SET_SEND_DUTY_CYCLE| + LIRC_CAN_SEND_PULSE| + LIRC_CAN_REC_MODE2) + }, + + /* AnimaX */ + { + UART_MSR_DCD, + UART_MSR_DDCD, + 0, + UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2, + NULL, + NULL, + LIRC_CAN_REC_MODE2 + }, + + /* home-brew receiver/transmitter (Igor Cesko's variation) */ + { + UART_MSR_DSR, + UART_MSR_DDSR, + UART_MCR_RTS|UART_MCR_OUT2|UART_MCR_DTR, + UART_MCR_RTS|UART_MCR_OUT2, + send_pulse_homebrew, + send_space_homebrew, + ( +#ifdef LIRC_SERIAL_TRANSMITTER + LIRC_CAN_SET_SEND_DUTY_CYCLE| + LIRC_CAN_SET_SEND_CARRIER| + LIRC_CAN_SEND_PULSE| +#endif + LIRC_CAN_REC_MODE2) + }, + +#if defined(LIRC_SERIAL_NSLU2) + /* Modified Linksys Network Storage Link USB 2.0 (NSLU2): + We receive on CTS of the 2nd serial port (R142,LHS), we + transmit with a IR diode between GPIO[1] (green status LED), + and ground (Matthias Goebl ). + See also http://www.nslu2-linux.org for this device */ + { + UART_MSR_CTS, + UART_MSR_DCTS, + UART_MCR_RTS|UART_MCR_OUT2|UART_MCR_DTR, + UART_MCR_RTS|UART_MCR_OUT2, + send_pulse_homebrew, + send_space_homebrew, + ( +#ifdef LIRC_SERIAL_TRANSMITTER + LIRC_CAN_SET_SEND_DUTY_CYCLE| + LIRC_CAN_SET_SEND_CARRIER| + LIRC_CAN_SEND_PULSE| +#endif + LIRC_CAN_REC_MODE2) + }, +#endif + +}; + +#define RS_ISR_PASS_LIMIT 256 + +/* A long pulse code from a remote might take upto 300 bytes. The + daemon should read the bytes as soon as they are generated, so take + the number of keys you think you can push before the daemon runs + and multiply by 300. The driver will warn you if you overrun this + buffer. If you have a slow computer or non-busmastering IDE disks, + maybe you will need to increase this. */ + +/* This MUST be a power of two! It has to be larger than 1 as well. */ + +#define RBUF_LEN 256 +#define WBUF_LEN 256 + +static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */ +static int txsense; /* 0 = active high, 1 = active low */ + +#ifndef LIRC_IRQ +#define LIRC_IRQ 4 +#endif +#ifndef LIRC_PORT +#define LIRC_PORT 0x3f8 +#endif + +static int io = LIRC_PORT; +static int irq = LIRC_IRQ; + +static struct timeval lasttv = {0, 0}; + +static struct lirc_buffer rbuf; + +static lirc_t wbuf[WBUF_LEN]; + +static unsigned int freq = 38000; +static unsigned int duty_cycle = 50; + +/* Initialized in init_timing_params() */ +static unsigned long period; +static unsigned long pulse_width; +static unsigned long space_width; + +#if defined(__i386__) +/* + From: + Linux I/O port programming mini-HOWTO + Author: Riku Saikkonen + v, 28 December 1997 + + [...] + Actually, a port I/O instruction on most ports in the 0-0x3ff range + takes almost exactly 1 microsecond, so if you're, for example, using + the parallel port directly, just do additional inb()s from that port + to delay. + [...] +*/ +/* transmitter latency 1.5625us 0x1.90 - this figure arrived at from + * comment above plus trimming to match actual measured frequency. + * This will be sensitive to cpu speed, though hopefully most of the 1.5us + * is spent in the uart access. Still - for reference test machine was a + * 1.13GHz Athlon system - Steve + */ + +/* changed from 400 to 450 as this works better on slower machines; + faster machines will use the rdtsc code anyway */ + +#define LIRC_SERIAL_TRANSMITTER_LATENCY 450 + +#else + +/* does anybody have information on other platforms ? */ +/* 256 = 1<<8 */ +#define LIRC_SERIAL_TRANSMITTER_LATENCY 256 + +#endif /* __i386__ */ + +static inline unsigned int sinp(int offset) +{ +#if defined(LIRC_ALLOW_MMAPPED_IO) + if (iommap != 0) { /* the register is memory-mapped */ + offset <<= ioshift; + return readb(io + offset); + } +#endif + return inb(io + offset); +} + +static inline void soutp(int offset, int value) +{ +#if defined(LIRC_ALLOW_MMAPPED_IO) + if (iommap != 0) { /* the register is memory-mapped */ + offset <<= ioshift; + writeb(value, io + offset); + } +#endif + outb(value, io + offset); +} + +static inline void on(void) +{ +#if defined(LIRC_SERIAL_NSLU2) + /* On NSLU2, we put the transmit diode between the output of the green + status LED and ground */ + if (type == LIRC_NSLU2) { + gpio_line_set(NSLU2_LED_GRN_GPIO, IXP4XX_GPIO_LOW); + return; + } +#endif + if (txsense) + soutp(UART_MCR, hardware[type].off); + else + soutp(UART_MCR, hardware[type].on); +} + +static inline void off(void) +{ +#if defined(LIRC_SERIAL_NSLU2) + if (type == LIRC_NSLU2) { + gpio_line_set(NSLU2_LED_GRN_GPIO, IXP4XX_GPIO_HIGH); + return; + } +#endif + if (txsense) + soutp(UART_MCR, hardware[type].on); + else + soutp(UART_MCR, hardware[type].off); +} + +#ifndef MAX_UDELAY_MS +#define MAX_UDELAY_US 5000 +#else +#define MAX_UDELAY_US (MAX_UDELAY_MS*1000) +#endif + +static inline void safe_udelay(unsigned long usecs) +{ + while (usecs > MAX_UDELAY_US) { + udelay(MAX_UDELAY_US); + usecs -= MAX_UDELAY_US; + } + udelay(usecs); +} + +#ifdef USE_RDTSC +/* This is an overflow/precision juggle, complicated in that we can't + do long long divide in the kernel */ + +/* When we use the rdtsc instruction to measure clocks, we keep the + * pulse and space widths as clock cycles. As this is CPU speed + * dependent, the widths must be calculated in init_port and ioctl + * time + */ + +/* So send_pulse can quickly convert microseconds to clocks */ +static unsigned long conv_us_to_clocks; + +static inline int init_timing_params(unsigned int new_duty_cycle, + unsigned int new_freq) +{ + unsigned long long loops_per_sec, work; + + duty_cycle = new_duty_cycle; + freq = new_freq; + + loops_per_sec = current_cpu_data.loops_per_jiffy; + loops_per_sec *= HZ; + + /* How many clocks in a microsecond?, avoiding long long divide */ + work = loops_per_sec; + work *= 4295; /* 4295 = 2^32 / 1e6 */ + conv_us_to_clocks = (work>>32); + + /* Carrier period in clocks, approach good up to 32GHz clock, + gets carrier frequency within 8Hz */ + period = loops_per_sec>>3; + period /= (freq>>3); + + /* Derive pulse and space from the period */ + + pulse_width = period*duty_cycle/100; + space_width = period - pulse_width; + dprintk("in init_timing_params, freq=%d, duty_cycle=%d, " + "clk/jiffy=%ld, pulse=%ld, space=%ld, " + "conv_us_to_clocks=%ld\n", + freq, duty_cycle, current_cpu_data.loops_per_jiffy, + pulse_width, space_width, conv_us_to_clocks); + return 0; +} +#else /* ! USE_RDTSC */ +static inline int init_timing_params(unsigned int new_duty_cycle, + unsigned int new_freq) +{ +/* period, pulse/space width are kept with 8 binary places - + * IE multiplied by 256. */ + if (256*1000000L/new_freq*new_duty_cycle/100 <= + LIRC_SERIAL_TRANSMITTER_LATENCY) + return(-EINVAL); + if (256*1000000L/new_freq*(100-new_duty_cycle)/100 <= + LIRC_SERIAL_TRANSMITTER_LATENCY) + return(-EINVAL); + duty_cycle = new_duty_cycle; + freq = new_freq; + period = 256*1000000L/freq; + pulse_width = period*duty_cycle/100; + space_width = period-pulse_width; + dprintk("in init_timing_params, freq=%d pulse=%ld, " + "space=%ld\n", freq, pulse_width, space_width); + return 0; +} +#endif /* USE_RDTSC */ + + +/* return value: space length delta */ + +static long send_pulse_irdeo(unsigned long length) +{ + long rawbits; + int i; + unsigned char output; + unsigned char chunk, shifted; + + /* how many bits have to be sent ? */ + rawbits = length*1152/10000; + if (duty_cycle > 50) + chunk = 3; + else + chunk = 1; + for (i = 0, output = 0x7f; rawbits > 0; rawbits -= 3) { + shifted = chunk<<(i*3); + shifted >>= 1; + output &= (~shifted); + i++; + if (i == 3) { + soutp(UART_TX, output); + while (!(sinp(UART_LSR) & UART_LSR_THRE)); + output = 0x7f; + i = 0; + } + } + if (i != 0) { + soutp(UART_TX, output); + while (!(sinp(UART_LSR) & UART_LSR_TEMT)); + } + + if (i == 0) + return ((-rawbits)*10000/1152); + else + return ((3-i)*3*10000/1152+(-rawbits)*10000/1152); +} + +#ifdef USE_RDTSC +/* Version that uses Pentium rdtsc instruction to measure clocks */ + +/* This version does sub-microsecond timing using rdtsc instruction, + * and does away with the fudged LIRC_SERIAL_TRANSMITTER_LATENCY + * Implicitly i586 architecture... - Steve + */ + +static inline long send_pulse_homebrew_softcarrier(unsigned long length) +{ + int flag; + unsigned long target, start, now; + + /* Get going quick as we can */ + rdtscl(start); on(); + /* Convert length from microseconds to clocks */ + length *= conv_us_to_clocks; + /* And loop till time is up - flipping at right intervals */ + now = start; + target = pulse_width; + flag = 1; + while ((now-start) < length) { + /* Delay till flip time */ + do + rdtscl(now); + while ((now-start) < target); + + /* flip */ + if (flag) { + rdtscl(now); off(); + target += space_width; + } else { + rdtscl(now); on(); + target += pulse_width; + } + flag = !flag; + } + rdtscl(now); + return (((now-start)-length)/conv_us_to_clocks); +} +#else /* ! USE_RDTSC */ +/* Version using udelay() */ + +/* here we use fixed point arithmetic, with 8 + fractional bits. that gets us within 0.1% or so of the right average + frequency, albeit with some jitter in pulse length - Steve */ + +/* To match 8 fractional bits used for pulse/space length */ + +static inline long send_pulse_homebrew_softcarrier(unsigned long length) +{ + int flag; + unsigned long actual, target, d; + length <<= 8; + + actual = 0; target = 0; flag = 0; + while (actual < length) { + if (flag) { + off(); + target += space_width; + } else { + on(); + target += pulse_width; + } + d = (target-actual-LIRC_SERIAL_TRANSMITTER_LATENCY+128)>>8; + /* Note - we've checked in ioctl that the pulse/space + widths are big enough so that d is > 0 */ + udelay(d); + actual += (d<<8)+LIRC_SERIAL_TRANSMITTER_LATENCY; + flag = !flag; + } + return ((actual-length)>>8); +} +#endif /* USE_RDTSC */ + +static long send_pulse_homebrew(unsigned long length) +{ + if (length <= 0) + return 0; + + if (softcarrier) + return send_pulse_homebrew_softcarrier(length); + else { + on(); + safe_udelay(length); + return 0; + } +} + +static void send_space_irdeo(long length) +{ + if (length <= 0) + return; + + safe_udelay(length); +} + +static void send_space_homebrew(long length) +{ + off(); + if (length <= 0) + return; + safe_udelay(length); +} + +static inline void rbwrite(lirc_t l) +{ + if (lirc_buffer_full(&rbuf)) { /* no new signals will be accepted */ + dprintk("Buffer overrun\n"); + return; + } + _lirc_buffer_write_1(&rbuf, (void *)&l); +} + +static inline void frbwrite(lirc_t l) +{ + /* simple noise filter */ + static lirc_t pulse = 0L, space = 0L; + static unsigned int ptr; + + if (ptr > 0 && (l&PULSE_BIT)) { + pulse += l&PULSE_MASK; + if (pulse > 250) { + rbwrite(space); + rbwrite(pulse|PULSE_BIT); + ptr = 0; + pulse = 0; + } + return; + } + if (!(l&PULSE_BIT)) { + if (ptr == 0) { + if (l > 20000) { + space = l; + ptr++; + return; + } + } else { + if (l > 20000) { + space += pulse; + if (space > PULSE_MASK) + space = PULSE_MASK; + space += l; + if (space > PULSE_MASK) + space = PULSE_MASK; + pulse = 0; + return; + } + rbwrite(space); + rbwrite(pulse|PULSE_BIT); + ptr = 0; + pulse = 0; + } + } + rbwrite(l); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) +static irqreturn_t irq_handler(int i, void *blah) +#else +static irqreturn_t irq_handler(int i, void *blah, struct pt_regs *regs) +#endif +{ + struct timeval tv; + int status, counter, dcd; + long deltv; + lirc_t data; + static int last_dcd = -1; + + if ((sinp(UART_IIR) & UART_IIR_NO_INT)) { + /* not our interrupt */ + return IRQ_RETVAL(IRQ_NONE); + } + + counter = 0; + do { + counter++; + status = sinp(UART_MSR); + if (counter > RS_ISR_PASS_LIMIT) { + printk(KERN_WARNING LIRC_DRIVER_NAME ": AIEEEE: " + "We're caught!\n"); + break; + } + if ((status&hardware[type].signal_pin_change) && sense != -1) { + /* get current time */ + do_gettimeofday(&tv); + + /* New mode, written by Trent Piepho + . */ + + /* The old format was not very portable. + We now use the type lirc_t to pass pulses + and spaces to user space. + + If PULSE_BIT is set a pulse has been + received, otherwise a space has been + received. The driver needs to know if your + receiver is active high or active low, or + the space/pulse sense could be + inverted. The bits denoted by PULSE_MASK are + the length in microseconds. Lengths greater + than or equal to 16 seconds are clamped to + PULSE_MASK. All other bits are unused. + This is a much simpler interface for user + programs, as well as eliminating "out of + phase" errors with space/pulse + autodetection. */ + + /* calculate time since last interrupt in + microseconds */ + dcd = (status & hardware[type].signal_pin) ? 1:0; + + if (dcd == last_dcd) { + printk(KERN_WARNING LIRC_DRIVER_NAME + ": ignoring spike: %d %d %lx %lx %lx %lx\n", + dcd, sense, + tv.tv_sec, lasttv.tv_sec, + tv.tv_usec, lasttv.tv_usec); + continue; + } + + deltv = tv.tv_sec-lasttv.tv_sec; + if (tv.tv_sec < lasttv.tv_sec || + (tv.tv_sec == lasttv.tv_sec && + tv.tv_usec < lasttv.tv_usec)) { + printk(KERN_WARNING LIRC_DRIVER_NAME + ": AIEEEE: your clock just jumped " + "backwards\n"); + printk(KERN_WARNING LIRC_DRIVER_NAME + ": %d %d %lx %lx %lx %lx\n", + dcd, sense, + tv.tv_sec, lasttv.tv_sec, + tv.tv_usec, lasttv.tv_usec); + data = PULSE_MASK; + } else if (deltv > 15) { + data = PULSE_MASK; /* really long time */ + if (!(dcd^sense)) { /* sanity check */ + printk(KERN_WARNING LIRC_DRIVER_NAME + ": AIEEEE: " + "%d %d %lx %lx %lx %lx\n", + dcd, sense, + tv.tv_sec, lasttv.tv_sec, + tv.tv_usec, lasttv.tv_usec); + /* detecting pulse while this + MUST be a space! */ + sense = sense ? 0:1; + } + } else + data = (lirc_t) (deltv*1000000 + + tv.tv_usec - + lasttv.tv_usec); + frbwrite(dcd^sense ? data : (data|PULSE_BIT)); + lasttv = tv; + last_dcd = dcd; + wake_up_interruptible(&rbuf.wait_poll); + } + } while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */ + return IRQ_RETVAL(IRQ_HANDLED); +} + +static void hardware_init_port(void) +{ + unsigned long flags; + local_irq_save(flags); + + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + /* First of all, disable all interrupts */ + soutp(UART_IER, sinp(UART_IER) & + (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); + + /* Clear registers. */ + sinp(UART_LSR); + sinp(UART_RX); + sinp(UART_IIR); + sinp(UART_MSR); + +#if defined(LIRC_SERIAL_NSLU2) + if (type == LIRC_NSLU2) { /* Setup NSLU2 UART */ + /* Enable UART */ + soutp(UART_IER, sinp(UART_IER) | UART_IE_IXP42X_UUE); + /* Disable Receiver data Time out interrupt */ + soutp(UART_IER, sinp(UART_IER) & ~UART_IE_IXP42X_RTOIE); + /* set out2 = interupt unmask; off() doesn't set MCR + on NSLU2 */ + soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); + } +#endif + + /* Set line for power source */ + off(); + + /* Clear registers again to be sure. */ + sinp(UART_LSR); + sinp(UART_RX); + sinp(UART_IIR); + sinp(UART_MSR); + + switch (type) { + case LIRC_IRDEO: + case LIRC_IRDEO_REMOTE: + /* setup port to 7N1 @ 115200 Baud */ + /* 7N1+start = 9 bits at 115200 ~ 3 bits at 38kHz */ + + /* Set DLAB 1. */ + soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); + /* Set divisor to 1 => 115200 Baud */ + soutp(UART_DLM, 0); + soutp(UART_DLL, 1); + /* Set DLAB 0 + 7N1 */ + soutp(UART_LCR, UART_LCR_WLEN7); + /* THR interrupt already disabled at this point */ + break; + default: + break; + } + + local_irq_restore(flags); +} + +static int init_port(void) +{ + int i, nlow, nhigh; + + /* Reserve io region. */ +#if defined(LIRC_ALLOW_MMAPPED_IO) + /* Future MMAP-Developers: Attention! + For memory mapped I/O you *might* need to use ioremap() first, + for the NSLU2 it's done in boot code. */ + if (((iommap != 0) + && (request_mem_region(iommap, 8<= nhigh ? 1 : 0); + printk(KERN_INFO LIRC_DRIVER_NAME ": auto-detected active " + "%s receiver\n", sense ? "low":"high"); + } else + printk(KERN_INFO LIRC_DRIVER_NAME ": Manually using active " + "%s receiver\n", sense ? "low":"high"); + + return 0; +} + +static int set_use_inc(void *data) +{ + int result; + unsigned long flags; + + /* Init read buffer. */ + if (lirc_buffer_init(&rbuf, sizeof(lirc_t), RBUF_LEN) < 0) + return -ENOMEM; + + /* initialize timestamp */ + do_gettimeofday(&lasttv); + + result = request_irq(irq, irq_handler, + IRQF_DISABLED | (share_irq ? IRQF_SHARED:0), + LIRC_DRIVER_NAME, (void *)&hardware); + + switch (result) { + case -EBUSY: + printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq); + lirc_buffer_free(&rbuf); + return -EBUSY; + case -EINVAL: + printk(KERN_ERR LIRC_DRIVER_NAME + ": Bad irq number or handler\n"); + lirc_buffer_free(&rbuf); + return -EINVAL; + default: + dprintk("Interrupt %d, port %04x obtained\n", irq, io); + break; + }; + + local_irq_save(flags); + + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); + + local_irq_restore(flags); + + MOD_INC_USE_COUNT; + return 0; +} + +static void set_use_dec(void *data) +{ unsigned long flags; + + local_irq_save(flags); + + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + /* First of all, disable all interrupts */ + soutp(UART_IER, sinp(UART_IER) & + (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); + local_irq_restore(flags); + + free_irq(irq, (void *)&hardware); + + dprintk("freed IRQ %d\n", irq); + lirc_buffer_free(&rbuf); + + MOD_DEC_USE_COUNT; +} + +static ssize_t lirc_write(struct file *file, const char *buf, + size_t n, loff_t *ppos) +{ + int i, count; + unsigned long flags; + long delta = 0; + + if (!(hardware[type].features&LIRC_CAN_SEND_PULSE)) + return(-EBADF); + + if (n%sizeof(lirc_t)) return(-EINVAL); + count = n/sizeof(lirc_t); + if (count > WBUF_LEN || count%2 == 0) return(-EINVAL); + if (copy_from_user(wbuf, buf, n)) return -EFAULT; + local_irq_save(flags); + if (type == LIRC_IRDEO) { + /* DTR, RTS down */ + on(); + } + for (i = 0; i < count; i++) { + if (i%2) + hardware[type].send_space(wbuf[i]-delta); + else + delta = hardware[type].send_pulse(wbuf[i]); + } + off(); + local_irq_restore(flags); + return(n); +} + +static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, + unsigned long arg) +{ + int result; + unsigned long value; + unsigned int ivalue; + + switch (cmd) { + case LIRC_GET_SEND_MODE: + if (!(hardware[type].features&LIRC_CAN_SEND_MASK)) + return(-ENOIOCTLCMD); + + result = put_user(LIRC_SEND2MODE + (hardware[type].features&LIRC_CAN_SEND_MASK), + (unsigned long *) arg); + if (result) + return result; + break; + + case LIRC_SET_SEND_MODE: + if (!(hardware[type].features&LIRC_CAN_SEND_MASK)) + return(-ENOIOCTLCMD); + + result = get_user(value, (unsigned long *) arg); + if (result) + return result; + /* only LIRC_MODE_PULSE supported */ + if (value != LIRC_MODE_PULSE) + return -ENOSYS; + break; + + case LIRC_GET_LENGTH: + return -ENOSYS; + break; + + case LIRC_SET_SEND_DUTY_CYCLE: + dprintk("SET_SEND_DUTY_CYCLE\n"); + if (!(hardware[type].features&LIRC_CAN_SET_SEND_DUTY_CYCLE)) + return -ENOIOCTLCMD; + + result = get_user(ivalue, (unsigned int *) arg); + if (result) + return result; + if (ivalue <= 0 || ivalue > 100) + return -EINVAL; + return init_timing_params(ivalue, freq); + break; + + case LIRC_SET_SEND_CARRIER: + dprintk("SET_SEND_CARRIER\n"); + if (!(hardware[type].features&LIRC_CAN_SET_SEND_CARRIER)) + return -ENOIOCTLCMD; + + result = get_user(ivalue, (unsigned int *) arg); + if (result) + return result; + if (ivalue > 500000 || ivalue < 20000) + return -EINVAL; + return init_timing_params(duty_cycle, ivalue); + break; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static struct file_operations lirc_fops = { + .write = lirc_write, +}; + +static struct lirc_plugin plugin = { + .name = LIRC_DRIVER_NAME, + .minor = -1, + .code_length = 1, + .sample_rate = 0, + .data = NULL, + .add_to_buf = NULL, + .get_queue = NULL, + .rbuf = &rbuf, + .set_use_inc = set_use_inc, + .set_use_dec = set_use_dec, + .ioctl = lirc_ioctl, + .fops = &lirc_fops, + .dev = NULL, + .owner = THIS_MODULE, +}; + +#ifdef MODULE + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) +static struct platform_device *lirc_serial_igor_dev; + +static int __devinit lirc_serial_igor_probe(struct platform_device *dev) +{ + return 0; +} + +static int __devexit lirc_serial_igor_remove(struct platform_device * dev) +{ + return 0; +} + +static int lirc_serial_igor_suspend(struct platform_device *dev, + pm_message_t state) +{ + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + /* Disable all interrupts */ + soutp(UART_IER, sinp(UART_IER) & + (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); + + /* Clear registers. */ + sinp(UART_LSR); + sinp(UART_RX); + sinp(UART_IIR); + sinp(UART_MSR); + + return 0; +} + +static int lirc_serial_igor_resume(struct platform_device *dev) +{ + unsigned long flags; + + hardware_init_port(); + + local_irq_save(flags); + /* Enable Interrupt */ + do_gettimeofday(&lasttv); + soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); + off(); + + lirc_buffer_clear(&rbuf); + + local_irq_restore(flags); + + return 0; +} + +static struct platform_driver lirc_serial_igor_driver = { + .probe = lirc_serial_igor_probe, + .remove = __devexit_p(lirc_serial_igor_remove), + .suspend = lirc_serial_igor_suspend, + .resume = lirc_serial_igor_resume, + .driver = { + .name = "lirc_serial_igor", + .owner = THIS_MODULE, + }, +}; + +static int __init lirc_serial_igor_init(void) +{ + int result; + + result = platform_driver_register(&lirc_serial_igor_driver); + if (result) { + printk("lirc register returned %d\n", result); + return result; + } + + lirc_serial_igor_dev = platform_device_alloc("lirc_serial_igor", 0); + if (!lirc_serial_igor_dev) { + result = -ENOMEM; + goto exit_driver_unregister; + } + + result = platform_device_add(lirc_serial_igor_dev); + if (result) + goto exit_device_put; + + return 0; + +exit_device_put: + platform_device_put(lirc_serial_igor_dev); +exit_driver_unregister: + platform_driver_unregister(&lirc_serial_igor_driver); + return result; +} + +static void __exit lirc_serial_igor_exit(void) +{ + platform_device_unregister(lirc_serial_igor_dev); + platform_driver_unregister(&lirc_serial_igor_driver); +} +#endif + +int __init init_module(void) +{ + int result; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) + result = lirc_serial_igor_init(); + if (result) + return result; +#endif + switch (type) { + case LIRC_HOMEBREW: + case LIRC_IRDEO: + case LIRC_IRDEO_REMOTE: + case LIRC_ANIMAX: + case LIRC_IGOR: +#if defined(LIRC_SERIAL_NSLU2) + case LIRC_NSLU2: +#endif + break; + default: + result = -EINVAL; + goto exit_serial_exit; + } + if (!softcarrier) { + switch (type) { + case LIRC_HOMEBREW: + case LIRC_IGOR: + case LIRC_NSLU2: + hardware[type].features &= + ~(LIRC_CAN_SET_SEND_DUTY_CYCLE| + LIRC_CAN_SET_SEND_CARRIER); + break; + } + } + result = init_port(); + if (result < 0) + goto exit_serial_exit; + plugin.features = hardware[type].features; + plugin.minor = lirc_register_plugin(&plugin); + if (plugin.minor < 0) { + printk(KERN_ERR LIRC_DRIVER_NAME + ": register_chrdev failed!\n"); + result = -EIO; + goto exit_release; + } + return 0; +exit_release: + release_region(io, 8); +exit_serial_exit: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) + lirc_serial_igor_exit(); +#endif + return result; +} + +void __exit cleanup_module(void) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) + lirc_serial_igor_exit(); +#endif +#if defined(LIRC_ALLOW_MMAPPED_IO) + if (iommap != 0) + release_mem_region(iommap, 8< + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/*********************************************************************** + ************************* Includes *********************** + ***********************************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) +#error "**********************************************************" +#error " Sorry, this driver needs kernel version 2.2.18 or higher " +#error "**********************************************************" +#endif + +#include + +#ifdef CONFIG_SMP +#error "--- Sorry, this driver is not SMP safe. ---" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) +#include +#endif + +#include +#include + +#include "lirc.h" +#include "kcompat.h" +#include "lirc_dev/lirc_dev.h" + +#include "lirc_parallel.h" + +#define LIRC_DRIVER_NAME "lirc_parallel" + +#ifndef LIRC_IRQ +#define LIRC_IRQ 7 +#endif +#ifndef LIRC_PORT +#define LIRC_PORT 0x378 +#endif +#ifndef LIRC_TIMER +#define LIRC_TIMER 65536 +#endif + +/*********************************************************************** + ************************* Globale Variablen *********************** + ***********************************************************************/ + +static int debug; +static int check_pselecd; + +unsigned int irq = LIRC_IRQ; +unsigned int io = LIRC_PORT; +#ifdef LIRC_TIMER +unsigned int timer; +unsigned int default_timer = LIRC_TIMER; +#endif + +#define WBUF_SIZE (256) +#define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */ + +static lirc_t wbuf[WBUF_SIZE]; +static lirc_t rbuf[RBUF_SIZE]; + +DECLARE_WAIT_QUEUE_HEAD(lirc_wait); + +unsigned int rptr; +unsigned int wptr; +unsigned int lost_irqs; +int is_open; + +struct parport *pport; +struct pardevice *ppdevice; +int is_claimed; + +unsigned int tx_mask = 1; + +/*********************************************************************** + ************************* Interne Funktionen *********************** + ***********************************************************************/ + +static inline unsigned int in(int offset) +{ + switch (offset) { + case LIRC_LP_BASE: + return (parport_read_data(pport)); + case LIRC_LP_STATUS: + return (parport_read_status(pport)); + case LIRC_LP_CONTROL: + return (parport_read_control(pport)); + } + return 0; /* make compiler happy */ +} + +static inline void out(int offset, int value) +{ + switch (offset) { + case LIRC_LP_BASE: + parport_write_data(pport, value); + break; + case LIRC_LP_CONTROL: + parport_write_control(pport, value); + break; + case LIRC_LP_STATUS: + printk(KERN_INFO "%s: attempt to write to status register\n", + LIRC_DRIVER_NAME); + break; + } +} + +static inline unsigned int lirc_get_timer(void) +{ + return (in(LIRC_PORT_TIMER)&LIRC_PORT_TIMER_BIT); +} + +static inline unsigned int lirc_get_signal(void) +{ + return (in(LIRC_PORT_SIGNAL)&LIRC_PORT_SIGNAL_BIT); +} + +static inline void lirc_on(void) +{ + out(LIRC_PORT_DATA, tx_mask); +} + +static inline void lirc_off(void) +{ + out(LIRC_PORT_DATA, 0); +} + +static unsigned int init_lirc_timer(void) +{ + struct timeval tv, now; + unsigned int level, newlevel, timeelapsed, newtimer; + int count = 0; + + do_gettimeofday(&tv); + tv.tv_sec++; /* wait max. 1 sec. */ + level = lirc_get_timer(); + do { + newlevel = lirc_get_timer(); + if (level == 0 && newlevel != 0) + count++; + level = newlevel; + do_gettimeofday(&now); + } while (count < 1000 && (now.tv_sec < tv.tv_sec + || (now.tv_sec == tv.tv_sec + && now.tv_usec < tv.tv_usec))); + + timeelapsed = ((now.tv_sec + 1 - tv.tv_sec)*1000000 + + (now.tv_usec - tv.tv_usec)); + if (count >= 1000 && timeelapsed > 0) { + if (default_timer == 0) { + /* autodetect timer */ + newtimer = (1000000*count)/timeelapsed; + printk(KERN_INFO "%s: %u Hz timer detected\n", + LIRC_DRIVER_NAME, newtimer); + return newtimer; + } else { + newtimer = (1000000*count)/timeelapsed; + if (abs(newtimer - default_timer) > default_timer/10) { + /* bad timer */ + printk(KERN_NOTICE "%s: bad timer: %u Hz\n", + LIRC_DRIVER_NAME, newtimer); + printk(KERN_NOTICE "%s: using default timer: " + "%u Hz\n", + LIRC_DRIVER_NAME, default_timer); + return default_timer; + } else { + printk(KERN_INFO "%s: %u Hz timer detected\n", + LIRC_DRIVER_NAME, newtimer); + return newtimer; /* use detected value */ + } + } + } else { + printk(KERN_NOTICE "%s: no timer detected\n", LIRC_DRIVER_NAME); + return 0; + } +} + +static int lirc_claim(void) +{ + if (parport_claim(ppdevice) != 0) { + printk(KERN_WARNING "%s: could not claim port\n", + LIRC_DRIVER_NAME); + printk(KERN_WARNING "%s: waiting for port becoming available" + "\n", LIRC_DRIVER_NAME); + if (parport_claim_or_block(ppdevice) < 0) { + printk(KERN_NOTICE "%s: could not claim port, giving" + " up\n", LIRC_DRIVER_NAME); + return 0; + } + } + out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP); + is_claimed = 1; + return 1; +} + +/*********************************************************************** + ************************* interrupt handler ************************ + ***********************************************************************/ + +static inline void rbuf_write(lirc_t signal) +{ + unsigned int nwptr; + + nwptr = (wptr + 1) & (RBUF_SIZE - 1); + if (nwptr == rptr) { + /* no new signals will be accepted */ + lost_irqs++; + printk(KERN_NOTICE "%s: buffer overrun\n", LIRC_DRIVER_NAME); + return; + } + rbuf[wptr] = signal; + wptr = nwptr; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void irq_handler(int i, void *blah, struct pt_regs *regs) +#else +static void irq_handler(int i, void *blah) +#endif +{ + struct timeval tv; + static struct timeval lasttv; + static int init; + long signal; + lirc_t data; + unsigned int level, newlevel; + unsigned int timeout; + + if (!MOD_IN_USE) + return; + + if (!is_claimed) + return; + + /* disable interrupt */ + /* + disable_irq(irq); + out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ) & (~LP_PINTEN)); + */ + if (check_pselecd && (in(1) & LP_PSELECD)) + return; + +#ifdef LIRC_TIMER + if (init) { + do_gettimeofday(&tv); + + signal = tv.tv_sec - lasttv.tv_sec; + if (signal > 15) + /* really long time */ + data = PULSE_MASK; + else + data = (lirc_t) (signal*1000000 + + tv.tv_usec - lasttv.tv_usec + + LIRC_SFH506_DELAY); + + rbuf_write(data); /* space */ + } else { + if (timer == 0) { + /* wake up; we'll lose this signal + * but it will be garbage if the device + * is turned on anyway */ + timer = init_lirc_timer(); + /* enable_irq(irq); */ + return; + } + init = 1; + } + + timeout = timer/10; /* timeout after 1/10 sec. */ + signal = 1; + level = lirc_get_timer(); + do { + newlevel = lirc_get_timer(); + if (level == 0 && newlevel != 0) + signal++; + level = newlevel; + + /* giving up */ + if (signal > timeout + || (check_pselecd && (in(1) & LP_PSELECD))) { + signal = 0; + printk(KERN_NOTICE "%s: timeout\n", LIRC_DRIVER_NAME); + break; + } + } + while (lirc_get_signal()); + if (signal != 0) { + /* ajust value to usecs */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) + unsigned long long helper; + + helper = ((unsigned long long) signal)*1000000; + do_div(helper, timer); + signal = (long) helper; +#else + signal = (long) ((((double) signal)*1000000)/timer); +#endif + + if (signal > LIRC_SFH506_DELAY) + data = signal - LIRC_SFH506_DELAY; + else + data = 1; + rbuf_write(PULSE_BIT|data); /* pulse */ + } + do_gettimeofday(&lasttv); +#else + /* add your code here */ +#endif + + wake_up_interruptible(&lirc_wait); + + /* enable interrupt */ + /* + enable_irq(irq); + out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ)|LP_PINTEN); + */ +} + +/*********************************************************************** + ************************** file_operations ************************ + ***********************************************************************/ + +static loff_t lirc_lseek(struct file *filep, loff_t offset, int orig) +{ + return -ESPIPE; +} + +static ssize_t lirc_read(struct file *filep, char *buf, size_t n, loff_t *ppos) +{ + int result = 0; + int count = 0; + DECLARE_WAITQUEUE(wait, current); + + if (n % sizeof(lirc_t)) + return -EINVAL; + + add_wait_queue(&lirc_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + while (count < n) { + if (rptr != wptr) { + if (copy_to_user(buf+count, (char *) &rbuf[rptr], + sizeof(lirc_t))) { + result = -EFAULT; + break; + } + rptr = (rptr + 1) & (RBUF_SIZE - 1); + count += sizeof(lirc_t); + } else { + if (filep->f_flags & O_NONBLOCK) { + result = -EAGAIN; + break; + } + if (signal_pending(current)) { + result = -ERESTARTSYS; + break; + } + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + } + } + remove_wait_queue(&lirc_wait, &wait); + set_current_state(TASK_RUNNING); + return (count ? count : result); +} + +static ssize_t lirc_write(struct file *filep, const char *buf, size_t n, + loff_t *ppos) +{ + int count; + unsigned int i; + unsigned int level, newlevel; + unsigned long flags; + lirc_t counttimer; + + if (!is_claimed) + return(-EBUSY); + + if (n % sizeof(lirc_t)) + return(-EINVAL); + + count = n / sizeof(lirc_t); + + if (count > WBUF_SIZE || count % 2 == 0) + return(-EINVAL); + + if (copy_from_user(wbuf, buf, n)) + return -EFAULT; + +#ifdef LIRC_TIMER + if (timer == 0) { + /* try again if device is ready */ + timer = init_lirc_timer(); + if (timer == 0) + return(-EIO); + } + + /* ajust values from usecs */ + for (i = 0; i < count; i++) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) + unsigned long long helper; + + helper = ((unsigned long long) wbuf[i])*timer; + do_div(helper, 1000000); + wbuf[i] = (lirc_t) helper; +#else + wbuf[i] = (lirc_t) (((double) wbuf[i])*timer/1000000); +#endif + } + + local_irq_save(flags); + i = 0; + while (i < count) { + level = lirc_get_timer(); + counttimer = 0; + lirc_on(); + do { + newlevel = lirc_get_timer(); + if (level == 0 && newlevel != 0) + counttimer++; + level = newlevel; + if (check_pselecd && (in(1) & LP_PSELECD)) { + lirc_off(); + local_irq_restore(flags); + return -EIO; + } + } while (counttimer < wbuf[i]); + i++; + + lirc_off(); + if (i == count) + break; + counttimer = 0; + do { + newlevel = lirc_get_timer(); + if (level == 0 && newlevel != 0) + counttimer++; + level = newlevel; + if (check_pselecd && (in(1) & LP_PSELECD)) { + local_irq_restore(flags); + return -EIO; + } + } while (counttimer < wbuf[i]); + i++; + } + local_irq_restore(flags); +#else + /* place code that handles write + * without external timer here */ +#endif + return n; +} + +static unsigned int lirc_poll(struct file *file, poll_table *wait) +{ + poll_wait(file, &lirc_wait, wait); + if (rptr != wptr) + return (POLLIN|POLLRDNORM); + return 0; +} + +static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, + unsigned long arg) +{ + int result; + unsigned long features = LIRC_CAN_SET_TRANSMITTER_MASK | + LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2; + unsigned long mode; + unsigned int ivalue; + + switch (cmd) { + case LIRC_GET_FEATURES: + result = put_user(features, (unsigned long *) arg); + if (result) + return result; + break; + case LIRC_GET_SEND_MODE: + result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg); + if (result) + return result; + break; + case LIRC_GET_REC_MODE: + result = put_user(LIRC_MODE_MODE2, (unsigned long *) arg); + if (result) + return result; + break; + case LIRC_SET_SEND_MODE: + result = get_user(mode, (unsigned long *) arg); + if (result) + return result; + if (mode != LIRC_MODE_PULSE) + return -EINVAL; + break; + case LIRC_SET_REC_MODE: + result = get_user(mode, (unsigned long *) arg); + if (result) + return result; + if (mode != LIRC_MODE_MODE2) + return -ENOSYS; + break; + case LIRC_SET_TRANSMITTER_MASK: + result = get_user(ivalue, (unsigned int *) arg); + if (result) + return result; + if ((ivalue & LIRC_PARALLEL_TRANSMITTER_MASK) != ivalue) + return LIRC_PARALLEL_MAX_TRANSMITTERS; + tx_mask = ivalue; + break; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static int lirc_open(struct inode *node, struct file *filep) +{ + if (MOD_IN_USE || !lirc_claim()) + return -EBUSY; + + parport_enable_irq(pport); + + /* init read ptr */ + rptr = 0; + wptr = 0; + lost_irqs = 0; + + MOD_INC_USE_COUNT; + is_open = 1; + return 0; +} + +static int lirc_close(struct inode *node, struct file *filep) +{ + if (is_claimed) { + is_claimed = 0; + parport_release(ppdevice); + } + is_open = 0; + MOD_DEC_USE_COUNT; + return 0; +} + +static struct file_operations lirc_fops = { + .llseek = lirc_lseek, + .read = lirc_read, + .write = lirc_write, + .poll = lirc_poll, + .ioctl = lirc_ioctl, + .open = lirc_open, + .release = lirc_close +}; + +static int set_use_inc(void *data) +{ +#if WE_DONT_USE_LOCAL_OPEN_CLOSE + MOD_INC_USE_COUNT; +#endif + return 0; +} + +static void set_use_dec(void *data) +{ +#if WE_DONT_USE_LOCAL_OPEN_CLOSE + MOD_DEC_USE_COUNT; +#endif +} + +static struct lirc_plugin plugin = { + .name = LIRC_DRIVER_NAME, + .minor = -1, + .code_length = 1, + .sample_rate = 0, + .data = NULL, + .add_to_buf = NULL, + .get_queue = NULL, + .set_use_inc = set_use_inc, + .set_use_dec = set_use_dec, + .fops = &lirc_fops, + .dev = NULL, + .owner = THIS_MODULE, +}; + +#ifdef MODULE + +static int pf(void *handle); +static void kf(void *handle); + +static struct timer_list poll_timer; +static void poll_state(unsigned long ignored); + +static void poll_state(unsigned long ignored) +{ + printk(KERN_NOTICE "%s: time\n", + LIRC_DRIVER_NAME); + del_timer(&poll_timer); + if (is_claimed) + return; + kf(NULL); + if (!is_claimed) { + printk(KERN_NOTICE "%s: could not claim port, giving up\n", + LIRC_DRIVER_NAME); + init_timer(&poll_timer); + poll_timer.expires = jiffies + HZ; + poll_timer.data = (unsigned long)current; + poll_timer.function = poll_state; + add_timer(&poll_timer); + } +} + +static int pf(void *handle) +{ + parport_disable_irq(pport); + is_claimed = 0; + return 0; +} + +static void kf(void *handle) +{ + if (!is_open) + return; + if (!lirc_claim()) + return; + parport_enable_irq(pport); + lirc_off(); + /* this is a bit annoying when you actually print...*/ + /* + printk(KERN_INFO "%s: reclaimed port\n", LIRC_DRIVER_NAME); + */ +} + +/*********************************************************************** + ****************** init_module()/cleanup_module() ****************** + ***********************************************************************/ + +int init_module(void) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 3) + pport = parport_find_base(io); +#else + pport = parport_enumerate(); + while (pport != NULL) { + if (pport->base == io) + break; + pport = pport->next; + } +#endif + if (pport == NULL) { + printk(KERN_NOTICE "%s: no port at %x found\n", + LIRC_DRIVER_NAME, io); + return -ENXIO; + } + ppdevice = parport_register_device(pport, LIRC_DRIVER_NAME, + pf, kf, irq_handler, 0, NULL); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 3) + parport_put_port(pport); +#endif + if (ppdevice == NULL) { + printk(KERN_NOTICE "%s: parport_register_device() failed\n", + LIRC_DRIVER_NAME); + return -ENXIO; + } + if (parport_claim(ppdevice) != 0) + goto skip_init; + is_claimed = 1; + out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP); + +#ifdef LIRC_TIMER + if (debug) + out(LIRC_PORT_DATA, tx_mask); + + timer = init_lirc_timer(); + +#if 0 /* continue even if device is offline */ + if (timer == 0) { + is_claimed = 0; + parport_release(pport); + parport_unregister_device(ppdevice); + return -EIO; + } + +#endif + if (debug) + out(LIRC_PORT_DATA, 0); +#endif + + is_claimed = 0; + parport_release(ppdevice); + skip_init: + plugin.minor = lirc_register_plugin(&plugin); + if (plugin.minor < 0) { + printk(KERN_NOTICE "%s: register_chrdev() failed\n", + LIRC_DRIVER_NAME); + parport_unregister_device(ppdevice); + return -EIO; + } + printk(KERN_INFO "%s: installed using port 0x%04x irq %d\n", + LIRC_DRIVER_NAME, io, irq); + return 0; +} + +void cleanup_module(void) +{ + parport_unregister_device(ppdevice); + lirc_unregister_plugin(plugin.minor); +} + +MODULE_DESCRIPTION("Infrared receiver driver for parallel ports."); +MODULE_AUTHOR("Christoph Bartelmus"); +MODULE_LICENSE("GPL"); + +module_param(io, int, 0444); +MODULE_PARM_DESC(io, "I/O address base (0x3bc, 0x378 or 0x278)"); + +module_param(irq, int, 0444); +MODULE_PARM_DESC(irq, "Interrupt (7 or 5)"); + +module_param(tx_mask, int, 0444); +MODULE_PARM_DESC(tx_maxk, "Transmitter mask (default: 0x01)"); + +module_param(debug, bool, 0644); +MODULE_PARM_DESC(debug, "Enable debugging messages"); + +module_param(check_pselecd, bool, 0644); +MODULE_PARM_DESC(debug, "Check for printer (default: 0)"); + +EXPORT_NO_SYMBOLS; + +#endif /* MODULE */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_parallel/lirc_parallel.h +++ linux-2.6.27/ubuntu/lirc/lirc_parallel/lirc_parallel.h @@ -0,0 +1,26 @@ +/* $Id: lirc_parallel.h,v 5.2 2007/01/25 04:32:05 lirc Exp $ */ + +#ifndef _LIRC_PARALLEL_H +#define _LIRC_PARALLEL_H + +#include + +#define LIRC_PORT_LEN 3 + +#define LIRC_LP_BASE 0 +#define LIRC_LP_STATUS 1 +#define LIRC_LP_CONTROL 2 + +#define LIRC_PORT_DATA LIRC_LP_BASE /* base */ +#define LIRC_PORT_TIMER LIRC_LP_STATUS /* status port */ +#define LIRC_PORT_TIMER_BIT LP_PBUSY /* busy signal */ +#define LIRC_PORT_SIGNAL LIRC_LP_STATUS /* status port */ +#define LIRC_PORT_SIGNAL_BIT LP_PACK /* ack signal */ +#define LIRC_PORT_IRQ LIRC_LP_CONTROL /* control port */ + +#define LIRC_SFH506_DELAY 0 /* delay t_phl in usecs */ + +#define LIRC_PARALLEL_MAX_TRANSMITTERS 8 +#define LIRC_PARALLEL_TRANSMITTER_MASK ((1< + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * ITE IT8705 and IT8712(not tested) CIR-port support for lirc based + * via cut and paste from lirc_sir.c (C) 2000 Milan Pikula + * + * Attention: Sendmode only tested with debugging logs + * + * 2001/02/27 Christoph Bartelmus : + * reimplemented read function + * 2005/06/05 Andrew Calkin implemented support for Asus Digimatrix, + * based on work of the following member of the Outertrack Digimatrix + * Forum: Art103 + */ + + +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif + +#include + +#include "lirc.h" +#include "lirc_dev/lirc_dev.h" +#include "kcompat.h" + +#include "lirc_it87.h" + +#ifdef LIRC_IT87_DIGIMATRIX +static int digimatrix = 1; +static int it87_freq = 36; /* kHz */ +static int irq = 9; +#else +static int digimatrix; +static int it87_freq = 38; /* kHz */ +static int irq = IT87_CIR_DEFAULT_IRQ; +#endif + +static unsigned long it87_bits_in_byte_out; +static unsigned long it87_send_counter; +static unsigned char it87_RXEN_mask = IT87_CIR_RCR_RXEN; + +#define RBUF_LEN 1024 +#define WBUF_LEN 1024 + +#define LIRC_DRIVER_NAME "lirc_it87" + +/* timeout for sequences in jiffies (=5/100s) */ +/* must be longer than TIME_CONST */ +#define IT87_TIMEOUT (HZ*5/100) + +/* insmod parameters */ +static int debug; +#define dprintk(fmt, args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ + fmt, ## args); \ + } while (0) + +static int io = IT87_CIR_DEFAULT_IOBASE; +/* receiver demodulator default: off */ +static int it87_enable_demodulator; + +static int timer_enabled; +static DEFINE_SPINLOCK(timer_lock); +static struct timer_list timerlist; +/* time of last signal change detected */ +static struct timeval last_tv = {0, 0}; +/* time of last UART data ready interrupt */ +static struct timeval last_intr_tv = {0, 0}; +static int last_value; + +static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue); + +static DEFINE_SPINLOCK(hardware_lock); +static DEFINE_SPINLOCK(dev_lock); + +static lirc_t rx_buf[RBUF_LEN]; +unsigned int rx_tail, rx_head; +static lirc_t tx_buf[WBUF_LEN]; + +/* SECTION: Prototypes */ + +/* Communication with user-space */ +static int lirc_open(struct inode *inode, struct file *file); +static int lirc_close(struct inode *inode, struct file *file); +static unsigned int lirc_poll(struct file *file, poll_table *wait); +static ssize_t lirc_read(struct file *file, char *buf, + size_t count, loff_t *ppos); +static ssize_t lirc_write(struct file *file, const char *buf, + size_t n, loff_t *pos); +static int lirc_ioctl(struct inode *node, struct file *filep, + unsigned int cmd, unsigned long arg); +static void add_read_queue(int flag, unsigned long val); +#ifdef MODULE +static int init_chrdev(void); +static void drop_chrdev(void); +#endif + /* Hardware */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static irqreturn_t it87_interrupt(int irq, void *dev_id, + struct pt_regs *regs); +#else +static irqreturn_t it87_interrupt(int irq, void *dev_id); +#endif +static void send_space(unsigned long len); +static void send_pulse(unsigned long len); +static void init_send(void); +static void terminate_send(unsigned long len); +static int init_hardware(void); +static void drop_hardware(void); + /* Initialisation */ +static int init_port(void); +static void drop_port(void); +int init_module(void); +void cleanup_module(void); + + +/* SECTION: Communication with user-space */ + +static int lirc_open(struct inode *inode, struct file *file) +{ + spin_lock(&dev_lock); + if (MOD_IN_USE) { + spin_unlock(&dev_lock); + return -EBUSY; + } + MOD_INC_USE_COUNT; + spin_unlock(&dev_lock); + return 0; +} + + +static int lirc_close(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + return 0; +} + + +static unsigned int lirc_poll(struct file *file, poll_table *wait) +{ + poll_wait(file, &lirc_read_queue, wait); + if (rx_head != rx_tail) + return POLLIN | POLLRDNORM; + return 0; +} + + +static ssize_t lirc_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + int n = 0; + int retval = 0; + + while (n < count) { + if (file->f_flags & O_NONBLOCK && rx_head == rx_tail) { + retval = -EAGAIN; + break; + } + retval = wait_event_interruptible(lirc_read_queue, + rx_head != rx_tail); + if (retval) + break; + + if (copy_to_user((void *) buf + n, (void *) (rx_buf + rx_head), + sizeof(lirc_t))) { + retval = -EFAULT; + break; + } + rx_head = (rx_head + 1) & (RBUF_LEN - 1); + n += sizeof(lirc_t); + } + if (n) + return n; + return retval; +} + + +static ssize_t lirc_write(struct file *file, const char *buf, + size_t n, loff_t *pos) +{ + int i = 0; + + if (n % sizeof(lirc_t) || (n / sizeof(lirc_t)) > WBUF_LEN) + return -EINVAL; + if (copy_from_user(tx_buf, buf, n)) + return -EFAULT; + n /= sizeof(lirc_t); + init_send(); + while (1) { + if (i >= n) + break; + if (tx_buf[i]) + send_pulse(tx_buf[i]); + i++; + if (i >= n) + break; + if (tx_buf[i]) + send_space(tx_buf[i]); + i++; + } + terminate_send(tx_buf[i - 1]); + return n; +} + + +static int lirc_ioctl(struct inode *node, struct file *filep, + unsigned int cmd, unsigned long arg) +{ + int retval = 0; + unsigned long value = 0; + unsigned int ivalue; + unsigned long hw_flags; + + if (cmd == LIRC_GET_FEATURES) + value = LIRC_CAN_SEND_PULSE | + LIRC_CAN_SET_SEND_CARRIER | + LIRC_CAN_REC_MODE2; + else if (cmd == LIRC_GET_SEND_MODE) + value = LIRC_MODE_PULSE; + else if (cmd == LIRC_GET_REC_MODE) + value = LIRC_MODE_MODE2; + + switch (cmd) { + case LIRC_GET_FEATURES: + case LIRC_GET_SEND_MODE: + case LIRC_GET_REC_MODE: + retval = put_user(value, (unsigned long *) arg); + break; + + case LIRC_SET_SEND_MODE: + case LIRC_SET_REC_MODE: + retval = get_user(value, (unsigned long *) arg); + break; + + case LIRC_SET_SEND_CARRIER: + retval = get_user(ivalue, (unsigned int *) arg); + if (retval) + return retval; + ivalue /= 1000; + if (ivalue > IT87_CIR_FREQ_MAX || + ivalue < IT87_CIR_FREQ_MIN) + return -EINVAL; + + it87_freq = ivalue; + + spin_lock_irqsave(&hardware_lock, hw_flags); + outb(((inb(io + IT87_CIR_TCR2) & IT87_CIR_TCR2_TXMPW) | + (it87_freq - IT87_CIR_FREQ_MIN) << 3), + io + IT87_CIR_TCR2); + spin_unlock_irqrestore(&hardware_lock, hw_flags); + dprintk("demodulation frequency: %d kHz\n", it87_freq); + + break; + + default: + retval = -ENOIOCTLCMD; + } + + if (retval) + return retval; + + if (cmd == LIRC_SET_REC_MODE) { + if (value != LIRC_MODE_MODE2) + retval = -ENOSYS; + } else if (cmd == LIRC_SET_SEND_MODE) { + if (value != LIRC_MODE_PULSE) + retval = -ENOSYS; + } + return retval; +} + +static void add_read_queue(int flag, unsigned long val) +{ + unsigned int new_rx_tail; + lirc_t newval; + + dprintk("add flag %d with val %lu\n", flag, val); + + newval = val & PULSE_MASK; + + /* statistically pulses are ~TIME_CONST/2 too long: we could + maybe make this more exactly but this is good enough */ + if (flag) { + /* pulse */ + if (newval > TIME_CONST / 2) + newval -= TIME_CONST / 2; + else /* should not ever happen */ + newval = 1; + newval |= PULSE_BIT; + } else + newval += TIME_CONST / 2; + new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1); + if (new_rx_tail == rx_head) { + dprintk("Buffer overrun.\n"); + return; + } + rx_buf[rx_tail] = newval; + rx_tail = new_rx_tail; + wake_up_interruptible(&lirc_read_queue); +} + + +static struct file_operations lirc_fops = { + .read = lirc_read, + .write = lirc_write, + .poll = lirc_poll, + .ioctl = lirc_ioctl, + .open = lirc_open, + .release = lirc_close, +}; + +static int set_use_inc(void *data) +{ + return 0; +} + +static void set_use_dec(void *data) +{ + +} +static struct lirc_plugin plugin = { + .name = LIRC_DRIVER_NAME, + .minor = -1, + .code_length = 1, + .sample_rate = 0, + .data = NULL, + .add_to_buf = NULL, + .get_queue = NULL, + .set_use_inc = set_use_inc, + .set_use_dec = set_use_dec, + .fops = &lirc_fops, + .dev = NULL, + .owner = THIS_MODULE, +}; + + +#ifdef MODULE +static int init_chrdev(void) +{ + plugin.minor = lirc_register_plugin(&plugin); + + if (plugin.minor < 0) { + printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n"); + return -EIO; + } + return 0; +} + + +static void drop_chrdev(void) +{ + lirc_unregister_plugin(plugin.minor); +} +#endif + + +/* SECTION: Hardware */ +static long delta(struct timeval *tv1, struct timeval *tv2) +{ + unsigned long deltv; + + deltv = tv2->tv_sec - tv1->tv_sec; + if (deltv > 15) + deltv = 0xFFFFFF; + else + deltv = deltv*1000000 + tv2->tv_usec - tv1->tv_usec; + return deltv; +} + +static void it87_timeout(unsigned long data) +{ + unsigned long flags; + + /* avoid interference with interrupt */ + spin_lock_irqsave(&timer_lock, flags); + + if (digimatrix) { + /* We have timed out. + Disable the RX mechanism. + */ + + outb((inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN) | + IT87_CIR_RCR_RXACT, io + IT87_CIR_RCR); + if (it87_RXEN_mask) + outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN, + io + IT87_CIR_RCR); + dprintk(" TIMEOUT\n"); + timer_enabled = 0; + + /* fifo clear */ + outb(inb(io + IT87_CIR_TCR1) | IT87_CIR_TCR1_FIFOCLR, + io+IT87_CIR_TCR1); + + } else { + /* if last received signal was a pulse, but receiving + stopped within the 9 bit frame, we need to finish + this pulse and simulate a signal change to from + pulse to space. Otherwise upper layers will receive + two sequences next time. */ + + if (last_value) { + unsigned long pulse_end; + + /* determine 'virtual' pulse end: */ + pulse_end = delta(&last_tv, &last_intr_tv); + dprintk("timeout add %d for %lu usec\n", + last_value, pulse_end); + add_read_queue(last_value, pulse_end); + last_value = 0; + last_tv = last_intr_tv; + } + } + spin_unlock_irqrestore(&timer_lock, flags); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static irqreturn_t it87_interrupt(int irq, void *dev_id, struct pt_regs *regs) +#else +static irqreturn_t it87_interrupt(int irq, void *dev_id) +#endif +{ + unsigned char data; + struct timeval curr_tv; + static unsigned long deltv; + unsigned long deltintrtv; + unsigned long flags, hw_flags; + int iir, lsr; + int fifo = 0; + static char lastbit; + char bit; + + /* Bit duration in microseconds */ + const unsigned long bit_duration = 1000000ul / + (115200 / IT87_CIR_BAUDRATE_DIVISOR); + + + iir = inb(io + IT87_CIR_IIR); + + switch (iir & IT87_CIR_IIR_IID) { + case 0x4: + case 0x6: + lsr = inb(io + IT87_CIR_RSR) & (IT87_CIR_RSR_RXFTO | + IT87_CIR_RSR_RXFBC); + fifo = lsr & IT87_CIR_RSR_RXFBC; + dprintk("iir: 0x%x fifo: 0x%x\n", iir, lsr); + + /* avoid interference with timer */ + spin_lock_irqsave(&timer_lock, flags); + spin_lock_irqsave(&hardware_lock, hw_flags); + if (digimatrix) { + static unsigned long acc_pulse; + static unsigned long acc_space; + + do { + data = inb(io + IT87_CIR_DR); + data = ~data; + fifo--; + if (data != 0x00) { + if (timer_enabled) + del_timer(&timerlist); + /* start timer for end of + * sequence detection */ + timerlist.expires = jiffies + + IT87_TIMEOUT; + add_timer(&timerlist); + timer_enabled = 1; + } + /* Loop through */ + for (bit = 0; bit < 8; ++bit) { + if ((data >> bit) & 1) { + ++acc_pulse; + if (lastbit == 0) { + add_read_queue(0, + acc_space * + bit_duration); + acc_space = 0; + } + } else { + ++acc_space; + if (lastbit == 1) { + add_read_queue(1, + acc_pulse * + bit_duration); + acc_pulse = 0; + } + } + lastbit = (data >> bit) & 1; + } + + } while (fifo != 0); + } else { /* Normal Operation */ + do { + del_timer(&timerlist); + data = inb(io + IT87_CIR_DR); + + dprintk("data=%.2x\n", data); + do_gettimeofday(&curr_tv); + deltv = delta(&last_tv, &curr_tv); + deltintrtv = delta(&last_intr_tv, &curr_tv); + + dprintk("t %lu , d %d\n", + deltintrtv, (int)data); + + /* if nothing came in last 2 cycles, + it was gap */ + if (deltintrtv > TIME_CONST * 2) { + if (last_value) { + dprintk("GAP\n"); + + /* simulate signal change */ + add_read_queue(last_value, + deltv - + deltintrtv); + last_value = 0; + last_tv.tv_sec = + last_intr_tv.tv_sec; + last_tv.tv_usec = + last_intr_tv.tv_usec; + deltv = deltintrtv; + } + } + data = 1; + if (data ^ last_value) { + /* deltintrtv > 2*TIME_CONST, + remember ? */ + /* the other case is timeout */ + add_read_queue(last_value, + deltv-TIME_CONST); + last_value = data; + last_tv = curr_tv; + if (last_tv.tv_usec >= TIME_CONST) + last_tv.tv_usec -= TIME_CONST; + else { + last_tv.tv_sec--; + last_tv.tv_usec += 1000000 - + TIME_CONST; + } + } + last_intr_tv = curr_tv; + if (data) { + /* start timer for end of + * sequence detection */ + timerlist.expires = + jiffies + IT87_TIMEOUT; + add_timer(&timerlist); + } + outb((inb(io + IT87_CIR_RCR) & + ~IT87_CIR_RCR_RXEN) | + IT87_CIR_RCR_RXACT, + io + IT87_CIR_RCR); + if (it87_RXEN_mask) + outb(inb(io + IT87_CIR_RCR) | + IT87_CIR_RCR_RXEN, + io + IT87_CIR_RCR); + fifo--; + } while (fifo != 0); + } + spin_unlock_irqrestore(&hardware_lock, hw_flags); + spin_unlock_irqrestore(&timer_lock, flags); + + return IRQ_RETVAL(IRQ_HANDLED); + + default: + /* not our irq */ + dprintk("unknown IRQ (shouldn't happen) !!\n"); + return IRQ_RETVAL(IRQ_NONE); + } +} + + +static void send_it87(unsigned long len, unsigned long stime, + unsigned char send_byte, unsigned int count_bits) +{ + long count = len / stime; + long time_left = 0; + static unsigned char byte_out; + unsigned long hw_flags; + + dprintk("%s: len=%ld, sb=%d\n", __FUNCTION__, len, send_byte); + + time_left = (long)len - (long)count * (long)stime; + count += ((2 * time_left) / stime); + while (count) { + long i = 0; + for (i = 0; i < count_bits; i++) { + byte_out = (byte_out << 1) | (send_byte & 1); + it87_bits_in_byte_out++; + } + if (it87_bits_in_byte_out == 8) { + dprintk("out=0x%x, tsr_txfbc: 0x%x\n", + byte_out, + inb(io + IT87_CIR_TSR) & + IT87_CIR_TSR_TXFBC); + + while ((inb(io + IT87_CIR_TSR) & + IT87_CIR_TSR_TXFBC) >= IT87_CIR_FIFO_SIZE) + ; + + spin_lock_irqsave(&hardware_lock, hw_flags); + outb(byte_out, io + IT87_CIR_DR); + spin_unlock_irqrestore(&hardware_lock, hw_flags); + + it87_bits_in_byte_out = 0; + it87_send_counter++; + byte_out = 0; + } + count--; + } +} + + +/* +maybe: exchange space and pulse because +it8705 only modulates 0-bits +*/ + + +static void send_space(unsigned long len) +{ + send_it87(len, TIME_CONST, IT87_CIR_SPACE, IT87_CIR_BAUDRATE_DIVISOR); +} + +static void send_pulse(unsigned long len) +{ + send_it87(len, TIME_CONST, IT87_CIR_PULSE, IT87_CIR_BAUDRATE_DIVISOR); +} + + +static void init_send() +{ + unsigned long flags; + + spin_lock_irqsave(&hardware_lock, flags); + /* RXEN=0: receiver disable */ + it87_RXEN_mask = 0; + outb(inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN, + io + IT87_CIR_RCR); + spin_unlock_irqrestore(&hardware_lock, flags); + it87_bits_in_byte_out = 0; + it87_send_counter = 0; +} + + +static void terminate_send(unsigned long len) +{ + unsigned long flags; + unsigned long last = 0; + + last = it87_send_counter; + /* make sure all necessary data has been sent */ + while (last == it87_send_counter) + send_space(len); + /* wait until all data sent */ + while ((inb(io + IT87_CIR_TSR) & IT87_CIR_TSR_TXFBC) != 0); + /* then reenable receiver */ + spin_lock_irqsave(&hardware_lock, flags); + it87_RXEN_mask = IT87_CIR_RCR_RXEN; + outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN, + io + IT87_CIR_RCR); + spin_unlock_irqrestore(&hardware_lock, flags); +} + + +static int init_hardware(void) +{ + unsigned long flags; + unsigned char it87_rcr = 0; + + spin_lock_irqsave(&hardware_lock, flags); + /* init cir-port */ + /* enable r/w-access to Baudrate-Register */ + outb(IT87_CIR_IER_BR, io + IT87_CIR_IER); + outb(IT87_CIR_BAUDRATE_DIVISOR % 0x100, io+IT87_CIR_BDLR); + outb(IT87_CIR_BAUDRATE_DIVISOR / 0x100, io+IT87_CIR_BDHR); + /* Baudrate Register off, define IRQs: Input only */ + if (digimatrix) { + outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RFOIE, io + IT87_CIR_IER); + /* RX: HCFS=0, RXDCR = 001b (33,75..38,25 kHz), RXEN=1 */ + } else { + outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RDAIE, io + IT87_CIR_IER); + /* RX: HCFS=0, RXDCR = 001b (35,6..40,3 kHz), RXEN=1 */ + } + it87_rcr = (IT87_CIR_RCR_RXEN & it87_RXEN_mask) | 0x1; + if (it87_enable_demodulator) + it87_rcr |= IT87_CIR_RCR_RXEND; + outb(it87_rcr, io + IT87_CIR_RCR); + if (digimatrix) { + /* Set FIFO depth to 1 byte, and disable TX */ + outb(inb(io + IT87_CIR_TCR1) | 0x00, + io + IT87_CIR_TCR1); + + /* TX: it87_freq (36kHz), + 'reserved' sensitivity setting (0x00) */ + outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x00, + io + IT87_CIR_TCR2); + } else { + /* TX: 38kHz, 13,3us (pulse-width */ + outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x06, + io + IT87_CIR_TCR2); + } + spin_unlock_irqrestore(&hardware_lock, flags); + return 0; +} + + +static void drop_hardware(void) +{ + unsigned long flags; + + spin_lock_irqsave(&hardware_lock, flags); + disable_irq(irq); + /* receiver disable */ + it87_RXEN_mask = 0; + outb(0x1, io + IT87_CIR_RCR); + /* turn off irqs */ + outb(0, io + IT87_CIR_IER); + /* fifo clear */ + outb(IT87_CIR_TCR1_FIFOCLR, io+IT87_CIR_TCR1); + /* reset */ + outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER); + enable_irq(irq); + spin_unlock_irqrestore(&hardware_lock, flags); +} + + +static unsigned char it87_read(unsigned char port) +{ + outb(port, IT87_ADRPORT); + return inb(IT87_DATAPORT); +} + + +static void it87_write(unsigned char port, unsigned char data) +{ + outb(port, IT87_ADRPORT); + outb(data, IT87_DATAPORT); +} + + +/* SECTION: Initialisation */ + +static int init_port(void) +{ + unsigned long hw_flags; + int retval = 0; + + unsigned char init_bytes[4] = {IT87_INIT}; + unsigned char it87_chipid = 0; + unsigned char ldn = 0; + unsigned int it87_io = 0; + unsigned int it87_irq = 0; + + /* Enter MB PnP Mode */ + outb(init_bytes[0], IT87_ADRPORT); + outb(init_bytes[1], IT87_ADRPORT); + outb(init_bytes[2], IT87_ADRPORT); + outb(init_bytes[3], IT87_ADRPORT); + + /* 8712 or 8705 ? */ + it87_chipid = it87_read(IT87_CHIP_ID1); + if (it87_chipid != 0x87) { + retval = -ENXIO; + return retval; + } + it87_chipid = it87_read(IT87_CHIP_ID2); + if ((it87_chipid != 0x12) && (it87_chipid != 0x05)) { + printk(KERN_INFO LIRC_DRIVER_NAME + ": no IT8705/12 found, exiting..\n"); + retval = -ENXIO; + return retval; + } + printk(KERN_INFO LIRC_DRIVER_NAME + ": found IT87%.2x.\n", + it87_chipid); + + /* get I/O-Port and IRQ */ + if (it87_chipid == 0x12) + ldn = IT8712_CIR_LDN; + else + ldn = IT8705_CIR_LDN; + it87_write(IT87_LDN, ldn); + + it87_io = it87_read(IT87_CIR_BASE_MSB) * 256 + + it87_read(IT87_CIR_BASE_LSB); + if (it87_io == 0) { + if (io == 0) + io = IT87_CIR_DEFAULT_IOBASE; + printk(KERN_INFO LIRC_DRIVER_NAME + ": set default io 0x%x\n", + io); + it87_write(IT87_CIR_BASE_MSB, io / 0x100); + it87_write(IT87_CIR_BASE_LSB, io % 0x100); + } else + io = it87_io; + + it87_irq = it87_read(IT87_CIR_IRQ); + if (digimatrix || it87_irq == 0) { + if (irq == 0) + irq = IT87_CIR_DEFAULT_IRQ; + printk(KERN_INFO LIRC_DRIVER_NAME + ": set default irq 0x%x\n", + irq); + it87_write(IT87_CIR_IRQ, irq); + } else + irq = it87_irq; + + spin_lock_irqsave(&hardware_lock, hw_flags); + /* reset */ + outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER); + /* fifo clear */ + outb(IT87_CIR_TCR1_FIFOCLR | + /* IT87_CIR_TCR1_ILE | */ + IT87_CIR_TCR1_TXRLE | + IT87_CIR_TCR1_TXENDF, io+IT87_CIR_TCR1); + spin_unlock_irqrestore(&hardware_lock, hw_flags); + + /* get I/O port access and IRQ line */ + if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) { + printk(KERN_ERR LIRC_DRIVER_NAME + ": i/o port 0x%.4x already in use.\n", io); + /* Leaving MB PnP Mode */ + it87_write(IT87_CFGCTRL, 0x2); + return -EBUSY; + } + + /* activate CIR-Device */ + it87_write(IT87_CIR_ACT, 0x1); + + /* Leaving MB PnP Mode */ + it87_write(IT87_CFGCTRL, 0x2); + + retval = request_irq(irq, it87_interrupt, 0 /*IRQF_DISABLED*/, + LIRC_DRIVER_NAME, NULL); + if (retval < 0) { + printk(KERN_ERR LIRC_DRIVER_NAME + ": IRQ %d already in use.\n", + irq); + release_region(io, 8); + return retval; + } + + printk(KERN_INFO LIRC_DRIVER_NAME + ": I/O port 0x%.4x, IRQ %d.\n", io, irq); + + init_timer(&timerlist); + timerlist.function = it87_timeout; + timerlist.data = 0xabadcafe; + + return 0; +} + + +static void drop_port(void) +{ +/* + unsigned char init_bytes[4] = {IT87_INIT}; + + / * Enter MB PnP Mode * / + outb(init_bytes[0], IT87_ADRPORT); + outb(init_bytes[1], IT87_ADRPORT); + outb(init_bytes[2], IT87_ADRPORT); + outb(init_bytes[3], IT87_ADRPORT); + + / * deactivate CIR-Device * / + it87_write(IT87_CIR_ACT, 0x0); + + / * Leaving MB PnP Mode * / + it87_write(IT87_CFGCTRL, 0x2); +*/ + + del_timer_sync(&timerlist); + free_irq(irq, NULL); + release_region(io, 8); +} + + +static int init_lirc_it87(void) +{ + int retval; + + init_waitqueue_head(&lirc_read_queue); + retval = init_port(); + if (retval < 0) + return retval; + init_hardware(); + printk(KERN_INFO LIRC_DRIVER_NAME ": Installed.\n"); + return 0; +} + + +#ifdef MODULE + +int init_module(void) +{ + int retval; + + retval = init_chrdev(); + if (retval < 0) + return retval; + retval = init_lirc_it87(); + if (retval) { + drop_chrdev(); + return retval; + } + return 0; +} + + +void cleanup_module(void) +{ + drop_hardware(); + drop_chrdev(); + drop_port(); + printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n"); +} + +MODULE_DESCRIPTION("LIRC driver for ITE IT8712/IT8705 CIR port"); +MODULE_AUTHOR("Hans-Günter Lütke Uphues"); +MODULE_LICENSE("GPL"); + +module_param(io, int, 0444); +MODULE_PARM_DESC(io, "I/O base address (default: 0x310)"); + +module_param(irq, int, 0444); +#ifdef LIRC_IT87_DIGIMATRIX +MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 9)"); +#else +MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 7)"); +#endif + +module_param(it87_enable_demodulator, bool, 0444); +MODULE_PARM_DESC(it87_enable_demodulator, + "Receiver demodulator enable/disable (1/0), default: 0"); + +module_param(debug, bool, 0644); +MODULE_PARM_DESC(debug, "Enable debugging messages"); + +module_param(digimatrix, bool, 0644); +#ifdef LIRC_IT87_DIGIMATRIX +MODULE_PARM_DESC(digimatrix, + "Asus Digimatrix it87 compat. enable/disable (1/0), default: 1"); +#else +MODULE_PARM_DESC(digimatrix, + "Asus Digimatrix it87 compat. enable/disable (1/0), default: 0"); +#endif + + +module_param(it87_freq, int, 0444); +#ifdef LIRC_IT87_DIGIMATRIX +MODULE_PARM_DESC(it87_freq, + "Carrier demodulator frequency (kHz), (default: 36)"); +#else +MODULE_PARM_DESC(it87_freq, + "Carrier demodulator frequency (kHz), (default: 38)"); +#endif + +EXPORT_NO_SYMBOLS; + +#endif /* MODULE */ + + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_streamzap/Makefile +++ linux-2.6.27/ubuntu/lirc/lirc_streamzap/Makefile @@ -0,0 +1,3 @@ + +EXTRA_CFLAGS =-DIRCTL_DEV_MAJOR=61 -DLIRC_SERIAL_TRANSMITTER -DLIRC_SERIAL_SOFTCARRIER -I$(src)/.. +obj-$(CONFIG_LIRC_STREAMZAP) += lirc_streamzap.o --- linux-2.6.27.orig/ubuntu/lirc/lirc_streamzap/lirc_streamzap.c +++ linux-2.6.27/ubuntu/lirc/lirc_streamzap/lirc_streamzap.c @@ -0,0 +1,912 @@ +/* $Id: lirc_streamzap.c,v 1.27 2008/01/13 11:13:50 lirc Exp $ */ + +/* + * Streamzap Remote Control driver + * + * Copyright (c) 2005 Christoph Bartelmus + * + * This driver was based on the work of Greg Wickham and Adrian + * Dewhurst. It was substantially rewritten to support correct signal + * gaps and now maintains a delay buffer, which is used to present + * consistent timing behaviour to user space applications. Without the + * delay buffer an ugly hack would be required in lircd, which can + * cause sluggish signal decoding in certain situations. + * + * This driver is based on the USB skeleton driver packaged with the + * kernel; copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) +#error "*******************************************************" +#error "Sorry, this driver needs kernel version 2.4.0 or higher" +#error "*******************************************************" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) +#include +#else +#include +#endif +#include + +#include "lirc.h" +#include "kcompat.h" +#include "lirc_dev/lirc_dev.h" + +#define DRIVER_VERSION "$Revision: 1.27 $" +#define DRIVER_NAME "lirc_streamzap" +#define DRIVER_DESC "Streamzap Remote Control driver" + +/* ------------------------------------------------------------------ */ + +static int debug; + +#define USB_STREAMZAP_VENDOR_ID 0x0e9c +#define USB_STREAMZAP_PRODUCT_ID 0x0000 + +/* Use our own dbg macro */ +#define dprintk(fmt, args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG DRIVER_NAME "[%d]: " \ + fmt "\n", ## args); \ + } while (0) + +/* + * table of devices that work with this driver + */ +static struct usb_device_id streamzap_table [] = { + { USB_DEVICE(USB_STREAMZAP_VENDOR_ID, USB_STREAMZAP_PRODUCT_ID) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, streamzap_table); + +#define STREAMZAP_PULSE_MASK 0xf0 +#define STREAMZAP_SPACE_MASK 0x0f +#define STREAMZAP_RESOLUTION 256 + +/* number of samples buffered */ +#define STREAMZAP_BUFFER_SIZE 128 + +enum StreamzapDecoderState { + PulseSpace, + FullPulse, + FullSpace, + IgnorePulse +}; + +/* Structure to hold all of our device specific stuff */ +/* some remarks regarding locking: + theoretically this struct can be accessed from three threads: + + - from lirc_dev through set_use_inc/set_use_dec + + - from the USB layer throuh probe/disconnect/irq + + Careful placement of lirc_register_plugin/lirc_unregister_plugin + calls will prevent conflicts. lirc_dev makes sure that + set_use_inc/set_use_dec are not being executed and will not be + called after lirc_unregister_plugin returns. + + - by the timer callback + + The timer is only running when the device is connected and the + LIRC device is open. Making sure the timer is deleted by + set_use_dec will make conflicts impossible. +*/ +struct usb_streamzap { + + /* usb */ + /* save off the usb device pointer */ + struct usb_device *udev; + /* the interface for this device */ + struct usb_interface *interface; + + /* buffer & dma */ + unsigned char *buf_in; + dma_addr_t dma_in; + unsigned int buf_in_len; + + struct usb_endpoint_descriptor *endpoint; + + /* IRQ */ + struct urb *urb_in; + + /* lirc */ + struct lirc_plugin plugin; + struct lirc_buffer delay_buf; + struct lirc_buffer lirc_buf; + + /* timer used to support delay buffering */ + struct timer_list delay_timer; + int timer_running; + spinlock_t timer_lock; + + /* tracks whether we are currently receiving some signal */ + int idle; + /* sum of signal lengths received since signal start */ + unsigned long sum; + /* start time of signal; necessary for gap tracking */ + struct timeval signal_last; + struct timeval signal_start; + enum StreamzapDecoderState decoder_state; + struct timer_list flush_timer; + int flush; + int in_use; +}; + + +/* local function prototypes */ +#ifdef KERNEL_2_5 +static int streamzap_probe(struct usb_interface *interface, + const struct usb_device_id *id); +static void streamzap_disconnect(struct usb_interface *interface); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void usb_streamzap_irq(struct urb *urb, struct pt_regs *regs); +#else +static void usb_streamzap_irq(struct urb *urb); +#endif +#else +static void *streamzap_probe(struct usb_device *udev, unsigned int ifnum, + const struct usb_device_id *id); +static void streamzap_disconnect(struct usb_device *dev, void *ptr); +static void usb_streamzap_irq(struct urb *urb); +#endif +static int streamzap_use_inc(void *data); +static void streamzap_use_dec(void *data); +static int streamzap_ioctl(struct inode *node, struct file *filep, + unsigned int cmd, unsigned long arg); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) +static int streamzap_suspend(struct usb_interface *intf, pm_message_t message); +static int streamzap_resume(struct usb_interface *intf); +#endif + +/* usb specific object needed to register this driver with the usb subsystem */ + +static struct usb_driver streamzap_driver = { + LIRC_THIS_MODULE(.owner = THIS_MODULE) + .name = DRIVER_NAME, + .probe = streamzap_probe, + .disconnect = streamzap_disconnect, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + .suspend = streamzap_suspend, + .resume = streamzap_resume, +#endif + .id_table = streamzap_table, +}; + +static void stop_timer(struct usb_streamzap *sz) +{ + unsigned long flags; + + spin_lock_irqsave(&sz->timer_lock, flags); + if (sz->timer_running) { + sz->timer_running = 0; + del_timer_sync(&sz->delay_timer); + } + spin_unlock_irqrestore(&sz->timer_lock, flags); +} + +static void flush_timeout(unsigned long arg) +{ + struct usb_streamzap *sz = (struct usb_streamzap *) arg; + + /* finally start accepting data */ + sz->flush = 0; +} +static void delay_timeout(unsigned long arg) +{ + unsigned long flags; + /* deliver data every 10 ms */ + static unsigned long timer_inc = + (10000/(1000000/HZ)) == 0 ? 1:(10000/(1000000/HZ)); + struct usb_streamzap *sz = (struct usb_streamzap *) arg; + lirc_t data; + + spin_lock_irqsave(&sz->timer_lock, flags); + + if (!lirc_buffer_empty(&sz->delay_buf) && + !lirc_buffer_full(&sz->lirc_buf)) { + lirc_buffer_read_1(&sz->delay_buf, (unsigned char *) &data); + lirc_buffer_write_1(&sz->lirc_buf, (unsigned char *) &data); + } + if (!lirc_buffer_empty(&sz->delay_buf)) { + while (lirc_buffer_available(&sz->delay_buf) < + STREAMZAP_BUFFER_SIZE/2 && + !lirc_buffer_full(&sz->lirc_buf)) { + lirc_buffer_read_1(&sz->delay_buf, + (unsigned char *) &data); + lirc_buffer_write_1(&sz->lirc_buf, + (unsigned char *) &data); + } + if (sz->timer_running) { + sz->delay_timer.expires += timer_inc; + add_timer(&sz->delay_timer); + } + } else { + sz->timer_running = 0; + } + + if (!lirc_buffer_empty(&sz->lirc_buf)) + wake_up(&sz->lirc_buf.wait_poll); + + spin_unlock_irqrestore(&sz->timer_lock, flags); +} + +static inline void flush_delay_buffer(struct usb_streamzap *sz) +{ + lirc_t data; + int empty = 1; + + while (!lirc_buffer_empty(&sz->delay_buf)) { + empty = 0; + lirc_buffer_read_1(&sz->delay_buf, (unsigned char *) &data); + if (!lirc_buffer_full(&sz->lirc_buf)) { + lirc_buffer_write_1(&sz->lirc_buf, + (unsigned char *) &data); + } else { + dprintk("buffer overflow\n", sz->plugin.minor); + } + } + if (!empty) + wake_up(&sz->lirc_buf.wait_poll); +} + +static inline void push(struct usb_streamzap *sz, unsigned char *data) +{ + unsigned long flags; + + spin_lock_irqsave(&sz->timer_lock, flags); + if (lirc_buffer_full(&sz->delay_buf)) { + lirc_t data; + + lirc_buffer_read_1(&sz->delay_buf, (unsigned char *) &data); + if (!lirc_buffer_full(&sz->lirc_buf)) { + lirc_buffer_write_1(&sz->lirc_buf, + (unsigned char *) &data); + } else { + dprintk("buffer overflow", sz->plugin.minor); + } + } + + lirc_buffer_write_1(&sz->delay_buf, data); + + if (!sz->timer_running) { + sz->delay_timer.expires = jiffies + HZ/10; + add_timer(&sz->delay_timer); + sz->timer_running = 1; + } + + spin_unlock_irqrestore(&sz->timer_lock, flags); +} + +static inline void push_full_pulse(struct usb_streamzap *sz, + unsigned char value) +{ + lirc_t pulse; + + if (sz->idle) { + long deltv; + lirc_t tmp; + + sz->signal_last = sz->signal_start; + do_gettimeofday(&sz->signal_start); + + deltv = sz->signal_start.tv_sec-sz->signal_last.tv_sec; + if (deltv > 15) { + tmp = PULSE_MASK; /* really long time */ + } else { + tmp = (lirc_t) (deltv*1000000+ + sz->signal_start.tv_usec - + sz->signal_last.tv_usec); + tmp -= sz->sum; + } + dprintk("ls %u", sz->plugin.minor, tmp); + push(sz, (char *)&tmp); + + sz->idle = 0; + sz->sum = 0; + } + + pulse = ((lirc_t) value)*STREAMZAP_RESOLUTION; + pulse += STREAMZAP_RESOLUTION/2; + sz->sum += pulse; + pulse |= PULSE_BIT; + + dprintk("p %u", sz->plugin.minor, pulse&PULSE_MASK); + push(sz, (char *)&pulse); +} + +static inline void push_half_pulse(struct usb_streamzap *sz, + unsigned char value) +{ + push_full_pulse(sz, (value & STREAMZAP_PULSE_MASK)>>4); +} + +static inline void push_full_space(struct usb_streamzap *sz, + unsigned char value) +{ + lirc_t space; + + space = ((lirc_t) value)*STREAMZAP_RESOLUTION; + space += STREAMZAP_RESOLUTION/2; + sz->sum += space; + dprintk("s %u", sz->plugin.minor, space); + push(sz, (char *)&space); +} + +static inline void push_half_space(struct usb_streamzap *sz, + unsigned char value) +{ + push_full_space(sz, value & STREAMZAP_SPACE_MASK); +} + +/* + * usb_streamzap_irq - IRQ handler + * + * This procedure is invoked on reception of data from + * the usb remote. + */ +#if defined(KERNEL_2_5) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void usb_streamzap_irq(struct urb *urb, struct pt_regs *regs) +#else +static void usb_streamzap_irq(struct urb *urb) +#endif +{ + struct usb_streamzap *sz; + int len; + unsigned int i = 0; + + if (!urb) + return; + + sz = urb->context; + len = urb->actual_length; + + switch (urb->status) { + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + /* sz might already be invalid at this point */ + dprintk("urb status: %d", -1, urb->status); + return; + default: + break; + } + + dprintk("received %d", sz->plugin.minor, urb->actual_length); + if (!sz->flush) { + for (i = 0; i < urb->actual_length; i++) { + dprintk("%d: %x", sz->plugin.minor, + i, (unsigned char) sz->buf_in[i]); + switch (sz->decoder_state) { + case PulseSpace: + if ((sz->buf_in[i]&STREAMZAP_PULSE_MASK) == + STREAMZAP_PULSE_MASK) { + sz->decoder_state = FullPulse; + continue; + } else if ((sz->buf_in[i]&STREAMZAP_SPACE_MASK) + == STREAMZAP_SPACE_MASK) { + push_half_pulse(sz, sz->buf_in[i]); + sz->decoder_state = FullSpace; + continue; + } else { + push_half_pulse(sz, sz->buf_in[i]); + push_half_space(sz, sz->buf_in[i]); + } + break; + case FullPulse: + push_full_pulse(sz, sz->buf_in[i]); + sz->decoder_state = IgnorePulse; + break; + case FullSpace: + if (sz->buf_in[i] == 0xff) { + sz->idle = 1; + stop_timer(sz); + flush_delay_buffer(sz); + } else + push_full_space(sz, sz->buf_in[i]); + sz->decoder_state = PulseSpace; + break; + case IgnorePulse: + if ((sz->buf_in[i]&STREAMZAP_SPACE_MASK) == + STREAMZAP_SPACE_MASK) { + sz->decoder_state = FullSpace; + continue; + } + push_half_space(sz, sz->buf_in[i]); + sz->decoder_state = PulseSpace; + break; + } + } + } + +#ifdef KERNEL_2_5 + /* resubmit only for 2.6 */ + usb_submit_urb(urb, GFP_ATOMIC); +#endif + + return; +} + +/** + * streamzap_probe + * + * Called by usb-core to associated with a candidate device + * On any failure the return value is the ERROR + * On success return 0 + */ +#ifdef KERNEL_2_5 +static int streamzap_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(interface); + struct usb_host_interface *iface_host; +#else +static void *streamzap_probe(struct usb_device *udev, unsigned int ifnum, + const struct usb_device_id *id) +{ + struct usb_interface *interface = &udev->actconfig->interface[ifnum]; + struct usb_interface_descriptor *iface_host; +#endif + int retval = -ENOMEM; + struct usb_streamzap *sz = NULL; + char buf[63], name[128] = ""; + + /*************************************************** + * Allocate space for device driver specific data + */ + sz = kmalloc(sizeof(struct usb_streamzap), GFP_KERNEL); + if (sz == NULL) + goto error; + + memset(sz, 0, sizeof(*sz)); + sz->udev = udev; + sz->interface = interface; + + /*************************************************** + * Check to ensure endpoint information matches requirements + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 5) + iface_host = &interface->altsetting[interface->act_altsetting]; +#else + iface_host = interface->cur_altsetting; +#endif + +#ifdef KERNEL_2_5 + if (iface_host->desc.bNumEndpoints != 1) { +#else + if (iface_host->bNumEndpoints != 1) { +#endif +#ifdef KERNEL_2_5 + err("%s: Unexpected desc.bNumEndpoints (%d)", __FUNCTION__, + iface_host->desc.bNumEndpoints); +#else + err("%s: Unexpected desc.bNumEndpoints (%d)", __FUNCTION__, + iface_host->bNumEndpoints); +#endif + retval = -ENODEV; + goto error; + } + +#ifdef KERNEL_2_5 + sz->endpoint = &(iface_host->endpoint[0].desc); +#else + sz->endpoint = &(iface_host->endpoint[0]); +#endif + if ((sz->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + != USB_DIR_IN) { + err("%s: endpoint doesn't match input device 02%02x", + __FUNCTION__, sz->endpoint->bEndpointAddress); + retval = -ENODEV; + goto error; + } + + if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + != USB_ENDPOINT_XFER_INT) { + err("%s: endpoint attributes don't match xfer 02%02x", + __FUNCTION__, sz->endpoint->bmAttributes); + retval = -ENODEV; + goto error; + } + + if (sz->endpoint->wMaxPacketSize == 0) { + err("%s: endpoint message size==0? ", __FUNCTION__); + retval = -ENODEV; + goto error; + } + + /*************************************************** + * Allocate the USB buffer and IRQ URB + */ + + sz->buf_in_len = sz->endpoint->wMaxPacketSize; +#ifdef KERNEL_2_5 + sz->buf_in = usb_buffer_alloc(sz->udev, sz->buf_in_len, + GFP_ATOMIC, &sz->dma_in); +#else + sz->buf_in = kmalloc(sz->buf_in_len, GFP_KERNEL); +#endif + if (sz->buf_in == NULL) + goto error; + +#ifdef KERNEL_2_5 + sz->urb_in = usb_alloc_urb(0, GFP_KERNEL); +#else + + sz->urb_in = usb_alloc_urb(0); +#endif + if (sz->urb_in == NULL) + goto error; + + /*************************************************** + * Connect this device to the LIRC sub-system + */ + + if (lirc_buffer_init(&sz->lirc_buf, sizeof(lirc_t), + STREAMZAP_BUFFER_SIZE)) + goto error; + + if (lirc_buffer_init(&sz->delay_buf, sizeof(lirc_t), + STREAMZAP_BUFFER_SIZE)) { + lirc_buffer_free(&sz->lirc_buf); + goto error; + } + + /*************************************************** + * As required memory is allocated now populate the plugin structure + */ + + memset(&sz->plugin, 0, sizeof(sz->plugin)); + + strcpy(sz->plugin.name, DRIVER_NAME); + sz->plugin.minor = -1; + sz->plugin.sample_rate = 0; + sz->plugin.code_length = sizeof(lirc_t) * 8; + sz->plugin.features = LIRC_CAN_REC_MODE2|LIRC_CAN_GET_REC_RESOLUTION; + sz->plugin.data = sz; + sz->plugin.rbuf = &sz->lirc_buf; + sz->plugin.set_use_inc = &streamzap_use_inc; + sz->plugin.set_use_dec = &streamzap_use_dec; + sz->plugin.ioctl = streamzap_ioctl; +#ifdef LIRC_HAVE_SYSFS + sz->plugin.dev = &udev->dev; +#endif + sz->plugin.owner = THIS_MODULE; + + sz->idle = 1; + sz->decoder_state = PulseSpace; + init_timer(&sz->delay_timer); + sz->delay_timer.function = delay_timeout; + sz->delay_timer.data = (unsigned long) sz; + sz->timer_running = 0; + spin_lock_init(&sz->timer_lock); + + init_timer(&sz->flush_timer); + sz->flush_timer.function = flush_timeout; + sz->flush_timer.data = (unsigned long) sz; + /*************************************************** + * Complete final initialisations + */ + + usb_fill_int_urb(sz->urb_in, udev, + usb_rcvintpipe(udev, sz->endpoint->bEndpointAddress), + sz->buf_in, sz->buf_in_len, usb_streamzap_irq, sz, + sz->endpoint->bInterval); + + if (udev->descriptor.iManufacturer + && usb_string(udev, udev->descriptor.iManufacturer, buf, 63) > 0) + strncpy(name, buf, 128); + + if (udev->descriptor.iProduct + && usb_string(udev, udev->descriptor.iProduct, buf, 63) > 0) + snprintf(name, 128, "%s %s", name, buf); + + printk(KERN_INFO DRIVER_NAME "[%d]: %s on usb%d:%d attached\n", + sz->plugin.minor, name, + udev->bus->busnum, sz->udev->devnum); + +#ifdef KERNEL_2_5 + usb_set_intfdata(interface, sz); +#endif + + if (lirc_register_plugin(&sz->plugin) < 0) { + lirc_buffer_free(&sz->delay_buf); + lirc_buffer_free(&sz->lirc_buf); + goto error; + } + +#ifdef KERNEL_2_5 + return 0; +#else + return sz; +#endif + +error: + + /*************************************************** + * Premise is that a 'goto error' can be invoked from inside the + * probe function and all necessary cleanup actions will be taken + * including freeing any necessary memory blocks + */ + + if (retval == -ENOMEM) + err("Out of memory"); + + if (sz) { + + if (sz->urb_in) + usb_free_urb(sz->urb_in); + + if (sz->buf_in) { +#ifdef KERNEL_2_5 + usb_buffer_free(udev, sz->buf_in_len, + sz->buf_in, sz->dma_in); +#else + kfree(sz->buf_in); +#endif + } + kfree(sz); + } + +#ifdef KERNEL_2_5 + return retval; +#else + return NULL; +#endif +} + +static int streamzap_use_inc(void *data) +{ + struct usb_streamzap *sz = data; + + if (!sz) { + dprintk("%s called with no context", -1, __FUNCTION__); + return -EINVAL; + } + dprintk("set use inc", sz->plugin.minor); + + MOD_INC_USE_COUNT; + + while (!lirc_buffer_empty(&sz->lirc_buf)) + lirc_buffer_remove_1(&sz->lirc_buf); + while (!lirc_buffer_empty(&sz->delay_buf)) + lirc_buffer_remove_1(&sz->delay_buf); + + sz->flush_timer.expires = jiffies + HZ; + sz->flush = 1; + add_timer(&sz->flush_timer); + + sz->urb_in->dev = sz->udev; +#ifdef KERNEL_2_5 + if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { +#else + if (usb_submit_urb(sz->urb_in)) { +#endif + dprintk("open result = -EIO error submitting urb", + sz->plugin.minor); + MOD_DEC_USE_COUNT; + return -EIO; + } + sz->in_use++; + + return 0; +} + +static void streamzap_use_dec(void *data) +{ + struct usb_streamzap *sz = data; + + if (!sz) { + dprintk("%s called with no context", -1, __FUNCTION__); + return; + } + dprintk("set use dec", sz->plugin.minor); + + if (sz->flush) { + sz->flush = 0; + del_timer_sync(&sz->flush_timer); + } + + stop_timer(sz); + + usb_kill_urb(sz->urb_in); + + MOD_DEC_USE_COUNT; + sz->in_use--; +} + +static int streamzap_ioctl(struct inode *node, struct file *filep, + unsigned int cmd, unsigned long arg) +{ + int result; + + switch (cmd) { + case LIRC_GET_REC_RESOLUTION: + result = put_user(STREAMZAP_RESOLUTION, (unsigned long *) arg); + if (result) + return(result); + break; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +/** + * streamzap_disconnect + * + * Called by the usb core when the device is removed from the system. + * + * This routine guarantees that the driver will not submit any more urbs + * by clearing dev->udev. It is also supposed to terminate any currently + * active urbs. Unfortunately, usb_bulk_msg(), used in streamzap_read(), + * does not provide any way to do this. + */ +#ifdef KERNEL_2_5 +static void streamzap_disconnect(struct usb_interface *interface) +#else +static void streamzap_disconnect(struct usb_device *dev, void *ptr) +#endif +{ + struct usb_streamzap *sz; + int errnum; + int minor; + +#ifdef KERNEL_2_5 + sz = usb_get_intfdata(interface); +#else + sz = ptr; +#endif + + /* + * unregister from the LIRC sub-system + */ + + errnum = lirc_unregister_plugin(sz->plugin.minor); + if (errnum != 0) + dprintk("error in lirc_unregister: (returned %d)", + sz->plugin.minor, errnum); + + lirc_buffer_free(&sz->delay_buf); + lirc_buffer_free(&sz->lirc_buf); + + /* + * unregister from the USB sub-system + */ + + usb_free_urb(sz->urb_in); + +#ifdef KERNEL_2_5 + usb_buffer_free(sz->udev, sz->buf_in_len, sz->buf_in, sz->dma_in); +#else + kfree(sz->buf_in); +#endif + + minor = sz->plugin.minor; + kfree(sz); + + printk(KERN_INFO DRIVER_NAME "[%d]: disconnected\n", minor); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) +static int streamzap_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct usb_streamzap *sz = usb_get_intfdata(intf); + + printk(DRIVER_NAME "[%d]: suspend\n", sz->plugin.minor); + if (sz->in_use) { + if (sz->flush) { + sz->flush = 0; + del_timer_sync(&sz->flush_timer); + } + + stop_timer(sz); + + usb_kill_urb(sz->urb_in); + } + return 0; +} + +static int streamzap_resume(struct usb_interface *intf) +{ + struct usb_streamzap *sz = usb_get_intfdata(intf); + + while (!lirc_buffer_empty(&sz->lirc_buf)) + lirc_buffer_remove_1(&sz->lirc_buf); + while (!lirc_buffer_empty(&sz->delay_buf)) + lirc_buffer_remove_1(&sz->delay_buf); + + if (sz->in_use) { + sz->flush_timer.expires = jiffies + HZ; + sz->flush = 1; + add_timer(&sz->flush_timer); + + sz->urb_in->dev = sz->udev; +#ifdef KERNEL_2_5 + if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { +#else + if (usb_submit_urb(sz->urb_in)) { +#endif + dprintk("open result = -EIO error submitting urb", + sz->plugin.minor); + MOD_DEC_USE_COUNT; + return -EIO; + } + } + return 0; +} +#endif + +#ifdef MODULE + +/** + * usb_streamzap_init + */ +static int __init usb_streamzap_init(void) +{ + int result; + + /* register this driver with the USB subsystem */ + + result = usb_register(&streamzap_driver); + + if (result) { + err("usb_register failed. Error number %d", + result); + return result; + } + + printk(KERN_INFO DRIVER_NAME " " DRIVER_VERSION " registered\n"); + return 0; +} + +/** + * usb_streamzap_exit + */ +static void __exit usb_streamzap_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&streamzap_driver); +} + + +module_init(usb_streamzap_init); +module_exit(usb_streamzap_exit); + +MODULE_AUTHOR("Christoph Bartelmus, Greg Wickham, Adrian Dewhurst"); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, 0644); +MODULE_PARM_DESC(debug, "Enable debugging messages"); + +EXPORT_NO_SYMBOLS; + +#endif /* MODULE */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_bt829/lirc_bt829.c +++ linux-2.6.27/ubuntu/lirc/lirc_bt829/lirc_bt829.c @@ -0,0 +1,403 @@ +/* + * Remote control driver for the TV-card based on bt829 + * + * by Leonid Froenchenko + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) +#error "This driver needs kernel version 2.4.0 or higher" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kcompat.h" +#include "lirc_dev/lirc_dev.h" + +static int poll_main(void); +static int atir_init_start(void); + +static void write_index(unsigned char index, unsigned int value); +static unsigned int read_index(unsigned char index); + +static void do_i2c_start(void); +static void do_i2c_stop(void); + +static void seems_wr_byte(unsigned char al); +static unsigned char seems_rd_byte(void); + +static unsigned int read_index(unsigned char al); +static void write_index(unsigned char ah, unsigned int edx); + +static void cycle_delay(int cycle); + +static void do_set_bits(unsigned char bl); +static unsigned char do_get_bits(void); + +#define DATA_PCI_OFF 0x7FFC00 +#define WAIT_CYCLE 20 + +static int debug; +#define dprintk(fmt, args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG fmt, ## args); \ + } while (0) + +static int atir_minor; +static unsigned long pci_addr_phys; +static unsigned char *pci_addr_lin; + +static struct lirc_plugin atir_plugin; + +static struct pci_dev *do_pci_probe(void) +{ + struct pci_dev *my_dev; +#ifndef KERNEL_2_5 + /* unnecessary with recent kernels */ + if (!pci_present()) + printk(KERN_ERR "ATIR: no pci in this kernel\n"); +#endif + my_dev = pci_get_device(PCI_VENDOR_ID_ATI, + PCI_DEVICE_ID_ATI_264VT, NULL); + if (my_dev) { + printk(KERN_ERR "ATIR: Using device: %s\n", + pci_name(my_dev)); + pci_addr_phys = 0; + if (my_dev->resource[0].flags & IORESOURCE_MEM) { + pci_addr_phys = my_dev->resource[0].start; + printk(KERN_INFO "ATIR memory at 0x%08X \n", + (unsigned int)pci_addr_phys); + } + if (pci_addr_phys == 0) { + printk(KERN_ERR "ATIR no memory resource ?\n"); + return NULL; + } + } else { + printk(KERN_ERR "ATIR: pci_prob failed\n"); + return NULL; + } + return my_dev; +} + +static int atir_add_to_buf(void *data, struct lirc_buffer *buf) +{ + unsigned char key; + int status; + status = poll_main(); + key = (status >> 8) & 0xFF; + if (status & 0xFF) { + dprintk("ATIR reading key %02X\n", key); + lirc_buffer_write_1(buf, &key); + return 0; + } + return -ENODATA; +} + +static int atir_set_use_inc(void *data) +{ + MOD_INC_USE_COUNT; + dprintk("ATIR driver is opened\n"); + return 0; +} + +static void atir_set_use_dec(void *data) +{ + MOD_DEC_USE_COUNT; + dprintk("ATIR driver is closed\n"); +} + +int init_module(void) +{ + struct pci_dev *pdev; + + pdev = do_pci_probe(); + if (pdev == NULL) + return 1; + + if (!atir_init_start()) + return 1; + + strcpy(atir_plugin.name, "ATIR"); + atir_plugin.minor = -1; + atir_plugin.code_length = 8; + atir_plugin.sample_rate = 10; + atir_plugin.data = 0; + atir_plugin.add_to_buf = atir_add_to_buf; + atir_plugin.set_use_inc = atir_set_use_inc; + atir_plugin.set_use_dec = atir_set_use_dec; +#ifdef LIRC_HAVE_SYSFS + atir_plugin.dev = &pdev->dev; +#endif + atir_plugin.owner = THIS_MODULE; + + atir_minor = lirc_register_plugin(&atir_plugin); + dprintk("ATIR driver is registered on minor %d\n", atir_minor); + + return 0; +} + + +void cleanup_module(void) +{ + lirc_unregister_plugin(atir_minor); +} + + +static int atir_init_start(void) +{ + pci_addr_lin = ioremap(pci_addr_phys + DATA_PCI_OFF, 0x400); + if (pci_addr_lin == 0) { + printk(KERN_INFO "atir: pci mem must be mapped\n"); + return 0; + } + return 1; +} + +static void cycle_delay(int cycle) +{ + udelay(WAIT_CYCLE*cycle); +} + + +static int poll_main() +{ + unsigned char status_high, status_low; + + do_i2c_start(); + + seems_wr_byte(0xAA); + seems_wr_byte(0x01); + + do_i2c_start(); + + seems_wr_byte(0xAB); + + status_low = seems_rd_byte(); + status_high = seems_rd_byte(); + + do_i2c_stop(); + + return (status_high << 8) | status_low; +} + +static void do_i2c_start(void) +{ + do_set_bits(3); + cycle_delay(4); + + do_set_bits(1); + cycle_delay(7); + + do_set_bits(0); + cycle_delay(2); +} + +static void do_i2c_stop(void) +{ + unsigned char bits; + bits = do_get_bits() & 0xFD; + do_set_bits(bits); + cycle_delay(1); + + bits |= 1; + do_set_bits(bits); + cycle_delay(2); + + bits |= 2; + do_set_bits(bits); + bits = 3; + do_set_bits(bits); + cycle_delay(2); +} + +static void seems_wr_byte(unsigned char value) +{ + int i; + unsigned char reg; + + reg = do_get_bits(); + for (i = 0; i < 8; i++) { + if (value & 0x80) + reg |= 0x02; + else + reg &= 0xFD; + + do_set_bits(reg); + cycle_delay(1); + + reg |= 1; + do_set_bits(reg); + cycle_delay(1); + + reg &= 0xFE; + do_set_bits(reg); + cycle_delay(1); + value <<= 1; + } + cycle_delay(2); + + reg |= 2; + do_set_bits(reg); + + reg |= 1; + do_set_bits(reg); + + cycle_delay(1); + do_get_bits(); + + reg &= 0xFE; + do_set_bits(reg); + cycle_delay(3); +} + +static unsigned char seems_rd_byte(void) +{ + int i; + int rd_byte; + unsigned char bits_2, bits_1; + + bits_1 = do_get_bits() | 2; + do_set_bits(bits_1); + + rd_byte = 0; + for (i = 0; i < 8; i++) { + bits_1 &= 0xFE; + do_set_bits(bits_1); + cycle_delay(2); + + bits_1 |= 1; + do_set_bits(bits_1); + cycle_delay(1); + + bits_2 = do_get_bits(); + if (bits_2 & 2) + rd_byte |= 1; + + rd_byte <<= 1; + } + + bits_1 = 0; + if (bits_2 == 0) + bits_1 |= 2; + + do_set_bits(bits_1); + cycle_delay(2); + + bits_1 |= 1; + do_set_bits(bits_1); + cycle_delay(3); + + bits_1 &= 0xFE; + do_set_bits(bits_1); + cycle_delay(2); + + rd_byte >>= 1; + rd_byte &= 0xFF; + return rd_byte; +} + +static void do_set_bits(unsigned char new_bits) +{ + int reg_val; + reg_val = read_index(0x34); + if (new_bits & 2) { + reg_val &= 0xFFFFFFDF; + reg_val |= 1; + } else { + reg_val &= 0xFFFFFFFE; + reg_val |= 0x20; + } + reg_val |= 0x10; + write_index(0x34, reg_val); + + reg_val = read_index(0x31); + if (new_bits & 1) { + reg_val |= 0x1000000; + } else { + reg_val &= 0xFEFFFFFF; + } + reg_val |= 0x8000000; + write_index(0x31, reg_val); +} + +static unsigned char do_get_bits(void) +{ + unsigned char bits; + int reg_val; + + reg_val = read_index(0x34); + reg_val |= 0x10; + reg_val &= 0xFFFFFFDF; + write_index(0x34, reg_val); + + reg_val = read_index(0x34); + bits = 0; + if (reg_val & 8) { + bits |= 2; + } else { + bits &= 0xFD; + } + reg_val = read_index(0x31); + if (reg_val & 0x1000000) { + bits |= 1; + } else { + bits &= 0xFE; + } + return bits; +} + +static unsigned int read_index(unsigned char index) +{ + unsigned char *addr; + unsigned int value; + /* addr = pci_addr_lin + DATA_PCI_OFF + ((index & 0xFF) << 2); */ + addr = pci_addr_lin + ((index & 0xFF) << 2); + value = readl(addr); + return value; +} + +static void write_index(unsigned char index, unsigned int reg_val) +{ + unsigned char *addr; + addr = pci_addr_lin + ((index & 0xFF) << 2); + writel(reg_val, addr); +} + +MODULE_AUTHOR("Froenchenko Leonid"); +MODULE_DESCRIPTION("IR remote driver for bt829 based TV cards"); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, 0644); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +EXPORT_NO_SYMBOLS; + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_bt829/Makefile +++ linux-2.6.27/ubuntu/lirc/lirc_bt829/Makefile @@ -0,0 +1,3 @@ +EXTRA_CFLAGS =-DIRCTL_DEV_MAJOR=61 -DLIRC_SERIAL_TRANSMITTER -DLIRC_SERIAL_SOFTCARRIER -I$(src)/.. + +obj-$(CONFIG_LIRC_ATIUSB) += lirc_bt829.o --- linux-2.6.27.orig/ubuntu/lirc/lirc_atiusb/lirc_atiusb.c +++ linux-2.6.27/ubuntu/lirc/lirc_atiusb/lirc_atiusb.c @@ -0,0 +1,1437 @@ +/* lirc_atiusb - USB remote support for LIRC + * (currently only supports X10 USB remotes) + * (supports ATI Remote Wonder and ATI Remote Wonder II, too) + * + * Copyright (C) 2003-2004 Paul Miller + * + * This driver was derived from: + * Vladimir Dergachev 's 2002 + * "USB ATI Remote support" (input device) + * Adrian Dewhurst 's 2002 + * "USB StreamZap remote driver" (LIRC) + * Artur Lipowski 's 2002 + * "lirc_dev" and "lirc_gpio" LIRC modules + * Michael Wojciechowski + * initial xbox support + * Vassilis Virvilis 2006 + * reworked the patch for lirc submission + * + * $Id: lirc_atiusb.c,v 1.69 2008/04/28 06:47:29 lirc Exp $ + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) +#error "*******************************************************" +#error "Sorry, this driver needs kernel version 2.4.0 or higher" +#error "*******************************************************" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) +#include +#else +#include +#endif +#include +#include +#include +#include + +#include "lirc.h" +#include "kcompat.h" +#include "lirc_dev/lirc_dev.h" + +#define DRIVER_VERSION "$Revision: 1.69 $" +#define DRIVER_AUTHOR "Paul Miller " +#define DRIVER_DESC "USB remote driver for LIRC" +#define DRIVER_NAME "lirc_atiusb" + +#define CODE_LENGTH code_length[ir->remote_type] +#define CODE_MIN_LENGTH code_min_length[ir->remote_type] +#define DECODE_LENGTH decode_length[ir->remote_type] + +#define RW2_MODENAV_KEYCODE 0x3F +#define RW2_NULL_MODE 0xFF +/* Fake (virtual) keycode indicating compass mouse usage */ +#define RW2_MOUSE_KEYCODE 0xFF +#define RW2_PRESSRELEASE_KEYCODE 0xFE + +#define RW2_PRESS_CODE 1 +#define RW2_HOLD_CODE 2 +#define RW2_RELEASE_CODE 0 + +/* module parameters */ +#ifdef CONFIG_USB_DEBUG +static int debug = 1; +#else +static int debug; +#endif +#define dprintk(fmt, args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG fmt, ## args); \ + } while (0) + +/* ATI, ATI2, XBOX */ +static const int code_length[] = {5, 3, 6}; +static const int code_min_length[] = {3, 3, 6}; +static const int decode_length[] = {5, 3, 1}; +/* USB_BUFF_LEN must be the maximum value of the code_length array. + * It is used for static arrays. */ +#define USB_BUFF_LEN 6 + +static int mask = 0xFFFF; /* channel acceptance bit mask */ +static int unique; /* enable channel-specific codes */ +static int repeat = 10; /* repeat time in 1/100 sec */ +static int emit_updown; /* send seperate press/release codes (rw2) */ +static int emit_modekeys; /* send keycodes for aux1-4, pc, and mouse (rw2) */ +static unsigned long repeat_jiffies; /* repeat timeout */ +static int mdeadzone; /* mouse sensitivity >= 0 */ +static int mgradient = 375; /* 1000*gradient from cardinal direction */ + +/* get hi and low bytes of a 16-bits int */ +#define HI(a) ((unsigned char)((a) >> 8)) +#define LO(a) ((unsigned char)((a) & 0xff)) + +/* lock irctl structure */ +#define IRLOCK down_interruptible(&ir->lock) +#define IRUNLOCK up(&ir->lock) + +/* general constants */ +#define SUCCESS 0 +#define SEND_FLAG_IN_PROGRESS 1 +#define SEND_FLAG_COMPLETE 2 +#define FREE_ALL 0xFF + +/* endpoints */ +#define EP_KEYS 0 +#define EP_MOUSE 1 +#define EP_MOUSE_ADDR 0x81 +#define EP_KEYS_ADDR 0x82 + +#define VENDOR_ATI1 0x0bc7 +#define VENDOR_ATI2 0x0471 +#define VENDOR_MS1 0x040b +#define VENDOR_MS2 0x045e +#define VENDOR_MS3 0xFFFF + +static struct usb_device_id usb_remote_table [] = { + /* X10 USB Firecracker Interface */ + { USB_DEVICE(VENDOR_ATI1, 0x0002) }, + + /* X10 VGA Video Sender */ + { USB_DEVICE(VENDOR_ATI1, 0x0003) }, + + /* ATI Wireless Remote Receiver */ + { USB_DEVICE(VENDOR_ATI1, 0x0004) }, + + /* NVIDIA Wireless Remote Receiver */ + { USB_DEVICE(VENDOR_ATI1, 0x0005) }, + + /* ATI Wireless Remote Receiver */ + { USB_DEVICE(VENDOR_ATI1, 0x0006) }, + + /* X10 USB Wireless Transceivers */ + { USB_DEVICE(VENDOR_ATI1, 0x0007) }, + { USB_DEVICE(VENDOR_ATI1, 0x0008) }, + { USB_DEVICE(VENDOR_ATI1, 0x0009) }, + { USB_DEVICE(VENDOR_ATI1, 0x000A) }, + { USB_DEVICE(VENDOR_ATI1, 0x000B) }, + { USB_DEVICE(VENDOR_ATI1, 0x000C) }, + { USB_DEVICE(VENDOR_ATI1, 0x000D) }, + { USB_DEVICE(VENDOR_ATI1, 0x000E) }, + { USB_DEVICE(VENDOR_ATI1, 0x000F) }, + + /* ATI Remote Wonder 2: Input Device */ + { USB_DEVICE(VENDOR_ATI2, 0x0602) }, + + /* ATI Remote Wonder 2: Controller (???) */ + { USB_DEVICE(VENDOR_ATI2, 0x0603) }, + + /* Gamester Xbox DVD Movie Playback Kit IR */ + { USB_DEVICE(VENDOR_MS1, 0x6521) }, + + /* Microsoft Xbox DVD Movie Playback Kit IR */ + { USB_DEVICE(VENDOR_MS2, 0x0284) }, + + /* Some chinese manufacterer -- conflicts with the joystick from the + * same manufacterer */ + { USB_DEVICE(VENDOR_MS3, 0xFFFF) }, + + /* Terminating entry */ + { } +}; + + +/* init strings */ +#define USB_OUTLEN 7 + +static char init1[] = {0x01, 0x00, 0x20, 0x14}; +static char init2[] = {0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20}; + +struct in_endpt { + /* inner link in list of endpoints for the remote specified by ir */ + struct list_head iep_list_link; + struct irctl *ir; + struct urb *urb; + struct usb_endpoint_descriptor *ep; + int type; + + /* buffers and dma */ + unsigned char *buf; + unsigned int len; +#ifdef KERNEL_2_5 + dma_addr_t dma; +#endif + + /* handle repeats */ + unsigned char old[USB_BUFF_LEN]; + unsigned long old_jiffies; +}; + +struct out_endpt { + struct irctl *ir; + struct urb *urb; + struct usb_endpoint_descriptor *ep; + + /* buffers and dma */ + unsigned char *buf; +#ifdef KERNEL_2_5 + dma_addr_t dma; +#endif + + /* handle sending (init strings) */ + int send_flags; + wait_queue_head_t wait; +}; + + +/* data structure for each usb remote */ +struct irctl { + /* inner link in list of all remotes managed by this module */ + struct list_head remote_list_link; + /* Number of usb interfaces associated with this device */ + int dev_refcount; + + /* usb */ + struct usb_device *usbdev; + /* Head link to list of all inbound endpoints in this remote */ + struct list_head iep_listhead; + struct out_endpt *out_init; + int devnum; + + /* remote type based on usb_device_id tables */ + enum { + ATI1_COMPATIBLE, + ATI2_COMPATIBLE, + XBOX_COMPATIBLE + } remote_type; + + /* rw2 current mode (mirror's remote's state) */ + int mode; + + /* lirc */ + struct lirc_plugin *p; + int connected; + + /* locking */ + struct semaphore lock; +}; + +/* list of all registered devices via the remote_list_link in irctl */ +static struct list_head remote_list; + +/* Convenience macros to retrieve a pointer to the surrounding struct from + * the given list_head reference within, pointed at by link. */ +#define get_iep_from_link(link) \ + list_entry((link), struct in_endpt, iep_list_link); +#define get_irctl_from_link(link) \ + list_entry((link), struct irctl, remote_list_link); + +/* send packet - used to initialize remote */ +static void send_packet(struct out_endpt *oep, u16 cmd, unsigned char *data) +{ + struct irctl *ir = oep->ir; + DECLARE_WAITQUEUE(wait, current); + int timeout = HZ; /* 1 second */ + unsigned char buf[USB_OUTLEN]; + + dprintk(DRIVER_NAME "[%d]: send called (%#x)\n", ir->devnum, cmd); + + IRLOCK; + oep->urb->transfer_buffer_length = LO(cmd) + 1; + oep->urb->dev = oep->ir->usbdev; + oep->send_flags = SEND_FLAG_IN_PROGRESS; + + memcpy(buf+1, data, LO(cmd)); + buf[0] = HI(cmd); + memcpy(oep->buf, buf, LO(cmd)+1); + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&oep->wait, &wait); + +#ifdef KERNEL_2_5 + if (usb_submit_urb(oep->urb, GFP_ATOMIC)) { +#else + if (usb_submit_urb(oep->urb)) { +#endif + set_current_state(TASK_RUNNING); + remove_wait_queue(&oep->wait, &wait); + IRUNLOCK; + return; + } + IRUNLOCK; + + while (timeout && (oep->urb->status == -EINPROGRESS) + && !(oep->send_flags & SEND_FLAG_COMPLETE)) { + timeout = schedule_timeout(timeout); + rmb(); + } + + dprintk(DRIVER_NAME "[%d]: send complete (%#x)\n", ir->devnum, cmd); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&oep->wait, &wait); +#ifdef KERNEL_2_5 + oep->urb->transfer_flags |= URB_ASYNC_UNLINK; +#endif + usb_unlink_urb(oep->urb); +} + +static int unregister_from_lirc(struct irctl *ir) +{ + struct lirc_plugin *p = ir->p; + int devnum; + + devnum = ir->devnum; + dprintk(DRIVER_NAME "[%d]: unregister from lirc called\n", devnum); + + lirc_unregister_plugin(p->minor); + + printk(DRIVER_NAME "[%d]: usb remote disconnected\n", devnum); + return SUCCESS; +} + + +static int set_use_inc(void *data) +{ + struct irctl *ir = data; + struct list_head *pos, *n; + struct in_endpt *iep; + int rtn; + + if (!ir) { + printk(DRIVER_NAME "[?]: set_use_inc called with no context\n"); + return -EIO; + } + dprintk(DRIVER_NAME "[%d]: set use inc\n", ir->devnum); + + MOD_INC_USE_COUNT; + + IRLOCK; + if (!ir->connected) { + if (!ir->usbdev) { + IRUNLOCK; + dprintk(DRIVER_NAME "[%d]: !ir->usbdev\n", ir->devnum); + return -ENOENT; + } + + /* Iterate through the inbound endpoints */ + list_for_each_safe(pos, n, &ir->iep_listhead) { + /* extract the current in_endpt */ + iep = get_iep_from_link(pos); + iep->urb->dev = ir->usbdev; + dprintk(DRIVER_NAME "[%d]: linking iep 0x%02x (%p)\n", + ir->devnum, iep->ep->bEndpointAddress, iep); +#ifdef KERNEL_2_5 + rtn = usb_submit_urb(iep->urb, GFP_ATOMIC); +#else + rtn = usb_submit_urb(iep->urb); +#endif + if (rtn) { + printk(DRIVER_NAME "[%d]: open result = %d " + "error submitting urb\n", + ir->devnum, rtn); + IRUNLOCK; + MOD_DEC_USE_COUNT; + return -EIO; + } + } + ir->connected = 1; + } + IRUNLOCK; + + return SUCCESS; +} + +static void set_use_dec(void *data) +{ + struct irctl *ir = data; + struct list_head *pos, *n; + struct in_endpt *iep; + + if (!ir) { + printk(DRIVER_NAME "[?]: set_use_dec called with no context\n"); + return; + } + dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum); + + IRLOCK; + if (ir->connected) { + /* Free inbound usb urbs */ + list_for_each_safe(pos, n, &ir->iep_listhead) { + iep = get_iep_from_link(pos); + dprintk(DRIVER_NAME "[%d]: unlinking iep 0x%02x (%p)\n", + ir->devnum, iep->ep->bEndpointAddress, iep); + usb_kill_urb(iep->urb); + } + ir->connected = 0; + } + IRUNLOCK; + MOD_DEC_USE_COUNT; +} + +static void print_data(struct in_endpt *iep, char *buf, int len) +{ + const int clen = code_length[iep->ir->remote_type]; + char codes[clen * 3 + 1]; + int i; + + if (len <= 0) + return; + + for (i = 0; i < len && i < clen; i++) + snprintf(codes+i*3, 4, "%02x ", buf[i] & 0xFF); + printk(DRIVER_NAME "[%d]: data received %s (ep=0x%x length=%d)\n", + iep->ir->devnum, codes, iep->ep->bEndpointAddress, len); +} + +static int code_check_ati1(struct in_endpt *iep, int len) +{ + struct irctl *ir = iep->ir; + int i, chan; + + /* ATI RW1: some remotes emit both 4 and 5 byte length codes. */ + /* ATI RW2: emit 3 byte codes */ + if (len < CODE_MIN_LENGTH || len > CODE_LENGTH) + return -1; + + /* *** channel not tested with 4/5-byte Dutch remotes *** */ + chan = ((iep->buf[len-1]>>4) & 0x0F); + + /* strip channel code */ + if (!unique) { + iep->buf[len-1] &= 0x0F; + iep->buf[len-3] -= (chan<<4); + } + + if (!((1U<devnum, chan+1); + return -1; + } + dprintk(DRIVER_NAME "[%d]: accept channel %d\n", ir->devnum, chan+1); + + if (ir->remote_type == ATI1_COMPATIBLE) { + for (i = len; i < CODE_LENGTH; i++) iep->buf[i] = 0; + /* check for repeats */ + if (memcmp(iep->old, iep->buf, len) == 0) { + if (iep->old_jiffies + repeat_jiffies > jiffies) + return -1; + } else + memcpy(iep->old, iep->buf, CODE_LENGTH); + iep->old_jiffies = jiffies; + } + + return SUCCESS; +} + +/* + * Since the ATI Remote Wonder II has quite a different structure from the + * prior version, this function was seperated out to clarify the sanitization + * process. + * + * Here is a summary of the main differences: + * + * a. The rw2 has no sense of a transmission channel. But, it does have an + * auxilliary mode state, which is set by the mode buttons Aux1 through + * Aux4 and "PC". These map respectively to 0-4 in the first byte of the + * recv buffer. Any subsequent button press sends this mode number as its + * "channel code." Annoyingly enough, the mode setting buttons all send + * the same key code (0x3f), and can only be distinguished via their mode + * byte. + * + * Because of this, old-style "unique"-parameter-enabled channel squashing + * kills the functionality of the aux1-aux4 and PC buttons. However, to + * not do so would cause each remote key to send a different code depending + * on the active aux. Further complicating matters, using the mouse norb + * also sends an identical code as would pushing the active aux button. To + * handle this we need a seperate parameter, like rw2modes, with the + * following values and meanings: + * + * 0: Don't squash any channel info + * 1: Only squash channel data for non-mode setting keys + * 2: Ignore aux keypresses, but don't squash channel + * 3: Ignore aux keypresses and squash channel data + * + * Option 1 may seem useless since the mouse sends the same code, but one + * need only ignore in userspace any press of a mode-setting code that only + * reaffirms the current mode. The 3rd party lirccd should be able to + * handle this easily enough, but lircd doesn't keep the state necessary + * for this. TODO We could work around this in the driver by emitting a + * single 02 (press) code for a mode key only if that mode is not currently + * active. + * + * Option 2 would be useful for those wanting super configurability, + * offering the ability to program 5 times the number actions based on the + * current mode. + * + * b. The rw2 has its own built in repeat handling; the keys endpoint + * encodes this in the second byte as 1 for press, 2 for hold, and 0 for + * release. This is generally much more responsive than lirc's built-in + * timeout handling. + * + * The problem is that the remote can send the release-recieve pair + * (0,1) while one is still holding down the same button if the + * transmission is momentarilly interrupted. (It seems that the receiver + * manages this count instead of the remote.) By default, this information + * is squashed to 2. + * + * In order to expose the built-in repeat code, set the emit_updown + * parameter as described below. + * + * c. The mouse norb is much more sensitive than on the rw1. It emulates + * a joystick-like controller with the second byte representing the x-axis + * and the third, the y-axis. Treated as signed integers, these axes range + * approximately as follows: + * + * x: (left) -46 ... 46 (right) (0xd2..0x2e) + * y: (up) -46 ... 46 (down) (0xd2..0x2e) + * + * NB these values do not correspond to the pressure with which the mouse + * norb is pushed in a given direction, but rather seems to indicate the + * duration for which a given direction is held. + * + * These are normalized to 8 cardinal directions for easy configuration via + * lircd.conf. The normalization can be fined tuned with the mdeadzone and + * mgradient parameters as described below. + * + * d. The interrupt rate of the mouse vs. the normal keys is different. + * + * mouse: ~27Hz (37ms between interrupts) + * keys: ~10Hz (100ms between interrupts) + * + * This means that the normal gap mechanism for lircd won't work as + * expected; is emit_updown>0 if you can get away with it. + */ +static int code_check_ati2(struct in_endpt *iep, int len) +{ + struct irctl *ir = iep->ir; + int mode, i; + char *buf = iep->buf; + + if (len != CODE_LENGTH) { + dprintk(DRIVER_NAME + "[%d]: Huh? Abnormal length (%d) buffer recieved.\n", + ir->devnum, len); + return -1; + } + for (i = len; i < CODE_LENGTH; i++) iep->buf[i] = 0; + + mode = buf[0]; + + /* Squash the mode indicator if unique wasn't set non-zero */ + if (!unique) + buf[0] = 0; + + if (iep->ep->bEndpointAddress == EP_KEYS_ADDR) { + /* ignore mouse navigation indicator key and + * mode-set (aux) keys */ + if (buf[2] == RW2_MODENAV_KEYCODE) { + if (emit_modekeys >= 2) /* emit raw */ + buf[0] = mode; + else if (emit_modekeys == 1) { + /* translate */ + buf[0] = mode; + if (ir->mode != mode) { + buf[1] = 0x03; + ir->mode = mode; + return SUCCESS; + } + } else { + dprintk(DRIVER_NAME + "[%d]: ignore dummy code 0x%x " + "(ep=0x%x)\n", ir->devnum, + buf[2], iep->ep->bEndpointAddress); + return -1; + } + } + + if (buf[1] != 2) { + /* handle press/release codes */ + if (emit_updown == 0) /* ignore */ + return -1; + else if (emit_updown == 1) /* normalize keycode */ + buf[2] = RW2_PRESSRELEASE_KEYCODE; + /* else emit raw */ + } + + } else { + int x = (signed char)buf[1]; + int y = (signed char)buf[2]; + int code = 0x00; + int dir_ew, dir_ns; + + buf[2] = RW2_MOUSE_KEYCODE; + + /* sensitivity threshold (use L2norm^2) */ + if (mdeadzone > (x*x+y*y)) { + buf[1] = 0x00; + return SUCCESS; + } + +/* Nybble encoding: xy, 2 is -1 (S or W); 1 (N or E) */ +#define MOUSE_N 0x01 +#define MOUSE_NE 0x11 +#define MOUSE_E 0x10 +#define MOUSE_SE 0x12 +#define MOUSE_S 0x02 +#define MOUSE_SW 0x22 +#define MOUSE_W 0x20 +#define MOUSE_NW 0x21 + + /* cardinal leanings: positive x -> E, positive y -> S */ + dir_ew = (x > 0) ? MOUSE_E : MOUSE_W; + dir_ns = (y > 0) ? MOUSE_S : MOUSE_N; + + /* convert coordintes(angle) into compass direction */ + if (x == 0) + code = dir_ns; + else if (y == 0) + code = dir_ew; + else { + if (abs(1000*y/x) > mgradient) + code = dir_ns; + if (abs(1000*x/y) > mgradient) + code |= dir_ew; + } + + buf[1] = code; + dprintk(DRIVER_NAME "[%d]: mouse compass=0x%x %s%s (%d,%d)\n", + ir->devnum, code, + (code & MOUSE_S ? "S" : (code & MOUSE_N ? "N" : "")), + (code & MOUSE_E ? "E" : (code & MOUSE_W ? "W" : "")), + x, y); + } + + return SUCCESS; +} + +static int code_check_xbox(struct in_endpt *iep, int len) +{ + struct irctl *ir = iep->ir; + const int clen = CODE_LENGTH; + + if (len != clen) { + dprintk(DRIVER_NAME ": We got %d instead of %d bytes from xbox " + "ir.. ?\n", len, clen); + return -1; + } + + /* check for repeats */ + if (memcmp(iep->old, iep->buf, len) == 0) { + if (iep->old_jiffies + repeat_jiffies > jiffies) + return -1; + } else { + /* the third byte of xbox ir packet seems to contain key info + * the last two bytes are.. some kind of clock? */ + iep->buf[0] = iep->buf[2]; + memset(iep->buf + 1, 0, len - 1); + memcpy(iep->old, iep->buf, len); + } + iep->old_jiffies = jiffies; + + return SUCCESS; +} + +#if defined(KERNEL_2_5) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void usb_remote_recv(struct urb *urb, struct pt_regs *regs) +#else +static void usb_remote_recv(struct urb *urb) +#endif +{ + struct in_endpt *iep; + int len, result = -1; + + if (!urb) + return; + iep = urb->context; + if (!iep) { +#ifdef KERNEL_2_5 + urb->transfer_flags |= URB_ASYNC_UNLINK; +#endif + usb_unlink_urb(urb); + return; + } + if (!iep->ir->usbdev) + return; + + len = urb->actual_length; + if (debug) + print_data(iep, urb->transfer_buffer, len); + + switch (urb->status) { + + /* success */ + case SUCCESS: + switch (iep->ir->remote_type) { + case XBOX_COMPATIBLE: + result = code_check_xbox(iep, len); + break; + case ATI2_COMPATIBLE: + result = code_check_ati2(iep, len); + break; + case ATI1_COMPATIBLE: + default: + result = code_check_ati1(iep, len); + } + if (result < 0) + break; + lirc_buffer_write_1(iep->ir->p->rbuf, iep->buf); + wake_up(&iep->ir->p->rbuf->wait_poll); + break; + + /* unlink */ + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: +#ifdef KERNEL_2_5 + urb->transfer_flags |= URB_ASYNC_UNLINK; +#endif + usb_unlink_urb(urb); + return; + + case -EPIPE: + default: + break; + } + + /* resubmit urb */ +#ifdef KERNEL_2_5 + usb_submit_urb(urb, GFP_ATOMIC); +#endif +} + +#if defined(KERNEL_2_5) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void usb_remote_send(struct urb *urb, struct pt_regs *regs) +#else +static void usb_remote_send(struct urb *urb) +#endif +{ + struct out_endpt *oep; + + if (!urb) + return; + oep = urb->context; + if (!oep) { +#ifdef KERNEL_2_5 + urb->transfer_flags |= URB_ASYNC_UNLINK; +#endif + usb_unlink_urb(urb); + return; + } + if (!oep->ir->usbdev) + return; + + dprintk(DRIVER_NAME "[%d]: usb out called\n", oep->ir->devnum); + + if (urb->status) + return; + + oep->send_flags |= SEND_FLAG_COMPLETE; + wmb(); + if (waitqueue_active(&oep->wait)) + wake_up(&oep->wait); +} + + +/*************************************************************************** + * Initialization and removal + ***************************************************************************/ + +/* + * Free iep according to mem_failure which specifies a checkpoint into the + * initialization sequence for rollback recovery. + */ +static void free_in_endpt(struct in_endpt *iep, int mem_failure) +{ + struct irctl *ir; + dprintk(DRIVER_NAME ": free_in_endpt(%p, %d)\n", iep, mem_failure); + if (!iep) + return; + + ir = iep->ir; + if (!ir) { + dprintk(DRIVER_NAME ": free_in_endpt: WARNING! null ir\n"); + return; + } + IRLOCK; + switch (mem_failure) { + case FREE_ALL: + case 5: + list_del(&iep->iep_list_link); + dprintk(DRIVER_NAME "[%d]: free_in_endpt removing ep=0x%0x " + "from list\n", ir->devnum, iep->ep->bEndpointAddress); + case 4: + if (iep->urb) { +#ifdef KERNEL_2_5 + iep->urb->transfer_flags |= URB_ASYNC_UNLINK; +#endif + usb_unlink_urb(iep->urb); + usb_free_urb(iep->urb); + iep->urb = 0; + } else + dprintk(DRIVER_NAME "[%d]: free_in_endpt null urb!\n", + ir->devnum); + case 3: +#ifdef KERNEL_2_5 + usb_buffer_free(iep->ir->usbdev, iep->len, iep->buf, iep->dma); +#else + kfree(iep->buf); +#endif + iep->buf = 0; + case 2: + kfree(iep); + } + IRUNLOCK; +} + +/* + * Construct a new inbound endpoint for this remote, and add it to the list of + * in_epts in ir. + */ +static struct in_endpt *new_in_endpt(struct irctl *ir, + struct usb_endpoint_descriptor *ep) +{ + struct usb_device *dev = ir->usbdev; + struct in_endpt *iep; + int pipe, maxp, len, addr; + int mem_failure; + + addr = ep->bEndpointAddress; + pipe = usb_rcvintpipe(dev, addr); + maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + +/* len = (maxp > USB_BUFLEN) ? USB_BUFLEN : maxp; + * len -= (len % CODE_LENGTH); */ + len = CODE_LENGTH; + + dprintk(DRIVER_NAME "[%d]: acceptable inbound endpoint (0x%x) found " + "(maxp=%d len=%d)\n", ir->devnum, addr, maxp, len); + + mem_failure = 0; + iep = kmalloc(sizeof(*iep), GFP_KERNEL); + if (!iep) { + mem_failure = 1; + goto new_in_endpt_failure_check; + } + memset(iep, 0, sizeof(*iep)); + iep->ir = ir; + iep->ep = ep; + iep->len = len; + +#ifdef KERNEL_2_5 + iep->buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &iep->dma); +#else + iep->buf = kmalloc(len, GFP_KERNEL); +#endif + if (!iep->buf) { + mem_failure = 2; + goto new_in_endpt_failure_check; + } + +#ifdef KERNEL_2_5 + iep->urb = usb_alloc_urb(0, GFP_KERNEL); +#else + iep->urb = usb_alloc_urb(0); +#endif + if (!iep->urb) + mem_failure = 3; + +new_in_endpt_failure_check: + + if (mem_failure) { + free_in_endpt(iep, mem_failure); + printk(DRIVER_NAME "[%d]: ep=0x%x out of memory (code=%d)\n", + ir->devnum, addr, mem_failure); + return NULL; + } + list_add_tail(&iep->iep_list_link, &ir->iep_listhead); + dprintk(DRIVER_NAME "[%d]: adding ep=0x%0x to list\n", + ir->devnum, iep->ep->bEndpointAddress); + return iep; +} + +static void free_out_endpt(struct out_endpt *oep, int mem_failure) +{ + struct irctl *ir; + dprintk(DRIVER_NAME ": free_out_endpt(%p, %d)\n", oep, mem_failure); + if (!oep) + return; + + wake_up_all(&oep->wait); + + ir = oep->ir; + if (!ir) { + dprintk(DRIVER_NAME ": free_out_endpt: WARNING! null ir\n"); + return; + } + IRLOCK; + switch (mem_failure) { + case FREE_ALL: + case 4: + if (oep->urb) { +#ifdef KERNEL_2_5 + oep->urb->transfer_flags |= URB_ASYNC_UNLINK; +#endif + usb_unlink_urb(oep->urb); + usb_free_urb(oep->urb); + oep->urb = 0; + } else { + dprintk(DRIVER_NAME "[%d]: free_out_endpt: null urb!\n", + ir->devnum); + } + case 3: +#ifdef KERNEL_2_5 + usb_buffer_free(oep->ir->usbdev, USB_OUTLEN, + oep->buf, oep->dma); +#else + kfree(oep->buf); +#endif + oep->buf = 0; + case 2: + kfree(oep); + } + IRUNLOCK; +} + +static struct out_endpt *new_out_endpt(struct irctl *ir, + struct usb_endpoint_descriptor *ep) +{ +#ifdef KERNEL_2_5 + struct usb_device *dev = ir->usbdev; +#endif + struct out_endpt *oep; + int mem_failure; + + dprintk(DRIVER_NAME "[%d]: acceptable outbound endpoint (0x%x) found\n", + ir->devnum, ep->bEndpointAddress); + + mem_failure = 0; + oep = kmalloc(sizeof(*oep), GFP_KERNEL); + if (!oep) + mem_failure = 1; + else { + memset(oep, 0, sizeof(*oep)); + oep->ir = ir; + oep->ep = ep; + init_waitqueue_head(&oep->wait); + +#ifdef KERNEL_2_5 + oep->buf = usb_buffer_alloc(dev, USB_OUTLEN, + GFP_ATOMIC, &oep->dma); +#else + oep->buf = kmalloc(USB_OUTLEN, GFP_KERNEL); +#endif + if (!oep->buf) + mem_failure = 2; + else { +#ifdef KERNEL_2_5 + oep->urb = usb_alloc_urb(0, GFP_KERNEL); +#else + oep->urb = usb_alloc_urb(0); +#endif + if (!oep->urb) + mem_failure = 3; + } + } + if (mem_failure) { + free_out_endpt(oep, mem_failure); + printk(DRIVER_NAME "[%d]: ep=0x%x out of memory (code=%d)\n", + ir->devnum, ep->bEndpointAddress, mem_failure); + return NULL; + } + return oep; +} + +static void free_irctl(struct irctl *ir, int mem_failure) +{ + struct list_head *pos, *n; + struct in_endpt *in; + dprintk(DRIVER_NAME ": free_irctl(%p, %d)\n", ir, mem_failure); + + if (!ir) + return; + + list_for_each_safe(pos, n, &ir->iep_listhead) { + in = get_iep_from_link(pos); + free_in_endpt(in, FREE_ALL); + } + if (ir->out_init) { + free_out_endpt(ir->out_init, FREE_ALL); + ir->out_init = NULL; + } + + IRLOCK; + switch (mem_failure) { + case FREE_ALL: + case 6: + if (!--ir->dev_refcount) { + list_del(&ir->remote_list_link); + dprintk(DRIVER_NAME "[%d]: free_irctl: removing " + "remote from list\n", ir->devnum); + } else { + dprintk(DRIVER_NAME "[%d]: free_irctl: refcount at %d," + "aborting free_irctl\n", + ir->devnum, ir->dev_refcount); + IRUNLOCK; + return; + } + case 5: + case 4: + case 3: + if (ir->p) { + switch (mem_failure) { + case 5: + lirc_buffer_free(ir->p->rbuf); + case 4: + kfree(ir->p->rbuf); + case 3: + kfree(ir->p); + } + } else + printk(DRIVER_NAME "[%d]: ir->p is a null pointer!\n", + ir->devnum); + case 2: + IRUNLOCK; + kfree(ir); + return; + } + IRUNLOCK; +} + +static struct irctl *new_irctl(struct usb_device *dev) +{ + struct irctl *ir; + struct lirc_plugin *plugin; + int type, devnum; + int mem_failure; + int dclen; + + devnum = dev->devnum; + + /* determine remote type */ + switch (cpu_to_le16(dev->descriptor.idVendor)) { + case VENDOR_ATI1: + type = ATI1_COMPATIBLE; + break; + case VENDOR_ATI2: + type = ATI2_COMPATIBLE; + break; + case VENDOR_MS1: + case VENDOR_MS2: + case VENDOR_MS3: + type = XBOX_COMPATIBLE; + break; + default: + dprintk(DRIVER_NAME "[%d]: unknown type\n", devnum); + return NULL; + } + dprintk(DRIVER_NAME "[%d]: remote type = %d\n", devnum, type); + + /* allocate kernel memory */ + mem_failure = 0; + ir = kmalloc(sizeof(*ir), GFP_KERNEL); + if (!ir) { + mem_failure = 1; + goto new_irctl_failure_check; + } + + /* at this stage we cannot use the macro [DE]CODE_LENGTH: ir + * is not yet setup */ + dclen = decode_length[type]; + memset(ir, 0, sizeof(*ir)); + /* add this infrared remote struct to remote_list, keeping track + * of the number of drivers registered. */ + dprintk(DRIVER_NAME "[%d]: adding remote to list\n", devnum); + list_add_tail(&ir->remote_list_link, &remote_list); + ir->dev_refcount = 1; + + plugin = kmalloc(sizeof(*plugin), GFP_KERNEL); + if (!plugin) { + mem_failure = 2; + goto new_irctl_failure_check; + } + + memset(plugin, 0, sizeof(*plugin)); + ir->p = plugin; + plugin->rbuf = kmalloc(sizeof(*(plugin->rbuf)), GFP_KERNEL); + if (!plugin->rbuf) { + mem_failure = 3; + goto new_irctl_failure_check; + } + + if (lirc_buffer_init(plugin->rbuf, dclen, 1)) { + mem_failure = 4; + goto new_irctl_failure_check; + } + + strcpy(plugin->name, DRIVER_NAME " "); + plugin->minor = -1; + plugin->code_length = dclen * 8; + plugin->features = LIRC_CAN_REC_LIRCCODE; + plugin->data = ir; + plugin->set_use_inc = &set_use_inc; + plugin->set_use_dec = &set_use_dec; +#ifdef LIRC_HAVE_SYSFS + plugin->dev = &dev->dev; +#endif + plugin->owner = THIS_MODULE; + ir->usbdev = dev; + ir->remote_type = type; + ir->devnum = devnum; + ir->mode = RW2_NULL_MODE; + + init_MUTEX(&ir->lock); + INIT_LIST_HEAD(&ir->iep_listhead); + +new_irctl_failure_check: + + if (mem_failure) { + free_irctl(ir, mem_failure); + printk(DRIVER_NAME "[%d]: out of memory (code=%d)\n", + devnum, mem_failure); + return NULL; + } + return ir; +} + + +/* + * Scan the global list of remotes to see if the device listed is one of them. + * If it is, the corresponding irctl is returned, with its dev_refcount + * incremented. Otherwise, returns null. + */ +static struct irctl *get_prior_reg_ir(struct usb_device *dev) +{ + struct list_head *pos; + struct irctl *ir = NULL; + + dprintk(DRIVER_NAME "[%d]: scanning remote_list...\n", dev->devnum); + list_for_each(pos, &remote_list) { + ir = get_irctl_from_link(pos); + if (ir->usbdev != dev) { + dprintk(DRIVER_NAME "[%d]: device %d isn't it...", + dev->devnum, ir->devnum); + ir = NULL; + } else { + dprintk(DRIVER_NAME "[%d]: prior instance found.\n", + dev->devnum); + ir->dev_refcount++; + break; + } + } + return ir; +} + +/* If the USB interface has an out endpoint for control (eg, the first Remote + * Wonder) send the appropriate initialization packets. */ +static void send_outbound_init(struct irctl *ir) +{ + if (ir->out_init) { + struct out_endpt *oep = ir->out_init; + dprintk(DRIVER_NAME "[%d]: usb_remote_probe: initializing " + "outbound ep\n", ir->devnum); + usb_fill_int_urb(oep->urb, ir->usbdev, + usb_sndintpipe(ir->usbdev, oep->ep->bEndpointAddress), + oep->buf, USB_OUTLEN, usb_remote_send, + oep, oep->ep->bInterval); + + send_packet(oep, 0x8004, init1); + send_packet(oep, 0x8007, init2); + } +} + +/* Log driver and usb info */ +static void log_usb_dev_info(struct usb_device *dev) +{ + char buf[63], name[128] = ""; + if (dev->descriptor.iManufacturer + && usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0) + strncpy(name, buf, 128); + if (dev->descriptor.iProduct + && usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0) + snprintf(name, 128, "%s %s", name, buf); + printk(DRIVER_NAME "[%d]: %s on usb%d:%d\n", dev->devnum, name, + dev->bus->busnum, dev->devnum); +} + + +#ifdef KERNEL_2_5 +static int usb_remote_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct usb_host_interface *idesc; +#else +static void *usb_remote_probe(struct usb_device *dev, unsigned int ifnum, + const struct usb_device_id *id) +{ + struct usb_interface *intf = &dev->actconfig->interface[ifnum]; + struct usb_interface_descriptor *idesc; +#endif + struct usb_endpoint_descriptor *ep; + struct in_endpt *iep; + struct irctl *ir; + int i, type; + + dprintk(DRIVER_NAME "[%d]: usb_remote_probe: dev:%p, intf:%p, id:%p)\n", + dev->devnum, dev, intf, id); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 5) + idesc = &intf->altsetting[intf->act_altsetting]; +#else + idesc = intf->cur_altsetting; +#endif + + /* Check if a usb remote has already been registered for this device */ + ir = get_prior_reg_ir(dev); + + if (!ir) { + ir = new_irctl(dev); + if (!ir) +#ifdef KERNEL_2_5 + return -ENOMEM; +#else + return NULL; +#endif + } + type = ir->remote_type; + + /* step through the endpoints to find first in and first out endpoint + * of type interrupt transfer */ +#ifdef KERNEL_2_5 + for (i = 0; i < idesc->desc.bNumEndpoints; ++i) { + ep = &idesc->endpoint[i].desc; +#else + for (i = 0; i < idesc->bNumEndpoints; ++i) { + ep = &idesc->endpoint[i]; +#endif + dprintk(DRIVER_NAME "[%d]: processing endpoint %d\n", + dev->devnum, i); + if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == + USB_DIR_IN) && + ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_INT)) { + + iep = new_in_endpt(ir, ep); + if (iep) + usb_fill_int_urb(iep->urb, dev, + usb_rcvintpipe(dev, + iep->ep->bEndpointAddress), + iep->buf, iep->len, usb_remote_recv, + iep, iep->ep->bInterval); + } + + if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == + USB_DIR_OUT) && + ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_INT) && + (ir->out_init == NULL)) + ir->out_init = new_out_endpt(ir, ep); + } + if (list_empty(&ir->iep_listhead)) { + printk(DRIVER_NAME "[%d]: inbound endpoint not found\n", + ir->devnum); + free_irctl(ir, FREE_ALL); +#ifdef KERNEL_2_5 + return -ENODEV; +#else + return NULL; +#endif + } + if (ir->dev_refcount == 1) { + ir->p->minor = lirc_register_plugin(ir->p); + if (ir->p->minor < 0) { + free_irctl(ir, FREE_ALL); +#ifdef KERNEL_2_5 + return -ENODEV; +#else + return NULL; +#endif + } + + /* Note new driver registration in kernel logs */ + log_usb_dev_info(dev); + + /* outbound data (initialization) */ + send_outbound_init(ir); + } + +#ifdef KERNEL_2_5 + usb_set_intfdata(intf, ir); + return SUCCESS; +#else + return ir; +#endif +} + +#ifdef KERNEL_2_5 +static void usb_remote_disconnect(struct usb_interface *intf) +{ +/* struct usb_device *dev = interface_to_usbdev(intf); */ + struct irctl *ir = usb_get_intfdata(intf); + usb_set_intfdata(intf, NULL); +#else +static void usb_remote_disconnect(struct usb_device *dev, void *ptr) +{ + struct irctl *ir = ptr; +#endif + + dprintk(DRIVER_NAME ": disconnecting remote %d:\n", + (ir? ir->devnum: -1)); + if (!ir || !ir->p) + return; + + if (ir->usbdev) { + /* Only unregister once */ + ir->usbdev = NULL; + unregister_from_lirc(ir); + } + + /* This also removes the current remote from remote_list */ + free_irctl(ir, FREE_ALL); +} + +static struct usb_driver usb_remote_driver = { + LIRC_THIS_MODULE(.owner = THIS_MODULE) + .name = DRIVER_NAME, + .probe = usb_remote_probe, + .disconnect = usb_remote_disconnect, + .id_table = usb_remote_table +}; + +static int __init usb_remote_init(void) +{ + int i; + + INIT_LIST_HEAD(&remote_list); + + printk(KERN_INFO "\n" DRIVER_NAME ": " DRIVER_DESC " " + DRIVER_VERSION "\n"); + printk(DRIVER_NAME ": " DRIVER_AUTHOR "\n"); + dprintk(DRIVER_NAME ": debug mode enabled: " + "$Id: lirc_atiusb.c,v 1.69 2008/04/28 06:47:29 lirc Exp $\n"); + + request_module("lirc_dev"); + + repeat_jiffies = repeat*HZ/100; + + i = usb_register(&usb_remote_driver); + if (i) { + printk(DRIVER_NAME ": usb register failed, result = %d\n", i); + return -ENODEV; + } + + return SUCCESS; +} + +static void __exit usb_remote_exit(void) +{ + usb_deregister(&usb_remote_driver); +} + +module_init(usb_remote_init); +module_exit(usb_remote_exit); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(usb, usb_remote_table); + +module_param(debug, bool, 0644); +MODULE_PARM_DESC(debug, "Debug enabled or not (default: 0)"); + +module_param(mask, int, 0644); +MODULE_PARM_DESC(mask, "Set channel acceptance bit mask (default: 0xFFFF)"); + +module_param(unique, bool, 0644); +MODULE_PARM_DESC(unique, "Enable channel-specific codes (default: 0)"); + +module_param(repeat, int, 0644); +MODULE_PARM_DESC(repeat, "Repeat timeout (1/100 sec) (default: 10)"); + +module_param(mdeadzone, int, 0644); +MODULE_PARM_DESC(mdeadzone, "rw2 mouse sensitivity threshold (default: 0)"); + +/* + * Enabling this will cause the built-in Remote Wonder II repeate coding to + * not be squashed. The second byte of the keys output will then be: + * + * 1 initial press (button down) + * 2 holding (button remains pressed) + * 0 release (button up) + * + * By default, the driver emits 2 for both 1 and 2, and emits nothing for 0. + * This is good for people having trouble getting their rw2 to send a good + * consistent signal to the receiver. + * + * However, if you have no troubles with the driver outputting up-down pairs + * at random points while you're still holding a button, then you can enable + * this parameter to get finer grain repeat control out of your remote: + * + * 1 Emit a single (per-channel) virtual code for all up/down events + * 2 Emit the actual rw2 output + * + * 1 is easier to write lircd configs for; 2 allows full control. + */ +module_param(emit_updown, int, 0644); +MODULE_PARM_DESC(emit_updown, "emit press/release codes (rw2): 0:don't " + "(default), 1:emit 2 codes only, 2:code for each button"); + +module_param(emit_modekeys, int, 0644); +MODULE_PARM_DESC(emit_modekeys, "emit keycodes for aux1-aux4, pc, and mouse " + "(rw2): 0:don't (default), 1:emit translated codes: one for " + "mode switch, one for same mode, 2:raw codes"); + +module_param(mgradient, int, 0644); +MODULE_PARM_DESC(mgradient, "rw2 mouse: 1000*gradient from E to NE (default: " + "500 => .5 => ~27 degrees)"); + +EXPORT_NO_SYMBOLS; --- linux-2.6.27.orig/ubuntu/lirc/lirc_atiusb/Makefile +++ linux-2.6.27/ubuntu/lirc/lirc_atiusb/Makefile @@ -0,0 +1,3 @@ +EXTRA_CFLAGS =-DIRCTL_DEV_MAJOR=61 -DLIRC_SERIAL_TRANSMITTER -DLIRC_SERIAL_SOFTCARRIER -I$(src)/.. + +obj-$(CONFIG_LIRC_ATIUSB) += lirc_atiusb.o --- linux-2.6.27.orig/ubuntu/lirc/lirc_serial/Makefile +++ linux-2.6.27/ubuntu/lirc/lirc_serial/Makefile @@ -0,0 +1,4 @@ + +EXTRA_CFLAGS =-DIRCTL_DEV_MAJOR=61 -DLIRC_SERIAL_TRANSMITTER -DLIRC_SERIAL_SOFTCARRIER -I$(src)/.. + +obj-$(CONFIG_LIRC_SERIAL_IGOR) += lirc_serial.o --- linux-2.6.27.orig/ubuntu/lirc/lirc_serial/lirc_serial.c +++ linux-2.6.27/ubuntu/lirc/lirc_serial/lirc_serial.c @@ -0,0 +1,1368 @@ +/* $Id: lirc_serial.c,v 5.89 2008/04/06 19:03:52 lirc Exp $ */ + +/**************************************************************************** + ** lirc_serial.c *********************************************************** + **************************************************************************** + * + * lirc_serial - Device driver that records pulse- and pause-lengths + * (space-lengths) between DDCD event on a serial port. + * + * Copyright (C) 1996,97 Ralph Metzler + * Copyright (C) 1998 Trent Piepho + * Copyright (C) 1998 Ben Pfaff + * Copyright (C) 1999 Christoph Bartelmus + * Copyright (C) 2007 Andrei Tanas (suspend/resume support) + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* Steve's changes to improve transmission fidelity: + - for systems with the rdtsc instruction and the clock counter, a + send_pule that times the pulses directly using the counter. + This means that the LIRC_SERIAL_TRANSMITTER_LATENCY fudge is + not needed. Measurement shows very stable waveform, even where + PCI activity slows the access to the UART, which trips up other + versions. + - For other system, non-integer-microsecond pulse/space lengths, + done using fixed point binary. So, much more accurate carrier + frequency. + - fine tuned transmitter latency, taking advantage of fractional + microseconds in previous change + - Fixed bug in the way transmitter latency was accounted for by + tuning the pulse lengths down - the send_pulse routine ignored + this overhead as it timed the overall pulse length - so the + pulse frequency was right but overall pulse length was too + long. Fixed by accounting for latency on each pulse/space + iteration. + + Steve Davies July 2001 +*/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) +#error "**********************************************************" +#error " Sorry, this driver needs kernel version 2.2.18 or higher " +#error "**********************************************************" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) +#include +#endif + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) +#include +#else +#include +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +#include +#else +#include +#endif +#include +#include + +#if defined(LIRC_SERIAL_NSLU2) +#include +/* From Intel IXP42X Developer's Manual (#252480-005): */ +/* ftp://download.intel.com/design/network/manuals/25248005.pdf */ +#define UART_IE_IXP42X_UUE 0x40 /* IXP42X UART Unit enable */ +#define UART_IE_IXP42X_RTOIE 0x10 /* IXP42X Receiver Data Timeout int.enable */ +#ifndef NSLU2_LED_GRN_GPIO +/* added in 2.6.22 */ +#define NSLU2_LED_GRN_GPIO NSLU2_LED_GRN +#endif +#endif + +#include "lirc.h" +#include "kcompat.h" +#include "lirc_dev/lirc_dev.h" + +#if defined(LIRC_SERIAL_SOFTCARRIER) && !defined(LIRC_SERIAL_TRANSMITTER) +#warning "Software carrier only affects transmitting" +#endif + +#if defined(rdtscl) + +#define USE_RDTSC +#warning "Note: using rdtsc instruction" +#endif + +#ifdef LIRC_SERIAL_ANIMAX +#ifdef LIRC_SERIAL_TRANSMITTER +#warning "******************************************" +#warning " This receiver does not have a " +#warning " transmitter diode " +#warning "******************************************" +#endif +#endif + +#define LIRC_DRIVER_NAME "lirc_serial" + +struct lirc_serial { + int signal_pin; + int signal_pin_change; + int on; + int off; + long (*send_pulse)(unsigned long length); + void (*send_space)(long length); + int features; +}; + +#define LIRC_HOMEBREW 0 +#define LIRC_IRDEO 1 +#define LIRC_IRDEO_REMOTE 2 +#define LIRC_ANIMAX 3 +#define LIRC_IGOR 4 +#define LIRC_NSLU2 5 + +#ifdef LIRC_SERIAL_IRDEO +static int type = LIRC_IRDEO; +#elif defined(LIRC_SERIAL_IRDEO_REMOTE) +static int type = LIRC_IRDEO_REMOTE; +#elif defined(LIRC_SERIAL_ANIMAX) +static int type = LIRC_ANIMAX; +#elif defined(LIRC_SERIAL_IGOR) +static int type = LIRC_IGOR; +#elif defined(LIRC_SERIAL_NSLU2) +static int type = LIRC_NSLU2; +#else +static int type = LIRC_HOMEBREW; +#endif + +/* Set defaults for NSLU2 */ +#if defined(LIRC_SERIAL_NSLU2) +#ifndef LIRC_IRQ +#define LIRC_IRQ IRQ_IXP4XX_UART2 +#endif +#ifndef LIRC_PORT +#define LIRC_PORT (IXP4XX_UART2_BASE_VIRT + REG_OFFSET) +#endif +#ifndef LIRC_IOMMAP +#define LIRC_IOMMAP IXP4XX_UART2_BASE_PHYS +#endif +#ifndef LIRC_IOSHIFT +#define LIRC_IOSHIFT 2 +#endif +#ifndef LIRC_ALLOW_MMAPPED_IO +#define LIRC_ALLOW_MMAPPED_IO +#endif +#endif + +#if defined(LIRC_ALLOW_MMAPPED_IO) +#ifndef LIRC_IOMMAP +#define LIRC_IOMMAP 0 +#endif +#ifndef LIRC_IOSHIFT +#define LIRC_IOSHIFT 0 +#endif +static int iommap = LIRC_IOMMAP; +static int ioshift = LIRC_IOSHIFT; +#endif + +#ifdef LIRC_SERIAL_SOFTCARRIER +static int softcarrier = 1; +#else +static int softcarrier; +#endif + +static int share_irq; +static int debug; + +#define dprintk(fmt, args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ + fmt, ## args); \ + } while (0) + +/* forward declarations */ +static long send_pulse_irdeo(unsigned long length); +static long send_pulse_homebrew(unsigned long length); +static void send_space_irdeo(long length); +static void send_space_homebrew(long length); + +static struct lirc_serial hardware[] = { + /* home-brew receiver/transmitter */ + { + UART_MSR_DCD, + UART_MSR_DDCD, + UART_MCR_RTS|UART_MCR_OUT2|UART_MCR_DTR, + UART_MCR_RTS|UART_MCR_OUT2, + send_pulse_homebrew, + send_space_homebrew, + ( +#ifdef LIRC_SERIAL_TRANSMITTER + LIRC_CAN_SET_SEND_DUTY_CYCLE| + LIRC_CAN_SET_SEND_CARRIER| + LIRC_CAN_SEND_PULSE| +#endif + LIRC_CAN_REC_MODE2) + }, + + /* IRdeo classic */ + { + UART_MSR_DSR, + UART_MSR_DDSR, + UART_MCR_OUT2, + UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2, + send_pulse_irdeo, + send_space_irdeo, + (LIRC_CAN_SET_SEND_DUTY_CYCLE| + LIRC_CAN_SEND_PULSE| + LIRC_CAN_REC_MODE2) + }, + + /* IRdeo remote */ + { + UART_MSR_DSR, + UART_MSR_DDSR, + UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2, + UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2, + send_pulse_irdeo, + send_space_irdeo, + (LIRC_CAN_SET_SEND_DUTY_CYCLE| + LIRC_CAN_SEND_PULSE| + LIRC_CAN_REC_MODE2) + }, + + /* AnimaX */ + { + UART_MSR_DCD, + UART_MSR_DDCD, + 0, + UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2, + NULL, + NULL, + LIRC_CAN_REC_MODE2 + }, + + /* home-brew receiver/transmitter (Igor Cesko's variation) */ + { + UART_MSR_DSR, + UART_MSR_DDSR, + UART_MCR_RTS|UART_MCR_OUT2|UART_MCR_DTR, + UART_MCR_RTS|UART_MCR_OUT2, + send_pulse_homebrew, + send_space_homebrew, + ( +#ifdef LIRC_SERIAL_TRANSMITTER + LIRC_CAN_SET_SEND_DUTY_CYCLE| + LIRC_CAN_SET_SEND_CARRIER| + LIRC_CAN_SEND_PULSE| +#endif + LIRC_CAN_REC_MODE2) + }, + +#if defined(LIRC_SERIAL_NSLU2) + /* Modified Linksys Network Storage Link USB 2.0 (NSLU2): + We receive on CTS of the 2nd serial port (R142,LHS), we + transmit with a IR diode between GPIO[1] (green status LED), + and ground (Matthias Goebl ). + See also http://www.nslu2-linux.org for this device */ + { + UART_MSR_CTS, + UART_MSR_DCTS, + UART_MCR_RTS|UART_MCR_OUT2|UART_MCR_DTR, + UART_MCR_RTS|UART_MCR_OUT2, + send_pulse_homebrew, + send_space_homebrew, + ( +#ifdef LIRC_SERIAL_TRANSMITTER + LIRC_CAN_SET_SEND_DUTY_CYCLE| + LIRC_CAN_SET_SEND_CARRIER| + LIRC_CAN_SEND_PULSE| +#endif + LIRC_CAN_REC_MODE2) + }, +#endif + +}; + +#define RS_ISR_PASS_LIMIT 256 + +/* A long pulse code from a remote might take upto 300 bytes. The + daemon should read the bytes as soon as they are generated, so take + the number of keys you think you can push before the daemon runs + and multiply by 300. The driver will warn you if you overrun this + buffer. If you have a slow computer or non-busmastering IDE disks, + maybe you will need to increase this. */ + +/* This MUST be a power of two! It has to be larger than 1 as well. */ + +#define RBUF_LEN 256 +#define WBUF_LEN 256 + +static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */ +static int txsense; /* 0 = active high, 1 = active low */ + +#ifndef LIRC_IRQ +#define LIRC_IRQ 4 +#endif +#ifndef LIRC_PORT +#define LIRC_PORT 0x3f8 +#endif + +static int io = LIRC_PORT; +static int irq = LIRC_IRQ; + +static struct timeval lasttv = {0, 0}; + +static struct lirc_buffer rbuf; + +static lirc_t wbuf[WBUF_LEN]; + +static unsigned int freq = 38000; +static unsigned int duty_cycle = 50; + +/* Initialized in init_timing_params() */ +static unsigned long period; +static unsigned long pulse_width; +static unsigned long space_width; + +#if defined(__i386__) +/* + From: + Linux I/O port programming mini-HOWTO + Author: Riku Saikkonen + v, 28 December 1997 + + [...] + Actually, a port I/O instruction on most ports in the 0-0x3ff range + takes almost exactly 1 microsecond, so if you're, for example, using + the parallel port directly, just do additional inb()s from that port + to delay. + [...] +*/ +/* transmitter latency 1.5625us 0x1.90 - this figure arrived at from + * comment above plus trimming to match actual measured frequency. + * This will be sensitive to cpu speed, though hopefully most of the 1.5us + * is spent in the uart access. Still - for reference test machine was a + * 1.13GHz Athlon system - Steve + */ + +/* changed from 400 to 450 as this works better on slower machines; + faster machines will use the rdtsc code anyway */ + +#define LIRC_SERIAL_TRANSMITTER_LATENCY 450 + +#else + +/* does anybody have information on other platforms ? */ +/* 256 = 1<<8 */ +#define LIRC_SERIAL_TRANSMITTER_LATENCY 256 + +#endif /* __i386__ */ + +static inline unsigned int sinp(int offset) +{ +#if defined(LIRC_ALLOW_MMAPPED_IO) + if (iommap != 0) { + /* the register is memory-mapped */ + offset <<= ioshift; + return readb(io + offset); + } +#endif + return inb(io + offset); +} + +static inline void soutp(int offset, int value) +{ +#if defined(LIRC_ALLOW_MMAPPED_IO) + if (iommap != 0) { + /* the register is memory-mapped */ + offset <<= ioshift; + writeb(value, io + offset); + } +#endif + outb(value, io + offset); +} + +static inline void on(void) +{ +#if defined(LIRC_SERIAL_NSLU2) + /* On NSLU2, we put the transmit diode between the output of the green + status LED and ground */ + if (type == LIRC_NSLU2) { + gpio_line_set(NSLU2_LED_GRN_GPIO, IXP4XX_GPIO_LOW); + return; + } +#endif + if (txsense) + soutp(UART_MCR, hardware[type].off); + else + soutp(UART_MCR, hardware[type].on); +} + +static inline void off(void) +{ +#if defined(LIRC_SERIAL_NSLU2) + if (type == LIRC_NSLU2) { + gpio_line_set(NSLU2_LED_GRN_GPIO, IXP4XX_GPIO_HIGH); + return; + } +#endif + if (txsense) + soutp(UART_MCR, hardware[type].on); + else + soutp(UART_MCR, hardware[type].off); +} + +#ifndef MAX_UDELAY_MS +#define MAX_UDELAY_US 5000 +#else +#define MAX_UDELAY_US (MAX_UDELAY_MS*1000) +#endif + +static inline void safe_udelay(unsigned long usecs) +{ + while (usecs > MAX_UDELAY_US) { + udelay(MAX_UDELAY_US); + usecs -= MAX_UDELAY_US; + } + udelay(usecs); +} + +#ifdef USE_RDTSC +/* This is an overflow/precision juggle, complicated in that we can't + do long long divide in the kernel */ + +/* When we use the rdtsc instruction to measure clocks, we keep the + * pulse and space widths as clock cycles. As this is CPU speed + * dependent, the widths must be calculated in init_port and ioctl + * time + */ + +/* So send_pulse can quickly convert microseconds to clocks */ +static unsigned long conv_us_to_clocks; + +static inline int init_timing_params(unsigned int new_duty_cycle, + unsigned int new_freq) +{ + unsigned long long loops_per_sec, work; + + duty_cycle = new_duty_cycle; + freq = new_freq; + + loops_per_sec = current_cpu_data.loops_per_jiffy; + loops_per_sec *= HZ; + + /* How many clocks in a microsecond?, avoiding long long divide */ + work = loops_per_sec; + work *= 4295; /* 4295 = 2^32 / 1e6 */ + conv_us_to_clocks = (work>>32); + + /* Carrier period in clocks, approach good up to 32GHz clock, + gets carrier frequency within 8Hz */ + period = loops_per_sec>>3; + period /= (freq>>3); + + /* Derive pulse and space from the period */ + + pulse_width = period*duty_cycle/100; + space_width = period - pulse_width; + dprintk("in init_timing_params, freq=%d, duty_cycle=%d, " + "clk/jiffy=%ld, pulse=%ld, space=%ld, " + "conv_us_to_clocks=%ld\n", + freq, duty_cycle, current_cpu_data.loops_per_jiffy, + pulse_width, space_width, conv_us_to_clocks); + return 0; +} +#else /* ! USE_RDTSC */ +static inline int init_timing_params(unsigned int new_duty_cycle, + unsigned int new_freq) +{ +/* period, pulse/space width are kept with 8 binary places - + * IE multiplied by 256. */ + if (256*1000000L/new_freq*new_duty_cycle/100 <= + LIRC_SERIAL_TRANSMITTER_LATENCY) + return -EINVAL; + if (256*1000000L/new_freq*(100-new_duty_cycle)/100 <= + LIRC_SERIAL_TRANSMITTER_LATENCY) + return -EINVAL; + duty_cycle = new_duty_cycle; + freq = new_freq; + period = 256*1000000L/freq; + pulse_width = period*duty_cycle/100; + space_width = period-pulse_width; + dprintk("in init_timing_params, freq=%d pulse=%ld, " + "space=%ld\n", freq, pulse_width, space_width); + return 0; +} +#endif /* USE_RDTSC */ + + +/* return value: space length delta */ + +static long send_pulse_irdeo(unsigned long length) +{ + long rawbits; + int i; + unsigned char output; + unsigned char chunk, shifted; + + /* how many bits have to be sent ? */ + rawbits = length*1152/10000; + if (duty_cycle > 50) + chunk = 3; + else + chunk = 1; + for (i = 0, output = 0x7f; rawbits > 0; rawbits -= 3) { + shifted = chunk<<(i*3); + shifted >>= 1; + output &= (~shifted); + i++; + if (i == 3) { + soutp(UART_TX, output); + while (!(sinp(UART_LSR) & UART_LSR_THRE)); + output = 0x7f; + i = 0; + } + } + if (i != 0) { + soutp(UART_TX, output); + while (!(sinp(UART_LSR) & UART_LSR_TEMT)); + } + + if (i == 0) + return ((-rawbits)*10000/1152); + else + return ((3-i)*3*10000/1152+(-rawbits)*10000/1152); +} + +#ifdef USE_RDTSC +/* Version that uses Pentium rdtsc instruction to measure clocks */ + +/* This version does sub-microsecond timing using rdtsc instruction, + * and does away with the fudged LIRC_SERIAL_TRANSMITTER_LATENCY + * Implicitly i586 architecture... - Steve + */ + +static inline long send_pulse_homebrew_softcarrier(unsigned long length) +{ + int flag; + unsigned long target, start, now; + + /* Get going quick as we can */ + rdtscl(start); on(); + /* Convert length from microseconds to clocks */ + length *= conv_us_to_clocks; + /* And loop till time is up - flipping at right intervals */ + now = start; + target = pulse_width; + flag = 1; + while ((now-start) < length) { + /* Delay till flip time */ + do + rdtscl(now); + while ((now-start) < target); + + /* flip */ + if (flag) { + rdtscl(now); off(); + target += space_width; + } else { + rdtscl(now); on(); + target += pulse_width; + } + flag = !flag; + } + rdtscl(now); + return (((now-start)-length)/conv_us_to_clocks); +} +#else /* ! USE_RDTSC */ +/* Version using udelay() */ + +/* here we use fixed point arithmetic, with 8 + fractional bits. that gets us within 0.1% or so of the right average + frequency, albeit with some jitter in pulse length - Steve */ + +/* To match 8 fractional bits used for pulse/space length */ + +static inline long send_pulse_homebrew_softcarrier(unsigned long length) +{ + int flag; + unsigned long actual, target, d; + length <<= 8; + + actual = 0; target = 0; flag = 0; + while (actual < length) { + if (flag) { + off(); + target += space_width; + } else { + on(); + target += pulse_width; + } + d = (target-actual-LIRC_SERIAL_TRANSMITTER_LATENCY+128)>>8; + /* Note - we've checked in ioctl that the pulse/space + widths are big enough so that d is > 0 */ + udelay(d); + actual += (d<<8)+LIRC_SERIAL_TRANSMITTER_LATENCY; + flag = !flag; + } + return ((actual-length)>>8); +} +#endif /* USE_RDTSC */ + +static long send_pulse_homebrew(unsigned long length) +{ + if (length <= 0) + return 0; + + if (softcarrier) + return send_pulse_homebrew_softcarrier(length); + else { + on(); + safe_udelay(length); + return 0; + } +} + +static void send_space_irdeo(long length) +{ + if (length <= 0) + return; + + safe_udelay(length); +} + +static void send_space_homebrew(long length) +{ + off(); + if (length <= 0) + return; + safe_udelay(length); +} + +static inline void rbwrite(lirc_t l) +{ + if (lirc_buffer_full(&rbuf)) { + /* no new signals will be accepted */ + dprintk("Buffer overrun\n"); + return; + } + _lirc_buffer_write_1(&rbuf, (void *)&l); +} + +static inline void frbwrite(lirc_t l) +{ + /* simple noise filter */ + static lirc_t pulse = 0L, space = 0L; + static unsigned int ptr; + + if (ptr > 0 && (l&PULSE_BIT)) { + pulse += l&PULSE_MASK; + if (pulse > 250) { + rbwrite(space); + rbwrite(pulse|PULSE_BIT); + ptr = 0; + pulse = 0; + } + return; + } + if (!(l&PULSE_BIT)) { + if (ptr == 0) { + if (l > 20000) { + space = l; + ptr++; + return; + } + } else { + if (l > 20000) { + space += pulse; + if (space > PULSE_MASK) + space = PULSE_MASK; + space += l; + if (space > PULSE_MASK) + space = PULSE_MASK; + pulse = 0; + return; + } + rbwrite(space); + rbwrite(pulse|PULSE_BIT); + ptr = 0; + pulse = 0; + } + } + rbwrite(l); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) +static irqreturn_t irq_handler(int i, void *blah) +#else +static irqreturn_t irq_handler(int i, void *blah, struct pt_regs *regs) +#endif +{ + struct timeval tv; + int status, counter, dcd; + long deltv; + lirc_t data; + static int last_dcd = -1; + + if ((sinp(UART_IIR) & UART_IIR_NO_INT)) { + /* not our interrupt */ + return IRQ_RETVAL(IRQ_NONE); + } + + counter = 0; + do { + counter++; + status = sinp(UART_MSR); + if (counter > RS_ISR_PASS_LIMIT) { + printk(KERN_WARNING LIRC_DRIVER_NAME ": AIEEEE: " + "We're caught!\n"); + break; + } + if ((status&hardware[type].signal_pin_change) && sense != -1) { + /* get current time */ + do_gettimeofday(&tv); + + /* New mode, written by Trent Piepho + . */ + + /* The old format was not very portable. + We now use the type lirc_t to pass pulses + and spaces to user space. + + If PULSE_BIT is set a pulse has been + received, otherwise a space has been + received. The driver needs to know if your + receiver is active high or active low, or + the space/pulse sense could be + inverted. The bits denoted by PULSE_MASK are + the length in microseconds. Lengths greater + than or equal to 16 seconds are clamped to + PULSE_MASK. All other bits are unused. + This is a much simpler interface for user + programs, as well as eliminating "out of + phase" errors with space/pulse + autodetection. */ + + /* calculate time since last interrupt in + microseconds */ + dcd = (status & hardware[type].signal_pin) ? 1:0; + + if (dcd == last_dcd) { + printk(KERN_WARNING LIRC_DRIVER_NAME + ": ignoring spike: %d %d %lx %lx %lx %lx\n", + dcd, sense, + tv.tv_sec, lasttv.tv_sec, + tv.tv_usec, lasttv.tv_usec); + continue; + } + + deltv = tv.tv_sec-lasttv.tv_sec; + if (tv.tv_sec < lasttv.tv_sec || + (tv.tv_sec == lasttv.tv_sec && + tv.tv_usec < lasttv.tv_usec)) { + printk(KERN_WARNING LIRC_DRIVER_NAME + ": AIEEEE: your clock just jumped " + "backwards\n"); + printk(KERN_WARNING LIRC_DRIVER_NAME + ": %d %d %lx %lx %lx %lx\n", + dcd, sense, + tv.tv_sec, lasttv.tv_sec, + tv.tv_usec, lasttv.tv_usec); + data = PULSE_MASK; + } else if (deltv > 15) { + data = PULSE_MASK; /* really long time */ + if (!(dcd^sense)) { + /* sanity check */ + printk(KERN_WARNING LIRC_DRIVER_NAME + ": AIEEEE: " + "%d %d %lx %lx %lx %lx\n", + dcd, sense, + tv.tv_sec, lasttv.tv_sec, + tv.tv_usec, lasttv.tv_usec); + /* detecting pulse while this + MUST be a space! */ + sense = sense ? 0:1; + } + } else + data = (lirc_t) (deltv*1000000 + + tv.tv_usec - + lasttv.tv_usec); + frbwrite(dcd^sense ? data : (data|PULSE_BIT)); + lasttv = tv; + last_dcd = dcd; + wake_up_interruptible(&rbuf.wait_poll); + } + } while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */ + return IRQ_RETVAL(IRQ_HANDLED); +} + +static void hardware_init_port(void) +{ + unsigned long flags; + local_irq_save(flags); + + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + /* First of all, disable all interrupts */ + soutp(UART_IER, sinp(UART_IER) & + (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); + + /* Clear registers. */ + sinp(UART_LSR); + sinp(UART_RX); + sinp(UART_IIR); + sinp(UART_MSR); + +#if defined(LIRC_SERIAL_NSLU2) + if (type == LIRC_NSLU2) { + /* Setup NSLU2 UART */ + + /* Enable UART */ + soutp(UART_IER, sinp(UART_IER) | UART_IE_IXP42X_UUE); + /* Disable Receiver data Time out interrupt */ + soutp(UART_IER, sinp(UART_IER) & ~UART_IE_IXP42X_RTOIE); + /* set out2 = interupt unmask; off() doesn't set MCR + on NSLU2 */ + soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); + } +#endif + + /* Set line for power source */ + off(); + + /* Clear registers again to be sure. */ + sinp(UART_LSR); + sinp(UART_RX); + sinp(UART_IIR); + sinp(UART_MSR); + + switch (type) { + case LIRC_IRDEO: + case LIRC_IRDEO_REMOTE: + /* setup port to 7N1 @ 115200 Baud */ + /* 7N1+start = 9 bits at 115200 ~ 3 bits at 38kHz */ + + /* Set DLAB 1. */ + soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); + /* Set divisor to 1 => 115200 Baud */ + soutp(UART_DLM, 0); + soutp(UART_DLL, 1); + /* Set DLAB 0 + 7N1 */ + soutp(UART_LCR, UART_LCR_WLEN7); + /* THR interrupt already disabled at this point */ + break; + default: + break; + } + + local_irq_restore(flags); +} + +static int init_port(void) +{ + int i, nlow, nhigh; + + /* Reserve io region. */ +#if defined(LIRC_ALLOW_MMAPPED_IO) + /* Future MMAP-Developers: Attention! + For memory mapped I/O you *might* need to use ioremap() first, + for the NSLU2 it's done in boot code. */ + if (((iommap != 0) + && (request_mem_region(iommap, 8<= nhigh ? 1 : 0); + printk(KERN_INFO LIRC_DRIVER_NAME ": auto-detected active " + "%s receiver\n", sense ? "low":"high"); + } else + printk(KERN_INFO LIRC_DRIVER_NAME ": Manually using active " + "%s receiver\n", sense ? "low":"high"); + + return 0; +} + +static int set_use_inc(void *data) +{ + int result; + unsigned long flags; + + /* Init read buffer. */ + if (lirc_buffer_init(&rbuf, sizeof(lirc_t), RBUF_LEN) < 0) + return -ENOMEM; + + /* initialize timestamp */ + do_gettimeofday(&lasttv); + + result = request_irq(irq, irq_handler, + IRQF_DISABLED | (share_irq ? IRQF_SHARED:0), + LIRC_DRIVER_NAME, (void *)&hardware); + + switch (result) { + case -EBUSY: + printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq); + lirc_buffer_free(&rbuf); + return -EBUSY; + case -EINVAL: + printk(KERN_ERR LIRC_DRIVER_NAME + ": Bad irq number or handler\n"); + lirc_buffer_free(&rbuf); + return -EINVAL; + default: + dprintk("Interrupt %d, port %04x obtained\n", irq, io); + break; + }; + + local_irq_save(flags); + + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); + + local_irq_restore(flags); + + MOD_INC_USE_COUNT; + return 0; +} + +static void set_use_dec(void *data) +{ unsigned long flags; + + local_irq_save(flags); + + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + /* First of all, disable all interrupts */ + soutp(UART_IER, sinp(UART_IER) & + (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); + local_irq_restore(flags); + + free_irq(irq, (void *)&hardware); + + dprintk("freed IRQ %d\n", irq); + lirc_buffer_free(&rbuf); + + MOD_DEC_USE_COUNT; +} + +static ssize_t lirc_write(struct file *file, const char *buf, + size_t n, loff_t *ppos) +{ + int i, count; + unsigned long flags; + long delta = 0; + + if (!(hardware[type].features&LIRC_CAN_SEND_PULSE)) + return -EBADF; + + if (n % sizeof(lirc_t)) + return -EINVAL; + count = n / sizeof(lirc_t); + if (count > WBUF_LEN || count % 2 == 0) + return -EINVAL; + if (copy_from_user(wbuf, buf, n)) + return -EFAULT; + local_irq_save(flags); + if (type == LIRC_IRDEO) { + /* DTR, RTS down */ + on(); + } + for (i = 0; i < count; i++) { + if (i%2) + hardware[type].send_space(wbuf[i]-delta); + else + delta = hardware[type].send_pulse(wbuf[i]); + } + off(); + local_irq_restore(flags); + return n; +} + +static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, + unsigned long arg) +{ + int result; + unsigned long value; + unsigned int ivalue; + + switch (cmd) { + case LIRC_GET_SEND_MODE: + if (!(hardware[type].features&LIRC_CAN_SEND_MASK)) + return -ENOIOCTLCMD; + + result = put_user(LIRC_SEND2MODE + (hardware[type].features&LIRC_CAN_SEND_MASK), + (unsigned long *) arg); + if (result) + return result; + break; + + case LIRC_SET_SEND_MODE: + if (!(hardware[type].features&LIRC_CAN_SEND_MASK)) + return -ENOIOCTLCMD; + + result = get_user(value, (unsigned long *) arg); + if (result) + return result; + /* only LIRC_MODE_PULSE supported */ + if (value != LIRC_MODE_PULSE) + return -ENOSYS; + break; + + case LIRC_GET_LENGTH: + return -ENOSYS; + break; + + case LIRC_SET_SEND_DUTY_CYCLE: + dprintk("SET_SEND_DUTY_CYCLE\n"); + if (!(hardware[type].features&LIRC_CAN_SET_SEND_DUTY_CYCLE)) + return -ENOIOCTLCMD; + + result = get_user(ivalue, (unsigned int *) arg); + if (result) + return result; + if (ivalue <= 0 || ivalue > 100) + return -EINVAL; + return init_timing_params(ivalue, freq); + break; + + case LIRC_SET_SEND_CARRIER: + dprintk("SET_SEND_CARRIER\n"); + if (!(hardware[type].features&LIRC_CAN_SET_SEND_CARRIER)) + return -ENOIOCTLCMD; + + result = get_user(ivalue, (unsigned int *) arg); + if (result) + return result; + if (ivalue > 500000 || ivalue < 20000) + return -EINVAL; + return init_timing_params(duty_cycle, ivalue); + break; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static struct file_operations lirc_fops = { + .write = lirc_write, +}; + +static struct lirc_plugin plugin = { + .name = LIRC_DRIVER_NAME, + .minor = -1, + .code_length = 1, + .sample_rate = 0, + .data = NULL, + .add_to_buf = NULL, + .get_queue = NULL, + .rbuf = &rbuf, + .set_use_inc = set_use_inc, + .set_use_dec = set_use_dec, + .ioctl = lirc_ioctl, + .fops = &lirc_fops, + .dev = NULL, + .owner = THIS_MODULE, +}; + +#ifdef MODULE + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) +static struct platform_device *lirc_serial_dev; + +static int __devinit lirc_serial_probe(struct platform_device *dev) +{ + return 0; +} + +static int __devexit lirc_serial_remove(struct platform_device *dev) +{ + return 0; +} + +static int lirc_serial_suspend(struct platform_device *dev, + pm_message_t state) +{ + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + /* Disable all interrupts */ + soutp(UART_IER, sinp(UART_IER) & + (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); + + /* Clear registers. */ + sinp(UART_LSR); + sinp(UART_RX); + sinp(UART_IIR); + sinp(UART_MSR); + + return 0; +} + +static int lirc_serial_resume(struct platform_device *dev) +{ + unsigned long flags; + + hardware_init_port(); + + local_irq_save(flags); + /* Enable Interrupt */ + do_gettimeofday(&lasttv); + soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); + off(); + + lirc_buffer_clear(&rbuf); + + local_irq_restore(flags); + + return 0; +} + +static struct platform_driver lirc_serial_driver = { + .probe = lirc_serial_probe, + .remove = __devexit_p(lirc_serial_remove), + .suspend = lirc_serial_suspend, + .resume = lirc_serial_resume, + .driver = { + .name = "lirc_serial", + .owner = THIS_MODULE, + }, +}; + +static int __init lirc_serial_init(void) +{ + int result; + + result = platform_driver_register(&lirc_serial_driver); + if (result) { + printk("lirc register returned %d\n", result); + return result; + } + + lirc_serial_dev = platform_device_alloc("lirc_serial", 0); + if (!lirc_serial_dev) { + result = -ENOMEM; + goto exit_driver_unregister; + } + + result = platform_device_add(lirc_serial_dev); + if (result) + goto exit_device_put; + + return 0; + +exit_device_put: + platform_device_put(lirc_serial_dev); +exit_driver_unregister: + platform_driver_unregister(&lirc_serial_driver); + return result; +} + +static void __exit lirc_serial_exit(void) +{ + platform_device_unregister(lirc_serial_dev); + platform_driver_unregister(&lirc_serial_driver); +} +#endif + +int __init init_module(void) +{ + int result; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) + result = lirc_serial_init(); + if (result) + return result; +#endif + switch (type) { + case LIRC_HOMEBREW: + case LIRC_IRDEO: + case LIRC_IRDEO_REMOTE: + case LIRC_ANIMAX: + case LIRC_IGOR: +#if defined(LIRC_SERIAL_NSLU2) + case LIRC_NSLU2: +#endif + break; + default: + result = -EINVAL; + goto exit_serial_exit; + } + if (!softcarrier) { + switch (type) { + case LIRC_HOMEBREW: + case LIRC_IGOR: + case LIRC_NSLU2: + hardware[type].features &= + ~(LIRC_CAN_SET_SEND_DUTY_CYCLE| + LIRC_CAN_SET_SEND_CARRIER); + break; + } + } + result = init_port(); + if (result < 0) + goto exit_serial_exit; + plugin.features = hardware[type].features; + plugin.minor = lirc_register_plugin(&plugin); + if (plugin.minor < 0) { + printk(KERN_ERR LIRC_DRIVER_NAME + ": register_chrdev failed!\n"); + result = -EIO; + goto exit_release; + } + return 0; +exit_release: + release_region(io, 8); +exit_serial_exit: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) + lirc_serial_exit(); +#endif + return result; +} + +void __exit cleanup_module(void) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) + lirc_serial_exit(); +#endif +#if defined(LIRC_ALLOW_MMAPPED_IO) + if (iommap != 0) + release_mem_region(iommap, 8< + * + * Transmitter support and reception code cleanup. + * (C) by Daniel Melander + * + * Derived from ATI USB driver by Paul Miller and the original + * MCE USB driver by Dan Corti + * + * This driver will only work reliably with kernel version 2.6.10 + * or higher, probably because of differences in USB device enumeration + * in the kernel code. Device initialization fails most of the time + * with earlier kernel versions. + * + ********************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 5) +#error "*******************************************************" +#error "Sorry, this driver needs kernel version 2.6.5 or higher" +#error "*******************************************************" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) +#include +#else +#include +#endif +#include +#include +#include +#include + +#include "lirc.h" +#include "kcompat.h" +#include "lirc_dev/lirc_dev.h" + +#define DRIVER_VERSION "$Revision: 1.44 $" +#define DRIVER_AUTHOR "Daniel Melander , " \ + "Martin Blatter " +#define DRIVER_DESC "Philips eHome USB IR Transceiver and Microsoft " \ + "MCE 2005 Remote Control driver for LIRC" +#define DRIVER_NAME "lirc_mceusb2" + +#define USB_BUFLEN 16 /* USB reception buffer length */ +#define LIRCBUF_SIZE 256 /* LIRC work buffer length */ + +/* MCE constants */ +#define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */ +#define MCE_TIME_UNIT 50 /* Approx 50us resolution */ +#define MCE_CODE_LENGTH 5 /* Normal length of packet (with header) */ +#define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */ +#define MCE_PACKET_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */ +#define MCE_CONTROL_HEADER 0x9F /* MCE status header */ +#define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */ +#define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */ +#define MCE_DEFAULT_TX_MASK 0x03 /* Val opts: TX1=0x01, TX2=0x02, ALL=0x03 */ +#define MCE_PULSE_BIT 0x80 /* Pulse bit, MSB set == PULSE else SPACE */ +#define MCE_PULSE_MASK 0x7F /* Pulse mask */ +#define MCE_MAX_PULSE_LENGTH 0x7F /* Longest transmittable pulse symbol */ + + +/* module parameters */ +#ifdef CONFIG_USB_DEBUG +static int debug = 1; +#else +static int debug; +#endif +#define dprintk(fmt, args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG fmt, ## args); \ + } while (0) + +/* lock irctl structure */ +/*#define IRLOCK down_interruptible(&ir->lock) */ +#define IRLOCK down(&ir->lock) +#define IRUNLOCK up(&ir->lock) + +/* general constants */ +#define SUCCESS 0 +#define SEND_FLAG_IN_PROGRESS 1 +#define SEND_FLAG_COMPLETE 2 +#define RECV_FLAG_IN_PROGRESS 3 +#define RECV_FLAG_COMPLETE 4 + +#define PHILUSB_INBOUND 1 +#define PHILUSB_OUTBOUND 2 + +#define VENDOR_PHILIPS 0x0471 +#define VENDOR_SMK 0x0609 +#define VENDOR_TATUNG 0x1460 +#define VENDOR_GATEWAY 0x107b +#define VENDOR_SHUTTLE 0x1308 +#define VENDOR_SHUTTLE2 0x051c +#define VENDOR_MITSUMI 0x03ee +#define VENDOR_TOPSEED 0x1784 +#define VENDOR_RICAVISION 0x179d +#define VENDOR_ITRON 0x195d +#define VENDOR_FIC 0x1509 +#define VENDOR_LG 0x043e +#define VENDOR_MICROSOFT 0x045e +#define VENDOR_FORMOSA 0x147a +#define VENDOR_FINTEK 0x1934 + +static struct usb_device_id usb_remote_table [] = { + /* Philips eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_PHILIPS, 0x0815) }, + /* Philips Infrared Transceiver - HP branded */ + { USB_DEVICE(VENDOR_PHILIPS, 0x060c) }, + /* Philips SRM5100 */ + { USB_DEVICE(VENDOR_PHILIPS, 0x060d) }, + /* SMK/Toshiba G83C0004D410 */ + { USB_DEVICE(VENDOR_SMK, 0x031d) }, + /* SMK eHome Infrared Transceiver (Sony VAIO) */ + { USB_DEVICE(VENDOR_SMK, 0x0322) }, + /* bundled with Hauppauge PVR-150 */ + { USB_DEVICE(VENDOR_SMK, 0x0334) }, + /* Tatung eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_TATUNG, 0x9150) }, + /* Shuttle eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_SHUTTLE, 0xc001) }, + /* Shuttle eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_SHUTTLE2, 0xc001) }, + /* Gateway eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_GATEWAY, 0x3009) }, + /* Mitsumi */ + { USB_DEVICE(VENDOR_MITSUMI, 0x2501) }, + /* Topseed eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_TOPSEED, 0x0001) }, + /* Topseed HP eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_TOPSEED, 0x0006) }, + /* Topseed eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_TOPSEED, 0x0007) }, + /* Topseed eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_TOPSEED, 0x0008) }, + /* Ricavision internal Infrared Transceiver */ + { USB_DEVICE(VENDOR_RICAVISION, 0x0010) }, + /* Itron ione Libra Q-11 */ + { USB_DEVICE(VENDOR_ITRON, 0x7002) }, + /* FIC eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_FIC, 0x9242) }, + /* LG eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_LG, 0x9803) }, + /* Microsoft MCE Infrared Transceiver */ + { USB_DEVICE(VENDOR_MICROSOFT, 0x00a0) }, + /* Formosa eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_FORMOSA, 0xe015) }, + /* Formosa aim / Trust MCE Infrared Receiver */ + { USB_DEVICE(VENDOR_FORMOSA, 0xe017) }, + /* Formosa Industrial Computing / Beanbag Emulation Device */ + { USB_DEVICE(VENDOR_FORMOSA, 0xe018) }, + /* Fintek eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_FINTEK, 0x0602) }, + /* Terminating entry */ + { } +}; + +/* data structure for each usb remote */ +struct irctl { + + /* usb */ + struct usb_device *usbdev; + struct urb *urb_in; + int devnum; + struct usb_endpoint_descriptor *usb_ep_in; + struct usb_endpoint_descriptor *usb_ep_out; + + /* buffers and dma */ + unsigned char *buf_in; + unsigned int len_in; + dma_addr_t dma_in; + dma_addr_t dma_out; + + /* lirc */ + struct lirc_plugin *p; + lirc_t lircdata; + unsigned char is_pulse; + int connected; + + unsigned char transmitter_mask; + unsigned int carrier_freq; + + /* handle sending (init strings) */ + int send_flags; + wait_queue_head_t wait_out; + + struct semaphore lock; +}; + +/* init strings */ +static char init1[] = {0x00, 0xff, 0xaa, 0xff, 0x0b}; +static char init2[] = {0xff, 0x18}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11) +static inline unsigned long usecs_to_jiffies(const unsigned int u) +{ + if (u > jiffies_to_usecs(MAX_JIFFY_OFFSET)) + return MAX_JIFFY_OFFSET; +#if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ) + return (u + (USEC_PER_SEC / HZ) - 1) / (USEC_PER_SEC / HZ); +#elif HZ > USEC_PER_SEC && !(HZ % USEC_PER_SEC) + return u * (HZ / USEC_PER_SEC); +#else + return (u * HZ + USEC_PER_SEC - 1) / USEC_PER_SEC; +#endif +} +#endif + + +static void usb_remote_printdata(struct irctl *ir, char *buf, int len) +{ + char codes[USB_BUFLEN*3 + 1]; + int i; + + if (len <= 0) + return; + + for (i = 0; i < len && i < USB_BUFLEN; i++) + snprintf(codes+i*3, 4, "%02x ", buf[i] & 0xFF); + + printk(KERN_INFO "" DRIVER_NAME "[%d]: data received %s (length=%d)\n", + ir->devnum, codes, len); +} + +static void usb_async_callback(struct urb *urb, struct pt_regs *regs) +{ + struct irctl *ir; + int len; + + if (!urb) + return; + + ir = urb->context; + if (ir) { + len = urb->actual_length; + + dprintk(DRIVER_NAME + "[%d]: callback called (status=%d len=%d)\n", + ir->devnum, urb->status, len); + + if (debug) + usb_remote_printdata(ir, urb->transfer_buffer, len); + } + +} + + +/* request incoming or send outgoing usb packet - used to initialize remote */ +static void request_packet_async(struct irctl *ir, + struct usb_endpoint_descriptor *ep, + unsigned char *data, int size, int urb_type) +{ + int res; + struct urb *async_urb; + unsigned char *async_buf; + + if (urb_type) { + async_urb = usb_alloc_urb(0, GFP_KERNEL); + if (async_urb) { + /* alloc buffer */ + async_buf = kmalloc(size, GFP_KERNEL); + if (async_buf) { + if (urb_type == PHILUSB_OUTBOUND) { + /* outbound data */ + usb_fill_int_urb(async_urb, ir->usbdev, + usb_sndintpipe(ir->usbdev, + ep->bEndpointAddress), + async_buf, + size, + (usb_complete_t) usb_async_callback, + ir, ep->bInterval); + + memcpy(async_buf, data, size); + async_urb->transfer_flags = + URB_ASYNC_UNLINK; + } else { + /* inbound data */ + usb_fill_int_urb(async_urb, ir->usbdev, + usb_rcvintpipe(ir->usbdev, + ep->bEndpointAddress), + async_buf, size, + (usb_complete_t) usb_async_callback, + ir, ep->bInterval); + + async_urb->transfer_flags = + URB_ASYNC_UNLINK; + } + } else { + usb_free_urb(async_urb); + return; + } + } + } else { + /* standard request */ + async_urb = ir->urb_in; + ir->send_flags = RECV_FLAG_IN_PROGRESS; + } + dprintk(DRIVER_NAME "[%d]: receive request called (size=%#x)\n", + ir->devnum, size); + + async_urb->transfer_buffer_length = size; + async_urb->dev = ir->usbdev; + + res = usb_submit_urb(async_urb, GFP_ATOMIC); + if (res) { + dprintk(DRIVER_NAME "[%d]: receive request FAILED! (res=%d)\n", + ir->devnum, res); + return; + } + dprintk(DRIVER_NAME "[%d]: receive request complete (res=%d)\n", + ir->devnum, res); +} + +static int unregister_from_lirc(struct irctl *ir) +{ + struct lirc_plugin *p = ir->p; + int devnum; + int rtn; + + devnum = ir->devnum; + dprintk(DRIVER_NAME "[%d]: unregister from lirc called\n", devnum); + + rtn = lirc_unregister_plugin(p->minor); + if (rtn > 0) { + printk(DRIVER_NAME "[%d]: error in lirc_unregister minor: %d\n" + "Trying again...\n", devnum, p->minor); + if (rtn == -EBUSY) { + printk(DRIVER_NAME + "[%d]: device is opened, will unregister" + " on close\n", devnum); + return -EAGAIN; + } + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + + rtn = lirc_unregister_plugin(p->minor); + if (rtn > 0) + printk(DRIVER_NAME "[%d]: lirc_unregister failed\n", + devnum); + } + + if (rtn != SUCCESS) { + printk(DRIVER_NAME "[%d]: didn't free resources\n", devnum); + return -EAGAIN; + } + + printk(DRIVER_NAME "[%d]: usb remote disconnected\n", devnum); + + lirc_buffer_free(p->rbuf); + kfree(p->rbuf); + kfree(p); + kfree(ir); + return SUCCESS; +} + +static int set_use_inc(void *data) +{ + struct irctl *ir = data; + + if (!ir) { + printk(DRIVER_NAME "[?]: set_use_inc called with no context\n"); + return -EIO; + } + dprintk(DRIVER_NAME "[%d]: set use inc\n", ir->devnum); + + MOD_INC_USE_COUNT; + + if (!ir->connected) { + if (!ir->usbdev) + return -ENOENT; + ir->connected = 1; + } + + return SUCCESS; +} + +static void set_use_dec(void *data) +{ + struct irctl *ir = data; + + if (!ir) { + printk(DRIVER_NAME "[?]: set_use_dec called with no context\n"); + return; + } + dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum); + + if (ir->connected) { + IRLOCK; + ir->connected = 0; + IRUNLOCK; + } + MOD_DEC_USE_COUNT; +} + +static void send_packet_to_lirc(struct irctl *ir) +{ + if (ir->lircdata != 0) { + lirc_buffer_write_1(ir->p->rbuf, + (unsigned char *) &ir->lircdata); + wake_up(&ir->p->rbuf->wait_poll); + ir->lircdata = 0; + } +} + +static void usb_remote_recv(struct urb *urb, struct pt_regs *regs) +{ + struct irctl *ir; + int buf_len, packet_len; + int i, j; + + if (!urb) + return; + + ir = urb->context; + if (!ir) { + urb->transfer_flags |= URB_ASYNC_UNLINK; + usb_unlink_urb(urb); + return; + } + + buf_len = urb->actual_length; + packet_len = 0; + + if (debug) + usb_remote_printdata(ir, urb->transfer_buffer, buf_len); + + if (ir->send_flags == RECV_FLAG_IN_PROGRESS) { + ir->send_flags = SEND_FLAG_COMPLETE; + dprintk(DRIVER_NAME "[%d]: setup answer received %d bytes\n", + ir->devnum, buf_len); + } + + switch (urb->status) { + /* success */ + case SUCCESS: + for (i = 0; i < buf_len; i++) { + /* decode mce packets on the form (84),AA,BB,CC,DD */ + switch (ir->buf_in[i]) { + /* data headers */ + case 0x8F: + case 0x8E: + case 0x8D: + case 0x8C: + case 0x8B: + case 0x8A: + case 0x89: + case 0x88: + case 0x87: + case 0x86: + case 0x85: + case 0x84: + case 0x83: + case 0x82: + case 0x81: + case 0x80: + /* decode packet data */ + packet_len = ir->buf_in[i] & MCE_PULSE_MASK; + for (j = 1; + j <= packet_len && (i+j < buf_len); + j++) { + /* rising/falling flank */ + if (ir->is_pulse != + (ir->buf_in[i + j] & + MCE_PULSE_BIT)) { + send_packet_to_lirc(ir); + ir->is_pulse = + ir->buf_in[i + j] & + MCE_PULSE_BIT; + } + + /* accumulate mce pulse/space values */ + ir->lircdata += + (ir->buf_in[i + j] & + MCE_PULSE_MASK)*MCE_TIME_UNIT; + ir->lircdata |= + (ir->is_pulse ? PULSE_BIT : 0); + } + + i += packet_len; + break; + + /* status header (0x9F) */ + case MCE_CONTROL_HEADER: + /* A transmission containing one or + more consecutive ir commands always + ends with a GAP of 100ms followed by the + sequence 0x9F 0x01 0x01 0x9F 0x15 + 0x00 0x00 0x80 */ + + /* + Uncomment this if the last 100ms + "infinity"-space should be transmitted + to lirc directly instead of at the beginning + of the next transmission. Changes pulse/space order. + + if (++i < buf_len && ir->buf_in[i]==0x01) + send_packet_to_lirc(ir); + + */ + + /* end decode loop */ + i = buf_len; + break; + default: + break; + } + } + + break; + + /* unlink */ + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + urb->transfer_flags |= URB_ASYNC_UNLINK; + usb_unlink_urb(urb); + return; + + case -EPIPE: + default: + break; + } + + /* resubmit urb */ + usb_submit_urb(urb, GFP_ATOMIC); +} + + +static ssize_t lirc_write(struct file *file, const char *buf, + size_t n, loff_t *ppos) +{ + int i, count = 0, cmdcount = 0; + struct irctl *ir = NULL; + lirc_t wbuf[LIRCBUF_SIZE]; /* Workbuffer with values from lirc */ + unsigned char cmdbuf[MCE_CMDBUF_SIZE]; /* MCE command buffer */ + unsigned long signal_duration = 0; /* Singnal length in us */ + struct timeval start_time, end_time; + + do_gettimeofday(&start_time); + + /* Retrieve lirc_plugin data for the device */ + ir = lirc_get_pdata(file); + if (!ir && !ir->usb_ep_out) + return -EFAULT; + + if (n % sizeof(lirc_t)) + return(-EINVAL); + count = n / sizeof(lirc_t); + + /* Check if command is within limits */ + if (count > LIRCBUF_SIZE || count%2 == 0) + return(-EINVAL); + if (copy_from_user(wbuf, buf, n)) + return -EFAULT; + + /* MCE tx init header */ + cmdbuf[cmdcount++] = MCE_CONTROL_HEADER; + cmdbuf[cmdcount++] = 0x08; + cmdbuf[cmdcount++] = ir->transmitter_mask; + + /* Generate mce packet data */ + for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) { + signal_duration += wbuf[i]; + wbuf[i] = wbuf[i] / MCE_TIME_UNIT; + + do { /* loop to support long pulses/spaces > 127*50us=6.35ms */ + + /* Insert mce packet header every 4th entry */ + if ((cmdcount < MCE_CMDBUF_SIZE) && + (cmdcount - MCE_TX_HEADER_LENGTH) % + MCE_CODE_LENGTH == 0) + cmdbuf[cmdcount++] = MCE_PACKET_HEADER; + + /* Insert mce packet data */ + if (cmdcount < MCE_CMDBUF_SIZE) + cmdbuf[cmdcount++] = + (wbuf[i] < MCE_PULSE_BIT ? + wbuf[i] : MCE_MAX_PULSE_LENGTH) | + (i & 1 ? 0x00 : MCE_PULSE_BIT); + else + return -EINVAL; + } while ((wbuf[i] > MCE_MAX_PULSE_LENGTH) && + (wbuf[i] -= MCE_MAX_PULSE_LENGTH)); + } + + /* Fix packet length in last header */ + cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] = + 0x80 + (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH - 1; + + /* Check if we have room for the empty packet at the end */ + if (cmdcount >= MCE_CMDBUF_SIZE) + return -EINVAL; + + /* All mce commands end with an empty packet (0x80) */ + cmdbuf[cmdcount++] = 0x80; + + /* Transmit the command to the mce device */ + request_packet_async(ir, ir->usb_ep_out, cmdbuf, + cmdcount, PHILUSB_OUTBOUND); + + /* The lircd gap calculation expects the write function to + wait the time it takes for the ircommand to be sent before + it returns. */ + do_gettimeofday(&end_time); + signal_duration -= (end_time.tv_usec - start_time.tv_usec) + + (end_time.tv_sec - start_time.tv_sec) * 1000000; + + /* delay with the closest number of ticks */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(usecs_to_jiffies(signal_duration)); + + return n; +} + +static void set_transmitter_mask(struct irctl *ir, unsigned int mask) +{ + + /* SMK Transceiver does not use the inverted scheme, nor does Topseed*/ + if ((ir->usbdev->descriptor.idVendor == VENDOR_SMK && + (ir->usbdev->descriptor.idProduct == 0x031d || + ir->usbdev->descriptor.idProduct == 0x0322 || + ir->usbdev->descriptor.idProduct == 0x0334)) || + (ir->usbdev->descriptor.idVendor == VENDOR_TOPSEED && + (ir->usbdev->descriptor.idProduct == 0x0001 || + ir->usbdev->descriptor.idProduct == 0x0007 || + ir->usbdev->descriptor.idProduct == 0x0008))) + ir->transmitter_mask = mask; + else + /* The mask begins at 0x02 and has an inverted + numbering scheme */ + ir->transmitter_mask = (mask != 0x03 ? mask ^ 0x03 : mask) << 1; +} + + +/* Sets the send carrier frequency */ +static int set_send_carrier(struct irctl *ir, int carrier) +{ + int clk = 10000000; + int prescaler = 0, divisor = 0; + unsigned char cmdbuf[] = { 0x9F, 0x06, 0x01, 0x80 }; + + /* Carrier is changed */ + if (ir->carrier_freq != carrier) { + + if (carrier <= 0) { + ir->carrier_freq = carrier; + dprintk(DRIVER_NAME "[%d]: SET_CARRIER disabling " + "carrier modulation\n", ir->devnum); + request_packet_async(ir, ir->usb_ep_out, + cmdbuf, sizeof(cmdbuf), + PHILUSB_OUTBOUND); + return carrier; + } + + for (prescaler = 0; prescaler < 4; ++prescaler) { + divisor = (clk >> (2 * prescaler)) / carrier; + if (divisor <= 0xFF) { + ir->carrier_freq = carrier; + cmdbuf[2] = prescaler; + cmdbuf[3] = divisor; + dprintk(DRIVER_NAME "[%d]: SET_CARRIER " + "requesting %d Hz\n", + ir->devnum, carrier); + + /* Transmit the new carrier to the mce + device */ + request_packet_async(ir, ir->usb_ep_out, + cmdbuf, sizeof(cmdbuf), + PHILUSB_OUTBOUND); + return carrier; + } + } + + return -EINVAL; + + } + + return carrier; +} + + +static int lirc_ioctl(struct inode *node, struct file *filep, + unsigned int cmd, unsigned long arg) +{ + int result; + unsigned int ivalue; + unsigned long lvalue; + struct irctl *ir = NULL; + + /* Retrieve lirc_plugin data for the device */ + ir = lirc_get_pdata(filep); + if (!ir && !ir->usb_ep_out) + return -EFAULT; + + + switch (cmd) { + case LIRC_SET_TRANSMITTER_MASK: + + result = get_user(ivalue, (unsigned int *) arg); + if (result) + return result; + switch (ivalue) { + case 0x01: /* Transmitter 1 => 0x04 */ + case 0x02: /* Transmitter 2 => 0x02 */ + case 0x03: /* Transmitter 1 & 2 => 0x06 */ + set_transmitter_mask(ir, ivalue); + break; + + default: /* Unsupported transmitter mask */ + return MCE_MAX_CHANNELS; + } + + dprintk(DRIVER_NAME ": SET_TRANSMITTERS mask=%d\n", ivalue); + break; + + case LIRC_GET_SEND_MODE: + + result = put_user(LIRC_SEND2MODE(LIRC_CAN_SEND_PULSE & + LIRC_CAN_SEND_MASK), + (unsigned long *) arg); + + if (result) + return result; + break; + + case LIRC_SET_SEND_MODE: + + result = get_user(lvalue, (unsigned long *) arg); + + if (result) + return result; + if (lvalue != (LIRC_MODE_PULSE&LIRC_CAN_SEND_MASK)) + return -EINVAL; + break; + + case LIRC_SET_SEND_CARRIER: + + result = get_user(ivalue, (unsigned int *) arg); + if (result) + return result; + + set_send_carrier(ir, ivalue); + break; + + default: + return -ENOIOCTLCMD; + } + + return 0; +} + +static struct file_operations lirc_fops = { + .write = lirc_write, +}; + + +static int usb_remote_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct usb_host_interface *idesc; + struct usb_endpoint_descriptor *ep = NULL; + struct usb_endpoint_descriptor *ep_in = NULL; + struct usb_endpoint_descriptor *ep_out = NULL; + struct usb_host_config *config; + struct irctl *ir = NULL; + struct lirc_plugin *plugin = NULL; + struct lirc_buffer *rbuf = NULL; + int devnum, pipe, maxp; + int minor = 0; + int i; + char buf[63], name[128] = ""; + int mem_failure = 0; + + dprintk(DRIVER_NAME ": usb probe called\n"); + + usb_reset_device(dev); + + config = dev->actconfig; + + idesc = intf->cur_altsetting; + + /* step through the endpoints to find first bulk in and out endpoint */ + for (i = 0; i < idesc->desc.bNumEndpoints; ++i) { + ep = &idesc->endpoint[i].desc; + + if ((ep_in == NULL) + && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + == USB_DIR_IN) + && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_BULK) + || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_INT))) { + + dprintk(DRIVER_NAME ": acceptable inbound endpoint " + "found\n"); + ep_in = ep; + ep_in->bmAttributes = USB_ENDPOINT_XFER_INT; + ep_in->bInterval = 1; + } + + if ((ep_out == NULL) + && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + == USB_DIR_OUT) + && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_BULK) + || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_INT))) { + + dprintk(DRIVER_NAME ": acceptable outbound endpoint " + "found\n"); + ep_out = ep; + ep_out->bmAttributes = USB_ENDPOINT_XFER_INT; + ep_out->bInterval = 1; + } + } + if (ep_in == NULL) { + dprintk(DRIVER_NAME ": inbound and/or endpoint not found\n"); + return -ENODEV; + } + + devnum = dev->devnum; + pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress); + maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + + /* allocate kernel memory */ + mem_failure = 0; + ir = kmalloc(sizeof(struct irctl), GFP_KERNEL); + if (!ir) { + mem_failure = 1; + goto mem_failure_switch; + } + + memset(ir, 0, sizeof(struct irctl)); + + plugin = kmalloc(sizeof(struct lirc_plugin), GFP_KERNEL); + if (!plugin) { + mem_failure = 2; + goto mem_failure_switch; + } + + rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); + if (!rbuf) { + mem_failure = 3; + goto mem_failure_switch; + } + + if (lirc_buffer_init(rbuf, sizeof(lirc_t), LIRCBUF_SIZE)) { + mem_failure = 4; + goto mem_failure_switch; + } + + ir->buf_in = usb_buffer_alloc(dev, maxp, GFP_ATOMIC, &ir->dma_in); + if (!ir->buf_in) { + mem_failure = 5; + goto mem_failure_switch; + } + + ir->urb_in = usb_alloc_urb(0, GFP_KERNEL); + if (!ir->urb_in) { + mem_failure = 7; + goto mem_failure_switch; + } + + memset(plugin, 0, sizeof(struct lirc_plugin)); + + strcpy(plugin->name, DRIVER_NAME " "); + plugin->minor = -1; + plugin->features = LIRC_CAN_SEND_PULSE | + LIRC_CAN_SET_TRANSMITTER_MASK | + LIRC_CAN_REC_MODE2 | + LIRC_CAN_SET_SEND_CARRIER; + plugin->data = ir; + plugin->rbuf = rbuf; + plugin->set_use_inc = &set_use_inc; + plugin->set_use_dec = &set_use_dec; + plugin->code_length = sizeof(lirc_t) * 8; + plugin->ioctl = lirc_ioctl; + plugin->fops = &lirc_fops; + plugin->dev = &dev->dev; + plugin->owner = THIS_MODULE; + + init_MUTEX(&ir->lock); + init_waitqueue_head(&ir->wait_out); + + minor = lirc_register_plugin(plugin); + if (minor < 0) + mem_failure = 9; + +mem_failure_switch: + + /* free allocated memory incase of failure */ + switch (mem_failure) { + case 9: + usb_free_urb(ir->urb_in); + case 7: + usb_buffer_free(dev, maxp, ir->buf_in, ir->dma_in); + case 5: + lirc_buffer_free(rbuf); + case 4: + kfree(rbuf); + case 3: + kfree(plugin); + case 2: + kfree(ir); + case 1: + printk(DRIVER_NAME "[%d]: out of memory (code=%d)\n", + devnum, mem_failure); + return -ENOMEM; + } + + plugin->minor = minor; + ir->p = plugin; + ir->devnum = devnum; + ir->usbdev = dev; + ir->len_in = maxp; + ir->connected = 0; + + ir->lircdata = PULSE_MASK; + ir->is_pulse = 0; + + /* ir->usbdev must be set */ + set_transmitter_mask(ir, MCE_DEFAULT_TX_MASK); + /* Saving usb interface data for use by the transmitter routine */ + ir->usb_ep_in = ep_in; + ir->usb_ep_out = ep_out; + + if (dev->descriptor.iManufacturer + && usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0) + strncpy(name, buf, 128); + if (dev->descriptor.iProduct + && usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0) + snprintf(name, 128, "%s %s", name, buf); + printk(DRIVER_NAME "[%d]: %s on usb%d:%d\n", devnum, name, + dev->bus->busnum, devnum); + + /* inbound data */ + usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, + maxp, (usb_complete_t) usb_remote_recv, ir, ep_in->bInterval); + + /* initialize device */ + request_packet_async(ir, ep_in, NULL, maxp, PHILUSB_INBOUND); + request_packet_async(ir, ep_in, NULL, maxp, PHILUSB_INBOUND); + request_packet_async(ir, ep_out, init1, + sizeof(init1), PHILUSB_OUTBOUND); + request_packet_async(ir, ep_in, NULL, maxp, PHILUSB_INBOUND); + request_packet_async(ir, ep_out, init2, + sizeof(init2), PHILUSB_OUTBOUND); + request_packet_async(ir, ep_in, NULL, maxp, 0); + + usb_set_intfdata(intf, ir); + + return SUCCESS; +} + + +static void usb_remote_disconnect(struct usb_interface *intf) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct irctl *ir = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); + + if (!ir || !ir->p) + return; + + ir->usbdev = NULL; + wake_up_all(&ir->wait_out); + + IRLOCK; + usb_kill_urb(ir->urb_in); + usb_free_urb(ir->urb_in); + usb_buffer_free(dev, ir->len_in, ir->buf_in, ir->dma_in); + IRUNLOCK; + + unregister_from_lirc(ir); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) +static int usb_remote_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct irctl *ir = usb_get_intfdata(intf); + printk(DRIVER_NAME "[%d]: suspend\n", ir->devnum); + usb_kill_urb(ir->urb_in); + return 0; +} + +static int usb_remote_resume(struct usb_interface *intf) +{ + struct irctl *ir = usb_get_intfdata(intf); + printk(DRIVER_NAME "[%d]: resume\n", ir->devnum); + if (usb_submit_urb(ir->urb_in, GFP_ATOMIC)) + return -EIO; + return 0; +} +#endif + +static struct usb_driver usb_remote_driver = { + LIRC_THIS_MODULE(.owner = THIS_MODULE) + .name = DRIVER_NAME, + .probe = usb_remote_probe, + .disconnect = usb_remote_disconnect, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + .suspend = usb_remote_suspend, + .resume = usb_remote_resume, +#endif + .id_table = usb_remote_table +}; + +static int __init usb_remote_init(void) +{ + int i; + + printk(KERN_INFO "\n"); + printk(KERN_INFO DRIVER_NAME ": " DRIVER_DESC " " DRIVER_VERSION "\n"); + printk(KERN_INFO DRIVER_NAME ": " DRIVER_AUTHOR "\n"); + dprintk(DRIVER_NAME ": debug mode enabled\n"); + + request_module("lirc_dev"); + + i = usb_register(&usb_remote_driver); + if (i < 0) { + printk(DRIVER_NAME ": usb register failed, result = %d\n", i); + return -ENODEV; + } + + return SUCCESS; +} + +static void __exit usb_remote_exit(void) +{ + usb_deregister(&usb_remote_driver); +} + +module_init(usb_remote_init); +module_exit(usb_remote_exit); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(usb, usb_remote_table); + +module_param(debug, bool, 0644); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +EXPORT_NO_SYMBOLS; --- linux-2.6.27.orig/ubuntu/lirc/lirc_mceusb2/Makefile +++ linux-2.6.27/ubuntu/lirc/lirc_mceusb2/Makefile @@ -0,0 +1,3 @@ +EXTRA_CFLAGS =-DIRCTL_DEV_MAJOR=61 -DLIRC_SERIAL_TRANSMITTER -DLIRC_SERIAL_SOFTCARRIER -I$(src)/.. + +obj-$(CONFIG_LIRC_MCEUSB2) += lirc_mceusb2.o --- linux-2.6.27.orig/ubuntu/lirc/lirc_sasem/Makefile +++ linux-2.6.27/ubuntu/lirc/lirc_sasem/Makefile @@ -0,0 +1,2 @@ +EXTRA_CFLAGS =-DIRCTL_DEV_MAJOR=61 -DLIRC_SERIAL_TRANSMITTER -DLIRC_SERIAL_SOFTCARRIER -I$(src)/.. +obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o --- linux-2.6.27.orig/ubuntu/lirc/lirc_sasem/lirc_sasem.c +++ linux-2.6.27/ubuntu/lirc/lirc_sasem/lirc_sasem.c @@ -0,0 +1,1130 @@ +/* $Id: lirc_sasem.c,v 1.21 2007/09/30 09:58:46 lirc Exp $ */ + +/* lirc_sasem.c - USB remote support for LIRC + * Version 0.5 + * + * Copyright (C) 2004-2005 Oliver Stabel + * Tim Davies + * + * This driver was derived from: + * Venky Raju + * "lirc_imon - "LIRC plugin/VFD driver for Ahanix/Soundgraph IMON IR/VFD" + * Paul Miller 's 2003-2004 + * "lirc_atiusb - USB remote support for LIRC" + * Culver Consulting Services 's 2003 + * "Sasem OnAir VFD/IR USB driver" + * + * + * 2004/06/13 - 0.1 + * initial version + * + * 2004/06/28 - 0.2 + * added file system support to write data to VFD device (used + * in conjunction with LCDProc) + * + * 2004/11/22 - 0.3 + * Ported to 2.6 kernel + * - Tim Davies + * + * 2005/03/29 - 0.4 + * A few tidyups and keypress timings + * - Tim Davies + * + * 2005/06/23 - 0.5 + * A complete rewrite (shamelessly) based on lirc_imon.c + * Tim Davies + * + * NOTE - The LCDproc iMon driver should work with this module. More info at + * http://www.frogstorm.info/sasem + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 22) +#error "*** Sorry, this driver requires kernel version 2.4.22 or higher" +#endif + +#include + +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) +#include +#else +#include +#endif +#include + +#include "kcompat.h" +#include "lirc.h" +#include "lirc_dev/lirc_dev.h" + + +#define MOD_AUTHOR "Oliver Stabel , " \ + "Tim Davies " +#define MOD_DESC "USB Driver for Sasem Remote Controller V1.1" +#define MOD_NAME "lirc_sasem" +#define MOD_VERSION "0.5" + +#define VFD_MINOR_BASE 144 /* Same as LCD */ +#define DEVFS_MODE S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH +#define DEVFS_NAME LIRC_DEVFS_PREFIX "lcd%d" + +#define BUF_CHUNK_SIZE 8 +#define BUF_SIZE 128 + +#define SUCCESS 0 +#define TRUE 1 +#define FALSE 0 + +#define IOCTL_LCD_CONTRAST 1 + +/* ------------------------------------------------------------ + * P R O T O T Y P E S + * ------------------------------------------------------------ + */ + +/* USB Callback prototypes */ +#ifdef KERNEL_2_5 +static int sasem_probe(struct usb_interface *interface, + const struct usb_device_id *id); +static void sasem_disconnect(struct usb_interface *interface); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void usb_rx_callback(struct urb *urb, struct pt_regs *regs); +static void usb_tx_callback(struct urb *urb, struct pt_regs *regs); +#else +static void usb_rx_callback(struct urb *urb); +static void usb_tx_callback(struct urb *urb); +#endif +#else +static void *sasem_probe(struct usb_device *dev, unsigned int intf, + const struct usb_device_id *id); +static void sasem_disconnect(struct usb_device *dev, void *data); +static void usb_rx_callback(struct urb *urb); +static void usb_tx_callback(struct urb *urb); +#endif + +/* VFD file_operations function prototypes */ +static int vfd_open(struct inode *inode, struct file *file); +static int vfd_ioctl(struct inode *inode, struct file *file, + unsigned cmd, unsigned long arg); +static int vfd_close(struct inode *inode, struct file *file); +static ssize_t vfd_write(struct file *file, const char *buf, + size_t n_bytes, loff_t *pos); + +/* LIRC plugin function prototypes */ +static int ir_open(void *data); +static void ir_close(void *data); + +/* Driver init/exit prototypes */ +static int __init sasem_init(void); +static void __exit sasem_exit(void); + +/* ------------------------------------------------------------ + * G L O B A L S + * ------------------------------------------------------------ + */ + +struct sasem_context { + + struct usb_device *dev; + int vfd_isopen; /* VFD port has been opened */ + unsigned int vfd_contrast; /* VFD contrast */ +#if !defined(KERNEL_2_5) + int subminor; /* index into minor_table */ + devfs_handle_t devfs; +#endif + int ir_isopen; /* IR port has been opened */ + int dev_present; /* USB device presence */ + struct semaphore sem; /* to lock this object */ + wait_queue_head_t remove_ok; /* For unexpected USB disconnects */ + + struct lirc_plugin *plugin; + struct usb_endpoint_descriptor *rx_endpoint; + struct usb_endpoint_descriptor *tx_endpoint; + struct urb *rx_urb; + struct urb *tx_urb; + unsigned char usb_rx_buf [8]; + unsigned char usb_tx_buf [8]; + + struct tx_t { + unsigned char data_buf [32]; /* user data buffer */ + struct completion finished; /* wait for write to finish */ + atomic_t busy; /* write in progress */ + int status; /* status of tx completion */ + } tx; + + /* for dealing with repeat codes (wish there was a toggle bit!) */ + struct timeval presstime; + char lastcode[8]; + int codesaved; +}; + +#define LOCK_CONTEXT down(&context->sem) +#define UNLOCK_CONTEXT up(&context->sem) + +/* VFD file operations */ +static struct file_operations vfd_fops = { + + .owner = THIS_MODULE, + .open = &vfd_open, + .write = &vfd_write, + .ioctl = &vfd_ioctl, + .release = &vfd_close +}; + +/* USB Device ID for Sasem USB Control Board */ +static struct usb_device_id sasem_usb_id_table [] = { + { USB_DEVICE(0x11ba, 0x0101) }, /* Sasem */ + {} +}; + +/* USB Device data */ +static struct usb_driver sasem_driver = { + LIRC_THIS_MODULE(.owner = THIS_MODULE) + .name = MOD_NAME, + .probe = sasem_probe, + .disconnect = sasem_disconnect, + .id_table = sasem_usb_id_table, +#if !defined(KERNEL_2_5) + .fops = &vfd_fops, + .minor = VFD_MINOR_BASE, +#endif +}; + +#ifdef KERNEL_2_5 +static struct usb_class_driver sasem_class = { + .name = DEVFS_NAME, + .fops = &vfd_fops, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15) + .mode = DEVFS_MODE, +#endif + .minor_base = VFD_MINOR_BASE, +}; +#endif + +/* to prevent races between open() and disconnect() */ +static DECLARE_MUTEX(disconnect_sem); + +static int debug; + +#if !defined(KERNEL_2_5) + +#define MAX_DEVICES 4 /* In case there's more than one Sasem device */ +static struct sasem_context *minor_table [MAX_DEVICES]; + +/* the global usb devfs handle */ +extern devfs_handle_t usb_devfs_handle; + +#endif + +/* ------------------------------------------------------------ + * M O D U L E C O D E + * ------------------------------------------------------------ + */ + +MODULE_AUTHOR(MOD_AUTHOR); +MODULE_DESCRIPTION(MOD_DESC); +MODULE_LICENSE("GPL"); +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)"); + +static inline void delete_context(struct sasem_context *context) +{ + usb_free_urb(context->tx_urb); /* VFD */ + usb_free_urb(context->rx_urb); /* IR */ + lirc_buffer_free(context->plugin->rbuf); + kfree(context->plugin->rbuf); + kfree(context->plugin); + kfree(context); + + if (debug) + info("%s: context deleted", __FUNCTION__); +} + +static inline void deregister_from_lirc(struct sasem_context *context) +{ + int retval; + int minor = context->plugin->minor; + + retval = lirc_unregister_plugin(minor); + if (retval) + err("%s: unable to deregister from lirc (%d)", + __FUNCTION__, retval); + else + info("Deregistered Sasem plugin (minor:%d)", minor); + +} + +/** + * Called when the VFD device (e.g. /dev/usb/lcd) + * is opened by the application. + */ +static int vfd_open(struct inode *inode, struct file *file) +{ +#ifdef KERNEL_2_5 + struct usb_interface *interface; +#endif + struct sasem_context *context = NULL; + int subminor; + int retval = SUCCESS; + + /* prevent races with disconnect */ + down(&disconnect_sem); + +#ifdef KERNEL_2_5 + subminor = iminor(inode); + interface = usb_find_interface(&sasem_driver, subminor); + if (!interface) { + err("%s: could not find interface for minor %d", + __FUNCTION__, subminor); + retval = -ENODEV; + goto exit; + } + context = usb_get_intfdata(interface); +#else + subminor = MINOR(inode->i_rdev) - VFD_MINOR_BASE; + if (subminor < 0 || subminor >= MAX_DEVICES) { + err("%s: no record of minor %d", __FUNCTION__, subminor); + retval = -ENODEV; + goto exit; + } + context = minor_table [subminor]; +#endif + + if (!context) { + err("%s: no context found for minor %d", + __FUNCTION__, subminor); + retval = -ENODEV; + goto exit; + } + + LOCK_CONTEXT; + + if (context->vfd_isopen) { + err("%s: VFD port is already open", __FUNCTION__); + retval = -EBUSY; + } else { + MOD_INC_USE_COUNT; + context->vfd_isopen = TRUE; + file->private_data = context; + info("VFD port opened"); + } + + UNLOCK_CONTEXT; + +exit: + up(&disconnect_sem); + return retval; +} + +/** + * Called when the VFD device (e.g. /dev/usb/lcd) + * is closed by the application. + */ +static int vfd_ioctl(struct inode *inode, struct file *file, + unsigned cmd, unsigned long arg) +{ + struct sasem_context *context = NULL; + + context = (struct sasem_context *) file->private_data; + + if (!context) { + err("%s: no context for device", __FUNCTION__); + return -ENODEV; + } + + LOCK_CONTEXT; + + switch (cmd) { + case IOCTL_LCD_CONTRAST: + if (arg > 1000) + arg = 1000; + if (arg < 0) + arg = 0; + context->vfd_contrast = (unsigned int)arg; + break; + default: + info("Unknown IOCTL command"); + UNLOCK_CONTEXT; + return -ENOIOCTLCMD; /* not supported */ + } + + UNLOCK_CONTEXT; + return 0; +} + +/** + * Called when the VFD device (e.g. /dev/usb/lcd) + * is closed by the application. + */ +static int vfd_close(struct inode *inode, struct file *file) +{ + struct sasem_context *context = NULL; + int retval = SUCCESS; + + context = (struct sasem_context *) file->private_data; + + if (!context) { + err("%s: no context for device", __FUNCTION__); + return -ENODEV; + } + + LOCK_CONTEXT; + + if (!context->vfd_isopen) { + err("%s: VFD is not open", __FUNCTION__); + retval = -EIO; + } else { + context->vfd_isopen = FALSE; + MOD_DEC_USE_COUNT; + info("VFD port closed"); + if (!context->dev_present && !context->ir_isopen) { + + /* Device disconnected before close and IR port is + * not open. If IR port is open, context will be + * deleted by ir_close. */ + UNLOCK_CONTEXT; + delete_context(context); + return retval; + } + } + + UNLOCK_CONTEXT; + return retval; +} + +/** + * Sends a packet to the VFD. + */ +static inline int send_packet(struct sasem_context *context) +{ + unsigned int pipe; + int interval = 0; + int retval = SUCCESS; + + pipe = usb_sndintpipe(context->dev, + context->tx_endpoint->bEndpointAddress); +#ifdef KERNEL_2_5 + interval = context->tx_endpoint->bInterval; +#endif /* Use 0 for 2.4 kernels */ + + usb_fill_int_urb(context->tx_urb, context->dev, pipe, + context->usb_tx_buf, sizeof(context->usb_tx_buf), + usb_tx_callback, context, interval); + + context->tx_urb->actual_length = 0; + + init_completion(&context->tx.finished); + atomic_set(&(context->tx.busy), 1); + +#ifdef KERNEL_2_5 + retval = usb_submit_urb(context->tx_urb, GFP_KERNEL); +#else + retval = usb_submit_urb(context->tx_urb); +#endif + if (retval != SUCCESS) { + atomic_set(&(context->tx.busy), 0); + err("%s: error submitting urb (%d)", __FUNCTION__, retval); + } else { + /* Wait for tranmission to complete (or abort) */ + UNLOCK_CONTEXT; + wait_for_completion(&context->tx.finished); + LOCK_CONTEXT; + + retval = context->tx.status; + if (retval != SUCCESS) + err("%s: packet tx failed (%d)", __FUNCTION__, retval); + } + + return retval; +} + +/** + * Writes data to the VFD. The Sasem VFD is 2x16 characters + * and requires data in 9 consecutive USB interrupt packets, + * each packet carrying 8 bytes. + */ +static ssize_t vfd_write(struct file *file, const char *buf, + size_t n_bytes, loff_t *pos) +{ + int i; + int retval = SUCCESS; + struct sasem_context *context; + + context = (struct sasem_context *) file->private_data; + if (!context) { + err("%s: no context for device", __FUNCTION__); + return -ENODEV; + } + + LOCK_CONTEXT; + + if (!context->dev_present) { + err("%s: no Sasem device present", __FUNCTION__); + retval = -ENODEV; + goto exit; + } + + if (n_bytes <= 0 || n_bytes > 32) { + err("%s: invalid payload size", __FUNCTION__); + retval = -EINVAL; + goto exit; + } + + copy_from_user(context->tx.data_buf, buf, n_bytes); + + /* Pad with spaces */ + for (i = n_bytes; i < 32; ++i) + context->tx.data_buf [i] = ' '; + + /* Nine 8 byte packets to be sent */ + /* NOTE: "\x07\x01\0\0\0\0\0\0" or "\x0c\0\0\0\0\0\0\0" + * will clear the VFD */ + for (i = 0; i < 9; i++) { + switch (i) { + case 0: + memcpy(context->usb_tx_buf, "\x07\0\0\0\0\0\0\0", 8); + context->usb_tx_buf[1] = (context->vfd_contrast) ? + (0x2B - (context->vfd_contrast - 1) / 250):0x2B; + break; + case 1: + memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8); + break; + case 2: + memcpy(context->usb_tx_buf, "\x0b\x01\0\0\0\0\0\0", 8); + break; + case 3: + memcpy(context->usb_tx_buf, context->tx.data_buf, 8); + break; + case 4: + memcpy(context->usb_tx_buf, + context->tx.data_buf + 8, 8); + break; + case 5: + memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8); + break; + case 6: + memcpy(context->usb_tx_buf, "\x0b\x02\0\0\0\0\0\0", 8); + break; + case 7: + memcpy(context->usb_tx_buf, + context->tx.data_buf + 16, 8); + break; + case 8: + memcpy(context->usb_tx_buf, + context->tx.data_buf + 24, 8); + break; + } + retval = send_packet(context); + if (retval != SUCCESS) { + + err("%s: send packet failed for packet #%d", + __FUNCTION__, i); + goto exit; + } + } +exit: + + UNLOCK_CONTEXT; + + return (retval == SUCCESS) ? n_bytes : retval; +} + +/** + * Callback function for USB core API: transmit data + */ +#if defined(KERNEL_2_5) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void usb_tx_callback(struct urb *urb, struct pt_regs *regs) +#else +static void usb_tx_callback(struct urb *urb) +#endif +{ + struct sasem_context *context; + + if (!urb) + return; + context = (struct sasem_context *) urb->context; + if (!context) + return; + + context->tx.status = urb->status; + + /* notify waiters that write has finished */ + atomic_set(&context->tx.busy, 0); + complete(&context->tx.finished); + + return; +} + +/** + * Called by lirc_dev when the application opens /dev/lirc + */ +static int ir_open(void *data) +{ + int retval = SUCCESS; + struct sasem_context *context; + + /* prevent races with disconnect */ + down(&disconnect_sem); + + context = (struct sasem_context *) data; + + LOCK_CONTEXT; + + if (context->ir_isopen) { + err("%s: IR port is already open", __FUNCTION__); + retval = -EBUSY; + goto exit; + } + + usb_fill_int_urb(context->rx_urb, context->dev, + usb_rcvintpipe(context->dev, + context->rx_endpoint->bEndpointAddress), + context->usb_rx_buf, sizeof(context->usb_rx_buf), + usb_rx_callback, context, context->rx_endpoint->bInterval); + +#ifdef KERNEL_2_5 + retval = usb_submit_urb(context->rx_urb, GFP_KERNEL); +#else + retval = usb_submit_urb(context->rx_urb); +#endif + + if (retval) + err("%s: usb_submit_urb failed for ir_open (%d)", + __FUNCTION__, retval); + else { + MOD_INC_USE_COUNT; + context->ir_isopen = TRUE; + info("IR port opened"); + } + +exit: + UNLOCK_CONTEXT; + + up(&disconnect_sem); + return SUCCESS; +} + +/** + * Called by lirc_dev when the application closes /dev/lirc + */ +static void ir_close(void *data) +{ + struct sasem_context *context; + + context = (struct sasem_context *)data; + if (!context) { + err("%s: no context for device", __FUNCTION__); + return; + } + + LOCK_CONTEXT; + + usb_kill_urb(context->rx_urb); + context->ir_isopen = FALSE; + MOD_DEC_USE_COUNT; + info("IR port closed"); + + if (!context->dev_present) { + + /* + * Device disconnected while IR port was + * still open. Plugin was not deregistered + * at disconnect time, so do it now. + */ + deregister_from_lirc(context); + + if (!context->vfd_isopen) { + + UNLOCK_CONTEXT; + delete_context(context); + return; + } + /* If VFD port is open, context will be deleted by vfd_close */ + } + + UNLOCK_CONTEXT; + return; +} + +/** + * Process the incoming packet + */ +static inline void incoming_packet(struct sasem_context *context, + struct urb *urb) +{ + int len = urb->actual_length; + unsigned char *buf = urb->transfer_buffer; + long ms; + struct timeval tv; + + if (len != 8) { + warn("%s: invalid incoming packet size (%d)", + __FUNCTION__, len); + return; + } + +#ifdef DEBUG + int i; + for (i = 0; i < 8; ++i) + printk(KERN_INFO "%02x ", buf [i]); + printk(KERN_INFO "\n"); +#endif + + /* Lirc could deal with the repeat code, but we really need to block it + * if it arrives too late. Otherwise we could repeat the wrong code. */ + + /* get the time since the last button press */ + do_gettimeofday(&tv); + ms = (tv.tv_sec - context->presstime.tv_sec) * 1000 + + (tv.tv_usec - context->presstime.tv_usec) / 1000; + + if (memcmp(buf, "\x08\0\0\0\0\0\0\0", 8) == 0) { + /* the repeat code is being sent, so we copy + * the old code to LIRC */ + + /* NOTE: Only if the last code was less than 250ms ago + * - no one should be able to push another (undetected) button + * in that time and then get a false repeat of the previous + * press but it is long enough for a genuine repeat */ + if ((ms < 250) && (context->codesaved != 0)) { + memcpy(buf, &context->lastcode, 8); + context->presstime.tv_sec = tv.tv_sec; + context->presstime.tv_usec = tv.tv_usec; + } + } else { + /* save the current valid code for repeats */ + memcpy(&context->lastcode, buf, 8); + /* set flag to signal a valid code was save; + * just for safety reasons */ + context->codesaved = 1; + context->presstime.tv_sec = tv.tv_sec; + context->presstime.tv_usec = tv.tv_usec; + } + + lirc_buffer_write_1(context->plugin->rbuf, buf); + wake_up(&context->plugin->rbuf->wait_poll); +} + +/** + * Callback function for USB core API: receive data + */ +#if defined(KERNEL_2_5) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void usb_rx_callback(struct urb *urb, struct pt_regs *regs) +#else +static void usb_rx_callback(struct urb *urb) +#endif +{ + struct sasem_context *context; + + if (!urb) + return; + context = (struct sasem_context *) urb->context; + if (!context) + return; + + switch (urb->status) { + + case -ENOENT: /* usbcore unlink successful! */ + return; + + case SUCCESS: + if (context->ir_isopen) + incoming_packet(context, urb); + break; + + default: + warn("%s: status (%d): ignored", + __FUNCTION__, urb->status); + break; + } + +#ifdef KERNEL_2_5 + usb_submit_urb(context->rx_urb, GFP_ATOMIC); +#endif + return; +} + + + +/** + * Callback function for USB core API: Probe + */ +#ifdef KERNEL_2_5 +static int sasem_probe(struct usb_interface *interface, + const struct usb_device_id *id) +#else +static void *sasem_probe(struct usb_device *dev, unsigned int intf, + const struct usb_device_id *id) +#endif +{ +#ifdef KERNEL_2_5 + struct usb_device *dev = NULL; + struct usb_host_interface *iface_desc = NULL; +#else + struct usb_interface *interface = NULL; + struct usb_interface_descriptor *iface_desc = NULL; + char name [10]; + int subminor = 0; +#endif + struct usb_endpoint_descriptor *rx_endpoint = NULL; + struct usb_endpoint_descriptor *tx_endpoint = NULL; + struct urb *rx_urb = NULL; + struct urb *tx_urb = NULL; + struct lirc_plugin *plugin = NULL; + struct lirc_buffer *rbuf = NULL; + int lirc_minor = 0; + int num_endpoints; + int retval = SUCCESS; + int vfd_ep_found; + int ir_ep_found; + int alloc_status; + struct sasem_context *context = NULL; + int i; + + info("%s: found Sasem device", __FUNCTION__); + +#if !defined(KERNEL_2_5) + for (subminor = 0; subminor < MAX_DEVICES; ++subminor) { + if (minor_table [subminor] == NULL) + break; + } + if (subminor == MAX_DEVICES) { + err("%s: allowed number of devices already present", + __FUNCTION__); + retval = -ENOMEM; + goto exit; + } +#endif + +#ifdef KERNEL_2_5 + dev = usb_get_dev(interface_to_usbdev(interface)); + iface_desc = interface->cur_altsetting; + num_endpoints = iface_desc->desc.bNumEndpoints; +#else + interface = &dev->actconfig->interface [intf]; + iface_desc = &interface->altsetting [interface->act_altsetting]; + num_endpoints = iface_desc->bNumEndpoints; +#endif + + /* + * Scan the endpoint list and set: + * first input endpoint = IR endpoint + * first output endpoint = VFD endpoint + */ + + ir_ep_found = FALSE; + vfd_ep_found = FALSE; + + for (i = 0; i < num_endpoints && !(ir_ep_found && vfd_ep_found); ++i) { + + struct usb_endpoint_descriptor *ep; + int ep_dir; + int ep_type; +#ifdef KERNEL_2_5 + ep = &iface_desc->endpoint [i].desc; +#else + ep = &iface_desc->endpoint [i]; +#endif + ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; + ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + + if (!ir_ep_found && + ep_dir == USB_DIR_IN && + ep_type == USB_ENDPOINT_XFER_INT) { + + rx_endpoint = ep; + ir_ep_found = TRUE; + if (debug) + info("%s: found IR endpoint", __FUNCTION__); + + } else if (!vfd_ep_found && + ep_dir == USB_DIR_OUT && + ep_type == USB_ENDPOINT_XFER_INT) { + + tx_endpoint = ep; + vfd_ep_found = TRUE; + if (debug) + info("%s: found VFD endpoint", __FUNCTION__); + } + } + + /* Input endpoint is mandatory */ + if (!ir_ep_found) { + + err("%s: no valid input (IR) endpoint found.", __FUNCTION__); + retval = -ENODEV; + goto exit; + } + + /* Warning if no VFD endpoint */ + if (!vfd_ep_found) + info("%s: no valid output (VFD) endpoint found.", __FUNCTION__); + + + /* Allocate memory */ + alloc_status = SUCCESS; + + context = kmalloc(sizeof(struct sasem_context), GFP_KERNEL); + if (!context) { + err("%s: kmalloc failed for context", __FUNCTION__); + alloc_status = 1; + goto alloc_status_switch; + } + plugin = kmalloc(sizeof(struct lirc_plugin), GFP_KERNEL); + if (!plugin) { + err("%s: kmalloc failed for lirc_plugin", __FUNCTION__); + alloc_status = 2; + goto alloc_status_switch; + } + rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); + if (!rbuf) { + err("%s: kmalloc failed for lirc_buffer", __FUNCTION__); + alloc_status = 3; + goto alloc_status_switch; + } + if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) { + err("%s: lirc_buffer_init failed", __FUNCTION__); + alloc_status = 4; + goto alloc_status_switch; + } +#ifdef KERNEL_2_5 + rx_urb = usb_alloc_urb(0, GFP_KERNEL); +#else + rx_urb = usb_alloc_urb(0); +#endif + if (!rx_urb) { + err("%s: usb_alloc_urb failed for IR urb", __FUNCTION__); + alloc_status = 5; + goto alloc_status_switch; + } + if (vfd_ep_found) { +#ifdef KERNEL_2_5 + tx_urb = usb_alloc_urb(0, GFP_KERNEL); +#else + tx_urb = usb_alloc_urb(0); +#endif + if (!tx_urb) { + err("%s: usb_alloc_urb failed for VFD urb", + __FUNCTION__); + alloc_status = 6; + goto alloc_status_switch; + } + } + + /* clear all members of sasem_context and lirc_plugin */ + memset(context, 0, sizeof(struct sasem_context)); + init_MUTEX(&context->sem); + + memset(plugin, 0, sizeof(struct lirc_plugin)); + + strcpy(plugin->name, MOD_NAME); + plugin->minor = -1; + plugin->code_length = 64; + plugin->sample_rate = 0; + plugin->features = LIRC_CAN_REC_LIRCCODE; + plugin->data = context; + plugin->rbuf = rbuf; + plugin->set_use_inc = ir_open; + plugin->set_use_dec = ir_close; +#ifdef LIRC_HAVE_SYSFS + plugin->dev = &dev->dev; +#endif + plugin->owner = THIS_MODULE; + + LOCK_CONTEXT; + + lirc_minor = lirc_register_plugin(plugin); + if (lirc_minor < 0) { + err("%s: lirc_register_plugin failed", __FUNCTION__); + alloc_status = 7; + UNLOCK_CONTEXT; + } else + info("%s: Registered Sasem plugin (minor:%d)", + __FUNCTION__, lirc_minor); + +alloc_status_switch: + + switch (alloc_status) { + + case 7: + if (vfd_ep_found) + usb_free_urb(tx_urb); + case 6: + usb_free_urb(rx_urb); + case 5: + lirc_buffer_free(rbuf); + case 4: + kfree(rbuf); + case 3: + kfree(plugin); + case 2: + kfree(context); + context = NULL; + case 1: + retval = -ENOMEM; + goto exit; + } + + /* Needed while unregistering! */ + plugin->minor = lirc_minor; + + context->dev = dev; + context->dev_present = TRUE; + context->rx_endpoint = rx_endpoint; + context->rx_urb = rx_urb; + if (vfd_ep_found) { + context->tx_endpoint = tx_endpoint; + context->tx_urb = tx_urb; + context->vfd_contrast = 1000; /* range 0 - 1000 */ + } + context->plugin = plugin; + +#ifdef KERNEL_2_5 + usb_set_intfdata(interface, context); +#else + minor_table [subminor] = context; + context->subminor = subminor; +#endif + + if (vfd_ep_found) { + + if (debug) + info("Registering VFD with devfs"); +#ifdef KERNEL_2_5 + if (usb_register_dev(interface, &sasem_class)) + /* Not a fatal error, so ignore */ + info("%s: could not get a minor number for VFD", + __FUNCTION__); +#else + sprintf(name, DEVFS_NAME, subminor); + context->devfs = devfs_register(usb_devfs_handle, name, + DEVFS_FL_DEFAULT, + USB_MAJOR, VFD_MINOR_BASE + subminor, + DEVFS_MODE, &vfd_fops, NULL); + if (!context->devfs) + /* not a fatal error so ignore */ + info("%s: devfs register failed for VFD", + __FUNCTION__); +#endif + } + + info("%s: Sasem device on usb<%d:%d> initialized", + __FUNCTION__, dev->bus->busnum, dev->devnum); + + UNLOCK_CONTEXT; +exit: +#ifdef KERNEL_2_5 + return retval; +#else + return (retval == SUCCESS) ? context : NULL; +#endif +} + +/** + * Callback function for USB core API: disonnect + */ +#ifdef KERNEL_2_5 +static void sasem_disconnect(struct usb_interface *interface) +#else +static void sasem_disconnect(struct usb_device *dev, void *data) +#endif +{ + struct sasem_context *context; + + /* prevent races with ir_open()/vfd_open() */ + down(&disconnect_sem); + +#ifdef KERNEL_2_5 + context = usb_get_intfdata(interface); +#else + context = (struct sasem_context *)data; +#endif + LOCK_CONTEXT; + + info("%s: Sasem device disconnected", __FUNCTION__); + +#ifdef KERNEL_2_5 + usb_set_intfdata(interface, NULL); +#else + minor_table [context->subminor] = NULL; +#endif + context->dev_present = FALSE; + + /* Stop reception */ + usb_kill_urb(context->rx_urb); + + /* Abort ongoing write */ + if (atomic_read(&context->tx.busy)) { + + usb_kill_urb(context->tx_urb); + wait_for_completion(&context->tx.finished); + } + + /* De-register from lirc_dev if IR port is not open */ + if (!context->ir_isopen) + deregister_from_lirc(context); + +#ifdef KERNEL_2_5 + usb_deregister_dev(interface, &sasem_class); +#else + if (context->devfs) + devfs_unregister(context->devfs); +#endif + + UNLOCK_CONTEXT; + + if (!context->ir_isopen && !context->vfd_isopen) + delete_context(context); + + up(&disconnect_sem); +} + +static int __init sasem_init(void) +{ + int rc; + + info(MOD_DESC ", v" MOD_VERSION); + info(MOD_AUTHOR); + + rc = usb_register(&sasem_driver); + if (rc < 0) { + err("%s: usb register failed (%d)", __FUNCTION__, rc); + return -ENODEV; + } + return SUCCESS; +} + +static void __exit sasem_exit(void) +{ + usb_deregister(&sasem_driver); + info("module removed. Goodbye!"); +} + + +module_init(sasem_init); +module_exit(sasem_exit); + +#if !defined(KERNEL_2_5) +EXPORT_NO_SYMBOLS; +#endif --- linux-2.6.27.orig/ubuntu/lirc/lirc_pvr150/lirc_pvr150.c +++ linux-2.6.27/ubuntu/lirc/lirc_pvr150/lirc_pvr150.c @@ -0,0 +1,1481 @@ +/* $Id: $ */ + +/* + * i2c IR lirc plugin for Hauppauge PVR 150 card + * + * Copyright (c) 2000 Gerd Knorr + * modified for PixelView (BT878P+W/FM) by + * Michal Kochanowicz + * Christoph Bartelmus + * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by + * Ulrich Mueller + * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by + * Stefan Jahn + * modified for inclusion into kernel sources by + * Jerome Brock + * modified for Leadtek Winfast PVR2000 by + * Thomas Reitmayr (treitmayr@yahoo.com) + * modified for Hauppauge PVR-150 IR TX device by + * Mark Weaver + * + * parts are cut&pasted from the lirc_pvr150.c driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "kcompat.h" +#include "lirc_dev/lirc_dev.h" +#include "lirc.h" + +/* We need to be able to reset the crappy IR chip by talking to the ivtv driver */ +struct ivtv; +void ivtv_reset_ir_gpio(struct ivtv *itv); + +struct IR +{ + struct lirc_plugin l; + + /* Device info */ + struct semaphore lock; + int open; + + /* RX device */ + struct i2c_client c_rx; + + /* RX device buffer & lock */ + struct lirc_buffer buf; + struct semaphore buf_sem; + + /* RX polling thread data */ + struct completion *t_notify; + struct completion *t_notify2; + int shutdown; + int tpid; + + /* RX read data */ + unsigned char b[3]; + + /* TX device */ + struct i2c_client c_tx; + int need_boot; + + /* # devices, for shutdown */ + int devs; +}; + +/* Minor -> data mapping */ +static struct IR *ir_devices[MAX_IRCTL_DEVICES]; + +/* Block size for haup PVR-150 IR transmitter */ +#define TX_BLOCK_SIZE 99 + +/* Hauppuage IR transmitter data */ +typedef struct TX_DATA_s +{ + /* Boot block */ + unsigned char *boot_data; + + /* Start of binary data block */ + unsigned char *datap; + + /* End of binary data block */ + unsigned char *endp; + + /* Number of installed codesets */ + unsigned int num_code_sets; + + /* Pointers to codesets */ + unsigned char **code_sets; + + /* Global fixed data template */ + int fixed[TX_BLOCK_SIZE]; +} TX_DATA; + +static TX_DATA *tx_data; +struct semaphore tx_data_lock; + +/* ----------------------------------------------------------------------- */ + +#define DEVICE_NAME "lirc_pvr150" + +/* ----------------------------------------------------------------------- */ +/* insmod parameters */ + +static int debug = 0; /* debug output */ +static int disable_rx = 0; /* disable RX device */ +static int disable_tx = 0; /* disable TX device */ +static int minor = -1; /* minor number */ + +#define dprintk(fmt, args...) \ + do{ \ + if(debug) printk(KERN_DEBUG DEVICE_NAME ": " fmt, \ + ## args); \ + }while(0) + +/* ----------------------------------------------------------------------- */ + +static int add_to_buf(struct IR *ir) +{ + __u16 code; + unsigned char codes[2]; + unsigned char keybuf[6]; + int got_data = 0; + int ret; + int failures = 0; + unsigned char sendbuf[1] = { 0 }; + + if (lirc_buffer_full(&ir->buf)) { + dprintk("buffer overflow\n"); + return -EOVERFLOW; + } + + /* service the device as long as it is returning + * data and we have space + */ + do + { + /* Lock i2c bus for the duration. RX/TX chips interfere so + this is worth it + */ + down(&ir->lock); + + /* Send random "poll command" (?) Windows driver does this + and it is a good point to detect chip failure. + */ + ret = i2c_master_send(&ir->c_rx, sendbuf, 1); + if (ret != 1) + { + printk(KERN_ERR + "lirc_pvr150: i2c_master_send failed with %d\n", + ret); + if (failures >= 3) { + up(&ir->lock); + printk(KERN_ERR "lirc_pvr150: unable to read " + "from the IR chip after 3 " + "resets, giving up\n"); + return ret; + } + + /* Looks like the chip crashed, reset it */ + printk(KERN_ERR "lirc_pvr150: polling the IR receiver " + "chip failed, trying reset\n"); + + ivtv_reset_ir_gpio(i2c_get_adapdata(ir->c_rx.adapter)); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((100 * HZ + 999) / 1000); + ir->need_boot = 1; + + ++failures; + up(&ir->lock); + continue; + } + + ret = i2c_master_recv(&ir->c_rx, keybuf, sizeof(keybuf)); + up(&ir->lock); + if (ret != sizeof(keybuf)) + { + printk(KERN_ERR + "lirc_pvr150: i2c_master_recv failed with %d" + " -- keeping last read buffer\n", ret); + } + else + { + ir->b[0] = keybuf[3]; + ir->b[1] = keybuf[4]; + ir->b[2] = keybuf[5]; + dprintk("key (0x%02x/0x%02x)\n", ir->b[0], ir->b[1]); + } + + /* key pressed ? */ + if ((ir->b[0] & 0x80) == 0) + return got_data ? 0 : -ENODATA; + + /* look what we have */ + code = (((__u16)ir->b[0]&0x7f)<<6) | (ir->b[1]>>2); + + codes[0] = (code >> 8) & 0xff; + codes[1] = code & 0xff; + + /* return it */ + lirc_buffer_write_1( &ir->buf, codes ); + ++got_data; + } while (!lirc_buffer_full(&ir->buf)); + return 0; +} + +/* Main function of the polling thread -- from lirc_dev. + * We don't fit the LIRC model at all anymore. This is horrible, but + * basically we have a single RX/TX device with a nasty failure mode + * that needs to be accounted for across the pair. lirc lets us provide + * fops, but prevents us from using the internal polling, etc. if we do + * so. Hence the replication. Might be neater to extend the LIRC model + * to account for this but I'd think it's a very special case of seriously + * messed up hardware. + */ +static int lirc_thread(void *arg) +{ + struct IR *ir = arg; + + /* This thread doesn't need any user-level access, + * so get rid of all our resources + */ + daemonize("lirc_pvr150"); + + if (ir->t_notify != NULL) { + complete(ir->t_notify); + } + + dprintk("poll thread started\n"); + + do { + if (ir->open) { + set_current_state(TASK_INTERRUPTIBLE); + + /* This is ~113*2 + 24 + jitter (2*repeat gap + + code length). We use this interval as the chip + resets every time you poll it (bad!). This is + therefore just sufficient to catch all of the + button presses. It makes the remote much more + responsive. You can see the difference by + running irw and holding down a button. With + 100ms, the old polling interval, you'll notice + breaks in the repeat sequence corresponding to + lost keypresses. + */ + schedule_timeout((260 * HZ) / 1000); + if (ir->shutdown) { + break; + } + if (!add_to_buf(ir)) { + wake_up_interruptible(&ir->buf.wait_poll); + } + } else { + /* if device not opened so we can sleep half a second */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/2); + } + } while (!ir->shutdown); + + if (ir->t_notify2 != NULL) { + wait_for_completion(ir->t_notify2); + } + + ir->tpid = -1; + if (ir->t_notify != NULL) { + complete(ir->t_notify); + } + + dprintk("poll thread ended\n"); + return 0; +} + +static int set_use_inc(void* data) +{ + struct IR *ir = data; + + if (ir->l.owner == NULL || try_module_get(ir->l.owner) == 0) { + return -ENODEV; + } + + /* lock bttv in memory while /dev/lirc is in use */ + /* this is completely broken code. lirc_unregister_plugin() + must be possible even when the device is open */ + if (ir->c_rx.addr) i2c_use_client(&ir->c_rx); + if (ir->c_tx.addr) i2c_use_client(&ir->c_tx); + MOD_INC_USE_COUNT; + + return 0; +} + +static void set_use_dec(void* data) +{ + struct IR *ir = data; + + if (ir->c_rx.addr) i2c_release_client(&ir->c_rx); + if (ir->c_tx.addr) i2c_release_client(&ir->c_tx); + MOD_DEC_USE_COUNT; + if (ir->l.owner != NULL) + module_put(ir->l.owner); +} + +/* safe read of a uint32 (always network byte order) */ +static __inline int read_uint32(unsigned char **data, + unsigned char *endp, unsigned int *val) +{ + if (*data + 4 > endp) + return 0; + *val = ((*data)[0] << 24) | ((*data)[1] << 16) | + ((*data)[2] << 8) | (*data)[3]; + *data += 4; + return 1; +} + +/* safe read of a uint8 */ +static __inline int read_uint8(unsigned char **data, + unsigned char *endp, unsigned char *val) +{ + if (*data + 1 > endp) + return 0; + *val = *((*data)++); + return 1; +} + +/* safe skipping of N bytes */ +static __inline int skip(unsigned char **data, + unsigned char *endp, unsigned int distance) +{ + if (*data + distance > endp) + return 0; + *data += distance; + return 1; +} + +/* decompress key data into the given buffer */ +static int get_key_data(unsigned char *buf, + unsigned int codeset, unsigned int key) +{ + unsigned char *data, *endp, *diffs, *key_block; + unsigned char keys, ndiffs, id; + unsigned int base, lim, pos, i; + + /* Binary search for the codeset */ + for (base = 0, lim = tx_data->num_code_sets; lim; lim >>= 1) { + pos = base + (lim >> 1); + data = tx_data->code_sets[pos]; + + if (!read_uint32(&data, tx_data->endp, &i)) + goto corrupt; + + if (i == codeset) + break; + else if (codeset > i) { + base = pos + 1; + --lim; + } + } + /* Not found? */ + if (!lim) + return -EPROTO; + + /* Set end of data block */ + endp = pos < tx_data->num_code_sets - 1 ? + tx_data->code_sets[pos + 1] : tx_data->endp; + + /* Read the block header */ + if (!read_uint8(&data, endp, &keys) || + !read_uint8(&data, endp, &ndiffs) || + ndiffs > TX_BLOCK_SIZE || keys == 0) + goto corrupt; + + /* Save diffs & skip */ + diffs = data; + if (!skip(&data, endp, ndiffs)) + goto corrupt; + + /* Read the id of the first key */ + if (!read_uint8(&data, endp, &id)) + goto corrupt; + + /* Unpack the first key's data */ + for (i = 0; i < TX_BLOCK_SIZE; ++i) + { + if (tx_data->fixed[i] == -1) + { + if (!read_uint8(&data, endp, &buf[i])) + goto corrupt; + } + else + { + buf[i] = (unsigned char)tx_data->fixed[i]; + } + } + + /* Early out key found/not found */ + if (key == id) + return 0; + if (keys == 1) + return -EPROTO; + + /* Sanity check */ + key_block = data; + if (!skip(&data, endp, (keys - 1) * (ndiffs + 1))) + goto corrupt; + + /* Binary search for the key */ + for (base = 0, lim = keys - 1; lim; lim >>= 1) { + /* Seek to block */ + unsigned char *key_data; + pos = base + (lim >> 1); + key_data = key_block + (ndiffs + 1) * pos; + + if (*key_data == key) { + /* skip key id */ + ++key_data; + + /* found, so unpack the diffs */ + for (i = 0; i < ndiffs; ++i) { + unsigned char val; + if (!read_uint8(&key_data, endp, &val) || + diffs[i] >= TX_BLOCK_SIZE) + goto corrupt; + buf[diffs[i]] = val; + } + + return 0; + } else if (key > *key_data) { + base = pos + 1; + --lim; + } + } + /* Key not found */ + return -EPROTO; + +corrupt: + printk(KERN_ERR "lirc_pvr150: firmware is corrupt\n"); + return -EFAULT; +} + +/* send a block of data to the IR TX device of the PVR-150 */ +static int send_data_block(struct IR *ir, unsigned char *data_block) +{ + int i, j, ret; + unsigned char buf[5]; + + for (i = 0; i < TX_BLOCK_SIZE; ) + { + int tosend = TX_BLOCK_SIZE - i; + if (tosend > 4) + tosend = 4; + buf[0] = (unsigned char)(i + 1); + for (j = 0; j < tosend; ++j) + buf[1 + j] = data_block[i + j]; + dprintk("%02x %02x %02x %02x %02x", + buf[0],buf[1],buf[2],buf[3],buf[4]); + ret = i2c_master_send(&ir->c_tx, buf, tosend + 1); + if (ret != tosend + 1) { + printk(KERN_ERR + "lirc_pvr150: i2c_master_send failed with %d\n", + ret); + return ret < 0 ? ret : -EFAULT; + } + i += tosend; + } + return 0; +} + +/* send boot data to the IR TX device of the PVR-150 */ +static int send_boot_data(struct IR *ir) +{ + int ret; + unsigned char buf[4]; + + /* send the boot block */ + ret = send_data_block(ir, tx_data->boot_data); + if (ret != 0) + return ret; + + /* kick it off? */ + buf[0] = 0x00; + buf[1] = 0x20; + ret = i2c_master_send(&ir->c_tx, buf, 2); + if (ret != 2) { + printk(KERN_ERR + "lirc_pvr150: i2c_master_send failed with %d\n", ret); + return ret < 0 ? ret : -EFAULT; + } + ret = i2c_master_send(&ir->c_tx, buf, 1); + if (ret != 1) { + printk(KERN_ERR + "lirc_pvr150: i2c_master_send failed with %d\n", ret); + return ret < 0 ? ret : -EFAULT; + } + + /* Here comes the firmware version... (hopefully) */ + ret = i2c_master_recv(&ir->c_tx, buf, 4); + if (ret != 4) { + printk(KERN_ERR + "lirc_pvr150: i2c_master_recv failed with %d\n", ret); + return 0; + } + if (buf[0] != 0x80) { + printk(KERN_ERR + "lirc_pvr150: unexpected IR TX response: %02x\n", + buf[0]); + return 0; + } + printk(KERN_INFO + "lirc_pvr150: Hauppauge PVR-150 IR blaster: " + "firmware version %d.%d.%d\n", + buf[1], buf[2], buf[3]); + + return 0; +} + +/* unload "firmware", lock held */ +static void fw_unload_locked(void) +{ + if (tx_data) { + if (tx_data->code_sets) + vfree(tx_data->code_sets); + + if (tx_data->datap) + vfree(tx_data->datap); + + vfree(tx_data); + tx_data = NULL; + dprintk("successfully unloaded PVR-150 IR " + "blaster firmware\n"); + } +} + +/* unload "firmware" for the IR TX device of the PVR-150 */ +static void fw_unload(void) +{ + down(&tx_data_lock); + fw_unload_locked(); + up(&tx_data_lock); +} + +/* load "firmware" for the IR TX device of the PVR-150 */ +static int fw_load(struct IR *ir) +{ + int ret; + unsigned int i; + unsigned char *data, version, num_global_fixed; + const struct firmware *fw_entry = NULL; + + /* Already loaded? */ + down(&tx_data_lock); + if (tx_data) { + ret = 0; + goto out; + } + + /* Request codeset data file */ + ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", &ir->c_tx.dev); + if (ret != 0) { + printk(KERN_ERR + "lirc_pvr150: firmware haup-ir-blaster.bin " + "not available (%d)\n", ret); + ret = ret < 0 ? ret : -EFAULT; + goto out; + } + printk(KERN_INFO + "lirc_pvr150: firmware of size %zd loaded\n", fw_entry->size); + + /* Parse the file */ + tx_data = vmalloc(sizeof(TX_DATA)); + if (tx_data == NULL) { + printk(KERN_ERR + "lirc_pvr150: out of memory\n"); + release_firmware(fw_entry); + ret = -ENOMEM; + goto out; + } + tx_data->code_sets = NULL; + + /* Copy the data so hotplug doesn't get confused and timeout */ + tx_data->datap = vmalloc(fw_entry->size); + if (tx_data->datap == NULL) { + printk(KERN_ERR + "lirc_pvr150: out of memory\n"); + release_firmware(fw_entry); + vfree(tx_data); + ret = -ENOMEM; + goto out; + } + memcpy(tx_data->datap, fw_entry->data, fw_entry->size); + tx_data->endp = tx_data->datap + fw_entry->size; + release_firmware(fw_entry); fw_entry = NULL; + + /* Check version */ + data = tx_data->datap; + if (!read_uint8(&data, tx_data->endp, &version)) + goto corrupt; + if (version != 1) { + printk(KERN_ERR + "lirc_pvr150: unsupported code set file version (%u, " + "expected 1) -- please upgrade to a newer driver", + version); + fw_unload_locked(); + ret = -EFAULT; + goto out; + } + + /* Save boot block for later */ + tx_data->boot_data = data; + if (!skip(&data, tx_data->endp, TX_BLOCK_SIZE)) + goto corrupt; + + if (!read_uint32(&data, tx_data->endp, + &tx_data->num_code_sets)) + goto corrupt; + + printk(KERN_INFO + "lirc_pvr150: %u codesets loaded\n", tx_data->num_code_sets); + + tx_data->code_sets = vmalloc( + tx_data->num_code_sets * sizeof(char *)); + if (tx_data->code_sets == NULL) { + fw_unload_locked(); + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < TX_BLOCK_SIZE; ++i) + tx_data->fixed[i] = -1; + + /* Read global fixed data template */ + if (!read_uint8(&data, tx_data->endp, &num_global_fixed) || + num_global_fixed > TX_BLOCK_SIZE) + goto corrupt; + for (i = 0; i < num_global_fixed; ++i) { + unsigned char pos, val; + if (!read_uint8(&data, tx_data->endp, &pos) || + !read_uint8(&data, tx_data->endp, &val) || + pos >= TX_BLOCK_SIZE) { + goto corrupt; + } + tx_data->fixed[pos] = (int)val; + } + + /* Filch out the position of each code set */ + for (i = 0; i < tx_data->num_code_sets; ++i) { + unsigned int id; + unsigned char keys; + unsigned char ndiffs; + + /* Save the codeset position */ + tx_data->code_sets[i] = data; + + /* Read header */ + if (!read_uint32(&data, tx_data->endp, &id) || + !read_uint8(&data, tx_data->endp, &keys) || + !read_uint8(&data, tx_data->endp, &ndiffs) || + ndiffs > TX_BLOCK_SIZE || keys == 0) + goto corrupt; + + /* skip diff positions */ + if (!skip(&data, tx_data->endp, ndiffs)) + goto corrupt; + + /* After the diffs we have the first key id + data - + global fixed */ + if (!skip(&data, tx_data->endp, + 1 + TX_BLOCK_SIZE - num_global_fixed)) + goto corrupt; + + /* Then we have keys-1 blocks of key id+diffs */ + if (!skip(&data, tx_data->endp, + (ndiffs + 1) * (keys - 1))) + goto corrupt; + } + ret = 0; + goto out; + +corrupt: + printk(KERN_ERR "lirc_pvr150: firmware is corrupt\n"); + fw_unload_locked(); + ret = -EFAULT; + +out: + up(&tx_data_lock); + return ret; +} + +/* initialise the IR TX device of the PVR-150 */ +static int tx_init(struct IR *ir) +{ + int ret; + + /* Load 'firmware' */ + ret = fw_load(ir); + if (ret != 0) + return ret; + + /* Send boot block */ + ret = send_boot_data(ir); + if (ret != 0) + return ret; + ir->need_boot = 0; + + /* Looks good */ + return 0; +} + +/* do nothing stub to make LIRC happy */ +static loff_t lseek(struct file *filep,loff_t offset,int orig) +{ + return(-ESPIPE); +} + +/* copied from lirc_dev */ +static ssize_t read(struct file *filep,char *outbuf,size_t n,loff_t *ppos) +{ + struct IR *ir = (struct IR *)filep->private_data; + unsigned char buf[ir->buf.chunk_size]; + int ret=0, written=0; + DECLARE_WAITQUEUE(wait, current); + + dprintk("read called\n"); + if (ir->c_rx.addr == 0) + return -ENODEV; + + if (down_interruptible(&ir->buf_sem)) + return -ERESTARTSYS; + + if (n % ir->buf.chunk_size) { + dprintk("read result = -EINVAL\n"); + up(&ir->buf_sem); + return -EINVAL; + } + + /* we add ourselves to the task queue before buffer check + * to avoid losing scan code (in case when queue is awaken somewhere + * beetwen while condition checking and scheduling) + */ + add_wait_queue(&ir->buf.wait_poll, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + /* while we did't provide 'length' bytes, device is opened in blocking + * mode and 'copy_to_user' is happy, wait for data. + */ + while (written < n && ret == 0) { + if (lirc_buffer_empty(&ir->buf)) { + /* According to the read(2) man page, 'written' can be + * returned as less than 'n', instead of blocking + * again, returning -EWOULDBLOCK, or returning + * -ERESTARTSYS */ + if (written) break; + if (filep->f_flags & O_NONBLOCK) { + ret = -EWOULDBLOCK; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + } else { + lirc_buffer_read_1(&ir->buf, buf); + ret = copy_to_user((void *)outbuf+written, buf, + ir->buf.chunk_size); + written += ir->buf.chunk_size; + } + } + + remove_wait_queue(&ir->buf.wait_poll, &wait); + set_current_state(TASK_RUNNING); + up(&ir->buf_sem); + + dprintk("read result = %s (%d)\n", + ret ? "-EFAULT" : "OK", ret); + + return ret ? ret : written; +} + +/* send a keypress to the IR TX device of the PVR-150 */ +static int send_code(struct IR *ir, unsigned int code, unsigned int key) +{ + unsigned char data_block[TX_BLOCK_SIZE]; + unsigned char buf[2]; + int i, ret; + + /* Get data for the codeset/key */ + ret = get_key_data(data_block, code, key); + + if (ret == -EPROTO) { + printk(KERN_ERR + "lirc_pvr150: failed to get data for code %u, " + "key %u -- check lircd.conf entries\n", + code, key); + return ret; + } else if (ret != 0) + return ret; + + /* Send the data block */ + ret = send_data_block(ir, data_block); + if (ret != 0) + return ret; + + /* Send data block length? */ + buf[0] = 0x00; + buf[1] = 0x40; + ret = i2c_master_send(&ir->c_tx, buf, 2); + if (ret != 2) { + printk(KERN_ERR + "lirc_pvr150: i2c_master_send failed with %d\n", ret); + return ret < 0 ? ret : -EFAULT; + } + ret = i2c_master_send(&ir->c_tx, buf, 1); + if (ret != 1) { + printk(KERN_ERR + "lirc_pvr150: i2c_master_send failed with %d\n", ret); + return ret < 0 ? ret : -EFAULT; + } + + /* Send finished download? */ + ret = i2c_master_recv(&ir->c_tx, buf, 1); + if (ret != 1) { + printk(KERN_ERR + "lirc_pvr150: i2c_master_recv failed with %d\n", ret); + return ret < 0 ? ret : -EFAULT; + } + if (buf[0] != 0xA0) { + printk(KERN_ERR + "lirc_pvr150: unexpected IR TX response #1: %02x\n", + buf[0]); + return ret < 0 ? ret : -EFAULT; + } + + /* Send prepare command? */ + buf[0] = 0x00; + buf[1] = 0x80; + ret = i2c_master_send(&ir->c_tx, buf, 2); + if (ret != 2) { + printk(KERN_ERR + "lirc_pvr150: i2c_master_send failed with %d\n", ret); + return ret < 0 ? ret : -EFAULT; + } + + /* This bit NAKs until the device is ready, so we retry it + sleeping a bit each time. This seems to be what the windows + driver does, approximately. + Try for up to 1s. + */ + for (i = 0; i < 20; ++i) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((50 * HZ + 999) / 1000); + ret = i2c_master_send(&ir->c_tx, buf, 1); + if (ret == 1) + break; + dprintk("NAK expected: i2c_master_send " + "failed with %d (try %d)\n", ret, i+1); + } + if (ret != 1) { + printk(KERN_ERR + "lirc_pvr150: IR TX chip never got ready: last " + "i2c_master_send failed with %d\n", ret); + return ret < 0 ? ret : -EFAULT; + } + + /* Seems to be an 'ok' response */ + i = i2c_master_recv(&ir->c_tx, buf, 1); + if (i != 1) { + printk(KERN_ERR + "lirc_pvr150: i2c_master_recv failed with %d\n", ret); + return ret < 0 ? ret : -EFAULT; + } + if (buf[0] != 0x80) { + printk(KERN_ERR + "lirc_pvr150: unexpected IR TX response #2: %02x\n", + buf[0]); + return -EFAULT; + } + + /* Oh good, it worked */ + dprintk("sent code %u, key %u\n", code, key); + return 0; +} + +/* Write a code to the device. We take in a 32-bit number (a lirc_t) and then + decode this to a codeset/key index. The key data is then decompressed and + sent to the device. We have a spin lock as per i2c documentation to prevent + multiple concurrent sends which would probably cause the device to explode. + */ +static ssize_t write(struct file *filep,const char *buf,size_t n, + loff_t *ppos) +{ + struct IR *ir = (struct IR *)filep->private_data; + size_t i; + int failures = 0; + + if (ir->c_tx.addr == 0) + return -ENODEV; + + /* Validate user parameters */ + if (n % sizeof(lirc_t)) + return(-EINVAL); + + /* Lock i2c bus for the duration */ + down(&ir->lock); + + /* Send each keypress */ + for (i = 0; i < n; ) + { + int ret = 0; + lirc_t command; + + if (copy_from_user(&command, buf + i, sizeof(command))) { + up(&ir->lock); + return -EFAULT; + } + + /* Send boot data first if required */ + if (ir->need_boot == 1) + { + ret = send_boot_data(ir); + if (ret == 0) + ir->need_boot = 0; + } + + /* Send the code */ + if (ret == 0) { + ret = send_code(ir, (unsigned)command >> 16, + (unsigned)command & 0xFFFF); + if (ret == -EPROTO) { + up(&ir->lock); + return ret; + } + } + + /* Hmm, a failure. If we've had a few then give up, otherwise + try a reset + */ + if (ret != 0) { + /* Looks like the chip crashed, reset it */ + printk(KERN_ERR "lirc_pvr150: sending to the IR " + "transmitter chip failed, trying " + "reset\n"); + + if (failures >= 3) { + printk(KERN_ERR "lirc_pvr150: unable to send " + "to the IR chip after 3 " + "resets, giving up\n"); + up(&ir->lock); + return ret; + } + ivtv_reset_ir_gpio(i2c_get_adapdata(ir->c_tx.adapter)); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((100 * HZ + 999) / 1000); + ir->need_boot = 1; + ++failures; + } + else + { + i += sizeof(lirc_t); + } + } + + /* Release i2c bus */ + up(&ir->lock); + + /* All looks good */ + return n; +} + +/* copied from lirc_dev */ +static unsigned int poll(struct file *filep, poll_table * wait) +{ + struct IR *ir = (struct IR *)filep->private_data; + unsigned int ret; + + dprintk("poll called\n"); + if (ir->c_rx.addr == 0) + return -ENODEV; + + down(&ir->buf_sem); + + poll_wait(filep, &ir->buf.wait_poll, wait); + + dprintk("poll result = %s\n", + lirc_buffer_empty(&ir->buf) ? "0" : "POLLIN|POLLRDNORM"); + + ret = lirc_buffer_empty(&ir->buf) ? 0 : (POLLIN|POLLRDNORM); + + up(&ir->buf_sem); + return ret; +} + +static int ioctl(struct inode *node,struct file *filep,unsigned int cmd, + unsigned long arg) +{ + struct IR *ir = (struct IR *)filep->private_data; + int result; + unsigned long mode, features = 0; + + if (ir->c_rx.addr != 0) + features |= LIRC_CAN_REC_LIRCCODE; + if (ir->c_tx.addr != 0) + features |= LIRC_CAN_SEND_PULSE; + + switch(cmd) + { + case LIRC_GET_LENGTH: + result = put_user((unsigned long)13, + (unsigned long *)arg); + break; + case LIRC_GET_FEATURES: + result=put_user(features,(unsigned long *) arg); + if(result) return(result); + break; + case LIRC_GET_REC_MODE: + if(!(features&LIRC_CAN_REC_MASK)) + return -ENOSYS; + + result = put_user(LIRC_REC2MODE + (features&LIRC_CAN_REC_MASK), + (unsigned long*)arg); + break; + case LIRC_SET_REC_MODE: + if(!(features&LIRC_CAN_REC_MASK)) + return -ENOSYS; + + result = get_user(mode, (unsigned long*)arg); + if(!result && !(LIRC_MODE2REC(mode) & features)) { + result = -EINVAL; + } + break; + case LIRC_GET_SEND_MODE: + if(!(features&LIRC_CAN_SEND_MASK)) + return -ENOSYS; + + result=put_user(LIRC_MODE_PULSE,(unsigned long *) arg); + if(result) return(result); + break; + case LIRC_SET_SEND_MODE: + if(!(features&LIRC_CAN_SEND_MASK)) + return -ENOSYS; + + result=get_user(mode,(unsigned long *) arg); + if(result) return(result); + if(mode!=LIRC_MODE_PULSE) return(-EINVAL); + break; + default: + return(-ENOIOCTLCMD); + } + return (0); +} + +/* Open the IR device of the PVR-150. Get hold of our IR structure and + stash it in private_data for the file */ +static int open(struct inode* node,struct file* filep) +{ + struct IR *ir; + int ret; + + /* find our IR struct */ + unsigned minor = MINOR(node->i_rdev); + if (minor >= MAX_IRCTL_DEVICES) { + dprintk("minor %d: open result = -ENODEV\n", + minor); + return -ENODEV; + } + ir = ir_devices[minor]; + + /* increment in use count */ + down(&ir->lock); + ++ir->open; + ret = set_use_inc(ir); + if (ret != 0) { + --ir->open; + up(&ir->lock); + return ret; + } + up(&ir->lock); + + /* stash our IR struct */ + filep->private_data = ir; + + return(0); +} + +/* Close the IR device of the PVR-150 */ +static int close(struct inode* node,struct file* filep) +{ + /* find our IR struct */ + struct IR *ir = (struct IR *)filep->private_data; + if (ir == NULL) { + printk(KERN_ERR + "lirc_pvr150: close: no private_data " + "attached to the file!\n"); + return -ENODEV; + } + + /* decrement in use count */ + down(&ir->lock); + --ir->open; + set_use_dec(ir); + up(&ir->lock); + + return(0); +} + +static struct lirc_plugin lirc_template = { + name: "lirc_pvr150", + set_use_inc: set_use_inc, + set_use_dec: set_use_dec, + owner: THIS_MODULE +}; + +/* ----------------------------------------------------------------------- */ + +static int ir_attach(struct i2c_adapter *adap, int have_rx, int have_tx); +static int ir_detach(struct i2c_client *client); +static int ir_probe(struct i2c_adapter *adap); +static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg); + +static struct i2c_driver driver = { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) + name: "i2c ir driver", + flags: I2C_DF_NOTIFY, +#else + .driver = { + owner: THIS_MODULE, + name: "i2c ir driver", + }, +#endif + id: I2C_DRIVERID_EXP3, /* FIXME */ + attach_adapter: ir_probe, + detach_client: ir_detach, + command: ir_command, +}; + +static struct i2c_client client_template = +{ + name: "unset", + driver: &driver +}; + +static struct file_operations lirc_fops = +{ + llseek: lseek, + read: read, + write: write, + poll: poll, + ioctl: ioctl, + open: open, + release: close +}; + +static int i2c_attach(struct i2c_client *client, struct IR *ir) +{ + int ret; + + i2c_set_clientdata(client, ir); + + ret = i2c_attach_client(client); + if (ret != 0) { + client->addr = 0; + return ret; + } + if (i2c_use_client(client) == NULL) { + i2c_detach_client(client); + client->addr = 0; + return ret; + } + ++ir->devs; + return 0; +} + +static int ir_attach(struct i2c_adapter *adap, int have_rx, int have_tx) +{ + struct IR *ir; + int ret, i; + + printk("lirc_pvr150: chip found with %s\n", + have_rx && have_tx ? "RX and TX" : + have_rx ? "RX only" : "TX only"); + + if (NULL == (ir = kmalloc(sizeof(struct IR),GFP_KERNEL))) + return -ENOMEM; + if (lirc_buffer_init(&ir->buf, 2, BUFLEN/2) != 0) { + kfree(ir); + return -ENOMEM; + } + init_MUTEX(&ir->lock); + init_MUTEX(&ir->buf_sem); + ir->open = 0; + ir->devs = 0; + ir->tpid = 0; + ir->need_boot = 1; + ir->shutdown = 0; + ir->t_notify = ir->t_notify2 = NULL; + for (i = 0; i < sizeof(ir->b); ++i) + ir->b[0] = 0; + + memcpy(&ir->l,&lirc_template,sizeof(struct lirc_plugin)); + ir->l.minor = -1; + + /* initialise RX device */ + client_template.adapter = adap; + memcpy(&ir->c_rx,&client_template,sizeof(struct i2c_client)); + if (have_rx) { + DECLARE_COMPLETION(tn); + + /* I2C attach to device */ + ir->c_rx.addr = 0x71; + strlcpy(ir->c_rx.name, "Hauppauge PVR150 RX", + sizeof(ir->c_rx.name)); + if ( (ret = i2c_attach(&ir->c_rx, ir)) != 0 ) + goto err; + + /* try to fire up polling thread */ + ir->t_notify = &tn; + ir->tpid = kernel_thread(lirc_thread, ir, 0); + if (ir->tpid < 0) { + printk(KERN_ERR "lirc_pvr150: lirc_register_plugin: " + "cannot run poll thread\n"); + ret = -ECHILD; + goto err; + } + wait_for_completion(&tn); + ir->t_notify = NULL; + } + + /* initialise TX device */ + memcpy(&ir->c_tx,&client_template,sizeof(struct i2c_client)); + if (have_tx) { + /* I2C attach to device */ + ir->c_tx.addr = 0x70; + strlcpy(ir->c_tx.name, "Hauppauge PVR150 TX", + sizeof(ir->c_tx.name)); + if ( (ret = i2c_attach(&ir->c_tx, ir)) != 0 ) + goto err; + } + + /* set lirc_dev stuff */ + ir->l.code_length = 13; + ir->l.rbuf = &ir->buf; + ir->l.fops = &lirc_fops; + ir->l.data = ir; + ir->l.minor = minor; + ir->l.sample_rate = 0; + + /* register with lirc */ + ir->l.minor = lirc_register_plugin(&ir->l); + if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) { + printk(KERN_ERR + "lirc_pvr150: ir_attach: " + "\"minor\" must be between 0 and %d (%d)!\n", + MAX_IRCTL_DEVICES-1, ir->l.minor); + ret = -EBADRQC; + goto err; + } + + /* store this for getting back in open() later on */ + ir_devices[ir->l.minor] = ir; + + /* if we have the tx device, load the 'firmware'. We do this + after registering with lirc as otherwise hotplug seems to take + 10s to create the lirc device. + */ + if (have_tx) { + /* Special TX init */ + ret = tx_init(ir); + if (ret != 0) + goto err; + } + return 0; + +err: + /* undo everything, hopefully... */ + if (ir->c_rx.addr) ir_detach(&ir->c_rx); + if (ir->c_tx.addr) ir_detach(&ir->c_tx); + return ret; +} + +static int ir_detach(struct i2c_client *client) +{ + struct IR *ir = i2c_get_clientdata(client); + down(&ir->lock); + + if (client == &ir->c_rx) { + DECLARE_COMPLETION(tn); + DECLARE_COMPLETION(tn2); + + /* end up polling thread */ + if (ir->tpid >= 0) { + ir->t_notify = &tn; + ir->t_notify2 = &tn2; + ir->shutdown = 1; + { + struct task_struct *p; + p = find_task_by_pid_ns(ir->tpid, &init_pid_ns); + wake_up_process(p); + } + complete(&tn2); + wait_for_completion(&tn); + ir->t_notify = NULL; + ir->t_notify2 = NULL; + } + + /* unregister device */ + i2c_release_client(&ir->c_rx); + i2c_detach_client(&ir->c_rx); + } else if (client == &ir->c_tx) { + i2c_release_client(&ir->c_tx); + i2c_detach_client(&ir->c_tx); + } else { + up(&ir->lock); + printk(KERN_ERR "lirc_pvr150: ir_detach: detached from " + "something we didn't attach to\n"); + return -ENODEV; + } + + --ir->devs; + if (ir->devs < 0) + { + up(&ir->lock); + printk(KERN_ERR "lirc_pvr150: ir_detach: invalid " + "device count\n"); + return -ENODEV; + } + else if (ir->devs == 0) + { + /* unregister lirc plugin */ + if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES) + { + lirc_unregister_plugin(ir->l.minor); + ir_devices[ir->l.minor] = NULL; + } + + /* free memory */ + lirc_buffer_free(&ir->buf); + up(&ir->lock); + kfree(ir); + return 0; + } + up(&ir->lock); + return 0; +} + +static int ir_probe(struct i2c_adapter *adap) +{ + struct i2c_client c; + char buf; + +#ifdef I2C_HW_B_CX2341X + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848) || + adap->id == (I2C_ALGO_BIT | I2C_HW_B_CX2341X)) +#else + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) +#endif + { + int have_rx = 0, have_tx = 0; + + /* The external IR receiver is at i2c address 0x71 on the PVR-150 + The IR transmitter is at 0x70. + */ + memset(&c,0,sizeof(c)); + c.adapter = adap; + c.addr = 0x70; + + if (!disable_rx) { + if (i2c_master_recv(&c,&buf,1) == 1) + have_rx = 1; + dprintk("probe 0x70 @ %s: %s\n", + adap->name, + have_rx ? "yes" : "no"); + } + + if (!disable_tx) { + c.addr = 0x71; + if (i2c_master_recv(&c,&buf,1) == 1) + have_tx = 1; + dprintk("probe 0x71 @ %s: %s\n", + adap->name, + have_tx ? "yes" : "no"); + } + + if (have_rx || have_tx) + return ir_attach(adap, have_rx, have_tx); + else + { + printk(KERN_ERR "lirc_pvr150: %s: no devices found\n", adap->name); + } + } + + return 0; +} + +static int ir_command(struct i2c_client *client,unsigned int cmd, void *arg) +{ + /* nothing */ + return 0; +} + +/* ----------------------------------------------------------------------- */ +#ifdef MODULE + +int init_module(void) +{ + init_MUTEX(&tx_data_lock); + request_module("ivtv"); + request_module("firmware_class"); + i2c_add_driver(&driver); + return 0; +} + +void cleanup_module(void) +{ + i2c_del_driver(&driver); + /* if loaded */ + fw_unload(); +} + +MODULE_DESCRIPTION("Infrared receiver driver for Hauppauge PVR-150 card (i2c stack)"); +MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver"); +MODULE_LICENSE("GPL"); + +module_param(minor, int, 0444); +MODULE_PARM_DESC(minor, "Preferred minor device number"); + +module_param(debug, bool, 0644); +MODULE_PARM_DESC(debug, "Enable debugging messages"); + +module_param(disable_rx, bool, 0644); +MODULE_PARM_DESC(disable_rx, "Disable the IR receiver device"); + +module_param(disable_tx, bool, 0644); +MODULE_PARM_DESC(disable_tx, "Disable the IR transmitter device"); + +EXPORT_NO_SYMBOLS; + +#endif /* MODULE */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_pvr150/Makefile +++ linux-2.6.27/ubuntu/lirc/lirc_pvr150/Makefile @@ -0,0 +1,3 @@ +EXTRA_CFLAGS =-DIRCTL_DEV_MAJOR=61 -DLIRC_SERIAL_TRANSMITTER -DLIRC_SERIAL_SOFTCARRIER -I$(src)/.. + +obj-$(CONFIG_LIRC_PVR150) += lirc_pvr150.o --- linux-2.6.27.orig/ubuntu/lirc/lirc_sir/lirc_sir.c +++ linux-2.6.27/ubuntu/lirc/lirc_sir/lirc_sir.c @@ -0,0 +1,1323 @@ +/* + * LIRC SIR driver, (C) 2000 Milan Pikula + * + * lirc_sir - Device driver for use with SIR (serial infra red) + * mode of IrDA on many notebooks. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * 2000/09/16 Frank Przybylski : + * added timeout and relaxed pulse detection, removed gap bug + * + * 2000/12/15 Christoph Bartelmus : + * added support for Tekram Irmate 210 (sending does not work yet, + * kind of disappointing that nobody was able to implement that + * before), + * major clean-up + * + * 2001/02/27 Christoph Bartelmus : + * added support for StrongARM SA1100 embedded microprocessor + * parts cut'n'pasted from sa1100_ir.c (C) 2000 Russell King + */ + + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) +#error "**********************************************************" +#error " Sorry, this driver needs kernel version 2.2.18 or higher " +#error "**********************************************************" +#endif +#include + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef LIRC_ON_SA1100 +#include +#ifdef CONFIG_SA1100_COLLIE +#include +#include +#endif +#endif + +#include + +#include "lirc.h" +#include "lirc_dev/lirc_dev.h" +#include "kcompat.h" + +/* SECTION: Definitions */ + +/**************************** Tekram dongle ***************************/ +#ifdef LIRC_SIR_TEKRAM +/* stolen from kernel source */ +/* definitions for Tekram dongle */ +#define TEKRAM_115200 0x00 +#define TEKRAM_57600 0x01 +#define TEKRAM_38400 0x02 +#define TEKRAM_19200 0x03 +#define TEKRAM_9600 0x04 +#define TEKRAM_2400 0x08 + +#define TEKRAM_PW 0x10 /* Pulse select bit */ + +/* 10bit * 1s/115200bit in miliseconds = 87ms*/ +#define TIME_CONST (10000000ul/115200ul) + +#endif + +#ifdef LIRC_SIR_ACTISYS_ACT200L +static void init_act200(void); +#elif defined(LIRC_SIR_ACTISYS_ACT220L) +static void init_act220(void); +#endif + +/******************************* SA1100 ********************************/ +#ifdef LIRC_ON_SA1100 +struct sa1100_ser2_registers { + /* HSSP control register */ + unsigned char hscr0; + /* UART registers */ + unsigned char utcr0; + unsigned char utcr1; + unsigned char utcr2; + unsigned char utcr3; + unsigned char utcr4; + unsigned char utdr; + unsigned char utsr0; + unsigned char utsr1; +} sr; + +static int irq = IRQ_Ser2ICP; + +#define LIRC_ON_SA1100_TRANSMITTER_LATENCY 0 + +/* pulse/space ratio of 50/50 */ +static unsigned long pulse_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY); +/* 1000000/freq-pulse_width */ +static unsigned long space_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY); +static unsigned int freq = 38000; /* modulation frequency */ +static unsigned int duty_cycle = 50; /* duty cycle of 50% */ + +#endif + +#define RBUF_LEN 1024 +#define WBUF_LEN 1024 + +#define LIRC_DRIVER_NAME "lirc_sir" + +#define PULSE '[' + +#ifndef LIRC_SIR_TEKRAM +/* 9bit * 1s/115200bit in milli seconds = 78.125ms*/ +#define TIME_CONST (9000000ul/115200ul) +#endif + + +/* timeout for sequences in jiffies (=5/100s) */ +/* must be longer than TIME_CONST */ +#define SIR_TIMEOUT (HZ*5/100) + +#ifndef LIRC_ON_SA1100 +#ifndef LIRC_IRQ +#define LIRC_IRQ 4 +#endif +#ifndef LIRC_PORT +#define LIRC_PORT 0x3e8 +#endif + +static int io = LIRC_PORT; +static int irq = LIRC_IRQ; +static int threshold = 3; +#endif + +static DEFINE_SPINLOCK(timer_lock); +static struct timer_list timerlist; +/* time of last signal change detected */ +static struct timeval last_tv = {0, 0}; +/* time of last UART data ready interrupt */ +static struct timeval last_intr_tv = {0, 0}; +static int last_value; + +static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue); + +static DEFINE_SPINLOCK(hardware_lock); +static DEFINE_SPINLOCK(dev_lock); + +static lirc_t rx_buf[RBUF_LEN]; +static unsigned int rx_tail, rx_head; +static lirc_t tx_buf[WBUF_LEN]; + +static int debug; +#define dprintk(fmt, args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ + fmt, ## args); \ + } while (0) + +/* SECTION: Prototypes */ + +/* Communication with user-space */ +static int lirc_open(struct inode *inode, struct file *file); +static int lirc_close(struct inode *inode, struct file *file); +static unsigned int lirc_poll(struct file *file, poll_table *wait); +static ssize_t lirc_read(struct file *file, char *buf, size_t count, + loff_t *ppos); +static ssize_t lirc_write(struct file *file, const char *buf, size_t n, + loff_t *pos); +static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, + unsigned long arg); +static void add_read_queue(int flag, unsigned long val); +#ifdef MODULE +static int init_chrdev(void); +static void drop_chrdev(void); +#endif + /* Hardware */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static irqreturn_t sir_interrupt(int irq, void *dev_id, + struct pt_regs *regs); +#else +static irqreturn_t sir_interrupt(int irq, void *dev_id); +#endif +static void send_space(unsigned long len); +static void send_pulse(unsigned long len); +static int init_hardware(void); +static void drop_hardware(void); + /* Initialisation */ +static int init_port(void); +static void drop_port(void); +int init_module(void); +void cleanup_module(void); + +#ifdef LIRC_ON_SA1100 +static inline void on(void) +{ + PPSR |= PPC_TXD2; +} + +static inline void off(void) +{ + PPSR &= ~PPC_TXD2; +} +#else +static inline unsigned int sinp(int offset) +{ + return inb(io + offset); +} + +static inline void soutp(int offset, int value) +{ + outb(value, io + offset); +} +#endif + +#ifndef MAX_UDELAY_MS +#define MAX_UDELAY_US 5000 +#else +#define MAX_UDELAY_US (MAX_UDELAY_MS*1000) +#endif + +static inline void safe_udelay(unsigned long usecs) +{ + while (usecs > MAX_UDELAY_US) { + udelay(MAX_UDELAY_US); + usecs -= MAX_UDELAY_US; + } + udelay(usecs); +} + +/* SECTION: Communication with user-space */ + +static int lirc_open(struct inode *inode, struct file *file) +{ + spin_lock(&dev_lock); + if (MOD_IN_USE) { + spin_unlock(&dev_lock); + return -EBUSY; + } + MOD_INC_USE_COUNT; + spin_unlock(&dev_lock); + return 0; +} + +static int lirc_close(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +static unsigned int lirc_poll(struct file *file, poll_table *wait) +{ + poll_wait(file, &lirc_read_queue, wait); + if (rx_head != rx_tail) + return POLLIN | POLLRDNORM; + return 0; +} + +static ssize_t lirc_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + int n = 0; + int retval = 0; + DECLARE_WAITQUEUE(wait, current); + + if (n % sizeof(lirc_t)) + return -EINVAL; + + add_wait_queue(&lirc_read_queue, &wait); + set_current_state(TASK_INTERRUPTIBLE); + while (n < count) { + if (rx_head != rx_tail) { + if (copy_to_user((void *) buf + n, + (void *) (rx_buf + rx_head), + sizeof(lirc_t))) { + retval = -EFAULT; + break; + } + rx_head = (rx_head + 1) & (RBUF_LEN - 1); + n += sizeof(lirc_t); + } else { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + } + } + remove_wait_queue(&lirc_read_queue, &wait); + set_current_state(TASK_RUNNING); + return (n ? n : retval); +} +static ssize_t lirc_write(struct file *file, const char *buf, size_t n, + loff_t *pos) +{ + unsigned long flags; + int i; + + if (n % sizeof(lirc_t) || (n/sizeof(lirc_t)) > WBUF_LEN) + return -EINVAL; + if (copy_from_user(tx_buf, buf, n)) + return -EFAULT; + i = 0; + n /= sizeof(lirc_t); +#ifdef LIRC_ON_SA1100 + /* disable receiver */ + Ser2UTCR3 = 0; +#endif + local_irq_save(flags); + while (1) { + if (i >= n) + break; + if (tx_buf[i]) + send_pulse(tx_buf[i]); + i++; + if (i >= n) + break; + if (tx_buf[i]) + send_space(tx_buf[i]); + i++; + } + local_irq_restore(flags); +#ifdef LIRC_ON_SA1100 + off(); + udelay(1000); /* wait 1ms for IR diode to recover */ + Ser2UTCR3 = 0; + /* clear status register to prevent unwanted interrupts */ + Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); + /* enable receiver */ + Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE; +#endif + return n; +} + +static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, + unsigned long arg) +{ + int retval = 0; + unsigned long value = 0; +#ifdef LIRC_ON_SA1100 + unsigned int ivalue; + + if (cmd == LIRC_GET_FEATURES) + value = LIRC_CAN_SEND_PULSE | + LIRC_CAN_SET_SEND_DUTY_CYCLE | + LIRC_CAN_SET_SEND_CARRIER | + LIRC_CAN_REC_MODE2; + else if (cmd == LIRC_GET_SEND_MODE) + value = LIRC_MODE_PULSE; + else if (cmd == LIRC_GET_REC_MODE) + value = LIRC_MODE_MODE2; +#else + if (cmd == LIRC_GET_FEATURES) + value = LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2; + else if (cmd == LIRC_GET_SEND_MODE) + value = LIRC_MODE_PULSE; + else if (cmd == LIRC_GET_REC_MODE) + value = LIRC_MODE_MODE2; +#endif + + switch (cmd) { + case LIRC_GET_FEATURES: + case LIRC_GET_SEND_MODE: + case LIRC_GET_REC_MODE: + retval = put_user(value, (unsigned long *) arg); + break; + + case LIRC_SET_SEND_MODE: + case LIRC_SET_REC_MODE: + retval = get_user(value, (unsigned long *) arg); + break; +#ifdef LIRC_ON_SA1100 + case LIRC_SET_SEND_DUTY_CYCLE: + retval = get_user(ivalue, (unsigned int *) arg); + if (retval) + return reetval; + if (ivalue <= 0 || ivalue > 100) + return -EINVAL; + /* (ivalue/100)*(1000000/freq) */ + duty_cycle = ivalue; + pulse_width = (unsigned long) duty_cycle*10000/freq; + space_width = (unsigned long) 1000000L/freq-pulse_width; + if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) + pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; + if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) + space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; + break; + case LIRC_SET_SEND_CARRIER: + retval = get_user(ivalue, (unsigned int *) arg); + if (retval) + return retval; + if (ivalue > 500000 || ivalue < 20000) + return -EINVAL; + freq = ivalue; + pulse_width = (unsigned long) duty_cycle*10000/freq; + space_width = (unsigned long) 1000000L/freq-pulse_width; + if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) + pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; + if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) + space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; + break; +#endif + default: + retval = -ENOIOCTLCMD; + + } + + if (retval) + return retval; + if (cmd == LIRC_SET_REC_MODE) { + if (value != LIRC_MODE_MODE2) + retval = -ENOSYS; + } else if (cmd == LIRC_SET_SEND_MODE) { + if (value != LIRC_MODE_PULSE) + retval = -ENOSYS; + } + + return retval; +} + +static void add_read_queue(int flag, unsigned long val) +{ + unsigned int new_rx_tail; + lirc_t newval; + + dprintk("add flag %d with val %lu\n", flag, val); + + newval = val & PULSE_MASK; + + /* statistically pulses are ~TIME_CONST/2 too long: we could + maybe make this more exactly but this is good enough */ + if (flag) { + /* pulse */ + if (newval > TIME_CONST/2) + newval -= TIME_CONST/2; + else /* should not ever happen */ + newval = 1; + newval |= PULSE_BIT; + } else { + newval += TIME_CONST/2; + } + new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1); + if (new_rx_tail == rx_head) { + dprintk("Buffer overrun.\n"); + return; + } + rx_buf[rx_tail] = newval; + rx_tail = new_rx_tail; + wake_up_interruptible(&lirc_read_queue); +} + +static struct file_operations lirc_fops = { + .read = lirc_read, + .write = lirc_write, + .poll = lirc_poll, + .ioctl = lirc_ioctl, + .open = lirc_open, + .release = lirc_close, +}; + +static int set_use_inc(void *data) +{ + return 0; +} + +static void set_use_dec(void *data) +{ +} +static struct lirc_plugin plugin = { + .name = LIRC_DRIVER_NAME, + .minor = -1, + .code_length = 1, + .sample_rate = 0, + .data = NULL, + .add_to_buf = NULL, + .get_queue = NULL, + .set_use_inc = set_use_inc, + .set_use_dec = set_use_dec, + .fops = &lirc_fops, + .dev = NULL, + .owner = THIS_MODULE, +}; + + +#ifdef MODULE +static int init_chrdev(void) +{ + plugin.minor = lirc_register_plugin(&plugin); + if (plugin.minor < 0) { + printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n"); + return -EIO; + } + return 0; +} + +static void drop_chrdev(void) +{ + lirc_unregister_plugin(plugin.minor); +} +#endif + +/* SECTION: Hardware */ +static long delta(struct timeval *tv1, struct timeval *tv2) +{ + unsigned long deltv; + + deltv = tv2->tv_sec - tv1->tv_sec; + if (deltv > 15) + deltv = 0xFFFFFF; + else + deltv = deltv*1000000 + + tv2->tv_usec - + tv1->tv_usec; + return deltv; +} + +static void sir_timeout(unsigned long data) +{ + /* if last received signal was a pulse, but receiving stopped + within the 9 bit frame, we need to finish this pulse and + simulate a signal change to from pulse to space. Otherwise + upper layers will receive two sequences next time. */ + + unsigned long flags; + unsigned long pulse_end; + + /* avoid interference with interrupt */ + spin_lock_irqsave(&timer_lock, flags); + if (last_value) { +#ifndef LIRC_ON_SA1100 + /* clear unread bits in UART and restart */ + outb(UART_FCR_CLEAR_RCVR, io + UART_FCR); +#endif + /* determine 'virtual' pulse end: */ + pulse_end = delta(&last_tv, &last_intr_tv); + dprintk("timeout add %d for %lu usec\n", last_value, pulse_end); + add_read_queue(last_value, pulse_end); + last_value = 0; + last_tv = last_intr_tv; + } + spin_unlock_irqrestore(&timer_lock, flags); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static irqreturn_t sir_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +#else +static irqreturn_t sir_interrupt(int irq, void *dev_id) +#endif +{ + unsigned char data; + struct timeval curr_tv; + static unsigned long deltv; +#ifdef LIRC_ON_SA1100 + int status; + static int n; + + status = Ser2UTSR0; + /* + * Deal with any receive errors first. The bytes in error may be + * the only bytes in the receive FIFO, so we do this first. + */ + while (status & UTSR0_EIF) { + int bstat; + + if (debug) { + dprintk("EIF\n"); + bstat = Ser2UTSR1; + + if (bstat & UTSR1_FRE) + dprintk("frame error\n"); + if (bstat & UTSR1_ROR) + dprintk("receive fifo overrun\n"); + if (bstat & UTSR1_PRE) + dprintk("parity error\n"); + } + + bstat = Ser2UTDR; + n++; + status = Ser2UTSR0; + } + + if (status & (UTSR0_RFS | UTSR0_RID)) { + do_gettimeofday(&curr_tv); + deltv = delta(&last_tv, &curr_tv); + do { + data = Ser2UTDR; + dprintk("%d data: %u\n", n, (unsigned int) data); + n++; + } while (status & UTSR0_RID && /* do not empty fifo in + order to get UTSR0_RID in + any case */ + Ser2UTSR1 & UTSR1_RNE); /* data ready */ + + if (status&UTSR0_RID) { + add_read_queue(0 , deltv - n * TIME_CONST); /*space*/ + add_read_queue(1, n * TIME_CONST); /*pulse*/ + n = 0; + last_tv = curr_tv; + } + } + + if (status & UTSR0_TFS) + printk(KERN_ERR "transmit fifo not full, shouldn't happen\n"); + + /* + * We must clear certain bits. + */ + status &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); + if (status) + Ser2UTSR0 = status; +#else + unsigned long deltintrtv; + unsigned long flags; + int iir, lsr; + + while ((iir = inb(io + UART_IIR) & UART_IIR_ID)) { + switch (iir&UART_IIR_ID) { /* FIXME toto treba preriedit */ + case UART_IIR_MSI: + (void) inb(io + UART_MSR); + break; + case UART_IIR_RLSI: + (void) inb(io + UART_LSR); + break; + case UART_IIR_THRI: +#if 0 + if (lsr & UART_LSR_THRE) /* FIFO is empty */ + outb(data, io + UART_TX) +#endif + break; + case UART_IIR_RDI: + /* avoid interference with timer */ + spin_lock_irqsave(&timer_lock, flags); + do { + del_timer(&timerlist); + data = inb(io + UART_RX); + do_gettimeofday(&curr_tv); + deltv = delta(&last_tv, &curr_tv); + deltintrtv = delta(&last_intr_tv, &curr_tv); + dprintk("t %lu, d %d\n", deltintrtv, (int)data); + /* if nothing came in last X cycles, + it was gap */ + if (deltintrtv > TIME_CONST * threshold) { + if (last_value) { + dprintk("GAP\n"); + /* simulate signal change */ + add_read_queue(last_value, + deltv - + deltintrtv); + last_value = 0; + last_tv.tv_sec = + last_intr_tv.tv_sec; + last_tv.tv_usec = + last_intr_tv.tv_usec; + deltv = deltintrtv; + } + } + data = 1; + if (data ^ last_value) { + /* deltintrtv > 2*TIME_CONST, + remember ? */ + /* the other case is timeout */ + add_read_queue(last_value, + deltv-TIME_CONST); + last_value = data; + last_tv = curr_tv; + if (last_tv.tv_usec >= TIME_CONST) { + last_tv.tv_usec -= TIME_CONST; + } else { + last_tv.tv_sec--; + last_tv.tv_usec += 1000000 - + TIME_CONST; + } + } + last_intr_tv = curr_tv; + if (data) { + /* start timer for end of + * sequence detection */ + timerlist.expires = jiffies + + SIR_TIMEOUT; + add_timer(&timerlist); + } + } + while ((lsr = inb(io + UART_LSR)) + & UART_LSR_DR); /* data ready */ + spin_unlock_irqrestore(&timer_lock, flags); + break; + default: + break; + } + } +#endif + return IRQ_RETVAL(IRQ_HANDLED); +} + +#ifdef LIRC_ON_SA1100 +static void send_pulse(unsigned long length) +{ + unsigned long k, delay; + int flag; + + if (length == 0) + return; + /* this won't give us the carrier frequency we really want + due to integer arithmetic, but we can accept this inaccuracy */ + + for (k = flag = 0; k < length; k += delay, flag = !flag) { + if (flag) { + off(); + delay = space_width; + } else { + on(); + delay = pulse_width; + } + safe_udelay(delay); + } + off(); +} + +static void send_space(unsigned long length) +{ + if (length == 0) + return; + off(); + safe_udelay(length); +} +#else +static void send_space(unsigned long len) +{ + safe_udelay(len); +} + +static void send_pulse(unsigned long len) +{ + long bytes_out = len / TIME_CONST; + long time_left; + + time_left = (long)len - (long)bytes_out * (long)TIME_CONST; + if (bytes_out == 0) { + bytes_out++; + time_left = 0; + } + while (bytes_out--) { + outb(PULSE, io + UART_TX); + /* FIXME treba seriozne cakanie z drivers/char/serial.c */ + while (!(inb(io + UART_LSR) & UART_LSR_THRE)); + } +#if 0 + if (time_left > 0) + safe_udelay(time_left); +#endif +} +#endif + +#ifdef CONFIG_SA1100_COLLIE +static inline int sa1100_irda_set_power_collie(int state) +{ + if (state) { + /* + * 0 - off + * 1 - short range, lowest power + * 2 - medium range, medium power + * 3 - maximum range, high power + */ + ucb1200_set_io_direction(TC35143_GPIO_IR_ON, + TC35143_IODIR_OUTPUT); + ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_LOW); + udelay(100); + } else { + /* OFF */ + ucb1200_set_io_direction(TC35143_GPIO_IR_ON, + TC35143_IODIR_OUTPUT); + ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_HIGH); + } + return 0; +} +#endif + +static int init_hardware(void) +{ + unsigned long flags; + + spin_lock_irqsave(&hardware_lock, flags); + /* reset UART */ +#ifdef LIRC_ON_SA1100 +#ifdef CONFIG_SA1100_BITSY + if (machine_is_bitsy()) { + printk(KERN_INFO "Power on IR module\n"); + set_bitsy_egpio(EGPIO_BITSY_IR_ON); + } +#endif +#ifdef CONFIG_SA1100_COLLIE + sa1100_irda_set_power_collie(3); /* power on */ +#endif + sr.hscr0 = Ser2HSCR0; + + sr.utcr0 = Ser2UTCR0; + sr.utcr1 = Ser2UTCR1; + sr.utcr2 = Ser2UTCR2; + sr.utcr3 = Ser2UTCR3; + sr.utcr4 = Ser2UTCR4; + + sr.utdr = Ser2UTDR; + sr.utsr0 = Ser2UTSR0; + sr.utsr1 = Ser2UTSR1; + + /* configure GPIO */ + /* output */ + PPDR |= PPC_TXD2; + PSDR |= PPC_TXD2; + /* set output to 0 */ + off(); + + /* + * Enable HP-SIR modulation, and ensure that the port is disabled. + */ + Ser2UTCR3 = 0; + Ser2HSCR0 = sr.hscr0 & (~HSCR0_HSSP); + + /* clear status register to prevent unwanted interrupts */ + Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); + + /* 7N1 */ + Ser2UTCR0 = UTCR0_1StpBit|UTCR0_7BitData; + /* 115200 */ + Ser2UTCR1 = 0; + Ser2UTCR2 = 1; + /* use HPSIR, 1.6 usec pulses */ + Ser2UTCR4 = UTCR4_HPSIR|UTCR4_Z1_6us; + + /* enable receiver, receive fifo interrupt */ + Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE; + + /* clear status register to prevent unwanted interrupts */ + Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); + +#elif defined(LIRC_SIR_TEKRAM) + /* disable FIFO */ + soutp(UART_FCR, + UART_FCR_CLEAR_RCVR| + UART_FCR_CLEAR_XMIT| + UART_FCR_TRIGGER_1); + + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + /* First of all, disable all interrupts */ + soutp(UART_IER, sinp(UART_IER) & + (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); + + /* Set DLAB 1. */ + soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); + + /* Set divisor to 12 => 9600 Baud */ + soutp(UART_DLM, 0); + soutp(UART_DLL, 12); + + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + /* power supply */ + soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); + safe_udelay(50*1000); + + /* -DTR low -> reset PIC */ + soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); + udelay(1*1000); + + soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); + udelay(100); + + + /* -RTS low -> send control byte */ + soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2); + udelay(7); + soutp(UART_TX, TEKRAM_115200|TEKRAM_PW); + + /* one byte takes ~1042 usec to transmit at 9600,8N1 */ + udelay(1500); + + /* back to normal operation */ + soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); + udelay(50); + + udelay(1500); + + /* read previous control byte */ + printk(KERN_INFO LIRC_DRIVER_NAME + ": 0x%02x\n", sinp(UART_RX)); + + /* Set DLAB 1. */ + soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); + + /* Set divisor to 1 => 115200 Baud */ + soutp(UART_DLM, 0); + soutp(UART_DLL, 1); + + /* Set DLAB 0, 8 Bit */ + soutp(UART_LCR, UART_LCR_WLEN8); + /* enable interrupts */ + soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI); +#else + outb(0, io + UART_MCR); + outb(0, io + UART_IER); + /* init UART */ + /* set DLAB, speed = 115200 */ + outb(UART_LCR_DLAB | UART_LCR_WLEN7, io + UART_LCR); + outb(1, io + UART_DLL); outb(0, io + UART_DLM); + /* 7N1+start = 9 bits at 115200 ~ 3 bits at 44000 */ + outb(UART_LCR_WLEN7, io + UART_LCR); + /* FIFO operation */ + outb(UART_FCR_ENABLE_FIFO, io + UART_FCR); + /* interrupts */ + /* outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, io + UART_IER); */ + outb(UART_IER_RDI, io + UART_IER); + /* turn on UART */ + outb(UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2, io + UART_MCR); +#ifdef LIRC_SIR_ACTISYS_ACT200L + init_act200(); +#elif defined(LIRC_SIR_ACTISYS_ACT220L) + init_act220(); +#endif +#endif + spin_unlock_irqrestore(&hardware_lock, flags); + return 0; +} + +static void drop_hardware(void) +{ + unsigned long flags; + + spin_lock_irqsave(&hardware_lock, flags); + +#ifdef LIRC_ON_SA1100 + Ser2UTCR3 = 0; + + Ser2UTCR0 = sr.utcr0; + Ser2UTCR1 = sr.utcr1; + Ser2UTCR2 = sr.utcr2; + Ser2UTCR4 = sr.utcr4; + Ser2UTCR3 = sr.utcr3; + + Ser2HSCR0 = sr.hscr0; +#ifdef CONFIG_SA1100_BITSY + if (machine_is_bitsy()) + clr_bitsy_egpio(EGPIO_BITSY_IR_ON); +#endif +#ifdef CONFIG_SA1100_COLLIE + sa1100_irda_set_power_collie(0); /* power off */ +#endif +#else + /* turn off interrupts */ + outb(0, io + UART_IER); +#endif + spin_unlock_irqrestore(&hardware_lock, flags); +} + +/* SECTION: Initialisation */ + +static int init_port(void) +{ + int retval; + + /* get I/O port access and IRQ line */ +#ifndef LIRC_ON_SA1100 + if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) { + printk(KERN_ERR LIRC_DRIVER_NAME + ": i/o port 0x%.4x already in use.\n", io); + return -EBUSY; + } +#endif + retval = request_irq(irq, sir_interrupt, IRQF_DISABLED, + LIRC_DRIVER_NAME, NULL); + if (retval < 0) { +# ifndef LIRC_ON_SA1100 + release_region(io, 8); +# endif + printk(KERN_ERR LIRC_DRIVER_NAME + ": IRQ %d already in use.\n", + irq); + return retval; + } +#ifndef LIRC_ON_SA1100 + printk(KERN_INFO LIRC_DRIVER_NAME + ": I/O port 0x%.4x, IRQ %d.\n", + io, irq); +#endif + + init_timer(&timerlist); + timerlist.function = sir_timeout; + timerlist.data = 0xabadcafe; + + return 0; +} + +static void drop_port(void) +{ + free_irq(irq, NULL); + del_timer_sync(&timerlist); +#ifndef LIRC_ON_SA1100 + release_region(io, 8); +#endif +} + +#ifdef LIRC_SIR_ACTISYS_ACT200L +/******************************************************/ +/* Crystal/Cirrus CS8130 IR transceiver, used in Actisys Act200L dongle */ +/* some code borrowed from Linux IRDA driver */ + +/* Regsiter 0: Control register #1 */ +#define ACT200L_REG0 0x00 +#define ACT200L_TXEN 0x01 /* Enable transmitter */ +#define ACT200L_RXEN 0x02 /* Enable receiver */ +#define ACT200L_ECHO 0x08 /* Echo control chars */ + +/* Register 1: Control register #2 */ +#define ACT200L_REG1 0x10 +#define ACT200L_LODB 0x01 /* Load new baud rate count value */ +#define ACT200L_WIDE 0x04 /* Expand the maximum allowable pulse */ + +/* Register 3: Transmit mode register #2 */ +#define ACT200L_REG3 0x30 +#define ACT200L_B0 0x01 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P) */ +#define ACT200L_B1 0x02 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P) */ +#define ACT200L_CHSY 0x04 /* StartBit Synced 0=bittime, 1=startbit */ + +/* Register 4: Output Power register */ +#define ACT200L_REG4 0x40 +#define ACT200L_OP0 0x01 /* Enable LED1C output */ +#define ACT200L_OP1 0x02 /* Enable LED2C output */ +#define ACT200L_BLKR 0x04 + +/* Register 5: Receive Mode register */ +#define ACT200L_REG5 0x50 +#define ACT200L_RWIDL 0x01 /* fixed 1.6us pulse mode */ + /*.. other various IRDA bit modes, and TV remote modes..*/ + +/* Register 6: Receive Sensitivity register #1 */ +#define ACT200L_REG6 0x60 +#define ACT200L_RS0 0x01 /* receive threshold bit 0 */ +#define ACT200L_RS1 0x02 /* receive threshold bit 1 */ + +/* Register 7: Receive Sensitivity register #2 */ +#define ACT200L_REG7 0x70 +#define ACT200L_ENPOS 0x04 /* Ignore the falling edge */ + +/* Register 8,9: Baud Rate Dvider register #1,#2 */ +#define ACT200L_REG8 0x80 +#define ACT200L_REG9 0x90 + +#define ACT200L_2400 0x5f +#define ACT200L_9600 0x17 +#define ACT200L_19200 0x0b +#define ACT200L_38400 0x05 +#define ACT200L_57600 0x03 +#define ACT200L_115200 0x01 + +/* Register 13: Control register #3 */ +#define ACT200L_REG13 0xd0 +#define ACT200L_SHDW 0x01 /* Enable access to shadow registers */ + +/* Register 15: Status register */ +#define ACT200L_REG15 0xf0 + +/* Register 21: Control register #4 */ +#define ACT200L_REG21 0x50 +#define ACT200L_EXCK 0x02 /* Disable clock output driver */ +#define ACT200L_OSCL 0x04 /* oscillator in low power, medium accuracy mode */ + +static void init_act200(void) +{ + int i; + __u8 control[] = { + ACT200L_REG15, + ACT200L_REG13 | ACT200L_SHDW, + ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL, + ACT200L_REG13, + ACT200L_REG7 | ACT200L_ENPOS, + ACT200L_REG6 | ACT200L_RS0 | ACT200L_RS1, + ACT200L_REG5 | ACT200L_RWIDL, + ACT200L_REG4 | ACT200L_OP0 | ACT200L_OP1 | ACT200L_BLKR, + ACT200L_REG3 | ACT200L_B0, + ACT200L_REG0 | ACT200L_TXEN | ACT200L_RXEN, + ACT200L_REG8 | (ACT200L_115200 & 0x0f), + ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f), + ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE + }; + + /* Set DLAB 1. */ + soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8); + + /* Set divisor to 12 => 9600 Baud */ + soutp(UART_DLM, 0); + soutp(UART_DLL, 12); + + /* Set DLAB 0. */ + soutp(UART_LCR, UART_LCR_WLEN8); + /* Set divisor to 12 => 9600 Baud */ + + /* power supply */ + soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); + for (i = 0; i < 50; i++) + safe_udelay(1000); + + /* Reset the dongle : set RTS low for 25 ms */ + soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2); + for (i = 0; i < 25; i++) + udelay(1000); + + soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); + udelay(100); + + /* Clear DTR and set RTS to enter command mode */ + soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); + udelay(7); + +/* send out the control register settings for 115K 7N1 SIR operation */ + for (i = 0; i < sizeof(control); i++) { + soutp(UART_TX, control[i]); + /* one byte takes ~1042 usec to transmit at 9600,8N1 */ + udelay(1500); + } + + /* back to normal operation */ + soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); + udelay(50); + + udelay(1500); + soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); + + /* Set DLAB 1. */ + soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7); + + /* Set divisor to 1 => 115200 Baud */ + soutp(UART_DLM, 0); + soutp(UART_DLL, 1); + + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + /* Set DLAB 0, 7 Bit */ + soutp(UART_LCR, UART_LCR_WLEN7); + + /* enable interrupts */ + soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI); +} +#endif + +#ifdef LIRC_SIR_ACTISYS_ACT220L +/* Derived from linux IrDA driver (drivers/net/irda/actisys.c) + * Drop me a mail for any kind of comment: maxx@spaceboyz.net */ + +void init_act220(void) +{ + int i; + + /* DLAB 1 */ + soutp(UART_LCR, UART_LCR_DLAB|UART_LCR_WLEN7); + + /* 9600 baud */ + soutp(UART_DLM, 0); + soutp(UART_DLL, 12); + + /* DLAB 0 */ + soutp(UART_LCR, UART_LCR_WLEN7); + + /* reset the dongle, set DTR low for 10us */ + soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); + udelay(10); + + /* back to normal (still 9600) */ + soutp(UART_MCR, UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2); + + /* send RTS pulses until we reach 115200 + * i hope this is really the same for act220l/act220l+ */ + for (i = 0; i < 3; i++) { + udelay(10); + /* set RTS low for 10 us */ + soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2); + udelay(10); + /* set RTS high for 10 us */ + soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); + } + + /* back to normal operation */ + udelay(1500); /* better safe than sorry ;) */ + + /* Set DLAB 1. */ + soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7); + + /* Set divisor to 1 => 115200 Baud */ + soutp(UART_DLM, 0); + soutp(UART_DLL, 1); + + /* Set DLAB 0, 7 Bit */ + /* The dongle doesn't seem to have any problems with operation + at 7N1 */ + soutp(UART_LCR, UART_LCR_WLEN7); + + /* enable interrupts */ + soutp(UART_IER, UART_IER_RDI); +} +#endif + +static int init_lirc_sir(void) +{ + int retval; + + init_waitqueue_head(&lirc_read_queue); + retval = init_port(); + if (retval < 0) + return retval; + init_hardware(); + printk(KERN_INFO LIRC_DRIVER_NAME + ": Installed.\n"); + return 0; +} + +#ifdef MODULE + +int init_module(void) +{ + int retval; + + retval = init_chrdev(); + if (retval < 0) + return retval; + retval = init_lirc_sir(); + if (retval) { + drop_chrdev(); + return retval; + } + return 0; +} + +void cleanup_module(void) +{ + drop_hardware(); + drop_chrdev(); + drop_port(); + printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n"); +} + +#ifdef LIRC_SIR_TEKRAM +MODULE_DESCRIPTION("Infrared receiver driver for Tekram Irmate 210"); +MODULE_AUTHOR("Christoph Bartelmus"); +#elif defined(LIRC_ON_SA1100) +MODULE_DESCRIPTION("LIRC driver for StrongARM SA1100 embedded microprocessor"); +MODULE_AUTHOR("Christoph Bartelmus"); +#elif defined(LIRC_SIR_ACTISYS_ACT200L) +MODULE_DESCRIPTION("LIRC driver for Actisys Act200L"); +MODULE_AUTHOR("Karl Bongers"); +#elif defined(LIRC_SIR_ACTISYS_ACT220L) +MODULE_DESCRIPTION("LIRC driver for Actisys Act220L(+)"); +MODULE_AUTHOR("Jan Roemisch"); +#else +MODULE_DESCRIPTION("Infrared receiver driver for SIR type serial ports"); +MODULE_AUTHOR("Milan Pikula"); +#endif +MODULE_LICENSE("GPL"); + +#ifdef LIRC_ON_SA1100 +module_param(irq, int, 0444); +MODULE_PARM_DESC(irq, "Interrupt (16)"); +#else +module_param(io, int, 0444); +MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); + +module_param(irq, int, 0444); +MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); + +module_param(threshold, int, 0444); +MODULE_PARM_DESC(threshold, "space detection threshold (3)"); +#endif + +module_param(debug, bool, 0644); +MODULE_PARM_DESC(debug, "Enable debugging messages"); + +EXPORT_NO_SYMBOLS; + +#endif /* MODULE */ --- linux-2.6.27.orig/ubuntu/lirc/lirc_sir/Makefile +++ linux-2.6.27/ubuntu/lirc/lirc_sir/Makefile @@ -0,0 +1,3 @@ +EXTRA_CFLAGS =-DIRCTL_DEV_MAJOR=61 -DLIRC_SERIAL_TRANSMITTER -DLIRC_SERIAL_SOFTCARRIER -I$(src)/.. + +obj-$(CONFIG_LIRC_SIR) += lirc_sir.o --- linux-2.6.27.orig/ubuntu/lirc/lirc_cmdir/lirc_cmdir.h +++ linux-2.6.27/ubuntu/lirc/lirc_cmdir/lirc_cmdir.h @@ -0,0 +1,27 @@ +/* $Id: lirc_cmdir.h,v 1.3 2007/09/27 19:47:20 lirc Exp $ */ + +/* + * lirc_cmdir.h + */ + +#ifndef LIRC_CMDIR_H +#define LIRC_CMDIR_H + +#define ON 1 +#define OFF 0 + +/* transmitter channel control */ +#define MAX_CHANNELS 32 + +/* CommandIR control codes */ +#define MCU_CTRL_SIZE 3 +#define FREQ_HEADER 2 +#define TX_HEADER 7 +#define TX_HEADER_NEW 8 + +extern int cmdir_write(unsigned char *buffer, int count, + void *callback_fct, int u); +extern ssize_t cmdir_read(unsigned char *buffer, size_t count); +extern int set_tx_channels(unsigned int next_tx); + +#endif --- linux-2.6.27.orig/ubuntu/lirc/lirc_cmdir/lirc_cmdir.c +++ linux-2.6.27/ubuntu/lirc/lirc_cmdir/lirc_cmdir.c @@ -0,0 +1,613 @@ +/* $Id: lirc_cmdir.c,v 1.9 2008/01/13 11:13:49 lirc Exp $ */ + +/* + * lirc_cmdir.c - Driver for InnovationOne's COMMANDIR USB Transceiver + * + * This driver requires the COMMANDIR hardware driver, available at + * http://www.commandir.com/. + * + * Copyright (C) 2005 InnovationOne - Evelyn Yeung + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) +#error "**********************************************************" +#error " Sorry, this driver needs kernel version 2.2.18 or higher " +#error "**********************************************************" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lirc.h" +#include "lirc_dev/lirc_dev.h" +#include "kcompat.h" +#include "lirc_cmdir.h" + +static int debug; +#define dprintk(fmt, args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG fmt, ## args); \ + } while (0) + +struct lirc_cmdir { + int features; +}; + +struct lirc_cmdir hardware = { + ( + /* LIRC_CAN_SET_SEND_DUTY_CYCLE| */ + LIRC_CAN_SET_SEND_CARRIER| + LIRC_CAN_SEND_PULSE| + LIRC_CAN_SET_TRANSMITTER_MASK| + LIRC_CAN_REC_MODE2) + , +}; + +#define LIRC_DRIVER_NAME "lirc_cmdir" +#define RBUF_LEN 256 +#define WBUF_LEN 256 +#define MAX_PACKET 64 + +static struct lirc_buffer rbuf; +static lirc_t wbuf[WBUF_LEN]; +static unsigned char cmdir_char[4*WBUF_LEN]; +static unsigned char write_control[MCU_CTRL_SIZE]; +static unsigned int last_mc_time; +static int usb_status = ON; +static unsigned char signal_num; +char timerval; + +unsigned int freq = 38000; +/* unsigned int duty_cycle = 50; */ + + +#ifndef MAX_UDELAY_MS +#define MAX_UDELAY_US 5000 +#else +#define MAX_UDELAY_US (MAX_UDELAY_MS*1000) +#endif + +static inline void safe_udelay(unsigned long usecs) +{ + while (usecs > MAX_UDELAY_US) { + udelay(MAX_UDELAY_US); + usecs -= MAX_UDELAY_US; + } + udelay(usecs); +} + +static unsigned int get_time_value(unsigned int firstint, + unsigned int secondint, unsigned char overflow) +{ /* get difference between two timestamps from MCU */ + unsigned int t_answer = 0; + + if (secondint > firstint) { + t_answer = secondint - firstint + overflow*65536; + } else { + if (overflow > 0) + t_answer = (65536 - firstint) + secondint + + (overflow - 1) * 65536; + else + t_answer = (65536 - firstint) + secondint; + } + + /* clamp to long signal */ + if (t_answer > 16000000) + t_answer = PULSE_MASK; + + return t_answer; +} + + +static int set_use_inc(void *data) +{ + /* Init read buffer. */ + if (lirc_buffer_init(&rbuf, sizeof(lirc_t), RBUF_LEN) < 0) + return -ENOMEM; + + MOD_INC_USE_COUNT; + return 0; +} + +static void set_use_dec(void *data) +{ + lirc_buffer_free(&rbuf); + MOD_DEC_USE_COUNT; +} + + +static void usb_error_handle(int retval) +{ + switch (retval) { + case -ENODEV: + /* device has been unplugged */ + if (usb_status == ON) { + usb_status = OFF; + printk(LIRC_DRIVER_NAME ": device is unplugged\n"); + } + break; + default: + printk(LIRC_DRIVER_NAME ": usb error = %d\n", retval); + break; + } +} + +static int write_to_usb(unsigned char *buffer, int count, int time_elapsed) +{ + int write_return; + + write_return = cmdir_write(buffer, count, NULL, time_elapsed); + if (write_return != count) { + usb_error_handle(write_return); + } else { + if (usb_status == OFF) { + printk(LIRC_DRIVER_NAME ": device is now plugged in\n"); + usb_status = ON; + } + } + return write_return; +} + +static void set_freq(void) +{ + /* float tempfreq = 0.0; */ + int write_return; + + /* + * Can't use floating point in 2.6 kernel! + * May be some loss of precision + */ + timerval = (1000000 / freq) / 2; + write_control[0] = FREQ_HEADER; + write_control[1] = timerval; + write_control[2] = 0; + write_return = write_to_usb(write_control, MCU_CTRL_SIZE, 0); + if (write_return == MCU_CTRL_SIZE) + printk(LIRC_DRIVER_NAME ": freq set to %dHz\n", freq); + else + printk(LIRC_DRIVER_NAME ": freq unchanged\n"); + +} + +static int cmdir_convert_RX(unsigned char *orig_rxbuffer) +{ + unsigned char tmp_char_buffer[80]; + unsigned int tmp_int_buffer[20]; + unsigned int final_data_buffer[20]; + unsigned int num_data_values = 0; + unsigned char num_data_bytes = 0; + unsigned int orig_index = 0; + int i; + + for (i = 0; i < 80; i++) + tmp_char_buffer[i] = 0; + for (i = 0; i < 20; i++) + tmp_int_buffer[i] = 0; + + /* + * get number of data bytes that follow the control bytes + * (NOT including them) + */ + num_data_bytes = orig_rxbuffer[1]; + + /* check if num_bytes is multiple of 3; if not, error */ + if (num_data_bytes % 3 > 0) + return -1; + if (num_data_bytes > 60) + return -3; + if (num_data_bytes < 3) + return -2; + + /* + * get number of ints to be returned; num_data_bytes does + * NOT include control bytes + */ + num_data_values = num_data_bytes/3; + + for (i = 0; i < num_data_values; i++) { + tmp_char_buffer[i*4] = orig_rxbuffer[(i+1)*3]; + tmp_char_buffer[i*4+1] = orig_rxbuffer[(i+1)*3+1]; + tmp_char_buffer[i*4+2] = 0; + tmp_char_buffer[i*4+3] = 0; + } + + /* convert to int array */ + memcpy((unsigned char *)tmp_int_buffer, tmp_char_buffer, + (num_data_values*4)); + + if (orig_rxbuffer[5] < 255) { + /* space */ + final_data_buffer[0] = get_time_value(last_mc_time, + tmp_int_buffer[0], + orig_rxbuffer[5]); + } else { /* is pulse */ + final_data_buffer[0] = get_time_value(last_mc_time, + tmp_int_buffer[0], + 0); + final_data_buffer[0] |= PULSE_BIT; + } + for (i = 1; i < num_data_values; i++) { + /* + * index of orig_rxbuffer that corresponds to + * overflow/pulse/space + */ + orig_index = (i + 1)*3 + 2; + if (orig_rxbuffer[orig_index] < 255) { + final_data_buffer[i] = + get_time_value(tmp_int_buffer[i - 1], + tmp_int_buffer[i], + orig_rxbuffer[orig_index]); + } else { + final_data_buffer[i] = + get_time_value(tmp_int_buffer[i - 1], + tmp_int_buffer[i], + 0); + final_data_buffer[i] |= PULSE_BIT; + } + } + last_mc_time = tmp_int_buffer[num_data_values - 1]; + + if (lirc_buffer_full(&rbuf)) { + printk(KERN_ERR LIRC_DRIVER_NAME ": lirc_buffer is full\n"); + return -EOVERFLOW; + } + lirc_buffer_write_n(&rbuf, (char *)final_data_buffer, num_data_values); + + return 0; +} + + +static int usb_read_once(void) +{ + int read_retval = 0; + int conv_retval = 0; + unsigned char read_buffer[MAX_PACKET]; + int i = 0; + int tooFull = 5; /* read up to 5 packets */ + + for (i = 0; i < MAX_PACKET; i++) + read_buffer[i] = 0; + + while (tooFull--) { + read_retval = cmdir_read(read_buffer, MAX_PACKET); + /* Loop until we unload the data build-up */ + if (read_buffer[1] < 60) + tooFull = 0; + if (!(read_retval == MAX_PACKET)) { + if (read_retval == -ENODEV) { + if (usb_status == ON) { + printk(KERN_ALERT LIRC_DRIVER_NAME + ": device is unplugged\n"); + usb_status = OFF; + } + } else { + /* supress errors */ + printk(KERN_ALERT LIRC_DRIVER_NAME + ": usb error on read = %d\n", + read_retval); + return -ENODATA; + } + dprintk("Error 3\n"); + return -ENODATA; + } else { + if (usb_status == OFF) { + usb_status = ON; + printk(LIRC_DRIVER_NAME + ": device is now plugged in\n"); + } + } + + if (read_buffer[0] & 0x08) { + conv_retval = cmdir_convert_RX(read_buffer); + if (conv_retval == 0) { + if (!tooFull) + return 0; + else + dprintk("Looping for more data...\n"); + } else { + dprintk("Error 2: %d\n", (int)conv_retval); + return -ENODATA; + } + } else { + /* There really is no data in their buffer */ + dprintk("Empty RX Buffer!\n"); + return -ENODATA; + } + } + return -1; +} + +int add_to_buf(void *data, struct lirc_buffer *buf) +{ + return usb_read_once(); +} + + +static ssize_t lirc_write(struct file *file, const char *buf, + size_t n, loff_t *ppos) +{ + int i, count; + unsigned int mod_signal_length = 0; + unsigned int time_elapse = 0; + unsigned int total_time_elapsed = 0; + unsigned int num_bytes_already_sent = 0; + unsigned int hibyte = 0; + unsigned int lobyte = 0; + int cmdir_cnt = 0; + unsigned int wait_this = 0; + struct timeval start_time; + struct timeval end_time; + unsigned int real_time_elapsed = 0; + + /* save the time we started the write: */ + do_gettimeofday(&start_time); + + if (n % sizeof(lirc_t)) + return -EINVAL; + + count = n/sizeof(lirc_t); + if (count > WBUF_LEN || count % 2 == 0) + return -EINVAL; + if (copy_from_user(wbuf, buf, n)) + return -EFAULT; + + /* + * the first time we have to flag that this is the start of a new + * signal otherwise COMMANDIR may receive 2 back-to-back pulses & + * invert the signal + */ + cmdir_char[0] = TX_HEADER_NEW; + signal_num++; + cmdir_char[1] = signal_num; + cmdir_cnt = 2; + for (i = 0; i < count; i++) { + /* conversion to number of modulation frequency pulse edges */ + mod_signal_length = wbuf[i] >> 3; + /* + * account for minor rounding errors - + * calculate length from this: + */ + time_elapse += mod_signal_length * timerval; + + hibyte = mod_signal_length / 256; + lobyte = mod_signal_length % 256; + cmdir_char[cmdir_cnt+1] = lobyte; + cmdir_char[cmdir_cnt] = hibyte; + cmdir_cnt += 2; + + /* write data to usb if full packet is collected */ + if (cmdir_cnt % MAX_PACKET == 0) { + write_to_usb(cmdir_char, MAX_PACKET, time_elapse); + + total_time_elapsed += time_elapse; + + num_bytes_already_sent += MAX_PACKET; + time_elapse = 0; + + if ((i + 1) < count) { + /* still more to send: */ + cmdir_char[0] = TX_HEADER; /* Next Packet */ + cmdir_char[1] = signal_num; + cmdir_cnt = 2; /* reset the count */ + } + } + } + + /* send last chunk of data */ + if (cmdir_cnt > 0) { + total_time_elapsed += time_elapse; + write_to_usb(cmdir_char, cmdir_cnt, time_elapse); + } + /* XXX ERS remove all this? */ + /* + * we need to _manually delay ourselves_ to remain backwards + * compatible with LIRC and prevent our queue buffer from overflowing. + * Queuing in this driver is about instant, and send_start for example + * will fill it up quickly and prevent send_stop from taking immediate + * effect. + */ + dprintk("Total elapsed time is: %d. \n", total_time_elapsed); + do_gettimeofday(&end_time); + /* + * udelay for the difference between endtime and + * start + total_time_elapsed + */ + if (start_time.tv_usec < end_time.tv_usec) + real_time_elapsed = (end_time.tv_usec - start_time.tv_usec); + else + real_time_elapsed = ((end_time.tv_usec + 1000000) - + start_time.tv_usec); + dprintk("Real time elapsed was %u.\n", real_time_elapsed); + if (real_time_elapsed < (total_time_elapsed - 1000)) + wait_this = total_time_elapsed - real_time_elapsed - 1000; + +#if 0 /* enable this for backwards compatibility */ + safe_udelay(wait_this); +#endif + + return(n); +} + + +static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, + unsigned long arg) +{ + int result; + unsigned long value; + unsigned int ivalue; + unsigned int multiplier = 1; + unsigned int mask = 0; + int i; + + switch (cmd) { + case LIRC_SET_TRANSMITTER_MASK: + if (!(hardware.features&LIRC_CAN_SET_TRANSMITTER_MASK)) + return -ENOIOCTLCMD; + result = get_user(ivalue, (unsigned int *) arg); + if (result) + return result; + for (i = 0; i < MAX_CHANNELS; i++) { + multiplier = multiplier * 0x10; + mask |= multiplier; + } + if (ivalue >= mask) + return MAX_CHANNELS; + set_tx_channels(ivalue); + return 0; + break; + + case LIRC_GET_SEND_MODE: + if (!(hardware.features & LIRC_CAN_SEND_MASK)) + return -ENOIOCTLCMD; + + result = put_user(LIRC_SEND2MODE + (hardware.features & LIRC_CAN_SEND_MASK), + (unsigned long *) arg); + if (result) + return result; + break; + + case LIRC_SET_SEND_MODE: + if (!(hardware.features&LIRC_CAN_SEND_MASK)) + return -ENOIOCTLCMD; + + result = get_user(value, (unsigned long *)arg); + if (result) + return result; + break; + + case LIRC_GET_LENGTH: + return -ENOSYS; + break; + + case LIRC_SET_SEND_DUTY_CYCLE: + dprintk(KERN_WARNING LIRC_DRIVER_NAME + ": SET_SEND_DUTY_CYCLE\n"); + + if (!(hardware.features&LIRC_CAN_SET_SEND_DUTY_CYCLE)) + return -ENOIOCTLCMD; + + result = get_user(ivalue, (unsigned int *)arg); + if (result) + return result; + if (ivalue <= 0 || ivalue > 100) + return -EINVAL; + + /* TODO: */ + dprintk(LIRC_DRIVER_NAME + ": set_send_duty_cycle not yet supported\n"); + + return 0; + break; + + case LIRC_SET_SEND_CARRIER: + dprintk(KERN_WARNING LIRC_DRIVER_NAME ": SET_SEND_CARRIER\n"); + + if (!(hardware.features & LIRC_CAN_SET_SEND_CARRIER)) + return -ENOIOCTLCMD; + + result = get_user(ivalue, (unsigned int *)arg); + if (result) + return result; + if (ivalue > 500000 || ivalue < 24000) + return -EINVAL; + if (ivalue != freq) { + freq = ivalue; + set_freq(); + } + return 0; + break; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static struct file_operations lirc_fops = { + .write = lirc_write, +}; + +static struct lirc_plugin plugin = { + .name = LIRC_DRIVER_NAME, + .minor = -1, + .code_length = 1, + .sample_rate = 20, + .data = NULL, + .add_to_buf = add_to_buf, + .get_queue = NULL, + .rbuf = &rbuf, + .set_use_inc = set_use_inc, + .set_use_dec = set_use_dec, + .ioctl = lirc_ioctl, + .fops = &lirc_fops, + .dev = NULL, + .owner = THIS_MODULE, +}; + +#ifdef MODULE + +MODULE_AUTHOR("Evelyn Yeung, Matt Bodkin"); +MODULE_DESCRIPTION("InnovationOne driver for " + "CommandIR USB infrared transceiver"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +module_param(debug, bool, 0644); +MODULE_PARM_DESC(debug, "Enable debugging messages"); + +#ifndef KERNEL_2_5 +EXPORT_NO_SYMBOLS; +#endif + +int init_module(void) +{ + plugin.features = hardware.features; + plugin.minor = lirc_register_plugin(&plugin); + if (plugin.minor < 0) { + printk(KERN_ERR LIRC_DRIVER_NAME + ": register_chrdev failed!\n"); + return -EIO; + } + set_freq(); + return 0; +} + +void cleanup_module(void) +{ + lirc_unregister_plugin(plugin.minor); + printk(KERN_INFO LIRC_DRIVER_NAME ": module removed\n"); +} + +#endif + + --- linux-2.6.27.orig/ubuntu/lirc/lirc_cmdir/Makefile +++ linux-2.6.27/ubuntu/lirc/lirc_cmdir/Makefile @@ -0,0 +1,3 @@ +EXTRA_CFLAGS =-DIRCTL_DEV_MAJOR=61 -DLIRC_SERIAL_TRANSMITTER -DLIRC_SERIAL_SOFTCARRIER -I$(src)/.. + +obj-$(CONFIG_LIRC_CMDIR) += lirc_cmdir.o commandir.o --- linux-2.6.27.orig/ubuntu/lirc/lirc_cmdir/commandir.h +++ linux-2.6.27/ubuntu/lirc/lirc_cmdir/commandir.h @@ -0,0 +1,41 @@ +/* + * commandir.h + */ + +#define ASCII0 48 + +/* transmitter channel control */ +#define MAX_DEVICES 8 +#define MAX_CHANNELS 32 +#define TX1_ENABLE 0x80 +#define TX2_ENABLE 0x40 +#define TX3_ENABLE 0x20 +#define TX4_ENABLE 0x10 + +/* command types */ +#define cNothing 0 +#define cRESET 1 +#define cFLASH 2 +#define cLCD 3 +#define cRX 4 + +/* CommandIR control codes */ +#define MCU_CTRL_SIZE 3 +#define FREQ_HEADER 2 +#define RESET_HEADER 3 +#define FLASH_HEADER 4 +#define LCD_HEADER 5 +#define TX_HEADER 7 +#define TX_HEADER_NEW 8 + +/* Queue buffering constants */ +#define SEND_IDLE 0 +#define SEND_ACTIVE 1 + +#define QUEUELENGTH 256 + +extern int cmdir_write(unsigned char *buffer, int count, + void *callback_fct, int u); +extern ssize_t cmdir_read(unsigned char *buffer, size_t count); +extern int set_tx_channels(unsigned int next_tx); + --- linux-2.6.27.orig/ubuntu/lirc/lirc_cmdir/commandir.c +++ linux-2.6.27/ubuntu/lirc/lirc_cmdir/commandir.c @@ -0,0 +1,1521 @@ + +/* + * + * Hardware Driver for COMMANDIR USB Transceiver + * 2005-2007 InnovationOne - Matt Bodkin, Evelyn Yeung + * + * Version 1.4.2 + * For 2.4.* or 2.6.* kernel versions + * Based on the USB Skeleton driver, versions 0.7 and 2.0 + * + */ + +#include +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include "commandir.h" + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +#include +#include +#include +#include +#include +#include +#include +#else +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) +#include +#else +#include +#endif +#endif + +#define DRIVER_VERSION "v1.1.2" +#define DRIVER_AUTHOR "Evelyn Yeung, InnovationOne" +#define DRIVER_DESC "CommandIR USB Transceiver Driver" + +#define USB_CMDIR_VENDOR_ID 0x10c4 +#define USB_CMDIR_PRODUCT_ID 0x0003 +#define USB_CMDIR_MINOR_BASE 192 + +/* table of devices that work with this driver */ +static struct usb_device_id cmdir_table [] = +{ + { USB_DEVICE(USB_CMDIR_VENDOR_ID, USB_CMDIR_PRODUCT_ID) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, cmdir_table); + +static int cmdir_open(struct inode *inode, struct file *file); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +static void *cmdir_probe(struct usb_device *dev, unsigned int ifnum, + const struct usb_device_id *id); +static int cmdir_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +static void cmdir_disconnect(struct usb_device *dev, void *ptr); +#else +static int cmdir_probe(struct usb_interface *interface, + const struct usb_device_id *id); +static void cmdir_disconnect(struct usb_interface *interface); +#endif +static int cmdir_release(struct inode *inode, struct file *file); +static int cmdir_check(int device_num); +static void init_cmdir_var(int device_num); +static void reset_cmdir(int device_num); +static void update_cmdir_string(int device_num); +static void print_cmdir(int device_num); +static ssize_t cmdir_file_read(struct file *file, char *buffer, + size_t count, loff_t *ppos); +ssize_t cmdir_read(unsigned char *buffer, size_t count); +static ssize_t cmdir_file_write(struct file *file, const char *buffer, + size_t count, loff_t *ppos); +int cmdir_write(unsigned char *buffer, int count, void *callback_fct, int u); +int write_core(unsigned char *buffer, int count, + void *callback_fct, int device_num); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +static void cmdir_write_bulk_callback(struct urb *urb); +#else +static void cmdir_write_bulk_callback(struct urb *urb, struct pt_regs *regs); +#endif +int set_tx_channels(unsigned int next_tx); + +int add_cmdir_queue(unsigned char *buffer, int count, + void *callback_vct, int usecdelay); +int cmdir_write_queue(unsigned char *buffer, int count, void *callback_vct); +int send_queue(void); +int wait_to_tx(int usecs); + +/* circular packet queue */ +unsigned char ourbuffers[QUEUELENGTH][64]; +int waitusecs[QUEUELENGTH]; +int ourbufferlengths[QUEUELENGTH]; +int nexttosend; +int nexttofill; +int send_status = SEND_IDLE; +int last_tx_sec; +int last_tx_usec; + +static int curTXFill; +struct timeval tp; + +int debug_commandir; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + +/* Structure to hold all of our device specific stuff */ +struct usb_skel { + struct usb_device *udev; /* save off the usb device pointer */ + struct usb_interface *interface; /* the interface for this device */ + devfs_handle_t devfs; /* devfs device node */ + unsigned char minor; /* the starting minor number */ + unsigned char num_ports; /* the number of ports this device has */ + char num_interrupt_in; /* number of interrupt in endpoints */ + char num_bulk_in; /* number of bulk in endpoints */ + char num_bulk_out; /* number of bulk out endpoints */ + + unsigned char *bulk_in_buffer; /* the buffer to receive data */ + int bulk_in_size; /* the size of the receive buffer */ + __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ + + unsigned char *bulk_out_buffer; /* the buffer to send data */ + int bulk_out_size; /* the size of the send buffer */ + struct urb *write_urb; /* the urb used to send data */ + __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ + + struct tq_struct tqueue; /* task queue for line discipline waking up */ + int open_count; /* number of times this port has been opened */ + struct semaphore sem; /* locks this structure */ +}; + +extern devfs_handle_t usb_devfs_handle; /* the global usb devfs handle */ + +/* array of pointers to our devices that are currently connected */ +static struct usb_skel *minor_table[MAX_DEVICES]; +/* lock to protect the minor_table structure */ +static DECLARE_MUTEX(minor_table_mutex); + +static struct file_operations cmdir_fops = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) + .owner = THIS_MODULE, +#endif /* kernel < 2.6.16 */ +#endif /* kernel >= 2.6.0 */ + .read = cmdir_file_read, + .write = cmdir_file_write, + .ioctl = cmdir_ioctl, + .open = cmdir_open, + .release = cmdir_release, +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver cmdir_driver = { + .name = "commandir", + .probe = cmdir_probe, + .disconnect = cmdir_disconnect, + .fops = &cmdir_fops, + .minor = USB_CMDIR_MINOR_BASE, + .id_table = cmdir_table, +}; + +#else /* kernel >= 2.6 */ + +/* Structure to hold all of our device specific stuff */ +struct usb_skel { + struct usb_device *udev; /* the usb device for this device */ + struct usb_interface *interface; /* the interface for this device */ + unsigned char *bulk_in_buffer; /* the buffer to receive data */ + size_t bulk_in_size; /* the size of the receive buffer */ + __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ + __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ + struct kref kref; +}; +#define to_skel_dev(d) container_of(d, struct usb_skel, kref) + +static struct file_operations cmdir_fops = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) + .owner = THIS_MODULE, +#endif /* kernel < 2.6.16 */ +#endif /* kernel >= 2.6.0 */ + .read = cmdir_file_read, + .write = cmdir_file_write, + .open = cmdir_open, + .release = cmdir_release, +}; + +/* usb class driver info in order to get a minor number from the usb core, + * and to have the device registered with devfs and the driver core */ +static struct usb_class_driver cmdir_class = { + .name = "usb/commandir%d", + .fops = &cmdir_fops, + /* .mode = S_IFCHR | S_IRUSR | S_IWUSR | + * S_IRGRP | S_IWGRP | S_IROTH, */ + .minor_base = USB_CMDIR_MINOR_BASE, +}; + +static struct usb_driver cmdir_driver = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) + .owner = THIS_MODULE, +#endif /* kernel < 2.6.16 */ +#endif /* kernel >= 2.6.0 */ + .name = "commandir", + .probe = cmdir_probe, + .disconnect = cmdir_disconnect, + .id_table = cmdir_table, +}; + +#endif /* kernel < 2.6.0 */ + +static int lcd_device; +static int rx_device; +static int def_device; + +#define DEFAULT_TRANSMITTERS 0x0F +static unsigned int transmitters = DEFAULT_TRANSMITTERS; +static unsigned int next_transmitters = DEFAULT_TRANSMITTERS; + +#define CMDIR_VAR_LEN 68 +static char cmdir_var[] = +"COMMANDIRx:\n TX Enabled: 1, 2, 3, 4\n RX: commandirx\n LCD: commandirx"; + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +static inline void cmdir_delete(struct usb_skel *dev) +{ + minor_table[dev->minor] = NULL; + if (dev->bulk_in_buffer != NULL) + kfree(dev->bulk_in_buffer); + if (dev->bulk_out_buffer != NULL) + kfree(dev->bulk_out_buffer); + if (dev->write_urb != NULL) + usb_free_urb(dev->write_urb); + kfree(dev); +} +#else +static void cmdir_delete(struct kref *kref) +{ + struct usb_skel *dev = to_skel_dev(kref); + + usb_put_dev(dev->udev); + kfree(dev->bulk_in_buffer); + kfree(dev); +} +#endif + +static int __init usb_cmdir_init(void) +{ + int result; + + /* register this driver with the USB subsystem */ + result = usb_register(&cmdir_driver); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + if (result < 0) { + err("usb_register failed for the "__FILE__ + " driver. Error number %d", result); + return -1; + } + + info(DRIVER_DESC " " DRIVER_VERSION); + + return 0; +#else + if (result) + err("usb_register failed. Error number %d", result); + + return result; +#endif +} + +static int cmdir_open(struct inode *inode, struct file *file) +{ + struct usb_skel *dev; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0) + struct usb_interface *interface; +#endif + int subminor; + int retval = 0; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + subminor = MINOR(inode->i_rdev) - USB_CMDIR_MINOR_BASE; + if ((subminor < 0) || (subminor >= MAX_DEVICES)) + return -ENODEV; + MOD_INC_USE_COUNT; + + /* lock our minor table and get our local data for this minor */ + down(&minor_table_mutex); + dev = minor_table[subminor]; + if (dev == NULL) { + up(&minor_table_mutex); + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + down(&dev->sem); /* lock this device */ + up(&minor_table_mutex); /* unlock the minor table */ + ++dev->open_count; /* increment our usage count for the driver */ + file->private_data = dev; /* save object in file's private structure */ + up(&dev->sem); /* unlock this device */ + + return retval; +#else + subminor = iminor(inode); + interface = usb_find_interface(&cmdir_driver, subminor); + if (!interface) { + err("%s - error, can't find device for minor %d", + __FUNCTION__, subminor); + retval = -ENODEV; + goto exit; + } + + dev = usb_get_intfdata(interface); + if (!dev) { + retval = -ENODEV; + goto exit; + } + + kref_get(&dev->kref); /* increment our usage count for the device */ + file->private_data = dev; /* save object in file's private structure */ + +exit: + return retval; +#endif +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +static void *cmdir_probe(struct usb_device *udev, unsigned int ifnum, + const struct usb_device_id *id) +{ + struct usb_skel *dev = NULL; + struct usb_interface *interface; + struct usb_interface_descriptor *iface_desc; + struct usb_endpoint_descriptor *endpoint; + int minor; + int buffer_size; + int i; + char name[10]; + + /* See if the device offered us matches what we can accept */ + if ((udev->descriptor.idVendor != USB_CMDIR_VENDOR_ID) || + (udev->descriptor.idProduct != USB_CMDIR_PRODUCT_ID)) + return NULL; + + /* select a "subminor" number (part of a minor number) */ + down(&minor_table_mutex); + for (minor = 0; minor < MAX_DEVICES; ++minor) { + if (minor_table[minor] == NULL) + break; + } + if (minor >= MAX_DEVICES) { + info("Too many devices plugged in, cannot handle this device."); + goto exit; + } + + /* allocate memory for our device state and intialize it */ + dev = kmalloc(sizeof(struct usb_skel), GFP_KERNEL); + if (dev == NULL) { + err("Out of memory"); + goto exit; + } + memset(dev, 0x00, sizeof(*dev)); + minor_table[minor] = dev; + + interface = &udev->actconfig->interface[ifnum]; + + init_MUTEX(&dev->sem); + dev->udev = udev; + dev->interface = interface; + dev->minor = minor; + + /* set up and check the endpoint information */ + iface_desc = &interface->altsetting[0]; + for (i = 0; i < iface_desc->bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i]; + + if ((endpoint->bEndpointAddress & 0x80) && + ((endpoint->bmAttributes & 3) == 0x02)) { + /* we found a bulk in endpoint */ + buffer_size = endpoint->wMaxPacketSize; + dev->bulk_in_size = buffer_size; + dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; + dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); + if (!dev->bulk_in_buffer) { + err("Couldn't allocate bulk_in_buffer"); + goto error; + } + } + + if (((endpoint->bEndpointAddress & 0x80) == 0x00) && + ((endpoint->bmAttributes & 3) == 0x02)) { + /* we found a bulk out endpoint */ + dev->write_urb = usb_alloc_urb(0); + if (!dev->write_urb) { + err("No free urbs available"); + goto error; + } + buffer_size = endpoint->wMaxPacketSize; + dev->bulk_out_size = buffer_size; + dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; + dev->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL); + if (!dev->bulk_out_buffer) { + err("Couldn't allocate bulk_out_buffer"); + goto error; + } + FILL_BULK_URB(dev->write_urb, udev, + usb_sndbulkpipe(udev, + endpoint->bEndpointAddress), + dev->bulk_out_buffer, buffer_size, + cmdir_write_bulk_callback, dev); + } + } + + /* initialize the devfs node for this device and register it */ + sprintf(name, "commandir%d", dev->minor); + + dev->devfs = devfs_register(usb_devfs_handle, name, + DEVFS_FL_DEFAULT, USB_MAJOR, + USB_CMDIR_MINOR_BASE + dev->minor, + S_IFCHR | S_IRUSR | S_IWUSR | + S_IRGRP | S_IWGRP | S_IROTH, + &cmdir_fops, NULL); + + /* let the user know what node this device is now attached to */ + info("CommandIR USB device now attached to commandir%d", dev->minor); + + /* should reset just the one that was plugged in */ + reset_cmdir(minor); + + goto exit; + +error: + cmdir_delete(dev); + dev = NULL; + +exit: + up(&minor_table_mutex); + return dev; +} +#else +static int cmdir_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_skel *dev = NULL; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + size_t buffer_size; + + int i; + int retval = -ENOMEM; + int minor; + + /* allocate memory for our device state and initialize it */ + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + err("Out of memory"); + goto error; + } + memset(dev, 0x00, sizeof(*dev)); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9) + kref_init(&dev->kref, cmdir_delete); +#else + kref_init(&dev->kref); +#endif + dev->udev = usb_get_dev(interface_to_usbdev(interface)); + dev->interface = interface; + + /* set up the endpoint information */ + /* use only the first bulk-in and bulk-out endpoints */ + iface_desc = interface->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (!dev->bulk_in_endpointAddr && + (endpoint->bEndpointAddress & USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_BULK)) { + /* we found a bulk in endpoint */ + buffer_size = endpoint->wMaxPacketSize; + dev->bulk_in_size = buffer_size; + dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; + dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); + if (!dev->bulk_in_buffer) { + err("Could not allocate bulk_in_buffer"); + goto error; + } + } + + if (!dev->bulk_out_endpointAddr && + !(endpoint->bEndpointAddress & USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_BULK)) { + /* we found a bulk out endpoint */ + dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; + } + } + if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { + err("Could not find both bulk-in and bulk-out endpoints"); + goto error; + } + + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, dev); + + /* we can register the device now, as it is ready */ + retval = usb_register_dev(interface, &cmdir_class); + if (retval) { + /* something prevented us from registering this driver */ + err("Not able to get a minor for this device."); + usb_set_intfdata(interface, NULL); + goto error; + } + + /* check whether minor already includes base */ + minor = interface->minor; + if (minor >= USB_CMDIR_MINOR_BASE) + minor = minor-USB_CMDIR_MINOR_BASE; + + /* let the user know what node this device is now attached to */ + info("CommandIR USB device now attached to commandir%d", minor); + + reset_cmdir(minor); + + return 0; + +error: + if (dev) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9) + kref_put(&dev->kref); +#else + kref_put(&dev->kref, cmdir_delete); +#endif + return retval; +} +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +static int cmdir_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct usb_skel *dev; + + dev = (struct usb_skel *)file->private_data; + + /* lock this object */ + down(&dev->sem); + + /* verify that the device wasn't unplugged */ + if (dev->udev == NULL) { + up(&dev->sem); + return -ENODEV; + } + + /* unlock the device */ + up(&dev->sem); + + /* return that we did not understand this ioctl call */ + return -ENOTTY; +} +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +static void cmdir_disconnect(struct usb_device *udev, void *ptr) +{ + struct usb_skel *dev; + int minor; + + dev = (struct usb_skel *)ptr; + + down(&minor_table_mutex); + down(&dev->sem); + + minor = dev->minor; + + /* remove our devfs node */ + devfs_unregister(dev->devfs); + + /* if the device is not opened, then we clean up right now */ + if (!dev->open_count) { + up(&dev->sem); + cmdir_delete(dev); + } else { + dev->udev = NULL; + up(&dev->sem); + } + + info("CommandIR #%d now disconnected", minor); + up(&minor_table_mutex); + + /* check if default RX device still exists */ + if (minor == rx_device) { + /* decrement until find next valid device */ + while (rx_device > 0) { + rx_device--; + if (cmdir_check(rx_device) == 0) break; + } + if (minor > 0) + info("Active Receiver is on CommandIR #%d", rx_device); + } + +} +#else +static void cmdir_disconnect(struct usb_interface *interface) +{ + struct usb_skel *dev; + int minor = interface->minor; + + /* prevent cmdir_open() from racing cmdir_disconnect() */ + lock_kernel(); + + dev = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + /* give back our minor */ + usb_deregister_dev(interface, &cmdir_class); + + unlock_kernel(); + + /* decrement our usage count */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9) + kref_put(&dev->kref); +#else + kref_put(&dev->kref, cmdir_delete); +#endif + + /* check whether minor already includes base */ + if (minor >= USB_CMDIR_MINOR_BASE) + minor = minor-USB_CMDIR_MINOR_BASE; + + info("CommandIR #%d now disconnected", minor); + + /* check if default RX device still exists */ + if (minor == rx_device) { + /* decrement until find next valid device */ + while (rx_device > 0) { + rx_device--; + if (cmdir_check(rx_device) == 0) + break; + } + if (minor > 0) + info("Active Receiver is on CommandIR #%d", rx_device); + } +} +#endif + +static int cmdir_release(struct inode *inode, struct file *file) +{ + struct usb_skel *dev; + int retval = 0; + + dev = (struct usb_skel *)file->private_data; + if (dev == NULL) + /*dbg(" - object is NULL");*/ + return -ENODEV; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + + /* lock our minor table */ + down(&minor_table_mutex); + + /* lock our device */ + down(&dev->sem); + + if (dev->open_count <= 0) { + /*dbg(" - device not opened");*/ + retval = -ENODEV; + goto exit_not_opened; + } + + if (dev->udev == NULL) { + /* the device was unplugged before the file was released */ + /*dbg(" - device unplugged before file released");*/ + up(&dev->sem); + cmdir_delete(dev); + up(&minor_table_mutex); + MOD_DEC_USE_COUNT; + return 0; + } + + /* decrement our usage count for the device */ + --dev->open_count; + if (dev->open_count <= 0) { + /* shutdown any bulk writes that might be going on */ + usb_unlink_urb(dev->write_urb); + dev->open_count = 0; + } + + /* decrement our usage count for the module */ + MOD_DEC_USE_COUNT; + +exit_not_opened: + up(&dev->sem); + up(&minor_table_mutex); + + return retval; + +#else + /* decrement the count on our device */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9) + kref_put(&dev->kref); +#else + kref_put(&dev->kref, cmdir_delete); +#endif + return retval; +#endif +} + +static void __exit usb_cmdir_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&cmdir_driver); + +} + +static int cmdir_check(int device_num) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + if (minor_table[device_num] == NULL) + return -ENODEV; + return 0; +#else + struct usb_interface *interface; + + interface = usb_find_interface(&cmdir_driver, + USB_CMDIR_MINOR_BASE+device_num); + if (!interface) { + /* also check without adding base, for devfs */ + interface = usb_find_interface(&cmdir_driver, rx_device); + if (!interface) + return -ENODEV; + } + return 0; +#endif +} + +static void init_cmdir_var(int device_num) +{ + int i; + unsigned int multiplier = 1; + + for (i = 0; i < device_num; i++) + multiplier = multiplier*0x10; + transmitters |= multiplier * 0x0F; + next_transmitters = transmitters; + info("commandir%d reset", device_num); + return; +} + +static void reset_cmdir(int device_num) +{ + unsigned char ctrl_buffer[MCU_CTRL_SIZE]; + int retval; + int i; + + ctrl_buffer[0] = RESET_HEADER; + for (i = 1; i < MCU_CTRL_SIZE; i++) + ctrl_buffer[i] = 'j'; + retval = write_core(ctrl_buffer, MCU_CTRL_SIZE, NULL, device_num); + + init_cmdir_var(device_num); + print_cmdir(device_num); + + return; +} + +static void update_cmdir_string(int device_num) +{ + int next_comma = 0; + int next_pos = 25; + unsigned int multiplier; + int i; + + /* cmdir_var[] = "COMMANDIRx:\n" + * " TX Enabled: 1, 2, 3, 4\n" + * " RX: commandirx\n" + * " LCD: commandirx\n" */ + + cmdir_var[9] = ASCII0+device_num; + cmdir_var[50] = ASCII0+rx_device; + cmdir_var[67] = ASCII0+lcd_device; + + for (i = 25; i < 35; i++) + cmdir_var[i] = ' '; + + multiplier = 1; + for (i = 0; i < device_num; i++) + multiplier = multiplier*0x10; + + if (transmitters & (multiplier*0x01)) { + cmdir_var[next_pos] = '1'; + next_pos += 3; + next_comma++; + } + if (transmitters & (multiplier*0x02)) { + cmdir_var[next_pos] = '2'; + if (next_comma > 0) + cmdir_var[next_pos-2] = ','; + next_pos += 3; + next_comma++; + } + if (transmitters & (multiplier*0x04)) { + cmdir_var[next_pos] = '3'; + if (next_comma > 0) + cmdir_var[next_pos-2] = ','; + next_pos += 3; + next_comma++; + } + if (transmitters & (multiplier*0x08)) { + cmdir_var[next_pos] = '4'; + if (next_comma > 0) + cmdir_var[next_pos-2] = ','; + next_pos += 3; + next_comma++; + } + return; +} + +static void print_cmdir(int device_num) +{ + update_cmdir_string(device_num); + info("%s", cmdir_var); + return; +} + +static ssize_t cmdir_file_read(struct file *file, char *buffer, + size_t count, loff_t *ppos) +{ + int retval = 0; + int minor = 0; + struct usb_skel *dev; + + dev = (struct usb_skel *)file->private_data; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + minor = dev->minor; +#else + minor = dev->interface->minor; + if (minor >= USB_CMDIR_MINOR_BASE) + minor = minor - USB_CMDIR_MINOR_BASE; +#endif + + if (((int)*ppos) == 0) { + update_cmdir_string(minor); + if (copy_to_user(buffer, cmdir_var, CMDIR_VAR_LEN)) + retval = -EFAULT; + else + retval = CMDIR_VAR_LEN; + return retval; + } else + return 0; +} + +/* Read data from CommandIR */ +ssize_t cmdir_read(unsigned char *buffer, size_t count) +{ + struct usb_skel *dev; + int retval = 0; + int len; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + if (minor_table[rx_device] == NULL) + return -ENODEV; + dev = minor_table[rx_device]; + + /* lock this object */ + down(&dev->sem); + retval = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, + dev->bulk_in_endpointAddr), + dev->bulk_in_buffer, dev->bulk_in_size, &len, HZ*100); +#else + struct usb_interface *interface; + interface = usb_find_interface(&cmdir_driver, + USB_CMDIR_MINOR_BASE+rx_device); + if (!interface) { + /* also check without adding base, for devfs */ + interface = usb_find_interface(&cmdir_driver, rx_device); + if (!interface) + return -ENODEV; + } + dev = usb_get_intfdata(interface); + if (!dev) + return -ENODEV; + retval = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, + dev->bulk_in_endpointAddr), + dev->bulk_in_buffer, min(dev->bulk_in_size, count), + &len, HZ*10); +#endif + if (!retval) { + if (!memcpy(buffer, dev->bulk_in_buffer, len)) + retval = -EFAULT; + else { + /* current status of the TX buffer */ + curTXFill = buffer[2]; + retval = len; + } + } + /* suppress errors */ + /* + else { + err("Read from device failed, error %d",retval); + } + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + /* unlock the device */ + up(&dev->sem); +#endif + /* printk(KERN_INFO "CommandIR Reporting TX buffer at %d bytes. \n", + * curTXFill); */ + return retval; +} +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +EXPORT_SYMBOL_NOVERS(cmdir_read); +#else +EXPORT_SYMBOL(cmdir_read); +#endif + +static ssize_t cmdir_file_write(struct file *file, const char *buffer, + size_t count, loff_t *ppos) +{ + int retval; + int i; + int equalsign = 0; + int changeType = 0; + unsigned char ctrl_buffer[MCU_CTRL_SIZE]; + char *local_buffer; + int minor; + + /* set as default - if non-specific error, + * won't keep calling this function */ + retval = count; + local_buffer = kmalloc(count, GFP_KERNEL); + + /* verify that we actually have some data to write */ + if (count == 0) { + err("Write request of 0 bytes"); + goto exit; + } + if (count > 64) { + err("Input too long"); + goto exit; + } + + /* copy the data from userspace into our local buffer */ + if (copy_from_user(local_buffer, buffer, count)) { + retval = -EFAULT; + goto exit; + } + + /* parse code */ + changeType = cNothing; + equalsign = 0; + for (i = 0; i < MCU_CTRL_SIZE; i++) + ctrl_buffer[i] = 'j'; + + for (i = 0; i < count; i++) { + switch (local_buffer[i]) { + case 'X': + case 'x': + if ((i > 0) && ((local_buffer[i - 1] == 'R') + || (local_buffer[i - 1] == 'r'))) + changeType = cRX; + break; + case 'S': + case 's': + if ((i > 1) && ((local_buffer[i - 1] == 'E') + || (local_buffer[i - 1] == 'e'))) { + if ((local_buffer[i-2] == 'R') + || (local_buffer[i-2] == 'r')) + changeType = cRESET; + } + break; + case 'L': + case 'l': + if ((i > 0) && ((local_buffer[i - 1] == 'F') + || (local_buffer[i - 1] == 'f'))) + changeType = cFLASH; + break; + case 'C': + case 'c': + if ((i > 0) && ((local_buffer[i - 1] == 'L') + || (local_buffer[i - 1] == 'l'))) + changeType = cLCD; + break; + case '=': + if (changeType != cNothing) + equalsign = i; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + if (equalsign > 0) { + minor = local_buffer[i] - ASCII0; + switch (changeType) { + case cRESET: + ctrl_buffer[0] = RESET_HEADER; + retval = write_core(ctrl_buffer, + MCU_CTRL_SIZE, + cmdir_write_bulk_callback, + minor); + if (retval != MCU_CTRL_SIZE) { + if (retval == -ENODEV) + err("Device %d " + "unplugged", minor); + else + err("Error on write to " + "%d", minor); + goto exit; + } else + retval = count; + init_cmdir_var(minor); + break; + case cFLASH: + ctrl_buffer[0] = FLASH_HEADER; + info("Flashing indicators on device %d", + minor); + retval = write_core(ctrl_buffer, + MCU_CTRL_SIZE, + cmdir_write_bulk_callback, + minor); + if (retval != MCU_CTRL_SIZE) { + if (retval == -ENODEV) + err("Device %d " + "unplugged", minor); + else + err("Error on write to " + "%d", minor); + goto exit; + } else + retval = count; + break; + case cRX: + rx_device = minor; + info("Default receiver set to %d", + minor); + break; + case cLCD: + lcd_device = minor; + info("commandir: Default LCD set to %d", + minor); + break; + default: + break; + } + } + break; + case ',': + equalsign = 0; + changeType = cNothing; + break; + default: + if ((equalsign > 0) && (local_buffer[i] > 32)) { + err("Non-numerical argument"); + goto exit; + } + break; + } + } + + if ((changeType != cNothing) && (equalsign == 0)) + err("No device specified"); + if (changeType == cNothing) + err("Unknown command"); + +exit: + kfree(local_buffer); + return retval; +} + +int cmdir_write(unsigned char *buffer, int count, + void *callback_fct, int usecdelay) +{ + /* Always add to queue, then send queue number + * no locks + * mbodkin, Sept 8, 2005 */ + int ret = 0; + if (debug_commandir == 1) { + do_gettimeofday(&tp); + printk(KERN_INFO "cmdir_write at %d\n", (int)tp.tv_usec); + } + ret = add_cmdir_queue(buffer, count, callback_fct, usecdelay); + + if (ret == -1) { + printk(KERN_INFO "cmdir_write returning 0\n"); + return 0; + } + return count; + +} +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +EXPORT_SYMBOL_NOVERS(cmdir_write); +#else +EXPORT_SYMBOL(cmdir_write); +#endif + +int add_cmdir_queue(unsigned char *buffer, int count, + void *callback_vct, int usecdelay) +{ + int ret = 0; + if ((nexttofill + 1) % (QUEUELENGTH - 1) == nexttosend) { + + /* our buffer is full */ + printk(KERN_INFO "Too many packets backlogged " + "in CommandIR Queue.\n"); + return -1; + } + /* go ahead and use this one: */ + memcpy(ourbuffers[nexttofill], buffer, count); + ourbufferlengths[nexttofill] = count; + waitusecs[nexttofill] = (usecdelay == 0) ? 10000 : usecdelay; + /* printk(KERN_INFO "Adding %d to queue at position %d.\n", + * count, nexttofill); */ + nexttofill = (nexttofill + 1) % (QUEUELENGTH - 1); + ret = nexttofill; + /* if (timer_running == 0) */ + send_queue(); /* fake it if the timer's not running */ + return ret; /* we accepted the full packet */ + +} + +int send_queue() +{ + int last_sent = 0; + int ret = 0; + if (debug_commandir == 1) { + do_gettimeofday(&tp); + printk(KERN_INFO "Send_queue() at %d\n", (int)tp.tv_usec); + } + /* initiate the send/callback routine if not already running. */ + if (send_status == SEND_IDLE) { + if (!(nexttofill == nexttosend)) { + /* start it up: */ + + last_sent = nexttosend - 1; + if (last_sent < 0) + last_sent = QUEUELENGTH - 1; + /* Final check - is it TIME to send this packet yet? */ + /* if (wait_to_tx(waitusecs[last_sent]) == 0) { */ + /* always send if there's room, + * otherwise wait until room */ + if (curTXFill < 190) { + if (debug_commandir == 1) { + do_gettimeofday(&tp); + printk(KERN_INFO "Sending packet data " + "at %d\n", (int)tp.tv_usec); + } + ret = cmdir_write_queue(ourbuffers[nexttosend], + ourbufferlengths[nexttosend], NULL); + if (ret <= 0) { + /* send failed - the device is either + * unplugged or full + * nexttosend = + * (nexttosend + 1) + * % (QUEUELENGTH - 1); */ + send_status = SEND_IDLE; + return 0; /*send_queue(); */ + } else + nexttosend = (nexttosend + 1) + % (QUEUELENGTH - 1); + return 1; + } else { + if (debug_commandir == 1) { + do_gettimeofday(&tp); + printk(KERN_INFO "Not time to send yet " + "- starting timer at %d.\n", + (int)tp.tv_usec); + printk(KERN_INFO "Enabling timer.\n"); + } + return 0; /* doesn't matter anymore */ + } + } else { + if (debug_commandir == 1) { + do_gettimeofday(&tp); + printk(KERN_INFO "No more data to send %d!\n", + (int)tp.tv_usec); + } + last_tx_sec = 0; /* reset our TX counters */ + last_tx_usec = 0; + return 1; /* nothing more to send! */ + } + } else { + if (debug_commandir == 1) + /* will try again on the callback */ + printk(KERN_INFO "Already sending\n"); + return 1; /* then the timer shouldn't be running... */ + } + return 0; /* should never get here... */ +} + + +int wait_to_tx(int usecs) +{ + /* don't return until last_time + usecs has been reached + * for non-zero last_tx's. */ + int wait_until_sec = 0, wait_until_usec = 0; + int now_sec = 0, now_usec = 0; + if (debug_commandir == 1) + printk(KERN_INFO "waittotx(%d)\n", usecs); + if (usecs == 0) + return 0; + + if (!(last_tx_sec == 0 && last_tx_usec == 0)) { + /* calculate wait time: */ + wait_until_sec = last_tx_sec + (usecs / 1000000); + wait_until_usec = last_tx_usec + usecs; + + do_gettimeofday(&tp); + now_sec = tp.tv_sec; + now_usec = tp.tv_usec; + + if (wait_until_usec > 1000000) { + /* we've spilled over to the next second. */ + wait_until_sec++; + wait_until_usec -= 1000000; + /* printk(KERN_INFO "usec rollover\n"); */ + } + if (debug_commandir == 1) + printk(KERN_INFO "Testing for the right second, now = " + "%d %d, wait = %d %d\n", + now_sec, now_usec, + wait_until_sec, wait_until_usec); + /* now we are always on the same second. */ + if (now_sec > wait_until_sec) { + if (debug_commandir == 1) + printk(KERN_INFO "Setting last_tx_sec to %d.\n", + wait_until_sec); + last_tx_sec = wait_until_sec; + last_tx_usec = wait_until_usec; + return 0; + } + + if ((now_sec == wait_until_sec) + && (now_usec > wait_until_usec)) { + if (debug_commandir == 1) + printk(KERN_INFO "Setting last_tx_sec to %d.\n", + wait_until_sec); + last_tx_sec = wait_until_sec; + last_tx_usec = wait_until_usec; + return 0; + } + return -1; /* didn't send */ + } + + do_gettimeofday(&tp); + last_tx_usec = tp.tv_usec; + last_tx_sec = tp.tv_sec; + return 0; /* if there's no last even, go ahead and send */ +} + + +int cmdir_write_queue(unsigned char *buffer, int count, void *callback_fct) +{ + int retval = count; + static char prev_signal_num; + unsigned char next_mask; + unsigned int multiplier; + int i; + + send_status = SEND_ACTIVE; + + if (count < 2) { + err("Not enough bytes (write request of %d bytes)", count); + return count; + } + + /* check data; decide which device to send to */ + switch (buffer[0]) { + case TX_HEADER: + case TX_HEADER_NEW: + /* this is LIRC transmit data */ + if (curTXFill >= 190) { + printk(KERN_INFO + "TX buffer too full to send more TX data\n"); + return 0; + } + if (next_transmitters != transmitters) { + if (buffer[1] != prev_signal_num) + /* this is new signal; change transmitter mask*/ + transmitters = next_transmitters; + } + prev_signal_num = buffer[1]; + + multiplier = 1; + for (i = 0; i < MAX_DEVICES; i++) { + next_mask = 0; + if (transmitters & (0x01*multiplier)) + next_mask |= TX1_ENABLE; + if (transmitters & (0x02*multiplier)) + next_mask |= TX2_ENABLE; + if (transmitters & (0x04*multiplier)) + next_mask |= TX3_ENABLE; + if (transmitters & (0x08*multiplier)) + next_mask |= TX4_ENABLE; + + if (next_mask > 0) { + buffer[1] = next_mask; + retval = write_core(buffer, count, + callback_fct, i); + if (retval != count) { + if (retval == -ENODEV) + err("Device %d not plugged in", + i); + else + err("Write error to device %d", + i); + return retval; + } + } + multiplier = multiplier*0x10; + } + return retval; + break; + case LCD_HEADER: + return write_core(buffer, count, callback_fct, lcd_device); + break; + default: + return write_core(buffer, count, callback_fct, def_device); + break; + } + /* should never get here */ + return retval; + +} + +int write_core(unsigned char *buffer, int count, + void *callback_fct, int device_num) +{ + struct usb_skel *dev; + int retval = count; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + ssize_t bytes_written = 0; + if (minor_table[device_num] == NULL) + /* device is unplugged */ + return -ENODEV; + dev = minor_table[device_num]; + + /* lock this object */ + down(&dev->sem); + + /* see if we are already in the middle of a write */ + if (dev->write_urb->status == -EINPROGRESS) { + /*suppress errors - should just try sending again*/ + /*dbg(" - already writing");*/ + retval = -EINPROGRESS; + goto exit; + } + + /* we can only write as much as 1 urb will hold */ + bytes_written = (count > dev->bulk_out_size) ? + dev->bulk_out_size : count; + + /* copy the data into our urb */ + if (!(memcpy(dev->write_urb->transfer_buffer, buffer, bytes_written))) { + retval = -EFAULT; + goto exit; + } + + /* set up our urb */ + if (callback_fct == NULL) { + /*FILL_BULK_URB(dev->write_urb, dev->udev, + usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), + dev->write_urb->transfer_buffer, bytes_written, + cmdir_write_bulk_callback, dev); */ + usb_fill_bulk_urb(dev->write_urb, dev->udev, + usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), + dev->write_urb->transfer_buffer, bytes_written, + cmdir_write_bulk_callback, dev); + } else { + FILL_BULK_URB(dev->write_urb, dev->udev, + usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), + dev->write_urb->transfer_buffer, bytes_written, + callback_fct, dev); + } + + /* send the data out the bulk port */ + retval = usb_submit_urb(dev->write_urb); + if (!(retval)) + retval = bytes_written; + /* suppress errors */ + /* else { + err("Failed submitting write urb, error %d", retval); + } */ +exit: + /* unlock the device */ + up(&dev->sem); + return retval; /* this should be return error I think */ + +#else + struct usb_interface *interface; + struct urb *urb = NULL; + char *buf = NULL; + interface = usb_find_interface(&cmdir_driver, + USB_CMDIR_MINOR_BASE + device_num); + if (!interface) { + /* also check without adding base, for devfs */ + interface = usb_find_interface(&cmdir_driver, device_num); + if (!interface) + return -ENODEV; + } + dev = usb_get_intfdata(interface); + if (!dev) + return -ENODEV; + /* create a urb, and a buffer for it, and copy the data to the urb */ + urb = usb_alloc_urb(0, GFP_ATOMIC); /* Now -=Atomic=- */ + if (!urb) { + retval = -ENOMEM; + goto error; + } + buf = usb_buffer_alloc(dev->udev, count, + GFP_KERNEL, &urb->transfer_dma); + if (!buf) { + retval = -ENOMEM; + goto error; + } + if (!memcpy(buf, buffer, count)) { + retval = -EFAULT; + goto error; + } + /* initialize the urb properly */ + if (callback_fct == NULL) { + usb_fill_bulk_urb(urb, dev->udev, + usb_sndbulkpipe(dev->udev, + dev->bulk_out_endpointAddr), + buf, count, (void *) cmdir_write_bulk_callback, dev); + } else { + usb_fill_bulk_urb(urb, dev->udev, + usb_sndbulkpipe(dev->udev, + dev->bulk_out_endpointAddr), + buf, count, callback_fct, dev); + } + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* double check this */ + + /* send the data out the bulk port */ + retval = usb_submit_urb(urb, GFP_KERNEL); + if (retval) { + err("%s - failed submitting write urb, error %d", + __FUNCTION__, retval); + goto error; + } + + /* release our reference to this urb, the USB + * core will eventually free it entirely */ + usb_free_urb(urb); + return count; + +error: + usb_buffer_free(dev->udev, count, buf, urb->transfer_dma); + usb_free_urb(urb); + return retval; +#endif +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +static void cmdir_write_bulk_callback(struct urb *urb) +{ + if (debug_commandir == 1) { + do_gettimeofday(&tp); + printk(KERN_INFO "cmdir_write_bulk_callback at %d\n", + (int)tp.tv_usec); + } + /*if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)) + return; + else { + dbg(" - urb status: %d", urb->status); + return; + }*/ + + send_status = SEND_IDLE; + /* printk(KERN_INFO "cmdir_write_bulk_callback - set idle\n"); */ + send_queue(); /* send the next packet */ + return; +} +#else +static void cmdir_write_bulk_callback(struct urb *urb, struct pt_regs *regs) +{ + struct usb_skel *dev; + dev = (struct usb_skel *)urb->context; + send_status = SEND_IDLE; + if (debug_commandir == 1) + printk(KERN_INFO "callback()\n"); + /* free up our allocated buffer */ + + usb_buffer_free(urb->dev, urb->transfer_buffer_length, + urb->transfer_buffer, urb->transfer_dma); + send_queue(); /* send the next packet */ + +} +#endif + +int set_tx_channels(unsigned int next_tx) +{ + next_transmitters = next_tx; + return 0; +} +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +EXPORT_SYMBOL_NOVERS(set_tx_channels); +#else +EXPORT_SYMBOL(set_tx_channels); +#endif + +module_init(usb_cmdir_init); +module_exit(usb_cmdir_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); --- linux-2.6.27.orig/ubuntu/lirc/lirc_ttusbir/Makefile +++ linux-2.6.27/ubuntu/lirc/lirc_ttusbir/Makefile @@ -0,0 +1,3 @@ +EXTRA_CFLAGS =-DIRCTL_DEV_MAJOR=61 -DLIRC_SERIAL_TRANSMITTER -DLIRC_SERIAL_SOFTCARRIER -I$(src)/.. + +obj-$(CONFIG_LIRC_TTUSBIR) += lirc_ttusbir.o --- linux-2.6.27.orig/ubuntu/lirc/lirc_ttusbir/lirc_ttusbir.c +++ linux-2.6.27/ubuntu/lirc/lirc_ttusbir/lirc_ttusbir.c @@ -0,0 +1,401 @@ +/**************************************************************************** + ** lirc_ttusbir.c *********************************************************** + **************************************************************************** + * + * lirc_ttusbir - LIRC device driver for the TechnoTrend USB IR Receiver + * + * Copyright (C) 2007 Stefan Macher + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* This LIRC driver provides access to the TechnoTrend USB IR Receiver. + * The receiver delivers the IR signal as raw sampled true/false data in + * isochronous USB packets each of size 128 byte. + * Currently the driver reduces the sampling rate by factor of 8 as this + * is still more than enough to decode RC-5 - others should be analyzed. + * But the driver does not rely on RC-5 it should be able to decode every + * IR signal that is not too fast. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "lirc.h" +#include "kcompat.h" +#include "lirc_dev/lirc_dev.h" + +MODULE_DESCRIPTION("TechnoTrend USB IR device driver for LIRC"); +MODULE_AUTHOR("Stefan Macher (st_maker-lirc@yahoo.de)"); +MODULE_LICENSE("GPL"); + +/* #define DEBUG */ +#ifdef DEBUG +#define DPRINTK printk +#else +#define DPRINTK(_x_, a...) +#endif + +/* function declarations */ +static int probe(struct usb_interface *intf, const struct usb_device_id *id); +static void disconnect(struct usb_interface *intf); +#if defined(KERNEL_2_5) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void urb_complete(struct urb *urb, struct pt_regs *pt_regs); +#else +static void urb_complete(struct urb *urb); +#endif +static int set_use_inc(void *data); +static void set_use_dec(void *data); + +static int num_urbs = 2; +module_param(num_urbs, int, 0444); +MODULE_PARM_DESC(num_urbs, + "Number of URBs in queue. Try to increase to 4 in case " + "of problems (default: 2; minimum: 2)"); + +/* table of devices that work with this driver */ +static struct usb_device_id device_id_table[] = { + { USB_DEVICE(0x0B48, 0x2003) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, device_id_table); + +/* USB driver definition */ +static struct usb_driver driver = { + .name = "TTUSBIR", + .id_table = &(device_id_table[0]), + .probe = probe, + .disconnect = disconnect, +}; + +/* USB device definition */ +struct ttusbir_device { + struct usb_driver *driver; + struct usb_device *udev; + struct usb_interface *interf; + struct usb_class_driver class_driver; + unsigned int ifnum; /* Interface number to use */ + unsigned int alt_setting; /* alternate setting to use */ + unsigned int endpoint; /* Endpoint to use */ + struct urb **urb; /* num_urb URB pointers*/ + char **buffer; /* 128 byte buffer for each URB */ + struct lirc_buffer rbuf; /* Buffer towards LIRC */ + struct lirc_plugin plugin; + int minor; + int last_pulse; /* remembers if last received byte was pulse or space */ + int last_num; /* remembers how many last bytes appeared */ + int opened; +}; + +/************************************* + * LIRC specific functions + */ +static int set_use_inc(void *data) +{ + int i; + struct ttusbir_device *ttusbir = data; + + DPRINTK("Sending first URBs\n"); + /* @TODO Do I need to check if I am already opened */ + ttusbir->opened = 1; + + for (i = 0; i < num_urbs; i++) + usb_submit_urb(ttusbir->urb[i], GFP_KERNEL); + + return 0; +} + +static void set_use_dec(void *data) +{ + struct ttusbir_device *ttusbir = data; + + DPRINTK("Device closed\n"); + + ttusbir->opened = 0; +} + +/************************************* + * USB specific functions + */ + +/* This mapping table is used to do a very simple filtering of the + * input signal. + * For a value with at least 4 bits set it returns 0xFF otherwise + * 0x00. For faster IR signals this can not be used. But for RC-5 we + * still have about 14 samples per pulse/space, i.e. we sample with 14 + * times higher frequency than the signal frequency */ +const unsigned char map_table[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +#if defined(KERNEL_2_5) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void urb_complete(struct urb *urb, struct pt_regs *pt_regs) +#else +static void urb_complete(struct urb *urb) +#endif +{ + struct ttusbir_device *ttusbir; + unsigned char *buf; + int i; + lirc_t l; + + ttusbir = urb->context; + + if (!ttusbir->opened) + return; + + buf = (unsigned char *)urb->transfer_buffer; + + for (i = 0; i < 128; i++) { + /* Here we do the filtering and some kind of down sampling */ + buf[i] = ~map_table[buf[i]]; + if (ttusbir->last_pulse == buf[i]) { + if (ttusbir->last_num < PULSE_MASK/63) + ttusbir->last_num++; + /* else we are in a idle period and do not need to + * increment any longer */ + } else { + l = ttusbir->last_num * 62; /* about 62 = us/byte */ + if (ttusbir->last_pulse) /* pulse or space? */ + l |= PULSE_BIT; + if (!lirc_buffer_full(&ttusbir->rbuf)) { + lirc_buffer_write_1(&ttusbir->rbuf, (void *)&l); + wake_up_interruptible(&ttusbir->rbuf.wait_poll); + } + ttusbir->last_num = 0; + ttusbir->last_pulse = buf[i]; + } + } + usb_submit_urb(urb, GFP_ATOMIC); /* keep data rolling :-) */ +} + +/* Called whenever the USB subsystem thinks we could be the right driver + to handle this device +*/ +static int probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + int alt_set, endp; + int found = 0; + int i, j; + int struct_size; + struct usb_host_interface *host_interf; + struct usb_interface_descriptor *interf_desc; + struct usb_host_endpoint *host_endpoint; + struct ttusbir_device *ttusbir; + + DPRINTK("Module ttusbir probe\n"); + + /* To reduce memory fragmentation we use only one allocation */ + struct_size = sizeof(struct ttusbir_device) + + (sizeof(struct urb *) * num_urbs) + + (sizeof(char *) * num_urbs) + + (num_urbs * 128); + ttusbir = kmalloc(struct_size, GFP_KERNEL); + if (!ttusbir) + return -ENOMEM; + memset(ttusbir, 0, struct_size); + + ttusbir->urb = (struct urb **)((char *)ttusbir + + sizeof(struct ttusbir_device)); + ttusbir->buffer = (char **)((char *)ttusbir->urb + + (sizeof(struct urb *) * num_urbs)); + for (i = 0; i < num_urbs; i++) + ttusbir->buffer[i] = (char *)ttusbir->buffer + + (sizeof(char *)*num_urbs) + (i * 128); + + ttusbir->driver = &driver; + ttusbir->alt_setting = -1; + /* @TODO check if error can be returned */ + ttusbir->udev = usb_get_dev(interface_to_usbdev(intf)); + ttusbir->interf = intf; + ttusbir->last_pulse = 0x00; + ttusbir->last_num = 0; + + /* Now look for interface setting we can handle + We are searching for the alt setting where end point + 0x82 has max packet size 16 + */ + for (alt_set = 0; alt_set < intf->num_altsetting && !found; alt_set++) { + host_interf = &intf->altsetting[alt_set]; + interf_desc = &host_interf->desc; + for (endp = 0; endp < interf_desc->bNumEndpoints; endp++) { + host_endpoint = &host_interf->endpoint[endp]; + if ((host_endpoint->desc.bEndpointAddress == 0x82) && + (host_endpoint->desc.wMaxPacketSize == 0x10)) { + ttusbir->alt_setting = alt_set; + ttusbir->endpoint = endp; + found = 1; + break; + } + } + } + if (ttusbir->alt_setting != -1) + DPRINTK("alt setting: %d\n", ttusbir->alt_setting); + else { + err("Could not find alternate setting\n"); + kfree(ttusbir); + return -EINVAL; + } + + /* OK lets setup this interface setting */ + usb_set_interface(ttusbir->udev, 0, ttusbir->alt_setting); + + /* Store device info in interface structure */ + usb_set_intfdata(intf, ttusbir); + + /* Register as a LIRC plugin */ + if (lirc_buffer_init(&ttusbir->rbuf, sizeof(lirc_t), 256) < 0) { + err("Could not get memory for LIRC data buffer\n"); + usb_set_intfdata(intf, NULL); + kfree(ttusbir); + return -ENOMEM; + } + strcpy(ttusbir->plugin.name, "TTUSBIR"); + ttusbir->plugin.minor = -1; + ttusbir->plugin.code_length = 1; + ttusbir->plugin.sample_rate = 0; + ttusbir->plugin.data = ttusbir; + ttusbir->plugin.add_to_buf = NULL; + ttusbir->plugin.get_queue = NULL; + ttusbir->plugin.rbuf = &ttusbir->rbuf; + ttusbir->plugin.set_use_inc = set_use_inc; + ttusbir->plugin.set_use_dec = set_use_dec; + ttusbir->plugin.ioctl = NULL; + ttusbir->plugin.fops = NULL; + ttusbir->plugin.owner = THIS_MODULE; + ttusbir->plugin.features = LIRC_CAN_REC_MODE2; + ttusbir->minor = lirc_register_plugin(&ttusbir->plugin); + if (ttusbir->minor < 0) { + err("Error registering as LIRC plugin\n"); + usb_set_intfdata(intf, NULL); + lirc_buffer_free(&ttusbir->rbuf); + kfree(ttusbir); + return -EIO; + } + + /* Allocate and setup the URB that we will use to talk to the device */ + for (i = 0; i < num_urbs; i++) { + ttusbir->urb[i] = usb_alloc_urb(8, GFP_KERNEL); + if (!ttusbir->urb[i]) { + err("Could not allocate memory for the URB\n"); + for (j = i - 1; j >= 0; j--) + kfree(ttusbir->urb[j]); + lirc_buffer_free(&ttusbir->rbuf); + lirc_unregister_plugin(ttusbir->minor); + kfree(ttusbir); + usb_set_intfdata(intf, NULL); + return -ENOMEM; + } + ttusbir->urb[i]->dev = ttusbir->udev; + ttusbir->urb[i]->context = ttusbir; + ttusbir->urb[i]->pipe = usb_rcvisocpipe(ttusbir->udev, + ttusbir->endpoint); + ttusbir->urb[i]->interval = 1; + ttusbir->urb[i]->transfer_flags = URB_ISO_ASAP; + ttusbir->urb[i]->transfer_buffer = &ttusbir->buffer[i][0]; + ttusbir->urb[i]->complete = urb_complete; + ttusbir->urb[i]->number_of_packets = 8; + ttusbir->urb[i]->transfer_buffer_length = 128; + for (j = 0; j < 8; j++) { + ttusbir->urb[i]->iso_frame_desc[j].offset = j*16; + ttusbir->urb[i]->iso_frame_desc[j].length = 16; + } + } + return 0; +} + +/* Called when the driver is unloaded or the device is unplugged + */ +static void disconnect(struct usb_interface *intf) +{ + int i; + struct ttusbir_device *ttusbir; + + DPRINTK("Module ttusbir disconnect\n"); + + ttusbir = (struct ttusbir_device *) usb_get_intfdata(intf); + usb_set_intfdata(intf, NULL); + lirc_unregister_plugin(ttusbir->minor); + DPRINTK("unregistered\n"); + + for (i = 0; i < num_urbs; i++) { + usb_kill_urb(ttusbir->urb[i]); + usb_free_urb(ttusbir->urb[i]); + } + DPRINTK("URBs killed\n"); + lirc_buffer_free(&ttusbir->rbuf); + kfree(ttusbir); +} + +static int ttusbir_init_module(void) +{ + int result; + + DPRINTK(KERN_DEBUG "Module ttusbir init\n"); + + /* register this driver with the USB subsystem */ + result = usb_register(&driver); + if (result) + err("usb_register failed. Error number %d", result); + return result; +} + +static void ttusbir_exit_module(void) +{ + printk(KERN_DEBUG "Module ttusbir exit\n"); + /* deregister this driver with the USB subsystem */ + usb_deregister(&driver); +} + +module_init(ttusbir_init_module); +module_exit(ttusbir_exit_module); --- linux-2.6.27.orig/ubuntu/lirc/lirc_dev/Makefile +++ linux-2.6.27/ubuntu/lirc/lirc_dev/Makefile @@ -0,0 +1,3 @@ +EXTRA_CFLAGS =-DIRCTL_DEV_MAJOR=61 -DLIRC_SERIAL_TRANSMITTER -DLIRC_SERIAL_SOFTCARRIER -I$(src)/.. + +obj-$(CONFIG_LIRC_DEV) += lirc_dev.o --- linux-2.6.27.orig/ubuntu/lirc/lirc_dev/lirc_dev.h +++ linux-2.6.27/ubuntu/lirc/lirc_dev/lirc_dev.h @@ -0,0 +1,264 @@ +/* + * LIRC base driver + * + * (L) by Artur Lipowski + * This code is licensed under GNU GPL + * + * $Id: lirc_dev.h,v 1.22 2008/01/13 10:45:02 lirc Exp $ + * + */ + +#ifndef _LINUX_LIRC_DEV_H +#define _LINUX_LIRC_DEV_H + +#define MAX_IRCTL_DEVICES 4 +#define BUFLEN 16 + +/* #define LIRC_BUFF_POWER_OF_2 */ +#ifdef LIRC_BUFF_POWER_OF_2 +#define mod(n, div) ((n) & ((div) - 1)) +#else +#define mod(n, div) ((n) % (div)) +#endif +#include +#include + +struct lirc_buffer { + wait_queue_head_t wait_poll; + spinlock_t lock; + + unsigned char *data; + unsigned int chunk_size; + unsigned int size; /* in chunks */ + unsigned int fill; /* in chunks */ + int head, tail; /* in chunks */ + /* Using chunks instead of bytes pretends to simplify boundary checking + * And should allow for some performance fine tunning later */ +}; +static inline void _lirc_buffer_clear(struct lirc_buffer *buf) +{ + buf->head = 0; + buf->tail = 0; + buf->fill = 0; +} +static inline int lirc_buffer_init(struct lirc_buffer *buf, + unsigned int chunk_size, + unsigned int size) +{ + /* Adjusting size to the next power of 2 would allow for + * inconditional LIRC_BUFF_POWER_OF_2 optimization */ + init_waitqueue_head(&buf->wait_poll); + spin_lock_init(&buf->lock); + _lirc_buffer_clear(buf); + buf->chunk_size = chunk_size; + buf->size = size; + buf->data = kmalloc(size*chunk_size, GFP_KERNEL); + if (buf->data == NULL) + return -1; + memset(buf->data, 0, size*chunk_size); + return 0; +} +static inline void lirc_buffer_free(struct lirc_buffer *buf) +{ + kfree(buf->data); + buf->data = NULL; + buf->head = 0; + buf->tail = 0; + buf->fill = 0; + buf->chunk_size = 0; + buf->size = 0; +} +static inline int lirc_buffer_full(struct lirc_buffer *buf) +{ + return (buf->fill >= buf->size); +} +static inline int lirc_buffer_empty(struct lirc_buffer *buf) +{ + return !(buf->fill); +} +static inline int lirc_buffer_available(struct lirc_buffer *buf) +{ + return (buf->size - buf->fill); +} +static inline void lirc_buffer_lock(struct lirc_buffer *buf, + unsigned long *flags) +{ + spin_lock_irqsave(&buf->lock, *flags); +} +static inline void lirc_buffer_unlock(struct lirc_buffer *buf, + unsigned long *flags) +{ + spin_unlock_irqrestore(&buf->lock, *flags); +} +static inline void lirc_buffer_clear(struct lirc_buffer *buf) +{ + unsigned long flags; + lirc_buffer_lock(buf, &flags); + _lirc_buffer_clear(buf); + lirc_buffer_unlock(buf, &flags); +} +static inline void _lirc_buffer_remove_1(struct lirc_buffer *buf) +{ + buf->head = mod(buf->head+1, buf->size); + buf->fill -= 1; +} +static inline void lirc_buffer_remove_1(struct lirc_buffer *buf) +{ + unsigned long flags; + lirc_buffer_lock(buf, &flags); + _lirc_buffer_remove_1(buf); + lirc_buffer_unlock(buf, &flags); +} +static inline void _lirc_buffer_read_1(struct lirc_buffer *buf, + unsigned char *dest) +{ + memcpy(dest, &buf->data[buf->head*buf->chunk_size], buf->chunk_size); + buf->head = mod(buf->head+1, buf->size); + buf->fill -= 1; +} +static inline void lirc_buffer_read_1(struct lirc_buffer *buf, + unsigned char *dest) +{ + unsigned long flags; + lirc_buffer_lock(buf, &flags); + _lirc_buffer_read_1(buf, dest); + lirc_buffer_unlock(buf, &flags); +} +static inline void _lirc_buffer_write_1(struct lirc_buffer *buf, + unsigned char *orig) +{ + memcpy(&buf->data[buf->tail*buf->chunk_size], orig, buf->chunk_size); + buf->tail = mod(buf->tail+1, buf->size); + buf->fill++; +} +static inline void lirc_buffer_write_1(struct lirc_buffer *buf, + unsigned char *orig) +{ + unsigned long flags; + lirc_buffer_lock(buf, &flags); + _lirc_buffer_write_1(buf, orig); + lirc_buffer_unlock(buf, &flags); +} +static inline void _lirc_buffer_write_n(struct lirc_buffer *buf, + unsigned char *orig, int count) +{ + memcpy(&buf->data[buf->tail * buf->chunk_size], orig, + count * buf->chunk_size); + buf->tail = mod(buf->tail + count, buf->size); + buf->fill += count; +} +static inline void lirc_buffer_write_n(struct lirc_buffer *buf, + unsigned char *orig, int count) +{ + unsigned long flags; + int space1; + + lirc_buffer_lock(buf, &flags); + if (buf->head > buf->tail) + space1 = buf->head - buf->tail; + else + space1 = buf->size - buf->tail; + + if (count > space1) { + _lirc_buffer_write_n(buf, orig, space1); + _lirc_buffer_write_n(buf, orig+(space1*buf->chunk_size), + count-space1); + } else { + _lirc_buffer_write_n(buf, orig, count); + } + lirc_buffer_unlock(buf, &flags); +} + +struct lirc_plugin { + char name[40]; + int minor; + int code_length; + int sample_rate; + unsigned long features; + void *data; + int (*add_to_buf) (void *data, struct lirc_buffer *buf); + wait_queue_head_t* (*get_queue) (void *data); + struct lirc_buffer *rbuf; + int (*set_use_inc) (void *data); + void (*set_use_dec) (void *data); + int (*ioctl) (struct inode *, struct file *, unsigned int, + unsigned long); + struct file_operations *fops; + struct device *dev; + struct module *owner; +}; +/* name: + * this string will be used for logs + * + * minor: + * indicates minor device (/dev/lirc) number for registered plugin + * if caller fills it with negative value, then the first free minor + * number will be used (if available) + * + * code_length: + * length of the remote control key code expressed in bits + * + * sample_rate: + * sample_rate equal to 0 means that no polling will be performed and + * add_to_buf will be triggered by external events (through task queue + * returned by get_queue) + * + * data: + * it may point to any plugin data and this pointer will be passed to + * all callback functions + * + * add_to_buf: + * add_to_buf will be called after specified period of the time or + * triggered by the external event, this behavior depends on value of + * the sample_rate this function will be called in user context. This + * routine should return 0 if data was added to the buffer and + * -ENODATA if none was available. This should add some number of bits + * evenly divisible by code_length to the buffer + * + * get_queue: + * this callback should return a pointer to the task queue which will + * be used for external event waiting + * + * rbuf: + * if not NULL, it will be used as a read buffer, you will have to + * write to the buffer by other means, like irq's (see also + * lirc_serial.c). + * + * set_use_inc: + * set_use_inc will be called after device is opened + * + * set_use_dec: + * set_use_dec will be called after device is closed + * + * ioctl: + * Some ioctl's can be directly handled by lirc_dev but will be + * forwared here if not NULL and only handled if it returns + * -ENOIOCTLCMD (see also lirc_serial.c). + * + * fops: + * file_operations for drivers which don't fit the current plugin model. + * + * owner: + * the module owning this struct + * + */ + + +/* following functions can be called ONLY from user context + * + * returns negative value on error or minor number + * of the registered device if success + * contens of the structure pointed by p is copied + */ +extern int lirc_register_plugin(struct lirc_plugin *p); + +/* returns negative value on error or 0 if success +*/ +extern int lirc_unregister_plugin(int minor); + +/* Returns the private data stored in the lirc_plugin + * associated with the given device file pointer. + */ +void *lirc_get_pdata(struct file *file); + +#endif --- linux-2.6.27.orig/ubuntu/lirc/lirc_dev/lirc_dev.c +++ linux-2.6.27/ubuntu/lirc/lirc_dev/lirc_dev.c @@ -0,0 +1,960 @@ +/* + * LIRC base driver + * + * (L) by Artur Lipowski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: lirc_dev.c,v 1.58 2008/05/14 16:37:49 lirc Exp $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) +#error "**********************************************************" +#error " Sorry, this driver needs kernel version 2.2.18 or higher " +#error "**********************************************************" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) +#include +#include +#else +#include +#include +#endif +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) +#include +#endif +#define __KERNEL_SYSCALLS__ +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) +#include +#endif + +#include "kcompat.h" + +/* SysFS header */ +#if defined(LIRC_HAVE_SYSFS) +#include +#endif + +#include "lirc.h" +#include "lirc_dev.h" + +static int debug; +#define dprintk(fmt, args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG fmt, ## args); \ + } while (0) + +#define IRCTL_DEV_NAME "BaseRemoteCtl" +#define SUCCESS 0 +#define NOPLUG -1 +#define LOGHEAD "lirc_dev (%s[%d]): " + +struct irctl { + struct lirc_plugin p; + int attached; + int open; + + struct semaphore buffer_sem; + struct lirc_buffer *buf; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) + int tpid; + struct completion *t_notify; + struct completion *t_notify2; + int shutdown; +#else + struct task_struct *task; +#endif + long jiffies_to_wait; + +#ifdef LIRC_HAVE_DEVFS_24 + devfs_handle_t devfs_handle; +#endif +}; + +DECLARE_MUTEX(plugin_lock); + +static struct irctl irctls[MAX_IRCTL_DEVICES]; +static struct file_operations fops; + +/* Only used for sysfs but defined to void otherwise */ +static lirc_class_t *lirc_class; + +/* helper function + * initializes the irctl structure + */ +static inline void init_irctl(struct irctl *ir) +{ + memset(&ir->p, 0, sizeof(struct lirc_plugin)); + sema_init(&ir->buffer_sem, 1); + ir->p.minor = NOPLUG; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) + ir->tpid = -1; + ir->t_notify = NULL; + ir->t_notify2 = NULL; + ir->shutdown = 0; +#else + ir->task = NULL; +#endif + ir->jiffies_to_wait = 0; + + ir->open = 0; + ir->attached = 0; +} + +static void cleanup(struct irctl *ir) +{ + dprintk(LOGHEAD "cleaning up\n", ir->p.name, ir->p.minor); + +#ifdef LIRC_HAVE_DEVFS_24 + devfs_unregister(ir->devfs_handle); +#endif +#ifdef LIRC_HAVE_DEVFS_26 + devfs_remove(DEV_LIRC "/%u", ir->p.minor); +#endif + lirc_device_destroy(lirc_class, + MKDEV(IRCTL_DEV_MAJOR, ir->p.minor)); + + if (ir->buf != ir->p.rbuf) { + lirc_buffer_free(ir->buf); + kfree(ir->buf); + } + ir->buf = NULL; + + init_irctl(ir); +} + +/* helper function + * reads key codes from plugin and puts them into buffer + * buffer free space is checked and locking performed + * returns 0 on success + */ +static inline int add_to_buf(struct irctl *ir) +{ + if (lirc_buffer_full(ir->buf)) { + dprintk(LOGHEAD "buffer overflow\n", + ir->p.name, ir->p.minor); + return -EOVERFLOW; + } + + if (ir->p.add_to_buf) { + int res = -ENODATA; + int got_data = 0; + + /* service the device as long as it is returning + * data and we have space + */ + while (!lirc_buffer_full(ir->buf)) { + res = ir->p.add_to_buf(ir->p.data, ir->buf); + if (res == SUCCESS) + got_data++; + else + break; + } + + if (res == -ENODEV) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) + ir->shutdown = 1; +#else + kthread_stop(ir->task); +#endif + + return (got_data ? SUCCESS : res); + } + + return SUCCESS; +} + +/* main function of the polling thread + */ +static int lirc_thread(void *irctl) +{ + struct irctl *ir = irctl; + + /* This thread doesn't need any user-level access, + * so get rid of all our resources + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) + daemonize("lirc_dev"); + + if (ir->t_notify != NULL) + complete(ir->t_notify); +#endif + + dprintk(LOGHEAD "poll thread started\n", ir->p.name, ir->p.minor); + + do { + if (ir->open) { + if (ir->jiffies_to_wait) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(ir->jiffies_to_wait); + } else { + interruptible_sleep_on( + ir->p.get_queue(ir->p.data)); + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) + if (ir->shutdown) +#else + if (kthread_should_stop()) +#endif + break; + if (!add_to_buf(ir)) + wake_up_interruptible(&ir->buf->wait_poll); + } else { + /* if device not opened so we can sleep half a second */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/2); + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) + } while (!ir->shutdown); + + if (ir->t_notify2 != NULL) + wait_for_completion(ir->t_notify2); + + ir->tpid = -1; + if (ir->t_notify != NULL) + complete(ir->t_notify); +#else + } while (!kthread_should_stop()); +#endif + + dprintk(LOGHEAD "poll thread ended\n", ir->p.name, ir->p.minor); + + return 0; +} + +int lirc_register_plugin(struct lirc_plugin *p) +{ + struct irctl *ir; + int minor; + int bytes_in_key; + int err; +#ifdef LIRC_HAVE_DEVFS_24 + char name[16]; +#endif + DECLARE_COMPLETION(tn); + + if (!p) { + printk(KERN_ERR "lirc_dev: lirc_register_plugin: " + "plugin pointer must be not NULL!\n"); + err = -EBADRQC; + goto out; + } + + if (MAX_IRCTL_DEVICES <= p->minor) { + printk(KERN_ERR "lirc_dev: lirc_register_plugin: " + "\"minor\" must be between 0 and %d (%d)!\n", + MAX_IRCTL_DEVICES-1, p->minor); + err = -EBADRQC; + goto out; + } + + if (1 > p->code_length || (BUFLEN * 8) < p->code_length) { + printk(KERN_ERR "lirc_dev: lirc_register_plugin: " + "code length in bits for minor (%d) " + "must be less than %d!\n", + p->minor, BUFLEN * 8); + err = -EBADRQC; + goto out; + } + + printk(KERN_INFO "lirc_dev: lirc_register_plugin: sample_rate: %d\n", + p->sample_rate); + if (p->sample_rate) { + if (2 > p->sample_rate || HZ < p->sample_rate) { + printk(KERN_ERR "lirc_dev: lirc_register_plugin: " + "sample_rate must be between 2 and %d!\n", HZ); + err = -EBADRQC; + goto out; + } + if (!p->add_to_buf) { + printk(KERN_ERR "lirc_dev: lirc_register_plugin: " + "add_to_buf cannot be NULL when " + "sample_rate is set\n"); + err = -EBADRQC; + goto out; + } + } else if (!(p->fops && p->fops->read) + && !p->get_queue && !p->rbuf) { + printk(KERN_ERR "lirc_dev: lirc_register_plugin: " + "fops->read, get_queue and rbuf " + "cannot all be NULL!\n"); + err = -EBADRQC; + goto out; + } else if (!p->get_queue && !p->rbuf) { + if (!(p->fops && p->fops->read && p->fops->poll) + || (!p->fops->ioctl && !p->ioctl)) { + printk(KERN_ERR "lirc_dev: lirc_register_plugin: " + "neither read, poll nor ioctl can be NULL!\n"); + err = -EBADRQC; + goto out; + } + } + + if (p->owner == NULL) { + printk(KERN_ERR "lirc_dev: lirc_register_plugin: " + "no module owner registered\n"); + err = -EBADRQC; + goto out; + } + + down(&plugin_lock); + + minor = p->minor; + + if (0 > minor) { + /* find first free slot for plugin */ + for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++) + if (irctls[minor].p.minor == NOPLUG) + break; + if (MAX_IRCTL_DEVICES == minor) { + printk(KERN_ERR "lirc_dev: lirc_register_plugin: " + "no free slots for plugins!\n"); + err = -ENOMEM; + goto out_lock; + } + } else if (irctls[minor].p.minor != NOPLUG) { + printk(KERN_ERR "lirc_dev: lirc_register_plugin: " + "minor (%d) just registered!\n", minor); + err = -EBUSY; + goto out_lock; + } + + ir = &irctls[minor]; + + if (p->sample_rate) { + ir->jiffies_to_wait = HZ / p->sample_rate; + } else { + /* it means - wait for external event in task queue */ + ir->jiffies_to_wait = 0; + } + + /* some safety check 8-) */ + p->name[sizeof(p->name)-1] = '\0'; + + bytes_in_key = p->code_length/8 + (p->code_length%8 ? 1 : 0); + + if (p->rbuf) { + ir->buf = p->rbuf; + } else { + ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); + if (!ir->buf) { + err = -ENOMEM; + goto out_lock; + } + if (lirc_buffer_init(ir->buf, bytes_in_key, + BUFLEN/bytes_in_key) != 0) { + kfree(ir->buf); + err = -ENOMEM; + goto out_lock; + } + } + + if (p->features == 0) + p->features = (p->code_length > 8) ? + LIRC_CAN_REC_LIRCCODE : LIRC_CAN_REC_CODE; + + ir->p = *p; + ir->p.minor = minor; + +#if defined(LIRC_HAVE_DEVFS_24) + sprintf(name, DEV_LIRC "/%d", ir->p.minor); + ir->devfs_handle = devfs_register(NULL, name, DEVFS_FL_DEFAULT, + IRCTL_DEV_MAJOR, ir->p.minor, + S_IFCHR | S_IRUSR | S_IWUSR, + &fops, NULL); +#elif defined(LIRC_HAVE_DEVFS_26) + devfs_mk_cdev(MKDEV(IRCTL_DEV_MAJOR, ir->p.minor), + S_IFCHR|S_IRUSR|S_IWUSR, + DEV_LIRC "/%u", ir->p.minor); +#endif + (void) device_create(lirc_class, ir->p.dev, + MKDEV(IRCTL_DEV_MAJOR, ir->p.minor), + NULL, "lirc%u", ir->p.minor); + + if (p->sample_rate || p->get_queue) { + /* try to fire up polling thread */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) + ir->t_notify = &tn; + ir->tpid = kernel_thread(lirc_thread, (void *)ir, 0); + if (ir->tpid < 0) { +#else + ir->task = kthread_run(lirc_thread, (void *)ir, "lirc_dev"); + if (IS_ERR(ir->task)) { +#endif + printk(KERN_ERR "lirc_dev: lirc_register_plugin: " + "cannot run poll thread for minor = %d\n", + p->minor); + err = -ECHILD; + goto out_sysfs; + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) + wait_for_completion(&tn); + ir->t_notify = NULL; +#endif + } + ir->attached = 1; + up(&plugin_lock); + +/* + * Recent kernels should handle this autmatically by increasing/decreasing + * use count when a dependant module is loaded/unloaded. + */ +#ifndef KERNEL_2_5 + MOD_INC_USE_COUNT; +#endif + dprintk("lirc_dev: plugin %s registered at minor number = %d\n", + ir->p.name, ir->p.minor); + p->minor = minor; + return minor; + +out_sysfs: + lirc_device_destroy(lirc_class, + MKDEV(IRCTL_DEV_MAJOR, ir->p.minor)); +#ifdef LIRC_HAVE_DEVFS_24 + devfs_unregister(ir->devfs_handle); +#endif +#ifdef LIRC_HAVE_DEVFS_26 + devfs_remove(DEV_LIRC "/%i", ir->p.minor); +#endif +out_lock: + up(&plugin_lock); +out: + return err; +} +EXPORT_SYMBOL(lirc_register_plugin); + +int lirc_unregister_plugin(int minor) +{ + struct irctl *ir; + DECLARE_COMPLETION(tn); + DECLARE_COMPLETION(tn2); + + if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { + printk(KERN_ERR "lirc_dev: lirc_unregister_plugin: " + "\"minor\" must be between 0 and %d!\n", + MAX_IRCTL_DEVICES-1); + return -EBADRQC; + } + + ir = &irctls[minor]; + + down(&plugin_lock); + + if (ir->p.minor != minor) { + printk(KERN_ERR "lirc_dev: lirc_unregister_plugin: " + "minor (%d) device not registered!", minor); + up(&plugin_lock); + return -ENOENT; + } + + /* end up polling thread */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) + if (ir->tpid >= 0) { + ir->t_notify = &tn; + ir->t_notify2 = &tn2; + ir->shutdown = 1; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) + { + struct task_struct *p; + + p = find_task_by_pid(ir->tpid); + wake_up_process(p); + } +#else + /* 2.2.x does not export wake_up_process() */ + wake_up_interruptible(ir->p.get_queue(ir->p.data)); +#endif + complete(&tn2); + wait_for_completion(&tn); + ir->t_notify = NULL; + ir->t_notify2 = NULL; + } +#else /* kernel >= 2.6.23 */ + if (ir->task) { + wake_up_process(ir->task); + kthread_stop(ir->task); + } +#endif + + dprintk("lirc_dev: plugin %s unregistered from minor number = %d\n", + ir->p.name, ir->p.minor); + + ir->attached = 0; + if (ir->open) { + dprintk(LOGHEAD "releasing opened plugin\n", + ir->p.name, ir->p.minor); + wake_up_interruptible(&ir->buf->wait_poll); + down(&ir->buffer_sem); + ir->p.set_use_dec(ir->p.data); + module_put(ir->p.owner); + up(&ir->buffer_sem); + } else + cleanup(ir); + up(&plugin_lock); + +/* + * Recent kernels should handle this autmatically by increasing/decreasing + * use count when a dependant module is loaded/unloaded. + */ +#ifndef KERNEL_2_5 + MOD_DEC_USE_COUNT; +#endif + + return SUCCESS; +} +EXPORT_SYMBOL(lirc_unregister_plugin); + +/* + * + */ +static int irctl_open(struct inode *inode, struct file *file) +{ + struct irctl *ir; + int retval; + + if (MINOR(inode->i_rdev) >= MAX_IRCTL_DEVICES) { + dprintk("lirc_dev [%d]: open result = -ENODEV\n", + MINOR(inode->i_rdev)); + return -ENODEV; + } + + ir = &irctls[MINOR(inode->i_rdev)]; + + dprintk(LOGHEAD "open called\n", ir->p.name, ir->p.minor); + + /* if the plugin has an open function use it instead */ + if (ir->p.fops && ir->p.fops->open) + return ir->p.fops->open(inode, file); + + if (down_interruptible(&plugin_lock)) + return -ERESTARTSYS; + + if (ir->p.minor == NOPLUG) { + up(&plugin_lock); + dprintk(LOGHEAD "open result = -ENODEV\n", + ir->p.name, ir->p.minor); + return -ENODEV; + } + + if (ir->open) { + up(&plugin_lock); + dprintk(LOGHEAD "open result = -EBUSY\n", + ir->p.name, ir->p.minor); + return -EBUSY; + } + + /* there is no need for locking here because ir->open is 0 + * and lirc_thread isn't using buffer + * plugins which use irq's should allocate them on set_use_inc, + * so there should be no problem with those either. + */ + ir->buf->head = ir->buf->tail; + ir->buf->fill = 0; + + if (ir->p.owner != NULL && try_module_get(ir->p.owner)) { + ++ir->open; + retval = ir->p.set_use_inc(ir->p.data); + + if (retval != SUCCESS) { + module_put(ir->p.owner); + --ir->open; + } + } else { + if (ir->p.owner == NULL) + dprintk(LOGHEAD "no module owner!!!\n", + ir->p.name, ir->p.minor); + + retval = -ENODEV; + } + + dprintk(LOGHEAD "open result = %d\n", ir->p.name, ir->p.minor, retval); + up(&plugin_lock); + + return retval; +} + +/* + * + */ +static int irctl_close(struct inode *inode, struct file *file) +{ + struct irctl *ir = &irctls[MINOR(inode->i_rdev)]; + + dprintk(LOGHEAD "close called\n", ir->p.name, ir->p.minor); + + /* if the plugin has a close function use it instead */ + if (ir->p.fops && ir->p.fops->release) + return ir->p.fops->release(inode, file); + + if (down_interruptible(&plugin_lock)) + return -ERESTARTSYS; + + --ir->open; + if (ir->attached) { + ir->p.set_use_dec(ir->p.data); + module_put(ir->p.owner); + } else { + cleanup(ir); + } + + up(&plugin_lock); + + return SUCCESS; +} + +/* + * + */ +static unsigned int irctl_poll(struct file *file, poll_table *wait) +{ + struct irctl *ir = &irctls[MINOR(file->f_dentry->d_inode->i_rdev)]; + unsigned int ret; + + dprintk(LOGHEAD "poll called\n", ir->p.name, ir->p.minor); + + /* if the plugin has a poll function use it instead */ + if (ir->p.fops && ir->p.fops->poll) + return ir->p.fops->poll(file, wait); + + down(&ir->buffer_sem); + if (!ir->attached) { + up(&ir->buffer_sem); + return POLLERR; + } + + poll_wait(file, &ir->buf->wait_poll, wait); + + dprintk(LOGHEAD "poll result = %s\n", + ir->p.name, ir->p.minor, + lirc_buffer_empty(ir->buf) ? "0" : "POLLIN|POLLRDNORM"); + + ret = lirc_buffer_empty(ir->buf) ? 0 : (POLLIN|POLLRDNORM); + + up(&ir->buffer_sem); + return ret; +} + +/* + * + */ +static int irctl_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned long mode; + int result; + struct irctl *ir = &irctls[MINOR(inode->i_rdev)]; + + dprintk(LOGHEAD "ioctl called (0x%x)\n", + ir->p.name, ir->p.minor, cmd); + + /* if the plugin has a ioctl function use it instead */ + if (ir->p.fops && ir->p.fops->ioctl) + return ir->p.fops->ioctl(inode, file, cmd, arg); + + if (ir->p.minor == NOPLUG || !ir->attached) { + dprintk(LOGHEAD "ioctl result = -ENODEV\n", + ir->p.name, ir->p.minor); + return -ENODEV; + } + + /* Give the plugin a chance to handle the ioctl */ + if (ir->p.ioctl) { + result = ir->p.ioctl(inode, file, cmd, arg); + if (result != -ENOIOCTLCMD) + return result; + } + /* The plugin can't handle cmd */ + result = SUCCESS; + + switch (cmd) { + case LIRC_GET_FEATURES: + result = put_user(ir->p.features, (unsigned long *)arg); + break; + case LIRC_GET_REC_MODE: + if (!(ir->p.features&LIRC_CAN_REC_MASK)) + return -ENOSYS; + + result = put_user(LIRC_REC2MODE + (ir->p.features&LIRC_CAN_REC_MASK), + (unsigned long *)arg); + break; + case LIRC_SET_REC_MODE: + if (!(ir->p.features&LIRC_CAN_REC_MASK)) + return -ENOSYS; + + result = get_user(mode, (unsigned long *)arg); + if (!result && !(LIRC_MODE2REC(mode) & ir->p.features)) + result = -EINVAL; + /* + * FIXME: We should actually set the mode somehow but + * for now, lirc_serial doesn't support mode changing either + */ + break; + case LIRC_GET_LENGTH: + result = put_user((unsigned long)ir->p.code_length, + (unsigned long *)arg); + break; + default: + result = -ENOIOCTLCMD; + } + + dprintk(LOGHEAD "ioctl result = %d\n", + ir->p.name, ir->p.minor, result); + + return result; +} + +/* + * + */ +static ssize_t irctl_read(struct file *file, + char *buffer, + size_t length, + loff_t *ppos) +{ + struct irctl *ir = &irctls[MINOR(file->f_dentry->d_inode->i_rdev)]; + unsigned char buf[ir->buf->chunk_size]; + int ret = 0, written = 0; + DECLARE_WAITQUEUE(wait, current); + + dprintk(LOGHEAD "read called\n", ir->p.name, ir->p.minor); + + /* if the plugin has a specific read function use it instead */ + if (ir->p.fops && ir->p.fops->read) + return ir->p.fops->read(file, buffer, length, ppos); + + if (down_interruptible(&ir->buffer_sem)) + return -ERESTARTSYS; + if (!ir->attached) { + up(&ir->buffer_sem); + return -ENODEV; + } + + if (length % ir->buf->chunk_size) { + dprintk(LOGHEAD "read result = -EINVAL\n", + ir->p.name, ir->p.minor); + up(&ir->buffer_sem); + return -EINVAL; + } + + /* + * we add ourselves to the task queue before buffer check + * to avoid losing scan code (in case when queue is awaken somewhere + * beetwen while condition checking and scheduling) + */ + add_wait_queue(&ir->buf->wait_poll, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + /* + * while we did't provide 'length' bytes, device is opened in blocking + * mode and 'copy_to_user' is happy, wait for data. + */ + while (written < length && ret == 0) { + if (lirc_buffer_empty(ir->buf)) { + /* According to the read(2) man page, 'written' can be + * returned as less than 'length', instead of blocking + * again, returning -EWOULDBLOCK, or returning + * -ERESTARTSYS */ + if (written) + break; + if (file->f_flags & O_NONBLOCK) { + ret = -EWOULDBLOCK; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + if (!ir->attached) { + ret = -ENODEV; + break; + } + } else { + lirc_buffer_read_1(ir->buf, buf); + ret = copy_to_user((void *)buffer+written, buf, + ir->buf->chunk_size); + written += ir->buf->chunk_size; + } + } + + remove_wait_queue(&ir->buf->wait_poll, &wait); + set_current_state(TASK_RUNNING); + up(&ir->buffer_sem); + + dprintk(LOGHEAD "read result = %s (%d)\n", + ir->p.name, ir->p.minor, ret ? "-EFAULT" : "OK", ret); + + return ret ? ret : written; +} + + +void *lirc_get_pdata(struct file *file) +{ + void *data = NULL; + + if (file && file->f_dentry && file->f_dentry->d_inode && + file->f_dentry->d_inode->i_rdev) { + struct irctl *ir; + ir = &irctls[MINOR(file->f_dentry->d_inode->i_rdev)]; + data = ir->p.data; + } + + return data; +} +EXPORT_SYMBOL(lirc_get_pdata); + + +static ssize_t irctl_write(struct file *file, const char *buffer, + size_t length, loff_t *ppos) +{ + struct irctl *ir = &irctls[MINOR(file->f_dentry->d_inode->i_rdev)]; + + dprintk(LOGHEAD "write called\n", ir->p.name, ir->p.minor); + + /* if the plugin has a specific read function use it instead */ + if (ir->p.fops && ir->p.fops->write) + return ir->p.fops->write(file, buffer, length, ppos); + + if (!ir->attached) + return -ENODEV; + + return -EINVAL; +} + + +static struct file_operations fops = { + .read = irctl_read, + .write = irctl_write, + .poll = irctl_poll, + .ioctl = irctl_ioctl, + .open = irctl_open, + .release = irctl_close +}; + + +static int lirc_dev_init(void) +{ + int i; + + for (i = 0; i < MAX_IRCTL_DEVICES; ++i) + init_irctl(&irctls[i]); + + if (register_chrdev(IRCTL_DEV_MAJOR, IRCTL_DEV_NAME, &fops)) { + printk(KERN_ERR "lirc_dev: register_chrdev failed\n"); + goto out; + } + + lirc_class = class_create(THIS_MODULE, "lirc"); + if (IS_ERR(lirc_class)) { + printk(KERN_ERR "lirc_dev: class_create failed\n"); + goto out_unregister; + } + + printk(KERN_INFO "lirc_dev: IR Remote Control driver registered, " + "major %d \n", IRCTL_DEV_MAJOR); + + return SUCCESS; + +out_unregister: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) + if (unregister_chrdev(IRCTL_DEV_MAJOR, IRCTL_DEV_NAME)) + printk(KERN_ERR "lirc_dev: unregister_chrdev failed!\n"); +#else + /* unregister_chrdev returns void now */ + unregister_chrdev(IRCTL_DEV_MAJOR, IRCTL_DEV_NAME); +#endif +out: + return -1; +} + +/* ---------------------------------------------------------------------- */ + +/* For now dont try to use it as a static version ! */ + +#ifdef MODULE + +/* + * + */ +int init_module(void) +{ + return lirc_dev_init(); +} + +/* + * + */ +void cleanup_module(void) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) + int ret; + + ret = unregister_chrdev(IRCTL_DEV_MAJOR, IRCTL_DEV_NAME); + class_destroy(lirc_class); + + if (ret) + printk(KERN_ERR "lirc_dev: error in " + "module_unregister_chrdev: %d\n", ret); + else + dprintk("lirc_dev: module successfully unloaded\n"); +#else + /* unregister_chrdev returns void now */ + unregister_chrdev(IRCTL_DEV_MAJOR, IRCTL_DEV_NAME); + class_destroy(lirc_class); + dprintk("lirc_dev: module unloaded\n"); +#endif +} + +MODULE_DESCRIPTION("LIRC base driver module"); +MODULE_AUTHOR("Artur Lipowski"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV_MAJOR(IRCTL_DEV_MAJOR); + +module_param(debug, bool, 0644); +MODULE_PARM_DESC(debug, "Enable debugging messages"); + +#endif /* MODULE */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.6.27.orig/ubuntu/squashfs/Kconfig +++ linux-2.6.27/ubuntu/squashfs/Kconfig @@ -0,0 +1,50 @@ +config SQUASHFS + tristate "SquashFS 3.3 - Squashed file system support" + select ZLIB_INFLATE + help + Saying Y here includes support for SquashFS 3.3 (a Compressed + Read-Only File System). Squashfs is a highly compressed read-only + filesystem for Linux. It uses zlib compression to compress both + files, inodes and directories. Inodes in the system are very small + and all blocks are packed to minimise data overhead. Block sizes + greater than 4K are supported up to a maximum of 1 Mbytes (default + block size 128K). SquashFS 3.3 supports 64 bit filesystems and files + (larger than 4GB), full uid/gid information, hard links and timestamps. + + Squashfs is intended for general read-only filesystem use, for + archival use (i.e. in cases where a .tar.gz file may be used), and in + embedded systems where low overhead is needed. Further information + and filesystem tools are available from http://squashfs.sourceforge.net. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module + will be called squashfs. Note that the root file system (the one + containing the directory /) cannot be compiled as a module. + + If unsure, say N. + +config SQUASHFS_EMBEDDED + + bool "Additional option for memory-constrained systems" + depends on SQUASHFS + default n + help + Saying Y here allows you to specify cache size. + + If unsure, say N. + +config SQUASHFS_FRAGMENT_CACHE_SIZE + int "Number of fragments cached" if SQUASHFS_EMBEDDED + depends on SQUASHFS + default "3" + help + By default SquashFS caches the last 3 fragments read from + the filesystem. Increasing this amount may mean SquashFS + has to re-read fragments less often from disk, at the expense + of extra system memory. Decreasing this amount will mean + SquashFS uses less memory at the expense of extra reads from disk. + + Note there must be at least one cached fragment. Anything + much more than three will probably not make much difference. + --- linux-2.6.27.orig/ubuntu/squashfs/inode.c +++ linux-2.6.27/ubuntu/squashfs/inode.c @@ -0,0 +1,2187 @@ +/* + * Squashfs - a compressed read only filesystem for Linux + * + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 + * Phillip Lougher + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * inode.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "squashfs.h" + +int squashfs_cached_blks; + +#ifdef USE_EXPORT +static struct dentry *squashfs_get_parent(struct dentry *child); +#endif + +static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode); +static int squashfs_statfs(struct dentry *, struct kstatfs *); +static int squashfs_symlink_readpage(struct file *file, struct page *page); +static long long read_blocklist(struct inode *inode, int index, + int readahead_blks, char *block_list, + unsigned short **block_p, unsigned int *bsize); +static int squashfs_readpage(struct file *file, struct page *page); +static int squashfs_readdir(struct file *, void *, filldir_t); +static struct dentry *squashfs_lookup(struct inode *, struct dentry *, + struct nameidata *); +static int squashfs_remount(struct super_block *s, int *flags, char *data); +static void squashfs_put_super(struct super_block *); +static int squashfs_get_sb(struct file_system_type *,int, const char *, void *, + struct vfsmount *); +static struct inode *squashfs_alloc_inode(struct super_block *sb); +static void squashfs_destroy_inode(struct inode *inode); +static int init_inodecache(void); +static void destroy_inodecache(void); + +static struct file_system_type squashfs_fs_type = { + .owner = THIS_MODULE, + .name = "squashfs", + .get_sb = squashfs_get_sb, + .kill_sb = kill_block_super, + .fs_flags = FS_REQUIRES_DEV +}; + +static const unsigned char squashfs_filetype_table[] = { + DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK +}; + +static struct super_operations squashfs_super_ops = { + .alloc_inode = squashfs_alloc_inode, + .destroy_inode = squashfs_destroy_inode, + .statfs = squashfs_statfs, + .put_super = squashfs_put_super, + .remount_fs = squashfs_remount +}; + +static struct super_operations squashfs_export_super_ops = { + .alloc_inode = squashfs_alloc_inode, + .destroy_inode = squashfs_destroy_inode, + .statfs = squashfs_statfs, + .put_super = squashfs_put_super, +}; + +#ifdef USE_EXPORT +static struct export_operations squashfs_export_ops = { + .get_parent = squashfs_get_parent +}; +#endif + +SQSH_EXTERN const struct address_space_operations squashfs_symlink_aops = { + .readpage = squashfs_symlink_readpage +}; + +SQSH_EXTERN const struct address_space_operations squashfs_aops = { + .readpage = squashfs_readpage +}; + +static const struct file_operations squashfs_dir_ops = { + .read = generic_read_dir, + .readdir = squashfs_readdir +}; + +SQSH_EXTERN struct inode_operations squashfs_dir_inode_ops = { + .lookup = squashfs_lookup +}; + + +static struct buffer_head *get_block_length(struct super_block *s, + int *cur_index, int *offset, int *c_byte) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + unsigned short temp; + struct buffer_head *bh; + + if (!(bh = sb_bread(s, *cur_index))) + goto out; + + if (msblk->devblksize - *offset == 1) { + if (msblk->swap) + ((unsigned char *) &temp)[1] = *((unsigned char *) + (bh->b_data + *offset)); + else + ((unsigned char *) &temp)[0] = *((unsigned char *) + (bh->b_data + *offset)); + brelse(bh); + if (!(bh = sb_bread(s, ++(*cur_index)))) + goto out; + if (msblk->swap) + ((unsigned char *) &temp)[0] = *((unsigned char *) + bh->b_data); + else + ((unsigned char *) &temp)[1] = *((unsigned char *) + bh->b_data); + *c_byte = temp; + *offset = 1; + } else { + if (msblk->swap) { + ((unsigned char *) &temp)[1] = *((unsigned char *) + (bh->b_data + *offset)); + ((unsigned char *) &temp)[0] = *((unsigned char *) + (bh->b_data + *offset + 1)); + } else { + ((unsigned char *) &temp)[0] = *((unsigned char *) + (bh->b_data + *offset)); + ((unsigned char *) &temp)[1] = *((unsigned char *) + (bh->b_data + *offset + 1)); + } + *c_byte = temp; + *offset += 2; + } + + if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) { + if (*offset == msblk->devblksize) { + brelse(bh); + if (!(bh = sb_bread(s, ++(*cur_index)))) + goto out; + *offset = 0; + } + if (*((unsigned char *) (bh->b_data + *offset)) != + SQUASHFS_MARKER_BYTE) { + ERROR("Metadata block marker corrupt @ %x\n", + *cur_index); + brelse(bh); + goto out; + } + (*offset)++; + } + return bh; + +out: + return NULL; +} + + +SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, + long long index, unsigned int length, + long long *next_index, int srclength) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + struct buffer_head **bh; + unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1); + unsigned int cur_index = index >> msblk->devblksize_log2; + int bytes, avail_bytes, b = 0, k = 0; + unsigned int compressed; + unsigned int c_byte = length; + + bh = kmalloc(((sblk->block_size >> msblk->devblksize_log2) + 1) * + sizeof(struct buffer_head *), GFP_KERNEL); + if (bh == NULL) + goto read_failure; + + if (c_byte) { + bytes = msblk->devblksize - offset; + compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte); + c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); + + TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index, + compressed ? "" : "un", (unsigned int) c_byte, srclength); + + if (c_byte > srclength || index < 0 || (index + c_byte) > sblk->bytes_used) + goto read_failure; + + bh[0] = sb_getblk(s, cur_index); + if (bh[0] == NULL) + goto block_release; + + for (b = 1; bytes < c_byte; b++) { + bh[b] = sb_getblk(s, ++cur_index); + if (bh[b] == NULL) + goto block_release; + bytes += msblk->devblksize; + } + ll_rw_block(READ, b, bh); + } else { + if (index < 0 || (index + 2) > sblk->bytes_used) + goto read_failure; + + bh[0] = get_block_length(s, &cur_index, &offset, &c_byte); + if (bh[0] == NULL) + goto read_failure; + + bytes = msblk->devblksize - offset; + compressed = SQUASHFS_COMPRESSED(c_byte); + c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); + + TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed + ? "" : "un", (unsigned int) c_byte); + + if (c_byte > srclength || (index + c_byte) > sblk->bytes_used) + goto read_failure; + + for (b = 1; bytes < c_byte; b++) { + bh[b] = sb_getblk(s, ++cur_index); + if (bh[b] == NULL) + goto block_release; + bytes += msblk->devblksize; + } + ll_rw_block(READ, b - 1, bh + 1); + } + + if (compressed) { + int zlib_err = 0; + + /* + * uncompress block + */ + + mutex_lock(&msblk->read_data_mutex); + + msblk->stream.next_out = buffer; + msblk->stream.avail_out = srclength; + + for (bytes = 0; k < b; k++) { + avail_bytes = min(c_byte - bytes, msblk->devblksize - offset); + + wait_on_buffer(bh[k]); + if (!buffer_uptodate(bh[k])) + goto release_mutex; + + msblk->stream.next_in = bh[k]->b_data + offset; + msblk->stream.avail_in = avail_bytes; + + if (k == 0) { + zlib_err = zlib_inflateInit(&msblk->stream); + if (zlib_err != Z_OK) { + ERROR("zlib_inflateInit returned unexpected result 0x%x," + " srclength %d\n", zlib_err, srclength); + goto release_mutex; + } + + if (avail_bytes == 0) { + offset = 0; + brelse(bh[k]); + continue; + } + } + + zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH); + if (zlib_err != Z_OK && zlib_err != Z_STREAM_END) { + ERROR("zlib_inflate returned unexpected result 0x%x," + " srclength %d, avail_in %d, avail_out %d\n", zlib_err, + srclength, msblk->stream.avail_in, msblk->stream.avail_out); + goto release_mutex; + } + + bytes += avail_bytes; + offset = 0; + brelse(bh[k]); + } + + if (zlib_err != Z_STREAM_END) + goto release_mutex; + + zlib_err = zlib_inflateEnd(&msblk->stream); + if (zlib_err != Z_OK) { + ERROR("zlib_inflateEnd returned unexpected result 0x%x," + " srclength %d\n", zlib_err, srclength); + goto release_mutex; + } + bytes = msblk->stream.total_out; + mutex_unlock(&msblk->read_data_mutex); + } else { + int i; + + for(i = 0; i < b; i++) { + wait_on_buffer(bh[i]); + if (!buffer_uptodate(bh[i])) + goto block_release; + } + + for (bytes = 0; k < b; k++) { + avail_bytes = min(c_byte - bytes, msblk->devblksize - offset); + + memcpy(buffer + bytes, bh[k]->b_data + offset, avail_bytes); + bytes += avail_bytes; + offset = 0; + brelse(bh[k]); + } + } + + if (next_index) + *next_index = index + c_byte + (length ? 0 : + (SQUASHFS_CHECK_DATA(msblk->sblk.flags) ? 3 : 2)); + + kfree(bh); + return bytes; + +release_mutex: + mutex_unlock(&msblk->read_data_mutex); + +block_release: + for (; k < b; k++) + brelse(bh[k]); + +read_failure: + ERROR("sb_bread failed reading block 0x%x\n", cur_index); + kfree(bh); + return 0; +} + + +SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, void *buffer, + long long block, unsigned int offset, + int length, long long *next_block, + unsigned int *next_offset) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + int n, i, bytes, return_length = length; + long long next_index; + + TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset); + + while (1) { + for (i = 0; i < squashfs_cached_blks; i++) + if (msblk->block_cache[i].block == block) + break; + + mutex_lock(&msblk->block_cache_mutex); + + if (i == squashfs_cached_blks) { + /* read inode header block */ + if (msblk->unused_cache_blks == 0) { + mutex_unlock(&msblk->block_cache_mutex); + wait_event(msblk->waitq, msblk->unused_cache_blks); + continue; + } + + i = msblk->next_cache; + for (n = 0; n < squashfs_cached_blks; n++) { + if (msblk->block_cache[i].block != SQUASHFS_USED_BLK) + break; + i = (i + 1) % squashfs_cached_blks; + } + + msblk->next_cache = (i + 1) % squashfs_cached_blks; + + if (msblk->block_cache[i].block == SQUASHFS_INVALID_BLK) { + msblk->block_cache[i].data = vmalloc(SQUASHFS_METADATA_SIZE); + if (msblk->block_cache[i].data == NULL) { + ERROR("Failed to allocate cache block\n"); + mutex_unlock(&msblk->block_cache_mutex); + goto out; + } + } + + msblk->block_cache[i].block = SQUASHFS_USED_BLK; + msblk->unused_cache_blks --; + mutex_unlock(&msblk->block_cache_mutex); + + msblk->block_cache[i].length = squashfs_read_data(s, + msblk->block_cache[i].data, block, 0, &next_index, + SQUASHFS_METADATA_SIZE); + + if (msblk->block_cache[i].length == 0) { + ERROR("Unable to read cache block [%llx:%x]\n", block, offset); + mutex_lock(&msblk->block_cache_mutex); + msblk->block_cache[i].block = SQUASHFS_INVALID_BLK; + msblk->unused_cache_blks ++; + smp_mb(); + vfree(msblk->block_cache[i].data); + wake_up(&msblk->waitq); + mutex_unlock(&msblk->block_cache_mutex); + goto out; + } + + mutex_lock(&msblk->block_cache_mutex); + msblk->block_cache[i].block = block; + msblk->block_cache[i].next_index = next_index; + msblk->unused_cache_blks ++; + smp_mb(); + wake_up(&msblk->waitq); + TRACE("Read cache block [%llx:%x]\n", block, offset); + } + + if (msblk->block_cache[i].block != block) { + mutex_unlock(&msblk->block_cache_mutex); + continue; + } + + bytes = msblk->block_cache[i].length - offset; + + if (bytes < 1) { + mutex_unlock(&msblk->block_cache_mutex); + goto out; + } else if (bytes >= length) { + if (buffer) + memcpy(buffer, msblk->block_cache[i].data + offset, length); + if (msblk->block_cache[i].length - offset == length) { + *next_block = msblk->block_cache[i].next_index; + *next_offset = 0; + } else { + *next_block = block; + *next_offset = offset + length; + } + mutex_unlock(&msblk->block_cache_mutex); + goto finish; + } else { + if (buffer) { + memcpy(buffer, msblk->block_cache[i].data + offset, bytes); + buffer = (char *) buffer + bytes; + } + block = msblk->block_cache[i].next_index; + mutex_unlock(&msblk->block_cache_mutex); + length -= bytes; + offset = 0; + } + } + +finish: + return return_length; +out: + return 0; +} + + +static int get_fragment_location(struct super_block *s, unsigned int fragment, + long long *fragment_start_block, + unsigned int *fragment_size) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + long long start_block = + msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)]; + int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); + struct squashfs_fragment_entry fragment_entry; + + if (msblk->swap) { + struct squashfs_fragment_entry sfragment_entry; + + if (!squashfs_get_cached_block(s, &sfragment_entry, start_block, offset, + sizeof(sfragment_entry), &start_block, &offset)) + goto out; + SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry); + } else + if (!squashfs_get_cached_block(s, &fragment_entry, start_block, offset, + sizeof(fragment_entry), &start_block, &offset)) + goto out; + + *fragment_start_block = fragment_entry.start_block; + *fragment_size = fragment_entry.size; + + return 1; + +out: + return 0; +} + + +SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, + struct squashfs_fragment_cache *fragment) +{ + mutex_lock(&msblk->fragment_mutex); + fragment->locked --; + if (fragment->locked == 0) { + msblk->unused_frag_blks ++; + smp_mb(); + wake_up(&msblk->fragment_wait_queue); + } + mutex_unlock(&msblk->fragment_mutex); +} + + +SQSH_EXTERN +struct squashfs_fragment_cache *get_cached_fragment(struct super_block *s, + long long start_block, int length) +{ + int i, n; + struct squashfs_sb_info *msblk = s->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + + while (1) { + mutex_lock(&msblk->fragment_mutex); + + for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS && + msblk->fragment[i].block != start_block; i++); + + if (i == SQUASHFS_CACHED_FRAGMENTS) { + if (msblk->unused_frag_blks == 0) { + mutex_unlock(&msblk->fragment_mutex); + wait_event(msblk->fragment_wait_queue, msblk->unused_frag_blks); + continue; + } + + i = msblk->next_fragment; + for (n = 0; n < SQUASHFS_CACHED_FRAGMENTS; n++) { + if (msblk->fragment[i].locked == 0) + break; + i = (i + 1) % SQUASHFS_CACHED_FRAGMENTS; + } + + msblk->next_fragment = (msblk->next_fragment + 1) % + SQUASHFS_CACHED_FRAGMENTS; + + if (msblk->fragment[i].data == NULL) { + msblk->fragment[i].data = vmalloc(sblk->block_size); + if (msblk->fragment[i].data == NULL) { + ERROR("Failed to allocate fragment cache block\n"); + mutex_unlock(&msblk->fragment_mutex); + goto out; + } + } + + msblk->unused_frag_blks --; + msblk->fragment[i].block = SQUASHFS_INVALID_BLK; + msblk->fragment[i].locked = 1; + mutex_unlock(&msblk->fragment_mutex); + + msblk->fragment[i].length = squashfs_read_data(s, + msblk->fragment[i].data, start_block, length, NULL, + sblk->block_size); + + if (msblk->fragment[i].length == 0) { + ERROR("Unable to read fragment cache block [%llx]\n", start_block); + msblk->fragment[i].locked = 0; + msblk->unused_frag_blks ++; + smp_mb(); + wake_up(&msblk->fragment_wait_queue); + goto out; + } + + mutex_lock(&msblk->fragment_mutex); + msblk->fragment[i].block = start_block; + TRACE("New fragment %d, start block %lld, locked %d\n", + i, msblk->fragment[i].block, msblk->fragment[i].locked); + mutex_unlock(&msblk->fragment_mutex); + break; + } + + if (msblk->fragment[i].locked == 0) + msblk->unused_frag_blks --; + msblk->fragment[i].locked++; + mutex_unlock(&msblk->fragment_mutex); + TRACE("Got fragment %d, start block %lld, locked %d\n", i, + msblk->fragment[i].block, msblk->fragment[i].locked); + break; + } + + return &msblk->fragment[i]; + +out: + return NULL; +} + + +static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i, + struct squashfs_base_inode_header *inodeb) +{ + i->i_ino = inodeb->inode_number; + i->i_mtime.tv_sec = inodeb->mtime; + i->i_atime.tv_sec = inodeb->mtime; + i->i_ctime.tv_sec = inodeb->mtime; + i->i_uid = msblk->uid[inodeb->uid]; + i->i_mode = inodeb->mode; + i->i_size = 0; + + if (inodeb->guid == SQUASHFS_GUIDS) + i->i_gid = i->i_uid; + else + i->i_gid = msblk->guid[inodeb->guid]; +} + +#ifdef USE_EXPORT +static squashfs_inode_t squashfs_inode_lookup(struct super_block *s, int ino) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + long long start = msblk->inode_lookup_table[SQUASHFS_LOOKUP_BLOCK(ino - 1)]; + int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino - 1); + squashfs_inode_t inode; + + TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino); + + if (msblk->swap) { + squashfs_inode_t sinode; + + if (!squashfs_get_cached_block(s, &sinode, start, offset, + sizeof(sinode), &start, &offset)) + goto out; + SQUASHFS_SWAP_INODE_T((&inode), &sinode); + } else if (!squashfs_get_cached_block(s, &inode, start, offset, + sizeof(inode), &start, &offset)) + goto out; + + TRACE("squashfs_inode_lookup, inode = 0x%llx\n", inode); + + return inode; + +out: + return SQUASHFS_INVALID_BLK; +} + +static struct dentry *squashfs_get_parent(struct dentry *child) +{ + struct inode *i = child->d_inode; + struct inode *parent = iget(i->i_sb, SQUASHFS_I(i)->u.s2.parent_inode); + struct dentry *rv; + + TRACE("Entered squashfs_get_parent\n"); + + if(parent == NULL) { + rv = ERR_PTR(-EACCES); + goto out; + } + + rv = d_alloc_anon(parent); + if(rv == NULL) + rv = ERR_PTR(-ENOMEM); + +out: + return rv; +} +#endif + +SQSH_EXTERN struct inode *squashfs_iget(struct super_block *s, + squashfs_inode_t inode, unsigned int inode_number) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + struct inode *i = iget_locked(s, inode_number); + + TRACE("Entered squashfs_iget\n"); + + if (!i) + return ERR_PTR(-ENOMEM); + + if (i->i_state & I_NEW) { + (msblk->read_inode)(i, inode); + unlock_new_inode(i); + } + + return i; +} + + +static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode) +{ + struct super_block *s = i->i_sb; + struct squashfs_sb_info *msblk = s->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + long long block = SQUASHFS_INODE_BLK(inode) + sblk->inode_table_start; + unsigned int offset = SQUASHFS_INODE_OFFSET(inode); + long long next_block; + unsigned int next_offset; + union squashfs_inode_header id, sid; + struct squashfs_base_inode_header *inodeb = &id.base, *sinodeb = &sid.base; + + TRACE("Entered squashfs_read_inode\n"); + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, sinodeb, block, offset, + sizeof(*sinodeb), &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb, sizeof(*sinodeb)); + } else + if (!squashfs_get_cached_block(s, inodeb, block, offset, + sizeof(*inodeb), &next_block, &next_offset)) + goto failed_read; + + squashfs_new_inode(msblk, i, inodeb); + + switch(inodeb->inode_type) { + case SQUASHFS_FILE_TYPE: { + unsigned int frag_size; + long long frag_blk; + struct squashfs_reg_inode_header *inodep = &id.reg; + struct squashfs_reg_inode_header *sinodep = &sid.reg; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, sinodep, block, offset, + sizeof(*sinodep), &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep); + } else + if (!squashfs_get_cached_block(s, inodep, block, offset, + sizeof(*inodep), &next_block, &next_offset)) + goto failed_read; + + frag_blk = SQUASHFS_INVALID_BLK; + + if (inodep->fragment != SQUASHFS_INVALID_FRAG) + if(!get_fragment_location(s, inodep->fragment, &frag_blk, + &frag_size)) + goto failed_read; + + i->i_nlink = 1; + i->i_size = inodep->file_size; + i->i_fop = &generic_ro_fops; + i->i_mode |= S_IFREG; + i->i_blocks = ((i->i_size - 1) >> 9) + 1; + SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; + SQUASHFS_I(i)->u.s1.fragment_size = frag_size; + SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; + SQUASHFS_I(i)->start_block = inodep->start_block; + SQUASHFS_I(i)->u.s1.block_list_start = next_block; + SQUASHFS_I(i)->offset = next_offset; + i->i_data.a_ops = &squashfs_aops; + + TRACE("File inode %x:%x, start_block %llx, " + "block_list_start %llx, offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, + inodep->start_block, next_block, + next_offset); + break; + } + case SQUASHFS_LREG_TYPE: { + unsigned int frag_size; + long long frag_blk; + struct squashfs_lreg_inode_header *inodep = &id.lreg; + struct squashfs_lreg_inode_header *sinodep = &sid.lreg; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, sinodep, block, offset, + sizeof(*sinodep), &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep); + } else + if (!squashfs_get_cached_block(s, inodep, block, offset, + sizeof(*inodep), &next_block, &next_offset)) + goto failed_read; + + frag_blk = SQUASHFS_INVALID_BLK; + + if (inodep->fragment != SQUASHFS_INVALID_FRAG) + if (!get_fragment_location(s, inodep->fragment, &frag_blk, + &frag_size)) + goto failed_read; + + i->i_nlink = inodep->nlink; + i->i_size = inodep->file_size; + i->i_fop = &generic_ro_fops; + i->i_mode |= S_IFREG; + i->i_blocks = ((i->i_size - 1) >> 9) + 1; + SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; + SQUASHFS_I(i)->u.s1.fragment_size = frag_size; + SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; + SQUASHFS_I(i)->start_block = inodep->start_block; + SQUASHFS_I(i)->u.s1.block_list_start = next_block; + SQUASHFS_I(i)->offset = next_offset; + i->i_data.a_ops = &squashfs_aops; + + TRACE("File inode %x:%x, start_block %llx, " + "block_list_start %llx, offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, + inodep->start_block, next_block, + next_offset); + break; + } + case SQUASHFS_DIR_TYPE: { + struct squashfs_dir_inode_header *inodep = &id.dir; + struct squashfs_dir_inode_header *sinodep = &sid.dir; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, sinodep, block, offset, + sizeof(*sinodep), &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep); + } else + if (!squashfs_get_cached_block(s, inodep, block, offset, + sizeof(*inodep), &next_block, &next_offset)) + goto failed_read; + + i->i_nlink = inodep->nlink; + i->i_size = inodep->file_size; + i->i_op = &squashfs_dir_inode_ops; + i->i_fop = &squashfs_dir_ops; + i->i_mode |= S_IFDIR; + SQUASHFS_I(i)->start_block = inodep->start_block; + SQUASHFS_I(i)->offset = inodep->offset; + SQUASHFS_I(i)->u.s2.directory_index_count = 0; + SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode; + + TRACE("Directory inode %x:%x, start_block %x, offset " + "%x\n", SQUASHFS_INODE_BLK(inode), + offset, inodep->start_block, + inodep->offset); + break; + } + case SQUASHFS_LDIR_TYPE: { + struct squashfs_ldir_inode_header *inodep = &id.ldir; + struct squashfs_ldir_inode_header *sinodep = &sid.ldir; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, sinodep, block, offset, + sizeof(*sinodep), &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep, sinodep); + } else + if (!squashfs_get_cached_block(s, inodep, block, offset, + sizeof(*inodep), &next_block, &next_offset)) + goto failed_read; + + i->i_nlink = inodep->nlink; + i->i_size = inodep->file_size; + i->i_op = &squashfs_dir_inode_ops; + i->i_fop = &squashfs_dir_ops; + i->i_mode |= S_IFDIR; + SQUASHFS_I(i)->start_block = inodep->start_block; + SQUASHFS_I(i)->offset = inodep->offset; + SQUASHFS_I(i)->u.s2.directory_index_start = next_block; + SQUASHFS_I(i)->u.s2.directory_index_offset = next_offset; + SQUASHFS_I(i)->u.s2.directory_index_count = inodep->i_count; + SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode; + + TRACE("Long directory inode %x:%x, start_block %x, offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, + inodep->start_block, inodep->offset); + break; + } + case SQUASHFS_SYMLINK_TYPE: { + struct squashfs_symlink_inode_header *inodep = &id.symlink; + struct squashfs_symlink_inode_header *sinodep = &sid.symlink; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, sinodep, block, offset, + sizeof(*sinodep), &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, sinodep); + } else + if (!squashfs_get_cached_block(s, inodep, block, offset, + sizeof(*inodep), &next_block, &next_offset)) + goto failed_read; + + i->i_nlink = inodep->nlink; + i->i_size = inodep->symlink_size; + i->i_op = &page_symlink_inode_operations; + i->i_data.a_ops = &squashfs_symlink_aops; + i->i_mode |= S_IFLNK; + SQUASHFS_I(i)->start_block = next_block; + SQUASHFS_I(i)->offset = next_offset; + + TRACE("Symbolic link inode %x:%x, start_block %llx, offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, + next_block, next_offset); + break; + } + case SQUASHFS_BLKDEV_TYPE: + case SQUASHFS_CHRDEV_TYPE: { + struct squashfs_dev_inode_header *inodep = &id.dev; + struct squashfs_dev_inode_header *sinodep = &sid.dev; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, sinodep, block, offset, + sizeof(*sinodep), &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep); + } else + if (!squashfs_get_cached_block(s, inodep, block, offset, + sizeof(*inodep), &next_block, &next_offset)) + goto failed_read; + + i->i_nlink = inodep->nlink; + i->i_mode |= (inodeb->inode_type == SQUASHFS_CHRDEV_TYPE) ? + S_IFCHR : S_IFBLK; + init_special_inode(i, i->i_mode, old_decode_dev(inodep->rdev)); + + TRACE("Device inode %x:%x, rdev %x\n", + SQUASHFS_INODE_BLK(inode), offset, inodep->rdev); + break; + } + case SQUASHFS_FIFO_TYPE: + case SQUASHFS_SOCKET_TYPE: { + struct squashfs_ipc_inode_header *inodep = &id.ipc; + struct squashfs_ipc_inode_header *sinodep = &sid.ipc; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, sinodep, block, offset, + sizeof(*sinodep), &next_block, &next_offset)) + goto failed_read; + SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep); + } else + if (!squashfs_get_cached_block(s, inodep, block, offset, + sizeof(*inodep), &next_block, &next_offset)) + goto failed_read; + + i->i_nlink = inodep->nlink; + i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE) + ? S_IFIFO : S_IFSOCK; + init_special_inode(i, i->i_mode, 0); + break; + } + default: + ERROR("Unknown inode type %d in squashfs_iget!\n", + inodeb->inode_type); + goto failed_read1; + } + + return 1; + +failed_read: + ERROR("Unable to read inode [%llx:%x]\n", block, offset); + +failed_read1: + make_bad_inode(i); + return 0; +} + + +static int read_inode_lookup_table(struct super_block *s) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(sblk->inodes); + + TRACE("In read_inode_lookup_table, length %d\n", length); + + /* Allocate inode lookup table */ + msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL); + if (msblk->inode_lookup_table == NULL) { + ERROR("Failed to allocate inode lookup table\n"); + return 0; + } + + if (!squashfs_read_data(s, (char *) msblk->inode_lookup_table, + sblk->lookup_table_start, length | + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) { + ERROR("unable to read inode lookup table\n"); + return 0; + } + + if (msblk->swap) { + int i; + long long block; + + for (i = 0; i < SQUASHFS_LOOKUP_BLOCKS(sblk->inodes); i++) { + /* XXX */ + SQUASHFS_SWAP_LOOKUP_BLOCKS((&block), + &msblk->inode_lookup_table[i], 1); + msblk->inode_lookup_table[i] = block; + } + } + + return 1; +} + + +static int read_fragment_index_table(struct super_block *s) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments); + + if(length == 0) + return 1; + + /* Allocate fragment index table */ + msblk->fragment_index = kmalloc(length, GFP_KERNEL); + if (msblk->fragment_index == NULL) { + ERROR("Failed to allocate fragment index table\n"); + return 0; + } + + if (!squashfs_read_data(s, (char *) msblk->fragment_index, + sblk->fragment_table_start, length | + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) { + ERROR("unable to read fragment index table\n"); + return 0; + } + + if (msblk->swap) { + int i; + long long fragment; + + for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); i++) { + /* XXX */ + SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment), + &msblk->fragment_index[i], 1); + msblk->fragment_index[i] = fragment; + } + } + + return 1; +} + + +static int readahead_metadata(struct super_block *s) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + int i; + + squashfs_cached_blks = SQUASHFS_CACHED_BLKS; + + /* Init inode_table block pointer array */ + msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) * + squashfs_cached_blks, GFP_KERNEL); + if (msblk->block_cache == NULL) { + ERROR("Failed to allocate block cache\n"); + goto failed; + } + + for (i = 0; i < squashfs_cached_blks; i++) + msblk->block_cache[i].block = SQUASHFS_INVALID_BLK; + + msblk->next_cache = 0; + msblk->unused_cache_blks = squashfs_cached_blks; + + return 1; + +failed: + return 0; +} + + +static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent) +{ + struct squashfs_super_block *sblk = &msblk->sblk; + + msblk->read_inode = squashfs_read_inode; + msblk->read_blocklist = read_blocklist; + msblk->read_fragment_index_table = read_fragment_index_table; + + if (sblk->s_major == 1) { + if (!squashfs_1_0_supported(msblk)) { + SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems " + "are unsupported\n"); + SERROR("Please recompile with Squashfs 1.0 support enabled\n"); + return 0; + } + } else if (sblk->s_major == 2) { + if (!squashfs_2_0_supported(msblk)) { + SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems " + "are unsupported\n"); + SERROR("Please recompile with Squashfs 2.0 support enabled\n"); + return 0; + } + } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor > + SQUASHFS_MINOR) { + SERROR("Major/Minor mismatch, trying to mount newer %d.%d " + "filesystem\n", sblk->s_major, sblk->s_minor); + SERROR("Please update your kernel\n"); + return 0; + } + + return 1; +} + + +static int squashfs_fill_super(struct super_block *s, void *data, int silent) +{ + struct squashfs_sb_info *msblk; + struct squashfs_super_block *sblk; + int i; + char b[BDEVNAME_SIZE]; + struct inode *root; + + TRACE("Entered squashfs_fill_superblock\n"); + + s->s_fs_info = kzalloc(sizeof(struct squashfs_sb_info), GFP_KERNEL); + if (s->s_fs_info == NULL) { + ERROR("Failed to allocate superblock\n"); + goto failure; + } + msblk = s->s_fs_info; + + msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize()); + if (msblk->stream.workspace == NULL) { + ERROR("Failed to allocate zlib workspace\n"); + goto failure; + } + sblk = &msblk->sblk; + + msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE); + msblk->devblksize_log2 = ffz(~msblk->devblksize); + + mutex_init(&msblk->read_data_mutex); + mutex_init(&msblk->read_page_mutex); + mutex_init(&msblk->block_cache_mutex); + mutex_init(&msblk->fragment_mutex); + mutex_init(&msblk->meta_index_mutex); + + init_waitqueue_head(&msblk->waitq); + init_waitqueue_head(&msblk->fragment_wait_queue); + + /* sblk->bytes_used is checked in squashfs_read_data to ensure reads are not + * beyond filesystem end. As we're using squashfs_read_data to read sblk here, + * first set sblk->bytes_used to a useful value */ + sblk->bytes_used = sizeof(struct squashfs_super_block); + if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START, + sizeof(struct squashfs_super_block) | + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, sizeof(struct squashfs_super_block))) { + SERROR("unable to read superblock\n"); + goto failed_mount; + } + + /* Check it is a SQUASHFS superblock */ + if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) { + if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) { + struct squashfs_super_block ssblk; + + WARNING("Mounting a different endian SQUASHFS filesystem on %s\n", + bdevname(s->s_bdev, b)); + + SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk); + memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block)); + msblk->swap = 1; + } else { + SERROR("Can't find a SQUASHFS superblock on %s\n", + bdevname(s->s_bdev, b)); + goto failed_mount; + } + } + + /* Check the MAJOR & MINOR versions */ + if(!supported_squashfs_filesystem(msblk, silent)) + goto failed_mount; + + /* Check the filesystem does not extend beyond the end of the + block device */ + if(sblk->bytes_used < 0 || sblk->bytes_used > i_size_read(s->s_bdev->bd_inode)) + goto failed_mount; + + /* Check the root inode for sanity */ + if (SQUASHFS_INODE_OFFSET(sblk->root_inode) > SQUASHFS_METADATA_SIZE) + goto failed_mount; + + TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b)); + TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sblk->flags) + ? "un" : ""); + TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sblk->flags) + ? "un" : ""); + TRACE("Check data is %spresent in the filesystem\n", + SQUASHFS_CHECK_DATA(sblk->flags) ? "" : "not "); + TRACE("Filesystem size %lld bytes\n", sblk->bytes_used); + TRACE("Block size %d\n", sblk->block_size); + TRACE("Number of inodes %d\n", sblk->inodes); + if (sblk->s_major > 1) + TRACE("Number of fragments %d\n", sblk->fragments); + TRACE("Number of uids %d\n", sblk->no_uids); + TRACE("Number of gids %d\n", sblk->no_guids); + TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start); + TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start); + if (sblk->s_major > 1) + TRACE("sblk->fragment_table_start %llx\n", sblk->fragment_table_start); + TRACE("sblk->uid_start %llx\n", sblk->uid_start); + + s->s_maxbytes = MAX_LFS_FILESIZE; + s->s_flags |= MS_RDONLY; + s->s_op = &squashfs_super_ops; + + if (readahead_metadata(s) == 0) + goto failed_mount; + + /* Allocate read_page block */ + msblk->read_page = vmalloc(sblk->block_size); + if (msblk->read_page == NULL) { + ERROR("Failed to allocate read_page block\n"); + goto failed_mount; + } + + /* Allocate uid and gid tables */ + msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) * + sizeof(unsigned int), GFP_KERNEL); + if (msblk->uid == NULL) { + ERROR("Failed to allocate uid/gid table\n"); + goto failed_mount; + } + msblk->guid = msblk->uid + sblk->no_uids; + + if (msblk->swap) { + unsigned int suid[sblk->no_uids + sblk->no_guids]; + + if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start, + ((sblk->no_uids + sblk->no_guids) * + sizeof(unsigned int)) | + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) { + ERROR("unable to read uid/gid table\n"); + goto failed_mount; + } + + SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids + + sblk->no_guids), (sizeof(unsigned int) * 8)); + } else + if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start, + ((sblk->no_uids + sblk->no_guids) * + sizeof(unsigned int)) | + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) { + ERROR("unable to read uid/gid table\n"); + goto failed_mount; + } + + + if (sblk->s_major == 1 && squashfs_1_0_supported(msblk)) + goto allocate_root; + + msblk->fragment = kzalloc(sizeof(struct squashfs_fragment_cache) * + SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL); + if (msblk->fragment == NULL) { + ERROR("Failed to allocate fragment block cache\n"); + goto failed_mount; + } + + for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) { + msblk->fragment[i].block = SQUASHFS_INVALID_BLK; + } + + msblk->next_fragment = 0; + msblk->unused_frag_blks = SQUASHFS_CACHED_FRAGMENTS; + + /* Allocate and read fragment index table */ + if (msblk->read_fragment_index_table(s) == 0) + goto failed_mount; + + if(sblk->s_major < 3 || sblk->lookup_table_start == SQUASHFS_INVALID_BLK) + goto allocate_root; + + /* Allocate and read inode lookup table */ + if (read_inode_lookup_table(s) == 0) + goto failed_mount; + + s->s_op = &squashfs_export_super_ops; +#ifdef USE_EXPORT + s->s_export_op = &squashfs_export_ops; +#endif + +allocate_root: + root = new_inode(s); + if ((msblk->read_inode)(root, sblk->root_inode) == 0) + goto failed_mount; + insert_inode_hash(root); + + s->s_root = d_alloc_root(root); + if (s->s_root == NULL) { + ERROR("Root inode create failed\n"); + iput(root); + goto failed_mount; + } + + TRACE("Leaving squashfs_fill_super\n"); + return 0; + +failed_mount: + kfree(msblk->inode_lookup_table); + kfree(msblk->fragment_index); + kfree(msblk->fragment); + kfree(msblk->uid); + vfree(msblk->read_page); + kfree(msblk->block_cache); + kfree(msblk->fragment_index_2); + vfree(msblk->stream.workspace); + kfree(s->s_fs_info); + s->s_fs_info = NULL; + return -EINVAL; + +failure: + return -ENOMEM; +} + + +static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + + TRACE("Entered squashfs_statfs\n"); + + buf->f_type = SQUASHFS_MAGIC; + buf->f_bsize = sblk->block_size; + buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1; + buf->f_bfree = buf->f_bavail = 0; + buf->f_files = sblk->inodes; + buf->f_ffree = 0; + buf->f_namelen = SQUASHFS_NAME_LEN; + + return 0; +} + + +static int squashfs_symlink_readpage(struct file *file, struct page *page) +{ + struct inode *inode = page->mapping->host; + int index = page->index << PAGE_CACHE_SHIFT, length, bytes, avail_bytes; + long long block = SQUASHFS_I(inode)->start_block; + int offset = SQUASHFS_I(inode)->offset; + void *pageaddr = kmap(page); + + TRACE("Entered squashfs_symlink_readpage, page index %ld, start block " + "%llx, offset %x\n", page->index, + SQUASHFS_I(inode)->start_block, + SQUASHFS_I(inode)->offset); + + for (length = 0; length < index; length += bytes) { + bytes = squashfs_get_cached_block(inode->i_sb, NULL, block, + offset, PAGE_CACHE_SIZE, &block, &offset); + if (bytes == 0) { + ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset); + goto skip_read; + } + } + + if (length != index) { + ERROR("(squashfs_symlink_readpage) length != index\n"); + bytes = 0; + goto skip_read; + } + + avail_bytes = min_t(int, i_size_read(inode) - length, PAGE_CACHE_SIZE); + + bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, offset, + avail_bytes, &block, &offset); + if (bytes == 0) + ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset); + +skip_read: + memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); + kunmap(page); + flush_dcache_page(page); + SetPageUptodate(page); + unlock_page(page); + + return 0; +} + + +struct meta_index *locate_meta_index(struct inode *inode, int index, int offset) +{ + struct meta_index *meta = NULL; + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; + int i; + + mutex_lock(&msblk->meta_index_mutex); + + TRACE("locate_meta_index: index %d, offset %d\n", index, offset); + + if (msblk->meta_index == NULL) + goto not_allocated; + + for (i = 0; i < SQUASHFS_META_NUMBER; i ++) { + if (msblk->meta_index[i].inode_number == inode->i_ino && + msblk->meta_index[i].offset >= offset && + msblk->meta_index[i].offset <= index && + msblk->meta_index[i].locked == 0) { + TRACE("locate_meta_index: entry %d, offset %d\n", i, + msblk->meta_index[i].offset); + meta = &msblk->meta_index[i]; + offset = meta->offset; + } + } + + if (meta) + meta->locked = 1; + +not_allocated: + mutex_unlock(&msblk->meta_index_mutex); + + return meta; +} + + +struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip) +{ + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; + struct meta_index *meta = NULL; + int i; + + mutex_lock(&msblk->meta_index_mutex); + + TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip); + + if (msblk->meta_index == NULL) { + msblk->meta_index = kmalloc(sizeof(struct meta_index) * + SQUASHFS_META_NUMBER, GFP_KERNEL); + if (msblk->meta_index == NULL) { + ERROR("Failed to allocate meta_index\n"); + goto failed; + } + for (i = 0; i < SQUASHFS_META_NUMBER; i++) { + msblk->meta_index[i].inode_number = 0; + msblk->meta_index[i].locked = 0; + } + msblk->next_meta_index = 0; + } + + for (i = SQUASHFS_META_NUMBER; i && + msblk->meta_index[msblk->next_meta_index].locked; i --) + msblk->next_meta_index = (msblk->next_meta_index + 1) % + SQUASHFS_META_NUMBER; + + if (i == 0) { + TRACE("empty_meta_index: failed!\n"); + goto failed; + } + + TRACE("empty_meta_index: returned meta entry %d, %p\n", + msblk->next_meta_index, + &msblk->meta_index[msblk->next_meta_index]); + + meta = &msblk->meta_index[msblk->next_meta_index]; + msblk->next_meta_index = (msblk->next_meta_index + 1) % + SQUASHFS_META_NUMBER; + + meta->inode_number = inode->i_ino; + meta->offset = offset; + meta->skip = skip; + meta->entries = 0; + meta->locked = 1; + +failed: + mutex_unlock(&msblk->meta_index_mutex); + return meta; +} + + +void release_meta_index(struct inode *inode, struct meta_index *meta) +{ + meta->locked = 0; + smp_mb(); +} + + +static int read_block_index(struct super_block *s, int blocks, char *block_list, + long long *start_block, int *offset) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + unsigned int *block_listp; + int block = 0; + + if (msblk->swap) { + char sblock_list[blocks << 2]; + + if (!squashfs_get_cached_block(s, sblock_list, *start_block, + *offset, blocks << 2, start_block, offset)) { + ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset); + goto failure; + } + SQUASHFS_SWAP_INTS(((unsigned int *)block_list), + ((unsigned int *)sblock_list), blocks); + } else { + if (!squashfs_get_cached_block(s, block_list, *start_block, + *offset, blocks << 2, start_block, offset)) { + ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset); + goto failure; + } + } + + for (block_listp = (unsigned int *) block_list; blocks; + block_listp++, blocks --) + block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp); + + return block; + +failure: + return -1; +} + + +#define SIZE 256 + +static inline int calculate_skip(int blocks) { + int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES); + return skip >= 7 ? 7 : skip + 1; +} + + +static int get_meta_index(struct inode *inode, int index, + long long *index_block, int *index_offset, + long long *data_block, char *block_list) +{ + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + int skip = calculate_skip(i_size_read(inode) >> sblk->block_log); + int offset = 0; + struct meta_index *meta; + struct meta_entry *meta_entry; + long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start; + int cur_offset = SQUASHFS_I(inode)->offset; + long long cur_data_block = SQUASHFS_I(inode)->start_block; + int i; + + index /= SQUASHFS_META_INDEXES * skip; + + while (offset < index) { + meta = locate_meta_index(inode, index, offset + 1); + + if (meta == NULL) { + meta = empty_meta_index(inode, offset + 1, skip); + if (meta == NULL) + goto all_done; + } else { + if(meta->entries == 0) + goto failed; + /* XXX */ + offset = index < meta->offset + meta->entries ? index : + meta->offset + meta->entries - 1; + /* XXX */ + meta_entry = &meta->meta_entry[offset - meta->offset]; + cur_index_block = meta_entry->index_block + sblk->inode_table_start; + cur_offset = meta_entry->offset; + cur_data_block = meta_entry->data_block; + TRACE("get_meta_index: offset %d, meta->offset %d, " + "meta->entries %d\n", offset, meta->offset, meta->entries); + TRACE("get_meta_index: index_block 0x%llx, offset 0x%x" + " data_block 0x%llx\n", cur_index_block, + cur_offset, cur_data_block); + } + + for (i = meta->offset + meta->entries; i <= index && + i < meta->offset + SQUASHFS_META_ENTRIES; i++) { + int blocks = skip * SQUASHFS_META_INDEXES; + + while (blocks) { + int block = blocks > (SIZE >> 2) ? (SIZE >> 2) : blocks; + int res = read_block_index(inode->i_sb, block, block_list, + &cur_index_block, &cur_offset); + + if (res == -1) + goto failed; + + cur_data_block += res; + blocks -= block; + } + + meta_entry = &meta->meta_entry[i - meta->offset]; + meta_entry->index_block = cur_index_block - sblk->inode_table_start; + meta_entry->offset = cur_offset; + meta_entry->data_block = cur_data_block; + meta->entries ++; + offset ++; + } + + TRACE("get_meta_index: meta->offset %d, meta->entries %d\n", + meta->offset, meta->entries); + + release_meta_index(inode, meta); + } + +all_done: + *index_block = cur_index_block; + *index_offset = cur_offset; + *data_block = cur_data_block; + + return offset * SQUASHFS_META_INDEXES * skip; + +failed: + release_meta_index(inode, meta); + return -1; +} + + +static long long read_blocklist(struct inode *inode, int index, + int readahead_blks, char *block_list, + unsigned short **block_p, unsigned int *bsize) +{ + long long block_ptr; + int offset; + long long block; + int res = get_meta_index(inode, index, &block_ptr, &offset, &block, + block_list); + + TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset" + " 0x%x, block 0x%llx\n", res, index, block_ptr, offset, block); + + if(res == -1) + goto failure; + + index -= res; + + while (index) { + int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index; + int res = read_block_index(inode->i_sb, blocks, block_list, + &block_ptr, &offset); + if (res == -1) + goto failure; + block += res; + index -= blocks; + } + + if (read_block_index(inode->i_sb, 1, block_list, &block_ptr, &offset) == -1) + goto failure; + *bsize = *((unsigned int *) block_list); + + return block; + +failure: + return 0; +} + + +static int squashfs_readpage(struct file *file, struct page *page) +{ + struct inode *inode = page->mapping->host; + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + unsigned char *block_list = NULL; + long long block; + unsigned int bsize, i; + int bytes; + int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT); + void *pageaddr; + struct squashfs_fragment_cache *fragment = NULL; + char *data_ptr = msblk->read_page; + + int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1; + int start_index = page->index & ~mask; + int end_index = start_index | mask; + int file_end = i_size_read(inode) >> sblk->block_log; + int sparse = 0; + + TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n", + page->index, SQUASHFS_I(inode)->start_block); + + if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> + PAGE_CACHE_SHIFT)) + goto out; + + if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK + || index < file_end) { + block_list = kmalloc(SIZE, GFP_KERNEL); + if (block_list == NULL) { + ERROR("Failed to allocate block_list\n"); + goto error_out; + } + + block = (msblk->read_blocklist)(inode, index, 1, block_list, NULL, &bsize); + if (block == 0) + goto error_out; + + if (bsize == 0) { /* hole */ + bytes = index == file_end ? + (i_size_read(inode) & (sblk->block_size - 1)) : sblk->block_size; + sparse = 1; + } else { + mutex_lock(&msblk->read_page_mutex); + + bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block, + bsize, NULL, sblk->block_size); + + if (bytes == 0) { + ERROR("Unable to read page, block %llx, size %x\n", block, bsize); + mutex_unlock(&msblk->read_page_mutex); + goto error_out; + } + } + } else { + fragment = get_cached_fragment(inode->i_sb, + SQUASHFS_I(inode)-> u.s1.fragment_start_block, + SQUASHFS_I(inode)->u.s1.fragment_size); + + if (fragment == NULL) { + ERROR("Unable to read page, block %llx, size %x\n", + SQUASHFS_I(inode)->u.s1.fragment_start_block, + (int) SQUASHFS_I(inode)->u.s1.fragment_size); + goto error_out; + } + bytes = i_size_read(inode) & (sblk->block_size - 1); + data_ptr = fragment->data + SQUASHFS_I(inode)->u.s1.fragment_offset; + } + + for (i = start_index; i <= end_index && bytes > 0; i++, + bytes -= PAGE_CACHE_SIZE, data_ptr += PAGE_CACHE_SIZE) { + struct page *push_page; + int avail = sparse ? 0 : min_t(unsigned int, bytes, PAGE_CACHE_SIZE); + + TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail); + + push_page = (i == page->index) ? page : + grab_cache_page_nowait(page->mapping, i); + + if (!push_page) + continue; + + if (PageUptodate(push_page)) + goto skip_page; + + pageaddr = kmap_atomic(push_page, KM_USER0); + memcpy(pageaddr, data_ptr, avail); + memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail); + kunmap_atomic(pageaddr, KM_USER0); + flush_dcache_page(push_page); + SetPageUptodate(push_page); +skip_page: + unlock_page(push_page); + if(i != page->index) + page_cache_release(push_page); + } + + if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK + || index < file_end) { + if (!sparse) + mutex_unlock(&msblk->read_page_mutex); + kfree(block_list); + } else + release_cached_fragment(msblk, fragment); + + return 0; + +error_out: + SetPageError(page); +out: + pageaddr = kmap_atomic(page, KM_USER0); + memset(pageaddr, 0, PAGE_CACHE_SIZE); + kunmap_atomic(pageaddr, KM_USER0); + flush_dcache_page(page); + if (!PageError(page)) + SetPageUptodate(page); + unlock_page(page); + + kfree(block_list); + return 0; +} + + +static int get_dir_index_using_offset(struct super_block *s, + long long *next_block, unsigned int *next_offset, + long long index_start, unsigned int index_offset, int i_count, + long long f_pos) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + int i, length = 0; + struct squashfs_dir_index index; + + TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n", + i_count, (unsigned int) f_pos); + + f_pos =- 3; + if (f_pos == 0) + goto finish; + + for (i = 0; i < i_count; i++) { + if (msblk->swap) { + struct squashfs_dir_index sindex; + squashfs_get_cached_block(s, &sindex, index_start, index_offset, + sizeof(sindex), &index_start, &index_offset); + SQUASHFS_SWAP_DIR_INDEX(&index, &sindex); + } else + squashfs_get_cached_block(s, &index, index_start, index_offset, + sizeof(index), &index_start, &index_offset); + + if (index.index > f_pos) + break; + + squashfs_get_cached_block(s, NULL, index_start, index_offset, + index.size + 1, &index_start, &index_offset); + + length = index.index; + *next_block = index.start_block + sblk->directory_table_start; + } + + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; + +finish: + return length + 3; +} + + +static int get_dir_index_using_name(struct super_block *s, + long long *next_block, unsigned int *next_offset, + long long index_start, unsigned int index_offset, int i_count, + const char *name, int size) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + int i, length = 0; + struct squashfs_dir_index *index; + char *str; + + TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); + + str = kmalloc(sizeof(struct squashfs_dir_index) + + (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL); + if (str == NULL) { + ERROR("Failed to allocate squashfs_dir_index\n"); + goto failure; + } + + index = (struct squashfs_dir_index *) (str + SQUASHFS_NAME_LEN + 1); + strncpy(str, name, size); + str[size] = '\0'; + + for (i = 0; i < i_count; i++) { + if (msblk->swap) { + struct squashfs_dir_index sindex; + squashfs_get_cached_block(s, &sindex, index_start, index_offset, + sizeof(sindex), &index_start, &index_offset); + SQUASHFS_SWAP_DIR_INDEX(index, &sindex); + } else + squashfs_get_cached_block(s, index, index_start, index_offset, + sizeof(struct squashfs_dir_index), &index_start, &index_offset); + + squashfs_get_cached_block(s, index->name, index_start, index_offset, + index->size + 1, &index_start, &index_offset); + + index->name[index->size + 1] = '\0'; + + if (strcmp(index->name, str) > 0) + break; + + length = index->index; + *next_block = index->start_block + sblk->directory_table_start; + } + + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; + kfree(str); + +failure: + return length + 3; +} + + +static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir) +{ + struct inode *i = file->f_dentry->d_inode; + struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + long long next_block = SQUASHFS_I(i)->start_block + + sblk->directory_table_start; + int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count; + struct squashfs_dir_header dirh; + struct squashfs_dir_entry *dire; + + TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset); + + dire = kmalloc(sizeof(struct squashfs_dir_entry) + + SQUASHFS_NAME_LEN + 1, GFP_KERNEL); + if (dire == NULL) { + ERROR("Failed to allocate squashfs_dir_entry\n"); + goto finish; + } + + while(file->f_pos < 3) { + char *name; + int size, i_ino; + + if(file->f_pos == 0) { + name = "."; + size = 1; + i_ino = i->i_ino; + } else { + name = ".."; + size = 2; + i_ino = SQUASHFS_I(i)->u.s2.parent_inode; + } + TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n", + (unsigned int) dirent, name, size, (int) + file->f_pos, i_ino, squashfs_filetype_table[1]); + + if (filldir(dirent, name, size, file->f_pos, i_ino, + squashfs_filetype_table[1]) < 0) { + TRACE("Filldir returned less than 0\n"); + goto finish; + } + file->f_pos += size; + } + + length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset, + SQUASHFS_I(i)->u.s2.directory_index_start, + SQUASHFS_I(i)->u.s2.directory_index_offset, + SQUASHFS_I(i)->u.s2.directory_index_count, file->f_pos); + + while (length < i_size_read(i)) { + /* read directory header */ + if (msblk->swap) { + struct squashfs_dir_header sdirh; + + if (!squashfs_get_cached_block(i->i_sb, &sdirh, next_block, + next_offset, sizeof(sdirh), &next_block, &next_offset)) + goto failed_read; + + length += sizeof(sdirh); + SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); + } else { + if (!squashfs_get_cached_block(i->i_sb, &dirh, next_block, + next_offset, sizeof(dirh), &next_block, &next_offset)) + goto failed_read; + + length += sizeof(dirh); + } + + dir_count = dirh.count + 1; + while (dir_count--) { + if (msblk->swap) { + struct squashfs_dir_entry sdire; + if (!squashfs_get_cached_block(i->i_sb, &sdire, next_block, + next_offset, sizeof(sdire), &next_block, &next_offset)) + goto failed_read; + + length += sizeof(sdire); + SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); + } else { + if (!squashfs_get_cached_block(i->i_sb, dire, next_block, + next_offset, sizeof(*dire), &next_block, &next_offset)) + goto failed_read; + + length += sizeof(*dire); + } + + if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block, + next_offset, dire->size + 1, &next_block, &next_offset)) + goto failed_read; + + length += dire->size + 1; + + if (file->f_pos >= length) + continue; + + dire->name[dire->size + 1] = '\0'; + + TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n", + (unsigned int) dirent, dire->name, dire->size + 1, + (int) file->f_pos, dirh.start_block, dire->offset, + dirh.inode_number + dire->inode_number, + squashfs_filetype_table[dire->type]); + + if (filldir(dirent, dire->name, dire->size + 1, file->f_pos, + dirh.inode_number + dire->inode_number, + squashfs_filetype_table[dire->type]) < 0) { + TRACE("Filldir returned less than 0\n"); + goto finish; + } + file->f_pos = length; + } + } + +finish: + kfree(dire); + return 0; + +failed_read: + ERROR("Unable to read directory block [%llx:%x]\n", next_block, + next_offset); + kfree(dire); + return 0; +} + + +static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry, + struct nameidata *nd) +{ + const unsigned char *name = dentry->d_name.name; + int len = dentry->d_name.len; + struct inode *inode = NULL; + struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + long long next_block = SQUASHFS_I(i)->start_block + + sblk->directory_table_start; + int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count; + struct squashfs_dir_header dirh; + struct squashfs_dir_entry *dire; + + TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset); + + dire = kmalloc(sizeof(struct squashfs_dir_entry) + + SQUASHFS_NAME_LEN + 1, GFP_KERNEL); + if (dire == NULL) { + ERROR("Failed to allocate squashfs_dir_entry\n"); + goto exit_lookup; + } + + if (len > SQUASHFS_NAME_LEN) + goto exit_lookup; + + length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, + SQUASHFS_I(i)->u.s2.directory_index_start, + SQUASHFS_I(i)->u.s2.directory_index_offset, + SQUASHFS_I(i)->u.s2.directory_index_count, name, len); + + while (length < i_size_read(i)) { + /* read directory header */ + if (msblk->swap) { + struct squashfs_dir_header sdirh; + if (!squashfs_get_cached_block(i->i_sb, &sdirh, next_block, + next_offset, sizeof(sdirh), &next_block, &next_offset)) + goto failed_read; + + length += sizeof(sdirh); + SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); + } else { + if (!squashfs_get_cached_block(i->i_sb, &dirh, next_block, + next_offset, sizeof(dirh), &next_block, &next_offset)) + goto failed_read; + + length += sizeof(dirh); + } + + dir_count = dirh.count + 1; + while (dir_count--) { + if (msblk->swap) { + struct squashfs_dir_entry sdire; + if (!squashfs_get_cached_block(i->i_sb, &sdire, next_block, + next_offset, sizeof(sdire), &next_block, &next_offset)) + goto failed_read; + + length += sizeof(sdire); + SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); + } else { + if (!squashfs_get_cached_block(i->i_sb, dire, next_block, + next_offset, sizeof(*dire), &next_block, &next_offset)) + goto failed_read; + + length += sizeof(*dire); + } + + if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block, + next_offset, dire->size + 1, &next_block, &next_offset)) + goto failed_read; + + length += dire->size + 1; + + if (name[0] < dire->name[0]) + goto exit_lookup; + + if ((len == dire->size + 1) && !strncmp(name, dire->name, len)) { + squashfs_inode_t ino = SQUASHFS_MKINODE(dirh.start_block, + dire->offset); + + TRACE("calling squashfs_iget for directory entry %s, inode" + " %x:%x, %d\n", name, dirh.start_block, dire->offset, + dirh.inode_number + dire->inode_number); + + inode = squashfs_iget(i->i_sb, ino, dirh.inode_number + dire->inode_number); + + goto exit_lookup; + } + } + } + +exit_lookup: + kfree(dire); + if (inode) + return d_splice_alias(inode, dentry); + d_add(dentry, inode); + return ERR_PTR(0); + +failed_read: + ERROR("Unable to read directory block [%llx:%x]\n", next_block, + next_offset); + goto exit_lookup; +} + + +static int squashfs_remount(struct super_block *s, int *flags, char *data) +{ + *flags |= MS_RDONLY; + return 0; +} + + +static void squashfs_put_super(struct super_block *s) +{ + int i; + + if (s->s_fs_info) { + struct squashfs_sb_info *sbi = s->s_fs_info; + if (sbi->block_cache) + for (i = 0; i < squashfs_cached_blks; i++) + if (sbi->block_cache[i].block != SQUASHFS_INVALID_BLK) + vfree(sbi->block_cache[i].data); + if (sbi->fragment) + for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) + vfree(sbi->fragment[i].data); + kfree(sbi->fragment); + kfree(sbi->block_cache); + vfree(sbi->read_page); + kfree(sbi->uid); + kfree(sbi->fragment_index); + kfree(sbi->fragment_index_2); + kfree(sbi->meta_index); + vfree(sbi->stream.workspace); + kfree(s->s_fs_info); + s->s_fs_info = NULL; + } +} + + +static int squashfs_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, struct vfsmount *mnt) +{ + return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super, + mnt); +} + + +static int __init init_squashfs_fs(void) +{ + int err = init_inodecache(); + if (err) + goto out; + + printk(KERN_INFO "squashfs: version 3.3 (2007/10/31) " + "Phillip Lougher\n"); + + err = register_filesystem(&squashfs_fs_type); + if (err) + destroy_inodecache(); + +out: + return err; +} + + +static void __exit exit_squashfs_fs(void) +{ + unregister_filesystem(&squashfs_fs_type); + destroy_inodecache(); +} + + +static struct kmem_cache * squashfs_inode_cachep; + + +static struct inode *squashfs_alloc_inode(struct super_block *sb) +{ + struct squashfs_inode_info *ei; + ei = kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL); + return ei ? &ei->vfs_inode : NULL; +} + + +static void squashfs_destroy_inode(struct inode *inode) +{ + kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode)); +} + + +static void init_once(void *foo) +{ + struct squashfs_inode_info *ei = foo; + + inode_init_once(&ei->vfs_inode); +} + + +static int __init init_inodecache(void) +{ + squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache", + sizeof(struct squashfs_inode_info), 0, + SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, init_once); + if (squashfs_inode_cachep == NULL) + return -ENOMEM; + return 0; +} + + +static void destroy_inodecache(void) +{ + kmem_cache_destroy(squashfs_inode_cachep); +} + + +module_init(init_squashfs_fs); +module_exit(exit_squashfs_fs); +MODULE_DESCRIPTION("squashfs 3.2-r2-CVS, a compressed read-only filesystem"); +MODULE_AUTHOR("Phillip Lougher "); +MODULE_LICENSE("GPL"); --- linux-2.6.27.orig/ubuntu/squashfs/Makefile +++ linux-2.6.27/ubuntu/squashfs/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the linux squashfs routines. +# + +obj-$(CONFIG_SQUASHFS) += squashfs.o +squashfs-objs := inode.o squashfs2_0.o --- linux-2.6.27.orig/ubuntu/squashfs/squashfs2_0.c +++ linux-2.6.27/ubuntu/squashfs/squashfs2_0.c @@ -0,0 +1,740 @@ +/* + * Squashfs - a compressed read only filesystem for Linux + * + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 + * Phillip Lougher + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * squashfs2_0.c + */ + +#include +#include +#include +#include +#include +#include + +#include "squashfs.h" +static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir); +static struct dentry *squashfs_lookup_2(struct inode *, struct dentry *, + struct nameidata *); + +static struct file_operations squashfs_dir_ops_2 = { + .read = generic_read_dir, + .readdir = squashfs_readdir_2 +}; + +static struct inode_operations squashfs_dir_inode_ops_2 = { + .lookup = squashfs_lookup_2 +}; + +static unsigned char squashfs_filetype_table[] = { + DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK +}; + +static int read_fragment_index_table_2(struct super_block *s) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + + if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2 + (sblk->fragments), GFP_KERNEL))) { + ERROR("Failed to allocate uid/gid table\n"); + return 0; + } + + if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) && + !squashfs_read_data(s, (char *) + msblk->fragment_index_2, + sblk->fragment_table_start, + SQUASHFS_FRAGMENT_INDEX_BYTES_2 + (sblk->fragments) | + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments))) { + ERROR("unable to read fragment index table\n"); + return 0; + } + + if (msblk->swap) { + int i; + unsigned int fragment; + + for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments); + i++) { + SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment), + &msblk->fragment_index_2[i], 1); + msblk->fragment_index_2[i] = fragment; + } + } + + return 1; +} + + +static int get_fragment_location_2(struct super_block *s, unsigned int fragment, + long long *fragment_start_block, + unsigned int *fragment_size) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + long long start_block = + msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)]; + int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment); + struct squashfs_fragment_entry_2 fragment_entry; + + if (msblk->swap) { + struct squashfs_fragment_entry_2 sfragment_entry; + + if (!squashfs_get_cached_block(s, (char *) &sfragment_entry, + start_block, offset, + sizeof(sfragment_entry), &start_block, + &offset)) + goto out; + SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry); + } else + if (!squashfs_get_cached_block(s, (char *) &fragment_entry, + start_block, offset, + sizeof(fragment_entry), &start_block, + &offset)) + goto out; + + *fragment_start_block = fragment_entry.start_block; + *fragment_size = fragment_entry.size; + + return 1; + +out: + return 0; +} + + +static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i, + struct squashfs_base_inode_header_2 *inodeb, unsigned int ino) +{ + struct squashfs_super_block *sblk = &msblk->sblk; + + i->i_ino = ino; + i->i_mtime.tv_sec = sblk->mkfs_time; + i->i_atime.tv_sec = sblk->mkfs_time; + i->i_ctime.tv_sec = sblk->mkfs_time; + i->i_uid = msblk->uid[inodeb->uid]; + i->i_mode = inodeb->mode; + i->i_nlink = 1; + i->i_size = 0; + if (inodeb->guid == SQUASHFS_GUIDS) + i->i_gid = i->i_uid; + else + i->i_gid = msblk->guid[inodeb->guid]; +} + + +static int squashfs_read_inode_2(struct inode *i, squashfs_inode_t inode) +{ + struct super_block *s = i->i_sb; + struct squashfs_sb_info *msblk = s->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + unsigned int block = SQUASHFS_INODE_BLK(inode) + + sblk->inode_table_start; + unsigned int offset = SQUASHFS_INODE_OFFSET(inode); + unsigned int ino = SQUASHFS_MK_VFS_INODE(block - + sblk->inode_table_start, offset); + long long next_block; + unsigned int next_offset; + union squashfs_inode_header_2 id, sid; + struct squashfs_base_inode_header_2 *inodeb = &id.base, + *sinodeb = &sid.base; + + TRACE("Entered squashfs_read_inode_2\n"); + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) sinodeb, block, + offset, sizeof(*sinodeb), &next_block, + &next_offset)) + goto failed_read; + SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb, + sizeof(*sinodeb)); + } else + if (!squashfs_get_cached_block(s, (char *) inodeb, block, + offset, sizeof(*inodeb), &next_block, + &next_offset)) + goto failed_read; + + squashfs_new_inode(msblk, i, inodeb, ino); + + switch(inodeb->inode_type) { + case SQUASHFS_FILE_TYPE: { + struct squashfs_reg_inode_header_2 *inodep = &id.reg; + struct squashfs_reg_inode_header_2 *sinodep = &sid.reg; + long long frag_blk; + unsigned int frag_size = 0; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) + sinodep, block, offset, + sizeof(*sinodep), &next_block, + &next_offset)) + goto failed_read; + SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep); + } else + if (!squashfs_get_cached_block(s, (char *) + inodep, block, offset, + sizeof(*inodep), &next_block, + &next_offset)) + goto failed_read; + + frag_blk = SQUASHFS_INVALID_BLK; + if (inodep->fragment != SQUASHFS_INVALID_FRAG && + !get_fragment_location_2(s, + inodep->fragment, &frag_blk, &frag_size)) + goto failed_read; + + i->i_size = inodep->file_size; + i->i_fop = &generic_ro_fops; + i->i_mode |= S_IFREG; + i->i_mtime.tv_sec = inodep->mtime; + i->i_atime.tv_sec = inodep->mtime; + i->i_ctime.tv_sec = inodep->mtime; + i->i_blocks = ((i->i_size - 1) >> 9) + 1; + SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; + SQUASHFS_I(i)->u.s1.fragment_size = frag_size; + SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; + SQUASHFS_I(i)->start_block = inodep->start_block; + SQUASHFS_I(i)->u.s1.block_list_start = next_block; + SQUASHFS_I(i)->offset = next_offset; + i->i_data.a_ops = &squashfs_aops; + + TRACE("File inode %x:%x, start_block %x, " + "block_list_start %llx, offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, + inodep->start_block, next_block, + next_offset); + break; + } + case SQUASHFS_DIR_TYPE: { + struct squashfs_dir_inode_header_2 *inodep = &id.dir; + struct squashfs_dir_inode_header_2 *sinodep = &sid.dir; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) + sinodep, block, offset, + sizeof(*sinodep), &next_block, + &next_offset)) + goto failed_read; + SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep); + } else + if (!squashfs_get_cached_block(s, (char *) + inodep, block, offset, + sizeof(*inodep), &next_block, + &next_offset)) + goto failed_read; + + i->i_size = inodep->file_size; + i->i_op = &squashfs_dir_inode_ops_2; + i->i_fop = &squashfs_dir_ops_2; + i->i_mode |= S_IFDIR; + i->i_mtime.tv_sec = inodep->mtime; + i->i_atime.tv_sec = inodep->mtime; + i->i_ctime.tv_sec = inodep->mtime; + SQUASHFS_I(i)->start_block = inodep->start_block; + SQUASHFS_I(i)->offset = inodep->offset; + SQUASHFS_I(i)->u.s2.directory_index_count = 0; + SQUASHFS_I(i)->u.s2.parent_inode = 0; + + TRACE("Directory inode %x:%x, start_block %x, offset " + "%x\n", SQUASHFS_INODE_BLK(inode), + offset, inodep->start_block, + inodep->offset); + break; + } + case SQUASHFS_LDIR_TYPE: { + struct squashfs_ldir_inode_header_2 *inodep = &id.ldir; + struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) + sinodep, block, offset, + sizeof(*sinodep), &next_block, + &next_offset)) + goto failed_read; + SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep, + sinodep); + } else + if (!squashfs_get_cached_block(s, (char *) + inodep, block, offset, + sizeof(*inodep), &next_block, + &next_offset)) + goto failed_read; + + i->i_size = inodep->file_size; + i->i_op = &squashfs_dir_inode_ops_2; + i->i_fop = &squashfs_dir_ops_2; + i->i_mode |= S_IFDIR; + i->i_mtime.tv_sec = inodep->mtime; + i->i_atime.tv_sec = inodep->mtime; + i->i_ctime.tv_sec = inodep->mtime; + SQUASHFS_I(i)->start_block = inodep->start_block; + SQUASHFS_I(i)->offset = inodep->offset; + SQUASHFS_I(i)->u.s2.directory_index_start = next_block; + SQUASHFS_I(i)->u.s2.directory_index_offset = + next_offset; + SQUASHFS_I(i)->u.s2.directory_index_count = + inodep->i_count; + SQUASHFS_I(i)->u.s2.parent_inode = 0; + + TRACE("Long directory inode %x:%x, start_block %x, " + "offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, + inodep->start_block, inodep->offset); + break; + } + case SQUASHFS_SYMLINK_TYPE: { + struct squashfs_symlink_inode_header_2 *inodep = + &id.symlink; + struct squashfs_symlink_inode_header_2 *sinodep = + &sid.symlink; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) + sinodep, block, offset, + sizeof(*sinodep), &next_block, + &next_offset)) + goto failed_read; + SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep, + sinodep); + } else + if (!squashfs_get_cached_block(s, (char *) + inodep, block, offset, + sizeof(*inodep), &next_block, + &next_offset)) + goto failed_read; + + i->i_size = inodep->symlink_size; + i->i_op = &page_symlink_inode_operations; + i->i_data.a_ops = &squashfs_symlink_aops; + i->i_mode |= S_IFLNK; + SQUASHFS_I(i)->start_block = next_block; + SQUASHFS_I(i)->offset = next_offset; + + TRACE("Symbolic link inode %x:%x, start_block %llx, " + "offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, + next_block, next_offset); + break; + } + case SQUASHFS_BLKDEV_TYPE: + case SQUASHFS_CHRDEV_TYPE: { + struct squashfs_dev_inode_header_2 *inodep = &id.dev; + struct squashfs_dev_inode_header_2 *sinodep = &sid.dev; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) + sinodep, block, offset, + sizeof(*sinodep), &next_block, + &next_offset)) + goto failed_read; + SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep); + } else + if (!squashfs_get_cached_block(s, (char *) + inodep, block, offset, + sizeof(*inodep), &next_block, + &next_offset)) + goto failed_read; + + i->i_mode |= (inodeb->inode_type == + SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : + S_IFBLK; + init_special_inode(i, i->i_mode, + old_decode_dev(inodep->rdev)); + + TRACE("Device inode %x:%x, rdev %x\n", + SQUASHFS_INODE_BLK(inode), offset, + inodep->rdev); + break; + } + case SQUASHFS_FIFO_TYPE: + case SQUASHFS_SOCKET_TYPE: { + + i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE) + ? S_IFIFO : S_IFSOCK; + init_special_inode(i, i->i_mode, 0); + break; + } + default: + ERROR("Unknown inode type %d in squashfs_iget!\n", + inodeb->inode_type); + goto failed_read1; + } + + return 1; + +failed_read: + ERROR("Unable to read inode [%x:%x]\n", block, offset); + +failed_read1: + return 0; +} + + +static int get_dir_index_using_offset(struct super_block *s, long long + *next_block, unsigned int *next_offset, + long long index_start, + unsigned int index_offset, int i_count, + long long f_pos) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + int i, length = 0; + struct squashfs_dir_index_2 index; + + TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n", + i_count, (unsigned int) f_pos); + + if (f_pos == 0) + goto finish; + + for (i = 0; i < i_count; i++) { + if (msblk->swap) { + struct squashfs_dir_index_2 sindex; + squashfs_get_cached_block(s, (char *) &sindex, + index_start, index_offset, + sizeof(sindex), &index_start, + &index_offset); + SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex); + } else + squashfs_get_cached_block(s, (char *) &index, + index_start, index_offset, + sizeof(index), &index_start, + &index_offset); + + if (index.index > f_pos) + break; + + squashfs_get_cached_block(s, NULL, index_start, index_offset, + index.size + 1, &index_start, + &index_offset); + + length = index.index; + *next_block = index.start_block + sblk->directory_table_start; + } + + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; + +finish: + return length; +} + + +static int get_dir_index_using_name(struct super_block *s, long long + *next_block, unsigned int *next_offset, + long long index_start, + unsigned int index_offset, int i_count, + const char *name, int size) +{ + struct squashfs_sb_info *msblk = s->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + int i, length = 0; + struct squashfs_dir_index_2 *index; + char *str; + + TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); + + if (!(str = kmalloc(sizeof(struct squashfs_dir_index) + + (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) { + ERROR("Failed to allocate squashfs_dir_index\n"); + goto failure; + } + + index = (struct squashfs_dir_index_2 *) (str + SQUASHFS_NAME_LEN + 1); + strncpy(str, name, size); + str[size] = '\0'; + + for (i = 0; i < i_count; i++) { + if (msblk->swap) { + struct squashfs_dir_index_2 sindex; + squashfs_get_cached_block(s, (char *) &sindex, + index_start, index_offset, + sizeof(sindex), &index_start, + &index_offset); + SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex); + } else + squashfs_get_cached_block(s, (char *) index, + index_start, index_offset, + sizeof(struct squashfs_dir_index_2), + &index_start, &index_offset); + + squashfs_get_cached_block(s, index->name, index_start, + index_offset, index->size + 1, + &index_start, &index_offset); + + index->name[index->size + 1] = '\0'; + + if (strcmp(index->name, str) > 0) + break; + + length = index->index; + *next_block = index->start_block + sblk->directory_table_start; + } + + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; + kfree(str); +failure: + return length; +} + + +static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir) +{ + struct inode *i = file->f_dentry->d_inode; + struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + long long next_block = SQUASHFS_I(i)->start_block + + sblk->directory_table_start; + int next_offset = SQUASHFS_I(i)->offset, length = 0, + dir_count; + struct squashfs_dir_header_2 dirh; + struct squashfs_dir_entry_2 *dire; + + TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset); + + if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + + SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { + ERROR("Failed to allocate squashfs_dir_entry\n"); + goto finish; + } + + length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset, + SQUASHFS_I(i)->u.s2.directory_index_start, + SQUASHFS_I(i)->u.s2.directory_index_offset, + SQUASHFS_I(i)->u.s2.directory_index_count, + file->f_pos); + + while (length < i_size_read(i)) { + /* read directory header */ + if (msblk->swap) { + struct squashfs_dir_header_2 sdirh; + + if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, + next_block, next_offset, sizeof(sdirh), + &next_block, &next_offset)) + goto failed_read; + + length += sizeof(sdirh); + SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); + } else { + if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, + next_block, next_offset, sizeof(dirh), + &next_block, &next_offset)) + goto failed_read; + + length += sizeof(dirh); + } + + dir_count = dirh.count + 1; + while (dir_count--) { + if (msblk->swap) { + struct squashfs_dir_entry_2 sdire; + if (!squashfs_get_cached_block(i->i_sb, (char *) + &sdire, next_block, next_offset, + sizeof(sdire), &next_block, + &next_offset)) + goto failed_read; + + length += sizeof(sdire); + SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); + } else { + if (!squashfs_get_cached_block(i->i_sb, (char *) + dire, next_block, next_offset, + sizeof(*dire), &next_block, + &next_offset)) + goto failed_read; + + length += sizeof(*dire); + } + + if (!squashfs_get_cached_block(i->i_sb, dire->name, + next_block, next_offset, + dire->size + 1, &next_block, + &next_offset)) + goto failed_read; + + length += dire->size + 1; + + if (file->f_pos >= length) + continue; + + dire->name[dire->size + 1] = '\0'; + + TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n", + (unsigned int) dirent, dire->name, + dire->size + 1, (int) file->f_pos, + dirh.start_block, dire->offset, + squashfs_filetype_table[dire->type]); + + if (filldir(dirent, dire->name, dire->size + 1, + file->f_pos, SQUASHFS_MK_VFS_INODE( + dirh.start_block, dire->offset), + squashfs_filetype_table[dire->type]) + < 0) { + TRACE("Filldir returned less than 0\n"); + goto finish; + } + file->f_pos = length; + } + } + +finish: + kfree(dire); + return 0; + +failed_read: + ERROR("Unable to read directory block [%llx:%x]\n", next_block, + next_offset); + kfree(dire); + return 0; +} + + +static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry, + struct nameidata *nd) +{ + const unsigned char *name = dentry->d_name.name; + int len = dentry->d_name.len; + struct inode *inode = NULL; + struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; + long long next_block = SQUASHFS_I(i)->start_block + + sblk->directory_table_start; + int next_offset = SQUASHFS_I(i)->offset, length = 0, + dir_count; + struct squashfs_dir_header_2 dirh; + struct squashfs_dir_entry_2 *dire; + int sorted = sblk->s_major == 2 && sblk->s_minor >= 1; + + TRACE("Entered squashfs_lookup_2 [%llx:%x]\n", next_block, next_offset); + + if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + + SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { + ERROR("Failed to allocate squashfs_dir_entry\n"); + goto exit_loop; + } + + if (len > SQUASHFS_NAME_LEN) + goto exit_loop; + + length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, + SQUASHFS_I(i)->u.s2.directory_index_start, + SQUASHFS_I(i)->u.s2.directory_index_offset, + SQUASHFS_I(i)->u.s2.directory_index_count, name, + len); + + while (length < i_size_read(i)) { + /* read directory header */ + if (msblk->swap) { + struct squashfs_dir_header_2 sdirh; + if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, + next_block, next_offset, sizeof(sdirh), + &next_block, &next_offset)) + goto failed_read; + + length += sizeof(sdirh); + SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); + } else { + if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, + next_block, next_offset, sizeof(dirh), + &next_block, &next_offset)) + goto failed_read; + + length += sizeof(dirh); + } + + dir_count = dirh.count + 1; + while (dir_count--) { + if (msblk->swap) { + struct squashfs_dir_entry_2 sdire; + if (!squashfs_get_cached_block(i->i_sb, (char *) + &sdire, next_block,next_offset, + sizeof(sdire), &next_block, + &next_offset)) + goto failed_read; + + length += sizeof(sdire); + SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); + } else { + if (!squashfs_get_cached_block(i->i_sb, (char *) + dire, next_block,next_offset, + sizeof(*dire), &next_block, + &next_offset)) + goto failed_read; + + length += sizeof(*dire); + } + + if (!squashfs_get_cached_block(i->i_sb, dire->name, + next_block, next_offset, dire->size + 1, + &next_block, &next_offset)) + goto failed_read; + + length += dire->size + 1; + + if (sorted && name[0] < dire->name[0]) + goto exit_loop; + + if ((len == dire->size + 1) && !strncmp(name, + dire->name, len)) { + squashfs_inode_t ino = + SQUASHFS_MKINODE(dirh.start_block, + dire->offset); + unsigned int inode_number = SQUASHFS_MK_VFS_INODE(dirh.start_block, + dire->offset); + + TRACE("calling squashfs_iget for directory " + "entry %s, inode %x:%x, %lld\n", name, + dirh.start_block, dire->offset, ino); + + inode = squashfs_iget(i->i_sb, ino, inode_number); + + goto exit_loop; + } + } + } + +exit_loop: + kfree(dire); + d_add(dentry, inode); + return ERR_PTR(0); + +failed_read: + ERROR("Unable to read directory block [%llx:%x]\n", next_block, + next_offset); + goto exit_loop; +} + + +int squashfs_2_0_supported(struct squashfs_sb_info *msblk) +{ + struct squashfs_super_block *sblk = &msblk->sblk; + + msblk->read_inode = squashfs_read_inode_2; + msblk->read_fragment_index_table = read_fragment_index_table_2; + + sblk->bytes_used = sblk->bytes_used_2; + sblk->uid_start = sblk->uid_start_2; + sblk->guid_start = sblk->guid_start_2; + sblk->inode_table_start = sblk->inode_table_start_2; + sblk->directory_table_start = sblk->directory_table_start_2; + sblk->fragment_table_start = sblk->fragment_table_start_2; + + return 1; +} --- linux-2.6.27.orig/ubuntu/squashfs/squashfs.h +++ linux-2.6.27/ubuntu/squashfs/squashfs.h @@ -0,0 +1,86 @@ +/* + * Squashfs - a compressed read only filesystem for Linux + * + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 + * Phillip Lougher + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * squashfs.h + */ + +#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY +#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY +#endif + +#ifdef SQUASHFS_TRACE +#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args) +#else +#define TRACE(s, args...) {} +#endif + +#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args) + +#define SERROR(s, args...) do { \ + if (!silent) \ + printk(KERN_ERR "SQUASHFS error: "s, ## args);\ + } while(0) + +#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args) + +static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode) +{ + return list_entry(inode, struct squashfs_inode_info, vfs_inode); +} + +#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY) +#define SQSH_EXTERN +extern unsigned int squashfs_read_data(struct super_block *s, char *buffer, + long long index, unsigned int length, + long long *next_index, int srclength); +extern int squashfs_get_cached_block(struct super_block *s, void *buffer, + long long block, unsigned int offset, + int length, long long *next_block, + unsigned int *next_offset); +extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct + squashfs_fragment_cache *fragment); +extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block + *s, long long start_block, + int length); +extern struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number); +extern const struct address_space_operations squashfs_symlink_aops; +extern const struct address_space_operations squashfs_aops; +extern struct inode_operations squashfs_dir_inode_ops; +#else +#define SQSH_EXTERN static +#endif + +#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY +extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk); +#else +static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk) +{ + return 0; +} +#endif + +#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY +extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk); +#else +static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk) +{ + return 0; +} +#endif --- linux-2.6.27.orig/ubuntu/squashfs/BOM +++ linux-2.6.27/ubuntu/squashfs/BOM @@ -0,0 +1,2 @@ +Downloaded from: http://sourceforge.net/project/showfiles.php?group_id=63835 +Current Version: 3.3 --- linux-2.6.27.orig/drivers/bluetooth/hci_usb.c +++ linux-2.6.27/drivers/bluetooth/hci_usb.c @@ -137,6 +137,9 @@ { USB_DEVICE(0x413c, 0x8156), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, /* Dell Wireless 410 */ { USB_DEVICE(0x413c, 0x8152), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, + + /* Broadcom 2046 */ + { USB_DEVICE(0x0a5c, 0x2151), .driver_info = HCI_RESET }, /* Broadcom 2046 */ { USB_DEVICE(0x0a5c, 0x2151), .driver_info = HCI_RESET }, @@ -1030,8 +1033,10 @@ while ((_urb = _urb_dequeue(q))) { /* reset queue since _urb_dequeue sets it to NULL */ _urb->queue = q; - usb_kill_urb(&_urb->urb); + spin_lock_irqsave(&q->lock, flags); list_add(&_urb->list, &killed); + spin_unlock_irqrestore(&q->lock, flags); + usb_kill_urb(&_urb->urb); } spin_lock_irqsave(&q->lock, flags); --- linux-2.6.27.orig/drivers/bluetooth/bt3c_cs.c +++ linux-2.6.27/drivers/bluetooth/bt3c_cs.c @@ -344,7 +344,10 @@ unsigned int iobase; int iir; - BUG_ON(!info->hdev); + if (!info || !info->hdev) { + BT_ERR("Call of irq %d for unknown device", irq); + return IRQ_NONE; + } iobase = info->p_dev->io.BasePort1; --- linux-2.6.27.orig/drivers/bluetooth/btusb.c +++ linux-2.6.27/drivers/bluetooth/btusb.c @@ -41,6 +41,7 @@ #define BT_DBG(D...) #endif +/* Backported patch would update version from 0.4 to 0.5 */ #define VERSION "0.3" static int ignore_dga; @@ -108,6 +109,9 @@ /* Apple MacBook Pro with Broadcom chip */ { USB_DEVICE(0x05ac, 0x820f), .driver_info = BTUSB_RESET }, + /* Apple MacBook Pro 5,1 */ + { USB_DEVICE(0x05ac, 0x8213), .driver_info = BTUSB_RESET }, + /* IBM/Lenovo ThinkPad with Broadcom chip */ { USB_DEVICE(0x0a5c, 0x201e), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x2110), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, @@ -125,6 +129,9 @@ /* Dell laptop with Broadcom chip */ { USB_DEVICE(0x413c, 0x8126), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, + /* Dell Wireless 365 */ + { USB_DEVICE(0x413c, 0x8160), .driver_info = BTUSB_RESET }, + /* Dell Wireless 370 */ { USB_DEVICE(0x413c, 0x8156), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, @@ -197,6 +204,7 @@ struct usb_endpoint_descriptor *isoc_tx_ep; struct usb_endpoint_descriptor *isoc_rx_ep; + unsigned int sco_num; int isoc_altsetting; }; @@ -236,7 +244,7 @@ } } -static int btusb_submit_intr_urb(struct hci_dev *hdev) +static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags) { struct btusb_data *data = hdev->driver_data; struct urb *urb; @@ -249,13 +257,13 @@ if (!data->intr_ep) return -ENODEV; - urb = usb_alloc_urb(0, GFP_ATOMIC); + urb = usb_alloc_urb(0, mem_flags); if (!urb) return -ENOMEM; size = le16_to_cpu(data->intr_ep->wMaxPacketSize); - buf = kmalloc(size, GFP_ATOMIC); + buf = kmalloc(size, mem_flags); if (!buf) { usb_free_urb(urb); return -ENOMEM; @@ -271,7 +279,7 @@ usb_anchor_urb(urb, &data->intr_anchor); - err = usb_submit_urb(urb, GFP_ATOMIC); + err = usb_submit_urb(urb, mem_flags); if (err < 0) { BT_ERR("%s urb %p submission failed (%d)", hdev->name, urb, -err); @@ -319,7 +327,7 @@ } } -static int btusb_submit_bulk_urb(struct hci_dev *hdev) +static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags) { struct btusb_data *data = hdev->driver_data; struct urb *urb; @@ -332,13 +340,13 @@ if (!data->bulk_rx_ep) return -ENODEV; - urb = usb_alloc_urb(0, GFP_KERNEL); + urb = usb_alloc_urb(0, mem_flags); if (!urb) return -ENOMEM; size = le16_to_cpu(data->bulk_rx_ep->wMaxPacketSize); - buf = kmalloc(size, GFP_KERNEL); + buf = kmalloc(size, mem_flags); if (!buf) { usb_free_urb(urb); return -ENOMEM; @@ -353,7 +361,7 @@ usb_anchor_urb(urb, &data->bulk_anchor); - err = usb_submit_urb(urb, GFP_KERNEL); + err = usb_submit_urb(urb, mem_flags); if (err < 0) { BT_ERR("%s urb %p submission failed (%d)", hdev->name, urb, -err); @@ -430,7 +438,7 @@ urb->number_of_packets = i; } -static int btusb_submit_isoc_urb(struct hci_dev *hdev) +static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags) { struct btusb_data *data = hdev->driver_data; struct urb *urb; @@ -443,14 +451,14 @@ if (!data->isoc_rx_ep) return -ENODEV; - urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL); + urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, mem_flags); if (!urb) return -ENOMEM; size = le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize) * BTUSB_MAX_ISOC_FRAMES; - buf = kmalloc(size, GFP_KERNEL); + buf = kmalloc(size, mem_flags); if (!buf) { usb_free_urb(urb); return -ENOMEM; @@ -473,7 +481,7 @@ usb_anchor_urb(urb, &data->isoc_anchor); - err = usb_submit_urb(urb, GFP_KERNEL); + err = usb_submit_urb(urb, mem_flags); if (err < 0) { BT_ERR("%s urb %p submission failed (%d)", hdev->name, urb, -err); @@ -520,12 +528,24 @@ if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags)) return 0; - err = btusb_submit_intr_urb(hdev); + err = btusb_submit_intr_urb(hdev, GFP_KERNEL); + if (err < 0) + goto failed; + + err = btusb_submit_bulk_urb(hdev, GFP_KERNEL); if (err < 0) { - clear_bit(BTUSB_INTR_RUNNING, &data->flags); - clear_bit(HCI_RUNNING, &hdev->flags); + usb_kill_anchored_urbs(&data->intr_anchor); + goto failed; } + set_bit(BTUSB_BULK_RUNNING, &data->flags); + btusb_submit_bulk_urb(hdev, GFP_KERNEL); + + return 0; + +failed: + clear_bit(BTUSB_INTR_RUNNING, &data->flags); + clear_bit(HCI_RUNNING, &hdev->flags); return err; } @@ -680,8 +700,10 @@ BT_DBG("%s evt %d", hdev->name, evt); - if (evt == HCI_NOTIFY_CONN_ADD || evt == HCI_NOTIFY_CONN_DEL) + if (hdev->conn_hash.sco_num != data->sco_num) { + data->sco_num = hdev->conn_hash.sco_num; schedule_work(&data->work); + } } static int inline __set_isoc_interface(struct hci_dev *hdev, int altsetting) @@ -732,18 +754,6 @@ struct btusb_data *data = container_of(work, struct btusb_data, work); struct hci_dev *hdev = data->hdev; - if (hdev->conn_hash.acl_num > 0) { - if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) { - if (btusb_submit_bulk_urb(hdev) < 0) - clear_bit(BTUSB_BULK_RUNNING, &data->flags); - else - btusb_submit_bulk_urb(hdev); - } - } else { - clear_bit(BTUSB_BULK_RUNNING, &data->flags); - usb_kill_anchored_urbs(&data->bulk_anchor); - } - if (hdev->conn_hash.sco_num > 0) { if (data->isoc_altsetting != 2) { clear_bit(BTUSB_ISOC_RUNNING, &data->flags); @@ -754,10 +764,10 @@ } if (!test_and_set_bit(BTUSB_ISOC_RUNNING, &data->flags)) { - if (btusb_submit_isoc_urb(hdev) < 0) + if (btusb_submit_isoc_urb(hdev, GFP_KERNEL) < 0) clear_bit(BTUSB_ISOC_RUNNING, &data->flags); else - btusb_submit_isoc_urb(hdev); + btusb_submit_isoc_urb(hdev, GFP_KERNEL); } } else { clear_bit(BTUSB_ISOC_RUNNING, &data->flags); --- linux-2.6.27.orig/drivers/bluetooth/dtl1_cs.c +++ linux-2.6.27/drivers/bluetooth/dtl1_cs.c @@ -298,7 +298,10 @@ int boguscount = 0; int iir, lsr; - BUG_ON(!info->hdev); + if (!info || !info->hdev) { + BT_ERR("Call of irq %d for unknown device", irq); + return IRQ_NONE; + } iobase = info->p_dev->io.BasePort1; --- linux-2.6.27.orig/drivers/bluetooth/bluecard_cs.c +++ linux-2.6.27/drivers/bluetooth/bluecard_cs.c @@ -503,7 +503,10 @@ unsigned int iobase; unsigned char reg; - BUG_ON(!info->hdev); + if (!info || !info->hdev) { + BT_ERR("Call of irq %d for unknown device", irq); + return IRQ_NONE; + } if (!test_bit(CARD_READY, &(info->hw_state))) return IRQ_HANDLED; --- linux-2.6.27.orig/drivers/bluetooth/btuart_cs.c +++ linux-2.6.27/drivers/bluetooth/btuart_cs.c @@ -294,7 +294,10 @@ int boguscount = 0; int iir, lsr; - BUG_ON(!info->hdev); + if (!info || !info->hdev) { + BT_ERR("Call of irq %d for unknown device", irq); + return IRQ_NONE; + } iobase = info->p_dev->io.BasePort1; --- linux-2.6.27.orig/drivers/mtd/chips/jedec_probe.c +++ linux-2.6.27/drivers/mtd/chips/jedec_probe.c @@ -1808,9 +1808,7 @@ * several first banks can contain 0x7f instead of actual ID */ do { - uint32_t ofs = cfi_build_cmd_addr(0 + (bank << 8), - cfi_interleave(cfi), - cfi->device_type); + uint32_t ofs = cfi_build_cmd_addr(0 + (bank << 8), map, cfi); mask = (1 << (cfi->device_type * 8)) - 1; result = map_read(map, base + ofs); bank++; @@ -1824,7 +1822,7 @@ { map_word result; unsigned long mask; - u32 ofs = cfi_build_cmd_addr(1, cfi_interleave(cfi), cfi->device_type); + u32 ofs = cfi_build_cmd_addr(1, map, cfi); mask = (1 << (cfi->device_type * 8)) -1; result = map_read(map, base + ofs); return result.x[0] & mask; @@ -2067,8 +2065,8 @@ } /* Ensure the unlock addresses we try stay inside the map */ - probe_offset1 = cfi_build_cmd_addr(cfi->addr_unlock1, cfi_interleave(cfi), cfi->device_type); - probe_offset2 = cfi_build_cmd_addr(cfi->addr_unlock2, cfi_interleave(cfi), cfi->device_type); + probe_offset1 = cfi_build_cmd_addr(cfi->addr_unlock1, map, cfi); + probe_offset2 = cfi_build_cmd_addr(cfi->addr_unlock2, map, cfi); if ( ((base + probe_offset1 + map_bankwidth(map)) >= map->size) || ((base + probe_offset2 + map_bankwidth(map)) >= map->size)) goto retry; --- linux-2.6.27.orig/drivers/mtd/chips/cfi_cmdset_0002.c +++ linux-2.6.27/drivers/mtd/chips/cfi_cmdset_0002.c @@ -362,19 +362,6 @@ /* Set the default CFI lock/unlock addresses */ cfi->addr_unlock1 = 0x555; cfi->addr_unlock2 = 0x2aa; - /* Modify the unlock address if we are in compatibility mode */ - if ( /* x16 in x8 mode */ - ((cfi->device_type == CFI_DEVICETYPE_X8) && - (cfi->cfiq->InterfaceDesc == - CFI_INTERFACE_X8_BY_X16_ASYNC)) || - /* x32 in x16 mode */ - ((cfi->device_type == CFI_DEVICETYPE_X16) && - (cfi->cfiq->InterfaceDesc == - CFI_INTERFACE_X16_BY_X32_ASYNC))) - { - cfi->addr_unlock1 = 0xaaa; - cfi->addr_unlock2 = 0x555; - } } /* CFI mode */ else if (cfi->cfi_mode == CFI_MODE_JEDEC) { --- linux-2.6.27.orig/drivers/edac/cell_edac.c +++ linux-2.6.27/drivers/edac/cell_edac.c @@ -9,6 +9,7 @@ */ #undef DEBUG +#include #include #include #include @@ -142,7 +143,7 @@ csrow->nr_pages = (r.end - r.start + 1) >> PAGE_SHIFT; csrow->last_page = csrow->first_page + csrow->nr_pages - 1; csrow->mtype = MEM_XDR; - csrow->edac_mode = EDAC_FLAG_EC | EDAC_FLAG_SECDED; + csrow->edac_mode = EDAC_SECDED; dev_dbg(mci->dev, "Initialized on node %d, chanmask=0x%x," " first_page=0x%lx, nr_pages=0x%x\n", @@ -164,6 +165,8 @@ if (regs == NULL) return -ENODEV; + edac_op_state = EDAC_OPSTATE_POLL; + /* Get channel population */ reg = in_be64(®s->mic_mnt_cfg); dev_dbg(&pdev->dev, "MIC_MNT_CFG = 0x%016lx\n", reg); --- linux-2.6.27.orig/drivers/cpuidle/cpuidle.c +++ linux-2.6.27/drivers/cpuidle/cpuidle.c @@ -56,7 +56,11 @@ if (pm_idle_old) pm_idle_old(); else +#if defined(CONFIG_ARCH_HAS_DEFAULT_IDLE) + default_idle(); +#else local_irq_enable(); +#endif return; } @@ -67,8 +71,11 @@ target_state = &dev->states[next_state]; /* enter the state and update stats */ - dev->last_residency = target_state->enter(dev, target_state); dev->last_state = target_state; + dev->last_residency = target_state->enter(dev, target_state); + if (dev->last_state) + target_state = dev->last_state; + target_state->time += (unsigned long long)dev->last_residency; target_state->usage++; --- linux-2.6.27.orig/drivers/cpuidle/governors/menu.c +++ linux-2.6.27/drivers/cpuidle/governors/menu.c @@ -15,12 +15,14 @@ #include #define BREAK_FUZZ 4 /* 4 us */ +#define PRED_HISTORY_PCT 50 struct menu_device { int last_state_idx; unsigned int expected_us; unsigned int predicted_us; + unsigned int current_predicted_us; unsigned int last_measured_us; unsigned int elapsed_us; }; @@ -47,6 +49,12 @@ data->expected_us = (u32) ktime_to_ns(tick_nohz_get_sleep_length()) / 1000; + /* Recalculate predicted_us based on prediction_history_pct */ + data->predicted_us *= PRED_HISTORY_PCT; + data->predicted_us += (100 - PRED_HISTORY_PCT) * + data->current_predicted_us; + data->predicted_us /= 100; + /* find the deepest idle state that satisfies our constraints */ for (i = CPUIDLE_DRIVER_STATE_START + 1; i < dev->state_count; i++) { struct cpuidle_state *s = &dev->states[i]; @@ -97,7 +105,7 @@ measured_us = -1; /* Predict time until next break event */ - data->predicted_us = max(measured_us, data->last_measured_us); + data->current_predicted_us = max(measured_us, data->last_measured_us); if (last_idle_us + BREAK_FUZZ < data->expected_us - target->exit_latency) { --- linux-2.6.27.orig/drivers/serial/8250_pci.c +++ linux-2.6.27/drivers/serial/8250_pci.c @@ -599,6 +599,10 @@ /* subdevice 0x00PS means

parallel, serial */ unsigned int num_serial = dev->subsystem_device & 0xf; + if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM && + dev->subsystem_device == 0x0299) + return 0; + if (num_serial == 0) return -ENODEV; return num_serial; @@ -766,6 +770,8 @@ #define PCI_SUBDEVICE_ID_OCTPRO422 0x0208 #define PCI_SUBDEVICE_ID_POCTAL232 0x0308 #define PCI_SUBDEVICE_ID_POCTAL422 0x0408 +#define PCI_VENDOR_ID_ADVANTECH 0x13fe +#define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 @@ -2051,6 +2057,10 @@ #endif static struct pci_device_id serial_pci_tbl[] = { + /* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */ + { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620, + PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0, + pbn_b2_8_921600 }, { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0, @@ -2190,6 +2200,9 @@ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_8_115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_7803, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_8_460800 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_8_115200 }, @@ -2291,6 +2304,9 @@ * For now just used the hex ID 0x950a. */ { PCI_VENDOR_ID_OXSEMI, 0x950a, + PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL, 0, 0, + pbn_b0_2_115200 }, + { PCI_VENDOR_ID_OXSEMI, 0x950a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_2_1130000 }, { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, @@ -2843,6 +2859,10 @@ 0, pbn_b0_8_115200 }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835, + PCI_VENDOR_ID_IBM, 0x0299, + 0, 0, pbn_b0_bt_2_115200 }, + /* * These entries match devices with class COMMUNICATION_SERIAL, * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL --- linux-2.6.27.orig/drivers/serial/jsm/jsm_tty.c +++ linux-2.6.27/drivers/serial/jsm/jsm_tty.c @@ -161,6 +161,11 @@ channel->ch_bd->bd_ops->disable_receiver(channel); } +static void jsm_tty_enable_ms(struct uart_port *port) +{ + /* Nothing needed */ +} + static void jsm_tty_break(struct uart_port *port, int break_state) { unsigned long lock_flags; @@ -345,6 +350,7 @@ .start_tx = jsm_tty_start_tx, .send_xchar = jsm_tty_send_xchar, .stop_rx = jsm_tty_stop_rx, + .enable_ms = jsm_tty_enable_ms, .break_ctl = jsm_tty_break, .startup = jsm_tty_open, .shutdown = jsm_tty_close, --- linux-2.6.27.orig/drivers/isdn/hardware/avm/b1isa.c +++ linux-2.6.27/drivers/isdn/hardware/avm/b1isa.c @@ -233,10 +233,8 @@ int i; for (i = 0; i < MAX_CARDS; i++) { - if (!io[i]) - break; - - b1isa_remove(&isa_dev[i]); + if (isa_dev[i].resource[0].start) + b1isa_remove(&isa_dev[i]); } unregister_capi_driver(&capi_driver_b1isa); } --- linux-2.6.27.orig/drivers/hid/hidraw.c +++ linux-2.6.27/drivers/hid/hidraw.c @@ -113,7 +113,7 @@ if (!dev->hid_output_raw_report) return -ENODEV; - if (count > HID_MIN_BUFFER_SIZE) { + if (count > HID_MAX_BUFFER_SIZE) { printk(KERN_WARNING "hidraw: pid %d passed too large report\n", task_pid_nr(current)); return -EINVAL; --- linux-2.6.27.orig/drivers/hid/usbhid/hid-quirks.c +++ linux-2.6.27/drivers/hid/usbhid/hid-quirks.c @@ -83,6 +83,7 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b +#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241 #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 #define USB_VENDOR_ID_ASUS 0x0b05 @@ -147,6 +148,7 @@ #define USB_VENDOR_ID_GAMERON 0x0810 #define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001 +#define USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR 0x0002 #define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc @@ -247,8 +249,6 @@ #define USB_DEVICE_ID_LD_MACHINETEST 0x2040 #define USB_VENDOR_ID_LOGITECH 0x046d -#define USB_DEVICE_ID_LOGITECH_LX3 0xc044 -#define USB_DEVICE_ID_LOGITECH_V150 0xc047 #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 #define USB_DEVICE_ID_LOGITECH_HARMONY 0xc110 #define USB_DEVICE_ID_LOGITECH_HARMONY_2 0xc111 @@ -445,6 +445,7 @@ { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, @@ -460,6 +461,7 @@ { USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL }, { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT }, { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT }, @@ -603,8 +605,6 @@ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP }, - { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_LX3, HID_QUIRK_INVERT_HWHEEL }, - { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_V150, HID_QUIRK_INVERT_HWHEEL }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K, HID_QUIRK_MICROSOFT_KEYS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K, HID_QUIRK_MICROSOFT_KEYS }, @@ -1132,24 +1132,16 @@ } /* - * Microsoft Wireless Desktop Receiver (Model 1028) has several + * Microsoft Wireless Desktop Receiver (Model 1028) has * 'Usage Min/Max' where it ought to have 'Physical Min/Max' */ static void usbhid_fixup_microsoft_descriptor(unsigned char *rdesc, int rsize) { - if (rsize == 571 && rdesc[284] == 0x19 - && rdesc[286] == 0x2a - && rdesc[304] == 0x19 - && rdesc[306] == 0x29 - && rdesc[352] == 0x1a - && rdesc[355] == 0x2a - && rdesc[557] == 0x19 + if (rsize == 571 && rdesc[557] == 0x19 && rdesc[559] == 0x29) { printk(KERN_INFO "Fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n"); - rdesc[284] = rdesc[304] = rdesc[557] = 0x35; - rdesc[352] = 0x36; - rdesc[286] = rdesc[355] = 0x46; - rdesc[306] = rdesc[559] = 0x45; + rdesc[557] = 0x35; + rdesc[559] = 0x45; } } --- linux-2.6.27.orig/drivers/rtc/rtc-cmos.c +++ linux-2.6.27/drivers/rtc/rtc-cmos.c @@ -1030,29 +1030,32 @@ static int __init cmos_init(void) { + int retval = 0; + +#ifdef CONFIG_PNP + pnp_register_driver(&cmos_pnp_driver); +#endif + + if (!cmos_rtc.dev) + retval = platform_driver_probe(&cmos_platform_driver, + cmos_platform_probe); + + if (retval == 0) + return 0; + #ifdef CONFIG_PNP - if (pnp_platform_devices) - return pnp_register_driver(&cmos_pnp_driver); - else - return platform_driver_probe(&cmos_platform_driver, - cmos_platform_probe); -#else - return platform_driver_probe(&cmos_platform_driver, - cmos_platform_probe); -#endif /* CONFIG_PNP */ + pnp_unregister_driver(&cmos_pnp_driver); +#endif + return retval; } module_init(cmos_init); static void __exit cmos_exit(void) { #ifdef CONFIG_PNP - if (pnp_platform_devices) - pnp_unregister_driver(&cmos_pnp_driver); - else - platform_driver_unregister(&cmos_platform_driver); -#else + pnp_unregister_driver(&cmos_pnp_driver); +#endif platform_driver_unregister(&cmos_platform_driver); -#endif /* CONFIG_PNP */ } module_exit(cmos_exit); --- linux-2.6.27.orig/drivers/i2c/busses/scx200_i2c.c +++ linux-2.6.27/drivers/i2c/busses/scx200_i2c.c @@ -81,6 +81,7 @@ static struct i2c_adapter scx200_i2c_ops = { .owner = THIS_MODULE, + .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, .id = I2C_HW_B_SCX200, .algo_data = &scx200_i2c_data, .name = "NatSemi SCx200 I2C", --- linux-2.6.27.orig/drivers/block/nbd.c +++ linux-2.6.27/drivers/block/nbd.c @@ -547,6 +547,15 @@ BUG_ON(lo->magic != LO_MAGIC); + if (unlikely(!lo->sock)) { + printk(KERN_ERR "%s: Attempted send on closed socket\n", + lo->disk->disk_name); + req->errors++; + nbd_end_request(req); + spin_lock_irq(q->queue_lock); + continue; + } + spin_lock_irq(&lo->queue_lock); list_add_tail(&req->queuelist, &lo->waiting_queue); spin_unlock_irq(&lo->queue_lock); --- linux-2.6.27.orig/drivers/block/cciss.c +++ linux-2.6.27/drivers/block/cciss.c @@ -96,6 +96,8 @@ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3245}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3247}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3249}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324A}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324B}, {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0}, {0,} @@ -133,6 +135,8 @@ {0x3245103C, "Smart Array P410i", &SA5_access}, {0x3247103C, "Smart Array P411", &SA5_access}, {0x3249103C, "Smart Array P812", &SA5_access}, + {0x324A103C, "Smart Array P712m", &SA5_access}, + {0x324B103C, "Smart Array P711m", &SA5_access}, {0xFFFF103C, "Unknown Smart Array", &SA5_access}, }; @@ -1365,6 +1369,7 @@ disk->first_minor = drv_index << NWD_SHIFT; disk->fops = &cciss_fops; disk->private_data = &h->drv[drv_index]; + disk->driverfs_dev = &h->pdev->dev; /* Set up queue information */ blk_queue_bounce_limit(disk->queue, h->pdev->dma_mask); @@ -1687,6 +1692,11 @@ for (i = 0; i <= h->highest_lun; i++) { int j; drv_found = 0; + + /* skip holes in the array from already deleted drives */ + if (h->drv[i].raid_level == -1) + continue; + for (j = 0; j < num_luns; j++) { memcpy(&lunid, &ld_buff->LUN[j][0], 4); lunid = le32_to_cpu(lunid); @@ -3403,7 +3413,8 @@ int i; int j = 0; int rc; - int dac; + int dac, return_code; + InquiryData_struct *inq_buff = NULL; i = alloc_cciss_hba(); if (i < 0) @@ -3509,6 +3520,25 @@ /* Turn the interrupts on so we can service requests */ hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_ON); + /* Get the firmware version */ + inq_buff = kzalloc(sizeof(InquiryData_struct), GFP_KERNEL); + if (inq_buff == NULL) { + printk(KERN_ERR "cciss: out of memory\n"); + goto clean4; + } + + return_code = sendcmd_withirq(CISS_INQUIRY, i, inq_buff, + sizeof(InquiryData_struct), 0, 0 , 0, TYPE_CMD); + if (return_code == IO_OK) { + hba[i]->firm_ver[0] = inq_buff->data_byte[32]; + hba[i]->firm_ver[1] = inq_buff->data_byte[33]; + hba[i]->firm_ver[2] = inq_buff->data_byte[34]; + hba[i]->firm_ver[3] = inq_buff->data_byte[35]; + } else { /* send command failed */ + printk(KERN_WARNING "cciss: unable to determine firmware" + " version of controller\n"); + } + cciss_procinit(i); hba[i]->cciss_max_sectors = 2048; @@ -3519,6 +3549,7 @@ return 1; clean4: + kfree(inq_buff); #ifdef CONFIG_CISS_SCSI_TAPE kfree(hba[i]->scsi_rejects.complete); #endif --- linux-2.6.27.orig/drivers/block/cpqarray.c +++ linux-2.6.27/drivers/block/cpqarray.c @@ -567,7 +567,12 @@ num_cntlrs_reg++; } - return(num_cntlrs_reg); + if (num_cntlrs_reg) + return 0; + else { + pci_unregister_driver(&cpqarray_pci_driver); + return -ENODEV; + } } /* Function to find the first free pointer into our hba[] array */ --- linux-2.6.27.orig/drivers/block/floppy.c +++ linux-2.6.27/drivers/block/floppy.c @@ -177,6 +177,7 @@ #include #include #include +#include #include /* for invalidate_buffers() */ #include @@ -4572,6 +4573,13 @@ MODULE_SUPPORTED_DEVICE("fd"); MODULE_LICENSE("GPL"); +/* This doesn't actually get used other than for module information */ +static const struct pnp_device_id floppy_pnpids[] = { + { "PNP0700", 0 }, + { } +}; +MODULE_DEVICE_TABLE(pnp, floppy_pnpids); + #else __setup("floppy=", floppy_setup); --- linux-2.6.27.orig/drivers/hwmon/abituguru3.c +++ linux-2.6.27/drivers/hwmon/abituguru3.c @@ -279,7 +279,7 @@ { "OTES1 Fan", 36, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0011, "AT8 32X(ATI RD580-ULI M1575)", { + { 0x0011, "AT8 32X", { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 20, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -402,7 +402,7 @@ { "AUX3 Fan", 36, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0016, NULL /* AW9D-MAX, need DMI string */, { + { 0x0016, "AW9D-MAX", { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR2", 1, 0, 20, 1, 0 }, { "DDR2 VTT", 2, 0, 10, 1, 0 }, @@ -509,7 +509,7 @@ { "AUX3 FAN", 36, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x001A, "IP35 Pro(Intel P35-ICH9R)", { + { 0x001A, "IP35 Pro", { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR2", 1, 0, 20, 1, 0 }, { "DDR2 VTT", 2, 0, 10, 1, 0 }, @@ -1128,6 +1128,7 @@ { const char *board_vendor, *board_name; int i, err = (force) ? 1 : -ENODEV; + size_t sublen; board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); if (!board_vendor || strcmp(board_vendor, "http://www.abit.com.tw/")) @@ -1137,9 +1138,20 @@ if (!board_name) return err; + /* At the moment, we don't care about the part of the vendor + * DMI string contained in brackets. Truncate the string at + * the first occurrence of a bracket. Trim any trailing space + * from the substring. + */ + sublen = strcspn(board_name, "("); + while (sublen > 0 && board_name[sublen - 1] == ' ') + sublen--; + for (i = 0; abituguru3_motherboards[i].id; i++) { const char *dmi_name = abituguru3_motherboards[i].dmi_name; - if (dmi_name && !strcmp(dmi_name, board_name)) + if (!dmi_name || strlen(dmi_name) != sublen) + continue; + if (!strncasecmp(board_name, dmi_name, sublen)) break; } @@ -1153,7 +1165,7 @@ static inline int abituguru3_dmi_detect(void) { - return -ENODEV; + return 1; } #endif /* CONFIG_DMI */ --- linux-2.6.27.orig/drivers/hwmon/hwmon-vid.c +++ linux-2.6.27/drivers/hwmon/hwmon-vid.c @@ -180,6 +180,7 @@ {X86_VENDOR_AMD, 0x6, ANY, ANY, 90}, /* Athlon Duron etc */ {X86_VENDOR_AMD, 0xF, 0x3F, ANY, 24}, /* Athlon 64, Opteron */ {X86_VENDOR_AMD, 0xF, ANY, ANY, 25}, /* NPT family 0Fh */ + {X86_VENDOR_AMD, 0x10, ANY, ANY, 25}, /* NPT family 10h */ {X86_VENDOR_INTEL, 0x6, 0x9, ANY, 13}, /* Pentium M (130 nm) */ {X86_VENDOR_INTEL, 0x6, 0xB, ANY, 85}, /* Tualatin */ {X86_VENDOR_INTEL, 0x6, 0xD, ANY, 13}, /* Pentium M (90 nm) */ --- linux-2.6.27.orig/drivers/hwmon/hdaps.c +++ linux-2.6.27/drivers/hwmon/hdaps.c @@ -533,6 +533,9 @@ HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad Z60m"), HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m"), HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p"), + HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T61P"), + HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R61"), + HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T61"), { .ident = NULL } }; --- linux-2.6.27.orig/drivers/hwmon/ibmaem.c +++ linux-2.6.27/drivers/hwmon/ibmaem.c @@ -88,9 +88,11 @@ static DEFINE_IDR(aem_idr); static DEFINE_SPINLOCK(aem_idr_lock); -static struct device_driver aem_driver = { - .name = DRVNAME, - .bus = &platform_bus_type, +static struct platform_driver aem_driver = { + .driver = { + .name = DRVNAME, + .bus = &platform_bus_type, + } }; struct aem_ipmi_data { @@ -583,7 +585,7 @@ data->pdev = platform_device_alloc(DRVNAME, data->id); if (!data->pdev) goto dev_err; - data->pdev->dev.driver = &aem_driver; + data->pdev->dev.driver = &aem_driver.driver; res = platform_device_add(data->pdev); if (res) @@ -716,7 +718,7 @@ data->pdev = platform_device_alloc(DRVNAME, data->id); if (!data->pdev) goto dev_err; - data->pdev->dev.driver = &aem_driver; + data->pdev->dev.driver = &aem_driver.driver; res = platform_device_add(data->pdev); if (res) @@ -1085,7 +1087,7 @@ { int res; - res = driver_register(&aem_driver); + res = driver_register(&aem_driver.driver); if (res) { printk(KERN_ERR "Can't register aem driver\n"); return res; @@ -1097,7 +1099,7 @@ return 0; ipmi_reg_err: - driver_unregister(&aem_driver); + driver_unregister(&aem_driver.driver); return res; } @@ -1107,7 +1109,7 @@ struct aem_data *p1, *next1; ipmi_smi_watcher_unregister(&driver_data.bmc_events); - driver_unregister(&aem_driver); + driver_unregister(&aem_driver.driver); list_for_each_entry_safe(p1, next1, &driver_data.aem_devices, list) aem_delete(p1); } --- linux-2.6.27.orig/drivers/hwmon/applesmc.c +++ linux-2.6.27/drivers/hwmon/applesmc.c @@ -49,6 +49,9 @@ #define APPLESMC_MAX_DATA_LENGTH 32 +#define APPLESMC_MIN_WAIT 0x0040 +#define APPLESMC_MAX_WAIT 0x8000 + #define APPLESMC_STATUS_MASK 0x0f #define APPLESMC_READ_CMD 0x10 #define APPLESMC_WRITE_CMD 0x11 @@ -57,8 +60,8 @@ #define KEY_COUNT_KEY "#KEY" /* r-o ui32 */ -#define LIGHT_SENSOR_LEFT_KEY "ALV0" /* r-o {alv (6 bytes) */ -#define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6 bytes) */ +#define LIGHT_SENSOR_LEFT_KEY "ALV0" /* r-o {alv (6-10 bytes) */ +#define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6-10 bytes) */ #define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */ #define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */ @@ -104,6 +107,15 @@ /* Set 6: Macbook3 set */ { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TTF0", "TW0P", "Th0H", "Th0S", "Th1H", NULL }, +/* Set 7: Macbook Air */ + { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TC0P", "TCFP", + "TTF0", "TW0P", "Th0H", "Tp0P", "TpFP", "Ts0P", "Ts0S", NULL }, +/* Set 8: Macbook Pro 4,1 (Penryn) */ + { "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P", "Th0H", + "Th1H", "Th2H", "Tm0P", "Ts0P", NULL }, +/* Set 9: Macbook Pro 3,1 (Santa Rosa) */ + { "TALP", "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P", + "Th0H", "Th1H", "Th2H", "Tm0P", "Ts0P", NULL }, }; /* List of keys used to read/write fan speeds */ @@ -163,25 +175,25 @@ static struct workqueue_struct *applesmc_led_wq; /* - * __wait_status - Wait up to 2ms for the status port to get a certain value + * __wait_status - Wait up to 32ms for the status port to get a certain value * (masked with 0x0f), returning zero if the value is obtained. Callers must * hold applesmc_lock. */ static int __wait_status(u8 val) { - unsigned int i; + int us; val = val & APPLESMC_STATUS_MASK; - for (i = 0; i < 200; i++) { + for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) { + udelay(us); if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) { if (debug) printk(KERN_DEBUG - "Waited %d us for status %x\n", - i*10, val); + "Waited %d us for status %x\n", + 2 * us - APPLESMC_MIN_WAIT, val); return 0; } - udelay(10); } printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n", @@ -191,6 +203,25 @@ } /* + * special treatment of command port - on newer macbooks, it seems necessary + * to resend the command byte before polling the status again. Callers must + * hold applesmc_lock. + */ +static int send_command(u8 cmd) +{ + int us; + for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) { + outb(cmd, APPLESMC_CMD_PORT); + udelay(us); + if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c) + return 0; + } + printk(KERN_WARNING "applesmc: command failed: %x -> %x\n", + cmd, inb(APPLESMC_CMD_PORT)); + return -EIO; +} + +/* * applesmc_read_key - reads len bytes from a given key, and put them in buffer. * Returns zero on success or a negative error on failure. Callers must * hold applesmc_lock. @@ -205,8 +236,7 @@ return -EINVAL; } - outb(APPLESMC_READ_CMD, APPLESMC_CMD_PORT); - if (__wait_status(0x0c)) + if (send_command(APPLESMC_READ_CMD)) return -EIO; for (i = 0; i < 4; i++) { @@ -249,8 +279,7 @@ return -EINVAL; } - outb(APPLESMC_WRITE_CMD, APPLESMC_CMD_PORT); - if (__wait_status(0x0c)) + if (send_command(APPLESMC_WRITE_CMD)) return -EIO; for (i = 0; i < 4; i++) { @@ -284,8 +313,7 @@ readkey[2] = index >> 8; readkey[3] = index; - outb(APPLESMC_GET_KEY_BY_INDEX_CMD, APPLESMC_CMD_PORT); - if (__wait_status(0x0c)) + if (send_command(APPLESMC_GET_KEY_BY_INDEX_CMD)) return -EIO; for (i = 0; i < 4; i++) { @@ -315,8 +343,7 @@ { int i; - outb(APPLESMC_GET_KEY_TYPE_CMD, APPLESMC_CMD_PORT); - if (__wait_status(0x0c)) + if (send_command(APPLESMC_GET_KEY_TYPE_CMD)) return -EIO; for (i = 0; i < 4; i++) { @@ -325,7 +352,7 @@ return -EIO; } - outb(5, APPLESMC_DATA_PORT); + outb(6, APPLESMC_DATA_PORT); for (i = 0; i < 6; i++) { if (__wait_status(0x05)) @@ -527,17 +554,27 @@ static ssize_t applesmc_light_show(struct device *dev, struct device_attribute *attr, char *sysfsbuf) { + static int data_length; int ret; u8 left = 0, right = 0; - u8 buffer[6]; + u8 buffer[10], query[6]; mutex_lock(&applesmc_lock); - ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, 6); + if (!data_length) { + ret = applesmc_get_key_type(LIGHT_SENSOR_LEFT_KEY, query); + if (ret) + goto out; + data_length = clamp_val(query[0], 0, 10); + printk(KERN_INFO "applesmc: light sensor data length set to " + "%d\n", data_length); + } + + ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length); left = buffer[2]; if (ret) goto out; - ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, 6); + ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length); right = buffer[2]; out: @@ -1233,11 +1270,29 @@ { .accelerometer = 0, .light = 0, .temperature_set = 5 }, /* MacBook3: accelerometer and temperature set 6 */ { .accelerometer = 1, .light = 0, .temperature_set = 6 }, +/* MacBook Air: accelerometer, backlight and temperature set 7 */ + { .accelerometer = 1, .light = 1, .temperature_set = 7 }, +/* MacBook Pro 4: accelerometer, backlight and temperature set 8 */ + { .accelerometer = 1, .light = 1, .temperature_set = 8 }, +/* MacBook Pro 3: accelerometer, backlight and temperature set 9 */ + { .accelerometer = 1, .light = 1, .temperature_set = 9 }, }; /* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1". * So we need to put "Apple MacBook Pro" before "Apple MacBook". */ static __initdata struct dmi_system_id applesmc_whitelist[] = { + { applesmc_dmi_match, "Apple MacBook Air", { + DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") }, + (void*)&applesmc_dmi_data[7]}, + { applesmc_dmi_match, "Apple MacBook Pro 3", { + DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3") }, + &applesmc_dmi_data[9]}, + { applesmc_dmi_match, "Apple MacBook Pro 4", { + DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4") }, + &applesmc_dmi_data[8]}, { applesmc_dmi_match, "Apple MacBook Pro", { DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") }, --- linux-2.6.27.orig/drivers/parport/parport_serial.c +++ linux-2.6.27/drivers/parport/parport_serial.c @@ -64,12 +64,19 @@ static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc_pci *card, int autoirq, int autodma) { + /* the rule described below doesn't hold for this device */ + if (dev->device == PCI_DEVICE_ID_NETMOS_9835 && + dev->subsystem_vendor == PCI_VENDOR_ID_IBM && + dev->subsystem_device == 0x0299) + return -ENODEV; /* * Netmos uses the subdevice ID to indicate the number of parallel * and serial ports. The form is 0x00PS, where

is the number of * parallel ports and is the number of serial ports. */ card->numports = (dev->subsystem_device & 0xf0) >> 4; + if (card->numports > ARRAY_SIZE(card->addr)) + card->numports = ARRAY_SIZE(card->addr); return 0; } --- linux-2.6.27.orig/drivers/pci/pci.c +++ linux-2.6.27/drivers/pci/pci.c @@ -636,19 +636,14 @@ int pos, i = 0; struct pci_cap_saved_state *save_state; u16 *cap; - int found = 0; pos = pci_find_capability(dev, PCI_CAP_ID_EXP); if (pos <= 0) return 0; save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); - if (!save_state) - save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL); - else - found = 1; if (!save_state) { - dev_err(&dev->dev, "out of memory in pci_save_pcie_state\n"); + dev_err(&dev->dev, "buffer not found in %s\n", __FUNCTION__); return -ENOMEM; } cap = (u16 *)&save_state->data[0]; @@ -657,9 +652,7 @@ pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]); pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]); pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]); - save_state->cap_nr = PCI_CAP_ID_EXP; - if (!found) - pci_add_saved_cap(dev, save_state); + return 0; } @@ -684,30 +677,21 @@ static int pci_save_pcix_state(struct pci_dev *dev) { - int pos, i = 0; + int pos; struct pci_cap_saved_state *save_state; - u16 *cap; - int found = 0; pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); if (pos <= 0) return 0; save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX); - if (!save_state) - save_state = kzalloc(sizeof(*save_state) + sizeof(u16), GFP_KERNEL); - else - found = 1; if (!save_state) { - dev_err(&dev->dev, "out of memory in pci_save_pcie_state\n"); + dev_err(&dev->dev, "buffer not found in %s\n", __FUNCTION__); return -ENOMEM; } - cap = (u16 *)&save_state->data[0]; - pci_read_config_word(dev, pos + PCI_X_CMD, &cap[i++]); - save_state->cap_nr = PCI_CAP_ID_PCIX; - if (!found) - pci_add_saved_cap(dev, save_state); + pci_read_config_word(dev, pos + PCI_X_CMD, (u16 *)save_state->data); + return 0; } @@ -726,6 +710,50 @@ pci_write_config_word(dev, pos + PCI_X_CMD, cap[i++]); } + /** + * pci_add_save_buffer - allocate buffer for saving given capability registers + * @dev: the PCI device + * @cap: the capability to allocate the buffer for + * @size: requested size of the buffer + */ +static int pci_add_cap_save_buffer( + struct pci_dev *dev, char cap, unsigned int size) +{ + int pos; + struct pci_cap_saved_state *save_state; + + pos = pci_find_capability(dev, cap); + if (pos <= 0) + return 0; + + save_state = kzalloc(sizeof(*save_state) + size, GFP_KERNEL); + if (!save_state) + return -ENOMEM; + + save_state->cap_nr = cap; + pci_add_saved_cap(dev, save_state); + + return 0; +} + +/** + * pci_allocate_cap_save_buffers - allocate buffers for saving capabilities + * @dev: the PCI device + */ +void pci_allocate_cap_save_buffers(struct pci_dev *dev) +{ + int error; + + error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_EXP, 4 * sizeof(u16)); + if (error) + dev_err(&dev->dev, + "unable to preallocate PCI Express save buffer\n"); + + error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_PCIX, sizeof(u16)); + if (error) + dev_err(&dev->dev, + "unable to preallocate PCI-X save buffer\n"); +} /** * pci_save_state - save the PCI configuration space of a device before suspending --- linux-2.6.27.orig/drivers/pci/pci-driver.c +++ linux-2.6.27/drivers/pci/pci-driver.c @@ -287,6 +287,14 @@ #ifdef CONFIG_PM_SLEEP +static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev) +{ + struct pci_driver *drv = pci_dev->driver; + + return drv && (drv->suspend || drv->suspend_late || drv->resume + || drv->resume_early); +} + /* * Default "suspend" method for devices that have no driver provided suspend, * or not even a driver at all. @@ -304,14 +312,22 @@ /* * Default "resume" method for devices that have no driver provided resume, - * or not even a driver at all. + * or not even a driver at all (first part). */ -static int pci_default_pm_resume(struct pci_dev *pci_dev) +static void pci_default_pm_resume_early(struct pci_dev *pci_dev) { - int retval = 0; - /* restore the PCI config space */ pci_restore_state(pci_dev); +} + +/* + * Default "resume" method for devices that have no driver provided resume, + * or not even a driver at all (second part). + */ +static int pci_default_pm_resume_late(struct pci_dev *pci_dev) +{ + int retval; + /* if the device was enabled before suspend, reenable */ retval = pci_reenable_device(pci_dev); /* @@ -358,10 +374,12 @@ struct pci_dev * pci_dev = to_pci_dev(dev); struct pci_driver * drv = pci_dev->driver; - if (drv && drv->resume) + if (drv && drv->resume) { error = drv->resume(pci_dev); - else - error = pci_default_pm_resume(pci_dev); + } else { + pci_default_pm_resume_early(pci_dev); + error = pci_default_pm_resume_late(pci_dev); + } return error; } @@ -407,10 +425,8 @@ if (drv->pm->suspend) { error = drv->pm->suspend(dev); suspend_report_result(drv->pm->suspend, error); - } else { - pci_default_pm_suspend(pci_dev); } - } else { + } else if (pci_has_legacy_pm_support(pci_dev)) { error = pci_legacy_suspend(dev, PMSG_SUSPEND); } pci_fixup_device(pci_fixup_suspend, pci_dev); @@ -429,8 +445,10 @@ error = drv->pm->suspend_noirq(dev); suspend_report_result(drv->pm->suspend_noirq, error); } - } else { + } else if (pci_has_legacy_pm_support(pci_dev)) { error = pci_legacy_suspend_late(dev, PMSG_SUSPEND); + } else { + pci_default_pm_suspend(pci_dev); } return error; @@ -440,15 +458,17 @@ { struct pci_dev *pci_dev = to_pci_dev(dev); struct device_driver *drv = dev->driver; - int error; + int error = 0; pci_fixup_device(pci_fixup_resume, pci_dev); if (drv && drv->pm) { - error = drv->pm->resume ? drv->pm->resume(dev) : - pci_default_pm_resume(pci_dev); - } else { + if (drv->pm->resume) + error = drv->pm->resume(dev); + } else if (pci_has_legacy_pm_support(pci_dev)) { error = pci_legacy_resume(dev); + } else { + error = pci_default_pm_resume_late(pci_dev); } return error; @@ -465,8 +485,10 @@ if (drv && drv->pm) { if (drv->pm->resume_noirq) error = drv->pm->resume_noirq(dev); - } else { + } else if (pci_has_legacy_pm_support(pci_dev)) { error = pci_legacy_resume_early(dev); + } else { + pci_default_pm_resume_early(pci_dev); } return error; @@ -493,10 +515,8 @@ if (drv->pm->freeze) { error = drv->pm->freeze(dev); suspend_report_result(drv->pm->freeze, error); - } else { - pci_default_pm_suspend(pci_dev); } - } else { + } else if (pci_has_legacy_pm_support(pci_dev)) { error = pci_legacy_suspend(dev, PMSG_FREEZE); pci_fixup_device(pci_fixup_suspend, pci_dev); } @@ -515,8 +535,10 @@ error = drv->pm->freeze_noirq(dev); suspend_report_result(drv->pm->freeze_noirq, error); } - } else { + } else if (pci_has_legacy_pm_support(pci_dev)) { error = pci_legacy_suspend_late(dev, PMSG_FREEZE); + } else { + pci_default_pm_suspend(pci_dev); } return error; @@ -524,14 +546,15 @@ static int pci_pm_thaw(struct device *dev) { + struct pci_dev *pci_dev = to_pci_dev(dev); struct device_driver *drv = dev->driver; int error = 0; if (drv && drv->pm) { if (drv->pm->thaw) error = drv->pm->thaw(dev); - } else { - pci_fixup_device(pci_fixup_resume, to_pci_dev(dev)); + } else if (pci_has_legacy_pm_support(pci_dev)) { + pci_fixup_device(pci_fixup_resume, pci_dev); error = pci_legacy_resume(dev); } @@ -547,7 +570,7 @@ if (drv && drv->pm) { if (drv->pm->thaw_noirq) error = drv->pm->thaw_noirq(dev); - } else { + } else if (pci_has_legacy_pm_support(pci_dev)) { pci_fixup_device(pci_fixup_resume_early, pci_dev); error = pci_legacy_resume_early(dev); } @@ -557,17 +580,18 @@ static int pci_pm_poweroff(struct device *dev) { + struct pci_dev *pci_dev = to_pci_dev(dev); struct device_driver *drv = dev->driver; int error = 0; - pci_fixup_device(pci_fixup_suspend, to_pci_dev(dev)); + pci_fixup_device(pci_fixup_suspend, pci_dev); if (drv && drv->pm) { if (drv->pm->poweroff) { error = drv->pm->poweroff(dev); suspend_report_result(drv->pm->poweroff, error); } - } else { + } else if (pci_has_legacy_pm_support(pci_dev)) { error = pci_legacy_suspend(dev, PMSG_HIBERNATE); } @@ -585,7 +609,7 @@ error = drv->pm->poweroff_noirq(dev); suspend_report_result(drv->pm->poweroff_noirq, error); } - } else { + } else if (pci_has_legacy_pm_support(to_pci_dev(dev))) { error = pci_legacy_suspend_late(dev, PMSG_HIBERNATE); } @@ -596,13 +620,15 @@ { struct pci_dev *pci_dev = to_pci_dev(dev); struct device_driver *drv = dev->driver; - int error; + int error = 0; if (drv && drv->pm) { - error = drv->pm->restore ? drv->pm->restore(dev) : - pci_default_pm_resume(pci_dev); - } else { + if (drv->pm->restore) + error = drv->pm->restore(dev); + } else if (pci_has_legacy_pm_support(pci_dev)) { error = pci_legacy_resume(dev); + } else { + error = pci_default_pm_resume_late(pci_dev); } pci_fixup_device(pci_fixup_resume, pci_dev); @@ -620,8 +646,10 @@ if (drv && drv->pm) { if (drv->pm->restore_noirq) error = drv->pm->restore_noirq(dev); - } else { + } else if (pci_has_legacy_pm_support(pci_dev)) { error = pci_legacy_resume_early(dev); + } else { + pci_default_pm_resume_early(pci_dev); } pci_fixup_device(pci_fixup_resume_early, pci_dev); --- linux-2.6.27.orig/drivers/pci/syscall.c +++ linux-2.6.27/drivers/pci/syscall.c @@ -14,10 +14,8 @@ #include #include "pci.h" -asmlinkage long -sys_pciconfig_read(unsigned long bus, unsigned long dfn, - unsigned long off, unsigned long len, - void __user *buf) +SYSCALL_DEFINE5(pciconfig_read, unsigned long, bus, unsigned long, dfn, + unsigned long, off, unsigned long, len, void __user *, buf) { struct pci_dev *dev; u8 byte; @@ -86,10 +84,8 @@ return err; } -asmlinkage long -sys_pciconfig_write(unsigned long bus, unsigned long dfn, - unsigned long off, unsigned long len, - void __user *buf) +SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn, + unsigned long, off, unsigned long, len, void __user *, buf) { struct pci_dev *dev; u8 byte; --- linux-2.6.27.orig/drivers/pci/probe.c +++ linux-2.6.27/drivers/pci/probe.c @@ -219,7 +219,7 @@ res->flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK; - if (res->flags == PCI_BASE_ADDRESS_MEM_TYPE_64) + if (res->flags & PCI_BASE_ADDRESS_MEM_TYPE_64) return pci_bar_mem64; return pci_bar_mem32; } @@ -1028,6 +1028,9 @@ /* Fix up broken headers */ pci_fixup_device(pci_fixup_header, dev); + /* Buffers for saving PCIe and PCI-X capabilities */ + pci_allocate_cap_save_buffers(dev); + /* Initialize power management of the device */ pci_pm_init(dev); --- linux-2.6.27.orig/drivers/pci/pci-sysfs.c +++ linux-2.6.27/drivers/pci/pci-sysfs.c @@ -694,8 +694,8 @@ return -EINVAL; rom = pci_map_rom(pdev, &size); /* size starts out as PCI window size */ - if (!rom) - return 0; + if (!rom || !size) + return -EIO; if (off >= size) count = 0; --- linux-2.6.27.orig/drivers/pci/slot.c +++ linux-2.6.27/drivers/pci/slot.c @@ -73,18 +73,100 @@ .default_attrs = pci_slot_default_attrs, }; +static char *make_slot_name(const char *name) +{ + char *new_name; + int len, max, dup; + + new_name = kstrdup(name, GFP_KERNEL); + if (!new_name) + return NULL; + + /* + * Make sure we hit the realloc case the first time through the + * loop. 'len' will be strlen(name) + 3 at that point which is + * enough space for "name-X" and the trailing NUL. + */ + len = strlen(name) + 2; + max = 1; + dup = 1; + + for (;;) { + struct kobject *dup_slot; + dup_slot = kset_find_obj(pci_slots_kset, new_name); + if (!dup_slot) + break; + kobject_put(dup_slot); + if (dup == max) { + len++; + max *= 10; + kfree(new_name); + new_name = kmalloc(len, GFP_KERNEL); + if (!new_name) + break; + } + sprintf(new_name, "%s-%d", name, dup++); + } + + return new_name; +} + +static int rename_slot(struct pci_slot *slot, const char *name) +{ + int result = 0; + char *slot_name; + + if (strcmp(pci_slot_name(slot), name) == 0) + return result; + + slot_name = make_slot_name(name); + if (!slot_name) + return -ENOMEM; + + result = kobject_rename(&slot->kobj, slot_name); + kfree(slot_name); + + return result; +} + +static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) +{ + struct pci_slot *slot; + /* + * We already hold pci_bus_sem so don't worry + */ + list_for_each_entry(slot, &parent->slots, list) + if (slot->number == slot_nr) { + kobject_get(&slot->kobj); + return slot; + } + + return NULL; +} + /** * pci_create_slot - create or increment refcount for physical PCI slot * @parent: struct pci_bus of parent bridge * @slot_nr: PCI_SLOT(pci_dev->devfn) or -1 for placeholder * @name: user visible string presented in /sys/bus/pci/slots/ + * @hotplug: set if caller is hotplug driver, NULL otherwise * * PCI slots have first class attributes such as address, speed, width, * and a &struct pci_slot is used to manage them. This interface will * either return a new &struct pci_slot to the caller, or if the pci_slot * already exists, its refcount will be incremented. * - * Slots are uniquely identified by a @pci_bus, @slot_nr, @name tuple. + * Slots are uniquely identified by a @pci_bus, @slot_nr tuple. + * + * There are known platforms with broken firmware that assign the same + * name to multiple slots. Workaround these broken platforms by renaming + * the slots on behalf of the caller. If firmware assigns name N to + * multiple slots: + * + * The first slot is assigned N + * The second slot is assigned N-1 + * The third slot is assigned N-2 + * etc. * * Placeholder slots: * In most cases, @pci_bus, @slot_nr will be sufficient to uniquely identify @@ -93,12 +175,8 @@ * the slot. In this scenario, the caller may pass -1 for @slot_nr. * * The following semantics are imposed when the caller passes @slot_nr == - * -1. First, the check for existing %struct pci_slot is skipped, as the - * caller may know about several unpopulated slots on a given %struct - * pci_bus, and each slot would have a @slot_nr of -1. Uniqueness for - * these slots is then determined by the @name parameter. We expect - * kobject_init_and_add() to warn us if the caller attempts to create - * multiple slots with the same name. The other change in semantics is + * -1. First, we no longer check for an existing %struct pci_slot, as there + * may be many slots with @slot_nr of -1. The other change in semantics is * user-visible, which is the 'address' parameter presented in sysfs will * consist solely of a dddd:bb tuple, where dddd is the PCI domain of the * %struct pci_bus and bb is the bus number. In other words, the devfn of @@ -106,47 +184,57 @@ */ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, - const char *name) + const char *name, + struct hotplug_slot *hotplug) { struct pci_slot *slot; - int err; + int err = 0; + char *slot_name = NULL; down_write(&pci_bus_sem); if (slot_nr == -1) goto placeholder; - /* If we've already created this slot, bump refcount and return. */ - list_for_each_entry(slot, &parent->slots, list) { - if (slot->number == slot_nr) { - kobject_get(&slot->kobj); - pr_debug("%s: inc refcount to %d on %04x:%02x:%02x\n", - __func__, - atomic_read(&slot->kobj.kref.refcount), - pci_domain_nr(parent), parent->number, - slot_nr); - goto out; + /* + * Hotplug drivers are allowed to rename an existing slot, + * but only if not already claimed. + */ + slot = get_slot(parent, slot_nr); + if (slot) { + if (hotplug) { + if ((err = slot->hotplug ? -EBUSY : 0) + || (err = rename_slot(slot, name))) { + kobject_put(&slot->kobj); + slot = NULL; + goto err; + } } + goto out; } placeholder: slot = kzalloc(sizeof(*slot), GFP_KERNEL); if (!slot) { - slot = ERR_PTR(-ENOMEM); - goto out; + err = -ENOMEM; + goto err; } slot->bus = parent; slot->number = slot_nr; slot->kobj.kset = pci_slots_kset; - err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL, - "%s", name); - if (err) { - printk(KERN_ERR "Unable to register kobject %s\n", name); + slot_name = make_slot_name(name); + if (!slot_name) { + err = -ENOMEM; goto err; } + err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL, + "%s", slot_name); + if (err) + goto err; + INIT_LIST_HEAD(&slot->list); list_add(&slot->list, &parent->slots); @@ -154,10 +242,11 @@ pr_debug("%s: created pci_slot on %04x:%02x:%02x\n", __func__, pci_domain_nr(parent), parent->number, slot_nr); - out: +out: + kfree(slot_name); up_write(&pci_bus_sem); return slot; - err: +err: kfree(slot); slot = ERR_PTR(err); goto out; @@ -203,7 +292,6 @@ * just call kobject_put on its kobj and let our release methods do the * rest. */ - void pci_destroy_slot(struct pci_slot *slot) { pr_debug("%s: dec refcount to %d on %04x:%02x:%02x\n", __func__, --- linux-2.6.27.orig/drivers/pci/setup-res.c +++ linux-2.6.27/drivers/pci/setup-res.c @@ -162,8 +162,8 @@ } if (ret) { - dev_err(&dev->dev, "BAR %d: can't allocate %s resource " - "[%#llx-%#llx]\n", resno, + dev_warn(&dev->dev, "BAR %d: can't allocate %s resource " + "[%#llx-%#llx]\n", resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", (unsigned long long)res->start, (unsigned long long)res->end); --- linux-2.6.27.orig/drivers/pci/pci.h +++ linux-2.6.27/drivers/pci/pci.h @@ -35,6 +35,7 @@ extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops); extern void pci_pm_init(struct pci_dev *dev); +extern void pci_allocate_cap_save_buffers(struct pci_dev *dev); extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val); extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val); --- linux-2.6.27.orig/drivers/pci/rom.c +++ linux-2.6.27/drivers/pci/rom.c @@ -63,7 +63,7 @@ * The PCI window size could be much larger than the * actual image size. */ -size_t pci_get_rom_size(void __iomem *rom, size_t size) +size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size) { void __iomem *image; int last_image; @@ -72,8 +72,10 @@ do { void __iomem *pds; /* Standard PCI ROMs start out with these bytes 55 AA */ - if (readb(image) != 0x55) + if (readb(image) != 0x55) { + dev_err(&pdev->dev, "Invalid ROM contents\n"); break; + } if (readb(image + 1) != 0xAA) break; /* get the PCI data structure and check its signature */ @@ -158,7 +160,7 @@ * size is much larger than the actual size of the ROM. * True size is important if the ROM is going to be copied. */ - *size = pci_get_rom_size(rom, *size); + *size = pci_get_rom_size(pdev, rom, *size); return rom; } --- linux-2.6.27.orig/drivers/pci/hotplug/shpchp_core.c +++ linux-2.6.27/drivers/pci/hotplug/shpchp_core.c @@ -89,7 +89,7 @@ { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); kfree(slot->hotplug_slot->info); kfree(slot->hotplug_slot); @@ -101,8 +101,9 @@ struct slot *slot; struct hotplug_slot *hotplug_slot; struct hotplug_slot_info *info; + char name[SLOT_NAME_SIZE]; int retval = -ENOMEM; - int i, len, dup = 1; + int i; for (i = 0; i < ctrl->num_slots; i++) { slot = kzalloc(sizeof(*slot), GFP_KERNEL); @@ -119,8 +120,6 @@ goto error_hpslot; hotplug_slot->info = info; - hotplug_slot->name = slot->name; - slot->hp_slot = i; slot->ctrl = ctrl; slot->bus = ctrl->pci_dev->subordinate->number; @@ -133,37 +132,24 @@ /* register this slot with the hotplug pci core */ hotplug_slot->private = slot; hotplug_slot->release = &release_slot; - snprintf(slot->name, SLOT_NAME_SIZE, "%d", slot->number); + snprintf(name, SLOT_NAME_SIZE, "%d", slot->number); hotplug_slot->ops = &shpchp_hotplug_slot_ops; - get_power_status(hotplug_slot, &info->power_status); - get_attention_status(hotplug_slot, &info->attention_status); - get_latch_status(hotplug_slot, &info->latch_status); - get_adapter_status(hotplug_slot, &info->adapter_status); - dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " "slot_device_offset=%x\n", slot->bus, slot->device, slot->hp_slot, slot->number, ctrl->slot_device_offset); -duplicate_name: retval = pci_hp_register(slot->hotplug_slot, - ctrl->pci_dev->subordinate, slot->device); + ctrl->pci_dev->subordinate, slot->device, name); if (retval) { - /* - * If slot N already exists, we'll try to create - * slot N-1, N-2 ... N-M, until we overflow. - */ - if (retval == -EEXIST) { - len = snprintf(slot->name, SLOT_NAME_SIZE, - "%d-%d", slot->number, dup++); - if (len < SLOT_NAME_SIZE) - goto duplicate_name; - else - err("duplicate slot name overflow\n"); - } err("pci_hp_register failed with error %d\n", retval); goto error_info; } + get_power_status(hotplug_slot, &info->power_status); + get_attention_status(hotplug_slot, &info->attention_status); + get_latch_status(hotplug_slot, &info->latch_status); + get_adapter_status(hotplug_slot, &info->adapter_status); + list_add(&slot->slot_list, &ctrl->slot_list); } @@ -201,7 +187,7 @@ { struct slot *slot = get_slot(hotplug_slot); - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); hotplug_slot->info->attention_status = status; slot->hpc_ops->set_attention_status(slot, status); @@ -213,7 +199,7 @@ { struct slot *slot = get_slot(hotplug_slot); - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); return shpchp_sysfs_enable_slot(slot); } @@ -222,7 +208,7 @@ { struct slot *slot = get_slot(hotplug_slot); - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); return shpchp_sysfs_disable_slot(slot); } @@ -232,7 +218,7 @@ struct slot *slot = get_slot(hotplug_slot); int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); retval = slot->hpc_ops->get_power_status(slot, value); if (retval < 0) @@ -246,7 +232,7 @@ struct slot *slot = get_slot(hotplug_slot); int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); retval = slot->hpc_ops->get_attention_status(slot, value); if (retval < 0) @@ -260,7 +246,7 @@ struct slot *slot = get_slot(hotplug_slot); int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); retval = slot->hpc_ops->get_latch_status(slot, value); if (retval < 0) @@ -274,7 +260,7 @@ struct slot *slot = get_slot(hotplug_slot); int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); retval = slot->hpc_ops->get_adapter_status(slot, value); if (retval < 0) @@ -289,7 +275,7 @@ struct slot *slot = get_slot(hotplug_slot); int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); retval = slot->hpc_ops->get_max_bus_speed(slot, value); if (retval < 0) @@ -303,7 +289,7 @@ struct slot *slot = get_slot(hotplug_slot); int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); retval = slot->hpc_ops->get_cur_bus_speed(slot, value); if (retval < 0) --- linux-2.6.27.orig/drivers/pci/hotplug/ibmphp_ebda.c +++ linux-2.6.27/drivers/pci/hotplug/ibmphp_ebda.c @@ -620,11 +620,14 @@ return first_slot + 1; } + +#define SLOT_NAME_SIZE 30 + static char *create_file_name (struct slot * slot_cur) { struct opt_rio *opt_vg_ptr = NULL; struct opt_rio_lo *opt_lo_ptr = NULL; - static char str[30]; + static char str[SLOT_NAME_SIZE]; int which = 0; /* rxe = 1, chassis = 0 */ u8 number = 1; /* either chassis or rxe # */ u8 first_slot = 1; @@ -736,7 +739,6 @@ slot = hotplug_slot->private; kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); slot->ctrl = NULL; slot->bus_on = NULL; @@ -768,6 +770,7 @@ int rc; struct slot *tmp_slot; struct list_head *list; + char name[SLOT_NAME_SIZE]; addr = hpc_list_ptr->phys_addr; for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) { @@ -931,12 +934,6 @@ goto error_no_hp_info; } - hp_slot_ptr->name = kmalloc(30, GFP_KERNEL); - if (!hp_slot_ptr->name) { - rc = -ENOMEM; - goto error_no_hp_name; - } - tmp_slot = kzalloc(sizeof(*tmp_slot), GFP_KERNEL); if (!tmp_slot) { rc = -ENOMEM; @@ -1000,9 +997,9 @@ list_for_each (list, &ibmphp_slot_head) { tmp_slot = list_entry (list, struct slot, ibm_slot_list); - snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot)); + snprintf(name, SLOT_NAME_SIZE, "%s", create_file_name(tmp_slot)); pci_hp_register(tmp_slot->hotplug_slot, - pci_find_bus(0, tmp_slot->bus), tmp_slot->device); + pci_find_bus(0, tmp_slot->bus), tmp_slot->device, name); } print_ebda_hpc (); @@ -1012,8 +1009,6 @@ error: kfree (hp_slot_ptr->private); error_no_slot: - kfree (hp_slot_ptr->name); -error_no_hp_name: kfree (hp_slot_ptr->info); error_no_hp_info: kfree (hp_slot_ptr); --- linux-2.6.27.orig/drivers/pci/hotplug/acpiphp_core.c +++ linux-2.6.27/drivers/pci/hotplug/acpiphp_core.c @@ -44,6 +44,9 @@ #define MY_NAME "acpiphp" +/* name size which is used for entries in pcihpfs */ +#define SLOT_NAME_SIZE 21 /* {_SUN} */ + static int debug; int acpiphp_debug; @@ -84,7 +87,6 @@ .get_adapter_status = get_adapter_status, }; - /** * acpiphp_register_attention - set attention LED callback * @info: must be completely filled with LED callbacks @@ -136,7 +138,7 @@ { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); /* enable the specified slot */ return acpiphp_enable_slot(slot->acpi_slot); @@ -154,7 +156,7 @@ struct slot *slot = hotplug_slot->private; int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); /* disable the specified slot */ retval = acpiphp_disable_slot(slot->acpi_slot); @@ -177,7 +179,7 @@ { int retval = -ENODEV; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot)); if (attention_info && try_module_get(attention_info->owner)) { retval = attention_info->set_attn(hotplug_slot, status); @@ -200,7 +202,7 @@ { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = acpiphp_get_power_status(slot->acpi_slot); @@ -222,7 +224,7 @@ { int retval = -EINVAL; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot)); if (attention_info && try_module_get(attention_info->owner)) { retval = attention_info->get_attn(hotplug_slot, value); @@ -245,7 +247,7 @@ { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = acpiphp_get_latch_status(slot->acpi_slot); @@ -265,7 +267,7 @@ { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = acpiphp_get_adapter_status(slot->acpi_slot); @@ -299,7 +301,7 @@ { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); kfree(slot->hotplug_slot); kfree(slot); @@ -310,6 +312,7 @@ { struct slot *slot; int retval = -ENOMEM; + char name[SLOT_NAME_SIZE]; slot = kzalloc(sizeof(*slot), GFP_KERNEL); if (!slot) @@ -321,8 +324,6 @@ slot->hotplug_slot->info = &slot->info; - slot->hotplug_slot->name = slot->name; - slot->hotplug_slot->private = slot; slot->hotplug_slot->release = &release_slot; slot->hotplug_slot->ops = &acpi_hotplug_slot_ops; @@ -336,11 +337,12 @@ slot->hotplug_slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN; acpiphp_slot->slot = slot; - snprintf(slot->name, sizeof(slot->name), "%u", slot->acpi_slot->sun); + snprintf(name, SLOT_NAME_SIZE, "%u", slot->acpi_slot->sun); retval = pci_hp_register(slot->hotplug_slot, acpiphp_slot->bridge->pci_bus, - acpiphp_slot->device); + acpiphp_slot->device, + name); if (retval == -EBUSY) goto error_hpslot; if (retval) { @@ -348,7 +350,7 @@ goto error_hpslot; } - info("Slot [%s] registered\n", slot->hotplug_slot->name); + info("Slot [%s] registered\n", slot_name(slot)); return 0; error_hpslot: @@ -365,7 +367,7 @@ struct slot *slot = acpiphp_slot->slot; int retval = 0; - info ("Slot [%s] unregistered\n", slot->hotplug_slot->name); + info("Slot [%s] unregistered\n", slot_name(slot)); retval = pci_hp_deregister(slot->hotplug_slot); if (retval) --- linux-2.6.27.orig/drivers/pci/hotplug/acpiphp.h +++ linux-2.6.27/drivers/pci/hotplug/acpiphp.h @@ -50,9 +50,6 @@ #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) -/* name size which is used for entries in pcihpfs */ -#define SLOT_NAME_SIZE 20 /* {_SUN} */ - struct acpiphp_bridge; struct acpiphp_slot; @@ -63,9 +60,13 @@ struct hotplug_slot *hotplug_slot; struct acpiphp_slot *acpi_slot; struct hotplug_slot_info info; - char name[SLOT_NAME_SIZE]; }; +static inline const char *slot_name(struct slot *slot) +{ + return hotplug_slot_name(slot->hotplug_slot); +} + /* * struct acpiphp_bridge - PCI bridge information * --- linux-2.6.27.orig/drivers/pci/hotplug/pciehp_hpc.c +++ linux-2.6.27/drivers/pci/hotplug/pciehp_hpc.c @@ -1044,7 +1044,6 @@ slot->device = ctrl->slot_device_offset + slot->hp_slot; slot->hpc_ops = ctrl->hpc_ops; slot->number = ctrl->first_slot; - snprintf(slot->name, SLOT_NAME_SIZE, "%d", slot->number); mutex_init(&slot->lock); INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); list_add(&slot->slot_list, &ctrl->slot_list); --- linux-2.6.27.orig/drivers/pci/hotplug/pciehp_ctrl.c +++ linux-2.6.27/drivers/pci/hotplug/pciehp_ctrl.c @@ -65,7 +65,7 @@ /* * Button pressed - See if need to TAKE ACTION!!! */ - info("Button pressed on Slot(%s)\n", p_slot->name); + info("Button pressed on Slot(%s)\n", slot_name(p_slot)); event_type = INT_BUTTON_PRESS; queue_interrupt_event(p_slot, event_type); @@ -86,13 +86,13 @@ /* * Switch opened */ - info("Latch open on Slot(%s)\n", p_slot->name); + info("Latch open on Slot(%s)\n", slot_name(p_slot)); event_type = INT_SWITCH_OPEN; } else { /* * Switch closed */ - info("Latch close on Slot(%s)\n", p_slot->name); + info("Latch close on Slot(%s)\n", slot_name(p_slot)); event_type = INT_SWITCH_CLOSE; } @@ -117,13 +117,13 @@ /* * Card Present */ - info("Card present on Slot(%s)\n", p_slot->name); + info("Card present on Slot(%s)\n", slot_name(p_slot)); event_type = INT_PRESENCE_ON; } else { /* * Not Present */ - info("Card not present on Slot(%s)\n", p_slot->name); + info("Card not present on Slot(%s)\n", slot_name(p_slot)); event_type = INT_PRESENCE_OFF; } @@ -143,13 +143,13 @@ /* * power fault Cleared */ - info("Power fault cleared on Slot(%s)\n", p_slot->name); + info("Power fault cleared on Slot(%s)\n", slot_name(p_slot)); event_type = INT_POWER_FAULT_CLEAR; } else { /* * power fault */ - info("Power fault on Slot(%s)\n", p_slot->name); + info("Power fault on Slot(%s)\n", slot_name(p_slot)); event_type = INT_POWER_FAULT; info("power fault bit %x set\n", 0); } @@ -404,11 +404,11 @@ if (getstatus) { p_slot->state = BLINKINGOFF_STATE; info("PCI slot #%s - powering off due to button " - "press.\n", p_slot->name); + "press.\n", slot_name(p_slot)); } else { p_slot->state = BLINKINGON_STATE; info("PCI slot #%s - powering on due to button " - "press.\n", p_slot->name); + "press.\n", slot_name(p_slot)); } /* blink green LED and turn off amber */ if (PWR_LED(ctrl)) @@ -425,7 +425,7 @@ * press the attention again before the 5 sec. limit * expires to cancel hot-add or hot-remove */ - info("Button cancel on Slot(%s)\n", p_slot->name); + info("Button cancel on Slot(%s)\n", slot_name(p_slot)); dbg("%s: button cancel\n", __func__); cancel_delayed_work(&p_slot->work); if (p_slot->state == BLINKINGOFF_STATE) { @@ -438,7 +438,7 @@ if (ATTN_LED(ctrl)) p_slot->hpc_ops->set_attention_status(p_slot, 0); info("PCI slot #%s - action canceled due to button press\n", - p_slot->name); + slot_name(p_slot)); p_slot->state = STATIC_STATE; break; case POWEROFF_STATE: @@ -448,7 +448,7 @@ * this means that the previous attention button action * to hot-add or hot-remove is undergoing */ - info("Button ignore on Slot(%s)\n", p_slot->name); + info("Button ignore on Slot(%s)\n", slot_name(p_slot)); update_slot_info(p_slot); break; default: @@ -529,7 +529,7 @@ rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (rc || !getstatus) { info("%s: no adapter on slot(%s)\n", __func__, - p_slot->name); + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } @@ -537,7 +537,7 @@ rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: latch open on slot(%s)\n", __func__, - p_slot->name); + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } @@ -547,7 +547,7 @@ rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: already enabled on slot(%s)\n", __func__, - p_slot->name); + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -EINVAL; } @@ -582,7 +582,7 @@ ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: no adapter on slot(%s)\n", __func__, - p_slot->name); + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } @@ -592,7 +592,7 @@ ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (ret || getstatus) { info("%s: latch open on slot(%s)\n", __func__, - p_slot->name); + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } @@ -602,7 +602,7 @@ ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: already disabled slot(%s)\n", __func__, - p_slot->name); + slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -EINVAL; } @@ -632,14 +632,14 @@ break; case POWERON_STATE: info("Slot %s is already in powering on state\n", - p_slot->name); + slot_name(p_slot)); break; case BLINKINGOFF_STATE: case POWEROFF_STATE: - info("Already enabled on slot %s\n", p_slot->name); + info("Already enabled on slot %s\n", slot_name(p_slot)); break; default: - err("Not a valid state on slot %s\n", p_slot->name); + err("Not a valid state on slot %s\n", slot_name(p_slot)); break; } mutex_unlock(&p_slot->lock); @@ -664,14 +664,14 @@ break; case POWEROFF_STATE: info("Slot %s is already in powering off state\n", - p_slot->name); + slot_name(p_slot)); break; case BLINKINGON_STATE: case POWERON_STATE: - info("Already disabled on slot %s\n", p_slot->name); + info("Already disabled on slot %s\n", slot_name(p_slot)); break; default: - err("Not a valid state on slot %s\n", p_slot->name); + err("Not a valid state on slot %s\n", slot_name(p_slot)); break; } mutex_unlock(&p_slot->lock); --- linux-2.6.27.orig/drivers/pci/hotplug/pci_hotplug_core.c +++ linux-2.6.27/drivers/pci/hotplug/pci_hotplug_core.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -61,7 +62,7 @@ ////////////////////////////////////////////////////////////////// static LIST_HEAD(pci_hotplug_slot_list); -static DEFINE_SPINLOCK(pci_hotplug_slot_list_lock); +static DEFINE_MUTEX(pci_hp_mutex); /* these strings match up with the values in pci_bus_speed */ static char *pci_bus_speed_strings[] = { @@ -530,16 +531,12 @@ struct hotplug_slot *slot; struct list_head *tmp; - spin_lock(&pci_hotplug_slot_list_lock); list_for_each (tmp, &pci_hotplug_slot_list) { slot = list_entry (tmp, struct hotplug_slot, slot_list); - if (strcmp(slot->name, name) == 0) - goto out; + if (strcmp(hotplug_slot_name(slot), name) == 0) + return slot; } - slot = NULL; -out: - spin_unlock(&pci_hotplug_slot_list_lock); - return slot; + return NULL; } /** @@ -547,13 +544,15 @@ * @bus: bus this slot is on * @slot: pointer to the &struct hotplug_slot to register * @slot_nr: slot number + * @name: name registered with kobject core * * Registers a hotplug slot with the pci hotplug subsystem, which will allow * userspace interaction to the slot. * * Returns 0 if successful, anything else for an error. */ -int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr) +int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr, + const char *name) { int result; struct pci_slot *pci_slot; @@ -568,48 +567,29 @@ return -EINVAL; } - /* Check if we have already registered a slot with the same name. */ - if (get_slot_from_name(slot->name)) - return -EEXIST; + mutex_lock(&pci_hp_mutex); /* * No problems if we call this interface from both ACPI_PCI_SLOT * driver and call it here again. If we've already created the * pci_slot, the interface will simply bump the refcount. */ - pci_slot = pci_create_slot(bus, slot_nr, slot->name); - if (IS_ERR(pci_slot)) - return PTR_ERR(pci_slot); - - if (pci_slot->hotplug) { - dbg("%s: already claimed\n", __func__); - pci_destroy_slot(pci_slot); - return -EBUSY; + pci_slot = pci_create_slot(bus, slot_nr, name, slot); + if (IS_ERR(pci_slot)) { + result = PTR_ERR(pci_slot); + goto out; } slot->pci_slot = pci_slot; pci_slot->hotplug = slot; - /* - * Allow pcihp drivers to override the ACPI_PCI_SLOT name. - */ - if (strcmp(kobject_name(&pci_slot->kobj), slot->name)) { - result = kobject_rename(&pci_slot->kobj, slot->name); - if (result) { - pci_destroy_slot(pci_slot); - return result; - } - } - - spin_lock(&pci_hotplug_slot_list_lock); list_add(&slot->slot_list, &pci_hotplug_slot_list); - spin_unlock(&pci_hotplug_slot_list_lock); result = fs_add_slot(pci_slot); kobject_uevent(&pci_slot->kobj, KOBJ_ADD); - dbg("Added slot %s to the list\n", slot->name); - - + dbg("Added slot %s to the list\n", name); +out: + mutex_unlock(&pci_hp_mutex); return result; } @@ -630,21 +610,23 @@ if (!hotplug) return -ENODEV; - temp = get_slot_from_name(hotplug->name); - if (temp != hotplug) + mutex_lock(&pci_hp_mutex); + temp = get_slot_from_name(hotplug_slot_name(hotplug)); + if (temp != hotplug) { + mutex_unlock(&pci_hp_mutex); return -ENODEV; + } - spin_lock(&pci_hotplug_slot_list_lock); list_del(&hotplug->slot_list); - spin_unlock(&pci_hotplug_slot_list_lock); slot = hotplug->pci_slot; fs_remove_slot(slot); - dbg("Removed slot %s from the list\n", hotplug->name); + dbg("Removed slot %s from the list\n", hotplug_slot_name(hotplug)); hotplug->release(hotplug); slot->hotplug = NULL; pci_destroy_slot(slot); + mutex_unlock(&pci_hp_mutex); return 0; } --- linux-2.6.27.orig/drivers/pci/hotplug/pciehp_core.c +++ linux-2.6.27/drivers/pci/hotplug/pciehp_core.c @@ -126,8 +126,10 @@ mutex_lock(&slot->ctrl->crit_sect); /* has it been >1 sec since our last toggle? */ - if ((get_seconds() - slot->last_emi_toggle) < 1) + if ((get_seconds() - slot->last_emi_toggle) < 1) { + mutex_unlock(&slot->ctrl->crit_sect); return -EINVAL; + } /* see what our current state is */ retval = get_lock_status(hotplug_slot, &value); @@ -180,7 +182,8 @@ */ static void release_slot(struct hotplug_slot *hotplug_slot) { - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, + hotplug_slot_name(hotplug_slot)); kfree(hotplug_slot->info); kfree(hotplug_slot); @@ -191,7 +194,7 @@ struct slot *slot; struct hotplug_slot *hotplug_slot; struct hotplug_slot_info *info; - int len, dup = 1; + char name[SLOT_NAME_SIZE]; int retval = -ENOMEM; list_for_each_entry(slot, &ctrl->slot_list, slot_list) { @@ -205,39 +208,27 @@ /* register this slot with the hotplug pci core */ hotplug_slot->info = info; - hotplug_slot->name = slot->name; hotplug_slot->private = slot; hotplug_slot->release = &release_slot; hotplug_slot->ops = &pciehp_hotplug_slot_ops; - get_power_status(hotplug_slot, &info->power_status); - get_attention_status(hotplug_slot, &info->attention_status); - get_latch_status(hotplug_slot, &info->latch_status); - get_adapter_status(hotplug_slot, &info->adapter_status); slot->hotplug_slot = hotplug_slot; + snprintf(name, SLOT_NAME_SIZE, "%u", slot->number); dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " "slot_device_offset=%x\n", slot->bus, slot->device, slot->hp_slot, slot->number, ctrl->slot_device_offset); -duplicate_name: retval = pci_hp_register(hotplug_slot, ctrl->pci_dev->subordinate, - slot->device); + slot->device, + name); if (retval) { - /* - * If slot N already exists, we'll try to create - * slot N-1, N-2 ... N-M, until we overflow. - */ - if (retval == -EEXIST) { - len = snprintf(slot->name, SLOT_NAME_SIZE, - "%d-%d", slot->number, dup++); - if (len < SLOT_NAME_SIZE) - goto duplicate_name; - else - err("duplicate slot name overflow\n"); - } err("pci_hp_register failed with error %d\n", retval); goto error_info; } + get_power_status(hotplug_slot, &info->power_status); + get_attention_status(hotplug_slot, &info->attention_status); + get_latch_status(hotplug_slot, &info->latch_status); + get_adapter_status(hotplug_slot, &info->adapter_status); /* create additional sysfs entries */ if (EMI(ctrl)) { retval = sysfs_create_file(&hotplug_slot->pci_slot->kobj, @@ -278,7 +269,7 @@ { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); hotplug_slot->info->attention_status = status; @@ -293,7 +284,7 @@ { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); return pciehp_sysfs_enable_slot(slot); } @@ -303,7 +294,7 @@ { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); return pciehp_sysfs_disable_slot(slot); } @@ -313,7 +304,7 @@ struct slot *slot = hotplug_slot->private; int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); retval = slot->hpc_ops->get_power_status(slot, value); if (retval < 0) @@ -327,7 +318,7 @@ struct slot *slot = hotplug_slot->private; int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); retval = slot->hpc_ops->get_attention_status(slot, value); if (retval < 0) @@ -341,7 +332,7 @@ struct slot *slot = hotplug_slot->private; int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); retval = slot->hpc_ops->get_latch_status(slot, value); if (retval < 0) @@ -355,7 +346,7 @@ struct slot *slot = hotplug_slot->private; int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); retval = slot->hpc_ops->get_adapter_status(slot, value); if (retval < 0) @@ -370,7 +361,7 @@ struct slot *slot = hotplug_slot->private; int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); retval = slot->hpc_ops->get_max_bus_speed(slot, value); if (retval < 0) @@ -384,7 +375,7 @@ struct slot *slot = hotplug_slot->private; int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); retval = slot->hpc_ops->get_cur_bus_speed(slot, value); if (retval < 0) --- linux-2.6.27.orig/drivers/pci/hotplug/fakephp.c +++ linux-2.6.27/drivers/pci/hotplug/fakephp.c @@ -66,7 +66,6 @@ struct pci_dev *dev; struct work_struct remove_work; unsigned long removed; - char name[8]; }; static int debug; @@ -96,10 +95,13 @@ kfree(dslot); } +#define SLOT_NAME_SIZE 8 + static int add_slot(struct pci_dev *dev) { struct dummy_slot *dslot; struct hotplug_slot *slot; + char name[SLOT_NAME_SIZE]; int retval = -ENOMEM; static int count = 1; @@ -119,19 +121,18 @@ if (!dslot) goto error_info; - slot->name = dslot->name; - snprintf(slot->name, sizeof(dslot->name), "fake%d", count++); - dbg("slot->name = %s\n", slot->name); + snprintf(name, SLOT_NAME_SIZE, "fake%d", count++); slot->ops = &dummy_hotplug_slot_ops; slot->release = &dummy_release; slot->private = dslot; - retval = pci_hp_register(slot, dev->bus, PCI_SLOT(dev->devfn)); + retval = pci_hp_register(slot, dev->bus, PCI_SLOT(dev->devfn), name); if (retval) { err("pci_hp_register failed with error %d\n", retval); goto error_dslot; } + dbg("slot->name = %s\n", hotplug_slot_name(slot)); dslot->slot = slot; dslot->dev = pci_dev_get(dev); list_add (&dslot->node, &slot_list); @@ -167,10 +168,11 @@ { int retval; - dbg("removing slot %s\n", dslot->slot->name); + dbg("removing slot %s\n", hotplug_slot_name(dslot->slot)); retval = pci_hp_deregister(dslot->slot); if (retval) - err("Problem unregistering a slot %s\n", dslot->slot->name); + err("Problem unregistering a slot %s\n", + hotplug_slot_name(dslot->slot)); } /* called from the single-threaded workqueue handler to remove a slot */ @@ -308,7 +310,7 @@ return -ENODEV; dslot = slot->private; - dbg("%s - physical_slot = %s\n", __func__, slot->name); + dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(slot)); for (func = 7; func >= 0; func--) { dev = pci_get_slot(dslot->dev->bus, dslot->dev->devfn + func); --- linux-2.6.27.orig/drivers/pci/hotplug/shpchp_ctrl.c +++ linux-2.6.27/drivers/pci/hotplug/shpchp_ctrl.c @@ -70,7 +70,7 @@ /* * Button pressed - See if need to TAKE ACTION!!! */ - info("Button pressed on Slot(%s)\n", p_slot->name); + info("Button pressed on Slot(%s)\n", slot_name(p_slot)); event_type = INT_BUTTON_PRESS; queue_interrupt_event(p_slot, event_type); @@ -98,7 +98,7 @@ /* * Switch opened */ - info("Latch open on Slot(%s)\n", p_slot->name); + info("Latch open on Slot(%s)\n", slot_name(p_slot)); event_type = INT_SWITCH_OPEN; if (p_slot->pwr_save && p_slot->presence_save) { event_type = INT_POWER_FAULT; @@ -108,7 +108,7 @@ /* * Switch closed */ - info("Latch close on Slot(%s)\n", p_slot->name); + info("Latch close on Slot(%s)\n", slot_name(p_slot)); event_type = INT_SWITCH_CLOSE; } @@ -135,13 +135,13 @@ /* * Card Present */ - info("Card present on Slot(%s)\n", p_slot->name); + info("Card present on Slot(%s)\n", slot_name(p_slot)); event_type = INT_PRESENCE_ON; } else { /* * Not Present */ - info("Card not present on Slot(%s)\n", p_slot->name); + info("Card not present on Slot(%s)\n", slot_name(p_slot)); event_type = INT_PRESENCE_OFF; } @@ -164,14 +164,14 @@ /* * Power fault Cleared */ - info("Power fault cleared on Slot(%s)\n", p_slot->name); + info("Power fault cleared on Slot(%s)\n", slot_name(p_slot)); p_slot->status = 0x00; event_type = INT_POWER_FAULT_CLEAR; } else { /* * Power fault */ - info("Power fault on Slot(%s)\n", p_slot->name); + info("Power fault on Slot(%s)\n", slot_name(p_slot)); event_type = INT_POWER_FAULT; /* set power fault status for this board */ p_slot->status = 0xFF; @@ -493,11 +493,11 @@ if (getstatus) { p_slot->state = BLINKINGOFF_STATE; info("PCI slot #%s - powering off due to button " - "press.\n", p_slot->name); + "press.\n", slot_name(p_slot)); } else { p_slot->state = BLINKINGON_STATE; info("PCI slot #%s - powering on due to button " - "press.\n", p_slot->name); + "press.\n", slot_name(p_slot)); } /* blink green LED and turn off amber */ p_slot->hpc_ops->green_led_blink(p_slot); @@ -512,7 +512,7 @@ * press the attention again before the 5 sec. limit * expires to cancel hot-add or hot-remove */ - info("Button cancel on Slot(%s)\n", p_slot->name); + info("Button cancel on Slot(%s)\n", slot_name(p_slot)); dbg("%s: button cancel\n", __func__); cancel_delayed_work(&p_slot->work); if (p_slot->state == BLINKINGOFF_STATE) @@ -521,7 +521,7 @@ p_slot->hpc_ops->green_led_off(p_slot); p_slot->hpc_ops->set_attention_status(p_slot, 0); info("PCI slot #%s - action canceled due to button press\n", - p_slot->name); + slot_name(p_slot)); p_slot->state = STATIC_STATE; break; case POWEROFF_STATE: @@ -531,7 +531,7 @@ * this means that the previous attention button action * to hot-add or hot-remove is undergoing */ - info("Button ignore on Slot(%s)\n", p_slot->name); + info("Button ignore on Slot(%s)\n", slot_name(p_slot)); update_slot_info(p_slot); break; default: @@ -574,17 +574,17 @@ mutex_lock(&p_slot->ctrl->crit_sect); rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (rc || !getstatus) { - info("No adapter on slot(%s)\n", p_slot->name); + info("No adapter on slot(%s)\n", slot_name(p_slot)); goto out; } rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { - info("Latch open on slot(%s)\n", p_slot->name); + info("Latch open on slot(%s)\n", slot_name(p_slot)); goto out; } rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { - info("Already enabled on slot(%s)\n", p_slot->name); + info("Already enabled on slot(%s)\n", slot_name(p_slot)); goto out; } @@ -633,17 +633,17 @@ rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (rc || !getstatus) { - info("No adapter on slot(%s)\n", p_slot->name); + info("No adapter on slot(%s)\n", slot_name(p_slot)); goto out; } rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { - info("Latch open on slot(%s)\n", p_slot->name); + info("Latch open on slot(%s)\n", slot_name(p_slot)); goto out; } rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || !getstatus) { - info("Already disabled slot(%s)\n", p_slot->name); + info("Already disabled slot(%s)\n", slot_name(p_slot)); goto out; } @@ -671,14 +671,14 @@ break; case POWERON_STATE: info("Slot %s is already in powering on state\n", - p_slot->name); + slot_name(p_slot)); break; case BLINKINGOFF_STATE: case POWEROFF_STATE: - info("Already enabled on slot %s\n", p_slot->name); + info("Already enabled on slot %s\n", slot_name(p_slot)); break; default: - err("Not a valid state on slot %s\n", p_slot->name); + err("Not a valid state on slot %s\n", slot_name(p_slot)); break; } mutex_unlock(&p_slot->lock); @@ -703,14 +703,14 @@ break; case POWEROFF_STATE: info("Slot %s is already in powering off state\n", - p_slot->name); + slot_name(p_slot)); break; case BLINKINGON_STATE: case POWERON_STATE: - info("Already disabled on slot %s\n", p_slot->name); + info("Already disabled on slot %s\n", slot_name(p_slot)); break; default: - err("Not a valid state on slot %s\n", p_slot->name); + err("Not a valid state on slot %s\n", slot_name(p_slot)); break; } mutex_unlock(&p_slot->lock); --- linux-2.6.27.orig/drivers/pci/hotplug/rpaphp_slot.c +++ linux-2.6.27/drivers/pci/hotplug/rpaphp_slot.c @@ -43,7 +43,7 @@ void dealloc_slot_struct(struct slot *slot) { kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); + kfree(slot->name); kfree(slot->hotplug_slot); kfree(slot); } @@ -63,11 +63,9 @@ GFP_KERNEL); if (!slot->hotplug_slot->info) goto error_hpslot; - slot->hotplug_slot->name = kmalloc(strlen(drc_name) + 1, GFP_KERNEL); - if (!slot->hotplug_slot->name) + slot->name = kstrdup(drc_name, GFP_KERNEL); + if (!slot->name) goto error_info; - slot->name = slot->hotplug_slot->name; - strcpy(slot->name, drc_name); slot->dn = dn; slot->index = drc_index; slot->power_domain = power_domain; @@ -137,7 +135,7 @@ slotno = PCI_SLOT(PCI_DN(slot->dn->child)->devfn); else slotno = -1; - retval = pci_hp_register(php_slot, slot->bus, slotno); + retval = pci_hp_register(php_slot, slot->bus, slotno, slot->name); if (retval) { err("pci_hp_register failed with error %d\n", retval); return retval; --- linux-2.6.27.orig/drivers/pci/hotplug/cpci_hotplug_pci.c +++ linux-2.6.27/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -209,7 +209,7 @@ hs_cap + 2, hs_csr)) { err("Could not set LOO for slot %s", - slot->hotplug_slot->name); + hotplug_slot_name(slot->hotplug_slot)); return -ENODEV; } } @@ -238,7 +238,7 @@ hs_cap + 2, hs_csr)) { err("Could not clear LOO for slot %s", - slot->hotplug_slot->name); + hotplug_slot_name(slot->hotplug_slot)); return -ENODEV; } } --- linux-2.6.27.orig/drivers/pci/hotplug/pciehp.h +++ linux-2.6.27/drivers/pci/hotplug/pciehp.h @@ -61,15 +61,13 @@ struct slot { u8 bus; u8 device; - u32 number; u8 state; - struct timer_list task_event; u8 hp_slot; + u32 number; struct controller *ctrl; struct hpc_ops *hpc_ops; struct hotplug_slot *hotplug_slot; struct list_head slot_list; - char name[SLOT_NAME_SIZE]; unsigned long last_emi_toggle; struct delayed_work work; /* work for button event */ struct mutex lock; @@ -161,6 +159,11 @@ int pciehp_disable_slot(struct slot *p_slot); int pcie_enable_notification(struct controller *ctrl); +static inline const char *slot_name(struct slot *slot) +{ + return hotplug_slot_name(slot->hotplug_slot); +} + static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) { struct slot *slot; --- linux-2.6.27.orig/drivers/pci/hotplug/cpci_hotplug.h +++ linux-2.6.27/drivers/pci/hotplug/cpci_hotplug.h @@ -30,6 +30,7 @@ #include #include +#include /* PICMG 2.1 R2.0 HS CSR bits: */ #define HS_CSR_INS 0x0080 @@ -69,6 +70,11 @@ struct cpci_hp_controller_ops *ops; }; +static inline const char *slot_name(struct slot *slot) +{ + return hotplug_slot_name(slot->hotplug_slot); +} + extern int cpci_hp_register_controller(struct cpci_hp_controller *controller); extern int cpci_hp_unregister_controller(struct cpci_hp_controller *controller); extern int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last); --- linux-2.6.27.orig/drivers/pci/hotplug/cpqphp_core.c +++ linux-2.6.27/drivers/pci/hotplug/cpqphp_core.c @@ -315,14 +315,15 @@ { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); kfree(slot); } +#define SLOT_NAME_SIZE 10 + static int ctrl_slot_setup(struct controller *ctrl, void __iomem *smbios_start, void __iomem *smbios_table) @@ -335,6 +336,7 @@ u8 slot_number; u8 ctrl_slot; u32 tempdword; + char name[SLOT_NAME_SIZE]; void __iomem *slot_entry= NULL; int result = -ENOMEM; @@ -363,16 +365,12 @@ if (!hotplug_slot->info) goto error_hpslot; hotplug_slot_info = hotplug_slot->info; - hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); - - if (!hotplug_slot->name) - goto error_info; slot->ctrl = ctrl; slot->bus = ctrl->bus; slot->device = slot_device; slot->number = slot_number; - dbg("slot->number = %d\n", slot->number); + dbg("slot->number = %u\n", slot->number); slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, slot_entry); @@ -418,9 +416,9 @@ /* register this slot with the hotplug pci core */ hotplug_slot->release = &release_slot; hotplug_slot->private = slot; - make_slot_name(hotplug_slot->name, SLOT_NAME_SIZE, slot); + snprintf(name, SLOT_NAME_SIZE, "%u", slot->number); hotplug_slot->ops = &cpqphp_hotplug_slot_ops; - + hotplug_slot_info->power_status = get_slot_enabled(ctrl, slot); hotplug_slot_info->attention_status = cpq_get_attention_status(ctrl, slot); @@ -435,11 +433,12 @@ slot->number, ctrl->slot_device_offset, slot_number); result = pci_hp_register(hotplug_slot, - ctrl->pci_dev->subordinate, - slot->device); + ctrl->pci_dev->bus, + slot->device, + name); if (result) { err("pci_hp_register failed with error %d\n", result); - goto error_name; + goto error_info; } slot->next = ctrl->slot; @@ -451,8 +450,6 @@ } return 0; -error_name: - kfree(hotplug_slot->name); error_info: kfree(hotplug_slot_info); error_hpslot: @@ -638,7 +635,7 @@ u8 device; u8 function; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) return -ENODEV; @@ -665,7 +662,7 @@ u8 device; u8 function; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) return -ENODEV; @@ -697,7 +694,7 @@ u8 device; u8 function; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) return -ENODEV; @@ -720,7 +717,7 @@ struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); return cpqhp_hardware_test(ctrl, value); } @@ -731,7 +728,7 @@ struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = get_slot_enabled(ctrl, slot); return 0; @@ -742,7 +739,7 @@ struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = cpq_get_attention_status(ctrl, slot); return 0; @@ -753,7 +750,7 @@ struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = cpq_get_latch_status(ctrl, slot); @@ -765,7 +762,7 @@ struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = get_presence_status(ctrl, slot); @@ -777,7 +774,7 @@ struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = ctrl->speed_capability; @@ -789,7 +786,7 @@ struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = ctrl->speed; --- linux-2.6.27.orig/drivers/pci/hotplug/sgi_hotplug.c +++ linux-2.6.27/drivers/pci/hotplug/sgi_hotplug.c @@ -161,7 +161,8 @@ } static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, - struct pci_bus *pci_bus, int device) + struct pci_bus *pci_bus, int device, + char *name) { struct pcibus_info *pcibus_info; struct slot *slot; @@ -173,15 +174,9 @@ return -ENOMEM; bss_hotplug_slot->private = slot; - bss_hotplug_slot->name = kmalloc(SN_SLOT_NAME_SIZE, GFP_KERNEL); - if (!bss_hotplug_slot->name) { - kfree(bss_hotplug_slot->private); - return -ENOMEM; - } - slot->device_num = device; slot->pci_bus = pci_bus; - sprintf(bss_hotplug_slot->name, "%04x:%02x:%02x", + sprintf(name, "%04x:%02x:%02x", pci_domain_nr(pci_bus), ((u16)pcibus_info->pbi_buscommon.bs_persist_busnum), device + 1); @@ -608,7 +603,6 @@ static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot) { kfree(bss_hotplug_slot->info); - kfree(bss_hotplug_slot->name); kfree(bss_hotplug_slot->private); kfree(bss_hotplug_slot); } @@ -618,6 +612,7 @@ int device; struct pci_slot *pci_slot; struct hotplug_slot *bss_hotplug_slot; + char name[SN_SLOT_NAME_SIZE]; int rc = 0; /* @@ -645,15 +640,14 @@ } if (sn_hp_slot_private_alloc(bss_hotplug_slot, - pci_bus, device)) { + pci_bus, device, name)) { rc = -ENOMEM; goto alloc_err; } - bss_hotplug_slot->ops = &sn_hotplug_slot_ops; bss_hotplug_slot->release = &sn_release_slot; - rc = pci_hp_register(bss_hotplug_slot, pci_bus, device); + rc = pci_hp_register(bss_hotplug_slot, pci_bus, device, name); if (rc) goto register_err; --- linux-2.6.27.orig/drivers/pci/hotplug/cpqphp.h +++ linux-2.6.27/drivers/pci/hotplug/cpqphp.h @@ -449,6 +449,11 @@ /* inline functions */ +static inline char *slot_name(struct slot *slot) +{ + return hotplug_slot_name(slot->hotplug_slot); +} + /* * return_resource * @@ -696,14 +701,6 @@ return presence_save; } -#define SLOT_NAME_SIZE 10 - -static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot) -{ - snprintf(buffer, buffer_size, "%d", slot->number); -} - - static inline int wait_for_ctrl_irq(struct controller *ctrl) { DECLARE_WAITQUEUE(wait, current); --- linux-2.6.27.orig/drivers/pci/hotplug/shpchp.h +++ linux-2.6.27/drivers/pci/hotplug/shpchp.h @@ -69,15 +69,13 @@ u8 state; u8 presence_save; u8 pwr_save; - struct timer_list task_event; - u8 hp_slot; struct controller *ctrl; struct hpc_ops *hpc_ops; struct hotplug_slot *hotplug_slot; struct list_head slot_list; - char name[SLOT_NAME_SIZE]; struct delayed_work work; /* work for button event */ struct mutex lock; + u8 hp_slot; }; struct event_info { @@ -169,6 +167,11 @@ extern void shpchp_queue_pushbutton_work(struct work_struct *work); extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev); +static inline const char *slot_name(struct slot *slot) +{ + return hotplug_slot_name(slot->hotplug_slot); +} + #ifdef CONFIG_ACPI #include static inline int get_hp_params_from_firmware(struct pci_dev *dev, --- linux-2.6.27.orig/drivers/pci/hotplug/cpci_hotplug_core.c +++ linux-2.6.27/drivers/pci/hotplug/cpci_hotplug_core.c @@ -108,7 +108,7 @@ struct slot *slot = hotplug_slot->private; int retval = 0; - dbg("%s - physical_slot = %s", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s", __func__, slot_name(slot)); if (controller->ops->set_power) retval = controller->ops->set_power(slot, 1); @@ -121,25 +121,23 @@ struct slot *slot = hotplug_slot->private; int retval = 0; - dbg("%s - physical_slot = %s", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s", __func__, slot_name(slot)); down_write(&list_rwsem); /* Unconfigure device */ - dbg("%s - unconfiguring slot %s", - __func__, slot->hotplug_slot->name); + dbg("%s - unconfiguring slot %s", __func__, slot_name(slot)); if ((retval = cpci_unconfigure_slot(slot))) { err("%s - could not unconfigure slot %s", - __func__, slot->hotplug_slot->name); + __func__, slot_name(slot)); goto disable_error; } - dbg("%s - finished unconfiguring slot %s", - __func__, slot->hotplug_slot->name); + dbg("%s - finished unconfiguring slot %s", __func__, slot_name(slot)); /* Clear EXT (by setting it) */ if (cpci_clear_ext(slot)) { err("%s - could not clear EXT for slot %s", - __func__, slot->hotplug_slot->name); + __func__, slot_name(slot)); retval = -ENODEV; goto disable_error; } @@ -214,7 +212,6 @@ struct slot *slot = hotplug_slot->private; kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); if (slot->dev) pci_dev_put(slot->dev); @@ -222,12 +219,6 @@ } #define SLOT_NAME_SIZE 6 -static void -make_slot_name(struct slot *slot) -{ - snprintf(slot->hotplug_slot->name, - SLOT_NAME_SIZE, "%02x:%02x", slot->bus->number, slot->number); -} int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) @@ -235,7 +226,7 @@ struct slot *slot; struct hotplug_slot *hotplug_slot; struct hotplug_slot_info *info; - char *name; + char name[SLOT_NAME_SIZE]; int status = -ENOMEM; int i; @@ -262,34 +253,31 @@ goto error_hpslot; hotplug_slot->info = info; - name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); - if (!name) - goto error_info; - hotplug_slot->name = name; - slot->bus = bus; slot->number = i; slot->devfn = PCI_DEVFN(i, 0); + snprintf(name, SLOT_NAME_SIZE, "%02x:%02x", bus->number, i); + hotplug_slot->private = slot; hotplug_slot->release = &release_slot; - make_slot_name(slot); hotplug_slot->ops = &cpci_hotplug_slot_ops; /* * Initialize the slot info structure with some known * good values. */ - dbg("initializing slot %s", slot->hotplug_slot->name); + dbg("initializing slot %s", name); info->power_status = cpci_get_power_status(slot); info->attention_status = cpci_get_attention_status(slot); - dbg("registering slot %s", slot->hotplug_slot->name); - status = pci_hp_register(slot->hotplug_slot, bus, i); + dbg("registering slot %s", name); + status = pci_hp_register(slot->hotplug_slot, bus, i, name); if (status) { err("pci_hp_register failed with error %d", status); - goto error_name; + goto error_info; } + dbg("slot registered with name: %s", slot_name(slot)); /* Add slot to our internal list */ down_write(&list_rwsem); @@ -298,8 +286,6 @@ up_write(&list_rwsem); } return 0; -error_name: - kfree(name); error_info: kfree(info); error_hpslot: @@ -327,7 +313,7 @@ list_del(&slot->slot_list); slots--; - dbg("deregistering slot %s", slot->hotplug_slot->name); + dbg("deregistering slot %s", slot_name(slot)); status = pci_hp_deregister(slot->hotplug_slot); if (status) { err("pci_hp_deregister failed with error %d", @@ -379,11 +365,10 @@ return -1; } list_for_each_entry(slot, &slot_list, slot_list) { - dbg("%s - looking at slot %s", - __func__, slot->hotplug_slot->name); + dbg("%s - looking at slot %s", __func__, slot_name(slot)); if (clear_ins && cpci_check_and_clear_ins(slot)) dbg("%s - cleared INS for slot %s", - __func__, slot->hotplug_slot->name); + __func__, slot_name(slot)); dev = pci_get_slot(slot->bus, PCI_DEVFN(slot->number, 0)); if (dev) { if (update_adapter_status(slot->hotplug_slot, 1)) @@ -414,8 +399,7 @@ } extracted = inserted = 0; list_for_each_entry(slot, &slot_list, slot_list) { - dbg("%s - looking at slot %s", - __func__, slot->hotplug_slot->name); + dbg("%s - looking at slot %s", __func__, slot_name(slot)); if (cpci_check_and_clear_ins(slot)) { /* * Some broken hardware (e.g. PLX 9054AB) asserts @@ -423,35 +407,34 @@ */ if (slot->dev) { warn("slot %s already inserted", - slot->hotplug_slot->name); + slot_name(slot)); inserted++; continue; } /* Process insertion */ - dbg("%s - slot %s inserted", - __func__, slot->hotplug_slot->name); + dbg("%s - slot %s inserted", __func__, slot_name(slot)); /* GSM, debug */ hs_csr = cpci_get_hs_csr(slot); dbg("%s - slot %s HS_CSR (1) = %04x", - __func__, slot->hotplug_slot->name, hs_csr); + __func__, slot_name(slot), hs_csr); /* Configure device */ dbg("%s - configuring slot %s", - __func__, slot->hotplug_slot->name); + __func__, slot_name(slot)); if (cpci_configure_slot(slot)) { err("%s - could not configure slot %s", - __func__, slot->hotplug_slot->name); + __func__, slot_name(slot)); continue; } dbg("%s - finished configuring slot %s", - __func__, slot->hotplug_slot->name); + __func__, slot_name(slot)); /* GSM, debug */ hs_csr = cpci_get_hs_csr(slot); dbg("%s - slot %s HS_CSR (2) = %04x", - __func__, slot->hotplug_slot->name, hs_csr); + __func__, slot_name(slot), hs_csr); if (update_latch_status(slot->hotplug_slot, 1)) warn("failure to update latch file"); @@ -464,18 +447,18 @@ /* GSM, debug */ hs_csr = cpci_get_hs_csr(slot); dbg("%s - slot %s HS_CSR (3) = %04x", - __func__, slot->hotplug_slot->name, hs_csr); + __func__, slot_name(slot), hs_csr); inserted++; } else if (cpci_check_ext(slot)) { /* Process extraction request */ dbg("%s - slot %s extracted", - __func__, slot->hotplug_slot->name); + __func__, slot_name(slot)); /* GSM, debug */ hs_csr = cpci_get_hs_csr(slot); dbg("%s - slot %s HS_CSR = %04x", - __func__, slot->hotplug_slot->name, hs_csr); + __func__, slot_name(slot), hs_csr); if (!slot->extracting) { if (update_latch_status(slot->hotplug_slot, 0)) { @@ -493,7 +476,7 @@ * bother trying to tell the driver or not? */ err("card in slot %s was improperly removed", - slot->hotplug_slot->name); + slot_name(slot)); if (update_adapter_status(slot->hotplug_slot, 0)) warn("failure to update adapter file"); slot->extracting = 0; --- linux-2.6.27.orig/drivers/pci/hotplug/ibmphp.h +++ linux-2.6.27/drivers/pci/hotplug/ibmphp.h @@ -707,17 +707,16 @@ u8 device; u8 number; u8 real_physical_slot_num; - char name[100]; u32 capabilities; u8 supported_speed; u8 supported_bus_mode; + u8 flag; /* this is for disable slot and polling */ + u8 ctlr_index; struct hotplug_slot *hotplug_slot; struct controller *ctrl; struct pci_func *func; u8 irq[4]; - u8 flag; /* this is for disable slot and polling */ int bit_mode; /* 0 = 32, 1 = 64 */ - u8 ctlr_index; struct bus_info *bus_on; struct list_head ibm_slot_list; u8 status; --- linux-2.6.27.orig/drivers/pci/pcie/aspm.c +++ linux-2.6.27/drivers/pci/pcie/aspm.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "../pci.h" @@ -32,6 +33,11 @@ struct pcie_link_state { struct list_head sibiling; struct pci_dev *pdev; + bool downstream_has_switch; + + struct pcie_link_state *parent; + struct list_head children; + struct list_head link; /* ASPM state */ unsigned int support_state; @@ -124,7 +130,7 @@ link_state->clk_pm_enabled = !!enable; } -static void pcie_check_clock_pm(struct pci_dev *pdev) +static void pcie_check_clock_pm(struct pci_dev *pdev, int blacklist) { int pos; u32 reg32; @@ -148,10 +154,26 @@ if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN)) enabled = 0; } - link_state->clk_pm_capable = capable; link_state->clk_pm_enabled = enabled; link_state->bios_clk_state = enabled; - pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); + if (!blacklist) { + link_state->clk_pm_capable = capable; + pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); + } else { + link_state->clk_pm_capable = 0; + pcie_set_clock_pm(pdev, 0); + } +} + +static bool pcie_aspm_downstream_has_switch(struct pci_dev *pdev) +{ + struct pci_dev *child_dev; + + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + if (child_dev->pcie_type == PCI_EXP_TYPE_UPSTREAM) + return true; + } + return false; } /* @@ -161,11 +183,12 @@ */ static void pcie_aspm_configure_common_clock(struct pci_dev *pdev) { - int pos, child_pos; + int pos, child_pos, i = 0; u16 reg16 = 0; struct pci_dev *child_dev; int same_clock = 1; - + unsigned long start_jiffies; + u16 child_regs[8], parent_reg; /* * all functions of a slot should have the same Slot Clock * Configuration, so just check one function @@ -191,16 +214,19 @@ child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, ®16); + child_regs[i] = reg16; if (same_clock) reg16 |= PCI_EXP_LNKCTL_CCC; else reg16 &= ~PCI_EXP_LNKCTL_CCC; pci_write_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, reg16); + i++; } /* Configure upstream component */ pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); + parent_reg = reg16; if (same_clock) reg16 |= PCI_EXP_LNKCTL_CCC; else @@ -212,12 +238,30 @@ pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); /* Wait for link training end */ - while (1) { + /* break out after waiting for 1 second */ + start_jiffies = jiffies; + while ((jiffies - start_jiffies) < HZ) { pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, ®16); if (!(reg16 & PCI_EXP_LNKSTA_LT)) break; cpu_relax(); } + /* training failed -> recover */ + if ((jiffies - start_jiffies) >= HZ) { + dev_printk (KERN_ERR, &pdev->dev, "ASPM: Could not configure" + " common clock\n"); + i = 0; + list_for_each_entry(child_dev, &pdev->subordinate->devices, + bus_list) { + child_pos = pci_find_capability(child_dev, + PCI_CAP_ID_EXP); + pci_write_config_word(child_dev, + child_pos + PCI_EXP_LNKCTL, + child_regs[i]); + i++; + } + pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, parent_reg); + } } /* @@ -396,9 +440,9 @@ { struct pci_dev *child_dev; - /* If no child, disable the link */ + /* If no child, ignore the link */ if (list_empty(&pdev->subordinate->devices)) - return 0; + return state; list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { /* @@ -439,6 +483,9 @@ int valid = 1; struct pcie_link_state *link_state = pdev->link_state; + /* If no child, disable the link */ + if (list_empty(&pdev->subordinate->devices)) + state = 0; /* * if the downstream component has pci bridge function, don't do ASPM * now @@ -470,20 +517,52 @@ link_state->enabled_state = state; } +static struct pcie_link_state *get_root_port_link(struct pcie_link_state *link) +{ + struct pcie_link_state *root_port_link = link; + while (root_port_link->parent) + root_port_link = root_port_link->parent; + return root_port_link; +} + +/* check the whole hierarchy, and configure each link in the hierarchy */ static void __pcie_aspm_configure_link_state(struct pci_dev *pdev, unsigned int state) { struct pcie_link_state *link_state = pdev->link_state; + struct pcie_link_state *root_port_link = get_root_port_link(link_state); + struct pcie_link_state *leaf; - if (link_state->support_state == 0) - return; state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; - /* state 0 means disabling aspm */ - state = pcie_aspm_check_state(pdev, state); + /* check all links who have specific root port link */ + list_for_each_entry(leaf, &link_list, sibiling) { + if (!list_empty(&leaf->children) || + get_root_port_link(leaf) != root_port_link) + continue; + state = pcie_aspm_check_state(leaf->pdev, state); + } + /* check root port link too in case it hasn't children */ + state = pcie_aspm_check_state(root_port_link->pdev, state); + if (link_state->enabled_state == state) return; - __pcie_aspm_config_link(pdev, state); + + /* + * we must change the hierarchy. See comments in + * __pcie_aspm_config_link for the order + **/ + if (state & PCIE_LINK_STATE_L1) { + list_for_each_entry(leaf, &link_list, sibiling) { + if (get_root_port_link(leaf) == root_port_link) + __pcie_aspm_config_link(leaf->pdev, state); + } + } else { + list_for_each_entry_reverse(leaf, &link_list, sibiling) { + if (get_root_port_link(leaf) == root_port_link) + __pcie_aspm_config_link(leaf->pdev, state); + } + } } /* @@ -547,6 +626,7 @@ unsigned int state; struct pcie_link_state *link_state; int error = 0; + int blacklist; if (aspm_disabled || !pdev->is_pcie || pdev->link_state) return; @@ -557,29 +637,58 @@ if (list_empty(&pdev->subordinate->devices)) goto out; - if (pcie_aspm_sanity_check(pdev)) - goto out; + blacklist = !!pcie_aspm_sanity_check(pdev); mutex_lock(&aspm_lock); link_state = kzalloc(sizeof(*link_state), GFP_KERNEL); if (!link_state) goto unlock_out; - pdev->link_state = link_state; - - pcie_aspm_configure_common_clock(pdev); - pcie_aspm_cap_init(pdev); + link_state->downstream_has_switch = pcie_aspm_downstream_has_switch(pdev); + INIT_LIST_HEAD(&link_state->children); + INIT_LIST_HEAD(&link_state->link); + if (pdev->bus->self) {/* this is a switch */ + struct pcie_link_state *parent_link_state; + + parent_link_state = pdev->bus->parent->self->link_state; + if (!parent_link_state) { + kfree(link_state); + goto unlock_out; + } + list_add(&link_state->link, &parent_link_state->children); + link_state->parent = parent_link_state; + } - /* config link state to avoid BIOS error */ - state = pcie_aspm_check_state(pdev, policy_to_aspm_state(pdev)); - __pcie_aspm_config_link(pdev, state); + pdev->link_state = link_state; - pcie_check_clock_pm(pdev); + if (!blacklist) { + pcie_aspm_configure_common_clock(pdev); + pcie_aspm_cap_init(pdev); + } else { + link_state->enabled_state = PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; + link_state->bios_aspm_state = 0; + /* Set support state to 0, so we will disable ASPM later */ + link_state->support_state = 0; + } link_state->pdev = pdev; list_add(&link_state->sibiling, &link_list); + if (link_state->downstream_has_switch) { + /* + * If link has switch, delay the link config. The leaf link + * initialization will config the whole hierarchy. but we must + * make sure BIOS doesn't set unsupported link state + **/ + state = pcie_aspm_check_state(pdev, link_state->bios_aspm_state); + __pcie_aspm_config_link(pdev, state); + } else + __pcie_aspm_configure_link_state(pdev, + policy_to_aspm_state(pdev)); + + pcie_check_clock_pm(pdev, blacklist); + unlock_out: if (error) free_link_state(pdev); @@ -604,14 +713,15 @@ /* * All PCIe functions are in one slot, remove one function will remove - * the the whole slot, so just wait + * the whole slot, so just wait until we are the last function left. */ - if (!list_empty(&parent->subordinate->devices)) + if (!list_is_last(&pdev->bus_list, &parent->subordinate->devices)) goto out; /* All functions are removed, so just disable ASPM for the link */ __pcie_aspm_config_one_dev(parent, 0); list_del(&link_state->sibiling); + list_del(&link_state->link); /* Clock PM is for endpoint device */ free_link_state(parent); --- linux-2.6.27.orig/drivers/pci/pcie/portdrv_pci.c +++ linux-2.6.27/drivers/pci/pcie/portdrv_pci.c @@ -41,7 +41,6 @@ { int retval; - pci_restore_state(dev); retval = pci_enable_device(dev); if (retval) return retval; @@ -52,11 +51,18 @@ #ifdef CONFIG_PM static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state) { - int ret = pcie_port_device_suspend(dev, state); + return pcie_port_device_suspend(dev, state); - if (!ret) - ret = pcie_portdrv_save_config(dev); - return ret; +} + +static int pcie_portdrv_suspend_late(struct pci_dev *dev, pm_message_t state) +{ + return pci_save_state(dev); +} + +static int pcie_portdrv_resume_early(struct pci_dev *dev) +{ + return pci_restore_state(dev); } static int pcie_portdrv_resume(struct pci_dev *dev) @@ -66,6 +72,8 @@ } #else #define pcie_portdrv_suspend NULL +#define pcie_portdrv_suspend_late NULL +#define pcie_portdrv_resume_early NULL #define pcie_portdrv_resume NULL #endif @@ -221,6 +229,7 @@ /* If fatal, restore cfg space for possible link reset at upstream */ if (dev->error_state == pci_channel_io_frozen) { + pci_restore_state(dev); pcie_portdrv_restore_config(dev); pci_enable_pcie_error_reporting(dev); } @@ -283,6 +292,8 @@ .remove = pcie_portdrv_remove, .suspend = pcie_portdrv_suspend, + .suspend_late = pcie_portdrv_suspend_late, + .resume_early = pcie_portdrv_resume_early, .resume = pcie_portdrv_resume, .err_handler = &pcie_portdrv_err_handler, --- linux-2.6.27.orig/drivers/media/video/ir-kbd-i2c.c +++ linux-2.6.27/drivers/media/video/ir-kbd-i2c.c @@ -12,6 +12,10 @@ * Markus Rechberger * modified for DViCO Fusion HDTV 5 RT GOLD by * Chaogui Zhang + * modified for MSI TV@nywhere Plus by + * Henry Wong + * Mark Schultz + * Brian Rogers * * 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 @@ -224,9 +228,15 @@ static void ir_work(struct work_struct *work) { struct IR_i2c *ir = container_of(work, struct IR_i2c, work); + int polling_interval = 100; + + /* MSI TV@nywhere Plus requires more frequent polling + otherwise it will miss some keypresses */ + if (ir->c.adapter->id == I2C_HW_SAA7134 && ir->c.addr == 0x30) + polling_interval = 50; ir_key_poll(ir); - mod_timer(&ir->timer, jiffies + msecs_to_jiffies(100)); + mod_timer(&ir->timer, jiffies + msecs_to_jiffies(polling_interval)); } /* ----------------------------------------------------------------------- */ @@ -465,9 +475,37 @@ (1 == rc) ? "yes" : "no"); if (1 == rc) { ir_attach(adap, probe[i], 0, 0); - break; + return 0; } } + + /* Special case for MSI TV@nywhere Plus remote */ + if (adap->id == I2C_HW_SAA7134) { + u8 temp; + + /* MSI TV@nywhere Plus controller doesn't seem to + respond to probes unless we read something from + an existing device. Weird... */ + + msg.addr = 0x50; + rc = i2c_transfer(adap, &msg, 1); + dprintk(1, "probe 0x%02x @ %s: %s\n", + msg.addr, adap->name, + (1 == rc) ? "yes" : "no"); + + /* Now do the probe. The controller does not respond + to 0-byte reads, so we use a 1-byte read instead. */ + msg.addr = 0x30; + msg.len = 1; + msg.buf = &temp; + rc = i2c_transfer(adap, &msg, 1); + dprintk(1, "probe 0x%02x @ %s: %s\n", + msg.addr, adap->name, + (1 == rc) ? "yes" : "no"); + if (1 == rc) + ir_attach(adap, msg.addr, 0, 0); + } + return 0; } --- linux-2.6.27.orig/drivers/media/video/compat_ioctl32.c +++ linux-2.6.27/drivers/media/video/compat_ioctl32.c @@ -867,6 +867,7 @@ case VIDIOC_STREAMON32: case VIDIOC_STREAMOFF32: case VIDIOC_G_PARM: + case VIDIOC_S_PARM: case VIDIOC_G_STD: case VIDIOC_S_STD: case VIDIOC_G_TUNER: @@ -885,6 +886,8 @@ case VIDIOC_S_INPUT32: case VIDIOC_TRY_FMT32: case VIDIOC_S_HW_FREQ_SEEK: + case VIDIOC_ENUM_FRAMESIZES: + case VIDIOC_ENUM_FRAMEINTERVALS: ret = do_video_ioctl(file, cmd, arg); break; --- linux-2.6.27.orig/drivers/media/video/tvaudio.c +++ linux-2.6.27/drivers/media/video/tvaudio.c @@ -152,7 +152,7 @@ { unsigned char buffer[2]; - if (-1 == subaddr) { + if (subaddr < 0) { v4l_dbg(1, debug, chip->c, "%s: chip_write: 0x%x\n", chip->c->name, val); chip->shadow.bytes[1] = val; @@ -163,6 +163,13 @@ return -1; } } else { + if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) { + v4l_info(chip->c, + "Tried to access a non-existent register: %d\n", + subaddr); + return -EINVAL; + } + v4l_dbg(1, debug, chip->c, "%s: chip_write: reg%d=0x%x\n", chip->c->name, subaddr, val); chip->shadow.bytes[subaddr+1] = val; @@ -177,12 +184,20 @@ return 0; } -static int chip_write_masked(struct CHIPSTATE *chip, int subaddr, int val, int mask) +static int chip_write_masked(struct CHIPSTATE *chip, + int subaddr, int val, int mask) { if (mask != 0) { - if (-1 == subaddr) { + if (subaddr < 0) { val = (chip->shadow.bytes[1] & ~mask) | (val & mask); } else { + if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) { + v4l_info(chip->c, + "Tried to access a non-existent register: %d\n", + subaddr); + return -EINVAL; + } + val = (chip->shadow.bytes[subaddr+1] & ~mask) | (val & mask); } } @@ -228,6 +243,15 @@ if (0 == cmd->count) return 0; + if (cmd->count + cmd->bytes[0] - 1 >= ARRAY_SIZE(chip->shadow.bytes)) { + v4l_info(chip->c, + "Tried to access a non-existent register range: %d to %d\n", + cmd->bytes[0] + 1, cmd->bytes[0] + cmd->count - 1); + return -EINVAL; + } + + /* FIXME: it seems that the shadow bytes are wrong bellow !*/ + /* update our shadow register set; print bytes if (debug > 0) */ v4l_dbg(1, debug, chip->c, "%s: chip_cmd(%s): reg=%d, data:", chip->c->name, name,cmd->bytes[0]); @@ -1576,13 +1600,13 @@ return 0; } case V4L2_CID_AUDIO_BASS: - if (desc->flags & CHIP_HAS_BASSTREBLE) + if (!(desc->flags & CHIP_HAS_BASSTREBLE)) break; ctrl->value = chip->bass; return 0; case V4L2_CID_AUDIO_TREBLE: - if (desc->flags & CHIP_HAS_BASSTREBLE) - return -EINVAL; + if (!(desc->flags & CHIP_HAS_BASSTREBLE)) + break; ctrl->value = chip->treble; return 0; } @@ -1642,16 +1666,15 @@ return 0; } case V4L2_CID_AUDIO_BASS: - if (desc->flags & CHIP_HAS_BASSTREBLE) + if (!(desc->flags & CHIP_HAS_BASSTREBLE)) break; chip->bass = ctrl->value; chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass)); return 0; case V4L2_CID_AUDIO_TREBLE: - if (desc->flags & CHIP_HAS_BASSTREBLE) - return -EINVAL; - + if (!(desc->flags & CHIP_HAS_BASSTREBLE)) + break; chip->treble = ctrl->value; chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble)); @@ -1695,7 +1718,7 @@ break; case V4L2_CID_AUDIO_BASS: case V4L2_CID_AUDIO_TREBLE: - if (desc->flags & CHIP_HAS_BASSTREBLE) + if (!(desc->flags & CHIP_HAS_BASSTREBLE)) return -EINVAL; break; default: @@ -1792,7 +1815,7 @@ break; case VIDIOC_S_FREQUENCY: chip->mode = 0; /* automatic */ - if (desc->checkmode) { + if (desc->checkmode && desc->setmode) { desc->setmode(chip,V4L2_TUNER_MODE_MONO); if (chip->prevmode != V4L2_TUNER_MODE_MONO) chip->prevmode = -1; /* reset previous mode */ --- linux-2.6.27.orig/drivers/media/video/cx88/cx88-input.c +++ linux-2.6.27/drivers/media/video/cx88/cx88-input.c @@ -229,6 +229,7 @@ ir->sampling = 1; break; case CX88_BOARD_WINFAST_DTV2000H: + case CX88_BOARD_WINFAST_DTV2000H_2: ir_codes = ir_codes_winfast; ir->gpio_addr = MO_GP0_IO; ir->mask_keycode = 0x8f8; --- linux-2.6.27.orig/drivers/media/video/cx88/cx88-dvb.c +++ linux-2.6.27/drivers/media/video/cx88/cx88-dvb.c @@ -554,6 +554,7 @@ } break; case CX88_BOARD_WINFAST_DTV2000H: + case CX88_BOARD_WINFAST_DTV2000H_2: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR1100LP: case CX88_BOARD_HAUPPAUGE_HVR1300: --- linux-2.6.27.orig/drivers/media/video/cx88/cx88-mpeg.c +++ linux-2.6.27/drivers/media/video/cx88/cx88-mpeg.c @@ -126,6 +126,11 @@ cx_write(TS_VALERR_CNTRL, 0); udelay(100); break; + case CX88_BOARD_WINFAST_DTV2000H_2: + /* switch signal input to antena */ + cx_write(MO_GP0_IO, 0x00017300); + cx_write(TS_SOP_STAT, 0x00); + break; default: cx_write(TS_SOP_STAT, 0x00); break; --- linux-2.6.27.orig/drivers/media/video/cx88/cx88-cards.c +++ linux-2.6.27/drivers/media/video/cx88/cx88-cards.c @@ -1238,7 +1238,7 @@ }, [CX88_BOARD_WINFAST_DTV2000H] = { /* video inputs and radio still in testing */ - .name = "WinFast DTV2000 H", + .name = "WinFast DTV2000 H ver. I (old)", .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, .radio_type = UNSET, .tuner_addr = ADDR_UNSET, @@ -1254,6 +1254,45 @@ }}, .mpeg = CX88_MPEG_DVB, }, + [CX88_BOARD_WINFAST_DTV2000H_2] = { + /* this is just a try */ + .name = "WinFast DTV2000 H ver. J (new)", + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = { { + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00017300, + .gpio1 = 0x00008207, + .gpio2 = 0x00000000, + .gpio3 = 0x02000000, + }, { + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00018300, + .gpio1 = 0x0000f207, + .gpio2 = 0x00017304, + .gpio3 = 0x02000000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x00018301, + .gpio1 = 0x0000f207, + .gpio2 = 0x00017304, + .gpio3 = 0x02000000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x00018301, + .gpio1 = 0x0000f207, + .gpio2 = 0x00017304, + .gpio3 = 0x02000000, + } }, + .mpeg = CX88_MPEG_DVB, + }, [CX88_BOARD_GENIATECH_DVBS] = { .name = "Geniatech DVB-S", .tuner_type = TUNER_ABSENT, @@ -1913,6 +1952,10 @@ .subdevice = 0x665e, .card = CX88_BOARD_WINFAST_DTV2000H, },{ + .subvendor = 0x107d, + .subdevice = 0x6f2b, + .card = CX88_BOARD_WINFAST_DTV2000H_2, + },{ .subvendor = 0x18ac, .subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */ .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q, --- linux-2.6.27.orig/drivers/media/video/cx88/cx88.h +++ linux-2.6.27/drivers/media/video/cx88/cx88.h @@ -221,6 +221,7 @@ #define CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD 65 #define CX88_BOARD_PROLINK_PV_8000GT 66 #define CX88_BOARD_KWORLD_ATSC_120 67 +#define CX88_BOARD_WINFAST_DTV2000H_2 68 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, --- linux-2.6.27.orig/drivers/media/video/gspca/zc3xx.c +++ linux-2.6.27/drivers/media/video/gspca/zc3xx.c @@ -7555,9 +7555,7 @@ {USB_DEVICE(0x0ac8, 0x0301), .driver_info = SENSOR_PAS106}, {USB_DEVICE(0x0ac8, 0x0302)}, {USB_DEVICE(0x0ac8, 0x301b)}, -#if !defined CONFIG_USB_ZC0301 && !defined CONFIG_USB_ZC0301_MODULE {USB_DEVICE(0x0ac8, 0x303b)}, -#endif {USB_DEVICE(0x0ac8, 0x305b), .driver_info = SENSOR_TAS5130C_VF0250}, {USB_DEVICE(0x0ac8, 0x307b)}, {USB_DEVICE(0x10fd, 0x0128)}, --- linux-2.6.27.orig/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ linux-2.6.27/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -60,7 +60,6 @@ static DEFINE_MUTEX(pvr2_unit_mtx); static int ctlchg; -static int initusbreset = 1; static int procreload; static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 }; static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 }; @@ -71,8 +70,6 @@ MODULE_PARM_DESC(ctlchg, "0=optimize ctl change 1=always accept new ctl value"); module_param(init_pause_msec, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(init_pause_msec, "hardware initialization settling delay"); -module_param(initusbreset, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(initusbreset, "Do USB reset device on probe"); module_param(procreload, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(procreload, "Attempt init failure recovery with firmware reload"); @@ -1698,9 +1695,6 @@ } hdw->fw1_state = FW1_STATE_OK; - if (initusbreset) { - pvr2_hdw_device_reset(hdw); - } if (!pvr2_hdw_dev_ok(hdw)) return; for (idx = 0; idx < hdw->hdw_desc->client_modules.cnt; idx++) { --- linux-2.6.27.orig/drivers/media/video/pvrusb2/pvrusb2-encoder.c +++ linux-2.6.27/drivers/media/video/pvrusb2/pvrusb2-encoder.c @@ -402,6 +402,10 @@ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 0,3,0,0); ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4,15,0,0,0); + /* prevent the PTSs from slowly drifting away in the generated + MPEG stream */ + ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC, 2, 4, 1); + return ret; } --- linux-2.6.27.orig/drivers/media/video/au0828/au0828-cards.c +++ linux-2.6.27/drivers/media/video/au0828/au0828-cards.c @@ -90,6 +90,7 @@ case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */ case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */ case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and basic analog video */ + case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and basic analog video */ case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and basic analog video */ case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */ break; @@ -198,6 +199,8 @@ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, { USB_DEVICE(0x2040, 0x721b), .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, + { USB_DEVICE(0x2040, 0x721e), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, { USB_DEVICE(0x2040, 0x721f), .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, { USB_DEVICE(0x2040, 0x7280), --- linux-2.6.27.orig/drivers/media/video/saa7134/saa7134-i2c.c +++ linux-2.6.27/drivers/media/video/saa7134/saa7134-i2c.c @@ -337,6 +337,7 @@ case 0x47: case 0x71: case 0x2d: + case 0x30: { struct IR_i2c *ir = i2c_get_clientdata(client); d1printk("%s i2c IR detected (%s).\n", --- linux-2.6.27.orig/drivers/media/video/saa7134/saa7134-cards.c +++ linux-2.6.27/drivers/media/video/saa7134/saa7134-cards.c @@ -5745,6 +5745,7 @@ case SAA7134_BOARD_PINNACLE_PCTV_110i: case SAA7134_BOARD_PINNACLE_PCTV_310i: case SAA7134_BOARD_UPMOST_PURPLE_TV: + case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS: case SAA7134_BOARD_HAUPPAUGE_HVR1110: case SAA7134_BOARD_BEHOLD_607_9FM: case SAA7134_BOARD_BEHOLD_M6: --- linux-2.6.27.orig/drivers/media/video/saa7134/saa7134-input.c +++ linux-2.6.27/drivers/media/video/saa7134/saa7134-input.c @@ -115,6 +115,53 @@ /* --------------------- Chip specific I2C key builders ----------------- */ +static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key, + u32 *ir_raw) +{ + unsigned char b; + int gpio; + + /* is needed to access GPIO. Used by the saa_readl macro. */ + struct saa7134_dev *dev = ir->c.adapter->algo_data; + if (dev == NULL) { + dprintk("get_key_msi_tvanywhere_plus: " + "gir->c.adapter->algo_data is NULL!\n"); + return -EIO; + } + + /* rising SAA7134_GPIO_GPRESCAN reads the status */ + + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + + gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); + + /* GPIO&0x40 is pulsed low when a button is pressed. Don't do + I2C receive if gpio&0x40 is not low. */ + + if (gpio & 0x40) + return 0; /* No button press */ + + /* GPIO says there is a button press. Get it. */ + + if (1 != i2c_master_recv(&ir->c, &b, 1)) { + i2cdprintk("read error\n"); + return -EIO; + } + + /* No button press */ + + if (b == 0xff) + return 0; + + /* Button pressed */ + + dprintk("get_key_msi_tvanywhere_plus: Key = 0x%02X\n", b); + *ir_key = b; + *ir_raw = b; + return 1; +} + static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char b; @@ -612,6 +659,11 @@ ir->get_key = get_key_purpletv; ir->ir_codes = ir_codes_purpletv; break; + case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS: + snprintf(ir->c.name, sizeof(ir->c.name), "MSI TV@nywhere Plus"); + ir->get_key = get_key_msi_tvanywhere_plus; + ir->ir_codes = ir_codes_msi_tvanywhere_plus; + break; case SAA7134_BOARD_HAUPPAUGE_HVR1110: snprintf(ir->c.name, sizeof(ir->c.name), "HVR 1110"); ir->get_key = get_key_hvr1110; --- linux-2.6.27.orig/drivers/media/video/uvc/uvc_status.c +++ linux-2.6.27/drivers/media/video/uvc/uvc_status.c @@ -177,9 +177,15 @@ uvc_input_init(dev); + dev->status = kzalloc(UVC_MAX_STATUS_SIZE, GFP_KERNEL); + if (dev->status == NULL) + return -ENOMEM; + dev->int_urb = usb_alloc_urb(0, GFP_KERNEL); - if (dev->int_urb == NULL) + if (dev->int_urb == NULL) { + kfree(dev->status); return -ENOMEM; + } pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress); @@ -192,7 +198,7 @@ interval = fls(interval) - 1; usb_fill_int_urb(dev->int_urb, dev->udev, pipe, - dev->status, sizeof dev->status, uvc_status_complete, + dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete, dev, interval); return usb_submit_urb(dev->int_urb, GFP_KERNEL); @@ -202,6 +208,7 @@ { usb_kill_urb(dev->int_urb); usb_free_urb(dev->int_urb); + kfree(dev->status); uvc_input_cleanup(dev); } --- linux-2.6.27.orig/drivers/media/video/uvc/uvc_video.c +++ linux-2.6.27/drivers/media/video/uvc/uvc_video.c @@ -455,7 +455,8 @@ urb->iso_frame_desc[i].actual_length - ret); /* Process the header again. */ - uvc_video_decode_end(video, buf, mem, ret); + uvc_video_decode_end(video, buf, mem, + urb->iso_frame_desc[i].actual_length); if (buf->state == UVC_BUF_STATE_DONE || buf->state == UVC_BUF_STATE_ERROR) @@ -512,7 +513,7 @@ video->bulk.payload_size >= video->bulk.max_payload_size) { if (!video->bulk.skip_payload && buf != NULL) { uvc_video_decode_end(video, buf, video->bulk.header, - video->bulk.header_size); + video->bulk.payload_size); if (buf->state == UVC_BUF_STATE_DONE || buf->state == UVC_BUF_STATE_ERROR) buf = uvc_queue_next_buffer(&video->queue, buf); @@ -655,7 +656,7 @@ if (size > UVC_MAX_FRAME_SIZE) return -EINVAL; - npackets = (size + psize - 1) / psize; + npackets = DIV_ROUND_UP(size, psize); if (npackets > UVC_MAX_ISO_PACKETS) npackets = UVC_MAX_ISO_PACKETS; @@ -934,11 +935,8 @@ break; } - /* Commit the default settings. */ probe->bFormatIndex = format->index; probe->bFrameIndex = frame->bFrameIndex; - if ((ret = uvc_set_video_ctrl(video, probe, 0)) < 0) - return ret; video->streaming->cur_format = format; video->streaming->cur_frame = frame; @@ -970,9 +968,18 @@ return 0; } + if (video->streaming->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) + video->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE; + else + video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE; + if ((ret = uvc_queue_enable(&video->queue, 1)) < 0) return ret; + /* Commit the streaming parameters. */ + if ((ret = uvc_set_video_ctrl(video, &video->streaming->ctrl, 0)) < 0) + return ret; + return uvc_init_video(video, GFP_KERNEL); } --- linux-2.6.27.orig/drivers/media/video/uvc/uvc_ctrl.c +++ linux-2.6.27/drivers/media/video/uvc/uvc_ctrl.c @@ -83,6 +83,22 @@ }, { .entity = UVC_GUID_UVC_PROCESSING, + .selector = PU_WHITE_BALANCE_TEMPERATURE_CONTROL, + .index = 6, + .size = 2, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, + }, + { + .entity = UVC_GUID_UVC_PROCESSING, + .selector = PU_WHITE_BALANCE_COMPONENT_CONTROL, + .index = 7, + .size = 4, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, + }, + { + .entity = UVC_GUID_UVC_PROCESSING, .selector = PU_BACKLIGHT_COMPENSATION_CONTROL, .index = 8, .size = 2, @@ -114,6 +130,60 @@ | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, }, { + .entity = UVC_GUID_UVC_PROCESSING, + .selector = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, + .index = 12, + .size = 1, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR + | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, + }, + { + .entity = UVC_GUID_UVC_PROCESSING, + .selector = PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL, + .index = 13, + .size = 1, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR + | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, + }, + { + .entity = UVC_GUID_UVC_PROCESSING, + .selector = PU_DIGITAL_MULTIPLIER_CONTROL, + .index = 14, + .size = 2, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_RESTORE, + }, + { + .entity = UVC_GUID_UVC_PROCESSING, + .selector = PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL, + .index = 15, + .size = 2, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_RESTORE, + }, + { + .entity = UVC_GUID_UVC_PROCESSING, + .selector = PU_ANALOG_VIDEO_STANDARD_CONTROL, + .index = 16, + .size = 1, + .flags = UVC_CONTROL_GET_CUR, + }, + { + .entity = UVC_GUID_UVC_PROCESSING, + .selector = PU_ANALOG_LOCK_STATUS_CONTROL, + .index = 17, + .size = 1, + .flags = UVC_CONTROL_GET_CUR, + }, + { + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_SCANNING_MODE_CONTROL, + .index = 0, + .size = 1, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR + | UVC_CONTROL_RESTORE, + }, + { .entity = UVC_GUID_UVC_CAMERA, .selector = CT_AE_MODE_CONTROL, .index = 1, @@ -140,6 +210,14 @@ }, { .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_EXPOSURE_TIME_RELATIVE_CONTROL, + .index = 4, + .size = 1, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR + | UVC_CONTROL_RESTORE, + }, + { + .entity = UVC_GUID_UVC_CAMERA, .selector = CT_FOCUS_ABSOLUTE_CONTROL, .index = 5, .size = 2, @@ -148,42 +226,90 @@ }, { .entity = UVC_GUID_UVC_CAMERA, - .selector = CT_FOCUS_AUTO_CONTROL, - .index = 17, - .size = 1, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR - | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, + .selector = CT_FOCUS_RELATIVE_CONTROL, + .index = 6, + .size = 2, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_AUTO_UPDATE, }, { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, - .index = 12, + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_IRIS_ABSOLUTE_CONTROL, + .index = 7, + .size = 2, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, + }, + { + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_IRIS_RELATIVE_CONTROL, + .index = 8, .size = 1, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR - | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, + | UVC_CONTROL_AUTO_UPDATE, }, { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = PU_WHITE_BALANCE_TEMPERATURE_CONTROL, - .index = 6, + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_ZOOM_ABSOLUTE_CONTROL, + .index = 9, .size = 2, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, }, { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL, + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_ZOOM_RELATIVE_CONTROL, + .index = 10, + .size = 3, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_AUTO_UPDATE, + }, + { + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_PANTILT_ABSOLUTE_CONTROL, + .index = 11, + .size = 8, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, + }, + { + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_PANTILT_RELATIVE_CONTROL, + .index = 12, + .size = 4, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_AUTO_UPDATE, + }, + { + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_ROLL_ABSOLUTE_CONTROL, .index = 13, + .size = 2, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, + }, + { + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_ROLL_RELATIVE_CONTROL, + .index = 14, + .size = 2, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + | UVC_CONTROL_AUTO_UPDATE, + }, + { + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_FOCUS_AUTO_CONTROL, + .index = 17, .size = 1, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, }, { - .entity = UVC_GUID_UVC_PROCESSING, - .selector = PU_WHITE_BALANCE_COMPONENT_CONTROL, - .index = 7, - .size = 4, - .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE + .entity = UVC_GUID_UVC_CAMERA, + .selector = CT_PRIVACY_CONTROL, + .index = 18, + .size = 1, + .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, }, }; @@ -711,7 +837,17 @@ for (i = 0; i < entity->ncontrols; ++i) { ctrl = &entity->controls[i]; - if (ctrl->info == NULL || !ctrl->dirty) + if (ctrl->info == NULL) + continue; + + /* Reset the loaded flag for auto-update controls that were + * marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent + * uvc_ctrl_get from using the cached value. + */ + if (ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) + ctrl->loaded = 0; + + if (!ctrl->dirty) continue; if (!rollback) @@ -727,9 +863,6 @@ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), ctrl->info->size); - if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) - ctrl->loaded = 0; - ctrl->dirty = 0; if (ret < 0) @@ -787,8 +920,7 @@ if (ret < 0) return ret; - if ((ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) == 0) - ctrl->loaded = 1; + ctrl->loaded = 1; } xctrl->value = uvc_get_le_value( @@ -839,8 +971,7 @@ return ret; } - if ((ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) == 0) - ctrl->loaded = 1; + ctrl->loaded = 1; } if (!ctrl->dirty) { --- linux-2.6.27.orig/drivers/media/video/uvc/uvc_driver.c +++ linux-2.6.27/drivers/media/video/uvc/uvc_driver.c @@ -1663,7 +1663,7 @@ return uvc_video_suspend(&dev->video); } -static int uvc_resume(struct usb_interface *intf) +static int __uvc_resume(struct usb_interface *intf, int reset) { struct uvc_device *dev = usb_get_intfdata(intf); int ret; @@ -1672,7 +1672,7 @@ intf->cur_altsetting->desc.bInterfaceNumber); if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL) { - if ((ret = uvc_ctrl_resume_device(dev)) < 0) + if (reset && (ret = uvc_ctrl_resume_device(dev)) < 0) return ret; return uvc_status_resume(dev); @@ -1687,6 +1687,16 @@ return uvc_video_resume(&dev->video); } +static int uvc_resume(struct usb_interface *intf) +{ + return __uvc_resume(intf, 0); +} + +static int uvc_reset_resume(struct usb_interface *intf) +{ + return __uvc_resume(intf, 1); +} + /* ------------------------------------------------------------------------ * Driver initialization and cleanup */ @@ -1902,6 +1912,24 @@ .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX }, + /* Compaq Presario B1200 - Bison Electronics */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x5986, + .idProduct = 0x0104, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_MINMAX }, + /* Acer Travelmate 7720 - Bison Electronics */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x5986, + .idProduct = 0x0105, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_MINMAX }, /* Medion Akoya Mini E1210 - Bison Electronics */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -1920,6 +1948,24 @@ .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX }, + /* Fujitsu Amilo SI2636 - Bison Electronics */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x5986, + .idProduct = 0x0202, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_MINMAX }, + /* Advent 4211 - Bison Electronics */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x5986, + .idProduct = 0x0203, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_MINMAX }, /* Bison Electronics */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -1938,6 +1984,15 @@ .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX }, + /* COMPAL JHL90 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x064e, + .idProduct = 0xa115, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_MINMAX }, /* Generic USB Video Class */ { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) }, {} @@ -1952,6 +2007,7 @@ .disconnect = uvc_disconnect, .suspend = uvc_suspend, .resume = uvc_resume, + .reset_resume = uvc_reset_resume, .id_table = uvc_ids, .supports_autosuspend = 1, }, --- linux-2.6.27.orig/drivers/media/video/uvc/uvc_v4l2.c +++ linux-2.6.27/drivers/media/video/uvc/uvc_v4l2.c @@ -252,9 +252,6 @@ if (ret < 0) return ret; - if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0) - return ret; - memcpy(&video->streaming->ctrl, &probe, sizeof probe); video->streaming->cur_format = format; video->streaming->cur_frame = frame; @@ -315,10 +312,6 @@ if ((ret = uvc_probe_video(video, &probe)) < 0) return ret; - /* Commit the new settings. */ - if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0) - return ret; - memcpy(&video->streaming->ctrl, &probe, sizeof probe); /* Return the actual frame period. */ @@ -845,10 +838,6 @@ if (ret < 0) return ret; - if (!(video->streaming->cur_format->flags & - UVC_FMT_FLAG_COMPRESSED)) - video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE; - rb->count = ret; ret = 0; break; --- linux-2.6.27.orig/drivers/media/video/uvc/uvcvideo.h +++ linux-2.6.27/drivers/media/video/uvc/uvcvideo.h @@ -303,6 +303,8 @@ #define UVC_MAX_FRAME_SIZE (16*1024*1024) /* Maximum number of video buffers. */ #define UVC_MAX_VIDEO_BUFFERS 32 +/* Maximum status buffer size in bytes of interrupt URB. */ +#define UVC_MAX_STATUS_SIZE 16 #define UVC_CTRL_CONTROL_TIMEOUT 300 #define UVC_CTRL_STREAMING_TIMEOUT 1000 @@ -634,7 +636,7 @@ /* Status Interrupt Endpoint */ struct usb_host_endpoint *int_ep; struct urb *int_urb; - __u8 status[16]; + __u8 *status; struct input_dev *input; /* Video Streaming interfaces */ --- linux-2.6.27.orig/drivers/media/video/zc0301/zc0301_sensor.h +++ linux-2.6.27/drivers/media/video/zc0301/zc0301_sensor.h @@ -61,7 +61,6 @@ #define ZC0301_ID_TABLE \ static const struct usb_device_id zc0301_id_table[] = { \ { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \ - { ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */ \ { } \ }; --- linux-2.6.27.orig/drivers/media/common/ir-keymaps.c +++ linux-2.6.27/drivers/media/common/ir-keymaps.c @@ -467,7 +467,8 @@ /* ---------------------------------------------------------------------- */ -/* MSI TV@nywhere remote */ +/* MSI TV@nywhere MASTER remote */ + IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = { /* Keys 0 to 9 */ [ 0x00 ] = KEY_0, @@ -501,6 +502,95 @@ /* ---------------------------------------------------------------------- */ +/* + Keycodes for remote on the MSI TV@nywhere Plus. The controller IC on the card + is marked "KS003". The controller is I2C at address 0x30, but does not seem + to respond to probes until a read is performed from a valid device. + I don't know why... + + Note: This remote may be of similar or identical design to the + Pixelview remote (?). The raw codes and duplicate button codes + appear to be the same. + + Henry Wong + Some changes to formatting and keycodes by Mark Schultz + +*/ + +IR_KEYTAB_TYPE ir_codes_msi_tvanywhere_plus[IR_KEYTAB_SIZE] = { + +/* ---- Remote Button Layout ---- + + POWER SOURCE SCAN MUTE + TV/FM 1 2 3 + |> 4 5 6 + <| 7 8 9 + ^^UP 0 + RECALL + vvDN RECORD STOP PLAY + + MINIMIZE ZOOM + + CH+ + VOL- VOL+ + CH- + + SNAPSHOT MTS + + << FUNC >> RESET +*/ + + [0x01] = KEY_KP1, /* 1 */ + [0x0b] = KEY_KP2, /* 2 */ + [0x1b] = KEY_KP3, /* 3 */ + [0x05] = KEY_KP4, /* 4 */ + [0x09] = KEY_KP5, /* 5 */ + [0x15] = KEY_KP6, /* 6 */ + [0x06] = KEY_KP7, /* 7 */ + [0x0a] = KEY_KP8, /* 8 */ + [0x12] = KEY_KP9, /* 9 */ + [0x02] = KEY_KP0, /* 0 */ + [0x10] = KEY_KPPLUS, /* + */ + [0x13] = KEY_AGAIN, /* Recall */ + + [0x1e] = KEY_POWER, /* Power */ + [0x07] = KEY_TUNER, /* Source */ + [0x1c] = KEY_SEARCH, /* Scan */ + [0x18] = KEY_MUTE, /* Mute */ + + [0x03] = KEY_RADIO, /* TV/FM */ + /* The next four keys are duplicates that appear to send the + same IR code as Ch+, Ch-, >>, and << . The raw code assigned + to them is the actual code + 0x20 - they will never be + detected as such unless some way is discovered to distinguish + these buttons from those that have the same code. */ + [0x3f] = KEY_RIGHT, /* |> and Ch+ */ + [0x37] = KEY_LEFT, /* <| and Ch- */ + [0x2c] = KEY_UP, /* ^^Up and >> */ + [0x24] = KEY_DOWN, /* vvDn and << */ + + [0x00] = KEY_RECORD, /* Record */ + [0x08] = KEY_STOP, /* Stop */ + [0x11] = KEY_PLAY, /* Play */ + + [0x0f] = KEY_CLOSE, /* Minimize */ + [0x19] = KEY_ZOOM, /* Zoom */ + [0x1a] = KEY_SHUFFLE, /* Snapshot */ + [0x0d] = KEY_LANGUAGE, /* MTS */ + + [0x14] = KEY_VOLUMEDOWN, /* Vol- */ + [0x16] = KEY_VOLUMEUP, /* Vol+ */ + [0x17] = KEY_CHANNELDOWN, /* Ch- */ + [0x1f] = KEY_CHANNELUP, /* Ch+ */ + + [0x04] = KEY_REWIND, /* << */ + [0x0e] = KEY_MENU, /* Function */ + [0x0c] = KEY_FASTFORWARD, /* >> */ + [0x1d] = KEY_RESTART, /* Reset */ +}; +EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere_plus); + +/* ---------------------------------------------------------------------- */ + /* Cinergy 1400 DVB-T */ IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = { [ 0x01 ] = KEY_POWER, --- linux-2.6.27.orig/drivers/media/dvb/frontends/s5h1411.c +++ linux-2.6.27/drivers/media/dvb/frontends/s5h1411.c @@ -471,6 +471,20 @@ return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x24, val); } +static int s5h1411_set_serialmode(struct dvb_frontend *fe, int serial) +{ + struct s5h1411_state *state = fe->demodulator_priv; + u16 val; + + dprintk("%s(%d)\n", __func__, serial); + val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbd) & ~0x100; + + if (serial == 1) + val |= 0x100; + + return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, val); +} + static int s5h1411_enable_modulation(struct dvb_frontend *fe, fe_modulation_t m) { @@ -535,7 +549,7 @@ return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0, val); } -static int s5h1411_sleep(struct dvb_frontend *fe, int enable) +static int s5h1411_set_powerstate(struct dvb_frontend *fe, int enable) { struct s5h1411_state *state = fe->demodulator_priv; @@ -551,6 +565,11 @@ return 0; } +static int s5h1411_sleep(struct dvb_frontend *fe) +{ + return s5h1411_set_powerstate(fe, 1); +} + static int s5h1411_register_reset(struct dvb_frontend *fe) { struct s5h1411_state *state = fe->demodulator_priv; @@ -574,9 +593,6 @@ s5h1411_enable_modulation(fe, p->u.vsb.modulation); - /* Allow the demod to settle */ - msleep(100); - if (fe->ops.tuner_ops.set_params) { if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -587,6 +603,10 @@ fe->ops.i2c_gate_ctrl(fe, 0); } + /* Issue a reset to the demod so it knows to resync against the + newly tuned frequency */ + s5h1411_softreset(fe); + return 0; } @@ -599,7 +619,7 @@ dprintk("%s()\n", __func__); - s5h1411_sleep(fe, 0); + s5h1411_set_powerstate(fe, 0); s5h1411_register_reset(fe); for (i = 0; i < ARRAY_SIZE(init_tab); i++) @@ -612,10 +632,10 @@ if (state->config->output_mode == S5H1411_SERIAL_OUTPUT) /* Serial */ - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, 0x1101); + s5h1411_set_serialmode(fe, 1); else /* Parallel */ - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, 0x1001); + s5h1411_set_serialmode(fe, 0); s5h1411_set_spectralinversion(fe, state->config->inversion); s5h1411_set_if_freq(fe, state->config->vsb_if); @@ -863,6 +883,7 @@ }, .init = s5h1411_init, + .sleep = s5h1411_sleep, .i2c_gate_ctrl = s5h1411_i2c_gate_ctrl, .set_frontend = s5h1411_set_frontend, .get_frontend = s5h1411_get_frontend, --- linux-2.6.27.orig/drivers/media/dvb/siano/smscoreapi.h +++ linux-2.6.27/drivers/media/dvb/siano/smscoreapi.h @@ -186,6 +186,8 @@ #define MSG_SW_RELOAD_EXEC_REQ 704 #define MSG_SW_RELOAD_EXEC_RES 705 #define MSG_SMS_SPI_INT_LINE_SET_REQ 710 +#define MSG_SMS_GPIO_CONFIG_EX_REQ 712 +#define MSG_SMS_GPIO_CONFIG_EX_RES 713 #define MSG_SMS_ISDBT_TUNE_REQ 776 #define MSG_SMS_ISDBT_TUNE_RES 777 @@ -353,7 +355,7 @@ struct dvb_frontend frontend; fe_status_t fe_status; - int fe_ber, fe_snr, fe_signal_strength; + int fe_ber, fe_snr, fe_unc, fe_signal_strength; struct completion tune_done, stat_done; @@ -362,6 +364,32 @@ }; +struct smscore_gpio_config { +#define SMS_GPIO_DIRECTION_INPUT 0 +#define SMS_GPIO_DIRECTION_OUTPUT 1 + u8 direction; + +#define SMS_GPIO_PULLUPDOWN_NONE 0 +#define SMS_GPIO_PULLUPDOWN_PULLDOWN 1 +#define SMS_GPIO_PULLUPDOWN_PULLUP 2 +#define SMS_GPIO_PULLUPDOWN_KEEPER 3 + u8 pullupdown; + +#define SMS_GPIO_INPUTCHARACTERISTICS_NORMAL 0 +#define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1 + u8 inputcharacteristics; + +#define SMS_GPIO_OUTPUTSLEWRATE_FAST 0 +#define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1 + u8 outputslewrate; + +#define SMS_GPIO_OUTPUTDRIVING_4mA 0 +#define SMS_GPIO_OUTPUTDRIVING_8mA 1 +#define SMS_GPIO_OUTPUTDRIVING_12mA 2 +#define SMS_GPIO_OUTPUTDRIVING_16mA 3 + u8 outputdriving; +}; + extern void smscore_registry_setmode(char *devpath, int mode); extern int smscore_registry_getmode(char *devpath); @@ -396,9 +424,15 @@ extern void smscore_putbuffer(struct smscore_device_t *coredev, struct smscore_buffer_t *cb); +int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, + struct smscore_gpio_config *pinconfig); +int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level); + void smscore_set_board_id(struct smscore_device_t *core, int id); int smscore_get_board_id(struct smscore_device_t *core); +int smscore_led_state(struct smscore_device_t *core, int led); + /* smsdvb.c */ int smsdvb_register(void); void smsdvb_unregister(void); --- linux-2.6.27.orig/drivers/media/dvb/siano/sms-cards.h +++ linux-2.6.27/drivers/media/dvb/siano/sms-cards.h @@ -32,14 +32,29 @@ #define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6 #define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7 #define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8 +#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9 +#define SMS1XXX_BOARD_DELL_TIGER_MINICARD_R2 10 +#define SMS1XXX_BOARD_DELL_TIGER_MINICARD 11 +#define SMS1XXX_BOARD_DELL_DVBT 12 struct sms_board { enum sms_device_type_st type; char *name, *fw[DEVICE_MODE_MAX]; + + /* gpios */ + int led_power, led_hi, led_lo, lna_ctrl; }; struct sms_board *sms_get_board(int id); +int sms_board_setup(struct smscore_device_t *coredev); + +#define SMS_LED_OFF 0 +#define SMS_LED_LO 1 +#define SMS_LED_HI 2 +int sms_board_led_feedback(struct smscore_device_t *coredev, int led); +int sms_board_power(struct smscore_device_t *coredev, int onoff); + extern struct usb_device_id smsusb_id_table[]; #endif /* __SMS_CARDS_H__ */ --- linux-2.6.27.orig/drivers/media/dvb/siano/smscoreapi.c +++ linux-2.6.27/drivers/media/dvb/siano/smscoreapi.c @@ -91,6 +91,7 @@ struct completion init_device_done, reload_start_done, resume_done; int board_id; + int led_state; }; void smscore_set_board_id(struct smscore_device_t *core, int id) @@ -98,6 +99,13 @@ core->board_id = id; } +int smscore_led_state(struct smscore_device_t *core, int led) +{ + if (led >= 0) + core->led_state = led; + return core->led_state; +} + int smscore_get_board_id(struct smscore_device_t *core) { return core->board_id; @@ -1187,6 +1195,76 @@ } +int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, + struct smscore_gpio_config *pinconfig) +{ + struct { + struct SmsMsgHdr_ST hdr; + u32 data[6]; + } msg; + + if (coredev->device_flags & SMS_DEVICE_FAMILY2) { + msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + msg.hdr.msgDstId = HIF_TASK; + msg.hdr.msgFlags = 0; + msg.hdr.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; + msg.hdr.msgLength = sizeof(msg); + + msg.data[0] = pin; + msg.data[1] = pinconfig->pullupdown; + + /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */ + msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0; + + switch (pinconfig->outputdriving) { + case SMS_GPIO_OUTPUTDRIVING_16mA: + msg.data[3] = 7; /* Nova - 16mA */ + break; + case SMS_GPIO_OUTPUTDRIVING_12mA: + msg.data[3] = 5; /* Nova - 11mA */ + break; + case SMS_GPIO_OUTPUTDRIVING_8mA: + msg.data[3] = 3; /* Nova - 7mA */ + break; + case SMS_GPIO_OUTPUTDRIVING_4mA: + default: + msg.data[3] = 2; /* Nova - 4mA */ + break; + } + + msg.data[4] = pinconfig->direction; + msg.data[5] = 0; + } else /* TODO: SMS_DEVICE_FAMILY1 */ + return -EINVAL; + + return coredev->sendrequest_handler(coredev->context, + &msg, sizeof(msg)); +} + +int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level) +{ + struct { + struct SmsMsgHdr_ST hdr; + u32 data[3]; + } msg; + + if (pin > MAX_GPIO_PIN_NUMBER) + return -EINVAL; + + msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + msg.hdr.msgDstId = HIF_TASK; + msg.hdr.msgFlags = 0; + msg.hdr.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; + msg.hdr.msgLength = sizeof(msg); + + msg.data[0] = pin; + msg.data[1] = level ? 1 : 0; + msg.data[2] = 0; + + return coredev->sendrequest_handler(coredev->context, + &msg, sizeof(msg)); +} + static int __init smscore_module_init(void) { int rc = 0; --- linux-2.6.27.orig/drivers/media/dvb/siano/smsdvb.c +++ linux-2.6.27/drivers/media/dvb/siano/smsdvb.c @@ -60,6 +60,7 @@ client->fe_snr = p->Stat.SNR; client->fe_ber = p->Stat.BER; + client->fe_unc = p->Stat.BERErrorCount; if (p->Stat.InBandPwr < -95) client->fe_signal_strength = 0; @@ -72,6 +73,7 @@ client->fe_status = 0; client->fe_snr = client->fe_ber = + client->fe_unc = client->fe_signal_strength = 0; } @@ -165,8 +167,18 @@ struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ, DVBT_BDA_CONTROL_MSG_ID, HIF_TASK, sizeof(struct SmsMsgHdr_ST), 0 }; - return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->stat_done); + int ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + &client->stat_done); + if (ret < 0) + return ret; + + if (client->fe_status & FE_HAS_LOCK) + sms_board_led_feedback(client->coredev, + (client->fe_unc == 0) ? + SMS_LED_HI : SMS_LED_LO); + else + sms_board_led_feedback(client->coredev, SMS_LED_OFF); + return ret; } static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat) @@ -217,6 +229,18 @@ return rc; } +static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + int rc = smsdvb_send_statistics_request(client); + + if (!rc) + *ucblocks = client->fe_unc; + + return rc; +} + static int smsdvb_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) { @@ -273,6 +297,28 @@ /* todo: */ memcpy(fep, &client->fe_params, sizeof(struct dvb_frontend_parameters)); + + return 0; +} + +static int smsdvb_init(struct dvb_frontend *fe) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + sms_board_power(client->coredev, 1); + + return 0; +} + +static int smsdvb_sleep(struct dvb_frontend *fe) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + sms_board_led_feedback(client->coredev, SMS_LED_OFF); + sms_board_power(client->coredev, 0); + return 0; } @@ -308,6 +354,10 @@ .read_ber = smsdvb_read_ber, .read_signal_strength = smsdvb_read_signal_strength, .read_snr = smsdvb_read_snr, + .read_ucblocks = smsdvb_read_ucblocks, + + .init = smsdvb_init, + .sleep = smsdvb_sleep, }; static int smsdvb_hotplug(struct smscore_device_t *coredev, @@ -402,6 +452,8 @@ sms_info("success"); + sms_board_setup(coredev); + return 0; client_error: --- linux-2.6.27.orig/drivers/media/dvb/siano/sms-cards.c +++ linux-2.6.27/drivers/media/dvb/siano/sms-cards.c @@ -38,14 +38,28 @@ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A }, { USB_DEVICE(0x2040, 0x1801), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B }, + { USB_DEVICE(0x2040, 0x2000), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x2009), + .driver_info = SMS1XXX_BOARD_DELL_TIGER_MINICARD_R2 }, + { USB_DEVICE(0x2040, 0x200a), + .driver_info = SMS1XXX_BOARD_DELL_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x2010), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD }, + { USB_DEVICE(0x2040, 0x2019), + .driver_info = SMS1XXX_BOARD_DELL_TIGER_MINICARD }, { USB_DEVICE(0x2040, 0x5500), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { USB_DEVICE(0x2040, 0x5510), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0x5580), + { USB_DEVICE(0x2040, 0x5520), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0x5590), + { USB_DEVICE(0x2040, 0x5530), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5580), + .driver_info = SMS1XXX_BOARD_DELL_DVBT }, + { USB_DEVICE(0x2040, 0x5590), + .driver_info = SMS1XXX_BOARD_DELL_DVBT }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, smsusb_id_table); @@ -91,7 +105,33 @@ [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = { .name = "Hauppauge WinTV MiniStick", .type = SMS_NOVA_B0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-01.fw", + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .led_power = 26, + .led_lo = 27, + .led_hi = 28, + }, + [SMS1XXX_BOARD_DELL_DVBT] = { + .name = "Dell Digital TV Receiver", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + }, + [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = { + .name = "Hauppauge WinTV MiniCard", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .lna_ctrl = 29, + }, + [SMS1XXX_BOARD_DELL_TIGER_MINICARD] = { + .name = "Dell Digital TV Receiver", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .lna_ctrl = 29, + }, + [SMS1XXX_BOARD_DELL_TIGER_MINICARD_R2] = { + .name = "Dell Digital TV Receiver", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .lna_ctrl = 1, }, }; @@ -102,3 +142,90 @@ return &sms_boards[id]; } +static int sms_set_gpio(struct smscore_device_t *coredev, u32 pin, int enable) +{ + int ret; + struct smscore_gpio_config gpioconfig = { + .direction = SMS_GPIO_DIRECTION_OUTPUT, + .pullupdown = SMS_GPIO_PULLUPDOWN_NONE, + .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL, + .outputslewrate = SMS_GPIO_OUTPUTSLEWRATE_FAST, + .outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA, + }; + + if (pin == 0) + return -EINVAL; + + ret = smscore_configure_gpio(coredev, pin, &gpioconfig); + + if (ret < 0) + return ret; + + return smscore_set_gpio(coredev, pin, enable); +} + +int sms_board_setup(struct smscore_device_t *coredev) +{ + int board_id = smscore_get_board_id(coredev); + struct sms_board *board = sms_get_board(board_id); + + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + /* turn off all LEDs */ + sms_set_gpio(coredev, board->led_power, 0); + sms_set_gpio(coredev, board->led_hi, 0); + sms_set_gpio(coredev, board->led_lo, 0); + break; + case SMS1XXX_BOARD_DELL_TIGER_MINICARD_R2: + case SMS1XXX_BOARD_DELL_TIGER_MINICARD: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + /* turn off LNA */ + sms_set_gpio(coredev, board->lna_ctrl, 0); + break; + } + return 0; +} + +int sms_board_power(struct smscore_device_t *coredev, int onoff) +{ + int board_id = smscore_get_board_id(coredev); + struct sms_board *board = sms_get_board(board_id); + + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + /* power LED */ + sms_set_gpio(coredev, + board->led_power, onoff ? 1 : 0); + break; + case SMS1XXX_BOARD_DELL_TIGER_MINICARD_R2: + case SMS1XXX_BOARD_DELL_TIGER_MINICARD: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + /* LNA */ + sms_set_gpio(coredev, + board->lna_ctrl, onoff ? 1 : 0); + break; + } + return 0; +} + +int sms_board_led_feedback(struct smscore_device_t *coredev, int led) +{ + int board_id = smscore_get_board_id(coredev); + struct sms_board *board = sms_get_board(board_id); + + /* dont touch GPIO if LEDs are already set */ + if (smscore_led_state(coredev, -1) == led) + return 0; + + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + sms_set_gpio(coredev, + board->led_lo, (led & SMS_LED_LO) ? 1 : 0); + sms_set_gpio(coredev, + board->led_hi, (led & SMS_LED_HI) ? 1 : 0); + + smscore_led_state(coredev, led); + break; + } + return 0; +} --- linux-2.6.27.orig/drivers/mmc/core/core.c +++ linux-2.6.27/drivers/mmc/core/core.c @@ -280,7 +280,11 @@ (card->host->ios.clock / 1000); if (data->flags & MMC_DATA_WRITE) - limit_us = 250000; + /* + * The limit is really 250 ms, but that is + * insufficient for some crappy cards. + */ + limit_us = 300000; else limit_us = 100000; @@ -520,7 +524,7 @@ * This delay must be at least 74 clock sizes, or 1 ms, or the * time required to reach a stable voltage. */ - mmc_delay(2); + mmc_delay(10); } static void mmc_power_off(struct mmc_host *host) --- linux-2.6.27.orig/drivers/mmc/host/ricoh_mmc.c +++ linux-2.6.27/drivers/mmc/host/ricoh_mmc.c @@ -11,9 +11,10 @@ /* * This is a conceptually ridiculous driver, but it is required by the way - * the Ricoh multi-function R5C832 works. This chip implements firewire - * and four different memory card controllers. Two of those controllers are - * an SDHCI controller and a proprietary MMC controller. The linux SDHCI + * the Ricoh multi-function chips (R5CXXX) work. These chips implement + * the four main memory card controllers (SD, MMC, MS, xD) and one or both + * of cardbus or firewire. It happens that they implement SD and MMC + * support as separate controllers (and PCI functions). The linux SDHCI * driver supports MMC cards but the chip detects MMC cards in hardware * and directs them to the MMC controller - so the SDHCI driver never sees * them. To get around this, we must disable the useless MMC controller. @@ -21,8 +22,10 @@ * a detection event occurs immediately, even if the MMC card is already * in the reader. * - * The relevant registers live on the firewire function, so this is unavoidably - * ugly. Such is life. + * It seems to be the case that the relevant PCI registers to deactivate the + * MMC controller live on PCI function 0, which might be the cardbus controller + * or the firewire controller, depending on the particular chip in question. As + * such, it makes what this driver has to do unavoidably ugly. Such is life. */ #include @@ -143,6 +146,7 @@ pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, fw_dev))) { if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) && + PCI_FUNC(fw_dev->devfn) == 0 && pdev->bus == fw_dev->bus) { if (ricoh_mmc_disable(fw_dev) != 0) return -ENODEV; @@ -160,6 +164,7 @@ (fw_dev = pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, fw_dev))) { if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) && + PCI_FUNC(fw_dev->devfn) == 0 && pdev->bus == fw_dev->bus) { if (ricoh_mmc_disable(fw_dev) != 0) return -ENODEV; @@ -172,7 +177,7 @@ if (!ctrlfound) { printk(KERN_WARNING DRIVER_NAME - ": Main firewire function not found. Cannot disable controller.\n"); + ": Main Ricoh function not found. Cannot disable controller.\n"); return -ENODEV; } --- linux-2.6.27.orig/drivers/input/joydev.c +++ linux-2.6.27/drivers/input/joydev.c @@ -847,7 +847,13 @@ INPUT_DEVICE_ID_MATCH_KEYBIT, .evbit = { BIT_MASK(EV_KEY) }, .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) }, - }, /* Avoid itouchpads, touchscreens and tablets */ + }, /* Avoid itouchpads and touchscreens */ + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_KEYBIT, + .evbit = { BIT_MASK(EV_KEY) }, + .keybit = { [BIT_WORD(BTN_DIGI)] = BIT_MASK(BTN_DIGI) }, + }, /* Avoid tablets, digitisers and similar devices */ { } /* Terminating entry */ }; --- linux-2.6.27.orig/drivers/input/tablet/wacom.h +++ linux-2.6.27/drivers/input/tablet/wacom.h @@ -66,6 +66,7 @@ * - Support Intuos3 4x6 * v1.47 (pc) - Added support for Bamboo * v1.48 (pc) - Added support for Bamboo1, BambooFun, and Cintiq 12WX + * v1.49 (pc) - Added support for USB Tablet PC (0x90, 0x93, and 0x9A) */ /* @@ -86,7 +87,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.48" +#define DRIVER_VERSION "v1.49" #define DRIVER_AUTHOR "Vojtech Pavlik " #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver" #define DRIVER_LICENSE "GPL" @@ -105,7 +106,7 @@ struct urb *irq; struct wacom_wac * wacom_wac; struct mutex lock; - unsigned int open:1; + int open:1; char phys[32]; }; --- linux-2.6.27.orig/drivers/input/tablet/wacom_wac.h +++ linux-2.6.27/drivers/input/tablet/wacom_wac.h @@ -10,6 +10,7 @@ #define WACOM_WAC_H #define STYLUS_DEVICE_ID 0x02 +#define TOUCH_DEVICE_ID 0x03 #define CURSOR_DEVICE_ID 0x06 #define ERASER_DEVICE_ID 0x0A #define PAD_DEVICE_ID 0x0F @@ -27,6 +28,7 @@ CINTIQ, WACOM_BEE, WACOM_MO, + TABLETPC, MAX_TYPE }; @@ -38,6 +40,8 @@ int pressure_max; int distance_max; int type; + int touch_x_max; + int touch_y_max; }; struct wacom_wac { --- linux-2.6.27.orig/drivers/input/tablet/wacom_sys.c +++ linux-2.6.27/drivers/input/tablet/wacom_sys.c @@ -14,8 +14,43 @@ #include "wacom.h" #include "wacom_wac.h" +/* defines to get HID report descriptor */ +#define HID_DEVICET_HID (USB_TYPE_CLASS | 0x01) +#define HID_DEVICET_REPORT (USB_TYPE_CLASS | 0x02) +#define HID_USAGE_PAGE 0x05 +#define HID_USAGE_PAGE_DIGITIZER 0x0d +#define HID_USAGE_PAGE_DESKTOP 0x01 +#define HID_USAGE 0x09 +#define HID_USAGE_X 0x30 +#define HID_USAGE_Y 0x31 +#define HID_USAGE_X_TILT 0x3d +#define HID_USAGE_Y_TILT 0x3e +#define HID_USAGE_FINGER 0x22 +#define HID_USAGE_STYLUS 0x20 +#define HID_COLLECTION 0xc0 +#define HID_USAGE_PAGE_VDEFINED 0xff + +enum { + WCM_UNDEFINED = 0, + WCM_DESKTOP, + WCM_DIGITIZER, + MAX_USAGE_PAGE +}; + +struct hid_descriptor +{ + struct usb_descriptor_header header; + __le16 bcdHID; + u8 bCountryCode; + u8 bNumDescriptors; + u8 bDescriptorType; + __le16 wDescriptorLength; +} __attribute__ ((packed)); + +/* defines to get/set USB message */ #define USB_REQ_GET_REPORT 0x01 #define USB_REQ_SET_REPORT 0x09 +#define WAC_HID_FEATURE_REPORT 0x03 static int usb_get_report(struct usb_interface *intf, unsigned char type, unsigned char id, void *buf, int size) @@ -56,10 +91,10 @@ case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, urb->status); + dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, urb->status); + dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); goto exit; } @@ -74,7 +109,7 @@ retval = usb_submit_urb (urb, GFP_ATOMIC); if (retval) err ("%s - usb_submit_urb failed with result %d", - __func__, retval); + __FUNCTION__, retval); } void wacom_report_key(void *wcombo, unsigned int key_type, int key_data) @@ -160,7 +195,7 @@ void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { - input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_1) | + input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_1) | BIT_MASK(BTN_5); input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); } @@ -170,7 +205,7 @@ input_dev->evbit[0] |= BIT_MASK(EV_MSC); input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL); input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_FINGER); - input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_0) | + input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_0) | BIT_MASK(BTN_4); } @@ -178,7 +213,7 @@ { input_dev->evbit[0] |= BIT_MASK(EV_REL); input_dev->relbit[0] |= BIT_MASK(REL_WHEEL); - input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) | + input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE); input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) | BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_STYLUS2); @@ -188,7 +223,7 @@ void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_FINGER); - input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_0) | + input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_0) | BIT_MASK(BTN_1) | BIT_MASK(BTN_2) | BIT_MASK(BTN_3); input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0); input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); @@ -196,14 +231,14 @@ void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { - input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_4) | + input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_4) | BIT_MASK(BTN_5) | BIT_MASK(BTN_6) | BIT_MASK(BTN_7); input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0); } void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { - input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_8) | BIT_MASK(BTN_9); + input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_8) | BIT_MASK(BTN_9); } void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac) @@ -211,7 +246,7 @@ input_dev->evbit[0] |= BIT_MASK(EV_MSC) | BIT_MASK(EV_REL); input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL); input_dev->relbit[0] |= BIT_MASK(REL_WHEEL); - input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) | + input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA); input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) | @@ -228,8 +263,7 @@ void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { - input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_STYLUS2) | - BIT_MASK(BTN_TOOL_RUBBER); + input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_STYLUS2); } void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac) @@ -237,15 +271,106 @@ input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER); } +static void wacom_paser_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc, + struct wacom_wac *wacom_wac, char *report) +{ + struct usb_device *dev = interface_to_usbdev(intf); + char limit = 0, result = 0; + int i = 0, usage = WCM_UNDEFINED, finger = 0, pen = 0; + + /* retrive report descriptors */ + do { + result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, + USB_RECIP_INTERFACE | USB_DIR_IN, + HID_DEVICET_REPORT << 8, + intf->altsetting[0].desc.bInterfaceNumber, /* interface */ + report, + hid_desc->wDescriptorLength, + 5000); /* 5 secs */ + } while (limit++ < 5); + + for (i=0; iwDescriptorLength; i++) { + if ((unsigned short)report[i] == HID_USAGE_PAGE) { + switch ((unsigned short)report[i+1]) { + case HID_USAGE_PAGE_DIGITIZER: + usage = WCM_DIGITIZER; + i++; + continue; + case HID_USAGE_PAGE_DESKTOP: + usage = WCM_DESKTOP; + i++; + continue; + case HID_USAGE_PAGE_VDEFINED: + if (!report[i+3]) { /* capacity */ + wacom_wac->features->pressure_max = (unsigned short)report[i+5]; + } + i += 6; + continue; + } + } + + if ((unsigned short)report[i] == HID_USAGE) { + switch ((unsigned short)report[i+1]) { + case HID_USAGE_X: + if (usage == WCM_DESKTOP) { + if (finger) { + wacom_wac->features->touch_x_max = + wacom_wac->features->touch_y_max = (unsigned short) + (wacom_le16_to_cpu(&report[i+3])); + wacom_wac->features->x_max = (unsigned short) + (wacom_le16_to_cpu(&report[i+6])); + i += 7; + } else if (pen) { + wacom_wac->features->x_max = (unsigned short) + (wacom_le16_to_cpu(&report[i+3])); + i += 4; + } + } else if (usage == WCM_DIGITIZER) { + /* max pressure isn't reported + wacom_wac->features->pressure_max = (unsigned short) + (report[i+4] << 8 | report[i+3]); + */ + wacom_wac->features->pressure_max = 255; + i += 4; + } + break; + case HID_USAGE_Y: + if (usage == WCM_DESKTOP) { + wacom_wac->features->y_max = (unsigned short) + (wacom_le16_to_cpu(&report[i+3])); + } + i += 4; + break; + case HID_USAGE_FINGER: + finger = 1; + i++; + break; + case HID_USAGE_STYLUS: + pen = 1; + i++; + break; + } + } + + if ((unsigned short)report[i] == HID_COLLECTION) { + /* reset UsagePage ans Finger */ + finger = usage = 0; + } + } +} + static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); + struct usb_host_interface *interface = intf->cur_altsetting; struct usb_endpoint_descriptor *endpoint; struct wacom *wacom; struct wacom_wac *wacom_wac; struct input_dev *input_dev; int error = -ENOMEM; - char rep_data[2], limit = 0; + char rep_data[2], limit = 0, mode = 2, *report = NULL; + struct hid_descriptor *hid_desc; wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL); wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL); @@ -282,18 +407,38 @@ input_dev->open = wacom_open; input_dev->close = wacom_close; + endpoint = &intf->cur_altsetting->endpoint[0].desc; + + /* TabletPC need to retrieve the physical and logical maximum from report descriptor */ + if (wacom_wac->features->type == TABLETPC) { + if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) { + if (usb_get_extra_descriptor(&interface->endpoint[0], + HID_DEVICET_REPORT, &hid_desc)) { + printk("wacom: can not retrive extra class descriptor\n"); + goto fail2; + } + } + report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL); + if (!report) { + goto fail2; + } + wacom_paser_hid(intf, hid_desc, wacom_wac, report); + } + input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) | - BIT_MASK(BTN_TOUCH) | BIT_MASK(BTN_STYLUS); + input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_STYLUS); input_set_abs_params(input_dev, ABS_X, 0, wacom_wac->features->x_max, 4, 0); input_set_abs_params(input_dev, ABS_Y, 0, wacom_wac->features->y_max, 4, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom_wac->features->pressure_max, 0, 0); + if (wacom_wac->features->type == TABLETPC) { + input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOUCH); + input_set_abs_params(input_dev, ABS_RX, 0, wacom_wac->features->touch_x_max, 4, 0); + input_set_abs_params(input_dev, ABS_RY, 0, wacom_wac->features->touch_y_max, 4, 0); + } input_dev->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC); wacom_init_input_dev(input_dev, wacom_wac); - endpoint = &intf->cur_altsetting->endpoint[0].desc; - usb_fill_int_urb(wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), wacom_wac->data, wacom_wac->features->pktlen, @@ -305,15 +450,21 @@ if (error) goto fail3; - /* Ask the tablet to report tablet data. Repeat until it succeeds */ - do { - rep_data[0] = 2; - rep_data[1] = 2; - usb_set_report(intf, 3, 2, rep_data, 2); - usb_get_report(intf, 3, 2, rep_data, 2); - } while (rep_data[1] != 2 && limit++ < 5); + /* Ask the tablet to report tablet data if it is not a Tablet PC. + * Repeat until it succeeds + */ + if (wacom_wac->features->type != TABLETPC) { + do { + rep_data[0] = 2; + rep_data[1] = mode; + error = error = usb_set_report(intf, WAC_HID_FEATURE_REPORT, 2, rep_data, 2); + if(error >= 0) + error = usb_get_report(intf, WAC_HID_FEATURE_REPORT, 2, rep_data, 2); + } while (((error <= 0) || (rep_data[1] != mode)) && limit++ < 5); + } usb_set_intfdata(intf, wacom); + kfree(report); return 0; fail3: usb_free_urb(wacom->irq); --- linux-2.6.27.orig/drivers/input/serio/i8042-x86ia64io.h +++ linux-2.6.27/drivers/input/serio/i8042-x86ia64io.h @@ -135,6 +135,14 @@ DMI_MATCH(DMI_PRODUCT_VERSION, "5a"), }, }, + { + .ident = "Blue FB5601", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "blue"), + DMI_MATCH(DMI_PRODUCT_NAME, "FB5601"), + DMI_MATCH(DMI_PRODUCT_VERSION, "M606"), + }, + }, { } }; @@ -322,6 +330,27 @@ DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"), }, }, + { + .ident = "IBM 2656", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "IBM"), + DMI_MATCH(DMI_PRODUCT_NAME, "2656"), + }, + }, + { + .ident = "Dell XPS M1530", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "XPS M1530"), + }, + }, + { + .ident = "Compal HEL80I", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "COMPAL"), + DMI_MATCH(DMI_PRODUCT_NAME, "HEL80I"), + }, + }, { } }; --- linux-2.6.27.orig/drivers/input/mouse/alps.c +++ linux-2.6.27/drivers/input/mouse/alps.c @@ -54,6 +54,7 @@ { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ + { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude E6500 */ { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 } /* Dell Vostro 1400 */ }; @@ -421,7 +422,8 @@ static int alps_reconnect(struct psmouse *psmouse) { - psmouse_reset(psmouse); + /* UBUNTU: Causes lockups on resume */ + /* psmouse_reset(psmouse); */ if (alps_hw_init(psmouse, NULL)) return -1; --- linux-2.6.27.orig/drivers/input/keyboard/atkbd.c +++ linux-2.6.27/drivers/input/keyboard/atkbd.c @@ -834,10 +834,10 @@ } /* - * Most special keys (Fn+F?) on Dell Latitudes do not generate release + * Most special keys (Fn+F?) on Dell laptops do not generate release * events so we have to do it ourselves. */ -static void atkbd_latitude_keymap_fixup(struct atkbd *atkbd) +static void atkbd_dell_laptop_keymap_fixup(struct atkbd *atkbd) { const unsigned int forced_release_keys[] = { 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93, @@ -868,6 +868,71 @@ } /* + * Inventec system with broken key release on volume keys + */ +static void atkbd_inventec_keymap_fixup(struct atkbd *atkbd) +{ + const unsigned int forced_release_keys[] = { + 0xae, 0xb0, + }; + int i; + + if (atkbd->set == 2) + for (i = 0; i < ARRAY_SIZE(forced_release_keys); i++) + __set_bit(forced_release_keys[i], + atkbd->force_release_mask); +} + +/* + * Perform fixup for HP Pavilion ZV6100 laptop that doesn't generate release + * for its volume buttons + */ +static void atkbd_hp_zv6100_keymap_fixup(struct atkbd *atkbd) +{ + const unsigned int forced_release_keys[] = { + 0xae, 0xb0, + }; + int i; + + if (atkbd->set == 2) + for (i = 0; i < ARRAY_SIZE(forced_release_keys); i++) + __set_bit(forced_release_keys[i], + atkbd->force_release_mask); +} + +/* + * Samsung NC10 with Fn+F? key release not working + */ +static void atkbd_samsung_keymap_fixup(struct atkbd *atkbd) +{ + const unsigned int forced_release_keys[] = { + 0x82, 0x83, 0x84, 0x86, 0x88, 0x89, 0xb3, 0xf7, 0xf9, + }; + int i; + + if (atkbd->set == 2) + for (i = 0; i < ARRAY_SIZE(forced_release_keys); i++) + __set_bit(forced_release_keys[i], + atkbd->force_release_mask); +} + +/* + * Fujitsu Siemens system with broken key release on volume keys and mute key + */ +static void atkbd_amilo_xi_2428_keymap_fixup(struct atkbd *atkbd) +{ + const unsigned int forced_release_keys[] = { + 0xa0, 0xae, 0xb0, + }; + int i; + + if (atkbd->set == 2) + for (i = 0; i < ARRAY_SIZE(forced_release_keys); i++) + __set_bit(forced_release_keys[i], + atkbd->force_release_mask); +} + +/* * atkbd_set_keycode_table() initializes keyboard's keycode table * according to the selected scancode set */ @@ -1461,13 +1526,22 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { { - .ident = "Dell Latitude series", + .ident = "Dell Laptop", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), + DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ + }, + .callback = atkbd_setup_fixup, + .driver_data = atkbd_dell_laptop_keymap_fixup, + }, + { + .ident = "Dell Laptop", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ }, .callback = atkbd_setup_fixup, - .driver_data = atkbd_latitude_keymap_fixup, + .driver_data = atkbd_dell_laptop_keymap_fixup, }, { .ident = "HP 2133", @@ -1478,6 +1552,61 @@ .callback = atkbd_setup_fixup, .driver_data = atkbd_hp_keymap_fixup, }, + { + .ident = "HP Pavilion ZV6100", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"), + }, + .callback = atkbd_setup_fixup, + .driver_data = atkbd_hp_zv6100_keymap_fixup, + }, + { + .ident = "Inventec Symphony", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"), + DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"), + }, + .callback = atkbd_setup_fixup, + .driver_data = atkbd_inventec_keymap_fixup, + }, + { + .ident = "Samsung NC10", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "NC10"), + }, + .callback = atkbd_setup_fixup, + .driver_data = atkbd_samsung_keymap_fixup, + }, + { + .ident = "Znote 6615WD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Zepto"), + DMI_MATCH(DMI_PRODUCT_NAME, "Znote 6615WD"), + }, + .callback = atkbd_setup_fixup, + .driver_data = atkbd_inventec_keymap_fixup, + }, + { + .ident = "Znote 6625WD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Zepto"), + DMI_MATCH(DMI_PRODUCT_NAME, "Znote"), + DMI_MATCH(DMI_PRODUCT_VERSION, "6625WD"), + }, + .callback = atkbd_setup_fixup, + .driver_data = atkbd_inventec_keymap_fixup, + }, + { + .ident = "AMILO Xi 2428", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428"), + }, + .callback = atkbd_setup_fixup, + .driver_data = atkbd_amilo_xi_2428_keymap_fixup, + }, { } }; --- linux-2.6.27.orig/drivers/acpi/processor_idle.c +++ linux-2.6.27/drivers/acpi/processor_idle.c @@ -129,52 +129,7 @@ static struct dmi_system_id __cpuinitdata processor_power_dmi_table[] = { { set_max_cstate, "IBM ThinkPad R40e", { DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET70WW")}, (void *)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW")}, (void *)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET43WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET45WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET47WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET50WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET52WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET55WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET56WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET59WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET61WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET62WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET64WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET65WW") }, (void*)1}, - { set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), - DMI_MATCH(DMI_BIOS_VERSION,"1SET68WW") }, (void*)1}, + DMI_MATCH(DMI_BIOS_VERSION,"1SET")}, (void *)1}, { set_max_cstate, "Medion 41700", { DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"), DMI_MATCH(DMI_BIOS_VERSION,"R01-A1J")}, (void *)1}, @@ -1587,6 +1542,7 @@ if (acpi_idle_bm_check()) { if (dev->safe_state) { + dev->last_state = dev->safe_state; return dev->safe_state->enter(dev, dev->safe_state); } else { local_irq_disable(); --- linux-2.6.27.orig/drivers/acpi/scan.c +++ linux-2.6.27/drivers/acpi/scan.c @@ -276,6 +276,13 @@ { const struct acpi_device_id *id; + /* + * If the device is not present, it is unnecessary to load device + * driver for it. + */ + if (!device->status.present) + return -ENODEV; + if (device->flags.hardware_id) { for (id = ids; id->id[0]; id++) { if (!strcmp((char*)id->id, device->pnp.hardware_id)) @@ -901,36 +908,6 @@ } } -static int -acpi_video_bus_match(struct acpi_device *device) -{ - acpi_handle h_dummy; - - if (!device) - return -EINVAL; - - /* Since there is no HID, CID for ACPI Video drivers, we have - * to check well known required nodes for each feature we support. - */ - - /* Does this device able to support video switching ? */ - if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) && - ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy))) - return 0; - - /* Does this device able to retrieve a video ROM ? */ - if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy))) - return 0; - - /* Does this device able to configure which video head to be POSTed ? */ - if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) && - ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) && - ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy))) - return 0; - - return -ENODEV; -} - /* * acpi_bay_match - see if a device is an ejectable driver bay * @@ -1013,7 +990,7 @@ will get autoloaded and the device might still match against another driver. */ - if (ACPI_SUCCESS(acpi_video_bus_match(device))) + if (acpi_is_video_device(device)) cid_add = ACPI_VIDEO_HID; else if (ACPI_SUCCESS(acpi_bay_match(device))) cid_add = ACPI_BAY_HID; @@ -1221,15 +1198,18 @@ result = -ENODEV; goto end; } - if (!device->status.present) { - /* Bay and dock should be handled even if absent */ - if (!ACPI_SUCCESS( - acpi_is_child_device(device, acpi_bay_match)) && - !ACPI_SUCCESS( - acpi_is_child_device(device, acpi_dock_match))) { - result = -ENODEV; - goto end; - } + /* + * When the device is neither present nor functional, the + * device should not be added to Linux ACPI device tree. + * When the status of the device is not present but functinal, + * it should be added to Linux ACPI tree. For example : bay + * device , dock device. + * In such conditions it is unncessary to check whether it is + * bay device or dock device. + */ + if (!device->status.present && !device->status.functional) { + result = -ENODEV; + goto end; } break; default: @@ -1252,6 +1232,16 @@ acpi_device_set_id(device, parent, handle, type); /* + * The ACPI device is attached to acpi handle before getting + * the power/wakeup/peformance flags. Otherwise OS can't get + * the corresponding ACPI device by the acpi handle in the course + * of getting the power/wakeup/performance flags. + */ + result = acpi_device_set_context(device, type); + if (result) + goto end; + + /* * Power Management * ---------------- */ @@ -1281,8 +1271,6 @@ goto end; } - if ((result = acpi_device_set_context(device, type))) - goto end; result = acpi_device_register(device, parent); @@ -1402,7 +1390,12 @@ * TBD: Need notifications and other detection mechanisms * in place before we can fully implement this. */ - if (child->status.present) { + /* + * When the device is not present but functional, it is also + * necessary to scan the children of this device. + */ + if (child->status.present || (!child->status.present && + child->status.functional)) { status = acpi_get_next_object(ACPI_TYPE_ANY, chandle, NULL, NULL); if (ACPI_SUCCESS(status)) { --- linux-2.6.27.orig/drivers/acpi/video.c +++ linux-2.6.27/drivers/acpi/video.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -482,6 +483,7 @@ int status = AE_OK; union acpi_object arg0 = { ACPI_TYPE_INTEGER }; struct acpi_object_list args = { 1, &arg0 }; + int state; arg0.integer.value = level; @@ -490,6 +492,10 @@ status = acpi_evaluate_object(device->dev->handle, "_BCM", &args, NULL); device->brightness->curr = level; + for (state = 2; state < device->brightness->count; state++) + if (level == device->brightness->levels[state]) + device->backlight->props.brightness = state - 2; + return status; } @@ -627,6 +633,16 @@ } /* + * Simple comparison function used to sort backlight levels. + */ + +static int +acpi_video_cmp_level(const void *a, const void *b) +{ + return *(int *)a - *(int *)b; +} + +/* * Arg: * device : video output device (LCD, CRT, ..) * @@ -677,6 +693,10 @@ count++; } + /* don't sort the first two brightness levels */ + sort(&br->levels[2], count - 2, sizeof(br->levels[2]), + acpi_video_cmp_level, NULL); + if (count < 2) goto out_free_levels; @@ -739,7 +759,8 @@ device->cap._DSS = 1; } - max_level = acpi_video_init_brightness(device); + if (acpi_video_backlight_support() & ACPI_VIDEO_BACKLIGHT) + max_level = acpi_video_init_brightness(device); if (device->cap._BCL && device->cap._BCM && max_level > 0) { int result; @@ -785,18 +806,21 @@ printk(KERN_ERR PREFIX "Create sysfs link\n"); } - if (device->cap._DCS && device->cap._DSS){ - static int count = 0; - char *name; - name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); - if (!name) - return; - sprintf(name, "acpi_video%d", count++); - device->output_dev = video_output_register(name, - NULL, device, &acpi_output_properties); - kfree(name); + + if (acpi_video_display_switch_support()) { + + if (device->cap._DCS && device->cap._DSS) { + static int count; + char *name; + name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); + if (!name) + return; + sprintf(name, "acpi_video%d", count++); + device->output_dev = video_output_register(name, + NULL, device, &acpi_output_properties); + kfree(name); + } } - return; } /* @@ -842,11 +866,16 @@ static int acpi_video_bus_check(struct acpi_video_bus *video) { acpi_status status = -ENOENT; - + struct device *dev; if (!video) return -EINVAL; + dev = acpi_get_physical_pci_device(video->device->handle); + if (!dev) + return -ENODEV; + put_device(dev); + /* Since there is no HID, CID and so on for VGA driver, we have * to check well known required nodes. */ @@ -992,7 +1021,7 @@ } seq_printf(seq, "levels: "); - for (i = 0; i < dev->brightness->count; i++) + for (i = 2; i < dev->brightness->count; i++) seq_printf(seq, " %d", dev->brightness->levels[i]); seq_printf(seq, "\ncurrent: %d\n", dev->brightness->curr); @@ -1031,7 +1060,7 @@ return -EFAULT; /* validate through the list of available levels */ - for (i = 0; i < dev->brightness->count; i++) + for (i = 2; i < dev->brightness->count; i++) if (level == dev->brightness->levels[i]) { if (ACPI_SUCCESS (acpi_video_device_lcd_set_level(dev, level))) @@ -1684,7 +1713,7 @@ max = max_below = 0; min = min_above = 255; /* Find closest level to level_current */ - for (i = 0; i < device->brightness->count; i++) { + for (i = 2; i < device->brightness->count; i++) { l = device->brightness->levels[i]; if (abs(l - level_current) < abs(delta)) { delta = l - level_current; @@ -1694,7 +1723,7 @@ } /* Ajust level_current to closest available level */ level_current += delta; - for (i = 0; i < device->brightness->count; i++) { + for (i = 2; i < device->brightness->count; i++) { l = device->brightness->levels[i]; if (l < min) min = l; @@ -1978,6 +2007,12 @@ device->pnp.bus_id[3] = '0' + instance; instance ++; } + /* a hack to fix the duplicate name "VGA" problem on Pa 3553 */ + if (!strcmp(device->pnp.bus_id, "VGA")) { + if (instance) + device->pnp.bus_id[3] = '0' + instance; + instance++; + } video->device = device; strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME); --- linux-2.6.27.orig/drivers/acpi/dock.c +++ linux-2.6.27/drivers/acpi/dock.c @@ -604,14 +604,17 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) { struct dock_station *ds = data; + struct acpi_device *tmp; switch (event) { case ACPI_NOTIFY_BUS_CHECK: - if (!dock_in_progress(ds) && dock_present(ds)) { + if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle, + &tmp)) { begin_dock(ds); dock(ds); if (!dock_present(ds)) { printk(KERN_ERR PREFIX "Unable to dock!\n"); + complete_dock(ds); break; } atomic_notifier_call_chain(&dock_notifier_list, --- linux-2.6.27.orig/drivers/acpi/power.c +++ linux-2.6.27/drivers/acpi/power.c @@ -54,6 +54,14 @@ #define ACPI_POWER_RESOURCE_STATE_OFF 0x00 #define ACPI_POWER_RESOURCE_STATE_ON 0x01 #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF + +#ifdef MODULE_PARAM_PREFIX +#undef MODULE_PARAM_PREFIX +#endif +#define MODULE_PARAM_PREFIX "acpi." +int acpi_power_nocheck; +module_param_named(power_nocheck, acpi_power_nocheck, bool, 000); + static int acpi_power_add(struct acpi_device *device); static int acpi_power_remove(struct acpi_device *device, int type); static int acpi_power_resume(struct acpi_device *device); @@ -226,11 +234,17 @@ if (ACPI_FAILURE(status)) return -ENODEV; - result = acpi_power_get_state(resource, &state); - if (result) - return result; - if (state != ACPI_POWER_RESOURCE_STATE_ON) - return -ENOEXEC; + if (!acpi_power_nocheck) { + /* + * If acpi_power_nocheck is set, it is unnecessary to check + * the power state after power transition. + */ + result = acpi_power_get_state(resource, &state); + if (result) + return result; + if (state != ACPI_POWER_RESOURCE_STATE_ON) + return -ENOEXEC; + } /* Update the power resource's _device_ power state */ resource->device->power.state = ACPI_STATE_D0; @@ -277,11 +291,18 @@ if (ACPI_FAILURE(status)) return -ENODEV; - result = acpi_power_get_state(resource, &state); - if (result) - return result; - if (state != ACPI_POWER_RESOURCE_STATE_OFF) - return -ENOEXEC; + if (!acpi_power_nocheck) { + /* + * If acpi_power_nocheck is set, it is unnecessary to check + * the power state after power transition. + */ + result = acpi_power_get_state(resource, &state); + if (result) + return result; + if (state != ACPI_POWER_RESOURCE_STATE_OFF) + return -ENOEXEC; + } + /* Update the power resource's _device_ power state */ resource->device->power.state = ACPI_STATE_D3; --- linux-2.6.27.orig/drivers/acpi/button.c +++ linux-2.6.27/drivers/acpi/button.c @@ -262,6 +262,7 @@ return -ENODEV; /* input layer checks if event is redundant */ input_report_switch(button->input, SW_LID, !state); + input_sync(button->input); return 0; } @@ -285,8 +286,8 @@ input_report_key(input, keycode, 1); input_sync(input); input_report_key(input, keycode, 0); + input_sync(input); } - input_sync(input); acpi_bus_generate_proc_event(button->device, event, ++button->pushed); --- linux-2.6.27.orig/drivers/acpi/tables.c +++ linux-2.6.27/drivers/acpi/tables.c @@ -293,7 +293,12 @@ int __init acpi_table_init(void) { - acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); + acpi_status status; + + status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); + if (ACPI_FAILURE(status)) + return 1; + check_multiple_madt(); return 0; } --- linux-2.6.27.orig/drivers/acpi/glue.c +++ linux-2.6.27/drivers/acpi/glue.c @@ -140,6 +140,46 @@ EXPORT_SYMBOL(acpi_get_physical_device); +/* ToDo: When a PCI bridge is found, return the PCI device behind the bridge + * This should work in general, but did not on a Lenovo T61 for the + * graphics card. But this must be fixed when the PCI device is + * bound and the kernel device struct is attached to the acpi device + * Note: A success call will increase reference count by one + * Do call put_device(dev) on the returned device then + */ +struct device *acpi_get_physical_pci_device(acpi_handle handle) +{ + struct device *dev; + long long device_id; + acpi_status status; + + status = + acpi_evaluate_integer(handle, "_ADR", NULL, &device_id); + + if (ACPI_FAILURE(status)) + return NULL; + + /* We need to attempt to determine whether the _ADR refers to a + PCI device or not. There's no terribly good way to do this, + so the best we can hope for is to assume that there'll never + be a device in the host bridge */ + if (device_id >= 0x10000) { + /* It looks like a PCI device. Does it exist? */ + dev = acpi_get_physical_device(handle); + } else { + /* It doesn't look like a PCI device. Does its parent + exist? */ + acpi_handle phandle; + if (acpi_get_parent(handle, &phandle)) + return NULL; + dev = acpi_get_physical_device(phandle); + } + if (!dev) + return NULL; + return dev; +} +EXPORT_SYMBOL(acpi_get_physical_pci_device); + static int acpi_bind_one(struct device *dev, acpi_handle handle) { struct acpi_device *acpi_dev; --- linux-2.6.27.orig/drivers/acpi/toshiba_acpi.c +++ linux-2.6.27/drivers/acpi/toshiba_acpi.c @@ -27,13 +27,28 @@ * engineering the Windows drivers * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5 * Rob Miller - TV out and hotkeys help + * Daniel Silverstone - Punting of hotkeys via acpi using a thread * + * PLEASE NOTE + * + * This is an experimental version of toshiba_acpi which includes emulation + * of the original toshiba driver's /proc/toshiba and /dev/toshiba, + * allowing Toshiba userspace utilities to work. The relevant code was + * based on toshiba.c (copyright 1996-2001 Jonathan A. Buzzard) and + * incorporated into this driver with help from Gintautas Miliauskas, + * Charles Schwieters, and Christoph Burger-Scheidlin. + * + * Caveats: + * * hotkey status in /proc/toshiba is not implemented + * * to make accesses to /dev/toshiba load this driver instead of + * the original driver, you will have to modify your module + * auto-loading configuration * * TODO * */ -#define TOSHIBA_ACPI_VERSION "0.18" +#define TOSHIBA_ACPI_VERSION "0.19a-dev" #define PROC_INTERFACE_VERSION 1 #include @@ -41,12 +56,33 @@ #include #include #include +#include +#include +#include +#include +#include #include - +#include +#include #include #include +/* Some compatibility for isa legacy interface */ +#ifndef isa_readb + +#define isa_readb(a) readb(__ISA_IO_base + (a)) +#define isa_readw(a) readw(__ISA_IO_base + (a)) +#define isa_readl(a) readl(__ISA_IO_base + (a)) +#define isa_writeb(b,a) writeb(b,__ISA_IO_base + (a)) +#define isa_writew(w,a) writew(w,__ISA_IO_base + (a)) +#define isa_writel(l,a) writel(l,__ISA_IO_base + (a)) +#define isa_memset_io(a,b,c) memset_io(__ISA_IO_base + (a),(b),(c)) +#define isa_memcpy_fromio(a,b,c) memcpy_fromio((a),__ISA_IO_base + (b),(c)) +#define isa_memcpy_toio(a,b,c) memcpy_toio(__ISA_IO_base + (a),(b),(c)) + +#endif + MODULE_AUTHOR("John Belmonte"); MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); MODULE_LICENSE("GPL"); @@ -223,6 +259,11 @@ static int force_fan; static int last_key_event; static int key_event_valid; +static int hotkeys_over_acpi = 1; +static int hotkeys_check_per_sec = 2; + +module_param(hotkeys_over_acpi, uint, 0400); +module_param(hotkeys_check_per_sec, uint, 0400); typedef struct _ProcItem { const char *name; @@ -450,27 +491,34 @@ u32 hci_result; u32 value; - if (!key_event_valid) { - hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result); - if (hci_result == HCI_SUCCESS) { - key_event_valid = 1; - last_key_event = value; - } else if (hci_result == HCI_EMPTY) { - /* better luck next time */ - } else if (hci_result == HCI_NOT_SUPPORTED) { - /* This is a workaround for an unresolved issue on - * some machines where system events sporadically - * become disabled. */ - hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result); - printk(MY_NOTICE "Re-enabled hotkeys\n"); - } else { - printk(MY_ERR "Error reading hotkey status\n"); - goto end; + if (!hotkeys_over_acpi) { + if (!key_event_valid) { + hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result); + if (hci_result == HCI_SUCCESS) { + key_event_valid = 1; + last_key_event = value; + } else if (hci_result == HCI_EMPTY) { + /* better luck next time */ + } else if (hci_result == HCI_NOT_SUPPORTED) { + /* This is a workaround for an + * unresolved issue on some machines + * where system events sporadically + * become disabled. */ + hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result); + printk(MY_NOTICE "Re-enabled hotkeys\n"); + } else { + printk(MY_ERR "Error reading hotkey status\n"); + goto end; + } } + } else { + key_event_valid = 0; + last_key_event = 0; } p += sprintf(p, "hotkey_ready: %d\n", key_event_valid); p += sprintf(p, "hotkey: 0x%04x\n", last_key_event); + p += sprintf(p, "hotkeys_via_acpi: %d\n", hotkeys_over_acpi); end: return p; @@ -497,6 +545,190 @@ return p; } +/* /dev/toshiba and /proc/toshiba handlers {{{ + * + * ISSUE: lots of magic numbers and mysterious code + */ + +#define TOSH_MINOR_DEV 181 +#define OLD_PROC_TOSHIBA "toshiba" + +static int +tosh_acpi_bridge(SMMRegisters* regs) +{ + acpi_status status; + + /* assert(sizeof(SMMRegisters) == sizeof(u32)*HCI_WORDS); */ + status = hci_raw((u32*)regs, (u32*)regs); + if (status == AE_OK && (regs->eax & 0xff00) == HCI_SUCCESS) + return 0; + + return -EINVAL; +} + +static int +tosh_ioctl(struct inode* ip, struct file* fp, unsigned int cmd, + unsigned long arg) +{ + SMMRegisters regs; + unsigned short ax,bx; + int err; + + if ((!arg) || (cmd != TOSH_SMM)) + return -EINVAL; + + if (copy_from_user(®s, (SMMRegisters*)arg, sizeof(SMMRegisters))) + return -EFAULT; + + ax = regs.eax & 0xff00; + bx = regs.ebx & 0xffff; + + /* block HCI calls to read/write memory & PCI devices */ + if (((ax==HCI_SET) || (ax==HCI_GET)) && (bx>0x0069)) + return -EINVAL; + + err = tosh_acpi_bridge(®s); + + if (copy_to_user((SMMRegisters*)arg, ®s, sizeof(SMMRegisters))) + return -EFAULT; + + return err; +} + +static int +tosh_get_machine_id(void) +{ + int id; + unsigned short bx,cx; + unsigned long address; + + id = (0x100*(int)isa_readb(0xffffe))+((int)isa_readb(0xffffa)); + + /* do we have a SCTTable machine identication number on our hands */ + if (id==0xfc2f) { + bx = 0xe6f5; /* cheat */ + /* now twiddle with our pointer a bit */ + address = 0x000f0000+bx; + cx = isa_readw(address); + address = 0x000f0009+bx+cx; + cx = isa_readw(address); + address = 0x000f000a+cx; + cx = isa_readw(address); + /* now construct our machine identification number */ + id = ((cx & 0xff)<<8)+((cx & 0xff00)>>8); + } + + return id; +} + +static int tosh_id; +static int tosh_bios; +static int tosh_date; +static int tosh_sci; + +static struct file_operations tosh_fops = { + .owner = THIS_MODULE, + .ioctl = tosh_ioctl +}; + +static struct miscdevice tosh_device = { + TOSH_MINOR_DEV, + "toshiba", + &tosh_fops +}; + +static void +setup_tosh_info(void __iomem *bios) +{ + int major, minor; + int day, month, year; + + tosh_id = tosh_get_machine_id(); + + /* get the BIOS version */ + major = isa_readb(0xfe009)-'0'; + minor = ((isa_readb(0xfe00b)-'0')*10)+(isa_readb(0xfe00c)-'0'); + tosh_bios = (major*0x100)+minor; + + /* get the BIOS date */ + day = ((isa_readb(0xffff5)-'0')*10)+(isa_readb(0xffff6)-'0'); + month = ((isa_readb(0xffff8)-'0')*10)+(isa_readb(0xffff9)-'0'); + year = ((isa_readb(0xffffb)-'0')*10)+(isa_readb(0xffffc)-'0'); + tosh_date = (((year-90) & 0x1f)<<10) | ((month & 0xf)<<6) + | ((day & 0x1f)<<1); +} + +/* /proc/toshiba read handler */ +static int +old_toshiba_proc_show(struct seq_file *m, void *v) +{ + /* TODO: tosh_fn_status() */ + int key = 0; + + /* Format: + * 0) Linux driver version (this will change if format changes) + * 1) Machine ID + * 2) SCI version + * 3) BIOS version (major, minor) + * 4) BIOS date (in SCI date format) + * 5) Fn Key status + */ + seq_printf(m, "1.1 0x%04x %d.%d %d.%d 0x%04x 0x%02x\n", + tosh_id, + (tosh_sci & 0xff00)>>8, + tosh_sci & 0xff, + (tosh_bios & 0xff00)>>8, + tosh_bios & 0xff, + tosh_date, + key); + + return 0; +} + +static int old_toshiba_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, old_toshiba_proc_show, NULL); +} + +static const struct file_operations old_toshiba_proc_fops = { + .owner = THIS_MODULE, + .open = old_toshiba_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init +old_driver_emulation_init(void) +{ + int status; + void __iomem *bios = ioremap(0xf0000, 0x10000); + if (!bios) + return -ENOMEM; + + if ((status = misc_register(&tosh_device))) { + printk(MY_ERR "failed to register misc device %d (\"%s\")\n", + tosh_device.minor, tosh_device.name); + return status; + } + + setup_tosh_info(bios); + proc_create(OLD_PROC_TOSHIBA, 0, NULL, &old_toshiba_proc_fops); + + iounmap(bios); + + return 0; +} + +static void __exit +old_driver_emulation_exit(void) +{ + remove_proc_entry(OLD_PROC_TOSHIBA, NULL); + misc_deregister(&tosh_device); +} + +/* }}} end of /dev/toshiba and /proc/toshiba handlers */ + /* proc and module init */ @@ -545,16 +777,151 @@ .update_status = set_lcd_status, }; +static struct semaphore thread_sem; +static int thread_should_die; + +static struct acpi_device *threaded_device = 0; + +static void thread_deliver_button_event(u32 value) +{ + if (!threaded_device) return; + if( value == 0x0100 ) { + /* Ignore FN on its own */ + } else if( value & 0x80 ) { + acpi_bus_generate_proc_event( threaded_device, 1, value & ~0x80 ); + } else { + acpi_bus_generate_proc_event( threaded_device, 0, value ); + } +} + +static int toshiba_acpi_thread(void *data) +{ + int dropped = 0; + u32 hci_result, value; + + daemonize("ktoshkeyd"); + set_user_nice(current, 4); + thread_should_die = 0; + + up(&thread_sem); + + do { + /* In case we get stuck; we can rmmod the module here */ + if (thread_should_die) + break; + + hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result); + if (hci_result == HCI_SUCCESS) { + dropped++; + } else if (hci_result == HCI_EMPTY) { + /* better luck next time */ + } else if (hci_result == HCI_NOT_SUPPORTED) { + /* This is a workaround for an unresolved issue on + * some machines where system events sporadically + * become disabled. */ + hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result); + printk(MY_NOTICE "Re-enabled hotkeys\n"); + } + } while (hci_result != HCI_EMPTY); + + printk(MY_INFO "Dropped %d keys from the queue on startup\n", dropped); + + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / hotkeys_check_per_sec); + + if (thread_should_die) + break; + + if (try_to_freeze()) + continue; + + do { + hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result); + if (hci_result == HCI_SUCCESS) { + thread_deliver_button_event(value); + } else if (hci_result == HCI_EMPTY) { + /* better luck next time */ + } else if (hci_result == HCI_NOT_SUPPORTED) { + /* This is a workaround for an + * unresolved issue on some machines + * where system events sporadically + * become disabled. */ + hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result); + printk(MY_NOTICE "Re-enabled hotkeys\n"); + } + } while (hci_result == HCI_SUCCESS); + } + set_user_nice(current, -20); /* Become nasty so we are cleaned up + * before the module exits making us oops */ + up(&thread_sem); + return 0; +} + +static int acpi_toshkeys_add (struct acpi_device *device) +{ + threaded_device = device; + strcpy(acpi_device_name(device), "Toshiba laptop hotkeys"); + strcpy(acpi_device_class(device), "hkey"); + return 0; +} + +static int acpi_toshkeys_remove (struct acpi_device *device, int type) +{ + if (threaded_device == device) + threaded_device = 0; + return 0; +} + +static const struct acpi_device_id acpi_toshkeys_ids[] = { + { "TOS6200", 0 }, + { "TOS6207", 0 }, + { "TOS6208", 0 }, + {"", 0} +}; + +static struct acpi_driver acpi_threaded_toshkeys = { + .name = "Toshiba laptop hotkeys driver", + .class = "hkey", + .ids = acpi_toshkeys_ids, + .ops = { + .add = acpi_toshkeys_add, + .remove = acpi_toshkeys_remove, + }, +}; + +static int __init init_threaded_acpi(void) +{ + acpi_status result = AE_OK; + result = acpi_bus_register_driver(&acpi_threaded_toshkeys); + if( result < 0 ) + printk(MY_ERR "Registration of toshkeys acpi device failed\n"); + return result; +} + +static void kill_threaded_acpi(void) +{ + acpi_bus_unregister_driver(&acpi_threaded_toshkeys); +} + static void toshiba_acpi_exit(void) { if (toshiba_backlight_device) backlight_device_unregister(toshiba_backlight_device); + if (hotkeys_over_acpi) { + thread_should_die = 1; + down(&thread_sem); + kill_threaded_acpi(); + } + remove_device(); if (toshiba_proc_dir) remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); + old_driver_emulation_exit(); + return; } @@ -562,6 +929,7 @@ { acpi_status status = AE_OK; u32 hci_result; + int status2; if (acpi_disabled) return -ENODEV; @@ -578,6 +946,9 @@ TOSHIBA_ACPI_VERSION); printk(MY_INFO " HCI method: %s\n", method_hci); + if ((status2 = old_driver_emulation_init())) + return status2; + force_fan = 0; key_event_valid = 0; @@ -605,7 +976,27 @@ toshiba_acpi_exit(); return ret; } - toshiba_backlight_device->props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; + toshiba_backlight_device->props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; + + if (hotkeys_over_acpi && ACPI_SUCCESS(status)) { + printk(MY_INFO "Toshiba hotkeys are sent as ACPI events\n"); + if (hotkeys_check_per_sec < 1) + hotkeys_check_per_sec = 1; + if (hotkeys_check_per_sec > 10) + hotkeys_check_per_sec = 10; + printk(MY_INFO "ktoshkeyd will check %d time%s per second\n", + hotkeys_check_per_sec, hotkeys_check_per_sec==1?"":"s"); + if (init_threaded_acpi() >= 0) { + init_MUTEX_LOCKED(&thread_sem); + kernel_thread(toshiba_acpi_thread, NULL, CLONE_KERNEL); + down(&thread_sem); + } else { + remove_device(); + remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); + status = AE_ERROR; + printk(MY_INFO "ktoshkeyd initialisation failed. Refusing to load module\n"); + } + } return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; } --- linux-2.6.27.orig/drivers/acpi/Kconfig +++ linux-2.6.27/drivers/acpi/Kconfig @@ -301,6 +301,17 @@ bool default ACPI_CUSTOM_DSDT_FILE != "" +config ACPI_CUSTOM_DSDT_INITRD + bool "Read Custom DSDT from initramfs" + depends on BLK_DEV_INITRD + default n + help + This option supports a custom DSDT by optionally loading it from initrd. + See Documentation/acpi/dsdt-override.txt + + If you are not using this feature now, but may use it later, + it is safe to say Y here. + config ACPI_BLACKLIST_YEAR int "Disable ACPI for systems before Jan 1st this year" if X86_32 default 0 --- linux-2.6.27.orig/drivers/acpi/pci_link.c +++ linux-2.6.27/drivers/acpi/pci_link.c @@ -796,10 +796,6 @@ struct list_head *node = NULL; struct acpi_pci_link *link = NULL; - - /* Make sure SCI is enabled again (Apple firmware bug?) */ - acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1); - list_for_each(node, &acpi_link.entries) { link = list_entry(node, struct acpi_pci_link, node); if (!link) { --- linux-2.6.27.orig/drivers/acpi/battery.c +++ linux-2.6.27/drivers/acpi/battery.c @@ -472,7 +472,7 @@ static int acpi_battery_update(struct acpi_battery *battery) { - int result; + int result, old_present = acpi_battery_present(battery); result = acpi_battery_get_status(battery); if (result) return result; @@ -483,7 +483,8 @@ return 0; } #endif - if (!battery->update_time) { + if (!battery->update_time || + old_present != acpi_battery_present(battery)) { result = acpi_battery_get_info(battery); if (result) return result; --- linux-2.6.27.orig/drivers/acpi/reboot.c +++ linux-2.6.27/drivers/acpi/reboot.c @@ -15,9 +15,28 @@ rr = &acpi_gbl_FADT.reset_register; - /* Is the reset register supported? */ - if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) || - rr->bit_width != 8 || rr->bit_offset != 0) + /* + * Is the ACPI reset register supported? + * + * According to ACPI 3.0, FADT.flags.RESET_REG_SUP indicates + * whether the ACPI reset mechanism is supported. + * + * However, some boxes have this bit clear, yet a valid + * ACPI_RESET_REG & RESET_VALUE, and ACPI reboot is the only + * mechanism that works for them after S3. + * + * This suggests that other operating systems may not be checking + * the RESET_REG_SUP bit, and are using other means to decide + * whether to use the ACPI reboot mechanism or not. + * + * So when acpi reboot is requested, + * only the reset_register is checked. If the following + * conditions are met, it indicates that the reset register is supported. + * a. reset_register is not zero + * b. the access width is eight + * c. the bit_offset is zero + */ + if (!(rr->address) || rr->bit_width != 8 || rr->bit_offset != 0) return; reset_value = acpi_gbl_FADT.reset_value; --- linux-2.6.27.orig/drivers/acpi/system.c +++ linux-2.6.27/drivers/acpi/system.c @@ -78,9 +78,15 @@ container_of(bin_attr, struct acpi_table_attr, attr); struct acpi_table_header *table_header = NULL; acpi_status status; + char name[ACPI_NAME_SIZE]; + + if (strncmp(table_attr->name, "NULL", 4)) + memcpy(name, table_attr->name, ACPI_NAME_SIZE); + else + memcpy(name, "\0\0\0\0", 4); status = - acpi_get_table(table_attr->name, table_attr->instance, + acpi_get_table(name, table_attr->instance, &table_header); if (ACPI_FAILURE(status)) return -ENODEV; @@ -95,21 +101,24 @@ struct acpi_table_header *header = NULL; struct acpi_table_attr *attr = NULL; - memcpy(table_attr->name, table_header->signature, ACPI_NAME_SIZE); + if (table_header->signature[0] != '\0') + memcpy(table_attr->name, table_header->signature, + ACPI_NAME_SIZE); + else + memcpy(table_attr->name, "NULL", 4); list_for_each_entry(attr, &acpi_table_attr_list, node) { - if (!memcmp(table_header->signature, attr->name, - ACPI_NAME_SIZE)) + if (!memcmp(table_attr->name, attr->name, ACPI_NAME_SIZE)) if (table_attr->instance < attr->instance) table_attr->instance = attr->instance; } table_attr->instance++; if (table_attr->instance > 1 || (table_attr->instance == 1 && - !acpi_get_table(table_header-> - signature, 2, - &header))) - sprintf(table_attr->name + 4, "%d", table_attr->instance); + !acpi_get_table + (table_header->signature, 2, &header))) + sprintf(table_attr->name + ACPI_NAME_SIZE, "%d", + table_attr->instance); table_attr->attr.size = 0; table_attr->attr.read = acpi_table_show; --- linux-2.6.27.orig/drivers/acpi/Makefile +++ linux-2.6.27/drivers/acpi/Makefile @@ -47,6 +47,10 @@ obj-$(CONFIG_ACPI_DOCK) += dock.o obj-$(CONFIG_ACPI_BAY) += bay.o obj-$(CONFIG_ACPI_VIDEO) += video.o +ifdef CONFIG_ACPI_VIDEO +obj-y += video_detect.o +endif + obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o obj-$(CONFIG_ACPI_POWER) += power.o --- linux-2.6.27.orig/drivers/acpi/video_detect.c +++ linux-2.6.27/drivers/acpi/video_detect.c @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2008 SuSE Linux Products GmbH + * Thomas Renninger + * + * May be copied or modified under the terms of the GNU General Public License + * + * video_detect.c: + * Provides acpi_is_video_device() for early scanning of ACPI devices in scan.c + * There a Linux specific (Spec does not provide a HID for video devices) is + * assinged + * + * After PCI devices are glued with ACPI devices + * acpi_get_physical_pci_device() can be called to identify ACPI graphics + * devices for which a real graphics card is plugged in + * + * Now acpi_video_get_capabilities() can be called to check which + * capabilities the graphics cards plugged in support. The check for general + * video capabilities will be triggered by the first caller of + * acpi_video_get_capabilities(NULL); which will happen when the first + * backlight (or display output) switching supporting driver calls: + * acpi_video_backlight_support(); + * + * Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B) + * are available, video.ko should be used to handle the device. + * + * Otherwise vendor specific drivers like thinkpad_acpi, asus_acpi, + * sony_acpi,... can take care about backlight brightness and display output + * switching. + * + * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m) + * this file will not be compiled, acpi_video_get_capabilities() and + * acpi_video_backlight_support() will always return 0 and vendor specific + * drivers always can handle backlight. + * + */ + +#include +#include + +ACPI_MODULE_NAME("video"); +#define ACPI_VIDEO_COMPONENT 0x08000000 +#define _COMPONENT ACPI_VIDEO_COMPONENT + +static long acpi_video_support; +static bool acpi_video_caps_checked; + +static acpi_status +acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context, + void **retyurn_value) +{ + long *cap = context; + acpi_handle h_dummy; + + if (ACPI_SUCCESS(acpi_get_handle(handle, "_BCM", &h_dummy)) && + ACPI_SUCCESS(acpi_get_handle(handle, "_BCL", &h_dummy))) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight " + "support\n")); + *cap |= ACPI_VIDEO_BACKLIGHT; + /* We have backlight support, no need to scan further */ + return AE_CTRL_TERMINATE; + } + return 0; +} + +/* Returns true if the device is a video device which can be handled by + * video.ko. + * The device will get a Linux specific CID added in scan.c to + * identify the device as an ACPI graphics device + * Be aware that the graphics device may not be physically present + * Use acpi_video_get_capabilities() to detect general ACPI video + * capabilities of present cards + */ +long acpi_is_video_device(struct acpi_device *device) +{ + acpi_handle h_dummy; + long video_caps = 0; + + if (!device) + return 0; + + /* Does this device able to support video switching ? */ + if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) && + ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy))) + video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING; + + /* Does this device able to retrieve a video ROM ? */ + if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy))) + video_caps |= ACPI_VIDEO_ROM_AVAILABLE; + + /* Does this device able to configure which video head to be POSTed ? */ + if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) && + ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) && + ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy))) + video_caps |= ACPI_VIDEO_DEVICE_POSTING; + + /* Only check for backlight functionality if one of the above hit. */ + if (video_caps) + acpi_walk_namespace(ACPI_TYPE_DEVICE, device->handle, + ACPI_UINT32_MAX, acpi_backlight_cap_match, + &video_caps, NULL); + + return video_caps; +} +EXPORT_SYMBOL(acpi_is_video_device); + +static acpi_status +find_video(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + long *cap = context; + struct device *dev; + struct acpi_device *acpi_dev; + + const struct acpi_device_id video_ids[] = { + {ACPI_VIDEO_HID, 0}, + {"", 0}, + }; + if (acpi_bus_get_device(handle, &acpi_dev)) + return AE_OK; + + if (!acpi_match_device_ids(acpi_dev, video_ids)) { + dev = acpi_get_physical_pci_device(handle); + if (!dev) + return AE_OK; + put_device(dev); + *cap |= acpi_is_video_device(acpi_dev); + } + return AE_OK; +} + +/* + * Returns the video capabilities of a specific ACPI graphics device + * + * if NULL is passed as argument all ACPI devices are enumerated and + * all graphics capabilities of physically present devices are + * summerized and returned. This is cached and done only once. + */ +long acpi_video_get_capabilities(acpi_handle graphics_handle) +{ + long caps = 0; + struct acpi_device *tmp_dev; + acpi_status status; + + if (acpi_video_caps_checked && graphics_handle == NULL) + return acpi_video_support; + + if (!graphics_handle) { + /* Only do the global walk through all graphics devices once */ + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, find_video, + &caps, NULL); + /* There might be boot param flags set already... */ + acpi_video_support |= caps; + acpi_video_caps_checked = 1; + /* Add blacklists here. Be careful to use the right *DMI* bits + * to still be able to override logic via boot params, e.g.: + * + * if (dmi_name_in_vendors("XY")) { + * acpi_video_support |= + * ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR; + * acpi_video_support |= + * ACPI_VIDEO_BACKLIGHT_DMI_VENDOR; + *} + */ + } else { + status = acpi_bus_get_device(graphics_handle, &tmp_dev); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Invalid device")); + return 0; + } + acpi_walk_namespace(ACPI_TYPE_DEVICE, graphics_handle, + ACPI_UINT32_MAX, find_video, + &caps, NULL); + } + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "We have 0x%lX video support %s %s\n", + graphics_handle ? caps : acpi_video_support, + graphics_handle ? "on device " : "in general", + graphics_handle ? acpi_device_bid(tmp_dev) : "")); + return caps; +} +EXPORT_SYMBOL(acpi_video_get_capabilities); + +/* + * Temporary hack to enable a default of "both" which seemed to be true + * before. (LP#311716) + * Returns the bits ACPI_VIDEO_BACKLIGHT and/or + * ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR set to indicate which support should + * get activated. + */ +int acpi_video_backlight_support(void) +{ + /* + * We must check whether the ACPI graphics device is physically plugged + * in. Therefore this must be called after binding PCI and ACPI devices + */ + if (!acpi_video_caps_checked) + acpi_video_get_capabilities(NULL); + + /* First check for boot param -> highest prio */ + if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR) + return ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR; + else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO) + return ACPI_VIDEO_BACKLIGHT; + + /* Then check for DMI blacklist -> second highest prio */ + if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VENDOR) + return ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR; + else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VIDEO) + return ACPI_VIDEO_BACKLIGHT; + + /* Then go the default way */ + return (acpi_video_support & ACPI_VIDEO_BACKLIGHT) | + ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR; +} +EXPORT_SYMBOL(acpi_video_backlight_support); + +/* + * Returns true if video.ko can do display output switching. + * This does not work well/at all with binary graphics drivers + * which disable system io ranges and do it on their own. + */ +int acpi_video_display_switch_support(void) +{ + if (!acpi_video_caps_checked) + acpi_video_get_capabilities(NULL); + + if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR) + return 0; + else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO) + return 1; + + if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR) + return 0; + else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO) + return 1; + + return acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING; +} +EXPORT_SYMBOL(acpi_video_display_switch_support); + +/* + * Use acpi_display_output=vendor/video or acpi_backlight=vendor/video + * To force that backlight or display output switching is processed by vendor + * specific acpi drivers or video.ko driver. + */ +int __init acpi_backlight(char *str) +{ + if (str == NULL || *str == '\0') + return 1; + else { + if (!strcmp("vendor", str)) + acpi_video_support |= + ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR; + if (!strcmp("video", str)) + acpi_video_support |= + ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO; + } + return 1; +} +__setup("acpi_backlight=", acpi_backlight); + +int __init acpi_display_output(char *str) +{ + if (str == NULL || *str == '\0') + return 1; + else { + if (!strcmp("vendor", str)) + acpi_video_support |= + ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR; + if (!strcmp("video", str)) + acpi_video_support |= + ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO; + } + return 1; +} +__setup("acpi_display_output=", acpi_display_output); --- linux-2.6.27.orig/drivers/acpi/ec.c +++ linux-2.6.27/drivers/acpi/ec.c @@ -1,7 +1,7 @@ /* - * ec.c - ACPI Embedded Controller Driver (v2.0) + * ec.c - ACPI Embedded Controller Driver (v2.1) * - * Copyright (C) 2006, 2007 Alexey Starikovskiy + * Copyright (C) 2006-2008 Alexey Starikovskiy * Copyright (C) 2006 Denis Sadykov * Copyright (C) 2004 Luming Yu * Copyright (C) 2001, 2002 Andy Grover @@ -26,7 +26,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -/* Uncomment next line to get verbose print outs*/ +/* Uncomment next line to get verbose printout */ /* #define DEBUG */ #include @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -65,22 +66,21 @@ ACPI_EC_COMMAND_QUERY = 0x84, }; -/* EC events */ -enum ec_event { - ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */ - ACPI_EC_EVENT_IBF_0, /* Input buffer empty */ -}; - #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ #define ACPI_EC_UDELAY 100 /* Wait 100us before polling EC again */ +#define ACPI_EC_STORM_THRESHOLD 8 /* number of false interrupts + per one transaction */ + enum { - EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */ EC_FLAGS_QUERY_PENDING, /* Query is pending */ - EC_FLAGS_GPE_MODE, /* Expect GPE to be sent for status change */ + EC_FLAGS_GPE_MODE, /* Expect GPE to be sent + * for status change */ EC_FLAGS_NO_GPE, /* Don't use GPE mode */ - EC_FLAGS_RESCHEDULE_POLL /* Re-schedule poll */ + EC_FLAGS_GPE_STORM, /* GPE storm detected */ + EC_FLAGS_HANDLERS_INSTALLED /* Handlers for GPE and + * OpReg are installed */ }; /* If we find an EC via the ECDT, we need to keep a ptr to its context */ @@ -95,6 +95,18 @@ u8 query_bit; }; +struct transaction { + const u8 *wdata; + u8 *rdata; + unsigned short irq_count; + u8 command; + u8 wi; + u8 ri; + u8 wlen; + u8 rlen; + bool done; +}; + static struct acpi_ec { acpi_handle handle; unsigned long gpe; @@ -105,9 +117,8 @@ struct mutex lock; wait_queue_head_t wait; struct list_head list; - struct delayed_work work; - atomic_t irq_count; - u8 handlers_installed; + struct transaction *curr; + spinlock_t curr_lock; } *boot_ec, *first_ec; /* @@ -150,7 +161,7 @@ { u8 x = inb(ec->data_addr); pr_debug(PREFIX "---> data = 0x%2.2x\n", x); - return inb(ec->data_addr); + return x; } static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) @@ -165,158 +176,193 @@ outb(data, ec->data_addr); } -static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event) +static int ec_transaction_done(struct acpi_ec *ec) { - if (test_bit(EC_FLAGS_WAIT_GPE, &ec->flags)) - return 0; - if (event == ACPI_EC_EVENT_OBF_1) { - if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF) - return 1; - } else if (event == ACPI_EC_EVENT_IBF_0) { - if (!(acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)) - return 1; - } + unsigned long flags; + int ret = 0; + spin_lock_irqsave(&ec->curr_lock, flags); + if (!ec->curr || ec->curr->done) + ret = 1; + spin_unlock_irqrestore(&ec->curr_lock, flags); + return ret; +} - return 0; +static void start_transaction(struct acpi_ec *ec) +{ + ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0; + ec->curr->done = false; + acpi_ec_write_cmd(ec, ec->curr->command); } -static void ec_schedule_ec_poll(struct acpi_ec *ec) +static void gpe_transaction(struct acpi_ec *ec, u8 status) { - if (test_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags)) - schedule_delayed_work(&ec->work, - msecs_to_jiffies(ACPI_EC_DELAY)); + unsigned long flags; + spin_lock_irqsave(&ec->curr_lock, flags); + if (!ec->curr) + goto unlock; + if (ec->curr->wlen > ec->curr->wi) { + if ((status & ACPI_EC_FLAG_IBF) == 0) + acpi_ec_write_data(ec, + ec->curr->wdata[ec->curr->wi++]); + else + goto err; + } else if (ec->curr->rlen > ec->curr->ri) { + if ((status & ACPI_EC_FLAG_OBF) == 1) { + ec->curr->rdata[ec->curr->ri++] = acpi_ec_read_data(ec); + if (ec->curr->rlen == ec->curr->ri) + ec->curr->done = true; + } else + goto err; + } else if (ec->curr->wlen == ec->curr->wi && + (status & ACPI_EC_FLAG_IBF) == 0) + ec->curr->done = true; + goto unlock; +err: + /* false interrupt, state didn't change */ + if (in_interrupt()) + ++ec->curr->irq_count; +unlock: + spin_unlock_irqrestore(&ec->curr_lock, flags); } -static void ec_switch_to_poll_mode(struct acpi_ec *ec) +static int acpi_ec_wait(struct acpi_ec *ec) { + if (wait_event_timeout(ec->wait, ec_transaction_done(ec), + msecs_to_jiffies(ACPI_EC_DELAY))) + return 0; + /* try restart command if we get any false interrupts */ + if (ec->curr->irq_count && + (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) { + pr_debug(PREFIX "controller reset, restart transaction\n"); + start_transaction(ec); + if (wait_event_timeout(ec->wait, ec_transaction_done(ec), + msecs_to_jiffies(ACPI_EC_DELAY))) + return 0; + } + /* missing GPEs, switch back to poll mode */ + if (printk_ratelimit()) + pr_info(PREFIX "missing confirmations, " + "switch off interrupt mode.\n"); set_bit(EC_FLAGS_NO_GPE, &ec->flags); clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); - acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); - set_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); + return 1; } -static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) +static void acpi_ec_gpe_query(void *ec_cxt); + +static int ec_check_sci(struct acpi_ec *ec, u8 state) { - atomic_set(&ec->irq_count, 0); - if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) && - likely(!force_poll)) { - if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event), - msecs_to_jiffies(ACPI_EC_DELAY))) - return 0; - clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); - if (acpi_ec_check_status(ec, event)) { - /* missing GPEs, switch back to poll mode */ - if (printk_ratelimit()) - pr_info(PREFIX "missing confirmations, " - "switch off interrupt mode.\n"); - ec_switch_to_poll_mode(ec); - ec_schedule_ec_poll(ec); - return 0; - } - } else { - unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); - clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); - while (time_before(jiffies, delay)) { - if (acpi_ec_check_status(ec, event)) - return 0; - msleep(1); - } - if (acpi_ec_check_status(ec,event)) + if (state & ACPI_EC_FLAG_SCI) { + if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) + return acpi_os_execute(OSL_EC_BURST_HANDLER, + acpi_ec_gpe_query, ec); + } + return 0; +} + +static int ec_poll(struct acpi_ec *ec) +{ + unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); + udelay(ACPI_EC_UDELAY); + while (time_before(jiffies, delay)) { + gpe_transaction(ec, acpi_ec_read_status(ec)); + udelay(ACPI_EC_UDELAY); + if (ec_transaction_done(ec)) return 0; } - pr_err(PREFIX "acpi_ec_wait timeout, status = 0x%2.2x, event = %s\n", - acpi_ec_read_status(ec), - (event == ACPI_EC_EVENT_OBF_1) ? "\"b0=1\"" : "\"b1=0\""); return -ETIME; } -static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, - const u8 * wdata, unsigned wdata_len, - u8 * rdata, unsigned rdata_len, +static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, + struct transaction *t, int force_poll) { - int result = 0; - set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); + unsigned long tmp; + int ret = 0; pr_debug(PREFIX "transaction start\n"); - acpi_ec_write_cmd(ec, command); - for (; wdata_len > 0; --wdata_len) { - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); - if (result) { - pr_err(PREFIX - "write_cmd timeout, command = %d\n", command); - goto end; - } - set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); - acpi_ec_write_data(ec, *(wdata++)); + /* disable GPE during transaction if storm is detected */ + if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { + clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); + acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); + } + /* start transaction */ + spin_lock_irqsave(&ec->curr_lock, tmp); + /* following two actions should be kept atomic */ + ec->curr = t; + start_transaction(ec); + if (ec->curr->command == ACPI_EC_COMMAND_QUERY) + clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); + spin_unlock_irqrestore(&ec->curr_lock, tmp); + /* if we selected poll mode or failed in GPE-mode do a poll loop */ + if (force_poll || + !test_bit(EC_FLAGS_GPE_MODE, &ec->flags) || + acpi_ec_wait(ec)) + ret = ec_poll(ec); + pr_debug(PREFIX "transaction end\n"); + spin_lock_irqsave(&ec->curr_lock, tmp); + ec->curr = NULL; + spin_unlock_irqrestore(&ec->curr_lock, tmp); + if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { + /* check if we received SCI during transaction */ + ec_check_sci(ec, acpi_ec_read_status(ec)); + /* it is safe to enable GPE outside of transaction */ + acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); + } else if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && + t->irq_count > ACPI_EC_STORM_THRESHOLD) { + pr_info(PREFIX "GPE storm detected, " + "transactions will use polling mode\n"); + set_bit(EC_FLAGS_GPE_STORM, &ec->flags); } + return ret; +} - if (!rdata_len) { - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); - if (result) { - pr_err(PREFIX - "finish-write timeout, command = %d\n", command); - goto end; - } - } else if (command == ACPI_EC_COMMAND_QUERY) - clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); +static int ec_check_ibf0(struct acpi_ec *ec) +{ + u8 status = acpi_ec_read_status(ec); + return (status & ACPI_EC_FLAG_IBF) == 0; +} - for (; rdata_len > 0; --rdata_len) { - result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, force_poll); - if (result) { - pr_err(PREFIX "read timeout, command = %d\n", command); - goto end; - } - /* Don't expect GPE after last read */ - if (rdata_len > 1) - set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); - *(rdata++) = acpi_ec_read_data(ec); - } - end: - pr_debug(PREFIX "transaction end\n"); - return result; +static int ec_wait_ibf0(struct acpi_ec *ec) +{ + unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); + /* interrupt wait manually if GPE mode is not active */ + unsigned long timeout = test_bit(EC_FLAGS_GPE_MODE, &ec->flags) ? + msecs_to_jiffies(ACPI_EC_DELAY) : msecs_to_jiffies(1); + while (time_before(jiffies, delay)) + if (wait_event_timeout(ec->wait, ec_check_ibf0(ec), timeout)) + return 0; + return -ETIME; } -static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, - const u8 * wdata, unsigned wdata_len, - u8 * rdata, unsigned rdata_len, +static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t, int force_poll) { int status; u32 glk; - - if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata)) + if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata)) return -EINVAL; - - if (rdata) - memset(rdata, 0, rdata_len); - + if (t->rdata) + memset(t->rdata, 0, t->rlen); mutex_lock(&ec->lock); if (ec->global_lock) { status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); if (ACPI_FAILURE(status)) { - mutex_unlock(&ec->lock); - return -ENODEV; + status = -ENODEV; + goto unlock; } } - - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0); - if (status) { + if (ec_wait_ibf0(ec)) { pr_err(PREFIX "input buffer is not empty, " "aborting transaction\n"); + status = -ETIME; goto end; } - - status = acpi_ec_transaction_unlocked(ec, command, - wdata, wdata_len, - rdata, rdata_len, - force_poll); - - end: - + status = acpi_ec_transaction_unlocked(ec, t, force_poll); +end: if (ec->global_lock) acpi_release_global_lock(glk); +unlock: mutex_unlock(&ec->lock); - return status; } @@ -327,21 +373,32 @@ int acpi_ec_burst_enable(struct acpi_ec *ec) { u8 d; - return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1, 0); + struct transaction t = {.command = ACPI_EC_BURST_ENABLE, + .wdata = NULL, .rdata = &d, + .wlen = 0, .rlen = 1}; + + return acpi_ec_transaction(ec, &t, 0); } int acpi_ec_burst_disable(struct acpi_ec *ec) { - return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0, 0); + struct transaction t = {.command = ACPI_EC_BURST_DISABLE, + .wdata = NULL, .rdata = NULL, + .wlen = 0, .rlen = 0}; + + return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ? + acpi_ec_transaction(ec, &t, 0) : 0; } static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) { int result; u8 d; + struct transaction t = {.command = ACPI_EC_COMMAND_READ, + .wdata = &address, .rdata = &d, + .wlen = 1, .rlen = 1}; - result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ, - &address, 1, &d, 1, 0); + result = acpi_ec_transaction(ec, &t, 0); *data = d; return result; } @@ -349,8 +406,11 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) { u8 wdata[2] = { address, data }; - return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE, - wdata, 2, NULL, 0, 0); + struct transaction t = {.command = ACPI_EC_COMMAND_WRITE, + .wdata = wdata, .rdata = NULL, + .wlen = 2, .rlen = 0}; + + return acpi_ec_transaction(ec, &t, 0); } /* @@ -412,12 +472,13 @@ u8 * rdata, unsigned rdata_len, int force_poll) { + struct transaction t = {.command = command, + .wdata = wdata, .rdata = rdata, + .wlen = wdata_len, .rlen = rdata_len}; if (!first_ec) return -ENODEV; - return acpi_ec_transaction(first_ec, command, wdata, - wdata_len, rdata, rdata_len, - force_poll); + return acpi_ec_transaction(first_ec, &t, force_poll); } EXPORT_SYMBOL(ec_transaction); @@ -426,7 +487,9 @@ { int result; u8 d; - + struct transaction t = {.command = ACPI_EC_COMMAND_QUERY, + .wdata = NULL, .rdata = &d, + .wlen = 0, .rlen = 1}; if (!ec || !data) return -EINVAL; @@ -436,7 +499,7 @@ * bit to be cleared (and thus clearing the interrupt source). */ - result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1, 0); + result = acpi_ec_transaction(ec, &t, 0); if (result) return result; @@ -513,46 +576,35 @@ static u32 acpi_ec_gpe_handler(void *data) { - acpi_status status = AE_OK; struct acpi_ec *ec = data; - u8 state = acpi_ec_read_status(ec); + u8 status; pr_debug(PREFIX "~~~> interrupt\n"); - atomic_inc(&ec->irq_count); - if (atomic_read(&ec->irq_count) > 5) { - pr_err(PREFIX "GPE storm detected, disabling EC GPE\n"); - ec_switch_to_poll_mode(ec); - goto end; + status = acpi_ec_read_status(ec); + + if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) { + gpe_transaction(ec, status); + if (ec_transaction_done(ec) && + (status & ACPI_EC_FLAG_IBF) == 0) + wake_up(&ec->wait); } - clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); - if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) - wake_up(&ec->wait); - if (state & ACPI_EC_FLAG_SCI) { - if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) - status = acpi_os_execute(OSL_EC_BURST_HANDLER, - acpi_ec_gpe_query, ec); - } else if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && - !test_bit(EC_FLAGS_NO_GPE, &ec->flags) && - in_interrupt()) { + ec_check_sci(ec, status); + if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && + !test_bit(EC_FLAGS_NO_GPE, &ec->flags)) { /* this is non-query, must be confirmation */ - if (printk_ratelimit()) - pr_info(PREFIX "non-query interrupt received," + if (!test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { + if (printk_ratelimit()) + pr_info(PREFIX "non-query interrupt received," + " switching to interrupt mode\n"); + } else { + /* hush, STORM switches the mode every transaction */ + pr_debug(PREFIX "non-query interrupt received," " switching to interrupt mode\n"); + } set_bit(EC_FLAGS_GPE_MODE, &ec->flags); - clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); } -end: - ec_schedule_ec_poll(ec); - return ACPI_SUCCESS(status) ? - ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; -} - -static void do_ec_poll(struct work_struct *work) -{ - struct acpi_ec *ec = container_of(work, struct acpi_ec, work.work); - atomic_set(&ec->irq_count, 0); - (void)acpi_ec_gpe_handler(ec); + return ACPI_INTERRUPT_HANDLED; } /* -------------------------------------------------------------------------- @@ -696,8 +748,7 @@ mutex_init(&ec->lock); init_waitqueue_head(&ec->wait); INIT_LIST_HEAD(&ec->list); - INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll); - atomic_set(&ec->irq_count, 0); + spin_lock_init(&ec->curr_lock); return ec; } @@ -718,6 +769,7 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) { acpi_status status; + unsigned long tmp = 0; struct acpi_ec *ec = context; status = acpi_walk_resources(handle, METHOD_NAME__CRS, @@ -731,27 +783,22 @@ if (ACPI_FAILURE(status)) return status; /* Use the global lock for all EC transactions? */ - acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); + tmp = 0; + acpi_evaluate_integer(handle, "_GLK", NULL, &tmp); + ec->global_lock = tmp; ec->handle = handle; return AE_CTRL_TERMINATE; } -static void ec_poll_stop(struct acpi_ec *ec) -{ - clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); - cancel_delayed_work(&ec->work); -} - static void ec_remove_handlers(struct acpi_ec *ec) { - ec_poll_stop(ec); if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) pr_err(PREFIX "failed to remove space handler\n"); if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler))) pr_err(PREFIX "failed to remove gpe handler\n"); - ec->handlers_installed = 0; + clear_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags); } static int acpi_ec_add(struct acpi_device *device) @@ -846,17 +893,15 @@ static int ec_install_handlers(struct acpi_ec *ec) { acpi_status status; - if (ec->handlers_installed) + if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) return 0; status = acpi_install_gpe_handler(NULL, ec->gpe, - ACPI_GPE_EDGE_TRIGGERED, - &acpi_ec_gpe_handler, ec); + ACPI_GPE_EDGE_TRIGGERED, + &acpi_ec_gpe_handler, ec); if (ACPI_FAILURE(status)) return -ENODEV; - acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); - status = acpi_install_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, @@ -866,7 +911,7 @@ return -ENODEV; } - ec->handlers_installed = 1; + set_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags); return 0; } @@ -887,7 +932,6 @@ /* EC is fully operational, allow queries */ clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); - ec_schedule_ec_poll(ec); return ret; } @@ -906,7 +950,7 @@ int __init acpi_boot_ec_enable(void) { - if (!boot_ec || boot_ec->handlers_installed) + if (!boot_ec || test_bit(EC_FLAGS_HANDLERS_INSTALLED, &boot_ec->flags)) return 0; if (!ec_install_handlers(boot_ec)) { first_ec = boot_ec; @@ -953,7 +997,7 @@ } else { /* This workaround is needed only on some broken machines, * which require early EC, but fail to provide ECDT */ - acpi_handle x; + acpi_handle dummy; printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n"); status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device, boot_ec, NULL); @@ -964,7 +1008,9 @@ * which needs it, has fake EC._INI method, so use it as flag. * Keep boot_ec struct as it will be needed soon. */ - if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &x))) + if (!dmi_name_in_vendors("ASUS") || + ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", + &dummy))) return -ENODEV; } --- linux-2.6.27.orig/drivers/acpi/osl.c +++ linux-2.6.27/drivers/acpi/osl.c @@ -96,6 +96,11 @@ #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ static char osi_additional_string[OSI_STRING_LENGTH_MAX]; +#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD +static __initdata int acpi_no_initrd_override; +extern struct acpi_table_header *acpi_find_dsdt_initrd(void); +#endif + /* * "Ode to _OSI(Linux)" * @@ -338,6 +343,16 @@ if (strncmp(existing_table->signature, "DSDT", 4) == 0) *new_table = (struct acpi_table_header *)AmlCode; #endif +#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD + if ((strncmp(existing_table->signature, "DSDT", 4) == 0) && + !acpi_no_initrd_override) { + struct acpi_table_header *initrd_table; + + initrd_table = acpi_find_dsdt_initrd(); + if (initrd_table) + *new_table = initrd_table; + } +#endif if (*new_table != NULL) { printk(KERN_WARNING PREFIX "Override [%4.4s-%8.8s], " "this is unsafe: tainting kernel\n", @@ -348,6 +363,15 @@ return AE_OK; } +#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD +static int __init acpi_no_initrd_override_setup(char *s) +{ + acpi_no_initrd_override = 1; + return 1; +} +__setup("acpi_no_initrd_override", acpi_no_initrd_override_setup); +#endif + static irqreturn_t acpi_irq(int irq, void *dev_id) { u32 handled; @@ -1261,34 +1285,6 @@ return (AE_OK); } -/** - * acpi_dmi_dump - dump DMI slots needed for blacklist entry - * - * Returns 0 on success - */ -static int acpi_dmi_dump(void) -{ - - if (!dmi_available) - return -1; - - printk(KERN_NOTICE PREFIX "DMI System Vendor: %s\n", - dmi_get_system_info(DMI_SYS_VENDOR)); - printk(KERN_NOTICE PREFIX "DMI Product Name: %s\n", - dmi_get_system_info(DMI_PRODUCT_NAME)); - printk(KERN_NOTICE PREFIX "DMI Product Version: %s\n", - dmi_get_system_info(DMI_PRODUCT_VERSION)); - printk(KERN_NOTICE PREFIX "DMI Board Name: %s\n", - dmi_get_system_info(DMI_BOARD_NAME)); - printk(KERN_NOTICE PREFIX "DMI BIOS Vendor: %s\n", - dmi_get_system_info(DMI_BIOS_VENDOR)); - printk(KERN_NOTICE PREFIX "DMI BIOS Date: %s\n", - dmi_get_system_info(DMI_BIOS_DATE)); - - return 0; -} - - /****************************************************************************** * * FUNCTION: acpi_os_validate_interface @@ -1315,14 +1311,6 @@ osi_linux.cmdline ? " via cmdline" : osi_linux.dmi ? " via DMI" : ""); - if (!osi_linux.dmi) { - if (acpi_dmi_dump()) - printk(KERN_NOTICE PREFIX - "[please extract dmidecode output]\n"); - printk(KERN_NOTICE PREFIX - "Please send DMI info above to " - "linux-acpi@vger.kernel.org\n"); - } if (!osi_linux.known && !osi_linux.cmdline) { printk(KERN_NOTICE PREFIX "If \"acpi_osi=%sLinux\" works better, " --- linux-2.6.27.orig/drivers/acpi/bus.c +++ linux-2.6.27/drivers/acpi/bus.c @@ -48,6 +48,23 @@ #define STRUCT_TO_INT(s) (*((int*)&s)) +static int set_power_nocheck(const struct dmi_system_id *id) +{ + printk(KERN_NOTICE PREFIX "%s detected - " + "disable power check in power transistion\n", id->ident); + acpi_power_nocheck = 1; + return 0; +} +static struct dmi_system_id __cpuinitdata power_nocheck_dmi_table[] = { + { + set_power_nocheck, "HP Pavilion 05", { + DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), + DMI_MATCH(DMI_SYS_VENDOR, "HP Pavilion 05"), + DMI_MATCH(DMI_PRODUCT_VERSION, "2001211RE101GLEND") }, NULL}, + {}, +}; + + /* -------------------------------------------------------------------------- Device Management -------------------------------------------------------------------------- */ @@ -95,21 +112,21 @@ } /* - * Otherwise we assume the status of our parent (unless we don't - * have one, in which case status is implied). + * According to ACPI spec some device can be present and functional + * even if the parent is not present but functional. + * In such conditions the child device should not inherit the status + * from the parent. */ - else if (device->parent) - device->status = device->parent->status; else STRUCT_TO_INT(device->status) = ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; if (device->status.functional && !device->status.present) { - printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: " - "functional but not present; setting present\n", - device->pnp.bus_id, (u32) STRUCT_TO_INT(device->status)); - device->status.present = 1; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: " + "functional but not present;\n", + device->pnp.bus_id, + (u32) STRUCT_TO_INT(device->status))); } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n", @@ -223,7 +240,19 @@ /* * Get device's current power state */ - acpi_bus_get_power(device->handle, &device->power.state); + if (!acpi_power_nocheck) { + /* + * Maybe the incorrect power state is returned on the bogus + * bios, which is different with the real power state. + * For example: the bios returns D0 state and the real power + * state is D3. OS expects to set the device to D0 state. In + * such case if OS uses the power state returned by the BIOS, + * the device can't be transisted to the correct power state. + * So if the acpi_power_nocheck is set, it is unnecessary to + * get the power state by calling acpi_bus_get_power. + */ + acpi_bus_get_power(device->handle, &device->power.state); + } if ((state == device->power.state) && !device->flags.force_power_state) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", state)); @@ -818,7 +847,11 @@ } } else disable_acpi(); - + /* + * If the laptop falls into the DMI check table, the power state check + * will be disabled in the course of device power transistion. + */ + dmi_check_system(power_nocheck_dmi_table); return result; } --- linux-2.6.27.orig/drivers/acpi/pci_slot.c +++ linux-2.6.27/drivers/acpi/pci_slot.c @@ -150,7 +150,7 @@ } snprintf(name, sizeof(name), "%u", (u32)sun); - pci_slot = pci_create_slot(pci_bus, device, name); + pci_slot = pci_create_slot(pci_bus, device, name, NULL); if (IS_ERR(pci_slot)) { err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot)); kfree(slot); --- linux-2.6.27.orig/drivers/acpi/asus_acpi.c +++ linux-2.6.27/drivers/acpi/asus_acpi.c @@ -1244,6 +1244,8 @@ "default values\n", string); printk(KERN_NOTICE " send /proc/acpi/dsdt to the developers\n"); + kfree(model); + return -ENODEV; } hotk->methods = &model_conf[hotk->model]; return AE_OK; --- linux-2.6.27.orig/drivers/acpi/sleep/main.c +++ linux-2.6.27/drivers/acpi/sleep/main.c @@ -60,6 +60,18 @@ old_suspend_ordering = true; } +/* + * According to the ACPI specification the BIOS should make sure that ACPI is + * enabled and SCI_EN bit is set on wake-up from S1 - S3 sleep states. Still, + * some BIOSes don't do that and therefore we use acpi_enable() to enable ACPI + * on such systems during resume. Unfortunately that doesn't help in + * particularly pathological cases in which SCI_EN has to be set directly on + * resume, although the specification states very clearly that this flag is + * owned by the hardware. The set_sci_en_on_resume variable will be set in such + * cases. + */ +static bool set_sci_en_on_resume; + /** * acpi_pm_disable_gpes - Disable the GPEs. */ @@ -200,6 +212,12 @@ break; } + /* If ACPI is not enabled by the BIOS, we need to enable it here. */ + if (set_sci_en_on_resume) + acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1); + else + acpi_enable(); + /* Reprogram control registers and execute _BFS */ acpi_leave_sleep_state_prep(acpi_state); @@ -287,6 +305,12 @@ return 0; } +static int __init init_set_sci_en_on_resume(const struct dmi_system_id *d) +{ + set_sci_en_on_resume = true; + return 0; +} + static struct dmi_system_id __initdata acpisleep_dmi_table[] = { { .callback = init_old_suspend_ordering, @@ -296,6 +320,38 @@ DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"), }, }, + { + .callback = init_old_suspend_ordering, + .ident = "HP xw4600 Workstation", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP xw4600 Workstation"), + }, + }, + { + .callback = init_set_sci_en_on_resume, + .ident = "Apple MacBook 1,1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"), + }, + }, + { + .callback = init_set_sci_en_on_resume, + .ident = "Apple MacMini 1,1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Macmini1,1"), + }, + }, + { + .callback = init_old_suspend_ordering, + .ident = "HP xw4600 Workstation", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP xw4600 Workstation"), + }, + }, {}, }; #endif /* CONFIG_SUSPEND */ --- linux-2.6.27.orig/drivers/acpi/parser/psparse.c +++ linux-2.6.27/drivers/acpi/parser/psparse.c @@ -641,10 +641,12 @@ ACPI_WALK_METHOD_RESTART; } } else { - /* On error, delete any return object */ + /* On error, delete any return object or implicit return */ acpi_ut_remove_reference(previous_walk_state-> return_desc); + acpi_ds_clear_implicit_return + (previous_walk_state); } } --- linux-2.6.27.orig/drivers/acpi/executer/exconfig.c +++ linux-2.6.27/drivers/acpi/executer/exconfig.c @@ -280,6 +280,7 @@ struct acpi_walk_state *walk_state) { union acpi_operand_object *ddb_handle; + struct acpi_table_header *table; struct acpi_table_desc table_desc; u32 table_index; acpi_status status; @@ -294,9 +295,8 @@ switch (ACPI_GET_OBJECT_TYPE(obj_desc)) { case ACPI_TYPE_REGION: - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n", - obj_desc, - acpi_ut_get_object_type_name(obj_desc))); + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Load table from Region %p\n", obj_desc)); /* Region must be system_memory (from ACPI spec) */ @@ -316,61 +316,112 @@ } /* - * We will simply map the memory region for the table. However, the - * memory region is technically not guaranteed to remain stable and - * we may eventually have to copy the table to a local buffer. + * Map the table header and get the actual table length. The region + * length is not guaranteed to be the same as the table length. + */ + table = acpi_os_map_memory(obj_desc->region.address, + sizeof(struct acpi_table_header)); + if (!table) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + length = table->length; + acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); + + /* Must have at least an ACPI table header */ + + if (length < sizeof(struct acpi_table_header)) { + return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); + } + + /* + * The memory region is not guaranteed to remain stable and we must + * copy the table to a local buffer. For example, the memory region + * is corrupted after suspend on some machines. Dynamically loaded + * tables are usually small, so this overhead is minimal. */ + + /* Allocate a buffer for the table */ + + table_desc.pointer = ACPI_ALLOCATE(length); + if (!table_desc.pointer) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + /* Map the entire table and copy it */ + + table = acpi_os_map_memory(obj_desc->region.address, length); + if (!table) { + ACPI_FREE(table_desc.pointer); + return_ACPI_STATUS(AE_NO_MEMORY); + } + + ACPI_MEMCPY(table_desc.pointer, table, length); + acpi_os_unmap_memory(table, length); + table_desc.address = obj_desc->region.address; - table_desc.length = obj_desc->region.length; - table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED; break; case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Load from Buffer or Field %p %s\n", obj_desc, - acpi_ut_get_object_type_name(obj_desc))); - - length = obj_desc->buffer.length; + "Load table from Buffer or Field %p\n", + obj_desc)); /* Must have at least an ACPI table header */ - if (length < sizeof(struct acpi_table_header)) { + if (obj_desc->buffer.length < sizeof(struct acpi_table_header)) { return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); } - /* Validate checksum here. It won't get validated in tb_add_table */ + /* Get the actual table length from the table header */ - status = - acpi_tb_verify_checksum(ACPI_CAST_PTR - (struct acpi_table_header, - obj_desc->buffer.pointer), length); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + table = + ACPI_CAST_PTR(struct acpi_table_header, + obj_desc->buffer.pointer); + length = table->length; + + /* Table cannot extend beyond the buffer */ + + if (length > obj_desc->buffer.length) { + return_ACPI_STATUS(AE_AML_BUFFER_LIMIT); + } + if (length < sizeof(struct acpi_table_header)) { + return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); } /* - * We need to copy the buffer since the original buffer could be - * changed or deleted in the future + * Copy the table from the buffer because the buffer could be modified + * or even deleted in the future */ table_desc.pointer = ACPI_ALLOCATE(length); if (!table_desc.pointer) { return_ACPI_STATUS(AE_NO_MEMORY); } - ACPI_MEMCPY(table_desc.pointer, obj_desc->buffer.pointer, - length); - table_desc.length = length; - table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED; + ACPI_MEMCPY(table_desc.pointer, table, length); + table_desc.address = ACPI_TO_INTEGER(table_desc.pointer); break; default: return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } - /* - * Install the new table into the local data structures - */ + /* Validate table checksum (will not get validated in tb_add_table) */ + + status = acpi_tb_verify_checksum(table_desc.pointer, length); + if (ACPI_FAILURE(status)) { + ACPI_FREE(table_desc.pointer); + return_ACPI_STATUS(status); + } + + /* Complete the table descriptor */ + + table_desc.length = length; + table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED; + + /* Install the new table into the local data structures */ + status = acpi_tb_add_table(&table_desc, &table_index); if (ACPI_FAILURE(status)) { goto cleanup; @@ -379,7 +430,7 @@ /* * Add the table to the namespace. * - * Note: We load the table objects relative to the root of the namespace. + * Note: Load the table objects relative to the root of the namespace. * This appears to go against the ACPI specification, but we do it for * compatibility with other ACPI implementations. */ @@ -415,7 +466,7 @@ cleanup: if (ACPI_FAILURE(status)) { - /* Delete allocated buffer or mapping */ + /* Delete allocated table buffer */ acpi_tb_delete_table(&table_desc); } --- linux-2.6.27.orig/drivers/acpi/tables/tbutils.c +++ linux-2.6.27/drivers/acpi/tables/tbutils.c @@ -512,10 +512,9 @@ if (ACPI_FAILURE(status)) { ACPI_WARNING((AE_INFO, "Truncating %u table entries!", - (unsigned) - (acpi_gbl_root_table_list.size - - acpi_gbl_root_table_list. - count))); + (unsigned) (table_count - + (acpi_gbl_root_table_list. + count - 2)))); break; } } --- linux-2.6.27.orig/drivers/acpi/dispatcher/dsmethod.c +++ linux-2.6.27/drivers/acpi/dispatcher/dsmethod.c @@ -103,6 +103,9 @@ NULL); acpi_ex_enter_interpreter(); } + + acpi_ds_clear_implicit_return(walk_state); + #ifdef ACPI_DISASSEMBLER if (ACPI_FAILURE(status)) { --- linux-2.6.27.orig/drivers/acpi/hardware/hwsleep.c +++ linux-2.6.27/drivers/acpi/hardware/hwsleep.c @@ -78,19 +78,17 @@ return_ACPI_STATUS(status); } - /* Set the vector */ + /* + * According to the ACPI specification 2.0c and later, the 64-bit + * waking vector should be cleared and the 32-bit waking vector should + * be used, unless we want the wake-up code to be called by the BIOS in + * Protected Mode. Some systems (for example HP dv5-1004nr) are known + * to fail to resume if the 64-bit vector is used. + */ + if (facs->version >= 1) + facs->xfirmware_waking_vector = 0; - if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) { - /* - * ACPI 1.0 FACS or short table or optional X_ field is zero - */ - facs->firmware_waking_vector = (u32) physical_address; - } else { - /* - * ACPI 2.0 FACS with valid X_ field - */ - facs->xfirmware_waking_vector = physical_address; - } + facs->firmware_waking_vector = (u32)physical_address; return_ACPI_STATUS(AE_OK); } @@ -134,20 +132,7 @@ } /* Get the vector */ - - if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) { - /* - * ACPI 1.0 FACS or short table or optional X_ field is zero - */ - *physical_address = - (acpi_physical_address) facs->firmware_waking_vector; - } else { - /* - * ACPI 2.0 FACS with valid X_ field - */ - *physical_address = - (acpi_physical_address) facs->xfirmware_waking_vector; - } + *physical_address = (acpi_physical_address)facs->firmware_waking_vector; return_ACPI_STATUS(AE_OK); } @@ -627,6 +612,13 @@ } /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */ + /* + * Some BIOSes assume that WAK_STS will be cleared on resume and use + * it to determine whether the system is rebooting or resuming. Clear + * it for compatibility. + */ + acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1); + acpi_gbl_system_awake_and_running = TRUE; /* Enable power button */ --- linux-2.6.27.orig/drivers/acpi/namespace/nsxfname.c +++ linux-2.6.27/drivers/acpi/namespace/nsxfname.c @@ -253,6 +253,7 @@ node = acpi_ns_map_handle_to_node(handle); if (!node) { (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + status = AE_BAD_PARAMETER; goto cleanup; } --- linux-2.6.27.orig/drivers/acpi/namespace/nsutils.c +++ linux-2.6.27/drivers/acpi/namespace/nsutils.c @@ -314,9 +314,15 @@ * * strlen() + 1 covers the first name_seg, which has no path separator */ - if (acpi_ns_valid_root_prefix(next_external_char[0])) { + if (acpi_ns_valid_root_prefix(*next_external_char)) { info->fully_qualified = TRUE; next_external_char++; + + /* Skip redundant root_prefix, like \\_SB.PCI0.SBRG.EC0 */ + + while (acpi_ns_valid_root_prefix(*next_external_char)) { + next_external_char++; + } } else { /* * Handle Carat prefixes --- linux-2.6.27.orig/drivers/acpi/namespace/nsxfeval.c +++ linux-2.6.27/drivers/acpi/namespace/nsxfeval.c @@ -45,9 +45,14 @@ #include #include #include +#include #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsxfeval") + +/* Local prototypes */ +static void acpi_ns_resolve_references(struct acpi_evaluate_info *info); + #ifdef ACPI_FUTURE_USAGE /******************************************************************************* * @@ -69,6 +74,7 @@ * be valid (non-null) * ******************************************************************************/ + acpi_status acpi_evaluate_object_typed(acpi_handle handle, acpi_string pathname, @@ -283,6 +289,10 @@ if (ACPI_SUCCESS(status)) { + /* Dereference Index and ref_of references */ + + acpi_ns_resolve_references(info); + /* Get the size of the returned object */ status = @@ -352,6 +362,74 @@ /******************************************************************************* * + * FUNCTION: acpi_ns_resolve_references + * + * PARAMETERS: Info - Evaluation info block + * + * RETURN: Info->return_object is replaced with the dereferenced object + * + * DESCRIPTION: Dereference certain reference objects. Called before an + * internal return object is converted to an external union acpi_object. + * + * Performs an automatic dereference of Index and ref_of reference objects. + * These reference objects are not supported by the union acpi_object, so this is a + * last resort effort to return something useful. Also, provides compatibility + * with other ACPI implementations. + * + * NOTE: does not handle references within returned package objects or nested + * references, but this support could be added later if found to be necessary. + * + ******************************************************************************/ +static void acpi_ns_resolve_references(struct acpi_evaluate_info *info) +{ + union acpi_operand_object *obj_desc = NULL; + struct acpi_namespace_node *node; + + /* We are interested in reference objects only */ + + if (ACPI_GET_OBJECT_TYPE(info->return_object) != + ACPI_TYPE_LOCAL_REFERENCE) { + return; + } + + /* + * Two types of references are supported - those created by Index and + * ref_of operators. A name reference (AML_NAMEPATH_OP) can be converted + * to an union acpi_object, so it is not dereferenced here. A ddb_handle + * (AML_LOAD_OP) cannot be dereferenced, nor can it be converted to + * an union acpi_object. + */ + switch (info->return_object->reference.opcode) { + case AML_INDEX_OP: + + obj_desc = *(info->return_object->reference.where); + break; + + case AML_REF_OF_OP: + + node = info->return_object->reference.object; + if (node) { + obj_desc = node->object; + } + break; + + default: + return; + } + + /* Replace the existing reference object */ + + if (obj_desc) { + acpi_ut_add_reference(obj_desc); + acpi_ut_remove_reference(info->return_object); + info->return_object = obj_desc; + } + + return; +} + +/******************************************************************************* + * * FUNCTION: acpi_walk_namespace * * PARAMETERS: Type - acpi_object_type to search for @@ -379,6 +457,7 @@ * function, etc. * ******************************************************************************/ + acpi_status acpi_walk_namespace(acpi_object_type type, acpi_handle start_object, --- linux-2.6.27.orig/drivers/ata/libata-sff.c +++ linux-2.6.27/drivers/ata/libata-sff.c @@ -1227,10 +1227,19 @@ /* ATA PIO protocol */ if (unlikely((status & ATA_DRQ) == 0)) { /* handle BSY=0, DRQ=0 as error */ - if (likely(status & (ATA_ERR | ATA_DF))) + if (likely(status & (ATA_ERR | ATA_DF))) { /* device stops HSM for abort/error */ qc->err_mask |= AC_ERR_DEV; - else { + + /* If diagnostic failed and this is + * IDENTIFY, it's likely a phantom + * device. Mark hint. + */ + if (qc->dev->horkage & + ATA_HORKAGE_DIAGNOSTIC) + qc->err_mask |= + AC_ERR_NODEV_HINT; + } else { /* HSM violation. Let EH handle this. * Phantom devices also trigger this * condition. Mark hint. --- linux-2.6.27.orig/drivers/ata/libata-eh.c +++ linux-2.6.27/drivers/ata/libata-eh.c @@ -604,9 +604,6 @@ if (ata_ncq_enabled(dev)) ehc->saved_ncq_enabled |= 1 << devno; } - - /* set last reset timestamp to some time in the past */ - ehc->last_reset = jiffies - 60 * HZ; } ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; @@ -2209,17 +2206,21 @@ if (link->flags & ATA_LFLAG_NO_SRST) softreset = NULL; - now = jiffies; - deadline = ata_deadline(ehc->last_reset, ATA_EH_RESET_COOL_DOWN); - if (time_before(now, deadline)) - schedule_timeout_uninterruptible(deadline - now); + /* make sure each reset attemp is at least COOL_DOWN apart */ + if (ehc->i.flags & ATA_EHI_DID_RESET) { + now = jiffies; + WARN_ON(time_after(ehc->last_reset, now)); + deadline = ata_deadline(ehc->last_reset, + ATA_EH_RESET_COOL_DOWN); + if (time_before(now, deadline)) + schedule_timeout_uninterruptible(deadline - now); + } spin_lock_irqsave(ap->lock, flags); ap->pflags |= ATA_PFLAG_RESETTING; spin_unlock_irqrestore(ap->lock, flags); ata_eh_about_to_do(link, NULL, ATA_EH_RESET); - ehc->last_reset = jiffies; ata_link_for_each_dev(dev, link) { /* If we issue an SRST then an ATA drive (not ATAPI) @@ -2271,11 +2272,14 @@ } /* prereset() might have cleared ATA_EH_RESET. If so, - * bang classes and return. + * bang classes, thaw and return. */ if (reset && !(ehc->i.action & ATA_EH_RESET)) { ata_link_for_each_dev(dev, link) classes[dev->devno] = ATA_DEV_NONE; + if ((ap->pflags & ATA_PFLAG_FROZEN) && + ata_is_host_link(link)) + ata_eh_thaw_port(ap); rc = 0; goto out; } @@ -2285,7 +2289,6 @@ /* * Perform reset */ - ehc->last_reset = jiffies; if (ata_is_host_link(link)) ata_eh_freeze_port(ap); @@ -2297,6 +2300,7 @@ reset == softreset ? "soft" : "hard"); /* mark that this EH session started with reset */ + ehc->last_reset = jiffies; if (reset == hardreset) ehc->i.flags |= ATA_EHI_DID_HARDRESET; else @@ -2404,7 +2408,7 @@ /* reset successful, schedule revalidation */ ata_eh_done(link, NULL, ATA_EH_RESET); - ehc->last_reset = jiffies; + ehc->last_reset = jiffies; /* update to completion time */ ehc->i.action |= ATA_EH_REVALIDATE; rc = 0; @@ -2693,12 +2697,13 @@ /* give it just one more chance */ ehc->tries[dev->devno] = min(ehc->tries[dev->devno], 1); case -EIO: - if (ehc->tries[dev->devno] == 1 && dev->pio_mode > XFER_PIO_0) { + if (ehc->tries[dev->devno] == 1) { /* This is the last chance, better to slow * down than lose it. */ sata_down_spd_limit(dev->link); - ata_down_xfermask_limit(dev, ATA_DNXFER_PIO); + if (dev->pio_mode > XFER_PIO_0) + ata_down_xfermask_limit(dev, ATA_DNXFER_PIO); } } --- linux-2.6.27.orig/drivers/ata/libata-core.c +++ linux-2.6.27/drivers/ata/libata-core.c @@ -551,7 +551,7 @@ if (tf->flags & ATA_TFLAG_LBA48) { block |= (u64)tf->hob_lbah << 40; block |= (u64)tf->hob_lbam << 32; - block |= tf->hob_lbal << 24; + block |= (u64)tf->hob_lbal << 24; } else block |= (tf->device & 0xf) << 24; @@ -1207,7 +1207,7 @@ sectors |= ((u64)(tf->hob_lbah & 0xff)) << 40; sectors |= ((u64)(tf->hob_lbam & 0xff)) << 32; - sectors |= (tf->hob_lbal & 0xff) << 24; + sectors |= ((u64)(tf->hob_lbal & 0xff)) << 24; sectors |= (tf->lbah & 0xff) << 16; sectors |= (tf->lbam & 0xff) << 8; sectors |= (tf->lbal & 0xff); @@ -2428,6 +2428,13 @@ } } + if ((dev->horkage & ATA_HORKAGE_FIRMWARE_WARN) && print_info) { + ata_dev_printk(dev, KERN_WARNING, "WARNING: device requires " + "firmware update to be fully functional.\n"); + ata_dev_printk(dev, KERN_WARNING, " contact the vendor " + "or visit http://ata.wiki.kernel.org.\n"); + } + return 0; err_out_nosup: @@ -3971,11 +3978,79 @@ { "ST380817AS", "3.42", ATA_HORKAGE_NONCQ }, { "ST3160023AS", "3.42", ATA_HORKAGE_NONCQ }, + /* Seagate NCQ + FLUSH CACHE firmware bug */ + { "ST31500341AS", "SD15", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST31500341AS", "SD16", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST31500341AS", "SD17", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST31500341AS", "SD18", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST31500341AS", "SD19", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + + { "ST31000333AS", "SD15", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST31000333AS", "SD16", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST31000333AS", "SD17", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST31000333AS", "SD18", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST31000333AS", "SD19", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + + { "ST3640623AS", "SD15", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST3640623AS", "SD16", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST3640623AS", "SD17", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST3640623AS", "SD18", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST3640623AS", "SD19", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + + { "ST3640323AS", "SD15", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST3640323AS", "SD16", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST3640323AS", "SD17", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST3640323AS", "SD18", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST3640323AS", "SD19", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + + { "ST3320813AS", "SD15", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST3320813AS", "SD16", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST3320813AS", "SD17", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST3320813AS", "SD18", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST3320813AS", "SD19", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + + { "ST3320613AS", "SD15", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST3320613AS", "SD16", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST3320613AS", "SD17", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST3320613AS", "SD18", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + { "ST3320613AS", "SD19", ATA_HORKAGE_NONCQ | + ATA_HORKAGE_FIRMWARE_WARN }, + /* Blacklist entries taken from Silicon Image 3124/3132 Windows driver .inf file - also several Linux problem reports */ { "HTS541060G9SA00", "MB3OC60D", ATA_HORKAGE_NONCQ, }, { "HTS541080G9SA00", "MB4OC60D", ATA_HORKAGE_NONCQ, }, { "HTS541010G9SA00", "MBZOC60D", ATA_HORKAGE_NONCQ, }, + { "FUJITSU MHW2160BH PL", "0084001E", ATA_HORKAGE_NONCQ, }, /* devices which puke on READ_NATIVE_MAX */ { "HDS724040KLSA80", "KFAOA20N", ATA_HORKAGE_BROKEN_HPA, }, @@ -5259,6 +5334,8 @@ #ifdef CONFIG_ATA_SFF INIT_DELAYED_WORK(&ap->port_task, ata_pio_task); +#else + INIT_DELAYED_WORK(&ap->port_task, NULL); #endif INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug); INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan); --- linux-2.6.27.orig/drivers/ata/pata_via.c +++ linux-2.6.27/drivers/ata/pata_via.c @@ -87,6 +87,10 @@ VIA_SATA_PATA = 0x800, /* SATA/PATA combined configuration */ }; +enum { + VIA_IDFLAG_SINGLE = (1 << 0), /* single channel controller) */ +}; + /* * VIA SouthBridge chips. */ @@ -98,8 +102,12 @@ u8 rev_max; u16 flags; } via_isa_bridges[] = { + { "vx855", PCI_DEVICE_ID_VIA_VX855, 0x00, 0x2f, + VIA_UDMA_133 | VIA_BAD_AST | VIA_SATA_PATA }, { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_SATA_PATA }, + { "vt8261", PCI_DEVICE_ID_VIA_8261, 0x00, 0x2f, + VIA_UDMA_133 | VIA_BAD_AST }, { "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_SATA_PATA }, @@ -123,6 +131,8 @@ { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO }, { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK }, { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID }, + { "vtxxxx", PCI_DEVICE_ID_VIA_ANON, 0x00, 0x2f, + VIA_UDMA_133 | VIA_BAD_AST }, { NULL } }; @@ -461,6 +471,7 @@ static int printed_version; u8 enable; u32 timing; + unsigned long flags = id->driver_data; int rc; if (!printed_version++) @@ -470,9 +481,13 @@ if (rc) return rc; + if (flags & VIA_IDFLAG_SINGLE) + ppi[1] = &ata_dummy_port_info; + /* To find out how the IDE will behave and what features we actually have to look at the bridge not the IDE controller */ - for (config = via_isa_bridges; config->id; config++) + for (config = via_isa_bridges; config->id != PCI_DEVICE_ID_VIA_ANON; + config++) if ((isa = pci_get_device(PCI_VENDOR_ID_VIA + !!(config->flags & VIA_BAD_ID), config->id, NULL))) { @@ -483,10 +498,6 @@ pci_dev_put(isa); } - if (!config->id) { - printk(KERN_WARNING "via: Unknown VIA SouthBridge, disabling.\n"); - return -ENODEV; - } pci_dev_put(isa); if (!(config->flags & VIA_NO_ENABLES)) { @@ -588,6 +599,7 @@ { PCI_VDEVICE(VIA, 0x1571), }, { PCI_VDEVICE(VIA, 0x3164), }, { PCI_VDEVICE(VIA, 0x5324), }, + { PCI_VDEVICE(VIA, 0xC409), VIA_IDFLAG_SINGLE }, { }, }; --- linux-2.6.27.orig/drivers/ata/sata_nv.c +++ linux-2.6.27/drivers/ata/sata_nv.c @@ -305,12 +305,12 @@ static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); +static int nv_noclassify_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); static void nv_nf2_freeze(struct ata_port *ap); static void nv_nf2_thaw(struct ata_port *ap); static void nv_ck804_freeze(struct ata_port *ap); static void nv_ck804_thaw(struct ata_port *ap); -static int nv_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline); static int nv_adma_slave_config(struct scsi_device *sdev); static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc); static void nv_adma_qc_prep(struct ata_queued_cmd *qc); @@ -352,6 +352,7 @@ NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */ CK804, ADMA, + MCP5x, SWNCQ, }; @@ -363,10 +364,10 @@ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2), CK804 }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA), CK804 }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2), CK804 }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), SWNCQ }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), SWNCQ }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), SWNCQ }, - { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), SWNCQ }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), MCP5x }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), MCP5x }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), MCP5x }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), MCP5x }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), GENERIC }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), GENERIC }, { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), GENERIC }, @@ -405,17 +406,8 @@ .slave_configure = nv_swncq_slave_config, }; -/* OSDL bz3352 reports that some nv controllers can't determine device - * signature reliably and nv_hardreset is implemented to work around - * the problem. This was reported on nf3 and it's unclear whether any - * other controllers are affected. However, the workaround has been - * applied to all variants and there isn't much to gain by trying to - * find out exactly which ones are affected at this point especially - * because NV has moved over to ahci for newer controllers. - */ static struct ata_port_operations nv_common_ops = { .inherits = &ata_bmdma_port_ops, - .hardreset = nv_hardreset, .scr_read = nv_scr_read, .scr_write = nv_scr_write, }; @@ -429,21 +421,36 @@ .hardreset = ATA_OP_NULL, }; +/* OSDL bz3352 reports that nf2/3 controllers can't determine device + * signature reliably. Also, the following thread reports detection + * failure on cold boot with the standard debouncing timing. + * + * http://thread.gmane.org/gmane.linux.ide/34098 + * + * Debounce with hotplug timing and request follow-up SRST. + */ static struct ata_port_operations nv_nf2_ops = { .inherits = &nv_common_ops, .freeze = nv_nf2_freeze, .thaw = nv_nf2_thaw, + .hardreset = nv_noclassify_hardreset, }; +/* For initial probing after boot and hot plugging, hardreset mostly + * works fine on CK804 but curiously, reprobing on the initial port by + * rescanning or rmmod/insmod fails to acquire the initial D2H Reg FIS + * in somewhat undeterministic way. Use noclassify hardreset. + */ static struct ata_port_operations nv_ck804_ops = { .inherits = &nv_common_ops, .freeze = nv_ck804_freeze, .thaw = nv_ck804_thaw, + .hardreset = nv_noclassify_hardreset, .host_stop = nv_ck804_host_stop, }; static struct ata_port_operations nv_adma_ops = { - .inherits = &nv_common_ops, + .inherits = &nv_ck804_ops, .check_atapi_dma = nv_adma_check_atapi_dma, .sff_tf_read = nv_adma_tf_read, @@ -466,8 +473,19 @@ .host_stop = nv_adma_host_stop, }; -static struct ata_port_operations nv_swncq_ops = { +/* Kernel bz#12351 reports that when SWNCQ is enabled, for hotplug to + * work, hardreset should be used and hardreset can't report proper + * signature, which suggests that mcp5x is closer to nf2 as long as + * reset quirkiness is concerned. Define separate ops for mcp5x with + * nv_noclassify_hardreset(). + */ +static struct ata_port_operations nv_mcp5x_ops = { .inherits = &nv_common_ops, + .hardreset = nv_noclassify_hardreset, +}; + +static struct ata_port_operations nv_swncq_ops = { + .inherits = &nv_mcp5x_ops, .qc_defer = ata_std_qc_defer, .qc_prep = nv_swncq_qc_prep, @@ -530,6 +548,15 @@ .port_ops = &nv_adma_ops, .private_data = NV_PI_PRIV(nv_adma_interrupt, &nv_adma_sht), }, + /* MCP5x */ + { + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .pio_mask = NV_PIO_MASK, + .mwdma_mask = NV_MWDMA_MASK, + .udma_mask = NV_UDMA_MASK, + .port_ops = &nv_mcp5x_ops, + .private_data = NV_PI_PRIV(nv_generic_interrupt, &nv_sht), + }, /* SWNCQ */ { .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | @@ -1529,6 +1556,17 @@ return 0; } +static int nv_noclassify_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + bool online; + int rc; + + rc = sata_link_hardreset(link, sata_deb_timing_hotplug, deadline, + &online, NULL); + return online ? -EAGAIN : rc; +} + static void nv_nf2_freeze(struct ata_port *ap) { void __iomem *scr_addr = ap->host->ports[0]->ioaddr.scr_addr; @@ -1605,21 +1643,6 @@ ata_sff_thaw(ap); } -static int nv_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) -{ - int rc; - - /* SATA hardreset fails to retrieve proper device signature on - * some controllers. Request follow up SRST. For more info, - * see http://bugzilla.kernel.org/show_bug.cgi?id=3352 - */ - rc = sata_sff_hardreset(link, class, deadline); - if (rc) - return rc; - return -EAGAIN; -} - static void nv_adma_error_handler(struct ata_port *ap) { struct nv_adma_port_priv *pp = ap->private_data; @@ -2358,14 +2381,9 @@ if (type == CK804 && adma_enabled) { dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n"); type = ADMA; - } - - if (type == SWNCQ) { - if (swncq_enabled) - dev_printk(KERN_NOTICE, &pdev->dev, - "Using SWNCQ mode\n"); - else - type = GENERIC; + } else if (type == MCP5x && swncq_enabled) { + dev_printk(KERN_NOTICE, &pdev->dev, "Using SWNCQ mode\n"); + type = SWNCQ; } ppi[0] = &nv_port_info[type]; --- linux-2.6.27.orig/drivers/ata/pata_it821x.c +++ linux-2.6.27/drivers/ata/pata_it821x.c @@ -557,9 +557,8 @@ if (strstr(model_num, "Integrated Technology Express")) { /* Set feature bits the firmware neglects */ id[49] |= 0x0300; /* LBA, DMA */ - id[82] |= 0x0400; /* LBA48 */ id[83] &= 0x7FFF; - id[83] |= 0x4000; /* Word 83 is valid */ + id[83] |= 0x4400; /* Word 83 is valid and LBA48 */ id[86] |= 0x0400; /* LBA48 on */ id[ATA_ID_MAJOR_VER] |= 0x1F; } --- linux-2.6.27.orig/drivers/ata/sata_mv.c +++ linux-2.6.27/drivers/ata/sata_mv.c @@ -669,8 +669,8 @@ { PCI_VDEVICE(MARVELL, 0x5081), chip_508x }, /* RocketRAID 1720/174x have different identifiers */ { PCI_VDEVICE(TTI, 0x1720), chip_6042 }, - { PCI_VDEVICE(TTI, 0x1740), chip_508x }, - { PCI_VDEVICE(TTI, 0x1742), chip_508x }, + { PCI_VDEVICE(TTI, 0x1740), chip_6042 }, + { PCI_VDEVICE(TTI, 0x1742), chip_6042 }, { PCI_VDEVICE(MARVELL, 0x6040), chip_604x }, { PCI_VDEVICE(MARVELL, 0x6041), chip_604x }, @@ -883,7 +883,7 @@ struct mv_host_priv *hpriv = ap->host->private_data; int hardport = mv_hardport_from_port(ap->port_no); void __iomem *hc_mmio = mv_hc_base_from_port( - mv_host_base(ap->host), hardport); + mv_host_base(ap->host), ap->port_no); u32 hc_irq_cause, ipending; /* clear EDMA event indicators, if any */ --- linux-2.6.27.orig/drivers/ata/sata_promise.c +++ linux-2.6.27/drivers/ata/sata_promise.c @@ -153,6 +153,10 @@ static void pdc_sata_freeze(struct ata_port *ap); static void pdc_thaw(struct ata_port *ap); static void pdc_sata_thaw(struct ata_port *ap); +static int pdc_pata_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); +static int pdc_sata_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); static void pdc_error_handler(struct ata_port *ap); static void pdc_post_internal_cmd(struct ata_queued_cmd *qc); static int pdc_pata_cable_detect(struct ata_port *ap); @@ -186,6 +190,7 @@ .scr_read = pdc_sata_scr_read, .scr_write = pdc_sata_scr_write, .port_start = pdc_sata_port_start, + .hardreset = pdc_sata_hardreset, }; /* First-generation chips need a more restrictive ->check_atapi_dma op */ @@ -200,6 +205,7 @@ .freeze = pdc_freeze, .thaw = pdc_thaw, .port_start = pdc_common_port_start, + .softreset = pdc_pata_softreset, }; static const struct ata_port_info pdc_port_info[] = { @@ -691,6 +697,20 @@ readl(host_mmio + hotplug_offset); /* flush */ } +static int pdc_pata_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + pdc_reset_port(link->ap); + return ata_sff_softreset(link, class, deadline); +} + +static int pdc_sata_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + pdc_reset_port(link->ap); + return sata_sff_hardreset(link, class, deadline); +} + static void pdc_error_handler(struct ata_port *ap) { if (!(ap->pflags & ATA_PFLAG_FROZEN)) --- linux-2.6.27.orig/drivers/firmware/dell_rbu.c +++ linux-2.6.27/drivers/firmware/dell_rbu.c @@ -576,7 +576,7 @@ { int size = 0; if (!pos) - size = sprintf(buffer, "%s\n", image_type); + size = scnprintf(buffer, count, "%s\n", image_type); return size; } @@ -648,7 +648,7 @@ int size = 0; if (!pos) { spin_lock(&rbu_data.lock); - size = sprintf(buffer, "%lu\n", rbu_data.packetsize); + size = scnprintf(buffer, count, "%lu\n", rbu_data.packetsize); spin_unlock(&rbu_data.lock); } return size; --- linux-2.6.27.orig/drivers/firmware/dmi_scan.c +++ linux-2.6.27/drivers/firmware/dmi_scan.c @@ -457,6 +457,17 @@ } EXPORT_SYMBOL(dmi_get_system_info); +/** + * dmi_name_in_serial - Check if string is in the DMI product serial + * information. + */ +int dmi_name_in_serial(const char *str) +{ + int f = DMI_PRODUCT_SERIAL; + if (dmi_ident[f] && strstr(dmi_ident[f], str)) + return 1; + return 0; +} /** * dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information. --- linux-2.6.27.orig/drivers/base/core.c +++ linux-2.6.27/drivers/base/core.c @@ -523,11 +523,16 @@ * device_initialize - init device structure. * @dev: device. * - * This prepares the device for use by other layers, - * including adding it to the device hierarchy. + * This prepares the device for use by other layers by initializing + * its fields. * It is the first half of device_register(), if called by - * that, though it can also be called separately, so one - * may use @dev's fields (e.g. the refcount). + * that function, though it can also be called separately, so one + * may use @dev's fields. In particular, get_device()/put_device() + * may be used for reference counting of @dev after calling this + * function. + * + * NOTE: Use put_device() to give up your reference instead of freeing + * @dev directly once you have called this function. */ void device_initialize(struct device *dev) { @@ -836,9 +841,13 @@ * This is part 2 of device_register(), though may be called * separately _iff_ device_initialize() has been called separately. * - * This adds it to the kobject hierarchy via kobject_add(), adds it + * This adds @dev to the kobject hierarchy via kobject_add(), adds it * to the global and sibling lists for the device, then * adds it to the other relevant subsystems of the driver model. + * + * NOTE: _Never_ directly free @dev after calling this function, even + * if it returned an error! Always use put_device() to give up your + * reference instead. */ int device_add(struct device *dev) { @@ -965,6 +974,10 @@ * I.e. you should only call the two helpers separately if * have a clearly defined need to use and refcount the device * before it is added to the hierarchy. + * + * NOTE: _Never_ directly free @dev after calling this function, even + * if it returned an error! Always use put_device() to give up the + * reference initialized in this function instead. */ int device_register(struct device *dev) { @@ -1243,7 +1256,7 @@ return dev; error: - kfree(dev); + put_device(dev); return ERR_PTR(retval); } EXPORT_SYMBOL_GPL(device_create_vargs); --- linux-2.6.27.orig/drivers/base/sys.c +++ linux-2.6.27/drivers/base/sys.c @@ -488,7 +488,8 @@ if (end == buf) return -EINVAL; *(unsigned long *)(ea->var) = new; - return end - buf; + /* Always return full write size even if we didn't consume all */ + return size; } EXPORT_SYMBOL_GPL(sysdev_store_ulong); @@ -511,7 +512,8 @@ if (end == buf || new > INT_MAX || new < INT_MIN) return -EINVAL; *(int *)(ea->var) = new; - return end - buf; + /* Always return full write size even if we didn't consume all */ + return size; } EXPORT_SYMBOL_GPL(sysdev_store_int); --- linux-2.6.27.orig/drivers/dca/dca-core.c +++ linux-2.6.27/drivers/dca/dca-core.c @@ -270,6 +270,6 @@ dca_sysfs_exit(); } -module_init(dca_init); +subsys_initcall(dca_init); module_exit(dca_exit); --- linux-2.6.27.orig/drivers/scsi/eata.c +++ linux-2.6.27/drivers/scsi/eata.c @@ -1626,8 +1626,15 @@ cpp->sense_len = SCSI_SENSE_BUFFERSIZE; - count = scsi_dma_map(SCpnt); - BUG_ON(count < 0); + if (!scsi_sg_count(SCpnt)) { + cpp->data_len = 0; + return; + } + + count = pci_map_sg(ha->pdev, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), + pci_dir); + BUG_ON(!count); + scsi_for_each_sg(SCpnt, sg, count, k) { cpp->sglist[k].address = H2DEV(sg_dma_address(sg)); cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(sg)); @@ -1655,7 +1662,9 @@ pci_unmap_single(ha->pdev, DEV2H(cpp->sense_addr), DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); - scsi_dma_unmap(SCpnt); + if (scsi_sg_count(SCpnt)) + pci_unmap_sg(ha->pdev, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), + pci_dir); if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL; --- linux-2.6.27.orig/drivers/scsi/mvsas.c +++ linux-2.6.27/drivers/scsi/mvsas.c @@ -2959,7 +2959,7 @@ /* enable auto port detection */ mw32(GBL_PORT_TYPE, MODE_AUTO_DET_EN); - msleep(100); + msleep(1100); /* init and reset phys */ for (i = 0; i < mvi->chip->n_phy; i++) { u32 lo = be32_to_cpu(*(u32 *)&mvi->sas_addr[4]); --- linux-2.6.27.orig/drivers/scsi/scsi_transport_fc.c +++ linux-2.6.27/drivers/scsi/scsi_transport_fc.c @@ -479,10 +479,30 @@ MODULE_PARM_DESC(dev_loss_tmo, "Maximum number of seconds that the FC transport should" " insulate the loss of a remote port. Once this value is" - " exceeded, the scsi target is removed. Value should be" + " exceeded, the scsi target may be removed. Reference the" + " remove_on_dev_loss module parameter. Value should be" " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT."); /* + * remove_on_dev_loss: controls whether the transport will + * remove a scsi target after the device loss timer expires. + * Removal on disconnect is modeled after the USB subsystem + * and expects subsystems layered on SCSI to be aware of + * potential device loss and handle it appropriately. However, + * many subsystems do not support device removal, leaving situations + * where structure references may remain, causing new device + * name assignments, etc., if the target returns. + */ +static unsigned int fc_remove_on_dev_loss = 0; +module_param_named(remove_on_dev_loss, fc_remove_on_dev_loss, + int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(remove_on_dev_loss, + "Boolean. When the device loss timer fires, this variable" + " controls whether the scsi infrastructure for the target" + " device is removed. Values: zero means do not remove," + " non-zero means remove. Default is zero."); + +/** * Netlink Infrastructure */ @@ -2371,7 +2391,8 @@ if (i->f->terminate_rport_io) i->f->terminate_rport_io(rport); - scsi_remove_target(&rport->dev); + if (fc_remove_on_dev_loss) + scsi_remove_target(&rport->dev); } @@ -3006,9 +3027,13 @@ return; } - dev_printk(KERN_ERR, &rport->dev, - "blocked FC remote port time out: removing target and " - "saving binding\n"); + if (fc_remove_on_dev_loss) + dev_printk(KERN_ERR, &rport->dev, + "blocked FC remote port time out: removing target and " + "saving binding\n"); + else + dev_printk(KERN_ERR, &rport->dev, + "blocked FC remote port time out: saving binding\n"); list_move_tail(&rport->peers, &fc_host->rport_bindings); --- linux-2.6.27.orig/drivers/scsi/sd.c +++ linux-2.6.27/drivers/scsi/sd.c @@ -1047,7 +1047,6 @@ good_bytes = sd_completed_bytes(SCpnt); break; case RECOVERED_ERROR: - case NO_SENSE: /* Inform the user, but make sure that it's not treated * as a hard error. */ @@ -1056,6 +1055,15 @@ memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); good_bytes = scsi_bufflen(SCpnt); break; + case NO_SENSE: + /* This indicates a false check condition, so ignore it. An + * unknown amount of data was transferred so treat it as an + * error. + */ + scsi_print_sense("sd", SCpnt); + SCpnt->result = 0; + memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); + break; case ABORTED_COMMAND: if (sshdr.asc == 0x10) { /* DIF: Disk detected corruption */ scsi_print_result(SCpnt); --- linux-2.6.27.orig/drivers/scsi/dpt_i2o.c +++ linux-2.6.27/drivers/scsi/dpt_i2o.c @@ -2445,7 +2445,7 @@ hba_status = detailed_status >> 8; // calculate resid for sg - scsi_set_resid(cmd, scsi_bufflen(cmd) - readl(reply+5)); + scsi_set_resid(cmd, scsi_bufflen(cmd) - readl(reply+20)); pHba = (adpt_hba*) cmd->device->host->hostdata[0]; @@ -2456,7 +2456,7 @@ case I2O_SCSI_DSC_SUCCESS: cmd->result = (DID_OK << 16); // handle underflow - if(readl(reply+5) < cmd->underflow ) { + if (readl(reply+20) < cmd->underflow) { cmd->result = (DID_ERROR <<16); printk(KERN_WARNING"%s: SCSI CMD underflow\n",pHba->name); } --- linux-2.6.27.orig/drivers/scsi/ibmvscsi/ibmvstgt.c +++ linux-2.6.27/drivers/scsi/ibmvscsi/ibmvstgt.c @@ -864,21 +864,23 @@ INIT_WORK(&vport->crq_work, handle_crq); - err = crq_queue_create(&vport->crq_queue, target); + err = scsi_add_host(shost, target->dev); if (err) goto free_srp_target; - err = scsi_add_host(shost, target->dev); + err = scsi_tgt_alloc_queue(shost); if (err) - goto destroy_queue; + goto remove_host; - err = scsi_tgt_alloc_queue(shost); + err = crq_queue_create(&vport->crq_queue, target); if (err) - goto destroy_queue; + goto free_queue; return 0; -destroy_queue: - crq_queue_destroy(target); +free_queue: + scsi_tgt_free_queue(shost); +remove_host: + scsi_remove_host(shost); free_srp_target: srp_target_free(target); put_host: --- linux-2.6.27.orig/drivers/scsi/ibmvscsi/ibmvfc.h +++ linux-2.6.27/drivers/scsi/ibmvscsi/ibmvfc.h @@ -33,7 +33,7 @@ #define IBMVFC_DRIVER_DATE "(August 14, 2008)" #define IBMVFC_DEFAULT_TIMEOUT 15 -#define IBMVFC_INIT_TIMEOUT 30 +#define IBMVFC_INIT_TIMEOUT 120 #define IBMVFC_MAX_REQUESTS_DEFAULT 100 #define IBMVFC_DEBUG 0 @@ -43,7 +43,8 @@ #define IBMVFC_MAX_DISC_THREADS 4 #define IBMVFC_TGT_MEMPOOL_SZ 64 #define IBMVFC_MAX_CMDS_PER_LUN 64 -#define IBMVFC_MAX_INIT_RETRIES 3 +#define IBMVFC_MAX_HOST_INIT_RETRIES 6 +#define IBMVFC_MAX_TGT_INIT_RETRIES 3 #define IBMVFC_DEV_LOSS_TMO (5 * 60) #define IBMVFC_DEFAULT_LOG_LEVEL 2 #define IBMVFC_MAX_CDB_LEN 16 @@ -671,6 +672,7 @@ int discovery_threads; int client_migrated; int reinit; + int delay_init; int events_to_log; #define IBMVFC_AE_LINKUP 0x0001 #define IBMVFC_AE_LINKDOWN 0x0002 --- linux-2.6.27.orig/drivers/scsi/ibmvscsi/ibmvfc.c +++ linux-2.6.27/drivers/scsi/ibmvscsi/ibmvfc.c @@ -566,7 +566,7 @@ struct ibmvfc_target *tgt; if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) { - if (++vhost->init_retries > IBMVFC_MAX_INIT_RETRIES) { + if (++vhost->init_retries > IBMVFC_MAX_HOST_INIT_RETRIES) { dev_err(vhost->dev, "Host initialization retries exceeded. Taking adapter offline\n"); ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); @@ -847,11 +847,12 @@ static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost) { if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) { - if (++vhost->init_retries > IBMVFC_MAX_INIT_RETRIES) { + vhost->delay_init = 1; + if (++vhost->init_retries > IBMVFC_MAX_HOST_INIT_RETRIES) { dev_err(vhost->dev, "Host initialization retries exceeded. Taking adapter offline\n"); ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); - } else if (vhost->init_retries == IBMVFC_MAX_INIT_RETRIES) + } else if (vhost->init_retries == IBMVFC_MAX_HOST_INIT_RETRIES) __ibmvfc_reset_host(vhost); else ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); @@ -2091,15 +2092,17 @@ case IBMVFC_AE_LINK_UP: case IBMVFC_AE_RESUME: vhost->events_to_log |= IBMVFC_AE_LINKUP; - ibmvfc_init_host(vhost, 1); + vhost->delay_init = 1; + __ibmvfc_reset_host(vhost); break; case IBMVFC_AE_SCN_FABRIC: + case IBMVFC_AE_SCN_DOMAIN: vhost->events_to_log |= IBMVFC_AE_RSCN; - ibmvfc_init_host(vhost, 1); + vhost->delay_init = 1; + __ibmvfc_reset_host(vhost); break; case IBMVFC_AE_SCN_NPORT: case IBMVFC_AE_SCN_GROUP: - case IBMVFC_AE_SCN_DOMAIN: vhost->events_to_log |= IBMVFC_AE_RSCN; case IBMVFC_AE_ELS_LOGO: case IBMVFC_AE_ELS_PRLO: @@ -2671,7 +2674,7 @@ static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt, void (*job_step) (struct ibmvfc_target *)) { - if (++tgt->init_retries > IBMVFC_MAX_INIT_RETRIES) { + if (++tgt->init_retries > IBMVFC_MAX_TGT_INIT_RETRIES) { ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); wake_up(&tgt->vhost->work_wait_q); } else @@ -3521,7 +3524,13 @@ break; case IBMVFC_HOST_ACTION_INIT: BUG_ON(vhost->state != IBMVFC_INITIALIZING); - vhost->job_step(vhost); + if (vhost->delay_init) { + vhost->delay_init = 0; + spin_unlock_irqrestore(vhost->host->host_lock, flags); + ssleep(15); + return; + } else + vhost->job_step(vhost); break; case IBMVFC_HOST_ACTION_QUERY: list_for_each_entry(tgt, &vhost->targets, queue) --- linux-2.6.27.orig/drivers/scsi/device_handler/scsi_dh_rdac.c +++ linux-2.6.27/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -590,6 +590,8 @@ {"STK", "OPENstorage D280"}, {"SUN", "CSM200_R"}, {"SUN", "LCSM100_F"}, + {"DELL", "MD3000"}, + {"DELL", "MD3000i"}, {NULL, NULL}, }; --- linux-2.6.27.orig/drivers/scsi/aacraid/linit.c +++ linux-2.6.27/drivers/scsi/aacraid/linit.c @@ -175,8 +175,8 @@ { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Boxster/PERC3DiB) */ { aac_rx_init, "aacraid", "ADAPTEC ", "catapult ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* catapult */ { aac_rx_init, "aacraid", "ADAPTEC ", "tomcat ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* tomcat */ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2120S ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2120S (Crusader) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2200S (Vulcan) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2120S ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2120S (Crusader) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan) */ { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2200S (Vulcan-2m) */ { aac_rx_init, "aacraid", "Legend ", "Legend S220 ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend S220 (Legend Crusader) */ { aac_rx_init, "aacraid", "Legend ", "Legend S230 ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend S230 (Legend Vulcan) */ --- linux-2.6.27.orig/drivers/scsi/qla2xxx/qla_os.c +++ linux-2.6.27/drivers/scsi/qla2xxx/qla_os.c @@ -730,6 +730,7 @@ if (ha->isp_ops->abort_command(ha, sp)) { DEBUG2(printk("%s(%ld): abort_command " "mbx failed.\n", __func__, ha->host_no)); + ret = FAILED; } else { DEBUG3(printk("%s(%ld): abort_command " "mbx success.\n", __func__, ha->host_no)); --- linux-2.6.27.orig/drivers/scsi/qla2xxx/qla_init.c +++ linux-2.6.27/drivers/scsi/qla2xxx/qla_init.c @@ -974,7 +974,6 @@ &ha->fw_minor_version, &ha->fw_subminor_version, &ha->fw_attributes, &ha->fw_memory_size); - qla2x00_resize_request_q(ha); ha->flags.npiv_supported = 0; if ((IS_QLA24XX(ha) || IS_QLA25XX(ha) || IS_QLA84XX(ha)) && @@ -986,6 +985,7 @@ ha->max_npiv_vports = MIN_MULTI_ID_FABRIC - 1; } + qla2x00_resize_request_q(ha); if (ql2xallocfwdump) qla2x00_alloc_fw_dump(ha); --- linux-2.6.27.orig/drivers/scsi/qla2xxx/qla_mbx.c +++ linux-2.6.27/drivers/scsi/qla2xxx/qla_mbx.c @@ -1964,7 +1964,7 @@ *cur_iocb_cnt = mcp->mb[7]; if (orig_iocb_cnt) *orig_iocb_cnt = mcp->mb[10]; - if (max_npiv_vports) + if (ha->flags.npiv_supported && max_npiv_vports) *max_npiv_vports = mcp->mb[11]; } --- linux-2.6.27.orig/drivers/scsi/qla2xxx/qla_def.h +++ linux-2.6.27/drivers/scsi/qla2xxx/qla_def.h @@ -2546,7 +2546,6 @@ uint8_t fcode_revision[16]; uint32_t fw_revision[4]; - uint16_t fdt_odd_index; uint32_t fdt_wrt_disable; uint32_t fdt_erase_cmd; uint32_t fdt_block_size; --- linux-2.6.27.orig/drivers/scsi/qla2xxx/qla_sup.c +++ linux-2.6.27/drivers/scsi/qla2xxx/qla_sup.c @@ -546,6 +546,7 @@ void qla2xxx_get_flash_info(scsi_qla_host_t *ha) { +#define FLASH_BLK_SIZE_4K 0x1000 #define FLASH_BLK_SIZE_32K 0x8000 #define FLASH_BLK_SIZE_64K 0x10000 uint16_t cnt, chksum; @@ -577,7 +578,6 @@ goto no_flash_data; } - ha->fdt_odd_index = le16_to_cpu(fdt->man_id) == 0x1f; ha->fdt_wrt_disable = fdt->wrt_disable_bits; ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0300 | fdt->erase_cmd); ha->fdt_block_size = le32_to_cpu(fdt->block_size); @@ -590,10 +590,10 @@ } DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[FDT]: (0x%x/0x%x) erase=0x%x " - "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", + "pro=%x upro=%x wrtd=0x%x blk=0x%x.\n", le16_to_cpu(fdt->man_id), le16_to_cpu(fdt->id), ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd, ha->fdt_unprotect_sec_cmd, - ha->fdt_odd_index, ha->fdt_wrt_disable, ha->fdt_block_size)); + ha->fdt_wrt_disable, ha->fdt_block_size)); return; no_flash_data: @@ -614,8 +614,7 @@ ha->fdt_block_size = FLASH_BLK_SIZE_64K; break; case 0x1f: /* Atmel 26DF081A. */ - ha->fdt_odd_index = 1; - ha->fdt_block_size = FLASH_BLK_SIZE_64K; + ha->fdt_block_size = FLASH_BLK_SIZE_4K; ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0320); ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0339); ha->fdt_protect_sec_cmd = flash_conf_to_access_addr(0x0336); @@ -627,9 +626,9 @@ } DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[MID]: (0x%x/0x%x) erase=0x%x " - "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", man_id, flash_id, + "pro=%x upro=%x wrtd=0x%x blk=0x%x.\n", man_id, flash_id, ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd, - ha->fdt_unprotect_sec_cmd, ha->fdt_odd_index, ha->fdt_wrt_disable, + ha->fdt_unprotect_sec_cmd, ha->fdt_wrt_disable, ha->fdt_block_size)); } @@ -710,13 +709,9 @@ qla24xx_unprotect_flash(ha); for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { - if (ha->fdt_odd_index) { - findex = faddr << 2; - fdata = findex & sec_mask; - } else { - findex = faddr; - fdata = (findex & sec_mask) << 2; - } + + findex = faddr; + fdata = (findex & sec_mask) << 2; /* Are we at the beginning of a sector? */ if ((findex & rest_addr) == 0) { --- linux-2.6.27.orig/drivers/scsi/pcmcia/aha152x_stub.c +++ linux-2.6.27/drivers/scsi/pcmcia/aha152x_stub.c @@ -114,7 +114,7 @@ link->io.NumPorts1 = 0x20; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.IOAddrLines = 10; - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; --- linux-2.6.27.orig/drivers/gpu/drm/i915/i915_drv.c +++ linux-2.6.27/drivers/gpu/drm/i915/i915_drv.c @@ -256,6 +256,10 @@ pci_save_state(dev->pdev); pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB); + /* Render Standby */ + if (IS_I965G(dev) && IS_MOBILE(dev)) + dev_priv->saveRENDERSTANDBY = I915_READ(MCHBAR_RENDER_STANDBY); + /* Display arbitration control */ dev_priv->saveDSPARB = I915_READ(DSPARB); @@ -393,6 +397,11 @@ pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB); + /* Render Standby */ + if (IS_I965G(dev) && IS_MOBILE(dev)) + I915_WRITE(MCHBAR_RENDER_STANDBY, dev_priv->saveRENDERSTANDBY); + + /* Display arbitration */ I915_WRITE(DSPARB, dev_priv->saveDSPARB); /* Pipe & plane A info */ --- linux-2.6.27.orig/drivers/gpu/drm/i915/i915_dma.c +++ linux-2.6.27/drivers/gpu/drm/i915/i915_dma.c @@ -836,7 +836,7 @@ DRM_IOCTL_DEF(DRM_I915_SET_VBLANK_PIPE, i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ), DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH ), DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH), + DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); --- linux-2.6.27.orig/drivers/gpu/drm/i915/i915_drv.h +++ linux-2.6.27/drivers/gpu/drm/i915/i915_drv.h @@ -120,6 +120,7 @@ u32 saveDSPACNTR; u32 saveDSPBCNTR; u32 saveDSPARB; + u32 saveRENDERSTANDBY; u32 savePIPEACONF; u32 savePIPEBCONF; u32 savePIPEASRC; @@ -1060,6 +1061,9 @@ # define VGA_2X_MODE (1 << 30) # define VGA_PIPE_B_SELECT (1 << 29) +/** GM965 GM45 render standby register */ +#define MCHBAR_RENDER_STANDBY 0x111B8 + /* * Some BIOS scratch area registers. The 845 (and 830?) store the amount * of video memory available to the BIOS in SWF1. --- linux-2.6.27.orig/drivers/infiniband/hw/mlx4/cq.c +++ linux-2.6.27/drivers/infiniband/hw/mlx4/cq.c @@ -343,6 +343,7 @@ { struct mlx4_ib_dev *dev = to_mdev(ibcq->device); struct mlx4_ib_cq *cq = to_mcq(ibcq); + struct mlx4_mtt mtt; int outst_cqe; int err; @@ -376,10 +377,13 @@ goto out; } + mtt = cq->buf.mtt; + err = mlx4_cq_resize(dev->dev, &cq->mcq, entries, &cq->resize_buf->buf.mtt); if (err) goto err_buf; + mlx4_mtt_cleanup(dev->dev, &mtt); if (ibcq->uobject) { cq->buf = cq->resize_buf->buf; cq->ibcq.cqe = cq->resize_buf->cqe; @@ -406,6 +410,7 @@ goto out; err_buf: + mlx4_mtt_cleanup(dev->dev, &cq->resize_buf->buf.mtt); if (!ibcq->uobject) mlx4_ib_free_cq_buf(dev, &cq->resize_buf->buf, cq->resize_buf->cqe); --- linux-2.6.27.orig/drivers/ieee1394/nodemgr.c +++ linux-2.6.27/drivers/ieee1394/nodemgr.c @@ -115,8 +115,14 @@ return error; } +#define OUI_FREECOM_TECHNOLOGIES_GMBH 0x0001db + static int nodemgr_get_max_rom(quadlet_t *bus_info_data, void *__ci) { + /* Freecom FireWire Hard Drive firmware bug */ + if (be32_to_cpu(bus_info_data[3]) >> 8 == OUI_FREECOM_TECHNOLOGIES_GMBH) + return 0; + return (be32_to_cpu(bus_info_data[2]) >> 8) & 0x3; } --- linux-2.6.27.orig/drivers/ieee1394/ohci1394.h +++ linux-2.6.27/drivers/ieee1394/ohci1394.h @@ -26,7 +26,7 @@ #define OHCI1394_DRIVER_NAME "ohci1394" -#define OHCI1394_MAX_AT_REQ_RETRIES 0x2 +#define OHCI1394_MAX_AT_REQ_RETRIES 0xf #define OHCI1394_MAX_AT_RESP_RETRIES 0x2 #define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8 #define OHCI1394_MAX_SELF_ID_ERRORS 16 --- linux-2.6.27.orig/drivers/ieee1394/sbp2.c +++ linux-2.6.27/drivers/ieee1394/sbp2.c @@ -395,6 +395,16 @@ .model_id = SBP2_ROM_VALUE_WILDCARD, .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS, }, + /* + * iPod 2nd generation: needs 128k max transfer size workaround + * iPod 3rd generation: needs fix capacity workaround + */ + { + .firmware_revision = 0x0a2700, + .model_id = 0x000000, + .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS | + SBP2_WORKAROUND_FIX_CAPACITY, + }, /* iPod 4th generation */ { .firmware_revision = 0x0a2700, .model_id = 0x000021, @@ -402,6 +412,11 @@ }, /* iPod mini */ { .firmware_revision = 0x0a2700, + .model_id = 0x000022, + .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, + }, + /* iPod mini */ { + .firmware_revision = 0x0a2700, .model_id = 0x000023, .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, }, --- linux-2.6.27.orig/drivers/watchdog/ib700wdt.c +++ linux-2.6.27/drivers/watchdog/ib700wdt.c @@ -154,7 +154,7 @@ return -EINVAL; for (i = 0x0F; i > -1; i--) - if (wd_times[i] > t) + if (wd_times[i] >= t) break; wd_margin = i; return 0; --- linux-2.6.27.orig/drivers/watchdog/hpwdt.c +++ linux-2.6.27/drivers/watchdog/hpwdt.c @@ -40,6 +40,7 @@ #include #include #include +#include #define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */ #define CRU_BIOS_SIGNATURE_VALUE 0x55524324 @@ -394,6 +395,8 @@ smbios_cru64_ptr->double_offset; cru_rom_addr = ioremap(cru_physical_address, smbios_cru64_ptr->double_length); + set_memory_x((unsigned long)cru_rom_addr & PAGE_MASK, + smbios_cru64_ptr->double_length >> PAGE_SHIFT); } } } @@ -482,7 +485,7 @@ "Management Log for details.\n"); } - return NOTIFY_STOP; + return NOTIFY_OK; } /* --- linux-2.6.27.orig/drivers/message/fusion/mptbase.c +++ linux-2.6.27/drivers/message/fusion/mptbase.c @@ -3014,6 +3014,16 @@ pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus); pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo); pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices); + /* + * VMware emulation is broken, its PortFact's MaxDevices reports value + * programmed by IOC Init, so if you program IOC Init to 256 (which is 0, + * as that field is only 8 bit), it reports back 0 in port facts, instead + * of 256... And unfortunately using 256 triggers another bug in the + * code (parallel SCSI can have only 16 devices). + */ + if (pfacts->MaxDevices == 0) { + pfacts->MaxDevices = 16; + } pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID); pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags); pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers); --- linux-2.6.27.orig/drivers/video/Kconfig +++ linux-2.6.27/drivers/video/Kconfig @@ -673,8 +673,8 @@ If unsure, say N. config FB_VESA - bool "VESA VGA graphics support" - depends on (FB = y) && X86 + tristate "VESA VGA graphics support" + depends on FB && X86 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT --- linux-2.6.27.orig/drivers/video/fbmem.c +++ linux-2.6.27/drivers/video/fbmem.c @@ -232,7 +232,7 @@ greenshift = info->var.green.offset; blueshift = info->var.blue.offset; - for (i = 32; i < logo->clutsize; i++) + for (i = 32; i < 32 + logo->clutsize; i++) palette[i] = i << redshift | i << greenshift | i << blueshift; } --- linux-2.6.27.orig/drivers/video/vesafb.c +++ linux-2.6.27/drivers/video/vesafb.c @@ -28,6 +28,12 @@ #define dac_reg (0x3c8) #define dac_val (0x3c9) +struct vesafb_info +{ + u32 pseudo_palette[256]; + int mtrr_hdl; +}; + /* --------------------------------------------------------------------- */ static struct fb_var_screeninfo vesafb_defined __initdata = { @@ -47,16 +53,37 @@ .accel = FB_ACCEL_NONE, }; +#ifndef MODULE static int inverse __read_mostly; +#endif static int mtrr __read_mostly; /* disable mtrr */ static int vram_remap __initdata; /* Set amount of memory to be used */ static int vram_total __initdata; /* Set total amount of memory */ static int pmi_setpal __read_mostly = 1; /* pmi for palette changes ??? */ +static int redraw __read_mostly; static int ypan __read_mostly; /* 0..nothing, 1..ypan, 2..ywrap */ +static int ywrap __read_mostly; static void (*pmi_start)(void) __read_mostly; static void (*pmi_pal) (void) __read_mostly; static int depth __read_mostly; static int vga_compat __read_mostly; + +module_param(redraw, bool, 0); +module_param(ypan, bool, 0); +module_param(ywrap, bool, 0); +module_param_named(vgapal, pmi_setpal, invbool, 0); +MODULE_PARM_DESC(vgapal, "Use VGA for setting palette (default)"); +module_param_named(pmipal, pmi_setpal, bool, 0); +MODULE_PARM_DESC(pmipal, "Use PMI for setting palette"); +module_param(mtrr, bool, 0); +MODULE_PARM_DESC(mtrr, "Enable MTRR support (default)"); +module_param_named(nomtrr, mtrr, invbool, 0); +MODULE_PARM_DESC(nomtrr, "Disable MTRR support"); +module_param(vram_remap, int, 0); +MODULE_PARM_DESC(vram_remap, "Set total amount of memory to be used"); +module_param(vram_total, int, 0); +MODULE_PARM_DESC(vram_total, "Total amount of memory"); + /* --------------------------------------------------------------------- */ static int vesafb_pan_display(struct fb_var_screeninfo *var, @@ -183,6 +210,7 @@ .fb_imageblit = cfb_imageblit, }; +#ifndef MODULE static int __init vesafb_setup(char *options) { char *this_opt; @@ -216,6 +244,7 @@ } return 0; } +#endif static int __init vesafb_probe(struct platform_device *dev) { @@ -463,8 +492,28 @@ return err; } +static int __exit vesafb_remove(struct platform_device *device) +{ + struct fb_info *info = dev_get_drvdata(&device->dev); + + unregister_framebuffer(info); +#ifdef CONFIG_MTRR + { + struct vesafb_info *vfb_info = (struct vesafb_info *) info->par; + if (vfb_info->mtrr_hdl >= 0) + mtrr_del(vfb_info->mtrr_hdl, 0, 0); + } +#endif + iounmap(info->screen_base); + framebuffer_release(info); + release_mem_region(vesafb_fix.smem_start, vesafb_fix.smem_len); + + return 0; +} + static struct platform_driver vesafb_driver = { .probe = vesafb_probe, + .remove = vesafb_remove, .driver = { .name = "vesafb", }, @@ -475,11 +524,18 @@ static int __init vesafb_init(void) { int ret; +#ifndef MODULE char *option = NULL; /* ignore error return of fb_get_options */ fb_get_options("vesafb", &option); vesafb_setup(option); +#else + if (redraw) + ypan = 0; + if (ywrap) + ypan = 2; +#endif ret = platform_driver_register(&vesafb_driver); if (!ret) { @@ -498,6 +554,14 @@ return ret; } + +static void __exit vesafb_exit(void) +{ + platform_device_unregister(vesafb_device); + platform_driver_unregister(&vesafb_driver); +} + module_init(vesafb_init); +module_exit(vesafb_exit); MODULE_LICENSE("GPL"); --- linux-2.6.27.orig/drivers/video/macfb.c +++ linux-2.6.27/drivers/video/macfb.c @@ -164,7 +164,6 @@ }; static struct fb_fix_screeninfo macfb_fix = { - .id = "Macintosh ", .type = FB_TYPE_PACKED_PIXELS, .accel = FB_ACCEL_NONE, }; @@ -760,22 +759,22 @@ switch(ndev->dr_hw) { case NUBUS_DRHW_APPLE_MDC: - strcat( macfb_fix.id, "Display Card" ); + strcpy(macfb_fix.id, "Mac Disp. Card"); macfb_setpalette = mdc_setpalette; macfb_defined.activate = FB_ACTIVATE_NOW; break; case NUBUS_DRHW_APPLE_TFB: - strcat( macfb_fix.id, "Toby" ); + strcpy(macfb_fix.id, "Toby"); macfb_setpalette = toby_setpalette; macfb_defined.activate = FB_ACTIVATE_NOW; break; case NUBUS_DRHW_APPLE_JET: - strcat( macfb_fix.id, "Jet"); + strcpy(macfb_fix.id, "Jet"); macfb_setpalette = jet_setpalette; macfb_defined.activate = FB_ACTIVATE_NOW; break; default: - strcat( macfb_fix.id, "Generic NuBus" ); + strcpy(macfb_fix.id, "Generic NuBus"); break; } } @@ -786,21 +785,11 @@ if (!video_is_nubus) switch( mac_bi_data.id ) { - /* These don't have onboard video. Eventually, we may - be able to write separate framebuffer drivers for - them (tobyfb.c, hiresfb.c, etc, etc) */ - case MAC_MODEL_II: - case MAC_MODEL_IIX: - case MAC_MODEL_IICX: - case MAC_MODEL_IIFX: - strcat( macfb_fix.id, "Generic NuBus" ); - break; - /* Valkyrie Quadras */ case MAC_MODEL_Q630: /* I'm not sure about this one */ case MAC_MODEL_P588: - strcat( macfb_fix.id, "Valkyrie built-in" ); + strcpy(macfb_fix.id, "Valkyrie"); macfb_setpalette = valkyrie_setpalette; macfb_defined.activate = FB_ACTIVATE_NOW; valkyrie_cmap_regs = ioremap(DAC_BASE, 0x1000); @@ -823,7 +812,7 @@ case MAC_MODEL_Q700: case MAC_MODEL_Q900: case MAC_MODEL_Q950: - strcat( macfb_fix.id, "DAFB built-in" ); + strcpy(macfb_fix.id, "DAFB"); macfb_setpalette = dafb_setpalette; macfb_defined.activate = FB_ACTIVATE_NOW; dafb_cmap_regs = ioremap(DAFB_BASE, 0x1000); @@ -831,7 +820,7 @@ /* LC II uses the V8 framebuffer */ case MAC_MODEL_LCII: - strcat( macfb_fix.id, "V8 built-in" ); + strcpy(macfb_fix.id, "V8"); macfb_setpalette = v8_brazil_setpalette; macfb_defined.activate = FB_ACTIVATE_NOW; v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000); @@ -843,7 +832,7 @@ case MAC_MODEL_IIVI: case MAC_MODEL_IIVX: case MAC_MODEL_P600: - strcat( macfb_fix.id, "Brazil built-in" ); + strcpy(macfb_fix.id, "Brazil"); macfb_setpalette = v8_brazil_setpalette; macfb_defined.activate = FB_ACTIVATE_NOW; v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000); @@ -860,7 +849,7 @@ case MAC_MODEL_P460: macfb_setpalette = v8_brazil_setpalette; macfb_defined.activate = FB_ACTIVATE_NOW; - strcat( macfb_fix.id, "Sonora built-in" ); + strcpy(macfb_fix.id, "Sonora"); v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000); break; @@ -871,7 +860,7 @@ case MAC_MODEL_IISI: macfb_setpalette = rbv_setpalette; macfb_defined.activate = FB_ACTIVATE_NOW; - strcat( macfb_fix.id, "RBV built-in" ); + strcpy(macfb_fix.id, "RBV"); rbv_cmap_regs = ioremap(DAC_BASE, 0x1000); break; @@ -880,7 +869,7 @@ case MAC_MODEL_C660: macfb_setpalette = civic_setpalette; macfb_defined.activate = FB_ACTIVATE_NOW; - strcat( macfb_fix.id, "Civic built-in" ); + strcpy(macfb_fix.id, "Civic"); civic_cmap_regs = ioremap(CIVIC_BASE, 0x1000); break; @@ -901,7 +890,7 @@ v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000); } - strcat( macfb_fix.id, "LC built-in" ); + strcpy(macfb_fix.id, "LC"); break; /* We think this may be like the LC II */ case MAC_MODEL_CCL: @@ -911,18 +900,18 @@ v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000); } - strcat( macfb_fix.id, "Color Classic built-in" ); + strcpy(macfb_fix.id, "Color Classic"); break; /* And we *do* mean "weirdos" */ case MAC_MODEL_TV: - strcat( macfb_fix.id, "Mac TV built-in" ); + strcpy(macfb_fix.id, "Mac TV"); break; /* These don't have colour, so no need to worry */ case MAC_MODEL_SE30: case MAC_MODEL_CLII: - strcat( macfb_fix.id, "Monochrome built-in" ); + strcpy(macfb_fix.id, "Monochrome"); break; /* Powerbooks are particularly difficult. Many of @@ -935,7 +924,7 @@ case MAC_MODEL_PB140: case MAC_MODEL_PB145: case MAC_MODEL_PB170: - strcat( macfb_fix.id, "DDC built-in" ); + strcpy(macfb_fix.id, "DDC"); break; /* Internal is GSC, External (if present) is ViSC */ @@ -945,13 +934,13 @@ case MAC_MODEL_PB180: case MAC_MODEL_PB210: case MAC_MODEL_PB230: - strcat( macfb_fix.id, "GSC built-in" ); + strcpy(macfb_fix.id, "GSC"); break; /* Internal is TIM, External is ViSC */ case MAC_MODEL_PB165C: case MAC_MODEL_PB180C: - strcat( macfb_fix.id, "TIM built-in" ); + strcpy(macfb_fix.id, "TIM"); break; /* Internal is CSC, External is Keystone+Ariel. */ @@ -963,12 +952,12 @@ case MAC_MODEL_PB280C: macfb_setpalette = csc_setpalette; macfb_defined.activate = FB_ACTIVATE_NOW; - strcat( macfb_fix.id, "CSC built-in" ); + strcpy(macfb_fix.id, "CSC"); csc_cmap_regs = ioremap(CSC_BASE, 0x1000); break; default: - strcat( macfb_fix.id, "Unknown/Unsupported built-in" ); + strcpy(macfb_fix.id, "Unknown"); break; } @@ -978,16 +967,23 @@ fb_info.pseudo_palette = pseudo_palette; fb_info.flags = FBINFO_DEFAULT; - fb_alloc_cmap(&fb_info.cmap, video_cmap_len, 0); + err = fb_alloc_cmap(&fb_info.cmap, video_cmap_len, 0); + if (err) + goto fail_unmap; err = register_framebuffer(&fb_info); - if (!err) - printk("fb%d: %s frame buffer device\n", - fb_info.node, fb_info.fix.id); - else { - iounmap(fb_info.screen_base); - iounmap_macfb(); - } + if (err) + goto fail_dealloc; + + printk("fb%d: %s frame buffer device\n", + fb_info.node, fb_info.fix.id); + return 0; + +fail_dealloc: + fb_dealloc_cmap(&fb_info.cmap); +fail_unmap: + iounmap(fb_info.screen_base); + iounmap_macfb(); return err; } --- linux-2.6.27.orig/drivers/video/console/vgacon.c +++ linux-2.6.27/drivers/video/console/vgacon.c @@ -1266,7 +1266,7 @@ font->charcount = vga_512_chars ? 512 : 256; if (!font->data) return 0; - return vgacon_do_font_op(&state, font->data, 0, 0); + return vgacon_do_font_op(&state, font->data, 0, vga_512_chars); } #else @@ -1350,7 +1350,7 @@ } else c->vc_origin += delta; scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size - - delta), c->vc_scrl_erase_char, + delta), c->vc_video_erase_char, delta); } else { if (oldo - delta < vga_vram_base) { @@ -1363,7 +1363,7 @@ } else c->vc_origin -= delta; c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; - scr_memsetw((u16 *) (c->vc_origin), c->vc_scrl_erase_char, + scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char, delta); } c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; --- linux-2.6.27.orig/drivers/video/console/mdacon.c +++ linux-2.6.27/drivers/video/console/mdacon.c @@ -533,7 +533,7 @@ static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines) { - u16 eattr = mda_convert_attr(c->vc_scrl_erase_char); + u16 eattr = mda_convert_attr(c->vc_video_erase_char); if (!lines) return 0; --- linux-2.6.27.orig/drivers/video/console/sticon.c +++ linux-2.6.27/drivers/video/console/sticon.c @@ -170,12 +170,12 @@ switch (dir) { case SM_UP: sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols); - sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_scrl_erase_char); + sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_video_erase_char); break; case SM_DOWN: sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols); - sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_scrl_erase_char); + sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_video_erase_char); break; } --- linux-2.6.27.orig/drivers/video/console/fbcon.c +++ linux-2.6.27/drivers/video/console/fbcon.c @@ -1855,8 +1855,6 @@ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct display *p = &fb_display[vc->vc_num]; int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; - unsigned short saved_ec; - int ret; if (fbcon_is_inactive(vc, info)) return -EINVAL; @@ -1869,11 +1867,6 @@ * whole screen (prevents flicker). */ - saved_ec = vc->vc_video_erase_char; - vc->vc_video_erase_char = vc->vc_scrl_erase_char; - - ret = 0; - switch (dir) { case SM_UP: if (count > vc->vc_rows) /* Maximum realistic size */ @@ -1890,9 +1883,9 @@ scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * (b - count)), - vc->vc_scrl_erase_char, + vc->vc_video_erase_char, vc->vc_size_row * count); - ret = 1; + return 1; break; case SCROLL_WRAP_MOVE: @@ -1962,10 +1955,9 @@ scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * (b - count)), - vc->vc_scrl_erase_char, + vc->vc_video_erase_char, vc->vc_size_row * count); - ret = 1; - break; + return 1; } break; @@ -1982,9 +1974,9 @@ scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * t), - vc->vc_scrl_erase_char, + vc->vc_video_erase_char, vc->vc_size_row * count); - ret = 1; + return 1; break; case SCROLL_WRAP_MOVE: @@ -2052,15 +2044,12 @@ scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * t), - vc->vc_scrl_erase_char, + vc->vc_video_erase_char, vc->vc_size_row * count); - ret = 1; - break; + return 1; } - break; } - vc->vc_video_erase_char = saved_ec; - return ret; + return 0; } @@ -2522,9 +2511,6 @@ c = vc->vc_video_erase_char; vc->vc_video_erase_char = ((c & 0xfe00) >> 1) | (c & 0xff); - c = vc->vc_scrl_erase_char; - vc->vc_scrl_erase_char = - ((c & 0xFE00) >> 1) | (c & 0xFF); vc->vc_attr >>= 1; } } else if (!vc->vc_hi_font_mask && cnt == 512) { @@ -2555,14 +2541,9 @@ if (vc->vc_can_do_color) { vc->vc_video_erase_char = ((c & 0xff00) << 1) | (c & 0xff); - c = vc->vc_scrl_erase_char; - vc->vc_scrl_erase_char = - ((c & 0xFF00) << 1) | (c & 0xFF); vc->vc_attr <<= 1; - } else { + } else vc->vc_video_erase_char = c & ~0x100; - vc->vc_scrl_erase_char = c & ~0x100; - } } } @@ -2996,8 +2977,8 @@ p = &fb_display[vc->vc_num]; set_blitting_type(vc, info); var_to_display(p, &info->var, info); - cols = FBCON_SWAP(p->rotate, info->var.xres, info->var.yres); - rows = FBCON_SWAP(p->rotate, info->var.yres, info->var.xres); + cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); + rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); cols /= vc->vc_font.width; rows /= vc->vc_font.height; vc_resize(vc, cols, rows); --- linux-2.6.27.orig/drivers/video/aty/mach64_ct.c +++ linux-2.6.27/drivers/video/aty/mach64_ct.c @@ -8,6 +8,9 @@ #include #include